From 08df19bde65fbd23f20c1f611d085e7f606008a4 Mon Sep 17 00:00:00 2001 From: salmonstill Date: Tue, 18 Aug 2026 10:12:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=AD=A3=E5=9C=A8=E5=86=99deepseek=E9=80=8F?= =?UTF-8?q?=E4=BC=A0=E7=9A=84=E7=9B=B8=E5=85=B3=E4=BA=8B=E5=AE=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dsh-local-403-fix/README.md | 75 + dsh-local-403-fix/apply-403-fix.sh | 124 + dsh-local-403-fix/cordis.patch.yml | 18 + dsh-local-403-fix/node_modules/.bin/cordis | 55 + dsh-local-403-fix/node_modules/.modules.yaml | 189 + .../node_modules/.package-map.json | 1 + .../.pnpm-workspace-state-v1.json | 29 + .../node_modules/@deepseek-ai/cordis | 1 + .../cordis-plugin-include/LICENSE | 21 + .../cordis-plugin-include/README.md | 43 + .../cordis-plugin-include/lib/index.js | 284 + .../lib/types/index.d.ts | 99 + .../lib/types/index.d.ts.map | 1 + .../node_modules/.bin/cordis | 55 + .../node_modules/.bin/js-yaml | 55 + .../cordis-plugin-include/package.json | 40 + .../cordis-plugin-include/src/index.ts | 377 + .../@deepseek-ai/cordis-plugin-loader | 1 + .../node_modules/@deepseek-ai/cosmokit | 1 + .../node_modules/js-yaml | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/cordis-plugin-loader/LICENSE | 21 + .../cordis-plugin-loader/README.md | 48 + .../cordis-plugin-loader/lib/index.js | 744 ++ .../lib/types/config/entry.d.ts | 56 + .../lib/types/config/entry.d.ts.map | 1 + .../lib/types/config/group.d.ts | 27 + .../lib/types/config/group.d.ts.map | 1 + .../lib/types/config/isolate.d.ts | 35 + .../lib/types/config/isolate.d.ts.map | 1 + .../lib/types/config/tree.d.ts | 38 + .../lib/types/config/tree.d.ts.map | 1 + .../lib/types/config/utils.d.ts | 11 + .../lib/types/config/utils.d.ts.map | 1 + .../cordis-plugin-loader/lib/types/index.d.ts | 73 + .../lib/types/index.d.ts.map | 1 + .../lib/types/internal.d.ts | 97 + .../lib/types/internal.d.ts.map | 1 + .../node_modules/.bin/cordis | 55 + .../cordis-plugin-loader/package.json | 44 + .../cordis-plugin-loader/src/config/entry.ts | 303 + .../cordis-plugin-loader/src/config/group.ts | 129 + .../src/config/isolate.ts | 173 + .../cordis-plugin-loader/src/config/tree.ts | 166 + .../cordis-plugin-loader/src/config/utils.ts | 32 + .../cordis-plugin-loader/src/index.ts | 202 + .../cordis-plugin-loader/src/internal.ts | 132 + .../node_modules/@deepseek-ai/cosmokit | 1 + .../@deepseek-ai/cordis-plugin-include | 1 + .../@deepseek-ai/cordis-plugin-loader | 1 + .../node_modules/@deepseek-ai/cordis/LICENSE | 21 + .../@deepseek-ai/cordis/README.md | 101 + .../node_modules/@deepseek-ai/cordis/bin.js | 16 + .../@deepseek-ai/cordis/lib/index.js | 1828 +++ .../cordis/lib/types/context.d.ts | 101 + .../cordis/lib/types/context.d.ts.map | 1 + .../@deepseek-ai/cordis/lib/types/events.d.ts | 240 + .../cordis/lib/types/events.d.ts.map | 1 + .../@deepseek-ai/cordis/lib/types/fiber.d.ts | 202 + .../cordis/lib/types/fiber.d.ts.map | 1 + .../@deepseek-ai/cordis/lib/types/index.d.ts | 15 + .../cordis/lib/types/index.d.ts.map | 1 + .../@deepseek-ai/cordis/lib/types/logger.d.ts | 105 + .../cordis/lib/types/logger.d.ts.map | 1 + .../cordis/lib/types/reflect.d.ts | 186 + .../cordis/lib/types/reflect.d.ts.map | 1 + .../cordis/lib/types/registry.d.ts | 201 + .../cordis/lib/types/registry.d.ts.map | 1 + .../cordis/lib/types/service.d.ts | 55 + .../cordis/lib/types/service.d.ts.map | 1 + .../@deepseek-ai/cordis/lib/types/utils.d.ts | 62 + .../cordis/lib/types/utils.d.ts.map | 1 + .../cordis/node_modules/.bin/cordis | 55 + .../@deepseek-ai/cordis/package.json | 53 + .../@deepseek-ai/cordis/src/context.ts | 146 + .../@deepseek-ai/cordis/src/events.ts | 352 + .../@deepseek-ai/cordis/src/fiber.ts | 754 ++ .../@deepseek-ai/cordis/src/index.ts | 14 + .../@deepseek-ai/cordis/src/logger.ts | 270 + .../@deepseek-ai/cordis/src/reflect.ts | 418 + .../@deepseek-ai/cordis/src/registry.ts | 337 + .../@deepseek-ai/cordis/src/service.ts | 115 + .../@deepseek-ai/cordis/src/utils.ts | 287 + .../node_modules/@deepseek-ai/cosmokit | 1 + .../node_modules/@standard-schema/spec | 1 + .../@deepseek-ai/cosmokit/LICENSE | 21 + .../@deepseek-ai/cosmokit/README.md | 24 + .../@deepseek-ai/cosmokit/lib/index.js | 325 + .../cosmokit/lib/types/array.d.ts | 15 + .../cosmokit/lib/types/array.d.ts.map | 1 + .../cosmokit/lib/types/index.d.ts | 11 + .../cosmokit/lib/types/index.d.ts.map | 1 + .../@deepseek-ai/cosmokit/lib/types/misc.d.ts | 41 + .../cosmokit/lib/types/misc.d.ts.map | 1 + .../cosmokit/lib/types/string.d.ts | 89 + .../cosmokit/lib/types/string.d.ts.map | 1 + .../@deepseek-ai/cosmokit/lib/types/time.d.ts | 19 + .../cosmokit/lib/types/time.d.ts.map | 1 + .../cosmokit/lib/types/types.d.ts | 34 + .../cosmokit/lib/types/types.d.ts.map | 1 + .../@deepseek-ai/cosmokit/package.json | 32 + .../@deepseek-ai/cosmokit/src/array.ts | 42 + .../@deepseek-ai/cosmokit/src/index.ts | 10 + .../@deepseek-ai/cosmokit/src/misc.ts | 78 + .../@deepseek-ai/cosmokit/src/string.ts | 113 + .../@deepseek-ai/cosmokit/src/time.ts | 92 + .../@deepseek-ai/cosmokit/src/types.ts | 142 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../dsh-agent-default-model/LICENSE | 21 + .../dsh-agent-default-model/README.i18n.yaml | 6 + .../dsh-agent-default-model/README.md | 25 + .../dsh-agent-default-model/README.zh.md | 25 + .../dsh-agent-default-model/lib/index.js | 74 + .../dsh-agent-default-model/lib/invariant.js | 25 + .../lib/types/index.d.ts | 58 + .../lib/types/invariant.d.ts | 21 + .../node_modules/.bin/cordis | 55 + .../dsh-agent-default-model/package.json | 51 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-settings | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../dsh-agent-default-model/LICENSE | 21 + .../dsh-agent-default-model/README.i18n.yaml | 6 + .../dsh-agent-default-model/README.md | 25 + .../dsh-agent-default-model/README.zh.md | 25 + .../dsh-agent-default-model/lib/index.js | 74 + .../dsh-agent-default-model/lib/invariant.js | 25 + .../lib/types/index.d.ts | 58 + .../lib/types/invariant.d.ts | 21 + .../node_modules/.bin/cordis | 55 + .../dsh-agent-default-model/package.json | 51 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-settings | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/cordis-plugin-include | 1 + .../@deepseek-ai/cordis-plugin-loader | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-agent-presets/LICENSE | 21 + .../dsh-agent-presets/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-agent-presets/README.md | 154 + .../dsh-agent-presets/README.zh.md | 154 + .../dsh-agent-presets/lib/index.js | 1178 ++ .../dsh-agent-presets/lib/invariant.js | 1178 ++ .../lib/types/authoring.d.ts | 86 + .../dsh-agent-presets/lib/types/authoring.js | 183 + .../lib/types/discovery.d.ts | 55 + .../dsh-agent-presets/lib/types/discovery.js | 187 + .../dsh-agent-presets/lib/types/index.d.ts | 291 + .../dsh-agent-presets/lib/types/index.js | 500 + .../lib/types/invariant.d.ts | 16 + .../dsh-agent-presets/lib/types/invariant.js | 65 + .../dsh-agent-presets/lib/types/metadata.d.ts | 52 + .../dsh-agent-presets/lib/types/metadata.js | 92 + .../dsh-agent-presets/lib/types/mount.d.ts | 112 + .../dsh-agent-presets/lib/types/mount.js | 349 + .../dsh-agent-presets/lib/types/preset.d.ts | 88 + .../dsh-agent-presets/lib/types/preset.js | 45 + .../dsh-agent-presets/lib/types/session.d.ts | 47 + .../dsh-agent-presets/lib/types/session.js | 33 + .../dsh-agent-presets/lib/types/types.d.ts | 16 + .../dsh-agent-presets/lib/types/types.js | 2 + .../node_modules/.bin/cordis | 55 + .../node_modules/.bin/js-yaml | 55 + .../dsh-agent-presets/package.json | 73 + .../@deepseek-ai/dsh-atomic-write | 1 + .../node_modules/@deepseek-ai/dsh-home-paths | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../node_modules/@deepseek-ai/dsh-settings | 1 + .../@deepseek-ai/dsh-system-prompt | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/js-yaml | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/cordis-plugin-include | 1 + .../@deepseek-ai/cordis-plugin-loader | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-agent-presets/LICENSE | 21 + .../dsh-agent-presets/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-agent-presets/README.md | 154 + .../dsh-agent-presets/README.zh.md | 154 + .../dsh-agent-presets/lib/index.js | 1178 ++ .../dsh-agent-presets/lib/invariant.js | 1178 ++ .../lib/types/authoring.d.ts | 86 + .../dsh-agent-presets/lib/types/authoring.js | 183 + .../lib/types/discovery.d.ts | 55 + .../dsh-agent-presets/lib/types/discovery.js | 187 + .../dsh-agent-presets/lib/types/index.d.ts | 291 + .../dsh-agent-presets/lib/types/index.js | 500 + .../lib/types/invariant.d.ts | 16 + .../dsh-agent-presets/lib/types/invariant.js | 65 + .../dsh-agent-presets/lib/types/metadata.d.ts | 52 + .../dsh-agent-presets/lib/types/metadata.js | 92 + .../dsh-agent-presets/lib/types/mount.d.ts | 112 + .../dsh-agent-presets/lib/types/mount.js | 349 + .../dsh-agent-presets/lib/types/preset.d.ts | 88 + .../dsh-agent-presets/lib/types/preset.js | 45 + .../dsh-agent-presets/lib/types/session.d.ts | 47 + .../dsh-agent-presets/lib/types/session.js | 33 + .../dsh-agent-presets/lib/types/types.d.ts | 16 + .../dsh-agent-presets/lib/types/types.js | 2 + .../node_modules/.bin/cordis | 55 + .../node_modules/.bin/js-yaml | 55 + .../dsh-agent-presets/package.json | 73 + .../@deepseek-ai/dsh-atomic-write | 1 + .../node_modules/@deepseek-ai/dsh-home-paths | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../node_modules/@deepseek-ai/dsh-settings | 1 + .../@deepseek-ai/dsh-system-prompt | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/js-yaml | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-agent/LICENSE | 21 + .../@deepseek-ai/dsh-agent/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-agent/README.md | 121 + .../@deepseek-ai/dsh-agent/README.zh.md | 121 + .../@deepseek-ai/dsh-agent/lib/index.js | 794 ++ .../@deepseek-ai/dsh-agent/lib/invariant.js | 23 + .../dsh-agent/lib/types/consumed-work.d.ts | 39 + .../dsh-agent/lib/types/consumed-work.js | 92 + .../dsh-agent/lib/types/dispatch.d.ts | 111 + .../dsh-agent/lib/types/dispatch.js | 95 + .../dsh-agent/lib/types/inbox.d.ts | 92 + .../@deepseek-ai/dsh-agent/lib/types/inbox.js | 185 + .../dsh-agent/lib/types/index.d.ts | 385 + .../@deepseek-ai/dsh-agent/lib/types/index.js | 474 + .../dsh-agent/lib/types/invariant.d.ts | 13 + .../dsh-agent/lib/types/invariant.js | 24 + .../dsh-agent/lib/types/model-selection.d.ts | 36 + .../dsh-agent/lib/types/model-selection.js | 53 + .../dsh-agent/lib/types/runtime-types.d.ts | 324 + .../dsh-agent/lib/types/runtime-types.js | 8 + .../dsh-agent/lib/types/types.d.ts | 25 + .../@deepseek-ai/dsh-agent/lib/types/types.js | 7 + .../dsh-agent/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-agent/package.json | 58 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-system-prompt | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-agent/LICENSE | 21 + .../@deepseek-ai/dsh-agent/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-agent/README.md | 121 + .../@deepseek-ai/dsh-agent/README.zh.md | 121 + .../@deepseek-ai/dsh-agent/lib/index.js | 794 ++ .../@deepseek-ai/dsh-agent/lib/invariant.js | 23 + .../dsh-agent/lib/types/consumed-work.d.ts | 39 + .../dsh-agent/lib/types/consumed-work.js | 92 + .../dsh-agent/lib/types/dispatch.d.ts | 111 + .../dsh-agent/lib/types/dispatch.js | 95 + .../dsh-agent/lib/types/inbox.d.ts | 92 + .../@deepseek-ai/dsh-agent/lib/types/inbox.js | 185 + .../dsh-agent/lib/types/index.d.ts | 385 + .../@deepseek-ai/dsh-agent/lib/types/index.js | 474 + .../dsh-agent/lib/types/invariant.d.ts | 13 + .../dsh-agent/lib/types/invariant.js | 24 + .../dsh-agent/lib/types/model-selection.d.ts | 36 + .../dsh-agent/lib/types/model-selection.js | 53 + .../dsh-agent/lib/types/runtime-types.d.ts | 324 + .../dsh-agent/lib/types/runtime-types.js | 8 + .../dsh-agent/lib/types/types.d.ts | 25 + .../@deepseek-ai/dsh-agent/lib/types/types.js | 7 + .../dsh-agent/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-agent/package.json | 58 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-system-prompt | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-api-gateway/LICENSE | 21 + .../dsh-api-gateway/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-api-gateway/README.md | 42 + .../@deepseek-ai/dsh-api-gateway/README.zh.md | 42 + .../dsh-api-gateway/lib/client.js | 420 + .../@deepseek-ai/dsh-api-gateway/lib/index.js | 396 + .../dsh-api-gateway/lib/invariant.js | 24 + .../lib/types/client/index.d.ts | 23 + .../dsh-api-gateway/lib/types/client/index.js | 467 + .../dsh-api-gateway/lib/types/index.d.ts | 61 + .../dsh-api-gateway/lib/types/index.js | 508 + .../dsh-api-gateway/lib/types/invariant.d.ts | 16 + .../dsh-api-gateway/lib/types/invariant.js | 23 + .../dsh-api-gateway/lib/types/types.d.ts | 34 + .../dsh-api-gateway/lib/types/types.js | 6 + .../dsh-api-gateway/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-api-gateway/package.json | 75 + .../@deepseek-ai/dsh-client-connection | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../@deepseek-ai/dsh-typert-registry | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-api-gateway/LICENSE | 21 + .../dsh-api-gateway/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-api-gateway/README.md | 42 + .../@deepseek-ai/dsh-api-gateway/README.zh.md | 42 + .../dsh-api-gateway/lib/client.js | 420 + .../@deepseek-ai/dsh-api-gateway/lib/index.js | 396 + .../dsh-api-gateway/lib/invariant.js | 24 + .../lib/types/client/index.d.ts | 23 + .../dsh-api-gateway/lib/types/client/index.js | 467 + .../dsh-api-gateway/lib/types/index.d.ts | 61 + .../dsh-api-gateway/lib/types/index.js | 508 + .../dsh-api-gateway/lib/types/invariant.d.ts | 16 + .../dsh-api-gateway/lib/types/invariant.js | 23 + .../dsh-api-gateway/lib/types/types.d.ts | 34 + .../dsh-api-gateway/lib/types/types.js | 6 + .../dsh-api-gateway/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-api-gateway/package.json | 75 + .../@deepseek-ai/dsh-client-connection | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../@deepseek-ai/dsh-typert-registry | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-agent-presets | 1 + .../node_modules/@deepseek-ai/dsh-api-gateway | 1 + .../@deepseek-ai/dsh-api-remotes/LICENSE | 21 + .../dsh-api-remotes/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-api-remotes/README.md | 41 + .../@deepseek-ai/dsh-api-remotes/README.zh.md | 42 + .../dsh-api-remotes/lib/client.js | 5937 +++++++++ .../@deepseek-ai/dsh-api-remotes/lib/index.js | 172 + .../dsh-api-remotes/lib/invariant.js | 17 + .../lib/types/agent-lookup.d.ts | 95 + .../dsh-api-remotes/lib/types/agent-lookup.js | 166 + .../lib/types/client/index.d.ts | 41 + .../dsh-api-remotes/lib/types/client/index.js | 35 + .../dsh-api-remotes/lib/types/index.d.ts | 8 + .../dsh-api-remotes/lib/types/index.js | 16 + .../dsh-api-remotes/lib/types/invariant.d.ts | 13 + .../dsh-api-remotes/lib/types/invariant.js | 16 + .../lib/types/remote-events.d.ts | 17 + .../lib/types/remote-events.js | 29 + .../dsh-api-remotes/lib/types/types.d.ts | 18 + .../dsh-api-remotes/lib/types/types.js | 12 + .../dsh-api-remotes/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-api-remotes/package.json | 96 + .../node_modules/@deepseek-ai/dsh-commands | 1 + .../@deepseek-ai/dsh-cordis-host-runner | 1 + .../node_modules/@deepseek-ai/dsh-credentials | 1 + .../node_modules/@deepseek-ai/dsh-goal | 1 + .../@deepseek-ai/dsh-host-plugin-inventory | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../@deepseek-ai/dsh-message-feedback | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../node_modules/@deepseek-ai/dsh-settings | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../@deepseek-ai/dsh-typert-registry | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-agent-presets | 1 + .../node_modules/@deepseek-ai/dsh-api-gateway | 1 + .../@deepseek-ai/dsh-api-remotes/LICENSE | 21 + .../dsh-api-remotes/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-api-remotes/README.md | 41 + .../@deepseek-ai/dsh-api-remotes/README.zh.md | 42 + .../dsh-api-remotes/lib/client.js | 5937 +++++++++ .../@deepseek-ai/dsh-api-remotes/lib/index.js | 172 + .../dsh-api-remotes/lib/invariant.js | 17 + .../lib/types/agent-lookup.d.ts | 95 + .../dsh-api-remotes/lib/types/agent-lookup.js | 166 + .../lib/types/client/index.d.ts | 41 + .../dsh-api-remotes/lib/types/client/index.js | 35 + .../dsh-api-remotes/lib/types/index.d.ts | 8 + .../dsh-api-remotes/lib/types/index.js | 16 + .../dsh-api-remotes/lib/types/invariant.d.ts | 13 + .../dsh-api-remotes/lib/types/invariant.js | 16 + .../lib/types/remote-events.d.ts | 17 + .../lib/types/remote-events.js | 29 + .../dsh-api-remotes/lib/types/types.d.ts | 18 + .../dsh-api-remotes/lib/types/types.js | 12 + .../dsh-api-remotes/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-api-remotes/package.json | 96 + .../node_modules/@deepseek-ai/dsh-commands | 1 + .../@deepseek-ai/dsh-cordis-host-runner | 1 + .../node_modules/@deepseek-ai/dsh-credentials | 1 + .../node_modules/@deepseek-ai/dsh-goal | 1 + .../@deepseek-ai/dsh-host-plugin-inventory | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../@deepseek-ai/dsh-message-feedback | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../node_modules/@deepseek-ai/dsh-settings | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../@deepseek-ai/dsh-typert-registry | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-atomic-write/LICENSE | 21 + .../dsh-atomic-write/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-atomic-write/README.md | 45 + .../dsh-atomic-write/README.zh.md | 45 + .../dsh-atomic-write/lib/index.js | 97 + .../dsh-atomic-write/lib/invariant.js | 23 + .../dsh-atomic-write/lib/types/index.d.ts | 57 + .../dsh-atomic-write/lib/types/invariant.d.ts | 16 + .../dsh-atomic-write/node_modules/.bin/cordis | 55 + .../dsh-atomic-write/package.json | 42 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-atomic-write/LICENSE | 21 + .../dsh-atomic-write/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-atomic-write/README.md | 45 + .../dsh-atomic-write/README.zh.md | 45 + .../dsh-atomic-write/lib/index.js | 97 + .../dsh-atomic-write/lib/invariant.js | 23 + .../dsh-atomic-write/lib/types/index.d.ts | 57 + .../dsh-atomic-write/lib/types/invariant.d.ts | 16 + .../dsh-atomic-write/node_modules/.bin/cordis | 55 + .../dsh-atomic-write/package.json | 42 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-attachment/LICENSE | 21 + .../dsh-attachment/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-attachment/README.md | 21 + .../@deepseek-ai/dsh-attachment/README.zh.md | 21 + .../@deepseek-ai/dsh-attachment/lib/index.js | 48 + .../dsh-attachment/lib/invariant.js | 17 + .../dsh-attachment/lib/types/brand.d.ts | 11 + .../dsh-attachment/lib/types/error.d.ts | 21 + .../dsh-attachment/lib/types/index.d.ts | 40 + .../dsh-attachment/lib/types/invariant.d.ts | 13 + .../dsh-attachment/lib/types/types.d.ts | 42 + .../dsh-attachment/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-attachment/package.json | 44 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-attachment/LICENSE | 21 + .../dsh-attachment/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-attachment/README.md | 21 + .../@deepseek-ai/dsh-attachment/README.zh.md | 21 + .../@deepseek-ai/dsh-attachment/lib/index.js | 84 + .../dsh-attachment/lib/invariant.js | 17 + .../dsh-attachment/lib/types/brand.d.ts | 11 + .../dsh-attachment/lib/types/error.d.ts | 35 + .../dsh-attachment/lib/types/index.d.ts | 50 + .../dsh-attachment/lib/types/invariant.d.ts | 13 + .../dsh-attachment/lib/types/types.d.ts | 42 + .../dsh-attachment/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-attachment/package.json | 44 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-brand/LICENSE | 21 + .../@deepseek-ai/dsh-brand/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-brand/README.md | 28 + .../@deepseek-ai/dsh-brand/README.zh.md | 28 + .../@deepseek-ai/dsh-brand/lib/index.js | 1 + .../@deepseek-ai/dsh-brand/lib/invariant.js | 23 + .../dsh-brand/lib/types/index.d.ts | 29 + .../dsh-brand/lib/types/invariant.d.ts | 16 + .../dsh-brand/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-brand/package.json | 42 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-brand/LICENSE | 21 + .../@deepseek-ai/dsh-brand/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-brand/README.md | 28 + .../@deepseek-ai/dsh-brand/README.zh.md | 28 + .../@deepseek-ai/dsh-brand/lib/index.js | 1 + .../@deepseek-ai/dsh-brand/lib/invariant.js | 23 + .../dsh-brand/lib/types/index.d.ts | 29 + .../dsh-brand/lib/types/invariant.d.ts | 16 + .../dsh-brand/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-brand/package.json | 42 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-attachment | 1 + .../dsh-client-connection/LICENSE | 21 + .../dsh-client-connection/README.i18n.yaml | 6 + .../dsh-client-connection/README.md | 26 + .../dsh-client-connection/README.zh.md | 26 + .../dsh-client-connection/lib/client.js | 10212 ++++++++++++++++ .../dsh-client-connection/lib/index.js | 588 + .../dsh-client-connection/lib/invariant.js | 26 + .../lib/types/api-path.d.ts | 12 + .../lib/types/api-request-trust.d.ts | 43 + .../lib/types/client/api.d.ts | 20 + .../lib/types/client/connection.d.ts | 64 + .../lib/types/client/fixture.d.ts | 68 + .../lib/types/client/index.d.ts | 54 + .../lib/types/client/random-uuid.d.ts | 7 + .../lib/types/client/rpc.d.ts | 8 + .../lib/types/client/web-api-client.d.ts | 11 + .../lib/types/http-bridge.d.ts | 29 + .../lib/types/index.d.ts | 36 + .../lib/types/invariant.d.ts | 16 + .../lib/types/loopback-hostname.d.ts | 12 + .../lib/types/rpc-host.d.ts | 33 + .../dsh-client-connection/lib/types/rpc.d.ts | 51 + .../lib/types/websocket-downlink.d.ts | 43 + .../node_modules/.bin/cordis | 55 + .../dsh-client-connection/package.json | 67 + .../node_modules/@deepseek-ai/dsh-commands | 1 + .../@deepseek-ai/dsh-host-apiproxy | 1 + .../@deepseek-ai/dsh-host-webserver | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../node_modules/@deepseek-ai/dsh-tools | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/ws | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-attachment | 1 + .../dsh-client-connection/LICENSE | 21 + .../dsh-client-connection/README.i18n.yaml | 6 + .../dsh-client-connection/README.md | 26 + .../dsh-client-connection/README.zh.md | 26 + .../dsh-client-connection/lib/client.js | 10207 +++++++++++++++ .../dsh-client-connection/lib/index.js | 588 + .../dsh-client-connection/lib/invariant.js | 26 + .../lib/types/api-path.d.ts | 12 + .../lib/types/api-request-trust.d.ts | 43 + .../lib/types/client/api.d.ts | 20 + .../lib/types/client/connection.d.ts | 64 + .../lib/types/client/fixture.d.ts | 68 + .../lib/types/client/index.d.ts | 54 + .../lib/types/client/random-uuid.d.ts | 7 + .../lib/types/client/rpc.d.ts | 8 + .../lib/types/client/web-api-client.d.ts | 11 + .../lib/types/http-bridge.d.ts | 29 + .../lib/types/index.d.ts | 36 + .../lib/types/invariant.d.ts | 16 + .../lib/types/loopback-hostname.d.ts | 12 + .../lib/types/rpc-host.d.ts | 33 + .../dsh-client-connection/lib/types/rpc.d.ts | 51 + .../lib/types/websocket-downlink.d.ts | 43 + .../node_modules/.bin/cordis | 55 + .../dsh-client-connection/package.json | 67 + .../node_modules/@deepseek-ai/dsh-commands | 1 + .../@deepseek-ai/dsh-host-apiproxy | 1 + .../@deepseek-ai/dsh-host-webserver | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../node_modules/@deepseek-ai/dsh-tools | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/ws | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-code-runtime/LICENSE | 21 + .../dsh-code-runtime/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-code-runtime/README.md | 38 + .../dsh-code-runtime/README.zh.md | 38 + .../dsh-code-runtime/lib/index.js | 154 + .../dsh-code-runtime/lib/invariant.js | 23 + .../dsh-code-runtime/lib/types/index.d.ts | 99 + .../dsh-code-runtime/lib/types/invariant.d.ts | 16 + .../dsh-code-runtime/lib/types/types.d.ts | 123 + .../dsh-code-runtime/node_modules/.bin/cordis | 55 + .../dsh-code-runtime/package.json | 42 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-code-runtime/LICENSE | 21 + .../dsh-code-runtime/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-code-runtime/README.md | 38 + .../dsh-code-runtime/README.zh.md | 38 + .../dsh-code-runtime/lib/index.js | 154 + .../dsh-code-runtime/lib/invariant.js | 23 + .../dsh-code-runtime/lib/types/index.d.ts | 99 + .../dsh-code-runtime/lib/types/invariant.d.ts | 16 + .../dsh-code-runtime/lib/types/types.d.ts | 123 + .../dsh-code-runtime/node_modules/.bin/cordis | 55 + .../dsh-code-runtime/package.json | 42 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../@deepseek-ai/dsh-commands/LICENSE | 21 + .../dsh-commands/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-commands/README.md | 40 + .../@deepseek-ai/dsh-commands/README.zh.md | 40 + .../@deepseek-ai/dsh-commands/lib/index.js | 360 + .../dsh-commands/lib/invariant.js | 43 + .../dsh-commands/lib/typert.host.d.ts | 3 + .../dsh-commands/lib/typert.host.js | 502 + .../lib/typert.remote-client.d.ts | 29 + .../dsh-commands/lib/typert.remote-client.js | 103 + .../dsh-commands/lib/types/brand.d.ts | 25 + .../dsh-commands/lib/types/brand.js | 20 + .../dsh-commands/lib/types/index.d.ts | 126 + .../dsh-commands/lib/types/index.js | 343 + .../dsh-commands/lib/types/invariant.d.ts | 17 + .../dsh-commands/lib/types/invariant.js | 60 + .../dsh-commands/lib/types/types.d.ts | 102 + .../dsh-commands/lib/types/types.js | 10 + .../dsh-commands/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-commands/package.json | 76 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../@deepseek-ai/dsh-commands/LICENSE | 21 + .../dsh-commands/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-commands/README.md | 40 + .../@deepseek-ai/dsh-commands/README.zh.md | 40 + .../@deepseek-ai/dsh-commands/lib/index.js | 360 + .../dsh-commands/lib/invariant.js | 43 + .../dsh-commands/lib/typert.host.d.ts | 3 + .../dsh-commands/lib/typert.host.js | 506 + .../lib/typert.remote-client.d.ts | 29 + .../dsh-commands/lib/typert.remote-client.js | 103 + .../dsh-commands/lib/types/brand.d.ts | 25 + .../dsh-commands/lib/types/brand.js | 20 + .../dsh-commands/lib/types/index.d.ts | 126 + .../dsh-commands/lib/types/index.js | 343 + .../dsh-commands/lib/types/invariant.d.ts | 17 + .../dsh-commands/lib/types/invariant.js | 60 + .../dsh-commands/lib/types/types.d.ts | 102 + .../dsh-commands/lib/types/types.js | 10 + .../dsh-commands/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-commands/package.json | 76 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../dsh-cordis-host-runner/LICENSE | 21 + .../dsh-cordis-host-runner/README.i18n.yaml | 6 + .../dsh-cordis-host-runner/README.md | 72 + .../dsh-cordis-host-runner/README.zh.md | 72 + .../dsh-cordis-host-runner/lib/index.js | 2573 ++++ .../dsh-cordis-host-runner/lib/invariant.js | 25 + .../lib/typert.host.d.ts | 3 + .../dsh-cordis-host-runner/lib/typert.host.js | 1897 +++ .../lib/typert.remote-client.d.ts | 55 + .../lib/typert.remote-client.js | 769 ++ .../lib/types/guard.d.ts | 71 + .../dsh-cordis-host-runner/lib/types/guard.js | 766 ++ .../lib/types/index.d.ts | 270 + .../dsh-cordis-host-runner/lib/types/index.js | 1151 ++ .../lib/types/inspect-registry.d.ts | 72 + .../lib/types/inspect-registry.js | 192 + .../lib/types/invariant.d.ts | 16 + .../lib/types/invariant.js | 24 + .../lib/types/lifecycle.d.ts | 29 + .../lib/types/lifecycle.js | 49 + .../lib/types/registry.d.ts | 225 + .../lib/types/registry.js | 131 + .../lib/types/sandbox.d.ts | 93 + .../lib/types/sandbox.js | 223 + .../lib/types/types.d.ts | 359 + .../dsh-cordis-host-runner/lib/types/types.js | 6 + .../node_modules/.bin/cordis | 55 + .../dsh-cordis-host-runner/package.json | 78 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../node_modules/@deepseek-ai/dsh-tools | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../dsh-cordis-host-runner/LICENSE | 21 + .../dsh-cordis-host-runner/README.i18n.yaml | 6 + .../dsh-cordis-host-runner/README.md | 72 + .../dsh-cordis-host-runner/README.zh.md | 72 + .../dsh-cordis-host-runner/lib/index.js | 2573 ++++ .../dsh-cordis-host-runner/lib/invariant.js | 25 + .../lib/typert.host.d.ts | 3 + .../dsh-cordis-host-runner/lib/typert.host.js | 1905 +++ .../lib/typert.remote-client.d.ts | 55 + .../lib/typert.remote-client.js | 769 ++ .../lib/types/guard.d.ts | 71 + .../dsh-cordis-host-runner/lib/types/guard.js | 766 ++ .../lib/types/index.d.ts | 270 + .../dsh-cordis-host-runner/lib/types/index.js | 1151 ++ .../lib/types/inspect-registry.d.ts | 72 + .../lib/types/inspect-registry.js | 192 + .../lib/types/invariant.d.ts | 16 + .../lib/types/invariant.js | 24 + .../lib/types/lifecycle.d.ts | 29 + .../lib/types/lifecycle.js | 49 + .../lib/types/registry.d.ts | 225 + .../lib/types/registry.js | 131 + .../lib/types/sandbox.d.ts | 93 + .../lib/types/sandbox.js | 223 + .../lib/types/types.d.ts | 359 + .../dsh-cordis-host-runner/lib/types/types.js | 6 + .../node_modules/.bin/cordis | 55 + .../dsh-cordis-host-runner/package.json | 78 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../node_modules/@deepseek-ai/dsh-tools | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../@deepseek-ai/dsh-credentials/LICENSE | 21 + .../dsh-credentials/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-credentials/README.md | 48 + .../@deepseek-ai/dsh-credentials/README.zh.md | 48 + .../@deepseek-ai/dsh-credentials/lib/index.js | 67 + .../dsh-credentials/lib/invariant.js | 31 + .../dsh-credentials/lib/types/index.d.ts | 96 + .../dsh-credentials/lib/types/index.js | 78 + .../dsh-credentials/lib/types/invariant.d.ts | 16 + .../dsh-credentials/lib/types/invariant.js | 31 + .../dsh-credentials/lib/types/types.d.ts | 29 + .../dsh-credentials/lib/types/types.js | 10 + .../dsh-credentials/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-credentials/package.json | 49 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../@deepseek-ai/dsh-credentials/LICENSE | 21 + .../dsh-credentials/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-credentials/README.md | 48 + .../@deepseek-ai/dsh-credentials/README.zh.md | 48 + .../@deepseek-ai/dsh-credentials/lib/index.js | 67 + .../dsh-credentials/lib/invariant.js | 31 + .../dsh-credentials/lib/types/index.d.ts | 96 + .../dsh-credentials/lib/types/index.js | 78 + .../dsh-credentials/lib/types/invariant.d.ts | 16 + .../dsh-credentials/lib/types/invariant.js | 31 + .../dsh-credentials/lib/types/types.d.ts | 29 + .../dsh-credentials/lib/types/types.js | 10 + .../dsh-credentials/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-credentials/package.json | 49 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../@deepseek-ai/dsh-goal/LICENSE | 21 + .../@deepseek-ai/dsh-goal/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-goal/README.md | 58 + .../@deepseek-ai/dsh-goal/README.zh.md | 58 + .../@deepseek-ai/dsh-goal/lib/index.js | 827 ++ .../@deepseek-ai/dsh-goal/lib/invariant.js | 332 + .../dsh-goal/lib/typert.host.d.ts | 3 + .../@deepseek-ai/dsh-goal/lib/typert.host.js | 815 ++ .../dsh-goal/lib/typert.remote-client.d.ts | 41 + .../dsh-goal/lib/typert.remote-client.js | 366 + .../dsh-goal/lib/types/client.d.ts | 10 + .../@deepseek-ai/dsh-goal/lib/types/client.js | 10 + .../dsh-goal/lib/types/domain.d.ts | 92 + .../@deepseek-ai/dsh-goal/lib/types/domain.js | 10 + .../@deepseek-ai/dsh-goal/lib/types/fold.d.ts | 50 + .../@deepseek-ai/dsh-goal/lib/types/fold.js | 322 + .../dsh-goal/lib/types/index.d.ts | 155 + .../@deepseek-ai/dsh-goal/lib/types/index.js | 495 + .../dsh-goal/lib/types/invariant.d.ts | 13 + .../dsh-goal/lib/types/invariant.js | 70 + .../dsh-goal/lib/types/runtime.d.ts | 21 + .../dsh-goal/lib/types/runtime.js | 25 + .../dsh-goal/lib/types/types.d.ts | 96 + .../@deepseek-ai/dsh-goal/lib/types/types.js | 13 + .../dsh-goal/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-goal/package.json | 82 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../@deepseek-ai/dsh-goal/LICENSE | 21 + .../@deepseek-ai/dsh-goal/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-goal/README.md | 58 + .../@deepseek-ai/dsh-goal/README.zh.md | 58 + .../@deepseek-ai/dsh-goal/lib/index.js | 827 ++ .../@deepseek-ai/dsh-goal/lib/invariant.js | 332 + .../dsh-goal/lib/typert.host.d.ts | 3 + .../@deepseek-ai/dsh-goal/lib/typert.host.js | 819 ++ .../dsh-goal/lib/typert.remote-client.d.ts | 41 + .../dsh-goal/lib/typert.remote-client.js | 366 + .../dsh-goal/lib/types/client.d.ts | 10 + .../@deepseek-ai/dsh-goal/lib/types/client.js | 10 + .../dsh-goal/lib/types/domain.d.ts | 92 + .../@deepseek-ai/dsh-goal/lib/types/domain.js | 10 + .../@deepseek-ai/dsh-goal/lib/types/fold.d.ts | 50 + .../@deepseek-ai/dsh-goal/lib/types/fold.js | 322 + .../dsh-goal/lib/types/index.d.ts | 155 + .../@deepseek-ai/dsh-goal/lib/types/index.js | 495 + .../dsh-goal/lib/types/invariant.d.ts | 13 + .../dsh-goal/lib/types/invariant.js | 70 + .../dsh-goal/lib/types/runtime.d.ts | 21 + .../dsh-goal/lib/types/runtime.js | 25 + .../dsh-goal/lib/types/types.d.ts | 96 + .../@deepseek-ai/dsh-goal/lib/types/types.js | 13 + .../dsh-goal/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-goal/package.json | 82 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-home-paths/LICENSE | 21 + .../dsh-home-paths/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-home-paths/README.md | 30 + .../@deepseek-ai/dsh-home-paths/README.zh.md | 30 + .../@deepseek-ai/dsh-home-paths/lib/index.js | 97 + .../dsh-home-paths/lib/invariant.js | 23 + .../dsh-home-paths/lib/types/index.d.ts | 64 + .../dsh-home-paths/lib/types/invariant.d.ts | 16 + .../dsh-home-paths/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-home-paths/package.json | 42 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-home-paths/LICENSE | 21 + .../dsh-home-paths/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-home-paths/README.md | 30 + .../@deepseek-ai/dsh-home-paths/README.zh.md | 30 + .../@deepseek-ai/dsh-home-paths/lib/index.js | 97 + .../dsh-home-paths/lib/invariant.js | 23 + .../dsh-home-paths/lib/types/index.d.ts | 64 + .../dsh-home-paths/lib/types/invariant.d.ts | 16 + .../dsh-home-paths/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-home-paths/package.json | 42 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-agent-default-model | 1 + .../@deepseek-ai/dsh-agent-presets | 1 + .../node_modules/@deepseek-ai/dsh-api-remotes | 1 + .../node_modules/@deepseek-ai/dsh-attachment | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-commands | 1 + .../@deepseek-ai/dsh-cordis-host-runner | 1 + .../node_modules/@deepseek-ai/dsh-credentials | 1 + .../node_modules/@deepseek-ai/dsh-goal | 1 + .../@deepseek-ai/dsh-host-apiproxy/LICENSE | 21 + .../dsh-host-apiproxy/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-host-apiproxy/README.md | 83 + .../dsh-host-apiproxy/README.zh.md | 83 + .../dsh-host-apiproxy/lib/index.js | 5648 +++++++++ .../dsh-host-apiproxy/lib/invariant.js | 27 + .../lib/types/api-proxy.d.ts | 70 + .../dsh-host-apiproxy/lib/types/api-proxy.js | 3455 ++++++ .../lib/types/api/agent-presets.d.ts | 130 + .../lib/types/api/agent-presets.js | 12 + .../lib/types/api/agent-presets.schema.d.ts | 78 + .../lib/types/api/agent-presets.schema.js | 70 + .../lib/types/api/approvals.d.ts | 20 + .../lib/types/api/approvals.js | 8 + .../lib/types/api/approvals.schema.d.ts | 16 + .../lib/types/api/approvals.schema.js | 16 + .../lib/types/api/credentials.d.ts | 49 + .../lib/types/api/credentials.js | 10 + .../lib/types/api/credentials.schema.d.ts | 41 + .../lib/types/api/credentials.schema.js | 37 + .../lib/types/api/downloads.d.ts | 24 + .../lib/types/api/downloads.js | 8 + .../lib/types/api/downloads.schema.d.ts | 24 + .../lib/types/api/downloads.schema.js | 24 + .../lib/types/api/events.d.ts | 213 + .../dsh-host-apiproxy/lib/types/api/events.js | 9 + .../lib/types/api/events.schema.d.ts | 28 + .../lib/types/api/events.schema.js | 84 + .../lib/types/api/goals.d.ts | 73 + .../dsh-host-apiproxy/lib/types/api/goals.js | 12 + .../lib/types/api/goals.schema.d.ts | 35 + .../lib/types/api/goals.schema.js | 63 + .../dsh-host-apiproxy/lib/types/api/host.d.ts | 91 + .../dsh-host-apiproxy/lib/types/api/host.js | 6 + .../lib/types/api/host.schema.d.ts | 65 + .../lib/types/api/host.schema.js | 58 + .../lib/types/api/index.d.ts | 63 + .../dsh-host-apiproxy/lib/types/api/index.js | 11 + .../dsh-host-apiproxy/lib/types/api/jobs.d.ts | 35 + .../dsh-host-apiproxy/lib/types/api/jobs.js | 7 + .../lib/types/api/jobs.schema.d.ts | 23 + .../lib/types/api/jobs.schema.js | 28 + .../dsh-host-apiproxy/lib/types/api/llm.d.ts | 88 + .../dsh-host-apiproxy/lib/types/api/llm.js | 11 + .../lib/types/api/llm.schema.d.ts | 79 + .../lib/types/api/llm.schema.js | 53 + .../lib/types/api/questions.d.ts | 18 + .../lib/types/api/questions.js | 8 + .../lib/types/api/questions.schema.d.ts | 26 + .../lib/types/api/questions.schema.js | 21 + .../lib/types/api/rpc-map.d.ts | 80 + .../lib/types/api/rpc-map.js | 7 + .../dsh-host-apiproxy/lib/types/api/rpc.d.ts | 271 + .../dsh-host-apiproxy/lib/types/api/rpc.js | 30 + .../lib/types/api/rpc.schema.d.ts | 60 + .../lib/types/api/rpc.schema.js | 115 + .../lib/types/api/session-search.d.ts | 12 + .../lib/types/api/session-search.js | 22 + .../lib/types/api/sessions.d.ts | 407 + .../lib/types/api/sessions.js | 7 + .../lib/types/api/sessions.schema.d.ts | 279 + .../lib/types/api/sessions.schema.js | 282 + .../lib/types/api/settings.d.ts | 113 + .../lib/types/api/settings.js | 9 + .../lib/types/api/settings.schema.d.ts | 115 + .../lib/types/api/settings.schema.js | 65 + .../lib/types/api/skills.d.ts | 35 + .../dsh-host-apiproxy/lib/types/api/skills.js | 8 + .../lib/types/api/skills.schema.d.ts | 26 + .../lib/types/api/skills.schema.js | 22 + .../lib/types/api/subagents.d.ts | 101 + .../lib/types/api/subagents.js | 7 + .../lib/types/api/subagents.schema.d.ts | 79 + .../lib/types/api/subagents.schema.js | 74 + .../lib/types/api/workspace.d.ts | 121 + .../lib/types/api/workspace.js | 8 + .../lib/types/api/workspace.schema.d.ts | 105 + .../lib/types/api/workspace.schema.js | 78 + .../lib/types/fetch/client.d.ts | 194 + .../lib/types/fetch/client.js | 370 + .../lib/types/fetch/handler.d.ts | 17 + .../lib/types/fetch/handler.js | 245 + .../dsh-host-apiproxy/lib/types/index.d.ts | 77 + .../dsh-host-apiproxy/lib/types/index.js | 83 + .../lib/types/invariant.d.ts | 16 + .../dsh-host-apiproxy/lib/types/invariant.js | 26 + .../lib/types/native-path-opener.d.ts | 50 + .../lib/types/native-path-opener.js | 161 + .../lib/types/session-export.d.ts | 106 + .../lib/types/session-export.js | 388 + .../node_modules/.bin/cordis | 55 + .../dsh-host-apiproxy/package.json | 93 + .../@deepseek-ai/dsh-host-directory-picker | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-jobs | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../@deepseek-ai/dsh-native-command | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../@deepseek-ai/dsh-session-projection-cache | 1 + .../@deepseek-ai/dsh-session-query | 1 + .../@deepseek-ai/dsh-session-title | 1 + .../node_modules/@deepseek-ai/dsh-settings | 1 + .../node_modules/@deepseek-ai/dsh-skill | 1 + .../node_modules/@deepseek-ai/dsh-subagent | 1 + .../node_modules/@deepseek-ai/dsh-tools | 1 + .../@deepseek-ai/dsh-user-approval | 1 + .../@deepseek-ai/dsh-user-questions | 1 + .../node_modules/@deepseek-ai/dsh-workspace | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/fflate | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-agent-default-model | 1 + .../@deepseek-ai/dsh-agent-presets | 1 + .../node_modules/@deepseek-ai/dsh-api-remotes | 1 + .../node_modules/@deepseek-ai/dsh-attachment | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-commands | 1 + .../@deepseek-ai/dsh-cordis-host-runner | 1 + .../node_modules/@deepseek-ai/dsh-credentials | 1 + .../node_modules/@deepseek-ai/dsh-goal | 1 + .../@deepseek-ai/dsh-host-apiproxy/LICENSE | 21 + .../dsh-host-apiproxy/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-host-apiproxy/README.md | 83 + .../dsh-host-apiproxy/README.zh.md | 83 + .../dsh-host-apiproxy/lib/index.js | 5587 +++++++++ .../dsh-host-apiproxy/lib/invariant.js | 27 + .../lib/types/api-proxy.d.ts | 70 + .../dsh-host-apiproxy/lib/types/api-proxy.js | 3397 +++++ .../lib/types/api/agent-presets.d.ts | 130 + .../lib/types/api/agent-presets.js | 12 + .../lib/types/api/agent-presets.schema.d.ts | 78 + .../lib/types/api/agent-presets.schema.js | 70 + .../lib/types/api/approvals.d.ts | 20 + .../lib/types/api/approvals.js | 8 + .../lib/types/api/approvals.schema.d.ts | 16 + .../lib/types/api/approvals.schema.js | 16 + .../lib/types/api/credentials.d.ts | 49 + .../lib/types/api/credentials.js | 10 + .../lib/types/api/credentials.schema.d.ts | 41 + .../lib/types/api/credentials.schema.js | 37 + .../lib/types/api/downloads.d.ts | 24 + .../lib/types/api/downloads.js | 8 + .../lib/types/api/downloads.schema.d.ts | 24 + .../lib/types/api/downloads.schema.js | 24 + .../lib/types/api/events.d.ts | 213 + .../dsh-host-apiproxy/lib/types/api/events.js | 9 + .../lib/types/api/events.schema.d.ts | 28 + .../lib/types/api/events.schema.js | 84 + .../lib/types/api/goals.d.ts | 73 + .../dsh-host-apiproxy/lib/types/api/goals.js | 12 + .../lib/types/api/goals.schema.d.ts | 35 + .../lib/types/api/goals.schema.js | 63 + .../dsh-host-apiproxy/lib/types/api/host.d.ts | 91 + .../dsh-host-apiproxy/lib/types/api/host.js | 6 + .../lib/types/api/host.schema.d.ts | 65 + .../lib/types/api/host.schema.js | 58 + .../lib/types/api/index.d.ts | 63 + .../dsh-host-apiproxy/lib/types/api/index.js | 11 + .../dsh-host-apiproxy/lib/types/api/jobs.d.ts | 35 + .../dsh-host-apiproxy/lib/types/api/jobs.js | 7 + .../lib/types/api/jobs.schema.d.ts | 23 + .../lib/types/api/jobs.schema.js | 28 + .../dsh-host-apiproxy/lib/types/api/llm.d.ts | 88 + .../dsh-host-apiproxy/lib/types/api/llm.js | 11 + .../lib/types/api/llm.schema.d.ts | 79 + .../lib/types/api/llm.schema.js | 53 + .../lib/types/api/questions.d.ts | 18 + .../lib/types/api/questions.js | 8 + .../lib/types/api/questions.schema.d.ts | 26 + .../lib/types/api/questions.schema.js | 21 + .../lib/types/api/rpc-map.d.ts | 80 + .../lib/types/api/rpc-map.js | 7 + .../dsh-host-apiproxy/lib/types/api/rpc.d.ts | 263 + .../dsh-host-apiproxy/lib/types/api/rpc.js | 30 + .../lib/types/api/rpc.schema.d.ts | 60 + .../lib/types/api/rpc.schema.js | 114 + .../lib/types/api/session-search.d.ts | 12 + .../lib/types/api/session-search.js | 22 + .../lib/types/api/sessions.d.ts | 407 + .../lib/types/api/sessions.js | 7 + .../lib/types/api/sessions.schema.d.ts | 279 + .../lib/types/api/sessions.schema.js | 282 + .../lib/types/api/settings.d.ts | 113 + .../lib/types/api/settings.js | 9 + .../lib/types/api/settings.schema.d.ts | 115 + .../lib/types/api/settings.schema.js | 65 + .../lib/types/api/skills.d.ts | 35 + .../dsh-host-apiproxy/lib/types/api/skills.js | 8 + .../lib/types/api/skills.schema.d.ts | 26 + .../lib/types/api/skills.schema.js | 22 + .../lib/types/api/subagents.d.ts | 101 + .../lib/types/api/subagents.js | 7 + .../lib/types/api/subagents.schema.d.ts | 79 + .../lib/types/api/subagents.schema.js | 74 + .../lib/types/api/workspace.d.ts | 121 + .../lib/types/api/workspace.js | 8 + .../lib/types/api/workspace.schema.d.ts | 105 + .../lib/types/api/workspace.schema.js | 78 + .../lib/types/fetch/client.d.ts | 194 + .../lib/types/fetch/client.js | 370 + .../lib/types/fetch/handler.d.ts | 17 + .../lib/types/fetch/handler.js | 245 + .../dsh-host-apiproxy/lib/types/index.d.ts | 77 + .../dsh-host-apiproxy/lib/types/index.js | 83 + .../lib/types/invariant.d.ts | 16 + .../dsh-host-apiproxy/lib/types/invariant.js | 26 + .../lib/types/native-path-opener.d.ts | 50 + .../lib/types/native-path-opener.js | 161 + .../lib/types/session-export.d.ts | 106 + .../lib/types/session-export.js | 388 + .../node_modules/.bin/cordis | 55 + .../dsh-host-apiproxy/package.json | 93 + .../@deepseek-ai/dsh-host-directory-picker | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-jobs | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../@deepseek-ai/dsh-native-command | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../@deepseek-ai/dsh-session-projection-cache | 1 + .../@deepseek-ai/dsh-session-query | 1 + .../@deepseek-ai/dsh-session-title | 1 + .../node_modules/@deepseek-ai/dsh-settings | 1 + .../node_modules/@deepseek-ai/dsh-skill | 1 + .../node_modules/@deepseek-ai/dsh-subagent | 1 + .../node_modules/@deepseek-ai/dsh-tools | 1 + .../@deepseek-ai/dsh-user-approval | 1 + .../@deepseek-ai/dsh-user-questions | 1 + .../node_modules/@deepseek-ai/dsh-workspace | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/fflate | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../dsh-host-directory-picker/LICENSE | 21 + .../README.i18n.yaml | 6 + .../dsh-host-directory-picker/README.md | 19 + .../dsh-host-directory-picker/README.zh.md | 19 + .../dsh-host-directory-picker/lib/index.js | 44 + .../lib/invariant.js | 20 + .../lib/types/index.d.ts | 128 + .../lib/types/invariant.d.ts | 13 + .../node_modules/.bin/cordis | 55 + .../dsh-host-directory-picker/package.json | 42 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../dsh-host-directory-picker/LICENSE | 21 + .../README.i18n.yaml | 6 + .../dsh-host-directory-picker/README.md | 19 + .../dsh-host-directory-picker/README.zh.md | 19 + .../dsh-host-directory-picker/lib/index.js | 44 + .../lib/invariant.js | 20 + .../lib/types/index.d.ts | 128 + .../lib/types/invariant.d.ts | 13 + .../node_modules/.bin/cordis | 55 + .../dsh-host-directory-picker/package.json | 42 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/cordis-plugin-loader | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../dsh-host-plugin-inventory/LICENSE | 21 + .../README.i18n.yaml | 6 + .../dsh-host-plugin-inventory/README.md | 22 + .../dsh-host-plugin-inventory/README.zh.md | 22 + .../dsh-host-plugin-inventory/lib/index.js | 118 + .../lib/invariant.js | 13 + .../lib/typert.host.d.ts | 3 + .../lib/typert.host.js | 40 + .../lib/typert.remote-client.d.ts | 22 + .../lib/typert.remote-client.js | 34 + .../lib/types/index.d.ts | 19 + .../lib/types/index.js | 100 + .../lib/types/invariant.d.ts | 9 + .../lib/types/invariant.js | 12 + .../lib/types/types.d.ts | 19 + .../lib/types/types.js | 2 + .../node_modules/.bin/cordis | 55 + .../dsh-host-plugin-inventory/package.json | 68 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/cordis-plugin-loader | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../dsh-host-plugin-inventory/LICENSE | 21 + .../README.i18n.yaml | 6 + .../dsh-host-plugin-inventory/README.md | 22 + .../dsh-host-plugin-inventory/README.zh.md | 22 + .../dsh-host-plugin-inventory/lib/index.js | 118 + .../lib/invariant.js | 13 + .../lib/typert.host.d.ts | 3 + .../lib/typert.host.js | 40 + .../lib/typert.remote-client.d.ts | 22 + .../lib/typert.remote-client.js | 34 + .../lib/types/index.d.ts | 19 + .../lib/types/index.js | 100 + .../lib/types/invariant.d.ts | 9 + .../lib/types/invariant.js | 12 + .../lib/types/types.d.ts | 19 + .../lib/types/types.js | 2 + .../node_modules/.bin/cordis | 55 + .../dsh-host-plugin-inventory/package.json | 68 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-host-webserver/LICENSE | 21 + .../dsh-host-webserver/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-host-webserver/README.md | 22 + .../dsh-host-webserver/README.zh.md | 22 + .../dsh-host-webserver/lib/index.js | 217 + .../dsh-host-webserver/lib/invariant.js | 50 + .../dsh-host-webserver/lib/types/index.d.ts | 109 + .../lib/types/invariant.d.ts | 16 + .../node_modules/.bin/cordis | 55 + .../dsh-host-webserver/package.json | 45 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-host-webserver/LICENSE | 21 + .../dsh-host-webserver/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-host-webserver/README.md | 22 + .../dsh-host-webserver/README.zh.md | 22 + .../dsh-host-webserver/lib/index.js | 217 + .../dsh-host-webserver/lib/invariant.js | 50 + .../dsh-host-webserver/lib/types/index.d.ts | 109 + .../lib/types/invariant.d.ts | 16 + .../node_modules/.bin/cordis | 55 + .../dsh-host-webserver/package.json | 45 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-invariants/LICENSE | 21 + .../dsh-invariants/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-invariants/README.md | 85 + .../@deepseek-ai/dsh-invariants/README.zh.md | 85 + .../@deepseek-ai/dsh-invariants/lib/index.js | 123 + .../dsh-invariants/lib/invariant.js | 23 + .../dsh-invariants/lib/types/index.d.ts | 83 + .../dsh-invariants/lib/types/invariant.d.ts | 16 + .../dsh-invariants/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-invariants/package.json | 43 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/dsh-invariants/LICENSE | 21 + .../dsh-invariants/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-invariants/README.md | 85 + .../@deepseek-ai/dsh-invariants/README.zh.md | 85 + .../@deepseek-ai/dsh-invariants/lib/index.js | 123 + .../dsh-invariants/lib/invariant.js | 23 + .../dsh-invariants/lib/types/index.d.ts | 83 + .../dsh-invariants/lib/types/invariant.d.ts | 16 + .../dsh-invariants/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-invariants/package.json | 43 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-jobs/LICENSE | 21 + .../@deepseek-ai/dsh-jobs/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-jobs/README.md | 40 + .../@deepseek-ai/dsh-jobs/README.zh.md | 40 + .../@deepseek-ai/dsh-jobs/lib/index.js | 65 + .../@deepseek-ai/dsh-jobs/lib/invariant.js | 40 + .../dsh-jobs/lib/types/brand.d.ts | 24 + .../@deepseek-ai/dsh-jobs/lib/types/brand.js | 20 + .../dsh-jobs/lib/types/index.d.ts | 145 + .../@deepseek-ai/dsh-jobs/lib/types/index.js | 49 + .../dsh-jobs/lib/types/invariant.d.ts | 13 + .../dsh-jobs/lib/types/invariant.js | 47 + .../dsh-jobs/lib/types/types.d.ts | 146 + .../@deepseek-ai/dsh-jobs/lib/types/types.js | 7 + .../dsh-jobs/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-jobs/package.json | 53 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-jobs/LICENSE | 21 + .../@deepseek-ai/dsh-jobs/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-jobs/README.md | 40 + .../@deepseek-ai/dsh-jobs/README.zh.md | 40 + .../@deepseek-ai/dsh-jobs/lib/index.js | 65 + .../@deepseek-ai/dsh-jobs/lib/invariant.js | 40 + .../dsh-jobs/lib/types/brand.d.ts | 24 + .../@deepseek-ai/dsh-jobs/lib/types/brand.js | 20 + .../dsh-jobs/lib/types/index.d.ts | 145 + .../@deepseek-ai/dsh-jobs/lib/types/index.js | 49 + .../dsh-jobs/lib/types/invariant.d.ts | 13 + .../dsh-jobs/lib/types/invariant.js | 47 + .../dsh-jobs/lib/types/types.d.ts | 146 + .../@deepseek-ai/dsh-jobs/lib/types/types.js | 7 + .../dsh-jobs/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-jobs/package.json | 53 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-attachment | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm/LICENSE | 21 + .../@deepseek-ai/dsh-llm/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-llm/README.md | 101 + .../@deepseek-ai/dsh-llm/README.zh.md | 101 + .../@deepseek-ai/dsh-llm/lib/index.js | 1407 +++ .../@deepseek-ai/dsh-llm/lib/invariant.js | 84 + .../dsh-llm/lib/types/adapter-failure.d.ts | 14 + .../dsh-llm/lib/types/adapter-failure.js | 105 + .../dsh-llm/lib/types/api-key.d.ts | 28 + .../@deepseek-ai/dsh-llm/lib/types/api-key.js | 34 + .../dsh-llm/lib/types/assembler.d.ts | 56 + .../dsh-llm/lib/types/assembler.js | 148 + .../dsh-llm/lib/types/attribution.d.ts | 47 + .../dsh-llm/lib/types/attribution.js | 46 + .../@deepseek-ai/dsh-llm/lib/types/brand.d.ts | 48 + .../@deepseek-ai/dsh-llm/lib/types/brand.js | 44 + .../dsh-llm/lib/types/call-config.d.ts | 62 + .../dsh-llm/lib/types/call-config.js | 86 + .../dsh-llm/lib/types/content.d.ts | 12 + .../@deepseek-ai/dsh-llm/lib/types/content.js | 14 + .../@deepseek-ai/dsh-llm/lib/types/error.d.ts | 73 + .../@deepseek-ai/dsh-llm/lib/types/error.js | 145 + .../@deepseek-ai/dsh-llm/lib/types/index.d.ts | 341 + .../@deepseek-ai/dsh-llm/lib/types/index.js | 730 ++ .../dsh-llm/lib/types/invariant.d.ts | 13 + .../dsh-llm/lib/types/invariant.js | 100 + .../dsh-llm/lib/types/message.d.ts | 206 + .../@deepseek-ai/dsh-llm/lib/types/message.js | 100 + .../@deepseek-ai/dsh-llm/lib/types/never.d.ts | 16 + .../@deepseek-ai/dsh-llm/lib/types/never.js | 21 + .../dsh-llm/lib/types/retry-policy.d.ts | 66 + .../dsh-llm/lib/types/retry-policy.js | 123 + .../@deepseek-ai/dsh-llm/lib/types/types.d.ts | 349 + .../@deepseek-ai/dsh-llm/lib/types/types.js | 7 + .../dsh-llm/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-llm/package.json | 64 + .../node_modules/@deepseek-ai/dsh-timeout | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-attachment | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm/LICENSE | 21 + .../@deepseek-ai/dsh-llm/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-llm/README.md | 101 + .../@deepseek-ai/dsh-llm/README.zh.md | 101 + .../@deepseek-ai/dsh-llm/lib/index.js | 1436 +++ .../@deepseek-ai/dsh-llm/lib/invariant.js | 84 + .../dsh-llm/lib/types/adapter-failure.d.ts | 14 + .../dsh-llm/lib/types/adapter-failure.js | 105 + .../dsh-llm/lib/types/api-key.d.ts | 28 + .../@deepseek-ai/dsh-llm/lib/types/api-key.js | 34 + .../dsh-llm/lib/types/assembler.d.ts | 66 + .../dsh-llm/lib/types/assembler.js | 172 + .../dsh-llm/lib/types/attribution.d.ts | 47 + .../dsh-llm/lib/types/attribution.js | 46 + .../@deepseek-ai/dsh-llm/lib/types/brand.d.ts | 48 + .../@deepseek-ai/dsh-llm/lib/types/brand.js | 44 + .../dsh-llm/lib/types/call-config.d.ts | 62 + .../dsh-llm/lib/types/call-config.js | 86 + .../dsh-llm/lib/types/content.d.ts | 12 + .../@deepseek-ai/dsh-llm/lib/types/content.js | 14 + .../@deepseek-ai/dsh-llm/lib/types/error.d.ts | 73 + .../@deepseek-ai/dsh-llm/lib/types/error.js | 145 + .../@deepseek-ai/dsh-llm/lib/types/index.d.ts | 341 + .../@deepseek-ai/dsh-llm/lib/types/index.js | 730 ++ .../dsh-llm/lib/types/invariant.d.ts | 13 + .../dsh-llm/lib/types/invariant.js | 100 + .../dsh-llm/lib/types/message.d.ts | 206 + .../@deepseek-ai/dsh-llm/lib/types/message.js | 100 + .../@deepseek-ai/dsh-llm/lib/types/never.d.ts | 16 + .../@deepseek-ai/dsh-llm/lib/types/never.js | 21 + .../dsh-llm/lib/types/retry-policy.d.ts | 66 + .../dsh-llm/lib/types/retry-policy.js | 123 + .../@deepseek-ai/dsh-llm/lib/types/types.d.ts | 369 + .../@deepseek-ai/dsh-llm/lib/types/types.js | 7 + .../dsh-llm/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-llm/package.json | 64 + .../node_modules/@deepseek-ai/dsh-timeout | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../@deepseek-ai/dsh-message-feedback/LICENSE | 21 + .../dsh-message-feedback/README.i18n.yaml | 6 + .../dsh-message-feedback/README.md | 84 + .../dsh-message-feedback/README.zh.md | 84 + .../dsh-message-feedback/lib/index.js | 420 + .../dsh-message-feedback/lib/invariant.js | 20 + .../dsh-message-feedback/lib/typert.host.d.ts | 3 + .../dsh-message-feedback/lib/typert.host.js | 307 + .../lib/typert.remote-client.d.ts | 26 + .../lib/typert.remote-client.js | 179 + .../dsh-message-feedback/lib/types/index.d.ts | 88 + .../dsh-message-feedback/lib/types/index.js | 342 + .../lib/types/invariant.d.ts | 13 + .../lib/types/invariant.js | 19 + .../dsh-message-feedback/lib/types/spec.d.ts | 48 + .../dsh-message-feedback/lib/types/spec.js | 74 + .../dsh-message-feedback/lib/types/types.d.ts | 111 + .../dsh-message-feedback/lib/types/types.js | 8 + .../node_modules/.bin/cordis | 55 + .../dsh-message-feedback/package.json | 80 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-storage-domain | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../@deepseek-ai/dsh-message-feedback/LICENSE | 21 + .../dsh-message-feedback/README.i18n.yaml | 6 + .../dsh-message-feedback/README.md | 84 + .../dsh-message-feedback/README.zh.md | 84 + .../dsh-message-feedback/lib/index.js | 420 + .../dsh-message-feedback/lib/invariant.js | 20 + .../dsh-message-feedback/lib/typert.host.d.ts | 3 + .../dsh-message-feedback/lib/typert.host.js | 307 + .../lib/typert.remote-client.d.ts | 26 + .../lib/typert.remote-client.js | 179 + .../dsh-message-feedback/lib/types/index.d.ts | 88 + .../dsh-message-feedback/lib/types/index.js | 342 + .../lib/types/invariant.d.ts | 13 + .../lib/types/invariant.js | 19 + .../dsh-message-feedback/lib/types/spec.d.ts | 48 + .../dsh-message-feedback/lib/types/spec.js | 74 + .../dsh-message-feedback/lib/types/types.d.ts | 111 + .../dsh-message-feedback/lib/types/types.js | 8 + .../node_modules/.bin/cordis | 55 + .../dsh-message-feedback/package.json | 80 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-storage-domain | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-native-command/LICENSE | 21 + .../dsh-native-command/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-native-command/README.md | 27 + .../dsh-native-command/README.zh.md | 27 + .../dsh-native-command/lib/index.js | 38 + .../dsh-native-command/lib/invariant.js | 24 + .../dsh-native-command/lib/types/index.d.ts | 21 + .../lib/types/invariant.d.ts | 16 + .../node_modules/.bin/cordis | 55 + .../dsh-native-command/package.json | 42 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-native-command/LICENSE | 21 + .../dsh-native-command/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-native-command/README.md | 27 + .../dsh-native-command/README.zh.md | 27 + .../dsh-native-command/lib/index.js | 38 + .../dsh-native-command/lib/invariant.js | 24 + .../dsh-native-command/lib/types/index.d.ts | 21 + .../lib/types/invariant.d.ts | 16 + .../node_modules/.bin/cordis | 55 + .../dsh-native-command/package.json | 42 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-scope/LICENSE | 21 + .../@deepseek-ai/dsh-scope/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-scope/README.md | 37 + .../@deepseek-ai/dsh-scope/README.zh.md | 37 + .../@deepseek-ai/dsh-scope/lib/index.js | 357 + .../@deepseek-ai/dsh-scope/lib/invariant.js | 72 + .../dsh-scope/lib/types/index.d.ts | 110 + .../dsh-scope/lib/types/invariant.d.ts | 13 + .../lib/types/scoped-events.generated.d.ts | 18 + .../dsh-scope/lib/types/store.d.ts | 147 + .../dsh-scope/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-scope/package.json | 42 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-scope/LICENSE | 21 + .../@deepseek-ai/dsh-scope/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-scope/README.md | 37 + .../@deepseek-ai/dsh-scope/README.zh.md | 37 + .../@deepseek-ai/dsh-scope/lib/index.js | 357 + .../@deepseek-ai/dsh-scope/lib/invariant.js | 72 + .../dsh-scope/lib/types/index.d.ts | 110 + .../dsh-scope/lib/types/invariant.d.ts | 13 + .../lib/types/scoped-events.generated.d.ts | 18 + .../dsh-scope/lib/types/store.d.ts | 147 + .../dsh-scope/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-scope/package.json | 42 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../dsh-session-persistence/LICENSE | 21 + .../dsh-session-persistence/README.i18n.yaml | 6 + .../dsh-session-persistence/README.md | 85 + .../dsh-session-persistence/README.zh.md | 85 + .../dsh-session-persistence/lib/index.js | 1396 +++ .../dsh-session-persistence/lib/invariant.js | 23 + .../lib/types/coordinator.d.ts | 348 + .../lib/types/index.d.ts | 190 + .../lib/types/invariant.d.ts | 16 + .../lib/types/preparations.d.ts | 115 + .../lib/types/revision.d.ts | 14 + .../lib/types/write-behind.d.ts | 62 + .../node_modules/.bin/cordis | 55 + .../dsh-session-persistence/package.json | 49 + .../node_modules/@deepseek-ai/dsh-timeout | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../dsh-session-persistence/LICENSE | 21 + .../dsh-session-persistence/README.i18n.yaml | 6 + .../dsh-session-persistence/README.md | 85 + .../dsh-session-persistence/README.zh.md | 85 + .../dsh-session-persistence/lib/index.js | 1396 +++ .../dsh-session-persistence/lib/invariant.js | 23 + .../lib/types/coordinator.d.ts | 348 + .../lib/types/index.d.ts | 190 + .../lib/types/invariant.d.ts | 16 + .../lib/types/preparations.d.ts | 115 + .../lib/types/revision.d.ts | 14 + .../lib/types/write-behind.d.ts | 62 + .../node_modules/.bin/cordis | 55 + .../dsh-session-persistence/package.json | 49 + .../node_modules/@deepseek-ai/dsh-timeout | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../dsh-session-projection-cache/LICENSE | 21 + .../README.i18n.yaml | 6 + .../dsh-session-projection-cache/README.md | 62 + .../dsh-session-projection-cache/README.zh.md | 62 + .../dsh-session-projection-cache/lib/index.js | 286 + .../lib/invariant.js | 28 + .../lib/types/index.d.ts | 118 + .../lib/types/invariant.d.ts | 16 + .../lib/types/spec.d.ts | 82 + .../node_modules/.bin/cordis | 55 + .../dsh-session-projection-cache/package.json | 55 + .../@deepseek-ai/dsh-storage-domain | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../dsh-session-projection-cache/LICENSE | 21 + .../README.i18n.yaml | 6 + .../dsh-session-projection-cache/README.md | 62 + .../dsh-session-projection-cache/README.zh.md | 62 + .../dsh-session-projection-cache/lib/index.js | 286 + .../lib/invariant.js | 28 + .../lib/types/index.d.ts | 118 + .../lib/types/invariant.d.ts | 16 + .../lib/types/spec.d.ts | 82 + .../node_modules/.bin/cordis | 55 + .../dsh-session-projection-cache/package.json | 55 + .../@deepseek-ai/dsh-storage-domain | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../dsh-session-projection/LICENSE | 21 + .../dsh-session-projection/README.i18n.yaml | 6 + .../dsh-session-projection/README.md | 48 + .../dsh-session-projection/README.zh.md | 48 + .../dsh-session-projection/lib/index.js | 274 + .../dsh-session-projection/lib/invariant.js | 31 + .../lib/types/index.d.ts | 231 + .../dsh-session-projection/lib/types/index.js | 285 + .../lib/types/invariant.d.ts | 16 + .../lib/types/invariant.js | 30 + .../lib/types/types.d.ts | 18 + .../dsh-session-projection/lib/types/types.js | 11 + .../node_modules/.bin/cordis | 55 + .../dsh-session-projection/package.json | 52 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../dsh-session-projection/LICENSE | 21 + .../dsh-session-projection/README.i18n.yaml | 6 + .../dsh-session-projection/README.md | 48 + .../dsh-session-projection/README.zh.md | 48 + .../dsh-session-projection/lib/index.js | 274 + .../dsh-session-projection/lib/invariant.js | 31 + .../lib/types/index.d.ts | 231 + .../dsh-session-projection/lib/types/index.js | 285 + .../lib/types/invariant.d.ts | 16 + .../lib/types/invariant.js | 30 + .../lib/types/types.d.ts | 18 + .../dsh-session-projection/lib/types/types.js | 11 + .../node_modules/.bin/cordis | 55 + .../dsh-session-projection/package.json | 52 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-session-query/LICENSE | 21 + .../dsh-session-query/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-session-query/README.md | 56 + .../dsh-session-query/README.zh.md | 56 + .../dsh-session-query/lib/index.js | 969 ++ .../dsh-session-query/lib/invariant.js | 23 + .../dsh-session-query/lib/types/config.d.ts | 21 + .../dsh-session-query/lib/types/corpus.d.ts | 64 + .../dsh-session-query/lib/types/cursor.d.ts | 11 + .../lib/types/documents.d.ts | 18 + .../lib/types/extraction.d.ts | 12 + .../dsh-session-query/lib/types/filters.d.ts | 35 + .../dsh-session-query/lib/types/index.d.ts | 143 + .../lib/types/invariant.d.ts | 16 + .../dsh-session-query/lib/types/sources.d.ts | 9 + .../dsh-session-query/lib/types/tracing.d.ts | 33 + .../dsh-session-query/lib/types/types.d.ts | 259 + .../node_modules/.bin/cordis | 55 + .../dsh-session-query/package.json | 57 + .../@deepseek-ai/dsh-session-title | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-session-query/LICENSE | 21 + .../dsh-session-query/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-session-query/README.md | 56 + .../dsh-session-query/README.zh.md | 56 + .../dsh-session-query/lib/index.js | 969 ++ .../dsh-session-query/lib/invariant.js | 23 + .../dsh-session-query/lib/types/config.d.ts | 21 + .../dsh-session-query/lib/types/corpus.d.ts | 64 + .../dsh-session-query/lib/types/cursor.d.ts | 11 + .../lib/types/documents.d.ts | 18 + .../lib/types/extraction.d.ts | 12 + .../dsh-session-query/lib/types/filters.d.ts | 35 + .../dsh-session-query/lib/types/index.d.ts | 143 + .../lib/types/invariant.d.ts | 16 + .../dsh-session-query/lib/types/sources.d.ts | 9 + .../dsh-session-query/lib/types/tracing.d.ts | 33 + .../dsh-session-query/lib/types/types.d.ts | 259 + .../node_modules/.bin/cordis | 55 + .../dsh-session-query/package.json | 57 + .../@deepseek-ai/dsh-session-title | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../@deepseek-ai/dsh-session-title/LICENSE | 21 + .../dsh-session-title/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-session-title/README.md | 55 + .../dsh-session-title/README.zh.md | 55 + .../dsh-session-title/lib/index.js | 580 + .../dsh-session-title/lib/invariant.js | 38 + .../dsh-session-title/lib/types/client.d.ts | 10 + .../dsh-session-title/lib/types/client.js | 10 + .../dsh-session-title/lib/types/index.d.ts | 230 + .../dsh-session-title/lib/types/index.js | 601 + .../lib/types/invariant.d.ts | 16 + .../dsh-session-title/lib/types/invariant.js | 41 + .../lib/types/normalize.d.ts | 24 + .../dsh-session-title/lib/types/normalize.js | 71 + .../dsh-session-title/lib/types/types.d.ts | 21 + .../dsh-session-title/lib/types/types.js | 11 + .../node_modules/.bin/cordis | 55 + .../dsh-session-title/package.json | 65 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../@deepseek-ai/dsh-session-title/LICENSE | 21 + .../dsh-session-title/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-session-title/README.md | 55 + .../dsh-session-title/README.zh.md | 55 + .../dsh-session-title/lib/index.js | 580 + .../dsh-session-title/lib/invariant.js | 38 + .../dsh-session-title/lib/types/client.d.ts | 10 + .../dsh-session-title/lib/types/client.js | 10 + .../dsh-session-title/lib/types/index.d.ts | 230 + .../dsh-session-title/lib/types/index.js | 601 + .../lib/types/invariant.d.ts | 16 + .../dsh-session-title/lib/types/invariant.js | 41 + .../lib/types/normalize.d.ts | 24 + .../dsh-session-title/lib/types/normalize.js | 71 + .../dsh-session-title/lib/types/types.d.ts | 21 + .../dsh-session-title/lib/types/types.js | 11 + .../node_modules/.bin/cordis | 55 + .../dsh-session-title/package.json | 65 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../@deepseek-ai/dsh-session/LICENSE | 21 + .../@deepseek-ai/dsh-session/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-session/README.md | 144 + .../@deepseek-ai/dsh-session/README.zh.md | 144 + .../@deepseek-ai/dsh-session/lib/index.js | 1886 +++ .../@deepseek-ai/dsh-session/lib/invariant.js | 168 + .../dsh-session/lib/types/chunk-rows.d.ts | 92 + .../dsh-session/lib/types/chunk-rows.js | 301 + .../dsh-session/lib/types/index.d.ts | 418 + .../dsh-session/lib/types/index.js | 999 ++ .../dsh-session/lib/types/invariant.d.ts | 18 + .../dsh-session/lib/types/invariant.js | 199 + .../dsh-session/lib/types/json.d.ts | 36 + .../dsh-session/lib/types/json.js | 174 + .../lib/types/known-event-types.d.ts | 19 + .../lib/types/known-event-types.js | 64 + .../dsh-session/lib/types/preparation.d.ts | 33 + .../dsh-session/lib/types/preparation.js | 37 + .../dsh-session/lib/types/repair.d.ts | 22 + .../dsh-session/lib/types/repair.js | 126 + .../dsh-session/lib/types/request-header.d.ts | 35 + .../dsh-session/lib/types/request-header.js | 65 + .../dsh-session/lib/types/surface.d.ts | 123 + .../dsh-session/lib/types/surface.js | 377 + .../dsh-session/lib/types/types.d.ts | 453 + .../dsh-session/lib/types/types.js | 33 + .../dsh-session/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-session/package.json | 60 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../@deepseek-ai/dsh-session/LICENSE | 21 + .../@deepseek-ai/dsh-session/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-session/README.md | 144 + .../@deepseek-ai/dsh-session/README.zh.md | 144 + .../@deepseek-ai/dsh-session/lib/index.js | 1886 +++ .../@deepseek-ai/dsh-session/lib/invariant.js | 168 + .../dsh-session/lib/types/chunk-rows.d.ts | 92 + .../dsh-session/lib/types/chunk-rows.js | 301 + .../dsh-session/lib/types/index.d.ts | 418 + .../dsh-session/lib/types/index.js | 999 ++ .../dsh-session/lib/types/invariant.d.ts | 18 + .../dsh-session/lib/types/invariant.js | 199 + .../dsh-session/lib/types/json.d.ts | 36 + .../dsh-session/lib/types/json.js | 174 + .../lib/types/known-event-types.d.ts | 19 + .../lib/types/known-event-types.js | 64 + .../dsh-session/lib/types/preparation.d.ts | 33 + .../dsh-session/lib/types/preparation.js | 37 + .../dsh-session/lib/types/repair.d.ts | 22 + .../dsh-session/lib/types/repair.js | 126 + .../dsh-session/lib/types/request-header.d.ts | 35 + .../dsh-session/lib/types/request-header.js | 65 + .../dsh-session/lib/types/surface.d.ts | 123 + .../dsh-session/lib/types/surface.js | 377 + .../dsh-session/lib/types/types.d.ts | 453 + .../dsh-session/lib/types/types.js | 33 + .../dsh-session/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-session/package.json | 60 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-settings/LICENSE | 21 + .../dsh-settings/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-settings/README.md | 45 + .../@deepseek-ai/dsh-settings/README.zh.md | 45 + .../@deepseek-ai/dsh-settings/lib/index.js | 638 + .../dsh-settings/lib/invariant.js | 180 + .../dsh-settings/lib/types/index.d.ts | 343 + .../dsh-settings/lib/types/index.js | 688 ++ .../dsh-settings/lib/types/invariant.d.ts | 16 + .../dsh-settings/lib/types/invariant.js | 41 + .../dsh-settings/lib/types/redact.d.ts | 40 + .../dsh-settings/lib/types/redact.js | 78 + .../dsh-settings/lib/types/types.d.ts | 46 + .../dsh-settings/lib/types/types.js | 10 + .../dsh-settings/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-settings/package.json | 51 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-settings/LICENSE | 21 + .../dsh-settings/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-settings/README.md | 45 + .../@deepseek-ai/dsh-settings/README.zh.md | 45 + .../@deepseek-ai/dsh-settings/lib/index.js | 638 + .../dsh-settings/lib/invariant.js | 180 + .../dsh-settings/lib/types/index.d.ts | 343 + .../dsh-settings/lib/types/index.js | 688 ++ .../dsh-settings/lib/types/invariant.d.ts | 16 + .../dsh-settings/lib/types/invariant.js | 41 + .../dsh-settings/lib/types/redact.d.ts | 40 + .../dsh-settings/lib/types/redact.js | 78 + .../dsh-settings/lib/types/types.d.ts | 46 + .../dsh-settings/lib/types/types.js | 10 + .../dsh-settings/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-settings/package.json | 51 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../@deepseek-ai/dsh-skill/LICENSE | 21 + .../@deepseek-ai/dsh-skill/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-skill/README.md | 79 + .../@deepseek-ai/dsh-skill/README.zh.md | 79 + .../@deepseek-ai/dsh-skill/lib/index.js | 565 + .../@deepseek-ai/dsh-skill/lib/invariant.js | 23 + .../dsh-skill/lib/types/index.d.ts | 300 + .../dsh-skill/lib/types/invariant.d.ts | 16 + .../dsh-skill/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-skill/package.json | 49 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../@deepseek-ai/dsh-skill/LICENSE | 21 + .../@deepseek-ai/dsh-skill/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-skill/README.md | 79 + .../@deepseek-ai/dsh-skill/README.zh.md | 79 + .../@deepseek-ai/dsh-skill/lib/index.js | 565 + .../@deepseek-ai/dsh-skill/lib/invariant.js | 23 + .../dsh-skill/lib/types/index.d.ts | 300 + .../dsh-skill/lib/types/invariant.d.ts | 16 + .../dsh-skill/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-skill/package.json | 49 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-storage | 1 + .../@deepseek-ai/dsh-storage-domain/LICENSE | 21 + .../dsh-storage-domain/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-storage-domain/README.md | 35 + .../dsh-storage-domain/README.zh.md | 35 + .../dsh-storage-domain/lib/index.js | 430 + .../dsh-storage-domain/lib/invariant.js | 45 + .../dsh-storage-domain/lib/types/domain.d.ts | 166 + .../dsh-storage-domain/lib/types/error.d.ts | 37 + .../dsh-storage-domain/lib/types/events.d.ts | 44 + .../dsh-storage-domain/lib/types/index.d.ts | 104 + .../lib/types/invariant.d.ts | 22 + .../dsh-storage-domain/lib/types/spec.d.ts | 72 + .../node_modules/.bin/cordis | 55 + .../dsh-storage-domain/package.json | 48 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-storage | 1 + .../@deepseek-ai/dsh-storage-domain/LICENSE | 21 + .../dsh-storage-domain/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-storage-domain/README.md | 35 + .../dsh-storage-domain/README.zh.md | 35 + .../dsh-storage-domain/lib/index.js | 430 + .../dsh-storage-domain/lib/invariant.js | 45 + .../dsh-storage-domain/lib/types/domain.d.ts | 166 + .../dsh-storage-domain/lib/types/error.d.ts | 37 + .../dsh-storage-domain/lib/types/events.d.ts | 44 + .../dsh-storage-domain/lib/types/index.d.ts | 104 + .../lib/types/invariant.d.ts | 22 + .../dsh-storage-domain/lib/types/spec.d.ts | 72 + .../node_modules/.bin/cordis | 55 + .../dsh-storage-domain/package.json | 48 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-storage/LICENSE | 21 + .../@deepseek-ai/dsh-storage/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-storage/README.md | 32 + .../@deepseek-ai/dsh-storage/README.zh.md | 32 + .../@deepseek-ai/dsh-storage/lib/index.js | 140 + .../@deepseek-ai/dsh-storage/lib/invariant.js | 25 + .../dsh-storage/lib/types/backend.d.ts | 98 + .../dsh-storage/lib/types/error.d.ts | 21 + .../dsh-storage/lib/types/index.d.ts | 64 + .../dsh-storage/lib/types/invariant.d.ts | 16 + .../dsh-storage/lib/types/registry.d.ts | 34 + .../dsh-storage/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-storage/package.json | 42 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-storage/LICENSE | 21 + .../@deepseek-ai/dsh-storage/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-storage/README.md | 32 + .../@deepseek-ai/dsh-storage/README.zh.md | 32 + .../@deepseek-ai/dsh-storage/lib/index.js | 140 + .../@deepseek-ai/dsh-storage/lib/invariant.js | 25 + .../dsh-storage/lib/types/backend.d.ts | 98 + .../dsh-storage/lib/types/error.d.ts | 21 + .../dsh-storage/lib/types/index.d.ts | 64 + .../dsh-storage/lib/types/invariant.d.ts | 16 + .../dsh-storage/lib/types/registry.d.ts | 34 + .../dsh-storage/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-storage/package.json | 42 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-agent-presets | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-jobs | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../@deepseek-ai/dsh-session-projection-cache | 1 + .../@deepseek-ai/dsh-subagent/LICENSE | 21 + .../dsh-subagent/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-subagent/README.md | 154 + .../@deepseek-ai/dsh-subagent/README.zh.md | 154 + .../@deepseek-ai/dsh-subagent/lib/index.js | 2572 ++++ .../dsh-subagent/lib/invariant.js | 76 + .../lib/types/activation-setup-registry.d.ts | 57 + .../lib/types/activation-setup-registry.js | 148 + .../lib/types/assistant-output.d.ts | 48 + .../lib/types/assistant-output.js | 72 + .../dsh-subagent/lib/types/child-agent.d.ts | 139 + .../dsh-subagent/lib/types/child-agent.js | 169 + .../dsh-subagent/lib/types/client.d.ts | 7 + .../dsh-subagent/lib/types/client.js | 7 + .../dsh-subagent/lib/types/continuation.d.ts | 436 + .../dsh-subagent/lib/types/continuation.js | 1100 ++ .../dsh-subagent/lib/types/depth.d.ts | 31 + .../dsh-subagent/lib/types/depth.js | 39 + .../lib/types/descriptor-seed.d.ts | 21 + .../dsh-subagent/lib/types/descriptor-seed.js | 24 + .../dsh-subagent/lib/types/descriptor.d.ts | 139 + .../dsh-subagent/lib/types/descriptor.js | 189 + .../dsh-subagent/lib/types/error.d.ts | 11 + .../dsh-subagent/lib/types/error.js | 14 + .../dsh-subagent/lib/types/index.d.ts | 279 + .../dsh-subagent/lib/types/index.js | 339 + .../dsh-subagent/lib/types/invariant.d.ts | 13 + .../dsh-subagent/lib/types/invariant.js | 91 + .../dsh-subagent/lib/types/lifecycle.d.ts | 113 + .../dsh-subagent/lib/types/lifecycle.js | 177 + .../dsh-subagent/lib/types/list-children.d.ts | 112 + .../dsh-subagent/lib/types/list-children.js | 316 + .../lib/types/out-of-process.d.ts | 115 + .../dsh-subagent/lib/types/out-of-process.js | 181 + .../lib/types/projection-types.d.ts | 60 + .../lib/types/projection-types.js | 7 + .../dsh-subagent/lib/types/projection.d.ts | 48 + .../dsh-subagent/lib/types/projection.js | 135 + .../lib/types/run-settlement.d.ts | 17 + .../dsh-subagent/lib/types/run-settlement.js | 59 + .../dsh-subagent/lib/types/types.d.ts | 308 + .../dsh-subagent/lib/types/types.js | 19 + .../dsh-subagent/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-subagent/package.json | 106 + .../node_modules/@deepseek-ai/dsh-tools | 1 + .../@deepseek-ai/dsh-user-approval | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-agent-presets | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-jobs | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../@deepseek-ai/dsh-session-projection-cache | 1 + .../@deepseek-ai/dsh-subagent/LICENSE | 21 + .../dsh-subagent/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-subagent/README.md | 154 + .../@deepseek-ai/dsh-subagent/README.zh.md | 154 + .../@deepseek-ai/dsh-subagent/lib/index.js | 2572 ++++ .../dsh-subagent/lib/invariant.js | 76 + .../lib/types/activation-setup-registry.d.ts | 57 + .../lib/types/activation-setup-registry.js | 148 + .../lib/types/assistant-output.d.ts | 48 + .../lib/types/assistant-output.js | 72 + .../dsh-subagent/lib/types/child-agent.d.ts | 139 + .../dsh-subagent/lib/types/child-agent.js | 169 + .../dsh-subagent/lib/types/client.d.ts | 7 + .../dsh-subagent/lib/types/client.js | 7 + .../dsh-subagent/lib/types/continuation.d.ts | 436 + .../dsh-subagent/lib/types/continuation.js | 1100 ++ .../dsh-subagent/lib/types/depth.d.ts | 31 + .../dsh-subagent/lib/types/depth.js | 39 + .../lib/types/descriptor-seed.d.ts | 21 + .../dsh-subagent/lib/types/descriptor-seed.js | 24 + .../dsh-subagent/lib/types/descriptor.d.ts | 139 + .../dsh-subagent/lib/types/descriptor.js | 189 + .../dsh-subagent/lib/types/error.d.ts | 11 + .../dsh-subagent/lib/types/error.js | 14 + .../dsh-subagent/lib/types/index.d.ts | 279 + .../dsh-subagent/lib/types/index.js | 339 + .../dsh-subagent/lib/types/invariant.d.ts | 13 + .../dsh-subagent/lib/types/invariant.js | 91 + .../dsh-subagent/lib/types/lifecycle.d.ts | 113 + .../dsh-subagent/lib/types/lifecycle.js | 177 + .../dsh-subagent/lib/types/list-children.d.ts | 112 + .../dsh-subagent/lib/types/list-children.js | 316 + .../lib/types/out-of-process.d.ts | 115 + .../dsh-subagent/lib/types/out-of-process.js | 181 + .../lib/types/projection-types.d.ts | 60 + .../lib/types/projection-types.js | 7 + .../dsh-subagent/lib/types/projection.d.ts | 48 + .../dsh-subagent/lib/types/projection.js | 135 + .../lib/types/run-settlement.d.ts | 17 + .../dsh-subagent/lib/types/run-settlement.js | 59 + .../dsh-subagent/lib/types/types.d.ts | 308 + .../dsh-subagent/lib/types/types.js | 19 + .../dsh-subagent/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-subagent/package.json | 106 + .../node_modules/@deepseek-ai/dsh-tools | 1 + .../@deepseek-ai/dsh-user-approval | 1 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../@deepseek-ai/dsh-system-prompt/LICENSE | 21 + .../dsh-system-prompt/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-system-prompt/README.md | 90 + .../dsh-system-prompt/README.zh.md | 92 + .../dsh-system-prompt/lib/index.js | 293 + .../dsh-system-prompt/lib/invariant.js | 49 + .../dsh-system-prompt/lib/types/index.d.ts | 231 + .../lib/types/invariant.d.ts | 13 + .../node_modules/.bin/cordis | 55 + .../dsh-system-prompt/package.json | 49 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../@deepseek-ai/dsh-system-prompt/LICENSE | 21 + .../dsh-system-prompt/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-system-prompt/README.md | 90 + .../dsh-system-prompt/README.zh.md | 92 + .../dsh-system-prompt/lib/index.js | 293 + .../dsh-system-prompt/lib/invariant.js | 49 + .../dsh-system-prompt/lib/types/index.d.ts | 231 + .../lib/types/invariant.d.ts | 13 + .../node_modules/.bin/cordis | 55 + .../dsh-system-prompt/package.json | 49 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-timeout/LICENSE | 21 + .../@deepseek-ai/dsh-timeout/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-timeout/README.md | 70 + .../@deepseek-ai/dsh-timeout/README.zh.md | 70 + .../@deepseek-ai/dsh-timeout/lib/index.js | 140 + .../@deepseek-ai/dsh-timeout/lib/invariant.js | 23 + .../dsh-timeout/lib/types/index.d.ts | 93 + .../dsh-timeout/lib/types/invariant.d.ts | 16 + .../dsh-timeout/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-timeout/package.json | 42 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-timeout/LICENSE | 21 + .../@deepseek-ai/dsh-timeout/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-timeout/README.md | 70 + .../@deepseek-ai/dsh-timeout/README.zh.md | 70 + .../@deepseek-ai/dsh-timeout/lib/index.js | 140 + .../@deepseek-ai/dsh-timeout/lib/invariant.js | 23 + .../dsh-timeout/lib/types/index.d.ts | 93 + .../dsh-timeout/lib/types/invariant.d.ts | 16 + .../dsh-timeout/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-timeout/package.json | 42 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-code-runtime | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-system-prompt | 1 + .../@deepseek-ai/dsh-tools/LICENSE | 21 + .../@deepseek-ai/dsh-tools/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-tools/README.md | 198 + .../@deepseek-ai/dsh-tools/README.zh.md | 198 + .../@deepseek-ai/dsh-tools/lib/index.js | 3570 ++++++ .../@deepseek-ai/dsh-tools/lib/invariant.js | 100 + .../dsh-tools/lib/types/code-mode.d.ts | 68 + .../dsh-tools/lib/types/code-mode.js | 572 + .../dsh-tools/lib/types/index.d.ts | 819 ++ .../@deepseek-ai/dsh-tools/lib/types/index.js | 1326 ++ .../dsh-tools/lib/types/invariant.d.ts | 13 + .../dsh-tools/lib/types/invariant.js | 123 + .../dsh-tools/lib/types/json-schema.d.ts | 106 + .../dsh-tools/lib/types/json-schema.js | 577 + .../dsh-tools/lib/types/presentation.d.ts | 367 + .../dsh-tools/lib/types/presentation.js | 8 + .../dsh-tools/lib/types/py-types.d.ts | 49 + .../dsh-tools/lib/types/py-types.js | 788 ++ .../dsh-tools/lib/types/schema.d.ts | 241 + .../dsh-tools/lib/types/schema.js | 349 + .../dsh-tools/lib/types/testing.d.ts | 25 + .../dsh-tools/lib/types/testing.js | 25 + .../dsh-tools/lib/types/ts-types.d.ts | 37 + .../dsh-tools/lib/types/ts-types.js | 265 + .../dsh-tools/lib/types/types.d.ts | 55 + .../@deepseek-ai/dsh-tools/lib/types/types.js | 7 + .../dsh-tools/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-tools/package.json | 68 + .../@deepseek-ai/dsh-user-approval | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-code-runtime | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-system-prompt | 1 + .../@deepseek-ai/dsh-tools/LICENSE | 21 + .../@deepseek-ai/dsh-tools/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-tools/README.md | 198 + .../@deepseek-ai/dsh-tools/README.zh.md | 198 + .../@deepseek-ai/dsh-tools/lib/index.js | 3577 ++++++ .../@deepseek-ai/dsh-tools/lib/invariant.js | 100 + .../dsh-tools/lib/types/code-mode.d.ts | 68 + .../dsh-tools/lib/types/code-mode.js | 580 + .../dsh-tools/lib/types/index.d.ts | 819 ++ .../@deepseek-ai/dsh-tools/lib/types/index.js | 1326 ++ .../dsh-tools/lib/types/invariant.d.ts | 13 + .../dsh-tools/lib/types/invariant.js | 123 + .../dsh-tools/lib/types/json-schema.d.ts | 106 + .../dsh-tools/lib/types/json-schema.js | 577 + .../dsh-tools/lib/types/presentation.d.ts | 367 + .../dsh-tools/lib/types/presentation.js | 8 + .../dsh-tools/lib/types/py-types.d.ts | 49 + .../dsh-tools/lib/types/py-types.js | 788 ++ .../dsh-tools/lib/types/schema.d.ts | 241 + .../dsh-tools/lib/types/schema.js | 349 + .../dsh-tools/lib/types/testing.d.ts | 25 + .../dsh-tools/lib/types/testing.js | 25 + .../dsh-tools/lib/types/ts-types.d.ts | 37 + .../dsh-tools/lib/types/ts-types.js | 265 + .../dsh-tools/lib/types/types.d.ts | 55 + .../@deepseek-ai/dsh-tools/lib/types/types.js | 7 + .../dsh-tools/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-tools/package.json | 68 + .../@deepseek-ai/dsh-user-approval | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-typert-protocol/LICENSE | 21 + .../dsh-typert-protocol/README.i18n.yaml | 6 + .../dsh-typert-protocol/README.md | 38 + .../dsh-typert-protocol/README.zh.md | 38 + .../dsh-typert-protocol/lib/index.js | 140 + .../dsh-typert-protocol/lib/invariant.js | 23 + .../dsh-typert-protocol/lib/types/index.d.ts | 101 + .../dsh-typert-protocol/lib/types/index.js | 139 + .../lib/types/invariant.d.ts | 16 + .../lib/types/invariant.js | 22 + .../dsh-typert-protocol/lib/types/types.d.ts | 419 + .../dsh-typert-protocol/lib/types/types.js | 7 + .../node_modules/.bin/cordis | 55 + .../dsh-typert-protocol/package.json | 47 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-typert-protocol/LICENSE | 21 + .../dsh-typert-protocol/README.i18n.yaml | 6 + .../dsh-typert-protocol/README.md | 38 + .../dsh-typert-protocol/README.zh.md | 38 + .../dsh-typert-protocol/lib/index.js | 140 + .../dsh-typert-protocol/lib/invariant.js | 23 + .../dsh-typert-protocol/lib/types/index.d.ts | 101 + .../dsh-typert-protocol/lib/types/index.js | 139 + .../lib/types/invariant.d.ts | 16 + .../lib/types/invariant.js | 22 + .../dsh-typert-protocol/lib/types/types.d.ts | 419 + .../dsh-typert-protocol/lib/types/types.js | 7 + .../node_modules/.bin/cordis | 55 + .../dsh-typert-protocol/package.json | 47 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../@deepseek-ai/dsh-typert-registry/LICENSE | 21 + .../dsh-typert-registry/README.i18n.yaml | 6 + .../dsh-typert-registry/README.md | 33 + .../dsh-typert-registry/README.zh.md | 33 + .../dsh-typert-registry/lib/client.js | 1372 +++ .../dsh-typert-registry/lib/index.js | 562 + .../dsh-typert-registry/lib/invariant.js | 24 + .../lib/types/client/index.d.ts | 10 + .../lib/types/client/index.js | 12 + .../dsh-typert-registry/lib/types/index.d.ts | 18 + .../dsh-typert-registry/lib/types/index.js | 3 + .../lib/types/invariant.d.ts | 16 + .../lib/types/invariant.js | 23 + .../lib/types/service.d.ts | 103 + .../dsh-typert-registry/lib/types/service.js | 600 + .../dsh-typert-registry/lib/types/types.d.ts | 100 + .../dsh-typert-registry/lib/types/types.js | 7 + .../node_modules/.bin/cordis | 55 + .../dsh-typert-registry/package.json | 67 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../@deepseek-ai/dsh-typert-registry/LICENSE | 21 + .../dsh-typert-registry/README.i18n.yaml | 6 + .../dsh-typert-registry/README.md | 33 + .../dsh-typert-registry/README.zh.md | 33 + .../dsh-typert-registry/lib/client.js | 1372 +++ .../dsh-typert-registry/lib/index.js | 562 + .../dsh-typert-registry/lib/invariant.js | 24 + .../lib/types/client/index.d.ts | 10 + .../lib/types/client/index.js | 12 + .../dsh-typert-registry/lib/types/index.d.ts | 18 + .../dsh-typert-registry/lib/types/index.js | 3 + .../lib/types/invariant.d.ts | 16 + .../lib/types/invariant.js | 23 + .../lib/types/service.d.ts | 103 + .../dsh-typert-registry/lib/types/service.js | 600 + .../dsh-typert-registry/lib/types/types.d.ts | 100 + .../dsh-typert-registry/lib/types/types.js | 7 + .../node_modules/.bin/cordis | 55 + .../dsh-typert-registry/package.json | 67 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-system-prompt | 1 + .../@deepseek-ai/dsh-user-approval/LICENSE | 21 + .../dsh-user-approval/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-user-approval/README.md | 62 + .../dsh-user-approval/README.zh.md | 62 + .../dsh-user-approval/lib/index.js | 205 + .../dsh-user-approval/lib/invariant.js | 297 + .../dsh-user-approval/lib/types/index.d.ts | 195 + .../dsh-user-approval/lib/types/index.js | 217 + .../lib/types/invariant.d.ts | 13 + .../dsh-user-approval/lib/types/invariant.js | 101 + .../dsh-user-approval/lib/types/types.d.ts | 24 + .../dsh-user-approval/lib/types/types.js | 15 + .../node_modules/.bin/cordis | 55 + .../dsh-user-approval/package.json | 62 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-system-prompt | 1 + .../@deepseek-ai/dsh-user-approval/LICENSE | 21 + .../dsh-user-approval/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-user-approval/README.md | 62 + .../dsh-user-approval/README.zh.md | 62 + .../dsh-user-approval/lib/index.js | 205 + .../dsh-user-approval/lib/invariant.js | 297 + .../dsh-user-approval/lib/types/index.d.ts | 195 + .../dsh-user-approval/lib/types/index.js | 217 + .../lib/types/invariant.d.ts | 13 + .../dsh-user-approval/lib/types/invariant.js | 101 + .../dsh-user-approval/lib/types/types.d.ts | 24 + .../dsh-user-approval/lib/types/types.js | 15 + .../node_modules/.bin/cordis | 55 + .../dsh-user-approval/package.json | 62 + .../node_modules/@deepseek-ai/schemastery | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../@deepseek-ai/dsh-user-questions/LICENSE | 21 + .../dsh-user-questions/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-user-questions/README.md | 46 + .../dsh-user-questions/README.zh.md | 46 + .../dsh-user-questions/lib/index.js | 76 + .../dsh-user-questions/lib/invariant.js | 23 + .../dsh-user-questions/lib/types/index.d.ts | 65 + .../dsh-user-questions/lib/types/index.js | 101 + .../lib/types/invariant.d.ts | 16 + .../dsh-user-questions/lib/types/invariant.js | 22 + .../dsh-user-questions/lib/types/types.d.ts | 62 + .../dsh-user-questions/lib/types/types.js | 8 + .../node_modules/.bin/cordis | 55 + .../dsh-user-questions/package.json | 51 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-agent | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-llm | 1 + .../@deepseek-ai/dsh-user-questions/LICENSE | 21 + .../dsh-user-questions/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-user-questions/README.md | 46 + .../dsh-user-questions/README.zh.md | 46 + .../dsh-user-questions/lib/index.js | 76 + .../dsh-user-questions/lib/invariant.js | 23 + .../dsh-user-questions/lib/types/index.d.ts | 65 + .../dsh-user-questions/lib/types/index.js | 101 + .../lib/types/invariant.d.ts | 16 + .../dsh-user-questions/lib/types/invariant.js | 22 + .../dsh-user-questions/lib/types/types.d.ts | 62 + .../dsh-user-questions/lib/types/types.js | 8 + .../node_modules/.bin/cordis | 55 + .../dsh-user-questions/package.json | 51 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../node_modules/@deepseek-ai/dsh-storage | 1 + .../@deepseek-ai/dsh-storage-domain | 1 + .../@deepseek-ai/dsh-workspace/LICENSE | 21 + .../dsh-workspace/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-workspace/README.md | 44 + .../@deepseek-ai/dsh-workspace/README.zh.md | 44 + .../@deepseek-ai/dsh-workspace/lib/index.js | 757 ++ .../dsh-workspace/lib/invariant.js | 114 + .../dsh-workspace/lib/types/entity.d.ts | 88 + .../dsh-workspace/lib/types/entity.js | 156 + .../dsh-workspace/lib/types/index.d.ts | 163 + .../dsh-workspace/lib/types/index.js | 600 + .../dsh-workspace/lib/types/invariant.d.ts | 16 + .../dsh-workspace/lib/types/invariant.js | 43 + .../dsh-workspace/lib/types/paths.d.ts | 18 + .../dsh-workspace/lib/types/paths.js | 21 + .../dsh-workspace/lib/types/spec.d.ts | 85 + .../dsh-workspace/lib/types/spec.js | 63 + .../dsh-workspace/lib/types/types.d.ts | 92 + .../dsh-workspace/lib/types/types.js | 8 + .../dsh-workspace/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-workspace/package.json | 60 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cordis | 1 + .../node_modules/@deepseek-ai/dsh-brand | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../node_modules/@deepseek-ai/dsh-storage | 1 + .../@deepseek-ai/dsh-storage-domain | 1 + .../@deepseek-ai/dsh-workspace/LICENSE | 21 + .../dsh-workspace/README.i18n.yaml | 6 + .../@deepseek-ai/dsh-workspace/README.md | 44 + .../@deepseek-ai/dsh-workspace/README.zh.md | 44 + .../@deepseek-ai/dsh-workspace/lib/index.js | 757 ++ .../dsh-workspace/lib/invariant.js | 114 + .../dsh-workspace/lib/types/entity.d.ts | 88 + .../dsh-workspace/lib/types/entity.js | 156 + .../dsh-workspace/lib/types/index.d.ts | 163 + .../dsh-workspace/lib/types/index.js | 600 + .../dsh-workspace/lib/types/invariant.d.ts | 16 + .../dsh-workspace/lib/types/invariant.js | 43 + .../dsh-workspace/lib/types/paths.d.ts | 18 + .../dsh-workspace/lib/types/paths.js | 21 + .../dsh-workspace/lib/types/spec.d.ts | 85 + .../dsh-workspace/lib/types/spec.js | 63 + .../dsh-workspace/lib/types/types.d.ts | 92 + .../dsh-workspace/lib/types/types.js | 8 + .../dsh-workspace/node_modules/.bin/cordis | 55 + .../@deepseek-ai/dsh-workspace/package.json | 60 + .../node_modules/zod | 1 + .../node_modules/@deepseek-ai/cosmokit | 1 + .../@deepseek-ai/schemastery/LICENSE | 21 + .../@deepseek-ai/schemastery/README.md | 389 + .../@deepseek-ai/schemastery/lib/index.cjs | 596 + .../@deepseek-ai/schemastery/lib/index.mjs | 596 + .../schemastery/lib/types/index.d.ts | 200 + .../schemastery/lib/types/index.d.ts.map | 1 + .../@deepseek-ai/schemastery/package.json | 39 + .../@deepseek-ai/schemastery/src/index.ts | 902 ++ .../node_modules/@standard-schema/spec | 1 + .../@standard-schema/spec/LICENSE | 21 + .../@standard-schema/spec/README.md | 198 + .../@standard-schema/spec/dist/index.cjs | 18 + .../@standard-schema/spec/dist/index.d.cts | 119 + .../@standard-schema/spec/dist/index.d.ts | 119 + .../@standard-schema/spec/dist/index.js | 0 .../@standard-schema/spec/package.json | 52 + .../node_modules/argparse/CHANGELOG.md | 216 + .../node_modules/argparse/LICENSE | 254 + .../node_modules/argparse/README.md | 84 + .../node_modules/argparse/argparse.js | 3707 ++++++ .../node_modules/argparse/lib/sub.js | 67 + .../node_modules/argparse/lib/textwrap.js | 440 + .../node_modules/argparse/package.json | 31 + .../node_modules/fflate/CHANGELOG.md | 125 + .../fflate@0.8.3/node_modules/fflate/LICENSE | 21 + .../node_modules/fflate/README.md | 558 + .../node_modules/fflate/esm/browser.d.ts | 1539 +++ .../node_modules/fflate/esm/browser.js | 2692 ++++ .../node_modules/fflate/esm/index.d.mts | 1539 +++ .../node_modules/fflate/esm/index.mjs | 2710 ++++ .../node_modules/fflate/lib/browser.cjs | 2717 ++++ .../node_modules/fflate/lib/browser.d.cts | 1539 +++ .../node_modules/fflate/lib/index.cjs | 2697 ++++ .../node_modules/fflate/lib/index.d.ts | 1539 +++ .../node_modules/fflate/lib/node-worker.cjs | 36 + .../node_modules/fflate/lib/node.cjs | 2733 +++++ .../node_modules/fflate/lib/node.d.cts | 1539 +++ .../node_modules/fflate/lib/worker.cjs | 20 + .../node_modules/fflate/package.json | 128 + .../node_modules/fflate/umd/index.js | 1 + .../.pnpm/js-yaml@4.3.1/node_modules/argparse | 1 + .../node_modules/js-yaml/LICENSE | 21 + .../node_modules/js-yaml/README.md | 233 + .../node_modules/js-yaml/bin/js-yaml.js | 117 + .../node_modules/js-yaml/dist/js-yaml.js | 3014 +++++ .../node_modules/js-yaml/dist/js-yaml.js.map | 1 + .../node_modules/js-yaml/dist/js-yaml.min.js | 2 + .../js-yaml/dist/js-yaml.min.js.map | 1 + .../node_modules/js-yaml/dist/js-yaml.mjs | 3074 +++++ .../node_modules/js-yaml/dist/js-yaml.mjs.map | 1 + .../node_modules/js-yaml/index.js | 44 + .../node_modules/js-yaml/lib/common.js | 50 + .../node_modules/js-yaml/lib/dumper.js | 937 ++ .../node_modules/js-yaml/lib/exception.js | 51 + .../js-yaml/lib/index_vite_proxy.tmp.mjs | 37 + .../node_modules/js-yaml/lib/loader.js | 1790 +++ .../node_modules/js-yaml/lib/schema.js | 109 + .../node_modules/js-yaml/lib/schema/core.js | 9 + .../js-yaml/lib/schema/default.js | 20 + .../js-yaml/lib/schema/failsafe.js | 14 + .../node_modules/js-yaml/lib/schema/json.js | 17 + .../node_modules/js-yaml/lib/snippet.js | 96 + .../node_modules/js-yaml/lib/type.js | 66 + .../node_modules/js-yaml/lib/type/binary.js | 122 + .../node_modules/js-yaml/lib/type/bool.js | 35 + .../node_modules/js-yaml/lib/type/float.js | 99 + .../node_modules/js-yaml/lib/type/int.js | 142 + .../node_modules/js-yaml/lib/type/map.js | 8 + .../node_modules/js-yaml/lib/type/merge.js | 12 + .../node_modules/js-yaml/lib/type/null.js | 35 + .../node_modules/js-yaml/lib/type/omap.js | 45 + .../node_modules/js-yaml/lib/type/pairs.js | 50 + .../node_modules/js-yaml/lib/type/seq.js | 8 + .../node_modules/js-yaml/lib/type/set.js | 29 + .../node_modules/js-yaml/lib/type/str.js | 8 + .../js-yaml/lib/type/timestamp.js | 88 + .../js-yaml/node_modules/.bin/js-yaml | 55 + .../node_modules/js-yaml/package.json | 83 + .../node_modules/.pnpm/lock.yaml | 991 ++ .../.pnpm/node_modules/.bin/cordis | 55 + .../.pnpm/node_modules/.bin/js-yaml | 55 + .../.pnpm/node_modules/@deepseek-ai/cordis | 1 + .../@deepseek-ai/cordis-plugin-include | 1 + .../@deepseek-ai/cordis-plugin-loader | 1 + .../.pnpm/node_modules/@deepseek-ai/cosmokit | 1 + .../.pnpm/node_modules/@deepseek-ai/dsh-agent | 1 + .../@deepseek-ai/dsh-agent-default-model | 1 + .../@deepseek-ai/dsh-agent-presets | 1 + .../node_modules/@deepseek-ai/dsh-api-gateway | 1 + .../node_modules/@deepseek-ai/dsh-api-remotes | 1 + .../@deepseek-ai/dsh-atomic-write | 1 + .../node_modules/@deepseek-ai/dsh-attachment | 1 + .../.pnpm/node_modules/@deepseek-ai/dsh-brand | 1 + .../@deepseek-ai/dsh-client-connection | 1 + .../@deepseek-ai/dsh-code-runtime | 1 + .../node_modules/@deepseek-ai/dsh-commands | 1 + .../@deepseek-ai/dsh-cordis-host-runner | 1 + .../node_modules/@deepseek-ai/dsh-credentials | 1 + .../.pnpm/node_modules/@deepseek-ai/dsh-goal | 1 + .../node_modules/@deepseek-ai/dsh-home-paths | 1 + .../@deepseek-ai/dsh-host-directory-picker | 1 + .../@deepseek-ai/dsh-host-plugin-inventory | 1 + .../@deepseek-ai/dsh-host-webserver | 1 + .../node_modules/@deepseek-ai/dsh-invariants | 1 + .../.pnpm/node_modules/@deepseek-ai/dsh-jobs | 1 + .../.pnpm/node_modules/@deepseek-ai/dsh-llm | 1 + .../@deepseek-ai/dsh-message-feedback | 1 + .../@deepseek-ai/dsh-native-command | 1 + .../.pnpm/node_modules/@deepseek-ai/dsh-scope | 1 + .../node_modules/@deepseek-ai/dsh-session | 1 + .../@deepseek-ai/dsh-session-persistence | 1 + .../@deepseek-ai/dsh-session-projection | 1 + .../@deepseek-ai/dsh-session-projection-cache | 1 + .../@deepseek-ai/dsh-session-query | 1 + .../@deepseek-ai/dsh-session-title | 1 + .../node_modules/@deepseek-ai/dsh-settings | 1 + .../.pnpm/node_modules/@deepseek-ai/dsh-skill | 1 + .../node_modules/@deepseek-ai/dsh-storage | 1 + .../@deepseek-ai/dsh-storage-domain | 1 + .../node_modules/@deepseek-ai/dsh-subagent | 1 + .../@deepseek-ai/dsh-system-prompt | 1 + .../node_modules/@deepseek-ai/dsh-timeout | 1 + .../.pnpm/node_modules/@deepseek-ai/dsh-tools | 1 + .../@deepseek-ai/dsh-typert-protocol | 1 + .../@deepseek-ai/dsh-typert-registry | 1 + .../@deepseek-ai/dsh-user-approval | 1 + .../@deepseek-ai/dsh-user-questions | 1 + .../node_modules/@deepseek-ai/dsh-workspace | 1 + .../node_modules/@deepseek-ai/schemastery | 1 + .../.pnpm/node_modules/@standard-schema/spec | 1 + .../node_modules/.pnpm/node_modules/argparse | 1 + .../node_modules/.pnpm/node_modules/fflate | 1 + .../node_modules/.pnpm/node_modules/js-yaml | 1 + .../node_modules/.pnpm/node_modules/ws | 1 + .../node_modules/.pnpm/node_modules/zod | 1 + .../.pnpm/ws@8.21.3/node_modules/ws/LICENSE | 20 + .../.pnpm/ws@8.21.3/node_modules/ws/README.md | 548 + .../ws@8.21.3/node_modules/ws/browser.js | 8 + .../.pnpm/ws@8.21.3/node_modules/ws/index.js | 22 + .../node_modules/ws/lib/buffer-util.js | 131 + .../node_modules/ws/lib/constants.js | 19 + .../node_modules/ws/lib/event-target.js | 292 + .../node_modules/ws/lib/extension.js | 203 + .../ws@8.21.3/node_modules/ws/lib/limiter.js | 55 + .../node_modules/ws/lib/permessage-deflate.js | 530 + .../ws@8.21.3/node_modules/ws/lib/receiver.js | 743 ++ .../ws@8.21.3/node_modules/ws/lib/sender.js | 607 + .../ws@8.21.3/node_modules/ws/lib/stream.js | 161 + .../node_modules/ws/lib/subprotocol.js | 62 + .../node_modules/ws/lib/validation.js | 152 + .../node_modules/ws/lib/websocket-server.js | 562 + .../node_modules/ws/lib/websocket.js | 1407 +++ .../ws@8.21.3/node_modules/ws/package.json | 74 + .../ws@8.21.3/node_modules/ws/wrapper.mjs | 21 + .../.pnpm/zod@4.4.3/node_modules/zod/LICENSE | 21 + .../zod@4.4.3/node_modules/zod/README.md | 191 + .../zod@4.4.3/node_modules/zod/index.cjs | 33 + .../zod@4.4.3/node_modules/zod/index.d.cts | 4 + .../zod@4.4.3/node_modules/zod/index.d.ts | 4 + .../.pnpm/zod@4.4.3/node_modules/zod/index.js | 4 + .../node_modules/zod/locales/index.cjs | 17 + .../node_modules/zod/locales/index.d.cts | 1 + .../node_modules/zod/locales/index.d.ts | 1 + .../node_modules/zod/locales/index.js | 1 + .../node_modules/zod/locales/package.json | 7 + .../zod@4.4.3/node_modules/zod/mini/index.cjs | 32 + .../node_modules/zod/mini/index.d.cts | 3 + .../node_modules/zod/mini/index.d.ts | 3 + .../zod@4.4.3/node_modules/zod/mini/index.js | 3 + .../node_modules/zod/mini/package.json | 7 + .../zod@4.4.3/node_modules/zod/package.json | 135 + .../zod@4.4.3/node_modules/zod/src/index.ts | 4 + .../node_modules/zod/src/locales/index.ts | 1 + .../node_modules/zod/src/mini/index.ts | 3 + .../node_modules/zod/src/v3/ZodError.ts | 330 + .../zod/src/v3/benchmarks/datetime.ts | 58 + .../src/v3/benchmarks/discriminatedUnion.ts | 80 + .../zod/src/v3/benchmarks/index.ts | 59 + .../zod/src/v3/benchmarks/ipv4.ts | 57 + .../zod/src/v3/benchmarks/object.ts | 69 + .../zod/src/v3/benchmarks/primitives.ts | 162 + .../zod/src/v3/benchmarks/realworld.ts | 63 + .../zod/src/v3/benchmarks/string.ts | 55 + .../zod/src/v3/benchmarks/union.ts | 80 + .../node_modules/zod/src/v3/errors.ts | 13 + .../node_modules/zod/src/v3/external.ts | 6 + .../zod/src/v3/helpers/enumUtil.ts | 17 + .../zod/src/v3/helpers/errorUtil.ts | 8 + .../zod/src/v3/helpers/parseUtil.ts | 176 + .../zod/src/v3/helpers/partialUtil.ts | 34 + .../zod/src/v3/helpers/typeAliases.ts | 2 + .../node_modules/zod/src/v3/helpers/util.ts | 224 + .../node_modules/zod/src/v3/index.ts | 4 + .../node_modules/zod/src/v3/locales/en.ts | 124 + .../zod/src/v3/standard-schema.ts | 113 + .../node_modules/zod/src/v3/tests/Mocker.ts | 54 + .../zod/src/v3/tests/all-errors.test.ts | 157 + .../zod/src/v3/tests/anyunknown.test.ts | 28 + .../zod/src/v3/tests/array.test.ts | 71 + .../zod/src/v3/tests/async-parsing.test.ts | 388 + .../src/v3/tests/async-refinements.test.ts | 46 + .../zod/src/v3/tests/base.test.ts | 29 + .../zod/src/v3/tests/bigint.test.ts | 55 + .../zod/src/v3/tests/branded.test.ts | 53 + .../zod/src/v3/tests/catch.test.ts | 220 + .../zod/src/v3/tests/coerce.test.ts | 133 + .../zod/src/v3/tests/complex.test.ts | 70 + .../zod/src/v3/tests/custom.test.ts | 31 + .../zod/src/v3/tests/date.test.ts | 32 + .../zod/src/v3/tests/deepmasking.test.ts | 186 + .../zod/src/v3/tests/default.test.ts | 112 + .../zod/src/v3/tests/description.test.ts | 33 + .../src/v3/tests/discriminated-unions.test.ts | 315 + .../zod/src/v3/tests/enum.test.ts | 80 + .../zod/src/v3/tests/error.test.ts | 551 + .../zod/src/v3/tests/firstparty.test.ts | 87 + .../v3/tests/firstpartyschematypes.test.ts | 21 + .../zod/src/v3/tests/function.test.ts | 261 + .../zod/src/v3/tests/generics.test.ts | 48 + .../zod/src/v3/tests/instanceof.test.ts | 37 + .../zod/src/v3/tests/intersection.test.ts | 110 + .../src/v3/tests/language-server.source.ts | 76 + .../zod/src/v3/tests/language-server.test.ts | 207 + .../zod/src/v3/tests/literal.test.ts | 36 + .../node_modules/zod/src/v3/tests/map.test.ts | 110 + .../zod/src/v3/tests/masking.test.ts | 4 + .../zod/src/v3/tests/mocker.test.ts | 19 + .../node_modules/zod/src/v3/tests/nan.test.ts | 24 + .../zod/src/v3/tests/nativeEnum.test.ts | 87 + .../zod/src/v3/tests/nullable.test.ts | 42 + .../zod/src/v3/tests/number.test.ts | 176 + .../src/v3/tests/object-augmentation.test.ts | 29 + .../src/v3/tests/object-in-es5-env.test.ts | 29 + .../zod/src/v3/tests/object.test.ts | 434 + .../zod/src/v3/tests/optional.test.ts | 42 + .../zod/src/v3/tests/parseUtil.test.ts | 23 + .../zod/src/v3/tests/parser.test.ts | 41 + .../zod/src/v3/tests/partials.test.ts | 243 + .../zod/src/v3/tests/pickomit.test.ts | 111 + .../zod/src/v3/tests/pipeline.test.ts | 29 + .../zod/src/v3/tests/preprocess.test.ts | 186 + .../zod/src/v3/tests/primitive.test.ts | 440 + .../zod/src/v3/tests/promise.test.ts | 90 + .../zod/src/v3/tests/readonly.test.ts | 194 + .../zod/src/v3/tests/record.test.ts | 171 + .../zod/src/v3/tests/recursive.test.ts | 197 + .../zod/src/v3/tests/refine.test.ts | 313 + .../zod/src/v3/tests/safeparse.test.ts | 27 + .../node_modules/zod/src/v3/tests/set.test.ts | 142 + .../zod/src/v3/tests/standard-schema.test.ts | 83 + .../zod/src/v3/tests/string.test.ts | 916 ++ .../zod/src/v3/tests/transformer.test.ts | 233 + .../zod/src/v3/tests/tuple.test.ts | 90 + .../zod/src/v3/tests/unions.test.ts | 57 + .../zod/src/v3/tests/validations.test.ts | 133 + .../zod/src/v3/tests/void.test.ts | 15 + .../node_modules/zod/src/v3/types.ts | 5138 ++++++++ .../node_modules/zod/src/v4-mini/index.ts | 3 + .../node_modules/zod/src/v4/classic/checks.ts | 32 + .../node_modules/zod/src/v4/classic/coerce.ts | 27 + .../node_modules/zod/src/v4/classic/compat.ts | 70 + .../node_modules/zod/src/v4/classic/errors.ts | 82 + .../zod/src/v4/classic/external.ts | 52 + .../zod/src/v4/classic/from-json-schema.ts | 659 + .../node_modules/zod/src/v4/classic/index.ts | 5 + .../node_modules/zod/src/v4/classic/iso.ts | 90 + .../node_modules/zod/src/v4/classic/parse.ts | 82 + .../zod/src/v4/classic/schemas.ts | 2672 ++++ .../src/v4/classic/tests/anyunknown.test.ts | 26 + .../zod/src/v4/classic/tests/apply.test.ts | 59 + .../zod/src/v4/classic/tests/array.test.ts | 264 + .../v4/classic/tests/assignability.test.ts | 216 + .../v4/classic/tests/async-parsing.test.ts | 381 + .../classic/tests/async-refinements.test.ts | 68 + .../zod/src/v4/classic/tests/base.test.ts | 7 + .../zod/src/v4/classic/tests/bigint.test.ts | 54 + .../zod/src/v4/classic/tests/brand.test.ts | 106 + .../zod/src/v4/classic/tests/catch.test.ts | 326 + .../zod/src/v4/classic/tests/coalesce.test.ts | 20 + .../v4/classic/tests/codec-examples.test.ts | 573 + .../zod/src/v4/classic/tests/codec.test.ts | 703 ++ .../zod/src/v4/classic/tests/coerce.test.ts | 160 + .../v4/classic/tests/continuability.test.ts | 374 + .../zod/src/v4/classic/tests/custom.test.ts | 40 + .../zod/src/v4/classic/tests/date.test.ts | 62 + .../zod/src/v4/classic/tests/datetime.test.ts | 302 + .../zod/src/v4/classic/tests/default.test.ts | 409 + .../tests/describe-meta-checks.test.ts | 27 + .../src/v4/classic/tests/description.test.ts | 32 + .../v4/classic/tests/detached-methods.test.ts | 197 + .../tests/discriminated-unions.test.ts | 694 ++ .../zod/src/v4/classic/tests/enum.test.ts | 285 + .../src/v4/classic/tests/error-utils.test.ts | 807 ++ .../zod/src/v4/classic/tests/error.test.ts | 711 ++ .../zod/src/v4/classic/tests/file.test.ts | 96 + .../src/v4/classic/tests/firstparty.test.ts | 179 + .../v4/classic/tests/fix-json-issue.test.ts | 26 + .../v4/classic/tests/from-json-schema.test.ts | 895 ++ .../zod/src/v4/classic/tests/function.test.ts | 360 + .../zod/src/v4/classic/tests/generics.test.ts | 72 + .../v4/classic/tests/global-config.test.ts | 39 + .../zod/src/v4/classic/tests/hash.test.ts | 68 + .../zod/src/v4/classic/tests/index.test.ts | 939 ++ .../src/v4/classic/tests/instanceof.test.ts | 60 + .../src/v4/classic/tests/intersection.test.ts | 198 + .../classic/tests/jitless-allows-eval.test.ts | 46 + .../zod/src/v4/classic/tests/json.test.ts | 109 + .../zod/src/v4/classic/tests/lazy.test.ts | 227 + .../zod/src/v4/classic/tests/literal.test.ts | 117 + .../src/v4/classic/tests/locales_ka.test.ts | 29 + .../src/v4/classic/tests/locales_ro.test.ts | 24 + .../zod/src/v4/classic/tests/map.test.ts | 330 + .../zod/src/v4/classic/tests/nan.test.ts | 21 + .../v4/classic/tests/nested-refine.test.ts | 168 + .../src/v4/classic/tests/nonoptional.test.ts | 101 + .../zod/src/v4/classic/tests/nullable.test.ts | 22 + .../zod/src/v4/classic/tests/number.test.ts | 325 + .../zod/src/v4/classic/tests/object.test.ts | 717 ++ .../zod/src/v4/classic/tests/optional.test.ts | 333 + .../zod/src/v4/classic/tests/partial.test.ts | 450 + .../zod/src/v4/classic/tests/pickomit.test.ts | 211 + .../zod/src/v4/classic/tests/pipe.test.ts | 101 + .../zod/src/v4/classic/tests/prefault.test.ts | 74 + .../v4/classic/tests/preprocess-types.test.ts | 26 + .../src/v4/classic/tests/preprocess.test.ts | 351 + .../src/v4/classic/tests/primitive.test.ts | 175 + .../zod/src/v4/classic/tests/promise.test.ts | 81 + .../src/v4/classic/tests/prototypes.test.ts | 23 + .../zod/src/v4/classic/tests/readonly.test.ts | 252 + .../zod/src/v4/classic/tests/record.test.ts | 717 ++ .../v4/classic/tests/recursive-types.test.ts | 631 + .../zod/src/v4/classic/tests/refine.test.ts | 633 + .../src/v4/classic/tests/registries.test.ts | 243 + .../zod/src/v4/classic/tests/set.test.ts | 181 + .../v4/classic/tests/standard-schema.test.ts | 134 + .../v4/classic/tests/string-formats.test.ts | 125 + .../zod/src/v4/classic/tests/string.test.ts | 1224 ++ .../src/v4/classic/tests/stringbool.test.ts | 106 + .../v4/classic/tests/template-literal.test.ts | 771 ++ .../tests/to-json-schema-methods.test.ts | 438 + .../v4/classic/tests/to-json-schema.test.ts | 3125 +++++ .../src/v4/classic/tests/transform.test.ts | 378 + .../zod/src/v4/classic/tests/tuple.test.ts | 496 + .../zod/src/v4/classic/tests/union.test.ts | 273 + .../zod/src/v4/classic/tests/url.test.ts | 13 + .../src/v4/classic/tests/validations.test.ts | 283 + .../zod/src/v4/classic/tests/void.test.ts | 12 + .../node_modules/zod/src/v4/core/api.ts | 1823 +++ .../node_modules/zod/src/v4/core/checks.ts | 1293 ++ .../node_modules/zod/src/v4/core/config.ts | 15 + .../node_modules/zod/src/v4/core/core.ts | 153 + .../node_modules/zod/src/v4/core/doc.ts | 44 + .../node_modules/zod/src/v4/core/errors.ts | 455 + .../node_modules/zod/src/v4/core/index.ts | 16 + .../zod/src/v4/core/json-schema-generator.ts | 126 + .../zod/src/v4/core/json-schema-processors.ts | 666 + .../zod/src/v4/core/json-schema.ts | 147 + .../node_modules/zod/src/v4/core/parse.ts | 195 + .../node_modules/zod/src/v4/core/regexes.ts | 190 + .../zod/src/v4/core/registries.ts | 105 + .../node_modules/zod/src/v4/core/schemas.ts | 4730 +++++++ .../zod/src/v4/core/standard-schema.ts | 159 + .../zod/src/v4/core/tests/extend.test.ts | 59 + .../zod/src/v4/core/tests/index.test.ts | 46 + .../zod/src/v4/core/tests/locales/be.test.ts | 124 + .../zod/src/v4/core/tests/locales/el.test.ts | 215 + .../zod/src/v4/core/tests/locales/en.test.ts | 22 + .../zod/src/v4/core/tests/locales/es.test.ts | 181 + .../zod/src/v4/core/tests/locales/fr.test.ts | 72 + .../zod/src/v4/core/tests/locales/he.test.ts | 379 + .../zod/src/v4/core/tests/locales/hr.test.ts | 163 + .../zod/src/v4/core/tests/locales/nl.test.ts | 46 + .../zod/src/v4/core/tests/locales/ru.test.ts | 128 + .../zod/src/v4/core/tests/locales/tr.test.ts | 69 + .../zod/src/v4/core/tests/locales/uz.test.ts | 105 + .../v4/core/tests/record-constructor.test.ts | 125 + .../v4/core/tests/recursive-tuples.test.ts | 45 + .../zod/src/v4/core/to-json-schema.ts | 622 + .../node_modules/zod/src/v4/core/util.ts | 983 ++ .../node_modules/zod/src/v4/core/versions.ts | 5 + .../node_modules/zod/src/v4/core/zsf.ts | 323 + .../node_modules/zod/src/v4/index.ts | 4 + .../node_modules/zod/src/v4/locales/ar.ts | 115 + .../node_modules/zod/src/v4/locales/az.ts | 111 + .../node_modules/zod/src/v4/locales/be.ts | 176 + .../node_modules/zod/src/v4/locales/bg.ts | 128 + .../node_modules/zod/src/v4/locales/ca.ts | 116 + .../node_modules/zod/src/v4/locales/cs.ts | 118 + .../node_modules/zod/src/v4/locales/da.ts | 123 + .../node_modules/zod/src/v4/locales/de.ts | 116 + .../node_modules/zod/src/v4/locales/el.ts | 121 + .../node_modules/zod/src/v4/locales/en.ts | 123 + .../node_modules/zod/src/v4/locales/eo.ts | 118 + .../node_modules/zod/src/v4/locales/es.ts | 141 + .../node_modules/zod/src/v4/locales/fa.ts | 126 + .../node_modules/zod/src/v4/locales/fi.ts | 121 + .../node_modules/zod/src/v4/locales/fr-CA.ts | 116 + .../node_modules/zod/src/v4/locales/fr.ts | 132 + .../node_modules/zod/src/v4/locales/he.ts | 246 + .../node_modules/zod/src/v4/locales/hr.ts | 131 + .../node_modules/zod/src/v4/locales/hu.ts | 117 + .../node_modules/zod/src/v4/locales/hy.ts | 164 + .../node_modules/zod/src/v4/locales/id.ts | 115 + .../node_modules/zod/src/v4/locales/index.ts | 52 + .../node_modules/zod/src/v4/locales/is.ts | 119 + .../node_modules/zod/src/v4/locales/it.ts | 116 + .../node_modules/zod/src/v4/locales/ja.ts | 114 + .../node_modules/zod/src/v4/locales/ka.ts | 123 + .../node_modules/zod/src/v4/locales/kh.ts | 7 + .../node_modules/zod/src/v4/locales/km.ts | 119 + .../node_modules/zod/src/v4/locales/ko.ts | 121 + .../node_modules/zod/src/v4/locales/lt.ts | 239 + .../node_modules/zod/src/v4/locales/mk.ts | 118 + .../node_modules/zod/src/v4/locales/ms.ts | 115 + .../node_modules/zod/src/v4/locales/nl.ts | 121 + .../node_modules/zod/src/v4/locales/no.ts | 116 + .../node_modules/zod/src/v4/locales/ota.ts | 117 + .../node_modules/zod/src/v4/locales/pl.ts | 118 + .../node_modules/zod/src/v4/locales/ps.ts | 126 + .../node_modules/zod/src/v4/locales/pt.ts | 116 + .../node_modules/zod/src/v4/locales/ro.ts | 129 + .../node_modules/zod/src/v4/locales/ru.ts | 176 + .../node_modules/zod/src/v4/locales/sl.ts | 118 + .../node_modules/zod/src/v4/locales/sv.ts | 119 + .../node_modules/zod/src/v4/locales/ta.ts | 118 + .../node_modules/zod/src/v4/locales/th.ts | 119 + .../node_modules/zod/src/v4/locales/tr.ts | 111 + .../node_modules/zod/src/v4/locales/ua.ts | 7 + .../node_modules/zod/src/v4/locales/uk.ts | 117 + .../node_modules/zod/src/v4/locales/ur.ts | 119 + .../node_modules/zod/src/v4/locales/uz.ts | 117 + .../node_modules/zod/src/v4/locales/vi.ts | 117 + .../node_modules/zod/src/v4/locales/yo.ts | 124 + .../node_modules/zod/src/v4/locales/zh-CN.ts | 116 + .../node_modules/zod/src/v4/locales/zh-TW.ts | 115 + .../node_modules/zod/src/v4/mini/checks.ts | 32 + .../node_modules/zod/src/v4/mini/coerce.ts | 27 + .../node_modules/zod/src/v4/mini/external.ts | 41 + .../node_modules/zod/src/v4/mini/index.ts | 3 + .../node_modules/zod/src/v4/mini/iso.ts | 66 + .../node_modules/zod/src/v4/mini/parse.ts | 14 + .../node_modules/zod/src/v4/mini/schemas.ts | 1947 +++ .../zod/src/v4/mini/tests/apply.test.ts | 24 + .../src/v4/mini/tests/assignability.test.ts | 129 + .../zod/src/v4/mini/tests/brand.test.ts | 94 + .../zod/src/v4/mini/tests/checks.test.ts | 144 + .../zod/src/v4/mini/tests/codec.test.ts | 548 + .../zod/src/v4/mini/tests/computed.test.ts | 36 + .../zod/src/v4/mini/tests/error.test.ts | 22 + .../zod/src/v4/mini/tests/functions.test.ts | 5 + .../zod/src/v4/mini/tests/index.test.ts | 993 ++ .../zod/src/v4/mini/tests/number.test.ts | 95 + .../zod/src/v4/mini/tests/object.test.ts | 227 + .../zod/src/v4/mini/tests/prototypes.test.ts | 43 + .../src/v4/mini/tests/recursive-types.test.ts | 325 + .../src/v4/mini/tests/standard-schema.test.ts | 50 + .../zod/src/v4/mini/tests/string.test.ts | 352 + .../node_modules/zod/v3/ZodError.cjs | 138 + .../node_modules/zod/v3/ZodError.d.cts | 164 + .../node_modules/zod/v3/ZodError.d.ts | 164 + .../zod@4.4.3/node_modules/zod/v3/ZodError.js | 133 + .../zod@4.4.3/node_modules/zod/v3/errors.cjs | 17 + .../node_modules/zod/v3/errors.d.cts | 5 + .../zod@4.4.3/node_modules/zod/v3/errors.d.ts | 5 + .../zod@4.4.3/node_modules/zod/v3/errors.js | 9 + .../node_modules/zod/v3/external.cjs | 22 + .../node_modules/zod/v3/external.d.cts | 6 + .../node_modules/zod/v3/external.d.ts | 6 + .../zod@4.4.3/node_modules/zod/v3/external.js | 6 + .../node_modules/zod/v3/helpers/enumUtil.cjs | 2 + .../zod/v3/helpers/enumUtil.d.cts | 8 + .../node_modules/zod/v3/helpers/enumUtil.d.ts | 8 + .../node_modules/zod/v3/helpers/enumUtil.js | 1 + .../node_modules/zod/v3/helpers/errorUtil.cjs | 9 + .../zod/v3/helpers/errorUtil.d.cts | 9 + .../zod/v3/helpers/errorUtil.d.ts | 9 + .../node_modules/zod/v3/helpers/errorUtil.js | 6 + .../node_modules/zod/v3/helpers/parseUtil.cjs | 124 + .../zod/v3/helpers/parseUtil.d.cts | 78 + .../zod/v3/helpers/parseUtil.d.ts | 78 + .../node_modules/zod/v3/helpers/parseUtil.js | 109 + .../zod/v3/helpers/partialUtil.cjs | 2 + .../zod/v3/helpers/partialUtil.d.cts | 8 + .../zod/v3/helpers/partialUtil.d.ts | 8 + .../zod/v3/helpers/partialUtil.js | 1 + .../zod/v3/helpers/typeAliases.cjs | 2 + .../zod/v3/helpers/typeAliases.d.cts | 2 + .../zod/v3/helpers/typeAliases.d.ts | 2 + .../zod/v3/helpers/typeAliases.js | 1 + .../node_modules/zod/v3/helpers/util.cjs | 137 + .../node_modules/zod/v3/helpers/util.d.cts | 85 + .../node_modules/zod/v3/helpers/util.d.ts | 85 + .../node_modules/zod/v3/helpers/util.js | 133 + .../zod@4.4.3/node_modules/zod/v3/index.cjs | 33 + .../zod@4.4.3/node_modules/zod/v3/index.d.cts | 4 + .../zod@4.4.3/node_modules/zod/v3/index.d.ts | 4 + .../zod@4.4.3/node_modules/zod/v3/index.js | 4 + .../node_modules/zod/v3/locales/en.cjs | 112 + .../node_modules/zod/v3/locales/en.d.cts | 3 + .../node_modules/zod/v3/locales/en.d.ts | 3 + .../node_modules/zod/v3/locales/en.js | 109 + .../node_modules/zod/v3/package.json | 7 + .../node_modules/zod/v3/standard-schema.cjs | 2 + .../node_modules/zod/v3/standard-schema.d.cts | 102 + .../node_modules/zod/v3/standard-schema.d.ts | 102 + .../node_modules/zod/v3/standard-schema.js | 1 + .../zod@4.4.3/node_modules/zod/v3/types.cjs | 3777 ++++++ .../zod@4.4.3/node_modules/zod/v3/types.d.cts | 1034 ++ .../zod@4.4.3/node_modules/zod/v3/types.d.ts | 1034 ++ .../zod@4.4.3/node_modules/zod/v3/types.js | 3695 ++++++ .../node_modules/zod/v4-mini/index.cjs | 32 + .../node_modules/zod/v4-mini/index.d.cts | 3 + .../node_modules/zod/v4-mini/index.d.ts | 3 + .../node_modules/zod/v4-mini/index.js | 3 + .../node_modules/zod/v4-mini/package.json | 7 + .../node_modules/zod/v4/classic/checks.cjs | 33 + .../node_modules/zod/v4/classic/checks.d.cts | 1 + .../node_modules/zod/v4/classic/checks.d.ts | 1 + .../node_modules/zod/v4/classic/checks.js | 1 + .../node_modules/zod/v4/classic/coerce.cjs | 47 + .../node_modules/zod/v4/classic/coerce.d.cts | 17 + .../node_modules/zod/v4/classic/coerce.d.ts | 17 + .../node_modules/zod/v4/classic/coerce.js | 17 + .../node_modules/zod/v4/classic/compat.cjs | 61 + .../node_modules/zod/v4/classic/compat.d.cts | 50 + .../node_modules/zod/v4/classic/compat.d.ts | 50 + .../node_modules/zod/v4/classic/compat.js | 31 + .../node_modules/zod/v4/classic/errors.cjs | 74 + .../node_modules/zod/v4/classic/errors.d.cts | 30 + .../node_modules/zod/v4/classic/errors.d.ts | 30 + .../node_modules/zod/v4/classic/errors.js | 48 + .../node_modules/zod/v4/classic/external.cjs | 73 + .../zod/v4/classic/external.d.cts | 16 + .../node_modules/zod/v4/classic/external.d.ts | 16 + .../node_modules/zod/v4/classic/external.js | 20 + .../zod/v4/classic/from-json-schema.cjs | 625 + .../zod/v4/classic/from-json-schema.d.cts | 12 + .../zod/v4/classic/from-json-schema.d.ts | 12 + .../zod/v4/classic/from-json-schema.js | 599 + .../node_modules/zod/v4/classic/index.cjs | 33 + .../node_modules/zod/v4/classic/index.d.cts | 4 + .../node_modules/zod/v4/classic/index.d.ts | 4 + .../node_modules/zod/v4/classic/index.js | 4 + .../node_modules/zod/v4/classic/iso.cjs | 60 + .../node_modules/zod/v4/classic/iso.d.cts | 22 + .../node_modules/zod/v4/classic/iso.d.ts | 22 + .../node_modules/zod/v4/classic/iso.js | 30 + .../node_modules/zod/v4/classic/package.json | 7 + .../node_modules/zod/v4/classic/parse.cjs | 41 + .../node_modules/zod/v4/classic/parse.d.cts | 31 + .../node_modules/zod/v4/classic/parse.d.ts | 31 + .../node_modules/zod/v4/classic/parse.js | 15 + .../node_modules/zod/v4/classic/schemas.cjs | 1511 +++ .../node_modules/zod/v4/classic/schemas.d.cts | 767 ++ .../node_modules/zod/v4/classic/schemas.d.ts | 767 ++ .../node_modules/zod/v4/classic/schemas.js | 1395 +++ .../node_modules/zod/v4/core/api.cjs | 1227 ++ .../node_modules/zod/v4/core/api.d.cts | 325 + .../node_modules/zod/v4/core/api.d.ts | 325 + .../zod@4.4.3/node_modules/zod/v4/core/api.js | 1087 ++ .../node_modules/zod/v4/core/checks.cjs | 601 + .../node_modules/zod/v4/core/checks.d.cts | 278 + .../node_modules/zod/v4/core/checks.d.ts | 278 + .../node_modules/zod/v4/core/checks.js | 575 + .../node_modules/zod/v4/core/core.cjs | 85 + .../node_modules/zod/v4/core/core.d.cts | 70 + .../node_modules/zod/v4/core/core.d.ts | 70 + .../node_modules/zod/v4/core/core.js | 78 + .../node_modules/zod/v4/core/doc.cjs | 39 + .../node_modules/zod/v4/core/doc.d.cts | 14 + .../node_modules/zod/v4/core/doc.d.ts | 14 + .../zod@4.4.3/node_modules/zod/v4/core/doc.js | 35 + .../node_modules/zod/v4/core/errors.cjs | 216 + .../node_modules/zod/v4/core/errors.d.cts | 221 + .../node_modules/zod/v4/core/errors.d.ts | 221 + .../node_modules/zod/v4/core/errors.js | 185 + .../node_modules/zod/v4/core/index.cjs | 47 + .../node_modules/zod/v4/core/index.d.cts | 16 + .../node_modules/zod/v4/core/index.d.ts | 16 + .../node_modules/zod/v4/core/index.js | 16 + .../zod/v4/core/json-schema-generator.cjs | 99 + .../zod/v4/core/json-schema-generator.d.cts | 65 + .../zod/v4/core/json-schema-generator.d.ts | 65 + .../zod/v4/core/json-schema-generator.js | 95 + .../zod/v4/core/json-schema-processors.cjs | 644 + .../zod/v4/core/json-schema-processors.d.cts | 49 + .../zod/v4/core/json-schema-processors.d.ts | 49 + .../zod/v4/core/json-schema-processors.js | 601 + .../node_modules/zod/v4/core/json-schema.cjs | 2 + .../zod/v4/core/json-schema.d.cts | 88 + .../node_modules/zod/v4/core/json-schema.d.ts | 88 + .../node_modules/zod/v4/core/json-schema.js | 1 + .../node_modules/zod/v4/core/package.json | 7 + .../node_modules/zod/v4/core/parse.cjs | 131 + .../node_modules/zod/v4/core/parse.d.cts | 49 + .../node_modules/zod/v4/core/parse.d.ts | 49 + .../node_modules/zod/v4/core/parse.js | 93 + .../node_modules/zod/v4/core/regexes.cjs | 172 + .../node_modules/zod/v4/core/regexes.d.cts | 85 + .../node_modules/zod/v4/core/regexes.d.ts | 85 + .../node_modules/zod/v4/core/regexes.js | 139 + .../node_modules/zod/v4/core/registries.cjs | 56 + .../node_modules/zod/v4/core/registries.d.cts | 35 + .../node_modules/zod/v4/core/registries.d.ts | 35 + .../node_modules/zod/v4/core/registries.js | 51 + .../node_modules/zod/v4/core/schemas.cjs | 2270 ++++ .../node_modules/zod/v4/core/schemas.d.cts | 1184 ++ .../node_modules/zod/v4/core/schemas.d.ts | 1184 ++ .../node_modules/zod/v4/core/schemas.js | 2239 ++++ .../zod/v4/core/standard-schema.cjs | 2 + .../zod/v4/core/standard-schema.d.cts | 126 + .../zod/v4/core/standard-schema.d.ts | 126 + .../zod/v4/core/standard-schema.js | 1 + .../zod/v4/core/to-json-schema.cjs | 457 + .../zod/v4/core/to-json-schema.d.cts | 114 + .../zod/v4/core/to-json-schema.d.ts | 114 + .../zod/v4/core/to-json-schema.js | 448 + .../node_modules/zod/v4/core/util.cjs | 734 ++ .../node_modules/zod/v4/core/util.d.cts | 200 + .../node_modules/zod/v4/core/util.d.ts | 200 + .../node_modules/zod/v4/core/util.js | 674 + .../node_modules/zod/v4/core/versions.cjs | 8 + .../node_modules/zod/v4/core/versions.d.cts | 5 + .../node_modules/zod/v4/core/versions.d.ts | 5 + .../node_modules/zod/v4/core/versions.js | 5 + .../zod@4.4.3/node_modules/zod/v4/index.cjs | 22 + .../zod@4.4.3/node_modules/zod/v4/index.d.cts | 3 + .../zod@4.4.3/node_modules/zod/v4/index.d.ts | 3 + .../zod@4.4.3/node_modules/zod/v4/index.js | 3 + .../node_modules/zod/v4/locales/ar.cjs | 133 + .../node_modules/zod/v4/locales/ar.d.cts | 5 + .../node_modules/zod/v4/locales/ar.d.ts | 4 + .../node_modules/zod/v4/locales/ar.js | 106 + .../node_modules/zod/v4/locales/az.cjs | 132 + .../node_modules/zod/v4/locales/az.d.cts | 5 + .../node_modules/zod/v4/locales/az.d.ts | 4 + .../node_modules/zod/v4/locales/az.js | 105 + .../node_modules/zod/v4/locales/be.cjs | 183 + .../node_modules/zod/v4/locales/be.d.cts | 5 + .../node_modules/zod/v4/locales/be.d.ts | 4 + .../node_modules/zod/v4/locales/be.js | 156 + .../node_modules/zod/v4/locales/bg.cjs | 147 + .../node_modules/zod/v4/locales/bg.d.cts | 5 + .../node_modules/zod/v4/locales/bg.d.ts | 4 + .../node_modules/zod/v4/locales/bg.js | 120 + .../node_modules/zod/v4/locales/ca.cjs | 134 + .../node_modules/zod/v4/locales/ca.d.cts | 5 + .../node_modules/zod/v4/locales/ca.d.ts | 4 + .../node_modules/zod/v4/locales/ca.js | 107 + .../node_modules/zod/v4/locales/cs.cjs | 138 + .../node_modules/zod/v4/locales/cs.d.cts | 5 + .../node_modules/zod/v4/locales/cs.d.ts | 4 + .../node_modules/zod/v4/locales/cs.js | 111 + .../node_modules/zod/v4/locales/da.cjs | 142 + .../node_modules/zod/v4/locales/da.d.cts | 5 + .../node_modules/zod/v4/locales/da.d.ts | 4 + .../node_modules/zod/v4/locales/da.js | 115 + .../node_modules/zod/v4/locales/de.cjs | 135 + .../node_modules/zod/v4/locales/de.d.cts | 5 + .../node_modules/zod/v4/locales/de.d.ts | 4 + .../node_modules/zod/v4/locales/de.js | 108 + .../node_modules/zod/v4/locales/el.cjs | 136 + .../node_modules/zod/v4/locales/el.d.cts | 5 + .../node_modules/zod/v4/locales/el.d.ts | 4 + .../node_modules/zod/v4/locales/el.js | 109 + .../node_modules/zod/v4/locales/en.cjs | 140 + .../node_modules/zod/v4/locales/en.d.cts | 5 + .../node_modules/zod/v4/locales/en.d.ts | 4 + .../node_modules/zod/v4/locales/en.js | 113 + .../node_modules/zod/v4/locales/eo.cjs | 136 + .../node_modules/zod/v4/locales/eo.d.cts | 5 + .../node_modules/zod/v4/locales/eo.d.ts | 4 + .../node_modules/zod/v4/locales/eo.js | 109 + .../node_modules/zod/v4/locales/es.cjs | 159 + .../node_modules/zod/v4/locales/es.d.cts | 5 + .../node_modules/zod/v4/locales/es.d.ts | 4 + .../node_modules/zod/v4/locales/es.js | 132 + .../node_modules/zod/v4/locales/fa.cjs | 141 + .../node_modules/zod/v4/locales/fa.d.cts | 5 + .../node_modules/zod/v4/locales/fa.d.ts | 4 + .../node_modules/zod/v4/locales/fa.js | 114 + .../node_modules/zod/v4/locales/fi.cjs | 139 + .../node_modules/zod/v4/locales/fi.d.cts | 5 + .../node_modules/zod/v4/locales/fi.d.ts | 4 + .../node_modules/zod/v4/locales/fi.js | 112 + .../node_modules/zod/v4/locales/fr-CA.cjs | 134 + .../node_modules/zod/v4/locales/fr-CA.d.cts | 5 + .../node_modules/zod/v4/locales/fr-CA.d.ts | 4 + .../node_modules/zod/v4/locales/fr-CA.js | 107 + .../node_modules/zod/v4/locales/fr.cjs | 152 + .../node_modules/zod/v4/locales/fr.d.cts | 5 + .../node_modules/zod/v4/locales/fr.d.ts | 4 + .../node_modules/zod/v4/locales/fr.js | 125 + .../node_modules/zod/v4/locales/he.cjs | 241 + .../node_modules/zod/v4/locales/he.d.cts | 5 + .../node_modules/zod/v4/locales/he.d.ts | 4 + .../node_modules/zod/v4/locales/he.js | 214 + .../node_modules/zod/v4/locales/hr.cjs | 149 + .../node_modules/zod/v4/locales/hr.d.cts | 5 + .../node_modules/zod/v4/locales/hr.d.ts | 4 + .../node_modules/zod/v4/locales/hr.js | 122 + .../node_modules/zod/v4/locales/hu.cjs | 135 + .../node_modules/zod/v4/locales/hu.d.cts | 5 + .../node_modules/zod/v4/locales/hu.d.ts | 4 + .../node_modules/zod/v4/locales/hu.js | 108 + .../node_modules/zod/v4/locales/hy.cjs | 174 + .../node_modules/zod/v4/locales/hy.d.cts | 5 + .../node_modules/zod/v4/locales/hy.d.ts | 4 + .../node_modules/zod/v4/locales/hy.js | 147 + .../node_modules/zod/v4/locales/id.cjs | 133 + .../node_modules/zod/v4/locales/id.d.cts | 5 + .../node_modules/zod/v4/locales/id.d.ts | 4 + .../node_modules/zod/v4/locales/id.js | 106 + .../node_modules/zod/v4/locales/index.cjs | 111 + .../node_modules/zod/v4/locales/index.d.cts | 52 + .../node_modules/zod/v4/locales/index.d.ts | 52 + .../node_modules/zod/v4/locales/index.js | 52 + .../node_modules/zod/v4/locales/is.cjs | 136 + .../node_modules/zod/v4/locales/is.d.cts | 5 + .../node_modules/zod/v4/locales/is.d.ts | 4 + .../node_modules/zod/v4/locales/is.js | 109 + .../node_modules/zod/v4/locales/it.cjs | 135 + .../node_modules/zod/v4/locales/it.d.cts | 5 + .../node_modules/zod/v4/locales/it.d.ts | 4 + .../node_modules/zod/v4/locales/it.js | 108 + .../node_modules/zod/v4/locales/ja.cjs | 134 + .../node_modules/zod/v4/locales/ja.d.cts | 5 + .../node_modules/zod/v4/locales/ja.d.ts | 4 + .../node_modules/zod/v4/locales/ja.js | 107 + .../node_modules/zod/v4/locales/ka.cjs | 139 + .../node_modules/zod/v4/locales/ka.d.cts | 5 + .../node_modules/zod/v4/locales/ka.d.ts | 4 + .../node_modules/zod/v4/locales/ka.js | 112 + .../node_modules/zod/v4/locales/kh.cjs | 12 + .../node_modules/zod/v4/locales/kh.d.cts | 5 + .../node_modules/zod/v4/locales/kh.d.ts | 5 + .../node_modules/zod/v4/locales/kh.js | 5 + .../node_modules/zod/v4/locales/km.cjs | 137 + .../node_modules/zod/v4/locales/km.d.cts | 5 + .../node_modules/zod/v4/locales/km.d.ts | 4 + .../node_modules/zod/v4/locales/km.js | 110 + .../node_modules/zod/v4/locales/ko.cjs | 138 + .../node_modules/zod/v4/locales/ko.d.cts | 5 + .../node_modules/zod/v4/locales/ko.d.ts | 4 + .../node_modules/zod/v4/locales/ko.js | 111 + .../node_modules/zod/v4/locales/lt.cjs | 230 + .../node_modules/zod/v4/locales/lt.d.cts | 5 + .../node_modules/zod/v4/locales/lt.d.ts | 4 + .../node_modules/zod/v4/locales/lt.js | 203 + .../node_modules/zod/v4/locales/mk.cjs | 136 + .../node_modules/zod/v4/locales/mk.d.cts | 5 + .../node_modules/zod/v4/locales/mk.d.ts | 4 + .../node_modules/zod/v4/locales/mk.js | 109 + .../node_modules/zod/v4/locales/ms.cjs | 134 + .../node_modules/zod/v4/locales/ms.d.cts | 5 + .../node_modules/zod/v4/locales/ms.d.ts | 4 + .../node_modules/zod/v4/locales/ms.js | 107 + .../node_modules/zod/v4/locales/nl.cjs | 137 + .../node_modules/zod/v4/locales/nl.d.cts | 5 + .../node_modules/zod/v4/locales/nl.d.ts | 4 + .../node_modules/zod/v4/locales/nl.js | 110 + .../node_modules/zod/v4/locales/no.cjs | 135 + .../node_modules/zod/v4/locales/no.d.cts | 5 + .../node_modules/zod/v4/locales/no.d.ts | 4 + .../node_modules/zod/v4/locales/no.js | 108 + .../node_modules/zod/v4/locales/ota.cjs | 136 + .../node_modules/zod/v4/locales/ota.d.cts | 5 + .../node_modules/zod/v4/locales/ota.d.ts | 4 + .../node_modules/zod/v4/locales/ota.js | 109 + .../node_modules/zod/v4/locales/package.json | 7 + .../node_modules/zod/v4/locales/pl.cjs | 136 + .../node_modules/zod/v4/locales/pl.d.cts | 5 + .../node_modules/zod/v4/locales/pl.d.ts | 4 + .../node_modules/zod/v4/locales/pl.js | 109 + .../node_modules/zod/v4/locales/ps.cjs | 141 + .../node_modules/zod/v4/locales/ps.d.cts | 5 + .../node_modules/zod/v4/locales/ps.d.ts | 4 + .../node_modules/zod/v4/locales/ps.js | 114 + .../node_modules/zod/v4/locales/pt.cjs | 135 + .../node_modules/zod/v4/locales/pt.d.cts | 5 + .../node_modules/zod/v4/locales/pt.d.ts | 4 + .../node_modules/zod/v4/locales/pt.js | 108 + .../node_modules/zod/v4/locales/ro.cjs | 146 + .../node_modules/zod/v4/locales/ro.d.cts | 5 + .../node_modules/zod/v4/locales/ro.d.ts | 4 + .../node_modules/zod/v4/locales/ro.js | 119 + .../node_modules/zod/v4/locales/ru.cjs | 183 + .../node_modules/zod/v4/locales/ru.d.cts | 5 + .../node_modules/zod/v4/locales/ru.d.ts | 4 + .../node_modules/zod/v4/locales/ru.js | 156 + .../node_modules/zod/v4/locales/sl.cjs | 136 + .../node_modules/zod/v4/locales/sl.d.cts | 5 + .../node_modules/zod/v4/locales/sl.d.ts | 4 + .../node_modules/zod/v4/locales/sl.js | 109 + .../node_modules/zod/v4/locales/sv.cjs | 137 + .../node_modules/zod/v4/locales/sv.d.cts | 5 + .../node_modules/zod/v4/locales/sv.d.ts | 4 + .../node_modules/zod/v4/locales/sv.js | 110 + .../node_modules/zod/v4/locales/ta.cjs | 137 + .../node_modules/zod/v4/locales/ta.d.cts | 5 + .../node_modules/zod/v4/locales/ta.d.ts | 4 + .../node_modules/zod/v4/locales/ta.js | 110 + .../node_modules/zod/v4/locales/th.cjs | 137 + .../node_modules/zod/v4/locales/th.d.cts | 5 + .../node_modules/zod/v4/locales/th.d.ts | 4 + .../node_modules/zod/v4/locales/th.js | 110 + .../node_modules/zod/v4/locales/tr.cjs | 132 + .../node_modules/zod/v4/locales/tr.d.cts | 5 + .../node_modules/zod/v4/locales/tr.d.ts | 4 + .../node_modules/zod/v4/locales/tr.js | 105 + .../node_modules/zod/v4/locales/ua.cjs | 12 + .../node_modules/zod/v4/locales/ua.d.cts | 5 + .../node_modules/zod/v4/locales/ua.d.ts | 5 + .../node_modules/zod/v4/locales/ua.js | 5 + .../node_modules/zod/v4/locales/uk.cjs | 135 + .../node_modules/zod/v4/locales/uk.d.cts | 5 + .../node_modules/zod/v4/locales/uk.d.ts | 4 + .../node_modules/zod/v4/locales/uk.js | 108 + .../node_modules/zod/v4/locales/ur.cjs | 137 + .../node_modules/zod/v4/locales/ur.d.cts | 5 + .../node_modules/zod/v4/locales/ur.d.ts | 4 + .../node_modules/zod/v4/locales/ur.js | 110 + .../node_modules/zod/v4/locales/uz.cjs | 137 + .../node_modules/zod/v4/locales/uz.d.cts | 5 + .../node_modules/zod/v4/locales/uz.d.ts | 4 + .../node_modules/zod/v4/locales/uz.js | 110 + .../node_modules/zod/v4/locales/vi.cjs | 135 + .../node_modules/zod/v4/locales/vi.d.cts | 5 + .../node_modules/zod/v4/locales/vi.d.ts | 4 + .../node_modules/zod/v4/locales/vi.js | 108 + .../node_modules/zod/v4/locales/yo.cjs | 134 + .../node_modules/zod/v4/locales/yo.d.cts | 5 + .../node_modules/zod/v4/locales/yo.d.ts | 4 + .../node_modules/zod/v4/locales/yo.js | 107 + .../node_modules/zod/v4/locales/zh-CN.cjs | 136 + .../node_modules/zod/v4/locales/zh-CN.d.cts | 5 + .../node_modules/zod/v4/locales/zh-CN.d.ts | 4 + .../node_modules/zod/v4/locales/zh-CN.js | 109 + .../node_modules/zod/v4/locales/zh-TW.cjs | 134 + .../node_modules/zod/v4/locales/zh-TW.d.cts | 5 + .../node_modules/zod/v4/locales/zh-TW.d.ts | 4 + .../node_modules/zod/v4/locales/zh-TW.js | 107 + .../node_modules/zod/v4/mini/checks.cjs | 34 + .../node_modules/zod/v4/mini/checks.d.cts | 1 + .../node_modules/zod/v4/mini/checks.d.ts | 1 + .../node_modules/zod/v4/mini/checks.js | 1 + .../node_modules/zod/v4/mini/coerce.cjs | 52 + .../node_modules/zod/v4/mini/coerce.d.cts | 7 + .../node_modules/zod/v4/mini/coerce.d.ts | 7 + .../node_modules/zod/v4/mini/coerce.js | 22 + .../node_modules/zod/v4/mini/external.cjs | 63 + .../node_modules/zod/v4/mini/external.d.cts | 13 + .../node_modules/zod/v4/mini/external.d.ts | 13 + .../node_modules/zod/v4/mini/external.js | 14 + .../node_modules/zod/v4/mini/index.cjs | 32 + .../node_modules/zod/v4/mini/index.d.cts | 3 + .../node_modules/zod/v4/mini/index.d.ts | 3 + .../node_modules/zod/v4/mini/index.js | 3 + .../node_modules/zod/v4/mini/iso.cjs | 64 + .../node_modules/zod/v4/mini/iso.d.cts | 22 + .../node_modules/zod/v4/mini/iso.d.ts | 22 + .../zod@4.4.3/node_modules/zod/v4/mini/iso.js | 34 + .../node_modules/zod/v4/mini/package.json | 7 + .../node_modules/zod/v4/mini/parse.cjs | 16 + .../node_modules/zod/v4/mini/parse.d.cts | 1 + .../node_modules/zod/v4/mini/parse.d.ts | 1 + .../node_modules/zod/v4/mini/parse.js | 1 + .../node_modules/zod/v4/mini/schemas.cjs | 1083 ++ .../node_modules/zod/v4/mini/schemas.d.cts | 445 + .../node_modules/zod/v4/mini/schemas.d.ts | 445 + .../node_modules/zod/v4/mini/schemas.js | 961 ++ .../node_modules/zod/v4/package.json | 7 + .../@deepseek-ai/dsh-host-apiproxy | 1 + dsh-local-403-fix/package.json | 33 + ...-ai+dsh-client-connection@0.1.0-rc.7.patch | 13 + dsh-local-403-fix/pnpm-lock.yaml | 991 ++ dsh-local-403-fix/pnpm-workspace.yaml | 45 + dsh-local-403-fix/src/index.js | 262 + my_deepseek.sh | 67 + 3219 files changed, 426272 insertions(+) create mode 100644 dsh-local-403-fix/README.md create mode 100755 dsh-local-403-fix/apply-403-fix.sh create mode 100644 dsh-local-403-fix/cordis.patch.yml create mode 100755 dsh-local-403-fix/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.modules.yaml create mode 100644 dsh-local-403-fix/node_modules/.package-map.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm-workspace-state-v1.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/types/index.d.ts.map create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/node_modules/.bin/cordis create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/node_modules/.bin/js-yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/src/index.ts create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cosmokit create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/js-yaml create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/entry.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/entry.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/group.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/group.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/isolate.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/isolate.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/tree.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/tree.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/utils.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/utils.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/index.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/internal.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/internal.d.ts.map create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/entry.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/group.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/isolate.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/tree.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/utils.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/internal.ts create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cosmokit create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis-plugin-include create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis-plugin-loader create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/README.md create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/context.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/context.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/events.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/events.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/fiber.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/fiber.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/index.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/logger.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/logger.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/reflect.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/reflect.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/registry.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/registry.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/service.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/service.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/utils.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/utils.d.ts.map create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/context.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/events.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/fiber.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/logger.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/reflect.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/registry.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/service.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/utils.ts create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cosmokit create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@standard-schema/spec create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/array.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/array.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/index.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/string.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/string.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/time.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/time.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/array.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/misc.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/string.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/time.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/types.ts create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-settings create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-settings create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis-plugin-include create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis-plugin-loader create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/cordis create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/js-yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-atomic-write create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-home-paths create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-settings create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-system-prompt create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/js-yaml create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis-plugin-include create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis-plugin-loader create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/cordis create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/js-yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-atomic-write create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-home-paths create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-settings create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-system-prompt create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/js-yaml create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-system-prompt create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-system-prompt create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-client-connection create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-typert-registry create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-client-connection create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-typert-registry create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-agent-presets create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-gateway create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-commands create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-cordis-host-runner create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-credentials create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-goal create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-host-plugin-inventory create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-message-feedback create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-settings create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-typert-registry create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-agent-presets create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-gateway create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-commands create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-cordis-host-runner create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-credentials create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-goal create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-host-plugin-inventory create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-message-feedback create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-settings create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-typert-registry create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/brand.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/error.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/types.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/brand.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/error.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/types.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-attachment create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-path.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-request-trust.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/api.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/connection.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/fixture.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/random-uuid.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/rpc.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/web-api-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/http-bridge.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/loopback-hostname.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc-host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/websocket-downlink.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-commands create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-host-apiproxy create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-host-webserver create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-tools create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/ws create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-attachment create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-path.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-request-trust.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/api.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/connection.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/fixture.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/random-uuid.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/rpc.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/web-api-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/http-bridge.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/loopback-hostname.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc-host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/websocket-downlink.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-commands create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-host-apiproxy create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-host-webserver create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-tools create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/ws create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/types.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/types.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-brand create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-brand create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-brand create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-tools create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-brand create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-tools create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-brand create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-brand create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-brand create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-session-projection create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-brand create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-session-projection create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent-default-model create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent-presets create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-api-remotes create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-attachment create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-commands create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-cordis-host-runner create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-credentials create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-goal create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-directory-picker create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-jobs create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-native-command create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-projection create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-projection-cache create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-query create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-title create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-settings create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-skill create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-subagent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-tools create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-user-approval create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-user-questions create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-workspace create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/fflate create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent-default-model create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent-presets create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-api-remotes create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-attachment create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-commands create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-cordis-host-runner create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-credentials create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-goal create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-directory-picker create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-jobs create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-native-command create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-projection create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-projection-cache create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-query create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-title create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-settings create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-skill create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-subagent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-tools create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-user-approval create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-user-questions create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-workspace create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/fflate create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/cordis-plugin-loader create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-brand create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/cordis-plugin-loader create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-brand create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-attachment create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/content.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/content.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/error.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/error.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/message.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/message.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/never.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/never.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-timeout create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-attachment create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/content.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/content.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/error.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/error.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/message.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/message.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/never.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/never.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-timeout create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-llm create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-storage-domain create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-llm create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-storage-domain create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/scoped-events.generated.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/store.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/scoped-events.generated.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/store.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/coordinator.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/preparations.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/revision.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/write-behind.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-timeout create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/coordinator.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/preparations.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/revision.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/write-behind.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-timeout create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/spec.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-storage-domain create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/spec.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-storage-domain create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-persistence create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/config.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/corpus.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/cursor.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/documents.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/extraction.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/filters.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/sources.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/tracing.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/types.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-title create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-persistence create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/config.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/corpus.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/cursor.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/documents.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/extraction.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/filters.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/sources.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/tracing.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/types.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-title create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-projection create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-projection create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-scope create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/json.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/json.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/repair.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/repair.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/surface.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/surface.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-scope create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/json.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/json.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/repair.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/repair.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/surface.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/surface.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-scope create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-scope create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/domain.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/error.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/events.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/spec.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/domain.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/error.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/events.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/spec.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/backend.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/error.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/registry.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/backend.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/error.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/registry.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-agent-presets create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-jobs create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-projection create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-projection-cache create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-tools create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-user-approval create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-agent-presets create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-jobs create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-projection create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-projection-cache create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-tools create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-user-approval create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-scope create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-scope create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/types/invariant.d.ts create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-code-runtime create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-system-prompt create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-user-approval create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-code-runtime create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-system-prompt create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-user-approval create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-invariants create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-protocol create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-protocol create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/client.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-system-prompt create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-system-prompt create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-llm create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-llm create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-storage create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-storage-domain create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-storage create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-storage-domain create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.i18n.yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.zh.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/node_modules/.bin/cordis create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/package.json create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/zod create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/cosmokit create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/index.mjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/src/index.ts create mode 120000 dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@standard-schema/spec create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/CHANGELOG.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/argparse.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/lib/sub.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/lib/textwrap.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/CHANGELOG.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/browser.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/browser.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.d.mts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.mjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/browser.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/browser.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node-worker.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/worker.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/umd/index.js create mode 120000 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/argparse create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/README.md create mode 100755 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.js.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.min.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.min.js.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.mjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.mjs.map create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/common.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/dumper.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/exception.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/index_vite_proxy.tmp.mjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/loader.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/core.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/default.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/failsafe.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/json.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/snippet.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/binary.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/bool.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/float.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/int.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/map.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/merge.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/null.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/omap.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/pairs.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/seq.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/set.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/str.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/timestamp.js create mode 100755 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules/.bin/js-yaml create mode 100644 dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/lock.yaml create mode 100755 dsh-local-403-fix/node_modules/.pnpm/node_modules/.bin/cordis create mode 100755 dsh-local-403-fix/node_modules/.pnpm/node_modules/.bin/js-yaml create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis-plugin-include create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis-plugin-loader create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cosmokit create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent-default-model create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent-presets create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-api-gateway create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-api-remotes create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-atomic-write create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-attachment create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-brand create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-client-connection create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-code-runtime create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-commands create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-cordis-host-runner create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-credentials create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-goal create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-home-paths create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-directory-picker create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-plugin-inventory create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-webserver create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-invariants create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-jobs create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-llm create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-message-feedback create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-native-command create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-scope create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-persistence create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-projection create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-projection-cache create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-query create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-title create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-settings create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-skill create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-storage create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-storage-domain create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-subagent create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-system-prompt create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-timeout create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-tools create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-typert-protocol create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-typert-registry create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-user-approval create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-user-questions create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-workspace create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/schemastery create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/@standard-schema/spec create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/argparse create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/fflate create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/js-yaml create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/ws create mode 120000 dsh-local-403-fix/node_modules/.pnpm/node_modules/zod create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/browser.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/buffer-util.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/constants.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/event-target.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/extension.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/limiter.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/permessage-deflate.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/receiver.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/sender.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/stream.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/subprotocol.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/validation.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/websocket-server.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/websocket.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/wrapper.mjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/LICENSE create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/README.md create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/locales/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/mini/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/ZodError.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/datetime.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/discriminatedUnion.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/ipv4.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/object.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/primitives.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/realworld.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/string.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/union.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/errors.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/external.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/enumUtil.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/errorUtil.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/parseUtil.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/partialUtil.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/typeAliases.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/util.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/locales/en.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/standard-schema.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/Mocker.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/all-errors.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/anyunknown.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/array.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/async-parsing.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/async-refinements.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/base.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/bigint.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/branded.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/catch.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/coerce.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/complex.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/custom.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/date.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/deepmasking.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/default.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/description.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/discriminated-unions.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/enum.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/error.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/firstparty.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/firstpartyschematypes.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/function.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/generics.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/instanceof.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/intersection.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/language-server.source.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/language-server.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/literal.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/map.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/masking.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/mocker.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nan.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nativeEnum.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nullable.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/number.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object-augmentation.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object-in-es5-env.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/optional.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/parseUtil.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/parser.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/partials.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/pickomit.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/pipeline.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/preprocess.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/primitive.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/promise.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/readonly.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/record.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/recursive.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/refine.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/safeparse.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/set.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/standard-schema.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/string.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/transformer.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/tuple.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/unions.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/validations.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/void.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/types.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4-mini/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/checks.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/coerce.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/compat.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/errors.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/external.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/from-json-schema.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/iso.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/parse.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/schemas.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/anyunknown.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/apply.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/array.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/assignability.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/async-parsing.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/async-refinements.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/base.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/bigint.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/brand.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/catch.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/coalesce.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/codec-examples.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/codec.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/coerce.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/continuability.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/custom.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/date.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/datetime.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/default.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/describe-meta-checks.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/description.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/detached-methods.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/enum.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/error-utils.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/error.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/file.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/firstparty.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/fix-json-issue.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/from-json-schema.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/function.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/generics.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/global-config.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/hash.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/index.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/instanceof.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/intersection.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/jitless-allows-eval.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/json.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/lazy.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/literal.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/locales_ka.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/locales_ro.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/map.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/nan.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/nested-refine.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/nonoptional.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/nullable.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/number.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/object.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/optional.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/partial.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/pickomit.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/pipe.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/prefault.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/preprocess-types.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/preprocess.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/primitive.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/promise.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/prototypes.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/readonly.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/record.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/refine.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/registries.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/set.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/standard-schema.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/string-formats.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/string.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/stringbool.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/template-literal.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/to-json-schema-methods.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/transform.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/tuple.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/union.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/url.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/validations.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/tests/void.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/api.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/checks.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/config.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/core.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/doc.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/errors.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/json-schema-generator.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/json-schema-processors.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/json-schema.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/parse.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/regexes.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/registries.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/schemas.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/standard-schema.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/extend.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/index.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/be.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/el.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/en.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/es.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/fr.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/he.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/hr.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/nl.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/ru.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/tr.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/locales/uz.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/record-constructor.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/tests/recursive-tuples.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/to-json-schema.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/util.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/versions.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/core/zsf.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ar.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/az.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/be.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/bg.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ca.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/cs.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/da.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/de.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/el.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/en.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/eo.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/es.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/fa.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/fi.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/fr-CA.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/fr.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/he.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/hr.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/hu.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/hy.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/id.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/is.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/it.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ja.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ka.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/kh.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/km.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ko.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/lt.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/mk.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ms.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/nl.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/no.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ota.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/pl.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ps.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/pt.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ro.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ru.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/sl.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/sv.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ta.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/th.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/tr.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ua.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/uk.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/ur.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/uz.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/vi.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/yo.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/zh-CN.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/locales/zh-TW.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/checks.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/coerce.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/external.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/index.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/iso.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/parse.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/schemas.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/apply.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/assignability.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/brand.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/checks.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/codec.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/computed.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/error.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/functions.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/index.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/number.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/object.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/prototypes.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/recursive-types.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/standard-schema.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/mini/tests/string.test.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/ZodError.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/ZodError.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/ZodError.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/ZodError.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/errors.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/errors.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/errors.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/errors.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/external.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/external.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/external.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/external.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/enumUtil.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/enumUtil.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/enumUtil.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/enumUtil.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/errorUtil.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/errorUtil.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/errorUtil.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/errorUtil.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/parseUtil.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/parseUtil.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/parseUtil.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/parseUtil.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/partialUtil.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/partialUtil.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/partialUtil.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/partialUtil.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/typeAliases.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/typeAliases.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/typeAliases.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/typeAliases.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/util.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/util.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/util.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/util.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/locales/en.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/locales/en.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/locales/en.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/locales/en.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/standard-schema.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/standard-schema.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/standard-schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/standard-schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/types.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/types.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/types.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/types.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4-mini/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4-mini/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4-mini/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4-mini/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4-mini/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/checks.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/checks.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/checks.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/checks.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/coerce.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/coerce.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/coerce.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/coerce.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/compat.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/compat.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/compat.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/compat.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/errors.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/errors.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/errors.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/errors.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/from-json-schema.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/from-json-schema.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/from-json-schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/from-json-schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/iso.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/iso.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/iso.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/iso.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/parse.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/parse.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/parse.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/parse.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/api.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/api.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/api.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/api.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/checks.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/checks.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/checks.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/checks.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/doc.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/doc.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/doc.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/doc.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/errors.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/errors.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/errors.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/errors.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-generator.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-generator.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-generator.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-generator.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/parse.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/parse.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/parse.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/parse.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/regexes.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/regexes.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/regexes.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/regexes.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/schemas.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/schemas.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/schemas.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/schemas.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/standard-schema.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/standard-schema.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/standard-schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/standard-schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ar.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ar.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ar.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ar.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/az.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/az.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/az.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/az.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/be.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/be.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/be.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/be.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/bg.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/bg.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/bg.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/bg.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ca.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ca.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ca.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ca.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/cs.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/cs.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/cs.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/cs.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/da.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/da.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/da.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/da.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/de.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/de.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/de.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/de.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/el.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/el.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/el.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/el.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/en.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/en.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/en.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/en.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/eo.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/eo.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/eo.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/eo.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/es.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/es.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/es.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/es.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fa.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fa.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fa.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fa.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fi.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fi.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fi.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fi.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fr-CA.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fr-CA.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fr-CA.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fr-CA.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fr.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fr.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fr.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/fr.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/he.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/he.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/he.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/he.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hr.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hr.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hr.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hr.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hu.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hu.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hu.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hu.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hy.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hy.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hy.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/hy.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/id.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/id.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/id.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/id.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/is.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/is.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/is.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/is.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/it.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/it.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/it.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/it.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ja.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ja.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ja.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ja.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ka.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ka.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ka.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ka.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/kh.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/kh.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/kh.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/kh.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/km.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/km.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/km.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/km.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ko.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ko.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ko.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ko.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/lt.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/lt.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/lt.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/lt.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/mk.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/mk.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/mk.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/mk.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ms.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ms.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ms.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ms.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/nl.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/nl.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/nl.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/nl.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/no.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/no.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/no.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/no.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ota.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ota.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ota.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ota.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/pl.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/pl.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/pl.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/pl.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ps.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ps.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ps.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ps.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/pt.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/pt.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/pt.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/pt.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ro.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ro.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ro.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ro.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ru.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ru.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ru.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ru.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/sl.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/sl.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/sl.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/sl.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/sv.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/sv.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/sv.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/sv.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ta.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ta.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ta.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ta.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/th.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/th.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/th.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/th.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/tr.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/tr.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/tr.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/tr.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ua.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ua.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ua.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ua.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/uk.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/uk.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/uk.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/uk.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ur.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ur.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ur.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/ur.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/uz.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/uz.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/uz.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/uz.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/vi.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/vi.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/vi.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/vi.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/yo.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/yo.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/yo.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/yo.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/zh-CN.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/zh-CN.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/zh-CN.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/zh-CN.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/zh-TW.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/zh-TW.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/zh-TW.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/zh-TW.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/checks.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/checks.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/checks.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/checks.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/coerce.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/coerce.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/coerce.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/coerce.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/external.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/external.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/external.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/external.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/index.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/index.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/index.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/index.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/iso.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/iso.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/iso.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/iso.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/package.json create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/parse.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/parse.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/parse.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/parse.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/schemas.cjs create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/schemas.d.cts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/schemas.d.ts create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/schemas.js create mode 100644 dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/package.json create mode 120000 dsh-local-403-fix/node_modules/@deepseek-ai/dsh-host-apiproxy create mode 100644 dsh-local-403-fix/package.json create mode 100644 dsh-local-403-fix/patches/@deepseek-ai+dsh-client-connection@0.1.0-rc.7.patch create mode 100644 dsh-local-403-fix/pnpm-lock.yaml create mode 100644 dsh-local-403-fix/pnpm-workspace.yaml create mode 100644 dsh-local-403-fix/src/index.js create mode 100644 my_deepseek.sh diff --git a/dsh-local-403-fix/README.md b/dsh-local-403-fix/README.md new file mode 100644 index 0000000..f0f0067 --- /dev/null +++ b/dsh-local-403-fix/README.md @@ -0,0 +1,75 @@ +# dsh-local-403-fix + +修复 `dsh web` 反向代理访问时特权 `/api` 方法返回 **403** 的问题。 + +## 背景 + +官方 `@deepseek-ai/dsh-client-connection` 把 15 个特权方法(`settings.*`、`credentials.*`、 +`agentPreset.*`、`host.pickDirectory/openPath`、`llm.discoverModels`)钉死在 **loopback**: +前缀路由先用配置的 `trustedHosts` 校验,但进入 fetch handler 后,这些方法会**用空列表 +再校验一次**: + +```js +// dsh-client-connection@0.1.0-rc.7 lib/index.js 第 538 行 +if (method !== void 0 && PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, [])) + return new Response("forbidden", { status: 403 }); +``` + +因此即使 `--trusted-host` 配置了公网域名/IP,任何经过反向代理(本环境为 +Xray 隧道 + socat)到达的请求,只要 `Host` 头不是 loopback,特权方法一律 403。 +这是官方刻意设计(配置/凭据平面在"真正的认证层出现之前"保持 loopback 同源), +上游 master 至今未改(`packages/client/connection/src/index.ts` 第 147 行)。 + +## 方案(本目录采用一行补丁,替代旧的 260 行插件) + +对运行时实际加载的全局包打一行补丁,把特权检查的空列表换成配置的 `trustedHosts`: + +```diff +- if (method !== void 0 && PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, [])) return new Response("forbidden", { status: 403 }); ++ if (method !== void 0 && PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, trustedHosts)) return new Response("forbidden", { status: 403 }); +``` + +语义与上游一致:`trustedHosts` 仍是 DNS-rebinding 围栏,不是认证层。 +`trustedHosts` 变量在 `apply()` 作用域内(第 531 行),补丁无需额外改动。 + +## 文件 + +| 文件 | 作用 | +|---|---| +| `patches/@deepseek-ai+dsh-client-connection@0.1.0-rc.7.patch` | 标准 pnpm 补丁(进 git,可复现) | +| `apply-403-fix.sh` | 幂等脚本:定位全局包 → 备份 → `patch -p1` 应用/回滚/检查 | +| `package.json` | `pnpm.patchedDependencies` 声明(工程内 pnpm install 时自动应用) | +| `cordis.patch.yml` + `src/index.js` | ⚠️ 旧方案(260 行插件 bundle),已由本补丁替代,保留仅供回退参考 | + +## 用法 + +```bash +# 应用补丁(幂等;my_deepseek.sh 启动前会自动调用) +./apply-403-fix.sh + +# 检查状态 +./apply-403-fix.sh --check + +# 回滚 +./apply-403-fix.sh --revert +``` + +应用后重启 dsh 生效: + +```bash +my_deepseek.sh stop && my_deepseek.sh +``` + +## 为什么不用 pnpm patchedDependencies 直接生效? + +`pnpm.patchedDependencies` 只对**当前 pnpm 工程的依赖树**生效;而本环境的 dsh 是 +**全局 npm 安装**(`/home/salmonstill/.nvm/.../lib/node_modules/@deepseek-ai/dsh`), +运行时加载的是全局那份 `dsh-client-connection`。所以工程内保留标准补丁文件 + +`apply-403-fix.sh` 幂等打到全局包,两者兼顾可复现与运行时生效。 +将来若把 dsh 改为工程内安装,`patchedDependencies` 声明可直接复用。 + +## 升级 dsh 后 + +- `apply-403-fix.sh --check` 会显示 `unknown`(特权检查行已变),此时需对照新版 + 源码更新补丁文件; +- 补丁文件内的 blob hash 需用 `git hash-object` 重新计算(见 git 历史或脚本注释)。 diff --git a/dsh-local-403-fix/apply-403-fix.sh b/dsh-local-403-fix/apply-403-fix.sh new file mode 100755 index 0000000..fc98b05 --- /dev/null +++ b/dsh-local-403-fix/apply-403-fix.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +# apply-403-fix.sh — 幂等应用/回滚 dsh 403 修复补丁(方案 2) +# +# 背景:官方 dsh 把特权 /api 方法(settings.*、credentials.* 等)钉死在 +# loopback,反向代理访问时即使配置了 --trusted-host 也返回 403。本脚本把 +# 一行补丁打到运行时实际加载的全局 @deepseek-ai/dsh-client-connection 上, +# 让特权方法也使用配置的 trustedHosts 列表校验(trustedHosts 仍是 +# DNS-rebinding 围栏,不是认证,语义与上游一致)。 +# +# 用法: +# apply-403-fix.sh # 应用补丁(幂等,已应用则跳过) +# apply-403-fix.sh --check # 仅检查补丁状态,不修改 +# apply-403-fix.sh --revert # 从备份回滚补丁 +# apply-403-fix.sh --help # 帮助 +# +# 说明: +# - 通过 `readlink -f $(which dsh)` 定位全局 dsh 包根,不依赖硬编码路径 +# - 应用前自动备份为 lib/index.js.orig +# - 补丁文件在工程内维护:patches/@deepseek-ai+dsh-client-connection@0.1.0-rc.7.patch +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PATCH_FILE="$SCRIPT_DIR/patches/@deepseek-ai+dsh-client-connection@0.1.0-rc.7.patch" + +# 期望补丁后特权检查行包含 trustedHosts(而非空列表) +PATCHED_MARKER='PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, trustedHosts)' +ORIGINAL_MARKER='PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, []))' + +die() { echo "[apply-403-fix] 错误: $*" >&2; exit 1; } +info() { echo "[apply-403-fix] $*"; } + +# ── 定位运行时实际加载的全局 dsh 包 ────────────────────────────────────── +DSH_BIN="$(command -v dsh || true)" +if [ -z "$DSH_BIN" ]; then + die "未找到 dsh 命令。请确认已全局安装 @deepseek-ai/dsh。" +fi +DSH_REAL="$(readlink -f "$DSH_BIN")" # .../lib/node_modules/@deepseek-ai/dsh/lib/bin.js +DSH_ROOT="$(dirname "$(dirname "$DSH_REAL")")" # .../lib/node_modules/@deepseek-ai/dsh +CC_DIR="$DSH_ROOT/node_modules/@deepseek-ai/dsh-client-connection" +TARGET="$CC_DIR/lib/index.js" + +if [ ! -f "$TARGET" ]; then + die "未找到 $TARGET(dsh 依赖布局与预期不符,请检查 dsh 安装)。" +fi +if [ ! -f "$PATCH_FILE" ]; then + die "未找到补丁文件 $PATCH_FILE。" +fi + +# ── 检查状态 ────────────────────────────────────────────────────────────── +check_state() { + if grep -qF "$PATCHED_MARKER" "$TARGET"; then + echo "patched" + elif grep -qF "$ORIGINAL_MARKER" "$TARGET"; then + echo "unpatched" + else + echo "unknown" + fi +} + +# ── --check ─────────────────────────────────────────────────────────────── +if [ "${1:-}" = "--check" ]; then + case "$(check_state)" in + patched) info "已打补丁: $TARGET"; exit 0 ;; + unpatched) info "未打补丁: $TARGET"; exit 0 ;; + *) die "无法识别 $TARGET 的状态(可能 dsh 版本已升级,补丁已过期)。" ;; + esac +fi + +# ── --revert ────────────────────────────────────────────────────────────── +if [ "${1:-}" = "--revert" ]; then + if [ "$(check_state)" = "unpatched" ]; then + info "当前未打补丁,无需回滚。" + exit 0 + fi + if [ ! -f "$TARGET.orig" ]; then + die "没有备份文件 $TARGET.orig,无法回滚(可能不是本脚本打的补丁)。" + fi + cp "$TARGET.orig" "$TARGET" + info "已从备份回滚: $TARGET" + exit 0 +fi + +# ── --help / 未知参数 ──────────────────────────────────────────────────── +if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then + grep '^#' "$0" | sed 's/^# \{0,1\}//' + exit 0 +fi +if [ $# -gt 0 ]; then + die "未知参数: $*(用 --help 查看用法)" +fi + +# ── 应用补丁(幂等) ───────────────────────────────────────────────────── +case "$(check_state)" in + patched) + info "已打补丁,跳过: $TARGET" + exit 0 + ;; + unknown) + die "无法识别 $TARGET 的状态,拒绝修改。请人工检查(可能 dsh 已升级)。" + ;; +esac + +# 备份原始文件(仅在应用时创建,--revert 依赖它) +if [ ! -f "$TARGET.orig" ]; then + cp "$TARGET" "$TARGET.orig" + info "已备份原始文件: $TARGET.orig" +else + info "备份已存在,保留: $TARGET.orig" +fi + +# 在包根目录执行 patch -p1(补丁内路径为 lib/index.js) +if ! (cd "$CC_DIR" && patch -p1 --forward < "$PATCH_FILE"); then + info "patch 应用失败,正在回滚本次修改…" + if [ -f "$TARGET.orig" ]; then cp "$TARGET.orig" "$TARGET"; fi + die "补丁应用失败,已恢复原状。请人工检查。" +fi + +# 应用后校验 +if [ "$(check_state)" = "patched" ]; then + info "补丁已应用: $TARGET" +else + die "补丁应用后校验失败,请人工检查 $TARGET。" +fi +info "提示: 需要重启 dsh(my_deepseek.sh stop && my_deepseek.sh)后生效。" diff --git a/dsh-local-403-fix/cordis.patch.yml b/dsh-local-403-fix/cordis.patch.yml new file mode 100644 index 0000000..1bdb882 --- /dev/null +++ b/dsh-local-403-fix/cordis.patch.yml @@ -0,0 +1,18 @@ +# Local 403 fix for the web profile. +# Official dsh pins privileged /api methods (settings, credentials, presets, +# host dialogs, llm.discoverModels) to loopback by re-checking them with an +# empty trusted-host list. That makes a reverse-proxied /api always return 403 +# even when --trusted-host lists the public host. +# +# This bundle inserts one row that registers exact /api/ routes for +# those methods and validates them against the same webRuntime.trustedHosts +# list the rest of /api uses, so a host listed in --trusted-host can call them. +# +# trustedHosts keeps the official webRuntime expression, so +# `dsh web --trusted-host ` still feeds this fence. +- insert: + - id: local-403-fix + name: dsh-local-403-fix + inject: [webRuntime] + config: + trustedHosts: !!js ctx.webRuntime.trustedHosts diff --git a/dsh-local-403-fix/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.bin/cordis new file mode 100755 index 0000000..dc6cdc5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.modules.yaml b/dsh-local-403-fix/node_modules/.modules.yaml new file mode 100644 index 0000000..338ae76 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.modules.yaml @@ -0,0 +1,189 @@ +{ + "hoistedDependencies": { + "@standard-schema/spec@1.1.0": { + "@standard-schema/spec": "private" + }, + "@deepseek-ai/cosmokit@1.8.2": { + "@deepseek-ai/cosmokit": "private" + }, + "@deepseek-ai/cordis-plugin-loader@1.0.2(@deepseek-ai/cordis@4.0.1)": { + "@deepseek-ai/cordis-plugin-loader": "private" + }, + "@deepseek-ai/cordis-plugin-include@1.0.6(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)": { + "@deepseek-ai/cordis-plugin-include": "private" + }, + "ws@8.21.3": { + "ws": "private" + }, + "@deepseek-ai/schemastery@3.18.1": { + "@deepseek-ai/schemastery": "private" + }, + "zod@4.4.3": { + "zod": "private" + }, + "fflate@0.8.3": { + "fflate": "private" + }, + "js-yaml@4.3.1": { + "js-yaml": "private" + }, + "argparse@2.0.1": { + "argparse": "private" + }, + "@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)": { + "@deepseek-ai/dsh-agent": "private" + }, + "@deepseek-ai/dsh-agent-default-model@0.1.0-rc.7(1eb7ceb2998733be9eba21a37a3dc291)": { + "@deepseek-ai/dsh-agent-default-model": "private" + }, + "@deepseek-ai/dsh-api-remotes@0.1.0-rc.7(022498c733cc9b813e36f108b907ce4c)": { + "@deepseek-ai/dsh-api-remotes": "private" + }, + "@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-brand": "private" + }, + "@deepseek-ai/dsh-commands@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))": { + "@deepseek-ai/dsh-commands": "private" + }, + "@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-attachment": "private" + }, + "@deepseek-ai/dsh-credentials@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-credentials": "private" + }, + "@deepseek-ai/dsh-goal@0.1.0-rc.7(9616cea51a4bea931c5522310292a042)": { + "@deepseek-ai/dsh-goal": "private" + }, + "@deepseek-ai/dsh-host-directory-picker@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-host-directory-picker": "private" + }, + "@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))": { + "@deepseek-ai/dsh-llm": "private" + }, + "@deepseek-ai/dsh-native-command@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-native-command": "private" + }, + "@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)": { + "@deepseek-ai/dsh-session": "private" + }, + "@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))": { + "@deepseek-ai/dsh-session-persistence": "private" + }, + "@deepseek-ai/dsh-session-projection@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))": { + "@deepseek-ai/dsh-session-projection": "private" + }, + "@deepseek-ai/dsh-session-projection-cache@0.1.0-rc.7(5ae699d01eec9f3ccaa1e8c13f88dd36)": { + "@deepseek-ai/dsh-session-projection-cache": "private" + }, + "@deepseek-ai/dsh-session-query@0.1.0-rc.7(fa24861d08a9d735fc78888af6ddf326)": { + "@deepseek-ai/dsh-session-query": "private" + }, + "@deepseek-ai/dsh-settings@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1)": { + "@deepseek-ai/dsh-settings": "private" + }, + "@deepseek-ai/dsh-skill@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))": { + "@deepseek-ai/dsh-skill": "private" + }, + "@deepseek-ai/dsh-subagent@0.1.0-rc.7(17b22c2aa5d99096c13835bb226cad51)": { + "@deepseek-ai/dsh-subagent": "private" + }, + "@deepseek-ai/dsh-jobs@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))": { + "@deepseek-ai/dsh-jobs": "private" + }, + "@deepseek-ai/dsh-tools@0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa)": { + "@deepseek-ai/dsh-tools": "private" + }, + "@deepseek-ai/dsh-user-questions@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))": { + "@deepseek-ai/dsh-user-questions": "private" + }, + "@deepseek-ai/dsh-user-approval@0.1.0-rc.7(6b8cefd624fd84694a941b103cc9b3fb)": { + "@deepseek-ai/dsh-user-approval": "private" + }, + "@deepseek-ai/dsh-workspace@0.1.0-rc.7(52d55750df813bb508c3c8815dfcc2bd)": { + "@deepseek-ai/dsh-workspace": "private" + }, + "@deepseek-ai/dsh-session-title@0.1.0-rc.7(54a387d0d580a07b8dbef208df0b04c2)": { + "@deepseek-ai/dsh-session-title": "private" + }, + "@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)": { + "@deepseek-ai/cordis": "private" + }, + "@deepseek-ai/dsh-agent-presets@0.1.0-rc.7(c0f9f44edab94cddae92cd4b4f319bab)": { + "@deepseek-ai/dsh-agent-presets": "private" + }, + "@deepseek-ai/dsh-cordis-host-runner@0.1.0-rc.7(2a80d56ba6af58ca8075e00e0fa2157b)": { + "@deepseek-ai/dsh-cordis-host-runner": "private" + }, + "@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)": { + "@deepseek-ai/dsh-invariants": "private" + }, + "@deepseek-ai/dsh-atomic-write@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-atomic-write": "private" + }, + "@deepseek-ai/dsh-home-paths@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-home-paths": "private" + }, + "@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-scope": "private" + }, + "@deepseek-ai/dsh-system-prompt@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))": { + "@deepseek-ai/dsh-system-prompt": "private" + }, + "@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-typert-protocol": "private" + }, + "@deepseek-ai/dsh-api-gateway@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-client-connection@0.1.0-rc.7)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))": { + "@deepseek-ai/dsh-api-gateway": "private" + }, + "@deepseek-ai/dsh-host-plugin-inventory@0.1.0-rc.7(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))": { + "@deepseek-ai/dsh-host-plugin-inventory": "private" + }, + "@deepseek-ai/dsh-message-feedback@0.1.0-rc.7(1fcfefbbf5e365eda1a59fadd94056b9)": { + "@deepseek-ai/dsh-message-feedback": "private" + }, + "@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-typert-registry": "private" + }, + "@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-timeout": "private" + }, + "@deepseek-ai/dsh-storage-domain@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))": { + "@deepseek-ai/dsh-storage-domain": "private" + }, + "@deepseek-ai/dsh-code-runtime@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-code-runtime": "private" + }, + "@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-storage": "private" + }, + "@deepseek-ai/dsh-client-connection@0.1.0-rc.7(18ff0c05ab41670b8daa2e2e166479db)": { + "@deepseek-ai/dsh-client-connection": "private" + }, + "@deepseek-ai/dsh-host-webserver@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))": { + "@deepseek-ai/dsh-host-webserver": "private" + } + }, + "hoistPattern": [ + "*" + ], + "included": { + "dependencies": true, + "devDependencies": true, + "optionalDependencies": true + }, + "injectedDeps": {}, + "layoutVersion": 5, + "nodeLinker": "isolated", + "packageManager": "pnpm@11.22.0", + "pendingBuilds": [], + "publicHoistPattern": [], + "prunedAt": "Tue, 18 Aug 2026 01:51:00 GMT", + "registries": { + "default": "https://registry.npmjs.org/", + "@jsr": "https://npm.jsr.io/" + }, + "skipped": [], + "storeDir": "/home/salmonstill/.local/share/pnpm/store/v11", + "virtualStoreDir": ".pnpm", + "virtualStoreDirMaxLength": 120 +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.package-map.json b/dsh-local-403-fix/node_modules/.package-map.json new file mode 100644 index 0000000..6795f5b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.package-map.json @@ -0,0 +1 @@ +{"packages":{".":{"url":"..","dependencies":{"@deepseek-ai/dsh-host-apiproxy":"@deepseek-ai/dsh-host-apiproxy@0.1.0-rc.7(227e91a6307a4a5d4a380ed795ce9271)","dsh-local-403-fix":"."}},"@deepseek-ai/cordis-plugin-include@1.0.6(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)":{"url":"./.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/cordis-plugin-include":"@deepseek-ai/cordis-plugin-include@1.0.6(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/cordis-plugin-loader":"@deepseek-ai/cordis-plugin-loader@1.0.2(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/cosmokit":"@deepseek-ai/cosmokit@1.8.2","js-yaml":"js-yaml@4.3.1"}},"@deepseek-ai/cordis-plugin-loader@1.0.2(@deepseek-ai/cordis@4.0.1)":{"url":"./.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/cordis-plugin-loader":"@deepseek-ai/cordis-plugin-loader@1.0.2(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/cosmokit":"@deepseek-ai/cosmokit@1.8.2"}},"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)":{"url":"./.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/cordis-plugin-include":"@deepseek-ai/cordis-plugin-include@1.0.6(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/cordis-plugin-loader":"@deepseek-ai/cordis-plugin-loader@1.0.2(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/cosmokit":"@deepseek-ai/cosmokit@1.8.2","@standard-schema/spec":"@standard-schema/spec@1.1.0"}},"@deepseek-ai/cosmokit@1.8.2":{"url":"./.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit","dependencies":{"@deepseek-ai/cosmokit":"@deepseek-ai/cosmokit@1.8.2"}},"@deepseek-ai/dsh-agent-default-model@0.1.0-rc.7(1eb7ceb2998733be9eba21a37a3dc291)":{"url":"./.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-agent-default-model":"@deepseek-ai/dsh-agent-default-model@0.1.0-rc.7(1eb7ceb2998733be9eba21a37a3dc291)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-settings":"@deepseek-ai/dsh-settings@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1)","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1"}},"@deepseek-ai/dsh-agent-presets@0.1.0-rc.7(c0f9f44edab94cddae92cd4b4f319bab)":{"url":"./.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/cordis-plugin-include":"@deepseek-ai/cordis-plugin-include@1.0.6(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/cordis-plugin-loader":"@deepseek-ai/cordis-plugin-loader@1.0.2(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-agent-presets":"@deepseek-ai/dsh-agent-presets@0.1.0-rc.7(c0f9f44edab94cddae92cd4b4f319bab)","@deepseek-ai/dsh-atomic-write":"@deepseek-ai/dsh-atomic-write@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-home-paths":"@deepseek-ai/dsh-home-paths@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-settings":"@deepseek-ai/dsh-settings@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1)","@deepseek-ai/dsh-system-prompt":"@deepseek-ai/dsh-system-prompt@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1","js-yaml":"js-yaml@4.3.1"}},"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)":{"url":"./.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-system-prompt":"@deepseek-ai/dsh-system-prompt@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))"}},"@deepseek-ai/dsh-api-gateway@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-client-connection@0.1.0-rc.7)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))":{"url":"./.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-api-gateway":"@deepseek-ai/dsh-api-gateway@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-client-connection@0.1.0-rc.7)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-client-connection":"@deepseek-ai/dsh-client-connection@0.1.0-rc.7(18ff0c05ab41670b8daa2e2e166479db)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-typert-registry":"@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))"}},"@deepseek-ai/dsh-api-remotes@0.1.0-rc.7(022498c733cc9b813e36f108b907ce4c)":{"url":"./.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-agent-presets":"@deepseek-ai/dsh-agent-presets@0.1.0-rc.7(c0f9f44edab94cddae92cd4b4f319bab)","@deepseek-ai/dsh-api-gateway":"@deepseek-ai/dsh-api-gateway@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-client-connection@0.1.0-rc.7)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-api-remotes":"@deepseek-ai/dsh-api-remotes@0.1.0-rc.7(022498c733cc9b813e36f108b907ce4c)","@deepseek-ai/dsh-commands":"@deepseek-ai/dsh-commands@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-cordis-host-runner":"@deepseek-ai/dsh-cordis-host-runner@0.1.0-rc.7(2a80d56ba6af58ca8075e00e0fa2157b)","@deepseek-ai/dsh-credentials":"@deepseek-ai/dsh-credentials@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-goal":"@deepseek-ai/dsh-goal@0.1.0-rc.7(9616cea51a4bea931c5522310292a042)","@deepseek-ai/dsh-host-plugin-inventory":"@deepseek-ai/dsh-host-plugin-inventory@0.1.0-rc.7(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-message-feedback":"@deepseek-ai/dsh-message-feedback@0.1.0-rc.7(1fcfefbbf5e365eda1a59fadd94056b9)","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-persistence":"@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-settings":"@deepseek-ai/dsh-settings@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1)","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-typert-registry":"@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))"}},"@deepseek-ai/dsh-atomic-write@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-atomic-write":"@deepseek-ai/dsh-atomic-write@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)"}},"@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-attachment":"@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)"}},"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)"}},"@deepseek-ai/dsh-client-connection@0.1.0-rc.7(18ff0c05ab41670b8daa2e2e166479db)":{"url":"./.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-attachment":"@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-client-connection":"@deepseek-ai/dsh-client-connection@0.1.0-rc.7(18ff0c05ab41670b8daa2e2e166479db)","@deepseek-ai/dsh-commands":"@deepseek-ai/dsh-commands@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-host-apiproxy":"@deepseek-ai/dsh-host-apiproxy@0.1.0-rc.7(227e91a6307a4a5d4a380ed795ce9271)","@deepseek-ai/dsh-host-webserver":"@deepseek-ai/dsh-host-webserver@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-tools":"@deepseek-ai/dsh-tools@0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa)","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1","ws":"ws@8.21.3"}},"@deepseek-ai/dsh-code-runtime@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-code-runtime":"@deepseek-ai/dsh-code-runtime@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)"}},"@deepseek-ai/dsh-commands@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))":{"url":"./.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-commands":"@deepseek-ai/dsh-commands@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-cordis-host-runner@0.1.0-rc.7(2a80d56ba6af58ca8075e00e0fa2157b)":{"url":"./.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-cordis-host-runner":"@deepseek-ai/dsh-cordis-host-runner@0.1.0-rc.7(2a80d56ba6af58ca8075e00e0fa2157b)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-tools":"@deepseek-ai/dsh-tools@0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa)","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-credentials@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-credentials":"@deepseek-ai/dsh-credentials@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)"}},"@deepseek-ai/dsh-goal@0.1.0-rc.7(9616cea51a4bea931c5522310292a042)":{"url":"./.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-goal":"@deepseek-ai/dsh-goal@0.1.0-rc.7(9616cea51a4bea931c5522310292a042)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-projection":"@deepseek-ai/dsh-session-projection@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-home-paths@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-home-paths":"@deepseek-ai/dsh-home-paths@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)"}},"@deepseek-ai/dsh-host-apiproxy@0.1.0-rc.7(227e91a6307a4a5d4a380ed795ce9271)":{"url":"./.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-agent-default-model":"@deepseek-ai/dsh-agent-default-model@0.1.0-rc.7(1eb7ceb2998733be9eba21a37a3dc291)","@deepseek-ai/dsh-agent-presets":"@deepseek-ai/dsh-agent-presets@0.1.0-rc.7(c0f9f44edab94cddae92cd4b4f319bab)","@deepseek-ai/dsh-api-remotes":"@deepseek-ai/dsh-api-remotes@0.1.0-rc.7(022498c733cc9b813e36f108b907ce4c)","@deepseek-ai/dsh-attachment":"@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-commands":"@deepseek-ai/dsh-commands@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-cordis-host-runner":"@deepseek-ai/dsh-cordis-host-runner@0.1.0-rc.7(2a80d56ba6af58ca8075e00e0fa2157b)","@deepseek-ai/dsh-credentials":"@deepseek-ai/dsh-credentials@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-goal":"@deepseek-ai/dsh-goal@0.1.0-rc.7(9616cea51a4bea931c5522310292a042)","@deepseek-ai/dsh-host-apiproxy":"@deepseek-ai/dsh-host-apiproxy@0.1.0-rc.7(227e91a6307a4a5d4a380ed795ce9271)","@deepseek-ai/dsh-host-directory-picker":"@deepseek-ai/dsh-host-directory-picker@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-jobs":"@deepseek-ai/dsh-jobs@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-native-command":"@deepseek-ai/dsh-native-command@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-persistence":"@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-session-projection":"@deepseek-ai/dsh-session-projection@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))","@deepseek-ai/dsh-session-projection-cache":"@deepseek-ai/dsh-session-projection-cache@0.1.0-rc.7(5ae699d01eec9f3ccaa1e8c13f88dd36)","@deepseek-ai/dsh-session-query":"@deepseek-ai/dsh-session-query@0.1.0-rc.7(fa24861d08a9d735fc78888af6ddf326)","@deepseek-ai/dsh-session-title":"@deepseek-ai/dsh-session-title@0.1.0-rc.7(54a387d0d580a07b8dbef208df0b04c2)","@deepseek-ai/dsh-settings":"@deepseek-ai/dsh-settings@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1)","@deepseek-ai/dsh-skill":"@deepseek-ai/dsh-skill@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-subagent":"@deepseek-ai/dsh-subagent@0.1.0-rc.7(17b22c2aa5d99096c13835bb226cad51)","@deepseek-ai/dsh-tools":"@deepseek-ai/dsh-tools@0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa)","@deepseek-ai/dsh-user-approval":"@deepseek-ai/dsh-user-approval@0.1.0-rc.7(6b8cefd624fd84694a941b103cc9b3fb)","@deepseek-ai/dsh-user-questions":"@deepseek-ai/dsh-user-questions@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))","@deepseek-ai/dsh-workspace":"@deepseek-ai/dsh-workspace@0.1.0-rc.7(52d55750df813bb508c3c8815dfcc2bd)","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1","fflate":"fflate@0.8.3","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-host-directory-picker@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-host-directory-picker":"@deepseek-ai/dsh-host-directory-picker@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)"}},"@deepseek-ai/dsh-host-plugin-inventory@0.1.0-rc.7(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))":{"url":"./.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/cordis-plugin-loader":"@deepseek-ai/cordis-plugin-loader@1.0.2(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-host-plugin-inventory":"@deepseek-ai/dsh-host-plugin-inventory@0.1.0-rc.7(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-host-webserver@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-host-webserver":"@deepseek-ai/dsh-host-webserver@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1"}},"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)":{"url":"./.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1"}},"@deepseek-ai/dsh-jobs@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))":{"url":"./.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-jobs":"@deepseek-ai/dsh-jobs@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)"}},"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))":{"url":"./.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-attachment":"@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-timeout":"@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1"}},"@deepseek-ai/dsh-message-feedback@0.1.0-rc.7(1fcfefbbf5e365eda1a59fadd94056b9)":{"url":"./.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-message-feedback":"@deepseek-ai/dsh-message-feedback@0.1.0-rc.7(1fcfefbbf5e365eda1a59fadd94056b9)","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-persistence":"@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-storage-domain":"@deepseek-ai/dsh-storage-domain@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-native-command@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-native-command":"@deepseek-ai/dsh-native-command@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))"}},"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))"}},"@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))":{"url":"./.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-persistence":"@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-timeout":"@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))"}},"@deepseek-ai/dsh-session-projection-cache@0.1.0-rc.7(5ae699d01eec9f3ccaa1e8c13f88dd36)":{"url":"./.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-persistence":"@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-session-projection":"@deepseek-ai/dsh-session-projection@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))","@deepseek-ai/dsh-session-projection-cache":"@deepseek-ai/dsh-session-projection-cache@0.1.0-rc.7(5ae699d01eec9f3ccaa1e8c13f88dd36)","@deepseek-ai/dsh-storage-domain":"@deepseek-ai/dsh-storage-domain@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-session-projection@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))":{"url":"./.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-projection":"@deepseek-ai/dsh-session-projection@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-session-query@0.1.0-rc.7(fa24861d08a9d735fc78888af6ddf326)":{"url":"./.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-persistence":"@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-session-query":"@deepseek-ai/dsh-session-query@0.1.0-rc.7(fa24861d08a9d735fc78888af6ddf326)","@deepseek-ai/dsh-session-title":"@deepseek-ai/dsh-session-title@0.1.0-rc.7(54a387d0d580a07b8dbef208df0b04c2)"}},"@deepseek-ai/dsh-session-title@0.1.0-rc.7(54a387d0d580a07b8dbef208df0b04c2)":{"url":"./.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-projection":"@deepseek-ai/dsh-session-projection@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))","@deepseek-ai/dsh-session-title":"@deepseek-ai/dsh-session-title@0.1.0-rc.7(54a387d0d580a07b8dbef208df0b04c2)","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)":{"url":"./.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))"}},"@deepseek-ai/dsh-settings@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1)":{"url":"./.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-settings":"@deepseek-ai/dsh-settings@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1)","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1"}},"@deepseek-ai/dsh-skill@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))":{"url":"./.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-skill":"@deepseek-ai/dsh-skill@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1"}},"@deepseek-ai/dsh-storage-domain@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))":{"url":"./.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-storage":"@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-storage-domain":"@deepseek-ai/dsh-storage-domain@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-storage":"@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))"}},"@deepseek-ai/dsh-subagent@0.1.0-rc.7(17b22c2aa5d99096c13835bb226cad51)":{"url":"./.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-agent-presets":"@deepseek-ai/dsh-agent-presets@0.1.0-rc.7(c0f9f44edab94cddae92cd4b4f319bab)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-jobs":"@deepseek-ai/dsh-jobs@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-persistence":"@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-session-projection":"@deepseek-ai/dsh-session-projection@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))","@deepseek-ai/dsh-session-projection-cache":"@deepseek-ai/dsh-session-projection-cache@0.1.0-rc.7(5ae699d01eec9f3ccaa1e8c13f88dd36)","@deepseek-ai/dsh-subagent":"@deepseek-ai/dsh-subagent@0.1.0-rc.7(17b22c2aa5d99096c13835bb226cad51)","@deepseek-ai/dsh-tools":"@deepseek-ai/dsh-tools@0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa)","@deepseek-ai/dsh-user-approval":"@deepseek-ai/dsh-user-approval@0.1.0-rc.7(6b8cefd624fd84694a941b103cc9b3fb)","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-system-prompt@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))":{"url":"./.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-system-prompt":"@deepseek-ai/dsh-system-prompt@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1"}},"@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-timeout":"@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))"}},"@deepseek-ai/dsh-tools@0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa)":{"url":"./.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-code-runtime":"@deepseek-ai/dsh-code-runtime@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-system-prompt":"@deepseek-ai/dsh-system-prompt@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-tools":"@deepseek-ai/dsh-tools@0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa)","@deepseek-ai/dsh-user-approval":"@deepseek-ai/dsh-user-approval@0.1.0-rc.7(6b8cefd624fd84694a941b103cc9b3fb)","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1"}},"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))"}},"@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))":{"url":"./.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-typert-protocol":"@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-typert-registry":"@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","zod":"zod@4.4.3"}},"@deepseek-ai/dsh-user-approval@0.1.0-rc.7(6b8cefd624fd84694a941b103cc9b3fb)":{"url":"./.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-scope":"@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-system-prompt":"@deepseek-ai/dsh-system-prompt@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-user-approval":"@deepseek-ai/dsh-user-approval@0.1.0-rc.7(6b8cefd624fd84694a941b103cc9b3fb)","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1"}},"@deepseek-ai/dsh-user-questions@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))":{"url":"./.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-agent":"@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-llm":"@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-user-questions":"@deepseek-ai/dsh-user-questions@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))"}},"@deepseek-ai/dsh-workspace@0.1.0-rc.7(52d55750df813bb508c3c8815dfcc2bd)":{"url":"./.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace","dependencies":{"@deepseek-ai/cordis":"@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)","@deepseek-ai/dsh-brand":"@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-invariants":"@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)","@deepseek-ai/dsh-session":"@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)","@deepseek-ai/dsh-session-persistence":"@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-storage":"@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))","@deepseek-ai/dsh-storage-domain":"@deepseek-ai/dsh-storage-domain@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))","@deepseek-ai/dsh-workspace":"@deepseek-ai/dsh-workspace@0.1.0-rc.7(52d55750df813bb508c3c8815dfcc2bd)","zod":"zod@4.4.3"}},"@deepseek-ai/schemastery@3.18.1":{"url":"./.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery","dependencies":{"@deepseek-ai/cosmokit":"@deepseek-ai/cosmokit@1.8.2","@deepseek-ai/schemastery":"@deepseek-ai/schemastery@3.18.1","@standard-schema/spec":"@standard-schema/spec@1.1.0"}},"@standard-schema/spec@1.1.0":{"url":"./.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec","dependencies":{"@standard-schema/spec":"@standard-schema/spec@1.1.0"}},"argparse@2.0.1":{"url":"./.pnpm/argparse@2.0.1/node_modules/argparse","dependencies":{"argparse":"argparse@2.0.1"}},"fflate@0.8.3":{"url":"./.pnpm/fflate@0.8.3/node_modules/fflate","dependencies":{"fflate":"fflate@0.8.3"}},"js-yaml@4.3.1":{"url":"./.pnpm/js-yaml@4.3.1/node_modules/js-yaml","dependencies":{"argparse":"argparse@2.0.1","js-yaml":"js-yaml@4.3.1"}},"ws@8.21.3":{"url":"./.pnpm/ws@8.21.3/node_modules/ws","dependencies":{"ws":"ws@8.21.3"}},"zod@4.4.3":{"url":"./.pnpm/zod@4.4.3/node_modules/zod","dependencies":{"zod":"zod@4.4.3"}}}} diff --git a/dsh-local-403-fix/node_modules/.pnpm-workspace-state-v1.json b/dsh-local-403-fix/node_modules/.pnpm-workspace-state-v1.json new file mode 100644 index 0000000..37e2681 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm-workspace-state-v1.json @@ -0,0 +1,29 @@ +{ + "lastValidatedTimestamp": 1787018031089, + "projects": {}, + "pnpmfiles": [], + "settings": { + "autoInstallPeers": true, + "dedupeDirectDeps": false, + "dedupeInjectedDeps": true, + "dedupePeerDependents": true, + "dedupePeers": false, + "dev": true, + "excludeLinksFromLockfile": false, + "hoistPattern": [ + "*" + ], + "hoistWorkspacePackages": true, + "injectWorkspacePackages": false, + "linkWorkspacePackages": false, + "minimumReleaseAge": 1440, + "minimumReleaseAgeIgnoreMissingTime": true, + "nodeLinker": "isolated", + "optional": true, + "peersSuffixMaxLength": 1000, + "preferWorkspacePackages": false, + "production": true, + "publicHoistPattern": [] + }, + "filteredInstall": false +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/LICENSE new file mode 100644 index 0000000..9fdec8c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-present Shigma + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/README.md new file mode 100644 index 0000000..de0ecdc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/README.md @@ -0,0 +1,43 @@ +# @cordisjs/plugin-include + +File-backed loader tree for Cordis. The include plugin reads a YAML or JSON +file, turns it into loader entries, and writes updates back when the file is +writable. + +## Usage + +```ts +import { Context } from 'cordis' +import Loader from '@cordisjs/plugin-loader' +import Include from '@cordisjs/plugin-include' + +const root = new Context() +await root.plugin(Loader, { baseUrl: import.meta.url }) +await root.plugin(Include, { + path: './cordis.yml', + initial: [], + enableLogs: true, +}) +``` + +Example `cordis.yml`: + +```yaml +- id: timer + name: '@cordisjs/plugin-timer' +- id: app + name: ./plugins/app + config: + message: hello +``` + +## Config + +| Field | Description | +| --- | --- | +| `path` | YAML or JSON file path resolved from `ctx.baseUrl`. | +| `initial` | Entry list written when the file is missing. | +| `patches` | Runtime patches applied after reading the file. | +| `enableLogs` | Enables loader apply, reload, and unload logs. | + +Patches can insert entries or override fields on entries with a matching `id`. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/index.js new file mode 100644 index 0000000..0fed5c0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/index.js @@ -0,0 +1,284 @@ +import { EntryGroup, EntryTree, isJsExpr } from "@deepseek-ai/cordis-plugin-loader"; +import { Service } from "@deepseek-ai/cordis"; +import { extname } from "node:path"; +import { access, constants, readFile, rename, writeFile } from "node:fs/promises"; +import { setTimeout as setTimeout$1 } from "node:timers/promises"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import * as yaml from "js-yaml"; +//#region lib/types/index.js +var __rewriteRelativeImportExtension = function(path, preserveJsx) { + if (typeof path === "string" && /^\.\.?\//.test(path)) return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) { + return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js"; + }); + return path; +}; +const JsExpr = new yaml.Type("tag:yaml.org,2002:js", { + kind: "scalar", + resolve: (data) => typeof data === "string", + construct: (data) => ({ __jsExpr: data }), + predicate: isJsExpr, + represent: (data) => data["__jsExpr"] +}); +/** +* The entry-list YAML dialect: `!!js` scalars round-trip as expression nodes +* the Loader evaluates at entry activation. Exported so config tooling +* (`dsh --dump-config`) parses and prints exactly the dialect this include +* mounts. +*/ +const entryListSchema = yaml.JSON_SCHEMA.extend(JsExpr); +const schema = entryListSchema; +const writable = { + ".json": "application/json", + ".yaml": "application/yaml", + ".yml": "application/yaml" +}; +const supported = new Set(Object.keys(writable)); +const WRITE_RETRY_LIMIT = 10; +const WRITE_RETRY_DELAY_MS = 50; +function retryableWriteError(error) { + const code = error?.code; + return code === "EACCES" || code === "EBUSY" || code === "EPERM"; +} +/** +* Apply patch lists to an entry list — THE patch semantics of this include, +* shared by mounting (`applyPatches`) and offline config tooling +* (`dsh --dump-config`) so a dump can never drift from what boots. The input +* is never mutated and the result is always detached from it (even with no +* patches): patching or mounting shared entry objects would bake earlier +* values into the cached parse, so repeated application (config hot-reloads) +* could never revert a removed or changed patch. Inserted entries are indexed +* as they are added, so a later patch in the same list can target a row an +* earlier patch inserted. A patch that matches nothing warns and is skipped. +* @param data - the parsed entry list (JSON-safe plain data). +* @param patches - the patch list to apply, in order. +* @param warn - sink for skipped-patch diagnostics (printf-style, `%C` = code). +* @returns a detached entry list with every applicable patch applied. +*/ +function applyEntryPatches(data, patches, warn) { + data = structuredClone(data); + if (!patches?.length) return data; + const entryMap = /* @__PURE__ */ new Map(); + const buildMap = (entries) => { + for (const entry of entries) { + if (entry.id) entryMap.set(entry.id, entry); + if (entry.group && Array.isArray(entry.config)) buildMap(entry.config); + } + }; + buildMap(data); + for (const patch of patches) { + const { id, insert, name, ...overrides } = patch; + if (insert) { + if (id) { + const target = entryMap.get(id); + if (!target) { + warn("patch insert: entry %C not found", id); + continue; + } + if (!target.group) { + warn("patch insert: entry %C is not a group", id); + continue; + } + if (!Array.isArray(target.config)) target.config = []; + target.config.push(...insert); + } else data.push(...insert); + buildMap(insert); + continue; + } + if (!id) { + warn("patch: id is required for non-insert patches"); + continue; + } + const target = entryMap.get(id); + if (!target) { + warn("patch: entry %C not found", id); + continue; + } + if (name && name !== target.name) { + warn("patch: name mismatch for %C (expected %C, got %C), skipping", id, target.name, name); + continue; + } + for (const [key, value] of Object.entries(overrides)) { + if (key === "id") continue; + target[key] = value; + } + } + return data; +} +var ConfigFileError = class extends Error { + stage; + constructor(stage, path, cause) { + super(`failed to ${stage} config file ${path}`, { cause }); + this.stage = stage; + this.name = "ConfigFileError"; + } +}; +/** Loader entry tree backed by a YAML or JSON file. */ +var Include = class extends EntryTree { + config; + static inject = ["loader"]; + static [EntryGroup.key] = true; + filename; + type; + readonly; + content; + data; + writeTask; + pendingWrite; + writeQueue = Promise.resolve(); + applyQueue = Promise.resolve(); + constructor(ctx, config) { + super(ctx); + this.config = config; + this.enableLogs = config.enableLogs ?? ctx.fiber.entry?.parent.tree.enableLogs ?? false; + this.filename = fileURLToPath(new URL(this.config.path, this.ctx.baseUrl)); + const ext = extname(this.filename); + if (!supported.has(ext)) throw new Error(`extension "${ext}" not supported`); + this.type = writable[ext]; + this.readonly = !this.type; + this.ctx.baseUrl = new URL(".", pathToFileURL(this.filename)).href; + ctx.on("internal/update", async (config, _, next) => { + if (config.path !== this.config.path) return next(); + await this.enqueue(async () => { + const data = this.applyPatches(this.data, config.patches); + await this.root.update(data); + this.config = config; + }); + }); + } + /** + * Serialize one child-tree mutation behind every earlier one. The group's + * transactional `update` is not reentrant: two concurrent applies (the init + * apply racing an HMR-triggered refresh from the watcher's initial scan) + * interleave create and rollback on the same entries and strand the include + * fiber without settling, so every apply path funnels through this queue. + * A predecessor's failure is its own caller's outcome and never gates the + * next task. + */ + enqueue(task) { + const run = this.applyQueue.then(task, task); + this.applyQueue = run.then(() => {}, () => {}); + return run; + } + async checkAccess() { + if (!this.type) return; + try { + await access(this.filename, constants.W_OK); + } catch { + this.readonly = true; + } + } + async read(forced = false) { + let content; + try { + content = await readFile(this.filename, "utf8"); + } catch (error) { + throw new ConfigFileError("read", this.filename, error); + } + if (!forced && this.content === content) return; + let data; + try { + if (this.type === "application/yaml") data = yaml.load(content, { schema }); + else if (this.type === "application/json") data = JSON.parse(content); + else { + const module = await import(__rewriteRelativeImportExtension( + /* @vite-ignore */ + this.filename + )); + data = module.default || module; + } + } catch (error) { + throw new ConfigFileError("parse", this.filename, error); + } + if (!Array.isArray(data)) throw new ConfigFileError("validate", this.filename, /* @__PURE__ */ new TypeError("config file must be a top-level array")); + return { + content, + data + }; + } + applyPatches(data, patches) { + return applyEntryPatches(data, patches, (message, ...args) => { + this.ctx.root.logger?.("loader").warn(message, ...args); + }); + } + async *[Service.init]() { + let candidate; + try { + candidate = await this.read(true); + } catch (error) { + if (!(error instanceof ConfigFileError) || error.stage !== "read" || error.cause?.code !== "ENOENT") throw error; + if (this.config.initial) { + await this._writeFile(this.config.initial); + candidate = await this.read(true); + } else throw new Error(`config file not found: ${this.filename}`); + } + yield () => this.stop(); + await this.apply(candidate); + } + async stop() { + await this.root.stop(); + await this.flushWrite(); + } + /** + * Re-read the file and transactionally refresh child entries when content changed. + * @returns a promise resolving after the new tree commits, or immediately when unchanged. + * @throws when reading, parsing, validation, application, or rollback fails; the last good tree remains active when rollback succeeds. + */ + async refresh() { + await this.enqueue(async () => { + const candidate = await this.read(); + if (!candidate) return; + await this._apply(candidate); + }); + } + apply(candidate) { + return this.enqueue(() => this._apply(candidate)); + } + async _apply(candidate) { + const data = this.applyPatches(candidate.data, this.config.patches); + await this.root.update(data); + this.content = candidate.content; + this.data = candidate.data; + await this.checkAccess(); + } + async _writeFile(config) { + if (this.readonly) throw new Error(`cannot overwrite readonly config`); + if (this.type === "application/yaml") this.content = yaml.dump(config, { schema }); + else if (this.type === "application/json") this.content = JSON.stringify(config, null, 2); + await writeFile(this.filename + ".tmp", this.content); + for (let retry = 0;; retry++) try { + await rename(this.filename + ".tmp", this.filename); + return; + } catch (error) { + if (!retryableWriteError(error) || retry >= WRITE_RETRY_LIMIT) throw error; + await setTimeout$1((retry + 1) * WRITE_RETRY_DELAY_MS); + } + } + writeFile(config) { + clearTimeout(this.writeTask); + this.pendingWrite = config; + this.writeTask = setTimeout(() => { + this.flushWrite(); + }, 0); + } + flushWrite() { + clearTimeout(this.writeTask); + this.writeTask = void 0; + const config = this.pendingWrite; + this.pendingWrite = void 0; + if (config === void 0) return this.writeQueue; + const run = this.writeQueue.then(() => this._writeFile(config), () => this._writeFile(config)); + this.writeQueue = run; + run.catch((error) => { + this.ctx.root.logger?.("loader").warn("failed to write config file %C", this.filename); + this.ctx.root.logger?.("loader").warn(error); + }); + return run; + } + /** Schedule a write of the current root entry data. */ + write() { + this.context.emit("loader/config-update"); + return this.writeFile(this.root.data); + } +}; +//#endregion +export { Include, Include as default, applyEntryPatches, entryListSchema }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/types/index.d.ts new file mode 100644 index 0000000..4189573 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/types/index.d.ts @@ -0,0 +1,99 @@ +import { EntryGroup, EntryTree, type EntryOptions } from '@deepseek-ai/cordis-plugin-loader'; +import { Context, Service } from '@deepseek-ai/cordis'; +import * as yaml from 'js-yaml'; +/** + * The entry-list YAML dialect: `!!js` scalars round-trip as expression nodes + * the Loader evaluates at entry activation. Exported so config tooling + * (`dsh --dump-config`) parses and prints exactly the dialect this include + * mounts. + */ +export declare const entryListSchema: yaml.Schema; +/** + * Apply patch lists to an entry list — THE patch semantics of this include, + * shared by mounting (`applyPatches`) and offline config tooling + * (`dsh --dump-config`) so a dump can never drift from what boots. The input + * is never mutated and the result is always detached from it (even with no + * patches): patching or mounting shared entry objects would bake earlier + * values into the cached parse, so repeated application (config hot-reloads) + * could never revert a removed or changed patch. Inserted entries are indexed + * as they are added, so a later patch in the same list can target a row an + * earlier patch inserted. A patch that matches nothing warns and is skipped. + * @param data - the parsed entry list (JSON-safe plain data). + * @param patches - the patch list to apply, in order. + * @param warn - sink for skipped-patch diagnostics (printf-style, `%C` = code). + * @returns a detached entry list with every applicable patch applied. + */ +export declare function applyEntryPatches(data: EntryOptions[], patches: PatchOptions[] | undefined, warn: (message: string, ...args: any[]) => void): EntryOptions[]; +/** Runtime patch applied to entries loaded from an included config file. */ +export interface PatchOptions { + id?: string; + insert?: EntryOptions[]; + name?: string; + config?: any; + group?: boolean | null; + disabled?: boolean | null; + inject?: any; + intercept?: any; + isolate?: any; + [key: string]: any; +} +/** Config namespace for the file-backed include loader. */ +export declare namespace Include { + /** Config for a file-backed loader subtree. */ + interface Config { + /** YAML or JSON path resolved from `ctx.baseUrl`. */ + path: string; + /** Entry list written when the file does not already exist. */ + initial?: any[]; + /** Runtime patches applied after reading the file. */ + patches?: PatchOptions[]; + /** Enables loader apply/reload/unload logs for this subtree. */ + enableLogs?: boolean; + } +} +/** Loader entry tree backed by a YAML or JSON file. */ +export declare class Include extends EntryTree { + config: Include.Config; + static inject: string[]; + static readonly [EntryGroup.key] = true; + filename: string; + private type?; + private readonly; + private content?; + private data?; + private writeTask?; + private pendingWrite?; + private writeQueue; + private applyQueue; + constructor(ctx: Context, config: Include.Config); + /** + * Serialize one child-tree mutation behind every earlier one. The group's + * transactional `update` is not reentrant: two concurrent applies (the init + * apply racing an HMR-triggered refresh from the watcher's initial scan) + * interleave create and rollback on the same entries and strand the include + * fiber without settling, so every apply path funnels through this queue. + * A predecessor's failure is its own caller's outcome and never gates the + * next task. + */ + private enqueue; + private checkAccess; + private read; + private applyPatches; + [Service.init](): AsyncGenerator<() => Promise, void, unknown>; + stop(): Promise; + /** + * Re-read the file and transactionally refresh child entries when content changed. + * @returns a promise resolving after the new tree commits, or immediately when unchanged. + * @throws when reading, parsing, validation, application, or rollback fails; the last good tree remains active when rollback succeeds. + */ + refresh(): Promise; + private apply; + private _apply; + private _writeFile; + private writeFile; + private flushWrite; + /** Schedule a write of the current root entry data. */ + write(): void; +} +export default Include; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/types/index.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/types/index.d.ts.map new file mode 100644 index 0000000..98d7a2f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/lib/types/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAY,KAAK,YAAY,EAAE,MAAM,mCAAmC,CAAA;AACtG,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKtD,OAAO,KAAK,IAAI,MAAM,SAAS,CAAA;AAU/B;;;;;GAKG;AACH,eAAO,MAAM,eAAe,aAAkC,CAAA;AAoB9D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,YAAY,EAAE,EACpB,OAAO,EAAE,YAAY,EAAE,GAAG,SAAS,EACnC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAC9C,YAAY,EAAE,CAkEhB;AAgBD,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;IACvB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IACzB,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,SAAS,CAAC,EAAE,GAAG,CAAA;IACf,OAAO,CAAC,EAAE,GAAG,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED,2DAA2D;AAC3D,yBAAiB,OAAO,CAAC;IACvB,+CAA+C;IAC/C,UAAiB,MAAM;QACrB,qDAAqD;QACrD,IAAI,EAAE,MAAM,CAAA;QACZ,+DAA+D;QAC/D,OAAO,CAAC,EAAE,GAAG,EAAE,CAAA;QACf,sDAAsD;QACtD,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;QACxB,gEAAgE;QAChE,UAAU,CAAC,EAAE,OAAO,CAAA;KACrB;CACF;AAED,uDAAuD;AACvD,qBAAa,OAAQ,SAAQ,SAAS;IAoBH,MAAM,EAAE,OAAO,CAAC,MAAM;IAnBvD,MAAM,CAAC,MAAM,WAAa;IAO1B,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,QAAO;IAEhC,QAAQ,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,IAAI,CAAC,CAAQ;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAC,CAAQ;IACxB,OAAO,CAAC,IAAI,CAAC,CAAgB;IAC7B,OAAO,CAAC,SAAS,CAAC,CAA4B;IAC9C,OAAO,CAAC,YAAY,CAAC,CAAgB;IACrC,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,UAAU,CAAsC;gBAE5C,GAAG,EAAE,OAAO,EAAS,MAAM,EAAE,OAAO,CAAC,MAAM;IAsBvD;;;;;;;;OAQG;IACH,OAAO,CAAC,OAAO;YAMD,WAAW;YASX,IAAI;IA2BlB,OAAO,CAAC,YAAY;IAMb,CAAC,OAAO,CAAC,IAAI,CAAC;IAkBf,IAAI;IAKV;;;;OAIG;IACG,OAAO;IAUb,OAAO,CAAC,KAAK;YAIC,MAAM;YAQN,UAAU;IAqBxB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,UAAU;IAkBlB,uDAAuD;IACvD,KAAK;CAIN;AAED,eAAe,OAAO,CAAA"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/node_modules/.bin/js-yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/node_modules/.bin/js-yaml new file mode 100755 index 0000000..7cb3d55 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/node_modules/.bin/js-yaml @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +else + exec node "$basedir/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/package.json new file mode 100644 index 0000000..1f03208 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/package.json @@ -0,0 +1,40 @@ +{ + "name": "@deepseek-ai/cordis-plugin-include", + "description": "Include files in cordis configurations", + "version": "1.0.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "vendor/include" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/types/**/*.d.ts", + "lib/types/**/*.d.ts.map", + "src" + ], + "author": "Shigma ", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "js-yaml": "^4.1.0", + "@deepseek-ai/cosmokit": "^1.8.2" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/src/index.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/src/index.ts new file mode 100644 index 0000000..5ee20ef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include/src/index.ts @@ -0,0 +1,377 @@ +import { EntryGroup, EntryTree, isJsExpr, type EntryOptions } from '@deepseek-ai/cordis-plugin-loader' +import { Context, Service } from '@deepseek-ai/cordis' +import { extname } from 'node:path' +import { access, constants, readFile, rename, writeFile } from 'node:fs/promises' +import { setTimeout as delay } from 'node:timers/promises' +import { fileURLToPath, pathToFileURL } from 'node:url' +import * as yaml from 'js-yaml' + +const JsExpr = new yaml.Type('tag:yaml.org,2002:js', { + kind: 'scalar', + resolve: (data) => typeof data === 'string', + construct: (data) => ({ __jsExpr: data }), + predicate: isJsExpr, + represent: (data) => data['__jsExpr'], +}) + +/** + * The entry-list YAML dialect: `!!js` scalars round-trip as expression nodes + * the Loader evaluates at entry activation. Exported so config tooling + * (`dsh --dump-config`) parses and prints exactly the dialect this include + * mounts. + */ +export const entryListSchema = yaml.JSON_SCHEMA.extend(JsExpr) + +const schema = entryListSchema + +const writable: Record = { + '.json': 'application/json', + '.yaml': 'application/yaml', + '.yml': 'application/yaml', +} + +const supported = new Set(Object.keys(writable)) + +const WRITE_RETRY_LIMIT = 10 +const WRITE_RETRY_DELAY_MS = 50 + +function retryableWriteError(error: unknown): boolean { + const code = (error as NodeJS.ErrnoException | null)?.code + return code === 'EACCES' || code === 'EBUSY' || code === 'EPERM' +} + +/** + * Apply patch lists to an entry list — THE patch semantics of this include, + * shared by mounting (`applyPatches`) and offline config tooling + * (`dsh --dump-config`) so a dump can never drift from what boots. The input + * is never mutated and the result is always detached from it (even with no + * patches): patching or mounting shared entry objects would bake earlier + * values into the cached parse, so repeated application (config hot-reloads) + * could never revert a removed or changed patch. Inserted entries are indexed + * as they are added, so a later patch in the same list can target a row an + * earlier patch inserted. A patch that matches nothing warns and is skipped. + * @param data - the parsed entry list (JSON-safe plain data). + * @param patches - the patch list to apply, in order. + * @param warn - sink for skipped-patch diagnostics (printf-style, `%C` = code). + * @returns a detached entry list with every applicable patch applied. + */ +export function applyEntryPatches( + data: EntryOptions[], + patches: PatchOptions[] | undefined, + warn: (message: string, ...args: any[]) => void, +): EntryOptions[] { + data = structuredClone(data) + if (!patches?.length) return data + + const entryMap = new Map() + const buildMap = (entries: EntryOptions[]) => { + for (const entry of entries) { + if (entry.id) entryMap.set(entry.id, entry) + if (entry.group && Array.isArray(entry.config)) { + buildMap(entry.config) + } + } + } + buildMap(data) + + for (const patch of patches) { + const { id, insert, name, ...overrides } = patch + + if (insert) { + if (id) { + const target = entryMap.get(id) + if (!target) { + warn('patch insert: entry %C not found', id) + continue + } + if (!target.group) { + warn('patch insert: entry %C is not a group', id) + continue + } + if (!Array.isArray(target.config)) target.config = [] + target.config.push(...insert) + } else { + data.push(...insert) + } + // Index what this patch added so a LATER patch in the same list can + // target it. Patch lists compose one layer per source (each bundle + // layer, then the user's, then `--patch` overlays), and a layer must be + // able to configure or disable a row an earlier layer inserted; without + // this, inserted rows were silently unpatchable. + buildMap(insert) + continue + } + + if (!id) { + warn('patch: id is required for non-insert patches') + continue + } + + const target = entryMap.get(id) + if (!target) { + warn('patch: entry %C not found', id) + continue + } + + if (name && name !== target.name) { + warn('patch: name mismatch for %C (expected %C, got %C), skipping', id, target.name, name) + continue + } + + for (const [key, value] of Object.entries(overrides)) { + if (key === 'id') continue + target[key] = value + } + } + + return data +} + +type ConfigUpdateStage = 'read' | 'parse' | 'validate' + +interface ReadCandidate { + content: string + data: EntryOptions[] +} + +class ConfigFileError extends Error { + constructor(public readonly stage: ConfigUpdateStage, path: string, cause: unknown) { + super(`failed to ${stage} config file ${path}`, { cause }) + this.name = 'ConfigFileError' + } +} + +/** Runtime patch applied to entries loaded from an included config file. */ +export interface PatchOptions { + id?: string + insert?: EntryOptions[] + name?: string + config?: any + group?: boolean | null + disabled?: boolean | null + inject?: any + intercept?: any + isolate?: any + [key: string]: any +} + +/** Config namespace for the file-backed include loader. */ +export namespace Include { + /** Config for a file-backed loader subtree. */ + export interface Config { + /** YAML or JSON path resolved from `ctx.baseUrl`. */ + path: string + /** Entry list written when the file does not already exist. */ + initial?: any[] + /** Runtime patches applied after reading the file. */ + patches?: PatchOptions[] + /** Enables loader apply/reload/unload logs for this subtree. */ + enableLogs?: boolean + } +} + +/** Loader entry tree backed by a YAML or JSON file. */ +export class Include extends EntryTree { + static inject = ['loader'] + + // Tree-carrier marker (the Group plugin declares the same): this config is + // entry and patch lists, so the Loader's `internal/config` interpolation + // keeps it literal — a `!!js` expression inside a nested row's config + // belongs to that row's fiber, resolving lazily in the row's own context. + // Include's own fields (`path`, `enableLogs`) therefore stay literal too. + static readonly [EntryGroup.key] = true + + public filename: string + private type?: string + private readonly: boolean + private content?: string + private data?: EntryOptions[] + private writeTask?: NodeJS.Timeout | undefined + private pendingWrite?: EntryOptions[] + private writeQueue: Promise = Promise.resolve() + private applyQueue: Promise = Promise.resolve() + + constructor(ctx: Context, public config: Include.Config) { + super(ctx) + this.enableLogs = config.enableLogs ?? ctx.fiber.entry?.parent.tree.enableLogs ?? false + this.filename = fileURLToPath(new URL(this.config.path, this.ctx.baseUrl)) + const ext = extname(this.filename) + if (!supported.has(ext)) { + throw new Error(`extension "${ext}" not supported`) + } + this.type = writable[ext] + this.readonly = !this.type + this.ctx.baseUrl = new URL('.', pathToFileURL(this.filename)).href + + ctx.on('internal/update', async (config, _, next) => { + if (config.path !== this.config.path) return next() + await this.enqueue(async () => { + const data = this.applyPatches(this.data!, config.patches) + await this.root.update(data) + this.config = config + }) + }) + } + + /** + * Serialize one child-tree mutation behind every earlier one. The group's + * transactional `update` is not reentrant: two concurrent applies (the init + * apply racing an HMR-triggered refresh from the watcher's initial scan) + * interleave create and rollback on the same entries and strand the include + * fiber without settling, so every apply path funnels through this queue. + * A predecessor's failure is its own caller's outcome and never gates the + * next task. + */ + private enqueue(task: () => Promise): Promise { + const run = this.applyQueue.then(task, task) + this.applyQueue = run.then(() => {}, () => {}) + return run + } + + private async checkAccess() { + if (!this.type) return + try { + await access(this.filename, constants.W_OK) + } catch { + this.readonly = true + } + } + + private async read(forced = false): Promise { + let content: string + try { + content = await readFile(this.filename, 'utf8') + } catch (error) { + throw new ConfigFileError('read', this.filename, error) + } + if (!forced && this.content === content) return + let data: any + try { + if (this.type === 'application/yaml') { + data = yaml.load(content, { schema }) + } else if (this.type === 'application/json') { + data = JSON.parse(content) + } else { + const module = await import(/* @vite-ignore */ this.filename) + data = module.default || module + } + } catch (error) { + throw new ConfigFileError('parse', this.filename, error) + } + if (!Array.isArray(data)) { + throw new ConfigFileError('validate', this.filename, new TypeError('config file must be a top-level array')) + } + return { content, data } + } + + private applyPatches(data: EntryOptions[], patches?: PatchOptions[]): EntryOptions[] { + return applyEntryPatches(data, patches, (message, ...args) => { + this.ctx.root.logger?.('loader').warn(message, ...args) + }) + } + + async* [Service.init]() { + let candidate: ReadCandidate + try { + candidate = (await this.read(true))! + } catch (error) { + if (!(error instanceof ConfigFileError) || error.stage !== 'read' || (error.cause as NodeJS.ErrnoException)?.code !== 'ENOENT') throw error + if (this.config.initial) { + await this._writeFile(this.config.initial as any) + candidate = (await this.read(true))! + } else { + throw new Error(`config file not found: ${this.filename}`) + } + } + + yield () => this.stop() + await this.apply(candidate) + } + + async stop() { + await this.root.stop() + await this.flushWrite() + } + + /** + * Re-read the file and transactionally refresh child entries when content changed. + * @returns a promise resolving after the new tree commits, or immediately when unchanged. + * @throws when reading, parsing, validation, application, or rollback fails; the last good tree remains active when rollback succeeds. + */ + async refresh() { + // Read inside the queue so the changed-content check compares against the + // predecessor's committed state, not a mid-apply snapshot. + await this.enqueue(async () => { + const candidate = await this.read() + if (!candidate) return + await this._apply(candidate) + }) + } + + private apply(candidate: ReadCandidate) { + return this.enqueue(() => this._apply(candidate)) + } + + private async _apply(candidate: ReadCandidate) { + const data = this.applyPatches(candidate.data, this.config.patches) + await this.root.update(data) + this.content = candidate.content + this.data = candidate.data + await this.checkAccess() + } + + private async _writeFile(config: EntryOptions[]) { + if (this.readonly) { + throw new Error(`cannot overwrite readonly config`) + } + if (this.type === 'application/yaml') { + this.content = yaml.dump(config, { schema }) + } else if (this.type === 'application/json') { + this.content = JSON.stringify(config, null, 2) + } + await writeFile(this.filename + '.tmp', this.content!) + for (let retry = 0; ; retry++) { + try { + await rename(this.filename + '.tmp', this.filename) + return + } catch (error) { + if (!retryableWriteError(error) || retry >= WRITE_RETRY_LIMIT) throw error + await delay((retry + 1) * WRITE_RETRY_DELAY_MS) + } + } + } + + private writeFile(config: EntryOptions[]) { + clearTimeout(this.writeTask) + this.pendingWrite = config + this.writeTask = setTimeout(() => { + void this.flushWrite() + }, 0) + } + + private flushWrite(): Promise { + clearTimeout(this.writeTask) + this.writeTask = undefined + const config = this.pendingWrite + this.pendingWrite = undefined + if (config === undefined) return this.writeQueue + const run = this.writeQueue.then( + () => this._writeFile(config), + () => this._writeFile(config), + ) + this.writeQueue = run + void run.catch((error) => { + this.ctx.root.logger?.('loader').warn('failed to write config file %C', this.filename) + this.ctx.root.logger?.('loader').warn(error) + }) + return run + } + + /** Schedule a write of the current root entry data. */ + write() { + this.context.emit('loader/config-update') + return this.writeFile(this.root.data) + } +} + +export default Include diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader new file mode 120000 index 0000000..614b839 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cosmokit b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cosmokit new file mode 120000 index 0000000..dfc2397 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cosmokit @@ -0,0 +1 @@ +../../../@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/js-yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/js-yaml new file mode 120000 index 0000000..87e33ce --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/js-yaml @@ -0,0 +1 @@ +../../js-yaml@4.3.1/node_modules/js-yaml \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/LICENSE new file mode 100644 index 0000000..9fdec8c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-present Shigma + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/README.md new file mode 100644 index 0000000..fb71b77 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/README.md @@ -0,0 +1,48 @@ +# @cordisjs/plugin-loader + +Runtime plugin loader for Cordis. The loader owns an `EntryTree`, imports plugin +modules by name, applies their config, and keeps the running plugin graph in +sync with entry updates. + +## Usage + +```ts +import { Context } from 'cordis' +import Loader from '@cordisjs/plugin-loader' + +const root = new Context() +await root.plugin(Loader, { baseUrl: import.meta.url }) + +const id = await root.loader.create({ + name: './plugins/example', + config: { enabled: true }, +}) + +await root.loader.await() +root.loader.update(id, { config: { enabled: false } }) +``` + +## Entry Options + +| Field | Description | +| --- | --- | +| `id` | Stable id for resolving, updating, and removing the entry. | +| `name` | Module specifier imported by the loader. | +| `config` | Config passed to the plugin. | +| `group` | Marks the entry as a group whose `config` is a child entry list. | +| `disabled` | Stops the entry and prevents it from starting. | +| `inject` | Adds required services or intercept config for this entry. | + +## API + +| API | Description | +| --- | --- | +| `loader.create(options, parent?, position?)` | Add and start an entry. | +| `loader.update(id, options, parent?, position?)` | Update, move, and restart an entry. | +| `loader.remove(id)` | Stop and delete an entry. | +| `loader.resolve(id)` | Resolve an entry by id, including nested `a:b` ids. | +| `loader.resolveGroup(id)` | Resolve the root group or a nested group. | +| `loader.await()` | Wait for pending entry imports and fiber reloads. | +| `loader.locate(fiber?)` | Return the loader entry id that owns a fiber. | + +For file-backed trees, use `@cordisjs/plugin-include`. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/index.js new file mode 100644 index 0000000..6f4c713 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/index.js @@ -0,0 +1,744 @@ +import { createRequire } from "node:module"; +import { Context, Inject, Service, composeError } from "@deepseek-ai/cordis"; +import { deepEqual, defineProperty, isNonNullable, isNullable, valueMap } from "@deepseek-ai/cosmokit"; +//#region lib/types/internal.js +/** Helpers for locating the current Node internal module loader. */ +var ModuleLoader; +(function(ModuleLoader) { + let _cachedLoader; + function requireInternal(id) { + const require = createRequire(import.meta.url); + if (process.execArgv.includes("--expose-internals")) try { + return require(id); + } catch {} + try { + return require("node-addon-require-builtin").requireBuiltin(id); + } catch {} + } + function fromInternal() { + if (_cachedLoader) return _cachedLoader; + const [major] = process.versions.node.split(".").map(Number); + if (major >= 24) { + const raw = requireInternal("internal/modules/esm/loader")?.getOrInitializeCascadedLoader(); + if (raw) return _cachedLoader = Object.assign(raw, { version: "v2" }); + } else if (major >= 22) { + const raw = requireInternal("internal/modules/esm/loader")?.getOrInitializeCascadedLoader(); + if (raw) return _cachedLoader = Object.assign(raw, { version: "v1" }); + } + } + ModuleLoader.fromInternal = fromInternal; +})(ModuleLoader || (ModuleLoader = {})); +//#endregion +//#region lib/types/config/group.js +/** Runtime owner for a list of child loader entries. */ +var EntryGroup = class { + ctx; + tree; + static key = Symbol.for("cordis.group"); + data = []; + constructor(ctx, tree) { + this.ctx = ctx; + this.tree = tree; + const entry = ctx.fiber.entry; + if (entry) entry.subgroup = this; + } + get context() { + return this.ctx; + } + async create(options) { + const id = this.tree.ensureId(options); + const existing = this.tree.store[id]; + const entry = existing ?? (this.tree.store[id] = new Entry(this.ctx.loader)); + const previousParent = entry.parent; + entry.parent = this; + try { + await entry.update(options, true, true); + } catch (error) { + if (existing) entry.parent = previousParent; + else delete this.tree.store[id]; + throw error; + } + return entry.id; + } + unlink(options) { + const config = this.data; + const index = config.indexOf(options); + if (index >= 0) config.splice(index, 1); + } + async remove(id, isDispose = false) { + const entry = this.tree.store[id]; + if (!entry) return; + await entry._dispose(); + if (!isDispose) this.unlink(entry.options); + delete this.tree.store[id]; + this.context.emit("loader/partial-dispose", entry, entry.options, false); + } + async update(config) { + const oldConfig = this.data; + const seen = /* @__PURE__ */ new Set(); + for (const options of config) { + const id = this.tree.ensureId(options); + if (seen.has(id)) throw new TypeError(`duplicate loader entry id: ${id}`); + seen.add(id); + } + const oldMap = Object.fromEntries(oldConfig.map((options) => [options.id, options])); + const newMap = Object.fromEntries(config.map((options) => [options.id, options])); + try { + const outcomes = await Promise.allSettled(config.map((options) => this.create(options))); + if (this.ctx.fiber.uid === null) return; + const failures = outcomes.filter((outcome) => outcome.status === "rejected").map((outcome) => outcome.reason); + if (failures.length === 1) throw failures[0]; + if (failures.length > 1) throw new AggregateError(failures, "loader entries failed to apply"); + for (const id of Object.keys(oldMap)) if (!newMap[id]) await this.remove(id, true); + this.data = config; + } catch (error) { + const rollbackErrors = []; + for (const id of Object.keys(newMap).reverse()) { + if (oldMap[id]) continue; + try { + await this.remove(id, true); + } catch (rollbackError) { + rollbackErrors.push(rollbackError); + } + } + for (const options of oldConfig) try { + await this.create(options); + } catch (rollbackError) { + rollbackErrors.push(rollbackError); + } + this.data = oldConfig; + if (rollbackErrors.length) throw new AggregateError([error, ...rollbackErrors], "loader entry rollback failed"); + throw error; + } + } + async stop() { + for (const options of this.data) await this.remove(options.id, true); + } +}; +/** Plugin that mounts a nested loader entry group. */ +var Group = class extends EntryGroup { + ctx; + config; + static initial = []; + static [EntryGroup.key] = true; + constructor(ctx, config) { + super(ctx, ctx.fiber.entry.parent.tree); + this.ctx = ctx; + this.config = config; + ctx.on("internal/update", (config) => this.update(config)); + } + async *[Service.init]() { + yield () => this.stop(); + await this.update(this.config); + } +}; +//#endregion +//#region lib/types/config/tree.js +var __rewriteRelativeImportExtension = function(path, preserveJsx) { + if (typeof path === "string" && /^\.\.?\//.test(path)) return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) { + return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js"; + }); + return path; +}; +/** Mutable tree of loader entries. Persistence is supplied by subclasses. */ +var EntryTree = class EntryTree { + static sep = ":"; + ctx; + enableLogs; + root; + store = Object.create(null); + constructor(ctx) { + this.ctx = ctx.extend({ baseUrl: ctx.baseUrl }); + this.root = new EntryGroup(this.ctx, this); + const entry = this.ctx.fiber.entry; + if (entry) entry.subtree = this; + } + get context() { + return this.ctx; + } + /** Iterate entries in this tree and any nested subtrees. */ + *entries() { + for (const entry of Object.values(this.store)) { + yield entry; + if (!entry.subtree) continue; + yield* entry.subtree.entries(); + } + } + /** Return pending import and lifecycle tasks owned by this tree. */ + getTasks() { + return [...this.entries()].map((entry) => entry._initTask || entry.fiber?.inertia).filter(isNonNullable); + } + /** + * Wait until this tree has no active import or lifecycle tasks. + * @throws a settled fiber failure, or an aggregate when several fibers failed. + */ + async await() { + while (true) { + const tasks = this.getTasks(); + if (tasks.length) { + await Promise.allSettled(tasks); + continue; + } + const failures = (await Promise.allSettled([...this.entries()].map((entry) => entry._await()))).filter((outcome) => outcome.status === "rejected").map((outcome) => outcome.reason); + if (failures.length === 1) throw failures[0]; + if (failures.length > 1) throw new AggregateError(failures, "loader fibers failed"); + this.ctx.reflect.notify(["loader"]); + if (!this.getTasks().length) return; + } + } + ensureId(options) { + if (!options.id) do + options.id = Math.random().toString(16).slice(2, 10); + while (this.store[options.id]); + return options.id; + } + /** Resolve an entry by id, including nested ids separated by `EntryTree.sep`. */ + resolve(id) { + const parts = id.split(EntryTree.sep); + let tree = this; + const final = parts.pop(); + for (const part of parts) { + tree = tree.store[part]?.subtree; + if (!tree) throw new Error(`cannot resolve entry ${id}`); + } + const entry = tree.store[final]; + if (!entry) throw new Error(`cannot resolve entry ${id}`); + return entry; + } + resolveGroup(id) { + if (!id) return this.root; + const entry = this.resolve(id); + if (!entry.subgroup) throw new Error(`entry ${id} is not a group`); + return entry.subgroup; + } + /** Create an entry in the root group or a nested group. */ + async create(options, parent = null, position = Infinity) { + const group = this.resolveGroup(parent); + const id = await group.create(options); + const entry = this.resolve(id); + group.data.splice(position, 0, entry.options); + group.tree.write(); + return id; + } + /** Stop and remove an entry from its parent group. */ + async remove(id) { + const entry = this.resolve(id); + await entry.parent.remove(id); + entry.parent.tree.write(); + } + /** Update an entry and optionally move it to another group. */ + async update(id, options, parent, position) { + const entry = this.resolve(id); + const source = entry.parent; + const sourceIndex = source.data.indexOf(entry.options); + let target = source; + if (parent !== void 0) { + target = this.resolveGroup(parent); + source.unlink(entry.options); + target.data.splice(position ?? Infinity, 0, entry.options); + entry.parent = target; + } + try { + await entry.update(options, false, true); + } catch (error) { + if (parent !== void 0) { + target.unlink(entry.options); + source.data.splice(sourceIndex < 0 ? source.data.length : sourceIndex, 0, entry.options); + entry.parent = source; + try { + await entry.update({}, false, true); + } catch (rollbackError) { + throw new AggregateError([error, rollbackError], `failed to roll back loader entry move ${id}`); + } + } + throw error; + } + source.tree.write(); + if (target !== source) target.tree.write(); + } + /** Import a plugin module from a specifier or `cordis:` builtin. */ + import(name, getOuterStack) { + if (name.startsWith("cordis:")) return this.ctx.loader.builtins[name.slice(7)]; + return composeError(async (info) => { + info.offset += 3; + if (this.ctx.loader.internal) return await this.ctx.loader.internal.import(name, this.ctx.baseUrl, {}); + else if (name.startsWith(".")) return await import(__rewriteRelativeImportExtension( + /* @vite-ignore */ + new URL(name, this.ctx.baseUrl).href + )); + else return await import(__rewriteRelativeImportExtension( + /* @vite-ignore */ + name + )); + }, getOuterStack); + } +}; +//#endregion +//#region lib/types/config/utils.js +/** Evaluate a JavaScript expression against a loader context scope. */ +const evaluate = new Function("ctx", "expr", ` + with (ctx) { + return eval(expr) + } +`); +/** Recursively replace YAML `!js` expression nodes with evaluated values. */ +function interpolate(ctx, value) { + if (isJsExpr(value)) return evaluate(ctx, value.__jsExpr); + else if (!value || typeof value !== "object") return value; + else if (Array.isArray(value)) return value.map((item) => interpolate(ctx, item)); + else return valueMap(value, (item) => interpolate(ctx, item)); +} +/** Return true when a value is a serialized loader JavaScript expression. */ +function isJsExpr(value) { + return value instanceof Object && "__jsExpr" in value; +} +//#endregion +//#region lib/types/config/entry.js +function updateError(stage, options, cause) { + const detail = cause instanceof Error ? cause.message : String(cause); + return new Error(`failed to ${stage} loader entry ${options.id} (${options.name}): ${detail}`, { cause }); +} +function takeEntries(object, keys) { + const result = []; + for (const key of keys) { + if (!(key in object)) continue; + result.push([key, object[key]]); + delete object[key]; + } + return result; +} +function sortKeys(object, prepend = ["id", "name"], append = ["config"]) { + const part1 = takeEntries(object, prepend); + const part2 = takeEntries(object, append); + const rest = takeEntries(object, Object.keys(object)).sort(([a], [b]) => a.localeCompare(b)); + return Object.assign(object, Object.fromEntries([ + ...part1, + ...rest, + ...part2 + ])); +} +function replaceKeys(target, source) { + for (const key of Object.keys(target)) Reflect.deleteProperty(target, key); + return Object.assign(target, source); +} +/** One configured plugin node inside an `EntryTree`. */ +var Entry = class Entry { + loader; + static key = Symbol.for("cordis.entry"); + ctx; + fiber; + parent; + options = {}; + subgroup; + subtree; + _initTask; + _disposing = 0; + constructor(loader) { + this.loader = loader; + this.ctx = loader.ctx.extend({ [Entry.key]: this }); + this.context.emit("loader/entry-init", this); + } + get context() { + return this.ctx; + } + get id() { + let id = this.options.id; + if (this.parent.tree.ctx.fiber.entry) id = this.parent.tree.ctx.fiber.entry.id + EntryTree.sep + id; + return id; + } + /** True when this entry or any owning parent entry is disabled. */ + get disabled() { + return this._disabled(this.options); + } + _disabled(options) { + if (options.group) return false; + if (this.disabledOf(options)) return true; + let entry = this.parent.ctx.fiber.entry; + while (entry) { + if (this.disabledOf(entry.options)) return true; + entry = entry.parent.ctx.fiber.entry; + } + return false; + } + /** + * Effective disabled state: a `!!js` expression evaluates against the loader + * context. The raw node stays in the options, so write-back keeps the form. + */ + disabledOf(options) { + return isJsExpr(options.disabled) ? Boolean(this.evaluate(options.disabled.__jsExpr)) : Boolean(options.disabled); + } + evaluate(expr) { + return evaluate(this.ctx, expr); + } + async _patchContext(diff) { + await this.context.waterfall("loader/patch-context", this, async () => { + Object.setPrototypeOf(this.ctx, this.parent.ctx); + if (this.fiber?.uid && (diff.includes("config") || this.options.group)) await this.fiber.update(this.options.config, true); + }); + } + async refresh() { + if (this.fiber) return; + if (this.disabled) return; + await this.init(); + } + async _dispose(fiber = this.fiber) { + if (!fiber) return; + if (this.fiber === fiber) this.fiber = void 0; + this._disposing += 1; + try { + await fiber.dispose(); + } finally { + this._disposing -= 1; + } + } + /** Merge new options, restart as needed, and persist through the parent tree. */ + async update(options, create = false, force = false) { + const previousOptions = this.options; + const legacy = { ...previousOptions }; + const candidate = create ? options : { ...previousOptions }; + if (!create) for (const [key, value] of Object.entries(options)) if (isNullable(value)) delete candidate[key]; + else candidate[key] = value; + sortKeys(candidate); + const diff = Object.keys({ + ...candidate, + ...legacy + }).filter((key) => !deepEqual(candidate[key], legacy[key])); + if (!diff.length && !force) return; + const commit = () => { + if (create) return; + this.options = replaceKeys(previousOptions, candidate); + }; + const previous = this.fiber; + if (!previous?.uid) { + this.fiber = void 0; + this.options = candidate; + try { + if (!this._disabled(candidate)) await this.init(); + } catch (error) { + this.options = previousOptions; + throw error; + } + commit(); + return; + } + if (this._disabled(candidate)) { + this.options = candidate; + try { + await this._dispose(previous); + } catch (error) { + this.options = previousOptions; + throw updateError("dispose", candidate, error); + } + commit(); + this.context.emit("loader/partial-dispose", this, legacy, true); + return; + } + if (!diff.some((key) => key === "name" || key === "inject" || key === "group")) { + this.options = candidate; + try { + await this._patchContext(diff); + } catch (error) { + this.options = previousOptions; + try { + await this._patchContext(diff); + } catch (rollbackError) { + throw updateError("rollback", legacy, new AggregateError([error, rollbackError])); + } + this.context.emit("loader/partial-dispose", this, candidate, true); + throw updateError("apply", candidate, error); + } + commit(); + this.context.emit("loader/partial-dispose", this, legacy, true); + return; + } + let plugin; + try { + plugin = diff.includes("name") ? this.loader.unwrapExports(await this.parent.tree.import(candidate.name, this.getOuterStack)) : previous.runtime.callback; + } catch (error) { + throw updateError("import", candidate, error); + } + const previousPlugin = previous.runtime.callback; + this.options = candidate; + try { + await this._dispose(previous); + } catch (error) { + this.options = previousOptions; + throw updateError("dispose", candidate, error); + } + try { + await this._start(plugin); + } catch (error) { + this.options = previousOptions; + try { + await this._start(previousPlugin); + } catch (rollbackError) { + throw updateError("rollback", legacy, new AggregateError([error, rollbackError])); + } + this.context.emit("loader/partial-dispose", this, candidate, true); + throw updateError("apply", candidate, error); + } + commit(); + this.context.emit("loader/partial-dispose", this, legacy, true); + } + getOuterStack = () => { + let entry = this; + const result = []; + do { + result.push(` at ${entry.parent.tree.ctx.baseUrl}#${entry.options.id}`); + entry = entry.parent.ctx.fiber.entry; + } while (entry); + return result; + }; + /** Import and start the configured plugin if it is not already running. */ + async init() { + try { + await (this._initTask ??= this._init()); + } finally { + this._initTask = void 0; + if (!this.loader.getTasks().length) this.ctx.reflect.notify(["loader"]); + } + await this._await(); + } + async _await() { + try { + await this.fiber?.await(); + } catch (error) { + throw updateError("apply", this.options, error); + } + } + async _init() { + let plugin; + try { + plugin = this.loader.unwrapExports(await this.parent.tree.import(this.options.name, this.getOuterStack)); + } catch (error) { + throw updateError("import", this.options, error); + } + try { + await this._start(plugin); + } catch (error) { + throw updateError("apply", this.options, error); + } + } + async _start(plugin) { + let fiber; + try { + await this._patchContext([]); + this.loader.showLog(this, "apply"); + fiber = this.fiber = this.ctx.registry.plugin(plugin, this.options.config, this.getOuterStack); + await fiber.await(); + } catch (error) { + await this._dispose(fiber); + throw error; + } + } +}; +//#endregion +//#region lib/types/config/isolate.js +function swap(target, source) { + for (const key of Reflect.ownKeys(target)) Reflect.deleteProperty(target, key); + for (const key of Reflect.ownKeys(source || {})) Reflect.defineProperty(target, key, Reflect.getOwnPropertyDescriptor(source, key)); +} +/** Symbol realm used to isolate service implementations by entry or label. */ +var Realm = class { + store = Object.create(null); + access(key, create = false) { + if (create) return this.store[key] ??= Symbol(`${key}${this.suffix}`); + else return this.store[key] ?? Symbol(`${key}${this.suffix}`); + } + delete(key) { + delete this.store[key]; + } + get size() { + return Object.keys(this.store).length; + } +}; +/** Entry-local isolation realm. */ +var LocalRealm = class extends Realm { + entry; + constructor(entry) { + super(); + this.entry = entry; + } + get suffix() { + return "#" + this.entry.options.id; + } +}; +/** Named isolation realm shared by entries that use the same label. */ +var GlobalRealm = class extends Realm { + label; + constructor(label) { + super(); + this.label = label; + } + get suffix() { + return "@" + this.label; + } +}; +/** Install loader hooks that apply `intercept` and `isolate` entry options. */ +function isolate(ctx) { + const realms = Object.create(null); + const delims = Object.create(null); + function access(entry, name, create = false) { + let realm; + const label = entry.options.isolate?.[name]; + if (!label) return; + if (label === true) realm = entry.realm ??= new LocalRealm(entry); + else if (create) realm = realms[label] ??= new GlobalRealm(label); + else realm = realms[label]; + return realm?.access(name, create); + } + ctx.on("loader/entry-init", (entry) => { + entry.ctx[Context.intercept] = Object.create(entry.ctx[Context.intercept]); + entry.ctx[Context.isolate] = Object.create(entry.ctx[Context.isolate]); + }); + ctx.on("loader/patch-context", async (entry, next) => { + const newMap = Object.create(entry.parent.ctx[Context.isolate]); + for (const name of Object.keys(entry.options.isolate ?? {})) newMap[name] = access(entry, name, true); + const diff = Object.create(null); + const oldMap = entry.ctx[Context.isolate]; + for (const name in { + ...newMap, + ...delims + }) { + if (newMap[name] === oldMap[name]) continue; + const delim = delims[name] ??= Symbol(`delim:${name}`); + entry.ctx[delim] = Symbol(`${name}#${entry.id}`); + for (const symbol of [oldMap[name], newMap[name]]) { + const impl = symbol && entry.ctx.reflect.store[symbol]; + if (!impl) continue; + if (!impl.fiber) { + entry.ctx.logger.warn(/* @__PURE__ */ new Error(`expected service ${name} to be implemented`)); + continue; + } + diff[name] = [ + oldMap[name], + newMap[name], + entry.ctx[delim], + impl.fiber.ctx[delim] + ]; + if (entry.ctx[delim] !== impl.fiber.ctx[delim]) break; + } + } + Object.setPrototypeOf(entry.ctx[Context.isolate], entry.parent.ctx[Context.isolate]); + Object.setPrototypeOf(entry.ctx[Context.intercept], entry.parent.ctx[Context.intercept]); + swap(entry.ctx[Context.isolate], newMap); + swap(entry.ctx[Context.intercept], entry.options.intercept); + await next(); + for (const [symbol1, symbol2, flag1, flag2] of Object.values(diff)) if (flag1 === flag2 && entry.ctx.reflect.store[symbol1] && !entry.ctx.reflect.store[symbol2]) { + entry.ctx.reflect.store[symbol2] = entry.ctx.reflect.store[symbol1]; + delete entry.ctx.reflect.store[symbol1]; + } + ctx.reflect.notify(Object.keys(diff), (ctx, name) => { + const [symbol1, symbol2, flag1, flag2] = diff[name]; + const symbol3 = ctx[Context.isolate][name]; + const flag3 = ctx[delims[name]]; + return (symbol1 === symbol3 || symbol2 === symbol3) && flag1 === flag3 !== (flag1 === flag2); + }); + for (const name in delims) if (!Reflect.ownKeys(newMap).includes(name)) delete entry.ctx[delims[name]]; + }); + ctx.on("loader/partial-dispose", (entry, legacy, active) => { + for (const [name, label] of Object.entries(legacy.isolate ?? {})) { + if (label === true) continue; + if (active && entry.options.isolate?.[name] === label) continue; + const realm = realms[label]; + if (!realm) continue; + for (const entry of ctx.loader.entries()) if (entry.options.isolate?.[name] === realm.label) return; + realm.delete(name); + if (!realm.size) delete realms[realm.label]; + } + }); +} +//#endregion +//#region lib/types/index.js +/** +* Service that owns a loader entry tree and imports configured plugins. +* +* Subclasses provide persistence by implementing `write()` on `EntryTree`. +*/ +var Loader = class extends EntryTree { + config; + envData = process.env.CORDIS_SHARED ? JSON.parse(process.env.CORDIS_SHARED) : { startTime: Date.now() }; + name = "loader"; + internal = ModuleLoader.fromInternal(); + builtins = Object.create(null); + constructor(ctx, config = {}) { + super(ctx); + this.config = config; + if (config.baseUrl) this.ctx.baseUrl = config.baseUrl; + const self = this; + defineProperty(this, Service.tracker, { + associate: "loader", + property: "ctx", + noShadow: true + }); + ctx.reflect.provide("loader", this, this[Service.check]); + ctx.on("internal/config", function(_config, next) { + const config = next(); + if (!this.entry || this.parent.fiber?.entry === this.entry) return config; + if ((this.runtime?.callback)?.[EntryGroup.key]) return config; + return interpolate(this.ctx, config); + }, { global: true }); + ctx.on("internal/update", async function(config, noSave, next) { + if (!this.entry || noSave || this.parent.fiber?.entry === this.entry) return next(); + await next(); + const unparse = this.runtime?.Config?.["simplify"]; + this.entry.options.config = unparse ? unparse(config) : config; + this.entry.parent.tree.write(); + }, { + global: true, + prepend: true + }); + ctx.on("internal/update", function(config, _, next) { + if (!this.entry || this.parent.fiber?.entry === this.entry) return next(); + self.showLog(this.entry, "reload"); + return next(); + }, { global: true }); + ctx.on("internal/plugin", (fiber) => { + if (fiber.parent[Entry.key] && !fiber.entry) { + fiber.entry = fiber.parent[Entry.key]; + Inject.resolve(fiber.entry.options.inject, fiber.inject); + } + if (fiber.uid) return; + if (!fiber.entry) return; + if (fiber.parent.fiber?.entry === fiber.entry) return; + if (!ctx.registry.has(fiber.runtime.callback)) return; + const treeOwner = fiber.entry.parent.tree.ctx.fiber; + if (!treeOwner.uid || treeOwner.state === 5) return; + if (fiber.entry._disposing) return; + this.showLog(fiber.entry, "unload"); + if (fiber.entry.disabled) return; + fiber.entry.options.disabled = true; + fiber.entry.parent.tree.write(); + }); + ctx.plugin(isolate); + } + write() {} + [Service.check]() { + if (Service.prototype[Service.resolveConfig].call(this).await && this.getTasks().length) return false; + return true; + } + showLog(entry, type) { + if (entry.options.group || !entry.parent.tree.enableLogs) return; + this.ctx.root.logger?.("loader").info("%s plugin %C", type, entry.options.name); + } + /** Return the loader entry id that owns `fiber`, if any. */ + locate(fiber = this.ctx.fiber) { + while (1) { + if (fiber.entry) return fiber.entry.id; + const next = fiber.parent.fiber; + if (fiber === next) return; + fiber = next; + } + } + /** Hook for hosts that can restart the process on full-reload requests. */ + exit() {} + /** Normalize ESM/CJS/default export shapes before applying a plugin. */ + unwrapExports(exports) { + if (isNullable(exports)) return exports; + exports = exports.default ?? exports; + if (!exports.__esModule) return exports; + return exports.default ?? exports; + } +}; +//#endregion +export { Entry, EntryGroup, EntryTree, GlobalRealm, Group, Loader, Loader as default, LocalRealm, ModuleLoader, Realm, evaluate, interpolate, isJsExpr }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/entry.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/entry.d.ts new file mode 100644 index 0000000..c93e2ad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/entry.d.ts @@ -0,0 +1,56 @@ +import { Context, Fiber, Inject } from '@deepseek-ai/cordis'; +import { Loader } from '../index.ts'; +import { EntryGroup } from './group.ts'; +import { EntryTree } from './tree.ts'; +/** Serialized plugin entry options stored in loader config files. */ +export interface EntryOptions { + /** Stable id inside the containing entry tree. */ + id: string; + /** Module specifier imported by the entry tree. */ + name: string; + /** Config passed to the plugin. */ + config?: any; + /** Marks this entry as a nested group. */ + group?: boolean | null; + /** Prevents this entry and descendants from running. */ + disabled?: boolean | null; + /** Required services or service intercept config for this entry. */ + inject?: Inject | null; +} +/** One configured plugin node inside an `EntryTree`. */ +export declare class Entry { + loader: Loader; + static readonly key: unique symbol; + ctx: Context; + fiber?: Fiber; + parent: EntryGroup; + options: EntryOptions; + subgroup?: EntryGroup; + subtree?: EntryTree; + _initTask?: Promise; + _disposing: number; + constructor(loader: Loader); + get context(): Context; + get id(): string; + /** True when this entry or any owning parent entry is disabled. */ + get disabled(): boolean; + private _disabled; + /** + * Effective disabled state: a `!!js` expression evaluates against the loader + * context. The raw node stays in the options, so write-back keeps the form. + */ + private disabledOf; + evaluate(expr: string): any; + private _patchContext; + refresh(): Promise; + _dispose(fiber?: Fiber | undefined): Promise; + /** Merge new options, restart as needed, and persist through the parent tree. */ + update(options: Partial, create?: boolean, force?: boolean): Promise; + getOuterStack: () => string[]; + /** Import and start the configured plugin if it is not already running. */ + init(): Promise; + _await(): Promise; + private _init; + private _start; +} +//# sourceMappingURL=entry.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/entry.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/entry.d.ts.map new file mode 100644 index 0000000..4e62ea1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/entry.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../../src/config/entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAGrC,qEAAqE;AACrE,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAA;IACV,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAA;IACZ,mCAAmC;IACnC,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IACtB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IACzB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AA6BD,wDAAwD;AACxD,qBAAa,KAAK;IAcG,MAAM,EAAE,MAAM;IAbjC,MAAM,CAAC,QAAQ,CAAC,GAAG,gBAA6B;IAEzC,GAAG,EAAE,OAAO,CAAA;IACZ,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,MAAM,EAAG,UAAU,CAAA;IAEnB,OAAO,EAAS,YAAY,CAAA;IAC5B,QAAQ,CAAC,EAAE,UAAU,CAAA;IACrB,OAAO,CAAC,EAAE,SAAS,CAAA;IAE1B,SAAS,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,UAAU,SAAI;gBAEK,MAAM,EAAE,MAAM;IAKjC,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,EAAE,WAML;IAED,mEAAmE;IACnE,IAAI,QAAQ,YAEX;IAED,OAAO,CAAC,SAAS;IAYjB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAMlB,QAAQ,CAAC,IAAI,EAAE,MAAM;YAIP,aAAa;IAUrB,OAAO;IAMP,QAAQ,CAAC,KAAK,oBAAa;IAWjC,iFAAiF;IAC3E,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,MAAM,UAAQ,EAAE,KAAK,UAAQ;IA0G1E,aAAa,iBAQZ;IAED,2EAA2E;IACrE,IAAI;IAUJ,MAAM;YAQE,KAAK;YAcL,MAAM;CAYrB"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/group.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/group.d.ts new file mode 100644 index 0000000..879d4c9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/group.d.ts @@ -0,0 +1,27 @@ +import { Context, Service } from '@deepseek-ai/cordis'; +import { type EntryOptions } from './entry.ts'; +import { EntryTree } from './tree.ts'; +/** Runtime owner for a list of child loader entries. */ +export declare class EntryGroup { + ctx: Context; + tree: EntryTree; + static readonly key: unique symbol; + data: EntryOptions[]; + constructor(ctx: Context, tree: EntryTree); + get context(): Context; + create(options: Omit): Promise; + unlink(options: EntryOptions): void; + remove(id: string, isDispose?: boolean): Promise; + update(config: EntryOptions[]): Promise; + stop(): Promise; +} +/** Plugin that mounts a nested loader entry group. */ +export declare class Group extends EntryGroup { + ctx: Context; + config: EntryOptions[]; + static initial: Omit[]; + static readonly [EntryGroup.key] = true; + constructor(ctx: Context, config: EntryOptions[]); + [Service.init](): AsyncGenerator<() => Promise, void, unknown>; +} +//# sourceMappingURL=group.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/group.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/group.d.ts.map new file mode 100644 index 0000000..6a37033 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/group.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../../../src/config/group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,wDAAwD;AACxD,qBAAa,UAAU;IAKF,GAAG,EAAE,OAAO;IAAS,IAAI,EAAE,SAAS;IAJvD,MAAM,CAAC,QAAQ,CAAC,GAAG,gBAA6B;IAEzC,IAAI,EAAE,YAAY,EAAE,CAAK;gBAEb,GAAG,EAAE,OAAO,EAAS,IAAI,EAAE,SAAS;IAKvD,IAAI,OAAO,IAAI,OAAO,CAErB;IAEK,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC;IAsB9C,MAAM,CAAC,OAAO,EAAE,YAAY;IAMtB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,UAAQ;IAWpC,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE;IAiD7B,IAAI;CAKX;AAED,sDAAsD;AACtD,qBAAa,KAAM,SAAQ,UAAU;IAIhB,GAAG,EAAE,OAAO;IAAS,MAAM,EAAE,YAAY,EAAE;IAH9D,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAK;IAC/C,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,QAAO;gBAEpB,GAAG,EAAE,OAAO,EAAS,MAAM,EAAE,YAAY,EAAE;IAKvD,CAAC,OAAO,CAAC,IAAI,CAAC;CAItB"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/isolate.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/isolate.d.ts new file mode 100644 index 0000000..480b377 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/isolate.d.ts @@ -0,0 +1,35 @@ +import { Context } from '@deepseek-ai/cordis'; +import type { Dict } from '@deepseek-ai/cosmokit'; +import { Entry } from './entry.ts'; +declare module './entry.ts' { + interface EntryOptions { + intercept?: Dict | null; + isolate?: Dict | null; + } + interface Entry { + realm: LocalRealm; + } +} +/** Symbol realm used to isolate service implementations by entry or label. */ +export declare abstract class Realm { + protected store: Dict; + abstract get suffix(): string; + access(key: string, create?: boolean): symbol; + delete(key: string): void; + get size(): number; +} +/** Entry-local isolation realm. */ +export declare class LocalRealm extends Realm { + private entry; + constructor(entry: Entry); + get suffix(): string; +} +/** Named isolation realm shared by entries that use the same label. */ +export declare class GlobalRealm extends Realm { + label: string; + constructor(label: string); + get suffix(): string; +} +/** Install loader hooks that apply `intercept` and `isolate` entry options. */ +export default function isolate(ctx: Context): void; +//# sourceMappingURL=isolate.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/isolate.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/isolate.d.ts.map new file mode 100644 index 0000000..6564b5d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/isolate.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"isolate.d.ts","sourceRoot":"","sources":["../../../src/config/isolate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC,OAAO,QAAQ,YAAY,CAAC;IAC1B,UAAU,YAAY;QACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;QACvB,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,IAAI,CAAA;KACrC;IAED,UAAU,KAAK;QACb,KAAK,EAAE,UAAU,CAAA;KAClB;CACF;AAWD,8EAA8E;AAC9E,8BAAsB,KAAK;IACzB,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAsB;IAEnD,QAAQ,KAAK,MAAM,IAAI,MAAM,CAAA;IAE7B,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,UAAQ;IAQlC,MAAM,CAAC,GAAG,EAAE,MAAM;IAIlB,IAAI,IAAI,WAEP;CACF;AAED,mCAAmC;AACnC,qBAAa,UAAW,SAAQ,KAAK;IACvB,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,KAAK;IAIhC,IAAI,MAAM,WAET;CACF;AAED,uEAAuE;AACvE,qBAAa,WAAY,SAAQ,KAAK;IACjB,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM;IAIhC,IAAI,MAAM,WAET;CACF;AAED,+EAA+E;AAC/E,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,GAAG,EAAE,OAAO,QAsG3C"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/tree.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/tree.d.ts new file mode 100644 index 0000000..d12569a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/tree.d.ts @@ -0,0 +1,38 @@ +import { Context } from '@deepseek-ai/cordis'; +import { type Dict } from '@deepseek-ai/cosmokit'; +import { Entry, type EntryOptions } from './entry.ts'; +import { EntryGroup } from './group.ts'; +/** Mutable tree of loader entries. Persistence is supplied by subclasses. */ +export declare abstract class EntryTree { + static readonly sep = ":"; + ctx: Context; + enableLogs?: boolean; + root: EntryGroup; + store: Dict; + constructor(ctx: Context); + get context(): Context; + /** Iterate entries in this tree and any nested subtrees. */ + entries(): Generator; + /** Return pending import and lifecycle tasks owned by this tree. */ + getTasks(): Promise[]; + /** + * Wait until this tree has no active import or lifecycle tasks. + * @throws a settled fiber failure, or an aggregate when several fibers failed. + */ + await(): Promise; + ensureId(options: Partial): string; + /** Resolve an entry by id, including nested ids separated by `EntryTree.sep`. */ + resolve(id: string): Entry; + resolveGroup(id: string | null): EntryGroup; + /** Create an entry in the root group or a nested group. */ + create(options: Omit, parent?: string | null, position?: number): Promise; + /** Stop and remove an entry from its parent group. */ + remove(id: string): Promise; + /** Update an entry and optionally move it to another group. */ + update(id: string, options: Omit, parent?: string | null, position?: number): Promise; + /** Import a plugin module from a specifier or `cordis:` builtin. */ + import(name: string, getOuterStack?: () => string[]): any; + /** Persist current tree state. In-memory trees may implement this as a no-op. */ + abstract write(): void; +} +//# sourceMappingURL=tree.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/tree.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/tree.d.ts.map new file mode 100644 index 0000000..19b16b2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/tree.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../src/config/tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAiB,KAAK,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEvC,6EAA6E;AAC7E,8BAAsB,SAAS;IAC7B,MAAM,CAAC,QAAQ,CAAC,GAAG,OAAM;IAElB,GAAG,EAAE,OAAO,CAAA;IACZ,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAsB;gBAEnC,GAAG,EAAE,OAAO;IAOxB,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,4DAA4D;IAC1D,OAAO,IAAI,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC;IAQzC,oEAAoE;IACpE,QAAQ;IAMR;;;OAGG;IACG,KAAK;IAoBX,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC;IASvC,iFAAiF;IACjF,OAAO,CAAC,EAAE,EAAE,MAAM;IAalB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAO9B,2DAA2D;IACrD,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,MAAM,GAAE,MAAM,GAAG,IAAW,EAAE,QAAQ,SAAW;IASjG,sDAAsD;IAChD,MAAM,CAAC,EAAE,EAAE,MAAM;IAMvB,+DAA+D;IACzD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM;IA8B9G,oEAAoE;IACpE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,MAAM,EAAE;IAmBnD,iFAAiF;IACjF,QAAQ,CAAC,KAAK,IAAI,IAAI;CACvB"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/utils.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/utils.d.ts new file mode 100644 index 0000000..6e4b6a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/utils.d.ts @@ -0,0 +1,11 @@ +/** Evaluate a JavaScript expression against a loader context scope. */ +export declare const evaluate: ((ctx: object, expr: string) => any); +/** Recursively replace YAML `!js` expression nodes with evaluated values. */ +export declare function interpolate(ctx: object, value: any): any; +/** Return true when a value is a serialized loader JavaScript expression. */ +export declare function isJsExpr(value: any): value is JsExpr; +/** Serialized JavaScript expression produced by the include YAML tag. */ +export interface JsExpr { + __jsExpr: string; +} +//# sourceMappingURL=utils.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/utils.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/utils.d.ts.map new file mode 100644 index 0000000..a80de9e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/config/utils.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/config/utils.ts"],"names":[],"mappings":"AAGA,uEAAuE;AACvE,eAAO,MAAM,QAAQ,EAIf,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,GAAG,CAAC,CAAA;AAE1C,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,OAUlD;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,MAAM,CAEpD;AAED,yEAAyE;AACzE,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,MAAM,CAAA;CACjB"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/index.d.ts new file mode 100644 index 0000000..4c1e93f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/index.d.ts @@ -0,0 +1,73 @@ +import { Context, Service, type Fiber } from '@deepseek-ai/cordis'; +import { type Dict } from '@deepseek-ai/cosmokit'; +import { ModuleLoader } from './internal.ts'; +import { Entry, type EntryOptions } from './config/entry.ts'; +import { EntryTree } from './config/tree.ts'; +/** Re-export entry node APIs. */ +export * from './config/entry.ts'; +/** Re-export nested entry group APIs. */ +export * from './config/group.ts'; +/** Re-export service isolation helpers. */ +export * from './config/isolate.ts'; +/** Re-export entry tree persistence APIs. */ +export * from './config/tree.ts'; +/** Re-export loader config expression helpers. */ +export * from './config/utils.ts'; +/** Re-export Node internal module loader compatibility types. */ +export * from './internal.ts'; +declare module '@deepseek-ai/cordis' { + interface Events { + 'exit'(signal: NodeJS.Signals): Promise; + 'loader/config-update'(): void; + 'loader/entry-init'(entry: Entry): void; + 'loader/partial-dispose'(entry: Entry, legacy: Partial, active: boolean): void; + 'loader/patch-context'(entry: Entry, next: () => void | Promise): void | Promise; + } + interface Context { + loader: Loader; + } + interface EnvData { + startTime?: number; + } + interface Fiber { + entry?: Entry; + } +} +/** Loader config and dependency intercept namespace. */ +export declare namespace Loader { + /** Root loader configuration. */ + interface Config { + /** Base URL used to resolve relative plugin specifiers and config paths. */ + baseUrl?: string; + } + /** Intercept config used when other plugins depend on `loader`. */ + interface Intercept { + /** Keep dependent plugins pending while loader entries are still loading. */ + await?: boolean; + } +} +/** + * Service that owns a loader entry tree and imports configured plugins. + * + * Subclasses provide persistence by implementing `write()` on `EntryTree`. + */ +export declare class Loader extends EntryTree { + config: Loader.Config; + [Service.config]: Loader.Intercept; + envData: any; + name: string; + internal: ModuleLoader | undefined; + builtins: Dict; + constructor(ctx: Context, config?: Loader.Config); + write(): void; + [Service.check](): boolean; + showLog(entry: Entry, type: string): void; + /** Return the loader entry id that owns `fiber`, if any. */ + locate(fiber?: Fiber): string | undefined; + /** Hook for hosts that can restart the process on full-reload requests. */ + exit(): void; + /** Normalize ESM/CJS/default export shapes before applying a plugin. */ + unwrapExports(exports: any): any; +} +export default Loader; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/index.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/index.d.ts.map new file mode 100644 index 0000000..da62267 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAsB,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,qBAAqB,CAAA;AACtF,OAAO,EAA8B,KAAK,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAG5D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAG5C,iCAAiC;AACjC,cAAc,mBAAmB,CAAA;AACjC,yCAAyC;AACzC,cAAc,mBAAmB,CAAA;AACjC,2CAA2C;AAC3C,cAAc,qBAAqB,CAAA;AACnC,6CAA6C;AAC7C,cAAc,kBAAkB,CAAA;AAChC,kDAAkD;AAClD,cAAc,mBAAmB,CAAA;AACjC,iEAAiE;AACjE,cAAc,eAAe,CAAA;AAE7B,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QAC7C,sBAAsB,IAAI,IAAI,CAAA;QAC9B,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;QACvC,wBAAwB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAA;QAC5F,sBAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAC7F;IAED,UAAU,OAAO;QACf,MAAM,EAAE,MAAM,CAAA;KACf;IAED,UAAU,OAAO;QACf,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB;IAED,UAAU,KAAK;QACb,KAAK,CAAC,EAAE,KAAK,CAAA;KACd;CACF;AAED,wDAAwD;AACxD,yBAAiB,MAAM,CAAC;IACtB,iCAAiC;IACjC,UAAiB,MAAM;QACrB,4EAA4E;QAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;KACjB;IAED,mEAAmE;IACnE,UAAiB,SAAS;QACxB,6EAA6E;QAC7E,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB;CACF;AAED;;;;GAIG;AACH,qBAAa,MAAO,SAAQ,SAAS;IAYF,MAAM,EAAE,MAAM,CAAC,MAAM;IAX9C,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,SAAS,CAAA;IAEnC,OAAO,MAEe;IAEtB,IAAI,SAAW;IACf,QAAQ,2BAA8B;IAEtC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAsB;gBAEpC,GAAG,EAAE,OAAO,EAAS,MAAM,GAAE,MAAM,CAAC,MAAW;IAqF3D,KAAK;IAIL,CAAC,OAAO,CAAC,KAAK,CAAC;IAMf,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM;IAKlC,4DAA4D;IAC5D,MAAM,CAAC,KAAK,QAAiB;IAS7B,2EAA2E;IAC3E,IAAI;IAGJ,wEAAwE;IACxE,aAAa,CAAC,OAAO,EAAE,GAAG;CAQ3B;AAED,eAAe,MAAM,CAAA"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/internal.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/internal.d.ts new file mode 100644 index 0000000..40ce133 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/internal.d.ts @@ -0,0 +1,97 @@ +import { type LoadHookContext } from 'node:module'; +import type { Dict } from '@deepseek-ai/cosmokit'; +/** Node internal module format names handled by loader hooks. */ +export type ModuleFormat = 'builtin' | 'commonjs' | 'json' | 'module' | 'wasm'; +/** Source payload accepted by Node internal module load hooks. */ +export type ModuleSource = string | ArrayBuffer; +/** Result returned by a Node internal resolve hook. */ +export interface ResolveResult { + format: ModuleFormat; + url: string; +} +/** Result returned by a Node internal load hook. */ +export interface LoadResult { + format: ModuleFormat; + source?: ModuleSource; +} +type LoadCacheData = ModuleJob; +/** @see https://github.com/nodejs/node/blob/main/lib/internal/modules/esm/module_map.js */ +interface LoadCache extends Omit>, 'get' | 'set' | 'has'> { + get(url: string, type?: string): LoadCacheData | undefined; + set(url: string, type?: string, job?: LoadCacheData): this; + has(url: string, type?: string): boolean; +} +/** Minimal Node internal ModuleWrap surface used by HMR helpers. */ +export interface ModuleWrap { + url: string; + getNamespace(): any; +} +/** @see https://github.com/nodejs/node/blob/main/lib/internal/modules/esm/module_job.js */ +export interface ModuleJob { + url: string; + loader: ModuleLoader; + module?: ModuleWrap; + importAttributes: ImportAttributes; + linked: Promise; + instantiate(): Promise; + run(): Promise<{ + module: ModuleWrap; + }>; +} +/** + * Node 22/23 ModuleLoader interface. + * + * Key methods: + * - getModuleJobForImport(specifier, parentURL, importAttributes) + * - resolve(specifier, parentURL, importAttributes) → Promise + * - resolveSync(specifier, parentURL, importAttributes) → ResolveResult + */ +export interface ModuleLoaderV1 { + version: 'v1'; + loadCache: LoadCache; + import(specifier: string, parentURL: string, importAttributes: ImportAttributes): Promise; + register(specifier: string | URL, parentURL?: string | URL, data?: any, transferList?: any[]): void; + getModuleJobForImport(specifier: string, parentURL: string, importAttributes: ImportAttributes): Promise; + resolve(specifier: string, parentURL: string, importAttributes: ImportAttributes): Promise; + resolveSync(specifier: string, parentURL: string, importAttributes: ImportAttributes): ResolveResult; + load(specifier: string, context: Pick): Promise; +} +/** Node 24+ module request object. */ +export interface ModuleRequest { + specifier: string; + attributes?: ImportAttributes; + phase?: ModulePhase; +} +/** @see https://github.com/nodejs/node/blob/main/src/module_wrap.h */ +export declare const enum ModulePhase { + Source = 1, + Evaluation = 2 +} +/** Opaque Node internal module request type marker. */ +export type ModuleRequestType = unknown; +/** + * Node 24+ ModuleLoader interface. + * + * Breaking changes from v1: + * - getModuleJobForImport removed → getOrCreateModuleJob(parentURL, request, requestType) + * - resolve removed (became private #resolve) → resolveSync(parentURL, request) + * - Parameter order reversed for resolveSync, request object { specifier, attributes } + * - LoadCache became typed Map with delete only setting undefined + */ +export interface ModuleLoaderV2 { + version: 'v2'; + loadCache: LoadCache; + import(specifier: string, parentURL: string, importAttributes: ImportAttributes, phase?: ModulePhase, isEntryPoint?: boolean): Promise; + register(specifier: string | URL, parentURL?: string | URL, data?: any, transferList?: any[], isInternal?: boolean): void; + getOrCreateModuleJob(parentURL: string, request: ModuleRequest, requestType?: ModuleRequestType): Promise; + resolveSync(parentURL: string, request: ModuleRequest): ResolveResult; + load(url: string, context: Pick): Promise; +} +/** Supported Node internal ESM loader shapes. */ +export type ModuleLoader = ModuleLoaderV1 | ModuleLoaderV2; +/** Helpers for locating the current Node internal module loader. */ +export declare namespace ModuleLoader { + function fromInternal(): ModuleLoader | undefined; +} +export {}; +//# sourceMappingURL=internal.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/internal.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/internal.d.ts.map new file mode 100644 index 0000000..d14a4b1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/lib/types/internal.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AACjE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAEjD,iEAAiE;AACjE,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAC9E,kEAAkE;AAClE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,CAAA;AAE/C,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAA;IACpB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,YAAY,CAAA;IACpB,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB;AAED,KAAK,aAAa,GAAG,SAAS,CAAA;AAE9B,2FAA2F;AAC3F,UAAU,SAAU,SAAQ,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IACvF,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAA;IAC1D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,aAAa,GAAG,IAAI,CAAA;IAC1D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACzC;AAED,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,IAAI,GAAG,CAAA;CACpB;AAED,2FAA2F;AAC3F,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,YAAY,CAAA;IACpB,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAA;IAC5B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5B,GAAG,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC,CAAA;CACvC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,IAAI,CAAA;IACb,SAAS,EAAE,SAAS,CAAA;IACpB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IAC9F,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;IACnG,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IACnH,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;IACzG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,GAAG,aAAa,CAAA;IACpG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,kBAAkB,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;CAC5G;AAED,sCAAsC;AACtC,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,gBAAgB,CAAA;IAC7B,KAAK,CAAC,EAAE,WAAW,CAAA;CACpB;AAED,sEAAsE;AACtE,0BAAkB,WAAW;IAC3B,MAAM,IAAI;IACV,UAAU,IAAI;CACf;AAED,uDAAuD;AACvD,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAA;AAEvC;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,IAAI,CAAA;IACb,SAAS,EAAE,SAAS,CAAA;IACpB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,CAAC,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IAC3I,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,EAAE,GAAG,EAAE,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IACzH,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IACpH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,aAAa,CAAA;IACrE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,kBAAkB,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;CACtG;AAED,iDAAiD;AACjD,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,cAAc,CAAA;AAE1D,oEAAoE;AACpE,yBAAiB,YAAY,CAAC;IAe5B,SAAgB,YAAY,IAAI,YAAY,GAAG,SAAS,CAWvD;CACF"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/package.json new file mode 100644 index 0000000..154167c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/package.json @@ -0,0 +1,44 @@ +{ + "name": "@deepseek-ai/cordis-plugin-loader", + "description": "Plugin loader for cordis", + "version": "1.0.2", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "vendor/loader" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/types/**/*.d.ts", + "lib/types/**/*.d.ts.map", + "src" + ], + "author": "Shigma ", + "license": "MIT", + "peerDependencies": { + "node-addon-require-builtin": "^0.1.4", + "@deepseek-ai/cordis": "^4.0.1" + }, + "peerDependenciesMeta": { + "node-addon-require-builtin": { + "optional": true + } + }, + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/entry.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/entry.ts new file mode 100644 index 0000000..19dc11a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/entry.ts @@ -0,0 +1,303 @@ +import { Context, Fiber, Inject } from '@deepseek-ai/cordis' +import { deepEqual, isNullable } from '@deepseek-ai/cosmokit' +import { Loader } from '../index.ts' +import { EntryGroup } from './group.ts' +import { EntryTree } from './tree.ts' +import { evaluate, isJsExpr } from './utils.ts' + +/** Serialized plugin entry options stored in loader config files. */ +export interface EntryOptions { + /** Stable id inside the containing entry tree. */ + id: string + /** Module specifier imported by the entry tree. */ + name: string + /** Config passed to the plugin. */ + config?: any + /** Marks this entry as a nested group. */ + group?: boolean | null + /** Prevents this entry and descendants from running. */ + disabled?: boolean | null + /** Required services or service intercept config for this entry. */ + inject?: Inject | null +} + +function updateError(stage: 'import' | 'dispose' | 'apply' | 'rollback', options: EntryOptions, cause: unknown) { + const detail = cause instanceof Error ? cause.message : String(cause) + return new Error(`failed to ${stage} loader entry ${options.id} (${options.name}): ${detail}`, { cause }) +} + +function takeEntries(object: {}, keys: string[]) { + const result: [string, any][] = [] + for (const key of keys) { + if (!(key in object)) continue + result.push([key, object[key]]) + delete object[key] + } + return result +} + +function sortKeys(object: T, prepend = ['id', 'name'], append = ['config']): T { + const part1 = takeEntries(object, prepend) + const part2 = takeEntries(object, append) + const rest = takeEntries(object, Object.keys(object)).sort(([a], [b]) => a.localeCompare(b)) + return Object.assign(object, Object.fromEntries([...part1, ...rest, ...part2])) +} + +function replaceKeys(target: T, source: T): T { + for (const key of Object.keys(target)) Reflect.deleteProperty(target, key) + return Object.assign(target, source) +} + +/** One configured plugin node inside an `EntryTree`. */ +export class Entry { + static readonly key = Symbol.for('cordis.entry') + + public ctx: Context + public fiber?: Fiber + public parent!: EntryGroup + // safety: call `entry.update()` immediately after creating an entry + public options = {} as EntryOptions + public subgroup?: EntryGroup + public subtree?: EntryTree + + _initTask?: Promise + _disposing = 0 + + constructor(public loader: Loader) { + this.ctx = loader.ctx.extend({ [Entry.key]: this }) + this.context.emit('loader/entry-init', this) + } + + get context(): Context { + return this.ctx + } + + get id() { + let id = this.options.id + if (this.parent.tree.ctx.fiber.entry) { + id = this.parent.tree.ctx.fiber.entry.id + EntryTree.sep + id + } + return id + } + + /** True when this entry or any owning parent entry is disabled. */ + get disabled() { + return this._disabled(this.options) + } + + private _disabled(options: EntryOptions) { + // group is always enabled + if (options.group) return false + if (this.disabledOf(options)) return true + let entry = this.parent.ctx.fiber.entry + while (entry) { + if (this.disabledOf(entry.options)) return true + entry = entry.parent.ctx.fiber.entry + } + return false + } + + /** + * Effective disabled state: a `!!js` expression evaluates against the loader + * context. The raw node stays in the options, so write-back keeps the form. + */ + private disabledOf(options: EntryOptions): boolean { + return isJsExpr(options.disabled) + ? Boolean(this.evaluate(options.disabled.__jsExpr)) + : Boolean(options.disabled) + } + + evaluate(expr: string) { + return evaluate(this.ctx, expr) + } + + private async _patchContext(diff: string[]) { + await this.context.waterfall('loader/patch-context', this, async () => { + Object.setPrototypeOf(this.ctx, this.parent.ctx) + + if (this.fiber?.uid && (diff.includes('config') || this.options.group)) { + await this.fiber.update(this.options.config, true) + } + }) + } + + async refresh() { + if (this.fiber) return + if (this.disabled) return + await this.init() + } + + async _dispose(fiber = this.fiber) { + if (!fiber) return + if (this.fiber === fiber) this.fiber = undefined + this._disposing += 1 + try { + await fiber.dispose() + } finally { + this._disposing -= 1 + } + } + + /** Merge new options, restart as needed, and persist through the parent tree. */ + async update(options: Partial, create = false, force = false) { + const previousOptions = this.options + const legacy = { ...previousOptions } + const candidate = create ? options as EntryOptions : { ...previousOptions } + if (!create) { + for (const [key, value] of Object.entries(options)) { + if (isNullable(value)) { + delete candidate[key as keyof EntryOptions] + } else { + candidate[key as keyof EntryOptions] = value as never + } + } + } + sortKeys(candidate) + + const diff = Object + .keys({ ...candidate, ...legacy }) + .filter(key => !deepEqual(candidate[key as keyof EntryOptions], legacy[key as keyof EntryOptions])) + if (!diff.length && !force) return + + const commit = () => { + if (create) return + this.options = replaceKeys(previousOptions, candidate) + } + + const previous = this.fiber + if (!previous?.uid) { + this.fiber = undefined + this.options = candidate + try { + if (!this._disabled(candidate)) await this.init() + } catch (error) { + this.options = previousOptions + throw error + } + commit() + return + } + + if (this._disabled(candidate)) { + this.options = candidate + try { + await this._dispose(previous) + } catch (error) { + this.options = previousOptions + throw updateError('dispose', candidate, error) + } + commit() + this.context.emit('loader/partial-dispose', this, legacy, true) + return + } + + const replace = diff.some(key => key === 'name' || key === 'inject' || key === 'group') + if (!replace) { + this.options = candidate + try { + await this._patchContext(diff) + } catch (error) { + this.options = previousOptions + try { + await this._patchContext(diff) + } catch (rollbackError) { + throw updateError('rollback', legacy, new AggregateError([error, rollbackError])) + } + this.context.emit('loader/partial-dispose', this, candidate, true) + throw updateError('apply', candidate, error) + } + commit() + this.context.emit('loader/partial-dispose', this, legacy, true) + return + } + + let plugin: any + try { + plugin = diff.includes('name') + ? this.loader.unwrapExports(await this.parent.tree.import(candidate.name, this.getOuterStack)) + : previous.runtime!.callback + } catch (error) { + throw updateError('import', candidate, error) + } + + const previousPlugin = previous.runtime!.callback + this.options = candidate + try { + await this._dispose(previous) + } catch (error) { + this.options = previousOptions + throw updateError('dispose', candidate, error) + } + + try { + await this._start(plugin) + } catch (error) { + this.options = previousOptions + try { + await this._start(previousPlugin) + } catch (rollbackError) { + throw updateError('rollback', legacy, new AggregateError([error, rollbackError])) + } + this.context.emit('loader/partial-dispose', this, candidate, true) + throw updateError('apply', candidate, error) + } + commit() + this.context.emit('loader/partial-dispose', this, legacy, true) + } + + getOuterStack = () => { + let entry: Entry | undefined = this + const result: string[] = [] + do { + result.push(` at ${entry.parent.tree.ctx.baseUrl}#${entry.options.id}`) + entry = entry.parent.ctx.fiber.entry + } while (entry) + return result + } + + /** Import and start the configured plugin if it is not already running. */ + async init() { + try { + await (this._initTask ??= this._init()) + } finally { + this._initTask = undefined + if (!this.loader.getTasks().length) this.ctx.reflect.notify(['loader']) + } + await this._await() + } + + async _await() { + try { + await this.fiber?.await() + } catch (error) { + throw updateError('apply', this.options, error) + } + } + + private async _init() { + let plugin: any + try { + plugin = this.loader.unwrapExports(await this.parent.tree.import(this.options.name, this.getOuterStack)) + } catch (error) { + throw updateError('import', this.options, error) + } + try { + await this._start(plugin) + } catch (error) { + throw updateError('apply', this.options, error) + } + } + + private async _start(plugin: any) { + let fiber: Fiber | undefined + try { + await this._patchContext([]) + this.loader.showLog(this, 'apply') + fiber = this.fiber = this.ctx.registry.plugin(plugin, this.options.config, this.getOuterStack) + await fiber.await() + } catch (error) { + await this._dispose(fiber) + throw error + } + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/group.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/group.ts new file mode 100644 index 0000000..2e322b1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/group.ts @@ -0,0 +1,129 @@ +import { Context, Service } from '@deepseek-ai/cordis' +import { Entry, type EntryOptions } from './entry.ts' +import { EntryTree } from './tree.ts' + +/** Runtime owner for a list of child loader entries. */ +export class EntryGroup { + static readonly key = Symbol.for('cordis.group') + + public data: EntryOptions[] = [] + + constructor(public ctx: Context, public tree: EntryTree) { + const entry = ctx.fiber.entry + if (entry) entry.subgroup = this + } + + get context(): Context { + return this.ctx + } + + async create(options: Omit) { + const id = this.tree.ensureId(options) + const existing = this.tree.store[id] + const entry: Entry = existing ?? (this.tree.store[id] = new Entry(this.ctx.loader)) + const previousParent = entry.parent + // Entry may be moved from another group, + // so we need to update the parent reference. + entry.parent = this + // Use `create: true` to replace existing entry.options. + try { + await entry.update(options, true, true) + } catch (error) { + if (existing) { + entry.parent = previousParent + } else { + delete this.tree.store[id] + } + throw error + } + return entry.id + } + + unlink(options: EntryOptions) { + const config = this.data + const index = config.indexOf(options) + if (index >= 0) config.splice(index, 1) + } + + async remove(id: string, isDispose = false) { + const entry = this.tree.store[id] + if (!entry) return + await entry._dispose() + if (!isDispose) { + this.unlink(entry.options) + } + delete this.tree.store[id] + this.context.emit('loader/partial-dispose', entry, entry.options, false) + } + + async update(config: EntryOptions[]) { + const oldConfig = this.data as EntryOptions[] + const seen = new Set() + for (const options of config) { + const id = this.tree.ensureId(options) + if (seen.has(id)) throw new TypeError(`duplicate loader entry id: ${id}`) + seen.add(id) + } + const oldMap = Object.fromEntries(oldConfig.map(options => [options.id, options])) + const newMap = Object.fromEntries(config.map(options => [options.id, options])) + + try { + const outcomes = await Promise.allSettled(config.map(options => this.create(options))) + // Disposal owns termination: sibling starts can still be settling after + // the containing tree has gone away, but their failures no longer + // describe a live update to roll back. + if (this.ctx.fiber.uid === null) return + const failures = outcomes + .filter((outcome): outcome is PromiseRejectedResult => outcome.status === 'rejected') + .map(outcome => outcome.reason) + if (failures.length === 1) throw failures[0] + if (failures.length > 1) throw new AggregateError(failures, 'loader entries failed to apply') + for (const id of Object.keys(oldMap)) { + if (!newMap[id]) await this.remove(id, true) + } + this.data = config + } catch (error) { + const rollbackErrors: unknown[] = [] + for (const id of Object.keys(newMap).reverse()) { + if (oldMap[id]) continue + try { + await this.remove(id, true) + } catch (rollbackError) { + rollbackErrors.push(rollbackError) + } + } + for (const options of oldConfig) { + try { + await this.create(options) + } catch (rollbackError) { + rollbackErrors.push(rollbackError) + } + } + this.data = oldConfig + if (rollbackErrors.length) throw new AggregateError([error, ...rollbackErrors], 'loader entry rollback failed') + throw error + } + } + + async stop() { + for (const options of this.data) { + await this.remove(options.id, true) + } + } +} + +/** Plugin that mounts a nested loader entry group. */ +export class Group extends EntryGroup { + static initial: Omit[] = [] + static readonly [EntryGroup.key] = true + + constructor(public ctx: Context, public config: EntryOptions[]) { + super(ctx, ctx.fiber.entry!.parent.tree) + ctx.on('internal/update', config => this.update(config)) + } + + async* [Service.init]() { + yield () => this.stop() + await this.update(this.config) + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/isolate.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/isolate.ts new file mode 100644 index 0000000..0dd2a06 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/isolate.ts @@ -0,0 +1,173 @@ +import { Context } from '@deepseek-ai/cordis' +import type { Dict } from '@deepseek-ai/cosmokit' +import { Entry } from './entry.ts' + +declare module './entry.ts' { + interface EntryOptions { + intercept?: Dict | null + isolate?: Dict | null + } + + interface Entry { + realm: LocalRealm + } +} + +function swap(target: T, source?: T | null) { + for (const key of Reflect.ownKeys(target)) { + Reflect.deleteProperty(target, key) + } + for (const key of Reflect.ownKeys(source || {})) { + Reflect.defineProperty(target, key, Reflect.getOwnPropertyDescriptor(source!, key)!) + } +} + +/** Symbol realm used to isolate service implementations by entry or label. */ +export abstract class Realm { + protected store: Dict = Object.create(null) + + abstract get suffix(): string + + access(key: string, create = false) { + if (create) { + return this.store[key] ??= Symbol(`${key}${this.suffix}`) + } else { + return this.store[key] ?? Symbol(`${key}${this.suffix}`) + } + } + + delete(key: string) { + delete this.store[key] + } + + get size() { + return Object.keys(this.store).length + } +} + +/** Entry-local isolation realm. */ +export class LocalRealm extends Realm { + constructor(private entry: Entry) { + super() + } + + get suffix() { + return '#' + this.entry.options.id + } +} + +/** Named isolation realm shared by entries that use the same label. */ +export class GlobalRealm extends Realm { + constructor(public label: string) { + super() + } + + get suffix() { + return '@' + this.label + } +} + +/** Install loader hooks that apply `intercept` and `isolate` entry options. */ +export default function isolate(ctx: Context) { + const realms: Dict = Object.create(null) + const delims: Dict = Object.create(null) + + function access(entry: Entry, name: string, create: true): symbol + function access(entry: Entry, name: string, create?: boolean): symbol | undefined + function access(entry: Entry, name: string, create = false) { + let realm: Realm | undefined + const label = entry.options.isolate?.[name] + if (!label) return + if (label === true) { + realm = entry.realm ??= new LocalRealm(entry) + } else if (create) { + realm = realms[label] ??= new GlobalRealm(label) + } else { + realm = realms[label] + } + return realm?.access(name, create) + } + + ctx.on('loader/entry-init', (entry) => { + entry.ctx[Context.intercept] = Object.create(entry.ctx[Context.intercept]) + entry.ctx[Context.isolate] = Object.create(entry.ctx[Context.isolate]) + }) + + ctx.on('loader/patch-context', async (entry, next) => { + // step 1: generate new isolate map + const newMap: Dict = Object.create(entry.parent.ctx[Context.isolate]) + for (const name of Object.keys(entry.options.isolate ?? {})) { + newMap[name] = access(entry, name, true) + } + + // step 2: generate service diff + const diff: Dict<[symbol, symbol, symbol, symbol]> = Object.create(null) + const oldMap = entry.ctx[Context.isolate] + for (const name in { ...newMap, ...delims }) { + if (newMap[name] === oldMap[name]) continue + const delim = delims[name] ??= Symbol(`delim:${name}`) + entry.ctx[delim] = Symbol(`${name}#${entry.id}`) + for (const symbol of [oldMap[name], newMap[name]]) { + const impl = symbol && entry.ctx.reflect.store[symbol] + if (!impl) continue + if (!impl.fiber) { + entry.ctx.logger.warn(new Error(`expected service ${name} to be implemented`)) + continue + } + diff[name] = [oldMap[name], newMap[name], entry.ctx[delim], impl.fiber.ctx[delim]] + if (entry.ctx[delim] !== impl.fiber.ctx[delim]) break + } + } + + // step 3: set prototype for transferred context + Object.setPrototypeOf(entry.ctx[Context.isolate], entry.parent.ctx[Context.isolate]) + Object.setPrototypeOf(entry.ctx[Context.intercept], entry.parent.ctx[Context.intercept]) + swap(entry.ctx[Context.isolate], newMap) + swap(entry.ctx[Context.intercept], entry.options.intercept) + + // step 4: reload fiber + await next() + + // step 5: replace service impl + for (const [symbol1, symbol2, flag1, flag2] of Object.values(diff)) { + if (flag1 === flag2 && entry.ctx.reflect.store[symbol1] && !entry.ctx.reflect.store[symbol2]) { + entry.ctx.reflect.store[symbol2] = entry.ctx.reflect.store[symbol1] + delete entry.ctx.reflect.store[symbol1] + } + } + + // step 6: reflect notify + ctx.reflect.notify(Object.keys(diff), (ctx, name) => { + const [symbol1, symbol2, flag1, flag2] = diff[name] + const symbol3 = ctx[Context.isolate][name] + const flag3 = ctx[delims[name]] + return (symbol1 === symbol3 || symbol2 === symbol3) && (flag1 === flag3) !== (flag1 === flag2) + }) + + // step 7: clean up delimiters + for (const name in delims) { + if (!Reflect.ownKeys(newMap).includes(name)) { + delete entry.ctx[delims[name]] + } + } + }) + + ctx.on('loader/partial-dispose', (entry, legacy, active) => { + for (const [name, label] of Object.entries(legacy.isolate ?? {})) { + if (label === true) continue + if (active && entry.options.isolate?.[name] === label) continue + const realm = realms[label] + if (!realm) continue + + // realm garbage collection + for (const entry of ctx.loader.entries()) { + // has reference to this realm + if (entry.options.isolate?.[name] === realm.label) return + } + realm.delete(name) + if (!realm.size) { + delete realms[realm.label] + } + } + }) +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/tree.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/tree.ts new file mode 100644 index 0000000..c1925f0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/tree.ts @@ -0,0 +1,166 @@ +import { composeError, Context } from '@deepseek-ai/cordis' +import { isNonNullable, type Dict } from '@deepseek-ai/cosmokit' +import { Entry, type EntryOptions } from './entry.ts' +import { EntryGroup } from './group.ts' + +/** Mutable tree of loader entries. Persistence is supplied by subclasses. */ +export abstract class EntryTree { + static readonly sep = ':' + + public ctx: Context + public enableLogs?: boolean + public root: EntryGroup + public store: Dict = Object.create(null) + + constructor(ctx: Context) { + this.ctx = ctx.extend({ baseUrl: ctx.baseUrl }) + this.root = new EntryGroup(this.ctx, this) + const entry = this.ctx.fiber.entry + if (entry) entry.subtree = this + } + + get context(): Context { + return this.ctx + } + + /** Iterate entries in this tree and any nested subtrees. */ + * entries(): Generator { + for (const entry of Object.values(this.store)) { + yield entry + if (!entry.subtree) continue + yield* entry.subtree.entries() + } + } + + /** Return pending import and lifecycle tasks owned by this tree. */ + getTasks() { + return [...this.entries()] + .map(entry => entry._initTask || entry.fiber?.inertia) + .filter(isNonNullable) + } + + /** + * Wait until this tree has no active import or lifecycle tasks. + * @throws a settled fiber failure, or an aggregate when several fibers failed. + */ + async await() { + while (true) { + const tasks = this.getTasks() + if (tasks.length) { + await Promise.allSettled(tasks) + continue + } + const outcomes = await Promise.allSettled( + [...this.entries()].map(entry => entry._await()), + ) + const failures = outcomes + .filter((outcome): outcome is PromiseRejectedResult => outcome.status === 'rejected') + .map(outcome => outcome.reason) + if (failures.length === 1) throw failures[0] + if (failures.length > 1) throw new AggregateError(failures, 'loader fibers failed') + this.ctx.reflect.notify(['loader']) + if (!this.getTasks().length) return + } + } + + ensureId(options: Partial) { + if (!options.id) { + do { + options.id = Math.random().toString(16).slice(2, 10) + } while (this.store[options.id]) + } + return options.id! + } + + /** Resolve an entry by id, including nested ids separated by `EntryTree.sep`. */ + resolve(id: string) { + const parts = id.split(EntryTree.sep) + let tree: EntryTree | undefined = this + const final = parts.pop()! + for (const part of parts) { + tree = tree.store[part]?.subtree + if (!tree) throw new Error(`cannot resolve entry ${id}`) + } + const entry = tree.store[final] + if (!entry) throw new Error(`cannot resolve entry ${id}`) + return entry + } + + resolveGroup(id: string | null) { + if (!id) return this.root + const entry = this.resolve(id) + if (!entry.subgroup) throw new Error(`entry ${id} is not a group`) + return entry.subgroup + } + + /** Create an entry in the root group or a nested group. */ + async create(options: Omit, parent: string | null = null, position = Infinity) { + const group = this.resolveGroup(parent) + const id = await group.create(options) + const entry = this.resolve(id) + group.data.splice(position, 0, entry.options) + group.tree.write() + return id + } + + /** Stop and remove an entry from its parent group. */ + async remove(id: string) { + const entry = this.resolve(id) + await entry.parent.remove(id) + entry.parent.tree.write() + } + + /** Update an entry and optionally move it to another group. */ + async update(id: string, options: Omit, parent?: string | null, position?: number) { + const entry = this.resolve(id) + const source = entry.parent + const sourceIndex = source.data.indexOf(entry.options) + let target = source + if (parent !== undefined) { + target = this.resolveGroup(parent) + source.unlink(entry.options) + target.data.splice(position ?? Infinity, 0, entry.options) + entry.parent = target + } + try { + await entry.update(options, false, true) + } catch (error) { + if (parent !== undefined) { + target.unlink(entry.options) + source.data.splice(sourceIndex < 0 ? source.data.length : sourceIndex, 0, entry.options) + entry.parent = source + try { + await entry.update({}, false, true) + } catch (rollbackError) { + throw new AggregateError([error, rollbackError], `failed to roll back loader entry move ${id}`) + } + } + throw error + } + source.tree.write() + if (target !== source) target.tree.write() + } + + /** Import a plugin module from a specifier or `cordis:` builtin. */ + import(name: string, getOuterStack?: () => string[]) { + if (name.startsWith('cordis:')) { + return this.ctx.loader.builtins[name.slice(7)] + } + return composeError(async (info) => { + // ModuleJob.run + // onImport.tracePromise.__proto__ + // internal.import + info.offset += 3 + if (this.ctx.loader.internal) { + return await this.ctx.loader.internal.import(name, this.ctx.baseUrl!, {}) + } else if (name.startsWith('.')) { + return await import(/* @vite-ignore */new URL(name, this.ctx.baseUrl).href) + } else { + return await import(/* @vite-ignore */name) + } + }, getOuterStack) + } + + /** Persist current tree state. In-memory trees may implement this as a no-op. */ + abstract write(): void +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/utils.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/utils.ts new file mode 100644 index 0000000..cd706c0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/utils.ts @@ -0,0 +1,32 @@ +import { valueMap } from '@deepseek-ai/cosmokit' + +// eslint-disable-next-line no-new-func +/** Evaluate a JavaScript expression against a loader context scope. */ +export const evaluate = new Function('ctx', 'expr', ` + with (ctx) { + return eval(expr) + } +`) as ((ctx: object, expr: string) => any) + +/** Recursively replace YAML `!js` expression nodes with evaluated values. */ +export function interpolate(ctx: object, value: any) { + if (isJsExpr(value)) { + return evaluate(ctx, value.__jsExpr) + } else if (!value || typeof value !== 'object') { + return value + } else if (Array.isArray(value)) { + return value.map(item => interpolate(ctx, item)) + } else { + return valueMap(value, item => interpolate(ctx, item)) + } +} + +/** Return true when a value is a serialized loader JavaScript expression. */ +export function isJsExpr(value: any): value is JsExpr { + return value instanceof Object && '__jsExpr' in value +} + +/** Serialized JavaScript expression produced by the include YAML tag. */ +export interface JsExpr { + __jsExpr: string +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/index.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/index.ts new file mode 100644 index 0000000..781353b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/index.ts @@ -0,0 +1,202 @@ +import { Context, FiberState, Inject, Service, type Fiber } from '@deepseek-ai/cordis' +import { defineProperty, isNullable, type Dict } from '@deepseek-ai/cosmokit' +import { ModuleLoader } from './internal.ts' +import { Entry, type EntryOptions } from './config/entry.ts' +import { EntryGroup } from './config/group.ts' +import isolate from './config/isolate.ts' +import { EntryTree } from './config/tree.ts' +import { interpolate } from './config/utils.ts' + +/** Re-export entry node APIs. */ +export * from './config/entry.ts' +/** Re-export nested entry group APIs. */ +export * from './config/group.ts' +/** Re-export service isolation helpers. */ +export * from './config/isolate.ts' +/** Re-export entry tree persistence APIs. */ +export * from './config/tree.ts' +/** Re-export loader config expression helpers. */ +export * from './config/utils.ts' +/** Re-export Node internal module loader compatibility types. */ +export * from './internal.ts' + +declare module '@deepseek-ai/cordis' { + interface Events { + 'exit'(signal: NodeJS.Signals): Promise + 'loader/config-update'(): void + 'loader/entry-init'(entry: Entry): void + 'loader/partial-dispose'(entry: Entry, legacy: Partial, active: boolean): void + 'loader/patch-context'(entry: Entry, next: () => void | Promise): void | Promise + } + + interface Context { + loader: Loader + } + + interface EnvData { + startTime?: number + } + + interface Fiber { + entry?: Entry + } +} + +/** Loader config and dependency intercept namespace. */ +export namespace Loader { + /** Root loader configuration. */ + export interface Config { + /** Base URL used to resolve relative plugin specifiers and config paths. */ + baseUrl?: string + } + + /** Intercept config used when other plugins depend on `loader`. */ + export interface Intercept { + /** Keep dependent plugins pending while loader entries are still loading. */ + await?: boolean + } +} + +/** + * Service that owns a loader entry tree and imports configured plugins. + * + * Subclasses provide persistence by implementing `write()` on `EntryTree`. + */ +export class Loader extends EntryTree { + declare [Service.config]: Loader.Intercept + + public envData = process.env.CORDIS_SHARED + ? JSON.parse(process.env.CORDIS_SHARED) + : { startTime: Date.now() } + + public name = 'loader' + public internal = ModuleLoader.fromInternal() + + public builtins: Dict = Object.create(null) + + constructor(ctx: Context, public config: Loader.Config = {}) { + super(ctx) + if (config.baseUrl) { + this.ctx.baseUrl = config.baseUrl + } + const self = this + + defineProperty(this, Service.tracker, { + associate: 'loader', + property: 'ctx', + noShadow: true, + }) + + ctx.reflect.provide('loader', this, this[Service.check]) + + ctx.on('internal/config', function (this: Fiber, _config, next) { + const config = next() + if (!this.entry || this.parent.fiber?.entry === this.entry) return config + // Tree carriers (Group, Include) keep their configs literal: their + // entry and patch lists hold other rows' configs, whose `!!js` + // expressions belong to those rows' own fibers. + const plugin = this.runtime?.callback as Record | undefined + if (plugin?.[EntryGroup.key]) return config + return interpolate(this.ctx, config) + }, { global: true }) + + ctx.on('internal/update', async function (config, noSave, next) { + if (!this.entry || noSave || this.parent.fiber?.entry === this.entry) return next() + await next() + const unparse = this.runtime?.Config?.['simplify'] + this.entry.options.config = unparse ? unparse(config) : config + this.entry.parent.tree.write() + }, { global: true, prepend: true }) + + ctx.on('internal/update', function (config, _, next) { + if (!this.entry || this.parent.fiber?.entry === this.entry) return next() + self.showLog(this.entry, 'reload') + return next() + }, { global: true }) + + ctx.on('internal/plugin', (fiber) => { + // 1. set `fiber.entry` + if (fiber.parent[Entry.key] && !fiber.entry) { + fiber.entry = fiber.parent[Entry.key] + // FIXME merge config + Inject.resolve(fiber.entry!.options.inject, fiber.inject) + } + + // 2. handle self-dispose + // We only care about `ctx.fiber.dispose()`, so we need to filter out other cases. + + // case 1: fiber is created + if (fiber.uid) return + + // case 2: fiber is not tracked by loader + if (!fiber.entry) return + + // case 3: fiber is a child plugin under the entry (not the entry's root fiber) + if (fiber.parent.fiber?.entry === fiber.entry) return + + // case 4: fiber is disposed on behalf of plugin deletion (such as plugin hmr) + // self-dispose: ctx.fiber.dispose() -> fiber / runtime dispose -> delete(plugin) + // plugin hmr: delete(plugin) -> runtime dispose -> fiber dispose + if (!ctx.registry.has(fiber.runtime!.callback)) return + + // case 5: the entry's tree is being disposed + const treeOwner = fiber.entry.parent.tree.ctx.fiber + if (!treeOwner.uid || treeOwner.state === FiberState.UNLOADING) return + + // case 6: Loader is replacing or removing this exact fiber + if (fiber.entry._disposing) return + + this.showLog(fiber.entry, 'unload') + + // case 7: fiber is disposed by loader behavior + // such as inject checker, config file update, ancestor group disable + if (fiber.entry.disabled) return + + fiber.entry.options.disabled = true + fiber.entry.parent.tree.write() + }) + + ctx.plugin(isolate) + } + + write() { + // Loader's root tree is in-memory; writes are no-ops. + } + + [Service.check]() { + const config: Loader.Intercept = Service.prototype[Service.resolveConfig].call(this) + if (config.await && this.getTasks().length) return false + return true + } + + showLog(entry: Entry, type: string) { + if (entry.options.group || !entry.parent.tree.enableLogs) return + this.ctx.root.logger?.('loader').info('%s plugin %C', type, entry.options.name) + } + + /** Return the loader entry id that owns `fiber`, if any. */ + locate(fiber = this.ctx.fiber) { + while (1) { + if (fiber.entry) return fiber.entry.id + const next = fiber.parent.fiber + if (fiber === next) return + fiber = next + } + } + + /** Hook for hosts that can restart the process on full-reload requests. */ + exit() { + } + + /** Normalize ESM/CJS/default export shapes before applying a plugin. */ + unwrapExports(exports: any) { + if (isNullable(exports)) return exports + exports = exports.default ?? exports + // https://github.com/evanw/esbuild/issues/2623 + // https://esbuild.github.io/content-types/#default-interop + if (!exports.__esModule) return exports + return exports.default ?? exports + } +} + +export default Loader diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/internal.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/internal.ts new file mode 100644 index 0000000..ccf08de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader/src/internal.ts @@ -0,0 +1,132 @@ +import { createRequire, type LoadHookContext } from 'node:module' +import type { Dict } from '@deepseek-ai/cosmokit' + +/** Node internal module format names handled by loader hooks. */ +export type ModuleFormat = 'builtin' | 'commonjs' | 'json' | 'module' | 'wasm' +/** Source payload accepted by Node internal module load hooks. */ +export type ModuleSource = string | ArrayBuffer + +/** Result returned by a Node internal resolve hook. */ +export interface ResolveResult { + format: ModuleFormat + url: string +} + +/** Result returned by a Node internal load hook. */ +export interface LoadResult { + format: ModuleFormat + source?: ModuleSource +} + +type LoadCacheData = ModuleJob // | Function + +/** @see https://github.com/nodejs/node/blob/main/lib/internal/modules/esm/module_map.js */ +interface LoadCache extends Omit>, 'get' | 'set' | 'has'> { + get(url: string, type?: string): LoadCacheData | undefined + set(url: string, type?: string, job?: LoadCacheData): this + has(url: string, type?: string): boolean +} + +/** Minimal Node internal ModuleWrap surface used by HMR helpers. */ +export interface ModuleWrap { + url: string + getNamespace(): any +} + +/** @see https://github.com/nodejs/node/blob/main/lib/internal/modules/esm/module_job.js */ +export interface ModuleJob { + url: string + loader: ModuleLoader + module?: ModuleWrap + importAttributes: ImportAttributes + linked: Promise + instantiate(): Promise + run(): Promise<{ module: ModuleWrap }> +} + +/** + * Node 22/23 ModuleLoader interface. + * + * Key methods: + * - getModuleJobForImport(specifier, parentURL, importAttributes) + * - resolve(specifier, parentURL, importAttributes) → Promise + * - resolveSync(specifier, parentURL, importAttributes) → ResolveResult + */ +export interface ModuleLoaderV1 { + version: 'v1' + loadCache: LoadCache + import(specifier: string, parentURL: string, importAttributes: ImportAttributes): Promise + register(specifier: string | URL, parentURL?: string | URL, data?: any, transferList?: any[]): void + getModuleJobForImport(specifier: string, parentURL: string, importAttributes: ImportAttributes): Promise + resolve(specifier: string, parentURL: string, importAttributes: ImportAttributes): Promise + resolveSync(specifier: string, parentURL: string, importAttributes: ImportAttributes): ResolveResult + load(specifier: string, context: Pick): Promise +} + +/** Node 24+ module request object. */ +export interface ModuleRequest { + specifier: string + attributes?: ImportAttributes + phase?: ModulePhase +} + +/** @see https://github.com/nodejs/node/blob/main/src/module_wrap.h */ +export const enum ModulePhase { + Source = 1, + Evaluation = 2, +} + +/** Opaque Node internal module request type marker. */ +export type ModuleRequestType = unknown // internal symbols + +/** + * Node 24+ ModuleLoader interface. + * + * Breaking changes from v1: + * - getModuleJobForImport removed → getOrCreateModuleJob(parentURL, request, requestType) + * - resolve removed (became private #resolve) → resolveSync(parentURL, request) + * - Parameter order reversed for resolveSync, request object { specifier, attributes } + * - LoadCache became typed Map with delete only setting undefined + */ +export interface ModuleLoaderV2 { + version: 'v2' + loadCache: LoadCache + import(specifier: string, parentURL: string, importAttributes: ImportAttributes, phase?: ModulePhase, isEntryPoint?: boolean): Promise + register(specifier: string | URL, parentURL?: string | URL, data?: any, transferList?: any[], isInternal?: boolean): void + getOrCreateModuleJob(parentURL: string, request: ModuleRequest, requestType?: ModuleRequestType): Promise + resolveSync(parentURL: string, request: ModuleRequest): ResolveResult + load(url: string, context: Pick): Promise +} + +/** Supported Node internal ESM loader shapes. */ +export type ModuleLoader = ModuleLoaderV1 | ModuleLoaderV2 + +/** Helpers for locating the current Node internal module loader. */ +export namespace ModuleLoader { + let _cachedLoader: ModuleLoader | undefined + + function requireInternal(id: string): any { + const require = createRequire(import.meta.url) + if (process.execArgv.includes('--expose-internals')) { + try { + return require(id) + } catch {} + } + try { + return require('node-addon-require-builtin').requireBuiltin(id) + } catch {} + } + + export function fromInternal(): ModuleLoader | undefined { + if (_cachedLoader) return _cachedLoader + const [major] = process.versions.node.split('.').map(Number) + + if (major >= 24) { + const raw = requireInternal('internal/modules/esm/loader')?.getOrInitializeCascadedLoader() + if (raw) return _cachedLoader = Object.assign(raw, { version: 'v2' }) + } else if (major >= 22) { + const raw = requireInternal('internal/modules/esm/loader')?.getOrInitializeCascadedLoader() + if (raw) return _cachedLoader = Object.assign(raw, { version: 'v1' }) + } + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cosmokit b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cosmokit new file mode 120000 index 0000000..dfc2397 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cosmokit @@ -0,0 +1 @@ +../../../@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis-plugin-include b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis-plugin-include new file mode 120000 index 0000000..361c171 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis-plugin-include @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis-plugin-loader b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis-plugin-loader new file mode 120000 index 0000000..614b839 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis-plugin-loader @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/LICENSE new file mode 100644 index 0000000..9fdec8c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-present Shigma + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/README.md new file mode 100644 index 0000000..538809d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/README.md @@ -0,0 +1,101 @@ +# Cordis + +Cordis is a TypeScript plugin framework for applications that need explicit +dependency injection, scoped services, lifecycle-managed cleanup, and optional +configuration-driven loading. The core package is published as `cordis`; the +official packages in this repository add a loader, config-file includes, HMR, +console logging, timers, and project scaffolding. + +## Install + +```sh +yarn add cordis +``` + +Cordis is ESM-first. The repository is tested on current Node releases, and the +scaffolder requires Node 22 or newer. + +## Quick Start + +```ts +import { Context, Service } from 'cordis' + +declare module 'cordis' { + interface Context { + counter: Counter + } + + interface Events { + 'app/ready'(message: string): void + } +} + +class Counter extends Service { + value = 0 + + constructor(ctx: Context) { + super(ctx, 'counter') + } + + next() { + return ++this.value + } +} + +const greeter = Object.assign((ctx: Context) => { + ctx.on('app/ready', (message) => { + ctx.logger.info('%s #%d', message, ctx.counter.next()) + }) +}, { + inject: ['counter'], +}) + +const root = new Context() +await root.plugin(Counter) +await root.plugin(greeter) + +root.emit('app/ready', 'started') +await root.fiber.dispose() +``` + +The important pieces are: + +- `new Context()` creates the root dependency container. +- `ctx.plugin()` starts a plugin and returns a `Fiber`. +- `inject` tells Cordis which services must exist before the plugin runs. +- Effects, event listeners, and services are removed when their owning fiber is + disposed. + +## Documentation + +- [Tutorial: build a plugin](../../docs/tutorials/build-a-plugin.md) +- [Guide: plugin lifecycle](../../docs/guides/plugin-lifecycle.md) +- [Guide: loader configuration](../../docs/guides/loader-config.md) +- [API reference](../../docs/api/core.md) + +## Packages + +| Package | Purpose | +| --- | --- | +| `cordis` | Core context, plugin registry, fiber lifecycle, events, services, and logger. | +| `create-cordis` | Interactive project scaffolder. | +| `@cordisjs/plugin-loader` | Runtime plugin tree and loader service. | +| `@cordisjs/plugin-include` | YAML/JSON config-file include support for the loader. | +| `@cordisjs/plugin-group` | Nested plugin groups for loader configs. | +| `@cordisjs/plugin-hmr` | Hot module replacement for loader-managed plugins. | +| `@cordisjs/plugin-logger-console` | Console exporter for the built-in logger. | +| `@cordisjs/plugin-timer` | Disposal-aware timeout, interval, throttle, and debounce helpers. | +| `@cordisjs/utils` | Shared utilities used by Cordis packages. | + +## Development + +```sh +yarn install +yarn build +yarn test +yarn lint +``` + +The monorepo uses Yakumo to build and test all packages. Most examples in the +docs use public APIs from `cordis`; loader examples additionally use +`@cordisjs/plugin-loader` and `@cordisjs/plugin-include`. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js new file mode 100755 index 0000000..e5ee522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js @@ -0,0 +1,16 @@ +#!/usr/bin/env node + +import { Context } from '@deepseek-ai/cordis' +import { pathToFileURL } from 'node:url' +import Loader from '@deepseek-ai/cordis-plugin-loader' + +const ctx = new Context() +ctx.baseUrl = pathToFileURL(process.cwd()).href + '/' + +await ctx.plugin(Loader) +await ctx.loader.create({ + name: '@deepseek-ai/cordis-plugin-include', + config: { + path: './cordis.yml', + }, +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/index.js new file mode 100644 index 0000000..ce0bbeb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/index.js @@ -0,0 +1,1828 @@ +import { defineProperty, hyphenate, isNullable } from "@deepseek-ai/cosmokit"; +//#region lib/types/utils.js +/** Ordered collection of disposable values with O(1) deletion by value. */ +var DisposableList = class { + sn = 0; + map = /* @__PURE__ */ new Map(); + weak = /* @__PURE__ */ new WeakMap(); + get length() { + return this.map.size; + } + push(value) { + const sn = ++this.sn; + this.map.set(sn, value); + this.weak.set(value, sn); + return () => this.map.delete(sn); + } + delete(value) { + const sn = this.weak.get(value); + if (!sn) return false; + return this.map.delete(sn); + } + clear() { + const values = [...this.map.values()]; + this.map.clear(); + return values.reverse(); + } + [Symbol.iterator]() { + return this.map.values(); + } + [Symbol.for("nodejs.util.inspect.custom")]() { + return [...this]; + } +}; +/** Shared symbols used to avoid public property-name collisions. */ +const symbols = { + shadow: Symbol.for("cordis.shadow"), + receiver: Symbol.for("cordis.receiver"), + original: Symbol.for("cordis.original"), + metadata: Symbol.for("cordis.metadata"), + initHooks: Symbol.for("cordis.initHooks"), + checkProto: Symbol.for("cordis.checkProto"), + effect: Symbol.for("cordis.effect"), + filter: Symbol.for("cordis.filter"), + isolate: Symbol.for("cordis.isolate"), + intercept: Symbol.for("cordis.intercept"), + init: Symbol.for("cordis.init"), + check: Symbol.for("cordis.check"), + config: Symbol.for("cordis.config"), + invoke: Symbol.for("cordis.invoke"), + extend: Symbol.for("cordis.extend"), + tracker: Symbol.for("cordis.tracker"), + resolveConfig: Symbol.for("cordis.resolveConfig") +}; +const GeneratorFunction = function* () {}.constructor; +const AsyncGeneratorFunction = async function* () {}.constructor; +/** Return true when a plugin callback should be constructed with `new`. */ +function isConstructor(func) { + if (!func.prototype) return false; + if (func instanceof GeneratorFunction) return false; + if (AsyncGeneratorFunction !== Function && func instanceof AsyncGeneratorFunction) return false; + return true; +} +/** Merge two prototype chains while preserving descriptors from `proto1`. */ +function joinPrototype(proto1, proto2) { + if (proto1 === Object.prototype) return proto2; + const result = Object.create(joinPrototype(Object.getPrototypeOf(proto1), proto2)); + for (const key of Reflect.ownKeys(proto1)) Object.defineProperty(result, key, Object.getOwnPropertyDescriptor(proto1, key)); + return result; +} +/** Return true for non-null objects and functions. */ +function isObject(value) { + return value && (typeof value === "object" || typeof value === "function"); +} +/** Find a property descriptor by walking an object's prototype chain. */ +function getPropertyDescriptor(target, prop) { + let proto = target; + while (proto) { + const desc = Reflect.getOwnPropertyDescriptor(proto, prop); + if (desc) return desc; + proto = Object.getPrototypeOf(proto); + } +} +/** Wrap services/functions so method calls see the caller's active context. */ +function getTraceable(ctx, value) { + if (!isObject(value)) return value; + if (Object.hasOwn(value, symbols.shadow)) return Object.getPrototypeOf(value); + const tracker = value[symbols.tracker]; + if (!tracker) return value; + return createTraceable(ctx, value, tracker); +} +/** Return a proxy that overlays readonly or writable properties onto a target. */ +function withProps(target, props) { + if (!props) return target; + return new Proxy(target, { + get: (target, prop, receiver) => { + if (prop in props && prop !== "constructor") return Reflect.get(props, prop, receiver); + return Reflect.get(target, prop, receiver); + }, + set: (target, prop, value, receiver) => { + if (prop in props && prop !== "constructor") return Reflect.set(props, prop, value, receiver); + return Reflect.set(target, prop, value, receiver); + } + }); +} +function withProp(target, prop, value) { + return withProps(target, Object.defineProperty(Object.create(null), prop, { + value, + writable: false + })); +} +function createShadow(ctx, target, property, receiver) { + if (!property) return receiver; + const origin = Reflect.getOwnPropertyDescriptor(target, property)?.value; + if (!origin) return receiver; + return withProp(receiver, property, ctx.extend({ [symbols.shadow]: origin })); +} +function createShadowMethod(ctx, value, outer, shadow) { + return new Proxy(value, { apply: (target, thisArg, args) => { + if (thisArg === outer) thisArg = shadow; + return getTraceable(ctx, Reflect.apply(target, thisArg, args)); + } }); +} +function createTraceable(ctx, value, tracker) { + if (ctx[symbols.shadow] && !tracker.noShadow) ctx = Object.getPrototypeOf(ctx); + const proxy = new Proxy(value, { + get: (target, prop, receiver) => { + if (prop === symbols.original) return target; + if (prop === tracker.property) return ctx; + if (typeof prop === "symbol") return Reflect.get(target, prop, receiver); + if (tracker.associate && ctx.reflect.props[`${tracker.associate}.${prop}`]) return Reflect.get(ctx, `${tracker.associate}.${prop}`, withProp(ctx, symbols.receiver, receiver)); + let shadow, innerValue; + const desc = getPropertyDescriptor(target, prop); + if (desc && "value" in desc) innerValue = desc.value; + else { + shadow = createShadow(ctx, target, tracker.property, receiver); + innerValue = Reflect.get(target, prop, shadow); + } + const innerTracker = innerValue?.[symbols.tracker]; + if (innerTracker) return createTraceable(ctx, innerValue, innerTracker); + else if (!tracker.noShadow && typeof innerValue === "function") { + shadow ??= createShadow(ctx, target, tracker.property, receiver); + return createShadowMethod(ctx, innerValue, receiver, shadow); + } else return innerValue; + }, + set: (target, prop, value, receiver) => { + if (prop === symbols.original) return false; + if (prop === tracker.property) return false; + if (typeof prop === "symbol") return Reflect.set(target, prop, value, receiver); + if (tracker.associate && ctx.reflect.props[`${tracker.associate}.${prop}`]) return Reflect.set(ctx, `${tracker.associate}.${prop}`, value, withProp(ctx, symbols.receiver, receiver)); + const shadow = createShadow(ctx, target, tracker.property, receiver); + return Reflect.set(target, prop, value, shadow); + }, + apply: (target, thisArg, args) => { + return applyTraceable(proxy, target, thisArg, args); + } + }); + return proxy; +} +function applyTraceable(proxy, value, thisArg, args) { + if (!value[symbols.invoke]) return Reflect.apply(value, thisArg, args); + return value[symbols.invoke].apply(proxy, args); +} +/** Create a callable service object that dispatches through `symbols.invoke`. */ +function createCallable(name, proto, tracker) { + const self = function(...args) { + return applyTraceable(createTraceable(self["ctx"], self, tracker), self, this, args); + }; + defineProperty(self, "name", name); + return Object.setPrototypeOf(self, proto); +} +function handleError(info, reason, getOuterStack) { + const innerLines = info.error.stack.split("\n"); + if (typeof reason?.stack !== "string") { + const outerError = new Error(reason); + const lines = outerError.stack.split("\n"); + lines.splice(1, Infinity, ...getOuterStack()); + outerError.stack = lines.join("\n"); + throw outerError; + } + const lines = reason.stack.split("\n"); + let index = lines.indexOf(innerLines[2]); + if (index === -1) throw reason; + index -= info.offset; + while (index > 0) { + if (!lines[index - 1].endsWith(" ()")) break; + index -= 1; + } + lines.splice(index, Infinity, ...getOuterStack()); + reason.stack = lines.join("\n"); + throw reason; +} +/** Run a callback and splice outer call-site frames into thrown async errors. */ +function composeError(callback, getOuterStack = buildOuterStack()) { + const info = { + offset: 1, + error: /* @__PURE__ */ new Error() + }; + try { + const result = callback(info); + if (isObject(result) && "then" in result) return result.then(void 0, (reason) => handleError(info, reason, getOuterStack)); + else return result; + } catch (reason) { + handleError(info, reason, getOuterStack); + } +} +/** Capture a lazy stack-frame supplier for later error composition. */ +function buildOuterStack(offset = 0) { + const outerError = /* @__PURE__ */ new Error(); + return () => outerError.stack.split("\n").slice(3 + offset); +} +//#endregion +//#region lib/types/events.js +/** +* Return whether an event result should stop a bail-style dispatch. +* +* @param value — a listener's return value. +* @returns `true` unless `value` is `null`, `false`, or `undefined`. +*/ +function isBailed(value) { + return value !== null && value !== false && value !== void 0; +} +/** +* Event bus installed as `ctx.events` and mixed into every context. +* +* The service supports concurrent, synchronous, serial, bail, and waterfall +* dispatch and automatically disposes listeners with their owning fiber. +*/ +var EventsService = class { + ctx; + _hooks = {}; + constructor(ctx) { + this.ctx = ctx; + defineProperty(this, symbols.tracker, { + property: "ctx", + noShadow: true + }); + this.on("internal/listener", function(name, listener, options) { + if (name === "internal/update" && !options.global) return (this.fiber._hooks["internal/update"] ??= new DisposableList())[options.prepend ? "unshift" : "push"](listener); + }); + this.on("internal/update", function(config, noSave, next) { + const cbs = [...this._hooks["internal/update"] || []]; + const _next = () => { + return (cbs.shift() ?? next).call(this, config, noSave, _next); + }; + return _next(); + }, { + global: true, + prepend: true + }); + } + /** + * Resolve listeners for one dispatch and apply context filtering. + * + * @param type — the dispatch mode, reported on `internal/dispatch`. + * @param args — the raw dispatch arguments; consumed up to the event name. + * @returns the matching listener callbacks, bound to the dispatch `this`. + */ + dispatch(type, args) { + const thisArg = typeof args[0] === "object" || typeof args[0] === "function" ? args.shift() : null; + const name = args.shift(); + if (!name.startsWith("internal/")) this.emit("internal/dispatch", type, name, args, thisArg); + const filter = thisArg?.[Context.filter]; + return (this._hooks[name] || []).filter((hook) => hook.global || !filter || filter.call(thisArg, hook.ctx)).map((hook) => hook.callback.bind(thisArg)); + } + /** + * Run listeners concurrently and wait for all of them. + * + * @param args — optional `this`, the event name, then listener arguments. + * @returns a promise resolving once every listener has settled. + */ + async parallel(...args) { + const errors = (await Promise.allSettled(this.dispatch("emit", args).map(async (cb) => cb(...args)))).filter((result) => result.status === "rejected"); + if (errors.length) throw new AggregateError(errors.map((error) => error.reason)); + } + /** + * Run listeners synchronously without waiting for returned promises. + * + * @param args — optional `this`, the event name, then listener arguments. + */ + emit(...args) { + this.dispatch("emit", args).map((cb) => cb(...args)); + } + /** + * Run listeners in order, awaiting each, until one returns a bail value. + * + * @param args — optional `this`, the event name, then listener arguments. + * @returns the first bail value (see {@link isBailed}), if any. + */ + async serial(...args) { + for (const cb of this.dispatch("serial", args)) { + const result = await cb(...args); + if (isBailed(result)) return result; + } + } + /** + * Run listeners synchronously until one returns a bail value. + * + * @param args — optional `this`, the event name, then listener arguments. + * @returns the first bail value (see {@link isBailed}), if any. + */ + bail(...args) { + for (const cb of this.dispatch("bail", args)) { + const result = cb(...args); + if (isBailed(result)) return result; + } + } + /** + * Compose listeners around the final `next` callback. + * + * The last dispatch argument is treated as the innermost `next`. Listeners + * run outermost-first; a listener that does not call `next()` vetoes the + * rest of the chain, including the built-in behavior. + * + * @param args — optional `this`, the event name, listener arguments, then `next`. + * @returns the outermost listener's return value. + */ + waterfall(...args) { + const cbs = this.dispatch("waterfall", args); + const inner = args.pop(); + const next = () => { + return (cbs.shift() ?? inner)(...args); + }; + args.push(next); + return next(); + } + /** + * Store a listener record as an effect on the current fiber. + * + * @param label — effect label shown in fiber diagnostics. + * @param hooks — the listener list for one event. + * @param callback — the listener to store. + * @param options — placement and filtering options. + * @returns a disposer that unregisters the listener. + */ + register(label, hooks, callback, options) { + const method = options.prepend ? "unshift" : "push"; + return this.ctx.fiber.effect(() => { + hooks[method]({ + ctx: this.ctx, + callback, + ...options + }); + return () => this.unregister(hooks, callback); + }, label); + } + /** + * Remove a stored listener record. + * + * @param hooks — the listener list for one event. + * @param callback — the listener to remove. + * @returns `true` if the listener was found and removed. + */ + unregister(hooks, callback) { + const index = hooks.findIndex((hook) => hook.callback === callback); + if (index >= 0) { + hooks.splice(index, 1); + return true; + } + } + /** + * Register an event listener owned by the current fiber. + * + * The listener is removed automatically when the fiber unloads. Throws + * `CordisError('INACTIVE_EFFECT')` if the fiber is already disposed. + * + * @param name — the event name to listen for. + * @param listener — called with the dispatch arguments. + * @param options — listener options; a boolean is shorthand for `prepend`. + * @returns a disposer removing the listener; `true` if it was still registered. + */ + on(name, listener, options) { + if (typeof options !== "object") options = { prepend: options }; + this.ctx.fiber.assertActive(); + listener = this.ctx.reflect.bind(listener); + const result = this.bail(this.ctx, "internal/listener", name, listener, options); + if (result) return result; + const hooks = this._hooks[name] ||= []; + const label = `ctx.on(${typeof name === "string" ? JSON.stringify(name) : name.toString()})`; + return this.register(label, hooks, listener, options); + } + /** + * Register an event listener that disposes itself after the first call. + * + * @param name — the event name to listen for. + * @param listener — called at most once with the dispatch arguments. + * @param options — listener options; a boolean is shorthand for `prepend`. + * @returns a disposer removing the listener; `true` if it was still registered. + */ + once(name, listener, options) { + const dispose = this.on(name, function(...args) { + dispose(); + return listener.apply(this, args); + }, options); + return dispose; + } +}; +//#endregion +//#region lib/types/logger.js +/** Built-in placeholder formatters used by `Logger.format()`. */ +const defaultFormatters = { + s: (value) => String(value), + d: (value) => Math.trunc(Number(value)), + i: (value) => Math.trunc(Number(value)), + f: (value) => Number(value), + o: (value) => JSON.stringify(value), + O: (value) => JSON.stringify(value), + c: () => "", + C: (value, exporter, message) => { + return Logger.color(exporter, Logger.code(message.name, exporter.colors), value); + } +}; +function isAggregateError(error) { + return error instanceof Error && Array.isArray(error["errors"]); +} +/** Logger facade for one named subsystem. */ +var Logger = class { + service; + static color(exporter, code, value, decoration = "") { + if (!exporter.colors) return "" + value; + return `\u001b[3${code < 8 ? code : "8;5;" + code}${exporter.colors >= 2 ? decoration : ""}m${value}\u001b[0m`; + } + static code(name, level) { + let hash = 0; + for (let i = 0; i < name.length; i++) { + hash = (hash << 3) - hash + name.charCodeAt(i) + 13; + hash |= 0; + } + const colors = !level ? [] : level >= 2 ? c256 : c16; + return colors[Math.abs(hash) % colors.length]; + } + static format(exporter, message) { + const args = message.args.slice(); + if (args[0] instanceof Error) { + args[0] = args[0].stack || args[0].message; + args.unshift("%s"); + } else if (typeof args[0] !== "string") args.unshift("%o"); + let format = args.shift(); + format = format.replace(/%([a-zA-Z%])/g, (match, char) => { + if (match === "%%") return "%"; + const formatter = exporter.formatters?.[char] ?? defaultFormatters[char]; + if (typeof formatter === "function") return formatter(args.shift(), exporter, message); + return match; + }); + const oFormatter = exporter.formatters?.o ?? defaultFormatters.o; + for (let arg of args) { + if (typeof arg === "object" && arg) arg = oFormatter(arg, exporter, message); + format += " " + arg; + } + const { maxLength = 10240 } = exporter; + return format.split(/\r?\n/g).map((line) => { + return line.slice(0, maxLength) + (line.length > maxLength ? "..." : ""); + }).join("\n"); + } + constructor(options, service) { + this.service = service; + Object.assign(this, options); + this.error = this._method("error", 0); + this.info = this._method("info", 1); + this.warn = this._method("warn", 2); + this.debug = this._method("debug", 3); + } + _method(type, level) { + return (...args) => { + if (args.length === 1 && args[0] instanceof Error) { + if (args[0].cause) this[type](args[0].cause); + else if (isAggregateError(args[0])) { + args[0].errors.forEach((error) => this[type](error)); + return; + } + } + const sn = ++this.service._snMessage; + const ts = Date.now(); + for (const exporter of this.service.exporters.values()) { + if ((exporter.levels?.[this.name] ?? exporter.levels?.default ?? this.level ?? 1) < level) continue; + const message = { + sn, + ts, + type, + level, + name: this.name, + ...this.meta, + args + }; + exporter.export(message); + } + }; + } +}; +/** ANSI 16-color palette indexes used for logger name coloring. */ +const c16 = [ + 6, + 2, + 3, + 4, + 5, + 1 +]; +/** ANSI 256-color palette indexes used for logger name coloring. */ +const c256 = [ + 20, + 21, + 26, + 27, + 32, + 33, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 56, + 57, + 62, + 63, + 68, + 69, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 92, + 93, + 98, + 99, + 112, + 113, + 129, + 134, + 135, + 148, + 149, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 178, + 179, + 184, + 185, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 214, + 215, + 220, + 221 +]; +/** +* Built-in logging service. +* +* Call `ctx.logger()` to create a named logger, or call `ctx.logger.info()` +* directly to log with the current fiber-derived name. +*/ +var LoggerService = class LoggerService { + bufferSize = 1e3; + buffer = []; + ctx; + _snMessage = 0; + _snExporter = 0; + exporters = /* @__PURE__ */ new Map(); + constructor(ctx) { + const tracker = { + property: "ctx", + noShadow: true + }; + const self = createCallable("logger", joinPrototype(Object.getPrototypeOf(this), Function.prototype), tracker); + Object.assign(self, this); + self.ctx = ctx; + defineProperty(self, symbols.tracker, tracker); + self.exporter({ + colors: 3, + export: (message) => { + self.buffer.push(message); + if (self.buffer.length > self.bufferSize) self.buffer = self.buffer.slice(-self.bufferSize); + } + }); + return self; + } + /** + * Register an exporter and dispose it with the current fiber. + * + * @param exporter — the sink that receives structured log messages. + * @returns a disposer that removes the exporter. + */ + exporter(exporter) { + return this.ctx.effect(() => { + this.exporters.set(++this._snExporter, exporter); + return () => this.exporters.delete(this._snExporter); + }, "ctx.logger.exporter()"); + } + _resolveConfig() { + let intercept = this.ctx[symbols.intercept]; + const configs = []; + while ("logger" in intercept) { + if (Object.hasOwn(intercept, "logger")) configs.unshift(intercept["logger"]); + intercept = Object.getPrototypeOf(intercept); + } + return Object.assign({}, ...configs); + } + [symbols.invoke](name) { + const config = this._resolveConfig(); + const fiber = (this.ctx[symbols.shadow] ?? this.ctx).fiber; + name ??= config.name; + name ??= hyphenate(fiber.name); + return new Logger({ + name, + level: config.level, + meta: { fiber: new WeakRef(fiber) } + }, this); + } + static { + for (const type of [ + "error", + "info", + "warn", + "debug" + ]) LoggerService.prototype[type] = function(...args) { + return this()[type](...args); + }; + } +}; +//#endregion +//#region lib/types/reflect.js +function enhanceError(error) { + const lines = error.stack.split("\n"); + lines.splice(0, 2, `Error: ${error.message}`); + error.stack = lines.join("\n"); + return error; +} +const RESERVED_WORDS = ["prototype", "then"]; +function isSpecialProperty(prop) { + return typeof prop === "symbol" || RESERVED_WORDS.includes(prop) || parseInt(prop).toString() === prop || prop.startsWith("_"); +} +/** +* Reflection and service-resolution layer installed as `ctx.reflect`. +* +* This service powers the context proxy, service registration, accessors, and +* the mixins that expose core service methods directly on `ctx`. +*/ +var ReflectService = class { + ctx; + /** Proxy traps implementing service resolution for every context object. */ + static handler = { + get: (target, prop, ctx) => { + if (isSpecialProperty(prop)) return Reflect.get(target, prop, ctx); + if (Reflect.has(target, prop)) return getTraceable(ctx, Reflect.get(target, prop, ctx)); + const error = /* @__PURE__ */ new Error(`cannot get property "${prop}" without inject`); + try { + const def = target.reflect.props[prop]; + if (def?.type === "accessor") return def.get.call(ctx, ctx[symbols.receiver], error); + if (!ctx.fiber.runtime) return ctx.reflect.get(prop, false); + return ctx.events.waterfall("internal/get", ctx, prop, error, () => { + const key = target[symbols.isolate][prop]; + let fiber = (ctx[symbols.shadow] ?? ctx).fiber; + while (true) { + const impl = fiber.store?.[prop]; + if (impl) return getTraceable(ctx, impl.value); + if (prop in fiber.inject) { + error.message = `cannot get required service "${prop}" in inactive context`; + throw error; + } + if (!fiber.runtime) throw error; + if (fiber.parent[symbols.isolate][prop] !== key) throw error; + fiber = fiber.parent.fiber; + } + }); + } catch (e) { + throw e === error ? enhanceError(e) : e; + } + }, + set: (target, prop, value, ctx) => { + if (isSpecialProperty(prop)) return Reflect.set(target, prop, value, ctx); + const error = /* @__PURE__ */ new Error(`cannot set property "${prop}" without provide`); + const def = target.reflect.props[prop]; + if (!def) { + if (!ctx.fiber.runtime) return Reflect.set(target, prop, value, ctx); + throw enhanceError(error); + } + try { + if (def.type === "accessor") { + if (!def.set) return false; + return def.set.call(ctx, value, ctx[symbols.receiver], error); + } + return ctx.events.waterfall("internal/set", ctx, prop, value, error, () => { + return ctx.reflect.set(prop, value, error); + }); + } catch (e) { + throw e === error ? enhanceError(e) : e; + } + }, + has: (target, prop) => { + if (isSpecialProperty(prop)) return Reflect.has(target, prop); + if (Reflect.has(target, prop)) return true; + return !!target.reflect.props[prop]; + } + }; + /** Service implementations, keyed by isolation label. */ + store = Object.create(null); + /** Declared context properties (services and accessors), by name. */ + props = Object.create(null); + constructor(ctx) { + this.ctx = ctx; + defineProperty(this, symbols.tracker, { + property: "ctx", + noShadow: true + }); + this.mixin("reflect", [ + "get", + "set", + "provide", + "accessor", + "mixin" + ]); + this.mixin("fiber", ["runtime", "effect"]); + this.mixin("registry", ["inject", "plugin"]); + this.mixin("events", [ + "on", + "once", + "parallel", + "emit", + "serial", + "bail", + "waterfall" + ]); + } + /** + * Read a service from the store without the inject requirement. + * + * @param name — the service name. + * @param strict — when `true`, only return implementations whose providing + * fiber is currently active. + * @returns the service value, or `undefined` when not (yet) provided. + */ + get(name, strict = true) { + return getTraceable(this.ctx, this._getImpl(name, strict)?.value); + } + _getImpl(name, strict = true) { + const key = this.ctx[symbols.isolate][name]; + const impl = key && this.store[key]; + if (!impl) return; + if (strict && impl.fiber.state !== 2) return; + return impl; + } + /** + * Overwrite a provided service's value. + * + * @param name — the service name. + * @param value — the new service value. + * @param error — carrier for the caller stack in diagnostics. + * @returns `true` on success. + * @throws when `name` was never provided, or was provided by another fiber. + */ + set(name, value, error) { + const key = this.ctx[symbols.isolate][name]; + const impl = this.store[key]; + if (!impl) throw new Error(`cannot set property "${name}" without provide`); + if (impl.fiber !== this.ctx.fiber) throw new Error(`cannot set property "${name}" in multiple fibers`); + impl.value = value; + return true; + } + /** + * Register a service implementation owned by the current fiber. + * + * See the `ctx.provide()` overload above for the full contract. + * + * @param name — the service name. + * @param value — the service value. + * @param check — optional availability predicate for dependents. + * @returns a disposer that unregisters the service. + */ + provide(name, value, check) { + return this.ctx.fiber.effect(() => { + if (!this.props[name]) this.props[name] ??= { type: "service" }; + else if (this.props[name].type !== "service") throw new Error(`property "${name}" is already declared as ${this.props[name].type}`); + this.props[name] = { type: "service" }; + this.ctx.root[symbols.isolate][name] ??= Symbol(name); + const key = this.ctx[symbols.isolate][name]; + const impl = { + name, + value, + fiber: this.ctx.fiber, + check + }; + if (this.store[key]) throw new Error(`service "${name}" has been registered at <${this.store[key].fiber.name}>`); + this.store[key] = impl; + this.ctx.fiber.store[name] = impl; + if (this.ctx.fiber.state === 2) this.notify([name]); + return async () => { + delete this.store[key]; + const fibers = this.notify([name]); + await Promise.allSettled(fibers.map((fiber) => fiber.await())); + delete this.ctx.fiber.store[name]; + }; + }, `ctx.provide(${JSON.stringify(name)})`); + } + /** + * Re-evaluate every fiber that requires one of the given services. + * + * @param names — the service names that changed. + * @param filter — restricts notification to matching isolation scopes. + * @returns the fibers whose dependency state was refreshed. + */ + notify(names, filter = (ctx, name) => ctx[symbols.isolate][name] === this.ctx[symbols.isolate][name]) { + const fibers = []; + for (const runtime of this.ctx.registry.values()) for (const fiber of runtime.fibers) { + let hasUpdate = false; + for (const name of names) { + if (!(name in fiber.inject)) continue; + if (!filter(fiber.ctx, name)) continue; + hasUpdate = true; + fiber._checkImpl(name); + } + if (!hasUpdate) continue; + fiber._refresh(); + fibers.push(fiber); + } + for (const name of names) { + const self = Object.create(this.ctx); + self[symbols.filter] = (target) => filter(target, name); + this.ctx.events.emit(self, "internal/service", name, this._getImpl(name, false)?.value); + } + return fibers; + } + /** + * Define a computed context property backed by get/set hooks. + * + * @param name — the context property name. + * @param options — the `get` hook and optional `set` hook. + * @returns a disposer that removes the accessor. + */ + accessor(name, options) { + return this.ctx.fiber.effect(() => { + if (name in this.props) throw new Error(`property "${name}" is already declared as ${this.props[name].type}`); + this.props[name] = { + type: "accessor", + ...options + }; + return () => delete this.props[name]; + }, `ctx.accessor(${JSON.stringify(name)})`); + } + /** + * Expose selected members of a service directly on `ctx`. + * + * See the `ctx.mixin()` overload above for the full contract. + * + * @param source — a context property name or a source object. + * @param mixins — keys to forward, or a source-key → ctx-key map. + * @returns a disposer that removes all created accessors. + */ + mixin(source, mixins) { + const self = this; + return this.ctx.fiber.effect(function* () { + const entries = Array.isArray(mixins) ? mixins.map((key) => [key, key]) : Object.entries(mixins); + const getTarget = (ctx, error) => { + return ctx[source]; + }; + for (const [key, value] of entries) yield self.accessor(value, { + get(receiver, error) { + const service = getTarget(this, error); + if (isNullable(service)) return service; + const mixin = receiver ? withProps(receiver, service) : service; + const value = Reflect.get(service, key, mixin); + if (typeof value !== "function") return value; + return value.bind(mixin ?? service); + }, + set(value, receiver, error) { + const service = getTarget(this, error); + const mixin = receiver ? withProps(receiver, service) : service; + return Reflect.set(service, key, value, mixin); + } + }); + }, `ctx.mixin(${JSON.stringify(source)})`); + } + /** + * Attach this context's tracing wrapper to a value. + * + * @param value — the value to wrap. + * @returns the traceable wrapper (or the value itself when not applicable). + */ + trace(value) { + return getTraceable(this.ctx, value); + } + /** + * Wrap a callback so calls trace `this` and arguments to this context. + * + * @param callback — the function to wrap. + * @returns a proxy delegating to `callback` with traced values. + */ + bind(callback) { + return new Proxy(callback, { + apply: (target, thisArg, args) => { + return Reflect.apply(target, this.trace(thisArg), args.map((arg) => this.trace(arg))); + }, + construct: (target, args, newTarget) => { + return Reflect.construct(target, args.map((arg) => this.trace(arg)), newTarget); + } + }); + } +}; +//#endregion +//#region lib/types/fiber.js +const kValidationError = Symbol.for("ValidationError"); +/** Error raised when plugin configuration fails standard-schema validation. */ +var ValidationError = class extends TypeError { + name = "ValidationError"; + /** + * Build the aggregated message from schema issues. + * + * @param issues — the standard-schema issues, one message line each. + */ + constructor(issues) { + super(`invalid config:\n` + issues.map((issue) => { + if (issue.path) return ` - ${issue.message} (at ${issue.path.join(".")})`; + else return ` - ${issue.message}`; + }).join("\n")); + } +}; +Object.defineProperty(ValidationError.prototype, kValidationError, { value: true }); +/** +* Validate and normalize config for a plugin runtime before it starts. +* +* @param runtime — the plugin runtime whose `Config` schema to apply. +* @param config — the raw user config. +* @returns the validated config, or `config` unchanged if the runtime has no schema. +* @throws {ValidationError} when validation reports issues. +*/ +function resolveConfig(runtime, config) { + if (!runtime.Config) return config; + const result = runtime.Config["~standard"].validate(config); + if ("then" in result) throw new TypeError("Async config validation is not supported"); + if (result.issues) throw new ValidationError(result.issues); + else return result.value; +} +const effectInertia = /* @__PURE__ */ new WeakMap(); +function runDisposable(dispose) { + const result = dispose(); + return effectInertia.get(dispose)?.() ?? result; +} +/** Notify plugin teardown without allowing one observer to break ownership cleanup. */ +function emitPluginDisposed(context, fiber) { + const args = ["internal/plugin", fiber]; + let callbacks; + try { + callbacks = context.events.dispatch("emit", args); + } catch (error) { + context.logger.error(error); + return; + } + for (const callback of callbacks) try { + const returned = callback(...args); + Promise.resolve(returned).catch((error) => context.logger.error(error)); + } catch (error) { + context.logger.error(error); + } +} +/** Framework error with a stable machine-readable code. */ +var CordisError = class CordisError extends Error { + code; + /** + * @param code — the stable error code; also the default message. + * @param message — optional human-readable override. + */ + constructor(code, message) { + super(message ?? CordisError.Code[code]); + this.code = code; + } +}; +/** Cordis error code definitions. */ +(function(CordisError) { + CordisError.Code = { INACTIVE_EFFECT: "cannot create effect on inactive context" }; +})(CordisError || (CordisError = {})); +const INACTIVE = "__INACTIVE__"; +/** +* Runtime instance of one plugin application. +* +* A fiber tracks dependency state, validated config, lifecycle effects, and +* cleanup for the plugin context returned by `ctx.plugin()`. +*/ +var Fiber = class { + parent; + inject; + runtime; + /** Unique id within the registry; 0 for the root fiber, `null` once disposed. */ + uid; + /** The context this fiber's plugin runs in (extends the parent context). */ + ctx; + /** The validated plugin config (updated by `update()`). */ + config; + /** The raw plugin config, re-resolved before each activation. */ + _config; + /** Current lifecycle state; transitions emit `internal/status`. */ + state = 0; + /** Dispose this fiber: unload the plugin, then settle once cleanup finished. */ + dispose; + /** Snapshot of required service implementations while loaded; `undefined` otherwise. */ + store; + /** The in-flight load/unload transition, if one is currently running. */ + inertia; + _hooks = Object.create(null); + _disposables = new DisposableList(); + context; + _error; + _runner; + _store = Object.create(null); + /** + * Create a fiber. Plugin authors normally obtain fibers from `ctx.plugin()` + * rather than constructing them directly. + * + * @param parent — the context the plugin was loaded from. + * @param config — raw config, validated against the runtime's schema. + * @param inject — resolved dependency map (service name → intercept config). + * @param runtime — the shared plugin runtime, or `null` for the root fiber. + * @param getOuterStack — captures the caller stack for effect diagnostics. + */ + constructor(parent, config, inject, runtime, getOuterStack) { + this.parent = parent; + this.inject = inject; + this.runtime = runtime; + this._config = config; + const collect = (dispose) => { + this._disposables.push(dispose); + }; + if (runtime) { + this.uid = parent.registry.counter; + this.ctx = this.context = parent.extend({ fiber: this }); + const injectEntries = Object.entries(this.inject); + if (injectEntries.length) { + this.ctx[Context.intercept] = Object.create(parent[Context.intercept]); + for (const [name, config] of injectEntries) { + if (isNullable(config)) continue; + this.ctx[Context.intercept][name] = config; + } + } + this._runner = { + epoch: INACTIVE, + getOuterStack, + execute: function() { + if (isConstructor(runtime.callback)) { + const instance = new runtime.callback(this.ctx, this.config); + for (const hook of instance?.[symbols.initHooks] ?? []) hook(); + return instance?.[symbols.init]?.(); + } else return runtime.callback(this.ctx, this.config); + }, + collect + }; + this.dispose = parent.fiber.effect(() => { + const remove = runtime.fibers.push(this); + return async () => { + this.uid = null; + emitPluginDisposed(this.context, this); + if (this.ctx.registry.has(runtime.callback)) { + remove(); + if (!runtime.fibers.length) this.ctx.registry.delete(runtime.callback); + } + this._setEpoch(INACTIVE); + if (!this.inertia) this._updateState(() => { + this.inertia = this._unload(); + return 5; + }); + while (this.inertia) await this.inertia; + }; + }, "ctx.plugin()"); + try { + this.context.emit("internal/plugin", this); + } catch (error) { + Promise.resolve(this.dispose()).catch((reason) => this.ctx.logger.error(reason)); + throw error; + } + if (this.uid !== null && parent.fiber.state !== 5) { + for (const name of Object.keys(this.inject)) this._checkImpl(name); + this._refresh(); + } + } else { + this.uid = 0; + this.ctx = this.context = parent; + this.state = 2; + this.store = Object.create(null); + this._runner = { + epoch: "", + getOuterStack, + execute: () => {}, + collect + }; + this.dispose = () => this.restart(); + } + } + /** The plugin's display name, inherited from the nearest named ancestor, else `'root'`. */ + get name() { + let fiber = this; + do { + if (fiber.runtime?.name) return fiber.runtime.name; + fiber = fiber.parent.fiber; + } while (fiber !== fiber.parent.fiber); + return "root"; + } + /** + * Throw if the fiber has already been disposed. + * + * @returns nothing when the fiber is still active. + * @throws {CordisError} `INACTIVE_EFFECT` when the fiber's uid has been cleared. + */ + assertActive() { + if (this.uid !== null) return; + throw new CordisError("INACTIVE_EFFECT"); + } + _execute(runner) { + const oldEpoch = runner.epoch; + return composeError((info) => { + const safeCollect = (dispose) => { + if (typeof dispose === "function") runner.collect(dispose); + else if (!isNullable(dispose)) throw new TypeError("Invalid effect"); + }; + const effect = runner.execute.call(this); + if (typeof effect === "function") return runner.collect(effect); + else if (isNullable(effect)) {} else if (!isObject(effect)) throw new TypeError("Invalid effect"); + else if ("then" in effect) return effect.then(safeCollect); + else if (Symbol.iterator in effect) { + info.error = /* @__PURE__ */ new Error(); + const iter = effect[Symbol.iterator](); + while (true) { + const result = iter.next(); + safeCollect(result.value); + if (result.done) return; + } + } else if (Symbol.asyncIterator in effect) { + const iter = effect[Symbol.asyncIterator](); + return (async () => { + await Promise.resolve(); + info.error = /* @__PURE__ */ new Error(); + while (true) { + if (runner.epoch !== oldEpoch) return; + const result = await iter.next(); + safeCollect(result.value); + if (result.done) return; + } + })(); + } else throw new TypeError("Invalid effect"); + }, runner.getOuterStack); + } + effect(execute, label = "anonymous") { + this.assertActive(); + if (this.state === 5) throw new CordisError("INACTIVE_EFFECT"); + const disposables = []; + let disposing = false; + let disposalTask; + const dispose = () => { + if (disposing) return disposalTask; + disposing = true; + let task; + for (const disposable of disposables.splice(0).reverse()) if (task) task = task.then(() => runDisposable(disposable)); + else { + const result = runDisposable(disposable); + if (isObject(result) && "then" in result) task = result; + } + return disposalTask = task; + }; + const meta = { + label, + children: [] + }; + const runner = { + execute, + epoch: true, + collect: (dispose) => { + disposables.push(dispose); + this._disposables.delete(dispose); + if (dispose[symbols.effect]) meta.children.push(dispose[symbols.effect]); + }, + getOuterStack: buildOuterStack() + }; + let task; + let executing = true; + let resolveSetup; + let rejectSetup; + let setupBarrier; + let setupFailed = false; + let inFlight; + let removeWrapper = () => false; + const waitForSetup = () => { + setupBarrier ??= new Promise((resolve, reject) => { + resolveSetup = resolve; + rejectSetup = reject; + }); + return setupBarrier; + }; + const disposeAfter = (setup) => { + return Promise.resolve(setup).then(() => dispose(), async (reason) => { + await dispose(); + throw reason; + }); + }; + const finalizeDisposal = (callback) => { + let result; + try { + result = callback(); + } catch (error) { + removeWrapper(); + throw error; + } + if (isObject(result) && "then" in result) { + const pending = Promise.resolve(result).finally(() => { + removeWrapper(); + if (inFlight === pending) inFlight = void 0; + }); + return inFlight = pending; + } + removeWrapper(); + return result; + }; + const wrapper = defineProperty(() => { + if (!runner.epoch) return setupFailed ? inFlight : void 0; + runner.epoch = false; + return finalizeDisposal(() => { + if (executing) return disposeAfter(waitForSetup()); + return task ? disposeAfter(task) : dispose(); + }); + }, symbols.effect, meta); + effectInertia.set(wrapper, () => inFlight); + removeWrapper = this._disposables.push(wrapper); + try { + task = this._execute(runner); + } catch (reason) { + executing = false; + setupFailed = true; + runner.epoch = false; + let cleanup; + try { + cleanup = finalizeDisposal(dispose); + } finally { + rejectSetup?.(reason); + } + if (isObject(cleanup) && "then" in cleanup) cleanup.catch((error) => this.ctx.logger.error(error)); + throw reason; + } + executing = false; + if (setupBarrier) Promise.resolve(task).then(resolveSetup, rejectSetup); + task?.catch(() => { + if (!runner.epoch) return dispose(); + return finalizeDisposal(dispose); + }).catch((error) => this.ctx.logger.error(error)); + const disposeAsync = () => { + if (!runner.epoch) return; + runner.epoch = false; + return finalizeDisposal(dispose); + }; + wrapper.then = async (onFulfilled, onRejected) => { + return Promise.resolve(task).then(() => disposeAsync).then(onFulfilled, onRejected); + }; + return wrapper; + } + /** + * Return metadata for currently registered effects. + * + * @returns one {@link EffectMeta} tree per labeled live effect. + */ + getEffects() { + return [...this._disposables].map((dispose) => dispose[symbols.effect]).filter(Boolean); + } + _getState() { + if (this.uid === null) return 4; + if (this._error) return 3; + if (this._runner.epoch !== INACTIVE) return 2; + return 0; + } + _updateState(callback) { + const oldState = this.state; + this.state = callback() ?? this._getState(); + if (oldState === this.state) return; + this.context.emit("internal/status", this, oldState); + if (oldState !== 2 && this.state !== 2) return; + for (const key of Reflect.ownKeys(this.ctx.reflect.store)) { + const impl = this.ctx.reflect.store[key]; + if (impl.fiber !== this) continue; + this.ctx.reflect.notify([impl.name]); + } + } + _checkImpl(name) { + const impl = this.ctx.reflect._getImpl(name, true); + if (!impl) return delete this._store[name]; + try { + if (impl.check && !impl.check.call(getTraceable(this.ctx, impl.value))) return delete this._store[name]; + } catch (error) { + impl.fiber.ctx.logger.error(error); + return delete this._store[name]; + } + this._store[name] = impl; + } + _refresh() { + let epoch = false; + epoch = ""; + for (const name of Object.keys(this.inject)) { + const impl = this._store[name]; + if (!impl) { + epoch = INACTIVE; + break; + } + epoch += ":" + impl.fiber.uid; + } + this._setEpoch(epoch); + } + _setEpoch(epoch) { + const oldEpoch = this._runner.epoch; + if (epoch === oldEpoch) return; + this._runner.epoch = epoch; + if (this.inertia) return; + this._updateState(() => { + if (epoch !== INACTIVE && oldEpoch === INACTIVE) { + this.inertia = this._reload(); + return 1; + } else { + this.inertia = this._unload(); + return 5; + } + }); + } + _resolveConfig(config) { + config = this.context.waterfall(this, "internal/config", config, () => config); + return this.runtime ? resolveConfig(this.runtime, config) : config; + } + async _reload() { + this.store = { ...this._store }; + const oldEpoch = this._runner.epoch; + try { + await Promise.resolve(); + if (this._runner.epoch === oldEpoch) { + this.config = this._resolveConfig(this._config); + await this._execute(this._runner); + this._error = void 0; + } + } catch (reason) { + this.ctx.logger.error(reason); + this._error = reason; + this._runner.epoch = INACTIVE; + } + this._updateState(() => { + if (this._runner.epoch === oldEpoch) this.inertia = void 0; + else { + this.inertia = this._unload(); + return 5; + } + }); + } + async _unload() { + await Promise.all(this._disposables.clear().map(async (dispose) => { + try { + await composeError(async (info) => { + await Promise.resolve(); + info.error = /* @__PURE__ */ new Error(); + await runDisposable(dispose); + }, this._runner.getOuterStack); + } catch (reason) { + this.ctx.logger.error(reason); + } + })); + this.store = void 0; + this._updateState(() => { + if (this._runner.epoch === INACTIVE) this.inertia = void 0; + else { + this.inertia = this._reload(); + return 1; + } + }); + } + /** + * Wait for current lifecycle work and rethrow startup errors. + * + * @returns this fiber, once it has settled into a stable state. + * @throws the config-validation or plugin-startup error, if any. + */ + async await() { + while (this.inertia) await this.inertia; + if (this._error) throw this._error; + return this; + } + /** + * Dispose and immediately reload this plugin with its current config. + * + * @returns a promise resolving once the reload settled. + * @throws {CordisError} `INACTIVE_EFFECT` when the fiber is already disposed. + */ + async restart() { + this.assertActive(); + this._setEpoch(INACTIVE); + this._refresh(); + await this.await(); + } + /** + * Validate and apply new config, then restart the plugin. + * + * Runs the `internal/update` waterfall first, so update hooks (and HMR) + * can veto or replace the restart. + * + * @param config — the new raw config; validated before anything restarts. + * @param noSave — hint for persistence hooks not to write the change back. + * @returns the update waterfall result; the default restart returns a promise. + * @throws when validation, an update listener, or the restarted plugin fails. + */ + update(config, noSave = false) { + this.assertActive(); + this._config = config; + if (this.state !== 2) { + this._error = void 0; + this._setEpoch(INACTIVE); + this._refresh(); + return; + } + config = this._resolveConfig(config); + return this.context.waterfall(this, "internal/update", config, noSave, () => { + this.config = config; + this._error = void 0; + return this.restart(); + }); + } +}; +//#endregion +//#region lib/types/registry.js +function isApplicable(object) { + return object && typeof object === "object" && typeof object.apply === "function"; +} +/** +* Decorator for declaring service dependencies on classes or class methods. +* +* On classes it contributes to the plugin's static `inject` map. On methods it +* delays the method call until the declared services are available. +*/ +/** +* @param name — the required service name. +* @param config — optional intercept config applied for that service. +* @returns the class or method decorator. +*/ +function Inject(name, config) { + return function(value, decorator) { + if (decorator.kind === "class") { + if (!Object.hasOwn(value, "inject")) { + defineProperty(value, "inject", Object.create(Object.getPrototypeOf(value).inject ?? null)); + defineProperty(value.inject, symbols.checkProto, true); + } + value.inject[name] = config; + } else if (decorator.kind === "method") { + const inject = (value[symbols.metadata] ??= {}).inject ??= Object.create(null); + inject[name] = config; + decorator.addInitializer(function() { + const property = this[symbols.tracker]?.property; + (this[symbols.initHooks] ??= []).push(() => { + this.ctx.inject(inject, (ctx) => { + return value.call(property ? withProps(this, { [property]: ctx }) : this); + }); + }); + }); + } else throw new Error("@Inject() can only be used on class or class methods"); + }; +} +/** Utilities for normalizing plugin dependency declarations. */ +(function(Inject) { + /** + * Convert array/object/class-inherited inject metadata into a plain map. + * + * @param inject — the declaration to normalize; `null`/`undefined` add nothing. + * @param result — the map to fill (service name → intercept config or `null`). + * @returns `result`. + */ + function resolve(inject, result = Object.create(null)) { + if (!inject) return result; + if (Array.isArray(inject)) for (const name of inject) result[name] = null; + else if (Reflect.has(inject, symbols.checkProto)) { + Object.assign(result, resolve(Object.getPrototypeOf(inject))); + for (const name of Object.keys(inject)) result[name] = inject[name] ?? null; + } else for (const name of Object.keys(inject)) result[name] = inject[name] ?? null; + return result; + } + Inject.resolve = resolve; +})(Inject || (Inject = {})); +/** +* Plugin registry installed as `ctx.registry` and mixed into every context. +* +* It normalizes plugin shapes, tracks plugin runtimes, starts fibers, and +* exposes map-like inspection over active plugin callbacks. +*/ +var RegistryService = class { + ctx; + _counter = 0; + _internal = /* @__PURE__ */ new Map(); + constructor(ctx) { + this.ctx = ctx; + defineProperty(this, symbols.tracker, { + property: "ctx", + noShadow: true + }); + } + /** Allocate the next fiber uid (increments on every read). */ + get counter() { + return ++this._counter; + } + /** Number of registered plugin runtimes. */ + get size() { + return this._internal.size; + } + /** + * Resolve a supported plugin shape to its executable callback. + * + * @param plugin — a function, class, or `{ apply }` object plugin. + * @returns the callback identifying the plugin, or `undefined` if invalid. + */ + resolve(plugin) { + try { + if (typeof plugin === "function") return plugin; + if (isApplicable(plugin)) return plugin.apply; + } catch {} + } + /** + * Look up the runtime record for a plugin. + * + * @param plugin — any supported plugin shape. + * @returns the runtime, or `undefined` when the plugin is not registered. + */ + get(plugin) { + const key = this.resolve(plugin); + return key && this._internal.get(key); + } + /** + * Check whether a plugin has a registered runtime. + * + * @param plugin — any supported plugin shape. + * @returns `true` when at least one fiber of the plugin exists. + */ + has(plugin) { + const key = this.resolve(plugin); + return !!key && this._internal.has(key); + } + /** + * Dispose every running fiber for a plugin and remove its runtime record. + * + * @param plugin — any supported plugin shape. + * @returns the removed runtime, or `undefined` when none was registered. + */ + delete(plugin) { + const key = this.resolve(plugin); + const runtime = key && this._internal.get(key); + if (!runtime) return; + this._internal.delete(key); + for (const fiber of runtime.fibers) fiber.dispose(); + return runtime; + } + /** Iterate the registered plugin callbacks. */ + keys() { + return this._internal.keys(); + } + /** Iterate the registered plugin runtimes. */ + values() { + return this._internal.values(); + } + /** Iterate `[callback, runtime]` pairs. */ + entries() { + return this._internal.entries(); + } + /** + * Visit every registered runtime. + * + * @param callback — receives each runtime and its identifying callback. + */ + forEach(callback) { + return this._internal.forEach(callback); + } + /** + * Start a callback once the requested dependencies are available. + * + * @param inject — required services, as an array or a name → config map. + * @param callback — plugin body called with `(ctx, config)`. + * @returns the fiber; awaiting it settles once loading finished. + */ + inject(inject, callback) { + return this.plugin({ + inject, + apply: callback, + name: callback.name + }); + } + /** + * Start a plugin in the current context and return its fiber. + * + * Creates (or reuses) the plugin's runtime record, then starts a new fiber + * under the current context. Throws if `plugin` is not a supported shape or + * if the current fiber is already disposed. + * + * @param plugin — a function, class, or `{ apply }` object plugin. + * @param config — the plugin config, validated against its `Config` schema. + * @param getOuterStack — captures the caller stack for effect diagnostics. + * @returns the fiber; awaiting it settles once loading finished. + */ + plugin(plugin, config, getOuterStack = buildOuterStack()) { + const callback = this.resolve(plugin); + if (!callback) throw new Error("invalid plugin, expect function or object with an \"apply\" method, received " + typeof plugin); + this.ctx.fiber.assertActive(); + let runtime = this._internal.get(callback); + if (!runtime) { + let name = plugin.name; + if (name === "apply") name = void 0; + runtime = { + name, + callback, + fibers: new DisposableList(), + Config: plugin.Config + }; + this._internal.set(callback, runtime); + } + const fiber = new Fiber(this.ctx, config, Inject.resolve(plugin.inject), runtime, getOuterStack); + const wrapped = Object.create(fiber); + wrapped.then = (onFulfilled, onRejected) => { + return fiber.await().then(onFulfilled, onRejected); + }; + return wrapped; + } +}; +//#endregion +//#region lib/types/context.js +/** +* Root and child dependency containers for Cordis plugins. +* +* A context is a proxy: normal property reads go through the service resolver, +* while `extend()`, `isolate()`, and `intercept()` create scoped child +* contexts without mutating their parent. +*/ +var Context = class Context { + /** Symbol key under which a disposer exposes its {@link EffectMeta} diagnostics tree. */ + static effect = symbols.effect; + /** Symbol key for a context's listener filter, consulted on every event dispatch. */ + static filter = symbols.filter; + /** Symbol key of the isolation map (see the `Context[symbols.isolate]` property). */ + static isolate = symbols.isolate; + /** Symbol key of the intercept map (see the `Context[symbols.intercept]` property). */ + static intercept = symbols.intercept; + /** + * Returns true for Cordis context proxies and context prototypes. + * + * Works across realms and across multiple copies of cordis, because the + * brand is keyed by a global symbol rather than by `instanceof`. + * + * @param value — the value to test. + * @returns `true` if `value` is a Cordis context, narrowing its type. + */ + static is(value) { + return !!value?.[Context.is]; + } + static { + Context.is[Symbol.toPrimitive] = () => Symbol.for("cordis.is"); + Context.prototype[Context.is] = true; + } + /** Create the root context and install the built-in services. */ + constructor() { + this[symbols.isolate] = Object.create(null); + this[symbols.intercept] = Object.create(null); + const self = new Proxy(this, ReflectService.handler); + this.root = self; + this.baseUrl = void 0; + this.fiber = new Fiber(self, {}, Object.create(null), null, () => []); + this.reflect = new ReflectService(self); + this.registry = new RegistryService(self); + this.events = new EventsService(self); + this.logger = new LoggerService(self); + this.fiber._disposables.clear(); + return self; + } + [Symbol.for("nodejs.util.inspect.custom")]() { + return `Context <${this.fiber.name}>`; + } + /** + * Create a child context with extra metadata on top of the current scope. + * + * The child prototypally inherits every property of this context; own + * properties of `meta` shadow the inherited ones. The parent is not mutated. + * + * @param meta — own properties (including symbol keys) to define on the child. + * @returns a child context inheriting from this one. + */ + extend(meta = {}) { + const shadow = Reflect.getOwnPropertyDescriptor(this, symbols.shadow)?.value; + const self = Object.create(getTraceable(this, this)); + for (const prop of Reflect.ownKeys(meta)) Object.defineProperty(self, prop, Reflect.getOwnPropertyDescriptor(meta, prop)); + if (!shadow) return self; + return Object.assign(Object.create(self), { [symbols.shadow]: shadow }); + } + /** + * Create a child context with an independent service scope for `name`. + * + * Below the returned context, reads and writes of the service `name` + * resolve against the new label instead of the parent's, so a different + * implementation can be provided without affecting the parent scope. + * Passing the same `label` to two `isolate()` calls joins their scopes. + * + * @param name — the service name to isolate. + * @param label — scope label to join; defaults to a fresh unique symbol. + * @returns a child context whose `name` service resolves in the new scope. + */ + isolate(name, label) { + const shadow = Object.create(this[symbols.isolate]); + shadow[name] = label ?? Symbol(name); + return this.extend({ [symbols.isolate]: shadow }); + } + intercept(name, config) { + const intercept = Object.create(this[symbols.intercept]); + intercept[name] = config; + return this.extend({ [symbols.intercept]: intercept }); + } +}; +//#endregion +//#region lib/types/service.js +/** +* Base class for services that expose a named API on `ctx`. +* +* Subclasses call `super(ctx, name)` from their constructor. The service is +* registered immediately and is automatically removed with the owning fiber. +*/ +var Service = class Service { + ctx; + /** Symbol key of an instance method run after construction (class plugins). */ + static init = symbols.init; + /** Symbol key of the availability predicate passed to `ctx.provide()`. */ + static check = symbols.check; + /** Symbol key of the phantom intercept-config type parameter. */ + static config = symbols.config; + /** Symbol key of the call body making a service callable (e.g. `ctx.logger()`). */ + static invoke = symbols.invoke; + /** Symbol key of the helper deriving an extended service instance. */ + static extend = symbols.extend; + /** Symbol key of the tracker metadata used for context tracing. */ + static tracker = symbols.tracker; + /** Symbol key of the intercept-config resolution helper below. */ + static resolveConfig = symbols.resolveConfig; + /** The service name this instance is registered under. */ + name; + /** + * Register this instance as `name` in the current context. + * + * Calls `ctx.reflect.provide(name, this, this[Service.check])`, so the + * service is unregistered automatically when the owning fiber unloads. + * Services with a `[Service.invoke]` body return a callable instance. + * + * @param ctx — the context to register in (stored as `this.ctx`). + * @param name — the service name; defaults to the static `provide` field. + */ + constructor(ctx, name) { + this.ctx = ctx; + name ??= this.constructor["provide"]; + let self = this; + const tracker = { + associate: name, + property: "ctx" + }; + if (self[symbols.invoke]) self = createCallable(name, joinPrototype(Object.getPrototypeOf(this), Function.prototype), tracker); + self.ctx = ctx; + self.name = name; + defineProperty(self, symbols.tracker, tracker); + self.ctx.reflect.provide(name, self, this[symbols.check]); + return self; + } + [symbols.filter](ctx) { + return ctx[symbols.isolate][this.name] === this.ctx[symbols.isolate][this.name]; + } + [symbols.extend](props) { + let self; + if (this[Service.invoke]) self = createCallable(this.name, this, this[symbols.tracker]); + else self = Object.create(this); + return Object.assign(self, props); + } + /** + * Merge intercept config from ancestors with optional base and head values. + * + * Entries added closer to the root apply first; `base` is prepended and + * `head` appended. Uses `Config.merge` when the service declares one, + * otherwise a shallow `Object.assign`. + * + * @param base — lowest-precedence config merged before all intercepts. + * @param head — highest-precedence config merged after all intercepts. + * @returns the merged config. + */ + [symbols.resolveConfig](base, head) { + let intercept = this.ctx[Context.intercept]; + const configs = []; + while (this.name in intercept) { + if (Object.hasOwn(intercept, this.name)) configs.unshift(intercept[this.name]); + intercept = Object.getPrototypeOf(intercept); + } + if (base) configs.unshift(base); + if (head) configs.push(head); + if (this["Config"]?.merge) return this["Config"].merge(...configs); + else return Object.assign({}, ...configs); + } + static [Symbol.hasInstance](instance) { + if (!instance) return false; + let constructor = instance.constructor; + while (constructor) { + constructor = constructor.prototype?.constructor; + if (constructor === this) return true; + constructor &&= Object.getPrototypeOf(constructor); + } + return false; + } +}; +//#endregion +export { Context, CordisError, DisposableList, EventsService, Fiber, Inject, Logger, LoggerService, RegistryService, Service, ValidationError, buildOuterStack, c16, c256, composeError, createCallable, defaultFormatters, getPropertyDescriptor, getTraceable, isBailed, isConstructor, isObject, joinPrototype, resolveConfig, symbols, withProps }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/context.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/context.d.ts new file mode 100644 index 0000000..93c2b37 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/context.d.ts @@ -0,0 +1,101 @@ +import type { Dict } from '@deepseek-ai/cosmokit'; +import { EventsService } from './events.ts'; +import { LoggerService } from './logger.ts'; +import { ReflectService } from './reflect.ts'; +import { RegistryService, type InjectKey } from './registry.ts'; +import { symbols } from './utils.ts'; +import './fiber.ts'; +/** + * Public shape of a Cordis context. + * + * The concrete `Context` class is proxied at runtime, so this interface is + * augmented by core services and plugins to describe the properties that may + * be read from `ctx`. + */ +export interface Context { + /** Isolation map: service name → scope label. Lookups for a name resolve within its label. */ + [symbols.isolate]: Dict; + /** Intercept map: service name → config merged into that service's per-plugin config. */ + [symbols.intercept]: Dict; + /** The root context of the application (every child context shares it). @experimental */ + root: this; + /** Base URL used to resolve relative plugin/module specifiers, if the runtime sets one. */ + baseUrl?: string; + /** The event bus. Its methods are also mixed onto `ctx` (`ctx.on`, `ctx.emit`, ...). */ + events: EventsService; + /** The logging service. Call `ctx.logger(name)` for a named logger. */ + logger: LoggerService; + /** The reflection layer backing the context proxy (`ctx.get`, `ctx.provide`, ...). */ + reflect: ReflectService; + /** The plugin registry. Its methods are mixed onto `ctx` (`ctx.plugin`, `ctx.inject`). */ + registry: RegistryService; +} +/** + * Root and child dependency containers for Cordis plugins. + * + * A context is a proxy: normal property reads go through the service resolver, + * while `extend()`, `isolate()`, and `intercept()` create scoped child + * contexts without mutating their parent. + */ +export declare class Context { + /** Symbol key under which a disposer exposes its {@link EffectMeta} diagnostics tree. */ + static readonly effect: unique symbol; + /** Symbol key for a context's listener filter, consulted on every event dispatch. */ + static readonly filter: unique symbol; + /** Symbol key of the isolation map (see the `Context[symbols.isolate]` property). */ + static readonly isolate: unique symbol; + /** Symbol key of the intercept map (see the `Context[symbols.intercept]` property). */ + static readonly intercept: unique symbol; + /** + * Returns true for Cordis context proxies and context prototypes. + * + * Works across realms and across multiple copies of cordis, because the + * brand is keyed by a global symbol rather than by `instanceof`. + * + * @param value — the value to test. + * @returns `true` if `value` is a Cordis context, narrowing its type. + */ + static is(value: any): value is Context; + /** Create the root context and install the built-in services. */ + constructor(); + /** + * Create a child context with extra metadata on top of the current scope. + * + * The child prototypally inherits every property of this context; own + * properties of `meta` shadow the inherited ones. The parent is not mutated. + * + * @param meta — own properties (including symbol keys) to define on the child. + * @returns a child context inheriting from this one. + */ + extend(meta?: {}): this; + /** + * Create a child context with an independent service scope for `name`. + * + * Below the returned context, reads and writes of the service `name` + * resolve against the new label instead of the parent's, so a different + * implementation can be provided without affecting the parent scope. + * Passing the same `label` to two `isolate()` calls joins their scopes. + * + * @param name — the service name to isolate. + * @param label — scope label to join; defaults to a fresh unique symbol. + * @returns a child context whose `name` service resolves in the new scope. + */ + isolate(name: string, label?: symbol): this; + /** + * Add service-specific intercept config for plugins started below this + * context. + * + * Plugins loaded under the returned context see `config` merged into the + * service's resolved config (ancestor entries first; see + * `Service[symbols.resolveConfig]`). The parent context is not affected. + * + * @param name — the service name whose config to intercept. + * @param config — the intercept config to merge for that service. + * @returns a child context carrying the additional intercept entry. + */ + intercept(name: K, config: Context[K] extends { + [symbols.config]: infer T; + } ? T : never): this; + intercept(name: string, config: any): this; +} +//# sourceMappingURL=context.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/context.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/context.d.ts.map new file mode 100644 index 0000000..de91c76 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/context.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAA;AAC/D,OAAO,EAAgB,OAAO,EAAE,MAAM,YAAY,CAAA;AAClD,OAAsB,YAAY,CAAA;AAElC;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACtB,8FAA8F;IAC9F,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;IAC/B,yFAAyF;IACzF,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,CAAA;IACzB,yFAAyF;IACzF,IAAI,EAAE,IAAI,CAAA;IACV,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,wFAAwF;IACxF,MAAM,EAAE,aAAa,CAAA;IACrB,uEAAuE;IACvE,MAAM,EAAE,aAAa,CAAA;IACrB,sFAAsF;IACtF,OAAO,EAAE,cAAc,CAAA;IACvB,0FAA0F;IAC1F,QAAQ,EAAE,eAAe,CAAA;CAC1B;AAED;;;;;;GAMG;AACH,qBAAa,OAAO;IAClB,yFAAyF;IACzF,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,MAAM,CAAiB;IACtD,qFAAqF;IACrF,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,MAAM,CAAiB;IACtD,qFAAqF;IACrF,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,MAAM,CAAkB;IACxD,uFAAuF;IACvF,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,MAAM,CAAoB;IAE5D;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,OAAO;IASvC,iEAAiE;;IAoBjE;;;;;;;;OAQG;IACH,MAAM,CAAC,IAAI,KAAK,GAAG,IAAI;IAUvB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAMpC;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS;QAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK,GAAG,IAAI;IACnH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CAM3C"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/events.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/events.d.ts new file mode 100644 index 0000000..f6c4b9a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/events.d.ts @@ -0,0 +1,240 @@ +import type { Promisify } from '@deepseek-ai/cosmokit'; +import { Context } from './context.ts'; +import { Fiber, FiberState } from './fiber.ts'; +/** + * Return whether an event result should stop a bail-style dispatch. + * + * @param value — a listener's return value. + * @returns `true` unless `value` is `null`, `false`, or `undefined`. + */ +export declare function isBailed(value: any): boolean; +/** Extract the parameter tuple from a function type. */ +export type Parameters = F extends (...args: infer P) => any ? P : never; +/** Extract the return type from a function type. */ +export type ReturnType = F extends (...args: any) => infer R ? R : never; +/** Extract the explicit `this` type from a function type. */ +export type ThisType = F extends (this: infer T, ...args: any) => any ? T : never; +/** + * Event dispatch strategy used by the event service. + * + * `emit` runs synchronous listeners without awaiting them, `parallel` awaits + * all listeners together, `serial` awaits them in order until one bails, + * `bail` stops on the first synchronous bail value, and `waterfall` composes + * listeners around a final `next` callback. + */ +export type DispatchMode = 'emit' | 'parallel' | 'serial' | 'bail' | 'waterfall'; +declare module './context.ts' { + interface Context { + /** + * Dispatch an event, running all listeners concurrently. + * + * @param name — the event name. + * @param args — arguments passed to every listener. + * @returns a promise resolving once every listener has settled. + */ + parallel(name: K, ...args: Parameters): Promise; + /** Same as above, with an explicit `this` for listeners (also used for filtering). */ + parallel(thisArg: NoInfer>, name: K, ...args: Parameters): Promise; + /** + * Dispatch an event synchronously, ignoring listener return values. + * + * @param name — the event name. + * @param args — arguments passed to every listener. + */ + emit(name: K, ...args: Parameters): void; + /** Same as above, with an explicit `this` for listeners (also used for filtering). */ + emit(thisArg: NoInfer>, name: K, ...args: Parameters): void; + /** + * Dispatch an event, awaiting listeners in order until one bails. + * + * @param name — the event name. + * @param args — arguments passed to each listener. + * @returns the first bail value (non-null, non-false, non-undefined), if any. + */ + serial(name: K, ...args: Parameters): Promisify>; + /** Same as above, with an explicit `this` for listeners (also used for filtering). */ + serial(thisArg: NoInfer>, name: K, ...args: Parameters): Promisify>; + /** + * Dispatch an event, calling listeners in order until one bails. + * + * @param name — the event name. + * @param args — arguments passed to each listener. + * @returns the first bail value (non-null, non-false, non-undefined), if any. + */ + bail(name: K, ...args: Parameters): ReturnType; + /** Same as above, with an explicit `this` for listeners (also used for filtering). */ + bail(thisArg: NoInfer>, name: K, ...args: Parameters): ReturnType; + /** + * Dispatch an event whose last argument is a `next` continuation. + * + * Each listener wraps the rest of the chain: calling `next()` invokes the + * next listener (finally the built-in behavior); not calling it vetoes. + * + * @param name — the event name. + * @param args — listener arguments; the final one is the innermost `next`. + * @returns the outermost listener's return value. + */ + waterfall(name: K, ...args: Parameters): ReturnType; + /** Same as above, with an explicit `this` for listeners (also used for filtering). */ + waterfall(thisArg: NoInfer>, name: K, ...args: Parameters): ReturnType; + /** + * Register an event listener owned by the current fiber. + * + * @param name — the event name to listen for. + * @param listener — called with the dispatch arguments. + * @param options — listener options; a boolean is shorthand for `prepend`. + * @returns a disposer removing the listener; `true` if it was still registered. + */ + on(name: K, listener: Events[K], options?: boolean | EventOptions): () => boolean; + /** + * Same as `on()`, but the listener disposes itself after its first call. + * + * @param name — the event name to listen for. + * @param listener — called at most once with the dispatch arguments. + * @param options — listener options; a boolean is shorthand for `prepend`. + * @returns a disposer removing the listener; `true` if it was still registered. + */ + once(name: K, listener: Events[K], options?: boolean | EventOptions): () => boolean; + } +} +/** Options accepted by `ctx.on()` and `ctx.once()`. */ +export interface EventOptions { + /** Add the listener before existing listeners for the same event. */ + prepend?: boolean; + /** Receive the event regardless of context filter checks. */ + global?: boolean; +} +/** Registered listener record stored by the event service. */ +export interface Hook extends EventOptions { + ctx: Context; + callback: (...args: any[]) => any; +} +/** + * Event bus installed as `ctx.events` and mixed into every context. + * + * The service supports concurrent, synchronous, serial, bail, and waterfall + * dispatch and automatically disposes listeners with their owning fiber. + */ +export declare class EventsService { + private ctx; + _hooks: Record; + constructor(ctx: Context); + /** + * Resolve listeners for one dispatch and apply context filtering. + * + * @param type — the dispatch mode, reported on `internal/dispatch`. + * @param args — the raw dispatch arguments; consumed up to the event name. + * @returns the matching listener callbacks, bound to the dispatch `this`. + */ + dispatch(type: string, args: any[]): ((...args: any[]) => any)[]; + /** + * Run listeners concurrently and wait for all of them. + * + * @param args — optional `this`, the event name, then listener arguments. + * @returns a promise resolving once every listener has settled. + */ + parallel(...args: any[]): Promise; + /** + * Run listeners synchronously without waiting for returned promises. + * + * @param args — optional `this`, the event name, then listener arguments. + */ + emit(...args: any[]): void; + /** + * Run listeners in order, awaiting each, until one returns a bail value. + * + * @param args — optional `this`, the event name, then listener arguments. + * @returns the first bail value (see {@link isBailed}), if any. + */ + serial(...args: any[]): Promise; + /** + * Run listeners synchronously until one returns a bail value. + * + * @param args — optional `this`, the event name, then listener arguments. + * @returns the first bail value (see {@link isBailed}), if any. + */ + bail(...args: any[]): any; + /** + * Compose listeners around the final `next` callback. + * + * The last dispatch argument is treated as the innermost `next`. Listeners + * run outermost-first; a listener that does not call `next()` vetoes the + * rest of the chain, including the built-in behavior. + * + * @param args — optional `this`, the event name, listener arguments, then `next`. + * @returns the outermost listener's return value. + */ + waterfall(...args: any[]): any; + /** + * Store a listener record as an effect on the current fiber. + * + * @param label — effect label shown in fiber diagnostics. + * @param hooks — the listener list for one event. + * @param callback — the listener to store. + * @param options — placement and filtering options. + * @returns a disposer that unregisters the listener. + */ + register(label: string, hooks: Hook[], callback: any, options: EventOptions): () => void; + /** + * Remove a stored listener record. + * + * @param hooks — the listener list for one event. + * @param callback — the listener to remove. + * @returns `true` if the listener was found and removed. + */ + unregister(hooks: Hook[], callback: any): true | undefined; + /** + * Register an event listener owned by the current fiber. + * + * The listener is removed automatically when the fiber unloads. Throws + * `CordisError('INACTIVE_EFFECT')` if the fiber is already disposed. + * + * @param name — the event name to listen for. + * @param listener — called with the dispatch arguments. + * @param options — listener options; a boolean is shorthand for `prepend`. + * @returns a disposer removing the listener; `true` if it was still registered. + */ + on(name: string | symbol, listener: (...args: any) => any, options?: boolean | EventOptions): any; + /** + * Register an event listener that disposes itself after the first call. + * + * @param name — the event name to listen for. + * @param listener — called at most once with the dispatch arguments. + * @param options — listener options; a boolean is shorthand for `prepend`. + * @returns a disposer removing the listener; `true` if it was still registered. + */ + once(name: string, listener: (...args: any) => any, options?: boolean | EventOptions): any; +} +/** + * Built-in framework events used by core services and extension points. + * + * Plugin and status events track fiber lifecycle, service events observe + * dependency registration, update/get/set/listener events allow core services + * to intercept runtime operations, and `internal/dispatch` exposes event-bus + * diagnostics before public events are delivered. + */ +export interface Events { + /** A plugin fiber was created or its uid was cleared on disposal. */ + 'internal/plugin'(fiber: Fiber): void; + /** A fiber changed lifecycle state; receives the fiber and its previous state. */ + 'internal/status'(fiber: Fiber, oldValue: FiberState): void; + /** + * Resolve raw plugin config after the fiber's injections become active. + * @param config - the raw config for this activation. + * @mode waterfall + */ + 'internal/config'(this: Fiber, config: any, next: () => any): any; + /** Interception hook for a service binding (no core producer). */ + 'internal/service'(this: Context, name: string, value: any): void; + /** Waterfall: a fiber config update is being applied; skip `next()` to veto. */ + 'internal/update'(this: Fiber, config: any, noSave: boolean, next: () => void | Promise): void | Promise; + /** Waterfall: a service is being read through the context proxy. */ + 'internal/get'(ctx: Context, name: string, error: Error, next: () => any): any; + /** Waterfall: a service is being written through the context proxy. */ + 'internal/set'(ctx: Context, name: string, value: any, error: Error, next: () => boolean): boolean; + /** Bail: a listener is being registered; a non-null result replaces registration. */ + 'internal/listener'(this: Context, name: string, listener: any, prepend: boolean): void; + /** An event is being dispatched to listeners (fired for non-internal events only). */ + 'internal/dispatch'(mode: DispatchMode, name: string, args: any[], thisArg: any): void; +} +//# sourceMappingURL=events.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/events.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/events.d.ts.map new file mode 100644 index 0000000..b39678e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/events.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/events.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAG9C;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,GAAG,WAElC;AAED,wDAAwD;AACxD,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,CAAA;AAC3E,oDAAoD;AACpD,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAC3E,6DAA6D;AAC7D,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,CAAA;AAEpF;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAA;AAEhF,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAiB,OAAO;QAEtB;;;;;;WAMG;QACH,QAAQ,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QACxF,sFAAsF;QACtF,QAAQ,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QAC/H;;;;;WAKG;QACH,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;QAC3E,sFAAsF;QACtF,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;QAClH;;;;;;WAMG;QACH,MAAM,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACzG,sFAAsF;QACtF,MAAM,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAChJ;;;;;;WAMG;QACH,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5F,sFAAsF;QACtF,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QACnI;;;;;;;;;WASG;QACH,SAAS,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QACjG,sFAAsF;QACtF,SAAS,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QACxI;;;;;;;WAOG;QACH,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,MAAM,OAAO,CAAA;QACzG;;;;;;;WAOG;QACH,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,MAAM,OAAO,CAAA;KAE5G;CACF;AAED,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,8DAA8D;AAC9D,MAAM,WAAW,IAAK,SAAQ,YAAY;IACxC,GAAG,EAAE,OAAO,CAAA;IACZ,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;CAClC;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IAGZ,OAAO,CAAC,GAAG;IAFvB,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,CAAK;gBAElB,GAAG,EAAE,OAAO;IAwBhC;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,cA3Cd,GAAG,EAAE,KAAK,GAAG;IAuDjC;;;;;OAKG;IACG,QAAQ,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAM7B;;;;OAIG;IACH,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAInB;;;;;OAKG;IACG,MAAM,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAO3B;;;;;OAKG;IACH,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOnB;;;;;;;;;OASG;IACH,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAWxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI;IAQxF;;;;;;OAMG;IACH,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG;IAQvC;;;;;;;;;;OAUG;IACH,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,YAAY;IAgB3F;;;;;;;OAOG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,YAAY;CAOrF;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,MAAM;IACrB,qEAAqE;IACrE,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACrC,kFAAkF;IAClF,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAA;IAC3D;;;;OAIG;IACH,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,CAAA;IACjE,kEAAkE;IAClE,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAA;IACjE,gFAAgF;IAChF,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpH,oEAAoE;IACpE,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,CAAA;IAC9E,uEAAuE;IACvE,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,GAAG,OAAO,CAAA;IAClG,qFAAqF;IACrF,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACvF,sFAAsF;IACtF,mBAAmB,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI,CAAA;CACvF"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/fiber.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/fiber.d.ts new file mode 100644 index 0000000..3d656ed --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/fiber.d.ts @@ -0,0 +1,202 @@ +import type { Awaitable, Dict } from '@deepseek-ai/cosmokit'; +import { Context } from './context.ts'; +import type { Plugin } from './registry.ts'; +import { DisposableList } from './utils.ts'; +import type { Impl } from './reflect.ts'; +import type { StandardSchemaV1 } from '@standard-schema/spec'; +declare module './context.ts' { + interface Context extends Pick { + /** The fiber (plugin runtime instance) that owns this context. */ + fiber: Fiber; + } +} +/** Error raised when plugin configuration fails standard-schema validation. */ +export declare class ValidationError extends TypeError { + name: string; + /** + * Build the aggregated message from schema issues. + * + * @param issues — the standard-schema issues, one message line each. + */ + constructor(issues: readonly StandardSchemaV1.Issue[]); +} +/** + * Validate and normalize config for a plugin runtime before it starts. + * + * @param runtime — the plugin runtime whose `Config` schema to apply. + * @param config — the raw user config. + * @returns the validated config, or `config` unchanged if the runtime has no schema. + * @throws {ValidationError} when validation reports issues. + */ +export declare function resolveConfig(runtime: Plugin.Runtime, config: any): any; +interface AsyncDisposable = Awaitable> extends PromiseLike<() => T> { + (): T; +} +/** + * Function returned by an effect to release resources during disposal. + * + * Disposers run in reverse registration order when the owning fiber unloads; + * they may be async, in which case unloading awaits them. + */ +export type Disposable = () => T; +/** + * Effect body result accepted by `ctx.effect()` and plugin startup. + * + * Either a single disposer, a promise of one, or a (possibly async) iterable + * yielding several — generator effects register each yielded disposer as it + * is produced. + */ +export type Effect = SyncEffect | AsyncEffect; +type SyncEffect = Disposable | Iterable, void, void>; +type AsyncEffect = Promise> | AsyncIterable, void, void>; +/** Tree node used to expose nested effect labels for diagnostics. */ +export interface EffectMeta { + /** Human-readable effect label, e.g. `ctx.on("event")` or `ctx.provide("name")`. */ + label: string; + /** Metadata of nested effects registered while this effect ran. */ + children: EffectMeta[]; +} +/** + * Lifecycle state for one plugin fiber. + * + * `PENDING` — waiting for required services; `LOADING` — the plugin callback + * is running; `ACTIVE` — loaded and providing; `FAILED` — the callback or its + * config threw; `UNLOADING` — disposers are running; `DISPOSED` — the fiber + * was removed and cannot restart. + */ +export declare const enum FiberState { + PENDING = 0, + LOADING = 1, + ACTIVE = 2, + FAILED = 3, + DISPOSED = 4, + UNLOADING = 5 +} +/** Framework error with a stable machine-readable code. */ +export declare class CordisError extends Error { + code: CordisError.Code; + /** + * @param code — the stable error code; also the default message. + * @param message — optional human-readable override. + */ + constructor(code: CordisError.Code, message?: string); +} +/** Cordis error code definitions. */ +export declare namespace CordisError { + type Code = keyof typeof Code; + const Code: { + readonly INACTIVE_EFFECT: "cannot create effect on inactive context"; + }; +} +/** + * Runtime instance of one plugin application. + * + * A fiber tracks dependency state, validated config, lifecycle effects, and + * cleanup for the plugin context returned by `ctx.plugin()`. + */ +export declare class Fiber { + parent: Context; + inject: Dict; + runtime: Plugin.Runtime | null; + /** Unique id within the registry; 0 for the root fiber, `null` once disposed. */ + uid: number | null; + /** The context this fiber's plugin runs in (extends the parent context). */ + readonly ctx: Context; + /** The validated plugin config (updated by `update()`). */ + config: any; + /** The raw plugin config, re-resolved before each activation. */ + _config: any; + /** Current lifecycle state; transitions emit `internal/status`. */ + state: FiberState; + /** Dispose this fiber: unload the plugin, then settle once cleanup finished. */ + readonly dispose: () => Promise; + /** Snapshot of required service implementations while loaded; `undefined` otherwise. */ + store: Dict | undefined; + /** The in-flight load/unload transition, if one is currently running. */ + inertia: Promise | undefined; + readonly _hooks: Dict>; + readonly _disposables: DisposableList>; + protected context: Context; + private _error; + private _runner; + private _store; + /** + * Create a fiber. Plugin authors normally obtain fibers from `ctx.plugin()` + * rather than constructing them directly. + * + * @param parent — the context the plugin was loaded from. + * @param config — raw config, validated against the runtime's schema. + * @param inject — resolved dependency map (service name → intercept config). + * @param runtime — the shared plugin runtime, or `null` for the root fiber. + * @param getOuterStack — captures the caller stack for effect diagnostics. + */ + constructor(parent: Context, config: any, inject: Dict, runtime: Plugin.Runtime | null, getOuterStack: () => string[]); + /** The plugin's display name, inherited from the nearest named ancestor, else `'root'`. */ + get name(): string; + /** + * Throw if the fiber has already been disposed. + * + * @returns nothing when the fiber is still active. + * @throws {CordisError} `INACTIVE_EFFECT` when the fiber's uid has been cleared. + */ + assertActive(): void; + private _execute; + /** + * Register a cleanup-aware effect on this fiber. + * + * `execute` runs immediately; the disposers it produces are collected and + * run (in reverse order) either when the returned disposer is called or + * when the fiber unloads, whichever comes first. Calling the disposer twice + * is a no-op. Throws `CordisError('INACTIVE_EFFECT')` if the fiber is + * already disposed, and `TypeError` if `execute` returns an invalid shape. + * + * @param execute — the effect body; see {@link Effect} for accepted shapes. + * @param label — effect label shown in `getEffects()` diagnostics. + * @returns a disposer that tears the effect down and settles once done. + */ + effect(execute: () => SyncEffect, label?: string): Disposable>; + /** Same as above for async effects; the disposer is also awaitable. */ + effect(execute: () => Effect, label?: string): AsyncDisposable>; + /** + * Return metadata for currently registered effects. + * + * @returns one {@link EffectMeta} tree per labeled live effect. + */ + getEffects(): EffectMeta[]; + private _getState; + private _updateState; + _checkImpl(name: string): boolean | undefined; + _refresh(): void; + private _setEpoch; + private _resolveConfig; + private _reload; + private _unload; + /** + * Wait for current lifecycle work and rethrow startup errors. + * + * @returns this fiber, once it has settled into a stable state. + * @throws the config-validation or plugin-startup error, if any. + */ + await(): Promise; + /** + * Dispose and immediately reload this plugin with its current config. + * + * @returns a promise resolving once the reload settled. + * @throws {CordisError} `INACTIVE_EFFECT` when the fiber is already disposed. + */ + restart(): Promise; + /** + * Validate and apply new config, then restart the plugin. + * + * Runs the `internal/update` waterfall first, so update hooks (and HMR) + * can veto or replace the restart. + * + * @param config — the new raw config; validated before anything restarts. + * @param noSave — hint for persistence hooks not to write the change back. + * @returns the update waterfall result; the default restart returns a promise. + * @throws when validation, an update listener, or the restarted plugin fails. + */ + update(config: any, noSave?: boolean): void | Promise; +} +export {}; +//# sourceMappingURL=fiber.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/fiber.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/fiber.d.ts.map new file mode 100644 index 0000000..9da6072 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/fiber.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"fiber.d.ts","sourceRoot":"","sources":["../../src/fiber.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAiC,cAAc,EAAkD,MAAM,YAAY,CAAA;AAC1H,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAE7D,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAiB,OAAQ,SAAQ,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC;QACpD,kEAAkE;QAClE,KAAK,EAAE,KAAK,CAAA;KACb;CACF;AAID,+EAA+E;AAC/E,qBAAa,eAAgB,SAAQ,SAAS;IAC5C,IAAI,SAAoB;IAExB;;;;OAIG;gBACS,MAAM,EAAE,SAAS,gBAAgB,CAAC,KAAK,EAAE;CAStD;AAMD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAYjE;AAED,UAAU,eAAe,CAAC,CAAC,SAAS,SAAS,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAE,SAAQ,WAAW,CAAC,MAAM,CAAC,CAAC;IACjG,IAAI,CAAC,CAAA;CACN;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,GAAG,GAAG,IAAI,MAAM,CAAC,CAAA;AAEzC;;;;;;GAMG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,GAAG,GAAG,IACtB,UAAU,CAAC,CAAC,CAAC,GACb,WAAW,CAAC,CAAC,CAAC,CAAA;AAElB,KAAK,UAAU,CAAC,CAAC,GAAG,GAAG,IACnB,UAAU,CAAC,CAAC,CAAC,GACb,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;AAEvC,KAAK,WAAW,CAAC,CAAC,GAAG,GAAG,IACpB,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GACtB,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;AAE5C,qEAAqE;AACrE,MAAM,WAAW,UAAU;IACzB,oFAAoF;IACpF,KAAK,EAAE,MAAM,CAAA;IACb,mEAAmE;IACnE,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAsCD;;;;;;;GAOG;AACH,0BAAkB,UAAU;IAC1B,OAAO,IAAA;IACP,OAAO,IAAA;IACP,MAAM,IAAA;IACN,MAAM,IAAA;IACN,QAAQ,IAAA;IACR,SAAS,IAAA;CACV;AAED,2DAA2D;AAC3D,qBAAa,WAAY,SAAQ,KAAK;IAKjB,IAAI,EAAE,WAAW,CAAC,IAAI;IAJzC;;;OAGG;gBACgB,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,MAAM;CAG5D;AAED,qCAAqC;AACrC,yBAAiB,WAAW,CAAC;IAC3B,KAAY,IAAI,GAAG,MAAM,OAAO,IAAI,CAAA;IAE7B,MAAM,IAAI;;KAEP,CAAA;CACX;AAID;;;;;GAKG;AACH,qBAAa,KAAK;IAuCP,MAAM,EAAE,OAAO;IAEf,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI;IAzCvC,iFAAiF;IAC1E,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,4EAA4E;IAC5E,SAAgB,GAAG,EAAE,OAAO,CAAA;IAC5B,2DAA2D;IACpD,MAAM,EAAE,GAAG,CAAA;IAClB,iEAAiE;IAC1D,OAAO,EAAE,GAAG,CAAA;IACnB,mEAAmE;IAC5D,KAAK,aAAqB;IACjC,gFAAgF;IAChF,SAAgB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5C,wFAAwF;IACjF,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,CAAA;IACpC,yEAAyE;IAClE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAAA;IAEzC,SAAgB,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAsB;IAC5E,SAAgB,YAAY,kCAAmC;IAG/D,SAAS,CAAC,OAAO,EAAE,OAAO,CAAA;IAE1B,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,MAAM,CAAkC;IAEhD;;;;;;;;;OASG;gBAEM,MAAM,EAAE,OAAO,EACtB,MAAM,EAAE,GAAG,EACJ,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,EACrC,aAAa,EAAE,MAAM,MAAM,EAAE;IA4G/B,2FAA2F;IAC3F,IAAI,IAAI,WAOP;IAED;;;;;OAKG;IACH,YAAY;IAKZ,OAAO,CAAC,QAAQ;IA8ChB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,uEAAuE;IACvE,MAAM,CAAC,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAkJ7E;;;;OAIG;IACH,UAAU;IAMV,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,YAAY;IAgBpB,UAAU,CAAC,IAAI,EAAE,MAAM;IAcvB,QAAQ;IAcR,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,cAAc;YAKR,OAAO;YA6BP,OAAO;IAuBrB;;;;;OAKG;IACG,KAAK;IAQX;;;;;OAKG;IACG,OAAO;IAOb;;;;;;;;;;OAUG;IACH,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,UAAQ;CAkBnC"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/index.d.ts new file mode 100644 index 0000000..0cc8347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/index.d.ts @@ -0,0 +1,15 @@ +/** Core context type and root context implementation. */ +export * from './context.ts'; +/** Event bus, dispatch modes, and event augmentation types. */ +export * from './events.ts'; +/** Plugin fiber lifecycle, effects, and config validation helpers. */ +export * from './fiber.ts'; +/** Logger facade, logger service, message, exporter, and formatting types. */ +export * from './logger.ts'; +/** Plugin registry, dependency injection, and plugin entrypoint types. */ +export * from './registry.ts'; +/** Base service class and service lifecycle symbols. */ +export * from './service.ts'; +/** Shared internal helpers used by context, services, and plugin fibers. */ +export * from './utils.ts'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/index.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/index.d.ts.map new file mode 100644 index 0000000..dbb7b0a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,cAAc,cAAc,CAAA;AAC5B,+DAA+D;AAC/D,cAAc,aAAa,CAAA;AAC3B,sEAAsE;AACtE,cAAc,YAAY,CAAA;AAC1B,8EAA8E;AAC9E,cAAc,aAAa,CAAA;AAC3B,0EAA0E;AAC1E,cAAc,eAAe,CAAA;AAC7B,wDAAwD;AACxD,cAAc,cAAc,CAAA;AAC5B,4EAA4E;AAC5E,cAAc,YAAY,CAAA"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/logger.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/logger.d.ts new file mode 100644 index 0000000..4f4c977 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/logger.d.ts @@ -0,0 +1,105 @@ +import { Context } from './context.ts'; +import { Fiber } from './fiber.ts'; +import { symbols } from './utils.ts'; +declare module './context.ts' { + interface Intercept { + logger: LoggerService.Intercept; + } +} +/** Logger method name and severity category. */ +export type LoggerType = 'error' | 'info' | 'warn' | 'debug'; +/** Callable shape for one logger severity method. */ +export type LoggerMethod = (format: any, ...param: any[]) => void; +/** Formatter used to resolve a printf-style placeholder. */ +export type Formatter = (value: any, exporter: Exporter, message: Message) => any; +/** Numeric severity used when exporters decide whether to emit a message. */ +export declare const enum LoggerLevel { + ERROR = 0, + INFO = 1, + WARN = 2, + DEBUG = 3 +} +/** Structured log record delivered to exporters. */ +export interface Message { + sn: number; + ts: number; + name: string; + type: LoggerType; + level: number; + args: any[]; + fiber?: WeakRef; +} +/** Sink that receives structured log messages. */ +export interface Exporter { + colors?: number | false; + maxLength?: number; + levels?: Record; + formatters?: Record; + export(message: Message): void; +} +/** Built-in placeholder formatters used by `Logger.format()`. */ +export declare const defaultFormatters: Record; +/** Options used when creating a named logger facade. */ +export interface LoggerOptions { + /** The logger name shown with each message. */ + name: string; + /** Message fields merged into every record from this logger. */ + meta?: Partial; + /** Default maximum level exported when an exporter has no own threshold. */ + level?: number; +} +/** Logger facade identity, inherited message metadata, and optional minimum level. */ +export interface Logger extends LoggerOptions { +} +/** Logger facade severity methods. */ +export interface Logger extends Record { +} +/** Logger facade for one named subsystem. */ +export declare class Logger { + private service; + static color(exporter: Exporter, code: number, value: any, decoration?: string): string; + static code(name: string, level?: false | number): number; + static format(exporter: Exporter, message: Message): string; + constructor(options: LoggerOptions, service: LoggerService); + private _method; +} +/** ANSI 16-color palette indexes used for logger name coloring. */ +export declare const c16: number[]; +/** ANSI 256-color palette indexes used for logger name coloring. */ +export declare const c256: number[]; +/** Logger service configuration merged from context intercepts. */ +export declare namespace LoggerService { + interface Intercept { + name?: string; + level?: number; + } +} +/** Callable `ctx.logger` service shape. */ +export interface LoggerService extends Record { + (name?: string): Logger; +} +/** + * Built-in logging service. + * + * Call `ctx.logger()` to create a named logger, or call `ctx.logger.info()` + * directly to log with the current fiber-derived name. + */ +export declare class LoggerService { + bufferSize: number; + buffer: Message[]; + ctx: Context; + _snMessage: number; + _snExporter: number; + exporters: Map; + constructor(ctx: Context); + /** + * Register an exporter and dispose it with the current fiber. + * + * @param exporter — the sink that receives structured log messages. + * @returns a disposer that removes the exporter. + */ + exporter(exporter: Exporter): import("./fiber.ts").Disposable>; + private _resolveConfig; + [symbols.invoke](name?: string): Logger; +} +//# sourceMappingURL=logger.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/logger.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/logger.d.ts.map new file mode 100644 index 0000000..45d2652 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/logger.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAiC,OAAO,EAAgB,MAAM,YAAY,CAAA;AAEjF,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,SAAS;QACjB,MAAM,EAAE,aAAa,CAAC,SAAS,CAAA;KAChC;CACF;AAED,gDAAgD;AAChD,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAE5D,qDAAqD;AACrD,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;AAEjE,4DAA4D;AAC5D,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,KAAK,GAAG,CAAA;AAEjF,6EAA6E;AAC7E,0BAAkB,WAAW;IAC3B,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACV;AAED,oDAAoD;AACpD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,GAAG,EAAE,CAAA;IACX,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;CACvB;AAED,kDAAkD;AAClD,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACtC,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;CAC/B;AAED,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAWvD,CAAA;AAED,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAA;IACZ,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;IACvB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,sFAAsF;AACtF,MAAM,WAAW,MAAO,SAAQ,aAAa;CAAG;AAChD,sCAAsC;AACtC,MAAM,WAAW,MAAO,SAAQ,MAAM,CAAC,UAAU,EAAE,YAAY,CAAC;CAAG;AAMnE,6CAA6C;AAC7C,qBAAa,MAAM;IAkDmB,OAAO,CAAC,OAAO;IAjDnD,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,SAAK;IAK1E,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM;IAUhD,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM;gBAkC/C,OAAO,EAAE,aAAa,EAAU,OAAO,EAAE,aAAa;IAQlE,OAAO,CAAC,OAAO;CAqBhB;AAED,mEAAmE;AACnE,eAAO,MAAM,GAAG,UAAqB,CAAA;AACrC,oEAAoE;AACpE,eAAO,MAAM,IAAI,UAMhB,CAAA;AAED,mEAAmE;AACnE,yBAAiB,aAAa,CAAC;IAC7B,UAAiB,SAAS;QACxB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,KAAK,CAAC,EAAE,MAAM,CAAA;KACf;CACF;AAED,2CAA2C;AAC3C,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,UAAU,EAAE,YAAY,CAAC;IACrE,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CACxB;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,UAAU,SAAO;IACjB,MAAM,EAAE,OAAO,EAAE,CAAK;IACtB,GAAG,EAAG,OAAO,CAAA;IAEb,UAAU,SAAI;IACd,WAAW,SAAI;IACf,SAAS,wBAA8B;gBAE3B,GAAG,EAAE,OAAO;IAuBxB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ;IAO3B,OAAO,CAAC,cAAc;IAYtB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;CAmBxC"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/reflect.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/reflect.d.ts new file mode 100644 index 0000000..acbd2a9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/reflect.d.ts @@ -0,0 +1,186 @@ +import type { Dict } from '@deepseek-ai/cosmokit'; +import { Context } from './context.ts'; +import { Fiber } from './fiber.ts'; +declare module './context.ts' { + interface Context { + /** + * Read a service from the store without the inject requirement. + * + * @param name — the service name. + * @param strict — when `true` (default), only return implementations + * whose providing fiber is currently active. + * @returns the service value, or `undefined` when not (yet) provided. + */ + get(name: K, strict?: boolean): undefined | this[K]; + /** Same as above for service names outside the typed `Context` surface. */ + get(name: string, strict?: boolean): any; + /** + * Overwrite a provided service's value. + * + * Only the fiber that provided the service may set it; setting an + * unprovided name throws. + * + * @param name — the service name. + * @param value — the new service value. + */ + set(name: K, value: undefined | this[K]): void; + /** Same as above for service names outside the typed `Context` surface. */ + set(name: string, value: any): void; + /** + * Register a service implementation owned by the current fiber. + * + * The service becomes visible to dependents in the same isolation scope + * once the fiber is active; it is unregistered (waking dependents) when + * the returned disposer runs or the fiber unloads. Throws if the name is + * already provided in this scope or declared as an accessor. + * + * @param name — the service name. + * @param value — the service value. + * @returns a disposer that unregisters the service. + */ + provide(name: K, value: undefined | this[K]): () => void; + /** Same as above for service names outside the typed `Context` surface. */ + provide(name: string, value?: any): () => void; + /** + * Define a computed context property backed by get/set hooks. + * + * The accessor is removed when the current fiber unloads. Throws if the + * name is already declared. + * + * @param name — the context property name. + * @param options — the `get` hook and optional `set` hook. + */ + accessor(name: string, options: Omit): void; + /** + * Expose selected members of a service directly on `ctx`. + * + * Each mixed-in key becomes an accessor that forwards to the service + * (binding methods to it), so e.g. `ctx.on` forwards to `ctx.events.on`. + * Mixins are removed when the current fiber unloads. + * + * @param name — the context property holding the source service. + * @param mixins — keys to forward, or a source-key → ctx-key map. + */ + mixin(name: K, mixins: (keyof this & keyof this[K])[] | Dict): void; + /** Same as above with a source object instead of a context property name. */ + mixin(source: T, mixins: (keyof this & keyof T)[] | Dict): void; + } +} +/** Context property definition known by the reflection service. */ +export type Property = Property.Service | Property.Accessor; +/** Property definition variants understood by `ReflectService`. */ +export declare namespace Property { + /** Service property backed by a provided implementation. */ + interface Service { + /** Discriminator. */ + type: 'service'; + } + /** Computed context property backed by custom get/set hooks. */ + interface Accessor { + /** Discriminator. */ + type: 'accessor'; + /** Compute the property value; `error` carries the caller stack for diagnostics. */ + get: (this: Context, receiver: any, error: Error) => any; + /** Optional setter; return `false` to reject the write. */ + set?: (this: Context, value: any, receiver: any, error: Error) => boolean; + } +} +/** Concrete service implementation record stored in the root reflect service. */ +export interface Impl { + /** The service name. */ + name: string; + /** The fiber that provided the service (owns its lifetime). */ + fiber: Fiber; + /** The current service value. */ + value?: any; + /** Optional availability predicate consulted before dependents may load. */ + check?: () => boolean; +} +/** + * Reflection and service-resolution layer installed as `ctx.reflect`. + * + * This service powers the context proxy, service registration, accessors, and + * the mixins that expose core service methods directly on `ctx`. + */ +export declare class ReflectService { + ctx: Context; + /** Proxy traps implementing service resolution for every context object. */ + static handler: ProxyHandler; + /** Service implementations, keyed by isolation label. */ + store: Dict; + /** Declared context properties (services and accessors), by name. */ + props: Dict; + constructor(ctx: Context); + /** + * Read a service from the store without the inject requirement. + * + * @param name — the service name. + * @param strict — when `true`, only return implementations whose providing + * fiber is currently active. + * @returns the service value, or `undefined` when not (yet) provided. + */ + get(name: string, strict?: boolean): any; + _getImpl(name: string, strict?: boolean): Impl | undefined; + /** + * Overwrite a provided service's value. + * + * @param name — the service name. + * @param value — the new service value. + * @param error — carrier for the caller stack in diagnostics. + * @returns `true` on success. + * @throws when `name` was never provided, or was provided by another fiber. + */ + set(name: string, value: any, error?: Error): boolean; + /** + * Register a service implementation owned by the current fiber. + * + * See the `ctx.provide()` overload above for the full contract. + * + * @param name — the service name. + * @param value — the service value. + * @param check — optional availability predicate for dependents. + * @returns a disposer that unregisters the service. + */ + provide(name: string, value?: any, check?: () => boolean): import("./fiber.ts").Disposable>; + /** + * Re-evaluate every fiber that requires one of the given services. + * + * @param names — the service names that changed. + * @param filter — restricts notification to matching isolation scopes. + * @returns the fibers whose dependency state was refreshed. + */ + notify(names: string[], filter?: (ctx: Context, name: string) => boolean): Fiber[]; + /** + * Define a computed context property backed by get/set hooks. + * + * @param name — the context property name. + * @param options — the `get` hook and optional `set` hook. + * @returns a disposer that removes the accessor. + */ + accessor(name: string, options: Omit): import("./fiber.ts").Disposable>; + /** + * Expose selected members of a service directly on `ctx`. + * + * See the `ctx.mixin()` overload above for the full contract. + * + * @param source — a context property name or a source object. + * @param mixins — keys to forward, or a source-key → ctx-key map. + * @returns a disposer that removes all created accessors. + */ + mixin(source: any, mixins: string[] | Dict): import("./fiber.ts").Disposable>; + /** + * Attach this context's tracing wrapper to a value. + * + * @param value — the value to wrap. + * @returns the traceable wrapper (or the value itself when not applicable). + */ + trace(value: T): T; + /** + * Wrap a callback so calls trace `this` and arguments to this context. + * + * @param callback — the function to wrap. + * @returns a proxy delegating to `callback` with traced values. + */ + bind(callback: T): T; +} +//# sourceMappingURL=reflect.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/reflect.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/reflect.d.ts.map new file mode 100644 index 0000000..575e8cd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/reflect.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"reflect.d.ts","sourceRoot":"","sources":["../../src/reflect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,OAAO,EAAE,KAAK,EAAc,MAAM,YAAY,CAAA;AAE9C,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,OAAO;QACf;;;;;;;WAOG;QACH,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QAClF,2EAA2E;QAC3E,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,GAAG,CAAA;QACxC;;;;;;;;WAQG;QACH,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;QAC7E,2EAA2E;QAC3E,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAA;QACnC;;;;;;;;;;;WAWG;QACH,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAA;QACvF,2EAA2E;QAC3E,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,MAAM,IAAI,CAAA;QAC9C;;;;;;;;WAQG;QACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;QACtE;;;;;;;;;WASG;QACH,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;QAC1G,6EAA6E;QAC7E,KAAK,CAAC,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;KACtF;CACF;AAsBD,mEAAmE;AACnE,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAA;AAE3D,mEAAmE;AACnE,yBAAiB,QAAQ,CAAC;IACxB,4DAA4D;IAC5D,UAAiB,OAAO;QACtB,qBAAqB;QACrB,IAAI,EAAE,SAAS,CAAA;KAChB;IAED,gEAAgE;IAChE,UAAiB,QAAQ;QACvB,qBAAqB;QACrB,IAAI,EAAE,UAAU,CAAA;QAChB,oFAAoF;QACpF,GAAG,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,KAAK,GAAG,CAAA;QACxD,2DAA2D;QAC3D,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;KAC1E;CACF;AAED,iFAAiF;AACjF,MAAM,WAAW,IAAI;IACnB,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,+DAA+D;IAC/D,KAAK,EAAE,KAAK,CAAA;IACZ,iCAAiC;IACjC,KAAK,CAAC,EAAE,GAAG,CAAA;IACX,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,OAAO,CAAA;CACtB;AAED;;;;;GAKG;AACH,qBAAa,cAAc;IAgFN,GAAG,EAAE,OAAO;IA/E/B,4EAA4E;IAC5E,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAuEpC;IAED,yDAAyD;IAClD,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAsB;IACtD,qEAAqE;IAC9D,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAsB;gBAE/B,GAAG,EAAE,OAAO;IAY/B;;;;;;;OAOG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,UAAO;IAI/B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,UAAO;IAQpC;;;;;;;;OAQG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,KAAK;IAa3C;;;;;;;;;OASG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,OAAO;IA8BxD;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,IAAI,KAAK,OAAO,EAAE,MAAM,MAAM,YAAmE;IAwB/H;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAU/D;;;;;;;;OAQG;IACH,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;IA4BlD;;;;;OAKG;IACH,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;IAIjB;;;;;OAKG;IACH,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,QAAQ,EAAE,CAAC;CAUrC"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/registry.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/registry.d.ts new file mode 100644 index 0000000..2de394d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/registry.d.ts @@ -0,0 +1,201 @@ +import type { Dict } from '@deepseek-ai/cosmokit'; +import type { StandardSchemaV1 } from '@standard-schema/spec'; +import { Context } from './context.ts'; +import { Fiber } from './fiber.ts'; +import { DisposableList, symbols } from './utils.ts'; +/** + * Service dependency declaration accepted by plugins and the `@Inject` + * decorator. + * + * Array form requests services without intercept config. Object form maps each + * service name to optional intercept config for the plugin context. + */ +export type Inject = (keyof M)[] | { + [K in keyof M]?: M[K]; +}; +/** Context keys that correspond to services with typed intercept config. */ +export type InjectKey = keyof { + [K in keyof Context & string as Context[K] extends { + [symbols.config]: any; + } ? K : never]: any; +}; +/** + * Decorator for declaring service dependencies on classes or class methods. + * + * On classes it contributes to the plugin's static `inject` map. On methods it + * delays the method call until the declared services are available. + */ +/** + * @param name — the required service name. + * @param config — optional intercept config applied for that service. + * @returns the class or method decorator. + */ +export declare function Inject(name: K, config?: Context[K] extends { + [symbols.config]: infer T; +} ? T : never): (value: any, decorator: ClassDecoratorContext | ClassMethodDecoratorContext) => void; +/** Utilities for normalizing plugin dependency declarations. */ +export declare namespace Inject { + /** + * Convert array/object/class-inherited inject metadata into a plain map. + * + * @param inject — the declaration to normalize; `null`/`undefined` add nothing. + * @param result — the map to fill (service name → intercept config or `null`). + * @returns `result`. + */ + function resolve(inject: Inject | null | undefined, result?: Dict): Dict; +} +/** Supported plugin entrypoint shapes. */ +export type Plugin = Plugin.Function | Plugin.Constructor | Plugin.Object; +/** Types associated with plugin entrypoints and runtime records. */ +export declare namespace Plugin { + /** Shared metadata understood by the plugin registry and related tooling. */ + interface Base { + /** Display name used for fiber diagnostics and logger names. */ + name?: string; + /** Standard-schema validator applied to config before the plugin starts. */ + Config?: StandardSchemaV1; + /** Services the plugin requires; it only loads while all are available. */ + inject?: Inject; + /** Service name(s) the plugin provides (read by `Service` and by loaders). */ + provide?: string | string[]; + /** Service names whose intercept config the plugin declares it consumes. */ + intercept?: Dict; + } + interface Transform { + /** Marks the transform object as a schema/config transform. */ + schema?: true; + /** Convert user-facing config to runtime config. */ + Config: (config: S) => T; + } + /** Function plugin called with `(ctx, config)`. */ + interface Function extends Base { + (ctx: Context, config: T): any; + } + /** Class plugin constructed with `(ctx, config)`. */ + interface Constructor extends Base { + new (ctx: Context, config: T): any; + } + /** Object plugin with an `apply(ctx, config)` method. */ + interface Object extends Base { + apply(ctx: Context, config: T): any; + } + /** Mutable registry record shared by all fibers of one plugin callback. */ + interface Runtime { + /** Display name copied from the first registered plugin shape. */ + name?: string; + /** Every live fiber of this plugin (one per `ctx.plugin()` call). */ + fibers: DisposableList; + /** The executable entrypoint all fibers share (registry identity key). */ + callback: globalThis.Function; + /** Standard-schema validator applied to each fiber's config. */ + Config?: StandardSchemaV1; + } +} +type Spread = undefined extends T ? [config?: T] : [config: T]; +type GetPluginParameters

= P extends (ctx: Context, ...args: infer R) => any ? R : P extends new (ctx: Context, ...args: infer R) => any ? R : P extends { + apply(ctx: Context, ...args: infer R): any; +} ? R : never; +type GetPluginConfig

= P extends Plugin.Transform ? S : GetPluginParameters

[0]; +declare module './context.ts' { + interface Context { + /** + * Run a callback once the requested services are available. + * + * Shorthand for `ctx.plugin({ inject, apply: callback })`: the callback + * is unloaded and re-run whenever a required service changes. + * + * @param deps — required services, as an array or a name → config map. + * @param callback — plugin body called with `(ctx, config)`. + * @returns the fiber; awaiting it settles once loading finished. + */ + inject(deps: Inject, callback: Plugin.Function): Fiber & PromiseLike; + /** + * Load a plugin in the current context. + * + * @param plugin — a function, class, or `{ apply }` object plugin. + * @param args — the plugin config, validated against its `Config` schema. + * @returns the fiber; awaiting it settles once loading finished + * (rejecting on config or startup errors). + */ + plugin

(plugin: P, ...args: Spread>): Fiber & PromiseLike; + } +} +/** + * Plugin registry installed as `ctx.registry` and mixed into every context. + * + * It normalizes plugin shapes, tracks plugin runtimes, starts fibers, and + * exposes map-like inspection over active plugin callbacks. + */ +export declare class RegistryService { + ctx: Context; + private _counter; + private _internal; + constructor(ctx: Context); + /** Allocate the next fiber uid (increments on every read). */ + get counter(): number; + /** Number of registered plugin runtimes. */ + get size(): number; + /** + * Resolve a supported plugin shape to its executable callback. + * + * @param plugin — a function, class, or `{ apply }` object plugin. + * @returns the callback identifying the plugin, or `undefined` if invalid. + */ + resolve(plugin: Plugin): Function | undefined; + /** + * Look up the runtime record for a plugin. + * + * @param plugin — any supported plugin shape. + * @returns the runtime, or `undefined` when the plugin is not registered. + */ + get(plugin: Plugin): Plugin.Runtime | undefined; + /** + * Check whether a plugin has a registered runtime. + * + * @param plugin — any supported plugin shape. + * @returns `true` when at least one fiber of the plugin exists. + */ + has(plugin: Plugin): boolean; + /** + * Dispose every running fiber for a plugin and remove its runtime record. + * + * @param plugin — any supported plugin shape. + * @returns the removed runtime, or `undefined` when none was registered. + */ + delete(plugin: Plugin): Plugin.Runtime | undefined; + /** Iterate the registered plugin callbacks. */ + keys(): MapIterator; + /** Iterate the registered plugin runtimes. */ + values(): MapIterator; + /** Iterate `[callback, runtime]` pairs. */ + entries(): MapIterator<[Function, Plugin.Runtime]>; + /** + * Visit every registered runtime. + * + * @param callback — receives each runtime and its identifying callback. + */ + forEach(callback: (value: Plugin.Runtime, key: Function) => void): void; + /** + * Start a callback once the requested dependencies are available. + * + * @param inject — required services, as an array or a name → config map. + * @param callback — plugin body called with `(ctx, config)`. + * @returns the fiber; awaiting it settles once loading finished. + */ + inject(inject: Inject, callback: Plugin.Function): Fiber & PromiseLike; + /** + * Start a plugin in the current context and return its fiber. + * + * Creates (or reuses) the plugin's runtime record, then starts a new fiber + * under the current context. Throws if `plugin` is not a supported shape or + * if the current fiber is already disposed. + * + * @param plugin — a function, class, or `{ apply }` object plugin. + * @param config — the plugin config, validated against its `Config` schema. + * @param getOuterStack — captures the caller stack for effect diagnostics. + * @returns the fiber; awaiting it settles once loading finished. + */ + plugin(plugin: Plugin, config?: any, getOuterStack?: () => string[]): Fiber & PromiseLike; +} +export {}; +//# sourceMappingURL=registry.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/registry.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/registry.d.ts.map new file mode 100644 index 0000000..d99347e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/registry.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAmB,cAAc,EAAE,OAAO,EAAa,MAAM,YAAY,CAAA;AAMhF;;;;;;GAMG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;CAAE,CAAA;AAEtE,4EAA4E;AAC5E,MAAM,MAAM,SAAS,GAAG,MAAM;KAC3B,CAAC,IAAI,MAAM,OAAO,GAAG,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,SAAS;QAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK,GAAG,GAAG;CAC/F,CAAA;AAED;;;;;GAKG;AACH;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS;IAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,KAAK,IACvG,OAAO,GAAG,EAAE,WAAW,qBAAqB,CAAC,GAAG,CAAC,GAAG,2BAA2B,CAAC,GAAG,CAAC,UAsBtG;AAED,gEAAgE;AAChE,yBAAiB,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,SAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,MAAM,GAAE,IAA0B,QAiB5F;CACF;AAED,0CAA0C;AAC1C,MAAM,MAAM,MAAM,CAAC,CAAC,GAAG,GAAG,IACtB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAClB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,GACrB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;AAEpB,oEAAoE;AACpE,yBAAiB,MAAM,CAAC;IACtB,6EAA6E;IAC7E,UAAiB,IAAI,CAAC,CAAC,GAAG,GAAG;QAC3B,gEAAgE;QAChE,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,4EAA4E;QAC5E,MAAM,CAAC,EAAE,gBAAgB,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACjC,2EAA2E;QAC3E,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,8EAA8E;QAC9E,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;QAC3B,4EAA4E;QAC5E,SAAS,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;KAC1B;IAED,UAAiB,SAAS,CAAC,CAAC,EAAE,CAAC;QAC7B,+DAA+D;QAC/D,MAAM,CAAC,EAAE,IAAI,CAAA;QACb,oDAAoD;QACpD,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAA;KACzB;IAED,mDAAmD;IACnD,UAAiB,QAAQ,CAAC,CAAC,GAAG,GAAG,CAAE,SAAQ,IAAI,CAAC,CAAC,CAAC;QAChD,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,GAAG,CAAA;KAC/B;IAED,qDAAqD;IACrD,UAAiB,WAAW,CAAC,CAAC,GAAG,GAAG,CAAE,SAAQ,IAAI,CAAC,CAAC,CAAC;QACnD,KAAK,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,GAAG,CAAA;KACnC;IAED,yDAAyD;IACzD,UAAiB,MAAM,CAAC,CAAC,GAAG,GAAG,CAAE,SAAQ,IAAI,CAAC,CAAC,CAAC;QAC9C,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,GAAG,CAAA;KACpC;IAED,2EAA2E;IAC3E,UAAiB,OAAO;QACtB,kEAAkE;QAClE,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,qEAAqE;QACrE,MAAM,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;QAC7B,0EAA0E;QAC1E,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAA;QAC7B,gEAAgE;QAChE,MAAM,CAAC,EAAE,gBAAgB,CAAA;KAC1B;CACF;AAED,KAAK,MAAM,CAAC,CAAC,IAAI,SAAS,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;AAEjE,KAAK,mBAAmB,CAAC,CAAC,IACtB,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GACjD,CAAC,GACD,CAAC,SAAS,KAAK,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GACrD,CAAC,GACD,CAAC,SAAS;IAAE,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,GAAG,GAAG,CAAA;CAAE,GACxD,CAAC,GACD,KAAK,CAAA;AAET,KAAK,eAAe,CAAC,CAAC,IAClB,CAAC,SAAS,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,GACxC,CAAC,GACD,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAE7B,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAiB,OAAO;QACtB;;;;;;;;;WASG;QACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;QACjF;;;;;;;WAOG;QACH,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;KACrG;CACF;AAED;;;;;GAKG;AACH,qBAAa,eAAe;IAIP,GAAG,EAAE,OAAO;IAH/B,OAAO,CAAC,QAAQ,CAAI;IACpB,OAAO,CAAC,SAAS,CAAsC;gBAEpC,GAAG,EAAE,OAAO;IAO/B,8DAA8D;IAC9D,IAAI,OAAO,WAEV;IAED,4CAA4C;IAC5C,IAAI,IAAI,WAEP;IAED;;;;;OAKG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAQ7C;;;;;OAKG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM;IAKlB;;;;;OAKG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM;IAKlB;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM;IAWrB,+CAA+C;IAC/C,IAAI;IAIJ,8CAA8C;IAC9C,MAAM;IAIN,2CAA2C;IAC3C,OAAO;IAIP;;;;OAIG;IACH,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,IAAI;IAIhE;;;;;;OAMG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;IAItD;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,aAAa,iBAAoB;CAqBvE"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/service.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/service.d.ts new file mode 100644 index 0000000..6d0b1f4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/service.d.ts @@ -0,0 +1,55 @@ +import { Context } from './context.ts'; +import { symbols } from './utils.ts'; +/** + * Base class for services that expose a named API on `ctx`. + * + * Subclasses call `super(ctx, name)` from their constructor. The service is + * registered immediately and is automatically removed with the owning fiber. + */ +export declare abstract class Service { + protected ctx: Context; + /** Symbol key of an instance method run after construction (class plugins). */ + static readonly init: unique symbol; + /** Symbol key of the availability predicate passed to `ctx.provide()`. */ + static readonly check: unique symbol; + /** Symbol key of the phantom intercept-config type parameter. */ + static readonly config: unique symbol; + /** Symbol key of the call body making a service callable (e.g. `ctx.logger()`). */ + static readonly invoke: unique symbol; + /** Symbol key of the helper deriving an extended service instance. */ + static readonly extend: unique symbol; + /** Symbol key of the tracker metadata used for context tracing. */ + static readonly tracker: unique symbol; + /** Symbol key of the intercept-config resolution helper below. */ + static readonly resolveConfig: unique symbol; + [symbols.config]: T; + /** The service name this instance is registered under. */ + name: string; + /** + * Register this instance as `name` in the current context. + * + * Calls `ctx.reflect.provide(name, this, this[Service.check])`, so the + * service is unregistered automatically when the owning fiber unloads. + * Services with a `[Service.invoke]` body return a callable instance. + * + * @param ctx — the context to register in (stored as `this.ctx`). + * @param name — the service name; defaults to the static `provide` field. + */ + constructor(ctx: Context, name: string); + protected [symbols.filter](ctx: Context): boolean; + protected [symbols.extend](props?: any): any; + /** + * Merge intercept config from ancestors with optional base and head values. + * + * Entries added closer to the root apply first; `base` is prepended and + * `head` appended. Uses `Config.merge` when the service declares one, + * otherwise a shallow `Object.assign`. + * + * @param base — lowest-precedence config merged before all intercepts. + * @param head — highest-precedence config merged after all intercepts. + * @returns the merged config. + */ + [symbols.resolveConfig](base?: T, head?: T): T; + static [Symbol.hasInstance](instance: any): boolean; +} +//# sourceMappingURL=service.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/service.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/service.d.ts.map new file mode 100644 index 0000000..ae498ab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/service.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAiC,OAAO,EAAgB,MAAM,YAAY,CAAA;AAEjF;;;;;GAKG;AACH,8BAAsB,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK;IA+B7B,SAAS,CAAC,GAAG,EAAE,OAAO;IA9BlC,+EAA+E;IAC/E,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,MAAM,CAAe;IAClD,0EAA0E;IAC1E,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,MAAM,CAAgB;IACpD,iEAAiE;IACjE,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,MAAM,CAAiB;IACtD,mFAAmF;IACnF,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,MAAM,CAAiB;IACtD,sEAAsE;IACtE,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,MAAM,CAAiB;IACtD,mEAAmE;IACnE,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,MAAM,CAAkB;IACxD,kEAAkE;IAClE,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,MAAM,CAAwB;IAE5D,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAE3B,0DAA0D;IACnD,IAAI,EAAG,MAAM,CAAA;IAEpB;;;;;;;;;OASG;gBACmB,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM;IAmBhD,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,OAAO;IAIvC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG;IAUtC;;;;;;;;;;OAUG;IACH,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;IAkB9C,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,GAAG;CAW1C"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/utils.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/utils.d.ts new file mode 100644 index 0000000..be94e20 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/utils.d.ts @@ -0,0 +1,62 @@ +import type { Context, Service } from './index.ts'; +/** Ordered collection of disposable values with O(1) deletion by value. */ +export declare class DisposableList { + private sn; + private map; + private weak; + get length(): number; + push(value: T): () => boolean; + delete(value: T): boolean; + clear(): T[]; + [Symbol.iterator](): MapIterator; +} +/** Metadata used by traceable proxies to rebind `ctx` and associated services. */ +export interface Tracker { + associate?: string; + property?: string; + noShadow?: boolean; +} +/** Shared symbols used to avoid public property-name collisions. */ +export declare const symbols: { + shadow: symbol; + receiver: symbol; + original: symbol; + metadata: symbol; + initHooks: symbol; + checkProto: symbol; + effect: typeof Context.effect; + filter: typeof Context.filter; + isolate: typeof Context.isolate; + intercept: typeof Context.intercept; + init: typeof Service.init; + check: typeof Service.check; + config: typeof Service.config; + invoke: typeof Service.invoke; + extend: typeof Service.extend; + tracker: typeof Service.tracker; + resolveConfig: typeof Service.resolveConfig; +}; +/** Return true when a plugin callback should be constructed with `new`. */ +export declare function isConstructor(func: any): func is new (...args: any) => any; +/** Merge two prototype chains while preserving descriptors from `proto1`. */ +export declare function joinPrototype(proto1: {}, proto2: {}): any; +/** Return true for non-null objects and functions. */ +export declare function isObject(value: any): value is {}; +/** Find a property descriptor by walking an object's prototype chain. */ +export declare function getPropertyDescriptor(target: any, prop: string | symbol): TypedPropertyDescriptor | undefined; +/** Wrap services/functions so method calls see the caller's active context. */ +export declare function getTraceable(ctx: Context, value: T): T; +/** Return a proxy that overlays readonly or writable properties onto a target. */ +export declare function withProps(target: any, props?: {}): any; +/** Create a callable service object that dispatches through `symbols.invoke`. */ +export declare function createCallable(name: string, proto: {}, tracker: Tracker): any; +interface StackInfo { + offset: number; + error: Error; +} +/** Run a callback and splice outer call-site frames into thrown async errors. */ +export declare function composeError(callback: (info: StackInfo) => T, getOuterStack?: () => string[]): T; +/** Capture a lazy stack-frame supplier for later error composition. */ +export declare function buildOuterStack(offset?: number): () => string[]; +export {}; +//# sourceMappingURL=utils.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/utils.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/utils.d.ts.map new file mode 100644 index 0000000..c5e65f1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/lib/types/utils.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAElD,2EAA2E;AAC3E,qBAAa,cAAc,CAAC,CAAC,SAAS,OAAO;IAC3C,OAAO,CAAC,EAAE,CAAI;IACd,OAAO,CAAC,GAAG,CAAuB;IAClC,OAAO,CAAC,IAAI,CAA2B;IAEvC,IAAI,MAAM,WAET;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;IAOb,MAAM,CAAC,KAAK,EAAE,CAAC;IAMf,KAAK;IAML,CAAC,MAAM,CAAC,QAAQ,CAAC;CAOlB;AAED,kFAAkF;AAClF,MAAM,WAAW,OAAO;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,oEAAoE;AACpE,eAAO,MAAM,OAAO;;;;;;;YAUqB,OAAO,OAAO,CAAC,MAAM;YACrB,OAAO,OAAO,CAAC,MAAM;aACnB,OAAO,OAAO,CAAC,OAAO;eAClB,OAAO,OAAO,CAAC,SAAS;UAGlC,OAAO,OAAO,CAAC,IAAI;WACjB,OAAO,OAAO,CAAC,KAAK;YAClB,OAAO,OAAO,CAAC,MAAM;YACrB,OAAO,OAAO,CAAC,MAAM;YACrB,OAAO,OAAO,CAAC,MAAM;aACnB,OAAO,OAAO,CAAC,OAAO;mBACV,OAAO,OAAO,CAAC,aAAa;CAClF,CAAA;AAKD,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAU1E;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,OAOnD;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,EAAE,CAEhD;AAED,yEAAyE;AACzE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,4CAOvE;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAQzD;AAED,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,OAYhD;AAqFD,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,OAOvE;AAED,UAAU,SAAS;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,KAAK,CAAA;CACb;AA6BD,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,CAAC,EAAE,aAAa,iBAAoB,GAAG,CAAC,CAatG;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,MAAM,SAAI,kBAGzC"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules/.bin/cordis new file mode 100755 index 0000000..a337f87 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../bin.js" "$@" +else + exec node "$basedir/../../bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/package.json new file mode 100644 index 0000000..740c70c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/package.json @@ -0,0 +1,53 @@ +{ + "name": "@deepseek-ai/cordis", + "description": "Meta-Framework for Modern JavaScript Applications", + "version": "4.0.1", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "vendor/cordis" + }, + "sideEffects": false, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/types/**/*.d.ts", + "lib/types/**/*.d.ts.map", + "bin.js", + "src" + ], + "author": "Shigma ", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/cordis-plugin-include": "^1.0.6" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-include": { + "optional": true + }, + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } + }, + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@deepseek-ai/cosmokit": "^1.8.2" + }, + "bin": { + "cordis": "bin.js" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/context.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/context.ts new file mode 100644 index 0000000..0488423 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/context.ts @@ -0,0 +1,146 @@ +import type { Dict } from '@deepseek-ai/cosmokit' +import { EventsService } from './events.ts' +import { LoggerService } from './logger.ts' +import { ReflectService } from './reflect.ts' +import { RegistryService, type InjectKey } from './registry.ts' +import { getTraceable, symbols } from './utils.ts' +import { Fiber } from './fiber.ts' + +/** + * Public shape of a Cordis context. + * + * The concrete `Context` class is proxied at runtime, so this interface is + * augmented by core services and plugins to describe the properties that may + * be read from `ctx`. + */ +export interface Context { + /** Isolation map: service name → scope label. Lookups for a name resolve within its label. */ + [symbols.isolate]: Dict + /** Intercept map: service name → config merged into that service's per-plugin config. */ + [symbols.intercept]: Dict + /** The root context of the application (every child context shares it). @experimental */ + root: this + /** Base URL used to resolve relative plugin/module specifiers, if the runtime sets one. */ + baseUrl?: string + /** The event bus. Its methods are also mixed onto `ctx` (`ctx.on`, `ctx.emit`, ...). */ + events: EventsService + /** The logging service. Call `ctx.logger(name)` for a named logger. */ + logger: LoggerService + /** The reflection layer backing the context proxy (`ctx.get`, `ctx.provide`, ...). */ + reflect: ReflectService + /** The plugin registry. Its methods are mixed onto `ctx` (`ctx.plugin`, `ctx.inject`). */ + registry: RegistryService +} + +/** + * Root and child dependency containers for Cordis plugins. + * + * A context is a proxy: normal property reads go through the service resolver, + * while `extend()`, `isolate()`, and `intercept()` create scoped child + * contexts without mutating their parent. + */ +export class Context { + /** Symbol key under which a disposer exposes its {@link EffectMeta} diagnostics tree. */ + static readonly effect: unique symbol = symbols.effect + /** Symbol key for a context's listener filter, consulted on every event dispatch. */ + static readonly filter: unique symbol = symbols.filter + /** Symbol key of the isolation map (see the `Context[symbols.isolate]` property). */ + static readonly isolate: unique symbol = symbols.isolate + /** Symbol key of the intercept map (see the `Context[symbols.intercept]` property). */ + static readonly intercept: unique symbol = symbols.intercept + + /** + * Returns true for Cordis context proxies and context prototypes. + * + * Works across realms and across multiple copies of cordis, because the + * brand is keyed by a global symbol rather than by `instanceof`. + * + * @param value — the value to test. + * @returns `true` if `value` is a Cordis context, narrowing its type. + */ + static is(value: any): value is Context { + return !!value?.[Context.is as any] + } + + static { + Context.is[Symbol.toPrimitive] = () => Symbol.for('cordis.is') + Context.prototype[Context.is as any] = true + } + + /** Create the root context and install the built-in services. */ + constructor() { + this[symbols.isolate] = Object.create(null) + this[symbols.intercept] = Object.create(null) + const self = new Proxy(this, ReflectService.handler) + this.root = self + this.baseUrl = undefined + this.fiber = new Fiber(self, {}, Object.create(null), null, () => []) + this.reflect = new ReflectService(self) + this.registry = new RegistryService(self) + this.events = new EventsService(self) + this.logger = new LoggerService(self) + this.fiber._disposables.clear() + return self + } + + [Symbol.for('nodejs.util.inspect.custom')]() { + return `Context <${this.fiber.name}>` + } + + /** + * Create a child context with extra metadata on top of the current scope. + * + * The child prototypally inherits every property of this context; own + * properties of `meta` shadow the inherited ones. The parent is not mutated. + * + * @param meta — own properties (including symbol keys) to define on the child. + * @returns a child context inheriting from this one. + */ + extend(meta = {}): this { + const shadow = Reflect.getOwnPropertyDescriptor(this, symbols.shadow)?.value + const self = Object.create(getTraceable(this, this)) + for (const prop of Reflect.ownKeys(meta)) { + Object.defineProperty(self, prop, Reflect.getOwnPropertyDescriptor(meta, prop)!) + } + if (!shadow) return self + return Object.assign(Object.create(self), { [symbols.shadow]: shadow }) + } + + /** + * Create a child context with an independent service scope for `name`. + * + * Below the returned context, reads and writes of the service `name` + * resolve against the new label instead of the parent's, so a different + * implementation can be provided without affecting the parent scope. + * Passing the same `label` to two `isolate()` calls joins their scopes. + * + * @param name — the service name to isolate. + * @param label — scope label to join; defaults to a fresh unique symbol. + * @returns a child context whose `name` service resolves in the new scope. + */ + isolate(name: string, label?: symbol) { + const shadow = Object.create(this[symbols.isolate]) + shadow[name] = label ?? Symbol(name) + return this.extend({ [symbols.isolate]: shadow }) + } + + /** + * Add service-specific intercept config for plugins started below this + * context. + * + * Plugins loaded under the returned context see `config` merged into the + * service's resolved config (ancestor entries first; see + * `Service[symbols.resolveConfig]`). The parent context is not affected. + * + * @param name — the service name whose config to intercept. + * @param config — the intercept config to merge for that service. + * @returns a child context carrying the additional intercept entry. + */ + intercept(name: K, config: Context[K] extends { [symbols.config]: infer T } ? T : never): this + intercept(name: string, config: any): this + intercept(name: string, config: any) { + const intercept = Object.create(this[symbols.intercept]) + intercept[name] = config + return this.extend({ [symbols.intercept]: intercept }) + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/events.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/events.ts new file mode 100644 index 0000000..e9bd85e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/events.ts @@ -0,0 +1,352 @@ +import { defineProperty } from '@deepseek-ai/cosmokit' +import type { Promisify } from '@deepseek-ai/cosmokit' +import { Context } from './context.ts' +import { Fiber, FiberState } from './fiber.ts' +import { DisposableList, symbols } from './utils.ts' + +/** + * Return whether an event result should stop a bail-style dispatch. + * + * @param value — a listener's return value. + * @returns `true` unless `value` is `null`, `false`, or `undefined`. + */ +export function isBailed(value: any) { + return value !== null && value !== false && value !== undefined +} + +/** Extract the parameter tuple from a function type. */ +export type Parameters = F extends (...args: infer P) => any ? P : never +/** Extract the return type from a function type. */ +export type ReturnType = F extends (...args: any) => infer R ? R : never +/** Extract the explicit `this` type from a function type. */ +export type ThisType = F extends (this: infer T, ...args: any) => any ? T : never + +/** + * Event dispatch strategy used by the event service. + * + * `emit` runs synchronous listeners without awaiting them, `parallel` awaits + * all listeners together, `serial` awaits them in order until one bails, + * `bail` stops on the first synchronous bail value, and `waterfall` composes + * listeners around a final `next` callback. + */ +export type DispatchMode = 'emit' | 'parallel' | 'serial' | 'bail' | 'waterfall' + +declare module './context.ts' { + export interface Context { + /* eslint-disable max-len */ + /** + * Dispatch an event, running all listeners concurrently. + * + * @param name — the event name. + * @param args — arguments passed to every listener. + * @returns a promise resolving once every listener has settled. + */ + parallel(name: K, ...args: Parameters): Promise + /** Same as above, with an explicit `this` for listeners (also used for filtering). */ + parallel(thisArg: NoInfer>, name: K, ...args: Parameters): Promise + /** + * Dispatch an event synchronously, ignoring listener return values. + * + * @param name — the event name. + * @param args — arguments passed to every listener. + */ + emit(name: K, ...args: Parameters): void + /** Same as above, with an explicit `this` for listeners (also used for filtering). */ + emit(thisArg: NoInfer>, name: K, ...args: Parameters): void + /** + * Dispatch an event, awaiting listeners in order until one bails. + * + * @param name — the event name. + * @param args — arguments passed to each listener. + * @returns the first bail value (non-null, non-false, non-undefined), if any. + */ + serial(name: K, ...args: Parameters): Promisify> + /** Same as above, with an explicit `this` for listeners (also used for filtering). */ + serial(thisArg: NoInfer>, name: K, ...args: Parameters): Promisify> + /** + * Dispatch an event, calling listeners in order until one bails. + * + * @param name — the event name. + * @param args — arguments passed to each listener. + * @returns the first bail value (non-null, non-false, non-undefined), if any. + */ + bail(name: K, ...args: Parameters): ReturnType + /** Same as above, with an explicit `this` for listeners (also used for filtering). */ + bail(thisArg: NoInfer>, name: K, ...args: Parameters): ReturnType + /** + * Dispatch an event whose last argument is a `next` continuation. + * + * Each listener wraps the rest of the chain: calling `next()` invokes the + * next listener (finally the built-in behavior); not calling it vetoes. + * + * @param name — the event name. + * @param args — listener arguments; the final one is the innermost `next`. + * @returns the outermost listener's return value. + */ + waterfall(name: K, ...args: Parameters): ReturnType + /** Same as above, with an explicit `this` for listeners (also used for filtering). */ + waterfall(thisArg: NoInfer>, name: K, ...args: Parameters): ReturnType + /** + * Register an event listener owned by the current fiber. + * + * @param name — the event name to listen for. + * @param listener — called with the dispatch arguments. + * @param options — listener options; a boolean is shorthand for `prepend`. + * @returns a disposer removing the listener; `true` if it was still registered. + */ + on(name: K, listener: Events[K], options?: boolean | EventOptions): () => boolean + /** + * Same as `on()`, but the listener disposes itself after its first call. + * + * @param name — the event name to listen for. + * @param listener — called at most once with the dispatch arguments. + * @param options — listener options; a boolean is shorthand for `prepend`. + * @returns a disposer removing the listener; `true` if it was still registered. + */ + once(name: K, listener: Events[K], options?: boolean | EventOptions): () => boolean + /* eslint-enable max-len */ + } +} + +/** Options accepted by `ctx.on()` and `ctx.once()`. */ +export interface EventOptions { + /** Add the listener before existing listeners for the same event. */ + prepend?: boolean + /** Receive the event regardless of context filter checks. */ + global?: boolean +} + +/** Registered listener record stored by the event service. */ +export interface Hook extends EventOptions { + ctx: Context + callback: (...args: any[]) => any +} + +/** + * Event bus installed as `ctx.events` and mixed into every context. + * + * The service supports concurrent, synchronous, serial, bail, and waterfall + * dispatch and automatically disposes listeners with their owning fiber. + */ +export class EventsService { + _hooks: Record = {} + + constructor(private ctx: Context) { + defineProperty(this, symbols.tracker, { + property: 'ctx', + noShadow: true, + }) + + this.on('internal/listener', function (this: Context, name, listener, options: EventOptions) { + if (name === 'internal/update' && !options.global) { + const hooks = this.fiber._hooks['internal/update'] ??= new DisposableList() + const method = options.prepend ? 'unshift' : 'push' + return hooks[method](listener) + } + }) + + this.on('internal/update', function (config, noSave, next) { + const cbs = [...this._hooks['internal/update'] || []] + const _next = () => { + const cb = cbs.shift() ?? next + return cb.call(this, config, noSave, _next) + } + return _next() + }, { global: true, prepend: true }) + } + + /** + * Resolve listeners for one dispatch and apply context filtering. + * + * @param type — the dispatch mode, reported on `internal/dispatch`. + * @param args — the raw dispatch arguments; consumed up to the event name. + * @returns the matching listener callbacks, bound to the dispatch `this`. + */ + dispatch(type: string, args: any[]) { + const thisArg = typeof args[0] === 'object' || typeof args[0] === 'function' ? args.shift() : null + const name: string = args.shift() + if (!name.startsWith('internal/')) { + this.emit('internal/dispatch', type, name, args, thisArg) + } + const filter = thisArg?.[Context.filter] + return (this._hooks[name] || []) + .filter(hook => hook.global || !filter || filter.call(thisArg, hook.ctx)) + .map(hook => hook.callback.bind(thisArg)) + } + + /** + * Run listeners concurrently and wait for all of them. + * + * @param args — optional `this`, the event name, then listener arguments. + * @returns a promise resolving once every listener has settled. + */ + async parallel(...args: any[]) { + const results = await Promise.allSettled(this.dispatch('emit', args).map(async cb => cb(...args))) + const errors = results.filter((result): result is PromiseRejectedResult => result.status === 'rejected') + if (errors.length) throw new AggregateError(errors.map(error => error.reason)) + } + + /** + * Run listeners synchronously without waiting for returned promises. + * + * @param args — optional `this`, the event name, then listener arguments. + */ + emit(...args: any[]) { + this.dispatch('emit', args).map(cb => cb(...args)) + } + + /** + * Run listeners in order, awaiting each, until one returns a bail value. + * + * @param args — optional `this`, the event name, then listener arguments. + * @returns the first bail value (see {@link isBailed}), if any. + */ + async serial(...args: any[]) { + for (const cb of this.dispatch('serial', args)) { + const result = await cb(...args) + if (isBailed(result)) return result + } + } + + /** + * Run listeners synchronously until one returns a bail value. + * + * @param args — optional `this`, the event name, then listener arguments. + * @returns the first bail value (see {@link isBailed}), if any. + */ + bail(...args: any[]) { + for (const cb of this.dispatch('bail', args)) { + const result = cb(...args) + if (isBailed(result)) return result + } + } + + /** + * Compose listeners around the final `next` callback. + * + * The last dispatch argument is treated as the innermost `next`. Listeners + * run outermost-first; a listener that does not call `next()` vetoes the + * rest of the chain, including the built-in behavior. + * + * @param args — optional `this`, the event name, listener arguments, then `next`. + * @returns the outermost listener's return value. + */ + waterfall(...args: any[]) { + const cbs = this.dispatch('waterfall', args) + const inner = args.pop() + const next = () => { + const cb = cbs.shift() ?? inner + return cb(...args) + } + args.push(next) + return next() + } + + /** + * Store a listener record as an effect on the current fiber. + * + * @param label — effect label shown in fiber diagnostics. + * @param hooks — the listener list for one event. + * @param callback — the listener to store. + * @param options — placement and filtering options. + * @returns a disposer that unregisters the listener. + */ + register(label: string, hooks: Hook[], callback: any, options: EventOptions): () => void { + const method = options.prepend ? 'unshift' : 'push' + return this.ctx.fiber.effect(() => { + hooks[method]({ ctx: this.ctx, callback, ...options }) + return () => this.unregister(hooks, callback) + }, label) + } + + /** + * Remove a stored listener record. + * + * @param hooks — the listener list for one event. + * @param callback — the listener to remove. + * @returns `true` if the listener was found and removed. + */ + unregister(hooks: Hook[], callback: any) { + const index = hooks.findIndex(hook => hook.callback === callback) + if (index >= 0) { + hooks.splice(index, 1) + return true + } + } + + /** + * Register an event listener owned by the current fiber. + * + * The listener is removed automatically when the fiber unloads. Throws + * `CordisError('INACTIVE_EFFECT')` if the fiber is already disposed. + * + * @param name — the event name to listen for. + * @param listener — called with the dispatch arguments. + * @param options — listener options; a boolean is shorthand for `prepend`. + * @returns a disposer removing the listener; `true` if it was still registered. + */ + on(name: string | symbol, listener: (...args: any) => any, options?: boolean | EventOptions) { + if (typeof options !== 'object') { + options = { prepend: options } + } + + // handle special events + this.ctx.fiber.assertActive() + listener = this.ctx.reflect.bind(listener) + const result = this.bail(this.ctx, 'internal/listener', name, listener, options) + if (result) return result + + const hooks = this._hooks[name] ||= [] + const label = `ctx.on(${typeof name === 'string' ? JSON.stringify(name) : name.toString()})` + return this.register(label, hooks, listener, options) + } + + /** + * Register an event listener that disposes itself after the first call. + * + * @param name — the event name to listen for. + * @param listener — called at most once with the dispatch arguments. + * @param options — listener options; a boolean is shorthand for `prepend`. + * @returns a disposer removing the listener; `true` if it was still registered. + */ + once(name: string, listener: (...args: any) => any, options?: boolean | EventOptions) { + const dispose = this.on(name, function (...args: any[]) { + dispose() + return listener.apply(this, args) + }, options) + return dispose + } +} + +/** + * Built-in framework events used by core services and extension points. + * + * Plugin and status events track fiber lifecycle, service events observe + * dependency registration, update/get/set/listener events allow core services + * to intercept runtime operations, and `internal/dispatch` exposes event-bus + * diagnostics before public events are delivered. + */ +export interface Events { + /** A plugin fiber was created or its uid was cleared on disposal. */ + 'internal/plugin'(fiber: Fiber): void + /** A fiber changed lifecycle state; receives the fiber and its previous state. */ + 'internal/status'(fiber: Fiber, oldValue: FiberState): void + /** + * Resolve raw plugin config after the fiber's injections become active. + * @param config - the raw config for this activation. + * @mode waterfall + */ + 'internal/config'(this: Fiber, config: any, next: () => any): any + /** Interception hook for a service binding (no core producer). */ + 'internal/service'(this: Context, name: string, value: any): void + /** Waterfall: a fiber config update is being applied; skip `next()` to veto. */ + 'internal/update'(this: Fiber, config: any, noSave: boolean, next: () => void | Promise): void | Promise + /** Waterfall: a service is being read through the context proxy. */ + 'internal/get'(ctx: Context, name: string, error: Error, next: () => any): any + /** Waterfall: a service is being written through the context proxy. */ + 'internal/set'(ctx: Context, name: string, value: any, error: Error, next: () => boolean): boolean + /** Bail: a listener is being registered; a non-null result replaces registration. */ + 'internal/listener'(this: Context, name: string, listener: any, prepend: boolean): void + /** An event is being dispatched to listeners (fired for non-internal events only). */ + 'internal/dispatch'(mode: DispatchMode, name: string, args: any[], thisArg: any): void +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/fiber.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/fiber.ts new file mode 100644 index 0000000..38a3197 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/fiber.ts @@ -0,0 +1,754 @@ +import { defineProperty, isNullable } from '@deepseek-ai/cosmokit' +import type { Awaitable, Dict } from '@deepseek-ai/cosmokit' +import { Context } from './context.ts' +import type { Plugin } from './registry.ts' +import { buildOuterStack, composeError, DisposableList, getTraceable, isConstructor, isObject, symbols } from './utils.ts' +import type { Impl } from './reflect.ts' +import type { StandardSchemaV1 } from '@standard-schema/spec' + +declare module './context.ts' { + export interface Context extends Pick { + /** The fiber (plugin runtime instance) that owns this context. */ + fiber: Fiber + } +} + +const kValidationError = Symbol.for('ValidationError') + +/** Error raised when plugin configuration fails standard-schema validation. */ +export class ValidationError extends TypeError { + name = 'ValidationError' + + /** + * Build the aggregated message from schema issues. + * + * @param issues — the standard-schema issues, one message line each. + */ + constructor(issues: readonly StandardSchemaV1.Issue[]) { + super(`invalid config:\n` + issues.map(issue => { + if (issue.path) { + return ` - ${issue.message} (at ${issue.path.join('.')})` + } else { + return ` - ${issue.message}` + } + }).join('\n')) + } +} + +Object.defineProperty(ValidationError.prototype, kValidationError, { + value: true, +}) + +/** + * Validate and normalize config for a plugin runtime before it starts. + * + * @param runtime — the plugin runtime whose `Config` schema to apply. + * @param config — the raw user config. + * @returns the validated config, or `config` unchanged if the runtime has no schema. + * @throws {ValidationError} when validation reports issues. + */ +export function resolveConfig(runtime: Plugin.Runtime, config: any) { + if (!runtime.Config) return config + // TODO: async validation + const result = runtime.Config['~standard'].validate(config) + if ('then' in result) { + throw new TypeError('Async config validation is not supported') + } + if (result.issues) { + throw new ValidationError(result.issues) + } else { + return result.value + } +} + +interface AsyncDisposable = Awaitable> extends PromiseLike<() => T> { + (): T +} + +/** + * Function returned by an effect to release resources during disposal. + * + * Disposers run in reverse registration order when the owning fiber unloads; + * they may be async, in which case unloading awaits them. + */ +export type Disposable = () => T + +/** + * Effect body result accepted by `ctx.effect()` and plugin startup. + * + * Either a single disposer, a promise of one, or a (possibly async) iterable + * yielding several — generator effects register each yielded disposer as it + * is produced. + */ +export type Effect = + | SyncEffect + | AsyncEffect + +type SyncEffect = + | Disposable + | Iterable, void, void> + +type AsyncEffect = + | Promise> + | AsyncIterable, void, void> + +/** Tree node used to expose nested effect labels for diagnostics. */ +export interface EffectMeta { + /** Human-readable effect label, e.g. `ctx.on("event")` or `ctx.provide("name")`. */ + label: string + /** Metadata of nested effects registered while this effect ran. */ + children: EffectMeta[] +} + +interface EffectRunner { + epoch: T + execute: () => any + collect: (dispose: Disposable) => void + getOuterStack: () => string[] +} + +// Public effect disposers remain single-shot, but structural owners and outer +// effects must still be able to join a cleanup that another caller started. +const effectInertia = new WeakMap void | Promise>() + +function runDisposable(dispose: Disposable) { + const result = dispose() + return effectInertia.get(dispose)?.() ?? result +} + +/** Notify plugin teardown without allowing one observer to break ownership cleanup. */ +function emitPluginDisposed(context: Context, fiber: Fiber) { + const args: any[] = ['internal/plugin', fiber] + let callbacks: Function[] + try { + callbacks = context.events.dispatch('emit', args) + } catch (error) { + context.logger.error(error) + return + } + for (const callback of callbacks) { + try { + const returned = callback(...args) + void Promise.resolve(returned).catch(error => context.logger.error(error)) + } catch (error) { + context.logger.error(error) + } + } +} + +/** + * Lifecycle state for one plugin fiber. + * + * `PENDING` — waiting for required services; `LOADING` — the plugin callback + * is running; `ACTIVE` — loaded and providing; `FAILED` — the callback or its + * config threw; `UNLOADING` — disposers are running; `DISPOSED` — the fiber + * was removed and cannot restart. + */ +export const enum FiberState { + PENDING, + LOADING, + ACTIVE, + FAILED, + DISPOSED, + UNLOADING, +} + +/** Framework error with a stable machine-readable code. */ +export class CordisError extends Error { + /** + * @param code — the stable error code; also the default message. + * @param message — optional human-readable override. + */ + constructor(public code: CordisError.Code, message?: string) { + super(message ?? CordisError.Code[code]) + } +} + +/** Cordis error code definitions. */ +export namespace CordisError { + export type Code = keyof typeof Code + + export const Code = { + INACTIVE_EFFECT: 'cannot create effect on inactive context', + } as const +} + +const INACTIVE = '__INACTIVE__' + +/** + * Runtime instance of one plugin application. + * + * A fiber tracks dependency state, validated config, lifecycle effects, and + * cleanup for the plugin context returned by `ctx.plugin()`. + */ +export class Fiber { + /** Unique id within the registry; 0 for the root fiber, `null` once disposed. */ + public uid: number | null + /** The context this fiber's plugin runs in (extends the parent context). */ + public readonly ctx: Context + /** The validated plugin config (updated by `update()`). */ + public config: any + /** The raw plugin config, re-resolved before each activation. */ + public _config: any + /** Current lifecycle state; transitions emit `internal/status`. */ + public state = FiberState.PENDING + /** Dispose this fiber: unload the plugin, then settle once cleanup finished. */ + public readonly dispose: () => Promise + /** Snapshot of required service implementations while loaded; `undefined` otherwise. */ + public store: Dict | undefined + /** The in-flight load/unload transition, if one is currently running. */ + public inertia: Promise | undefined + + public readonly _hooks: Dict> = Object.create(null) + public readonly _disposables = new DisposableList() + + // Same as `this.ctx`, but with a more specific type. + protected context: Context + + private _error: any + private _runner: EffectRunner + private _store: Dict = Object.create(null) + + /** + * Create a fiber. Plugin authors normally obtain fibers from `ctx.plugin()` + * rather than constructing them directly. + * + * @param parent — the context the plugin was loaded from. + * @param config — raw config, validated against the runtime's schema. + * @param inject — resolved dependency map (service name → intercept config). + * @param runtime — the shared plugin runtime, or `null` for the root fiber. + * @param getOuterStack — captures the caller stack for effect diagnostics. + */ + constructor( + public parent: Context, + config: any, + public inject: Dict, + public runtime: Plugin.Runtime | null, + getOuterStack: () => string[], + ) { + this._config = config + const collect = (dispose: Disposable) => { + this._disposables.push(dispose) + } + + if (runtime) { + this.uid = parent.registry.counter + this.ctx = this.context = parent.extend({ fiber: this }) + + const injectEntries = Object.entries(this.inject) + if (injectEntries.length) { + this.ctx[Context.intercept] = Object.create(parent[Context.intercept]) + for (const [name, config] of injectEntries) { + if (isNullable(config)) continue + this.ctx[Context.intercept][name] = config + } + } + + this._runner = { + epoch: INACTIVE, + getOuterStack, + execute: function () { + if (isConstructor(runtime.callback)) { + // eslint-disable-next-line new-cap + const instance = new runtime.callback(this.ctx, this.config) + for (const hook of instance?.[symbols.initHooks] ?? []) { + hook() + } + return instance?.[symbols.init]?.() + } else { + return runtime.callback(this.ctx, this.config) + } + }, + collect, + } + + this.dispose = parent.fiber.effect(() => { + const remove = runtime.fibers.push(this) + return async () => { + this.uid = null + emitPluginDisposed(this.context, this) + if (this.ctx.registry.has(runtime.callback)) { + remove() + if (!runtime.fibers.length) { + this.ctx.registry.delete(runtime.callback) + } + } + this._setEpoch(INACTIVE) + // A PENDING fiber can already own effects registered by an + // internal/plugin observer. Its epoch is still INACTIVE, so + // _setEpoch() has no transition to drive; explicitly unload that + // pre-activation work before reporting disposal complete. + if (!this.inertia) { + this._updateState(() => { + this.inertia = this._unload() + return FiberState.UNLOADING + }) + } + // `this.inertia` itself should never reject — both `_reload` and + // `_unload` swallow their own work errors via `ctx.logger.error`. + // If it *does* reject, the only remaining cause is the logger + // itself failing, which we can't recover from in this exact spot + // (calling the logger again is what just failed). Let the + // rejection propagate; process-level crash is the honest outcome. + while (this.inertia) { + await this.inertia + } + } + }, 'ctx.plugin()') + + try { + // Publish only after the parent owns a fully assigned disposer. A + // synchronous observer may dispose either this fiber or its parent. + this.context.emit('internal/plugin', this) + } catch (error) { + // Publication failed synchronously. The disposer removes the child + // from both the parent and runtime before control escapes. + void Promise.resolve(this.dispose()).catch(reason => this.ctx.logger.error(reason)) + throw error + } + + // Keep the initial notification's historical PENDING view. The loader + // may also extend `inject` in that notification, so resolve dependencies + // only after publication. A reentrant parent unload makes the child + // disposer responsible for draining any PENDING effects instead. + if (this.uid !== null && parent.fiber.state !== FiberState.UNLOADING) { + for (const name of Object.keys(this.inject)) { + this._checkImpl(name) + } + this._refresh() + } + } else { + this.uid = 0 + this.ctx = this.context = parent + this.state = FiberState.ACTIVE + this.store = Object.create(null) + this._runner = { + epoch: '', + getOuterStack, + execute: () => {}, + collect, + } + this.dispose = () => this.restart() + } + } + + /** The plugin's display name, inherited from the nearest named ancestor, else `'root'`. */ + get name() { + let fiber: Fiber = this + do { + if (fiber.runtime?.name) return fiber.runtime.name + fiber = fiber.parent.fiber + } while (fiber !== fiber.parent.fiber) + return 'root' + } + + /** + * Throw if the fiber has already been disposed. + * + * @returns nothing when the fiber is still active. + * @throws {CordisError} `INACTIVE_EFFECT` when the fiber's uid has been cleared. + */ + assertActive() { + if (this.uid !== null) return + throw new CordisError('INACTIVE_EFFECT') + } + + private _execute(runner: EffectRunner) { + const oldEpoch = runner.epoch + return composeError((info) => { + const safeCollect = (dispose: void | Disposable) => { + if (typeof dispose === 'function') { + runner.collect(dispose) + } else if (!isNullable(dispose)) { + throw new TypeError('Invalid effect') + } + } + const effect: Effect = runner.execute.call(this) + if (typeof effect === 'function') { + return runner.collect(effect) + } else if (isNullable(effect)) { + // return + } else if (!isObject(effect)) { + throw new TypeError('Invalid effect') + } else if ('then' in effect) { + return effect.then(safeCollect) + } else if (Symbol.iterator in effect) { + info.error = new Error() + const iter = effect[Symbol.iterator]() + while (true) { + const result = iter.next() + safeCollect(result.value) + if (result.done) return + } + } else if (Symbol.asyncIterator in effect) { + const iter = effect[Symbol.asyncIterator]() + return (async () => { + // force async stack trace + await Promise.resolve() + info.error = new Error() + while (true) { + if (runner.epoch !== oldEpoch) return + const result = await iter.next() + safeCollect(result.value) + if (result.done) return + } + })() + } else { + throw new TypeError('Invalid effect') + } + }, runner.getOuterStack) + } + + /** + * Register a cleanup-aware effect on this fiber. + * + * `execute` runs immediately; the disposers it produces are collected and + * run (in reverse order) either when the returned disposer is called or + * when the fiber unloads, whichever comes first. Calling the disposer twice + * is a no-op. Throws `CordisError('INACTIVE_EFFECT')` if the fiber is + * already disposed, and `TypeError` if `execute` returns an invalid shape. + * + * @param execute — the effect body; see {@link Effect} for accepted shapes. + * @param label — effect label shown in `getEffects()` diagnostics. + * @returns a disposer that tears the effect down and settles once done. + */ + effect(execute: () => SyncEffect, label?: string): Disposable> + /** Same as above for async effects; the disposer is also awaitable. */ + effect(execute: () => Effect, label?: string): AsyncDisposable> + effect(execute: () => Effect, label = 'anonymous'): any { + this.assertActive() + if (this.state === FiberState.UNLOADING) { + throw new CordisError('INACTIVE_EFFECT') + } + + const disposables: Disposable[] = [] + let disposing = false + let disposalTask: void | Promise + const dispose = () => { + if (disposing) return disposalTask + disposing = true + let task!: void | Promise + for (const disposable of disposables.splice(0).reverse()) { + if (task) { + task = task.then(() => runDisposable(disposable)) + } else { + const result = runDisposable(disposable) + if (isObject(result) && 'then' in result) { + task = result as any + } + } + } + return disposalTask = task + } + + const meta: EffectMeta = { label, children: [] } + const runner: EffectRunner = { + execute, + epoch: true, + collect: (dispose) => { + disposables.push(dispose) + this._disposables.delete(dispose) + if (dispose[symbols.effect]) { + meta.children.push(dispose[symbols.effect]) + } + }, + getOuterStack: buildOuterStack(), + } + + let task: void | Promise + let executing = true + let resolveSetup: (() => void) | undefined + let rejectSetup: ((reason: unknown) => void) | undefined + let setupBarrier: Promise | undefined + let setupFailed = false + let inFlight: void | Promise + let removeWrapper = () => false + + const waitForSetup = () => { + setupBarrier ??= new Promise((resolve, reject) => { + resolveSetup = resolve + rejectSetup = reject + }) + return setupBarrier + } + + const disposeAfter = (setup: PromiseLike) => { + return Promise.resolve(setup).then( + () => dispose(), + async (reason) => { + await dispose() + throw reason + }, + ) + } + + const finalizeDisposal = (callback: () => void | Promise) => { + let result: void | Promise + try { + result = callback() + } catch (error) { + removeWrapper() + throw error + } + if (isObject(result) && 'then' in result) { + const pending = Promise.resolve(result).finally(() => { + removeWrapper() + if (inFlight === pending) inFlight = undefined + }) + return inFlight = pending + } + removeWrapper() + return result + } + + const wrapper = defineProperty(() => { + // A synchronous setup failure can race an owner unload that already + // captured this wrapper but has not invoked it yet. The failed effect is + // never returned publicly, so let that internal caller await rollback. + if (!runner.epoch) return setupFailed ? inFlight : undefined + runner.epoch = false + return finalizeDisposal(() => { + if (executing) return disposeAfter(waitForSetup()) + return task ? disposeAfter(task) : dispose() + }) + }, symbols.effect, meta) as AsyncDisposable + effectInertia.set(wrapper, () => inFlight) + + // Make the effect visible to a reentrant owner unload before execute() + // runs any plugin code. Async teardown stays owner-visible until it + // settles, allowing an outer effect to join cleanup another caller began. + removeWrapper = this._disposables.push(wrapper) + try { + task = this._execute(runner) + } catch (reason) { + executing = false + setupFailed = true + runner.epoch = false + let cleanup: void | Promise + try { + cleanup = finalizeDisposal(dispose) + } finally { + rejectSetup?.(reason) + } + if (isObject(cleanup) && 'then' in cleanup) { + cleanup.catch(error => this.ctx.logger.error(error)) + } + throw reason + } + executing = false + if (setupBarrier) { + Promise.resolve(task).then(resolveSetup, rejectSetup) + } + + // prevent unhandled rejection — both from `task` itself and from the + // disposer chain if it fails to settle cleanly. + task?.catch(() => { + if (!runner.epoch) return dispose() + return finalizeDisposal(dispose) + }).catch((error) => this.ctx.logger.error(error)) + + const disposeAsync = () => { + if (!runner.epoch) return + runner.epoch = false + return finalizeDisposal(dispose) + } + wrapper.then = async (onFulfilled, onRejected) => { + return Promise.resolve(task) + .then(() => disposeAsync) + .then(onFulfilled, onRejected) + } + return wrapper + } + + /** + * Return metadata for currently registered effects. + * + * @returns one {@link EffectMeta} tree per labeled live effect. + */ + getEffects() { + return [...this._disposables] + .map(dispose => dispose[symbols.effect]) + .filter(Boolean) + } + + private _getState() { + if (this.uid === null) return FiberState.DISPOSED + if (this._error) return FiberState.FAILED + if (this._runner.epoch !== INACTIVE) return FiberState.ACTIVE + return FiberState.PENDING + } + + private _updateState(callback: () => void | FiberState) { + const oldState = this.state + this.state = callback() ?? this._getState() + if (oldState === this.state) return + // FIXME internal/fiber-info + this.context.emit('internal/status', this, oldState) + + // only notify changes between ACTIVE and NON-ACTIVE states + if (oldState !== FiberState.ACTIVE && this.state !== FiberState.ACTIVE) return + for (const key of Reflect.ownKeys(this.ctx.reflect.store)) { + const impl = this.ctx.reflect.store[key as symbol] + if (impl.fiber !== this) continue + this.ctx.reflect.notify([impl.name]) + } + } + + _checkImpl(name: string) { + const impl = this.ctx.reflect._getImpl(name, true) + if (!impl) return delete this._store[name] + try { + if (impl.check && !impl.check.call(getTraceable(this.ctx, impl.value))) { + return delete this._store[name] + } + } catch (error) { + impl.fiber.ctx.logger.error(error) + return delete this._store[name] + } + this._store[name] = impl + } + + _refresh() { + let epoch: string | boolean = false + epoch = '' + for (const name of Object.keys(this.inject)) { + const impl = this._store[name] + if (!impl) { + epoch = INACTIVE + break + } + epoch += ':' + impl.fiber.uid + } + this._setEpoch(epoch) + } + + private _setEpoch(epoch: string) { + const oldEpoch = this._runner.epoch + if (epoch === oldEpoch) return + this._runner.epoch = epoch + if (this.inertia) return + this._updateState(() => { + if (epoch !== INACTIVE && oldEpoch === INACTIVE) { + this.inertia = this._reload() + return FiberState.LOADING + } else { + this.inertia = this._unload() + return FiberState.UNLOADING + } + }) + } + + private _resolveConfig(config: any) { + config = this.context.waterfall(this, 'internal/config', config, () => config) + return this.runtime ? resolveConfig(this.runtime, config) : config + } + + private async _reload() { + this.store = { ...this._store } + const oldEpoch = this._runner.epoch + try { + await Promise.resolve() + // A disposer queued before this checkpoint may already have invalidated + // the load. Do not run plugin code for a stale epoch; the state update + // below will drain any effects collected while the fiber was PENDING. + if (this._runner.epoch === oldEpoch) { + this.config = this._resolveConfig(this._config) + await this._execute(this._runner) + this._error = undefined + } + } catch (reason) { + // impl guarantees that the error is non-null (?) + this.ctx.logger.error(reason) + this._error = reason + this._runner.epoch = INACTIVE + } + this._updateState(() => { + if (this._runner.epoch === oldEpoch) { + this.inertia = undefined + } else { + this.inertia = this._unload() + return FiberState.UNLOADING + } + }) + } + + private async _unload() { + await Promise.all(this._disposables.clear().map(async (dispose) => { + try { + await composeError(async (info) => { + await Promise.resolve() + info.error = new Error() + await runDisposable(dispose) + }, this._runner.getOuterStack) + } catch (reason) { + this.ctx.logger.error(reason) + } + })) + this.store = undefined + this._updateState(() => { + if (this._runner.epoch === INACTIVE) { + this.inertia = undefined + } else { + this.inertia = this._reload() + return FiberState.LOADING + } + }) + } + + /** + * Wait for current lifecycle work and rethrow startup errors. + * + * @returns this fiber, once it has settled into a stable state. + * @throws the config-validation or plugin-startup error, if any. + */ + async await() { + while (this.inertia) { + await this.inertia + } + if (this._error) throw this._error + return this + } + + /** + * Dispose and immediately reload this plugin with its current config. + * + * @returns a promise resolving once the reload settled. + * @throws {CordisError} `INACTIVE_EFFECT` when the fiber is already disposed. + */ + async restart() { + this.assertActive() + this._setEpoch(INACTIVE) + this._refresh() + await this.await() + } + + /** + * Validate and apply new config, then restart the plugin. + * + * Runs the `internal/update` waterfall first, so update hooks (and HMR) + * can veto or replace the restart. + * + * @param config — the new raw config; validated before anything restarts. + * @param noSave — hint for persistence hooks not to write the change back. + * @returns the update waterfall result; the default restart returns a promise. + * @throws when validation, an update listener, or the restarted plugin fails. + */ + update(config: any, noSave = false) { + this.assertActive() + this._config = config + if (this.state !== FiberState.ACTIVE) { + // Config resolution may access injected services, so defer it until the + // fiber can activate. + this._error = undefined + this._setEpoch(INACTIVE) + this._refresh() + return + } + config = this._resolveConfig(config) + return this.context.waterfall(this, 'internal/update', config, noSave, () => { + this.config = config + this._error = undefined + return this.restart() + }) + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/index.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/index.ts new file mode 100644 index 0000000..d081421 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/index.ts @@ -0,0 +1,14 @@ +/** Core context type and root context implementation. */ +export * from './context.ts' +/** Event bus, dispatch modes, and event augmentation types. */ +export * from './events.ts' +/** Plugin fiber lifecycle, effects, and config validation helpers. */ +export * from './fiber.ts' +/** Logger facade, logger service, message, exporter, and formatting types. */ +export * from './logger.ts' +/** Plugin registry, dependency injection, and plugin entrypoint types. */ +export * from './registry.ts' +/** Base service class and service lifecycle symbols. */ +export * from './service.ts' +/** Shared internal helpers used by context, services, and plugin fibers. */ +export * from './utils.ts' diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/logger.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/logger.ts new file mode 100644 index 0000000..c905bce --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/logger.ts @@ -0,0 +1,270 @@ +import { defineProperty, hyphenate } from '@deepseek-ai/cosmokit' +import { Context } from './context.ts' +import { Fiber } from './fiber.ts' +import { createCallable, joinPrototype, symbols, type Tracker } from './utils.ts' + +declare module './context.ts' { + interface Intercept { + logger: LoggerService.Intercept + } +} + +/** Logger method name and severity category. */ +export type LoggerType = 'error' | 'info' | 'warn' | 'debug' + +/** Callable shape for one logger severity method. */ +export type LoggerMethod = (format: any, ...param: any[]) => void + +/** Formatter used to resolve a printf-style placeholder. */ +export type Formatter = (value: any, exporter: Exporter, message: Message) => any + +/** Numeric severity used when exporters decide whether to emit a message. */ +export const enum LoggerLevel { + ERROR = 0, + INFO = 1, + WARN = 2, + DEBUG = 3, +} + +/** Structured log record delivered to exporters. */ +export interface Message { + sn: number + ts: number + name: string + type: LoggerType + level: number + args: any[] + fiber?: WeakRef +} + +/** Sink that receives structured log messages. */ +export interface Exporter { + colors?: number | false + maxLength?: number + levels?: Record + formatters?: Record + export(message: Message): void +} + +/** Built-in placeholder formatters used by `Logger.format()`. */ +export const defaultFormatters: Record = { + s: (value) => String(value), + d: (value) => Math.trunc(Number(value)), + i: (value) => Math.trunc(Number(value)), + f: (value) => Number(value), + o: (value) => JSON.stringify(value), + O: (value) => JSON.stringify(value), + c: () => '', + C: (value, exporter, message) => { + return Logger.color(exporter, Logger.code(message.name, exporter.colors), value) + }, +} + +/** Options used when creating a named logger facade. */ +export interface LoggerOptions { + /** The logger name shown with each message. */ + name: string + /** Message fields merged into every record from this logger. */ + meta?: Partial + /** Default maximum level exported when an exporter has no own threshold. */ + level?: number +} + +/** Logger facade identity, inherited message metadata, and optional minimum level. */ +export interface Logger extends LoggerOptions {} +/** Logger facade severity methods. */ +export interface Logger extends Record {} + +function isAggregateError(error: any): error is Error & { errors: Error[] } { + return error instanceof Error && Array.isArray(error['errors']) +} + +/** Logger facade for one named subsystem. */ +export class Logger { + static color(exporter: Exporter, code: number, value: any, decoration = '') { + if (!exporter.colors) return '' + value + return `\u001b[3${code < 8 ? code : '8;5;' + code}${exporter.colors >= 2 ? decoration : ''}m${value}\u001b[0m` + } + + static code(name: string, level?: false | number) { + let hash = 0 + for (let i = 0; i < name.length; i++) { + hash = ((hash << 3) - hash) + name.charCodeAt(i) + 13 + hash |= 0 + } + const colors = !level ? [] : level >= 2 ? c256 : c16 + return colors[Math.abs(hash) % colors.length] + } + + static format(exporter: Exporter, message: Message): string { + const args = message.args.slice() + if (args[0] instanceof Error) { + args[0] = args[0].stack || args[0].message + args.unshift('%s') + } else if (typeof args[0] !== 'string') { + args.unshift('%o') + } + + let format: string = args.shift() + format = format.replace(/%([a-zA-Z%])/g, (match, char) => { + if (match === '%%') return '%' + const formatter = exporter.formatters?.[char] ?? defaultFormatters[char] + if (typeof formatter === 'function') { + const value = args.shift() + return formatter(value, exporter, message) + } + return match + }) + + const oFormatter = exporter.formatters?.o ?? defaultFormatters.o + for (let arg of args) { + if (typeof arg === 'object' && arg) { + arg = oFormatter(arg, exporter, message) + } + format += ' ' + arg + } + + const { maxLength = 10240 } = exporter + return format.split(/\r?\n/g).map(line => { + return line.slice(0, maxLength) + (line.length > maxLength ? '...' : '') + }).join('\n') + } + + constructor(options: LoggerOptions, private service: LoggerService) { + Object.assign(this, options) + this.error = this._method('error', LoggerLevel.ERROR) + this.info = this._method('info', LoggerLevel.INFO) + this.warn = this._method('warn', LoggerLevel.WARN) + this.debug = this._method('debug', LoggerLevel.DEBUG) + } + + private _method(type: LoggerType, level: number): LoggerMethod { + return (...args: any[]) => { + if (args.length === 1 && args[0] instanceof Error) { + if (args[0].cause) { + this[type](args[0].cause) + } else if (isAggregateError(args[0])) { + args[0].errors.forEach(error => this[type](error)) + return + } + } + + const sn = ++this.service._snMessage + const ts = Date.now() + for (const exporter of this.service.exporters.values()) { + const targetLevel = exporter.levels?.[this.name] ?? exporter.levels?.default ?? this.level ?? LoggerLevel.INFO + if (targetLevel < level) continue + const message: Message = { sn, ts, type, level, name: this.name, ...this.meta, args } + exporter.export(message) + } + } + } +} + +/** ANSI 16-color palette indexes used for logger name coloring. */ +export const c16 = [6, 2, 3, 4, 5, 1] +/** ANSI 256-color palette indexes used for logger name coloring. */ +export const c256 = [ + 20, 21, 26, 27, 32, 33, 38, 39, 40, 41, 42, 43, 44, 45, 56, 57, 62, + 63, 68, 69, 74, 75, 76, 77, 78, 79, 80, 81, 92, 93, 98, 99, 112, 113, + 129, 134, 135, 148, 149, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 178, 179, 184, 185, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 214, 215, 220, 221, +] + +/** Logger service configuration merged from context intercepts. */ +export namespace LoggerService { + export interface Intercept { + name?: string + level?: number + } +} + +/** Callable `ctx.logger` service shape. */ +export interface LoggerService extends Record { + (name?: string): Logger +} + +/** + * Built-in logging service. + * + * Call `ctx.logger()` to create a named logger, or call `ctx.logger.info()` + * directly to log with the current fiber-derived name. + */ +export class LoggerService { + bufferSize = 1000 + buffer: Message[] = [] + ctx!: Context + + _snMessage = 0 + _snExporter = 0 + exporters = new Map() + + constructor(ctx: Context) { + const tracker: Tracker = { + property: 'ctx', + noShadow: true, + } + const self = createCallable('logger', joinPrototype(Object.getPrototypeOf(this), Function.prototype), tracker) as unknown as LoggerService + Object.assign(self, this) + self.ctx = ctx + defineProperty(self, symbols.tracker, tracker) + + self.exporter({ + colors: 3, + export: (message) => { + self.buffer.push(message) + if (self.buffer.length > self.bufferSize) { + self.buffer = self.buffer.slice(-self.bufferSize) + } + }, + }) + + return self + } + + /** + * Register an exporter and dispose it with the current fiber. + * + * @param exporter — the sink that receives structured log messages. + * @returns a disposer that removes the exporter. + */ + exporter(exporter: Exporter) { + return this.ctx.effect(() => { + this.exporters.set(++this._snExporter, exporter) + return () => this.exporters.delete(this._snExporter) + }, 'ctx.logger.exporter()') + } + + private _resolveConfig(): LoggerService.Intercept { + let intercept = this.ctx[symbols.intercept] + const configs: LoggerService.Intercept[] = [] + while ('logger' in intercept) { + if (Object.hasOwn(intercept, 'logger')) { + configs.unshift(intercept['logger']) + } + intercept = Object.getPrototypeOf(intercept) + } + return Object.assign({}, ...configs) + } + + [symbols.invoke](name?: string): Logger { + const config = this._resolveConfig() + const fiber = ((this.ctx as any)[symbols.shadow] ?? this.ctx).fiber + name ??= config.name + name ??= hyphenate(fiber.name) + return new Logger({ + name, + level: config.level, + meta: { fiber: new WeakRef(fiber) }, + }, this) + } + + static { + for (const type of ['error', 'info', 'warn', 'debug'] as const) { + ;(LoggerService.prototype as any)[type] = function (this: LoggerService, ...args: any[]) { + return (this as any)()[type](...args) + } + } + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/reflect.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/reflect.ts new file mode 100644 index 0000000..7bbe1ae --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/reflect.ts @@ -0,0 +1,418 @@ +import { defineProperty, isNullable } from '@deepseek-ai/cosmokit' +import type { Dict } from '@deepseek-ai/cosmokit' +import { Context } from './context.ts' +import { getTraceable, symbols, withProps } from './utils.ts' +import { Fiber, FiberState } from './fiber.ts' + +declare module './context.ts' { + interface Context { + /** + * Read a service from the store without the inject requirement. + * + * @param name — the service name. + * @param strict — when `true` (default), only return implementations + * whose providing fiber is currently active. + * @returns the service value, or `undefined` when not (yet) provided. + */ + get(name: K, strict?: boolean): undefined | this[K] + /** Same as above for service names outside the typed `Context` surface. */ + get(name: string, strict?: boolean): any + /** + * Overwrite a provided service's value. + * + * Only the fiber that provided the service may set it; setting an + * unprovided name throws. + * + * @param name — the service name. + * @param value — the new service value. + */ + set(name: K, value: undefined | this[K]): void + /** Same as above for service names outside the typed `Context` surface. */ + set(name: string, value: any): void + /** + * Register a service implementation owned by the current fiber. + * + * The service becomes visible to dependents in the same isolation scope + * once the fiber is active; it is unregistered (waking dependents) when + * the returned disposer runs or the fiber unloads. Throws if the name is + * already provided in this scope or declared as an accessor. + * + * @param name — the service name. + * @param value — the service value. + * @returns a disposer that unregisters the service. + */ + provide(name: K, value: undefined | this[K]): () => void + /** Same as above for service names outside the typed `Context` surface. */ + provide(name: string, value?: any): () => void + /** + * Define a computed context property backed by get/set hooks. + * + * The accessor is removed when the current fiber unloads. Throws if the + * name is already declared. + * + * @param name — the context property name. + * @param options — the `get` hook and optional `set` hook. + */ + accessor(name: string, options: Omit): void + /** + * Expose selected members of a service directly on `ctx`. + * + * Each mixed-in key becomes an accessor that forwards to the service + * (binding methods to it), so e.g. `ctx.on` forwards to `ctx.events.on`. + * Mixins are removed when the current fiber unloads. + * + * @param name — the context property holding the source service. + * @param mixins — keys to forward, or a source-key → ctx-key map. + */ + mixin(name: K, mixins: (keyof this & keyof this[K])[] | Dict): void + /** Same as above with a source object instead of a context property name. */ + mixin(source: T, mixins: (keyof this & keyof T)[] | Dict): void + } +} + +function enhanceError(error: Error) { + const lines = error.stack!.split('\n') + lines.splice(0, 2, `Error: ${error.message}`) + error.stack = lines.join('\n') + return error +} + +const RESERVED_WORDS = ['prototype', 'then'] + +// - is a symbol +// - is a reserved word (prototype, then) +// - is a number string (0, 1, 2, ...) +// - starts with `_` +function isSpecialProperty(prop: string | symbol): prop is symbol { + return typeof prop === 'symbol' + || RESERVED_WORDS.includes(prop) + || parseInt(prop).toString() === prop + || prop.startsWith('_') +} + +/** Context property definition known by the reflection service. */ +export type Property = Property.Service | Property.Accessor + +/** Property definition variants understood by `ReflectService`. */ +export namespace Property { + /** Service property backed by a provided implementation. */ + export interface Service { + /** Discriminator. */ + type: 'service' + } + + /** Computed context property backed by custom get/set hooks. */ + export interface Accessor { + /** Discriminator. */ + type: 'accessor' + /** Compute the property value; `error` carries the caller stack for diagnostics. */ + get: (this: Context, receiver: any, error: Error) => any + /** Optional setter; return `false` to reject the write. */ + set?: (this: Context, value: any, receiver: any, error: Error) => boolean + } +} + +/** Concrete service implementation record stored in the root reflect service. */ +export interface Impl { + /** The service name. */ + name: string + /** The fiber that provided the service (owns its lifetime). */ + fiber: Fiber + /** The current service value. */ + value?: any + /** Optional availability predicate consulted before dependents may load. */ + check?: () => boolean +} + +/** + * Reflection and service-resolution layer installed as `ctx.reflect`. + * + * This service powers the context proxy, service registration, accessors, and + * the mixins that expose core service methods directly on `ctx`. + */ +export class ReflectService { + /** Proxy traps implementing service resolution for every context object. */ + static handler: ProxyHandler = { + get: (target, prop, ctx: Context) => { + if (isSpecialProperty(prop)) { + return Reflect.get(target, prop, ctx) + } + if (Reflect.has(target, prop)) { + return getTraceable(ctx, Reflect.get(target, prop, ctx)) + } + + const error = new Error(`cannot get property "${prop}" without inject`) + + try { + const def = target.reflect.props[prop] + if (def?.type === 'accessor') { + return def.get.call(ctx, ctx[symbols.receiver], error) + } + + if (!ctx.fiber.runtime) return ctx.reflect.get(prop, false) + return ctx.events.waterfall('internal/get', ctx, prop, error, () => { + const key = target[symbols.isolate][prop] + let fiber = (ctx[symbols.shadow] as Context ?? ctx).fiber + while (true) { + const impl = fiber.store?.[prop] + if (impl) return getTraceable(ctx, impl.value) + if (prop in fiber.inject) { + error.message = `cannot get required service "${prop}" in inactive context` + throw error + } + if (!fiber.runtime) throw error + if (fiber.parent[symbols.isolate][prop] !== key) throw error + fiber = fiber.parent.fiber + } + }) + } catch (e: any) { + throw e === error ? enhanceError(e) : e + } + }, + + set: (target, prop, value, ctx: Context) => { + if (isSpecialProperty(prop)) { + return Reflect.set(target, prop, value, ctx) + } + + const error = new Error(`cannot set property "${prop}" without provide`) + const def = target.reflect.props[prop] + if (!def) { + if (!ctx.fiber.runtime) return Reflect.set(target, prop, value, ctx) + throw enhanceError(error) + } + + try { + if (def.type === 'accessor') { + if (!def.set) return false + return def.set.call(ctx, value, ctx[symbols.receiver], error) + } + + return ctx.events.waterfall('internal/set', ctx, prop, value, error, () => { + return ctx.reflect.set(prop, value, error) + }) + } catch (e: any) { + throw e === error ? enhanceError(e) : e + } + }, + + has: (target, prop) => { + if (isSpecialProperty(prop)) { + return Reflect.has(target, prop) + } + if (Reflect.has(target, prop)) return true + return !!target.reflect.props[prop] + }, + } + + /** Service implementations, keyed by isolation label. */ + public store: Dict = Object.create(null) + /** Declared context properties (services and accessors), by name. */ + public props: Dict = Object.create(null) + + constructor(public ctx: Context) { + defineProperty(this, symbols.tracker, { + property: 'ctx', + noShadow: true, + }) + + this.mixin('reflect', ['get', 'set', 'provide', 'accessor', 'mixin']) + this.mixin('fiber', ['runtime', 'effect']) + this.mixin('registry', ['inject', 'plugin']) + this.mixin('events', ['on', 'once', 'parallel', 'emit', 'serial', 'bail', 'waterfall']) + } + + /** + * Read a service from the store without the inject requirement. + * + * @param name — the service name. + * @param strict — when `true`, only return implementations whose providing + * fiber is currently active. + * @returns the service value, or `undefined` when not (yet) provided. + */ + get(name: string, strict = true) { + return getTraceable(this.ctx, this._getImpl(name, strict)?.value) + } + + _getImpl(name: string, strict = true) { + const key = this.ctx[symbols.isolate][name] + const impl = key && this.store[key] + if (!impl) return + if (strict && impl.fiber.state !== FiberState.ACTIVE) return + return impl + } + + /** + * Overwrite a provided service's value. + * + * @param name — the service name. + * @param value — the new service value. + * @param error — carrier for the caller stack in diagnostics. + * @returns `true` on success. + * @throws when `name` was never provided, or was provided by another fiber. + */ + set(name: string, value: any, error?: Error) { + const key = this.ctx[symbols.isolate][name] + const impl = this.store[key] + if (!impl) { + throw new Error(`cannot set property "${name}" without provide`) + } + if (impl.fiber !== this.ctx.fiber) { + throw new Error(`cannot set property "${name}" in multiple fibers`) + } + impl.value = value + return true + } + + /** + * Register a service implementation owned by the current fiber. + * + * See the `ctx.provide()` overload above for the full contract. + * + * @param name — the service name. + * @param value — the service value. + * @param check — optional availability predicate for dependents. + * @returns a disposer that unregisters the service. + */ + provide(name: string, value?: any, check?: () => boolean) { + return this.ctx.fiber.effect(() => { + if (!this.props[name]) { + this.props[name] ??= { type: 'service' } + } else if (this.props[name].type !== 'service') { + throw new Error(`property "${name}" is already declared as ${this.props[name].type}`) + } + this.props[name] = { type: 'service' } + + this.ctx.root[symbols.isolate][name] ??= Symbol(name) + const key = this.ctx[symbols.isolate][name] + const impl: Impl = { name, value, fiber: this.ctx.fiber, check } + if (this.store[key]) { + throw new Error(`service "${name}" has been registered at <${this.store[key].fiber.name}>`) + } + this.store[key] = impl + this.ctx.fiber.store![name] = impl + if (this.ctx.fiber.state === FiberState.ACTIVE) { + this.notify([name]) + } + return async () => { + delete this.store[key] + const fibers = this.notify([name]) + await Promise.allSettled(fibers.map(fiber => fiber.await())) + // ensure self access before dependencies cleanup + delete this.ctx.fiber.store![name] + } + }, `ctx.provide(${JSON.stringify(name)})`) + } + + /** + * Re-evaluate every fiber that requires one of the given services. + * + * @param names — the service names that changed. + * @param filter — restricts notification to matching isolation scopes. + * @returns the fibers whose dependency state was refreshed. + */ + notify(names: string[], filter = (ctx: Context, name: string) => ctx[symbols.isolate][name] === this.ctx[symbols.isolate][name]) { + const fibers: Fiber[] = [] + for (const runtime of this.ctx.registry.values()) { + for (const fiber of runtime.fibers) { + let hasUpdate = false + for (const name of names) { + if (!(name in fiber.inject)) continue + if (!filter(fiber.ctx, name)) continue + hasUpdate = true + fiber._checkImpl(name) + } + if (!hasUpdate) continue + fiber._refresh() + fibers.push(fiber) + } + } + for (const name of names) { + const self: Context = Object.create(this.ctx) + self[symbols.filter] = (target: Context) => filter(target, name) + this.ctx.events.emit(self, 'internal/service', name, this._getImpl(name, false)?.value) + } + return fibers + } + + /** + * Define a computed context property backed by get/set hooks. + * + * @param name — the context property name. + * @param options — the `get` hook and optional `set` hook. + * @returns a disposer that removes the accessor. + */ + accessor(name: string, options: Omit) { + return this.ctx.fiber.effect(() => { + if (name in this.props) { + throw new Error(`property "${name}" is already declared as ${this.props[name].type}`) + } + this.props[name] = { type: 'accessor', ...options } + return () => delete this.props[name] + }, `ctx.accessor(${JSON.stringify(name)})`) + } + + /** + * Expose selected members of a service directly on `ctx`. + * + * See the `ctx.mixin()` overload above for the full contract. + * + * @param source — a context property name or a source object. + * @param mixins — keys to forward, or a source-key → ctx-key map. + * @returns a disposer that removes all created accessors. + */ + mixin(source: any, mixins: string[] | Dict) { + const self = this + return this.ctx.fiber.effect(function* () { + const entries = Array.isArray(mixins) ? mixins.map(key => [key, key]) : Object.entries(mixins) + const getTarget = (ctx: Context, error: Error) => { + // TODO enhance error message + return ctx[source] + } + for (const [key, value] of entries) { + yield self.accessor(value, { + get(receiver, error) { + const service = getTarget(this, error) + if (isNullable(service)) return service + const mixin = receiver ? withProps(receiver, service) : service + const value = Reflect.get(service, key, mixin) + if (typeof value !== 'function') return value + return value.bind(mixin ?? service) + }, + set(value, receiver, error) { + const service = getTarget(this, error) + const mixin = receiver ? withProps(receiver, service) : service + return Reflect.set(service, key, value, mixin) + }, + }) + } + }, `ctx.mixin(${JSON.stringify(source)})`) + } + + /** + * Attach this context's tracing wrapper to a value. + * + * @param value — the value to wrap. + * @returns the traceable wrapper (or the value itself when not applicable). + */ + trace(value: T) { + return getTraceable(this.ctx, value) + } + + /** + * Wrap a callback so calls trace `this` and arguments to this context. + * + * @param callback — the function to wrap. + * @returns a proxy delegating to `callback` with traced values. + */ + bind(callback: T) { + return new Proxy(callback, { + apply: (target, thisArg, args) => { + return Reflect.apply(target, this.trace(thisArg), args.map(arg => this.trace(arg))) + }, + construct: (target, args, newTarget) => { + return Reflect.construct(target, args.map(arg => this.trace(arg)), newTarget) + }, + }) + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/registry.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/registry.ts new file mode 100644 index 0000000..478cf03 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/registry.ts @@ -0,0 +1,337 @@ +import { defineProperty } from '@deepseek-ai/cosmokit' +import type { Dict } from '@deepseek-ai/cosmokit' +import type { StandardSchemaV1 } from '@standard-schema/spec' +import { Context } from './context.ts' +import { Fiber } from './fiber.ts' +import { buildOuterStack, DisposableList, symbols, withProps } from './utils.ts' + +function isApplicable(object: Plugin) { + return object && typeof object === 'object' && typeof object.apply === 'function' +} + +/** + * Service dependency declaration accepted by plugins and the `@Inject` + * decorator. + * + * Array form requests services without intercept config. Object form maps each + * service name to optional intercept config for the plugin context. + */ +export type Inject = (keyof M)[] | { [K in keyof M]?: M[K] } + +/** Context keys that correspond to services with typed intercept config. */ +export type InjectKey = keyof { + [K in keyof Context & string as Context[K] extends { [symbols.config]: any } ? K : never]: any +} + +/** + * Decorator for declaring service dependencies on classes or class methods. + * + * On classes it contributes to the plugin's static `inject` map. On methods it + * delays the method call until the declared services are available. + */ +/** + * @param name — the required service name. + * @param config — optional intercept config applied for that service. + * @returns the class or method decorator. + */ +export function Inject(name: K, config?: Context[K] extends { [symbols.config]: infer T } ? T : never) { + return function (value: any, decorator: ClassDecoratorContext | ClassMethodDecoratorContext) { + if (decorator.kind === 'class') { + if (!Object.hasOwn(value, 'inject')) { + defineProperty(value, 'inject', Object.create(Object.getPrototypeOf(value).inject ?? null)) + defineProperty(value.inject, symbols.checkProto, true) + } + value.inject[name] = config + } else if (decorator.kind === 'method') { + const inject = (value[symbols.metadata] ??= {}).inject ??= Object.create(null) + inject[name] = config + decorator.addInitializer(function () { + const property = this[symbols.tracker]?.property + ;(this[symbols.initHooks] ??= []).push(() => { + (this.ctx as Context).inject(inject, (ctx) => { + return value.call(property ? withProps(this, { [property]: ctx }) : this) + }) + }) + }) + } else { + throw new Error('@Inject() can only be used on class or class methods') + } + } +} + +/** Utilities for normalizing plugin dependency declarations. */ +export namespace Inject { + /** + * Convert array/object/class-inherited inject metadata into a plain map. + * + * @param inject — the declaration to normalize; `null`/`undefined` add nothing. + * @param result — the map to fill (service name → intercept config or `null`). + * @returns `result`. + */ + export function resolve(inject: Inject | null | undefined, result: Dict = Object.create(null)) { + if (!inject) return result + if (Array.isArray(inject)) { + for (const name of inject) { + result[name] = null + } + } else if (Reflect.has(inject, symbols.checkProto)) { + Object.assign(result, resolve(Object.getPrototypeOf(inject))) + for (const name of Object.keys(inject)) { + result[name] = inject[name] ?? null + } + } else { + for (const name of Object.keys(inject)) { + result[name] = inject[name] ?? null + } + } + return result + } +} + +/** Supported plugin entrypoint shapes. */ +export type Plugin = + | Plugin.Function + | Plugin.Constructor + | Plugin.Object + +/** Types associated with plugin entrypoints and runtime records. */ +export namespace Plugin { + /** Shared metadata understood by the plugin registry and related tooling. */ + export interface Base { + /** Display name used for fiber diagnostics and logger names. */ + name?: string + /** Standard-schema validator applied to config before the plugin starts. */ + Config?: StandardSchemaV1 + /** Services the plugin requires; it only loads while all are available. */ + inject?: Inject + /** Service name(s) the plugin provides (read by `Service` and by loaders). */ + provide?: string | string[] + /** Service names whose intercept config the plugin declares it consumes. */ + intercept?: Dict + } + + export interface Transform { + /** Marks the transform object as a schema/config transform. */ + schema?: true + /** Convert user-facing config to runtime config. */ + Config: (config: S) => T + } + + /** Function plugin called with `(ctx, config)`. */ + export interface Function extends Base { + (ctx: Context, config: T): any + } + + /** Class plugin constructed with `(ctx, config)`. */ + export interface Constructor extends Base { + new (ctx: Context, config: T): any + } + + /** Object plugin with an `apply(ctx, config)` method. */ + export interface Object extends Base { + apply(ctx: Context, config: T): any + } + + /** Mutable registry record shared by all fibers of one plugin callback. */ + export interface Runtime { + /** Display name copied from the first registered plugin shape. */ + name?: string + /** Every live fiber of this plugin (one per `ctx.plugin()` call). */ + fibers: DisposableList + /** The executable entrypoint all fibers share (registry identity key). */ + callback: globalThis.Function + /** Standard-schema validator applied to each fiber's config. */ + Config?: StandardSchemaV1 + } +} + +type Spread = undefined extends T ? [config?: T] : [config: T] + +type GetPluginParameters

= + | P extends (ctx: Context, ...args: infer R) => any + ? R + : P extends new (ctx: Context, ...args: infer R) => any + ? R + : P extends { apply(ctx: Context, ...args: infer R): any } + ? R + : never + +type GetPluginConfig

= + | P extends Plugin.Transform + ? S + : GetPluginParameters

[0] + +declare module './context.ts' { + export interface Context { + /** + * Run a callback once the requested services are available. + * + * Shorthand for `ctx.plugin({ inject, apply: callback })`: the callback + * is unloaded and re-run whenever a required service changes. + * + * @param deps — required services, as an array or a name → config map. + * @param callback — plugin body called with `(ctx, config)`. + * @returns the fiber; awaiting it settles once loading finished. + */ + inject(deps: Inject, callback: Plugin.Function): Fiber & PromiseLike + /** + * Load a plugin in the current context. + * + * @param plugin — a function, class, or `{ apply }` object plugin. + * @param args — the plugin config, validated against its `Config` schema. + * @returns the fiber; awaiting it settles once loading finished + * (rejecting on config or startup errors). + */ + plugin

(plugin: P, ...args: Spread>): Fiber & PromiseLike + } +} + +/** + * Plugin registry installed as `ctx.registry` and mixed into every context. + * + * It normalizes plugin shapes, tracks plugin runtimes, starts fibers, and + * exposes map-like inspection over active plugin callbacks. + */ +export class RegistryService { + private _counter = 0 + private _internal = new Map() + + constructor(public ctx: Context) { + defineProperty(this, symbols.tracker, { + property: 'ctx', + noShadow: true, + }) + } + + /** Allocate the next fiber uid (increments on every read). */ + get counter() { + return ++this._counter + } + + /** Number of registered plugin runtimes. */ + get size() { + return this._internal.size + } + + /** + * Resolve a supported plugin shape to its executable callback. + * + * @param plugin — a function, class, or `{ apply }` object plugin. + * @returns the callback identifying the plugin, or `undefined` if invalid. + */ + resolve(plugin: Plugin): Function | undefined { + // plugin.apply may throw + try { + if (typeof plugin === 'function') return plugin + if (isApplicable(plugin)) return plugin.apply + } catch {} + } + + /** + * Look up the runtime record for a plugin. + * + * @param plugin — any supported plugin shape. + * @returns the runtime, or `undefined` when the plugin is not registered. + */ + get(plugin: Plugin) { + const key = this.resolve(plugin) + return key && this._internal.get(key) + } + + /** + * Check whether a plugin has a registered runtime. + * + * @param plugin — any supported plugin shape. + * @returns `true` when at least one fiber of the plugin exists. + */ + has(plugin: Plugin) { + const key = this.resolve(plugin) + return !!key && this._internal.has(key) + } + + /** + * Dispose every running fiber for a plugin and remove its runtime record. + * + * @param plugin — any supported plugin shape. + * @returns the removed runtime, or `undefined` when none was registered. + */ + delete(plugin: Plugin) { + const key = this.resolve(plugin) + const runtime = key && this._internal.get(key) + if (!runtime) return + this._internal.delete(key) + for (const fiber of runtime.fibers) { + fiber.dispose() + } + return runtime + } + + /** Iterate the registered plugin callbacks. */ + keys() { + return this._internal.keys() + } + + /** Iterate the registered plugin runtimes. */ + values() { + return this._internal.values() + } + + /** Iterate `[callback, runtime]` pairs. */ + entries() { + return this._internal.entries() + } + + /** + * Visit every registered runtime. + * + * @param callback — receives each runtime and its identifying callback. + */ + forEach(callback: (value: Plugin.Runtime, key: Function) => void) { + return this._internal.forEach(callback) + } + + /** + * Start a callback once the requested dependencies are available. + * + * @param inject — required services, as an array or a name → config map. + * @param callback — plugin body called with `(ctx, config)`. + * @returns the fiber; awaiting it settles once loading finished. + */ + inject(inject: Inject, callback: Plugin.Function) { + return this.plugin({ inject, apply: callback, name: callback.name }) + } + + /** + * Start a plugin in the current context and return its fiber. + * + * Creates (or reuses) the plugin's runtime record, then starts a new fiber + * under the current context. Throws if `plugin` is not a supported shape or + * if the current fiber is already disposed. + * + * @param plugin — a function, class, or `{ apply }` object plugin. + * @param config — the plugin config, validated against its `Config` schema. + * @param getOuterStack — captures the caller stack for effect diagnostics. + * @returns the fiber; awaiting it settles once loading finished. + */ + plugin(plugin: Plugin, config?: any, getOuterStack = buildOuterStack()) { + // check if it's a valid plugin + const callback = this.resolve(plugin) + if (!callback) throw new Error('invalid plugin, expect function or object with an "apply" method, received ' + typeof plugin) + this.ctx.fiber.assertActive() + + let runtime = this._internal.get(callback) + if (!runtime) { + let name = plugin.name + if (name === 'apply') name = undefined + runtime = { name, callback, fibers: new DisposableList(), Config: plugin.Config } + this._internal.set(callback, runtime) + } + + const fiber = new Fiber(this.ctx, config, Inject.resolve(plugin.inject), runtime, getOuterStack) + const wrapped = Object.create(fiber) as Fiber & PromiseLike + wrapped.then = (onFulfilled, onRejected) => { + return fiber.await().then(onFulfilled, onRejected) + } + return wrapped + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/service.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/service.ts new file mode 100644 index 0000000..dc5742f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/service.ts @@ -0,0 +1,115 @@ +import { defineProperty } from '@deepseek-ai/cosmokit' +import { Context } from './context.ts' +import { createCallable, joinPrototype, symbols, type Tracker } from './utils.ts' + +/** + * Base class for services that expose a named API on `ctx`. + * + * Subclasses call `super(ctx, name)` from their constructor. The service is + * registered immediately and is automatically removed with the owning fiber. + */ +export abstract class Service { + /** Symbol key of an instance method run after construction (class plugins). */ + static readonly init: unique symbol = symbols.init + /** Symbol key of the availability predicate passed to `ctx.provide()`. */ + static readonly check: unique symbol = symbols.check + /** Symbol key of the phantom intercept-config type parameter. */ + static readonly config: unique symbol = symbols.config + /** Symbol key of the call body making a service callable (e.g. `ctx.logger()`). */ + static readonly invoke: unique symbol = symbols.invoke + /** Symbol key of the helper deriving an extended service instance. */ + static readonly extend: unique symbol = symbols.extend + /** Symbol key of the tracker metadata used for context tracing. */ + static readonly tracker: unique symbol = symbols.tracker + /** Symbol key of the intercept-config resolution helper below. */ + static readonly resolveConfig: unique symbol = symbols.resolveConfig + + declare [symbols.config]: T + + /** The service name this instance is registered under. */ + public name!: string + + /** + * Register this instance as `name` in the current context. + * + * Calls `ctx.reflect.provide(name, this, this[Service.check])`, so the + * service is unregistered automatically when the owning fiber unloads. + * Services with a `[Service.invoke]` body return a callable instance. + * + * @param ctx — the context to register in (stored as `this.ctx`). + * @param name — the service name; defaults to the static `provide` field. + */ + constructor(protected ctx: Context, name: string) { + name ??= this.constructor['provide'] as string + + let self = this + const tracker: Tracker = { + associate: name, + property: 'ctx', + } + if (self[symbols.invoke]) { + self = createCallable(name, joinPrototype(Object.getPrototypeOf(this), Function.prototype), tracker) + } + self.ctx = ctx + self.name = name + defineProperty(self, symbols.tracker, tracker) + + self.ctx.reflect.provide(name, self, this[symbols.check]) + return self + } + + protected [symbols.filter](ctx: Context) { + return ctx[symbols.isolate][this.name] === this.ctx[symbols.isolate][this.name] + } + + protected [symbols.extend](props?: any) { + let self: any + if (this[Service.invoke]) { + self = createCallable(this.name, this, this[symbols.tracker]) + } else { + self = Object.create(this) + } + return Object.assign(self, props) + } + + /** + * Merge intercept config from ancestors with optional base and head values. + * + * Entries added closer to the root apply first; `base` is prepended and + * `head` appended. Uses `Config.merge` when the service declares one, + * otherwise a shallow `Object.assign`. + * + * @param base — lowest-precedence config merged before all intercepts. + * @param head — highest-precedence config merged after all intercepts. + * @returns the merged config. + */ + [symbols.resolveConfig](base?: T, head?: T): T { + let intercept = this.ctx[Context.intercept] + const configs: any[] = [] + while (this.name in intercept) { + if (Object.hasOwn(intercept, this.name)) { + configs.unshift(intercept[this.name]) + } + intercept = Object.getPrototypeOf(intercept) + } + if (base) configs.unshift(base) + if (head) configs.push(head) + if (this['Config']?.merge) { + return this['Config'].merge(...configs) + } else { + return Object.assign({}, ...configs) + } + } + + static [Symbol.hasInstance](instance: any) { + if (!instance) return false + let constructor = instance.constructor + while (constructor) { + // constructor may be a proxy + constructor = constructor.prototype?.constructor + if (constructor === this) return true + constructor &&= Object.getPrototypeOf(constructor) + } + return false + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/utils.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/utils.ts new file mode 100644 index 0000000..024d21f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/src/utils.ts @@ -0,0 +1,287 @@ +import { defineProperty } from '@deepseek-ai/cosmokit' +import type { Context, Service } from './index.ts' + +/** Ordered collection of disposable values with O(1) deletion by value. */ +export class DisposableList { + private sn = 0 + private map = new Map() + private weak = new WeakMap() + + get length() { + return this.map.size + } + + push(value: T) { + const sn = ++this.sn + this.map.set(sn, value) + this.weak.set(value, sn) + return () => this.map.delete(sn) + } + + delete(value: T) { + const sn = this.weak.get(value) + if (!sn) return false + return this.map.delete(sn) + } + + clear() { + const values = [...this.map.values()] + this.map.clear() + return values.reverse() + } + + [Symbol.iterator]() { + return this.map.values() + } + + [Symbol.for('nodejs.util.inspect.custom')]() { + return [...this] + } +} + +/** Metadata used by traceable proxies to rebind `ctx` and associated services. */ +export interface Tracker { + associate?: string + property?: string + noShadow?: boolean +} + +/** Shared symbols used to avoid public property-name collisions. */ +export const symbols = { + // internal symbols + shadow: Symbol.for('cordis.shadow'), + receiver: Symbol.for('cordis.receiver'), + original: Symbol.for('cordis.original'), + metadata: Symbol.for('cordis.metadata'), + initHooks: Symbol.for('cordis.initHooks'), + checkProto: Symbol.for('cordis.checkProto'), + + // context symbols + effect: Symbol.for('cordis.effect') as typeof Context.effect, + filter: Symbol.for('cordis.filter') as typeof Context.filter, + isolate: Symbol.for('cordis.isolate') as typeof Context.isolate, + intercept: Symbol.for('cordis.intercept') as typeof Context.intercept, + + // service symbols + init: Symbol.for('cordis.init') as typeof Service.init, + check: Symbol.for('cordis.check') as typeof Service.check, + config: Symbol.for('cordis.config') as typeof Service.config, + invoke: Symbol.for('cordis.invoke') as typeof Service.invoke, + extend: Symbol.for('cordis.extend') as typeof Service.extend, + tracker: Symbol.for('cordis.tracker') as typeof Service.tracker, + resolveConfig: Symbol.for('cordis.resolveConfig') as typeof Service.resolveConfig, +} + +const GeneratorFunction = function* () {}.constructor +const AsyncGeneratorFunction = async function* () {}.constructor + +/** Return true when a plugin callback should be constructed with `new`. */ +export function isConstructor(func: any): func is new (...args: any) => any { + // async function or arrow function + if (!func.prototype) return false + // generator function or malformed definition + // we cannot use below check because `mock.fn()` is proxied + // if (func.prototype.constructor !== func) return false + if (func instanceof GeneratorFunction) return false + // polyfilled AsyncGeneratorFunction === Function + if (AsyncGeneratorFunction !== Function && func instanceof AsyncGeneratorFunction) return false + return true +} + +/** Merge two prototype chains while preserving descriptors from `proto1`. */ +export function joinPrototype(proto1: {}, proto2: {}) { + if (proto1 === Object.prototype) return proto2 + const result = Object.create(joinPrototype(Object.getPrototypeOf(proto1), proto2)) + for (const key of Reflect.ownKeys(proto1)) { + Object.defineProperty(result, key, Object.getOwnPropertyDescriptor(proto1, key)!) + } + return result +} + +/** Return true for non-null objects and functions. */ +export function isObject(value: any): value is {} { + return value && (typeof value === 'object' || typeof value === 'function') +} + +/** Find a property descriptor by walking an object's prototype chain. */ +export function getPropertyDescriptor(target: any, prop: string | symbol) { + let proto = target + while (proto) { + const desc = Reflect.getOwnPropertyDescriptor(proto, prop) + if (desc) return desc + proto = Object.getPrototypeOf(proto) + } +} + +/** Wrap services/functions so method calls see the caller's active context. */ +export function getTraceable(ctx: Context, value: T): T { + if (!isObject(value)) return value + if (Object.hasOwn(value, symbols.shadow)) { + return Object.getPrototypeOf(value) + } + const tracker = value[symbols.tracker] + if (!tracker) return value + return createTraceable(ctx, value, tracker) +} + +/** Return a proxy that overlays readonly or writable properties onto a target. */ +export function withProps(target: any, props?: {}) { + if (!props) return target + return new Proxy(target, { + get: (target, prop, receiver) => { + if (prop in props && prop !== 'constructor') return Reflect.get(props, prop, receiver) + return Reflect.get(target, prop, receiver) + }, + set: (target, prop, value, receiver) => { + if (prop in props && prop !== 'constructor') return Reflect.set(props, prop, value, receiver) + return Reflect.set(target, prop, value, receiver) + }, + }) +} + +function withProp(target: any, prop: string | symbol, value: any) { + return withProps(target, Object.defineProperty(Object.create(null), prop, { + value, + writable: false, + })) +} + +function createShadow(ctx: Context, target: any, property: string | undefined, receiver: any) { + if (!property) return receiver + const origin = Reflect.getOwnPropertyDescriptor(target, property)?.value + if (!origin) return receiver + return withProp(receiver, property, ctx.extend({ [symbols.shadow]: origin })) +} + +function createShadowMethod(ctx: Context, value: any, outer: any, shadow: {}) { + return new Proxy(value, { + apply: (target, thisArg, args) => { + if (thisArg === outer) thisArg = shadow + return getTraceable(ctx, Reflect.apply(target, thisArg, args)) + }, + }) +} + +function createTraceable(ctx: Context, value: any, tracker: Tracker) { + // noShadow services are identity-aware (e.g. logger uses the origin fiber to + // derive its name): keep the shadow ctx so they can read [symbols.shadow] + // and resolve the origin. Non-noShadow services strip — their side effects + // bind to caller, not origin. + if (ctx[symbols.shadow] && !tracker.noShadow) { + ctx = Object.getPrototypeOf(ctx) + } + const proxy = new Proxy(value, { + get: (target, prop, receiver) => { + if (prop === symbols.original) return target + if (prop === tracker.property) return ctx + if (typeof prop === 'symbol') { + return Reflect.get(target, prop, receiver) + } + if (tracker.associate && ctx.reflect.props[`${tracker.associate}.${prop}`]) { + return Reflect.get(ctx, `${tracker.associate}.${prop}`, withProp(ctx, symbols.receiver, receiver)) + } + let shadow: any, innerValue: any + const desc = getPropertyDescriptor(target, prop) + if (desc && 'value' in desc) { + innerValue = desc.value + } else { + shadow = createShadow(ctx, target, tracker.property, receiver) + innerValue = Reflect.get(target, prop, shadow) + } + const innerTracker = innerValue?.[symbols.tracker] + if (innerTracker) { + return createTraceable(ctx, innerValue, innerTracker) + } else if (!tracker.noShadow && typeof innerValue === 'function') { + shadow ??= createShadow(ctx, target, tracker.property, receiver) + return createShadowMethod(ctx, innerValue, receiver, shadow) + } else { + return innerValue + } + }, + set: (target, prop, value, receiver) => { + if (prop === symbols.original) return false + if (prop === tracker.property) return false + if (typeof prop === 'symbol') { + return Reflect.set(target, prop, value, receiver) + } + if (tracker.associate && ctx.reflect.props[`${tracker.associate}.${prop}`]) { + return Reflect.set(ctx, `${tracker.associate}.${prop}`, value, withProp(ctx, symbols.receiver, receiver)) + } + const shadow = createShadow(ctx, target, tracker.property, receiver) + return Reflect.set(target, prop, value, shadow) + }, + apply: (target, thisArg, args) => { + return applyTraceable(proxy, target, thisArg, args) + }, + }) + return proxy +} + +function applyTraceable(proxy: any, value: any, thisArg: any, args: any[]) { + if (!value[symbols.invoke]) return Reflect.apply(value, thisArg, args) + return value[symbols.invoke].apply(proxy, args) +} + +/** Create a callable service object that dispatches through `symbols.invoke`. */ +export function createCallable(name: string, proto: {}, tracker: Tracker) { + const self = function (...args: any[]) { + const proxy = createTraceable(self['ctx'], self, tracker) + return applyTraceable(proxy, self, this, args) + } + defineProperty(self, 'name', name) + return Object.setPrototypeOf(self, proto) +} + +interface StackInfo { + offset: number + error: Error +} + +function handleError(info: StackInfo, reason: any, getOuterStack: () => string[]): never { + const innerLines = info.error.stack!.split('\n') + + // malformed error + if (typeof reason?.stack !== 'string') { + const outerError = new Error(reason) + const lines = outerError.stack!.split('\n') + lines.splice(1, Infinity, ...getOuterStack()) + outerError.stack = lines.join('\n') + throw outerError + } + + // long stack trace + const lines: string[] = reason.stack.split('\n') + let index = lines.indexOf(innerLines[2]) + if (index === -1) throw reason + + index -= info.offset + while (index > 0) { + if (!lines[index - 1].endsWith(' ()')) break + index -= 1 + } + lines.splice(index, Infinity, ...getOuterStack()) + reason.stack = lines.join('\n') + throw reason +} + +/** Run a callback and splice outer call-site frames into thrown async errors. */ +export function composeError(callback: (info: StackInfo) => T, getOuterStack = buildOuterStack()): T { + const info: StackInfo = { offset: 1, error: new Error() } + + try { + const result: any = callback(info) + if (isObject(result) && 'then' in result) { + return (result as any).then(undefined, (reason) => handleError(info, reason, getOuterStack)) as T + } else { + return result + } + } catch (reason: any) { + handleError(info, reason, getOuterStack) + } +} + +/** Capture a lazy stack-frame supplier for later error composition. */ +export function buildOuterStack(offset = 0) { + const outerError = new Error() + return () => outerError.stack!.split('\n').slice(3 + offset) +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cosmokit b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cosmokit new file mode 120000 index 0000000..dfc2397 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cosmokit @@ -0,0 +1 @@ +../../../@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@standard-schema/spec b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@standard-schema/spec new file mode 120000 index 0000000..f2c558c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@standard-schema/spec @@ -0,0 +1 @@ +../../../@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/LICENSE new file mode 100644 index 0000000..9fdec8c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-present Shigma + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/README.md new file mode 100644 index 0000000..5398a14 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/README.md @@ -0,0 +1,24 @@ +# cosmokit + +[![Codecov](https://img.shields.io/codecov/c/github/shigma/cosmokit?style=flat-square)](https://codecov.io/gh/shigma/cosmokit) +[![npm](https://img.shields.io/npm/v/cosmokit?style=flat-square)](https://www.npmjs.com/package/cosmokit) + +A collection of common utilities. + +## Usage + +### Node.js + +```sh +npm install cosmokit +``` + +```ts +import cosmokit from 'cosmokit' +``` + +### Deno + +```ts +import cosmokit from 'npm:cosmokit@latest' +``` diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/index.js new file mode 100644 index 0000000..dd123c4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/index.js @@ -0,0 +1,325 @@ +//#region lib/types/misc.js +/** No-op callback returning `undefined` at runtime and `any` at type level. */ +function noop() {} +/** Return true when a value is `null` or `undefined`. */ +function isNullable(value) { + return value === null || value === void 0; +} +/** Return true when a value is neither `null` nor `undefined`. */ +function isNonNullable(value) { + return !isNullable(value); +} +/** Return true for non-array object values. */ +function isPlainObject(data) { + return data && typeof data === "object" && !Array.isArray(data); +} +/** Filter object entries and return a new object. */ +function filterKeys(object, filter) { + return Object.fromEntries(Object.entries(object).filter(([key, value]) => filter(key, value))); +} +/** Map object values while preserving the original key set. */ +function mapValues(object, transform) { + return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, transform(value, key)])); +} +/** Pick selected keys from an object, optionally including `undefined` values. */ +function pick(source, keys, forced) { + if (!keys) return { ...source }; + const result = {}; + for (const key of keys) if (forced || source[key] !== void 0) result[key] = source[key]; + return result; +} +/** Omit selected keys from a shallow object copy. */ +function omit(source, keys) { + if (!keys) return { ...source }; + const result = { ...source }; + for (const key of keys) Reflect.deleteProperty(result, key); + return result; +} +/** Define a non-enumerable writable property and return the object. */ +function defineProperty(object, key, value) { + return Object.defineProperty(object, key, { + writable: true, + value, + enumerable: false + }); +} +//#endregion +//#region lib/types/array.js +/** Return true when every item in `array2` is present in `array1`. */ +function contain(array1, array2) { + return array2.every((item) => array1.includes(item)); +} +/** Return items that appear in both arrays. */ +function intersection(array1, array2) { + return array1.filter((item) => array2.includes(item)); +} +/** Return items from `array1` that do not appear in `array2`. */ +function difference(array1, array2) { + return array1.filter((item) => !array2.includes(item)); +} +/** Return the set-union of two arrays while preserving first occurrence order. */ +function union(array1, array2) { + return Array.from(new Set([...array1, ...array2])); +} +/** Remove duplicate values while preserving first occurrence order. */ +function deduplicate(array) { + return [...new Set(array)]; +} +/** Remove one item from an array and report whether it was found. */ +function remove(list, item) { + const index = list?.indexOf(item); + if (index >= 0) { + list.splice(index, 1); + return true; + } else return false; +} +/** Normalize nullish, scalar, or array input to an array. */ +function makeArray(source) { + return Array.isArray(source) ? source : isNullable(source) ? [] : [source]; +} +//#endregion +//#region lib/types/types.js +/** Test values using `instanceof` with a `toStringTag` fallback. */ +function is(type, value) { + if (arguments.length === 1) return (value) => is(type, value); + return type in globalThis && value instanceof globalThis[type] || Object.prototype.toString.call(value).slice(8, -1) === type; +} +function isArrayBufferLike(value) { + return is("ArrayBuffer", value) || is("SharedArrayBuffer", value); +} +function isArrayBufferSource(value) { + return isArrayBufferLike(value) || ArrayBuffer.isView(value); +} +/** Binary source detection and base64/hex conversion helpers. */ +var Binary; +(function(Binary) { + Binary.is = isArrayBufferLike; + Binary.isSource = isArrayBufferSource; + function fromSource(source) { + if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength); + else return source; + } + Binary.fromSource = fromSource; + function toBase64(source) { + source = fromSource(source); + if (typeof Buffer !== "undefined") return Buffer.from(source).toString("base64"); + let binary = ""; + const bytes = new Uint8Array(source); + for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]); + return btoa(binary); + } + Binary.toBase64 = toBase64; + function fromBase64(source) { + if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "base64")); + return Uint8Array.from(atob(source), (c) => c.charCodeAt(0)); + } + Binary.fromBase64 = fromBase64; + function toHex(source) { + source = fromSource(source); + if (typeof Buffer !== "undefined") return Buffer.from(source).toString("hex"); + return Array.from(new Uint8Array(source), (byte) => byte.toString(16).padStart(2, "0")).join(""); + } + Binary.toHex = toHex; + function fromHex(source) { + if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "hex")); + const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1); + const buffer = []; + for (let i = 0; i < hex.length; i += 2) buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16)); + return Uint8Array.from(buffer).buffer; + } + Binary.fromHex = fromHex; +})(Binary || (Binary = {})); +/** Decode a base64 string into binary data. */ +const base64ToArrayBuffer = Binary.fromBase64; +/** Encode binary data as base64. */ +const arrayBufferToBase64 = Binary.toBase64; +/** Decode a hex string into binary data. */ +const hexToArrayBuffer = Binary.fromHex; +/** Encode binary data as hex. */ +const arrayBufferToHex = Binary.toHex; +/** Deep-clone common JavaScript values while preserving prototypes and cycles. */ +function clone(source, refs = /* @__PURE__ */ new Map()) { + if (!source || typeof source !== "object") return source; + if (is("Date", source)) return new Date(source.valueOf()); + if (is("RegExp", source)) return new RegExp(source.source, source.flags); + if (isArrayBufferLike(source)) return source.slice(0); + if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength); + const cached = refs.get(source); + if (cached) return cached; + if (Array.isArray(source)) { + const result = []; + refs.set(source, result); + source.forEach((value, index) => { + result[index] = Reflect.apply(clone, null, [value, refs]); + }); + return result; + } + const result = Object.create(Object.getPrototypeOf(source)); + refs.set(source, result); + for (const key of Reflect.ownKeys(source)) { + const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) }; + if ("value" in descriptor) descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs]); + Reflect.defineProperty(result, key, descriptor); + } + return result; +} +/** Deeply compare arrays, dates, regexps, buffers, and plain object fields. */ +function deepEqual(a, b, strict) { + if (a === b) return true; + if (!strict && isNullable(a) && isNullable(b)) return true; + if (typeof a !== typeof b) return false; + if (typeof a !== "object") return false; + if (!a || !b) return false; + function check(test, then) { + return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : void 0; + } + return check(Array.isArray, (a, b) => a.length === b.length && a.every((item, index) => deepEqual(item, b[index]))) ?? check(is("Date"), (a, b) => a.valueOf() === b.valueOf()) ?? check(is("RegExp"), (a, b) => a.source === b.source && a.flags === b.flags) ?? check(isArrayBufferLike, (a, b) => { + if (a.byteLength !== b.byteLength) return false; + const viewA = new Uint8Array(a); + const viewB = new Uint8Array(b); + for (let i = 0; i < viewA.length; i++) if (viewA[i] !== viewB[i]) return false; + return true; + }) ?? Object.keys({ + ...a, + ...b + }).every((key) => deepEqual(a[key], b[key], strict)); +} +//#endregion +//#region lib/types/string.js +/** Uppercase the first character of a string. */ +function capitalize(source) { + return source.charAt(0).toUpperCase() + source.slice(1); +} +/** Lowercase the first character of a string. */ +function uncapitalize(source) { + return source.charAt(0).toLowerCase() + source.slice(1); +} +/** Convert dash or underscore delimited text to camelCase. */ +function camelCase(source) { + return source.replace(/[_-][a-z]/g, (str) => str.slice(1).toUpperCase()); +} +function tokenize(source, delimiters, delimiter) { + const output = []; + let state = 0; + for (let i = 0; i < source.length; i++) { + const code = source.charCodeAt(i); + if (code >= 65 && code <= 90) { + if (state === 1) { + const next = source.charCodeAt(i + 1); + if (next >= 97 && next <= 122) output.push(delimiter); + output.push(code + 32); + } else { + if (state !== 0) output.push(delimiter); + output.push(code + 32); + } + state = 1; + } else if (code >= 97 && code <= 122) { + output.push(code); + state = 2; + } else if (delimiters.includes(code)) { + if (state !== 0) output.push(delimiter); + state = 0; + } else output.push(code); + } + return String.fromCharCode(...output); +} +/** Convert text to dash-delimited parameter case. */ +function paramCase(source) { + return tokenize(source, [45, 95], 45); +} +/** Convert text to underscore-delimited snake case. */ +function snakeCase(source) { + return tokenize(source, [45, 95], 95); +} +/** Runtime alias for `camelCase`. */ +const camelize = camelCase; +/** Runtime alias for `paramCase`. */ +const hyphenate = paramCase; +/** Format a property key as a JavaScript member access suffix. */ +function formatProperty(key) { + if (typeof key !== "string") return `[${key.toString()}]`; + return /^[a-z_$][\w$]*$/i.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`; +} +/** Remove one trailing slash from a path string. */ +function trimSlash(source) { + return source.replace(/\/$/, ""); +} +/** Ensure a path starts with `/` and has no trailing slash. */ +function sanitize(source) { + if (!source.startsWith("/")) source = "/" + source; + return trimSlash(source); +} +//#endregion +//#region lib/types/time.js +/** Time constants plus parsing and formatting helpers. */ +var Time; +(function(Time) { + Time.millisecond = 1; + Time.second = 1e3; + Time.minute = Time.second * 60; + Time.hour = Time.minute * 60; + Time.day = Time.hour * 24; + Time.week = Time.day * 7; + let timezoneOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset(); + function setTimezoneOffset(offset) { + timezoneOffset = offset; + } + Time.setTimezoneOffset = setTimezoneOffset; + function getTimezoneOffset() { + return timezoneOffset; + } + Time.getTimezoneOffset = getTimezoneOffset; + function getDateNumber(date = /* @__PURE__ */ new Date(), offset) { + if (typeof date === "number") date = new Date(date); + if (offset === void 0) offset = timezoneOffset; + return Math.floor((date.valueOf() / Time.minute - offset) / 1440); + } + Time.getDateNumber = getDateNumber; + function fromDateNumber(value, offset) { + const date = new Date(value * Time.day); + if (offset === void 0) offset = timezoneOffset; + return new Date(+date + offset * Time.minute); + } + Time.fromDateNumber = fromDateNumber; + const numeric = /\d+(?:\.\d+)?/.source; + const timeRegExp = new RegExp(`^${[ + "w(?:eek(?:s)?)?", + "d(?:ay(?:s)?)?", + "h(?:our(?:s)?)?", + "m(?:in(?:ute)?(?:s)?)?", + "s(?:ec(?:ond)?(?:s)?)?" + ].map((unit) => `(${numeric}${unit})?`).join("")}$`); + function parseTime(source) { + const capture = timeRegExp.exec(source); + if (!capture) return 0; + return (parseFloat(capture[1]) * Time.week || 0) + (parseFloat(capture[2]) * Time.day || 0) + (parseFloat(capture[3]) * Time.hour || 0) + (parseFloat(capture[4]) * Time.minute || 0) + (parseFloat(capture[5]) * Time.second || 0); + } + Time.parseTime = parseTime; + function parseDate(date) { + const parsed = parseTime(date); + if (parsed) date = Date.now() + parsed; + else if (/^\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).toLocaleDateString()}-${date}`; + else if (/^\d{1,2}-\d{1,2}-\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).getFullYear()}-${date}`; + return date ? new Date(date) : /* @__PURE__ */ new Date(); + } + Time.parseDate = parseDate; + function format(ms) { + const abs = Math.abs(ms); + if (abs >= Time.day - Time.hour / 2) return Math.round(ms / Time.day) + "d"; + else if (abs >= Time.hour - Time.minute / 2) return Math.round(ms / Time.hour) + "h"; + else if (abs >= Time.minute - Time.second / 2) return Math.round(ms / Time.minute) + "m"; + else if (abs >= Time.second) return Math.round(ms / Time.second) + "s"; + return ms + "ms"; + } + Time.format = format; + function toDigits(source, length = 2) { + return source.toString().padStart(length, "0"); + } + Time.toDigits = toDigits; + function template(template, time = /* @__PURE__ */ new Date()) { + return template.replace("yyyy", time.getFullYear().toString()).replace("yy", time.getFullYear().toString().slice(2)).replace("MM", toDigits(time.getMonth() + 1)).replace("dd", toDigits(time.getDate())).replace("hh", toDigits(time.getHours())).replace("mm", toDigits(time.getMinutes())).replace("ss", toDigits(time.getSeconds())).replace("SSS", toDigits(time.getMilliseconds(), 3)); + } + Time.template = template; +})(Time || (Time = {})); +//#endregion +export { Binary, Time, arrayBufferToBase64, arrayBufferToHex, base64ToArrayBuffer, camelCase, camelize, capitalize, clone, contain, deduplicate, deepEqual, defineProperty, difference, filterKeys, formatProperty, hexToArrayBuffer, hyphenate, intersection, is, isNonNullable, isNullable, isPlainObject, makeArray, mapValues, mapValues as valueMap, noop, omit, paramCase, pick, remove, sanitize, snakeCase, trimSlash, uncapitalize, union }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/array.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/array.d.ts new file mode 100644 index 0000000..cf4e281 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/array.d.ts @@ -0,0 +1,15 @@ +/** Return true when every item in `array2` is present in `array1`. */ +export declare function contain(array1: readonly any[], array2: readonly any[]): boolean; +/** Return items that appear in both arrays. */ +export declare function intersection(array1: readonly T[], array2: readonly T[]): T[]; +/** Return items from `array1` that do not appear in `array2`. */ +export declare function difference(array1: readonly S[], array2: readonly any[]): S[]; +/** Return the set-union of two arrays while preserving first occurrence order. */ +export declare function union(array1: readonly T[], array2: readonly T[]): T[]; +/** Remove duplicate values while preserving first occurrence order. */ +export declare function deduplicate(array: readonly T[]): T[]; +/** Remove one item from an array and report whether it was found. */ +export declare function remove(list: T[], item: T): boolean; +/** Normalize nullish, scalar, or array input to an array. */ +export declare function makeArray(source: null | undefined | T | T[]): T[]; +//# sourceMappingURL=array.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/array.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/array.d.ts.map new file mode 100644 index 0000000..89a310f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/array.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"array.d.ts","sourceRoot":"","sources":["../../src/array.ts"],"names":[],"mappings":"AAEA,sEAAsE;AACtE,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,GAAG,EAAE,WAErE;AAED,+CAA+C;AAC/C,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAEzE;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,GAAG,EAAE,OAEzE;AAED,kFAAkF;AAClF,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAElE;AAED,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,OAEjD;AAED,qEAAqE;AACrE,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,WAQ3C;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,CAAC,GAAG,CAAC,EAAE,OAE9D"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/index.d.ts new file mode 100644 index 0000000..37f4769 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/index.d.ts @@ -0,0 +1,11 @@ +/** Array set and normalization helpers. */ +export * from './array.ts'; +/** Runtime type, binary, clone, and equality helpers. */ +export * from './types.ts'; +/** Shared utility types and object helpers. */ +export * from './misc.ts'; +/** String case, path, and property formatting helpers. */ +export * from './string.ts'; +/** Time constants, parsing, and formatting helpers. */ +export * from './time.ts'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/index.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/index.d.ts.map new file mode 100644 index 0000000..a19f391 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,cAAc,YAAY,CAAA;AAC1B,yDAAyD;AACzD,cAAc,YAAY,CAAA;AAC1B,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AACzB,0DAA0D;AAC1D,cAAc,aAAa,CAAA;AAC3B,uDAAuD;AACvD,cAAc,WAAW,CAAA"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts new file mode 100644 index 0000000..2f5fe5e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts @@ -0,0 +1,41 @@ +/** String/symbol keyed dictionary type. */ +export type Dict = { + [key in K]: T; +}; +/** Safely read `T[K]`, returning `never` when `K` is not a key of `T`. */ +export type Get = K extends keyof T ? T[K] : never; +/** Conditional extraction helper with a configurable return type. */ +export type Extract = S extends T ? U : never; +/** Accept a value or an array, unless the value is already an array type. */ +export type MaybeArray = [T] extends [unknown[]] ? T : T | T[]; +/** Wrap a value in `Promise`, preserving the resolved type of existing promises. */ +export type Promisify = Promise ? S : T>; +/** Accept a value or promise unless the value type is already promise-like. */ +export type Awaitable = [T] extends [Promise] ? T : T | Promise; +/** Convert a union type to an intersection type. */ +export type Intersect = (U extends any ? (arg: U) => void : never) extends ((arg: infer I) => void) ? I : never; +/** No-op callback returning `undefined` at runtime and `any` at type level. */ +export declare function noop(): any; +/** Return true when a value is `null` or `undefined`. */ +export declare function isNullable(value: any): value is null | undefined | void; +/** Return true when a value is neither `null` nor `undefined`. */ +export declare function isNonNullable(value: T): value is NonNullable; +/** Return true for non-array object values. */ +export declare function isPlainObject(data: any): any; +/** Filter object entries with a key type guard. */ +export declare function filterKeys(object: Dict, filter: (key: K, value: T) => key is U): Dict; +/** Filter object entries with a boolean predicate. */ +export declare function filterKeys(object: Dict, filter: (key: K, value: T) => boolean): Dict; +/** Map object values while preserving the original key set. */ +export declare function mapValues(object: Dict, transform: (value: T, key: K) => U): Dict; +/** Alias for `mapValues`. */ +export { mapValues as valueMap }; +/** Pick selected keys from an object, optionally including `undefined` values. */ +export declare function pick(source: T, keys?: Iterable, forced?: boolean): Pick; +/** Omit selected keys from a shallow object copy. */ +export declare function omit(source: T, keys?: Iterable): Omit; +/** Define a non-enumerable writable property with a typed key. */ +export declare function defineProperty(object: T, key: K, value: T[K]): T; +/** Define a non-enumerable writable property with an arbitrary key. */ +export declare function defineProperty(object: T, key: K, value: any): T; +//# sourceMappingURL=misc.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts.map new file mode 100644 index 0000000..9113d8e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"misc.d.ts","sourceRoot":"","sources":["../../src/misc.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,MAAM,MAAM,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,MAAM,IAAI;KAAG,GAAG,IAAI,CAAC,GAAG,CAAC;CAAE,CAAA;AACjF,0EAA0E;AAC1E,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;AACnE,qEAAqE;AACrE,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAC1D,6EAA6E;AAC7E,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAA;AACjE,oFAAoF;AACpF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;AACtE,+EAA+E;AAC/E,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAC9E,oDAAoD;AACpD,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAElH,+EAA+E;AAC/E,wBAAgB,IAAI,IAAI,GAAG,CAAG;AAE9B,yDAAyD;AACzD,wBAAgB,UAAU,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,IAAI,GAAG,SAAS,GAAG,IAAI,CAEvE;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,KAAK,IAAI,WAAW,CAAC,CAAC,CAAC,CAElE;AAED,+CAA+C;AAC/C,wBAAgB,aAAa,CAAC,IAAI,EAAE,GAAG,OAEtC;AAED,mDAAmD;AACnD,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AACpI,sDAAsD;AACtD,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAMtH,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,GACY,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAC7H;AAED,6BAA6B;AAC7B,OAAO,EAAE,SAAS,IAAI,QAAQ,EAAE,CAAA;AAEhC,kFAAkF;AAClF,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,OAAO,cAOxG;AAED,qDAAqD;AACrD,wBAAgB,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,cAOvE;AAED,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;AACvF,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,CAAA"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/string.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/string.d.ts new file mode 100644 index 0000000..5929fff --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/string.d.ts @@ -0,0 +1,89 @@ +/** Uppercase the first character of a string. */ +export declare function capitalize(source: string): string; +/** Lowercase the first character of a string. */ +export declare function uncapitalize(source: string): string; +/** Convert dash or underscore delimited text to camelCase. */ +export declare function camelCase(source: string): string; +/** Convert text to dash-delimited parameter case. */ +export declare function paramCase(source: string): string; +/** Convert text to underscore-delimited snake case. */ +export declare function snakeCase(source: string): string; +/** Runtime alias for `camelCase`. */ +export declare const camelize: typeof camelCase; +/** Runtime alias for `paramCase`. */ +export declare const hyphenate: typeof paramCase; +declare namespace Letter { + interface LowerToUpper { + a: 'A'; + b: 'B'; + c: 'C'; + d: 'D'; + e: 'E'; + f: 'F'; + g: 'G'; + h: 'H'; + i: 'I'; + j: 'J'; + k: 'K'; + l: 'L'; + m: 'M'; + n: 'N'; + o: 'O'; + p: 'P'; + q: 'Q'; + r: 'R'; + s: 'S'; + t: 'T'; + u: 'U'; + v: 'V'; + w: 'W'; + x: 'X'; + y: 'Y'; + z: 'Z'; + } + interface UpperToLower { + A: 'a'; + B: 'b'; + C: 'c'; + D: 'd'; + E: 'e'; + F: 'f'; + G: 'g'; + H: 'h'; + I: 'i'; + J: 'j'; + K: 'k'; + L: 'l'; + M: 'm'; + N: 'n'; + O: 'o'; + P: 'p'; + Q: 'q'; + R: 'r'; + S: 's'; + T: 't'; + U: 'u'; + V: 'v'; + W: 'w'; + X: 'x'; + Y: 'y'; + Z: 'z'; + } + export type Upper = keyof UpperToLower; + export type Lower = keyof LowerToUpper; + export type ToUpper = S extends Lower ? LowerToUpper[S] : S; + export type ToLower = S extends Upper ? `${P}${UpperToLower[S]}` : S; + export {}; +} +/** Type-level conversion from dash-delimited text to camelCase. */ +export type camelize = S extends `${infer L}-${infer M}${infer R}` ? `${L}${Letter.ToUpper}${camelize}` : S; +/** Type-level conversion from camelCase text to dash-delimited text. */ +export type hyphenate = S extends `${infer L}${infer R}` ? `${Letter.ToLower}${hyphenate}` : S; +/** Format a property key as a JavaScript member access suffix. */ +export declare function formatProperty(key: keyof any): string; +/** Remove one trailing slash from a path string. */ +export declare function trimSlash(source: string): string; +/** Ensure a path starts with `/` and has no trailing slash. */ +export declare function sanitize(source: string): string; +export {}; +//# sourceMappingURL=string.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/string.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/string.d.ts.map new file mode 100644 index 0000000..75652d1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/string.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../../src/string.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,UAExC;AAED,iDAAiD;AACjD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,UAE1C;AAED,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,UAEvC;AA0CD,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,UAEvC;AAED,uDAAuD;AACvD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,UAEvC;AAED,qCAAqC;AACrC,eAAO,MAAM,QAAQ,kBAAY,CAAA;AACjC,qCAAqC;AACrC,eAAO,MAAM,SAAS,kBAAY,CAAA;AAElC,kBAAU,MAAM,CAAC;IAEf,UAAU,YAAY;QACpB,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QACvG,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;KACxG;IAED,UAAU,YAAY;QACpB,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QACvG,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;QAAC,CAAC,EAAE,GAAG,CAAC;KACxG;IAGD,MAAM,MAAM,KAAK,GAAG,MAAM,YAAY,CAAA;IACtC,MAAM,MAAM,KAAK,GAAG,MAAM,YAAY,CAAA;IAEtC,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAC7E,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,EAAE,IAAI,CAAC,SAAS,KAAK,GAAG,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;;CAC9G;AAGD,mEAAmE;AACnE,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AACnI,wEAAwE;AACxE,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AAG3H,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,UAG5C;AAED,oDAAoD;AACpD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,UAEvC;AAED,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,UAGtC"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/time.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/time.d.ts new file mode 100644 index 0000000..56ac710 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/time.d.ts @@ -0,0 +1,19 @@ +/** Time constants plus parsing and formatting helpers. */ +export declare namespace Time { + const millisecond = 1; + const second = 1000; + const minute: number; + const hour: number; + const day: number; + const week: number; + function setTimezoneOffset(offset: number): void; + function getTimezoneOffset(): number; + function getDateNumber(date?: number | Date, offset?: number): number; + function fromDateNumber(value: number, offset?: number): Date; + function parseTime(source: string): number; + function parseDate(date: string): Date; + function format(ms: number): string; + function toDigits(source: number, length?: number): string; + function template(template: string, time?: Date): string; +} +//# sourceMappingURL=time.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/time.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/time.d.ts.map new file mode 100644 index 0000000..3b25975 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/time.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/time.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,yBAAiB,IAAI,CAAC;IACb,MAAM,WAAW,IAAI,CAAA;IACrB,MAAM,MAAM,OAAO,CAAA;IACnB,MAAM,MAAM,QAAc,CAAA;IAC1B,MAAM,IAAI,QAAc,CAAA;IACxB,MAAM,GAAG,QAAY,CAAA;IACrB,MAAM,IAAI,QAAU,CAAA;IAI3B,SAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,QAE/C;IAED,SAAgB,iBAAiB,WAEhC;IAED,SAAgB,aAAa,CAAC,IAAI,GAAE,MAAM,GAAG,IAAiB,EAAE,MAAM,CAAC,EAAE,MAAM,UAI9E;IAED,SAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,QAI5D;IAWD,SAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,UAQvC;IAED,SAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,QAUrC;IAED,SAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,UAYhC;IAED,SAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,SAAI,UAElD;IAED,SAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,OAAa,UAU3D;CACF"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts new file mode 100644 index 0000000..b94f99b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts @@ -0,0 +1,34 @@ +type GlobalConstructorNames = keyof { + [K in keyof typeof globalThis as typeof globalThis[K] extends abstract new (...args: any) => any ? K : never]: K; +}; +/** Create a predicate for a global constructor name. */ +export declare function is(type: K): (value: any) => value is InstanceType; +/** Test whether a value matches a global constructor name. */ +export declare function is(type: K, value: any): value is InstanceType; +declare function isArrayBufferLike(value: any): value is ArrayBufferLike; +declare function isArrayBufferSource(value: any): value is Binary.Source; +/** Binary source detection and base64/hex conversion helpers. */ +export declare namespace Binary { + type Source = T | ArrayBufferView; + const is: typeof isArrayBufferLike; + const isSource: typeof isArrayBufferSource; + function fromSource(source: Source): T; + function toBase64(source: Source): string; + function fromBase64(source: string): ArrayBuffer | Uint8Array; + function toHex(source: Source): string; + function fromHex(source: string): ArrayBuffer; +} +/** Decode a base64 string into binary data. */ +export declare const base64ToArrayBuffer: typeof Binary.fromBase64; +/** Encode binary data as base64. */ +export declare const arrayBufferToBase64: typeof Binary.toBase64; +/** Decode a hex string into binary data. */ +export declare const hexToArrayBuffer: typeof Binary.fromHex; +/** Encode binary data as hex. */ +export declare const arrayBufferToHex: typeof Binary.toHex; +/** Deep-clone common JavaScript values while preserving prototypes. */ +export declare function clone(source: T): T; +/** Deeply compare arrays, dates, regexps, buffers, and plain object fields. */ +export declare function deepEqual(a: any, b: any, strict?: boolean): boolean; +export {}; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts.map new file mode 100644 index 0000000..7885060 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAEA,KAAK,sBAAsB,GAAG,MAAM;KACjC,CAAC,IAAI,MAAM,OAAO,UAAU,IAAI,OAAO,UAAU,CAAC,CAAC,CAAC,SAAS,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC;CACjH,CAAA;AAED,wDAAwD;AACxD,wBAAgB,EAAE,CAAC,CAAC,SAAS,sBAAsB,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,KAAK,IAAI,YAAY,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;AAC1H,8DAA8D;AAC9D,wBAAgB,EAAE,CAAC,CAAC,SAAS,sBAAsB,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,YAAY,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;AAQtH,iBAAS,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,eAAe,CAE/D;AAED,iBAAS,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,CAE/D;AAED,iEAAiE;AACjE,yBAAiB,MAAM,CAAC;IACtB,KAAY,MAAM,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;IAEjF,MAAM,EAAE,0BAAoB,CAAA;IAC5B,MAAM,QAAQ,4BAAsB,CAAA;IAE3C,SAAgB,UAAU,CAAC,CAAC,SAAS,eAAe,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAO1E;IAED,SAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,UAWtC;IAED,SAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,yCAGxC;IAED,SAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,UAInC;IAED,SAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,eAQrC;CACF;AAED,+CAA+C;AAC/C,eAAO,MAAM,mBAAmB,0BAAoB,CAAA;AACpD,oCAAoC;AACpC,eAAO,MAAM,mBAAmB,wBAAkB,CAAA;AAClD,4CAA4C;AAC5C,eAAO,MAAM,gBAAgB,uBAAiB,CAAA;AAC9C,iCAAiC;AACjC,eAAO,MAAM,gBAAgB,qBAAe,CAAA;AAE5C,uEAAuE;AACvE,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAA;AA8BtC,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAwBnE"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/package.json new file mode 100644 index 0000000..489fd5d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/package.json @@ -0,0 +1,32 @@ +{ + "name": "@deepseek-ai/cosmokit", + "description": "A collection of common utilities", + "version": "1.8.2", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "vendor/cosmokit" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/types/**/*.d.ts", + "lib/types/**/*.d.ts.map", + "src" + ], + "author": "Shigma ", + "license": "MIT" +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/array.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/array.ts new file mode 100644 index 0000000..18ed5e4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/array.ts @@ -0,0 +1,42 @@ +import { isNullable } from './misc.ts' + +/** Return true when every item in `array2` is present in `array1`. */ +export function contain(array1: readonly any[], array2: readonly any[]) { + return array2.every(item => array1.includes(item)) +} + +/** Return items that appear in both arrays. */ +export function intersection(array1: readonly T[], array2: readonly T[]) { + return array1.filter(item => array2.includes(item)) +} + +/** Return items from `array1` that do not appear in `array2`. */ +export function difference(array1: readonly S[], array2: readonly any[]) { + return array1.filter(item => !array2.includes(item)) +} + +/** Return the set-union of two arrays while preserving first occurrence order. */ +export function union(array1: readonly T[], array2: readonly T[]) { + return Array.from(new Set([...array1, ...array2])) +} + +/** Remove duplicate values while preserving first occurrence order. */ +export function deduplicate(array: readonly T[]) { + return [...new Set(array)] +} + +/** Remove one item from an array and report whether it was found. */ +export function remove(list: T[], item: T) { + const index = list?.indexOf(item) + if (index >= 0) { + list.splice(index, 1) + return true + } else { + return false + } +} + +/** Normalize nullish, scalar, or array input to an array. */ +export function makeArray(source: null | undefined | T | T[]) { + return Array.isArray(source) ? source : isNullable(source) ? [] : [source] +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/index.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/index.ts new file mode 100644 index 0000000..9fe48de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/index.ts @@ -0,0 +1,10 @@ +/** Array set and normalization helpers. */ +export * from './array.ts' +/** Runtime type, binary, clone, and equality helpers. */ +export * from './types.ts' +/** Shared utility types and object helpers. */ +export * from './misc.ts' +/** String case, path, and property formatting helpers. */ +export * from './string.ts' +/** Time constants, parsing, and formatting helpers. */ +export * from './time.ts' diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/misc.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/misc.ts new file mode 100644 index 0000000..11ed0a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/misc.ts @@ -0,0 +1,78 @@ +/** String/symbol keyed dictionary type. */ +export type Dict = { [key in K]: T } +/** Safely read `T[K]`, returning `never` when `K` is not a key of `T`. */ +export type Get = K extends keyof T ? T[K] : never +/** Conditional extraction helper with a configurable return type. */ +export type Extract = S extends T ? U : never +/** Accept a value or an array, unless the value is already an array type. */ +export type MaybeArray = [T] extends [unknown[]] ? T : T | T[] +/** Wrap a value in `Promise`, preserving the resolved type of existing promises. */ +export type Promisify = Promise ? S : T> +/** Accept a value or promise unless the value type is already promise-like. */ +export type Awaitable = [T] extends [Promise] ? T : T | Promise +/** Convert a union type to an intersection type. */ +export type Intersect = (U extends any ? (arg: U) => void : never) extends ((arg: infer I) => void) ? I : never + +/** No-op callback returning `undefined` at runtime and `any` at type level. */ +export function noop(): any {} + +/** Return true when a value is `null` or `undefined`. */ +export function isNullable(value: any): value is null | undefined | void { + return value === null || value === undefined +} + +/** Return true when a value is neither `null` nor `undefined`. */ +export function isNonNullable(value: T): value is NonNullable { + return !isNullable(value) +} + +/** Return true for non-array object values. */ +export function isPlainObject(data: any) { + return data && typeof data === 'object' && !Array.isArray(data) +} + +/** Filter object entries with a key type guard. */ +export function filterKeys(object: Dict, filter: (key: K, value: T) => key is U): Dict +/** Filter object entries with a boolean predicate. */ +export function filterKeys(object: Dict, filter: (key: K, value: T) => boolean): Dict +/** Filter object entries and return a new object. */ +export function filterKeys(object: {}, filter: (key: string, value: any) => boolean) { + return Object.fromEntries(Object.entries(object).filter(([key, value]) => filter(key, value))) +} + +/** Map object values while preserving the original key set. */ +export function mapValues(object: Dict, transform: (value: T, key: K) => U) { + return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, (transform as any)(value, key)])) as Dict +} + +/** Alias for `mapValues`. */ +export { mapValues as valueMap } + +/** Pick selected keys from an object, optionally including `undefined` values. */ +export function pick(source: T, keys?: Iterable, forced?: boolean) { + if (!keys) return { ...source } + const result = {} as Pick + for (const key of keys) { + if (forced || source[key] !== undefined) result[key] = source[key] + } + return result +} + +/** Omit selected keys from a shallow object copy. */ +export function omit(source: T, keys?: Iterable) { + if (!keys) return { ...source } + const result = { ...source } as Omit + for (const key of keys) { + Reflect.deleteProperty(result, key) + } + return result +} + +/** Define a non-enumerable writable property with a typed key. */ +export function defineProperty(object: T, key: K, value: T[K]): T +/** Define a non-enumerable writable property with an arbitrary key. */ +export function defineProperty(object: T, key: K, value: any): T +/** Define a non-enumerable writable property and return the object. */ +export function defineProperty(object: T, key: K, value: any) { + return Object.defineProperty(object, key, { writable: true, value, enumerable: false }) +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/string.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/string.ts new file mode 100644 index 0000000..6f70844 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/string.ts @@ -0,0 +1,113 @@ +/** Uppercase the first character of a string. */ +export function capitalize(source: string) { + return source.charAt(0).toUpperCase() + source.slice(1) +} + +/** Lowercase the first character of a string. */ +export function uncapitalize(source: string) { + return source.charAt(0).toLowerCase() + source.slice(1) +} + +/** Convert dash or underscore delimited text to camelCase. */ +export function camelCase(source: string) { + return source.replace(/[_-][a-z]/g, str => str.slice(1).toUpperCase()) +} + +const enum State { + DELIM, + UPPER, + LOWER, +} + +function tokenize(source: string, delimiters: number[], delimiter: number) { + const output: number[] = [] + let state = State.DELIM + for (let i = 0; i < source.length; i++) { + const code = source.charCodeAt(i) + if (code >= 65 && code <= 90) { + if (state === State.UPPER) { + const next = source.charCodeAt(i + 1) + if (next >= 97 && next <= 122) { + output.push(delimiter) + } + output.push(code + 32) + } else { + if (state !== State.DELIM) { + output.push(delimiter) + } + output.push(code + 32) + } + state = State.UPPER + } else if (code >= 97 && code <= 122) { + output.push(code) + state = State.LOWER + } else if (delimiters.includes(code)) { + if (state !== State.DELIM) { + output.push(delimiter) + } + state = State.DELIM + } else { + output.push(code) + } + } + return String.fromCharCode(...output) +} + +/** Convert text to dash-delimited parameter case. */ +export function paramCase(source: string) { + return tokenize(source, [45, 95], 45) +} + +/** Convert text to underscore-delimited snake case. */ +export function snakeCase(source: string) { + return tokenize(source, [45, 95], 95) +} + +/** Runtime alias for `camelCase`. */ +export const camelize = camelCase +/** Runtime alias for `paramCase`. */ +export const hyphenate = paramCase + +namespace Letter { + /* eslint-disable @typescript-eslint/member-delimiter-style */ + interface LowerToUpper { + a: 'A', b: 'B', c: 'C', d: 'D', e: 'E', f: 'F', g: 'G', h: 'H', i: 'I', j: 'J', k: 'K', l: 'L', m: 'M', + n: 'N', o: 'O', p: 'P', q: 'Q', r: 'R', s: 'S', t: 'T', u: 'U', v: 'V', w: 'W', x: 'X', y: 'Y', z: 'Z', + } + + interface UpperToLower { + A: 'a', B: 'b', C: 'c', D: 'd', E: 'e', F: 'f', G: 'g', H: 'h', I: 'i', J: 'j', K: 'k', L: 'l', M: 'm', + N: 'n', O: 'o', P: 'p', Q: 'q', R: 'r', S: 's', T: 't', U: 'u', V: 'v', W: 'w', X: 'x', Y: 'y', Z: 'z', + } + /* eslint-enable @typescript-eslint/member-delimiter-style */ + + export type Upper = keyof UpperToLower + export type Lower = keyof LowerToUpper + + export type ToUpper = S extends Lower ? LowerToUpper[S] : S + export type ToLower = S extends Upper ? `${P}${UpperToLower[S]}` : S +} + +/* eslint-disable @typescript-eslint/naming-convention */ +/** Type-level conversion from dash-delimited text to camelCase. */ +export type camelize = S extends `${infer L}-${infer M}${infer R}` ? `${L}${Letter.ToUpper}${camelize}` : S +/** Type-level conversion from camelCase text to dash-delimited text. */ +export type hyphenate = S extends `${infer L}${infer R}` ? `${Letter.ToLower}${hyphenate}` : S +/* eslint-enable @typescript-eslint/naming-convention */ + +/** Format a property key as a JavaScript member access suffix. */ +export function formatProperty(key: keyof any) { + if (typeof key !== 'string') return `[${key.toString()}]` + return /^[a-z_$][\w$]*$/i.test(key) ? `.${key}` : `[${JSON.stringify(key)}]` +} + +/** Remove one trailing slash from a path string. */ +export function trimSlash(source: string) { + return source.replace(/\/$/, '') +} + +/** Ensure a path starts with `/` and has no trailing slash. */ +export function sanitize(source: string) { + if (!source.startsWith('/')) source = '/' + source + return trimSlash(source) +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/time.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/time.ts new file mode 100644 index 0000000..6f90654 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/time.ts @@ -0,0 +1,92 @@ +/** Time constants plus parsing and formatting helpers. */ +export namespace Time { + export const millisecond = 1 + export const second = 1000 + export const minute = second * 60 + export const hour = minute * 60 + export const day = hour * 24 + export const week = day * 7 + + let timezoneOffset = new Date().getTimezoneOffset() + + export function setTimezoneOffset(offset: number) { + timezoneOffset = offset + } + + export function getTimezoneOffset() { + return timezoneOffset + } + + export function getDateNumber(date: number | Date = new Date(), offset?: number) { + if (typeof date === 'number') date = new Date(date) + if (offset === undefined) offset = timezoneOffset + return Math.floor((date.valueOf() / minute - offset) / 1440) + } + + export function fromDateNumber(value: number, offset?: number) { + const date = new Date(value * day) + if (offset === undefined) offset = timezoneOffset + return new Date(+date + offset * minute) + } + + const numeric = /\d+(?:\.\d+)?/.source + const timeRegExp = new RegExp(`^${[ + 'w(?:eek(?:s)?)?', + 'd(?:ay(?:s)?)?', + 'h(?:our(?:s)?)?', + 'm(?:in(?:ute)?(?:s)?)?', + 's(?:ec(?:ond)?(?:s)?)?', + ].map(unit => `(${numeric}${unit})?`).join('')}$`) + + export function parseTime(source: string) { + const capture = timeRegExp.exec(source) + if (!capture) return 0 + return (parseFloat(capture[1]) * week || 0) + + (parseFloat(capture[2]) * day || 0) + + (parseFloat(capture[3]) * hour || 0) + + (parseFloat(capture[4]) * minute || 0) + + (parseFloat(capture[5]) * second || 0) + } + + export function parseDate(date: string) { + const parsed = parseTime(date) + if (parsed) { + date = Date.now() + parsed as any + } else if (/^\d{1,2}(:\d{1,2}){1,2}$/.test(date)) { + date = `${new Date().toLocaleDateString()}-${date}` + } else if (/^\d{1,2}-\d{1,2}-\d{1,2}(:\d{1,2}){1,2}$/.test(date)) { + date = `${new Date().getFullYear()}-${date}` + } + return date ? new Date(date) : new Date() + } + + export function format(ms: number) { + const abs = Math.abs(ms) + if (abs >= day - hour / 2) { + return Math.round(ms / day) + 'd' + } else if (abs >= hour - minute / 2) { + return Math.round(ms / hour) + 'h' + } else if (abs >= minute - second / 2) { + return Math.round(ms / minute) + 'm' + } else if (abs >= second) { + return Math.round(ms / second) + 's' + } + return ms + 'ms' + } + + export function toDigits(source: number, length = 2) { + return source.toString().padStart(length, '0') + } + + export function template(template: string, time = new Date()) { + return template + .replace('yyyy', time.getFullYear().toString()) + .replace('yy', time.getFullYear().toString().slice(2)) + .replace('MM', toDigits(time.getMonth() + 1)) + .replace('dd', toDigits(time.getDate())) + .replace('hh', toDigits(time.getHours())) + .replace('mm', toDigits(time.getMinutes())) + .replace('ss', toDigits(time.getSeconds())) + .replace('SSS', toDigits(time.getMilliseconds(), 3)) + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/types.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/types.ts new file mode 100644 index 0000000..499a462 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/src/types.ts @@ -0,0 +1,142 @@ +import { isNullable } from './misc.ts' + +type GlobalConstructorNames = keyof { + [K in keyof typeof globalThis as typeof globalThis[K] extends abstract new (...args: any) => any ? K : never]: K +} + +/** Create a predicate for a global constructor name. */ +export function is(type: K): (value: any) => value is InstanceType +/** Test whether a value matches a global constructor name. */ +export function is(type: K, value: any): value is InstanceType +/** Test values using `instanceof` with a `toStringTag` fallback. */ +export function is(type: K, value?: any): any { + if (arguments.length === 1) return (value: any) => is(type, value) + return type in globalThis && value instanceof (globalThis[type] as any) + || Object.prototype.toString.call(value).slice(8, -1) === type +} + +function isArrayBufferLike(value: any): value is ArrayBufferLike { + return is('ArrayBuffer', value) || is('SharedArrayBuffer', value) +} + +function isArrayBufferSource(value: any): value is Binary.Source { + return isArrayBufferLike(value) || ArrayBuffer.isView(value) +} + +/** Binary source detection and base64/hex conversion helpers. */ +export namespace Binary { + export type Source = T | ArrayBufferView + + export const is = isArrayBufferLike + export const isSource = isArrayBufferSource + + export function fromSource(source: Source): T { + if (ArrayBuffer.isView(source)) { + // https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer#answer-31394257 + return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength) as T + } else { + return source + } + } + + export function toBase64(source: Source) { + source = fromSource(source) + if (typeof Buffer !== 'undefined') { + return Buffer.from(source).toString('base64') + } + let binary = '' + const bytes = new Uint8Array(source) + for (let i = 0; i < bytes.byteLength; i++) { + binary += String.fromCharCode(bytes[i]) + } + return btoa(binary) + } + + export function fromBase64(source: string) { + if (typeof Buffer !== 'undefined') return fromSource(Buffer.from(source, 'base64')) + return Uint8Array.from(atob(source), c => c.charCodeAt(0)) + } + + export function toHex(source: Source) { + source = fromSource(source) + if (typeof Buffer !== 'undefined') return Buffer.from(source).toString('hex') + return Array.from(new Uint8Array(source), byte => byte.toString(16).padStart(2, '0')).join('') + } + + export function fromHex(source: string) { + if (typeof Buffer !== 'undefined') return fromSource(Buffer.from(source, 'hex')) + const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1) + const buffer: number[] = [] + for (let i = 0; i < hex.length; i += 2) { + buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16)) + } + return Uint8Array.from(buffer).buffer + } +} + +/** Decode a base64 string into binary data. */ +export const base64ToArrayBuffer = Binary.fromBase64 +/** Encode binary data as base64. */ +export const arrayBufferToBase64 = Binary.toBase64 +/** Decode a hex string into binary data. */ +export const hexToArrayBuffer = Binary.fromHex +/** Encode binary data as hex. */ +export const arrayBufferToHex = Binary.toHex + +/** Deep-clone common JavaScript values while preserving prototypes. */ +export function clone(source: T): T +/** Deep-clone common JavaScript values while preserving prototypes and cycles. */ +export function clone(source: any, refs = new Map()) { + if (!source || typeof source !== 'object') return source + if (is('Date', source)) return new Date(source.valueOf()) + if (is('RegExp', source)) return new RegExp(source.source, source.flags) + if (isArrayBufferLike(source)) return source.slice(0) + if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength) + const cached = refs.get(source) + if (cached) return cached + if (Array.isArray(source)) { + const result: any[] = [] + refs.set(source, result) + source.forEach((value, index) => { + result[index] = Reflect.apply(clone, null, [value, refs]) + }) + return result + } + const result = Object.create(Object.getPrototypeOf(source)) + refs.set(source, result) + for (const key of Reflect.ownKeys(source)) { + const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) } + if ('value' in descriptor) { + descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs]) + } + Reflect.defineProperty(result, key, descriptor) + } + return result +} + +/** Deeply compare arrays, dates, regexps, buffers, and plain object fields. */ +export function deepEqual(a: any, b: any, strict?: boolean): boolean { + if (a === b) return true + if (!strict && isNullable(a) && isNullable(b)) return true + if (typeof a !== typeof b) return false + if (typeof a !== 'object') return false + if (!a || !b) return false + + function check(test: (x: any) => x is T, then: (a: T, b: T) => boolean) { + return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : undefined + } + + return check(Array.isArray, (a, b) => a.length === b.length && a.every((item, index) => deepEqual(item, b[index]))) + ?? check(is('Date'), (a, b) => a.valueOf() === b.valueOf()) + ?? check(is('RegExp'), (a, b) => a.source === b.source && a.flags === b.flags) + ?? check(isArrayBufferLike, (a, b) => { + if (a.byteLength !== b.byteLength) return false + const viewA = new Uint8Array(a) + const viewB = new Uint8Array(b) + for (let i = 0; i < viewA.length; i++) { + if (viewA[i] !== viewB[i]) return false + } + return true + }) + ?? Object.keys({ ...a, ...b }).every(key => deepEqual(a[key], b[key], strict)) +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.i18n.yaml new file mode 100644 index 0000000..82f76f2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/agent-default-model/README.md +README.md: 4b9e06c1f68150633afa8aad752845f6d96dda85 +README.zh.md: f3b8acb1a64e9a80aece87ac71f49a963d573352 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.md new file mode 100644 index 0000000..4b9e06c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.md @@ -0,0 +1,25 @@ +# @deepseek-ai/dsh-agent-default-model + +English | [中文](README.zh.md) + +The deployment default used when an entry point creates an Agent that has no session-local model selection. `AgentDefaultModelConfig` provides `ctx.agentDefaultModel`; direct entry points such as `dsh --profile headless` and Host-backed entry points such as ApiProxy read the same service instead of owning parallel provider/model defaults. + +The plugin config requires `{ provider, model }`. That composition entry is the base of the `agent-default-model` Settings section; a mounted settings provider layers the user's choice over it and changes are visible on the next `currentSelection()` read. `reasoningEffort` belongs to the Settings section but deliberately not to plugin config: a complete saved selection can clear an effort when the next selected model has none, while a composition value would be inherited again. + +- `ctx.agentDefaultModel.currentSelection()` returns a detached `{ provider, model, reasoningEffort? }` selection for a newly created Agent. +- `ctx.agentDefaultModel.saveSelection(selection)` saves the complete user selection. Without a settings provider it is a no-op and the composition entry remains current. + +The service does not validate catalog membership. A provider route may serve an unadvertised model, and the consumer that actually opens a model request owns availability diagnostics. + +## Model Experience + +Indirectly, through the provider/model selection supplied to an entry point; request assembly and adapters own the model-visible request. + +#### KV Cache effect + +Changing the default affects only Agents that subsequently resolve from it. An existing session whose request log already names a selection keeps that selection, so this service does not invalidate its established prefix. + +## Known Limitations and Deferred Work + +- The service owns one process-wide default; per-session selection remains the entry point's responsibility. +- Without a settings provider, `saveSelection()` cannot retain a selection for a later Agent. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.zh.md new file mode 100644 index 0000000..f3b8acb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/README.zh.md @@ -0,0 +1,25 @@ +# @deepseek-ai/dsh-agent-default-model + +[English](README.md) | 中文 + +该部署默认值供入口在创建尚无会话级模型选择的 Agent 时使用。`AgentDefaultModelConfig` 提供 `ctx.agentDefaultModel`;`dsh --profile headless` 这类直接入口与 ApiProxy 这类由 Host 支撑的入口读取同一服务,而不是分别持有平行的提供方/模型默认值。 + +插件配置必须提供 `{ provider, model }`。该组合配置项构成 Settings 中 `agent-default-model` 分节的基础层;挂载的设置提供方在其上叠加用户选择,更改会在下一次调用 `currentSelection()` 时可见。`reasoningEffort` 属于该 Settings 分节,但特意不属于插件配置:完整保存的选择必须能在下一个选定模型没有推理(reasoning)强度时清除旧值,而组合配置值会再次被继承。 + +- `ctx.agentDefaultModel.currentSelection()` 返回一份独立的 `{ provider, model, reasoningEffort? }` 选择,供新创建的 Agent 使用。 +- `ctx.agentDefaultModel.saveSelection(selection)` 保存完整的用户选择。未挂载设置提供方时,此调用不执行任何操作,组合配置项仍为当前值。 + +该服务不校验目录成员关系。提供方路由可以服务未在目录中公布的模型;实际发起模型请求的消费方负责可用性诊断。 + +## 模型体验 + +通过提供给入口的提供方/模型选择间接影响;模型可见请求由请求组装与适配器负责。 + +#### KV Cache 影响 + +更改默认值只影响之后从该默认值解析选择的 Agent。请求日志已经指明选择的现有会话仍沿用该选择,因此本服务不会使其已建立的前缀失效。 + +## 已知限制与暂缓事项 + +- 该服务只拥有一项进程级默认值;每个会话的选择仍由入口负责。 +- 未挂载设置提供方时,`saveSelection()` 无法保留选择供后续 Agent 使用。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js new file mode 100644 index 0000000..0a9be80 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js @@ -0,0 +1,74 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { ReasoningEffortId } from "@deepseek-ai/dsh-llm"; +import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings"; +//#region lib/types/index.js +/** +* Default model selection for an Agent without a session-specific selection. +* +* @module @deepseek-ai/dsh-agent-default-model +*/ +/** Settings namespace carrying the default model selection for future Agents. */ +const AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE = settingsNamespace("agent-default-model"); +/** Schema of the default Agent model settings section. */ +const AGENT_DEFAULT_MODEL_SETTINGS_SCHEMA = z.object({ + provider: z.string().required(), + model: z.string().required(), + reasoningEffort: z.string() +}); +/** Project stored settings onto the Agent-facing selection type. */ +function selection(settings) { + return { + provider: settings.provider, + model: settings.model, + ...settings.reasoningEffort === void 0 ? {} : { reasoningEffort: ReasoningEffortId(settings.reasoningEffort) } + }; +} +/** +* Owns the default model selection independently of any Host or transport. +* The composition entry remains usable without a settings provider; when one +* is mounted, its user layer is read live. +*/ +var AgentDefaultModelConfig = class extends Service { + static Config = z.object({ + provider: z.string().required(), + model: z.string().required() + }); + source; + constructor(ctx, config) { + super(ctx, "agentDefaultModel"); + const entry = { + provider: config.provider, + model: config.model + }; + this.source = () => entry; + installSettingsSection(ctx, AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE, AGENT_DEFAULT_MODEL_SETTINGS_SCHEMA, entry, { + setSource: (current) => { + this.source = current; + }, + onChange: () => {} + }); + } + /** + * Read the current default model selection. + * @returns a detached provider, model, and optional reasoning selection. + */ + currentSelection() { + return selection(this.source()); + } + /** + * Save the complete default model selection. A deployment without a settings + * provider keeps its composition entry. + * @param next - resolved selection accepted by an entry point. + * @returns fulfillment after the optional settings write settles. + */ + async saveSelection(next) { + await this.ctx.get("settings")?.replace(AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE, { + provider: next.provider, + model: next.model, + ...next.reasoningEffort === void 0 ? {} : { reasoningEffort: String(next.reasoningEffort) } + }); + } +}; +//#endregion +export { AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE, AGENT_DEFAULT_MODEL_SETTINGS_SCHEMA, AgentDefaultModelConfig, AgentDefaultModelConfig as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/invariant.js new file mode 100644 index 0000000..d35ad21 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/invariant.js @@ -0,0 +1,25 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for the default Agent model selection. +* +* The service owns no independent event relationship: settings registration +* already validates every mutable value before `currentSelection()` can observe it. +* The empty installer keeps that absence explicit in composed invariant sets. +* +* @module @deepseek-ai/dsh-agent-default-model/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-agent-default-model"; +/** Cordis companion plugin name. */ +const name = "agent-default-model-invariant"; +/** Services required before the companion can register. */ +const inject = ["invariants"]; +/** No runtime invariant: settings validation owns the only mutable-value relationship. */ +const install = () => {}; +/** +* Register the intentionally empty invariant contribution. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/index.d.ts new file mode 100644 index 0000000..3fad5dd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/index.d.ts @@ -0,0 +1,58 @@ +/** + * Default model selection for an Agent without a session-specific selection. + * + * @module @deepseek-ai/dsh-agent-default-model + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { ModelSelection } from '@deepseek-ai/dsh-agent'; +declare module '@deepseek-ai/cordis' { + interface Context { + /** Default model selection for Agents created without an explicit model. */ + agentDefaultModel: AgentDefaultModelConfig; + } +} +/** Settings namespace carrying the default model selection for future Agents. */ +export declare const AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE: import("@deepseek-ai/dsh-settings").SettingsNamespace; +/** Stored and composed default model selection. */ +export interface AgentDefaultModelSettings { + /** Registered provider route. */ + provider: string; + /** Provider-owned model id. */ + model: string; + /** Adapter-owned reasoning effort, or provider/default behavior when absent. */ + reasoningEffort?: string; +} +/** Schema of the default Agent model settings section. */ +export declare const AGENT_DEFAULT_MODEL_SETTINGS_SCHEMA: z; +/** Composition entry for the default model selection. */ +export interface Config { + /** Registered provider route. */ + provider: string; + /** Provider-owned model id. */ + model: string; +} +/** + * Owns the default model selection independently of any Host or transport. + * The composition entry remains usable without a settings provider; when one + * is mounted, its user layer is read live. + */ +export declare class AgentDefaultModelConfig extends Service { + static Config: z; + private source; + constructor(ctx: Context, config: Config); + /** + * Read the current default model selection. + * @returns a detached provider, model, and optional reasoning selection. + */ + currentSelection(): ModelSelection; + /** + * Save the complete default model selection. A deployment without a settings + * provider keeps its composition entry. + * @param next - resolved selection accepted by an entry point. + * @returns fulfillment after the optional settings write settles. + */ + saveSelection(next: ModelSelection): Promise; +} +export default AgentDefaultModelConfig; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/invariant.d.ts new file mode 100644 index 0000000..3c97224 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/invariant.d.ts @@ -0,0 +1,21 @@ +/** + * Package-owned invariant companion for the default Agent model selection. + * + * The service owns no independent event relationship: settings registration + * already validates every mutable value before `currentSelection()` can observe it. + * The empty installer keeps that absence explicit in composed invariant sets. + * + * @module @deepseek-ai/dsh-agent-default-model/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "agent-default-model-invariant"; +/** Services required before the companion can register. */ +export declare const inject: string[]; +/** + * Register the intentionally empty invariant contribution. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/package.json new file mode 100644 index 0000000..f3a2d07 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model/package.json @@ -0,0 +1,51 @@ +{ + "name": "@deepseek-ai/dsh-agent-default-model", + "description": "Default model selection shared by Agent entry points", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/agent-default-model" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-settings b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-settings new file mode 120000 index 0000000..810b363 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-settings @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.i18n.yaml new file mode 100644 index 0000000..82f76f2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/agent-default-model/README.md +README.md: 4b9e06c1f68150633afa8aad752845f6d96dda85 +README.zh.md: f3b8acb1a64e9a80aece87ac71f49a963d573352 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.md new file mode 100644 index 0000000..4b9e06c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.md @@ -0,0 +1,25 @@ +# @deepseek-ai/dsh-agent-default-model + +English | [中文](README.zh.md) + +The deployment default used when an entry point creates an Agent that has no session-local model selection. `AgentDefaultModelConfig` provides `ctx.agentDefaultModel`; direct entry points such as `dsh --profile headless` and Host-backed entry points such as ApiProxy read the same service instead of owning parallel provider/model defaults. + +The plugin config requires `{ provider, model }`. That composition entry is the base of the `agent-default-model` Settings section; a mounted settings provider layers the user's choice over it and changes are visible on the next `currentSelection()` read. `reasoningEffort` belongs to the Settings section but deliberately not to plugin config: a complete saved selection can clear an effort when the next selected model has none, while a composition value would be inherited again. + +- `ctx.agentDefaultModel.currentSelection()` returns a detached `{ provider, model, reasoningEffort? }` selection for a newly created Agent. +- `ctx.agentDefaultModel.saveSelection(selection)` saves the complete user selection. Without a settings provider it is a no-op and the composition entry remains current. + +The service does not validate catalog membership. A provider route may serve an unadvertised model, and the consumer that actually opens a model request owns availability diagnostics. + +## Model Experience + +Indirectly, through the provider/model selection supplied to an entry point; request assembly and adapters own the model-visible request. + +#### KV Cache effect + +Changing the default affects only Agents that subsequently resolve from it. An existing session whose request log already names a selection keeps that selection, so this service does not invalidate its established prefix. + +## Known Limitations and Deferred Work + +- The service owns one process-wide default; per-session selection remains the entry point's responsibility. +- Without a settings provider, `saveSelection()` cannot retain a selection for a later Agent. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.zh.md new file mode 100644 index 0000000..f3b8acb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/README.zh.md @@ -0,0 +1,25 @@ +# @deepseek-ai/dsh-agent-default-model + +[English](README.md) | 中文 + +该部署默认值供入口在创建尚无会话级模型选择的 Agent 时使用。`AgentDefaultModelConfig` 提供 `ctx.agentDefaultModel`;`dsh --profile headless` 这类直接入口与 ApiProxy 这类由 Host 支撑的入口读取同一服务,而不是分别持有平行的提供方/模型默认值。 + +插件配置必须提供 `{ provider, model }`。该组合配置项构成 Settings 中 `agent-default-model` 分节的基础层;挂载的设置提供方在其上叠加用户选择,更改会在下一次调用 `currentSelection()` 时可见。`reasoningEffort` 属于该 Settings 分节,但特意不属于插件配置:完整保存的选择必须能在下一个选定模型没有推理(reasoning)强度时清除旧值,而组合配置值会再次被继承。 + +- `ctx.agentDefaultModel.currentSelection()` 返回一份独立的 `{ provider, model, reasoningEffort? }` 选择,供新创建的 Agent 使用。 +- `ctx.agentDefaultModel.saveSelection(selection)` 保存完整的用户选择。未挂载设置提供方时,此调用不执行任何操作,组合配置项仍为当前值。 + +该服务不校验目录成员关系。提供方路由可以服务未在目录中公布的模型;实际发起模型请求的消费方负责可用性诊断。 + +## 模型体验 + +通过提供给入口的提供方/模型选择间接影响;模型可见请求由请求组装与适配器负责。 + +#### KV Cache 影响 + +更改默认值只影响之后从该默认值解析选择的 Agent。请求日志已经指明选择的现有会话仍沿用该选择,因此本服务不会使其已建立的前缀失效。 + +## 已知限制与暂缓事项 + +- 该服务只拥有一项进程级默认值;每个会话的选择仍由入口负责。 +- 未挂载设置提供方时,`saveSelection()` 无法保留选择供后续 Agent 使用。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js new file mode 100644 index 0000000..0a9be80 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js @@ -0,0 +1,74 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { ReasoningEffortId } from "@deepseek-ai/dsh-llm"; +import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings"; +//#region lib/types/index.js +/** +* Default model selection for an Agent without a session-specific selection. +* +* @module @deepseek-ai/dsh-agent-default-model +*/ +/** Settings namespace carrying the default model selection for future Agents. */ +const AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE = settingsNamespace("agent-default-model"); +/** Schema of the default Agent model settings section. */ +const AGENT_DEFAULT_MODEL_SETTINGS_SCHEMA = z.object({ + provider: z.string().required(), + model: z.string().required(), + reasoningEffort: z.string() +}); +/** Project stored settings onto the Agent-facing selection type. */ +function selection(settings) { + return { + provider: settings.provider, + model: settings.model, + ...settings.reasoningEffort === void 0 ? {} : { reasoningEffort: ReasoningEffortId(settings.reasoningEffort) } + }; +} +/** +* Owns the default model selection independently of any Host or transport. +* The composition entry remains usable without a settings provider; when one +* is mounted, its user layer is read live. +*/ +var AgentDefaultModelConfig = class extends Service { + static Config = z.object({ + provider: z.string().required(), + model: z.string().required() + }); + source; + constructor(ctx, config) { + super(ctx, "agentDefaultModel"); + const entry = { + provider: config.provider, + model: config.model + }; + this.source = () => entry; + installSettingsSection(ctx, AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE, AGENT_DEFAULT_MODEL_SETTINGS_SCHEMA, entry, { + setSource: (current) => { + this.source = current; + }, + onChange: () => {} + }); + } + /** + * Read the current default model selection. + * @returns a detached provider, model, and optional reasoning selection. + */ + currentSelection() { + return selection(this.source()); + } + /** + * Save the complete default model selection. A deployment without a settings + * provider keeps its composition entry. + * @param next - resolved selection accepted by an entry point. + * @returns fulfillment after the optional settings write settles. + */ + async saveSelection(next) { + await this.ctx.get("settings")?.replace(AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE, { + provider: next.provider, + model: next.model, + ...next.reasoningEffort === void 0 ? {} : { reasoningEffort: String(next.reasoningEffort) } + }); + } +}; +//#endregion +export { AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE, AGENT_DEFAULT_MODEL_SETTINGS_SCHEMA, AgentDefaultModelConfig, AgentDefaultModelConfig as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/invariant.js new file mode 100644 index 0000000..d35ad21 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/invariant.js @@ -0,0 +1,25 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for the default Agent model selection. +* +* The service owns no independent event relationship: settings registration +* already validates every mutable value before `currentSelection()` can observe it. +* The empty installer keeps that absence explicit in composed invariant sets. +* +* @module @deepseek-ai/dsh-agent-default-model/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-agent-default-model"; +/** Cordis companion plugin name. */ +const name = "agent-default-model-invariant"; +/** Services required before the companion can register. */ +const inject = ["invariants"]; +/** No runtime invariant: settings validation owns the only mutable-value relationship. */ +const install = () => {}; +/** +* Register the intentionally empty invariant contribution. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/index.d.ts new file mode 100644 index 0000000..3fad5dd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/index.d.ts @@ -0,0 +1,58 @@ +/** + * Default model selection for an Agent without a session-specific selection. + * + * @module @deepseek-ai/dsh-agent-default-model + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { ModelSelection } from '@deepseek-ai/dsh-agent'; +declare module '@deepseek-ai/cordis' { + interface Context { + /** Default model selection for Agents created without an explicit model. */ + agentDefaultModel: AgentDefaultModelConfig; + } +} +/** Settings namespace carrying the default model selection for future Agents. */ +export declare const AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE: import("@deepseek-ai/dsh-settings").SettingsNamespace; +/** Stored and composed default model selection. */ +export interface AgentDefaultModelSettings { + /** Registered provider route. */ + provider: string; + /** Provider-owned model id. */ + model: string; + /** Adapter-owned reasoning effort, or provider/default behavior when absent. */ + reasoningEffort?: string; +} +/** Schema of the default Agent model settings section. */ +export declare const AGENT_DEFAULT_MODEL_SETTINGS_SCHEMA: z; +/** Composition entry for the default model selection. */ +export interface Config { + /** Registered provider route. */ + provider: string; + /** Provider-owned model id. */ + model: string; +} +/** + * Owns the default model selection independently of any Host or transport. + * The composition entry remains usable without a settings provider; when one + * is mounted, its user layer is read live. + */ +export declare class AgentDefaultModelConfig extends Service { + static Config: z; + private source; + constructor(ctx: Context, config: Config); + /** + * Read the current default model selection. + * @returns a detached provider, model, and optional reasoning selection. + */ + currentSelection(): ModelSelection; + /** + * Save the complete default model selection. A deployment without a settings + * provider keeps its composition entry. + * @param next - resolved selection accepted by an entry point. + * @returns fulfillment after the optional settings write settles. + */ + saveSelection(next: ModelSelection): Promise; +} +export default AgentDefaultModelConfig; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/invariant.d.ts new file mode 100644 index 0000000..3c97224 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/invariant.d.ts @@ -0,0 +1,21 @@ +/** + * Package-owned invariant companion for the default Agent model selection. + * + * The service owns no independent event relationship: settings registration + * already validates every mutable value before `currentSelection()` can observe it. + * The empty installer keeps that absence explicit in composed invariant sets. + * + * @module @deepseek-ai/dsh-agent-default-model/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "agent-default-model-invariant"; +/** Services required before the companion can register. */ +export declare const inject: string[]; +/** + * Register the intentionally empty invariant contribution. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/package.json new file mode 100644 index 0000000..1c40157 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model/package.json @@ -0,0 +1,51 @@ +{ + "name": "@deepseek-ai/dsh-agent-default-model", + "description": "Default model selection shared by Agent entry points", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/agent-default-model" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-settings b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-settings new file mode 120000 index 0000000..a0d8497 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-settings @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis-plugin-include b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis-plugin-include new file mode 120000 index 0000000..361c171 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis-plugin-include @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis-plugin-loader b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis-plugin-loader new file mode 120000 index 0000000..614b839 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/cordis-plugin-loader @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.i18n.yaml new file mode 100644 index 0000000..f3fef85 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/preset/agent-presets/README.md +README.md: 2438d751f000297cc4ede7b2a34736a62cc39dda +README.zh.md: c8ab8e167d624f639f6657d4c0ade7205b23821b diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.md new file mode 100644 index 0000000..2438d75 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.md @@ -0,0 +1,154 @@ +# dsh-agent-presets + +English | [中文](README.zh.md) + +Per-preset agent composition. A **preset** is a directory holding one `agent.cordis.yml`; the roster mounts it ONCE per process under a standing scope, and each session that names it joins by having its agent scope key parented to the mount's (`dsh-scope`'s parent chain). The mount's tools, prompt sections, and projection units exist exactly once and cover every joined agent — its plugins key their state by Session/Agent, so sessions stay apart inside one shared instance — and a host reader with no agent at all (a cold transcript read) resolves the same standing registrations by preset id. + +The mechanism is two seams. Entry contexts chain to the context a subtree was plugged into, and both [`dsh-tools`](../../core/tools/README.md) and [`dsh-system-prompt`](../../core/system-prompt/README.md) file registrations into the calling context's scope layer — so the standing mount's contributions land in the PRESET's layer. What carries them to each session is `dsh-scope`'s parent chain: an agent's views resolve `agent → preset → global` (nearest shadowing farthest), and the mount's listeners are admitted for every agent parented under it while a sibling preset's stay deaf. + +## Service: `AgentPresets` (ctx key: `agentPresets`) + +Discovery is unmemoized: `list()` and `resolve()` re-read the roots on every call, so a preset authored while the process runs is visible immediately and a deleted one disappears from the next read. Discovery also owns preset **health**: a directory whose composition is missing or unloadable (unparsable YAML — checked with the loader's own dialect, `!!js` included — or not a list of named plugin rows) is listed with a `broken` reason rather than skipped, because a skipped directory would still occupy its id on disk while every surface shows nothing to delete. A directory whose name is not a usable preset id (`[a-z0-9][a-z0-9-]*`) is skipped outright: no copy could ever claim it. + +- `ctx.agentPresets.defaultId: string` The preset id mounted when a caller names none. +- `ctx.agentPresets.list(): Promise` Every preset the configured roots currently supply, earlier root winning a duplicate id; broken presets included, each carrying its reason. +- `ctx.agentPresets.resolve(id?): Promise` One preset by id, defaulting to `defaultId`. Throws naming the available ids when no root supplies it. A broken preset resolves — deleting, reading, and reporting one all need the row. +- `ctx.agentPresets.mount(agentCtx, id?): Promise` Compose one agent from a preset — ensure its standing mount (single-flight) and parent the agent's scope key to it — returning the preset for the caller to record. Refuses a broken preset up front with its discovery-reported reason, so every unloadable shape fails the same way before the loader is involved. +- `ctx.agentPresets.composeFrom(agentCtx, parentCtx): string | undefined` Join one agent to the standing composition another already runs on, returning the preset id joined — `undefined` when the parent joined none, which is the rosterless deployment and not an error. A bind rather than a mount, so it is synchronous and has no composition failure mode; it still rejects a caller error (an unscoped context, or an agent that already joined). +- `ctx.agentPresets.composedPreset(agentCtx): string | undefined` The preset one LIVE agent runs on, read from its scope chain rather than from its session — the only answer available for an agent whose durable header is still being built. +- `ctx.agentPresets.recompose(agentCtx, id): Promise` Re-link one agent to a different preset's standing composition. Valid only while the agent has produced nothing — **the caller owns that check**; the new mount is ensured before the link moves, so a failure leaves the agent as it was. Refuses a broken preset like `mount()`. +- `ctx.agentPresets.standingKeyFor(id?): Promise` The standing scope key a host reader with no agent (a cold transcript read) resolves preset registrations in; ensures the mount without starting an agent, session, or turn. Refuses a broken preset like `mount()`. +- `ctx.agentPresets.roots: readonly PresetRoot[]` The roots this roster scans — every configured root in order, then the derived harness-home root. Not `config.roots`: read this to answer whether a roster is composed at all, so one derivation decides it. +- `ctx.agentPresets.authorable: boolean` Whether any of those roots has `user` trust, and therefore whether a preset can be created at all. +- `ctx.agentPresets.read(id): Promise` One preset's composition text, exactly as stored. +- `ctx.agentPresets.copy(from, id, name?): Promise` Create a locally authored preset by copying an existing one's whole directory — the only authoring write. No composition text crosses this seam, so a copy is exactly as loadable as its source; the copied metadata keeps the source's description but never its name or roster order, and `name` (or the id fallback) is what distinguishes the rows. +- `ctx.agentPresets.remove(id): Promise` Delete a locally authored preset; joined sessions keep their standing mount. Clears the user default when it named the preset just deleted: storing a default that does not exist yet is deliberate, but one this call removed will never be supplied again and would fail every session created without an explicit pick. + +`AgentPreset` carries `id` (the directory name), `trust` (`system` or `user`, from the root it was found under), `path` (the absolute composition file), and — only when the preset cannot compose a session — `broken` (one human-readable reason, shown verbatim on roster surfaces). + +### Where to call `mount()` + +The agent factory's `setup(agentCtx)` hook is the one supported call site. Only there is the join installed while the agent is still unpublished, so a rejected composition rolls the whole creation back rather than leaving a half-composed session. The standing subtree is owned by the roster service's own fiber — deliberately its UNTRACED context, because a subtree minted from a traced `this.ctx` resolves every service through the caller's shadow fiber instead of each entry's own inject store — so it survives every agent and unwinds only with the whole tree. Each generation records its composition file's stamp (mtime and size): a session that finds the stamp stale starts the next generation, while every session already joined keeps the one it runs on — the composition a running session joined outlives its file changing or disappearing underneath it, and files are the only composition editor, so the stamp is what carries an edit to later sessions. + +### Composing a child agent + +A subagent's child joins its parent's standing composition through `composeFrom()`, never through `mount()`. Every model-facing row lives on the agent plane, so the tool registry's global layer is empty and a child that joins nothing reaches the model with no tools at all and none of its parent's prompt sections. + +Re-mounting the parent's preset by id would differ from the bind in two ways that both matter. A composition file edited since the parent started would hand the child a DIFFERENT generation than the one its parent's history was produced under, and a preset deleted since would fail the child outright while its parent keeps running. The bind is also synchronous, which is what lets the in-process subagent drivers use it at all — they compose their children inside a synchronous creation window. + +The child records the joined id on its own durable header ([`dsh-subagent`](../../subagent/subagent/README.md)), so a cold read of the child's history rebuilds the composition it actually ran under rather than the deployment default. + +### Which preset a session runs + +The creation header names the preset a session STARTED with; `resolveSessionPreset(session)` names the one it RUNS. They differ whenever a blank session switched, so every reconstruction path — the summary a picker reads, a resume, a fork — resolves rather than reading the header. + +The header stays frozen because it is a creation fact. A switch is an `agent-preset/selected` session event appended after the swap commits, which is what the model-visible ⟺ logged rule requires: the preset decides the tool schemas and prompt sections the model sees, so it has to be reconstructable from the log. The service re-emits that committed fact as the non-scoped cordis event `agent-preset/selected(sessionId, agentPreset)` declared by the client-safe `./types` export, allowing remote consumers to invalidate session-derived state without importing Host runtime types. Reading the header alone would rebuild a switched session under the composition it was created with, replaying history the new tool set cannot act on — the exact hazard the blank-only lock exists to prevent. + +### Switching a blank agent + +`recompose()` unmounts the installed subtree and mounts the new one, because two compositions cannot coexist — both would register the same tool names into one layer. A failed mount restores the previous composition rather than leaving the agent with nothing, and an unknown id is rejected before anything is torn down. + +The restriction to a produced-nothing agent is a product rule, not a mechanical one: swapping tools mid-conversation would leave logged tool calls the new composition cannot make. The gateway enforces it at the wire ([`dsh-apiproxy`](../../host/apiproxy/README.md) answers `agent-preset-locked`), which is where session history is in hand. + +## Authoring + +Authoring is copy-only. A new preset is a whole-directory copy of an existing one — composition, metadata, skill directories, assets — landed under the first `user` root; the inputs are two ids the service resolves against its own roots plus an optional display name, so no caller ever supplies composition text and a copy grants nothing the roster did not already carry. Everything after creation happens in the preset's own files. `copy()` refuses three things before anything lands: + +- **An id that is not `[a-z0-9][a-z0-9-]*`.** The id becomes a directory name, so containment is a property of the id itself rather than of a path check after the fact — `../escape`, `a/b`, and an absolute path are all rejected as ids. +- **An id that is already taken.** A copy never overwrites: any root supplying the id refuses it (a user directory named like a shipped preset would be shadowed by it), and a directory occupying the name on disk refuses it too. Discovery lists such a directory as a broken preset, so the refusal's way out — delete it — is on the same page that reported it. +- **An unknown source.** The source may be any trust — copying a shipped preset is the primary case — but it must exist; a failed copy rolls its half-made directory back rather than leaving one discovery cannot see. + +The copied tree is re-tightened to owner-only (`0o600` files keeping their owner-execute bit, `0o700` directories), symlinks are dereferenced so the copy is self-contained, and the root is created on first copy — a deployment configuring a user root that does not exist yet is the normal first-run state. The copied `preset.yml` is rewritten: the source's description is kept for the author to edit in place, but its name and roster `order` are dropped — a copy presenting itself identically to its source, or sorted into the shipped set's declared order, would make the roster stop distinguishing them. `remove()` refuses a preset that ships with the deployment; the shipped set is the known-good compositions copies start from. + +### How a preset's rows resolve + +A row's **package name** resolves from the host composition, not from the preset directory. The Loader normally resolves an entry against its own tree's `baseUrl`, which for a preset is wherever the composition file sits; a locally authored preset lives under the user's home, where Node's upward `node_modules` walk never reaches the harness, so every `@deepseek-ai/dsh-*` row would fail to import. The mount records the host base before plugging the subtree and sends bare specifiers there. + +A **relative** path still resolves from the preset's own directory, so a preset's own plugin files and skill directories travel with it. + +An **absolute** filesystem path keeps its own location. The mount converts it to a `file:` URL before ESM import so POSIX paths and Windows drive-letter or UNC paths use a specifier Node accepts. + +### Display metadata + +A preset may publish display text in an optional `preset.yml` beside its composition: + +```yaml +name: 极简模式 +description: 仅提供持久 bash 与 str_replace_editor 的双工具编码 Agent。 +``` + +It carries display text ONLY. `id` is the directory name and `trust` comes from the root the preset was discovered under, so neither is writable here — otherwise a locally authored preset could name itself into the shipped set. It is a separate file because the composition is a top-level list of plugin rows: YAML cannot carry sibling keys beside it, and a fake metadata row would hand the Loader something to load. + +Every read failure degrades to no metadata — absent, malformed, wrongly typed, or blank all mean the same thing, and a picker falls back to the id. Presentation is not capability: a preset with a broken name still mounts. + +## Config + +| Field | Default | Meaning | +|---|---|---| +| `default` | required | Preset id mounted when a caller names none | +| `roots` | `[]` | Scanned directories in precedence order; each supplies `path` (a leading `~` expands) and `trust` (defaults to `user`) | +| `includeUserRoot` | `true` | Append `/.agent-presets` as a `user` root, after every configured root | + +An absent root supplies no presets rather than failing: the user root does not exist until the first locally authored preset, and naming a default no root supplies already fails loud at resolution. + +### The writable root is this package's, the shipped root is the app's + +`/.agent-presets` is where a person's own presets live, the way `/skills` is where their own skills live ([`dsh-skill-filesystem`](../../skill/skill-filesystem/README.md)), so the roster derives it rather than waiting for a deployment to remember it — a launcher that configures nothing still finds and authors presets. It is appended AFTER every configured root, which keeps an earlier root winning a duplicate id: a shipped `standard` still shadows a home directory that claimed the name, and `copy()` refuses that id rather than landing a preset nothing would resolve. + +The roots are resolved once, when the service is constructed. A root set that changed between a `list()` and the `copy()` acting on its answer would author into a directory the caller never saw. + +`includeUserRoot: false` mounts a roster over `roots` alone. A deployment that confines presets to its own directories needs it, and so does any test pinning an exact roster — otherwise the machine's real `` decides what the roster contains. + +The SHIPPED root stays an assembly fact: it sits beside the installed app's own config, a path only that app can resolve. + +### The default preset is a user setting + +When a settings provider is composed, this plugin registers the `agent-presets` namespace with `config.default` as its composition base, so the user document layers over the deployment's engineering default: + +```yaml +agent-presets: + default: minimal +``` + +The value is read per resolution rather than snapshotted, so a hot-reloaded document takes effect on the next session created and every running session stays on the preset it was composed from. Clearing the user field re-inherits the composition default. A default naming a preset no root supplies is stored without complaint and fails at the next `resolve()` — the roster is a live directory, so a name absent now may exist by the time a session asks for it. + +## What a mount rejects + +A directly-plugged subtree is absent from `ctx.loader.entries()`, so no boot audit covers it. `mount()` therefore proves the result usable itself, and rejects three things. + +**An unscoped target.** Mounting into a context that carries no agent scope would register the preset's tools globally, for every agent in the process. + +**A row that never became usable.** The loader already rejects a row whose module failed to import or whose plugin threw; what remains is a row still waiting for a service the composition never supplies, which the audit names. + +**A row that published a service into the root realm.** Such a service is process-global, so the second preset publishing the same name collides with the first, and a host reader would resolve one preset's instance for every session. A preset that genuinely owns a service puts it behind an `isolate` realm — entry-local realms keep two presets' same-named services apart exactly as they once kept two sessions' apart — or the service belongs in the host composition instead. + +The package invariant re-checks that last rule on every service notification, because a row that publishes from a timer or an asynchronous continuation would escape the one-shot audit. + +## A preset file is an input, never a persistence target + +The Loader writes a tree back to its source file whenever it decides the config changed, and a row disposing its own fiber is enough to decide that: the entry is marked `disabled` and the tree is written. Inherited, that would burn one session's runtime state into a file every session shares — comments stripped by the YAML round trip, and a `writeFile` rejection inside a `setTimeout` for a read-only shipped preset. + +The mounted subtree therefore overrides `write()` as a no-op. Nothing in this package writes a composition; authoring one is a separate, explicit operation. + +## Trust + +Presets are compositions, so a preset is exactly as privileged as the plugins it names. A `user` preset — authored by a person or by an agent — carries the same trust as shell access; the `trust` field exists so consumers can present that difference, not to enforce it. + +## Model Experience + +Indirectly, through the plugins a standing composition registers, which own every tool schema and prompt section the preset makes visible to the agents joined to it. + +#### KV Cache effect + +Prefix-stable for the life of an agent: a composition is installed once, before the agent is published and therefore before its first request, and is never re-read while the agent runs. Choosing a different preset for a new session establishes a different prefix for that session alone and cannot invalidate reuse for any session already running. + +## Known Limitations and Deferred Work + +- **A preset outside the writable root is discoverable but not deletable** — `remove()` refuses anything that does not live under the FIRST `user` root, so a deployment that configures its own writable root while leaving `includeUserRoot` on lists the harness-home presets, mounts them, and then answers "it does not live under the writable preset root" for every delete. The roster carries one writable root by design; a deployment that wants only its own sets `includeUserRoot: false`. +- **A preset cannot be changed once a session has produced anything** — `recompose` re-links a BLANK session's parent scope to another standing mount, and only a blank one: switching a composition that already ran would strand tools the model has called. Changing the default affects only sessions created afterwards. +- **A generation is keyed on the composition file alone** — the stamp check notices `agent.cordis.yml` changing, not an edit to a skill file or asset beside it; those reach new sessions only once the composition file itself moves or the process restarts. +- **A superseded generation is never reclaimed** — sessions already joined keep the generation they run on, and the roster holds no join count that could tell when the last one left, so the whole subtree stays mounted until the process ends. The cost is per generation rather than per session, but it is not free: `dsh-skill-filesystem` watches its roots by default, so each edit-then-create cycle adds a live watcher set. Bounded by how often compositions are edited — which the settings-page authoring flow makes a per-save event rather than a per-deploy one. Reclaiming one needs a joined-agent count on the standing mount; see the `TODO` at `ensureStanding`. +- **A copy is never mounted to validate** — it is byte-identical to its source, so a source broken on disk yields a copy exactly as broken as the source; discovery's health check marks both rows on the next roster read rather than deferring the failure to a session start. +- **Health is a shape check, not a mount** — discovery proves the composition parses in the loader dialect and holds named rows, not that every row's module resolves or activates; a row naming an absent package still fails at the first session, which rolls the creation back. +- **A copy is a snapshot that drifts** — upgrading the deployment does not update copies of shipped presets, and there is no patch semantics at this layer to express "standard plus one change" (that is the bundle layer's `cordis.patch.yml`); the shipped set itself accepts the same cost — `cordis` and `code` are full copies of `standard` — so the whole assembly stays readable in one file. +- **Root scans are not watched** — every read hits the filesystem instead, which keeps the roster fresh but puts one `readdir` per root on each `list()`. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.zh.md new file mode 100644 index 0000000..c8ab8e1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/README.zh.md @@ -0,0 +1,154 @@ +# dsh-agent-presets + +[English](README.md) | 中文 + +按 preset 组装 agent(智能体)。**preset** 是一个目录,其中放置一份 `agent.cordis.yml`;roster 在整个进程内只把它挂载一次(常驻 scope),命名它的每个会话通过把自己 agent 的 scope key 认父到该挂载(`dsh-scope` 的父链)来加入。挂载的工具、提示词段落与投影单元只存在一份,覆盖所有已加入的 agent——其插件本就按 Session/Agent 分键存状态,会话在共享实例内互不串扰——而完全没有 agent 的宿主读取方(冷读记录)也能按 preset id 解析到同一份常驻注册。 + +其机制是两条 seam。entry 上下文沿原型链连到子树被挂载时所在的上下文,而 [`dsh-tools`](../../core/tools/README.md) 与 [`dsh-system-prompt`](../../core/system-prompt/README.md) 本就按调用方上下文的 scope 分层归档注册——因此常驻挂载的贡献落在 **preset 的分层**里。把它们送达每个会话的是 `dsh-scope` 的父链:agent 的视图按 `agent → preset → global` 解析(近者遮蔽远者),挂载的监听器对认父到它的每个 agent 放行,而兄弟 preset 的监听器保持失聪。 + +## 服务:`AgentPresets`(ctx 键:`agentPresets`) + +发现过程不做缓存:`list()` 与 `resolve()` 每次调用都重新读取各个根目录,因此进程运行期间新写的 preset 立即可见,被删除的 preset 也会在下一次读取时消失。发现过程同时负责 preset 的**健康**:组装文件缺失或不可加载(YAML 无法解析——用加载器自己的方言检查,含 `!!js`——或不是由具名插件行组成的列表)的目录会作为携带 `broken` 原因的行列出而不是被跳过,因为被跳过的目录仍在磁盘上占着它的 id,而各个界面却没有任何可删的东西。目录名不是可用 preset id(`[a-z0-9][a-z0-9-]*`)的目录才被直接跳过:复制永远不可能占用那种名字。 + +- `ctx.agentPresets.defaultId: string` 调用方未指定时挂载的 preset id。 +- `ctx.agentPresets.list(): Promise` 当前各根目录提供的全部 preset;id 重复时靠前的根目录胜出;损坏的 preset 也在其中,各自携带原因。 +- `ctx.agentPresets.resolve(id?): Promise` 按 id 取一个 preset,缺省取 `defaultId`。没有任何根目录提供该 id 时抛错,并列出可用 id。损坏的 preset 照样解析——删除、读取与上报都需要这一行。 +- `ctx.agentPresets.mount(agentCtx, id?): Promise` 用一个 preset 组装一个 agent——确保其常驻挂载(并发去重)并把 agent 的 scope key 认父到它——返回该 preset 供调用方记录。对损坏的 preset 直接以发现时记下的原因拒绝,所以每种不可加载的形态都在加载器介入之前以同一方式失败。 +- `ctx.agentPresets.composeFrom(agentCtx, parentCtx): string | undefined` 让一个 agent 加入另一个 agent 已在运行的常驻组装,返回所加入的 preset id——父方未加入任何 preset 时返回 `undefined`,那是无 roster 的部署,不是错误。这是认父而非挂载,因此同步、且自身没有组装失败模式;调用方用错(上下文无 scope、agent 已加入过)仍会拒绝。 +- `ctx.agentPresets.composedPreset(agentCtx): string | undefined` 某个**活着的** agent 正在运行的 preset,从其 scope 链读取而不是从其会话读取——对于持久化 header 尚在构建中的 agent,这是唯一能拿到的答案。 +- `ctx.agentPresets.recompose(agentCtx, id): Promise` 把一个 agent 重链到另一个 preset 的常驻组装。仅在该 agent 尚无任何产出时合法——**由调用方负责该检查**;新挂载在链移动之前确保完成,失败时 agent 原封不动。与 `mount()` 一样拒绝损坏的 preset。 +- `ctx.agentPresets.standingKeyFor(id?): Promise` 没有 agent 的宿主读取方(冷读记录)解析 preset 注册所用的常驻 scope key;确保挂载而不启动任何 agent、会话或轮次。与 `mount()` 一样拒绝损坏的 preset。 +- `ctx.agentPresets.roots: readonly PresetRoot[]` 本 roster 实际扫描的根目录——全部已配置根目录按序在前,随后是推导出的 harness home 根目录。它不是 `config.roots`:判断「是否已组装 roster」应读它,从而由同一处推导决定。 +- `ctx.agentPresets.authorable: boolean` 上述根目录中是否有任一具备 `user` 信任级别,因而 preset 是否可创建。 +- `ctx.agentPresets.read(id): Promise` 某个 preset 的组装文本,与存储内容逐字一致。 +- `ctx.agentPresets.copy(from, id, name?): Promise` 通过整目录复制一个既有 preset 来创建本地创作的 preset——唯一的创作写入。组装文本不经过这道接缝,因此副本与其来源同等可加载;复制出的元数据保留来源的描述、但绝不保留其名称与 roster 排序,`name`(或回退到 id)才是区分两行的依据。 +- `ctx.agentPresets.remove(id): Promise` 删除一个本地创作的 preset;已加入的会话保留其常驻挂载。若用户默认值恰好指向刚删除的 preset 则一并清除:存一个尚不存在的默认值是刻意的,但本次删除的这个再也不会有人提供,留着会让所有未显式指定的新会话无法启动。 + +`AgentPreset` 携带 `id`(目录名)、`trust`(`system` 或 `user`,取自它所在的根目录)、`path`(组装文件的绝对路径),以及——仅当该 preset 无法组装会话时——`broken`(一条人类可读的原因,名单界面原样展示)。 + +### 应在何处调用 `mount()` + +agent 工厂的 `setup(agentCtx)` 钩子是唯一受支持的调用点。只有在那里,认父是在 agent 尚未发布时完成的,因此组装被拒绝会让整次创建回滚,而不会留下一个组装到一半的会话。常驻子树归 roster 服务自己的 fiber 所有——刻意用其未追踪的上下文,因为从被追踪的 `this.ctx` 派生的子树会经调用方的 shadow fiber 解析一切服务、无视各 entry 自己的 inject store——所以它比任何 agent 都活得久,只随整棵树卸载。每个代际记录其组装文件的 stamp(mtime 与大小):发现 stamp 过期的会话会开启下一个代际,而所有已加入的会话保持各自正在运行的那个——正在运行的会话所加入的组装在其文件被修改或删除后继续存活;文件是唯一的组装编辑器,stamp 正是把编辑送达后续会话的机制。 + +### 组装子 agent + +subagent 的子 agent 通过 `composeFrom()` 加入其父方的常驻组装,绝不走 `mount()`。所有面向模型的行都在 agent 平面,工具注册表的全局层是空的,因此没有加入任何组装的子 agent 抵达模型时既没有任何工具,也没有父方的任何提示段。 + +按 id 重新挂载父方的 preset 与认父有两处差别,且两处都要紧。父方启动后被编辑过的组装文件会把与父方历史所产出时**不同**的一个代际交给子 agent;而此后被删除的 preset 会让子 agent 直接失败,尽管其父方仍在正常运行。认父还是同步的,这正是进程内 subagent 驱动能够使用它的前提——它们在同步的创建窗口里组装子 agent。 + +子 agent 会把所加入的 id 记在自己的持久化 header 上(见 [`dsh-subagent`](../../subagent/subagent/README.md)),因此冷读子 agent 的历史时重建的是它实际运行过的组装,而不是部署默认值。 + +### 会话实际运行的是哪个 preset + +创建头部记录的是会话**以什么开始**,`resolveSessionPreset(session)` 给出的才是它**实际运行的**。空白会话一旦切换过,两者就不同,因此所有重建路径——选择器读取的摘要、resume、fork——都走解析,而非直接读头部。 + +头部保持冻结,因为它是创建期事实。切换以 `agent-preset/selected` 会话事件记录,在替换提交之后追加;这正是 model-visible ⟺ logged 规则的要求:preset 决定模型看到的工具 schema 与提示词段落,因此必须能从日志重建。服务会把这项已提交事实重新发为不带 scope 的 cordis 事件 `agent-preset/selected(sessionId, agentPreset)`,其声明位于 client-safe 的 `./types` 出口,使远端消费方无需导入 Host 运行时类型即可让会话派生状态失效。只读头部会让切换过的会话按创建时的组装重建,从而重放新工具集无法执行的历史——这正是「仅空白可切」那道锁要防的危险。 + +### 切换空白 agent + +`recompose()` 先卸载已装入的子树、再装入新的,因为两份组装无法共存——它们会把相同的工具名注册进同一个层。挂载失败会恢复先前的组装,而不是让 agent 一无所有;未知 id 则在任何东西被拆除之前就被拒绝。 + +"仅限尚未产出任何内容的 agent"是一条产品规则而非机制约束:在对话进行中调换工具,会留下新组装无法执行的、已被记录的工具调用。该规则由网关在传输层执行([`dsh-apiproxy`](../../host/apiproxy/README.md) 返回 `agent-preset-locked`),因为会话历史在那里才拿得到。 + +## 创作 + +创作即复制。新 preset 是某个既有 preset 的整目录副本——组装、元数据、skill 目录、附带资产——落在首个 `user` 根目录之下;输入只有两个由服务对照自身根目录解析的 id 加一个可选显示名,因此调用方从不提供组装文本,一次复制不会授予 roster 尚未携带的任何能力。创建之后的一切都发生在 preset 自己的文件里。`copy()` 在任何内容落盘之前拒绝三种情况: + +- **不符合 `[a-z0-9][a-z0-9-]*` 的 id。** id 会成为目录名,因此约束是 id 自身的性质,而非事后再做一次路径检查——`../escape`、`a/b` 与绝对路径都作为 id 被拒绝。 +- **已被占用的 id。** 复制从不覆写:任一根目录已提供该 id 即拒绝(与随附 preset 同名的用户目录只会被它遮蔽),磁盘上占着该名字的目录同样拒绝。发现过程会把这样的目录列为损坏的 preset,所以这条拒绝的出路——删掉它——就在报告它的同一页面上。 +- **未知的来源。** 来源可以是任何信任级别——复制随附 preset 正是主要用途——但必须存在;复制失败会回滚做到一半的目录,而不是留下一个 discovery 看不见的目录。 + +复制出的目录树被收紧为仅属主可用(文件 `0o600` 并保留属主执行位,目录 `0o700`),符号链接被解引用以保证副本自包含,且根目录在首次复制时创建——部署配置了尚不存在的用户根目录,正是首次运行的正常状态。复制出的 `preset.yml` 会被重写:保留来源的描述供作者就地编辑,但丢弃其名称与 roster `order`——副本若与来源呈现得一模一样、或按随附集合声明的顺序排序,roster 就不再能区分它们。`remove()` 拒绝随部署提供的 preset;随附集合正是副本的已知良好起点。 + +### preset 的各行如何解析 + +行的**包名**从宿主组装解析,而非从 preset 目录解析。Loader 通常按 entry 所属树的 `baseUrl` 解析,而对 preset 而言那就是组装文件所在之处;本地创作的 preset 位于用户主目录之下,Node 向上查找 `node_modules` 永远够不到 harness,因此每一个 `@deepseek-ai/dsh-*` 行都会导入失败。挂载在插入子树之前先记录宿主的基址,并把裸标识符送往那里。 + +**相对**路径仍从 preset 自身的目录解析,因此 preset 自带的插件文件与 skill 目录会随它一同迁移。 + +**绝对**文件系统路径则保留其自身位置。挂载会先将它转换为 `file:` URL 再交给 ESM 导入,从而使 POSIX 路径和 Windows 盘符或 UNC 路径都采用 Node 能够接受的说明符。 + +### 展示用元信息 + +preset 可以在组装文件旁的可选 `preset.yml` 里发布展示文本: + +```yaml +name: 极简模式 +description: 仅提供持久 bash 与 str_replace_editor 的双工具编码 Agent。 +``` + +它**只**承载展示文本。`id` 是目录名,`trust` 取自 preset 被发现时所在的根目录,两者都不可写在这里——否则本地创作的 preset 就能把自己命名进随附集合。之所以是独立文件:组装是插件行的顶层列表,YAML 无法在其旁携带同级键,而伪造一个元信息行等于递给 Loader 一个要加载的东西。 + +任何读取失败都退化为「没有元信息」——缺失、格式错误、类型不对、内容为空,含义相同,选择器回退到 id。展示不是能力:名字坏掉的 preset 依然能挂载。 + +## 配置 + +| 字段 | 默认值 | 含义 | +|---|---|---| +| `default` | 必填 | 调用方未指定时挂载的 preset id | +| `roots` | `[]` | 按优先级排列的扫描目录;每项提供 `path`(开头的 `~` 会展开)与 `trust`(默认为 `user`) | +| `includeUserRoot` | `true` | 在全部已配置根目录之后,追加 `/.agent-presets` 作为 `user` 根目录 | + +根目录不存在时视为不提供任何 preset,而非失败:用户根目录在写出第一个本地 preset 之前并不存在,而指定了没有任何根目录提供的默认值,在解析时本就会明确报错。 + +### 可写根目录属于本包,随附根目录属于 app + +`/.agent-presets` 是个人自有 preset 的所在,正如 `/skills` 是其自有 skill 的所在([`dsh-skill-filesystem`](../../skill/skill-filesystem/README.md)),因此 roster 自行推导它,而不等某个部署记得配置——一个什么都没配的启动器同样能发现并创作 preset。它追加在全部已配置根目录**之后**,从而保持靠前的根目录赢得重复 id:随附的 `standard` 仍然遮蔽一个占用该名字的家目录目录,而 `copy()` 会拒绝该 id,不会落下一个无人解析得到的 preset。 + +根目录在服务构造时解析一次。若根目录集合在一次 `list()` 与依据其答案执行的 `copy()` 之间发生变化,写入的将是调用方从未见过的目录。 + +`includeUserRoot: false` 使 roster 只覆盖 `roots`。把 preset 限制在自有目录内的部署需要它,任何钉住确切 roster 的测试同样需要——否则将由这台机器真实的 `` 决定 roster 的内容。 + +随附根目录仍然是装配事实:它位于已安装 app 自身配置的旁边,那个路径只有该 app 能解析。 + +### 默认 preset 是一项用户设置 + +当组装中存在 settings 提供方时,本插件会注册 `agent-presets` 命名空间,并以 `config.default` 作为其组装 base,因此用户文档会层叠覆盖部署方的工程默认值: + +```yaml +agent-presets: + default: minimal +``` + +该值在每次解析时读取而非快照,因此热重载的文档对**此后创建**的会话生效,而每个运行中的会话仍停留在它当初据以组装的 preset 上。清空用户字段即重新继承组装默认值。若默认值指向没有任何根目录提供的 preset,写入时不会报错,而在下一次 `resolve()` 时失败——名单是一个活动目录,此刻不存在的名字,等到某个会话真正索取时可能已经存在。 + +## 挂载会拒绝什么 + +直接挂载的子树不会出现在 `ctx.loader.entries()` 中,因此没有任何启动审计能覆盖它。`mount()` 因此自行校验结果可用,并拒绝三种情况。 + +**目标上下文没有 scope。** 挂载到不带 agent scope 的上下文,会把该 preset 的工具注册成全局的,作用于进程内每一个 agent。 + +**某一行始终未进入可用状态。** 模块导入失败或插件抛错的行,loader 已经会拒绝;剩下的情况是某一行仍在等待该组装从未提供的服务,审计会指名这种情况。 + +**某一行把服务发布进了根 realm。** 这类服务是进程级全局的,因此第二个发布同名服务的 preset 会与第一个相撞,宿主读取方也会把某一个 preset 的实例当成所有会话的。确实需要自带服务的 preset,应把它放在 `isolate` realm 之后——entry 本地 realm 让两个 preset 的同名服务互不相干,正如它从前隔开两个会话——否则该服务应改放进宿主组装。 + +最后一条规则由本包的运行时不变量在每次服务通知时复查,因为从定时器或异步续体中发布的行会绕过一次性审计。 + +## preset 文件是输入,不是持久化目标 + +只要 Loader 认为配置变了,它就会把树写回源文件——而一个行释放自己的 fiber 就足以让它这么认为:该 entry 被标记 `disabled`,随即触发写回。若继承该行为,一个会话的运行时状态就会被烧进所有会话共享的文件里:YAML 往返会抹掉注释,而对随附的只读 preset,`writeFile` 还会在 `setTimeout` 内抛出无人接管的 rejection。 + +因此被挂载的子树把 `write()` 覆写为空操作。本包不写任何组装;创作组装是另一件独立且显式的操作。 + +## 信任 + +preset 就是组装,因此一个 preset 的权限恰好等于它所引用的插件。`user` preset——无论由人还是由 agent 写出——与 shell 访问权限同级;`trust` 字段的存在是为了让消费方呈现这一差异,而不是用来强制隔离。 + +## 模型体验 + +Indirectly, through the plugins a standing composition registers, which own every tool schema and prompt section the preset makes visible to the agents joined to it. + +#### KV Cache effect + +在一个 agent 的整个生命周期内保持前缀稳定:组装只装入一次,发生在 agent 发布之前、因而也在它的首个请求之前,且在 agent 运行期间不再重新读取。为新会话选择不同的 preset,只会为该会话建立不同的前缀,无法让任何已在运行的会话失去缓存复用。 + +## 已知限制与暂缓事项 + +- **位于可写根目录之外的 preset 可被发现却无法删除** —— `remove()` 拒绝任何不在**第一个** `user` 根目录下的 preset,因此一个既配置了自有可写根、又保留 `includeUserRoot` 的部署,会列出并挂载 harness home 下的 preset,却对每次删除回答「它不在可写 preset 根目录之下」。roster 按设计只有一个可写根;只想要自有根的部署应设置 `includeUserRoot: false`。 +- **会话一旦产出内容便无法更换 preset** —— `recompose` 把**空白**会话的父作用域重链到另一个常驻挂载,且仅限空白会话:切换已运行过的组装会抽走模型已调用的工具。更改默认值只影响此后创建的会话。 +- **代际只以组装文件为键** —— stamp 检查只察觉 `agent.cordis.yml` 的变化,察觉不到旁边 skill 文件或资产的编辑;那些编辑要等组装文件本身变动或进程重启才达到新会话。 +- **被替代的代际永不回收** —— 已加入的会话保持其运行所在的代际,而名单没有加入计数可以判断最后一个何时离开,因此整棵子树一直挂到进程结束。代价按代际计而非按会话计,但并非为零:`dsh-skill-filesystem` 默认监听自己的根目录,因此每一轮「编辑后建会话」都会新增一套活的 watcher。上限取决于组装被编辑的频率——而设置页的编写流程把这件事从「每次部署」变成了「每次保存」。要回收就需要给常驻挂载加上已加入 agent 的计数;见 `ensureStanding` 处的 `TODO`。 +- **副本从不被实际挂载以校验** —— 它与来源逐字节相同,因此磁盘上已坏的来源会产出与来源同样损坏的副本;发现过程的健康检查会在下一次读取名单时把两行都标出来,而不是把失败推迟到会话启动。 +- **健康是形状检查,不是挂载** —— 发现过程只证明组装能以加载器方言解析、由具名行组成,不证明每一行的模块都能解析并激活;引用不存在的包的行仍在第一个会话处失败,并回滚该会话的创建。 +- **副本是会漂移的快照** —— 升级部署不会更新随附 preset 的副本,本层也没有表达「standard 加一处改动」的 patch 语义(那是 bundle 层 `cordis.patch.yml` 的能力);随附集合自己也接受同样的代价——`cordis` 与 `code` 就是 `standard` 的完整副本——换来整份组装在一个文件里可读。 +- **根目录扫描不做监听** —— 每次读取都实际访问文件系统,这让名单保持新鲜,但每次 `list()` 会对每个根目录产生一次 `readdir`。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/index.js new file mode 100644 index 0000000..c49f172 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/index.js @@ -0,0 +1,1178 @@ +import { chmod, cp, readFile, readdir, rm, stat } from "node:fs/promises"; +import { Context, Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { bindScopeParent, createScope, scopeOf, scopeParentOf } from "@deepseek-ai/dsh-scope"; +import { settingsNamespace } from "@deepseek-ai/dsh-settings"; +import { dshHomePath, expandHomePath } from "@deepseek-ai/dsh-home-paths"; +import { dirname, isAbsolute, join, resolve } from "node:path"; +import yaml, { load } from "js-yaml"; +import { Include, entryListSchema } from "@deepseek-ai/cordis-plugin-include"; +import { writeFileAtomic } from "@deepseek-ai/dsh-atomic-write"; +import { pathToFileURL } from "node:url"; +//#region lib/types/metadata.js +/** +* A preset's display metadata: the name and description a picker shows. +* +* It lives in its own file because the composition is a top-level list of +* plugin rows — YAML cannot carry sibling keys beside it, and faking a +* metadata row would hand the Loader something to load. Keeping it separate +* also keeps the composition exactly what its name says: a Cordis file the +* loader owns and the cordis preset can author. +* +* The file carries display text ONLY. `id` is the directory name and `trust` +* comes from the root a preset was discovered under, so neither is writable +* here — otherwise a locally authored preset could claim to be a shipped one. +* +* Every read failure degrades to no metadata. A preset whose display text is +* missing, malformed, or unreadable still mounts: presentation is not a +* capability, and a broken name must never become an agent that cannot start. +* @module @deepseek-ai/dsh-agent-presets/metadata +*/ +/** The optional display-metadata file beside a preset's composition. */ +const METADATA_FILE = "preset.yml"; +/** A non-empty trimmed string, or undefined for anything else. */ +function text(value) { + if (typeof value !== "string") return void 0; + const trimmed = value.trim(); + return trimmed === "" ? void 0 : trimmed; +} +/** +* Read one preset directory's display metadata. +* +* Absent, unparsable, and wrongly-shaped files are all the same answer — +* empty metadata — because the caller renders a picker, not a diagnostic. +* @param directory - the preset directory. +* @returns the display text the preset published, possibly empty. +*/ +async function readPresetMetadata(directory) { + let raw; + try { + raw = await readFile(join(directory, METADATA_FILE), "utf8"); + } catch { + return {}; + } + let parsed; + try { + parsed = yaml.load(raw); + } catch { + return {}; + } + if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {}; + const record = parsed; + const name = text(record.name); + const description = text(record.description); + const order = typeof record.order === "number" && Number.isFinite(record.order) ? record.order : void 0; + return { + ...name === void 0 ? {} : { name }, + ...description === void 0 ? {} : { description }, + ...order === void 0 ? {} : { order } + }; +} +/** +* Render display metadata as the file's contents. +* +* Absent fields are omitted rather than written empty, so a preset with no +* description does not ship a key that reads as an intentional blank. +* @param metadata - the display text to store. +* @returns the YAML document, or undefined when there is nothing to store. +*/ +function renderPresetMetadata(metadata) { + const name = text(metadata.name); + const description = text(metadata.description); + const { order } = metadata; + if (name === void 0 && description === void 0 && order === void 0) return void 0; + return yaml.dump({ + ...name === void 0 ? {} : { name }, + ...description === void 0 ? {} : { description }, + ...order === void 0 ? {} : { order } + }, { lineWidth: -1 }); +} +//#endregion +//#region lib/types/preset.js +/** Agent-preset vocabulary shared by discovery, mounting, and consumers. */ +/** +* Ids a preset directory may use. +* +* The id becomes a path segment, so this is a containment boundary rather than +* a style rule: `..`, a separator, or an absolute-looking name would place the +* composition outside the root the deployment authorised. Discovery shares it: +* a directory whose name no copy could ever claim is not a preset slot. +*/ +const PRESET_ID = /^[a-z0-9][a-z0-9-]*$/; +/** +* No configured root supplies the requested preset. +* +* Separate from a mount failure because the two mean different things to a +* caller: an unknown id is a bad request, while an unusable composition is a +* broken preset the deployment must fix. +*/ +var UnknownPresetError = class extends Error { + presetId; + available; + constructor(presetId, available) { + super(`agent-presets: preset "${presetId}" not found (available: ${available.join(", ") || "none"})`); + this.presetId = presetId; + this.available = available; + } +}; +/** A preset exists but its composition cannot be installed. */ +var PresetMountError = class extends Error { + presetId; + reason; + constructor(presetId, reason, options) { + super(`agent-presets: preset "${presetId}" failed to mount: ${reason}`, options); + this.presetId = presetId; + this.reason = reason; + } +}; +//#endregion +//#region lib/types/discovery.js +/** +* Filesystem discovery of agent presets. A preset is a directory holding +* {@link COMPOSITION_FILE}, optionally beside a {@link METADATA_FILE} carrying +* its display text; the directory name is the preset id. Discovery +* re-reads the roots on every call so a preset authored while the process is +* running is visible without a restart. +* +* Discovery also owns preset HEALTH: a directory whose composition is +* missing or unloadable is reported as a broken roster row rather than +* skipped. A skipped directory would still occupy its id on disk — the copy +* path refuses the name while no surface shows anything to delete — and a +* malformed composition would otherwise read as an ordinary preset until the +* first session fails to mount it. +* @module @deepseek-ai/dsh-agent-presets/discovery +*/ +/** The composition file that makes a directory a preset. */ +const COMPOSITION_FILE = "agent.cordis.yml"; +/** +* Harness-home directory holding locally authored presets. +* +* This package owns the writable root the way `dsh-skill-filesystem` owns +* `/skills`. An app must assemble the SHIPPED root, whose path only +* the installed app can resolve; where a person's own presets go is the same +* place in every deployment that does not say otherwise, so a launcher that +* forgets to configure one still finds them. +* +* Package-internal on purpose: no consumer outside this package addresses the +* directory by name, and a test that imported it could not catch this value +* being wrong — the expected segment is spelled out where it is asserted. +*/ +const USER_PRESET_DIR = ".agent-presets"; +/** +* Why `rows` cannot be an entry list, or undefined when it can. +* +* A shallow shape check, deliberately short of the loader's work: it does not +* resolve plugin names or apply configs. What it catches is the hand-edit +* that produces a file the loader cannot even begin with — and it must accept +* everything the loader accepts, which is why rows are only required to be +* maps carrying a plugin `name` (groups recurse into their own lists). +* @param rows - the parsed composition document. +* @param at - row-path prefix for nested diagnostics, empty at the top level. +* @returns one human-readable reason, or undefined when the shape holds. +*/ +function entryListProblem(rows, at = "") { + if (!Array.isArray(rows)) return at === "" ? "the composition must be a top-level list of plugin rows" : `group ${at} must hold a list of plugin rows`; + for (const [index, row] of rows.entries()) { + const label = at === "" ? `row ${String(index + 1)}` : `${at} row ${String(index + 1)}`; + if (typeof row !== "object" || row === null || Array.isArray(row)) return `${label} is not a plugin row (expected a map with a "name")`; + const { name, group, config } = row; + if (typeof name !== "string" || name === "") return `${label} names no plugin (a "name" string is required)`; + if (group === true) { + const nested = entryListProblem(config, label); + if (nested !== void 0) return nested; + } + } +} +/** +* Why the composition at `path` cannot mount, or undefined when it looks +* loadable. Parsed with the loader's own YAML dialect ({@link entryListSchema}, +* the one carrying `!!js`), so health can never call a composition broken +* that the loader would accept. +* @param path - absolute path of the composition file. +* @returns one human-readable reason, or undefined when the file is loadable. +*/ +async function compositionProblem(path) { + let content; + try { + content = await readFile(path, "utf8"); + } catch { + return `the composition file ${COMPOSITION_FILE} cannot be read`; + } + let rows; + try { + rows = load(content, { schema: entryListSchema }); + } catch (error) { + return `the composition is not valid YAML: ${(error instanceof Error ? error.message : String(error)).replace(/\n[\s\S]*$/, "")}`; + } + return entryListProblem(rows); +} +/** +* Whether `path` names an existing regular file. +* @param path - absolute path to test. +* @returns true when the path resolves to a file. +*/ +async function isFile(path) { + try { + return (await stat(path)).isFile(); + } catch { + return false; + } +} +/** +* Scan one root for preset directories. +* +* An absent root yields no presets rather than throwing: the user root does +* not exist until the first locally authored preset, and naming a default +* that no root supplies already fails loud at resolution. +* +* Every directory whose name is a usable preset id is a roster row — broken +* when its composition is missing or unloadable. A directory named outside +* {@link PRESET_ID} is skipped instead: no copy could ever claim that name, +* so it blocks nothing, and reporting `.DS_Store`-grade residue as broken +* presets would teach users to ignore the marker. +* @param root - the directory and the trust its presets inherit. +* @returns the root's presets ordered by id. +*/ +async function scanRoot(root) { + const dir = resolve(expandHomePath(root.path)); + let children; + try { + children = await readdir(dir, { withFileTypes: true }); + } catch (error) { + if (error.code === "ENOENT") return []; + throw new Error(`agent-presets: cannot read preset root ${dir}: ${String(error)}`, { cause: error }); + } + const found = []; + for (const child of children) { + if (!child.isDirectory() || !PRESET_ID.test(child.name)) continue; + const directory = join(dir, child.name); + const path = join(directory, COMPOSITION_FILE); + const broken = await isFile(path) ? await compositionProblem(path) : `the composition file ${COMPOSITION_FILE} is missing — the directory still occupies the id; delete it or restore the file`; + const metadata = await readPresetMetadata(directory); + found.push({ + id: child.name, + trust: root.trust, + path, + ...metadata, + ...broken === void 0 ? {} : { broken } + }); + } + return found.sort((left, right) => { + const byOrder = (left.order ?? Number.POSITIVE_INFINITY) - (right.order ?? Number.POSITIVE_INFINITY); + return byOrder === 0 ? left.id.localeCompare(right.id) : byOrder; + }); +} +/** +* Scan every root in precedence order. +* @param roots - roots in precedence order; an earlier root wins a duplicate id. +* @returns every discovered preset, first-root-wins per id. +*/ +async function discoverPresets(roots) { + const byId = /* @__PURE__ */ new Map(); + for (const root of roots) for (const preset of await scanRoot(root)) { + if (byId.has(preset.id)) continue; + byId.set(preset.id, preset); + } + return [...byId.values()]; +} +//#endregion +//#region lib/types/authoring.js +/** +* Copying, reading, and deleting locally authored presets. +* +* Authoring is confined to a `user` root: the shipped `.system` set is part of +* the deployment, and letting a browser rewrite it would turn "reset to a known +* preset" into something the same caller could have broken first. +* +* The only authoring write is a whole-directory copy of an existing preset. +* No caller supplies composition text: the inputs are ids the host resolves +* against its own roots plus an optional display name, so authoring grants no +* capability the copied preset did not already carry. +* @module @deepseek-ai/dsh-agent-presets/authoring +*/ +/** A preset id that cannot be used as a directory name under a root. */ +var InvalidPresetIdError = class extends Error { + presetId; + constructor(presetId) { + super(`agent-presets: preset id ${JSON.stringify(presetId)} must match ${String(PRESET_ID)} — the id is a directory name, so anything else could escape the preset root`); + this.presetId = presetId; + } +}; +/** A copy target that is already occupied — a copy never overwrites. */ +var PresetExistsError = class extends Error { + presetId; + constructor(presetId) { + super(`agent-presets: preset "${presetId}" already exists — a copy never overwrites; delete the existing preset first or choose another id`); + this.presetId = presetId; + } +}; +/** Authoring was attempted where the deployment allows none. */ +var PresetNotWritableError = class extends Error { + presetId; + constructor(presetId, reason) { + super(`agent-presets: preset "${presetId}" cannot be written: ${reason}`); + this.presetId = presetId; + } +}; +/** +* The root locally authored presets are written to. +* @param roots - the configured roots in precedence order. +* @returns the absolute path of the first `user` root. +* @throws when the deployment configured no writable root. +*/ +function writableRoot(roots) { + const root = roots.find((candidate) => candidate.trust === "user"); + if (root === void 0) throw new PresetNotWritableError("", "this deployment configures no user-writable preset root"); + return resolve(expandHomePath(root.path)); +} +/** +* Read one preset's composition text. +* @param preset - the resolved preset. +* @returns the file's contents. +*/ +async function readComposition(preset) { + return await readFile(preset.path, "utf8"); +} +/** Whether anything occupies the path (cp's own errorOnExist backstops races). */ +async function occupied(path) { + let present = true; + try { + await stat(path); + } catch { + present = false; + } + return present; +} +/** +* Re-tighten a copied tree to owner-only. A shipped preset is world-readable +* in its install and `cp` preserves that; the copy carries the same weight as +* the settings document beside it, so group/other access is stripped. A +* file's owner-execute bit survives — a preset may ship runnable helpers. +*/ +async function tightenModes(dir) { + await chmod(dir, 448); + for (const entry of await readdir(dir, { withFileTypes: true })) { + const target = join(dir, entry.name); + if (entry.isDirectory()) await tightenModes(target); + else + /* v8 ignore next -- Windows exposes no POSIX owner-execute bit; the POSIX lane covers both file modes. */ + await chmod(target, ((await stat(target)).mode & 64) === 0 ? 384 : 448); + } +} +/** +* Create a preset by copying an existing one's whole directory. +* +* The copy carries everything the source directory holds — composition, +* metadata, skill directories, assets — because a preset is its directory, +* not one file. Symlinks are dereferenced so the copy is self-contained +* rather than a set of links back into the install it was copied from. +* +* The copied metadata is then rewritten: the source's description is kept +* (the file is the author's to edit afterwards), but its name and roster +* `order` are not — a copy presenting itself identically to its source, or +* sorted into the shipped set's declared order, would make the roster stop +* distinguishing them. With no name given and no description to keep, the +* file is removed so the copy publishes nothing rather than a blank. +* @param roots - the configured roots; the first `user` one receives the copy. +* @param source - the resolved preset the copy starts from. +* @param id - the new preset's id, which becomes its directory name. +* @param name - display name for the copy; omitted falls back to the id. +* @returns the absolute path of the new preset directory. +* @throws when the id is unusable or already occupied on disk, or the +* deployment configures no writable root. +*/ +async function copyComposition(roots, source, id, name) { + if (!PRESET_ID.test(id)) throw new InvalidPresetIdError(id); + const dir = join(writableRoot(roots), id); + if (await occupied(dir)) throw new PresetExistsError(id); + try { + await cp(dirname(source.path), dir, { + recursive: true, + dereference: true, + force: false, + errorOnExist: true + }); + await tightenModes(dir); + const rendered = renderPresetMetadata({ + ...name === void 0 ? {} : { name }, + ...source.description === void 0 ? {} : { description: source.description } + }); + const metadataPath = join(dir, METADATA_FILE); + if (rendered === void 0) await rm(metadataPath, { force: true }); + else await writeFileAtomic(metadataPath, rendered, { + mode: 384, + dirMode: 448 + }); + } catch (error) { + await rm(dir, { + recursive: true, + force: true + }); + throw error; + } + return dir; +} +/** +* Delete a locally authored preset. +* +* A shipped preset is refused: it belongs to the deployment. A preset a live +* session mounted is NOT refused — the composition was read at creation and is +* never re-read, so that session keeps running exactly as it was. +* @param roots - the configured roots. +* @param preset - the resolved preset to remove. +* @throws when the preset ships with the deployment or lies outside the writable root. +*/ +async function deleteComposition(roots, preset) { + if (preset.trust !== "user") throw new PresetNotWritableError(preset.id, "it ships with the deployment"); + const dir = join(writableRoot(roots), preset.id); + if (!isAbsolute(preset.path) || !preset.path.startsWith(dir)) throw new PresetNotWritableError(preset.id, "it does not live under the writable preset root"); + await rm(dir, { + recursive: true, + force: true + }); +} +//#endregion +//#region lib/types/mount.js +/** +* Mount one preset composition under an agent's scope context, then prove the +* result is usable before the agent is published. +* +* The scope context is what makes the composition per-session: entry contexts +* chain to the context the subtree was plugged into, so every `ctx.tools` +* and `ctx.systemPrompt` registration inside the preset files into that +* agent's layer and unwinds with it. Two guards make that safe. A row that +* never reached a usable state is rejected, because a directly-plugged subtree +* is absent from `ctx.loader.entries()` and no boot audit covers it. A row that +* published a service into the ROOT realm is rejected, because such a service +* is process-global rather than per-session and the second session mounting the +* same preset collides with the first. +* @module @deepseek-ai/dsh-agent-presets/mount +*/ +/** +* Subtrees captured by config identity. A subtree plugged directly (rather than +* created as a loader entry) never links itself to an `Entry`, so this is the +* only handle to the rows it created; config objects are minted per mount, so +* concurrent mounts cannot collide. +*/ +const mounted = /* @__PURE__ */ new WeakMap(); +/** +* The base URL bare specifiers resolve against, per pending mount, keyed by the +* same config object. Recorded before the subtree is plugged, because `Include` +* rewrites its own context's `baseUrl` to the composition's directory and the +* pre-mount value is the only handle on where the harness itself lives. +*/ +const harnessBase = /* @__PURE__ */ new WeakMap(); +/** +* Include subclass that publishes its tree and fiber for the audit, and never +* writes to the file it read. +*/ +var PresetTree = class extends Include { + constructor(ctx, config) { + super(ctx, config); + mounted.set(config, { + tree: this, + fiber: ctx.fiber + }); + } + /** + * Resolve a bare specifier from the harness rather than from the preset. + * + * `EntryTree.import()` resolves against the tree's own `baseUrl`, which + * `Include` sets to the composition's directory. That is right for a + * relative specifier — a preset's own files travel with it — and wrong for + * a package name: a locally authored preset lives under the user's home, + * where Node's upward `node_modules` walk never reaches the harness's own + * dependencies, so every `@deepseek-ai/dsh-*` row would fail to import. The + * mount records the host composition's base instead, which is inside the + * installed harness, and bare names resolve from there. An absolute + * filesystem path names neither base and becomes a file URL before Node's + * ESM loader receives it, which is required for drive-letter paths on + * Windows. + * @param name - the module specifier from the row. + * @param getOuterStack - the loader's stack composer for import diagnostics. + * @returns the imported module, or the `cordis:` builtin. + */ + import(name, getOuterStack) { + const specifier = isAbsolute(name) ? pathToFileURL(name).href : name; + const base = harnessBase.get(this.config); + /* v8 ignore next -- every PresetTree is constructed by `mountPreset`, which records the base first */ + if (base === void 0) return super.import(specifier, getOuterStack); + if (name.startsWith(".") || name.startsWith("cordis:")) return super.import(name, getOuterStack); + const internal = this.ctx.loader.internal; + /* v8 ignore next -- Node always supplies the internal module loader; the branch keeps a + hypothetical embedder from losing the row's name in a resolution error. */ + if (internal === void 0) return super.import(specifier, getOuterStack); + return internal.import(specifier, base, {}); + } + /** + * A preset is an input, never a persistence target. + * + * The Loader writes a tree back through this method whenever it decides the + * config changed — a plugin self-disposing is enough, and tearing an agent + * down disposes its whole subtree. Inherited, that rewrites the preset file + * with whatever the dying tree held, which in practice means truncating a + * shipped composition to `[]` the first time a session ends. Persisting a + * preset is also meaningless: nothing here is user state, and the same file + * backs every session that names it. + * + * Dropping the write drops the `loader/config-update` the inherited method + * emits with it. Nothing observes one for a preset subtree today, and a + * future "edit your preset while it runs" flow needs a deliberate + * persistence path rather than this method's return. + */ + write() {} +}; +const mounts = /* @__PURE__ */ new Set(); +/** +* Drop every record whose subtree is gone. +* +* Records are pruned by observation rather than through a disposal hook +* because a subtree can be torn down by its owning agent, by a failed mount, or +* by the whole tree unloading, and a cleared `uid` is what all three share. +* +* Pruning therefore has to happen on a path this module owns. Reading is one +* such path, but not a reliable one: the only production reader is the +* invariant companion's service listener, and `dsh-invariants` is a +* development composition — a shipped host never loads it. Mounting is the +* other, and it is the one every session takes, which bounds the set at one +* generation of dead records rather than one per session ever composed. Each +* record would otherwise retain its whole disposed subtree: the fiber holds +* its config, and that config is the key its `EntryTree` is stored under. +*/ +function pruneDisposedMounts() { + for (const mount of mounts) if (mount.fiber.uid === null) mounts.delete(mount); +} +/** +* Every preset composition still installed, pruning fibers disposed since the +* last read. +* @returns the live mounts. +*/ +function livePresetMounts() { + pruneDisposedMounts(); + return [...mounts]; +} +/** +* Whether `fiber` is `root` itself or is mounted anywhere inside its subtree. +* +* Membership is object identity. `uid` looks like a cheaper key but is a +* per-registry counter, so fibers in two different roots collide on it and a +* subtree in one runtime would be blamed for a service published in another. +* @param fiber - the fiber to locate. +* @param root - the subtree root to test membership against. +* @returns true when `fiber` belongs to `root`'s subtree. +*/ +function withinFiber(fiber, root) { + let current = fiber; + while (true) { + if (current === root) return true; + const parent = current.parent.fiber; + if (parent === current) return false; + current = parent; + } +} +/** +* Service names the mounted subtree published into the root realm. +* +* A provider without an `isolate` realm stores its implementation under the +* root's symbol for that name, which is exactly the comparison below; a +* provider inside an `isolate` realm stores under a realm-private symbol and +* is correctly absent here. +* @param ctx - any context of the runtime whose service store is inspected. +* @param mount - the mounted subtree's fiber. +* @returns the leaked service names in lexical order. +*/ +function leakedServices(ctx, mount) { + const store = ctx.reflect.store; + const rootIsolate = ctx.root[Context.isolate]; + const leaked = []; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than + clearing it, so an own symbol always resolves; the guard exists only + because the store's index signature is optional. */ + if (impl === void 0) continue; + if (!withinFiber(impl.fiber, mount)) continue; + if (rootIsolate[impl.name] === key) leaked.push(impl.name); + } + return leaked.sort((left, right) => left.localeCompare(right)); +} +/** +* The standing composition one agent is joined to. +* +* The agent's own key is parented to its preset's standing key, so the mount +* is found by matching that parent rather than by walking up from the agent — +* the mount is not under the agent's fiber. An agent that joined no preset — +* a deployment composing no roster, or a child agent before its join — has no +* parent link and resolves to undefined. +* @param agentCtx - the agent's scope context. +* @returns the mount the agent joined, or undefined when it joined none. +*/ +function standingMountFor(agentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) return void 0; + const standingKey = scopeParentOf(agentKey); + if (standingKey === void 0) return void 0; + return livePresetMounts().find((candidate) => candidate.key === standingKey); +} +/** +* One agent's instance of a service its preset mounted. +* +* A preset publishes a service behind an `isolate` realm so two sessions +* cannot collide, and an entry-local realm is invisible to everything outside +* the group — including the agent's own scope context and the host. That is +* right for the rows inside the group and wrong for one caller: a request that +* is ABOUT a session but arrives from outside it, which is every browser RPC +* the api-proxy serves. +* +* Ownership is the same relation {@link leakedServices} reads, inverted: there +* it names implementations a subtree published into the ROOT realm, here it +* names the one this subtree published anywhere. Fiber membership is object +* identity for the reason stated on {@link withinFiber}. +* +* This is READ addressing for a caller that already holds the agent. It is not +* a general host handle on a session's internals: a host row that `inject`s a +* service cannot use it, because injection resolves before any session exists +* and has no agent to key by — such a service belongs on the host plane. +* @param ctx - any context of the runtime whose service store is inspected. +* @param agent - the agent whose mounted composition to look inside. +* @param name - the service name as the preset's rows resolve it. +* @returns the agent's instance, or undefined when its preset mounts none. +*/ +function serviceForAgent(ctx, agent, name) { + const mount = standingMountFor(agent.ctx); + if (mount === void 0) return void 0; + const store = ctx.reflect.store; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than clearing it */ + if (impl === void 0) continue; + if (impl.name !== name) continue; + if (withinFiber(impl.fiber, mount.fiber)) return impl.value; + } +} +/** +* Rows that did not reach a usable state, each rendered as one diagnostic line. +* +* A row whose module failed to import or whose plugin threw already rejects the +* mount through the loader; what remains observable here is a row still waiting +* for a service the composition never supplies. +* @param tree - the mounted subtree. +* @returns one line per unusable row, empty when every enabled row is usable. +*/ +function inactiveRows(tree) { + const lines = []; + for (const entry of tree.entries()) { + if (entry.disabled) continue; + const fiber = entry.fiber; + /* v8 ignore next 4 -- the loader rejects an entry whose module or plugin failed, + so a settled tree never holds an enabled fiber-less entry; the branch exists + only because `Entry.fiber` is declared optional. */ + if (fiber === void 0) { + lines.push(`${entry.options.id} (${entry.options.name}): never started`); + continue; + } + const missing = Object.keys(fiber.inject).filter((name) => fiber.ctx.get(name) === void 0); + if (missing.length > 0) lines.push(`${entry.options.id} (${entry.options.name}): waiting for ${missing.join(", ")}`); + } + return lines; +} +/** +* The reportable text of a mount failure. +* +* The loader reports several failed rows as one `AggregateError`, whose own +* message names none of them; without flattening, a composition that fails on +* two rows says only "loader entries failed to apply" and the operator has +* nothing to act on. +* @param error - the value the mount rejected with. +* @returns a single-line-per-cause description. +*/ +function mountDetail(error) { + /* v8 ignore next -- every path into the mount's catch throws an Error: the loader + wraps a row's thrown value before it propagates, and this module's own + rejections are Errors. The fallback keeps a hostile value readable. */ + if (!(error instanceof Error)) return String(error); + if (!(error instanceof AggregateError)) return error.message; + return [error.message, ...error.errors.map((cause) => `- ${mountDetail(cause)}`)].join("\n"); +} +/** +* Mount `preset` under `agentCtx` and return only once every row is usable. +* +* The subtree is owned by `agentCtx`'s fiber, so it unwinds with the agent and +* the caller receives no disposer. A rejection leaves nothing mounted. +* @param agentCtx - the agent's scope context, from the agent factory's `setup`. +* @param preset - the resolved preset to compose the agent from. +* @throws when `agentCtx` carries no scope, a row is unusable, or a row +* published a service into the root realm. +*/ +async function mountPreset(agentCtx, preset) { + if (scopeOf(agentCtx) === void 0) throw new Error(`agent-presets: refusing to mount preset "${preset.id}" into an unscoped context; its registrations would apply to every agent in the process`); + const config = { path: pathToFileURL(preset.path).href }; + /* v8 ignore next -- the Loader sets `baseUrl` on the root before any scoped context derives from it */ + if (agentCtx.baseUrl !== void 0) harnessBase.set(config, agentCtx.baseUrl); + pruneDisposedMounts(); + const handle = agentCtx.plugin(PresetTree, config); + try { + await handle.await(); + const subtree = mounted.get(config); + /* v8 ignore next -- the subclass constructor runs before `await()` settles for every mounted tree */ + if (subtree === void 0) throw new Error("mounted subtree did not publish its entry tree"); + const { tree, fiber } = subtree; + const unusable = inactiveRows(tree); + if (unusable.length > 0) throw new Error(`${String(unusable.length)} row(s) did not activate:\n${unusable.join("\n")}`); + const leaked = leakedServices(agentCtx, fiber); + if (leaked.length > 0) throw new Error(`row(s) published process-global service(s) [${leaked.join(", ")}]; a preset service must sit behind an \`isolate\` realm or move to the host composition`); + mounts.add({ + presetId: preset.id, + fiber, + key: scopeOf(agentCtx) + }); + } catch (error) { + try { + await handle.dispose(); + } catch {} + throw new PresetMountError(preset.id, `${mountDetail(error)} (${preset.path})`, { cause: error }); + } +} +//#endregion +//#region lib/types/session.js +/** +* The session-log record of which preset a session actually runs. +* +* The creation header names the preset a session STARTED with, and it is +* deep-frozen because that is a creation fact. A session may still change +* preset while it is blank, and the effect of that change outlives the blank +* window: the first turn — and every turn after it — runs under the newly +* mounted composition. Recording the change is what keeps the log honest, and +* it is required outright by the repo's model-visible ⟺ logged rule, since the +* preset decides the tool schemas and prompt sections the model sees. +* +* Reconstruction reads {@link resolveSessionPreset}, never the header alone. +* @module @deepseek-ai/dsh-agent-presets/session +*/ +/** +* The preset a session actually runs, newest selection winning. +* +* The header supplies the creation-time value; every later selection is a +* logged event, so the last one is the answer. Reading the header alone +* rebuilds a switched session under the composition it was created with, not +* the one its history was produced under. +* @param session - the session's header and event log. +* @returns the preset id, or `undefined` when the deployment composes none. +*/ +function resolveSessionPreset(session) { + for (let index = session.events.length - 1; index >= 0; index -= 1) { + const event = session.events[index]; + if (event?.type === "agent-preset/selected") return event.data.agentPreset; + } + return session.header.agentPreset; +} +//#endregion +//#region lib/types/index.js +/** +* Agent presets: each session composes its model-facing plugin set from one +* preset `cordis.yml`, mounted ONCE per preset under a standing scope and +* joined by every agent that names it. +* +* The standing mount is what makes a preset one composition rather than one +* per session: its plugin instances, tool registrations, prompt sections, and +* projection units exist exactly once, keyed per session inside the plugins +* themselves (they predate presets and were written for a shared world). An +* agent joins by having its scope key parented to the mount's +* ({@link bindScopeParent}), which makes the mount's registrations visible to +* that agent's views and the mount's listeners receive that agent's events — +* and a host reader with no agent at all (a cold transcript read) resolves +* the same standing registrations by preset id. +* +* This package owns the preset vocabulary, filesystem discovery, and the +* guarded standing mount. It does not decide when an agent is created — the +* agent factory's `setup(agentCtx)` hook is the one supported call site, +* because only there is the join installed while the agent is still +* unpublished, so a rejected composition rolls the whole creation back. +* @module @deepseek-ai/dsh-agent-presets +*/ +/** Settings namespace carrying the user's chosen default preset. */ +const SETTINGS_NAMESPACE = "agent-presets"; +/** Runtime schema for the user-writable slice. */ +const AgentPresetSettingsSchema = z.object({ default: z.string() }); +/** +* Registry over the deployment's agent presets. +* +* Discovery is unmemoized: `list()` and `resolve()` re-read the roots on every +* call so a preset authored while the process runs is visible immediately, +* and a preset deleted underneath a picker disappears from the next read. +*/ +var AgentPresets = class extends Service { + config; + static inject = ["loader"]; + /** Runtime schema for the preset roster. */ + static Config = z.object({ + default: z.string().required(), + roots: z.array(z.object({ + path: z.string().required(), + trust: z.union(["system", "user"]).default("user") + })).default([]), + includeUserRoot: z.boolean().default(true) + }); + /** + * The roots discovery and authoring actually scan: every configured root in + * order, then the harness-home user root unless `includeUserRoot` is false. + * + * Derived once, because a root set that changed between `list()` and the + * `copy()` acting on its answer would author into a directory the caller + * never saw. Appending rather than prepending keeps an earlier configured + * root winning a duplicate id, so a shipped preset still shadows a + * locally authored directory that claimed its name. + */ + resolvedRoots; + /** + * The user layer over `config.default`, present only while a settings + * provider is composed. Held rather than snapshotted so a hot-reloaded + * document takes effect without a restart. + */ + settings; + /** + * The settings service behind {@link settings}, held for the one write this + * service makes: clearing a user default it has just deleted. + */ + settingsService; + /** + * The service's own untraced context. Methods invoked through the traceable + * proxy see `this.ctx` rebound to the CALLER's context, which carries a + * shadow; a subtree minted from it resolves every service through that + * shadow's fiber instead of each entry's own inject store, so preset rows + * would fail on the very services they declare. Standing mounts must hang + * off the untraced original (the `jobs-local` selfCtx precedent). + */ + selfCtx; + constructor(ctx, config) { + super(ctx, "agentPresets"); + this.config = config; + this.selfCtx = ctx; + this.resolvedRoots = config.includeUserRoot ? [...config.roots, { + path: dshHomePath(USER_PRESET_DIR), + trust: "user" + }] : [...config.roots]; + ctx.inject(["settings"], (settingsCtx) => { + this.settings = settingsCtx.settings.register(settingsNamespace(SETTINGS_NAMESPACE), AgentPresetSettingsSchema, { base: { default: config.default } }); + this.settingsService = settingsCtx.settings; + settingsCtx.effect(() => () => { + this.settings = void 0; + this.settingsService = void 0; + }, "agentPresets.settings()"); + }); + ctx.on("agent/created", ({ agent }) => { + if (this.resolvedRoots.length === 0) return; + if (this.composedPreset(agent.ctx) !== void 0) return; + ctx.logger.warn(`agent "${agent.id}" was published without joining an agent preset; its tools, prompt sections, and skill catalog resolve against the empty global layer (join through AgentPresets.mount() or composeFrom() in the agent factory setup)`); + }); + ctx.on("session/event", (session, event) => { + if (event.type !== "agent-preset/selected") return; + ctx.emit("agent-preset/selected", session.id, event.data.agentPreset); + }); + } + /** + * The preset id mounted when a caller names none. + * + * Read per call rather than cached: the settings document is hot-reloaded, so + * changing the default takes effect on the next session created and leaves + * every running session on the preset it was composed from. + */ + get defaultId() { + return this.settings?.get().default ?? this.config.default; + } + /** + * Every preset the configured roots currently supply. + * @returns the presets, first-root-wins per id. + */ + async list() { + return await discoverPresets(this.resolvedRoots); + } + /** + * Resolve one preset by id. + * + * A broken preset resolves — deleting one, reading one, and reporting one + * all need the row — and the mounting paths refuse it AFTER resolution + * through {@link resolveMountable}. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved preset. + * @throws when no configured root supplies that id. + */ + async resolve(id) { + const wanted = id ?? this.defaultId; + const presets = await this.list(); + const found = presets.find((preset) => preset.id === wanted); + if (found === void 0) throw new UnknownPresetError(wanted, presets.map((preset) => preset.id)); + return found; + } + /** + * Resolve one preset that is about to compose an agent, refusing a broken + * one with its discovery-reported reason. Failing here rather than inside + * the loader keeps the answer the same for every unloadable shape — ghost + * directory, unparsable YAML, rowless list — and spends no mount attempt + * on a composition discovery already read as unusable. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved, mountable preset. + * @throws when the preset is unknown or discovery reports it broken. + */ + async resolveMountable(id) { + const preset = await this.resolve(id); + if (preset.broken !== void 0) throw new PresetMountError(preset.id, preset.broken); + return preset; + } + /** + * Standing mounts by preset id, single-flight so two agents racing the + * first use of one preset share one composition. A settled failure is + * removed so a later session retries a preset whose file has been fixed; a + * settled success serves until the composition FILE visibly changes — each + * generation records its file stamp, and a stale stamp starts the next + * generation for sessions created afterwards. Sessions already joined keep + * the generation they run on; a superseded one is never disposed while the + * process lives (reclaimed only by whole-tree teardown), so editing files + * is bounded by how often compositions change, not by session count. + */ + standing = /* @__PURE__ */ new Map(); + /** + * Parent bindings of the agents this roster composed, keyed by the agent's + * scope key. The binding is dsh-scope's only re-link capability; holding it + * here makes this service the sole authority that can move an agent between + * standing compositions. WeakMap: entries die with their agents. + */ + bindings = /* @__PURE__ */ new WeakMap(); + /** + * Compose one agent from a preset: ensure the preset's standing mount, then + * parent the agent's scope key to it so the mount's registrations and + * listeners cover this agent. + * + * Call from the agent factory's `setup(agentCtx)`; a rejection there rolls + * the agent creation back, so a broken preset never yields a half-composed + * session. + * @param agentCtx - the agent's scope context. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the preset that was composed, for the caller to record. + * @throws when the preset is unknown or its composition is unusable. + */ + async mount(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset"); + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return preset; + } + /** + * Join one agent to the SAME standing composition another already runs on. + * + * This is how a child agent inherits its parent's capabilities. It is a bind, + * not a mount: the parent's generation is already composed, so the child gets + * that exact instance — the same plugin objects, the same tool registrations, + * the same prompt sections. Re-resolving the parent's preset by id instead + * would re-read the roster, and a composition file edited since the parent + * started would hand the child a DIFFERENT generation than the one its + * parent's history was produced under (and a preset deleted since would fail + * the child outright while its parent keeps running). + * + * Synchronous, and with no composition failure mode of its own — it reads no + * roster, mounts nothing, and touches no file — which is what lets a child + * creation window use it: the two in-process subagent drivers compose their + * children inside a synchronous `setup`. It still rejects a caller error, as + * the `@throws` below record. + * + * A parent that joined no preset — a rosterless deployment — yields no join + * and no error: there, the model-facing rows sit in the host composition and + * the child already sees them through the global layer. + * @param agentCtx - the joining agent's scope context. + * @param parentCtx - the scope context of the agent whose composition to join. + * @returns the preset id joined, or undefined when the parent joined none. + * @throws when `agentCtx` carries no scope, or has already joined a preset. + */ + composeFrom(agentCtx, parentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset"); + const standing = standingMountFor(parentCtx); + if (standing === void 0) return void 0; + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return standing.presetId; + } + /** + * The preset one live agent runs on. + * + * Read from the live scope chain rather than from the session, so it answers + * for an agent whose session has not recorded a preset yet — a child agent + * whose durable header is being built from its parent's composition. + * @param agentCtx - the agent's scope context. + * @returns the preset id, or undefined when the agent joined none. + */ + composedPreset(agentCtx) { + return standingMountFor(agentCtx)?.presetId; + } + /** + * The roots this roster scans, which is not `config.roots`: it is every + * configured root in order, then the harness-home user root unless + * `includeUserRoot` is false. Read this — not the config field — to answer + * whether a roster is composed at all, so one derivation decides it. + */ + get roots() { + return this.resolvedRoots; + } + /** Whether this deployment has a root locally authored presets go to. */ + get authorable() { + return this.resolvedRoots.some((root) => root.trust === "user"); + } + /** + * Read one preset's composition text. + * @param id - the preset id. + * @returns the composition exactly as stored. + * @throws when no configured root supplies that id. + */ + async read(id) { + return await readComposition(await this.resolve(id)); + } + /** + * Create a locally authored preset by copying an existing one whole. + * + * Copy is the only authoring write. Composition text never crosses this + * seam: the source is named by id and its directory is copied as it stands, + * so the copy is exactly as loadable as its source and authoring grants no + * capability the roster did not already carry. The copy is NOT mounted to + * validate — a source that mounts today yields a copy that mounts today. + * @param from - the preset the copy starts from; shipped presets are the + * primary source, so any trust is accepted. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; absent falls back to the id. + * @throws when the source is unknown, the id is unusable or already taken, + * or the deployment configures no writable root. + */ + async copy(from, id, name) { + const source = await this.resolve(from); + if ((await this.list()).some((preset) => preset.id === id)) throw new PresetExistsError(id); + await copyComposition(this.resolvedRoots, source, id, name); + this.standing.delete(id); + } + /** + * Delete a locally authored preset. + * @param id - the preset id. + * @throws when the preset is unknown or ships with the deployment. + */ + async remove(id) { + await deleteComposition(this.resolvedRoots, await this.resolve(id)); + this.standing.delete(id); + if (this.settings?.get().default !== id) return; + await this.settingsService?.mutate(settingsNamespace(SETTINGS_NAMESPACE), [{ + op: "unset", + path: ["default"] + }]); + } + /** + * One agent's instance of a service its preset mounted. + * + * A preset publishes services behind `isolate` realms, which are invisible + * outside the group that declares them — including to the host. This is how a + * caller holding the agent reads one anyway: a request that is ABOUT a + * session but arrives from outside it, which is every browser RPC. + * + * Read addressing only. A host row that `inject`s a service cannot use this, + * because injection resolves before any session exists and has no agent to + * key by; such a service belongs on the host plane instead. + * @param agent - the agent whose composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ + serviceFor(agent, name) { + return serviceForAgent(this.ctx, agent, name); + } + /** + * Re-link one agent to a different preset's standing composition. + * + * Only valid while the agent has produced nothing: swapping tools mid + * conversation would leave logged tool calls the new composition cannot + * make. The CALLER owns that check — this method does not read session + * history. + * + * The swap is a parent re-link, not an unmount: standing mounts are shared + * and permanent, so the old composition stays for its other agents and the + * new one is ensured BEFORE the link moves. An unknown or unusable preset + * therefore throws with the agent exactly as it was — there is no torn-down + * state to restore. The re-link runs through the binding this roster kept + * from the agent's mount — dsh-scope's only re-link authority. An agent + * that never composed one has nothing to re-link: the switch is then the + * agent's first bind, exactly a mount. + * @param agentCtx - the agent's scope context. + * @param id - the preset to compose the agent from instead. + * @returns the preset now installed. + * @throws when the preset is unknown or its composition is unusable. + */ + async recompose(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to recompose an unscoped context"); + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + const binding = this.bindings.get(agentKey); + if (binding === void 0) this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + else binding.rebind(standing.key); + return preset; + } + /** + * The standing scope key of one preset, for a host reader with no agent. + * + * A cold transcript read resolves tool presenters against the composition + * the session recorded, and the standing mount makes that possible without + * resuming anything: ensuring the mount composes plugins but starts no + * agent, no session, and no turn. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the standing scope key readers pass as a registry view scope. + * @throws when the preset is unknown or its composition is unusable. + */ + async standingKeyFor(id) { + const preset = await this.resolveMountable(id); + return (await this.ensureStanding(preset)).key; + } + /** Resolve (or create, single-flight) the standing mount of one preset. */ + async ensureStanding(preset) { + const pending = this.standing.get(preset.id); + if (pending !== void 0) { + const mounted = await pending; + const current = await compositionStamp(preset.path); + if (current === void 0 || sameStamp(mounted.stamp, current)) return mounted; + if (this.standing.get(preset.id) === pending) this.standing.delete(preset.id); + return this.ensureStanding(preset); + } + const created = (async () => { + const key = { agentPreset: preset.id }; + const scope = createScope(this.selfCtx, key); + try { + const stamp = await compositionStamp(preset.path); + if (stamp === void 0) throw new PresetMountError(preset.id, `composition file is unreadable: ${preset.path}`); + await mountPreset(scope.ctx, preset); + return { + key, + scope, + stamp + }; + } catch (error) { + this.standing.delete(preset.id); + await scope.dispose(); + throw error; + } + })(); + this.standing.set(preset.id, created); + return created; + } +}; +/** Read one composition file's stamp, or undefined when it cannot be statted. */ +async function compositionStamp(path) { + try { + const { mtimeMs, size } = await stat(path); + return { + mtimeMs, + size + }; + } catch { + return; + } +} +/** Whether two stamps name the same file state. */ +function sameStamp(a, b) { + return a.mtimeMs === b.mtimeMs && a.size === b.size; +} +//#endregion +export { AgentPresetSettingsSchema, AgentPresets, AgentPresets as default, COMPOSITION_FILE, InvalidPresetIdError, METADATA_FILE, PresetExistsError, PresetMountError, PresetNotWritableError, SETTINGS_NAMESPACE, UnknownPresetError, copyComposition, deleteComposition, discoverPresets, inactiveRows, leakedServices, livePresetMounts, mountPreset, readComposition, readPresetMetadata, renderPresetMetadata, resolveSessionPreset, scanRoot, serviceForAgent, standingMountFor, writableRoot }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/invariant.js new file mode 100644 index 0000000..107adfc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/invariant.js @@ -0,0 +1,1178 @@ +import { chmod, cp, readFile, readdir, rm, stat } from "node:fs/promises"; +import { Context, Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { bindScopeParent, createScope, scopeOf, scopeParentOf } from "@deepseek-ai/dsh-scope"; +import { settingsNamespace } from "@deepseek-ai/dsh-settings"; +import { dshHomePath, expandHomePath } from "@deepseek-ai/dsh-home-paths"; +import { dirname, isAbsolute, join, resolve } from "node:path"; +import yaml, { load } from "js-yaml"; +import { Include, entryListSchema } from "@deepseek-ai/cordis-plugin-include"; +import { writeFileAtomic } from "@deepseek-ai/dsh-atomic-write"; +import { pathToFileURL } from "node:url"; +//#region src/metadata.ts +/** +* A preset's display metadata: the name and description a picker shows. +* +* It lives in its own file because the composition is a top-level list of +* plugin rows — YAML cannot carry sibling keys beside it, and faking a +* metadata row would hand the Loader something to load. Keeping it separate +* also keeps the composition exactly what its name says: a Cordis file the +* loader owns and the cordis preset can author. +* +* The file carries display text ONLY. `id` is the directory name and `trust` +* comes from the root a preset was discovered under, so neither is writable +* here — otherwise a locally authored preset could claim to be a shipped one. +* +* Every read failure degrades to no metadata. A preset whose display text is +* missing, malformed, or unreadable still mounts: presentation is not a +* capability, and a broken name must never become an agent that cannot start. +* @module @deepseek-ai/dsh-agent-presets/metadata +*/ +/** The optional display-metadata file beside a preset's composition. */ +const METADATA_FILE = "preset.yml"; +/** A non-empty trimmed string, or undefined for anything else. */ +function text(value) { + if (typeof value !== "string") return void 0; + const trimmed = value.trim(); + return trimmed === "" ? void 0 : trimmed; +} +/** +* Read one preset directory's display metadata. +* +* Absent, unparsable, and wrongly-shaped files are all the same answer — +* empty metadata — because the caller renders a picker, not a diagnostic. +* @param directory - the preset directory. +* @returns the display text the preset published, possibly empty. +*/ +async function readPresetMetadata(directory) { + let raw; + try { + raw = await readFile(join(directory, METADATA_FILE), "utf8"); + } catch { + return {}; + } + let parsed; + try { + parsed = yaml.load(raw); + } catch { + return {}; + } + if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {}; + const record = parsed; + const name = text(record.name); + const description = text(record.description); + const order = typeof record.order === "number" && Number.isFinite(record.order) ? record.order : void 0; + return { + ...name === void 0 ? {} : { name }, + ...description === void 0 ? {} : { description }, + ...order === void 0 ? {} : { order } + }; +} +/** +* Render display metadata as the file's contents. +* +* Absent fields are omitted rather than written empty, so a preset with no +* description does not ship a key that reads as an intentional blank. +* @param metadata - the display text to store. +* @returns the YAML document, or undefined when there is nothing to store. +*/ +function renderPresetMetadata(metadata) { + const name = text(metadata.name); + const description = text(metadata.description); + const { order } = metadata; + if (name === void 0 && description === void 0 && order === void 0) return void 0; + return yaml.dump({ + ...name === void 0 ? {} : { name }, + ...description === void 0 ? {} : { description }, + ...order === void 0 ? {} : { order } + }, { lineWidth: -1 }); +} +//#endregion +//#region src/preset.ts +/** +* Ids a preset directory may use. +* +* The id becomes a path segment, so this is a containment boundary rather than +* a style rule: `..`, a separator, or an absolute-looking name would place the +* composition outside the root the deployment authorised. Discovery shares it: +* a directory whose name no copy could ever claim is not a preset slot. +*/ +const PRESET_ID = /^[a-z0-9][a-z0-9-]*$/; +/** +* No configured root supplies the requested preset. +* +* Separate from a mount failure because the two mean different things to a +* caller: an unknown id is a bad request, while an unusable composition is a +* broken preset the deployment must fix. +*/ +var UnknownPresetError = class extends Error { + presetId; + available; + constructor(presetId, available) { + super(`agent-presets: preset "${presetId}" not found (available: ${available.join(", ") || "none"})`); + this.presetId = presetId; + this.available = available; + } +}; +/** A preset exists but its composition cannot be installed. */ +var PresetMountError = class extends Error { + presetId; + reason; + constructor(presetId, reason, options) { + super(`agent-presets: preset "${presetId}" failed to mount: ${reason}`, options); + this.presetId = presetId; + this.reason = reason; + } +}; +//#endregion +//#region src/discovery.ts +/** +* Filesystem discovery of agent presets. A preset is a directory holding +* {@link COMPOSITION_FILE}, optionally beside a {@link METADATA_FILE} carrying +* its display text; the directory name is the preset id. Discovery +* re-reads the roots on every call so a preset authored while the process is +* running is visible without a restart. +* +* Discovery also owns preset HEALTH: a directory whose composition is +* missing or unloadable is reported as a broken roster row rather than +* skipped. A skipped directory would still occupy its id on disk — the copy +* path refuses the name while no surface shows anything to delete — and a +* malformed composition would otherwise read as an ordinary preset until the +* first session fails to mount it. +* @module @deepseek-ai/dsh-agent-presets/discovery +*/ +/** The composition file that makes a directory a preset. */ +const COMPOSITION_FILE = "agent.cordis.yml"; +/** +* Harness-home directory holding locally authored presets. +* +* This package owns the writable root the way `dsh-skill-filesystem` owns +* `/skills`. An app must assemble the SHIPPED root, whose path only +* the installed app can resolve; where a person's own presets go is the same +* place in every deployment that does not say otherwise, so a launcher that +* forgets to configure one still finds them. +* +* Package-internal on purpose: no consumer outside this package addresses the +* directory by name, and a test that imported it could not catch this value +* being wrong — the expected segment is spelled out where it is asserted. +*/ +const USER_PRESET_DIR = ".agent-presets"; +/** +* Why `rows` cannot be an entry list, or undefined when it can. +* +* A shallow shape check, deliberately short of the loader's work: it does not +* resolve plugin names or apply configs. What it catches is the hand-edit +* that produces a file the loader cannot even begin with — and it must accept +* everything the loader accepts, which is why rows are only required to be +* maps carrying a plugin `name` (groups recurse into their own lists). +* @param rows - the parsed composition document. +* @param at - row-path prefix for nested diagnostics, empty at the top level. +* @returns one human-readable reason, or undefined when the shape holds. +*/ +function entryListProblem(rows, at = "") { + if (!Array.isArray(rows)) return at === "" ? "the composition must be a top-level list of plugin rows" : `group ${at} must hold a list of plugin rows`; + for (const [index, row] of rows.entries()) { + const label = at === "" ? `row ${String(index + 1)}` : `${at} row ${String(index + 1)}`; + if (typeof row !== "object" || row === null || Array.isArray(row)) return `${label} is not a plugin row (expected a map with a "name")`; + const { name, group, config } = row; + if (typeof name !== "string" || name === "") return `${label} names no plugin (a "name" string is required)`; + if (group === true) { + const nested = entryListProblem(config, label); + if (nested !== void 0) return nested; + } + } +} +/** +* Why the composition at `path` cannot mount, or undefined when it looks +* loadable. Parsed with the loader's own YAML dialect ({@link entryListSchema}, +* the one carrying `!!js`), so health can never call a composition broken +* that the loader would accept. +* @param path - absolute path of the composition file. +* @returns one human-readable reason, or undefined when the file is loadable. +*/ +async function compositionProblem(path) { + let content; + try { + content = await readFile(path, "utf8"); + } catch { + return `the composition file ${COMPOSITION_FILE} cannot be read`; + } + let rows; + try { + rows = load(content, { schema: entryListSchema }); + } catch (error) { + return `the composition is not valid YAML: ${(error instanceof Error ? error.message : String(error)).replace(/\n[\s\S]*$/, "")}`; + } + return entryListProblem(rows); +} +/** +* Whether `path` names an existing regular file. +* @param path - absolute path to test. +* @returns true when the path resolves to a file. +*/ +async function isFile(path) { + try { + return (await stat(path)).isFile(); + } catch { + return false; + } +} +/** +* Scan one root for preset directories. +* +* An absent root yields no presets rather than throwing: the user root does +* not exist until the first locally authored preset, and naming a default +* that no root supplies already fails loud at resolution. +* +* Every directory whose name is a usable preset id is a roster row — broken +* when its composition is missing or unloadable. A directory named outside +* {@link PRESET_ID} is skipped instead: no copy could ever claim that name, +* so it blocks nothing, and reporting `.DS_Store`-grade residue as broken +* presets would teach users to ignore the marker. +* @param root - the directory and the trust its presets inherit. +* @returns the root's presets ordered by id. +*/ +async function scanRoot(root) { + const dir = resolve(expandHomePath(root.path)); + let children; + try { + children = await readdir(dir, { withFileTypes: true }); + } catch (error) { + if (error.code === "ENOENT") return []; + throw new Error(`agent-presets: cannot read preset root ${dir}: ${String(error)}`, { cause: error }); + } + const found = []; + for (const child of children) { + if (!child.isDirectory() || !PRESET_ID.test(child.name)) continue; + const directory = join(dir, child.name); + const path = join(directory, COMPOSITION_FILE); + const broken = await isFile(path) ? await compositionProblem(path) : `the composition file ${COMPOSITION_FILE} is missing — the directory still occupies the id; delete it or restore the file`; + const metadata = await readPresetMetadata(directory); + found.push({ + id: child.name, + trust: root.trust, + path, + ...metadata, + ...broken === void 0 ? {} : { broken } + }); + } + return found.sort((left, right) => { + const byOrder = (left.order ?? Number.POSITIVE_INFINITY) - (right.order ?? Number.POSITIVE_INFINITY); + return byOrder === 0 ? left.id.localeCompare(right.id) : byOrder; + }); +} +/** +* Scan every root in precedence order. +* @param roots - roots in precedence order; an earlier root wins a duplicate id. +* @returns every discovered preset, first-root-wins per id. +*/ +async function discoverPresets(roots) { + const byId = /* @__PURE__ */ new Map(); + for (const root of roots) for (const preset of await scanRoot(root)) { + if (byId.has(preset.id)) continue; + byId.set(preset.id, preset); + } + return [...byId.values()]; +} +//#endregion +//#region src/authoring.ts +/** +* Copying, reading, and deleting locally authored presets. +* +* Authoring is confined to a `user` root: the shipped `.system` set is part of +* the deployment, and letting a browser rewrite it would turn "reset to a known +* preset" into something the same caller could have broken first. +* +* The only authoring write is a whole-directory copy of an existing preset. +* No caller supplies composition text: the inputs are ids the host resolves +* against its own roots plus an optional display name, so authoring grants no +* capability the copied preset did not already carry. +* @module @deepseek-ai/dsh-agent-presets/authoring +*/ +/** A preset id that cannot be used as a directory name under a root. */ +var InvalidPresetIdError = class extends Error { + presetId; + constructor(presetId) { + super(`agent-presets: preset id ${JSON.stringify(presetId)} must match ${String(PRESET_ID)} — the id is a directory name, so anything else could escape the preset root`); + this.presetId = presetId; + } +}; +/** A copy target that is already occupied — a copy never overwrites. */ +var PresetExistsError = class extends Error { + presetId; + constructor(presetId) { + super(`agent-presets: preset "${presetId}" already exists — a copy never overwrites; delete the existing preset first or choose another id`); + this.presetId = presetId; + } +}; +/** Authoring was attempted where the deployment allows none. */ +var PresetNotWritableError = class extends Error { + presetId; + constructor(presetId, reason) { + super(`agent-presets: preset "${presetId}" cannot be written: ${reason}`); + this.presetId = presetId; + } +}; +/** +* The root locally authored presets are written to. +* @param roots - the configured roots in precedence order. +* @returns the absolute path of the first `user` root. +* @throws when the deployment configured no writable root. +*/ +function writableRoot(roots) { + const root = roots.find((candidate) => candidate.trust === "user"); + if (root === void 0) throw new PresetNotWritableError("", "this deployment configures no user-writable preset root"); + return resolve(expandHomePath(root.path)); +} +/** +* Read one preset's composition text. +* @param preset - the resolved preset. +* @returns the file's contents. +*/ +async function readComposition(preset) { + return await readFile(preset.path, "utf8"); +} +/** Whether anything occupies the path (cp's own errorOnExist backstops races). */ +async function occupied(path) { + let present = true; + try { + await stat(path); + } catch { + present = false; + } + return present; +} +/** +* Re-tighten a copied tree to owner-only. A shipped preset is world-readable +* in its install and `cp` preserves that; the copy carries the same weight as +* the settings document beside it, so group/other access is stripped. A +* file's owner-execute bit survives — a preset may ship runnable helpers. +*/ +async function tightenModes(dir) { + await chmod(dir, 448); + for (const entry of await readdir(dir, { withFileTypes: true })) { + const target = join(dir, entry.name); + if (entry.isDirectory()) await tightenModes(target); + else + /* v8 ignore next -- Windows exposes no POSIX owner-execute bit; the POSIX lane covers both file modes. */ + await chmod(target, ((await stat(target)).mode & 64) === 0 ? 384 : 448); + } +} +/** +* Create a preset by copying an existing one's whole directory. +* +* The copy carries everything the source directory holds — composition, +* metadata, skill directories, assets — because a preset is its directory, +* not one file. Symlinks are dereferenced so the copy is self-contained +* rather than a set of links back into the install it was copied from. +* +* The copied metadata is then rewritten: the source's description is kept +* (the file is the author's to edit afterwards), but its name and roster +* `order` are not — a copy presenting itself identically to its source, or +* sorted into the shipped set's declared order, would make the roster stop +* distinguishing them. With no name given and no description to keep, the +* file is removed so the copy publishes nothing rather than a blank. +* @param roots - the configured roots; the first `user` one receives the copy. +* @param source - the resolved preset the copy starts from. +* @param id - the new preset's id, which becomes its directory name. +* @param name - display name for the copy; omitted falls back to the id. +* @returns the absolute path of the new preset directory. +* @throws when the id is unusable or already occupied on disk, or the +* deployment configures no writable root. +*/ +async function copyComposition(roots, source, id, name) { + if (!PRESET_ID.test(id)) throw new InvalidPresetIdError(id); + const dir = join(writableRoot(roots), id); + if (await occupied(dir)) throw new PresetExistsError(id); + try { + await cp(dirname(source.path), dir, { + recursive: true, + dereference: true, + force: false, + errorOnExist: true + }); + await tightenModes(dir); + const rendered = renderPresetMetadata({ + ...name === void 0 ? {} : { name }, + ...source.description === void 0 ? {} : { description: source.description } + }); + const metadataPath = join(dir, METADATA_FILE); + if (rendered === void 0) await rm(metadataPath, { force: true }); + else await writeFileAtomic(metadataPath, rendered, { + mode: 384, + dirMode: 448 + }); + } catch (error) { + await rm(dir, { + recursive: true, + force: true + }); + throw error; + } + return dir; +} +/** +* Delete a locally authored preset. +* +* A shipped preset is refused: it belongs to the deployment. A preset a live +* session mounted is NOT refused — the composition was read at creation and is +* never re-read, so that session keeps running exactly as it was. +* @param roots - the configured roots. +* @param preset - the resolved preset to remove. +* @throws when the preset ships with the deployment or lies outside the writable root. +*/ +async function deleteComposition(roots, preset) { + if (preset.trust !== "user") throw new PresetNotWritableError(preset.id, "it ships with the deployment"); + const dir = join(writableRoot(roots), preset.id); + if (!isAbsolute(preset.path) || !preset.path.startsWith(dir)) throw new PresetNotWritableError(preset.id, "it does not live under the writable preset root"); + await rm(dir, { + recursive: true, + force: true + }); +} +//#endregion +//#region src/mount.ts +/** +* Mount one preset composition under an agent's scope context, then prove the +* result is usable before the agent is published. +* +* The scope context is what makes the composition per-session: entry contexts +* chain to the context the subtree was plugged into, so every `ctx.tools` +* and `ctx.systemPrompt` registration inside the preset files into that +* agent's layer and unwinds with it. Two guards make that safe. A row that +* never reached a usable state is rejected, because a directly-plugged subtree +* is absent from `ctx.loader.entries()` and no boot audit covers it. A row that +* published a service into the ROOT realm is rejected, because such a service +* is process-global rather than per-session and the second session mounting the +* same preset collides with the first. +* @module @deepseek-ai/dsh-agent-presets/mount +*/ +/** +* Subtrees captured by config identity. A subtree plugged directly (rather than +* created as a loader entry) never links itself to an `Entry`, so this is the +* only handle to the rows it created; config objects are minted per mount, so +* concurrent mounts cannot collide. +*/ +const mounted = /* @__PURE__ */ new WeakMap(); +/** +* The base URL bare specifiers resolve against, per pending mount, keyed by the +* same config object. Recorded before the subtree is plugged, because `Include` +* rewrites its own context's `baseUrl` to the composition's directory and the +* pre-mount value is the only handle on where the harness itself lives. +*/ +const harnessBase = /* @__PURE__ */ new WeakMap(); +/** +* Include subclass that publishes its tree and fiber for the audit, and never +* writes to the file it read. +*/ +var PresetTree = class extends Include { + constructor(ctx, config) { + super(ctx, config); + mounted.set(config, { + tree: this, + fiber: ctx.fiber + }); + } + /** + * Resolve a bare specifier from the harness rather than from the preset. + * + * `EntryTree.import()` resolves against the tree's own `baseUrl`, which + * `Include` sets to the composition's directory. That is right for a + * relative specifier — a preset's own files travel with it — and wrong for + * a package name: a locally authored preset lives under the user's home, + * where Node's upward `node_modules` walk never reaches the harness's own + * dependencies, so every `@deepseek-ai/dsh-*` row would fail to import. The + * mount records the host composition's base instead, which is inside the + * installed harness, and bare names resolve from there. An absolute + * filesystem path names neither base and becomes a file URL before Node's + * ESM loader receives it, which is required for drive-letter paths on + * Windows. + * @param name - the module specifier from the row. + * @param getOuterStack - the loader's stack composer for import diagnostics. + * @returns the imported module, or the `cordis:` builtin. + */ + import(name, getOuterStack) { + const specifier = isAbsolute(name) ? pathToFileURL(name).href : name; + const base = harnessBase.get(this.config); + /* v8 ignore next -- every PresetTree is constructed by `mountPreset`, which records the base first */ + if (base === void 0) return super.import(specifier, getOuterStack); + if (name.startsWith(".") || name.startsWith("cordis:")) return super.import(name, getOuterStack); + const internal = this.ctx.loader.internal; + /* v8 ignore next -- Node always supplies the internal module loader; the branch keeps a + hypothetical embedder from losing the row's name in a resolution error. */ + if (internal === void 0) return super.import(specifier, getOuterStack); + return internal.import(specifier, base, {}); + } + /** + * A preset is an input, never a persistence target. + * + * The Loader writes a tree back through this method whenever it decides the + * config changed — a plugin self-disposing is enough, and tearing an agent + * down disposes its whole subtree. Inherited, that rewrites the preset file + * with whatever the dying tree held, which in practice means truncating a + * shipped composition to `[]` the first time a session ends. Persisting a + * preset is also meaningless: nothing here is user state, and the same file + * backs every session that names it. + * + * Dropping the write drops the `loader/config-update` the inherited method + * emits with it. Nothing observes one for a preset subtree today, and a + * future "edit your preset while it runs" flow needs a deliberate + * persistence path rather than this method's return. + */ + write() {} +}; +const mounts = /* @__PURE__ */ new Set(); +/** +* Drop every record whose subtree is gone. +* +* Records are pruned by observation rather than through a disposal hook +* because a subtree can be torn down by its owning agent, by a failed mount, or +* by the whole tree unloading, and a cleared `uid` is what all three share. +* +* Pruning therefore has to happen on a path this module owns. Reading is one +* such path, but not a reliable one: the only production reader is the +* invariant companion's service listener, and `dsh-invariants` is a +* development composition — a shipped host never loads it. Mounting is the +* other, and it is the one every session takes, which bounds the set at one +* generation of dead records rather than one per session ever composed. Each +* record would otherwise retain its whole disposed subtree: the fiber holds +* its config, and that config is the key its `EntryTree` is stored under. +*/ +function pruneDisposedMounts() { + for (const mount of mounts) if (mount.fiber.uid === null) mounts.delete(mount); +} +/** +* Every preset composition still installed, pruning fibers disposed since the +* last read. +* @returns the live mounts. +*/ +function livePresetMounts() { + pruneDisposedMounts(); + return [...mounts]; +} +/** +* Whether `fiber` is `root` itself or is mounted anywhere inside its subtree. +* +* Membership is object identity. `uid` looks like a cheaper key but is a +* per-registry counter, so fibers in two different roots collide on it and a +* subtree in one runtime would be blamed for a service published in another. +* @param fiber - the fiber to locate. +* @param root - the subtree root to test membership against. +* @returns true when `fiber` belongs to `root`'s subtree. +*/ +function withinFiber(fiber, root) { + let current = fiber; + while (true) { + if (current === root) return true; + const parent = current.parent.fiber; + if (parent === current) return false; + current = parent; + } +} +/** +* Service names the mounted subtree published into the root realm. +* +* A provider without an `isolate` realm stores its implementation under the +* root's symbol for that name, which is exactly the comparison below; a +* provider inside an `isolate` realm stores under a realm-private symbol and +* is correctly absent here. +* @param ctx - any context of the runtime whose service store is inspected. +* @param mount - the mounted subtree's fiber. +* @returns the leaked service names in lexical order. +*/ +function leakedServices(ctx, mount) { + const store = ctx.reflect.store; + const rootIsolate = ctx.root[Context.isolate]; + const leaked = []; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than + clearing it, so an own symbol always resolves; the guard exists only + because the store's index signature is optional. */ + if (impl === void 0) continue; + if (!withinFiber(impl.fiber, mount)) continue; + if (rootIsolate[impl.name] === key) leaked.push(impl.name); + } + return leaked.sort((left, right) => left.localeCompare(right)); +} +/** +* The standing composition one agent is joined to. +* +* The agent's own key is parented to its preset's standing key, so the mount +* is found by matching that parent rather than by walking up from the agent — +* the mount is not under the agent's fiber. An agent that joined no preset — +* a deployment composing no roster, or a child agent before its join — has no +* parent link and resolves to undefined. +* @param agentCtx - the agent's scope context. +* @returns the mount the agent joined, or undefined when it joined none. +*/ +function standingMountFor(agentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) return void 0; + const standingKey = scopeParentOf(agentKey); + if (standingKey === void 0) return void 0; + return livePresetMounts().find((candidate) => candidate.key === standingKey); +} +/** +* One agent's instance of a service its preset mounted. +* +* A preset publishes a service behind an `isolate` realm so two sessions +* cannot collide, and an entry-local realm is invisible to everything outside +* the group — including the agent's own scope context and the host. That is +* right for the rows inside the group and wrong for one caller: a request that +* is ABOUT a session but arrives from outside it, which is every browser RPC +* the api-proxy serves. +* +* Ownership is the same relation {@link leakedServices} reads, inverted: there +* it names implementations a subtree published into the ROOT realm, here it +* names the one this subtree published anywhere. Fiber membership is object +* identity for the reason stated on {@link withinFiber}. +* +* This is READ addressing for a caller that already holds the agent. It is not +* a general host handle on a session's internals: a host row that `inject`s a +* service cannot use it, because injection resolves before any session exists +* and has no agent to key by — such a service belongs on the host plane. +* @param ctx - any context of the runtime whose service store is inspected. +* @param agent - the agent whose mounted composition to look inside. +* @param name - the service name as the preset's rows resolve it. +* @returns the agent's instance, or undefined when its preset mounts none. +*/ +function serviceForAgent(ctx, agent, name) { + const mount = standingMountFor(agent.ctx); + if (mount === void 0) return void 0; + const store = ctx.reflect.store; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than clearing it */ + if (impl === void 0) continue; + if (impl.name !== name) continue; + if (withinFiber(impl.fiber, mount.fiber)) return impl.value; + } +} +/** +* Rows that did not reach a usable state, each rendered as one diagnostic line. +* +* A row whose module failed to import or whose plugin threw already rejects the +* mount through the loader; what remains observable here is a row still waiting +* for a service the composition never supplies. +* @param tree - the mounted subtree. +* @returns one line per unusable row, empty when every enabled row is usable. +*/ +function inactiveRows(tree) { + const lines = []; + for (const entry of tree.entries()) { + if (entry.disabled) continue; + const fiber = entry.fiber; + /* v8 ignore next 4 -- the loader rejects an entry whose module or plugin failed, + so a settled tree never holds an enabled fiber-less entry; the branch exists + only because `Entry.fiber` is declared optional. */ + if (fiber === void 0) { + lines.push(`${entry.options.id} (${entry.options.name}): never started`); + continue; + } + const missing = Object.keys(fiber.inject).filter((name) => fiber.ctx.get(name) === void 0); + if (missing.length > 0) lines.push(`${entry.options.id} (${entry.options.name}): waiting for ${missing.join(", ")}`); + } + return lines; +} +/** +* The reportable text of a mount failure. +* +* The loader reports several failed rows as one `AggregateError`, whose own +* message names none of them; without flattening, a composition that fails on +* two rows says only "loader entries failed to apply" and the operator has +* nothing to act on. +* @param error - the value the mount rejected with. +* @returns a single-line-per-cause description. +*/ +function mountDetail(error) { + /* v8 ignore next -- every path into the mount's catch throws an Error: the loader + wraps a row's thrown value before it propagates, and this module's own + rejections are Errors. The fallback keeps a hostile value readable. */ + if (!(error instanceof Error)) return String(error); + if (!(error instanceof AggregateError)) return error.message; + return [error.message, ...error.errors.map((cause) => `- ${mountDetail(cause)}`)].join("\n"); +} +/** +* Mount `preset` under `agentCtx` and return only once every row is usable. +* +* The subtree is owned by `agentCtx`'s fiber, so it unwinds with the agent and +* the caller receives no disposer. A rejection leaves nothing mounted. +* @param agentCtx - the agent's scope context, from the agent factory's `setup`. +* @param preset - the resolved preset to compose the agent from. +* @throws when `agentCtx` carries no scope, a row is unusable, or a row +* published a service into the root realm. +*/ +async function mountPreset(agentCtx, preset) { + if (scopeOf(agentCtx) === void 0) throw new Error(`agent-presets: refusing to mount preset "${preset.id}" into an unscoped context; its registrations would apply to every agent in the process`); + const config = { path: pathToFileURL(preset.path).href }; + /* v8 ignore next -- the Loader sets `baseUrl` on the root before any scoped context derives from it */ + if (agentCtx.baseUrl !== void 0) harnessBase.set(config, agentCtx.baseUrl); + pruneDisposedMounts(); + const handle = agentCtx.plugin(PresetTree, config); + try { + await handle.await(); + const subtree = mounted.get(config); + /* v8 ignore next -- the subclass constructor runs before `await()` settles for every mounted tree */ + if (subtree === void 0) throw new Error("mounted subtree did not publish its entry tree"); + const { tree, fiber } = subtree; + const unusable = inactiveRows(tree); + if (unusable.length > 0) throw new Error(`${String(unusable.length)} row(s) did not activate:\n${unusable.join("\n")}`); + const leaked = leakedServices(agentCtx, fiber); + if (leaked.length > 0) throw new Error(`row(s) published process-global service(s) [${leaked.join(", ")}]; a preset service must sit behind an \`isolate\` realm or move to the host composition`); + mounts.add({ + presetId: preset.id, + fiber, + key: scopeOf(agentCtx) + }); + } catch (error) { + try { + await handle.dispose(); + } catch {} + throw new PresetMountError(preset.id, `${mountDetail(error)} (${preset.path})`, { cause: error }); + } +} +//#endregion +//#region src/index.ts +/** +* Agent presets: each session composes its model-facing plugin set from one +* preset `cordis.yml`, mounted ONCE per preset under a standing scope and +* joined by every agent that names it. +* +* The standing mount is what makes a preset one composition rather than one +* per session: its plugin instances, tool registrations, prompt sections, and +* projection units exist exactly once, keyed per session inside the plugins +* themselves (they predate presets and were written for a shared world). An +* agent joins by having its scope key parented to the mount's +* ({@link bindScopeParent}), which makes the mount's registrations visible to +* that agent's views and the mount's listeners receive that agent's events — +* and a host reader with no agent at all (a cold transcript read) resolves +* the same standing registrations by preset id. +* +* This package owns the preset vocabulary, filesystem discovery, and the +* guarded standing mount. It does not decide when an agent is created — the +* agent factory's `setup(agentCtx)` hook is the one supported call site, +* because only there is the join installed while the agent is still +* unpublished, so a rejected composition rolls the whole creation back. +* @module @deepseek-ai/dsh-agent-presets +*/ +/** Settings namespace carrying the user's chosen default preset. */ +const SETTINGS_NAMESPACE = "agent-presets"; +/** Runtime schema for the user-writable slice. */ +const AgentPresetSettingsSchema = z.object({ default: z.string() }); +(class extends Service { + config; + static inject = ["loader"]; + /** Runtime schema for the preset roster. */ + static Config = z.object({ + default: z.string().required(), + roots: z.array(z.object({ + path: z.string().required(), + trust: z.union(["system", "user"]).default("user") + })).default([]), + includeUserRoot: z.boolean().default(true) + }); + /** + * The roots discovery and authoring actually scan: every configured root in + * order, then the harness-home user root unless `includeUserRoot` is false. + * + * Derived once, because a root set that changed between `list()` and the + * `copy()` acting on its answer would author into a directory the caller + * never saw. Appending rather than prepending keeps an earlier configured + * root winning a duplicate id, so a shipped preset still shadows a + * locally authored directory that claimed its name. + */ + resolvedRoots; + /** + * The user layer over `config.default`, present only while a settings + * provider is composed. Held rather than snapshotted so a hot-reloaded + * document takes effect without a restart. + */ + settings; + /** + * The settings service behind {@link settings}, held for the one write this + * service makes: clearing a user default it has just deleted. + */ + settingsService; + /** + * The service's own untraced context. Methods invoked through the traceable + * proxy see `this.ctx` rebound to the CALLER's context, which carries a + * shadow; a subtree minted from it resolves every service through that + * shadow's fiber instead of each entry's own inject store, so preset rows + * would fail on the very services they declare. Standing mounts must hang + * off the untraced original (the `jobs-local` selfCtx precedent). + */ + selfCtx; + constructor(ctx, config) { + super(ctx, "agentPresets"); + this.config = config; + this.selfCtx = ctx; + this.resolvedRoots = config.includeUserRoot ? [...config.roots, { + path: dshHomePath(USER_PRESET_DIR), + trust: "user" + }] : [...config.roots]; + ctx.inject(["settings"], (settingsCtx) => { + this.settings = settingsCtx.settings.register(settingsNamespace(SETTINGS_NAMESPACE), AgentPresetSettingsSchema, { base: { default: config.default } }); + this.settingsService = settingsCtx.settings; + settingsCtx.effect(() => () => { + this.settings = void 0; + this.settingsService = void 0; + }, "agentPresets.settings()"); + }); + ctx.on("agent/created", ({ agent }) => { + if (this.resolvedRoots.length === 0) return; + if (this.composedPreset(agent.ctx) !== void 0) return; + ctx.logger.warn(`agent "${agent.id}" was published without joining an agent preset; its tools, prompt sections, and skill catalog resolve against the empty global layer (join through AgentPresets.mount() or composeFrom() in the agent factory setup)`); + }); + ctx.on("session/event", (session, event) => { + if (event.type !== "agent-preset/selected") return; + ctx.emit("agent-preset/selected", session.id, event.data.agentPreset); + }); + } + /** + * The preset id mounted when a caller names none. + * + * Read per call rather than cached: the settings document is hot-reloaded, so + * changing the default takes effect on the next session created and leaves + * every running session on the preset it was composed from. + */ + get defaultId() { + return this.settings?.get().default ?? this.config.default; + } + /** + * Every preset the configured roots currently supply. + * @returns the presets, first-root-wins per id. + */ + async list() { + return await discoverPresets(this.resolvedRoots); + } + /** + * Resolve one preset by id. + * + * A broken preset resolves — deleting one, reading one, and reporting one + * all need the row — and the mounting paths refuse it AFTER resolution + * through {@link resolveMountable}. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved preset. + * @throws when no configured root supplies that id. + */ + async resolve(id) { + const wanted = id ?? this.defaultId; + const presets = await this.list(); + const found = presets.find((preset) => preset.id === wanted); + if (found === void 0) throw new UnknownPresetError(wanted, presets.map((preset) => preset.id)); + return found; + } + /** + * Resolve one preset that is about to compose an agent, refusing a broken + * one with its discovery-reported reason. Failing here rather than inside + * the loader keeps the answer the same for every unloadable shape — ghost + * directory, unparsable YAML, rowless list — and spends no mount attempt + * on a composition discovery already read as unusable. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved, mountable preset. + * @throws when the preset is unknown or discovery reports it broken. + */ + async resolveMountable(id) { + const preset = await this.resolve(id); + if (preset.broken !== void 0) throw new PresetMountError(preset.id, preset.broken); + return preset; + } + /** + * Standing mounts by preset id, single-flight so two agents racing the + * first use of one preset share one composition. A settled failure is + * removed so a later session retries a preset whose file has been fixed; a + * settled success serves until the composition FILE visibly changes — each + * generation records its file stamp, and a stale stamp starts the next + * generation for sessions created afterwards. Sessions already joined keep + * the generation they run on; a superseded one is never disposed while the + * process lives (reclaimed only by whole-tree teardown), so editing files + * is bounded by how often compositions change, not by session count. + */ + standing = /* @__PURE__ */ new Map(); + /** + * Parent bindings of the agents this roster composed, keyed by the agent's + * scope key. The binding is dsh-scope's only re-link capability; holding it + * here makes this service the sole authority that can move an agent between + * standing compositions. WeakMap: entries die with their agents. + */ + bindings = /* @__PURE__ */ new WeakMap(); + /** + * Compose one agent from a preset: ensure the preset's standing mount, then + * parent the agent's scope key to it so the mount's registrations and + * listeners cover this agent. + * + * Call from the agent factory's `setup(agentCtx)`; a rejection there rolls + * the agent creation back, so a broken preset never yields a half-composed + * session. + * @param agentCtx - the agent's scope context. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the preset that was composed, for the caller to record. + * @throws when the preset is unknown or its composition is unusable. + */ + async mount(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset"); + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return preset; + } + /** + * Join one agent to the SAME standing composition another already runs on. + * + * This is how a child agent inherits its parent's capabilities. It is a bind, + * not a mount: the parent's generation is already composed, so the child gets + * that exact instance — the same plugin objects, the same tool registrations, + * the same prompt sections. Re-resolving the parent's preset by id instead + * would re-read the roster, and a composition file edited since the parent + * started would hand the child a DIFFERENT generation than the one its + * parent's history was produced under (and a preset deleted since would fail + * the child outright while its parent keeps running). + * + * Synchronous, and with no composition failure mode of its own — it reads no + * roster, mounts nothing, and touches no file — which is what lets a child + * creation window use it: the two in-process subagent drivers compose their + * children inside a synchronous `setup`. It still rejects a caller error, as + * the `@throws` below record. + * + * A parent that joined no preset — a rosterless deployment — yields no join + * and no error: there, the model-facing rows sit in the host composition and + * the child already sees them through the global layer. + * @param agentCtx - the joining agent's scope context. + * @param parentCtx - the scope context of the agent whose composition to join. + * @returns the preset id joined, or undefined when the parent joined none. + * @throws when `agentCtx` carries no scope, or has already joined a preset. + */ + composeFrom(agentCtx, parentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset"); + const standing = standingMountFor(parentCtx); + if (standing === void 0) return void 0; + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return standing.presetId; + } + /** + * The preset one live agent runs on. + * + * Read from the live scope chain rather than from the session, so it answers + * for an agent whose session has not recorded a preset yet — a child agent + * whose durable header is being built from its parent's composition. + * @param agentCtx - the agent's scope context. + * @returns the preset id, or undefined when the agent joined none. + */ + composedPreset(agentCtx) { + return standingMountFor(agentCtx)?.presetId; + } + /** + * The roots this roster scans, which is not `config.roots`: it is every + * configured root in order, then the harness-home user root unless + * `includeUserRoot` is false. Read this — not the config field — to answer + * whether a roster is composed at all, so one derivation decides it. + */ + get roots() { + return this.resolvedRoots; + } + /** Whether this deployment has a root locally authored presets go to. */ + get authorable() { + return this.resolvedRoots.some((root) => root.trust === "user"); + } + /** + * Read one preset's composition text. + * @param id - the preset id. + * @returns the composition exactly as stored. + * @throws when no configured root supplies that id. + */ + async read(id) { + return await readComposition(await this.resolve(id)); + } + /** + * Create a locally authored preset by copying an existing one whole. + * + * Copy is the only authoring write. Composition text never crosses this + * seam: the source is named by id and its directory is copied as it stands, + * so the copy is exactly as loadable as its source and authoring grants no + * capability the roster did not already carry. The copy is NOT mounted to + * validate — a source that mounts today yields a copy that mounts today. + * @param from - the preset the copy starts from; shipped presets are the + * primary source, so any trust is accepted. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; absent falls back to the id. + * @throws when the source is unknown, the id is unusable or already taken, + * or the deployment configures no writable root. + */ + async copy(from, id, name) { + const source = await this.resolve(from); + if ((await this.list()).some((preset) => preset.id === id)) throw new PresetExistsError(id); + await copyComposition(this.resolvedRoots, source, id, name); + this.standing.delete(id); + } + /** + * Delete a locally authored preset. + * @param id - the preset id. + * @throws when the preset is unknown or ships with the deployment. + */ + async remove(id) { + await deleteComposition(this.resolvedRoots, await this.resolve(id)); + this.standing.delete(id); + if (this.settings?.get().default !== id) return; + await this.settingsService?.mutate(settingsNamespace(SETTINGS_NAMESPACE), [{ + op: "unset", + path: ["default"] + }]); + } + /** + * One agent's instance of a service its preset mounted. + * + * A preset publishes services behind `isolate` realms, which are invisible + * outside the group that declares them — including to the host. This is how a + * caller holding the agent reads one anyway: a request that is ABOUT a + * session but arrives from outside it, which is every browser RPC. + * + * Read addressing only. A host row that `inject`s a service cannot use this, + * because injection resolves before any session exists and has no agent to + * key by; such a service belongs on the host plane instead. + * @param agent - the agent whose composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ + serviceFor(agent, name) { + return serviceForAgent(this.ctx, agent, name); + } + /** + * Re-link one agent to a different preset's standing composition. + * + * Only valid while the agent has produced nothing: swapping tools mid + * conversation would leave logged tool calls the new composition cannot + * make. The CALLER owns that check — this method does not read session + * history. + * + * The swap is a parent re-link, not an unmount: standing mounts are shared + * and permanent, so the old composition stays for its other agents and the + * new one is ensured BEFORE the link moves. An unknown or unusable preset + * therefore throws with the agent exactly as it was — there is no torn-down + * state to restore. The re-link runs through the binding this roster kept + * from the agent's mount — dsh-scope's only re-link authority. An agent + * that never composed one has nothing to re-link: the switch is then the + * agent's first bind, exactly a mount. + * @param agentCtx - the agent's scope context. + * @param id - the preset to compose the agent from instead. + * @returns the preset now installed. + * @throws when the preset is unknown or its composition is unusable. + */ + async recompose(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to recompose an unscoped context"); + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + const binding = this.bindings.get(agentKey); + if (binding === void 0) this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + else binding.rebind(standing.key); + return preset; + } + /** + * The standing scope key of one preset, for a host reader with no agent. + * + * A cold transcript read resolves tool presenters against the composition + * the session recorded, and the standing mount makes that possible without + * resuming anything: ensuring the mount composes plugins but starts no + * agent, no session, and no turn. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the standing scope key readers pass as a registry view scope. + * @throws when the preset is unknown or its composition is unusable. + */ + async standingKeyFor(id) { + const preset = await this.resolveMountable(id); + return (await this.ensureStanding(preset)).key; + } + /** Resolve (or create, single-flight) the standing mount of one preset. */ + async ensureStanding(preset) { + const pending = this.standing.get(preset.id); + if (pending !== void 0) { + const mounted = await pending; + const current = await compositionStamp(preset.path); + if (current === void 0 || sameStamp(mounted.stamp, current)) return mounted; + if (this.standing.get(preset.id) === pending) this.standing.delete(preset.id); + return this.ensureStanding(preset); + } + const created = (async () => { + const key = { agentPreset: preset.id }; + const scope = createScope(this.selfCtx, key); + try { + const stamp = await compositionStamp(preset.path); + if (stamp === void 0) throw new PresetMountError(preset.id, `composition file is unreadable: ${preset.path}`); + await mountPreset(scope.ctx, preset); + return { + key, + scope, + stamp + }; + } catch (error) { + this.standing.delete(preset.id); + await scope.dispose(); + throw error; + } + })(); + this.standing.set(preset.id, created); + return created; + } +}); +/** Read one composition file's stamp, or undefined when it cannot be statted. */ +async function compositionStamp(path) { + try { + const { mtimeMs, size } = await stat(path); + return { + mtimeMs, + size + }; + } catch { + return; + } +} +/** Whether two stamps name the same file state. */ +function sameStamp(a, b) { + return a.mtimeMs === b.mtimeMs && a.size === b.size; +} +//#endregion +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-agent-presets`. +* @module @deepseek-ai/dsh-agent-presets/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-agent-presets"; +/** Cordis companion plugin name. */ +const name = "agent-presets-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* Assert that no installed preset composition reaches the root service realm, +* and that a deployment configuring a roster composes every agent from it. +* +* `mountPreset` proves the first once, when the subtree settles. A row that +* publishes later — from a timer, or an asynchronous continuation after its +* plugin returned — would escape that one-shot audit, so re-check every live +* mount whenever a service registration changes. +*/ +const install = (ctx, fail) => { + ctx.on("internal/service", function(name) { + for (const mount of livePresetMounts()) { + const leaked = leakedServices(ctx, mount.fiber); + if (leaked.length === 0) continue; + fail(`preset "${mount.presetId}" published process-global service(s) [${leaked.join(", ")}] after its mount was audited (observed while notifying "${name}") — a preset service must sit behind an \`isolate\` realm or move to the host composition`); + } + }, { global: true }); + ctx.on("system-prompt/assemble", (_assembly, context, next) => { + const presets = ctx.get("agentPresets"); + const agent = context.agent; + if (presets !== void 0 && presets.roots.length > 0 && agent !== void 0 && presets.composedPreset(agent.ctx) === void 0) fail(`agent "${agent.id}" addressed a model without joining any agent preset while a roster is composed; its tools, prompt sections, and skill catalog resolve against the empty global layer`); + return next(); + }); +}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.d.ts new file mode 100644 index 0000000..7d8fe21 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.d.ts @@ -0,0 +1,86 @@ +/** + * Copying, reading, and deleting locally authored presets. + * + * Authoring is confined to a `user` root: the shipped `.system` set is part of + * the deployment, and letting a browser rewrite it would turn "reset to a known + * preset" into something the same caller could have broken first. + * + * The only authoring write is a whole-directory copy of an existing preset. + * No caller supplies composition text: the inputs are ids the host resolves + * against its own roots plus an optional display name, so authoring grants no + * capability the copied preset did not already carry. + * @module @deepseek-ai/dsh-agent-presets/authoring + */ +import { type AgentPreset, type PresetRoot } from './preset.ts'; +/** A preset id that cannot be used as a directory name under a root. */ +export declare class InvalidPresetIdError extends Error { + /** The rejected id. */ + readonly presetId: string; + constructor( + /** The rejected id. */ + presetId: string); +} +/** A copy target that is already occupied — a copy never overwrites. */ +export declare class PresetExistsError extends Error { + /** The id that is already taken. */ + readonly presetId: string; + constructor( + /** The id that is already taken. */ + presetId: string); +} +/** Authoring was attempted where the deployment allows none. */ +export declare class PresetNotWritableError extends Error { + /** What the caller tried to change, for the diagnostic. */ + readonly presetId: string; + constructor( + /** What the caller tried to change, for the diagnostic. */ + presetId: string, reason: string); +} +/** + * The root locally authored presets are written to. + * @param roots - the configured roots in precedence order. + * @returns the absolute path of the first `user` root. + * @throws when the deployment configured no writable root. + */ +export declare function writableRoot(roots: readonly PresetRoot[]): string; +/** + * Read one preset's composition text. + * @param preset - the resolved preset. + * @returns the file's contents. + */ +export declare function readComposition(preset: AgentPreset): Promise; +/** + * Create a preset by copying an existing one's whole directory. + * + * The copy carries everything the source directory holds — composition, + * metadata, skill directories, assets — because a preset is its directory, + * not one file. Symlinks are dereferenced so the copy is self-contained + * rather than a set of links back into the install it was copied from. + * + * The copied metadata is then rewritten: the source's description is kept + * (the file is the author's to edit afterwards), but its name and roster + * `order` are not — a copy presenting itself identically to its source, or + * sorted into the shipped set's declared order, would make the roster stop + * distinguishing them. With no name given and no description to keep, the + * file is removed so the copy publishes nothing rather than a blank. + * @param roots - the configured roots; the first `user` one receives the copy. + * @param source - the resolved preset the copy starts from. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; omitted falls back to the id. + * @returns the absolute path of the new preset directory. + * @throws when the id is unusable or already occupied on disk, or the + * deployment configures no writable root. + */ +export declare function copyComposition(roots: readonly PresetRoot[], source: AgentPreset, id: string, name?: string): Promise; +/** + * Delete a locally authored preset. + * + * A shipped preset is refused: it belongs to the deployment. A preset a live + * session mounted is NOT refused — the composition was read at creation and is + * never re-read, so that session keeps running exactly as it was. + * @param roots - the configured roots. + * @param preset - the resolved preset to remove. + * @throws when the preset ships with the deployment or lies outside the writable root. + */ +export declare function deleteComposition(roots: readonly PresetRoot[], preset: AgentPreset): Promise; +//# sourceMappingURL=authoring.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.js new file mode 100644 index 0000000..bf1de13 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.js @@ -0,0 +1,183 @@ +/** + * Copying, reading, and deleting locally authored presets. + * + * Authoring is confined to a `user` root: the shipped `.system` set is part of + * the deployment, and letting a browser rewrite it would turn "reset to a known + * preset" into something the same caller could have broken first. + * + * The only authoring write is a whole-directory copy of an existing preset. + * No caller supplies composition text: the inputs are ids the host resolves + * against its own roots plus an optional display name, so authoring grants no + * capability the copied preset did not already carry. + * @module @deepseek-ai/dsh-agent-presets/authoring + */ +import { chmod, cp, readdir, readFile, rm, stat } from 'node:fs/promises'; +import { dirname, isAbsolute, join, resolve } from 'node:path'; +import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write'; +import { expandHomePath } from '@deepseek-ai/dsh-home-paths'; +import { METADATA_FILE, renderPresetMetadata } from "./metadata.js"; +import { PRESET_ID } from "./preset.js"; +/** A preset id that cannot be used as a directory name under a root. */ +export class InvalidPresetIdError extends Error { + presetId; + constructor( + /** The rejected id. */ + presetId) { + super(`agent-presets: preset id ${JSON.stringify(presetId)} must match ${String(PRESET_ID)} — ` + + 'the id is a directory name, so anything else could escape the preset root'); + this.presetId = presetId; + } +} +/** A copy target that is already occupied — a copy never overwrites. */ +export class PresetExistsError extends Error { + presetId; + constructor( + /** The id that is already taken. */ + presetId) { + super(`agent-presets: preset "${presetId}" already exists — ` + + 'a copy never overwrites; delete the existing preset first or choose another id'); + this.presetId = presetId; + } +} +/** Authoring was attempted where the deployment allows none. */ +export class PresetNotWritableError extends Error { + presetId; + constructor( + /** What the caller tried to change, for the diagnostic. */ + presetId, reason) { + super(`agent-presets: preset "${presetId}" cannot be written: ${reason}`); + this.presetId = presetId; + } +} +/** + * The root locally authored presets are written to. + * @param roots - the configured roots in precedence order. + * @returns the absolute path of the first `user` root. + * @throws when the deployment configured no writable root. + */ +export function writableRoot(roots) { + const root = roots.find(candidate => candidate.trust === 'user'); + if (root === undefined) { + throw new PresetNotWritableError('', 'this deployment configures no user-writable preset root'); + } + return resolve(expandHomePath(root.path)); +} +/** + * Read one preset's composition text. + * @param preset - the resolved preset. + * @returns the file's contents. + */ +export async function readComposition(preset) { + return await readFile(preset.path, 'utf8'); +} +/** Whether anything occupies the path (cp's own errorOnExist backstops races). */ +async function occupied(path) { + let present = true; + try { + await stat(path); + } + catch { + // Every stat failure means the same thing here: nothing usable occupies + // the path, so the copy may claim it. + present = false; + } + return present; +} +/** + * Re-tighten a copied tree to owner-only. A shipped preset is world-readable + * in its install and `cp` preserves that; the copy carries the same weight as + * the settings document beside it, so group/other access is stripped. A + * file's owner-execute bit survives — a preset may ship runnable helpers. + */ +async function tightenModes(dir) { + await chmod(dir, 0o700); + for (const entry of await readdir(dir, { withFileTypes: true })) { + const target = join(dir, entry.name); + if (entry.isDirectory()) { + await tightenModes(target); + } + else { + /* v8 ignore next -- Windows exposes no POSIX owner-execute bit; the POSIX lane covers both file modes. */ + await chmod(target, ((await stat(target)).mode & 0o100) === 0 ? 0o600 : 0o700); + } + } +} +/** + * Create a preset by copying an existing one's whole directory. + * + * The copy carries everything the source directory holds — composition, + * metadata, skill directories, assets — because a preset is its directory, + * not one file. Symlinks are dereferenced so the copy is self-contained + * rather than a set of links back into the install it was copied from. + * + * The copied metadata is then rewritten: the source's description is kept + * (the file is the author's to edit afterwards), but its name and roster + * `order` are not — a copy presenting itself identically to its source, or + * sorted into the shipped set's declared order, would make the roster stop + * distinguishing them. With no name given and no description to keep, the + * file is removed so the copy publishes nothing rather than a blank. + * @param roots - the configured roots; the first `user` one receives the copy. + * @param source - the resolved preset the copy starts from. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; omitted falls back to the id. + * @returns the absolute path of the new preset directory. + * @throws when the id is unusable or already occupied on disk, or the + * deployment configures no writable root. + */ +export async function copyComposition(roots, source, id, name) { + if (!PRESET_ID.test(id)) + throw new InvalidPresetIdError(id); + const dir = join(writableRoot(roots), id); + // The roster check upstream only sees discovered presets; a directory with + // no composition file still occupies the name and deserves a readable + // refusal rather than a filesystem error code. + if (await occupied(dir)) + throw new PresetExistsError(id); + try { + await cp(dirname(source.path), dir, { + recursive: true, dereference: true, force: false, errorOnExist: true, + }); + await tightenModes(dir); + const rendered = renderPresetMetadata({ + ...name === undefined ? {} : { name }, + ...source.description === undefined ? {} : { description: source.description }, + }); + const metadataPath = join(dir, METADATA_FILE); + if (rendered === undefined) { + await rm(metadataPath, { force: true }); + } + else { + await writeFileAtomic(metadataPath, rendered, { mode: 0o600, dirMode: 0o700 }); + } + } + catch (error) { + // A half-copied directory would be invisible to discovery at best and a + // mountable-but-incomplete preset at worst; a failed copy leaves nothing. + await rm(dir, { recursive: true, force: true }); + throw error; + } + return dir; +} +/** + * Delete a locally authored preset. + * + * A shipped preset is refused: it belongs to the deployment. A preset a live + * session mounted is NOT refused — the composition was read at creation and is + * never re-read, so that session keeps running exactly as it was. + * @param roots - the configured roots. + * @param preset - the resolved preset to remove. + * @throws when the preset ships with the deployment or lies outside the writable root. + */ +export async function deleteComposition(roots, preset) { + if (preset.trust !== 'user') { + throw new PresetNotWritableError(preset.id, 'it ships with the deployment'); + } + const dir = join(writableRoot(roots), preset.id); + // Belt and braces over the id pattern: the resolved directory must still be + // the one the writable root owns, whatever discovery reported. + if (!isAbsolute(preset.path) || !preset.path.startsWith(dir)) { + throw new PresetNotWritableError(preset.id, 'it does not live under the writable preset root'); + } + await rm(dir, { recursive: true, force: true }); +} +//# sourceMappingURL=authoring.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.d.ts new file mode 100644 index 0000000..0f65584 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.d.ts @@ -0,0 +1,55 @@ +/** + * Filesystem discovery of agent presets. A preset is a directory holding + * {@link COMPOSITION_FILE}, optionally beside a {@link METADATA_FILE} carrying + * its display text; the directory name is the preset id. Discovery + * re-reads the roots on every call so a preset authored while the process is + * running is visible without a restart. + * + * Discovery also owns preset HEALTH: a directory whose composition is + * missing or unloadable is reported as a broken roster row rather than + * skipped. A skipped directory would still occupy its id on disk — the copy + * path refuses the name while no surface shows anything to delete — and a + * malformed composition would otherwise read as an ordinary preset until the + * first session fails to mount it. + * @module @deepseek-ai/dsh-agent-presets/discovery + */ +import { type AgentPreset, type PresetRoot } from './preset.ts'; +/** The composition file that makes a directory a preset. */ +export declare const COMPOSITION_FILE = "agent.cordis.yml"; +/** + * Harness-home directory holding locally authored presets. + * + * This package owns the writable root the way `dsh-skill-filesystem` owns + * `/skills`. An app must assemble the SHIPPED root, whose path only + * the installed app can resolve; where a person's own presets go is the same + * place in every deployment that does not say otherwise, so a launcher that + * forgets to configure one still finds them. + * + * Package-internal on purpose: no consumer outside this package addresses the + * directory by name, and a test that imported it could not catch this value + * being wrong — the expected segment is spelled out where it is asserted. + */ +export declare const USER_PRESET_DIR = ".agent-presets"; +/** + * Scan one root for preset directories. + * + * An absent root yields no presets rather than throwing: the user root does + * not exist until the first locally authored preset, and naming a default + * that no root supplies already fails loud at resolution. + * + * Every directory whose name is a usable preset id is a roster row — broken + * when its composition is missing or unloadable. A directory named outside + * {@link PRESET_ID} is skipped instead: no copy could ever claim that name, + * so it blocks nothing, and reporting `.DS_Store`-grade residue as broken + * presets would teach users to ignore the marker. + * @param root - the directory and the trust its presets inherit. + * @returns the root's presets ordered by id. + */ +export declare function scanRoot(root: PresetRoot): Promise; +/** + * Scan every root in precedence order. + * @param roots - roots in precedence order; an earlier root wins a duplicate id. + * @returns every discovered preset, first-root-wins per id. + */ +export declare function discoverPresets(roots: readonly PresetRoot[]): Promise; +//# sourceMappingURL=discovery.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.js new file mode 100644 index 0000000..63bb39e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.js @@ -0,0 +1,187 @@ +/** + * Filesystem discovery of agent presets. A preset is a directory holding + * {@link COMPOSITION_FILE}, optionally beside a {@link METADATA_FILE} carrying + * its display text; the directory name is the preset id. Discovery + * re-reads the roots on every call so a preset authored while the process is + * running is visible without a restart. + * + * Discovery also owns preset HEALTH: a directory whose composition is + * missing or unloadable is reported as a broken roster row rather than + * skipped. A skipped directory would still occupy its id on disk — the copy + * path refuses the name while no surface shows anything to delete — and a + * malformed composition would otherwise read as an ordinary preset until the + * first session fails to mount it. + * @module @deepseek-ai/dsh-agent-presets/discovery + */ +import { readdir, readFile, stat } from 'node:fs/promises'; +import { join, resolve } from 'node:path'; +import { load } from 'js-yaml'; +import { entryListSchema } from '@deepseek-ai/cordis-plugin-include'; +import { expandHomePath } from '@deepseek-ai/dsh-home-paths'; +import { readPresetMetadata } from "./metadata.js"; +import { PRESET_ID } from "./preset.js"; +/** The composition file that makes a directory a preset. */ +export const COMPOSITION_FILE = 'agent.cordis.yml'; +/** + * Harness-home directory holding locally authored presets. + * + * This package owns the writable root the way `dsh-skill-filesystem` owns + * `/skills`. An app must assemble the SHIPPED root, whose path only + * the installed app can resolve; where a person's own presets go is the same + * place in every deployment that does not say otherwise, so a launcher that + * forgets to configure one still finds them. + * + * Package-internal on purpose: no consumer outside this package addresses the + * directory by name, and a test that imported it could not catch this value + * being wrong — the expected segment is spelled out where it is asserted. + */ +export const USER_PRESET_DIR = '.agent-presets'; +/** + * Why `rows` cannot be an entry list, or undefined when it can. + * + * A shallow shape check, deliberately short of the loader's work: it does not + * resolve plugin names or apply configs. What it catches is the hand-edit + * that produces a file the loader cannot even begin with — and it must accept + * everything the loader accepts, which is why rows are only required to be + * maps carrying a plugin `name` (groups recurse into their own lists). + * @param rows - the parsed composition document. + * @param at - row-path prefix for nested diagnostics, empty at the top level. + * @returns one human-readable reason, or undefined when the shape holds. + */ +function entryListProblem(rows, at = '') { + if (!Array.isArray(rows)) { + return at === '' + ? 'the composition must be a top-level list of plugin rows' + : `group ${at} must hold a list of plugin rows`; + } + for (const [index, row] of rows.entries()) { + const label = at === '' ? `row ${String(index + 1)}` : `${at} row ${String(index + 1)}`; + if (typeof row !== 'object' || row === null || Array.isArray(row)) { + return `${label} is not a plugin row (expected a map with a "name")`; + } + const { name, group, config } = row; + if (typeof name !== 'string' || name === '') { + return `${label} names no plugin (a "name" string is required)`; + } + if (group === true) { + const nested = entryListProblem(config, label); + if (nested !== undefined) + return nested; + } + } + return undefined; +} +/** + * Why the composition at `path` cannot mount, or undefined when it looks + * loadable. Parsed with the loader's own YAML dialect ({@link entryListSchema}, + * the one carrying `!!js`), so health can never call a composition broken + * that the loader would accept. + * @param path - absolute path of the composition file. + * @returns one human-readable reason, or undefined when the file is loadable. + */ +async function compositionProblem(path) { + let content; + try { + content = await readFile(path, 'utf8'); + } + catch { + // The caller statted this file moments ago; any read failure now — + // deleted in between, permissions — is the same answer as unparsable. + return `the composition file ${COMPOSITION_FILE} cannot be read`; + } + let rows; + try { + rows = load(content, { schema: entryListSchema }); + } + catch (error) { + /* v8 ignore next -- js-yaml throws YAMLException (an Error) for every parse failure; the fallback keeps a hostile value readable */ + const full = error instanceof Error ? error.message : String(error); + // First line only: js-yaml appends a multi-line code-frame snippet, and + // the reason is displayed on a roster card, not in a terminal. + return `the composition is not valid YAML: ${full.replace(/\n[\s\S]*$/, '')}`; + } + return entryListProblem(rows); +} +/** + * Whether `path` names an existing regular file. + * @param path - absolute path to test. + * @returns true when the path resolves to a file. + */ +async function isFile(path) { + try { + return (await stat(path)).isFile(); + } + catch { + // Any stat failure — absent, unreadable, a dangling link — means this + // directory does not present a composition, which is not an error: the + // directory simply is not a preset. + return false; + } +} +/** + * Scan one root for preset directories. + * + * An absent root yields no presets rather than throwing: the user root does + * not exist until the first locally authored preset, and naming a default + * that no root supplies already fails loud at resolution. + * + * Every directory whose name is a usable preset id is a roster row — broken + * when its composition is missing or unloadable. A directory named outside + * {@link PRESET_ID} is skipped instead: no copy could ever claim that name, + * so it blocks nothing, and reporting `.DS_Store`-grade residue as broken + * presets would teach users to ignore the marker. + * @param root - the directory and the trust its presets inherit. + * @returns the root's presets ordered by id. + */ +export async function scanRoot(root) { + const dir = resolve(expandHomePath(root.path)); + let children; + try { + children = await readdir(dir, { withFileTypes: true }); + } + catch (error) { + if (error.code === 'ENOENT') + return []; + throw new Error(`agent-presets: cannot read preset root ${dir}: ${String(error)}`, { cause: error }); + } + const found = []; + for (const child of children) { + if (!child.isDirectory() || !PRESET_ID.test(child.name)) + continue; + const directory = join(dir, child.name); + const path = join(directory, COMPOSITION_FILE); + const broken = await isFile(path) + ? await compositionProblem(path) + : `the composition file ${COMPOSITION_FILE} is missing — the directory still occupies the id; delete it or restore the file`; + // Display text only, and never fatal: a preset with unreadable metadata + // still mounts, it just shows its id. + const metadata = await readPresetMetadata(directory); + found.push({ + id: child.name, trust: root.trust, path, ...metadata, + ...broken === undefined ? {} : { broken }, + }); + } + // Declared order first so the shipped set reads by capability; everything + // else falls back to the id, which keeps authored presets stable. + return found.sort((left, right) => { + const byOrder = (left.order ?? Number.POSITIVE_INFINITY) - (right.order ?? Number.POSITIVE_INFINITY); + return byOrder === 0 ? left.id.localeCompare(right.id) : byOrder; + }); +} +/** + * Scan every root in precedence order. + * @param roots - roots in precedence order; an earlier root wins a duplicate id. + * @returns every discovered preset, first-root-wins per id. + */ +export async function discoverPresets(roots) { + const byId = new Map(); + for (const root of roots) { + for (const preset of await scanRoot(root)) { + if (byId.has(preset.id)) + continue; + byId.set(preset.id, preset); + } + } + return [...byId.values()]; +} +//# sourceMappingURL=discovery.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.d.ts new file mode 100644 index 0000000..cce4c5b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.d.ts @@ -0,0 +1,291 @@ +/** + * Agent presets: each session composes its model-facing plugin set from one + * preset `cordis.yml`, mounted ONCE per preset under a standing scope and + * joined by every agent that names it. + * + * The standing mount is what makes a preset one composition rather than one + * per session: its plugin instances, tool registrations, prompt sections, and + * projection units exist exactly once, keyed per session inside the plugins + * themselves (they predate presets and were written for a shared world). An + * agent joins by having its scope key parented to the mount's + * ({@link bindScopeParent}), which makes the mount's registrations visible to + * that agent's views and the mount's listeners receive that agent's events — + * and a host reader with no agent at all (a cold transcript read) resolves + * the same standing registrations by preset id. + * + * This package owns the preset vocabulary, filesystem discovery, and the + * guarded standing mount. It does not decide when an agent is created — the + * agent factory's `setup(agentCtx)` hook is the one supported call site, + * because only there is the join installed while the agent is still + * unpublished, so a rejected composition rolls the whole creation back. + * @module @deepseek-ai/dsh-agent-presets + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { type ScopeKey } from '@deepseek-ai/dsh-scope'; +import { type AgentPreset, type Config, type PresetRoot } from './preset.ts'; +/** Settings namespace carrying the user's chosen default preset. */ +export declare const SETTINGS_NAMESPACE = "agent-presets"; +/** The user-writable slice of this plugin's config. */ +export interface AgentPresetSettings { + /** Preset mounted when a session names none. */ + default?: string; +} +/** Runtime schema for the user-writable slice. */ +export declare const AgentPresetSettingsSchema: z; +export { COMPOSITION_FILE, discoverPresets, scanRoot } from './discovery.ts'; +export { METADATA_FILE, readPresetMetadata, renderPresetMetadata, type PresetMetadata, } from './metadata.ts'; +export { inactiveRows, leakedServices, livePresetMounts, mountPreset, serviceForAgent, standingMountFor, type JoinedPresetMount, type PresetMount, } from './mount.ts'; +export { copyComposition, deleteComposition, InvalidPresetIdError, PresetExistsError, PresetNotWritableError, readComposition, writableRoot, } from './authoring.ts'; +export { resolveSessionPreset, type PresetBearingSession } from './session.ts'; +export { PresetMountError, UnknownPresetError } from './preset.ts'; +export type { AgentPreset, Config, PresetRoot, PresetTrust } from './preset.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + agentPresets: AgentPresets; + } +} +/** + * Registry over the deployment's agent presets. + * + * Discovery is unmemoized: `list()` and `resolve()` re-read the roots on every + * call so a preset authored while the process runs is visible immediately, + * and a preset deleted underneath a picker disappears from the next read. + */ +export declare class AgentPresets extends Service { + config: Config; + static inject: string[]; + /** Runtime schema for the preset roster. */ + static Config: z; + /** + * The roots discovery and authoring actually scan: every configured root in + * order, then the harness-home user root unless `includeUserRoot` is false. + * + * Derived once, because a root set that changed between `list()` and the + * `copy()` acting on its answer would author into a directory the caller + * never saw. Appending rather than prepending keeps an earlier configured + * root winning a duplicate id, so a shipped preset still shadows a + * locally authored directory that claimed its name. + */ + private readonly resolvedRoots; + /** + * The user layer over `config.default`, present only while a settings + * provider is composed. Held rather than snapshotted so a hot-reloaded + * document takes effect without a restart. + */ + private settings; + /** + * The settings service behind {@link settings}, held for the one write this + * service makes: clearing a user default it has just deleted. + */ + private settingsService; + /** + * The service's own untraced context. Methods invoked through the traceable + * proxy see `this.ctx` rebound to the CALLER's context, which carries a + * shadow; a subtree minted from it resolves every service through that + * shadow's fiber instead of each entry's own inject store, so preset rows + * would fail on the very services they declare. Standing mounts must hang + * off the untraced original (the `jobs-local` selfCtx precedent). + */ + private readonly selfCtx; + constructor(ctx: Context, config: Config); + /** + * The preset id mounted when a caller names none. + * + * Read per call rather than cached: the settings document is hot-reloaded, so + * changing the default takes effect on the next session created and leaves + * every running session on the preset it was composed from. + */ + get defaultId(): string; + /** + * Every preset the configured roots currently supply. + * @returns the presets, first-root-wins per id. + */ + list(): Promise; + /** + * Resolve one preset by id. + * + * A broken preset resolves — deleting one, reading one, and reporting one + * all need the row — and the mounting paths refuse it AFTER resolution + * through {@link resolveMountable}. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved preset. + * @throws when no configured root supplies that id. + */ + resolve(id?: string): Promise; + /** + * Resolve one preset that is about to compose an agent, refusing a broken + * one with its discovery-reported reason. Failing here rather than inside + * the loader keeps the answer the same for every unloadable shape — ghost + * directory, unparsable YAML, rowless list — and spends no mount attempt + * on a composition discovery already read as unusable. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved, mountable preset. + * @throws when the preset is unknown or discovery reports it broken. + */ + private resolveMountable; + /** + * Standing mounts by preset id, single-flight so two agents racing the + * first use of one preset share one composition. A settled failure is + * removed so a later session retries a preset whose file has been fixed; a + * settled success serves until the composition FILE visibly changes — each + * generation records its file stamp, and a stale stamp starts the next + * generation for sessions created afterwards. Sessions already joined keep + * the generation they run on; a superseded one is never disposed while the + * process lives (reclaimed only by whole-tree teardown), so editing files + * is bounded by how often compositions change, not by session count. + */ + private readonly standing; + /** + * Parent bindings of the agents this roster composed, keyed by the agent's + * scope key. The binding is dsh-scope's only re-link capability; holding it + * here makes this service the sole authority that can move an agent between + * standing compositions. WeakMap: entries die with their agents. + */ + private readonly bindings; + /** + * Compose one agent from a preset: ensure the preset's standing mount, then + * parent the agent's scope key to it so the mount's registrations and + * listeners cover this agent. + * + * Call from the agent factory's `setup(agentCtx)`; a rejection there rolls + * the agent creation back, so a broken preset never yields a half-composed + * session. + * @param agentCtx - the agent's scope context. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the preset that was composed, for the caller to record. + * @throws when the preset is unknown or its composition is unusable. + */ + mount(agentCtx: Context, id?: string): Promise; + /** + * Join one agent to the SAME standing composition another already runs on. + * + * This is how a child agent inherits its parent's capabilities. It is a bind, + * not a mount: the parent's generation is already composed, so the child gets + * that exact instance — the same plugin objects, the same tool registrations, + * the same prompt sections. Re-resolving the parent's preset by id instead + * would re-read the roster, and a composition file edited since the parent + * started would hand the child a DIFFERENT generation than the one its + * parent's history was produced under (and a preset deleted since would fail + * the child outright while its parent keeps running). + * + * Synchronous, and with no composition failure mode of its own — it reads no + * roster, mounts nothing, and touches no file — which is what lets a child + * creation window use it: the two in-process subagent drivers compose their + * children inside a synchronous `setup`. It still rejects a caller error, as + * the `@throws` below record. + * + * A parent that joined no preset — a rosterless deployment — yields no join + * and no error: there, the model-facing rows sit in the host composition and + * the child already sees them through the global layer. + * @param agentCtx - the joining agent's scope context. + * @param parentCtx - the scope context of the agent whose composition to join. + * @returns the preset id joined, or undefined when the parent joined none. + * @throws when `agentCtx` carries no scope, or has already joined a preset. + */ + composeFrom(agentCtx: Context, parentCtx: Context): string | undefined; + /** + * The preset one live agent runs on. + * + * Read from the live scope chain rather than from the session, so it answers + * for an agent whose session has not recorded a preset yet — a child agent + * whose durable header is being built from its parent's composition. + * @param agentCtx - the agent's scope context. + * @returns the preset id, or undefined when the agent joined none. + */ + composedPreset(agentCtx: Context): string | undefined; + /** + * The roots this roster scans, which is not `config.roots`: it is every + * configured root in order, then the harness-home user root unless + * `includeUserRoot` is false. Read this — not the config field — to answer + * whether a roster is composed at all, so one derivation decides it. + */ + get roots(): readonly PresetRoot[]; + /** Whether this deployment has a root locally authored presets go to. */ + get authorable(): boolean; + /** + * Read one preset's composition text. + * @param id - the preset id. + * @returns the composition exactly as stored. + * @throws when no configured root supplies that id. + */ + read(id: string): Promise; + /** + * Create a locally authored preset by copying an existing one whole. + * + * Copy is the only authoring write. Composition text never crosses this + * seam: the source is named by id and its directory is copied as it stands, + * so the copy is exactly as loadable as its source and authoring grants no + * capability the roster did not already carry. The copy is NOT mounted to + * validate — a source that mounts today yields a copy that mounts today. + * @param from - the preset the copy starts from; shipped presets are the + * primary source, so any trust is accepted. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; absent falls back to the id. + * @throws when the source is unknown, the id is unusable or already taken, + * or the deployment configures no writable root. + */ + copy(from: string, id: string, name?: string): Promise; + /** + * Delete a locally authored preset. + * @param id - the preset id. + * @throws when the preset is unknown or ships with the deployment. + */ + remove(id: string): Promise; + /** + * One agent's instance of a service its preset mounted. + * + * A preset publishes services behind `isolate` realms, which are invisible + * outside the group that declares them — including to the host. This is how a + * caller holding the agent reads one anyway: a request that is ABOUT a + * session but arrives from outside it, which is every browser RPC. + * + * Read addressing only. A host row that `inject`s a service cannot use this, + * because injection resolves before any session exists and has no agent to + * key by; such a service belongs on the host plane instead. + * @param agent - the agent whose composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ + serviceFor(agent: { + ctx: Context; + }, name: K): Context[K] | undefined; + /** + * Re-link one agent to a different preset's standing composition. + * + * Only valid while the agent has produced nothing: swapping tools mid + * conversation would leave logged tool calls the new composition cannot + * make. The CALLER owns that check — this method does not read session + * history. + * + * The swap is a parent re-link, not an unmount: standing mounts are shared + * and permanent, so the old composition stays for its other agents and the + * new one is ensured BEFORE the link moves. An unknown or unusable preset + * therefore throws with the agent exactly as it was — there is no torn-down + * state to restore. The re-link runs through the binding this roster kept + * from the agent's mount — dsh-scope's only re-link authority. An agent + * that never composed one has nothing to re-link: the switch is then the + * agent's first bind, exactly a mount. + * @param agentCtx - the agent's scope context. + * @param id - the preset to compose the agent from instead. + * @returns the preset now installed. + * @throws when the preset is unknown or its composition is unusable. + */ + recompose(agentCtx: Context, id: string): Promise; + /** + * The standing scope key of one preset, for a host reader with no agent. + * + * A cold transcript read resolves tool presenters against the composition + * the session recorded, and the standing mount makes that possible without + * resuming anything: ensuring the mount composes plugins but starts no + * agent, no session, and no turn. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the standing scope key readers pass as a registry view scope. + * @throws when the preset is unknown or its composition is unusable. + */ + standingKeyFor(id?: string): Promise; + /** Resolve (or create, single-flight) the standing mount of one preset. */ + private ensureStanding; +} +export default AgentPresets; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.js new file mode 100644 index 0000000..015f50d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.js @@ -0,0 +1,500 @@ +/** + * Agent presets: each session composes its model-facing plugin set from one + * preset `cordis.yml`, mounted ONCE per preset under a standing scope and + * joined by every agent that names it. + * + * The standing mount is what makes a preset one composition rather than one + * per session: its plugin instances, tool registrations, prompt sections, and + * projection units exist exactly once, keyed per session inside the plugins + * themselves (they predate presets and were written for a shared world). An + * agent joins by having its scope key parented to the mount's + * ({@link bindScopeParent}), which makes the mount's registrations visible to + * that agent's views and the mount's listeners receive that agent's events — + * and a host reader with no agent at all (a cold transcript read) resolves + * the same standing registrations by preset id. + * + * This package owns the preset vocabulary, filesystem discovery, and the + * guarded standing mount. It does not decide when an agent is created — the + * agent factory's `setup(agentCtx)` hook is the one supported call site, + * because only there is the join installed while the agent is still + * unpublished, so a rejected composition rolls the whole creation back. + * @module @deepseek-ai/dsh-agent-presets + */ +import { stat } from 'node:fs/promises'; +import { Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { bindScopeParent, createScope, scopeOf } from '@deepseek-ai/dsh-scope'; +import { settingsNamespace } from '@deepseek-ai/dsh-settings'; +import { dshHomePath } from '@deepseek-ai/dsh-home-paths'; +import { discoverPresets, USER_PRESET_DIR } from "./discovery.js"; +import { copyComposition, deleteComposition, readComposition } from "./authoring.js"; +import { mountPreset, serviceForAgent, standingMountFor } from "./mount.js"; +import { PresetExistsError } from "./authoring.js"; +import { PresetMountError, UnknownPresetError } from "./preset.js"; +/** Settings namespace carrying the user's chosen default preset. */ +export const SETTINGS_NAMESPACE = 'agent-presets'; +/** Runtime schema for the user-writable slice. */ +export const AgentPresetSettingsSchema = z.object({ + default: z.string(), +}); +export { COMPOSITION_FILE, discoverPresets, scanRoot } from "./discovery.js"; +export { METADATA_FILE, readPresetMetadata, renderPresetMetadata, } from "./metadata.js"; +export { inactiveRows, leakedServices, livePresetMounts, mountPreset, serviceForAgent, standingMountFor, } from "./mount.js"; +export { copyComposition, deleteComposition, InvalidPresetIdError, PresetExistsError, PresetNotWritableError, readComposition, writableRoot, } from "./authoring.js"; +export { resolveSessionPreset } from "./session.js"; +export { PresetMountError, UnknownPresetError } from "./preset.js"; +/** + * Registry over the deployment's agent presets. + * + * Discovery is unmemoized: `list()` and `resolve()` re-read the roots on every + * call so a preset authored while the process runs is visible immediately, + * and a preset deleted underneath a picker disappears from the next read. + */ +export class AgentPresets extends Service { + config; + static inject = ['loader']; + /** Runtime schema for the preset roster. */ + static Config = z.object({ + default: z.string().required(), + roots: z.array(z.object({ + path: z.string().required(), + trust: z.union(['system', 'user']).default('user'), + })).default([]), + includeUserRoot: z.boolean().default(true), + }); + /** + * The roots discovery and authoring actually scan: every configured root in + * order, then the harness-home user root unless `includeUserRoot` is false. + * + * Derived once, because a root set that changed between `list()` and the + * `copy()` acting on its answer would author into a directory the caller + * never saw. Appending rather than prepending keeps an earlier configured + * root winning a duplicate id, so a shipped preset still shadows a + * locally authored directory that claimed its name. + */ + resolvedRoots; + /** + * The user layer over `config.default`, present only while a settings + * provider is composed. Held rather than snapshotted so a hot-reloaded + * document takes effect without a restart. + */ + settings; + /** + * The settings service behind {@link settings}, held for the one write this + * service makes: clearing a user default it has just deleted. + */ + settingsService; + /** + * The service's own untraced context. Methods invoked through the traceable + * proxy see `this.ctx` rebound to the CALLER's context, which carries a + * shadow; a subtree minted from it resolves every service through that + * shadow's fiber instead of each entry's own inject store, so preset rows + * would fail on the very services they declare. Standing mounts must hang + * off the untraced original (the `jobs-local` selfCtx precedent). + */ + selfCtx; + constructor(ctx, config) { + super(ctx, 'agentPresets'); + this.config = config; + this.selfCtx = ctx; + this.resolvedRoots = config.includeUserRoot + ? [...config.roots, { path: dshHomePath(USER_PRESET_DIR), trust: 'user' }] + : [...config.roots]; + // Deliberately not `installSettingsSection`: that helper exists to re-judge + // what a consumer DERIVED from the source — memoized resolutions, + // registration-level facts — across attach, detach, and change. Nothing + // here is derived. `defaultId` reads through on every call, so both of its + // hooks would be no-ops and the source thunk would restate this field. + ctx.inject(['settings'], (settingsCtx) => { + this.settings = settingsCtx.settings.register(settingsNamespace(SETTINGS_NAMESPACE), AgentPresetSettingsSchema, { base: { default: config.default } }); + this.settingsService = settingsCtx.settings; + settingsCtx.effect(() => () => { + this.settings = undefined; + this.settingsService = undefined; + }, 'agentPresets.settings()'); + }); + // Advisory, not fatal: a synchronous `agent/created` listener that throws + // VETOES publication, and this service must not, because composing an agent + // outside the roster is legal — `recompose` binds exactly such a bare agent + // below, and the ACP, SDK-server, and headless entry points all create one. + // The invariant companion is the check that fails loud, at assembly. Why an + // unjoined agent matters at all has one home: the [Agent + // Note](../../../../.agents/notes/implemented/architecture/2026-08-10-host-plane-ownership-after-presets.md). + // + // Known false positive: a session created bare and bound later by + // `recompose` is warned about once, before its first bind. No shipped flow + // does that today — the Web surface mounts in `setup` and children join + // through `composeFrom` before publication. + ctx.on('agent/created', ({ agent }) => { + if (this.resolvedRoots.length === 0) + return; + if (this.composedPreset(agent.ctx) !== undefined) + return; + ctx.logger.warn(`agent "${agent.id}" was published without joining an agent preset; ` + + 'its tools, prompt sections, and skill catalog resolve against the empty global layer ' + + '(join through AgentPresets.mount() or composeFrom() in the agent factory setup)'); + }); + // The durable record is the commit point. Its public notification carries + // only the stable identity needed by clients, never the live Session. + ctx.on('session/event', (session, event) => { + if (event.type !== 'agent-preset/selected') + return; + ctx.emit('agent-preset/selected', session.id, event.data.agentPreset); + }); + } + /** + * The preset id mounted when a caller names none. + * + * Read per call rather than cached: the settings document is hot-reloaded, so + * changing the default takes effect on the next session created and leaves + * every running session on the preset it was composed from. + */ + get defaultId() { + return this.settings?.get().default ?? this.config.default; + } + /** + * Every preset the configured roots currently supply. + * @returns the presets, first-root-wins per id. + */ + async list() { + return await discoverPresets(this.resolvedRoots); + } + /** + * Resolve one preset by id. + * + * A broken preset resolves — deleting one, reading one, and reporting one + * all need the row — and the mounting paths refuse it AFTER resolution + * through {@link resolveMountable}. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved preset. + * @throws when no configured root supplies that id. + */ + async resolve(id) { + const wanted = id ?? this.defaultId; + const presets = await this.list(); + const found = presets.find(preset => preset.id === wanted); + if (found === undefined) { + throw new UnknownPresetError(wanted, presets.map(preset => preset.id)); + } + return found; + } + /** + * Resolve one preset that is about to compose an agent, refusing a broken + * one with its discovery-reported reason. Failing here rather than inside + * the loader keeps the answer the same for every unloadable shape — ghost + * directory, unparsable YAML, rowless list — and spends no mount attempt + * on a composition discovery already read as unusable. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved, mountable preset. + * @throws when the preset is unknown or discovery reports it broken. + */ + async resolveMountable(id) { + const preset = await this.resolve(id); + if (preset.broken !== undefined) { + throw new PresetMountError(preset.id, preset.broken); + } + return preset; + } + /** + * Standing mounts by preset id, single-flight so two agents racing the + * first use of one preset share one composition. A settled failure is + * removed so a later session retries a preset whose file has been fixed; a + * settled success serves until the composition FILE visibly changes — each + * generation records its file stamp, and a stale stamp starts the next + * generation for sessions created afterwards. Sessions already joined keep + * the generation they run on; a superseded one is never disposed while the + * process lives (reclaimed only by whole-tree teardown), so editing files + * is bounded by how often compositions change, not by session count. + */ + standing = new Map(); + /** + * Parent bindings of the agents this roster composed, keyed by the agent's + * scope key. The binding is dsh-scope's only re-link capability; holding it + * here makes this service the sole authority that can move an agent between + * standing compositions. WeakMap: entries die with their agents. + */ + bindings = new WeakMap(); + /** + * Compose one agent from a preset: ensure the preset's standing mount, then + * parent the agent's scope key to it so the mount's registrations and + * listeners cover this agent. + * + * Call from the agent factory's `setup(agentCtx)`; a rejection there rolls + * the agent creation back, so a broken preset never yields a half-composed + * session. + * @param agentCtx - the agent's scope context. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the preset that was composed, for the caller to record. + * @throws when the preset is unknown or its composition is unusable. + */ + async mount(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === undefined) { + throw new Error('agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset'); + } + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + // The one bind of this agent's ancestry. The binding is the only re-link + // authority, held privately so nothing outside this roster can move a + // composed agent to another preset; a later recompose layer re-links + // through it under the caller-owned blank-session contract. + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return preset; + } + /** + * Join one agent to the SAME standing composition another already runs on. + * + * This is how a child agent inherits its parent's capabilities. It is a bind, + * not a mount: the parent's generation is already composed, so the child gets + * that exact instance — the same plugin objects, the same tool registrations, + * the same prompt sections. Re-resolving the parent's preset by id instead + * would re-read the roster, and a composition file edited since the parent + * started would hand the child a DIFFERENT generation than the one its + * parent's history was produced under (and a preset deleted since would fail + * the child outright while its parent keeps running). + * + * Synchronous, and with no composition failure mode of its own — it reads no + * roster, mounts nothing, and touches no file — which is what lets a child + * creation window use it: the two in-process subagent drivers compose their + * children inside a synchronous `setup`. It still rejects a caller error, as + * the `@throws` below record. + * + * A parent that joined no preset — a rosterless deployment — yields no join + * and no error: there, the model-facing rows sit in the host composition and + * the child already sees them through the global layer. + * @param agentCtx - the joining agent's scope context. + * @param parentCtx - the scope context of the agent whose composition to join. + * @returns the preset id joined, or undefined when the parent joined none. + * @throws when `agentCtx` carries no scope, or has already joined a preset. + */ + composeFrom(agentCtx, parentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === undefined) { + throw new Error('agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset'); + } + const standing = standingMountFor(parentCtx); + if (standing === undefined) + return undefined; + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return standing.presetId; + } + /** + * The preset one live agent runs on. + * + * Read from the live scope chain rather than from the session, so it answers + * for an agent whose session has not recorded a preset yet — a child agent + * whose durable header is being built from its parent's composition. + * @param agentCtx - the agent's scope context. + * @returns the preset id, or undefined when the agent joined none. + */ + composedPreset(agentCtx) { + return standingMountFor(agentCtx)?.presetId; + } + /** + * The roots this roster scans, which is not `config.roots`: it is every + * configured root in order, then the harness-home user root unless + * `includeUserRoot` is false. Read this — not the config field — to answer + * whether a roster is composed at all, so one derivation decides it. + */ + get roots() { + return this.resolvedRoots; + } + /** Whether this deployment has a root locally authored presets go to. */ + get authorable() { + return this.resolvedRoots.some(root => root.trust === 'user'); + } + /** + * Read one preset's composition text. + * @param id - the preset id. + * @returns the composition exactly as stored. + * @throws when no configured root supplies that id. + */ + async read(id) { + return await readComposition(await this.resolve(id)); + } + /** + * Create a locally authored preset by copying an existing one whole. + * + * Copy is the only authoring write. Composition text never crosses this + * seam: the source is named by id and its directory is copied as it stands, + * so the copy is exactly as loadable as its source and authoring grants no + * capability the roster did not already carry. The copy is NOT mounted to + * validate — a source that mounts today yields a copy that mounts today. + * @param from - the preset the copy starts from; shipped presets are the + * primary source, so any trust is accepted. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; absent falls back to the id. + * @throws when the source is unknown, the id is unusable or already taken, + * or the deployment configures no writable root. + */ + async copy(from, id, name) { + const source = await this.resolve(from); + // The roster check refuses ids any root supplies — shipped ones included, + // since a user directory named like a shipped preset is shadowed by it. + // The disk check inside copyComposition only sees the writable root. + if ((await this.list()).some(preset => preset.id === id)) { + throw new PresetExistsError(id); + } + await copyComposition(this.resolvedRoots, source, id, name); + // A settled mount under this id can only be stale (its preset was deleted + // from disk outside `remove`); the new preset must not inherit it. Every + // session already joined keeps the generation it runs on regardless. + this.standing.delete(id); + } + /** + * Delete a locally authored preset. + * @param id - the preset id. + * @throws when the preset is unknown or ships with the deployment. + */ + async remove(id) { + await deleteComposition(this.resolvedRoots, await this.resolve(id)); + // Sessions on the deleted preset keep their standing mount; only new + // sessions see the roster without it. + this.standing.delete(id); + // Storing a default that does not exist YET is deliberate — the roster is a + // live directory, so a name absent now may exist by the time a session asks + // for it, and `resolve` reports it then. A default this call just deleted is + // not that case: nothing will ever supply it again, and left in place every + // session created without an explicit pick would fail to start. Clearing it + // exposes the deployment's own default underneath, which is the layering. + if (this.settings?.get().default !== id) + return; + await this.settingsService?.mutate(settingsNamespace(SETTINGS_NAMESPACE), [{ op: 'unset', path: ['default'] }]); + } + /** + * One agent's instance of a service its preset mounted. + * + * A preset publishes services behind `isolate` realms, which are invisible + * outside the group that declares them — including to the host. This is how a + * caller holding the agent reads one anyway: a request that is ABOUT a + * session but arrives from outside it, which is every browser RPC. + * + * Read addressing only. A host row that `inject`s a service cannot use this, + * because injection resolves before any session exists and has no agent to + * key by; such a service belongs on the host plane instead. + * @param agent - the agent whose composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ + serviceFor(agent, name) { + return serviceForAgent(this.ctx, agent, name); + } + /** + * Re-link one agent to a different preset's standing composition. + * + * Only valid while the agent has produced nothing: swapping tools mid + * conversation would leave logged tool calls the new composition cannot + * make. The CALLER owns that check — this method does not read session + * history. + * + * The swap is a parent re-link, not an unmount: standing mounts are shared + * and permanent, so the old composition stays for its other agents and the + * new one is ensured BEFORE the link moves. An unknown or unusable preset + * therefore throws with the agent exactly as it was — there is no torn-down + * state to restore. The re-link runs through the binding this roster kept + * from the agent's mount — dsh-scope's only re-link authority. An agent + * that never composed one has nothing to re-link: the switch is then the + * agent's first bind, exactly a mount. + * @param agentCtx - the agent's scope context. + * @param id - the preset to compose the agent from instead. + * @returns the preset now installed. + * @throws when the preset is unknown or its composition is unusable. + */ + async recompose(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === undefined) { + throw new Error('agent-presets: refusing to recompose an unscoped context'); + } + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + const binding = this.bindings.get(agentKey); + if (binding === undefined) { + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + } + else { + binding.rebind(standing.key); + } + return preset; + } + /** + * The standing scope key of one preset, for a host reader with no agent. + * + * A cold transcript read resolves tool presenters against the composition + * the session recorded, and the standing mount makes that possible without + * resuming anything: ensuring the mount composes plugins but starts no + * agent, no session, and no turn. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the standing scope key readers pass as a registry view scope. + * @throws when the preset is unknown or its composition is unusable. + */ + async standingKeyFor(id) { + const preset = await this.resolveMountable(id); + return (await this.ensureStanding(preset)).key; + } + /** Resolve (or create, single-flight) the standing mount of one preset. */ + async ensureStanding(preset) { + const pending = this.standing.get(preset.id); + if (pending !== undefined) { + const mounted = await pending; + // Files are the only composition editor (authoring is copy/delete), so + // the stamp is what notices an edit: a changed file starts the next + // generation here, for this and later sessions. An unreadable stamp + // serves the current generation — a mount must survive its file + // disappearing, and failing the session over a stat would not. + const current = await compositionStamp(preset.path); + if (current === undefined || sameStamp(mounted.stamp, current)) + return mounted; + // TODO: reclaim the superseded generation once the last agent joined to + // it is gone. The subtree is not inert — `dsh-skill-filesystem` watches its + // roots — and the settings-page authoring flow turns "a composition + // changed" into a per-save event. This needs a joined-agent count on + // StandingMount, incremented in `mount`/`composeFrom`/`recompose` and + // decremented when the agent's scope key dies. + // Guarded delete: a caller that raced this one may have already started + // the next generation, and dropping THAT pointer would fork a third. + if (this.standing.get(preset.id) === pending) + this.standing.delete(preset.id); + return this.ensureStanding(preset); + } + const created = (async () => { + const key = { agentPreset: preset.id }; + const scope = createScope(this.selfCtx, key); + try { + // Stamped before the file is read: an edit racing the mount makes the + // stamp stale rather than silently current, so the next session + // refreshes instead of trusting a composition older than its stamp. + const stamp = await compositionStamp(preset.path); + if (stamp === undefined) { + throw new PresetMountError(preset.id, `composition file is unreadable: ${preset.path}`); + } + await mountPreset(scope.ctx, preset); + return { key, scope, stamp }; + } + catch (error) { + this.standing.delete(preset.id); + await scope.dispose(); + throw error; + } + })(); + this.standing.set(preset.id, created); + return created; + } +} +/** Read one composition file's stamp, or undefined when it cannot be statted. */ +async function compositionStamp(path) { + try { + const { mtimeMs, size } = await stat(path); + return { mtimeMs, size }; + } + catch { + // Deleted, replaced by an unreadable entry, or otherwise unstattable all + // mean the same to the caller: the file offers no identity to compare. + return undefined; + } +} +/** Whether two stamps name the same file state. */ +function sameStamp(a, b) { + return a.mtimeMs === b.mtimeMs && a.size === b.size; +} +export default AgentPresets; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.d.ts new file mode 100644 index 0000000..7b01c4f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-agent-presets`. + * @module @deepseek-ai/dsh-agent-presets/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "agent-presets-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.js new file mode 100644 index 0000000..71c027f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.js @@ -0,0 +1,65 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-agent-presets`. + * @module @deepseek-ai/dsh-agent-presets/invariant + */ +// Imported through the package name, not `./mount.ts`: a module shared between +// the two build entry points becomes a third chunk that the published `files` +// list does not carry, which `verify-built-package-invariants` rejects. +import { leakedServices, livePresetMounts } from '@deepseek-ai/dsh-agent-presets'; +const PACKAGE_NAME = '@deepseek-ai/dsh-agent-presets'; +/** Cordis companion plugin name. */ +export const name = 'agent-presets-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * Assert that no installed preset composition reaches the root service realm, + * and that a deployment configuring a roster composes every agent from it. + * + * `mountPreset` proves the first once, when the subtree settles. A row that + * publishes later — from a timer, or an asynchronous continuation after its + * plugin returned — would escape that one-shot audit, so re-check every live + * mount whenever a service registration changes. + */ +const install = (ctx, fail) => { + ctx.on('internal/service', function (name) { + for (const mount of livePresetMounts()) { + const leaked = leakedServices(ctx, mount.fiber); + if (leaked.length === 0) + continue; + fail(`preset "${mount.presetId}" published process-global service(s) [${leaked.join(', ')}] ` + + `after its mount was audited (observed while notifying "${name}") — ` + + 'a preset service must sit behind an `isolate` realm or move to the host composition'); + } + }, { global: true }); + // An agent that joined no preset resolves `tools`, `system-prompt`, and + // `skill` against the empty global layer, so the model receives nothing. + // `composedPreset()` is the roster's own answer to "did this agent join", + // read from the live scope chain — see the [Agent + // Note](../../../../.agents/notes/implemented/architecture/2026-08-10-host-plane-ownership-after-presets.md) + // for why the warning beside it is advisory while this one fails. + // + // Two conditions, each load-bearing. `context.agent` is what makes this an + // AGENT assembly: a scope-only assembly — a cold read resolving presenters + // in a standing key, a diagnostic — is not an agent and must not be judged + // on whether it joined anything. And assembly rather than publication is the + // moment that matters, because an unjoined agent is legal until it addresses + // a model: `recompose` binds a bare agent as its first link, and that agent + // is unjoined for its whole life up to the switch. + ctx.on('system-prompt/assemble', (_assembly, context, next) => { + const presets = ctx.get('agentPresets'); + const agent = context.agent; + if (presets !== undefined && presets.roots.length > 0 + && agent !== undefined && presets.composedPreset(agent.ctx) === undefined) { + fail(`agent "${agent.id}" addressed a model without joining any agent preset while a roster is ` + + 'composed; its tools, prompt sections, and skill catalog resolve against the empty global layer'); + } + return next(); + }); +}; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.d.ts new file mode 100644 index 0000000..4660208 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.d.ts @@ -0,0 +1,52 @@ +/** + * A preset's display metadata: the name and description a picker shows. + * + * It lives in its own file because the composition is a top-level list of + * plugin rows — YAML cannot carry sibling keys beside it, and faking a + * metadata row would hand the Loader something to load. Keeping it separate + * also keeps the composition exactly what its name says: a Cordis file the + * loader owns and the cordis preset can author. + * + * The file carries display text ONLY. `id` is the directory name and `trust` + * comes from the root a preset was discovered under, so neither is writable + * here — otherwise a locally authored preset could claim to be a shipped one. + * + * Every read failure degrades to no metadata. A preset whose display text is + * missing, malformed, or unreadable still mounts: presentation is not a + * capability, and a broken name must never become an agent that cannot start. + * @module @deepseek-ai/dsh-agent-presets/metadata + */ +/** The optional display-metadata file beside a preset's composition. */ +export declare const METADATA_FILE = "preset.yml"; +/** Display text a preset may publish about itself. */ +export interface PresetMetadata { + /** Human-facing name; falls back to the preset id when absent. */ + readonly name?: string; + /** One sentence on what this preset is for. */ + readonly description?: string; + /** + * Position within its group; lower comes first. A preset that declares + * none sorts after every preset that does, then by id — so the shipped set + * can read in capability order while authored ones stay alphabetical. + */ + readonly order?: number; +} +/** + * Read one preset directory's display metadata. + * + * Absent, unparsable, and wrongly-shaped files are all the same answer — + * empty metadata — because the caller renders a picker, not a diagnostic. + * @param directory - the preset directory. + * @returns the display text the preset published, possibly empty. + */ +export declare function readPresetMetadata(directory: string): Promise; +/** + * Render display metadata as the file's contents. + * + * Absent fields are omitted rather than written empty, so a preset with no + * description does not ship a key that reads as an intentional blank. + * @param metadata - the display text to store. + * @returns the YAML document, or undefined when there is nothing to store. + */ +export declare function renderPresetMetadata(metadata: PresetMetadata): string | undefined; +//# sourceMappingURL=metadata.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.js new file mode 100644 index 0000000..fe86def --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.js @@ -0,0 +1,92 @@ +/** + * A preset's display metadata: the name and description a picker shows. + * + * It lives in its own file because the composition is a top-level list of + * plugin rows — YAML cannot carry sibling keys beside it, and faking a + * metadata row would hand the Loader something to load. Keeping it separate + * also keeps the composition exactly what its name says: a Cordis file the + * loader owns and the cordis preset can author. + * + * The file carries display text ONLY. `id` is the directory name and `trust` + * comes from the root a preset was discovered under, so neither is writable + * here — otherwise a locally authored preset could claim to be a shipped one. + * + * Every read failure degrades to no metadata. A preset whose display text is + * missing, malformed, or unreadable still mounts: presentation is not a + * capability, and a broken name must never become an agent that cannot start. + * @module @deepseek-ai/dsh-agent-presets/metadata + */ +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import yaml from 'js-yaml'; +/** The optional display-metadata file beside a preset's composition. */ +export const METADATA_FILE = 'preset.yml'; +/** A non-empty trimmed string, or undefined for anything else. */ +function text(value) { + if (typeof value !== 'string') + return undefined; + const trimmed = value.trim(); + return trimmed === '' ? undefined : trimmed; +} +/** + * Read one preset directory's display metadata. + * + * Absent, unparsable, and wrongly-shaped files are all the same answer — + * empty metadata — because the caller renders a picker, not a diagnostic. + * @param directory - the preset directory. + * @returns the display text the preset published, possibly empty. + */ +export async function readPresetMetadata(directory) { + let raw; + try { + raw = await readFile(join(directory, METADATA_FILE), 'utf8'); + } + catch { + // Absent is the common case: metadata is optional and most presets, + // including every one authored by duplicating another, carry none. + return {}; + } + let parsed; + try { + parsed = yaml.load(raw); + } + catch { + // Malformed display text is not worth failing discovery over; the picker + // falls back to the id, and the composition still mounts. + return {}; + } + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) + return {}; + const record = parsed; + const name = text(record.name); + const description = text(record.description); + const order = typeof record.order === 'number' && Number.isFinite(record.order) + ? record.order + : undefined; + return { + ...name === undefined ? {} : { name }, + ...description === undefined ? {} : { description }, + ...order === undefined ? {} : { order }, + }; +} +/** + * Render display metadata as the file's contents. + * + * Absent fields are omitted rather than written empty, so a preset with no + * description does not ship a key that reads as an intentional blank. + * @param metadata - the display text to store. + * @returns the YAML document, or undefined when there is nothing to store. + */ +export function renderPresetMetadata(metadata) { + const name = text(metadata.name); + const description = text(metadata.description); + const { order } = metadata; + if (name === undefined && description === undefined && order === undefined) + return undefined; + return yaml.dump({ + ...name === undefined ? {} : { name }, + ...description === undefined ? {} : { description }, + ...order === undefined ? {} : { order }, + }, { lineWidth: -1 }); +} +//# sourceMappingURL=metadata.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.d.ts new file mode 100644 index 0000000..a1415e6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.d.ts @@ -0,0 +1,112 @@ +/** + * Mount one preset composition under an agent's scope context, then prove the + * result is usable before the agent is published. + * + * The scope context is what makes the composition per-session: entry contexts + * chain to the context the subtree was plugged into, so every `ctx.tools` + * and `ctx.systemPrompt` registration inside the preset files into that + * agent's layer and unwinds with it. Two guards make that safe. A row that + * never reached a usable state is rejected, because a directly-plugged subtree + * is absent from `ctx.loader.entries()` and no boot audit covers it. A row that + * published a service into the ROOT realm is rejected, because such a service + * is process-global rather than per-session and the second session mounting the + * same preset collides with the first. + * @module @deepseek-ai/dsh-agent-presets/mount + */ +import { Context, type Fiber } from '@deepseek-ai/cordis'; +import type { EntryTree } from '@deepseek-ai/cordis-plugin-loader'; +import { type ScopeKey } from '@deepseek-ai/dsh-scope'; +import { type AgentPreset } from './preset.ts'; +/** One preset composition currently installed under some agent. */ +export interface PresetMount { + /** The preset the subtree was composed from. */ + readonly presetId: string; + /** The mounted subtree's fiber. */ + readonly fiber: Fiber; + /** The standing scope key agents are parented to (undefined only in torn-down records). */ + readonly key: ScopeKey | undefined; +} +/** + * Every preset composition still installed, pruning fibers disposed since the + * last read. + * @returns the live mounts. + */ +export declare function livePresetMounts(): PresetMount[]; +/** + * Service names the mounted subtree published into the root realm. + * + * A provider without an `isolate` realm stores its implementation under the + * root's symbol for that name, which is exactly the comparison below; a + * provider inside an `isolate` realm stores under a realm-private symbol and + * is correctly absent here. + * @param ctx - any context of the runtime whose service store is inspected. + * @param mount - the mounted subtree's fiber. + * @returns the leaked service names in lexical order. + */ +export declare function leakedServices(ctx: Context, mount: Fiber): string[]; +/** A live standing mount located through one agent already joined to it. */ +export type JoinedPresetMount = PresetMount & { + /** The standing key, definite because it is what the lookup matched on. */ + readonly key: ScopeKey; +}; +/** + * The standing composition one agent is joined to. + * + * The agent's own key is parented to its preset's standing key, so the mount + * is found by matching that parent rather than by walking up from the agent — + * the mount is not under the agent's fiber. An agent that joined no preset — + * a deployment composing no roster, or a child agent before its join — has no + * parent link and resolves to undefined. + * @param agentCtx - the agent's scope context. + * @returns the mount the agent joined, or undefined when it joined none. + */ +export declare function standingMountFor(agentCtx: Context): JoinedPresetMount | undefined; +/** + * One agent's instance of a service its preset mounted. + * + * A preset publishes a service behind an `isolate` realm so two sessions + * cannot collide, and an entry-local realm is invisible to everything outside + * the group — including the agent's own scope context and the host. That is + * right for the rows inside the group and wrong for one caller: a request that + * is ABOUT a session but arrives from outside it, which is every browser RPC + * the api-proxy serves. + * + * Ownership is the same relation {@link leakedServices} reads, inverted: there + * it names implementations a subtree published into the ROOT realm, here it + * names the one this subtree published anywhere. Fiber membership is object + * identity for the reason stated on {@link withinFiber}. + * + * This is READ addressing for a caller that already holds the agent. It is not + * a general host handle on a session's internals: a host row that `inject`s a + * service cannot use it, because injection resolves before any session exists + * and has no agent to key by — such a service belongs on the host plane. + * @param ctx - any context of the runtime whose service store is inspected. + * @param agent - the agent whose mounted composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ +export declare function serviceForAgent(ctx: Context, agent: { + ctx: Context; +}, name: K): Context[K] | undefined; +/** + * Rows that did not reach a usable state, each rendered as one diagnostic line. + * + * A row whose module failed to import or whose plugin threw already rejects the + * mount through the loader; what remains observable here is a row still waiting + * for a service the composition never supplies. + * @param tree - the mounted subtree. + * @returns one line per unusable row, empty when every enabled row is usable. + */ +export declare function inactiveRows(tree: EntryTree): string[]; +/** + * Mount `preset` under `agentCtx` and return only once every row is usable. + * + * The subtree is owned by `agentCtx`'s fiber, so it unwinds with the agent and + * the caller receives no disposer. A rejection leaves nothing mounted. + * @param agentCtx - the agent's scope context, from the agent factory's `setup`. + * @param preset - the resolved preset to compose the agent from. + * @throws when `agentCtx` carries no scope, a row is unusable, or a row + * published a service into the root realm. + */ +export declare function mountPreset(agentCtx: Context, preset: AgentPreset): Promise; +//# sourceMappingURL=mount.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.js new file mode 100644 index 0000000..be5f76d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.js @@ -0,0 +1,349 @@ +/** + * Mount one preset composition under an agent's scope context, then prove the + * result is usable before the agent is published. + * + * The scope context is what makes the composition per-session: entry contexts + * chain to the context the subtree was plugged into, so every `ctx.tools` + * and `ctx.systemPrompt` registration inside the preset files into that + * agent's layer and unwinds with it. Two guards make that safe. A row that + * never reached a usable state is rejected, because a directly-plugged subtree + * is absent from `ctx.loader.entries()` and no boot audit covers it. A row that + * published a service into the ROOT realm is rejected, because such a service + * is process-global rather than per-session and the second session mounting the + * same preset collides with the first. + * @module @deepseek-ai/dsh-agent-presets/mount + */ +import { isAbsolute } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { Context } from '@deepseek-ai/cordis'; +import { Include } from '@deepseek-ai/cordis-plugin-include'; +import { scopeOf, scopeParentOf } from '@deepseek-ai/dsh-scope'; +import { PresetMountError } from "./preset.js"; +/** + * Subtrees captured by config identity. A subtree plugged directly (rather than + * created as a loader entry) never links itself to an `Entry`, so this is the + * only handle to the rows it created; config objects are minted per mount, so + * concurrent mounts cannot collide. + */ +const mounted = new WeakMap(); +/** + * The base URL bare specifiers resolve against, per pending mount, keyed by the + * same config object. Recorded before the subtree is plugged, because `Include` + * rewrites its own context's `baseUrl` to the composition's directory and the + * pre-mount value is the only handle on where the harness itself lives. + */ +const harnessBase = new WeakMap(); +/** + * Include subclass that publishes its tree and fiber for the audit, and never + * writes to the file it read. + */ +class PresetTree extends Include { + constructor(ctx, config) { + super(ctx, config); + mounted.set(config, { tree: this, fiber: ctx.fiber }); + } + /** + * Resolve a bare specifier from the harness rather than from the preset. + * + * `EntryTree.import()` resolves against the tree's own `baseUrl`, which + * `Include` sets to the composition's directory. That is right for a + * relative specifier — a preset's own files travel with it — and wrong for + * a package name: a locally authored preset lives under the user's home, + * where Node's upward `node_modules` walk never reaches the harness's own + * dependencies, so every `@deepseek-ai/dsh-*` row would fail to import. The + * mount records the host composition's base instead, which is inside the + * installed harness, and bare names resolve from there. An absolute + * filesystem path names neither base and becomes a file URL before Node's + * ESM loader receives it, which is required for drive-letter paths on + * Windows. + * @param name - the module specifier from the row. + * @param getOuterStack - the loader's stack composer for import diagnostics. + * @returns the imported module, or the `cordis:` builtin. + */ + import(name, getOuterStack) { + const specifier = isAbsolute(name) ? pathToFileURL(name).href : name; + const base = harnessBase.get(this.config); + /* v8 ignore next -- every PresetTree is constructed by `mountPreset`, which records the base first */ + if (base === undefined) + return super.import(specifier, getOuterStack); + if (name.startsWith('.') || name.startsWith('cordis:')) + return super.import(name, getOuterStack); + const internal = this.ctx.loader.internal; + /* v8 ignore next -- Node always supplies the internal module loader; the branch keeps a + hypothetical embedder from losing the row's name in a resolution error. */ + if (internal === undefined) + return super.import(specifier, getOuterStack); + return internal.import(specifier, base, {}); + } + /** + * A preset is an input, never a persistence target. + * + * The Loader writes a tree back through this method whenever it decides the + * config changed — a plugin self-disposing is enough, and tearing an agent + * down disposes its whole subtree. Inherited, that rewrites the preset file + * with whatever the dying tree held, which in practice means truncating a + * shipped composition to `[]` the first time a session ends. Persisting a + * preset is also meaningless: nothing here is user state, and the same file + * backs every session that names it. + * + * Dropping the write drops the `loader/config-update` the inherited method + * emits with it. Nothing observes one for a preset subtree today, and a + * future "edit your preset while it runs" flow needs a deliberate + * persistence path rather than this method's return. + */ + write() { + } +} +const mounts = new Set(); +/** + * Drop every record whose subtree is gone. + * + * Records are pruned by observation rather than through a disposal hook + * because a subtree can be torn down by its owning agent, by a failed mount, or + * by the whole tree unloading, and a cleared `uid` is what all three share. + * + * Pruning therefore has to happen on a path this module owns. Reading is one + * such path, but not a reliable one: the only production reader is the + * invariant companion's service listener, and `dsh-invariants` is a + * development composition — a shipped host never loads it. Mounting is the + * other, and it is the one every session takes, which bounds the set at one + * generation of dead records rather than one per session ever composed. Each + * record would otherwise retain its whole disposed subtree: the fiber holds + * its config, and that config is the key its `EntryTree` is stored under. + */ +function pruneDisposedMounts() { + for (const mount of mounts) { + if (mount.fiber.uid === null) + mounts.delete(mount); + } +} +/** + * Every preset composition still installed, pruning fibers disposed since the + * last read. + * @returns the live mounts. + */ +export function livePresetMounts() { + pruneDisposedMounts(); + return [...mounts]; +} +/** + * Whether `fiber` is `root` itself or is mounted anywhere inside its subtree. + * + * Membership is object identity. `uid` looks like a cheaper key but is a + * per-registry counter, so fibers in two different roots collide on it and a + * subtree in one runtime would be blamed for a service published in another. + * @param fiber - the fiber to locate. + * @param root - the subtree root to test membership against. + * @returns true when `fiber` belongs to `root`'s subtree. + */ +function withinFiber(fiber, root) { + let current = fiber; + while (true) { + if (current === root) + return true; + const parent = current.parent.fiber; + if (parent === current) + return false; + current = parent; + } +} +/** + * Service names the mounted subtree published into the root realm. + * + * A provider without an `isolate` realm stores its implementation under the + * root's symbol for that name, which is exactly the comparison below; a + * provider inside an `isolate` realm stores under a realm-private symbol and + * is correctly absent here. + * @param ctx - any context of the runtime whose service store is inspected. + * @param mount - the mounted subtree's fiber. + * @returns the leaked service names in lexical order. + */ +export function leakedServices(ctx, mount) { + const store = ctx.reflect.store; + const rootIsolate = ctx.root[Context.isolate]; + const leaked = []; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than + clearing it, so an own symbol always resolves; the guard exists only + because the store's index signature is optional. */ + if (impl === undefined) + continue; + if (!withinFiber(impl.fiber, mount)) + continue; + if (rootIsolate[impl.name] === key) + leaked.push(impl.name); + } + return leaked.sort((left, right) => left.localeCompare(right)); +} +/** + * The standing composition one agent is joined to. + * + * The agent's own key is parented to its preset's standing key, so the mount + * is found by matching that parent rather than by walking up from the agent — + * the mount is not under the agent's fiber. An agent that joined no preset — + * a deployment composing no roster, or a child agent before its join — has no + * parent link and resolves to undefined. + * @param agentCtx - the agent's scope context. + * @returns the mount the agent joined, or undefined when it joined none. + */ +export function standingMountFor(agentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === undefined) + return undefined; + const standingKey = scopeParentOf(agentKey); + if (standingKey === undefined) + return undefined; + return livePresetMounts().find((candidate) => candidate.key === standingKey); +} +/** + * One agent's instance of a service its preset mounted. + * + * A preset publishes a service behind an `isolate` realm so two sessions + * cannot collide, and an entry-local realm is invisible to everything outside + * the group — including the agent's own scope context and the host. That is + * right for the rows inside the group and wrong for one caller: a request that + * is ABOUT a session but arrives from outside it, which is every browser RPC + * the api-proxy serves. + * + * Ownership is the same relation {@link leakedServices} reads, inverted: there + * it names implementations a subtree published into the ROOT realm, here it + * names the one this subtree published anywhere. Fiber membership is object + * identity for the reason stated on {@link withinFiber}. + * + * This is READ addressing for a caller that already holds the agent. It is not + * a general host handle on a session's internals: a host row that `inject`s a + * service cannot use it, because injection resolves before any session exists + * and has no agent to key by — such a service belongs on the host plane. + * @param ctx - any context of the runtime whose service store is inspected. + * @param agent - the agent whose mounted composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ +export function serviceForAgent(ctx, agent, name) { + const mount = standingMountFor(agent.ctx); + if (mount === undefined) + return undefined; + const store = ctx.reflect.store; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than clearing it */ + if (impl === undefined) + continue; + if (impl.name !== name) + continue; + if (withinFiber(impl.fiber, mount.fiber)) + return impl.value; + } + return undefined; +} +/** + * Rows that did not reach a usable state, each rendered as one diagnostic line. + * + * A row whose module failed to import or whose plugin threw already rejects the + * mount through the loader; what remains observable here is a row still waiting + * for a service the composition never supplies. + * @param tree - the mounted subtree. + * @returns one line per unusable row, empty when every enabled row is usable. + */ +export function inactiveRows(tree) { + const lines = []; + for (const entry of tree.entries()) { + if (entry.disabled) + continue; + const fiber = entry.fiber; + /* v8 ignore next 4 -- the loader rejects an entry whose module or plugin failed, + so a settled tree never holds an enabled fiber-less entry; the branch exists + only because `Entry.fiber` is declared optional. */ + if (fiber === undefined) { + lines.push(`${entry.options.id} (${entry.options.name}): never started`); + continue; + } + const missing = Object.keys(fiber.inject).filter(name => fiber.ctx.get(name) === undefined); + if (missing.length > 0) { + lines.push(`${entry.options.id} (${entry.options.name}): waiting for ${missing.join(', ')}`); + } + } + return lines; +} +/** + * The reportable text of a mount failure. + * + * The loader reports several failed rows as one `AggregateError`, whose own + * message names none of them; without flattening, a composition that fails on + * two rows says only "loader entries failed to apply" and the operator has + * nothing to act on. + * @param error - the value the mount rejected with. + * @returns a single-line-per-cause description. + */ +function mountDetail(error) { + /* v8 ignore next -- every path into the mount's catch throws an Error: the loader + wraps a row's thrown value before it propagates, and this module's own + rejections are Errors. The fallback keeps a hostile value readable. */ + if (!(error instanceof Error)) + return String(error); + if (!(error instanceof AggregateError)) + return error.message; + return [error.message, ...error.errors.map(cause => `- ${mountDetail(cause)}`)].join('\n'); +} +/** + * Mount `preset` under `agentCtx` and return only once every row is usable. + * + * The subtree is owned by `agentCtx`'s fiber, so it unwinds with the agent and + * the caller receives no disposer. A rejection leaves nothing mounted. + * @param agentCtx - the agent's scope context, from the agent factory's `setup`. + * @param preset - the resolved preset to compose the agent from. + * @throws when `agentCtx` carries no scope, a row is unusable, or a row + * published a service into the root realm. + */ +export async function mountPreset(agentCtx, preset) { + const scope = scopeOf(agentCtx); + if (scope === undefined) { + throw new Error(`agent-presets: refusing to mount preset "${preset.id}" into an unscoped context; ` + + 'its registrations would apply to every agent in the process'); + } + const config = { path: pathToFileURL(preset.path).href }; + // Captured before the subtree exists: the standing scope context still + // carries the host composition's base, which is inside the installed + // harness and is therefore where a row's package name has to resolve from. + /* v8 ignore next -- the Loader sets `baseUrl` on the root before any scoped context derives from it */ + if (agentCtx.baseUrl !== undefined) + harnessBase.set(config, agentCtx.baseUrl); + // Before the record this mount is about to add: standing mounts are one per + // preset and live until whole-tree teardown, so pruning here only sweeps + // records of torn-down runtimes (tests; an HMR reload of the roster). + pruneDisposedMounts(); + const handle = agentCtx.plugin(PresetTree, config); + try { + await handle.await(); + const subtree = mounted.get(config); + /* v8 ignore next -- the subclass constructor runs before `await()` settles for every mounted tree */ + if (subtree === undefined) + throw new Error('mounted subtree did not publish its entry tree'); + const { tree, fiber } = subtree; + const unusable = inactiveRows(tree); + if (unusable.length > 0) { + throw new Error(`${String(unusable.length)} row(s) did not activate:\n${unusable.join('\n')}`); + } + const leaked = leakedServices(agentCtx, fiber); + if (leaked.length > 0) { + throw new Error(`row(s) published process-global service(s) [${leaked.join(', ')}]; ` + + 'a preset service must sit behind an `isolate` realm or move to the host composition'); + } + mounts.add({ presetId: preset.id, fiber, key: scopeOf(agentCtx) }); + } + catch (error) { + try { + await handle.dispose(); + /* v8 ignore next 5 -- teardown of a subtree nothing else references has no + observed failure mode; the guard exists so a teardown error cannot + replace the mount diagnostic the caller needs. */ + } + catch { + // Swallows only this subtree's teardown failure. The mount error below is + // the actionable one, and the discarded fiber is unreachable either way. + } + throw new PresetMountError(preset.id, `${mountDetail(error)} (${preset.path})`, { cause: error }); + } +} +//# sourceMappingURL=mount.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.d.ts new file mode 100644 index 0000000..a245ee1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.d.ts @@ -0,0 +1,88 @@ +/** Agent-preset vocabulary shared by discovery, mounting, and consumers. */ +/** + * Where a preset's composition came from. A `system` preset ships with the + * deployment; a `user` preset was authored locally, by a person or by an + * agent, and therefore carries the same trust as shell access. + */ +export type PresetTrust = 'system' | 'user'; +/** + * Ids a preset directory may use. + * + * The id becomes a path segment, so this is a containment boundary rather than + * a style rule: `..`, a separator, or an absolute-looking name would place the + * composition outside the root the deployment authorised. Discovery shares it: + * a directory whose name no copy could ever claim is not a preset slot. + */ +export declare const PRESET_ID: RegExp; +/** One preset directory that carries a mountable agent composition. */ +export interface AgentPreset { + /** Stable identifier; the preset directory's name. */ + readonly id: string; + /** Trust recorded from the root this preset was discovered under. */ + readonly trust: PresetTrust; + /** Absolute path of the preset's agent composition file. */ + readonly path: string; + /** Display name from the preset's own metadata; absent falls back to {@link id}. */ + readonly name?: string; + /** One sentence on what this preset is for, when it published one. */ + readonly description?: string; + /** Declared position within its group; absent sorts after those that declare one. */ + readonly order?: number; + /** + * Why this preset cannot compose a session, absent when it can. A broken + * preset stays on the roster — hiding it would leave its directory blocking + * the id with nothing to see or delete — but every mounting path refuses it + * up front with this reason instead of failing deep inside the loader. + */ + readonly broken?: string; +} +/** One directory scanned for preset subdirectories. */ +export interface PresetRoot { + /** Directory holding one subdirectory per preset; a leading `~` expands. */ + path: string; + /** Trust recorded on every preset discovered under this root. */ + trust: PresetTrust; +} +/** Plugin config: which preset is the default, and where presets live. */ +export interface Config { + /** Preset id mounted when a caller names none. Missing at mount time fails loud. */ + default: string; + /** Scanned roots in precedence order; an earlier root wins a duplicate id. */ + roots: PresetRoot[]; + /** + * Append the harness home's `USER_PRESET_DIR` as a `user` root, after every + * configured root. False mounts a roster over `roots` alone. + */ + includeUserRoot: boolean; +} +/** + * No configured root supplies the requested preset. + * + * Separate from a mount failure because the two mean different things to a + * caller: an unknown id is a bad request, while an unusable composition is a + * broken preset the deployment must fix. + */ +export declare class UnknownPresetError extends Error { + /** The id that was requested. */ + readonly presetId: string; + /** Ids the roster does supply, for the caller to offer instead. */ + readonly available: readonly string[]; + constructor( + /** The id that was requested. */ + presetId: string, + /** Ids the roster does supply, for the caller to offer instead. */ + available: readonly string[]); +} +/** A preset exists but its composition cannot be installed. */ +export declare class PresetMountError extends Error { + /** The preset whose composition failed. */ + readonly presetId: string; + /** Why it failed, without this package's own message prefix. */ + readonly reason: string; + constructor( + /** The preset whose composition failed. */ + presetId: string, + /** Why it failed, without this package's own message prefix. */ + reason: string, options?: ErrorOptions); +} +//# sourceMappingURL=preset.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.js new file mode 100644 index 0000000..22e2ca9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.js @@ -0,0 +1,45 @@ +/** Agent-preset vocabulary shared by discovery, mounting, and consumers. */ +/** + * Ids a preset directory may use. + * + * The id becomes a path segment, so this is a containment boundary rather than + * a style rule: `..`, a separator, or an absolute-looking name would place the + * composition outside the root the deployment authorised. Discovery shares it: + * a directory whose name no copy could ever claim is not a preset slot. + */ +export const PRESET_ID = /^[a-z0-9][a-z0-9-]*$/; +/** + * No configured root supplies the requested preset. + * + * Separate from a mount failure because the two mean different things to a + * caller: an unknown id is a bad request, while an unusable composition is a + * broken preset the deployment must fix. + */ +export class UnknownPresetError extends Error { + presetId; + available; + constructor( + /** The id that was requested. */ + presetId, + /** Ids the roster does supply, for the caller to offer instead. */ + available) { + super(`agent-presets: preset "${presetId}" not found (available: ${available.join(', ') || 'none'})`); + this.presetId = presetId; + this.available = available; + } +} +/** A preset exists but its composition cannot be installed. */ +export class PresetMountError extends Error { + presetId; + reason; + constructor( + /** The preset whose composition failed. */ + presetId, + /** Why it failed, without this package's own message prefix. */ + reason, options) { + super(`agent-presets: preset "${presetId}" failed to mount: ${reason}`, options); + this.presetId = presetId; + this.reason = reason; + } +} +//# sourceMappingURL=preset.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.d.ts new file mode 100644 index 0000000..7058875 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.d.ts @@ -0,0 +1,47 @@ +/** + * The session-log record of which preset a session actually runs. + * + * The creation header names the preset a session STARTED with, and it is + * deep-frozen because that is a creation fact. A session may still change + * preset while it is blank, and the effect of that change outlives the blank + * window: the first turn — and every turn after it — runs under the newly + * mounted composition. Recording the change is what keeps the log honest, and + * it is required outright by the repo's model-visible ⟺ logged rule, since the + * preset decides the tool schemas and prompt sections the model sees. + * + * Reconstruction reads {@link resolveSessionPreset}, never the header alone. + * @module @deepseek-ai/dsh-agent-presets/session + */ +import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session'; +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * The session's agent preset was chosen after creation, while the session + * was still blank. Log-only: it records the composition later turns ran + * under, so a resumed or forked session rebuilds the same one instead of + * the header's creation-time value. + */ + 'agent-preset/selected': { + agentPreset: string; + }; + } +} +/** The minimum a caller must supply to resolve a session's preset. */ +export interface PresetBearingSession { + /** The session's creation header. */ + readonly header: SessionHeader; + /** The session's event log, oldest first. */ + readonly events: readonly SessionEvent[]; +} +/** + * The preset a session actually runs, newest selection winning. + * + * The header supplies the creation-time value; every later selection is a + * logged event, so the last one is the answer. Reading the header alone + * rebuilds a switched session under the composition it was created with, not + * the one its history was produced under. + * @param session - the session's header and event log. + * @returns the preset id, or `undefined` when the deployment composes none. + */ +export declare function resolveSessionPreset(session: PresetBearingSession): string | undefined; +//# sourceMappingURL=session.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.js new file mode 100644 index 0000000..1fba0cc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.js @@ -0,0 +1,33 @@ +/** + * The session-log record of which preset a session actually runs. + * + * The creation header names the preset a session STARTED with, and it is + * deep-frozen because that is a creation fact. A session may still change + * preset while it is blank, and the effect of that change outlives the blank + * window: the first turn — and every turn after it — runs under the newly + * mounted composition. Recording the change is what keeps the log honest, and + * it is required outright by the repo's model-visible ⟺ logged rule, since the + * preset decides the tool schemas and prompt sections the model sees. + * + * Reconstruction reads {@link resolveSessionPreset}, never the header alone. + * @module @deepseek-ai/dsh-agent-presets/session + */ +/** + * The preset a session actually runs, newest selection winning. + * + * The header supplies the creation-time value; every later selection is a + * logged event, so the last one is the answer. Reading the header alone + * rebuilds a switched session under the composition it was created with, not + * the one its history was produced under. + * @param session - the session's header and event log. + * @returns the preset id, or `undefined` when the deployment composes none. + */ +export function resolveSessionPreset(session) { + for (let index = session.events.length - 1; index >= 0; index -= 1) { + const event = session.events[index]; + if (event?.type === 'agent-preset/selected') + return event.data.agentPreset; + } + return session.header.agentPreset; +} +//# sourceMappingURL=session.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.d.ts new file mode 100644 index 0000000..a2193fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.d.ts @@ -0,0 +1,16 @@ +/** Client-safe event declarations owned by the agent-preset domain. */ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * One session committed a different agent preset to its durable log. + * Consumers invalidate only state derived from that session's composition. + * @mode emit + * @param sessionId - the session whose composition changed. + * @param agentPreset - the preset recorded by the committed selection. + */ + 'agent-preset/selected'(sessionId: SessionId, agentPreset: string): void; + } +} +export {}; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.js new file mode 100644 index 0000000..718fd38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/js-yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/js-yaml new file mode 100755 index 0000000..7cb3d55 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/js-yaml @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +else + exec node "$basedir/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/package.json new file mode 100644 index 0000000..82c9a62 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets/package.json @@ -0,0 +1,73 @@ +{ + "name": "@deepseek-ai/dsh-agent-presets", + "description": "Per-session agent composition from preset cordis.yml files for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/preset/agent-presets" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6" + }, + "dependencies": { + "js-yaml": "^4.1.0", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent-loop": "^0.1.0-rc.6", + "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.6", + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.6", + "@deepseek-ai/dsh-settings-file": "^0.1.0-rc.6", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-atomic-write b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-atomic-write new file mode 120000 index 0000000..f400fed --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-atomic-write @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-home-paths b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-home-paths new file mode 120000 index 0000000..c4b1460 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-home-paths @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-settings b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-settings new file mode 120000 index 0000000..810b363 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-settings @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-system-prompt b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-system-prompt new file mode 120000 index 0000000..7b9075d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-system-prompt @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/js-yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/js-yaml new file mode 120000 index 0000000..87e33ce --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/js-yaml @@ -0,0 +1 @@ +../../js-yaml@4.3.1/node_modules/js-yaml \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis-plugin-include b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis-plugin-include new file mode 120000 index 0000000..361c171 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis-plugin-include @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis-plugin-loader b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis-plugin-loader new file mode 120000 index 0000000..614b839 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/cordis-plugin-loader @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.i18n.yaml new file mode 100644 index 0000000..f3fef85 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/preset/agent-presets/README.md +README.md: 2438d751f000297cc4ede7b2a34736a62cc39dda +README.zh.md: c8ab8e167d624f639f6657d4c0ade7205b23821b diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.md new file mode 100644 index 0000000..2438d75 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.md @@ -0,0 +1,154 @@ +# dsh-agent-presets + +English | [中文](README.zh.md) + +Per-preset agent composition. A **preset** is a directory holding one `agent.cordis.yml`; the roster mounts it ONCE per process under a standing scope, and each session that names it joins by having its agent scope key parented to the mount's (`dsh-scope`'s parent chain). The mount's tools, prompt sections, and projection units exist exactly once and cover every joined agent — its plugins key their state by Session/Agent, so sessions stay apart inside one shared instance — and a host reader with no agent at all (a cold transcript read) resolves the same standing registrations by preset id. + +The mechanism is two seams. Entry contexts chain to the context a subtree was plugged into, and both [`dsh-tools`](../../core/tools/README.md) and [`dsh-system-prompt`](../../core/system-prompt/README.md) file registrations into the calling context's scope layer — so the standing mount's contributions land in the PRESET's layer. What carries them to each session is `dsh-scope`'s parent chain: an agent's views resolve `agent → preset → global` (nearest shadowing farthest), and the mount's listeners are admitted for every agent parented under it while a sibling preset's stay deaf. + +## Service: `AgentPresets` (ctx key: `agentPresets`) + +Discovery is unmemoized: `list()` and `resolve()` re-read the roots on every call, so a preset authored while the process runs is visible immediately and a deleted one disappears from the next read. Discovery also owns preset **health**: a directory whose composition is missing or unloadable (unparsable YAML — checked with the loader's own dialect, `!!js` included — or not a list of named plugin rows) is listed with a `broken` reason rather than skipped, because a skipped directory would still occupy its id on disk while every surface shows nothing to delete. A directory whose name is not a usable preset id (`[a-z0-9][a-z0-9-]*`) is skipped outright: no copy could ever claim it. + +- `ctx.agentPresets.defaultId: string` The preset id mounted when a caller names none. +- `ctx.agentPresets.list(): Promise` Every preset the configured roots currently supply, earlier root winning a duplicate id; broken presets included, each carrying its reason. +- `ctx.agentPresets.resolve(id?): Promise` One preset by id, defaulting to `defaultId`. Throws naming the available ids when no root supplies it. A broken preset resolves — deleting, reading, and reporting one all need the row. +- `ctx.agentPresets.mount(agentCtx, id?): Promise` Compose one agent from a preset — ensure its standing mount (single-flight) and parent the agent's scope key to it — returning the preset for the caller to record. Refuses a broken preset up front with its discovery-reported reason, so every unloadable shape fails the same way before the loader is involved. +- `ctx.agentPresets.composeFrom(agentCtx, parentCtx): string | undefined` Join one agent to the standing composition another already runs on, returning the preset id joined — `undefined` when the parent joined none, which is the rosterless deployment and not an error. A bind rather than a mount, so it is synchronous and has no composition failure mode; it still rejects a caller error (an unscoped context, or an agent that already joined). +- `ctx.agentPresets.composedPreset(agentCtx): string | undefined` The preset one LIVE agent runs on, read from its scope chain rather than from its session — the only answer available for an agent whose durable header is still being built. +- `ctx.agentPresets.recompose(agentCtx, id): Promise` Re-link one agent to a different preset's standing composition. Valid only while the agent has produced nothing — **the caller owns that check**; the new mount is ensured before the link moves, so a failure leaves the agent as it was. Refuses a broken preset like `mount()`. +- `ctx.agentPresets.standingKeyFor(id?): Promise` The standing scope key a host reader with no agent (a cold transcript read) resolves preset registrations in; ensures the mount without starting an agent, session, or turn. Refuses a broken preset like `mount()`. +- `ctx.agentPresets.roots: readonly PresetRoot[]` The roots this roster scans — every configured root in order, then the derived harness-home root. Not `config.roots`: read this to answer whether a roster is composed at all, so one derivation decides it. +- `ctx.agentPresets.authorable: boolean` Whether any of those roots has `user` trust, and therefore whether a preset can be created at all. +- `ctx.agentPresets.read(id): Promise` One preset's composition text, exactly as stored. +- `ctx.agentPresets.copy(from, id, name?): Promise` Create a locally authored preset by copying an existing one's whole directory — the only authoring write. No composition text crosses this seam, so a copy is exactly as loadable as its source; the copied metadata keeps the source's description but never its name or roster order, and `name` (or the id fallback) is what distinguishes the rows. +- `ctx.agentPresets.remove(id): Promise` Delete a locally authored preset; joined sessions keep their standing mount. Clears the user default when it named the preset just deleted: storing a default that does not exist yet is deliberate, but one this call removed will never be supplied again and would fail every session created without an explicit pick. + +`AgentPreset` carries `id` (the directory name), `trust` (`system` or `user`, from the root it was found under), `path` (the absolute composition file), and — only when the preset cannot compose a session — `broken` (one human-readable reason, shown verbatim on roster surfaces). + +### Where to call `mount()` + +The agent factory's `setup(agentCtx)` hook is the one supported call site. Only there is the join installed while the agent is still unpublished, so a rejected composition rolls the whole creation back rather than leaving a half-composed session. The standing subtree is owned by the roster service's own fiber — deliberately its UNTRACED context, because a subtree minted from a traced `this.ctx` resolves every service through the caller's shadow fiber instead of each entry's own inject store — so it survives every agent and unwinds only with the whole tree. Each generation records its composition file's stamp (mtime and size): a session that finds the stamp stale starts the next generation, while every session already joined keeps the one it runs on — the composition a running session joined outlives its file changing or disappearing underneath it, and files are the only composition editor, so the stamp is what carries an edit to later sessions. + +### Composing a child agent + +A subagent's child joins its parent's standing composition through `composeFrom()`, never through `mount()`. Every model-facing row lives on the agent plane, so the tool registry's global layer is empty and a child that joins nothing reaches the model with no tools at all and none of its parent's prompt sections. + +Re-mounting the parent's preset by id would differ from the bind in two ways that both matter. A composition file edited since the parent started would hand the child a DIFFERENT generation than the one its parent's history was produced under, and a preset deleted since would fail the child outright while its parent keeps running. The bind is also synchronous, which is what lets the in-process subagent drivers use it at all — they compose their children inside a synchronous creation window. + +The child records the joined id on its own durable header ([`dsh-subagent`](../../subagent/subagent/README.md)), so a cold read of the child's history rebuilds the composition it actually ran under rather than the deployment default. + +### Which preset a session runs + +The creation header names the preset a session STARTED with; `resolveSessionPreset(session)` names the one it RUNS. They differ whenever a blank session switched, so every reconstruction path — the summary a picker reads, a resume, a fork — resolves rather than reading the header. + +The header stays frozen because it is a creation fact. A switch is an `agent-preset/selected` session event appended after the swap commits, which is what the model-visible ⟺ logged rule requires: the preset decides the tool schemas and prompt sections the model sees, so it has to be reconstructable from the log. The service re-emits that committed fact as the non-scoped cordis event `agent-preset/selected(sessionId, agentPreset)` declared by the client-safe `./types` export, allowing remote consumers to invalidate session-derived state without importing Host runtime types. Reading the header alone would rebuild a switched session under the composition it was created with, replaying history the new tool set cannot act on — the exact hazard the blank-only lock exists to prevent. + +### Switching a blank agent + +`recompose()` unmounts the installed subtree and mounts the new one, because two compositions cannot coexist — both would register the same tool names into one layer. A failed mount restores the previous composition rather than leaving the agent with nothing, and an unknown id is rejected before anything is torn down. + +The restriction to a produced-nothing agent is a product rule, not a mechanical one: swapping tools mid-conversation would leave logged tool calls the new composition cannot make. The gateway enforces it at the wire ([`dsh-apiproxy`](../../host/apiproxy/README.md) answers `agent-preset-locked`), which is where session history is in hand. + +## Authoring + +Authoring is copy-only. A new preset is a whole-directory copy of an existing one — composition, metadata, skill directories, assets — landed under the first `user` root; the inputs are two ids the service resolves against its own roots plus an optional display name, so no caller ever supplies composition text and a copy grants nothing the roster did not already carry. Everything after creation happens in the preset's own files. `copy()` refuses three things before anything lands: + +- **An id that is not `[a-z0-9][a-z0-9-]*`.** The id becomes a directory name, so containment is a property of the id itself rather than of a path check after the fact — `../escape`, `a/b`, and an absolute path are all rejected as ids. +- **An id that is already taken.** A copy never overwrites: any root supplying the id refuses it (a user directory named like a shipped preset would be shadowed by it), and a directory occupying the name on disk refuses it too. Discovery lists such a directory as a broken preset, so the refusal's way out — delete it — is on the same page that reported it. +- **An unknown source.** The source may be any trust — copying a shipped preset is the primary case — but it must exist; a failed copy rolls its half-made directory back rather than leaving one discovery cannot see. + +The copied tree is re-tightened to owner-only (`0o600` files keeping their owner-execute bit, `0o700` directories), symlinks are dereferenced so the copy is self-contained, and the root is created on first copy — a deployment configuring a user root that does not exist yet is the normal first-run state. The copied `preset.yml` is rewritten: the source's description is kept for the author to edit in place, but its name and roster `order` are dropped — a copy presenting itself identically to its source, or sorted into the shipped set's declared order, would make the roster stop distinguishing them. `remove()` refuses a preset that ships with the deployment; the shipped set is the known-good compositions copies start from. + +### How a preset's rows resolve + +A row's **package name** resolves from the host composition, not from the preset directory. The Loader normally resolves an entry against its own tree's `baseUrl`, which for a preset is wherever the composition file sits; a locally authored preset lives under the user's home, where Node's upward `node_modules` walk never reaches the harness, so every `@deepseek-ai/dsh-*` row would fail to import. The mount records the host base before plugging the subtree and sends bare specifiers there. + +A **relative** path still resolves from the preset's own directory, so a preset's own plugin files and skill directories travel with it. + +An **absolute** filesystem path keeps its own location. The mount converts it to a `file:` URL before ESM import so POSIX paths and Windows drive-letter or UNC paths use a specifier Node accepts. + +### Display metadata + +A preset may publish display text in an optional `preset.yml` beside its composition: + +```yaml +name: 极简模式 +description: 仅提供持久 bash 与 str_replace_editor 的双工具编码 Agent。 +``` + +It carries display text ONLY. `id` is the directory name and `trust` comes from the root the preset was discovered under, so neither is writable here — otherwise a locally authored preset could name itself into the shipped set. It is a separate file because the composition is a top-level list of plugin rows: YAML cannot carry sibling keys beside it, and a fake metadata row would hand the Loader something to load. + +Every read failure degrades to no metadata — absent, malformed, wrongly typed, or blank all mean the same thing, and a picker falls back to the id. Presentation is not capability: a preset with a broken name still mounts. + +## Config + +| Field | Default | Meaning | +|---|---|---| +| `default` | required | Preset id mounted when a caller names none | +| `roots` | `[]` | Scanned directories in precedence order; each supplies `path` (a leading `~` expands) and `trust` (defaults to `user`) | +| `includeUserRoot` | `true` | Append `/.agent-presets` as a `user` root, after every configured root | + +An absent root supplies no presets rather than failing: the user root does not exist until the first locally authored preset, and naming a default no root supplies already fails loud at resolution. + +### The writable root is this package's, the shipped root is the app's + +`/.agent-presets` is where a person's own presets live, the way `/skills` is where their own skills live ([`dsh-skill-filesystem`](../../skill/skill-filesystem/README.md)), so the roster derives it rather than waiting for a deployment to remember it — a launcher that configures nothing still finds and authors presets. It is appended AFTER every configured root, which keeps an earlier root winning a duplicate id: a shipped `standard` still shadows a home directory that claimed the name, and `copy()` refuses that id rather than landing a preset nothing would resolve. + +The roots are resolved once, when the service is constructed. A root set that changed between a `list()` and the `copy()` acting on its answer would author into a directory the caller never saw. + +`includeUserRoot: false` mounts a roster over `roots` alone. A deployment that confines presets to its own directories needs it, and so does any test pinning an exact roster — otherwise the machine's real `` decides what the roster contains. + +The SHIPPED root stays an assembly fact: it sits beside the installed app's own config, a path only that app can resolve. + +### The default preset is a user setting + +When a settings provider is composed, this plugin registers the `agent-presets` namespace with `config.default` as its composition base, so the user document layers over the deployment's engineering default: + +```yaml +agent-presets: + default: minimal +``` + +The value is read per resolution rather than snapshotted, so a hot-reloaded document takes effect on the next session created and every running session stays on the preset it was composed from. Clearing the user field re-inherits the composition default. A default naming a preset no root supplies is stored without complaint and fails at the next `resolve()` — the roster is a live directory, so a name absent now may exist by the time a session asks for it. + +## What a mount rejects + +A directly-plugged subtree is absent from `ctx.loader.entries()`, so no boot audit covers it. `mount()` therefore proves the result usable itself, and rejects three things. + +**An unscoped target.** Mounting into a context that carries no agent scope would register the preset's tools globally, for every agent in the process. + +**A row that never became usable.** The loader already rejects a row whose module failed to import or whose plugin threw; what remains is a row still waiting for a service the composition never supplies, which the audit names. + +**A row that published a service into the root realm.** Such a service is process-global, so the second preset publishing the same name collides with the first, and a host reader would resolve one preset's instance for every session. A preset that genuinely owns a service puts it behind an `isolate` realm — entry-local realms keep two presets' same-named services apart exactly as they once kept two sessions' apart — or the service belongs in the host composition instead. + +The package invariant re-checks that last rule on every service notification, because a row that publishes from a timer or an asynchronous continuation would escape the one-shot audit. + +## A preset file is an input, never a persistence target + +The Loader writes a tree back to its source file whenever it decides the config changed, and a row disposing its own fiber is enough to decide that: the entry is marked `disabled` and the tree is written. Inherited, that would burn one session's runtime state into a file every session shares — comments stripped by the YAML round trip, and a `writeFile` rejection inside a `setTimeout` for a read-only shipped preset. + +The mounted subtree therefore overrides `write()` as a no-op. Nothing in this package writes a composition; authoring one is a separate, explicit operation. + +## Trust + +Presets are compositions, so a preset is exactly as privileged as the plugins it names. A `user` preset — authored by a person or by an agent — carries the same trust as shell access; the `trust` field exists so consumers can present that difference, not to enforce it. + +## Model Experience + +Indirectly, through the plugins a standing composition registers, which own every tool schema and prompt section the preset makes visible to the agents joined to it. + +#### KV Cache effect + +Prefix-stable for the life of an agent: a composition is installed once, before the agent is published and therefore before its first request, and is never re-read while the agent runs. Choosing a different preset for a new session establishes a different prefix for that session alone and cannot invalidate reuse for any session already running. + +## Known Limitations and Deferred Work + +- **A preset outside the writable root is discoverable but not deletable** — `remove()` refuses anything that does not live under the FIRST `user` root, so a deployment that configures its own writable root while leaving `includeUserRoot` on lists the harness-home presets, mounts them, and then answers "it does not live under the writable preset root" for every delete. The roster carries one writable root by design; a deployment that wants only its own sets `includeUserRoot: false`. +- **A preset cannot be changed once a session has produced anything** — `recompose` re-links a BLANK session's parent scope to another standing mount, and only a blank one: switching a composition that already ran would strand tools the model has called. Changing the default affects only sessions created afterwards. +- **A generation is keyed on the composition file alone** — the stamp check notices `agent.cordis.yml` changing, not an edit to a skill file or asset beside it; those reach new sessions only once the composition file itself moves or the process restarts. +- **A superseded generation is never reclaimed** — sessions already joined keep the generation they run on, and the roster holds no join count that could tell when the last one left, so the whole subtree stays mounted until the process ends. The cost is per generation rather than per session, but it is not free: `dsh-skill-filesystem` watches its roots by default, so each edit-then-create cycle adds a live watcher set. Bounded by how often compositions are edited — which the settings-page authoring flow makes a per-save event rather than a per-deploy one. Reclaiming one needs a joined-agent count on the standing mount; see the `TODO` at `ensureStanding`. +- **A copy is never mounted to validate** — it is byte-identical to its source, so a source broken on disk yields a copy exactly as broken as the source; discovery's health check marks both rows on the next roster read rather than deferring the failure to a session start. +- **Health is a shape check, not a mount** — discovery proves the composition parses in the loader dialect and holds named rows, not that every row's module resolves or activates; a row naming an absent package still fails at the first session, which rolls the creation back. +- **A copy is a snapshot that drifts** — upgrading the deployment does not update copies of shipped presets, and there is no patch semantics at this layer to express "standard plus one change" (that is the bundle layer's `cordis.patch.yml`); the shipped set itself accepts the same cost — `cordis` and `code` are full copies of `standard` — so the whole assembly stays readable in one file. +- **Root scans are not watched** — every read hits the filesystem instead, which keeps the roster fresh but puts one `readdir` per root on each `list()`. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.zh.md new file mode 100644 index 0000000..c8ab8e1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/README.zh.md @@ -0,0 +1,154 @@ +# dsh-agent-presets + +[English](README.md) | 中文 + +按 preset 组装 agent(智能体)。**preset** 是一个目录,其中放置一份 `agent.cordis.yml`;roster 在整个进程内只把它挂载一次(常驻 scope),命名它的每个会话通过把自己 agent 的 scope key 认父到该挂载(`dsh-scope` 的父链)来加入。挂载的工具、提示词段落与投影单元只存在一份,覆盖所有已加入的 agent——其插件本就按 Session/Agent 分键存状态,会话在共享实例内互不串扰——而完全没有 agent 的宿主读取方(冷读记录)也能按 preset id 解析到同一份常驻注册。 + +其机制是两条 seam。entry 上下文沿原型链连到子树被挂载时所在的上下文,而 [`dsh-tools`](../../core/tools/README.md) 与 [`dsh-system-prompt`](../../core/system-prompt/README.md) 本就按调用方上下文的 scope 分层归档注册——因此常驻挂载的贡献落在 **preset 的分层**里。把它们送达每个会话的是 `dsh-scope` 的父链:agent 的视图按 `agent → preset → global` 解析(近者遮蔽远者),挂载的监听器对认父到它的每个 agent 放行,而兄弟 preset 的监听器保持失聪。 + +## 服务:`AgentPresets`(ctx 键:`agentPresets`) + +发现过程不做缓存:`list()` 与 `resolve()` 每次调用都重新读取各个根目录,因此进程运行期间新写的 preset 立即可见,被删除的 preset 也会在下一次读取时消失。发现过程同时负责 preset 的**健康**:组装文件缺失或不可加载(YAML 无法解析——用加载器自己的方言检查,含 `!!js`——或不是由具名插件行组成的列表)的目录会作为携带 `broken` 原因的行列出而不是被跳过,因为被跳过的目录仍在磁盘上占着它的 id,而各个界面却没有任何可删的东西。目录名不是可用 preset id(`[a-z0-9][a-z0-9-]*`)的目录才被直接跳过:复制永远不可能占用那种名字。 + +- `ctx.agentPresets.defaultId: string` 调用方未指定时挂载的 preset id。 +- `ctx.agentPresets.list(): Promise` 当前各根目录提供的全部 preset;id 重复时靠前的根目录胜出;损坏的 preset 也在其中,各自携带原因。 +- `ctx.agentPresets.resolve(id?): Promise` 按 id 取一个 preset,缺省取 `defaultId`。没有任何根目录提供该 id 时抛错,并列出可用 id。损坏的 preset 照样解析——删除、读取与上报都需要这一行。 +- `ctx.agentPresets.mount(agentCtx, id?): Promise` 用一个 preset 组装一个 agent——确保其常驻挂载(并发去重)并把 agent 的 scope key 认父到它——返回该 preset 供调用方记录。对损坏的 preset 直接以发现时记下的原因拒绝,所以每种不可加载的形态都在加载器介入之前以同一方式失败。 +- `ctx.agentPresets.composeFrom(agentCtx, parentCtx): string | undefined` 让一个 agent 加入另一个 agent 已在运行的常驻组装,返回所加入的 preset id——父方未加入任何 preset 时返回 `undefined`,那是无 roster 的部署,不是错误。这是认父而非挂载,因此同步、且自身没有组装失败模式;调用方用错(上下文无 scope、agent 已加入过)仍会拒绝。 +- `ctx.agentPresets.composedPreset(agentCtx): string | undefined` 某个**活着的** agent 正在运行的 preset,从其 scope 链读取而不是从其会话读取——对于持久化 header 尚在构建中的 agent,这是唯一能拿到的答案。 +- `ctx.agentPresets.recompose(agentCtx, id): Promise` 把一个 agent 重链到另一个 preset 的常驻组装。仅在该 agent 尚无任何产出时合法——**由调用方负责该检查**;新挂载在链移动之前确保完成,失败时 agent 原封不动。与 `mount()` 一样拒绝损坏的 preset。 +- `ctx.agentPresets.standingKeyFor(id?): Promise` 没有 agent 的宿主读取方(冷读记录)解析 preset 注册所用的常驻 scope key;确保挂载而不启动任何 agent、会话或轮次。与 `mount()` 一样拒绝损坏的 preset。 +- `ctx.agentPresets.roots: readonly PresetRoot[]` 本 roster 实际扫描的根目录——全部已配置根目录按序在前,随后是推导出的 harness home 根目录。它不是 `config.roots`:判断「是否已组装 roster」应读它,从而由同一处推导决定。 +- `ctx.agentPresets.authorable: boolean` 上述根目录中是否有任一具备 `user` 信任级别,因而 preset 是否可创建。 +- `ctx.agentPresets.read(id): Promise` 某个 preset 的组装文本,与存储内容逐字一致。 +- `ctx.agentPresets.copy(from, id, name?): Promise` 通过整目录复制一个既有 preset 来创建本地创作的 preset——唯一的创作写入。组装文本不经过这道接缝,因此副本与其来源同等可加载;复制出的元数据保留来源的描述、但绝不保留其名称与 roster 排序,`name`(或回退到 id)才是区分两行的依据。 +- `ctx.agentPresets.remove(id): Promise` 删除一个本地创作的 preset;已加入的会话保留其常驻挂载。若用户默认值恰好指向刚删除的 preset 则一并清除:存一个尚不存在的默认值是刻意的,但本次删除的这个再也不会有人提供,留着会让所有未显式指定的新会话无法启动。 + +`AgentPreset` 携带 `id`(目录名)、`trust`(`system` 或 `user`,取自它所在的根目录)、`path`(组装文件的绝对路径),以及——仅当该 preset 无法组装会话时——`broken`(一条人类可读的原因,名单界面原样展示)。 + +### 应在何处调用 `mount()` + +agent 工厂的 `setup(agentCtx)` 钩子是唯一受支持的调用点。只有在那里,认父是在 agent 尚未发布时完成的,因此组装被拒绝会让整次创建回滚,而不会留下一个组装到一半的会话。常驻子树归 roster 服务自己的 fiber 所有——刻意用其未追踪的上下文,因为从被追踪的 `this.ctx` 派生的子树会经调用方的 shadow fiber 解析一切服务、无视各 entry 自己的 inject store——所以它比任何 agent 都活得久,只随整棵树卸载。每个代际记录其组装文件的 stamp(mtime 与大小):发现 stamp 过期的会话会开启下一个代际,而所有已加入的会话保持各自正在运行的那个——正在运行的会话所加入的组装在其文件被修改或删除后继续存活;文件是唯一的组装编辑器,stamp 正是把编辑送达后续会话的机制。 + +### 组装子 agent + +subagent 的子 agent 通过 `composeFrom()` 加入其父方的常驻组装,绝不走 `mount()`。所有面向模型的行都在 agent 平面,工具注册表的全局层是空的,因此没有加入任何组装的子 agent 抵达模型时既没有任何工具,也没有父方的任何提示段。 + +按 id 重新挂载父方的 preset 与认父有两处差别,且两处都要紧。父方启动后被编辑过的组装文件会把与父方历史所产出时**不同**的一个代际交给子 agent;而此后被删除的 preset 会让子 agent 直接失败,尽管其父方仍在正常运行。认父还是同步的,这正是进程内 subagent 驱动能够使用它的前提——它们在同步的创建窗口里组装子 agent。 + +子 agent 会把所加入的 id 记在自己的持久化 header 上(见 [`dsh-subagent`](../../subagent/subagent/README.md)),因此冷读子 agent 的历史时重建的是它实际运行过的组装,而不是部署默认值。 + +### 会话实际运行的是哪个 preset + +创建头部记录的是会话**以什么开始**,`resolveSessionPreset(session)` 给出的才是它**实际运行的**。空白会话一旦切换过,两者就不同,因此所有重建路径——选择器读取的摘要、resume、fork——都走解析,而非直接读头部。 + +头部保持冻结,因为它是创建期事实。切换以 `agent-preset/selected` 会话事件记录,在替换提交之后追加;这正是 model-visible ⟺ logged 规则的要求:preset 决定模型看到的工具 schema 与提示词段落,因此必须能从日志重建。服务会把这项已提交事实重新发为不带 scope 的 cordis 事件 `agent-preset/selected(sessionId, agentPreset)`,其声明位于 client-safe 的 `./types` 出口,使远端消费方无需导入 Host 运行时类型即可让会话派生状态失效。只读头部会让切换过的会话按创建时的组装重建,从而重放新工具集无法执行的历史——这正是「仅空白可切」那道锁要防的危险。 + +### 切换空白 agent + +`recompose()` 先卸载已装入的子树、再装入新的,因为两份组装无法共存——它们会把相同的工具名注册进同一个层。挂载失败会恢复先前的组装,而不是让 agent 一无所有;未知 id 则在任何东西被拆除之前就被拒绝。 + +"仅限尚未产出任何内容的 agent"是一条产品规则而非机制约束:在对话进行中调换工具,会留下新组装无法执行的、已被记录的工具调用。该规则由网关在传输层执行([`dsh-apiproxy`](../../host/apiproxy/README.md) 返回 `agent-preset-locked`),因为会话历史在那里才拿得到。 + +## 创作 + +创作即复制。新 preset 是某个既有 preset 的整目录副本——组装、元数据、skill 目录、附带资产——落在首个 `user` 根目录之下;输入只有两个由服务对照自身根目录解析的 id 加一个可选显示名,因此调用方从不提供组装文本,一次复制不会授予 roster 尚未携带的任何能力。创建之后的一切都发生在 preset 自己的文件里。`copy()` 在任何内容落盘之前拒绝三种情况: + +- **不符合 `[a-z0-9][a-z0-9-]*` 的 id。** id 会成为目录名,因此约束是 id 自身的性质,而非事后再做一次路径检查——`../escape`、`a/b` 与绝对路径都作为 id 被拒绝。 +- **已被占用的 id。** 复制从不覆写:任一根目录已提供该 id 即拒绝(与随附 preset 同名的用户目录只会被它遮蔽),磁盘上占着该名字的目录同样拒绝。发现过程会把这样的目录列为损坏的 preset,所以这条拒绝的出路——删掉它——就在报告它的同一页面上。 +- **未知的来源。** 来源可以是任何信任级别——复制随附 preset 正是主要用途——但必须存在;复制失败会回滚做到一半的目录,而不是留下一个 discovery 看不见的目录。 + +复制出的目录树被收紧为仅属主可用(文件 `0o600` 并保留属主执行位,目录 `0o700`),符号链接被解引用以保证副本自包含,且根目录在首次复制时创建——部署配置了尚不存在的用户根目录,正是首次运行的正常状态。复制出的 `preset.yml` 会被重写:保留来源的描述供作者就地编辑,但丢弃其名称与 roster `order`——副本若与来源呈现得一模一样、或按随附集合声明的顺序排序,roster 就不再能区分它们。`remove()` 拒绝随部署提供的 preset;随附集合正是副本的已知良好起点。 + +### preset 的各行如何解析 + +行的**包名**从宿主组装解析,而非从 preset 目录解析。Loader 通常按 entry 所属树的 `baseUrl` 解析,而对 preset 而言那就是组装文件所在之处;本地创作的 preset 位于用户主目录之下,Node 向上查找 `node_modules` 永远够不到 harness,因此每一个 `@deepseek-ai/dsh-*` 行都会导入失败。挂载在插入子树之前先记录宿主的基址,并把裸标识符送往那里。 + +**相对**路径仍从 preset 自身的目录解析,因此 preset 自带的插件文件与 skill 目录会随它一同迁移。 + +**绝对**文件系统路径则保留其自身位置。挂载会先将它转换为 `file:` URL 再交给 ESM 导入,从而使 POSIX 路径和 Windows 盘符或 UNC 路径都采用 Node 能够接受的说明符。 + +### 展示用元信息 + +preset 可以在组装文件旁的可选 `preset.yml` 里发布展示文本: + +```yaml +name: 极简模式 +description: 仅提供持久 bash 与 str_replace_editor 的双工具编码 Agent。 +``` + +它**只**承载展示文本。`id` 是目录名,`trust` 取自 preset 被发现时所在的根目录,两者都不可写在这里——否则本地创作的 preset 就能把自己命名进随附集合。之所以是独立文件:组装是插件行的顶层列表,YAML 无法在其旁携带同级键,而伪造一个元信息行等于递给 Loader 一个要加载的东西。 + +任何读取失败都退化为「没有元信息」——缺失、格式错误、类型不对、内容为空,含义相同,选择器回退到 id。展示不是能力:名字坏掉的 preset 依然能挂载。 + +## 配置 + +| 字段 | 默认值 | 含义 | +|---|---|---| +| `default` | 必填 | 调用方未指定时挂载的 preset id | +| `roots` | `[]` | 按优先级排列的扫描目录;每项提供 `path`(开头的 `~` 会展开)与 `trust`(默认为 `user`) | +| `includeUserRoot` | `true` | 在全部已配置根目录之后,追加 `/.agent-presets` 作为 `user` 根目录 | + +根目录不存在时视为不提供任何 preset,而非失败:用户根目录在写出第一个本地 preset 之前并不存在,而指定了没有任何根目录提供的默认值,在解析时本就会明确报错。 + +### 可写根目录属于本包,随附根目录属于 app + +`/.agent-presets` 是个人自有 preset 的所在,正如 `/skills` 是其自有 skill 的所在([`dsh-skill-filesystem`](../../skill/skill-filesystem/README.md)),因此 roster 自行推导它,而不等某个部署记得配置——一个什么都没配的启动器同样能发现并创作 preset。它追加在全部已配置根目录**之后**,从而保持靠前的根目录赢得重复 id:随附的 `standard` 仍然遮蔽一个占用该名字的家目录目录,而 `copy()` 会拒绝该 id,不会落下一个无人解析得到的 preset。 + +根目录在服务构造时解析一次。若根目录集合在一次 `list()` 与依据其答案执行的 `copy()` 之间发生变化,写入的将是调用方从未见过的目录。 + +`includeUserRoot: false` 使 roster 只覆盖 `roots`。把 preset 限制在自有目录内的部署需要它,任何钉住确切 roster 的测试同样需要——否则将由这台机器真实的 `` 决定 roster 的内容。 + +随附根目录仍然是装配事实:它位于已安装 app 自身配置的旁边,那个路径只有该 app 能解析。 + +### 默认 preset 是一项用户设置 + +当组装中存在 settings 提供方时,本插件会注册 `agent-presets` 命名空间,并以 `config.default` 作为其组装 base,因此用户文档会层叠覆盖部署方的工程默认值: + +```yaml +agent-presets: + default: minimal +``` + +该值在每次解析时读取而非快照,因此热重载的文档对**此后创建**的会话生效,而每个运行中的会话仍停留在它当初据以组装的 preset 上。清空用户字段即重新继承组装默认值。若默认值指向没有任何根目录提供的 preset,写入时不会报错,而在下一次 `resolve()` 时失败——名单是一个活动目录,此刻不存在的名字,等到某个会话真正索取时可能已经存在。 + +## 挂载会拒绝什么 + +直接挂载的子树不会出现在 `ctx.loader.entries()` 中,因此没有任何启动审计能覆盖它。`mount()` 因此自行校验结果可用,并拒绝三种情况。 + +**目标上下文没有 scope。** 挂载到不带 agent scope 的上下文,会把该 preset 的工具注册成全局的,作用于进程内每一个 agent。 + +**某一行始终未进入可用状态。** 模块导入失败或插件抛错的行,loader 已经会拒绝;剩下的情况是某一行仍在等待该组装从未提供的服务,审计会指名这种情况。 + +**某一行把服务发布进了根 realm。** 这类服务是进程级全局的,因此第二个发布同名服务的 preset 会与第一个相撞,宿主读取方也会把某一个 preset 的实例当成所有会话的。确实需要自带服务的 preset,应把它放在 `isolate` realm 之后——entry 本地 realm 让两个 preset 的同名服务互不相干,正如它从前隔开两个会话——否则该服务应改放进宿主组装。 + +最后一条规则由本包的运行时不变量在每次服务通知时复查,因为从定时器或异步续体中发布的行会绕过一次性审计。 + +## preset 文件是输入,不是持久化目标 + +只要 Loader 认为配置变了,它就会把树写回源文件——而一个行释放自己的 fiber 就足以让它这么认为:该 entry 被标记 `disabled`,随即触发写回。若继承该行为,一个会话的运行时状态就会被烧进所有会话共享的文件里:YAML 往返会抹掉注释,而对随附的只读 preset,`writeFile` 还会在 `setTimeout` 内抛出无人接管的 rejection。 + +因此被挂载的子树把 `write()` 覆写为空操作。本包不写任何组装;创作组装是另一件独立且显式的操作。 + +## 信任 + +preset 就是组装,因此一个 preset 的权限恰好等于它所引用的插件。`user` preset——无论由人还是由 agent 写出——与 shell 访问权限同级;`trust` 字段的存在是为了让消费方呈现这一差异,而不是用来强制隔离。 + +## 模型体验 + +Indirectly, through the plugins a standing composition registers, which own every tool schema and prompt section the preset makes visible to the agents joined to it. + +#### KV Cache effect + +在一个 agent 的整个生命周期内保持前缀稳定:组装只装入一次,发生在 agent 发布之前、因而也在它的首个请求之前,且在 agent 运行期间不再重新读取。为新会话选择不同的 preset,只会为该会话建立不同的前缀,无法让任何已在运行的会话失去缓存复用。 + +## 已知限制与暂缓事项 + +- **位于可写根目录之外的 preset 可被发现却无法删除** —— `remove()` 拒绝任何不在**第一个** `user` 根目录下的 preset,因此一个既配置了自有可写根、又保留 `includeUserRoot` 的部署,会列出并挂载 harness home 下的 preset,却对每次删除回答「它不在可写 preset 根目录之下」。roster 按设计只有一个可写根;只想要自有根的部署应设置 `includeUserRoot: false`。 +- **会话一旦产出内容便无法更换 preset** —— `recompose` 把**空白**会话的父作用域重链到另一个常驻挂载,且仅限空白会话:切换已运行过的组装会抽走模型已调用的工具。更改默认值只影响此后创建的会话。 +- **代际只以组装文件为键** —— stamp 检查只察觉 `agent.cordis.yml` 的变化,察觉不到旁边 skill 文件或资产的编辑;那些编辑要等组装文件本身变动或进程重启才达到新会话。 +- **被替代的代际永不回收** —— 已加入的会话保持其运行所在的代际,而名单没有加入计数可以判断最后一个何时离开,因此整棵子树一直挂到进程结束。代价按代际计而非按会话计,但并非为零:`dsh-skill-filesystem` 默认监听自己的根目录,因此每一轮「编辑后建会话」都会新增一套活的 watcher。上限取决于组装被编辑的频率——而设置页的编写流程把这件事从「每次部署」变成了「每次保存」。要回收就需要给常驻挂载加上已加入 agent 的计数;见 `ensureStanding` 处的 `TODO`。 +- **副本从不被实际挂载以校验** —— 它与来源逐字节相同,因此磁盘上已坏的来源会产出与来源同样损坏的副本;发现过程的健康检查会在下一次读取名单时把两行都标出来,而不是把失败推迟到会话启动。 +- **健康是形状检查,不是挂载** —— 发现过程只证明组装能以加载器方言解析、由具名行组成,不证明每一行的模块都能解析并激活;引用不存在的包的行仍在第一个会话处失败,并回滚该会话的创建。 +- **副本是会漂移的快照** —— 升级部署不会更新随附 preset 的副本,本层也没有表达「standard 加一处改动」的 patch 语义(那是 bundle 层 `cordis.patch.yml` 的能力);随附集合自己也接受同样的代价——`cordis` 与 `code` 就是 `standard` 的完整副本——换来整份组装在一个文件里可读。 +- **根目录扫描不做监听** —— 每次读取都实际访问文件系统,这让名单保持新鲜,但每次 `list()` 会对每个根目录产生一次 `readdir`。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/index.js new file mode 100644 index 0000000..c49f172 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/index.js @@ -0,0 +1,1178 @@ +import { chmod, cp, readFile, readdir, rm, stat } from "node:fs/promises"; +import { Context, Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { bindScopeParent, createScope, scopeOf, scopeParentOf } from "@deepseek-ai/dsh-scope"; +import { settingsNamespace } from "@deepseek-ai/dsh-settings"; +import { dshHomePath, expandHomePath } from "@deepseek-ai/dsh-home-paths"; +import { dirname, isAbsolute, join, resolve } from "node:path"; +import yaml, { load } from "js-yaml"; +import { Include, entryListSchema } from "@deepseek-ai/cordis-plugin-include"; +import { writeFileAtomic } from "@deepseek-ai/dsh-atomic-write"; +import { pathToFileURL } from "node:url"; +//#region lib/types/metadata.js +/** +* A preset's display metadata: the name and description a picker shows. +* +* It lives in its own file because the composition is a top-level list of +* plugin rows — YAML cannot carry sibling keys beside it, and faking a +* metadata row would hand the Loader something to load. Keeping it separate +* also keeps the composition exactly what its name says: a Cordis file the +* loader owns and the cordis preset can author. +* +* The file carries display text ONLY. `id` is the directory name and `trust` +* comes from the root a preset was discovered under, so neither is writable +* here — otherwise a locally authored preset could claim to be a shipped one. +* +* Every read failure degrades to no metadata. A preset whose display text is +* missing, malformed, or unreadable still mounts: presentation is not a +* capability, and a broken name must never become an agent that cannot start. +* @module @deepseek-ai/dsh-agent-presets/metadata +*/ +/** The optional display-metadata file beside a preset's composition. */ +const METADATA_FILE = "preset.yml"; +/** A non-empty trimmed string, or undefined for anything else. */ +function text(value) { + if (typeof value !== "string") return void 0; + const trimmed = value.trim(); + return trimmed === "" ? void 0 : trimmed; +} +/** +* Read one preset directory's display metadata. +* +* Absent, unparsable, and wrongly-shaped files are all the same answer — +* empty metadata — because the caller renders a picker, not a diagnostic. +* @param directory - the preset directory. +* @returns the display text the preset published, possibly empty. +*/ +async function readPresetMetadata(directory) { + let raw; + try { + raw = await readFile(join(directory, METADATA_FILE), "utf8"); + } catch { + return {}; + } + let parsed; + try { + parsed = yaml.load(raw); + } catch { + return {}; + } + if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {}; + const record = parsed; + const name = text(record.name); + const description = text(record.description); + const order = typeof record.order === "number" && Number.isFinite(record.order) ? record.order : void 0; + return { + ...name === void 0 ? {} : { name }, + ...description === void 0 ? {} : { description }, + ...order === void 0 ? {} : { order } + }; +} +/** +* Render display metadata as the file's contents. +* +* Absent fields are omitted rather than written empty, so a preset with no +* description does not ship a key that reads as an intentional blank. +* @param metadata - the display text to store. +* @returns the YAML document, or undefined when there is nothing to store. +*/ +function renderPresetMetadata(metadata) { + const name = text(metadata.name); + const description = text(metadata.description); + const { order } = metadata; + if (name === void 0 && description === void 0 && order === void 0) return void 0; + return yaml.dump({ + ...name === void 0 ? {} : { name }, + ...description === void 0 ? {} : { description }, + ...order === void 0 ? {} : { order } + }, { lineWidth: -1 }); +} +//#endregion +//#region lib/types/preset.js +/** Agent-preset vocabulary shared by discovery, mounting, and consumers. */ +/** +* Ids a preset directory may use. +* +* The id becomes a path segment, so this is a containment boundary rather than +* a style rule: `..`, a separator, or an absolute-looking name would place the +* composition outside the root the deployment authorised. Discovery shares it: +* a directory whose name no copy could ever claim is not a preset slot. +*/ +const PRESET_ID = /^[a-z0-9][a-z0-9-]*$/; +/** +* No configured root supplies the requested preset. +* +* Separate from a mount failure because the two mean different things to a +* caller: an unknown id is a bad request, while an unusable composition is a +* broken preset the deployment must fix. +*/ +var UnknownPresetError = class extends Error { + presetId; + available; + constructor(presetId, available) { + super(`agent-presets: preset "${presetId}" not found (available: ${available.join(", ") || "none"})`); + this.presetId = presetId; + this.available = available; + } +}; +/** A preset exists but its composition cannot be installed. */ +var PresetMountError = class extends Error { + presetId; + reason; + constructor(presetId, reason, options) { + super(`agent-presets: preset "${presetId}" failed to mount: ${reason}`, options); + this.presetId = presetId; + this.reason = reason; + } +}; +//#endregion +//#region lib/types/discovery.js +/** +* Filesystem discovery of agent presets. A preset is a directory holding +* {@link COMPOSITION_FILE}, optionally beside a {@link METADATA_FILE} carrying +* its display text; the directory name is the preset id. Discovery +* re-reads the roots on every call so a preset authored while the process is +* running is visible without a restart. +* +* Discovery also owns preset HEALTH: a directory whose composition is +* missing or unloadable is reported as a broken roster row rather than +* skipped. A skipped directory would still occupy its id on disk — the copy +* path refuses the name while no surface shows anything to delete — and a +* malformed composition would otherwise read as an ordinary preset until the +* first session fails to mount it. +* @module @deepseek-ai/dsh-agent-presets/discovery +*/ +/** The composition file that makes a directory a preset. */ +const COMPOSITION_FILE = "agent.cordis.yml"; +/** +* Harness-home directory holding locally authored presets. +* +* This package owns the writable root the way `dsh-skill-filesystem` owns +* `/skills`. An app must assemble the SHIPPED root, whose path only +* the installed app can resolve; where a person's own presets go is the same +* place in every deployment that does not say otherwise, so a launcher that +* forgets to configure one still finds them. +* +* Package-internal on purpose: no consumer outside this package addresses the +* directory by name, and a test that imported it could not catch this value +* being wrong — the expected segment is spelled out where it is asserted. +*/ +const USER_PRESET_DIR = ".agent-presets"; +/** +* Why `rows` cannot be an entry list, or undefined when it can. +* +* A shallow shape check, deliberately short of the loader's work: it does not +* resolve plugin names or apply configs. What it catches is the hand-edit +* that produces a file the loader cannot even begin with — and it must accept +* everything the loader accepts, which is why rows are only required to be +* maps carrying a plugin `name` (groups recurse into their own lists). +* @param rows - the parsed composition document. +* @param at - row-path prefix for nested diagnostics, empty at the top level. +* @returns one human-readable reason, or undefined when the shape holds. +*/ +function entryListProblem(rows, at = "") { + if (!Array.isArray(rows)) return at === "" ? "the composition must be a top-level list of plugin rows" : `group ${at} must hold a list of plugin rows`; + for (const [index, row] of rows.entries()) { + const label = at === "" ? `row ${String(index + 1)}` : `${at} row ${String(index + 1)}`; + if (typeof row !== "object" || row === null || Array.isArray(row)) return `${label} is not a plugin row (expected a map with a "name")`; + const { name, group, config } = row; + if (typeof name !== "string" || name === "") return `${label} names no plugin (a "name" string is required)`; + if (group === true) { + const nested = entryListProblem(config, label); + if (nested !== void 0) return nested; + } + } +} +/** +* Why the composition at `path` cannot mount, or undefined when it looks +* loadable. Parsed with the loader's own YAML dialect ({@link entryListSchema}, +* the one carrying `!!js`), so health can never call a composition broken +* that the loader would accept. +* @param path - absolute path of the composition file. +* @returns one human-readable reason, or undefined when the file is loadable. +*/ +async function compositionProblem(path) { + let content; + try { + content = await readFile(path, "utf8"); + } catch { + return `the composition file ${COMPOSITION_FILE} cannot be read`; + } + let rows; + try { + rows = load(content, { schema: entryListSchema }); + } catch (error) { + return `the composition is not valid YAML: ${(error instanceof Error ? error.message : String(error)).replace(/\n[\s\S]*$/, "")}`; + } + return entryListProblem(rows); +} +/** +* Whether `path` names an existing regular file. +* @param path - absolute path to test. +* @returns true when the path resolves to a file. +*/ +async function isFile(path) { + try { + return (await stat(path)).isFile(); + } catch { + return false; + } +} +/** +* Scan one root for preset directories. +* +* An absent root yields no presets rather than throwing: the user root does +* not exist until the first locally authored preset, and naming a default +* that no root supplies already fails loud at resolution. +* +* Every directory whose name is a usable preset id is a roster row — broken +* when its composition is missing or unloadable. A directory named outside +* {@link PRESET_ID} is skipped instead: no copy could ever claim that name, +* so it blocks nothing, and reporting `.DS_Store`-grade residue as broken +* presets would teach users to ignore the marker. +* @param root - the directory and the trust its presets inherit. +* @returns the root's presets ordered by id. +*/ +async function scanRoot(root) { + const dir = resolve(expandHomePath(root.path)); + let children; + try { + children = await readdir(dir, { withFileTypes: true }); + } catch (error) { + if (error.code === "ENOENT") return []; + throw new Error(`agent-presets: cannot read preset root ${dir}: ${String(error)}`, { cause: error }); + } + const found = []; + for (const child of children) { + if (!child.isDirectory() || !PRESET_ID.test(child.name)) continue; + const directory = join(dir, child.name); + const path = join(directory, COMPOSITION_FILE); + const broken = await isFile(path) ? await compositionProblem(path) : `the composition file ${COMPOSITION_FILE} is missing — the directory still occupies the id; delete it or restore the file`; + const metadata = await readPresetMetadata(directory); + found.push({ + id: child.name, + trust: root.trust, + path, + ...metadata, + ...broken === void 0 ? {} : { broken } + }); + } + return found.sort((left, right) => { + const byOrder = (left.order ?? Number.POSITIVE_INFINITY) - (right.order ?? Number.POSITIVE_INFINITY); + return byOrder === 0 ? left.id.localeCompare(right.id) : byOrder; + }); +} +/** +* Scan every root in precedence order. +* @param roots - roots in precedence order; an earlier root wins a duplicate id. +* @returns every discovered preset, first-root-wins per id. +*/ +async function discoverPresets(roots) { + const byId = /* @__PURE__ */ new Map(); + for (const root of roots) for (const preset of await scanRoot(root)) { + if (byId.has(preset.id)) continue; + byId.set(preset.id, preset); + } + return [...byId.values()]; +} +//#endregion +//#region lib/types/authoring.js +/** +* Copying, reading, and deleting locally authored presets. +* +* Authoring is confined to a `user` root: the shipped `.system` set is part of +* the deployment, and letting a browser rewrite it would turn "reset to a known +* preset" into something the same caller could have broken first. +* +* The only authoring write is a whole-directory copy of an existing preset. +* No caller supplies composition text: the inputs are ids the host resolves +* against its own roots plus an optional display name, so authoring grants no +* capability the copied preset did not already carry. +* @module @deepseek-ai/dsh-agent-presets/authoring +*/ +/** A preset id that cannot be used as a directory name under a root. */ +var InvalidPresetIdError = class extends Error { + presetId; + constructor(presetId) { + super(`agent-presets: preset id ${JSON.stringify(presetId)} must match ${String(PRESET_ID)} — the id is a directory name, so anything else could escape the preset root`); + this.presetId = presetId; + } +}; +/** A copy target that is already occupied — a copy never overwrites. */ +var PresetExistsError = class extends Error { + presetId; + constructor(presetId) { + super(`agent-presets: preset "${presetId}" already exists — a copy never overwrites; delete the existing preset first or choose another id`); + this.presetId = presetId; + } +}; +/** Authoring was attempted where the deployment allows none. */ +var PresetNotWritableError = class extends Error { + presetId; + constructor(presetId, reason) { + super(`agent-presets: preset "${presetId}" cannot be written: ${reason}`); + this.presetId = presetId; + } +}; +/** +* The root locally authored presets are written to. +* @param roots - the configured roots in precedence order. +* @returns the absolute path of the first `user` root. +* @throws when the deployment configured no writable root. +*/ +function writableRoot(roots) { + const root = roots.find((candidate) => candidate.trust === "user"); + if (root === void 0) throw new PresetNotWritableError("", "this deployment configures no user-writable preset root"); + return resolve(expandHomePath(root.path)); +} +/** +* Read one preset's composition text. +* @param preset - the resolved preset. +* @returns the file's contents. +*/ +async function readComposition(preset) { + return await readFile(preset.path, "utf8"); +} +/** Whether anything occupies the path (cp's own errorOnExist backstops races). */ +async function occupied(path) { + let present = true; + try { + await stat(path); + } catch { + present = false; + } + return present; +} +/** +* Re-tighten a copied tree to owner-only. A shipped preset is world-readable +* in its install and `cp` preserves that; the copy carries the same weight as +* the settings document beside it, so group/other access is stripped. A +* file's owner-execute bit survives — a preset may ship runnable helpers. +*/ +async function tightenModes(dir) { + await chmod(dir, 448); + for (const entry of await readdir(dir, { withFileTypes: true })) { + const target = join(dir, entry.name); + if (entry.isDirectory()) await tightenModes(target); + else + /* v8 ignore next -- Windows exposes no POSIX owner-execute bit; the POSIX lane covers both file modes. */ + await chmod(target, ((await stat(target)).mode & 64) === 0 ? 384 : 448); + } +} +/** +* Create a preset by copying an existing one's whole directory. +* +* The copy carries everything the source directory holds — composition, +* metadata, skill directories, assets — because a preset is its directory, +* not one file. Symlinks are dereferenced so the copy is self-contained +* rather than a set of links back into the install it was copied from. +* +* The copied metadata is then rewritten: the source's description is kept +* (the file is the author's to edit afterwards), but its name and roster +* `order` are not — a copy presenting itself identically to its source, or +* sorted into the shipped set's declared order, would make the roster stop +* distinguishing them. With no name given and no description to keep, the +* file is removed so the copy publishes nothing rather than a blank. +* @param roots - the configured roots; the first `user` one receives the copy. +* @param source - the resolved preset the copy starts from. +* @param id - the new preset's id, which becomes its directory name. +* @param name - display name for the copy; omitted falls back to the id. +* @returns the absolute path of the new preset directory. +* @throws when the id is unusable or already occupied on disk, or the +* deployment configures no writable root. +*/ +async function copyComposition(roots, source, id, name) { + if (!PRESET_ID.test(id)) throw new InvalidPresetIdError(id); + const dir = join(writableRoot(roots), id); + if (await occupied(dir)) throw new PresetExistsError(id); + try { + await cp(dirname(source.path), dir, { + recursive: true, + dereference: true, + force: false, + errorOnExist: true + }); + await tightenModes(dir); + const rendered = renderPresetMetadata({ + ...name === void 0 ? {} : { name }, + ...source.description === void 0 ? {} : { description: source.description } + }); + const metadataPath = join(dir, METADATA_FILE); + if (rendered === void 0) await rm(metadataPath, { force: true }); + else await writeFileAtomic(metadataPath, rendered, { + mode: 384, + dirMode: 448 + }); + } catch (error) { + await rm(dir, { + recursive: true, + force: true + }); + throw error; + } + return dir; +} +/** +* Delete a locally authored preset. +* +* A shipped preset is refused: it belongs to the deployment. A preset a live +* session mounted is NOT refused — the composition was read at creation and is +* never re-read, so that session keeps running exactly as it was. +* @param roots - the configured roots. +* @param preset - the resolved preset to remove. +* @throws when the preset ships with the deployment or lies outside the writable root. +*/ +async function deleteComposition(roots, preset) { + if (preset.trust !== "user") throw new PresetNotWritableError(preset.id, "it ships with the deployment"); + const dir = join(writableRoot(roots), preset.id); + if (!isAbsolute(preset.path) || !preset.path.startsWith(dir)) throw new PresetNotWritableError(preset.id, "it does not live under the writable preset root"); + await rm(dir, { + recursive: true, + force: true + }); +} +//#endregion +//#region lib/types/mount.js +/** +* Mount one preset composition under an agent's scope context, then prove the +* result is usable before the agent is published. +* +* The scope context is what makes the composition per-session: entry contexts +* chain to the context the subtree was plugged into, so every `ctx.tools` +* and `ctx.systemPrompt` registration inside the preset files into that +* agent's layer and unwinds with it. Two guards make that safe. A row that +* never reached a usable state is rejected, because a directly-plugged subtree +* is absent from `ctx.loader.entries()` and no boot audit covers it. A row that +* published a service into the ROOT realm is rejected, because such a service +* is process-global rather than per-session and the second session mounting the +* same preset collides with the first. +* @module @deepseek-ai/dsh-agent-presets/mount +*/ +/** +* Subtrees captured by config identity. A subtree plugged directly (rather than +* created as a loader entry) never links itself to an `Entry`, so this is the +* only handle to the rows it created; config objects are minted per mount, so +* concurrent mounts cannot collide. +*/ +const mounted = /* @__PURE__ */ new WeakMap(); +/** +* The base URL bare specifiers resolve against, per pending mount, keyed by the +* same config object. Recorded before the subtree is plugged, because `Include` +* rewrites its own context's `baseUrl` to the composition's directory and the +* pre-mount value is the only handle on where the harness itself lives. +*/ +const harnessBase = /* @__PURE__ */ new WeakMap(); +/** +* Include subclass that publishes its tree and fiber for the audit, and never +* writes to the file it read. +*/ +var PresetTree = class extends Include { + constructor(ctx, config) { + super(ctx, config); + mounted.set(config, { + tree: this, + fiber: ctx.fiber + }); + } + /** + * Resolve a bare specifier from the harness rather than from the preset. + * + * `EntryTree.import()` resolves against the tree's own `baseUrl`, which + * `Include` sets to the composition's directory. That is right for a + * relative specifier — a preset's own files travel with it — and wrong for + * a package name: a locally authored preset lives under the user's home, + * where Node's upward `node_modules` walk never reaches the harness's own + * dependencies, so every `@deepseek-ai/dsh-*` row would fail to import. The + * mount records the host composition's base instead, which is inside the + * installed harness, and bare names resolve from there. An absolute + * filesystem path names neither base and becomes a file URL before Node's + * ESM loader receives it, which is required for drive-letter paths on + * Windows. + * @param name - the module specifier from the row. + * @param getOuterStack - the loader's stack composer for import diagnostics. + * @returns the imported module, or the `cordis:` builtin. + */ + import(name, getOuterStack) { + const specifier = isAbsolute(name) ? pathToFileURL(name).href : name; + const base = harnessBase.get(this.config); + /* v8 ignore next -- every PresetTree is constructed by `mountPreset`, which records the base first */ + if (base === void 0) return super.import(specifier, getOuterStack); + if (name.startsWith(".") || name.startsWith("cordis:")) return super.import(name, getOuterStack); + const internal = this.ctx.loader.internal; + /* v8 ignore next -- Node always supplies the internal module loader; the branch keeps a + hypothetical embedder from losing the row's name in a resolution error. */ + if (internal === void 0) return super.import(specifier, getOuterStack); + return internal.import(specifier, base, {}); + } + /** + * A preset is an input, never a persistence target. + * + * The Loader writes a tree back through this method whenever it decides the + * config changed — a plugin self-disposing is enough, and tearing an agent + * down disposes its whole subtree. Inherited, that rewrites the preset file + * with whatever the dying tree held, which in practice means truncating a + * shipped composition to `[]` the first time a session ends. Persisting a + * preset is also meaningless: nothing here is user state, and the same file + * backs every session that names it. + * + * Dropping the write drops the `loader/config-update` the inherited method + * emits with it. Nothing observes one for a preset subtree today, and a + * future "edit your preset while it runs" flow needs a deliberate + * persistence path rather than this method's return. + */ + write() {} +}; +const mounts = /* @__PURE__ */ new Set(); +/** +* Drop every record whose subtree is gone. +* +* Records are pruned by observation rather than through a disposal hook +* because a subtree can be torn down by its owning agent, by a failed mount, or +* by the whole tree unloading, and a cleared `uid` is what all three share. +* +* Pruning therefore has to happen on a path this module owns. Reading is one +* such path, but not a reliable one: the only production reader is the +* invariant companion's service listener, and `dsh-invariants` is a +* development composition — a shipped host never loads it. Mounting is the +* other, and it is the one every session takes, which bounds the set at one +* generation of dead records rather than one per session ever composed. Each +* record would otherwise retain its whole disposed subtree: the fiber holds +* its config, and that config is the key its `EntryTree` is stored under. +*/ +function pruneDisposedMounts() { + for (const mount of mounts) if (mount.fiber.uid === null) mounts.delete(mount); +} +/** +* Every preset composition still installed, pruning fibers disposed since the +* last read. +* @returns the live mounts. +*/ +function livePresetMounts() { + pruneDisposedMounts(); + return [...mounts]; +} +/** +* Whether `fiber` is `root` itself or is mounted anywhere inside its subtree. +* +* Membership is object identity. `uid` looks like a cheaper key but is a +* per-registry counter, so fibers in two different roots collide on it and a +* subtree in one runtime would be blamed for a service published in another. +* @param fiber - the fiber to locate. +* @param root - the subtree root to test membership against. +* @returns true when `fiber` belongs to `root`'s subtree. +*/ +function withinFiber(fiber, root) { + let current = fiber; + while (true) { + if (current === root) return true; + const parent = current.parent.fiber; + if (parent === current) return false; + current = parent; + } +} +/** +* Service names the mounted subtree published into the root realm. +* +* A provider without an `isolate` realm stores its implementation under the +* root's symbol for that name, which is exactly the comparison below; a +* provider inside an `isolate` realm stores under a realm-private symbol and +* is correctly absent here. +* @param ctx - any context of the runtime whose service store is inspected. +* @param mount - the mounted subtree's fiber. +* @returns the leaked service names in lexical order. +*/ +function leakedServices(ctx, mount) { + const store = ctx.reflect.store; + const rootIsolate = ctx.root[Context.isolate]; + const leaked = []; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than + clearing it, so an own symbol always resolves; the guard exists only + because the store's index signature is optional. */ + if (impl === void 0) continue; + if (!withinFiber(impl.fiber, mount)) continue; + if (rootIsolate[impl.name] === key) leaked.push(impl.name); + } + return leaked.sort((left, right) => left.localeCompare(right)); +} +/** +* The standing composition one agent is joined to. +* +* The agent's own key is parented to its preset's standing key, so the mount +* is found by matching that parent rather than by walking up from the agent — +* the mount is not under the agent's fiber. An agent that joined no preset — +* a deployment composing no roster, or a child agent before its join — has no +* parent link and resolves to undefined. +* @param agentCtx - the agent's scope context. +* @returns the mount the agent joined, or undefined when it joined none. +*/ +function standingMountFor(agentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) return void 0; + const standingKey = scopeParentOf(agentKey); + if (standingKey === void 0) return void 0; + return livePresetMounts().find((candidate) => candidate.key === standingKey); +} +/** +* One agent's instance of a service its preset mounted. +* +* A preset publishes a service behind an `isolate` realm so two sessions +* cannot collide, and an entry-local realm is invisible to everything outside +* the group — including the agent's own scope context and the host. That is +* right for the rows inside the group and wrong for one caller: a request that +* is ABOUT a session but arrives from outside it, which is every browser RPC +* the api-proxy serves. +* +* Ownership is the same relation {@link leakedServices} reads, inverted: there +* it names implementations a subtree published into the ROOT realm, here it +* names the one this subtree published anywhere. Fiber membership is object +* identity for the reason stated on {@link withinFiber}. +* +* This is READ addressing for a caller that already holds the agent. It is not +* a general host handle on a session's internals: a host row that `inject`s a +* service cannot use it, because injection resolves before any session exists +* and has no agent to key by — such a service belongs on the host plane. +* @param ctx - any context of the runtime whose service store is inspected. +* @param agent - the agent whose mounted composition to look inside. +* @param name - the service name as the preset's rows resolve it. +* @returns the agent's instance, or undefined when its preset mounts none. +*/ +function serviceForAgent(ctx, agent, name) { + const mount = standingMountFor(agent.ctx); + if (mount === void 0) return void 0; + const store = ctx.reflect.store; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than clearing it */ + if (impl === void 0) continue; + if (impl.name !== name) continue; + if (withinFiber(impl.fiber, mount.fiber)) return impl.value; + } +} +/** +* Rows that did not reach a usable state, each rendered as one diagnostic line. +* +* A row whose module failed to import or whose plugin threw already rejects the +* mount through the loader; what remains observable here is a row still waiting +* for a service the composition never supplies. +* @param tree - the mounted subtree. +* @returns one line per unusable row, empty when every enabled row is usable. +*/ +function inactiveRows(tree) { + const lines = []; + for (const entry of tree.entries()) { + if (entry.disabled) continue; + const fiber = entry.fiber; + /* v8 ignore next 4 -- the loader rejects an entry whose module or plugin failed, + so a settled tree never holds an enabled fiber-less entry; the branch exists + only because `Entry.fiber` is declared optional. */ + if (fiber === void 0) { + lines.push(`${entry.options.id} (${entry.options.name}): never started`); + continue; + } + const missing = Object.keys(fiber.inject).filter((name) => fiber.ctx.get(name) === void 0); + if (missing.length > 0) lines.push(`${entry.options.id} (${entry.options.name}): waiting for ${missing.join(", ")}`); + } + return lines; +} +/** +* The reportable text of a mount failure. +* +* The loader reports several failed rows as one `AggregateError`, whose own +* message names none of them; without flattening, a composition that fails on +* two rows says only "loader entries failed to apply" and the operator has +* nothing to act on. +* @param error - the value the mount rejected with. +* @returns a single-line-per-cause description. +*/ +function mountDetail(error) { + /* v8 ignore next -- every path into the mount's catch throws an Error: the loader + wraps a row's thrown value before it propagates, and this module's own + rejections are Errors. The fallback keeps a hostile value readable. */ + if (!(error instanceof Error)) return String(error); + if (!(error instanceof AggregateError)) return error.message; + return [error.message, ...error.errors.map((cause) => `- ${mountDetail(cause)}`)].join("\n"); +} +/** +* Mount `preset` under `agentCtx` and return only once every row is usable. +* +* The subtree is owned by `agentCtx`'s fiber, so it unwinds with the agent and +* the caller receives no disposer. A rejection leaves nothing mounted. +* @param agentCtx - the agent's scope context, from the agent factory's `setup`. +* @param preset - the resolved preset to compose the agent from. +* @throws when `agentCtx` carries no scope, a row is unusable, or a row +* published a service into the root realm. +*/ +async function mountPreset(agentCtx, preset) { + if (scopeOf(agentCtx) === void 0) throw new Error(`agent-presets: refusing to mount preset "${preset.id}" into an unscoped context; its registrations would apply to every agent in the process`); + const config = { path: pathToFileURL(preset.path).href }; + /* v8 ignore next -- the Loader sets `baseUrl` on the root before any scoped context derives from it */ + if (agentCtx.baseUrl !== void 0) harnessBase.set(config, agentCtx.baseUrl); + pruneDisposedMounts(); + const handle = agentCtx.plugin(PresetTree, config); + try { + await handle.await(); + const subtree = mounted.get(config); + /* v8 ignore next -- the subclass constructor runs before `await()` settles for every mounted tree */ + if (subtree === void 0) throw new Error("mounted subtree did not publish its entry tree"); + const { tree, fiber } = subtree; + const unusable = inactiveRows(tree); + if (unusable.length > 0) throw new Error(`${String(unusable.length)} row(s) did not activate:\n${unusable.join("\n")}`); + const leaked = leakedServices(agentCtx, fiber); + if (leaked.length > 0) throw new Error(`row(s) published process-global service(s) [${leaked.join(", ")}]; a preset service must sit behind an \`isolate\` realm or move to the host composition`); + mounts.add({ + presetId: preset.id, + fiber, + key: scopeOf(agentCtx) + }); + } catch (error) { + try { + await handle.dispose(); + } catch {} + throw new PresetMountError(preset.id, `${mountDetail(error)} (${preset.path})`, { cause: error }); + } +} +//#endregion +//#region lib/types/session.js +/** +* The session-log record of which preset a session actually runs. +* +* The creation header names the preset a session STARTED with, and it is +* deep-frozen because that is a creation fact. A session may still change +* preset while it is blank, and the effect of that change outlives the blank +* window: the first turn — and every turn after it — runs under the newly +* mounted composition. Recording the change is what keeps the log honest, and +* it is required outright by the repo's model-visible ⟺ logged rule, since the +* preset decides the tool schemas and prompt sections the model sees. +* +* Reconstruction reads {@link resolveSessionPreset}, never the header alone. +* @module @deepseek-ai/dsh-agent-presets/session +*/ +/** +* The preset a session actually runs, newest selection winning. +* +* The header supplies the creation-time value; every later selection is a +* logged event, so the last one is the answer. Reading the header alone +* rebuilds a switched session under the composition it was created with, not +* the one its history was produced under. +* @param session - the session's header and event log. +* @returns the preset id, or `undefined` when the deployment composes none. +*/ +function resolveSessionPreset(session) { + for (let index = session.events.length - 1; index >= 0; index -= 1) { + const event = session.events[index]; + if (event?.type === "agent-preset/selected") return event.data.agentPreset; + } + return session.header.agentPreset; +} +//#endregion +//#region lib/types/index.js +/** +* Agent presets: each session composes its model-facing plugin set from one +* preset `cordis.yml`, mounted ONCE per preset under a standing scope and +* joined by every agent that names it. +* +* The standing mount is what makes a preset one composition rather than one +* per session: its plugin instances, tool registrations, prompt sections, and +* projection units exist exactly once, keyed per session inside the plugins +* themselves (they predate presets and were written for a shared world). An +* agent joins by having its scope key parented to the mount's +* ({@link bindScopeParent}), which makes the mount's registrations visible to +* that agent's views and the mount's listeners receive that agent's events — +* and a host reader with no agent at all (a cold transcript read) resolves +* the same standing registrations by preset id. +* +* This package owns the preset vocabulary, filesystem discovery, and the +* guarded standing mount. It does not decide when an agent is created — the +* agent factory's `setup(agentCtx)` hook is the one supported call site, +* because only there is the join installed while the agent is still +* unpublished, so a rejected composition rolls the whole creation back. +* @module @deepseek-ai/dsh-agent-presets +*/ +/** Settings namespace carrying the user's chosen default preset. */ +const SETTINGS_NAMESPACE = "agent-presets"; +/** Runtime schema for the user-writable slice. */ +const AgentPresetSettingsSchema = z.object({ default: z.string() }); +/** +* Registry over the deployment's agent presets. +* +* Discovery is unmemoized: `list()` and `resolve()` re-read the roots on every +* call so a preset authored while the process runs is visible immediately, +* and a preset deleted underneath a picker disappears from the next read. +*/ +var AgentPresets = class extends Service { + config; + static inject = ["loader"]; + /** Runtime schema for the preset roster. */ + static Config = z.object({ + default: z.string().required(), + roots: z.array(z.object({ + path: z.string().required(), + trust: z.union(["system", "user"]).default("user") + })).default([]), + includeUserRoot: z.boolean().default(true) + }); + /** + * The roots discovery and authoring actually scan: every configured root in + * order, then the harness-home user root unless `includeUserRoot` is false. + * + * Derived once, because a root set that changed between `list()` and the + * `copy()` acting on its answer would author into a directory the caller + * never saw. Appending rather than prepending keeps an earlier configured + * root winning a duplicate id, so a shipped preset still shadows a + * locally authored directory that claimed its name. + */ + resolvedRoots; + /** + * The user layer over `config.default`, present only while a settings + * provider is composed. Held rather than snapshotted so a hot-reloaded + * document takes effect without a restart. + */ + settings; + /** + * The settings service behind {@link settings}, held for the one write this + * service makes: clearing a user default it has just deleted. + */ + settingsService; + /** + * The service's own untraced context. Methods invoked through the traceable + * proxy see `this.ctx` rebound to the CALLER's context, which carries a + * shadow; a subtree minted from it resolves every service through that + * shadow's fiber instead of each entry's own inject store, so preset rows + * would fail on the very services they declare. Standing mounts must hang + * off the untraced original (the `jobs-local` selfCtx precedent). + */ + selfCtx; + constructor(ctx, config) { + super(ctx, "agentPresets"); + this.config = config; + this.selfCtx = ctx; + this.resolvedRoots = config.includeUserRoot ? [...config.roots, { + path: dshHomePath(USER_PRESET_DIR), + trust: "user" + }] : [...config.roots]; + ctx.inject(["settings"], (settingsCtx) => { + this.settings = settingsCtx.settings.register(settingsNamespace(SETTINGS_NAMESPACE), AgentPresetSettingsSchema, { base: { default: config.default } }); + this.settingsService = settingsCtx.settings; + settingsCtx.effect(() => () => { + this.settings = void 0; + this.settingsService = void 0; + }, "agentPresets.settings()"); + }); + ctx.on("agent/created", ({ agent }) => { + if (this.resolvedRoots.length === 0) return; + if (this.composedPreset(agent.ctx) !== void 0) return; + ctx.logger.warn(`agent "${agent.id}" was published without joining an agent preset; its tools, prompt sections, and skill catalog resolve against the empty global layer (join through AgentPresets.mount() or composeFrom() in the agent factory setup)`); + }); + ctx.on("session/event", (session, event) => { + if (event.type !== "agent-preset/selected") return; + ctx.emit("agent-preset/selected", session.id, event.data.agentPreset); + }); + } + /** + * The preset id mounted when a caller names none. + * + * Read per call rather than cached: the settings document is hot-reloaded, so + * changing the default takes effect on the next session created and leaves + * every running session on the preset it was composed from. + */ + get defaultId() { + return this.settings?.get().default ?? this.config.default; + } + /** + * Every preset the configured roots currently supply. + * @returns the presets, first-root-wins per id. + */ + async list() { + return await discoverPresets(this.resolvedRoots); + } + /** + * Resolve one preset by id. + * + * A broken preset resolves — deleting one, reading one, and reporting one + * all need the row — and the mounting paths refuse it AFTER resolution + * through {@link resolveMountable}. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved preset. + * @throws when no configured root supplies that id. + */ + async resolve(id) { + const wanted = id ?? this.defaultId; + const presets = await this.list(); + const found = presets.find((preset) => preset.id === wanted); + if (found === void 0) throw new UnknownPresetError(wanted, presets.map((preset) => preset.id)); + return found; + } + /** + * Resolve one preset that is about to compose an agent, refusing a broken + * one with its discovery-reported reason. Failing here rather than inside + * the loader keeps the answer the same for every unloadable shape — ghost + * directory, unparsable YAML, rowless list — and spends no mount attempt + * on a composition discovery already read as unusable. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved, mountable preset. + * @throws when the preset is unknown or discovery reports it broken. + */ + async resolveMountable(id) { + const preset = await this.resolve(id); + if (preset.broken !== void 0) throw new PresetMountError(preset.id, preset.broken); + return preset; + } + /** + * Standing mounts by preset id, single-flight so two agents racing the + * first use of one preset share one composition. A settled failure is + * removed so a later session retries a preset whose file has been fixed; a + * settled success serves until the composition FILE visibly changes — each + * generation records its file stamp, and a stale stamp starts the next + * generation for sessions created afterwards. Sessions already joined keep + * the generation they run on; a superseded one is never disposed while the + * process lives (reclaimed only by whole-tree teardown), so editing files + * is bounded by how often compositions change, not by session count. + */ + standing = /* @__PURE__ */ new Map(); + /** + * Parent bindings of the agents this roster composed, keyed by the agent's + * scope key. The binding is dsh-scope's only re-link capability; holding it + * here makes this service the sole authority that can move an agent between + * standing compositions. WeakMap: entries die with their agents. + */ + bindings = /* @__PURE__ */ new WeakMap(); + /** + * Compose one agent from a preset: ensure the preset's standing mount, then + * parent the agent's scope key to it so the mount's registrations and + * listeners cover this agent. + * + * Call from the agent factory's `setup(agentCtx)`; a rejection there rolls + * the agent creation back, so a broken preset never yields a half-composed + * session. + * @param agentCtx - the agent's scope context. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the preset that was composed, for the caller to record. + * @throws when the preset is unknown or its composition is unusable. + */ + async mount(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset"); + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return preset; + } + /** + * Join one agent to the SAME standing composition another already runs on. + * + * This is how a child agent inherits its parent's capabilities. It is a bind, + * not a mount: the parent's generation is already composed, so the child gets + * that exact instance — the same plugin objects, the same tool registrations, + * the same prompt sections. Re-resolving the parent's preset by id instead + * would re-read the roster, and a composition file edited since the parent + * started would hand the child a DIFFERENT generation than the one its + * parent's history was produced under (and a preset deleted since would fail + * the child outright while its parent keeps running). + * + * Synchronous, and with no composition failure mode of its own — it reads no + * roster, mounts nothing, and touches no file — which is what lets a child + * creation window use it: the two in-process subagent drivers compose their + * children inside a synchronous `setup`. It still rejects a caller error, as + * the `@throws` below record. + * + * A parent that joined no preset — a rosterless deployment — yields no join + * and no error: there, the model-facing rows sit in the host composition and + * the child already sees them through the global layer. + * @param agentCtx - the joining agent's scope context. + * @param parentCtx - the scope context of the agent whose composition to join. + * @returns the preset id joined, or undefined when the parent joined none. + * @throws when `agentCtx` carries no scope, or has already joined a preset. + */ + composeFrom(agentCtx, parentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset"); + const standing = standingMountFor(parentCtx); + if (standing === void 0) return void 0; + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return standing.presetId; + } + /** + * The preset one live agent runs on. + * + * Read from the live scope chain rather than from the session, so it answers + * for an agent whose session has not recorded a preset yet — a child agent + * whose durable header is being built from its parent's composition. + * @param agentCtx - the agent's scope context. + * @returns the preset id, or undefined when the agent joined none. + */ + composedPreset(agentCtx) { + return standingMountFor(agentCtx)?.presetId; + } + /** + * The roots this roster scans, which is not `config.roots`: it is every + * configured root in order, then the harness-home user root unless + * `includeUserRoot` is false. Read this — not the config field — to answer + * whether a roster is composed at all, so one derivation decides it. + */ + get roots() { + return this.resolvedRoots; + } + /** Whether this deployment has a root locally authored presets go to. */ + get authorable() { + return this.resolvedRoots.some((root) => root.trust === "user"); + } + /** + * Read one preset's composition text. + * @param id - the preset id. + * @returns the composition exactly as stored. + * @throws when no configured root supplies that id. + */ + async read(id) { + return await readComposition(await this.resolve(id)); + } + /** + * Create a locally authored preset by copying an existing one whole. + * + * Copy is the only authoring write. Composition text never crosses this + * seam: the source is named by id and its directory is copied as it stands, + * so the copy is exactly as loadable as its source and authoring grants no + * capability the roster did not already carry. The copy is NOT mounted to + * validate — a source that mounts today yields a copy that mounts today. + * @param from - the preset the copy starts from; shipped presets are the + * primary source, so any trust is accepted. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; absent falls back to the id. + * @throws when the source is unknown, the id is unusable or already taken, + * or the deployment configures no writable root. + */ + async copy(from, id, name) { + const source = await this.resolve(from); + if ((await this.list()).some((preset) => preset.id === id)) throw new PresetExistsError(id); + await copyComposition(this.resolvedRoots, source, id, name); + this.standing.delete(id); + } + /** + * Delete a locally authored preset. + * @param id - the preset id. + * @throws when the preset is unknown or ships with the deployment. + */ + async remove(id) { + await deleteComposition(this.resolvedRoots, await this.resolve(id)); + this.standing.delete(id); + if (this.settings?.get().default !== id) return; + await this.settingsService?.mutate(settingsNamespace(SETTINGS_NAMESPACE), [{ + op: "unset", + path: ["default"] + }]); + } + /** + * One agent's instance of a service its preset mounted. + * + * A preset publishes services behind `isolate` realms, which are invisible + * outside the group that declares them — including to the host. This is how a + * caller holding the agent reads one anyway: a request that is ABOUT a + * session but arrives from outside it, which is every browser RPC. + * + * Read addressing only. A host row that `inject`s a service cannot use this, + * because injection resolves before any session exists and has no agent to + * key by; such a service belongs on the host plane instead. + * @param agent - the agent whose composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ + serviceFor(agent, name) { + return serviceForAgent(this.ctx, agent, name); + } + /** + * Re-link one agent to a different preset's standing composition. + * + * Only valid while the agent has produced nothing: swapping tools mid + * conversation would leave logged tool calls the new composition cannot + * make. The CALLER owns that check — this method does not read session + * history. + * + * The swap is a parent re-link, not an unmount: standing mounts are shared + * and permanent, so the old composition stays for its other agents and the + * new one is ensured BEFORE the link moves. An unknown or unusable preset + * therefore throws with the agent exactly as it was — there is no torn-down + * state to restore. The re-link runs through the binding this roster kept + * from the agent's mount — dsh-scope's only re-link authority. An agent + * that never composed one has nothing to re-link: the switch is then the + * agent's first bind, exactly a mount. + * @param agentCtx - the agent's scope context. + * @param id - the preset to compose the agent from instead. + * @returns the preset now installed. + * @throws when the preset is unknown or its composition is unusable. + */ + async recompose(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to recompose an unscoped context"); + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + const binding = this.bindings.get(agentKey); + if (binding === void 0) this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + else binding.rebind(standing.key); + return preset; + } + /** + * The standing scope key of one preset, for a host reader with no agent. + * + * A cold transcript read resolves tool presenters against the composition + * the session recorded, and the standing mount makes that possible without + * resuming anything: ensuring the mount composes plugins but starts no + * agent, no session, and no turn. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the standing scope key readers pass as a registry view scope. + * @throws when the preset is unknown or its composition is unusable. + */ + async standingKeyFor(id) { + const preset = await this.resolveMountable(id); + return (await this.ensureStanding(preset)).key; + } + /** Resolve (or create, single-flight) the standing mount of one preset. */ + async ensureStanding(preset) { + const pending = this.standing.get(preset.id); + if (pending !== void 0) { + const mounted = await pending; + const current = await compositionStamp(preset.path); + if (current === void 0 || sameStamp(mounted.stamp, current)) return mounted; + if (this.standing.get(preset.id) === pending) this.standing.delete(preset.id); + return this.ensureStanding(preset); + } + const created = (async () => { + const key = { agentPreset: preset.id }; + const scope = createScope(this.selfCtx, key); + try { + const stamp = await compositionStamp(preset.path); + if (stamp === void 0) throw new PresetMountError(preset.id, `composition file is unreadable: ${preset.path}`); + await mountPreset(scope.ctx, preset); + return { + key, + scope, + stamp + }; + } catch (error) { + this.standing.delete(preset.id); + await scope.dispose(); + throw error; + } + })(); + this.standing.set(preset.id, created); + return created; + } +}; +/** Read one composition file's stamp, or undefined when it cannot be statted. */ +async function compositionStamp(path) { + try { + const { mtimeMs, size } = await stat(path); + return { + mtimeMs, + size + }; + } catch { + return; + } +} +/** Whether two stamps name the same file state. */ +function sameStamp(a, b) { + return a.mtimeMs === b.mtimeMs && a.size === b.size; +} +//#endregion +export { AgentPresetSettingsSchema, AgentPresets, AgentPresets as default, COMPOSITION_FILE, InvalidPresetIdError, METADATA_FILE, PresetExistsError, PresetMountError, PresetNotWritableError, SETTINGS_NAMESPACE, UnknownPresetError, copyComposition, deleteComposition, discoverPresets, inactiveRows, leakedServices, livePresetMounts, mountPreset, readComposition, readPresetMetadata, renderPresetMetadata, resolveSessionPreset, scanRoot, serviceForAgent, standingMountFor, writableRoot }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/invariant.js new file mode 100644 index 0000000..107adfc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/invariant.js @@ -0,0 +1,1178 @@ +import { chmod, cp, readFile, readdir, rm, stat } from "node:fs/promises"; +import { Context, Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { bindScopeParent, createScope, scopeOf, scopeParentOf } from "@deepseek-ai/dsh-scope"; +import { settingsNamespace } from "@deepseek-ai/dsh-settings"; +import { dshHomePath, expandHomePath } from "@deepseek-ai/dsh-home-paths"; +import { dirname, isAbsolute, join, resolve } from "node:path"; +import yaml, { load } from "js-yaml"; +import { Include, entryListSchema } from "@deepseek-ai/cordis-plugin-include"; +import { writeFileAtomic } from "@deepseek-ai/dsh-atomic-write"; +import { pathToFileURL } from "node:url"; +//#region src/metadata.ts +/** +* A preset's display metadata: the name and description a picker shows. +* +* It lives in its own file because the composition is a top-level list of +* plugin rows — YAML cannot carry sibling keys beside it, and faking a +* metadata row would hand the Loader something to load. Keeping it separate +* also keeps the composition exactly what its name says: a Cordis file the +* loader owns and the cordis preset can author. +* +* The file carries display text ONLY. `id` is the directory name and `trust` +* comes from the root a preset was discovered under, so neither is writable +* here — otherwise a locally authored preset could claim to be a shipped one. +* +* Every read failure degrades to no metadata. A preset whose display text is +* missing, malformed, or unreadable still mounts: presentation is not a +* capability, and a broken name must never become an agent that cannot start. +* @module @deepseek-ai/dsh-agent-presets/metadata +*/ +/** The optional display-metadata file beside a preset's composition. */ +const METADATA_FILE = "preset.yml"; +/** A non-empty trimmed string, or undefined for anything else. */ +function text(value) { + if (typeof value !== "string") return void 0; + const trimmed = value.trim(); + return trimmed === "" ? void 0 : trimmed; +} +/** +* Read one preset directory's display metadata. +* +* Absent, unparsable, and wrongly-shaped files are all the same answer — +* empty metadata — because the caller renders a picker, not a diagnostic. +* @param directory - the preset directory. +* @returns the display text the preset published, possibly empty. +*/ +async function readPresetMetadata(directory) { + let raw; + try { + raw = await readFile(join(directory, METADATA_FILE), "utf8"); + } catch { + return {}; + } + let parsed; + try { + parsed = yaml.load(raw); + } catch { + return {}; + } + if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {}; + const record = parsed; + const name = text(record.name); + const description = text(record.description); + const order = typeof record.order === "number" && Number.isFinite(record.order) ? record.order : void 0; + return { + ...name === void 0 ? {} : { name }, + ...description === void 0 ? {} : { description }, + ...order === void 0 ? {} : { order } + }; +} +/** +* Render display metadata as the file's contents. +* +* Absent fields are omitted rather than written empty, so a preset with no +* description does not ship a key that reads as an intentional blank. +* @param metadata - the display text to store. +* @returns the YAML document, or undefined when there is nothing to store. +*/ +function renderPresetMetadata(metadata) { + const name = text(metadata.name); + const description = text(metadata.description); + const { order } = metadata; + if (name === void 0 && description === void 0 && order === void 0) return void 0; + return yaml.dump({ + ...name === void 0 ? {} : { name }, + ...description === void 0 ? {} : { description }, + ...order === void 0 ? {} : { order } + }, { lineWidth: -1 }); +} +//#endregion +//#region src/preset.ts +/** +* Ids a preset directory may use. +* +* The id becomes a path segment, so this is a containment boundary rather than +* a style rule: `..`, a separator, or an absolute-looking name would place the +* composition outside the root the deployment authorised. Discovery shares it: +* a directory whose name no copy could ever claim is not a preset slot. +*/ +const PRESET_ID = /^[a-z0-9][a-z0-9-]*$/; +/** +* No configured root supplies the requested preset. +* +* Separate from a mount failure because the two mean different things to a +* caller: an unknown id is a bad request, while an unusable composition is a +* broken preset the deployment must fix. +*/ +var UnknownPresetError = class extends Error { + presetId; + available; + constructor(presetId, available) { + super(`agent-presets: preset "${presetId}" not found (available: ${available.join(", ") || "none"})`); + this.presetId = presetId; + this.available = available; + } +}; +/** A preset exists but its composition cannot be installed. */ +var PresetMountError = class extends Error { + presetId; + reason; + constructor(presetId, reason, options) { + super(`agent-presets: preset "${presetId}" failed to mount: ${reason}`, options); + this.presetId = presetId; + this.reason = reason; + } +}; +//#endregion +//#region src/discovery.ts +/** +* Filesystem discovery of agent presets. A preset is a directory holding +* {@link COMPOSITION_FILE}, optionally beside a {@link METADATA_FILE} carrying +* its display text; the directory name is the preset id. Discovery +* re-reads the roots on every call so a preset authored while the process is +* running is visible without a restart. +* +* Discovery also owns preset HEALTH: a directory whose composition is +* missing or unloadable is reported as a broken roster row rather than +* skipped. A skipped directory would still occupy its id on disk — the copy +* path refuses the name while no surface shows anything to delete — and a +* malformed composition would otherwise read as an ordinary preset until the +* first session fails to mount it. +* @module @deepseek-ai/dsh-agent-presets/discovery +*/ +/** The composition file that makes a directory a preset. */ +const COMPOSITION_FILE = "agent.cordis.yml"; +/** +* Harness-home directory holding locally authored presets. +* +* This package owns the writable root the way `dsh-skill-filesystem` owns +* `/skills`. An app must assemble the SHIPPED root, whose path only +* the installed app can resolve; where a person's own presets go is the same +* place in every deployment that does not say otherwise, so a launcher that +* forgets to configure one still finds them. +* +* Package-internal on purpose: no consumer outside this package addresses the +* directory by name, and a test that imported it could not catch this value +* being wrong — the expected segment is spelled out where it is asserted. +*/ +const USER_PRESET_DIR = ".agent-presets"; +/** +* Why `rows` cannot be an entry list, or undefined when it can. +* +* A shallow shape check, deliberately short of the loader's work: it does not +* resolve plugin names or apply configs. What it catches is the hand-edit +* that produces a file the loader cannot even begin with — and it must accept +* everything the loader accepts, which is why rows are only required to be +* maps carrying a plugin `name` (groups recurse into their own lists). +* @param rows - the parsed composition document. +* @param at - row-path prefix for nested diagnostics, empty at the top level. +* @returns one human-readable reason, or undefined when the shape holds. +*/ +function entryListProblem(rows, at = "") { + if (!Array.isArray(rows)) return at === "" ? "the composition must be a top-level list of plugin rows" : `group ${at} must hold a list of plugin rows`; + for (const [index, row] of rows.entries()) { + const label = at === "" ? `row ${String(index + 1)}` : `${at} row ${String(index + 1)}`; + if (typeof row !== "object" || row === null || Array.isArray(row)) return `${label} is not a plugin row (expected a map with a "name")`; + const { name, group, config } = row; + if (typeof name !== "string" || name === "") return `${label} names no plugin (a "name" string is required)`; + if (group === true) { + const nested = entryListProblem(config, label); + if (nested !== void 0) return nested; + } + } +} +/** +* Why the composition at `path` cannot mount, or undefined when it looks +* loadable. Parsed with the loader's own YAML dialect ({@link entryListSchema}, +* the one carrying `!!js`), so health can never call a composition broken +* that the loader would accept. +* @param path - absolute path of the composition file. +* @returns one human-readable reason, or undefined when the file is loadable. +*/ +async function compositionProblem(path) { + let content; + try { + content = await readFile(path, "utf8"); + } catch { + return `the composition file ${COMPOSITION_FILE} cannot be read`; + } + let rows; + try { + rows = load(content, { schema: entryListSchema }); + } catch (error) { + return `the composition is not valid YAML: ${(error instanceof Error ? error.message : String(error)).replace(/\n[\s\S]*$/, "")}`; + } + return entryListProblem(rows); +} +/** +* Whether `path` names an existing regular file. +* @param path - absolute path to test. +* @returns true when the path resolves to a file. +*/ +async function isFile(path) { + try { + return (await stat(path)).isFile(); + } catch { + return false; + } +} +/** +* Scan one root for preset directories. +* +* An absent root yields no presets rather than throwing: the user root does +* not exist until the first locally authored preset, and naming a default +* that no root supplies already fails loud at resolution. +* +* Every directory whose name is a usable preset id is a roster row — broken +* when its composition is missing or unloadable. A directory named outside +* {@link PRESET_ID} is skipped instead: no copy could ever claim that name, +* so it blocks nothing, and reporting `.DS_Store`-grade residue as broken +* presets would teach users to ignore the marker. +* @param root - the directory and the trust its presets inherit. +* @returns the root's presets ordered by id. +*/ +async function scanRoot(root) { + const dir = resolve(expandHomePath(root.path)); + let children; + try { + children = await readdir(dir, { withFileTypes: true }); + } catch (error) { + if (error.code === "ENOENT") return []; + throw new Error(`agent-presets: cannot read preset root ${dir}: ${String(error)}`, { cause: error }); + } + const found = []; + for (const child of children) { + if (!child.isDirectory() || !PRESET_ID.test(child.name)) continue; + const directory = join(dir, child.name); + const path = join(directory, COMPOSITION_FILE); + const broken = await isFile(path) ? await compositionProblem(path) : `the composition file ${COMPOSITION_FILE} is missing — the directory still occupies the id; delete it or restore the file`; + const metadata = await readPresetMetadata(directory); + found.push({ + id: child.name, + trust: root.trust, + path, + ...metadata, + ...broken === void 0 ? {} : { broken } + }); + } + return found.sort((left, right) => { + const byOrder = (left.order ?? Number.POSITIVE_INFINITY) - (right.order ?? Number.POSITIVE_INFINITY); + return byOrder === 0 ? left.id.localeCompare(right.id) : byOrder; + }); +} +/** +* Scan every root in precedence order. +* @param roots - roots in precedence order; an earlier root wins a duplicate id. +* @returns every discovered preset, first-root-wins per id. +*/ +async function discoverPresets(roots) { + const byId = /* @__PURE__ */ new Map(); + for (const root of roots) for (const preset of await scanRoot(root)) { + if (byId.has(preset.id)) continue; + byId.set(preset.id, preset); + } + return [...byId.values()]; +} +//#endregion +//#region src/authoring.ts +/** +* Copying, reading, and deleting locally authored presets. +* +* Authoring is confined to a `user` root: the shipped `.system` set is part of +* the deployment, and letting a browser rewrite it would turn "reset to a known +* preset" into something the same caller could have broken first. +* +* The only authoring write is a whole-directory copy of an existing preset. +* No caller supplies composition text: the inputs are ids the host resolves +* against its own roots plus an optional display name, so authoring grants no +* capability the copied preset did not already carry. +* @module @deepseek-ai/dsh-agent-presets/authoring +*/ +/** A preset id that cannot be used as a directory name under a root. */ +var InvalidPresetIdError = class extends Error { + presetId; + constructor(presetId) { + super(`agent-presets: preset id ${JSON.stringify(presetId)} must match ${String(PRESET_ID)} — the id is a directory name, so anything else could escape the preset root`); + this.presetId = presetId; + } +}; +/** A copy target that is already occupied — a copy never overwrites. */ +var PresetExistsError = class extends Error { + presetId; + constructor(presetId) { + super(`agent-presets: preset "${presetId}" already exists — a copy never overwrites; delete the existing preset first or choose another id`); + this.presetId = presetId; + } +}; +/** Authoring was attempted where the deployment allows none. */ +var PresetNotWritableError = class extends Error { + presetId; + constructor(presetId, reason) { + super(`agent-presets: preset "${presetId}" cannot be written: ${reason}`); + this.presetId = presetId; + } +}; +/** +* The root locally authored presets are written to. +* @param roots - the configured roots in precedence order. +* @returns the absolute path of the first `user` root. +* @throws when the deployment configured no writable root. +*/ +function writableRoot(roots) { + const root = roots.find((candidate) => candidate.trust === "user"); + if (root === void 0) throw new PresetNotWritableError("", "this deployment configures no user-writable preset root"); + return resolve(expandHomePath(root.path)); +} +/** +* Read one preset's composition text. +* @param preset - the resolved preset. +* @returns the file's contents. +*/ +async function readComposition(preset) { + return await readFile(preset.path, "utf8"); +} +/** Whether anything occupies the path (cp's own errorOnExist backstops races). */ +async function occupied(path) { + let present = true; + try { + await stat(path); + } catch { + present = false; + } + return present; +} +/** +* Re-tighten a copied tree to owner-only. A shipped preset is world-readable +* in its install and `cp` preserves that; the copy carries the same weight as +* the settings document beside it, so group/other access is stripped. A +* file's owner-execute bit survives — a preset may ship runnable helpers. +*/ +async function tightenModes(dir) { + await chmod(dir, 448); + for (const entry of await readdir(dir, { withFileTypes: true })) { + const target = join(dir, entry.name); + if (entry.isDirectory()) await tightenModes(target); + else + /* v8 ignore next -- Windows exposes no POSIX owner-execute bit; the POSIX lane covers both file modes. */ + await chmod(target, ((await stat(target)).mode & 64) === 0 ? 384 : 448); + } +} +/** +* Create a preset by copying an existing one's whole directory. +* +* The copy carries everything the source directory holds — composition, +* metadata, skill directories, assets — because a preset is its directory, +* not one file. Symlinks are dereferenced so the copy is self-contained +* rather than a set of links back into the install it was copied from. +* +* The copied metadata is then rewritten: the source's description is kept +* (the file is the author's to edit afterwards), but its name and roster +* `order` are not — a copy presenting itself identically to its source, or +* sorted into the shipped set's declared order, would make the roster stop +* distinguishing them. With no name given and no description to keep, the +* file is removed so the copy publishes nothing rather than a blank. +* @param roots - the configured roots; the first `user` one receives the copy. +* @param source - the resolved preset the copy starts from. +* @param id - the new preset's id, which becomes its directory name. +* @param name - display name for the copy; omitted falls back to the id. +* @returns the absolute path of the new preset directory. +* @throws when the id is unusable or already occupied on disk, or the +* deployment configures no writable root. +*/ +async function copyComposition(roots, source, id, name) { + if (!PRESET_ID.test(id)) throw new InvalidPresetIdError(id); + const dir = join(writableRoot(roots), id); + if (await occupied(dir)) throw new PresetExistsError(id); + try { + await cp(dirname(source.path), dir, { + recursive: true, + dereference: true, + force: false, + errorOnExist: true + }); + await tightenModes(dir); + const rendered = renderPresetMetadata({ + ...name === void 0 ? {} : { name }, + ...source.description === void 0 ? {} : { description: source.description } + }); + const metadataPath = join(dir, METADATA_FILE); + if (rendered === void 0) await rm(metadataPath, { force: true }); + else await writeFileAtomic(metadataPath, rendered, { + mode: 384, + dirMode: 448 + }); + } catch (error) { + await rm(dir, { + recursive: true, + force: true + }); + throw error; + } + return dir; +} +/** +* Delete a locally authored preset. +* +* A shipped preset is refused: it belongs to the deployment. A preset a live +* session mounted is NOT refused — the composition was read at creation and is +* never re-read, so that session keeps running exactly as it was. +* @param roots - the configured roots. +* @param preset - the resolved preset to remove. +* @throws when the preset ships with the deployment or lies outside the writable root. +*/ +async function deleteComposition(roots, preset) { + if (preset.trust !== "user") throw new PresetNotWritableError(preset.id, "it ships with the deployment"); + const dir = join(writableRoot(roots), preset.id); + if (!isAbsolute(preset.path) || !preset.path.startsWith(dir)) throw new PresetNotWritableError(preset.id, "it does not live under the writable preset root"); + await rm(dir, { + recursive: true, + force: true + }); +} +//#endregion +//#region src/mount.ts +/** +* Mount one preset composition under an agent's scope context, then prove the +* result is usable before the agent is published. +* +* The scope context is what makes the composition per-session: entry contexts +* chain to the context the subtree was plugged into, so every `ctx.tools` +* and `ctx.systemPrompt` registration inside the preset files into that +* agent's layer and unwinds with it. Two guards make that safe. A row that +* never reached a usable state is rejected, because a directly-plugged subtree +* is absent from `ctx.loader.entries()` and no boot audit covers it. A row that +* published a service into the ROOT realm is rejected, because such a service +* is process-global rather than per-session and the second session mounting the +* same preset collides with the first. +* @module @deepseek-ai/dsh-agent-presets/mount +*/ +/** +* Subtrees captured by config identity. A subtree plugged directly (rather than +* created as a loader entry) never links itself to an `Entry`, so this is the +* only handle to the rows it created; config objects are minted per mount, so +* concurrent mounts cannot collide. +*/ +const mounted = /* @__PURE__ */ new WeakMap(); +/** +* The base URL bare specifiers resolve against, per pending mount, keyed by the +* same config object. Recorded before the subtree is plugged, because `Include` +* rewrites its own context's `baseUrl` to the composition's directory and the +* pre-mount value is the only handle on where the harness itself lives. +*/ +const harnessBase = /* @__PURE__ */ new WeakMap(); +/** +* Include subclass that publishes its tree and fiber for the audit, and never +* writes to the file it read. +*/ +var PresetTree = class extends Include { + constructor(ctx, config) { + super(ctx, config); + mounted.set(config, { + tree: this, + fiber: ctx.fiber + }); + } + /** + * Resolve a bare specifier from the harness rather than from the preset. + * + * `EntryTree.import()` resolves against the tree's own `baseUrl`, which + * `Include` sets to the composition's directory. That is right for a + * relative specifier — a preset's own files travel with it — and wrong for + * a package name: a locally authored preset lives under the user's home, + * where Node's upward `node_modules` walk never reaches the harness's own + * dependencies, so every `@deepseek-ai/dsh-*` row would fail to import. The + * mount records the host composition's base instead, which is inside the + * installed harness, and bare names resolve from there. An absolute + * filesystem path names neither base and becomes a file URL before Node's + * ESM loader receives it, which is required for drive-letter paths on + * Windows. + * @param name - the module specifier from the row. + * @param getOuterStack - the loader's stack composer for import diagnostics. + * @returns the imported module, or the `cordis:` builtin. + */ + import(name, getOuterStack) { + const specifier = isAbsolute(name) ? pathToFileURL(name).href : name; + const base = harnessBase.get(this.config); + /* v8 ignore next -- every PresetTree is constructed by `mountPreset`, which records the base first */ + if (base === void 0) return super.import(specifier, getOuterStack); + if (name.startsWith(".") || name.startsWith("cordis:")) return super.import(name, getOuterStack); + const internal = this.ctx.loader.internal; + /* v8 ignore next -- Node always supplies the internal module loader; the branch keeps a + hypothetical embedder from losing the row's name in a resolution error. */ + if (internal === void 0) return super.import(specifier, getOuterStack); + return internal.import(specifier, base, {}); + } + /** + * A preset is an input, never a persistence target. + * + * The Loader writes a tree back through this method whenever it decides the + * config changed — a plugin self-disposing is enough, and tearing an agent + * down disposes its whole subtree. Inherited, that rewrites the preset file + * with whatever the dying tree held, which in practice means truncating a + * shipped composition to `[]` the first time a session ends. Persisting a + * preset is also meaningless: nothing here is user state, and the same file + * backs every session that names it. + * + * Dropping the write drops the `loader/config-update` the inherited method + * emits with it. Nothing observes one for a preset subtree today, and a + * future "edit your preset while it runs" flow needs a deliberate + * persistence path rather than this method's return. + */ + write() {} +}; +const mounts = /* @__PURE__ */ new Set(); +/** +* Drop every record whose subtree is gone. +* +* Records are pruned by observation rather than through a disposal hook +* because a subtree can be torn down by its owning agent, by a failed mount, or +* by the whole tree unloading, and a cleared `uid` is what all three share. +* +* Pruning therefore has to happen on a path this module owns. Reading is one +* such path, but not a reliable one: the only production reader is the +* invariant companion's service listener, and `dsh-invariants` is a +* development composition — a shipped host never loads it. Mounting is the +* other, and it is the one every session takes, which bounds the set at one +* generation of dead records rather than one per session ever composed. Each +* record would otherwise retain its whole disposed subtree: the fiber holds +* its config, and that config is the key its `EntryTree` is stored under. +*/ +function pruneDisposedMounts() { + for (const mount of mounts) if (mount.fiber.uid === null) mounts.delete(mount); +} +/** +* Every preset composition still installed, pruning fibers disposed since the +* last read. +* @returns the live mounts. +*/ +function livePresetMounts() { + pruneDisposedMounts(); + return [...mounts]; +} +/** +* Whether `fiber` is `root` itself or is mounted anywhere inside its subtree. +* +* Membership is object identity. `uid` looks like a cheaper key but is a +* per-registry counter, so fibers in two different roots collide on it and a +* subtree in one runtime would be blamed for a service published in another. +* @param fiber - the fiber to locate. +* @param root - the subtree root to test membership against. +* @returns true when `fiber` belongs to `root`'s subtree. +*/ +function withinFiber(fiber, root) { + let current = fiber; + while (true) { + if (current === root) return true; + const parent = current.parent.fiber; + if (parent === current) return false; + current = parent; + } +} +/** +* Service names the mounted subtree published into the root realm. +* +* A provider without an `isolate` realm stores its implementation under the +* root's symbol for that name, which is exactly the comparison below; a +* provider inside an `isolate` realm stores under a realm-private symbol and +* is correctly absent here. +* @param ctx - any context of the runtime whose service store is inspected. +* @param mount - the mounted subtree's fiber. +* @returns the leaked service names in lexical order. +*/ +function leakedServices(ctx, mount) { + const store = ctx.reflect.store; + const rootIsolate = ctx.root[Context.isolate]; + const leaked = []; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than + clearing it, so an own symbol always resolves; the guard exists only + because the store's index signature is optional. */ + if (impl === void 0) continue; + if (!withinFiber(impl.fiber, mount)) continue; + if (rootIsolate[impl.name] === key) leaked.push(impl.name); + } + return leaked.sort((left, right) => left.localeCompare(right)); +} +/** +* The standing composition one agent is joined to. +* +* The agent's own key is parented to its preset's standing key, so the mount +* is found by matching that parent rather than by walking up from the agent — +* the mount is not under the agent's fiber. An agent that joined no preset — +* a deployment composing no roster, or a child agent before its join — has no +* parent link and resolves to undefined. +* @param agentCtx - the agent's scope context. +* @returns the mount the agent joined, or undefined when it joined none. +*/ +function standingMountFor(agentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) return void 0; + const standingKey = scopeParentOf(agentKey); + if (standingKey === void 0) return void 0; + return livePresetMounts().find((candidate) => candidate.key === standingKey); +} +/** +* One agent's instance of a service its preset mounted. +* +* A preset publishes a service behind an `isolate` realm so two sessions +* cannot collide, and an entry-local realm is invisible to everything outside +* the group — including the agent's own scope context and the host. That is +* right for the rows inside the group and wrong for one caller: a request that +* is ABOUT a session but arrives from outside it, which is every browser RPC +* the api-proxy serves. +* +* Ownership is the same relation {@link leakedServices} reads, inverted: there +* it names implementations a subtree published into the ROOT realm, here it +* names the one this subtree published anywhere. Fiber membership is object +* identity for the reason stated on {@link withinFiber}. +* +* This is READ addressing for a caller that already holds the agent. It is not +* a general host handle on a session's internals: a host row that `inject`s a +* service cannot use it, because injection resolves before any session exists +* and has no agent to key by — such a service belongs on the host plane. +* @param ctx - any context of the runtime whose service store is inspected. +* @param agent - the agent whose mounted composition to look inside. +* @param name - the service name as the preset's rows resolve it. +* @returns the agent's instance, or undefined when its preset mounts none. +*/ +function serviceForAgent(ctx, agent, name) { + const mount = standingMountFor(agent.ctx); + if (mount === void 0) return void 0; + const store = ctx.reflect.store; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than clearing it */ + if (impl === void 0) continue; + if (impl.name !== name) continue; + if (withinFiber(impl.fiber, mount.fiber)) return impl.value; + } +} +/** +* Rows that did not reach a usable state, each rendered as one diagnostic line. +* +* A row whose module failed to import or whose plugin threw already rejects the +* mount through the loader; what remains observable here is a row still waiting +* for a service the composition never supplies. +* @param tree - the mounted subtree. +* @returns one line per unusable row, empty when every enabled row is usable. +*/ +function inactiveRows(tree) { + const lines = []; + for (const entry of tree.entries()) { + if (entry.disabled) continue; + const fiber = entry.fiber; + /* v8 ignore next 4 -- the loader rejects an entry whose module or plugin failed, + so a settled tree never holds an enabled fiber-less entry; the branch exists + only because `Entry.fiber` is declared optional. */ + if (fiber === void 0) { + lines.push(`${entry.options.id} (${entry.options.name}): never started`); + continue; + } + const missing = Object.keys(fiber.inject).filter((name) => fiber.ctx.get(name) === void 0); + if (missing.length > 0) lines.push(`${entry.options.id} (${entry.options.name}): waiting for ${missing.join(", ")}`); + } + return lines; +} +/** +* The reportable text of a mount failure. +* +* The loader reports several failed rows as one `AggregateError`, whose own +* message names none of them; without flattening, a composition that fails on +* two rows says only "loader entries failed to apply" and the operator has +* nothing to act on. +* @param error - the value the mount rejected with. +* @returns a single-line-per-cause description. +*/ +function mountDetail(error) { + /* v8 ignore next -- every path into the mount's catch throws an Error: the loader + wraps a row's thrown value before it propagates, and this module's own + rejections are Errors. The fallback keeps a hostile value readable. */ + if (!(error instanceof Error)) return String(error); + if (!(error instanceof AggregateError)) return error.message; + return [error.message, ...error.errors.map((cause) => `- ${mountDetail(cause)}`)].join("\n"); +} +/** +* Mount `preset` under `agentCtx` and return only once every row is usable. +* +* The subtree is owned by `agentCtx`'s fiber, so it unwinds with the agent and +* the caller receives no disposer. A rejection leaves nothing mounted. +* @param agentCtx - the agent's scope context, from the agent factory's `setup`. +* @param preset - the resolved preset to compose the agent from. +* @throws when `agentCtx` carries no scope, a row is unusable, or a row +* published a service into the root realm. +*/ +async function mountPreset(agentCtx, preset) { + if (scopeOf(agentCtx) === void 0) throw new Error(`agent-presets: refusing to mount preset "${preset.id}" into an unscoped context; its registrations would apply to every agent in the process`); + const config = { path: pathToFileURL(preset.path).href }; + /* v8 ignore next -- the Loader sets `baseUrl` on the root before any scoped context derives from it */ + if (agentCtx.baseUrl !== void 0) harnessBase.set(config, agentCtx.baseUrl); + pruneDisposedMounts(); + const handle = agentCtx.plugin(PresetTree, config); + try { + await handle.await(); + const subtree = mounted.get(config); + /* v8 ignore next -- the subclass constructor runs before `await()` settles for every mounted tree */ + if (subtree === void 0) throw new Error("mounted subtree did not publish its entry tree"); + const { tree, fiber } = subtree; + const unusable = inactiveRows(tree); + if (unusable.length > 0) throw new Error(`${String(unusable.length)} row(s) did not activate:\n${unusable.join("\n")}`); + const leaked = leakedServices(agentCtx, fiber); + if (leaked.length > 0) throw new Error(`row(s) published process-global service(s) [${leaked.join(", ")}]; a preset service must sit behind an \`isolate\` realm or move to the host composition`); + mounts.add({ + presetId: preset.id, + fiber, + key: scopeOf(agentCtx) + }); + } catch (error) { + try { + await handle.dispose(); + } catch {} + throw new PresetMountError(preset.id, `${mountDetail(error)} (${preset.path})`, { cause: error }); + } +} +//#endregion +//#region src/index.ts +/** +* Agent presets: each session composes its model-facing plugin set from one +* preset `cordis.yml`, mounted ONCE per preset under a standing scope and +* joined by every agent that names it. +* +* The standing mount is what makes a preset one composition rather than one +* per session: its plugin instances, tool registrations, prompt sections, and +* projection units exist exactly once, keyed per session inside the plugins +* themselves (they predate presets and were written for a shared world). An +* agent joins by having its scope key parented to the mount's +* ({@link bindScopeParent}), which makes the mount's registrations visible to +* that agent's views and the mount's listeners receive that agent's events — +* and a host reader with no agent at all (a cold transcript read) resolves +* the same standing registrations by preset id. +* +* This package owns the preset vocabulary, filesystem discovery, and the +* guarded standing mount. It does not decide when an agent is created — the +* agent factory's `setup(agentCtx)` hook is the one supported call site, +* because only there is the join installed while the agent is still +* unpublished, so a rejected composition rolls the whole creation back. +* @module @deepseek-ai/dsh-agent-presets +*/ +/** Settings namespace carrying the user's chosen default preset. */ +const SETTINGS_NAMESPACE = "agent-presets"; +/** Runtime schema for the user-writable slice. */ +const AgentPresetSettingsSchema = z.object({ default: z.string() }); +(class extends Service { + config; + static inject = ["loader"]; + /** Runtime schema for the preset roster. */ + static Config = z.object({ + default: z.string().required(), + roots: z.array(z.object({ + path: z.string().required(), + trust: z.union(["system", "user"]).default("user") + })).default([]), + includeUserRoot: z.boolean().default(true) + }); + /** + * The roots discovery and authoring actually scan: every configured root in + * order, then the harness-home user root unless `includeUserRoot` is false. + * + * Derived once, because a root set that changed between `list()` and the + * `copy()` acting on its answer would author into a directory the caller + * never saw. Appending rather than prepending keeps an earlier configured + * root winning a duplicate id, so a shipped preset still shadows a + * locally authored directory that claimed its name. + */ + resolvedRoots; + /** + * The user layer over `config.default`, present only while a settings + * provider is composed. Held rather than snapshotted so a hot-reloaded + * document takes effect without a restart. + */ + settings; + /** + * The settings service behind {@link settings}, held for the one write this + * service makes: clearing a user default it has just deleted. + */ + settingsService; + /** + * The service's own untraced context. Methods invoked through the traceable + * proxy see `this.ctx` rebound to the CALLER's context, which carries a + * shadow; a subtree minted from it resolves every service through that + * shadow's fiber instead of each entry's own inject store, so preset rows + * would fail on the very services they declare. Standing mounts must hang + * off the untraced original (the `jobs-local` selfCtx precedent). + */ + selfCtx; + constructor(ctx, config) { + super(ctx, "agentPresets"); + this.config = config; + this.selfCtx = ctx; + this.resolvedRoots = config.includeUserRoot ? [...config.roots, { + path: dshHomePath(USER_PRESET_DIR), + trust: "user" + }] : [...config.roots]; + ctx.inject(["settings"], (settingsCtx) => { + this.settings = settingsCtx.settings.register(settingsNamespace(SETTINGS_NAMESPACE), AgentPresetSettingsSchema, { base: { default: config.default } }); + this.settingsService = settingsCtx.settings; + settingsCtx.effect(() => () => { + this.settings = void 0; + this.settingsService = void 0; + }, "agentPresets.settings()"); + }); + ctx.on("agent/created", ({ agent }) => { + if (this.resolvedRoots.length === 0) return; + if (this.composedPreset(agent.ctx) !== void 0) return; + ctx.logger.warn(`agent "${agent.id}" was published without joining an agent preset; its tools, prompt sections, and skill catalog resolve against the empty global layer (join through AgentPresets.mount() or composeFrom() in the agent factory setup)`); + }); + ctx.on("session/event", (session, event) => { + if (event.type !== "agent-preset/selected") return; + ctx.emit("agent-preset/selected", session.id, event.data.agentPreset); + }); + } + /** + * The preset id mounted when a caller names none. + * + * Read per call rather than cached: the settings document is hot-reloaded, so + * changing the default takes effect on the next session created and leaves + * every running session on the preset it was composed from. + */ + get defaultId() { + return this.settings?.get().default ?? this.config.default; + } + /** + * Every preset the configured roots currently supply. + * @returns the presets, first-root-wins per id. + */ + async list() { + return await discoverPresets(this.resolvedRoots); + } + /** + * Resolve one preset by id. + * + * A broken preset resolves — deleting one, reading one, and reporting one + * all need the row — and the mounting paths refuse it AFTER resolution + * through {@link resolveMountable}. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved preset. + * @throws when no configured root supplies that id. + */ + async resolve(id) { + const wanted = id ?? this.defaultId; + const presets = await this.list(); + const found = presets.find((preset) => preset.id === wanted); + if (found === void 0) throw new UnknownPresetError(wanted, presets.map((preset) => preset.id)); + return found; + } + /** + * Resolve one preset that is about to compose an agent, refusing a broken + * one with its discovery-reported reason. Failing here rather than inside + * the loader keeps the answer the same for every unloadable shape — ghost + * directory, unparsable YAML, rowless list — and spends no mount attempt + * on a composition discovery already read as unusable. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved, mountable preset. + * @throws when the preset is unknown or discovery reports it broken. + */ + async resolveMountable(id) { + const preset = await this.resolve(id); + if (preset.broken !== void 0) throw new PresetMountError(preset.id, preset.broken); + return preset; + } + /** + * Standing mounts by preset id, single-flight so two agents racing the + * first use of one preset share one composition. A settled failure is + * removed so a later session retries a preset whose file has been fixed; a + * settled success serves until the composition FILE visibly changes — each + * generation records its file stamp, and a stale stamp starts the next + * generation for sessions created afterwards. Sessions already joined keep + * the generation they run on; a superseded one is never disposed while the + * process lives (reclaimed only by whole-tree teardown), so editing files + * is bounded by how often compositions change, not by session count. + */ + standing = /* @__PURE__ */ new Map(); + /** + * Parent bindings of the agents this roster composed, keyed by the agent's + * scope key. The binding is dsh-scope's only re-link capability; holding it + * here makes this service the sole authority that can move an agent between + * standing compositions. WeakMap: entries die with their agents. + */ + bindings = /* @__PURE__ */ new WeakMap(); + /** + * Compose one agent from a preset: ensure the preset's standing mount, then + * parent the agent's scope key to it so the mount's registrations and + * listeners cover this agent. + * + * Call from the agent factory's `setup(agentCtx)`; a rejection there rolls + * the agent creation back, so a broken preset never yields a half-composed + * session. + * @param agentCtx - the agent's scope context. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the preset that was composed, for the caller to record. + * @throws when the preset is unknown or its composition is unusable. + */ + async mount(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset"); + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return preset; + } + /** + * Join one agent to the SAME standing composition another already runs on. + * + * This is how a child agent inherits its parent's capabilities. It is a bind, + * not a mount: the parent's generation is already composed, so the child gets + * that exact instance — the same plugin objects, the same tool registrations, + * the same prompt sections. Re-resolving the parent's preset by id instead + * would re-read the roster, and a composition file edited since the parent + * started would hand the child a DIFFERENT generation than the one its + * parent's history was produced under (and a preset deleted since would fail + * the child outright while its parent keeps running). + * + * Synchronous, and with no composition failure mode of its own — it reads no + * roster, mounts nothing, and touches no file — which is what lets a child + * creation window use it: the two in-process subagent drivers compose their + * children inside a synchronous `setup`. It still rejects a caller error, as + * the `@throws` below record. + * + * A parent that joined no preset — a rosterless deployment — yields no join + * and no error: there, the model-facing rows sit in the host composition and + * the child already sees them through the global layer. + * @param agentCtx - the joining agent's scope context. + * @param parentCtx - the scope context of the agent whose composition to join. + * @returns the preset id joined, or undefined when the parent joined none. + * @throws when `agentCtx` carries no scope, or has already joined a preset. + */ + composeFrom(agentCtx, parentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset"); + const standing = standingMountFor(parentCtx); + if (standing === void 0) return void 0; + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return standing.presetId; + } + /** + * The preset one live agent runs on. + * + * Read from the live scope chain rather than from the session, so it answers + * for an agent whose session has not recorded a preset yet — a child agent + * whose durable header is being built from its parent's composition. + * @param agentCtx - the agent's scope context. + * @returns the preset id, or undefined when the agent joined none. + */ + composedPreset(agentCtx) { + return standingMountFor(agentCtx)?.presetId; + } + /** + * The roots this roster scans, which is not `config.roots`: it is every + * configured root in order, then the harness-home user root unless + * `includeUserRoot` is false. Read this — not the config field — to answer + * whether a roster is composed at all, so one derivation decides it. + */ + get roots() { + return this.resolvedRoots; + } + /** Whether this deployment has a root locally authored presets go to. */ + get authorable() { + return this.resolvedRoots.some((root) => root.trust === "user"); + } + /** + * Read one preset's composition text. + * @param id - the preset id. + * @returns the composition exactly as stored. + * @throws when no configured root supplies that id. + */ + async read(id) { + return await readComposition(await this.resolve(id)); + } + /** + * Create a locally authored preset by copying an existing one whole. + * + * Copy is the only authoring write. Composition text never crosses this + * seam: the source is named by id and its directory is copied as it stands, + * so the copy is exactly as loadable as its source and authoring grants no + * capability the roster did not already carry. The copy is NOT mounted to + * validate — a source that mounts today yields a copy that mounts today. + * @param from - the preset the copy starts from; shipped presets are the + * primary source, so any trust is accepted. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; absent falls back to the id. + * @throws when the source is unknown, the id is unusable or already taken, + * or the deployment configures no writable root. + */ + async copy(from, id, name) { + const source = await this.resolve(from); + if ((await this.list()).some((preset) => preset.id === id)) throw new PresetExistsError(id); + await copyComposition(this.resolvedRoots, source, id, name); + this.standing.delete(id); + } + /** + * Delete a locally authored preset. + * @param id - the preset id. + * @throws when the preset is unknown or ships with the deployment. + */ + async remove(id) { + await deleteComposition(this.resolvedRoots, await this.resolve(id)); + this.standing.delete(id); + if (this.settings?.get().default !== id) return; + await this.settingsService?.mutate(settingsNamespace(SETTINGS_NAMESPACE), [{ + op: "unset", + path: ["default"] + }]); + } + /** + * One agent's instance of a service its preset mounted. + * + * A preset publishes services behind `isolate` realms, which are invisible + * outside the group that declares them — including to the host. This is how a + * caller holding the agent reads one anyway: a request that is ABOUT a + * session but arrives from outside it, which is every browser RPC. + * + * Read addressing only. A host row that `inject`s a service cannot use this, + * because injection resolves before any session exists and has no agent to + * key by; such a service belongs on the host plane instead. + * @param agent - the agent whose composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ + serviceFor(agent, name) { + return serviceForAgent(this.ctx, agent, name); + } + /** + * Re-link one agent to a different preset's standing composition. + * + * Only valid while the agent has produced nothing: swapping tools mid + * conversation would leave logged tool calls the new composition cannot + * make. The CALLER owns that check — this method does not read session + * history. + * + * The swap is a parent re-link, not an unmount: standing mounts are shared + * and permanent, so the old composition stays for its other agents and the + * new one is ensured BEFORE the link moves. An unknown or unusable preset + * therefore throws with the agent exactly as it was — there is no torn-down + * state to restore. The re-link runs through the binding this roster kept + * from the agent's mount — dsh-scope's only re-link authority. An agent + * that never composed one has nothing to re-link: the switch is then the + * agent's first bind, exactly a mount. + * @param agentCtx - the agent's scope context. + * @param id - the preset to compose the agent from instead. + * @returns the preset now installed. + * @throws when the preset is unknown or its composition is unusable. + */ + async recompose(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === void 0) throw new Error("agent-presets: refusing to recompose an unscoped context"); + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + const binding = this.bindings.get(agentKey); + if (binding === void 0) this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + else binding.rebind(standing.key); + return preset; + } + /** + * The standing scope key of one preset, for a host reader with no agent. + * + * A cold transcript read resolves tool presenters against the composition + * the session recorded, and the standing mount makes that possible without + * resuming anything: ensuring the mount composes plugins but starts no + * agent, no session, and no turn. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the standing scope key readers pass as a registry view scope. + * @throws when the preset is unknown or its composition is unusable. + */ + async standingKeyFor(id) { + const preset = await this.resolveMountable(id); + return (await this.ensureStanding(preset)).key; + } + /** Resolve (or create, single-flight) the standing mount of one preset. */ + async ensureStanding(preset) { + const pending = this.standing.get(preset.id); + if (pending !== void 0) { + const mounted = await pending; + const current = await compositionStamp(preset.path); + if (current === void 0 || sameStamp(mounted.stamp, current)) return mounted; + if (this.standing.get(preset.id) === pending) this.standing.delete(preset.id); + return this.ensureStanding(preset); + } + const created = (async () => { + const key = { agentPreset: preset.id }; + const scope = createScope(this.selfCtx, key); + try { + const stamp = await compositionStamp(preset.path); + if (stamp === void 0) throw new PresetMountError(preset.id, `composition file is unreadable: ${preset.path}`); + await mountPreset(scope.ctx, preset); + return { + key, + scope, + stamp + }; + } catch (error) { + this.standing.delete(preset.id); + await scope.dispose(); + throw error; + } + })(); + this.standing.set(preset.id, created); + return created; + } +}); +/** Read one composition file's stamp, or undefined when it cannot be statted. */ +async function compositionStamp(path) { + try { + const { mtimeMs, size } = await stat(path); + return { + mtimeMs, + size + }; + } catch { + return; + } +} +/** Whether two stamps name the same file state. */ +function sameStamp(a, b) { + return a.mtimeMs === b.mtimeMs && a.size === b.size; +} +//#endregion +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-agent-presets`. +* @module @deepseek-ai/dsh-agent-presets/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-agent-presets"; +/** Cordis companion plugin name. */ +const name = "agent-presets-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* Assert that no installed preset composition reaches the root service realm, +* and that a deployment configuring a roster composes every agent from it. +* +* `mountPreset` proves the first once, when the subtree settles. A row that +* publishes later — from a timer, or an asynchronous continuation after its +* plugin returned — would escape that one-shot audit, so re-check every live +* mount whenever a service registration changes. +*/ +const install = (ctx, fail) => { + ctx.on("internal/service", function(name) { + for (const mount of livePresetMounts()) { + const leaked = leakedServices(ctx, mount.fiber); + if (leaked.length === 0) continue; + fail(`preset "${mount.presetId}" published process-global service(s) [${leaked.join(", ")}] after its mount was audited (observed while notifying "${name}") — a preset service must sit behind an \`isolate\` realm or move to the host composition`); + } + }, { global: true }); + ctx.on("system-prompt/assemble", (_assembly, context, next) => { + const presets = ctx.get("agentPresets"); + const agent = context.agent; + if (presets !== void 0 && presets.roots.length > 0 && agent !== void 0 && presets.composedPreset(agent.ctx) === void 0) fail(`agent "${agent.id}" addressed a model without joining any agent preset while a roster is composed; its tools, prompt sections, and skill catalog resolve against the empty global layer`); + return next(); + }); +}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.d.ts new file mode 100644 index 0000000..7d8fe21 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.d.ts @@ -0,0 +1,86 @@ +/** + * Copying, reading, and deleting locally authored presets. + * + * Authoring is confined to a `user` root: the shipped `.system` set is part of + * the deployment, and letting a browser rewrite it would turn "reset to a known + * preset" into something the same caller could have broken first. + * + * The only authoring write is a whole-directory copy of an existing preset. + * No caller supplies composition text: the inputs are ids the host resolves + * against its own roots plus an optional display name, so authoring grants no + * capability the copied preset did not already carry. + * @module @deepseek-ai/dsh-agent-presets/authoring + */ +import { type AgentPreset, type PresetRoot } from './preset.ts'; +/** A preset id that cannot be used as a directory name under a root. */ +export declare class InvalidPresetIdError extends Error { + /** The rejected id. */ + readonly presetId: string; + constructor( + /** The rejected id. */ + presetId: string); +} +/** A copy target that is already occupied — a copy never overwrites. */ +export declare class PresetExistsError extends Error { + /** The id that is already taken. */ + readonly presetId: string; + constructor( + /** The id that is already taken. */ + presetId: string); +} +/** Authoring was attempted where the deployment allows none. */ +export declare class PresetNotWritableError extends Error { + /** What the caller tried to change, for the diagnostic. */ + readonly presetId: string; + constructor( + /** What the caller tried to change, for the diagnostic. */ + presetId: string, reason: string); +} +/** + * The root locally authored presets are written to. + * @param roots - the configured roots in precedence order. + * @returns the absolute path of the first `user` root. + * @throws when the deployment configured no writable root. + */ +export declare function writableRoot(roots: readonly PresetRoot[]): string; +/** + * Read one preset's composition text. + * @param preset - the resolved preset. + * @returns the file's contents. + */ +export declare function readComposition(preset: AgentPreset): Promise; +/** + * Create a preset by copying an existing one's whole directory. + * + * The copy carries everything the source directory holds — composition, + * metadata, skill directories, assets — because a preset is its directory, + * not one file. Symlinks are dereferenced so the copy is self-contained + * rather than a set of links back into the install it was copied from. + * + * The copied metadata is then rewritten: the source's description is kept + * (the file is the author's to edit afterwards), but its name and roster + * `order` are not — a copy presenting itself identically to its source, or + * sorted into the shipped set's declared order, would make the roster stop + * distinguishing them. With no name given and no description to keep, the + * file is removed so the copy publishes nothing rather than a blank. + * @param roots - the configured roots; the first `user` one receives the copy. + * @param source - the resolved preset the copy starts from. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; omitted falls back to the id. + * @returns the absolute path of the new preset directory. + * @throws when the id is unusable or already occupied on disk, or the + * deployment configures no writable root. + */ +export declare function copyComposition(roots: readonly PresetRoot[], source: AgentPreset, id: string, name?: string): Promise; +/** + * Delete a locally authored preset. + * + * A shipped preset is refused: it belongs to the deployment. A preset a live + * session mounted is NOT refused — the composition was read at creation and is + * never re-read, so that session keeps running exactly as it was. + * @param roots - the configured roots. + * @param preset - the resolved preset to remove. + * @throws when the preset ships with the deployment or lies outside the writable root. + */ +export declare function deleteComposition(roots: readonly PresetRoot[], preset: AgentPreset): Promise; +//# sourceMappingURL=authoring.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.js new file mode 100644 index 0000000..bf1de13 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/authoring.js @@ -0,0 +1,183 @@ +/** + * Copying, reading, and deleting locally authored presets. + * + * Authoring is confined to a `user` root: the shipped `.system` set is part of + * the deployment, and letting a browser rewrite it would turn "reset to a known + * preset" into something the same caller could have broken first. + * + * The only authoring write is a whole-directory copy of an existing preset. + * No caller supplies composition text: the inputs are ids the host resolves + * against its own roots plus an optional display name, so authoring grants no + * capability the copied preset did not already carry. + * @module @deepseek-ai/dsh-agent-presets/authoring + */ +import { chmod, cp, readdir, readFile, rm, stat } from 'node:fs/promises'; +import { dirname, isAbsolute, join, resolve } from 'node:path'; +import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write'; +import { expandHomePath } from '@deepseek-ai/dsh-home-paths'; +import { METADATA_FILE, renderPresetMetadata } from "./metadata.js"; +import { PRESET_ID } from "./preset.js"; +/** A preset id that cannot be used as a directory name under a root. */ +export class InvalidPresetIdError extends Error { + presetId; + constructor( + /** The rejected id. */ + presetId) { + super(`agent-presets: preset id ${JSON.stringify(presetId)} must match ${String(PRESET_ID)} — ` + + 'the id is a directory name, so anything else could escape the preset root'); + this.presetId = presetId; + } +} +/** A copy target that is already occupied — a copy never overwrites. */ +export class PresetExistsError extends Error { + presetId; + constructor( + /** The id that is already taken. */ + presetId) { + super(`agent-presets: preset "${presetId}" already exists — ` + + 'a copy never overwrites; delete the existing preset first or choose another id'); + this.presetId = presetId; + } +} +/** Authoring was attempted where the deployment allows none. */ +export class PresetNotWritableError extends Error { + presetId; + constructor( + /** What the caller tried to change, for the diagnostic. */ + presetId, reason) { + super(`agent-presets: preset "${presetId}" cannot be written: ${reason}`); + this.presetId = presetId; + } +} +/** + * The root locally authored presets are written to. + * @param roots - the configured roots in precedence order. + * @returns the absolute path of the first `user` root. + * @throws when the deployment configured no writable root. + */ +export function writableRoot(roots) { + const root = roots.find(candidate => candidate.trust === 'user'); + if (root === undefined) { + throw new PresetNotWritableError('', 'this deployment configures no user-writable preset root'); + } + return resolve(expandHomePath(root.path)); +} +/** + * Read one preset's composition text. + * @param preset - the resolved preset. + * @returns the file's contents. + */ +export async function readComposition(preset) { + return await readFile(preset.path, 'utf8'); +} +/** Whether anything occupies the path (cp's own errorOnExist backstops races). */ +async function occupied(path) { + let present = true; + try { + await stat(path); + } + catch { + // Every stat failure means the same thing here: nothing usable occupies + // the path, so the copy may claim it. + present = false; + } + return present; +} +/** + * Re-tighten a copied tree to owner-only. A shipped preset is world-readable + * in its install and `cp` preserves that; the copy carries the same weight as + * the settings document beside it, so group/other access is stripped. A + * file's owner-execute bit survives — a preset may ship runnable helpers. + */ +async function tightenModes(dir) { + await chmod(dir, 0o700); + for (const entry of await readdir(dir, { withFileTypes: true })) { + const target = join(dir, entry.name); + if (entry.isDirectory()) { + await tightenModes(target); + } + else { + /* v8 ignore next -- Windows exposes no POSIX owner-execute bit; the POSIX lane covers both file modes. */ + await chmod(target, ((await stat(target)).mode & 0o100) === 0 ? 0o600 : 0o700); + } + } +} +/** + * Create a preset by copying an existing one's whole directory. + * + * The copy carries everything the source directory holds — composition, + * metadata, skill directories, assets — because a preset is its directory, + * not one file. Symlinks are dereferenced so the copy is self-contained + * rather than a set of links back into the install it was copied from. + * + * The copied metadata is then rewritten: the source's description is kept + * (the file is the author's to edit afterwards), but its name and roster + * `order` are not — a copy presenting itself identically to its source, or + * sorted into the shipped set's declared order, would make the roster stop + * distinguishing them. With no name given and no description to keep, the + * file is removed so the copy publishes nothing rather than a blank. + * @param roots - the configured roots; the first `user` one receives the copy. + * @param source - the resolved preset the copy starts from. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; omitted falls back to the id. + * @returns the absolute path of the new preset directory. + * @throws when the id is unusable or already occupied on disk, or the + * deployment configures no writable root. + */ +export async function copyComposition(roots, source, id, name) { + if (!PRESET_ID.test(id)) + throw new InvalidPresetIdError(id); + const dir = join(writableRoot(roots), id); + // The roster check upstream only sees discovered presets; a directory with + // no composition file still occupies the name and deserves a readable + // refusal rather than a filesystem error code. + if (await occupied(dir)) + throw new PresetExistsError(id); + try { + await cp(dirname(source.path), dir, { + recursive: true, dereference: true, force: false, errorOnExist: true, + }); + await tightenModes(dir); + const rendered = renderPresetMetadata({ + ...name === undefined ? {} : { name }, + ...source.description === undefined ? {} : { description: source.description }, + }); + const metadataPath = join(dir, METADATA_FILE); + if (rendered === undefined) { + await rm(metadataPath, { force: true }); + } + else { + await writeFileAtomic(metadataPath, rendered, { mode: 0o600, dirMode: 0o700 }); + } + } + catch (error) { + // A half-copied directory would be invisible to discovery at best and a + // mountable-but-incomplete preset at worst; a failed copy leaves nothing. + await rm(dir, { recursive: true, force: true }); + throw error; + } + return dir; +} +/** + * Delete a locally authored preset. + * + * A shipped preset is refused: it belongs to the deployment. A preset a live + * session mounted is NOT refused — the composition was read at creation and is + * never re-read, so that session keeps running exactly as it was. + * @param roots - the configured roots. + * @param preset - the resolved preset to remove. + * @throws when the preset ships with the deployment or lies outside the writable root. + */ +export async function deleteComposition(roots, preset) { + if (preset.trust !== 'user') { + throw new PresetNotWritableError(preset.id, 'it ships with the deployment'); + } + const dir = join(writableRoot(roots), preset.id); + // Belt and braces over the id pattern: the resolved directory must still be + // the one the writable root owns, whatever discovery reported. + if (!isAbsolute(preset.path) || !preset.path.startsWith(dir)) { + throw new PresetNotWritableError(preset.id, 'it does not live under the writable preset root'); + } + await rm(dir, { recursive: true, force: true }); +} +//# sourceMappingURL=authoring.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.d.ts new file mode 100644 index 0000000..0f65584 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.d.ts @@ -0,0 +1,55 @@ +/** + * Filesystem discovery of agent presets. A preset is a directory holding + * {@link COMPOSITION_FILE}, optionally beside a {@link METADATA_FILE} carrying + * its display text; the directory name is the preset id. Discovery + * re-reads the roots on every call so a preset authored while the process is + * running is visible without a restart. + * + * Discovery also owns preset HEALTH: a directory whose composition is + * missing or unloadable is reported as a broken roster row rather than + * skipped. A skipped directory would still occupy its id on disk — the copy + * path refuses the name while no surface shows anything to delete — and a + * malformed composition would otherwise read as an ordinary preset until the + * first session fails to mount it. + * @module @deepseek-ai/dsh-agent-presets/discovery + */ +import { type AgentPreset, type PresetRoot } from './preset.ts'; +/** The composition file that makes a directory a preset. */ +export declare const COMPOSITION_FILE = "agent.cordis.yml"; +/** + * Harness-home directory holding locally authored presets. + * + * This package owns the writable root the way `dsh-skill-filesystem` owns + * `/skills`. An app must assemble the SHIPPED root, whose path only + * the installed app can resolve; where a person's own presets go is the same + * place in every deployment that does not say otherwise, so a launcher that + * forgets to configure one still finds them. + * + * Package-internal on purpose: no consumer outside this package addresses the + * directory by name, and a test that imported it could not catch this value + * being wrong — the expected segment is spelled out where it is asserted. + */ +export declare const USER_PRESET_DIR = ".agent-presets"; +/** + * Scan one root for preset directories. + * + * An absent root yields no presets rather than throwing: the user root does + * not exist until the first locally authored preset, and naming a default + * that no root supplies already fails loud at resolution. + * + * Every directory whose name is a usable preset id is a roster row — broken + * when its composition is missing or unloadable. A directory named outside + * {@link PRESET_ID} is skipped instead: no copy could ever claim that name, + * so it blocks nothing, and reporting `.DS_Store`-grade residue as broken + * presets would teach users to ignore the marker. + * @param root - the directory and the trust its presets inherit. + * @returns the root's presets ordered by id. + */ +export declare function scanRoot(root: PresetRoot): Promise; +/** + * Scan every root in precedence order. + * @param roots - roots in precedence order; an earlier root wins a duplicate id. + * @returns every discovered preset, first-root-wins per id. + */ +export declare function discoverPresets(roots: readonly PresetRoot[]): Promise; +//# sourceMappingURL=discovery.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.js new file mode 100644 index 0000000..63bb39e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/discovery.js @@ -0,0 +1,187 @@ +/** + * Filesystem discovery of agent presets. A preset is a directory holding + * {@link COMPOSITION_FILE}, optionally beside a {@link METADATA_FILE} carrying + * its display text; the directory name is the preset id. Discovery + * re-reads the roots on every call so a preset authored while the process is + * running is visible without a restart. + * + * Discovery also owns preset HEALTH: a directory whose composition is + * missing or unloadable is reported as a broken roster row rather than + * skipped. A skipped directory would still occupy its id on disk — the copy + * path refuses the name while no surface shows anything to delete — and a + * malformed composition would otherwise read as an ordinary preset until the + * first session fails to mount it. + * @module @deepseek-ai/dsh-agent-presets/discovery + */ +import { readdir, readFile, stat } from 'node:fs/promises'; +import { join, resolve } from 'node:path'; +import { load } from 'js-yaml'; +import { entryListSchema } from '@deepseek-ai/cordis-plugin-include'; +import { expandHomePath } from '@deepseek-ai/dsh-home-paths'; +import { readPresetMetadata } from "./metadata.js"; +import { PRESET_ID } from "./preset.js"; +/** The composition file that makes a directory a preset. */ +export const COMPOSITION_FILE = 'agent.cordis.yml'; +/** + * Harness-home directory holding locally authored presets. + * + * This package owns the writable root the way `dsh-skill-filesystem` owns + * `/skills`. An app must assemble the SHIPPED root, whose path only + * the installed app can resolve; where a person's own presets go is the same + * place in every deployment that does not say otherwise, so a launcher that + * forgets to configure one still finds them. + * + * Package-internal on purpose: no consumer outside this package addresses the + * directory by name, and a test that imported it could not catch this value + * being wrong — the expected segment is spelled out where it is asserted. + */ +export const USER_PRESET_DIR = '.agent-presets'; +/** + * Why `rows` cannot be an entry list, or undefined when it can. + * + * A shallow shape check, deliberately short of the loader's work: it does not + * resolve plugin names or apply configs. What it catches is the hand-edit + * that produces a file the loader cannot even begin with — and it must accept + * everything the loader accepts, which is why rows are only required to be + * maps carrying a plugin `name` (groups recurse into their own lists). + * @param rows - the parsed composition document. + * @param at - row-path prefix for nested diagnostics, empty at the top level. + * @returns one human-readable reason, or undefined when the shape holds. + */ +function entryListProblem(rows, at = '') { + if (!Array.isArray(rows)) { + return at === '' + ? 'the composition must be a top-level list of plugin rows' + : `group ${at} must hold a list of plugin rows`; + } + for (const [index, row] of rows.entries()) { + const label = at === '' ? `row ${String(index + 1)}` : `${at} row ${String(index + 1)}`; + if (typeof row !== 'object' || row === null || Array.isArray(row)) { + return `${label} is not a plugin row (expected a map with a "name")`; + } + const { name, group, config } = row; + if (typeof name !== 'string' || name === '') { + return `${label} names no plugin (a "name" string is required)`; + } + if (group === true) { + const nested = entryListProblem(config, label); + if (nested !== undefined) + return nested; + } + } + return undefined; +} +/** + * Why the composition at `path` cannot mount, or undefined when it looks + * loadable. Parsed with the loader's own YAML dialect ({@link entryListSchema}, + * the one carrying `!!js`), so health can never call a composition broken + * that the loader would accept. + * @param path - absolute path of the composition file. + * @returns one human-readable reason, or undefined when the file is loadable. + */ +async function compositionProblem(path) { + let content; + try { + content = await readFile(path, 'utf8'); + } + catch { + // The caller statted this file moments ago; any read failure now — + // deleted in between, permissions — is the same answer as unparsable. + return `the composition file ${COMPOSITION_FILE} cannot be read`; + } + let rows; + try { + rows = load(content, { schema: entryListSchema }); + } + catch (error) { + /* v8 ignore next -- js-yaml throws YAMLException (an Error) for every parse failure; the fallback keeps a hostile value readable */ + const full = error instanceof Error ? error.message : String(error); + // First line only: js-yaml appends a multi-line code-frame snippet, and + // the reason is displayed on a roster card, not in a terminal. + return `the composition is not valid YAML: ${full.replace(/\n[\s\S]*$/, '')}`; + } + return entryListProblem(rows); +} +/** + * Whether `path` names an existing regular file. + * @param path - absolute path to test. + * @returns true when the path resolves to a file. + */ +async function isFile(path) { + try { + return (await stat(path)).isFile(); + } + catch { + // Any stat failure — absent, unreadable, a dangling link — means this + // directory does not present a composition, which is not an error: the + // directory simply is not a preset. + return false; + } +} +/** + * Scan one root for preset directories. + * + * An absent root yields no presets rather than throwing: the user root does + * not exist until the first locally authored preset, and naming a default + * that no root supplies already fails loud at resolution. + * + * Every directory whose name is a usable preset id is a roster row — broken + * when its composition is missing or unloadable. A directory named outside + * {@link PRESET_ID} is skipped instead: no copy could ever claim that name, + * so it blocks nothing, and reporting `.DS_Store`-grade residue as broken + * presets would teach users to ignore the marker. + * @param root - the directory and the trust its presets inherit. + * @returns the root's presets ordered by id. + */ +export async function scanRoot(root) { + const dir = resolve(expandHomePath(root.path)); + let children; + try { + children = await readdir(dir, { withFileTypes: true }); + } + catch (error) { + if (error.code === 'ENOENT') + return []; + throw new Error(`agent-presets: cannot read preset root ${dir}: ${String(error)}`, { cause: error }); + } + const found = []; + for (const child of children) { + if (!child.isDirectory() || !PRESET_ID.test(child.name)) + continue; + const directory = join(dir, child.name); + const path = join(directory, COMPOSITION_FILE); + const broken = await isFile(path) + ? await compositionProblem(path) + : `the composition file ${COMPOSITION_FILE} is missing — the directory still occupies the id; delete it or restore the file`; + // Display text only, and never fatal: a preset with unreadable metadata + // still mounts, it just shows its id. + const metadata = await readPresetMetadata(directory); + found.push({ + id: child.name, trust: root.trust, path, ...metadata, + ...broken === undefined ? {} : { broken }, + }); + } + // Declared order first so the shipped set reads by capability; everything + // else falls back to the id, which keeps authored presets stable. + return found.sort((left, right) => { + const byOrder = (left.order ?? Number.POSITIVE_INFINITY) - (right.order ?? Number.POSITIVE_INFINITY); + return byOrder === 0 ? left.id.localeCompare(right.id) : byOrder; + }); +} +/** + * Scan every root in precedence order. + * @param roots - roots in precedence order; an earlier root wins a duplicate id. + * @returns every discovered preset, first-root-wins per id. + */ +export async function discoverPresets(roots) { + const byId = new Map(); + for (const root of roots) { + for (const preset of await scanRoot(root)) { + if (byId.has(preset.id)) + continue; + byId.set(preset.id, preset); + } + } + return [...byId.values()]; +} +//# sourceMappingURL=discovery.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.d.ts new file mode 100644 index 0000000..cce4c5b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.d.ts @@ -0,0 +1,291 @@ +/** + * Agent presets: each session composes its model-facing plugin set from one + * preset `cordis.yml`, mounted ONCE per preset under a standing scope and + * joined by every agent that names it. + * + * The standing mount is what makes a preset one composition rather than one + * per session: its plugin instances, tool registrations, prompt sections, and + * projection units exist exactly once, keyed per session inside the plugins + * themselves (they predate presets and were written for a shared world). An + * agent joins by having its scope key parented to the mount's + * ({@link bindScopeParent}), which makes the mount's registrations visible to + * that agent's views and the mount's listeners receive that agent's events — + * and a host reader with no agent at all (a cold transcript read) resolves + * the same standing registrations by preset id. + * + * This package owns the preset vocabulary, filesystem discovery, and the + * guarded standing mount. It does not decide when an agent is created — the + * agent factory's `setup(agentCtx)` hook is the one supported call site, + * because only there is the join installed while the agent is still + * unpublished, so a rejected composition rolls the whole creation back. + * @module @deepseek-ai/dsh-agent-presets + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { type ScopeKey } from '@deepseek-ai/dsh-scope'; +import { type AgentPreset, type Config, type PresetRoot } from './preset.ts'; +/** Settings namespace carrying the user's chosen default preset. */ +export declare const SETTINGS_NAMESPACE = "agent-presets"; +/** The user-writable slice of this plugin's config. */ +export interface AgentPresetSettings { + /** Preset mounted when a session names none. */ + default?: string; +} +/** Runtime schema for the user-writable slice. */ +export declare const AgentPresetSettingsSchema: z; +export { COMPOSITION_FILE, discoverPresets, scanRoot } from './discovery.ts'; +export { METADATA_FILE, readPresetMetadata, renderPresetMetadata, type PresetMetadata, } from './metadata.ts'; +export { inactiveRows, leakedServices, livePresetMounts, mountPreset, serviceForAgent, standingMountFor, type JoinedPresetMount, type PresetMount, } from './mount.ts'; +export { copyComposition, deleteComposition, InvalidPresetIdError, PresetExistsError, PresetNotWritableError, readComposition, writableRoot, } from './authoring.ts'; +export { resolveSessionPreset, type PresetBearingSession } from './session.ts'; +export { PresetMountError, UnknownPresetError } from './preset.ts'; +export type { AgentPreset, Config, PresetRoot, PresetTrust } from './preset.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + agentPresets: AgentPresets; + } +} +/** + * Registry over the deployment's agent presets. + * + * Discovery is unmemoized: `list()` and `resolve()` re-read the roots on every + * call so a preset authored while the process runs is visible immediately, + * and a preset deleted underneath a picker disappears from the next read. + */ +export declare class AgentPresets extends Service { + config: Config; + static inject: string[]; + /** Runtime schema for the preset roster. */ + static Config: z; + /** + * The roots discovery and authoring actually scan: every configured root in + * order, then the harness-home user root unless `includeUserRoot` is false. + * + * Derived once, because a root set that changed between `list()` and the + * `copy()` acting on its answer would author into a directory the caller + * never saw. Appending rather than prepending keeps an earlier configured + * root winning a duplicate id, so a shipped preset still shadows a + * locally authored directory that claimed its name. + */ + private readonly resolvedRoots; + /** + * The user layer over `config.default`, present only while a settings + * provider is composed. Held rather than snapshotted so a hot-reloaded + * document takes effect without a restart. + */ + private settings; + /** + * The settings service behind {@link settings}, held for the one write this + * service makes: clearing a user default it has just deleted. + */ + private settingsService; + /** + * The service's own untraced context. Methods invoked through the traceable + * proxy see `this.ctx` rebound to the CALLER's context, which carries a + * shadow; a subtree minted from it resolves every service through that + * shadow's fiber instead of each entry's own inject store, so preset rows + * would fail on the very services they declare. Standing mounts must hang + * off the untraced original (the `jobs-local` selfCtx precedent). + */ + private readonly selfCtx; + constructor(ctx: Context, config: Config); + /** + * The preset id mounted when a caller names none. + * + * Read per call rather than cached: the settings document is hot-reloaded, so + * changing the default takes effect on the next session created and leaves + * every running session on the preset it was composed from. + */ + get defaultId(): string; + /** + * Every preset the configured roots currently supply. + * @returns the presets, first-root-wins per id. + */ + list(): Promise; + /** + * Resolve one preset by id. + * + * A broken preset resolves — deleting one, reading one, and reporting one + * all need the row — and the mounting paths refuse it AFTER resolution + * through {@link resolveMountable}. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved preset. + * @throws when no configured root supplies that id. + */ + resolve(id?: string): Promise; + /** + * Resolve one preset that is about to compose an agent, refusing a broken + * one with its discovery-reported reason. Failing here rather than inside + * the loader keeps the answer the same for every unloadable shape — ghost + * directory, unparsable YAML, rowless list — and spends no mount attempt + * on a composition discovery already read as unusable. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved, mountable preset. + * @throws when the preset is unknown or discovery reports it broken. + */ + private resolveMountable; + /** + * Standing mounts by preset id, single-flight so two agents racing the + * first use of one preset share one composition. A settled failure is + * removed so a later session retries a preset whose file has been fixed; a + * settled success serves until the composition FILE visibly changes — each + * generation records its file stamp, and a stale stamp starts the next + * generation for sessions created afterwards. Sessions already joined keep + * the generation they run on; a superseded one is never disposed while the + * process lives (reclaimed only by whole-tree teardown), so editing files + * is bounded by how often compositions change, not by session count. + */ + private readonly standing; + /** + * Parent bindings of the agents this roster composed, keyed by the agent's + * scope key. The binding is dsh-scope's only re-link capability; holding it + * here makes this service the sole authority that can move an agent between + * standing compositions. WeakMap: entries die with their agents. + */ + private readonly bindings; + /** + * Compose one agent from a preset: ensure the preset's standing mount, then + * parent the agent's scope key to it so the mount's registrations and + * listeners cover this agent. + * + * Call from the agent factory's `setup(agentCtx)`; a rejection there rolls + * the agent creation back, so a broken preset never yields a half-composed + * session. + * @param agentCtx - the agent's scope context. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the preset that was composed, for the caller to record. + * @throws when the preset is unknown or its composition is unusable. + */ + mount(agentCtx: Context, id?: string): Promise; + /** + * Join one agent to the SAME standing composition another already runs on. + * + * This is how a child agent inherits its parent's capabilities. It is a bind, + * not a mount: the parent's generation is already composed, so the child gets + * that exact instance — the same plugin objects, the same tool registrations, + * the same prompt sections. Re-resolving the parent's preset by id instead + * would re-read the roster, and a composition file edited since the parent + * started would hand the child a DIFFERENT generation than the one its + * parent's history was produced under (and a preset deleted since would fail + * the child outright while its parent keeps running). + * + * Synchronous, and with no composition failure mode of its own — it reads no + * roster, mounts nothing, and touches no file — which is what lets a child + * creation window use it: the two in-process subagent drivers compose their + * children inside a synchronous `setup`. It still rejects a caller error, as + * the `@throws` below record. + * + * A parent that joined no preset — a rosterless deployment — yields no join + * and no error: there, the model-facing rows sit in the host composition and + * the child already sees them through the global layer. + * @param agentCtx - the joining agent's scope context. + * @param parentCtx - the scope context of the agent whose composition to join. + * @returns the preset id joined, or undefined when the parent joined none. + * @throws when `agentCtx` carries no scope, or has already joined a preset. + */ + composeFrom(agentCtx: Context, parentCtx: Context): string | undefined; + /** + * The preset one live agent runs on. + * + * Read from the live scope chain rather than from the session, so it answers + * for an agent whose session has not recorded a preset yet — a child agent + * whose durable header is being built from its parent's composition. + * @param agentCtx - the agent's scope context. + * @returns the preset id, or undefined when the agent joined none. + */ + composedPreset(agentCtx: Context): string | undefined; + /** + * The roots this roster scans, which is not `config.roots`: it is every + * configured root in order, then the harness-home user root unless + * `includeUserRoot` is false. Read this — not the config field — to answer + * whether a roster is composed at all, so one derivation decides it. + */ + get roots(): readonly PresetRoot[]; + /** Whether this deployment has a root locally authored presets go to. */ + get authorable(): boolean; + /** + * Read one preset's composition text. + * @param id - the preset id. + * @returns the composition exactly as stored. + * @throws when no configured root supplies that id. + */ + read(id: string): Promise; + /** + * Create a locally authored preset by copying an existing one whole. + * + * Copy is the only authoring write. Composition text never crosses this + * seam: the source is named by id and its directory is copied as it stands, + * so the copy is exactly as loadable as its source and authoring grants no + * capability the roster did not already carry. The copy is NOT mounted to + * validate — a source that mounts today yields a copy that mounts today. + * @param from - the preset the copy starts from; shipped presets are the + * primary source, so any trust is accepted. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; absent falls back to the id. + * @throws when the source is unknown, the id is unusable or already taken, + * or the deployment configures no writable root. + */ + copy(from: string, id: string, name?: string): Promise; + /** + * Delete a locally authored preset. + * @param id - the preset id. + * @throws when the preset is unknown or ships with the deployment. + */ + remove(id: string): Promise; + /** + * One agent's instance of a service its preset mounted. + * + * A preset publishes services behind `isolate` realms, which are invisible + * outside the group that declares them — including to the host. This is how a + * caller holding the agent reads one anyway: a request that is ABOUT a + * session but arrives from outside it, which is every browser RPC. + * + * Read addressing only. A host row that `inject`s a service cannot use this, + * because injection resolves before any session exists and has no agent to + * key by; such a service belongs on the host plane instead. + * @param agent - the agent whose composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ + serviceFor(agent: { + ctx: Context; + }, name: K): Context[K] | undefined; + /** + * Re-link one agent to a different preset's standing composition. + * + * Only valid while the agent has produced nothing: swapping tools mid + * conversation would leave logged tool calls the new composition cannot + * make. The CALLER owns that check — this method does not read session + * history. + * + * The swap is a parent re-link, not an unmount: standing mounts are shared + * and permanent, so the old composition stays for its other agents and the + * new one is ensured BEFORE the link moves. An unknown or unusable preset + * therefore throws with the agent exactly as it was — there is no torn-down + * state to restore. The re-link runs through the binding this roster kept + * from the agent's mount — dsh-scope's only re-link authority. An agent + * that never composed one has nothing to re-link: the switch is then the + * agent's first bind, exactly a mount. + * @param agentCtx - the agent's scope context. + * @param id - the preset to compose the agent from instead. + * @returns the preset now installed. + * @throws when the preset is unknown or its composition is unusable. + */ + recompose(agentCtx: Context, id: string): Promise; + /** + * The standing scope key of one preset, for a host reader with no agent. + * + * A cold transcript read resolves tool presenters against the composition + * the session recorded, and the standing mount makes that possible without + * resuming anything: ensuring the mount composes plugins but starts no + * agent, no session, and no turn. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the standing scope key readers pass as a registry view scope. + * @throws when the preset is unknown or its composition is unusable. + */ + standingKeyFor(id?: string): Promise; + /** Resolve (or create, single-flight) the standing mount of one preset. */ + private ensureStanding; +} +export default AgentPresets; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.js new file mode 100644 index 0000000..015f50d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/index.js @@ -0,0 +1,500 @@ +/** + * Agent presets: each session composes its model-facing plugin set from one + * preset `cordis.yml`, mounted ONCE per preset under a standing scope and + * joined by every agent that names it. + * + * The standing mount is what makes a preset one composition rather than one + * per session: its plugin instances, tool registrations, prompt sections, and + * projection units exist exactly once, keyed per session inside the plugins + * themselves (they predate presets and were written for a shared world). An + * agent joins by having its scope key parented to the mount's + * ({@link bindScopeParent}), which makes the mount's registrations visible to + * that agent's views and the mount's listeners receive that agent's events — + * and a host reader with no agent at all (a cold transcript read) resolves + * the same standing registrations by preset id. + * + * This package owns the preset vocabulary, filesystem discovery, and the + * guarded standing mount. It does not decide when an agent is created — the + * agent factory's `setup(agentCtx)` hook is the one supported call site, + * because only there is the join installed while the agent is still + * unpublished, so a rejected composition rolls the whole creation back. + * @module @deepseek-ai/dsh-agent-presets + */ +import { stat } from 'node:fs/promises'; +import { Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { bindScopeParent, createScope, scopeOf } from '@deepseek-ai/dsh-scope'; +import { settingsNamespace } from '@deepseek-ai/dsh-settings'; +import { dshHomePath } from '@deepseek-ai/dsh-home-paths'; +import { discoverPresets, USER_PRESET_DIR } from "./discovery.js"; +import { copyComposition, deleteComposition, readComposition } from "./authoring.js"; +import { mountPreset, serviceForAgent, standingMountFor } from "./mount.js"; +import { PresetExistsError } from "./authoring.js"; +import { PresetMountError, UnknownPresetError } from "./preset.js"; +/** Settings namespace carrying the user's chosen default preset. */ +export const SETTINGS_NAMESPACE = 'agent-presets'; +/** Runtime schema for the user-writable slice. */ +export const AgentPresetSettingsSchema = z.object({ + default: z.string(), +}); +export { COMPOSITION_FILE, discoverPresets, scanRoot } from "./discovery.js"; +export { METADATA_FILE, readPresetMetadata, renderPresetMetadata, } from "./metadata.js"; +export { inactiveRows, leakedServices, livePresetMounts, mountPreset, serviceForAgent, standingMountFor, } from "./mount.js"; +export { copyComposition, deleteComposition, InvalidPresetIdError, PresetExistsError, PresetNotWritableError, readComposition, writableRoot, } from "./authoring.js"; +export { resolveSessionPreset } from "./session.js"; +export { PresetMountError, UnknownPresetError } from "./preset.js"; +/** + * Registry over the deployment's agent presets. + * + * Discovery is unmemoized: `list()` and `resolve()` re-read the roots on every + * call so a preset authored while the process runs is visible immediately, + * and a preset deleted underneath a picker disappears from the next read. + */ +export class AgentPresets extends Service { + config; + static inject = ['loader']; + /** Runtime schema for the preset roster. */ + static Config = z.object({ + default: z.string().required(), + roots: z.array(z.object({ + path: z.string().required(), + trust: z.union(['system', 'user']).default('user'), + })).default([]), + includeUserRoot: z.boolean().default(true), + }); + /** + * The roots discovery and authoring actually scan: every configured root in + * order, then the harness-home user root unless `includeUserRoot` is false. + * + * Derived once, because a root set that changed between `list()` and the + * `copy()` acting on its answer would author into a directory the caller + * never saw. Appending rather than prepending keeps an earlier configured + * root winning a duplicate id, so a shipped preset still shadows a + * locally authored directory that claimed its name. + */ + resolvedRoots; + /** + * The user layer over `config.default`, present only while a settings + * provider is composed. Held rather than snapshotted so a hot-reloaded + * document takes effect without a restart. + */ + settings; + /** + * The settings service behind {@link settings}, held for the one write this + * service makes: clearing a user default it has just deleted. + */ + settingsService; + /** + * The service's own untraced context. Methods invoked through the traceable + * proxy see `this.ctx` rebound to the CALLER's context, which carries a + * shadow; a subtree minted from it resolves every service through that + * shadow's fiber instead of each entry's own inject store, so preset rows + * would fail on the very services they declare. Standing mounts must hang + * off the untraced original (the `jobs-local` selfCtx precedent). + */ + selfCtx; + constructor(ctx, config) { + super(ctx, 'agentPresets'); + this.config = config; + this.selfCtx = ctx; + this.resolvedRoots = config.includeUserRoot + ? [...config.roots, { path: dshHomePath(USER_PRESET_DIR), trust: 'user' }] + : [...config.roots]; + // Deliberately not `installSettingsSection`: that helper exists to re-judge + // what a consumer DERIVED from the source — memoized resolutions, + // registration-level facts — across attach, detach, and change. Nothing + // here is derived. `defaultId` reads through on every call, so both of its + // hooks would be no-ops and the source thunk would restate this field. + ctx.inject(['settings'], (settingsCtx) => { + this.settings = settingsCtx.settings.register(settingsNamespace(SETTINGS_NAMESPACE), AgentPresetSettingsSchema, { base: { default: config.default } }); + this.settingsService = settingsCtx.settings; + settingsCtx.effect(() => () => { + this.settings = undefined; + this.settingsService = undefined; + }, 'agentPresets.settings()'); + }); + // Advisory, not fatal: a synchronous `agent/created` listener that throws + // VETOES publication, and this service must not, because composing an agent + // outside the roster is legal — `recompose` binds exactly such a bare agent + // below, and the ACP, SDK-server, and headless entry points all create one. + // The invariant companion is the check that fails loud, at assembly. Why an + // unjoined agent matters at all has one home: the [Agent + // Note](../../../../.agents/notes/implemented/architecture/2026-08-10-host-plane-ownership-after-presets.md). + // + // Known false positive: a session created bare and bound later by + // `recompose` is warned about once, before its first bind. No shipped flow + // does that today — the Web surface mounts in `setup` and children join + // through `composeFrom` before publication. + ctx.on('agent/created', ({ agent }) => { + if (this.resolvedRoots.length === 0) + return; + if (this.composedPreset(agent.ctx) !== undefined) + return; + ctx.logger.warn(`agent "${agent.id}" was published without joining an agent preset; ` + + 'its tools, prompt sections, and skill catalog resolve against the empty global layer ' + + '(join through AgentPresets.mount() or composeFrom() in the agent factory setup)'); + }); + // The durable record is the commit point. Its public notification carries + // only the stable identity needed by clients, never the live Session. + ctx.on('session/event', (session, event) => { + if (event.type !== 'agent-preset/selected') + return; + ctx.emit('agent-preset/selected', session.id, event.data.agentPreset); + }); + } + /** + * The preset id mounted when a caller names none. + * + * Read per call rather than cached: the settings document is hot-reloaded, so + * changing the default takes effect on the next session created and leaves + * every running session on the preset it was composed from. + */ + get defaultId() { + return this.settings?.get().default ?? this.config.default; + } + /** + * Every preset the configured roots currently supply. + * @returns the presets, first-root-wins per id. + */ + async list() { + return await discoverPresets(this.resolvedRoots); + } + /** + * Resolve one preset by id. + * + * A broken preset resolves — deleting one, reading one, and reporting one + * all need the row — and the mounting paths refuse it AFTER resolution + * through {@link resolveMountable}. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved preset. + * @throws when no configured root supplies that id. + */ + async resolve(id) { + const wanted = id ?? this.defaultId; + const presets = await this.list(); + const found = presets.find(preset => preset.id === wanted); + if (found === undefined) { + throw new UnknownPresetError(wanted, presets.map(preset => preset.id)); + } + return found; + } + /** + * Resolve one preset that is about to compose an agent, refusing a broken + * one with its discovery-reported reason. Failing here rather than inside + * the loader keeps the answer the same for every unloadable shape — ghost + * directory, unparsable YAML, rowless list — and spends no mount attempt + * on a composition discovery already read as unusable. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the resolved, mountable preset. + * @throws when the preset is unknown or discovery reports it broken. + */ + async resolveMountable(id) { + const preset = await this.resolve(id); + if (preset.broken !== undefined) { + throw new PresetMountError(preset.id, preset.broken); + } + return preset; + } + /** + * Standing mounts by preset id, single-flight so two agents racing the + * first use of one preset share one composition. A settled failure is + * removed so a later session retries a preset whose file has been fixed; a + * settled success serves until the composition FILE visibly changes — each + * generation records its file stamp, and a stale stamp starts the next + * generation for sessions created afterwards. Sessions already joined keep + * the generation they run on; a superseded one is never disposed while the + * process lives (reclaimed only by whole-tree teardown), so editing files + * is bounded by how often compositions change, not by session count. + */ + standing = new Map(); + /** + * Parent bindings of the agents this roster composed, keyed by the agent's + * scope key. The binding is dsh-scope's only re-link capability; holding it + * here makes this service the sole authority that can move an agent between + * standing compositions. WeakMap: entries die with their agents. + */ + bindings = new WeakMap(); + /** + * Compose one agent from a preset: ensure the preset's standing mount, then + * parent the agent's scope key to it so the mount's registrations and + * listeners cover this agent. + * + * Call from the agent factory's `setup(agentCtx)`; a rejection there rolls + * the agent creation back, so a broken preset never yields a half-composed + * session. + * @param agentCtx - the agent's scope context. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the preset that was composed, for the caller to record. + * @throws when the preset is unknown or its composition is unusable. + */ + async mount(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === undefined) { + throw new Error('agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset'); + } + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + // The one bind of this agent's ancestry. The binding is the only re-link + // authority, held privately so nothing outside this roster can move a + // composed agent to another preset; a later recompose layer re-links + // through it under the caller-owned blank-session contract. + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return preset; + } + /** + * Join one agent to the SAME standing composition another already runs on. + * + * This is how a child agent inherits its parent's capabilities. It is a bind, + * not a mount: the parent's generation is already composed, so the child gets + * that exact instance — the same plugin objects, the same tool registrations, + * the same prompt sections. Re-resolving the parent's preset by id instead + * would re-read the roster, and a composition file edited since the parent + * started would hand the child a DIFFERENT generation than the one its + * parent's history was produced under (and a preset deleted since would fail + * the child outright while its parent keeps running). + * + * Synchronous, and with no composition failure mode of its own — it reads no + * roster, mounts nothing, and touches no file — which is what lets a child + * creation window use it: the two in-process subagent drivers compose their + * children inside a synchronous `setup`. It still rejects a caller error, as + * the `@throws` below record. + * + * A parent that joined no preset — a rosterless deployment — yields no join + * and no error: there, the model-facing rows sit in the host composition and + * the child already sees them through the global layer. + * @param agentCtx - the joining agent's scope context. + * @param parentCtx - the scope context of the agent whose composition to join. + * @returns the preset id joined, or undefined when the parent joined none. + * @throws when `agentCtx` carries no scope, or has already joined a preset. + */ + composeFrom(agentCtx, parentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === undefined) { + throw new Error('agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset'); + } + const standing = standingMountFor(parentCtx); + if (standing === undefined) + return undefined; + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + return standing.presetId; + } + /** + * The preset one live agent runs on. + * + * Read from the live scope chain rather than from the session, so it answers + * for an agent whose session has not recorded a preset yet — a child agent + * whose durable header is being built from its parent's composition. + * @param agentCtx - the agent's scope context. + * @returns the preset id, or undefined when the agent joined none. + */ + composedPreset(agentCtx) { + return standingMountFor(agentCtx)?.presetId; + } + /** + * The roots this roster scans, which is not `config.roots`: it is every + * configured root in order, then the harness-home user root unless + * `includeUserRoot` is false. Read this — not the config field — to answer + * whether a roster is composed at all, so one derivation decides it. + */ + get roots() { + return this.resolvedRoots; + } + /** Whether this deployment has a root locally authored presets go to. */ + get authorable() { + return this.resolvedRoots.some(root => root.trust === 'user'); + } + /** + * Read one preset's composition text. + * @param id - the preset id. + * @returns the composition exactly as stored. + * @throws when no configured root supplies that id. + */ + async read(id) { + return await readComposition(await this.resolve(id)); + } + /** + * Create a locally authored preset by copying an existing one whole. + * + * Copy is the only authoring write. Composition text never crosses this + * seam: the source is named by id and its directory is copied as it stands, + * so the copy is exactly as loadable as its source and authoring grants no + * capability the roster did not already carry. The copy is NOT mounted to + * validate — a source that mounts today yields a copy that mounts today. + * @param from - the preset the copy starts from; shipped presets are the + * primary source, so any trust is accepted. + * @param id - the new preset's id, which becomes its directory name. + * @param name - display name for the copy; absent falls back to the id. + * @throws when the source is unknown, the id is unusable or already taken, + * or the deployment configures no writable root. + */ + async copy(from, id, name) { + const source = await this.resolve(from); + // The roster check refuses ids any root supplies — shipped ones included, + // since a user directory named like a shipped preset is shadowed by it. + // The disk check inside copyComposition only sees the writable root. + if ((await this.list()).some(preset => preset.id === id)) { + throw new PresetExistsError(id); + } + await copyComposition(this.resolvedRoots, source, id, name); + // A settled mount under this id can only be stale (its preset was deleted + // from disk outside `remove`); the new preset must not inherit it. Every + // session already joined keeps the generation it runs on regardless. + this.standing.delete(id); + } + /** + * Delete a locally authored preset. + * @param id - the preset id. + * @throws when the preset is unknown or ships with the deployment. + */ + async remove(id) { + await deleteComposition(this.resolvedRoots, await this.resolve(id)); + // Sessions on the deleted preset keep their standing mount; only new + // sessions see the roster without it. + this.standing.delete(id); + // Storing a default that does not exist YET is deliberate — the roster is a + // live directory, so a name absent now may exist by the time a session asks + // for it, and `resolve` reports it then. A default this call just deleted is + // not that case: nothing will ever supply it again, and left in place every + // session created without an explicit pick would fail to start. Clearing it + // exposes the deployment's own default underneath, which is the layering. + if (this.settings?.get().default !== id) + return; + await this.settingsService?.mutate(settingsNamespace(SETTINGS_NAMESPACE), [{ op: 'unset', path: ['default'] }]); + } + /** + * One agent's instance of a service its preset mounted. + * + * A preset publishes services behind `isolate` realms, which are invisible + * outside the group that declares them — including to the host. This is how a + * caller holding the agent reads one anyway: a request that is ABOUT a + * session but arrives from outside it, which is every browser RPC. + * + * Read addressing only. A host row that `inject`s a service cannot use this, + * because injection resolves before any session exists and has no agent to + * key by; such a service belongs on the host plane instead. + * @param agent - the agent whose composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ + serviceFor(agent, name) { + return serviceForAgent(this.ctx, agent, name); + } + /** + * Re-link one agent to a different preset's standing composition. + * + * Only valid while the agent has produced nothing: swapping tools mid + * conversation would leave logged tool calls the new composition cannot + * make. The CALLER owns that check — this method does not read session + * history. + * + * The swap is a parent re-link, not an unmount: standing mounts are shared + * and permanent, so the old composition stays for its other agents and the + * new one is ensured BEFORE the link moves. An unknown or unusable preset + * therefore throws with the agent exactly as it was — there is no torn-down + * state to restore. The re-link runs through the binding this roster kept + * from the agent's mount — dsh-scope's only re-link authority. An agent + * that never composed one has nothing to re-link: the switch is then the + * agent's first bind, exactly a mount. + * @param agentCtx - the agent's scope context. + * @param id - the preset to compose the agent from instead. + * @returns the preset now installed. + * @throws when the preset is unknown or its composition is unusable. + */ + async recompose(agentCtx, id) { + const agentKey = scopeOf(agentCtx); + if (agentKey === undefined) { + throw new Error('agent-presets: refusing to recompose an unscoped context'); + } + const preset = await this.resolveMountable(id); + const standing = await this.ensureStanding(preset); + const binding = this.bindings.get(agentKey); + if (binding === undefined) { + this.bindings.set(agentKey, bindScopeParent(agentKey, standing.key)); + } + else { + binding.rebind(standing.key); + } + return preset; + } + /** + * The standing scope key of one preset, for a host reader with no agent. + * + * A cold transcript read resolves tool presenters against the composition + * the session recorded, and the standing mount makes that possible without + * resuming anything: ensuring the mount composes plugins but starts no + * agent, no session, and no turn. + * @param id - the preset id, or `undefined` for {@link defaultId}. + * @returns the standing scope key readers pass as a registry view scope. + * @throws when the preset is unknown or its composition is unusable. + */ + async standingKeyFor(id) { + const preset = await this.resolveMountable(id); + return (await this.ensureStanding(preset)).key; + } + /** Resolve (or create, single-flight) the standing mount of one preset. */ + async ensureStanding(preset) { + const pending = this.standing.get(preset.id); + if (pending !== undefined) { + const mounted = await pending; + // Files are the only composition editor (authoring is copy/delete), so + // the stamp is what notices an edit: a changed file starts the next + // generation here, for this and later sessions. An unreadable stamp + // serves the current generation — a mount must survive its file + // disappearing, and failing the session over a stat would not. + const current = await compositionStamp(preset.path); + if (current === undefined || sameStamp(mounted.stamp, current)) + return mounted; + // TODO: reclaim the superseded generation once the last agent joined to + // it is gone. The subtree is not inert — `dsh-skill-filesystem` watches its + // roots — and the settings-page authoring flow turns "a composition + // changed" into a per-save event. This needs a joined-agent count on + // StandingMount, incremented in `mount`/`composeFrom`/`recompose` and + // decremented when the agent's scope key dies. + // Guarded delete: a caller that raced this one may have already started + // the next generation, and dropping THAT pointer would fork a third. + if (this.standing.get(preset.id) === pending) + this.standing.delete(preset.id); + return this.ensureStanding(preset); + } + const created = (async () => { + const key = { agentPreset: preset.id }; + const scope = createScope(this.selfCtx, key); + try { + // Stamped before the file is read: an edit racing the mount makes the + // stamp stale rather than silently current, so the next session + // refreshes instead of trusting a composition older than its stamp. + const stamp = await compositionStamp(preset.path); + if (stamp === undefined) { + throw new PresetMountError(preset.id, `composition file is unreadable: ${preset.path}`); + } + await mountPreset(scope.ctx, preset); + return { key, scope, stamp }; + } + catch (error) { + this.standing.delete(preset.id); + await scope.dispose(); + throw error; + } + })(); + this.standing.set(preset.id, created); + return created; + } +} +/** Read one composition file's stamp, or undefined when it cannot be statted. */ +async function compositionStamp(path) { + try { + const { mtimeMs, size } = await stat(path); + return { mtimeMs, size }; + } + catch { + // Deleted, replaced by an unreadable entry, or otherwise unstattable all + // mean the same to the caller: the file offers no identity to compare. + return undefined; + } +} +/** Whether two stamps name the same file state. */ +function sameStamp(a, b) { + return a.mtimeMs === b.mtimeMs && a.size === b.size; +} +export default AgentPresets; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.d.ts new file mode 100644 index 0000000..7b01c4f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-agent-presets`. + * @module @deepseek-ai/dsh-agent-presets/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "agent-presets-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.js new file mode 100644 index 0000000..71c027f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/invariant.js @@ -0,0 +1,65 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-agent-presets`. + * @module @deepseek-ai/dsh-agent-presets/invariant + */ +// Imported through the package name, not `./mount.ts`: a module shared between +// the two build entry points becomes a third chunk that the published `files` +// list does not carry, which `verify-built-package-invariants` rejects. +import { leakedServices, livePresetMounts } from '@deepseek-ai/dsh-agent-presets'; +const PACKAGE_NAME = '@deepseek-ai/dsh-agent-presets'; +/** Cordis companion plugin name. */ +export const name = 'agent-presets-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * Assert that no installed preset composition reaches the root service realm, + * and that a deployment configuring a roster composes every agent from it. + * + * `mountPreset` proves the first once, when the subtree settles. A row that + * publishes later — from a timer, or an asynchronous continuation after its + * plugin returned — would escape that one-shot audit, so re-check every live + * mount whenever a service registration changes. + */ +const install = (ctx, fail) => { + ctx.on('internal/service', function (name) { + for (const mount of livePresetMounts()) { + const leaked = leakedServices(ctx, mount.fiber); + if (leaked.length === 0) + continue; + fail(`preset "${mount.presetId}" published process-global service(s) [${leaked.join(', ')}] ` + + `after its mount was audited (observed while notifying "${name}") — ` + + 'a preset service must sit behind an `isolate` realm or move to the host composition'); + } + }, { global: true }); + // An agent that joined no preset resolves `tools`, `system-prompt`, and + // `skill` against the empty global layer, so the model receives nothing. + // `composedPreset()` is the roster's own answer to "did this agent join", + // read from the live scope chain — see the [Agent + // Note](../../../../.agents/notes/implemented/architecture/2026-08-10-host-plane-ownership-after-presets.md) + // for why the warning beside it is advisory while this one fails. + // + // Two conditions, each load-bearing. `context.agent` is what makes this an + // AGENT assembly: a scope-only assembly — a cold read resolving presenters + // in a standing key, a diagnostic — is not an agent and must not be judged + // on whether it joined anything. And assembly rather than publication is the + // moment that matters, because an unjoined agent is legal until it addresses + // a model: `recompose` binds a bare agent as its first link, and that agent + // is unjoined for its whole life up to the switch. + ctx.on('system-prompt/assemble', (_assembly, context, next) => { + const presets = ctx.get('agentPresets'); + const agent = context.agent; + if (presets !== undefined && presets.roots.length > 0 + && agent !== undefined && presets.composedPreset(agent.ctx) === undefined) { + fail(`agent "${agent.id}" addressed a model without joining any agent preset while a roster is ` + + 'composed; its tools, prompt sections, and skill catalog resolve against the empty global layer'); + } + return next(); + }); +}; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.d.ts new file mode 100644 index 0000000..4660208 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.d.ts @@ -0,0 +1,52 @@ +/** + * A preset's display metadata: the name and description a picker shows. + * + * It lives in its own file because the composition is a top-level list of + * plugin rows — YAML cannot carry sibling keys beside it, and faking a + * metadata row would hand the Loader something to load. Keeping it separate + * also keeps the composition exactly what its name says: a Cordis file the + * loader owns and the cordis preset can author. + * + * The file carries display text ONLY. `id` is the directory name and `trust` + * comes from the root a preset was discovered under, so neither is writable + * here — otherwise a locally authored preset could claim to be a shipped one. + * + * Every read failure degrades to no metadata. A preset whose display text is + * missing, malformed, or unreadable still mounts: presentation is not a + * capability, and a broken name must never become an agent that cannot start. + * @module @deepseek-ai/dsh-agent-presets/metadata + */ +/** The optional display-metadata file beside a preset's composition. */ +export declare const METADATA_FILE = "preset.yml"; +/** Display text a preset may publish about itself. */ +export interface PresetMetadata { + /** Human-facing name; falls back to the preset id when absent. */ + readonly name?: string; + /** One sentence on what this preset is for. */ + readonly description?: string; + /** + * Position within its group; lower comes first. A preset that declares + * none sorts after every preset that does, then by id — so the shipped set + * can read in capability order while authored ones stay alphabetical. + */ + readonly order?: number; +} +/** + * Read one preset directory's display metadata. + * + * Absent, unparsable, and wrongly-shaped files are all the same answer — + * empty metadata — because the caller renders a picker, not a diagnostic. + * @param directory - the preset directory. + * @returns the display text the preset published, possibly empty. + */ +export declare function readPresetMetadata(directory: string): Promise; +/** + * Render display metadata as the file's contents. + * + * Absent fields are omitted rather than written empty, so a preset with no + * description does not ship a key that reads as an intentional blank. + * @param metadata - the display text to store. + * @returns the YAML document, or undefined when there is nothing to store. + */ +export declare function renderPresetMetadata(metadata: PresetMetadata): string | undefined; +//# sourceMappingURL=metadata.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.js new file mode 100644 index 0000000..fe86def --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/metadata.js @@ -0,0 +1,92 @@ +/** + * A preset's display metadata: the name and description a picker shows. + * + * It lives in its own file because the composition is a top-level list of + * plugin rows — YAML cannot carry sibling keys beside it, and faking a + * metadata row would hand the Loader something to load. Keeping it separate + * also keeps the composition exactly what its name says: a Cordis file the + * loader owns and the cordis preset can author. + * + * The file carries display text ONLY. `id` is the directory name and `trust` + * comes from the root a preset was discovered under, so neither is writable + * here — otherwise a locally authored preset could claim to be a shipped one. + * + * Every read failure degrades to no metadata. A preset whose display text is + * missing, malformed, or unreadable still mounts: presentation is not a + * capability, and a broken name must never become an agent that cannot start. + * @module @deepseek-ai/dsh-agent-presets/metadata + */ +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import yaml from 'js-yaml'; +/** The optional display-metadata file beside a preset's composition. */ +export const METADATA_FILE = 'preset.yml'; +/** A non-empty trimmed string, or undefined for anything else. */ +function text(value) { + if (typeof value !== 'string') + return undefined; + const trimmed = value.trim(); + return trimmed === '' ? undefined : trimmed; +} +/** + * Read one preset directory's display metadata. + * + * Absent, unparsable, and wrongly-shaped files are all the same answer — + * empty metadata — because the caller renders a picker, not a diagnostic. + * @param directory - the preset directory. + * @returns the display text the preset published, possibly empty. + */ +export async function readPresetMetadata(directory) { + let raw; + try { + raw = await readFile(join(directory, METADATA_FILE), 'utf8'); + } + catch { + // Absent is the common case: metadata is optional and most presets, + // including every one authored by duplicating another, carry none. + return {}; + } + let parsed; + try { + parsed = yaml.load(raw); + } + catch { + // Malformed display text is not worth failing discovery over; the picker + // falls back to the id, and the composition still mounts. + return {}; + } + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) + return {}; + const record = parsed; + const name = text(record.name); + const description = text(record.description); + const order = typeof record.order === 'number' && Number.isFinite(record.order) + ? record.order + : undefined; + return { + ...name === undefined ? {} : { name }, + ...description === undefined ? {} : { description }, + ...order === undefined ? {} : { order }, + }; +} +/** + * Render display metadata as the file's contents. + * + * Absent fields are omitted rather than written empty, so a preset with no + * description does not ship a key that reads as an intentional blank. + * @param metadata - the display text to store. + * @returns the YAML document, or undefined when there is nothing to store. + */ +export function renderPresetMetadata(metadata) { + const name = text(metadata.name); + const description = text(metadata.description); + const { order } = metadata; + if (name === undefined && description === undefined && order === undefined) + return undefined; + return yaml.dump({ + ...name === undefined ? {} : { name }, + ...description === undefined ? {} : { description }, + ...order === undefined ? {} : { order }, + }, { lineWidth: -1 }); +} +//# sourceMappingURL=metadata.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.d.ts new file mode 100644 index 0000000..a1415e6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.d.ts @@ -0,0 +1,112 @@ +/** + * Mount one preset composition under an agent's scope context, then prove the + * result is usable before the agent is published. + * + * The scope context is what makes the composition per-session: entry contexts + * chain to the context the subtree was plugged into, so every `ctx.tools` + * and `ctx.systemPrompt` registration inside the preset files into that + * agent's layer and unwinds with it. Two guards make that safe. A row that + * never reached a usable state is rejected, because a directly-plugged subtree + * is absent from `ctx.loader.entries()` and no boot audit covers it. A row that + * published a service into the ROOT realm is rejected, because such a service + * is process-global rather than per-session and the second session mounting the + * same preset collides with the first. + * @module @deepseek-ai/dsh-agent-presets/mount + */ +import { Context, type Fiber } from '@deepseek-ai/cordis'; +import type { EntryTree } from '@deepseek-ai/cordis-plugin-loader'; +import { type ScopeKey } from '@deepseek-ai/dsh-scope'; +import { type AgentPreset } from './preset.ts'; +/** One preset composition currently installed under some agent. */ +export interface PresetMount { + /** The preset the subtree was composed from. */ + readonly presetId: string; + /** The mounted subtree's fiber. */ + readonly fiber: Fiber; + /** The standing scope key agents are parented to (undefined only in torn-down records). */ + readonly key: ScopeKey | undefined; +} +/** + * Every preset composition still installed, pruning fibers disposed since the + * last read. + * @returns the live mounts. + */ +export declare function livePresetMounts(): PresetMount[]; +/** + * Service names the mounted subtree published into the root realm. + * + * A provider without an `isolate` realm stores its implementation under the + * root's symbol for that name, which is exactly the comparison below; a + * provider inside an `isolate` realm stores under a realm-private symbol and + * is correctly absent here. + * @param ctx - any context of the runtime whose service store is inspected. + * @param mount - the mounted subtree's fiber. + * @returns the leaked service names in lexical order. + */ +export declare function leakedServices(ctx: Context, mount: Fiber): string[]; +/** A live standing mount located through one agent already joined to it. */ +export type JoinedPresetMount = PresetMount & { + /** The standing key, definite because it is what the lookup matched on. */ + readonly key: ScopeKey; +}; +/** + * The standing composition one agent is joined to. + * + * The agent's own key is parented to its preset's standing key, so the mount + * is found by matching that parent rather than by walking up from the agent — + * the mount is not under the agent's fiber. An agent that joined no preset — + * a deployment composing no roster, or a child agent before its join — has no + * parent link and resolves to undefined. + * @param agentCtx - the agent's scope context. + * @returns the mount the agent joined, or undefined when it joined none. + */ +export declare function standingMountFor(agentCtx: Context): JoinedPresetMount | undefined; +/** + * One agent's instance of a service its preset mounted. + * + * A preset publishes a service behind an `isolate` realm so two sessions + * cannot collide, and an entry-local realm is invisible to everything outside + * the group — including the agent's own scope context and the host. That is + * right for the rows inside the group and wrong for one caller: a request that + * is ABOUT a session but arrives from outside it, which is every browser RPC + * the api-proxy serves. + * + * Ownership is the same relation {@link leakedServices} reads, inverted: there + * it names implementations a subtree published into the ROOT realm, here it + * names the one this subtree published anywhere. Fiber membership is object + * identity for the reason stated on {@link withinFiber}. + * + * This is READ addressing for a caller that already holds the agent. It is not + * a general host handle on a session's internals: a host row that `inject`s a + * service cannot use it, because injection resolves before any session exists + * and has no agent to key by — such a service belongs on the host plane. + * @param ctx - any context of the runtime whose service store is inspected. + * @param agent - the agent whose mounted composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ +export declare function serviceForAgent(ctx: Context, agent: { + ctx: Context; +}, name: K): Context[K] | undefined; +/** + * Rows that did not reach a usable state, each rendered as one diagnostic line. + * + * A row whose module failed to import or whose plugin threw already rejects the + * mount through the loader; what remains observable here is a row still waiting + * for a service the composition never supplies. + * @param tree - the mounted subtree. + * @returns one line per unusable row, empty when every enabled row is usable. + */ +export declare function inactiveRows(tree: EntryTree): string[]; +/** + * Mount `preset` under `agentCtx` and return only once every row is usable. + * + * The subtree is owned by `agentCtx`'s fiber, so it unwinds with the agent and + * the caller receives no disposer. A rejection leaves nothing mounted. + * @param agentCtx - the agent's scope context, from the agent factory's `setup`. + * @param preset - the resolved preset to compose the agent from. + * @throws when `agentCtx` carries no scope, a row is unusable, or a row + * published a service into the root realm. + */ +export declare function mountPreset(agentCtx: Context, preset: AgentPreset): Promise; +//# sourceMappingURL=mount.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.js new file mode 100644 index 0000000..be5f76d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/mount.js @@ -0,0 +1,349 @@ +/** + * Mount one preset composition under an agent's scope context, then prove the + * result is usable before the agent is published. + * + * The scope context is what makes the composition per-session: entry contexts + * chain to the context the subtree was plugged into, so every `ctx.tools` + * and `ctx.systemPrompt` registration inside the preset files into that + * agent's layer and unwinds with it. Two guards make that safe. A row that + * never reached a usable state is rejected, because a directly-plugged subtree + * is absent from `ctx.loader.entries()` and no boot audit covers it. A row that + * published a service into the ROOT realm is rejected, because such a service + * is process-global rather than per-session and the second session mounting the + * same preset collides with the first. + * @module @deepseek-ai/dsh-agent-presets/mount + */ +import { isAbsolute } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { Context } from '@deepseek-ai/cordis'; +import { Include } from '@deepseek-ai/cordis-plugin-include'; +import { scopeOf, scopeParentOf } from '@deepseek-ai/dsh-scope'; +import { PresetMountError } from "./preset.js"; +/** + * Subtrees captured by config identity. A subtree plugged directly (rather than + * created as a loader entry) never links itself to an `Entry`, so this is the + * only handle to the rows it created; config objects are minted per mount, so + * concurrent mounts cannot collide. + */ +const mounted = new WeakMap(); +/** + * The base URL bare specifiers resolve against, per pending mount, keyed by the + * same config object. Recorded before the subtree is plugged, because `Include` + * rewrites its own context's `baseUrl` to the composition's directory and the + * pre-mount value is the only handle on where the harness itself lives. + */ +const harnessBase = new WeakMap(); +/** + * Include subclass that publishes its tree and fiber for the audit, and never + * writes to the file it read. + */ +class PresetTree extends Include { + constructor(ctx, config) { + super(ctx, config); + mounted.set(config, { tree: this, fiber: ctx.fiber }); + } + /** + * Resolve a bare specifier from the harness rather than from the preset. + * + * `EntryTree.import()` resolves against the tree's own `baseUrl`, which + * `Include` sets to the composition's directory. That is right for a + * relative specifier — a preset's own files travel with it — and wrong for + * a package name: a locally authored preset lives under the user's home, + * where Node's upward `node_modules` walk never reaches the harness's own + * dependencies, so every `@deepseek-ai/dsh-*` row would fail to import. The + * mount records the host composition's base instead, which is inside the + * installed harness, and bare names resolve from there. An absolute + * filesystem path names neither base and becomes a file URL before Node's + * ESM loader receives it, which is required for drive-letter paths on + * Windows. + * @param name - the module specifier from the row. + * @param getOuterStack - the loader's stack composer for import diagnostics. + * @returns the imported module, or the `cordis:` builtin. + */ + import(name, getOuterStack) { + const specifier = isAbsolute(name) ? pathToFileURL(name).href : name; + const base = harnessBase.get(this.config); + /* v8 ignore next -- every PresetTree is constructed by `mountPreset`, which records the base first */ + if (base === undefined) + return super.import(specifier, getOuterStack); + if (name.startsWith('.') || name.startsWith('cordis:')) + return super.import(name, getOuterStack); + const internal = this.ctx.loader.internal; + /* v8 ignore next -- Node always supplies the internal module loader; the branch keeps a + hypothetical embedder from losing the row's name in a resolution error. */ + if (internal === undefined) + return super.import(specifier, getOuterStack); + return internal.import(specifier, base, {}); + } + /** + * A preset is an input, never a persistence target. + * + * The Loader writes a tree back through this method whenever it decides the + * config changed — a plugin self-disposing is enough, and tearing an agent + * down disposes its whole subtree. Inherited, that rewrites the preset file + * with whatever the dying tree held, which in practice means truncating a + * shipped composition to `[]` the first time a session ends. Persisting a + * preset is also meaningless: nothing here is user state, and the same file + * backs every session that names it. + * + * Dropping the write drops the `loader/config-update` the inherited method + * emits with it. Nothing observes one for a preset subtree today, and a + * future "edit your preset while it runs" flow needs a deliberate + * persistence path rather than this method's return. + */ + write() { + } +} +const mounts = new Set(); +/** + * Drop every record whose subtree is gone. + * + * Records are pruned by observation rather than through a disposal hook + * because a subtree can be torn down by its owning agent, by a failed mount, or + * by the whole tree unloading, and a cleared `uid` is what all three share. + * + * Pruning therefore has to happen on a path this module owns. Reading is one + * such path, but not a reliable one: the only production reader is the + * invariant companion's service listener, and `dsh-invariants` is a + * development composition — a shipped host never loads it. Mounting is the + * other, and it is the one every session takes, which bounds the set at one + * generation of dead records rather than one per session ever composed. Each + * record would otherwise retain its whole disposed subtree: the fiber holds + * its config, and that config is the key its `EntryTree` is stored under. + */ +function pruneDisposedMounts() { + for (const mount of mounts) { + if (mount.fiber.uid === null) + mounts.delete(mount); + } +} +/** + * Every preset composition still installed, pruning fibers disposed since the + * last read. + * @returns the live mounts. + */ +export function livePresetMounts() { + pruneDisposedMounts(); + return [...mounts]; +} +/** + * Whether `fiber` is `root` itself or is mounted anywhere inside its subtree. + * + * Membership is object identity. `uid` looks like a cheaper key but is a + * per-registry counter, so fibers in two different roots collide on it and a + * subtree in one runtime would be blamed for a service published in another. + * @param fiber - the fiber to locate. + * @param root - the subtree root to test membership against. + * @returns true when `fiber` belongs to `root`'s subtree. + */ +function withinFiber(fiber, root) { + let current = fiber; + while (true) { + if (current === root) + return true; + const parent = current.parent.fiber; + if (parent === current) + return false; + current = parent; + } +} +/** + * Service names the mounted subtree published into the root realm. + * + * A provider without an `isolate` realm stores its implementation under the + * root's symbol for that name, which is exactly the comparison below; a + * provider inside an `isolate` realm stores under a realm-private symbol and + * is correctly absent here. + * @param ctx - any context of the runtime whose service store is inspected. + * @param mount - the mounted subtree's fiber. + * @returns the leaked service names in lexical order. + */ +export function leakedServices(ctx, mount) { + const store = ctx.reflect.store; + const rootIsolate = ctx.root[Context.isolate]; + const leaked = []; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than + clearing it, so an own symbol always resolves; the guard exists only + because the store's index signature is optional. */ + if (impl === undefined) + continue; + if (!withinFiber(impl.fiber, mount)) + continue; + if (rootIsolate[impl.name] === key) + leaked.push(impl.name); + } + return leaked.sort((left, right) => left.localeCompare(right)); +} +/** + * The standing composition one agent is joined to. + * + * The agent's own key is parented to its preset's standing key, so the mount + * is found by matching that parent rather than by walking up from the agent — + * the mount is not under the agent's fiber. An agent that joined no preset — + * a deployment composing no roster, or a child agent before its join — has no + * parent link and resolves to undefined. + * @param agentCtx - the agent's scope context. + * @returns the mount the agent joined, or undefined when it joined none. + */ +export function standingMountFor(agentCtx) { + const agentKey = scopeOf(agentCtx); + if (agentKey === undefined) + return undefined; + const standingKey = scopeParentOf(agentKey); + if (standingKey === undefined) + return undefined; + return livePresetMounts().find((candidate) => candidate.key === standingKey); +} +/** + * One agent's instance of a service its preset mounted. + * + * A preset publishes a service behind an `isolate` realm so two sessions + * cannot collide, and an entry-local realm is invisible to everything outside + * the group — including the agent's own scope context and the host. That is + * right for the rows inside the group and wrong for one caller: a request that + * is ABOUT a session but arrives from outside it, which is every browser RPC + * the api-proxy serves. + * + * Ownership is the same relation {@link leakedServices} reads, inverted: there + * it names implementations a subtree published into the ROOT realm, here it + * names the one this subtree published anywhere. Fiber membership is object + * identity for the reason stated on {@link withinFiber}. + * + * This is READ addressing for a caller that already holds the agent. It is not + * a general host handle on a session's internals: a host row that `inject`s a + * service cannot use it, because injection resolves before any session exists + * and has no agent to key by — such a service belongs on the host plane. + * @param ctx - any context of the runtime whose service store is inspected. + * @param agent - the agent whose mounted composition to look inside. + * @param name - the service name as the preset's rows resolve it. + * @returns the agent's instance, or undefined when its preset mounts none. + */ +export function serviceForAgent(ctx, agent, name) { + const mount = standingMountFor(agent.ctx); + if (mount === undefined) + return undefined; + const store = ctx.reflect.store; + for (const key of Object.getOwnPropertySymbols(store)) { + const impl = store[key]; + /* v8 ignore next -- cordis deletes a store slot on disposal rather than clearing it */ + if (impl === undefined) + continue; + if (impl.name !== name) + continue; + if (withinFiber(impl.fiber, mount.fiber)) + return impl.value; + } + return undefined; +} +/** + * Rows that did not reach a usable state, each rendered as one diagnostic line. + * + * A row whose module failed to import or whose plugin threw already rejects the + * mount through the loader; what remains observable here is a row still waiting + * for a service the composition never supplies. + * @param tree - the mounted subtree. + * @returns one line per unusable row, empty when every enabled row is usable. + */ +export function inactiveRows(tree) { + const lines = []; + for (const entry of tree.entries()) { + if (entry.disabled) + continue; + const fiber = entry.fiber; + /* v8 ignore next 4 -- the loader rejects an entry whose module or plugin failed, + so a settled tree never holds an enabled fiber-less entry; the branch exists + only because `Entry.fiber` is declared optional. */ + if (fiber === undefined) { + lines.push(`${entry.options.id} (${entry.options.name}): never started`); + continue; + } + const missing = Object.keys(fiber.inject).filter(name => fiber.ctx.get(name) === undefined); + if (missing.length > 0) { + lines.push(`${entry.options.id} (${entry.options.name}): waiting for ${missing.join(', ')}`); + } + } + return lines; +} +/** + * The reportable text of a mount failure. + * + * The loader reports several failed rows as one `AggregateError`, whose own + * message names none of them; without flattening, a composition that fails on + * two rows says only "loader entries failed to apply" and the operator has + * nothing to act on. + * @param error - the value the mount rejected with. + * @returns a single-line-per-cause description. + */ +function mountDetail(error) { + /* v8 ignore next -- every path into the mount's catch throws an Error: the loader + wraps a row's thrown value before it propagates, and this module's own + rejections are Errors. The fallback keeps a hostile value readable. */ + if (!(error instanceof Error)) + return String(error); + if (!(error instanceof AggregateError)) + return error.message; + return [error.message, ...error.errors.map(cause => `- ${mountDetail(cause)}`)].join('\n'); +} +/** + * Mount `preset` under `agentCtx` and return only once every row is usable. + * + * The subtree is owned by `agentCtx`'s fiber, so it unwinds with the agent and + * the caller receives no disposer. A rejection leaves nothing mounted. + * @param agentCtx - the agent's scope context, from the agent factory's `setup`. + * @param preset - the resolved preset to compose the agent from. + * @throws when `agentCtx` carries no scope, a row is unusable, or a row + * published a service into the root realm. + */ +export async function mountPreset(agentCtx, preset) { + const scope = scopeOf(agentCtx); + if (scope === undefined) { + throw new Error(`agent-presets: refusing to mount preset "${preset.id}" into an unscoped context; ` + + 'its registrations would apply to every agent in the process'); + } + const config = { path: pathToFileURL(preset.path).href }; + // Captured before the subtree exists: the standing scope context still + // carries the host composition's base, which is inside the installed + // harness and is therefore where a row's package name has to resolve from. + /* v8 ignore next -- the Loader sets `baseUrl` on the root before any scoped context derives from it */ + if (agentCtx.baseUrl !== undefined) + harnessBase.set(config, agentCtx.baseUrl); + // Before the record this mount is about to add: standing mounts are one per + // preset and live until whole-tree teardown, so pruning here only sweeps + // records of torn-down runtimes (tests; an HMR reload of the roster). + pruneDisposedMounts(); + const handle = agentCtx.plugin(PresetTree, config); + try { + await handle.await(); + const subtree = mounted.get(config); + /* v8 ignore next -- the subclass constructor runs before `await()` settles for every mounted tree */ + if (subtree === undefined) + throw new Error('mounted subtree did not publish its entry tree'); + const { tree, fiber } = subtree; + const unusable = inactiveRows(tree); + if (unusable.length > 0) { + throw new Error(`${String(unusable.length)} row(s) did not activate:\n${unusable.join('\n')}`); + } + const leaked = leakedServices(agentCtx, fiber); + if (leaked.length > 0) { + throw new Error(`row(s) published process-global service(s) [${leaked.join(', ')}]; ` + + 'a preset service must sit behind an `isolate` realm or move to the host composition'); + } + mounts.add({ presetId: preset.id, fiber, key: scopeOf(agentCtx) }); + } + catch (error) { + try { + await handle.dispose(); + /* v8 ignore next 5 -- teardown of a subtree nothing else references has no + observed failure mode; the guard exists so a teardown error cannot + replace the mount diagnostic the caller needs. */ + } + catch { + // Swallows only this subtree's teardown failure. The mount error below is + // the actionable one, and the discarded fiber is unreachable either way. + } + throw new PresetMountError(preset.id, `${mountDetail(error)} (${preset.path})`, { cause: error }); + } +} +//# sourceMappingURL=mount.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.d.ts new file mode 100644 index 0000000..a245ee1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.d.ts @@ -0,0 +1,88 @@ +/** Agent-preset vocabulary shared by discovery, mounting, and consumers. */ +/** + * Where a preset's composition came from. A `system` preset ships with the + * deployment; a `user` preset was authored locally, by a person or by an + * agent, and therefore carries the same trust as shell access. + */ +export type PresetTrust = 'system' | 'user'; +/** + * Ids a preset directory may use. + * + * The id becomes a path segment, so this is a containment boundary rather than + * a style rule: `..`, a separator, or an absolute-looking name would place the + * composition outside the root the deployment authorised. Discovery shares it: + * a directory whose name no copy could ever claim is not a preset slot. + */ +export declare const PRESET_ID: RegExp; +/** One preset directory that carries a mountable agent composition. */ +export interface AgentPreset { + /** Stable identifier; the preset directory's name. */ + readonly id: string; + /** Trust recorded from the root this preset was discovered under. */ + readonly trust: PresetTrust; + /** Absolute path of the preset's agent composition file. */ + readonly path: string; + /** Display name from the preset's own metadata; absent falls back to {@link id}. */ + readonly name?: string; + /** One sentence on what this preset is for, when it published one. */ + readonly description?: string; + /** Declared position within its group; absent sorts after those that declare one. */ + readonly order?: number; + /** + * Why this preset cannot compose a session, absent when it can. A broken + * preset stays on the roster — hiding it would leave its directory blocking + * the id with nothing to see or delete — but every mounting path refuses it + * up front with this reason instead of failing deep inside the loader. + */ + readonly broken?: string; +} +/** One directory scanned for preset subdirectories. */ +export interface PresetRoot { + /** Directory holding one subdirectory per preset; a leading `~` expands. */ + path: string; + /** Trust recorded on every preset discovered under this root. */ + trust: PresetTrust; +} +/** Plugin config: which preset is the default, and where presets live. */ +export interface Config { + /** Preset id mounted when a caller names none. Missing at mount time fails loud. */ + default: string; + /** Scanned roots in precedence order; an earlier root wins a duplicate id. */ + roots: PresetRoot[]; + /** + * Append the harness home's `USER_PRESET_DIR` as a `user` root, after every + * configured root. False mounts a roster over `roots` alone. + */ + includeUserRoot: boolean; +} +/** + * No configured root supplies the requested preset. + * + * Separate from a mount failure because the two mean different things to a + * caller: an unknown id is a bad request, while an unusable composition is a + * broken preset the deployment must fix. + */ +export declare class UnknownPresetError extends Error { + /** The id that was requested. */ + readonly presetId: string; + /** Ids the roster does supply, for the caller to offer instead. */ + readonly available: readonly string[]; + constructor( + /** The id that was requested. */ + presetId: string, + /** Ids the roster does supply, for the caller to offer instead. */ + available: readonly string[]); +} +/** A preset exists but its composition cannot be installed. */ +export declare class PresetMountError extends Error { + /** The preset whose composition failed. */ + readonly presetId: string; + /** Why it failed, without this package's own message prefix. */ + readonly reason: string; + constructor( + /** The preset whose composition failed. */ + presetId: string, + /** Why it failed, without this package's own message prefix. */ + reason: string, options?: ErrorOptions); +} +//# sourceMappingURL=preset.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.js new file mode 100644 index 0000000..22e2ca9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/preset.js @@ -0,0 +1,45 @@ +/** Agent-preset vocabulary shared by discovery, mounting, and consumers. */ +/** + * Ids a preset directory may use. + * + * The id becomes a path segment, so this is a containment boundary rather than + * a style rule: `..`, a separator, or an absolute-looking name would place the + * composition outside the root the deployment authorised. Discovery shares it: + * a directory whose name no copy could ever claim is not a preset slot. + */ +export const PRESET_ID = /^[a-z0-9][a-z0-9-]*$/; +/** + * No configured root supplies the requested preset. + * + * Separate from a mount failure because the two mean different things to a + * caller: an unknown id is a bad request, while an unusable composition is a + * broken preset the deployment must fix. + */ +export class UnknownPresetError extends Error { + presetId; + available; + constructor( + /** The id that was requested. */ + presetId, + /** Ids the roster does supply, for the caller to offer instead. */ + available) { + super(`agent-presets: preset "${presetId}" not found (available: ${available.join(', ') || 'none'})`); + this.presetId = presetId; + this.available = available; + } +} +/** A preset exists but its composition cannot be installed. */ +export class PresetMountError extends Error { + presetId; + reason; + constructor( + /** The preset whose composition failed. */ + presetId, + /** Why it failed, without this package's own message prefix. */ + reason, options) { + super(`agent-presets: preset "${presetId}" failed to mount: ${reason}`, options); + this.presetId = presetId; + this.reason = reason; + } +} +//# sourceMappingURL=preset.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.d.ts new file mode 100644 index 0000000..7058875 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.d.ts @@ -0,0 +1,47 @@ +/** + * The session-log record of which preset a session actually runs. + * + * The creation header names the preset a session STARTED with, and it is + * deep-frozen because that is a creation fact. A session may still change + * preset while it is blank, and the effect of that change outlives the blank + * window: the first turn — and every turn after it — runs under the newly + * mounted composition. Recording the change is what keeps the log honest, and + * it is required outright by the repo's model-visible ⟺ logged rule, since the + * preset decides the tool schemas and prompt sections the model sees. + * + * Reconstruction reads {@link resolveSessionPreset}, never the header alone. + * @module @deepseek-ai/dsh-agent-presets/session + */ +import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session'; +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * The session's agent preset was chosen after creation, while the session + * was still blank. Log-only: it records the composition later turns ran + * under, so a resumed or forked session rebuilds the same one instead of + * the header's creation-time value. + */ + 'agent-preset/selected': { + agentPreset: string; + }; + } +} +/** The minimum a caller must supply to resolve a session's preset. */ +export interface PresetBearingSession { + /** The session's creation header. */ + readonly header: SessionHeader; + /** The session's event log, oldest first. */ + readonly events: readonly SessionEvent[]; +} +/** + * The preset a session actually runs, newest selection winning. + * + * The header supplies the creation-time value; every later selection is a + * logged event, so the last one is the answer. Reading the header alone + * rebuilds a switched session under the composition it was created with, not + * the one its history was produced under. + * @param session - the session's header and event log. + * @returns the preset id, or `undefined` when the deployment composes none. + */ +export declare function resolveSessionPreset(session: PresetBearingSession): string | undefined; +//# sourceMappingURL=session.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.js new file mode 100644 index 0000000..1fba0cc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/session.js @@ -0,0 +1,33 @@ +/** + * The session-log record of which preset a session actually runs. + * + * The creation header names the preset a session STARTED with, and it is + * deep-frozen because that is a creation fact. A session may still change + * preset while it is blank, and the effect of that change outlives the blank + * window: the first turn — and every turn after it — runs under the newly + * mounted composition. Recording the change is what keeps the log honest, and + * it is required outright by the repo's model-visible ⟺ logged rule, since the + * preset decides the tool schemas and prompt sections the model sees. + * + * Reconstruction reads {@link resolveSessionPreset}, never the header alone. + * @module @deepseek-ai/dsh-agent-presets/session + */ +/** + * The preset a session actually runs, newest selection winning. + * + * The header supplies the creation-time value; every later selection is a + * logged event, so the last one is the answer. Reading the header alone + * rebuilds a switched session under the composition it was created with, not + * the one its history was produced under. + * @param session - the session's header and event log. + * @returns the preset id, or `undefined` when the deployment composes none. + */ +export function resolveSessionPreset(session) { + for (let index = session.events.length - 1; index >= 0; index -= 1) { + const event = session.events[index]; + if (event?.type === 'agent-preset/selected') + return event.data.agentPreset; + } + return session.header.agentPreset; +} +//# sourceMappingURL=session.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.d.ts new file mode 100644 index 0000000..a2193fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.d.ts @@ -0,0 +1,16 @@ +/** Client-safe event declarations owned by the agent-preset domain. */ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * One session committed a different agent preset to its durable log. + * Consumers invalidate only state derived from that session's composition. + * @mode emit + * @param sessionId - the session whose composition changed. + * @param agentPreset - the preset recorded by the committed selection. + */ + 'agent-preset/selected'(sessionId: SessionId, agentPreset: string): void; + } +} +export {}; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.js new file mode 100644 index 0000000..718fd38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/lib/types/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/js-yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/js-yaml new file mode 100755 index 0000000..7cb3d55 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/node_modules/.bin/js-yaml @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +else + exec node "$basedir/../../../../../../js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/package.json new file mode 100644 index 0000000..7aea48f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets/package.json @@ -0,0 +1,73 @@ +{ + "name": "@deepseek-ai/dsh-agent-presets", + "description": "Per-session agent composition from preset cordis.yml files for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/preset/agent-presets" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.7", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "js-yaml": "^4.1.0", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-agent-loop": "^0.1.0-rc.7", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.7", + "@deepseek-ai/dsh-settings-file": "^0.1.0-rc.7", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.7", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-atomic-write b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-atomic-write new file mode 120000 index 0000000..87b5d86 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-atomic-write @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-home-paths b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-home-paths new file mode 120000 index 0000000..1a54918 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-home-paths @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-settings b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-settings new file mode 120000 index 0000000..a0d8497 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-settings @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-system-prompt b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-system-prompt new file mode 120000 index 0000000..943dd86 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-system-prompt @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/js-yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/js-yaml new file mode 120000 index 0000000..87e33ce --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/js-yaml @@ -0,0 +1 @@ +../../js-yaml@4.3.1/node_modules/js-yaml \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.i18n.yaml new file mode 100644 index 0000000..7b36d3c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/agent/README.md +README.md: f6b698e93b254c97786155e7d2c7e81f07c0d981 +README.zh.md: 787c4f353909a1e2dbc60c33abb3c101e677e011 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.md new file mode 100644 index 0000000..f6b698e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.md @@ -0,0 +1,121 @@ +# dsh-agent + +English | [中文](README.zh.md) + +Agent interface, registry, process-local initiator scope, and `agent/*` event vocabulary. Every plugin (UI, hooks, orchestrators) programs against the `Agent` handle defined here — it has zero loop dependency, so the loop is swappable. + +The optional `@deepseek-ai/dsh-agent/invariant` companion registers this package's agent-status transition checks with `ctx.invariants`. The root agent service does not load diagnostics implicitly. + +## Service: `AgentRegistry` (ctx key: `agents`) + +Tracks live agents and carries the initiating Agent through asynchronous driver work without importing the concrete loop package. + +### Public API + +The scoped-registration surface: `Agent.ctx` is the agent's scope context (`dsh-scope`, key = the agent) — register tools/sections/variables/listeners through it for that agent alone, all unwound on disposal. `agentEvents(ctx, agent)` is the fused dispatcher for ordinary agent-subject operations (carrier + injected subject in one move); its notification mode invokes every listener and contains both synchronous throws and returned-promise rejections. The registry lifecycle pair reuses one stable routing carrier. `assembleContextFor(agent)` builds the per-agent assembly context (`agent` + `scope` together). `installModelSelection(agentCtx, selection)` snapshots a mutable provider/model/reasoning-effort selection during prompt assembly, applies its provider and model to prompt variables, and applies the complete selection to request routing for one step; an absent selected effort clears an inherited effort so adapter/provider defaults apply. `CreateAgentOptions.setup(agentCtx)` and `ResumeAgentOptions.setup(agentCtx)` compose a fresh or resumed agent's scoped world while both objects remain unpublished. Setup is trusted, composition-only same-process code: drive the agent only after creation resolves. + +`AgentOptions` supplies the initial provider/model route and an optional positive `maxTokens` output cap. The concrete loop resolves any exact-model adapter default, records the effective cap in the request header, and applies it to each conversation-model request; an explicit Agent option wins, while omission leaves the adapter or provider route default in control. + +- `ctx.agents.register(agent: Agent): () => void` — record an **already-constructed** agent. Disposed with the calling fiber. +- Advanced ordered lifecycle: `enter(agent, owner): () => void` enforces `agent.id === agent.session.id`, performs the authoritative ID collision check, and inserts without announcing; `owner` explicitly records the live creator-agent relation (or `undefined` for a root), independently of durable session lineage. `announce(agent)` emits `agent/created` exactly once. A detach requested synchronously by a creation listener is deferred until that dispatch unwinds, and every detach checks the captured entry object, so a stale capability cannot delete a later same-ID replacement. The async factory uses this split; ordinary plugins use `register()`. +- `ctx.agents.get(id: SessionId): Agent | undefined` +- `ctx.agents.isOwnedBy(id: SessionId, owner: Agent): boolean` — whether the exact live entry was created through that parent agent's scoped context; runtime ownership is independent of durable session lineage. +- `ctx.agents.list(): Agent[]` +- `ctx.agents.roots(): Agent[]` — live agents created without an owning agent context; a resumed lineage-bearing session can still be a runtime root. + +#### Initiating Agent scope + +`AgentLoop` runs each concrete driver's complete lifetime inside an initiator boundary. Concurrent drivers remain isolated: a child driver's continuations carry the child, while the parent continuation regains the parent as soon as `withInitiator()` returns; drain tracking continues until the child driver's Promise settles. Creation, persistence load, and unpublished setup remain outside the child's boundary, so setup initiated by a parent inherits the parent while `agentCtx.agent` identifies the child explicitly. + +- `ctx.agents.currentInitiator(): Agent | undefined` — read the inherited initiator without requiring one. +- `ctx.agents.requireInitiator(): Agent` — read it or throw `no initiating agent is active`. +- `ctx.agents.withInitiator(agent, operation)` — run with one exact Agent and preserve the operation's exact synchronous value or Promise. +- `ctx.agents.withoutInitiator(operation)` — hide an inherited initiator for unrelated process-local work. + +The scope carries the `Agent` itself and is process-local. Ambient presence is neither liveness proof nor authorization; explicit Agent fields remain authoritative at service, worker, process, persistence, and wire boundaries. Teardown rejects new boundaries, lets injected dependents and returned-Promise boundaries drain, then disables the underlying `AsyncLocalStorage`; unreturned work remains owned by the subsystem that detached it. If a boundary's inherited async chain starts an owning Cordis fiber's unload, that nested boundary chain is released from the drain so the unload cannot wait on itself; its continuations observe the disposed service after teardown. The [initiator-scope decision](../../../.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md) owns the detailed boundary and teardown contract. + +#### Factory API (creation) + +Agent *creation* is provided by the plugin implementing `AgentFactory` (`dsh-agent-loop`), registered via `setFactory`. This keeps creation on the `dsh-agent` interface so consumers (UI, the ACP bridge) program against `ctx.agents` without depending on the concrete loop package. The registry canonicalizes an already traced Service to its concrete target and re-traces each call through the caller's context; this avoids nested Cordis shadows while passing an explicit caller-bound `ownerCtx` to plain factories. + +- `ctx.agents.setFactory(factory: AgentFactory): () => void` — register the creation factory (the loop calls this on construction). Throws on a second factory; the slot clears on dispose. +- `ctx.agents.create(options: CreateAgentOptions): Promise` — create a session and agent, await optional setup while unpublished, then publish through final `SessionStore.enter()` and `AgentRegistry.enter()` checks. Concurrent same-ID creation is unsupported: more than one operation may prepare, but only one can enter; every loser rolls its private scope/session/driver back. An optional creation-only `signal` cancels unpublished setup and is detached before the handle is returned; later cancellation uses `handle.dispose()` or `agent.cancel()`. Publication is rollback-covered and every delivered creation edge is paired during rollback. Rejects if no factory is registered. +- `ctx.agents.resume(options: ResumeAgentOptions): Promise` — load a persisted session ([session persistence](../../../.agents/notes/implemented/architecture/2026-06-14-session-persistence.md)), mint a fresh unpublished agent scope, await optional setup, and use the same final-entry publication sequence. Its optional `signal` is likewise creation-only. Rejects if no factory is registered or session persistence is unconfigured. + +`AgentHandle = { agent: Agent; dispose(): Promise }`. The disposer is a **consumer capability** — no observer holding the bare registry entry can tear the agent down. The caller fiber and the registered factory provider are structural co-owners: caller unload enforces structured ownership, while factory unload must stop old instances because their scoped dependency surface belongs to that provider. `dispose()` from any owner reaches one memoized quiescence boundary: it stops the loop, awaits its exit, unregisters the agent, removes its session from the store, and finally unwinds its scoped world. `ctx.agents.get(id)` still returns a bare `Agent`; the ACP bridge and in-process subagent backends hold consumer handles, while config-created agents are already owned by the loop fiber. + +### Live events + +`dsh-agent` declares the live `agent/*` coordination vocabulary so plugins do not depend on the concrete loop. Exact signatures, dispatch modes, scope-filtering rules, and payload contracts live in the generated region of [core.md](../../../docs/subsystems/core.md#cordis-surface); the [architecture turn flow](../../../docs/architecture.md#turn-flow) shows their order relative to durable session events. + +The lifecycle edges have two important local caveats. `agent/created` runs after scoped setup and after both session and agent registry entries exist. Setup is trusted composition-only code; the immediately following non-vetoing `agent/session-start` notification is the first supported startup injection point. `agent/disposed` always means the exact agent has left the registry. AgentLoop emits it after its driver is quiescent, while ordered teardown may still be detaching the session and unwinding the scope; custom agents registered directly own any stronger driver-ordering contract themselves. + +Most interception points are cooperative waterfalls. `agent/pre-step` receives a payload carrying the subject `agent`, the exclusive claimed `UserMessage[]`, and the proposed `turn`, `step`, and cancellation `signal`; its batch may be empty when tools already require another request. Agent-scoped turn extension points carry their explicit `AbortSignal` in the payload; the remaining turn-scoped extension points receive it through their request value. Listeners may cooperate with a signal but must not retain it as authority over another turn. `agent/request-error` is the failed-model-request recovery waterfall: it receives request coordinates, normalized failure facts, the serving registration's retry policy when available, and the signal. A listener returns `{ kind: 'retry' }` without calling `next()` when it owns recovery. `agent/turn-stopping` runs before an otherwise completed turn closes. The [explicit-cancellation decision](../../../.agents/notes/implemented/architecture/2026-07-16-explicit-turn-cancellation.md) owns signal lifetime; the [agent-scope runtime-design Agent Note](../../../.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#three-execution-boundaries-are-deliberately-one-way) owns scoped dispatch and terminal settlement. + +`PreStepDecision` is either `{ kind: 'reject' }` or `{ kind: 'enter', messages }`. The enter branch is the complete identified, frozen batch for the proposed step. A listener that wraps downstream entry preserves that batch unless it intentionally replaces it; additions follow the waterfall's natural return order. Claiming already removed the offered messages from the inbox, so rejection does not retain them. Messages inserted after the claim remain pending for a later boundary. + +Inbox live notifications are deliberately per-message and minimal: `agent/inbox/inserted { message }`, `agent/inbox/claimed { message, turn }`, and `agent/inbox/discarded { message }`. They complement the durable `agent/inbox/spliced` projection without adding another lifecycle envelope. + +Turn and step boundaries and the model token stream are durable `session/event` facts rather than mirrored `agent/*` notifications. Consumers read `turn/*`, `step/*`, and `assistant/chunk` from the session feed; tool policy and outcome observation belong to the complete pipeline documented by [`dsh-tools`](../tools/README.md). + +`foldConsumedWork(events)` reads that feed back for the one question the turn sequence cannot answer alone: what became of the work a log consumed. It returns the latest `turn/end` that accounts for consumed work — a turn that entered a model step, or one that claimed inbox input and then failed, was stopped, or was rejected before reaching one — plus whether accepted work was later cancelled out of the inbox unrun. Both facts come from the log, so a cancellation reads the same whichever owner issued it. A no-step turn that took nothing, or emptied its claim and completed, describes no work and is skipped; a `blocked` end over claimed input is an account, because rejection discarded that input. + +### Agent interface (`types.ts`) + +The handle every plugin programs against: + +- `agent.inbox` — the agent-owned projection of durable `agent/inbox/spliced` events. `nextTurn` and `nextStep` expose pending `UserMessage` values. `append`, `prepend`, `replace`, `remove`, `clear`, `splice`, and `claim` mutate them; `replace(messageId, newMessage)` and `remove(messageId)` locate the pending message across both lists. Replacement may change identity and publishes the old message as discarded followed by the new message as inserted. Ordinary removals and `clear()` are durable cancellations and emit `agent/inbox/discarded`. `claim(target)` removes the next proposed batch with pure deletion splices; the loop then emits `agent/inbox/claimed`. `MessageId` is the only occurrence identity and must remain unique while pending. +- `agent.followup(message)` — queue an ordinary `next-turn` message and wake the driver. It returns no completion handle; the message id identifies inbox insertion, claim, and discard facts, not a later output or `turn/end`. +- `agent.steer(message)` — queue waking `next-step` input. An idle agent starts a turn synchronously; a running driver consumes later steering at its next step boundary. +- `agent.inject(message)` — queue non-waking `next-step` context. A running driver claims it at the nearest later pre-step boundary; an idle driver leaves it pending until `followup()` or `steer()` wakes the driver. It may miss a request whose pre-step already claimed its batch. +- `agent.cancel(cause, options?)` — cancel the active driver and, unless `options.keepInbox`, durably cancel all pending inbox work. Idle cancellation is a no-op. +- `agent.whenIdle()` — observe whole-agent quiescence, including replacement work scheduled before the current driver retires. It does not settle any particular message. +- `agent.session`, `agent.status`, `agent.options`, `agent.id`, `agent.ctx` + +`running` describes a driver-wide drain interval, not proof that a turn is still open; it can cover turn close, the durability checkpoint, and consecutive queued turns. Only a caller that owns a complete interval may summarize it as a run result ([decision](../../../.agents/notes/implemented/architecture/2026-07-30-followup-enqueue-and-owned-runs.md)). + +### Extension points + +- Agent creation: `AgentLoop.create()` is the concrete config-path implementation (in `dsh-agent-loop`), while programmatic consumers create/resume owned agents through `ctx.agents.create()` / `ctx.agents.resume()`. Replace the loop by implementing `Agent` and registering via `ctx.agents.register()`. +- Event listeners: all `agent/*` events are declared here — no dependency on the loop package needed. +- Subagent delegation is not an `Agent` method; providers create or drive ordinary handles through the factory API, so delegation transports stay outside the core agent interface. + +## Model Experience + +### User, steering, and injected messages + +#### What the model sees + +`send`, `steer`, and `inject` feed the owning session. `agent/pre-step` and other declared events let plugins reject a proposed step or add durable request material; this interface contributes no fixed prose itself. + +#### Token effect + +Accepted content becomes retained history or a repeated session prefix; blocked content contributes no request tokens. Size is caller- and plugin-dependent. + +#### KV Cache effect + +Accepted history and steering are append-only; a blocked submission sends no request. A session prefix remains stable within its loop instance, while a new or resumed instance may establish a different prefix. + +### Agent-scoped request composition + +#### What the model sees + +Registrations through `agent.ctx` can shadow prompt sections or tools and can install agent-only interceptors during unpublished setup. + +#### Token effect + +The package adds zero tokens itself; scoped contributions affect only that agent and disappear on disposal. + +#### KV Cache effect + +Prefix-stable while an agent's scoped registrations are unchanged. Setup or reload that changes prompt sections, tool definitions, or request listeners may invalidate reuse from the first affected request token. + +## Known Limitations and Deferred Work + +- **Initiator scope is process-local** — workers, child processes, HTTP, durable queues, and restarts materialize any required identity explicitly. +- **Ambient identity may outlive liveness** — consumers still check `agent.status`, cancellation, and the owning capability contract before lifecycle-sensitive work. +- **Inter-agent channels beyond delegation** — shared state, streaming child output, and background/poll semantics remain outside the current synchronous `ctx.subagents` seam. +- **`agent/session-start` cannot gate startup** — it remains a synchronous, veto-less notification; async composition that must finish before publication belongs in the factory's `setup(agentCtx)` transaction instead. +- **`cancel()` clears the inbox by default** — it aborts the in-flight turn plus queued and steering work; `cancel(cause, { keepInbox: true })` aborts only the turn and preserves pending items. There is still no step-only abort that keeps the in-flight turn running ([stop API Agent Note](../../../.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-api.md)). +- **Each additional `UserMessage` carries exactly one `MessageSource`** — contributions from several plugins merged onto one tool call collapse under one source, so the message cannot name several producers. +- **`SessionStartSource` reserves `'clear'`/`'compact'` with no emitter yet** — only `'startup'`/`'resume'` occur until the driving subsystems land (`TODO(compaction)`). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.zh.md new file mode 100644 index 0000000..787c4f3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/README.zh.md @@ -0,0 +1,121 @@ +# dsh-agent + +[English](README.md) | 中文 + +Agent 接口、注册表、进程本地发起方作用域,以及 `agent/*` 事件词汇。每个插件(UI、钩子、编排器)都面向此处定义的 `Agent` handle 编程;它不依赖循环,因此循环可以替换。 + +可选配套包 `@deepseek-ai/dsh-agent/invariant` 会向 `ctx.invariants` 注册此包的 agent(智能体)状态转换检查。根 agent 服务不会隐式加载诊断。 + +## 服务:`AgentRegistry`(ctx 键:`agents`) + +跟踪实时 agent,并在异步驱动器工作中携带发起调用的 Agent,而无需导入具体循环包。 + +### 公开 API + +带作用域的注册接口:`Agent.ctx` 是 agent 的作用域上下文(`dsh-scope`,键 = 该 agent)。通过它注册工具/段/变量/监听器,只对该 agent 生效,并在 dispose(资源释放)时全部撤销。`agentEvents(ctx, agent)` 是普通 agent 主体操作的融合分发器(一次完成载体 + 注入主体);其通知 mode 会调用每个监听器,并同时收容同步抛出和返回 Promise 的拒绝。注册表生命周期对复用一个稳定路由载体。`assembleContextFor(agent)` 构建按 agent 的组装上下文(同时包含 `agent` + `scope`)。`installAgentLlmTarget(agentCtx, target)` 在提示词组装期间快照可变的提供方/模型/推理(reasoning)强度选择,将路由应用到提示词变量,并将完整目标应用到一个步骤的请求路由;如果没有选定推理强度,则会清除继承的推理强度,使该目标使用适配器/提供方默认值。`CreateAgentOptions.setup(agentCtx)` 和 `ResumeAgentOptions.setup(agentCtx)` 在新建或恢复的 agent 尚未发布时,组合其带作用域的世界。Setup 是受信任、仅用于组合的同进程代码:只有创建完成后才能驱动 agent。 + +`AgentOptions` 提供初始的提供方/模型路由,以及可选的正数 `maxTokens` 输出上限。具体循环会解析确切模型的适配器默认值,把生效上限记录到请求 header,并应用到每次对话模型请求;显式 Agent 选项优先,省略时由适配器或提供方路由默认值控制。 + +- `ctx.agents.register(agent: Agent): () => void`:记录一个 **已经构造完成** 的 agent。随调用 fiber dispose。 +- 高级有序生命周期:`enter(agent, owner): () => void` 强制 `agent.id === agent.session.id`,执行权威 ID 冲突检查,并在不通知的情况下插入;`owner` 显式记录实时创建方 agent 关系(根 agent 为 `undefined`),与持久会话谱系无关。`announce(agent)` 恰好发出一次 `agent/created`。创建监听器同步请求的 detach 会延后到该次分发结束;每次 detach 都会检查捕获的条目对象,因此陈旧能力无法删除后续使用同一 ID 的替代项。异步工厂使用这一拆分;普通插件使用 `register()`。 +- `ctx.agents.get(id: SessionId): Agent | undefined` +- `ctx.agents.isOwnedBy(id: SessionId, owner: Agent): boolean`:该确切实时条目是否通过父 agent 的作用域上下文创建;运行时所有权与持久会话谱系无关。 +- `ctx.agents.list(): Agent[]` +- `ctx.agents.roots(): Agent[]`:在没有所属 agent 上下文的情况下创建的实时 agent;带谱系的恢复会话仍可能是运行时根。 + +#### 发起方 Agent 作用域 + +`AgentLoop` 在发起方边界内运行每个具体驱动器的完整生命周期。并发驱动器彼此隔离:子驱动器的 continuation 携带子 agent,而 `withInitiator()` 返回后,父 continuation 立即重新取得父 agent;drain 跟踪持续到子驱动器的 Promise 结算。创建、持久化加载和未发布 setup 位于子边界之外,因此由父 agent 发起的 setup 会继承父 agent,而 `agentCtx.agent` 显式标识子 agent。 + +- `ctx.agents.currentInitiator(): Agent | undefined`:读取继承的发起方,不要求其存在。 +- `ctx.agents.requireInitiator(): Agent`:读取发起方,缺席时抛出 `no initiating agent is active`。 +- `ctx.agents.withInitiator(agent, operation)`:使用一个确切 Agent 运行,并保留操作的确切同步值或 Promise。 +- `ctx.agents.withoutInitiator(operation)`:对无关的进程本地工作隐藏继承的发起方。 + +该作用域携带 `Agent` 本身,并且只在进程内有效。环境中的身份既不是存活证明,也不是授权;在服务、worker、进程、持久化和 wire 边界,显式 Agent 字段仍是权威来源。Teardown 会拒绝新边界,允许注入的依赖方和返回 Promise 的边界 drain,然后禁用底层 `AsyncLocalStorage`;未返回的工作仍归将其分离的子系统所有。如果某个边界继承的异步链开始卸载一个拥有它的 Cordis fiber,该嵌套边界链会从 drain 中释放,使卸载不会等待自身;其 continuation 会在 teardown 后观察到已 dispose 的服务。详细边界与 teardown 约定由[发起方作用域决策](../../../.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md)拥有。 + +#### 工厂 API(创建) + +Agent *创建* 由实现 `AgentFactory` 的插件(`dsh-agent-loop`)提供,并通过 `setFactory` 注册。这样,创建功能留在 `dsh-agent` 接口上,消费方(UI、ACP(Agent Client Protocol)桥接层)可以面向 `ctx.agents` 编程,而不依赖具体循环包。注册表会把已经 traced 的 Service 规范化为具体目标,并通过调用方上下文重新 trace 每次调用;这既避免嵌套 Cordis shadow,也会把显式、绑定调用方的 `ownerCtx` 传给普通工厂。 + +- `ctx.agents.setFactory(factory: AgentFactory): () => void`:注册创建工厂(循环在构造时调用)。第二个工厂会导致抛出;dispose 时清空槽位。 +- `ctx.agents.create(options: CreateAgentOptions): Promise`:创建会话和 agent,在不发布的情况下等待可选 setup,然后通过最终的 `SessionStore.enter()` 与 `AgentRegistry.enter()` 检查发布。不支持并发创建同一 ID:多个操作可以进行准备,但只有一个能进入;每个失败方都会回滚其私有作用域/会话/驱动器。可选且只用于创建的 `signal` 会取消未发布的 setup,并在返回 handle 前分离;之后的取消使用 `handle.dispose()` 或 `agent.cancel()`。发布包含在回滚范围内,回滚期间每条已交付创建边都会成对处理。未注册工厂时拒绝。 +- `ctx.agents.resume(options: ResumeAgentOptions): Promise`:加载持久化会话([会话持久化](../../../.agents/notes/implemented/architecture/2026-06-14-session-persistence.md)),创建新的未发布 agent 作用域,等待可选 setup,并使用相同的最终进入发布序列。其可选 `signal` 同样只用于创建。未注册工厂或未配置会话持久化时拒绝。 + +`AgentHandle = { agent: Agent; dispose(): Promise }`。Disposer 是一项 **消费方能力**;仅持有裸注册表条目的观察方不能 teardown agent。调用方 fiber 和已注册工厂提供方是结构化共同拥有者:调用方卸载会强制结构化所有权,而工厂卸载必须停止旧实例,因为它们的作用域依赖范围属于该提供方。任意拥有者调用 `dispose()` 都会到达同一个记忆化完全停稳边界:它停止循环,等待循环退出,注销 agent,从存储中移除其会话,最后撤销其作用域世界。`ctx.agents.get(id)` 仍返回裸 `Agent`;ACP 桥接层与进程内 subagent 后端持有消费方 handle,而配置创建的 agent 已由循环 fiber 拥有。 + +### 实时事件 + +`dsh-agent` 声明实时 `agent/*` 协调词汇,使插件不必依赖具体循环。确切签名、分发 mode、作用域筛选规则与 payload 约定位于 [core.md](../../../docs/subsystems/core.md#cordis-surface) 的生成区块;[架构轮次流](../../../docs/architecture.md#turn-flow) 展示它们与持久会话事件的相对顺序。 + +生命周期边有两个重要的本地注意事项。`agent/created` 在作用域 setup 之后、会话与 agent 注册表条目都存在之后运行。Setup 是受信任、仅用于组合的代码;紧随其后且不可 veto 的 `agent/session-start` 通知是第一个受支持的启动注入点。`agent/disposed` 始终表示确切 agent 已离开注册表。AgentLoop 在其驱动器完全停稳后发出该事件,而有序 teardown 此时可能仍在分离会话并撤销作用域;直接注册的自定义 agent 自行拥有任何更强的驱动器顺序约定。 + +大多数拦截点都是协作式 waterfall(瀑布式事件)。`agent/pre-step` 接收一个 payload,携带主体 `agent`、独占的已领取 `UserMessage[]` 以及拟进入的 `turn`、`step` 与取消 `signal`;当工具已经要求继续请求时,该批次可以为空。agent 作用域轮次扩展点在 payload 中携带显式 `AbortSignal`;其余轮次作用域扩展点通过其请求值接收它。监听器可以配合信号,但不得将它保留为控制另一轮次的权限。`agent/request-error` 是失败模型请求的恢复 waterfall:它接收请求坐标、规范化失败事实、可用时提供服务的注册项重试策略以及信号。拥有恢复权的监听器返回 `{ kind: 'retry' }` 且不调用 `next()`。`agent/turn-stopping` 在本可完成的轮次关闭前运行。信号生命周期由[显式取消决策](../../../.agents/notes/implemented/architecture/2026-07-16-explicit-turn-cancellation.md)拥有;作用域分发与终止结算由 [agent 作用域 runtime 设计 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#three-execution-boundaries-are-deliberately-one-way)拥有。 + +`PreStepDecision` 要么是 `{ kind: 'reject' }`,要么是 `{ kind: 'enter', messages }`。enter 分支是拟进入步骤的完整、带标识且冻结的批次。包装下游 enter 的监听器会保留该批次,除非有意替换它;新增消息遵循 waterfall 的自然返回顺序。领取操作已经把候选消息从 inbox 删除,因此 reject 不会保留它们;领取后插入的消息仍等待后续边界。 + +inbox 的实时通知刻意采用逐消息的最小载荷:`agent/inbox/inserted { message }`、`agent/inbox/claimed { message, turn }` 与 `agent/inbox/discarded { message }`。它们补充持久 `agent/inbox/spliced` 投影,但不引入另一层生命周期封套。 + +轮次和步骤边界以及模型 token 流是持久 `session/event` 事实,而不是镜像的 `agent/*` 通知。消费方从会话事件流读取 `turn/*`、`step/*` 和 `assistant/chunk`;工具策略与结果观测属于 [`dsh-tools`](../tools/README.md) 记录的完整流水线。 + +`foldConsumedWork(events)` 把这条事件流读回来,回答仅凭轮次序列无法回答的那个问题:一份日志消费掉的工作最终怎样了。它返回能够为已消费工作作出交代的最新 `turn/end`——即进入过模型 step 的轮次,或者认领了 inbox 输入、但在进入 step 之前失败、被停下或被拒绝的轮次——并额外给出「已接受的工作此后是否被从 inbox 中取消且从未运行」。两项事实都来自日志,因此无论由哪个所有者发起取消,读出来都一样。没有取走任何输入、或认领批次被改写清空后正常结束的无 step 轮次不描述工作,会被跳过;认领过输入、以 `blocked` 结束的轮次则是一份交代,因为拒绝把这些输入一并丢弃了。 + +### Agent 接口(`types.ts`) + +每个插件面向的 handle: + +- `agent.inbox`:agent 所拥有的持久 `agent/inbox/spliced` 事件投影。`nextTurn` 与 `nextStep` 暴露待处理的 `UserMessage` 值。`append`、`prepend`、`replace`、`remove`、`clear`、`splice` 与 `claim` 用于变更队列;`replace(messageId, newMessage)` 与 `remove(messageId)` 通过 `MessageId` 跨两份列表定位待处理消息。替换可以改变标识,并先将旧消息作为 discarded 发布,再将新消息作为 inserted 发布。普通删除和 `clear()` 都是持久取消,并发出 `agent/inbox/discarded`。`claim(target)` 通过纯删除 splice 移除下一个候选批次,随后由循环发出 `agent/inbox/claimed`。`MessageId` 是唯一的入队项标识,在消息待处理期间必须保持唯一。 +- `agent.followup(message)`:将一条普通 `next-turn` 消息排队并唤醒驱动器。它不返回完成 handle;消息 id 标识 inbox 的插入、领取与丢弃事实,而不标识之后的输出或 `turn/end`。 +- `agent.steer(message)`:将会唤醒的 `next-step` steering(中途引导)输入排队。agent 空闲时会同步启动一个轮次;驱动器运行期间收到的后续 steering 会在下一个步骤边界被消费。 +- `agent.inject(message)`:将不会唤醒的 `next-step` 上下文排队。运行中的驱动器会在最近的后续 pre-step 边界领取它;idle 驱动器则会让它保持待处理,直至 `followup()` 或 `steer()` 唤醒驱动器。若某次请求的 pre-step 已经领取完批次,它可能赶不上该请求。 +- `agent.cancel(cause, options?)`:取消活跃驱动器,并在未设置 `options.keepInbox` 时持久取消全部待处理 inbox 工作。空闲取消是空操作。 +- `agent.whenIdle()`:观察整个 agent 达到完全停稳,包括当前驱动器退役前调度的替代工作。它不结算任何特定消息。 +- `agent.session`、`agent.status`、`agent.options`、`agent.id`、`agent.ctx` + +`running` 描述驱动器范围的 drain 区间,而不是轮次仍打开的证明;它可以覆盖轮次关闭、持久性检查点和连续的排队轮次。只有拥有完整区间的调用方才能将其概括为一次运行的结果([决策](../../../.agents/notes/implemented/architecture/2026-07-30-followup-enqueue-and-owned-runs.md))。 + +### 扩展点 + +- Agent 创建:`AgentLoop.create()` 是具体配置路径实现(位于 `dsh-agent-loop`),程序化消费方则通过 `ctx.agents.create()`/`ctx.agents.resume()` 创建或恢复有所有权的 agent。替换循环时,应实现 `Agent` 并通过 `ctx.agents.register()` 注册。 +- 事件监听器:全部 `agent/*` 事件都在此处声明,不需要依赖循环包。 +- subagent 委派不是 `Agent` 方法;提供方通过工厂 API 创建或驱动普通 handle,因此委派传输留在核心 agent 接口之外。 + +## 模型体验 + +### 用户、steering 与注入消息 + +#### 模型看到的内容 + +`send`、`steer` 与 `inject` 会向所属会话提供输入。`agent/pre-step` 和其他已声明事件让插件能够拒绝拟进入的步骤或添加持久请求材料;此接口本身不贡献固定文案。 + +#### Token 影响 + +已接受内容成为保留历史,或成为每次请求都会重复的会话前缀;被阻止内容不贡献请求 token。大小取决于调用方与插件。 + +#### KV Cache 影响 + +已接受历史与 steering 只追加;被阻止的提交不发送请求。会话前缀在循环实例内保持稳定,而新建或恢复的实例可能建立不同前缀。 + +### Agent 作用域的请求组合 + +#### 模型看到的内容 + +通过 `agent.ctx` 进行的注册可以遮蔽提示词段或工具,也可以在未发布 setup 期间安装仅适用于该 agent 的拦截器。 + +#### Token 影响 + +此包自身不增加 token;带作用域贡献只影响该 agent,并在 dispose 时消失。 + +#### KV Cache 影响 + +只要 agent 的作用域注册不变,前缀就保持稳定。改变提示词段、工具定义或请求监听器的 setup 或 reload,可能从第一个受影响的请求 token 起使复用失效。 + +## 已知限制与暂缓事项 + +- **发起方作用域只存在于进程内**:worker、子进程、HTTP、持久队列和重启必须显式传递所需身份。 +- **环境身份可能比存活状态更久**:消费方在生命周期敏感工作前,仍要检查 `agent.status`、取消状态和所属能力约定。 +- **委派以外的 agent 间通道**:共享状态、流式子输出和后台/轮询语义仍在当前同步 `ctx.subagents` seam 之外。 +- **`agent/session-start` 不能为启动设置门禁**:它仍是同步且不可 veto 的通知;必须在发布前完成的异步组合属于工厂的 `setup(agentCtx)` 事务。 +- **`cancel()` 默认清空 inbox**:它会中止正在处理的轮次以及排队和 steering 工作;`cancel(cause, { keepInbox: true })` 只中止轮次并保留待处理项。仍不存在只中止步骤、同时让正在处理的轮次继续运行的操作([停止 API Agent Note](../../../.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-api.md))。 +- **每条附加 `UserMessage` 恰好携带一个 `MessageSource`**:多个插件合并到一次工具调用上的贡献会归入同一来源,因此该消息无法列出多个生产者。 +- **`SessionStartSource` 预留 `'clear'`/`'compact'`,但还没有发出方**:在驱动子系统落地前,只会出现 `'startup'`/`'resume'`(`TODO(compaction)`)。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/index.js new file mode 100644 index 0000000..29202f1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/index.js @@ -0,0 +1,794 @@ +import { Service, getTraceable, symbols } from "@deepseek-ai/cordis"; +import { AsyncLocalStorage } from "node:async_hooks"; +import { isPromise } from "node:util/types"; +import { scopeTarget } from "@deepseek-ai/dsh-scope"; +//#region lib/types/inbox.js +/** +* Incremental projection of durable agent inbox events. +* +* @module @deepseek-ai/dsh-agent/inbox +*/ +/** A replay-once projection that incrementally consumes later inbox splices. */ +var Inbox = class { + session; + notifications; + state = { + "next-turn": [], + "next-step": [] + }; + constructor(session, notifications) { + this.session = session; + this.notifications = notifications; + for (const event of session.events.slice(session.header.seedLength ?? 0)) { + if (event.type !== "agent/inbox/spliced") continue; + try { + this.apply(event.data); + } catch (error) { + throw new Error(`invalid persisted inbox splice at session seq ${event.seq}`, { cause: error }); + } + } + } + /** Prompts awaiting individual turns. */ + get nextTurn() { + return this.state["next-turn"]; + } + /** Input awaiting the next step boundary. */ + get nextStep() { + return this.state["next-step"]; + } + /** Whether either pending-message list contains work. */ + get hasPending() { + return this.nextTurn.length > 0 || this.nextStep.length > 0; + } + /** Durably cancel all pending input, clearing next-step before next-turn. */ + clear() { + this.splice("next-step", 0, this.nextStep.length, []); + this.splice("next-turn", 0, this.nextTurn.length, []); + } + /** + * Remove and return the complete batch proposed for one step, publishing + * each claimed message. The durable splices are pure deletions. + * @param target - whether this boundary also consumes one queued turn. + * @param turn - turn that will own the claimed batch. + * @returns next-step input followed by the queued turn, when requested. + * @internal - The agent loop's step-boundary operation, not a plugin extension point. + */ + claim(target, turn) { + const claimed = this.mutate("next-step", 0, this.nextStep.length, [], false); + if (target === "next-turn") claimed.push(...this.mutate("next-turn", 0, 1, [], false)); + for (const message of claimed) this.notifications.claimed(message, turn); + return claimed; + } + /** + * Append one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to append. + * @throws if the message identity is already pending. + */ + append(target, message) { + this.splice(target, this.state[target].length, 0, [message]); + } + /** + * Prepend one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to prepend. + * @throws if the message identity is already pending. + */ + prepend(target, message) { + this.splice(target, 0, 0, [message]); + } + /** + * Replace one pending message in place, possibly changing its identity. A + * successful replacement publishes the old message as discarded and the new + * message as inserted. + * @param messageId - identity of the pending message to replace. + * @param newMessage - replacement message. + * @returns whether the message was still pending. + * @throws if the replacement duplicates another pending message identity. + */ + replace(messageId, newMessage) { + const location = this.locate(messageId); + if (location === void 0) return false; + this.splice(location.target, location.index, 1, [newMessage]); + return true; + } + /** + * Remove one pending message and durably record its cancellation. + * @param messageId - identity of the pending message to remove. + * @returns whether the message was still pending. + */ + remove(messageId) { + const location = this.locate(messageId); + if (location === void 0) return false; + this.splice(location.target, location.index, 1, []); + return true; + } + /** + * Apply standard splice semantics and durably record the normalized result. + * The durable event commits before the live projection mutates, so synchronous + * `session/event` observers see the pre-splice lists and can reconstruct the + * removed messages from the normalized coordinates. + * @param target - pending list to mutate. + * @param start - splice position. + * @param deleteCount - maximum number of messages to remove. + * @param inserted - messages to insert at the resolved position. + * @returns messages removed by the splice. + */ + splice(target, start, deleteCount, inserted) { + return this.mutate(target, start, deleteCount, inserted, true); + } + /** Locate one pending identity across both owned lists. */ + locate(messageId) { + for (const target of ["next-turn", "next-step"]) { + const index = this.state[target].findIndex((message) => message.id === messageId); + if (index >= 0) return { + target, + index + }; + } + } + /** Commit one normalized mutation and publish its live notifications. */ + mutate(target, start, deleteCount, inserted, discardRemoved) { + const inbox = this.state[target]; + const truncatedStart = Math.trunc(start); + const offset = Number.isNaN(truncatedStart) ? 0 : truncatedStart; + const actualStart = offset < 0 ? Math.max(inbox.length + offset, 0) : Math.min(offset, inbox.length); + const truncatedDeleteCount = Math.trunc(deleteCount); + const actualDeleteCount = Math.min(Math.max(Number.isNaN(truncatedDeleteCount) ? 0 : truncatedDeleteCount, 0), inbox.length - actualStart); + if (actualDeleteCount === 0 && inserted.length === 0) return []; + const outcome = discardRemoved && actualDeleteCount > 0 ? "canceled" : void 0; + const splice = { + target, + start: actualStart, + ...actualDeleteCount === 0 ? {} : { removedCount: actualDeleteCount }, + inserted, + ...outcome === void 0 ? {} : { outcome } + }; + this.validate(splice); + const event = this.session.append("agent/inbox/spliced", splice); + const removed = inbox.splice(actualStart, actualDeleteCount, ...event.data.inserted); + if (discardRemoved) for (const message of removed) this.notifications.discarded(message); + for (const message of event.data.inserted) this.notifications.inserted(message); + return removed; + } + /** Apply one normalized durable splice to the projection. */ + apply(splice) { + this.validate(splice); + return this.state[splice.target].splice(splice.start, splice.removedCount ?? 0, ...splice.inserted); + } + /** Validate one normalized splice against the current projection. */ + validate(splice) { + const inbox = this.state[splice.target]; + const removedCount = splice.removedCount ?? 0; + if (!Number.isSafeInteger(splice.start) || splice.start < 0 || splice.start > inbox.length || !Number.isSafeInteger(removedCount) || removedCount < 0 || splice.start + removedCount > inbox.length) throw new Error("invalid inbox splice"); + const candidate = inbox.toSpliced(splice.start, removedCount, ...splice.inserted); + const ids = /* @__PURE__ */ new Set(); + for (const message of splice.target === "next-turn" ? [...candidate, ...this.nextStep] : [...this.nextTurn, ...candidate]) { + if (ids.has(message.id)) throw new Error(`message "${message.id}" is already pending`); + ids.add(message.id); + } + } +}; +//#endregion +//#region lib/types/consumed-work.js +/** +* How one agent log accounts for the work it consumed. +* +* The turn and step vocabulary alone cannot answer this. A turn that stops +* before its first step leaves a `turn/end` shaped exactly like the balanced +* no-op turns a rejection or an empty claim produces, so reading turns in +* isolation either credits cut-short work as finished or convicts every no-op. +* The missing fact is the inbox's own record: {@link Inbox} logs each mutation +* with `removedCount` and marks a cancellation `outcome: 'canceled'`, which +* separates a turn claiming its input from work being dropped unrun. +* +* @module @deepseek-ai/dsh-agent/consumed-work +*/ +/** +* Whether a turn that consumed input but never reached a step ends in a way +* that accounts for that input. Only a `completed` end does not: it had +* nothing left to run once its claim was rewritten away. A `blocked` end is +* that input's ending too — the pre-step rejection that produced it discarded +* the claimed messages, so the work it took will never run. +* @param reason - the turn's recorded ending. +* @returns whether the ending accounts for the input the turn took. +*/ +function accountsForClaim(reason) { + switch (reason.kind) { + case "completed": return false; + case "blocked": + case "aborted": + case "interrupted": + case "error": return true; + /* v8 ignore next 4 -- unreachable: the one unnamed built-in, `max-tokens`, requires a step, + * so its turn short-circuits as stepped before this call, and `TurnEndReasonMap` is + * merge-extensible, so a backend-added variant cannot be listed; an unnameable ending over + * consumed input must not read as success. */ + default: return true; + } +} +/** +* Fold one agent log, or an owned suffix of one, into its account of consumed +* work. Single pass, and every input is the log itself: no caller has to sample +* live state before cancelling, so a cancellation issued by anyone — the owner's +* teardown, an ancestor's interrupt, an unloading plugin — reads the same. +* @param events - the log, or an owned suffix, to fold. +* @returns the accounting turn when one closed, and whether work was dropped unrun after it. +*/ +function foldConsumedWork(events) { + const stepped = /* @__PURE__ */ new Set(); + const claimed = /* @__PURE__ */ new Set(); + let open; + let end; + let droppedUnrun = false; + for (const event of events) switch (event.type) { + case "turn/start": + open = event.data.turn; + break; + case "step/start": + stepped.add(event.data.turn); + break; + case "agent/inbox/spliced": { + const { removedCount, outcome, inserted } = event.data; + if (removedCount === void 0) break; + if (outcome === "canceled") droppedUnrun ||= inserted.length === 0; + else if (open !== void 0) claimed.add(open); + break; + } + case "turn/end": { + const { turn, reason } = event.data; + open = void 0; + if (stepped.delete(turn) || claimed.delete(turn) && accountsForClaim(reason)) { + end = event; + droppedUnrun = false; + } + break; + } + default: break; + } + return { + ...end === void 0 ? {} : { end }, + droppedUnrun + }; +} +//#endregion +//#region lib/types/model-selection.js +/** +* Agent-scoped model selection shared by runtime entry points. +* @module @deepseek-ai/dsh-agent/model-selection +*/ +/** +* Couple one mutable selection to Agent-scoped prompt assembly and request routing. +* Prompt assembly snapshots the selected model before delegating, then applies +* its provider/model pair and effort to request config so a +* concurrent switch takes effect on a later step instead of splitting the two +* surfaces. An absent selected effort clears any inherited effort, restoring +* the selected model's provider/default behavior. +* +* @param agentCtx - The selected Agent's scoped context. +* @param selection - Mutable selection owned by the calling entry point. +* @returns Disposer for both scoped waterfall listeners. +*/ +function installModelSelection(agentCtx, selection) { + const disposeAssembly = agentCtx.on("system-prompt/assemble", async (_assembly, _context, next) => { + const selected = selection.current; + const assembled = await next(); + selection.assembled = selected; + if (selected === void 0) return assembled; + return { + ...assembled, + variables: { + ...assembled.variables, + provider: selected.provider, + model: selected.model + } + }; + }); + const disposeRequest = agentCtx.on("agent/request", async (_payload, next) => { + const resolved = await next(); + const selected = selection.assembled; + if (selected === void 0) return resolved; + const { reasoningEffort: _inheritedEffort, ...withoutInheritedEffort } = resolved; + return { + ...withoutInheritedEffort, + provider: selected.provider, + model: selected.model, + ...selected.reasoningEffort === void 0 ? {} : { reasoningEffort: selected.reasoningEffort } + }; + }); + return () => { + disposeAssembly(); + disposeRequest(); + }; +} +//#endregion +//#region lib/types/dispatch.js +/** +* Agent-scoped dispatch and prompt assembly helpers. The fused dispatcher +* {@link agentEvents} couples the agent subject to its scope carrier, so the +* scope key and the payload's `agent` cannot diverge; repeat dispatchers (the +* loop driver) build it once in the agent's constructor and reuse it. +* @module @deepseek-ai/dsh-agent/dispatch +*/ +/** +* Build the fused scope carrier for one agent subject. +* +* The carrier is a stateless routing object. {@link agentEvents} accepts an +* existing carrier, so callers that dispatch repeatedly for the same agent +* (the loop driver) build it once in the agent's constructor and reuse it, +* keeping hot-path dispatches allocation-free. +* @param agent - the subject agent and scope key. +* @returns the carrier passed as the event dispatcher `this` value. +*/ +function agentCarrier(agent) { + return scopeTarget(agent, agent); +} +/** +* Build a dispatcher that couples the agent subject to its scope carrier. +* @param ctx - the context to dispatch through (any context of the app). +* @param agent - the subject agent; also the scope-carrier key. +* @param carrier - the scope carrier to dispatch through; defaults to +* {@link agentCarrier} for the agent. Pass a constructor-built carrier to +* avoid rebuilding it for every dispatch. +* @returns the fused dispatcher. +*/ +function agentEvents(ctx, agent, carrier = agentCarrier(agent)) { + const fused = (payload) => ({ + ...payload, + agent + }); + return { + emit(name, payload) { + const args = [ + carrier, + name, + fused(payload) + ]; + const callbacks = ctx.events.dispatch("emit", args); + for (const callback of callbacks) try { + const returned = callback(...args); + Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`agent event "${name}" listener rejected: ${String(error)}`); + }); + } catch (error) { + ctx.logger.warn(`agent event "${name}" listener threw: ${String(error)}`); + } + }, + async serial(name, payload) { + const serial = ctx.serial; + return await serial(carrier, name, fused(payload)); + }, + waterfall(name, payload, ...rest) { + const waterfall = ctx.waterfall; + return waterfall(carrier, name, fused(payload), ...rest); + } + }; +} +/** +* Emit one contained agent notification without allocating a retained dispatcher. +* @param ctx - the context to dispatch through. +* @param agent - the subject agent and scope key. +* @param name - the agent-subject event to emit. +* @param payload - the event's payload fields; `agent` is injected. +*/ +function emitAgentEvent(ctx, agent, name, payload) { + agentEvents(ctx, agent).emit(name, payload); +} +/** +* Build the prompt assembly context with agent and scope set together, so +* agent-scoped prompt and tool contributions cannot be silently omitted. +* @param agent - the agent the assembly is for. +* @param signal - the current turn's explicit control signal, when assembly belongs to a turn. +* @returns the context to pass to `assemble()`. +*/ +function assembleContextFor(agent, signal) { + return { + agent, + scope: agent, + ...signal === void 0 ? {} : { signal } + }; +} +//#endregion +//#region lib/types/index.js +/** +* Agent service: live registry, factory delegation, and process-local +* initiator scope. Concrete creation and driving belong to the loop. +* +* @module @deepseek-ai/dsh-agent +*/ +/** Thrown when create/resume is called before an agent factory is registered. */ +const NO_FACTORY_MESSAGE = "no agent factory registered (load an agent-loop plugin)"; +const NO_INITIATOR_MESSAGE = "no initiating agent is active"; +const DISPOSED_INITIATOR_MESSAGE = "agent initiator scope is disposed"; +/** +* Agent service (`ctx.agents`): tracks live agents and carries the initiating +* Agent through one process-local asynchronous driver chain. Agent *creation* +* is provided by whichever plugin implements the {@link AgentFactory} +* (`@deepseek-ai/dsh-agent-loop`), registered via {@link setFactory}. +* +* Initiator methods provide same-process causal attribution only. Ambient +* presence is neither liveness proof nor authorization; subjects and owners +* remain explicit, as does identity at worker, process, persistence, and wire +* boundaries. Returned Promise boundaries drain during teardown, except a +* nested lineage that starts an owning-fiber unload is excluded from its own drain. +*/ +var AgentRegistry = class extends Service { + store = /* @__PURE__ */ new Map(); + factory; + initiators = new AsyncLocalStorage(); + initiatorRuns = new AsyncLocalStorage(); + initiatorState = "active"; + activeInitiatorRuns = 0; + initiatorDrain; + initiatorDisposal; + constructor(ctx) { + super(ctx, "agents"); + ctx.inject(["typert"], (typeCtx) => { + typeCtx.typert.lookups.register("agent", { + parameter: "agent", + wire: "agentId", + hostTypeSymbol: "@deepseek-ai/dsh-agent#Agent", + wireTypeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + resolve: (sessionId) => this.get(sessionId) + }); + typeCtx.typert.contexts.registerHost("agent", { + wire: "agentId", + wireTypeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + resolve: (sessionId) => this.get(sessionId)?.ctx + }); + }); + ctx.accessor("agent", { get: () => void 0 }); + ctx.on("internal/status", (fiber) => { + if (fiber.state === 5 && this.hasLifecycleAncestor(fiber)) this.closeInitiators(); + }); + ctx.effect(function* () { + yield () => this.disposeInitiators(); + yield () => { + this.closeInitiators(); + }; + }.bind(this), "agents.initiatorLifecycle()"); + } + /** + * Read the Agent that initiated the inherited asynchronous driver chain. + * Use this optional form for logging, tracing, metrics, or host attribution + * that also supports agentless calls. When a parent creates a child, setup + * reports the causal parent while `agentCtx.agent` identifies the child. + * @returns the inherited Agent, or `undefined` outside an initiator boundary + * and inside an explicit clearing boundary. + * @throws when this service instance has been disposed. + */ + currentInitiator() { + this.assertInitiatorsReadable(); + return this.initiators.getStore(); + } + /** + * Read the initiating Agent and fail when no initiator boundary is active. + * Use this for private helpers contractually below a driver, or for a + * deployment-owned outbound request whose contract forbids agentless calls. + * Generic or direct-call paths use optional lookup or explicit request fields. + * @returns the inherited Agent. + * @throws when no initiator is active or this service instance has been disposed. + */ + requireInitiator() { + const agent = this.currentInitiator(); + if (agent === void 0) throw new Error(NO_INITIATOR_MESSAGE); + return agent; + } + /** + * Run an operation with one exact Agent as its process-local initiator. The + * exact synchronous value or Promise returned by the operation is preserved. + * Custom drivers and test harnesses wrap their complete returned foreground + * lifetime. + * A queue or wire receiver may establish this boundary only after validating + * explicit identity and resolving the exact live Agent; this method does neither. + * Detached work remains owned by the subsystem that starts it. + * @param agent - initiating Agent to inherit; presence is neither liveness proof nor authorization. + * @param operation - synchronous or asynchronous operation to invoke. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withInitiator(agent, operation) { + return this.runWithInitiator(agent, operation); + } + /** + * Run an operation inside a boundary that hides any inherited initiating + * Agent. The exact synchronous value or Promise is preserved. + * Use this while creating lazy shared timers, queue pumps, pool maintenance, + * watchers, or exporters so they do not inherit the first Agent that happens + * to initialize them. It clears only initiator attribution, not explicit + * fields, and does not own or drain detached resources. + * @param operation - synchronous or asynchronous operation to invoke without an initiator. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withoutInitiator(operation) { + return this.runWithInitiator(void 0, operation); + } + /** + * Register the agent-creation factory (the loop calls this on construction, + * effect-scoped). A traced Cordis service is canonicalized to its concrete + * target; each create/resume call is then traced through that caller's + * context so ownership follows the caller without stacking proxy layers. + * Throws if a factory is already registered. Returns the disposer; on + * dispose the factory slot is cleared. + * @param factory - the loop-owned factory {@link create}/{@link resume} delegate to. + * @returns the disposer that clears the factory slot. The exact + * Cordis effect disposer (single-shot): composite (generator) effects may + * yield it directly — exact identity nests the teardown in order. + */ + setFactory(factory) { + return this.ctx.effect(() => { + if (this.factory !== void 0) throw new Error("an agent factory is already registered"); + const target = factory[symbols.original] ?? factory; + this.factory = { target }; + return () => { + this.factory = void 0; + }; + }, "agents.setFactory()"); + } + /** Return the active creation factory. */ + requireFactory() { + if (this.factory === void 0) throw new Error(NO_FACTORY_MESSAGE); + return this.factory; + } + /** + * Create and publish a new agent through the registered factory. + * Distinct from {@link register} (which records an already-constructed + * agent): this constructs the agent and its session. Rejects if no factory is + * registered or creation/setup fails. The resolved {@link AgentHandle} lets + * the owner tear down exactly this agent. + * @param options - shared identity, session seed/metadata, and agent options. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + async create(options) { + const ownerCtx = this.ctx; + const { target } = this.requireFactory(); + const receiver = getTraceable(ownerCtx, target); + return Reflect.apply(target.createAgent, receiver, [ownerCtx, options]); + } + /** + * Load a persisted session and resume an agent on it through the registered + * factory. Rejects if no factory is registered; the factory rejects if + * session persistence is not configured or persistence/setup fails. + * @param options - persisted identity, configuration, and optional setup. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + async resume(options) { + const ownerCtx = this.ctx; + const { target } = this.requireFactory(); + const receiver = getTraceable(ownerCtx, target); + return Reflect.apply(target.resume, receiver, [ownerCtx, options]); + } + /** + * Register a live agent. Throws if an agent with the same id is already + * registered. Emits `agent/created` on registration and `agent/disposed` + * when the calling fiber is disposed — both with the agent's scope carrier + * (`scopeTarget(agent, agent)`): the subject is the agent in hand, so the + * emits are scope-filtered regardless of which context invoked `register` + * (calling through `agent.ctx` scopes EFFECTS; dispatch scoping always + * requires passing the carrier). Returns the disposer. + * @param agent - the already-constructed agent to record in the store. + * @returns the EXACT Cordis effect disposer (single-shot; a repeat call + * returns undefined without awaiting an in-flight teardown). Exact + * identity is load-bearing: a composite (generator) effect that owns a + * teardown ORDER — the agent factory's lifecycle chain — must yield THIS + * function so Cordis nests the unregistration at that yield position; + * yielding a wrapper would leave it disposing as a concurrent sibling on + * owner unload, unregistering the agent (and emitting `agent/disposed`) + * while its final turn is still draining. + */ + register(agent) { + return this.ctx.effect(function* () { + yield this.enter(agent, this.ctx.agent); + this.announce(agent); + }.bind(this), "agents.register()"); + } + /** + * Insert an already-constructed agent without announcing it. This is the + * advanced ordered-lifecycle primitive used by the async agent factory: it + * first completes setup while the agent is unpublished, then assigns the + * returned detach closure into its pre-installed composite teardown before + * calling {@link announce}. Ordinary callers use {@link register}. + * @param agent - the prepared, unpublished agent. + * @param owner - live agent whose scoped context created this agent, or + * undefined for a top-level runtime root. This is runtime ownership, not + * the resumed session's durable parent lineage. + * @returns an idempotent closure that removes this exact entry and emits + * `agent/disposed` with listener failures contained. When called from a + * synchronous `agent/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + */ + enter(agent, owner) { + const id = agent.id; + if (id !== agent.session.id) throw new Error(`agent id "${id}" does not match session id "${agent.session.id}"`); + const carrier = scopeTarget(agent, agent); + if (this.store.has(id)) throw new Error(`agent "${id}" is already registered`); + const entry = { + id, + agent, + owner, + carrier, + announced: false, + announcing: false, + detachRequested: false + }; + this.store.set(id, entry); + let entered = true; + const detach = () => { + if (!entered) return; + entered = false; + if (entry.announcing) { + entry.detachRequested = true; + return; + } + this.detachEntered(entry); + }; + return detach; + } + /** Remove one exact entered agent and emit its paired disposal when announced. */ + detachEntered(entry) { + entry.detachRequested = false; + /* v8 ignore next -- enter() rejects replacement while this single-shot detach capability is live. */ + if (this.store.get(entry.id) !== entry) return; + this.store.delete(entry.id); + if (!entry.announced) return; + this.emitDisposed(entry); + } + /** Emit the paired disposal edge through the entry's stable carrier. */ + emitDisposed(entry) { + const args = [ + entry.carrier, + "agent/disposed", + { agent: entry.agent } + ]; + for (const callback of this.ctx.events.dispatch("emit", args)) try { + const returned = callback(...args); + Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`agent "${entry.id}": agent/disposed listener rejected: ${String(error)}`); + }); + } catch (error) { + this.ctx.logger.warn(`agent "${entry.id}": agent/disposed listener threw: ${String(error)}`); + } + } + /** + * Announce an agent previously inserted with {@link enter}. + * @param agent - the live inserted agent to announce. + * @throws if `agent` is not the exact live registry entry for its id, or its + * creation announcement already began (including a reentrant call from a + * creation listener). + */ + announce(agent) { + const entry = this.store.get(agent.id); + if (entry === void 0 || entry.agent !== agent) throw new Error(`agent "${agent.id}" is not live in this registry`); + if (entry.announced || entry.announcing) throw new Error(`agent "${entry.id}" was already announced`); + entry.announcing = true; + entry.announced = true; + const args = [ + entry.carrier, + "agent/created", + { agent: entry.agent } + ]; + try { + for (const callback of this.ctx.events.dispatch("emit", args)) { + const returned = callback(...args); + Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`agent "${entry.id}": agent/created listener rejected: ${String(error)}`); + }); + } + } finally { + entry.announcing = false; + if (entry.detachRequested) this.detachEntered(entry); + } + } + /** + * Look up a live agent. + * @param id - the shared agent/session id to look up. + * @returns the agent, or undefined when no live agent has that id. + */ + get(id) { + return this.store.get(id)?.agent; + } + /** + * Test whether a live agent was created through one exact parent agent's + * scoped context. Runtime ownership is independent of durable session + * lineage and remains unambiguous when unrelated providers reuse an id. + * @param id - the candidate child agent's shared agent/session id. + * @param owner - the expected runtime creator agent. + * @returns true only while the exact child entry is live under that owner. + */ + isOwnedBy(id, owner) { + return this.store.get(id)?.owner === owner; + } + /** + * All live agents, in registration order. + * @returns a fresh array; mutating it does not affect the registry. + */ + list() { + return [...this.store.values()].map((entry) => entry.agent); + } + /** + * All live top-level agents in registration order. A top-level agent was + * created without an owning agent context; durable session lineage does not + * affect this runtime relation, so a resumed fork may still be a root. + * @returns a fresh array; mutating it does not affect the registry. + */ + roots() { + return [...this.store.values()].filter((entry) => entry.owner === void 0).map((entry) => entry.agent); + } + /** Reject new initiator boundaries while inherited continuations drain. */ + closeInitiators() { + if (this.initiatorState === "active") this.initiatorState = "closing"; + } + /** Wait for returned-Promise boundaries, then invalidate retained references. */ + disposeInitiators() { + return this.initiatorDisposal ??= (async () => { + this.closeInitiators(); + this.releaseReentrantInitiatorRuns(); + if (this.activeInitiatorRuns !== 0) { + this.initiatorDrain ??= Promise.withResolvers(); + await this.initiatorDrain.promise; + } + this.initiatorState = "disposed"; + this.initiators.disable(); + this.initiatorRuns.disable(); + })(); + } + /** Establish one tracked initiator or clearing boundary. */ + runWithInitiator(agent, operation) { + if (this.initiatorState !== "active") throw new Error(DISPOSED_INITIATOR_MESSAGE); + const run = { + active: true, + parent: this.initiatorRuns.getStore() + }; + this.activeInitiatorRuns += 1; + let result; + try { + result = this.initiatorRuns.run(run, () => this.initiators.run(agent, operation)); + } catch (error) { + this.releaseInitiatorRun(run); + throw error; + } + if (isPromise(result)) try { + Promise.prototype.then.call(result, () => { + this.releaseInitiatorRun(run); + }, () => { + this.releaseInitiatorRun(run); + }); + } catch { + this.releaseInitiatorRun(run); + } + else this.releaseInitiatorRun(run); + return result; + } + /** Whether one unloading fiber owns this service's lifecycle. */ + hasLifecycleAncestor(candidate) { + let fiber = this.ctx.fiber; + while (true) { + if (fiber === candidate) return true; + const parent = fiber.parent.fiber; + if (parent === fiber) return false; + fiber = parent; + } + } + assertInitiatorsReadable() { + if (this.initiatorState === "disposed") throw new Error(DISPOSED_INITIATOR_MESSAGE); + } + /** Exclude the boundary chain that initiated this teardown from its own drain. */ + releaseReentrantInitiatorRuns() { + let run = this.initiatorRuns.getStore(); + while (run !== void 0) { + this.releaseInitiatorRun(run); + run = run.parent; + } + } + releaseInitiatorRun(run) { + if (!run.active) return; + run.active = false; + this.activeInitiatorRuns -= 1; + if (this.activeInitiatorRuns !== 0) return; + this.initiatorDrain?.resolve(); + this.initiatorDrain = void 0; + } +}; +//#endregion +export { AgentRegistry, AgentRegistry as default, Inbox, agentCarrier, agentEvents, assembleContextFor, emitAgentEvent, foldConsumedWork, installModelSelection }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/invariant.js new file mode 100644 index 0000000..4659487 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** Package-owned agent lifecycle invariants. @module @deepseek-ai/dsh-agent/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-agent"; +/** Cordis companion plugin name. */ +const name = "agent-invariant"; +/** Services required before the companion can register. */ +const inject = ["invariants"]; +/** Install the agent contribution into its child registration fiber. */ +const install = (ctx, fail) => { + const lastStatus = /* @__PURE__ */ new WeakMap(); + ctx.on("agent/status", ({ agent, status }) => { + if (lastStatus.get(agent) === status) fail(`agent/status repeated ${status} (no-op transition)`); + lastStatus.set(agent, status); + }, { global: true }); +}; +/** +* Register the agent invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.d.ts new file mode 100644 index 0000000..5c6f623 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.d.ts @@ -0,0 +1,39 @@ +/** + * How one agent log accounts for the work it consumed. + * + * The turn and step vocabulary alone cannot answer this. A turn that stops + * before its first step leaves a `turn/end` shaped exactly like the balanced + * no-op turns a rejection or an empty claim produces, so reading turns in + * isolation either credits cut-short work as finished or convicts every no-op. + * The missing fact is the inbox's own record: {@link Inbox} logs each mutation + * with `removedCount` and marks a cancellation `outcome: 'canceled'`, which + * separates a turn claiming its input from work being dropped unrun. + * + * @module @deepseek-ai/dsh-agent/consumed-work + */ +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +/** How one agent log accounts for the work it consumed. */ +export interface ConsumedWork { + /** + * The latest closed turn that accounts for consumed work: one that entered a + * model step, or one that claimed inbox input and then failed, was stopped, + * or was rejected. Absent when no turn closed over any work. + */ + readonly end?: SessionEvent<'turn/end'>; + /** + * Whether accepted work was cancelled out of the inbox, unrun, after that + * turn. This is the only account of input a cancellation took before any turn + * could open over it — no `turn/end` describes it. + */ + readonly droppedUnrun: boolean; +} +/** + * Fold one agent log, or an owned suffix of one, into its account of consumed + * work. Single pass, and every input is the log itself: no caller has to sample + * live state before cancelling, so a cancellation issued by anyone — the owner's + * teardown, an ancestor's interrupt, an unloading plugin — reads the same. + * @param events - the log, or an owned suffix, to fold. + * @returns the accounting turn when one closed, and whether work was dropped unrun after it. + */ +export declare function foldConsumedWork(events: readonly SessionEvent[]): ConsumedWork; +//# sourceMappingURL=consumed-work.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.js new file mode 100644 index 0000000..a6c2bb0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.js @@ -0,0 +1,92 @@ +/** + * How one agent log accounts for the work it consumed. + * + * The turn and step vocabulary alone cannot answer this. A turn that stops + * before its first step leaves a `turn/end` shaped exactly like the balanced + * no-op turns a rejection or an empty claim produces, so reading turns in + * isolation either credits cut-short work as finished or convicts every no-op. + * The missing fact is the inbox's own record: {@link Inbox} logs each mutation + * with `removedCount` and marks a cancellation `outcome: 'canceled'`, which + * separates a turn claiming its input from work being dropped unrun. + * + * @module @deepseek-ai/dsh-agent/consumed-work + */ +/** + * Whether a turn that consumed input but never reached a step ends in a way + * that accounts for that input. Only a `completed` end does not: it had + * nothing left to run once its claim was rewritten away. A `blocked` end is + * that input's ending too — the pre-step rejection that produced it discarded + * the claimed messages, so the work it took will never run. + * @param reason - the turn's recorded ending. + * @returns whether the ending accounts for the input the turn took. + */ +function accountsForClaim(reason) { + switch (reason.kind) { + case 'completed': + return false; + case 'blocked': + case 'aborted': + case 'interrupted': + case 'error': + return true; + /* v8 ignore next 4 -- unreachable: the one unnamed built-in, `max-tokens`, requires a step, + * so its turn short-circuits as stepped before this call, and `TurnEndReasonMap` is + * merge-extensible, so a backend-added variant cannot be listed; an unnameable ending over + * consumed input must not read as success. */ + default: + return true; + } +} +/** + * Fold one agent log, or an owned suffix of one, into its account of consumed + * work. Single pass, and every input is the log itself: no caller has to sample + * live state before cancelling, so a cancellation issued by anyone — the owner's + * teardown, an ancestor's interrupt, an unloading plugin — reads the same. + * @param events - the log, or an owned suffix, to fold. + * @returns the accounting turn when one closed, and whether work was dropped unrun after it. + */ +export function foldConsumedWork(events) { + const stepped = new Set(); + const claimed = new Set(); + let open; + let end; + let droppedUnrun = false; + for (const event of events) { + switch (event.type) { + case 'turn/start': + open = event.data.turn; + break; + case 'step/start': + stepped.add(event.data.turn); + break; + case 'agent/inbox/spliced': { + const { removedCount, outcome, inserted } = event.data; + if (removedCount === undefined) + break; + // A replacement keeps the work pending under a new identity, so only a + // cancellation that leaves nothing behind drops it. + if (outcome === 'canceled') + droppedUnrun ||= inserted.length === 0; + // Claims are the loop's own step-boundary reads, always inside a turn. + else if (open !== undefined) + claimed.add(open); + break; + } + case 'turn/end': { + const { turn, reason } = event.data; + open = undefined; + if (stepped.delete(turn) || (claimed.delete(turn) && accountsForClaim(reason))) { + end = event; + // Anything dropped before this turn closed is what its own ending + // reports; only a later drop is still unaccounted for. + droppedUnrun = false; + } + break; + } + default: + break; + } + } + return { ...end === undefined ? {} : { end }, droppedUnrun }; +} +//# sourceMappingURL=consumed-work.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.d.ts new file mode 100644 index 0000000..2e3b36e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.d.ts @@ -0,0 +1,111 @@ +/** + * Agent-scoped dispatch and prompt assembly helpers. The fused dispatcher + * {@link agentEvents} couples the agent subject to its scope carrier, so the + * scope key and the payload's `agent` cannot diverge; repeat dispatchers (the + * loop driver) build it once in the agent's constructor and reuse it. + * @module @deepseek-ai/dsh-agent/dispatch + */ +import type { Context, Events } from '@deepseek-ai/cordis'; +import type { Scoped } from '@deepseek-ai/dsh-scope'; +import type { AssembleContext } from '@deepseek-ai/dsh-system-prompt'; +import type { Agent } from './runtime-types.ts'; +/** Extract the parameter tuple from an event handler type (its `this` is not part of the tuple). */ +type Params = F extends (...args: infer P) => unknown ? P : never; +/** Extract the return type from an event handler type. */ +type Return = F extends (...args: never[]) => infer R ? R : never; +/** + * The event names whose subject is an agent: the handler's first parameter is + * a payload object carrying the `agent` subject AND the handler declares a + * `Scoped` `this` (the scope-carrier contract). The `this` check keeps + * accidental payload-happens-to-carry-an-Agent events (or zero-arg events, + * whose parameter tuple would satisfy a bare rest-tuple check via callability) + * out of the fused-dispatch surface. + */ +export type AgentSubjectEvent = { + [K in keyof Events]: Events[K] extends (this: Scoped, ...args: infer P) => unknown ? P extends [infer Payload, ...unknown[]] ? Payload extends { + agent: Agent; + } ? K : never : never : never; +}[keyof Events]; +/** The full payload object of one agent-subject event. */ +type PayloadOf = Params extends [infer Payload, ...unknown[]] ? Payload : never; +/** The event arguments AFTER the payload: the waterfall `next` when present. */ +type Tail = Params extends [unknown, ...infer R] ? R : never; +/** + * The payload as emit-side callers pass it: the full payload minus the agent + * field, which the fused dispatcher injects so subject and scope key cannot + * diverge. + */ +type PayloadRest = Omit & object, 'agent'>; +/** + * The fused dispatcher {@link agentEvents} returns: each method dispatches the + * named agent-subject event with the agent's scope carrier as `thisArg` and + * the agent itself injected into the payload. + */ +export interface AgentEventDispatch { + /** + * Fire-and-forget notification in the agent's scope. Every listener is + * invoked; synchronous throws and returned-promise rejections are logged and + * contained per listener, so a notification cannot veto lifecycle progress + * or starve a later observer. + * @param name - the agent-subject event to emit. + * @param payload - the event's payload fields; `agent` is injected. + */ + emit(name: K, payload: PayloadRest): void; + /** + * Awaited in-order dispatch (Cordis `serial`) in the agent's scope. + * @param name - the agent-subject event to dispatch. + * @param payload - the event's payload fields; `agent` is injected. + * @returns the serial chain's result (the first bail value, if any). + */ + serial(name: K, payload: PayloadRest): Promise>>; + /** + * Around-middleware dispatch (Cordis `waterfall`) in the agent's scope. The + * declared event parameters already end with the `next` callback, so `rest` + * is exactly the event's arguments after the payload — the final element + * being the innermost `next` (the default the listener chain wraps). + * @param name - the agent-subject event to dispatch. + * @param payload - the event's payload fields; `agent` is injected. + * @param rest - the event's arguments after the payload (the `next` callback). + * @returns the waterfall's composed result. + */ + waterfall(name: K, payload: PayloadRest, ...rest: Tail): Return; +} +/** + * Build the fused scope carrier for one agent subject. + * + * The carrier is a stateless routing object. {@link agentEvents} accepts an + * existing carrier, so callers that dispatch repeatedly for the same agent + * (the loop driver) build it once in the agent's constructor and reuse it, + * keeping hot-path dispatches allocation-free. + * @param agent - the subject agent and scope key. + * @returns the carrier passed as the event dispatcher `this` value. + */ +export declare function agentCarrier(agent: Agent): Scoped; +/** + * Build a dispatcher that couples the agent subject to its scope carrier. + * @param ctx - the context to dispatch through (any context of the app). + * @param agent - the subject agent; also the scope-carrier key. + * @param carrier - the scope carrier to dispatch through; defaults to + * {@link agentCarrier} for the agent. Pass a constructor-built carrier to + * avoid rebuilding it for every dispatch. + * @returns the fused dispatcher. + */ +export declare function agentEvents(ctx: Context, agent: Agent, carrier?: Scoped): AgentEventDispatch; +/** + * Emit one contained agent notification without allocating a retained dispatcher. + * @param ctx - the context to dispatch through. + * @param agent - the subject agent and scope key. + * @param name - the agent-subject event to emit. + * @param payload - the event's payload fields; `agent` is injected. + */ +export declare function emitAgentEvent(ctx: Context, agent: Agent, name: K, payload: PayloadRest): void; +/** + * Build the prompt assembly context with agent and scope set together, so + * agent-scoped prompt and tool contributions cannot be silently omitted. + * @param agent - the agent the assembly is for. + * @param signal - the current turn's explicit control signal, when assembly belongs to a turn. + * @returns the context to pass to `assemble()`. + */ +export declare function assembleContextFor(agent: Agent, signal?: AbortSignal): AssembleContext; +export {}; +//# sourceMappingURL=dispatch.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.js new file mode 100644 index 0000000..876f485 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.js @@ -0,0 +1,95 @@ +/** + * Agent-scoped dispatch and prompt assembly helpers. The fused dispatcher + * {@link agentEvents} couples the agent subject to its scope carrier, so the + * scope key and the payload's `agent` cannot diverge; repeat dispatchers (the + * loop driver) build it once in the agent's constructor and reuse it. + * @module @deepseek-ai/dsh-agent/dispatch + */ +import { scopeTarget } from '@deepseek-ai/dsh-scope'; +/** + * Build the fused scope carrier for one agent subject. + * + * The carrier is a stateless routing object. {@link agentEvents} accepts an + * existing carrier, so callers that dispatch repeatedly for the same agent + * (the loop driver) build it once in the agent's constructor and reuse it, + * keeping hot-path dispatches allocation-free. + * @param agent - the subject agent and scope key. + * @returns the carrier passed as the event dispatcher `this` value. + */ +export function agentCarrier(agent) { + return scopeTarget(agent, agent); +} +/** + * Build a dispatcher that couples the agent subject to its scope carrier. + * @param ctx - the context to dispatch through (any context of the app). + * @param agent - the subject agent; also the scope-carrier key. + * @param carrier - the scope carrier to dispatch through; defaults to + * {@link agentCarrier} for the agent. Pass a constructor-built carrier to + * avoid rebuilding it for every dispatch. + * @returns the fused dispatcher. + */ +export function agentEvents(ctx, agent, carrier = agentCarrier(agent)) { + // The ordinary dispatch methods forward through Cordis' variadic mixins. The + // fused (carrier, name, payload, ...rest) tuple is provably a valid argument + // list for the matching thisArg overload, but TypeScript cannot relate the + // generic Tail spread back to that overload's conditional parameter + // tuple — hence one contained, shape-preserving cast per method. + const fused = (payload) => + // The dispatcher owns the subject injection; callers pass PayloadRest, so + // the fused record is exactly the declared payload. The spread comes + // first, so a structurally acceptable payload that happens to carry an + // `agent` field can never override the injected subject. + ({ ...payload, agent }); + return { + emit(name, payload) { + // Cordis emit invokes callbacks through Array.map: one synchronous throw + // starves later listeners, and returned promises are discarded. Agent + // notifications are non-vetoing, so resolve the same filtered callback + // set ourselves and contain both failure modes independently. + const args = [carrier, name, fused(payload)]; + const callbacks = ctx.events.dispatch('emit', args); + for (const callback of callbacks) { + try { + const returned = callback(...args); + void Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`agent event "${name}" listener rejected: ${String(error)}`); + }); + } + catch (error) { + ctx.logger.warn(`agent event "${name}" listener threw: ${String(error)}`); + } + } + }, + async serial(name, payload) { + // oxlint-disable-next-line typescript/unbound-method -- the events mixin accessor returns a pre-bound function + const serial = ctx.serial; + return await serial(carrier, name, fused(payload)); + }, + waterfall(name, payload, ...rest) { + // oxlint-disable-next-line typescript/unbound-method -- the events mixin accessor returns a pre-bound function + const waterfall = ctx.waterfall; + return waterfall(carrier, name, fused(payload), ...rest); + }, + }; +} +/** + * Emit one contained agent notification without allocating a retained dispatcher. + * @param ctx - the context to dispatch through. + * @param agent - the subject agent and scope key. + * @param name - the agent-subject event to emit. + * @param payload - the event's payload fields; `agent` is injected. + */ +export function emitAgentEvent(ctx, agent, name, payload) { + agentEvents(ctx, agent).emit(name, payload); +} +/** + * Build the prompt assembly context with agent and scope set together, so + * agent-scoped prompt and tool contributions cannot be silently omitted. + * @param agent - the agent the assembly is for. + * @param signal - the current turn's explicit control signal, when assembly belongs to a turn. + * @returns the context to pass to `assemble()`. + */ +export function assembleContextFor(agent, signal) { + return { agent, scope: agent, ...signal === undefined ? {} : { signal } }; +} +//# sourceMappingURL=dispatch.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.d.ts new file mode 100644 index 0000000..28c4a1e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.d.ts @@ -0,0 +1,92 @@ +/** + * Incremental projection of durable agent inbox events. + * + * @module @deepseek-ai/dsh-agent/inbox + */ +import type { MessageId } from '@deepseek-ai/dsh-llm'; +import type { Session, UserMessage } from '@deepseek-ai/dsh-session'; +import type { InboxTarget } from './types.ts'; +/** Live notifications committed by inbox mutations. */ +export interface InboxNotifications { + /** Publish one inserted message. */ + inserted(message: UserMessage): void; + /** Publish one discarded message. */ + discarded(message: UserMessage): void; + /** Publish one claimed message inside its owning turn. */ + claimed(message: UserMessage, turn: number): void; +} +/** A replay-once projection that incrementally consumes later inbox splices. */ +export declare class Inbox { + private readonly session; + private readonly notifications; + private readonly state; + constructor(session: Session, notifications: InboxNotifications); + /** Prompts awaiting individual turns. */ + get nextTurn(): readonly UserMessage[]; + /** Input awaiting the next step boundary. */ + get nextStep(): readonly UserMessage[]; + /** Whether either pending-message list contains work. */ + get hasPending(): boolean; + /** Durably cancel all pending input, clearing next-step before next-turn. */ + clear(): void; + /** + * Remove and return the complete batch proposed for one step, publishing + * each claimed message. The durable splices are pure deletions. + * @param target - whether this boundary also consumes one queued turn. + * @param turn - turn that will own the claimed batch. + * @returns next-step input followed by the queued turn, when requested. + * @internal - The agent loop's step-boundary operation, not a plugin extension point. + */ + claim(target: InboxTarget, turn: number): UserMessage[]; + /** + * Append one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to append. + * @throws if the message identity is already pending. + */ + append(target: InboxTarget, message: UserMessage): void; + /** + * Prepend one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to prepend. + * @throws if the message identity is already pending. + */ + prepend(target: InboxTarget, message: UserMessage): void; + /** + * Replace one pending message in place, possibly changing its identity. A + * successful replacement publishes the old message as discarded and the new + * message as inserted. + * @param messageId - identity of the pending message to replace. + * @param newMessage - replacement message. + * @returns whether the message was still pending. + * @throws if the replacement duplicates another pending message identity. + */ + replace(messageId: MessageId, newMessage: UserMessage): boolean; + /** + * Remove one pending message and durably record its cancellation. + * @param messageId - identity of the pending message to remove. + * @returns whether the message was still pending. + */ + remove(messageId: MessageId): boolean; + /** + * Apply standard splice semantics and durably record the normalized result. + * The durable event commits before the live projection mutates, so synchronous + * `session/event` observers see the pre-splice lists and can reconstruct the + * removed messages from the normalized coordinates. + * @param target - pending list to mutate. + * @param start - splice position. + * @param deleteCount - maximum number of messages to remove. + * @param inserted - messages to insert at the resolved position. + * @returns messages removed by the splice. + */ + splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[]; + /** Locate one pending identity across both owned lists. */ + private locate; + /** Commit one normalized mutation and publish its live notifications. */ + private mutate; + /** Apply one normalized durable splice to the projection. */ + private apply; + /** Validate one normalized splice against the current projection. */ + private validate; +} +//# sourceMappingURL=inbox.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.js new file mode 100644 index 0000000..4d49a7a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.js @@ -0,0 +1,185 @@ +/** + * Incremental projection of durable agent inbox events. + * + * @module @deepseek-ai/dsh-agent/inbox + */ +/** A replay-once projection that incrementally consumes later inbox splices. */ +export class Inbox { + session; + notifications; + state = { 'next-turn': [], 'next-step': [] }; + constructor(session, notifications) { + this.session = session; + this.notifications = notifications; + for (const event of session.events.slice(session.header.seedLength ?? 0)) { + if (event.type !== 'agent/inbox/spliced') + continue; + try { + this.apply(event.data); + } + catch (error) { + throw new Error(`invalid persisted inbox splice at session seq ${event.seq}`, { cause: error }); + } + } + } + /** Prompts awaiting individual turns. */ + get nextTurn() { + return this.state['next-turn']; + } + /** Input awaiting the next step boundary. */ + get nextStep() { + return this.state['next-step']; + } + /** Whether either pending-message list contains work. */ + get hasPending() { + return this.nextTurn.length > 0 || this.nextStep.length > 0; + } + /** Durably cancel all pending input, clearing next-step before next-turn. */ + clear() { + this.splice('next-step', 0, this.nextStep.length, []); + this.splice('next-turn', 0, this.nextTurn.length, []); + } + /** + * Remove and return the complete batch proposed for one step, publishing + * each claimed message. The durable splices are pure deletions. + * @param target - whether this boundary also consumes one queued turn. + * @param turn - turn that will own the claimed batch. + * @returns next-step input followed by the queued turn, when requested. + * @internal - The agent loop's step-boundary operation, not a plugin extension point. + */ + claim(target, turn) { + const claimed = this.mutate('next-step', 0, this.nextStep.length, [], false); + if (target === 'next-turn') { + claimed.push(...this.mutate('next-turn', 0, 1, [], false)); + } + for (const message of claimed) + this.notifications.claimed(message, turn); + return claimed; + } + /** + * Append one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to append. + * @throws if the message identity is already pending. + */ + append(target, message) { + this.splice(target, this.state[target].length, 0, [message]); + } + /** + * Prepend one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to prepend. + * @throws if the message identity is already pending. + */ + prepend(target, message) { + this.splice(target, 0, 0, [message]); + } + /** + * Replace one pending message in place, possibly changing its identity. A + * successful replacement publishes the old message as discarded and the new + * message as inserted. + * @param messageId - identity of the pending message to replace. + * @param newMessage - replacement message. + * @returns whether the message was still pending. + * @throws if the replacement duplicates another pending message identity. + */ + replace(messageId, newMessage) { + const location = this.locate(messageId); + if (location === undefined) + return false; + this.splice(location.target, location.index, 1, [newMessage]); + return true; + } + /** + * Remove one pending message and durably record its cancellation. + * @param messageId - identity of the pending message to remove. + * @returns whether the message was still pending. + */ + remove(messageId) { + const location = this.locate(messageId); + if (location === undefined) + return false; + this.splice(location.target, location.index, 1, []); + return true; + } + /** + * Apply standard splice semantics and durably record the normalized result. + * The durable event commits before the live projection mutates, so synchronous + * `session/event` observers see the pre-splice lists and can reconstruct the + * removed messages from the normalized coordinates. + * @param target - pending list to mutate. + * @param start - splice position. + * @param deleteCount - maximum number of messages to remove. + * @param inserted - messages to insert at the resolved position. + * @returns messages removed by the splice. + */ + splice(target, start, deleteCount, inserted) { + return this.mutate(target, start, deleteCount, inserted, true); + } + /** Locate one pending identity across both owned lists. */ + locate(messageId) { + for (const target of ['next-turn', 'next-step']) { + const index = this.state[target].findIndex(message => message.id === messageId); + if (index >= 0) + return { target, index }; + } + return undefined; + } + /** Commit one normalized mutation and publish its live notifications. */ + mutate(target, start, deleteCount, inserted, discardRemoved) { + const inbox = this.state[target]; + const truncatedStart = Math.trunc(start); + const offset = Number.isNaN(truncatedStart) ? 0 : truncatedStart; + const actualStart = offset < 0 + ? Math.max(inbox.length + offset, 0) + : Math.min(offset, inbox.length); + const truncatedDeleteCount = Math.trunc(deleteCount); + const actualDeleteCount = Math.min(Math.max(Number.isNaN(truncatedDeleteCount) ? 0 : truncatedDeleteCount, 0), inbox.length - actualStart); + if (actualDeleteCount === 0 && inserted.length === 0) + return []; + const outcome = discardRemoved && actualDeleteCount > 0 ? 'canceled' : undefined; + const splice = { + target, + start: actualStart, + ...(actualDeleteCount === 0 ? {} : { removedCount: actualDeleteCount }), + inserted, + ...(outcome === undefined ? {} : { outcome }), + }; + this.validate(splice); + const event = this.session.append('agent/inbox/spliced', splice); + const removed = inbox.splice(actualStart, actualDeleteCount, ...event.data.inserted); + if (discardRemoved) { + for (const message of removed) + this.notifications.discarded(message); + } + for (const message of event.data.inserted) + this.notifications.inserted(message); + return removed; + } + /** Apply one normalized durable splice to the projection. */ + apply(splice) { + this.validate(splice); + const inbox = this.state[splice.target]; + return inbox.splice(splice.start, splice.removedCount ?? 0, ...splice.inserted); + } + /** Validate one normalized splice against the current projection. */ + validate(splice) { + const inbox = this.state[splice.target]; + const removedCount = splice.removedCount ?? 0; + if (!Number.isSafeInteger(splice.start) || splice.start < 0 || splice.start > inbox.length + || !Number.isSafeInteger(removedCount) || removedCount < 0 + || splice.start + removedCount > inbox.length) { + throw new Error('invalid inbox splice'); + } + const candidate = inbox.toSpliced(splice.start, removedCount, ...splice.inserted); + const ids = new Set(); + for (const message of splice.target === 'next-turn' + ? [...candidate, ...this.nextStep] + : [...this.nextTurn, ...candidate]) { + if (ids.has(message.id)) + throw new Error(`message "${message.id}" is already pending`); + ids.add(message.id); + } + } +} +//# sourceMappingURL=inbox.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/index.d.ts new file mode 100644 index 0000000..2909e92 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/index.d.ts @@ -0,0 +1,385 @@ +/** + * Agent service: live registry, factory delegation, and process-local + * initiator scope. Concrete creation and driving belong to the loop. + * + * @module @deepseek-ai/dsh-agent + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'; +import type { TypertContext, TypertLookup } from '@deepseek-ai/dsh-typert-protocol'; +import type { Agent, AgentOptions } from './runtime-types.ts'; +export * from './runtime-types.ts'; +export * from './types.ts'; +export * from './inbox.ts'; +export * from './consumed-work.ts'; +export * from './model-selection.ts'; +export { agentCarrier, agentEvents, assembleContextFor, emitAgentEvent } from './dispatch.ts'; +export type { AgentEventDispatch, AgentSubjectEvent } from './dispatch.ts'; +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertLookupMap { + agent: TypertLookup; + } + interface TypertContextMap { + agent: TypertContext; + } +} +declare module '@deepseek-ai/cordis' { + interface Context { + agents: AgentRegistry; + /** + * The agent association installed as an own property on `Agent.ctx`, or + * `undefined` on a plain context. Contexts derived from `Agent.ctx` inherit + * the association; a deliberately nested scope may carry a nearer + * `dsh-scope` tag while retaining it, so this field is DX context rather + * than the scope resolver. {@link AgentRegistry} registers a root accessor + * defaulting to `undefined`, and core packages below the agent layer use + * `scopeOf()` for layer selection instead of reading this field. + */ + agent?: Agent; + } +} +/** + * Synchronous finalizer returned by unpublished Agent setup when its + * contributions need validation at the exact publication commit point. + */ +export interface AgentSetupCommit { + /** + * Validate and commit the prepared setup immediately before publication. + * @throws when publication must roll the unpublished Agent back. + */ + commit(): void; +} +/** + * Compose an unpublished Agent scope and optionally return its publication commit. + * @param agentCtx - unpublished Agent scope. + * @returns an optional synchronous commit invoked after setup awaits settle and immediately before publication. + */ +export type AgentSetup = (agentCtx: Context) => AgentSetupCommit | Promise | void; +/** + * Options for programmatically creating an agent through the registry factory + * ({@link AgentRegistry.create}). The caller supplies the single live + * `sessionId` shared by the agent registry and session log (e.g. an + * ACP-generated id), plus optional session metadata (the validated `cwd`, fork + * lineage); the factory creates the session and agent under that identity. + */ +export interface CreateAgentOptions { + /** The live agent/session identity. */ + readonly sessionId: SessionId; + /** + * Session creation metadata: validated absolute `cwd`, `parentSession` + * fork lineage, the `seedLength` seed boundary, the coarse `origin` + * classification, and the `delegationDepth` recursion budget. Mirrors the + * `cwd`/`parentSession`/`seedLength`/`origin`/`delegationDepth` fields of + * {@link CreateSessionOptions.meta} in dsh-session (the internal-only + * `createdAt`, used when reconstructing a persisted session, is deliberately + * excluded — a factory caller never sets it). This is durable session data, + * so the session boundary validates and snapshots it before asynchronous + * setup begins. + */ + readonly meta?: { + readonly cwd?: string; + readonly parentSession?: SessionId; + readonly seedLength?: number; + readonly origin?: 'subagent'; + readonly delegationDepth?: number; + readonly agentPreset?: string; + }; + /** + * Initial replay/fork history. A fork supplies a balanced completed-turn + * prefix of the parent's log. The complete seed must be contiguous from seq + * 0, carry only lossless-JSON data, and contain no open turn/step or dangling + * tool call. The factory passes it to the session's durable + * validator/snapshot boundary before publication. + */ + readonly seed?: readonly SessionEvent[]; + /** Per-agent options (model, …). */ + readonly agentOptions?: AgentOptions; + /** Optional creation-only cancellation signal; detached before the returned handle becomes visible. */ + readonly signal?: AbortSignal; + /** + * Creation-time composition of the agent's scoped world. The factory awaits + * setup after minting `agentCtx` but BEFORE inserting or announcing either + * the session or agent, so observers can never see a partially configured + * world. Setup may return an {@link AgentSetupCommit}; the factory invokes its + * synchronous `commit()` after every setup await settles and immediately + * before registry publication. This lets mutable provisioning revalidate at + * the exact publication boundary. Everything registered through `agentCtx` + * (scoped tools, prompt sections/variables, `restrict()`, listeners, awaited + * child plugins) exists before `session/created`, `agent/created`, + * `agent/session-start`, and the first prompt assembly. A setup + * throw/rejection, commit throw, or owner disposal rolls the scope back + * without publishing either id. + * + * **Setup composes, it never drives**: the callback is trusted same-process + * code and receives the full scoped context, so this is a contract rather + * than a runtime restriction. Drive the agent only after creation resolves. + */ + readonly setup?: AgentSetup; +} +/** + * Options for resuming an agent on a persisted session + * ({@link AgentRegistry.resume}). + */ +export interface ResumeAgentOptions { + /** The persisted session id to load and use as the live agent/session identity. */ + readonly resumeSessionId: SessionId; + /** Per-agent options (model, …). */ + readonly agentOptions?: AgentOptions; + /** Optional creation-only cancellation signal for persistence load/setup; detached before return. */ + readonly signal?: AbortSignal; + /** + * Resume-time composition of the agent's fresh scoped world. Persistence is + * loaded first; the factory then mints `agentCtx` and awaits setup while the + * reconstructed session and agent remain unpublished. The callback has the + * same trusted composition-only contract and optional synchronous + * publication commit as {@link CreateAgentOptions.setup}: all registrations + * exist before either creation announcement, and rejection, commit failure, + * or owner disposal rolls the transaction back without publishing either id. + */ + readonly setup?: AgentSetup; +} +/** + * An owned agent plus its disposer, returned by {@link AgentRegistry.create} / + * {@link AgentRegistry.resume}. The disposer is a CAPABILITY: among consumers, + * only the holder can tear this agent down. The registered factory provider is + * also a structural owner because the scoped agent depends on that provider's + * service API; provider unload stops and drains every live handle it made. + * `dispose()` stops the loop, awaits its exit, unregisters the agent, removes + * its session from the store, and finally unwinds its scoped world. + * + * `ctx.agents.get(id)` still returns a bare {@link Agent} — the handle is + * exposed only to the consumer owner that created it; the structural provider + * reaches the same teardown internally. Config-created agents (the loop's own + * startup) are owned by the loop fiber and never need a handle. + */ +export interface AgentHandle { + agent: Agent; + dispose(): Promise; +} +/** + * The agent-creation factory the loop implementation provides to the registry + * via {@link AgentRegistry.setFactory}. Kept on the `dsh-agent` interface so + * consumers (e.g. the ACP bridge) program against `ctx.agents` without + * depending on the concrete `dsh-agent-loop` package. + */ +export interface AgentFactory { + /** + * Create a new agent on a caller-supplied session id. Async because creation + * awaits unpublished setup, invokes its optional synchronous commit, inserts + * both session and agent, emits their creation notifications in order, emits + * `agent/session-start`, and only then starts the loop. The sequence is + * rollback-covered, but notifications delivered before a later listener + * failure remain observable; every agent or session creation announcement + * that began is paired by `agent/disposed` or `session/disposed` during + * rollback. The owner disposes the resolved handle to stop/drain, + * unregister, remove the session, and unwind the scope. + * The registry passes a context carrying the `create()` caller's fiber and + * scope as `ownerCtx`. The implementation attaches the unpublished + * transaction and resulting lifecycle to that owner; it must not infer + * ownership from the factory object's registration context. + * @param ownerCtx - caller-bound context that owns the transaction and live handle. + * @param options - agent/session identity, configuration, and optional setup. + * @returns the owned handle after setup, both announcements, and loop start complete. + */ + createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise; + /** + * Prepare a persisted session and resume an agent on it. Async because it awaits + * both `ctx.sessionPersistence.prepare` and the optional unpublished setup + * transaction; must be called after that service exists (consumers inject + * `sessionPersistence`). Publication follows the same setup-commit and + * ordered boundary as {@link createAgent}. + * @param ownerCtx - caller-bound context that owns load, setup, and the live handle. + * @param options - persisted identity, configuration, and optional setup. + * @returns the owned handle after setup, both announcements, and loop start complete. + */ + resume(ownerCtx: Context, options: ResumeAgentOptions): Promise; +} +/** + * Agent service (`ctx.agents`): tracks live agents and carries the initiating + * Agent through one process-local asynchronous driver chain. Agent *creation* + * is provided by whichever plugin implements the {@link AgentFactory} + * (`@deepseek-ai/dsh-agent-loop`), registered via {@link setFactory}. + * + * Initiator methods provide same-process causal attribution only. Ambient + * presence is neither liveness proof nor authorization; subjects and owners + * remain explicit, as does identity at worker, process, persistence, and wire + * boundaries. Returned Promise boundaries drain during teardown, except a + * nested lineage that starts an owning-fiber unload is excluded from its own drain. + */ +export declare class AgentRegistry extends Service { + private store; + private factory; + private readonly initiators; + private readonly initiatorRuns; + private initiatorState; + private activeInitiatorRuns; + private initiatorDrain; + private initiatorDisposal; + constructor(ctx: Context); + /** + * Read the Agent that initiated the inherited asynchronous driver chain. + * Use this optional form for logging, tracing, metrics, or host attribution + * that also supports agentless calls. When a parent creates a child, setup + * reports the causal parent while `agentCtx.agent` identifies the child. + * @returns the inherited Agent, or `undefined` outside an initiator boundary + * and inside an explicit clearing boundary. + * @throws when this service instance has been disposed. + */ + currentInitiator(): Agent | undefined; + /** + * Read the initiating Agent and fail when no initiator boundary is active. + * Use this for private helpers contractually below a driver, or for a + * deployment-owned outbound request whose contract forbids agentless calls. + * Generic or direct-call paths use optional lookup or explicit request fields. + * @returns the inherited Agent. + * @throws when no initiator is active or this service instance has been disposed. + */ + requireInitiator(): Agent; + /** + * Run an operation with one exact Agent as its process-local initiator. The + * exact synchronous value or Promise returned by the operation is preserved. + * Custom drivers and test harnesses wrap their complete returned foreground + * lifetime. + * A queue or wire receiver may establish this boundary only after validating + * explicit identity and resolving the exact live Agent; this method does neither. + * Detached work remains owned by the subsystem that starts it. + * @param agent - initiating Agent to inherit; presence is neither liveness proof nor authorization. + * @param operation - synchronous or asynchronous operation to invoke. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withInitiator(agent: Agent, operation: () => T): T; + /** + * Run an operation inside a boundary that hides any inherited initiating + * Agent. The exact synchronous value or Promise is preserved. + * Use this while creating lazy shared timers, queue pumps, pool maintenance, + * watchers, or exporters so they do not inherit the first Agent that happens + * to initialize them. It clears only initiator attribution, not explicit + * fields, and does not own or drain detached resources. + * @param operation - synchronous or asynchronous operation to invoke without an initiator. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withoutInitiator(operation: () => T): T; + /** + * Register the agent-creation factory (the loop calls this on construction, + * effect-scoped). A traced Cordis service is canonicalized to its concrete + * target; each create/resume call is then traced through that caller's + * context so ownership follows the caller without stacking proxy layers. + * Throws if a factory is already registered. Returns the disposer; on + * dispose the factory slot is cleared. + * @param factory - the loop-owned factory {@link create}/{@link resume} delegate to. + * @returns the disposer that clears the factory slot. The exact + * Cordis effect disposer (single-shot): composite (generator) effects may + * yield it directly — exact identity nests the teardown in order. + */ + setFactory(factory: AgentFactory): () => void; + /** Return the active creation factory. */ + private requireFactory; + /** + * Create and publish a new agent through the registered factory. + * Distinct from {@link register} (which records an already-constructed + * agent): this constructs the agent and its session. Rejects if no factory is + * registered or creation/setup fails. The resolved {@link AgentHandle} lets + * the owner tear down exactly this agent. + * @param options - shared identity, session seed/metadata, and agent options. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + create(options: CreateAgentOptions): Promise; + /** + * Load a persisted session and resume an agent on it through the registered + * factory. Rejects if no factory is registered; the factory rejects if + * session persistence is not configured or persistence/setup fails. + * @param options - persisted identity, configuration, and optional setup. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + resume(options: ResumeAgentOptions): Promise; + /** + * Register a live agent. Throws if an agent with the same id is already + * registered. Emits `agent/created` on registration and `agent/disposed` + * when the calling fiber is disposed — both with the agent's scope carrier + * (`scopeTarget(agent, agent)`): the subject is the agent in hand, so the + * emits are scope-filtered regardless of which context invoked `register` + * (calling through `agent.ctx` scopes EFFECTS; dispatch scoping always + * requires passing the carrier). Returns the disposer. + * @param agent - the already-constructed agent to record in the store. + * @returns the EXACT Cordis effect disposer (single-shot; a repeat call + * returns undefined without awaiting an in-flight teardown). Exact + * identity is load-bearing: a composite (generator) effect that owns a + * teardown ORDER — the agent factory's lifecycle chain — must yield THIS + * function so Cordis nests the unregistration at that yield position; + * yielding a wrapper would leave it disposing as a concurrent sibling on + * owner unload, unregistering the agent (and emitting `agent/disposed`) + * while its final turn is still draining. + */ + register(agent: Agent): () => void; + /** + * Insert an already-constructed agent without announcing it. This is the + * advanced ordered-lifecycle primitive used by the async agent factory: it + * first completes setup while the agent is unpublished, then assigns the + * returned detach closure into its pre-installed composite teardown before + * calling {@link announce}. Ordinary callers use {@link register}. + * @param agent - the prepared, unpublished agent. + * @param owner - live agent whose scoped context created this agent, or + * undefined for a top-level runtime root. This is runtime ownership, not + * the resumed session's durable parent lineage. + * @returns an idempotent closure that removes this exact entry and emits + * `agent/disposed` with listener failures contained. When called from a + * synchronous `agent/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + */ + enter(agent: Agent, owner: Agent | undefined): () => void; + /** Remove one exact entered agent and emit its paired disposal when announced. */ + private detachEntered; + /** Emit the paired disposal edge through the entry's stable carrier. */ + private emitDisposed; + /** + * Announce an agent previously inserted with {@link enter}. + * @param agent - the live inserted agent to announce. + * @throws if `agent` is not the exact live registry entry for its id, or its + * creation announcement already began (including a reentrant call from a + * creation listener). + */ + announce(agent: Agent): void; + /** + * Look up a live agent. + * @param id - the shared agent/session id to look up. + * @returns the agent, or undefined when no live agent has that id. + */ + get(id: SessionId): Agent | undefined; + /** + * Test whether a live agent was created through one exact parent agent's + * scoped context. Runtime ownership is independent of durable session + * lineage and remains unambiguous when unrelated providers reuse an id. + * @param id - the candidate child agent's shared agent/session id. + * @param owner - the expected runtime creator agent. + * @returns true only while the exact child entry is live under that owner. + */ + isOwnedBy(id: SessionId, owner: Agent): boolean; + /** + * All live agents, in registration order. + * @returns a fresh array; mutating it does not affect the registry. + */ + list(): Agent[]; + /** + * All live top-level agents in registration order. A top-level agent was + * created without an owning agent context; durable session lineage does not + * affect this runtime relation, so a resumed fork may still be a root. + * @returns a fresh array; mutating it does not affect the registry. + */ + roots(): Agent[]; + /** Reject new initiator boundaries while inherited continuations drain. */ + private closeInitiators; + /** Wait for returned-Promise boundaries, then invalidate retained references. */ + private disposeInitiators; + /** Establish one tracked initiator or clearing boundary. */ + private runWithInitiator; + /** Whether one unloading fiber owns this service's lifecycle. */ + private hasLifecycleAncestor; + private assertInitiatorsReadable; + /** Exclude the boundary chain that initiated this teardown from its own drain. */ + private releaseReentrantInitiatorRuns; + private releaseInitiatorRun; +} +export default AgentRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/index.js new file mode 100644 index 0000000..ce3279d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/index.js @@ -0,0 +1,474 @@ +/** + * Agent service: live registry, factory delegation, and process-local + * initiator scope. Concrete creation and driving belong to the loop. + * + * @module @deepseek-ai/dsh-agent + */ +import { getTraceable, Service, symbols } from '@deepseek-ai/cordis'; +import { AsyncLocalStorage } from 'node:async_hooks'; +import { isPromise } from 'node:util/types'; +import { scopeTarget } from '@deepseek-ai/dsh-scope'; +export * from "./runtime-types.js"; +export * from "./types.js"; +export * from "./inbox.js"; +export * from "./consumed-work.js"; +export * from "./model-selection.js"; +export { agentCarrier, agentEvents, assembleContextFor, emitAgentEvent } from "./dispatch.js"; +/** Thrown when create/resume is called before an agent factory is registered. */ +const NO_FACTORY_MESSAGE = 'no agent factory registered (load an agent-loop plugin)'; +const NO_INITIATOR_MESSAGE = 'no initiating agent is active'; +const DISPOSED_INITIATOR_MESSAGE = 'agent initiator scope is disposed'; +/** + * Agent service (`ctx.agents`): tracks live agents and carries the initiating + * Agent through one process-local asynchronous driver chain. Agent *creation* + * is provided by whichever plugin implements the {@link AgentFactory} + * (`@deepseek-ai/dsh-agent-loop`), registered via {@link setFactory}. + * + * Initiator methods provide same-process causal attribution only. Ambient + * presence is neither liveness proof nor authorization; subjects and owners + * remain explicit, as does identity at worker, process, persistence, and wire + * boundaries. Returned Promise boundaries drain during teardown, except a + * nested lineage that starts an owning-fiber unload is excluded from its own drain. + */ +export class AgentRegistry extends Service { + store = new Map(); + factory; + initiators = new AsyncLocalStorage(); + initiatorRuns = new AsyncLocalStorage(); + initiatorState = 'active'; + activeInitiatorRuns = 0; + initiatorDrain; + initiatorDisposal; + constructor(ctx) { + super(ctx, 'agents'); + ctx.inject(['typert'], (typeCtx) => { + typeCtx.typert.lookups.register('agent', { + parameter: 'agent', + wire: 'agentId', + hostTypeSymbol: '@deepseek-ai/dsh-agent#Agent', + wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + resolve: sessionId => this.get(sessionId), + }); + typeCtx.typert.contexts.registerHost('agent', { + wire: 'agentId', + wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + resolve: sessionId => this.get(sessionId)?.ctx, + }); + }); + // The `ctx.agent` DX accessor: default `undefined` on every context, so a + // plain plugin context reads cleanly instead of hitting the Cordis + // unknown-property throw. Each Agent.ctx shadows it with an own property + // (own properties resolve before the context proxy is consulted), so the + // accessor body never needs to resolve a scope itself. Effect-scoped: + // unwinds with this service's fiber. + ctx.accessor('agent', { get: () => undefined }); + ctx.on('internal/status', (fiber) => { + if (fiber.state === 5 /* FiberState.UNLOADING */ && this.hasLifecycleAncestor(fiber)) { + this.closeInitiators(); + } + }); + ctx.effect(function* () { + yield () => this.disposeInitiators(); + yield () => { this.closeInitiators(); }; + }.bind(this), 'agents.initiatorLifecycle()'); + } + /** + * Read the Agent that initiated the inherited asynchronous driver chain. + * Use this optional form for logging, tracing, metrics, or host attribution + * that also supports agentless calls. When a parent creates a child, setup + * reports the causal parent while `agentCtx.agent` identifies the child. + * @returns the inherited Agent, or `undefined` outside an initiator boundary + * and inside an explicit clearing boundary. + * @throws when this service instance has been disposed. + */ + currentInitiator() { + this.assertInitiatorsReadable(); + return this.initiators.getStore(); + } + /** + * Read the initiating Agent and fail when no initiator boundary is active. + * Use this for private helpers contractually below a driver, or for a + * deployment-owned outbound request whose contract forbids agentless calls. + * Generic or direct-call paths use optional lookup or explicit request fields. + * @returns the inherited Agent. + * @throws when no initiator is active or this service instance has been disposed. + */ + requireInitiator() { + const agent = this.currentInitiator(); + if (agent === undefined) + throw new Error(NO_INITIATOR_MESSAGE); + return agent; + } + /** + * Run an operation with one exact Agent as its process-local initiator. The + * exact synchronous value or Promise returned by the operation is preserved. + * Custom drivers and test harnesses wrap their complete returned foreground + * lifetime. + * A queue or wire receiver may establish this boundary only after validating + * explicit identity and resolving the exact live Agent; this method does neither. + * Detached work remains owned by the subsystem that starts it. + * @param agent - initiating Agent to inherit; presence is neither liveness proof nor authorization. + * @param operation - synchronous or asynchronous operation to invoke. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withInitiator(agent, operation) { + return this.runWithInitiator(agent, operation); + } + /** + * Run an operation inside a boundary that hides any inherited initiating + * Agent. The exact synchronous value or Promise is preserved. + * Use this while creating lazy shared timers, queue pumps, pool maintenance, + * watchers, or exporters so they do not inherit the first Agent that happens + * to initialize them. It clears only initiator attribution, not explicit + * fields, and does not own or drain detached resources. + * @param operation - synchronous or asynchronous operation to invoke without an initiator. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withoutInitiator(operation) { + return this.runWithInitiator(undefined, operation); + } + /** + * Register the agent-creation factory (the loop calls this on construction, + * effect-scoped). A traced Cordis service is canonicalized to its concrete + * target; each create/resume call is then traced through that caller's + * context so ownership follows the caller without stacking proxy layers. + * Throws if a factory is already registered. Returns the disposer; on + * dispose the factory slot is cleared. + * @param factory - the loop-owned factory {@link create}/{@link resume} delegate to. + * @returns the disposer that clears the factory slot. The exact + * Cordis effect disposer (single-shot): composite (generator) effects may + * yield it directly — exact identity nests the teardown in order. + */ + setFactory(factory) { + const dispose = this.ctx.effect(() => { + if (this.factory !== undefined) + throw new Error('an agent factory is already registered'); + // Avoid stacking two Cordis shadow layers when a caller passes a Service + // already read through a context. Calls are re-traced through their + // actual owner context below. + const target = factory[symbols.original] ?? factory; + this.factory = { target }; + return () => { this.factory = undefined; }; + }, 'agents.setFactory()'); + // The exact cordis effect disposer (the agents.register() convention): a + // caller's composite effect can yield it for in-order teardown; the + // loop's constructor effect returns it directly, identity-nesting the + // registration under that effect. + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity + return dispose; + } + /** Return the active creation factory. */ + requireFactory() { + if (this.factory === undefined) + throw new Error(NO_FACTORY_MESSAGE); + return this.factory; + } + /** + * Create and publish a new agent through the registered factory. + * Distinct from {@link register} (which records an already-constructed + * agent): this constructs the agent and its session. Rejects if no factory is + * registered or creation/setup fails. The resolved {@link AgentHandle} lets + * the owner tear down exactly this agent. + * @param options - shared identity, session seed/metadata, and agent options. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + async create(options) { + const ownerCtx = this.ctx; + // Re-trace a Service-backed factory through the accessing context + // explicitly. This preserves AgentLoop's dependency origin while binding + // its effects to ownerCtx; plain factories receive ownerCtx as an explicit + // capability and need no Cordis tracker magic. + const { target } = this.requireFactory(); + const receiver = getTraceable(ownerCtx, target); + // oxlint-disable-next-line typescript/unbound-method -- Reflect.apply intentionally supplies the caller-traced receiver + return Reflect.apply(target.createAgent, receiver, [ownerCtx, options]); + } + /** + * Load a persisted session and resume an agent on it through the registered + * factory. Rejects if no factory is registered; the factory rejects if + * session persistence is not configured or persistence/setup fails. + * @param options - persisted identity, configuration, and optional setup. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + async resume(options) { + const ownerCtx = this.ctx; + const { target } = this.requireFactory(); + const receiver = getTraceable(ownerCtx, target); + // oxlint-disable-next-line typescript/unbound-method -- Reflect.apply intentionally supplies the caller-traced receiver + return Reflect.apply(target.resume, receiver, [ownerCtx, options]); + } + /** + * Register a live agent. Throws if an agent with the same id is already + * registered. Emits `agent/created` on registration and `agent/disposed` + * when the calling fiber is disposed — both with the agent's scope carrier + * (`scopeTarget(agent, agent)`): the subject is the agent in hand, so the + * emits are scope-filtered regardless of which context invoked `register` + * (calling through `agent.ctx` scopes EFFECTS; dispatch scoping always + * requires passing the carrier). Returns the disposer. + * @param agent - the already-constructed agent to record in the store. + * @returns the EXACT Cordis effect disposer (single-shot; a repeat call + * returns undefined without awaiting an in-flight teardown). Exact + * identity is load-bearing: a composite (generator) effect that owns a + * teardown ORDER — the agent factory's lifecycle chain — must yield THIS + * function so Cordis nests the unregistration at that yield position; + * yielding a wrapper would leave it disposing as a concurrent sibling on + * owner unload, unregistering the agent (and emitting `agent/disposed`) + * while its final turn is still draining. + */ + register(agent) { + const dispose = this.ctx.effect(function* () { + yield this.enter(agent, this.ctx.agent); + this.announce(agent); + }.bind(this), 'agents.register()'); + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity + return dispose; + } + /** + * Insert an already-constructed agent without announcing it. This is the + * advanced ordered-lifecycle primitive used by the async agent factory: it + * first completes setup while the agent is unpublished, then assigns the + * returned detach closure into its pre-installed composite teardown before + * calling {@link announce}. Ordinary callers use {@link register}. + * @param agent - the prepared, unpublished agent. + * @param owner - live agent whose scoped context created this agent, or + * undefined for a top-level runtime root. This is runtime ownership, not + * the resumed session's durable parent lineage. + * @returns an idempotent closure that removes this exact entry and emits + * `agent/disposed` with listener failures contained. When called from a + * synchronous `agent/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + */ + enter(agent, owner) { + const id = agent.id; + if (id !== agent.session.id) { + throw new Error(`agent id "${id}" does not match session id "${agent.session.id}"`); + } + const carrier = scopeTarget(agent, agent); + // This is the authoritative collision boundary. Concurrent create/resume + // operations may both prepare, but only one exact entry can publish. + if (this.store.has(id)) + throw new Error(`agent "${id}" is already registered`); + const entry = { + id, + agent, + owner, + carrier, + announced: false, + announcing: false, + detachRequested: false, + }; + this.store.set(id, entry); + let entered = true; + const detach = () => { + if (!entered) + return; + entered = false; + // Every callback reached by this creation dispatch must observe the same + // live entry, and disposal must follow creation. A listener may own + // the advanced detach capability, so make that ordering structural: + // visibility and the paired disposal are deferred until announce()'s + // synchronous dispatch has unwound. + if (entry.announcing) { + entry.detachRequested = true; + return; + } + this.detachEntered(entry); + }; + return detach; + } + /** Remove one exact entered agent and emit its paired disposal when announced. */ + detachEntered(entry) { + entry.detachRequested = false; + // A stale capability can never delete a later same-id lifecycle. The + // captured entry identity is the final boundary. + /* v8 ignore next -- enter() rejects replacement while this single-shot detach capability is live. */ + if (this.store.get(entry.id) !== entry) + return; + this.store.delete(entry.id); + // An insertion rolled back before announce was never externally created, + // so emitting disposed would invent an impossible lifecycle edge. Marking + // happens before the created emit: if a later created listener throws, + // earlier listeners may already have observed it and must see disposal. + if (!entry.announced) + return; + this.emitDisposed(entry); + } + /** Emit the paired disposal edge through the entry's stable carrier. */ + emitDisposed(entry) { + const args = [entry.carrier, 'agent/disposed', { agent: entry.agent }]; + for (const callback of this.ctx.events.dispatch('emit', args)) { + try { + const returned = callback(...args); + void Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`agent "${entry.id}": agent/disposed listener rejected: ${String(error)}`); + }); + } + catch (error) { + this.ctx.logger.warn(`agent "${entry.id}": agent/disposed listener threw: ${String(error)}`); + } + } + } + /** + * Announce an agent previously inserted with {@link enter}. + * @param agent - the live inserted agent to announce. + * @throws if `agent` is not the exact live registry entry for its id, or its + * creation announcement already began (including a reentrant call from a + * creation listener). + */ + announce(agent) { + const entry = this.store.get(agent.id); + if (entry === undefined || entry.agent !== agent) { + throw new Error(`agent "${agent.id}" is not live in this registry`); + } + if (entry.announced || entry.announcing) { + throw new Error(`agent "${entry.id}" was already announced`); + } + // Mark before dispatch so a listener cannot recursively create a second + // lifecycle edge; detach still pairs a partially delivered first edge. + entry.announcing = true; + entry.announced = true; + const args = [entry.carrier, 'agent/created', { agent: entry.agent }]; + try { + for (const callback of this.ctx.events.dispatch('emit', args)) { + // A synchronous creation failure vetoes publication and rolls back. + // Returned-promise rejection happens after this synchronous boundary, so + // observe and report it instead of leaking an unhandled rejection. + const returned = callback(...args); + void Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`agent "${entry.id}": agent/created listener rejected: ${String(error)}`); + }); + } + } + finally { + entry.announcing = false; + if (entry.detachRequested) + this.detachEntered(entry); + } + } + /** + * Look up a live agent. + * @param id - the shared agent/session id to look up. + * @returns the agent, or undefined when no live agent has that id. + */ + get(id) { + return this.store.get(id)?.agent; + } + /** + * Test whether a live agent was created through one exact parent agent's + * scoped context. Runtime ownership is independent of durable session + * lineage and remains unambiguous when unrelated providers reuse an id. + * @param id - the candidate child agent's shared agent/session id. + * @param owner - the expected runtime creator agent. + * @returns true only while the exact child entry is live under that owner. + */ + isOwnedBy(id, owner) { + return this.store.get(id)?.owner === owner; + } + /** + * All live agents, in registration order. + * @returns a fresh array; mutating it does not affect the registry. + */ + list() { + return [...this.store.values()].map(entry => entry.agent); + } + /** + * All live top-level agents in registration order. A top-level agent was + * created without an owning agent context; durable session lineage does not + * affect this runtime relation, so a resumed fork may still be a root. + * @returns a fresh array; mutating it does not affect the registry. + */ + roots() { + return [...this.store.values()] + .filter(entry => entry.owner === undefined) + .map(entry => entry.agent); + } + /** Reject new initiator boundaries while inherited continuations drain. */ + closeInitiators() { + if (this.initiatorState === 'active') + this.initiatorState = 'closing'; + } + /** Wait for returned-Promise boundaries, then invalidate retained references. */ + disposeInitiators() { + return (this.initiatorDisposal ??= (async () => { + this.closeInitiators(); + this.releaseReentrantInitiatorRuns(); + if (this.activeInitiatorRuns !== 0) { + this.initiatorDrain ??= Promise.withResolvers(); + await this.initiatorDrain.promise; + } + this.initiatorState = 'disposed'; + this.initiators.disable(); + this.initiatorRuns.disable(); + })()); + } + /** Establish one tracked initiator or clearing boundary. */ + runWithInitiator(agent, operation) { + if (this.initiatorState !== 'active') + throw new Error(DISPOSED_INITIATOR_MESSAGE); + const run = { + active: true, + parent: this.initiatorRuns.getStore(), + }; + this.activeInitiatorRuns += 1; + let result; + try { + result = this.initiatorRuns.run(run, () => this.initiators.run(agent, operation)); + } + catch (error) { + this.releaseInitiatorRun(run); + throw error; + } + if (isPromise(result)) { + try { + void Promise.prototype.then.call(result, () => { this.releaseInitiatorRun(run); }, () => { this.releaseInitiatorRun(run); }); + } + catch { + // A branded Promise may expose a failing @@species. Observer setup did + // not attach, so preserve the exact return without leaking the run. + this.releaseInitiatorRun(run); + } + } + else { + this.releaseInitiatorRun(run); + } + return result; + } + /** Whether one unloading fiber owns this service's lifecycle. */ + hasLifecycleAncestor(candidate) { + let fiber = this.ctx.fiber; + while (true) { + if (fiber === candidate) + return true; + const parent = fiber.parent.fiber; + if (parent === fiber) + return false; + fiber = parent; + } + } + assertInitiatorsReadable() { + if (this.initiatorState === 'disposed') + throw new Error(DISPOSED_INITIATOR_MESSAGE); + } + /** Exclude the boundary chain that initiated this teardown from its own drain. */ + releaseReentrantInitiatorRuns() { + let run = this.initiatorRuns.getStore(); + while (run !== undefined) { + this.releaseInitiatorRun(run); + run = run.parent; + } + } + releaseInitiatorRun(run) { + if (!run.active) + return; + run.active = false; + this.activeInitiatorRuns -= 1; + if (this.activeInitiatorRuns !== 0) + return; + this.initiatorDrain?.resolve(); + this.initiatorDrain = undefined; + } +} +export default AgentRegistry; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.d.ts new file mode 100644 index 0000000..5d42f3c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned agent lifecycle invariants. @module @deepseek-ai/dsh-agent/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "agent-invariant"; +/** Services required before the companion can register. */ +export declare const inject: string[]; +/** + * Register the agent invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.js new file mode 100644 index 0000000..e88c5bc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.js @@ -0,0 +1,24 @@ +/** Package-owned agent lifecycle invariants. @module @deepseek-ai/dsh-agent/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-agent'; +/** Cordis companion plugin name. */ +export const name = 'agent-invariant'; +/** Services required before the companion can register. */ +export const inject = ['invariants']; +/** Install the agent contribution into its child registration fiber. */ +const install = (ctx, fail) => { + const lastStatus = new WeakMap(); + ctx.on('agent/status', ({ agent, status }) => { + const previous = lastStatus.get(agent); + if (previous === status) { + fail(`agent/status repeated ${status} (no-op transition)`); + } + lastStatus.set(agent, status); + }, { global: true }); +}; +/** + * Register the agent invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.d.ts new file mode 100644 index 0000000..2ba3db5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.d.ts @@ -0,0 +1,36 @@ +/** + * Agent-scoped model selection shared by runtime entry points. + * @module @deepseek-ai/dsh-agent/model-selection + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { ReasoningEffortId } from '@deepseek-ai/dsh-llm'; +/** Complete provider, model, and optional reasoning effort selected for one live Agent. */ +export interface ModelSelection { + /** Registered provider route. */ + provider: string; + /** Provider-owned model id. */ + model: string; + /** Adapter-owned reasoning effort, or provider/default behavior when absent. */ + reasoningEffort?: ReasoningEffortId; +} +/** Mutable model selection plus the value captured for the current step. */ +export interface ModelSelectionRef { + /** Model selected for the next step that enters prompt assembly. */ + current: ModelSelection | undefined; + /** Selection captured when the current step entered prompt assembly. */ + assembled: ModelSelection | undefined; +} +/** + * Couple one mutable selection to Agent-scoped prompt assembly and request routing. + * Prompt assembly snapshots the selected model before delegating, then applies + * its provider/model pair and effort to request config so a + * concurrent switch takes effect on a later step instead of splitting the two + * surfaces. An absent selected effort clears any inherited effort, restoring + * the selected model's provider/default behavior. + * + * @param agentCtx - The selected Agent's scoped context. + * @param selection - Mutable selection owned by the calling entry point. + * @returns Disposer for both scoped waterfall listeners. + */ +export declare function installModelSelection(agentCtx: Context, selection: ModelSelectionRef): () => void; +//# sourceMappingURL=model-selection.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.js new file mode 100644 index 0000000..d8a5963 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.js @@ -0,0 +1,53 @@ +/** + * Agent-scoped model selection shared by runtime entry points. + * @module @deepseek-ai/dsh-agent/model-selection + */ +/** + * Couple one mutable selection to Agent-scoped prompt assembly and request routing. + * Prompt assembly snapshots the selected model before delegating, then applies + * its provider/model pair and effort to request config so a + * concurrent switch takes effect on a later step instead of splitting the two + * surfaces. An absent selected effort clears any inherited effort, restoring + * the selected model's provider/default behavior. + * + * @param agentCtx - The selected Agent's scoped context. + * @param selection - Mutable selection owned by the calling entry point. + * @returns Disposer for both scoped waterfall listeners. + */ +export function installModelSelection(agentCtx, selection) { + const disposeAssembly = agentCtx.on('system-prompt/assemble', async (_assembly, _context, next) => { + const selected = selection.current; + const assembled = await next(); + selection.assembled = selected; + if (selected === undefined) + return assembled; + return { + ...assembled, + variables: { + ...assembled.variables, + provider: selected.provider, + model: selected.model, + }, + }; + }); + const disposeRequest = agentCtx.on('agent/request', async (_payload, next) => { + const resolved = await next(); + const selected = selection.assembled; + if (selected === undefined) + return resolved; + const { reasoningEffort: _inheritedEffort, ...withoutInheritedEffort } = resolved; + return { + ...withoutInheritedEffort, + provider: selected.provider, + model: selected.model, + ...selected.reasoningEffort === undefined + ? {} + : { reasoningEffort: selected.reasoningEffort }, + }; + }); + return () => { + disposeAssembly(); + disposeRequest(); + }; +} +//# sourceMappingURL=model-selection.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.d.ts new file mode 100644 index 0000000..70e82d1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.d.ts @@ -0,0 +1,324 @@ +/** + * Public agent types and live-runtime events. Durable transcript facts and + * turn/step boundaries remain `@deepseek-ai/dsh-session` events. + * + * @module @deepseek-ai/dsh-agent + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { Scoped } from '@deepseek-ai/dsh-scope'; +import type { LlmCallConfig, LlmFailure, ResolvedRetryPolicy } from '@deepseek-ai/dsh-llm'; +import type { AgentCancelCause, Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session'; +export type { AgentCancelCause } from '@deepseek-ai/dsh-session'; +import type { Inbox } from './inbox.ts'; +import type { InboxTarget } from './types.ts'; +declare module '@deepseek-ai/dsh-system-prompt' { + interface AssembleContext { + /** Agent for this assembly; absent on diagnostics. When present, `scope` must identify the same agent. */ + agent?: Agent; + } +} +/** Merge-extensible agent creation options. Persona belongs to system-prompt sections. */ +export interface AgentOptions { + /** Provider route (must have a registered adapter at call time). */ + provider?: string; + /** Model id interpreted by the selected provider adapter. */ + model?: string; + /** Maximum output tokens for each conversation-model request. */ + maxTokens?: number; +} +/** Options for {@link Agent.cancel}. */ +export interface CancelOptions { + /** + * Preserve queued and steering inbox items instead of discarding them. The + * active turn is still aborted, but un-started and pending work survives for a + * later turn and no canceled inbox splice is logged. + */ + keepInbox?: boolean | undefined; +} +/** + * An agent's lifecycle state, emitted on every transition as `agent/status`: + * `idle` means no driver is active; `running` begins when waking input starts + * cancellable pre-step processing and lasts while the driver drains, + * closes, or checkpoints turns. Disposal removes the agent from its registry; + * it is not a third observable status. + */ +export type AgentStatus = 'idle' | 'running'; +/** Whether and with which messages the loop enters a proposed step. */ +export type PreStepDecision = { + kind: 'reject'; +} | { + kind: 'enter'; + messages: UserMessage[]; +}; +/** Action returned by a listener that owns model-request recovery. */ +export type RequestErrorAction = { + kind: 'retry'; +} | undefined; +/** Why a session lifecycle began; seeded creates are `startup`, while persisted loads are `resume`. */ +export type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact'; +/** Public live-agent handle. */ +export interface Agent { + /** The single identity shared with {@link session}. */ + readonly id: SessionId; + /** The provider route and model this agent's requests use. */ + readonly options: AgentOptions; + /** The live session this agent drives; its log is the durable source of truth. */ + readonly session: Session; + /** The agent-owned projection of durable pending work. */ + readonly inbox: Inbox; + /** The current lifecycle state, mirrored on every `agent/status` transition. */ + readonly status: AgentStatus; + /** Agent-scoped context; its contributions are agent-local, unwind on disposal, and reject registration afterward. */ + readonly ctx: Context; + /** + * Clear queued and steering work — unless `keepInbox` — and abort the active + * turn or between-turn task. The first cause wins for that activity. With no + * active activity, cancellation is a no-op and does not arm later work. + * @param cause - the stable caller intent carried by the active operation signal. + * @param options - cancellation options; `keepInbox` preserves pending work. + */ + cancel(cause: AgentCancelCause, options?: CancelOptions): void; + /** + * Resolve after the current whole-agent activity reaches quiescence. This + * follows replacement work started before the observed driver retires, + * but does not identify the settlement of any particular message. + * @returns fulfillment after no active driver or maintenance task remains. + */ + whenIdle(): Promise; + /** + * Run one non-turn maintenance task from the true idle phase. The task starts + * synchronously after claiming that phase; later waking input remains in the + * inbox until the task settles, while public status stays `idle`. + * `whenIdle()` follows both the task and any waking work released behind it. + * @param task - operation whose fulfillment or rejection is preserved, with a signal aborted by {@link cancel}. + * @throws synchronously when turn-driving or another maintenance task already owns the agent. + * @returns the task promise. + */ + runMaintenance(task: (signal: AbortSignal) => Promise): Promise; + /** + * Route identified input to an inbox boundary and optionally wake the driver. + * Waking input submitted after active cancellation is queued for the next + * turn and runs when the aborted activity converges to idle; a `disposed` + * cancel leaves it parked. A wake submitted while already idle always opens + * its turn boundary, even when its message is cleared before the driver + * claims ([cancel-convergence wake latch](../../../../.agents/notes/implemented/bug-fix/2026-08-07-cancel-convergence-wake-latch.md)). + * @param message - identified content and the source that supplied it. + * @param target - the preferred next-turn or next-step inbox boundary. + * @param wakeup - whether delivery may wake the driver. + */ + send(message: UserMessage, target: InboxTarget, wakeup: boolean): void; + /** + * Queue an ordinary follow-up turn and wake the driver. The item becomes the + * sole ordinary message of its own turn. + * @param message - identified prompt content and the source that supplied it. + */ + followup(message: UserMessage): void; + /** + * Submit steering for the nearest step. An idle driver starts a turn; + * a running driver consumes it at its next step boundary. + * A rejected step leaves steering parked in the inbox until the next + * wake; cancellation or disposal may discard pending steering. + * @param message - identified steering content and the source that supplied it. + */ + steer(message: UserMessage): void; + /** + * Queue model-facing context for the next pre-step without waking the + * driver. A running driver claims it at the nearest later step boundary; + * idle drivers leave it pending until follow-up or steering + * wakes them. It may miss a request whose pre-step already claimed its + * batch. Cancellation or disposal may discard pending context. + * @param message - identified injected context and the source that supplied it. + */ + inject(message: UserMessage): void; +} +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * A fully configured agent and live session were published. Setup is + * composition-only; `agent/session-start` is the first startup-driving extension point. + * Synchronous listener failure vetoes publication, while returned-promise + * rejection is reported. Detach requested during dispatch waits until every + * creation listener has observed the stable entry. + * @param payload.agent - the newly registered agent with its live session and completed setup. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/created'(this: Scoped, payload: { + agent: Agent; + }): void; + /** + * An agent left the registry; AgentLoop emits this after driver quiescence + * and scoped-registration unwind, but before session detachment. Custom + * registry users own their driver-ordering contract. + * @param payload.agent - the exact agent removed from the registry. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/disposed'(this: Scoped, payload: { + agent: Agent; + }): void; + /** + * Agent status changed (`idle` ⇄ `running`). A waking delivery enters + * `running` synchronously after reserving cancellation; `idle` means no + * driver remains scheduled or active. + * @param payload.agent - the agent whose status flipped. + * @param payload.status - the status just entered (the transition's destination). + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/status'(this: Scoped, payload: { + agent: Agent; + status: AgentStatus; + }): void; + /** + * One message entered the live inbox. + * @param payload.agent - the agent whose inbox changed. + * @param payload.message - the inserted message. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/inbox/inserted'(this: Scoped, payload: { + agent: Agent; + message: UserMessage; + }): void; + /** + * One message left the inbox inside its open turn. If the proposed step + * is rejected, the claimed message ends here: it is neither discarded nor + * re-emitted as a user/message, and the turn closes without a step. + * @param payload.agent - the agent whose inbox changed. + * @param payload.message - the claimed message. + * @param payload.turn - the owning turn. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/inbox/claimed'(this: Scoped, payload: { + agent: Agent; + message: UserMessage; + turn: number; + }): void; + /** + * One message was discarded from the live inbox. + * @param payload.agent - the agent whose inbox changed. + * @param payload.message - the discarded message. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/inbox/discarded'(this: Scoped, payload: { + agent: Agent; + message: UserMessage; + }): void; + /** + * The session lifecycle began, once before the first turn. Use + * `agent.inject()` to seed model-facing context. This is a notification, not + * a veto; disposal requested by a lifecycle owner is rechecked before the + * driver starts. + * @param payload.agent - the agent whose session lifecycle began. + * @param payload.source - why the session started (fresh startup, resume, …). + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/session-start'(this: Scoped, payload: { + agent: Agent; + source: SessionStartSource; + }): void; + /** + * Reject a proposed step or replace the messages that enter it. Calling + * `next()` preserves the current messages. + * @param payload.agent - the agent proposing the step. + * @param payload.messages - messages removed from the inbox for this step. + * @param payload.turn - the turn that will own the step. + * @param payload.step - the step proposed by the loop. + * @param payload.signal - the current turn's cancellation signal. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode waterfall + */ + 'agent/pre-step'(this: Scoped, payload: { + agent: Agent; + messages: UserMessage[]; + turn: number; + step: number; + signal: AbortSignal; + }, next: () => Promise): Promise; + /** + * Replace the frozen call configuration. `await next()` yields the config + * the machine would use (agent options on the first request, the logged + * header afterwards); return a replacement to switch. Model-visible + * content must use logged channels; this waterfall cannot mutate messages. + * @param payload.agent - the agent making the model call. + * @param payload.turn - the open turn number. + * @param payload.step - the step whose request this is. + * @param payload.signal - the current turn's explicit abort signal. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode waterfall + */ + 'agent/request'(this: Scoped, payload: { + agent: Agent; + turn: number; + step: number; + signal: AbortSignal; + }, next: () => Promise): Promise; + /** + * Handle one failed model-request attempt before the loop retries or closes + * its step. A listener returns `{ kind: 'retry' }` without calling `next()` + * when it owns recovery, or calls `next()` to delegate. The default + * `undefined` leaves the failure terminal. + * @param payload.agent - the agent whose request failed. + * @param payload.turn - the turn containing the failed request. + * @param payload.step - the step containing the failed request attempt. + * @param payload.provider - the provider selected for the failed request. + * @param payload.failure - serializable facts normalized at the final adapter boundary. + * @param payload.retryPolicy - the policy of the adapter registration that served the failed request. + * @param payload.signal - the turn abort signal. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode waterfall + */ + 'agent/request-error'(this: Scoped, payload: { + agent: Agent; + turn: number; + step: number; + provider: string; + failure: LlmFailure; + retryPolicy: ResolvedRetryPolicy | undefined; + signal: AbortSignal; + }, next: () => Promise): Promise; + /** + * The turn is about to close: the model owes no response (no live tool + * calls, no fresh steering). Awaited before the boundary commits — a + * listener that objects steers (`agent.steer(...)`) and the machine + * re-reads its inbox: fresh steering runs another step, none closes the + * turn. Data decides, so listener order cannot change the outcome. The + * inverse control (stop a tool loop early) is data too: a tool result + * carrying `concludesTurn` ends the turn at its step. The conclusion + * never short-circuits already-submitted next-step work: same-step + * `additionalContexts` or racing steering still runs, and the turn + * closes only when that inbox drains. + * @param payload.agent - the agent whose turn is at its stop boundary. + * @param payload.turn - the turn about to close. + * @param payload.signal - the current turn's explicit abort signal. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode serial + */ + 'agent/turn-stopping'(this: Scoped, payload: { + agent: Agent; + turn: number; + signal: AbortSignal; + }): Promise | void; + /** + * A step or turn errored. The machine reports a failure here even when + * the error has no in-turn position for a durable record. + * @param payload.agent - the agent whose turn errored. + * @param payload.turn - the turn in which the failure surfaced. + * @param payload.step - the step at which the failure surfaced. + * @param payload.error - the failure, verbatim. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/error'(this: Scoped, payload: { + agent: Agent; + turn: number; + step: number; + error: unknown; + }): void; + } +} +//# sourceMappingURL=runtime-types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.js new file mode 100644 index 0000000..2f6b2fc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.js @@ -0,0 +1,8 @@ +/** + * Public agent types and live-runtime events. Durable transcript facts and + * turn/step boundaries remain `@deepseek-ai/dsh-session` events. + * + * @module @deepseek-ai/dsh-agent + */ +export {}; +//# sourceMappingURL=runtime-types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/types.d.ts new file mode 100644 index 0000000..368e1f5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/types.d.ts @@ -0,0 +1,25 @@ +/** + * Durable agent session-event vocabulary shared with type-only consumers. + * + * @module @deepseek-ai/dsh-agent/types + */ +import type { UserMessage } from '@deepseek-ai/dsh-llm/types'; +/** One of the two ordered pending-message lists owned by an agent. */ +export type InboxTarget = 'next-turn' | 'next-step'; +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * One normalized mutation of an agent's durable pending-message lists. + * Live dispatch precedes projection mutation, so synchronous observers may + * read the pre-splice inbox to recover the removed messages. + */ + 'agent/inbox/spliced': { + target: InboxTarget; + start: number; + removedCount?: number; + inserted: UserMessage[]; + outcome?: 'canceled'; + }; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/types.js new file mode 100644 index 0000000..3ecc23f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Durable agent session-event vocabulary shared with type-only consumers. + * + * @module @deepseek-ai/dsh-agent/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/package.json new file mode 100644 index 0000000..cfc6aa7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent/package.json @@ -0,0 +1,58 @@ +{ + "name": "@deepseek-ai/dsh-agent", + "description": "Agent interface, registry, initiator scope, and event vocabulary for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/agent" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-system-prompt b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-system-prompt new file mode 120000 index 0000000..7b9075d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-system-prompt @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..aa2ae83 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.i18n.yaml new file mode 100644 index 0000000..7b36d3c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/agent/README.md +README.md: f6b698e93b254c97786155e7d2c7e81f07c0d981 +README.zh.md: 787c4f353909a1e2dbc60c33abb3c101e677e011 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.md new file mode 100644 index 0000000..f6b698e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.md @@ -0,0 +1,121 @@ +# dsh-agent + +English | [中文](README.zh.md) + +Agent interface, registry, process-local initiator scope, and `agent/*` event vocabulary. Every plugin (UI, hooks, orchestrators) programs against the `Agent` handle defined here — it has zero loop dependency, so the loop is swappable. + +The optional `@deepseek-ai/dsh-agent/invariant` companion registers this package's agent-status transition checks with `ctx.invariants`. The root agent service does not load diagnostics implicitly. + +## Service: `AgentRegistry` (ctx key: `agents`) + +Tracks live agents and carries the initiating Agent through asynchronous driver work without importing the concrete loop package. + +### Public API + +The scoped-registration surface: `Agent.ctx` is the agent's scope context (`dsh-scope`, key = the agent) — register tools/sections/variables/listeners through it for that agent alone, all unwound on disposal. `agentEvents(ctx, agent)` is the fused dispatcher for ordinary agent-subject operations (carrier + injected subject in one move); its notification mode invokes every listener and contains both synchronous throws and returned-promise rejections. The registry lifecycle pair reuses one stable routing carrier. `assembleContextFor(agent)` builds the per-agent assembly context (`agent` + `scope` together). `installModelSelection(agentCtx, selection)` snapshots a mutable provider/model/reasoning-effort selection during prompt assembly, applies its provider and model to prompt variables, and applies the complete selection to request routing for one step; an absent selected effort clears an inherited effort so adapter/provider defaults apply. `CreateAgentOptions.setup(agentCtx)` and `ResumeAgentOptions.setup(agentCtx)` compose a fresh or resumed agent's scoped world while both objects remain unpublished. Setup is trusted, composition-only same-process code: drive the agent only after creation resolves. + +`AgentOptions` supplies the initial provider/model route and an optional positive `maxTokens` output cap. The concrete loop resolves any exact-model adapter default, records the effective cap in the request header, and applies it to each conversation-model request; an explicit Agent option wins, while omission leaves the adapter or provider route default in control. + +- `ctx.agents.register(agent: Agent): () => void` — record an **already-constructed** agent. Disposed with the calling fiber. +- Advanced ordered lifecycle: `enter(agent, owner): () => void` enforces `agent.id === agent.session.id`, performs the authoritative ID collision check, and inserts without announcing; `owner` explicitly records the live creator-agent relation (or `undefined` for a root), independently of durable session lineage. `announce(agent)` emits `agent/created` exactly once. A detach requested synchronously by a creation listener is deferred until that dispatch unwinds, and every detach checks the captured entry object, so a stale capability cannot delete a later same-ID replacement. The async factory uses this split; ordinary plugins use `register()`. +- `ctx.agents.get(id: SessionId): Agent | undefined` +- `ctx.agents.isOwnedBy(id: SessionId, owner: Agent): boolean` — whether the exact live entry was created through that parent agent's scoped context; runtime ownership is independent of durable session lineage. +- `ctx.agents.list(): Agent[]` +- `ctx.agents.roots(): Agent[]` — live agents created without an owning agent context; a resumed lineage-bearing session can still be a runtime root. + +#### Initiating Agent scope + +`AgentLoop` runs each concrete driver's complete lifetime inside an initiator boundary. Concurrent drivers remain isolated: a child driver's continuations carry the child, while the parent continuation regains the parent as soon as `withInitiator()` returns; drain tracking continues until the child driver's Promise settles. Creation, persistence load, and unpublished setup remain outside the child's boundary, so setup initiated by a parent inherits the parent while `agentCtx.agent` identifies the child explicitly. + +- `ctx.agents.currentInitiator(): Agent | undefined` — read the inherited initiator without requiring one. +- `ctx.agents.requireInitiator(): Agent` — read it or throw `no initiating agent is active`. +- `ctx.agents.withInitiator(agent, operation)` — run with one exact Agent and preserve the operation's exact synchronous value or Promise. +- `ctx.agents.withoutInitiator(operation)` — hide an inherited initiator for unrelated process-local work. + +The scope carries the `Agent` itself and is process-local. Ambient presence is neither liveness proof nor authorization; explicit Agent fields remain authoritative at service, worker, process, persistence, and wire boundaries. Teardown rejects new boundaries, lets injected dependents and returned-Promise boundaries drain, then disables the underlying `AsyncLocalStorage`; unreturned work remains owned by the subsystem that detached it. If a boundary's inherited async chain starts an owning Cordis fiber's unload, that nested boundary chain is released from the drain so the unload cannot wait on itself; its continuations observe the disposed service after teardown. The [initiator-scope decision](../../../.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md) owns the detailed boundary and teardown contract. + +#### Factory API (creation) + +Agent *creation* is provided by the plugin implementing `AgentFactory` (`dsh-agent-loop`), registered via `setFactory`. This keeps creation on the `dsh-agent` interface so consumers (UI, the ACP bridge) program against `ctx.agents` without depending on the concrete loop package. The registry canonicalizes an already traced Service to its concrete target and re-traces each call through the caller's context; this avoids nested Cordis shadows while passing an explicit caller-bound `ownerCtx` to plain factories. + +- `ctx.agents.setFactory(factory: AgentFactory): () => void` — register the creation factory (the loop calls this on construction). Throws on a second factory; the slot clears on dispose. +- `ctx.agents.create(options: CreateAgentOptions): Promise` — create a session and agent, await optional setup while unpublished, then publish through final `SessionStore.enter()` and `AgentRegistry.enter()` checks. Concurrent same-ID creation is unsupported: more than one operation may prepare, but only one can enter; every loser rolls its private scope/session/driver back. An optional creation-only `signal` cancels unpublished setup and is detached before the handle is returned; later cancellation uses `handle.dispose()` or `agent.cancel()`. Publication is rollback-covered and every delivered creation edge is paired during rollback. Rejects if no factory is registered. +- `ctx.agents.resume(options: ResumeAgentOptions): Promise` — load a persisted session ([session persistence](../../../.agents/notes/implemented/architecture/2026-06-14-session-persistence.md)), mint a fresh unpublished agent scope, await optional setup, and use the same final-entry publication sequence. Its optional `signal` is likewise creation-only. Rejects if no factory is registered or session persistence is unconfigured. + +`AgentHandle = { agent: Agent; dispose(): Promise }`. The disposer is a **consumer capability** — no observer holding the bare registry entry can tear the agent down. The caller fiber and the registered factory provider are structural co-owners: caller unload enforces structured ownership, while factory unload must stop old instances because their scoped dependency surface belongs to that provider. `dispose()` from any owner reaches one memoized quiescence boundary: it stops the loop, awaits its exit, unregisters the agent, removes its session from the store, and finally unwinds its scoped world. `ctx.agents.get(id)` still returns a bare `Agent`; the ACP bridge and in-process subagent backends hold consumer handles, while config-created agents are already owned by the loop fiber. + +### Live events + +`dsh-agent` declares the live `agent/*` coordination vocabulary so plugins do not depend on the concrete loop. Exact signatures, dispatch modes, scope-filtering rules, and payload contracts live in the generated region of [core.md](../../../docs/subsystems/core.md#cordis-surface); the [architecture turn flow](../../../docs/architecture.md#turn-flow) shows their order relative to durable session events. + +The lifecycle edges have two important local caveats. `agent/created` runs after scoped setup and after both session and agent registry entries exist. Setup is trusted composition-only code; the immediately following non-vetoing `agent/session-start` notification is the first supported startup injection point. `agent/disposed` always means the exact agent has left the registry. AgentLoop emits it after its driver is quiescent, while ordered teardown may still be detaching the session and unwinding the scope; custom agents registered directly own any stronger driver-ordering contract themselves. + +Most interception points are cooperative waterfalls. `agent/pre-step` receives a payload carrying the subject `agent`, the exclusive claimed `UserMessage[]`, and the proposed `turn`, `step`, and cancellation `signal`; its batch may be empty when tools already require another request. Agent-scoped turn extension points carry their explicit `AbortSignal` in the payload; the remaining turn-scoped extension points receive it through their request value. Listeners may cooperate with a signal but must not retain it as authority over another turn. `agent/request-error` is the failed-model-request recovery waterfall: it receives request coordinates, normalized failure facts, the serving registration's retry policy when available, and the signal. A listener returns `{ kind: 'retry' }` without calling `next()` when it owns recovery. `agent/turn-stopping` runs before an otherwise completed turn closes. The [explicit-cancellation decision](../../../.agents/notes/implemented/architecture/2026-07-16-explicit-turn-cancellation.md) owns signal lifetime; the [agent-scope runtime-design Agent Note](../../../.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#three-execution-boundaries-are-deliberately-one-way) owns scoped dispatch and terminal settlement. + +`PreStepDecision` is either `{ kind: 'reject' }` or `{ kind: 'enter', messages }`. The enter branch is the complete identified, frozen batch for the proposed step. A listener that wraps downstream entry preserves that batch unless it intentionally replaces it; additions follow the waterfall's natural return order. Claiming already removed the offered messages from the inbox, so rejection does not retain them. Messages inserted after the claim remain pending for a later boundary. + +Inbox live notifications are deliberately per-message and minimal: `agent/inbox/inserted { message }`, `agent/inbox/claimed { message, turn }`, and `agent/inbox/discarded { message }`. They complement the durable `agent/inbox/spliced` projection without adding another lifecycle envelope. + +Turn and step boundaries and the model token stream are durable `session/event` facts rather than mirrored `agent/*` notifications. Consumers read `turn/*`, `step/*`, and `assistant/chunk` from the session feed; tool policy and outcome observation belong to the complete pipeline documented by [`dsh-tools`](../tools/README.md). + +`foldConsumedWork(events)` reads that feed back for the one question the turn sequence cannot answer alone: what became of the work a log consumed. It returns the latest `turn/end` that accounts for consumed work — a turn that entered a model step, or one that claimed inbox input and then failed, was stopped, or was rejected before reaching one — plus whether accepted work was later cancelled out of the inbox unrun. Both facts come from the log, so a cancellation reads the same whichever owner issued it. A no-step turn that took nothing, or emptied its claim and completed, describes no work and is skipped; a `blocked` end over claimed input is an account, because rejection discarded that input. + +### Agent interface (`types.ts`) + +The handle every plugin programs against: + +- `agent.inbox` — the agent-owned projection of durable `agent/inbox/spliced` events. `nextTurn` and `nextStep` expose pending `UserMessage` values. `append`, `prepend`, `replace`, `remove`, `clear`, `splice`, and `claim` mutate them; `replace(messageId, newMessage)` and `remove(messageId)` locate the pending message across both lists. Replacement may change identity and publishes the old message as discarded followed by the new message as inserted. Ordinary removals and `clear()` are durable cancellations and emit `agent/inbox/discarded`. `claim(target)` removes the next proposed batch with pure deletion splices; the loop then emits `agent/inbox/claimed`. `MessageId` is the only occurrence identity and must remain unique while pending. +- `agent.followup(message)` — queue an ordinary `next-turn` message and wake the driver. It returns no completion handle; the message id identifies inbox insertion, claim, and discard facts, not a later output or `turn/end`. +- `agent.steer(message)` — queue waking `next-step` input. An idle agent starts a turn synchronously; a running driver consumes later steering at its next step boundary. +- `agent.inject(message)` — queue non-waking `next-step` context. A running driver claims it at the nearest later pre-step boundary; an idle driver leaves it pending until `followup()` or `steer()` wakes the driver. It may miss a request whose pre-step already claimed its batch. +- `agent.cancel(cause, options?)` — cancel the active driver and, unless `options.keepInbox`, durably cancel all pending inbox work. Idle cancellation is a no-op. +- `agent.whenIdle()` — observe whole-agent quiescence, including replacement work scheduled before the current driver retires. It does not settle any particular message. +- `agent.session`, `agent.status`, `agent.options`, `agent.id`, `agent.ctx` + +`running` describes a driver-wide drain interval, not proof that a turn is still open; it can cover turn close, the durability checkpoint, and consecutive queued turns. Only a caller that owns a complete interval may summarize it as a run result ([decision](../../../.agents/notes/implemented/architecture/2026-07-30-followup-enqueue-and-owned-runs.md)). + +### Extension points + +- Agent creation: `AgentLoop.create()` is the concrete config-path implementation (in `dsh-agent-loop`), while programmatic consumers create/resume owned agents through `ctx.agents.create()` / `ctx.agents.resume()`. Replace the loop by implementing `Agent` and registering via `ctx.agents.register()`. +- Event listeners: all `agent/*` events are declared here — no dependency on the loop package needed. +- Subagent delegation is not an `Agent` method; providers create or drive ordinary handles through the factory API, so delegation transports stay outside the core agent interface. + +## Model Experience + +### User, steering, and injected messages + +#### What the model sees + +`send`, `steer`, and `inject` feed the owning session. `agent/pre-step` and other declared events let plugins reject a proposed step or add durable request material; this interface contributes no fixed prose itself. + +#### Token effect + +Accepted content becomes retained history or a repeated session prefix; blocked content contributes no request tokens. Size is caller- and plugin-dependent. + +#### KV Cache effect + +Accepted history and steering are append-only; a blocked submission sends no request. A session prefix remains stable within its loop instance, while a new or resumed instance may establish a different prefix. + +### Agent-scoped request composition + +#### What the model sees + +Registrations through `agent.ctx` can shadow prompt sections or tools and can install agent-only interceptors during unpublished setup. + +#### Token effect + +The package adds zero tokens itself; scoped contributions affect only that agent and disappear on disposal. + +#### KV Cache effect + +Prefix-stable while an agent's scoped registrations are unchanged. Setup or reload that changes prompt sections, tool definitions, or request listeners may invalidate reuse from the first affected request token. + +## Known Limitations and Deferred Work + +- **Initiator scope is process-local** — workers, child processes, HTTP, durable queues, and restarts materialize any required identity explicitly. +- **Ambient identity may outlive liveness** — consumers still check `agent.status`, cancellation, and the owning capability contract before lifecycle-sensitive work. +- **Inter-agent channels beyond delegation** — shared state, streaming child output, and background/poll semantics remain outside the current synchronous `ctx.subagents` seam. +- **`agent/session-start` cannot gate startup** — it remains a synchronous, veto-less notification; async composition that must finish before publication belongs in the factory's `setup(agentCtx)` transaction instead. +- **`cancel()` clears the inbox by default** — it aborts the in-flight turn plus queued and steering work; `cancel(cause, { keepInbox: true })` aborts only the turn and preserves pending items. There is still no step-only abort that keeps the in-flight turn running ([stop API Agent Note](../../../.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-api.md)). +- **Each additional `UserMessage` carries exactly one `MessageSource`** — contributions from several plugins merged onto one tool call collapse under one source, so the message cannot name several producers. +- **`SessionStartSource` reserves `'clear'`/`'compact'` with no emitter yet** — only `'startup'`/`'resume'` occur until the driving subsystems land (`TODO(compaction)`). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.zh.md new file mode 100644 index 0000000..787c4f3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/README.zh.md @@ -0,0 +1,121 @@ +# dsh-agent + +[English](README.md) | 中文 + +Agent 接口、注册表、进程本地发起方作用域,以及 `agent/*` 事件词汇。每个插件(UI、钩子、编排器)都面向此处定义的 `Agent` handle 编程;它不依赖循环,因此循环可以替换。 + +可选配套包 `@deepseek-ai/dsh-agent/invariant` 会向 `ctx.invariants` 注册此包的 agent(智能体)状态转换检查。根 agent 服务不会隐式加载诊断。 + +## 服务:`AgentRegistry`(ctx 键:`agents`) + +跟踪实时 agent,并在异步驱动器工作中携带发起调用的 Agent,而无需导入具体循环包。 + +### 公开 API + +带作用域的注册接口:`Agent.ctx` 是 agent 的作用域上下文(`dsh-scope`,键 = 该 agent)。通过它注册工具/段/变量/监听器,只对该 agent 生效,并在 dispose(资源释放)时全部撤销。`agentEvents(ctx, agent)` 是普通 agent 主体操作的融合分发器(一次完成载体 + 注入主体);其通知 mode 会调用每个监听器,并同时收容同步抛出和返回 Promise 的拒绝。注册表生命周期对复用一个稳定路由载体。`assembleContextFor(agent)` 构建按 agent 的组装上下文(同时包含 `agent` + `scope`)。`installAgentLlmTarget(agentCtx, target)` 在提示词组装期间快照可变的提供方/模型/推理(reasoning)强度选择,将路由应用到提示词变量,并将完整目标应用到一个步骤的请求路由;如果没有选定推理强度,则会清除继承的推理强度,使该目标使用适配器/提供方默认值。`CreateAgentOptions.setup(agentCtx)` 和 `ResumeAgentOptions.setup(agentCtx)` 在新建或恢复的 agent 尚未发布时,组合其带作用域的世界。Setup 是受信任、仅用于组合的同进程代码:只有创建完成后才能驱动 agent。 + +`AgentOptions` 提供初始的提供方/模型路由,以及可选的正数 `maxTokens` 输出上限。具体循环会解析确切模型的适配器默认值,把生效上限记录到请求 header,并应用到每次对话模型请求;显式 Agent 选项优先,省略时由适配器或提供方路由默认值控制。 + +- `ctx.agents.register(agent: Agent): () => void`:记录一个 **已经构造完成** 的 agent。随调用 fiber dispose。 +- 高级有序生命周期:`enter(agent, owner): () => void` 强制 `agent.id === agent.session.id`,执行权威 ID 冲突检查,并在不通知的情况下插入;`owner` 显式记录实时创建方 agent 关系(根 agent 为 `undefined`),与持久会话谱系无关。`announce(agent)` 恰好发出一次 `agent/created`。创建监听器同步请求的 detach 会延后到该次分发结束;每次 detach 都会检查捕获的条目对象,因此陈旧能力无法删除后续使用同一 ID 的替代项。异步工厂使用这一拆分;普通插件使用 `register()`。 +- `ctx.agents.get(id: SessionId): Agent | undefined` +- `ctx.agents.isOwnedBy(id: SessionId, owner: Agent): boolean`:该确切实时条目是否通过父 agent 的作用域上下文创建;运行时所有权与持久会话谱系无关。 +- `ctx.agents.list(): Agent[]` +- `ctx.agents.roots(): Agent[]`:在没有所属 agent 上下文的情况下创建的实时 agent;带谱系的恢复会话仍可能是运行时根。 + +#### 发起方 Agent 作用域 + +`AgentLoop` 在发起方边界内运行每个具体驱动器的完整生命周期。并发驱动器彼此隔离:子驱动器的 continuation 携带子 agent,而 `withInitiator()` 返回后,父 continuation 立即重新取得父 agent;drain 跟踪持续到子驱动器的 Promise 结算。创建、持久化加载和未发布 setup 位于子边界之外,因此由父 agent 发起的 setup 会继承父 agent,而 `agentCtx.agent` 显式标识子 agent。 + +- `ctx.agents.currentInitiator(): Agent | undefined`:读取继承的发起方,不要求其存在。 +- `ctx.agents.requireInitiator(): Agent`:读取发起方,缺席时抛出 `no initiating agent is active`。 +- `ctx.agents.withInitiator(agent, operation)`:使用一个确切 Agent 运行,并保留操作的确切同步值或 Promise。 +- `ctx.agents.withoutInitiator(operation)`:对无关的进程本地工作隐藏继承的发起方。 + +该作用域携带 `Agent` 本身,并且只在进程内有效。环境中的身份既不是存活证明,也不是授权;在服务、worker、进程、持久化和 wire 边界,显式 Agent 字段仍是权威来源。Teardown 会拒绝新边界,允许注入的依赖方和返回 Promise 的边界 drain,然后禁用底层 `AsyncLocalStorage`;未返回的工作仍归将其分离的子系统所有。如果某个边界继承的异步链开始卸载一个拥有它的 Cordis fiber,该嵌套边界链会从 drain 中释放,使卸载不会等待自身;其 continuation 会在 teardown 后观察到已 dispose 的服务。详细边界与 teardown 约定由[发起方作用域决策](../../../.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md)拥有。 + +#### 工厂 API(创建) + +Agent *创建* 由实现 `AgentFactory` 的插件(`dsh-agent-loop`)提供,并通过 `setFactory` 注册。这样,创建功能留在 `dsh-agent` 接口上,消费方(UI、ACP(Agent Client Protocol)桥接层)可以面向 `ctx.agents` 编程,而不依赖具体循环包。注册表会把已经 traced 的 Service 规范化为具体目标,并通过调用方上下文重新 trace 每次调用;这既避免嵌套 Cordis shadow,也会把显式、绑定调用方的 `ownerCtx` 传给普通工厂。 + +- `ctx.agents.setFactory(factory: AgentFactory): () => void`:注册创建工厂(循环在构造时调用)。第二个工厂会导致抛出;dispose 时清空槽位。 +- `ctx.agents.create(options: CreateAgentOptions): Promise`:创建会话和 agent,在不发布的情况下等待可选 setup,然后通过最终的 `SessionStore.enter()` 与 `AgentRegistry.enter()` 检查发布。不支持并发创建同一 ID:多个操作可以进行准备,但只有一个能进入;每个失败方都会回滚其私有作用域/会话/驱动器。可选且只用于创建的 `signal` 会取消未发布的 setup,并在返回 handle 前分离;之后的取消使用 `handle.dispose()` 或 `agent.cancel()`。发布包含在回滚范围内,回滚期间每条已交付创建边都会成对处理。未注册工厂时拒绝。 +- `ctx.agents.resume(options: ResumeAgentOptions): Promise`:加载持久化会话([会话持久化](../../../.agents/notes/implemented/architecture/2026-06-14-session-persistence.md)),创建新的未发布 agent 作用域,等待可选 setup,并使用相同的最终进入发布序列。其可选 `signal` 同样只用于创建。未注册工厂或未配置会话持久化时拒绝。 + +`AgentHandle = { agent: Agent; dispose(): Promise }`。Disposer 是一项 **消费方能力**;仅持有裸注册表条目的观察方不能 teardown agent。调用方 fiber 和已注册工厂提供方是结构化共同拥有者:调用方卸载会强制结构化所有权,而工厂卸载必须停止旧实例,因为它们的作用域依赖范围属于该提供方。任意拥有者调用 `dispose()` 都会到达同一个记忆化完全停稳边界:它停止循环,等待循环退出,注销 agent,从存储中移除其会话,最后撤销其作用域世界。`ctx.agents.get(id)` 仍返回裸 `Agent`;ACP 桥接层与进程内 subagent 后端持有消费方 handle,而配置创建的 agent 已由循环 fiber 拥有。 + +### 实时事件 + +`dsh-agent` 声明实时 `agent/*` 协调词汇,使插件不必依赖具体循环。确切签名、分发 mode、作用域筛选规则与 payload 约定位于 [core.md](../../../docs/subsystems/core.md#cordis-surface) 的生成区块;[架构轮次流](../../../docs/architecture.md#turn-flow) 展示它们与持久会话事件的相对顺序。 + +生命周期边有两个重要的本地注意事项。`agent/created` 在作用域 setup 之后、会话与 agent 注册表条目都存在之后运行。Setup 是受信任、仅用于组合的代码;紧随其后且不可 veto 的 `agent/session-start` 通知是第一个受支持的启动注入点。`agent/disposed` 始终表示确切 agent 已离开注册表。AgentLoop 在其驱动器完全停稳后发出该事件,而有序 teardown 此时可能仍在分离会话并撤销作用域;直接注册的自定义 agent 自行拥有任何更强的驱动器顺序约定。 + +大多数拦截点都是协作式 waterfall(瀑布式事件)。`agent/pre-step` 接收一个 payload,携带主体 `agent`、独占的已领取 `UserMessage[]` 以及拟进入的 `turn`、`step` 与取消 `signal`;当工具已经要求继续请求时,该批次可以为空。agent 作用域轮次扩展点在 payload 中携带显式 `AbortSignal`;其余轮次作用域扩展点通过其请求值接收它。监听器可以配合信号,但不得将它保留为控制另一轮次的权限。`agent/request-error` 是失败模型请求的恢复 waterfall:它接收请求坐标、规范化失败事实、可用时提供服务的注册项重试策略以及信号。拥有恢复权的监听器返回 `{ kind: 'retry' }` 且不调用 `next()`。`agent/turn-stopping` 在本可完成的轮次关闭前运行。信号生命周期由[显式取消决策](../../../.agents/notes/implemented/architecture/2026-07-16-explicit-turn-cancellation.md)拥有;作用域分发与终止结算由 [agent 作用域 runtime 设计 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#three-execution-boundaries-are-deliberately-one-way)拥有。 + +`PreStepDecision` 要么是 `{ kind: 'reject' }`,要么是 `{ kind: 'enter', messages }`。enter 分支是拟进入步骤的完整、带标识且冻结的批次。包装下游 enter 的监听器会保留该批次,除非有意替换它;新增消息遵循 waterfall 的自然返回顺序。领取操作已经把候选消息从 inbox 删除,因此 reject 不会保留它们;领取后插入的消息仍等待后续边界。 + +inbox 的实时通知刻意采用逐消息的最小载荷:`agent/inbox/inserted { message }`、`agent/inbox/claimed { message, turn }` 与 `agent/inbox/discarded { message }`。它们补充持久 `agent/inbox/spliced` 投影,但不引入另一层生命周期封套。 + +轮次和步骤边界以及模型 token 流是持久 `session/event` 事实,而不是镜像的 `agent/*` 通知。消费方从会话事件流读取 `turn/*`、`step/*` 和 `assistant/chunk`;工具策略与结果观测属于 [`dsh-tools`](../tools/README.md) 记录的完整流水线。 + +`foldConsumedWork(events)` 把这条事件流读回来,回答仅凭轮次序列无法回答的那个问题:一份日志消费掉的工作最终怎样了。它返回能够为已消费工作作出交代的最新 `turn/end`——即进入过模型 step 的轮次,或者认领了 inbox 输入、但在进入 step 之前失败、被停下或被拒绝的轮次——并额外给出「已接受的工作此后是否被从 inbox 中取消且从未运行」。两项事实都来自日志,因此无论由哪个所有者发起取消,读出来都一样。没有取走任何输入、或认领批次被改写清空后正常结束的无 step 轮次不描述工作,会被跳过;认领过输入、以 `blocked` 结束的轮次则是一份交代,因为拒绝把这些输入一并丢弃了。 + +### Agent 接口(`types.ts`) + +每个插件面向的 handle: + +- `agent.inbox`:agent 所拥有的持久 `agent/inbox/spliced` 事件投影。`nextTurn` 与 `nextStep` 暴露待处理的 `UserMessage` 值。`append`、`prepend`、`replace`、`remove`、`clear`、`splice` 与 `claim` 用于变更队列;`replace(messageId, newMessage)` 与 `remove(messageId)` 通过 `MessageId` 跨两份列表定位待处理消息。替换可以改变标识,并先将旧消息作为 discarded 发布,再将新消息作为 inserted 发布。普通删除和 `clear()` 都是持久取消,并发出 `agent/inbox/discarded`。`claim(target)` 通过纯删除 splice 移除下一个候选批次,随后由循环发出 `agent/inbox/claimed`。`MessageId` 是唯一的入队项标识,在消息待处理期间必须保持唯一。 +- `agent.followup(message)`:将一条普通 `next-turn` 消息排队并唤醒驱动器。它不返回完成 handle;消息 id 标识 inbox 的插入、领取与丢弃事实,而不标识之后的输出或 `turn/end`。 +- `agent.steer(message)`:将会唤醒的 `next-step` steering(中途引导)输入排队。agent 空闲时会同步启动一个轮次;驱动器运行期间收到的后续 steering 会在下一个步骤边界被消费。 +- `agent.inject(message)`:将不会唤醒的 `next-step` 上下文排队。运行中的驱动器会在最近的后续 pre-step 边界领取它;idle 驱动器则会让它保持待处理,直至 `followup()` 或 `steer()` 唤醒驱动器。若某次请求的 pre-step 已经领取完批次,它可能赶不上该请求。 +- `agent.cancel(cause, options?)`:取消活跃驱动器,并在未设置 `options.keepInbox` 时持久取消全部待处理 inbox 工作。空闲取消是空操作。 +- `agent.whenIdle()`:观察整个 agent 达到完全停稳,包括当前驱动器退役前调度的替代工作。它不结算任何特定消息。 +- `agent.session`、`agent.status`、`agent.options`、`agent.id`、`agent.ctx` + +`running` 描述驱动器范围的 drain 区间,而不是轮次仍打开的证明;它可以覆盖轮次关闭、持久性检查点和连续的排队轮次。只有拥有完整区间的调用方才能将其概括为一次运行的结果([决策](../../../.agents/notes/implemented/architecture/2026-07-30-followup-enqueue-and-owned-runs.md))。 + +### 扩展点 + +- Agent 创建:`AgentLoop.create()` 是具体配置路径实现(位于 `dsh-agent-loop`),程序化消费方则通过 `ctx.agents.create()`/`ctx.agents.resume()` 创建或恢复有所有权的 agent。替换循环时,应实现 `Agent` 并通过 `ctx.agents.register()` 注册。 +- 事件监听器:全部 `agent/*` 事件都在此处声明,不需要依赖循环包。 +- subagent 委派不是 `Agent` 方法;提供方通过工厂 API 创建或驱动普通 handle,因此委派传输留在核心 agent 接口之外。 + +## 模型体验 + +### 用户、steering 与注入消息 + +#### 模型看到的内容 + +`send`、`steer` 与 `inject` 会向所属会话提供输入。`agent/pre-step` 和其他已声明事件让插件能够拒绝拟进入的步骤或添加持久请求材料;此接口本身不贡献固定文案。 + +#### Token 影响 + +已接受内容成为保留历史,或成为每次请求都会重复的会话前缀;被阻止内容不贡献请求 token。大小取决于调用方与插件。 + +#### KV Cache 影响 + +已接受历史与 steering 只追加;被阻止的提交不发送请求。会话前缀在循环实例内保持稳定,而新建或恢复的实例可能建立不同前缀。 + +### Agent 作用域的请求组合 + +#### 模型看到的内容 + +通过 `agent.ctx` 进行的注册可以遮蔽提示词段或工具,也可以在未发布 setup 期间安装仅适用于该 agent 的拦截器。 + +#### Token 影响 + +此包自身不增加 token;带作用域贡献只影响该 agent,并在 dispose 时消失。 + +#### KV Cache 影响 + +只要 agent 的作用域注册不变,前缀就保持稳定。改变提示词段、工具定义或请求监听器的 setup 或 reload,可能从第一个受影响的请求 token 起使复用失效。 + +## 已知限制与暂缓事项 + +- **发起方作用域只存在于进程内**:worker、子进程、HTTP、持久队列和重启必须显式传递所需身份。 +- **环境身份可能比存活状态更久**:消费方在生命周期敏感工作前,仍要检查 `agent.status`、取消状态和所属能力约定。 +- **委派以外的 agent 间通道**:共享状态、流式子输出和后台/轮询语义仍在当前同步 `ctx.subagents` seam 之外。 +- **`agent/session-start` 不能为启动设置门禁**:它仍是同步且不可 veto 的通知;必须在发布前完成的异步组合属于工厂的 `setup(agentCtx)` 事务。 +- **`cancel()` 默认清空 inbox**:它会中止正在处理的轮次以及排队和 steering 工作;`cancel(cause, { keepInbox: true })` 只中止轮次并保留待处理项。仍不存在只中止步骤、同时让正在处理的轮次继续运行的操作([停止 API Agent Note](../../../.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-api.md))。 +- **每条附加 `UserMessage` 恰好携带一个 `MessageSource`**:多个插件合并到一次工具调用上的贡献会归入同一来源,因此该消息无法列出多个生产者。 +- **`SessionStartSource` 预留 `'clear'`/`'compact'`,但还没有发出方**:在驱动子系统落地前,只会出现 `'startup'`/`'resume'`(`TODO(compaction)`)。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/index.js new file mode 100644 index 0000000..29202f1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/index.js @@ -0,0 +1,794 @@ +import { Service, getTraceable, symbols } from "@deepseek-ai/cordis"; +import { AsyncLocalStorage } from "node:async_hooks"; +import { isPromise } from "node:util/types"; +import { scopeTarget } from "@deepseek-ai/dsh-scope"; +//#region lib/types/inbox.js +/** +* Incremental projection of durable agent inbox events. +* +* @module @deepseek-ai/dsh-agent/inbox +*/ +/** A replay-once projection that incrementally consumes later inbox splices. */ +var Inbox = class { + session; + notifications; + state = { + "next-turn": [], + "next-step": [] + }; + constructor(session, notifications) { + this.session = session; + this.notifications = notifications; + for (const event of session.events.slice(session.header.seedLength ?? 0)) { + if (event.type !== "agent/inbox/spliced") continue; + try { + this.apply(event.data); + } catch (error) { + throw new Error(`invalid persisted inbox splice at session seq ${event.seq}`, { cause: error }); + } + } + } + /** Prompts awaiting individual turns. */ + get nextTurn() { + return this.state["next-turn"]; + } + /** Input awaiting the next step boundary. */ + get nextStep() { + return this.state["next-step"]; + } + /** Whether either pending-message list contains work. */ + get hasPending() { + return this.nextTurn.length > 0 || this.nextStep.length > 0; + } + /** Durably cancel all pending input, clearing next-step before next-turn. */ + clear() { + this.splice("next-step", 0, this.nextStep.length, []); + this.splice("next-turn", 0, this.nextTurn.length, []); + } + /** + * Remove and return the complete batch proposed for one step, publishing + * each claimed message. The durable splices are pure deletions. + * @param target - whether this boundary also consumes one queued turn. + * @param turn - turn that will own the claimed batch. + * @returns next-step input followed by the queued turn, when requested. + * @internal - The agent loop's step-boundary operation, not a plugin extension point. + */ + claim(target, turn) { + const claimed = this.mutate("next-step", 0, this.nextStep.length, [], false); + if (target === "next-turn") claimed.push(...this.mutate("next-turn", 0, 1, [], false)); + for (const message of claimed) this.notifications.claimed(message, turn); + return claimed; + } + /** + * Append one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to append. + * @throws if the message identity is already pending. + */ + append(target, message) { + this.splice(target, this.state[target].length, 0, [message]); + } + /** + * Prepend one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to prepend. + * @throws if the message identity is already pending. + */ + prepend(target, message) { + this.splice(target, 0, 0, [message]); + } + /** + * Replace one pending message in place, possibly changing its identity. A + * successful replacement publishes the old message as discarded and the new + * message as inserted. + * @param messageId - identity of the pending message to replace. + * @param newMessage - replacement message. + * @returns whether the message was still pending. + * @throws if the replacement duplicates another pending message identity. + */ + replace(messageId, newMessage) { + const location = this.locate(messageId); + if (location === void 0) return false; + this.splice(location.target, location.index, 1, [newMessage]); + return true; + } + /** + * Remove one pending message and durably record its cancellation. + * @param messageId - identity of the pending message to remove. + * @returns whether the message was still pending. + */ + remove(messageId) { + const location = this.locate(messageId); + if (location === void 0) return false; + this.splice(location.target, location.index, 1, []); + return true; + } + /** + * Apply standard splice semantics and durably record the normalized result. + * The durable event commits before the live projection mutates, so synchronous + * `session/event` observers see the pre-splice lists and can reconstruct the + * removed messages from the normalized coordinates. + * @param target - pending list to mutate. + * @param start - splice position. + * @param deleteCount - maximum number of messages to remove. + * @param inserted - messages to insert at the resolved position. + * @returns messages removed by the splice. + */ + splice(target, start, deleteCount, inserted) { + return this.mutate(target, start, deleteCount, inserted, true); + } + /** Locate one pending identity across both owned lists. */ + locate(messageId) { + for (const target of ["next-turn", "next-step"]) { + const index = this.state[target].findIndex((message) => message.id === messageId); + if (index >= 0) return { + target, + index + }; + } + } + /** Commit one normalized mutation and publish its live notifications. */ + mutate(target, start, deleteCount, inserted, discardRemoved) { + const inbox = this.state[target]; + const truncatedStart = Math.trunc(start); + const offset = Number.isNaN(truncatedStart) ? 0 : truncatedStart; + const actualStart = offset < 0 ? Math.max(inbox.length + offset, 0) : Math.min(offset, inbox.length); + const truncatedDeleteCount = Math.trunc(deleteCount); + const actualDeleteCount = Math.min(Math.max(Number.isNaN(truncatedDeleteCount) ? 0 : truncatedDeleteCount, 0), inbox.length - actualStart); + if (actualDeleteCount === 0 && inserted.length === 0) return []; + const outcome = discardRemoved && actualDeleteCount > 0 ? "canceled" : void 0; + const splice = { + target, + start: actualStart, + ...actualDeleteCount === 0 ? {} : { removedCount: actualDeleteCount }, + inserted, + ...outcome === void 0 ? {} : { outcome } + }; + this.validate(splice); + const event = this.session.append("agent/inbox/spliced", splice); + const removed = inbox.splice(actualStart, actualDeleteCount, ...event.data.inserted); + if (discardRemoved) for (const message of removed) this.notifications.discarded(message); + for (const message of event.data.inserted) this.notifications.inserted(message); + return removed; + } + /** Apply one normalized durable splice to the projection. */ + apply(splice) { + this.validate(splice); + return this.state[splice.target].splice(splice.start, splice.removedCount ?? 0, ...splice.inserted); + } + /** Validate one normalized splice against the current projection. */ + validate(splice) { + const inbox = this.state[splice.target]; + const removedCount = splice.removedCount ?? 0; + if (!Number.isSafeInteger(splice.start) || splice.start < 0 || splice.start > inbox.length || !Number.isSafeInteger(removedCount) || removedCount < 0 || splice.start + removedCount > inbox.length) throw new Error("invalid inbox splice"); + const candidate = inbox.toSpliced(splice.start, removedCount, ...splice.inserted); + const ids = /* @__PURE__ */ new Set(); + for (const message of splice.target === "next-turn" ? [...candidate, ...this.nextStep] : [...this.nextTurn, ...candidate]) { + if (ids.has(message.id)) throw new Error(`message "${message.id}" is already pending`); + ids.add(message.id); + } + } +}; +//#endregion +//#region lib/types/consumed-work.js +/** +* How one agent log accounts for the work it consumed. +* +* The turn and step vocabulary alone cannot answer this. A turn that stops +* before its first step leaves a `turn/end` shaped exactly like the balanced +* no-op turns a rejection or an empty claim produces, so reading turns in +* isolation either credits cut-short work as finished or convicts every no-op. +* The missing fact is the inbox's own record: {@link Inbox} logs each mutation +* with `removedCount` and marks a cancellation `outcome: 'canceled'`, which +* separates a turn claiming its input from work being dropped unrun. +* +* @module @deepseek-ai/dsh-agent/consumed-work +*/ +/** +* Whether a turn that consumed input but never reached a step ends in a way +* that accounts for that input. Only a `completed` end does not: it had +* nothing left to run once its claim was rewritten away. A `blocked` end is +* that input's ending too — the pre-step rejection that produced it discarded +* the claimed messages, so the work it took will never run. +* @param reason - the turn's recorded ending. +* @returns whether the ending accounts for the input the turn took. +*/ +function accountsForClaim(reason) { + switch (reason.kind) { + case "completed": return false; + case "blocked": + case "aborted": + case "interrupted": + case "error": return true; + /* v8 ignore next 4 -- unreachable: the one unnamed built-in, `max-tokens`, requires a step, + * so its turn short-circuits as stepped before this call, and `TurnEndReasonMap` is + * merge-extensible, so a backend-added variant cannot be listed; an unnameable ending over + * consumed input must not read as success. */ + default: return true; + } +} +/** +* Fold one agent log, or an owned suffix of one, into its account of consumed +* work. Single pass, and every input is the log itself: no caller has to sample +* live state before cancelling, so a cancellation issued by anyone — the owner's +* teardown, an ancestor's interrupt, an unloading plugin — reads the same. +* @param events - the log, or an owned suffix, to fold. +* @returns the accounting turn when one closed, and whether work was dropped unrun after it. +*/ +function foldConsumedWork(events) { + const stepped = /* @__PURE__ */ new Set(); + const claimed = /* @__PURE__ */ new Set(); + let open; + let end; + let droppedUnrun = false; + for (const event of events) switch (event.type) { + case "turn/start": + open = event.data.turn; + break; + case "step/start": + stepped.add(event.data.turn); + break; + case "agent/inbox/spliced": { + const { removedCount, outcome, inserted } = event.data; + if (removedCount === void 0) break; + if (outcome === "canceled") droppedUnrun ||= inserted.length === 0; + else if (open !== void 0) claimed.add(open); + break; + } + case "turn/end": { + const { turn, reason } = event.data; + open = void 0; + if (stepped.delete(turn) || claimed.delete(turn) && accountsForClaim(reason)) { + end = event; + droppedUnrun = false; + } + break; + } + default: break; + } + return { + ...end === void 0 ? {} : { end }, + droppedUnrun + }; +} +//#endregion +//#region lib/types/model-selection.js +/** +* Agent-scoped model selection shared by runtime entry points. +* @module @deepseek-ai/dsh-agent/model-selection +*/ +/** +* Couple one mutable selection to Agent-scoped prompt assembly and request routing. +* Prompt assembly snapshots the selected model before delegating, then applies +* its provider/model pair and effort to request config so a +* concurrent switch takes effect on a later step instead of splitting the two +* surfaces. An absent selected effort clears any inherited effort, restoring +* the selected model's provider/default behavior. +* +* @param agentCtx - The selected Agent's scoped context. +* @param selection - Mutable selection owned by the calling entry point. +* @returns Disposer for both scoped waterfall listeners. +*/ +function installModelSelection(agentCtx, selection) { + const disposeAssembly = agentCtx.on("system-prompt/assemble", async (_assembly, _context, next) => { + const selected = selection.current; + const assembled = await next(); + selection.assembled = selected; + if (selected === void 0) return assembled; + return { + ...assembled, + variables: { + ...assembled.variables, + provider: selected.provider, + model: selected.model + } + }; + }); + const disposeRequest = agentCtx.on("agent/request", async (_payload, next) => { + const resolved = await next(); + const selected = selection.assembled; + if (selected === void 0) return resolved; + const { reasoningEffort: _inheritedEffort, ...withoutInheritedEffort } = resolved; + return { + ...withoutInheritedEffort, + provider: selected.provider, + model: selected.model, + ...selected.reasoningEffort === void 0 ? {} : { reasoningEffort: selected.reasoningEffort } + }; + }); + return () => { + disposeAssembly(); + disposeRequest(); + }; +} +//#endregion +//#region lib/types/dispatch.js +/** +* Agent-scoped dispatch and prompt assembly helpers. The fused dispatcher +* {@link agentEvents} couples the agent subject to its scope carrier, so the +* scope key and the payload's `agent` cannot diverge; repeat dispatchers (the +* loop driver) build it once in the agent's constructor and reuse it. +* @module @deepseek-ai/dsh-agent/dispatch +*/ +/** +* Build the fused scope carrier for one agent subject. +* +* The carrier is a stateless routing object. {@link agentEvents} accepts an +* existing carrier, so callers that dispatch repeatedly for the same agent +* (the loop driver) build it once in the agent's constructor and reuse it, +* keeping hot-path dispatches allocation-free. +* @param agent - the subject agent and scope key. +* @returns the carrier passed as the event dispatcher `this` value. +*/ +function agentCarrier(agent) { + return scopeTarget(agent, agent); +} +/** +* Build a dispatcher that couples the agent subject to its scope carrier. +* @param ctx - the context to dispatch through (any context of the app). +* @param agent - the subject agent; also the scope-carrier key. +* @param carrier - the scope carrier to dispatch through; defaults to +* {@link agentCarrier} for the agent. Pass a constructor-built carrier to +* avoid rebuilding it for every dispatch. +* @returns the fused dispatcher. +*/ +function agentEvents(ctx, agent, carrier = agentCarrier(agent)) { + const fused = (payload) => ({ + ...payload, + agent + }); + return { + emit(name, payload) { + const args = [ + carrier, + name, + fused(payload) + ]; + const callbacks = ctx.events.dispatch("emit", args); + for (const callback of callbacks) try { + const returned = callback(...args); + Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`agent event "${name}" listener rejected: ${String(error)}`); + }); + } catch (error) { + ctx.logger.warn(`agent event "${name}" listener threw: ${String(error)}`); + } + }, + async serial(name, payload) { + const serial = ctx.serial; + return await serial(carrier, name, fused(payload)); + }, + waterfall(name, payload, ...rest) { + const waterfall = ctx.waterfall; + return waterfall(carrier, name, fused(payload), ...rest); + } + }; +} +/** +* Emit one contained agent notification without allocating a retained dispatcher. +* @param ctx - the context to dispatch through. +* @param agent - the subject agent and scope key. +* @param name - the agent-subject event to emit. +* @param payload - the event's payload fields; `agent` is injected. +*/ +function emitAgentEvent(ctx, agent, name, payload) { + agentEvents(ctx, agent).emit(name, payload); +} +/** +* Build the prompt assembly context with agent and scope set together, so +* agent-scoped prompt and tool contributions cannot be silently omitted. +* @param agent - the agent the assembly is for. +* @param signal - the current turn's explicit control signal, when assembly belongs to a turn. +* @returns the context to pass to `assemble()`. +*/ +function assembleContextFor(agent, signal) { + return { + agent, + scope: agent, + ...signal === void 0 ? {} : { signal } + }; +} +//#endregion +//#region lib/types/index.js +/** +* Agent service: live registry, factory delegation, and process-local +* initiator scope. Concrete creation and driving belong to the loop. +* +* @module @deepseek-ai/dsh-agent +*/ +/** Thrown when create/resume is called before an agent factory is registered. */ +const NO_FACTORY_MESSAGE = "no agent factory registered (load an agent-loop plugin)"; +const NO_INITIATOR_MESSAGE = "no initiating agent is active"; +const DISPOSED_INITIATOR_MESSAGE = "agent initiator scope is disposed"; +/** +* Agent service (`ctx.agents`): tracks live agents and carries the initiating +* Agent through one process-local asynchronous driver chain. Agent *creation* +* is provided by whichever plugin implements the {@link AgentFactory} +* (`@deepseek-ai/dsh-agent-loop`), registered via {@link setFactory}. +* +* Initiator methods provide same-process causal attribution only. Ambient +* presence is neither liveness proof nor authorization; subjects and owners +* remain explicit, as does identity at worker, process, persistence, and wire +* boundaries. Returned Promise boundaries drain during teardown, except a +* nested lineage that starts an owning-fiber unload is excluded from its own drain. +*/ +var AgentRegistry = class extends Service { + store = /* @__PURE__ */ new Map(); + factory; + initiators = new AsyncLocalStorage(); + initiatorRuns = new AsyncLocalStorage(); + initiatorState = "active"; + activeInitiatorRuns = 0; + initiatorDrain; + initiatorDisposal; + constructor(ctx) { + super(ctx, "agents"); + ctx.inject(["typert"], (typeCtx) => { + typeCtx.typert.lookups.register("agent", { + parameter: "agent", + wire: "agentId", + hostTypeSymbol: "@deepseek-ai/dsh-agent#Agent", + wireTypeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + resolve: (sessionId) => this.get(sessionId) + }); + typeCtx.typert.contexts.registerHost("agent", { + wire: "agentId", + wireTypeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + resolve: (sessionId) => this.get(sessionId)?.ctx + }); + }); + ctx.accessor("agent", { get: () => void 0 }); + ctx.on("internal/status", (fiber) => { + if (fiber.state === 5 && this.hasLifecycleAncestor(fiber)) this.closeInitiators(); + }); + ctx.effect(function* () { + yield () => this.disposeInitiators(); + yield () => { + this.closeInitiators(); + }; + }.bind(this), "agents.initiatorLifecycle()"); + } + /** + * Read the Agent that initiated the inherited asynchronous driver chain. + * Use this optional form for logging, tracing, metrics, or host attribution + * that also supports agentless calls. When a parent creates a child, setup + * reports the causal parent while `agentCtx.agent` identifies the child. + * @returns the inherited Agent, or `undefined` outside an initiator boundary + * and inside an explicit clearing boundary. + * @throws when this service instance has been disposed. + */ + currentInitiator() { + this.assertInitiatorsReadable(); + return this.initiators.getStore(); + } + /** + * Read the initiating Agent and fail when no initiator boundary is active. + * Use this for private helpers contractually below a driver, or for a + * deployment-owned outbound request whose contract forbids agentless calls. + * Generic or direct-call paths use optional lookup or explicit request fields. + * @returns the inherited Agent. + * @throws when no initiator is active or this service instance has been disposed. + */ + requireInitiator() { + const agent = this.currentInitiator(); + if (agent === void 0) throw new Error(NO_INITIATOR_MESSAGE); + return agent; + } + /** + * Run an operation with one exact Agent as its process-local initiator. The + * exact synchronous value or Promise returned by the operation is preserved. + * Custom drivers and test harnesses wrap their complete returned foreground + * lifetime. + * A queue or wire receiver may establish this boundary only after validating + * explicit identity and resolving the exact live Agent; this method does neither. + * Detached work remains owned by the subsystem that starts it. + * @param agent - initiating Agent to inherit; presence is neither liveness proof nor authorization. + * @param operation - synchronous or asynchronous operation to invoke. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withInitiator(agent, operation) { + return this.runWithInitiator(agent, operation); + } + /** + * Run an operation inside a boundary that hides any inherited initiating + * Agent. The exact synchronous value or Promise is preserved. + * Use this while creating lazy shared timers, queue pumps, pool maintenance, + * watchers, or exporters so they do not inherit the first Agent that happens + * to initialize them. It clears only initiator attribution, not explicit + * fields, and does not own or drain detached resources. + * @param operation - synchronous or asynchronous operation to invoke without an initiator. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withoutInitiator(operation) { + return this.runWithInitiator(void 0, operation); + } + /** + * Register the agent-creation factory (the loop calls this on construction, + * effect-scoped). A traced Cordis service is canonicalized to its concrete + * target; each create/resume call is then traced through that caller's + * context so ownership follows the caller without stacking proxy layers. + * Throws if a factory is already registered. Returns the disposer; on + * dispose the factory slot is cleared. + * @param factory - the loop-owned factory {@link create}/{@link resume} delegate to. + * @returns the disposer that clears the factory slot. The exact + * Cordis effect disposer (single-shot): composite (generator) effects may + * yield it directly — exact identity nests the teardown in order. + */ + setFactory(factory) { + return this.ctx.effect(() => { + if (this.factory !== void 0) throw new Error("an agent factory is already registered"); + const target = factory[symbols.original] ?? factory; + this.factory = { target }; + return () => { + this.factory = void 0; + }; + }, "agents.setFactory()"); + } + /** Return the active creation factory. */ + requireFactory() { + if (this.factory === void 0) throw new Error(NO_FACTORY_MESSAGE); + return this.factory; + } + /** + * Create and publish a new agent through the registered factory. + * Distinct from {@link register} (which records an already-constructed + * agent): this constructs the agent and its session. Rejects if no factory is + * registered or creation/setup fails. The resolved {@link AgentHandle} lets + * the owner tear down exactly this agent. + * @param options - shared identity, session seed/metadata, and agent options. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + async create(options) { + const ownerCtx = this.ctx; + const { target } = this.requireFactory(); + const receiver = getTraceable(ownerCtx, target); + return Reflect.apply(target.createAgent, receiver, [ownerCtx, options]); + } + /** + * Load a persisted session and resume an agent on it through the registered + * factory. Rejects if no factory is registered; the factory rejects if + * session persistence is not configured or persistence/setup fails. + * @param options - persisted identity, configuration, and optional setup. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + async resume(options) { + const ownerCtx = this.ctx; + const { target } = this.requireFactory(); + const receiver = getTraceable(ownerCtx, target); + return Reflect.apply(target.resume, receiver, [ownerCtx, options]); + } + /** + * Register a live agent. Throws if an agent with the same id is already + * registered. Emits `agent/created` on registration and `agent/disposed` + * when the calling fiber is disposed — both with the agent's scope carrier + * (`scopeTarget(agent, agent)`): the subject is the agent in hand, so the + * emits are scope-filtered regardless of which context invoked `register` + * (calling through `agent.ctx` scopes EFFECTS; dispatch scoping always + * requires passing the carrier). Returns the disposer. + * @param agent - the already-constructed agent to record in the store. + * @returns the EXACT Cordis effect disposer (single-shot; a repeat call + * returns undefined without awaiting an in-flight teardown). Exact + * identity is load-bearing: a composite (generator) effect that owns a + * teardown ORDER — the agent factory's lifecycle chain — must yield THIS + * function so Cordis nests the unregistration at that yield position; + * yielding a wrapper would leave it disposing as a concurrent sibling on + * owner unload, unregistering the agent (and emitting `agent/disposed`) + * while its final turn is still draining. + */ + register(agent) { + return this.ctx.effect(function* () { + yield this.enter(agent, this.ctx.agent); + this.announce(agent); + }.bind(this), "agents.register()"); + } + /** + * Insert an already-constructed agent without announcing it. This is the + * advanced ordered-lifecycle primitive used by the async agent factory: it + * first completes setup while the agent is unpublished, then assigns the + * returned detach closure into its pre-installed composite teardown before + * calling {@link announce}. Ordinary callers use {@link register}. + * @param agent - the prepared, unpublished agent. + * @param owner - live agent whose scoped context created this agent, or + * undefined for a top-level runtime root. This is runtime ownership, not + * the resumed session's durable parent lineage. + * @returns an idempotent closure that removes this exact entry and emits + * `agent/disposed` with listener failures contained. When called from a + * synchronous `agent/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + */ + enter(agent, owner) { + const id = agent.id; + if (id !== agent.session.id) throw new Error(`agent id "${id}" does not match session id "${agent.session.id}"`); + const carrier = scopeTarget(agent, agent); + if (this.store.has(id)) throw new Error(`agent "${id}" is already registered`); + const entry = { + id, + agent, + owner, + carrier, + announced: false, + announcing: false, + detachRequested: false + }; + this.store.set(id, entry); + let entered = true; + const detach = () => { + if (!entered) return; + entered = false; + if (entry.announcing) { + entry.detachRequested = true; + return; + } + this.detachEntered(entry); + }; + return detach; + } + /** Remove one exact entered agent and emit its paired disposal when announced. */ + detachEntered(entry) { + entry.detachRequested = false; + /* v8 ignore next -- enter() rejects replacement while this single-shot detach capability is live. */ + if (this.store.get(entry.id) !== entry) return; + this.store.delete(entry.id); + if (!entry.announced) return; + this.emitDisposed(entry); + } + /** Emit the paired disposal edge through the entry's stable carrier. */ + emitDisposed(entry) { + const args = [ + entry.carrier, + "agent/disposed", + { agent: entry.agent } + ]; + for (const callback of this.ctx.events.dispatch("emit", args)) try { + const returned = callback(...args); + Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`agent "${entry.id}": agent/disposed listener rejected: ${String(error)}`); + }); + } catch (error) { + this.ctx.logger.warn(`agent "${entry.id}": agent/disposed listener threw: ${String(error)}`); + } + } + /** + * Announce an agent previously inserted with {@link enter}. + * @param agent - the live inserted agent to announce. + * @throws if `agent` is not the exact live registry entry for its id, or its + * creation announcement already began (including a reentrant call from a + * creation listener). + */ + announce(agent) { + const entry = this.store.get(agent.id); + if (entry === void 0 || entry.agent !== agent) throw new Error(`agent "${agent.id}" is not live in this registry`); + if (entry.announced || entry.announcing) throw new Error(`agent "${entry.id}" was already announced`); + entry.announcing = true; + entry.announced = true; + const args = [ + entry.carrier, + "agent/created", + { agent: entry.agent } + ]; + try { + for (const callback of this.ctx.events.dispatch("emit", args)) { + const returned = callback(...args); + Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`agent "${entry.id}": agent/created listener rejected: ${String(error)}`); + }); + } + } finally { + entry.announcing = false; + if (entry.detachRequested) this.detachEntered(entry); + } + } + /** + * Look up a live agent. + * @param id - the shared agent/session id to look up. + * @returns the agent, or undefined when no live agent has that id. + */ + get(id) { + return this.store.get(id)?.agent; + } + /** + * Test whether a live agent was created through one exact parent agent's + * scoped context. Runtime ownership is independent of durable session + * lineage and remains unambiguous when unrelated providers reuse an id. + * @param id - the candidate child agent's shared agent/session id. + * @param owner - the expected runtime creator agent. + * @returns true only while the exact child entry is live under that owner. + */ + isOwnedBy(id, owner) { + return this.store.get(id)?.owner === owner; + } + /** + * All live agents, in registration order. + * @returns a fresh array; mutating it does not affect the registry. + */ + list() { + return [...this.store.values()].map((entry) => entry.agent); + } + /** + * All live top-level agents in registration order. A top-level agent was + * created without an owning agent context; durable session lineage does not + * affect this runtime relation, so a resumed fork may still be a root. + * @returns a fresh array; mutating it does not affect the registry. + */ + roots() { + return [...this.store.values()].filter((entry) => entry.owner === void 0).map((entry) => entry.agent); + } + /** Reject new initiator boundaries while inherited continuations drain. */ + closeInitiators() { + if (this.initiatorState === "active") this.initiatorState = "closing"; + } + /** Wait for returned-Promise boundaries, then invalidate retained references. */ + disposeInitiators() { + return this.initiatorDisposal ??= (async () => { + this.closeInitiators(); + this.releaseReentrantInitiatorRuns(); + if (this.activeInitiatorRuns !== 0) { + this.initiatorDrain ??= Promise.withResolvers(); + await this.initiatorDrain.promise; + } + this.initiatorState = "disposed"; + this.initiators.disable(); + this.initiatorRuns.disable(); + })(); + } + /** Establish one tracked initiator or clearing boundary. */ + runWithInitiator(agent, operation) { + if (this.initiatorState !== "active") throw new Error(DISPOSED_INITIATOR_MESSAGE); + const run = { + active: true, + parent: this.initiatorRuns.getStore() + }; + this.activeInitiatorRuns += 1; + let result; + try { + result = this.initiatorRuns.run(run, () => this.initiators.run(agent, operation)); + } catch (error) { + this.releaseInitiatorRun(run); + throw error; + } + if (isPromise(result)) try { + Promise.prototype.then.call(result, () => { + this.releaseInitiatorRun(run); + }, () => { + this.releaseInitiatorRun(run); + }); + } catch { + this.releaseInitiatorRun(run); + } + else this.releaseInitiatorRun(run); + return result; + } + /** Whether one unloading fiber owns this service's lifecycle. */ + hasLifecycleAncestor(candidate) { + let fiber = this.ctx.fiber; + while (true) { + if (fiber === candidate) return true; + const parent = fiber.parent.fiber; + if (parent === fiber) return false; + fiber = parent; + } + } + assertInitiatorsReadable() { + if (this.initiatorState === "disposed") throw new Error(DISPOSED_INITIATOR_MESSAGE); + } + /** Exclude the boundary chain that initiated this teardown from its own drain. */ + releaseReentrantInitiatorRuns() { + let run = this.initiatorRuns.getStore(); + while (run !== void 0) { + this.releaseInitiatorRun(run); + run = run.parent; + } + } + releaseInitiatorRun(run) { + if (!run.active) return; + run.active = false; + this.activeInitiatorRuns -= 1; + if (this.activeInitiatorRuns !== 0) return; + this.initiatorDrain?.resolve(); + this.initiatorDrain = void 0; + } +}; +//#endregion +export { AgentRegistry, AgentRegistry as default, Inbox, agentCarrier, agentEvents, assembleContextFor, emitAgentEvent, foldConsumedWork, installModelSelection }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/invariant.js new file mode 100644 index 0000000..4659487 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** Package-owned agent lifecycle invariants. @module @deepseek-ai/dsh-agent/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-agent"; +/** Cordis companion plugin name. */ +const name = "agent-invariant"; +/** Services required before the companion can register. */ +const inject = ["invariants"]; +/** Install the agent contribution into its child registration fiber. */ +const install = (ctx, fail) => { + const lastStatus = /* @__PURE__ */ new WeakMap(); + ctx.on("agent/status", ({ agent, status }) => { + if (lastStatus.get(agent) === status) fail(`agent/status repeated ${status} (no-op transition)`); + lastStatus.set(agent, status); + }, { global: true }); +}; +/** +* Register the agent invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.d.ts new file mode 100644 index 0000000..5c6f623 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.d.ts @@ -0,0 +1,39 @@ +/** + * How one agent log accounts for the work it consumed. + * + * The turn and step vocabulary alone cannot answer this. A turn that stops + * before its first step leaves a `turn/end` shaped exactly like the balanced + * no-op turns a rejection or an empty claim produces, so reading turns in + * isolation either credits cut-short work as finished or convicts every no-op. + * The missing fact is the inbox's own record: {@link Inbox} logs each mutation + * with `removedCount` and marks a cancellation `outcome: 'canceled'`, which + * separates a turn claiming its input from work being dropped unrun. + * + * @module @deepseek-ai/dsh-agent/consumed-work + */ +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +/** How one agent log accounts for the work it consumed. */ +export interface ConsumedWork { + /** + * The latest closed turn that accounts for consumed work: one that entered a + * model step, or one that claimed inbox input and then failed, was stopped, + * or was rejected. Absent when no turn closed over any work. + */ + readonly end?: SessionEvent<'turn/end'>; + /** + * Whether accepted work was cancelled out of the inbox, unrun, after that + * turn. This is the only account of input a cancellation took before any turn + * could open over it — no `turn/end` describes it. + */ + readonly droppedUnrun: boolean; +} +/** + * Fold one agent log, or an owned suffix of one, into its account of consumed + * work. Single pass, and every input is the log itself: no caller has to sample + * live state before cancelling, so a cancellation issued by anyone — the owner's + * teardown, an ancestor's interrupt, an unloading plugin — reads the same. + * @param events - the log, or an owned suffix, to fold. + * @returns the accounting turn when one closed, and whether work was dropped unrun after it. + */ +export declare function foldConsumedWork(events: readonly SessionEvent[]): ConsumedWork; +//# sourceMappingURL=consumed-work.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.js new file mode 100644 index 0000000..a6c2bb0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/consumed-work.js @@ -0,0 +1,92 @@ +/** + * How one agent log accounts for the work it consumed. + * + * The turn and step vocabulary alone cannot answer this. A turn that stops + * before its first step leaves a `turn/end` shaped exactly like the balanced + * no-op turns a rejection or an empty claim produces, so reading turns in + * isolation either credits cut-short work as finished or convicts every no-op. + * The missing fact is the inbox's own record: {@link Inbox} logs each mutation + * with `removedCount` and marks a cancellation `outcome: 'canceled'`, which + * separates a turn claiming its input from work being dropped unrun. + * + * @module @deepseek-ai/dsh-agent/consumed-work + */ +/** + * Whether a turn that consumed input but never reached a step ends in a way + * that accounts for that input. Only a `completed` end does not: it had + * nothing left to run once its claim was rewritten away. A `blocked` end is + * that input's ending too — the pre-step rejection that produced it discarded + * the claimed messages, so the work it took will never run. + * @param reason - the turn's recorded ending. + * @returns whether the ending accounts for the input the turn took. + */ +function accountsForClaim(reason) { + switch (reason.kind) { + case 'completed': + return false; + case 'blocked': + case 'aborted': + case 'interrupted': + case 'error': + return true; + /* v8 ignore next 4 -- unreachable: the one unnamed built-in, `max-tokens`, requires a step, + * so its turn short-circuits as stepped before this call, and `TurnEndReasonMap` is + * merge-extensible, so a backend-added variant cannot be listed; an unnameable ending over + * consumed input must not read as success. */ + default: + return true; + } +} +/** + * Fold one agent log, or an owned suffix of one, into its account of consumed + * work. Single pass, and every input is the log itself: no caller has to sample + * live state before cancelling, so a cancellation issued by anyone — the owner's + * teardown, an ancestor's interrupt, an unloading plugin — reads the same. + * @param events - the log, or an owned suffix, to fold. + * @returns the accounting turn when one closed, and whether work was dropped unrun after it. + */ +export function foldConsumedWork(events) { + const stepped = new Set(); + const claimed = new Set(); + let open; + let end; + let droppedUnrun = false; + for (const event of events) { + switch (event.type) { + case 'turn/start': + open = event.data.turn; + break; + case 'step/start': + stepped.add(event.data.turn); + break; + case 'agent/inbox/spliced': { + const { removedCount, outcome, inserted } = event.data; + if (removedCount === undefined) + break; + // A replacement keeps the work pending under a new identity, so only a + // cancellation that leaves nothing behind drops it. + if (outcome === 'canceled') + droppedUnrun ||= inserted.length === 0; + // Claims are the loop's own step-boundary reads, always inside a turn. + else if (open !== undefined) + claimed.add(open); + break; + } + case 'turn/end': { + const { turn, reason } = event.data; + open = undefined; + if (stepped.delete(turn) || (claimed.delete(turn) && accountsForClaim(reason))) { + end = event; + // Anything dropped before this turn closed is what its own ending + // reports; only a later drop is still unaccounted for. + droppedUnrun = false; + } + break; + } + default: + break; + } + } + return { ...end === undefined ? {} : { end }, droppedUnrun }; +} +//# sourceMappingURL=consumed-work.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.d.ts new file mode 100644 index 0000000..2e3b36e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.d.ts @@ -0,0 +1,111 @@ +/** + * Agent-scoped dispatch and prompt assembly helpers. The fused dispatcher + * {@link agentEvents} couples the agent subject to its scope carrier, so the + * scope key and the payload's `agent` cannot diverge; repeat dispatchers (the + * loop driver) build it once in the agent's constructor and reuse it. + * @module @deepseek-ai/dsh-agent/dispatch + */ +import type { Context, Events } from '@deepseek-ai/cordis'; +import type { Scoped } from '@deepseek-ai/dsh-scope'; +import type { AssembleContext } from '@deepseek-ai/dsh-system-prompt'; +import type { Agent } from './runtime-types.ts'; +/** Extract the parameter tuple from an event handler type (its `this` is not part of the tuple). */ +type Params = F extends (...args: infer P) => unknown ? P : never; +/** Extract the return type from an event handler type. */ +type Return = F extends (...args: never[]) => infer R ? R : never; +/** + * The event names whose subject is an agent: the handler's first parameter is + * a payload object carrying the `agent` subject AND the handler declares a + * `Scoped` `this` (the scope-carrier contract). The `this` check keeps + * accidental payload-happens-to-carry-an-Agent events (or zero-arg events, + * whose parameter tuple would satisfy a bare rest-tuple check via callability) + * out of the fused-dispatch surface. + */ +export type AgentSubjectEvent = { + [K in keyof Events]: Events[K] extends (this: Scoped, ...args: infer P) => unknown ? P extends [infer Payload, ...unknown[]] ? Payload extends { + agent: Agent; + } ? K : never : never : never; +}[keyof Events]; +/** The full payload object of one agent-subject event. */ +type PayloadOf = Params extends [infer Payload, ...unknown[]] ? Payload : never; +/** The event arguments AFTER the payload: the waterfall `next` when present. */ +type Tail = Params extends [unknown, ...infer R] ? R : never; +/** + * The payload as emit-side callers pass it: the full payload minus the agent + * field, which the fused dispatcher injects so subject and scope key cannot + * diverge. + */ +type PayloadRest = Omit & object, 'agent'>; +/** + * The fused dispatcher {@link agentEvents} returns: each method dispatches the + * named agent-subject event with the agent's scope carrier as `thisArg` and + * the agent itself injected into the payload. + */ +export interface AgentEventDispatch { + /** + * Fire-and-forget notification in the agent's scope. Every listener is + * invoked; synchronous throws and returned-promise rejections are logged and + * contained per listener, so a notification cannot veto lifecycle progress + * or starve a later observer. + * @param name - the agent-subject event to emit. + * @param payload - the event's payload fields; `agent` is injected. + */ + emit(name: K, payload: PayloadRest): void; + /** + * Awaited in-order dispatch (Cordis `serial`) in the agent's scope. + * @param name - the agent-subject event to dispatch. + * @param payload - the event's payload fields; `agent` is injected. + * @returns the serial chain's result (the first bail value, if any). + */ + serial(name: K, payload: PayloadRest): Promise>>; + /** + * Around-middleware dispatch (Cordis `waterfall`) in the agent's scope. The + * declared event parameters already end with the `next` callback, so `rest` + * is exactly the event's arguments after the payload — the final element + * being the innermost `next` (the default the listener chain wraps). + * @param name - the agent-subject event to dispatch. + * @param payload - the event's payload fields; `agent` is injected. + * @param rest - the event's arguments after the payload (the `next` callback). + * @returns the waterfall's composed result. + */ + waterfall(name: K, payload: PayloadRest, ...rest: Tail): Return; +} +/** + * Build the fused scope carrier for one agent subject. + * + * The carrier is a stateless routing object. {@link agentEvents} accepts an + * existing carrier, so callers that dispatch repeatedly for the same agent + * (the loop driver) build it once in the agent's constructor and reuse it, + * keeping hot-path dispatches allocation-free. + * @param agent - the subject agent and scope key. + * @returns the carrier passed as the event dispatcher `this` value. + */ +export declare function agentCarrier(agent: Agent): Scoped; +/** + * Build a dispatcher that couples the agent subject to its scope carrier. + * @param ctx - the context to dispatch through (any context of the app). + * @param agent - the subject agent; also the scope-carrier key. + * @param carrier - the scope carrier to dispatch through; defaults to + * {@link agentCarrier} for the agent. Pass a constructor-built carrier to + * avoid rebuilding it for every dispatch. + * @returns the fused dispatcher. + */ +export declare function agentEvents(ctx: Context, agent: Agent, carrier?: Scoped): AgentEventDispatch; +/** + * Emit one contained agent notification without allocating a retained dispatcher. + * @param ctx - the context to dispatch through. + * @param agent - the subject agent and scope key. + * @param name - the agent-subject event to emit. + * @param payload - the event's payload fields; `agent` is injected. + */ +export declare function emitAgentEvent(ctx: Context, agent: Agent, name: K, payload: PayloadRest): void; +/** + * Build the prompt assembly context with agent and scope set together, so + * agent-scoped prompt and tool contributions cannot be silently omitted. + * @param agent - the agent the assembly is for. + * @param signal - the current turn's explicit control signal, when assembly belongs to a turn. + * @returns the context to pass to `assemble()`. + */ +export declare function assembleContextFor(agent: Agent, signal?: AbortSignal): AssembleContext; +export {}; +//# sourceMappingURL=dispatch.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.js new file mode 100644 index 0000000..876f485 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/dispatch.js @@ -0,0 +1,95 @@ +/** + * Agent-scoped dispatch and prompt assembly helpers. The fused dispatcher + * {@link agentEvents} couples the agent subject to its scope carrier, so the + * scope key and the payload's `agent` cannot diverge; repeat dispatchers (the + * loop driver) build it once in the agent's constructor and reuse it. + * @module @deepseek-ai/dsh-agent/dispatch + */ +import { scopeTarget } from '@deepseek-ai/dsh-scope'; +/** + * Build the fused scope carrier for one agent subject. + * + * The carrier is a stateless routing object. {@link agentEvents} accepts an + * existing carrier, so callers that dispatch repeatedly for the same agent + * (the loop driver) build it once in the agent's constructor and reuse it, + * keeping hot-path dispatches allocation-free. + * @param agent - the subject agent and scope key. + * @returns the carrier passed as the event dispatcher `this` value. + */ +export function agentCarrier(agent) { + return scopeTarget(agent, agent); +} +/** + * Build a dispatcher that couples the agent subject to its scope carrier. + * @param ctx - the context to dispatch through (any context of the app). + * @param agent - the subject agent; also the scope-carrier key. + * @param carrier - the scope carrier to dispatch through; defaults to + * {@link agentCarrier} for the agent. Pass a constructor-built carrier to + * avoid rebuilding it for every dispatch. + * @returns the fused dispatcher. + */ +export function agentEvents(ctx, agent, carrier = agentCarrier(agent)) { + // The ordinary dispatch methods forward through Cordis' variadic mixins. The + // fused (carrier, name, payload, ...rest) tuple is provably a valid argument + // list for the matching thisArg overload, but TypeScript cannot relate the + // generic Tail spread back to that overload's conditional parameter + // tuple — hence one contained, shape-preserving cast per method. + const fused = (payload) => + // The dispatcher owns the subject injection; callers pass PayloadRest, so + // the fused record is exactly the declared payload. The spread comes + // first, so a structurally acceptable payload that happens to carry an + // `agent` field can never override the injected subject. + ({ ...payload, agent }); + return { + emit(name, payload) { + // Cordis emit invokes callbacks through Array.map: one synchronous throw + // starves later listeners, and returned promises are discarded. Agent + // notifications are non-vetoing, so resolve the same filtered callback + // set ourselves and contain both failure modes independently. + const args = [carrier, name, fused(payload)]; + const callbacks = ctx.events.dispatch('emit', args); + for (const callback of callbacks) { + try { + const returned = callback(...args); + void Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`agent event "${name}" listener rejected: ${String(error)}`); + }); + } + catch (error) { + ctx.logger.warn(`agent event "${name}" listener threw: ${String(error)}`); + } + } + }, + async serial(name, payload) { + // oxlint-disable-next-line typescript/unbound-method -- the events mixin accessor returns a pre-bound function + const serial = ctx.serial; + return await serial(carrier, name, fused(payload)); + }, + waterfall(name, payload, ...rest) { + // oxlint-disable-next-line typescript/unbound-method -- the events mixin accessor returns a pre-bound function + const waterfall = ctx.waterfall; + return waterfall(carrier, name, fused(payload), ...rest); + }, + }; +} +/** + * Emit one contained agent notification without allocating a retained dispatcher. + * @param ctx - the context to dispatch through. + * @param agent - the subject agent and scope key. + * @param name - the agent-subject event to emit. + * @param payload - the event's payload fields; `agent` is injected. + */ +export function emitAgentEvent(ctx, agent, name, payload) { + agentEvents(ctx, agent).emit(name, payload); +} +/** + * Build the prompt assembly context with agent and scope set together, so + * agent-scoped prompt and tool contributions cannot be silently omitted. + * @param agent - the agent the assembly is for. + * @param signal - the current turn's explicit control signal, when assembly belongs to a turn. + * @returns the context to pass to `assemble()`. + */ +export function assembleContextFor(agent, signal) { + return { agent, scope: agent, ...signal === undefined ? {} : { signal } }; +} +//# sourceMappingURL=dispatch.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.d.ts new file mode 100644 index 0000000..28c4a1e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.d.ts @@ -0,0 +1,92 @@ +/** + * Incremental projection of durable agent inbox events. + * + * @module @deepseek-ai/dsh-agent/inbox + */ +import type { MessageId } from '@deepseek-ai/dsh-llm'; +import type { Session, UserMessage } from '@deepseek-ai/dsh-session'; +import type { InboxTarget } from './types.ts'; +/** Live notifications committed by inbox mutations. */ +export interface InboxNotifications { + /** Publish one inserted message. */ + inserted(message: UserMessage): void; + /** Publish one discarded message. */ + discarded(message: UserMessage): void; + /** Publish one claimed message inside its owning turn. */ + claimed(message: UserMessage, turn: number): void; +} +/** A replay-once projection that incrementally consumes later inbox splices. */ +export declare class Inbox { + private readonly session; + private readonly notifications; + private readonly state; + constructor(session: Session, notifications: InboxNotifications); + /** Prompts awaiting individual turns. */ + get nextTurn(): readonly UserMessage[]; + /** Input awaiting the next step boundary. */ + get nextStep(): readonly UserMessage[]; + /** Whether either pending-message list contains work. */ + get hasPending(): boolean; + /** Durably cancel all pending input, clearing next-step before next-turn. */ + clear(): void; + /** + * Remove and return the complete batch proposed for one step, publishing + * each claimed message. The durable splices are pure deletions. + * @param target - whether this boundary also consumes one queued turn. + * @param turn - turn that will own the claimed batch. + * @returns next-step input followed by the queued turn, when requested. + * @internal - The agent loop's step-boundary operation, not a plugin extension point. + */ + claim(target: InboxTarget, turn: number): UserMessage[]; + /** + * Append one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to append. + * @throws if the message identity is already pending. + */ + append(target: InboxTarget, message: UserMessage): void; + /** + * Prepend one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to prepend. + * @throws if the message identity is already pending. + */ + prepend(target: InboxTarget, message: UserMessage): void; + /** + * Replace one pending message in place, possibly changing its identity. A + * successful replacement publishes the old message as discarded and the new + * message as inserted. + * @param messageId - identity of the pending message to replace. + * @param newMessage - replacement message. + * @returns whether the message was still pending. + * @throws if the replacement duplicates another pending message identity. + */ + replace(messageId: MessageId, newMessage: UserMessage): boolean; + /** + * Remove one pending message and durably record its cancellation. + * @param messageId - identity of the pending message to remove. + * @returns whether the message was still pending. + */ + remove(messageId: MessageId): boolean; + /** + * Apply standard splice semantics and durably record the normalized result. + * The durable event commits before the live projection mutates, so synchronous + * `session/event` observers see the pre-splice lists and can reconstruct the + * removed messages from the normalized coordinates. + * @param target - pending list to mutate. + * @param start - splice position. + * @param deleteCount - maximum number of messages to remove. + * @param inserted - messages to insert at the resolved position. + * @returns messages removed by the splice. + */ + splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[]; + /** Locate one pending identity across both owned lists. */ + private locate; + /** Commit one normalized mutation and publish its live notifications. */ + private mutate; + /** Apply one normalized durable splice to the projection. */ + private apply; + /** Validate one normalized splice against the current projection. */ + private validate; +} +//# sourceMappingURL=inbox.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.js new file mode 100644 index 0000000..4d49a7a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/inbox.js @@ -0,0 +1,185 @@ +/** + * Incremental projection of durable agent inbox events. + * + * @module @deepseek-ai/dsh-agent/inbox + */ +/** A replay-once projection that incrementally consumes later inbox splices. */ +export class Inbox { + session; + notifications; + state = { 'next-turn': [], 'next-step': [] }; + constructor(session, notifications) { + this.session = session; + this.notifications = notifications; + for (const event of session.events.slice(session.header.seedLength ?? 0)) { + if (event.type !== 'agent/inbox/spliced') + continue; + try { + this.apply(event.data); + } + catch (error) { + throw new Error(`invalid persisted inbox splice at session seq ${event.seq}`, { cause: error }); + } + } + } + /** Prompts awaiting individual turns. */ + get nextTurn() { + return this.state['next-turn']; + } + /** Input awaiting the next step boundary. */ + get nextStep() { + return this.state['next-step']; + } + /** Whether either pending-message list contains work. */ + get hasPending() { + return this.nextTurn.length > 0 || this.nextStep.length > 0; + } + /** Durably cancel all pending input, clearing next-step before next-turn. */ + clear() { + this.splice('next-step', 0, this.nextStep.length, []); + this.splice('next-turn', 0, this.nextTurn.length, []); + } + /** + * Remove and return the complete batch proposed for one step, publishing + * each claimed message. The durable splices are pure deletions. + * @param target - whether this boundary also consumes one queued turn. + * @param turn - turn that will own the claimed batch. + * @returns next-step input followed by the queued turn, when requested. + * @internal - The agent loop's step-boundary operation, not a plugin extension point. + */ + claim(target, turn) { + const claimed = this.mutate('next-step', 0, this.nextStep.length, [], false); + if (target === 'next-turn') { + claimed.push(...this.mutate('next-turn', 0, 1, [], false)); + } + for (const message of claimed) + this.notifications.claimed(message, turn); + return claimed; + } + /** + * Append one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to append. + * @throws if the message identity is already pending. + */ + append(target, message) { + this.splice(target, this.state[target].length, 0, [message]); + } + /** + * Prepend one message to a pending list and durably record the insertion. + * @param target - pending list to extend. + * @param message - message to prepend. + * @throws if the message identity is already pending. + */ + prepend(target, message) { + this.splice(target, 0, 0, [message]); + } + /** + * Replace one pending message in place, possibly changing its identity. A + * successful replacement publishes the old message as discarded and the new + * message as inserted. + * @param messageId - identity of the pending message to replace. + * @param newMessage - replacement message. + * @returns whether the message was still pending. + * @throws if the replacement duplicates another pending message identity. + */ + replace(messageId, newMessage) { + const location = this.locate(messageId); + if (location === undefined) + return false; + this.splice(location.target, location.index, 1, [newMessage]); + return true; + } + /** + * Remove one pending message and durably record its cancellation. + * @param messageId - identity of the pending message to remove. + * @returns whether the message was still pending. + */ + remove(messageId) { + const location = this.locate(messageId); + if (location === undefined) + return false; + this.splice(location.target, location.index, 1, []); + return true; + } + /** + * Apply standard splice semantics and durably record the normalized result. + * The durable event commits before the live projection mutates, so synchronous + * `session/event` observers see the pre-splice lists and can reconstruct the + * removed messages from the normalized coordinates. + * @param target - pending list to mutate. + * @param start - splice position. + * @param deleteCount - maximum number of messages to remove. + * @param inserted - messages to insert at the resolved position. + * @returns messages removed by the splice. + */ + splice(target, start, deleteCount, inserted) { + return this.mutate(target, start, deleteCount, inserted, true); + } + /** Locate one pending identity across both owned lists. */ + locate(messageId) { + for (const target of ['next-turn', 'next-step']) { + const index = this.state[target].findIndex(message => message.id === messageId); + if (index >= 0) + return { target, index }; + } + return undefined; + } + /** Commit one normalized mutation and publish its live notifications. */ + mutate(target, start, deleteCount, inserted, discardRemoved) { + const inbox = this.state[target]; + const truncatedStart = Math.trunc(start); + const offset = Number.isNaN(truncatedStart) ? 0 : truncatedStart; + const actualStart = offset < 0 + ? Math.max(inbox.length + offset, 0) + : Math.min(offset, inbox.length); + const truncatedDeleteCount = Math.trunc(deleteCount); + const actualDeleteCount = Math.min(Math.max(Number.isNaN(truncatedDeleteCount) ? 0 : truncatedDeleteCount, 0), inbox.length - actualStart); + if (actualDeleteCount === 0 && inserted.length === 0) + return []; + const outcome = discardRemoved && actualDeleteCount > 0 ? 'canceled' : undefined; + const splice = { + target, + start: actualStart, + ...(actualDeleteCount === 0 ? {} : { removedCount: actualDeleteCount }), + inserted, + ...(outcome === undefined ? {} : { outcome }), + }; + this.validate(splice); + const event = this.session.append('agent/inbox/spliced', splice); + const removed = inbox.splice(actualStart, actualDeleteCount, ...event.data.inserted); + if (discardRemoved) { + for (const message of removed) + this.notifications.discarded(message); + } + for (const message of event.data.inserted) + this.notifications.inserted(message); + return removed; + } + /** Apply one normalized durable splice to the projection. */ + apply(splice) { + this.validate(splice); + const inbox = this.state[splice.target]; + return inbox.splice(splice.start, splice.removedCount ?? 0, ...splice.inserted); + } + /** Validate one normalized splice against the current projection. */ + validate(splice) { + const inbox = this.state[splice.target]; + const removedCount = splice.removedCount ?? 0; + if (!Number.isSafeInteger(splice.start) || splice.start < 0 || splice.start > inbox.length + || !Number.isSafeInteger(removedCount) || removedCount < 0 + || splice.start + removedCount > inbox.length) { + throw new Error('invalid inbox splice'); + } + const candidate = inbox.toSpliced(splice.start, removedCount, ...splice.inserted); + const ids = new Set(); + for (const message of splice.target === 'next-turn' + ? [...candidate, ...this.nextStep] + : [...this.nextTurn, ...candidate]) { + if (ids.has(message.id)) + throw new Error(`message "${message.id}" is already pending`); + ids.add(message.id); + } + } +} +//# sourceMappingURL=inbox.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/index.d.ts new file mode 100644 index 0000000..2909e92 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/index.d.ts @@ -0,0 +1,385 @@ +/** + * Agent service: live registry, factory delegation, and process-local + * initiator scope. Concrete creation and driving belong to the loop. + * + * @module @deepseek-ai/dsh-agent + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'; +import type { TypertContext, TypertLookup } from '@deepseek-ai/dsh-typert-protocol'; +import type { Agent, AgentOptions } from './runtime-types.ts'; +export * from './runtime-types.ts'; +export * from './types.ts'; +export * from './inbox.ts'; +export * from './consumed-work.ts'; +export * from './model-selection.ts'; +export { agentCarrier, agentEvents, assembleContextFor, emitAgentEvent } from './dispatch.ts'; +export type { AgentEventDispatch, AgentSubjectEvent } from './dispatch.ts'; +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertLookupMap { + agent: TypertLookup; + } + interface TypertContextMap { + agent: TypertContext; + } +} +declare module '@deepseek-ai/cordis' { + interface Context { + agents: AgentRegistry; + /** + * The agent association installed as an own property on `Agent.ctx`, or + * `undefined` on a plain context. Contexts derived from `Agent.ctx` inherit + * the association; a deliberately nested scope may carry a nearer + * `dsh-scope` tag while retaining it, so this field is DX context rather + * than the scope resolver. {@link AgentRegistry} registers a root accessor + * defaulting to `undefined`, and core packages below the agent layer use + * `scopeOf()` for layer selection instead of reading this field. + */ + agent?: Agent; + } +} +/** + * Synchronous finalizer returned by unpublished Agent setup when its + * contributions need validation at the exact publication commit point. + */ +export interface AgentSetupCommit { + /** + * Validate and commit the prepared setup immediately before publication. + * @throws when publication must roll the unpublished Agent back. + */ + commit(): void; +} +/** + * Compose an unpublished Agent scope and optionally return its publication commit. + * @param agentCtx - unpublished Agent scope. + * @returns an optional synchronous commit invoked after setup awaits settle and immediately before publication. + */ +export type AgentSetup = (agentCtx: Context) => AgentSetupCommit | Promise | void; +/** + * Options for programmatically creating an agent through the registry factory + * ({@link AgentRegistry.create}). The caller supplies the single live + * `sessionId` shared by the agent registry and session log (e.g. an + * ACP-generated id), plus optional session metadata (the validated `cwd`, fork + * lineage); the factory creates the session and agent under that identity. + */ +export interface CreateAgentOptions { + /** The live agent/session identity. */ + readonly sessionId: SessionId; + /** + * Session creation metadata: validated absolute `cwd`, `parentSession` + * fork lineage, the `seedLength` seed boundary, the coarse `origin` + * classification, and the `delegationDepth` recursion budget. Mirrors the + * `cwd`/`parentSession`/`seedLength`/`origin`/`delegationDepth` fields of + * {@link CreateSessionOptions.meta} in dsh-session (the internal-only + * `createdAt`, used when reconstructing a persisted session, is deliberately + * excluded — a factory caller never sets it). This is durable session data, + * so the session boundary validates and snapshots it before asynchronous + * setup begins. + */ + readonly meta?: { + readonly cwd?: string; + readonly parentSession?: SessionId; + readonly seedLength?: number; + readonly origin?: 'subagent'; + readonly delegationDepth?: number; + readonly agentPreset?: string; + }; + /** + * Initial replay/fork history. A fork supplies a balanced completed-turn + * prefix of the parent's log. The complete seed must be contiguous from seq + * 0, carry only lossless-JSON data, and contain no open turn/step or dangling + * tool call. The factory passes it to the session's durable + * validator/snapshot boundary before publication. + */ + readonly seed?: readonly SessionEvent[]; + /** Per-agent options (model, …). */ + readonly agentOptions?: AgentOptions; + /** Optional creation-only cancellation signal; detached before the returned handle becomes visible. */ + readonly signal?: AbortSignal; + /** + * Creation-time composition of the agent's scoped world. The factory awaits + * setup after minting `agentCtx` but BEFORE inserting or announcing either + * the session or agent, so observers can never see a partially configured + * world. Setup may return an {@link AgentSetupCommit}; the factory invokes its + * synchronous `commit()` after every setup await settles and immediately + * before registry publication. This lets mutable provisioning revalidate at + * the exact publication boundary. Everything registered through `agentCtx` + * (scoped tools, prompt sections/variables, `restrict()`, listeners, awaited + * child plugins) exists before `session/created`, `agent/created`, + * `agent/session-start`, and the first prompt assembly. A setup + * throw/rejection, commit throw, or owner disposal rolls the scope back + * without publishing either id. + * + * **Setup composes, it never drives**: the callback is trusted same-process + * code and receives the full scoped context, so this is a contract rather + * than a runtime restriction. Drive the agent only after creation resolves. + */ + readonly setup?: AgentSetup; +} +/** + * Options for resuming an agent on a persisted session + * ({@link AgentRegistry.resume}). + */ +export interface ResumeAgentOptions { + /** The persisted session id to load and use as the live agent/session identity. */ + readonly resumeSessionId: SessionId; + /** Per-agent options (model, …). */ + readonly agentOptions?: AgentOptions; + /** Optional creation-only cancellation signal for persistence load/setup; detached before return. */ + readonly signal?: AbortSignal; + /** + * Resume-time composition of the agent's fresh scoped world. Persistence is + * loaded first; the factory then mints `agentCtx` and awaits setup while the + * reconstructed session and agent remain unpublished. The callback has the + * same trusted composition-only contract and optional synchronous + * publication commit as {@link CreateAgentOptions.setup}: all registrations + * exist before either creation announcement, and rejection, commit failure, + * or owner disposal rolls the transaction back without publishing either id. + */ + readonly setup?: AgentSetup; +} +/** + * An owned agent plus its disposer, returned by {@link AgentRegistry.create} / + * {@link AgentRegistry.resume}. The disposer is a CAPABILITY: among consumers, + * only the holder can tear this agent down. The registered factory provider is + * also a structural owner because the scoped agent depends on that provider's + * service API; provider unload stops and drains every live handle it made. + * `dispose()` stops the loop, awaits its exit, unregisters the agent, removes + * its session from the store, and finally unwinds its scoped world. + * + * `ctx.agents.get(id)` still returns a bare {@link Agent} — the handle is + * exposed only to the consumer owner that created it; the structural provider + * reaches the same teardown internally. Config-created agents (the loop's own + * startup) are owned by the loop fiber and never need a handle. + */ +export interface AgentHandle { + agent: Agent; + dispose(): Promise; +} +/** + * The agent-creation factory the loop implementation provides to the registry + * via {@link AgentRegistry.setFactory}. Kept on the `dsh-agent` interface so + * consumers (e.g. the ACP bridge) program against `ctx.agents` without + * depending on the concrete `dsh-agent-loop` package. + */ +export interface AgentFactory { + /** + * Create a new agent on a caller-supplied session id. Async because creation + * awaits unpublished setup, invokes its optional synchronous commit, inserts + * both session and agent, emits their creation notifications in order, emits + * `agent/session-start`, and only then starts the loop. The sequence is + * rollback-covered, but notifications delivered before a later listener + * failure remain observable; every agent or session creation announcement + * that began is paired by `agent/disposed` or `session/disposed` during + * rollback. The owner disposes the resolved handle to stop/drain, + * unregister, remove the session, and unwind the scope. + * The registry passes a context carrying the `create()` caller's fiber and + * scope as `ownerCtx`. The implementation attaches the unpublished + * transaction and resulting lifecycle to that owner; it must not infer + * ownership from the factory object's registration context. + * @param ownerCtx - caller-bound context that owns the transaction and live handle. + * @param options - agent/session identity, configuration, and optional setup. + * @returns the owned handle after setup, both announcements, and loop start complete. + */ + createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise; + /** + * Prepare a persisted session and resume an agent on it. Async because it awaits + * both `ctx.sessionPersistence.prepare` and the optional unpublished setup + * transaction; must be called after that service exists (consumers inject + * `sessionPersistence`). Publication follows the same setup-commit and + * ordered boundary as {@link createAgent}. + * @param ownerCtx - caller-bound context that owns load, setup, and the live handle. + * @param options - persisted identity, configuration, and optional setup. + * @returns the owned handle after setup, both announcements, and loop start complete. + */ + resume(ownerCtx: Context, options: ResumeAgentOptions): Promise; +} +/** + * Agent service (`ctx.agents`): tracks live agents and carries the initiating + * Agent through one process-local asynchronous driver chain. Agent *creation* + * is provided by whichever plugin implements the {@link AgentFactory} + * (`@deepseek-ai/dsh-agent-loop`), registered via {@link setFactory}. + * + * Initiator methods provide same-process causal attribution only. Ambient + * presence is neither liveness proof nor authorization; subjects and owners + * remain explicit, as does identity at worker, process, persistence, and wire + * boundaries. Returned Promise boundaries drain during teardown, except a + * nested lineage that starts an owning-fiber unload is excluded from its own drain. + */ +export declare class AgentRegistry extends Service { + private store; + private factory; + private readonly initiators; + private readonly initiatorRuns; + private initiatorState; + private activeInitiatorRuns; + private initiatorDrain; + private initiatorDisposal; + constructor(ctx: Context); + /** + * Read the Agent that initiated the inherited asynchronous driver chain. + * Use this optional form for logging, tracing, metrics, or host attribution + * that also supports agentless calls. When a parent creates a child, setup + * reports the causal parent while `agentCtx.agent` identifies the child. + * @returns the inherited Agent, or `undefined` outside an initiator boundary + * and inside an explicit clearing boundary. + * @throws when this service instance has been disposed. + */ + currentInitiator(): Agent | undefined; + /** + * Read the initiating Agent and fail when no initiator boundary is active. + * Use this for private helpers contractually below a driver, or for a + * deployment-owned outbound request whose contract forbids agentless calls. + * Generic or direct-call paths use optional lookup or explicit request fields. + * @returns the inherited Agent. + * @throws when no initiator is active or this service instance has been disposed. + */ + requireInitiator(): Agent; + /** + * Run an operation with one exact Agent as its process-local initiator. The + * exact synchronous value or Promise returned by the operation is preserved. + * Custom drivers and test harnesses wrap their complete returned foreground + * lifetime. + * A queue or wire receiver may establish this boundary only after validating + * explicit identity and resolving the exact live Agent; this method does neither. + * Detached work remains owned by the subsystem that starts it. + * @param agent - initiating Agent to inherit; presence is neither liveness proof nor authorization. + * @param operation - synchronous or asynchronous operation to invoke. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withInitiator(agent: Agent, operation: () => T): T; + /** + * Run an operation inside a boundary that hides any inherited initiating + * Agent. The exact synchronous value or Promise is preserved. + * Use this while creating lazy shared timers, queue pumps, pool maintenance, + * watchers, or exporters so they do not inherit the first Agent that happens + * to initialize them. It clears only initiator attribution, not explicit + * fields, and does not own or drain detached resources. + * @param operation - synchronous or asynchronous operation to invoke without an initiator. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withoutInitiator(operation: () => T): T; + /** + * Register the agent-creation factory (the loop calls this on construction, + * effect-scoped). A traced Cordis service is canonicalized to its concrete + * target; each create/resume call is then traced through that caller's + * context so ownership follows the caller without stacking proxy layers. + * Throws if a factory is already registered. Returns the disposer; on + * dispose the factory slot is cleared. + * @param factory - the loop-owned factory {@link create}/{@link resume} delegate to. + * @returns the disposer that clears the factory slot. The exact + * Cordis effect disposer (single-shot): composite (generator) effects may + * yield it directly — exact identity nests the teardown in order. + */ + setFactory(factory: AgentFactory): () => void; + /** Return the active creation factory. */ + private requireFactory; + /** + * Create and publish a new agent through the registered factory. + * Distinct from {@link register} (which records an already-constructed + * agent): this constructs the agent and its session. Rejects if no factory is + * registered or creation/setup fails. The resolved {@link AgentHandle} lets + * the owner tear down exactly this agent. + * @param options - shared identity, session seed/metadata, and agent options. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + create(options: CreateAgentOptions): Promise; + /** + * Load a persisted session and resume an agent on it through the registered + * factory. Rejects if no factory is registered; the factory rejects if + * session persistence is not configured or persistence/setup fails. + * @param options - persisted identity, configuration, and optional setup. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + resume(options: ResumeAgentOptions): Promise; + /** + * Register a live agent. Throws if an agent with the same id is already + * registered. Emits `agent/created` on registration and `agent/disposed` + * when the calling fiber is disposed — both with the agent's scope carrier + * (`scopeTarget(agent, agent)`): the subject is the agent in hand, so the + * emits are scope-filtered regardless of which context invoked `register` + * (calling through `agent.ctx` scopes EFFECTS; dispatch scoping always + * requires passing the carrier). Returns the disposer. + * @param agent - the already-constructed agent to record in the store. + * @returns the EXACT Cordis effect disposer (single-shot; a repeat call + * returns undefined without awaiting an in-flight teardown). Exact + * identity is load-bearing: a composite (generator) effect that owns a + * teardown ORDER — the agent factory's lifecycle chain — must yield THIS + * function so Cordis nests the unregistration at that yield position; + * yielding a wrapper would leave it disposing as a concurrent sibling on + * owner unload, unregistering the agent (and emitting `agent/disposed`) + * while its final turn is still draining. + */ + register(agent: Agent): () => void; + /** + * Insert an already-constructed agent without announcing it. This is the + * advanced ordered-lifecycle primitive used by the async agent factory: it + * first completes setup while the agent is unpublished, then assigns the + * returned detach closure into its pre-installed composite teardown before + * calling {@link announce}. Ordinary callers use {@link register}. + * @param agent - the prepared, unpublished agent. + * @param owner - live agent whose scoped context created this agent, or + * undefined for a top-level runtime root. This is runtime ownership, not + * the resumed session's durable parent lineage. + * @returns an idempotent closure that removes this exact entry and emits + * `agent/disposed` with listener failures contained. When called from a + * synchronous `agent/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + */ + enter(agent: Agent, owner: Agent | undefined): () => void; + /** Remove one exact entered agent and emit its paired disposal when announced. */ + private detachEntered; + /** Emit the paired disposal edge through the entry's stable carrier. */ + private emitDisposed; + /** + * Announce an agent previously inserted with {@link enter}. + * @param agent - the live inserted agent to announce. + * @throws if `agent` is not the exact live registry entry for its id, or its + * creation announcement already began (including a reentrant call from a + * creation listener). + */ + announce(agent: Agent): void; + /** + * Look up a live agent. + * @param id - the shared agent/session id to look up. + * @returns the agent, or undefined when no live agent has that id. + */ + get(id: SessionId): Agent | undefined; + /** + * Test whether a live agent was created through one exact parent agent's + * scoped context. Runtime ownership is independent of durable session + * lineage and remains unambiguous when unrelated providers reuse an id. + * @param id - the candidate child agent's shared agent/session id. + * @param owner - the expected runtime creator agent. + * @returns true only while the exact child entry is live under that owner. + */ + isOwnedBy(id: SessionId, owner: Agent): boolean; + /** + * All live agents, in registration order. + * @returns a fresh array; mutating it does not affect the registry. + */ + list(): Agent[]; + /** + * All live top-level agents in registration order. A top-level agent was + * created without an owning agent context; durable session lineage does not + * affect this runtime relation, so a resumed fork may still be a root. + * @returns a fresh array; mutating it does not affect the registry. + */ + roots(): Agent[]; + /** Reject new initiator boundaries while inherited continuations drain. */ + private closeInitiators; + /** Wait for returned-Promise boundaries, then invalidate retained references. */ + private disposeInitiators; + /** Establish one tracked initiator or clearing boundary. */ + private runWithInitiator; + /** Whether one unloading fiber owns this service's lifecycle. */ + private hasLifecycleAncestor; + private assertInitiatorsReadable; + /** Exclude the boundary chain that initiated this teardown from its own drain. */ + private releaseReentrantInitiatorRuns; + private releaseInitiatorRun; +} +export default AgentRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/index.js new file mode 100644 index 0000000..ce3279d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/index.js @@ -0,0 +1,474 @@ +/** + * Agent service: live registry, factory delegation, and process-local + * initiator scope. Concrete creation and driving belong to the loop. + * + * @module @deepseek-ai/dsh-agent + */ +import { getTraceable, Service, symbols } from '@deepseek-ai/cordis'; +import { AsyncLocalStorage } from 'node:async_hooks'; +import { isPromise } from 'node:util/types'; +import { scopeTarget } from '@deepseek-ai/dsh-scope'; +export * from "./runtime-types.js"; +export * from "./types.js"; +export * from "./inbox.js"; +export * from "./consumed-work.js"; +export * from "./model-selection.js"; +export { agentCarrier, agentEvents, assembleContextFor, emitAgentEvent } from "./dispatch.js"; +/** Thrown when create/resume is called before an agent factory is registered. */ +const NO_FACTORY_MESSAGE = 'no agent factory registered (load an agent-loop plugin)'; +const NO_INITIATOR_MESSAGE = 'no initiating agent is active'; +const DISPOSED_INITIATOR_MESSAGE = 'agent initiator scope is disposed'; +/** + * Agent service (`ctx.agents`): tracks live agents and carries the initiating + * Agent through one process-local asynchronous driver chain. Agent *creation* + * is provided by whichever plugin implements the {@link AgentFactory} + * (`@deepseek-ai/dsh-agent-loop`), registered via {@link setFactory}. + * + * Initiator methods provide same-process causal attribution only. Ambient + * presence is neither liveness proof nor authorization; subjects and owners + * remain explicit, as does identity at worker, process, persistence, and wire + * boundaries. Returned Promise boundaries drain during teardown, except a + * nested lineage that starts an owning-fiber unload is excluded from its own drain. + */ +export class AgentRegistry extends Service { + store = new Map(); + factory; + initiators = new AsyncLocalStorage(); + initiatorRuns = new AsyncLocalStorage(); + initiatorState = 'active'; + activeInitiatorRuns = 0; + initiatorDrain; + initiatorDisposal; + constructor(ctx) { + super(ctx, 'agents'); + ctx.inject(['typert'], (typeCtx) => { + typeCtx.typert.lookups.register('agent', { + parameter: 'agent', + wire: 'agentId', + hostTypeSymbol: '@deepseek-ai/dsh-agent#Agent', + wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + resolve: sessionId => this.get(sessionId), + }); + typeCtx.typert.contexts.registerHost('agent', { + wire: 'agentId', + wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + resolve: sessionId => this.get(sessionId)?.ctx, + }); + }); + // The `ctx.agent` DX accessor: default `undefined` on every context, so a + // plain plugin context reads cleanly instead of hitting the Cordis + // unknown-property throw. Each Agent.ctx shadows it with an own property + // (own properties resolve before the context proxy is consulted), so the + // accessor body never needs to resolve a scope itself. Effect-scoped: + // unwinds with this service's fiber. + ctx.accessor('agent', { get: () => undefined }); + ctx.on('internal/status', (fiber) => { + if (fiber.state === 5 /* FiberState.UNLOADING */ && this.hasLifecycleAncestor(fiber)) { + this.closeInitiators(); + } + }); + ctx.effect(function* () { + yield () => this.disposeInitiators(); + yield () => { this.closeInitiators(); }; + }.bind(this), 'agents.initiatorLifecycle()'); + } + /** + * Read the Agent that initiated the inherited asynchronous driver chain. + * Use this optional form for logging, tracing, metrics, or host attribution + * that also supports agentless calls. When a parent creates a child, setup + * reports the causal parent while `agentCtx.agent` identifies the child. + * @returns the inherited Agent, or `undefined` outside an initiator boundary + * and inside an explicit clearing boundary. + * @throws when this service instance has been disposed. + */ + currentInitiator() { + this.assertInitiatorsReadable(); + return this.initiators.getStore(); + } + /** + * Read the initiating Agent and fail when no initiator boundary is active. + * Use this for private helpers contractually below a driver, or for a + * deployment-owned outbound request whose contract forbids agentless calls. + * Generic or direct-call paths use optional lookup or explicit request fields. + * @returns the inherited Agent. + * @throws when no initiator is active or this service instance has been disposed. + */ + requireInitiator() { + const agent = this.currentInitiator(); + if (agent === undefined) + throw new Error(NO_INITIATOR_MESSAGE); + return agent; + } + /** + * Run an operation with one exact Agent as its process-local initiator. The + * exact synchronous value or Promise returned by the operation is preserved. + * Custom drivers and test harnesses wrap their complete returned foreground + * lifetime. + * A queue or wire receiver may establish this boundary only after validating + * explicit identity and resolving the exact live Agent; this method does neither. + * Detached work remains owned by the subsystem that starts it. + * @param agent - initiating Agent to inherit; presence is neither liveness proof nor authorization. + * @param operation - synchronous or asynchronous operation to invoke. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withInitiator(agent, operation) { + return this.runWithInitiator(agent, operation); + } + /** + * Run an operation inside a boundary that hides any inherited initiating + * Agent. The exact synchronous value or Promise is preserved. + * Use this while creating lazy shared timers, queue pumps, pool maintenance, + * watchers, or exporters so they do not inherit the first Agent that happens + * to initialize them. It clears only initiator attribution, not explicit + * fields, and does not own or drain detached resources. + * @param operation - synchronous or asynchronous operation to invoke without an initiator. + * @returns the exact value returned by `operation`. + * @throws when the initiator scope is closing/disposed, or when `operation` throws. + */ + withoutInitiator(operation) { + return this.runWithInitiator(undefined, operation); + } + /** + * Register the agent-creation factory (the loop calls this on construction, + * effect-scoped). A traced Cordis service is canonicalized to its concrete + * target; each create/resume call is then traced through that caller's + * context so ownership follows the caller without stacking proxy layers. + * Throws if a factory is already registered. Returns the disposer; on + * dispose the factory slot is cleared. + * @param factory - the loop-owned factory {@link create}/{@link resume} delegate to. + * @returns the disposer that clears the factory slot. The exact + * Cordis effect disposer (single-shot): composite (generator) effects may + * yield it directly — exact identity nests the teardown in order. + */ + setFactory(factory) { + const dispose = this.ctx.effect(() => { + if (this.factory !== undefined) + throw new Error('an agent factory is already registered'); + // Avoid stacking two Cordis shadow layers when a caller passes a Service + // already read through a context. Calls are re-traced through their + // actual owner context below. + const target = factory[symbols.original] ?? factory; + this.factory = { target }; + return () => { this.factory = undefined; }; + }, 'agents.setFactory()'); + // The exact cordis effect disposer (the agents.register() convention): a + // caller's composite effect can yield it for in-order teardown; the + // loop's constructor effect returns it directly, identity-nesting the + // registration under that effect. + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity + return dispose; + } + /** Return the active creation factory. */ + requireFactory() { + if (this.factory === undefined) + throw new Error(NO_FACTORY_MESSAGE); + return this.factory; + } + /** + * Create and publish a new agent through the registered factory. + * Distinct from {@link register} (which records an already-constructed + * agent): this constructs the agent and its session. Rejects if no factory is + * registered or creation/setup fails. The resolved {@link AgentHandle} lets + * the owner tear down exactly this agent. + * @param options - shared identity, session seed/metadata, and agent options. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + async create(options) { + const ownerCtx = this.ctx; + // Re-trace a Service-backed factory through the accessing context + // explicitly. This preserves AgentLoop's dependency origin while binding + // its effects to ownerCtx; plain factories receive ownerCtx as an explicit + // capability and need no Cordis tracker magic. + const { target } = this.requireFactory(); + const receiver = getTraceable(ownerCtx, target); + // oxlint-disable-next-line typescript/unbound-method -- Reflect.apply intentionally supplies the caller-traced receiver + return Reflect.apply(target.createAgent, receiver, [ownerCtx, options]); + } + /** + * Load a persisted session and resume an agent on it through the registered + * factory. Rejects if no factory is registered; the factory rejects if + * session persistence is not configured or persistence/setup fails. + * @param options - persisted identity, configuration, and optional setup. + * @returns the handle after setup, rollback-covered publication, and loop start complete. + */ + async resume(options) { + const ownerCtx = this.ctx; + const { target } = this.requireFactory(); + const receiver = getTraceable(ownerCtx, target); + // oxlint-disable-next-line typescript/unbound-method -- Reflect.apply intentionally supplies the caller-traced receiver + return Reflect.apply(target.resume, receiver, [ownerCtx, options]); + } + /** + * Register a live agent. Throws if an agent with the same id is already + * registered. Emits `agent/created` on registration and `agent/disposed` + * when the calling fiber is disposed — both with the agent's scope carrier + * (`scopeTarget(agent, agent)`): the subject is the agent in hand, so the + * emits are scope-filtered regardless of which context invoked `register` + * (calling through `agent.ctx` scopes EFFECTS; dispatch scoping always + * requires passing the carrier). Returns the disposer. + * @param agent - the already-constructed agent to record in the store. + * @returns the EXACT Cordis effect disposer (single-shot; a repeat call + * returns undefined without awaiting an in-flight teardown). Exact + * identity is load-bearing: a composite (generator) effect that owns a + * teardown ORDER — the agent factory's lifecycle chain — must yield THIS + * function so Cordis nests the unregistration at that yield position; + * yielding a wrapper would leave it disposing as a concurrent sibling on + * owner unload, unregistering the agent (and emitting `agent/disposed`) + * while its final turn is still draining. + */ + register(agent) { + const dispose = this.ctx.effect(function* () { + yield this.enter(agent, this.ctx.agent); + this.announce(agent); + }.bind(this), 'agents.register()'); + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity + return dispose; + } + /** + * Insert an already-constructed agent without announcing it. This is the + * advanced ordered-lifecycle primitive used by the async agent factory: it + * first completes setup while the agent is unpublished, then assigns the + * returned detach closure into its pre-installed composite teardown before + * calling {@link announce}. Ordinary callers use {@link register}. + * @param agent - the prepared, unpublished agent. + * @param owner - live agent whose scoped context created this agent, or + * undefined for a top-level runtime root. This is runtime ownership, not + * the resumed session's durable parent lineage. + * @returns an idempotent closure that removes this exact entry and emits + * `agent/disposed` with listener failures contained. When called from a + * synchronous `agent/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + */ + enter(agent, owner) { + const id = agent.id; + if (id !== agent.session.id) { + throw new Error(`agent id "${id}" does not match session id "${agent.session.id}"`); + } + const carrier = scopeTarget(agent, agent); + // This is the authoritative collision boundary. Concurrent create/resume + // operations may both prepare, but only one exact entry can publish. + if (this.store.has(id)) + throw new Error(`agent "${id}" is already registered`); + const entry = { + id, + agent, + owner, + carrier, + announced: false, + announcing: false, + detachRequested: false, + }; + this.store.set(id, entry); + let entered = true; + const detach = () => { + if (!entered) + return; + entered = false; + // Every callback reached by this creation dispatch must observe the same + // live entry, and disposal must follow creation. A listener may own + // the advanced detach capability, so make that ordering structural: + // visibility and the paired disposal are deferred until announce()'s + // synchronous dispatch has unwound. + if (entry.announcing) { + entry.detachRequested = true; + return; + } + this.detachEntered(entry); + }; + return detach; + } + /** Remove one exact entered agent and emit its paired disposal when announced. */ + detachEntered(entry) { + entry.detachRequested = false; + // A stale capability can never delete a later same-id lifecycle. The + // captured entry identity is the final boundary. + /* v8 ignore next -- enter() rejects replacement while this single-shot detach capability is live. */ + if (this.store.get(entry.id) !== entry) + return; + this.store.delete(entry.id); + // An insertion rolled back before announce was never externally created, + // so emitting disposed would invent an impossible lifecycle edge. Marking + // happens before the created emit: if a later created listener throws, + // earlier listeners may already have observed it and must see disposal. + if (!entry.announced) + return; + this.emitDisposed(entry); + } + /** Emit the paired disposal edge through the entry's stable carrier. */ + emitDisposed(entry) { + const args = [entry.carrier, 'agent/disposed', { agent: entry.agent }]; + for (const callback of this.ctx.events.dispatch('emit', args)) { + try { + const returned = callback(...args); + void Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`agent "${entry.id}": agent/disposed listener rejected: ${String(error)}`); + }); + } + catch (error) { + this.ctx.logger.warn(`agent "${entry.id}": agent/disposed listener threw: ${String(error)}`); + } + } + } + /** + * Announce an agent previously inserted with {@link enter}. + * @param agent - the live inserted agent to announce. + * @throws if `agent` is not the exact live registry entry for its id, or its + * creation announcement already began (including a reentrant call from a + * creation listener). + */ + announce(agent) { + const entry = this.store.get(agent.id); + if (entry === undefined || entry.agent !== agent) { + throw new Error(`agent "${agent.id}" is not live in this registry`); + } + if (entry.announced || entry.announcing) { + throw new Error(`agent "${entry.id}" was already announced`); + } + // Mark before dispatch so a listener cannot recursively create a second + // lifecycle edge; detach still pairs a partially delivered first edge. + entry.announcing = true; + entry.announced = true; + const args = [entry.carrier, 'agent/created', { agent: entry.agent }]; + try { + for (const callback of this.ctx.events.dispatch('emit', args)) { + // A synchronous creation failure vetoes publication and rolls back. + // Returned-promise rejection happens after this synchronous boundary, so + // observe and report it instead of leaking an unhandled rejection. + const returned = callback(...args); + void Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`agent "${entry.id}": agent/created listener rejected: ${String(error)}`); + }); + } + } + finally { + entry.announcing = false; + if (entry.detachRequested) + this.detachEntered(entry); + } + } + /** + * Look up a live agent. + * @param id - the shared agent/session id to look up. + * @returns the agent, or undefined when no live agent has that id. + */ + get(id) { + return this.store.get(id)?.agent; + } + /** + * Test whether a live agent was created through one exact parent agent's + * scoped context. Runtime ownership is independent of durable session + * lineage and remains unambiguous when unrelated providers reuse an id. + * @param id - the candidate child agent's shared agent/session id. + * @param owner - the expected runtime creator agent. + * @returns true only while the exact child entry is live under that owner. + */ + isOwnedBy(id, owner) { + return this.store.get(id)?.owner === owner; + } + /** + * All live agents, in registration order. + * @returns a fresh array; mutating it does not affect the registry. + */ + list() { + return [...this.store.values()].map(entry => entry.agent); + } + /** + * All live top-level agents in registration order. A top-level agent was + * created without an owning agent context; durable session lineage does not + * affect this runtime relation, so a resumed fork may still be a root. + * @returns a fresh array; mutating it does not affect the registry. + */ + roots() { + return [...this.store.values()] + .filter(entry => entry.owner === undefined) + .map(entry => entry.agent); + } + /** Reject new initiator boundaries while inherited continuations drain. */ + closeInitiators() { + if (this.initiatorState === 'active') + this.initiatorState = 'closing'; + } + /** Wait for returned-Promise boundaries, then invalidate retained references. */ + disposeInitiators() { + return (this.initiatorDisposal ??= (async () => { + this.closeInitiators(); + this.releaseReentrantInitiatorRuns(); + if (this.activeInitiatorRuns !== 0) { + this.initiatorDrain ??= Promise.withResolvers(); + await this.initiatorDrain.promise; + } + this.initiatorState = 'disposed'; + this.initiators.disable(); + this.initiatorRuns.disable(); + })()); + } + /** Establish one tracked initiator or clearing boundary. */ + runWithInitiator(agent, operation) { + if (this.initiatorState !== 'active') + throw new Error(DISPOSED_INITIATOR_MESSAGE); + const run = { + active: true, + parent: this.initiatorRuns.getStore(), + }; + this.activeInitiatorRuns += 1; + let result; + try { + result = this.initiatorRuns.run(run, () => this.initiators.run(agent, operation)); + } + catch (error) { + this.releaseInitiatorRun(run); + throw error; + } + if (isPromise(result)) { + try { + void Promise.prototype.then.call(result, () => { this.releaseInitiatorRun(run); }, () => { this.releaseInitiatorRun(run); }); + } + catch { + // A branded Promise may expose a failing @@species. Observer setup did + // not attach, so preserve the exact return without leaking the run. + this.releaseInitiatorRun(run); + } + } + else { + this.releaseInitiatorRun(run); + } + return result; + } + /** Whether one unloading fiber owns this service's lifecycle. */ + hasLifecycleAncestor(candidate) { + let fiber = this.ctx.fiber; + while (true) { + if (fiber === candidate) + return true; + const parent = fiber.parent.fiber; + if (parent === fiber) + return false; + fiber = parent; + } + } + assertInitiatorsReadable() { + if (this.initiatorState === 'disposed') + throw new Error(DISPOSED_INITIATOR_MESSAGE); + } + /** Exclude the boundary chain that initiated this teardown from its own drain. */ + releaseReentrantInitiatorRuns() { + let run = this.initiatorRuns.getStore(); + while (run !== undefined) { + this.releaseInitiatorRun(run); + run = run.parent; + } + } + releaseInitiatorRun(run) { + if (!run.active) + return; + run.active = false; + this.activeInitiatorRuns -= 1; + if (this.activeInitiatorRuns !== 0) + return; + this.initiatorDrain?.resolve(); + this.initiatorDrain = undefined; + } +} +export default AgentRegistry; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.d.ts new file mode 100644 index 0000000..5d42f3c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned agent lifecycle invariants. @module @deepseek-ai/dsh-agent/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "agent-invariant"; +/** Services required before the companion can register. */ +export declare const inject: string[]; +/** + * Register the agent invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.js new file mode 100644 index 0000000..e88c5bc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/invariant.js @@ -0,0 +1,24 @@ +/** Package-owned agent lifecycle invariants. @module @deepseek-ai/dsh-agent/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-agent'; +/** Cordis companion plugin name. */ +export const name = 'agent-invariant'; +/** Services required before the companion can register. */ +export const inject = ['invariants']; +/** Install the agent contribution into its child registration fiber. */ +const install = (ctx, fail) => { + const lastStatus = new WeakMap(); + ctx.on('agent/status', ({ agent, status }) => { + const previous = lastStatus.get(agent); + if (previous === status) { + fail(`agent/status repeated ${status} (no-op transition)`); + } + lastStatus.set(agent, status); + }, { global: true }); +}; +/** + * Register the agent invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.d.ts new file mode 100644 index 0000000..2ba3db5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.d.ts @@ -0,0 +1,36 @@ +/** + * Agent-scoped model selection shared by runtime entry points. + * @module @deepseek-ai/dsh-agent/model-selection + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { ReasoningEffortId } from '@deepseek-ai/dsh-llm'; +/** Complete provider, model, and optional reasoning effort selected for one live Agent. */ +export interface ModelSelection { + /** Registered provider route. */ + provider: string; + /** Provider-owned model id. */ + model: string; + /** Adapter-owned reasoning effort, or provider/default behavior when absent. */ + reasoningEffort?: ReasoningEffortId; +} +/** Mutable model selection plus the value captured for the current step. */ +export interface ModelSelectionRef { + /** Model selected for the next step that enters prompt assembly. */ + current: ModelSelection | undefined; + /** Selection captured when the current step entered prompt assembly. */ + assembled: ModelSelection | undefined; +} +/** + * Couple one mutable selection to Agent-scoped prompt assembly and request routing. + * Prompt assembly snapshots the selected model before delegating, then applies + * its provider/model pair and effort to request config so a + * concurrent switch takes effect on a later step instead of splitting the two + * surfaces. An absent selected effort clears any inherited effort, restoring + * the selected model's provider/default behavior. + * + * @param agentCtx - The selected Agent's scoped context. + * @param selection - Mutable selection owned by the calling entry point. + * @returns Disposer for both scoped waterfall listeners. + */ +export declare function installModelSelection(agentCtx: Context, selection: ModelSelectionRef): () => void; +//# sourceMappingURL=model-selection.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.js new file mode 100644 index 0000000..d8a5963 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/model-selection.js @@ -0,0 +1,53 @@ +/** + * Agent-scoped model selection shared by runtime entry points. + * @module @deepseek-ai/dsh-agent/model-selection + */ +/** + * Couple one mutable selection to Agent-scoped prompt assembly and request routing. + * Prompt assembly snapshots the selected model before delegating, then applies + * its provider/model pair and effort to request config so a + * concurrent switch takes effect on a later step instead of splitting the two + * surfaces. An absent selected effort clears any inherited effort, restoring + * the selected model's provider/default behavior. + * + * @param agentCtx - The selected Agent's scoped context. + * @param selection - Mutable selection owned by the calling entry point. + * @returns Disposer for both scoped waterfall listeners. + */ +export function installModelSelection(agentCtx, selection) { + const disposeAssembly = agentCtx.on('system-prompt/assemble', async (_assembly, _context, next) => { + const selected = selection.current; + const assembled = await next(); + selection.assembled = selected; + if (selected === undefined) + return assembled; + return { + ...assembled, + variables: { + ...assembled.variables, + provider: selected.provider, + model: selected.model, + }, + }; + }); + const disposeRequest = agentCtx.on('agent/request', async (_payload, next) => { + const resolved = await next(); + const selected = selection.assembled; + if (selected === undefined) + return resolved; + const { reasoningEffort: _inheritedEffort, ...withoutInheritedEffort } = resolved; + return { + ...withoutInheritedEffort, + provider: selected.provider, + model: selected.model, + ...selected.reasoningEffort === undefined + ? {} + : { reasoningEffort: selected.reasoningEffort }, + }; + }); + return () => { + disposeAssembly(); + disposeRequest(); + }; +} +//# sourceMappingURL=model-selection.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.d.ts new file mode 100644 index 0000000..70e82d1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.d.ts @@ -0,0 +1,324 @@ +/** + * Public agent types and live-runtime events. Durable transcript facts and + * turn/step boundaries remain `@deepseek-ai/dsh-session` events. + * + * @module @deepseek-ai/dsh-agent + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { Scoped } from '@deepseek-ai/dsh-scope'; +import type { LlmCallConfig, LlmFailure, ResolvedRetryPolicy } from '@deepseek-ai/dsh-llm'; +import type { AgentCancelCause, Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session'; +export type { AgentCancelCause } from '@deepseek-ai/dsh-session'; +import type { Inbox } from './inbox.ts'; +import type { InboxTarget } from './types.ts'; +declare module '@deepseek-ai/dsh-system-prompt' { + interface AssembleContext { + /** Agent for this assembly; absent on diagnostics. When present, `scope` must identify the same agent. */ + agent?: Agent; + } +} +/** Merge-extensible agent creation options. Persona belongs to system-prompt sections. */ +export interface AgentOptions { + /** Provider route (must have a registered adapter at call time). */ + provider?: string; + /** Model id interpreted by the selected provider adapter. */ + model?: string; + /** Maximum output tokens for each conversation-model request. */ + maxTokens?: number; +} +/** Options for {@link Agent.cancel}. */ +export interface CancelOptions { + /** + * Preserve queued and steering inbox items instead of discarding them. The + * active turn is still aborted, but un-started and pending work survives for a + * later turn and no canceled inbox splice is logged. + */ + keepInbox?: boolean | undefined; +} +/** + * An agent's lifecycle state, emitted on every transition as `agent/status`: + * `idle` means no driver is active; `running` begins when waking input starts + * cancellable pre-step processing and lasts while the driver drains, + * closes, or checkpoints turns. Disposal removes the agent from its registry; + * it is not a third observable status. + */ +export type AgentStatus = 'idle' | 'running'; +/** Whether and with which messages the loop enters a proposed step. */ +export type PreStepDecision = { + kind: 'reject'; +} | { + kind: 'enter'; + messages: UserMessage[]; +}; +/** Action returned by a listener that owns model-request recovery. */ +export type RequestErrorAction = { + kind: 'retry'; +} | undefined; +/** Why a session lifecycle began; seeded creates are `startup`, while persisted loads are `resume`. */ +export type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact'; +/** Public live-agent handle. */ +export interface Agent { + /** The single identity shared with {@link session}. */ + readonly id: SessionId; + /** The provider route and model this agent's requests use. */ + readonly options: AgentOptions; + /** The live session this agent drives; its log is the durable source of truth. */ + readonly session: Session; + /** The agent-owned projection of durable pending work. */ + readonly inbox: Inbox; + /** The current lifecycle state, mirrored on every `agent/status` transition. */ + readonly status: AgentStatus; + /** Agent-scoped context; its contributions are agent-local, unwind on disposal, and reject registration afterward. */ + readonly ctx: Context; + /** + * Clear queued and steering work — unless `keepInbox` — and abort the active + * turn or between-turn task. The first cause wins for that activity. With no + * active activity, cancellation is a no-op and does not arm later work. + * @param cause - the stable caller intent carried by the active operation signal. + * @param options - cancellation options; `keepInbox` preserves pending work. + */ + cancel(cause: AgentCancelCause, options?: CancelOptions): void; + /** + * Resolve after the current whole-agent activity reaches quiescence. This + * follows replacement work started before the observed driver retires, + * but does not identify the settlement of any particular message. + * @returns fulfillment after no active driver or maintenance task remains. + */ + whenIdle(): Promise; + /** + * Run one non-turn maintenance task from the true idle phase. The task starts + * synchronously after claiming that phase; later waking input remains in the + * inbox until the task settles, while public status stays `idle`. + * `whenIdle()` follows both the task and any waking work released behind it. + * @param task - operation whose fulfillment or rejection is preserved, with a signal aborted by {@link cancel}. + * @throws synchronously when turn-driving or another maintenance task already owns the agent. + * @returns the task promise. + */ + runMaintenance(task: (signal: AbortSignal) => Promise): Promise; + /** + * Route identified input to an inbox boundary and optionally wake the driver. + * Waking input submitted after active cancellation is queued for the next + * turn and runs when the aborted activity converges to idle; a `disposed` + * cancel leaves it parked. A wake submitted while already idle always opens + * its turn boundary, even when its message is cleared before the driver + * claims ([cancel-convergence wake latch](../../../../.agents/notes/implemented/bug-fix/2026-08-07-cancel-convergence-wake-latch.md)). + * @param message - identified content and the source that supplied it. + * @param target - the preferred next-turn or next-step inbox boundary. + * @param wakeup - whether delivery may wake the driver. + */ + send(message: UserMessage, target: InboxTarget, wakeup: boolean): void; + /** + * Queue an ordinary follow-up turn and wake the driver. The item becomes the + * sole ordinary message of its own turn. + * @param message - identified prompt content and the source that supplied it. + */ + followup(message: UserMessage): void; + /** + * Submit steering for the nearest step. An idle driver starts a turn; + * a running driver consumes it at its next step boundary. + * A rejected step leaves steering parked in the inbox until the next + * wake; cancellation or disposal may discard pending steering. + * @param message - identified steering content and the source that supplied it. + */ + steer(message: UserMessage): void; + /** + * Queue model-facing context for the next pre-step without waking the + * driver. A running driver claims it at the nearest later step boundary; + * idle drivers leave it pending until follow-up or steering + * wakes them. It may miss a request whose pre-step already claimed its + * batch. Cancellation or disposal may discard pending context. + * @param message - identified injected context and the source that supplied it. + */ + inject(message: UserMessage): void; +} +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * A fully configured agent and live session were published. Setup is + * composition-only; `agent/session-start` is the first startup-driving extension point. + * Synchronous listener failure vetoes publication, while returned-promise + * rejection is reported. Detach requested during dispatch waits until every + * creation listener has observed the stable entry. + * @param payload.agent - the newly registered agent with its live session and completed setup. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/created'(this: Scoped, payload: { + agent: Agent; + }): void; + /** + * An agent left the registry; AgentLoop emits this after driver quiescence + * and scoped-registration unwind, but before session detachment. Custom + * registry users own their driver-ordering contract. + * @param payload.agent - the exact agent removed from the registry. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/disposed'(this: Scoped, payload: { + agent: Agent; + }): void; + /** + * Agent status changed (`idle` ⇄ `running`). A waking delivery enters + * `running` synchronously after reserving cancellation; `idle` means no + * driver remains scheduled or active. + * @param payload.agent - the agent whose status flipped. + * @param payload.status - the status just entered (the transition's destination). + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/status'(this: Scoped, payload: { + agent: Agent; + status: AgentStatus; + }): void; + /** + * One message entered the live inbox. + * @param payload.agent - the agent whose inbox changed. + * @param payload.message - the inserted message. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/inbox/inserted'(this: Scoped, payload: { + agent: Agent; + message: UserMessage; + }): void; + /** + * One message left the inbox inside its open turn. If the proposed step + * is rejected, the claimed message ends here: it is neither discarded nor + * re-emitted as a user/message, and the turn closes without a step. + * @param payload.agent - the agent whose inbox changed. + * @param payload.message - the claimed message. + * @param payload.turn - the owning turn. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/inbox/claimed'(this: Scoped, payload: { + agent: Agent; + message: UserMessage; + turn: number; + }): void; + /** + * One message was discarded from the live inbox. + * @param payload.agent - the agent whose inbox changed. + * @param payload.message - the discarded message. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/inbox/discarded'(this: Scoped, payload: { + agent: Agent; + message: UserMessage; + }): void; + /** + * The session lifecycle began, once before the first turn. Use + * `agent.inject()` to seed model-facing context. This is a notification, not + * a veto; disposal requested by a lifecycle owner is rechecked before the + * driver starts. + * @param payload.agent - the agent whose session lifecycle began. + * @param payload.source - why the session started (fresh startup, resume, …). + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/session-start'(this: Scoped, payload: { + agent: Agent; + source: SessionStartSource; + }): void; + /** + * Reject a proposed step or replace the messages that enter it. Calling + * `next()` preserves the current messages. + * @param payload.agent - the agent proposing the step. + * @param payload.messages - messages removed from the inbox for this step. + * @param payload.turn - the turn that will own the step. + * @param payload.step - the step proposed by the loop. + * @param payload.signal - the current turn's cancellation signal. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode waterfall + */ + 'agent/pre-step'(this: Scoped, payload: { + agent: Agent; + messages: UserMessage[]; + turn: number; + step: number; + signal: AbortSignal; + }, next: () => Promise): Promise; + /** + * Replace the frozen call configuration. `await next()` yields the config + * the machine would use (agent options on the first request, the logged + * header afterwards); return a replacement to switch. Model-visible + * content must use logged channels; this waterfall cannot mutate messages. + * @param payload.agent - the agent making the model call. + * @param payload.turn - the open turn number. + * @param payload.step - the step whose request this is. + * @param payload.signal - the current turn's explicit abort signal. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode waterfall + */ + 'agent/request'(this: Scoped, payload: { + agent: Agent; + turn: number; + step: number; + signal: AbortSignal; + }, next: () => Promise): Promise; + /** + * Handle one failed model-request attempt before the loop retries or closes + * its step. A listener returns `{ kind: 'retry' }` without calling `next()` + * when it owns recovery, or calls `next()` to delegate. The default + * `undefined` leaves the failure terminal. + * @param payload.agent - the agent whose request failed. + * @param payload.turn - the turn containing the failed request. + * @param payload.step - the step containing the failed request attempt. + * @param payload.provider - the provider selected for the failed request. + * @param payload.failure - serializable facts normalized at the final adapter boundary. + * @param payload.retryPolicy - the policy of the adapter registration that served the failed request. + * @param payload.signal - the turn abort signal. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode waterfall + */ + 'agent/request-error'(this: Scoped, payload: { + agent: Agent; + turn: number; + step: number; + provider: string; + failure: LlmFailure; + retryPolicy: ResolvedRetryPolicy | undefined; + signal: AbortSignal; + }, next: () => Promise): Promise; + /** + * The turn is about to close: the model owes no response (no live tool + * calls, no fresh steering). Awaited before the boundary commits — a + * listener that objects steers (`agent.steer(...)`) and the machine + * re-reads its inbox: fresh steering runs another step, none closes the + * turn. Data decides, so listener order cannot change the outcome. The + * inverse control (stop a tool loop early) is data too: a tool result + * carrying `concludesTurn` ends the turn at its step. The conclusion + * never short-circuits already-submitted next-step work: same-step + * `additionalContexts` or racing steering still runs, and the turn + * closes only when that inbox drains. + * @param payload.agent - the agent whose turn is at its stop boundary. + * @param payload.turn - the turn about to close. + * @param payload.signal - the current turn's explicit abort signal. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode serial + */ + 'agent/turn-stopping'(this: Scoped, payload: { + agent: Agent; + turn: number; + signal: AbortSignal; + }): Promise | void; + /** + * A step or turn errored. The machine reports a failure here even when + * the error has no in-turn position for a durable record. + * @param payload.agent - the agent whose turn errored. + * @param payload.turn - the turn in which the failure surfaced. + * @param payload.step - the step at which the failure surfaced. + * @param payload.error - the failure, verbatim. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @mode emit + */ + 'agent/error'(this: Scoped, payload: { + agent: Agent; + turn: number; + step: number; + error: unknown; + }): void; + } +} +//# sourceMappingURL=runtime-types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.js new file mode 100644 index 0000000..2f6b2fc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/runtime-types.js @@ -0,0 +1,8 @@ +/** + * Public agent types and live-runtime events. Durable transcript facts and + * turn/step boundaries remain `@deepseek-ai/dsh-session` events. + * + * @module @deepseek-ai/dsh-agent + */ +export {}; +//# sourceMappingURL=runtime-types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/types.d.ts new file mode 100644 index 0000000..368e1f5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/types.d.ts @@ -0,0 +1,25 @@ +/** + * Durable agent session-event vocabulary shared with type-only consumers. + * + * @module @deepseek-ai/dsh-agent/types + */ +import type { UserMessage } from '@deepseek-ai/dsh-llm/types'; +/** One of the two ordered pending-message lists owned by an agent. */ +export type InboxTarget = 'next-turn' | 'next-step'; +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * One normalized mutation of an agent's durable pending-message lists. + * Live dispatch precedes projection mutation, so synchronous observers may + * read the pre-splice inbox to recover the removed messages. + */ + 'agent/inbox/spliced': { + target: InboxTarget; + start: number; + removedCount?: number; + inserted: UserMessage[]; + outcome?: 'canceled'; + }; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/types.js new file mode 100644 index 0000000..3ecc23f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Durable agent session-event vocabulary shared with type-only consumers. + * + * @module @deepseek-ai/dsh-agent/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/package.json new file mode 100644 index 0000000..b6f1a14 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent/package.json @@ -0,0 +1,58 @@ +{ + "name": "@deepseek-ai/dsh-agent", + "description": "Agent interface, registry, initiator scope, and event vocabulary for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/agent" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-system-prompt b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-system-prompt new file mode 120000 index 0000000..943dd86 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-system-prompt @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..a2fcff1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.i18n.yaml new file mode 100644 index 0000000..826bd88 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/api/gateway/README.md +README.md: 7caf707c376bd3e2654fad1f0c01ac83e6faa44c +README.zh.md: b340df982ed1ca9b980fbcf60729d8124319ce6e diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.md new file mode 100644 index 0000000..7caf707 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.md @@ -0,0 +1,42 @@ +# @deepseek-ai/dsh-api-gateway + +English | [中文](README.zh.md) + +Two-sided Typert RPC endpoint for Host and Client Cordis environments. The Host entry provides `ctx.typertGateway`, while `@deepseek-ai/dsh-api-gateway/client` provides `ctx.remote`; both consume the same generated `InvocationDescriptor` contract and leave business selection to API Remotes and transport, request correlation, trust, and response envelopes to Connection. + +## Host service: `TypertGatewayService` (ctx key: `typertGateway`) + +`ctx.typertGateway.invoke()` resolves the current descriptor and Cordis Service for each call, validates exact named arguments, resolves registered object or Context identities, invokes the public business method, and validates its result. Business Services extend `TypertRemoteService` and mark methods with `@Remote` or `@RemoteScope` from [`dsh-typert-protocol`](../../typert/protocol/README.md); `bindTypertRemote()` remains available when another base class owns inheritance. + +Strict mode reads generated invocation descriptors from `ctx.typert.local`. Lookup parameters use the currently active resolver in `ctx.typert.lookups`: the business package registers the stable declaration and default policy, while Host composition can override resolution behavior with effect-scoped `configure()`; `@RemoteScope` resolves its receiver through a registered Host Context provider. SRC mode is a development fallback for endpoints that have never had a strict definition; it parses simple parameter names and accepts only JSON-safe values for non-lookup parameters. Withdrawing an observed strict definition fails instead of weakening validation. + +The Host entry registers a trusted-host interceptor on Connection's shared `/api` FetchHandler. Connection passes this composite handler through its HTTP bridge; the handler dispatches claimed endpoints to Gateway and unclaimed endpoints to API Proxy. Direct `invoke()` calls preserve business errors; `TypertGatewayError` distinguishes failures owned by dispatch, binding, providers, lookup, Context, arguments, and codecs. A resolver may use `TypertLookupFailure` to carry an existing RPC error, preserving its original error code for policy rejections such as cold-resume failures or ownership fences. + +A cancellation-aware Remote method declares `signal: AbortSignal` as its final Host parameter. The signal is descriptor metadata rather than a wire argument: Connection supplies it to the Gateway, and the Gateway injects it after decoded business parameters. SRC recognizes the reserved final name, while strict generation additionally requires the global `AbortSignal` type. + +## Client service: `ClientRemote` (ctx key: `remote`) + +`ctx.remote.$mount()` validates and registers a generated Host-for-Client contribution, then installs concrete direct and scoped methods for the calling Cordis fiber. Each namespace is a traced `remote.` child Service and unloads after its last method is withdrawn. Duplicate endpoints, namespace collisions, and descriptors without strict generated codecs fail before methods become callable. + +Each call validates positional inputs, constructs the descriptor's exact named `args`, and sends it through `ctx.connection.rpc.call('/api', endpoint, ...)`. Generated cancellation-aware methods accept a final optional `AbortSignal`; the Client combines it with the contribution mount lifetime before calling Connection. The returned value is validated before reaching application code. Withdrawing a contribution removes its descriptors and methods together, aborts in-flight calls, and makes retained method handles reject. + +`ctx.remote.$on()` subscribes to one forwarded Host event. Its legal keys are exactly the Host assembly's forwarding selection, and the listener type is the owning package's own Cordis `Events` declaration, so no second signature can drift from it. Each subscription belongs to the calling fiber and disappears with it. Delivery is one-way and follows registration order; a listener that throws is logged and isolated from the remaining listeners, which never affects the frame pump. `ctx.remote.$dispatch()` is the other half of that surface, and it is the carrier's: the Client half owning the Host frame sink hands each decoded frame over, and an event name nobody subscribes to is dropped, since the wire carries whatever the Host selected. A consumer subscribes and never calls it. + +Generated declaration merges provide the TypeScript API through the shared `TypertClientRemote` contract. The Client entry contains no Host Service or Host Cordis interface merge, and method lookup and invocation use ordinary objects and functions rather than a JavaScript Proxy. + +## Model Experience + +None, as the package dispatches application calls and registers no prompt, tool, or session event. + +#### KV Cache effect + +No direct effect; invoked business Services own any model-visible result. + +## Known Limitations and Deferred Work + +- The Connection adapter maps ordinary dispatch failures and business exceptions to the RPC `internal` code with empty details; lookup-policy errors carried by `TypertLookupFailure` are returned unchanged. Structured `TypertGatewayError` categories remain available only to same-process callers. +- SRC mode supports unique identifier parameters without destructuring, defaults, or rest parameters. It validates JSON safety rather than generated business types and never infers optional fields. +- Only strict generated contributions can mount on the Client face. SRC markers have no Client codec or type projection. +- The package dispatches unary methods only. Incremental Session data uses a separate named-stream protocol over the same Connection. +- Lookup resolvers are configured per key; an individual Remote parameter or endpoint cannot currently select a live-only policy under the same `agent`/`session` key. +- Forwarded events reach `$on` exactly as the Host emitted them: no payload projection or redaction, no Scope-bound subscription, and no replay after a reconnect. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.zh.md new file mode 100644 index 0000000..b340df9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/README.zh.md @@ -0,0 +1,42 @@ +# @deepseek-ai/dsh-api-gateway + +[English](README.md) | 中文 + +为 Host 与 Client 两侧的 Cordis 环境提供 Typert RPC endpoint。Host 入口提供 `ctx.typertGateway`,`@deepseek-ai/dsh-api-gateway/client` 则提供 `ctx.remote`;两者使用同一份生成的 `InvocationDescriptor` 约定,并将业务选择交给 API Remotes,将传输、请求关联、信任和响应封装交给 Connection。 + +## Host 服务:`TypertGatewayService`(ctx key:`typertGateway`) + +每次调用时,`ctx.typertGateway.invoke()` 都会解析当前的描述符和 Cordis 服务,校验具名参数是否完全匹配,解析已注册的对象或 Context 身份标识,调用公开的业务方法,并校验其结果。业务服务继承 [`dsh-typert-protocol`](../../typert/protocol/README.md) 的 `TypertRemoteService`,并用 `@Remote` 或 `@RemoteScope` 标记方法;已有其他基类时仍可改用 `bindTypertRemote()`。 + +严格模式从 `ctx.typert.local` 读取生成的调用描述符。查找参数使用 `ctx.typert.lookups` 中当前有效的 resolver:业务包注册稳定声明与默认策略,Host 组合可用 effect-scoped `configure()` 覆盖解析行为;`@RemoteScope` 则通过已注册的 Host Context 提供方解析其接收者。SRC 模式是开发阶段的回退路径,适用于从未具备严格定义的端点;它解析简单参数名,并且只允许非查找参数使用可安全表示为 JSON 的值。已观测到的严格定义一旦撤回,系统会直接报错,而不会降低校验强度。 + +Connection 可用时,Host 入口会在 Connection 共享的 `/api` FetchHandler 上注册 trusted-host interceptor。Connection 把这个复合 handler 交给 HTTP bridge;handler 将已认领 endpoint 分发给 Gateway,未认领 endpoint 则交给 API Proxy。直接调用 `invoke()` 会保留业务错误;`TypertGatewayError` 可区分分发、绑定、提供方、查找、Context、参数和编解码器各自负责的故障。resolver 可以用 `TypertLookupFailure` 携带既有 RPC error,使冷恢复失败或 ownership fence 等策略拒绝保持原错误码。 + +支持取消的 Remote 方法会把 `signal: AbortSignal` 声明为最后一个 Host 参数。signal 是 descriptor 元数据,而不是 wire 参数:Connection 将它提供给 Gateway,Gateway 则在已解码的业务参数之后注入它。SRC 识别这个保留的末位参数名,严格生成还要求它具有全局 `AbortSignal` 类型。 + +## Client 服务:`ClientRemote`(ctx key:`remote`) + +`ctx.remote.$mount()` 会校验并注册生成的 Host-for-Client 贡献项,然后为发起调用的 Cordis fiber 安装具体的直接方法和作用域方法。每个 namespace 都是可追踪的 `remote.` 子 Service,并在最后一个方法撤回后卸载。重复端点、命名空间冲突,以及缺少生成的严格编解码器的描述符,都会在方法可调用前报错。 + +每次调用都会校验位置参数,构造与描述符完全匹配的具名 `args`,再通过 `ctx.connection.rpc.call('/api', endpoint, ...)` 发送。生成的支持取消的方法接受最后一个可选 `AbortSignal`;Client 会在调用 Connection 前将它与贡献项的挂载生命周期合并。返回值经过校验后才会交给应用代码。撤回贡献项会同时移除其描述符和方法、中止正在进行的调用,并使外部仍持有的方法句柄在调用时返回拒绝。 + +`ctx.remote.$on()` 订阅一条被转发的 Host 事件。它的合法键恰好等于 Host 装配声明的转发选择,listener 类型就是事件所属包自己的 Cordis `Events` 声明,因此不存在会与之漂移的第二份签名。每个订阅归属发起调用的 fiber,并随该 fiber 一起消失。投递是单向的,并按注册顺序进行;抛错的 listener 会被记录并与其余 listener 隔离,绝不影响帧泵。`ctx.remote.$dispatch()` 是该面的另一半,且属于载体:持有 Host 帧 sink 的 Client 半把每个解码后的帧交进来,收到无人订阅的事件名即丢弃,因为 wire 上出现什么取决于 Host 的转发选择。消费方只订阅,绝不调用它。 + +生成的声明合并通过共享的 `TypertClientRemote` 约定提供 TypeScript API。Client 入口不包含 Host 服务或 Host Cordis 接口合并;方法查找和调用使用普通对象与函数,而不使用 JavaScript Proxy。 + +## 模型体验 + +无,因为该包分发应用调用,不注册任何提示词、工具或会话事件。 + +#### KV Cache 影响 + +无直接影响;被调用的业务服务负责产生任何模型可见结果。 + +## 已知限制与延期工作 + +- Connection 适配器将普通分发故障和业务异常映射为 RPC 的 `internal` 代码,且不附带详细信息;`TypertLookupFailure` 携带的 lookup 策略错误会原样返回。结构化的 `TypertGatewayError` 类别仅供同进程调用方使用。 +- SRC 模式仅支持名称唯一的标识符参数,不支持解构、默认值或剩余参数。它只校验值能否安全表示为 JSON,不校验生成的业务类型,也绝不会推断可选字段。 +- Client 侧只能挂载严格模式生成的贡献项。SRC 标记不具备 Client 编解码器或类型投影。 +- 该包只分发一元方法。增量会话数据通过同一个 Connection 上独立的具名流协议传输。 +- lookup resolver 按 key 配置;当前无法让单个 Remote 参数或 endpoint 在同一 `agent`/`session` key 下选择 live-only 策略。 +- 被转发的事件原样到达 `$on`:没有载荷投影或脱敏,不支持 Scope 化订阅,重连后也不重放。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/client.js new file mode 100644 index 0000000..9440fcd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/client.js @@ -0,0 +1,420 @@ +window.__ModuleLoader__.load({ + id: "@deepseek-ai/dsh-api-gateway", + factory: (require) => { + var module = { exports: {} }; + var exports = module.exports; + Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); + let _deepseek_ai_cordis = require("@deepseek-ai/cordis"); + //#region lib/types/client/index.js + /** + * Client projection of generated Typert Remote descriptors. Contributions + * install traced `remote.` services; no JavaScript Proxy + * participates in method lookup, invocation, or type exposure. + */ + /** Required Client services: the Typert registry and the existing Connection carrier. */ + const inject = ["typert", "connection"]; + /** + * Install the typed Client Remote service. + * @param ctx - Client Cordis root. + */ + function apply(ctx) { + new ClientRemoteService(ctx); + } + var ClientRemoteService = class extends _deepseek_ai_cordis.Service { + ownerCtx; + namespaces = /* @__PURE__ */ new Map(); + subscriptions = /* @__PURE__ */ new Map(); + mutations = Promise.resolve(); + constructor(ctx) { + super(ctx, "remote"); + this.ownerCtx = ctx; + ctx.effect(() => () => { + this.subscriptions.clear(); + }, "api-gateway.client.subscriptions"); + } + async $mount(contribution) { + const callerCtx = this.ctx; + const owned = callerCtx.effect(async () => { + const dispose = await this.enqueue(() => this.mountContribution(callerCtx, contribution)); + return () => this.enqueue(dispose); + }, `api-gateway.client.$mount(${JSON.stringify(contribution.package)})`); + await owned; + return async () => { + await owned(); + }; + } + $on(event, listener) { + const subscription = { listener }; + const owned = this.ctx.effect(() => { + const listeners = this.listeners(event); + listeners.push(subscription); + return () => { + const at = listeners.indexOf(subscription); + /* v8 ignore next -- listener */ + if (at >= 0) listeners.splice(at, 1); + }; + }, `api-gateway.client.$on(${JSON.stringify(event)})`); + return () => { + owned(); + }; + } + /** + * Deliver one forwarded event in registration order, isolating a listener + * that fails either synchronously or by rejecting a returned promise; see + * {@link TypertClientRemote.$dispatch} for the caller contract. + */ + $dispatch(event, args) { + const listeners = this.subscriptions.get(event); + if (listeners === void 0) return; + for (const { listener } of [...listeners]) { + const report = (error) => { + console.error(`client api: Remote event ${JSON.stringify(event)} listener threw:`, error); + }; + try { + const settled = listener(...args); + if (settled instanceof Promise) settled.catch(report); + } catch (error) { + report(error); + } + } + } + /** Subscriptions for one event name; empty arrays are retained, bounded by the Host's selection. */ + listeners(event) { + let listeners = this.subscriptions.get(event); + if (listeners === void 0) { + listeners = []; + this.subscriptions.set(event, listeners); + } + return listeners; + } + enqueue(operation) { + const result = this.mutations.then(operation, operation); + this.mutations = result.then(() => void 0, () => void 0); + return result; + } + async mountContribution(callerCtx, contribution) { + this.validateContribution(contribution); + const disposeRemote = callerCtx.typert.remotes.register(contribution); + const installed = []; + try { + for (const descriptor of contribution.descriptors) installed.push(await this.install(descriptor)); + } catch (error) { + for (const dispose of installed.reverse()) await dispose(); + await disposeRemote(); + throw error; + } + return async () => { + for (const dispose of installed.reverse()) await dispose(); + await disposeRemote(); + }; + } + validateContribution(contribution) { + const direct = /* @__PURE__ */ new Map(); + const scoped = /* @__PURE__ */ new Map(); + const add = (table, descriptor, kind) => { + const methods = table.get(descriptor.namespace) ?? /* @__PURE__ */ new Set(); + if (methods.has(descriptor.method)) throw new Error(`client api: contribution repeats ${kind} method ${endpointOf(descriptor)}`); + methods.add(descriptor.method); + table.set(descriptor.namespace, methods); + if ((this.namespaces.get(descriptor.namespace)?.service)?.has(kind, descriptor.method) === true) throw new Error(`client api: ${kind} method ${endpointOf(descriptor)} is already mounted`); + }; + for (const descriptor of contribution.descriptors) { + requireStrictDescriptor(descriptor); + if (descriptor.invocation.kind === "direct") add(direct, descriptor, "direct"); + if (scopedProjection(descriptor) !== void 0) add(scoped, descriptor, "scoped"); + } + const namespaces = new Set([...direct.keys(), ...scoped.keys()]); + for (const namespace of namespaces) { + const service = this.namespaces.get(namespace)?.service; + if (service === void 0) { + if (namespace in this) throw new Error(`client api: namespace ${JSON.stringify(namespace)} conflicts with the Remote service`); + const serviceKey = remoteServiceKey(namespace); + if (this.ownerCtx.reflect.props[serviceKey]?.type === "accessor" || this.ownerCtx.get(serviceKey) !== void 0) throw new Error(`client api: namespace ${JSON.stringify(namespace)} conflicts with an existing Remote namespace`); + } + for (const method of new Set([...direct.get(namespace) ?? [], ...scoped.get(namespace) ?? []])) if (service === void 0) RemoteNamespaceService.assertMethodAvailable(namespace, method); + else service.assertMethodAvailable(method); + } + } + async install(descriptor) { + const token = { + active: true, + abort: new AbortController() + }; + const installed = []; + try { + if (descriptor.invocation.kind === "direct") installed.push(await this.installDirect(descriptor, token)); + const projection = scopedProjection(descriptor); + if (projection !== void 0) installed.push(await this.installScoped(descriptor, projection, token)); + } catch (error) { + token.active = false; + token.abort.abort(); + for (const dispose of installed.reverse()) await dispose(); + throw error; + } + return async () => { + /* v8 ignore next -- Cordis effect disposers are idempotent and invoke this cleanup at most once. */ + if (!token.active) return; + token.active = false; + token.abort.abort(); + for (const dispose of installed.reverse()) await dispose(); + }; + } + async installDirect(descriptor, token) { + const namespace = await this.namespace(descriptor.namespace); + try { + namespace.service.installDirect(descriptor, token); + } catch (error) { + await this.disposeNamespace(descriptor.namespace, namespace); + throw error; + } + return async () => { + namespace.service.remove("direct", descriptor.method, token); + await this.disposeNamespace(descriptor.namespace, namespace); + }; + } + async installScoped(descriptor, projection, token) { + const namespace = await this.namespace(descriptor.namespace); + try { + namespace.service.installScoped(descriptor, projection, token); + } catch (error) { + await this.disposeNamespace(descriptor.namespace, namespace); + throw error; + } + return async () => { + namespace.service.remove("scoped", descriptor.method, token); + await this.disposeNamespace(descriptor.namespace, namespace); + }; + } + async namespace(name) { + let namespace = this.namespaces.get(name); + if (namespace !== void 0) return namespace; + let service; + const fiber = this.ownerCtx.plugin({ + name: remoteServiceKey(name), + apply: (ctx) => { + service = new RemoteNamespaceService(ctx, name, (direct, scoped, caller, args) => this.invokeMethod(direct, scoped, caller, args)); + } + }); + try { + await fiber; + } catch (error) { + await fiber.dispose(); + throw error; + } + /* v8 ignore next -- a settled namespace fiber synchronously constructs its Service. */ + if (service === void 0) throw new Error(`client api: namespace ${JSON.stringify(name)} did not start`); + namespace = { + service, + dispose: fiber.dispose + }; + this.namespaces.set(name, namespace); + return namespace; + } + async disposeNamespace(name, namespace) { + if (!namespace.service.empty || this.namespaces.get(name) !== namespace) return; + this.namespaces.delete(name); + await namespace.dispose(); + } + invokeMethod(direct, scoped, callerCtx, values) { + if (scoped !== void 0) { + const identity = this.ownerCtx.typert.contexts.getClient(scoped.projection.context)?.identity(callerCtx); + if (identity !== void 0) return this.invoke(scoped.descriptor, scoped.projection, scoped.token, callerCtx, values, { value: identity }); + } + if (direct !== void 0) return this.invoke(direct.descriptor, void 0, direct.token, callerCtx, values); + if (scoped !== void 0) return this.invoke(scoped.descriptor, scoped.projection, scoped.token, callerCtx, values); + throw new Error("client api: Remote method is no longer mounted"); + } + async invoke(descriptor, projection, token, callerCtx, values, boundIdentity) { + const endpoint = endpointOf(descriptor); + if (!token.active) return withdrawn(endpoint); + const expected = descriptor.parameters.length - (projection?.parameterIndex === void 0 ? 0 : 1); + const hasCallerSignal = descriptor.cancellation !== void 0 && values.length === expected + 1; + if (values.length !== expected && !hasCallerSignal) { + const contract = descriptor.cancellation === void 0 ? `${String(expected)} argument(s)` : `${String(expected)} business argument(s) plus an optional AbortSignal`; + throw new Error(`client api: ${endpoint} expected ${contract}, got ${String(values.length)}`); + } + const args = Object.create(null); + if (projection !== void 0) { + const binder = boundIdentity === void 0 ? this.ownerCtx.typert.contexts.getClient(projection.context) : void 0; + if (boundIdentity === void 0 && binder === void 0) throw new Error(`client api: ${endpoint} has no Client Context binder for ${JSON.stringify(projection.context)}`); + const identity = boundIdentity === void 0 ? binder?.identity(callerCtx) : boundIdentity.value; + if (identity === void 0) throw new Error(`client api: ${endpoint} requires a ${JSON.stringify(projection.context)} Context`); + args[projection.wire] = parse(projection.codec, identity, endpoint, projection.wire); + } + let valueIndex = 0; + descriptor.parameters.forEach((parameter, parameterIndex) => { + if (parameterIndex === projection?.parameterIndex) return; + const value = parse(parameter.codec, values[valueIndex], endpoint, parameter.wire); + if (value !== void 0) args[parameter.wire] = value; + valueIndex += 1; + }); + const connection = this.ownerCtx.get("connection"); + if (connection === void 0) throw new Error(`client api: ${endpoint} has no active Connection`); + const callerSignal = hasCallerSignal ? values[expected] : void 0; + const signal = callerSignal === void 0 ? token.abort.signal : AbortSignal.any([token.abort.signal, callerSignal]); + try { + const result = await connection.rpc.call("/api", endpoint, { args }, signal); + if (!mountActive(token)) return withdrawn(endpoint); + if (!result.ok) return { + ok: false, + error: result.error + }; + return { + ok: true, + value: parse(descriptor.result, result.value, endpoint, "result") + }; + } catch (error) { + return carrierFailure(endpoint, error); + } + } + }; + var RemoteNamespaceService = class RemoteNamespaceService extends _deepseek_ai_cordis.Service { + invokeRemote; + methods = /* @__PURE__ */ new Map(); + namespace; + static assertMethodAvailable(namespace, method) { + if (REMOTE_NAMESPACE_FIELDS.has(method) || method in RemoteNamespaceService.prototype) throw new Error(`client api: method ${JSON.stringify(`${namespace}/${method}`)} conflicts with its namespace service`); + } + constructor(ctx, name, invokeRemote) { + super(ctx, remoteServiceKey(name)); + this.invokeRemote = invokeRemote; + this.namespace = name; + } + assertMethodAvailable(method) { + RemoteNamespaceService.assertMethodAvailable(this.namespace, method); + if (method in this && !this.methods.has(method)) throw new Error(`client api: method ${JSON.stringify(`${this.namespace}/${method}`)} conflicts with its namespace service`); + } + get empty() { + return this.methods.size === 0; + } + has(kind, method) { + return this.methods.get(method)?.[kind] !== void 0; + } + installDirect(descriptor, token) { + this.install(descriptor.method, "direct", { + descriptor, + token + }); + } + installScoped(descriptor, projection, token) { + this.install(descriptor.method, "scoped", { + descriptor, + projection, + token + }); + } + install(method, kind, value) { + this.assertMethodAvailable(method); + let record = this.methods.get(method); + const fresh = record === void 0; + record ??= {}; + if (fresh) { + Object.defineProperty(this, method, { + configurable: true, + enumerable: true, + get: function() { + const callerCtx = this.ctx; + const current = this.methods.get(method); + const direct = current?.direct; + const scoped = current?.scoped; + return (...args) => { + return this.invokeRemote(direct, scoped, callerCtx, args); + }; + } + }); + this.methods.set(method, record); + } + if (kind === "direct") record.direct = value; + else record.scoped = value; + } + remove(kind, method, token) { + const record = this.methods.get(method); + const current = record?.[kind]; + /* v8 ignore next -- duplicate live variants are rejected before installation, so no newer token can replace this one. */ + if (record === void 0 || current?.token !== token) return; + if (kind === "direct") delete record.direct; + else delete record.scoped; + if (record.direct !== void 0 || record.scoped !== void 0) return; + this.methods.delete(method); + Reflect.deleteProperty(this, method); + } + }; + const REMOTE_NAMESPACE_FIELDS = new Set([ + "ctx", + "empty", + "invokeRemote", + "methods", + "name", + "namespace" + ]); + function remoteServiceKey(namespace) { + return `remote.${namespace}`; + } + function endpointOf(descriptor) { + return `${descriptor.namespace}/${descriptor.method}`; + } + function mountActive(token) { + return token.active; + } + function scopedProjection(descriptor) { + if (descriptor.invocation.kind === "context") return { + context: descriptor.invocation.context, + wire: descriptor.invocation.wire, + codec: descriptor.invocation.codec + }; + if (descriptor.scope === void 0) return void 0; + const lookupParameters = descriptor.parameters.map((parameter, index) => ({ + parameter, + index + })).filter((candidate) => candidate.parameter.source === "lookup"); + const selected = lookupParameters.length === 1 ? lookupParameters[0] : void 0; + if (selected === void 0 || selected.parameter.wire !== descriptor.scope.wire || selected.parameter.lookup !== descriptor.scope.context) throw new Error(`client api: generated Remote ${endpointOf(descriptor)} scope must select its only lookup parameter`); + return { + context: descriptor.scope.context, + wire: descriptor.scope.wire, + codec: selected.parameter.codec, + parameterIndex: selected.index + }; + } + function requireStrictDescriptor(descriptor) { + const endpoint = endpointOf(descriptor); + requireStrictCodec(descriptor.result, endpoint, "result"); + for (const parameter of descriptor.parameters) requireStrictCodec(parameter.codec, endpoint, parameter.wire); + if (descriptor.invocation.kind === "context") requireStrictCodec(descriptor.invocation.codec, endpoint, descriptor.invocation.wire); + } + function requireStrictCodec(codec, endpoint, field) { + if (codec.mode !== "strict") throw new Error(`client api: generated Remote ${endpoint} field ${JSON.stringify(field)} has no strict codec`); + } + function parse(codec, value, endpoint, field) { + if (codec.mode !== "strict") throw new Error(`client api: generated Remote ${endpoint} field ${JSON.stringify(field)} has no strict codec`); + try { + return codec.schema.parse(value); + } catch (cause) { + throw new Error(`client api: ${endpoint} rejected ${JSON.stringify(field)}`, { cause }); + } + } + /** The namespace retired before or during the call, so no request outcome exists. */ + function withdrawn(endpoint) { + return internalFailure(`client api: Remote method ${endpoint} is no longer mounted`); + } + function carrierFailure(endpoint, error) { + return internalFailure(`client api: ${endpoint} failed: ${error instanceof Error ? error.message : String(error)}`); + } + function internalFailure(message) { + return { + ok: false, + error: { + code: "internal", + message, + details: {} + } + }; + } + //#endregion + exports.apply = apply; + exports.inject = inject; + return module.exports; + } +}); + +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js new file mode 100644 index 0000000..46d091b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js @@ -0,0 +1,396 @@ +import { Service, symbols } from "@deepseek-ai/cordis"; +import { TypertLookupFailure, remoteMethods } from "@deepseek-ai/dsh-typert-protocol"; +//#region lib/types/index.js +/** +* Live Typert Remote dispatch over Cordis Services and registered providers. +* Transport, request correlation, and response envelopes belong to Connection. +* @module @deepseek-ai/dsh-api-gateway +*/ +const NEVER_ABORTED_SIGNAL = new AbortController().signal; +/** Dispatch failure produced outside the invoked business method. */ +var TypertGatewayError = class extends Error { + /** Machine-readable failure category. */ + code; + /** Canonical `/` endpoint. */ + endpoint; + /** Affected wire field when the failure is field-specific. */ + field; + /** + * Construct a Gateway failure without embedding boundary values in its message. + * @param code - stable failure category. + * @param endpoint - canonical Remote endpoint. + * @param message - correction-oriented diagnostic without sensitive values. + * @param options - optional field and contained cause. + */ + constructor(code, endpoint, message, options = {}) { + super(`typert gateway: ${endpoint}: ${message}`, options.cause === void 0 ? void 0 : { cause: options.cause }); + this.name = "TypertGatewayError"; + this.code = code; + this.endpoint = endpoint; + this.field = options.field; + } +}; +/** Business invocation lost its carrier cancellation race. */ +var RemoteInvocationCancelled = class extends Error { + /** + * @param endpoint - canonical Remote endpoint. + * @param cause - business rejection observed after carrier cancellation. + */ + constructor(endpoint, cause) { + super(`Remote invocation "${endpoint}" was aborted`, { cause }); + this.name = "RemoteInvocationCancelled"; + } +}; +/** +* Resolve strict generated definitions or conservative SRC markers against +* current Cordis Services and Typert providers. +* @typert service typertGateway +*/ +var TypertGatewayService = class extends Service { + static inject = ["typert"]; + srcClaims; + /** + * Register the Gateway against the active Typert registry. + * @param ctx - owning Host Context with Typert registry access. + */ + constructor(ctx) { + super(ctx, "typertGateway"); + ctx.on("internal/service", () => { + this.srcClaims = void 0; + }); + ctx.inject(["connection"], (connectionCtx) => { + connectionCtx.connection.rpc.intercept("/api", (endpoint) => this.claimsEndpoint(endpoint), (endpoint, payload, signal) => this.dispatchRpc(endpoint, payload, signal), { authority: "trusted-host" }); + }); + } + claimsEndpoint(endpoint) { + const segments = endpoint.split("/"); + if (segments.length !== 2 || segments[0] === "" || segments[1] === "") return false; + if (this.ctx.typert.local.get(endpoint) !== void 0 || this.ctx.typert.local.hasSeen(endpoint)) return true; + this.srcClaims ??= this.collectSrcClaims(); + return this.srcClaims.has(endpoint); + } + collectSrcClaims() { + const claims = /* @__PURE__ */ new Set(); + for (const [serviceKey, definition] of Object.entries(this.ctx.reflect.props)) { + if (definition.type !== "service") continue; + const receiver = this.ctx.get(serviceKey); + if (!isObject(receiver)) continue; + const original = originalOf(receiver); + const binding = Reflect.get(original, "typertRemote"); + if (!isObject(binding) || typeof Reflect.get(binding, "namespace") !== "string") continue; + const namespace = Reflect.get(binding, "namespace"); + for (const candidate of remoteMethods(original)) claims.add(endpointOf(namespace, candidate.exportName ?? candidate.method)); + } + return claims; + } + /** + * Invoke one live Remote method through strict generated reflection or SRC markers. + * @param request - decoded endpoint and exact named wire arguments. + * @returns the validated business result. + * @throws {@link TypertGatewayError} for dispatch, provider, or boundary failures; lookup-policy and business errors retain identity. + */ + async invoke(request) { + const endpoint = endpointOf(request.namespace, request.method); + const descriptor = this.resolveDescriptor(request.namespace, request.method, endpoint); + assertExactArguments(request.args, descriptor, endpoint); + const receiver = (await this.resolveReceiverContext(descriptor, request.args, endpoint)).get(descriptor.service); + if (!isObject(receiver)) throw new TypertGatewayError("service-unavailable", endpoint, `active Service ${JSON.stringify(descriptor.service)} is unavailable`); + validateBinding(receiver, descriptor.service, descriptor.namespace, endpoint); + const args = await Promise.all(descriptor.parameters.map((parameter) => this.resolveParameter(parameter, request.args, endpoint))); + if (descriptor.cancellation !== void 0) args.push(request.signal ?? NEVER_ABORTED_SIGNAL); + const implementation = descriptor.implementation ?? descriptor.method; + const method = Reflect.get(receiver, implementation); + if (typeof method !== "function") throw new TypertGatewayError("method-unavailable", endpoint, `active Service ${JSON.stringify(descriptor.service)} has no callable method ${JSON.stringify(implementation)}`); + let result; + try { + result = await Reflect.apply(method, receiver, args); + } catch (error) { + if (request.signal?.aborted === true) throw new RemoteInvocationCancelled(endpoint, error); + throw error; + } + if (result === void 0 && descriptor.result.mode !== "strict") return result; + return decode(descriptor.result, result, "result-invalid", endpoint, "result"); + } + async dispatchRpc(endpoint, payload, signal) { + return this.invokeRpc(endpoint, payload, signal); + } + async invokeRpc(endpoint, payload, signal) { + try { + const segments = endpoint.split("/"); + if (segments.length !== 2 || segments[0] === "" || segments[1] === "") throw new Error(`invalid Remote endpoint ${JSON.stringify(endpoint)}`); + const [namespace, method] = segments; + if (!isObject(payload) || !isPlainObject(payload) || Reflect.ownKeys(payload).length !== 1 || !Object.hasOwn(payload, "args") || !isObject(payload.args) || !isPlainObject(payload.args)) throw new Error("Remote payload must contain exactly one plain-object args field"); + return { + ok: true, + value: await this.invoke({ + namespace, + method, + args: payload.args, + signal + }) + }; + } catch (error) { + return rpcFailure(error); + } + } + resolveDescriptor(namespace, method, endpoint) { + const strict = this.ctx.typert.local.get(endpoint); + if (strict !== void 0) return strict; + if (this.ctx.typert.local.hasSeen(endpoint)) throw new TypertGatewayError("definition-unavailable", endpoint, "its strict definition was withdrawn and SRC fallback is forbidden"); + return this.resolveSrcDescriptor(namespace, method, endpoint); + } + resolveSrcDescriptor(namespace, method, endpoint) { + const candidates = []; + for (const [serviceKey, definition] of Object.entries(this.ctx.reflect.props)) { + if (definition.type !== "service") continue; + const receiver = this.ctx.get(serviceKey); + if (!isObject(receiver)) continue; + const original = originalOf(receiver); + const value = Reflect.get(original, "typertRemote"); + if (value === void 0) continue; + const binding = readBinding(value, original, serviceKey, endpoint); + if (binding.namespace !== namespace) continue; + const marker = remoteMethods(original).find((candidate) => (candidate.exportName ?? candidate.method) === method); + if (marker === void 0) continue; + candidates.push(this.srcDescriptor(binding, marker, method, endpoint)); + } + if (candidates.length === 0) throw new TypertGatewayError("invocation-unavailable", endpoint, "no active Remote method exports this endpoint"); + if (candidates.length > 1) throw new TypertGatewayError("ambiguous-endpoint", endpoint, `multiple active Services export this endpoint: ${candidates.map((candidate) => candidate.service).sort().join(", ")}`); + return candidates[0]; + } + srcDescriptor(binding, marker, method, endpoint) { + const names = methodParameterNames(binding.service, marker.method, endpoint); + const signalIndex = names.indexOf("signal"); + if (signalIndex >= 0 && signalIndex !== names.length - 1) throw new TypertGatewayError("signature-invalid", endpoint, "SRC cancellation parameter signal must be the final parameter", { field: "signal" }); + const cancellation = signalIndex >= 0 ? { parameter: "signal" } : void 0; + const businessNames = cancellation === void 0 ? names : names.slice(0, -1); + const parameters = []; + const wires = /* @__PURE__ */ new Set(); + for (const name of businessNames) { + const matches = this.ctx.typert.lookups.definitions().filter((definition) => definition.parameter === name); + if (matches.length > 1) throw new TypertGatewayError("signature-invalid", endpoint, `parameter ${JSON.stringify(name)} matches multiple lookup providers`, { field: name }); + const match = matches[0]; + const parameter = match === void 0 ? { + name, + wire: name, + source: "json", + codec: { mode: "src-json" } + } : { + name, + wire: match.wire, + source: "lookup", + lookup: match.key, + codec: { mode: "src-json" } + }; + if (wires.has(parameter.wire)) throw new TypertGatewayError("signature-invalid", endpoint, `multiple parameters use wire field ${JSON.stringify(parameter.wire)}`, { field: parameter.wire }); + wires.add(parameter.wire); + parameters.push(parameter); + } + let receiver = { kind: "direct" }; + if (marker.invocation.kind === "context") { + const provider = this.ctx.typert.contexts.getHost(marker.invocation.context); + if (provider === void 0) throw new TypertGatewayError("context-unavailable", endpoint, `Context provider ${JSON.stringify(marker.invocation.context)} is unavailable`); + if (wires.has(provider.wire)) throw new TypertGatewayError("signature-invalid", endpoint, `Context identity conflicts with wire field ${JSON.stringify(provider.wire)}`, { field: provider.wire }); + receiver = { + kind: "context", + context: marker.invocation.context, + wire: provider.wire, + codec: { mode: "src-json" } + }; + } + return { + id: `src:${binding.serviceKey}#${endpoint}`, + service: binding.serviceKey, + namespace: binding.namespace, + method, + ...marker.method === method ? {} : { implementation: marker.method }, + invocation: receiver, + parameters, + ...cancellation === void 0 ? {} : { cancellation }, + result: { mode: "src-json" } + }; + } + async resolveReceiverContext(descriptor, args, endpoint) { + if (descriptor.invocation.kind === "direct") return this.ctx; + const invocation = descriptor.invocation; + const provider = this.ctx.typert.contexts.getHost(invocation.context); + if (provider === void 0) throw new TypertGatewayError("context-unavailable", endpoint, `Context provider ${JSON.stringify(invocation.context)} is unavailable`); + if (provider.wire !== invocation.wire || invocation.codec.mode === "strict" && provider.wireTypeSymbol !== invocation.codec.typeSymbol) throw new TypertGatewayError("provider-mismatch", endpoint, `Context provider ${JSON.stringify(invocation.context)} does not match its strict definition`, { field: invocation.wire }); + const identity = decode(invocation.codec, args[invocation.wire], "input-invalid", endpoint, invocation.wire); + let context; + try { + context = await provider.resolve(identity); + } catch (cause) { + if (cause instanceof TypertLookupFailure) throw cause; + throw new TypertGatewayError("context-failed", endpoint, `Context provider ${JSON.stringify(invocation.context)} failed`, { + cause, + field: invocation.wire + }); + } + if (context === void 0) throw new TypertGatewayError("context-not-found", endpoint, `Context provider ${JSON.stringify(invocation.context)} did not resolve the requested identity`, { field: invocation.wire }); + return context; + } + async resolveParameter(parameter, args, endpoint) { + if (!Object.hasOwn(args, parameter.wire)) return void 0; + const value = decode(parameter.codec, args[parameter.wire], "input-invalid", endpoint, parameter.wire); + if (parameter.source === "json") return value; + const key = parameter.lookup; + /* v8 ignore next -- registry validation rejects strict descriptors without a key, and SRC derivation always supplies one. */ + if (key === void 0) throw new TypertGatewayError("lookup-unavailable", endpoint, `lookup parameter ${JSON.stringify(parameter.name)} has no provider key`, { field: parameter.wire }); + const provider = this.ctx.typert.lookups.get(key); + if (provider === void 0) throw new TypertGatewayError("lookup-unavailable", endpoint, `lookup provider ${JSON.stringify(key)} is unavailable`, { field: parameter.wire }); + if (provider.wire !== parameter.wire || parameter.codec.mode === "strict" && provider.wireTypeSymbol !== parameter.codec.typeSymbol) throw new TypertGatewayError("provider-mismatch", endpoint, `lookup provider ${JSON.stringify(key)} does not match its strict definition`, { field: parameter.wire }); + let resolved; + try { + resolved = await provider.resolve(value); + } catch (cause) { + if (cause instanceof TypertLookupFailure) throw cause; + throw new TypertGatewayError("lookup-failed", endpoint, `lookup provider ${JSON.stringify(key)} failed`, { + cause, + field: parameter.wire + }); + } + if (resolved === void 0) throw new TypertGatewayError("lookup-not-found", endpoint, `lookup provider ${JSON.stringify(key)} did not resolve the requested identity`, { field: parameter.wire }); + return resolved; + } +}; +function rpcFailure(error) { + if (error instanceof RemoteInvocationCancelled) return { + ok: false, + error: { + code: "cancelled", + message: error.message, + details: {} + } + }; + if (error instanceof TypertLookupFailure) return { + ok: false, + error: error.failure + }; + return { + ok: false, + error: { + code: "internal", + message: error instanceof Error ? error.message : String(error), + details: {} + } + }; +} +function endpointOf(namespace, method) { + return `${namespace}/${method}`; +} +function validateBinding(receiver, serviceKey, namespace, endpoint) { + const original = originalOf(receiver); + const value = Reflect.get(original, "typertRemote"); + if (value === void 0) throw new TypertGatewayError("binding-invalid", endpoint, `Service ${JSON.stringify(serviceKey)} has no visible typertRemote binding`); + return { + binding: readBinding(value, original, serviceKey, endpoint, namespace), + original + }; +} +function readBinding(value, original, serviceKey, endpoint, namespace) { + if (!isObject(value) || Reflect.get(value, "service") !== original || Reflect.get(value, "serviceKey") !== serviceKey || typeof Reflect.get(value, "namespace") !== "string" || namespace !== void 0 && Reflect.get(value, "namespace") !== namespace) throw new TypertGatewayError("binding-invalid", endpoint, `Service ${JSON.stringify(serviceKey)} has an inconsistent typertRemote binding`); + return value; +} +function originalOf(receiver) { + const original = Reflect.get(receiver, symbols.original); + return isObject(original) ? original : receiver; +} +function methodParameterNames(service, method, endpoint) { + let prototype = Object.getPrototypeOf(service); + let implementation; + while (prototype !== null) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, method); + if (descriptor !== void 0) { + if ("value" in descriptor && typeof descriptor.value === "function") implementation = descriptor.value; + break; + } + prototype = Object.getPrototypeOf(prototype); + } + if (implementation === void 0) throw new TypertGatewayError("method-unavailable", endpoint, `Remote marker has no prototype method ${JSON.stringify(method)}`); + const source = Function.prototype.toString.call(implementation); + const open = source.indexOf("("); + const close = source.indexOf(")", open + 1); + /* v8 ignore next -- standard public class-method syntax always contains a parenthesized parameter list. */ + if (open < 0 || close < 0) return invalidSignature(endpoint, method); + const body = source.slice(open + 1, close).trim(); + if (body.length === 0) return []; + const parts = body.split(",").map((part) => part.trim()); + const names = /* @__PURE__ */ new Set(); + for (const part of parts) { + if (!/^[$A-Z_a-z][$\w]*$/u.test(part) || names.has(part)) return invalidSignature(endpoint, method); + names.add(part); + } + return [...names]; +} +function invalidSignature(endpoint, method) { + throw new TypertGatewayError("signature-invalid", endpoint, `SRC method ${JSON.stringify(method)} must use unique identifier parameters without destructuring, defaults, or rest`); +} +function assertExactArguments(args, descriptor, endpoint) { + if (!isPlainObject(args)) throw new TypertGatewayError("arguments-invalid", endpoint, "args must be a plain object"); + const expected = new Set(descriptor.parameters.map((parameter) => parameter.wire)); + if (descriptor.invocation.kind === "context") expected.add(descriptor.invocation.wire); + const extra = Reflect.ownKeys(args).filter((key) => typeof key !== "string" || !expected.has(key)); + const acceptsMissing = new Set(descriptor.parameters.filter((parameter) => parameter.source === "json" && (parameter.acceptsUndefined === true || parameter.codec.mode === "src-json")).map((parameter) => parameter.wire)); + const missing = [...expected].filter((key) => !Object.hasOwn(args, key) && !acceptsMissing.has(key)); + if (extra.length === 0 && missing.length === 0) return; + const clauses = []; + if (missing.length > 0) clauses.push(`missing ${missing.map((key) => JSON.stringify(key)).join(", ")}`); + if (extra.length > 0) clauses.push(`unexpected ${extra.map((key) => JSON.stringify(String(key))).join(", ")}`); + throw new TypertGatewayError("arguments-invalid", endpoint, `args fields do not match the descriptor: ${clauses.join("; ")}`); +} +function decode(codec, value, code, endpoint, field) { + try { + if (codec.mode === "strict") { + value = codec.schema.parse(value); + if (value === void 0) return value; + } + assertJsonValue(value, /* @__PURE__ */ new Set()); + return value; + } catch (cause) { + throw new TypertGatewayError(code, endpoint, code === "input-invalid" ? `wire field ${JSON.stringify(field)} failed boundary validation` : "business result failed boundary validation", { + cause, + field + }); + } +} +function assertJsonValue(value, ancestors) { + if (value === null || typeof value === "string" || typeof value === "boolean") return; + if (typeof value === "number") { + if (Number.isFinite(value)) return; + throw new TypeError("non-finite number is not JSON-safe"); + } + if (!isObject(value)) throw new TypeError(`${typeof value} is not JSON-safe`); + if (ancestors.has(value)) throw new TypeError("cyclic value is not JSON-safe"); + ancestors.add(value); + try { + if (Array.isArray(value)) { + if (Object.getOwnPropertySymbols(value).length > 0 || Object.keys(value).length !== value.length) throw new TypeError("sparse or decorated array is not JSON-safe"); + for (let index = 0; index < value.length; index += 1) { + if (!Object.hasOwn(value, index)) throw new TypeError("sparse array is not JSON-safe"); + assertJsonValue(value[index], ancestors); + } + return; + } + if (!isPlainObject(value)) throw new TypeError("non-plain object is not JSON-safe"); + if (Object.getOwnPropertySymbols(value).length > 0) throw new TypeError("symbol property is not JSON-safe"); + for (const key of Reflect.ownKeys(value)) { + const descriptor = Object.getOwnPropertyDescriptor(value, key); + /* v8 ignore next -- ownKeys() just returned this key; only a hostile same-process Proxy can delete it between operations. */ + if (descriptor === void 0 || !descriptor.enumerable || !("value" in descriptor)) throw new TypeError("non-data property is not JSON-safe"); + assertJsonValue(descriptor.value, ancestors); + } + } finally { + ancestors.delete(value); + } +} +function isPlainObject(value) { + if (Array.isArray(value)) return false; + const prototype = Object.getPrototypeOf(value); + return prototype === null || prototype === Object.prototype; +} +function isObject(value) { + return typeof value === "object" && value !== null || typeof value === "function"; +} +//#endregion +export { TypertGatewayError, TypertGatewayService, TypertGatewayService as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/invariant.js new file mode 100644 index 0000000..842ac5d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/invariant.js @@ -0,0 +1,24 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-api-gateway`. +* @module @deepseek-ai/dsh-api-gateway/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-api-gateway"; +/** Cordis companion plugin name. */ +const name = "api-gateway-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: Host calls re-read authoritative Cordis and Typert +* state, while Client methods, descriptors, and `$on` subscriptions mutate in +* one owned effect. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.d.ts new file mode 100644 index 0000000..8b61c7a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.d.ts @@ -0,0 +1,23 @@ +/** + * Client projection of generated Typert Remote descriptors. Contributions + * install traced `remote.` services; no JavaScript Proxy + * participates in method lookup, invocation, or type exposure. + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { TypertClientRemote } from '@deepseek-ai/dsh-typert-protocol'; +/** Typed Remote service augmented by generated direct namespaces. */ +export type ClientRemote = TypertClientRemote; +declare module '@deepseek-ai/cordis' { + interface Context { + /** Generated Remote namespaces selected by the Client assembly. */ + remote: ClientRemote; + } +} +/** Required Client services: the Typert registry and the existing Connection carrier. */ +export declare const inject: string[]; +/** + * Install the typed Client Remote service. + * @param ctx - Client Cordis root. + */ +export declare function apply(ctx: Context): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.js new file mode 100644 index 0000000..334b5a9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.js @@ -0,0 +1,467 @@ +/** + * Client projection of generated Typert Remote descriptors. Contributions + * install traced `remote.` services; no JavaScript Proxy + * participates in method lookup, invocation, or type exposure. + */ +import { Service } from '@deepseek-ai/cordis'; +/** Required Client services: the Typert registry and the existing Connection carrier. */ +export const inject = ['typert', 'connection']; +/** + * Install the typed Client Remote service. + * @param ctx - Client Cordis root. + */ +export function apply(ctx) { + new ClientRemoteService(ctx); +} +class ClientRemoteService extends Service { + ownerCtx; + namespaces = new Map(); + subscriptions = new Map(); + mutations = Promise.resolve(); + constructor(ctx) { + super(ctx, 'remote'); + this.ownerCtx = ctx; + ctx.effect(() => () => { this.subscriptions.clear(); }, 'api-gateway.client.subscriptions'); + } + async $mount(contribution) { + const callerCtx = this.ctx; + const owned = callerCtx.effect(async () => { + const dispose = await this.enqueue(() => this.mountContribution(callerCtx, contribution)); + return () => this.enqueue(dispose); + }, `api-gateway.client.$mount(${JSON.stringify(contribution.package)})`); + await owned; + return async () => { await owned(); }; + } + $on(event, listener) { + // The table is keyed by the runtime event name, so the argument list this + // signature pins per event cannot survive in it; `$deliver` restores it + // from the frame the Host emitted for that same name. + const subscription = { listener }; + const owned = this.ctx.effect(() => { + const listeners = this.listeners(event); + listeners.push(subscription); + return () => { + const at = listeners.indexOf(subscription); + /* v8 ignore next -- listener */ + if (at >= 0) + listeners.splice(at, 1); + }; + }, `api-gateway.client.$on(${JSON.stringify(event)})`); + return () => { void owned(); }; + } + /** + * Deliver one forwarded event in registration order, isolating a listener + * that fails either synchronously or by rejecting a returned promise; see + * {@link TypertClientRemote.$dispatch} for the caller contract. + */ + $dispatch(event, args) { + const listeners = this.subscriptions.get(event); + if (listeners === undefined) + return; + // Snapshot: a listener may subscribe or dispose during delivery, and this + // round's recipients are the ones registered when the frame arrived. + for (const { listener } of [...listeners]) { + const report = (error) => { + console.error(`client api: Remote event ${JSON.stringify(event)} listener threw:`, error); + }; + try { + /* oxlint-disable-next-line typescript/no-confusing-void-expression -- + * The declared return is void, so nobody awaits an async listener; the + * runtime value is still a promise, and reading it is the only way to + * keep its rejection inside this containment instead of surfacing as an + * unhandled one. */ + const settled = listener(...args); + if (settled instanceof Promise) + settled.catch(report); + } + catch (error) { + report(error); + } + } + } + /** Subscriptions for one event name; empty arrays are retained, bounded by the Host's selection. */ + listeners(event) { + let listeners = this.subscriptions.get(event); + if (listeners === undefined) { + listeners = []; + this.subscriptions.set(event, listeners); + } + return listeners; + } + enqueue(operation) { + const result = this.mutations.then(operation, operation); + this.mutations = result.then(() => undefined, () => undefined); + return result; + } + async mountContribution(callerCtx, contribution) { + this.validateContribution(contribution); + const disposeRemote = callerCtx.typert.remotes.register(contribution); + const installed = []; + try { + for (const descriptor of contribution.descriptors) + installed.push(await this.install(descriptor)); + } + catch (error) { + for (const dispose of installed.reverse()) + await dispose(); + await disposeRemote(); + throw error; + } + return async () => { + for (const dispose of installed.reverse()) + await dispose(); + await disposeRemote(); + }; + } + validateContribution(contribution) { + const direct = new Map(); + const scoped = new Map(); + const add = (table, descriptor, kind) => { + const methods = table.get(descriptor.namespace) ?? new Set(); + if (methods.has(descriptor.method)) { + throw new Error(`client api: contribution repeats ${kind} method ${endpointOf(descriptor)}`); + } + methods.add(descriptor.method); + table.set(descriptor.namespace, methods); + const namespace = this.namespaces.get(descriptor.namespace)?.service; + if (namespace?.has(kind, descriptor.method) === true) { + throw new Error(`client api: ${kind} method ${endpointOf(descriptor)} is already mounted`); + } + }; + for (const descriptor of contribution.descriptors) { + requireStrictDescriptor(descriptor); + if (descriptor.invocation.kind === 'direct') + add(direct, descriptor, 'direct'); + if (scopedProjection(descriptor) !== undefined) + add(scoped, descriptor, 'scoped'); + } + const namespaces = new Set([...direct.keys(), ...scoped.keys()]); + for (const namespace of namespaces) { + const service = this.namespaces.get(namespace)?.service; + if (service === undefined) { + if (namespace in this) { + throw new Error(`client api: namespace ${JSON.stringify(namespace)} conflicts with the Remote service`); + } + const serviceKey = remoteServiceKey(namespace); + const property = this.ownerCtx.reflect.props[serviceKey]; + if (property?.type === 'accessor' || this.ownerCtx.get(serviceKey) !== undefined) { + throw new Error(`client api: namespace ${JSON.stringify(namespace)} conflicts with an existing Remote namespace`); + } + } + for (const method of new Set([...(direct.get(namespace) ?? []), ...(scoped.get(namespace) ?? [])])) { + if (service === undefined) + RemoteNamespaceService.assertMethodAvailable(namespace, method); + else + service.assertMethodAvailable(method); + } + } + } + async install(descriptor) { + const token = { active: true, abort: new AbortController() }; + const installed = []; + try { + if (descriptor.invocation.kind === 'direct') { + installed.push(await this.installDirect(descriptor, token)); + } + const projection = scopedProjection(descriptor); + if (projection !== undefined) + installed.push(await this.installScoped(descriptor, projection, token)); + } + catch (error) { + token.active = false; + token.abort.abort(); + for (const dispose of installed.reverse()) + await dispose(); + throw error; + } + return async () => { + /* v8 ignore next -- Cordis effect disposers are idempotent and invoke this cleanup at most once. */ + if (!token.active) + return; + token.active = false; + token.abort.abort(); + for (const dispose of installed.reverse()) + await dispose(); + }; + } + async installDirect(descriptor, token) { + const namespace = await this.namespace(descriptor.namespace); + try { + namespace.service.installDirect(descriptor, token); + } + catch (error) { + await this.disposeNamespace(descriptor.namespace, namespace); + throw error; + } + return async () => { + namespace.service.remove('direct', descriptor.method, token); + await this.disposeNamespace(descriptor.namespace, namespace); + }; + } + async installScoped(descriptor, projection, token) { + const namespace = await this.namespace(descriptor.namespace); + try { + namespace.service.installScoped(descriptor, projection, token); + } + catch (error) { + await this.disposeNamespace(descriptor.namespace, namespace); + throw error; + } + return async () => { + namespace.service.remove('scoped', descriptor.method, token); + await this.disposeNamespace(descriptor.namespace, namespace); + }; + } + async namespace(name) { + let namespace = this.namespaces.get(name); + if (namespace !== undefined) + return namespace; + let service; + const fiber = this.ownerCtx.plugin({ + name: remoteServiceKey(name), + apply: (ctx) => { + service = new RemoteNamespaceService(ctx, name, (direct, scoped, caller, args) => this.invokeMethod(direct, scoped, caller, args)); + }, + }); + try { + await fiber; + } + catch (error) { + await fiber.dispose(); + throw error; + } + /* v8 ignore next -- a settled namespace fiber synchronously constructs its Service. */ + if (service === undefined) + throw new Error(`client api: namespace ${JSON.stringify(name)} did not start`); + namespace = { service, dispose: fiber.dispose }; + this.namespaces.set(name, namespace); + return namespace; + } + async disposeNamespace(name, namespace) { + if (!namespace.service.empty || this.namespaces.get(name) !== namespace) + return; + this.namespaces.delete(name); + await namespace.dispose(); + } + invokeMethod(direct, scoped, callerCtx, values) { + if (scoped !== undefined) { + const binder = this.ownerCtx.typert.contexts.getClient(scoped.projection.context); + const identity = binder?.identity(callerCtx); + if (identity !== undefined) { + return this.invoke(scoped.descriptor, scoped.projection, scoped.token, callerCtx, values, { value: identity }); + } + } + if (direct !== undefined) { + return this.invoke(direct.descriptor, undefined, direct.token, callerCtx, values); + } + if (scoped !== undefined) { + return this.invoke(scoped.descriptor, scoped.projection, scoped.token, callerCtx, values); + } + throw new Error('client api: Remote method is no longer mounted'); + } + async invoke(descriptor, projection, token, callerCtx, values, boundIdentity) { + const endpoint = endpointOf(descriptor); + if (!token.active) + return withdrawn(endpoint); + const expected = descriptor.parameters.length - (projection?.parameterIndex === undefined ? 0 : 1); + const hasCallerSignal = descriptor.cancellation !== undefined && values.length === expected + 1; + if (values.length !== expected && !hasCallerSignal) { + const contract = descriptor.cancellation === undefined + ? `${String(expected)} argument(s)` + : `${String(expected)} business argument(s) plus an optional AbortSignal`; + throw new Error(`client api: ${endpoint} expected ${contract}, got ${String(values.length)}`); + } + const args = Object.create(null); + if (projection !== undefined) { + const binder = boundIdentity === undefined + ? this.ownerCtx.typert.contexts.getClient(projection.context) + : undefined; + if (boundIdentity === undefined && binder === undefined) { + throw new Error(`client api: ${endpoint} has no Client Context binder for ${JSON.stringify(projection.context)}`); + } + const identity = boundIdentity === undefined + ? binder?.identity(callerCtx) + : boundIdentity.value; + if (identity === undefined) { + throw new Error(`client api: ${endpoint} requires a ${JSON.stringify(projection.context)} Context`); + } + args[projection.wire] = parse(projection.codec, identity, endpoint, projection.wire); + } + let valueIndex = 0; + descriptor.parameters.forEach((parameter, parameterIndex) => { + if (parameterIndex === projection?.parameterIndex) + return; + const value = parse(parameter.codec, values[valueIndex], endpoint, parameter.wire); + if (value !== undefined) + args[parameter.wire] = value; + valueIndex += 1; + }); + const connection = this.ownerCtx.get('connection'); + if (connection === undefined) + throw new Error(`client api: ${endpoint} has no active Connection`); + const callerSignal = hasCallerSignal ? values[expected] : undefined; + const signal = callerSignal === undefined + ? token.abort.signal + : AbortSignal.any([token.abort.signal, callerSignal]); + try { + const result = await connection.rpc.call('/api', endpoint, { args }, signal); + if (!mountActive(token)) + return withdrawn(endpoint); + if (!result.ok) + return { ok: false, error: result.error }; + return { ok: true, value: parse(descriptor.result, result.value, endpoint, 'result') }; + } + catch (error) { + // Carrier throws (offline, abort, a rejected result payload) are outcomes + // of the call, not assembly faults, so they join the same error branch. + return carrierFailure(endpoint, error); + } + } +} +class RemoteNamespaceService extends Service { + invokeRemote; + methods = new Map(); + namespace; + static assertMethodAvailable(namespace, method) { + if (REMOTE_NAMESPACE_FIELDS.has(method) || method in RemoteNamespaceService.prototype) { + throw new Error(`client api: method ${JSON.stringify(`${namespace}/${method}`)} conflicts with its namespace service`); + } + } + constructor(ctx, name, invokeRemote) { + super(ctx, remoteServiceKey(name)); + this.invokeRemote = invokeRemote; + this.namespace = name; + } + assertMethodAvailable(method) { + RemoteNamespaceService.assertMethodAvailable(this.namespace, method); + if (method in this && !this.methods.has(method)) { + throw new Error(`client api: method ${JSON.stringify(`${this.namespace}/${method}`)} conflicts with its namespace service`); + } + } + get empty() { + return this.methods.size === 0; + } + has(kind, method) { + return this.methods.get(method)?.[kind] !== undefined; + } + installDirect(descriptor, token) { + this.install(descriptor.method, 'direct', { descriptor, token }); + } + installScoped(descriptor, projection, token) { + this.install(descriptor.method, 'scoped', { descriptor, projection, token }); + } + install(method, kind, value) { + this.assertMethodAvailable(method); + let record = this.methods.get(method); + const fresh = record === undefined; + record ??= {}; + if (fresh) { + Object.defineProperty(this, method, { + configurable: true, + enumerable: true, + get: function () { + const callerCtx = this.ctx; + const current = this.methods.get(method); + const direct = current?.direct; + const scoped = current?.scoped; + return (...args) => { + return this.invokeRemote(direct, scoped, callerCtx, args); + }; + }, + }); + this.methods.set(method, record); + } + if (kind === 'direct') + record.direct = value; + else + record.scoped = value; + } + remove(kind, method, token) { + const record = this.methods.get(method); + const current = record?.[kind]; + /* v8 ignore next -- duplicate live variants are rejected before installation, so no newer token can replace this one. */ + if (record === undefined || current?.token !== token) + return; + if (kind === 'direct') + delete record.direct; + else + delete record.scoped; + if (record.direct !== undefined || record.scoped !== undefined) + return; + this.methods.delete(method); + Reflect.deleteProperty(this, method); + } +} +const REMOTE_NAMESPACE_FIELDS = new Set(['ctx', 'empty', 'invokeRemote', 'methods', 'name', 'namespace']); +function remoteServiceKey(namespace) { + return `remote.${namespace}`; +} +function endpointOf(descriptor) { + return `${descriptor.namespace}/${descriptor.method}`; +} +function mountActive(token) { + return token.active; +} +function scopedProjection(descriptor) { + if (descriptor.invocation.kind === 'context') { + return { + context: descriptor.invocation.context, + wire: descriptor.invocation.wire, + codec: descriptor.invocation.codec, + }; + } + if (descriptor.scope === undefined) + return undefined; + const lookupParameters = descriptor.parameters + .map((parameter, index) => ({ parameter, index })) + .filter(candidate => candidate.parameter.source === 'lookup'); + const selected = lookupParameters.length === 1 ? lookupParameters[0] : undefined; + if (selected === undefined + || selected.parameter.wire !== descriptor.scope.wire + || selected.parameter.lookup !== descriptor.scope.context) { + throw new Error(`client api: generated Remote ${endpointOf(descriptor)} scope must select its only lookup parameter`); + } + return { + context: descriptor.scope.context, + wire: descriptor.scope.wire, + codec: selected.parameter.codec, + parameterIndex: selected.index, + }; +} +function requireStrictDescriptor(descriptor) { + const endpoint = endpointOf(descriptor); + requireStrictCodec(descriptor.result, endpoint, 'result'); + for (const parameter of descriptor.parameters) { + requireStrictCodec(parameter.codec, endpoint, parameter.wire); + } + if (descriptor.invocation.kind === 'context') { + requireStrictCodec(descriptor.invocation.codec, endpoint, descriptor.invocation.wire); + } +} +function requireStrictCodec(codec, endpoint, field) { + if (codec.mode !== 'strict') { + throw new Error(`client api: generated Remote ${endpoint} field ${JSON.stringify(field)} has no strict codec`); + } +} +function parse(codec, value, endpoint, field) { + if (codec.mode !== 'strict') { + throw new Error(`client api: generated Remote ${endpoint} field ${JSON.stringify(field)} has no strict codec`); + } + try { + return codec.schema.parse(value); + } + catch (cause) { + throw new Error(`client api: ${endpoint} rejected ${JSON.stringify(field)}`, { cause }); + } +} +/** The namespace retired before or during the call, so no request outcome exists. */ +function withdrawn(endpoint) { + return internalFailure(`client api: Remote method ${endpoint} is no longer mounted`); +} +function carrierFailure(endpoint, error) { + return internalFailure(`client api: ${endpoint} failed: ${error instanceof Error ? error.message : String(error)}`); +} +function internalFailure(message) { + return { ok: false, error: { code: 'internal', message, details: {} } }; +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.d.ts new file mode 100644 index 0000000..ff0ae63 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.d.ts @@ -0,0 +1,61 @@ +/** + * Live Typert Remote dispatch over Cordis Services and registered providers. + * Transport, request correlation, and response envelopes belong to Connection. + * @module @deepseek-ai/dsh-api-gateway + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { InvokeRemoteRequest, TypertGateway, TypertGatewayErrorCode } from './types.ts'; +export type { InvokeRemoteRequest, TypertGateway, TypertGatewayErrorCode, } from './types.ts'; +interface GatewayErrorOptions { + readonly cause?: unknown; + readonly field?: string; +} +/** Dispatch failure produced outside the invoked business method. */ +export declare class TypertGatewayError extends Error { + /** Machine-readable failure category. */ + readonly code: TypertGatewayErrorCode; + /** Canonical `/` endpoint. */ + readonly endpoint: string; + /** Affected wire field when the failure is field-specific. */ + readonly field: string | undefined; + /** + * Construct a Gateway failure without embedding boundary values in its message. + * @param code - stable failure category. + * @param endpoint - canonical Remote endpoint. + * @param message - correction-oriented diagnostic without sensitive values. + * @param options - optional field and contained cause. + */ + constructor(code: TypertGatewayErrorCode, endpoint: string, message: string, options?: GatewayErrorOptions); +} +/** + * Resolve strict generated definitions or conservative SRC markers against + * current Cordis Services and Typert providers. + * @typert service typertGateway + */ +export declare class TypertGatewayService extends Service implements TypertGateway { + static inject: string[]; + private srcClaims; + /** + * Register the Gateway against the active Typert registry. + * @param ctx - owning Host Context with Typert registry access. + */ + constructor(ctx: Context); + private claimsEndpoint; + private collectSrcClaims; + /** + * Invoke one live Remote method through strict generated reflection or SRC markers. + * @param request - decoded endpoint and exact named wire arguments. + * @returns the validated business result. + * @throws {@link TypertGatewayError} for dispatch, provider, or boundary failures; lookup-policy and business errors retain identity. + */ + invoke(request: InvokeRemoteRequest): Promise; + private dispatchRpc; + private invokeRpc; + private resolveDescriptor; + private resolveSrcDescriptor; + private srcDescriptor; + private resolveReceiverContext; + private resolveParameter; +} +export default TypertGatewayService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.js new file mode 100644 index 0000000..37202a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.js @@ -0,0 +1,508 @@ +/** + * Live Typert Remote dispatch over Cordis Services and registered providers. + * Transport, request correlation, and response envelopes belong to Connection. + * @module @deepseek-ai/dsh-api-gateway + */ +import { Service, symbols } from '@deepseek-ai/cordis'; +import { remoteMethods, TypertLookupFailure, } from '@deepseek-ai/dsh-typert-protocol'; +const NEVER_ABORTED_SIGNAL = new AbortController().signal; +/** Dispatch failure produced outside the invoked business method. */ +export class TypertGatewayError extends Error { + /** Machine-readable failure category. */ + code; + /** Canonical `/` endpoint. */ + endpoint; + /** Affected wire field when the failure is field-specific. */ + field; + /** + * Construct a Gateway failure without embedding boundary values in its message. + * @param code - stable failure category. + * @param endpoint - canonical Remote endpoint. + * @param message - correction-oriented diagnostic without sensitive values. + * @param options - optional field and contained cause. + */ + constructor(code, endpoint, message, options = {}) { + super(`typert gateway: ${endpoint}: ${message}`, options.cause === undefined ? undefined : { cause: options.cause }); + this.name = 'TypertGatewayError'; + this.code = code; + this.endpoint = endpoint; + this.field = options.field; + } +} +/** Business invocation lost its carrier cancellation race. */ +class RemoteInvocationCancelled extends Error { + /** + * @param endpoint - canonical Remote endpoint. + * @param cause - business rejection observed after carrier cancellation. + */ + constructor(endpoint, cause) { + super(`Remote invocation "${endpoint}" was aborted`, { cause }); + this.name = 'RemoteInvocationCancelled'; + } +} +/** + * Resolve strict generated definitions or conservative SRC markers against + * current Cordis Services and Typert providers. + * @typert service typertGateway + */ +export class TypertGatewayService extends Service { + static inject = ['typert']; + srcClaims; + /** + * Register the Gateway against the active Typert registry. + * @param ctx - owning Host Context with Typert registry access. + */ + constructor(ctx) { + super(ctx, 'typertGateway'); + ctx.on('internal/service', () => { + this.srcClaims = undefined; + }); + ctx.inject(['connection'], (connectionCtx) => { + connectionCtx.connection.rpc.intercept('/api', endpoint => this.claimsEndpoint(endpoint), (endpoint, payload, signal) => this.dispatchRpc(endpoint, payload, signal), { authority: 'trusted-host' }); + }); + } + claimsEndpoint(endpoint) { + const segments = endpoint.split('/'); + if (segments.length !== 2 || segments[0] === '' || segments[1] === '') + return false; + if (this.ctx.typert.local.get(endpoint) !== undefined || this.ctx.typert.local.hasSeen(endpoint)) + return true; + this.srcClaims ??= this.collectSrcClaims(); + return this.srcClaims.has(endpoint); + } + collectSrcClaims() { + const claims = new Set(); + for (const [serviceKey, definition] of Object.entries(this.ctx.reflect.props)) { + if (definition.type !== 'service') + continue; + const receiver = this.ctx.get(serviceKey); + if (!isObject(receiver)) + continue; + const original = originalOf(receiver); + const binding = Reflect.get(original, 'typertRemote'); + if (!isObject(binding) || typeof Reflect.get(binding, 'namespace') !== 'string') + continue; + const namespace = Reflect.get(binding, 'namespace'); + for (const candidate of remoteMethods(original)) { + claims.add(endpointOf(namespace, candidate.exportName ?? candidate.method)); + } + } + return claims; + } + /** + * Invoke one live Remote method through strict generated reflection or SRC markers. + * @param request - decoded endpoint and exact named wire arguments. + * @returns the validated business result. + * @throws {@link TypertGatewayError} for dispatch, provider, or boundary failures; lookup-policy and business errors retain identity. + */ + async invoke(request) { + const endpoint = endpointOf(request.namespace, request.method); + const descriptor = this.resolveDescriptor(request.namespace, request.method, endpoint); + assertExactArguments(request.args, descriptor, endpoint); + const receiverContext = await this.resolveReceiverContext(descriptor, request.args, endpoint); + const receiver = receiverContext.get(descriptor.service); + if (!isObject(receiver)) { + throw new TypertGatewayError('service-unavailable', endpoint, `active Service ${JSON.stringify(descriptor.service)} is unavailable`); + } + validateBinding(receiver, descriptor.service, descriptor.namespace, endpoint); + const args = await Promise.all(descriptor.parameters.map(parameter => this.resolveParameter(parameter, request.args, endpoint))); + if (descriptor.cancellation !== undefined) + args.push(request.signal ?? NEVER_ABORTED_SIGNAL); + const implementation = descriptor.implementation ?? descriptor.method; + const method = Reflect.get(receiver, implementation); + if (typeof method !== 'function') { + throw new TypertGatewayError('method-unavailable', endpoint, `active Service ${JSON.stringify(descriptor.service)} has no callable method ${JSON.stringify(implementation)}`); + } + let result; + try { + result = await Reflect.apply(method, receiver, args); + } + catch (error) { + if (request.signal?.aborted === true) + throw new RemoteInvocationCancelled(endpoint, error); + throw error; + } + // A weak descriptor declares no return type, so nothing returned is a void + // result and rides the wire as an absent value field. A strict descriptor + // keeps its schema: there, undefined has to be a declared result. + if (result === undefined && descriptor.result.mode !== 'strict') + return result; + return decode(descriptor.result, result, 'result-invalid', endpoint, 'result'); + } + async dispatchRpc(endpoint, payload, signal) { + return this.invokeRpc(endpoint, payload, signal); + } + async invokeRpc(endpoint, payload, signal) { + try { + const segments = endpoint.split('/'); + if (segments.length !== 2 || segments[0] === '' || segments[1] === '') { + throw new Error(`invalid Remote endpoint ${JSON.stringify(endpoint)}`); + } + const [namespace, method] = segments; + if (!isObject(payload) + || !isPlainObject(payload) + || Reflect.ownKeys(payload).length !== 1 + || !Object.hasOwn(payload, 'args') + || !isObject(payload.args) + || !isPlainObject(payload.args)) { + throw new Error('Remote payload must contain exactly one plain-object args field'); + } + const value = await this.invoke({ + namespace, + method, + args: payload.args, + signal, + }); + // A void or explicitly absent business result carries no `value` field; + // JSON has no `undefined`, and the envelope's optional slot is the one + // representation of absence that both args and results already use. + return { ok: true, value }; + } + catch (error) { + return rpcFailure(error); + } + } + resolveDescriptor(namespace, method, endpoint) { + const strict = this.ctx.typert.local.get(endpoint); + if (strict !== undefined) + return strict; + if (this.ctx.typert.local.hasSeen(endpoint)) { + throw new TypertGatewayError('definition-unavailable', endpoint, 'its strict definition was withdrawn and SRC fallback is forbidden'); + } + return this.resolveSrcDescriptor(namespace, method, endpoint); + } + resolveSrcDescriptor(namespace, method, endpoint) { + const candidates = []; + for (const [serviceKey, definition] of Object.entries(this.ctx.reflect.props)) { + if (definition.type !== 'service') + continue; + const receiver = this.ctx.get(serviceKey); + if (!isObject(receiver)) + continue; + const original = originalOf(receiver); + const value = Reflect.get(original, 'typertRemote'); + if (value === undefined) + continue; + const binding = readBinding(value, original, serviceKey, endpoint); + if (binding.namespace !== namespace) + continue; + const marker = remoteMethods(original).find(candidate => (candidate.exportName ?? candidate.method) === method); + if (marker === undefined) + continue; + candidates.push(this.srcDescriptor(binding, marker, method, endpoint)); + } + if (candidates.length === 0) { + throw new TypertGatewayError('invocation-unavailable', endpoint, 'no active Remote method exports this endpoint'); + } + if (candidates.length > 1) { + throw new TypertGatewayError('ambiguous-endpoint', endpoint, `multiple active Services export this endpoint: ${candidates.map(candidate => candidate.service).sort().join(', ')}`); + } + return candidates[0]; + } + srcDescriptor(binding, marker, method, endpoint) { + const names = methodParameterNames(binding.service, marker.method, endpoint); + const signalIndex = names.indexOf('signal'); + if (signalIndex >= 0 && signalIndex !== names.length - 1) { + throw new TypertGatewayError('signature-invalid', endpoint, 'SRC cancellation parameter signal must be the final parameter', { field: 'signal' }); + } + const cancellation = signalIndex >= 0 + ? { parameter: 'signal' } + : undefined; + const businessNames = cancellation === undefined ? names : names.slice(0, -1); + const parameters = []; + const wires = new Set(); + for (const name of businessNames) { + const matches = this.ctx.typert.lookups.definitions() + .filter(definition => definition.parameter === name); + if (matches.length > 1) { + throw new TypertGatewayError('signature-invalid', endpoint, `parameter ${JSON.stringify(name)} matches multiple lookup providers`, { field: name }); + } + const match = matches[0]; + const parameter = match === undefined + ? { name, wire: name, source: 'json', codec: { mode: 'src-json' } } + : { + name, + wire: match.wire, + source: 'lookup', + lookup: match.key, + codec: { mode: 'src-json' }, + }; + if (wires.has(parameter.wire)) { + throw new TypertGatewayError('signature-invalid', endpoint, `multiple parameters use wire field ${JSON.stringify(parameter.wire)}`, { field: parameter.wire }); + } + wires.add(parameter.wire); + parameters.push(parameter); + } + let receiver = { kind: 'direct' }; + if (marker.invocation.kind === 'context') { + const provider = this.ctx.typert.contexts.getHost(marker.invocation.context); + if (provider === undefined) { + throw new TypertGatewayError('context-unavailable', endpoint, `Context provider ${JSON.stringify(marker.invocation.context)} is unavailable`); + } + if (wires.has(provider.wire)) { + throw new TypertGatewayError('signature-invalid', endpoint, `Context identity conflicts with wire field ${JSON.stringify(provider.wire)}`, { field: provider.wire }); + } + receiver = { + kind: 'context', + context: marker.invocation.context, + wire: provider.wire, + codec: { mode: 'src-json' }, + }; + } + return { + id: `src:${binding.serviceKey}#${endpoint}`, + service: binding.serviceKey, + namespace: binding.namespace, + method, + ...(marker.method === method ? {} : { implementation: marker.method }), + invocation: receiver, + parameters, + ...(cancellation === undefined ? {} : { cancellation }), + result: { mode: 'src-json' }, + }; + } + async resolveReceiverContext(descriptor, args, endpoint) { + if (descriptor.invocation.kind === 'direct') + return this.ctx; + const invocation = descriptor.invocation; + const provider = this.ctx.typert.contexts.getHost(invocation.context); + if (provider === undefined) { + throw new TypertGatewayError('context-unavailable', endpoint, `Context provider ${JSON.stringify(invocation.context)} is unavailable`); + } + if (provider.wire !== invocation.wire + || (invocation.codec.mode === 'strict' && provider.wireTypeSymbol !== invocation.codec.typeSymbol)) { + throw new TypertGatewayError('provider-mismatch', endpoint, `Context provider ${JSON.stringify(invocation.context)} does not match its strict definition`, { field: invocation.wire }); + } + const identity = decode(invocation.codec, args[invocation.wire], 'input-invalid', endpoint, invocation.wire); + let context; + try { + context = await provider.resolve(identity); + } + catch (cause) { + if (cause instanceof TypertLookupFailure) + throw cause; + throw new TypertGatewayError('context-failed', endpoint, `Context provider ${JSON.stringify(invocation.context)} failed`, { cause, field: invocation.wire }); + } + if (context === undefined) { + throw new TypertGatewayError('context-not-found', endpoint, `Context provider ${JSON.stringify(invocation.context)} did not resolve the requested identity`, { field: invocation.wire }); + } + return context; + } + async resolveParameter(parameter, args, endpoint) { + // An absent field reached assertExactArguments' allowance, so this parameter + // takes undefined; a present-but-undefined field is not JSON-safe input and + // still fails decode. Lookup ids are never omissible, so absence here only + // ever belongs to a json parameter. + if (!Object.hasOwn(args, parameter.wire)) + return undefined; + const value = decode(parameter.codec, args[parameter.wire], 'input-invalid', endpoint, parameter.wire); + if (parameter.source === 'json') + return value; + const key = parameter.lookup; + /* v8 ignore next -- registry validation rejects strict descriptors without a key, and SRC derivation always supplies one. */ + if (key === undefined) { + throw new TypertGatewayError('lookup-unavailable', endpoint, `lookup parameter ${JSON.stringify(parameter.name)} has no provider key`, { field: parameter.wire }); + } + const provider = this.ctx.typert.lookups.get(key); + if (provider === undefined) { + throw new TypertGatewayError('lookup-unavailable', endpoint, `lookup provider ${JSON.stringify(key)} is unavailable`, { field: parameter.wire }); + } + if (provider.wire !== parameter.wire + || (parameter.codec.mode === 'strict' && provider.wireTypeSymbol !== parameter.codec.typeSymbol)) { + throw new TypertGatewayError('provider-mismatch', endpoint, `lookup provider ${JSON.stringify(key)} does not match its strict definition`, { field: parameter.wire }); + } + let resolved; + try { + resolved = await provider.resolve(value); + } + catch (cause) { + if (cause instanceof TypertLookupFailure) + throw cause; + throw new TypertGatewayError('lookup-failed', endpoint, `lookup provider ${JSON.stringify(key)} failed`, { cause, field: parameter.wire }); + } + if (resolved === undefined) { + throw new TypertGatewayError('lookup-not-found', endpoint, `lookup provider ${JSON.stringify(key)} did not resolve the requested identity`, { field: parameter.wire }); + } + return resolved; + } +} +function rpcFailure(error) { + if (error instanceof RemoteInvocationCancelled) { + return { + ok: false, + error: { code: 'cancelled', message: error.message, details: {} }, + }; + } + if (error instanceof TypertLookupFailure) { + return { ok: false, error: error.failure }; + } + return { + ok: false, + error: { + code: 'internal', + message: error instanceof Error ? error.message : String(error), + details: {}, + }, + }; +} +function endpointOf(namespace, method) { + return `${namespace}/${method}`; +} +function validateBinding(receiver, serviceKey, namespace, endpoint) { + const original = originalOf(receiver); + const value = Reflect.get(original, 'typertRemote'); + if (value === undefined) { + throw new TypertGatewayError('binding-invalid', endpoint, `Service ${JSON.stringify(serviceKey)} has no visible typertRemote binding`); + } + return { + binding: readBinding(value, original, serviceKey, endpoint, namespace), + original, + }; +} +function readBinding(value, original, serviceKey, endpoint, namespace) { + if (!isObject(value) + || Reflect.get(value, 'service') !== original + || Reflect.get(value, 'serviceKey') !== serviceKey + || typeof Reflect.get(value, 'namespace') !== 'string' + || (namespace !== undefined && Reflect.get(value, 'namespace') !== namespace)) { + throw new TypertGatewayError('binding-invalid', endpoint, `Service ${JSON.stringify(serviceKey)} has an inconsistent typertRemote binding`); + } + return value; +} +function originalOf(receiver) { + const original = Reflect.get(receiver, symbols.original); + return isObject(original) ? original : receiver; +} +function methodParameterNames(service, method, endpoint) { + let prototype = Object.getPrototypeOf(service); + let implementation; + while (prototype !== null) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, method); + if (descriptor !== undefined) { + if ('value' in descriptor && typeof descriptor.value === 'function') { + implementation = descriptor.value; + } + break; + } + prototype = Object.getPrototypeOf(prototype); + } + if (implementation === undefined) { + throw new TypertGatewayError('method-unavailable', endpoint, `Remote marker has no prototype method ${JSON.stringify(method)}`); + } + const source = Function.prototype.toString.call(implementation); + const open = source.indexOf('('); + const close = source.indexOf(')', open + 1); + /* v8 ignore next -- standard public class-method syntax always contains a parenthesized parameter list. */ + if (open < 0 || close < 0) + return invalidSignature(endpoint, method); + const body = source.slice(open + 1, close).trim(); + if (body.length === 0) + return []; + const parts = body.split(',').map(part => part.trim()); + const names = new Set(); + for (const part of parts) { + if (!/^[$A-Z_a-z][$\w]*$/u.test(part) || names.has(part)) + return invalidSignature(endpoint, method); + names.add(part); + } + return [...names]; +} +function invalidSignature(endpoint, method) { + throw new TypertGatewayError('signature-invalid', endpoint, `SRC method ${JSON.stringify(method)} must use unique identifier parameters without destructuring, defaults, or rest`); +} +function assertExactArguments(args, descriptor, endpoint) { + if (!isPlainObject(args)) { + throw new TypertGatewayError('arguments-invalid', endpoint, 'args must be a plain object'); + } + const expected = new Set(descriptor.parameters.map(parameter => parameter.wire)); + if (descriptor.invocation.kind === 'context') + expected.add(descriptor.invocation.wire); + const actual = Reflect.ownKeys(args); + const extra = actual.filter(key => typeof key !== 'string' || !expected.has(key)); + // A JSON field may be omitted when the strict descriptor declares absence, + // and always under SRC: a weak descriptor reads parameter names from the + // JavaScript signature and cannot see which are optional, so LIB is where an + // omitted required argument is caught. Lookup ids are never omissible. + const acceptsMissing = new Set(descriptor.parameters + .filter(parameter => parameter.source === 'json' + && (parameter.acceptsUndefined === true || parameter.codec.mode === 'src-json')) + .map(parameter => parameter.wire)); + const missing = [...expected].filter(key => !Object.hasOwn(args, key) && !acceptsMissing.has(key)); + if (extra.length === 0 && missing.length === 0) + return; + const clauses = []; + if (missing.length > 0) + clauses.push(`missing ${missing.map(key => JSON.stringify(key)).join(', ')}`); + if (extra.length > 0) + clauses.push(`unexpected ${extra.map(key => JSON.stringify(String(key))).join(', ')}`); + throw new TypertGatewayError('arguments-invalid', endpoint, `args fields do not match the descriptor: ${clauses.join('; ')}`); +} +function decode(codec, value, code, endpoint, field) { + try { + if (codec.mode === 'strict') { + value = codec.schema.parse(value); + if (value === undefined) + return value; + } + assertJsonValue(value, new Set()); + return value; + } + catch (cause) { + throw new TypertGatewayError(code, endpoint, code === 'input-invalid' + ? `wire field ${JSON.stringify(field)} failed boundary validation` + : 'business result failed boundary validation', { cause, field }); + } +} +function assertJsonValue(value, ancestors) { + if (value === null || typeof value === 'string' || typeof value === 'boolean') + return; + if (typeof value === 'number') { + if (Number.isFinite(value)) + return; + throw new TypeError('non-finite number is not JSON-safe'); + } + if (!isObject(value)) + throw new TypeError(`${typeof value} is not JSON-safe`); + if (ancestors.has(value)) + throw new TypeError('cyclic value is not JSON-safe'); + ancestors.add(value); + try { + if (Array.isArray(value)) { + if (Object.getOwnPropertySymbols(value).length > 0 || Object.keys(value).length !== value.length) { + throw new TypeError('sparse or decorated array is not JSON-safe'); + } + for (let index = 0; index < value.length; index += 1) { + if (!Object.hasOwn(value, index)) + throw new TypeError('sparse array is not JSON-safe'); + assertJsonValue(value[index], ancestors); + } + return; + } + if (!isPlainObject(value)) + throw new TypeError('non-plain object is not JSON-safe'); + if (Object.getOwnPropertySymbols(value).length > 0) + throw new TypeError('symbol property is not JSON-safe'); + for (const key of Reflect.ownKeys(value)) { + const descriptor = Object.getOwnPropertyDescriptor(value, key); + /* v8 ignore next -- ownKeys() just returned this key; only a hostile same-process Proxy can delete it between operations. */ + if (descriptor === undefined || !descriptor.enumerable || !('value' in descriptor)) { + throw new TypeError('non-data property is not JSON-safe'); + } + assertJsonValue(descriptor.value, ancestors); + } + } + finally { + ancestors.delete(value); + } +} +function isPlainObject(value) { + if (Array.isArray(value)) + return false; + const prototype = Object.getPrototypeOf(value); + return prototype === null || prototype === Object.prototype; +} +function isObject(value) { + return (typeof value === 'object' && value !== null) || typeof value === 'function'; +} +export default TypertGatewayService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.d.ts new file mode 100644 index 0000000..8974e5f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-api-gateway`. + * @module @deepseek-ai/dsh-api-gateway/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "api-gateway-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.js new file mode 100644 index 0000000..f064654 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.js @@ -0,0 +1,23 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-api-gateway`. + * @module @deepseek-ai/dsh-api-gateway/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-api-gateway'; +/** Cordis companion plugin name. */ +export const name = 'api-gateway-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: Host calls re-read authoritative Cordis and Typert + * state, while Client methods, descriptors, and `$on` subscriptions mutate in + * one owned effect. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.d.ts new file mode 100644 index 0000000..6d90211 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.d.ts @@ -0,0 +1,34 @@ +/** + * Carrier-independent Typert Gateway request, service, and error contracts. + * @module @deepseek-ai/dsh-api-gateway/types + */ +/** One Remote method request after a carrier has decoded its envelope. */ +export interface InvokeRemoteRequest { + /** Remote namespace selected by the generated descriptor. */ + readonly namespace: string; + /** Exported Service method name. */ + readonly method: string; + /** Named wire values; fields must exactly match the descriptor. */ + readonly args: Readonly>; + /** Carrier or direct-caller cancellation injected only into cancellation-aware methods. */ + readonly signal?: AbortSignal; +} +/** Stable infrastructure and boundary failures emitted before or after business execution. */ +export type TypertGatewayErrorCode = 'ambiguous-endpoint' | 'arguments-invalid' | 'binding-invalid' | 'context-failed' | 'context-not-found' | 'context-unavailable' | 'definition-unavailable' | 'input-invalid' | 'invocation-unavailable' | 'lookup-failed' | 'lookup-not-found' | 'lookup-unavailable' | 'method-unavailable' | 'provider-mismatch' | 'result-invalid' | 'service-unavailable' | 'signature-invalid'; +/** Host dispatcher consumed by Connection adapters. */ +export interface TypertGateway { + /** + * Invoke one live Remote method without assuming a carrier or response envelope. + * @param request - decoded endpoint and named wire arguments. + * @returns the validated business result. + * @throws {@link TypertGatewayError} for dispatch, provider, or boundary failures; lookup-policy and business errors retain identity. + */ + invoke(request: InvokeRemoteRequest): Promise; +} +declare module '@deepseek-ai/cordis' { + interface Context { + /** Host dispatcher for Typert Remote calls. */ + typertGateway: TypertGateway; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.js new file mode 100644 index 0000000..aef140b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.js @@ -0,0 +1,6 @@ +/** + * Carrier-independent Typert Gateway request, service, and error contracts. + * @module @deepseek-ai/dsh-api-gateway/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/package.json new file mode 100644 index 0000000..c96ba1a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway/package.json @@ -0,0 +1,75 @@ +{ + "name": "@deepseek-ai/dsh-api-gateway", + "description": "Typert Remote Host dispatcher and Client API endpoint", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/api/gateway" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client/index.d.ts", + "default": "./lib/client.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "dsh": { + "client": { + "inject": [ + "@deepseek-ai/dsh-typert-registry", + "@deepseek-ai/dsh-client-connection" + ], + "platform": "web", + "immediately": true + } + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/client.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6" + }, + "peerDependencies": { + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "zod": "^4.4.3", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.6", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "scripts": { + "bundle": "tsdown", + "watch": "tsdown --watch" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-client-connection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-client-connection new file mode 120000 index 0000000..1a3f603 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-client-connection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..aa2ae83 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-typert-registry b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-typert-registry new file mode 120000 index 0000000..6e23eda --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-typert-registry @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.i18n.yaml new file mode 100644 index 0000000..826bd88 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/api/gateway/README.md +README.md: 7caf707c376bd3e2654fad1f0c01ac83e6faa44c +README.zh.md: b340df982ed1ca9b980fbcf60729d8124319ce6e diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.md new file mode 100644 index 0000000..7caf707 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.md @@ -0,0 +1,42 @@ +# @deepseek-ai/dsh-api-gateway + +English | [中文](README.zh.md) + +Two-sided Typert RPC endpoint for Host and Client Cordis environments. The Host entry provides `ctx.typertGateway`, while `@deepseek-ai/dsh-api-gateway/client` provides `ctx.remote`; both consume the same generated `InvocationDescriptor` contract and leave business selection to API Remotes and transport, request correlation, trust, and response envelopes to Connection. + +## Host service: `TypertGatewayService` (ctx key: `typertGateway`) + +`ctx.typertGateway.invoke()` resolves the current descriptor and Cordis Service for each call, validates exact named arguments, resolves registered object or Context identities, invokes the public business method, and validates its result. Business Services extend `TypertRemoteService` and mark methods with `@Remote` or `@RemoteScope` from [`dsh-typert-protocol`](../../typert/protocol/README.md); `bindTypertRemote()` remains available when another base class owns inheritance. + +Strict mode reads generated invocation descriptors from `ctx.typert.local`. Lookup parameters use the currently active resolver in `ctx.typert.lookups`: the business package registers the stable declaration and default policy, while Host composition can override resolution behavior with effect-scoped `configure()`; `@RemoteScope` resolves its receiver through a registered Host Context provider. SRC mode is a development fallback for endpoints that have never had a strict definition; it parses simple parameter names and accepts only JSON-safe values for non-lookup parameters. Withdrawing an observed strict definition fails instead of weakening validation. + +The Host entry registers a trusted-host interceptor on Connection's shared `/api` FetchHandler. Connection passes this composite handler through its HTTP bridge; the handler dispatches claimed endpoints to Gateway and unclaimed endpoints to API Proxy. Direct `invoke()` calls preserve business errors; `TypertGatewayError` distinguishes failures owned by dispatch, binding, providers, lookup, Context, arguments, and codecs. A resolver may use `TypertLookupFailure` to carry an existing RPC error, preserving its original error code for policy rejections such as cold-resume failures or ownership fences. + +A cancellation-aware Remote method declares `signal: AbortSignal` as its final Host parameter. The signal is descriptor metadata rather than a wire argument: Connection supplies it to the Gateway, and the Gateway injects it after decoded business parameters. SRC recognizes the reserved final name, while strict generation additionally requires the global `AbortSignal` type. + +## Client service: `ClientRemote` (ctx key: `remote`) + +`ctx.remote.$mount()` validates and registers a generated Host-for-Client contribution, then installs concrete direct and scoped methods for the calling Cordis fiber. Each namespace is a traced `remote.` child Service and unloads after its last method is withdrawn. Duplicate endpoints, namespace collisions, and descriptors without strict generated codecs fail before methods become callable. + +Each call validates positional inputs, constructs the descriptor's exact named `args`, and sends it through `ctx.connection.rpc.call('/api', endpoint, ...)`. Generated cancellation-aware methods accept a final optional `AbortSignal`; the Client combines it with the contribution mount lifetime before calling Connection. The returned value is validated before reaching application code. Withdrawing a contribution removes its descriptors and methods together, aborts in-flight calls, and makes retained method handles reject. + +`ctx.remote.$on()` subscribes to one forwarded Host event. Its legal keys are exactly the Host assembly's forwarding selection, and the listener type is the owning package's own Cordis `Events` declaration, so no second signature can drift from it. Each subscription belongs to the calling fiber and disappears with it. Delivery is one-way and follows registration order; a listener that throws is logged and isolated from the remaining listeners, which never affects the frame pump. `ctx.remote.$dispatch()` is the other half of that surface, and it is the carrier's: the Client half owning the Host frame sink hands each decoded frame over, and an event name nobody subscribes to is dropped, since the wire carries whatever the Host selected. A consumer subscribes and never calls it. + +Generated declaration merges provide the TypeScript API through the shared `TypertClientRemote` contract. The Client entry contains no Host Service or Host Cordis interface merge, and method lookup and invocation use ordinary objects and functions rather than a JavaScript Proxy. + +## Model Experience + +None, as the package dispatches application calls and registers no prompt, tool, or session event. + +#### KV Cache effect + +No direct effect; invoked business Services own any model-visible result. + +## Known Limitations and Deferred Work + +- The Connection adapter maps ordinary dispatch failures and business exceptions to the RPC `internal` code with empty details; lookup-policy errors carried by `TypertLookupFailure` are returned unchanged. Structured `TypertGatewayError` categories remain available only to same-process callers. +- SRC mode supports unique identifier parameters without destructuring, defaults, or rest parameters. It validates JSON safety rather than generated business types and never infers optional fields. +- Only strict generated contributions can mount on the Client face. SRC markers have no Client codec or type projection. +- The package dispatches unary methods only. Incremental Session data uses a separate named-stream protocol over the same Connection. +- Lookup resolvers are configured per key; an individual Remote parameter or endpoint cannot currently select a live-only policy under the same `agent`/`session` key. +- Forwarded events reach `$on` exactly as the Host emitted them: no payload projection or redaction, no Scope-bound subscription, and no replay after a reconnect. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.zh.md new file mode 100644 index 0000000..b340df9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/README.zh.md @@ -0,0 +1,42 @@ +# @deepseek-ai/dsh-api-gateway + +[English](README.md) | 中文 + +为 Host 与 Client 两侧的 Cordis 环境提供 Typert RPC endpoint。Host 入口提供 `ctx.typertGateway`,`@deepseek-ai/dsh-api-gateway/client` 则提供 `ctx.remote`;两者使用同一份生成的 `InvocationDescriptor` 约定,并将业务选择交给 API Remotes,将传输、请求关联、信任和响应封装交给 Connection。 + +## Host 服务:`TypertGatewayService`(ctx key:`typertGateway`) + +每次调用时,`ctx.typertGateway.invoke()` 都会解析当前的描述符和 Cordis 服务,校验具名参数是否完全匹配,解析已注册的对象或 Context 身份标识,调用公开的业务方法,并校验其结果。业务服务继承 [`dsh-typert-protocol`](../../typert/protocol/README.md) 的 `TypertRemoteService`,并用 `@Remote` 或 `@RemoteScope` 标记方法;已有其他基类时仍可改用 `bindTypertRemote()`。 + +严格模式从 `ctx.typert.local` 读取生成的调用描述符。查找参数使用 `ctx.typert.lookups` 中当前有效的 resolver:业务包注册稳定声明与默认策略,Host 组合可用 effect-scoped `configure()` 覆盖解析行为;`@RemoteScope` 则通过已注册的 Host Context 提供方解析其接收者。SRC 模式是开发阶段的回退路径,适用于从未具备严格定义的端点;它解析简单参数名,并且只允许非查找参数使用可安全表示为 JSON 的值。已观测到的严格定义一旦撤回,系统会直接报错,而不会降低校验强度。 + +Connection 可用时,Host 入口会在 Connection 共享的 `/api` FetchHandler 上注册 trusted-host interceptor。Connection 把这个复合 handler 交给 HTTP bridge;handler 将已认领 endpoint 分发给 Gateway,未认领 endpoint 则交给 API Proxy。直接调用 `invoke()` 会保留业务错误;`TypertGatewayError` 可区分分发、绑定、提供方、查找、Context、参数和编解码器各自负责的故障。resolver 可以用 `TypertLookupFailure` 携带既有 RPC error,使冷恢复失败或 ownership fence 等策略拒绝保持原错误码。 + +支持取消的 Remote 方法会把 `signal: AbortSignal` 声明为最后一个 Host 参数。signal 是 descriptor 元数据,而不是 wire 参数:Connection 将它提供给 Gateway,Gateway 则在已解码的业务参数之后注入它。SRC 识别这个保留的末位参数名,严格生成还要求它具有全局 `AbortSignal` 类型。 + +## Client 服务:`ClientRemote`(ctx key:`remote`) + +`ctx.remote.$mount()` 会校验并注册生成的 Host-for-Client 贡献项,然后为发起调用的 Cordis fiber 安装具体的直接方法和作用域方法。每个 namespace 都是可追踪的 `remote.` 子 Service,并在最后一个方法撤回后卸载。重复端点、命名空间冲突,以及缺少生成的严格编解码器的描述符,都会在方法可调用前报错。 + +每次调用都会校验位置参数,构造与描述符完全匹配的具名 `args`,再通过 `ctx.connection.rpc.call('/api', endpoint, ...)` 发送。生成的支持取消的方法接受最后一个可选 `AbortSignal`;Client 会在调用 Connection 前将它与贡献项的挂载生命周期合并。返回值经过校验后才会交给应用代码。撤回贡献项会同时移除其描述符和方法、中止正在进行的调用,并使外部仍持有的方法句柄在调用时返回拒绝。 + +`ctx.remote.$on()` 订阅一条被转发的 Host 事件。它的合法键恰好等于 Host 装配声明的转发选择,listener 类型就是事件所属包自己的 Cordis `Events` 声明,因此不存在会与之漂移的第二份签名。每个订阅归属发起调用的 fiber,并随该 fiber 一起消失。投递是单向的,并按注册顺序进行;抛错的 listener 会被记录并与其余 listener 隔离,绝不影响帧泵。`ctx.remote.$dispatch()` 是该面的另一半,且属于载体:持有 Host 帧 sink 的 Client 半把每个解码后的帧交进来,收到无人订阅的事件名即丢弃,因为 wire 上出现什么取决于 Host 的转发选择。消费方只订阅,绝不调用它。 + +生成的声明合并通过共享的 `TypertClientRemote` 约定提供 TypeScript API。Client 入口不包含 Host 服务或 Host Cordis 接口合并;方法查找和调用使用普通对象与函数,而不使用 JavaScript Proxy。 + +## 模型体验 + +无,因为该包分发应用调用,不注册任何提示词、工具或会话事件。 + +#### KV Cache 影响 + +无直接影响;被调用的业务服务负责产生任何模型可见结果。 + +## 已知限制与延期工作 + +- Connection 适配器将普通分发故障和业务异常映射为 RPC 的 `internal` 代码,且不附带详细信息;`TypertLookupFailure` 携带的 lookup 策略错误会原样返回。结构化的 `TypertGatewayError` 类别仅供同进程调用方使用。 +- SRC 模式仅支持名称唯一的标识符参数,不支持解构、默认值或剩余参数。它只校验值能否安全表示为 JSON,不校验生成的业务类型,也绝不会推断可选字段。 +- Client 侧只能挂载严格模式生成的贡献项。SRC 标记不具备 Client 编解码器或类型投影。 +- 该包只分发一元方法。增量会话数据通过同一个 Connection 上独立的具名流协议传输。 +- lookup resolver 按 key 配置;当前无法让单个 Remote 参数或 endpoint 在同一 `agent`/`session` key 下选择 live-only 策略。 +- 被转发的事件原样到达 `$on`:没有载荷投影或脱敏,不支持 Scope 化订阅,重连后也不重放。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/client.js new file mode 100644 index 0000000..9440fcd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/client.js @@ -0,0 +1,420 @@ +window.__ModuleLoader__.load({ + id: "@deepseek-ai/dsh-api-gateway", + factory: (require) => { + var module = { exports: {} }; + var exports = module.exports; + Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); + let _deepseek_ai_cordis = require("@deepseek-ai/cordis"); + //#region lib/types/client/index.js + /** + * Client projection of generated Typert Remote descriptors. Contributions + * install traced `remote.` services; no JavaScript Proxy + * participates in method lookup, invocation, or type exposure. + */ + /** Required Client services: the Typert registry and the existing Connection carrier. */ + const inject = ["typert", "connection"]; + /** + * Install the typed Client Remote service. + * @param ctx - Client Cordis root. + */ + function apply(ctx) { + new ClientRemoteService(ctx); + } + var ClientRemoteService = class extends _deepseek_ai_cordis.Service { + ownerCtx; + namespaces = /* @__PURE__ */ new Map(); + subscriptions = /* @__PURE__ */ new Map(); + mutations = Promise.resolve(); + constructor(ctx) { + super(ctx, "remote"); + this.ownerCtx = ctx; + ctx.effect(() => () => { + this.subscriptions.clear(); + }, "api-gateway.client.subscriptions"); + } + async $mount(contribution) { + const callerCtx = this.ctx; + const owned = callerCtx.effect(async () => { + const dispose = await this.enqueue(() => this.mountContribution(callerCtx, contribution)); + return () => this.enqueue(dispose); + }, `api-gateway.client.$mount(${JSON.stringify(contribution.package)})`); + await owned; + return async () => { + await owned(); + }; + } + $on(event, listener) { + const subscription = { listener }; + const owned = this.ctx.effect(() => { + const listeners = this.listeners(event); + listeners.push(subscription); + return () => { + const at = listeners.indexOf(subscription); + /* v8 ignore next -- listener */ + if (at >= 0) listeners.splice(at, 1); + }; + }, `api-gateway.client.$on(${JSON.stringify(event)})`); + return () => { + owned(); + }; + } + /** + * Deliver one forwarded event in registration order, isolating a listener + * that fails either synchronously or by rejecting a returned promise; see + * {@link TypertClientRemote.$dispatch} for the caller contract. + */ + $dispatch(event, args) { + const listeners = this.subscriptions.get(event); + if (listeners === void 0) return; + for (const { listener } of [...listeners]) { + const report = (error) => { + console.error(`client api: Remote event ${JSON.stringify(event)} listener threw:`, error); + }; + try { + const settled = listener(...args); + if (settled instanceof Promise) settled.catch(report); + } catch (error) { + report(error); + } + } + } + /** Subscriptions for one event name; empty arrays are retained, bounded by the Host's selection. */ + listeners(event) { + let listeners = this.subscriptions.get(event); + if (listeners === void 0) { + listeners = []; + this.subscriptions.set(event, listeners); + } + return listeners; + } + enqueue(operation) { + const result = this.mutations.then(operation, operation); + this.mutations = result.then(() => void 0, () => void 0); + return result; + } + async mountContribution(callerCtx, contribution) { + this.validateContribution(contribution); + const disposeRemote = callerCtx.typert.remotes.register(contribution); + const installed = []; + try { + for (const descriptor of contribution.descriptors) installed.push(await this.install(descriptor)); + } catch (error) { + for (const dispose of installed.reverse()) await dispose(); + await disposeRemote(); + throw error; + } + return async () => { + for (const dispose of installed.reverse()) await dispose(); + await disposeRemote(); + }; + } + validateContribution(contribution) { + const direct = /* @__PURE__ */ new Map(); + const scoped = /* @__PURE__ */ new Map(); + const add = (table, descriptor, kind) => { + const methods = table.get(descriptor.namespace) ?? /* @__PURE__ */ new Set(); + if (methods.has(descriptor.method)) throw new Error(`client api: contribution repeats ${kind} method ${endpointOf(descriptor)}`); + methods.add(descriptor.method); + table.set(descriptor.namespace, methods); + if ((this.namespaces.get(descriptor.namespace)?.service)?.has(kind, descriptor.method) === true) throw new Error(`client api: ${kind} method ${endpointOf(descriptor)} is already mounted`); + }; + for (const descriptor of contribution.descriptors) { + requireStrictDescriptor(descriptor); + if (descriptor.invocation.kind === "direct") add(direct, descriptor, "direct"); + if (scopedProjection(descriptor) !== void 0) add(scoped, descriptor, "scoped"); + } + const namespaces = new Set([...direct.keys(), ...scoped.keys()]); + for (const namespace of namespaces) { + const service = this.namespaces.get(namespace)?.service; + if (service === void 0) { + if (namespace in this) throw new Error(`client api: namespace ${JSON.stringify(namespace)} conflicts with the Remote service`); + const serviceKey = remoteServiceKey(namespace); + if (this.ownerCtx.reflect.props[serviceKey]?.type === "accessor" || this.ownerCtx.get(serviceKey) !== void 0) throw new Error(`client api: namespace ${JSON.stringify(namespace)} conflicts with an existing Remote namespace`); + } + for (const method of new Set([...direct.get(namespace) ?? [], ...scoped.get(namespace) ?? []])) if (service === void 0) RemoteNamespaceService.assertMethodAvailable(namespace, method); + else service.assertMethodAvailable(method); + } + } + async install(descriptor) { + const token = { + active: true, + abort: new AbortController() + }; + const installed = []; + try { + if (descriptor.invocation.kind === "direct") installed.push(await this.installDirect(descriptor, token)); + const projection = scopedProjection(descriptor); + if (projection !== void 0) installed.push(await this.installScoped(descriptor, projection, token)); + } catch (error) { + token.active = false; + token.abort.abort(); + for (const dispose of installed.reverse()) await dispose(); + throw error; + } + return async () => { + /* v8 ignore next -- Cordis effect disposers are idempotent and invoke this cleanup at most once. */ + if (!token.active) return; + token.active = false; + token.abort.abort(); + for (const dispose of installed.reverse()) await dispose(); + }; + } + async installDirect(descriptor, token) { + const namespace = await this.namespace(descriptor.namespace); + try { + namespace.service.installDirect(descriptor, token); + } catch (error) { + await this.disposeNamespace(descriptor.namespace, namespace); + throw error; + } + return async () => { + namespace.service.remove("direct", descriptor.method, token); + await this.disposeNamespace(descriptor.namespace, namespace); + }; + } + async installScoped(descriptor, projection, token) { + const namespace = await this.namespace(descriptor.namespace); + try { + namespace.service.installScoped(descriptor, projection, token); + } catch (error) { + await this.disposeNamespace(descriptor.namespace, namespace); + throw error; + } + return async () => { + namespace.service.remove("scoped", descriptor.method, token); + await this.disposeNamespace(descriptor.namespace, namespace); + }; + } + async namespace(name) { + let namespace = this.namespaces.get(name); + if (namespace !== void 0) return namespace; + let service; + const fiber = this.ownerCtx.plugin({ + name: remoteServiceKey(name), + apply: (ctx) => { + service = new RemoteNamespaceService(ctx, name, (direct, scoped, caller, args) => this.invokeMethod(direct, scoped, caller, args)); + } + }); + try { + await fiber; + } catch (error) { + await fiber.dispose(); + throw error; + } + /* v8 ignore next -- a settled namespace fiber synchronously constructs its Service. */ + if (service === void 0) throw new Error(`client api: namespace ${JSON.stringify(name)} did not start`); + namespace = { + service, + dispose: fiber.dispose + }; + this.namespaces.set(name, namespace); + return namespace; + } + async disposeNamespace(name, namespace) { + if (!namespace.service.empty || this.namespaces.get(name) !== namespace) return; + this.namespaces.delete(name); + await namespace.dispose(); + } + invokeMethod(direct, scoped, callerCtx, values) { + if (scoped !== void 0) { + const identity = this.ownerCtx.typert.contexts.getClient(scoped.projection.context)?.identity(callerCtx); + if (identity !== void 0) return this.invoke(scoped.descriptor, scoped.projection, scoped.token, callerCtx, values, { value: identity }); + } + if (direct !== void 0) return this.invoke(direct.descriptor, void 0, direct.token, callerCtx, values); + if (scoped !== void 0) return this.invoke(scoped.descriptor, scoped.projection, scoped.token, callerCtx, values); + throw new Error("client api: Remote method is no longer mounted"); + } + async invoke(descriptor, projection, token, callerCtx, values, boundIdentity) { + const endpoint = endpointOf(descriptor); + if (!token.active) return withdrawn(endpoint); + const expected = descriptor.parameters.length - (projection?.parameterIndex === void 0 ? 0 : 1); + const hasCallerSignal = descriptor.cancellation !== void 0 && values.length === expected + 1; + if (values.length !== expected && !hasCallerSignal) { + const contract = descriptor.cancellation === void 0 ? `${String(expected)} argument(s)` : `${String(expected)} business argument(s) plus an optional AbortSignal`; + throw new Error(`client api: ${endpoint} expected ${contract}, got ${String(values.length)}`); + } + const args = Object.create(null); + if (projection !== void 0) { + const binder = boundIdentity === void 0 ? this.ownerCtx.typert.contexts.getClient(projection.context) : void 0; + if (boundIdentity === void 0 && binder === void 0) throw new Error(`client api: ${endpoint} has no Client Context binder for ${JSON.stringify(projection.context)}`); + const identity = boundIdentity === void 0 ? binder?.identity(callerCtx) : boundIdentity.value; + if (identity === void 0) throw new Error(`client api: ${endpoint} requires a ${JSON.stringify(projection.context)} Context`); + args[projection.wire] = parse(projection.codec, identity, endpoint, projection.wire); + } + let valueIndex = 0; + descriptor.parameters.forEach((parameter, parameterIndex) => { + if (parameterIndex === projection?.parameterIndex) return; + const value = parse(parameter.codec, values[valueIndex], endpoint, parameter.wire); + if (value !== void 0) args[parameter.wire] = value; + valueIndex += 1; + }); + const connection = this.ownerCtx.get("connection"); + if (connection === void 0) throw new Error(`client api: ${endpoint} has no active Connection`); + const callerSignal = hasCallerSignal ? values[expected] : void 0; + const signal = callerSignal === void 0 ? token.abort.signal : AbortSignal.any([token.abort.signal, callerSignal]); + try { + const result = await connection.rpc.call("/api", endpoint, { args }, signal); + if (!mountActive(token)) return withdrawn(endpoint); + if (!result.ok) return { + ok: false, + error: result.error + }; + return { + ok: true, + value: parse(descriptor.result, result.value, endpoint, "result") + }; + } catch (error) { + return carrierFailure(endpoint, error); + } + } + }; + var RemoteNamespaceService = class RemoteNamespaceService extends _deepseek_ai_cordis.Service { + invokeRemote; + methods = /* @__PURE__ */ new Map(); + namespace; + static assertMethodAvailable(namespace, method) { + if (REMOTE_NAMESPACE_FIELDS.has(method) || method in RemoteNamespaceService.prototype) throw new Error(`client api: method ${JSON.stringify(`${namespace}/${method}`)} conflicts with its namespace service`); + } + constructor(ctx, name, invokeRemote) { + super(ctx, remoteServiceKey(name)); + this.invokeRemote = invokeRemote; + this.namespace = name; + } + assertMethodAvailable(method) { + RemoteNamespaceService.assertMethodAvailable(this.namespace, method); + if (method in this && !this.methods.has(method)) throw new Error(`client api: method ${JSON.stringify(`${this.namespace}/${method}`)} conflicts with its namespace service`); + } + get empty() { + return this.methods.size === 0; + } + has(kind, method) { + return this.methods.get(method)?.[kind] !== void 0; + } + installDirect(descriptor, token) { + this.install(descriptor.method, "direct", { + descriptor, + token + }); + } + installScoped(descriptor, projection, token) { + this.install(descriptor.method, "scoped", { + descriptor, + projection, + token + }); + } + install(method, kind, value) { + this.assertMethodAvailable(method); + let record = this.methods.get(method); + const fresh = record === void 0; + record ??= {}; + if (fresh) { + Object.defineProperty(this, method, { + configurable: true, + enumerable: true, + get: function() { + const callerCtx = this.ctx; + const current = this.methods.get(method); + const direct = current?.direct; + const scoped = current?.scoped; + return (...args) => { + return this.invokeRemote(direct, scoped, callerCtx, args); + }; + } + }); + this.methods.set(method, record); + } + if (kind === "direct") record.direct = value; + else record.scoped = value; + } + remove(kind, method, token) { + const record = this.methods.get(method); + const current = record?.[kind]; + /* v8 ignore next -- duplicate live variants are rejected before installation, so no newer token can replace this one. */ + if (record === void 0 || current?.token !== token) return; + if (kind === "direct") delete record.direct; + else delete record.scoped; + if (record.direct !== void 0 || record.scoped !== void 0) return; + this.methods.delete(method); + Reflect.deleteProperty(this, method); + } + }; + const REMOTE_NAMESPACE_FIELDS = new Set([ + "ctx", + "empty", + "invokeRemote", + "methods", + "name", + "namespace" + ]); + function remoteServiceKey(namespace) { + return `remote.${namespace}`; + } + function endpointOf(descriptor) { + return `${descriptor.namespace}/${descriptor.method}`; + } + function mountActive(token) { + return token.active; + } + function scopedProjection(descriptor) { + if (descriptor.invocation.kind === "context") return { + context: descriptor.invocation.context, + wire: descriptor.invocation.wire, + codec: descriptor.invocation.codec + }; + if (descriptor.scope === void 0) return void 0; + const lookupParameters = descriptor.parameters.map((parameter, index) => ({ + parameter, + index + })).filter((candidate) => candidate.parameter.source === "lookup"); + const selected = lookupParameters.length === 1 ? lookupParameters[0] : void 0; + if (selected === void 0 || selected.parameter.wire !== descriptor.scope.wire || selected.parameter.lookup !== descriptor.scope.context) throw new Error(`client api: generated Remote ${endpointOf(descriptor)} scope must select its only lookup parameter`); + return { + context: descriptor.scope.context, + wire: descriptor.scope.wire, + codec: selected.parameter.codec, + parameterIndex: selected.index + }; + } + function requireStrictDescriptor(descriptor) { + const endpoint = endpointOf(descriptor); + requireStrictCodec(descriptor.result, endpoint, "result"); + for (const parameter of descriptor.parameters) requireStrictCodec(parameter.codec, endpoint, parameter.wire); + if (descriptor.invocation.kind === "context") requireStrictCodec(descriptor.invocation.codec, endpoint, descriptor.invocation.wire); + } + function requireStrictCodec(codec, endpoint, field) { + if (codec.mode !== "strict") throw new Error(`client api: generated Remote ${endpoint} field ${JSON.stringify(field)} has no strict codec`); + } + function parse(codec, value, endpoint, field) { + if (codec.mode !== "strict") throw new Error(`client api: generated Remote ${endpoint} field ${JSON.stringify(field)} has no strict codec`); + try { + return codec.schema.parse(value); + } catch (cause) { + throw new Error(`client api: ${endpoint} rejected ${JSON.stringify(field)}`, { cause }); + } + } + /** The namespace retired before or during the call, so no request outcome exists. */ + function withdrawn(endpoint) { + return internalFailure(`client api: Remote method ${endpoint} is no longer mounted`); + } + function carrierFailure(endpoint, error) { + return internalFailure(`client api: ${endpoint} failed: ${error instanceof Error ? error.message : String(error)}`); + } + function internalFailure(message) { + return { + ok: false, + error: { + code: "internal", + message, + details: {} + } + }; + } + //#endregion + exports.apply = apply; + exports.inject = inject; + return module.exports; + } +}); + +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js new file mode 100644 index 0000000..46d091b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js @@ -0,0 +1,396 @@ +import { Service, symbols } from "@deepseek-ai/cordis"; +import { TypertLookupFailure, remoteMethods } from "@deepseek-ai/dsh-typert-protocol"; +//#region lib/types/index.js +/** +* Live Typert Remote dispatch over Cordis Services and registered providers. +* Transport, request correlation, and response envelopes belong to Connection. +* @module @deepseek-ai/dsh-api-gateway +*/ +const NEVER_ABORTED_SIGNAL = new AbortController().signal; +/** Dispatch failure produced outside the invoked business method. */ +var TypertGatewayError = class extends Error { + /** Machine-readable failure category. */ + code; + /** Canonical `/` endpoint. */ + endpoint; + /** Affected wire field when the failure is field-specific. */ + field; + /** + * Construct a Gateway failure without embedding boundary values in its message. + * @param code - stable failure category. + * @param endpoint - canonical Remote endpoint. + * @param message - correction-oriented diagnostic without sensitive values. + * @param options - optional field and contained cause. + */ + constructor(code, endpoint, message, options = {}) { + super(`typert gateway: ${endpoint}: ${message}`, options.cause === void 0 ? void 0 : { cause: options.cause }); + this.name = "TypertGatewayError"; + this.code = code; + this.endpoint = endpoint; + this.field = options.field; + } +}; +/** Business invocation lost its carrier cancellation race. */ +var RemoteInvocationCancelled = class extends Error { + /** + * @param endpoint - canonical Remote endpoint. + * @param cause - business rejection observed after carrier cancellation. + */ + constructor(endpoint, cause) { + super(`Remote invocation "${endpoint}" was aborted`, { cause }); + this.name = "RemoteInvocationCancelled"; + } +}; +/** +* Resolve strict generated definitions or conservative SRC markers against +* current Cordis Services and Typert providers. +* @typert service typertGateway +*/ +var TypertGatewayService = class extends Service { + static inject = ["typert"]; + srcClaims; + /** + * Register the Gateway against the active Typert registry. + * @param ctx - owning Host Context with Typert registry access. + */ + constructor(ctx) { + super(ctx, "typertGateway"); + ctx.on("internal/service", () => { + this.srcClaims = void 0; + }); + ctx.inject(["connection"], (connectionCtx) => { + connectionCtx.connection.rpc.intercept("/api", (endpoint) => this.claimsEndpoint(endpoint), (endpoint, payload, signal) => this.dispatchRpc(endpoint, payload, signal), { authority: "trusted-host" }); + }); + } + claimsEndpoint(endpoint) { + const segments = endpoint.split("/"); + if (segments.length !== 2 || segments[0] === "" || segments[1] === "") return false; + if (this.ctx.typert.local.get(endpoint) !== void 0 || this.ctx.typert.local.hasSeen(endpoint)) return true; + this.srcClaims ??= this.collectSrcClaims(); + return this.srcClaims.has(endpoint); + } + collectSrcClaims() { + const claims = /* @__PURE__ */ new Set(); + for (const [serviceKey, definition] of Object.entries(this.ctx.reflect.props)) { + if (definition.type !== "service") continue; + const receiver = this.ctx.get(serviceKey); + if (!isObject(receiver)) continue; + const original = originalOf(receiver); + const binding = Reflect.get(original, "typertRemote"); + if (!isObject(binding) || typeof Reflect.get(binding, "namespace") !== "string") continue; + const namespace = Reflect.get(binding, "namespace"); + for (const candidate of remoteMethods(original)) claims.add(endpointOf(namespace, candidate.exportName ?? candidate.method)); + } + return claims; + } + /** + * Invoke one live Remote method through strict generated reflection or SRC markers. + * @param request - decoded endpoint and exact named wire arguments. + * @returns the validated business result. + * @throws {@link TypertGatewayError} for dispatch, provider, or boundary failures; lookup-policy and business errors retain identity. + */ + async invoke(request) { + const endpoint = endpointOf(request.namespace, request.method); + const descriptor = this.resolveDescriptor(request.namespace, request.method, endpoint); + assertExactArguments(request.args, descriptor, endpoint); + const receiver = (await this.resolveReceiverContext(descriptor, request.args, endpoint)).get(descriptor.service); + if (!isObject(receiver)) throw new TypertGatewayError("service-unavailable", endpoint, `active Service ${JSON.stringify(descriptor.service)} is unavailable`); + validateBinding(receiver, descriptor.service, descriptor.namespace, endpoint); + const args = await Promise.all(descriptor.parameters.map((parameter) => this.resolveParameter(parameter, request.args, endpoint))); + if (descriptor.cancellation !== void 0) args.push(request.signal ?? NEVER_ABORTED_SIGNAL); + const implementation = descriptor.implementation ?? descriptor.method; + const method = Reflect.get(receiver, implementation); + if (typeof method !== "function") throw new TypertGatewayError("method-unavailable", endpoint, `active Service ${JSON.stringify(descriptor.service)} has no callable method ${JSON.stringify(implementation)}`); + let result; + try { + result = await Reflect.apply(method, receiver, args); + } catch (error) { + if (request.signal?.aborted === true) throw new RemoteInvocationCancelled(endpoint, error); + throw error; + } + if (result === void 0 && descriptor.result.mode !== "strict") return result; + return decode(descriptor.result, result, "result-invalid", endpoint, "result"); + } + async dispatchRpc(endpoint, payload, signal) { + return this.invokeRpc(endpoint, payload, signal); + } + async invokeRpc(endpoint, payload, signal) { + try { + const segments = endpoint.split("/"); + if (segments.length !== 2 || segments[0] === "" || segments[1] === "") throw new Error(`invalid Remote endpoint ${JSON.stringify(endpoint)}`); + const [namespace, method] = segments; + if (!isObject(payload) || !isPlainObject(payload) || Reflect.ownKeys(payload).length !== 1 || !Object.hasOwn(payload, "args") || !isObject(payload.args) || !isPlainObject(payload.args)) throw new Error("Remote payload must contain exactly one plain-object args field"); + return { + ok: true, + value: await this.invoke({ + namespace, + method, + args: payload.args, + signal + }) + }; + } catch (error) { + return rpcFailure(error); + } + } + resolveDescriptor(namespace, method, endpoint) { + const strict = this.ctx.typert.local.get(endpoint); + if (strict !== void 0) return strict; + if (this.ctx.typert.local.hasSeen(endpoint)) throw new TypertGatewayError("definition-unavailable", endpoint, "its strict definition was withdrawn and SRC fallback is forbidden"); + return this.resolveSrcDescriptor(namespace, method, endpoint); + } + resolveSrcDescriptor(namespace, method, endpoint) { + const candidates = []; + for (const [serviceKey, definition] of Object.entries(this.ctx.reflect.props)) { + if (definition.type !== "service") continue; + const receiver = this.ctx.get(serviceKey); + if (!isObject(receiver)) continue; + const original = originalOf(receiver); + const value = Reflect.get(original, "typertRemote"); + if (value === void 0) continue; + const binding = readBinding(value, original, serviceKey, endpoint); + if (binding.namespace !== namespace) continue; + const marker = remoteMethods(original).find((candidate) => (candidate.exportName ?? candidate.method) === method); + if (marker === void 0) continue; + candidates.push(this.srcDescriptor(binding, marker, method, endpoint)); + } + if (candidates.length === 0) throw new TypertGatewayError("invocation-unavailable", endpoint, "no active Remote method exports this endpoint"); + if (candidates.length > 1) throw new TypertGatewayError("ambiguous-endpoint", endpoint, `multiple active Services export this endpoint: ${candidates.map((candidate) => candidate.service).sort().join(", ")}`); + return candidates[0]; + } + srcDescriptor(binding, marker, method, endpoint) { + const names = methodParameterNames(binding.service, marker.method, endpoint); + const signalIndex = names.indexOf("signal"); + if (signalIndex >= 0 && signalIndex !== names.length - 1) throw new TypertGatewayError("signature-invalid", endpoint, "SRC cancellation parameter signal must be the final parameter", { field: "signal" }); + const cancellation = signalIndex >= 0 ? { parameter: "signal" } : void 0; + const businessNames = cancellation === void 0 ? names : names.slice(0, -1); + const parameters = []; + const wires = /* @__PURE__ */ new Set(); + for (const name of businessNames) { + const matches = this.ctx.typert.lookups.definitions().filter((definition) => definition.parameter === name); + if (matches.length > 1) throw new TypertGatewayError("signature-invalid", endpoint, `parameter ${JSON.stringify(name)} matches multiple lookup providers`, { field: name }); + const match = matches[0]; + const parameter = match === void 0 ? { + name, + wire: name, + source: "json", + codec: { mode: "src-json" } + } : { + name, + wire: match.wire, + source: "lookup", + lookup: match.key, + codec: { mode: "src-json" } + }; + if (wires.has(parameter.wire)) throw new TypertGatewayError("signature-invalid", endpoint, `multiple parameters use wire field ${JSON.stringify(parameter.wire)}`, { field: parameter.wire }); + wires.add(parameter.wire); + parameters.push(parameter); + } + let receiver = { kind: "direct" }; + if (marker.invocation.kind === "context") { + const provider = this.ctx.typert.contexts.getHost(marker.invocation.context); + if (provider === void 0) throw new TypertGatewayError("context-unavailable", endpoint, `Context provider ${JSON.stringify(marker.invocation.context)} is unavailable`); + if (wires.has(provider.wire)) throw new TypertGatewayError("signature-invalid", endpoint, `Context identity conflicts with wire field ${JSON.stringify(provider.wire)}`, { field: provider.wire }); + receiver = { + kind: "context", + context: marker.invocation.context, + wire: provider.wire, + codec: { mode: "src-json" } + }; + } + return { + id: `src:${binding.serviceKey}#${endpoint}`, + service: binding.serviceKey, + namespace: binding.namespace, + method, + ...marker.method === method ? {} : { implementation: marker.method }, + invocation: receiver, + parameters, + ...cancellation === void 0 ? {} : { cancellation }, + result: { mode: "src-json" } + }; + } + async resolveReceiverContext(descriptor, args, endpoint) { + if (descriptor.invocation.kind === "direct") return this.ctx; + const invocation = descriptor.invocation; + const provider = this.ctx.typert.contexts.getHost(invocation.context); + if (provider === void 0) throw new TypertGatewayError("context-unavailable", endpoint, `Context provider ${JSON.stringify(invocation.context)} is unavailable`); + if (provider.wire !== invocation.wire || invocation.codec.mode === "strict" && provider.wireTypeSymbol !== invocation.codec.typeSymbol) throw new TypertGatewayError("provider-mismatch", endpoint, `Context provider ${JSON.stringify(invocation.context)} does not match its strict definition`, { field: invocation.wire }); + const identity = decode(invocation.codec, args[invocation.wire], "input-invalid", endpoint, invocation.wire); + let context; + try { + context = await provider.resolve(identity); + } catch (cause) { + if (cause instanceof TypertLookupFailure) throw cause; + throw new TypertGatewayError("context-failed", endpoint, `Context provider ${JSON.stringify(invocation.context)} failed`, { + cause, + field: invocation.wire + }); + } + if (context === void 0) throw new TypertGatewayError("context-not-found", endpoint, `Context provider ${JSON.stringify(invocation.context)} did not resolve the requested identity`, { field: invocation.wire }); + return context; + } + async resolveParameter(parameter, args, endpoint) { + if (!Object.hasOwn(args, parameter.wire)) return void 0; + const value = decode(parameter.codec, args[parameter.wire], "input-invalid", endpoint, parameter.wire); + if (parameter.source === "json") return value; + const key = parameter.lookup; + /* v8 ignore next -- registry validation rejects strict descriptors without a key, and SRC derivation always supplies one. */ + if (key === void 0) throw new TypertGatewayError("lookup-unavailable", endpoint, `lookup parameter ${JSON.stringify(parameter.name)} has no provider key`, { field: parameter.wire }); + const provider = this.ctx.typert.lookups.get(key); + if (provider === void 0) throw new TypertGatewayError("lookup-unavailable", endpoint, `lookup provider ${JSON.stringify(key)} is unavailable`, { field: parameter.wire }); + if (provider.wire !== parameter.wire || parameter.codec.mode === "strict" && provider.wireTypeSymbol !== parameter.codec.typeSymbol) throw new TypertGatewayError("provider-mismatch", endpoint, `lookup provider ${JSON.stringify(key)} does not match its strict definition`, { field: parameter.wire }); + let resolved; + try { + resolved = await provider.resolve(value); + } catch (cause) { + if (cause instanceof TypertLookupFailure) throw cause; + throw new TypertGatewayError("lookup-failed", endpoint, `lookup provider ${JSON.stringify(key)} failed`, { + cause, + field: parameter.wire + }); + } + if (resolved === void 0) throw new TypertGatewayError("lookup-not-found", endpoint, `lookup provider ${JSON.stringify(key)} did not resolve the requested identity`, { field: parameter.wire }); + return resolved; + } +}; +function rpcFailure(error) { + if (error instanceof RemoteInvocationCancelled) return { + ok: false, + error: { + code: "cancelled", + message: error.message, + details: {} + } + }; + if (error instanceof TypertLookupFailure) return { + ok: false, + error: error.failure + }; + return { + ok: false, + error: { + code: "internal", + message: error instanceof Error ? error.message : String(error), + details: {} + } + }; +} +function endpointOf(namespace, method) { + return `${namespace}/${method}`; +} +function validateBinding(receiver, serviceKey, namespace, endpoint) { + const original = originalOf(receiver); + const value = Reflect.get(original, "typertRemote"); + if (value === void 0) throw new TypertGatewayError("binding-invalid", endpoint, `Service ${JSON.stringify(serviceKey)} has no visible typertRemote binding`); + return { + binding: readBinding(value, original, serviceKey, endpoint, namespace), + original + }; +} +function readBinding(value, original, serviceKey, endpoint, namespace) { + if (!isObject(value) || Reflect.get(value, "service") !== original || Reflect.get(value, "serviceKey") !== serviceKey || typeof Reflect.get(value, "namespace") !== "string" || namespace !== void 0 && Reflect.get(value, "namespace") !== namespace) throw new TypertGatewayError("binding-invalid", endpoint, `Service ${JSON.stringify(serviceKey)} has an inconsistent typertRemote binding`); + return value; +} +function originalOf(receiver) { + const original = Reflect.get(receiver, symbols.original); + return isObject(original) ? original : receiver; +} +function methodParameterNames(service, method, endpoint) { + let prototype = Object.getPrototypeOf(service); + let implementation; + while (prototype !== null) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, method); + if (descriptor !== void 0) { + if ("value" in descriptor && typeof descriptor.value === "function") implementation = descriptor.value; + break; + } + prototype = Object.getPrototypeOf(prototype); + } + if (implementation === void 0) throw new TypertGatewayError("method-unavailable", endpoint, `Remote marker has no prototype method ${JSON.stringify(method)}`); + const source = Function.prototype.toString.call(implementation); + const open = source.indexOf("("); + const close = source.indexOf(")", open + 1); + /* v8 ignore next -- standard public class-method syntax always contains a parenthesized parameter list. */ + if (open < 0 || close < 0) return invalidSignature(endpoint, method); + const body = source.slice(open + 1, close).trim(); + if (body.length === 0) return []; + const parts = body.split(",").map((part) => part.trim()); + const names = /* @__PURE__ */ new Set(); + for (const part of parts) { + if (!/^[$A-Z_a-z][$\w]*$/u.test(part) || names.has(part)) return invalidSignature(endpoint, method); + names.add(part); + } + return [...names]; +} +function invalidSignature(endpoint, method) { + throw new TypertGatewayError("signature-invalid", endpoint, `SRC method ${JSON.stringify(method)} must use unique identifier parameters without destructuring, defaults, or rest`); +} +function assertExactArguments(args, descriptor, endpoint) { + if (!isPlainObject(args)) throw new TypertGatewayError("arguments-invalid", endpoint, "args must be a plain object"); + const expected = new Set(descriptor.parameters.map((parameter) => parameter.wire)); + if (descriptor.invocation.kind === "context") expected.add(descriptor.invocation.wire); + const extra = Reflect.ownKeys(args).filter((key) => typeof key !== "string" || !expected.has(key)); + const acceptsMissing = new Set(descriptor.parameters.filter((parameter) => parameter.source === "json" && (parameter.acceptsUndefined === true || parameter.codec.mode === "src-json")).map((parameter) => parameter.wire)); + const missing = [...expected].filter((key) => !Object.hasOwn(args, key) && !acceptsMissing.has(key)); + if (extra.length === 0 && missing.length === 0) return; + const clauses = []; + if (missing.length > 0) clauses.push(`missing ${missing.map((key) => JSON.stringify(key)).join(", ")}`); + if (extra.length > 0) clauses.push(`unexpected ${extra.map((key) => JSON.stringify(String(key))).join(", ")}`); + throw new TypertGatewayError("arguments-invalid", endpoint, `args fields do not match the descriptor: ${clauses.join("; ")}`); +} +function decode(codec, value, code, endpoint, field) { + try { + if (codec.mode === "strict") { + value = codec.schema.parse(value); + if (value === void 0) return value; + } + assertJsonValue(value, /* @__PURE__ */ new Set()); + return value; + } catch (cause) { + throw new TypertGatewayError(code, endpoint, code === "input-invalid" ? `wire field ${JSON.stringify(field)} failed boundary validation` : "business result failed boundary validation", { + cause, + field + }); + } +} +function assertJsonValue(value, ancestors) { + if (value === null || typeof value === "string" || typeof value === "boolean") return; + if (typeof value === "number") { + if (Number.isFinite(value)) return; + throw new TypeError("non-finite number is not JSON-safe"); + } + if (!isObject(value)) throw new TypeError(`${typeof value} is not JSON-safe`); + if (ancestors.has(value)) throw new TypeError("cyclic value is not JSON-safe"); + ancestors.add(value); + try { + if (Array.isArray(value)) { + if (Object.getOwnPropertySymbols(value).length > 0 || Object.keys(value).length !== value.length) throw new TypeError("sparse or decorated array is not JSON-safe"); + for (let index = 0; index < value.length; index += 1) { + if (!Object.hasOwn(value, index)) throw new TypeError("sparse array is not JSON-safe"); + assertJsonValue(value[index], ancestors); + } + return; + } + if (!isPlainObject(value)) throw new TypeError("non-plain object is not JSON-safe"); + if (Object.getOwnPropertySymbols(value).length > 0) throw new TypeError("symbol property is not JSON-safe"); + for (const key of Reflect.ownKeys(value)) { + const descriptor = Object.getOwnPropertyDescriptor(value, key); + /* v8 ignore next -- ownKeys() just returned this key; only a hostile same-process Proxy can delete it between operations. */ + if (descriptor === void 0 || !descriptor.enumerable || !("value" in descriptor)) throw new TypeError("non-data property is not JSON-safe"); + assertJsonValue(descriptor.value, ancestors); + } + } finally { + ancestors.delete(value); + } +} +function isPlainObject(value) { + if (Array.isArray(value)) return false; + const prototype = Object.getPrototypeOf(value); + return prototype === null || prototype === Object.prototype; +} +function isObject(value) { + return typeof value === "object" && value !== null || typeof value === "function"; +} +//#endregion +export { TypertGatewayError, TypertGatewayService, TypertGatewayService as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/invariant.js new file mode 100644 index 0000000..842ac5d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/invariant.js @@ -0,0 +1,24 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-api-gateway`. +* @module @deepseek-ai/dsh-api-gateway/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-api-gateway"; +/** Cordis companion plugin name. */ +const name = "api-gateway-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: Host calls re-read authoritative Cordis and Typert +* state, while Client methods, descriptors, and `$on` subscriptions mutate in +* one owned effect. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.d.ts new file mode 100644 index 0000000..8b61c7a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.d.ts @@ -0,0 +1,23 @@ +/** + * Client projection of generated Typert Remote descriptors. Contributions + * install traced `remote.` services; no JavaScript Proxy + * participates in method lookup, invocation, or type exposure. + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { TypertClientRemote } from '@deepseek-ai/dsh-typert-protocol'; +/** Typed Remote service augmented by generated direct namespaces. */ +export type ClientRemote = TypertClientRemote; +declare module '@deepseek-ai/cordis' { + interface Context { + /** Generated Remote namespaces selected by the Client assembly. */ + remote: ClientRemote; + } +} +/** Required Client services: the Typert registry and the existing Connection carrier. */ +export declare const inject: string[]; +/** + * Install the typed Client Remote service. + * @param ctx - Client Cordis root. + */ +export declare function apply(ctx: Context): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.js new file mode 100644 index 0000000..334b5a9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/client/index.js @@ -0,0 +1,467 @@ +/** + * Client projection of generated Typert Remote descriptors. Contributions + * install traced `remote.` services; no JavaScript Proxy + * participates in method lookup, invocation, or type exposure. + */ +import { Service } from '@deepseek-ai/cordis'; +/** Required Client services: the Typert registry and the existing Connection carrier. */ +export const inject = ['typert', 'connection']; +/** + * Install the typed Client Remote service. + * @param ctx - Client Cordis root. + */ +export function apply(ctx) { + new ClientRemoteService(ctx); +} +class ClientRemoteService extends Service { + ownerCtx; + namespaces = new Map(); + subscriptions = new Map(); + mutations = Promise.resolve(); + constructor(ctx) { + super(ctx, 'remote'); + this.ownerCtx = ctx; + ctx.effect(() => () => { this.subscriptions.clear(); }, 'api-gateway.client.subscriptions'); + } + async $mount(contribution) { + const callerCtx = this.ctx; + const owned = callerCtx.effect(async () => { + const dispose = await this.enqueue(() => this.mountContribution(callerCtx, contribution)); + return () => this.enqueue(dispose); + }, `api-gateway.client.$mount(${JSON.stringify(contribution.package)})`); + await owned; + return async () => { await owned(); }; + } + $on(event, listener) { + // The table is keyed by the runtime event name, so the argument list this + // signature pins per event cannot survive in it; `$deliver` restores it + // from the frame the Host emitted for that same name. + const subscription = { listener }; + const owned = this.ctx.effect(() => { + const listeners = this.listeners(event); + listeners.push(subscription); + return () => { + const at = listeners.indexOf(subscription); + /* v8 ignore next -- listener */ + if (at >= 0) + listeners.splice(at, 1); + }; + }, `api-gateway.client.$on(${JSON.stringify(event)})`); + return () => { void owned(); }; + } + /** + * Deliver one forwarded event in registration order, isolating a listener + * that fails either synchronously or by rejecting a returned promise; see + * {@link TypertClientRemote.$dispatch} for the caller contract. + */ + $dispatch(event, args) { + const listeners = this.subscriptions.get(event); + if (listeners === undefined) + return; + // Snapshot: a listener may subscribe or dispose during delivery, and this + // round's recipients are the ones registered when the frame arrived. + for (const { listener } of [...listeners]) { + const report = (error) => { + console.error(`client api: Remote event ${JSON.stringify(event)} listener threw:`, error); + }; + try { + /* oxlint-disable-next-line typescript/no-confusing-void-expression -- + * The declared return is void, so nobody awaits an async listener; the + * runtime value is still a promise, and reading it is the only way to + * keep its rejection inside this containment instead of surfacing as an + * unhandled one. */ + const settled = listener(...args); + if (settled instanceof Promise) + settled.catch(report); + } + catch (error) { + report(error); + } + } + } + /** Subscriptions for one event name; empty arrays are retained, bounded by the Host's selection. */ + listeners(event) { + let listeners = this.subscriptions.get(event); + if (listeners === undefined) { + listeners = []; + this.subscriptions.set(event, listeners); + } + return listeners; + } + enqueue(operation) { + const result = this.mutations.then(operation, operation); + this.mutations = result.then(() => undefined, () => undefined); + return result; + } + async mountContribution(callerCtx, contribution) { + this.validateContribution(contribution); + const disposeRemote = callerCtx.typert.remotes.register(contribution); + const installed = []; + try { + for (const descriptor of contribution.descriptors) + installed.push(await this.install(descriptor)); + } + catch (error) { + for (const dispose of installed.reverse()) + await dispose(); + await disposeRemote(); + throw error; + } + return async () => { + for (const dispose of installed.reverse()) + await dispose(); + await disposeRemote(); + }; + } + validateContribution(contribution) { + const direct = new Map(); + const scoped = new Map(); + const add = (table, descriptor, kind) => { + const methods = table.get(descriptor.namespace) ?? new Set(); + if (methods.has(descriptor.method)) { + throw new Error(`client api: contribution repeats ${kind} method ${endpointOf(descriptor)}`); + } + methods.add(descriptor.method); + table.set(descriptor.namespace, methods); + const namespace = this.namespaces.get(descriptor.namespace)?.service; + if (namespace?.has(kind, descriptor.method) === true) { + throw new Error(`client api: ${kind} method ${endpointOf(descriptor)} is already mounted`); + } + }; + for (const descriptor of contribution.descriptors) { + requireStrictDescriptor(descriptor); + if (descriptor.invocation.kind === 'direct') + add(direct, descriptor, 'direct'); + if (scopedProjection(descriptor) !== undefined) + add(scoped, descriptor, 'scoped'); + } + const namespaces = new Set([...direct.keys(), ...scoped.keys()]); + for (const namespace of namespaces) { + const service = this.namespaces.get(namespace)?.service; + if (service === undefined) { + if (namespace in this) { + throw new Error(`client api: namespace ${JSON.stringify(namespace)} conflicts with the Remote service`); + } + const serviceKey = remoteServiceKey(namespace); + const property = this.ownerCtx.reflect.props[serviceKey]; + if (property?.type === 'accessor' || this.ownerCtx.get(serviceKey) !== undefined) { + throw new Error(`client api: namespace ${JSON.stringify(namespace)} conflicts with an existing Remote namespace`); + } + } + for (const method of new Set([...(direct.get(namespace) ?? []), ...(scoped.get(namespace) ?? [])])) { + if (service === undefined) + RemoteNamespaceService.assertMethodAvailable(namespace, method); + else + service.assertMethodAvailable(method); + } + } + } + async install(descriptor) { + const token = { active: true, abort: new AbortController() }; + const installed = []; + try { + if (descriptor.invocation.kind === 'direct') { + installed.push(await this.installDirect(descriptor, token)); + } + const projection = scopedProjection(descriptor); + if (projection !== undefined) + installed.push(await this.installScoped(descriptor, projection, token)); + } + catch (error) { + token.active = false; + token.abort.abort(); + for (const dispose of installed.reverse()) + await dispose(); + throw error; + } + return async () => { + /* v8 ignore next -- Cordis effect disposers are idempotent and invoke this cleanup at most once. */ + if (!token.active) + return; + token.active = false; + token.abort.abort(); + for (const dispose of installed.reverse()) + await dispose(); + }; + } + async installDirect(descriptor, token) { + const namespace = await this.namespace(descriptor.namespace); + try { + namespace.service.installDirect(descriptor, token); + } + catch (error) { + await this.disposeNamespace(descriptor.namespace, namespace); + throw error; + } + return async () => { + namespace.service.remove('direct', descriptor.method, token); + await this.disposeNamespace(descriptor.namespace, namespace); + }; + } + async installScoped(descriptor, projection, token) { + const namespace = await this.namespace(descriptor.namespace); + try { + namespace.service.installScoped(descriptor, projection, token); + } + catch (error) { + await this.disposeNamespace(descriptor.namespace, namespace); + throw error; + } + return async () => { + namespace.service.remove('scoped', descriptor.method, token); + await this.disposeNamespace(descriptor.namespace, namespace); + }; + } + async namespace(name) { + let namespace = this.namespaces.get(name); + if (namespace !== undefined) + return namespace; + let service; + const fiber = this.ownerCtx.plugin({ + name: remoteServiceKey(name), + apply: (ctx) => { + service = new RemoteNamespaceService(ctx, name, (direct, scoped, caller, args) => this.invokeMethod(direct, scoped, caller, args)); + }, + }); + try { + await fiber; + } + catch (error) { + await fiber.dispose(); + throw error; + } + /* v8 ignore next -- a settled namespace fiber synchronously constructs its Service. */ + if (service === undefined) + throw new Error(`client api: namespace ${JSON.stringify(name)} did not start`); + namespace = { service, dispose: fiber.dispose }; + this.namespaces.set(name, namespace); + return namespace; + } + async disposeNamespace(name, namespace) { + if (!namespace.service.empty || this.namespaces.get(name) !== namespace) + return; + this.namespaces.delete(name); + await namespace.dispose(); + } + invokeMethod(direct, scoped, callerCtx, values) { + if (scoped !== undefined) { + const binder = this.ownerCtx.typert.contexts.getClient(scoped.projection.context); + const identity = binder?.identity(callerCtx); + if (identity !== undefined) { + return this.invoke(scoped.descriptor, scoped.projection, scoped.token, callerCtx, values, { value: identity }); + } + } + if (direct !== undefined) { + return this.invoke(direct.descriptor, undefined, direct.token, callerCtx, values); + } + if (scoped !== undefined) { + return this.invoke(scoped.descriptor, scoped.projection, scoped.token, callerCtx, values); + } + throw new Error('client api: Remote method is no longer mounted'); + } + async invoke(descriptor, projection, token, callerCtx, values, boundIdentity) { + const endpoint = endpointOf(descriptor); + if (!token.active) + return withdrawn(endpoint); + const expected = descriptor.parameters.length - (projection?.parameterIndex === undefined ? 0 : 1); + const hasCallerSignal = descriptor.cancellation !== undefined && values.length === expected + 1; + if (values.length !== expected && !hasCallerSignal) { + const contract = descriptor.cancellation === undefined + ? `${String(expected)} argument(s)` + : `${String(expected)} business argument(s) plus an optional AbortSignal`; + throw new Error(`client api: ${endpoint} expected ${contract}, got ${String(values.length)}`); + } + const args = Object.create(null); + if (projection !== undefined) { + const binder = boundIdentity === undefined + ? this.ownerCtx.typert.contexts.getClient(projection.context) + : undefined; + if (boundIdentity === undefined && binder === undefined) { + throw new Error(`client api: ${endpoint} has no Client Context binder for ${JSON.stringify(projection.context)}`); + } + const identity = boundIdentity === undefined + ? binder?.identity(callerCtx) + : boundIdentity.value; + if (identity === undefined) { + throw new Error(`client api: ${endpoint} requires a ${JSON.stringify(projection.context)} Context`); + } + args[projection.wire] = parse(projection.codec, identity, endpoint, projection.wire); + } + let valueIndex = 0; + descriptor.parameters.forEach((parameter, parameterIndex) => { + if (parameterIndex === projection?.parameterIndex) + return; + const value = parse(parameter.codec, values[valueIndex], endpoint, parameter.wire); + if (value !== undefined) + args[parameter.wire] = value; + valueIndex += 1; + }); + const connection = this.ownerCtx.get('connection'); + if (connection === undefined) + throw new Error(`client api: ${endpoint} has no active Connection`); + const callerSignal = hasCallerSignal ? values[expected] : undefined; + const signal = callerSignal === undefined + ? token.abort.signal + : AbortSignal.any([token.abort.signal, callerSignal]); + try { + const result = await connection.rpc.call('/api', endpoint, { args }, signal); + if (!mountActive(token)) + return withdrawn(endpoint); + if (!result.ok) + return { ok: false, error: result.error }; + return { ok: true, value: parse(descriptor.result, result.value, endpoint, 'result') }; + } + catch (error) { + // Carrier throws (offline, abort, a rejected result payload) are outcomes + // of the call, not assembly faults, so they join the same error branch. + return carrierFailure(endpoint, error); + } + } +} +class RemoteNamespaceService extends Service { + invokeRemote; + methods = new Map(); + namespace; + static assertMethodAvailable(namespace, method) { + if (REMOTE_NAMESPACE_FIELDS.has(method) || method in RemoteNamespaceService.prototype) { + throw new Error(`client api: method ${JSON.stringify(`${namespace}/${method}`)} conflicts with its namespace service`); + } + } + constructor(ctx, name, invokeRemote) { + super(ctx, remoteServiceKey(name)); + this.invokeRemote = invokeRemote; + this.namespace = name; + } + assertMethodAvailable(method) { + RemoteNamespaceService.assertMethodAvailable(this.namespace, method); + if (method in this && !this.methods.has(method)) { + throw new Error(`client api: method ${JSON.stringify(`${this.namespace}/${method}`)} conflicts with its namespace service`); + } + } + get empty() { + return this.methods.size === 0; + } + has(kind, method) { + return this.methods.get(method)?.[kind] !== undefined; + } + installDirect(descriptor, token) { + this.install(descriptor.method, 'direct', { descriptor, token }); + } + installScoped(descriptor, projection, token) { + this.install(descriptor.method, 'scoped', { descriptor, projection, token }); + } + install(method, kind, value) { + this.assertMethodAvailable(method); + let record = this.methods.get(method); + const fresh = record === undefined; + record ??= {}; + if (fresh) { + Object.defineProperty(this, method, { + configurable: true, + enumerable: true, + get: function () { + const callerCtx = this.ctx; + const current = this.methods.get(method); + const direct = current?.direct; + const scoped = current?.scoped; + return (...args) => { + return this.invokeRemote(direct, scoped, callerCtx, args); + }; + }, + }); + this.methods.set(method, record); + } + if (kind === 'direct') + record.direct = value; + else + record.scoped = value; + } + remove(kind, method, token) { + const record = this.methods.get(method); + const current = record?.[kind]; + /* v8 ignore next -- duplicate live variants are rejected before installation, so no newer token can replace this one. */ + if (record === undefined || current?.token !== token) + return; + if (kind === 'direct') + delete record.direct; + else + delete record.scoped; + if (record.direct !== undefined || record.scoped !== undefined) + return; + this.methods.delete(method); + Reflect.deleteProperty(this, method); + } +} +const REMOTE_NAMESPACE_FIELDS = new Set(['ctx', 'empty', 'invokeRemote', 'methods', 'name', 'namespace']); +function remoteServiceKey(namespace) { + return `remote.${namespace}`; +} +function endpointOf(descriptor) { + return `${descriptor.namespace}/${descriptor.method}`; +} +function mountActive(token) { + return token.active; +} +function scopedProjection(descriptor) { + if (descriptor.invocation.kind === 'context') { + return { + context: descriptor.invocation.context, + wire: descriptor.invocation.wire, + codec: descriptor.invocation.codec, + }; + } + if (descriptor.scope === undefined) + return undefined; + const lookupParameters = descriptor.parameters + .map((parameter, index) => ({ parameter, index })) + .filter(candidate => candidate.parameter.source === 'lookup'); + const selected = lookupParameters.length === 1 ? lookupParameters[0] : undefined; + if (selected === undefined + || selected.parameter.wire !== descriptor.scope.wire + || selected.parameter.lookup !== descriptor.scope.context) { + throw new Error(`client api: generated Remote ${endpointOf(descriptor)} scope must select its only lookup parameter`); + } + return { + context: descriptor.scope.context, + wire: descriptor.scope.wire, + codec: selected.parameter.codec, + parameterIndex: selected.index, + }; +} +function requireStrictDescriptor(descriptor) { + const endpoint = endpointOf(descriptor); + requireStrictCodec(descriptor.result, endpoint, 'result'); + for (const parameter of descriptor.parameters) { + requireStrictCodec(parameter.codec, endpoint, parameter.wire); + } + if (descriptor.invocation.kind === 'context') { + requireStrictCodec(descriptor.invocation.codec, endpoint, descriptor.invocation.wire); + } +} +function requireStrictCodec(codec, endpoint, field) { + if (codec.mode !== 'strict') { + throw new Error(`client api: generated Remote ${endpoint} field ${JSON.stringify(field)} has no strict codec`); + } +} +function parse(codec, value, endpoint, field) { + if (codec.mode !== 'strict') { + throw new Error(`client api: generated Remote ${endpoint} field ${JSON.stringify(field)} has no strict codec`); + } + try { + return codec.schema.parse(value); + } + catch (cause) { + throw new Error(`client api: ${endpoint} rejected ${JSON.stringify(field)}`, { cause }); + } +} +/** The namespace retired before or during the call, so no request outcome exists. */ +function withdrawn(endpoint) { + return internalFailure(`client api: Remote method ${endpoint} is no longer mounted`); +} +function carrierFailure(endpoint, error) { + return internalFailure(`client api: ${endpoint} failed: ${error instanceof Error ? error.message : String(error)}`); +} +function internalFailure(message) { + return { ok: false, error: { code: 'internal', message, details: {} } }; +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.d.ts new file mode 100644 index 0000000..ff0ae63 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.d.ts @@ -0,0 +1,61 @@ +/** + * Live Typert Remote dispatch over Cordis Services and registered providers. + * Transport, request correlation, and response envelopes belong to Connection. + * @module @deepseek-ai/dsh-api-gateway + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { InvokeRemoteRequest, TypertGateway, TypertGatewayErrorCode } from './types.ts'; +export type { InvokeRemoteRequest, TypertGateway, TypertGatewayErrorCode, } from './types.ts'; +interface GatewayErrorOptions { + readonly cause?: unknown; + readonly field?: string; +} +/** Dispatch failure produced outside the invoked business method. */ +export declare class TypertGatewayError extends Error { + /** Machine-readable failure category. */ + readonly code: TypertGatewayErrorCode; + /** Canonical `/` endpoint. */ + readonly endpoint: string; + /** Affected wire field when the failure is field-specific. */ + readonly field: string | undefined; + /** + * Construct a Gateway failure without embedding boundary values in its message. + * @param code - stable failure category. + * @param endpoint - canonical Remote endpoint. + * @param message - correction-oriented diagnostic without sensitive values. + * @param options - optional field and contained cause. + */ + constructor(code: TypertGatewayErrorCode, endpoint: string, message: string, options?: GatewayErrorOptions); +} +/** + * Resolve strict generated definitions or conservative SRC markers against + * current Cordis Services and Typert providers. + * @typert service typertGateway + */ +export declare class TypertGatewayService extends Service implements TypertGateway { + static inject: string[]; + private srcClaims; + /** + * Register the Gateway against the active Typert registry. + * @param ctx - owning Host Context with Typert registry access. + */ + constructor(ctx: Context); + private claimsEndpoint; + private collectSrcClaims; + /** + * Invoke one live Remote method through strict generated reflection or SRC markers. + * @param request - decoded endpoint and exact named wire arguments. + * @returns the validated business result. + * @throws {@link TypertGatewayError} for dispatch, provider, or boundary failures; lookup-policy and business errors retain identity. + */ + invoke(request: InvokeRemoteRequest): Promise; + private dispatchRpc; + private invokeRpc; + private resolveDescriptor; + private resolveSrcDescriptor; + private srcDescriptor; + private resolveReceiverContext; + private resolveParameter; +} +export default TypertGatewayService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.js new file mode 100644 index 0000000..37202a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/index.js @@ -0,0 +1,508 @@ +/** + * Live Typert Remote dispatch over Cordis Services and registered providers. + * Transport, request correlation, and response envelopes belong to Connection. + * @module @deepseek-ai/dsh-api-gateway + */ +import { Service, symbols } from '@deepseek-ai/cordis'; +import { remoteMethods, TypertLookupFailure, } from '@deepseek-ai/dsh-typert-protocol'; +const NEVER_ABORTED_SIGNAL = new AbortController().signal; +/** Dispatch failure produced outside the invoked business method. */ +export class TypertGatewayError extends Error { + /** Machine-readable failure category. */ + code; + /** Canonical `/` endpoint. */ + endpoint; + /** Affected wire field when the failure is field-specific. */ + field; + /** + * Construct a Gateway failure without embedding boundary values in its message. + * @param code - stable failure category. + * @param endpoint - canonical Remote endpoint. + * @param message - correction-oriented diagnostic without sensitive values. + * @param options - optional field and contained cause. + */ + constructor(code, endpoint, message, options = {}) { + super(`typert gateway: ${endpoint}: ${message}`, options.cause === undefined ? undefined : { cause: options.cause }); + this.name = 'TypertGatewayError'; + this.code = code; + this.endpoint = endpoint; + this.field = options.field; + } +} +/** Business invocation lost its carrier cancellation race. */ +class RemoteInvocationCancelled extends Error { + /** + * @param endpoint - canonical Remote endpoint. + * @param cause - business rejection observed after carrier cancellation. + */ + constructor(endpoint, cause) { + super(`Remote invocation "${endpoint}" was aborted`, { cause }); + this.name = 'RemoteInvocationCancelled'; + } +} +/** + * Resolve strict generated definitions or conservative SRC markers against + * current Cordis Services and Typert providers. + * @typert service typertGateway + */ +export class TypertGatewayService extends Service { + static inject = ['typert']; + srcClaims; + /** + * Register the Gateway against the active Typert registry. + * @param ctx - owning Host Context with Typert registry access. + */ + constructor(ctx) { + super(ctx, 'typertGateway'); + ctx.on('internal/service', () => { + this.srcClaims = undefined; + }); + ctx.inject(['connection'], (connectionCtx) => { + connectionCtx.connection.rpc.intercept('/api', endpoint => this.claimsEndpoint(endpoint), (endpoint, payload, signal) => this.dispatchRpc(endpoint, payload, signal), { authority: 'trusted-host' }); + }); + } + claimsEndpoint(endpoint) { + const segments = endpoint.split('/'); + if (segments.length !== 2 || segments[0] === '' || segments[1] === '') + return false; + if (this.ctx.typert.local.get(endpoint) !== undefined || this.ctx.typert.local.hasSeen(endpoint)) + return true; + this.srcClaims ??= this.collectSrcClaims(); + return this.srcClaims.has(endpoint); + } + collectSrcClaims() { + const claims = new Set(); + for (const [serviceKey, definition] of Object.entries(this.ctx.reflect.props)) { + if (definition.type !== 'service') + continue; + const receiver = this.ctx.get(serviceKey); + if (!isObject(receiver)) + continue; + const original = originalOf(receiver); + const binding = Reflect.get(original, 'typertRemote'); + if (!isObject(binding) || typeof Reflect.get(binding, 'namespace') !== 'string') + continue; + const namespace = Reflect.get(binding, 'namespace'); + for (const candidate of remoteMethods(original)) { + claims.add(endpointOf(namespace, candidate.exportName ?? candidate.method)); + } + } + return claims; + } + /** + * Invoke one live Remote method through strict generated reflection or SRC markers. + * @param request - decoded endpoint and exact named wire arguments. + * @returns the validated business result. + * @throws {@link TypertGatewayError} for dispatch, provider, or boundary failures; lookup-policy and business errors retain identity. + */ + async invoke(request) { + const endpoint = endpointOf(request.namespace, request.method); + const descriptor = this.resolveDescriptor(request.namespace, request.method, endpoint); + assertExactArguments(request.args, descriptor, endpoint); + const receiverContext = await this.resolveReceiverContext(descriptor, request.args, endpoint); + const receiver = receiverContext.get(descriptor.service); + if (!isObject(receiver)) { + throw new TypertGatewayError('service-unavailable', endpoint, `active Service ${JSON.stringify(descriptor.service)} is unavailable`); + } + validateBinding(receiver, descriptor.service, descriptor.namespace, endpoint); + const args = await Promise.all(descriptor.parameters.map(parameter => this.resolveParameter(parameter, request.args, endpoint))); + if (descriptor.cancellation !== undefined) + args.push(request.signal ?? NEVER_ABORTED_SIGNAL); + const implementation = descriptor.implementation ?? descriptor.method; + const method = Reflect.get(receiver, implementation); + if (typeof method !== 'function') { + throw new TypertGatewayError('method-unavailable', endpoint, `active Service ${JSON.stringify(descriptor.service)} has no callable method ${JSON.stringify(implementation)}`); + } + let result; + try { + result = await Reflect.apply(method, receiver, args); + } + catch (error) { + if (request.signal?.aborted === true) + throw new RemoteInvocationCancelled(endpoint, error); + throw error; + } + // A weak descriptor declares no return type, so nothing returned is a void + // result and rides the wire as an absent value field. A strict descriptor + // keeps its schema: there, undefined has to be a declared result. + if (result === undefined && descriptor.result.mode !== 'strict') + return result; + return decode(descriptor.result, result, 'result-invalid', endpoint, 'result'); + } + async dispatchRpc(endpoint, payload, signal) { + return this.invokeRpc(endpoint, payload, signal); + } + async invokeRpc(endpoint, payload, signal) { + try { + const segments = endpoint.split('/'); + if (segments.length !== 2 || segments[0] === '' || segments[1] === '') { + throw new Error(`invalid Remote endpoint ${JSON.stringify(endpoint)}`); + } + const [namespace, method] = segments; + if (!isObject(payload) + || !isPlainObject(payload) + || Reflect.ownKeys(payload).length !== 1 + || !Object.hasOwn(payload, 'args') + || !isObject(payload.args) + || !isPlainObject(payload.args)) { + throw new Error('Remote payload must contain exactly one plain-object args field'); + } + const value = await this.invoke({ + namespace, + method, + args: payload.args, + signal, + }); + // A void or explicitly absent business result carries no `value` field; + // JSON has no `undefined`, and the envelope's optional slot is the one + // representation of absence that both args and results already use. + return { ok: true, value }; + } + catch (error) { + return rpcFailure(error); + } + } + resolveDescriptor(namespace, method, endpoint) { + const strict = this.ctx.typert.local.get(endpoint); + if (strict !== undefined) + return strict; + if (this.ctx.typert.local.hasSeen(endpoint)) { + throw new TypertGatewayError('definition-unavailable', endpoint, 'its strict definition was withdrawn and SRC fallback is forbidden'); + } + return this.resolveSrcDescriptor(namespace, method, endpoint); + } + resolveSrcDescriptor(namespace, method, endpoint) { + const candidates = []; + for (const [serviceKey, definition] of Object.entries(this.ctx.reflect.props)) { + if (definition.type !== 'service') + continue; + const receiver = this.ctx.get(serviceKey); + if (!isObject(receiver)) + continue; + const original = originalOf(receiver); + const value = Reflect.get(original, 'typertRemote'); + if (value === undefined) + continue; + const binding = readBinding(value, original, serviceKey, endpoint); + if (binding.namespace !== namespace) + continue; + const marker = remoteMethods(original).find(candidate => (candidate.exportName ?? candidate.method) === method); + if (marker === undefined) + continue; + candidates.push(this.srcDescriptor(binding, marker, method, endpoint)); + } + if (candidates.length === 0) { + throw new TypertGatewayError('invocation-unavailable', endpoint, 'no active Remote method exports this endpoint'); + } + if (candidates.length > 1) { + throw new TypertGatewayError('ambiguous-endpoint', endpoint, `multiple active Services export this endpoint: ${candidates.map(candidate => candidate.service).sort().join(', ')}`); + } + return candidates[0]; + } + srcDescriptor(binding, marker, method, endpoint) { + const names = methodParameterNames(binding.service, marker.method, endpoint); + const signalIndex = names.indexOf('signal'); + if (signalIndex >= 0 && signalIndex !== names.length - 1) { + throw new TypertGatewayError('signature-invalid', endpoint, 'SRC cancellation parameter signal must be the final parameter', { field: 'signal' }); + } + const cancellation = signalIndex >= 0 + ? { parameter: 'signal' } + : undefined; + const businessNames = cancellation === undefined ? names : names.slice(0, -1); + const parameters = []; + const wires = new Set(); + for (const name of businessNames) { + const matches = this.ctx.typert.lookups.definitions() + .filter(definition => definition.parameter === name); + if (matches.length > 1) { + throw new TypertGatewayError('signature-invalid', endpoint, `parameter ${JSON.stringify(name)} matches multiple lookup providers`, { field: name }); + } + const match = matches[0]; + const parameter = match === undefined + ? { name, wire: name, source: 'json', codec: { mode: 'src-json' } } + : { + name, + wire: match.wire, + source: 'lookup', + lookup: match.key, + codec: { mode: 'src-json' }, + }; + if (wires.has(parameter.wire)) { + throw new TypertGatewayError('signature-invalid', endpoint, `multiple parameters use wire field ${JSON.stringify(parameter.wire)}`, { field: parameter.wire }); + } + wires.add(parameter.wire); + parameters.push(parameter); + } + let receiver = { kind: 'direct' }; + if (marker.invocation.kind === 'context') { + const provider = this.ctx.typert.contexts.getHost(marker.invocation.context); + if (provider === undefined) { + throw new TypertGatewayError('context-unavailable', endpoint, `Context provider ${JSON.stringify(marker.invocation.context)} is unavailable`); + } + if (wires.has(provider.wire)) { + throw new TypertGatewayError('signature-invalid', endpoint, `Context identity conflicts with wire field ${JSON.stringify(provider.wire)}`, { field: provider.wire }); + } + receiver = { + kind: 'context', + context: marker.invocation.context, + wire: provider.wire, + codec: { mode: 'src-json' }, + }; + } + return { + id: `src:${binding.serviceKey}#${endpoint}`, + service: binding.serviceKey, + namespace: binding.namespace, + method, + ...(marker.method === method ? {} : { implementation: marker.method }), + invocation: receiver, + parameters, + ...(cancellation === undefined ? {} : { cancellation }), + result: { mode: 'src-json' }, + }; + } + async resolveReceiverContext(descriptor, args, endpoint) { + if (descriptor.invocation.kind === 'direct') + return this.ctx; + const invocation = descriptor.invocation; + const provider = this.ctx.typert.contexts.getHost(invocation.context); + if (provider === undefined) { + throw new TypertGatewayError('context-unavailable', endpoint, `Context provider ${JSON.stringify(invocation.context)} is unavailable`); + } + if (provider.wire !== invocation.wire + || (invocation.codec.mode === 'strict' && provider.wireTypeSymbol !== invocation.codec.typeSymbol)) { + throw new TypertGatewayError('provider-mismatch', endpoint, `Context provider ${JSON.stringify(invocation.context)} does not match its strict definition`, { field: invocation.wire }); + } + const identity = decode(invocation.codec, args[invocation.wire], 'input-invalid', endpoint, invocation.wire); + let context; + try { + context = await provider.resolve(identity); + } + catch (cause) { + if (cause instanceof TypertLookupFailure) + throw cause; + throw new TypertGatewayError('context-failed', endpoint, `Context provider ${JSON.stringify(invocation.context)} failed`, { cause, field: invocation.wire }); + } + if (context === undefined) { + throw new TypertGatewayError('context-not-found', endpoint, `Context provider ${JSON.stringify(invocation.context)} did not resolve the requested identity`, { field: invocation.wire }); + } + return context; + } + async resolveParameter(parameter, args, endpoint) { + // An absent field reached assertExactArguments' allowance, so this parameter + // takes undefined; a present-but-undefined field is not JSON-safe input and + // still fails decode. Lookup ids are never omissible, so absence here only + // ever belongs to a json parameter. + if (!Object.hasOwn(args, parameter.wire)) + return undefined; + const value = decode(parameter.codec, args[parameter.wire], 'input-invalid', endpoint, parameter.wire); + if (parameter.source === 'json') + return value; + const key = parameter.lookup; + /* v8 ignore next -- registry validation rejects strict descriptors without a key, and SRC derivation always supplies one. */ + if (key === undefined) { + throw new TypertGatewayError('lookup-unavailable', endpoint, `lookup parameter ${JSON.stringify(parameter.name)} has no provider key`, { field: parameter.wire }); + } + const provider = this.ctx.typert.lookups.get(key); + if (provider === undefined) { + throw new TypertGatewayError('lookup-unavailable', endpoint, `lookup provider ${JSON.stringify(key)} is unavailable`, { field: parameter.wire }); + } + if (provider.wire !== parameter.wire + || (parameter.codec.mode === 'strict' && provider.wireTypeSymbol !== parameter.codec.typeSymbol)) { + throw new TypertGatewayError('provider-mismatch', endpoint, `lookup provider ${JSON.stringify(key)} does not match its strict definition`, { field: parameter.wire }); + } + let resolved; + try { + resolved = await provider.resolve(value); + } + catch (cause) { + if (cause instanceof TypertLookupFailure) + throw cause; + throw new TypertGatewayError('lookup-failed', endpoint, `lookup provider ${JSON.stringify(key)} failed`, { cause, field: parameter.wire }); + } + if (resolved === undefined) { + throw new TypertGatewayError('lookup-not-found', endpoint, `lookup provider ${JSON.stringify(key)} did not resolve the requested identity`, { field: parameter.wire }); + } + return resolved; + } +} +function rpcFailure(error) { + if (error instanceof RemoteInvocationCancelled) { + return { + ok: false, + error: { code: 'cancelled', message: error.message, details: {} }, + }; + } + if (error instanceof TypertLookupFailure) { + return { ok: false, error: error.failure }; + } + return { + ok: false, + error: { + code: 'internal', + message: error instanceof Error ? error.message : String(error), + details: {}, + }, + }; +} +function endpointOf(namespace, method) { + return `${namespace}/${method}`; +} +function validateBinding(receiver, serviceKey, namespace, endpoint) { + const original = originalOf(receiver); + const value = Reflect.get(original, 'typertRemote'); + if (value === undefined) { + throw new TypertGatewayError('binding-invalid', endpoint, `Service ${JSON.stringify(serviceKey)} has no visible typertRemote binding`); + } + return { + binding: readBinding(value, original, serviceKey, endpoint, namespace), + original, + }; +} +function readBinding(value, original, serviceKey, endpoint, namespace) { + if (!isObject(value) + || Reflect.get(value, 'service') !== original + || Reflect.get(value, 'serviceKey') !== serviceKey + || typeof Reflect.get(value, 'namespace') !== 'string' + || (namespace !== undefined && Reflect.get(value, 'namespace') !== namespace)) { + throw new TypertGatewayError('binding-invalid', endpoint, `Service ${JSON.stringify(serviceKey)} has an inconsistent typertRemote binding`); + } + return value; +} +function originalOf(receiver) { + const original = Reflect.get(receiver, symbols.original); + return isObject(original) ? original : receiver; +} +function methodParameterNames(service, method, endpoint) { + let prototype = Object.getPrototypeOf(service); + let implementation; + while (prototype !== null) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, method); + if (descriptor !== undefined) { + if ('value' in descriptor && typeof descriptor.value === 'function') { + implementation = descriptor.value; + } + break; + } + prototype = Object.getPrototypeOf(prototype); + } + if (implementation === undefined) { + throw new TypertGatewayError('method-unavailable', endpoint, `Remote marker has no prototype method ${JSON.stringify(method)}`); + } + const source = Function.prototype.toString.call(implementation); + const open = source.indexOf('('); + const close = source.indexOf(')', open + 1); + /* v8 ignore next -- standard public class-method syntax always contains a parenthesized parameter list. */ + if (open < 0 || close < 0) + return invalidSignature(endpoint, method); + const body = source.slice(open + 1, close).trim(); + if (body.length === 0) + return []; + const parts = body.split(',').map(part => part.trim()); + const names = new Set(); + for (const part of parts) { + if (!/^[$A-Z_a-z][$\w]*$/u.test(part) || names.has(part)) + return invalidSignature(endpoint, method); + names.add(part); + } + return [...names]; +} +function invalidSignature(endpoint, method) { + throw new TypertGatewayError('signature-invalid', endpoint, `SRC method ${JSON.stringify(method)} must use unique identifier parameters without destructuring, defaults, or rest`); +} +function assertExactArguments(args, descriptor, endpoint) { + if (!isPlainObject(args)) { + throw new TypertGatewayError('arguments-invalid', endpoint, 'args must be a plain object'); + } + const expected = new Set(descriptor.parameters.map(parameter => parameter.wire)); + if (descriptor.invocation.kind === 'context') + expected.add(descriptor.invocation.wire); + const actual = Reflect.ownKeys(args); + const extra = actual.filter(key => typeof key !== 'string' || !expected.has(key)); + // A JSON field may be omitted when the strict descriptor declares absence, + // and always under SRC: a weak descriptor reads parameter names from the + // JavaScript signature and cannot see which are optional, so LIB is where an + // omitted required argument is caught. Lookup ids are never omissible. + const acceptsMissing = new Set(descriptor.parameters + .filter(parameter => parameter.source === 'json' + && (parameter.acceptsUndefined === true || parameter.codec.mode === 'src-json')) + .map(parameter => parameter.wire)); + const missing = [...expected].filter(key => !Object.hasOwn(args, key) && !acceptsMissing.has(key)); + if (extra.length === 0 && missing.length === 0) + return; + const clauses = []; + if (missing.length > 0) + clauses.push(`missing ${missing.map(key => JSON.stringify(key)).join(', ')}`); + if (extra.length > 0) + clauses.push(`unexpected ${extra.map(key => JSON.stringify(String(key))).join(', ')}`); + throw new TypertGatewayError('arguments-invalid', endpoint, `args fields do not match the descriptor: ${clauses.join('; ')}`); +} +function decode(codec, value, code, endpoint, field) { + try { + if (codec.mode === 'strict') { + value = codec.schema.parse(value); + if (value === undefined) + return value; + } + assertJsonValue(value, new Set()); + return value; + } + catch (cause) { + throw new TypertGatewayError(code, endpoint, code === 'input-invalid' + ? `wire field ${JSON.stringify(field)} failed boundary validation` + : 'business result failed boundary validation', { cause, field }); + } +} +function assertJsonValue(value, ancestors) { + if (value === null || typeof value === 'string' || typeof value === 'boolean') + return; + if (typeof value === 'number') { + if (Number.isFinite(value)) + return; + throw new TypeError('non-finite number is not JSON-safe'); + } + if (!isObject(value)) + throw new TypeError(`${typeof value} is not JSON-safe`); + if (ancestors.has(value)) + throw new TypeError('cyclic value is not JSON-safe'); + ancestors.add(value); + try { + if (Array.isArray(value)) { + if (Object.getOwnPropertySymbols(value).length > 0 || Object.keys(value).length !== value.length) { + throw new TypeError('sparse or decorated array is not JSON-safe'); + } + for (let index = 0; index < value.length; index += 1) { + if (!Object.hasOwn(value, index)) + throw new TypeError('sparse array is not JSON-safe'); + assertJsonValue(value[index], ancestors); + } + return; + } + if (!isPlainObject(value)) + throw new TypeError('non-plain object is not JSON-safe'); + if (Object.getOwnPropertySymbols(value).length > 0) + throw new TypeError('symbol property is not JSON-safe'); + for (const key of Reflect.ownKeys(value)) { + const descriptor = Object.getOwnPropertyDescriptor(value, key); + /* v8 ignore next -- ownKeys() just returned this key; only a hostile same-process Proxy can delete it between operations. */ + if (descriptor === undefined || !descriptor.enumerable || !('value' in descriptor)) { + throw new TypeError('non-data property is not JSON-safe'); + } + assertJsonValue(descriptor.value, ancestors); + } + } + finally { + ancestors.delete(value); + } +} +function isPlainObject(value) { + if (Array.isArray(value)) + return false; + const prototype = Object.getPrototypeOf(value); + return prototype === null || prototype === Object.prototype; +} +function isObject(value) { + return (typeof value === 'object' && value !== null) || typeof value === 'function'; +} +export default TypertGatewayService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.d.ts new file mode 100644 index 0000000..8974e5f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-api-gateway`. + * @module @deepseek-ai/dsh-api-gateway/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "api-gateway-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.js new file mode 100644 index 0000000..f064654 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/invariant.js @@ -0,0 +1,23 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-api-gateway`. + * @module @deepseek-ai/dsh-api-gateway/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-api-gateway'; +/** Cordis companion plugin name. */ +export const name = 'api-gateway-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: Host calls re-read authoritative Cordis and Typert + * state, while Client methods, descriptors, and `$on` subscriptions mutate in + * one owned effect. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.d.ts new file mode 100644 index 0000000..6d90211 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.d.ts @@ -0,0 +1,34 @@ +/** + * Carrier-independent Typert Gateway request, service, and error contracts. + * @module @deepseek-ai/dsh-api-gateway/types + */ +/** One Remote method request after a carrier has decoded its envelope. */ +export interface InvokeRemoteRequest { + /** Remote namespace selected by the generated descriptor. */ + readonly namespace: string; + /** Exported Service method name. */ + readonly method: string; + /** Named wire values; fields must exactly match the descriptor. */ + readonly args: Readonly>; + /** Carrier or direct-caller cancellation injected only into cancellation-aware methods. */ + readonly signal?: AbortSignal; +} +/** Stable infrastructure and boundary failures emitted before or after business execution. */ +export type TypertGatewayErrorCode = 'ambiguous-endpoint' | 'arguments-invalid' | 'binding-invalid' | 'context-failed' | 'context-not-found' | 'context-unavailable' | 'definition-unavailable' | 'input-invalid' | 'invocation-unavailable' | 'lookup-failed' | 'lookup-not-found' | 'lookup-unavailable' | 'method-unavailable' | 'provider-mismatch' | 'result-invalid' | 'service-unavailable' | 'signature-invalid'; +/** Host dispatcher consumed by Connection adapters. */ +export interface TypertGateway { + /** + * Invoke one live Remote method without assuming a carrier or response envelope. + * @param request - decoded endpoint and named wire arguments. + * @returns the validated business result. + * @throws {@link TypertGatewayError} for dispatch, provider, or boundary failures; lookup-policy and business errors retain identity. + */ + invoke(request: InvokeRemoteRequest): Promise; +} +declare module '@deepseek-ai/cordis' { + interface Context { + /** Host dispatcher for Typert Remote calls. */ + typertGateway: TypertGateway; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.js new file mode 100644 index 0000000..aef140b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/lib/types/types.js @@ -0,0 +1,6 @@ +/** + * Carrier-independent Typert Gateway request, service, and error contracts. + * @module @deepseek-ai/dsh-api-gateway/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/package.json new file mode 100644 index 0000000..f70c03e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway/package.json @@ -0,0 +1,75 @@ +{ + "name": "@deepseek-ai/dsh-api-gateway", + "description": "Typert Remote Host dispatcher and Client API endpoint", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/api/gateway" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client/index.d.ts", + "default": "./lib/client.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "dsh": { + "client": { + "inject": [ + "@deepseek-ai/dsh-typert-registry", + "@deepseek-ai/dsh-client-connection" + ], + "platform": "web", + "immediately": true + } + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/client.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7" + }, + "peerDependencies": { + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "zod": "^4.4.3", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.7", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "scripts": { + "bundle": "tsdown", + "watch": "tsdown --watch" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-client-connection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-client-connection new file mode 120000 index 0000000..26e9dc5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-client-connection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..a2fcff1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-typert-registry b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-typert-registry new file mode 120000 index 0000000..07c8e9b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-typert-registry @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-agent-presets b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-agent-presets new file mode 120000 index 0000000..485bbde --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-agent-presets @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-gateway b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-gateway new file mode 120000 index 0000000..ec195c7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-gateway @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-api-gateway@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_0d2edb4cc38849dcd7ccf011b7f8322f/node_modules/@deepseek-ai/dsh-api-gateway \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.i18n.yaml new file mode 100644 index 0000000..b9ff0c0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/api/remotes/README.md +README.md: 18d39c6e86f114d2aac2f24e5d15c13335eab020 +README.zh.md: bf3dfbbaa6e0c7bd1da8398977837d4cb19d4688 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.md new file mode 100644 index 0000000..18d39c6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.md @@ -0,0 +1,41 @@ +# @deepseek-ai/dsh-api-remotes + +English | [中文](README.zh.md) + +Two-sided BFF for Host Remote capabilities selected by this application. The Host entry owns Agent/Session identity policy; the Client entry imports generated `/remote` artifacts as runtime values, mounts each contribution through `ctx.remote.$mount()`, and re-exports their declaration merges. Client business packages depend on this facade rather than the Gateway implementation or individual Remote runtime entries. + +`createApiRemoteAgentResolver()` reuses live Agents, resumes ordinary cold sessions, deduplicates concurrent resumes, preserves the subagent ownership fence, and configures the same resolver for Typert `agent` and `session` lookups. The standard Web API Proxy supplies its Agent defaults and scope setup, then uses the returned resolver for legacy methods, so migrated and unmigrated methods share one policy implementation. + +The current Client assembly mounts the Goal Remote contribution and the read-only Host plugin inventory contribution (`pluginInventory/list`). Cordis effect ownership withdraws every contribution when this assembly unloads, while `@deepseek-ai/dsh-api-gateway/client` owns descriptor validation, traced namespace Services, direct and scoped methods, invocation, and cancellation. The Client entry consumes the shared `TypertClientRemote` interface through Cordis and does not import the concrete Gateway. It re-exports the Gateway Client face's declaration merges type-only, so a consumer reaching the forwarded-event vocabulary through this facade gains no runtime edge to the Gateway implementation. + +This package contains no transport or Host service discovery logic. Its Client face can be reused by Web or a future TUI that provides the same React-free `ctx.remote` contract. + +## Forwarded Host events + +`src/remote-events.ts` holds `API_REMOTE_FORWARDED_EVENTS`, the allowlist of Host cordis events this application forwards to consumers verbatim — no projection, no redaction, no renaming — and therefore the legal key set of `ctx.remote.$on`; the type-only `src/types.ts` derives its selection face. Forwarding one more event is an entry in that array and nothing else: the type projection, the consumer key face, and the Host forwarding loop all derive from it. + +The listener signature is not restated here. Each allowlisted event's cordis `Events` declaration lives in its owner package's client-safe `./types` export (`dsh-agent-presets`, `dsh-commands`, `dsh-credentials`, `dsh-llm`, `dsh-settings`), and both faces of this package pull those declarations in, so "forwarded verbatim" holds by construction rather than by proof. The Host face additionally asserts the list against `TypertForwardableEvent`, which rejects a name that is not a declared event, one that binds an AgentScope, and one whose shape is not one-way. + +## Build boundary + +An ordinary repository package belongs to one TypeScript face: Host packages are registered in the root `tsconfig.host.json`, and Client packages in the root `tsconfig.client.json`. `api-remotes` is the only deliberate exception because its Host entry must participate in the Host Typert graph, while `src/client/index.ts` cannot compile until Host tsdown has generated the business packages' `/remote` declarations. + +This package's root `tsconfig.json` is only a solution that references `tsconfig.host.json` and `tsconfig.client.json`. The Host aggregate and direct Host consumers reference the former, while the Client aggregate and direct Client consumers reference the latter; the package-root solution must not enter either aggregate's dependency graph. The two projects own disjoint source files and `.tsbuildinfo` files but share the `lib/types` output directory, with one deliberate exception: `src/remote-events.ts` and `src/types.ts` are listed in BOTH faces' `files`, because the forwarded-event allowlist is the single control point over what a consumer can receive, and the Host forwarding loop and the Client `ctx.remote.$on` key face must read one declaration rather than two that could drift. + +That exception is not just a `files` entry. The root `tsconfig.base.json` maps `@deepseek-ai/dsh-api-remotes/types` to `src/types.ts` — the source plane, like every other workspace subpath and unlike the generated `/remote` artifacts, which have no `paths` entry and resolve through `exports` to built output. Both faces therefore admit the same allowlist and type projection into their own programs and emit byte-identical `remote-events` and `types` outputs into `lib/types`; the `.tsbuildinfo` files stay independent. No gate enforces the faces' source-file disjointness — `scripts/project-reference-faces.ts` only checks that a reference into a split project names the matching face — so this paragraph records why the double listing is intentional. + +The package-local `clientBundle(..., { hostPhase: true })` makes Host tsdown bundle the Host entry and the later Client tsdown bundle only the browser entry. Ordinary Client plugins remain single Client projects and produce both their Node loader entry and browser bundle during Client tsdown; do not copy this package's split merely because a package has both `src/index.ts` and `src/client/index.ts`. + +## Model Experience + +None, as this BFF selects Remote application methods and identity policy but registers nothing model-facing. + +#### KV Cache effect + +No direct effect; mounted Host capabilities own any model-visible behavior they trigger. + +## Known Limitations and Deferred Work + +- The capability set is fixed by explicit build-time value imports; the Client does not discover the Host's active Services or Remote definitions at runtime. +- Additional capabilities require an explicit `/remote` value import and mount in this assembly. +- The standard Web Host supplies resume defaults and Agent-scope setup from the legacy API Proxy until that remaining BFF configuration moves into `api-remotes`. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.zh.md new file mode 100644 index 0000000..bf3dfbb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/README.zh.md @@ -0,0 +1,42 @@ +# @deepseek-ai/dsh-api-remotes + +[English](README.md) | 中文 + +为本应用选定的 Host Remote 能力提供双侧 BFF。Host 入口负责 Agent/Session 身份策略;Client 入口以运行时值形式导入生成的 `/remote` 产物,通过 `ctx.remote.$mount()` 挂载每项贡献,并重新导出对应的声明合并。Client 业务包依赖该外观,而不依赖 Gateway 实现或单独的 Remote 运行时入口。 + +`createApiRemoteAgentResolver()` 会复用 live Agent、恢复普通冷会话、对并发恢复去重、保留 subagent ownership fence,并为 Typert `agent` 和 `session` lookup 配置同一个 resolver。标准 Web API Proxy 提供 Agent 默认值和 scope 设置,再将返回的 resolver 用于旧方法,使已迁移与未迁移方法共用同一份策略实现。 + +当前 Client 组合挂载 Goal Remote 贡献和只读 Host 插件清单贡献(`pluginInventory/list`)。该组合卸载时,Cordis effect 的所有权机制会撤回所有贡献;`@deepseek-ai/dsh-api-gateway/client` 负责描述符校验、可追踪 namespace Service、直接与作用域方法、调用与取消。Client 入口通过 Cordis 消费共享的 `TypertClientRemote` 接口,不导入具体 Gateway;它只以 type-only 形式重新导出 Gateway Client face 的声明合并,因此消费端经由本外观取到转发事件词汇时,运行时不会多出一条通往 Gateway 实现的边。 + +本包不包含传输逻辑或 Host 服务发现逻辑。Web 或未来的 TUI 只要提供同一份不依赖 React 的 `ctx.remote` 约定,均可复用其 Client face。 + +## 转发的 Host 事件 + +`src/remote-events.ts` 持有 `API_REMOTE_FORWARDED_EVENTS`——本应用原样转发给消费端的 Host cordis 事件名单(无投影、无脱敏、无改名),它同时就是 `ctx.remote.$on` 的合法键集;只含类型的 `src/types.ts` 派生其选择面。多转发一个事件只需在该数组里加一行:类型投影、消费端键面与 Host 转发循环全部由它派生。 + +监听器签名不在此处重写。名单内每条事件的 cordis `Events` 声明都住在其 owner 包 client-safe 的 `./types` 出口(`dsh-agent-presets`、`dsh-commands`、`dsh-credentials`、`dsh-llm`、`dsh-settings`),本包两个 face 都把那些声明纳入编译面,因此「原样转发」是构造性成立的,不需要另立证明。Host face 还额外把名单断言给 `TypertForwardableEvent`:未声明的事件名、绑定 AgentScope 的事件、以及形状不是单向的事件都会在此被拒绝。 + +## 构建边界 + +仓库中的普通包只属于一个 TypeScript face:Host 包登记在根 `tsconfig.host.json`,Client 包登记在根 `tsconfig.client.json`。`api-remotes` 是唯一刻意拆分的特例,因为它的 Host 入口要参与 Host Typert 图,而 `src/client/index.ts` 必须等 Host tsdown 生成业务包的 `/remote` 声明后才能编译。 + +本包根 `tsconfig.json` 只是引用 `tsconfig.host.json` 与 `tsconfig.client.json` 的 solution。Host aggregate 和 Host 直接消费方引用前者,Client aggregate 和 Client 直接消费方引用后者;禁止把包根 solution 放进任一 aggregate 的依赖图。两个 project 拥有互不重叠的源码和 `.tsbuildinfo`,但共享 `lib/types` 输出目录——只有一处刻意的例外:`src/remote-events.ts` 与 `src/types.ts` **同时**列进两个 face 的 `files`,因为转发事件名单是「消费端能收到什么」的唯一控制点,Host 转发循环与 Client 的 `ctx.remote.$on` 键面必须读同一份声明,而不是两份可能彼此漂移的声明。 + +这条例外不止是一行 `files`。根 `tsconfig.base.json` 把 `@deepseek-ai/dsh-api-remotes/types` 映射到 `src/types.ts`——**源平面**,与其余所有 workspace 子路径一致,也与生成的 `/remote` 产物相反(后者没有 `paths` 条目,靠 `exports` 命中构建产物)。于是两个 face 都把同一份名单与类型投影收进各自的 program,并向 `lib/types` 发射逐字相同的 `remote-events` 与 `types` 输出;`.tsbuildinfo` 仍各自独立。没有任何门禁强制两个 face 的源文件互不重叠——`scripts/project-reference-faces.ts` 只校验「引用一个 split project 必须指到对应 face」——因此本段记录这次双列为何是有意的。 + + +包内 `clientBundle(..., { hostPhase: true })` 让 Host tsdown 打包 Host 入口,让后续 Client tsdown 只打包 browser 入口。普通 Client 插件仍使用单一 Client project,并在 Client tsdown 阶段一起生成 Node loader 入口和 browser bundle;不得因一个包同时存在 `src/index.ts` 与 `src/client/index.ts` 就复制本包的拆分。 + +## 模型体验 + +无,因为该 BFF 只选择 Remote 应用方法和身份策略,不注册任何模型接口。 + +#### KV Cache 影响 + +无直接影响;其触发的任何模型可见行为均由已挂载的 Host 能力负责。 + +## 已知限制与暂缓事项 + +- 能力集合由构建时显式导入的值固定确定;Client 不会在运行时发现 Host 中已启用的服务或 Remote 定义。 +- 若要增加能力,必须显式导入相应的 `/remote` 值并在此组合中挂载。 +- 在剩余 BFF 配置迁移到 `api-remotes` 之前,标准 Web Host 仍从旧 API Proxy 提供恢复默认值与 Agent scope 设置。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js new file mode 100644 index 0000000..461490b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js @@ -0,0 +1,5937 @@ +window.__ModuleLoader__.load({ + id: "@deepseek-ai/dsh-api-remotes", + factory: (require) => { + var module = { exports: {} }; + var exports = module.exports; + Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js + var _a$1; + function $constructor(name, initializer, params) { + function init(inst, def) { + if (!inst._zod) Object.defineProperty(inst, "_zod", { + value: { + def, + constr: _, + traits: /* @__PURE__ */ new Set() + }, + enumerable: false + }); + if (inst._zod.traits.has(name)) return; + inst._zod.traits.add(name); + initializer(inst, def); + const proto = _.prototype; + const keys = Object.keys(proto); + for (let i = 0; i < keys.length; i++) { + const k = keys[i]; + if (!(k in inst)) inst[k] = proto[k].bind(inst); + } + } + const Parent = params?.Parent ?? Object; + class Definition extends Parent {} + Object.defineProperty(Definition, "name", { value: name }); + function _(def) { + var _a; + const inst = params?.Parent ? new Definition() : this; + init(inst, def); + (_a = inst._zod).deferred ?? (_a.deferred = []); + for (const fn of inst._zod.deferred) fn(); + return inst; + } + Object.defineProperty(_, "init", { value: init }); + Object.defineProperty(_, Symbol.hasInstance, { value: (inst) => { + if (params?.Parent && inst instanceof params.Parent) return true; + return inst?._zod?.traits?.has(name); + } }); + Object.defineProperty(_, "name", { value: name }); + return _; + } + var $ZodAsyncError = class extends Error { + constructor() { + super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`); + } + }; + var $ZodEncodeError = class extends Error { + constructor(name) { + super(`Encountered unidirectional transform during encode: ${name}`); + this.name = "ZodEncodeError"; + } + }; + (_a$1 = globalThis).__zod_globalConfig ?? (_a$1.__zod_globalConfig = {}); + const globalConfig = globalThis.__zod_globalConfig; + function config(newConfig) { + if (newConfig) Object.assign(globalConfig, newConfig); + return globalConfig; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.js + function getEnumValues(entries) { + const numericValues = Object.values(entries).filter((v) => typeof v === "number"); + return Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v); + } + function jsonStringifyReplacer(_, value) { + if (typeof value === "bigint") return value.toString(); + return value; + } + function cached(getter) { + return { get value() { + { + const value = getter(); + Object.defineProperty(this, "value", { value }); + return value; + } + throw new Error("cached value already set"); + } }; + } + function nullish(input) { + return input === null || input === void 0; + } + function cleanRegex(source) { + const start = source.startsWith("^") ? 1 : 0; + const end = source.endsWith("$") ? source.length - 1 : source.length; + return source.slice(start, end); + } + function floatSafeRemainder(val, step) { + const ratio = val / step; + const roundedRatio = Math.round(ratio); + const tolerance = Number.EPSILON * Math.max(Math.abs(ratio), 1); + if (Math.abs(ratio - roundedRatio) < tolerance) return 0; + return ratio - roundedRatio; + } + const EVALUATING = /* @__PURE__*/ Symbol("evaluating"); + function defineLazy(object, key, getter) { + let value = void 0; + Object.defineProperty(object, key, { + get() { + if (value === EVALUATING) return; + if (value === void 0) { + value = EVALUATING; + value = getter(); + } + return value; + }, + set(v) { + Object.defineProperty(object, key, { value: v }); + }, + configurable: true + }); + } + function assignProp(target, prop, value) { + Object.defineProperty(target, prop, { + value, + writable: true, + enumerable: true, + configurable: true + }); + } + function mergeDefs(...defs) { + const mergedDescriptors = {}; + for (const def of defs) Object.assign(mergedDescriptors, Object.getOwnPropertyDescriptors(def)); + return Object.defineProperties({}, mergedDescriptors); + } + function esc(str) { + return JSON.stringify(str); + } + function slugify(input) { + return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, ""); + } + const captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {}; + function isObject(data) { + return typeof data === "object" && data !== null && !Array.isArray(data); + } + const allowsEval = /* @__PURE__*/ cached(() => { + if (globalConfig.jitless) return false; + if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) return false; + try { + new Function(""); + return true; + } catch (_) { + return false; + } + }); + function isPlainObject(o) { + if (isObject(o) === false) return false; + const ctor = o.constructor; + if (ctor === void 0) return true; + if (typeof ctor !== "function") return true; + const prot = ctor.prototype; + if (isObject(prot) === false) return false; + if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) return false; + return true; + } + function shallowClone(o) { + if (isPlainObject(o)) return { ...o }; + if (Array.isArray(o)) return [...o]; + if (o instanceof Map) return new Map(o); + if (o instanceof Set) return new Set(o); + return o; + } + const propertyKeyTypes = /* @__PURE__*/ new Set([ + "string", + "number", + "symbol" + ]); + function escapeRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + } + function clone(inst, def, params) { + const cl = new inst._zod.constr(def ?? inst._zod.def); + if (!def || params?.parent) cl._zod.parent = inst; + return cl; + } + function normalizeParams(_params) { + const params = _params; + if (!params) return {}; + if (typeof params === "string") return { error: () => params }; + if (params?.message !== void 0) { + if (params?.error !== void 0) throw new Error("Cannot specify both `message` and `error` params"); + params.error = params.message; + } + delete params.message; + if (typeof params.error === "string") return { + ...params, + error: () => params.error + }; + return params; + } + function optionalKeys(shape) { + return Object.keys(shape).filter((k) => { + return shape[k]._zod.optin === "optional" && shape[k]._zod.optout === "optional"; + }); + } + const NUMBER_FORMAT_RANGES = { + safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], + int32: [-2147483648, 2147483647], + uint32: [0, 4294967295], + float32: [-34028234663852886e22, 34028234663852886e22], + float64: [-Number.MAX_VALUE, Number.MAX_VALUE] + }; + function pick(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + if (checks && checks.length > 0) throw new Error(".pick() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const newShape = {}; + for (const key in mask) { + if (!(key in currDef.shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + newShape[key] = currDef.shape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + })); + } + function omit(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + if (checks && checks.length > 0) throw new Error(".omit() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const newShape = { ...schema._zod.def.shape }; + for (const key in mask) { + if (!(key in currDef.shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + delete newShape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + })); + } + function extend(schema, shape) { + if (!isPlainObject(shape)) throw new Error("Invalid input to extend: expected a plain object"); + const checks = schema._zod.def.checks; + if (checks && checks.length > 0) { + const existingShape = schema._zod.def.shape; + for (const key in shape) if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead."); + } + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const _shape = { + ...schema._zod.def.shape, + ...shape + }; + assignProp(this, "shape", _shape); + return _shape; + } })); + } + function safeExtend(schema, shape) { + if (!isPlainObject(shape)) throw new Error("Invalid input to safeExtend: expected a plain object"); + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const _shape = { + ...schema._zod.def.shape, + ...shape + }; + assignProp(this, "shape", _shape); + return _shape; + } })); + } + function merge(a, b) { + if (a._zod.def.checks?.length) throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead."); + return clone(a, mergeDefs(a._zod.def, { + get shape() { + const _shape = { + ...a._zod.def.shape, + ...b._zod.def.shape + }; + assignProp(this, "shape", _shape); + return _shape; + }, + get catchall() { + return b._zod.def.catchall; + }, + checks: b._zod.def.checks ?? [] + })); + } + function partial(Class, schema, mask) { + const checks = schema._zod.def.checks; + if (checks && checks.length > 0) throw new Error(".partial() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) for (const key in mask) { + if (!(key in oldShape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + shape[key] = Class ? new Class({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + } + else for (const key in oldShape) shape[key] = Class ? new Class({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + assignProp(this, "shape", shape); + return shape; + }, + checks: [] + })); + } + function required(Class, schema, mask) { + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) for (const key in mask) { + if (!(key in shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + shape[key] = new Class({ + type: "nonoptional", + innerType: oldShape[key] + }); + } + else for (const key in oldShape) shape[key] = new Class({ + type: "nonoptional", + innerType: oldShape[key] + }); + assignProp(this, "shape", shape); + return shape; + } })); + } + function aborted(x, startIndex = 0) { + if (x.aborted === true) return true; + for (let i = startIndex; i < x.issues.length; i++) if (x.issues[i]?.continue !== true) return true; + return false; + } + function explicitlyAborted(x, startIndex = 0) { + if (x.aborted === true) return true; + for (let i = startIndex; i < x.issues.length; i++) if (x.issues[i]?.continue === false) return true; + return false; + } + function prefixIssues(path, issues) { + return issues.map((iss) => { + var _a; + (_a = iss).path ?? (_a.path = []); + iss.path.unshift(path); + return iss; + }); + } + function unwrapMessage(message) { + return typeof message === "string" ? message : message?.message; + } + function finalizeIssue(iss, ctx, config) { + const message = iss.message ? iss.message : unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config.customError?.(iss)) ?? unwrapMessage(config.localeError?.(iss)) ?? "Invalid input"; + const { inst: _inst, continue: _continue, input: _input, ...rest } = iss; + rest.path ?? (rest.path = []); + rest.message = message; + if (ctx?.reportInput) rest.input = _input; + return rest; + } + function getLengthableOrigin(input) { + if (Array.isArray(input)) return "array"; + if (typeof input === "string") return "string"; + return "unknown"; + } + function issue(...args) { + const [iss, input, inst] = args; + if (typeof iss === "string") return { + message: iss, + code: "custom", + input, + inst + }; + return { ...iss }; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/errors.js + const initializer$1 = (inst, def) => { + inst.name = "$ZodError"; + Object.defineProperty(inst, "_zod", { + value: inst._zod, + enumerable: false + }); + Object.defineProperty(inst, "issues", { + value: def, + enumerable: false + }); + inst.message = JSON.stringify(def, jsonStringifyReplacer, 2); + Object.defineProperty(inst, "toString", { + value: () => inst.message, + enumerable: false + }); + }; + const $ZodError = $constructor("$ZodError", initializer$1); + const $ZodRealError = $constructor("$ZodError", initializer$1, { Parent: Error }); + function flattenError(error, mapper = (issue) => issue.message) { + const fieldErrors = {}; + const formErrors = []; + for (const sub of error.issues) if (sub.path.length > 0) { + fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || []; + fieldErrors[sub.path[0]].push(mapper(sub)); + } else formErrors.push(mapper(sub)); + return { + formErrors, + fieldErrors + }; + } + function formatError(error, mapper = (issue) => issue.message) { + const fieldErrors = { _errors: [] }; + const processError = (error, path = []) => { + for (const issue of error.issues) if (issue.code === "invalid_union" && issue.errors.length) issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path])); + else if (issue.code === "invalid_key") processError({ issues: issue.issues }, [...path, ...issue.path]); + else if (issue.code === "invalid_element") processError({ issues: issue.issues }, [...path, ...issue.path]); + else { + const fullpath = [...path, ...issue.path]; + if (fullpath.length === 0) fieldErrors._errors.push(mapper(issue)); + else { + let curr = fieldErrors; + let i = 0; + while (i < fullpath.length) { + const el = fullpath[i]; + if (!(i === fullpath.length - 1)) curr[el] = curr[el] || { _errors: [] }; + else { + curr[el] = curr[el] || { _errors: [] }; + curr[el]._errors.push(mapper(issue)); + } + curr = curr[el]; + i++; + } + } + } + }; + processError(error); + return fieldErrors; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/parse.js + const _parse = (_Err) => (schema, value, _ctx, _params) => { + const ctx = _ctx ? { + ..._ctx, + async: false + } : { async: false }; + const result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) throw new $ZodAsyncError(); + if (result.issues.length) { + const e = new ((_params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, _params?.callee); + throw e; + } + return result.value; + }; + const _parseAsync = (_Err) => async (schema, value, _ctx, params) => { + const ctx = _ctx ? { + ..._ctx, + async: true + } : { async: true }; + let result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) result = await result; + if (result.issues.length) { + const e = new ((params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, params?.callee); + throw e; + } + return result.value; + }; + const _safeParse = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + async: false + } : { async: false }; + const result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) throw new $ZodAsyncError(); + return result.issues.length ? { + success: false, + error: new (_Err ?? $ZodError)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { + success: true, + data: result.value + }; + }; + const safeParse$1 = /* @__PURE__*/ _safeParse($ZodRealError); + const _safeParseAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + async: true + } : { async: true }; + let result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) result = await result; + return result.issues.length ? { + success: false, + error: new _Err(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { + success: true, + data: result.value + }; + }; + const safeParseAsync$1 = /* @__PURE__*/ _safeParseAsync($ZodRealError); + const _encode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _parse(_Err)(schema, value, ctx); + }; + const _decode = (_Err) => (schema, value, _ctx) => { + return _parse(_Err)(schema, value, _ctx); + }; + const _encodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _parseAsync(_Err)(schema, value, ctx); + }; + const _decodeAsync = (_Err) => async (schema, value, _ctx) => { + return _parseAsync(_Err)(schema, value, _ctx); + }; + const _safeEncode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _safeParse(_Err)(schema, value, ctx); + }; + const _safeDecode = (_Err) => (schema, value, _ctx) => { + return _safeParse(_Err)(schema, value, _ctx); + }; + const _safeEncodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _safeParseAsync(_Err)(schema, value, ctx); + }; + const _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => { + return _safeParseAsync(_Err)(schema, value, _ctx); + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/regexes.js + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link cuid2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const cuid = /^[cC][0-9a-z]{6,}$/; + const cuid2 = /^[0-9a-z]+$/; + const ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/; + const xid = /^[0-9a-vA-V]{20}$/; + const ksuid = /^[A-Za-z0-9]{27}$/; + const nanoid = /^[a-zA-Z0-9_-]{21}$/; + /** ISO 8601-1 duration regex. Does not support the 8601-2 extensions like negative durations or fractional/negative components. */ + const duration$1 = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/; + /** A regex for any UUID-like identifier: 8-4-4-4-12 hex pattern */ + const guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/; + /** Returns a regex for validating an RFC 9562/4122 UUID. + * + * @param version Optionally specify a version 1-8. If no version is specified, all versions are supported. */ + const uuid = (version) => { + if (!version) return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/; + return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`); + }; + /** Practical email validation */ + const email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/; + const _emoji$1 = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; + function emoji() { + return new RegExp(_emoji$1, "u"); + } + const ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; + const ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/; + const cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/; + const cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; + const base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/; + const base64url = /^[A-Za-z0-9_-]*$/; + const httpProtocol = /^https?$/; + const e164 = /^\+[1-9]\d{6,14}$/; + const dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`; + const date$1 = /*@__PURE__*/ new RegExp(`^${dateSource}$`); + function timeSource(args) { + const hhmm = `(?:[01]\\d|2[0-3]):[0-5]\\d`; + return typeof args.precision === "number" ? args.precision === -1 ? `${hhmm}` : args.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args.precision}}` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`; + } + function time$1(args) { + return new RegExp(`^${timeSource(args)}$`); + } + function datetime$1(args) { + const time = timeSource({ precision: args.precision }); + const opts = ["Z"]; + if (args.local) opts.push(""); + if (args.offset) opts.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`); + const timeRegex = `${time}(?:${opts.join("|")})`; + return new RegExp(`^${dateSource}T(?:${timeRegex})$`); + } + const string$1 = (params) => { + const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`; + return new RegExp(`^${regex}$`); + }; + const integer = /^-?\d+$/; + const number$1 = /^-?\d+(?:\.\d+)?$/; + const boolean$1 = /^(?:true|false)$/i; + const _undefined$2 = /^undefined$/i; + const lowercase = /^[^A-Z]*$/; + const uppercase = /^[^a-z]*$/; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/checks.js + const $ZodCheck = /*@__PURE__*/ $constructor("$ZodCheck", (inst, def) => { + var _a; + inst._zod ?? (inst._zod = {}); + inst._zod.def = def; + (_a = inst._zod).onattach ?? (_a.onattach = []); + }); + const numericOriginMap = { + number: "number", + bigint: "bigint", + object: "date" + }; + const $ZodCheckLessThan = /*@__PURE__*/ $constructor("$ZodCheckLessThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + const curr = (def.inclusive ? bag.maximum : bag.exclusiveMaximum) ?? Number.POSITIVE_INFINITY; + if (def.value < curr) if (def.inclusive) bag.maximum = def.value; + else bag.exclusiveMaximum = def.value; + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value <= def.value : payload.value < def.value) return; + payload.issues.push({ + origin, + code: "too_big", + maximum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckGreaterThan = /*@__PURE__*/ $constructor("$ZodCheckGreaterThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY; + if (def.value > curr) if (def.inclusive) bag.minimum = def.value; + else bag.exclusiveMinimum = def.value; + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value >= def.value : payload.value > def.value) return; + payload.issues.push({ + origin, + code: "too_small", + minimum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMultipleOf = /*@__PURE__*/ $constructor("$ZodCheckMultipleOf", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst) => { + var _a; + (_a = inst._zod.bag).multipleOf ?? (_a.multipleOf = def.value); + }); + inst._zod.check = (payload) => { + if (typeof payload.value !== typeof def.value) throw new Error("Cannot mix number and bigint in multiple_of check."); + if (typeof payload.value === "bigint" ? payload.value % def.value === BigInt(0) : floatSafeRemainder(payload.value, def.value) === 0) return; + payload.issues.push({ + origin: typeof payload.value, + code: "not_multiple_of", + divisor: def.value, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckNumberFormat = /*@__PURE__*/ $constructor("$ZodCheckNumberFormat", (inst, def) => { + $ZodCheck.init(inst, def); + def.format = def.format || "float64"; + const isInt = def.format?.includes("int"); + const origin = isInt ? "int" : "number"; + const [minimum, maximum] = NUMBER_FORMAT_RANGES[def.format]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.format = def.format; + bag.minimum = minimum; + bag.maximum = maximum; + if (isInt) bag.pattern = integer; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (isInt) { + if (!Number.isInteger(input)) { + payload.issues.push({ + expected: origin, + format: def.format, + code: "invalid_type", + continue: false, + input, + inst + }); + return; + } + if (!Number.isSafeInteger(input)) { + if (input > 0) payload.issues.push({ + input, + code: "too_big", + maximum: Number.MAX_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + else payload.issues.push({ + input, + code: "too_small", + minimum: Number.MIN_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + return; + } + } + if (input < minimum) payload.issues.push({ + origin: "number", + input, + code: "too_small", + minimum, + inclusive: true, + inst, + continue: !def.abort + }); + if (input > maximum) payload.issues.push({ + origin: "number", + input, + code: "too_big", + maximum, + inclusive: true, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMaxLength = /*@__PURE__*/ $constructor("$ZodCheckMaxLength", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const curr = inst._zod.bag.maximum ?? Number.POSITIVE_INFINITY; + if (def.maximum < curr) inst._zod.bag.maximum = def.maximum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (input.length <= def.maximum) return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_big", + maximum: def.maximum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMinLength = /*@__PURE__*/ $constructor("$ZodCheckMinLength", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const curr = inst._zod.bag.minimum ?? Number.NEGATIVE_INFINITY; + if (def.minimum > curr) inst._zod.bag.minimum = def.minimum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (input.length >= def.minimum) return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_small", + minimum: def.minimum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckLengthEquals = /*@__PURE__*/ $constructor("$ZodCheckLengthEquals", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.minimum = def.length; + bag.maximum = def.length; + bag.length = def.length; + }); + inst._zod.check = (payload) => { + const input = payload.value; + const length = input.length; + if (length === def.length) return; + const origin = getLengthableOrigin(input); + const tooBig = length > def.length; + payload.issues.push({ + origin, + ...tooBig ? { + code: "too_big", + maximum: def.length + } : { + code: "too_small", + minimum: def.length + }, + inclusive: true, + exact: true, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckStringFormat = /*@__PURE__*/ $constructor("$ZodCheckStringFormat", (inst, def) => { + var _a, _b; + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.format = def.format; + if (def.pattern) { + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(def.pattern); + } + }); + if (def.pattern) (_a = inst._zod).check ?? (_a.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: def.format, + input: payload.value, + ...def.pattern ? { pattern: def.pattern.toString() } : {}, + inst, + continue: !def.abort + }); + }); + else (_b = inst._zod).check ?? (_b.check = () => {}); + }); + const $ZodCheckRegex = /*@__PURE__*/ $constructor("$ZodCheckRegex", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + inst._zod.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "regex", + input: payload.value, + pattern: def.pattern.toString(), + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckLowerCase = /*@__PURE__*/ $constructor("$ZodCheckLowerCase", (inst, def) => { + def.pattern ?? (def.pattern = lowercase); + $ZodCheckStringFormat.init(inst, def); + }); + const $ZodCheckUpperCase = /*@__PURE__*/ $constructor("$ZodCheckUpperCase", (inst, def) => { + def.pattern ?? (def.pattern = uppercase); + $ZodCheckStringFormat.init(inst, def); + }); + const $ZodCheckIncludes = /*@__PURE__*/ $constructor("$ZodCheckIncludes", (inst, def) => { + $ZodCheck.init(inst, def); + const escapedRegex = escapeRegex(def.includes); + const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex); + def.pattern = pattern; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.includes(def.includes, def.position)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "includes", + includes: def.includes, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckStartsWith = /*@__PURE__*/ $constructor("$ZodCheckStartsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`^${escapeRegex(def.prefix)}.*`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.startsWith(def.prefix)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "starts_with", + prefix: def.prefix, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckEndsWith = /*@__PURE__*/ $constructor("$ZodCheckEndsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`.*${escapeRegex(def.suffix)}$`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.endsWith(def.suffix)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "ends_with", + suffix: def.suffix, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckOverwrite = /*@__PURE__*/ $constructor("$ZodCheckOverwrite", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.check = (payload) => { + payload.value = def.tx(payload.value); + }; + }); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/doc.js + var Doc = class { + constructor(args = []) { + this.content = []; + this.indent = 0; + if (this) this.args = args; + } + indented(fn) { + this.indent += 1; + fn(this); + this.indent -= 1; + } + write(arg) { + if (typeof arg === "function") { + arg(this, { execution: "sync" }); + arg(this, { execution: "async" }); + return; + } + const lines = arg.split("\n").filter((x) => x); + const minIndent = Math.min(...lines.map((x) => x.length - x.trimStart().length)); + const dedented = lines.map((x) => x.slice(minIndent)).map((x) => " ".repeat(this.indent * 2) + x); + for (const line of dedented) this.content.push(line); + } + compile() { + const F = Function; + const args = this?.args; + const lines = [...(this?.content ?? [``]).map((x) => ` ${x}`)]; + return new F(...args, lines.join("\n")); + } + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.js + const version = { + major: 4, + minor: 4, + patch: 3 + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/schemas.js + const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => { + var _a; + inst ?? (inst = {}); + inst._zod.def = def; + inst._zod.bag = inst._zod.bag || {}; + inst._zod.version = version; + const checks = [...inst._zod.def.checks ?? []]; + if (inst._zod.traits.has("$ZodCheck")) checks.unshift(inst); + for (const ch of checks) for (const fn of ch._zod.onattach) fn(inst); + if (checks.length === 0) { + (_a = inst._zod).deferred ?? (_a.deferred = []); + inst._zod.deferred?.push(() => { + inst._zod.run = inst._zod.parse; + }); + } else { + const runChecks = (payload, checks, ctx) => { + let isAborted = aborted(payload); + let asyncResult; + for (const ch of checks) { + if (ch._zod.def.when) { + if (explicitlyAborted(payload)) continue; + if (!ch._zod.def.when(payload)) continue; + } else if (isAborted) continue; + const currLen = payload.issues.length; + const _ = ch._zod.check(payload); + if (_ instanceof Promise && ctx?.async === false) throw new $ZodAsyncError(); + if (asyncResult || _ instanceof Promise) asyncResult = (asyncResult ?? Promise.resolve()).then(async () => { + await _; + if (payload.issues.length === currLen) return; + if (!isAborted) isAborted = aborted(payload, currLen); + }); + else { + if (payload.issues.length === currLen) continue; + if (!isAborted) isAborted = aborted(payload, currLen); + } + } + if (asyncResult) return asyncResult.then(() => { + return payload; + }); + return payload; + }; + const handleCanaryResult = (canary, payload, ctx) => { + if (aborted(canary)) { + canary.aborted = true; + return canary; + } + const checkResult = runChecks(payload, checks, ctx); + if (checkResult instanceof Promise) { + if (ctx.async === false) throw new $ZodAsyncError(); + return checkResult.then((checkResult) => inst._zod.parse(checkResult, ctx)); + } + return inst._zod.parse(checkResult, ctx); + }; + inst._zod.run = (payload, ctx) => { + if (ctx.skipChecks) return inst._zod.parse(payload, ctx); + if (ctx.direction === "backward") { + const canary = inst._zod.parse({ + value: payload.value, + issues: [] + }, { + ...ctx, + skipChecks: true + }); + if (canary instanceof Promise) return canary.then((canary) => { + return handleCanaryResult(canary, payload, ctx); + }); + return handleCanaryResult(canary, payload, ctx); + } + const result = inst._zod.parse(payload, ctx); + if (result instanceof Promise) { + if (ctx.async === false) throw new $ZodAsyncError(); + return result.then((result) => runChecks(result, checks, ctx)); + } + return runChecks(result, checks, ctx); + }; + } + defineLazy(inst, "~standard", () => ({ + validate: (value) => { + try { + const r = safeParse$1(inst, value); + return r.success ? { value: r.data } : { issues: r.error?.issues }; + } catch (_) { + return safeParseAsync$1(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues }); + } + }, + vendor: "zod", + version: 1 + })); + }); + const $ZodString = /*@__PURE__*/ $constructor("$ZodString", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = [...inst?._zod.bag?.patterns ?? []].pop() ?? string$1(inst._zod.bag); + inst._zod.parse = (payload, _) => { + if (def.coerce) try { + payload.value = String(payload.value); + } catch (_) {} + if (typeof payload.value === "string") return payload; + payload.issues.push({ + expected: "string", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; + }); + const $ZodStringFormat = /*@__PURE__*/ $constructor("$ZodStringFormat", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + $ZodString.init(inst, def); + }); + const $ZodGUID = /*@__PURE__*/ $constructor("$ZodGUID", (inst, def) => { + def.pattern ?? (def.pattern = guid); + $ZodStringFormat.init(inst, def); + }); + const $ZodUUID = /*@__PURE__*/ $constructor("$ZodUUID", (inst, def) => { + if (def.version) { + const v = { + v1: 1, + v2: 2, + v3: 3, + v4: 4, + v5: 5, + v6: 6, + v7: 7, + v8: 8 + }[def.version]; + if (v === void 0) throw new Error(`Invalid UUID version: "${def.version}"`); + def.pattern ?? (def.pattern = uuid(v)); + } else def.pattern ?? (def.pattern = uuid()); + $ZodStringFormat.init(inst, def); + }); + const $ZodEmail = /*@__PURE__*/ $constructor("$ZodEmail", (inst, def) => { + def.pattern ?? (def.pattern = email); + $ZodStringFormat.init(inst, def); + }); + const $ZodURL = /*@__PURE__*/ $constructor("$ZodURL", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + try { + const trimmed = payload.value.trim(); + if (!def.normalize && def.protocol?.source === httpProtocol.source) { + if (!/^https?:\/\//i.test(trimmed)) { + payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid URL format", + input: payload.value, + inst, + continue: !def.abort + }); + return; + } + } + const url = new URL(trimmed); + if (def.hostname) { + def.hostname.lastIndex = 0; + if (!def.hostname.test(url.hostname)) payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid hostname", + pattern: def.hostname.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + if (def.protocol) { + def.protocol.lastIndex = 0; + if (!def.protocol.test(url.protocol.endsWith(":") ? url.protocol.slice(0, -1) : url.protocol)) payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid protocol", + pattern: def.protocol.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + if (def.normalize) payload.value = url.href; + else payload.value = trimmed; + return; + } catch (_) { + payload.issues.push({ + code: "invalid_format", + format: "url", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + const $ZodEmoji = /*@__PURE__*/ $constructor("$ZodEmoji", (inst, def) => { + def.pattern ?? (def.pattern = emoji()); + $ZodStringFormat.init(inst, def); + }); + const $ZodNanoID = /*@__PURE__*/ $constructor("$ZodNanoID", (inst, def) => { + def.pattern ?? (def.pattern = nanoid); + $ZodStringFormat.init(inst, def); + }); + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link $ZodCUID2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const $ZodCUID = /*@__PURE__*/ $constructor("$ZodCUID", (inst, def) => { + def.pattern ?? (def.pattern = cuid); + $ZodStringFormat.init(inst, def); + }); + const $ZodCUID2 = /*@__PURE__*/ $constructor("$ZodCUID2", (inst, def) => { + def.pattern ?? (def.pattern = cuid2); + $ZodStringFormat.init(inst, def); + }); + const $ZodULID = /*@__PURE__*/ $constructor("$ZodULID", (inst, def) => { + def.pattern ?? (def.pattern = ulid); + $ZodStringFormat.init(inst, def); + }); + const $ZodXID = /*@__PURE__*/ $constructor("$ZodXID", (inst, def) => { + def.pattern ?? (def.pattern = xid); + $ZodStringFormat.init(inst, def); + }); + const $ZodKSUID = /*@__PURE__*/ $constructor("$ZodKSUID", (inst, def) => { + def.pattern ?? (def.pattern = ksuid); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODateTime = /*@__PURE__*/ $constructor("$ZodISODateTime", (inst, def) => { + def.pattern ?? (def.pattern = datetime$1(def)); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODate = /*@__PURE__*/ $constructor("$ZodISODate", (inst, def) => { + def.pattern ?? (def.pattern = date$1); + $ZodStringFormat.init(inst, def); + }); + const $ZodISOTime = /*@__PURE__*/ $constructor("$ZodISOTime", (inst, def) => { + def.pattern ?? (def.pattern = time$1(def)); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODuration = /*@__PURE__*/ $constructor("$ZodISODuration", (inst, def) => { + def.pattern ?? (def.pattern = duration$1); + $ZodStringFormat.init(inst, def); + }); + const $ZodIPv4 = /*@__PURE__*/ $constructor("$ZodIPv4", (inst, def) => { + def.pattern ?? (def.pattern = ipv4); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv4`; + }); + const $ZodIPv6 = /*@__PURE__*/ $constructor("$ZodIPv6", (inst, def) => { + def.pattern ?? (def.pattern = ipv6); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv6`; + inst._zod.check = (payload) => { + try { + new URL(`http://[${payload.value}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "ipv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + const $ZodCIDRv4 = /*@__PURE__*/ $constructor("$ZodCIDRv4", (inst, def) => { + def.pattern ?? (def.pattern = cidrv4); + $ZodStringFormat.init(inst, def); + }); + const $ZodCIDRv6 = /*@__PURE__*/ $constructor("$ZodCIDRv6", (inst, def) => { + def.pattern ?? (def.pattern = cidrv6); + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + const parts = payload.value.split("/"); + try { + if (parts.length !== 2) throw new Error(); + const [address, prefix] = parts; + if (!prefix) throw new Error(); + const prefixNum = Number(prefix); + if (`${prefixNum}` !== prefix) throw new Error(); + if (prefixNum < 0 || prefixNum > 128) throw new Error(); + new URL(`http://[${address}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "cidrv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + function isValidBase64(data) { + if (data === "") return true; + if (/\s/.test(data)) return false; + if (data.length % 4 !== 0) return false; + try { + atob(data); + return true; + } catch { + return false; + } + } + const $ZodBase64 = /*@__PURE__*/ $constructor("$ZodBase64", (inst, def) => { + def.pattern ?? (def.pattern = base64); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64"; + inst._zod.check = (payload) => { + if (isValidBase64(payload.value)) return; + payload.issues.push({ + code: "invalid_format", + format: "base64", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + function isValidBase64URL(data) { + if (!base64url.test(data)) return false; + const base64 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/"); + return isValidBase64(base64.padEnd(Math.ceil(base64.length / 4) * 4, "=")); + } + const $ZodBase64URL = /*@__PURE__*/ $constructor("$ZodBase64URL", (inst, def) => { + def.pattern ?? (def.pattern = base64url); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64url"; + inst._zod.check = (payload) => { + if (isValidBase64URL(payload.value)) return; + payload.issues.push({ + code: "invalid_format", + format: "base64url", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodE164 = /*@__PURE__*/ $constructor("$ZodE164", (inst, def) => { + def.pattern ?? (def.pattern = e164); + $ZodStringFormat.init(inst, def); + }); + function isValidJWT(token, algorithm = null) { + try { + const tokensParts = token.split("."); + if (tokensParts.length !== 3) return false; + const [header] = tokensParts; + if (!header) return false; + const parsedHeader = JSON.parse(atob(header)); + if ("typ" in parsedHeader && parsedHeader?.typ !== "JWT") return false; + if (!parsedHeader.alg) return false; + if (algorithm && (!("alg" in parsedHeader) || parsedHeader.alg !== algorithm)) return false; + return true; + } catch { + return false; + } + } + const $ZodJWT = /*@__PURE__*/ $constructor("$ZodJWT", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + if (isValidJWT(payload.value, def.alg)) return; + payload.issues.push({ + code: "invalid_format", + format: "jwt", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodNumber = /*@__PURE__*/ $constructor("$ZodNumber", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = inst._zod.bag.pattern ?? number$1; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) try { + payload.value = Number(payload.value); + } catch (_) {} + const input = payload.value; + if (typeof input === "number" && !Number.isNaN(input) && Number.isFinite(input)) return payload; + const received = typeof input === "number" ? Number.isNaN(input) ? "NaN" : !Number.isFinite(input) ? "Infinity" : void 0 : void 0; + payload.issues.push({ + expected: "number", + code: "invalid_type", + input, + inst, + ...received ? { received } : {} + }); + return payload; + }; + }); + const $ZodNumberFormat = /*@__PURE__*/ $constructor("$ZodNumberFormat", (inst, def) => { + $ZodCheckNumberFormat.init(inst, def); + $ZodNumber.init(inst, def); + }); + const $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = boolean$1; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) try { + payload.value = Boolean(payload.value); + } catch (_) {} + const input = payload.value; + if (typeof input === "boolean") return payload; + payload.issues.push({ + expected: "boolean", + code: "invalid_type", + input, + inst + }); + return payload; + }; + }); + const $ZodUndefined = /*@__PURE__*/ $constructor("$ZodUndefined", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = _undefined$2; + inst._zod.values = new Set([void 0]); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (typeof input === "undefined") return payload; + payload.issues.push({ + expected: "undefined", + code: "invalid_type", + input, + inst + }); + return payload; + }; + }); + const $ZodUnknown = /*@__PURE__*/ $constructor("$ZodUnknown", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload) => payload; + }); + const $ZodNever = /*@__PURE__*/ $constructor("$ZodNever", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, _ctx) => { + payload.issues.push({ + expected: "never", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; + }); + function handleArrayResult(result, final, index) { + if (result.issues.length) final.issues.push(...prefixIssues(index, result.issues)); + final.value[index] = result.value; + } + const $ZodArray = /*@__PURE__*/ $constructor("$ZodArray", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!Array.isArray(input)) { + payload.issues.push({ + expected: "array", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = Array(input.length); + const proms = []; + for (let i = 0; i < input.length; i++) { + const item = input[i]; + const result = def.element._zod.run({ + value: item, + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => handleArrayResult(result, payload, i))); + else handleArrayResult(result, payload, i); + } + if (proms.length) return Promise.all(proms).then(() => payload); + return payload; + }; + }); + function handlePropertyResult(result, final, key, input, isOptionalIn, isOptionalOut) { + const isPresent = key in input; + if (result.issues.length) { + if (isOptionalIn && isOptionalOut && !isPresent) return; + final.issues.push(...prefixIssues(key, result.issues)); + } + if (!isPresent && !isOptionalIn) { + if (!result.issues.length) final.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: void 0, + path: [key] + }); + return; + } + if (result.value === void 0) { + if (isPresent) final.value[key] = void 0; + } else final.value[key] = result.value; + } + function normalizeDef(def) { + const keys = Object.keys(def.shape); + for (const k of keys) if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) throw new Error(`Invalid element at key "${k}": expected a Zod schema`); + const okeys = optionalKeys(def.shape); + return { + ...def, + keys, + keySet: new Set(keys), + numKeys: keys.length, + optionalKeys: new Set(okeys) + }; + } + function handleCatchall(proms, input, payload, ctx, def, inst) { + const unrecognized = []; + const keySet = def.keySet; + const _catchall = def.catchall._zod; + const t = _catchall.def.type; + const isOptionalIn = _catchall.optin === "optional"; + const isOptionalOut = _catchall.optout === "optional"; + for (const key in input) { + if (key === "__proto__") continue; + if (keySet.has(key)) continue; + if (t === "never") { + unrecognized.push(key); + continue; + } + const r = _catchall.run({ + value: input[key], + issues: [] + }, ctx); + if (r instanceof Promise) proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut))); + else handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + if (unrecognized.length) payload.issues.push({ + code: "unrecognized_keys", + keys: unrecognized, + input, + inst + }); + if (!proms.length) return payload; + return Promise.all(proms).then(() => { + return payload; + }); + } + const $ZodObject = /*@__PURE__*/ $constructor("$ZodObject", (inst, def) => { + $ZodType.init(inst, def); + if (!Object.getOwnPropertyDescriptor(def, "shape")?.get) { + const sh = def.shape; + Object.defineProperty(def, "shape", { get: () => { + const newSh = { ...sh }; + Object.defineProperty(def, "shape", { value: newSh }); + return newSh; + } }); + } + const _normalized = cached(() => normalizeDef(def)); + defineLazy(inst._zod, "propValues", () => { + const shape = def.shape; + const propValues = {}; + for (const key in shape) { + const field = shape[key]._zod; + if (field.values) { + propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set()); + for (const v of field.values) propValues[key].add(v); + } + } + return propValues; + }); + const isObject$1 = isObject; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject$1(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = {}; + const proms = []; + const shape = value.shape; + for (const key of value.keys) { + const el = shape[key]; + const isOptionalIn = el._zod.optin === "optional"; + const isOptionalOut = el._zod.optout === "optional"; + const r = el._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (r instanceof Promise) proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut))); + else handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + if (!catchall) return proms.length ? Promise.all(proms).then(() => payload) : payload; + return handleCatchall(proms, input, payload, ctx, _normalized.value, inst); + }; + }); + const $ZodObjectJIT = /*@__PURE__*/ $constructor("$ZodObjectJIT", (inst, def) => { + $ZodObject.init(inst, def); + const superParse = inst._zod.parse; + const _normalized = cached(() => normalizeDef(def)); + const generateFastpass = (shape) => { + const doc = new Doc([ + "shape", + "payload", + "ctx" + ]); + const normalized = _normalized.value; + const parseStr = (key) => { + const k = esc(key); + return `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`; + }; + doc.write(`const input = payload.value;`); + const ids = Object.create(null); + let counter = 0; + for (const key of normalized.keys) ids[key] = `key_${counter++}`; + doc.write(`const newResult = {};`); + for (const key of normalized.keys) { + const id = ids[key]; + const k = esc(key); + const schema = shape[key]; + const isOptionalIn = schema?._zod?.optin === "optional"; + const isOptionalOut = schema?._zod?.optout === "optional"; + doc.write(`const ${id} = ${parseStr(key)};`); + if (isOptionalIn && isOptionalOut) doc.write(` + if (${id}.issues.length) { + if (${k} in input) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + else if (!isOptionalIn) doc.write(` + const ${id}_present = ${k} in input; + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + if (!${id}_present && !${id}.issues.length) { + payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: undefined, + path: [${k}] + }); + } + + if (${id}_present) { + if (${id}.value === undefined) { + newResult[${k}] = undefined; + } else { + newResult[${k}] = ${id}.value; + } + } + + `); + else doc.write(` + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + } + doc.write(`payload.value = newResult;`); + doc.write(`return payload;`); + const fn = doc.compile(); + return (payload, ctx) => fn(shape, payload, ctx); + }; + let fastpass; + const isObject$2 = isObject; + const jit = !globalConfig.jitless; + const fastEnabled = jit && allowsEval.value; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject$2(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + if (jit && fastEnabled && ctx?.async === false && ctx.jitless !== true) { + if (!fastpass) fastpass = generateFastpass(def.shape); + payload = fastpass(payload, ctx); + if (!catchall) return payload; + return handleCatchall([], input, payload, ctx, value, inst); + } + return superParse(payload, ctx); + }; + }); + function handleUnionResults(results, final, inst, ctx) { + for (const result of results) if (result.issues.length === 0) { + final.value = result.value; + return final; + } + const nonaborted = results.filter((r) => !aborted(r)); + if (nonaborted.length === 1) { + final.value = nonaborted[0].value; + return nonaborted[0]; + } + final.issues.push({ + code: "invalid_union", + input: final.value, + inst, + errors: results.map((result) => result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + }); + return final; + } + const $ZodUnion = /*@__PURE__*/ $constructor("$ZodUnion", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.options.some((o) => o._zod.optin === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "optout", () => def.options.some((o) => o._zod.optout === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "values", () => { + if (def.options.every((o) => o._zod.values)) return new Set(def.options.flatMap((option) => Array.from(option._zod.values))); + }); + defineLazy(inst._zod, "pattern", () => { + if (def.options.every((o) => o._zod.pattern)) { + const patterns = def.options.map((o) => o._zod.pattern); + return new RegExp(`^(${patterns.map((p) => cleanRegex(p.source)).join("|")})$`); + } + }); + const first = def.options.length === 1 ? def.options[0]._zod.run : null; + inst._zod.parse = (payload, ctx) => { + if (first) return first(payload, ctx); + let async = false; + const results = []; + for (const option of def.options) { + const result = option._zod.run({ + value: payload.value, + issues: [] + }, ctx); + if (result instanceof Promise) { + results.push(result); + async = true; + } else { + if (result.issues.length === 0) return result; + results.push(result); + } + } + if (!async) return handleUnionResults(results, payload, inst, ctx); + return Promise.all(results).then((results) => { + return handleUnionResults(results, payload, inst, ctx); + }); + }; + }); + const $ZodIntersection = /*@__PURE__*/ $constructor("$ZodIntersection", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + const left = def.left._zod.run({ + value: input, + issues: [] + }, ctx); + const right = def.right._zod.run({ + value: input, + issues: [] + }, ctx); + if (left instanceof Promise || right instanceof Promise) return Promise.all([left, right]).then(([left, right]) => { + return handleIntersectionResults(payload, left, right); + }); + return handleIntersectionResults(payload, left, right); + }; + }); + function mergeValues(a, b) { + if (a === b) return { + valid: true, + data: a + }; + if (a instanceof Date && b instanceof Date && +a === +b) return { + valid: true, + data: a + }; + if (isPlainObject(a) && isPlainObject(b)) { + const bKeys = Object.keys(b); + const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1); + const newObj = { + ...a, + ...b + }; + for (const key of sharedKeys) { + const sharedValue = mergeValues(a[key], b[key]); + if (!sharedValue.valid) return { + valid: false, + mergeErrorPath: [key, ...sharedValue.mergeErrorPath] + }; + newObj[key] = sharedValue.data; + } + return { + valid: true, + data: newObj + }; + } + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) return { + valid: false, + mergeErrorPath: [] + }; + const newArray = []; + for (let index = 0; index < a.length; index++) { + const itemA = a[index]; + const itemB = b[index]; + const sharedValue = mergeValues(itemA, itemB); + if (!sharedValue.valid) return { + valid: false, + mergeErrorPath: [index, ...sharedValue.mergeErrorPath] + }; + newArray.push(sharedValue.data); + } + return { + valid: true, + data: newArray + }; + } + return { + valid: false, + mergeErrorPath: [] + }; + } + function handleIntersectionResults(result, left, right) { + const unrecKeys = /* @__PURE__ */ new Map(); + let unrecIssue; + for (const iss of left.issues) if (iss.code === "unrecognized_keys") { + unrecIssue ?? (unrecIssue = iss); + for (const k of iss.keys) { + if (!unrecKeys.has(k)) unrecKeys.set(k, {}); + unrecKeys.get(k).l = true; + } + } else result.issues.push(iss); + for (const iss of right.issues) if (iss.code === "unrecognized_keys") for (const k of iss.keys) { + if (!unrecKeys.has(k)) unrecKeys.set(k, {}); + unrecKeys.get(k).r = true; + } + else result.issues.push(iss); + const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k); + if (bothKeys.length && unrecIssue) result.issues.push({ + ...unrecIssue, + keys: bothKeys + }); + if (aborted(result)) return result; + const merged = mergeValues(left.value, right.value); + if (!merged.valid) throw new Error(`Unmergable intersection. Error path: ${JSON.stringify(merged.mergeErrorPath)}`); + result.value = merged.data; + return result; + } + const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!isPlainObject(input)) { + payload.issues.push({ + expected: "record", + code: "invalid_type", + input, + inst + }); + return payload; + } + const proms = []; + const values = def.keyType._zod.values; + if (values) { + payload.value = {}; + const recordKeys = /* @__PURE__ */ new Set(); + for (const key of values) if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") { + recordKeys.add(typeof key === "number" ? key.toString() : key); + const keyResult = def.keyType._zod.run({ + value: key, + issues: [] + }, ctx); + if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (keyResult.issues.length) { + payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + continue; + } + const outKey = keyResult.value; + const result = def.valueType._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[outKey] = result.value; + })); + else { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[outKey] = result.value; + } + } + let unrecognized; + for (const key in input) if (!recordKeys.has(key)) { + unrecognized = unrecognized ?? []; + unrecognized.push(key); + } + if (unrecognized && unrecognized.length > 0) payload.issues.push({ + code: "unrecognized_keys", + input, + inst, + keys: unrecognized + }); + } else { + payload.value = {}; + for (const key of Reflect.ownKeys(input)) { + if (key === "__proto__") continue; + if (!Object.prototype.propertyIsEnumerable.call(input, key)) continue; + let keyResult = def.keyType._zod.run({ + value: key, + issues: [] + }, ctx); + if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (typeof key === "string" && number$1.test(key) && keyResult.issues.length) { + const retryResult = def.keyType._zod.run({ + value: Number(key), + issues: [] + }, ctx); + if (retryResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (retryResult.issues.length === 0) keyResult = retryResult; + } + if (keyResult.issues.length) { + if (def.mode === "loose") payload.value[key] = input[key]; + else payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + continue; + } + const result = def.valueType._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[keyResult.value] = result.value; + })); + else { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[keyResult.value] = result.value; + } + } + } + if (proms.length) return Promise.all(proms).then(() => payload); + return payload; + }; + }); + const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => { + $ZodType.init(inst, def); + const values = getEnumValues(def.entries); + const valuesSet = new Set(values); + inst._zod.values = valuesSet; + inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (valuesSet.has(input)) return payload; + payload.issues.push({ + code: "invalid_value", + values, + input, + inst + }); + return payload; + }; + }); + const $ZodLiteral = /*@__PURE__*/ $constructor("$ZodLiteral", (inst, def) => { + $ZodType.init(inst, def); + if (def.values.length === 0) throw new Error("Cannot create literal schema with no valid values"); + const values = new Set(def.values); + inst._zod.values = values; + inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (values.has(input)) return payload; + payload.issues.push({ + code: "invalid_value", + values: def.values, + input, + inst + }); + return payload; + }; + }); + const $ZodTransform = /*@__PURE__*/ $constructor("$ZodTransform", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") throw new $ZodEncodeError(inst.constructor.name); + const _out = def.transform(payload.value, payload); + if (ctx.async) return (_out instanceof Promise ? _out : Promise.resolve(_out)).then((output) => { + payload.value = output; + payload.fallback = true; + return payload; + }); + if (_out instanceof Promise) throw new $ZodAsyncError(); + payload.value = _out; + payload.fallback = true; + return payload; + }; + }); + function handleOptionalResult(result, input) { + if (input === void 0 && (result.issues.length || result.fallback)) return { + issues: [], + value: void 0 + }; + return result; + } + const $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.optout = "optional"; + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? new Set([...def.innerType._zod.values, void 0]) : void 0; + }); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)})?$`) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (def.innerType._zod.optin === "optional") { + const input = payload.value; + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((r) => handleOptionalResult(r, input)); + return handleOptionalResult(result, input); + } + if (payload.value === void 0) return payload; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodExactOptional = /*@__PURE__*/ $constructor("$ZodExactOptional", (inst, def) => { + $ZodOptional.init(inst, def); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "pattern", () => def.innerType._zod.pattern); + inst._zod.parse = (payload, ctx) => { + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodNullable = /*@__PURE__*/ $constructor("$ZodNullable", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.innerType._zod.optin); + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0; + }); + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (payload.value === null) return payload; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodDefault = /*@__PURE__*/ $constructor("$ZodDefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + if (payload.value === void 0) { + payload.value = def.defaultValue; + /** + * $ZodDefault returns the default value immediately in forward direction. + * It doesn't pass the default value into the validator ("prefault"). There's no reason to pass the default value through validation. The validity of the default is enforced by TypeScript statically. Otherwise, it's the responsibility of the user to ensure the default is valid. In the case of pipes with divergent in/out types, you can specify the default on the `in` schema of your ZodPipe to set a "prefault" for the pipe. */ + return payload; + } + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => handleDefaultResult(result, def)); + return handleDefaultResult(result, def); + }; + }); + function handleDefaultResult(payload, def) { + if (payload.value === void 0) payload.value = def.defaultValue; + return payload; + } + const $ZodPrefault = /*@__PURE__*/ $constructor("$ZodPrefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + if (payload.value === void 0) payload.value = def.defaultValue; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodNonOptional = /*@__PURE__*/ $constructor("$ZodNonOptional", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => { + const v = def.innerType._zod.values; + return v ? new Set([...v].filter((x) => x !== void 0)) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => handleNonOptionalResult(result, inst)); + return handleNonOptionalResult(result, inst); + }; + }); + function handleNonOptionalResult(payload, inst) { + if (!payload.issues.length && payload.value === void 0) payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: payload.value, + inst + }); + return payload; + } + const $ZodCatch = /*@__PURE__*/ $constructor("$ZodCatch", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => { + payload.value = result.value; + if (result.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }); + payload.value = result.value; + if (result.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }; + }); + const $ZodPipe = /*@__PURE__*/ $constructor("$ZodPipe", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => def.in._zod.values); + defineLazy(inst._zod, "optin", () => def.in._zod.optin); + defineLazy(inst._zod, "optout", () => def.out._zod.optout); + defineLazy(inst._zod, "propValues", () => def.in._zod.propValues); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + const right = def.out._zod.run(payload, ctx); + if (right instanceof Promise) return right.then((right) => handlePipeResult(right, def.in, ctx)); + return handlePipeResult(right, def.in, ctx); + } + const left = def.in._zod.run(payload, ctx); + if (left instanceof Promise) return left.then((left) => handlePipeResult(left, def.out, ctx)); + return handlePipeResult(left, def.out, ctx); + }; + }); + function handlePipeResult(left, next, ctx) { + if (left.issues.length) { + left.aborted = true; + return left; + } + return next._zod.run({ + value: left.value, + issues: left.issues, + fallback: left.fallback + }, ctx); + } + const $ZodReadonly = /*@__PURE__*/ $constructor("$ZodReadonly", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "propValues", () => def.innerType._zod.propValues); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "optin", () => def.innerType?._zod?.optin); + defineLazy(inst._zod, "optout", () => def.innerType?._zod?.optout); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then(handleReadonlyResult); + return handleReadonlyResult(result); + }; + }); + function handleReadonlyResult(payload) { + payload.value = Object.freeze(payload.value); + return payload; + } + const $ZodLazy = /*@__PURE__*/ $constructor("$ZodLazy", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "innerType", () => { + const d = def; + if (!d._cachedInner) d._cachedInner = def.getter(); + return d._cachedInner; + }); + defineLazy(inst._zod, "pattern", () => inst._zod.innerType?._zod?.pattern); + defineLazy(inst._zod, "propValues", () => inst._zod.innerType?._zod?.propValues); + defineLazy(inst._zod, "optin", () => inst._zod.innerType?._zod?.optin ?? void 0); + defineLazy(inst._zod, "optout", () => inst._zod.innerType?._zod?.optout ?? void 0); + inst._zod.parse = (payload, ctx) => { + return inst._zod.innerType._zod.run(payload, ctx); + }; + }); + const $ZodCustom = /*@__PURE__*/ $constructor("$ZodCustom", (inst, def) => { + $ZodCheck.init(inst, def); + $ZodType.init(inst, def); + inst._zod.parse = (payload, _) => { + return payload; + }; + inst._zod.check = (payload) => { + const input = payload.value; + const r = def.fn(input); + if (r instanceof Promise) return r.then((r) => handleRefineResult(r, payload, input, inst)); + handleRefineResult(r, payload, input, inst); + }; + }); + function handleRefineResult(result, payload, input, inst) { + if (!result) { + const _iss = { + code: "custom", + input, + inst, + path: [...inst._zod.def.path ?? []], + continue: !inst._zod.def.abort + }; + if (inst._zod.def.params) _iss.params = inst._zod.def.params; + payload.issues.push(issue(_iss)); + } + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.js + var _a; + var $ZodRegistry = class { + constructor() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + } + add(schema, ..._meta) { + const meta = _meta[0]; + this._map.set(schema, meta); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.set(meta.id, schema); + return this; + } + clear() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + return this; + } + remove(schema) { + const meta = this._map.get(schema); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.delete(meta.id); + this._map.delete(schema); + return this; + } + get(schema) { + const p = schema._zod.parent; + if (p) { + const pm = { ...this.get(p) ?? {} }; + delete pm.id; + const f = { + ...pm, + ...this._map.get(schema) + }; + return Object.keys(f).length ? f : void 0; + } + return this._map.get(schema); + } + has(schema) { + return this._map.has(schema); + } + }; + function registry() { + return new $ZodRegistry(); + } + (_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry()); + const globalRegistry = globalThis.__zod_globalRegistry; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/api.js + // @__NO_SIDE_EFFECTS__ + function _string(Class, params) { + return new Class({ + type: "string", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _email(Class, params) { + return new Class({ + type: "string", + format: "email", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _guid(Class, params) { + return new Class({ + type: "string", + format: "guid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuid(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv4(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v4", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv6(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v6", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv7(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v7", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _url(Class, params) { + return new Class({ + type: "string", + format: "url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _emoji(Class, params) { + return new Class({ + type: "string", + format: "emoji", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _nanoid(Class, params) { + return new Class({ + type: "string", + format: "nanoid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link _cuid2} instead. + * See https://github.com/paralleldrive/cuid. + */ + // @__NO_SIDE_EFFECTS__ + function _cuid(Class, params) { + return new Class({ + type: "string", + format: "cuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cuid2(Class, params) { + return new Class({ + type: "string", + format: "cuid2", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ulid(Class, params) { + return new Class({ + type: "string", + format: "ulid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _xid(Class, params) { + return new Class({ + type: "string", + format: "xid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ksuid(Class, params) { + return new Class({ + type: "string", + format: "ksuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ipv4(Class, params) { + return new Class({ + type: "string", + format: "ipv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ipv6(Class, params) { + return new Class({ + type: "string", + format: "ipv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cidrv4(Class, params) { + return new Class({ + type: "string", + format: "cidrv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cidrv6(Class, params) { + return new Class({ + type: "string", + format: "cidrv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _base64(Class, params) { + return new Class({ + type: "string", + format: "base64", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _base64url(Class, params) { + return new Class({ + type: "string", + format: "base64url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _e164(Class, params) { + return new Class({ + type: "string", + format: "e164", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _jwt(Class, params) { + return new Class({ + type: "string", + format: "jwt", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDateTime(Class, params) { + return new Class({ + type: "string", + format: "datetime", + check: "string_format", + offset: false, + local: false, + precision: null, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDate(Class, params) { + return new Class({ + type: "string", + format: "date", + check: "string_format", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoTime(Class, params) { + return new Class({ + type: "string", + format: "time", + check: "string_format", + precision: null, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDuration(Class, params) { + return new Class({ + type: "string", + format: "duration", + check: "string_format", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _number(Class, params) { + return new Class({ + type: "number", + checks: [], + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _int(Class, params) { + return new Class({ + type: "number", + check: "number_format", + abort: false, + format: "safeint", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _boolean(Class, params) { + return new Class({ + type: "boolean", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _undefined$1(Class, params) { + return new Class({ + type: "undefined", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _unknown(Class) { + return new Class({ type: "unknown" }); + } + // @__NO_SIDE_EFFECTS__ + function _never(Class, params) { + return new Class({ + type: "never", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _lt(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: false + }); + } + // @__NO_SIDE_EFFECTS__ + function _lte(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: true + }); + } + // @__NO_SIDE_EFFECTS__ + function _gt(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: false + }); + } + // @__NO_SIDE_EFFECTS__ + function _gte(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: true + }); + } + // @__NO_SIDE_EFFECTS__ + function _multipleOf(value, params) { + return new $ZodCheckMultipleOf({ + check: "multiple_of", + ...normalizeParams(params), + value + }); + } + // @__NO_SIDE_EFFECTS__ + function _maxLength(maximum, params) { + return new $ZodCheckMaxLength({ + check: "max_length", + ...normalizeParams(params), + maximum + }); + } + // @__NO_SIDE_EFFECTS__ + function _minLength(minimum, params) { + return new $ZodCheckMinLength({ + check: "min_length", + ...normalizeParams(params), + minimum + }); + } + // @__NO_SIDE_EFFECTS__ + function _length(length, params) { + return new $ZodCheckLengthEquals({ + check: "length_equals", + ...normalizeParams(params), + length + }); + } + // @__NO_SIDE_EFFECTS__ + function _regex(pattern, params) { + return new $ZodCheckRegex({ + check: "string_format", + format: "regex", + ...normalizeParams(params), + pattern + }); + } + // @__NO_SIDE_EFFECTS__ + function _lowercase(params) { + return new $ZodCheckLowerCase({ + check: "string_format", + format: "lowercase", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uppercase(params) { + return new $ZodCheckUpperCase({ + check: "string_format", + format: "uppercase", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _includes(includes, params) { + return new $ZodCheckIncludes({ + check: "string_format", + format: "includes", + ...normalizeParams(params), + includes + }); + } + // @__NO_SIDE_EFFECTS__ + function _startsWith(prefix, params) { + return new $ZodCheckStartsWith({ + check: "string_format", + format: "starts_with", + ...normalizeParams(params), + prefix + }); + } + // @__NO_SIDE_EFFECTS__ + function _endsWith(suffix, params) { + return new $ZodCheckEndsWith({ + check: "string_format", + format: "ends_with", + ...normalizeParams(params), + suffix + }); + } + // @__NO_SIDE_EFFECTS__ + function _overwrite(tx) { + return new $ZodCheckOverwrite({ + check: "overwrite", + tx + }); + } + // @__NO_SIDE_EFFECTS__ + function _normalize(form) { + return /* @__PURE__ */ _overwrite((input) => input.normalize(form)); + } + // @__NO_SIDE_EFFECTS__ + function _trim() { + return /* @__PURE__ */ _overwrite((input) => input.trim()); + } + // @__NO_SIDE_EFFECTS__ + function _toLowerCase() { + return /* @__PURE__ */ _overwrite((input) => input.toLowerCase()); + } + // @__NO_SIDE_EFFECTS__ + function _toUpperCase() { + return /* @__PURE__ */ _overwrite((input) => input.toUpperCase()); + } + // @__NO_SIDE_EFFECTS__ + function _slugify() { + return /* @__PURE__ */ _overwrite((input) => slugify(input)); + } + // @__NO_SIDE_EFFECTS__ + function _array(Class, element, params) { + return new Class({ + type: "array", + element, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _refine(Class, fn, _params) { + return new Class({ + type: "custom", + check: "custom", + fn, + ...normalizeParams(_params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _superRefine(fn, params) { + const ch = /* @__PURE__ */ _check((payload) => { + payload.addIssue = (issue$2) => { + if (typeof issue$2 === "string") payload.issues.push(issue(issue$2, payload.value, ch._zod.def)); + else { + const _issue = issue$2; + if (_issue.fatal) _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = ch); + _issue.continue ?? (_issue.continue = !ch._zod.def.abort); + payload.issues.push(issue(_issue)); + } + }; + return fn(payload.value, payload); + }, params); + return ch; + } + // @__NO_SIDE_EFFECTS__ + function _check(fn, params) { + const ch = new $ZodCheck({ + check: "custom", + ...normalizeParams(params) + }); + ch._zod.check = fn; + return ch; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.js + function initializeContext(params) { + let target = params?.target ?? "draft-2020-12"; + if (target === "draft-4") target = "draft-04"; + if (target === "draft-7") target = "draft-07"; + return { + processors: params.processors ?? {}, + metadataRegistry: params?.metadata ?? globalRegistry, + target, + unrepresentable: params?.unrepresentable ?? "throw", + override: params?.override ?? (() => {}), + io: params?.io ?? "output", + counter: 0, + seen: /* @__PURE__ */ new Map(), + cycles: params?.cycles ?? "ref", + reused: params?.reused ?? "inline", + external: params?.external ?? void 0 + }; + } + function process(schema, ctx, _params = { + path: [], + schemaPath: [] + }) { + var _a; + const def = schema._zod.def; + const seen = ctx.seen.get(schema); + if (seen) { + seen.count++; + if (_params.schemaPath.includes(schema)) seen.cycle = _params.path; + return seen.schema; + } + const result = { + schema: {}, + count: 1, + cycle: void 0, + path: _params.path + }; + ctx.seen.set(schema, result); + const overrideSchema = schema._zod.toJSONSchema?.(); + if (overrideSchema) result.schema = overrideSchema; + else { + const params = { + ..._params, + schemaPath: [..._params.schemaPath, schema], + path: _params.path + }; + if (schema._zod.processJSONSchema) schema._zod.processJSONSchema(ctx, result.schema, params); + else { + const _json = result.schema; + const processor = ctx.processors[def.type]; + if (!processor) throw new Error(`[toJSONSchema]: Non-representable type encountered: ${def.type}`); + processor(schema, ctx, _json, params); + } + const parent = schema._zod.parent; + if (parent) { + if (!result.ref) result.ref = parent; + process(parent, ctx, params); + ctx.seen.get(parent).isParent = true; + } + } + const meta = ctx.metadataRegistry.get(schema); + if (meta) Object.assign(result.schema, meta); + if (ctx.io === "input" && isTransforming(schema)) { + delete result.schema.examples; + delete result.schema.default; + } + if (ctx.io === "input" && "_prefault" in result.schema) (_a = result.schema).default ?? (_a.default = result.schema._prefault); + delete result.schema._prefault; + return ctx.seen.get(schema).schema; + } + function extractDefs(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const idToSchema = /* @__PURE__ */ new Map(); + for (const entry of ctx.seen.entries()) { + const id = ctx.metadataRegistry.get(entry[0])?.id; + if (id) { + const existing = idToSchema.get(id); + if (existing && existing !== entry[0]) throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`); + idToSchema.set(id, entry[0]); + } + } + const makeURI = (entry) => { + const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions"; + if (ctx.external) { + const externalId = ctx.external.registry.get(entry[0])?.id; + const uriGenerator = ctx.external.uri ?? ((id) => id); + if (externalId) return { ref: uriGenerator(externalId) }; + const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`; + entry[1].defId = id; + return { + defId: id, + ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` + }; + } + if (entry[1] === root) return { ref: "#" }; + const defUriPrefix = `#/${defsSegment}/`; + const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`; + return { + defId, + ref: defUriPrefix + defId + }; + }; + const extractToDef = (entry) => { + if (entry[1].schema.$ref) return; + const seen = entry[1]; + const { ref, defId } = makeURI(entry); + seen.def = { ...seen.schema }; + if (defId) seen.defId = defId; + const schema = seen.schema; + for (const key in schema) delete schema[key]; + schema.$ref = ref; + }; + if (ctx.cycles === "throw") for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.cycle) throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/ + +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`); + } + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (schema === entry[0]) { + extractToDef(entry); + continue; + } + if (ctx.external) { + const ext = ctx.external.registry.get(entry[0])?.id; + if (schema !== entry[0] && ext) { + extractToDef(entry); + continue; + } + } + if (ctx.metadataRegistry.get(entry[0])?.id) { + extractToDef(entry); + continue; + } + if (seen.cycle) { + extractToDef(entry); + continue; + } + if (seen.count > 1) { + if (ctx.reused === "ref") { + extractToDef(entry); + continue; + } + } + } + } + function finalize(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const flattenRef = (zodSchema) => { + const seen = ctx.seen.get(zodSchema); + if (seen.ref === null) return; + const schema = seen.def ?? seen.schema; + const _cached = { ...schema }; + const ref = seen.ref; + seen.ref = null; + if (ref) { + flattenRef(ref); + const refSeen = ctx.seen.get(ref); + const refSchema = refSeen.schema; + if (refSchema.$ref && (ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0")) { + schema.allOf = schema.allOf ?? []; + schema.allOf.push(refSchema); + } else Object.assign(schema, refSchema); + Object.assign(schema, _cached); + if (zodSchema._zod.parent === ref) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (!(key in _cached)) delete schema[key]; + } + if (refSchema.$ref && refSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in refSeen.def && JSON.stringify(schema[key]) === JSON.stringify(refSeen.def[key])) delete schema[key]; + } + } + const parent = zodSchema._zod.parent; + if (parent && parent !== ref) { + flattenRef(parent); + const parentSeen = ctx.seen.get(parent); + if (parentSeen?.schema.$ref) { + schema.$ref = parentSeen.schema.$ref; + if (parentSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in parentSeen.def && JSON.stringify(schema[key]) === JSON.stringify(parentSeen.def[key])) delete schema[key]; + } + } + } + ctx.override({ + zodSchema, + jsonSchema: schema, + path: seen.path ?? [] + }); + }; + for (const entry of [...ctx.seen.entries()].reverse()) flattenRef(entry[0]); + const result = {}; + if (ctx.target === "draft-2020-12") result.$schema = "https://json-schema.org/draft/2020-12/schema"; + else if (ctx.target === "draft-07") result.$schema = "http://json-schema.org/draft-07/schema#"; + else if (ctx.target === "draft-04") result.$schema = "http://json-schema.org/draft-04/schema#"; + else if (ctx.target === "openapi-3.0") {} + if (ctx.external?.uri) { + const id = ctx.external.registry.get(schema)?.id; + if (!id) throw new Error("Schema is missing an `id` property"); + result.$id = ctx.external.uri(id); + } + Object.assign(result, root.def ?? root.schema); + const rootMetaId = ctx.metadataRegistry.get(schema)?.id; + if (rootMetaId !== void 0 && result.id === rootMetaId) delete result.id; + const defs = ctx.external?.defs ?? {}; + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.def && seen.defId) { + if (seen.def.id === seen.defId) delete seen.def.id; + defs[seen.defId] = seen.def; + } + } + if (ctx.external) {} else if (Object.keys(defs).length > 0) if (ctx.target === "draft-2020-12") result.$defs = defs; + else result.definitions = defs; + try { + const finalized = JSON.parse(JSON.stringify(result)); + Object.defineProperty(finalized, "~standard", { + value: { + ...schema["~standard"], + jsonSchema: { + input: createStandardJSONSchemaMethod(schema, "input", ctx.processors), + output: createStandardJSONSchemaMethod(schema, "output", ctx.processors) + } + }, + enumerable: false, + writable: false + }); + return finalized; + } catch (_err) { + throw new Error("Error converting schema to JSON."); + } + } + function isTransforming(_schema, _ctx) { + const ctx = _ctx ?? { seen: /* @__PURE__ */ new Set() }; + if (ctx.seen.has(_schema)) return false; + ctx.seen.add(_schema); + const def = _schema._zod.def; + if (def.type === "transform") return true; + if (def.type === "array") return isTransforming(def.element, ctx); + if (def.type === "set") return isTransforming(def.valueType, ctx); + if (def.type === "lazy") return isTransforming(def.getter(), ctx); + if (def.type === "promise" || def.type === "optional" || def.type === "nonoptional" || def.type === "nullable" || def.type === "readonly" || def.type === "default" || def.type === "prefault") return isTransforming(def.innerType, ctx); + if (def.type === "intersection") return isTransforming(def.left, ctx) || isTransforming(def.right, ctx); + if (def.type === "record" || def.type === "map") return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); + if (def.type === "pipe") { + if (_schema._zod.traits.has("$ZodCodec")) return true; + return isTransforming(def.in, ctx) || isTransforming(def.out, ctx); + } + if (def.type === "object") { + for (const key in def.shape) if (isTransforming(def.shape[key], ctx)) return true; + return false; + } + if (def.type === "union") { + for (const option of def.options) if (isTransforming(option, ctx)) return true; + return false; + } + if (def.type === "tuple") { + for (const item of def.items) if (isTransforming(item, ctx)) return true; + if (def.rest && isTransforming(def.rest, ctx)) return true; + return false; + } + return false; + } + /** + * Creates a toJSONSchema method for a schema instance. + * This encapsulates the logic of initializing context, processing, extracting defs, and finalizing. + */ + const createToJSONSchemaMethod = (schema, processors = {}) => (params) => { + const ctx = initializeContext({ + ...params, + processors + }); + process(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); + }; + const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => { + const { libraryOptions, target } = params ?? {}; + const ctx = initializeContext({ + ...libraryOptions ?? {}, + target, + io, + processors + }); + process(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.js + const formatMap = { + guid: "uuid", + url: "uri", + datetime: "date-time", + json_string: "json-string", + regex: "" + }; + const stringProcessor = (schema, ctx, _json, _params) => { + const json = _json; + json.type = "string"; + const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag; + if (typeof minimum === "number") json.minLength = minimum; + if (typeof maximum === "number") json.maxLength = maximum; + if (format) { + json.format = formatMap[format] ?? format; + if (json.format === "") delete json.format; + if (format === "time") delete json.format; + } + if (contentEncoding) json.contentEncoding = contentEncoding; + if (patterns && patterns.size > 0) { + const regexes = [...patterns]; + if (regexes.length === 1) json.pattern = regexes[0].source; + else if (regexes.length > 1) json.allOf = [...regexes.map((regex) => ({ + ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {}, + pattern: regex.source + }))]; + } + }; + const numberProcessor = (schema, ctx, _json, _params) => { + const json = _json; + const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; + if (typeof format === "string" && format.includes("int")) json.type = "integer"; + else json.type = "number"; + const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY); + const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY); + const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0"; + if (exMin) if (legacy) { + json.minimum = exclusiveMinimum; + json.exclusiveMinimum = true; + } else json.exclusiveMinimum = exclusiveMinimum; + else if (typeof minimum === "number") json.minimum = minimum; + if (exMax) if (legacy) { + json.maximum = exclusiveMaximum; + json.exclusiveMaximum = true; + } else json.exclusiveMaximum = exclusiveMaximum; + else if (typeof maximum === "number") json.maximum = maximum; + if (typeof multipleOf === "number") json.multipleOf = multipleOf; + }; + const booleanProcessor = (_schema, _ctx, json, _params) => { + json.type = "boolean"; + }; + const undefinedProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Undefined cannot be represented in JSON Schema"); + }; + const neverProcessor = (_schema, _ctx, json, _params) => { + json.not = {}; + }; + const enumProcessor = (schema, _ctx, json, _params) => { + const def = schema._zod.def; + const values = getEnumValues(def.entries); + if (values.every((v) => typeof v === "number")) json.type = "number"; + if (values.every((v) => typeof v === "string")) json.type = "string"; + json.enum = values; + }; + const literalProcessor = (schema, ctx, json, _params) => { + const def = schema._zod.def; + const vals = []; + for (const val of def.values) if (val === void 0) { + if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema"); + } else if (typeof val === "bigint") if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema"); + else vals.push(Number(val)); + else vals.push(val); + if (vals.length === 0) {} else if (vals.length === 1) { + const val = vals[0]; + json.type = val === null ? "null" : typeof val; + if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") json.enum = [val]; + else json.const = val; + } else { + if (vals.every((v) => typeof v === "number")) json.type = "number"; + if (vals.every((v) => typeof v === "string")) json.type = "string"; + if (vals.every((v) => typeof v === "boolean")) json.type = "boolean"; + if (vals.every((v) => v === null)) json.type = "null"; + json.enum = vals; + } + }; + const customProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Custom types cannot be represented in JSON Schema"); + }; + const transformProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Transforms cannot be represented in JSON Schema"); + }; + const arrayProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") json.minItems = minimum; + if (typeof maximum === "number") json.maxItems = maximum; + json.type = "array"; + json.items = process(def.element, ctx, { + ...params, + path: [...params.path, "items"] + }); + }; + const objectProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + json.properties = {}; + const shape = def.shape; + for (const key in shape) json.properties[key] = process(shape[key], ctx, { + ...params, + path: [ + ...params.path, + "properties", + key + ] + }); + const allKeys = new Set(Object.keys(shape)); + const requiredKeys = new Set([...allKeys].filter((key) => { + const v = def.shape[key]._zod; + if (ctx.io === "input") return v.optin === void 0; + else return v.optout === void 0; + })); + if (requiredKeys.size > 0) json.required = Array.from(requiredKeys); + if (def.catchall?._zod.def.type === "never") json.additionalProperties = false; + else if (!def.catchall) { + if (ctx.io === "output") json.additionalProperties = false; + } else if (def.catchall) json.additionalProperties = process(def.catchall, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + }; + const unionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const isExclusive = def.inclusive === false; + const options = def.options.map((x, i) => process(x, ctx, { + ...params, + path: [ + ...params.path, + isExclusive ? "oneOf" : "anyOf", + i + ] + })); + if (isExclusive) json.oneOf = options; + else json.anyOf = options; + }; + const intersectionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const a = process(def.left, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 0 + ] + }); + const b = process(def.right, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 1 + ] + }); + const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1; + json.allOf = [...isSimpleIntersection(a) ? a.allOf : [a], ...isSimpleIntersection(b) ? b.allOf : [b]]; + }; + const recordProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + const keyType = def.keyType; + const patterns = keyType._zod.bag?.patterns; + if (def.mode === "loose" && patterns && patterns.size > 0) { + const valueSchema = process(def.valueType, ctx, { + ...params, + path: [ + ...params.path, + "patternProperties", + "*" + ] + }); + json.patternProperties = {}; + for (const pattern of patterns) json.patternProperties[pattern.source] = valueSchema; + } else { + if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") json.propertyNames = process(def.keyType, ctx, { + ...params, + path: [...params.path, "propertyNames"] + }); + json.additionalProperties = process(def.valueType, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + } + const keyValues = keyType._zod.values; + if (keyValues) { + const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number"); + if (validKeyValues.length > 0) json.required = validKeyValues; + } + }; + const nullableProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const inner = process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + if (ctx.target === "openapi-3.0") { + seen.ref = def.innerType; + json.nullable = true; + } else json.anyOf = [inner, { type: "null" }]; + }; + const nonoptionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const defaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.default = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const prefaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + if (ctx.io === "input") json._prefault = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const catchProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + let catchValue; + try { + catchValue = def.catchValue(void 0); + } catch { + throw new Error("Dynamic catch values are not supported in JSON Schema"); + } + json.default = catchValue; + }; + const pipeProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + const inIsTransform = def.in._zod.traits.has("$ZodTransform"); + const innerType = ctx.io === "input" ? inIsTransform ? def.out : def.in : def.out; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + const readonlyProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.readOnly = true; + }; + const optionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const lazyProcessor = (schema, ctx, _json, params) => { + const innerType = schema._zod.innerType; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/iso.js + const ZodISODateTime = /*@__PURE__*/ $constructor("ZodISODateTime", (inst, def) => { + $ZodISODateTime.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function datetime(params) { + return /* @__PURE__ */ _isoDateTime(ZodISODateTime, params); + } + const ZodISODate = /*@__PURE__*/ $constructor("ZodISODate", (inst, def) => { + $ZodISODate.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function date(params) { + return /* @__PURE__ */ _isoDate(ZodISODate, params); + } + const ZodISOTime = /*@__PURE__*/ $constructor("ZodISOTime", (inst, def) => { + $ZodISOTime.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function time(params) { + return /* @__PURE__ */ _isoTime(ZodISOTime, params); + } + const ZodISODuration = /*@__PURE__*/ $constructor("ZodISODuration", (inst, def) => { + $ZodISODuration.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function duration(params) { + return /* @__PURE__ */ _isoDuration(ZodISODuration, params); + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/errors.js + const initializer = (inst, issues) => { + $ZodError.init(inst, issues); + inst.name = "ZodError"; + Object.defineProperties(inst, { + format: { value: (mapper) => formatError(inst, mapper) }, + flatten: { value: (mapper) => flattenError(inst, mapper) }, + addIssue: { value: (issue) => { + inst.issues.push(issue); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } }, + addIssues: { value: (issues) => { + inst.issues.push(...issues); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } }, + isEmpty: { get() { + return inst.issues.length === 0; + } } + }); + }; + const ZodRealError = /*@__PURE__*/ $constructor("ZodError", initializer, { Parent: Error }); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/parse.js + const parse = /* @__PURE__ */ _parse(ZodRealError); + const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError); + const safeParse = /* @__PURE__ */ _safeParse(ZodRealError); + const safeParseAsync = /* @__PURE__ */ _safeParseAsync(ZodRealError); + const encode = /* @__PURE__ */ _encode(ZodRealError); + const decode = /* @__PURE__ */ _decode(ZodRealError); + const encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError); + const decodeAsync = /* @__PURE__ */ _decodeAsync(ZodRealError); + const safeEncode = /* @__PURE__ */ _safeEncode(ZodRealError); + const safeDecode = /* @__PURE__ */ _safeDecode(ZodRealError); + const safeEncodeAsync = /* @__PURE__ */ _safeEncodeAsync(ZodRealError); + const safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync(ZodRealError); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js + const _installedGroups = /* @__PURE__ */ new WeakMap(); + function _installLazyMethods(inst, group, methods) { + const proto = Object.getPrototypeOf(inst); + let installed = _installedGroups.get(proto); + if (!installed) { + installed = /* @__PURE__ */ new Set(); + _installedGroups.set(proto, installed); + } + if (installed.has(group)) return; + installed.add(group); + for (const key in methods) { + const fn = methods[key]; + Object.defineProperty(proto, key, { + configurable: true, + enumerable: false, + get() { + const bound = fn.bind(this); + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: bound + }); + return bound; + }, + set(v) { + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: v + }); + } + }); + } + } + const ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => { + $ZodType.init(inst, def); + Object.assign(inst["~standard"], { jsonSchema: { + input: createStandardJSONSchemaMethod(inst, "input"), + output: createStandardJSONSchemaMethod(inst, "output") + } }); + inst.toJSONSchema = createToJSONSchemaMethod(inst, {}); + inst.def = def; + inst.type = def.type; + Object.defineProperty(inst, "_def", { value: def }); + inst.parse = (data, params) => parse(inst, data, params, { callee: inst.parse }); + inst.safeParse = (data, params) => safeParse(inst, data, params); + inst.parseAsync = async (data, params) => parseAsync(inst, data, params, { callee: inst.parseAsync }); + inst.safeParseAsync = async (data, params) => safeParseAsync(inst, data, params); + inst.spa = inst.safeParseAsync; + inst.encode = (data, params) => encode(inst, data, params); + inst.decode = (data, params) => decode(inst, data, params); + inst.encodeAsync = async (data, params) => encodeAsync(inst, data, params); + inst.decodeAsync = async (data, params) => decodeAsync(inst, data, params); + inst.safeEncode = (data, params) => safeEncode(inst, data, params); + inst.safeDecode = (data, params) => safeDecode(inst, data, params); + inst.safeEncodeAsync = async (data, params) => safeEncodeAsync(inst, data, params); + inst.safeDecodeAsync = async (data, params) => safeDecodeAsync(inst, data, params); + _installLazyMethods(inst, "ZodType", { + check(...chks) { + const def = this.def; + return this.clone(mergeDefs(def, { checks: [...def.checks ?? [], ...chks.map((ch) => typeof ch === "function" ? { _zod: { + check: ch, + def: { check: "custom" }, + onattach: [] + } } : ch)] }), { parent: true }); + }, + with(...chks) { + return this.check(...chks); + }, + clone(def, params) { + return clone(this, def, params); + }, + brand() { + return this; + }, + register(reg, meta) { + reg.add(this, meta); + return this; + }, + refine(check, params) { + return this.check(refine(check, params)); + }, + superRefine(refinement, params) { + return this.check(superRefine(refinement, params)); + }, + overwrite(fn) { + return this.check(/* @__PURE__ */ _overwrite(fn)); + }, + optional() { + return optional(this); + }, + exactOptional() { + return exactOptional(this); + }, + nullable() { + return nullable(this); + }, + nullish() { + return optional(nullable(this)); + }, + nonoptional(params) { + return nonoptional(this, params); + }, + array() { + return array(this); + }, + or(arg) { + return union([this, arg]); + }, + and(arg) { + return intersection(this, arg); + }, + transform(tx) { + return pipe(this, transform(tx)); + }, + default(d) { + return _default(this, d); + }, + prefault(d) { + return prefault(this, d); + }, + catch(params) { + return _catch(this, params); + }, + pipe(target) { + return pipe(this, target); + }, + readonly() { + return readonly(this); + }, + describe(description) { + const cl = this.clone(); + globalRegistry.add(cl, { description }); + return cl; + }, + meta(...args) { + if (args.length === 0) return globalRegistry.get(this); + const cl = this.clone(); + globalRegistry.add(cl, args[0]); + return cl; + }, + isOptional() { + return this.safeParse(void 0).success; + }, + isNullable() { + return this.safeParse(null).success; + }, + apply(fn) { + return fn(this); + } + }); + Object.defineProperty(inst, "description", { + get() { + return globalRegistry.get(inst)?.description; + }, + configurable: true + }); + return inst; + }); + /** @internal */ + const _ZodString = /*@__PURE__*/ $constructor("_ZodString", (inst, def) => { + $ZodString.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => stringProcessor(inst, ctx, json, params); + const bag = inst._zod.bag; + inst.format = bag.format ?? null; + inst.minLength = bag.minimum ?? null; + inst.maxLength = bag.maximum ?? null; + _installLazyMethods(inst, "_ZodString", { + regex(...args) { + return this.check(/* @__PURE__ */ _regex(...args)); + }, + includes(...args) { + return this.check(/* @__PURE__ */ _includes(...args)); + }, + startsWith(...args) { + return this.check(/* @__PURE__ */ _startsWith(...args)); + }, + endsWith(...args) { + return this.check(/* @__PURE__ */ _endsWith(...args)); + }, + min(...args) { + return this.check(/* @__PURE__ */ _minLength(...args)); + }, + max(...args) { + return this.check(/* @__PURE__ */ _maxLength(...args)); + }, + length(...args) { + return this.check(/* @__PURE__ */ _length(...args)); + }, + nonempty(...args) { + return this.check(/* @__PURE__ */ _minLength(1, ...args)); + }, + lowercase(params) { + return this.check(/* @__PURE__ */ _lowercase(params)); + }, + uppercase(params) { + return this.check(/* @__PURE__ */ _uppercase(params)); + }, + trim() { + return this.check(/* @__PURE__ */ _trim()); + }, + normalize(...args) { + return this.check(/* @__PURE__ */ _normalize(...args)); + }, + toLowerCase() { + return this.check(/* @__PURE__ */ _toLowerCase()); + }, + toUpperCase() { + return this.check(/* @__PURE__ */ _toUpperCase()); + }, + slugify() { + return this.check(/* @__PURE__ */ _slugify()); + } + }); + }); + const ZodString = /*@__PURE__*/ $constructor("ZodString", (inst, def) => { + $ZodString.init(inst, def); + _ZodString.init(inst, def); + inst.email = (params) => inst.check(/* @__PURE__ */ _email(ZodEmail, params)); + inst.url = (params) => inst.check(/* @__PURE__ */ _url(ZodURL, params)); + inst.jwt = (params) => inst.check(/* @__PURE__ */ _jwt(ZodJWT, params)); + inst.emoji = (params) => inst.check(/* @__PURE__ */ _emoji(ZodEmoji, params)); + inst.guid = (params) => inst.check(/* @__PURE__ */ _guid(ZodGUID, params)); + inst.uuid = (params) => inst.check(/* @__PURE__ */ _uuid(ZodUUID, params)); + inst.uuidv4 = (params) => inst.check(/* @__PURE__ */ _uuidv4(ZodUUID, params)); + inst.uuidv6 = (params) => inst.check(/* @__PURE__ */ _uuidv6(ZodUUID, params)); + inst.uuidv7 = (params) => inst.check(/* @__PURE__ */ _uuidv7(ZodUUID, params)); + inst.nanoid = (params) => inst.check(/* @__PURE__ */ _nanoid(ZodNanoID, params)); + inst.guid = (params) => inst.check(/* @__PURE__ */ _guid(ZodGUID, params)); + inst.cuid = (params) => inst.check(/* @__PURE__ */ _cuid(ZodCUID, params)); + inst.cuid2 = (params) => inst.check(/* @__PURE__ */ _cuid2(ZodCUID2, params)); + inst.ulid = (params) => inst.check(/* @__PURE__ */ _ulid(ZodULID, params)); + inst.base64 = (params) => inst.check(/* @__PURE__ */ _base64(ZodBase64, params)); + inst.base64url = (params) => inst.check(/* @__PURE__ */ _base64url(ZodBase64URL, params)); + inst.xid = (params) => inst.check(/* @__PURE__ */ _xid(ZodXID, params)); + inst.ksuid = (params) => inst.check(/* @__PURE__ */ _ksuid(ZodKSUID, params)); + inst.ipv4 = (params) => inst.check(/* @__PURE__ */ _ipv4(ZodIPv4, params)); + inst.ipv6 = (params) => inst.check(/* @__PURE__ */ _ipv6(ZodIPv6, params)); + inst.cidrv4 = (params) => inst.check(/* @__PURE__ */ _cidrv4(ZodCIDRv4, params)); + inst.cidrv6 = (params) => inst.check(/* @__PURE__ */ _cidrv6(ZodCIDRv6, params)); + inst.e164 = (params) => inst.check(/* @__PURE__ */ _e164(ZodE164, params)); + inst.datetime = (params) => inst.check(datetime(params)); + inst.date = (params) => inst.check(date(params)); + inst.time = (params) => inst.check(time(params)); + inst.duration = (params) => inst.check(duration(params)); + }); + function string(params) { + return /* @__PURE__ */ _string(ZodString, params); + } + const ZodStringFormat = /*@__PURE__*/ $constructor("ZodStringFormat", (inst, def) => { + $ZodStringFormat.init(inst, def); + _ZodString.init(inst, def); + }); + const ZodEmail = /*@__PURE__*/ $constructor("ZodEmail", (inst, def) => { + $ZodEmail.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodGUID = /*@__PURE__*/ $constructor("ZodGUID", (inst, def) => { + $ZodGUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodUUID = /*@__PURE__*/ $constructor("ZodUUID", (inst, def) => { + $ZodUUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodURL = /*@__PURE__*/ $constructor("ZodURL", (inst, def) => { + $ZodURL.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodEmoji = /*@__PURE__*/ $constructor("ZodEmoji", (inst, def) => { + $ZodEmoji.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodNanoID = /*@__PURE__*/ $constructor("ZodNanoID", (inst, def) => { + $ZodNanoID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link ZodCUID2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const ZodCUID = /*@__PURE__*/ $constructor("ZodCUID", (inst, def) => { + $ZodCUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCUID2 = /*@__PURE__*/ $constructor("ZodCUID2", (inst, def) => { + $ZodCUID2.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodULID = /*@__PURE__*/ $constructor("ZodULID", (inst, def) => { + $ZodULID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodXID = /*@__PURE__*/ $constructor("ZodXID", (inst, def) => { + $ZodXID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodKSUID = /*@__PURE__*/ $constructor("ZodKSUID", (inst, def) => { + $ZodKSUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodIPv4 = /*@__PURE__*/ $constructor("ZodIPv4", (inst, def) => { + $ZodIPv4.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodIPv6 = /*@__PURE__*/ $constructor("ZodIPv6", (inst, def) => { + $ZodIPv6.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCIDRv4 = /*@__PURE__*/ $constructor("ZodCIDRv4", (inst, def) => { + $ZodCIDRv4.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCIDRv6 = /*@__PURE__*/ $constructor("ZodCIDRv6", (inst, def) => { + $ZodCIDRv6.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodBase64 = /*@__PURE__*/ $constructor("ZodBase64", (inst, def) => { + $ZodBase64.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodBase64URL = /*@__PURE__*/ $constructor("ZodBase64URL", (inst, def) => { + $ZodBase64URL.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodE164 = /*@__PURE__*/ $constructor("ZodE164", (inst, def) => { + $ZodE164.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodJWT = /*@__PURE__*/ $constructor("ZodJWT", (inst, def) => { + $ZodJWT.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodNumber = /*@__PURE__*/ $constructor("ZodNumber", (inst, def) => { + $ZodNumber.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => numberProcessor(inst, ctx, json, params); + _installLazyMethods(inst, "ZodNumber", { + gt(value, params) { + return this.check(/* @__PURE__ */ _gt(value, params)); + }, + gte(value, params) { + return this.check(/* @__PURE__ */ _gte(value, params)); + }, + min(value, params) { + return this.check(/* @__PURE__ */ _gte(value, params)); + }, + lt(value, params) { + return this.check(/* @__PURE__ */ _lt(value, params)); + }, + lte(value, params) { + return this.check(/* @__PURE__ */ _lte(value, params)); + }, + max(value, params) { + return this.check(/* @__PURE__ */ _lte(value, params)); + }, + int(params) { + return this.check(int(params)); + }, + safe(params) { + return this.check(int(params)); + }, + positive(params) { + return this.check(/* @__PURE__ */ _gt(0, params)); + }, + nonnegative(params) { + return this.check(/* @__PURE__ */ _gte(0, params)); + }, + negative(params) { + return this.check(/* @__PURE__ */ _lt(0, params)); + }, + nonpositive(params) { + return this.check(/* @__PURE__ */ _lte(0, params)); + }, + multipleOf(value, params) { + return this.check(/* @__PURE__ */ _multipleOf(value, params)); + }, + step(value, params) { + return this.check(/* @__PURE__ */ _multipleOf(value, params)); + }, + finite() { + return this; + } + }); + const bag = inst._zod.bag; + inst.minValue = Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null; + inst.maxValue = Math.min(bag.maximum ?? Number.POSITIVE_INFINITY, bag.exclusiveMaximum ?? Number.POSITIVE_INFINITY) ?? null; + inst.isInt = (bag.format ?? "").includes("int") || Number.isSafeInteger(bag.multipleOf ?? .5); + inst.isFinite = true; + inst.format = bag.format ?? null; + }); + function number(params) { + return /* @__PURE__ */ _number(ZodNumber, params); + } + const ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def) => { + $ZodNumberFormat.init(inst, def); + ZodNumber.init(inst, def); + }); + function int(params) { + return /* @__PURE__ */ _int(ZodNumberFormat, params); + } + const ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => { + $ZodBoolean.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params); + }); + function boolean(params) { + return /* @__PURE__ */ _boolean(ZodBoolean, params); + } + const ZodUndefined = /*@__PURE__*/ $constructor("ZodUndefined", (inst, def) => { + $ZodUndefined.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => undefinedProcessor(inst, ctx, json, params); + }); + function _undefined(params) { + return /* @__PURE__ */ _undefined$1(ZodUndefined, params); + } + const ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => { + $ZodUnknown.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => void 0; + }); + function unknown() { + return /* @__PURE__ */ _unknown(ZodUnknown); + } + const ZodNever = /*@__PURE__*/ $constructor("ZodNever", (inst, def) => { + $ZodNever.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => neverProcessor(inst, ctx, json, params); + }); + function never(params) { + return /* @__PURE__ */ _never(ZodNever, params); + } + const ZodArray = /*@__PURE__*/ $constructor("ZodArray", (inst, def) => { + $ZodArray.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => arrayProcessor(inst, ctx, json, params); + inst.element = def.element; + _installLazyMethods(inst, "ZodArray", { + min(n, params) { + return this.check(/* @__PURE__ */ _minLength(n, params)); + }, + nonempty(params) { + return this.check(/* @__PURE__ */ _minLength(1, params)); + }, + max(n, params) { + return this.check(/* @__PURE__ */ _maxLength(n, params)); + }, + length(n, params) { + return this.check(/* @__PURE__ */ _length(n, params)); + }, + unwrap() { + return this.element; + } + }); + }); + function array(element, params) { + return /* @__PURE__ */ _array(ZodArray, element, params); + } + const ZodObject = /*@__PURE__*/ $constructor("ZodObject", (inst, def) => { + $ZodObjectJIT.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => objectProcessor(inst, ctx, json, params); + defineLazy(inst, "shape", () => { + return def.shape; + }); + _installLazyMethods(inst, "ZodObject", { + keyof() { + return _enum(Object.keys(this._zod.def.shape)); + }, + catchall(catchall) { + return this.clone({ + ...this._zod.def, + catchall + }); + }, + passthrough() { + return this.clone({ + ...this._zod.def, + catchall: unknown() + }); + }, + loose() { + return this.clone({ + ...this._zod.def, + catchall: unknown() + }); + }, + strict() { + return this.clone({ + ...this._zod.def, + catchall: never() + }); + }, + strip() { + return this.clone({ + ...this._zod.def, + catchall: void 0 + }); + }, + extend(incoming) { + return extend(this, incoming); + }, + safeExtend(incoming) { + return safeExtend(this, incoming); + }, + merge(other) { + return merge(this, other); + }, + pick(mask) { + return pick(this, mask); + }, + omit(mask) { + return omit(this, mask); + }, + partial(...args) { + return partial(ZodOptional, this, args[0]); + }, + required(...args) { + return required(ZodNonOptional, this, args[0]); + } + }); + }); + function object(shape, params) { + return new ZodObject({ + type: "object", + shape: shape ?? {}, + ...normalizeParams(params) + }); + } + const ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => { + $ZodUnion.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => unionProcessor(inst, ctx, json, params); + inst.options = def.options; + }); + function union(options, params) { + return new ZodUnion({ + type: "union", + options, + ...normalizeParams(params) + }); + } + const ZodIntersection = /*@__PURE__*/ $constructor("ZodIntersection", (inst, def) => { + $ZodIntersection.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => intersectionProcessor(inst, ctx, json, params); + }); + function intersection(left, right) { + return new ZodIntersection({ + type: "intersection", + left, + right + }); + } + const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => { + $ZodRecord.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params); + inst.keyType = def.keyType; + inst.valueType = def.valueType; + }); + function record(keyType, valueType, params) { + if (!valueType || !valueType._zod) return new ZodRecord({ + type: "record", + keyType: string(), + valueType: keyType, + ...normalizeParams(valueType) + }); + return new ZodRecord({ + type: "record", + keyType, + valueType, + ...normalizeParams(params) + }); + } + const ZodEnum = /*@__PURE__*/ $constructor("ZodEnum", (inst, def) => { + $ZodEnum.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => enumProcessor(inst, ctx, json, params); + inst.enum = def.entries; + inst.options = Object.values(def.entries); + const keys = new Set(Object.keys(def.entries)); + inst.extract = (values, params) => { + const newEntries = {}; + for (const value of values) if (keys.has(value)) newEntries[value] = def.entries[value]; + else throw new Error(`Key ${value} not found in enum`); + return new ZodEnum({ + ...def, + checks: [], + ...normalizeParams(params), + entries: newEntries + }); + }; + inst.exclude = (values, params) => { + const newEntries = { ...def.entries }; + for (const value of values) if (keys.has(value)) delete newEntries[value]; + else throw new Error(`Key ${value} not found in enum`); + return new ZodEnum({ + ...def, + checks: [], + ...normalizeParams(params), + entries: newEntries + }); + }; + }); + function _enum(values, params) { + return new ZodEnum({ + type: "enum", + entries: Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values, + ...normalizeParams(params) + }); + } + const ZodLiteral = /*@__PURE__*/ $constructor("ZodLiteral", (inst, def) => { + $ZodLiteral.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => literalProcessor(inst, ctx, json, params); + inst.values = new Set(def.values); + Object.defineProperty(inst, "value", { get() { + if (def.values.length > 1) throw new Error("This schema contains multiple valid literal values. Use `.values` instead."); + return def.values[0]; + } }); + }); + function literal(value, params) { + return new ZodLiteral({ + type: "literal", + values: Array.isArray(value) ? value : [value], + ...normalizeParams(params) + }); + } + const ZodTransform = /*@__PURE__*/ $constructor("ZodTransform", (inst, def) => { + $ZodTransform.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => transformProcessor(inst, ctx, json, params); + inst._zod.parse = (payload, _ctx) => { + if (_ctx.direction === "backward") throw new $ZodEncodeError(inst.constructor.name); + payload.addIssue = (issue$1) => { + if (typeof issue$1 === "string") payload.issues.push(issue(issue$1, payload.value, def)); + else { + const _issue = issue$1; + if (_issue.fatal) _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = inst); + payload.issues.push(issue(_issue)); + } + }; + const output = def.transform(payload.value, payload); + if (output instanceof Promise) return output.then((output) => { + payload.value = output; + payload.fallback = true; + return payload; + }); + payload.value = output; + payload.fallback = true; + return payload; + }; + }); + function transform(fn) { + return new ZodTransform({ + type: "transform", + transform: fn + }); + } + const ZodOptional = /*@__PURE__*/ $constructor("ZodOptional", (inst, def) => { + $ZodOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function optional(innerType) { + return new ZodOptional({ + type: "optional", + innerType + }); + } + const ZodExactOptional = /*@__PURE__*/ $constructor("ZodExactOptional", (inst, def) => { + $ZodExactOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function exactOptional(innerType) { + return new ZodExactOptional({ + type: "optional", + innerType + }); + } + const ZodNullable = /*@__PURE__*/ $constructor("ZodNullable", (inst, def) => { + $ZodNullable.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nullableProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function nullable(innerType) { + return new ZodNullable({ + type: "nullable", + innerType + }); + } + const ZodDefault = /*@__PURE__*/ $constructor("ZodDefault", (inst, def) => { + $ZodDefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => defaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeDefault = inst.unwrap; + }); + function _default(innerType, defaultValue) { + return new ZodDefault({ + type: "default", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); + } + }); + } + const ZodPrefault = /*@__PURE__*/ $constructor("ZodPrefault", (inst, def) => { + $ZodPrefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => prefaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function prefault(innerType, defaultValue) { + return new ZodPrefault({ + type: "prefault", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); + } + }); + } + const ZodNonOptional = /*@__PURE__*/ $constructor("ZodNonOptional", (inst, def) => { + $ZodNonOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nonoptionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function nonoptional(innerType, params) { + return new ZodNonOptional({ + type: "nonoptional", + innerType, + ...normalizeParams(params) + }); + } + const ZodCatch = /*@__PURE__*/ $constructor("ZodCatch", (inst, def) => { + $ZodCatch.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => catchProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeCatch = inst.unwrap; + }); + function _catch(innerType, catchValue) { + return new ZodCatch({ + type: "catch", + innerType, + catchValue: typeof catchValue === "function" ? catchValue : () => catchValue + }); + } + const ZodPipe = /*@__PURE__*/ $constructor("ZodPipe", (inst, def) => { + $ZodPipe.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => pipeProcessor(inst, ctx, json, params); + inst.in = def.in; + inst.out = def.out; + }); + function pipe(in_, out) { + return new ZodPipe({ + type: "pipe", + in: in_, + out + }); + } + const ZodReadonly = /*@__PURE__*/ $constructor("ZodReadonly", (inst, def) => { + $ZodReadonly.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => readonlyProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function readonly(innerType) { + return new ZodReadonly({ + type: "readonly", + innerType + }); + } + const ZodLazy = /*@__PURE__*/ $constructor("ZodLazy", (inst, def) => { + $ZodLazy.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => lazyProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.getter(); + }); + function lazy(getter) { + return new ZodLazy({ + type: "lazy", + getter + }); + } + const ZodCustom = /*@__PURE__*/ $constructor("ZodCustom", (inst, def) => { + $ZodCustom.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => customProcessor(inst, ctx, json, params); + }); + function refine(fn, _params = {}) { + return /* @__PURE__ */ _refine(ZodCustom, fn, _params); + } + function superRefine(fn, params) { + return /* @__PURE__ */ _superRefine(fn, params); + } + //#endregion + //#region ../../interaction/commands/lib/typert.remote-client.js + const _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema = string(); + const _deepseek_ai_dsh_commands_commands_execute_result$schema = union([_undefined(), object({ + "commandId": intersection(string(), unknown()).readonly(), + "result": union([object({ + "kind": literal("success").readonly(), + "text": string().readonly().optional(), + "sourceEventSeq": number().readonly().optional() + }), object({ + "kind": literal("error").readonly(), + "text": string().readonly() + })]).readonly() + })]); + const _deepseek_ai_dsh_commands_commands_list_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_commands_commands_list_result$schema = array(object({ + "name": string().readonly(), + "description": string().readonly(), + "input": object({ "hint": string().readonly() }).readonly().optional() + })); + const TYPERT_REMOTE$4 = { + package: "@deepseek-ai/dsh-commands", + descriptors: [{ + id: "@deepseek-ai/dsh-commands#commands/execute", + service: "commands", + namespace: "commands", + method: "execute", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema + } + }, { + name: "line", + wire: "line", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-commands#commands/execute:line", + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema + } + }], + cancellation: { parameter: "signal" }, + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-commands#commands/execute:result", + schema: _deepseek_ai_dsh_commands_commands_execute_result$schema + }, + sourceLocation: { + "file": "packages/interaction/commands/src/index.ts", + "line": 297, + "column": 9 + } + }, { + id: "@deepseek-ai/dsh-commands#commands/list", + service: "commands", + namespace: "commands", + method: "list", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_commands_commands_list_parameter_0$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-commands#commands/list:result", + schema: _deepseek_ai_dsh_commands_commands_list_result$schema + }, + sourceLocation: { + "file": "packages/interaction/commands/src/index.ts", + "line": 260, + "column": 3 + } + }] + }; + //#endregion + //#region ../../goal/goal/lib/typert.remote-client.js + const _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_clear_result$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_complete_result$schema = object({ + "roundsStarted": number().readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly(), + "activation": union([literal("armed"), literal("disarmed")]).readonly(), + "objective": string().readonly(), + "phase": union([ + literal("active"), + literal("paused"), + literal("blocked"), + literal("complete") + ]).readonly(), + "blockedReason": object({ + "code": string().readonly(), + "message": string().readonly() + }).readonly().optional(), + "maxGoalRounds": number().readonly(), + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_create_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_create_parameter_1$schema = object({ + "objective": string().readonly(), + "maxGoalRounds": number().readonly().optional() + }); + const _deepseek_ai_dsh_goal_goals_create_result$schema = object({ "ref": object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }).readonly() }); + const _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema = object({ + "objective": string().readonly().optional(), + "maxGoalRounds": number().readonly().optional() + }); + const _deepseek_ai_dsh_goal_goals_edit_result$schema = object({ + "roundsStarted": number().readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly(), + "activation": union([literal("armed"), literal("disarmed")]).readonly(), + "objective": string().readonly(), + "phase": union([ + literal("active"), + literal("paused"), + literal("blocked"), + literal("complete") + ]).readonly(), + "blockedReason": object({ + "code": string().readonly(), + "message": string().readonly() + }).readonly().optional(), + "maxGoalRounds": number().readonly(), + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_pause_result$schema = object({ + "roundsStarted": number().readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly(), + "activation": union([literal("armed"), literal("disarmed")]).readonly(), + "objective": string().readonly(), + "phase": union([ + literal("active"), + literal("paused"), + literal("blocked"), + literal("complete") + ]).readonly(), + "blockedReason": object({ + "code": string().readonly(), + "message": string().readonly() + }).readonly().optional(), + "maxGoalRounds": number().readonly(), + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_resume_result$schema = object({ + "roundsStarted": number().readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly(), + "activation": union([literal("armed"), literal("disarmed")]).readonly(), + "objective": string().readonly(), + "phase": union([ + literal("active"), + literal("paused"), + literal("blocked"), + literal("complete") + ]).readonly(), + "blockedReason": object({ + "code": string().readonly(), + "message": string().readonly() + }).readonly().optional(), + "maxGoalRounds": number().readonly(), + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const TYPERT_REMOTE$3 = { + package: "@deepseek-ai/dsh-goal", + descriptors: [ + { + id: "@deepseek-ai/dsh-goal#goals/clear", + service: "goals", + namespace: "goals", + method: "clear", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema + } + }, { + name: "ref", + wire: "ref", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_clear_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 377, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-goal#goals/complete", + service: "goals", + namespace: "goals", + method: "complete", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema + } + }, { + name: "ref", + wire: "ref", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalView", + schema: _deepseek_ai_dsh_goal_goals_complete_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 337, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-goal#goals/create", + service: "goals", + namespace: "goals", + method: "create", + implementation: "remoteExportCreate", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_create_parameter_0$schema + } + }, { + name: "request", + wire: "request", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#CreateGoalRequest", + schema: _deepseek_ai_dsh_goal_goals_create_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#CreateGoalResult", + schema: _deepseek_ai_dsh_goal_goals_create_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 586, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-goal#goals/edit", + service: "goals", + namespace: "goals", + method: "edit", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema + } + }, + { + name: "ref", + wire: "ref", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema + } + }, + { + name: "request", + wire: "request", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#EditGoalRequest", + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalView", + schema: _deepseek_ai_dsh_goal_goals_edit_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 277, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-goal#goals/pause", + service: "goals", + namespace: "goals", + method: "pause", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema + } + }, { + name: "ref", + wire: "ref", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalView", + schema: _deepseek_ai_dsh_goal_goals_pause_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 299, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-goal#goals/resume", + service: "goals", + namespace: "goals", + method: "resume", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema + } + }, { + name: "ref", + wire: "ref", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalView", + schema: _deepseek_ai_dsh_goal_goals_resume_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 311, + "column": 3 + } + } + ] + }; + //#endregion + //#region ../../extensions/cordis-host-runner/lib/typert.remote-client.js + const JsonValueRemoteCodec$schema = union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema)), + record(string(), lazy(() => JsonValueRemoteCodec$schema)) + ]); + const JsonValueRemoteCodec$schema2 = union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema2)), + record(string(), lazy(() => JsonValueRemoteCodec$schema2)) + ]); + const JsonValueRemoteCodec$schema3 = union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema3)), + record(string(), lazy(() => JsonValueRemoteCodec$schema3)) + ]); + const JsonValueRemoteCodec$schema4 = union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema4)), + record(string(), lazy(() => JsonValueRemoteCodec$schema4)) + ]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema = object({ + "code": string(), + "name": string(), + "pluginId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()), + "pluginRunId": intersection(string(), unknown()) + }); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema = array(object({ + "pluginId": intersection(string(), unknown()), + "agentId": intersection(string(), unknown()), + "packages": array(object({ + "packageId": intersection(string(), unknown()), + "name": string(), + "purpose": string(), + "hasHostHalf": boolean(), + "hasClientHalf": boolean() + })), + "currentPackageId": intersection(string(), unknown()).optional(), + "nextPackageId": intersection(string(), unknown()).optional(), + "activeRun": object({ + "pluginRunId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()) + }).optional(), + "latestRun": object({ + "pluginRunId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()), + "mode": union([literal("run"), literal("update")]), + "status": union([ + literal("rejected"), + literal("awaiting-approval"), + literal("running"), + literal("cancelled"), + literal("starting-host"), + literal("client-pending"), + literal("waiting"), + literal("failed"), + literal("stopped") + ]), + "approvalRequestId": intersection(string(), unknown()).optional(), + "requiresApproval": boolean().optional(), + "host": object({ + "status": union([ + literal("running"), + literal("waiting"), + literal("failed"), + literal("stopped"), + literal("absent"), + literal("pending") + ]), + "waitingFor": array(string()), + "error": string().optional() + }), + "client": object({ + "status": union([ + literal("running"), + literal("waiting"), + literal("failed"), + literal("stopped"), + literal("absent"), + literal("pending") + ]), + "waitingFor": array(string()), + "error": string().optional() + }), + "error": object({ + "phase": union([ + literal("approval"), + literal("host-load"), + literal("host-apply"), + literal("client-load"), + literal("client-apply"), + literal("client-render") + ]), + "message": string(), + "stack": string().optional(), + "pluginId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()), + "pluginRunId": intersection(string(), unknown()) + }).optional() + }).optional() + })); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema = string(); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema = union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema3)), + record(string(), lazy(() => JsonValueRemoteCodec$schema3)) + ]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema = union([object({ + "ok": literal(true), + "value": union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema4)), + record(string(), lazy(() => JsonValueRemoteCodec$schema4)) + ]) + }), intersection(object({ + "ok": literal(false), + "code": union([ + literal("plugin-not-running"), + literal("stale-run"), + literal("method-not-found"), + literal("handler-error") + ]) + }), object({ + "message": string(), + "stack": string().optional() + }))]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema = object({ + "message": string(), + "stack": string().optional() + }); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema = literal(null); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema = object({ + "slot": string(), + "message": string(), + "stack": string().optional(), + "abdicated": boolean() + }); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema = literal(null); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema = union([object({ + "ok": literal(true), + "data": union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema2)), + record(string(), lazy(() => JsonValueRemoteCodec$schema2)) + ]) + }), object({ + "ok": literal(false), + "reason": union([ + literal("cancelled"), + literal("provider-missing"), + literal("method-missing"), + literal("invalid-input"), + literal("provider-error") + ]), + "message": string() + })]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema = object({ "accepted": boolean() }); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema = union([object({ + "ok": literal(true), + "pluginRunId": intersection(string(), unknown()), + "waitingFor": array(string()).optional() + }), object({ + "ok": literal(false), + "reason": union([ + literal("rejected"), + literal("host-half-failed"), + literal("client-half-failed") + ]), + "pluginRunId": intersection(string(), unknown()).optional(), + "startedHere": boolean().optional(), + "message": string().optional(), + "stack": string().optional() + })]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema = object({ "accepted": boolean() }); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema = union([literal("run"), literal("update")]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema = union([literal(null), intersection(string(), unknown())]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema = boolean(); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema = union([object({ + "ok": literal(true), + "pluginId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()), + "pluginRunId": intersection(string(), unknown()), + "waitingFor": array(string()), + "startedHere": boolean() + }), intersection(object({ "ok": literal(false) }), object({ + "message": string(), + "stack": string().optional() + }))]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema = union([object({ + "ok": literal(true), + "pluginRunId": intersection(string(), unknown()), + "waitingFor": array(string()).optional() + }), object({ + "ok": literal(false), + "reason": union([ + literal("rejected"), + literal("host-half-failed"), + literal("client-half-failed") + ]), + "pluginRunId": intersection(string(), unknown()).optional(), + "startedHere": boolean().optional(), + "message": string().optional(), + "stack": string().optional() + })]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema = union([object({ + "ok": literal(true), + "status": union([ + literal("awaiting-approval"), + literal("starting"), + literal("running") + ]), + "pluginId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()), + "pluginRunId": intersection(string(), unknown()), + "waitingFor": array(string()), + "clientWaitingFor": array(string()).optional(), + "currentPackageId": intersection(string(), unknown()).optional(), + "nextPackageId": intersection(string(), unknown()).optional(), + "mode": union([literal("run"), literal("update")]) + }), object({ + "ok": literal(false), + "reason": union([ + literal("plugin-missing"), + literal("rejected"), + literal("host-half-failed"), + literal("client-half-failed"), + literal("package-missing"), + literal("invalid-mode"), + literal("transition-in-flight"), + literal("cancelled"), + literal("not-running") + ]), + "message": string(), + "stack": string().optional() + })]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema = union([object({ "ok": literal(true) }), object({ + "ok": literal(false), + "reason": union([literal("plugin-missing"), literal("not-running")]), + "message": string() + })]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema = array(object({ + "id": string(), + "description": string(), + "methods": array(object({ + "name": string(), + "description": string(), + "inputSchema": union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema)), + record(string(), lazy(() => JsonValueRemoteCodec$schema)) + ]), + "outputSchema": union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema)), + record(string(), lazy(() => JsonValueRemoteCodec$schema)) + ]) + })) + })); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema = literal(null); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema = union([object({ + "ok": literal(true), + "wasRunning": boolean() + }), object({ + "ok": literal(false), + "reason": literal("plugin-missing"), + "message": string() + })]); + const TYPERT_REMOTE$2 = { + package: "@deepseek-ai/dsh-cordis-host-runner", + descriptors: [ + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/getClientCode", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "getClientCode", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema + } + }, + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema + } + }, + { + name: "pluginRunId", + wire: "pluginRunId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisClientSource", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 384, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "inventory", + invocation: { kind: "direct" }, + parameters: [], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory:result", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 525, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "invoke", + invocation: { kind: "direct" }, + parameters: [ + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema + } + }, + { + name: "pluginRunId", + wire: "pluginRunId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema + } + }, + { + name: "method", + wire: "method", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke:method", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema + } + }, + { + name: "args", + wire: "args", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#JsonValue", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisInvokeResult", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 741, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "reportClientGuardFailure", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema + } + }, + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema + } + }, + { + name: "pluginRunId", + wire: "pluginRunId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema + } + }, + { + name: "failure", + wire: "failure", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisErrorDetails", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure:result", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 718, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "reportRenderFailure", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema + } + }, + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema + } + }, + { + name: "pluginRunId", + wire: "pluginRunId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema + } + }, + { + name: "failure", + wire: "failure", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRenderFailure", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure:result", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 684, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveInspectQuery", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "resolveInspectQuery", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema + } + }, + { + name: "requestId", + wire: "requestId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectRequestId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema + } + }, + { + name: "resolution", + wire: "resolution", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectQueryResolution", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectResolveAck", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 511, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveRequestRun", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "resolveRequestRun", + invocation: { kind: "direct" }, + parameters: [{ + name: "requestId", + wire: "requestId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#ApprovalRequestId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema + } + }, { + name: "resolution", + wire: "resolution", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisResolveAck", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 413, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "runHostHalf", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema + } + }, + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema + } + }, + { + name: "packageId", + wire: "packageId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPackageId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema + } + }, + { + name: "mode", + wire: "mode", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicRunMode", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema + } + }, + { + name: "requestId", + wire: "requestId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:requestId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema + } + }, + { + name: "approveFutureVersions", + wire: "approveFutureVersions", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:approveFutureVersions", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisHostHalfResult", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 325, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/settleUserRun", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "settleUserRun", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema + } + }, + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema + } + }, + { + name: "resolution", + wire: "resolution", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResponse", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 438, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/stopFromPanel", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "stopFromPanel", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema + } + }, { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisStopResponse", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 480, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "syncInspectManifest", + invocation: { kind: "direct" }, + parameters: [{ + name: "providers", + wire: "providers", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:providers", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:result", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 498, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/undefineFromPanel", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "undefineFromPanel", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema + } + }, { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisUndefineReceipt", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 227, + "column": 9 + } + } + ] + }; + const TYPERT_REMOTE$1 = { + package: "@deepseek-ai/dsh-host-plugin-inventory", + descriptors: [{ + id: "@deepseek-ai/dsh-host-plugin-inventory#pluginInventory/list", + service: "pluginInventory", + namespace: "pluginInventory", + method: "list", + invocation: { kind: "direct" }, + parameters: [], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-host-plugin-inventory/types#PluginInventorySnapshot", + schema: object({ "entries": array(object({ + "entryId": intersection(string(), unknown()).readonly(), + "moduleName": string().readonly(), + "enabled": boolean().readonly(), + "fiberPhase": union([ + literal(null), + literal("failed"), + literal("pending"), + literal("active"), + literal("loading"), + literal("unloading") + ]).readonly() + })).readonly() }) + }, + sourceLocation: { + "file": "packages/host/plugin-inventory/src/index.ts", + "line": 57, + "column": 3 + } + }] + }; + //#endregion + //#region ../../feedback/message-feedback/lib/typert.remote-client.js + const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema = object({ + "sessionId": intersection(string(), unknown()).readonly(), + "messageId": intersection(string(), unknown()).readonly(), + "ifVersion": intersection(string(), unknown()).readonly() + }); + const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema = union([object({ + "ok": literal(true).readonly(), + "value": object({ "absent": literal(true).readonly() }).readonly() + }), object({ + "ok": literal(false).readonly(), + "error": union([object({ + "code": literal("session-not-found").readonly(), + "sessionId": intersection(string(), unknown()).readonly() + }), object({ + "code": literal("version-conflict").readonly(), + "current": union([literal(null), object({ + "messageId": intersection(string(), unknown()).readonly(), + "rating": union([literal("positive"), literal("negative")]).readonly(), + "note": string().readonly().optional(), + "version": intersection(string(), unknown()).readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly() + })]).readonly() + })]).readonly() + })]); + const _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema = object({ "sessionId": intersection(string(), unknown()).readonly() }); + const _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema = union([object({ + "ok": literal(true).readonly(), + "value": object({ "items": array(object({ + "messageId": intersection(string(), unknown()).readonly(), + "rating": union([literal("positive"), literal("negative")]).readonly(), + "note": string().readonly().optional(), + "version": intersection(string(), unknown()).readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly() + })).readonly() }).readonly() + }), object({ + "ok": literal(false).readonly(), + "error": object({ + "code": literal("session-not-found").readonly(), + "sessionId": intersection(string(), unknown()).readonly() + }).readonly() + })]); + const _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema = object({ + "sessionId": intersection(string(), unknown()).readonly(), + "messageId": intersection(string(), unknown()).readonly(), + "rating": union([literal("positive"), literal("negative")]).readonly(), + "note": string().readonly().optional(), + "ifVersion": union([literal(null), intersection(string(), unknown())]).readonly() + }); + const _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema = union([object({ + "ok": literal(true).readonly(), + "value": object({ + "messageId": intersection(string(), unknown()).readonly(), + "rating": union([literal("positive"), literal("negative")]).readonly(), + "note": string().readonly().optional(), + "version": intersection(string(), unknown()).readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly() + }).readonly() + }), object({ + "ok": literal(false).readonly(), + "error": union([ + object({ + "code": literal("session-not-found").readonly(), + "sessionId": intersection(string(), unknown()).readonly() + }), + object({ + "code": literal("target-not-found").readonly(), + "sessionId": intersection(string(), unknown()).readonly(), + "messageId": intersection(string(), unknown()).readonly() + }), + object({ + "code": literal("version-conflict").readonly(), + "current": union([literal(null), object({ + "messageId": intersection(string(), unknown()).readonly(), + "rating": union([literal("positive"), literal("negative")]).readonly(), + "note": string().readonly().optional(), + "version": intersection(string(), unknown()).readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly() + })]).readonly() + }), + object({ "code": literal("note-blank").readonly() }), + object({ + "code": literal("note-too-large").readonly(), + "maxBytes": number().readonly(), + "actualBytes": number().readonly() + }) + ]).readonly() + })]); + const TYPERT_REMOTE = { + package: "@deepseek-ai/dsh-message-feedback", + descriptors: [ + { + id: "@deepseek-ai/dsh-message-feedback#messageFeedback/delete", + service: "messageFeedback", + namespace: "messageFeedback", + method: "delete", + invocation: { kind: "direct" }, + parameters: [{ + name: "request", + wire: "request", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteRequest", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteResult", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema + }, + sourceLocation: { + "file": "packages/feedback/message-feedback/src/index.ts", + "line": 272, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-message-feedback#messageFeedback/list", + service: "messageFeedback", + namespace: "messageFeedback", + method: "list", + invocation: { kind: "direct" }, + parameters: [{ + name: "request", + wire: "request", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListRequest", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListResult", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema + }, + sourceLocation: { + "file": "packages/feedback/message-feedback/src/index.ts", + "line": 190, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-message-feedback#messageFeedback/put", + service: "messageFeedback", + namespace: "messageFeedback", + method: "put", + invocation: { kind: "direct" }, + parameters: [{ + name: "request", + wire: "request", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutRequest", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutResult", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema + }, + sourceLocation: { + "file": "packages/feedback/message-feedback/src/index.ts", + "line": 206, + "column": 3 + } + } + ] + }; + //#endregion + //#region lib/types/client/index.js + /** Platform-neutral assembly of generated Host Remote contributions. */ + /** Required service: the typed Client Remote contribution mount. */ + const inject = ["remote"]; + /** + * Mount the Host capabilities explicitly selected for this Client assembly. + * @param ctx - Client Cordis root carrying the typed API service. + * @returns disposer after every selected Remote namespace is ready. + */ + async function apply(ctx) { + const disposers = []; + try { + for (const contribution of [ + TYPERT_REMOTE$4, + TYPERT_REMOTE$3, + TYPERT_REMOTE$2, + TYPERT_REMOTE$1, + TYPERT_REMOTE + ]) disposers.push(await ctx.remote.$mount(contribution)); + } catch (error) { + for (const dispose of disposers.reverse()) await dispose(); + throw error; + } + return async () => { + for (const dispose of disposers.reverse()) await dispose(); + }; + } + //#endregion + exports.apply = apply; + exports.inject = inject; + return module.exports; + } +}); + +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/index.js new file mode 100644 index 0000000..1946294 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/index.js @@ -0,0 +1,172 @@ +import { TypertLookupFailure } from "@deepseek-ai/dsh-typert-protocol"; +//#region lib/types/remote-events.js +/** +* The one home of this application's forwarded-Host-event allowlist. Both +* compiler faces list this file, so the Host forwarding loop and the consumer +* `ctx.remote.$on` key face read one declaration instead of two copies that +* could drift; `./types.ts` derives the type projection from it and stays +* type-only. +*/ +/** +* Host events this application forwards to consumers verbatim: no projection, +* no redaction, no renaming. The wire name is the Host cordis event name and +* the payload is its argument list, so this array is simultaneously the whole +* control point over what a consumer can receive and the legal key set of +* `ctx.remote.$on`. Forwarding one more event is an entry here and nothing +* else. +*/ +const API_REMOTE_FORWARDED_EVENTS = [ + "agent-preset/selected", + "commands/change", + "credentials/updated", + "cordis/request-run", + "cordis/request-run-resolved", + "cordis/dynamic-package", + "cordis/dynamic-retract", + "cordis/inspect-query", + "cordis/inspect-query-resolved", + "llm/adapters-updated", + "settings/document-updated" +]; +//#endregion +//#region lib/types/agent-lookup.js +/** Host BFF policy for resolving Remote Agent and Session identities. */ +/** Cold identity absent from the durable session store. */ +var ApiRemoteSessionNotFound = class extends Error {}; +/** Session identity whose lifecycle belongs to subagent routing. */ +var ApiRemoteSubagentSessionOwnership = class extends Error { + sessionId; + /** + * Construct the ownership fence. + * @param sessionId - identity reserved to subagent routing. + */ + constructor(sessionId) { + super(`session "${sessionId}" is a subagent session; use subagent delivery`); + this.sessionId = sessionId; + } +}; +/** +* Test whether generic Host routing must leave an identity to subagent routing. +* @param ctx - Host Context carrying the live Agent registry. +* @param session - attached or live Session metadata. +* @param agent - live Agent when one is registered. +* @returns whether generic Remote and legacy API calls must reject the identity. +*/ +function hasApiRemoteSubagentOwner(ctx, session, agent) { + if (session.header.origin === "subagent") return true; + const parentId = session.header.parentSession; + if (parentId === void 0 || agent === void 0) return false; + const parent = ctx.agents.get(parentId); + return parent !== void 0 && ctx.agents.isOwnedBy(agent.id, parent); +} +/** +* Build the stable caller-facing ownership rejection. +* @param sessionId - identity reserved to subagent routing. +* @returns the existing `agent-busy` RPC shape. +*/ +function apiRemoteSubagentOwnershipError(sessionId) { + return { + code: "agent-busy", + message: `session "${sessionId}" is owned by subagent routing`, + details: { reason: "use subagent delivery for this child session" } + }; +} +/** +* Inspect one cold served session without repairing, resuming, or publishing it. +* @param ctx - Host Context carrying the optional persistence provider. +* @param sessionId - durable identity to inspect. +* @returns detached metadata and events for a servable session. +* @throws {@link ApiRemoteSessionNotFound} when the identity has no project-backed session. +*/ +async function inspectApiRemoteSession(ctx, sessionId) { + const persistence = ctx.get("sessionPersistence"); + if (persistence === void 0) throw new Error("session persistence is not configured (load a dsh-session-persistence backend)"); + const meta = (await persistence.list()).find((candidate) => candidate.id === sessionId); + if (meta === void 0 || meta.cwd === void 0) throw new ApiRemoteSessionNotFound(`session "${sessionId}" not found`); + const inspected = await persistence.inspect(sessionId); + if (inspected.meta.cwd === void 0) throw new ApiRemoteSessionNotFound(`session "${sessionId}" not found`); + return { + meta: inspected.meta, + events: [...inspected.events] + }; +} +/** +* Create the Host's shared Agent resolver and configure Agent/Session Typert lookups. +* Live Agents are reused, ordinary cold sessions resume once per identity, and +* subagent-owned identities retain the legacy `agent-busy` fence. +* @param ctx - owning Host Context. +* @param options - defaults and Agent-scope setup used only for cold resume. +* @returns resolver shared by legacy API Proxy methods and Typert lookups. +*/ +function createApiRemoteAgentResolver(ctx, options) { + const resumes = /* @__PURE__ */ new Map(); + const fencedLiveAgent = (sessionId) => { + const live = ctx.agents.get(sessionId); + if (live === void 0) return void 0; + if (hasApiRemoteSubagentOwner(ctx, live.session, live)) return { error: apiRemoteSubagentOwnershipError(sessionId) }; + return { agent: live }; + }; + const agentFor = async (sessionId) => { + const fenced = fencedLiveAgent(sessionId); + if (fenced !== void 0) return fenced; + const attached = ctx.sessions.get(sessionId); + if (attached !== void 0 && hasApiRemoteSubagentOwner(ctx, attached, void 0)) return { error: apiRemoteSubagentOwnershipError(sessionId) }; + let resume = resumes.get(sessionId); + if (resume === void 0) { + resume = (async () => { + try { + const inspected = await inspectApiRemoteSession(ctx, sessionId); + if (hasApiRemoteSubagentOwner(ctx, { header: inspected.meta }, void 0)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + const setup = options.setup === void 0 ? void 0 : await options.setup(inspected); + const publishedSession = ctx.sessions.get(sessionId); + const publishedAgent = ctx.agents.get(sessionId); + if (publishedSession !== void 0 && hasApiRemoteSubagentOwner(ctx, publishedSession, publishedAgent)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + return (await ctx.agents.resume({ + resumeSessionId: sessionId, + ...options.agentOptions === void 0 ? {} : { agentOptions: options.agentOptions() }, + ...setup === void 0 ? {} : { setup } + })).agent; + } finally { + resumes.delete(sessionId); + } + })(); + resumes.set(sessionId, resume); + } + try { + return { agent: await resume }; + } catch (error) { + if (error instanceof ApiRemoteSessionNotFound) return { error: { + code: "session-not-found", + message: error.message, + details: { sessionId } + } }; + if (error instanceof ApiRemoteSubagentSessionOwnership) return { error: apiRemoteSubagentOwnershipError(error.sessionId) }; + const fenced = fencedLiveAgent(sessionId); + if (fenced !== void 0) return fenced; + const attached = ctx.sessions.get(sessionId); + if (attached !== void 0 && hasApiRemoteSubagentOwner(ctx, attached, void 0)) return { error: apiRemoteSubagentOwnershipError(sessionId) }; + return { error: { + code: "internal", + message: `resume failed for session "${sessionId}": ${String(error)}`, + details: {} + } }; + } + }; + ctx.inject(["typert"], (typeCtx) => { + const resolveAgent = async (sessionId) => { + const found = await agentFor(sessionId); + if ("error" in found) throw new TypertLookupFailure(found.error); + return found.agent; + }; + typeCtx.typert.lookups.configure("agent", resolveAgent); + typeCtx.typert.lookups.configure("session", async (sessionId) => (await resolveAgent(sessionId)).session); + typeCtx.typert.contexts.configureHost("agent", async (sessionId) => (await resolveAgent(sessionId)).ctx); + }); + return agentFor; +} +//#endregion +//#region lib/types/index.js +/** Host plugin body; the selected contributions mount only in Client environments. */ +function apply() {} +//#endregion +export { API_REMOTE_FORWARDED_EVENTS, ApiRemoteSessionNotFound, ApiRemoteSubagentSessionOwnership, apiRemoteSubagentOwnershipError, apply, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/invariant.js new file mode 100644 index 0000000..3c389fb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/invariant.js @@ -0,0 +1,17 @@ +//#region lib/types/invariant.js +/** Package-owned invariant companion for `@deepseek-ai/dsh-api-remotes`. */ +const PACKAGE_NAME = "@deepseek-ai/dsh-api-remotes"; +/** Cordis companion plugin name. */ +const name = "api-remotes-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** No runtime invariant: Typert and the Agent/Session registries own the observed relationships. */ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.d.ts new file mode 100644 index 0000000..97abfcf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.d.ts @@ -0,0 +1,95 @@ +/** Host BFF policy for resolving Remote Agent and Session identities. */ +import type { Context } from '@deepseek-ai/cordis'; +import type { Agent, AgentOptions, AgentSetup } from '@deepseek-ai/dsh-agent'; +import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session'; +/** Caller-facing failures preserved by the Gateway's RPC adapter. */ +export type ApiRemoteLookupError = { + readonly code: 'agent-busy'; + readonly message: string; + readonly details: { + readonly reason: string; + }; +} | { + readonly code: 'session-not-found'; + readonly message: string; + readonly details: { + readonly sessionId: SessionId; + }; +} | { + readonly code: 'internal'; + readonly message: string; + readonly details: Record; +}; +/** Result of resolving one session identity to its live Agent. */ +export type ApiRemoteAgentResult = { + readonly agent: Agent; +} | { + readonly error: ApiRemoteLookupError; +}; +/** Resume configuration supplied by the owning Host composition. */ +export interface ApiRemoteAgentOptions { + /** Read the per-Agent defaults when a cold identity must resume. */ + readonly agentOptions?: () => AgentOptions; + /** + * Build the Host-specific Agent-scope composition completed before + * publication. Keyed by the resumed session itself because what a Host + * installs may depend on what that session recorded: an agent preset fixes + * the tools its history was produced under, so rebuilding it under another + * composition would replay tool calls the agent can no longer make. The + * events come along because a session's own record of such a choice may be + * an event rather than a header field. + * @param session - the resumed session's persisted header and event log. + * @returns the Agent-scope setup to run before publication. + */ + readonly setup?: (session: { + meta: SessionHeader; + events: readonly SessionEvent[]; + }) => AgentSetup | Promise; +} +/** Cold identity absent from the durable session store. */ +export declare class ApiRemoteSessionNotFound extends Error { +} +/** Session identity whose lifecycle belongs to subagent routing. */ +export declare class ApiRemoteSubagentSessionOwnership extends Error { + readonly sessionId: SessionId; + /** + * Construct the ownership fence. + * @param sessionId - identity reserved to subagent routing. + */ + constructor(sessionId: SessionId); +} +/** + * Test whether generic Host routing must leave an identity to subagent routing. + * @param ctx - Host Context carrying the live Agent registry. + * @param session - attached or live Session metadata. + * @param agent - live Agent when one is registered. + * @returns whether generic Remote and legacy API calls must reject the identity. + */ +export declare function hasApiRemoteSubagentOwner(ctx: Context, session: Pick, agent: Agent | undefined): boolean; +/** + * Build the stable caller-facing ownership rejection. + * @param sessionId - identity reserved to subagent routing. + * @returns the existing `agent-busy` RPC shape. + */ +export declare function apiRemoteSubagentOwnershipError(sessionId: SessionId): ApiRemoteLookupError; +/** + * Inspect one cold served session without repairing, resuming, or publishing it. + * @param ctx - Host Context carrying the optional persistence provider. + * @param sessionId - durable identity to inspect. + * @returns detached metadata and events for a servable session. + * @throws {@link ApiRemoteSessionNotFound} when the identity has no project-backed session. + */ +export declare function inspectApiRemoteSession(ctx: Context, sessionId: SessionId): Promise<{ + meta: SessionHeader; + events: SessionEvent[]; +}>; +/** + * Create the Host's shared Agent resolver and configure Agent/Session Typert lookups. + * Live Agents are reused, ordinary cold sessions resume once per identity, and + * subagent-owned identities retain the legacy `agent-busy` fence. + * @param ctx - owning Host Context. + * @param options - defaults and Agent-scope setup used only for cold resume. + * @returns resolver shared by legacy API Proxy methods and Typert lookups. + */ +export declare function createApiRemoteAgentResolver(ctx: Context, options: ApiRemoteAgentOptions): (sessionId: SessionId) => Promise; +//# sourceMappingURL=agent-lookup.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.js new file mode 100644 index 0000000..a2f7ce4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.js @@ -0,0 +1,166 @@ +/** Host BFF policy for resolving Remote Agent and Session identities. */ +import { TypertLookupFailure } from '@deepseek-ai/dsh-typert-protocol'; +/** Cold identity absent from the durable session store. */ +export class ApiRemoteSessionNotFound extends Error { +} +/** Session identity whose lifecycle belongs to subagent routing. */ +export class ApiRemoteSubagentSessionOwnership extends Error { + sessionId; + /** + * Construct the ownership fence. + * @param sessionId - identity reserved to subagent routing. + */ + constructor(sessionId) { + super(`session "${sessionId}" is a subagent session; use subagent delivery`); + this.sessionId = sessionId; + } +} +/** + * Test whether generic Host routing must leave an identity to subagent routing. + * @param ctx - Host Context carrying the live Agent registry. + * @param session - attached or live Session metadata. + * @param agent - live Agent when one is registered. + * @returns whether generic Remote and legacy API calls must reject the identity. + */ +export function hasApiRemoteSubagentOwner(ctx, session, agent) { + if (session.header.origin === 'subagent') + return true; + const parentId = session.header.parentSession; + if (parentId === undefined || agent === undefined) + return false; + const parent = ctx.agents.get(parentId); + return parent !== undefined && ctx.agents.isOwnedBy(agent.id, parent); +} +/** + * Build the stable caller-facing ownership rejection. + * @param sessionId - identity reserved to subagent routing. + * @returns the existing `agent-busy` RPC shape. + */ +export function apiRemoteSubagentOwnershipError(sessionId) { + return { + code: 'agent-busy', + message: `session "${sessionId}" is owned by subagent routing`, + details: { reason: 'use subagent delivery for this child session' }, + }; +} +/** + * Inspect one cold served session without repairing, resuming, or publishing it. + * @param ctx - Host Context carrying the optional persistence provider. + * @param sessionId - durable identity to inspect. + * @returns detached metadata and events for a servable session. + * @throws {@link ApiRemoteSessionNotFound} when the identity has no project-backed session. + */ +export async function inspectApiRemoteSession(ctx, sessionId) { + const persistence = ctx.get('sessionPersistence'); + if (persistence === undefined) { + throw new Error('session persistence is not configured (load a dsh-session-persistence backend)'); + } + const meta = (await persistence.list()).find(candidate => candidate.id === sessionId); + if (meta === undefined || meta.cwd === undefined) { + throw new ApiRemoteSessionNotFound(`session "${sessionId}" not found`); + } + const inspected = await persistence.inspect(sessionId); + if (inspected.meta.cwd === undefined) { + throw new ApiRemoteSessionNotFound(`session "${sessionId}" not found`); + } + return { meta: inspected.meta, events: [...inspected.events] }; +} +/** + * Create the Host's shared Agent resolver and configure Agent/Session Typert lookups. + * Live Agents are reused, ordinary cold sessions resume once per identity, and + * subagent-owned identities retain the legacy `agent-busy` fence. + * @param ctx - owning Host Context. + * @param options - defaults and Agent-scope setup used only for cold resume. + * @returns resolver shared by legacy API Proxy methods and Typert lookups. + */ +export function createApiRemoteAgentResolver(ctx, options) { + const resumes = new Map(); + const fencedLiveAgent = (sessionId) => { + const live = ctx.agents.get(sessionId); + if (live === undefined) + return undefined; + if (hasApiRemoteSubagentOwner(ctx, live.session, live)) { + return { error: apiRemoteSubagentOwnershipError(sessionId) }; + } + return { agent: live }; + }; + const agentFor = async (sessionId) => { + const fenced = fencedLiveAgent(sessionId); + if (fenced !== undefined) + return fenced; + const attached = ctx.sessions.get(sessionId); + if (attached !== undefined && hasApiRemoteSubagentOwner(ctx, attached, undefined)) { + return { error: apiRemoteSubagentOwnershipError(sessionId) }; + } + let resume = resumes.get(sessionId); + if (resume === undefined) { + resume = (async () => { + try { + const inspected = await inspectApiRemoteSession(ctx, sessionId); + if (hasApiRemoteSubagentOwner(ctx, { header: inspected.meta }, undefined)) { + throw new ApiRemoteSubagentSessionOwnership(sessionId); + } + // Built from the inspected session before the published re-checks + // below, so those stay adjacent to `resume` and a Host setup that + // awaits (composing a preset, say) does not widen the collision + // window. + const setup = options.setup === undefined ? undefined : await options.setup(inspected); + const publishedSession = ctx.sessions.get(sessionId); + const publishedAgent = ctx.agents.get(sessionId); + if (publishedSession !== undefined + && hasApiRemoteSubagentOwner(ctx, publishedSession, publishedAgent)) { + throw new ApiRemoteSubagentSessionOwnership(sessionId); + } + const handle = await ctx.agents.resume({ + resumeSessionId: sessionId, + ...options.agentOptions === undefined ? {} : { agentOptions: options.agentOptions() }, + ...setup === undefined ? {} : { setup }, + }); + return handle.agent; + } + finally { + resumes.delete(sessionId); + } + })(); + resumes.set(sessionId, resume); + } + try { + return { agent: await resume }; + } + catch (error) { + if (error instanceof ApiRemoteSessionNotFound) { + return { error: { code: 'session-not-found', message: error.message, details: { sessionId } } }; + } + if (error instanceof ApiRemoteSubagentSessionOwnership) { + return { error: apiRemoteSubagentOwnershipError(error.sessionId) }; + } + const fenced = fencedLiveAgent(sessionId); + if (fenced !== undefined) + return fenced; + const attached = ctx.sessions.get(sessionId); + if (attached !== undefined && hasApiRemoteSubagentOwner(ctx, attached, undefined)) { + return { error: apiRemoteSubagentOwnershipError(sessionId) }; + } + return { + error: { + code: 'internal', + message: `resume failed for session "${sessionId}": ${String(error)}`, + details: {}, + }, + }; + } + }; + ctx.inject(['typert'], (typeCtx) => { + const resolveAgent = async (sessionId) => { + const found = await agentFor(sessionId); + if ('error' in found) + throw new TypertLookupFailure(found.error); + return found.agent; + }; + typeCtx.typert.lookups.configure('agent', resolveAgent); + typeCtx.typert.lookups.configure('session', async (sessionId) => (await resolveAgent(sessionId)).session); + typeCtx.typert.contexts.configureHost('agent', async (sessionId) => (await resolveAgent(sessionId)).ctx); + }); + return agentFor; +} +//# sourceMappingURL=agent-lookup.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.d.ts new file mode 100644 index 0000000..7032aa4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.d.ts @@ -0,0 +1,41 @@ +/** Platform-neutral assembly of generated Host Remote contributions. */ +import type { Context } from '@deepseek-ai/cordis'; +import type { TypertClientRemote } from '@deepseek-ai/dsh-typert-protocol'; +export type { TypertClientRemote as ClientRemote } from '@deepseek-ai/dsh-typert-protocol'; +export type { PluginInventorySnapshot } from '@deepseek-ai/dsh-host-plugin-inventory/types'; +export type {} from '@deepseek-ai/dsh-commands/remote'; +export type {} from '@deepseek-ai/dsh-goal/remote'; +export type {} from '@deepseek-ai/dsh-host-plugin-inventory/remote'; +export type {} from '@deepseek-ai/dsh-message-feedback/remote'; +export type { ApiRemoteForwardedEvent } from '../types.ts'; +export type {} from '@deepseek-ai/dsh-commands/types'; +export type {} from '@deepseek-ai/dsh-cordis-host-runner/types'; +export type {} from '@deepseek-ai/dsh-credentials/types'; +export type {} from '@deepseek-ai/dsh-llm/types'; +export type {} from '@deepseek-ai/dsh-agent-presets/types'; +export type {} from '@deepseek-ai/dsh-settings/types'; +/** + * The carrier's Client-facing types, re-exported so a business package names one + * assembly package instead of both this facade and the Connection plugin. Type-only: + * the carrier's runtime values stay behind their own module edge. + */ +export type { ClientResponse, ConfigurableProviderView, ConnectionHandle, ConnectionSinks, ContentBlock, CredentialView, DirectoryListing, DiscoveredModelView, HistoryEntry, HostFrame, IApiClient, MessageId, ModelCatalogFailure, ModelProviderGroup, ModelReasoningEffort, ModelSelection, MuxFrame, PromptContentPart, QuestionResponsePayload, QueueAction, RpcError, RpcId, RpcReceipt, RpcRequest, RpcResponse, RpcResult, SessionId, SessionModels, SessionSearchItem, SessionSummary, SettingsNamespaceView, SettingsPathOpView, SkillEntry, StreamChunk, SubagentAddress, SubagentCatalog, JobView, ToolCallView, ToolEventView, ToolResultView, WorkspaceId, WorkspaceView, } from '@deepseek-ai/dsh-client-connection/client'; +export type {} from '@deepseek-ai/dsh-api-gateway/client'; +export type {} from '@deepseek-ai/dsh-cordis-host-runner/remote'; +export type { ApprovalRequestId, CordisHalfState, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisDynamicRunMode, CordisInspectMethodManifest, CordisInspectPlatform, CordisInspectProviderManifest, CordisInspectProviderView, CordisInspectQueryRequest, CordisInspectQueryResolution, CordisInspectQueryResolved, CordisInspectRequestId, CordisInspectResolveAck, CordisRunDiagnostic, CordisRunStatus, DynamicCordisClientSource, DynamicCordisHostHalfResult, DynamicCordisInventoryRow, DynamicCordisInvokeResult, DynamicCordisPackage, DynamicCordisRequestResolved, DynamicCordisResolveAck, DynamicCordisRetracted, DynamicCordisRunRequest, DynamicCordisRunResolution, DynamicCordisRunAttempt, DynamicCordisRunResponse, DynamicCordisStopResponse, DynamicCordisUndefineReceipt, RequestRunOutcome, } from '@deepseek-ai/dsh-cordis-host-runner/types'; +export type { JsonValue } from '@deepseek-ai/dsh-session/types'; +declare module '@deepseek-ai/cordis' { + interface Context { + /** Generated Remote namespaces selected by this Client assembly. */ + remote: TypertClientRemote; + } +} +/** Required service: the typed Client Remote contribution mount. */ +export declare const inject: string[]; +/** + * Mount the Host capabilities explicitly selected for this Client assembly. + * @param ctx - Client Cordis root carrying the typed API service. + * @returns disposer after every selected Remote namespace is ready. + */ +export declare function apply(ctx: Context): Promise<() => Promise>; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.js new file mode 100644 index 0000000..ba70087 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.js @@ -0,0 +1,35 @@ +/** Platform-neutral assembly of generated Host Remote contributions. */ +import commandsRemote from '@deepseek-ai/dsh-commands/remote'; +import goalsRemote from '@deepseek-ai/dsh-goal/remote'; +import dynamicRemote from '@deepseek-ai/dsh-cordis-host-runner/remote'; +import pluginInventoryRemote from '@deepseek-ai/dsh-host-plugin-inventory/remote'; +import messageFeedbackRemote from '@deepseek-ai/dsh-message-feedback/remote'; +/** Required service: the typed Client Remote contribution mount. */ +export const inject = ['remote']; +/** + * Mount the Host capabilities explicitly selected for this Client assembly. + * @param ctx - Client Cordis root carrying the typed API service. + * @returns disposer after every selected Remote namespace is ready. + */ +export async function apply(ctx) { + const disposers = []; + try { + for (const contribution of [ + commandsRemote, goalsRemote, dynamicRemote, pluginInventoryRemote, messageFeedbackRemote, + ]) { + disposers.push(await ctx.remote.$mount(contribution)); + } + } + catch (error) { + for (const dispose of disposers.reverse()) + await dispose(); + throw error; + } + // Unwound in reverse mount order, so a namespace never outlives one mounted + // after it. + return async () => { + for (const dispose of disposers.reverse()) + await dispose(); + }; +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.d.ts new file mode 100644 index 0000000..986d541 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.d.ts @@ -0,0 +1,8 @@ +/** Host BFF entry and Loader shell for the Remote contribution assembly. */ +export { ApiRemoteSessionNotFound, ApiRemoteSubagentSessionOwnership, apiRemoteSubagentOwnershipError, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession, } from './agent-lookup.ts'; +export type { ApiRemoteAgentOptions, ApiRemoteAgentResult, ApiRemoteLookupError, } from './agent-lookup.ts'; +export { API_REMOTE_FORWARDED_EVENTS } from './remote-events.ts'; +export type { ApiRemoteForwardedEvent } from './types.ts'; +/** Host plugin body; the selected contributions mount only in Client environments. */ +export declare function apply(): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.js new file mode 100644 index 0000000..bc7bff8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.js @@ -0,0 +1,16 @@ +/** Host BFF entry and Loader shell for the Remote contribution assembly. */ +import { API_REMOTE_FORWARDED_EVENTS } from "./remote-events.js"; +export { ApiRemoteSessionNotFound, ApiRemoteSubagentSessionOwnership, apiRemoteSubagentOwnershipError, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession, } from "./agent-lookup.js"; +export { API_REMOTE_FORWARDED_EVENTS } from "./remote-events.js"; +// Shape gate over the allowlist, kept in the Host face because the Host's event +// vocabulary is the authoritative one. It pins three things at compile time: +// every entry NAMES a declared event (the predicate is keyed on `keyof +// Events`), no entry BINDS a Scope (a scoped event's `ThisParameterType` is not +// `unknown`, which is how "must not depend on AgentScope" is stated statically), +// and every entry is ONE-WAY (a waterfall or bail shape returns something other +// than void and is excluded). Widening the array to an event that fails any of +// these fails here, not on the wire. +API_REMOTE_FORWARDED_EVENTS; +/** Host plugin body; the selected contributions mount only in Client environments. */ +export function apply() { } +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.d.ts new file mode 100644 index 0000000..caa7541 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned invariant companion for `@deepseek-ai/dsh-api-remotes`. */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "api-remotes-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.js new file mode 100644 index 0000000..8807737 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.js @@ -0,0 +1,16 @@ +/** Package-owned invariant companion for `@deepseek-ai/dsh-api-remotes`. */ +const PACKAGE_NAME = '@deepseek-ai/dsh-api-remotes'; +/** Cordis companion plugin name. */ +export const name = 'api-remotes-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** No runtime invariant: Typert and the Agent/Session registries own the observed relationships. */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.d.ts new file mode 100644 index 0000000..b97dbc4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.d.ts @@ -0,0 +1,17 @@ +/** + * The one home of this application's forwarded-Host-event allowlist. Both + * compiler faces list this file, so the Host forwarding loop and the consumer + * `ctx.remote.$on` key face read one declaration instead of two copies that + * could drift; `./types.ts` derives the type projection from it and stays + * type-only. + */ +/** + * Host events this application forwards to consumers verbatim: no projection, + * no redaction, no renaming. The wire name is the Host cordis event name and + * the payload is its argument list, so this array is simultaneously the whole + * control point over what a consumer can receive and the legal key set of + * `ctx.remote.$on`. Forwarding one more event is an entry here and nothing + * else. + */ +export declare const API_REMOTE_FORWARDED_EVENTS: readonly ["agent-preset/selected", "commands/change", "credentials/updated", "cordis/request-run", "cordis/request-run-resolved", "cordis/dynamic-package", "cordis/dynamic-retract", "cordis/inspect-query", "cordis/inspect-query-resolved", "llm/adapters-updated", "settings/document-updated"]; +//# sourceMappingURL=remote-events.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.js new file mode 100644 index 0000000..7ba8f5d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.js @@ -0,0 +1,29 @@ +/** + * The one home of this application's forwarded-Host-event allowlist. Both + * compiler faces list this file, so the Host forwarding loop and the consumer + * `ctx.remote.$on` key face read one declaration instead of two copies that + * could drift; `./types.ts` derives the type projection from it and stays + * type-only. + */ +/** + * Host events this application forwards to consumers verbatim: no projection, + * no redaction, no renaming. The wire name is the Host cordis event name and + * the payload is its argument list, so this array is simultaneously the whole + * control point over what a consumer can receive and the legal key set of + * `ctx.remote.$on`. Forwarding one more event is an entry here and nothing + * else. + */ +export const API_REMOTE_FORWARDED_EVENTS = [ + 'agent-preset/selected', + 'commands/change', + 'credentials/updated', + 'cordis/request-run', + 'cordis/request-run-resolved', + 'cordis/dynamic-package', + 'cordis/dynamic-retract', + 'cordis/inspect-query', + 'cordis/inspect-query-resolved', + 'llm/adapters-updated', + 'settings/document-updated', +]; +//# sourceMappingURL=remote-events.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.d.ts new file mode 100644 index 0000000..178e23d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.d.ts @@ -0,0 +1,18 @@ +/** + * Type face of the forwarded-Host-event allowlist: the consumer key projection + * and the selection seat it fills. The allowlist VALUE lives in + * `./remote-events.ts`, keeping this module type-only per the package + * convention; both compiler faces list both files, so the Host forwarding loop + * and the consumer `ctx.remote.$on` key face read one declaration instead of + * two copies that could drift. + * + * @module @deepseek-ai/dsh-api-remotes/types + */ +import type { API_REMOTE_FORWARDED_EVENTS } from './remote-events.ts'; +/** Type projection of the allowlist; the consumer and the Host read this one. */ +export type ApiRemoteForwardedEvent = typeof API_REMOTE_FORWARDED_EVENTS[number]; +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteEventSelection extends Record { + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.js new file mode 100644 index 0000000..dca6a38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.js @@ -0,0 +1,12 @@ +/** + * Type face of the forwarded-Host-event allowlist: the consumer key projection + * and the selection seat it fills. The allowlist VALUE lives in + * `./remote-events.ts`, keeping this module type-only per the package + * convention; both compiler faces list both files, so the Host forwarding loop + * and the consumer `ctx.remote.$on` key face read one declaration instead of + * two copies that could drift. + * + * @module @deepseek-ai/dsh-api-remotes/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/package.json new file mode 100644 index 0000000..8a56bd0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes/package.json @@ -0,0 +1,96 @@ +{ + "name": "@deepseek-ai/dsh-api-remotes", + "description": "Remote BFF assembly and Host Agent/Session lookup policy", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/api/remotes" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client/index.d.ts", + "default": "./lib/client.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "dsh": { + "client": { + "inject": [ + "@deepseek-ai/dsh-api-gateway" + ], + "platform": "web", + "immediately": true + } + }, + "license": "MIT", + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/client.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.6", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.6", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.6", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.6", + "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.6" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.6", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.6", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.6", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.6", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.6", + "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "scripts": { + "bundle": "tsdown", + "watch": "tsdown --watch" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-commands b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-commands new file mode 120000 index 0000000..fff701f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-commands @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-cordis-host-runner b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-cordis-host-runner new file mode 120000 index 0000000..e7009aa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-cordis-host-runner @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-credentials b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-credentials new file mode 120000 index 0000000..ea853b1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-credentials @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-goal b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-goal new file mode 120000 index 0000000..2465185 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-goal @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-host-plugin-inventory b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-host-plugin-inventory new file mode 120000 index 0000000..d674895 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-host-plugin-inventory @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-message-feedback b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-message-feedback new file mode 120000 index 0000000..1f78cd5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-message-feedback @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..a0535b0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-settings b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-settings new file mode 120000 index 0000000..810b363 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-settings @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..aa2ae83 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-typert-registry b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-typert-registry new file mode 120000 index 0000000..6e23eda --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-typert-registry @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-agent-presets b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-agent-presets new file mode 120000 index 0000000..dff57a0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-agent-presets @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-gateway b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-gateway new file mode 120000 index 0000000..d2053f4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-gateway @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.i18n.yaml new file mode 100644 index 0000000..b9ff0c0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/api/remotes/README.md +README.md: 18d39c6e86f114d2aac2f24e5d15c13335eab020 +README.zh.md: bf3dfbbaa6e0c7bd1da8398977837d4cb19d4688 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.md new file mode 100644 index 0000000..18d39c6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.md @@ -0,0 +1,41 @@ +# @deepseek-ai/dsh-api-remotes + +English | [中文](README.zh.md) + +Two-sided BFF for Host Remote capabilities selected by this application. The Host entry owns Agent/Session identity policy; the Client entry imports generated `/remote` artifacts as runtime values, mounts each contribution through `ctx.remote.$mount()`, and re-exports their declaration merges. Client business packages depend on this facade rather than the Gateway implementation or individual Remote runtime entries. + +`createApiRemoteAgentResolver()` reuses live Agents, resumes ordinary cold sessions, deduplicates concurrent resumes, preserves the subagent ownership fence, and configures the same resolver for Typert `agent` and `session` lookups. The standard Web API Proxy supplies its Agent defaults and scope setup, then uses the returned resolver for legacy methods, so migrated and unmigrated methods share one policy implementation. + +The current Client assembly mounts the Goal Remote contribution and the read-only Host plugin inventory contribution (`pluginInventory/list`). Cordis effect ownership withdraws every contribution when this assembly unloads, while `@deepseek-ai/dsh-api-gateway/client` owns descriptor validation, traced namespace Services, direct and scoped methods, invocation, and cancellation. The Client entry consumes the shared `TypertClientRemote` interface through Cordis and does not import the concrete Gateway. It re-exports the Gateway Client face's declaration merges type-only, so a consumer reaching the forwarded-event vocabulary through this facade gains no runtime edge to the Gateway implementation. + +This package contains no transport or Host service discovery logic. Its Client face can be reused by Web or a future TUI that provides the same React-free `ctx.remote` contract. + +## Forwarded Host events + +`src/remote-events.ts` holds `API_REMOTE_FORWARDED_EVENTS`, the allowlist of Host cordis events this application forwards to consumers verbatim — no projection, no redaction, no renaming — and therefore the legal key set of `ctx.remote.$on`; the type-only `src/types.ts` derives its selection face. Forwarding one more event is an entry in that array and nothing else: the type projection, the consumer key face, and the Host forwarding loop all derive from it. + +The listener signature is not restated here. Each allowlisted event's cordis `Events` declaration lives in its owner package's client-safe `./types` export (`dsh-agent-presets`, `dsh-commands`, `dsh-credentials`, `dsh-llm`, `dsh-settings`), and both faces of this package pull those declarations in, so "forwarded verbatim" holds by construction rather than by proof. The Host face additionally asserts the list against `TypertForwardableEvent`, which rejects a name that is not a declared event, one that binds an AgentScope, and one whose shape is not one-way. + +## Build boundary + +An ordinary repository package belongs to one TypeScript face: Host packages are registered in the root `tsconfig.host.json`, and Client packages in the root `tsconfig.client.json`. `api-remotes` is the only deliberate exception because its Host entry must participate in the Host Typert graph, while `src/client/index.ts` cannot compile until Host tsdown has generated the business packages' `/remote` declarations. + +This package's root `tsconfig.json` is only a solution that references `tsconfig.host.json` and `tsconfig.client.json`. The Host aggregate and direct Host consumers reference the former, while the Client aggregate and direct Client consumers reference the latter; the package-root solution must not enter either aggregate's dependency graph. The two projects own disjoint source files and `.tsbuildinfo` files but share the `lib/types` output directory, with one deliberate exception: `src/remote-events.ts` and `src/types.ts` are listed in BOTH faces' `files`, because the forwarded-event allowlist is the single control point over what a consumer can receive, and the Host forwarding loop and the Client `ctx.remote.$on` key face must read one declaration rather than two that could drift. + +That exception is not just a `files` entry. The root `tsconfig.base.json` maps `@deepseek-ai/dsh-api-remotes/types` to `src/types.ts` — the source plane, like every other workspace subpath and unlike the generated `/remote` artifacts, which have no `paths` entry and resolve through `exports` to built output. Both faces therefore admit the same allowlist and type projection into their own programs and emit byte-identical `remote-events` and `types` outputs into `lib/types`; the `.tsbuildinfo` files stay independent. No gate enforces the faces' source-file disjointness — `scripts/project-reference-faces.ts` only checks that a reference into a split project names the matching face — so this paragraph records why the double listing is intentional. + +The package-local `clientBundle(..., { hostPhase: true })` makes Host tsdown bundle the Host entry and the later Client tsdown bundle only the browser entry. Ordinary Client plugins remain single Client projects and produce both their Node loader entry and browser bundle during Client tsdown; do not copy this package's split merely because a package has both `src/index.ts` and `src/client/index.ts`. + +## Model Experience + +None, as this BFF selects Remote application methods and identity policy but registers nothing model-facing. + +#### KV Cache effect + +No direct effect; mounted Host capabilities own any model-visible behavior they trigger. + +## Known Limitations and Deferred Work + +- The capability set is fixed by explicit build-time value imports; the Client does not discover the Host's active Services or Remote definitions at runtime. +- Additional capabilities require an explicit `/remote` value import and mount in this assembly. +- The standard Web Host supplies resume defaults and Agent-scope setup from the legacy API Proxy until that remaining BFF configuration moves into `api-remotes`. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.zh.md new file mode 100644 index 0000000..bf3dfbb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/README.zh.md @@ -0,0 +1,42 @@ +# @deepseek-ai/dsh-api-remotes + +[English](README.md) | 中文 + +为本应用选定的 Host Remote 能力提供双侧 BFF。Host 入口负责 Agent/Session 身份策略;Client 入口以运行时值形式导入生成的 `/remote` 产物,通过 `ctx.remote.$mount()` 挂载每项贡献,并重新导出对应的声明合并。Client 业务包依赖该外观,而不依赖 Gateway 实现或单独的 Remote 运行时入口。 + +`createApiRemoteAgentResolver()` 会复用 live Agent、恢复普通冷会话、对并发恢复去重、保留 subagent ownership fence,并为 Typert `agent` 和 `session` lookup 配置同一个 resolver。标准 Web API Proxy 提供 Agent 默认值和 scope 设置,再将返回的 resolver 用于旧方法,使已迁移与未迁移方法共用同一份策略实现。 + +当前 Client 组合挂载 Goal Remote 贡献和只读 Host 插件清单贡献(`pluginInventory/list`)。该组合卸载时,Cordis effect 的所有权机制会撤回所有贡献;`@deepseek-ai/dsh-api-gateway/client` 负责描述符校验、可追踪 namespace Service、直接与作用域方法、调用与取消。Client 入口通过 Cordis 消费共享的 `TypertClientRemote` 接口,不导入具体 Gateway;它只以 type-only 形式重新导出 Gateway Client face 的声明合并,因此消费端经由本外观取到转发事件词汇时,运行时不会多出一条通往 Gateway 实现的边。 + +本包不包含传输逻辑或 Host 服务发现逻辑。Web 或未来的 TUI 只要提供同一份不依赖 React 的 `ctx.remote` 约定,均可复用其 Client face。 + +## 转发的 Host 事件 + +`src/remote-events.ts` 持有 `API_REMOTE_FORWARDED_EVENTS`——本应用原样转发给消费端的 Host cordis 事件名单(无投影、无脱敏、无改名),它同时就是 `ctx.remote.$on` 的合法键集;只含类型的 `src/types.ts` 派生其选择面。多转发一个事件只需在该数组里加一行:类型投影、消费端键面与 Host 转发循环全部由它派生。 + +监听器签名不在此处重写。名单内每条事件的 cordis `Events` 声明都住在其 owner 包 client-safe 的 `./types` 出口(`dsh-agent-presets`、`dsh-commands`、`dsh-credentials`、`dsh-llm`、`dsh-settings`),本包两个 face 都把那些声明纳入编译面,因此「原样转发」是构造性成立的,不需要另立证明。Host face 还额外把名单断言给 `TypertForwardableEvent`:未声明的事件名、绑定 AgentScope 的事件、以及形状不是单向的事件都会在此被拒绝。 + +## 构建边界 + +仓库中的普通包只属于一个 TypeScript face:Host 包登记在根 `tsconfig.host.json`,Client 包登记在根 `tsconfig.client.json`。`api-remotes` 是唯一刻意拆分的特例,因为它的 Host 入口要参与 Host Typert 图,而 `src/client/index.ts` 必须等 Host tsdown 生成业务包的 `/remote` 声明后才能编译。 + +本包根 `tsconfig.json` 只是引用 `tsconfig.host.json` 与 `tsconfig.client.json` 的 solution。Host aggregate 和 Host 直接消费方引用前者,Client aggregate 和 Client 直接消费方引用后者;禁止把包根 solution 放进任一 aggregate 的依赖图。两个 project 拥有互不重叠的源码和 `.tsbuildinfo`,但共享 `lib/types` 输出目录——只有一处刻意的例外:`src/remote-events.ts` 与 `src/types.ts` **同时**列进两个 face 的 `files`,因为转发事件名单是「消费端能收到什么」的唯一控制点,Host 转发循环与 Client 的 `ctx.remote.$on` 键面必须读同一份声明,而不是两份可能彼此漂移的声明。 + +这条例外不止是一行 `files`。根 `tsconfig.base.json` 把 `@deepseek-ai/dsh-api-remotes/types` 映射到 `src/types.ts`——**源平面**,与其余所有 workspace 子路径一致,也与生成的 `/remote` 产物相反(后者没有 `paths` 条目,靠 `exports` 命中构建产物)。于是两个 face 都把同一份名单与类型投影收进各自的 program,并向 `lib/types` 发射逐字相同的 `remote-events` 与 `types` 输出;`.tsbuildinfo` 仍各自独立。没有任何门禁强制两个 face 的源文件互不重叠——`scripts/project-reference-faces.ts` 只校验「引用一个 split project 必须指到对应 face」——因此本段记录这次双列为何是有意的。 + + +包内 `clientBundle(..., { hostPhase: true })` 让 Host tsdown 打包 Host 入口,让后续 Client tsdown 只打包 browser 入口。普通 Client 插件仍使用单一 Client project,并在 Client tsdown 阶段一起生成 Node loader 入口和 browser bundle;不得因一个包同时存在 `src/index.ts` 与 `src/client/index.ts` 就复制本包的拆分。 + +## 模型体验 + +无,因为该 BFF 只选择 Remote 应用方法和身份策略,不注册任何模型接口。 + +#### KV Cache 影响 + +无直接影响;其触发的任何模型可见行为均由已挂载的 Host 能力负责。 + +## 已知限制与暂缓事项 + +- 能力集合由构建时显式导入的值固定确定;Client 不会在运行时发现 Host 中已启用的服务或 Remote 定义。 +- 若要增加能力,必须显式导入相应的 `/remote` 值并在此组合中挂载。 +- 在剩余 BFF 配置迁移到 `api-remotes` 之前,标准 Web Host 仍从旧 API Proxy 提供恢复默认值与 Agent scope 设置。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js new file mode 100644 index 0000000..461490b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js @@ -0,0 +1,5937 @@ +window.__ModuleLoader__.load({ + id: "@deepseek-ai/dsh-api-remotes", + factory: (require) => { + var module = { exports: {} }; + var exports = module.exports; + Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js + var _a$1; + function $constructor(name, initializer, params) { + function init(inst, def) { + if (!inst._zod) Object.defineProperty(inst, "_zod", { + value: { + def, + constr: _, + traits: /* @__PURE__ */ new Set() + }, + enumerable: false + }); + if (inst._zod.traits.has(name)) return; + inst._zod.traits.add(name); + initializer(inst, def); + const proto = _.prototype; + const keys = Object.keys(proto); + for (let i = 0; i < keys.length; i++) { + const k = keys[i]; + if (!(k in inst)) inst[k] = proto[k].bind(inst); + } + } + const Parent = params?.Parent ?? Object; + class Definition extends Parent {} + Object.defineProperty(Definition, "name", { value: name }); + function _(def) { + var _a; + const inst = params?.Parent ? new Definition() : this; + init(inst, def); + (_a = inst._zod).deferred ?? (_a.deferred = []); + for (const fn of inst._zod.deferred) fn(); + return inst; + } + Object.defineProperty(_, "init", { value: init }); + Object.defineProperty(_, Symbol.hasInstance, { value: (inst) => { + if (params?.Parent && inst instanceof params.Parent) return true; + return inst?._zod?.traits?.has(name); + } }); + Object.defineProperty(_, "name", { value: name }); + return _; + } + var $ZodAsyncError = class extends Error { + constructor() { + super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`); + } + }; + var $ZodEncodeError = class extends Error { + constructor(name) { + super(`Encountered unidirectional transform during encode: ${name}`); + this.name = "ZodEncodeError"; + } + }; + (_a$1 = globalThis).__zod_globalConfig ?? (_a$1.__zod_globalConfig = {}); + const globalConfig = globalThis.__zod_globalConfig; + function config(newConfig) { + if (newConfig) Object.assign(globalConfig, newConfig); + return globalConfig; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.js + function getEnumValues(entries) { + const numericValues = Object.values(entries).filter((v) => typeof v === "number"); + return Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v); + } + function jsonStringifyReplacer(_, value) { + if (typeof value === "bigint") return value.toString(); + return value; + } + function cached(getter) { + return { get value() { + { + const value = getter(); + Object.defineProperty(this, "value", { value }); + return value; + } + throw new Error("cached value already set"); + } }; + } + function nullish(input) { + return input === null || input === void 0; + } + function cleanRegex(source) { + const start = source.startsWith("^") ? 1 : 0; + const end = source.endsWith("$") ? source.length - 1 : source.length; + return source.slice(start, end); + } + function floatSafeRemainder(val, step) { + const ratio = val / step; + const roundedRatio = Math.round(ratio); + const tolerance = Number.EPSILON * Math.max(Math.abs(ratio), 1); + if (Math.abs(ratio - roundedRatio) < tolerance) return 0; + return ratio - roundedRatio; + } + const EVALUATING = /* @__PURE__*/ Symbol("evaluating"); + function defineLazy(object, key, getter) { + let value = void 0; + Object.defineProperty(object, key, { + get() { + if (value === EVALUATING) return; + if (value === void 0) { + value = EVALUATING; + value = getter(); + } + return value; + }, + set(v) { + Object.defineProperty(object, key, { value: v }); + }, + configurable: true + }); + } + function assignProp(target, prop, value) { + Object.defineProperty(target, prop, { + value, + writable: true, + enumerable: true, + configurable: true + }); + } + function mergeDefs(...defs) { + const mergedDescriptors = {}; + for (const def of defs) Object.assign(mergedDescriptors, Object.getOwnPropertyDescriptors(def)); + return Object.defineProperties({}, mergedDescriptors); + } + function esc(str) { + return JSON.stringify(str); + } + function slugify(input) { + return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, ""); + } + const captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {}; + function isObject(data) { + return typeof data === "object" && data !== null && !Array.isArray(data); + } + const allowsEval = /* @__PURE__*/ cached(() => { + if (globalConfig.jitless) return false; + if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) return false; + try { + new Function(""); + return true; + } catch (_) { + return false; + } + }); + function isPlainObject(o) { + if (isObject(o) === false) return false; + const ctor = o.constructor; + if (ctor === void 0) return true; + if (typeof ctor !== "function") return true; + const prot = ctor.prototype; + if (isObject(prot) === false) return false; + if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) return false; + return true; + } + function shallowClone(o) { + if (isPlainObject(o)) return { ...o }; + if (Array.isArray(o)) return [...o]; + if (o instanceof Map) return new Map(o); + if (o instanceof Set) return new Set(o); + return o; + } + const propertyKeyTypes = /* @__PURE__*/ new Set([ + "string", + "number", + "symbol" + ]); + function escapeRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + } + function clone(inst, def, params) { + const cl = new inst._zod.constr(def ?? inst._zod.def); + if (!def || params?.parent) cl._zod.parent = inst; + return cl; + } + function normalizeParams(_params) { + const params = _params; + if (!params) return {}; + if (typeof params === "string") return { error: () => params }; + if (params?.message !== void 0) { + if (params?.error !== void 0) throw new Error("Cannot specify both `message` and `error` params"); + params.error = params.message; + } + delete params.message; + if (typeof params.error === "string") return { + ...params, + error: () => params.error + }; + return params; + } + function optionalKeys(shape) { + return Object.keys(shape).filter((k) => { + return shape[k]._zod.optin === "optional" && shape[k]._zod.optout === "optional"; + }); + } + const NUMBER_FORMAT_RANGES = { + safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], + int32: [-2147483648, 2147483647], + uint32: [0, 4294967295], + float32: [-34028234663852886e22, 34028234663852886e22], + float64: [-Number.MAX_VALUE, Number.MAX_VALUE] + }; + function pick(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + if (checks && checks.length > 0) throw new Error(".pick() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const newShape = {}; + for (const key in mask) { + if (!(key in currDef.shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + newShape[key] = currDef.shape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + })); + } + function omit(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + if (checks && checks.length > 0) throw new Error(".omit() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const newShape = { ...schema._zod.def.shape }; + for (const key in mask) { + if (!(key in currDef.shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + delete newShape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + })); + } + function extend(schema, shape) { + if (!isPlainObject(shape)) throw new Error("Invalid input to extend: expected a plain object"); + const checks = schema._zod.def.checks; + if (checks && checks.length > 0) { + const existingShape = schema._zod.def.shape; + for (const key in shape) if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead."); + } + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const _shape = { + ...schema._zod.def.shape, + ...shape + }; + assignProp(this, "shape", _shape); + return _shape; + } })); + } + function safeExtend(schema, shape) { + if (!isPlainObject(shape)) throw new Error("Invalid input to safeExtend: expected a plain object"); + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const _shape = { + ...schema._zod.def.shape, + ...shape + }; + assignProp(this, "shape", _shape); + return _shape; + } })); + } + function merge(a, b) { + if (a._zod.def.checks?.length) throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead."); + return clone(a, mergeDefs(a._zod.def, { + get shape() { + const _shape = { + ...a._zod.def.shape, + ...b._zod.def.shape + }; + assignProp(this, "shape", _shape); + return _shape; + }, + get catchall() { + return b._zod.def.catchall; + }, + checks: b._zod.def.checks ?? [] + })); + } + function partial(Class, schema, mask) { + const checks = schema._zod.def.checks; + if (checks && checks.length > 0) throw new Error(".partial() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) for (const key in mask) { + if (!(key in oldShape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + shape[key] = Class ? new Class({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + } + else for (const key in oldShape) shape[key] = Class ? new Class({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + assignProp(this, "shape", shape); + return shape; + }, + checks: [] + })); + } + function required(Class, schema, mask) { + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) for (const key in mask) { + if (!(key in shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + shape[key] = new Class({ + type: "nonoptional", + innerType: oldShape[key] + }); + } + else for (const key in oldShape) shape[key] = new Class({ + type: "nonoptional", + innerType: oldShape[key] + }); + assignProp(this, "shape", shape); + return shape; + } })); + } + function aborted(x, startIndex = 0) { + if (x.aborted === true) return true; + for (let i = startIndex; i < x.issues.length; i++) if (x.issues[i]?.continue !== true) return true; + return false; + } + function explicitlyAborted(x, startIndex = 0) { + if (x.aborted === true) return true; + for (let i = startIndex; i < x.issues.length; i++) if (x.issues[i]?.continue === false) return true; + return false; + } + function prefixIssues(path, issues) { + return issues.map((iss) => { + var _a; + (_a = iss).path ?? (_a.path = []); + iss.path.unshift(path); + return iss; + }); + } + function unwrapMessage(message) { + return typeof message === "string" ? message : message?.message; + } + function finalizeIssue(iss, ctx, config) { + const message = iss.message ? iss.message : unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config.customError?.(iss)) ?? unwrapMessage(config.localeError?.(iss)) ?? "Invalid input"; + const { inst: _inst, continue: _continue, input: _input, ...rest } = iss; + rest.path ?? (rest.path = []); + rest.message = message; + if (ctx?.reportInput) rest.input = _input; + return rest; + } + function getLengthableOrigin(input) { + if (Array.isArray(input)) return "array"; + if (typeof input === "string") return "string"; + return "unknown"; + } + function issue(...args) { + const [iss, input, inst] = args; + if (typeof iss === "string") return { + message: iss, + code: "custom", + input, + inst + }; + return { ...iss }; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/errors.js + const initializer$1 = (inst, def) => { + inst.name = "$ZodError"; + Object.defineProperty(inst, "_zod", { + value: inst._zod, + enumerable: false + }); + Object.defineProperty(inst, "issues", { + value: def, + enumerable: false + }); + inst.message = JSON.stringify(def, jsonStringifyReplacer, 2); + Object.defineProperty(inst, "toString", { + value: () => inst.message, + enumerable: false + }); + }; + const $ZodError = $constructor("$ZodError", initializer$1); + const $ZodRealError = $constructor("$ZodError", initializer$1, { Parent: Error }); + function flattenError(error, mapper = (issue) => issue.message) { + const fieldErrors = {}; + const formErrors = []; + for (const sub of error.issues) if (sub.path.length > 0) { + fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || []; + fieldErrors[sub.path[0]].push(mapper(sub)); + } else formErrors.push(mapper(sub)); + return { + formErrors, + fieldErrors + }; + } + function formatError(error, mapper = (issue) => issue.message) { + const fieldErrors = { _errors: [] }; + const processError = (error, path = []) => { + for (const issue of error.issues) if (issue.code === "invalid_union" && issue.errors.length) issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path])); + else if (issue.code === "invalid_key") processError({ issues: issue.issues }, [...path, ...issue.path]); + else if (issue.code === "invalid_element") processError({ issues: issue.issues }, [...path, ...issue.path]); + else { + const fullpath = [...path, ...issue.path]; + if (fullpath.length === 0) fieldErrors._errors.push(mapper(issue)); + else { + let curr = fieldErrors; + let i = 0; + while (i < fullpath.length) { + const el = fullpath[i]; + if (!(i === fullpath.length - 1)) curr[el] = curr[el] || { _errors: [] }; + else { + curr[el] = curr[el] || { _errors: [] }; + curr[el]._errors.push(mapper(issue)); + } + curr = curr[el]; + i++; + } + } + } + }; + processError(error); + return fieldErrors; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/parse.js + const _parse = (_Err) => (schema, value, _ctx, _params) => { + const ctx = _ctx ? { + ..._ctx, + async: false + } : { async: false }; + const result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) throw new $ZodAsyncError(); + if (result.issues.length) { + const e = new ((_params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, _params?.callee); + throw e; + } + return result.value; + }; + const _parseAsync = (_Err) => async (schema, value, _ctx, params) => { + const ctx = _ctx ? { + ..._ctx, + async: true + } : { async: true }; + let result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) result = await result; + if (result.issues.length) { + const e = new ((params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, params?.callee); + throw e; + } + return result.value; + }; + const _safeParse = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + async: false + } : { async: false }; + const result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) throw new $ZodAsyncError(); + return result.issues.length ? { + success: false, + error: new (_Err ?? $ZodError)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { + success: true, + data: result.value + }; + }; + const safeParse$1 = /* @__PURE__*/ _safeParse($ZodRealError); + const _safeParseAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + async: true + } : { async: true }; + let result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) result = await result; + return result.issues.length ? { + success: false, + error: new _Err(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { + success: true, + data: result.value + }; + }; + const safeParseAsync$1 = /* @__PURE__*/ _safeParseAsync($ZodRealError); + const _encode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _parse(_Err)(schema, value, ctx); + }; + const _decode = (_Err) => (schema, value, _ctx) => { + return _parse(_Err)(schema, value, _ctx); + }; + const _encodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _parseAsync(_Err)(schema, value, ctx); + }; + const _decodeAsync = (_Err) => async (schema, value, _ctx) => { + return _parseAsync(_Err)(schema, value, _ctx); + }; + const _safeEncode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _safeParse(_Err)(schema, value, ctx); + }; + const _safeDecode = (_Err) => (schema, value, _ctx) => { + return _safeParse(_Err)(schema, value, _ctx); + }; + const _safeEncodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _safeParseAsync(_Err)(schema, value, ctx); + }; + const _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => { + return _safeParseAsync(_Err)(schema, value, _ctx); + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/regexes.js + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link cuid2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const cuid = /^[cC][0-9a-z]{6,}$/; + const cuid2 = /^[0-9a-z]+$/; + const ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/; + const xid = /^[0-9a-vA-V]{20}$/; + const ksuid = /^[A-Za-z0-9]{27}$/; + const nanoid = /^[a-zA-Z0-9_-]{21}$/; + /** ISO 8601-1 duration regex. Does not support the 8601-2 extensions like negative durations or fractional/negative components. */ + const duration$1 = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/; + /** A regex for any UUID-like identifier: 8-4-4-4-12 hex pattern */ + const guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/; + /** Returns a regex for validating an RFC 9562/4122 UUID. + * + * @param version Optionally specify a version 1-8. If no version is specified, all versions are supported. */ + const uuid = (version) => { + if (!version) return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/; + return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`); + }; + /** Practical email validation */ + const email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/; + const _emoji$1 = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; + function emoji() { + return new RegExp(_emoji$1, "u"); + } + const ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; + const ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/; + const cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/; + const cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; + const base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/; + const base64url = /^[A-Za-z0-9_-]*$/; + const httpProtocol = /^https?$/; + const e164 = /^\+[1-9]\d{6,14}$/; + const dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`; + const date$1 = /*@__PURE__*/ new RegExp(`^${dateSource}$`); + function timeSource(args) { + const hhmm = `(?:[01]\\d|2[0-3]):[0-5]\\d`; + return typeof args.precision === "number" ? args.precision === -1 ? `${hhmm}` : args.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args.precision}}` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`; + } + function time$1(args) { + return new RegExp(`^${timeSource(args)}$`); + } + function datetime$1(args) { + const time = timeSource({ precision: args.precision }); + const opts = ["Z"]; + if (args.local) opts.push(""); + if (args.offset) opts.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`); + const timeRegex = `${time}(?:${opts.join("|")})`; + return new RegExp(`^${dateSource}T(?:${timeRegex})$`); + } + const string$1 = (params) => { + const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`; + return new RegExp(`^${regex}$`); + }; + const integer = /^-?\d+$/; + const number$1 = /^-?\d+(?:\.\d+)?$/; + const boolean$1 = /^(?:true|false)$/i; + const _undefined$2 = /^undefined$/i; + const lowercase = /^[^A-Z]*$/; + const uppercase = /^[^a-z]*$/; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/checks.js + const $ZodCheck = /*@__PURE__*/ $constructor("$ZodCheck", (inst, def) => { + var _a; + inst._zod ?? (inst._zod = {}); + inst._zod.def = def; + (_a = inst._zod).onattach ?? (_a.onattach = []); + }); + const numericOriginMap = { + number: "number", + bigint: "bigint", + object: "date" + }; + const $ZodCheckLessThan = /*@__PURE__*/ $constructor("$ZodCheckLessThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + const curr = (def.inclusive ? bag.maximum : bag.exclusiveMaximum) ?? Number.POSITIVE_INFINITY; + if (def.value < curr) if (def.inclusive) bag.maximum = def.value; + else bag.exclusiveMaximum = def.value; + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value <= def.value : payload.value < def.value) return; + payload.issues.push({ + origin, + code: "too_big", + maximum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckGreaterThan = /*@__PURE__*/ $constructor("$ZodCheckGreaterThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY; + if (def.value > curr) if (def.inclusive) bag.minimum = def.value; + else bag.exclusiveMinimum = def.value; + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value >= def.value : payload.value > def.value) return; + payload.issues.push({ + origin, + code: "too_small", + minimum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMultipleOf = /*@__PURE__*/ $constructor("$ZodCheckMultipleOf", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst) => { + var _a; + (_a = inst._zod.bag).multipleOf ?? (_a.multipleOf = def.value); + }); + inst._zod.check = (payload) => { + if (typeof payload.value !== typeof def.value) throw new Error("Cannot mix number and bigint in multiple_of check."); + if (typeof payload.value === "bigint" ? payload.value % def.value === BigInt(0) : floatSafeRemainder(payload.value, def.value) === 0) return; + payload.issues.push({ + origin: typeof payload.value, + code: "not_multiple_of", + divisor: def.value, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckNumberFormat = /*@__PURE__*/ $constructor("$ZodCheckNumberFormat", (inst, def) => { + $ZodCheck.init(inst, def); + def.format = def.format || "float64"; + const isInt = def.format?.includes("int"); + const origin = isInt ? "int" : "number"; + const [minimum, maximum] = NUMBER_FORMAT_RANGES[def.format]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.format = def.format; + bag.minimum = minimum; + bag.maximum = maximum; + if (isInt) bag.pattern = integer; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (isInt) { + if (!Number.isInteger(input)) { + payload.issues.push({ + expected: origin, + format: def.format, + code: "invalid_type", + continue: false, + input, + inst + }); + return; + } + if (!Number.isSafeInteger(input)) { + if (input > 0) payload.issues.push({ + input, + code: "too_big", + maximum: Number.MAX_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + else payload.issues.push({ + input, + code: "too_small", + minimum: Number.MIN_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + return; + } + } + if (input < minimum) payload.issues.push({ + origin: "number", + input, + code: "too_small", + minimum, + inclusive: true, + inst, + continue: !def.abort + }); + if (input > maximum) payload.issues.push({ + origin: "number", + input, + code: "too_big", + maximum, + inclusive: true, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMaxLength = /*@__PURE__*/ $constructor("$ZodCheckMaxLength", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const curr = inst._zod.bag.maximum ?? Number.POSITIVE_INFINITY; + if (def.maximum < curr) inst._zod.bag.maximum = def.maximum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (input.length <= def.maximum) return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_big", + maximum: def.maximum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMinLength = /*@__PURE__*/ $constructor("$ZodCheckMinLength", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const curr = inst._zod.bag.minimum ?? Number.NEGATIVE_INFINITY; + if (def.minimum > curr) inst._zod.bag.minimum = def.minimum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (input.length >= def.minimum) return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_small", + minimum: def.minimum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckLengthEquals = /*@__PURE__*/ $constructor("$ZodCheckLengthEquals", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.minimum = def.length; + bag.maximum = def.length; + bag.length = def.length; + }); + inst._zod.check = (payload) => { + const input = payload.value; + const length = input.length; + if (length === def.length) return; + const origin = getLengthableOrigin(input); + const tooBig = length > def.length; + payload.issues.push({ + origin, + ...tooBig ? { + code: "too_big", + maximum: def.length + } : { + code: "too_small", + minimum: def.length + }, + inclusive: true, + exact: true, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckStringFormat = /*@__PURE__*/ $constructor("$ZodCheckStringFormat", (inst, def) => { + var _a, _b; + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.format = def.format; + if (def.pattern) { + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(def.pattern); + } + }); + if (def.pattern) (_a = inst._zod).check ?? (_a.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: def.format, + input: payload.value, + ...def.pattern ? { pattern: def.pattern.toString() } : {}, + inst, + continue: !def.abort + }); + }); + else (_b = inst._zod).check ?? (_b.check = () => {}); + }); + const $ZodCheckRegex = /*@__PURE__*/ $constructor("$ZodCheckRegex", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + inst._zod.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "regex", + input: payload.value, + pattern: def.pattern.toString(), + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckLowerCase = /*@__PURE__*/ $constructor("$ZodCheckLowerCase", (inst, def) => { + def.pattern ?? (def.pattern = lowercase); + $ZodCheckStringFormat.init(inst, def); + }); + const $ZodCheckUpperCase = /*@__PURE__*/ $constructor("$ZodCheckUpperCase", (inst, def) => { + def.pattern ?? (def.pattern = uppercase); + $ZodCheckStringFormat.init(inst, def); + }); + const $ZodCheckIncludes = /*@__PURE__*/ $constructor("$ZodCheckIncludes", (inst, def) => { + $ZodCheck.init(inst, def); + const escapedRegex = escapeRegex(def.includes); + const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex); + def.pattern = pattern; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.includes(def.includes, def.position)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "includes", + includes: def.includes, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckStartsWith = /*@__PURE__*/ $constructor("$ZodCheckStartsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`^${escapeRegex(def.prefix)}.*`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.startsWith(def.prefix)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "starts_with", + prefix: def.prefix, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckEndsWith = /*@__PURE__*/ $constructor("$ZodCheckEndsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`.*${escapeRegex(def.suffix)}$`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.endsWith(def.suffix)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "ends_with", + suffix: def.suffix, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckOverwrite = /*@__PURE__*/ $constructor("$ZodCheckOverwrite", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.check = (payload) => { + payload.value = def.tx(payload.value); + }; + }); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/doc.js + var Doc = class { + constructor(args = []) { + this.content = []; + this.indent = 0; + if (this) this.args = args; + } + indented(fn) { + this.indent += 1; + fn(this); + this.indent -= 1; + } + write(arg) { + if (typeof arg === "function") { + arg(this, { execution: "sync" }); + arg(this, { execution: "async" }); + return; + } + const lines = arg.split("\n").filter((x) => x); + const minIndent = Math.min(...lines.map((x) => x.length - x.trimStart().length)); + const dedented = lines.map((x) => x.slice(minIndent)).map((x) => " ".repeat(this.indent * 2) + x); + for (const line of dedented) this.content.push(line); + } + compile() { + const F = Function; + const args = this?.args; + const lines = [...(this?.content ?? [``]).map((x) => ` ${x}`)]; + return new F(...args, lines.join("\n")); + } + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.js + const version = { + major: 4, + minor: 4, + patch: 3 + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/schemas.js + const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => { + var _a; + inst ?? (inst = {}); + inst._zod.def = def; + inst._zod.bag = inst._zod.bag || {}; + inst._zod.version = version; + const checks = [...inst._zod.def.checks ?? []]; + if (inst._zod.traits.has("$ZodCheck")) checks.unshift(inst); + for (const ch of checks) for (const fn of ch._zod.onattach) fn(inst); + if (checks.length === 0) { + (_a = inst._zod).deferred ?? (_a.deferred = []); + inst._zod.deferred?.push(() => { + inst._zod.run = inst._zod.parse; + }); + } else { + const runChecks = (payload, checks, ctx) => { + let isAborted = aborted(payload); + let asyncResult; + for (const ch of checks) { + if (ch._zod.def.when) { + if (explicitlyAborted(payload)) continue; + if (!ch._zod.def.when(payload)) continue; + } else if (isAborted) continue; + const currLen = payload.issues.length; + const _ = ch._zod.check(payload); + if (_ instanceof Promise && ctx?.async === false) throw new $ZodAsyncError(); + if (asyncResult || _ instanceof Promise) asyncResult = (asyncResult ?? Promise.resolve()).then(async () => { + await _; + if (payload.issues.length === currLen) return; + if (!isAborted) isAborted = aborted(payload, currLen); + }); + else { + if (payload.issues.length === currLen) continue; + if (!isAborted) isAborted = aborted(payload, currLen); + } + } + if (asyncResult) return asyncResult.then(() => { + return payload; + }); + return payload; + }; + const handleCanaryResult = (canary, payload, ctx) => { + if (aborted(canary)) { + canary.aborted = true; + return canary; + } + const checkResult = runChecks(payload, checks, ctx); + if (checkResult instanceof Promise) { + if (ctx.async === false) throw new $ZodAsyncError(); + return checkResult.then((checkResult) => inst._zod.parse(checkResult, ctx)); + } + return inst._zod.parse(checkResult, ctx); + }; + inst._zod.run = (payload, ctx) => { + if (ctx.skipChecks) return inst._zod.parse(payload, ctx); + if (ctx.direction === "backward") { + const canary = inst._zod.parse({ + value: payload.value, + issues: [] + }, { + ...ctx, + skipChecks: true + }); + if (canary instanceof Promise) return canary.then((canary) => { + return handleCanaryResult(canary, payload, ctx); + }); + return handleCanaryResult(canary, payload, ctx); + } + const result = inst._zod.parse(payload, ctx); + if (result instanceof Promise) { + if (ctx.async === false) throw new $ZodAsyncError(); + return result.then((result) => runChecks(result, checks, ctx)); + } + return runChecks(result, checks, ctx); + }; + } + defineLazy(inst, "~standard", () => ({ + validate: (value) => { + try { + const r = safeParse$1(inst, value); + return r.success ? { value: r.data } : { issues: r.error?.issues }; + } catch (_) { + return safeParseAsync$1(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues }); + } + }, + vendor: "zod", + version: 1 + })); + }); + const $ZodString = /*@__PURE__*/ $constructor("$ZodString", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = [...inst?._zod.bag?.patterns ?? []].pop() ?? string$1(inst._zod.bag); + inst._zod.parse = (payload, _) => { + if (def.coerce) try { + payload.value = String(payload.value); + } catch (_) {} + if (typeof payload.value === "string") return payload; + payload.issues.push({ + expected: "string", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; + }); + const $ZodStringFormat = /*@__PURE__*/ $constructor("$ZodStringFormat", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + $ZodString.init(inst, def); + }); + const $ZodGUID = /*@__PURE__*/ $constructor("$ZodGUID", (inst, def) => { + def.pattern ?? (def.pattern = guid); + $ZodStringFormat.init(inst, def); + }); + const $ZodUUID = /*@__PURE__*/ $constructor("$ZodUUID", (inst, def) => { + if (def.version) { + const v = { + v1: 1, + v2: 2, + v3: 3, + v4: 4, + v5: 5, + v6: 6, + v7: 7, + v8: 8 + }[def.version]; + if (v === void 0) throw new Error(`Invalid UUID version: "${def.version}"`); + def.pattern ?? (def.pattern = uuid(v)); + } else def.pattern ?? (def.pattern = uuid()); + $ZodStringFormat.init(inst, def); + }); + const $ZodEmail = /*@__PURE__*/ $constructor("$ZodEmail", (inst, def) => { + def.pattern ?? (def.pattern = email); + $ZodStringFormat.init(inst, def); + }); + const $ZodURL = /*@__PURE__*/ $constructor("$ZodURL", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + try { + const trimmed = payload.value.trim(); + if (!def.normalize && def.protocol?.source === httpProtocol.source) { + if (!/^https?:\/\//i.test(trimmed)) { + payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid URL format", + input: payload.value, + inst, + continue: !def.abort + }); + return; + } + } + const url = new URL(trimmed); + if (def.hostname) { + def.hostname.lastIndex = 0; + if (!def.hostname.test(url.hostname)) payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid hostname", + pattern: def.hostname.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + if (def.protocol) { + def.protocol.lastIndex = 0; + if (!def.protocol.test(url.protocol.endsWith(":") ? url.protocol.slice(0, -1) : url.protocol)) payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid protocol", + pattern: def.protocol.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + if (def.normalize) payload.value = url.href; + else payload.value = trimmed; + return; + } catch (_) { + payload.issues.push({ + code: "invalid_format", + format: "url", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + const $ZodEmoji = /*@__PURE__*/ $constructor("$ZodEmoji", (inst, def) => { + def.pattern ?? (def.pattern = emoji()); + $ZodStringFormat.init(inst, def); + }); + const $ZodNanoID = /*@__PURE__*/ $constructor("$ZodNanoID", (inst, def) => { + def.pattern ?? (def.pattern = nanoid); + $ZodStringFormat.init(inst, def); + }); + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link $ZodCUID2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const $ZodCUID = /*@__PURE__*/ $constructor("$ZodCUID", (inst, def) => { + def.pattern ?? (def.pattern = cuid); + $ZodStringFormat.init(inst, def); + }); + const $ZodCUID2 = /*@__PURE__*/ $constructor("$ZodCUID2", (inst, def) => { + def.pattern ?? (def.pattern = cuid2); + $ZodStringFormat.init(inst, def); + }); + const $ZodULID = /*@__PURE__*/ $constructor("$ZodULID", (inst, def) => { + def.pattern ?? (def.pattern = ulid); + $ZodStringFormat.init(inst, def); + }); + const $ZodXID = /*@__PURE__*/ $constructor("$ZodXID", (inst, def) => { + def.pattern ?? (def.pattern = xid); + $ZodStringFormat.init(inst, def); + }); + const $ZodKSUID = /*@__PURE__*/ $constructor("$ZodKSUID", (inst, def) => { + def.pattern ?? (def.pattern = ksuid); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODateTime = /*@__PURE__*/ $constructor("$ZodISODateTime", (inst, def) => { + def.pattern ?? (def.pattern = datetime$1(def)); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODate = /*@__PURE__*/ $constructor("$ZodISODate", (inst, def) => { + def.pattern ?? (def.pattern = date$1); + $ZodStringFormat.init(inst, def); + }); + const $ZodISOTime = /*@__PURE__*/ $constructor("$ZodISOTime", (inst, def) => { + def.pattern ?? (def.pattern = time$1(def)); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODuration = /*@__PURE__*/ $constructor("$ZodISODuration", (inst, def) => { + def.pattern ?? (def.pattern = duration$1); + $ZodStringFormat.init(inst, def); + }); + const $ZodIPv4 = /*@__PURE__*/ $constructor("$ZodIPv4", (inst, def) => { + def.pattern ?? (def.pattern = ipv4); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv4`; + }); + const $ZodIPv6 = /*@__PURE__*/ $constructor("$ZodIPv6", (inst, def) => { + def.pattern ?? (def.pattern = ipv6); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv6`; + inst._zod.check = (payload) => { + try { + new URL(`http://[${payload.value}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "ipv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + const $ZodCIDRv4 = /*@__PURE__*/ $constructor("$ZodCIDRv4", (inst, def) => { + def.pattern ?? (def.pattern = cidrv4); + $ZodStringFormat.init(inst, def); + }); + const $ZodCIDRv6 = /*@__PURE__*/ $constructor("$ZodCIDRv6", (inst, def) => { + def.pattern ?? (def.pattern = cidrv6); + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + const parts = payload.value.split("/"); + try { + if (parts.length !== 2) throw new Error(); + const [address, prefix] = parts; + if (!prefix) throw new Error(); + const prefixNum = Number(prefix); + if (`${prefixNum}` !== prefix) throw new Error(); + if (prefixNum < 0 || prefixNum > 128) throw new Error(); + new URL(`http://[${address}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "cidrv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + function isValidBase64(data) { + if (data === "") return true; + if (/\s/.test(data)) return false; + if (data.length % 4 !== 0) return false; + try { + atob(data); + return true; + } catch { + return false; + } + } + const $ZodBase64 = /*@__PURE__*/ $constructor("$ZodBase64", (inst, def) => { + def.pattern ?? (def.pattern = base64); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64"; + inst._zod.check = (payload) => { + if (isValidBase64(payload.value)) return; + payload.issues.push({ + code: "invalid_format", + format: "base64", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + function isValidBase64URL(data) { + if (!base64url.test(data)) return false; + const base64 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/"); + return isValidBase64(base64.padEnd(Math.ceil(base64.length / 4) * 4, "=")); + } + const $ZodBase64URL = /*@__PURE__*/ $constructor("$ZodBase64URL", (inst, def) => { + def.pattern ?? (def.pattern = base64url); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64url"; + inst._zod.check = (payload) => { + if (isValidBase64URL(payload.value)) return; + payload.issues.push({ + code: "invalid_format", + format: "base64url", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodE164 = /*@__PURE__*/ $constructor("$ZodE164", (inst, def) => { + def.pattern ?? (def.pattern = e164); + $ZodStringFormat.init(inst, def); + }); + function isValidJWT(token, algorithm = null) { + try { + const tokensParts = token.split("."); + if (tokensParts.length !== 3) return false; + const [header] = tokensParts; + if (!header) return false; + const parsedHeader = JSON.parse(atob(header)); + if ("typ" in parsedHeader && parsedHeader?.typ !== "JWT") return false; + if (!parsedHeader.alg) return false; + if (algorithm && (!("alg" in parsedHeader) || parsedHeader.alg !== algorithm)) return false; + return true; + } catch { + return false; + } + } + const $ZodJWT = /*@__PURE__*/ $constructor("$ZodJWT", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + if (isValidJWT(payload.value, def.alg)) return; + payload.issues.push({ + code: "invalid_format", + format: "jwt", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodNumber = /*@__PURE__*/ $constructor("$ZodNumber", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = inst._zod.bag.pattern ?? number$1; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) try { + payload.value = Number(payload.value); + } catch (_) {} + const input = payload.value; + if (typeof input === "number" && !Number.isNaN(input) && Number.isFinite(input)) return payload; + const received = typeof input === "number" ? Number.isNaN(input) ? "NaN" : !Number.isFinite(input) ? "Infinity" : void 0 : void 0; + payload.issues.push({ + expected: "number", + code: "invalid_type", + input, + inst, + ...received ? { received } : {} + }); + return payload; + }; + }); + const $ZodNumberFormat = /*@__PURE__*/ $constructor("$ZodNumberFormat", (inst, def) => { + $ZodCheckNumberFormat.init(inst, def); + $ZodNumber.init(inst, def); + }); + const $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = boolean$1; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) try { + payload.value = Boolean(payload.value); + } catch (_) {} + const input = payload.value; + if (typeof input === "boolean") return payload; + payload.issues.push({ + expected: "boolean", + code: "invalid_type", + input, + inst + }); + return payload; + }; + }); + const $ZodUndefined = /*@__PURE__*/ $constructor("$ZodUndefined", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = _undefined$2; + inst._zod.values = new Set([void 0]); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (typeof input === "undefined") return payload; + payload.issues.push({ + expected: "undefined", + code: "invalid_type", + input, + inst + }); + return payload; + }; + }); + const $ZodUnknown = /*@__PURE__*/ $constructor("$ZodUnknown", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload) => payload; + }); + const $ZodNever = /*@__PURE__*/ $constructor("$ZodNever", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, _ctx) => { + payload.issues.push({ + expected: "never", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; + }); + function handleArrayResult(result, final, index) { + if (result.issues.length) final.issues.push(...prefixIssues(index, result.issues)); + final.value[index] = result.value; + } + const $ZodArray = /*@__PURE__*/ $constructor("$ZodArray", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!Array.isArray(input)) { + payload.issues.push({ + expected: "array", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = Array(input.length); + const proms = []; + for (let i = 0; i < input.length; i++) { + const item = input[i]; + const result = def.element._zod.run({ + value: item, + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => handleArrayResult(result, payload, i))); + else handleArrayResult(result, payload, i); + } + if (proms.length) return Promise.all(proms).then(() => payload); + return payload; + }; + }); + function handlePropertyResult(result, final, key, input, isOptionalIn, isOptionalOut) { + const isPresent = key in input; + if (result.issues.length) { + if (isOptionalIn && isOptionalOut && !isPresent) return; + final.issues.push(...prefixIssues(key, result.issues)); + } + if (!isPresent && !isOptionalIn) { + if (!result.issues.length) final.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: void 0, + path: [key] + }); + return; + } + if (result.value === void 0) { + if (isPresent) final.value[key] = void 0; + } else final.value[key] = result.value; + } + function normalizeDef(def) { + const keys = Object.keys(def.shape); + for (const k of keys) if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) throw new Error(`Invalid element at key "${k}": expected a Zod schema`); + const okeys = optionalKeys(def.shape); + return { + ...def, + keys, + keySet: new Set(keys), + numKeys: keys.length, + optionalKeys: new Set(okeys) + }; + } + function handleCatchall(proms, input, payload, ctx, def, inst) { + const unrecognized = []; + const keySet = def.keySet; + const _catchall = def.catchall._zod; + const t = _catchall.def.type; + const isOptionalIn = _catchall.optin === "optional"; + const isOptionalOut = _catchall.optout === "optional"; + for (const key in input) { + if (key === "__proto__") continue; + if (keySet.has(key)) continue; + if (t === "never") { + unrecognized.push(key); + continue; + } + const r = _catchall.run({ + value: input[key], + issues: [] + }, ctx); + if (r instanceof Promise) proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut))); + else handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + if (unrecognized.length) payload.issues.push({ + code: "unrecognized_keys", + keys: unrecognized, + input, + inst + }); + if (!proms.length) return payload; + return Promise.all(proms).then(() => { + return payload; + }); + } + const $ZodObject = /*@__PURE__*/ $constructor("$ZodObject", (inst, def) => { + $ZodType.init(inst, def); + if (!Object.getOwnPropertyDescriptor(def, "shape")?.get) { + const sh = def.shape; + Object.defineProperty(def, "shape", { get: () => { + const newSh = { ...sh }; + Object.defineProperty(def, "shape", { value: newSh }); + return newSh; + } }); + } + const _normalized = cached(() => normalizeDef(def)); + defineLazy(inst._zod, "propValues", () => { + const shape = def.shape; + const propValues = {}; + for (const key in shape) { + const field = shape[key]._zod; + if (field.values) { + propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set()); + for (const v of field.values) propValues[key].add(v); + } + } + return propValues; + }); + const isObject$1 = isObject; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject$1(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = {}; + const proms = []; + const shape = value.shape; + for (const key of value.keys) { + const el = shape[key]; + const isOptionalIn = el._zod.optin === "optional"; + const isOptionalOut = el._zod.optout === "optional"; + const r = el._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (r instanceof Promise) proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut))); + else handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + if (!catchall) return proms.length ? Promise.all(proms).then(() => payload) : payload; + return handleCatchall(proms, input, payload, ctx, _normalized.value, inst); + }; + }); + const $ZodObjectJIT = /*@__PURE__*/ $constructor("$ZodObjectJIT", (inst, def) => { + $ZodObject.init(inst, def); + const superParse = inst._zod.parse; + const _normalized = cached(() => normalizeDef(def)); + const generateFastpass = (shape) => { + const doc = new Doc([ + "shape", + "payload", + "ctx" + ]); + const normalized = _normalized.value; + const parseStr = (key) => { + const k = esc(key); + return `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`; + }; + doc.write(`const input = payload.value;`); + const ids = Object.create(null); + let counter = 0; + for (const key of normalized.keys) ids[key] = `key_${counter++}`; + doc.write(`const newResult = {};`); + for (const key of normalized.keys) { + const id = ids[key]; + const k = esc(key); + const schema = shape[key]; + const isOptionalIn = schema?._zod?.optin === "optional"; + const isOptionalOut = schema?._zod?.optout === "optional"; + doc.write(`const ${id} = ${parseStr(key)};`); + if (isOptionalIn && isOptionalOut) doc.write(` + if (${id}.issues.length) { + if (${k} in input) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + else if (!isOptionalIn) doc.write(` + const ${id}_present = ${k} in input; + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + if (!${id}_present && !${id}.issues.length) { + payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: undefined, + path: [${k}] + }); + } + + if (${id}_present) { + if (${id}.value === undefined) { + newResult[${k}] = undefined; + } else { + newResult[${k}] = ${id}.value; + } + } + + `); + else doc.write(` + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + } + doc.write(`payload.value = newResult;`); + doc.write(`return payload;`); + const fn = doc.compile(); + return (payload, ctx) => fn(shape, payload, ctx); + }; + let fastpass; + const isObject$2 = isObject; + const jit = !globalConfig.jitless; + const fastEnabled = jit && allowsEval.value; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject$2(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + if (jit && fastEnabled && ctx?.async === false && ctx.jitless !== true) { + if (!fastpass) fastpass = generateFastpass(def.shape); + payload = fastpass(payload, ctx); + if (!catchall) return payload; + return handleCatchall([], input, payload, ctx, value, inst); + } + return superParse(payload, ctx); + }; + }); + function handleUnionResults(results, final, inst, ctx) { + for (const result of results) if (result.issues.length === 0) { + final.value = result.value; + return final; + } + const nonaborted = results.filter((r) => !aborted(r)); + if (nonaborted.length === 1) { + final.value = nonaborted[0].value; + return nonaborted[0]; + } + final.issues.push({ + code: "invalid_union", + input: final.value, + inst, + errors: results.map((result) => result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + }); + return final; + } + const $ZodUnion = /*@__PURE__*/ $constructor("$ZodUnion", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.options.some((o) => o._zod.optin === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "optout", () => def.options.some((o) => o._zod.optout === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "values", () => { + if (def.options.every((o) => o._zod.values)) return new Set(def.options.flatMap((option) => Array.from(option._zod.values))); + }); + defineLazy(inst._zod, "pattern", () => { + if (def.options.every((o) => o._zod.pattern)) { + const patterns = def.options.map((o) => o._zod.pattern); + return new RegExp(`^(${patterns.map((p) => cleanRegex(p.source)).join("|")})$`); + } + }); + const first = def.options.length === 1 ? def.options[0]._zod.run : null; + inst._zod.parse = (payload, ctx) => { + if (first) return first(payload, ctx); + let async = false; + const results = []; + for (const option of def.options) { + const result = option._zod.run({ + value: payload.value, + issues: [] + }, ctx); + if (result instanceof Promise) { + results.push(result); + async = true; + } else { + if (result.issues.length === 0) return result; + results.push(result); + } + } + if (!async) return handleUnionResults(results, payload, inst, ctx); + return Promise.all(results).then((results) => { + return handleUnionResults(results, payload, inst, ctx); + }); + }; + }); + const $ZodIntersection = /*@__PURE__*/ $constructor("$ZodIntersection", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + const left = def.left._zod.run({ + value: input, + issues: [] + }, ctx); + const right = def.right._zod.run({ + value: input, + issues: [] + }, ctx); + if (left instanceof Promise || right instanceof Promise) return Promise.all([left, right]).then(([left, right]) => { + return handleIntersectionResults(payload, left, right); + }); + return handleIntersectionResults(payload, left, right); + }; + }); + function mergeValues(a, b) { + if (a === b) return { + valid: true, + data: a + }; + if (a instanceof Date && b instanceof Date && +a === +b) return { + valid: true, + data: a + }; + if (isPlainObject(a) && isPlainObject(b)) { + const bKeys = Object.keys(b); + const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1); + const newObj = { + ...a, + ...b + }; + for (const key of sharedKeys) { + const sharedValue = mergeValues(a[key], b[key]); + if (!sharedValue.valid) return { + valid: false, + mergeErrorPath: [key, ...sharedValue.mergeErrorPath] + }; + newObj[key] = sharedValue.data; + } + return { + valid: true, + data: newObj + }; + } + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) return { + valid: false, + mergeErrorPath: [] + }; + const newArray = []; + for (let index = 0; index < a.length; index++) { + const itemA = a[index]; + const itemB = b[index]; + const sharedValue = mergeValues(itemA, itemB); + if (!sharedValue.valid) return { + valid: false, + mergeErrorPath: [index, ...sharedValue.mergeErrorPath] + }; + newArray.push(sharedValue.data); + } + return { + valid: true, + data: newArray + }; + } + return { + valid: false, + mergeErrorPath: [] + }; + } + function handleIntersectionResults(result, left, right) { + const unrecKeys = /* @__PURE__ */ new Map(); + let unrecIssue; + for (const iss of left.issues) if (iss.code === "unrecognized_keys") { + unrecIssue ?? (unrecIssue = iss); + for (const k of iss.keys) { + if (!unrecKeys.has(k)) unrecKeys.set(k, {}); + unrecKeys.get(k).l = true; + } + } else result.issues.push(iss); + for (const iss of right.issues) if (iss.code === "unrecognized_keys") for (const k of iss.keys) { + if (!unrecKeys.has(k)) unrecKeys.set(k, {}); + unrecKeys.get(k).r = true; + } + else result.issues.push(iss); + const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k); + if (bothKeys.length && unrecIssue) result.issues.push({ + ...unrecIssue, + keys: bothKeys + }); + if (aborted(result)) return result; + const merged = mergeValues(left.value, right.value); + if (!merged.valid) throw new Error(`Unmergable intersection. Error path: ${JSON.stringify(merged.mergeErrorPath)}`); + result.value = merged.data; + return result; + } + const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!isPlainObject(input)) { + payload.issues.push({ + expected: "record", + code: "invalid_type", + input, + inst + }); + return payload; + } + const proms = []; + const values = def.keyType._zod.values; + if (values) { + payload.value = {}; + const recordKeys = /* @__PURE__ */ new Set(); + for (const key of values) if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") { + recordKeys.add(typeof key === "number" ? key.toString() : key); + const keyResult = def.keyType._zod.run({ + value: key, + issues: [] + }, ctx); + if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (keyResult.issues.length) { + payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + continue; + } + const outKey = keyResult.value; + const result = def.valueType._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[outKey] = result.value; + })); + else { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[outKey] = result.value; + } + } + let unrecognized; + for (const key in input) if (!recordKeys.has(key)) { + unrecognized = unrecognized ?? []; + unrecognized.push(key); + } + if (unrecognized && unrecognized.length > 0) payload.issues.push({ + code: "unrecognized_keys", + input, + inst, + keys: unrecognized + }); + } else { + payload.value = {}; + for (const key of Reflect.ownKeys(input)) { + if (key === "__proto__") continue; + if (!Object.prototype.propertyIsEnumerable.call(input, key)) continue; + let keyResult = def.keyType._zod.run({ + value: key, + issues: [] + }, ctx); + if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (typeof key === "string" && number$1.test(key) && keyResult.issues.length) { + const retryResult = def.keyType._zod.run({ + value: Number(key), + issues: [] + }, ctx); + if (retryResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (retryResult.issues.length === 0) keyResult = retryResult; + } + if (keyResult.issues.length) { + if (def.mode === "loose") payload.value[key] = input[key]; + else payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + continue; + } + const result = def.valueType._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[keyResult.value] = result.value; + })); + else { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[keyResult.value] = result.value; + } + } + } + if (proms.length) return Promise.all(proms).then(() => payload); + return payload; + }; + }); + const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => { + $ZodType.init(inst, def); + const values = getEnumValues(def.entries); + const valuesSet = new Set(values); + inst._zod.values = valuesSet; + inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (valuesSet.has(input)) return payload; + payload.issues.push({ + code: "invalid_value", + values, + input, + inst + }); + return payload; + }; + }); + const $ZodLiteral = /*@__PURE__*/ $constructor("$ZodLiteral", (inst, def) => { + $ZodType.init(inst, def); + if (def.values.length === 0) throw new Error("Cannot create literal schema with no valid values"); + const values = new Set(def.values); + inst._zod.values = values; + inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (values.has(input)) return payload; + payload.issues.push({ + code: "invalid_value", + values: def.values, + input, + inst + }); + return payload; + }; + }); + const $ZodTransform = /*@__PURE__*/ $constructor("$ZodTransform", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") throw new $ZodEncodeError(inst.constructor.name); + const _out = def.transform(payload.value, payload); + if (ctx.async) return (_out instanceof Promise ? _out : Promise.resolve(_out)).then((output) => { + payload.value = output; + payload.fallback = true; + return payload; + }); + if (_out instanceof Promise) throw new $ZodAsyncError(); + payload.value = _out; + payload.fallback = true; + return payload; + }; + }); + function handleOptionalResult(result, input) { + if (input === void 0 && (result.issues.length || result.fallback)) return { + issues: [], + value: void 0 + }; + return result; + } + const $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.optout = "optional"; + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? new Set([...def.innerType._zod.values, void 0]) : void 0; + }); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)})?$`) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (def.innerType._zod.optin === "optional") { + const input = payload.value; + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((r) => handleOptionalResult(r, input)); + return handleOptionalResult(result, input); + } + if (payload.value === void 0) return payload; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodExactOptional = /*@__PURE__*/ $constructor("$ZodExactOptional", (inst, def) => { + $ZodOptional.init(inst, def); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "pattern", () => def.innerType._zod.pattern); + inst._zod.parse = (payload, ctx) => { + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodNullable = /*@__PURE__*/ $constructor("$ZodNullable", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.innerType._zod.optin); + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0; + }); + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (payload.value === null) return payload; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodDefault = /*@__PURE__*/ $constructor("$ZodDefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + if (payload.value === void 0) { + payload.value = def.defaultValue; + /** + * $ZodDefault returns the default value immediately in forward direction. + * It doesn't pass the default value into the validator ("prefault"). There's no reason to pass the default value through validation. The validity of the default is enforced by TypeScript statically. Otherwise, it's the responsibility of the user to ensure the default is valid. In the case of pipes with divergent in/out types, you can specify the default on the `in` schema of your ZodPipe to set a "prefault" for the pipe. */ + return payload; + } + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => handleDefaultResult(result, def)); + return handleDefaultResult(result, def); + }; + }); + function handleDefaultResult(payload, def) { + if (payload.value === void 0) payload.value = def.defaultValue; + return payload; + } + const $ZodPrefault = /*@__PURE__*/ $constructor("$ZodPrefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + if (payload.value === void 0) payload.value = def.defaultValue; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodNonOptional = /*@__PURE__*/ $constructor("$ZodNonOptional", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => { + const v = def.innerType._zod.values; + return v ? new Set([...v].filter((x) => x !== void 0)) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => handleNonOptionalResult(result, inst)); + return handleNonOptionalResult(result, inst); + }; + }); + function handleNonOptionalResult(payload, inst) { + if (!payload.issues.length && payload.value === void 0) payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: payload.value, + inst + }); + return payload; + } + const $ZodCatch = /*@__PURE__*/ $constructor("$ZodCatch", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => { + payload.value = result.value; + if (result.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }); + payload.value = result.value; + if (result.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }; + }); + const $ZodPipe = /*@__PURE__*/ $constructor("$ZodPipe", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => def.in._zod.values); + defineLazy(inst._zod, "optin", () => def.in._zod.optin); + defineLazy(inst._zod, "optout", () => def.out._zod.optout); + defineLazy(inst._zod, "propValues", () => def.in._zod.propValues); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + const right = def.out._zod.run(payload, ctx); + if (right instanceof Promise) return right.then((right) => handlePipeResult(right, def.in, ctx)); + return handlePipeResult(right, def.in, ctx); + } + const left = def.in._zod.run(payload, ctx); + if (left instanceof Promise) return left.then((left) => handlePipeResult(left, def.out, ctx)); + return handlePipeResult(left, def.out, ctx); + }; + }); + function handlePipeResult(left, next, ctx) { + if (left.issues.length) { + left.aborted = true; + return left; + } + return next._zod.run({ + value: left.value, + issues: left.issues, + fallback: left.fallback + }, ctx); + } + const $ZodReadonly = /*@__PURE__*/ $constructor("$ZodReadonly", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "propValues", () => def.innerType._zod.propValues); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "optin", () => def.innerType?._zod?.optin); + defineLazy(inst._zod, "optout", () => def.innerType?._zod?.optout); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then(handleReadonlyResult); + return handleReadonlyResult(result); + }; + }); + function handleReadonlyResult(payload) { + payload.value = Object.freeze(payload.value); + return payload; + } + const $ZodLazy = /*@__PURE__*/ $constructor("$ZodLazy", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "innerType", () => { + const d = def; + if (!d._cachedInner) d._cachedInner = def.getter(); + return d._cachedInner; + }); + defineLazy(inst._zod, "pattern", () => inst._zod.innerType?._zod?.pattern); + defineLazy(inst._zod, "propValues", () => inst._zod.innerType?._zod?.propValues); + defineLazy(inst._zod, "optin", () => inst._zod.innerType?._zod?.optin ?? void 0); + defineLazy(inst._zod, "optout", () => inst._zod.innerType?._zod?.optout ?? void 0); + inst._zod.parse = (payload, ctx) => { + return inst._zod.innerType._zod.run(payload, ctx); + }; + }); + const $ZodCustom = /*@__PURE__*/ $constructor("$ZodCustom", (inst, def) => { + $ZodCheck.init(inst, def); + $ZodType.init(inst, def); + inst._zod.parse = (payload, _) => { + return payload; + }; + inst._zod.check = (payload) => { + const input = payload.value; + const r = def.fn(input); + if (r instanceof Promise) return r.then((r) => handleRefineResult(r, payload, input, inst)); + handleRefineResult(r, payload, input, inst); + }; + }); + function handleRefineResult(result, payload, input, inst) { + if (!result) { + const _iss = { + code: "custom", + input, + inst, + path: [...inst._zod.def.path ?? []], + continue: !inst._zod.def.abort + }; + if (inst._zod.def.params) _iss.params = inst._zod.def.params; + payload.issues.push(issue(_iss)); + } + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.js + var _a; + var $ZodRegistry = class { + constructor() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + } + add(schema, ..._meta) { + const meta = _meta[0]; + this._map.set(schema, meta); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.set(meta.id, schema); + return this; + } + clear() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + return this; + } + remove(schema) { + const meta = this._map.get(schema); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.delete(meta.id); + this._map.delete(schema); + return this; + } + get(schema) { + const p = schema._zod.parent; + if (p) { + const pm = { ...this.get(p) ?? {} }; + delete pm.id; + const f = { + ...pm, + ...this._map.get(schema) + }; + return Object.keys(f).length ? f : void 0; + } + return this._map.get(schema); + } + has(schema) { + return this._map.has(schema); + } + }; + function registry() { + return new $ZodRegistry(); + } + (_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry()); + const globalRegistry = globalThis.__zod_globalRegistry; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/api.js + // @__NO_SIDE_EFFECTS__ + function _string(Class, params) { + return new Class({ + type: "string", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _email(Class, params) { + return new Class({ + type: "string", + format: "email", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _guid(Class, params) { + return new Class({ + type: "string", + format: "guid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuid(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv4(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v4", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv6(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v6", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv7(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v7", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _url(Class, params) { + return new Class({ + type: "string", + format: "url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _emoji(Class, params) { + return new Class({ + type: "string", + format: "emoji", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _nanoid(Class, params) { + return new Class({ + type: "string", + format: "nanoid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link _cuid2} instead. + * See https://github.com/paralleldrive/cuid. + */ + // @__NO_SIDE_EFFECTS__ + function _cuid(Class, params) { + return new Class({ + type: "string", + format: "cuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cuid2(Class, params) { + return new Class({ + type: "string", + format: "cuid2", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ulid(Class, params) { + return new Class({ + type: "string", + format: "ulid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _xid(Class, params) { + return new Class({ + type: "string", + format: "xid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ksuid(Class, params) { + return new Class({ + type: "string", + format: "ksuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ipv4(Class, params) { + return new Class({ + type: "string", + format: "ipv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ipv6(Class, params) { + return new Class({ + type: "string", + format: "ipv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cidrv4(Class, params) { + return new Class({ + type: "string", + format: "cidrv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cidrv6(Class, params) { + return new Class({ + type: "string", + format: "cidrv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _base64(Class, params) { + return new Class({ + type: "string", + format: "base64", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _base64url(Class, params) { + return new Class({ + type: "string", + format: "base64url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _e164(Class, params) { + return new Class({ + type: "string", + format: "e164", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _jwt(Class, params) { + return new Class({ + type: "string", + format: "jwt", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDateTime(Class, params) { + return new Class({ + type: "string", + format: "datetime", + check: "string_format", + offset: false, + local: false, + precision: null, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDate(Class, params) { + return new Class({ + type: "string", + format: "date", + check: "string_format", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoTime(Class, params) { + return new Class({ + type: "string", + format: "time", + check: "string_format", + precision: null, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDuration(Class, params) { + return new Class({ + type: "string", + format: "duration", + check: "string_format", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _number(Class, params) { + return new Class({ + type: "number", + checks: [], + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _int(Class, params) { + return new Class({ + type: "number", + check: "number_format", + abort: false, + format: "safeint", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _boolean(Class, params) { + return new Class({ + type: "boolean", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _undefined$1(Class, params) { + return new Class({ + type: "undefined", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _unknown(Class) { + return new Class({ type: "unknown" }); + } + // @__NO_SIDE_EFFECTS__ + function _never(Class, params) { + return new Class({ + type: "never", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _lt(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: false + }); + } + // @__NO_SIDE_EFFECTS__ + function _lte(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: true + }); + } + // @__NO_SIDE_EFFECTS__ + function _gt(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: false + }); + } + // @__NO_SIDE_EFFECTS__ + function _gte(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: true + }); + } + // @__NO_SIDE_EFFECTS__ + function _multipleOf(value, params) { + return new $ZodCheckMultipleOf({ + check: "multiple_of", + ...normalizeParams(params), + value + }); + } + // @__NO_SIDE_EFFECTS__ + function _maxLength(maximum, params) { + return new $ZodCheckMaxLength({ + check: "max_length", + ...normalizeParams(params), + maximum + }); + } + // @__NO_SIDE_EFFECTS__ + function _minLength(minimum, params) { + return new $ZodCheckMinLength({ + check: "min_length", + ...normalizeParams(params), + minimum + }); + } + // @__NO_SIDE_EFFECTS__ + function _length(length, params) { + return new $ZodCheckLengthEquals({ + check: "length_equals", + ...normalizeParams(params), + length + }); + } + // @__NO_SIDE_EFFECTS__ + function _regex(pattern, params) { + return new $ZodCheckRegex({ + check: "string_format", + format: "regex", + ...normalizeParams(params), + pattern + }); + } + // @__NO_SIDE_EFFECTS__ + function _lowercase(params) { + return new $ZodCheckLowerCase({ + check: "string_format", + format: "lowercase", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uppercase(params) { + return new $ZodCheckUpperCase({ + check: "string_format", + format: "uppercase", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _includes(includes, params) { + return new $ZodCheckIncludes({ + check: "string_format", + format: "includes", + ...normalizeParams(params), + includes + }); + } + // @__NO_SIDE_EFFECTS__ + function _startsWith(prefix, params) { + return new $ZodCheckStartsWith({ + check: "string_format", + format: "starts_with", + ...normalizeParams(params), + prefix + }); + } + // @__NO_SIDE_EFFECTS__ + function _endsWith(suffix, params) { + return new $ZodCheckEndsWith({ + check: "string_format", + format: "ends_with", + ...normalizeParams(params), + suffix + }); + } + // @__NO_SIDE_EFFECTS__ + function _overwrite(tx) { + return new $ZodCheckOverwrite({ + check: "overwrite", + tx + }); + } + // @__NO_SIDE_EFFECTS__ + function _normalize(form) { + return /* @__PURE__ */ _overwrite((input) => input.normalize(form)); + } + // @__NO_SIDE_EFFECTS__ + function _trim() { + return /* @__PURE__ */ _overwrite((input) => input.trim()); + } + // @__NO_SIDE_EFFECTS__ + function _toLowerCase() { + return /* @__PURE__ */ _overwrite((input) => input.toLowerCase()); + } + // @__NO_SIDE_EFFECTS__ + function _toUpperCase() { + return /* @__PURE__ */ _overwrite((input) => input.toUpperCase()); + } + // @__NO_SIDE_EFFECTS__ + function _slugify() { + return /* @__PURE__ */ _overwrite((input) => slugify(input)); + } + // @__NO_SIDE_EFFECTS__ + function _array(Class, element, params) { + return new Class({ + type: "array", + element, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _refine(Class, fn, _params) { + return new Class({ + type: "custom", + check: "custom", + fn, + ...normalizeParams(_params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _superRefine(fn, params) { + const ch = /* @__PURE__ */ _check((payload) => { + payload.addIssue = (issue$2) => { + if (typeof issue$2 === "string") payload.issues.push(issue(issue$2, payload.value, ch._zod.def)); + else { + const _issue = issue$2; + if (_issue.fatal) _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = ch); + _issue.continue ?? (_issue.continue = !ch._zod.def.abort); + payload.issues.push(issue(_issue)); + } + }; + return fn(payload.value, payload); + }, params); + return ch; + } + // @__NO_SIDE_EFFECTS__ + function _check(fn, params) { + const ch = new $ZodCheck({ + check: "custom", + ...normalizeParams(params) + }); + ch._zod.check = fn; + return ch; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.js + function initializeContext(params) { + let target = params?.target ?? "draft-2020-12"; + if (target === "draft-4") target = "draft-04"; + if (target === "draft-7") target = "draft-07"; + return { + processors: params.processors ?? {}, + metadataRegistry: params?.metadata ?? globalRegistry, + target, + unrepresentable: params?.unrepresentable ?? "throw", + override: params?.override ?? (() => {}), + io: params?.io ?? "output", + counter: 0, + seen: /* @__PURE__ */ new Map(), + cycles: params?.cycles ?? "ref", + reused: params?.reused ?? "inline", + external: params?.external ?? void 0 + }; + } + function process(schema, ctx, _params = { + path: [], + schemaPath: [] + }) { + var _a; + const def = schema._zod.def; + const seen = ctx.seen.get(schema); + if (seen) { + seen.count++; + if (_params.schemaPath.includes(schema)) seen.cycle = _params.path; + return seen.schema; + } + const result = { + schema: {}, + count: 1, + cycle: void 0, + path: _params.path + }; + ctx.seen.set(schema, result); + const overrideSchema = schema._zod.toJSONSchema?.(); + if (overrideSchema) result.schema = overrideSchema; + else { + const params = { + ..._params, + schemaPath: [..._params.schemaPath, schema], + path: _params.path + }; + if (schema._zod.processJSONSchema) schema._zod.processJSONSchema(ctx, result.schema, params); + else { + const _json = result.schema; + const processor = ctx.processors[def.type]; + if (!processor) throw new Error(`[toJSONSchema]: Non-representable type encountered: ${def.type}`); + processor(schema, ctx, _json, params); + } + const parent = schema._zod.parent; + if (parent) { + if (!result.ref) result.ref = parent; + process(parent, ctx, params); + ctx.seen.get(parent).isParent = true; + } + } + const meta = ctx.metadataRegistry.get(schema); + if (meta) Object.assign(result.schema, meta); + if (ctx.io === "input" && isTransforming(schema)) { + delete result.schema.examples; + delete result.schema.default; + } + if (ctx.io === "input" && "_prefault" in result.schema) (_a = result.schema).default ?? (_a.default = result.schema._prefault); + delete result.schema._prefault; + return ctx.seen.get(schema).schema; + } + function extractDefs(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const idToSchema = /* @__PURE__ */ new Map(); + for (const entry of ctx.seen.entries()) { + const id = ctx.metadataRegistry.get(entry[0])?.id; + if (id) { + const existing = idToSchema.get(id); + if (existing && existing !== entry[0]) throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`); + idToSchema.set(id, entry[0]); + } + } + const makeURI = (entry) => { + const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions"; + if (ctx.external) { + const externalId = ctx.external.registry.get(entry[0])?.id; + const uriGenerator = ctx.external.uri ?? ((id) => id); + if (externalId) return { ref: uriGenerator(externalId) }; + const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`; + entry[1].defId = id; + return { + defId: id, + ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` + }; + } + if (entry[1] === root) return { ref: "#" }; + const defUriPrefix = `#/${defsSegment}/`; + const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`; + return { + defId, + ref: defUriPrefix + defId + }; + }; + const extractToDef = (entry) => { + if (entry[1].schema.$ref) return; + const seen = entry[1]; + const { ref, defId } = makeURI(entry); + seen.def = { ...seen.schema }; + if (defId) seen.defId = defId; + const schema = seen.schema; + for (const key in schema) delete schema[key]; + schema.$ref = ref; + }; + if (ctx.cycles === "throw") for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.cycle) throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/ + +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`); + } + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (schema === entry[0]) { + extractToDef(entry); + continue; + } + if (ctx.external) { + const ext = ctx.external.registry.get(entry[0])?.id; + if (schema !== entry[0] && ext) { + extractToDef(entry); + continue; + } + } + if (ctx.metadataRegistry.get(entry[0])?.id) { + extractToDef(entry); + continue; + } + if (seen.cycle) { + extractToDef(entry); + continue; + } + if (seen.count > 1) { + if (ctx.reused === "ref") { + extractToDef(entry); + continue; + } + } + } + } + function finalize(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const flattenRef = (zodSchema) => { + const seen = ctx.seen.get(zodSchema); + if (seen.ref === null) return; + const schema = seen.def ?? seen.schema; + const _cached = { ...schema }; + const ref = seen.ref; + seen.ref = null; + if (ref) { + flattenRef(ref); + const refSeen = ctx.seen.get(ref); + const refSchema = refSeen.schema; + if (refSchema.$ref && (ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0")) { + schema.allOf = schema.allOf ?? []; + schema.allOf.push(refSchema); + } else Object.assign(schema, refSchema); + Object.assign(schema, _cached); + if (zodSchema._zod.parent === ref) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (!(key in _cached)) delete schema[key]; + } + if (refSchema.$ref && refSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in refSeen.def && JSON.stringify(schema[key]) === JSON.stringify(refSeen.def[key])) delete schema[key]; + } + } + const parent = zodSchema._zod.parent; + if (parent && parent !== ref) { + flattenRef(parent); + const parentSeen = ctx.seen.get(parent); + if (parentSeen?.schema.$ref) { + schema.$ref = parentSeen.schema.$ref; + if (parentSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in parentSeen.def && JSON.stringify(schema[key]) === JSON.stringify(parentSeen.def[key])) delete schema[key]; + } + } + } + ctx.override({ + zodSchema, + jsonSchema: schema, + path: seen.path ?? [] + }); + }; + for (const entry of [...ctx.seen.entries()].reverse()) flattenRef(entry[0]); + const result = {}; + if (ctx.target === "draft-2020-12") result.$schema = "https://json-schema.org/draft/2020-12/schema"; + else if (ctx.target === "draft-07") result.$schema = "http://json-schema.org/draft-07/schema#"; + else if (ctx.target === "draft-04") result.$schema = "http://json-schema.org/draft-04/schema#"; + else if (ctx.target === "openapi-3.0") {} + if (ctx.external?.uri) { + const id = ctx.external.registry.get(schema)?.id; + if (!id) throw new Error("Schema is missing an `id` property"); + result.$id = ctx.external.uri(id); + } + Object.assign(result, root.def ?? root.schema); + const rootMetaId = ctx.metadataRegistry.get(schema)?.id; + if (rootMetaId !== void 0 && result.id === rootMetaId) delete result.id; + const defs = ctx.external?.defs ?? {}; + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.def && seen.defId) { + if (seen.def.id === seen.defId) delete seen.def.id; + defs[seen.defId] = seen.def; + } + } + if (ctx.external) {} else if (Object.keys(defs).length > 0) if (ctx.target === "draft-2020-12") result.$defs = defs; + else result.definitions = defs; + try { + const finalized = JSON.parse(JSON.stringify(result)); + Object.defineProperty(finalized, "~standard", { + value: { + ...schema["~standard"], + jsonSchema: { + input: createStandardJSONSchemaMethod(schema, "input", ctx.processors), + output: createStandardJSONSchemaMethod(schema, "output", ctx.processors) + } + }, + enumerable: false, + writable: false + }); + return finalized; + } catch (_err) { + throw new Error("Error converting schema to JSON."); + } + } + function isTransforming(_schema, _ctx) { + const ctx = _ctx ?? { seen: /* @__PURE__ */ new Set() }; + if (ctx.seen.has(_schema)) return false; + ctx.seen.add(_schema); + const def = _schema._zod.def; + if (def.type === "transform") return true; + if (def.type === "array") return isTransforming(def.element, ctx); + if (def.type === "set") return isTransforming(def.valueType, ctx); + if (def.type === "lazy") return isTransforming(def.getter(), ctx); + if (def.type === "promise" || def.type === "optional" || def.type === "nonoptional" || def.type === "nullable" || def.type === "readonly" || def.type === "default" || def.type === "prefault") return isTransforming(def.innerType, ctx); + if (def.type === "intersection") return isTransforming(def.left, ctx) || isTransforming(def.right, ctx); + if (def.type === "record" || def.type === "map") return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); + if (def.type === "pipe") { + if (_schema._zod.traits.has("$ZodCodec")) return true; + return isTransforming(def.in, ctx) || isTransforming(def.out, ctx); + } + if (def.type === "object") { + for (const key in def.shape) if (isTransforming(def.shape[key], ctx)) return true; + return false; + } + if (def.type === "union") { + for (const option of def.options) if (isTransforming(option, ctx)) return true; + return false; + } + if (def.type === "tuple") { + for (const item of def.items) if (isTransforming(item, ctx)) return true; + if (def.rest && isTransforming(def.rest, ctx)) return true; + return false; + } + return false; + } + /** + * Creates a toJSONSchema method for a schema instance. + * This encapsulates the logic of initializing context, processing, extracting defs, and finalizing. + */ + const createToJSONSchemaMethod = (schema, processors = {}) => (params) => { + const ctx = initializeContext({ + ...params, + processors + }); + process(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); + }; + const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => { + const { libraryOptions, target } = params ?? {}; + const ctx = initializeContext({ + ...libraryOptions ?? {}, + target, + io, + processors + }); + process(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.js + const formatMap = { + guid: "uuid", + url: "uri", + datetime: "date-time", + json_string: "json-string", + regex: "" + }; + const stringProcessor = (schema, ctx, _json, _params) => { + const json = _json; + json.type = "string"; + const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag; + if (typeof minimum === "number") json.minLength = minimum; + if (typeof maximum === "number") json.maxLength = maximum; + if (format) { + json.format = formatMap[format] ?? format; + if (json.format === "") delete json.format; + if (format === "time") delete json.format; + } + if (contentEncoding) json.contentEncoding = contentEncoding; + if (patterns && patterns.size > 0) { + const regexes = [...patterns]; + if (regexes.length === 1) json.pattern = regexes[0].source; + else if (regexes.length > 1) json.allOf = [...regexes.map((regex) => ({ + ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {}, + pattern: regex.source + }))]; + } + }; + const numberProcessor = (schema, ctx, _json, _params) => { + const json = _json; + const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; + if (typeof format === "string" && format.includes("int")) json.type = "integer"; + else json.type = "number"; + const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY); + const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY); + const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0"; + if (exMin) if (legacy) { + json.minimum = exclusiveMinimum; + json.exclusiveMinimum = true; + } else json.exclusiveMinimum = exclusiveMinimum; + else if (typeof minimum === "number") json.minimum = minimum; + if (exMax) if (legacy) { + json.maximum = exclusiveMaximum; + json.exclusiveMaximum = true; + } else json.exclusiveMaximum = exclusiveMaximum; + else if (typeof maximum === "number") json.maximum = maximum; + if (typeof multipleOf === "number") json.multipleOf = multipleOf; + }; + const booleanProcessor = (_schema, _ctx, json, _params) => { + json.type = "boolean"; + }; + const undefinedProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Undefined cannot be represented in JSON Schema"); + }; + const neverProcessor = (_schema, _ctx, json, _params) => { + json.not = {}; + }; + const enumProcessor = (schema, _ctx, json, _params) => { + const def = schema._zod.def; + const values = getEnumValues(def.entries); + if (values.every((v) => typeof v === "number")) json.type = "number"; + if (values.every((v) => typeof v === "string")) json.type = "string"; + json.enum = values; + }; + const literalProcessor = (schema, ctx, json, _params) => { + const def = schema._zod.def; + const vals = []; + for (const val of def.values) if (val === void 0) { + if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema"); + } else if (typeof val === "bigint") if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema"); + else vals.push(Number(val)); + else vals.push(val); + if (vals.length === 0) {} else if (vals.length === 1) { + const val = vals[0]; + json.type = val === null ? "null" : typeof val; + if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") json.enum = [val]; + else json.const = val; + } else { + if (vals.every((v) => typeof v === "number")) json.type = "number"; + if (vals.every((v) => typeof v === "string")) json.type = "string"; + if (vals.every((v) => typeof v === "boolean")) json.type = "boolean"; + if (vals.every((v) => v === null)) json.type = "null"; + json.enum = vals; + } + }; + const customProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Custom types cannot be represented in JSON Schema"); + }; + const transformProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Transforms cannot be represented in JSON Schema"); + }; + const arrayProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") json.minItems = minimum; + if (typeof maximum === "number") json.maxItems = maximum; + json.type = "array"; + json.items = process(def.element, ctx, { + ...params, + path: [...params.path, "items"] + }); + }; + const objectProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + json.properties = {}; + const shape = def.shape; + for (const key in shape) json.properties[key] = process(shape[key], ctx, { + ...params, + path: [ + ...params.path, + "properties", + key + ] + }); + const allKeys = new Set(Object.keys(shape)); + const requiredKeys = new Set([...allKeys].filter((key) => { + const v = def.shape[key]._zod; + if (ctx.io === "input") return v.optin === void 0; + else return v.optout === void 0; + })); + if (requiredKeys.size > 0) json.required = Array.from(requiredKeys); + if (def.catchall?._zod.def.type === "never") json.additionalProperties = false; + else if (!def.catchall) { + if (ctx.io === "output") json.additionalProperties = false; + } else if (def.catchall) json.additionalProperties = process(def.catchall, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + }; + const unionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const isExclusive = def.inclusive === false; + const options = def.options.map((x, i) => process(x, ctx, { + ...params, + path: [ + ...params.path, + isExclusive ? "oneOf" : "anyOf", + i + ] + })); + if (isExclusive) json.oneOf = options; + else json.anyOf = options; + }; + const intersectionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const a = process(def.left, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 0 + ] + }); + const b = process(def.right, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 1 + ] + }); + const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1; + json.allOf = [...isSimpleIntersection(a) ? a.allOf : [a], ...isSimpleIntersection(b) ? b.allOf : [b]]; + }; + const recordProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + const keyType = def.keyType; + const patterns = keyType._zod.bag?.patterns; + if (def.mode === "loose" && patterns && patterns.size > 0) { + const valueSchema = process(def.valueType, ctx, { + ...params, + path: [ + ...params.path, + "patternProperties", + "*" + ] + }); + json.patternProperties = {}; + for (const pattern of patterns) json.patternProperties[pattern.source] = valueSchema; + } else { + if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") json.propertyNames = process(def.keyType, ctx, { + ...params, + path: [...params.path, "propertyNames"] + }); + json.additionalProperties = process(def.valueType, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + } + const keyValues = keyType._zod.values; + if (keyValues) { + const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number"); + if (validKeyValues.length > 0) json.required = validKeyValues; + } + }; + const nullableProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const inner = process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + if (ctx.target === "openapi-3.0") { + seen.ref = def.innerType; + json.nullable = true; + } else json.anyOf = [inner, { type: "null" }]; + }; + const nonoptionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const defaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.default = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const prefaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + if (ctx.io === "input") json._prefault = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const catchProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + let catchValue; + try { + catchValue = def.catchValue(void 0); + } catch { + throw new Error("Dynamic catch values are not supported in JSON Schema"); + } + json.default = catchValue; + }; + const pipeProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + const inIsTransform = def.in._zod.traits.has("$ZodTransform"); + const innerType = ctx.io === "input" ? inIsTransform ? def.out : def.in : def.out; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + const readonlyProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.readOnly = true; + }; + const optionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const lazyProcessor = (schema, ctx, _json, params) => { + const innerType = schema._zod.innerType; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/iso.js + const ZodISODateTime = /*@__PURE__*/ $constructor("ZodISODateTime", (inst, def) => { + $ZodISODateTime.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function datetime(params) { + return /* @__PURE__ */ _isoDateTime(ZodISODateTime, params); + } + const ZodISODate = /*@__PURE__*/ $constructor("ZodISODate", (inst, def) => { + $ZodISODate.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function date(params) { + return /* @__PURE__ */ _isoDate(ZodISODate, params); + } + const ZodISOTime = /*@__PURE__*/ $constructor("ZodISOTime", (inst, def) => { + $ZodISOTime.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function time(params) { + return /* @__PURE__ */ _isoTime(ZodISOTime, params); + } + const ZodISODuration = /*@__PURE__*/ $constructor("ZodISODuration", (inst, def) => { + $ZodISODuration.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function duration(params) { + return /* @__PURE__ */ _isoDuration(ZodISODuration, params); + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/errors.js + const initializer = (inst, issues) => { + $ZodError.init(inst, issues); + inst.name = "ZodError"; + Object.defineProperties(inst, { + format: { value: (mapper) => formatError(inst, mapper) }, + flatten: { value: (mapper) => flattenError(inst, mapper) }, + addIssue: { value: (issue) => { + inst.issues.push(issue); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } }, + addIssues: { value: (issues) => { + inst.issues.push(...issues); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } }, + isEmpty: { get() { + return inst.issues.length === 0; + } } + }); + }; + const ZodRealError = /*@__PURE__*/ $constructor("ZodError", initializer, { Parent: Error }); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/parse.js + const parse = /* @__PURE__ */ _parse(ZodRealError); + const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError); + const safeParse = /* @__PURE__ */ _safeParse(ZodRealError); + const safeParseAsync = /* @__PURE__ */ _safeParseAsync(ZodRealError); + const encode = /* @__PURE__ */ _encode(ZodRealError); + const decode = /* @__PURE__ */ _decode(ZodRealError); + const encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError); + const decodeAsync = /* @__PURE__ */ _decodeAsync(ZodRealError); + const safeEncode = /* @__PURE__ */ _safeEncode(ZodRealError); + const safeDecode = /* @__PURE__ */ _safeDecode(ZodRealError); + const safeEncodeAsync = /* @__PURE__ */ _safeEncodeAsync(ZodRealError); + const safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync(ZodRealError); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js + const _installedGroups = /* @__PURE__ */ new WeakMap(); + function _installLazyMethods(inst, group, methods) { + const proto = Object.getPrototypeOf(inst); + let installed = _installedGroups.get(proto); + if (!installed) { + installed = /* @__PURE__ */ new Set(); + _installedGroups.set(proto, installed); + } + if (installed.has(group)) return; + installed.add(group); + for (const key in methods) { + const fn = methods[key]; + Object.defineProperty(proto, key, { + configurable: true, + enumerable: false, + get() { + const bound = fn.bind(this); + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: bound + }); + return bound; + }, + set(v) { + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: v + }); + } + }); + } + } + const ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => { + $ZodType.init(inst, def); + Object.assign(inst["~standard"], { jsonSchema: { + input: createStandardJSONSchemaMethod(inst, "input"), + output: createStandardJSONSchemaMethod(inst, "output") + } }); + inst.toJSONSchema = createToJSONSchemaMethod(inst, {}); + inst.def = def; + inst.type = def.type; + Object.defineProperty(inst, "_def", { value: def }); + inst.parse = (data, params) => parse(inst, data, params, { callee: inst.parse }); + inst.safeParse = (data, params) => safeParse(inst, data, params); + inst.parseAsync = async (data, params) => parseAsync(inst, data, params, { callee: inst.parseAsync }); + inst.safeParseAsync = async (data, params) => safeParseAsync(inst, data, params); + inst.spa = inst.safeParseAsync; + inst.encode = (data, params) => encode(inst, data, params); + inst.decode = (data, params) => decode(inst, data, params); + inst.encodeAsync = async (data, params) => encodeAsync(inst, data, params); + inst.decodeAsync = async (data, params) => decodeAsync(inst, data, params); + inst.safeEncode = (data, params) => safeEncode(inst, data, params); + inst.safeDecode = (data, params) => safeDecode(inst, data, params); + inst.safeEncodeAsync = async (data, params) => safeEncodeAsync(inst, data, params); + inst.safeDecodeAsync = async (data, params) => safeDecodeAsync(inst, data, params); + _installLazyMethods(inst, "ZodType", { + check(...chks) { + const def = this.def; + return this.clone(mergeDefs(def, { checks: [...def.checks ?? [], ...chks.map((ch) => typeof ch === "function" ? { _zod: { + check: ch, + def: { check: "custom" }, + onattach: [] + } } : ch)] }), { parent: true }); + }, + with(...chks) { + return this.check(...chks); + }, + clone(def, params) { + return clone(this, def, params); + }, + brand() { + return this; + }, + register(reg, meta) { + reg.add(this, meta); + return this; + }, + refine(check, params) { + return this.check(refine(check, params)); + }, + superRefine(refinement, params) { + return this.check(superRefine(refinement, params)); + }, + overwrite(fn) { + return this.check(/* @__PURE__ */ _overwrite(fn)); + }, + optional() { + return optional(this); + }, + exactOptional() { + return exactOptional(this); + }, + nullable() { + return nullable(this); + }, + nullish() { + return optional(nullable(this)); + }, + nonoptional(params) { + return nonoptional(this, params); + }, + array() { + return array(this); + }, + or(arg) { + return union([this, arg]); + }, + and(arg) { + return intersection(this, arg); + }, + transform(tx) { + return pipe(this, transform(tx)); + }, + default(d) { + return _default(this, d); + }, + prefault(d) { + return prefault(this, d); + }, + catch(params) { + return _catch(this, params); + }, + pipe(target) { + return pipe(this, target); + }, + readonly() { + return readonly(this); + }, + describe(description) { + const cl = this.clone(); + globalRegistry.add(cl, { description }); + return cl; + }, + meta(...args) { + if (args.length === 0) return globalRegistry.get(this); + const cl = this.clone(); + globalRegistry.add(cl, args[0]); + return cl; + }, + isOptional() { + return this.safeParse(void 0).success; + }, + isNullable() { + return this.safeParse(null).success; + }, + apply(fn) { + return fn(this); + } + }); + Object.defineProperty(inst, "description", { + get() { + return globalRegistry.get(inst)?.description; + }, + configurable: true + }); + return inst; + }); + /** @internal */ + const _ZodString = /*@__PURE__*/ $constructor("_ZodString", (inst, def) => { + $ZodString.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => stringProcessor(inst, ctx, json, params); + const bag = inst._zod.bag; + inst.format = bag.format ?? null; + inst.minLength = bag.minimum ?? null; + inst.maxLength = bag.maximum ?? null; + _installLazyMethods(inst, "_ZodString", { + regex(...args) { + return this.check(/* @__PURE__ */ _regex(...args)); + }, + includes(...args) { + return this.check(/* @__PURE__ */ _includes(...args)); + }, + startsWith(...args) { + return this.check(/* @__PURE__ */ _startsWith(...args)); + }, + endsWith(...args) { + return this.check(/* @__PURE__ */ _endsWith(...args)); + }, + min(...args) { + return this.check(/* @__PURE__ */ _minLength(...args)); + }, + max(...args) { + return this.check(/* @__PURE__ */ _maxLength(...args)); + }, + length(...args) { + return this.check(/* @__PURE__ */ _length(...args)); + }, + nonempty(...args) { + return this.check(/* @__PURE__ */ _minLength(1, ...args)); + }, + lowercase(params) { + return this.check(/* @__PURE__ */ _lowercase(params)); + }, + uppercase(params) { + return this.check(/* @__PURE__ */ _uppercase(params)); + }, + trim() { + return this.check(/* @__PURE__ */ _trim()); + }, + normalize(...args) { + return this.check(/* @__PURE__ */ _normalize(...args)); + }, + toLowerCase() { + return this.check(/* @__PURE__ */ _toLowerCase()); + }, + toUpperCase() { + return this.check(/* @__PURE__ */ _toUpperCase()); + }, + slugify() { + return this.check(/* @__PURE__ */ _slugify()); + } + }); + }); + const ZodString = /*@__PURE__*/ $constructor("ZodString", (inst, def) => { + $ZodString.init(inst, def); + _ZodString.init(inst, def); + inst.email = (params) => inst.check(/* @__PURE__ */ _email(ZodEmail, params)); + inst.url = (params) => inst.check(/* @__PURE__ */ _url(ZodURL, params)); + inst.jwt = (params) => inst.check(/* @__PURE__ */ _jwt(ZodJWT, params)); + inst.emoji = (params) => inst.check(/* @__PURE__ */ _emoji(ZodEmoji, params)); + inst.guid = (params) => inst.check(/* @__PURE__ */ _guid(ZodGUID, params)); + inst.uuid = (params) => inst.check(/* @__PURE__ */ _uuid(ZodUUID, params)); + inst.uuidv4 = (params) => inst.check(/* @__PURE__ */ _uuidv4(ZodUUID, params)); + inst.uuidv6 = (params) => inst.check(/* @__PURE__ */ _uuidv6(ZodUUID, params)); + inst.uuidv7 = (params) => inst.check(/* @__PURE__ */ _uuidv7(ZodUUID, params)); + inst.nanoid = (params) => inst.check(/* @__PURE__ */ _nanoid(ZodNanoID, params)); + inst.guid = (params) => inst.check(/* @__PURE__ */ _guid(ZodGUID, params)); + inst.cuid = (params) => inst.check(/* @__PURE__ */ _cuid(ZodCUID, params)); + inst.cuid2 = (params) => inst.check(/* @__PURE__ */ _cuid2(ZodCUID2, params)); + inst.ulid = (params) => inst.check(/* @__PURE__ */ _ulid(ZodULID, params)); + inst.base64 = (params) => inst.check(/* @__PURE__ */ _base64(ZodBase64, params)); + inst.base64url = (params) => inst.check(/* @__PURE__ */ _base64url(ZodBase64URL, params)); + inst.xid = (params) => inst.check(/* @__PURE__ */ _xid(ZodXID, params)); + inst.ksuid = (params) => inst.check(/* @__PURE__ */ _ksuid(ZodKSUID, params)); + inst.ipv4 = (params) => inst.check(/* @__PURE__ */ _ipv4(ZodIPv4, params)); + inst.ipv6 = (params) => inst.check(/* @__PURE__ */ _ipv6(ZodIPv6, params)); + inst.cidrv4 = (params) => inst.check(/* @__PURE__ */ _cidrv4(ZodCIDRv4, params)); + inst.cidrv6 = (params) => inst.check(/* @__PURE__ */ _cidrv6(ZodCIDRv6, params)); + inst.e164 = (params) => inst.check(/* @__PURE__ */ _e164(ZodE164, params)); + inst.datetime = (params) => inst.check(datetime(params)); + inst.date = (params) => inst.check(date(params)); + inst.time = (params) => inst.check(time(params)); + inst.duration = (params) => inst.check(duration(params)); + }); + function string(params) { + return /* @__PURE__ */ _string(ZodString, params); + } + const ZodStringFormat = /*@__PURE__*/ $constructor("ZodStringFormat", (inst, def) => { + $ZodStringFormat.init(inst, def); + _ZodString.init(inst, def); + }); + const ZodEmail = /*@__PURE__*/ $constructor("ZodEmail", (inst, def) => { + $ZodEmail.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodGUID = /*@__PURE__*/ $constructor("ZodGUID", (inst, def) => { + $ZodGUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodUUID = /*@__PURE__*/ $constructor("ZodUUID", (inst, def) => { + $ZodUUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodURL = /*@__PURE__*/ $constructor("ZodURL", (inst, def) => { + $ZodURL.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodEmoji = /*@__PURE__*/ $constructor("ZodEmoji", (inst, def) => { + $ZodEmoji.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodNanoID = /*@__PURE__*/ $constructor("ZodNanoID", (inst, def) => { + $ZodNanoID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link ZodCUID2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const ZodCUID = /*@__PURE__*/ $constructor("ZodCUID", (inst, def) => { + $ZodCUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCUID2 = /*@__PURE__*/ $constructor("ZodCUID2", (inst, def) => { + $ZodCUID2.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodULID = /*@__PURE__*/ $constructor("ZodULID", (inst, def) => { + $ZodULID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodXID = /*@__PURE__*/ $constructor("ZodXID", (inst, def) => { + $ZodXID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodKSUID = /*@__PURE__*/ $constructor("ZodKSUID", (inst, def) => { + $ZodKSUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodIPv4 = /*@__PURE__*/ $constructor("ZodIPv4", (inst, def) => { + $ZodIPv4.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodIPv6 = /*@__PURE__*/ $constructor("ZodIPv6", (inst, def) => { + $ZodIPv6.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCIDRv4 = /*@__PURE__*/ $constructor("ZodCIDRv4", (inst, def) => { + $ZodCIDRv4.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCIDRv6 = /*@__PURE__*/ $constructor("ZodCIDRv6", (inst, def) => { + $ZodCIDRv6.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodBase64 = /*@__PURE__*/ $constructor("ZodBase64", (inst, def) => { + $ZodBase64.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodBase64URL = /*@__PURE__*/ $constructor("ZodBase64URL", (inst, def) => { + $ZodBase64URL.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodE164 = /*@__PURE__*/ $constructor("ZodE164", (inst, def) => { + $ZodE164.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodJWT = /*@__PURE__*/ $constructor("ZodJWT", (inst, def) => { + $ZodJWT.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodNumber = /*@__PURE__*/ $constructor("ZodNumber", (inst, def) => { + $ZodNumber.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => numberProcessor(inst, ctx, json, params); + _installLazyMethods(inst, "ZodNumber", { + gt(value, params) { + return this.check(/* @__PURE__ */ _gt(value, params)); + }, + gte(value, params) { + return this.check(/* @__PURE__ */ _gte(value, params)); + }, + min(value, params) { + return this.check(/* @__PURE__ */ _gte(value, params)); + }, + lt(value, params) { + return this.check(/* @__PURE__ */ _lt(value, params)); + }, + lte(value, params) { + return this.check(/* @__PURE__ */ _lte(value, params)); + }, + max(value, params) { + return this.check(/* @__PURE__ */ _lte(value, params)); + }, + int(params) { + return this.check(int(params)); + }, + safe(params) { + return this.check(int(params)); + }, + positive(params) { + return this.check(/* @__PURE__ */ _gt(0, params)); + }, + nonnegative(params) { + return this.check(/* @__PURE__ */ _gte(0, params)); + }, + negative(params) { + return this.check(/* @__PURE__ */ _lt(0, params)); + }, + nonpositive(params) { + return this.check(/* @__PURE__ */ _lte(0, params)); + }, + multipleOf(value, params) { + return this.check(/* @__PURE__ */ _multipleOf(value, params)); + }, + step(value, params) { + return this.check(/* @__PURE__ */ _multipleOf(value, params)); + }, + finite() { + return this; + } + }); + const bag = inst._zod.bag; + inst.minValue = Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null; + inst.maxValue = Math.min(bag.maximum ?? Number.POSITIVE_INFINITY, bag.exclusiveMaximum ?? Number.POSITIVE_INFINITY) ?? null; + inst.isInt = (bag.format ?? "").includes("int") || Number.isSafeInteger(bag.multipleOf ?? .5); + inst.isFinite = true; + inst.format = bag.format ?? null; + }); + function number(params) { + return /* @__PURE__ */ _number(ZodNumber, params); + } + const ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def) => { + $ZodNumberFormat.init(inst, def); + ZodNumber.init(inst, def); + }); + function int(params) { + return /* @__PURE__ */ _int(ZodNumberFormat, params); + } + const ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => { + $ZodBoolean.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params); + }); + function boolean(params) { + return /* @__PURE__ */ _boolean(ZodBoolean, params); + } + const ZodUndefined = /*@__PURE__*/ $constructor("ZodUndefined", (inst, def) => { + $ZodUndefined.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => undefinedProcessor(inst, ctx, json, params); + }); + function _undefined(params) { + return /* @__PURE__ */ _undefined$1(ZodUndefined, params); + } + const ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => { + $ZodUnknown.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => void 0; + }); + function unknown() { + return /* @__PURE__ */ _unknown(ZodUnknown); + } + const ZodNever = /*@__PURE__*/ $constructor("ZodNever", (inst, def) => { + $ZodNever.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => neverProcessor(inst, ctx, json, params); + }); + function never(params) { + return /* @__PURE__ */ _never(ZodNever, params); + } + const ZodArray = /*@__PURE__*/ $constructor("ZodArray", (inst, def) => { + $ZodArray.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => arrayProcessor(inst, ctx, json, params); + inst.element = def.element; + _installLazyMethods(inst, "ZodArray", { + min(n, params) { + return this.check(/* @__PURE__ */ _minLength(n, params)); + }, + nonempty(params) { + return this.check(/* @__PURE__ */ _minLength(1, params)); + }, + max(n, params) { + return this.check(/* @__PURE__ */ _maxLength(n, params)); + }, + length(n, params) { + return this.check(/* @__PURE__ */ _length(n, params)); + }, + unwrap() { + return this.element; + } + }); + }); + function array(element, params) { + return /* @__PURE__ */ _array(ZodArray, element, params); + } + const ZodObject = /*@__PURE__*/ $constructor("ZodObject", (inst, def) => { + $ZodObjectJIT.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => objectProcessor(inst, ctx, json, params); + defineLazy(inst, "shape", () => { + return def.shape; + }); + _installLazyMethods(inst, "ZodObject", { + keyof() { + return _enum(Object.keys(this._zod.def.shape)); + }, + catchall(catchall) { + return this.clone({ + ...this._zod.def, + catchall + }); + }, + passthrough() { + return this.clone({ + ...this._zod.def, + catchall: unknown() + }); + }, + loose() { + return this.clone({ + ...this._zod.def, + catchall: unknown() + }); + }, + strict() { + return this.clone({ + ...this._zod.def, + catchall: never() + }); + }, + strip() { + return this.clone({ + ...this._zod.def, + catchall: void 0 + }); + }, + extend(incoming) { + return extend(this, incoming); + }, + safeExtend(incoming) { + return safeExtend(this, incoming); + }, + merge(other) { + return merge(this, other); + }, + pick(mask) { + return pick(this, mask); + }, + omit(mask) { + return omit(this, mask); + }, + partial(...args) { + return partial(ZodOptional, this, args[0]); + }, + required(...args) { + return required(ZodNonOptional, this, args[0]); + } + }); + }); + function object(shape, params) { + return new ZodObject({ + type: "object", + shape: shape ?? {}, + ...normalizeParams(params) + }); + } + const ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => { + $ZodUnion.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => unionProcessor(inst, ctx, json, params); + inst.options = def.options; + }); + function union(options, params) { + return new ZodUnion({ + type: "union", + options, + ...normalizeParams(params) + }); + } + const ZodIntersection = /*@__PURE__*/ $constructor("ZodIntersection", (inst, def) => { + $ZodIntersection.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => intersectionProcessor(inst, ctx, json, params); + }); + function intersection(left, right) { + return new ZodIntersection({ + type: "intersection", + left, + right + }); + } + const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => { + $ZodRecord.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params); + inst.keyType = def.keyType; + inst.valueType = def.valueType; + }); + function record(keyType, valueType, params) { + if (!valueType || !valueType._zod) return new ZodRecord({ + type: "record", + keyType: string(), + valueType: keyType, + ...normalizeParams(valueType) + }); + return new ZodRecord({ + type: "record", + keyType, + valueType, + ...normalizeParams(params) + }); + } + const ZodEnum = /*@__PURE__*/ $constructor("ZodEnum", (inst, def) => { + $ZodEnum.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => enumProcessor(inst, ctx, json, params); + inst.enum = def.entries; + inst.options = Object.values(def.entries); + const keys = new Set(Object.keys(def.entries)); + inst.extract = (values, params) => { + const newEntries = {}; + for (const value of values) if (keys.has(value)) newEntries[value] = def.entries[value]; + else throw new Error(`Key ${value} not found in enum`); + return new ZodEnum({ + ...def, + checks: [], + ...normalizeParams(params), + entries: newEntries + }); + }; + inst.exclude = (values, params) => { + const newEntries = { ...def.entries }; + for (const value of values) if (keys.has(value)) delete newEntries[value]; + else throw new Error(`Key ${value} not found in enum`); + return new ZodEnum({ + ...def, + checks: [], + ...normalizeParams(params), + entries: newEntries + }); + }; + }); + function _enum(values, params) { + return new ZodEnum({ + type: "enum", + entries: Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values, + ...normalizeParams(params) + }); + } + const ZodLiteral = /*@__PURE__*/ $constructor("ZodLiteral", (inst, def) => { + $ZodLiteral.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => literalProcessor(inst, ctx, json, params); + inst.values = new Set(def.values); + Object.defineProperty(inst, "value", { get() { + if (def.values.length > 1) throw new Error("This schema contains multiple valid literal values. Use `.values` instead."); + return def.values[0]; + } }); + }); + function literal(value, params) { + return new ZodLiteral({ + type: "literal", + values: Array.isArray(value) ? value : [value], + ...normalizeParams(params) + }); + } + const ZodTransform = /*@__PURE__*/ $constructor("ZodTransform", (inst, def) => { + $ZodTransform.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => transformProcessor(inst, ctx, json, params); + inst._zod.parse = (payload, _ctx) => { + if (_ctx.direction === "backward") throw new $ZodEncodeError(inst.constructor.name); + payload.addIssue = (issue$1) => { + if (typeof issue$1 === "string") payload.issues.push(issue(issue$1, payload.value, def)); + else { + const _issue = issue$1; + if (_issue.fatal) _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = inst); + payload.issues.push(issue(_issue)); + } + }; + const output = def.transform(payload.value, payload); + if (output instanceof Promise) return output.then((output) => { + payload.value = output; + payload.fallback = true; + return payload; + }); + payload.value = output; + payload.fallback = true; + return payload; + }; + }); + function transform(fn) { + return new ZodTransform({ + type: "transform", + transform: fn + }); + } + const ZodOptional = /*@__PURE__*/ $constructor("ZodOptional", (inst, def) => { + $ZodOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function optional(innerType) { + return new ZodOptional({ + type: "optional", + innerType + }); + } + const ZodExactOptional = /*@__PURE__*/ $constructor("ZodExactOptional", (inst, def) => { + $ZodExactOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function exactOptional(innerType) { + return new ZodExactOptional({ + type: "optional", + innerType + }); + } + const ZodNullable = /*@__PURE__*/ $constructor("ZodNullable", (inst, def) => { + $ZodNullable.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nullableProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function nullable(innerType) { + return new ZodNullable({ + type: "nullable", + innerType + }); + } + const ZodDefault = /*@__PURE__*/ $constructor("ZodDefault", (inst, def) => { + $ZodDefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => defaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeDefault = inst.unwrap; + }); + function _default(innerType, defaultValue) { + return new ZodDefault({ + type: "default", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); + } + }); + } + const ZodPrefault = /*@__PURE__*/ $constructor("ZodPrefault", (inst, def) => { + $ZodPrefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => prefaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function prefault(innerType, defaultValue) { + return new ZodPrefault({ + type: "prefault", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); + } + }); + } + const ZodNonOptional = /*@__PURE__*/ $constructor("ZodNonOptional", (inst, def) => { + $ZodNonOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nonoptionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function nonoptional(innerType, params) { + return new ZodNonOptional({ + type: "nonoptional", + innerType, + ...normalizeParams(params) + }); + } + const ZodCatch = /*@__PURE__*/ $constructor("ZodCatch", (inst, def) => { + $ZodCatch.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => catchProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeCatch = inst.unwrap; + }); + function _catch(innerType, catchValue) { + return new ZodCatch({ + type: "catch", + innerType, + catchValue: typeof catchValue === "function" ? catchValue : () => catchValue + }); + } + const ZodPipe = /*@__PURE__*/ $constructor("ZodPipe", (inst, def) => { + $ZodPipe.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => pipeProcessor(inst, ctx, json, params); + inst.in = def.in; + inst.out = def.out; + }); + function pipe(in_, out) { + return new ZodPipe({ + type: "pipe", + in: in_, + out + }); + } + const ZodReadonly = /*@__PURE__*/ $constructor("ZodReadonly", (inst, def) => { + $ZodReadonly.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => readonlyProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function readonly(innerType) { + return new ZodReadonly({ + type: "readonly", + innerType + }); + } + const ZodLazy = /*@__PURE__*/ $constructor("ZodLazy", (inst, def) => { + $ZodLazy.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => lazyProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.getter(); + }); + function lazy(getter) { + return new ZodLazy({ + type: "lazy", + getter + }); + } + const ZodCustom = /*@__PURE__*/ $constructor("ZodCustom", (inst, def) => { + $ZodCustom.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => customProcessor(inst, ctx, json, params); + }); + function refine(fn, _params = {}) { + return /* @__PURE__ */ _refine(ZodCustom, fn, _params); + } + function superRefine(fn, params) { + return /* @__PURE__ */ _superRefine(fn, params); + } + //#endregion + //#region ../../interaction/commands/lib/typert.remote-client.js + const _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema = string(); + const _deepseek_ai_dsh_commands_commands_execute_result$schema = union([_undefined(), object({ + "commandId": intersection(string(), unknown()).readonly(), + "result": union([object({ + "kind": literal("success").readonly(), + "text": string().readonly().optional(), + "sourceEventSeq": number().readonly().optional() + }), object({ + "kind": literal("error").readonly(), + "text": string().readonly() + })]).readonly() + })]); + const _deepseek_ai_dsh_commands_commands_list_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_commands_commands_list_result$schema = array(object({ + "name": string().readonly(), + "description": string().readonly(), + "input": object({ "hint": string().readonly() }).readonly().optional() + })); + const TYPERT_REMOTE$4 = { + package: "@deepseek-ai/dsh-commands", + descriptors: [{ + id: "@deepseek-ai/dsh-commands#commands/execute", + service: "commands", + namespace: "commands", + method: "execute", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema + } + }, { + name: "line", + wire: "line", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-commands#commands/execute:line", + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema + } + }], + cancellation: { parameter: "signal" }, + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-commands#commands/execute:result", + schema: _deepseek_ai_dsh_commands_commands_execute_result$schema + }, + sourceLocation: { + "file": "packages/interaction/commands/src/index.ts", + "line": 297, + "column": 9 + } + }, { + id: "@deepseek-ai/dsh-commands#commands/list", + service: "commands", + namespace: "commands", + method: "list", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_commands_commands_list_parameter_0$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-commands#commands/list:result", + schema: _deepseek_ai_dsh_commands_commands_list_result$schema + }, + sourceLocation: { + "file": "packages/interaction/commands/src/index.ts", + "line": 260, + "column": 3 + } + }] + }; + //#endregion + //#region ../../goal/goal/lib/typert.remote-client.js + const _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_clear_result$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_complete_result$schema = object({ + "roundsStarted": number().readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly(), + "activation": union([literal("armed"), literal("disarmed")]).readonly(), + "objective": string().readonly(), + "phase": union([ + literal("active"), + literal("paused"), + literal("blocked"), + literal("complete") + ]).readonly(), + "blockedReason": object({ + "code": string().readonly(), + "message": string().readonly() + }).readonly().optional(), + "maxGoalRounds": number().readonly(), + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_create_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_create_parameter_1$schema = object({ + "objective": string().readonly(), + "maxGoalRounds": number().readonly().optional() + }); + const _deepseek_ai_dsh_goal_goals_create_result$schema = object({ "ref": object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }).readonly() }); + const _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema = object({ + "objective": string().readonly().optional(), + "maxGoalRounds": number().readonly().optional() + }); + const _deepseek_ai_dsh_goal_goals_edit_result$schema = object({ + "roundsStarted": number().readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly(), + "activation": union([literal("armed"), literal("disarmed")]).readonly(), + "objective": string().readonly(), + "phase": union([ + literal("active"), + literal("paused"), + literal("blocked"), + literal("complete") + ]).readonly(), + "blockedReason": object({ + "code": string().readonly(), + "message": string().readonly() + }).readonly().optional(), + "maxGoalRounds": number().readonly(), + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_pause_result$schema = object({ + "roundsStarted": number().readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly(), + "activation": union([literal("armed"), literal("disarmed")]).readonly(), + "objective": string().readonly(), + "phase": union([ + literal("active"), + literal("paused"), + literal("blocked"), + literal("complete") + ]).readonly(), + "blockedReason": object({ + "code": string().readonly(), + "message": string().readonly() + }).readonly().optional(), + "maxGoalRounds": number().readonly(), + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema = object({ + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const _deepseek_ai_dsh_goal_goals_resume_result$schema = object({ + "roundsStarted": number().readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly(), + "activation": union([literal("armed"), literal("disarmed")]).readonly(), + "objective": string().readonly(), + "phase": union([ + literal("active"), + literal("paused"), + literal("blocked"), + literal("complete") + ]).readonly(), + "blockedReason": object({ + "code": string().readonly(), + "message": string().readonly() + }).readonly().optional(), + "maxGoalRounds": number().readonly(), + "id": intersection(string(), unknown()).readonly(), + "revision": number().readonly() + }); + const TYPERT_REMOTE$3 = { + package: "@deepseek-ai/dsh-goal", + descriptors: [ + { + id: "@deepseek-ai/dsh-goal#goals/clear", + service: "goals", + namespace: "goals", + method: "clear", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema + } + }, { + name: "ref", + wire: "ref", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_clear_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 377, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-goal#goals/complete", + service: "goals", + namespace: "goals", + method: "complete", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema + } + }, { + name: "ref", + wire: "ref", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalView", + schema: _deepseek_ai_dsh_goal_goals_complete_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 337, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-goal#goals/create", + service: "goals", + namespace: "goals", + method: "create", + implementation: "remoteExportCreate", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_create_parameter_0$schema + } + }, { + name: "request", + wire: "request", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#CreateGoalRequest", + schema: _deepseek_ai_dsh_goal_goals_create_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#CreateGoalResult", + schema: _deepseek_ai_dsh_goal_goals_create_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 586, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-goal#goals/edit", + service: "goals", + namespace: "goals", + method: "edit", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema + } + }, + { + name: "ref", + wire: "ref", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema + } + }, + { + name: "request", + wire: "request", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#EditGoalRequest", + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalView", + schema: _deepseek_ai_dsh_goal_goals_edit_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 277, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-goal#goals/pause", + service: "goals", + namespace: "goals", + method: "pause", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema + } + }, { + name: "ref", + wire: "ref", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalView", + schema: _deepseek_ai_dsh_goal_goals_pause_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 299, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-goal#goals/resume", + service: "goals", + namespace: "goals", + method: "resume", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema + } + }, { + name: "ref", + wire: "ref", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalRef", + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-goal/client#GoalView", + schema: _deepseek_ai_dsh_goal_goals_resume_result$schema + }, + sourceLocation: { + "file": "packages/goal/goal/src/index.ts", + "line": 311, + "column": 3 + } + } + ] + }; + //#endregion + //#region ../../extensions/cordis-host-runner/lib/typert.remote-client.js + const JsonValueRemoteCodec$schema = union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema)), + record(string(), lazy(() => JsonValueRemoteCodec$schema)) + ]); + const JsonValueRemoteCodec$schema2 = union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema2)), + record(string(), lazy(() => JsonValueRemoteCodec$schema2)) + ]); + const JsonValueRemoteCodec$schema3 = union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema3)), + record(string(), lazy(() => JsonValueRemoteCodec$schema3)) + ]); + const JsonValueRemoteCodec$schema4 = union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema4)), + record(string(), lazy(() => JsonValueRemoteCodec$schema4)) + ]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema = object({ + "code": string(), + "name": string(), + "pluginId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()), + "pluginRunId": intersection(string(), unknown()) + }); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema = array(object({ + "pluginId": intersection(string(), unknown()), + "agentId": intersection(string(), unknown()), + "packages": array(object({ + "packageId": intersection(string(), unknown()), + "name": string(), + "purpose": string(), + "hasHostHalf": boolean(), + "hasClientHalf": boolean() + })), + "currentPackageId": intersection(string(), unknown()).optional(), + "nextPackageId": intersection(string(), unknown()).optional(), + "activeRun": object({ + "pluginRunId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()) + }).optional(), + "latestRun": object({ + "pluginRunId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()), + "mode": union([literal("run"), literal("update")]), + "status": union([ + literal("rejected"), + literal("awaiting-approval"), + literal("running"), + literal("cancelled"), + literal("starting-host"), + literal("client-pending"), + literal("waiting"), + literal("failed"), + literal("stopped") + ]), + "approvalRequestId": intersection(string(), unknown()).optional(), + "requiresApproval": boolean().optional(), + "host": object({ + "status": union([ + literal("running"), + literal("waiting"), + literal("failed"), + literal("stopped"), + literal("absent"), + literal("pending") + ]), + "waitingFor": array(string()), + "error": string().optional() + }), + "client": object({ + "status": union([ + literal("running"), + literal("waiting"), + literal("failed"), + literal("stopped"), + literal("absent"), + literal("pending") + ]), + "waitingFor": array(string()), + "error": string().optional() + }), + "error": object({ + "phase": union([ + literal("approval"), + literal("host-load"), + literal("host-apply"), + literal("client-load"), + literal("client-apply"), + literal("client-render") + ]), + "message": string(), + "stack": string().optional(), + "pluginId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()), + "pluginRunId": intersection(string(), unknown()) + }).optional() + }).optional() + })); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema = string(); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema = union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema3)), + record(string(), lazy(() => JsonValueRemoteCodec$schema3)) + ]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema = union([object({ + "ok": literal(true), + "value": union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema4)), + record(string(), lazy(() => JsonValueRemoteCodec$schema4)) + ]) + }), intersection(object({ + "ok": literal(false), + "code": union([ + literal("plugin-not-running"), + literal("stale-run"), + literal("method-not-found"), + literal("handler-error") + ]) + }), object({ + "message": string(), + "stack": string().optional() + }))]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema = object({ + "message": string(), + "stack": string().optional() + }); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema = literal(null); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema = object({ + "slot": string(), + "message": string(), + "stack": string().optional(), + "abdicated": boolean() + }); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema = literal(null); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema = union([object({ + "ok": literal(true), + "data": union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema2)), + record(string(), lazy(() => JsonValueRemoteCodec$schema2)) + ]) + }), object({ + "ok": literal(false), + "reason": union([ + literal("cancelled"), + literal("provider-missing"), + literal("method-missing"), + literal("invalid-input"), + literal("provider-error") + ]), + "message": string() + })]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema = object({ "accepted": boolean() }); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema = union([object({ + "ok": literal(true), + "pluginRunId": intersection(string(), unknown()), + "waitingFor": array(string()).optional() + }), object({ + "ok": literal(false), + "reason": union([ + literal("rejected"), + literal("host-half-failed"), + literal("client-half-failed") + ]), + "pluginRunId": intersection(string(), unknown()).optional(), + "startedHere": boolean().optional(), + "message": string().optional(), + "stack": string().optional() + })]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema = object({ "accepted": boolean() }); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema = union([literal("run"), literal("update")]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema = union([literal(null), intersection(string(), unknown())]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema = boolean(); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema = union([object({ + "ok": literal(true), + "pluginId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()), + "pluginRunId": intersection(string(), unknown()), + "waitingFor": array(string()), + "startedHere": boolean() + }), intersection(object({ "ok": literal(false) }), object({ + "message": string(), + "stack": string().optional() + }))]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema = union([object({ + "ok": literal(true), + "pluginRunId": intersection(string(), unknown()), + "waitingFor": array(string()).optional() + }), object({ + "ok": literal(false), + "reason": union([ + literal("rejected"), + literal("host-half-failed"), + literal("client-half-failed") + ]), + "pluginRunId": intersection(string(), unknown()).optional(), + "startedHere": boolean().optional(), + "message": string().optional(), + "stack": string().optional() + })]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema = union([object({ + "ok": literal(true), + "status": union([ + literal("awaiting-approval"), + literal("starting"), + literal("running") + ]), + "pluginId": intersection(string(), unknown()), + "packageId": intersection(string(), unknown()), + "pluginRunId": intersection(string(), unknown()), + "waitingFor": array(string()), + "clientWaitingFor": array(string()).optional(), + "currentPackageId": intersection(string(), unknown()).optional(), + "nextPackageId": intersection(string(), unknown()).optional(), + "mode": union([literal("run"), literal("update")]) + }), object({ + "ok": literal(false), + "reason": union([ + literal("plugin-missing"), + literal("rejected"), + literal("host-half-failed"), + literal("client-half-failed"), + literal("package-missing"), + literal("invalid-mode"), + literal("transition-in-flight"), + literal("cancelled"), + literal("not-running") + ]), + "message": string(), + "stack": string().optional() + })]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema = union([object({ "ok": literal(true) }), object({ + "ok": literal(false), + "reason": union([literal("plugin-missing"), literal("not-running")]), + "message": string() + })]); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema = array(object({ + "id": string(), + "description": string(), + "methods": array(object({ + "name": string(), + "description": string(), + "inputSchema": union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema)), + record(string(), lazy(() => JsonValueRemoteCodec$schema)) + ]), + "outputSchema": union([ + literal(null), + string(), + number(), + literal(false), + literal(true), + array(lazy(() => JsonValueRemoteCodec$schema)), + record(string(), lazy(() => JsonValueRemoteCodec$schema)) + ]) + })) + })); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema = literal(null); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema = intersection(string(), unknown()); + const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema = union([object({ + "ok": literal(true), + "wasRunning": boolean() + }), object({ + "ok": literal(false), + "reason": literal("plugin-missing"), + "message": string() + })]); + const TYPERT_REMOTE$2 = { + package: "@deepseek-ai/dsh-cordis-host-runner", + descriptors: [ + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/getClientCode", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "getClientCode", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema + } + }, + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema + } + }, + { + name: "pluginRunId", + wire: "pluginRunId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisClientSource", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 384, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "inventory", + invocation: { kind: "direct" }, + parameters: [], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory:result", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 525, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "invoke", + invocation: { kind: "direct" }, + parameters: [ + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema + } + }, + { + name: "pluginRunId", + wire: "pluginRunId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema + } + }, + { + name: "method", + wire: "method", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke:method", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema + } + }, + { + name: "args", + wire: "args", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#JsonValue", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisInvokeResult", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 741, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "reportClientGuardFailure", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema + } + }, + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema + } + }, + { + name: "pluginRunId", + wire: "pluginRunId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema + } + }, + { + name: "failure", + wire: "failure", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisErrorDetails", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure:result", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 718, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "reportRenderFailure", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema + } + }, + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema + } + }, + { + name: "pluginRunId", + wire: "pluginRunId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema + } + }, + { + name: "failure", + wire: "failure", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRenderFailure", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure:result", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 684, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveInspectQuery", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "resolveInspectQuery", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema + } + }, + { + name: "requestId", + wire: "requestId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectRequestId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema + } + }, + { + name: "resolution", + wire: "resolution", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectQueryResolution", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectResolveAck", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 511, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveRequestRun", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "resolveRequestRun", + invocation: { kind: "direct" }, + parameters: [{ + name: "requestId", + wire: "requestId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#ApprovalRequestId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema + } + }, { + name: "resolution", + wire: "resolution", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisResolveAck", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 413, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "runHostHalf", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema + } + }, + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema + } + }, + { + name: "packageId", + wire: "packageId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPackageId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema + } + }, + { + name: "mode", + wire: "mode", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicRunMode", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema + } + }, + { + name: "requestId", + wire: "requestId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:requestId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema + } + }, + { + name: "approveFutureVersions", + wire: "approveFutureVersions", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:approveFutureVersions", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisHostHalfResult", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 325, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/settleUserRun", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "settleUserRun", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [ + { + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema + } + }, + { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema + } + }, + { + name: "resolution", + wire: "resolution", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema + } + } + ], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResponse", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 438, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/stopFromPanel", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "stopFromPanel", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema + } + }, { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisStopResponse", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 480, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "syncInspectManifest", + invocation: { kind: "direct" }, + parameters: [{ + name: "providers", + wire: "providers", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:providers", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:result", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 498, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/undefineFromPanel", + service: "dynamicCordisRunner", + namespace: "dynamicCordisRunner", + method: "undefineFromPanel", + invocation: { kind: "direct" }, + scope: { + context: "agent", + wire: "agentId" + }, + parameters: [{ + name: "agent", + wire: "agentId", + source: "lookup", + lookup: "agent", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema + } + }, { + name: "pluginId", + wire: "pluginId", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisUndefineReceipt", + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema + }, + sourceLocation: { + "file": "packages/extensions/cordis-host-runner/src/index.ts", + "line": 227, + "column": 9 + } + } + ] + }; + const TYPERT_REMOTE$1 = { + package: "@deepseek-ai/dsh-host-plugin-inventory", + descriptors: [{ + id: "@deepseek-ai/dsh-host-plugin-inventory#pluginInventory/list", + service: "pluginInventory", + namespace: "pluginInventory", + method: "list", + invocation: { kind: "direct" }, + parameters: [], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-host-plugin-inventory/types#PluginInventorySnapshot", + schema: object({ "entries": array(object({ + "entryId": intersection(string(), unknown()).readonly(), + "moduleName": string().readonly(), + "enabled": boolean().readonly(), + "fiberPhase": union([ + literal(null), + literal("failed"), + literal("pending"), + literal("active"), + literal("loading"), + literal("unloading") + ]).readonly() + })).readonly() }) + }, + sourceLocation: { + "file": "packages/host/plugin-inventory/src/index.ts", + "line": 57, + "column": 3 + } + }] + }; + //#endregion + //#region ../../feedback/message-feedback/lib/typert.remote-client.js + const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema = object({ + "sessionId": intersection(string(), unknown()).readonly(), + "messageId": intersection(string(), unknown()).readonly(), + "ifVersion": intersection(string(), unknown()).readonly() + }); + const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema = union([object({ + "ok": literal(true).readonly(), + "value": object({ "absent": literal(true).readonly() }).readonly() + }), object({ + "ok": literal(false).readonly(), + "error": union([object({ + "code": literal("session-not-found").readonly(), + "sessionId": intersection(string(), unknown()).readonly() + }), object({ + "code": literal("version-conflict").readonly(), + "current": union([literal(null), object({ + "messageId": intersection(string(), unknown()).readonly(), + "rating": union([literal("positive"), literal("negative")]).readonly(), + "note": string().readonly().optional(), + "version": intersection(string(), unknown()).readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly() + })]).readonly() + })]).readonly() + })]); + const _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema = object({ "sessionId": intersection(string(), unknown()).readonly() }); + const _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema = union([object({ + "ok": literal(true).readonly(), + "value": object({ "items": array(object({ + "messageId": intersection(string(), unknown()).readonly(), + "rating": union([literal("positive"), literal("negative")]).readonly(), + "note": string().readonly().optional(), + "version": intersection(string(), unknown()).readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly() + })).readonly() }).readonly() + }), object({ + "ok": literal(false).readonly(), + "error": object({ + "code": literal("session-not-found").readonly(), + "sessionId": intersection(string(), unknown()).readonly() + }).readonly() + })]); + const _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema = object({ + "sessionId": intersection(string(), unknown()).readonly(), + "messageId": intersection(string(), unknown()).readonly(), + "rating": union([literal("positive"), literal("negative")]).readonly(), + "note": string().readonly().optional(), + "ifVersion": union([literal(null), intersection(string(), unknown())]).readonly() + }); + const _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema = union([object({ + "ok": literal(true).readonly(), + "value": object({ + "messageId": intersection(string(), unknown()).readonly(), + "rating": union([literal("positive"), literal("negative")]).readonly(), + "note": string().readonly().optional(), + "version": intersection(string(), unknown()).readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly() + }).readonly() + }), object({ + "ok": literal(false).readonly(), + "error": union([ + object({ + "code": literal("session-not-found").readonly(), + "sessionId": intersection(string(), unknown()).readonly() + }), + object({ + "code": literal("target-not-found").readonly(), + "sessionId": intersection(string(), unknown()).readonly(), + "messageId": intersection(string(), unknown()).readonly() + }), + object({ + "code": literal("version-conflict").readonly(), + "current": union([literal(null), object({ + "messageId": intersection(string(), unknown()).readonly(), + "rating": union([literal("positive"), literal("negative")]).readonly(), + "note": string().readonly().optional(), + "version": intersection(string(), unknown()).readonly(), + "createdAt": number().readonly(), + "updatedAt": number().readonly() + })]).readonly() + }), + object({ "code": literal("note-blank").readonly() }), + object({ + "code": literal("note-too-large").readonly(), + "maxBytes": number().readonly(), + "actualBytes": number().readonly() + }) + ]).readonly() + })]); + const TYPERT_REMOTE = { + package: "@deepseek-ai/dsh-message-feedback", + descriptors: [ + { + id: "@deepseek-ai/dsh-message-feedback#messageFeedback/delete", + service: "messageFeedback", + namespace: "messageFeedback", + method: "delete", + invocation: { kind: "direct" }, + parameters: [{ + name: "request", + wire: "request", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteRequest", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteResult", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema + }, + sourceLocation: { + "file": "packages/feedback/message-feedback/src/index.ts", + "line": 272, + "column": 3 + } + }, + { + id: "@deepseek-ai/dsh-message-feedback#messageFeedback/list", + service: "messageFeedback", + namespace: "messageFeedback", + method: "list", + invocation: { kind: "direct" }, + parameters: [{ + name: "request", + wire: "request", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListRequest", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListResult", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema + }, + sourceLocation: { + "file": "packages/feedback/message-feedback/src/index.ts", + "line": 190, + "column": 9 + } + }, + { + id: "@deepseek-ai/dsh-message-feedback#messageFeedback/put", + service: "messageFeedback", + namespace: "messageFeedback", + method: "put", + invocation: { kind: "direct" }, + parameters: [{ + name: "request", + wire: "request", + source: "json", + codec: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutRequest", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema + } + }], + result: { + mode: "strict", + typeSymbol: "@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutResult", + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema + }, + sourceLocation: { + "file": "packages/feedback/message-feedback/src/index.ts", + "line": 206, + "column": 3 + } + } + ] + }; + //#endregion + //#region lib/types/client/index.js + /** Platform-neutral assembly of generated Host Remote contributions. */ + /** Required service: the typed Client Remote contribution mount. */ + const inject = ["remote"]; + /** + * Mount the Host capabilities explicitly selected for this Client assembly. + * @param ctx - Client Cordis root carrying the typed API service. + * @returns disposer after every selected Remote namespace is ready. + */ + async function apply(ctx) { + const disposers = []; + try { + for (const contribution of [ + TYPERT_REMOTE$4, + TYPERT_REMOTE$3, + TYPERT_REMOTE$2, + TYPERT_REMOTE$1, + TYPERT_REMOTE + ]) disposers.push(await ctx.remote.$mount(contribution)); + } catch (error) { + for (const dispose of disposers.reverse()) await dispose(); + throw error; + } + return async () => { + for (const dispose of disposers.reverse()) await dispose(); + }; + } + //#endregion + exports.apply = apply; + exports.inject = inject; + return module.exports; + } +}); + +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/index.js new file mode 100644 index 0000000..1946294 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/index.js @@ -0,0 +1,172 @@ +import { TypertLookupFailure } from "@deepseek-ai/dsh-typert-protocol"; +//#region lib/types/remote-events.js +/** +* The one home of this application's forwarded-Host-event allowlist. Both +* compiler faces list this file, so the Host forwarding loop and the consumer +* `ctx.remote.$on` key face read one declaration instead of two copies that +* could drift; `./types.ts` derives the type projection from it and stays +* type-only. +*/ +/** +* Host events this application forwards to consumers verbatim: no projection, +* no redaction, no renaming. The wire name is the Host cordis event name and +* the payload is its argument list, so this array is simultaneously the whole +* control point over what a consumer can receive and the legal key set of +* `ctx.remote.$on`. Forwarding one more event is an entry here and nothing +* else. +*/ +const API_REMOTE_FORWARDED_EVENTS = [ + "agent-preset/selected", + "commands/change", + "credentials/updated", + "cordis/request-run", + "cordis/request-run-resolved", + "cordis/dynamic-package", + "cordis/dynamic-retract", + "cordis/inspect-query", + "cordis/inspect-query-resolved", + "llm/adapters-updated", + "settings/document-updated" +]; +//#endregion +//#region lib/types/agent-lookup.js +/** Host BFF policy for resolving Remote Agent and Session identities. */ +/** Cold identity absent from the durable session store. */ +var ApiRemoteSessionNotFound = class extends Error {}; +/** Session identity whose lifecycle belongs to subagent routing. */ +var ApiRemoteSubagentSessionOwnership = class extends Error { + sessionId; + /** + * Construct the ownership fence. + * @param sessionId - identity reserved to subagent routing. + */ + constructor(sessionId) { + super(`session "${sessionId}" is a subagent session; use subagent delivery`); + this.sessionId = sessionId; + } +}; +/** +* Test whether generic Host routing must leave an identity to subagent routing. +* @param ctx - Host Context carrying the live Agent registry. +* @param session - attached or live Session metadata. +* @param agent - live Agent when one is registered. +* @returns whether generic Remote and legacy API calls must reject the identity. +*/ +function hasApiRemoteSubagentOwner(ctx, session, agent) { + if (session.header.origin === "subagent") return true; + const parentId = session.header.parentSession; + if (parentId === void 0 || agent === void 0) return false; + const parent = ctx.agents.get(parentId); + return parent !== void 0 && ctx.agents.isOwnedBy(agent.id, parent); +} +/** +* Build the stable caller-facing ownership rejection. +* @param sessionId - identity reserved to subagent routing. +* @returns the existing `agent-busy` RPC shape. +*/ +function apiRemoteSubagentOwnershipError(sessionId) { + return { + code: "agent-busy", + message: `session "${sessionId}" is owned by subagent routing`, + details: { reason: "use subagent delivery for this child session" } + }; +} +/** +* Inspect one cold served session without repairing, resuming, or publishing it. +* @param ctx - Host Context carrying the optional persistence provider. +* @param sessionId - durable identity to inspect. +* @returns detached metadata and events for a servable session. +* @throws {@link ApiRemoteSessionNotFound} when the identity has no project-backed session. +*/ +async function inspectApiRemoteSession(ctx, sessionId) { + const persistence = ctx.get("sessionPersistence"); + if (persistence === void 0) throw new Error("session persistence is not configured (load a dsh-session-persistence backend)"); + const meta = (await persistence.list()).find((candidate) => candidate.id === sessionId); + if (meta === void 0 || meta.cwd === void 0) throw new ApiRemoteSessionNotFound(`session "${sessionId}" not found`); + const inspected = await persistence.inspect(sessionId); + if (inspected.meta.cwd === void 0) throw new ApiRemoteSessionNotFound(`session "${sessionId}" not found`); + return { + meta: inspected.meta, + events: [...inspected.events] + }; +} +/** +* Create the Host's shared Agent resolver and configure Agent/Session Typert lookups. +* Live Agents are reused, ordinary cold sessions resume once per identity, and +* subagent-owned identities retain the legacy `agent-busy` fence. +* @param ctx - owning Host Context. +* @param options - defaults and Agent-scope setup used only for cold resume. +* @returns resolver shared by legacy API Proxy methods and Typert lookups. +*/ +function createApiRemoteAgentResolver(ctx, options) { + const resumes = /* @__PURE__ */ new Map(); + const fencedLiveAgent = (sessionId) => { + const live = ctx.agents.get(sessionId); + if (live === void 0) return void 0; + if (hasApiRemoteSubagentOwner(ctx, live.session, live)) return { error: apiRemoteSubagentOwnershipError(sessionId) }; + return { agent: live }; + }; + const agentFor = async (sessionId) => { + const fenced = fencedLiveAgent(sessionId); + if (fenced !== void 0) return fenced; + const attached = ctx.sessions.get(sessionId); + if (attached !== void 0 && hasApiRemoteSubagentOwner(ctx, attached, void 0)) return { error: apiRemoteSubagentOwnershipError(sessionId) }; + let resume = resumes.get(sessionId); + if (resume === void 0) { + resume = (async () => { + try { + const inspected = await inspectApiRemoteSession(ctx, sessionId); + if (hasApiRemoteSubagentOwner(ctx, { header: inspected.meta }, void 0)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + const setup = options.setup === void 0 ? void 0 : await options.setup(inspected); + const publishedSession = ctx.sessions.get(sessionId); + const publishedAgent = ctx.agents.get(sessionId); + if (publishedSession !== void 0 && hasApiRemoteSubagentOwner(ctx, publishedSession, publishedAgent)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + return (await ctx.agents.resume({ + resumeSessionId: sessionId, + ...options.agentOptions === void 0 ? {} : { agentOptions: options.agentOptions() }, + ...setup === void 0 ? {} : { setup } + })).agent; + } finally { + resumes.delete(sessionId); + } + })(); + resumes.set(sessionId, resume); + } + try { + return { agent: await resume }; + } catch (error) { + if (error instanceof ApiRemoteSessionNotFound) return { error: { + code: "session-not-found", + message: error.message, + details: { sessionId } + } }; + if (error instanceof ApiRemoteSubagentSessionOwnership) return { error: apiRemoteSubagentOwnershipError(error.sessionId) }; + const fenced = fencedLiveAgent(sessionId); + if (fenced !== void 0) return fenced; + const attached = ctx.sessions.get(sessionId); + if (attached !== void 0 && hasApiRemoteSubagentOwner(ctx, attached, void 0)) return { error: apiRemoteSubagentOwnershipError(sessionId) }; + return { error: { + code: "internal", + message: `resume failed for session "${sessionId}": ${String(error)}`, + details: {} + } }; + } + }; + ctx.inject(["typert"], (typeCtx) => { + const resolveAgent = async (sessionId) => { + const found = await agentFor(sessionId); + if ("error" in found) throw new TypertLookupFailure(found.error); + return found.agent; + }; + typeCtx.typert.lookups.configure("agent", resolveAgent); + typeCtx.typert.lookups.configure("session", async (sessionId) => (await resolveAgent(sessionId)).session); + typeCtx.typert.contexts.configureHost("agent", async (sessionId) => (await resolveAgent(sessionId)).ctx); + }); + return agentFor; +} +//#endregion +//#region lib/types/index.js +/** Host plugin body; the selected contributions mount only in Client environments. */ +function apply() {} +//#endregion +export { API_REMOTE_FORWARDED_EVENTS, ApiRemoteSessionNotFound, ApiRemoteSubagentSessionOwnership, apiRemoteSubagentOwnershipError, apply, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/invariant.js new file mode 100644 index 0000000..3c389fb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/invariant.js @@ -0,0 +1,17 @@ +//#region lib/types/invariant.js +/** Package-owned invariant companion for `@deepseek-ai/dsh-api-remotes`. */ +const PACKAGE_NAME = "@deepseek-ai/dsh-api-remotes"; +/** Cordis companion plugin name. */ +const name = "api-remotes-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** No runtime invariant: Typert and the Agent/Session registries own the observed relationships. */ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.d.ts new file mode 100644 index 0000000..97abfcf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.d.ts @@ -0,0 +1,95 @@ +/** Host BFF policy for resolving Remote Agent and Session identities. */ +import type { Context } from '@deepseek-ai/cordis'; +import type { Agent, AgentOptions, AgentSetup } from '@deepseek-ai/dsh-agent'; +import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session'; +/** Caller-facing failures preserved by the Gateway's RPC adapter. */ +export type ApiRemoteLookupError = { + readonly code: 'agent-busy'; + readonly message: string; + readonly details: { + readonly reason: string; + }; +} | { + readonly code: 'session-not-found'; + readonly message: string; + readonly details: { + readonly sessionId: SessionId; + }; +} | { + readonly code: 'internal'; + readonly message: string; + readonly details: Record; +}; +/** Result of resolving one session identity to its live Agent. */ +export type ApiRemoteAgentResult = { + readonly agent: Agent; +} | { + readonly error: ApiRemoteLookupError; +}; +/** Resume configuration supplied by the owning Host composition. */ +export interface ApiRemoteAgentOptions { + /** Read the per-Agent defaults when a cold identity must resume. */ + readonly agentOptions?: () => AgentOptions; + /** + * Build the Host-specific Agent-scope composition completed before + * publication. Keyed by the resumed session itself because what a Host + * installs may depend on what that session recorded: an agent preset fixes + * the tools its history was produced under, so rebuilding it under another + * composition would replay tool calls the agent can no longer make. The + * events come along because a session's own record of such a choice may be + * an event rather than a header field. + * @param session - the resumed session's persisted header and event log. + * @returns the Agent-scope setup to run before publication. + */ + readonly setup?: (session: { + meta: SessionHeader; + events: readonly SessionEvent[]; + }) => AgentSetup | Promise; +} +/** Cold identity absent from the durable session store. */ +export declare class ApiRemoteSessionNotFound extends Error { +} +/** Session identity whose lifecycle belongs to subagent routing. */ +export declare class ApiRemoteSubagentSessionOwnership extends Error { + readonly sessionId: SessionId; + /** + * Construct the ownership fence. + * @param sessionId - identity reserved to subagent routing. + */ + constructor(sessionId: SessionId); +} +/** + * Test whether generic Host routing must leave an identity to subagent routing. + * @param ctx - Host Context carrying the live Agent registry. + * @param session - attached or live Session metadata. + * @param agent - live Agent when one is registered. + * @returns whether generic Remote and legacy API calls must reject the identity. + */ +export declare function hasApiRemoteSubagentOwner(ctx: Context, session: Pick, agent: Agent | undefined): boolean; +/** + * Build the stable caller-facing ownership rejection. + * @param sessionId - identity reserved to subagent routing. + * @returns the existing `agent-busy` RPC shape. + */ +export declare function apiRemoteSubagentOwnershipError(sessionId: SessionId): ApiRemoteLookupError; +/** + * Inspect one cold served session without repairing, resuming, or publishing it. + * @param ctx - Host Context carrying the optional persistence provider. + * @param sessionId - durable identity to inspect. + * @returns detached metadata and events for a servable session. + * @throws {@link ApiRemoteSessionNotFound} when the identity has no project-backed session. + */ +export declare function inspectApiRemoteSession(ctx: Context, sessionId: SessionId): Promise<{ + meta: SessionHeader; + events: SessionEvent[]; +}>; +/** + * Create the Host's shared Agent resolver and configure Agent/Session Typert lookups. + * Live Agents are reused, ordinary cold sessions resume once per identity, and + * subagent-owned identities retain the legacy `agent-busy` fence. + * @param ctx - owning Host Context. + * @param options - defaults and Agent-scope setup used only for cold resume. + * @returns resolver shared by legacy API Proxy methods and Typert lookups. + */ +export declare function createApiRemoteAgentResolver(ctx: Context, options: ApiRemoteAgentOptions): (sessionId: SessionId) => Promise; +//# sourceMappingURL=agent-lookup.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.js new file mode 100644 index 0000000..a2f7ce4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/agent-lookup.js @@ -0,0 +1,166 @@ +/** Host BFF policy for resolving Remote Agent and Session identities. */ +import { TypertLookupFailure } from '@deepseek-ai/dsh-typert-protocol'; +/** Cold identity absent from the durable session store. */ +export class ApiRemoteSessionNotFound extends Error { +} +/** Session identity whose lifecycle belongs to subagent routing. */ +export class ApiRemoteSubagentSessionOwnership extends Error { + sessionId; + /** + * Construct the ownership fence. + * @param sessionId - identity reserved to subagent routing. + */ + constructor(sessionId) { + super(`session "${sessionId}" is a subagent session; use subagent delivery`); + this.sessionId = sessionId; + } +} +/** + * Test whether generic Host routing must leave an identity to subagent routing. + * @param ctx - Host Context carrying the live Agent registry. + * @param session - attached or live Session metadata. + * @param agent - live Agent when one is registered. + * @returns whether generic Remote and legacy API calls must reject the identity. + */ +export function hasApiRemoteSubagentOwner(ctx, session, agent) { + if (session.header.origin === 'subagent') + return true; + const parentId = session.header.parentSession; + if (parentId === undefined || agent === undefined) + return false; + const parent = ctx.agents.get(parentId); + return parent !== undefined && ctx.agents.isOwnedBy(agent.id, parent); +} +/** + * Build the stable caller-facing ownership rejection. + * @param sessionId - identity reserved to subagent routing. + * @returns the existing `agent-busy` RPC shape. + */ +export function apiRemoteSubagentOwnershipError(sessionId) { + return { + code: 'agent-busy', + message: `session "${sessionId}" is owned by subagent routing`, + details: { reason: 'use subagent delivery for this child session' }, + }; +} +/** + * Inspect one cold served session without repairing, resuming, or publishing it. + * @param ctx - Host Context carrying the optional persistence provider. + * @param sessionId - durable identity to inspect. + * @returns detached metadata and events for a servable session. + * @throws {@link ApiRemoteSessionNotFound} when the identity has no project-backed session. + */ +export async function inspectApiRemoteSession(ctx, sessionId) { + const persistence = ctx.get('sessionPersistence'); + if (persistence === undefined) { + throw new Error('session persistence is not configured (load a dsh-session-persistence backend)'); + } + const meta = (await persistence.list()).find(candidate => candidate.id === sessionId); + if (meta === undefined || meta.cwd === undefined) { + throw new ApiRemoteSessionNotFound(`session "${sessionId}" not found`); + } + const inspected = await persistence.inspect(sessionId); + if (inspected.meta.cwd === undefined) { + throw new ApiRemoteSessionNotFound(`session "${sessionId}" not found`); + } + return { meta: inspected.meta, events: [...inspected.events] }; +} +/** + * Create the Host's shared Agent resolver and configure Agent/Session Typert lookups. + * Live Agents are reused, ordinary cold sessions resume once per identity, and + * subagent-owned identities retain the legacy `agent-busy` fence. + * @param ctx - owning Host Context. + * @param options - defaults and Agent-scope setup used only for cold resume. + * @returns resolver shared by legacy API Proxy methods and Typert lookups. + */ +export function createApiRemoteAgentResolver(ctx, options) { + const resumes = new Map(); + const fencedLiveAgent = (sessionId) => { + const live = ctx.agents.get(sessionId); + if (live === undefined) + return undefined; + if (hasApiRemoteSubagentOwner(ctx, live.session, live)) { + return { error: apiRemoteSubagentOwnershipError(sessionId) }; + } + return { agent: live }; + }; + const agentFor = async (sessionId) => { + const fenced = fencedLiveAgent(sessionId); + if (fenced !== undefined) + return fenced; + const attached = ctx.sessions.get(sessionId); + if (attached !== undefined && hasApiRemoteSubagentOwner(ctx, attached, undefined)) { + return { error: apiRemoteSubagentOwnershipError(sessionId) }; + } + let resume = resumes.get(sessionId); + if (resume === undefined) { + resume = (async () => { + try { + const inspected = await inspectApiRemoteSession(ctx, sessionId); + if (hasApiRemoteSubagentOwner(ctx, { header: inspected.meta }, undefined)) { + throw new ApiRemoteSubagentSessionOwnership(sessionId); + } + // Built from the inspected session before the published re-checks + // below, so those stay adjacent to `resume` and a Host setup that + // awaits (composing a preset, say) does not widen the collision + // window. + const setup = options.setup === undefined ? undefined : await options.setup(inspected); + const publishedSession = ctx.sessions.get(sessionId); + const publishedAgent = ctx.agents.get(sessionId); + if (publishedSession !== undefined + && hasApiRemoteSubagentOwner(ctx, publishedSession, publishedAgent)) { + throw new ApiRemoteSubagentSessionOwnership(sessionId); + } + const handle = await ctx.agents.resume({ + resumeSessionId: sessionId, + ...options.agentOptions === undefined ? {} : { agentOptions: options.agentOptions() }, + ...setup === undefined ? {} : { setup }, + }); + return handle.agent; + } + finally { + resumes.delete(sessionId); + } + })(); + resumes.set(sessionId, resume); + } + try { + return { agent: await resume }; + } + catch (error) { + if (error instanceof ApiRemoteSessionNotFound) { + return { error: { code: 'session-not-found', message: error.message, details: { sessionId } } }; + } + if (error instanceof ApiRemoteSubagentSessionOwnership) { + return { error: apiRemoteSubagentOwnershipError(error.sessionId) }; + } + const fenced = fencedLiveAgent(sessionId); + if (fenced !== undefined) + return fenced; + const attached = ctx.sessions.get(sessionId); + if (attached !== undefined && hasApiRemoteSubagentOwner(ctx, attached, undefined)) { + return { error: apiRemoteSubagentOwnershipError(sessionId) }; + } + return { + error: { + code: 'internal', + message: `resume failed for session "${sessionId}": ${String(error)}`, + details: {}, + }, + }; + } + }; + ctx.inject(['typert'], (typeCtx) => { + const resolveAgent = async (sessionId) => { + const found = await agentFor(sessionId); + if ('error' in found) + throw new TypertLookupFailure(found.error); + return found.agent; + }; + typeCtx.typert.lookups.configure('agent', resolveAgent); + typeCtx.typert.lookups.configure('session', async (sessionId) => (await resolveAgent(sessionId)).session); + typeCtx.typert.contexts.configureHost('agent', async (sessionId) => (await resolveAgent(sessionId)).ctx); + }); + return agentFor; +} +//# sourceMappingURL=agent-lookup.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.d.ts new file mode 100644 index 0000000..7032aa4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.d.ts @@ -0,0 +1,41 @@ +/** Platform-neutral assembly of generated Host Remote contributions. */ +import type { Context } from '@deepseek-ai/cordis'; +import type { TypertClientRemote } from '@deepseek-ai/dsh-typert-protocol'; +export type { TypertClientRemote as ClientRemote } from '@deepseek-ai/dsh-typert-protocol'; +export type { PluginInventorySnapshot } from '@deepseek-ai/dsh-host-plugin-inventory/types'; +export type {} from '@deepseek-ai/dsh-commands/remote'; +export type {} from '@deepseek-ai/dsh-goal/remote'; +export type {} from '@deepseek-ai/dsh-host-plugin-inventory/remote'; +export type {} from '@deepseek-ai/dsh-message-feedback/remote'; +export type { ApiRemoteForwardedEvent } from '../types.ts'; +export type {} from '@deepseek-ai/dsh-commands/types'; +export type {} from '@deepseek-ai/dsh-cordis-host-runner/types'; +export type {} from '@deepseek-ai/dsh-credentials/types'; +export type {} from '@deepseek-ai/dsh-llm/types'; +export type {} from '@deepseek-ai/dsh-agent-presets/types'; +export type {} from '@deepseek-ai/dsh-settings/types'; +/** + * The carrier's Client-facing types, re-exported so a business package names one + * assembly package instead of both this facade and the Connection plugin. Type-only: + * the carrier's runtime values stay behind their own module edge. + */ +export type { ClientResponse, ConfigurableProviderView, ConnectionHandle, ConnectionSinks, ContentBlock, CredentialView, DirectoryListing, DiscoveredModelView, HistoryEntry, HostFrame, IApiClient, MessageId, ModelCatalogFailure, ModelProviderGroup, ModelReasoningEffort, ModelSelection, MuxFrame, PromptContentPart, QuestionResponsePayload, QueueAction, RpcError, RpcId, RpcReceipt, RpcRequest, RpcResponse, RpcResult, SessionId, SessionModels, SessionSearchItem, SessionSummary, SettingsNamespaceView, SettingsPathOpView, SkillEntry, StreamChunk, SubagentAddress, SubagentCatalog, JobView, ToolCallView, ToolEventView, ToolResultView, WorkspaceId, WorkspaceView, } from '@deepseek-ai/dsh-client-connection/client'; +export type {} from '@deepseek-ai/dsh-api-gateway/client'; +export type {} from '@deepseek-ai/dsh-cordis-host-runner/remote'; +export type { ApprovalRequestId, CordisHalfState, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisDynamicRunMode, CordisInspectMethodManifest, CordisInspectPlatform, CordisInspectProviderManifest, CordisInspectProviderView, CordisInspectQueryRequest, CordisInspectQueryResolution, CordisInspectQueryResolved, CordisInspectRequestId, CordisInspectResolveAck, CordisRunDiagnostic, CordisRunStatus, DynamicCordisClientSource, DynamicCordisHostHalfResult, DynamicCordisInventoryRow, DynamicCordisInvokeResult, DynamicCordisPackage, DynamicCordisRequestResolved, DynamicCordisResolveAck, DynamicCordisRetracted, DynamicCordisRunRequest, DynamicCordisRunResolution, DynamicCordisRunAttempt, DynamicCordisRunResponse, DynamicCordisStopResponse, DynamicCordisUndefineReceipt, RequestRunOutcome, } from '@deepseek-ai/dsh-cordis-host-runner/types'; +export type { JsonValue } from '@deepseek-ai/dsh-session/types'; +declare module '@deepseek-ai/cordis' { + interface Context { + /** Generated Remote namespaces selected by this Client assembly. */ + remote: TypertClientRemote; + } +} +/** Required service: the typed Client Remote contribution mount. */ +export declare const inject: string[]; +/** + * Mount the Host capabilities explicitly selected for this Client assembly. + * @param ctx - Client Cordis root carrying the typed API service. + * @returns disposer after every selected Remote namespace is ready. + */ +export declare function apply(ctx: Context): Promise<() => Promise>; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.js new file mode 100644 index 0000000..ba70087 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/client/index.js @@ -0,0 +1,35 @@ +/** Platform-neutral assembly of generated Host Remote contributions. */ +import commandsRemote from '@deepseek-ai/dsh-commands/remote'; +import goalsRemote from '@deepseek-ai/dsh-goal/remote'; +import dynamicRemote from '@deepseek-ai/dsh-cordis-host-runner/remote'; +import pluginInventoryRemote from '@deepseek-ai/dsh-host-plugin-inventory/remote'; +import messageFeedbackRemote from '@deepseek-ai/dsh-message-feedback/remote'; +/** Required service: the typed Client Remote contribution mount. */ +export const inject = ['remote']; +/** + * Mount the Host capabilities explicitly selected for this Client assembly. + * @param ctx - Client Cordis root carrying the typed API service. + * @returns disposer after every selected Remote namespace is ready. + */ +export async function apply(ctx) { + const disposers = []; + try { + for (const contribution of [ + commandsRemote, goalsRemote, dynamicRemote, pluginInventoryRemote, messageFeedbackRemote, + ]) { + disposers.push(await ctx.remote.$mount(contribution)); + } + } + catch (error) { + for (const dispose of disposers.reverse()) + await dispose(); + throw error; + } + // Unwound in reverse mount order, so a namespace never outlives one mounted + // after it. + return async () => { + for (const dispose of disposers.reverse()) + await dispose(); + }; +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.d.ts new file mode 100644 index 0000000..986d541 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.d.ts @@ -0,0 +1,8 @@ +/** Host BFF entry and Loader shell for the Remote contribution assembly. */ +export { ApiRemoteSessionNotFound, ApiRemoteSubagentSessionOwnership, apiRemoteSubagentOwnershipError, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession, } from './agent-lookup.ts'; +export type { ApiRemoteAgentOptions, ApiRemoteAgentResult, ApiRemoteLookupError, } from './agent-lookup.ts'; +export { API_REMOTE_FORWARDED_EVENTS } from './remote-events.ts'; +export type { ApiRemoteForwardedEvent } from './types.ts'; +/** Host plugin body; the selected contributions mount only in Client environments. */ +export declare function apply(): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.js new file mode 100644 index 0000000..bc7bff8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/index.js @@ -0,0 +1,16 @@ +/** Host BFF entry and Loader shell for the Remote contribution assembly. */ +import { API_REMOTE_FORWARDED_EVENTS } from "./remote-events.js"; +export { ApiRemoteSessionNotFound, ApiRemoteSubagentSessionOwnership, apiRemoteSubagentOwnershipError, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession, } from "./agent-lookup.js"; +export { API_REMOTE_FORWARDED_EVENTS } from "./remote-events.js"; +// Shape gate over the allowlist, kept in the Host face because the Host's event +// vocabulary is the authoritative one. It pins three things at compile time: +// every entry NAMES a declared event (the predicate is keyed on `keyof +// Events`), no entry BINDS a Scope (a scoped event's `ThisParameterType` is not +// `unknown`, which is how "must not depend on AgentScope" is stated statically), +// and every entry is ONE-WAY (a waterfall or bail shape returns something other +// than void and is excluded). Widening the array to an event that fails any of +// these fails here, not on the wire. +API_REMOTE_FORWARDED_EVENTS; +/** Host plugin body; the selected contributions mount only in Client environments. */ +export function apply() { } +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.d.ts new file mode 100644 index 0000000..caa7541 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned invariant companion for `@deepseek-ai/dsh-api-remotes`. */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "api-remotes-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.js new file mode 100644 index 0000000..8807737 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/invariant.js @@ -0,0 +1,16 @@ +/** Package-owned invariant companion for `@deepseek-ai/dsh-api-remotes`. */ +const PACKAGE_NAME = '@deepseek-ai/dsh-api-remotes'; +/** Cordis companion plugin name. */ +export const name = 'api-remotes-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** No runtime invariant: Typert and the Agent/Session registries own the observed relationships. */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.d.ts new file mode 100644 index 0000000..b97dbc4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.d.ts @@ -0,0 +1,17 @@ +/** + * The one home of this application's forwarded-Host-event allowlist. Both + * compiler faces list this file, so the Host forwarding loop and the consumer + * `ctx.remote.$on` key face read one declaration instead of two copies that + * could drift; `./types.ts` derives the type projection from it and stays + * type-only. + */ +/** + * Host events this application forwards to consumers verbatim: no projection, + * no redaction, no renaming. The wire name is the Host cordis event name and + * the payload is its argument list, so this array is simultaneously the whole + * control point over what a consumer can receive and the legal key set of + * `ctx.remote.$on`. Forwarding one more event is an entry here and nothing + * else. + */ +export declare const API_REMOTE_FORWARDED_EVENTS: readonly ["agent-preset/selected", "commands/change", "credentials/updated", "cordis/request-run", "cordis/request-run-resolved", "cordis/dynamic-package", "cordis/dynamic-retract", "cordis/inspect-query", "cordis/inspect-query-resolved", "llm/adapters-updated", "settings/document-updated"]; +//# sourceMappingURL=remote-events.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.js new file mode 100644 index 0000000..7ba8f5d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.js @@ -0,0 +1,29 @@ +/** + * The one home of this application's forwarded-Host-event allowlist. Both + * compiler faces list this file, so the Host forwarding loop and the consumer + * `ctx.remote.$on` key face read one declaration instead of two copies that + * could drift; `./types.ts` derives the type projection from it and stays + * type-only. + */ +/** + * Host events this application forwards to consumers verbatim: no projection, + * no redaction, no renaming. The wire name is the Host cordis event name and + * the payload is its argument list, so this array is simultaneously the whole + * control point over what a consumer can receive and the legal key set of + * `ctx.remote.$on`. Forwarding one more event is an entry here and nothing + * else. + */ +export const API_REMOTE_FORWARDED_EVENTS = [ + 'agent-preset/selected', + 'commands/change', + 'credentials/updated', + 'cordis/request-run', + 'cordis/request-run-resolved', + 'cordis/dynamic-package', + 'cordis/dynamic-retract', + 'cordis/inspect-query', + 'cordis/inspect-query-resolved', + 'llm/adapters-updated', + 'settings/document-updated', +]; +//# sourceMappingURL=remote-events.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.d.ts new file mode 100644 index 0000000..178e23d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.d.ts @@ -0,0 +1,18 @@ +/** + * Type face of the forwarded-Host-event allowlist: the consumer key projection + * and the selection seat it fills. The allowlist VALUE lives in + * `./remote-events.ts`, keeping this module type-only per the package + * convention; both compiler faces list both files, so the Host forwarding loop + * and the consumer `ctx.remote.$on` key face read one declaration instead of + * two copies that could drift. + * + * @module @deepseek-ai/dsh-api-remotes/types + */ +import type { API_REMOTE_FORWARDED_EVENTS } from './remote-events.ts'; +/** Type projection of the allowlist; the consumer and the Host read this one. */ +export type ApiRemoteForwardedEvent = typeof API_REMOTE_FORWARDED_EVENTS[number]; +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteEventSelection extends Record { + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.js new file mode 100644 index 0000000..dca6a38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/types.js @@ -0,0 +1,12 @@ +/** + * Type face of the forwarded-Host-event allowlist: the consumer key projection + * and the selection seat it fills. The allowlist VALUE lives in + * `./remote-events.ts`, keeping this module type-only per the package + * convention; both compiler faces list both files, so the Host forwarding loop + * and the consumer `ctx.remote.$on` key face read one declaration instead of + * two copies that could drift. + * + * @module @deepseek-ai/dsh-api-remotes/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/package.json new file mode 100644 index 0000000..4317d0d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes/package.json @@ -0,0 +1,96 @@ +{ + "name": "@deepseek-ai/dsh-api-remotes", + "description": "Remote BFF assembly and Host Agent/Session lookup policy", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/api/remotes" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client/index.d.ts", + "default": "./lib/client.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "dsh": { + "client": { + "inject": [ + "@deepseek-ai/dsh-api-gateway" + ], + "platform": "web", + "immediately": true + } + }, + "license": "MIT", + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/client.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.7", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.7", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.7", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.7", + "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.7", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.7", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.7", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.7", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.7", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.7", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.7", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "scripts": { + "bundle": "tsdown", + "watch": "tsdown --watch" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-commands b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-commands new file mode 120000 index 0000000..75a57f5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-commands @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-cordis-host-runner b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-cordis-host-runner new file mode 120000 index 0000000..a8f80c4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-cordis-host-runner @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-credentials b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-credentials new file mode 120000 index 0000000..a0353d6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-credentials @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-goal b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-goal new file mode 120000 index 0000000..0ededa6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-goal @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-host-plugin-inventory b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-host-plugin-inventory new file mode 120000 index 0000000..c8c32b0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-host-plugin-inventory @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-message-feedback b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-message-feedback new file mode 120000 index 0000000..1629586 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-message-feedback @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..5362978 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-settings b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-settings new file mode 120000 index 0000000..a0d8497 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-settings @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..a2fcff1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-typert-registry b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-typert-registry new file mode 120000 index 0000000..07c8e9b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-typert-registry @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.i18n.yaml new file mode 100644 index 0000000..d293beb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/atomic-write/README.md +README.md: a767f24064c368b60d85fed6fa1d88349cab9587 +README.zh.md: 6388e264898e0025fb6586acecab450be3eb9e55 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.md new file mode 100644 index 0000000..a767f24 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.md @@ -0,0 +1,45 @@ +# dsh-atomic-write + +English | [中文](README.zh.md) + +Zero-dependency atomic file replacement shared by file-backed stores that must never leave partial, symlink-hijacked, or wider-than-intended content on disk — the user-settings document (`dsh-settings-file`) and the credentials store (`dsh-credentials-local`). + +## Surface + +```ts +import { withFileLock, writeFileAtomic } from '@deepseek-ai/dsh-atomic-write' + +declare const text: string +declare const render: (previous: string) => string + +await writeFileAtomic('/home/u/.dsh/settings.yaml', text, { mode: 0o600 }) + +// Read-modify-write against the same file from several processes. +await withFileLock('/home/u/.dsh/settings.yaml', async () => { + await writeFileAtomic('/home/u/.dsh/settings.yaml', render(text), { mode: 0o600 }) +}) +``` + +`writeFileAtomic` commits one already-rendered string. The contract, in the order failures would exploit it: + +- **Exclusive-create temp** (`wx`, random suffix): the open refuses to follow a symlink planted at a guessable temp path. +- **The fresh inode carries `mode` through the rename**: replacing a wider-permission file narrows it without a chmod race. `mode` is required so the permission decision stays visible at every call site (subject to the process umask, like every fresh inode). +- **`rename` replaces a symlinked target itself**, never writing through to its referent. +- **Same-directory sibling** keeps the rename on one filesystem, so the swap stays atomic. +- Parent directories are created; on any failure the temp is removed and the failure rethrown; readers observe either the old or the new complete content. + +`withFileLock` serializes the writers of one file across processes, for the read-render-commit cycles a bare atomic commit cannot make safe on its own. The lock is a `wx`-created `.lock` sibling, so readers never contend; waiters back off exponentially and fail with a timeout rather than block forever. A contender never removes the existing lock: age cannot distinguish a crashed owner from a paused live writer. + +## Model Experience + +None, as this is a pure filesystem primitive; nothing here reaches a model request. + +#### KV Cache effect + +None; nothing here enters a request prefix. + +## Known Limitations and Deferred Work + +- **Atomic, not durable** — no `fsync` of the file or its directory, so after a crash the rename may be observed unwound. The file-backed stores here re-read and republish on boot, keeping durability the caller's policy. +- **String content only** — no `Buffer` or stream form until a consumer needs one. +- **Orphaned locks require operator recovery** — a process that exits while holding the lock can leave the sibling behind. Later writers time out without deleting it; an operator removes it only after verifying that no writer still owns it. File age alone is not safe evidence of abandonment. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.zh.md new file mode 100644 index 0000000..6388e26 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/README.zh.md @@ -0,0 +1,45 @@ +# dsh-atomic-write + +[English](README.md) | 中文 + +零依赖的原子文件替换,供绝不允许在磁盘上留下不完整、被符号链接劫持或权限过宽内容的文件型存储共用:用户设置文档(`dsh-settings-file`)与凭据存储(`dsh-credentials-local`)。 + +## 接口面 + +```ts +import { withFileLock, writeFileAtomic } from '@deepseek-ai/dsh-atomic-write' + +declare const text: string +declare const render: (previous: string) => string + +await writeFileAtomic('/home/u/.dsh/settings.yaml', text, { mode: 0o600 }) + +// Read-modify-write against the same file from several processes. +await withFileLock('/home/u/.dsh/settings.yaml', async () => { + await writeFileAtomic('/home/u/.dsh/settings.yaml', render(text), { mode: 0o600 }) +}) +``` + +`writeFileAtomic` 提交一份已经渲染好的字符串。约定按故障利用它的先后顺序列出: + +- **独占创建临时文件**(`wx` + 随机后缀):open 拒绝跟随预先埋在可猜测临时路径上的符号链接。 +- **全新 inode 携带 `mode` 走完 rename**:替换权限过宽的旧文件时直接收窄,不存在 chmod 竞态。`mode` 为必填,让权限决策始终可见于每个调用点(与所有新建 inode 一样受进程 umask 影响)。 +- **`rename` 替换的是符号链接目标本身**,绝不写穿到其指向的文件。 +- **同目录兄弟文件**保证 rename 落在同一文件系统上,交换保持原子。 +- 自动创建父目录;任何失败都会移除临时文件并重新抛出该失败;读取方只会观察到旧内容或完整的新内容。 + +`withFileLock` 跨进程串行化同一文件的写入方,服务于单靠原子提交无法保证安全的读-渲染-提交循环。锁是以 `wx` 创建的同目录 `.lock`,因此读取方从不参与竞争;等待方按指数退避,超时即失败而非无限阻塞。竞争者绝不移除现有锁:锁龄无法区分已经崩溃的所有者与被暂停但仍存活的写入方。 + +## 模型体验 + +无:本包是纯文件系统原语,此处没有任何内容会到达模型请求。 + +#### KV Cache 影响 + +无;此处没有任何内容会进入请求前缀。 + +## 已知限制与暂缓事项 + +- **原子但不保证持久**——不对文件或其所在目录做 `fsync`,因此崩溃后可能观察到 rename 被回退。此处的文件型存储在启动时重新读取并重新发布,把持久性留作调用方的策略。 +- **仅支持字符串内容**——在有消费方需要之前,不提供 `Buffer` 或流式形态。 +- **遗留锁需要操作者恢复**——进程持锁退出时可能留下同级锁文件。后续写入方超时也不会删除它;操作者只有在确认没有写入方仍拥有该锁后才会移除。文件存续时间本身不能安全证明它已无人持有。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/index.js new file mode 100644 index 0000000..75f4553 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/index.js @@ -0,0 +1,97 @@ +import { randomBytes } from "node:crypto"; +import { mkdir, rename, rm, writeFile } from "node:fs/promises"; +import { dirname } from "node:path"; +//#region lib/types/index.js +/** +* Zero-dependency atomic file replacement and writer coordination. +* `writeFileAtomic` writes a random-suffix sibling with exclusive create and +* the caller's permission bits, then renames it over the target, so readers +* observe either the old or the new complete content and a replaced file ends +* up with exactly the stated mode. `withFileLock` serializes cross-process +* writers of one file through a `wx`-created `.lock` sibling, so a +* read-modify-write cycle can never resurrect a state another writer just +* replaced; readers stay lock-free because the rename commit is atomic. +* @module @deepseek-ai/dsh-atomic-write +*/ +/** +* Replace `filename` with `content` in one atomic step, creating parent +* directories. The content is first written to a random-suffix sibling opened +* with exclusive create (`wx`): the open refuses to follow a symlink planted +* at the temp path, and the fresh inode carries `options.mode` through the +* rename, so replacing a wider-permission file narrows it without a chmod +* race. The rename also replaces a symlinked target itself instead of writing +* through to its referent, and the same-directory sibling keeps the rename on +* one filesystem. On any failure the temp file is removed and the failure +* rethrown. Crash durability (fsync) is out of scope. +* @param filename - final path receiving the content. +* @param content - complete next file content. +* @param options - permission bits for the replacement inode. +*/ +async function writeFileAtomic(filename, content, options) { + await mkdir(dirname(filename), { + recursive: true, + ...options.dirMode === void 0 ? {} : { mode: options.dirMode } + }); + const temp = `${filename}.${randomBytes(6).toString("hex")}.tmp`; + try { + await writeFile(temp, content, { + mode: options.mode, + flag: "wx" + }); + await rename(temp, filename); + } catch (error) { + await rm(temp, { force: true }); + throw error; + } +} +/** Whether an exclusive create failed because the path already exists. */ +function isEEXIST(error) { + return error?.code === "EEXIST"; +} +/** +* Writer-lock protocol constants. These are robustness invariants of the +* cross-process write protocol, not deployment tunables: contention normally +* resolves within the retry deadline, while expiry fails the contender without +* guessing whether the existing lock still has an owner. +*/ +const LOCK_RETRY_INITIAL_MS = 20; +const LOCK_RETRY_MAX_MS = 200; +const LOCK_TIMEOUT_MS = 2e3; +/** +* Hold the cross-process writer lock for `filename` around one operation. The +* lock is a `wx`-created sibling (`.lock`); paired with the +* rename-based commit of {@link writeFileAtomic}, readers stay lock-free and +* only writers contend. Contention backs off exponentially and fails with a +* timed-out error after the deadline. The contender never removes an existing +* lock because file age cannot prove that its owner stopped; orphan recovery +* is an operator action. The parent directory must exist. +* @param filename - the file whose writers this lock serializes. +* @param operation - the read-render-commit cycle to run while holding the lock. +* @returns the operation's result; the lock releases on both outcomes. +*/ +async function withFileLock(filename, operation) { + const lockPath = `${filename}.lock`; + const deadline = Date.now() + LOCK_TIMEOUT_MS; + let delay = LOCK_RETRY_INITIAL_MS; + for (;;) { + try { + await writeFile(lockPath, `${process.pid}\n`, { + mode: 384, + flag: "wx" + }); + break; + } catch (error) { + if (!isEEXIST(error)) throw error; + } + if (Date.now() >= deadline) throw new Error(`atomic-write: timed out waiting for the writer lock at ${lockPath}`); + await new Promise((resolve) => setTimeout(resolve, delay)); + delay = Math.min(delay * 2, LOCK_RETRY_MAX_MS); + } + try { + return await operation(); + } finally { + await rm(lockPath, { force: true }); + } +} +//#endregion +export { withFileLock, writeFileAtomic }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/invariant.js new file mode 100644 index 0000000..25b89af --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-atomic-write`. +* @module @deepseek-ai/dsh-atomic-write/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-atomic-write"; +/** Cordis companion plugin name. */ +const name = "atomic-write-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this pure filesystem primitive owns no event stream or mutable runtime +* data; its replacement contract is enforced by unit tests. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/index.d.ts new file mode 100644 index 0000000..88a21eb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/index.d.ts @@ -0,0 +1,57 @@ +/** + * Zero-dependency atomic file replacement and writer coordination. + * `writeFileAtomic` writes a random-suffix sibling with exclusive create and + * the caller's permission bits, then renames it over the target, so readers + * observe either the old or the new complete content and a replaced file ends + * up with exactly the stated mode. `withFileLock` serializes cross-process + * writers of one file through a `wx`-created `.lock` sibling, so a + * read-modify-write cycle can never resurrect a state another writer just + * replaced; readers stay lock-free because the rename commit is atomic. + * @module @deepseek-ai/dsh-atomic-write + */ +/** + * Filesystem options for {@link writeFileAtomic}; `mode` is required so the + * permission decision stays visible at every call site. + */ +export interface WriteFileAtomicOptions { + /** + * Permission bits stamped on the fresh temp inode and carried through the + * rename (subject to the process umask, like every fresh inode). + */ + mode: number; + /** + * Permission bits for parent directories this call creates (subject to the + * umask; existing directories keep their mode). Omission uses the mkdir + * default — pass `0o700` when the tree holds user-private data. + */ + dirMode?: number; +} +/** + * Replace `filename` with `content` in one atomic step, creating parent + * directories. The content is first written to a random-suffix sibling opened + * with exclusive create (`wx`): the open refuses to follow a symlink planted + * at the temp path, and the fresh inode carries `options.mode` through the + * rename, so replacing a wider-permission file narrows it without a chmod + * race. The rename also replaces a symlinked target itself instead of writing + * through to its referent, and the same-directory sibling keeps the rename on + * one filesystem. On any failure the temp file is removed and the failure + * rethrown. Crash durability (fsync) is out of scope. + * @param filename - final path receiving the content. + * @param content - complete next file content. + * @param options - permission bits for the replacement inode. + */ +export declare function writeFileAtomic(filename: string, content: string, options: WriteFileAtomicOptions): Promise; +/** + * Hold the cross-process writer lock for `filename` around one operation. The + * lock is a `wx`-created sibling (`.lock`); paired with the + * rename-based commit of {@link writeFileAtomic}, readers stay lock-free and + * only writers contend. Contention backs off exponentially and fails with a + * timed-out error after the deadline. The contender never removes an existing + * lock because file age cannot prove that its owner stopped; orphan recovery + * is an operator action. The parent directory must exist. + * @param filename - the file whose writers this lock serializes. + * @param operation - the read-render-commit cycle to run while holding the lock. + * @returns the operation's result; the lock releases on both outcomes. + */ +export declare function withFileLock(filename: string, operation: () => Promise): Promise; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/invariant.d.ts new file mode 100644 index 0000000..7a853e2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-atomic-write`. + * @module @deepseek-ai/dsh-atomic-write/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "atomic-write-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/package.json new file mode 100644 index 0000000..8988b4c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-atomic-write/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-atomic-write", + "description": "Zero-dependency atomic file replacement: exclusive-create random-suffix temp + rename carrying the caller-stated permissions (writeFileAtomic)", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/util/atomic-write" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_413dfe5bd61b96e1026b0591a4519606/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.i18n.yaml new file mode 100644 index 0000000..d293beb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/atomic-write/README.md +README.md: a767f24064c368b60d85fed6fa1d88349cab9587 +README.zh.md: 6388e264898e0025fb6586acecab450be3eb9e55 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.md new file mode 100644 index 0000000..a767f24 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.md @@ -0,0 +1,45 @@ +# dsh-atomic-write + +English | [中文](README.zh.md) + +Zero-dependency atomic file replacement shared by file-backed stores that must never leave partial, symlink-hijacked, or wider-than-intended content on disk — the user-settings document (`dsh-settings-file`) and the credentials store (`dsh-credentials-local`). + +## Surface + +```ts +import { withFileLock, writeFileAtomic } from '@deepseek-ai/dsh-atomic-write' + +declare const text: string +declare const render: (previous: string) => string + +await writeFileAtomic('/home/u/.dsh/settings.yaml', text, { mode: 0o600 }) + +// Read-modify-write against the same file from several processes. +await withFileLock('/home/u/.dsh/settings.yaml', async () => { + await writeFileAtomic('/home/u/.dsh/settings.yaml', render(text), { mode: 0o600 }) +}) +``` + +`writeFileAtomic` commits one already-rendered string. The contract, in the order failures would exploit it: + +- **Exclusive-create temp** (`wx`, random suffix): the open refuses to follow a symlink planted at a guessable temp path. +- **The fresh inode carries `mode` through the rename**: replacing a wider-permission file narrows it without a chmod race. `mode` is required so the permission decision stays visible at every call site (subject to the process umask, like every fresh inode). +- **`rename` replaces a symlinked target itself**, never writing through to its referent. +- **Same-directory sibling** keeps the rename on one filesystem, so the swap stays atomic. +- Parent directories are created; on any failure the temp is removed and the failure rethrown; readers observe either the old or the new complete content. + +`withFileLock` serializes the writers of one file across processes, for the read-render-commit cycles a bare atomic commit cannot make safe on its own. The lock is a `wx`-created `.lock` sibling, so readers never contend; waiters back off exponentially and fail with a timeout rather than block forever. A contender never removes the existing lock: age cannot distinguish a crashed owner from a paused live writer. + +## Model Experience + +None, as this is a pure filesystem primitive; nothing here reaches a model request. + +#### KV Cache effect + +None; nothing here enters a request prefix. + +## Known Limitations and Deferred Work + +- **Atomic, not durable** — no `fsync` of the file or its directory, so after a crash the rename may be observed unwound. The file-backed stores here re-read and republish on boot, keeping durability the caller's policy. +- **String content only** — no `Buffer` or stream form until a consumer needs one. +- **Orphaned locks require operator recovery** — a process that exits while holding the lock can leave the sibling behind. Later writers time out without deleting it; an operator removes it only after verifying that no writer still owns it. File age alone is not safe evidence of abandonment. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.zh.md new file mode 100644 index 0000000..6388e26 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/README.zh.md @@ -0,0 +1,45 @@ +# dsh-atomic-write + +[English](README.md) | 中文 + +零依赖的原子文件替换,供绝不允许在磁盘上留下不完整、被符号链接劫持或权限过宽内容的文件型存储共用:用户设置文档(`dsh-settings-file`)与凭据存储(`dsh-credentials-local`)。 + +## 接口面 + +```ts +import { withFileLock, writeFileAtomic } from '@deepseek-ai/dsh-atomic-write' + +declare const text: string +declare const render: (previous: string) => string + +await writeFileAtomic('/home/u/.dsh/settings.yaml', text, { mode: 0o600 }) + +// Read-modify-write against the same file from several processes. +await withFileLock('/home/u/.dsh/settings.yaml', async () => { + await writeFileAtomic('/home/u/.dsh/settings.yaml', render(text), { mode: 0o600 }) +}) +``` + +`writeFileAtomic` 提交一份已经渲染好的字符串。约定按故障利用它的先后顺序列出: + +- **独占创建临时文件**(`wx` + 随机后缀):open 拒绝跟随预先埋在可猜测临时路径上的符号链接。 +- **全新 inode 携带 `mode` 走完 rename**:替换权限过宽的旧文件时直接收窄,不存在 chmod 竞态。`mode` 为必填,让权限决策始终可见于每个调用点(与所有新建 inode 一样受进程 umask 影响)。 +- **`rename` 替换的是符号链接目标本身**,绝不写穿到其指向的文件。 +- **同目录兄弟文件**保证 rename 落在同一文件系统上,交换保持原子。 +- 自动创建父目录;任何失败都会移除临时文件并重新抛出该失败;读取方只会观察到旧内容或完整的新内容。 + +`withFileLock` 跨进程串行化同一文件的写入方,服务于单靠原子提交无法保证安全的读-渲染-提交循环。锁是以 `wx` 创建的同目录 `.lock`,因此读取方从不参与竞争;等待方按指数退避,超时即失败而非无限阻塞。竞争者绝不移除现有锁:锁龄无法区分已经崩溃的所有者与被暂停但仍存活的写入方。 + +## 模型体验 + +无:本包是纯文件系统原语,此处没有任何内容会到达模型请求。 + +#### KV Cache 影响 + +无;此处没有任何内容会进入请求前缀。 + +## 已知限制与暂缓事项 + +- **原子但不保证持久**——不对文件或其所在目录做 `fsync`,因此崩溃后可能观察到 rename 被回退。此处的文件型存储在启动时重新读取并重新发布,把持久性留作调用方的策略。 +- **仅支持字符串内容**——在有消费方需要之前,不提供 `Buffer` 或流式形态。 +- **遗留锁需要操作者恢复**——进程持锁退出时可能留下同级锁文件。后续写入方超时也不会删除它;操作者只有在确认没有写入方仍拥有该锁后才会移除。文件存续时间本身不能安全证明它已无人持有。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/index.js new file mode 100644 index 0000000..75f4553 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/index.js @@ -0,0 +1,97 @@ +import { randomBytes } from "node:crypto"; +import { mkdir, rename, rm, writeFile } from "node:fs/promises"; +import { dirname } from "node:path"; +//#region lib/types/index.js +/** +* Zero-dependency atomic file replacement and writer coordination. +* `writeFileAtomic` writes a random-suffix sibling with exclusive create and +* the caller's permission bits, then renames it over the target, so readers +* observe either the old or the new complete content and a replaced file ends +* up with exactly the stated mode. `withFileLock` serializes cross-process +* writers of one file through a `wx`-created `.lock` sibling, so a +* read-modify-write cycle can never resurrect a state another writer just +* replaced; readers stay lock-free because the rename commit is atomic. +* @module @deepseek-ai/dsh-atomic-write +*/ +/** +* Replace `filename` with `content` in one atomic step, creating parent +* directories. The content is first written to a random-suffix sibling opened +* with exclusive create (`wx`): the open refuses to follow a symlink planted +* at the temp path, and the fresh inode carries `options.mode` through the +* rename, so replacing a wider-permission file narrows it without a chmod +* race. The rename also replaces a symlinked target itself instead of writing +* through to its referent, and the same-directory sibling keeps the rename on +* one filesystem. On any failure the temp file is removed and the failure +* rethrown. Crash durability (fsync) is out of scope. +* @param filename - final path receiving the content. +* @param content - complete next file content. +* @param options - permission bits for the replacement inode. +*/ +async function writeFileAtomic(filename, content, options) { + await mkdir(dirname(filename), { + recursive: true, + ...options.dirMode === void 0 ? {} : { mode: options.dirMode } + }); + const temp = `${filename}.${randomBytes(6).toString("hex")}.tmp`; + try { + await writeFile(temp, content, { + mode: options.mode, + flag: "wx" + }); + await rename(temp, filename); + } catch (error) { + await rm(temp, { force: true }); + throw error; + } +} +/** Whether an exclusive create failed because the path already exists. */ +function isEEXIST(error) { + return error?.code === "EEXIST"; +} +/** +* Writer-lock protocol constants. These are robustness invariants of the +* cross-process write protocol, not deployment tunables: contention normally +* resolves within the retry deadline, while expiry fails the contender without +* guessing whether the existing lock still has an owner. +*/ +const LOCK_RETRY_INITIAL_MS = 20; +const LOCK_RETRY_MAX_MS = 200; +const LOCK_TIMEOUT_MS = 2e3; +/** +* Hold the cross-process writer lock for `filename` around one operation. The +* lock is a `wx`-created sibling (`.lock`); paired with the +* rename-based commit of {@link writeFileAtomic}, readers stay lock-free and +* only writers contend. Contention backs off exponentially and fails with a +* timed-out error after the deadline. The contender never removes an existing +* lock because file age cannot prove that its owner stopped; orphan recovery +* is an operator action. The parent directory must exist. +* @param filename - the file whose writers this lock serializes. +* @param operation - the read-render-commit cycle to run while holding the lock. +* @returns the operation's result; the lock releases on both outcomes. +*/ +async function withFileLock(filename, operation) { + const lockPath = `${filename}.lock`; + const deadline = Date.now() + LOCK_TIMEOUT_MS; + let delay = LOCK_RETRY_INITIAL_MS; + for (;;) { + try { + await writeFile(lockPath, `${process.pid}\n`, { + mode: 384, + flag: "wx" + }); + break; + } catch (error) { + if (!isEEXIST(error)) throw error; + } + if (Date.now() >= deadline) throw new Error(`atomic-write: timed out waiting for the writer lock at ${lockPath}`); + await new Promise((resolve) => setTimeout(resolve, delay)); + delay = Math.min(delay * 2, LOCK_RETRY_MAX_MS); + } + try { + return await operation(); + } finally { + await rm(lockPath, { force: true }); + } +} +//#endregion +export { withFileLock, writeFileAtomic }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/invariant.js new file mode 100644 index 0000000..25b89af --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-atomic-write`. +* @module @deepseek-ai/dsh-atomic-write/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-atomic-write"; +/** Cordis companion plugin name. */ +const name = "atomic-write-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this pure filesystem primitive owns no event stream or mutable runtime +* data; its replacement contract is enforced by unit tests. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/index.d.ts new file mode 100644 index 0000000..88a21eb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/index.d.ts @@ -0,0 +1,57 @@ +/** + * Zero-dependency atomic file replacement and writer coordination. + * `writeFileAtomic` writes a random-suffix sibling with exclusive create and + * the caller's permission bits, then renames it over the target, so readers + * observe either the old or the new complete content and a replaced file ends + * up with exactly the stated mode. `withFileLock` serializes cross-process + * writers of one file through a `wx`-created `.lock` sibling, so a + * read-modify-write cycle can never resurrect a state another writer just + * replaced; readers stay lock-free because the rename commit is atomic. + * @module @deepseek-ai/dsh-atomic-write + */ +/** + * Filesystem options for {@link writeFileAtomic}; `mode` is required so the + * permission decision stays visible at every call site. + */ +export interface WriteFileAtomicOptions { + /** + * Permission bits stamped on the fresh temp inode and carried through the + * rename (subject to the process umask, like every fresh inode). + */ + mode: number; + /** + * Permission bits for parent directories this call creates (subject to the + * umask; existing directories keep their mode). Omission uses the mkdir + * default — pass `0o700` when the tree holds user-private data. + */ + dirMode?: number; +} +/** + * Replace `filename` with `content` in one atomic step, creating parent + * directories. The content is first written to a random-suffix sibling opened + * with exclusive create (`wx`): the open refuses to follow a symlink planted + * at the temp path, and the fresh inode carries `options.mode` through the + * rename, so replacing a wider-permission file narrows it without a chmod + * race. The rename also replaces a symlinked target itself instead of writing + * through to its referent, and the same-directory sibling keeps the rename on + * one filesystem. On any failure the temp file is removed and the failure + * rethrown. Crash durability (fsync) is out of scope. + * @param filename - final path receiving the content. + * @param content - complete next file content. + * @param options - permission bits for the replacement inode. + */ +export declare function writeFileAtomic(filename: string, content: string, options: WriteFileAtomicOptions): Promise; +/** + * Hold the cross-process writer lock for `filename` around one operation. The + * lock is a `wx`-created sibling (`.lock`); paired with the + * rename-based commit of {@link writeFileAtomic}, readers stay lock-free and + * only writers contend. Contention backs off exponentially and fails with a + * timed-out error after the deadline. The contender never removes an existing + * lock because file age cannot prove that its owner stopped; orphan recovery + * is an operator action. The parent directory must exist. + * @param filename - the file whose writers this lock serializes. + * @param operation - the read-render-commit cycle to run while holding the lock. + * @returns the operation's result; the lock releases on both outcomes. + */ +export declare function withFileLock(filename: string, operation: () => Promise): Promise; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/invariant.d.ts new file mode 100644 index 0000000..7a853e2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-atomic-write`. + * @module @deepseek-ai/dsh-atomic-write/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "atomic-write-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/package.json new file mode 100644 index 0000000..74e9b1e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-atomic-write", + "description": "Zero-dependency atomic file replacement: exclusive-create random-suffix temp + rename carrying the caller-stated permissions (writeFileAtomic)", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/util/atomic-write" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.i18n.yaml new file mode 100644 index 0000000..bebd5ee --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/attachment/attachment/README.md +README.md: baeeca0cf939f1a3d4608769b362d532507b90f5 +README.zh.md: 238b90794c510e71fffe34d62b044a5c2ece8a6e diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.md new file mode 100644 index 0000000..baeeca0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.md @@ -0,0 +1,21 @@ +# @deepseek-ai/dsh-attachment + +English | [中文](README.zh.md) + +The durable attachment seam. `ctx.attachments` validates and atomically commits immutable image bytes, then returns a serializable `ImageAttachmentRef`; consumers never persist browser paths, object URLs, provider URLs, or base64 in session events. + +Unsent composer images remain browser-owned temporary drafts. `validateImage` runs the same admission policy without persisting; batch writers validate every member first so a malformed member cannot strand earlier members as unreferenced objects. `saveImage` commits each accepted image before any model-visible session event is published, and `readImage` verifies the content-addressed object against its logged metadata. Callers may cancel `readImage`; implementations observe cancellation around backend and verification work and preserve it instead of translating it into a storage failure. + +## Model Experience + +Indirectly, through the role-neutral core `ImageBlock` and provider adapters that resolve its durable reference. + +#### KV Cache effect + +Adding an image changes the provider request and therefore invalidates the affected request suffix. + +## Known Limitations and Deferred Work + +- Version one accepts PNG, JPEG, WebP, and GIF only. +- Retention and garbage collection are deferred because resumed and forked sessions may share immutable objects. +- Generic files, audio, video, and persistent unsent drafts require separate lifecycle and provider contracts. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.zh.md new file mode 100644 index 0000000..238b907 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/README.zh.md @@ -0,0 +1,21 @@ +# @deepseek-ai/dsh-attachment + +[English](README.md) | 中文 + +持久附件服务边界。`ctx.attachments` 校验并以原子方式提交不可变图片字节,随后返回可序列化的 `ImageAttachmentRef`;消费方绝不会在会话事件中持久保存浏览器路径、对象 URL、提供方 URL 或 base64。 + +未发送的输入区图片仍是由浏览器持有的临时草稿。`validateImage` 运行相同的准入策略,但不执行持久化;批量写入方会先校验每个成员,避免某个格式错误的成员使较早的成员成为无引用对象。`saveImage` 会在发布任何模型可见的会话事件前提交每张已接受的图片,`readImage` 则根据已记录的元数据校验内容寻址对象。调用方可以取消 `readImage`;实现会在后端读取与校验工作的边界观察取消,并保留取消语义,而不会将其转换为存储失败。 + +## 模型体验 + +该包通过角色无关的核心 `ImageBlock`,以及解析其持久引用的提供方适配器,间接影响模型。 + +#### KV 缓存影响 + +添加图片会改变提供方请求,因此会使受影响的请求后缀失效。 + +## 已知限制与待完成工作 + +- 第一版仅接受 PNG、JPEG、WebP 和 GIF。 +- 保留策略与垃圾回收尚未实现,因为恢复和 fork 后的会话可能共享不可变对象。 +- 通用文件、音频、视频和持久的未发送草稿需要单独的生命周期与提供方契约。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/index.js new file mode 100644 index 0000000..27ef8a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/index.js @@ -0,0 +1,48 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/brand.js +/** Attachment identifier brand. @module @deepseek-ai/dsh-attachment/brand */ +/** +* Brand a validated storage identifier. +* @param value - backend-produced opaque identifier. +* @returns the branded identifier. +*/ +function AttachmentId(value) { + return value; +} +//#endregion +//#region lib/types/error.js +/** Attachment failure class. @module @deepseek-ai/dsh-attachment/error */ +/** +* Stable failures suitable for host RPC error mapping. +* +* Deliberately re-implements the `HarnessError` shape instead of extending it: +* the base lives in `@deepseek-ai/dsh-llm`, which itself depends on this +* package (`ImageBlock` references `ImageAttachmentRef`), so sharing the base +* would create a dependency cycle. Consumers route on `code`, never on the +* prototype chain, so the shapes stay interchangeable at the wire boundary. +*/ +var AttachmentError = class extends Error { + /** Stable machine-routing failure code. */ + code; + /** + * @param message - human-readable failure description without raw bytes or host paths. + * @param code - stable machine-routing code. + * @param options - optional chained cause. + */ + constructor(message, code, options) { + super(message, options); + this.name = "AttachmentError"; + this.code = code; + } +}; +//#endregion +//#region lib/types/index.js +/** Durable attachment storage seam (`ctx.attachments`). @module @deepseek-ai/dsh-attachment */ +/** Immutable binary attachment service. Implementations validate bytes before publishing a reference. */ +var AttachmentStore = class extends Service { + constructor(ctx) { + super(ctx, "attachments"); + } +}; +//#endregion +export { AttachmentError, AttachmentId, AttachmentStore, AttachmentStore as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/invariant.js new file mode 100644 index 0000000..e9a44fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/invariant.js @@ -0,0 +1,17 @@ +//#region lib/types/invariant.js +/** Package-owned invariant companion for `@deepseek-ai/dsh-attachment`. @module @deepseek-ai/dsh-attachment/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-attachment"; +/** Cordis companion plugin name. */ +const name = "attachment-invariant"; +/** Service required before package ownership can be reserved. */ +const inject = ["invariants"]; +/** No runtime invariant: this stateless seam owns types while implementations enforce immutable-store checks. */ +const install = () => {}; +/** +* Register the package invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the registration disposer. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/brand.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/brand.d.ts new file mode 100644 index 0000000..557acf7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/brand.d.ts @@ -0,0 +1,11 @@ +/** Attachment identifier brand. @module @deepseek-ai/dsh-attachment/brand */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Opaque content-addressed identifier for one immutable attachment object. */ +export type AttachmentId = Branded<'AttachmentId'>; +/** + * Brand a validated storage identifier. + * @param value - backend-produced opaque identifier. + * @returns the branded identifier. + */ +export declare function AttachmentId(value: string): AttachmentId; +//# sourceMappingURL=brand.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/error.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/error.d.ts new file mode 100644 index 0000000..a2f1de5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/error.d.ts @@ -0,0 +1,21 @@ +/** Attachment failure class. @module @deepseek-ai/dsh-attachment/error */ +/** + * Stable failures suitable for host RPC error mapping. + * + * Deliberately re-implements the `HarnessError` shape instead of extending it: + * the base lives in `@deepseek-ai/dsh-llm`, which itself depends on this + * package (`ImageBlock` references `ImageAttachmentRef`), so sharing the base + * would create a dependency cycle. Consumers route on `code`, never on the + * prototype chain, so the shapes stay interchangeable at the wire boundary. + */ +export declare class AttachmentError extends Error { + /** Stable machine-routing failure code. */ + readonly code: string; + /** + * @param message - human-readable failure description without raw bytes or host paths. + * @param code - stable machine-routing code. + * @param options - optional chained cause. + */ + constructor(message: string, code: string, options?: ErrorOptions); +} +//# sourceMappingURL=error.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/index.d.ts new file mode 100644 index 0000000..6c3c8ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/index.d.ts @@ -0,0 +1,40 @@ +/** Durable attachment storage seam (`ctx.attachments`). @module @deepseek-ai/dsh-attachment */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { ImageAttachmentLimits, ImageAttachmentRef, SaveImageAttachment, StoredImageAttachment } from './types.ts'; +export { AttachmentId } from './brand.ts'; +export { AttachmentError } from './error.ts'; +export type { AttachmentId as AttachmentIdType, ImageAttachmentLimits, ImageAttachmentRef, ImageMediaType, SaveImageAttachment, StoredImageAttachment, } from './types.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + attachments: AttachmentStore; + } +} +/** Immutable binary attachment service. Implementations validate bytes before publishing a reference. */ +export declare abstract class AttachmentStore extends Service { + constructor(ctx: Context); + /** Deployment-resolved image policy used by authoritative and fast-path validation. */ + abstract readonly imageLimits: ImageAttachmentLimits; + /** + * Validate one image without persisting it. + * Batch callers validate every member before saving any member. + * @param input - encoded bytes, declared media type, and optional display name. + * @returns completion after the encoded raster has been fully decoded. + */ + abstract validateImage(input: SaveImageAttachment): Promise; + /** + * Validate and durably commit one image before its owning session event is appended. + * @param input - encoded bytes, declared media type, and optional display name. + * @returns a durable content-addressed reference. + */ + abstract saveImage(input: SaveImageAttachment): Promise; + /** + * Read one image and verify that bytes still match the recorded reference. + * @param ref - durable reference from the session log. + * @param signal - optional cancellation for backend read and verification work. + * @returns the verified bytes and canonical reference. + * @throws the signal reason when aborted, or a storage error when verification fails. + */ + abstract readImage(ref: ImageAttachmentRef, signal?: AbortSignal): Promise; +} +export default AttachmentStore; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/invariant.d.ts new file mode 100644 index 0000000..c864624 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned invariant companion for `@deepseek-ai/dsh-attachment`. @module @deepseek-ai/dsh-attachment/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "attachment-invariant"; +/** Service required before package ownership can be reserved. */ +export declare const inject: string[]; +/** + * Register the package invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the registration disposer. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/types.d.ts new file mode 100644 index 0000000..feb5568 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/lib/types/types.d.ts @@ -0,0 +1,42 @@ +/** Durable attachment vocabulary. @module @deepseek-ai/dsh-attachment/types */ +import type { AttachmentId } from './brand.ts'; +export type { AttachmentId } from './brand.ts'; +/** Raster image formats accepted by the version-one attachment path. */ +export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'; +/** Durable, serializable metadata for one immutable image object. */ +export interface ImageAttachmentRef { + /** Opaque storage identifier; never a filesystem path or bearer URL. */ + attachmentId: AttachmentId; + /** Media type verified from the stored bytes. */ + mediaType: ImageMediaType; + /** Exact encoded byte length. */ + bytes: number; + /** Intrinsic encoded width in pixels. */ + width: number; + /** Intrinsic encoded height in pixels. */ + height: number; + /** Optional display name stripped of local path information. */ + name?: string; +} +/** Deployment-resolved limits used by upload admission and request buffering. */ +export interface ImageAttachmentLimits { + maxImageBytes: number; + maxImagesPerMessage: number; + maxMessageImageBytes: number; + maxImagePixels: number; + mediaTypes: readonly ImageMediaType[]; +} +/** Request to validate and durably commit one image. */ +export interface SaveImageAttachment { + data: Uint8Array; + /** Caller-declared media type, checked against fully decoded bytes. */ + mediaType: ImageMediaType; + /** Optional browser/provider display name; it is never interpreted as a path. */ + name?: string; +} +/** Stored image bytes returned after reference and digest verification. */ +export interface StoredImageAttachment { + ref: ImageAttachmentRef; + data: Uint8Array; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/package.json new file mode 100644 index 0000000..f53d8b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment/package.json @@ -0,0 +1,44 @@ +{ + "name": "@deepseek-ai/dsh-attachment", + "description": "Durable immutable attachment storage seam for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/attachment/attachment" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.i18n.yaml new file mode 100644 index 0000000..7075b0f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/attachment/attachment/README.md +README.md: 4fe608552492c33d2bd9acddce51ea1cf20acae4 +README.zh.md: a3093fc9dd1f926cb1c54831c6302eb7bbca25c5 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.md new file mode 100644 index 0000000..4fe6085 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.md @@ -0,0 +1,21 @@ +# @deepseek-ai/dsh-attachment + +English | [中文](README.zh.md) + +The durable attachment seam. `ctx.attachments` validates and durably commits immutable image bytes, then returns a serializable `ImageAttachmentRef`; consumers never persist browser paths, object URLs, provider URLs, or base64 in session events. + +Unsent composer images remain browser-owned temporary drafts. `validateImage` runs the same admission policy without persisting. `saveImages` owns batch count and aggregate-byte limits, validates every member before writing any member, then commits in order and returns references only after the complete batch succeeds. A later storage failure returns no partial references, although an earlier immutable content-addressed object may remain unreachable until reference-aware garbage collection exists. `AttachmentError.code` uses the closed `AttachmentErrorCode` string union. Its `ImageAdmissionErrorCode` subset marks caller-correctable image-input failures; `isImageAdmissionError` recognizes that subset at runtime so each protocol adapter can map its own error vocabulary. `saveImage` commits one accepted image before any model-visible session event is published, and `readImage` verifies the content-addressed object against its logged metadata. Callers may cancel `readImage`; implementations observe cancellation around backend and verification work and preserve it instead of translating it into a storage failure. + +## Model Experience + +Indirectly, through the role-neutral core `ImageBlock` and provider adapters that resolve its durable reference. + +#### KV Cache effect + +Adding an image changes the provider request and therefore invalidates the affected request suffix. + +## Known Limitations and Deferred Work + +- Version one accepts PNG, JPEG, WebP, and GIF only. +- Retention and garbage collection are deferred because resumed and forked sessions may share immutable objects. +- Generic files, audio, video, and persistent unsent drafts require separate lifecycle and provider contracts. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.zh.md new file mode 100644 index 0000000..a3093fc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/README.zh.md @@ -0,0 +1,21 @@ +# @deepseek-ai/dsh-attachment + +[English](README.md) | 中文 + +持久附件服务边界。`ctx.attachments` 校验并持久提交不可变图片字节,随后返回可序列化的 `ImageAttachmentRef`;消费方绝不会在会话事件中持久保存浏览器路径、对象 URL、提供方 URL 或 base64。 + +未发送的输入区图片仍是由浏览器持有的临时草稿。`validateImage` 运行相同的准入策略,但不执行持久化。`saveImages` 负责批次图片数量和总字节限制,先校验全部成员,再按顺序提交,并且只在完整批次成功后返回引用。后续存储失败不会返回部分引用,但较早写入的不可变内容寻址对象可能保持不可达,直至具备按引用感知的垃圾回收。`AttachmentError.code` 使用封闭的 `AttachmentErrorCode` 字符串联合类型。其 `ImageAdmissionErrorCode` 子集标记可由调用方修正的图片输入失败;`isImageAdmissionError` 在运行时识别该子集,使每个协议适配器可以映射自己的错误词汇。`saveImage` 会在发布任何模型可见的会话事件前提交一张已接受的图片,`readImage` 则根据已记录的元数据校验内容寻址对象。调用方可以取消 `readImage`;实现会在后端读取与校验工作的边界观察取消,并保留取消语义,而不会将其转换为存储失败。 + +## 模型体验 + +该包通过角色无关的核心 `ImageBlock`,以及解析其持久引用的提供方适配器,间接影响模型。 + +#### KV 缓存影响 + +添加图片会改变提供方请求,因此会使受影响的请求后缀失效。 + +## 已知限制与待完成工作 + +- 第一版仅接受 PNG、JPEG、WebP 和 GIF。 +- 保留策略与垃圾回收尚未实现,因为恢复和 fork 后的会话可能共享不可变对象。 +- 通用文件、音频、视频和持久的未发送草稿需要单独的生命周期与提供方契约。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/index.js new file mode 100644 index 0000000..d8c9b84 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/index.js @@ -0,0 +1,84 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/error.js +/** Runtime membership for structurally compatible errors crossing package boundaries. */ +const IMAGE_ADMISSION_ERROR_CODE_SET = new Set([ + "TOO_MANY_IMAGES", + "IMAGES_TOO_LARGE", + "UNSUPPORTED_IMAGE_TYPE", + "INVALID_IMAGE_BASE64", + "INVALID_IMAGE", + "IMAGE_TYPE_MISMATCH", + "IMAGE_TOO_LARGE", + "IMAGE_TOO_MANY_PIXELS" +]); +/** +* Stable failures suitable for host RPC error mapping. +* +* Deliberately re-implements the `HarnessError` shape instead of extending it: +* the base lives in `@deepseek-ai/dsh-llm`, which itself depends on this +* package (`ImageBlock` references `ImageAttachmentRef`), so sharing the base +* would create a dependency cycle. Consumers route on `code`, never on the +* prototype chain, so the shapes stay interchangeable at the wire boundary. +*/ +var AttachmentError = class extends Error { + /** Stable machine-routing failure code. */ + code; + /** + * @param message - human-readable failure description without raw bytes or host paths. + * @param code - stable machine-routing code. + * @param options - optional chained cause. + */ + constructor(message, code, options) { + super(message, options); + this.name = "AttachmentError"; + this.code = code; + } +}; +/** +* Distinguish caller-correctable image admission failures from storage faults. +* @param error - failure raised while validating or persisting an image batch. +* @returns whether the caller can correct the proposed image content or batch. +*/ +function isImageAdmissionError(error) { + return error instanceof Error && "code" in error && typeof error.code === "string" && IMAGE_ADMISSION_ERROR_CODE_SET.has(error.code); +} +//#endregion +//#region lib/types/brand.js +/** Attachment identifier brand. @module @deepseek-ai/dsh-attachment/brand */ +/** +* Brand a validated storage identifier. +* @param value - backend-produced opaque identifier. +* @returns the branded identifier. +*/ +function AttachmentId(value) { + return value; +} +//#endregion +//#region lib/types/index.js +/** Durable attachment storage seam (`ctx.attachments`). @module @deepseek-ai/dsh-attachment */ +/** Immutable binary attachment service. Implementations validate bytes before publishing a reference. */ +var AttachmentStore = class extends Service { + constructor(ctx) { + super(ctx, "attachments"); + } + /** + * Validate one ordered image batch before committing any member. + * Validation failures start no writes; storage failures return no partial + * references, although already published content-addressed objects may stay + * unreachable until a future retention policy collects them. + * @param inputs - encoded images in their owning message order. + * @returns durable references in the exact input order. + */ + async saveImages(inputs) { + const { maxImagesPerMessage, maxMessageImageBytes, mediaTypes } = this.imageLimits; + if (inputs.length > maxImagesPerMessage) throw new AttachmentError("Image batch exceeds the configured image-count limit.", "TOO_MANY_IMAGES"); + if (inputs.reduce((sum, input) => sum + input.data.byteLength, 0) > maxMessageImageBytes) throw new AttachmentError("Image batch exceeds the configured aggregate image-byte limit.", "IMAGES_TOO_LARGE"); + for (const input of inputs) if (!mediaTypes.includes(input.mediaType)) throw new AttachmentError(`Image type ${input.mediaType} is not accepted by this deployment.`, "UNSUPPORTED_IMAGE_TYPE"); + for (const input of inputs) await this.validateImage(input); + const refs = []; + for (const input of inputs) refs.push(await this.saveImage(input)); + return refs; + } +}; +//#endregion +export { AttachmentError, AttachmentId, AttachmentStore, AttachmentStore as default, isImageAdmissionError }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/invariant.js new file mode 100644 index 0000000..e9a44fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/invariant.js @@ -0,0 +1,17 @@ +//#region lib/types/invariant.js +/** Package-owned invariant companion for `@deepseek-ai/dsh-attachment`. @module @deepseek-ai/dsh-attachment/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-attachment"; +/** Cordis companion plugin name. */ +const name = "attachment-invariant"; +/** Service required before package ownership can be reserved. */ +const inject = ["invariants"]; +/** No runtime invariant: this stateless seam owns types while implementations enforce immutable-store checks. */ +const install = () => {}; +/** +* Register the package invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the registration disposer. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/brand.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/brand.d.ts new file mode 100644 index 0000000..557acf7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/brand.d.ts @@ -0,0 +1,11 @@ +/** Attachment identifier brand. @module @deepseek-ai/dsh-attachment/brand */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Opaque content-addressed identifier for one immutable attachment object. */ +export type AttachmentId = Branded<'AttachmentId'>; +/** + * Brand a validated storage identifier. + * @param value - backend-produced opaque identifier. + * @returns the branded identifier. + */ +export declare function AttachmentId(value: string): AttachmentId; +//# sourceMappingURL=brand.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/error.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/error.d.ts new file mode 100644 index 0000000..45655f0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/error.d.ts @@ -0,0 +1,35 @@ +/** Attachment failure class. @module @deepseek-ai/dsh-attachment/error */ +declare const IMAGE_ADMISSION_ERROR_CODES: readonly ["TOO_MANY_IMAGES", "IMAGES_TOO_LARGE", "UNSUPPORTED_IMAGE_TYPE", "INVALID_IMAGE_BASE64", "INVALID_IMAGE", "IMAGE_TYPE_MISMATCH", "IMAGE_TOO_LARGE", "IMAGE_TOO_MANY_PIXELS"]; +/** Caller-correctable attachment failure codes raised while admitting image input. */ +export type ImageAdmissionErrorCode = typeof IMAGE_ADMISSION_ERROR_CODES[number]; +/** Stable attachment failure codes used for protocol error routing. */ +export type AttachmentErrorCode = ImageAdmissionErrorCode | 'INVALID_ATTACHMENT_REF' | 'ATTACHMENT_CORRUPT' | 'ATTACHMENT_WRITE_FAILED' | 'ATTACHMENT_NOT_FOUND' | 'ATTACHMENT_READ_FAILED'; +/** + * Stable failures suitable for host RPC error mapping. + * + * Deliberately re-implements the `HarnessError` shape instead of extending it: + * the base lives in `@deepseek-ai/dsh-llm`, which itself depends on this + * package (`ImageBlock` references `ImageAttachmentRef`), so sharing the base + * would create a dependency cycle. Consumers route on `code`, never on the + * prototype chain, so the shapes stay interchangeable at the wire boundary. + */ +export declare class AttachmentError extends Error { + /** Stable machine-routing failure code. */ + readonly code: AttachmentErrorCode; + /** + * @param message - human-readable failure description without raw bytes or host paths. + * @param code - stable machine-routing code. + * @param options - optional chained cause. + */ + constructor(message: string, code: AttachmentErrorCode, options?: ErrorOptions); +} +/** + * Distinguish caller-correctable image admission failures from storage faults. + * @param error - failure raised while validating or persisting an image batch. + * @returns whether the caller can correct the proposed image content or batch. + */ +export declare function isImageAdmissionError(error: unknown): error is AttachmentError & { + readonly code: ImageAdmissionErrorCode; +}; +export {}; +//# sourceMappingURL=error.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/index.d.ts new file mode 100644 index 0000000..453295a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/index.d.ts @@ -0,0 +1,50 @@ +/** Durable attachment storage seam (`ctx.attachments`). @module @deepseek-ai/dsh-attachment */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { ImageAttachmentLimits, ImageAttachmentRef, SaveImageAttachment, StoredImageAttachment } from './types.ts'; +export { AttachmentId } from './brand.ts'; +export { AttachmentError, isImageAdmissionError } from './error.ts'; +export type { AttachmentErrorCode, ImageAdmissionErrorCode } from './error.ts'; +export type { AttachmentId as AttachmentIdType, ImageAttachmentLimits, ImageAttachmentRef, ImageMediaType, SaveImageAttachment, StoredImageAttachment, } from './types.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + attachments: AttachmentStore; + } +} +/** Immutable binary attachment service. Implementations validate bytes before publishing a reference. */ +export declare abstract class AttachmentStore extends Service { + constructor(ctx: Context); + /** Deployment-resolved image policy used by authoritative and fast-path validation. */ + abstract readonly imageLimits: ImageAttachmentLimits; + /** + * Validate one image without persisting it. + * Batch callers validate every member before saving any member. + * @param input - encoded bytes, declared media type, and optional display name. + * @returns completion after the encoded raster has been fully decoded. + */ + abstract validateImage(input: SaveImageAttachment): Promise; + /** + * Validate one ordered image batch before committing any member. + * Validation failures start no writes; storage failures return no partial + * references, although already published content-addressed objects may stay + * unreachable until a future retention policy collects them. + * @param inputs - encoded images in their owning message order. + * @returns durable references in the exact input order. + */ + saveImages(inputs: readonly SaveImageAttachment[]): Promise; + /** + * Validate and durably commit one image before its owning session event is appended. + * @param input - encoded bytes, declared media type, and optional display name. + * @returns a durable content-addressed reference. + */ + abstract saveImage(input: SaveImageAttachment): Promise; + /** + * Read one image and verify that bytes still match the recorded reference. + * @param ref - durable reference from the session log. + * @param signal - optional cancellation for backend read and verification work. + * @returns the verified bytes and canonical reference. + * @throws the signal reason when aborted, or a storage error when verification fails. + */ + abstract readImage(ref: ImageAttachmentRef, signal?: AbortSignal): Promise; +} +export default AttachmentStore; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/invariant.d.ts new file mode 100644 index 0000000..c864624 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned invariant companion for `@deepseek-ai/dsh-attachment`. @module @deepseek-ai/dsh-attachment/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "attachment-invariant"; +/** Service required before package ownership can be reserved. */ +export declare const inject: string[]; +/** + * Register the package invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the registration disposer. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/types.d.ts new file mode 100644 index 0000000..feb5568 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/lib/types/types.d.ts @@ -0,0 +1,42 @@ +/** Durable attachment vocabulary. @module @deepseek-ai/dsh-attachment/types */ +import type { AttachmentId } from './brand.ts'; +export type { AttachmentId } from './brand.ts'; +/** Raster image formats accepted by the version-one attachment path. */ +export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'; +/** Durable, serializable metadata for one immutable image object. */ +export interface ImageAttachmentRef { + /** Opaque storage identifier; never a filesystem path or bearer URL. */ + attachmentId: AttachmentId; + /** Media type verified from the stored bytes. */ + mediaType: ImageMediaType; + /** Exact encoded byte length. */ + bytes: number; + /** Intrinsic encoded width in pixels. */ + width: number; + /** Intrinsic encoded height in pixels. */ + height: number; + /** Optional display name stripped of local path information. */ + name?: string; +} +/** Deployment-resolved limits used by upload admission and request buffering. */ +export interface ImageAttachmentLimits { + maxImageBytes: number; + maxImagesPerMessage: number; + maxMessageImageBytes: number; + maxImagePixels: number; + mediaTypes: readonly ImageMediaType[]; +} +/** Request to validate and durably commit one image. */ +export interface SaveImageAttachment { + data: Uint8Array; + /** Caller-declared media type, checked against fully decoded bytes. */ + mediaType: ImageMediaType; + /** Optional browser/provider display name; it is never interpreted as a path. */ + name?: string; +} +/** Stored image bytes returned after reference and digest verification. */ +export interface StoredImageAttachment { + ref: ImageAttachmentRef; + data: Uint8Array; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/package.json new file mode 100644 index 0000000..ad33cd3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment/package.json @@ -0,0 +1,44 @@ +{ + "name": "@deepseek-ai/dsh-attachment", + "description": "Durable immutable attachment storage seam for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/attachment/attachment" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.i18n.yaml new file mode 100644 index 0000000..7a31df8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/brand/README.md +README.md: ce05a652e2f863f737bf71fc473224fc16e25ab9 +README.zh.md: 07d1279b601d38d4dcf9ca10ddeccb3c3ed3547b diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.md new file mode 100644 index 0000000..ce05a65 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.md @@ -0,0 +1,28 @@ +# dsh-brand + +English | [中文](README.zh.md) + +The `Branded` nominal-typing primitive — a tiny, **type-only** package (no runtime code, no harness-package dependency) shared by every package that owns a cross-boundary id. + +## What `Branded` is + +A brand makes structurally-identical strings non-interchangeable at the type level: a `SessionId` cannot be passed where a `CallId` is expected, even though both are plain `string`s at runtime. + +```ts +import type { Branded } from '@deepseek-ai/dsh-brand' + +export type SessionId = Branded<'SessionId'> + +/** Brand a string as a SessionId (a plain cast — zero runtime cost). */ +export function SessionId(id: string): SessionId { + return id as SessionId +} +``` + +Construction goes through the per-id factory in the owning package. Comparison, logging, JSON serialization, and the wire format behave as for an ordinary string; the brand is erased at compile time. + +## Policy: brand ids that cross package boundaries + +A package brands the ids it owns — `CallId` in `dsh-llm`, the shared agent/session `SessionId` in `dsh-session`, and `JobId` in `dsh-jobs`. Brand cross-package ids that could plausibly be confused; not every string needs one. + +This package owns only the primitive. Keeping it dependency-free lets `dsh-jobs`, for example, brand `JobId` without importing an unrelated capability package merely to reach `Branded`. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.zh.md new file mode 100644 index 0000000..07d1279 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/README.zh.md @@ -0,0 +1,28 @@ +# dsh-brand + +[English](README.md) | 中文 + +`Branded` 名义类型原语:一个微小的**仅类型**包,无运行时代码,也不依赖其他 harness 包;所有负责跨边界 id 的包都会共享它。 + +## `Branded` 是什么 + +品牌使 `SessionId` 和 `CallId` 这样结构相同的字符串在类型层面不可互换,尽管两者在运行时都是普通 `string`。 + +```ts +import type { Branded } from '@deepseek-ai/dsh-brand' + +export type SessionId = Branded<'SessionId'> + +/** Brand a string as a SessionId (a plain cast — zero runtime cost). */ +export function SessionId(id: string): SessionId { + return id as SessionId +} +``` + +构造操作通过所属包中各 id 专用的工厂完成。比较、日志记录、JSON 序列化和协议格式(wire format)的行为与普通字符串相同;品牌信息会在编译时被擦除。 + +## 策略:为跨包边界的 id 添加品牌 + +包为自己拥有的 id 添加品牌:`CallId` 位于 `dsh-llm`,共享的 agent/会话 `SessionId` 位于 `dsh-session`,`JobId` 位于 `dsh-jobs`。为可能被混淆的跨包 id 添加品牌,但无需为每个字符串都添加。 + +该包只负责这一原语。保持无依赖意味着,例如 `dsh-jobs` 可以为 `JobId` 使用品牌类型,而无需仅为使用 `Branded` 而导入不相关的功能包。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/index.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/index.js @@ -0,0 +1 @@ +export {}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/invariant.js new file mode 100644 index 0000000..82705fb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-brand`. +* @module @deepseek-ai/dsh-brand/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-brand"; +/** Cordis companion plugin name. */ +const name = "brand-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value +* algebra is enforced by unit tests. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/types/index.d.ts new file mode 100644 index 0000000..8bc0741 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/types/index.d.ts @@ -0,0 +1,29 @@ +/** + * The `Branded` nominal-typing primitive — a type-only utility (no runtime + * code, no harness-package dependency) shared by every package that owns a + * cross-boundary id. + * + * A brand makes structurally-identical strings non-interchangeable at the type + * level: a `SessionId` cannot be passed where a `CallId` is expected, even + * though both are plain strings at runtime. Construction goes through a per-id + * factory in the OWNING package (a plain cast inside — zero runtime cost); + * comparison, logging, and serialization all behave as ordinary strings. + * + * Policy: a package brands the ids it owns — `CallId` in dsh-llm (tool-call + * correlation), the shared agent/session `SessionId` in dsh-session, and + * `JobId` in dsh-jobs. Branding is for ids that cross package boundaries and + * could plausibly be confused; not every string needs a brand. + * This package owns ONLY the primitive — no concrete id, no runtime code beyond + * the (erased) type — so the brand vocabulary stays dependency-free and a + * package can brand its ids without depending on an unrelated capability + * package. + * + * @module @deepseek-ai/dsh-brand + */ +declare const BRAND: unique symbol; +/** A string carrying a compile-time-only brand `B`. */ +export type Branded = string & { + readonly [BRAND]: B; +}; +export {}; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/types/invariant.d.ts new file mode 100644 index 0000000..257604b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-brand`. + * @module @deepseek-ai/dsh-brand/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "brand-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/package.json new file mode 100644 index 0000000..c8f9169 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-brand", + "description": "Type-only Branded nominal-typing primitive for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/util/brand" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.i18n.yaml new file mode 100644 index 0000000..7a31df8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/brand/README.md +README.md: ce05a652e2f863f737bf71fc473224fc16e25ab9 +README.zh.md: 07d1279b601d38d4dcf9ca10ddeccb3c3ed3547b diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.md new file mode 100644 index 0000000..ce05a65 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.md @@ -0,0 +1,28 @@ +# dsh-brand + +English | [中文](README.zh.md) + +The `Branded` nominal-typing primitive — a tiny, **type-only** package (no runtime code, no harness-package dependency) shared by every package that owns a cross-boundary id. + +## What `Branded` is + +A brand makes structurally-identical strings non-interchangeable at the type level: a `SessionId` cannot be passed where a `CallId` is expected, even though both are plain `string`s at runtime. + +```ts +import type { Branded } from '@deepseek-ai/dsh-brand' + +export type SessionId = Branded<'SessionId'> + +/** Brand a string as a SessionId (a plain cast — zero runtime cost). */ +export function SessionId(id: string): SessionId { + return id as SessionId +} +``` + +Construction goes through the per-id factory in the owning package. Comparison, logging, JSON serialization, and the wire format behave as for an ordinary string; the brand is erased at compile time. + +## Policy: brand ids that cross package boundaries + +A package brands the ids it owns — `CallId` in `dsh-llm`, the shared agent/session `SessionId` in `dsh-session`, and `JobId` in `dsh-jobs`. Brand cross-package ids that could plausibly be confused; not every string needs one. + +This package owns only the primitive. Keeping it dependency-free lets `dsh-jobs`, for example, brand `JobId` without importing an unrelated capability package merely to reach `Branded`. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.zh.md new file mode 100644 index 0000000..07d1279 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/README.zh.md @@ -0,0 +1,28 @@ +# dsh-brand + +[English](README.md) | 中文 + +`Branded` 名义类型原语:一个微小的**仅类型**包,无运行时代码,也不依赖其他 harness 包;所有负责跨边界 id 的包都会共享它。 + +## `Branded` 是什么 + +品牌使 `SessionId` 和 `CallId` 这样结构相同的字符串在类型层面不可互换,尽管两者在运行时都是普通 `string`。 + +```ts +import type { Branded } from '@deepseek-ai/dsh-brand' + +export type SessionId = Branded<'SessionId'> + +/** Brand a string as a SessionId (a plain cast — zero runtime cost). */ +export function SessionId(id: string): SessionId { + return id as SessionId +} +``` + +构造操作通过所属包中各 id 专用的工厂完成。比较、日志记录、JSON 序列化和协议格式(wire format)的行为与普通字符串相同;品牌信息会在编译时被擦除。 + +## 策略:为跨包边界的 id 添加品牌 + +包为自己拥有的 id 添加品牌:`CallId` 位于 `dsh-llm`,共享的 agent/会话 `SessionId` 位于 `dsh-session`,`JobId` 位于 `dsh-jobs`。为可能被混淆的跨包 id 添加品牌,但无需为每个字符串都添加。 + +该包只负责这一原语。保持无依赖意味着,例如 `dsh-jobs` 可以为 `JobId` 使用品牌类型,而无需仅为使用 `Branded` 而导入不相关的功能包。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/index.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/index.js @@ -0,0 +1 @@ +export {}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/invariant.js new file mode 100644 index 0000000..82705fb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-brand`. +* @module @deepseek-ai/dsh-brand/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-brand"; +/** Cordis companion plugin name. */ +const name = "brand-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value +* algebra is enforced by unit tests. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/types/index.d.ts new file mode 100644 index 0000000..8bc0741 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/types/index.d.ts @@ -0,0 +1,29 @@ +/** + * The `Branded` nominal-typing primitive — a type-only utility (no runtime + * code, no harness-package dependency) shared by every package that owns a + * cross-boundary id. + * + * A brand makes structurally-identical strings non-interchangeable at the type + * level: a `SessionId` cannot be passed where a `CallId` is expected, even + * though both are plain strings at runtime. Construction goes through a per-id + * factory in the OWNING package (a plain cast inside — zero runtime cost); + * comparison, logging, and serialization all behave as ordinary strings. + * + * Policy: a package brands the ids it owns — `CallId` in dsh-llm (tool-call + * correlation), the shared agent/session `SessionId` in dsh-session, and + * `JobId` in dsh-jobs. Branding is for ids that cross package boundaries and + * could plausibly be confused; not every string needs a brand. + * This package owns ONLY the primitive — no concrete id, no runtime code beyond + * the (erased) type — so the brand vocabulary stays dependency-free and a + * package can brand its ids without depending on an unrelated capability + * package. + * + * @module @deepseek-ai/dsh-brand + */ +declare const BRAND: unique symbol; +/** A string carrying a compile-time-only brand `B`. */ +export type Branded = string & { + readonly [BRAND]: B; +}; +export {}; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/types/invariant.d.ts new file mode 100644 index 0000000..257604b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-brand`. + * @module @deepseek-ai/dsh-brand/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "brand-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/package.json new file mode 100644 index 0000000..0c0437e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-brand", + "description": "Type-only Branded nominal-typing primitive for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/util/brand" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-attachment b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-attachment new file mode 120000 index 0000000..ad086eb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-attachment @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.i18n.yaml new file mode 100644 index 0000000..4745644 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/client/connection/README.md +README.md: f0a707cc5f3a962c7852f7323c727d0a39a57b10 +README.zh.md: b529eebf9af93e36b6b92c19964678b7f5a04ea1 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.md new file mode 100644 index 0000000..f0a707c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.md @@ -0,0 +1,26 @@ +# @deepseek-ai/dsh-client-connection + +English | [中文](README.zh.md) + +Wire consumer layer: the client plugin's apply mounts `ctx.connection` (shared api client + current-page loopback state + observable generation-scoped `hostDescription` + single-consumer stream-loop starter); the export face carries the wire contract types, the `AbstractApiClient` abstraction, and the loop's sink/config types. Each successful readiness handshake publishes the exact `host.describe` value before `onConnected`; generation loss and explicit stop clear it, so native-capability consumers never retain a disconnected answer. The browser carrier uses HTTP POST for unary and respond operations and opens one downlink-only WebSocket each for `events.mux` and `events.host`; the in-process carrier satisfies the same two-stream abstraction. The Host half owns the single `/api` route and its Fetch bridge; a registered Typert interceptor claims its Remote endpoints before the API Proxy fallback. Loopback hostname classification stays package-internal: the `/api` Host fence and WebSocket upgrades use it directly, while other client plugins consume the derived `ctx.connection.isLoopback` state. The node half's `/api` route pins the privileged method set (`host.pickDirectory`, `host.openPath`, and the whole configuration plane — `settings.describe`/`openDocument`/`update`/`replace`/`mutate` and `credentials.describe`/`set`/`unset`; reads and native actions included, since describing returns the exposed configuration, opening acts on the Host desktop, and probing an arbitrary reference reports where a credential comes from — and the agent-preset authoring plane, `agentPreset.read`/`copy`/`openDocument`/`remove`, since a composition names the plugins a session runs, so reading one is reconnaissance, and copy/remove/openDocument manage the roster and drive the host desktop (authoring is copy-only, so none of them accepts composition text or a path); `agentPreset.list` and `agentPreset.select` stay out — the roster carries only ids and trust, and choosing a preset grants nothing `session.create`'s own `agentPreset` did not, over a default that already carries bash) to loopback by passing the trust fence with an empty trust list — a declared `trustedHosts` authority reaches every other method, while these stay loopback-local until a real authentication layer exists. The platform carriers and ConnectionController loop are package-internal; apply selects and drives them. The downlink boundary is documented in the [WebSocket downlink carrier Agent Note](../../../.agents/notes/implemented/architecture/2026-08-04-websocket-downlink-carrier.md). + +## /api browser-trust fence + +The node half guards every entry under `/api` before bridging or upgrading (`src/api-request-trust.ts`). Every request — browser-marked or not — must present a `Host` that is a loopback authority or matches a `trustedHosts` entry: exact on `host:port` entries, any port on port-less entries, both sides compared through WHATWG normalization (DNS-rebinding defense). There is deliberately no shortcut for unmarked HTTP requests: over plain HTTP a browser attaches neither `Origin` nor Fetch-Metadata to image and navigation reads, so an unmarked request may still be a rebound browser read with a readable response, and Host is the one header rebinding cannot forge; a browser WebSocket handshake carries `Origin` and passes the same comparison. Non-browser clients pass the same fence via loopback, deployment-derived LAN IP literals, or a declared authority. When markers are present, an attached `Origin` must equal the Host authority, and an explicit `sec-fetch-site: cross-site` marker is refused. A `trustedHosts` entry that is not a bare, canonical `host[:port]` authority — one WHATWG parsing reads back exactly as written — fails the plugin load loudly: parsing would otherwise quietly authorize the hostname inside `harness.internal/path`, or broaden a dangling-colon or zero-padded port to an any-port grant. HTTP failures answer plain 403 before any RPC dispatch; upgrade failures reject the handshake before any event stream starts. Non-loopback compositions must trust their serving authorities explicitly: the Web runtime derives LAN IP literals from an all-interfaces server config, while `trustedHosts` in cordis.yml and the CLI's `--trusted-host` flag declare named authorities. `dsh web --host 0.0.0.0` is intentionally unsupported until remote access has an authentication layer. The fence is a reachability policy, not authentication; the Web carrier provides no authentication layer. Decision record: [the api browser-trust boundary Agent Note](../../../.agents/notes/implemented/architecture/2026-07-28-api-browser-trust-boundary.md). + +## `/api` WebSocket downlinks + +`/api/events.mux` and `/api/events.host` each accept a WebSocket upgrade and send only the corresponding `ServerRequest` text messages to the browser; the client sends no application data over these sockets. If either socket ends, the current connection generation fails and rebuilds both streams; readiness still requires both sockets to be open and the `host.describe` HTTP call to succeed. Host teardown terminates both sockets, aborts their sources, and waits for source cleanup before returning. Ordinary network GETs to these paths return 426 with no SSE fallback; `toFetchHandler`'s SSE codec serves only the isomorphic in-process carrier. + +## Model Experience + +None, as the wire consumer layer moves already-composed messages between browser and host; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **History resumes an unattached session** — opening history may create the host-side agent and add latency to the first open; there is no persistence-only read path. +- **The `/api` bridge buffers each request body in memory** — `maxRequestBodyBytes` (default 160 MiB, sized for the default 100 MiB aggregate image limit after base64 expansion plus envelope headroom) is therefore also the per-request resident bound; a streaming body path would be needed to lower it without shrinking the image limits. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.zh.md new file mode 100644 index 0000000..b529eeb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/README.zh.md @@ -0,0 +1,26 @@ +# @deepseek-ai/dsh-client-connection + +[English](README.md) | 中文 + +协议消费层:客户端插件的 apply 会挂载 `ctx.connection`(共享 API 客户端 + 当前页面的 loopback 状态 + 可观察且按 generation 生效的 `hostDescription` + 单消费方流循环启动器);导出表层携带协议约定类型、`AbstractApiClient` 抽象,以及循环的 sink/配置类型。每次就绪握手成功后,都会在 `onConnected` 之前发布完整的 `host.describe` 值;generation 失效或显式 stop 会清空它,因此原生能力消费者不会保留已经断线的判断。浏览器载体以 HTTP POST 发送 unary/respond,并为 `events.mux` 与 `events.host` 各开一条只下行的 WebSocket;进程内载体满足同一双流抽象。Host half 持有唯一 `/api` route 及其 Fetch bridge;已注册的 Typert interceptor 会先认领自己的 Remote endpoint,未认领请求再回退 API Proxy。Loopback hostname 判定逻辑留在包内部:`/api` Host fence 与 WebSocket upgrade 会直接使用它,其他客户端插件则消费派生的 `ctx.connection.isLoopback` 状态。node 半侧的 `/api` 路由让特权方法集(`host.pickDirectory`、`host.openPath`,以及整个配置面——`settings.describe`/`openDocument`/`update`/`replace`/`mutate` 与 `credentials.describe`/`set`/`unset`;读取与原生操作也在内,因为 describe 会返回已暴露的配置、打开操作会作用于 Host 桌面,而探测任意引用会报出某条凭据来自何处——以及 agent(智能体) preset 的创作面 `agentPreset.read`/`copy`/`openDocument`/`remove`,因为组装指明了一个会话所运行的插件,读取它是侦察,而 copy/remove/openDocument 管理名单并驱动宿主桌面(创作只有复制一种写入,因此这些方法都不接收组装文本或路径);`agentPreset.list` 与 `agentPreset.select` 不在其中——名单只携带 id 与信任级别,而选择一个 preset 并不比 `session.create` 自带的 `agentPreset` 多给任何能力,何况默认 preset 本就带着 bash)以空信任表过信任 fence,从而钉在回环——已声明的 `trustedHosts` 授权可达其余全部方法,而这些方法在真正的认证层出现之前仍只限回环本机。平台载体与 ConnectionController 循环属于包内部;apply 负责选择并驱动它们。下行边界见 [WebSocket 下行载体 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-04-websocket-downlink-carrier.md)。 + +## /api 浏览器信任栅栏 + +node 半侧在桥接或 upgrade 前守卫 `/api` 下的每个入口(`src/api-request-trust.ts`)。每个请求——无论是否带浏览器标记——`Host` 都必须是回环地址权威,或与某个 `trustedHosts` 条目匹配:带端口的 `host:port` 条目精确匹配,不带端口的条目匹配任意端口,两侧均经 WHATWG 归一化后比较(DNS rebinding 防御)。刻意不为无浏览器标记的 HTTP 请求开捷径:明文 HTTP 下浏览器的图片与导航读取既不带 `Origin` 也不带 Fetch-Metadata,因此无标记请求仍可能是被重绑页面发起的、响应可被读走的读取,而 Host 是重绑唯一伪造不了的请求头;WebSocket 浏览器握手会带 `Origin` 并通过同一道比较。非浏览器客户端经由回环地址、部署推导的 LAN IP 字面量或已声明的权威通过同一道栅栏。当标记存在时,如附带 `Origin`,则它必须与 Host 权威完全一致;显式的 `sec-fetch-site: cross-site` 标记一律拒绝。不是纯的、规范形 `host[:port]` 权威的 `trustedHosts` 条目——即 WHATWG 解析读回后与原文不完全一致的——会让插件加载明确报错:否则解析会悄悄授权 `harness.internal/path` 这类笔误里的 hostname,或把悬空冒号、补零端口放大成任意端口授权。HTTP 失败在任何 RPC 分发之前以纯 403 应答,upgrade 失败在启动任何事件流前拒绝握手。非回环组合必须显式信任其服务权威:Web 运行时从全接口服务器配置推导 LAN IP 字面量,cordis.yml 中的 `trustedHosts` 与 CLI(命令行界面)的 `--trusted-host` flag 则声明具名权威。`dsh web --host 0.0.0.0` 在远程访问具备认证层之前有意不受支持。这道栅栏是可达性策略,而不是认证;Web 载体不提供认证层。决策记录:[api 浏览器信任边界 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-28-api-browser-trust-boundary.md)。 + +## `/api` WebSocket 下行 + +`/api/events.mux` 与 `/api/events.host` 各接受一条 WebSocket upgrade,并只向浏览器发送对应的 `ServerRequest` 文本消息;客户端不会在这些 socket 上发送业务数据。任一 socket 结束都会使当前 connection generation 失败并重建两条流,连接就绪仍要求两条 socket 均已打开且 `host.describe` HTTP 调用成功。Host teardown 会终止两条 socket、中止各自的 source,并等待 source 清理完成后再返回。普通网络 GET 这些路径会返回 426,不保留 SSE(Server-Sent Events)回退;`toFetchHandler` 的 SSE 编解码只服务进程内同构载体。 + +## 模型体验 + +无。协议消费层只在浏览器与主机之间搬运已经组合好的消息;这里没有任何内容进入模型请求。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **History 会恢复未附加的会话**:打开 history 可能创建宿主侧 agent,并增加首次打开的延迟;没有仅从持久化读取的路径。 +- **`/api` 桥把每个请求体整体缓冲在内存里**:`maxRequestBodyBytes`(默认 160 MiB,按默认 100 MiB 图片总量上限经 base64 膨胀加信封余量得出)因此同时是单请求的驻留内存上界;要降低它而不缩小图片限额,需要流式请求体路径。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/client.js new file mode 100644 index 0000000..3e4ae0e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/client.js @@ -0,0 +1,10212 @@ +window.__ModuleLoader__.load({ + id: "@deepseek-ai/dsh-client-connection", + factory: (require) => { + var module = { exports: {} }; + var exports = module.exports; + Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); + //#region lib/types/client/connection.js + const CONNECTION_DEFAULTS = { + backoffBaseMs: 500, + backoffFactor: 2, + backoffMaxMs: 1e4, + streamOpenTimeoutMs: 3e3 + }; + function sleep(ms, signal) { + return new Promise((resolve) => { + const t = setTimeout(done, ms); + signal.addEventListener("abort", done, { once: true }); + function done() { + clearTimeout(t); + signal.removeEventListener("abort", done); + resolve(); + } + }); + } + /** + * Opens both streams and keeps iterating (pull mode: nothing reads the socket and the tap + * never fires unless someone for-awaits), reconnecting with exponential backoff on loss. + * State (generation/attempt) is instance-private, never in the store. + * The pump body feeds each frame to a sink (sink exceptions must + * not kill the pump — a broken business layer must not drag down the connection layer). + */ + var ConnectionController = class { + api; + sinks; + generation = 0; + attempt = 0; + current = null; + running = false; + lastState = null; + config; + constructor(api, sinks = {}, config = {}) { + this.api = api; + this.sinks = sinks; + this.config = { + ...CONNECTION_DEFAULTS, + ...config + }; + } + /** Idempotent: begin the connect/pump/reconnect loop. */ + start() { + if (this.running) return; + this.running = true; + this.loop(); + } + /** Stop the loop and abort the current generation's streams. */ + stop() { + this.running = false; + this.current?.abort(); + this.current = null; + } + backoffDelay(attempt) { + const { backoffBaseMs, backoffFactor, backoffMaxMs } = this.config; + const cap = Math.min(backoffMaxMs, backoffBaseMs * backoffFactor ** Math.max(0, attempt - 1)); + return cap / 2 + Math.random() * (cap / 2); + } + /** Read through a method: stop() flips the flag across awaits, so narrowing from the loop condition must not stick. */ + isRunning() { + return this.running; + } + /** Re-read both mutable liveness guards after a potentially reentrant sink. */ + isGenerationActive(controller) { + return this.isRunning() && !controller.signal.aborted; + } + async loop() { + while (this.running) { + const gen = ++this.generation; + const ac = new AbortController(); + this.current = ac; + /* v8 ignore next -- initializer placeholder: the Promise executor + * below runs synchronously and replaces it before anyone can call it. */ + let muxOpened = () => {}; + /* v8 ignore next -- same placeholder pattern as muxOpened. */ + let hostOpened = () => {}; + const streamsOpen = Promise.all([new Promise((resolve) => { + muxOpened = resolve; + }), new Promise((resolve) => { + hostOpened = resolve; + })]); + const failed = new Promise((resolve) => { + const settle = () => { + if (gen === this.generation && !ac.signal.aborted) ac.abort(); + resolve(); + }; + this.pumpStream(this.api.events.mux({}, ac.signal, muxOpened), this.sinks.onMuxEnvelope, settle); + this.pumpStream(this.api.events.host({}, ac.signal, hostOpened), this.sinks.onHostEnvelope, settle); + }); + try { + const timeout = new AbortController(); + const [description] = await Promise.all([this.api.host.describe({}), Promise.race([streamsOpen, sleep(this.config.streamOpenTimeoutMs, timeout.signal)])]); + timeout.abort(); + const descriptionResult = description.result; + if (!descriptionResult.ok) throw new Error(`host.describe failed: ${descriptionResult.error.code}: ${descriptionResult.error.message}`); + if (ac.signal.aborted) throw new Error("generation aborted during readiness handshake"); + this.attempt = 0; + this.emitState("connected"); + if (this.isGenerationActive(ac)) this.callSink(() => { + this.sinks.onConnected?.(descriptionResult.value); + }); + } catch { + if (!ac.signal.aborted) ac.abort(); + } + await failed; + if (!this.isRunning()) return; + this.emitState("reconnecting"); + this.attempt += 1; + console.warn(`[web-runtime] connection lost, retry #${this.attempt}`); + const idle = new AbortController(); + await sleep(this.backoffDelay(this.attempt), idle.signal); + } + } + /** Deduplicated state emission (sink isolation applies). */ + emitState(state) { + if (this.lastState === state) return; + this.lastState = state; + this.callSink(() => this.sinks.onStateChange?.(state)); + } + async pumpStream(stream, sink, onEnd) { + try { + for await (const envelope of stream) { + if (envelope.payload.type === "stream/error") break; + if (sink !== void 0) this.callSink(() => { + sink(envelope); + }); + } + } catch {} + onEnd(); + } + /** Sink exception isolation: a business-layer throw is logged only, never affecting pump or reconnect semantics. */ + callSink(fn) { + try { + fn(); + } catch (error) { + console.error("[web-runtime] connection sink threw:", error); + } + } + }; + //#endregion + //#region ../../llm/llm/lib/types/brand.js + /** + * dsh-llm's owned branded ids: tool-call correlation and provider request + * diagnostics. + * + * The `Branded` primitive itself lives in `@deepseek-ai/dsh-brand` (a + * zero-dependency type-only package) so every owner of a cross-boundary id can + * brand it without depending on dsh-llm; see that package's README for the + * nominal-typing policy. + * + * @module @deepseek-ai/dsh-llm/brand + */ + /** + * Brand a message identifier. + * @param id - the opaque message identifier. + * @returns the same string, branded; no validation is performed. + */ + function MessageId(id) { + return id; + } + /** + * Brand a string as a {@link CallId}. + * @param id - the provider-issued (or synthesized) call id. + * @returns the same string, branded; no validation is performed. + */ + function CallId(id) { + return id; + } + //#endregion + //#region ../../llm/llm/lib/types/call-config.js + /** + * Deep-freeze a value in place with an iterative traversal, guarding cycles, + * so later mutation throws without imposing a JavaScript call-stack depth cap. + * {@link AbortSignal} objects are deliberately skipped because they are the + * request's live cancellation channel and freezing them breaks abort. + * @param value - the value to freeze in place. + * @returns the same value, frozen. + */ + function deepFreeze(value) { + const seen = /* @__PURE__ */ new WeakSet(); + const pending = [{ + kind: "visit", + node: value + }]; + while (pending.length > 0) { + const task = pending.pop(); + /* v8 ignore next -- the loop condition guarantees one pending task. */ + if (task === void 0) continue; + if (task.kind === "property") { + pending.push({ + kind: "visit", + node: task.source[task.key] + }); + continue; + } + const node = task.node; + if (node === null || typeof node !== "object") continue; + if (node instanceof AbortSignal) continue; + if (seen.has(node)) continue; + seen.add(node); + Object.freeze(node); + const keys = Object.keys(node); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === void 0) continue; + pending.push({ + kind: "property", + source: node, + key + }); + } + } + return value; + } + //#endregion + //#region ../../llm/llm/lib/types/message.js + /** Message value types, identity, and immutable construction helpers. */ + /** + * Detach and deep-freeze a message whose identity already exists. + * @param message - complete message, including its stable identity. + * @returns an immutable snapshot that preserves the identity. + */ + function freezeMessage(message) { + return deepFreeze(structuredClone(message)); + } + /** + * Create one identified message and freeze it before publication. + * @param input - complete role, content, and source for a new message. + * @returns an immutable message with a fresh stable identity. + */ + function createMessage(input) { + return freezeMessage({ + ...input, + id: MessageId(crypto.randomUUID()) + }); + } + /** + * Create one identified user-role message and freeze it before publication. + * @param input - complete content and source for a new user message. + * @returns an immutable user message with a fresh stable identity. + */ + function createUserMessage(input) { + return createMessage({ + ...input, + role: "user" + }); + } + /** + * Create one identified model-produced assistant message and freeze it before publication. + * @param input - complete content plus the provider, model, and optional replay state for a new assistant message. + * @returns an immutable assistant message with fixed role/source tags and a fresh stable identity. + */ + function createAssistantMessage(input) { + return createMessage({ + role: "assistant", + content: input.content, + source: { + kind: "model", + ...input.source + } + }); + } + /** + * Create and freeze one identified tool-result message. + * @param input - call identity, raw result blocks, and outcome. + * @returns an immutable user-role tool-result message. + */ + function createToolResultMessage(input) { + return createUserMessage({ + source: { + kind: "tool", + callId: input.callId + }, + content: [{ + type: "tool-result", + toolCallId: input.callId, + content: input.content, + isError: input.isError + }] + }); + } + /** + * Whether a stream chunk carries visible model output (the first-token + * boundary shared by client step timing and the whole-log sessionStats + * projection). Empty deltas (heartbeats, empty tool-call frames) do not count + * as a first token. + * @param chunk - the stream chunk to test. + * @returns true when the chunk contains a non-empty text/reasoning/tool delta. + */ + function isTokenDelta(chunk) { + switch (chunk.type) { + case "text-delta": + case "reasoning-delta": return chunk.text !== ""; + case "tool-call-delta": return chunk.argumentsDelta !== "" || chunk.name !== void 0; + default: return false; + } + } + //#endregion + //#region ../../core/session/lib/types/surface.js + /** + * Surface layer on top of the session event log: an ordered view of events + * that produce LLM messages. The append-only log remains the source of truth. + * + * Browser-safe: web clients consume this subpath export, so it must stay free + * of `node:` imports (they break the vite bundle). + * + * @module @deepseek-ai/dsh-session/surface + */ + /** Runtime counterpart of the message-producing event union. */ + const SURFACE_EVENT_TYPES = new Set([ + "user/message", + "assistant/message", + "tool/result" + ]); + /** + * Whether an event type can join the model-visible surface. + * @param type - event type to test. + * @returns true for one of the three message-producing event types. + */ + function isSurfaceEligibleType(type) { + return SURFACE_EVENT_TYPES.has(type); + } + /** + * Project a single event into the LLM message it derives to, or null when it + * produces none — a non-surface event (chunk, boundary, log-only record) or an + * empty-content assistant/message (which exists only to host usage). This is + * THE per-node projection rule: `Session.deriveMessages` folds it over the + * live surface, external reconstructors and pure projections fold the same + * function over a log prefix's surface to rebuild the exact messages any + * request was built from. The returned message is the already frozen message + * nested in the event wrapper and shared by delivery, durable history, and + * model requests. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ + function deriveEventMessage(event) { + switch (event.type) { + case "user/message": return event.data; + case "assistant/message": + if (event.data.message.content.length === 0) return null; + return event.data.message; + case "tool/result": return event.data.message; + default: return null; + } + } + /** Create an empty surface fold state. */ + function createFoldState() { + return { + nodes: [], + replaceGeneration: 0 + }; + } + /** Whether a runtime value is a non-negative safe event sequence. */ + function isEventSeq(value) { + return typeof value === "number" && Number.isSafeInteger(value) && value >= 0; + } + /** Whether a runtime value is the exact positional-replacement shape. */ + function isReplaceOp(value) { + const op = value; + return Object.keys(op).length === 3 && Object.hasOwn(op, "op") && Object.hasOwn(op, "start") && Object.hasOwn(op, "end") && op["op"] === "replace" && isEventSeq(op["start"]) && isEventSeq(op["end"]); + } + /** Validate event-local surface eligibility and return its operation. */ + function surfaceOpOf(event) { + const raw = event; + if (!isSurfaceEligibleType(event.type)) { + if (raw.surfaceOp !== void 0) throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry surfaceOp`); + if (raw.sourceEventSeqs !== void 0) throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry sourceEventSeqs`); + return; + } + const op = raw.surfaceOp; + if (op === void 0) throw new Error(`session event "${event.type}" is surface-eligible and requires a surfaceOp marker`); + if (op === "append") return op; + if (op === null || typeof op !== "object" || Array.isArray(op)) throw new Error(`session event "${event.type}" carries an invalid surfaceOp`); + if (!isReplaceOp(op)) throw new Error(`session event "${event.type}" carries an invalid replace surfaceOp`); + return op; + } + /** Validate cited source-event seqs against prior log entries and the replacement range. */ + function assertProvenance(event, shadowedSeqs) { + const raw = event.sourceEventSeqs; + const sources = /* @__PURE__ */ new Set(); + if (raw !== void 0) { + if (!Array.isArray(raw)) throw new Error(`sourceEventSeqs on event at seq ${event.seq} must be an array when present`); + if (raw.length === 0 && event.type !== "assistant/message") throw new Error("sourceEventSeqs must not be empty except on assistant/message"); + let nonEarlierSource; + for (const source of raw) { + if (!isEventSeq(source)) throw new Error(`session event "${event.type}" sourceEventSeqs must densely contain non-negative safe integers`); + sources.add(source); + if (nonEarlierSource === void 0 && source >= event.seq) nonEarlierSource = source; + } + if (sources.size !== raw.length) throw new Error("sourceEventSeqs must not contain duplicates"); + if (nonEarlierSource !== void 0) throw new Error(`sourceEventSeqs must reference earlier events: ${nonEarlierSource} >= current seq ${event.seq}`); + } + const missing = shadowedSeqs.filter((seq) => !sources.has(seq)); + if (missing.length > 0) throw new Error(`surface replace: sourceEventSeqs must include every shadowed surface node; missing ${missing.join(", ")}`); + } + /** Locate one replacement range without mutating the current fold state. */ + function replacementRange(state, op) { + const startIdx = state.nodes.indexOf(op.start); + if (startIdx === -1) throw new Error(`surface replace: start seq ${op.start} not found in surface`); + const endIdx = state.nodes.indexOf(op.end); + if (endIdx === -1) throw new Error(`surface replace: end seq ${op.end} not found in surface`); + if (startIdx > endIdx) throw new Error(`surface replace: start seq ${op.start} (index ${startIdx}) is after end seq ${op.end} (index ${endIdx})`); + return { + startIdx, + endIdx, + shadowedSeqs: state.nodes.slice(startIdx, endIdx + 1) + }; + } + /** + * Deep structural equality over the session-event JSON value domain + * (null/boolean/number/string, arrays, plain objects). Replaces + * `node:util`'s isDeepStrictEqual to keep this module browser-safe. + */ + function isDeepEqualJson(a, b) { + if (a === b) return true; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false; + return a.every((item, i) => isDeepEqualJson(item, b[i])); + } + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false; + const aKeys = Object.keys(a); + const bRecord = b; + if (aKeys.length !== Object.keys(b).length) return false; + return aKeys.every((key) => Object.hasOwn(b, key) && isDeepEqualJson(a[key], bRecord[key])); + } + /** Restrict a tool-result replacement to one current result's content. */ + function assertToolResultRewrite(event, shadowedSeqs, events, baseSeq) { + if (event.type !== "tool/result") return; + if (shadowedSeqs.length !== 1) throw new Error("tool/result surface replacement must rewrite exactly one current node"); + for (const originalSeq of shadowedSeqs) { + const original = events[originalSeq - baseSeq]; + if (original?.type !== "tool/result") throw new Error("tool/result surface replacement must target a current tool/result"); + const originalRest = { ...original.data }; + const replacementRest = { ...event.data }; + const originalResult = original.data.message.content[0]; + const replacementResult = event.data.message.content[0]; + originalRest["message"] = { + ...original.data.message, + content: [{ + ...originalResult, + content: null + }] + }; + replacementRest["message"] = { + ...event.data.message, + content: [{ + ...replacementResult, + content: null + }] + }; + if (!isDeepEqualJson(originalRest, replacementRest)) throw new Error("tool/result surface replacement may change only content"); + } + } + /** Validate one event at its replay boundary and prepare its atomic fold transition. */ + function planSurfaceEvent(state, event, expectedSeq, events, baseSeq) { + if (event.seq !== expectedSeq) throw new Error(`session event seq ${event.seq} is not contiguous; expected ${expectedSeq}`); + const surfaceOp = surfaceOpOf(event); + if (surfaceOp === void 0) return; + if (surfaceOp === "append") { + assertProvenance(event, []); + return { + kind: "append", + seq: event.seq + }; + } + const range = replacementRange(state, surfaceOp); + assertProvenance(event, range.shadowedSeqs); + assertToolResultRewrite(event, range.shadowedSeqs, events, baseSeq); + return { + kind: "replace", + seq: event.seq, + start: surfaceOp.start, + end: surfaceOp.end, + ...range + }; + } + /** Apply one event and return replacement metadata only when one occurred. */ + function applySurfaceEvent(state, event, expectedSeq, events, baseSeq) { + return applySurfacePlan(state, planSurfaceEvent(state, event, expectedSeq, events, baseSeq)); + } + /** Commit one previously validated surface transition. */ + function applySurfacePlan(state, plan) { + if (plan?.kind === "append") state.nodes.push(plan.seq); + else if (plan?.kind === "replace") { + state.nodes.splice(plan.startIdx, plan.endIdx - plan.startIdx + 1, plan.seq); + state.replaceGeneration += 1; + } + if (plan?.kind !== "replace") return; + return { + seq: plan.seq, + start: plan.start, + end: plan.end, + shadowedSeqs: plan.shadowedSeqs + }; + } + /** + * Replay a complete session log through the canonical surface fold. + * @param events - session events in contiguous seq order. + * @returns detached current sequences and replacement history. + * @throws when an event violates surface metadata, source-event references, range, or tool-result rewrite rules. + */ + function foldSurface(events) { + const state = createFoldState(); + const replacements = []; + for (const [index, event] of events.entries()) { + const replacement = applySurfaceEvent(state, event, index, events, 0); + if (replacement !== void 0) replacements.push(replacement); + } + return { + nodes: [...state.nodes], + replacements + }; + } + //#endregion + //#region ../../host/apiproxy/lib/types/api/rpc.js + /** + * Four-quadrant RPC message model. Channels and messages are decoupled: HTTP, + * WebSocket, and in-process SSE are physical carriers, while logical messages + * are channel-independent and form a four-member discriminated union. + * api/ contract layer: zero Node dependencies, importable from the browser. + */ + /** + * Brands a string as RpcId (same precedent as core `SessionId()`). Minted by the initiator: + * client-request → client mints; server-request → host mints (answerable frames get a stable + * logical id, pure pushes mint a fresh one each time). + * @param id - Raw id string (implementations mint UUIDs; tests may pass fixtures). + * @returns The same string, branded (compile-time cast, zero runtime cost). + */ + function RpcId(id) { + return id; + } + /** + * Fold a transport exception into the RpcResult error branch (unified error + * API; 'internal' as the catch-all code). Lives with RpcResult so every + * carrier consumer folds the same way. + * @param error - the thrown value from the carrier. + * @returns the error branch of an RpcResult. + */ + function transportError(error) { + return { + ok: false, + error: { + code: "internal", + message: error instanceof Error ? error.message : String(error), + details: {} + } + }; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js + var _a$1; + function $constructor(name, initializer, params) { + function init(inst, def) { + if (!inst._zod) Object.defineProperty(inst, "_zod", { + value: { + def, + constr: _, + traits: /* @__PURE__ */ new Set() + }, + enumerable: false + }); + if (inst._zod.traits.has(name)) return; + inst._zod.traits.add(name); + initializer(inst, def); + const proto = _.prototype; + const keys = Object.keys(proto); + for (let i = 0; i < keys.length; i++) { + const k = keys[i]; + if (!(k in inst)) inst[k] = proto[k].bind(inst); + } + } + const Parent = params?.Parent ?? Object; + class Definition extends Parent {} + Object.defineProperty(Definition, "name", { value: name }); + function _(def) { + var _a; + const inst = params?.Parent ? new Definition() : this; + init(inst, def); + (_a = inst._zod).deferred ?? (_a.deferred = []); + for (const fn of inst._zod.deferred) fn(); + return inst; + } + Object.defineProperty(_, "init", { value: init }); + Object.defineProperty(_, Symbol.hasInstance, { value: (inst) => { + if (params?.Parent && inst instanceof params.Parent) return true; + return inst?._zod?.traits?.has(name); + } }); + Object.defineProperty(_, "name", { value: name }); + return _; + } + var $ZodAsyncError = class extends Error { + constructor() { + super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`); + } + }; + var $ZodEncodeError = class extends Error { + constructor(name) { + super(`Encountered unidirectional transform during encode: ${name}`); + this.name = "ZodEncodeError"; + } + }; + (_a$1 = globalThis).__zod_globalConfig ?? (_a$1.__zod_globalConfig = {}); + const globalConfig = globalThis.__zod_globalConfig; + function config(newConfig) { + if (newConfig) Object.assign(globalConfig, newConfig); + return globalConfig; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.js + function getEnumValues(entries) { + const numericValues = Object.values(entries).filter((v) => typeof v === "number"); + return Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v); + } + function jsonStringifyReplacer(_, value) { + if (typeof value === "bigint") return value.toString(); + return value; + } + function cached(getter) { + return { get value() { + { + const value = getter(); + Object.defineProperty(this, "value", { value }); + return value; + } + throw new Error("cached value already set"); + } }; + } + function nullish(input) { + return input === null || input === void 0; + } + function cleanRegex(source) { + const start = source.startsWith("^") ? 1 : 0; + const end = source.endsWith("$") ? source.length - 1 : source.length; + return source.slice(start, end); + } + function floatSafeRemainder(val, step) { + const ratio = val / step; + const roundedRatio = Math.round(ratio); + const tolerance = Number.EPSILON * Math.max(Math.abs(ratio), 1); + if (Math.abs(ratio - roundedRatio) < tolerance) return 0; + return ratio - roundedRatio; + } + const EVALUATING = /* @__PURE__*/ Symbol("evaluating"); + function defineLazy(object, key, getter) { + let value = void 0; + Object.defineProperty(object, key, { + get() { + if (value === EVALUATING) return; + if (value === void 0) { + value = EVALUATING; + value = getter(); + } + return value; + }, + set(v) { + Object.defineProperty(object, key, { value: v }); + }, + configurable: true + }); + } + function assignProp(target, prop, value) { + Object.defineProperty(target, prop, { + value, + writable: true, + enumerable: true, + configurable: true + }); + } + function mergeDefs(...defs) { + const mergedDescriptors = {}; + for (const def of defs) Object.assign(mergedDescriptors, Object.getOwnPropertyDescriptors(def)); + return Object.defineProperties({}, mergedDescriptors); + } + function esc(str) { + return JSON.stringify(str); + } + function slugify(input) { + return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, ""); + } + const captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {}; + function isObject(data) { + return typeof data === "object" && data !== null && !Array.isArray(data); + } + const allowsEval = /* @__PURE__*/ cached(() => { + if (globalConfig.jitless) return false; + if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) return false; + try { + new Function(""); + return true; + } catch (_) { + return false; + } + }); + function isPlainObject(o) { + if (isObject(o) === false) return false; + const ctor = o.constructor; + if (ctor === void 0) return true; + if (typeof ctor !== "function") return true; + const prot = ctor.prototype; + if (isObject(prot) === false) return false; + if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) return false; + return true; + } + function shallowClone(o) { + if (isPlainObject(o)) return { ...o }; + if (Array.isArray(o)) return [...o]; + if (o instanceof Map) return new Map(o); + if (o instanceof Set) return new Set(o); + return o; + } + const propertyKeyTypes = /* @__PURE__*/ new Set([ + "string", + "number", + "symbol" + ]); + function escapeRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + } + function clone(inst, def, params) { + const cl = new inst._zod.constr(def ?? inst._zod.def); + if (!def || params?.parent) cl._zod.parent = inst; + return cl; + } + function normalizeParams(_params) { + const params = _params; + if (!params) return {}; + if (typeof params === "string") return { error: () => params }; + if (params?.message !== void 0) { + if (params?.error !== void 0) throw new Error("Cannot specify both `message` and `error` params"); + params.error = params.message; + } + delete params.message; + if (typeof params.error === "string") return { + ...params, + error: () => params.error + }; + return params; + } + function optionalKeys(shape) { + return Object.keys(shape).filter((k) => { + return shape[k]._zod.optin === "optional" && shape[k]._zod.optout === "optional"; + }); + } + const NUMBER_FORMAT_RANGES = { + safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], + int32: [-2147483648, 2147483647], + uint32: [0, 4294967295], + float32: [-34028234663852886e22, 34028234663852886e22], + float64: [-Number.MAX_VALUE, Number.MAX_VALUE] + }; + function pick(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + if (checks && checks.length > 0) throw new Error(".pick() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const newShape = {}; + for (const key in mask) { + if (!(key in currDef.shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + newShape[key] = currDef.shape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + })); + } + function omit(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + if (checks && checks.length > 0) throw new Error(".omit() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const newShape = { ...schema._zod.def.shape }; + for (const key in mask) { + if (!(key in currDef.shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + delete newShape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + })); + } + function extend(schema, shape) { + if (!isPlainObject(shape)) throw new Error("Invalid input to extend: expected a plain object"); + const checks = schema._zod.def.checks; + if (checks && checks.length > 0) { + const existingShape = schema._zod.def.shape; + for (const key in shape) if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead."); + } + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const _shape = { + ...schema._zod.def.shape, + ...shape + }; + assignProp(this, "shape", _shape); + return _shape; + } })); + } + function safeExtend(schema, shape) { + if (!isPlainObject(shape)) throw new Error("Invalid input to safeExtend: expected a plain object"); + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const _shape = { + ...schema._zod.def.shape, + ...shape + }; + assignProp(this, "shape", _shape); + return _shape; + } })); + } + function merge(a, b) { + if (a._zod.def.checks?.length) throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead."); + return clone(a, mergeDefs(a._zod.def, { + get shape() { + const _shape = { + ...a._zod.def.shape, + ...b._zod.def.shape + }; + assignProp(this, "shape", _shape); + return _shape; + }, + get catchall() { + return b._zod.def.catchall; + }, + checks: b._zod.def.checks ?? [] + })); + } + function partial(Class, schema, mask) { + const checks = schema._zod.def.checks; + if (checks && checks.length > 0) throw new Error(".partial() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) for (const key in mask) { + if (!(key in oldShape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + shape[key] = Class ? new Class({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + } + else for (const key in oldShape) shape[key] = Class ? new Class({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + assignProp(this, "shape", shape); + return shape; + }, + checks: [] + })); + } + function required(Class, schema, mask) { + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) for (const key in mask) { + if (!(key in shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + shape[key] = new Class({ + type: "nonoptional", + innerType: oldShape[key] + }); + } + else for (const key in oldShape) shape[key] = new Class({ + type: "nonoptional", + innerType: oldShape[key] + }); + assignProp(this, "shape", shape); + return shape; + } })); + } + function aborted(x, startIndex = 0) { + if (x.aborted === true) return true; + for (let i = startIndex; i < x.issues.length; i++) if (x.issues[i]?.continue !== true) return true; + return false; + } + function explicitlyAborted(x, startIndex = 0) { + if (x.aborted === true) return true; + for (let i = startIndex; i < x.issues.length; i++) if (x.issues[i]?.continue === false) return true; + return false; + } + function prefixIssues(path, issues) { + return issues.map((iss) => { + var _a; + (_a = iss).path ?? (_a.path = []); + iss.path.unshift(path); + return iss; + }); + } + function unwrapMessage(message) { + return typeof message === "string" ? message : message?.message; + } + function finalizeIssue(iss, ctx, config) { + const message = iss.message ? iss.message : unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config.customError?.(iss)) ?? unwrapMessage(config.localeError?.(iss)) ?? "Invalid input"; + const { inst: _inst, continue: _continue, input: _input, ...rest } = iss; + rest.path ?? (rest.path = []); + rest.message = message; + if (ctx?.reportInput) rest.input = _input; + return rest; + } + function getLengthableOrigin(input) { + if (Array.isArray(input)) return "array"; + if (typeof input === "string") return "string"; + return "unknown"; + } + function issue(...args) { + const [iss, input, inst] = args; + if (typeof iss === "string") return { + message: iss, + code: "custom", + input, + inst + }; + return { ...iss }; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/errors.js + const initializer$1 = (inst, def) => { + inst.name = "$ZodError"; + Object.defineProperty(inst, "_zod", { + value: inst._zod, + enumerable: false + }); + Object.defineProperty(inst, "issues", { + value: def, + enumerable: false + }); + inst.message = JSON.stringify(def, jsonStringifyReplacer, 2); + Object.defineProperty(inst, "toString", { + value: () => inst.message, + enumerable: false + }); + }; + const $ZodError = $constructor("$ZodError", initializer$1); + const $ZodRealError = $constructor("$ZodError", initializer$1, { Parent: Error }); + function flattenError(error, mapper = (issue) => issue.message) { + const fieldErrors = {}; + const formErrors = []; + for (const sub of error.issues) if (sub.path.length > 0) { + fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || []; + fieldErrors[sub.path[0]].push(mapper(sub)); + } else formErrors.push(mapper(sub)); + return { + formErrors, + fieldErrors + }; + } + function formatError(error, mapper = (issue) => issue.message) { + const fieldErrors = { _errors: [] }; + const processError = (error, path = []) => { + for (const issue of error.issues) if (issue.code === "invalid_union" && issue.errors.length) issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path])); + else if (issue.code === "invalid_key") processError({ issues: issue.issues }, [...path, ...issue.path]); + else if (issue.code === "invalid_element") processError({ issues: issue.issues }, [...path, ...issue.path]); + else { + const fullpath = [...path, ...issue.path]; + if (fullpath.length === 0) fieldErrors._errors.push(mapper(issue)); + else { + let curr = fieldErrors; + let i = 0; + while (i < fullpath.length) { + const el = fullpath[i]; + if (!(i === fullpath.length - 1)) curr[el] = curr[el] || { _errors: [] }; + else { + curr[el] = curr[el] || { _errors: [] }; + curr[el]._errors.push(mapper(issue)); + } + curr = curr[el]; + i++; + } + } + } + }; + processError(error); + return fieldErrors; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/parse.js + const _parse = (_Err) => (schema, value, _ctx, _params) => { + const ctx = _ctx ? { + ..._ctx, + async: false + } : { async: false }; + const result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) throw new $ZodAsyncError(); + if (result.issues.length) { + const e = new ((_params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, _params?.callee); + throw e; + } + return result.value; + }; + const _parseAsync = (_Err) => async (schema, value, _ctx, params) => { + const ctx = _ctx ? { + ..._ctx, + async: true + } : { async: true }; + let result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) result = await result; + if (result.issues.length) { + const e = new ((params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, params?.callee); + throw e; + } + return result.value; + }; + const _safeParse = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + async: false + } : { async: false }; + const result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) throw new $ZodAsyncError(); + return result.issues.length ? { + success: false, + error: new (_Err ?? $ZodError)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { + success: true, + data: result.value + }; + }; + const safeParse$1 = /* @__PURE__*/ _safeParse($ZodRealError); + const _safeParseAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + async: true + } : { async: true }; + let result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) result = await result; + return result.issues.length ? { + success: false, + error: new _Err(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { + success: true, + data: result.value + }; + }; + const safeParseAsync$1 = /* @__PURE__*/ _safeParseAsync($ZodRealError); + const _encode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _parse(_Err)(schema, value, ctx); + }; + const _decode = (_Err) => (schema, value, _ctx) => { + return _parse(_Err)(schema, value, _ctx); + }; + const _encodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _parseAsync(_Err)(schema, value, ctx); + }; + const _decodeAsync = (_Err) => async (schema, value, _ctx) => { + return _parseAsync(_Err)(schema, value, _ctx); + }; + const _safeEncode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _safeParse(_Err)(schema, value, ctx); + }; + const _safeDecode = (_Err) => (schema, value, _ctx) => { + return _safeParse(_Err)(schema, value, _ctx); + }; + const _safeEncodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _safeParseAsync(_Err)(schema, value, ctx); + }; + const _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => { + return _safeParseAsync(_Err)(schema, value, _ctx); + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/regexes.js + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link cuid2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const cuid = /^[cC][0-9a-z]{6,}$/; + const cuid2 = /^[0-9a-z]+$/; + const ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/; + const xid = /^[0-9a-vA-V]{20}$/; + const ksuid = /^[A-Za-z0-9]{27}$/; + const nanoid = /^[a-zA-Z0-9_-]{21}$/; + /** ISO 8601-1 duration regex. Does not support the 8601-2 extensions like negative durations or fractional/negative components. */ + const duration$1 = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/; + /** A regex for any UUID-like identifier: 8-4-4-4-12 hex pattern */ + const guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/; + /** Returns a regex for validating an RFC 9562/4122 UUID. + * + * @param version Optionally specify a version 1-8. If no version is specified, all versions are supported. */ + const uuid = (version) => { + if (!version) return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/; + return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`); + }; + /** Practical email validation */ + const email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/; + const _emoji$1 = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; + function emoji() { + return new RegExp(_emoji$1, "u"); + } + const ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; + const ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/; + const cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/; + const cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; + const base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/; + const base64url = /^[A-Za-z0-9_-]*$/; + const httpProtocol = /^https?$/; + const e164 = /^\+[1-9]\d{6,14}$/; + const dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`; + const date$1 = /*@__PURE__*/ new RegExp(`^${dateSource}$`); + function timeSource(args) { + const hhmm = `(?:[01]\\d|2[0-3]):[0-5]\\d`; + return typeof args.precision === "number" ? args.precision === -1 ? `${hhmm}` : args.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args.precision}}` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`; + } + function time$1(args) { + return new RegExp(`^${timeSource(args)}$`); + } + function datetime$1(args) { + const time = timeSource({ precision: args.precision }); + const opts = ["Z"]; + if (args.local) opts.push(""); + if (args.offset) opts.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`); + const timeRegex = `${time}(?:${opts.join("|")})`; + return new RegExp(`^${dateSource}T(?:${timeRegex})$`); + } + const string$1 = (params) => { + const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`; + return new RegExp(`^${regex}$`); + }; + const integer = /^-?\d+$/; + const number$1 = /^-?\d+(?:\.\d+)?$/; + const boolean$1 = /^(?:true|false)$/i; + const lowercase = /^[^A-Z]*$/; + const uppercase = /^[^a-z]*$/; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/checks.js + const $ZodCheck = /*@__PURE__*/ $constructor("$ZodCheck", (inst, def) => { + var _a; + inst._zod ?? (inst._zod = {}); + inst._zod.def = def; + (_a = inst._zod).onattach ?? (_a.onattach = []); + }); + const numericOriginMap = { + number: "number", + bigint: "bigint", + object: "date" + }; + const $ZodCheckLessThan = /*@__PURE__*/ $constructor("$ZodCheckLessThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + const curr = (def.inclusive ? bag.maximum : bag.exclusiveMaximum) ?? Number.POSITIVE_INFINITY; + if (def.value < curr) if (def.inclusive) bag.maximum = def.value; + else bag.exclusiveMaximum = def.value; + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value <= def.value : payload.value < def.value) return; + payload.issues.push({ + origin, + code: "too_big", + maximum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckGreaterThan = /*@__PURE__*/ $constructor("$ZodCheckGreaterThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY; + if (def.value > curr) if (def.inclusive) bag.minimum = def.value; + else bag.exclusiveMinimum = def.value; + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value >= def.value : payload.value > def.value) return; + payload.issues.push({ + origin, + code: "too_small", + minimum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMultipleOf = /*@__PURE__*/ $constructor("$ZodCheckMultipleOf", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst) => { + var _a; + (_a = inst._zod.bag).multipleOf ?? (_a.multipleOf = def.value); + }); + inst._zod.check = (payload) => { + if (typeof payload.value !== typeof def.value) throw new Error("Cannot mix number and bigint in multiple_of check."); + if (typeof payload.value === "bigint" ? payload.value % def.value === BigInt(0) : floatSafeRemainder(payload.value, def.value) === 0) return; + payload.issues.push({ + origin: typeof payload.value, + code: "not_multiple_of", + divisor: def.value, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckNumberFormat = /*@__PURE__*/ $constructor("$ZodCheckNumberFormat", (inst, def) => { + $ZodCheck.init(inst, def); + def.format = def.format || "float64"; + const isInt = def.format?.includes("int"); + const origin = isInt ? "int" : "number"; + const [minimum, maximum] = NUMBER_FORMAT_RANGES[def.format]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.format = def.format; + bag.minimum = minimum; + bag.maximum = maximum; + if (isInt) bag.pattern = integer; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (isInt) { + if (!Number.isInteger(input)) { + payload.issues.push({ + expected: origin, + format: def.format, + code: "invalid_type", + continue: false, + input, + inst + }); + return; + } + if (!Number.isSafeInteger(input)) { + if (input > 0) payload.issues.push({ + input, + code: "too_big", + maximum: Number.MAX_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + else payload.issues.push({ + input, + code: "too_small", + minimum: Number.MIN_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + return; + } + } + if (input < minimum) payload.issues.push({ + origin: "number", + input, + code: "too_small", + minimum, + inclusive: true, + inst, + continue: !def.abort + }); + if (input > maximum) payload.issues.push({ + origin: "number", + input, + code: "too_big", + maximum, + inclusive: true, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMaxLength = /*@__PURE__*/ $constructor("$ZodCheckMaxLength", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const curr = inst._zod.bag.maximum ?? Number.POSITIVE_INFINITY; + if (def.maximum < curr) inst._zod.bag.maximum = def.maximum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (input.length <= def.maximum) return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_big", + maximum: def.maximum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMinLength = /*@__PURE__*/ $constructor("$ZodCheckMinLength", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const curr = inst._zod.bag.minimum ?? Number.NEGATIVE_INFINITY; + if (def.minimum > curr) inst._zod.bag.minimum = def.minimum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (input.length >= def.minimum) return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_small", + minimum: def.minimum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckLengthEquals = /*@__PURE__*/ $constructor("$ZodCheckLengthEquals", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.minimum = def.length; + bag.maximum = def.length; + bag.length = def.length; + }); + inst._zod.check = (payload) => { + const input = payload.value; + const length = input.length; + if (length === def.length) return; + const origin = getLengthableOrigin(input); + const tooBig = length > def.length; + payload.issues.push({ + origin, + ...tooBig ? { + code: "too_big", + maximum: def.length + } : { + code: "too_small", + minimum: def.length + }, + inclusive: true, + exact: true, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckStringFormat = /*@__PURE__*/ $constructor("$ZodCheckStringFormat", (inst, def) => { + var _a, _b; + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.format = def.format; + if (def.pattern) { + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(def.pattern); + } + }); + if (def.pattern) (_a = inst._zod).check ?? (_a.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: def.format, + input: payload.value, + ...def.pattern ? { pattern: def.pattern.toString() } : {}, + inst, + continue: !def.abort + }); + }); + else (_b = inst._zod).check ?? (_b.check = () => {}); + }); + const $ZodCheckRegex = /*@__PURE__*/ $constructor("$ZodCheckRegex", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + inst._zod.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "regex", + input: payload.value, + pattern: def.pattern.toString(), + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckLowerCase = /*@__PURE__*/ $constructor("$ZodCheckLowerCase", (inst, def) => { + def.pattern ?? (def.pattern = lowercase); + $ZodCheckStringFormat.init(inst, def); + }); + const $ZodCheckUpperCase = /*@__PURE__*/ $constructor("$ZodCheckUpperCase", (inst, def) => { + def.pattern ?? (def.pattern = uppercase); + $ZodCheckStringFormat.init(inst, def); + }); + const $ZodCheckIncludes = /*@__PURE__*/ $constructor("$ZodCheckIncludes", (inst, def) => { + $ZodCheck.init(inst, def); + const escapedRegex = escapeRegex(def.includes); + const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex); + def.pattern = pattern; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.includes(def.includes, def.position)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "includes", + includes: def.includes, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckStartsWith = /*@__PURE__*/ $constructor("$ZodCheckStartsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`^${escapeRegex(def.prefix)}.*`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.startsWith(def.prefix)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "starts_with", + prefix: def.prefix, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckEndsWith = /*@__PURE__*/ $constructor("$ZodCheckEndsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`.*${escapeRegex(def.suffix)}$`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.endsWith(def.suffix)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "ends_with", + suffix: def.suffix, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckOverwrite = /*@__PURE__*/ $constructor("$ZodCheckOverwrite", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.check = (payload) => { + payload.value = def.tx(payload.value); + }; + }); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/doc.js + var Doc = class { + constructor(args = []) { + this.content = []; + this.indent = 0; + if (this) this.args = args; + } + indented(fn) { + this.indent += 1; + fn(this); + this.indent -= 1; + } + write(arg) { + if (typeof arg === "function") { + arg(this, { execution: "sync" }); + arg(this, { execution: "async" }); + return; + } + const lines = arg.split("\n").filter((x) => x); + const minIndent = Math.min(...lines.map((x) => x.length - x.trimStart().length)); + const dedented = lines.map((x) => x.slice(minIndent)).map((x) => " ".repeat(this.indent * 2) + x); + for (const line of dedented) this.content.push(line); + } + compile() { + const F = Function; + const args = this?.args; + const lines = [...(this?.content ?? [``]).map((x) => ` ${x}`)]; + return new F(...args, lines.join("\n")); + } + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.js + const version = { + major: 4, + minor: 4, + patch: 3 + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/schemas.js + const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => { + var _a; + inst ?? (inst = {}); + inst._zod.def = def; + inst._zod.bag = inst._zod.bag || {}; + inst._zod.version = version; + const checks = [...inst._zod.def.checks ?? []]; + if (inst._zod.traits.has("$ZodCheck")) checks.unshift(inst); + for (const ch of checks) for (const fn of ch._zod.onattach) fn(inst); + if (checks.length === 0) { + (_a = inst._zod).deferred ?? (_a.deferred = []); + inst._zod.deferred?.push(() => { + inst._zod.run = inst._zod.parse; + }); + } else { + const runChecks = (payload, checks, ctx) => { + let isAborted = aborted(payload); + let asyncResult; + for (const ch of checks) { + if (ch._zod.def.when) { + if (explicitlyAborted(payload)) continue; + if (!ch._zod.def.when(payload)) continue; + } else if (isAborted) continue; + const currLen = payload.issues.length; + const _ = ch._zod.check(payload); + if (_ instanceof Promise && ctx?.async === false) throw new $ZodAsyncError(); + if (asyncResult || _ instanceof Promise) asyncResult = (asyncResult ?? Promise.resolve()).then(async () => { + await _; + if (payload.issues.length === currLen) return; + if (!isAborted) isAborted = aborted(payload, currLen); + }); + else { + if (payload.issues.length === currLen) continue; + if (!isAborted) isAborted = aborted(payload, currLen); + } + } + if (asyncResult) return asyncResult.then(() => { + return payload; + }); + return payload; + }; + const handleCanaryResult = (canary, payload, ctx) => { + if (aborted(canary)) { + canary.aborted = true; + return canary; + } + const checkResult = runChecks(payload, checks, ctx); + if (checkResult instanceof Promise) { + if (ctx.async === false) throw new $ZodAsyncError(); + return checkResult.then((checkResult) => inst._zod.parse(checkResult, ctx)); + } + return inst._zod.parse(checkResult, ctx); + }; + inst._zod.run = (payload, ctx) => { + if (ctx.skipChecks) return inst._zod.parse(payload, ctx); + if (ctx.direction === "backward") { + const canary = inst._zod.parse({ + value: payload.value, + issues: [] + }, { + ...ctx, + skipChecks: true + }); + if (canary instanceof Promise) return canary.then((canary) => { + return handleCanaryResult(canary, payload, ctx); + }); + return handleCanaryResult(canary, payload, ctx); + } + const result = inst._zod.parse(payload, ctx); + if (result instanceof Promise) { + if (ctx.async === false) throw new $ZodAsyncError(); + return result.then((result) => runChecks(result, checks, ctx)); + } + return runChecks(result, checks, ctx); + }; + } + defineLazy(inst, "~standard", () => ({ + validate: (value) => { + try { + const r = safeParse$1(inst, value); + return r.success ? { value: r.data } : { issues: r.error?.issues }; + } catch (_) { + return safeParseAsync$1(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues }); + } + }, + vendor: "zod", + version: 1 + })); + }); + const $ZodString = /*@__PURE__*/ $constructor("$ZodString", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = [...inst?._zod.bag?.patterns ?? []].pop() ?? string$1(inst._zod.bag); + inst._zod.parse = (payload, _) => { + if (def.coerce) try { + payload.value = String(payload.value); + } catch (_) {} + if (typeof payload.value === "string") return payload; + payload.issues.push({ + expected: "string", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; + }); + const $ZodStringFormat = /*@__PURE__*/ $constructor("$ZodStringFormat", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + $ZodString.init(inst, def); + }); + const $ZodGUID = /*@__PURE__*/ $constructor("$ZodGUID", (inst, def) => { + def.pattern ?? (def.pattern = guid); + $ZodStringFormat.init(inst, def); + }); + const $ZodUUID = /*@__PURE__*/ $constructor("$ZodUUID", (inst, def) => { + if (def.version) { + const v = { + v1: 1, + v2: 2, + v3: 3, + v4: 4, + v5: 5, + v6: 6, + v7: 7, + v8: 8 + }[def.version]; + if (v === void 0) throw new Error(`Invalid UUID version: "${def.version}"`); + def.pattern ?? (def.pattern = uuid(v)); + } else def.pattern ?? (def.pattern = uuid()); + $ZodStringFormat.init(inst, def); + }); + const $ZodEmail = /*@__PURE__*/ $constructor("$ZodEmail", (inst, def) => { + def.pattern ?? (def.pattern = email); + $ZodStringFormat.init(inst, def); + }); + const $ZodURL = /*@__PURE__*/ $constructor("$ZodURL", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + try { + const trimmed = payload.value.trim(); + if (!def.normalize && def.protocol?.source === httpProtocol.source) { + if (!/^https?:\/\//i.test(trimmed)) { + payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid URL format", + input: payload.value, + inst, + continue: !def.abort + }); + return; + } + } + const url = new URL(trimmed); + if (def.hostname) { + def.hostname.lastIndex = 0; + if (!def.hostname.test(url.hostname)) payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid hostname", + pattern: def.hostname.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + if (def.protocol) { + def.protocol.lastIndex = 0; + if (!def.protocol.test(url.protocol.endsWith(":") ? url.protocol.slice(0, -1) : url.protocol)) payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid protocol", + pattern: def.protocol.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + if (def.normalize) payload.value = url.href; + else payload.value = trimmed; + return; + } catch (_) { + payload.issues.push({ + code: "invalid_format", + format: "url", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + const $ZodEmoji = /*@__PURE__*/ $constructor("$ZodEmoji", (inst, def) => { + def.pattern ?? (def.pattern = emoji()); + $ZodStringFormat.init(inst, def); + }); + const $ZodNanoID = /*@__PURE__*/ $constructor("$ZodNanoID", (inst, def) => { + def.pattern ?? (def.pattern = nanoid); + $ZodStringFormat.init(inst, def); + }); + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link $ZodCUID2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const $ZodCUID = /*@__PURE__*/ $constructor("$ZodCUID", (inst, def) => { + def.pattern ?? (def.pattern = cuid); + $ZodStringFormat.init(inst, def); + }); + const $ZodCUID2 = /*@__PURE__*/ $constructor("$ZodCUID2", (inst, def) => { + def.pattern ?? (def.pattern = cuid2); + $ZodStringFormat.init(inst, def); + }); + const $ZodULID = /*@__PURE__*/ $constructor("$ZodULID", (inst, def) => { + def.pattern ?? (def.pattern = ulid); + $ZodStringFormat.init(inst, def); + }); + const $ZodXID = /*@__PURE__*/ $constructor("$ZodXID", (inst, def) => { + def.pattern ?? (def.pattern = xid); + $ZodStringFormat.init(inst, def); + }); + const $ZodKSUID = /*@__PURE__*/ $constructor("$ZodKSUID", (inst, def) => { + def.pattern ?? (def.pattern = ksuid); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODateTime = /*@__PURE__*/ $constructor("$ZodISODateTime", (inst, def) => { + def.pattern ?? (def.pattern = datetime$1(def)); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODate = /*@__PURE__*/ $constructor("$ZodISODate", (inst, def) => { + def.pattern ?? (def.pattern = date$1); + $ZodStringFormat.init(inst, def); + }); + const $ZodISOTime = /*@__PURE__*/ $constructor("$ZodISOTime", (inst, def) => { + def.pattern ?? (def.pattern = time$1(def)); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODuration = /*@__PURE__*/ $constructor("$ZodISODuration", (inst, def) => { + def.pattern ?? (def.pattern = duration$1); + $ZodStringFormat.init(inst, def); + }); + const $ZodIPv4 = /*@__PURE__*/ $constructor("$ZodIPv4", (inst, def) => { + def.pattern ?? (def.pattern = ipv4); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv4`; + }); + const $ZodIPv6 = /*@__PURE__*/ $constructor("$ZodIPv6", (inst, def) => { + def.pattern ?? (def.pattern = ipv6); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv6`; + inst._zod.check = (payload) => { + try { + new URL(`http://[${payload.value}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "ipv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + const $ZodCIDRv4 = /*@__PURE__*/ $constructor("$ZodCIDRv4", (inst, def) => { + def.pattern ?? (def.pattern = cidrv4); + $ZodStringFormat.init(inst, def); + }); + const $ZodCIDRv6 = /*@__PURE__*/ $constructor("$ZodCIDRv6", (inst, def) => { + def.pattern ?? (def.pattern = cidrv6); + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + const parts = payload.value.split("/"); + try { + if (parts.length !== 2) throw new Error(); + const [address, prefix] = parts; + if (!prefix) throw new Error(); + const prefixNum = Number(prefix); + if (`${prefixNum}` !== prefix) throw new Error(); + if (prefixNum < 0 || prefixNum > 128) throw new Error(); + new URL(`http://[${address}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "cidrv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + function isValidBase64(data) { + if (data === "") return true; + if (/\s/.test(data)) return false; + if (data.length % 4 !== 0) return false; + try { + atob(data); + return true; + } catch { + return false; + } + } + const $ZodBase64 = /*@__PURE__*/ $constructor("$ZodBase64", (inst, def) => { + def.pattern ?? (def.pattern = base64); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64"; + inst._zod.check = (payload) => { + if (isValidBase64(payload.value)) return; + payload.issues.push({ + code: "invalid_format", + format: "base64", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + function isValidBase64URL(data) { + if (!base64url.test(data)) return false; + const base64 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/"); + return isValidBase64(base64.padEnd(Math.ceil(base64.length / 4) * 4, "=")); + } + const $ZodBase64URL = /*@__PURE__*/ $constructor("$ZodBase64URL", (inst, def) => { + def.pattern ?? (def.pattern = base64url); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64url"; + inst._zod.check = (payload) => { + if (isValidBase64URL(payload.value)) return; + payload.issues.push({ + code: "invalid_format", + format: "base64url", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodE164 = /*@__PURE__*/ $constructor("$ZodE164", (inst, def) => { + def.pattern ?? (def.pattern = e164); + $ZodStringFormat.init(inst, def); + }); + function isValidJWT(token, algorithm = null) { + try { + const tokensParts = token.split("."); + if (tokensParts.length !== 3) return false; + const [header] = tokensParts; + if (!header) return false; + const parsedHeader = JSON.parse(atob(header)); + if ("typ" in parsedHeader && parsedHeader?.typ !== "JWT") return false; + if (!parsedHeader.alg) return false; + if (algorithm && (!("alg" in parsedHeader) || parsedHeader.alg !== algorithm)) return false; + return true; + } catch { + return false; + } + } + const $ZodJWT = /*@__PURE__*/ $constructor("$ZodJWT", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + if (isValidJWT(payload.value, def.alg)) return; + payload.issues.push({ + code: "invalid_format", + format: "jwt", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodNumber = /*@__PURE__*/ $constructor("$ZodNumber", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = inst._zod.bag.pattern ?? number$1; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) try { + payload.value = Number(payload.value); + } catch (_) {} + const input = payload.value; + if (typeof input === "number" && !Number.isNaN(input) && Number.isFinite(input)) return payload; + const received = typeof input === "number" ? Number.isNaN(input) ? "NaN" : !Number.isFinite(input) ? "Infinity" : void 0 : void 0; + payload.issues.push({ + expected: "number", + code: "invalid_type", + input, + inst, + ...received ? { received } : {} + }); + return payload; + }; + }); + const $ZodNumberFormat = /*@__PURE__*/ $constructor("$ZodNumberFormat", (inst, def) => { + $ZodCheckNumberFormat.init(inst, def); + $ZodNumber.init(inst, def); + }); + const $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = boolean$1; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) try { + payload.value = Boolean(payload.value); + } catch (_) {} + const input = payload.value; + if (typeof input === "boolean") return payload; + payload.issues.push({ + expected: "boolean", + code: "invalid_type", + input, + inst + }); + return payload; + }; + }); + const $ZodUnknown = /*@__PURE__*/ $constructor("$ZodUnknown", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload) => payload; + }); + const $ZodNever = /*@__PURE__*/ $constructor("$ZodNever", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, _ctx) => { + payload.issues.push({ + expected: "never", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; + }); + function handleArrayResult(result, final, index) { + if (result.issues.length) final.issues.push(...prefixIssues(index, result.issues)); + final.value[index] = result.value; + } + const $ZodArray = /*@__PURE__*/ $constructor("$ZodArray", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!Array.isArray(input)) { + payload.issues.push({ + expected: "array", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = Array(input.length); + const proms = []; + for (let i = 0; i < input.length; i++) { + const item = input[i]; + const result = def.element._zod.run({ + value: item, + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => handleArrayResult(result, payload, i))); + else handleArrayResult(result, payload, i); + } + if (proms.length) return Promise.all(proms).then(() => payload); + return payload; + }; + }); + function handlePropertyResult(result, final, key, input, isOptionalIn, isOptionalOut) { + const isPresent = key in input; + if (result.issues.length) { + if (isOptionalIn && isOptionalOut && !isPresent) return; + final.issues.push(...prefixIssues(key, result.issues)); + } + if (!isPresent && !isOptionalIn) { + if (!result.issues.length) final.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: void 0, + path: [key] + }); + return; + } + if (result.value === void 0) { + if (isPresent) final.value[key] = void 0; + } else final.value[key] = result.value; + } + function normalizeDef(def) { + const keys = Object.keys(def.shape); + for (const k of keys) if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) throw new Error(`Invalid element at key "${k}": expected a Zod schema`); + const okeys = optionalKeys(def.shape); + return { + ...def, + keys, + keySet: new Set(keys), + numKeys: keys.length, + optionalKeys: new Set(okeys) + }; + } + function handleCatchall(proms, input, payload, ctx, def, inst) { + const unrecognized = []; + const keySet = def.keySet; + const _catchall = def.catchall._zod; + const t = _catchall.def.type; + const isOptionalIn = _catchall.optin === "optional"; + const isOptionalOut = _catchall.optout === "optional"; + for (const key in input) { + if (key === "__proto__") continue; + if (keySet.has(key)) continue; + if (t === "never") { + unrecognized.push(key); + continue; + } + const r = _catchall.run({ + value: input[key], + issues: [] + }, ctx); + if (r instanceof Promise) proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut))); + else handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + if (unrecognized.length) payload.issues.push({ + code: "unrecognized_keys", + keys: unrecognized, + input, + inst + }); + if (!proms.length) return payload; + return Promise.all(proms).then(() => { + return payload; + }); + } + const $ZodObject = /*@__PURE__*/ $constructor("$ZodObject", (inst, def) => { + $ZodType.init(inst, def); + if (!Object.getOwnPropertyDescriptor(def, "shape")?.get) { + const sh = def.shape; + Object.defineProperty(def, "shape", { get: () => { + const newSh = { ...sh }; + Object.defineProperty(def, "shape", { value: newSh }); + return newSh; + } }); + } + const _normalized = cached(() => normalizeDef(def)); + defineLazy(inst._zod, "propValues", () => { + const shape = def.shape; + const propValues = {}; + for (const key in shape) { + const field = shape[key]._zod; + if (field.values) { + propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set()); + for (const v of field.values) propValues[key].add(v); + } + } + return propValues; + }); + const isObject$1 = isObject; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject$1(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = {}; + const proms = []; + const shape = value.shape; + for (const key of value.keys) { + const el = shape[key]; + const isOptionalIn = el._zod.optin === "optional"; + const isOptionalOut = el._zod.optout === "optional"; + const r = el._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (r instanceof Promise) proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut))); + else handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + if (!catchall) return proms.length ? Promise.all(proms).then(() => payload) : payload; + return handleCatchall(proms, input, payload, ctx, _normalized.value, inst); + }; + }); + const $ZodObjectJIT = /*@__PURE__*/ $constructor("$ZodObjectJIT", (inst, def) => { + $ZodObject.init(inst, def); + const superParse = inst._zod.parse; + const _normalized = cached(() => normalizeDef(def)); + const generateFastpass = (shape) => { + const doc = new Doc([ + "shape", + "payload", + "ctx" + ]); + const normalized = _normalized.value; + const parseStr = (key) => { + const k = esc(key); + return `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`; + }; + doc.write(`const input = payload.value;`); + const ids = Object.create(null); + let counter = 0; + for (const key of normalized.keys) ids[key] = `key_${counter++}`; + doc.write(`const newResult = {};`); + for (const key of normalized.keys) { + const id = ids[key]; + const k = esc(key); + const schema = shape[key]; + const isOptionalIn = schema?._zod?.optin === "optional"; + const isOptionalOut = schema?._zod?.optout === "optional"; + doc.write(`const ${id} = ${parseStr(key)};`); + if (isOptionalIn && isOptionalOut) doc.write(` + if (${id}.issues.length) { + if (${k} in input) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + else if (!isOptionalIn) doc.write(` + const ${id}_present = ${k} in input; + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + if (!${id}_present && !${id}.issues.length) { + payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: undefined, + path: [${k}] + }); + } + + if (${id}_present) { + if (${id}.value === undefined) { + newResult[${k}] = undefined; + } else { + newResult[${k}] = ${id}.value; + } + } + + `); + else doc.write(` + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + } + doc.write(`payload.value = newResult;`); + doc.write(`return payload;`); + const fn = doc.compile(); + return (payload, ctx) => fn(shape, payload, ctx); + }; + let fastpass; + const isObject$2 = isObject; + const jit = !globalConfig.jitless; + const fastEnabled = jit && allowsEval.value; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject$2(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + if (jit && fastEnabled && ctx?.async === false && ctx.jitless !== true) { + if (!fastpass) fastpass = generateFastpass(def.shape); + payload = fastpass(payload, ctx); + if (!catchall) return payload; + return handleCatchall([], input, payload, ctx, value, inst); + } + return superParse(payload, ctx); + }; + }); + function handleUnionResults(results, final, inst, ctx) { + for (const result of results) if (result.issues.length === 0) { + final.value = result.value; + return final; + } + const nonaborted = results.filter((r) => !aborted(r)); + if (nonaborted.length === 1) { + final.value = nonaborted[0].value; + return nonaborted[0]; + } + final.issues.push({ + code: "invalid_union", + input: final.value, + inst, + errors: results.map((result) => result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + }); + return final; + } + const $ZodUnion = /*@__PURE__*/ $constructor("$ZodUnion", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.options.some((o) => o._zod.optin === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "optout", () => def.options.some((o) => o._zod.optout === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "values", () => { + if (def.options.every((o) => o._zod.values)) return new Set(def.options.flatMap((option) => Array.from(option._zod.values))); + }); + defineLazy(inst._zod, "pattern", () => { + if (def.options.every((o) => o._zod.pattern)) { + const patterns = def.options.map((o) => o._zod.pattern); + return new RegExp(`^(${patterns.map((p) => cleanRegex(p.source)).join("|")})$`); + } + }); + const first = def.options.length === 1 ? def.options[0]._zod.run : null; + inst._zod.parse = (payload, ctx) => { + if (first) return first(payload, ctx); + let async = false; + const results = []; + for (const option of def.options) { + const result = option._zod.run({ + value: payload.value, + issues: [] + }, ctx); + if (result instanceof Promise) { + results.push(result); + async = true; + } else { + if (result.issues.length === 0) return result; + results.push(result); + } + } + if (!async) return handleUnionResults(results, payload, inst, ctx); + return Promise.all(results).then((results) => { + return handleUnionResults(results, payload, inst, ctx); + }); + }; + }); + const $ZodDiscriminatedUnion = /*@__PURE__*/ $constructor("$ZodDiscriminatedUnion", (inst, def) => { + def.inclusive = false; + $ZodUnion.init(inst, def); + const _super = inst._zod.parse; + defineLazy(inst._zod, "propValues", () => { + const propValues = {}; + for (const option of def.options) { + const pv = option._zod.propValues; + if (!pv || Object.keys(pv).length === 0) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(option)}"`); + for (const [k, v] of Object.entries(pv)) { + if (!propValues[k]) propValues[k] = /* @__PURE__ */ new Set(); + for (const val of v) propValues[k].add(val); + } + } + return propValues; + }); + const disc = cached(() => { + const opts = def.options; + const map = /* @__PURE__ */ new Map(); + for (const o of opts) { + const values = o._zod.propValues?.[def.discriminator]; + if (!values || values.size === 0) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(o)}"`); + for (const v of values) { + if (map.has(v)) throw new Error(`Duplicate discriminator value "${String(v)}"`); + map.set(v, o); + } + } + return map; + }); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!isObject(input)) { + payload.issues.push({ + code: "invalid_type", + expected: "object", + input, + inst + }); + return payload; + } + const opt = disc.value.get(input?.[def.discriminator]); + if (opt) return opt._zod.run(payload, ctx); + if (def.unionFallback || ctx.direction === "backward") return _super(payload, ctx); + payload.issues.push({ + code: "invalid_union", + errors: [], + note: "No matching discriminator", + discriminator: def.discriminator, + options: Array.from(disc.value.keys()), + input, + path: [def.discriminator], + inst + }); + return payload; + }; + }); + const $ZodIntersection = /*@__PURE__*/ $constructor("$ZodIntersection", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + const left = def.left._zod.run({ + value: input, + issues: [] + }, ctx); + const right = def.right._zod.run({ + value: input, + issues: [] + }, ctx); + if (left instanceof Promise || right instanceof Promise) return Promise.all([left, right]).then(([left, right]) => { + return handleIntersectionResults(payload, left, right); + }); + return handleIntersectionResults(payload, left, right); + }; + }); + function mergeValues(a, b) { + if (a === b) return { + valid: true, + data: a + }; + if (a instanceof Date && b instanceof Date && +a === +b) return { + valid: true, + data: a + }; + if (isPlainObject(a) && isPlainObject(b)) { + const bKeys = Object.keys(b); + const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1); + const newObj = { + ...a, + ...b + }; + for (const key of sharedKeys) { + const sharedValue = mergeValues(a[key], b[key]); + if (!sharedValue.valid) return { + valid: false, + mergeErrorPath: [key, ...sharedValue.mergeErrorPath] + }; + newObj[key] = sharedValue.data; + } + return { + valid: true, + data: newObj + }; + } + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) return { + valid: false, + mergeErrorPath: [] + }; + const newArray = []; + for (let index = 0; index < a.length; index++) { + const itemA = a[index]; + const itemB = b[index]; + const sharedValue = mergeValues(itemA, itemB); + if (!sharedValue.valid) return { + valid: false, + mergeErrorPath: [index, ...sharedValue.mergeErrorPath] + }; + newArray.push(sharedValue.data); + } + return { + valid: true, + data: newArray + }; + } + return { + valid: false, + mergeErrorPath: [] + }; + } + function handleIntersectionResults(result, left, right) { + const unrecKeys = /* @__PURE__ */ new Map(); + let unrecIssue; + for (const iss of left.issues) if (iss.code === "unrecognized_keys") { + unrecIssue ?? (unrecIssue = iss); + for (const k of iss.keys) { + if (!unrecKeys.has(k)) unrecKeys.set(k, {}); + unrecKeys.get(k).l = true; + } + } else result.issues.push(iss); + for (const iss of right.issues) if (iss.code === "unrecognized_keys") for (const k of iss.keys) { + if (!unrecKeys.has(k)) unrecKeys.set(k, {}); + unrecKeys.get(k).r = true; + } + else result.issues.push(iss); + const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k); + if (bothKeys.length && unrecIssue) result.issues.push({ + ...unrecIssue, + keys: bothKeys + }); + if (aborted(result)) return result; + const merged = mergeValues(left.value, right.value); + if (!merged.valid) throw new Error(`Unmergable intersection. Error path: ${JSON.stringify(merged.mergeErrorPath)}`); + result.value = merged.data; + return result; + } + const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!isPlainObject(input)) { + payload.issues.push({ + expected: "record", + code: "invalid_type", + input, + inst + }); + return payload; + } + const proms = []; + const values = def.keyType._zod.values; + if (values) { + payload.value = {}; + const recordKeys = /* @__PURE__ */ new Set(); + for (const key of values) if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") { + recordKeys.add(typeof key === "number" ? key.toString() : key); + const keyResult = def.keyType._zod.run({ + value: key, + issues: [] + }, ctx); + if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (keyResult.issues.length) { + payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + continue; + } + const outKey = keyResult.value; + const result = def.valueType._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[outKey] = result.value; + })); + else { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[outKey] = result.value; + } + } + let unrecognized; + for (const key in input) if (!recordKeys.has(key)) { + unrecognized = unrecognized ?? []; + unrecognized.push(key); + } + if (unrecognized && unrecognized.length > 0) payload.issues.push({ + code: "unrecognized_keys", + input, + inst, + keys: unrecognized + }); + } else { + payload.value = {}; + for (const key of Reflect.ownKeys(input)) { + if (key === "__proto__") continue; + if (!Object.prototype.propertyIsEnumerable.call(input, key)) continue; + let keyResult = def.keyType._zod.run({ + value: key, + issues: [] + }, ctx); + if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (typeof key === "string" && number$1.test(key) && keyResult.issues.length) { + const retryResult = def.keyType._zod.run({ + value: Number(key), + issues: [] + }, ctx); + if (retryResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (retryResult.issues.length === 0) keyResult = retryResult; + } + if (keyResult.issues.length) { + if (def.mode === "loose") payload.value[key] = input[key]; + else payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + continue; + } + const result = def.valueType._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[keyResult.value] = result.value; + })); + else { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[keyResult.value] = result.value; + } + } + } + if (proms.length) return Promise.all(proms).then(() => payload); + return payload; + }; + }); + const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => { + $ZodType.init(inst, def); + const values = getEnumValues(def.entries); + const valuesSet = new Set(values); + inst._zod.values = valuesSet; + inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (valuesSet.has(input)) return payload; + payload.issues.push({ + code: "invalid_value", + values, + input, + inst + }); + return payload; + }; + }); + const $ZodLiteral = /*@__PURE__*/ $constructor("$ZodLiteral", (inst, def) => { + $ZodType.init(inst, def); + if (def.values.length === 0) throw new Error("Cannot create literal schema with no valid values"); + const values = new Set(def.values); + inst._zod.values = values; + inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (values.has(input)) return payload; + payload.issues.push({ + code: "invalid_value", + values: def.values, + input, + inst + }); + return payload; + }; + }); + const $ZodTransform = /*@__PURE__*/ $constructor("$ZodTransform", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") throw new $ZodEncodeError(inst.constructor.name); + const _out = def.transform(payload.value, payload); + if (ctx.async) return (_out instanceof Promise ? _out : Promise.resolve(_out)).then((output) => { + payload.value = output; + payload.fallback = true; + return payload; + }); + if (_out instanceof Promise) throw new $ZodAsyncError(); + payload.value = _out; + payload.fallback = true; + return payload; + }; + }); + function handleOptionalResult(result, input) { + if (input === void 0 && (result.issues.length || result.fallback)) return { + issues: [], + value: void 0 + }; + return result; + } + const $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.optout = "optional"; + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? new Set([...def.innerType._zod.values, void 0]) : void 0; + }); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)})?$`) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (def.innerType._zod.optin === "optional") { + const input = payload.value; + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((r) => handleOptionalResult(r, input)); + return handleOptionalResult(result, input); + } + if (payload.value === void 0) return payload; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodExactOptional = /*@__PURE__*/ $constructor("$ZodExactOptional", (inst, def) => { + $ZodOptional.init(inst, def); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "pattern", () => def.innerType._zod.pattern); + inst._zod.parse = (payload, ctx) => { + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodNullable = /*@__PURE__*/ $constructor("$ZodNullable", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.innerType._zod.optin); + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0; + }); + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (payload.value === null) return payload; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodDefault = /*@__PURE__*/ $constructor("$ZodDefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + if (payload.value === void 0) { + payload.value = def.defaultValue; + /** + * $ZodDefault returns the default value immediately in forward direction. + * It doesn't pass the default value into the validator ("prefault"). There's no reason to pass the default value through validation. The validity of the default is enforced by TypeScript statically. Otherwise, it's the responsibility of the user to ensure the default is valid. In the case of pipes with divergent in/out types, you can specify the default on the `in` schema of your ZodPipe to set a "prefault" for the pipe. */ + return payload; + } + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => handleDefaultResult(result, def)); + return handleDefaultResult(result, def); + }; + }); + function handleDefaultResult(payload, def) { + if (payload.value === void 0) payload.value = def.defaultValue; + return payload; + } + const $ZodPrefault = /*@__PURE__*/ $constructor("$ZodPrefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + if (payload.value === void 0) payload.value = def.defaultValue; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodNonOptional = /*@__PURE__*/ $constructor("$ZodNonOptional", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => { + const v = def.innerType._zod.values; + return v ? new Set([...v].filter((x) => x !== void 0)) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => handleNonOptionalResult(result, inst)); + return handleNonOptionalResult(result, inst); + }; + }); + function handleNonOptionalResult(payload, inst) { + if (!payload.issues.length && payload.value === void 0) payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: payload.value, + inst + }); + return payload; + } + const $ZodCatch = /*@__PURE__*/ $constructor("$ZodCatch", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => { + payload.value = result.value; + if (result.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }); + payload.value = result.value; + if (result.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }; + }); + const $ZodPipe = /*@__PURE__*/ $constructor("$ZodPipe", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => def.in._zod.values); + defineLazy(inst._zod, "optin", () => def.in._zod.optin); + defineLazy(inst._zod, "optout", () => def.out._zod.optout); + defineLazy(inst._zod, "propValues", () => def.in._zod.propValues); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + const right = def.out._zod.run(payload, ctx); + if (right instanceof Promise) return right.then((right) => handlePipeResult(right, def.in, ctx)); + return handlePipeResult(right, def.in, ctx); + } + const left = def.in._zod.run(payload, ctx); + if (left instanceof Promise) return left.then((left) => handlePipeResult(left, def.out, ctx)); + return handlePipeResult(left, def.out, ctx); + }; + }); + function handlePipeResult(left, next, ctx) { + if (left.issues.length) { + left.aborted = true; + return left; + } + return next._zod.run({ + value: left.value, + issues: left.issues, + fallback: left.fallback + }, ctx); + } + const $ZodReadonly = /*@__PURE__*/ $constructor("$ZodReadonly", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "propValues", () => def.innerType._zod.propValues); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "optin", () => def.innerType?._zod?.optin); + defineLazy(inst._zod, "optout", () => def.innerType?._zod?.optout); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then(handleReadonlyResult); + return handleReadonlyResult(result); + }; + }); + function handleReadonlyResult(payload) { + payload.value = Object.freeze(payload.value); + return payload; + } + const $ZodLazy = /*@__PURE__*/ $constructor("$ZodLazy", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "innerType", () => { + const d = def; + if (!d._cachedInner) d._cachedInner = def.getter(); + return d._cachedInner; + }); + defineLazy(inst._zod, "pattern", () => inst._zod.innerType?._zod?.pattern); + defineLazy(inst._zod, "propValues", () => inst._zod.innerType?._zod?.propValues); + defineLazy(inst._zod, "optin", () => inst._zod.innerType?._zod?.optin ?? void 0); + defineLazy(inst._zod, "optout", () => inst._zod.innerType?._zod?.optout ?? void 0); + inst._zod.parse = (payload, ctx) => { + return inst._zod.innerType._zod.run(payload, ctx); + }; + }); + const $ZodCustom = /*@__PURE__*/ $constructor("$ZodCustom", (inst, def) => { + $ZodCheck.init(inst, def); + $ZodType.init(inst, def); + inst._zod.parse = (payload, _) => { + return payload; + }; + inst._zod.check = (payload) => { + const input = payload.value; + const r = def.fn(input); + if (r instanceof Promise) return r.then((r) => handleRefineResult(r, payload, input, inst)); + handleRefineResult(r, payload, input, inst); + }; + }); + function handleRefineResult(result, payload, input, inst) { + if (!result) { + const _iss = { + code: "custom", + input, + inst, + path: [...inst._zod.def.path ?? []], + continue: !inst._zod.def.abort + }; + if (inst._zod.def.params) _iss.params = inst._zod.def.params; + payload.issues.push(issue(_iss)); + } + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.js + var _a; + var $ZodRegistry = class { + constructor() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + } + add(schema, ..._meta) { + const meta = _meta[0]; + this._map.set(schema, meta); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.set(meta.id, schema); + return this; + } + clear() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + return this; + } + remove(schema) { + const meta = this._map.get(schema); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.delete(meta.id); + this._map.delete(schema); + return this; + } + get(schema) { + const p = schema._zod.parent; + if (p) { + const pm = { ...this.get(p) ?? {} }; + delete pm.id; + const f = { + ...pm, + ...this._map.get(schema) + }; + return Object.keys(f).length ? f : void 0; + } + return this._map.get(schema); + } + has(schema) { + return this._map.has(schema); + } + }; + function registry() { + return new $ZodRegistry(); + } + (_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry()); + const globalRegistry = globalThis.__zod_globalRegistry; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/api.js + // @__NO_SIDE_EFFECTS__ + function _string(Class, params) { + return new Class({ + type: "string", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _email(Class, params) { + return new Class({ + type: "string", + format: "email", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _guid(Class, params) { + return new Class({ + type: "string", + format: "guid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuid(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv4(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v4", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv6(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v6", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv7(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v7", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _url(Class, params) { + return new Class({ + type: "string", + format: "url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _emoji(Class, params) { + return new Class({ + type: "string", + format: "emoji", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _nanoid(Class, params) { + return new Class({ + type: "string", + format: "nanoid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link _cuid2} instead. + * See https://github.com/paralleldrive/cuid. + */ + // @__NO_SIDE_EFFECTS__ + function _cuid(Class, params) { + return new Class({ + type: "string", + format: "cuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cuid2(Class, params) { + return new Class({ + type: "string", + format: "cuid2", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ulid(Class, params) { + return new Class({ + type: "string", + format: "ulid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _xid(Class, params) { + return new Class({ + type: "string", + format: "xid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ksuid(Class, params) { + return new Class({ + type: "string", + format: "ksuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ipv4(Class, params) { + return new Class({ + type: "string", + format: "ipv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ipv6(Class, params) { + return new Class({ + type: "string", + format: "ipv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cidrv4(Class, params) { + return new Class({ + type: "string", + format: "cidrv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cidrv6(Class, params) { + return new Class({ + type: "string", + format: "cidrv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _base64(Class, params) { + return new Class({ + type: "string", + format: "base64", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _base64url(Class, params) { + return new Class({ + type: "string", + format: "base64url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _e164(Class, params) { + return new Class({ + type: "string", + format: "e164", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _jwt(Class, params) { + return new Class({ + type: "string", + format: "jwt", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDateTime(Class, params) { + return new Class({ + type: "string", + format: "datetime", + check: "string_format", + offset: false, + local: false, + precision: null, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDate(Class, params) { + return new Class({ + type: "string", + format: "date", + check: "string_format", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoTime(Class, params) { + return new Class({ + type: "string", + format: "time", + check: "string_format", + precision: null, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDuration(Class, params) { + return new Class({ + type: "string", + format: "duration", + check: "string_format", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _number(Class, params) { + return new Class({ + type: "number", + checks: [], + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _int(Class, params) { + return new Class({ + type: "number", + check: "number_format", + abort: false, + format: "safeint", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _boolean(Class, params) { + return new Class({ + type: "boolean", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _unknown(Class) { + return new Class({ type: "unknown" }); + } + // @__NO_SIDE_EFFECTS__ + function _never(Class, params) { + return new Class({ + type: "never", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _lt(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: false + }); + } + // @__NO_SIDE_EFFECTS__ + function _lte(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: true + }); + } + // @__NO_SIDE_EFFECTS__ + function _gt(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: false + }); + } + // @__NO_SIDE_EFFECTS__ + function _gte(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: true + }); + } + // @__NO_SIDE_EFFECTS__ + function _multipleOf(value, params) { + return new $ZodCheckMultipleOf({ + check: "multiple_of", + ...normalizeParams(params), + value + }); + } + // @__NO_SIDE_EFFECTS__ + function _maxLength(maximum, params) { + return new $ZodCheckMaxLength({ + check: "max_length", + ...normalizeParams(params), + maximum + }); + } + // @__NO_SIDE_EFFECTS__ + function _minLength(minimum, params) { + return new $ZodCheckMinLength({ + check: "min_length", + ...normalizeParams(params), + minimum + }); + } + // @__NO_SIDE_EFFECTS__ + function _length(length, params) { + return new $ZodCheckLengthEquals({ + check: "length_equals", + ...normalizeParams(params), + length + }); + } + // @__NO_SIDE_EFFECTS__ + function _regex(pattern, params) { + return new $ZodCheckRegex({ + check: "string_format", + format: "regex", + ...normalizeParams(params), + pattern + }); + } + // @__NO_SIDE_EFFECTS__ + function _lowercase(params) { + return new $ZodCheckLowerCase({ + check: "string_format", + format: "lowercase", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uppercase(params) { + return new $ZodCheckUpperCase({ + check: "string_format", + format: "uppercase", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _includes(includes, params) { + return new $ZodCheckIncludes({ + check: "string_format", + format: "includes", + ...normalizeParams(params), + includes + }); + } + // @__NO_SIDE_EFFECTS__ + function _startsWith(prefix, params) { + return new $ZodCheckStartsWith({ + check: "string_format", + format: "starts_with", + ...normalizeParams(params), + prefix + }); + } + // @__NO_SIDE_EFFECTS__ + function _endsWith(suffix, params) { + return new $ZodCheckEndsWith({ + check: "string_format", + format: "ends_with", + ...normalizeParams(params), + suffix + }); + } + // @__NO_SIDE_EFFECTS__ + function _overwrite(tx) { + return new $ZodCheckOverwrite({ + check: "overwrite", + tx + }); + } + // @__NO_SIDE_EFFECTS__ + function _normalize(form) { + return /* @__PURE__ */ _overwrite((input) => input.normalize(form)); + } + // @__NO_SIDE_EFFECTS__ + function _trim() { + return /* @__PURE__ */ _overwrite((input) => input.trim()); + } + // @__NO_SIDE_EFFECTS__ + function _toLowerCase() { + return /* @__PURE__ */ _overwrite((input) => input.toLowerCase()); + } + // @__NO_SIDE_EFFECTS__ + function _toUpperCase() { + return /* @__PURE__ */ _overwrite((input) => input.toUpperCase()); + } + // @__NO_SIDE_EFFECTS__ + function _slugify() { + return /* @__PURE__ */ _overwrite((input) => slugify(input)); + } + // @__NO_SIDE_EFFECTS__ + function _array(Class, element, params) { + return new Class({ + type: "array", + element, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _custom(Class, fn, _params) { + const norm = normalizeParams(_params); + norm.abort ?? (norm.abort = true); + return new Class({ + type: "custom", + check: "custom", + fn, + ...norm + }); + } + // @__NO_SIDE_EFFECTS__ + function _refine(Class, fn, _params) { + return new Class({ + type: "custom", + check: "custom", + fn, + ...normalizeParams(_params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _superRefine(fn, params) { + const ch = /* @__PURE__ */ _check((payload) => { + payload.addIssue = (issue$2) => { + if (typeof issue$2 === "string") payload.issues.push(issue(issue$2, payload.value, ch._zod.def)); + else { + const _issue = issue$2; + if (_issue.fatal) _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = ch); + _issue.continue ?? (_issue.continue = !ch._zod.def.abort); + payload.issues.push(issue(_issue)); + } + }; + return fn(payload.value, payload); + }, params); + return ch; + } + // @__NO_SIDE_EFFECTS__ + function _check(fn, params) { + const ch = new $ZodCheck({ + check: "custom", + ...normalizeParams(params) + }); + ch._zod.check = fn; + return ch; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.js + function initializeContext(params) { + let target = params?.target ?? "draft-2020-12"; + if (target === "draft-4") target = "draft-04"; + if (target === "draft-7") target = "draft-07"; + return { + processors: params.processors ?? {}, + metadataRegistry: params?.metadata ?? globalRegistry, + target, + unrepresentable: params?.unrepresentable ?? "throw", + override: params?.override ?? (() => {}), + io: params?.io ?? "output", + counter: 0, + seen: /* @__PURE__ */ new Map(), + cycles: params?.cycles ?? "ref", + reused: params?.reused ?? "inline", + external: params?.external ?? void 0 + }; + } + function process(schema, ctx, _params = { + path: [], + schemaPath: [] + }) { + var _a; + const def = schema._zod.def; + const seen = ctx.seen.get(schema); + if (seen) { + seen.count++; + if (_params.schemaPath.includes(schema)) seen.cycle = _params.path; + return seen.schema; + } + const result = { + schema: {}, + count: 1, + cycle: void 0, + path: _params.path + }; + ctx.seen.set(schema, result); + const overrideSchema = schema._zod.toJSONSchema?.(); + if (overrideSchema) result.schema = overrideSchema; + else { + const params = { + ..._params, + schemaPath: [..._params.schemaPath, schema], + path: _params.path + }; + if (schema._zod.processJSONSchema) schema._zod.processJSONSchema(ctx, result.schema, params); + else { + const _json = result.schema; + const processor = ctx.processors[def.type]; + if (!processor) throw new Error(`[toJSONSchema]: Non-representable type encountered: ${def.type}`); + processor(schema, ctx, _json, params); + } + const parent = schema._zod.parent; + if (parent) { + if (!result.ref) result.ref = parent; + process(parent, ctx, params); + ctx.seen.get(parent).isParent = true; + } + } + const meta = ctx.metadataRegistry.get(schema); + if (meta) Object.assign(result.schema, meta); + if (ctx.io === "input" && isTransforming(schema)) { + delete result.schema.examples; + delete result.schema.default; + } + if (ctx.io === "input" && "_prefault" in result.schema) (_a = result.schema).default ?? (_a.default = result.schema._prefault); + delete result.schema._prefault; + return ctx.seen.get(schema).schema; + } + function extractDefs(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const idToSchema = /* @__PURE__ */ new Map(); + for (const entry of ctx.seen.entries()) { + const id = ctx.metadataRegistry.get(entry[0])?.id; + if (id) { + const existing = idToSchema.get(id); + if (existing && existing !== entry[0]) throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`); + idToSchema.set(id, entry[0]); + } + } + const makeURI = (entry) => { + const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions"; + if (ctx.external) { + const externalId = ctx.external.registry.get(entry[0])?.id; + const uriGenerator = ctx.external.uri ?? ((id) => id); + if (externalId) return { ref: uriGenerator(externalId) }; + const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`; + entry[1].defId = id; + return { + defId: id, + ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` + }; + } + if (entry[1] === root) return { ref: "#" }; + const defUriPrefix = `#/${defsSegment}/`; + const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`; + return { + defId, + ref: defUriPrefix + defId + }; + }; + const extractToDef = (entry) => { + if (entry[1].schema.$ref) return; + const seen = entry[1]; + const { ref, defId } = makeURI(entry); + seen.def = { ...seen.schema }; + if (defId) seen.defId = defId; + const schema = seen.schema; + for (const key in schema) delete schema[key]; + schema.$ref = ref; + }; + if (ctx.cycles === "throw") for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.cycle) throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/ + +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`); + } + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (schema === entry[0]) { + extractToDef(entry); + continue; + } + if (ctx.external) { + const ext = ctx.external.registry.get(entry[0])?.id; + if (schema !== entry[0] && ext) { + extractToDef(entry); + continue; + } + } + if (ctx.metadataRegistry.get(entry[0])?.id) { + extractToDef(entry); + continue; + } + if (seen.cycle) { + extractToDef(entry); + continue; + } + if (seen.count > 1) { + if (ctx.reused === "ref") { + extractToDef(entry); + continue; + } + } + } + } + function finalize(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const flattenRef = (zodSchema) => { + const seen = ctx.seen.get(zodSchema); + if (seen.ref === null) return; + const schema = seen.def ?? seen.schema; + const _cached = { ...schema }; + const ref = seen.ref; + seen.ref = null; + if (ref) { + flattenRef(ref); + const refSeen = ctx.seen.get(ref); + const refSchema = refSeen.schema; + if (refSchema.$ref && (ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0")) { + schema.allOf = schema.allOf ?? []; + schema.allOf.push(refSchema); + } else Object.assign(schema, refSchema); + Object.assign(schema, _cached); + if (zodSchema._zod.parent === ref) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (!(key in _cached)) delete schema[key]; + } + if (refSchema.$ref && refSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in refSeen.def && JSON.stringify(schema[key]) === JSON.stringify(refSeen.def[key])) delete schema[key]; + } + } + const parent = zodSchema._zod.parent; + if (parent && parent !== ref) { + flattenRef(parent); + const parentSeen = ctx.seen.get(parent); + if (parentSeen?.schema.$ref) { + schema.$ref = parentSeen.schema.$ref; + if (parentSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in parentSeen.def && JSON.stringify(schema[key]) === JSON.stringify(parentSeen.def[key])) delete schema[key]; + } + } + } + ctx.override({ + zodSchema, + jsonSchema: schema, + path: seen.path ?? [] + }); + }; + for (const entry of [...ctx.seen.entries()].reverse()) flattenRef(entry[0]); + const result = {}; + if (ctx.target === "draft-2020-12") result.$schema = "https://json-schema.org/draft/2020-12/schema"; + else if (ctx.target === "draft-07") result.$schema = "http://json-schema.org/draft-07/schema#"; + else if (ctx.target === "draft-04") result.$schema = "http://json-schema.org/draft-04/schema#"; + else if (ctx.target === "openapi-3.0") {} + if (ctx.external?.uri) { + const id = ctx.external.registry.get(schema)?.id; + if (!id) throw new Error("Schema is missing an `id` property"); + result.$id = ctx.external.uri(id); + } + Object.assign(result, root.def ?? root.schema); + const rootMetaId = ctx.metadataRegistry.get(schema)?.id; + if (rootMetaId !== void 0 && result.id === rootMetaId) delete result.id; + const defs = ctx.external?.defs ?? {}; + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.def && seen.defId) { + if (seen.def.id === seen.defId) delete seen.def.id; + defs[seen.defId] = seen.def; + } + } + if (ctx.external) {} else if (Object.keys(defs).length > 0) if (ctx.target === "draft-2020-12") result.$defs = defs; + else result.definitions = defs; + try { + const finalized = JSON.parse(JSON.stringify(result)); + Object.defineProperty(finalized, "~standard", { + value: { + ...schema["~standard"], + jsonSchema: { + input: createStandardJSONSchemaMethod(schema, "input", ctx.processors), + output: createStandardJSONSchemaMethod(schema, "output", ctx.processors) + } + }, + enumerable: false, + writable: false + }); + return finalized; + } catch (_err) { + throw new Error("Error converting schema to JSON."); + } + } + function isTransforming(_schema, _ctx) { + const ctx = _ctx ?? { seen: /* @__PURE__ */ new Set() }; + if (ctx.seen.has(_schema)) return false; + ctx.seen.add(_schema); + const def = _schema._zod.def; + if (def.type === "transform") return true; + if (def.type === "array") return isTransforming(def.element, ctx); + if (def.type === "set") return isTransforming(def.valueType, ctx); + if (def.type === "lazy") return isTransforming(def.getter(), ctx); + if (def.type === "promise" || def.type === "optional" || def.type === "nonoptional" || def.type === "nullable" || def.type === "readonly" || def.type === "default" || def.type === "prefault") return isTransforming(def.innerType, ctx); + if (def.type === "intersection") return isTransforming(def.left, ctx) || isTransforming(def.right, ctx); + if (def.type === "record" || def.type === "map") return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); + if (def.type === "pipe") { + if (_schema._zod.traits.has("$ZodCodec")) return true; + return isTransforming(def.in, ctx) || isTransforming(def.out, ctx); + } + if (def.type === "object") { + for (const key in def.shape) if (isTransforming(def.shape[key], ctx)) return true; + return false; + } + if (def.type === "union") { + for (const option of def.options) if (isTransforming(option, ctx)) return true; + return false; + } + if (def.type === "tuple") { + for (const item of def.items) if (isTransforming(item, ctx)) return true; + if (def.rest && isTransforming(def.rest, ctx)) return true; + return false; + } + return false; + } + /** + * Creates a toJSONSchema method for a schema instance. + * This encapsulates the logic of initializing context, processing, extracting defs, and finalizing. + */ + const createToJSONSchemaMethod = (schema, processors = {}) => (params) => { + const ctx = initializeContext({ + ...params, + processors + }); + process(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); + }; + const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => { + const { libraryOptions, target } = params ?? {}; + const ctx = initializeContext({ + ...libraryOptions ?? {}, + target, + io, + processors + }); + process(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.js + const formatMap = { + guid: "uuid", + url: "uri", + datetime: "date-time", + json_string: "json-string", + regex: "" + }; + const stringProcessor = (schema, ctx, _json, _params) => { + const json = _json; + json.type = "string"; + const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag; + if (typeof minimum === "number") json.minLength = minimum; + if (typeof maximum === "number") json.maxLength = maximum; + if (format) { + json.format = formatMap[format] ?? format; + if (json.format === "") delete json.format; + if (format === "time") delete json.format; + } + if (contentEncoding) json.contentEncoding = contentEncoding; + if (patterns && patterns.size > 0) { + const regexes = [...patterns]; + if (regexes.length === 1) json.pattern = regexes[0].source; + else if (regexes.length > 1) json.allOf = [...regexes.map((regex) => ({ + ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {}, + pattern: regex.source + }))]; + } + }; + const numberProcessor = (schema, ctx, _json, _params) => { + const json = _json; + const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; + if (typeof format === "string" && format.includes("int")) json.type = "integer"; + else json.type = "number"; + const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY); + const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY); + const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0"; + if (exMin) if (legacy) { + json.minimum = exclusiveMinimum; + json.exclusiveMinimum = true; + } else json.exclusiveMinimum = exclusiveMinimum; + else if (typeof minimum === "number") json.minimum = minimum; + if (exMax) if (legacy) { + json.maximum = exclusiveMaximum; + json.exclusiveMaximum = true; + } else json.exclusiveMaximum = exclusiveMaximum; + else if (typeof maximum === "number") json.maximum = maximum; + if (typeof multipleOf === "number") json.multipleOf = multipleOf; + }; + const booleanProcessor = (_schema, _ctx, json, _params) => { + json.type = "boolean"; + }; + const neverProcessor = (_schema, _ctx, json, _params) => { + json.not = {}; + }; + const enumProcessor = (schema, _ctx, json, _params) => { + const def = schema._zod.def; + const values = getEnumValues(def.entries); + if (values.every((v) => typeof v === "number")) json.type = "number"; + if (values.every((v) => typeof v === "string")) json.type = "string"; + json.enum = values; + }; + const literalProcessor = (schema, ctx, json, _params) => { + const def = schema._zod.def; + const vals = []; + for (const val of def.values) if (val === void 0) { + if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema"); + } else if (typeof val === "bigint") if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema"); + else vals.push(Number(val)); + else vals.push(val); + if (vals.length === 0) {} else if (vals.length === 1) { + const val = vals[0]; + json.type = val === null ? "null" : typeof val; + if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") json.enum = [val]; + else json.const = val; + } else { + if (vals.every((v) => typeof v === "number")) json.type = "number"; + if (vals.every((v) => typeof v === "string")) json.type = "string"; + if (vals.every((v) => typeof v === "boolean")) json.type = "boolean"; + if (vals.every((v) => v === null)) json.type = "null"; + json.enum = vals; + } + }; + const customProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Custom types cannot be represented in JSON Schema"); + }; + const transformProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Transforms cannot be represented in JSON Schema"); + }; + const arrayProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") json.minItems = minimum; + if (typeof maximum === "number") json.maxItems = maximum; + json.type = "array"; + json.items = process(def.element, ctx, { + ...params, + path: [...params.path, "items"] + }); + }; + const objectProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + json.properties = {}; + const shape = def.shape; + for (const key in shape) json.properties[key] = process(shape[key], ctx, { + ...params, + path: [ + ...params.path, + "properties", + key + ] + }); + const allKeys = new Set(Object.keys(shape)); + const requiredKeys = new Set([...allKeys].filter((key) => { + const v = def.shape[key]._zod; + if (ctx.io === "input") return v.optin === void 0; + else return v.optout === void 0; + })); + if (requiredKeys.size > 0) json.required = Array.from(requiredKeys); + if (def.catchall?._zod.def.type === "never") json.additionalProperties = false; + else if (!def.catchall) { + if (ctx.io === "output") json.additionalProperties = false; + } else if (def.catchall) json.additionalProperties = process(def.catchall, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + }; + const unionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const isExclusive = def.inclusive === false; + const options = def.options.map((x, i) => process(x, ctx, { + ...params, + path: [ + ...params.path, + isExclusive ? "oneOf" : "anyOf", + i + ] + })); + if (isExclusive) json.oneOf = options; + else json.anyOf = options; + }; + const intersectionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const a = process(def.left, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 0 + ] + }); + const b = process(def.right, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 1 + ] + }); + const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1; + json.allOf = [...isSimpleIntersection(a) ? a.allOf : [a], ...isSimpleIntersection(b) ? b.allOf : [b]]; + }; + const recordProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + const keyType = def.keyType; + const patterns = keyType._zod.bag?.patterns; + if (def.mode === "loose" && patterns && patterns.size > 0) { + const valueSchema = process(def.valueType, ctx, { + ...params, + path: [ + ...params.path, + "patternProperties", + "*" + ] + }); + json.patternProperties = {}; + for (const pattern of patterns) json.patternProperties[pattern.source] = valueSchema; + } else { + if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") json.propertyNames = process(def.keyType, ctx, { + ...params, + path: [...params.path, "propertyNames"] + }); + json.additionalProperties = process(def.valueType, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + } + const keyValues = keyType._zod.values; + if (keyValues) { + const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number"); + if (validKeyValues.length > 0) json.required = validKeyValues; + } + }; + const nullableProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const inner = process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + if (ctx.target === "openapi-3.0") { + seen.ref = def.innerType; + json.nullable = true; + } else json.anyOf = [inner, { type: "null" }]; + }; + const nonoptionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const defaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.default = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const prefaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + if (ctx.io === "input") json._prefault = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const catchProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + let catchValue; + try { + catchValue = def.catchValue(void 0); + } catch { + throw new Error("Dynamic catch values are not supported in JSON Schema"); + } + json.default = catchValue; + }; + const pipeProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + const inIsTransform = def.in._zod.traits.has("$ZodTransform"); + const innerType = ctx.io === "input" ? inIsTransform ? def.out : def.in : def.out; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + const readonlyProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.readOnly = true; + }; + const optionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const lazyProcessor = (schema, ctx, _json, params) => { + const innerType = schema._zod.innerType; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/iso.js + const ZodISODateTime = /*@__PURE__*/ $constructor("ZodISODateTime", (inst, def) => { + $ZodISODateTime.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function datetime(params) { + return /* @__PURE__ */ _isoDateTime(ZodISODateTime, params); + } + const ZodISODate = /*@__PURE__*/ $constructor("ZodISODate", (inst, def) => { + $ZodISODate.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function date(params) { + return /* @__PURE__ */ _isoDate(ZodISODate, params); + } + const ZodISOTime = /*@__PURE__*/ $constructor("ZodISOTime", (inst, def) => { + $ZodISOTime.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function time(params) { + return /* @__PURE__ */ _isoTime(ZodISOTime, params); + } + const ZodISODuration = /*@__PURE__*/ $constructor("ZodISODuration", (inst, def) => { + $ZodISODuration.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function duration(params) { + return /* @__PURE__ */ _isoDuration(ZodISODuration, params); + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/errors.js + const initializer = (inst, issues) => { + $ZodError.init(inst, issues); + inst.name = "ZodError"; + Object.defineProperties(inst, { + format: { value: (mapper) => formatError(inst, mapper) }, + flatten: { value: (mapper) => flattenError(inst, mapper) }, + addIssue: { value: (issue) => { + inst.issues.push(issue); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } }, + addIssues: { value: (issues) => { + inst.issues.push(...issues); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } }, + isEmpty: { get() { + return inst.issues.length === 0; + } } + }); + }; + const ZodRealError = /*@__PURE__*/ $constructor("ZodError", initializer, { Parent: Error }); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/parse.js + const parse = /* @__PURE__ */ _parse(ZodRealError); + const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError); + const safeParse = /* @__PURE__ */ _safeParse(ZodRealError); + const safeParseAsync = /* @__PURE__ */ _safeParseAsync(ZodRealError); + const encode = /* @__PURE__ */ _encode(ZodRealError); + const decode = /* @__PURE__ */ _decode(ZodRealError); + const encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError); + const decodeAsync = /* @__PURE__ */ _decodeAsync(ZodRealError); + const safeEncode = /* @__PURE__ */ _safeEncode(ZodRealError); + const safeDecode = /* @__PURE__ */ _safeDecode(ZodRealError); + const safeEncodeAsync = /* @__PURE__ */ _safeEncodeAsync(ZodRealError); + const safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync(ZodRealError); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js + const _installedGroups = /* @__PURE__ */ new WeakMap(); + function _installLazyMethods(inst, group, methods) { + const proto = Object.getPrototypeOf(inst); + let installed = _installedGroups.get(proto); + if (!installed) { + installed = /* @__PURE__ */ new Set(); + _installedGroups.set(proto, installed); + } + if (installed.has(group)) return; + installed.add(group); + for (const key in methods) { + const fn = methods[key]; + Object.defineProperty(proto, key, { + configurable: true, + enumerable: false, + get() { + const bound = fn.bind(this); + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: bound + }); + return bound; + }, + set(v) { + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: v + }); + } + }); + } + } + const ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => { + $ZodType.init(inst, def); + Object.assign(inst["~standard"], { jsonSchema: { + input: createStandardJSONSchemaMethod(inst, "input"), + output: createStandardJSONSchemaMethod(inst, "output") + } }); + inst.toJSONSchema = createToJSONSchemaMethod(inst, {}); + inst.def = def; + inst.type = def.type; + Object.defineProperty(inst, "_def", { value: def }); + inst.parse = (data, params) => parse(inst, data, params, { callee: inst.parse }); + inst.safeParse = (data, params) => safeParse(inst, data, params); + inst.parseAsync = async (data, params) => parseAsync(inst, data, params, { callee: inst.parseAsync }); + inst.safeParseAsync = async (data, params) => safeParseAsync(inst, data, params); + inst.spa = inst.safeParseAsync; + inst.encode = (data, params) => encode(inst, data, params); + inst.decode = (data, params) => decode(inst, data, params); + inst.encodeAsync = async (data, params) => encodeAsync(inst, data, params); + inst.decodeAsync = async (data, params) => decodeAsync(inst, data, params); + inst.safeEncode = (data, params) => safeEncode(inst, data, params); + inst.safeDecode = (data, params) => safeDecode(inst, data, params); + inst.safeEncodeAsync = async (data, params) => safeEncodeAsync(inst, data, params); + inst.safeDecodeAsync = async (data, params) => safeDecodeAsync(inst, data, params); + _installLazyMethods(inst, "ZodType", { + check(...chks) { + const def = this.def; + return this.clone(mergeDefs(def, { checks: [...def.checks ?? [], ...chks.map((ch) => typeof ch === "function" ? { _zod: { + check: ch, + def: { check: "custom" }, + onattach: [] + } } : ch)] }), { parent: true }); + }, + with(...chks) { + return this.check(...chks); + }, + clone(def, params) { + return clone(this, def, params); + }, + brand() { + return this; + }, + register(reg, meta) { + reg.add(this, meta); + return this; + }, + refine(check, params) { + return this.check(refine(check, params)); + }, + superRefine(refinement, params) { + return this.check(superRefine(refinement, params)); + }, + overwrite(fn) { + return this.check(/* @__PURE__ */ _overwrite(fn)); + }, + optional() { + return optional(this); + }, + exactOptional() { + return exactOptional(this); + }, + nullable() { + return nullable(this); + }, + nullish() { + return optional(nullable(this)); + }, + nonoptional(params) { + return nonoptional(this, params); + }, + array() { + return array(this); + }, + or(arg) { + return union([this, arg]); + }, + and(arg) { + return intersection(this, arg); + }, + transform(tx) { + return pipe(this, transform(tx)); + }, + default(d) { + return _default(this, d); + }, + prefault(d) { + return prefault(this, d); + }, + catch(params) { + return _catch(this, params); + }, + pipe(target) { + return pipe(this, target); + }, + readonly() { + return readonly(this); + }, + describe(description) { + const cl = this.clone(); + globalRegistry.add(cl, { description }); + return cl; + }, + meta(...args) { + if (args.length === 0) return globalRegistry.get(this); + const cl = this.clone(); + globalRegistry.add(cl, args[0]); + return cl; + }, + isOptional() { + return this.safeParse(void 0).success; + }, + isNullable() { + return this.safeParse(null).success; + }, + apply(fn) { + return fn(this); + } + }); + Object.defineProperty(inst, "description", { + get() { + return globalRegistry.get(inst)?.description; + }, + configurable: true + }); + return inst; + }); + /** @internal */ + const _ZodString = /*@__PURE__*/ $constructor("_ZodString", (inst, def) => { + $ZodString.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => stringProcessor(inst, ctx, json, params); + const bag = inst._zod.bag; + inst.format = bag.format ?? null; + inst.minLength = bag.minimum ?? null; + inst.maxLength = bag.maximum ?? null; + _installLazyMethods(inst, "_ZodString", { + regex(...args) { + return this.check(/* @__PURE__ */ _regex(...args)); + }, + includes(...args) { + return this.check(/* @__PURE__ */ _includes(...args)); + }, + startsWith(...args) { + return this.check(/* @__PURE__ */ _startsWith(...args)); + }, + endsWith(...args) { + return this.check(/* @__PURE__ */ _endsWith(...args)); + }, + min(...args) { + return this.check(/* @__PURE__ */ _minLength(...args)); + }, + max(...args) { + return this.check(/* @__PURE__ */ _maxLength(...args)); + }, + length(...args) { + return this.check(/* @__PURE__ */ _length(...args)); + }, + nonempty(...args) { + return this.check(/* @__PURE__ */ _minLength(1, ...args)); + }, + lowercase(params) { + return this.check(/* @__PURE__ */ _lowercase(params)); + }, + uppercase(params) { + return this.check(/* @__PURE__ */ _uppercase(params)); + }, + trim() { + return this.check(/* @__PURE__ */ _trim()); + }, + normalize(...args) { + return this.check(/* @__PURE__ */ _normalize(...args)); + }, + toLowerCase() { + return this.check(/* @__PURE__ */ _toLowerCase()); + }, + toUpperCase() { + return this.check(/* @__PURE__ */ _toUpperCase()); + }, + slugify() { + return this.check(/* @__PURE__ */ _slugify()); + } + }); + }); + const ZodString = /*@__PURE__*/ $constructor("ZodString", (inst, def) => { + $ZodString.init(inst, def); + _ZodString.init(inst, def); + inst.email = (params) => inst.check(/* @__PURE__ */ _email(ZodEmail, params)); + inst.url = (params) => inst.check(/* @__PURE__ */ _url(ZodURL, params)); + inst.jwt = (params) => inst.check(/* @__PURE__ */ _jwt(ZodJWT, params)); + inst.emoji = (params) => inst.check(/* @__PURE__ */ _emoji(ZodEmoji, params)); + inst.guid = (params) => inst.check(/* @__PURE__ */ _guid(ZodGUID, params)); + inst.uuid = (params) => inst.check(/* @__PURE__ */ _uuid(ZodUUID, params)); + inst.uuidv4 = (params) => inst.check(/* @__PURE__ */ _uuidv4(ZodUUID, params)); + inst.uuidv6 = (params) => inst.check(/* @__PURE__ */ _uuidv6(ZodUUID, params)); + inst.uuidv7 = (params) => inst.check(/* @__PURE__ */ _uuidv7(ZodUUID, params)); + inst.nanoid = (params) => inst.check(/* @__PURE__ */ _nanoid(ZodNanoID, params)); + inst.guid = (params) => inst.check(/* @__PURE__ */ _guid(ZodGUID, params)); + inst.cuid = (params) => inst.check(/* @__PURE__ */ _cuid(ZodCUID, params)); + inst.cuid2 = (params) => inst.check(/* @__PURE__ */ _cuid2(ZodCUID2, params)); + inst.ulid = (params) => inst.check(/* @__PURE__ */ _ulid(ZodULID, params)); + inst.base64 = (params) => inst.check(/* @__PURE__ */ _base64(ZodBase64, params)); + inst.base64url = (params) => inst.check(/* @__PURE__ */ _base64url(ZodBase64URL, params)); + inst.xid = (params) => inst.check(/* @__PURE__ */ _xid(ZodXID, params)); + inst.ksuid = (params) => inst.check(/* @__PURE__ */ _ksuid(ZodKSUID, params)); + inst.ipv4 = (params) => inst.check(/* @__PURE__ */ _ipv4(ZodIPv4, params)); + inst.ipv6 = (params) => inst.check(/* @__PURE__ */ _ipv6(ZodIPv6, params)); + inst.cidrv4 = (params) => inst.check(/* @__PURE__ */ _cidrv4(ZodCIDRv4, params)); + inst.cidrv6 = (params) => inst.check(/* @__PURE__ */ _cidrv6(ZodCIDRv6, params)); + inst.e164 = (params) => inst.check(/* @__PURE__ */ _e164(ZodE164, params)); + inst.datetime = (params) => inst.check(datetime(params)); + inst.date = (params) => inst.check(date(params)); + inst.time = (params) => inst.check(time(params)); + inst.duration = (params) => inst.check(duration(params)); + }); + function string(params) { + return /* @__PURE__ */ _string(ZodString, params); + } + const ZodStringFormat = /*@__PURE__*/ $constructor("ZodStringFormat", (inst, def) => { + $ZodStringFormat.init(inst, def); + _ZodString.init(inst, def); + }); + const ZodEmail = /*@__PURE__*/ $constructor("ZodEmail", (inst, def) => { + $ZodEmail.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodGUID = /*@__PURE__*/ $constructor("ZodGUID", (inst, def) => { + $ZodGUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodUUID = /*@__PURE__*/ $constructor("ZodUUID", (inst, def) => { + $ZodUUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodURL = /*@__PURE__*/ $constructor("ZodURL", (inst, def) => { + $ZodURL.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodEmoji = /*@__PURE__*/ $constructor("ZodEmoji", (inst, def) => { + $ZodEmoji.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodNanoID = /*@__PURE__*/ $constructor("ZodNanoID", (inst, def) => { + $ZodNanoID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link ZodCUID2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const ZodCUID = /*@__PURE__*/ $constructor("ZodCUID", (inst, def) => { + $ZodCUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCUID2 = /*@__PURE__*/ $constructor("ZodCUID2", (inst, def) => { + $ZodCUID2.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodULID = /*@__PURE__*/ $constructor("ZodULID", (inst, def) => { + $ZodULID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodXID = /*@__PURE__*/ $constructor("ZodXID", (inst, def) => { + $ZodXID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodKSUID = /*@__PURE__*/ $constructor("ZodKSUID", (inst, def) => { + $ZodKSUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodIPv4 = /*@__PURE__*/ $constructor("ZodIPv4", (inst, def) => { + $ZodIPv4.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodIPv6 = /*@__PURE__*/ $constructor("ZodIPv6", (inst, def) => { + $ZodIPv6.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCIDRv4 = /*@__PURE__*/ $constructor("ZodCIDRv4", (inst, def) => { + $ZodCIDRv4.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCIDRv6 = /*@__PURE__*/ $constructor("ZodCIDRv6", (inst, def) => { + $ZodCIDRv6.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodBase64 = /*@__PURE__*/ $constructor("ZodBase64", (inst, def) => { + $ZodBase64.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodBase64URL = /*@__PURE__*/ $constructor("ZodBase64URL", (inst, def) => { + $ZodBase64URL.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodE164 = /*@__PURE__*/ $constructor("ZodE164", (inst, def) => { + $ZodE164.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodJWT = /*@__PURE__*/ $constructor("ZodJWT", (inst, def) => { + $ZodJWT.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodNumber = /*@__PURE__*/ $constructor("ZodNumber", (inst, def) => { + $ZodNumber.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => numberProcessor(inst, ctx, json, params); + _installLazyMethods(inst, "ZodNumber", { + gt(value, params) { + return this.check(/* @__PURE__ */ _gt(value, params)); + }, + gte(value, params) { + return this.check(/* @__PURE__ */ _gte(value, params)); + }, + min(value, params) { + return this.check(/* @__PURE__ */ _gte(value, params)); + }, + lt(value, params) { + return this.check(/* @__PURE__ */ _lt(value, params)); + }, + lte(value, params) { + return this.check(/* @__PURE__ */ _lte(value, params)); + }, + max(value, params) { + return this.check(/* @__PURE__ */ _lte(value, params)); + }, + int(params) { + return this.check(int(params)); + }, + safe(params) { + return this.check(int(params)); + }, + positive(params) { + return this.check(/* @__PURE__ */ _gt(0, params)); + }, + nonnegative(params) { + return this.check(/* @__PURE__ */ _gte(0, params)); + }, + negative(params) { + return this.check(/* @__PURE__ */ _lt(0, params)); + }, + nonpositive(params) { + return this.check(/* @__PURE__ */ _lte(0, params)); + }, + multipleOf(value, params) { + return this.check(/* @__PURE__ */ _multipleOf(value, params)); + }, + step(value, params) { + return this.check(/* @__PURE__ */ _multipleOf(value, params)); + }, + finite() { + return this; + } + }); + const bag = inst._zod.bag; + inst.minValue = Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null; + inst.maxValue = Math.min(bag.maximum ?? Number.POSITIVE_INFINITY, bag.exclusiveMaximum ?? Number.POSITIVE_INFINITY) ?? null; + inst.isInt = (bag.format ?? "").includes("int") || Number.isSafeInteger(bag.multipleOf ?? .5); + inst.isFinite = true; + inst.format = bag.format ?? null; + }); + function number(params) { + return /* @__PURE__ */ _number(ZodNumber, params); + } + const ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def) => { + $ZodNumberFormat.init(inst, def); + ZodNumber.init(inst, def); + }); + function int(params) { + return /* @__PURE__ */ _int(ZodNumberFormat, params); + } + const ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => { + $ZodBoolean.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params); + }); + function boolean(params) { + return /* @__PURE__ */ _boolean(ZodBoolean, params); + } + const ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => { + $ZodUnknown.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => void 0; + }); + function unknown() { + return /* @__PURE__ */ _unknown(ZodUnknown); + } + const ZodNever = /*@__PURE__*/ $constructor("ZodNever", (inst, def) => { + $ZodNever.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => neverProcessor(inst, ctx, json, params); + }); + function never(params) { + return /* @__PURE__ */ _never(ZodNever, params); + } + const ZodArray = /*@__PURE__*/ $constructor("ZodArray", (inst, def) => { + $ZodArray.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => arrayProcessor(inst, ctx, json, params); + inst.element = def.element; + _installLazyMethods(inst, "ZodArray", { + min(n, params) { + return this.check(/* @__PURE__ */ _minLength(n, params)); + }, + nonempty(params) { + return this.check(/* @__PURE__ */ _minLength(1, params)); + }, + max(n, params) { + return this.check(/* @__PURE__ */ _maxLength(n, params)); + }, + length(n, params) { + return this.check(/* @__PURE__ */ _length(n, params)); + }, + unwrap() { + return this.element; + } + }); + }); + function array(element, params) { + return /* @__PURE__ */ _array(ZodArray, element, params); + } + const ZodObject = /*@__PURE__*/ $constructor("ZodObject", (inst, def) => { + $ZodObjectJIT.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => objectProcessor(inst, ctx, json, params); + defineLazy(inst, "shape", () => { + return def.shape; + }); + _installLazyMethods(inst, "ZodObject", { + keyof() { + return _enum(Object.keys(this._zod.def.shape)); + }, + catchall(catchall) { + return this.clone({ + ...this._zod.def, + catchall + }); + }, + passthrough() { + return this.clone({ + ...this._zod.def, + catchall: unknown() + }); + }, + loose() { + return this.clone({ + ...this._zod.def, + catchall: unknown() + }); + }, + strict() { + return this.clone({ + ...this._zod.def, + catchall: never() + }); + }, + strip() { + return this.clone({ + ...this._zod.def, + catchall: void 0 + }); + }, + extend(incoming) { + return extend(this, incoming); + }, + safeExtend(incoming) { + return safeExtend(this, incoming); + }, + merge(other) { + return merge(this, other); + }, + pick(mask) { + return pick(this, mask); + }, + omit(mask) { + return omit(this, mask); + }, + partial(...args) { + return partial(ZodOptional, this, args[0]); + }, + required(...args) { + return required(ZodNonOptional, this, args[0]); + } + }); + }); + function object(shape, params) { + return new ZodObject({ + type: "object", + shape: shape ?? {}, + ...normalizeParams(params) + }); + } + function looseObject(shape, params) { + return new ZodObject({ + type: "object", + shape, + catchall: unknown(), + ...normalizeParams(params) + }); + } + const ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => { + $ZodUnion.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => unionProcessor(inst, ctx, json, params); + inst.options = def.options; + }); + function union(options, params) { + return new ZodUnion({ + type: "union", + options, + ...normalizeParams(params) + }); + } + const ZodDiscriminatedUnion = /*@__PURE__*/ $constructor("ZodDiscriminatedUnion", (inst, def) => { + ZodUnion.init(inst, def); + $ZodDiscriminatedUnion.init(inst, def); + }); + function discriminatedUnion(discriminator, options, params) { + return new ZodDiscriminatedUnion({ + type: "union", + options, + discriminator, + ...normalizeParams(params) + }); + } + const ZodIntersection = /*@__PURE__*/ $constructor("ZodIntersection", (inst, def) => { + $ZodIntersection.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => intersectionProcessor(inst, ctx, json, params); + }); + function intersection(left, right) { + return new ZodIntersection({ + type: "intersection", + left, + right + }); + } + const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => { + $ZodRecord.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params); + inst.keyType = def.keyType; + inst.valueType = def.valueType; + }); + function record(keyType, valueType, params) { + if (!valueType || !valueType._zod) return new ZodRecord({ + type: "record", + keyType: string(), + valueType: keyType, + ...normalizeParams(valueType) + }); + return new ZodRecord({ + type: "record", + keyType, + valueType, + ...normalizeParams(params) + }); + } + const ZodEnum = /*@__PURE__*/ $constructor("ZodEnum", (inst, def) => { + $ZodEnum.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => enumProcessor(inst, ctx, json, params); + inst.enum = def.entries; + inst.options = Object.values(def.entries); + const keys = new Set(Object.keys(def.entries)); + inst.extract = (values, params) => { + const newEntries = {}; + for (const value of values) if (keys.has(value)) newEntries[value] = def.entries[value]; + else throw new Error(`Key ${value} not found in enum`); + return new ZodEnum({ + ...def, + checks: [], + ...normalizeParams(params), + entries: newEntries + }); + }; + inst.exclude = (values, params) => { + const newEntries = { ...def.entries }; + for (const value of values) if (keys.has(value)) delete newEntries[value]; + else throw new Error(`Key ${value} not found in enum`); + return new ZodEnum({ + ...def, + checks: [], + ...normalizeParams(params), + entries: newEntries + }); + }; + }); + function _enum(values, params) { + return new ZodEnum({ + type: "enum", + entries: Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values, + ...normalizeParams(params) + }); + } + const ZodLiteral = /*@__PURE__*/ $constructor("ZodLiteral", (inst, def) => { + $ZodLiteral.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => literalProcessor(inst, ctx, json, params); + inst.values = new Set(def.values); + Object.defineProperty(inst, "value", { get() { + if (def.values.length > 1) throw new Error("This schema contains multiple valid literal values. Use `.values` instead."); + return def.values[0]; + } }); + }); + function literal(value, params) { + return new ZodLiteral({ + type: "literal", + values: Array.isArray(value) ? value : [value], + ...normalizeParams(params) + }); + } + const ZodTransform = /*@__PURE__*/ $constructor("ZodTransform", (inst, def) => { + $ZodTransform.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => transformProcessor(inst, ctx, json, params); + inst._zod.parse = (payload, _ctx) => { + if (_ctx.direction === "backward") throw new $ZodEncodeError(inst.constructor.name); + payload.addIssue = (issue$1) => { + if (typeof issue$1 === "string") payload.issues.push(issue(issue$1, payload.value, def)); + else { + const _issue = issue$1; + if (_issue.fatal) _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = inst); + payload.issues.push(issue(_issue)); + } + }; + const output = def.transform(payload.value, payload); + if (output instanceof Promise) return output.then((output) => { + payload.value = output; + payload.fallback = true; + return payload; + }); + payload.value = output; + payload.fallback = true; + return payload; + }; + }); + function transform(fn) { + return new ZodTransform({ + type: "transform", + transform: fn + }); + } + const ZodOptional = /*@__PURE__*/ $constructor("ZodOptional", (inst, def) => { + $ZodOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function optional(innerType) { + return new ZodOptional({ + type: "optional", + innerType + }); + } + const ZodExactOptional = /*@__PURE__*/ $constructor("ZodExactOptional", (inst, def) => { + $ZodExactOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function exactOptional(innerType) { + return new ZodExactOptional({ + type: "optional", + innerType + }); + } + const ZodNullable = /*@__PURE__*/ $constructor("ZodNullable", (inst, def) => { + $ZodNullable.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nullableProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function nullable(innerType) { + return new ZodNullable({ + type: "nullable", + innerType + }); + } + const ZodDefault = /*@__PURE__*/ $constructor("ZodDefault", (inst, def) => { + $ZodDefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => defaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeDefault = inst.unwrap; + }); + function _default(innerType, defaultValue) { + return new ZodDefault({ + type: "default", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); + } + }); + } + const ZodPrefault = /*@__PURE__*/ $constructor("ZodPrefault", (inst, def) => { + $ZodPrefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => prefaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function prefault(innerType, defaultValue) { + return new ZodPrefault({ + type: "prefault", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); + } + }); + } + const ZodNonOptional = /*@__PURE__*/ $constructor("ZodNonOptional", (inst, def) => { + $ZodNonOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nonoptionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function nonoptional(innerType, params) { + return new ZodNonOptional({ + type: "nonoptional", + innerType, + ...normalizeParams(params) + }); + } + const ZodCatch = /*@__PURE__*/ $constructor("ZodCatch", (inst, def) => { + $ZodCatch.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => catchProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeCatch = inst.unwrap; + }); + function _catch(innerType, catchValue) { + return new ZodCatch({ + type: "catch", + innerType, + catchValue: typeof catchValue === "function" ? catchValue : () => catchValue + }); + } + const ZodPipe = /*@__PURE__*/ $constructor("ZodPipe", (inst, def) => { + $ZodPipe.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => pipeProcessor(inst, ctx, json, params); + inst.in = def.in; + inst.out = def.out; + }); + function pipe(in_, out) { + return new ZodPipe({ + type: "pipe", + in: in_, + out + }); + } + const ZodReadonly = /*@__PURE__*/ $constructor("ZodReadonly", (inst, def) => { + $ZodReadonly.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => readonlyProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function readonly(innerType) { + return new ZodReadonly({ + type: "readonly", + innerType + }); + } + const ZodLazy = /*@__PURE__*/ $constructor("ZodLazy", (inst, def) => { + $ZodLazy.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => lazyProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.getter(); + }); + function lazy(getter) { + return new ZodLazy({ + type: "lazy", + getter + }); + } + const ZodCustom = /*@__PURE__*/ $constructor("ZodCustom", (inst, def) => { + $ZodCustom.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => customProcessor(inst, ctx, json, params); + }); + function custom(fn, _params) { + return /* @__PURE__ */ _custom(ZodCustom, fn ?? (() => true), _params); + } + function refine(fn, _params = {}) { + return /* @__PURE__ */ _refine(ZodCustom, fn, _params); + } + function superRefine(fn, params) { + return /* @__PURE__ */ _superRefine(fn, params); + } + //#endregion + //#region ../../host/apiproxy/lib/types/api/rpc.schema.js + /** + * Message-layer zod schemas: the four wire full forms + error body + + * carrier receipt. The payload slot is unknown in the full-form schemas — business payloads + * get a second parse dispatched by method (two-level parse discipline). + * Brand cast point: rpcIdSchema, and only there. + */ + /** + * RpcId: one brand cast after schema validation (the only cast point in this + * file). No min-length: the id is an opaque echo token, and rejecting values + * here would only turn a correlatable error report into a client-side parse + * failure (the handler substitutes a sentinel when a request's id is unreadable). + */ + const rpcIdSchema = string(); + /** Error body: discriminated by code, per-branch details aligned to RpcErrorDetailsMap; details is required. */ + const rpcErrorSchema = discriminatedUnion("code", [ + object({ + code: literal("bad-request"), + message: string(), + details: object({ issues: array(custom()) }) + }), + object({ + code: literal("cancelled"), + message: string(), + details: object({}) + }), + object({ + code: literal("session-not-found"), + message: string(), + details: object({ sessionId: string() }) + }), + object({ + code: literal("model-unavailable"), + message: string(), + details: object({ + provider: string(), + model: string() + }) + }), + object({ + code: literal("session-conflict"), + message: string(), + details: object({ + sessionId: string(), + requestedCwd: string(), + existingCwd: string().optional() + }) + }), + object({ + code: literal("invalid-time-zone"), + message: string(), + details: object({ value: string() }) + }), + object({ + code: literal("workspace-attach-failed"), + message: string(), + details: object({ + sessionId: string(), + workspaceId: string() + }) + }), + object({ + code: literal("workspace-not-found"), + message: string(), + details: object({ workspaceId: string() }) + }), + object({ + code: literal("workspace-invalid-path"), + message: string(), + details: object({ path: string() }) + }), + object({ + code: literal("workspace-name-conflict"), + message: string(), + details: object({ name: string() }) + }), + object({ + code: literal("workspace-move-invalid"), + message: string(), + details: object({ + workspaceId: string(), + sessionId: string(), + beforeSessionId: string().optional() + }) + }), + object({ + code: literal("directory-unreadable"), + message: string(), + details: object({ path: string() }) + }), + object({ + code: literal("directory-exists"), + message: string(), + details: object({ path: string() }) + }), + object({ + code: literal("directory-create-failed"), + message: string(), + details: object({ path: string() }) + }), + object({ + code: literal("directory-picker-unavailable"), + message: string(), + details: object({ capability: string() }) + }), + object({ + code: literal("agent-preset-read-only"), + message: string(), + details: object({ + agentPreset: string(), + reason: string() + }) + }), + object({ + code: literal("agent-preset-locked"), + message: string(), + details: object({ + sessionId: string(), + agentPreset: string() + }) + }), + object({ + code: literal("agent-preset-conflict"), + message: string(), + details: object({ + sessionId: string(), + requestedPreset: string(), + existingPreset: string().optional() + }) + }), + object({ + code: literal("agent-preset-not-found"), + message: string(), + details: object({ + agentPreset: string(), + available: array(string()) + }) + }), + object({ + code: literal("agent-preset-invalid"), + message: string(), + details: object({ + agentPreset: string(), + reason: string() + }) + }), + object({ + code: literal("agent-busy"), + message: string(), + details: object({ reason: string() }) + }), + object({ + code: literal("attachment-error"), + message: string(), + details: object({ reason: string() }) + }), + object({ + code: literal("queue-item-not-found"), + message: string(), + details: object({ itemId: string() }) + }), + object({ + code: literal("steer-unavailable"), + message: string(), + details: object({ itemId: string() }) + }), + object({ + code: literal("command-error"), + message: string(), + details: object({}) + }), + object({ + code: literal("unknown-command"), + message: string(), + details: object({}) + }), + object({ + code: literal("settings-rejected"), + message: string(), + details: object({ ns: string() }) + }), + object({ + code: literal("settings-not-exposed"), + message: string(), + details: object({ ns: string() }) + }), + object({ + code: literal("settings-conflict"), + message: string(), + details: object({ + ns: string(), + expected: number(), + actual: number() + }) + }), + object({ + code: literal("credential-rejected"), + message: string(), + details: object({ ref: string() }) + }), + object({ + code: literal("model-discovery-failed"), + message: string(), + details: object({ + settingsNs: string(), + baseURL: string().optional() + }) + }), + object({ + code: literal("title-invalid"), + message: string(), + details: object({ sessionId: string() }) + }), + object({ + code: literal("fork-unavailable"), + message: string(), + details: object({ sessionId: string() }) + }), + object({ + code: literal("subagent-parent-unavailable"), + message: string(), + details: object({ parentSessionId: string() }) + }), + object({ + code: literal("subagent-not-found"), + message: string(), + details: object({ + parentSessionId: string(), + childSessionId: string() + }) + }), + object({ + code: literal("subagent-catalog-diagnostic"), + message: string(), + details: object({ + parentSessionId: string(), + childSessionId: string(), + reason: union([ + literal("corrupt"), + literal("unsupported"), + literal("unavailable") + ]) + }) + }), + object({ + code: literal("subagent-not-resumable"), + message: string(), + details: object({ childSessionId: string() }) + }), + object({ + code: literal("subagent-unauthorized"), + message: string(), + details: object({ childSessionId: string() }) + }), + object({ + code: literal("subagent-delivery-unavailable"), + message: string(), + details: object({ childSessionId: string() }) + }), + object({ + code: literal("internal"), + message: string(), + details: object({}) + }) + ]); + /** + * Business success/failure result schema (generic, reusable). + * @param value - Schema for the business value. + * @returns Schema for RpcResult. + */ + function rpcResultSchema(value) { + return union([object({ + ok: literal(true), + value + }), object({ + ok: literal(false), + error: rpcErrorSchema + })]); + } + /** ClientRequest full form (payload stays wide — the business layer runs the second parse). */ + const clientRequestSchema = object({ + type: literal("client-request"), + rpcId: rpcIdSchema, + method: string(), + payload: unknown() + }); + /** ServerResponse full form (result.value stays wide). */ + const serverResponseSchema = object({ + type: literal("server-response"), + rpcId: rpcIdSchema, + result: rpcResultSchema(unknown().optional()) + }); + /** ServerRequest full form (payload stays wide). */ + const serverRequestSchema = object({ + type: literal("server-request"), + rpcId: rpcIdSchema, + method: string(), + payload: unknown() + }); + discriminatedUnion("type", [ + clientRequestSchema, + serverResponseSchema, + serverRequestSchema, + object({ + type: literal("client-response"), + rpcId: rpcIdSchema, + result: rpcResultSchema(unknown().optional()) + }) + ]); + /** Carrier receipt schema. */ + const rpcReceiptSchema = union([object({ accepted: literal(true) }), object({ + accepted: literal(false), + reason: union([literal("not-pending"), literal("bad-response")]) + })]); + //#endregion + //#region ../../host/apiproxy/lib/types/api/session-search.js + /** + * Return the longest prefix containing at most `maximum` Unicode code points. + * @param value - text to bound. + * @param maximum - non-negative code-point limit. + * @returns `value` unchanged when it fits, otherwise a code-point-safe prefix. + */ + function truncateUnicodeCodePoints(value, maximum) { + let count = 0; + let end = 0; + for (const codePoint of value) { + if (count === maximum) return value.slice(0, end); + count++; + end += codePoint.length; + } + return value; + } + //#endregion + //#region ../../host/apiproxy/lib/types/api/sessions.schema.js + /** + * sessions domain zod schemas (names derived from map keys: sessionListRequestSchema / + * sessionListValueSchema). SessionEvent passthrough = strict envelope (type/seq/time) + wide + * data: the merge-extensible event API keeps an unknown-type branch at the union level, + * with no field-level passthrough. SessionId brand cast point: sessionIdSchema, and only there. + */ + /** SessionId: one brand cast after schema validation (the only cast point in this domain). */ + const sessionIdSchema = string().min(1); + /** MessageId: one brand cast after non-empty string validation. */ + const messageIdSchema$1 = string().min(1); + /** + * WorkspaceId: the workspace domain's one brand cast. Hosted here rather + * than in workspace.schema because session.create references it while + * workspace.schema references sessionIdSchema — schema modules must stay a + * DAG (both casts used at module top level; a cycle is a load-time TDZ). + */ + const workspaceIdSchema = string().min(1); + /** SessionEvent passthrough: strict envelope, wide data (the client fold handles unknown types via its documented default). */ + const sessionEventSchema = object({ + type: string(), + seq: number().int().nonnegative(), + time: number(), + data: unknown(), + sourceEventSeqs: array(number()).optional(), + surfaceOp: unknown().optional(), + ignorable: literal(true).optional() + }); + /** SessionSummary row of session.list (`projections` reuses the history block's shape and schema). */ + const sessionSummarySchema = object({ + sessionId: sessionIdSchema, + updatedAt: number(), + running: boolean(), + blank: boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: literal("subagent").optional(), + cwd: string().optional(), + agentPreset: string().optional(), + projections: lazy(() => sessionProjectionsBlockSchema).optional() + }); + object({ cursor: string().optional() }); + /** session.list response value. */ + const sessionListValueSchema = object({ items: array(sessionSummarySchema) }); + object({ query: string().trim().min(1).max(500).refine((query) => !query.includes("\0"), { message: "search query must not contain NUL" }) }); + /** session.search response value. */ + const sessionSearchValueSchema = object({ + items: array(object({ + sessionId: sessionIdSchema, + snippet: string().refine((snippet) => truncateUnicodeCodePoints(snippet, 240) === snippet, { message: `search snippet must contain at most 240 Unicode code points` }) + })).max(20), + hasMore: boolean() + }); + object({ + workspaceId: workspaceIdSchema.optional(), + cwd: string().optional(), + sessionId: sessionIdSchema.optional(), + agentPreset: string().optional() + }).refine((payload) => payload.workspaceId === void 0 || payload.cwd === void 0, { message: "session.create accepts workspaceId or cwd, not both" }); + /** session.create response value. */ + const sessionCreateValueSchema = object({ + sessionId: sessionIdSchema, + agentPreset: string().optional() + }); + object({ + sessionId: sessionIdSchema, + title: string() + }); + /** session.rename response value (the normalized accepted title and its event seq). */ + const sessionRenameValueSchema = object({ + title: string().min(1), + seq: number().int().nonnegative() + }); + object({ + sessionId: sessionIdSchema, + atSeq: number().int().nonnegative().optional() + }); + /** session.fork response value (the child session id). */ + const sessionForkValueSchema = object({ sessionId: sessionIdSchema }); + object({ + sessionId: sessionIdSchema, + beforeSeq: number().int().nonnegative().optional(), + maxMessages: number().int().positive().optional() + }); + /** Complete provider/model selection. */ + const modelSelectionSchema = object({ + provider: string().min(1), + model: string().min(1), + reasoningEffort: string().min(1).optional() + }); + /** Exact-model reasoning metadata. */ + const modelReasoningSchema = object({ + efforts: array(object({ + id: string().min(1), + name: string().min(1), + description: string().optional() + })).min(1), + defaultEffort: string().min(1).optional() + }); + /** One advisory model entry inside a provider group. */ + const modelCatalogModelSchema = object({ + id: string().min(1), + name: string().min(1), + description: string().optional(), + reasoning: modelReasoningSchema.optional() + }); + /** One successfully loaded provider group. */ + const modelProviderGroupSchema = object({ + id: string().min(1), + name: string().min(1), + models: array(modelCatalogModelSchema) + }); + /** One provider-local catalog failure. */ + const modelCatalogFailureSchema = object({ + id: string().min(1), + name: string().min(1), + message: string() + }); + /** + * ToolEventView passthrough: lock only the `for` discriminant and the presence + * of a card-tagged `view` object. The view interior is a host-computed product + * the client reads without echoing back; deep-validating it would hand-copy + * the dsh-tools vocabulary into this schema and drift with it. + */ + const toolEventViewSchema = discriminatedUnion("for", [object({ + for: literal("call"), + view: looseObject({ card: string() }) + }), object({ + for: literal("result"), + view: looseObject({ card: string() }) + })]); + /** One session.history item: the session event plus its optional host-computed tool view. */ + const historyEntrySchema = object({ + event: sessionEventSchema, + view: toolEventViewSchema.optional() + }); + /** + * Projection baseline passthrough: `values` stays a wide record — each value + * was already parsed by its provider's own schema on the host side, and + * deep-validating here would import every domain's schema into the carrier. + */ + const sessionProjectionsBlockSchema = object({ + asOfSeq: number().int().min(-1), + values: record(string(), unknown()) + }); + object({ + blank: boolean(), + lastPromptAt: number().nullable() + }); + object({ + maxImageBytes: number().int().positive(), + maxImagesPerMessage: number().int().positive(), + maxMessageImageBytes: number().int().positive(), + maxImagePixels: number().int().positive(), + mediaTypes: array(string()) + }); + /** session.history response value (projections rides the tail page only). */ + const sessionHistoryValueSchema = object({ + events: array(historyEntrySchema), + hasMore: boolean(), + projections: sessionProjectionsBlockSchema.optional() + }); + object({ sessionId: sessionIdSchema }); + /** session.models response value. */ + const sessionModelsValueSchema = object({ + current: modelSelectionSchema, + routable: boolean(), + groups: array(modelProviderGroupSchema), + failures: array(modelCatalogFailureSchema) + }); + object({ + sessionId: sessionIdSchema, + provider: string().min(1), + model: string().min(1), + reasoningEffort: string().min(1).optional() + }); + /** session.selectModel response value. */ + const sessionSelectModelValueSchema = object({ selected: modelSelectionSchema }); + /** ContentBlock passthrough: core is merge-extensible — the type discriminant envelope is strict, the rest stays wide. */ + const contentBlockSchema = looseObject({ type: string() }); + /** Raster image media types accepted by the version-one browser wire. */ + const imageMediaTypeSchema = union([ + literal("image/png"), + literal("image/jpeg"), + literal("image/webp"), + literal("image/gif") + ]); + /** Prompt wire content is intentionally narrower than merge-extensible durable core content. */ + const promptContentPartSchema = discriminatedUnion("type", [object({ + type: literal("text"), + text: string() + }), object({ + type: literal("image"), + mediaType: imageMediaTypeSchema, + data: string(), + name: string().optional() + })]); + object({ + sessionId: sessionIdSchema, + mode: union([literal("queue"), literal("steer")]), + content: array(promptContentPartSchema), + clientTimeZone: string().optional() + }); + /** session.prompt response value (the command slot appears only when the prompt dispatched a slash command). */ + const sessionPromptValueSchema = object({ + accepted: literal(true), + command: object({ + kind: literal("success"), + text: string().optional() + }).optional() + }); + /** Opaque attachment id after string-shape validation. */ + const attachmentIdSchema = string().min(1); + /** Durable image reference returned from the authenticated session lookup. */ + const imageAttachmentRefSchema = object({ + attachmentId: attachmentIdSchema, + mediaType: imageMediaTypeSchema, + bytes: number().int().positive(), + width: number().int().positive(), + height: number().int().positive(), + name: string().optional() + }); + object({ + sessionId: sessionIdSchema, + attachmentId: attachmentIdSchema + }); + /** session.attachment response value. */ + const sessionAttachmentValueSchema = object({ + attachment: imageAttachmentRefSchema, + data: string() + }); + object({ + sessionId: sessionIdSchema, + itemId: messageIdSchema$1, + action: discriminatedUnion("kind", [ + object({ + kind: literal("edit"), + content: array(contentBlockSchema) + }), + object({ kind: literal("remove") }), + object({ kind: literal("steer") }) + ]) + }); + /** session.updateQueue response value. */ + const sessionUpdateQueueValueSchema = object({ accepted: literal(true) }); + object({ sessionId: sessionIdSchema }); + /** session.cancel response value. */ + const sessionCancelValueSchema = object({ accepted: literal(true) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/approvals.schema.js + /** + * approvals domain zod schemas (respond is a client-response; the payload schema serves + * the /api/respond endpoint's second parse after routing via the pending table). + * ApprovalRequestId brand cast point: one. + */ + /** ApprovalRequestId: one brand cast after schema validation (the only cast point in this domain). */ + const approvalRequestIdSchema = string().min(1); + object({ + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + outcome: union([literal("allowed-once"), literal("rejected")]) + }); + /** + * One wire task view. `kind` stays an open string because producer plugins + * extend the registry's kind map by declaration merging, so the closed set is + * not knowable at this boundary. + */ + const taskViewSchema = object({ + id: string().min(1), + kind: string().min(1), + label: string().min(1), + status: union([ + literal("running"), + literal("stopping"), + literal("completed"), + literal("killed"), + literal("failed") + ]), + detail: string().optional(), + startedAt: number().int().nonnegative(), + finishedAt: number().int().nonnegative().optional() + }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/workspace.schema.js + /** + * workspace domain zod schemas (names derived from map keys). The + * WorkspaceId brand cast lives in sessions.schema (see the note there) and + * is re-exported here as the domain-local name. + */ + /** WorkspaceView row of every workspace.* response. */ + const workspaceViewSchema = object({ + workspaceId: workspaceIdSchema, + path: string(), + title: string(), + sessionIds: array(sessionIdSchema), + createdAt: string(), + updatedAt: string() + }); + object({}); + /** workspace.list response value. */ + const workspaceListValueSchema = object({ + items: array(workspaceViewSchema), + archivedSessionIds: array(sessionIdSchema) + }); + object({ path: string() }); + /** workspace.create response value. */ + const workspaceCreateValueSchema = object({ + workspace: workspaceViewSchema, + created: boolean() + }); + object({ + workspaceId: workspaceIdSchema, + title: string() + }).refine((payload) => payload.title.trim() !== "", { message: "workspace.rename requires a non-blank title" }); + /** workspace.rename response value. */ + const workspaceRenameValueSchema = object({ workspace: workspaceViewSchema }); + object({ workspaceId: workspaceIdSchema }); + /** workspace.delete response value. */ + const workspaceDeleteValueSchema = object({ deleted: literal(true) }); + object({ + workspaceId: workspaceIdSchema, + beforeWorkspaceId: workspaceIdSchema.optional() + }); + /** workspace.insertBefore response value: the complete durable display order. */ + const workspaceInsertBeforeValueSchema = object({ workspaceIds: array(workspaceIdSchema) }); + object({ + workspaceId: workspaceIdSchema, + sessionId: sessionIdSchema, + beforeSessionId: sessionIdSchema.optional() + }); + /** workspace.insertSessionBefore response value. */ + const workspaceInsertSessionBeforeValueSchema = object({ workspace: workspaceViewSchema }); + object({ sessionId: sessionIdSchema }); + /** workspace.archiveSession response value: the full updated archive set. */ + const workspaceArchiveSessionValueSchema = object({ archivedSessionIds: array(sessionIdSchema) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/events.schema.js + /** + * events domain zod schemas: MuxFrame / HostFrame unions (discriminatedUnion('type')). + * A frame is the payload slot of the ServerRequest full form; the SessionEvent inside + * a session/event frame reuses sessions.schema's strict-envelope + wide-data passthrough branch. + */ + /** Question fields validated strictly against core dsh-user-questions. */ + const askUserQuestionItemSchema = object({ + id: string(), + question: string(), + header: string().optional(), + detail: string().optional(), + options: array(object({ + label: string(), + description: string().optional() + })).optional(), + multiSelect: boolean().optional(), + intent: discriminatedUnion("kind", [object({ + kind: literal("plan-review"), + approve: string() + })]).optional() + }); + /** Unified message envelope carried by transient queue frames. */ + const messageSchema = object({ + id: string().min(1), + role: union([ + literal("system"), + literal("user"), + literal("assistant") + ]), + content: array(contentBlockSchema), + source: looseObject({ kind: string() }) + }); + /** MuxFrame union (payload slot of a mux-stream ServerRequest). */ + const muxFrameSchema = discriminatedUnion("type", [ + object({ + type: literal("session/event"), + sessionId: sessionIdSchema, + event: sessionEventSchema, + view: toolEventViewSchema.optional() + }), + object({ + type: literal("session/subscribed"), + sessionId: sessionIdSchema, + lastSeq: number().int() + }), + object({ + type: literal("approval/requested"), + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + toolName: string(), + callId: string().optional(), + reason: string().optional() + }), + object({ + type: literal("approval/resolved"), + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + outcome: union([ + literal("allowed-once"), + literal("rejected"), + literal("cancelled"), + literal("unavailable") + ]) + }), + object({ + type: literal("question/requested"), + sessionId: sessionIdSchema, + questions: array(askUserQuestionItemSchema).min(1) + }), + object({ + type: literal("question/resolved"), + sessionId: sessionIdSchema, + questionRpcId: rpcIdSchema, + outcome: union([literal("answered"), literal("cancelled")]) + }), + object({ + type: literal("session/queue"), + sessionId: sessionIdSchema, + items: array(object({ + id: messageIdSchema$1, + placement: union([ + literal("queued"), + literal("steering"), + literal("context") + ]), + message: messageSchema + })) + }), + object({ + type: literal("session/jobs"), + sessionId: sessionIdSchema, + jobs: array(taskViewSchema) + }), + object({ + type: literal("session/projection"), + sessionId: sessionIdSchema, + key: string().min(1), + value: unknown(), + seq: number().int().nonnegative() + }), + object({ + type: literal("stream/error"), + error: rpcErrorSchema + }) + ]); + /** HostFrame union (payload slot of a host-stream ServerRequest). */ + const hostFrameSchema = discriminatedUnion("type", [ + object({ + type: literal("host/session-added"), + sessionId: sessionIdSchema, + blank: boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: literal("subagent").optional(), + cwd: string().optional(), + agentPreset: string().optional() + }), + object({ + type: literal("host/session-removed"), + sessionId: sessionIdSchema + }), + object({ + type: literal("host/session-status"), + sessionId: sessionIdSchema, + running: boolean() + }), + object({ + type: literal("host/agent-error"), + sessionId: sessionIdSchema, + message: string() + }), + object({ + type: literal("host/workspace-changed"), + workspace: workspaceViewSchema + }), + object({ + type: literal("host/workspace-removed"), + workspaceId: workspaceIdSchema + }), + object({ + type: literal("host/workspace-order-changed"), + workspaceIds: array(workspaceIdSchema) + }), + object({ + type: literal("host/archived-sessions-changed"), + archivedSessionIds: array(sessionIdSchema) + }), + object({ + type: literal("host/remote-event"), + event: string().min(1), + args: array(unknown()) + }), + object({ + type: literal("stream/error"), + error: rpcErrorSchema + }) + ]); + object({}); + /** host.describe response value. */ + const hostDescribeValueSchema = object({ + version: string(), + cwd: string(), + provider: string().optional(), + model: string().optional(), + attachedSessions: number().int().nonnegative(), + canOpenPath: boolean() + }); + object({}); + /** host.pickDirectory response value; null means the user cancelled. */ + const hostPickDirectoryValueSchema = object({ path: string().nullable() }); + /** Directory row shared by listing entries and breadcrumb crumbs. */ + const directoryEntrySchema = object({ + name: string(), + path: string(), + hidden: boolean() + }); + object({ path: string().optional() }); + /** host.listDirectory response value. */ + const hostListDirectoryValueSchema = object({ + path: string(), + home: string(), + crumbs: array(directoryEntrySchema), + entries: array(directoryEntrySchema), + truncated: boolean() + }); + object({ + path: string(), + name: string() + }).refine((payload) => payload.name.trim() !== "" && payload.name !== "." && payload.name !== ".." && !/[/\\]/.test(payload.name), { message: "host.createDirectory requires a single non-blank path segment name" }); + /** host.createDirectory response value: the created directory's absolute path. */ + const hostCreateDirectoryValueSchema = object({ path: string() }); + object({ path: string().min(1) }); + /** host.openPath response value. */ + const hostOpenPathValueSchema = object({ opened: literal(true) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/skills.schema.js + /** + * skills domain zod schemas (names derived from map keys: skillListRequestSchema / + * skillListValueSchema). + */ + /** SkillEntry row of skill.list. */ + const skillEntrySchema = object({ + name: string().min(1), + description: string(), + whenToUse: string().optional(), + modelInvocable: boolean() + }); + object({ sessionId: sessionIdSchema }); + /** skill.list response value. */ + const skillListValueSchema = object({ skills: array(skillEntrySchema) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/agent-presets.schema.js + /** + * agent-presets domain zod schemas (names derived from map keys: + * agentPresetListRequestSchema / agentPresetListValueSchema). + */ + /** AgentPresetEntry row of agentPreset.list. */ + const agentPresetEntrySchema = object({ + id: string().min(1), + trust: union([literal("system"), literal("user")]), + isDefault: boolean(), + name: string().optional(), + description: string().optional(), + broken: string().min(1).optional() + }); + object({}); + /** agentPreset.list response value. */ + const agentPresetListValueSchema = object({ + presets: array(agentPresetEntrySchema), + authorable: boolean(), + hasDocument: boolean() + }); + object({ + sessionId: sessionIdSchema, + agentPreset: string().min(1) + }); + /** agentPreset.select response value. */ + const agentPresetSelectValueSchema = object({ agentPreset: string() }); + object({ agentPreset: string().min(1) }); + /** agentPreset.read response value. */ + const agentPresetReadValueSchema = object({ + agentPreset: string(), + trust: union([literal("system"), literal("user")]), + content: string(), + name: string().optional(), + description: string().optional() + }); + object({ + from: string().min(1), + agentPreset: string().min(1), + name: string().optional() + }); + /** agentPreset.copy response value. */ + const agentPresetCopyValueSchema = object({ agentPreset: string() }); + object({ agentPreset: string().min(1) }); + /** agentPreset.openDocument response value. */ + const agentPresetOpenDocumentValueSchema = union([object({ opened: literal(true) }), object({ + opened: literal(false), + path: string() + })]); + object({ agentPreset: string().min(1) }); + /** agentPreset.remove response value. */ + const agentPresetRemoveValueSchema = object({}); + //#endregion + //#region ../../host/apiproxy/lib/types/api/goals.schema.js + /** + * goals domain zod schemas. Mutation-only shapes: every value schema is a + * `{ ref }` acknowledgement (clear: `{ cleared }`) — the current goal state + * travels exclusively on the 'goal' session projection. + */ + /** GoalRef schema. */ + const goalRefSchema = object({ + id: string(), + revision: number().int().positive() + }); + /** Shared `{ ref }` acknowledgement value of every non-clear mutation. */ + const goalRefValueSchema = object({ ref: goalRefSchema }); + object({ + sessionId: string(), + objective: string().min(1), + maxGoalRounds: number().int().positive().optional() + }); + /** goal.create response value. */ + const goalCreateValueSchema = goalRefValueSchema; + object({ + sessionId: string(), + ref: goalRefSchema, + objective: string().min(1).optional(), + maxGoalRounds: number().int().positive().optional() + }).refine((value) => value.objective !== void 0 || value.maxGoalRounds !== void 0, { message: "goal.edit requires objective or maxGoalRounds" }); + /** goal.edit response value. */ + const goalEditValueSchema = goalRefValueSchema; + object({ + sessionId: string(), + ref: goalRefSchema + }); + /** goal.pause response value. */ + const goalPauseValueSchema = goalRefValueSchema; + object({ + sessionId: string(), + ref: goalRefSchema + }); + /** goal.resume response value. */ + const goalResumeValueSchema = goalRefValueSchema; + object({ + sessionId: string(), + ref: goalRefSchema + }); + /** goal.complete response value. */ + const goalCompleteValueSchema = goalRefValueSchema; + object({ + sessionId: string(), + ref: goalRefSchema + }); + /** goal.clear response value. */ + const goalClearValueSchema = object({ cleared: literal(true) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/settings.schema.js + /** + * settings domain zod schemas (names derived from map keys: settingsDescribeRequestSchema / + * settingsDescribeValueSchema / settingsUpdate* / settingsReplace*). + */ + /** One redacted secret slot. */ + const settingsSecretViewSchema = object({ + path: array(string()), + set: boolean() + }); + /** SettingsNamespaceView row of settings.describe and the write responses. */ + const settingsNamespaceViewSchema = object({ + ns: string().min(1), + schema: unknown(), + value: unknown(), + base: unknown().optional(), + user: unknown().optional(), + applies: union([literal("live"), literal("restart")]), + secrets: array(settingsSecretViewSchema), + revision: number() + }); + object({}); + /** settings.describe response value. */ + const settingsDescribeValueSchema = object({ + writable: boolean(), + hasDocument: boolean(), + namespaces: array(settingsNamespaceViewSchema) + }); + object({}); + /** settings.openDocument response value. */ + const settingsOpenDocumentValueSchema = object({ opened: literal(true) }); + object({ + ns: string().min(1), + patch: record(string(), unknown()), + expectedRevision: number().optional() + }); + /** settings.update response value: the namespace's new redacted view. */ + const settingsUpdateValueSchema = settingsNamespaceViewSchema; + object({ + ns: string().min(1), + section: record(string(), unknown()), + expectedRevision: number().optional() + }); + /** One path-addressed edit of settings.mutate. */ + const settingsPathOpSchema = discriminatedUnion("op", [object({ + op: literal("set"), + path: array(string()), + value: unknown() + }), object({ + op: literal("unset"), + path: array(string()) + })]); + object({ + ns: string().min(1), + ops: array(settingsPathOpSchema), + expectedRevision: number().optional() + }); + /** settings.mutate response value: the namespace's new redacted view. */ + const settingsMutateValueSchema = settingsNamespaceViewSchema; + /** settings.replace response value. */ + const settingsReplaceValueSchema = settingsNamespaceViewSchema; + //#endregion + //#region ../../host/apiproxy/lib/types/api/credentials.schema.js + /** + * credentials domain zod schemas (names derived from map keys: + * credentialsDescribeRequestSchema / credentialsDescribeValueSchema / …). + * The reference-name pattern mirrors the seam's `credentialRef` guard so an + * invalid name fails as `bad-request` before reaching the service. + */ + /** POSIX-portable environment-variable name (the seam's `credentialRef` pattern). */ + const credentialRefNameSchema = string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/); + /** CredentialView entry of credentials.describe. */ + const credentialViewSchema = object({ + configured: boolean(), + source: string().optional(), + writable: boolean() + }); + object({ refs: array(credentialRefNameSchema).max(64) }); + /** credentials.describe response value. */ + const credentialsDescribeValueSchema = object({ credentials: record(string(), credentialViewSchema) }); + object({ + ref: credentialRefNameSchema, + value: string().min(1) + }); + /** credentials.set response value. */ + const credentialsSetValueSchema = object({}); + object({ ref: credentialRefNameSchema }); + /** credentials.unset response value. */ + const credentialsUnsetValueSchema = object({}); + //#endregion + //#region ../../host/apiproxy/lib/types/api/llm.schema.js + /** + * llm domain zod schemas (names derived from map keys: llmProvidersRequestSchema / + * llmProvidersValueSchema / llmModelsRequestSchema / llmModelsValueSchema). + */ + /** ConfigurableProviderView row of llm.providers. */ + const configurableProviderViewSchema = object({ + provider: string().min(1), + displayName: string().min(1), + settingsNs: string(), + settingsPath: array(string()), + active: boolean(), + declared: boolean().optional() + }); + object({}); + /** llm.providers response value. */ + const llmProvidersValueSchema = object({ providers: array(configurableProviderViewSchema) }); + object({}); + /** llm.models response value. */ + const llmModelsValueSchema = object({ + groups: array(modelProviderGroupSchema), + failures: array(modelCatalogFailureSchema) + }); + /** DiscoveredModelView row of llm.discoverModels. */ + const discoveredModelViewSchema = object({ + id: string().min(1), + name: string().min(1).optional(), + contextWindow: number().int().positive().optional(), + maxTokens: number().int().positive().optional() + }); + object({ + settingsNs: string().min(1), + provider: string().min(1).optional(), + baseURL: string().min(1).optional(), + api: string().min(1).optional(), + apiKey: string().min(1).optional() + }); + /** llm.discoverModels response value. */ + const llmDiscoverModelsValueSchema = object({ models: array(discoveredModelViewSchema) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/subagents.schema.js + /** Zod schemas for the browser-safe subagent domain. */ + /** Healthy and diagnostic durable catalog rows. */ + const subagentListEntrySchema = union([ + object({ + kind: literal("child"), + id: sessionIdSchema, + mode: literal("one-shot"), + activity: union([literal("running"), literal("inactive")]), + hasChildren: boolean(), + label: string().optional() + }), + object({ + kind: literal("child"), + id: sessionIdSchema, + mode: literal("continuable"), + activity: union([literal("running"), literal("inactive")]), + hasChildren: boolean(), + label: string() + }), + object({ + kind: literal("diagnostic"), + id: sessionIdSchema, + reason: union([ + literal("corrupt"), + literal("unsupported"), + literal("unavailable") + ]) + }) + ]); + object({ parentSessionId: sessionIdSchema }); + /** subagent.list response value. */ + const subagentListValueSchema = object({ + entries: array(subagentListEntrySchema), + parentAvailable: boolean() + }); + object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: union([literal("one-shot"), literal("continuable")]), + beforeSeq: number().int().nonnegative().optional(), + maxMessages: number().int().positive().optional() + }); + /** subagent.history response value. */ + const subagentHistoryValueSchema = object({ + events: array(historyEntrySchema), + hasMore: boolean(), + projections: sessionProjectionsBlockSchema.optional() + }); + object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: literal("continuable"), + content: array(contentBlockSchema), + clientTimeZone: string().optional() + }); + object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: literal("continuable") + }); + /** subagent.interrupt response value. */ + const subagentInterruptValueSchema = object({ accepted: literal(true) }); + //#endregion + //#region ../../host/apiproxy/lib/types/fetch/client.js + /** + * Client side of the fetch carrier. AbstractApiClient holds every protocol invariant: rpcId minting, + * four-quadrant envelope wrap/unwrap, zod parsing, in-process SSE frame decoding, and the payload-direct + * IApiClient domain methods (business code never mints). Platform differences ride two aspects: + * abstract doFetch (transport) + overridable onEnvelope (tap). ApiProxy (the impl face) is untouched. + */ + /** + * S→C second-level parse table: value schema by method (the response-path + * mirror of the handler's request table; key coverage compiler-enforced against RpcMethodMap). + */ + const UNARY_VALUE_SCHEMAS = { + "session.list": sessionListValueSchema, + "session.search": sessionSearchValueSchema, + "session.create": sessionCreateValueSchema, + "session.history": sessionHistoryValueSchema, + "session.models": sessionModelsValueSchema, + "session.selectModel": sessionSelectModelValueSchema, + "session.rename": sessionRenameValueSchema, + "session.fork": sessionForkValueSchema, + "session.prompt": sessionPromptValueSchema, + "session.attachment": sessionAttachmentValueSchema, + "session.updateQueue": sessionUpdateQueueValueSchema, + "session.cancel": sessionCancelValueSchema, + "subagent.list": subagentListValueSchema, + "subagent.history": subagentHistoryValueSchema, + "subagent.prompt": object({ messageId: string() }), + "subagent.interrupt": subagentInterruptValueSchema, + "host.describe": hostDescribeValueSchema, + "host.pickDirectory": hostPickDirectoryValueSchema, + "host.listDirectory": hostListDirectoryValueSchema, + "host.createDirectory": hostCreateDirectoryValueSchema, + "host.openPath": hostOpenPathValueSchema, + "workspace.list": workspaceListValueSchema, + "workspace.create": workspaceCreateValueSchema, + "workspace.rename": workspaceRenameValueSchema, + "workspace.delete": workspaceDeleteValueSchema, + "workspace.insertBefore": workspaceInsertBeforeValueSchema, + "workspace.insertSessionBefore": workspaceInsertSessionBeforeValueSchema, + "workspace.archiveSession": workspaceArchiveSessionValueSchema, + "skill.list": skillListValueSchema, + "agentPreset.list": agentPresetListValueSchema, + "agentPreset.select": agentPresetSelectValueSchema, + "agentPreset.read": agentPresetReadValueSchema, + "agentPreset.copy": agentPresetCopyValueSchema, + "agentPreset.openDocument": agentPresetOpenDocumentValueSchema, + "agentPreset.remove": agentPresetRemoveValueSchema, + "goal.create": goalCreateValueSchema, + "goal.edit": goalEditValueSchema, + "goal.pause": goalPauseValueSchema, + "goal.resume": goalResumeValueSchema, + "goal.complete": goalCompleteValueSchema, + "goal.clear": goalClearValueSchema, + "settings.describe": settingsDescribeValueSchema, + "settings.openDocument": settingsOpenDocumentValueSchema, + "settings.update": settingsUpdateValueSchema, + "settings.replace": settingsReplaceValueSchema, + "settings.mutate": settingsMutateValueSchema, + "credentials.describe": credentialsDescribeValueSchema, + "credentials.set": credentialsSetValueSchema, + "credentials.unset": credentialsUnsetValueSchema, + "llm.providers": llmProvidersValueSchema, + "llm.models": llmModelsValueSchema, + "llm.discoverModels": llmDiscoverModelsValueSchema + }; + /** Default timeout for bounded unary calls (rpc-compare 2026-07-19: a hung host must not leave callers pending forever). */ + const DEFAULT_TIMEOUT_MS = 3e4; + /** URL base for in-process handler injection (fake authority, opencode precedent). */ + const INTERNAL_BASE$1 = "http://dsh.internal"; + /** + * Abstract fetch-carrier client. Subclasses supply the transport (doFetch) and may refine the + * per-message tap (onEnvelope) — platform aspects stay in subclasses, protocol invariants stay + * here. Envelope observation is a first-class aspect of this data middle layer: the instance + * owns a microtask-batched buffer (frame storms must not cost one consumer update per frame), + * and observers subscribe via subscribeEnvelopes. The isomorphic point survives: an in-process + * subclass whose doFetch is toFetchHandler(api).fetch never touches the network. + */ + var AbstractApiClient = class { + timeoutMs; + /** Instance-owned observation buffer (module-level state would leak across instances/tests). */ + envelopeBatch = []; + flushScheduled = false; + envelopeListeners = /* @__PURE__ */ new Set(); + /** @param timeoutMs - timeout for bounded unary calls; user-paced calls and streams do not use it. */ + constructor(timeoutMs = DEFAULT_TIMEOUT_MS) { + this.timeoutMs = timeoutMs; + } + /** + * Subscribe to batched envelope observation (diagnostics/logging consumers). + * Batches follow microtask boundaries; a listener throw is isolated (observation + * must never break the carrier). + * @param listener - receives each flushed batch in arrival order. + * @returns unsubscribe function. + */ + subscribeEnvelopes(listener) { + this.envelopeListeners.add(listener); + return () => { + this.envelopeListeners.delete(listener); + }; + } + /** Per-message tap: feeds the instance buffer. Subclasses may override to observe unbatched (call super to keep batching). */ + onEnvelope(message) { + if (this.envelopeListeners.size === 0) return; + this.envelopeBatch.push(message); + if (this.flushScheduled) return; + this.flushScheduled = true; + queueMicrotask(() => { + this.flushScheduled = false; + const batch = this.envelopeBatch; + this.envelopeBatch = []; + for (const notify of this.envelopeListeners) try { + notify(batch); + } catch (error) { + console.error("[apiproxy] envelope listener threw:", error); + } + }); + } + /** Browser = same-origin (a fake authority would fail DNS on real requests); no-location env (Node) = fake authority. */ + resolveBase() { + const loc = globalThis.location; + return loc?.origin !== void 0 && loc.origin !== "null" ? loc.origin : INTERNAL_BASE$1; + } + mintRpcId() { + return RpcId(crypto.randomUUID()); + } + /** + * Shared POST leg of both C→S carriers (callUnary/respond): JSON body, + * optional default timeout merged with the caller's external signal, non-2xx → transport throw. + */ + async postJson(path, body, signal, timeoutPolicy = "default") { + const requestSignal = timeoutPolicy === "default" ? signal === void 0 ? AbortSignal.timeout(this.timeoutMs) : AbortSignal.any([AbortSignal.timeout(this.timeoutMs), signal]) : signal; + const response = await this.doFetch(new URL(path, this.resolveBase()), { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), + ...requestSignal === void 0 ? {} : { signal: requestSignal } + }); + if (!response.ok) throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + return response; + } + /** + * Unary protocol path: mint → tap → POST full form → envelope parse → verify + * echo → value parse → tap → narrow. Virtual so a fake carrier (fixture) can + * override transport at this layer. + */ + async callUnary(method, payload, signal, timeoutPolicy = "default") { + const message = { + type: "client-request", + rpcId: this.mintRpcId(), + method, + payload + }; + this.onEnvelope(message); + const response = await this.postJson(`/api/${method}`, message, signal, timeoutPolicy); + const full = serverResponseSchema.parse(await response.json()); + this.onEnvelope(full); + if (full.rpcId !== message.rpcId) throw new Error(`rpcId mismatch for ${method}: sent ${message.rpcId}, got ${full.rpcId}`); + if (!full.result.ok) return { + rpcId: full.rpcId, + result: full.result + }; + const value = UNARY_VALUE_SCHEMAS[method].parse(full.result.value); + return { + rpcId: full.rpcId, + result: { + ok: true, + value + } + }; + } + /** Mux stream opener; virtual for the same override reason as callUnary. */ + openMux(_payload, signal, onOpen) { + return this.readSse("/api/events.mux", signal, muxFrameSchema, onOpen); + } + /** Host stream opener; virtual. */ + openHost(_payload, signal, onOpen) { + return this.readSse("/api/events.host", signal, hostFrameSchema, onOpen); + } + /** + * SSE protocol path: streaming fetch (not EventSource), '\n\n' framing, ServerRequest envelope + + * frame-schema parse, tap, narrow yield. onOpen fires once the response headers are in and the + * body is readable — the stream-established signal, before any frame arrives. A frame that fails + * either parse level is reported and skipped (one corrupt frame must not kill the stream; the + * client's gap detection covers whatever the frame carried). + */ + async *readSse(path, signal, frameSchema, onOpen) { + const response = await this.doFetch(new URL(path, this.resolveBase()), { signal }); + if (!response.ok || response.body === null) throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + onOpen?.(); + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let buffer = ""; + try { + while (true) { + const { done, value } = await reader.read(); + if (done) return; + buffer += decoder.decode(value, { stream: true }); + let boundary; + while ((boundary = buffer.indexOf("\n\n")) !== -1) { + const chunk = buffer.slice(0, boundary); + buffer = buffer.slice(boundary + 2); + const data = chunk.split("\n").filter((line) => line.startsWith("data: ")).map((line) => line.slice(6)).join(""); + if (data === "") continue; + let full; + let frame; + try { + full = serverRequestSchema.parse(JSON.parse(data)); + frame = frameSchema.parse(full.payload); + } catch (error) { + console.error(`[apiproxy] dropping malformed SSE frame on ${path}:`, error); + continue; + } + this.onEnvelope(full); + yield { + rpcId: full.rpcId, + payload: frame + }; + } + } + } finally { + await reader.cancel().catch(() => void 0); + } + } + sessions = { + list: (payload, signal) => this.callUnary("session.list", payload, signal), + search: (payload, signal) => this.callUnary("session.search", payload, signal), + create: (payload, signal) => this.callUnary("session.create", payload, signal), + history: (payload, signal) => this.callUnary("session.history", payload, signal), + models: (payload, signal) => this.callUnary("session.models", payload, signal), + selectModel: (payload, signal) => this.callUnary("session.selectModel", payload, signal), + rename: (payload, signal) => this.callUnary("session.rename", payload, signal), + fork: (payload, signal) => this.callUnary("session.fork", payload, signal), + prompt: (payload, signal) => this.callUnary("session.prompt", payload, signal), + attachment: (payload, signal) => this.callUnary("session.attachment", payload, signal), + updateQueue: (payload, signal) => this.callUnary("session.updateQueue", payload, signal), + cancel: (payload, signal) => this.callUnary("session.cancel", payload, signal) + }; + subagents = { + list: (payload, signal) => this.callUnary("subagent.list", payload, signal), + history: (payload, signal) => this.callUnary("subagent.history", payload, signal), + prompt: (payload, signal) => this.callUnary("subagent.prompt", payload, signal), + interrupt: (payload, signal) => this.callUnary("subagent.interrupt", payload, signal) + }; + host = { + describe: (payload, signal) => this.callUnary("host.describe", payload, signal), + pickDirectory: (payload, signal) => this.callUnary("host.pickDirectory", payload, signal, "caller-signal-only"), + listDirectory: (payload, signal) => this.callUnary("host.listDirectory", payload, signal), + createDirectory: (payload, signal) => this.callUnary("host.createDirectory", payload, signal), + openPath: (payload, signal) => this.callUnary("host.openPath", payload, signal) + }; + workspace = { + list: (payload, signal) => this.callUnary("workspace.list", payload, signal), + create: (payload, signal) => this.callUnary("workspace.create", payload, signal), + rename: (payload, signal) => this.callUnary("workspace.rename", payload, signal), + delete: (payload, signal) => this.callUnary("workspace.delete", payload, signal), + insertBefore: (payload, signal) => this.callUnary("workspace.insertBefore", payload, signal), + insertSessionBefore: (payload, signal) => this.callUnary("workspace.insertSessionBefore", payload, signal), + archiveSession: (payload, signal) => this.callUnary("workspace.archiveSession", payload, signal) + }; + skills = { list: (payload, signal) => this.callUnary("skill.list", payload, signal) }; + agentPresets = { + list: (payload, signal) => this.callUnary("agentPreset.list", payload, signal), + select: (payload, signal) => this.callUnary("agentPreset.select", payload, signal), + read: (payload, signal) => this.callUnary("agentPreset.read", payload, signal), + copy: (payload, signal) => this.callUnary("agentPreset.copy", payload, signal), + openDocument: (payload, signal) => this.callUnary("agentPreset.openDocument", payload, signal), + remove: (payload, signal) => this.callUnary("agentPreset.remove", payload, signal) + }; + goals = { + create: (payload, signal) => this.callUnary("goal.create", payload, signal), + edit: (payload, signal) => this.callUnary("goal.edit", payload, signal), + pause: (payload, signal) => this.callUnary("goal.pause", payload, signal), + resume: (payload, signal) => this.callUnary("goal.resume", payload, signal), + complete: (payload, signal) => this.callUnary("goal.complete", payload, signal), + clear: (payload, signal) => this.callUnary("goal.clear", payload, signal) + }; + settings = { + describe: (payload, signal) => this.callUnary("settings.describe", payload, signal), + openDocument: (payload, signal) => this.callUnary("settings.openDocument", payload, signal), + update: (payload, signal) => this.callUnary("settings.update", payload, signal), + replace: (payload, signal) => this.callUnary("settings.replace", payload, signal), + mutate: (payload, signal) => this.callUnary("settings.mutate", payload, signal) + }; + credentials = { + describe: (payload, signal) => this.callUnary("credentials.describe", payload, signal), + set: (payload, signal) => this.callUnary("credentials.set", payload, signal), + unset: (payload, signal) => this.callUnary("credentials.unset", payload, signal) + }; + llm = { + providers: (payload, signal) => this.callUnary("llm.providers", payload, signal), + models: (payload, signal) => this.callUnary("llm.models", payload, signal), + discoverModels: (payload, signal) => this.callUnary("llm.discoverModels", payload, signal) + }; + events = { + mux: (payload, signal, onOpen) => this.openMux(payload, signal, onOpen), + host: (payload, signal, onOpen) => this.openHost(payload, signal, onOpen) + }; + async respond(message, signal) { + this.onEnvelope(message); + const response = await this.postJson("/api/respond", message, signal); + return rpcReceiptSchema.parse(await response.json()); + } + }; + //#endregion + //#region lib/types/client/random-uuid.js + /** Browser-safe UUID generation for client-side wire correlation. */ + /** + * Generate an RFC 4122 version 4 UUID without requiring a secure context. + * @returns a UUID backed by `crypto.getRandomValues()`, which browsers expose on insecure origins. + */ + function randomUuid() { + const bytes = globalThis.crypto.getRandomValues(new Uint8Array(16)); + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + view.setUint8(6, view.getUint8(6) & 15 | 64); + view.setUint8(8, view.getUint8(8) & 63 | 128); + const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(""); + return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`; + } + //#endregion + //#region lib/types/client/fixture.js + /** The fake carrier mints like a real one (business code never mints). */ + function rpcRequest(payload) { + return { + rpcId: RpcId(randomUuid()), + payload + }; + } + function text(t) { + return [{ + type: "text", + text: t + }]; + } + function userMessage(content, source = { kind: "user" }) { + return createUserMessage({ + content, + source + }); + } + function assistantMessage(content, model = "fx-1") { + return createAssistantMessage({ + content, + source: { + provider: "fixture", + model + } + }); + } + function toolResultMessage(callId, content, isError) { + return createToolResultMessage({ + callId: CallId(callId), + content, + isError + }); + } + const MARKDOWN_FIXTURE = [ + "# Markdown fixture", + "", + "Assistant output renders **strong text**, *emphasis*, and `inline code`.", + "", + "- first item", + " - nested item", + "", + "| Area | State |", + "| --- | --- |", + "| history | rendered |", + "| streaming | stable |", + "", + "[DeepSeek](https://www.deepseek.com)", + "", + "```ts", + "const markdown = true", + "```" + ].join("\n"); + const USER_MARKDOWN_LITERAL = "用户字面量:# 不渲染 `code` [link](https://example.com)"; + /** + * SGR wrapper for the terminal output sample below: authoring the escapes as + * `\u001b` keeps literal control bytes out of this source file. + * @param code - the SGR parameter (an ANSI color or attribute number). + * @param body - the text the attribute applies to. + * @returns the body wrapped in the attribute and a reset. + */ + function sgr(code, body) { + return `\u001b[${code}m${body}\u001b[0m`; + } + /** + * Terminal output sample for fixture turn 66, authored to carry every feature + * the terminal card draws that turn 60's two prompt rows cannot reach: + * basic-16 SGR foreground runs (green, red, bright-black) that must resolve to + * `--dsw-*` tokens, a bold run, column-aligned table rows that must scroll + * rather than fold, more than DEFAULT_TERMINAL_MAX_LINES (16) lines so the + * height cap collapses the middle. The exit status is authored separately in + * TERMINAL_EXIT_STATUS and deliberately absent from this text: the real bash + * presenter CONSUMES its `[exit code: N]` marker out of the body, because a + * terminal card shows the exit as its own pill and leaving the marker in would + * render it twice (packages/shell/tool-bash/src/render.ts). + */ + const TERMINAL_OUTPUT_FIXTURE = [ + sgr(1, "Running 4 checks"), + `${sgr(32, "✓")} typecheck 1.82s`, + `${sgr(32, "✓")} lint 0.94s`, + `${sgr(32, "✓")} duplication 2.10s`, + `${sgr(31, "✗")} unit 8.41s`, + "", + sgr(90, "packages/client/ui-primitives/tests/terminal-block.client.spec.tsx"), + ` ${sgr(31, "FAIL")} caps output at the configured line budget`, + " expected 16 lines, received 24", + "", + "NAME LINES BRANCHES FUNCTIONS UNCOVERED", + "TerminalBlock.tsx 100% 100% 100% -", + "ansi.ts 100% 100% 100% -", + "clipboard.ts 100% 100% 100% -", + "CodeBlock.tsx 98.4% 96.2% 100% 41-43", + "highlight.ts 100% 100% 100% -", + "Pill.tsx 100% 100% 100% -", + "StateDot.tsx 100% 100% 100% -", + "markdown/Markdown.tsx 100% 100% 100% -", + "", + sgr(31, "1 of 4 checks failed") + ].join("\n"); + /** + * Exit status for each terminal sample, keyed by its output text. Authored + * alongside the sample rather than parsed back out of its trailing marker, + * which is the bash tool's own job and not something to reimplement here. + */ + const TERMINAL_EXIT_STATUS = { [TERMINAL_OUTPUT_FIXTURE]: { exitCode: 1 } }; + /** + * Structured grep result for the search sample (turn 67): matches grouped by + * file, authored inline because the client-side fixture cannot import the tool + * that produces the canonical value. `truncated` with a larger `total` than the + * retained match count exercises the search card's capped indicator; the file + * with more than CHAT_SEARCH_MAX_LINES rows exercises its head/tail height cap. + */ + const SEARCH_MATCHES_FIXTURE = [ + { + path: "packages/client/ui-primitives/src/SearchBlock.tsx", + matches: [ + { + lineNumber: 16, + line: "export const DEFAULT_SEARCH_MAX_LINES = 16" + }, + { + lineNumber: 138, + line: "export function SearchBlock(props: SearchBlockProps) {" + }, + { + lineNumber: 141, + line: " const [collapsed, setCollapsed] = useState>(() => new Set())" + } + ] + }, + { + path: "packages/client/ui-tool/src/client/tool/models/search-card-model.ts", + matches: [{ + lineNumber: 45, + line: "export const CHAT_SEARCH_MAX_LINES = 8" + }, { + lineNumber: 130, + line: "export function searchCardModel(block: ToolCallBlock): SearchCardModel | null {" + }] + }, + { + path: "packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx", + matches: [ + { + lineNumber: 34, + line: "export function SearchRow({ toolName, block, inspect, t }: SearchRowProps) {" + }, + { + lineNumber: 36, + line: " const search = searchCardModel(block)" + }, + { + lineNumber: 56, + line: " search={search}" + }, + { + lineNumber: 78, + line: " yield ctx.slots.register({ name: 'tool.call.toolview', key: 'grep', locale: NS }, SearchRow)" + } + ] + } + ]; + /** + * The model-facing grep render text for the sample — what a UI without a search + * card shows, attached as the view's `content`. Mirrors the real grep + * presenter's shape (see formatGrepOutput in dsh-tool-fs-search): a + * `Found X of Y matches` header, the matches grouped under file headers with + * `Line N:` rows, then a spill-recovery footer. + */ + const SEARCH_MATCHES_TEXT = [ + "Found 9 of 42 matches", + "", + ...SEARCH_MATCHES_FIXTURE.map((file) => [file.path, ...file.matches.map((m) => `Line ${m.lineNumber}: ${m.line}`)].join("\n")), + "", + "(Full grep result stored at: fixture://spill/grep-66. Read it to see every match.)" + ].join("\n"); + /** + * Structured glob result for the search sample (turn 68): a flat path list, + * truncated with a larger `total` so the path card shows its capped indicator. + */ + const SEARCH_PATHS_FIXTURE = [ + "packages/client/ui-primitives/src/SearchBlock.tsx", + "packages/client/ui-primitives/src/SearchBlock.module.css", + "packages/client/ui-tool/src/client/tool/models/search-card-model.ts", + "packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx", + "packages/client/ui-tool/tests/search-card.client.spec.tsx" + ]; + /** + * The model-facing glob render text — the newline-joined path list plus a + * spill-recovery footer, mirroring the real glob presenter's shape (see + * formatGlobOutput in dsh-tool-fs-search). + */ + const SEARCH_PATHS_TEXT = [ + ...SEARCH_PATHS_FIXTURE, + "", + "(Showing 5 of 23 paths. Full sorted result stored at: fixture://spill/glob-67. Read it to see every path.)" + ].join("\n"); + /** + * Read-card sample for the read turn: a WINDOW past an offset, so the line + * numbers start above 1 (the card's gutter keeps the file's own numbering) and + * `totalLines` exceeds the window (the card shows a "showing N of M" note). The + * fixture is client-side and cannot import the read tool, so the structured + * window is authored inline exactly as the tool would project it through + * `presentationMeta`. `lang` is a `ts` hint so the shiki path highlights it. + */ + const READ_SAMPLE_FIRST_LINE = 41; + const READ_SAMPLE_SOURCE = [ + "export interface ReadBlockProps {", + " label?: string | undefined", + " lines: readonly ReadBlockLine[]", + " totalLines: number", + " lang?: string | undefined", + " maxLines?: number | undefined", + " className?: string | undefined", + "}", + "", + "// A windowed read keeps the file line numbers in the gutter.", + "const marker = \"fixture read sample\"" + ]; + const READ_SAMPLE_LINES = READ_SAMPLE_SOURCE.map((text, index) => ({ + number: READ_SAMPLE_FIRST_LINE + index, + text + })); + const READ_SAMPLE_PATH = "packages/client/ui-primitives/src/ReadBlock.tsx"; + const READ_SAMPLE_TOTAL = 180; + const READ_SAMPLE_TEXT = READ_SAMPLE_SOURCE.map((text, index) => `${READ_SAMPLE_FIRST_LINE + index}: ${text}`).join("\n"); + /** + * The structured `web_search` result view for the web-search turn, authored inline + * because this client-side fixture cannot import the web tool that projects it. + * The sources exercise the citation list's features: a titled source with a + * snippet and a date, a source with no title (its hostname labels the link) and + * a snippet but no date, and a source with a title and a date but no snippet. + * `truncated` marks the capped indicator. The shape is the contract's own + * search view minus its wire discriminants. + */ + const WEB_SEARCH_RESULT = { + answer: "DeepSeek Harness is a plugin-based agent harness on vendored Cordis where **every capability is a plugin**.", + sources: [ + { + url: "https://github.com/deepseek-ai/deepseek-harness", + title: "DeepSeek Harness — plugin-based agent harness", + snippet: "Everything is a plugin: session, tools, agent-loop, and LLM adapters all mount on the same Cordis context.", + publishedAt: "2026-07-01" + }, + { + url: "https://www.deepseek.com/blog/harness-architecture", + snippet: "The capability-seam pattern splits each capability into interface, implementation, and consumer packages." + }, + { + url: "https://docs.deepseek.com/harness/plugins", + title: "Writing a harness plugin", + publishedAt: "2026-06-15" + } + ], + truncated: true + }; + /** The `web_fetch` result view for the web-fetch turn, authored inline for the same reason. */ + const WEB_FETCH_RESULT = { + url: "https://www.deepseek.com/blog/harness-architecture", + statusCode: 200, + truncated: false + }; + const DEEPSEEK_REASONING = { + efforts: [ + { + id: "off", + name: "Off" + }, + { + id: "high", + name: "High" + }, + { + id: "max", + name: "Max" + } + ], + defaultEffort: "high" + }; + const OPENAI_REASONING = { + efforts: [ + { + id: "off", + name: "Off" + }, + { + id: "medium", + name: "Medium" + }, + { + id: "high", + name: "High" + }, + { + id: "max", + name: "Max" + } + ], + defaultEffort: "medium" + }; + /** Catalog served by `session.models` and `llm.models` alike (fresh copies per call). */ + function fixtureModelGroups() { + return [{ + id: "deepseek-official", + name: "DeepSeek", + models: [{ + id: "deepseek-v4-flash", + name: "DeepSeek-V4-Flash", + description: "快速响应", + reasoning: DEEPSEEK_REASONING + }, { + id: "deepseek-v4-pro", + name: "DeepSeek-V4-Pro", + description: "复杂任务", + reasoning: DEEPSEEK_REASONING + }] + }, { + id: "openai", + name: "OpenAI", + models: [{ + id: "gpt-5", + name: "GPT-5", + reasoning: OPENAI_REASONING + }] + }]; + } + function sid(id) { + return id; + } + const FIXTURE_IMAGE_DATA = "iVBORw0KGgoAAAANSUhEUgAAAKAAAABaCAYAAAA/xl1SAAAAvklEQVR42u3SMQ0AAAjAMIyhELM4AAe8PD1qYFlk9cCXEAEDYkAwIAYEA2JAMCAGBANiQDAgBgQDYkAwIAYEA2JAMCAGBANiQDAgBgQDYkAwIAYEA2JAMCAGxIBCYEAMCAbEgGBADAgGxIBgQAwIBsSAYEAMCAbEgGBADAgGxIBgQAwIBsSAYEAMCAbEgGBADAgGxIAYEAyIAcGAGBAMiAHBgBgQDIgBwYAYEAyIAcGAGBAMiAHBgBgQDIgB4bYWLb6pnOb1xAAAAABJRU5ErkJggg=="; + const FIXTURE_IMAGE_REF = { + attachmentId: "fixture:image", + mediaType: "image/png", + bytes: 247, + width: 160, + height: 90, + name: "fixture-image.png" + }; + /** Deterministic provider billing attached to fixture assistant messages. */ + function fixtureUsage(turn, step) { + return { + inputTokens: 20 + turn % 5, + outputTokens: 8 + step, + cacheReadTokens: turn === 0 ? 0 : 80, + cacheWriteTokens: turn % 10 === 0 ? 4 : 0 + }; + } + /** fx-alpha history script: 75 turns (~150+ messages -> 4 pages at PAGE_MESSAGES=50), + * mixing reasoning blocks / tool call+result / context. */ + function buildAlphaLog() { + const events = []; + let time = Date.now() - 36e5; + const push = (e) => { + const seq = events.length; + const data = e["data"]; + const authored = e["type"] === "assistant/message" && data !== void 0 ? { + ...e, + data: { + ...data, + usage: fixtureUsage(data["turn"], data["step"]) + } + } : e; + events.push({ + seq, + time: time += 800, + ...authored + }); + return seq; + }; + push({ + type: "request/context", + data: { + provider: "deepseek-official", + model: "deepseek-v4-flash", + contextWindow: 128e3 + } + }); + for (let turn = 0; turn < 60; turn++) { + push({ + type: "turn/start", + data: { turn } + }); + const userSeq = push({ + type: "user/message", + surfaceOp: "append", + data: userMessage(text(turn === 59 ? USER_MARKDOWN_LITERAL : `问题 ${turn}:fixture 历史消息,用于翻页与渲染验收。`)) + }); + if (turn === 0) push({ + type: "session/title", + data: { + title: "Fixture 历史会话", + messageSeqs: [userSeq], + source: { kind: "fallback" } + } + }); + if (turn % 9 === 4) push({ + type: "user/message", + surfaceOp: "append", + data: userMessage(text(`[fixture] 上下文注入(turn ${turn})`), { + kind: "plugin", + plugin: "fixture" + }) + }); + push({ + type: "step/start", + data: { + turn, + step: 0 + } + }); + const withTool = turn % 5 === 2; + const withReasoning = turn % 3 === 1; + const blocks = []; + if (withReasoning) blocks.push({ + type: "reasoning", + text: `思考过程 ${turn}:这是一段可折叠的 reasoning 内容。` + }); + blocks.push({ + type: "text", + text: turn === 59 ? MARKDOWN_FIXTURE : `回答 ${turn}:这是 fixture 生成的历史回复正文。` + }); + if (withTool) { + const callId = `fx-call-${turn}`; + blocks.push({ + type: "tool-call", + id: callId, + name: "echo", + arguments: `{"text":"turn ${turn}"}` + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step: 0, + message: assistantMessage(blocks) + } + }); + push({ + type: "tool/call", + data: { + turn, + step: 0, + callId, + name: "echo", + arguments: `{"text":"turn ${turn}"}` + } + }); + push({ + type: "tool/result", + surfaceOp: "append", + data: { + turn, + step: 0, + message: toolResultMessage(callId, text(`ECHO: TURN ${turn}`), turn % 25 === 12) + } + }); + push({ + type: "step/end", + data: { + turn, + step: 0 + } + }); + push({ + type: "step/start", + data: { + turn, + step: 1 + } + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step: 1, + message: assistantMessage(text(`工具结果已消化(turn ${turn})。`)) + } + }); + push({ + type: "step/end", + data: { + turn, + step: 1 + } + }); + } else { + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step: 0, + message: assistantMessage(blocks) + } + }); + push({ + type: "step/end", + data: { + turn, + step: 0 + } + }); + } + push({ + type: "turn/end", + data: { + turn, + reason: { kind: "completed" } + } + }); + } + const toolTurn = (turn, name, args, resultText) => { + const callId = `fx-call-${turn}`; + push({ + type: "turn/start", + data: { turn } + }); + push({ + type: "user/message", + surfaceOp: "append", + data: userMessage(text(`问题 ${turn}:${name} 样本。`)) + }); + push({ + type: "step/start", + data: { + turn, + step: 0 + } + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step: 0, + message: assistantMessage([{ + type: "tool-call", + id: callId, + name, + arguments: args + }]) + } + }); + push({ + type: "tool/call", + data: { + turn, + step: 0, + callId, + name, + arguments: args + } + }); + push({ + type: "tool/result", + surfaceOp: "append", + data: { + turn, + step: 0, + message: toolResultMessage(callId, text(resultText), false) + } + }); + push({ + type: "step/end", + data: { + turn, + step: 0 + } + }); + push({ + type: "turn/end", + data: { + turn, + reason: { kind: "completed" } + } + }); + }; + toolTurn(60, "fx-bash", "{\"command\":\"ls -la\\necho done\",\"cwd\":\"/tmp/fixture\"}", "total 2\ndrwxr-xr-x fixture\n-rw-r--r-- demo.txt"); + toolTurn(61, "fx-write", "{\"path\":\"notes/demo.txt\",\"content\":\"hello fixture\\n\"}", "wrote notes/demo.txt"); + toolTurn(62, "edit", "{\"file_path\":\"notes/demo.txt\",\"old_string\":\"hello\",\"new_string\":\"hello fixture\"}", "已编辑"); + toolTurn(63, "write", "{\"file_path\":\"notes/new-demo.txt\",\"content\":\"hello fixture\\n\"}", "已写入"); + toolTurn(64, "edit", "{\"file_path\":\"src/config.ts\",\"old_string\":\"const timeout = 30\",\"new_string\":\"const timeout = 60\"}", "已编辑"); + { + const turn = 65; + const callId = `fx-call-${turn}`; + const args = JSON.stringify({ + code: "const listing = await tools.bash({ command: \"ls notes\", description: \"List notes\" })\nconst demo = await tools.read({ file_path: \"notes/demo.txt\" })\nawait tools.read({ file_path: \"notes/missing.txt\" }).catch(() => \"tolerated\")\nreturn { listing, demo }", + description: "Read the notes files and summarize" + }); + push({ + type: "turn/start", + data: { turn } + }); + push({ + type: "user/message", + surfaceOp: "append", + data: userMessage(text(`问题 ${turn}:run_code 样本。`)) + }); + push({ + type: "step/start", + data: { + turn, + step: 0 + } + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step: 0, + message: assistantMessage([{ + type: "tool-call", + id: callId, + name: "run_code", + arguments: args + }]) + } + }); + push({ + type: "tool/call", + data: { + turn, + step: 0, + callId, + name: "run_code", + arguments: args + } + }); + const dispatchPair = (n, name, dispatchArgs, resultText, isError = false) => { + push({ + type: "tool/code-dispatch-start", + data: { + rootCallId: callId, + parentCallId: callId, + subCallId: `${callId}:code:${n}`, + name, + arguments: dispatchArgs + } + }); + push({ + type: "tool/code-dispatch", + data: { + rootCallId: callId, + parentCallId: callId, + subCallId: `${callId}:code:${n}`, + name, + arguments: dispatchArgs, + isError, + content: [{ + type: "text", + text: resultText + }] + } + }); + }; + dispatchPair(1, "bash", { + command: "ls notes", + description: "List notes" + }, "demo.txt\nnew-demo.txt"); + dispatchPair(2, "read", { file_path: "notes/demo.txt" }, "hello fixture\n"); + dispatchPair(3, "read", { file_path: "notes/missing.txt" }, "Error: ENOENT: notes/missing.txt not found", true); + push({ + type: "tool/result", + surfaceOp: "append", + data: { + turn, + step: 0, + message: toolResultMessage(callId, text("{\"listing\":\"demo.txt\\nnew-demo.txt\",\"demo\":\"hello fixture\\n\"}"), false) + } + }); + push({ + type: "step/end", + data: { + turn, + step: 0 + } + }); + push({ + type: "turn/end", + data: { + turn, + reason: { kind: "completed" } + } + }); + } + const fixtureTodos = [ + { + content: "梳理需求", + status: "completed" + }, + { + content: "实现 fixture 样本", + status: "in_progress" + }, + { + content: "跑后台构建", + status: "in_progress" + }, + { + content: "浏览器验收", + status: "pending" + } + ]; + toolTurn(66, "bash", "{\"command\":\"pnpm run check\",\"cwd\":\"/tmp/fixture/deep/nested\"}", TERMINAL_OUTPUT_FIXTURE); + toolTurn(67, "grep", "{\"pattern\":\"SEARCH_MAX_LINES\",\"path\":\"packages/client\"}", SEARCH_MATCHES_TEXT); + toolTurn(68, "glob", "{\"pattern\":\"**/SearchBlock*\",\"path\":\"packages/client\"}", SEARCH_PATHS_TEXT); + toolTurn(69, "read", `{"file_path":${JSON.stringify(READ_SAMPLE_PATH)},"offset":${READ_SAMPLE_FIRST_LINE}}`, READ_SAMPLE_TEXT); + toolTurn(70, "web_search", "{\"query\":\"deepseek harness architecture\"}", "Search results for deepseek harness architecture."); + toolTurn(71, "web_fetch", "{\"url\":\"https://www.deepseek.com/blog/harness-architecture\"}", "# Harness architecture\n\nEverything is a plugin."); + push({ + type: "turn/start", + data: { turn: 72 } + }); + push({ + type: "user/message", + surfaceOp: "append", + data: userMessage(text("问题 72:请完整列出全部一百条条目。")) + }); + push({ + type: "step/start", + data: { + turn: 72, + step: 0 + } + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn: 72, + step: 0, + message: assistantMessage(text("条目 1:第一条。条目 2:第二条。条目 3:这一条写到一半被")) + } + }); + push({ + type: "step/end", + data: { + turn: 72, + step: 0 + } + }); + push({ + type: "turn/end", + data: { + turn: 72, + reason: { kind: "max-tokens" } + } + }); + push({ + type: "turn/start", + data: { turn: 73 } + }); + push({ + type: "user/message", + surfaceOp: "append", + data: userMessage([{ + type: "image", + attachment: FIXTURE_IMAGE_REF + }, ...text("历史用户图片")]) + }); + push({ + type: "step/start", + data: { + turn: 73, + step: 0 + } + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn: 73, + step: 0, + message: assistantMessage([...text("结构化模型图片:"), { + type: "image", + attachment: FIXTURE_IMAGE_REF + }], "fx-vision") + } + }); + push({ + type: "step/end", + data: { + turn: 73, + step: 0 + } + }); + push({ + type: "turn/end", + data: { + turn: 73, + reason: { kind: "completed" } + } + }); + toolTurn(74, "todo_write", JSON.stringify({ todos: fixtureTodos }), "Updated todo list: 1 pending, 2 in progress, 1 completed."); + const callIndex = events.length - 4; + const callTime = events[callIndex]?.time; + events.splice(callIndex + 1, 0, { + type: "todo/write", + time: callTime + 400, + data: { todos: fixtureTodos } + }); + events.forEach((e, i) => { + e.seq = i; + }); + return events; + } + /** Narrows a parsed-JSON field to string; fixture args are authored in-file, so non-strings only mean a typo here. */ + /* v8 ignore next -- the fallback arm is the same in-file-typo guard as the JSON.parse catch above. */ + const str = (value, fallback = "") => typeof value === "string" ? value : fallback; + /** Fixture presenter registry (mirrors host viewFor): pure derivation, undefined = no view. */ + function presentCall(name, argsRaw) { + let args; + try { + args = JSON.parse(argsRaw); + } catch { + /* v8 ignore next 2 -- defensive: fixture args are authored in-file as valid JSON; only an in-file typo could reach the catch. */ + return; + } + switch (name) { + case "fx-bash": + case "bash": return { + card: "terminal", + title: str(args.command), + cwd: str(args.cwd, "/tmp/fixture"), + description: "fixture 终端样本" + }; + case "fx-write": return { + card: "diff", + title: `Write ${str(args.path)}`, + diffs: [{ + path: str(args.path), + oldText: null, + newText: str(args.content) + }] + }; + case "read": return { + card: "generic", + title: `Read ${str(args.file_path)}`, + kind: "read", + locations: [{ path: str(args.file_path) }] + }; + case "edit": + if (str(args.file_path) === "src/config.ts") return { + card: "diff", + title: `Edit ${str(args.file_path)}`, + diffs: [{ + path: str(args.file_path), + oldText: "const timeout = 30", + newText: "const timeout = 60" + }, { + path: str(args.file_path), + oldText: "retries: 1", + newText: "retries: 3" + }] + }; + return { + card: "diff", + title: `Edit ${str(args.file_path)}`, + diffs: [{ + path: str(args.file_path), + oldText: str(args.old_string), + newText: str(args.new_string) + }] + }; + case "write": return { + card: "diff", + title: `Write ${str(args.file_path)}`, + diffs: [{ + path: str(args.file_path), + oldText: null, + newText: str(args.content) + }] + }; + case "grep": return { + card: "generic", + title: `Grep ${str(args.pattern)}`, + kind: "search", + rawInput: args + }; + case "glob": return { + card: "generic", + title: `Glob ${str(args.pattern)}`, + kind: "search", + rawInput: args + }; + case "web_search": return { + card: "generic", + title: `Search ${str(args.query)}`, + kind: "search", + rawInput: args + }; + case "web_fetch": return { + card: "generic", + title: `Fetch ${str(args.url)}`, + kind: "fetch", + rawInput: args + }; + default: return; + } + } + function presentResult(name, argsRaw, resultText) { + const call = presentCall(name, argsRaw); + if (call === void 0) return void 0; + if (name === "grep") return { + card: "search", + shape: "matches", + files: SEARCH_MATCHES_FIXTURE, + truncated: true, + total: 42 + }; + if (name === "glob") return { + card: "search", + shape: "paths", + paths: SEARCH_PATHS_FIXTURE, + truncated: true, + total: 23 + }; + if (name === "read") return { + card: "read", + path: READ_SAMPLE_PATH, + offset: READ_SAMPLE_FIRST_LINE, + lines: READ_SAMPLE_LINES, + totalLines: READ_SAMPLE_TOTAL, + lang: "ts", + content: text(resultText) + }; + if (name === "web_search") return { + card: "web", + kind: "search", + ...WEB_SEARCH_RESULT + }; + if (name === "web_fetch") return { + card: "web", + kind: "fetch", + ...WEB_FETCH_RESULT + }; + switch (call.card) { + case "terminal": return { + card: "terminal", + output: resultText, + ...TERMINAL_EXIT_STATUS[resultText] ?? { exitCode: 0 } + }; + case "diff": return { + card: "diff", + diffs: call.diffs + }; + case "generic": return { + card: "generic", + content: text(resultText) + }; + } + } + /** Host-side viewFor mirror: tool/call presents from its own args; tool/result back-scans the log for the paired call. */ + function viewFor(event, log) { + if (event.type === "tool/call") { + const view = presentCall(event.data.name, event.data.arguments); + return view === void 0 ? void 0 : { + for: "call", + view + }; + } + if (event.type === "tool/result") { + const callId = String(event.data.message.source.callId); + for (let i = log.length - 1; i >= 0; i--) { + const candidate = log[i]; + /* v8 ignore next -- dense-array guard: i stays within [0, log.length), + so the undefined arm needs a sparse log no code path builds. */ + if (candidate !== void 0 && candidate.type === "tool/call" && String(candidate.data.callId) === callId) { + const resultText = event.data.message.content[0].content.map((b) => b.type === "text" ? b.text : "").join(""); + const view = presentResult(candidate.data.name, candidate.data.arguments, resultText); + return view === void 0 ? void 0 : { + for: "result", + view + }; + } + } + return; + } + } + /** + * Fixture parallel of the plan unit's double-event fold: `command/run` + * records named `plan` with recorded input set the wanted target (`off` → + * false, else true); `plan/mode` commits and clears it. `wanted` is exposed + * for the prompt boundary (the fixture's step/start parallel). + */ + function foldPlan(log) { + let active = false; + let wanted = null; + for (const event of log) { + const item = event; + if (item.type === "command/run" && item.data?.["name"] === "plan") { + const args = item.data["args"]; + if (typeof args !== "string") continue; + wanted = args.trim() !== "off"; + } else if (item.type === "plan/mode") { + active = item.data?.["active"] === true; + wanted = null; + } + } + return { + active, + pending: wanted !== null && wanted !== active, + wanted + }; + } + /** The plan projection's wire view over the full log. */ + function planViewOf(log) { + const plan = foldPlan(log); + return { + active: plan.active, + pending: plan.pending + }; + } + /** Fixture parallel of the host's projection units: whole current values per key over the full log. */ + /** Fixture preset table (the host PermissionPresetService defaults). */ + const PERMISSION_PRESETS = { + "workspace-write": { + sandbox: "workspace-write", + approval: "ask", + description: "Write inside the workspace and permitted temporary directories; wider retries require approval." + }, + "danger-full-access": { + sandbox: "danger-full-access", + approval: "never", + description: "Full file access without approval prompts." + } + }; + /** Host permissions-unit parallel: fold the three knob events, derive the select over the fixture defaults. */ + function permissionSelectOf(log) { + let preset = null; + let sandbox = "workspace-write"; + let approval = "ask"; + for (const event of log) { + const item = event; + if (item.type === "permission/preset") preset = item.data["preset"]; + else if (item.type === "sandbox/mode") sandbox = item.data["mode"]; + else if (item.type === "approval/policy") approval = item.data["policy"]; + } + const matches = (spec) => spec.sandbox === sandbox && spec.approval === approval; + let currentValue = "custom"; + const folded = preset === null ? void 0 : PERMISSION_PRESETS[preset]; + if (preset !== null && folded !== void 0 && matches(folded)) currentValue = preset; + else for (const [name, spec] of Object.entries(PERMISSION_PRESETS)) if (matches(spec)) { + currentValue = name; + break; + } + return { + options: [...Object.entries(PERMISSION_PRESETS).map(([value, spec]) => ({ + value, + name: value, + description: spec.description + })), ...currentValue === "custom" ? [{ + value: "custom", + name: "Custom", + description: "Current sandbox and approval settings do not match a preset." + }] : []], + currentValue + }; + } + /** Read one provider usage sample from either durable carrier. */ + function usageSampleOf(event) { + const item = event; + const usage = item.type === "assistant/chunk" && item.data.chunk?.type === "usage" ? item.data.chunk.usage : item.type === "assistant/message" ? item.data.usage : void 0; + return usage === void 0 || item.data.turn === void 0 || item.data.step === void 0 ? void 0 : { + turn: item.data.turn, + step: item.data.step, + usage + }; + } + /** Fixture parallel of token-meter's last-sample-replacing usage projection. */ + function tokenUsageOf(log) { + const totals = { + uncachedInputTokens: 0, + outputTokens: 0, + cacheReadTokens: 0, + cacheWriteTokens: 0 + }; + let last = null; + for (const event of log) { + const sample = usageSampleOf(event); + if (sample === void 0) continue; + const buckets = { + uncachedInputTokens: sample.usage.inputTokens, + outputTokens: sample.usage.outputTokens, + cacheReadTokens: sample.usage.cacheReadTokens ?? 0, + cacheWriteTokens: sample.usage.cacheWriteTokens ?? 0 + }; + const previous = last?.turn === sample.turn && last.step === sample.step ? last.buckets : void 0; + totals.uncachedInputTokens += buckets.uncachedInputTokens - (previous?.uncachedInputTokens ?? 0); + totals.outputTokens += buckets.outputTokens - (previous?.outputTokens ?? 0); + totals.cacheReadTokens += buckets.cacheReadTokens - (previous?.cacheReadTokens ?? 0); + totals.cacheWriteTokens += buckets.cacheWriteTokens - (previous?.cacheWriteTokens ?? 0); + last = { + turn: sample.turn, + step: sample.step, + buckets + }; + } + return totals; + } + /** Fixture parallel of session-stats' whole-log counting and wall-time fold. */ + function sessionStatsOf(log) { + const value = { + turns: 0, + steps: 0, + llmMs: 0, + toolMs: 0, + ttftMs: 0, + ttftSteps: 0, + decodeMs: 0, + decodeTokens: 0 + }; + let lastTurn = null; + let openStep = null; + const pendingCalls = /* @__PURE__ */ new Map(); + for (const event of log) switch (event.type) { + case "step/start": + openStep = { + turn: event.data.turn, + step: event.data.step, + startTime: event.time, + firstTokenTime: null + }; + break; + case "assistant/chunk": + if (openStep !== null && openStep.turn === event.data.turn && openStep.step === event.data.step && openStep.firstTokenTime === null && isTokenDelta(event.data.chunk)) openStep.firstTokenTime = event.time; + break; + case "assistant/message": + if (openStep === null || openStep.turn !== event.data.turn || openStep.step !== event.data.step) break; + value.llmMs += Math.max(0, event.time - openStep.startTime); + if (openStep.firstTokenTime !== null) { + value.ttftMs += Math.max(0, openStep.firstTokenTime - openStep.startTime); + value.ttftSteps += 1; + const outputTokens = event.data.usage?.outputTokens; + if (typeof outputTokens === "number" && Number.isFinite(outputTokens) && outputTokens >= 0) { + value.decodeMs += Math.max(0, event.time - openStep.firstTokenTime); + value.decodeTokens += outputTokens; + } + } + openStep = null; + break; + case "tool/call": + pendingCalls.set(event.data.callId, event.time); + break; + case "tool/result": { + const callId = event.data.message.source.callId; + const dispatched = pendingCalls.get(callId); + if (dispatched === void 0) break; + pendingCalls.delete(callId); + value.toolMs += Math.max(0, event.time - dispatched); + break; + } + case "step/end": + if (event.data.turn !== lastTurn) { + value.turns += 1; + lastTurn = event.data.turn; + } + value.steps += 1; + openStep = null; + break; + case "turn/end": + pendingCalls.clear(); + break; + default: break; + } + return value; + } + /** Fixed token-meter heuristic constants mirrored by this client-only fixture. */ + const CHARS_PER_TOKEN = 4; + const BLOCK_OVERHEAD = 4; + const ROLE_OVERHEAD = 4; + /** Price fixture content with token-meter's fixed-density heuristic. */ + function estimateFixtureContent(blocks) { + const densityPrice = (value) => Math.ceil(value.length / CHARS_PER_TOKEN); + return blocks.reduce((tokens, block) => { + if (block.type === "text" || block.type === "reasoning") return tokens + densityPrice(block.text) + BLOCK_OVERHEAD; + if (block.type === "tool-call") return tokens + densityPrice(block.name) + densityPrice(block.arguments) + BLOCK_OVERHEAD; + if (block.type === "tool-result") return tokens + estimateFixtureContent(block.content) + BLOCK_OVERHEAD; + return tokens + densityPrice(JSON.stringify(block)) + BLOCK_OVERHEAD; + }, 0); + } + /** Fixture parallel of token-meter's heuristic context-composition projection. */ + function contextBreakdownOf(log) { + const headerEvent = log.findLast((event) => event.type === "request/header"); + const header = headerEvent === void 0 ? void 0 : headerEvent.data.header; + let messageTokens = 0; + for (const seq of foldSurface(log).nodes) { + const event = log[seq]; + if (event === void 0) continue; + const message = deriveEventMessage(event); + if (message !== null) messageTokens += estimateFixtureContent(message.content) + ROLE_OVERHEAD; + } + return { + systemTokens: header?.system === void 0 ? 0 : Math.ceil(header.system.length / CHARS_PER_TOKEN) + ROLE_OVERHEAD, + toolsTokens: header?.tools === void 0 || header.tools.length === 0 ? 0 : Math.ceil(JSON.stringify(header.tools).length / CHARS_PER_TOKEN) + BLOCK_OVERHEAD, + messageTokens + }; + } + /** Latest log-only route context, or undefined before any request ran. */ + function lastRequestContext(log) { + const event = log.findLast((item) => item.type === "request/context"); + return event === void 0 ? void 0 : event.data; + } + /** + * Fixture parallel of token-meter's request-pressure projection: the last + * provider-reported prompt size paired with the last recorded capacity. The + * two need not come from one request — see the token-meter README. The host's + * `projectedTokens` is deliberately absent: reproducing it would mean + * reimplementing the estimator client-side, and every consumer falls back to + * the bare sample, so a fixture-driven view simply lags a compaction the way + * the projection did before that field existed. + */ + function contextPressureOf(log) { + let pressureTokens; + for (const event of log) { + const sample = usageSampleOf(event); + if (sample === void 0) continue; + pressureTokens = sample.usage.inputTokens + (sample.usage.cacheReadTokens ?? 0) + (sample.usage.cacheWriteTokens ?? 0); + } + const contextWindow = lastRequestContext(log)?.contextWindow; + return { + ...pressureTokens === void 0 ? {} : { pressureTokens }, + ...contextWindow === void 0 ? {} : { contextWindow } + }; + } + function projectionValuesOf(log) { + const values = {}; + const titleEvent = log.findLast((item) => item.type === "session/title"); + if (titleEvent !== void 0) values["title"] = titleEvent.data.title; + values["todos"] = backscanTodos(log) ?? null; + values["permissions"] = permissionSelectOf(log); + values["plan"] = planViewOf(log); + values["goal"] = backscanGoal(log); + values["tokenUsage"] = tokenUsageOf(log); + values["contextPressure"] = contextPressureOf(log); + values["contextBreakdown"] = contextBreakdownOf(log); + values["sessionStats"] = sessionStatsOf(log); + values["imageLimits"] = { + maxImageBytes: 5 * 1024 * 1024, + maxImagesPerMessage: 20, + maxMessageImageBytes: 100 * 1024 * 1024, + maxImagePixels: 4e7, + mediaTypes: [ + "image/png", + "image/jpeg", + "image/webp", + "image/gif" + ] + }; + return values; + } + /** Host push-frame parallel: emit one session/projection frame per key the given event advanced. */ + function projectionFramesOf(id, log, event) { + const type = event.type; + const frames = []; + if (usageSampleOf(event) !== void 0) frames.push({ + type: "session/projection", + sessionId: id, + key: "tokenUsage", + value: tokenUsageOf(log), + seq: event.seq + }, { + type: "session/projection", + sessionId: id, + key: "contextPressure", + value: contextPressureOf(log), + seq: event.seq + }); + if (type === "request/context") frames.push({ + type: "session/projection", + sessionId: id, + key: "contextPressure", + value: contextPressureOf(log), + seq: event.seq + }); + if (type === "request/header" || type === "user/message" || type === "assistant/message" || type === "tool/result") frames.push({ + type: "session/projection", + sessionId: id, + key: "contextBreakdown", + value: contextBreakdownOf(log), + seq: event.seq + }); + if (type === "assistant/message" || type === "tool/result" || type === "step/end") frames.push({ + type: "session/projection", + sessionId: id, + key: "sessionStats", + value: sessionStatsOf(log), + seq: event.seq + }); + if (frames.length > 0) return frames; + if (type === "session/title") { + const values = projectionValuesOf(log); + /* v8 ignore next -- the advancing title event is in the log, so the key is present. */ + if (!Object.hasOwn(values, "title")) return []; + return [{ + type: "session/projection", + sessionId: id, + key: "title", + value: values["title"], + seq: event.seq + }]; + } + if (type === "goal/change") return [{ + type: "session/projection", + sessionId: id, + key: "goal", + value: backscanGoal(log), + seq: event.seq + }]; + if (type === "todo/write" || type === "turn/start") return [{ + type: "session/projection", + sessionId: id, + key: "todos", + value: backscanTodos(log) ?? null, + seq: event.seq + }]; + if (type === "permission/preset" || type === "sandbox/mode" || type === "approval/policy") return [{ + type: "session/projection", + sessionId: id, + key: "permissions", + value: permissionSelectOf(log), + seq: event.seq + }]; + const commandData = event; + if (type === "plan/mode" || type === "command/run" && commandData.data.name === "plan" && typeof commandData.data.args === "string") return [{ + type: "session/projection", + sessionId: id, + key: "plan", + value: planViewOf(log), + seq: event.seq + }]; + return []; + } + /** + * Message-boundary paging (mirrors the host's paging contract): count + * maxMessages messages + * backwards from end, cut at a turn/start boundary. + Entries carry pagination-time views + * (the host analogue computes viewFor per entry at page time). */ + function pageOf(log, beforeSeq, maxMessages) { + const end = beforeSeq === void 0 ? log.length : Math.max(0, Math.min(beforeSeq, log.length)); + let start = 0; + let messages = 0; + for (let i = end - 1; i >= 0; i--) { + const event = log[i]; + /* v8 ignore next -- dense-array guard: log seqs are array indexes, i stays within [0, end). */ + if (event === void 0) break; + if (event.type === "user/message" || event.type === "assistant/message") messages++; + if (event.type === "turn/start" && messages >= maxMessages) { + start = i; + break; + } + } + return { + events: log.slice(start, end).map((event) => { + const view = viewFor(event, log); + return view === void 0 ? { event } : { + event, + view + }; + }), + hasMore: start > 0 + }; + } + /** Fixture mirror of host session-scoped attachment authorization. */ + function logReferencesAttachment(log, attachmentId) { + const visit = (value) => { + if (Array.isArray(value)) return value.some(visit); + if (typeof value !== "object" || value === null) return false; + const record = value; + if (record.attachmentId === attachmentId) return true; + return Object.values(record).some(visit); + }; + return log.some((event) => visit(event.data)); + } + /** Fixture mirror of first-party message extraction used by session-query. */ + function searchBlockText(block) { + switch (block.type) { + case "text": return [block.text]; + case "reasoning": return []; + case "tool-call": return [block.name, block.arguments]; + case "tool-result": return block.content.flatMap(searchBlockText); + default: return []; + } + } + /** One current-surface user/assistant document, if searchable. */ + function searchEventText(event) { + const content = event.type === "user/message" ? event.data.content : event.type === "assistant/message" ? event.data.message.content : void 0; + if (content === void 0) return ""; + return content.flatMap(searchBlockText).map((part) => part.trim()).filter(Boolean).join("\n"); + } + /** + * Browser-safe approximation of SQLite FTS5 unicode61 token boundaries. + * Keeping phrase matching token-based prevents the development fixture from + * promising arbitrary within-token substring behavior that production lacks. + */ + function searchTokenSpans(value) { + const text = value.replace(/\s+/gu, " ").trim(); + const characters = Array.from(text); + const tokens = []; + let start; + let raw = ""; + const flush = (end) => { + if (start !== void 0) { + const folded = raw.normalize("NFD").replace(/\p{M}+/gu, "").toLowerCase(); + if (folded !== "") tokens.push({ + value: folded, + start, + end + }); + } + start = void 0; + raw = ""; + }; + for (let index = 0; index < characters.length; index++) { + const character = characters[index]; + const tokenBase = character.normalize("NFD").replace(/\p{M}+/gu, ""); + if (tokenBase === "") { + if (start !== void 0) raw += character; + continue; + } + if (/^[\p{L}\p{N}\p{Co}]+$/u.test(tokenBase)) { + start ??= index; + raw += character; + } else flush(index); + } + flush(characters.length); + return { + text, + tokens + }; + } + /** Count exact contiguous token-phrase occurrences and retain the first display span. */ + function phraseMatch(document, phrase) { + if (phrase.length === 0 || phrase.length > document.length) return { + count: 0, + start: 0, + end: 0 + }; + let count = 0; + let firstStart = 0; + let firstEnd = 0; + for (let start = 0; start <= document.length - phrase.length; start++) { + if (!phrase.every((token, offset) => document[start + offset]?.value === token)) continue; + count++; + if (count === 1) { + firstStart = document[start]?.start ?? 0; + firstEnd = document[start + phrase.length - 1]?.end ?? firstStart; + } + } + return { + count, + start: firstStart, + end: firstEnd + }; + } + /** Match-centered fixture excerpt, bounded by Unicode code points for the sidebar. */ + function searchSnippet(value, matchStart, matchEnd) { + const characters = Array.from(value); + if (characters.length <= 120) return value; + const boundedStart = Math.min(Math.max(0, matchStart), characters.length - 1); + const boundedEnd = Math.min(characters.length, Math.max(boundedStart + 1, matchEnd)); + const center = Math.floor((boundedStart + boundedEnd) / 2); + let start = Math.min(characters.length - 118, Math.max(0, center - Math.floor(118 / 2))); + let end = start + 118; + if (start === 0) end = 119; + else if (end === characters.length) start = characters.length - 119; + return `${start > 0 ? "…" : ""}${characters.slice(start, end).join("")}${end < characters.length ? "…" : ""}`; + } + /** Mirrors `packages/session-query/session-query-sqlite/src/index.ts`; update both together. */ + function compareSearchCandidates(a, b) { + if (a.matchCount !== b.matchCount) return b.matchCount - a.matchCount; + if (a.documentLength !== b.documentLength) return a.documentLength - b.documentLength; + if (a.time !== b.time) return b.time - a.time; + if (a.sessionId !== b.sessionId) return a.sessionId < b.sessionId ? -1 : 1; + return b.seq - a.seq; + } + /** + * Current plan projection over the full log (host parallel: latest todo/write + * with no later turn/start; a new turn retires the previous plan). + */ + function backscanTodos(log) { + for (let i = log.length - 1; i >= 0; i--) { + const event = log[i]; + if (event === void 0) continue; + if (event.type === "turn/start") return void 0; + if (event.type === "todo/write") return event.data.todos; + } + } + /** + * Current goal projection over the full log (host parallel: the GoalService + * unit's last-wins fold of goal/change whole values; clear returns null). + */ + function backscanGoal(log) { + for (let i = log.length - 1; i >= 0; i--) { + const event = log[i]; + if (event === void 0 || event.type !== "goal/change" || event.data === void 0) continue; + const change = event.data; + if (change.operation === "clear") return null; + return { + goal: change.goal, + roundsStarted: change.roundsStarted, + createdAt: change.createdAt, + updatedAt: change.updatedAt + }; + } + return null; + } + /** Inbox pump shared by both stream generators (FrameQueue pattern: ONE abort listener hung + * outside the loop — a per-iteration {once:true} listener never fires for non-final rounds and + * piles up for the stream's lifetime). breakNow force-ends the stream without the + * client's signal (timing hook: simulated connection loss). */ + var FxInbox = class { + inbox = []; + wake = null; + broken = false; + push(envelope) { + this.inbox.push(envelope); + this.wake?.(); + } + breakNow() { + this.broken = true; + this.wake?.(); + } + /** Read through a method: breakNow()/abort flip state across yields, so narrowing from the loop condition must not stick. */ + isLive(signal) { + return !signal.aborted && !this.broken; + } + async *drain(signal) { + const onAbort = () => this.wake?.(); + signal.addEventListener("abort", onAbort); + try { + while (this.isLive(signal)) { + while (this.inbox.length > 0) yield this.inbox.shift(); + if (!this.isLive(signal)) break; + await new Promise((resolve) => { + this.wake = resolve; + }); + this.wake = null; + } + } finally { + signal.removeEventListener("abort", onAbort); + } + } + }; + /** Build the fixture's legacy API and Remote RPC faces over one state graph. */ + function createFixtureWorld(options) { + const sessions = options.empty ? [] : [ + { + sessionId: sid("fx-alpha"), + updatedAt: Date.now(), + running: true, + blank: false, + cwd: "/tmp/fixture" + }, + { + sessionId: sid("fx-beta"), + updatedAt: Date.now() - 6e4, + running: false, + blank: false, + parentSessionId: sid("fx-alpha"), + cwd: "/tmp/fixture" + }, + { + sessionId: sid("fx-gamma"), + updatedAt: Date.now() - 12e4, + running: false, + blank: false, + cwd: "/tmp/fixture" + } + ]; + const logs = new Map([[sid("fx-alpha"), buildAlphaLog()]]); + const modelSelections = new Map(sessions.map((session) => [session.sessionId, { + provider: "deepseek-official", + model: "deepseek-v4-flash" + }])); + const attachments = new Map([[String(FIXTURE_IMAGE_REF.attachmentId), { + attachment: FIXTURE_IMAGE_REF, + data: FIXTURE_IMAGE_DATA + }]]); + /** Credential store double: set/unset flip the describe badge, values never read back. */ + const fixtureCredentials = new Map([["DEEPSEEK_API_KEY", true]]); + /** + * Preset compositions the fixture serves. Held as state rather than + * constants so the settings editor's save and delete are exercisable: the + * roster a GUI journey sees after writing is the text it wrote. + */ + const fixturePresets = new Map([ + ["standard", { + trust: "system", + content: "- id: tool-bash\n name: '@deepseek-ai/dsh-tool-bash'\n" + }], + ["minimal", { + trust: "system", + content: "- id: tool-web-search\n name: '@deepseek-ai/dsh-tool-web-search'\n" + }], + ["my-agent", { + trust: "user", + content: "- id: tool-read\n name: '@deepseek-ai/dsh-tool-read'\n" + }] + ]); + let fixtureDefaultPreset = "standard"; + const nextTurn = new Map([[sid("fx-alpha"), 75]]); + let nextSession = 1; + let nextRpc = 1; + let attachedSessions = options.empty ? 0 : 1; + const wid = (raw) => raw; + const fixtureEpoch = (/* @__PURE__ */ new Date(Date.now() - 3e5)).toISOString(); + const workspaces = options.empty ? [] : [{ + workspaceId: wid("fx-ws-fixture"), + path: "/tmp/fixture", + title: "fixture", + sessionIds: [ + sid("fx-alpha"), + sid("fx-beta"), + sid("fx-gamma") + ], + createdAt: fixtureEpoch, + updatedAt: fixtureEpoch + }]; + let nextWorkspace = 1; + const archivedSessionIds = []; + const FIXTURE_HOME = "/home/fixture"; + const directoryTree = new Map([ + ["/", ["home"]], + ["/home", ["fixture"]], + [FIXTURE_HOME, [ + "Documents", + "Downloads", + ".config" + ]], + [`${FIXTURE_HOME}/Documents`, [ + "project", + "deepseek-iOS", + "deepseek-android", + "deepseek-platform", + "deepseek-web", + "deepseek-harness", + "deepseek-app", + "deepseek-landing-blog" + ]] + ]); + const childrenOf = (path) => { + const known = directoryTree.get(path); + if (known !== void 0) return known; + const parent = path.slice(0, path.lastIndexOf("/")) || "/"; + const name = path.slice(path.lastIndexOf("/") + 1); + return directoryTree.get(parent)?.includes(name) === true ? [] : void 0; + }; + const crumbsOf = (path) => { + const crumbs = [{ + name: "/", + path: "/", + hidden: false + }]; + let acc = ""; + for (const segment of path.split("/").filter(Boolean)) { + acc += `/${segment}`; + crumbs.push({ + name: segment, + path: acc, + hidden: false + }); + } + return crumbs; + }; + const mint = () => RpcId(`fx-rpc-${nextRpc++}`); + /** Resident pending approval (stable rpcId: every mux open replays the same id while unanswered, matching host replay semantics). */ + const pendingApprovalRpcId = mint(); + const pendingApprovalId = "fx-approval-1"; + /** Cleared once answered through respond; replay stops and approval/resolved is broadcast. */ + let approvalPending = true; + const pendingQuestionRpcId = mint(); + let questionPending = true; + const fixtureQuestions = [ + { + id: "harness-profile", + header: "偏好", + question: "你现在更想招哪类 Agent/Harness 候选人?", + options: [ + { + label: "工程落地型 (Recommended)", + description: "更看重能直接做 runtime、tool executor、sandbox、trace 和线上问题排查。" + }, + { + label: "研究潜力型", + description: "更看重 Agent 理解、训练评测思路和长期成长空间。" + }, + { + label: "均衡型", + description: "同时要求工程能力和 Agent 认知,但可能筛选门槛更高。" + } + ] + }, + { + id: "work-mode", + header: "方式", + question: "你希望候选人优先展示哪种工作方式?", + options: [{ + label: "先做小型原型 (Recommended)", + description: "用可运行结果尽快验证关键假设。" + }, { + label: "先写完整设计", + description: "先收敛边界、协议和风险,再开始实现。" + }] + }, + { + id: "signals", + header: "信号", + question: "哪些面试信号最重要?", + detail: "按当前招聘目标选择;跳过则视为不设偏好。", + multiSelect: true, + options: [ + { label: "系统设计" }, + { label: "代码质量" }, + { label: "Agent 产品判断" } + ] + } + ]; + const muxConns = /* @__PURE__ */ new Set(); + const hostConns = /* @__PURE__ */ new Set(); + const emitMux = (frame) => { + for (const conn of muxConns) conn.push({ + rpcId: mint(), + payload: frame + }); + }; + const emitHost = (frame) => { + for (const conn of hostConns) conn.push({ + rpcId: mint(), + payload: frame + }); + }; + /** OK response echoing the caller's rpcId (contract: responses always backfill, never mint). */ + function ok(request, value) { + return Promise.resolve({ + rpcId: request.rpcId, + result: { + ok: true, + value + } + }); + } + function err(request, error) { + return Promise.resolve({ + rpcId: request.rpcId, + result: { + ok: false, + error + } + }); + } + const summaryOf = (id) => sessions.find((s) => s.sessionId === id); + /** Shared session guard for sessionId-addressed catalog routes: the error + * response when the session is unknown, undefined when it exists. */ + const requireSession = (request) => { + if (summaryOf(request.payload.sessionId) !== void 0) return void 0; + return err(request, { + code: "session-not-found", + message: `no session ${request.payload.sessionId}`, + details: { sessionId: request.payload.sessionId } + }); + }; + const setRunning = (id, running) => { + const summary = summaryOf(id); + if (summary === void 0 || summary.running === running) return; + summary.running = running; + emitHost({ + type: "host/session-status", + sessionId: id, + running + }); + }; + const logOf = (id) => { + let log = logs.get(id); + if (log === void 0) { + log = []; + logs.set(id, log); + } + return log; + }; + const append = (id, e) => { + const log = logOf(id); + const event = { + seq: log.length, + time: Date.now(), + ...e + }; + log.push(event); + const view = viewFor(event, log); + /* v8 ignore next 3 -- the view-present arm needs a live tool/call emission, + but the fixture replay produces text-only turns; view vocabulary is + exercised through the history samples (turns 60-62). */ + emitMux(view === void 0 ? { + type: "session/event", + sessionId: id, + event + } : { + type: "session/event", + sessionId: id, + event, + view + }); + for (const frame of projectionFramesOf(id, log, event)) emitMux(frame); + }; + /** Append one durable goal/change (host GoalService parallel). */ + const appendGoalChange = (id, change) => { + const log = logOf(id); + append(id, { + type: "goal/change", + data: change + }); + return backscanGoal(log); + }; + const goalFailure = (message) => ({ + ok: false, + error: { + code: "internal", + message, + details: {} + } + }); + const requireGoalSession = (id) => summaryOf(id) === void 0 ? { + ok: false, + error: { + code: "session-not-found", + message: `no session ${id}`, + details: { sessionId: id } + } + } : void 0; + /** Canonical fixture implementation of the generated Commands Remote contract. */ + const commandRemotes = { + list(id) { + const missing = requireGoalSession(id); + if (missing !== void 0) return missing; + return { + ok: true, + value: [ + { + name: "compact", + description: "fixture:压缩当前会话上下文" + }, + { + name: "echo", + description: "fixture:回显参数", + input: { hint: "text to echo" } + }, + { + name: "goal", + description: "set or view the goal for a long-running task", + input: { hint: "" } + }, + { + name: "permission", + description: "Switch the permission preset (sandbox mode + approval policy)", + input: { hint: "" } + }, + { + name: "plan", + description: "Enter or leave plan mode", + input: { hint: "[off|message]" } + } + ] + }; + }, + execute(id, line) { + const missing = requireGoalSession(id); + if (missing !== void 0) return missing; + const match = /^\/(\S+)((?:\s.*)?)$/.exec(line.trim()); + const name = match?.[1]; + const args = match?.[2] ?? ""; + if (name === "permission") { + const preset = args.trim(); + const commandId = `fx-cmd-${logOf(id).length}`; + append(id, { + type: "command/run", + data: { + commandId, + name, + args, + source: { kind: "user" } + } + }); + const spec = PERMISSION_PRESETS[preset]; + let result; + if (preset === "") result = { + kind: "success", + text: `current preset ${permissionSelectOf(logOf(id)).currentValue} (available: ${Object.keys(PERMISSION_PRESETS).join(", ")})` + }; + else if (spec === void 0) result = { + kind: "error", + text: `unknown preset "${preset}" (available: ${Object.keys(PERMISSION_PRESETS).join(", ")})` + }; + else { + if (permissionSelectOf(logOf(id)).currentValue !== preset) append(id, { + type: "permission/preset", + data: { preset } + }); + append(id, { + type: "sandbox/mode", + data: { mode: spec.sandbox } + }); + append(id, { + type: "approval/policy", + data: { policy: spec.approval } + }); + result = { + kind: "success", + text: `preset ${preset}` + }; + } + append(id, { + type: "command/done", + data: { + commandId, + ...result + } + }); + return { + ok: true, + value: { + commandId, + result + } + }; + } + if (name === "goal") { + const commandId = `fx-cmd-${logOf(id).length}`; + append(id, { + type: "command/run", + data: { + commandId, + name, + args, + source: { kind: "user" } + } + }); + const objective = args.trim(); + const current = backscanGoal(logOf(id)); + let text; + if (objective === "") text = current === null ? "No goal is set. Usage: /goal " : `Current goal: ${current.goal.objective}`; + else if (current !== null && current.goal.phase !== "complete") text = `A goal already exists (${current.goal.objective}). Clear it first.`; + else text = `Goal created: ${appendGoalChange(id, { + kind: "goal/change", + version: 1, + operation: "create", + goal: { + id: `fx-goal-${logOf(id).length}`, + revision: 1, + objective, + phase: "active", + maxGoalRounds: 256 + }, + roundsStarted: 0, + createdAt: Date.now(), + updatedAt: Date.now() + }).goal.objective}`; + const result = { + kind: "success", + text + }; + append(id, { + type: "command/done", + data: { + commandId, + ...result + } + }); + return { + ok: true, + value: { + commandId, + result + } + }; + } + const running = summaryOf(id)?.running === true; + const outcomes = { + compact: "fixture:已压缩(假动作)", + echo: args.trim(), + plan: args.trim() === "off" ? running ? "Leaving plan mode (applies from the next step)." : "Plan mode off." : running ? "Entering plan mode (applies from the next step). Use /plan off to leave." : "Plan mode on. Use /plan off to leave." + }; + const text = name === void 0 ? void 0 : outcomes[name]; + if (name === void 0 || text === void 0) return { + ok: true, + value: void 0 + }; + const commandId = `fx-cmd-${logOf(id).length}`; + append(id, { + type: "command/run", + data: { + commandId, + name, + args, + source: { kind: "user" } + } + }); + if (name === "plan" && !running) { + const plan = foldPlan(logOf(id)); + if (plan.wanted !== null && plan.wanted !== plan.active) append(id, { + type: "plan/mode", + data: { active: plan.wanted } + }); + } + const result = { + kind: "success", + ...text === "" ? {} : { text } + }; + append(id, { + type: "command/done", + data: { + commandId, + ...result + } + }); + return { + ok: true, + value: { + commandId, + result + } + }; + } + }; + const goalView = (projection) => ({ + ...projection.goal, + roundsStarted: projection.roundsStarted, + createdAt: projection.createdAt, + updatedAt: projection.updatedAt, + activation: projection.goal.phase === "active" ? "armed" : "disarmed" + }); + /** Canonical fixture implementation of the generated Goal Remote contract. */ + const goalRemotes = { + create(id, request) { + const missing = requireGoalSession(id); + if (missing !== void 0) return missing; + const current = backscanGoal(logOf(id)); + if (current !== null && current.goal.phase !== "complete") return goalFailure(`goal "${current.goal.id}" already exists`); + const now = Date.now(); + const projection = appendGoalChange(id, { + kind: "goal/change", + version: 1, + operation: "create", + goal: { + id: `fx-goal-${logOf(id).length}`, + revision: 1, + objective: request.objective, + phase: "active", + maxGoalRounds: request.maxGoalRounds ?? 256 + }, + roundsStarted: 0, + createdAt: now, + updatedAt: now + }); + return { + ok: true, + value: { ref: { + id: projection.goal.id, + revision: projection.goal.revision + } } + }; + }, + edit(id, ref, request) { + return mutateGoal(id, ref, (current) => ({ + ...current.goal, + revision: current.goal.revision + 1, + ...request.objective === void 0 ? {} : { objective: request.objective }, + ...request.maxGoalRounds === void 0 ? {} : { maxGoalRounds: request.maxGoalRounds } + })); + }, + pause(id, ref) { + return mutateGoal(id, ref, (current) => current.goal.phase === "active" ? { + ...current.goal, + revision: current.goal.revision + 1, + phase: "paused" + } : void 0); + }, + resume(id, ref) { + return mutateGoal(id, ref, (current) => current.goal.phase === "paused" || current.goal.phase === "blocked" || current.goal.phase === "active" ? { + ...current.goal, + revision: current.goal.revision + 1, + phase: "active" + } : void 0); + }, + complete(id, ref) { + return mutateGoal(id, ref, (current) => current.goal.phase === "complete" ? void 0 : { + ...current.goal, + revision: current.goal.revision + 1, + phase: "complete" + }); + }, + clear(id, ref) { + const resolved = resolveGoal(id, ref); + if (!resolved.ok) return resolved; + const current = resolved.value; + const tombstone = { + id: current.goal.id, + revision: current.goal.revision + 1 + }; + appendGoalChange(id, { + kind: "goal/change", + version: 1, + operation: "clear", + cleared: tombstone, + clearedAt: Date.now() + }); + return { + ok: true, + value: tombstone + }; + } + }; + /** Resolve one current goal revision for a canonical Remote mutation. */ + function resolveGoal(id, ref) { + const missing = requireGoalSession(id); + if (missing !== void 0) return missing; + const current = backscanGoal(logOf(id)); + if (current === null || current.goal.id !== ref.id || current.goal.revision !== ref.revision) return goalFailure("stale or missing goal revision"); + return { + ok: true, + value: current + }; + } + /** Shared CAS mutation path behind the canonical Remote verbs. */ + function mutateGoal(id, ref, next) { + const resolved = resolveGoal(id, ref); + if (!resolved.ok) return resolved; + const current = resolved.value; + const goal = next(current); + if (goal === void 0) return goalFailure(`invalid goal transition from "${current.goal.phase}"`); + return { + ok: true, + value: goalView(appendGoalChange(id, { + kind: "goal/change", + version: 1, + operation: goal.phase === current.goal.phase ? "edit" : goal.phase === "paused" ? "pause" : goal.phase === "active" ? "resume" : "complete", + goal, + roundsStarted: current.roundsStarted, + createdAt: current.createdAt, + updatedAt: Date.now() + })) + }; + } + const mapGoalResult = (result, map) => result.ok ? { + ok: true, + value: map(result.value) + } : result; + const goalRefResult = (result) => mapGoalResult(result, (view) => ({ ref: { + id: view.id, + revision: view.revision + } })); + const legacyGoalResponse = (request, result) => Promise.resolve({ + rpcId: request.rpcId, + result + }); + /** At most one in-flight replay per session; cancel clears it. */ + const replays = /* @__PURE__ */ new Map(); + /** history transit delay (timing hooks below); the page snapshot is taken at request time, like a real host. */ + let historyDelayMs = 0; + /** One-shot history failure (timing hook: a pre-disconnect history request already doomed when reconnect lands). */ + let failNextHistory = false; + /** Force-enders for currently open stream generators (timing hook: simulated connection loss). */ + const streamBreakers = /* @__PURE__ */ new Set(); + /** Retry scenarios opened by timing hooks and completed in a later browser assertion phase. */ + const retryScenarios = /* @__PURE__ */ new Map(); + /** The single opt-in browser stress producer; normal fixture journeys never start it. */ + let activeReasoningChunkStorm = null; + globalThis.__fxTiming = { + setHistoryDelay(ms) { + historyDelayMs = ms; + }, + /** Fail the NEXT history call (after its transit delay) with a transport-level throw. */ + failNextHistory() { + failNextHistory = true; + }, + /** Log append + mux emit (the normal live path). */ + appendUser(id, msg) { + append(sid(id), { + type: "user/message", + surfaceOp: "append", + data: userMessage(text(msg)) + }); + }, + /** Append a later durable title revision through the normal raw-event + control-frame path. */ + appendTitle(id, title) { + const messageSeqs = logOf(sid(id)).filter((event) => event.type === "user/message").map((event) => event.seq); + append(sid(id), { + type: "session/title", + data: { + title, + messageSeqs, + source: { + kind: "provider", + provider: "fixture" + } + } + }); + }, + /** Start an externally paced reasoning stream for the opt-in browser stress lane. */ + startReasoningChunkStorm(id, chunkCount, chunksPerInterval, intervalMs) { + if (!Number.isSafeInteger(chunkCount) || chunkCount < 1) throw new Error("fixture: reasoning chunk count must be a positive safe integer"); + if (!Number.isSafeInteger(chunksPerInterval) || chunksPerInterval < 1) throw new Error("fixture: reasoning chunks per interval must be a positive safe integer"); + if (!Number.isSafeInteger(intervalMs) || intervalMs < 1) throw new Error("fixture: reasoning interval must be a positive safe integer"); + if (activeReasoningChunkStorm?.emitting === true) throw new Error("fixture: reasoning chunk storm already running"); + const sessionId = sid(id); + const log = logOf(sessionId); + let turn = nextTurn.get(sessionId) ?? 0; + for (const event of log) { + const candidate = event.data?.turn; + if (typeof candidate === "number") turn = Math.max(turn, candidate + 1); + } + nextTurn.set(sessionId, turn + 1); + const marker = `REASONING_STRESS_COMPLETE:${String(turn)}:${String(chunkCount)}`; + const state = { + sessionId: id, + chunkCount, + chunksPerInterval, + intervalMs, + emitted: 0, + marker, + emitting: true + }; + activeReasoningChunkStorm = state; + setRunning(sessionId, true); + append(sessionId, { + type: "turn/start", + data: { + turn, + trigger: { + kind: "message", + source: { kind: "user" } + } + } + }); + append(sessionId, { + type: "user/message", + surfaceOp: "append", + data: userMessage(text(`Reasoning chunk stress: ${String(chunkCount)} chunks.`)) + }); + append(sessionId, { + type: "step/start", + data: { + turn, + step: 0 + } + }); + append(sessionId, { + type: "assistant/chunk", + data: { + turn, + step: 0, + chunk: { + type: "block-start", + index: 0, + blockType: "reasoning" + } + } + }); + const startedAt = Date.now(); + const pump = () => { + const elapsedIntervals = Math.floor((Date.now() - startedAt) / intervalMs) + 1; + const due = Math.max(state.emitted + chunksPerInterval, elapsedIntervals * chunksPerInterval); + const end = Math.min(due, chunkCount); + for (let index = state.emitted; index < end; index++) { + const chunkText = index === chunkCount - 1 ? `\n${marker}` : index % 64 === 63 ? "推理\n" : "推理"; + append(sessionId, { + type: "assistant/chunk", + data: { + turn, + step: 0, + chunk: { + type: "reasoning-delta", + index: 0, + text: chunkText + } + } + }); + } + state.emitted = end; + if (end < chunkCount) setTimeout(pump, intervalMs); + else state.emitting = false; + }; + setTimeout(pump, 0); + return marker; + }, + /** Return a copy so browser probes cannot mutate the active producer. */ + reasoningChunkStormState() { + return activeReasoningChunkStorm === null ? null : { ...activeReasoningChunkStorm }; + }, + /** Open one failed model step whose partial remains visible until llm/retry arrives. */ + beginModelRetry(id) { + const sessionId = sid(id); + const turn = nextTurn.get(sessionId) ?? 0; + nextTurn.set(sessionId, turn + 1); + retryScenarios.set(sessionId, { + turn, + stepStarted: true + }); + setRunning(sessionId, true); + append(sessionId, { + type: "turn/start", + data: { turn } + }); + append(sessionId, { + type: "user/message", + surfaceOp: "append", + data: { + content: text("请重试这个请求"), + source: { kind: "user" } + } + }); + append(sessionId, { + type: "step/start", + data: { + turn, + step: 1 + } + }); + append(sessionId, { + type: "assistant/chunk", + data: { + turn, + step: 1, + chunk: { + type: "block-start", + index: 0, + blockType: "text" + } + } + }); + append(sessionId, { + type: "assistant/chunk", + data: { + turn, + step: 1, + chunk: { + type: "text-delta", + index: 0, + text: "应撤回的半截回复" + } + } + }); + }, + /** Record one retry decision; the next attempt remains in the same step. */ + scheduleModelRetry(id, retry = 1, delayMs = 450) { + const sessionId = sid(id); + const scenario = retryScenarios.get(sessionId); + if (scenario === void 0) throw new Error(`fixture: no model retry scenario for ${id}`); + if (!scenario.stepStarted) { + append(sessionId, { + type: "assistant/chunk", + data: { + turn: scenario.turn, + step: 1, + chunk: { + type: "block-start", + index: 0, + blockType: "text" + } + } + }); + append(sessionId, { + type: "assistant/chunk", + data: { + turn: scenario.turn, + step: 1, + chunk: { + type: "text-delta", + index: 0, + text: `第 ${String(retry)} 次应撤回的回复` + } + } + }); + scenario.stepStarted = true; + } + append(sessionId, { + type: "llm/retry", + data: { + turn: scenario.turn, + step: 1, + provider: "fixture", + mode: "normal", + policyKey: "fixture-normal", + retry, + maxRetries: 2, + delayMs, + failure: { + code: "TRANSPORT", + message: "连接被重置" + } + } + }); + scenario.stepStarted = false; + }, + /** Record one retry decision, then cancel its source turn before the retry starts. */ + cancelModelRetryDuringBackoff(id, delayMs = 450) { + const sessionId = sid(id); + const scenario = retryScenarios.get(sessionId); + if (scenario === void 0) throw new Error(`fixture: no model retry scenario for ${id}`); + append(sessionId, { + type: "llm/retry", + data: { + turn: scenario.turn, + step: 1, + provider: "fixture", + mode: "normal", + policyKey: "fixture-normal", + retry: 1, + maxRetries: 2, + delayMs, + failure: { + code: "TRANSPORT", + message: "连接被重置" + } + } + }); + append(sessionId, { + type: "step/end", + data: { + turn: scenario.turn, + step: 1 + } + }); + append(sessionId, { + type: "turn/end", + data: { + turn: scenario.turn, + reason: { + kind: "aborted", + reason: { kind: "user" } + } + } + }); + retryScenarios.delete(sessionId); + setRunning(sessionId, false); + }, + /** Finish the timing-hook retry with a finalized response in the open step. */ + completeModelRetry(id) { + const sessionId = sid(id); + const scenario = retryScenarios.get(sessionId); + if (scenario === void 0) throw new Error(`fixture: no model retry scenario for ${id}`); + retryScenarios.delete(sessionId); + append(sessionId, { + type: "assistant/chunk", + data: { + turn: scenario.turn, + step: 1, + chunk: { + type: "block-start", + index: 0, + blockType: "text" + } + } + }); + append(sessionId, { + type: "assistant/message", + surfaceOp: "append", + data: { + turn: scenario.turn, + step: 1, + message: assistantMessage(text("重试后的完整回复")) + } + }); + append(sessionId, { + type: "step/end", + data: { + turn: scenario.turn, + step: 1 + } + }); + append(sessionId, { + type: "turn/end", + data: { + turn: scenario.turn, + reason: { kind: "completed" } + } + }); + setRunning(sessionId, false); + }, + /** Log append WITHOUT the mux emit: a frame lost in transit — history still serves it, the client must repull. */ + appendSilent(id, msg) { + const log = logOf(sid(id)); + log.push({ + type: "user/message", + surfaceOp: "append", + seq: log.length, + time: Date.now(), + data: userMessage(text(msg)) + }); + }, + /** End every open stream generator (client sees both streams close -> reconnect + resync path). */ + breakStreams() { + for (const breakNow of [...streamBreakers]) breakNow(); + } + }; + /** Prompt replay: chunk typewriter (80ms/frame) -> assistant/message finalize -> turn/end + running flip. */ + const startReply = (id, turn, replyText) => { + const step = 0; + append(id, { + type: "step/start", + data: { + turn, + step + } + }); + append(id, { + type: "assistant/chunk", + data: { + turn, + step, + chunk: { + type: "block-start", + index: 0, + blockType: "text" + } + } + }); + /* v8 ignore next -- the ?? arm needs a null match, but every fixture reply is non-empty. */ + const pieces = replyText.match(/[\s\S]{1,6}/gu) ?? [replyText]; + let i = 0; + const finish = (aborted) => { + replays.delete(id); + const done = pieces.slice(0, i).join(""); + append(id, { + type: "assistant/chunk", + data: { + turn, + step, + chunk: { + type: "block-end", + index: 0, + block: { + type: "text", + text: done + } + } + } + }); + append(id, { + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step, + message: assistantMessage(text(aborted ? `${done}(已中断)` : done)), + usage: fixtureUsage(turn, step) + } + }); + append(id, { + type: "step/end", + data: { + turn, + step + } + }); + append(id, { + type: "turn/end", + data: { + turn, + reason: { kind: aborted ? "cancelled" : "completed" } + } + }); + setRunning(id, false); + }; + const tick = () => { + const piece = pieces[i]; + if (piece === void 0) { + finish(false); + return; + } + i++; + append(id, { + type: "assistant/chunk", + data: { + turn, + step, + chunk: { + type: "text-delta", + index: 0, + text: piece + } + } + }); + replays.set(id, { + timer: setTimeout(tick, 80), + finish + }); + }; + replays.set(id, { + timer: setTimeout(tick, 80), + finish + }); + }; + return { + api: { + sessions: { + list: (request) => ok(request, { items: [...sessions].sort((a, b) => b.updatedAt - a.updatedAt) }), + search: (request, signal) => { + if (signal.aborted) return err(request, { + code: "cancelled", + message: "fixture session search was aborted", + details: {} + }); + const query = searchTokenSpans(request.payload.query).tokens.map((token) => token.value); + const matches = sessions.flatMap((summary) => { + const log = logs.get(summary.sessionId) ?? []; + const current = new Set(foldSurface(log).nodes); + const best = log.flatMap((event) => { + if (!current.has(event.seq)) return []; + const eventText = searchEventText(event); + const document = searchTokenSpans(eventText); + const match = phraseMatch(document.tokens, query); + if (match.count === 0) return []; + return [{ + sessionId: summary.sessionId, + seq: event.seq, + time: event.time, + text: document.text, + matchCount: match.count, + matchStart: match.start, + matchEnd: match.end, + documentLength: Array.from(eventText).length + }]; + }).sort(compareSearchCandidates)[0]; + return best === void 0 ? [] : [best]; + }).sort(compareSearchCandidates); + return ok(request, { + items: matches.slice(0, 20).map((match) => ({ + sessionId: match.sessionId, + snippet: searchSnippet(match.text, match.matchStart, match.matchEnd) + })), + hasMore: matches.length > 20 + }); + }, + create: async (request) => { + const workspace = request.payload.workspaceId === void 0 ? void 0 : workspaces.find((w) => w.workspaceId === request.payload.workspaceId); + if (request.payload.workspaceId !== void 0 && workspace === void 0) return err(request, { + code: "workspace-not-found", + message: `no workspace ${request.payload.workspaceId}`, + details: { workspaceId: request.payload.workspaceId } + }); + const cwd = workspace?.path ?? request.payload.cwd ?? "/tmp/fixture"; + const requestedId = request.payload.sessionId; + const attachWorkspace = (sessionId) => { + /* v8 ignore next -- callers enter only when a target Workspace exists. */ + if (workspace === void 0 || workspace.sessionIds.includes(sessionId)) return; + workspace.sessionIds = [sessionId, ...workspace.sessionIds]; + workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString(); + emitHost({ + type: "host/workspace-changed", + workspace: { ...workspace } + }); + }; + const attachFailure = (sessionId, workspaceId) => err(request, { + code: "workspace-attach-failed", + message: `fixture rejected Workspace attachment for ${sessionId}`, + details: { + sessionId, + workspaceId + } + }); + if (requestedId !== void 0) { + const existing = summaryOf(requestedId); + if (existing !== void 0) { + if (existing.cwd !== cwd) return err(request, { + code: "session-conflict", + message: `session ${requestedId} already uses ${existing.cwd ?? "no cwd"}`, + details: { + sessionId: requestedId, + requestedCwd: cwd, + ...existing.cwd === void 0 ? {} : { existingCwd: existing.cwd } + } + }); + if (workspace !== void 0 && !workspace.sessionIds.includes(requestedId)) { + if (options.failWorkspaceAttach) return attachFailure(requestedId, workspace.workspaceId); + attachWorkspace(requestedId); + } + return ok(request, { sessionId: requestedId }); + } + } + const created = { + sessionId: requestedId ?? sid(`fx-${nextSession++}`), + updatedAt: Date.now(), + running: false, + blank: true, + cwd + }; + sessions.push(created); + modelSelections.set(created.sessionId, { + provider: "deepseek-official", + model: "deepseek-v4-flash" + }); + attachedSessions += 1; + const emitSession = () => { + emitHost({ + type: "host/session-added", + sessionId: created.sessionId, + blank: true, + cwd + }); + }; + if (workspace !== void 0 && options.failWorkspaceAttach) { + emitSession(); + return attachFailure(created.sessionId, workspace.workspaceId); + } + if (workspace !== void 0 && options.createFrameOrder === "workspace-first") { + attachWorkspace(created.sessionId); + emitSession(); + } else { + emitSession(); + if (workspace !== void 0) attachWorkspace(created.sessionId); + } + if (options.dropSessionCreateResponse) throw new Error("fixture: dropped session.create response after publication"); + return ok(request, { sessionId: created.sessionId }); + }, + rename: (request) => { + const missing = requireSession(request); + if (missing !== void 0) return missing; + const { sessionId, title } = request.payload; + const normalized = title.trim().replace(/\s+/g, " "); + if (normalized.length === 0) return err(request, { + code: "title-invalid", + message: "session title must contain visible characters", + details: { sessionId } + }); + append(sessionId, { + type: "session/title", + data: { + title: normalized, + messageSeqs: [], + source: { kind: "user" } + } + }); + return ok(request, { + title: normalized, + seq: logOf(sessionId).at(-1).seq + }); + }, + fork: (request) => { + const { sessionId, atSeq } = request.payload; + const source = summaryOf(sessionId); + if (source === void 0) return err(request, { + code: "session-not-found", + message: `no session ${sessionId}`, + details: { sessionId } + }); + const log = logs.get(sessionId) ?? []; + const lastSeq = log.at(-1)?.seq ?? -1; + const boundary = (atSeq === void 0 ? void 0 : log.find((e) => e.type === "turn/end" && e.seq >= atSeq)) ?? (atSeq === void 0 || atSeq > lastSeq ? log.findLast((e) => e.type === "turn/end") : void 0); + if (boundary === void 0) return err(request, { + code: "fork-unavailable", + message: atSeq !== void 0 && atSeq <= lastSeq ? `session ${sessionId} has not completed the turn containing event ${String(atSeq)}` : `session ${sessionId} has no completed turn`, + details: { sessionId } + }); + let cut = boundary.seq + 1; + while (cut < log.length && log[cut]?.type !== "turn/start") cut++; + const child = { + sessionId: sid(`fx-${nextSession++}`), + updatedAt: Date.now(), + running: false, + blank: false, + parentSessionId: sessionId, + ...source.cwd === void 0 ? {} : { cwd: source.cwd } + }; + logs.set(child.sessionId, log.slice(0, cut)); + sessions.push(child); + emitHost({ + type: "host/session-added", + sessionId: child.sessionId, + blank: false, + parentSessionId: sessionId, + ...source.cwd === void 0 ? {} : { cwd: source.cwd } + }); + const workspace = workspaces.find((w) => w.sessionIds.includes(sessionId)); + if (workspace !== void 0) { + workspace.sessionIds = [child.sessionId, ...workspace.sessionIds]; + workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString(); + emitHost({ + type: "host/workspace-changed", + workspace: { ...workspace } + }); + } + return ok(request, { sessionId: child.sessionId }); + }, + history: async (request) => { + const log = logs.get(request.payload.sessionId) ?? []; + const page = pageOf(log, request.payload.beforeSeq, request.payload.maxMessages ?? 50); + const projections = request.payload.beforeSeq === void 0 ? { + asOfSeq: log.length - 1, + values: projectionValuesOf(log) + } : void 0; + const doomed = failNextHistory; + failNextHistory = false; + const delay = historyDelayMs; + if (delay > 0) await new Promise((resolve) => setTimeout(resolve, delay)); + if (doomed) throw new Error("fixture: simulated history transport failure"); + return ok(request, { + ...page, + ...projections === void 0 ? {} : { projections } + }); + }, + models: (request) => ok(request, { + current: modelSelections.get(request.payload.sessionId) ?? { + provider: "deepseek-official", + model: "deepseek-v4-flash" + }, + routable: true, + groups: fixtureModelGroups(), + failures: [] + }), + selectModel: (request) => { + const selected = { + provider: request.payload.provider, + model: request.payload.model, + ...request.payload.reasoningEffort === void 0 ? {} : { reasoningEffort: request.payload.reasoningEffort } + }; + modelSelections.set(request.payload.sessionId, selected); + return ok(request, { selected }); + }, + prompt: (request) => { + const { sessionId: id, mode, content } = request.payload; + const summary = summaryOf(id); + if (summary === void 0) return err(request, { + code: "session-not-found", + message: `no session ${id}`, + details: { sessionId: id } + }); + if (options.rejectPrompt) return err(request, { + code: "agent-busy", + message: "fixture: prompt rejected before acceptance", + details: { reason: "fixture-prompt-rejection" } + }); + summary.updatedAt = Date.now(); + summary.blank = false; + const userText = content.map((b) => b.type === "text" ? b.text : "").join(""); + const durable = content.map((block) => { + if (block.type === "text") return block; + const attachment = { + attachmentId: `fixture:${randomUuid()}`, + mediaType: block.mediaType, + bytes: Math.max(1, Math.floor(block.data.length * 3 / 4) - (block.data.endsWith("==") ? 2 : block.data.endsWith("=") ? 1 : 0)), + width: 160, + height: 90, + ...block.name === void 0 ? {} : { name: block.name } + }; + attachments.set(String(attachment.attachmentId), { + attachment, + data: block.data + }); + return { + type: "image", + attachment + }; + }); + if (mode === "steer" && replays.has(id)) { + append(id, { + type: "user/message", + surfaceOp: "append", + data: userMessage(durable) + }); + return ok(request, { accepted: true }); + } + const turn = nextTurn.get(id) ?? 0; + nextTurn.set(id, turn + 1); + setRunning(id, true); + append(id, { + type: "turn/start", + data: { turn } + }); + const plan = foldPlan(logOf(id)); + if (plan.wanted !== null && plan.wanted !== plan.active) append(id, { + type: "plan/mode", + data: { active: plan.wanted } + }); + append(id, { + type: "user/message", + surfaceOp: "append", + data: userMessage(durable) + }); + const selection = modelSelections.get(id) ?? { + provider: "deepseek", + model: "deepseek-v4-flash" + }; + if (lastRequestContext(logOf(id))?.model !== selection.model) append(id, { + type: "request/context", + data: { + provider: selection.provider, + model: selection.model, + contextWindow: 128e3 + } + }); + startReply(id, turn, userText === "render markdown" ? MARKDOWN_FIXTURE : userText === "report model" ? (() => { + const selection = modelSelections.get(id); + return `当前模型:${selection?.provider ?? "unknown"}/${selection?.model ?? "unknown"}` + (selection?.reasoningEffort === void 0 ? "" : ` · 推理等级:${selection.reasoningEffort}`); + })() : `回声:${userText}。这是 fixture 的流式回复,用于验证打字机增长与定稿切换。`); + return ok(request, { accepted: true }); + }, + attachment: (request) => { + const stored = attachments.get(String(request.payload.attachmentId)); + if (stored === void 0) return err(request, { + code: "attachment-error", + message: "fixture attachment missing", + details: { reason: "ATTACHMENT_NOT_FOUND" } + }); + if (!logReferencesAttachment(logs.get(request.payload.sessionId) ?? [], String(request.payload.attachmentId))) return err(request, { + code: "attachment-error", + message: "fixture attachment is not referenced by this session", + details: { reason: "ATTACHMENT_NOT_REFERENCED" } + }); + return ok(request, stored); + }, + updateQueue: (request) => err(request, { + code: "queue-item-not-found", + message: "fixture has no pending queue item", + details: { itemId: request.payload.itemId } + }), + cancel: (request) => { + const replay = replays.get(request.payload.sessionId); + if (replay !== void 0) { + clearTimeout(replay.timer); + replay.finish(true); + } else setRunning(request.payload.sessionId, false); + return ok(request, { accepted: true }); + } + }, + subagents: { + list: (request) => ok(request, { + entries: [], + parentAvailable: true + }), + history: (request) => { + const log = logs.get(request.payload.childSessionId) ?? []; + return Promise.resolve(ok(request, pageOf(log, request.payload.beforeSeq, request.payload.maxMessages ?? 50))); + }, + prompt: (request) => Promise.resolve(ok(request, { messageId: `fixture-message-${request.payload.childSessionId}` })), + interrupt: (request) => Promise.resolve(ok(request, { accepted: true })) + }, + host: { + describe: (request) => ok(request, { + version: "0.0.0-fixture", + cwd: "/tmp/fixture", + attachedSessions, + canOpenPath: true + }), + pickDirectory: (request) => ok(request, { path: `${FIXTURE_HOME}/Documents/project` }), + listDirectory: (request) => { + const target = request.payload.path ?? FIXTURE_HOME; + const children = childrenOf(target); + if (children === void 0) return err(request, { + code: "directory-unreadable", + message: `cannot list ${target}: not in the fixture tree`, + details: { path: target } + }); + return ok(request, { + path: target, + home: FIXTURE_HOME, + crumbs: crumbsOf(target), + entries: [...children].sort((a, b) => a.localeCompare(b)).map((name) => ({ + name, + path: target === "/" ? `/${name}` : `${target}/${name}`, + hidden: name.startsWith(".") + })), + truncated: false + }); + }, + createDirectory: (request) => { + const parent = request.payload.path; + const children = childrenOf(parent); + if (children === void 0) return err(request, { + code: "directory-create-failed", + message: `missing parent ${parent}`, + details: { path: parent } + }); + const target = parent === "/" ? `/${request.payload.name}` : `${parent}/${request.payload.name}`; + if (children.includes(request.payload.name)) return err(request, { + code: "directory-exists", + message: `${target} already exists`, + details: { path: target } + }); + directoryTree.set(parent, [...children, request.payload.name]); + directoryTree.set(target, []); + return ok(request, { path: target }); + }, + openPath: (request) => ok(request, { opened: true }) + }, + workspace: { + list: (request) => ok(request, { + items: workspaces.map((w) => ({ ...w })), + archivedSessionIds: [...archivedSessionIds] + }), + create: (request) => { + const { path } = request.payload; + const existing = workspaces.find((w) => w.path === path); + if (existing !== void 0) return ok(request, { + workspace: { ...existing }, + created: false + }); + const now = (/* @__PURE__ */ new Date()).toISOString(); + const created = { + workspaceId: wid(`fx-ws-${nextWorkspace++}`), + path, + title: path.split("/").filter(Boolean).at(-1) ?? path, + sessionIds: [], + createdAt: now, + updatedAt: now + }; + workspaces.unshift(created); + emitHost({ + type: "host/workspace-changed", + workspace: { ...created } + }); + return ok(request, { + workspace: { ...created }, + created: true + }); + }, + rename: (request) => { + const { workspaceId, title } = request.payload; + const workspace = workspaces.find((w) => w.workspaceId === workspaceId); + if (workspace === void 0) return err(request, { + code: "workspace-not-found", + message: `no workspace ${workspaceId}`, + details: { workspaceId } + }); + const trimmed = title.trim(); + if (trimmed !== workspace.title) { + if (workspaces.some((w) => w.workspaceId !== workspaceId && w.title === trimmed)) return err(request, { + code: "workspace-name-conflict", + message: `workspace name '${trimmed}' is already in use`, + details: { name: trimmed } + }); + workspace.title = trimmed; + workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString(); + emitHost({ + type: "host/workspace-changed", + workspace: { ...workspace } + }); + } + return ok(request, { workspace: { ...workspace } }); + }, + delete: (request) => { + const { workspaceId } = request.payload; + const index = workspaces.findIndex((workspace) => workspace.workspaceId === workspaceId); + if (index === -1) return err(request, { + code: "workspace-not-found", + message: `no workspace ${workspaceId}`, + details: { workspaceId } + }); + workspaces.splice(index, 1); + emitHost({ + type: "host/workspace-removed", + workspaceId + }); + return ok(request, { deleted: true }); + }, + insertBefore: (request) => { + const { workspaceId, beforeWorkspaceId } = request.payload; + const source = workspaces.findIndex((workspace) => workspace.workspaceId === workspaceId); + const anchor = beforeWorkspaceId === void 0 ? workspaces.length : workspaces.findIndex((workspace) => workspace.workspaceId === beforeWorkspaceId); + const missing = source === -1 ? workspaceId : anchor === -1 ? beforeWorkspaceId : void 0; + if (missing !== void 0) return err(request, { + code: "workspace-not-found", + message: `no workspace ${missing}`, + details: { workspaceId: missing } + }); + if (beforeWorkspaceId !== workspaceId) { + const previousOrder = workspaces.map((candidate) => candidate.workspaceId); + const [workspace] = workspaces.splice(source, 1); + /* v8 ignore next -- source was resolved from the same array immediately above. */ + if (workspace === void 0) throw new Error(`fixture lost workspace ${workspaceId}`); + const at = beforeWorkspaceId === void 0 ? workspaces.length : workspaces.findIndex((candidate) => candidate.workspaceId === beforeWorkspaceId); + workspaces.splice(at, 0, workspace); + if (workspaces.some((candidate, index) => candidate.workspaceId !== previousOrder[index])) emitHost({ + type: "host/workspace-order-changed", + workspaceIds: workspaces.map((candidate) => candidate.workspaceId) + }); + } + return ok(request, { workspaceIds: workspaces.map((candidate) => candidate.workspaceId) }); + }, + insertSessionBefore: (request) => { + const { workspaceId, sessionId, beforeSessionId } = request.payload; + const workspace = workspaces.find((w) => w.workspaceId === workspaceId); + if (workspace === void 0) return err(request, { + code: "workspace-not-found", + message: `no workspace ${workspaceId}`, + details: { workspaceId } + }); + if (!workspace.sessionIds.includes(sessionId) || beforeSessionId !== void 0 && !workspace.sessionIds.includes(beforeSessionId)) return err(request, { + code: "workspace-move-invalid", + message: `session or anchor is not accounted by workspace ${workspaceId}`, + details: { + workspaceId, + sessionId, + ...beforeSessionId === void 0 ? {} : { beforeSessionId } + } + }); + const without = workspace.sessionIds.filter((id) => id !== sessionId); + const at = beforeSessionId === void 0 ? without.length : without.indexOf(beforeSessionId); + const sessionIds = [ + ...without.slice(0, at), + sessionId, + ...without.slice(at) + ]; + if (!sessionIds.every((id, index) => id === workspace.sessionIds[index])) { + workspace.sessionIds = sessionIds; + workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString(); + emitHost({ + type: "host/workspace-changed", + workspace: { ...workspace } + }); + } + return ok(request, { workspace: { ...workspace } }); + }, + archiveSession: (request) => { + const missing = requireSession(request); + if (missing !== void 0) return missing; + const { sessionId } = request.payload; + if (!archivedSessionIds.includes(sessionId)) { + archivedSessionIds.push(sessionId); + emitHost({ + type: "host/archived-sessions-changed", + archivedSessionIds: [...archivedSessionIds] + }); + } + return ok(request, { archivedSessionIds: [...archivedSessionIds] }); + } + }, + agentPresets: { + list: (request) => ok(request, { + presets: [...fixturePresets].map(([id, preset]) => ({ + id, + trust: preset.trust, + isDefault: id === fixtureDefaultPreset + })), + authorable: true, + hasDocument: true + }), + select: (request) => { + fixtureDefaultPreset = request.payload.agentPreset; + return ok(request, { agentPreset: request.payload.agentPreset }); + }, + read: (request) => { + const { agentPreset } = request.payload; + const preset = fixturePresets.get(agentPreset); + if (preset === void 0) return err(request, { + code: "agent-preset-not-found", + message: `unknown agent preset "${agentPreset}"`, + details: { + agentPreset, + available: [...fixturePresets.keys()] + } + }); + return ok(request, { + agentPreset, + trust: preset.trust, + content: preset.content + }); + }, + copy: (request) => { + const { from, agentPreset } = request.payload; + const source = fixturePresets.get(from); + if (source === void 0) return err(request, { + code: "agent-preset-not-found", + message: `unknown agent preset "${from}"`, + details: { + agentPreset: from, + available: [...fixturePresets.keys()] + } + }); + if (fixturePresets.has(agentPreset)) return err(request, { + code: "agent-preset-invalid", + message: `agent preset "${agentPreset}" already exists`, + details: { + agentPreset, + reason: "already exists" + } + }); + fixturePresets.set(agentPreset, { + trust: "user", + content: source.content + }); + return ok(request, { agentPreset }); + }, + openDocument: (request) => { + const { agentPreset } = request.payload; + const existing = fixturePresets.get(agentPreset); + if (existing === void 0 || existing.trust === "system") return err(request, { + code: "agent-preset-read-only", + message: `agent preset "${agentPreset}" ships with the deployment`, + details: { + agentPreset, + reason: "it ships with the deployment" + } + }); + return ok(request, { opened: true }); + }, + remove: (request) => { + const { agentPreset } = request.payload; + if (fixturePresets.get(agentPreset)?.trust === "system") return err(request, { + code: "agent-preset-read-only", + message: `agent preset "${agentPreset}" ships with the deployment`, + details: { + agentPreset, + reason: "it ships with the deployment" + } + }); + fixturePresets.delete(agentPreset); + return ok(request, {}); + } + }, + skills: { list: (request) => { + const missing = requireSession(request); + if (missing !== void 0) return missing; + return ok(request, { skills: [{ + name: "fixture-demo", + description: "fixture 技能样本", + whenToUse: "仅供 UI 目录渲染验收", + modelInvocable: true + }, { + name: "fixture-user-only", + description: "fixture 仅用户技能样本", + modelInvocable: false + }] }); + } }, + goals: { + create: (request) => legacyGoalResponse(request, mapGoalResult(goalRemotes.create(request.payload.sessionId, { + objective: request.payload.objective, + ...request.payload.maxGoalRounds === void 0 ? {} : { maxGoalRounds: request.payload.maxGoalRounds } + }), (value) => ({ ref: { + id: value.ref.id, + revision: value.ref.revision + } }))), + edit: (request) => legacyGoalResponse(request, goalRefResult(goalRemotes.edit(request.payload.sessionId, request.payload.ref, { + ...request.payload.objective === void 0 ? {} : { objective: request.payload.objective }, + ...request.payload.maxGoalRounds === void 0 ? {} : { maxGoalRounds: request.payload.maxGoalRounds } + }))), + pause: (request) => legacyGoalResponse(request, goalRefResult(goalRemotes.pause(request.payload.sessionId, request.payload.ref))), + resume: (request) => legacyGoalResponse(request, goalRefResult(goalRemotes.resume(request.payload.sessionId, request.payload.ref))), + complete: (request) => legacyGoalResponse(request, goalRefResult(goalRemotes.complete(request.payload.sessionId, request.payload.ref))), + clear: (request) => legacyGoalResponse(request, mapGoalResult(goalRemotes.clear(request.payload.sessionId, request.payload.ref), () => ({ cleared: true }))) + }, + events: { + async *mux(_request, signal) { + const conn = new FxInbox(); + muxConns.add(conn); + const breakNow = () => { + conn.breakNow(); + }; + streamBreakers.add(breakNow); + for (const s of sessions) { + if (!s.running) continue; + const log = logs.get(s.sessionId) ?? []; + conn.push({ + rpcId: mint(), + payload: { + type: "session/subscribed", + sessionId: s.sessionId, + lastSeq: log.length - 1 + } + }); + const values = projectionValuesOf(log); + for (const key of Object.keys(values)) conn.push({ + rpcId: mint(), + payload: { + type: "session/projection", + sessionId: s.sessionId, + key, + value: values[key], + seq: log.length - 1 + } + }); + } + if (approvalPending) conn.push({ + rpcId: pendingApprovalRpcId, + payload: { + type: "approval/requested", + sessionId: sid("fx-alpha"), + approvalId: pendingApprovalId, + toolName: "dangerous_tool", + reason: "fixture 常驻审批(可答:批准/拒绝后消失)" + } + }); + if (questionPending) conn.push({ + rpcId: pendingQuestionRpcId, + payload: { + type: "question/requested", + sessionId: sid("fx-alpha"), + questions: fixtureQuestions + } + }); + try { + yield* conn.drain(signal); + } finally { + streamBreakers.delete(breakNow); + muxConns.delete(conn); + } + }, + async *host(_request, signal) { + const conn = new FxInbox(); + hostConns.add(conn); + const breakNow = () => { + conn.breakNow(); + }; + streamBreakers.add(breakNow); + const timer = setInterval(() => { + const gamma = summaryOf(sid("fx-gamma")); + /* v8 ignore next -- the undefined arm needs fx-gamma deleted, but the fixture never removes sessions. */ + if (gamma !== void 0) setRunning(gamma.sessionId, !gamma.running); + }, 5e3); + try { + yield* conn.drain(signal); + } finally { + clearInterval(timer); + streamBreakers.delete(breakNow); + hostConns.delete(conn); + } + } + }, + settings: { + describe: (request) => ok(request, { + writable: true, + hasDocument: true, + namespaces: [{ + ns: "llm-deepseek", + schema: {}, + value: { apiKeyEnv: "DEEPSEEK_API_KEY" }, + applies: "live", + secrets: [{ + path: ["apiKey"], + set: false + }], + revision: 0 + }] + }), + openDocument: (request) => ok(request, { opened: true }), + update: (request) => err(request, { + code: "settings-rejected", + message: "fixture: the minimal readiness settings descriptor is read-only", + details: { ns: request.payload.ns } + }), + replace: (request) => err(request, { + code: "settings-rejected", + message: "fixture: the minimal readiness settings descriptor is read-only", + details: { ns: request.payload.ns } + }), + mutate: (request) => err(request, { + code: "settings-rejected", + message: "fixture: no settings namespaces are registered", + details: { ns: request.payload.ns } + }) + }, + credentials: { + describe: (request) => ok(request, { credentials: Object.fromEntries(request.payload.refs.map((ref) => [ref, { + configured: fixtureCredentials.has(ref), + ...fixtureCredentials.has(ref) ? { source: "file" } : {}, + writable: true + }])) }), + set: (request) => { + fixtureCredentials.set(request.payload.ref, true); + return ok(request, {}); + }, + unset: (request) => { + fixtureCredentials.delete(request.payload.ref); + return ok(request, {}); + } + }, + llm: { + providers: (request) => ok(request, { providers: [ + { + provider: "deepseek-official", + displayName: "DeepSeek", + settingsNs: "llm-deepseek", + settingsPath: [], + active: true + }, + { + provider: "openai", + displayName: "openai", + settingsNs: "llm-pi-ai", + settingsPath: ["providers", "openai"], + active: true, + declared: false + }, + { + provider: "anthropic", + displayName: "anthropic", + settingsNs: "llm-pi-ai", + settingsPath: ["providers", "anthropic"], + active: false, + declared: false + }, + { + provider: "acme-gateway", + displayName: "Acme Gateway", + settingsNs: "llm-pi-ai", + settingsPath: ["providers", "acme-gateway"], + active: true, + declared: true + } + ] }), + models: (request) => ok(request, { + groups: fixtureModelGroups(), + failures: [] + }), + discoverModels: (request) => ok(request, { models: fixtureModelGroups().flatMap((group) => group.models.map((model) => ({ + id: model.id, + name: model.name + }))) }) + }, + respond(message) { + if (message.rpcId === pendingApprovalRpcId) { + if (!approvalPending) return Promise.resolve({ + accepted: false, + reason: "not-pending" + }); + if (!message.result.ok) return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + const value = message.result.value; + if (value.approvalId !== pendingApprovalId || value.outcome !== "allowed-once" && value.outcome !== "rejected") return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + approvalPending = false; + emitMux({ + type: "approval/resolved", + sessionId: sid("fx-alpha"), + approvalId: pendingApprovalId, + outcome: value.outcome + }); + return Promise.resolve({ accepted: true }); + } + if (!questionPending || message.rpcId !== pendingQuestionRpcId) return Promise.resolve({ + accepted: false, + reason: "not-pending" + }); + questionPending = false; + emitMux({ + type: "question/resolved", + sessionId: sid("fx-alpha"), + questionRpcId: pendingQuestionRpcId, + outcome: message.result.ok ? "answered" : "cancelled" + }); + return Promise.resolve({ accepted: true }); + }, + downloads: { sessionLog: () => Promise.resolve(new Response("fixture mode does not serve session export", { status: 404 })) } + }, + rpc: { call(channel, endpoint, payload) { + if (channel !== "/api") return Promise.reject(/* @__PURE__ */ new Error(`fixture connection RPC channel ${JSON.stringify(channel)} is unavailable`)); + const args = payload.args; + const sessionId = args.agentId; + switch (endpoint) { + case "commands/list": return Promise.resolve(commandRemotes.list(sessionId)); + case "commands/execute": return Promise.resolve(commandRemotes.execute(sessionId, args.line)); + case "goals/create": return Promise.resolve(goalRemotes.create(sessionId, { + objective: args.request?.objective, + ...args.request?.maxGoalRounds === void 0 ? {} : { maxGoalRounds: args.request.maxGoalRounds } + })); + case "goals/edit": return Promise.resolve(goalRemotes.edit(sessionId, args.ref, args.request ?? {})); + case "goals/pause": return Promise.resolve(goalRemotes.pause(sessionId, args.ref)); + case "goals/resume": return Promise.resolve(goalRemotes.resume(sessionId, args.ref)); + case "goals/complete": return Promise.resolve(goalRemotes.complete(sessionId, args.ref)); + case "goals/clear": return Promise.resolve(goalRemotes.clear(sessionId, args.ref)); + default: return Promise.reject(/* @__PURE__ */ new Error(`fixture connection RPC endpoint ${JSON.stringify(endpoint)} is unavailable`)); + } + } } + }; + } + /** + * Fixture platform subclass: there is no HTTP at all, so instead of a doFetch transport it + * overrides the protocol-level virtuals (callUnary/openMux/openHost/respond) to dispatch + * straight into the in-memory ApiProxy — while still minting rpcIds, fabricating the four + * named full forms, and feeding the same tap as a real carrier. TODO: delete when the fixture + * moves to the isomorphic pipeline (InProcessApiClient over toFetchHandler(fixtureImpl)). + */ + var FixtureApiClient = class extends AbstractApiClient { + api; + /** Generic Remote caller backed by the same in-memory state as the legacy fixture API. */ + rpc; + constructor() { + super(); + const world = createFixtureWorld(fixtureOptionsFromLocation()); + this.api = world.api; + this.rpc = world.rpc; + } + doFetch() { + throw new Error("FixtureApiClient overrides all protocol paths; doFetch must be unreachable"); + } + async callUnary(method, payload, signal) { + const request = rpcRequest(payload); + const full = { + type: "client-request", + rpcId: request.rpcId, + method, + payload + }; + this.onEnvelope(full); + const response = await this.dispatch(method, request, signal ?? new AbortController().signal); + const fullResponse = { + type: "server-response", + rpcId: response.rpcId, + result: response.result + }; + this.onEnvelope(fullResponse); + return response; + } + /** Method-key dispatch into the in-memory contract impl (a real carrier routes by URL path instead). */ + dispatch(method, request, signal) { + switch (method) { + case "session.list": return this.api.sessions.list(request); + case "session.search": return this.api.sessions.search(request, signal); + case "session.create": return this.api.sessions.create(request); + case "session.history": return this.api.sessions.history(request); + case "session.models": return this.api.sessions.models(request); + case "session.selectModel": return this.api.sessions.selectModel(request); + case "session.rename": return this.api.sessions.rename(request); + case "session.fork": return this.api.sessions.fork(request); + case "session.prompt": return this.api.sessions.prompt(request); + case "session.attachment": return this.api.sessions.attachment(request); + case "session.updateQueue": return this.api.sessions.updateQueue(request); + case "session.cancel": return this.api.sessions.cancel(request); + case "subagent.list": return this.api.subagents.list(request); + case "subagent.history": return this.api.subagents.history(request); + case "subagent.prompt": return this.api.subagents.prompt(request, signal); + case "subagent.interrupt": return this.api.subagents.interrupt(request); + case "host.describe": return this.api.host.describe(request); + case "host.pickDirectory": return this.api.host.pickDirectory(request, new AbortController().signal); + case "host.listDirectory": return this.api.host.listDirectory(request, new AbortController().signal); + case "host.createDirectory": return this.api.host.createDirectory(request); + case "host.openPath": return this.api.host.openPath(request, new AbortController().signal); + case "workspace.list": return this.api.workspace.list(request); + case "workspace.create": return this.api.workspace.create(request); + case "workspace.rename": return this.api.workspace.rename(request); + case "workspace.delete": return this.api.workspace.delete(request); + case "workspace.insertBefore": return this.api.workspace.insertBefore(request); + case "workspace.insertSessionBefore": return this.api.workspace.insertSessionBefore(request); + case "workspace.archiveSession": return this.api.workspace.archiveSession(request); + case "skill.list": return this.api.skills.list(request); + case "agentPreset.list": return this.api.agentPresets.list(request); + case "agentPreset.select": return this.api.agentPresets.select(request); + case "agentPreset.read": return this.api.agentPresets.read(request); + case "agentPreset.copy": return this.api.agentPresets.copy(request); + case "agentPreset.openDocument": return this.api.agentPresets.openDocument(request, new AbortController().signal); + case "agentPreset.remove": return this.api.agentPresets.remove(request); + case "goal.create": return this.api.goals.create(request); + case "goal.edit": return this.api.goals.edit(request); + case "goal.pause": return this.api.goals.pause(request); + case "goal.resume": return this.api.goals.resume(request); + case "goal.complete": return this.api.goals.complete(request); + case "goal.clear": return this.api.goals.clear(request); + case "settings.describe": return this.api.settings.describe(request); + case "settings.openDocument": return this.api.settings.openDocument(request, signal); + case "settings.update": return this.api.settings.update(request); + case "settings.replace": return this.api.settings.replace(request); + case "settings.mutate": return this.api.settings.mutate(request); + case "credentials.describe": return this.api.credentials.describe(request); + case "credentials.set": return this.api.credentials.set(request); + case "credentials.unset": return this.api.credentials.unset(request); + case "llm.providers": return this.api.llm.providers(request); + case "llm.models": return this.api.llm.models(request); + case "llm.discoverModels": return this.api.llm.discoverModels(request, signal); + } + } + openMux(payload, signal, onOpen) { + return this.tapStream(this.api.events.mux(rpcRequest(payload), signal), onOpen); + } + openHost(payload, signal, onOpen) { + return this.tapStream(this.api.events.host(rpcRequest(payload), signal), onOpen); + } + async *tapStream(stream, onOpen) { + onOpen?.(); + for await (const envelope of stream) { + const full = { + type: "server-request", + rpcId: envelope.rpcId, + method: envelope.payload.type, + payload: envelope.payload + }; + this.onEnvelope(full); + yield envelope; + } + } + /** + * Deliver a client response to the in-memory contract impl (no HTTP POST), + * echoing the envelope to the observation tap like every other path. + * @param message - the client-response envelope answering a server request. + * @returns the carrier receipt from the fixture impl. + */ + async respond(message) { + this.onEnvelope(message); + return this.api.respond(message); + } + }; + /** Browser query mapping; direct unit callers pass FixtureOptions explicitly. */ + function fixtureOptionsFromLocation() { + if (typeof location === "undefined") return {}; + const query = new URLSearchParams(location.search); + return { + empty: query.get("fixture") === "empty", + rejectPrompt: query.get("fixturePrompt") === "reject", + failWorkspaceAttach: query.get("fixtureAttach") === "fail", + dropSessionCreateResponse: query.get("fixtureSessionCreate") === "drop-response", + createFrameOrder: query.get("fixtureFrames") === "workspace-first" ? "workspace-first" : "session-first" + }; + } + //#endregion + //#region lib/types/api-path.js + /** + * The /api URL prefix — single source for both halves of the web transport. + * The node half registers this prefix on the web server; both halves share the + * event paths below for the browser WebSocket downlinks. + */ + /** Route prefix owning every api request (`/api` and `/api/`). */ + const API_PATH = "/api"; + /** Browser mux-frame WebSocket pathname. */ + const MUX_EVENTS_PATH = `${API_PATH}/events.mux`; + /** Browser host-frame WebSocket pathname. */ + const HOST_EVENTS_PATH = `${API_PATH}/events.host`; + //#endregion + //#region lib/types/client/web-api-client.js + /** Browser API carrier: HTTP upstream plus one WebSocket per downstream event stream. */ + /** Browser platform subclass: unary/respond use fetch; mux/host use downlink-only WebSockets. */ + var WebApiClient = class extends AbstractApiClient { + doFetch(input, init) { + return globalThis.fetch(input, init); + } + openMux(_payload, signal, onOpen) { + return this.readWebSocket(MUX_EVENTS_PATH, signal, muxFrameSchema, onOpen); + } + openHost(_payload, signal, onOpen) { + return this.readWebSocket(HOST_EVENTS_PATH, signal, hostFrameSchema, onOpen); + } + async *readWebSocket(path, signal, frameSchema, onOpen) { + const url = new URL(path, this.resolveBase()); + url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; + const socket = new WebSocket(url); + const inbox = []; + let wake; + const enqueue = (item) => { + inbox.push(item); + wake?.(); + wake = void 0; + }; + const handleOpen = () => { + onOpen?.(); + }; + const handleMessage = (event) => { + let full; + let frame; + try { + if (typeof event.data !== "string") throw new Error("binary WebSocket frame"); + full = serverRequestSchema.parse(JSON.parse(event.data)); + frame = frameSchema.parse(full.payload); + } catch (error) { + console.error(`[client-connection] dropping malformed WebSocket frame on ${path}:`, error); + return; + } + this.onEnvelope(full); + enqueue({ + kind: "frame", + envelope: { + rpcId: full.rpcId, + payload: frame + } + }); + }; + const handleClose = () => { + enqueue({ kind: "end" }); + }; + const handleAbort = () => { + if (socket.readyState === WebSocket.CONNECTING || socket.readyState === WebSocket.OPEN) socket.close(); + }; + socket.addEventListener("open", handleOpen); + socket.addEventListener("message", handleMessage); + socket.addEventListener("close", handleClose, { once: true }); + signal.addEventListener("abort", handleAbort, { once: true }); + if (signal.aborted) handleAbort(); + try { + while (true) { + while (inbox.length > 0) { + const item = inbox.shift(); + if (item.kind === "end") return; + yield item.envelope; + } + await new Promise((resolve) => { + wake = resolve; + }); + } + } finally { + signal.removeEventListener("abort", handleAbort); + socket.removeEventListener("open", handleOpen); + socket.removeEventListener("message", handleMessage); + socket.removeEventListener("close", handleClose); + handleAbort(); + } + } + }; + //#endregion + //#region lib/types/client/rpc.js + /** Browser caller for generic Connection unary RPC channels. */ + const INTERNAL_BASE = "http://dsh.internal"; + const CHANNEL_PATTERN = /^\/[A-Za-z0-9._~-]+$/; + const ENDPOINT_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/; + /** + * Create the browser-backed generic RPC caller. + * @returns caller that owns request correlation and response-envelope validation. + */ + function createWebConnectionRpc() { + return { async call(channel, endpoint, payload, signal) { + assertTarget(channel, endpoint); + const rpcId = RpcId(randomUuid()); + const message = { + type: "client-request", + rpcId, + method: endpoint, + payload + }; + const response = await globalThis.fetch(new URL(`${channel}/${endpoint}`, resolveBase()), { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(message), + ...signal === void 0 ? {} : { signal } + }); + if (!response.ok) throw new Error(`transport failure for ${channel}/${endpoint}: HTTP ${response.status}`); + const full = serverResponseSchema.parse(await response.json()); + if (full.rpcId !== rpcId) throw new Error(`rpcId mismatch for ${endpoint}: sent ${rpcId}, got ${full.rpcId}`); + return full.result; + } }; + } + function resolveBase() { + const location = globalThis.location; + return location?.origin !== void 0 && location.origin !== "null" ? location.origin : INTERNAL_BASE; + } + function assertTarget(channel, endpoint) { + const segments = endpoint.split("/"); + if (!CHANNEL_PATTERN.test(channel) || segments.some((segment) => segment === "" || segment === "." || segment === ".." || !ENDPOINT_SEGMENT_PATTERN.test(segment))) throw new Error(`connection: invalid RPC target ${JSON.stringify(`${channel}/${endpoint}`)}`); + } + //#endregion + //#region lib/types/loopback-hostname.js + /** + * Browser-safe, zero-dependency loopback classification shared by the `/api` + * Host fence and the package's `ctx.connection` state. The predicate stays + * package-internal; client plugins consume the derived state through Cordis. + */ + /** + * Whether a normalized URL hostname names the local loopback authority. + * @param hostname - WHATWG URL hostname (IPv6 literals retain brackets). + * @returns true for localhost, IPv6 loopback, or any IPv4 address in 127/8. + */ + function isLoopbackHostname(hostname) { + if (hostname === "localhost" || hostname === "[::1]") return true; + const parts = hostname.split("."); + return parts.length === 4 && parts[0] === "127" && parts.every((part) => /^\d{1,3}$/.test(part) && Number(part) <= 255); + } + //#endregion + //#region lib/types/client/index.js + /** Required services (none — this is the wire root). */ + const inject = []; + /** + * Client plugin body: pick the api by page mode and provide ctx.connection. + * @param ctx - client cordis context. + */ + function apply(ctx) { + const pageLocation = typeof location === "undefined" ? void 0 : location; + const fixtureClient = pageLocation !== void 0 && new URLSearchParams(pageLocation.search).has("fixture") ? new FixtureApiClient() : void 0; + const api = fixtureClient ?? new WebApiClient(); + const rpc = fixtureClient?.rpc ?? createWebConnectionRpc(); + let started = false; + let description; + const descriptionListeners = /* @__PURE__ */ new Set(); + const publishDescription = (next) => { + if (Object.is(description, next)) return; + description = next; + for (const listener of [...descriptionListeners]) try { + listener(); + } catch (error) { + console.error("[web-runtime] host-description listener threw:", error); + } + }; + const handle = { + api, + isLoopback: pageLocation === void 0 || isLoopbackHostname(pageLocation.hostname), + hostDescription: { + getSnapshot: () => description, + subscribe: (listener) => { + descriptionListeners.add(listener); + return () => { + descriptionListeners.delete(listener); + }; + } + }, + rpc, + start(sinks, config) { + if (started) throw new Error("connection: the stream loop is already owned by another consumer"); + started = true; + const controller = new ConnectionController(api, { + ...sinks, + onConnected: (next) => { + publishDescription(next); + if (!Object.is(description, next)) return; + sinks.onConnected?.(next); + }, + onStateChange: (state) => { + if (state === "reconnecting") publishDescription(void 0); + sinks.onStateChange?.(state); + } + }, config ?? {}); + controller.start(); + return { stop: () => { + controller.stop(); + publishDescription(void 0); + } }; + } + }; + ctx.provide("connection", handle); + } + //#endregion + exports.AbstractApiClient = AbstractApiClient; + exports.RpcId = RpcId; + exports.apply = apply; + exports.inject = inject; + exports.transportError = transportError; + return module.exports; + } +}); + +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/index.js new file mode 100644 index 0000000..acf1cde --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/index.js @@ -0,0 +1,588 @@ +import z from "@deepseek-ai/schemastery"; +import { toFetchHandler } from "@deepseek-ai/dsh-host-apiproxy"; +import { Service } from "@deepseek-ai/cordis"; +import { RpcId, clientRequestSchema } from "@deepseek-ai/dsh-host-apiproxy/api"; +import { randomUUID } from "node:crypto"; +import WebSocket, { WebSocketServer } from "ws"; +//#region lib/types/api-path.js +/** +* The /api URL prefix — single source for both halves of the web transport. +* The node half registers this prefix on the web server; both halves share the +* event paths below for the browser WebSocket downlinks. +*/ +/** Route prefix owning every api request (`/api` and `/api/`). */ +const API_PATH = "/api"; +/** Browser mux-frame WebSocket pathname. */ +const MUX_EVENTS_PATH = `${API_PATH}/events.mux`; +/** Browser host-frame WebSocket pathname. */ +const HOST_EVENTS_PATH = `${API_PATH}/events.host`; +//#endregion +//#region lib/types/http-bridge.js +/** +* node:http ↔ WHATWG fetch bridge for the /api transport (host side of the +* web carrier; the fetch-shaped handler itself is transport-agnostic). +*/ +/** Default carrier cap for all HTTP RPC bodies: sized for the default +* aggregate image limit (100 MiB) after base64 expansion plus envelope +* headroom (~134.3 MiB required), rounded up for slack. The bridge buffers +* each body in memory, so this cap is also the per-request resident bound. */ +const DEFAULT_MAX_REQUEST_BODY_BYTES = 160 * 1024 * 1024; +/** +* Bridge one node:http request to the fetch-shaped handler (client close +* aborts; SSE bodies stream out chunk by chunk). +* @param req - incoming node:http request (fully read before dispatch). +* @param res - node:http response the bridge writes and owns to completion. +* @param apiHandler - fetch-shaped API carrier the request is dispatched to. +* @param maxRequestBodyBytes - maximum body bytes buffered before dispatch. +*/ +async function bridge(req, res, apiHandler, maxRequestBodyBytes = DEFAULT_MAX_REQUEST_BODY_BYTES) { + const abort = new AbortController(); + res.on("close", () => { + if (!res.writableEnded) abort.abort(); + }); + const declaredLength = req.headers["content-length"]; + if (declaredLength !== void 0 && Number(declaredLength) > maxRequestBodyBytes) { + res.writeHead(413, { connection: "close" }); + res.end(); + req.destroy(); + return; + } + const chunks = []; + let received = 0; + for await (const chunk of req) { + const buffer = chunk; + received += buffer.byteLength; + if (received > maxRequestBodyBytes) { + res.writeHead(413, { connection: "close" }); + res.end(); + req.destroy(); + return; + } + chunks.push(buffer); + } + /* v8 ignore next 3 -- `??` arms: node:http always sets url/method on server + requests; the fields are only optional on the client-side IncomingMessage type */ + const request = new Request(new URL(req.url ?? "/", "http://dsh.internal"), { + method: req.method ?? "GET", + headers: Object.fromEntries(Object.entries(req.headers).filter(([, v]) => typeof v === "string")), + ...chunks.length > 0 ? { body: Buffer.concat(chunks) } : {}, + signal: abort.signal + }); + const response = await apiHandler.fetch(request); + res.writeHead(response.status, Object.fromEntries(response.headers.entries())); + if (response.body === null) { + res.end(); + return; + } + for await (const chunk of response.body) if (!res.write(chunk)) await new Promise((resolve) => { + const done = () => { + res.off("drain", done); + res.off("close", done); + resolve(); + }; + res.once("drain", done); + res.once("close", done); + }); + res.end(); +} +//#endregion +//#region lib/types/loopback-hostname.js +/** +* Browser-safe, zero-dependency loopback classification shared by the `/api` +* Host fence and the package's `ctx.connection` state. The predicate stays +* package-internal; client plugins consume the derived state through Cordis. +*/ +/** +* Whether a normalized URL hostname names the local loopback authority. +* @param hostname - WHATWG URL hostname (IPv6 literals retain brackets). +* @returns true for localhost, IPv6 loopback, or any IPv4 address in 127/8. +*/ +function isLoopbackHostname(hostname) { + if (hostname === "localhost" || hostname === "[::1]") return true; + const parts = hostname.split("."); + return parts.length === 4 && parts[0] === "127" && parts.every((part) => /^\d{1,3}$/.test(part) && Number(part) <= 255); +} +//#endregion +//#region lib/types/api-request-trust.js +/** +* Browser-trust fence for every /api request. Defends the two confused-deputy +* paths a browser opens against a local HTTP API — DNS rebinding (Host names +* the attacker's domain while the socket reaches this server) and cross-site +* requests fired from a malicious page. The Host fence binds every request, +* browser-looking or not: over plain HTTP a browser attaches neither Origin +* nor Fetch-Metadata to reads (images and navigations — those +* headers go only to trustworthy destinations), so an unmarked request may +* still be a rebound browser read and Host is the one header rebinding cannot +* forge. Non-browser and remote clients pass the same fence via loopback, +* deployment-derived LAN IP literals, or a declared `trustedHosts` authority. +* Network reachability and authentication stay out of scope: binding policy +* belongs to the webserver config, and this fence is not an auth layer. +*/ +function header(headers, name) { + if (headers instanceof Headers) return headers.get(name) ?? void 0; + const value = headers[name]; + return typeof value === "string" ? value : void 0; +} +/** Normalized URL of a Host-header authority (hostname lowercased, default port stripped, IPv6 bracketed), or undefined when unparsable. */ +function parseAuthority(authority) { + try { + return new URL(`http://${authority}`); + } catch { + return; + } +} +/** +* Assert one configured `trustedHosts` entry is a bare authority (`host` or +* `host:port`) in canonical form: it must survive WHATWG parsing unchanged +* (case aside). Anything parsing would silently rewrite is refused as a typo +* that must fail the load loudly instead of being ignored until requests 403 +* or quietly changing the grant: URL parts beyond the authority +* (`harness.internal/path`, `user@harness.internal` — which would authorize +* the embedded hostname), stripped whitespace, a dangling colon or +* zero-padded port (which would broaden an intended exact-port grant to every +* port), and non-canonical host spellings (`0x7f.0.0.1`, percent-encoding, +* unbracketed IPv6; IDN hosts are declared in punycode, the form the wire +* carries). +* @param entry - the configured value, verbatim. +*/ +function assertTrustedAuthority(entry) { + const entryUrl = parseAuthority(entry); + if (entryUrl !== void 0 && canonicalAuthority(entry, entryUrl) === entry.toLowerCase()) return; + throw new Error(`client-connection: trustedHosts entry ${JSON.stringify(entry)} is not a bare host[:port] authority`); +} +/** +* Canonical form of a parsed authority: `hostname` when no port was written, +* else `hostname:port`. The port is judged from URL parses under both special +* schemes (their default ports differ, so `:80` and `:443` still count as +* explicit), never from the raw string, where WHATWG trimming would misread +* shapes like `host:port ` as port-less. +*/ +function canonicalAuthority(entry, entryUrl) { + const port = entryUrl.port !== "" ? entryUrl.port : new URL(`https://${entry}`).port; + return port === "" ? entryUrl.hostname : `${entryUrl.hostname}:${port}`; +} +/** +* Whether the request authority matches a `trustedHosts` entry. An entry with +* an explicit port matches that exact authority; a port-less entry matches the +* hostname on any port (the shape the CLI derives for IP-literal LAN serving, +* where the bound port may be OS-assigned). Both sides compare through WHATWG +* normalization, so case and a redundant `:80` never decide trust. +*/ +function isTrustedAuthority(hostUrl, trustedHosts) { + return trustedHosts.some((entry) => { + const entryUrl = parseAuthority(entry); + if (entryUrl === void 0) return false; + return canonicalAuthority(entry, entryUrl) === entryUrl.hostname ? entryUrl.hostname === hostUrl.hostname : entryUrl.host === hostUrl.host; + }); +} +/** +* Decide whether one /api request may reach the RPC bridge. +* @param request - Node HTTP or Fetch request facts (headers). +* @param trustedHosts - non-loopback authorities this deployment serves: exact `host:port`, or port-less `host` matching any port. +* @returns true when the Host is ours (loopback or trusted) and any attached browser markers are same-origin. +*/ +function isTrustedApiRequest(request, trustedHosts) { + const host = header(request.headers, "host"); + if (host === void 0) return false; + const hostUrl = parseAuthority(host); + if (hostUrl === void 0) return false; + if (!isLoopbackHostname(hostUrl.hostname) && !isTrustedAuthority(hostUrl, trustedHosts)) return false; + if (header(request.headers, "sec-fetch-site") === "cross-site") return false; + const origin = header(request.headers, "origin"); + if (origin === void 0) return true; + try { + return new URL(origin).host === hostUrl.host; + } catch { + return false; + } +} +//#endregion +//#region lib/types/rpc-host.js +/** Host registry and HTTP adapter for generic Connection RPC channels. */ +const INVALID_REQUEST_RPC_ID = RpcId("invalid-request"); +const CHANNEL_PATTERN = /^\/[A-Za-z0-9._~-]+$/; +const ENDPOINT_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/; +/** Host Connection service whose channel registrations belong to the caller fiber. */ +var HostConnectionService = class extends Service { + trustedHosts; + interceptors = /* @__PURE__ */ new Map(); + /** + * Provide the Host half over the active HTTP server. + * @param ctx - owning Connection plugin context. + * @param trustedHosts - deployment authorities accepted by trusted-host channels. + */ + constructor(ctx, trustedHosts) { + super(ctx, "connection"); + this.trustedHosts = trustedHosts; + } + /** Generic channel registry scoped to the Context reading this service. */ + get rpc() { + const owner = this.ctx; + return { + handle: (channel, handler, options) => this.register(owner, channel, handler, options), + intercept: (channel, matches, handler, options) => this.registerInterceptor(owner, channel, matches, handler, options) + }; + } + /** + * Compose one shared-channel Fetch handler from its interceptor and fallback. + * @param channel - shared channel mounted by Connection. + * @param fallback - handler for endpoints not claimed by the interceptor. + * @returns Fetch handler that selects exactly one target for each request. + */ + createSharedFetchHandler(channel, fallback) { + return { fetch: (request) => { + const endpoint = endpointFromPath(channel, new URL(request.url).pathname); + const interceptor = this.interceptors.get(channel); + if (endpoint === void 0 || interceptor === void 0 || !interceptor.matches(endpoint)) return fallback.fetch(request); + if (interceptor.options.authority === "loopback" && !isTrustedApiRequest(request, [])) return Promise.resolve(new Response("forbidden", { status: 403 })); + return interceptor.fetchHandler.fetch(request); + } }; + } + register(owner, channel, handler, options) { + assertChannel(channel); + const trustedHosts = options.authority === "loopback" ? [] : this.trustedHosts; + const fetchHandler = rpcFetchHandler(channel, handler); + const route = { + kind: "prefix", + path: channel, + handler: async (req, res) => { + if (!isTrustedApiRequest(req, trustedHosts)) { + res.writeHead(403); + res.end("forbidden"); + return; + } + await bridge(req, res, fetchHandler); + } + }; + return owner.effect(() => owner.webServer.register(route), `client-connection: ${channel} rpc channel`); + } + registerInterceptor(owner, channel, matches, handler, options) { + if (channel !== "/api") throw new Error(`connection: invalid shared RPC channel ${JSON.stringify(channel)}`); + const interceptor = { + matches, + fetchHandler: rpcFetchHandler(channel, handler), + options + }; + return owner.effect(() => { + if (this.interceptors.has(channel)) throw new Error(`connection: shared RPC channel ${JSON.stringify(channel)} already has an interceptor`); + this.interceptors.set(channel, interceptor); + return () => { + this.interceptors.delete(channel); + }; + }, `client-connection: ${channel} rpc interceptor`); + } +}; +function rpcFetchHandler(channel, handler) { + return { async fetch(request) { + const endpoint = endpointFromPath(channel, new URL(request.url).pathname); + if (request.method !== "POST" || endpoint === void 0) return new Response("not found", { status: 404 }); + if (request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() !== "application/json") return new Response("content type must be application/json", { status: 415 }); + let body; + try { + body = await request.json(); + } catch { + return new Response("body is not JSON", { status: 400 }); + } + const envelope = clientRequestSchema.safeParse(body); + if (!envelope.success) return invalidEnvelopeResponse(body, envelope.error.issues); + const message = envelope.data; + if (message.method !== endpoint) return errorResponse(message.rpcId, { + code: "bad-request", + message: `method ${JSON.stringify(message.method)} does not match endpoint ${JSON.stringify(endpoint)}`, + details: { issues: [] } + }); + try { + const result = await handler(endpoint, message.payload, request.signal); + return fullResponse(message.rpcId, result); + } catch (error) { + return new Response(`handler failure: ${String(error)}`, { status: 500 }); + } + } }; +} +function invalidEnvelopeResponse(body, issues) { + const rawId = body?.rpcId; + return errorResponse(typeof rawId === "string" ? RpcId(rawId) : INVALID_REQUEST_RPC_ID, { + code: "bad-request", + message: "invalid client-request message", + details: { issues } + }); +} +function endpointFromPath(channel, pathname) { + if (!pathname.startsWith(`${channel}/`)) return void 0; + const endpoint = pathname.slice(channel.length + 1); + if (endpoint.split("/").some((segment) => segment === "" || segment === "." || segment === ".." || !ENDPOINT_SEGMENT_PATTERN.test(segment))) return; + return endpoint; +} +function errorResponse(rpcId, error) { + return fullResponse(rpcId, { + ok: false, + error + }); +} +function fullResponse(rpcId, result) { + const body = { + type: "server-response", + rpcId, + result + }; + return Response.json(body); +} +function assertChannel(channel) { + if (!CHANNEL_PATTERN.test(channel) || channel === "/api") throw new Error(`connection: invalid or reserved RPC channel ${JSON.stringify(channel)}`); +} +//#endregion +//#region lib/types/websocket-downlink.js +/** Host-side WebSocket carrier for the two server-to-browser event streams. */ +function serverRequest(frame) { + return { + type: "server-request", + rpcId: frame.rpcId, + method: frame.payload.type, + payload: frame.payload + }; +} +function send(socket, frame) { + return new Promise((resolve, reject) => { + if (socket.readyState !== WebSocket.OPEN) { + reject(/* @__PURE__ */ new Error("websocket downlink closed before frame delivery")); + return; + } + socket.send(JSON.stringify(serverRequest(frame)), (error) => { + if (error) reject(error); + else resolve(); + }); + }); +} +function failureFrame(error) { + return { + rpcId: RpcId(randomUUID()), + payload: { + type: "stream/error", + error: { + code: "internal", + message: String(error), + details: {} + } + } + }; +} +/** +* Owns WebSocket negotiation and frame pumping for the connection plugin's +* two downlinks. Client messages are a protocol violation: upstream traffic +* remains on HTTP. +*/ +var WebSocketDownlinks = class { + api; + server = new WebSocketServer({ noServer: true }); + pumps = /* @__PURE__ */ new Set(); + /** @param api - host API supplying the typed event streams. */ + constructor(api) { + this.api = api; + } + /** + * Upgrade one socket and pump the mux stream until either side closes. + * @param req - HTTP upgrade request. + * @param socket - Raw socket transferred by the HTTP server. + * @param head - Bytes already read after the upgrade headers. + */ + handleMux(req, socket, head) { + this.upgrade(req, socket, head, (signal) => this.api.events.mux({ + rpcId: RpcId(randomUUID()), + payload: {} + }, signal)); + } + /** + * Upgrade one socket and pump the host stream until either side closes. + * @param req - HTTP upgrade request. + * @param socket - Raw socket transferred by the HTTP server. + * @param head - Bytes already read after the upgrade headers. + */ + handleHost(req, socket, head) { + this.upgrade(req, socket, head, (signal) => this.api.events.host({ + rpcId: RpcId(randomUUID()), + payload: {} + }, signal)); + } + /** + * Terminate owned sockets and await the no-server acceptor plus frame pumps. + * @returns A promise resolving after every socket and source iterator stops. + */ + async close() { + for (const socket of this.server.clients) socket.terminate(); + await new Promise((resolve, reject) => { + this.server.close((error) => { + if (error === void 0) resolve(); + else reject(error); + }); + }); + await Promise.all(this.pumps); + } + upgrade(req, socket, head, open) { + this.server.handleUpgrade(req, socket, head, (websocket) => { + const abort = new AbortController(); + websocket.once("close", () => { + abort.abort(); + }); + websocket.once("error", () => { + abort.abort(); + }); + websocket.once("message", () => { + websocket.close(1008, "downlink only"); + }); + const pump = this.pump(websocket, open(abort.signal), abort); + this.pumps.add(pump); + pump.then(() => { + this.pumps.delete(pump); + }); + }); + } + async pump(socket, frames, abort) { + try { + for await (const frame of frames) await send(socket, frame); + } catch (error) { + if (!abort.signal.aborted) try { + await send(socket, failureFrame(error)); + } catch {} + } finally { + abort.abort(); + if (socket.readyState === WebSocket.OPEN) socket.close(); + } + } +}; +/** +* Reject an untrusted upgrade before protocol negotiation. +* @param socket - Raw HTTP socket that remains owned by the caller. +*/ +function rejectWebSocketUpgrade(socket) { + socket.end([ + "HTTP/1.1 403 Forbidden", + "Connection: close", + "Content-Type: text/plain; charset=utf-8", + "Content-Length: 9", + "", + "forbidden" + ].join("\r\n")); +} +//#endregion +//#region lib/types/index.js +/** Stable Cordis plugin name. */ +const name = "client-connection"; +/** Headroom for RPC JSON fields around aggregate base64 image payloads. */ +const REQUEST_ENVELOPE_HEADROOM_BYTES = 1024 * 1024; +function assertImageBodyCapacity(ctx, maxRequestBodyBytes) { + const attachments = ctx.get("attachments"); + if (attachments === void 0) return; + const requiredImageBodyBytes = Math.ceil(attachments.imageLimits.maxMessageImageBytes * 4 / 3) + REQUEST_ENVELOPE_HEADROOM_BYTES; + if (maxRequestBodyBytes < requiredImageBodyBytes) throw new Error(`client-connection maxRequestBodyBytes (${String(maxRequestBodyBytes)}) must be at least ${String(requiredImageBodyBytes)} for the configured aggregate image limit`); +} +/** Services required before providing Connection; API Proxy is an optional `/api` fallback. */ +const inject = ["webServer"]; +const Config = z.object({ + trustedHosts: z.array(String).default([]), + maxRequestBodyBytes: z.natural().min(1).default(DEFAULT_MAX_REQUEST_BODY_BYTES) +}); +/** +* Methods gated to loopback even on a trusted-host deployment. Native dialogs +* act on the host machine; the settings and credential domains mutate the +* user's configuration and secret store, and READING them is equally +* privileged — `settings.describe` returns every exposed namespace's +* configuration and `credentials.describe` reports whether an arbitrary +* environment-variable name is configured and where from, which is +* reconnaissance no anonymous caller should have. `trustedHosts` is a +* DNS-rebinding fence, explicitly not authentication, so the whole +* configuration plane stays loopback-same-origin until a real authentication +* layer exists. `llm.discoverModels` belongs to that plane on both counts: it +* carries a draft credential, and it makes the HOST issue a GET to a URL the +* caller chose and reports back the status or the parsed body — an anonymous +* LAN caller would have a probe for whatever the host can reach and the +* browser cannot. +* +* The model catalog (`llm.providers`, `llm.models`) is deliberately NOT here: +* it carries provider ids, display names, and model lists — no endpoints, +* keys, or key state — and a LAN client's model picker legitimately needs it. +*/ +const PRIVILEGED_METHODS = new Set([ + "agentPreset.read", + "agentPreset.copy", + "agentPreset.openDocument", + "agentPreset.remove", + "host.pickDirectory", + "host.openPath", + "settings.describe", + "settings.openDocument", + "settings.update", + "settings.replace", + "settings.mutate", + "credentials.describe", + "credentials.set", + "credentials.unset", + "llm.discoverModels" +]); +/** +* Mounts the API gateway under the browser transport prefix. Every request on +* the prefix passes the browser-trust fence first (DNS-rebinding and +* cross-site defense — [api-request-trust](./api-request-trust.ts)); +* privileged methods additionally pass it with an empty trust list, which +* pins them to loopback. +* @param ctx - Host plugin context. +* @param config - resolved plugin config (schema defaults applied). +*/ +function apply(ctx, config) { + const trustedHosts = config?.trustedHosts ?? []; + const maxRequestBodyBytes = config?.maxRequestBodyBytes ?? 167772160; + for (const entry of trustedHosts) assertTrustedAuthority(entry); + if (ctx.get("apiProxy") !== void 0) assertImageBodyCapacity(ctx, maxRequestBodyBytes); + const fetchHandler = new HostConnectionService(ctx, trustedHosts).createSharedFetchHandler(API_PATH, { async fetch(request) { + const pathname = new URL(request.url).pathname; + const method = pathname.startsWith(`/api/`) ? pathname.slice(5) : void 0; + if (method !== void 0 && PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, [])) return new Response("forbidden", { status: 403 }); + if (request.method === "GET" && (pathname === MUX_EVENTS_PATH || pathname === HOST_EVENTS_PATH)) return new Response("upgrade required", { + status: 426, + headers: { + connection: "Upgrade", + upgrade: "websocket" + } + }); + const apiProxy = ctx.get("apiProxy"); + if (apiProxy === void 0) return new Response("not found", { status: 404 }); + return toFetchHandler(apiProxy).fetch(request); + } }); + const route = { + kind: "prefix", + path: API_PATH, + handler: async (req, res) => { + if (!isTrustedApiRequest(req, trustedHosts)) { + res.writeHead(403); + res.end("forbidden"); + return; + } + await bridge(req, res, fetchHandler, maxRequestBodyBytes); + } + }; + ctx.effect(() => ctx.webServer.register(route), "client-connection: /api route"); + ctx.inject(["apiProxy"], (apiCtx) => { + assertImageBodyCapacity(apiCtx, maxRequestBodyBytes); + const downlinks = new WebSocketDownlinks(apiCtx.apiProxy); + const registerDownlink = (path, handle) => { + apiCtx.effect(() => apiCtx.webServer.registerUpgrade({ + path, + handler: (req, socket, head) => { + if (!isTrustedApiRequest(req, trustedHosts)) { + rejectWebSocketUpgrade(socket); + return; + } + return handle(req, socket, head); + } + }), `client-connection: ${path} WebSocket`); + }; + apiCtx.effect(() => () => downlinks.close(), "client-connection: WebSocket downlinks"); + registerDownlink(MUX_EVENTS_PATH, (req, socket, head) => { + downlinks.handleMux(req, socket, head); + }); + registerDownlink(HOST_EVENTS_PATH, (req, socket, head) => { + downlinks.handleHost(req, socket, head); + }); + }); +} +//#endregion +export { API_PATH, Config, HOST_EVENTS_PATH, HostConnectionService, MUX_EVENTS_PATH, apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/invariant.js new file mode 100644 index 0000000..74291ab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/invariant.js @@ -0,0 +1,26 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-client-connection`. +* @module @deepseek-ai/dsh-client-connection/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-client-connection"; +/** Cordis companion plugin name. */ +const name = "client-connection-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the wire layer emits no cordis events and owns no +* mutable cross-plugin relation — stream/reconnect sequencing is exercised +* directly by its behavior specs, rpcId round-trip discipline is owned by the +* apiproxy contract layer, and the node half's single route registration's +* register/dispose symmetry is audited by the webserver package's invariant. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-path.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-path.d.ts new file mode 100644 index 0000000..6e5b34c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-path.d.ts @@ -0,0 +1,12 @@ +/** + * The /api URL prefix — single source for both halves of the web transport. + * The node half registers this prefix on the web server; both halves share the + * event paths below for the browser WebSocket downlinks. + */ +/** Route prefix owning every api request (`/api` and `/api/`). */ +export declare const API_PATH = "/api"; +/** Browser mux-frame WebSocket pathname. */ +export declare const MUX_EVENTS_PATH = "/api/events.mux"; +/** Browser host-frame WebSocket pathname. */ +export declare const HOST_EVENTS_PATH = "/api/events.host"; +//# sourceMappingURL=api-path.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-request-trust.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-request-trust.d.ts new file mode 100644 index 0000000..6836179 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-request-trust.d.ts @@ -0,0 +1,43 @@ +/** + * Browser-trust fence for every /api request. Defends the two confused-deputy + * paths a browser opens against a local HTTP API — DNS rebinding (Host names + * the attacker's domain while the socket reaches this server) and cross-site + * requests fired from a malicious page. The Host fence binds every request, + * browser-looking or not: over plain HTTP a browser attaches neither Origin + * nor Fetch-Metadata to reads (images and navigations — those + * headers go only to trustworthy destinations), so an unmarked request may + * still be a rebound browser read and Host is the one header rebinding cannot + * forge. Non-browser and remote clients pass the same fence via loopback, + * deployment-derived LAN IP literals, or a declared `trustedHosts` authority. + * Network reachability and authentication stay out of scope: binding policy + * belongs to the webserver config, and this fence is not an auth layer. + */ +import type { IncomingHttpHeaders } from 'node:http'; +/** The request facts the fence reads from either HTTP representation. */ +interface ApiTrustRequest { + headers: IncomingHttpHeaders | Headers; +} +/** + * Assert one configured `trustedHosts` entry is a bare authority (`host` or + * `host:port`) in canonical form: it must survive WHATWG parsing unchanged + * (case aside). Anything parsing would silently rewrite is refused as a typo + * that must fail the load loudly instead of being ignored until requests 403 + * or quietly changing the grant: URL parts beyond the authority + * (`harness.internal/path`, `user@harness.internal` — which would authorize + * the embedded hostname), stripped whitespace, a dangling colon or + * zero-padded port (which would broaden an intended exact-port grant to every + * port), and non-canonical host spellings (`0x7f.0.0.1`, percent-encoding, + * unbracketed IPv6; IDN hosts are declared in punycode, the form the wire + * carries). + * @param entry - the configured value, verbatim. + */ +export declare function assertTrustedAuthority(entry: string): void; +/** + * Decide whether one /api request may reach the RPC bridge. + * @param request - Node HTTP or Fetch request facts (headers). + * @param trustedHosts - non-loopback authorities this deployment serves: exact `host:port`, or port-less `host` matching any port. + * @returns true when the Host is ours (loopback or trusted) and any attached browser markers are same-origin. + */ +export declare function isTrustedApiRequest(request: ApiTrustRequest, trustedHosts: readonly string[]): boolean; +export {}; +//# sourceMappingURL=api-request-trust.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/api.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/api.d.ts new file mode 100644 index 0000000..1102985 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/api.d.ts @@ -0,0 +1,20 @@ +export type { ApiProxy, SessionsApi, SessionSearchItem, SessionSummary, PromptContentPart, HostApi, EventsApi, MuxFrame, HostFrame, ApprovalResponsePayload, QuestionResponsePayload, HistoryEntry, ToolEventView, DirectoryEntry, DirectoryListing, ResponseValue, WorkspaceApi, WorkspaceId, WorkspaceView, SkillsApi, SkillEntry, ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning, ModelReasoningEffort, ModelSelection, QueueAction, QueuedInboxItem, SessionModels, GoalsApi, GoalRef, SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView, CredentialsApi, CredentialView, ConfigurableProviderView, DiscoveredModelView, LlmApi, SubagentsApi, SubagentAddress, SubagentCatalog, SubagentListEntry, SubagentPromptReceipt, JobView, } from '@deepseek-ai/dsh-host-apiproxy/api'; +export type { ToolCallView, ToolResultView } from '@deepseek-ai/dsh-tools/presentation'; +export type { RpcRequest, RpcResponse, RpcResult, RpcError, RpcErrorCode, ClientRequest, ServerResponse, ServerRequest, ClientResponse, RpcMessage, RpcReceipt, } from '@deepseek-ai/dsh-host-apiproxy/api'; +export { RpcId, SESSION_SEARCH_RESULT_LIMIT, transportError, } from '@deepseek-ai/dsh-host-apiproxy/api'; +export { AbstractApiClient } from '@deepseek-ai/dsh-host-apiproxy/client'; +export type { IApiClient } from '@deepseek-ai/dsh-host-apiproxy/client'; +export type { SessionId, SessionEvent } from '@deepseek-ai/dsh-session/types'; +export type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +export type { ContentBlock, StreamChunk } from '@deepseek-ai/dsh-llm/types'; +/** Successful value returned by the connection-generation host handshake. */ +export type HostDescription = import('@deepseek-ai/dsh-host-apiproxy/api').ResponseValue<'host.describe'>; +import type { RpcResponse, RpcResult } from '@deepseek-ai/dsh-host-apiproxy/api'; +/** + * Unwrap a unary response: RpcResponse -> RpcResult (business code only + * cares about the result slot). + * @param response - the unary response. + * @returns its result slot. + */ +export declare function resultOf(response: RpcResponse): RpcResult; +//# sourceMappingURL=api.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/connection.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/connection.d.ts new file mode 100644 index 0000000..b6ae466 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/connection.d.ts @@ -0,0 +1,64 @@ +import type { HostDescription, IApiClient, HostFrame, MuxFrame, RpcRequest } from './api.ts'; +/** Reconnect/backoff tunables (deployment-varying — no hardcoded tunables; these become the + * future `ctx.connection` plugin's Config). All fields optional; defaults below. */ +export interface ConnectionConfig { + /** First-retry backoff cap in ms (jittered: actual delay is cap/2..cap). */ + backoffBaseMs?: number; + /** Exponential growth factor per consecutive failed attempt. */ + backoffFactor?: number; + /** Upper bound for the backoff cap in ms. */ + backoffMaxMs?: number; + /** Cap on waiting for both streams' onOpen before onConnected, in ms. The strict handshake + * waits for mux+host stream establishment plus describe; a carrier that never + * fires onOpen (misbehaving proxy) must not wedge the connection forever — on timeout the + * generation proceeds as connected and the live-gap repair path covers stragglers. */ + streamOpenTimeoutMs?: number; +} +/** Coarse connection state for the UI: 'connected' after each generation's handshake, + * 'reconnecting' the moment the generation fails (covers the whole backoff+retry span). */ +export type ConnectionState = 'connected' | 'reconnecting'; +/** Frame sink callbacks: the Controller owns the physical streams; business dispatch belongs to + * SessionManager. */ +export interface ConnectionSinks { + onMuxEnvelope?: (envelope: RpcRequest) => void; + onHostEnvelope?: (envelope: RpcRequest) => void; + /** After each connection generation is established (both streams open + describe succeeded), first connect included. */ + onConnected?: (description: HostDescription) => void; + /** Coarse state transitions (deduplicated: fires only on change). The initial pre-connect + * span reports nothing — the UI treats "no state yet" as connecting, not as an outage. */ + onStateChange?: (state: ConnectionState) => void; +} +/** + * Opens both streams and keeps iterating (pull mode: nothing reads the socket and the tap + * never fires unless someone for-awaits), reconnecting with exponential backoff on loss. + * State (generation/attempt) is instance-private, never in the store. + * The pump body feeds each frame to a sink (sink exceptions must + * not kill the pump — a broken business layer must not drag down the connection layer). + */ +export declare class ConnectionController { + private readonly api; + private readonly sinks; + private generation; + private attempt; + private current; + private running; + private lastState; + private readonly config; + constructor(api: IApiClient, sinks?: ConnectionSinks, config?: ConnectionConfig); + /** Idempotent: begin the connect/pump/reconnect loop. */ + start(): void; + /** Stop the loop and abort the current generation's streams. */ + stop(): void; + private backoffDelay; + /** Read through a method: stop() flips the flag across awaits, so narrowing from the loop condition must not stick. */ + private isRunning; + /** Re-read both mutable liveness guards after a potentially reentrant sink. */ + private isGenerationActive; + private loop; + /** Deduplicated state emission (sink isolation applies). */ + private emitState; + private pumpStream; + /** Sink exception isolation: a business-layer throw is logged only, never affecting pump or reconnect semantics. */ + private callSink; +} +//# sourceMappingURL=connection.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/fixture.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/fixture.d.ts new file mode 100644 index 0000000..6ff192d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/fixture.d.ts @@ -0,0 +1,68 @@ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { ApiProxy, ClientResponse, HostFrame, MuxFrame, RpcReceipt, RpcRequest, RpcResponse } from './api.ts'; +import type { RequestPayload, ResponseValue, RpcMethodMap } from '@deepseek-ai/dsh-host-apiproxy/api'; +import { AbstractApiClient } from './api.ts'; +import type { ClientConnectionRpc } from '../rpc.ts'; +/** Deterministic fixture branches used by keyless Web assembly tests. */ +export interface FixtureOptions { + /** Start with no real Workspace or Session. */ + empty?: boolean; + /** Reject every prompt before appending its user event. */ + rejectPrompt?: boolean; + /** Publish the Session but fail its Workspace account write. */ + failWorkspaceAttach?: boolean; + /** Publish and frame the Session, then throw instead of returning create. */ + dropSessionCreateResponse?: boolean; + /** Order of the two successful create frames. */ + createFrameOrder?: 'session-first' | 'workspace-first'; +} +/** + * In-memory fake host: fx-alpha carries history and replay scripts; fx-beta is fx-alpha's child session (lineage indent material). + * @param options - fixture branches for empty state and failure timing. + * @returns an ApiProxy backed entirely by in-memory state — no host process, no network. + */ +export declare function createFixtureApi(options?: FixtureOptions): ApiProxy; +/** Both fixture faces over one state graph. */ +export interface FixtureWorld { + /** Legacy unary/stream API the fixture still answers. */ + readonly api: ApiProxy; + /** Generic Remote caller for the endpoints business services own. */ + readonly rpc: ClientConnectionRpc; +} +/** + * Build both fixture faces so a caller can drive the Remote endpoints and the + * legacy API against one in-memory state graph. + * @param options - fixture branches for empty state and failure timing. + * @returns the legacy API face and the Remote RPC face. + */ +export declare function createFixtureFaces(options?: FixtureOptions): FixtureWorld; +/** + * Fixture platform subclass: there is no HTTP at all, so instead of a doFetch transport it + * overrides the protocol-level virtuals (callUnary/openMux/openHost/respond) to dispatch + * straight into the in-memory ApiProxy — while still minting rpcIds, fabricating the four + * named full forms, and feeding the same tap as a real carrier. TODO: delete when the fixture + * moves to the isomorphic pipeline (InProcessApiClient over toFetchHandler(fixtureImpl)). + */ +export declare class FixtureApiClient extends AbstractApiClient { + private readonly api; + /** Generic Remote caller backed by the same in-memory state as the legacy fixture API. */ + readonly rpc: ClientConnectionRpc; + constructor(); + protected doFetch(): Promise; + protected callUnary(method: K, payload: RequestPayload, signal?: AbortSignal): Promise>>; + /** Method-key dispatch into the in-memory contract impl (a real carrier routes by URL path instead). */ + private dispatch; + protected openMux(payload: { + since?: Record; + }, signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + protected openHost(payload: Record, signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + private tapStream; + /** + * Deliver a client response to the in-memory contract impl (no HTTP POST), + * echoing the envelope to the observation tap like every other path. + * @param message - the client-response envelope answering a server request. + * @returns the carrier receipt from the fixture impl. + */ + respond(message: ClientResponse): Promise; +} +//# sourceMappingURL=fixture.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/index.d.ts new file mode 100644 index 0000000..66def88 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/index.d.ts @@ -0,0 +1,54 @@ +/** + * Browser wire client. The plugin selects fixture or HTTP transport, provides + * the shared API client, and lets the runtime object layer start the stream + * controller with its sinks. + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { HostDescription, IApiClient } from './api.ts'; +import { type ConnectionConfig, type ConnectionSinks, type ConnectionState } from './connection.ts'; +import type { ClientConnectionRpc } from '../rpc.ts'; +export type { ApiProxy, SessionsApi, SessionSearchItem, SessionSummary, PromptContentPart, HostApi, EventsApi, MuxFrame, HostFrame, ApprovalResponsePayload, QuestionResponsePayload, HistoryEntry, ToolEventView, DirectoryEntry, DirectoryListing, ToolCallView, ToolResultView, WorkspaceApi, WorkspaceId, WorkspaceView, SkillsApi, SkillEntry, ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning, MessageId, ModelReasoningEffort, ModelSelection, QueueAction, QueuedInboxItem, SessionModels, SubagentsApi, SubagentAddress, SubagentCatalog, SubagentListEntry, SubagentPromptReceipt, JobView, RpcRequest, RpcResponse, RpcResult, RpcError, RpcErrorCode, ClientRequest, ServerResponse, ServerRequest, ClientResponse, RpcMessage, RpcReceipt, HostDescription, IApiClient, SessionId, SessionEvent, ContentBlock, StreamChunk, GoalsApi, GoalRef, SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView, CredentialsApi, CredentialView, ConfigurableProviderView, DiscoveredModelView, LlmApi, } from './api.ts'; +export { RpcId, AbstractApiClient, transportError, } from './api.ts'; +export type { ConnectionConfig, ConnectionSinks, ConnectionState }; +export type { ClientConnectionRpc } from '../rpc.ts'; +/** Observable Host description published by each completed connection handshake. */ +export interface HostDescriptionSource { + /** Latest connected-generation description; absent before connect and while reconnecting. */ + getSnapshot(): HostDescription | undefined; + /** Subscribe to description replacement and connection loss. */ + subscribe(listener: () => void): () => void; +} +/** Required services (none — this is the wire root). */ +export declare const inject: string[]; +/** + * The ctx.connection service API: the API client plus a one-shot + * controller starter (the runtime plugin supplies sinks when its object layer + * is ready — connection stays consumer-agnostic). + */ +export interface ConnectionHandle { + /** Shared api client (fixture or real, decided at boot from the page URL). */ + readonly api: IApiClient; + /** Whether the current page authority is loopback; non-browser contexts default to true. */ + readonly isLoopback: boolean; + /** Generation-scoped Host facts, including native path-open capability. */ + readonly hostDescription: HostDescriptionSource; + /** Generic logical RPC channels over the same Connection transport. */ + readonly rpc: ClientConnectionRpc; + /** + * Start the connect/pump/reconnect loop with the consumer's frame sinks. + * One consumer owns the streams (the runtime object layer); a second call + * throws. + * @param sinks - frame/state callbacks. + * @param config - reconnect/backoff tunables. + * @returns stop handle for the loop. + */ + start(sinks: ConnectionSinks, config?: ConnectionConfig): { + stop(): void; + }; +} +/** + * Client plugin body: pick the api by page mode and provide ctx.connection. + * @param ctx - client cordis context. + */ +export declare function apply(ctx: Context): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/random-uuid.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/random-uuid.d.ts new file mode 100644 index 0000000..9c14cda --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/random-uuid.d.ts @@ -0,0 +1,7 @@ +/** Browser-safe UUID generation for client-side wire correlation. */ +/** + * Generate an RFC 4122 version 4 UUID without requiring a secure context. + * @returns a UUID backed by `crypto.getRandomValues()`, which browsers expose on insecure origins. + */ +export declare function randomUuid(): string; +//# sourceMappingURL=random-uuid.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/rpc.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/rpc.d.ts new file mode 100644 index 0000000..f6af7ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/rpc.d.ts @@ -0,0 +1,8 @@ +/** Browser caller for generic Connection unary RPC channels. */ +import type { ClientConnectionRpc } from '../rpc.ts'; +/** + * Create the browser-backed generic RPC caller. + * @returns caller that owns request correlation and response-envelope validation. + */ +export declare function createWebConnectionRpc(): ClientConnectionRpc; +//# sourceMappingURL=rpc.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/web-api-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/web-api-client.d.ts new file mode 100644 index 0000000..7a27aed --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/web-api-client.d.ts @@ -0,0 +1,11 @@ +/** Browser API carrier: HTTP upstream plus one WebSocket per downstream event stream. */ +import type { ApiProxy, HostFrame, MuxFrame, RpcRequest } from './api.ts'; +import { AbstractApiClient } from './api.ts'; +/** Browser platform subclass: unary/respond use fetch; mux/host use downlink-only WebSockets. */ +export declare class WebApiClient extends AbstractApiClient { + protected doFetch(input: URL, init?: RequestInit): Promise; + protected openMux(_payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + protected openHost(_payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + private readWebSocket; +} +//# sourceMappingURL=web-api-client.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/http-bridge.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/http-bridge.d.ts new file mode 100644 index 0000000..f7d5515 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/http-bridge.d.ts @@ -0,0 +1,29 @@ +/** + * node:http ↔ WHATWG fetch bridge for the /api transport (host side of the + * web carrier; the fetch-shaped handler itself is transport-agnostic). + */ +import type { IncomingMessage, ServerResponse } from 'node:http'; +/** Default carrier cap for all HTTP RPC bodies: sized for the default + * aggregate image limit (100 MiB) after base64 expansion plus envelope + * headroom (~134.3 MiB required), rounded up for slack. The bridge buffers + * each body in memory, so this cap is also the per-request resident bound. */ +export declare const DEFAULT_MAX_REQUEST_BODY_BYTES: number; +/** Transport-independent request handler consumed by the Host HTTP bridge. */ +export interface FetchHandler { + /** + * Handle one standard Fetch request. + * @param request - request produced by the active transport bridge. + * @returns complete or streaming Fetch response. + */ + fetch(request: Request): Promise; +} +/** + * Bridge one node:http request to the fetch-shaped handler (client close + * aborts; SSE bodies stream out chunk by chunk). + * @param req - incoming node:http request (fully read before dispatch). + * @param res - node:http response the bridge writes and owns to completion. + * @param apiHandler - fetch-shaped API carrier the request is dispatched to. + * @param maxRequestBodyBytes - maximum body bytes buffered before dispatch. + */ +export declare function bridge(req: IncomingMessage, res: ServerResponse, apiHandler: FetchHandler, maxRequestBodyBytes?: number): Promise; +//# sourceMappingURL=http-bridge.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/index.d.ts new file mode 100644 index 0000000..58a76c5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/index.d.ts @@ -0,0 +1,36 @@ +/** Host HTTP bridge for browser-client RPC. */ +import type { Context } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +export type { ConnectionRpcAuthority, ConnectionRpcEndpointMatcher, ConnectionRpcHandler, ConnectionRpcHandlerOptions, HostConnectionHandle, HostConnectionRpc, } from './rpc.ts'; +export { HostConnectionService } from './rpc-host.ts'; +export { API_PATH, HOST_EVENTS_PATH, MUX_EVENTS_PATH } from './api-path.ts'; +/** Stable Cordis plugin name. */ +export declare const name = "client-connection"; +/** Services required before providing Connection; API Proxy is an optional `/api` fallback. */ +export declare const inject: string[]; +/** Plugin config: the deployment's non-loopback serving authorities. */ +export interface ConnectionConfig { + /** + * Authorities this deployment serves beyond loopback: exact `host:port`, or + * port-less `host` matching any port. The /api trust fence refuses any + * request whose Host is neither loopback nor listed here, so a + * non-loopback (`0.0.0.0`) deployment must declare the names it is reached + * by (the dsh CLI derives the machine's LAN IP literals itself). An entry + * that is not a bare, canonical authority fails the plugin load. + */ + trustedHosts?: string[]; + /** Maximum buffered JSON body for every `/api` request. */ + maxRequestBodyBytes?: number; +} +export declare const Config: z; +/** + * Mounts the API gateway under the browser transport prefix. Every request on + * the prefix passes the browser-trust fence first (DNS-rebinding and + * cross-site defense — [api-request-trust](./api-request-trust.ts)); + * privileged methods additionally pass it with an empty trust list, which + * pins them to loopback. + * @param ctx - Host plugin context. + * @param config - resolved plugin config (schema defaults applied). + */ +export declare function apply(ctx: Context, config?: ConnectionConfig): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/invariant.d.ts new file mode 100644 index 0000000..cdbfd40 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-client-connection`. + * @module @deepseek-ai/dsh-client-connection/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "client-connection-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/loopback-hostname.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/loopback-hostname.d.ts new file mode 100644 index 0000000..9ae9118 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/loopback-hostname.d.ts @@ -0,0 +1,12 @@ +/** + * Browser-safe, zero-dependency loopback classification shared by the `/api` + * Host fence and the package's `ctx.connection` state. The predicate stays + * package-internal; client plugins consume the derived state through Cordis. + */ +/** + * Whether a normalized URL hostname names the local loopback authority. + * @param hostname - WHATWG URL hostname (IPv6 literals retain brackets). + * @returns true for localhost, IPv6 loopback, or any IPv4 address in 127/8. + */ +export declare function isLoopbackHostname(hostname: string): boolean; +//# sourceMappingURL=loopback-hostname.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc-host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc-host.d.ts new file mode 100644 index 0000000..09df9d7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc-host.d.ts @@ -0,0 +1,33 @@ +/** Host registry and HTTP adapter for generic Connection RPC channels. */ +import { Context, Service } from '@deepseek-ai/cordis'; +import { type FetchHandler } from './http-bridge.ts'; +import type { HostConnectionHandle, HostConnectionRpc } from './rpc.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + /** Host Connection transport and RPC registrations. */ + connection: HostConnectionHandle; + } +} +/** Host Connection service whose channel registrations belong to the caller fiber. */ +export declare class HostConnectionService extends Service implements HostConnectionHandle { + private readonly trustedHosts; + private readonly interceptors; + /** + * Provide the Host half over the active HTTP server. + * @param ctx - owning Connection plugin context. + * @param trustedHosts - deployment authorities accepted by trusted-host channels. + */ + constructor(ctx: Context, trustedHosts: readonly string[]); + /** Generic channel registry scoped to the Context reading this service. */ + get rpc(): HostConnectionRpc; + /** + * Compose one shared-channel Fetch handler from its interceptor and fallback. + * @param channel - shared channel mounted by Connection. + * @param fallback - handler for endpoints not claimed by the interceptor. + * @returns Fetch handler that selects exactly one target for each request. + */ + createSharedFetchHandler(channel: '/api', fallback: FetchHandler): FetchHandler; + private register; + private registerInterceptor; +} +//# sourceMappingURL=rpc-host.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc.d.ts new file mode 100644 index 0000000..e19b4d3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc.d.ts @@ -0,0 +1,51 @@ +/** Generic unary RPC contracts shared by the Host and Client Connection halves. */ +import type { RpcResult } from '@deepseek-ai/dsh-host-apiproxy/api'; +/** Trust fence applied before a Host RPC channel reaches its handler. */ +export type ConnectionRpcAuthority = 'trusted-host' | 'loopback'; +/** Registration policy for one logical RPC channel. */ +export interface ConnectionRpcHandlerOptions { + /** Browser authority accepted by every endpoint in this channel. */ + readonly authority: ConnectionRpcAuthority; +} +/** Handler invoked after Connection has decoded the transport envelope. */ +export type ConnectionRpcHandler = (endpoint: string, payload: unknown, signal: AbortSignal) => Promise>; +/** Synchronous ownership test for one endpoint on a shared RPC channel. */ +export type ConnectionRpcEndpointMatcher = (endpoint: string) => boolean; +/** Host registry for logical RPC channels carried by the current transport. */ +export interface HostConnectionRpc { + /** + * Register one absolute channel prefix and its trust policy. + * @param channel - absolute logical channel such as `/rpc`. + * @param handler - decoded endpoint handler returning the existing RPC result shape. + * @param options - channel trust policy. + * @returns asynchronous disposer removing the channel and its physical route. + */ + handle(channel: string, handler: ConnectionRpcHandler, options: ConnectionRpcHandlerOptions): () => Promise; + /** + * Intercept owned endpoints on the shared `/api` channel before its fallback. + * @param channel - reserved shared channel; currently `/api`. + * @param matches - synchronous endpoint ownership test. + * @param handler - decoded endpoint handler returning the existing RPC result shape. + * @param options - trust policy for every endpoint claimed by this interceptor. + * @returns asynchronous disposer removing the interceptor. + */ + intercept(channel: '/api', matches: ConnectionRpcEndpointMatcher, handler: ConnectionRpcHandler, options: ConnectionRpcHandlerOptions): () => Promise; +} +/** Host `ctx.connection` shape consumed by transport-independent adapters. */ +export interface HostConnectionHandle { + /** Generic RPC channel registry. */ + readonly rpc: HostConnectionRpc; +} +/** Client caller for logical RPC channels carried by the current transport. */ +export interface ClientConnectionRpc { + /** + * Call one endpoint through an already registered logical channel. + * @param channel - absolute logical channel such as `/api`. + * @param endpoint - channel-relative endpoint such as `goals/create`. + * @param payload - channel-owned request payload. + * @param signal - optional caller cancellation. + * @returns the existing RPC success/error result; correlation stays inside Connection. + */ + call(channel: string, endpoint: string, payload: unknown, signal?: AbortSignal): Promise>; +} +//# sourceMappingURL=rpc.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/websocket-downlink.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/websocket-downlink.d.ts new file mode 100644 index 0000000..a9d429e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/lib/types/websocket-downlink.d.ts @@ -0,0 +1,43 @@ +/** Host-side WebSocket carrier for the two server-to-browser event streams. */ +import type { IncomingMessage } from 'node:http'; +import type { Duplex } from 'node:stream'; +import type { ApiProxy } from '@deepseek-ai/dsh-host-apiproxy/api'; +/** + * Owns WebSocket negotiation and frame pumping for the connection plugin's + * two downlinks. Client messages are a protocol violation: upstream traffic + * remains on HTTP. + */ +export declare class WebSocketDownlinks { + private readonly api; + private readonly server; + private readonly pumps; + /** @param api - host API supplying the typed event streams. */ + constructor(api: ApiProxy); + /** + * Upgrade one socket and pump the mux stream until either side closes. + * @param req - HTTP upgrade request. + * @param socket - Raw socket transferred by the HTTP server. + * @param head - Bytes already read after the upgrade headers. + */ + handleMux(req: IncomingMessage, socket: Duplex, head: Buffer): void; + /** + * Upgrade one socket and pump the host stream until either side closes. + * @param req - HTTP upgrade request. + * @param socket - Raw socket transferred by the HTTP server. + * @param head - Bytes already read after the upgrade headers. + */ + handleHost(req: IncomingMessage, socket: Duplex, head: Buffer): void; + /** + * Terminate owned sockets and await the no-server acceptor plus frame pumps. + * @returns A promise resolving after every socket and source iterator stops. + */ + close(): Promise; + private upgrade; + private pump; +} +/** + * Reject an untrusted upgrade before protocol negotiation. + * @param socket - Raw HTTP socket that remains owned by the caller. + */ +export declare function rejectWebSocketUpgrade(socket: Duplex): void; +//# sourceMappingURL=websocket-downlink.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/package.json new file mode 100644 index 0000000..4b112aa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-client-connection/package.json @@ -0,0 +1,67 @@ +{ + "name": "@deepseek-ai/dsh-client-connection", + "description": "Wire consumer layer: HTTP-up/WebSocket-down client, ConnectionController dual streams with reconnect, and fixture api", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/client/connection" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client/index.d.ts", + "default": "./lib/client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "dsh": { + "client": { + "inject": [], + "platform": "web", + "immediately": true + } + }, + "license": "MIT", + "dependencies": { + "ws": "^8.21.0", + "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.6", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.6", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/client.js", + "lib/types/**/*.d.ts" + ], + "peerDependencies": { + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@types/ws": "^8.18.1", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-commands b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-commands new file mode 120000 index 0000000..fff701f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-commands @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-host-apiproxy b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-host-apiproxy new file mode 120000 index 0000000..80e698e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-host-apiproxy @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-host-webserver b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-host-webserver new file mode 120000 index 0000000..5723b61 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-host-webserver @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-tools b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-tools new file mode 120000 index 0000000..49af432 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/dsh-tools @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/ws b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/ws new file mode 120000 index 0000000..7b83861 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.6_4d97f918f32bf0a0e5cc153682aa7b50/node_modules/ws @@ -0,0 +1 @@ +../../ws@8.21.3/node_modules/ws \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-attachment b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-attachment new file mode 120000 index 0000000..dc64562 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-attachment @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.i18n.yaml new file mode 100644 index 0000000..4745644 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/client/connection/README.md +README.md: f0a707cc5f3a962c7852f7323c727d0a39a57b10 +README.zh.md: b529eebf9af93e36b6b92c19964678b7f5a04ea1 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.md new file mode 100644 index 0000000..f0a707c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.md @@ -0,0 +1,26 @@ +# @deepseek-ai/dsh-client-connection + +English | [中文](README.zh.md) + +Wire consumer layer: the client plugin's apply mounts `ctx.connection` (shared api client + current-page loopback state + observable generation-scoped `hostDescription` + single-consumer stream-loop starter); the export face carries the wire contract types, the `AbstractApiClient` abstraction, and the loop's sink/config types. Each successful readiness handshake publishes the exact `host.describe` value before `onConnected`; generation loss and explicit stop clear it, so native-capability consumers never retain a disconnected answer. The browser carrier uses HTTP POST for unary and respond operations and opens one downlink-only WebSocket each for `events.mux` and `events.host`; the in-process carrier satisfies the same two-stream abstraction. The Host half owns the single `/api` route and its Fetch bridge; a registered Typert interceptor claims its Remote endpoints before the API Proxy fallback. Loopback hostname classification stays package-internal: the `/api` Host fence and WebSocket upgrades use it directly, while other client plugins consume the derived `ctx.connection.isLoopback` state. The node half's `/api` route pins the privileged method set (`host.pickDirectory`, `host.openPath`, and the whole configuration plane — `settings.describe`/`openDocument`/`update`/`replace`/`mutate` and `credentials.describe`/`set`/`unset`; reads and native actions included, since describing returns the exposed configuration, opening acts on the Host desktop, and probing an arbitrary reference reports where a credential comes from — and the agent-preset authoring plane, `agentPreset.read`/`copy`/`openDocument`/`remove`, since a composition names the plugins a session runs, so reading one is reconnaissance, and copy/remove/openDocument manage the roster and drive the host desktop (authoring is copy-only, so none of them accepts composition text or a path); `agentPreset.list` and `agentPreset.select` stay out — the roster carries only ids and trust, and choosing a preset grants nothing `session.create`'s own `agentPreset` did not, over a default that already carries bash) to loopback by passing the trust fence with an empty trust list — a declared `trustedHosts` authority reaches every other method, while these stay loopback-local until a real authentication layer exists. The platform carriers and ConnectionController loop are package-internal; apply selects and drives them. The downlink boundary is documented in the [WebSocket downlink carrier Agent Note](../../../.agents/notes/implemented/architecture/2026-08-04-websocket-downlink-carrier.md). + +## /api browser-trust fence + +The node half guards every entry under `/api` before bridging or upgrading (`src/api-request-trust.ts`). Every request — browser-marked or not — must present a `Host` that is a loopback authority or matches a `trustedHosts` entry: exact on `host:port` entries, any port on port-less entries, both sides compared through WHATWG normalization (DNS-rebinding defense). There is deliberately no shortcut for unmarked HTTP requests: over plain HTTP a browser attaches neither `Origin` nor Fetch-Metadata to image and navigation reads, so an unmarked request may still be a rebound browser read with a readable response, and Host is the one header rebinding cannot forge; a browser WebSocket handshake carries `Origin` and passes the same comparison. Non-browser clients pass the same fence via loopback, deployment-derived LAN IP literals, or a declared authority. When markers are present, an attached `Origin` must equal the Host authority, and an explicit `sec-fetch-site: cross-site` marker is refused. A `trustedHosts` entry that is not a bare, canonical `host[:port]` authority — one WHATWG parsing reads back exactly as written — fails the plugin load loudly: parsing would otherwise quietly authorize the hostname inside `harness.internal/path`, or broaden a dangling-colon or zero-padded port to an any-port grant. HTTP failures answer plain 403 before any RPC dispatch; upgrade failures reject the handshake before any event stream starts. Non-loopback compositions must trust their serving authorities explicitly: the Web runtime derives LAN IP literals from an all-interfaces server config, while `trustedHosts` in cordis.yml and the CLI's `--trusted-host` flag declare named authorities. `dsh web --host 0.0.0.0` is intentionally unsupported until remote access has an authentication layer. The fence is a reachability policy, not authentication; the Web carrier provides no authentication layer. Decision record: [the api browser-trust boundary Agent Note](../../../.agents/notes/implemented/architecture/2026-07-28-api-browser-trust-boundary.md). + +## `/api` WebSocket downlinks + +`/api/events.mux` and `/api/events.host` each accept a WebSocket upgrade and send only the corresponding `ServerRequest` text messages to the browser; the client sends no application data over these sockets. If either socket ends, the current connection generation fails and rebuilds both streams; readiness still requires both sockets to be open and the `host.describe` HTTP call to succeed. Host teardown terminates both sockets, aborts their sources, and waits for source cleanup before returning. Ordinary network GETs to these paths return 426 with no SSE fallback; `toFetchHandler`'s SSE codec serves only the isomorphic in-process carrier. + +## Model Experience + +None, as the wire consumer layer moves already-composed messages between browser and host; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **History resumes an unattached session** — opening history may create the host-side agent and add latency to the first open; there is no persistence-only read path. +- **The `/api` bridge buffers each request body in memory** — `maxRequestBodyBytes` (default 160 MiB, sized for the default 100 MiB aggregate image limit after base64 expansion plus envelope headroom) is therefore also the per-request resident bound; a streaming body path would be needed to lower it without shrinking the image limits. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.zh.md new file mode 100644 index 0000000..b529eeb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/README.zh.md @@ -0,0 +1,26 @@ +# @deepseek-ai/dsh-client-connection + +[English](README.md) | 中文 + +协议消费层:客户端插件的 apply 会挂载 `ctx.connection`(共享 API 客户端 + 当前页面的 loopback 状态 + 可观察且按 generation 生效的 `hostDescription` + 单消费方流循环启动器);导出表层携带协议约定类型、`AbstractApiClient` 抽象,以及循环的 sink/配置类型。每次就绪握手成功后,都会在 `onConnected` 之前发布完整的 `host.describe` 值;generation 失效或显式 stop 会清空它,因此原生能力消费者不会保留已经断线的判断。浏览器载体以 HTTP POST 发送 unary/respond,并为 `events.mux` 与 `events.host` 各开一条只下行的 WebSocket;进程内载体满足同一双流抽象。Host half 持有唯一 `/api` route 及其 Fetch bridge;已注册的 Typert interceptor 会先认领自己的 Remote endpoint,未认领请求再回退 API Proxy。Loopback hostname 判定逻辑留在包内部:`/api` Host fence 与 WebSocket upgrade 会直接使用它,其他客户端插件则消费派生的 `ctx.connection.isLoopback` 状态。node 半侧的 `/api` 路由让特权方法集(`host.pickDirectory`、`host.openPath`,以及整个配置面——`settings.describe`/`openDocument`/`update`/`replace`/`mutate` 与 `credentials.describe`/`set`/`unset`;读取与原生操作也在内,因为 describe 会返回已暴露的配置、打开操作会作用于 Host 桌面,而探测任意引用会报出某条凭据来自何处——以及 agent(智能体) preset 的创作面 `agentPreset.read`/`copy`/`openDocument`/`remove`,因为组装指明了一个会话所运行的插件,读取它是侦察,而 copy/remove/openDocument 管理名单并驱动宿主桌面(创作只有复制一种写入,因此这些方法都不接收组装文本或路径);`agentPreset.list` 与 `agentPreset.select` 不在其中——名单只携带 id 与信任级别,而选择一个 preset 并不比 `session.create` 自带的 `agentPreset` 多给任何能力,何况默认 preset 本就带着 bash)以空信任表过信任 fence,从而钉在回环——已声明的 `trustedHosts` 授权可达其余全部方法,而这些方法在真正的认证层出现之前仍只限回环本机。平台载体与 ConnectionController 循环属于包内部;apply 负责选择并驱动它们。下行边界见 [WebSocket 下行载体 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-04-websocket-downlink-carrier.md)。 + +## /api 浏览器信任栅栏 + +node 半侧在桥接或 upgrade 前守卫 `/api` 下的每个入口(`src/api-request-trust.ts`)。每个请求——无论是否带浏览器标记——`Host` 都必须是回环地址权威,或与某个 `trustedHosts` 条目匹配:带端口的 `host:port` 条目精确匹配,不带端口的条目匹配任意端口,两侧均经 WHATWG 归一化后比较(DNS rebinding 防御)。刻意不为无浏览器标记的 HTTP 请求开捷径:明文 HTTP 下浏览器的图片与导航读取既不带 `Origin` 也不带 Fetch-Metadata,因此无标记请求仍可能是被重绑页面发起的、响应可被读走的读取,而 Host 是重绑唯一伪造不了的请求头;WebSocket 浏览器握手会带 `Origin` 并通过同一道比较。非浏览器客户端经由回环地址、部署推导的 LAN IP 字面量或已声明的权威通过同一道栅栏。当标记存在时,如附带 `Origin`,则它必须与 Host 权威完全一致;显式的 `sec-fetch-site: cross-site` 标记一律拒绝。不是纯的、规范形 `host[:port]` 权威的 `trustedHosts` 条目——即 WHATWG 解析读回后与原文不完全一致的——会让插件加载明确报错:否则解析会悄悄授权 `harness.internal/path` 这类笔误里的 hostname,或把悬空冒号、补零端口放大成任意端口授权。HTTP 失败在任何 RPC 分发之前以纯 403 应答,upgrade 失败在启动任何事件流前拒绝握手。非回环组合必须显式信任其服务权威:Web 运行时从全接口服务器配置推导 LAN IP 字面量,cordis.yml 中的 `trustedHosts` 与 CLI(命令行界面)的 `--trusted-host` flag 则声明具名权威。`dsh web --host 0.0.0.0` 在远程访问具备认证层之前有意不受支持。这道栅栏是可达性策略,而不是认证;Web 载体不提供认证层。决策记录:[api 浏览器信任边界 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-28-api-browser-trust-boundary.md)。 + +## `/api` WebSocket 下行 + +`/api/events.mux` 与 `/api/events.host` 各接受一条 WebSocket upgrade,并只向浏览器发送对应的 `ServerRequest` 文本消息;客户端不会在这些 socket 上发送业务数据。任一 socket 结束都会使当前 connection generation 失败并重建两条流,连接就绪仍要求两条 socket 均已打开且 `host.describe` HTTP 调用成功。Host teardown 会终止两条 socket、中止各自的 source,并等待 source 清理完成后再返回。普通网络 GET 这些路径会返回 426,不保留 SSE(Server-Sent Events)回退;`toFetchHandler` 的 SSE 编解码只服务进程内同构载体。 + +## 模型体验 + +无。协议消费层只在浏览器与主机之间搬运已经组合好的消息;这里没有任何内容进入模型请求。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **History 会恢复未附加的会话**:打开 history 可能创建宿主侧 agent,并增加首次打开的延迟;没有仅从持久化读取的路径。 +- **`/api` 桥把每个请求体整体缓冲在内存里**:`maxRequestBodyBytes`(默认 160 MiB,按默认 100 MiB 图片总量上限经 base64 膨胀加信封余量得出)因此同时是单请求的驻留内存上界;要降低它而不缩小图片限额,需要流式请求体路径。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/client.js new file mode 100644 index 0000000..81240d6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/client.js @@ -0,0 +1,10207 @@ +window.__ModuleLoader__.load({ + id: "@deepseek-ai/dsh-client-connection", + factory: (require) => { + var module = { exports: {} }; + var exports = module.exports; + Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); + //#region lib/types/client/connection.js + const CONNECTION_DEFAULTS = { + backoffBaseMs: 500, + backoffFactor: 2, + backoffMaxMs: 1e4, + streamOpenTimeoutMs: 3e3 + }; + function sleep(ms, signal) { + return new Promise((resolve) => { + const t = setTimeout(done, ms); + signal.addEventListener("abort", done, { once: true }); + function done() { + clearTimeout(t); + signal.removeEventListener("abort", done); + resolve(); + } + }); + } + /** + * Opens both streams and keeps iterating (pull mode: nothing reads the socket and the tap + * never fires unless someone for-awaits), reconnecting with exponential backoff on loss. + * State (generation/attempt) is instance-private, never in the store. + * The pump body feeds each frame to a sink (sink exceptions must + * not kill the pump — a broken business layer must not drag down the connection layer). + */ + var ConnectionController = class { + api; + sinks; + generation = 0; + attempt = 0; + current = null; + running = false; + lastState = null; + config; + constructor(api, sinks = {}, config = {}) { + this.api = api; + this.sinks = sinks; + this.config = { + ...CONNECTION_DEFAULTS, + ...config + }; + } + /** Idempotent: begin the connect/pump/reconnect loop. */ + start() { + if (this.running) return; + this.running = true; + this.loop(); + } + /** Stop the loop and abort the current generation's streams. */ + stop() { + this.running = false; + this.current?.abort(); + this.current = null; + } + backoffDelay(attempt) { + const { backoffBaseMs, backoffFactor, backoffMaxMs } = this.config; + const cap = Math.min(backoffMaxMs, backoffBaseMs * backoffFactor ** Math.max(0, attempt - 1)); + return cap / 2 + Math.random() * (cap / 2); + } + /** Read through a method: stop() flips the flag across awaits, so narrowing from the loop condition must not stick. */ + isRunning() { + return this.running; + } + /** Re-read both mutable liveness guards after a potentially reentrant sink. */ + isGenerationActive(controller) { + return this.isRunning() && !controller.signal.aborted; + } + async loop() { + while (this.running) { + const gen = ++this.generation; + const ac = new AbortController(); + this.current = ac; + /* v8 ignore next -- initializer placeholder: the Promise executor + * below runs synchronously and replaces it before anyone can call it. */ + let muxOpened = () => {}; + /* v8 ignore next -- same placeholder pattern as muxOpened. */ + let hostOpened = () => {}; + const streamsOpen = Promise.all([new Promise((resolve) => { + muxOpened = resolve; + }), new Promise((resolve) => { + hostOpened = resolve; + })]); + const failed = new Promise((resolve) => { + const settle = () => { + if (gen === this.generation && !ac.signal.aborted) ac.abort(); + resolve(); + }; + this.pumpStream(this.api.events.mux({}, ac.signal, muxOpened), this.sinks.onMuxEnvelope, settle); + this.pumpStream(this.api.events.host({}, ac.signal, hostOpened), this.sinks.onHostEnvelope, settle); + }); + try { + const timeout = new AbortController(); + const [description] = await Promise.all([this.api.host.describe({}), Promise.race([streamsOpen, sleep(this.config.streamOpenTimeoutMs, timeout.signal)])]); + timeout.abort(); + const descriptionResult = description.result; + if (!descriptionResult.ok) throw new Error(`host.describe failed: ${descriptionResult.error.code}: ${descriptionResult.error.message}`); + if (ac.signal.aborted) throw new Error("generation aborted during readiness handshake"); + this.attempt = 0; + this.emitState("connected"); + if (this.isGenerationActive(ac)) this.callSink(() => { + this.sinks.onConnected?.(descriptionResult.value); + }); + } catch { + if (!ac.signal.aborted) ac.abort(); + } + await failed; + if (!this.isRunning()) return; + this.emitState("reconnecting"); + this.attempt += 1; + console.warn(`[web-runtime] connection lost, retry #${this.attempt}`); + const idle = new AbortController(); + await sleep(this.backoffDelay(this.attempt), idle.signal); + } + } + /** Deduplicated state emission (sink isolation applies). */ + emitState(state) { + if (this.lastState === state) return; + this.lastState = state; + this.callSink(() => this.sinks.onStateChange?.(state)); + } + async pumpStream(stream, sink, onEnd) { + try { + for await (const envelope of stream) { + if (envelope.payload.type === "stream/error") break; + if (sink !== void 0) this.callSink(() => { + sink(envelope); + }); + } + } catch {} + onEnd(); + } + /** Sink exception isolation: a business-layer throw is logged only, never affecting pump or reconnect semantics. */ + callSink(fn) { + try { + fn(); + } catch (error) { + console.error("[web-runtime] connection sink threw:", error); + } + } + }; + //#endregion + //#region ../../llm/llm/lib/types/brand.js + /** + * dsh-llm's owned branded ids: tool-call correlation and provider request + * diagnostics. + * + * The `Branded` primitive itself lives in `@deepseek-ai/dsh-brand` (a + * zero-dependency type-only package) so every owner of a cross-boundary id can + * brand it without depending on dsh-llm; see that package's README for the + * nominal-typing policy. + * + * @module @deepseek-ai/dsh-llm/brand + */ + /** + * Brand a message identifier. + * @param id - the opaque message identifier. + * @returns the same string, branded; no validation is performed. + */ + function MessageId(id) { + return id; + } + /** + * Brand a string as a {@link CallId}. + * @param id - the provider-issued (or synthesized) call id. + * @returns the same string, branded; no validation is performed. + */ + function CallId(id) { + return id; + } + //#endregion + //#region ../../llm/llm/lib/types/call-config.js + /** + * Deep-freeze a value in place with an iterative traversal, guarding cycles, + * so later mutation throws without imposing a JavaScript call-stack depth cap. + * {@link AbortSignal} objects are deliberately skipped because they are the + * request's live cancellation channel and freezing them breaks abort. + * @param value - the value to freeze in place. + * @returns the same value, frozen. + */ + function deepFreeze(value) { + const seen = /* @__PURE__ */ new WeakSet(); + const pending = [{ + kind: "visit", + node: value + }]; + while (pending.length > 0) { + const task = pending.pop(); + /* v8 ignore next -- the loop condition guarantees one pending task. */ + if (task === void 0) continue; + if (task.kind === "property") { + pending.push({ + kind: "visit", + node: task.source[task.key] + }); + continue; + } + const node = task.node; + if (node === null || typeof node !== "object") continue; + if (node instanceof AbortSignal) continue; + if (seen.has(node)) continue; + seen.add(node); + Object.freeze(node); + const keys = Object.keys(node); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === void 0) continue; + pending.push({ + kind: "property", + source: node, + key + }); + } + } + return value; + } + //#endregion + //#region ../../llm/llm/lib/types/message.js + /** Message value types, identity, and immutable construction helpers. */ + /** + * Detach and deep-freeze a message whose identity already exists. + * @param message - complete message, including its stable identity. + * @returns an immutable snapshot that preserves the identity. + */ + function freezeMessage(message) { + return deepFreeze(structuredClone(message)); + } + /** + * Create one identified message and freeze it before publication. + * @param input - complete role, content, and source for a new message. + * @returns an immutable message with a fresh stable identity. + */ + function createMessage(input) { + return freezeMessage({ + ...input, + id: MessageId(crypto.randomUUID()) + }); + } + /** + * Create one identified user-role message and freeze it before publication. + * @param input - complete content and source for a new user message. + * @returns an immutable user message with a fresh stable identity. + */ + function createUserMessage(input) { + return createMessage({ + ...input, + role: "user" + }); + } + /** + * Create one identified model-produced assistant message and freeze it before publication. + * @param input - complete content plus the provider, model, and optional replay state for a new assistant message. + * @returns an immutable assistant message with fixed role/source tags and a fresh stable identity. + */ + function createAssistantMessage(input) { + return createMessage({ + role: "assistant", + content: input.content, + source: { + kind: "model", + ...input.source + } + }); + } + /** + * Create and freeze one identified tool-result message. + * @param input - call identity, raw result blocks, and outcome. + * @returns an immutable user-role tool-result message. + */ + function createToolResultMessage(input) { + return createUserMessage({ + source: { + kind: "tool", + callId: input.callId + }, + content: [{ + type: "tool-result", + toolCallId: input.callId, + content: input.content, + isError: input.isError + }] + }); + } + /** + * Whether a stream chunk carries visible model output (the first-token + * boundary shared by client step timing and the whole-log sessionStats + * projection). Empty deltas (heartbeats, empty tool-call frames) do not count + * as a first token. + * @param chunk - the stream chunk to test. + * @returns true when the chunk contains a non-empty text/reasoning/tool delta. + */ + function isTokenDelta(chunk) { + switch (chunk.type) { + case "text-delta": + case "reasoning-delta": return chunk.text !== ""; + case "tool-call-delta": return chunk.argumentsDelta !== "" || chunk.name !== void 0; + default: return false; + } + } + //#endregion + //#region ../../core/session/lib/types/surface.js + /** + * Surface layer on top of the session event log: an ordered view of events + * that produce LLM messages. The append-only log remains the source of truth. + * + * Browser-safe: web clients consume this subpath export, so it must stay free + * of `node:` imports (they break the vite bundle). + * + * @module @deepseek-ai/dsh-session/surface + */ + /** Runtime counterpart of the message-producing event union. */ + const SURFACE_EVENT_TYPES = new Set([ + "user/message", + "assistant/message", + "tool/result" + ]); + /** + * Whether an event type can join the model-visible surface. + * @param type - event type to test. + * @returns true for one of the three message-producing event types. + */ + function isSurfaceEligibleType(type) { + return SURFACE_EVENT_TYPES.has(type); + } + /** + * Project a single event into the LLM message it derives to, or null when it + * produces none — a non-surface event (chunk, boundary, log-only record) or an + * empty-content assistant/message (which exists only to host usage). This is + * THE per-node projection rule: `Session.deriveMessages` folds it over the + * live surface, external reconstructors and pure projections fold the same + * function over a log prefix's surface to rebuild the exact messages any + * request was built from. The returned message is the already frozen message + * nested in the event wrapper and shared by delivery, durable history, and + * model requests. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ + function deriveEventMessage(event) { + switch (event.type) { + case "user/message": return event.data; + case "assistant/message": + if (event.data.message.content.length === 0) return null; + return event.data.message; + case "tool/result": return event.data.message; + default: return null; + } + } + /** Create an empty surface fold state. */ + function createFoldState() { + return { + nodes: [], + replaceGeneration: 0 + }; + } + /** Whether a runtime value is a non-negative safe event sequence. */ + function isEventSeq(value) { + return typeof value === "number" && Number.isSafeInteger(value) && value >= 0; + } + /** Whether a runtime value is the exact positional-replacement shape. */ + function isReplaceOp(value) { + const op = value; + return Object.keys(op).length === 3 && Object.hasOwn(op, "op") && Object.hasOwn(op, "start") && Object.hasOwn(op, "end") && op["op"] === "replace" && isEventSeq(op["start"]) && isEventSeq(op["end"]); + } + /** Validate event-local surface eligibility and return its operation. */ + function surfaceOpOf(event) { + const raw = event; + if (!isSurfaceEligibleType(event.type)) { + if (raw.surfaceOp !== void 0) throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry surfaceOp`); + if (raw.sourceEventSeqs !== void 0) throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry sourceEventSeqs`); + return; + } + const op = raw.surfaceOp; + if (op === void 0) throw new Error(`session event "${event.type}" is surface-eligible and requires a surfaceOp marker`); + if (op === "append") return op; + if (op === null || typeof op !== "object" || Array.isArray(op)) throw new Error(`session event "${event.type}" carries an invalid surfaceOp`); + if (!isReplaceOp(op)) throw new Error(`session event "${event.type}" carries an invalid replace surfaceOp`); + return op; + } + /** Validate cited source-event seqs against prior log entries and the replacement range. */ + function assertProvenance(event, shadowedSeqs) { + const raw = event.sourceEventSeqs; + const sources = /* @__PURE__ */ new Set(); + if (raw !== void 0) { + if (!Array.isArray(raw)) throw new Error(`sourceEventSeqs on event at seq ${event.seq} must be an array when present`); + if (raw.length === 0 && event.type !== "assistant/message") throw new Error("sourceEventSeqs must not be empty except on assistant/message"); + let nonEarlierSource; + for (const source of raw) { + if (!isEventSeq(source)) throw new Error(`session event "${event.type}" sourceEventSeqs must densely contain non-negative safe integers`); + sources.add(source); + if (nonEarlierSource === void 0 && source >= event.seq) nonEarlierSource = source; + } + if (sources.size !== raw.length) throw new Error("sourceEventSeqs must not contain duplicates"); + if (nonEarlierSource !== void 0) throw new Error(`sourceEventSeqs must reference earlier events: ${nonEarlierSource} >= current seq ${event.seq}`); + } + const missing = shadowedSeqs.filter((seq) => !sources.has(seq)); + if (missing.length > 0) throw new Error(`surface replace: sourceEventSeqs must include every shadowed surface node; missing ${missing.join(", ")}`); + } + /** Locate one replacement range without mutating the current fold state. */ + function replacementRange(state, op) { + const startIdx = state.nodes.indexOf(op.start); + if (startIdx === -1) throw new Error(`surface replace: start seq ${op.start} not found in surface`); + const endIdx = state.nodes.indexOf(op.end); + if (endIdx === -1) throw new Error(`surface replace: end seq ${op.end} not found in surface`); + if (startIdx > endIdx) throw new Error(`surface replace: start seq ${op.start} (index ${startIdx}) is after end seq ${op.end} (index ${endIdx})`); + return { + startIdx, + endIdx, + shadowedSeqs: state.nodes.slice(startIdx, endIdx + 1) + }; + } + /** + * Deep structural equality over the session-event JSON value domain + * (null/boolean/number/string, arrays, plain objects). Replaces + * `node:util`'s isDeepStrictEqual to keep this module browser-safe. + */ + function isDeepEqualJson(a, b) { + if (a === b) return true; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false; + return a.every((item, i) => isDeepEqualJson(item, b[i])); + } + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false; + const aKeys = Object.keys(a); + const bRecord = b; + if (aKeys.length !== Object.keys(b).length) return false; + return aKeys.every((key) => Object.hasOwn(b, key) && isDeepEqualJson(a[key], bRecord[key])); + } + /** Restrict a tool-result replacement to one current result's content. */ + function assertToolResultRewrite(event, shadowedSeqs, events, baseSeq) { + if (event.type !== "tool/result") return; + if (shadowedSeqs.length !== 1) throw new Error("tool/result surface replacement must rewrite exactly one current node"); + for (const originalSeq of shadowedSeqs) { + const original = events[originalSeq - baseSeq]; + if (original?.type !== "tool/result") throw new Error("tool/result surface replacement must target a current tool/result"); + const originalRest = { ...original.data }; + const replacementRest = { ...event.data }; + const originalResult = original.data.message.content[0]; + const replacementResult = event.data.message.content[0]; + originalRest["message"] = { + ...original.data.message, + content: [{ + ...originalResult, + content: null + }] + }; + replacementRest["message"] = { + ...event.data.message, + content: [{ + ...replacementResult, + content: null + }] + }; + if (!isDeepEqualJson(originalRest, replacementRest)) throw new Error("tool/result surface replacement may change only content"); + } + } + /** Validate one event at its replay boundary and prepare its atomic fold transition. */ + function planSurfaceEvent(state, event, expectedSeq, events, baseSeq) { + if (event.seq !== expectedSeq) throw new Error(`session event seq ${event.seq} is not contiguous; expected ${expectedSeq}`); + const surfaceOp = surfaceOpOf(event); + if (surfaceOp === void 0) return; + if (surfaceOp === "append") { + assertProvenance(event, []); + return { + kind: "append", + seq: event.seq + }; + } + const range = replacementRange(state, surfaceOp); + assertProvenance(event, range.shadowedSeqs); + assertToolResultRewrite(event, range.shadowedSeqs, events, baseSeq); + return { + kind: "replace", + seq: event.seq, + start: surfaceOp.start, + end: surfaceOp.end, + ...range + }; + } + /** Apply one event and return replacement metadata only when one occurred. */ + function applySurfaceEvent(state, event, expectedSeq, events, baseSeq) { + return applySurfacePlan(state, planSurfaceEvent(state, event, expectedSeq, events, baseSeq)); + } + /** Commit one previously validated surface transition. */ + function applySurfacePlan(state, plan) { + if (plan?.kind === "append") state.nodes.push(plan.seq); + else if (plan?.kind === "replace") { + state.nodes.splice(plan.startIdx, plan.endIdx - plan.startIdx + 1, plan.seq); + state.replaceGeneration += 1; + } + if (plan?.kind !== "replace") return; + return { + seq: plan.seq, + start: plan.start, + end: plan.end, + shadowedSeqs: plan.shadowedSeqs + }; + } + /** + * Replay a complete session log through the canonical surface fold. + * @param events - session events in contiguous seq order. + * @returns detached current sequences and replacement history. + * @throws when an event violates surface metadata, source-event references, range, or tool-result rewrite rules. + */ + function foldSurface(events) { + const state = createFoldState(); + const replacements = []; + for (const [index, event] of events.entries()) { + const replacement = applySurfaceEvent(state, event, index, events, 0); + if (replacement !== void 0) replacements.push(replacement); + } + return { + nodes: [...state.nodes], + replacements + }; + } + //#endregion + //#region ../../host/apiproxy/lib/types/api/rpc.js + /** + * Four-quadrant RPC message model. Channels and messages are decoupled: HTTP, + * WebSocket, and in-process SSE are physical carriers, while logical messages + * are channel-independent and form a four-member discriminated union. + * api/ contract layer: zero Node dependencies, importable from the browser. + */ + /** + * Brands a string as RpcId (same precedent as core `SessionId()`). Minted by the initiator: + * client-request → client mints; server-request → host mints (answerable frames get a stable + * logical id, pure pushes mint a fresh one each time). + * @param id - Raw id string (implementations mint UUIDs; tests may pass fixtures). + * @returns The same string, branded (compile-time cast, zero runtime cost). + */ + function RpcId(id) { + return id; + } + /** + * Fold a transport exception into the RpcResult error branch (unified error + * API; 'internal' as the catch-all code). Lives with RpcResult so every + * carrier consumer folds the same way. + * @param error - the thrown value from the carrier. + * @returns the error branch of an RpcResult. + */ + function transportError(error) { + return { + ok: false, + error: { + code: "internal", + message: error instanceof Error ? error.message : String(error), + details: {} + } + }; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js + var _a$1; + function $constructor(name, initializer, params) { + function init(inst, def) { + if (!inst._zod) Object.defineProperty(inst, "_zod", { + value: { + def, + constr: _, + traits: /* @__PURE__ */ new Set() + }, + enumerable: false + }); + if (inst._zod.traits.has(name)) return; + inst._zod.traits.add(name); + initializer(inst, def); + const proto = _.prototype; + const keys = Object.keys(proto); + for (let i = 0; i < keys.length; i++) { + const k = keys[i]; + if (!(k in inst)) inst[k] = proto[k].bind(inst); + } + } + const Parent = params?.Parent ?? Object; + class Definition extends Parent {} + Object.defineProperty(Definition, "name", { value: name }); + function _(def) { + var _a; + const inst = params?.Parent ? new Definition() : this; + init(inst, def); + (_a = inst._zod).deferred ?? (_a.deferred = []); + for (const fn of inst._zod.deferred) fn(); + return inst; + } + Object.defineProperty(_, "init", { value: init }); + Object.defineProperty(_, Symbol.hasInstance, { value: (inst) => { + if (params?.Parent && inst instanceof params.Parent) return true; + return inst?._zod?.traits?.has(name); + } }); + Object.defineProperty(_, "name", { value: name }); + return _; + } + var $ZodAsyncError = class extends Error { + constructor() { + super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`); + } + }; + var $ZodEncodeError = class extends Error { + constructor(name) { + super(`Encountered unidirectional transform during encode: ${name}`); + this.name = "ZodEncodeError"; + } + }; + (_a$1 = globalThis).__zod_globalConfig ?? (_a$1.__zod_globalConfig = {}); + const globalConfig = globalThis.__zod_globalConfig; + function config(newConfig) { + if (newConfig) Object.assign(globalConfig, newConfig); + return globalConfig; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.js + function getEnumValues(entries) { + const numericValues = Object.values(entries).filter((v) => typeof v === "number"); + return Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v); + } + function jsonStringifyReplacer(_, value) { + if (typeof value === "bigint") return value.toString(); + return value; + } + function cached(getter) { + return { get value() { + { + const value = getter(); + Object.defineProperty(this, "value", { value }); + return value; + } + throw new Error("cached value already set"); + } }; + } + function nullish(input) { + return input === null || input === void 0; + } + function cleanRegex(source) { + const start = source.startsWith("^") ? 1 : 0; + const end = source.endsWith("$") ? source.length - 1 : source.length; + return source.slice(start, end); + } + function floatSafeRemainder(val, step) { + const ratio = val / step; + const roundedRatio = Math.round(ratio); + const tolerance = Number.EPSILON * Math.max(Math.abs(ratio), 1); + if (Math.abs(ratio - roundedRatio) < tolerance) return 0; + return ratio - roundedRatio; + } + const EVALUATING = /* @__PURE__*/ Symbol("evaluating"); + function defineLazy(object, key, getter) { + let value = void 0; + Object.defineProperty(object, key, { + get() { + if (value === EVALUATING) return; + if (value === void 0) { + value = EVALUATING; + value = getter(); + } + return value; + }, + set(v) { + Object.defineProperty(object, key, { value: v }); + }, + configurable: true + }); + } + function assignProp(target, prop, value) { + Object.defineProperty(target, prop, { + value, + writable: true, + enumerable: true, + configurable: true + }); + } + function mergeDefs(...defs) { + const mergedDescriptors = {}; + for (const def of defs) Object.assign(mergedDescriptors, Object.getOwnPropertyDescriptors(def)); + return Object.defineProperties({}, mergedDescriptors); + } + function esc(str) { + return JSON.stringify(str); + } + function slugify(input) { + return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, ""); + } + const captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {}; + function isObject(data) { + return typeof data === "object" && data !== null && !Array.isArray(data); + } + const allowsEval = /* @__PURE__*/ cached(() => { + if (globalConfig.jitless) return false; + if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) return false; + try { + new Function(""); + return true; + } catch (_) { + return false; + } + }); + function isPlainObject(o) { + if (isObject(o) === false) return false; + const ctor = o.constructor; + if (ctor === void 0) return true; + if (typeof ctor !== "function") return true; + const prot = ctor.prototype; + if (isObject(prot) === false) return false; + if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) return false; + return true; + } + function shallowClone(o) { + if (isPlainObject(o)) return { ...o }; + if (Array.isArray(o)) return [...o]; + if (o instanceof Map) return new Map(o); + if (o instanceof Set) return new Set(o); + return o; + } + const propertyKeyTypes = /* @__PURE__*/ new Set([ + "string", + "number", + "symbol" + ]); + function escapeRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + } + function clone(inst, def, params) { + const cl = new inst._zod.constr(def ?? inst._zod.def); + if (!def || params?.parent) cl._zod.parent = inst; + return cl; + } + function normalizeParams(_params) { + const params = _params; + if (!params) return {}; + if (typeof params === "string") return { error: () => params }; + if (params?.message !== void 0) { + if (params?.error !== void 0) throw new Error("Cannot specify both `message` and `error` params"); + params.error = params.message; + } + delete params.message; + if (typeof params.error === "string") return { + ...params, + error: () => params.error + }; + return params; + } + function optionalKeys(shape) { + return Object.keys(shape).filter((k) => { + return shape[k]._zod.optin === "optional" && shape[k]._zod.optout === "optional"; + }); + } + const NUMBER_FORMAT_RANGES = { + safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], + int32: [-2147483648, 2147483647], + uint32: [0, 4294967295], + float32: [-34028234663852886e22, 34028234663852886e22], + float64: [-Number.MAX_VALUE, Number.MAX_VALUE] + }; + function pick(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + if (checks && checks.length > 0) throw new Error(".pick() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const newShape = {}; + for (const key in mask) { + if (!(key in currDef.shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + newShape[key] = currDef.shape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + })); + } + function omit(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + if (checks && checks.length > 0) throw new Error(".omit() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const newShape = { ...schema._zod.def.shape }; + for (const key in mask) { + if (!(key in currDef.shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + delete newShape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + })); + } + function extend(schema, shape) { + if (!isPlainObject(shape)) throw new Error("Invalid input to extend: expected a plain object"); + const checks = schema._zod.def.checks; + if (checks && checks.length > 0) { + const existingShape = schema._zod.def.shape; + for (const key in shape) if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead."); + } + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const _shape = { + ...schema._zod.def.shape, + ...shape + }; + assignProp(this, "shape", _shape); + return _shape; + } })); + } + function safeExtend(schema, shape) { + if (!isPlainObject(shape)) throw new Error("Invalid input to safeExtend: expected a plain object"); + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const _shape = { + ...schema._zod.def.shape, + ...shape + }; + assignProp(this, "shape", _shape); + return _shape; + } })); + } + function merge(a, b) { + if (a._zod.def.checks?.length) throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead."); + return clone(a, mergeDefs(a._zod.def, { + get shape() { + const _shape = { + ...a._zod.def.shape, + ...b._zod.def.shape + }; + assignProp(this, "shape", _shape); + return _shape; + }, + get catchall() { + return b._zod.def.catchall; + }, + checks: b._zod.def.checks ?? [] + })); + } + function partial(Class, schema, mask) { + const checks = schema._zod.def.checks; + if (checks && checks.length > 0) throw new Error(".partial() cannot be used on object schemas containing refinements"); + return clone(schema, mergeDefs(schema._zod.def, { + get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) for (const key in mask) { + if (!(key in oldShape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + shape[key] = Class ? new Class({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + } + else for (const key in oldShape) shape[key] = Class ? new Class({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + assignProp(this, "shape", shape); + return shape; + }, + checks: [] + })); + } + function required(Class, schema, mask) { + return clone(schema, mergeDefs(schema._zod.def, { get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) for (const key in mask) { + if (!(key in shape)) throw new Error(`Unrecognized key: "${key}"`); + if (!mask[key]) continue; + shape[key] = new Class({ + type: "nonoptional", + innerType: oldShape[key] + }); + } + else for (const key in oldShape) shape[key] = new Class({ + type: "nonoptional", + innerType: oldShape[key] + }); + assignProp(this, "shape", shape); + return shape; + } })); + } + function aborted(x, startIndex = 0) { + if (x.aborted === true) return true; + for (let i = startIndex; i < x.issues.length; i++) if (x.issues[i]?.continue !== true) return true; + return false; + } + function explicitlyAborted(x, startIndex = 0) { + if (x.aborted === true) return true; + for (let i = startIndex; i < x.issues.length; i++) if (x.issues[i]?.continue === false) return true; + return false; + } + function prefixIssues(path, issues) { + return issues.map((iss) => { + var _a; + (_a = iss).path ?? (_a.path = []); + iss.path.unshift(path); + return iss; + }); + } + function unwrapMessage(message) { + return typeof message === "string" ? message : message?.message; + } + function finalizeIssue(iss, ctx, config) { + const message = iss.message ? iss.message : unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config.customError?.(iss)) ?? unwrapMessage(config.localeError?.(iss)) ?? "Invalid input"; + const { inst: _inst, continue: _continue, input: _input, ...rest } = iss; + rest.path ?? (rest.path = []); + rest.message = message; + if (ctx?.reportInput) rest.input = _input; + return rest; + } + function getLengthableOrigin(input) { + if (Array.isArray(input)) return "array"; + if (typeof input === "string") return "string"; + return "unknown"; + } + function issue(...args) { + const [iss, input, inst] = args; + if (typeof iss === "string") return { + message: iss, + code: "custom", + input, + inst + }; + return { ...iss }; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/errors.js + const initializer$1 = (inst, def) => { + inst.name = "$ZodError"; + Object.defineProperty(inst, "_zod", { + value: inst._zod, + enumerable: false + }); + Object.defineProperty(inst, "issues", { + value: def, + enumerable: false + }); + inst.message = JSON.stringify(def, jsonStringifyReplacer, 2); + Object.defineProperty(inst, "toString", { + value: () => inst.message, + enumerable: false + }); + }; + const $ZodError = $constructor("$ZodError", initializer$1); + const $ZodRealError = $constructor("$ZodError", initializer$1, { Parent: Error }); + function flattenError(error, mapper = (issue) => issue.message) { + const fieldErrors = {}; + const formErrors = []; + for (const sub of error.issues) if (sub.path.length > 0) { + fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || []; + fieldErrors[sub.path[0]].push(mapper(sub)); + } else formErrors.push(mapper(sub)); + return { + formErrors, + fieldErrors + }; + } + function formatError(error, mapper = (issue) => issue.message) { + const fieldErrors = { _errors: [] }; + const processError = (error, path = []) => { + for (const issue of error.issues) if (issue.code === "invalid_union" && issue.errors.length) issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path])); + else if (issue.code === "invalid_key") processError({ issues: issue.issues }, [...path, ...issue.path]); + else if (issue.code === "invalid_element") processError({ issues: issue.issues }, [...path, ...issue.path]); + else { + const fullpath = [...path, ...issue.path]; + if (fullpath.length === 0) fieldErrors._errors.push(mapper(issue)); + else { + let curr = fieldErrors; + let i = 0; + while (i < fullpath.length) { + const el = fullpath[i]; + if (!(i === fullpath.length - 1)) curr[el] = curr[el] || { _errors: [] }; + else { + curr[el] = curr[el] || { _errors: [] }; + curr[el]._errors.push(mapper(issue)); + } + curr = curr[el]; + i++; + } + } + } + }; + processError(error); + return fieldErrors; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/parse.js + const _parse = (_Err) => (schema, value, _ctx, _params) => { + const ctx = _ctx ? { + ..._ctx, + async: false + } : { async: false }; + const result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) throw new $ZodAsyncError(); + if (result.issues.length) { + const e = new ((_params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, _params?.callee); + throw e; + } + return result.value; + }; + const _parseAsync = (_Err) => async (schema, value, _ctx, params) => { + const ctx = _ctx ? { + ..._ctx, + async: true + } : { async: true }; + let result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) result = await result; + if (result.issues.length) { + const e = new ((params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, params?.callee); + throw e; + } + return result.value; + }; + const _safeParse = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + async: false + } : { async: false }; + const result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) throw new $ZodAsyncError(); + return result.issues.length ? { + success: false, + error: new (_Err ?? $ZodError)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { + success: true, + data: result.value + }; + }; + const safeParse$1 = /* @__PURE__*/ _safeParse($ZodRealError); + const _safeParseAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + async: true + } : { async: true }; + let result = schema._zod.run({ + value, + issues: [] + }, ctx); + if (result instanceof Promise) result = await result; + return result.issues.length ? { + success: false, + error: new _Err(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { + success: true, + data: result.value + }; + }; + const safeParseAsync$1 = /* @__PURE__*/ _safeParseAsync($ZodRealError); + const _encode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _parse(_Err)(schema, value, ctx); + }; + const _decode = (_Err) => (schema, value, _ctx) => { + return _parse(_Err)(schema, value, _ctx); + }; + const _encodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _parseAsync(_Err)(schema, value, ctx); + }; + const _decodeAsync = (_Err) => async (schema, value, _ctx) => { + return _parseAsync(_Err)(schema, value, _ctx); + }; + const _safeEncode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _safeParse(_Err)(schema, value, ctx); + }; + const _safeDecode = (_Err) => (schema, value, _ctx) => { + return _safeParse(_Err)(schema, value, _ctx); + }; + const _safeEncodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { + ..._ctx, + direction: "backward" + } : { direction: "backward" }; + return _safeParseAsync(_Err)(schema, value, ctx); + }; + const _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => { + return _safeParseAsync(_Err)(schema, value, _ctx); + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/regexes.js + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link cuid2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const cuid = /^[cC][0-9a-z]{6,}$/; + const cuid2 = /^[0-9a-z]+$/; + const ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/; + const xid = /^[0-9a-vA-V]{20}$/; + const ksuid = /^[A-Za-z0-9]{27}$/; + const nanoid = /^[a-zA-Z0-9_-]{21}$/; + /** ISO 8601-1 duration regex. Does not support the 8601-2 extensions like negative durations or fractional/negative components. */ + const duration$1 = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/; + /** A regex for any UUID-like identifier: 8-4-4-4-12 hex pattern */ + const guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/; + /** Returns a regex for validating an RFC 9562/4122 UUID. + * + * @param version Optionally specify a version 1-8. If no version is specified, all versions are supported. */ + const uuid = (version) => { + if (!version) return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/; + return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`); + }; + /** Practical email validation */ + const email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/; + const _emoji$1 = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; + function emoji() { + return new RegExp(_emoji$1, "u"); + } + const ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; + const ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/; + const cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/; + const cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; + const base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/; + const base64url = /^[A-Za-z0-9_-]*$/; + const httpProtocol = /^https?$/; + const e164 = /^\+[1-9]\d{6,14}$/; + const dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`; + const date$1 = /*@__PURE__*/ new RegExp(`^${dateSource}$`); + function timeSource(args) { + const hhmm = `(?:[01]\\d|2[0-3]):[0-5]\\d`; + return typeof args.precision === "number" ? args.precision === -1 ? `${hhmm}` : args.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args.precision}}` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`; + } + function time$1(args) { + return new RegExp(`^${timeSource(args)}$`); + } + function datetime$1(args) { + const time = timeSource({ precision: args.precision }); + const opts = ["Z"]; + if (args.local) opts.push(""); + if (args.offset) opts.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`); + const timeRegex = `${time}(?:${opts.join("|")})`; + return new RegExp(`^${dateSource}T(?:${timeRegex})$`); + } + const string$1 = (params) => { + const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`; + return new RegExp(`^${regex}$`); + }; + const integer = /^-?\d+$/; + const number$1 = /^-?\d+(?:\.\d+)?$/; + const boolean$1 = /^(?:true|false)$/i; + const lowercase = /^[^A-Z]*$/; + const uppercase = /^[^a-z]*$/; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/checks.js + const $ZodCheck = /*@__PURE__*/ $constructor("$ZodCheck", (inst, def) => { + var _a; + inst._zod ?? (inst._zod = {}); + inst._zod.def = def; + (_a = inst._zod).onattach ?? (_a.onattach = []); + }); + const numericOriginMap = { + number: "number", + bigint: "bigint", + object: "date" + }; + const $ZodCheckLessThan = /*@__PURE__*/ $constructor("$ZodCheckLessThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + const curr = (def.inclusive ? bag.maximum : bag.exclusiveMaximum) ?? Number.POSITIVE_INFINITY; + if (def.value < curr) if (def.inclusive) bag.maximum = def.value; + else bag.exclusiveMaximum = def.value; + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value <= def.value : payload.value < def.value) return; + payload.issues.push({ + origin, + code: "too_big", + maximum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckGreaterThan = /*@__PURE__*/ $constructor("$ZodCheckGreaterThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY; + if (def.value > curr) if (def.inclusive) bag.minimum = def.value; + else bag.exclusiveMinimum = def.value; + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value >= def.value : payload.value > def.value) return; + payload.issues.push({ + origin, + code: "too_small", + minimum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMultipleOf = /*@__PURE__*/ $constructor("$ZodCheckMultipleOf", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst) => { + var _a; + (_a = inst._zod.bag).multipleOf ?? (_a.multipleOf = def.value); + }); + inst._zod.check = (payload) => { + if (typeof payload.value !== typeof def.value) throw new Error("Cannot mix number and bigint in multiple_of check."); + if (typeof payload.value === "bigint" ? payload.value % def.value === BigInt(0) : floatSafeRemainder(payload.value, def.value) === 0) return; + payload.issues.push({ + origin: typeof payload.value, + code: "not_multiple_of", + divisor: def.value, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckNumberFormat = /*@__PURE__*/ $constructor("$ZodCheckNumberFormat", (inst, def) => { + $ZodCheck.init(inst, def); + def.format = def.format || "float64"; + const isInt = def.format?.includes("int"); + const origin = isInt ? "int" : "number"; + const [minimum, maximum] = NUMBER_FORMAT_RANGES[def.format]; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.format = def.format; + bag.minimum = minimum; + bag.maximum = maximum; + if (isInt) bag.pattern = integer; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (isInt) { + if (!Number.isInteger(input)) { + payload.issues.push({ + expected: origin, + format: def.format, + code: "invalid_type", + continue: false, + input, + inst + }); + return; + } + if (!Number.isSafeInteger(input)) { + if (input > 0) payload.issues.push({ + input, + code: "too_big", + maximum: Number.MAX_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + else payload.issues.push({ + input, + code: "too_small", + minimum: Number.MIN_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + return; + } + } + if (input < minimum) payload.issues.push({ + origin: "number", + input, + code: "too_small", + minimum, + inclusive: true, + inst, + continue: !def.abort + }); + if (input > maximum) payload.issues.push({ + origin: "number", + input, + code: "too_big", + maximum, + inclusive: true, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMaxLength = /*@__PURE__*/ $constructor("$ZodCheckMaxLength", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const curr = inst._zod.bag.maximum ?? Number.POSITIVE_INFINITY; + if (def.maximum < curr) inst._zod.bag.maximum = def.maximum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (input.length <= def.maximum) return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_big", + maximum: def.maximum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckMinLength = /*@__PURE__*/ $constructor("$ZodCheckMinLength", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const curr = inst._zod.bag.minimum ?? Number.NEGATIVE_INFINITY; + if (def.minimum > curr) inst._zod.bag.minimum = def.minimum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (input.length >= def.minimum) return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_small", + minimum: def.minimum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckLengthEquals = /*@__PURE__*/ $constructor("$ZodCheckLengthEquals", (inst, def) => { + var _a; + $ZodCheck.init(inst, def); + (_a = inst._zod.def).when ?? (_a.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.minimum = def.length; + bag.maximum = def.length; + bag.length = def.length; + }); + inst._zod.check = (payload) => { + const input = payload.value; + const length = input.length; + if (length === def.length) return; + const origin = getLengthableOrigin(input); + const tooBig = length > def.length; + payload.issues.push({ + origin, + ...tooBig ? { + code: "too_big", + maximum: def.length + } : { + code: "too_small", + minimum: def.length + }, + inclusive: true, + exact: true, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckStringFormat = /*@__PURE__*/ $constructor("$ZodCheckStringFormat", (inst, def) => { + var _a, _b; + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.format = def.format; + if (def.pattern) { + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(def.pattern); + } + }); + if (def.pattern) (_a = inst._zod).check ?? (_a.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: def.format, + input: payload.value, + ...def.pattern ? { pattern: def.pattern.toString() } : {}, + inst, + continue: !def.abort + }); + }); + else (_b = inst._zod).check ?? (_b.check = () => {}); + }); + const $ZodCheckRegex = /*@__PURE__*/ $constructor("$ZodCheckRegex", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + inst._zod.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "regex", + input: payload.value, + pattern: def.pattern.toString(), + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckLowerCase = /*@__PURE__*/ $constructor("$ZodCheckLowerCase", (inst, def) => { + def.pattern ?? (def.pattern = lowercase); + $ZodCheckStringFormat.init(inst, def); + }); + const $ZodCheckUpperCase = /*@__PURE__*/ $constructor("$ZodCheckUpperCase", (inst, def) => { + def.pattern ?? (def.pattern = uppercase); + $ZodCheckStringFormat.init(inst, def); + }); + const $ZodCheckIncludes = /*@__PURE__*/ $constructor("$ZodCheckIncludes", (inst, def) => { + $ZodCheck.init(inst, def); + const escapedRegex = escapeRegex(def.includes); + const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex); + def.pattern = pattern; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.includes(def.includes, def.position)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "includes", + includes: def.includes, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckStartsWith = /*@__PURE__*/ $constructor("$ZodCheckStartsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`^${escapeRegex(def.prefix)}.*`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.startsWith(def.prefix)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "starts_with", + prefix: def.prefix, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckEndsWith = /*@__PURE__*/ $constructor("$ZodCheckEndsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`.*${escapeRegex(def.suffix)}$`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.endsWith(def.suffix)) return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "ends_with", + suffix: def.suffix, + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodCheckOverwrite = /*@__PURE__*/ $constructor("$ZodCheckOverwrite", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.check = (payload) => { + payload.value = def.tx(payload.value); + }; + }); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/doc.js + var Doc = class { + constructor(args = []) { + this.content = []; + this.indent = 0; + if (this) this.args = args; + } + indented(fn) { + this.indent += 1; + fn(this); + this.indent -= 1; + } + write(arg) { + if (typeof arg === "function") { + arg(this, { execution: "sync" }); + arg(this, { execution: "async" }); + return; + } + const lines = arg.split("\n").filter((x) => x); + const minIndent = Math.min(...lines.map((x) => x.length - x.trimStart().length)); + const dedented = lines.map((x) => x.slice(minIndent)).map((x) => " ".repeat(this.indent * 2) + x); + for (const line of dedented) this.content.push(line); + } + compile() { + const F = Function; + const args = this?.args; + const lines = [...(this?.content ?? [``]).map((x) => ` ${x}`)]; + return new F(...args, lines.join("\n")); + } + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.js + const version = { + major: 4, + minor: 4, + patch: 3 + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/schemas.js + const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => { + var _a; + inst ?? (inst = {}); + inst._zod.def = def; + inst._zod.bag = inst._zod.bag || {}; + inst._zod.version = version; + const checks = [...inst._zod.def.checks ?? []]; + if (inst._zod.traits.has("$ZodCheck")) checks.unshift(inst); + for (const ch of checks) for (const fn of ch._zod.onattach) fn(inst); + if (checks.length === 0) { + (_a = inst._zod).deferred ?? (_a.deferred = []); + inst._zod.deferred?.push(() => { + inst._zod.run = inst._zod.parse; + }); + } else { + const runChecks = (payload, checks, ctx) => { + let isAborted = aborted(payload); + let asyncResult; + for (const ch of checks) { + if (ch._zod.def.when) { + if (explicitlyAborted(payload)) continue; + if (!ch._zod.def.when(payload)) continue; + } else if (isAborted) continue; + const currLen = payload.issues.length; + const _ = ch._zod.check(payload); + if (_ instanceof Promise && ctx?.async === false) throw new $ZodAsyncError(); + if (asyncResult || _ instanceof Promise) asyncResult = (asyncResult ?? Promise.resolve()).then(async () => { + await _; + if (payload.issues.length === currLen) return; + if (!isAborted) isAborted = aborted(payload, currLen); + }); + else { + if (payload.issues.length === currLen) continue; + if (!isAborted) isAborted = aborted(payload, currLen); + } + } + if (asyncResult) return asyncResult.then(() => { + return payload; + }); + return payload; + }; + const handleCanaryResult = (canary, payload, ctx) => { + if (aborted(canary)) { + canary.aborted = true; + return canary; + } + const checkResult = runChecks(payload, checks, ctx); + if (checkResult instanceof Promise) { + if (ctx.async === false) throw new $ZodAsyncError(); + return checkResult.then((checkResult) => inst._zod.parse(checkResult, ctx)); + } + return inst._zod.parse(checkResult, ctx); + }; + inst._zod.run = (payload, ctx) => { + if (ctx.skipChecks) return inst._zod.parse(payload, ctx); + if (ctx.direction === "backward") { + const canary = inst._zod.parse({ + value: payload.value, + issues: [] + }, { + ...ctx, + skipChecks: true + }); + if (canary instanceof Promise) return canary.then((canary) => { + return handleCanaryResult(canary, payload, ctx); + }); + return handleCanaryResult(canary, payload, ctx); + } + const result = inst._zod.parse(payload, ctx); + if (result instanceof Promise) { + if (ctx.async === false) throw new $ZodAsyncError(); + return result.then((result) => runChecks(result, checks, ctx)); + } + return runChecks(result, checks, ctx); + }; + } + defineLazy(inst, "~standard", () => ({ + validate: (value) => { + try { + const r = safeParse$1(inst, value); + return r.success ? { value: r.data } : { issues: r.error?.issues }; + } catch (_) { + return safeParseAsync$1(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues }); + } + }, + vendor: "zod", + version: 1 + })); + }); + const $ZodString = /*@__PURE__*/ $constructor("$ZodString", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = [...inst?._zod.bag?.patterns ?? []].pop() ?? string$1(inst._zod.bag); + inst._zod.parse = (payload, _) => { + if (def.coerce) try { + payload.value = String(payload.value); + } catch (_) {} + if (typeof payload.value === "string") return payload; + payload.issues.push({ + expected: "string", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; + }); + const $ZodStringFormat = /*@__PURE__*/ $constructor("$ZodStringFormat", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + $ZodString.init(inst, def); + }); + const $ZodGUID = /*@__PURE__*/ $constructor("$ZodGUID", (inst, def) => { + def.pattern ?? (def.pattern = guid); + $ZodStringFormat.init(inst, def); + }); + const $ZodUUID = /*@__PURE__*/ $constructor("$ZodUUID", (inst, def) => { + if (def.version) { + const v = { + v1: 1, + v2: 2, + v3: 3, + v4: 4, + v5: 5, + v6: 6, + v7: 7, + v8: 8 + }[def.version]; + if (v === void 0) throw new Error(`Invalid UUID version: "${def.version}"`); + def.pattern ?? (def.pattern = uuid(v)); + } else def.pattern ?? (def.pattern = uuid()); + $ZodStringFormat.init(inst, def); + }); + const $ZodEmail = /*@__PURE__*/ $constructor("$ZodEmail", (inst, def) => { + def.pattern ?? (def.pattern = email); + $ZodStringFormat.init(inst, def); + }); + const $ZodURL = /*@__PURE__*/ $constructor("$ZodURL", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + try { + const trimmed = payload.value.trim(); + if (!def.normalize && def.protocol?.source === httpProtocol.source) { + if (!/^https?:\/\//i.test(trimmed)) { + payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid URL format", + input: payload.value, + inst, + continue: !def.abort + }); + return; + } + } + const url = new URL(trimmed); + if (def.hostname) { + def.hostname.lastIndex = 0; + if (!def.hostname.test(url.hostname)) payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid hostname", + pattern: def.hostname.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + if (def.protocol) { + def.protocol.lastIndex = 0; + if (!def.protocol.test(url.protocol.endsWith(":") ? url.protocol.slice(0, -1) : url.protocol)) payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid protocol", + pattern: def.protocol.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + if (def.normalize) payload.value = url.href; + else payload.value = trimmed; + return; + } catch (_) { + payload.issues.push({ + code: "invalid_format", + format: "url", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + const $ZodEmoji = /*@__PURE__*/ $constructor("$ZodEmoji", (inst, def) => { + def.pattern ?? (def.pattern = emoji()); + $ZodStringFormat.init(inst, def); + }); + const $ZodNanoID = /*@__PURE__*/ $constructor("$ZodNanoID", (inst, def) => { + def.pattern ?? (def.pattern = nanoid); + $ZodStringFormat.init(inst, def); + }); + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link $ZodCUID2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const $ZodCUID = /*@__PURE__*/ $constructor("$ZodCUID", (inst, def) => { + def.pattern ?? (def.pattern = cuid); + $ZodStringFormat.init(inst, def); + }); + const $ZodCUID2 = /*@__PURE__*/ $constructor("$ZodCUID2", (inst, def) => { + def.pattern ?? (def.pattern = cuid2); + $ZodStringFormat.init(inst, def); + }); + const $ZodULID = /*@__PURE__*/ $constructor("$ZodULID", (inst, def) => { + def.pattern ?? (def.pattern = ulid); + $ZodStringFormat.init(inst, def); + }); + const $ZodXID = /*@__PURE__*/ $constructor("$ZodXID", (inst, def) => { + def.pattern ?? (def.pattern = xid); + $ZodStringFormat.init(inst, def); + }); + const $ZodKSUID = /*@__PURE__*/ $constructor("$ZodKSUID", (inst, def) => { + def.pattern ?? (def.pattern = ksuid); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODateTime = /*@__PURE__*/ $constructor("$ZodISODateTime", (inst, def) => { + def.pattern ?? (def.pattern = datetime$1(def)); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODate = /*@__PURE__*/ $constructor("$ZodISODate", (inst, def) => { + def.pattern ?? (def.pattern = date$1); + $ZodStringFormat.init(inst, def); + }); + const $ZodISOTime = /*@__PURE__*/ $constructor("$ZodISOTime", (inst, def) => { + def.pattern ?? (def.pattern = time$1(def)); + $ZodStringFormat.init(inst, def); + }); + const $ZodISODuration = /*@__PURE__*/ $constructor("$ZodISODuration", (inst, def) => { + def.pattern ?? (def.pattern = duration$1); + $ZodStringFormat.init(inst, def); + }); + const $ZodIPv4 = /*@__PURE__*/ $constructor("$ZodIPv4", (inst, def) => { + def.pattern ?? (def.pattern = ipv4); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv4`; + }); + const $ZodIPv6 = /*@__PURE__*/ $constructor("$ZodIPv6", (inst, def) => { + def.pattern ?? (def.pattern = ipv6); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv6`; + inst._zod.check = (payload) => { + try { + new URL(`http://[${payload.value}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "ipv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + const $ZodCIDRv4 = /*@__PURE__*/ $constructor("$ZodCIDRv4", (inst, def) => { + def.pattern ?? (def.pattern = cidrv4); + $ZodStringFormat.init(inst, def); + }); + const $ZodCIDRv6 = /*@__PURE__*/ $constructor("$ZodCIDRv6", (inst, def) => { + def.pattern ?? (def.pattern = cidrv6); + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + const parts = payload.value.split("/"); + try { + if (parts.length !== 2) throw new Error(); + const [address, prefix] = parts; + if (!prefix) throw new Error(); + const prefixNum = Number(prefix); + if (`${prefixNum}` !== prefix) throw new Error(); + if (prefixNum < 0 || prefixNum > 128) throw new Error(); + new URL(`http://[${address}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "cidrv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; + }); + function isValidBase64(data) { + if (data === "") return true; + if (/\s/.test(data)) return false; + if (data.length % 4 !== 0) return false; + try { + atob(data); + return true; + } catch { + return false; + } + } + const $ZodBase64 = /*@__PURE__*/ $constructor("$ZodBase64", (inst, def) => { + def.pattern ?? (def.pattern = base64); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64"; + inst._zod.check = (payload) => { + if (isValidBase64(payload.value)) return; + payload.issues.push({ + code: "invalid_format", + format: "base64", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + function isValidBase64URL(data) { + if (!base64url.test(data)) return false; + const base64 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/"); + return isValidBase64(base64.padEnd(Math.ceil(base64.length / 4) * 4, "=")); + } + const $ZodBase64URL = /*@__PURE__*/ $constructor("$ZodBase64URL", (inst, def) => { + def.pattern ?? (def.pattern = base64url); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64url"; + inst._zod.check = (payload) => { + if (isValidBase64URL(payload.value)) return; + payload.issues.push({ + code: "invalid_format", + format: "base64url", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodE164 = /*@__PURE__*/ $constructor("$ZodE164", (inst, def) => { + def.pattern ?? (def.pattern = e164); + $ZodStringFormat.init(inst, def); + }); + function isValidJWT(token, algorithm = null) { + try { + const tokensParts = token.split("."); + if (tokensParts.length !== 3) return false; + const [header] = tokensParts; + if (!header) return false; + const parsedHeader = JSON.parse(atob(header)); + if ("typ" in parsedHeader && parsedHeader?.typ !== "JWT") return false; + if (!parsedHeader.alg) return false; + if (algorithm && (!("alg" in parsedHeader) || parsedHeader.alg !== algorithm)) return false; + return true; + } catch { + return false; + } + } + const $ZodJWT = /*@__PURE__*/ $constructor("$ZodJWT", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + if (isValidJWT(payload.value, def.alg)) return; + payload.issues.push({ + code: "invalid_format", + format: "jwt", + input: payload.value, + inst, + continue: !def.abort + }); + }; + }); + const $ZodNumber = /*@__PURE__*/ $constructor("$ZodNumber", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = inst._zod.bag.pattern ?? number$1; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) try { + payload.value = Number(payload.value); + } catch (_) {} + const input = payload.value; + if (typeof input === "number" && !Number.isNaN(input) && Number.isFinite(input)) return payload; + const received = typeof input === "number" ? Number.isNaN(input) ? "NaN" : !Number.isFinite(input) ? "Infinity" : void 0 : void 0; + payload.issues.push({ + expected: "number", + code: "invalid_type", + input, + inst, + ...received ? { received } : {} + }); + return payload; + }; + }); + const $ZodNumberFormat = /*@__PURE__*/ $constructor("$ZodNumberFormat", (inst, def) => { + $ZodCheckNumberFormat.init(inst, def); + $ZodNumber.init(inst, def); + }); + const $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = boolean$1; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) try { + payload.value = Boolean(payload.value); + } catch (_) {} + const input = payload.value; + if (typeof input === "boolean") return payload; + payload.issues.push({ + expected: "boolean", + code: "invalid_type", + input, + inst + }); + return payload; + }; + }); + const $ZodUnknown = /*@__PURE__*/ $constructor("$ZodUnknown", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload) => payload; + }); + const $ZodNever = /*@__PURE__*/ $constructor("$ZodNever", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, _ctx) => { + payload.issues.push({ + expected: "never", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; + }); + function handleArrayResult(result, final, index) { + if (result.issues.length) final.issues.push(...prefixIssues(index, result.issues)); + final.value[index] = result.value; + } + const $ZodArray = /*@__PURE__*/ $constructor("$ZodArray", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!Array.isArray(input)) { + payload.issues.push({ + expected: "array", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = Array(input.length); + const proms = []; + for (let i = 0; i < input.length; i++) { + const item = input[i]; + const result = def.element._zod.run({ + value: item, + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => handleArrayResult(result, payload, i))); + else handleArrayResult(result, payload, i); + } + if (proms.length) return Promise.all(proms).then(() => payload); + return payload; + }; + }); + function handlePropertyResult(result, final, key, input, isOptionalIn, isOptionalOut) { + const isPresent = key in input; + if (result.issues.length) { + if (isOptionalIn && isOptionalOut && !isPresent) return; + final.issues.push(...prefixIssues(key, result.issues)); + } + if (!isPresent && !isOptionalIn) { + if (!result.issues.length) final.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: void 0, + path: [key] + }); + return; + } + if (result.value === void 0) { + if (isPresent) final.value[key] = void 0; + } else final.value[key] = result.value; + } + function normalizeDef(def) { + const keys = Object.keys(def.shape); + for (const k of keys) if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) throw new Error(`Invalid element at key "${k}": expected a Zod schema`); + const okeys = optionalKeys(def.shape); + return { + ...def, + keys, + keySet: new Set(keys), + numKeys: keys.length, + optionalKeys: new Set(okeys) + }; + } + function handleCatchall(proms, input, payload, ctx, def, inst) { + const unrecognized = []; + const keySet = def.keySet; + const _catchall = def.catchall._zod; + const t = _catchall.def.type; + const isOptionalIn = _catchall.optin === "optional"; + const isOptionalOut = _catchall.optout === "optional"; + for (const key in input) { + if (key === "__proto__") continue; + if (keySet.has(key)) continue; + if (t === "never") { + unrecognized.push(key); + continue; + } + const r = _catchall.run({ + value: input[key], + issues: [] + }, ctx); + if (r instanceof Promise) proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut))); + else handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + if (unrecognized.length) payload.issues.push({ + code: "unrecognized_keys", + keys: unrecognized, + input, + inst + }); + if (!proms.length) return payload; + return Promise.all(proms).then(() => { + return payload; + }); + } + const $ZodObject = /*@__PURE__*/ $constructor("$ZodObject", (inst, def) => { + $ZodType.init(inst, def); + if (!Object.getOwnPropertyDescriptor(def, "shape")?.get) { + const sh = def.shape; + Object.defineProperty(def, "shape", { get: () => { + const newSh = { ...sh }; + Object.defineProperty(def, "shape", { value: newSh }); + return newSh; + } }); + } + const _normalized = cached(() => normalizeDef(def)); + defineLazy(inst._zod, "propValues", () => { + const shape = def.shape; + const propValues = {}; + for (const key in shape) { + const field = shape[key]._zod; + if (field.values) { + propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set()); + for (const v of field.values) propValues[key].add(v); + } + } + return propValues; + }); + const isObject$1 = isObject; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject$1(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = {}; + const proms = []; + const shape = value.shape; + for (const key of value.keys) { + const el = shape[key]; + const isOptionalIn = el._zod.optin === "optional"; + const isOptionalOut = el._zod.optout === "optional"; + const r = el._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (r instanceof Promise) proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut))); + else handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + if (!catchall) return proms.length ? Promise.all(proms).then(() => payload) : payload; + return handleCatchall(proms, input, payload, ctx, _normalized.value, inst); + }; + }); + const $ZodObjectJIT = /*@__PURE__*/ $constructor("$ZodObjectJIT", (inst, def) => { + $ZodObject.init(inst, def); + const superParse = inst._zod.parse; + const _normalized = cached(() => normalizeDef(def)); + const generateFastpass = (shape) => { + const doc = new Doc([ + "shape", + "payload", + "ctx" + ]); + const normalized = _normalized.value; + const parseStr = (key) => { + const k = esc(key); + return `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`; + }; + doc.write(`const input = payload.value;`); + const ids = Object.create(null); + let counter = 0; + for (const key of normalized.keys) ids[key] = `key_${counter++}`; + doc.write(`const newResult = {};`); + for (const key of normalized.keys) { + const id = ids[key]; + const k = esc(key); + const schema = shape[key]; + const isOptionalIn = schema?._zod?.optin === "optional"; + const isOptionalOut = schema?._zod?.optout === "optional"; + doc.write(`const ${id} = ${parseStr(key)};`); + if (isOptionalIn && isOptionalOut) doc.write(` + if (${id}.issues.length) { + if (${k} in input) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + else if (!isOptionalIn) doc.write(` + const ${id}_present = ${k} in input; + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + if (!${id}_present && !${id}.issues.length) { + payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: undefined, + path: [${k}] + }); + } + + if (${id}_present) { + if (${id}.value === undefined) { + newResult[${k}] = undefined; + } else { + newResult[${k}] = ${id}.value; + } + } + + `); + else doc.write(` + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + } + doc.write(`payload.value = newResult;`); + doc.write(`return payload;`); + const fn = doc.compile(); + return (payload, ctx) => fn(shape, payload, ctx); + }; + let fastpass; + const isObject$2 = isObject; + const jit = !globalConfig.jitless; + const fastEnabled = jit && allowsEval.value; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject$2(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + if (jit && fastEnabled && ctx?.async === false && ctx.jitless !== true) { + if (!fastpass) fastpass = generateFastpass(def.shape); + payload = fastpass(payload, ctx); + if (!catchall) return payload; + return handleCatchall([], input, payload, ctx, value, inst); + } + return superParse(payload, ctx); + }; + }); + function handleUnionResults(results, final, inst, ctx) { + for (const result of results) if (result.issues.length === 0) { + final.value = result.value; + return final; + } + const nonaborted = results.filter((r) => !aborted(r)); + if (nonaborted.length === 1) { + final.value = nonaborted[0].value; + return nonaborted[0]; + } + final.issues.push({ + code: "invalid_union", + input: final.value, + inst, + errors: results.map((result) => result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + }); + return final; + } + const $ZodUnion = /*@__PURE__*/ $constructor("$ZodUnion", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.options.some((o) => o._zod.optin === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "optout", () => def.options.some((o) => o._zod.optout === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "values", () => { + if (def.options.every((o) => o._zod.values)) return new Set(def.options.flatMap((option) => Array.from(option._zod.values))); + }); + defineLazy(inst._zod, "pattern", () => { + if (def.options.every((o) => o._zod.pattern)) { + const patterns = def.options.map((o) => o._zod.pattern); + return new RegExp(`^(${patterns.map((p) => cleanRegex(p.source)).join("|")})$`); + } + }); + const first = def.options.length === 1 ? def.options[0]._zod.run : null; + inst._zod.parse = (payload, ctx) => { + if (first) return first(payload, ctx); + let async = false; + const results = []; + for (const option of def.options) { + const result = option._zod.run({ + value: payload.value, + issues: [] + }, ctx); + if (result instanceof Promise) { + results.push(result); + async = true; + } else { + if (result.issues.length === 0) return result; + results.push(result); + } + } + if (!async) return handleUnionResults(results, payload, inst, ctx); + return Promise.all(results).then((results) => { + return handleUnionResults(results, payload, inst, ctx); + }); + }; + }); + const $ZodDiscriminatedUnion = /*@__PURE__*/ $constructor("$ZodDiscriminatedUnion", (inst, def) => { + def.inclusive = false; + $ZodUnion.init(inst, def); + const _super = inst._zod.parse; + defineLazy(inst._zod, "propValues", () => { + const propValues = {}; + for (const option of def.options) { + const pv = option._zod.propValues; + if (!pv || Object.keys(pv).length === 0) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(option)}"`); + for (const [k, v] of Object.entries(pv)) { + if (!propValues[k]) propValues[k] = /* @__PURE__ */ new Set(); + for (const val of v) propValues[k].add(val); + } + } + return propValues; + }); + const disc = cached(() => { + const opts = def.options; + const map = /* @__PURE__ */ new Map(); + for (const o of opts) { + const values = o._zod.propValues?.[def.discriminator]; + if (!values || values.size === 0) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(o)}"`); + for (const v of values) { + if (map.has(v)) throw new Error(`Duplicate discriminator value "${String(v)}"`); + map.set(v, o); + } + } + return map; + }); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!isObject(input)) { + payload.issues.push({ + code: "invalid_type", + expected: "object", + input, + inst + }); + return payload; + } + const opt = disc.value.get(input?.[def.discriminator]); + if (opt) return opt._zod.run(payload, ctx); + if (def.unionFallback || ctx.direction === "backward") return _super(payload, ctx); + payload.issues.push({ + code: "invalid_union", + errors: [], + note: "No matching discriminator", + discriminator: def.discriminator, + options: Array.from(disc.value.keys()), + input, + path: [def.discriminator], + inst + }); + return payload; + }; + }); + const $ZodIntersection = /*@__PURE__*/ $constructor("$ZodIntersection", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + const left = def.left._zod.run({ + value: input, + issues: [] + }, ctx); + const right = def.right._zod.run({ + value: input, + issues: [] + }, ctx); + if (left instanceof Promise || right instanceof Promise) return Promise.all([left, right]).then(([left, right]) => { + return handleIntersectionResults(payload, left, right); + }); + return handleIntersectionResults(payload, left, right); + }; + }); + function mergeValues(a, b) { + if (a === b) return { + valid: true, + data: a + }; + if (a instanceof Date && b instanceof Date && +a === +b) return { + valid: true, + data: a + }; + if (isPlainObject(a) && isPlainObject(b)) { + const bKeys = Object.keys(b); + const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1); + const newObj = { + ...a, + ...b + }; + for (const key of sharedKeys) { + const sharedValue = mergeValues(a[key], b[key]); + if (!sharedValue.valid) return { + valid: false, + mergeErrorPath: [key, ...sharedValue.mergeErrorPath] + }; + newObj[key] = sharedValue.data; + } + return { + valid: true, + data: newObj + }; + } + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) return { + valid: false, + mergeErrorPath: [] + }; + const newArray = []; + for (let index = 0; index < a.length; index++) { + const itemA = a[index]; + const itemB = b[index]; + const sharedValue = mergeValues(itemA, itemB); + if (!sharedValue.valid) return { + valid: false, + mergeErrorPath: [index, ...sharedValue.mergeErrorPath] + }; + newArray.push(sharedValue.data); + } + return { + valid: true, + data: newArray + }; + } + return { + valid: false, + mergeErrorPath: [] + }; + } + function handleIntersectionResults(result, left, right) { + const unrecKeys = /* @__PURE__ */ new Map(); + let unrecIssue; + for (const iss of left.issues) if (iss.code === "unrecognized_keys") { + unrecIssue ?? (unrecIssue = iss); + for (const k of iss.keys) { + if (!unrecKeys.has(k)) unrecKeys.set(k, {}); + unrecKeys.get(k).l = true; + } + } else result.issues.push(iss); + for (const iss of right.issues) if (iss.code === "unrecognized_keys") for (const k of iss.keys) { + if (!unrecKeys.has(k)) unrecKeys.set(k, {}); + unrecKeys.get(k).r = true; + } + else result.issues.push(iss); + const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k); + if (bothKeys.length && unrecIssue) result.issues.push({ + ...unrecIssue, + keys: bothKeys + }); + if (aborted(result)) return result; + const merged = mergeValues(left.value, right.value); + if (!merged.valid) throw new Error(`Unmergable intersection. Error path: ${JSON.stringify(merged.mergeErrorPath)}`); + result.value = merged.data; + return result; + } + const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!isPlainObject(input)) { + payload.issues.push({ + expected: "record", + code: "invalid_type", + input, + inst + }); + return payload; + } + const proms = []; + const values = def.keyType._zod.values; + if (values) { + payload.value = {}; + const recordKeys = /* @__PURE__ */ new Set(); + for (const key of values) if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") { + recordKeys.add(typeof key === "number" ? key.toString() : key); + const keyResult = def.keyType._zod.run({ + value: key, + issues: [] + }, ctx); + if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (keyResult.issues.length) { + payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + continue; + } + const outKey = keyResult.value; + const result = def.valueType._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[outKey] = result.value; + })); + else { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[outKey] = result.value; + } + } + let unrecognized; + for (const key in input) if (!recordKeys.has(key)) { + unrecognized = unrecognized ?? []; + unrecognized.push(key); + } + if (unrecognized && unrecognized.length > 0) payload.issues.push({ + code: "unrecognized_keys", + input, + inst, + keys: unrecognized + }); + } else { + payload.value = {}; + for (const key of Reflect.ownKeys(input)) { + if (key === "__proto__") continue; + if (!Object.prototype.propertyIsEnumerable.call(input, key)) continue; + let keyResult = def.keyType._zod.run({ + value: key, + issues: [] + }, ctx); + if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (typeof key === "string" && number$1.test(key) && keyResult.issues.length) { + const retryResult = def.keyType._zod.run({ + value: Number(key), + issues: [] + }, ctx); + if (retryResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently"); + if (retryResult.issues.length === 0) keyResult = retryResult; + } + if (keyResult.issues.length) { + if (def.mode === "loose") payload.value[key] = input[key]; + else payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + continue; + } + const result = def.valueType._zod.run({ + value: input[key], + issues: [] + }, ctx); + if (result instanceof Promise) proms.push(result.then((result) => { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[keyResult.value] = result.value; + })); + else { + if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues)); + payload.value[keyResult.value] = result.value; + } + } + } + if (proms.length) return Promise.all(proms).then(() => payload); + return payload; + }; + }); + const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => { + $ZodType.init(inst, def); + const values = getEnumValues(def.entries); + const valuesSet = new Set(values); + inst._zod.values = valuesSet; + inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (valuesSet.has(input)) return payload; + payload.issues.push({ + code: "invalid_value", + values, + input, + inst + }); + return payload; + }; + }); + const $ZodLiteral = /*@__PURE__*/ $constructor("$ZodLiteral", (inst, def) => { + $ZodType.init(inst, def); + if (def.values.length === 0) throw new Error("Cannot create literal schema with no valid values"); + const values = new Set(def.values); + inst._zod.values = values; + inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (values.has(input)) return payload; + payload.issues.push({ + code: "invalid_value", + values: def.values, + input, + inst + }); + return payload; + }; + }); + const $ZodTransform = /*@__PURE__*/ $constructor("$ZodTransform", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") throw new $ZodEncodeError(inst.constructor.name); + const _out = def.transform(payload.value, payload); + if (ctx.async) return (_out instanceof Promise ? _out : Promise.resolve(_out)).then((output) => { + payload.value = output; + payload.fallback = true; + return payload; + }); + if (_out instanceof Promise) throw new $ZodAsyncError(); + payload.value = _out; + payload.fallback = true; + return payload; + }; + }); + function handleOptionalResult(result, input) { + if (input === void 0 && (result.issues.length || result.fallback)) return { + issues: [], + value: void 0 + }; + return result; + } + const $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.optout = "optional"; + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? new Set([...def.innerType._zod.values, void 0]) : void 0; + }); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)})?$`) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (def.innerType._zod.optin === "optional") { + const input = payload.value; + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((r) => handleOptionalResult(r, input)); + return handleOptionalResult(result, input); + } + if (payload.value === void 0) return payload; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodExactOptional = /*@__PURE__*/ $constructor("$ZodExactOptional", (inst, def) => { + $ZodOptional.init(inst, def); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "pattern", () => def.innerType._zod.pattern); + inst._zod.parse = (payload, ctx) => { + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodNullable = /*@__PURE__*/ $constructor("$ZodNullable", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.innerType._zod.optin); + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0; + }); + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (payload.value === null) return payload; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodDefault = /*@__PURE__*/ $constructor("$ZodDefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + if (payload.value === void 0) { + payload.value = def.defaultValue; + /** + * $ZodDefault returns the default value immediately in forward direction. + * It doesn't pass the default value into the validator ("prefault"). There's no reason to pass the default value through validation. The validity of the default is enforced by TypeScript statically. Otherwise, it's the responsibility of the user to ensure the default is valid. In the case of pipes with divergent in/out types, you can specify the default on the `in` schema of your ZodPipe to set a "prefault" for the pipe. */ + return payload; + } + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => handleDefaultResult(result, def)); + return handleDefaultResult(result, def); + }; + }); + function handleDefaultResult(payload, def) { + if (payload.value === void 0) payload.value = def.defaultValue; + return payload; + } + const $ZodPrefault = /*@__PURE__*/ $constructor("$ZodPrefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + if (payload.value === void 0) payload.value = def.defaultValue; + return def.innerType._zod.run(payload, ctx); + }; + }); + const $ZodNonOptional = /*@__PURE__*/ $constructor("$ZodNonOptional", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => { + const v = def.innerType._zod.values; + return v ? new Set([...v].filter((x) => x !== void 0)) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => handleNonOptionalResult(result, inst)); + return handleNonOptionalResult(result, inst); + }; + }); + function handleNonOptionalResult(payload, inst) { + if (!payload.issues.length && payload.value === void 0) payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: payload.value, + inst + }); + return payload; + } + const $ZodCatch = /*@__PURE__*/ $constructor("$ZodCatch", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then((result) => { + payload.value = result.value; + if (result.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }); + payload.value = result.value; + if (result.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }; + }); + const $ZodPipe = /*@__PURE__*/ $constructor("$ZodPipe", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => def.in._zod.values); + defineLazy(inst._zod, "optin", () => def.in._zod.optin); + defineLazy(inst._zod, "optout", () => def.out._zod.optout); + defineLazy(inst._zod, "propValues", () => def.in._zod.propValues); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + const right = def.out._zod.run(payload, ctx); + if (right instanceof Promise) return right.then((right) => handlePipeResult(right, def.in, ctx)); + return handlePipeResult(right, def.in, ctx); + } + const left = def.in._zod.run(payload, ctx); + if (left instanceof Promise) return left.then((left) => handlePipeResult(left, def.out, ctx)); + return handlePipeResult(left, def.out, ctx); + }; + }); + function handlePipeResult(left, next, ctx) { + if (left.issues.length) { + left.aborted = true; + return left; + } + return next._zod.run({ + value: left.value, + issues: left.issues, + fallback: left.fallback + }, ctx); + } + const $ZodReadonly = /*@__PURE__*/ $constructor("$ZodReadonly", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "propValues", () => def.innerType._zod.propValues); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "optin", () => def.innerType?._zod?.optin); + defineLazy(inst._zod, "optout", () => def.innerType?._zod?.optout); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") return def.innerType._zod.run(payload, ctx); + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) return result.then(handleReadonlyResult); + return handleReadonlyResult(result); + }; + }); + function handleReadonlyResult(payload) { + payload.value = Object.freeze(payload.value); + return payload; + } + const $ZodLazy = /*@__PURE__*/ $constructor("$ZodLazy", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "innerType", () => { + const d = def; + if (!d._cachedInner) d._cachedInner = def.getter(); + return d._cachedInner; + }); + defineLazy(inst._zod, "pattern", () => inst._zod.innerType?._zod?.pattern); + defineLazy(inst._zod, "propValues", () => inst._zod.innerType?._zod?.propValues); + defineLazy(inst._zod, "optin", () => inst._zod.innerType?._zod?.optin ?? void 0); + defineLazy(inst._zod, "optout", () => inst._zod.innerType?._zod?.optout ?? void 0); + inst._zod.parse = (payload, ctx) => { + return inst._zod.innerType._zod.run(payload, ctx); + }; + }); + const $ZodCustom = /*@__PURE__*/ $constructor("$ZodCustom", (inst, def) => { + $ZodCheck.init(inst, def); + $ZodType.init(inst, def); + inst._zod.parse = (payload, _) => { + return payload; + }; + inst._zod.check = (payload) => { + const input = payload.value; + const r = def.fn(input); + if (r instanceof Promise) return r.then((r) => handleRefineResult(r, payload, input, inst)); + handleRefineResult(r, payload, input, inst); + }; + }); + function handleRefineResult(result, payload, input, inst) { + if (!result) { + const _iss = { + code: "custom", + input, + inst, + path: [...inst._zod.def.path ?? []], + continue: !inst._zod.def.abort + }; + if (inst._zod.def.params) _iss.params = inst._zod.def.params; + payload.issues.push(issue(_iss)); + } + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.js + var _a; + var $ZodRegistry = class { + constructor() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + } + add(schema, ..._meta) { + const meta = _meta[0]; + this._map.set(schema, meta); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.set(meta.id, schema); + return this; + } + clear() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + return this; + } + remove(schema) { + const meta = this._map.get(schema); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.delete(meta.id); + this._map.delete(schema); + return this; + } + get(schema) { + const p = schema._zod.parent; + if (p) { + const pm = { ...this.get(p) ?? {} }; + delete pm.id; + const f = { + ...pm, + ...this._map.get(schema) + }; + return Object.keys(f).length ? f : void 0; + } + return this._map.get(schema); + } + has(schema) { + return this._map.has(schema); + } + }; + function registry() { + return new $ZodRegistry(); + } + (_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry()); + const globalRegistry = globalThis.__zod_globalRegistry; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/api.js + // @__NO_SIDE_EFFECTS__ + function _string(Class, params) { + return new Class({ + type: "string", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _email(Class, params) { + return new Class({ + type: "string", + format: "email", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _guid(Class, params) { + return new Class({ + type: "string", + format: "guid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuid(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv4(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v4", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv6(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v6", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uuidv7(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v7", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _url(Class, params) { + return new Class({ + type: "string", + format: "url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _emoji(Class, params) { + return new Class({ + type: "string", + format: "emoji", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _nanoid(Class, params) { + return new Class({ + type: "string", + format: "nanoid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link _cuid2} instead. + * See https://github.com/paralleldrive/cuid. + */ + // @__NO_SIDE_EFFECTS__ + function _cuid(Class, params) { + return new Class({ + type: "string", + format: "cuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cuid2(Class, params) { + return new Class({ + type: "string", + format: "cuid2", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ulid(Class, params) { + return new Class({ + type: "string", + format: "ulid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _xid(Class, params) { + return new Class({ + type: "string", + format: "xid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ksuid(Class, params) { + return new Class({ + type: "string", + format: "ksuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ipv4(Class, params) { + return new Class({ + type: "string", + format: "ipv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _ipv6(Class, params) { + return new Class({ + type: "string", + format: "ipv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cidrv4(Class, params) { + return new Class({ + type: "string", + format: "cidrv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _cidrv6(Class, params) { + return new Class({ + type: "string", + format: "cidrv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _base64(Class, params) { + return new Class({ + type: "string", + format: "base64", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _base64url(Class, params) { + return new Class({ + type: "string", + format: "base64url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _e164(Class, params) { + return new Class({ + type: "string", + format: "e164", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _jwt(Class, params) { + return new Class({ + type: "string", + format: "jwt", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDateTime(Class, params) { + return new Class({ + type: "string", + format: "datetime", + check: "string_format", + offset: false, + local: false, + precision: null, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDate(Class, params) { + return new Class({ + type: "string", + format: "date", + check: "string_format", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoTime(Class, params) { + return new Class({ + type: "string", + format: "time", + check: "string_format", + precision: null, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _isoDuration(Class, params) { + return new Class({ + type: "string", + format: "duration", + check: "string_format", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _number(Class, params) { + return new Class({ + type: "number", + checks: [], + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _int(Class, params) { + return new Class({ + type: "number", + check: "number_format", + abort: false, + format: "safeint", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _boolean(Class, params) { + return new Class({ + type: "boolean", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _unknown(Class) { + return new Class({ type: "unknown" }); + } + // @__NO_SIDE_EFFECTS__ + function _never(Class, params) { + return new Class({ + type: "never", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _lt(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: false + }); + } + // @__NO_SIDE_EFFECTS__ + function _lte(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: true + }); + } + // @__NO_SIDE_EFFECTS__ + function _gt(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: false + }); + } + // @__NO_SIDE_EFFECTS__ + function _gte(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: true + }); + } + // @__NO_SIDE_EFFECTS__ + function _multipleOf(value, params) { + return new $ZodCheckMultipleOf({ + check: "multiple_of", + ...normalizeParams(params), + value + }); + } + // @__NO_SIDE_EFFECTS__ + function _maxLength(maximum, params) { + return new $ZodCheckMaxLength({ + check: "max_length", + ...normalizeParams(params), + maximum + }); + } + // @__NO_SIDE_EFFECTS__ + function _minLength(minimum, params) { + return new $ZodCheckMinLength({ + check: "min_length", + ...normalizeParams(params), + minimum + }); + } + // @__NO_SIDE_EFFECTS__ + function _length(length, params) { + return new $ZodCheckLengthEquals({ + check: "length_equals", + ...normalizeParams(params), + length + }); + } + // @__NO_SIDE_EFFECTS__ + function _regex(pattern, params) { + return new $ZodCheckRegex({ + check: "string_format", + format: "regex", + ...normalizeParams(params), + pattern + }); + } + // @__NO_SIDE_EFFECTS__ + function _lowercase(params) { + return new $ZodCheckLowerCase({ + check: "string_format", + format: "lowercase", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _uppercase(params) { + return new $ZodCheckUpperCase({ + check: "string_format", + format: "uppercase", + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _includes(includes, params) { + return new $ZodCheckIncludes({ + check: "string_format", + format: "includes", + ...normalizeParams(params), + includes + }); + } + // @__NO_SIDE_EFFECTS__ + function _startsWith(prefix, params) { + return new $ZodCheckStartsWith({ + check: "string_format", + format: "starts_with", + ...normalizeParams(params), + prefix + }); + } + // @__NO_SIDE_EFFECTS__ + function _endsWith(suffix, params) { + return new $ZodCheckEndsWith({ + check: "string_format", + format: "ends_with", + ...normalizeParams(params), + suffix + }); + } + // @__NO_SIDE_EFFECTS__ + function _overwrite(tx) { + return new $ZodCheckOverwrite({ + check: "overwrite", + tx + }); + } + // @__NO_SIDE_EFFECTS__ + function _normalize(form) { + return /* @__PURE__ */ _overwrite((input) => input.normalize(form)); + } + // @__NO_SIDE_EFFECTS__ + function _trim() { + return /* @__PURE__ */ _overwrite((input) => input.trim()); + } + // @__NO_SIDE_EFFECTS__ + function _toLowerCase() { + return /* @__PURE__ */ _overwrite((input) => input.toLowerCase()); + } + // @__NO_SIDE_EFFECTS__ + function _toUpperCase() { + return /* @__PURE__ */ _overwrite((input) => input.toUpperCase()); + } + // @__NO_SIDE_EFFECTS__ + function _slugify() { + return /* @__PURE__ */ _overwrite((input) => slugify(input)); + } + // @__NO_SIDE_EFFECTS__ + function _array(Class, element, params) { + return new Class({ + type: "array", + element, + ...normalizeParams(params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _custom(Class, fn, _params) { + const norm = normalizeParams(_params); + norm.abort ?? (norm.abort = true); + return new Class({ + type: "custom", + check: "custom", + fn, + ...norm + }); + } + // @__NO_SIDE_EFFECTS__ + function _refine(Class, fn, _params) { + return new Class({ + type: "custom", + check: "custom", + fn, + ...normalizeParams(_params) + }); + } + // @__NO_SIDE_EFFECTS__ + function _superRefine(fn, params) { + const ch = /* @__PURE__ */ _check((payload) => { + payload.addIssue = (issue$2) => { + if (typeof issue$2 === "string") payload.issues.push(issue(issue$2, payload.value, ch._zod.def)); + else { + const _issue = issue$2; + if (_issue.fatal) _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = ch); + _issue.continue ?? (_issue.continue = !ch._zod.def.abort); + payload.issues.push(issue(_issue)); + } + }; + return fn(payload.value, payload); + }, params); + return ch; + } + // @__NO_SIDE_EFFECTS__ + function _check(fn, params) { + const ch = new $ZodCheck({ + check: "custom", + ...normalizeParams(params) + }); + ch._zod.check = fn; + return ch; + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.js + function initializeContext(params) { + let target = params?.target ?? "draft-2020-12"; + if (target === "draft-4") target = "draft-04"; + if (target === "draft-7") target = "draft-07"; + return { + processors: params.processors ?? {}, + metadataRegistry: params?.metadata ?? globalRegistry, + target, + unrepresentable: params?.unrepresentable ?? "throw", + override: params?.override ?? (() => {}), + io: params?.io ?? "output", + counter: 0, + seen: /* @__PURE__ */ new Map(), + cycles: params?.cycles ?? "ref", + reused: params?.reused ?? "inline", + external: params?.external ?? void 0 + }; + } + function process(schema, ctx, _params = { + path: [], + schemaPath: [] + }) { + var _a; + const def = schema._zod.def; + const seen = ctx.seen.get(schema); + if (seen) { + seen.count++; + if (_params.schemaPath.includes(schema)) seen.cycle = _params.path; + return seen.schema; + } + const result = { + schema: {}, + count: 1, + cycle: void 0, + path: _params.path + }; + ctx.seen.set(schema, result); + const overrideSchema = schema._zod.toJSONSchema?.(); + if (overrideSchema) result.schema = overrideSchema; + else { + const params = { + ..._params, + schemaPath: [..._params.schemaPath, schema], + path: _params.path + }; + if (schema._zod.processJSONSchema) schema._zod.processJSONSchema(ctx, result.schema, params); + else { + const _json = result.schema; + const processor = ctx.processors[def.type]; + if (!processor) throw new Error(`[toJSONSchema]: Non-representable type encountered: ${def.type}`); + processor(schema, ctx, _json, params); + } + const parent = schema._zod.parent; + if (parent) { + if (!result.ref) result.ref = parent; + process(parent, ctx, params); + ctx.seen.get(parent).isParent = true; + } + } + const meta = ctx.metadataRegistry.get(schema); + if (meta) Object.assign(result.schema, meta); + if (ctx.io === "input" && isTransforming(schema)) { + delete result.schema.examples; + delete result.schema.default; + } + if (ctx.io === "input" && "_prefault" in result.schema) (_a = result.schema).default ?? (_a.default = result.schema._prefault); + delete result.schema._prefault; + return ctx.seen.get(schema).schema; + } + function extractDefs(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const idToSchema = /* @__PURE__ */ new Map(); + for (const entry of ctx.seen.entries()) { + const id = ctx.metadataRegistry.get(entry[0])?.id; + if (id) { + const existing = idToSchema.get(id); + if (existing && existing !== entry[0]) throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`); + idToSchema.set(id, entry[0]); + } + } + const makeURI = (entry) => { + const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions"; + if (ctx.external) { + const externalId = ctx.external.registry.get(entry[0])?.id; + const uriGenerator = ctx.external.uri ?? ((id) => id); + if (externalId) return { ref: uriGenerator(externalId) }; + const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`; + entry[1].defId = id; + return { + defId: id, + ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` + }; + } + if (entry[1] === root) return { ref: "#" }; + const defUriPrefix = `#/${defsSegment}/`; + const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`; + return { + defId, + ref: defUriPrefix + defId + }; + }; + const extractToDef = (entry) => { + if (entry[1].schema.$ref) return; + const seen = entry[1]; + const { ref, defId } = makeURI(entry); + seen.def = { ...seen.schema }; + if (defId) seen.defId = defId; + const schema = seen.schema; + for (const key in schema) delete schema[key]; + schema.$ref = ref; + }; + if (ctx.cycles === "throw") for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.cycle) throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/ + +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`); + } + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (schema === entry[0]) { + extractToDef(entry); + continue; + } + if (ctx.external) { + const ext = ctx.external.registry.get(entry[0])?.id; + if (schema !== entry[0] && ext) { + extractToDef(entry); + continue; + } + } + if (ctx.metadataRegistry.get(entry[0])?.id) { + extractToDef(entry); + continue; + } + if (seen.cycle) { + extractToDef(entry); + continue; + } + if (seen.count > 1) { + if (ctx.reused === "ref") { + extractToDef(entry); + continue; + } + } + } + } + function finalize(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const flattenRef = (zodSchema) => { + const seen = ctx.seen.get(zodSchema); + if (seen.ref === null) return; + const schema = seen.def ?? seen.schema; + const _cached = { ...schema }; + const ref = seen.ref; + seen.ref = null; + if (ref) { + flattenRef(ref); + const refSeen = ctx.seen.get(ref); + const refSchema = refSeen.schema; + if (refSchema.$ref && (ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0")) { + schema.allOf = schema.allOf ?? []; + schema.allOf.push(refSchema); + } else Object.assign(schema, refSchema); + Object.assign(schema, _cached); + if (zodSchema._zod.parent === ref) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (!(key in _cached)) delete schema[key]; + } + if (refSchema.$ref && refSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in refSeen.def && JSON.stringify(schema[key]) === JSON.stringify(refSeen.def[key])) delete schema[key]; + } + } + const parent = zodSchema._zod.parent; + if (parent && parent !== ref) { + flattenRef(parent); + const parentSeen = ctx.seen.get(parent); + if (parentSeen?.schema.$ref) { + schema.$ref = parentSeen.schema.$ref; + if (parentSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in parentSeen.def && JSON.stringify(schema[key]) === JSON.stringify(parentSeen.def[key])) delete schema[key]; + } + } + } + ctx.override({ + zodSchema, + jsonSchema: schema, + path: seen.path ?? [] + }); + }; + for (const entry of [...ctx.seen.entries()].reverse()) flattenRef(entry[0]); + const result = {}; + if (ctx.target === "draft-2020-12") result.$schema = "https://json-schema.org/draft/2020-12/schema"; + else if (ctx.target === "draft-07") result.$schema = "http://json-schema.org/draft-07/schema#"; + else if (ctx.target === "draft-04") result.$schema = "http://json-schema.org/draft-04/schema#"; + else if (ctx.target === "openapi-3.0") {} + if (ctx.external?.uri) { + const id = ctx.external.registry.get(schema)?.id; + if (!id) throw new Error("Schema is missing an `id` property"); + result.$id = ctx.external.uri(id); + } + Object.assign(result, root.def ?? root.schema); + const rootMetaId = ctx.metadataRegistry.get(schema)?.id; + if (rootMetaId !== void 0 && result.id === rootMetaId) delete result.id; + const defs = ctx.external?.defs ?? {}; + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.def && seen.defId) { + if (seen.def.id === seen.defId) delete seen.def.id; + defs[seen.defId] = seen.def; + } + } + if (ctx.external) {} else if (Object.keys(defs).length > 0) if (ctx.target === "draft-2020-12") result.$defs = defs; + else result.definitions = defs; + try { + const finalized = JSON.parse(JSON.stringify(result)); + Object.defineProperty(finalized, "~standard", { + value: { + ...schema["~standard"], + jsonSchema: { + input: createStandardJSONSchemaMethod(schema, "input", ctx.processors), + output: createStandardJSONSchemaMethod(schema, "output", ctx.processors) + } + }, + enumerable: false, + writable: false + }); + return finalized; + } catch (_err) { + throw new Error("Error converting schema to JSON."); + } + } + function isTransforming(_schema, _ctx) { + const ctx = _ctx ?? { seen: /* @__PURE__ */ new Set() }; + if (ctx.seen.has(_schema)) return false; + ctx.seen.add(_schema); + const def = _schema._zod.def; + if (def.type === "transform") return true; + if (def.type === "array") return isTransforming(def.element, ctx); + if (def.type === "set") return isTransforming(def.valueType, ctx); + if (def.type === "lazy") return isTransforming(def.getter(), ctx); + if (def.type === "promise" || def.type === "optional" || def.type === "nonoptional" || def.type === "nullable" || def.type === "readonly" || def.type === "default" || def.type === "prefault") return isTransforming(def.innerType, ctx); + if (def.type === "intersection") return isTransforming(def.left, ctx) || isTransforming(def.right, ctx); + if (def.type === "record" || def.type === "map") return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); + if (def.type === "pipe") { + if (_schema._zod.traits.has("$ZodCodec")) return true; + return isTransforming(def.in, ctx) || isTransforming(def.out, ctx); + } + if (def.type === "object") { + for (const key in def.shape) if (isTransforming(def.shape[key], ctx)) return true; + return false; + } + if (def.type === "union") { + for (const option of def.options) if (isTransforming(option, ctx)) return true; + return false; + } + if (def.type === "tuple") { + for (const item of def.items) if (isTransforming(item, ctx)) return true; + if (def.rest && isTransforming(def.rest, ctx)) return true; + return false; + } + return false; + } + /** + * Creates a toJSONSchema method for a schema instance. + * This encapsulates the logic of initializing context, processing, extracting defs, and finalizing. + */ + const createToJSONSchemaMethod = (schema, processors = {}) => (params) => { + const ctx = initializeContext({ + ...params, + processors + }); + process(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); + }; + const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => { + const { libraryOptions, target } = params ?? {}; + const ctx = initializeContext({ + ...libraryOptions ?? {}, + target, + io, + processors + }); + process(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.js + const formatMap = { + guid: "uuid", + url: "uri", + datetime: "date-time", + json_string: "json-string", + regex: "" + }; + const stringProcessor = (schema, ctx, _json, _params) => { + const json = _json; + json.type = "string"; + const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag; + if (typeof minimum === "number") json.minLength = minimum; + if (typeof maximum === "number") json.maxLength = maximum; + if (format) { + json.format = formatMap[format] ?? format; + if (json.format === "") delete json.format; + if (format === "time") delete json.format; + } + if (contentEncoding) json.contentEncoding = contentEncoding; + if (patterns && patterns.size > 0) { + const regexes = [...patterns]; + if (regexes.length === 1) json.pattern = regexes[0].source; + else if (regexes.length > 1) json.allOf = [...regexes.map((regex) => ({ + ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {}, + pattern: regex.source + }))]; + } + }; + const numberProcessor = (schema, ctx, _json, _params) => { + const json = _json; + const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; + if (typeof format === "string" && format.includes("int")) json.type = "integer"; + else json.type = "number"; + const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY); + const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY); + const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0"; + if (exMin) if (legacy) { + json.minimum = exclusiveMinimum; + json.exclusiveMinimum = true; + } else json.exclusiveMinimum = exclusiveMinimum; + else if (typeof minimum === "number") json.minimum = minimum; + if (exMax) if (legacy) { + json.maximum = exclusiveMaximum; + json.exclusiveMaximum = true; + } else json.exclusiveMaximum = exclusiveMaximum; + else if (typeof maximum === "number") json.maximum = maximum; + if (typeof multipleOf === "number") json.multipleOf = multipleOf; + }; + const booleanProcessor = (_schema, _ctx, json, _params) => { + json.type = "boolean"; + }; + const neverProcessor = (_schema, _ctx, json, _params) => { + json.not = {}; + }; + const enumProcessor = (schema, _ctx, json, _params) => { + const def = schema._zod.def; + const values = getEnumValues(def.entries); + if (values.every((v) => typeof v === "number")) json.type = "number"; + if (values.every((v) => typeof v === "string")) json.type = "string"; + json.enum = values; + }; + const literalProcessor = (schema, ctx, json, _params) => { + const def = schema._zod.def; + const vals = []; + for (const val of def.values) if (val === void 0) { + if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema"); + } else if (typeof val === "bigint") if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema"); + else vals.push(Number(val)); + else vals.push(val); + if (vals.length === 0) {} else if (vals.length === 1) { + const val = vals[0]; + json.type = val === null ? "null" : typeof val; + if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") json.enum = [val]; + else json.const = val; + } else { + if (vals.every((v) => typeof v === "number")) json.type = "number"; + if (vals.every((v) => typeof v === "string")) json.type = "string"; + if (vals.every((v) => typeof v === "boolean")) json.type = "boolean"; + if (vals.every((v) => v === null)) json.type = "null"; + json.enum = vals; + } + }; + const customProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Custom types cannot be represented in JSON Schema"); + }; + const transformProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Transforms cannot be represented in JSON Schema"); + }; + const arrayProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") json.minItems = minimum; + if (typeof maximum === "number") json.maxItems = maximum; + json.type = "array"; + json.items = process(def.element, ctx, { + ...params, + path: [...params.path, "items"] + }); + }; + const objectProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + json.properties = {}; + const shape = def.shape; + for (const key in shape) json.properties[key] = process(shape[key], ctx, { + ...params, + path: [ + ...params.path, + "properties", + key + ] + }); + const allKeys = new Set(Object.keys(shape)); + const requiredKeys = new Set([...allKeys].filter((key) => { + const v = def.shape[key]._zod; + if (ctx.io === "input") return v.optin === void 0; + else return v.optout === void 0; + })); + if (requiredKeys.size > 0) json.required = Array.from(requiredKeys); + if (def.catchall?._zod.def.type === "never") json.additionalProperties = false; + else if (!def.catchall) { + if (ctx.io === "output") json.additionalProperties = false; + } else if (def.catchall) json.additionalProperties = process(def.catchall, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + }; + const unionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const isExclusive = def.inclusive === false; + const options = def.options.map((x, i) => process(x, ctx, { + ...params, + path: [ + ...params.path, + isExclusive ? "oneOf" : "anyOf", + i + ] + })); + if (isExclusive) json.oneOf = options; + else json.anyOf = options; + }; + const intersectionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const a = process(def.left, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 0 + ] + }); + const b = process(def.right, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 1 + ] + }); + const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1; + json.allOf = [...isSimpleIntersection(a) ? a.allOf : [a], ...isSimpleIntersection(b) ? b.allOf : [b]]; + }; + const recordProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + const keyType = def.keyType; + const patterns = keyType._zod.bag?.patterns; + if (def.mode === "loose" && patterns && patterns.size > 0) { + const valueSchema = process(def.valueType, ctx, { + ...params, + path: [ + ...params.path, + "patternProperties", + "*" + ] + }); + json.patternProperties = {}; + for (const pattern of patterns) json.patternProperties[pattern.source] = valueSchema; + } else { + if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") json.propertyNames = process(def.keyType, ctx, { + ...params, + path: [...params.path, "propertyNames"] + }); + json.additionalProperties = process(def.valueType, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + } + const keyValues = keyType._zod.values; + if (keyValues) { + const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number"); + if (validKeyValues.length > 0) json.required = validKeyValues; + } + }; + const nullableProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const inner = process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + if (ctx.target === "openapi-3.0") { + seen.ref = def.innerType; + json.nullable = true; + } else json.anyOf = [inner, { type: "null" }]; + }; + const nonoptionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const defaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.default = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const prefaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + if (ctx.io === "input") json._prefault = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const catchProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + let catchValue; + try { + catchValue = def.catchValue(void 0); + } catch { + throw new Error("Dynamic catch values are not supported in JSON Schema"); + } + json.default = catchValue; + }; + const pipeProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + const inIsTransform = def.in._zod.traits.has("$ZodTransform"); + const innerType = ctx.io === "input" ? inIsTransform ? def.out : def.in : def.out; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + const readonlyProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.readOnly = true; + }; + const optionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const lazyProcessor = (schema, ctx, _json, params) => { + const innerType = schema._zod.innerType; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/iso.js + const ZodISODateTime = /*@__PURE__*/ $constructor("ZodISODateTime", (inst, def) => { + $ZodISODateTime.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function datetime(params) { + return /* @__PURE__ */ _isoDateTime(ZodISODateTime, params); + } + const ZodISODate = /*@__PURE__*/ $constructor("ZodISODate", (inst, def) => { + $ZodISODate.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function date(params) { + return /* @__PURE__ */ _isoDate(ZodISODate, params); + } + const ZodISOTime = /*@__PURE__*/ $constructor("ZodISOTime", (inst, def) => { + $ZodISOTime.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function time(params) { + return /* @__PURE__ */ _isoTime(ZodISOTime, params); + } + const ZodISODuration = /*@__PURE__*/ $constructor("ZodISODuration", (inst, def) => { + $ZodISODuration.init(inst, def); + ZodStringFormat.init(inst, def); + }); + function duration(params) { + return /* @__PURE__ */ _isoDuration(ZodISODuration, params); + } + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/errors.js + const initializer = (inst, issues) => { + $ZodError.init(inst, issues); + inst.name = "ZodError"; + Object.defineProperties(inst, { + format: { value: (mapper) => formatError(inst, mapper) }, + flatten: { value: (mapper) => flattenError(inst, mapper) }, + addIssue: { value: (issue) => { + inst.issues.push(issue); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } }, + addIssues: { value: (issues) => { + inst.issues.push(...issues); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } }, + isEmpty: { get() { + return inst.issues.length === 0; + } } + }); + }; + const ZodRealError = /*@__PURE__*/ $constructor("ZodError", initializer, { Parent: Error }); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/parse.js + const parse = /* @__PURE__ */ _parse(ZodRealError); + const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError); + const safeParse = /* @__PURE__ */ _safeParse(ZodRealError); + const safeParseAsync = /* @__PURE__ */ _safeParseAsync(ZodRealError); + const encode = /* @__PURE__ */ _encode(ZodRealError); + const decode = /* @__PURE__ */ _decode(ZodRealError); + const encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError); + const decodeAsync = /* @__PURE__ */ _decodeAsync(ZodRealError); + const safeEncode = /* @__PURE__ */ _safeEncode(ZodRealError); + const safeDecode = /* @__PURE__ */ _safeDecode(ZodRealError); + const safeEncodeAsync = /* @__PURE__ */ _safeEncodeAsync(ZodRealError); + const safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync(ZodRealError); + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js + const _installedGroups = /* @__PURE__ */ new WeakMap(); + function _installLazyMethods(inst, group, methods) { + const proto = Object.getPrototypeOf(inst); + let installed = _installedGroups.get(proto); + if (!installed) { + installed = /* @__PURE__ */ new Set(); + _installedGroups.set(proto, installed); + } + if (installed.has(group)) return; + installed.add(group); + for (const key in methods) { + const fn = methods[key]; + Object.defineProperty(proto, key, { + configurable: true, + enumerable: false, + get() { + const bound = fn.bind(this); + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: bound + }); + return bound; + }, + set(v) { + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: v + }); + } + }); + } + } + const ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => { + $ZodType.init(inst, def); + Object.assign(inst["~standard"], { jsonSchema: { + input: createStandardJSONSchemaMethod(inst, "input"), + output: createStandardJSONSchemaMethod(inst, "output") + } }); + inst.toJSONSchema = createToJSONSchemaMethod(inst, {}); + inst.def = def; + inst.type = def.type; + Object.defineProperty(inst, "_def", { value: def }); + inst.parse = (data, params) => parse(inst, data, params, { callee: inst.parse }); + inst.safeParse = (data, params) => safeParse(inst, data, params); + inst.parseAsync = async (data, params) => parseAsync(inst, data, params, { callee: inst.parseAsync }); + inst.safeParseAsync = async (data, params) => safeParseAsync(inst, data, params); + inst.spa = inst.safeParseAsync; + inst.encode = (data, params) => encode(inst, data, params); + inst.decode = (data, params) => decode(inst, data, params); + inst.encodeAsync = async (data, params) => encodeAsync(inst, data, params); + inst.decodeAsync = async (data, params) => decodeAsync(inst, data, params); + inst.safeEncode = (data, params) => safeEncode(inst, data, params); + inst.safeDecode = (data, params) => safeDecode(inst, data, params); + inst.safeEncodeAsync = async (data, params) => safeEncodeAsync(inst, data, params); + inst.safeDecodeAsync = async (data, params) => safeDecodeAsync(inst, data, params); + _installLazyMethods(inst, "ZodType", { + check(...chks) { + const def = this.def; + return this.clone(mergeDefs(def, { checks: [...def.checks ?? [], ...chks.map((ch) => typeof ch === "function" ? { _zod: { + check: ch, + def: { check: "custom" }, + onattach: [] + } } : ch)] }), { parent: true }); + }, + with(...chks) { + return this.check(...chks); + }, + clone(def, params) { + return clone(this, def, params); + }, + brand() { + return this; + }, + register(reg, meta) { + reg.add(this, meta); + return this; + }, + refine(check, params) { + return this.check(refine(check, params)); + }, + superRefine(refinement, params) { + return this.check(superRefine(refinement, params)); + }, + overwrite(fn) { + return this.check(/* @__PURE__ */ _overwrite(fn)); + }, + optional() { + return optional(this); + }, + exactOptional() { + return exactOptional(this); + }, + nullable() { + return nullable(this); + }, + nullish() { + return optional(nullable(this)); + }, + nonoptional(params) { + return nonoptional(this, params); + }, + array() { + return array(this); + }, + or(arg) { + return union([this, arg]); + }, + and(arg) { + return intersection(this, arg); + }, + transform(tx) { + return pipe(this, transform(tx)); + }, + default(d) { + return _default(this, d); + }, + prefault(d) { + return prefault(this, d); + }, + catch(params) { + return _catch(this, params); + }, + pipe(target) { + return pipe(this, target); + }, + readonly() { + return readonly(this); + }, + describe(description) { + const cl = this.clone(); + globalRegistry.add(cl, { description }); + return cl; + }, + meta(...args) { + if (args.length === 0) return globalRegistry.get(this); + const cl = this.clone(); + globalRegistry.add(cl, args[0]); + return cl; + }, + isOptional() { + return this.safeParse(void 0).success; + }, + isNullable() { + return this.safeParse(null).success; + }, + apply(fn) { + return fn(this); + } + }); + Object.defineProperty(inst, "description", { + get() { + return globalRegistry.get(inst)?.description; + }, + configurable: true + }); + return inst; + }); + /** @internal */ + const _ZodString = /*@__PURE__*/ $constructor("_ZodString", (inst, def) => { + $ZodString.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => stringProcessor(inst, ctx, json, params); + const bag = inst._zod.bag; + inst.format = bag.format ?? null; + inst.minLength = bag.minimum ?? null; + inst.maxLength = bag.maximum ?? null; + _installLazyMethods(inst, "_ZodString", { + regex(...args) { + return this.check(/* @__PURE__ */ _regex(...args)); + }, + includes(...args) { + return this.check(/* @__PURE__ */ _includes(...args)); + }, + startsWith(...args) { + return this.check(/* @__PURE__ */ _startsWith(...args)); + }, + endsWith(...args) { + return this.check(/* @__PURE__ */ _endsWith(...args)); + }, + min(...args) { + return this.check(/* @__PURE__ */ _minLength(...args)); + }, + max(...args) { + return this.check(/* @__PURE__ */ _maxLength(...args)); + }, + length(...args) { + return this.check(/* @__PURE__ */ _length(...args)); + }, + nonempty(...args) { + return this.check(/* @__PURE__ */ _minLength(1, ...args)); + }, + lowercase(params) { + return this.check(/* @__PURE__ */ _lowercase(params)); + }, + uppercase(params) { + return this.check(/* @__PURE__ */ _uppercase(params)); + }, + trim() { + return this.check(/* @__PURE__ */ _trim()); + }, + normalize(...args) { + return this.check(/* @__PURE__ */ _normalize(...args)); + }, + toLowerCase() { + return this.check(/* @__PURE__ */ _toLowerCase()); + }, + toUpperCase() { + return this.check(/* @__PURE__ */ _toUpperCase()); + }, + slugify() { + return this.check(/* @__PURE__ */ _slugify()); + } + }); + }); + const ZodString = /*@__PURE__*/ $constructor("ZodString", (inst, def) => { + $ZodString.init(inst, def); + _ZodString.init(inst, def); + inst.email = (params) => inst.check(/* @__PURE__ */ _email(ZodEmail, params)); + inst.url = (params) => inst.check(/* @__PURE__ */ _url(ZodURL, params)); + inst.jwt = (params) => inst.check(/* @__PURE__ */ _jwt(ZodJWT, params)); + inst.emoji = (params) => inst.check(/* @__PURE__ */ _emoji(ZodEmoji, params)); + inst.guid = (params) => inst.check(/* @__PURE__ */ _guid(ZodGUID, params)); + inst.uuid = (params) => inst.check(/* @__PURE__ */ _uuid(ZodUUID, params)); + inst.uuidv4 = (params) => inst.check(/* @__PURE__ */ _uuidv4(ZodUUID, params)); + inst.uuidv6 = (params) => inst.check(/* @__PURE__ */ _uuidv6(ZodUUID, params)); + inst.uuidv7 = (params) => inst.check(/* @__PURE__ */ _uuidv7(ZodUUID, params)); + inst.nanoid = (params) => inst.check(/* @__PURE__ */ _nanoid(ZodNanoID, params)); + inst.guid = (params) => inst.check(/* @__PURE__ */ _guid(ZodGUID, params)); + inst.cuid = (params) => inst.check(/* @__PURE__ */ _cuid(ZodCUID, params)); + inst.cuid2 = (params) => inst.check(/* @__PURE__ */ _cuid2(ZodCUID2, params)); + inst.ulid = (params) => inst.check(/* @__PURE__ */ _ulid(ZodULID, params)); + inst.base64 = (params) => inst.check(/* @__PURE__ */ _base64(ZodBase64, params)); + inst.base64url = (params) => inst.check(/* @__PURE__ */ _base64url(ZodBase64URL, params)); + inst.xid = (params) => inst.check(/* @__PURE__ */ _xid(ZodXID, params)); + inst.ksuid = (params) => inst.check(/* @__PURE__ */ _ksuid(ZodKSUID, params)); + inst.ipv4 = (params) => inst.check(/* @__PURE__ */ _ipv4(ZodIPv4, params)); + inst.ipv6 = (params) => inst.check(/* @__PURE__ */ _ipv6(ZodIPv6, params)); + inst.cidrv4 = (params) => inst.check(/* @__PURE__ */ _cidrv4(ZodCIDRv4, params)); + inst.cidrv6 = (params) => inst.check(/* @__PURE__ */ _cidrv6(ZodCIDRv6, params)); + inst.e164 = (params) => inst.check(/* @__PURE__ */ _e164(ZodE164, params)); + inst.datetime = (params) => inst.check(datetime(params)); + inst.date = (params) => inst.check(date(params)); + inst.time = (params) => inst.check(time(params)); + inst.duration = (params) => inst.check(duration(params)); + }); + function string(params) { + return /* @__PURE__ */ _string(ZodString, params); + } + const ZodStringFormat = /*@__PURE__*/ $constructor("ZodStringFormat", (inst, def) => { + $ZodStringFormat.init(inst, def); + _ZodString.init(inst, def); + }); + const ZodEmail = /*@__PURE__*/ $constructor("ZodEmail", (inst, def) => { + $ZodEmail.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodGUID = /*@__PURE__*/ $constructor("ZodGUID", (inst, def) => { + $ZodGUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodUUID = /*@__PURE__*/ $constructor("ZodUUID", (inst, def) => { + $ZodUUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodURL = /*@__PURE__*/ $constructor("ZodURL", (inst, def) => { + $ZodURL.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodEmoji = /*@__PURE__*/ $constructor("ZodEmoji", (inst, def) => { + $ZodEmoji.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodNanoID = /*@__PURE__*/ $constructor("ZodNanoID", (inst, def) => { + $ZodNanoID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link ZodCUID2} instead. + * See https://github.com/paralleldrive/cuid. + */ + const ZodCUID = /*@__PURE__*/ $constructor("ZodCUID", (inst, def) => { + $ZodCUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCUID2 = /*@__PURE__*/ $constructor("ZodCUID2", (inst, def) => { + $ZodCUID2.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodULID = /*@__PURE__*/ $constructor("ZodULID", (inst, def) => { + $ZodULID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodXID = /*@__PURE__*/ $constructor("ZodXID", (inst, def) => { + $ZodXID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodKSUID = /*@__PURE__*/ $constructor("ZodKSUID", (inst, def) => { + $ZodKSUID.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodIPv4 = /*@__PURE__*/ $constructor("ZodIPv4", (inst, def) => { + $ZodIPv4.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodIPv6 = /*@__PURE__*/ $constructor("ZodIPv6", (inst, def) => { + $ZodIPv6.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCIDRv4 = /*@__PURE__*/ $constructor("ZodCIDRv4", (inst, def) => { + $ZodCIDRv4.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodCIDRv6 = /*@__PURE__*/ $constructor("ZodCIDRv6", (inst, def) => { + $ZodCIDRv6.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodBase64 = /*@__PURE__*/ $constructor("ZodBase64", (inst, def) => { + $ZodBase64.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodBase64URL = /*@__PURE__*/ $constructor("ZodBase64URL", (inst, def) => { + $ZodBase64URL.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodE164 = /*@__PURE__*/ $constructor("ZodE164", (inst, def) => { + $ZodE164.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodJWT = /*@__PURE__*/ $constructor("ZodJWT", (inst, def) => { + $ZodJWT.init(inst, def); + ZodStringFormat.init(inst, def); + }); + const ZodNumber = /*@__PURE__*/ $constructor("ZodNumber", (inst, def) => { + $ZodNumber.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => numberProcessor(inst, ctx, json, params); + _installLazyMethods(inst, "ZodNumber", { + gt(value, params) { + return this.check(/* @__PURE__ */ _gt(value, params)); + }, + gte(value, params) { + return this.check(/* @__PURE__ */ _gte(value, params)); + }, + min(value, params) { + return this.check(/* @__PURE__ */ _gte(value, params)); + }, + lt(value, params) { + return this.check(/* @__PURE__ */ _lt(value, params)); + }, + lte(value, params) { + return this.check(/* @__PURE__ */ _lte(value, params)); + }, + max(value, params) { + return this.check(/* @__PURE__ */ _lte(value, params)); + }, + int(params) { + return this.check(int(params)); + }, + safe(params) { + return this.check(int(params)); + }, + positive(params) { + return this.check(/* @__PURE__ */ _gt(0, params)); + }, + nonnegative(params) { + return this.check(/* @__PURE__ */ _gte(0, params)); + }, + negative(params) { + return this.check(/* @__PURE__ */ _lt(0, params)); + }, + nonpositive(params) { + return this.check(/* @__PURE__ */ _lte(0, params)); + }, + multipleOf(value, params) { + return this.check(/* @__PURE__ */ _multipleOf(value, params)); + }, + step(value, params) { + return this.check(/* @__PURE__ */ _multipleOf(value, params)); + }, + finite() { + return this; + } + }); + const bag = inst._zod.bag; + inst.minValue = Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null; + inst.maxValue = Math.min(bag.maximum ?? Number.POSITIVE_INFINITY, bag.exclusiveMaximum ?? Number.POSITIVE_INFINITY) ?? null; + inst.isInt = (bag.format ?? "").includes("int") || Number.isSafeInteger(bag.multipleOf ?? .5); + inst.isFinite = true; + inst.format = bag.format ?? null; + }); + function number(params) { + return /* @__PURE__ */ _number(ZodNumber, params); + } + const ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def) => { + $ZodNumberFormat.init(inst, def); + ZodNumber.init(inst, def); + }); + function int(params) { + return /* @__PURE__ */ _int(ZodNumberFormat, params); + } + const ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => { + $ZodBoolean.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params); + }); + function boolean(params) { + return /* @__PURE__ */ _boolean(ZodBoolean, params); + } + const ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => { + $ZodUnknown.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => void 0; + }); + function unknown() { + return /* @__PURE__ */ _unknown(ZodUnknown); + } + const ZodNever = /*@__PURE__*/ $constructor("ZodNever", (inst, def) => { + $ZodNever.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => neverProcessor(inst, ctx, json, params); + }); + function never(params) { + return /* @__PURE__ */ _never(ZodNever, params); + } + const ZodArray = /*@__PURE__*/ $constructor("ZodArray", (inst, def) => { + $ZodArray.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => arrayProcessor(inst, ctx, json, params); + inst.element = def.element; + _installLazyMethods(inst, "ZodArray", { + min(n, params) { + return this.check(/* @__PURE__ */ _minLength(n, params)); + }, + nonempty(params) { + return this.check(/* @__PURE__ */ _minLength(1, params)); + }, + max(n, params) { + return this.check(/* @__PURE__ */ _maxLength(n, params)); + }, + length(n, params) { + return this.check(/* @__PURE__ */ _length(n, params)); + }, + unwrap() { + return this.element; + } + }); + }); + function array(element, params) { + return /* @__PURE__ */ _array(ZodArray, element, params); + } + const ZodObject = /*@__PURE__*/ $constructor("ZodObject", (inst, def) => { + $ZodObjectJIT.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => objectProcessor(inst, ctx, json, params); + defineLazy(inst, "shape", () => { + return def.shape; + }); + _installLazyMethods(inst, "ZodObject", { + keyof() { + return _enum(Object.keys(this._zod.def.shape)); + }, + catchall(catchall) { + return this.clone({ + ...this._zod.def, + catchall + }); + }, + passthrough() { + return this.clone({ + ...this._zod.def, + catchall: unknown() + }); + }, + loose() { + return this.clone({ + ...this._zod.def, + catchall: unknown() + }); + }, + strict() { + return this.clone({ + ...this._zod.def, + catchall: never() + }); + }, + strip() { + return this.clone({ + ...this._zod.def, + catchall: void 0 + }); + }, + extend(incoming) { + return extend(this, incoming); + }, + safeExtend(incoming) { + return safeExtend(this, incoming); + }, + merge(other) { + return merge(this, other); + }, + pick(mask) { + return pick(this, mask); + }, + omit(mask) { + return omit(this, mask); + }, + partial(...args) { + return partial(ZodOptional, this, args[0]); + }, + required(...args) { + return required(ZodNonOptional, this, args[0]); + } + }); + }); + function object(shape, params) { + return new ZodObject({ + type: "object", + shape: shape ?? {}, + ...normalizeParams(params) + }); + } + function looseObject(shape, params) { + return new ZodObject({ + type: "object", + shape, + catchall: unknown(), + ...normalizeParams(params) + }); + } + const ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => { + $ZodUnion.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => unionProcessor(inst, ctx, json, params); + inst.options = def.options; + }); + function union(options, params) { + return new ZodUnion({ + type: "union", + options, + ...normalizeParams(params) + }); + } + const ZodDiscriminatedUnion = /*@__PURE__*/ $constructor("ZodDiscriminatedUnion", (inst, def) => { + ZodUnion.init(inst, def); + $ZodDiscriminatedUnion.init(inst, def); + }); + function discriminatedUnion(discriminator, options, params) { + return new ZodDiscriminatedUnion({ + type: "union", + options, + discriminator, + ...normalizeParams(params) + }); + } + const ZodIntersection = /*@__PURE__*/ $constructor("ZodIntersection", (inst, def) => { + $ZodIntersection.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => intersectionProcessor(inst, ctx, json, params); + }); + function intersection(left, right) { + return new ZodIntersection({ + type: "intersection", + left, + right + }); + } + const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => { + $ZodRecord.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params); + inst.keyType = def.keyType; + inst.valueType = def.valueType; + }); + function record(keyType, valueType, params) { + if (!valueType || !valueType._zod) return new ZodRecord({ + type: "record", + keyType: string(), + valueType: keyType, + ...normalizeParams(valueType) + }); + return new ZodRecord({ + type: "record", + keyType, + valueType, + ...normalizeParams(params) + }); + } + const ZodEnum = /*@__PURE__*/ $constructor("ZodEnum", (inst, def) => { + $ZodEnum.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => enumProcessor(inst, ctx, json, params); + inst.enum = def.entries; + inst.options = Object.values(def.entries); + const keys = new Set(Object.keys(def.entries)); + inst.extract = (values, params) => { + const newEntries = {}; + for (const value of values) if (keys.has(value)) newEntries[value] = def.entries[value]; + else throw new Error(`Key ${value} not found in enum`); + return new ZodEnum({ + ...def, + checks: [], + ...normalizeParams(params), + entries: newEntries + }); + }; + inst.exclude = (values, params) => { + const newEntries = { ...def.entries }; + for (const value of values) if (keys.has(value)) delete newEntries[value]; + else throw new Error(`Key ${value} not found in enum`); + return new ZodEnum({ + ...def, + checks: [], + ...normalizeParams(params), + entries: newEntries + }); + }; + }); + function _enum(values, params) { + return new ZodEnum({ + type: "enum", + entries: Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values, + ...normalizeParams(params) + }); + } + const ZodLiteral = /*@__PURE__*/ $constructor("ZodLiteral", (inst, def) => { + $ZodLiteral.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => literalProcessor(inst, ctx, json, params); + inst.values = new Set(def.values); + Object.defineProperty(inst, "value", { get() { + if (def.values.length > 1) throw new Error("This schema contains multiple valid literal values. Use `.values` instead."); + return def.values[0]; + } }); + }); + function literal(value, params) { + return new ZodLiteral({ + type: "literal", + values: Array.isArray(value) ? value : [value], + ...normalizeParams(params) + }); + } + const ZodTransform = /*@__PURE__*/ $constructor("ZodTransform", (inst, def) => { + $ZodTransform.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => transformProcessor(inst, ctx, json, params); + inst._zod.parse = (payload, _ctx) => { + if (_ctx.direction === "backward") throw new $ZodEncodeError(inst.constructor.name); + payload.addIssue = (issue$1) => { + if (typeof issue$1 === "string") payload.issues.push(issue(issue$1, payload.value, def)); + else { + const _issue = issue$1; + if (_issue.fatal) _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = inst); + payload.issues.push(issue(_issue)); + } + }; + const output = def.transform(payload.value, payload); + if (output instanceof Promise) return output.then((output) => { + payload.value = output; + payload.fallback = true; + return payload; + }); + payload.value = output; + payload.fallback = true; + return payload; + }; + }); + function transform(fn) { + return new ZodTransform({ + type: "transform", + transform: fn + }); + } + const ZodOptional = /*@__PURE__*/ $constructor("ZodOptional", (inst, def) => { + $ZodOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function optional(innerType) { + return new ZodOptional({ + type: "optional", + innerType + }); + } + const ZodExactOptional = /*@__PURE__*/ $constructor("ZodExactOptional", (inst, def) => { + $ZodExactOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function exactOptional(innerType) { + return new ZodExactOptional({ + type: "optional", + innerType + }); + } + const ZodNullable = /*@__PURE__*/ $constructor("ZodNullable", (inst, def) => { + $ZodNullable.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nullableProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function nullable(innerType) { + return new ZodNullable({ + type: "nullable", + innerType + }); + } + const ZodDefault = /*@__PURE__*/ $constructor("ZodDefault", (inst, def) => { + $ZodDefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => defaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeDefault = inst.unwrap; + }); + function _default(innerType, defaultValue) { + return new ZodDefault({ + type: "default", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); + } + }); + } + const ZodPrefault = /*@__PURE__*/ $constructor("ZodPrefault", (inst, def) => { + $ZodPrefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => prefaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function prefault(innerType, defaultValue) { + return new ZodPrefault({ + type: "prefault", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); + } + }); + } + const ZodNonOptional = /*@__PURE__*/ $constructor("ZodNonOptional", (inst, def) => { + $ZodNonOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nonoptionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function nonoptional(innerType, params) { + return new ZodNonOptional({ + type: "nonoptional", + innerType, + ...normalizeParams(params) + }); + } + const ZodCatch = /*@__PURE__*/ $constructor("ZodCatch", (inst, def) => { + $ZodCatch.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => catchProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeCatch = inst.unwrap; + }); + function _catch(innerType, catchValue) { + return new ZodCatch({ + type: "catch", + innerType, + catchValue: typeof catchValue === "function" ? catchValue : () => catchValue + }); + } + const ZodPipe = /*@__PURE__*/ $constructor("ZodPipe", (inst, def) => { + $ZodPipe.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => pipeProcessor(inst, ctx, json, params); + inst.in = def.in; + inst.out = def.out; + }); + function pipe(in_, out) { + return new ZodPipe({ + type: "pipe", + in: in_, + out + }); + } + const ZodReadonly = /*@__PURE__*/ $constructor("ZodReadonly", (inst, def) => { + $ZodReadonly.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => readonlyProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + }); + function readonly(innerType) { + return new ZodReadonly({ + type: "readonly", + innerType + }); + } + const ZodLazy = /*@__PURE__*/ $constructor("ZodLazy", (inst, def) => { + $ZodLazy.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => lazyProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.getter(); + }); + function lazy(getter) { + return new ZodLazy({ + type: "lazy", + getter + }); + } + const ZodCustom = /*@__PURE__*/ $constructor("ZodCustom", (inst, def) => { + $ZodCustom.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => customProcessor(inst, ctx, json, params); + }); + function custom(fn, _params) { + return /* @__PURE__ */ _custom(ZodCustom, fn ?? (() => true), _params); + } + function refine(fn, _params = {}) { + return /* @__PURE__ */ _refine(ZodCustom, fn, _params); + } + function superRefine(fn, params) { + return /* @__PURE__ */ _superRefine(fn, params); + } + //#endregion + //#region ../../host/apiproxy/lib/types/api/rpc.schema.js + /** + * Message-layer zod schemas: the four wire full forms + error body + + * carrier receipt. The payload slot is unknown in the full-form schemas — business payloads + * get a second parse dispatched by method (two-level parse discipline). + * Brand cast point: rpcIdSchema, and only there. + */ + /** + * RpcId: one brand cast after schema validation (the only cast point in this + * file). No min-length: the id is an opaque echo token, and rejecting values + * here would only turn a correlatable error report into a client-side parse + * failure (the handler substitutes a sentinel when a request's id is unreadable). + */ + const rpcIdSchema = string(); + /** Error body: discriminated by code, per-branch details aligned to RpcErrorDetailsMap; details is required. */ + const rpcErrorSchema = discriminatedUnion("code", [ + object({ + code: literal("bad-request"), + message: string(), + details: object({ issues: array(custom()) }) + }), + object({ + code: literal("cancelled"), + message: string(), + details: object({}) + }), + object({ + code: literal("session-not-found"), + message: string(), + details: object({ sessionId: string() }) + }), + object({ + code: literal("model-unavailable"), + message: string(), + details: object({ + provider: string(), + model: string() + }) + }), + object({ + code: literal("session-conflict"), + message: string(), + details: object({ + sessionId: string(), + requestedCwd: string(), + existingCwd: string().optional() + }) + }), + object({ + code: literal("invalid-time-zone"), + message: string(), + details: object({ value: string() }) + }), + object({ + code: literal("workspace-attach-failed"), + message: string(), + details: object({ + sessionId: string(), + workspaceId: string() + }) + }), + object({ + code: literal("workspace-not-found"), + message: string(), + details: object({ workspaceId: string() }) + }), + object({ + code: literal("workspace-invalid-path"), + message: string(), + details: object({ path: string() }) + }), + object({ + code: literal("workspace-name-conflict"), + message: string(), + details: object({ name: string() }) + }), + object({ + code: literal("workspace-move-invalid"), + message: string(), + details: object({ + workspaceId: string(), + sessionId: string(), + beforeSessionId: string().optional() + }) + }), + object({ + code: literal("directory-unreadable"), + message: string(), + details: object({ path: string() }) + }), + object({ + code: literal("directory-exists"), + message: string(), + details: object({ path: string() }) + }), + object({ + code: literal("directory-create-failed"), + message: string(), + details: object({ path: string() }) + }), + object({ + code: literal("directory-picker-unavailable"), + message: string(), + details: object({ capability: string() }) + }), + object({ + code: literal("agent-preset-read-only"), + message: string(), + details: object({ + agentPreset: string(), + reason: string() + }) + }), + object({ + code: literal("agent-preset-locked"), + message: string(), + details: object({ + sessionId: string(), + agentPreset: string() + }) + }), + object({ + code: literal("agent-preset-conflict"), + message: string(), + details: object({ + sessionId: string(), + requestedPreset: string(), + existingPreset: string().optional() + }) + }), + object({ + code: literal("agent-preset-not-found"), + message: string(), + details: object({ + agentPreset: string(), + available: array(string()) + }) + }), + object({ + code: literal("agent-preset-invalid"), + message: string(), + details: object({ + agentPreset: string(), + reason: string() + }) + }), + object({ + code: literal("agent-busy"), + message: string(), + details: object({ reason: string() }) + }), + object({ + code: literal("attachment-error"), + message: string(), + details: object({ reason: string() }) + }), + object({ + code: literal("queue-item-not-found"), + message: string(), + details: object({ itemId: string() }) + }), + object({ + code: literal("steer-unavailable"), + message: string(), + details: object({ itemId: string() }) + }), + object({ + code: literal("command-error"), + message: string(), + details: object({}) + }), + object({ + code: literal("unknown-command"), + message: string(), + details: object({}) + }), + object({ + code: literal("settings-rejected"), + message: string(), + details: object({ ns: string() }) + }), + object({ + code: literal("settings-conflict"), + message: string(), + details: object({ + ns: string(), + expected: number(), + actual: number() + }) + }), + object({ + code: literal("credential-rejected"), + message: string(), + details: object({ ref: string() }) + }), + object({ + code: literal("model-discovery-failed"), + message: string(), + details: object({ + settingsNs: string(), + baseURL: string().optional() + }) + }), + object({ + code: literal("title-invalid"), + message: string(), + details: object({ sessionId: string() }) + }), + object({ + code: literal("fork-unavailable"), + message: string(), + details: object({ sessionId: string() }) + }), + object({ + code: literal("subagent-parent-unavailable"), + message: string(), + details: object({ parentSessionId: string() }) + }), + object({ + code: literal("subagent-not-found"), + message: string(), + details: object({ + parentSessionId: string(), + childSessionId: string() + }) + }), + object({ + code: literal("subagent-catalog-diagnostic"), + message: string(), + details: object({ + parentSessionId: string(), + childSessionId: string(), + reason: union([ + literal("corrupt"), + literal("unsupported"), + literal("unavailable") + ]) + }) + }), + object({ + code: literal("subagent-not-resumable"), + message: string(), + details: object({ childSessionId: string() }) + }), + object({ + code: literal("subagent-unauthorized"), + message: string(), + details: object({ childSessionId: string() }) + }), + object({ + code: literal("subagent-delivery-unavailable"), + message: string(), + details: object({ childSessionId: string() }) + }), + object({ + code: literal("internal"), + message: string(), + details: object({}) + }) + ]); + /** + * Business success/failure result schema (generic, reusable). + * @param value - Schema for the business value. + * @returns Schema for RpcResult. + */ + function rpcResultSchema(value) { + return union([object({ + ok: literal(true), + value + }), object({ + ok: literal(false), + error: rpcErrorSchema + })]); + } + /** ClientRequest full form (payload stays wide — the business layer runs the second parse). */ + const clientRequestSchema = object({ + type: literal("client-request"), + rpcId: rpcIdSchema, + method: string(), + payload: unknown() + }); + /** ServerResponse full form (result.value stays wide). */ + const serverResponseSchema = object({ + type: literal("server-response"), + rpcId: rpcIdSchema, + result: rpcResultSchema(unknown().optional()) + }); + /** ServerRequest full form (payload stays wide). */ + const serverRequestSchema = object({ + type: literal("server-request"), + rpcId: rpcIdSchema, + method: string(), + payload: unknown() + }); + discriminatedUnion("type", [ + clientRequestSchema, + serverResponseSchema, + serverRequestSchema, + object({ + type: literal("client-response"), + rpcId: rpcIdSchema, + result: rpcResultSchema(unknown().optional()) + }) + ]); + /** Carrier receipt schema. */ + const rpcReceiptSchema = union([object({ accepted: literal(true) }), object({ + accepted: literal(false), + reason: union([literal("not-pending"), literal("bad-response")]) + })]); + //#endregion + //#region ../../host/apiproxy/lib/types/api/session-search.js + /** + * Return the longest prefix containing at most `maximum` Unicode code points. + * @param value - text to bound. + * @param maximum - non-negative code-point limit. + * @returns `value` unchanged when it fits, otherwise a code-point-safe prefix. + */ + function truncateUnicodeCodePoints(value, maximum) { + let count = 0; + let end = 0; + for (const codePoint of value) { + if (count === maximum) return value.slice(0, end); + count++; + end += codePoint.length; + } + return value; + } + //#endregion + //#region ../../host/apiproxy/lib/types/api/sessions.schema.js + /** + * sessions domain zod schemas (names derived from map keys: sessionListRequestSchema / + * sessionListValueSchema). SessionEvent passthrough = strict envelope (type/seq/time) + wide + * data: the merge-extensible event API keeps an unknown-type branch at the union level, + * with no field-level passthrough. SessionId brand cast point: sessionIdSchema, and only there. + */ + /** SessionId: one brand cast after schema validation (the only cast point in this domain). */ + const sessionIdSchema = string().min(1); + /** MessageId: one brand cast after non-empty string validation. */ + const messageIdSchema$1 = string().min(1); + /** + * WorkspaceId: the workspace domain's one brand cast. Hosted here rather + * than in workspace.schema because session.create references it while + * workspace.schema references sessionIdSchema — schema modules must stay a + * DAG (both casts used at module top level; a cycle is a load-time TDZ). + */ + const workspaceIdSchema = string().min(1); + /** SessionEvent passthrough: strict envelope, wide data (the client fold handles unknown types via its documented default). */ + const sessionEventSchema = object({ + type: string(), + seq: number().int().nonnegative(), + time: number(), + data: unknown(), + sourceEventSeqs: array(number()).optional(), + surfaceOp: unknown().optional(), + ignorable: literal(true).optional() + }); + /** SessionSummary row of session.list (`projections` reuses the history block's shape and schema). */ + const sessionSummarySchema = object({ + sessionId: sessionIdSchema, + updatedAt: number(), + running: boolean(), + blank: boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: literal("subagent").optional(), + cwd: string().optional(), + agentPreset: string().optional(), + projections: lazy(() => sessionProjectionsBlockSchema).optional() + }); + object({ cursor: string().optional() }); + /** session.list response value. */ + const sessionListValueSchema = object({ items: array(sessionSummarySchema) }); + object({ query: string().trim().min(1).max(500).refine((query) => !query.includes("\0"), { message: "search query must not contain NUL" }) }); + /** session.search response value. */ + const sessionSearchValueSchema = object({ + items: array(object({ + sessionId: sessionIdSchema, + snippet: string().refine((snippet) => truncateUnicodeCodePoints(snippet, 240) === snippet, { message: `search snippet must contain at most 240 Unicode code points` }) + })).max(20), + hasMore: boolean() + }); + object({ + workspaceId: workspaceIdSchema.optional(), + cwd: string().optional(), + sessionId: sessionIdSchema.optional(), + agentPreset: string().optional() + }).refine((payload) => payload.workspaceId === void 0 || payload.cwd === void 0, { message: "session.create accepts workspaceId or cwd, not both" }); + /** session.create response value. */ + const sessionCreateValueSchema = object({ + sessionId: sessionIdSchema, + agentPreset: string().optional() + }); + object({ + sessionId: sessionIdSchema, + title: string() + }); + /** session.rename response value (the normalized accepted title and its event seq). */ + const sessionRenameValueSchema = object({ + title: string().min(1), + seq: number().int().nonnegative() + }); + object({ + sessionId: sessionIdSchema, + atSeq: number().int().nonnegative().optional() + }); + /** session.fork response value (the child session id). */ + const sessionForkValueSchema = object({ sessionId: sessionIdSchema }); + object({ + sessionId: sessionIdSchema, + beforeSeq: number().int().nonnegative().optional(), + maxMessages: number().int().positive().optional() + }); + /** Complete provider/model selection. */ + const modelSelectionSchema = object({ + provider: string().min(1), + model: string().min(1), + reasoningEffort: string().min(1).optional() + }); + /** Exact-model reasoning metadata. */ + const modelReasoningSchema = object({ + efforts: array(object({ + id: string().min(1), + name: string().min(1), + description: string().optional() + })).min(1), + defaultEffort: string().min(1).optional() + }); + /** One advisory model entry inside a provider group. */ + const modelCatalogModelSchema = object({ + id: string().min(1), + name: string().min(1), + description: string().optional(), + reasoning: modelReasoningSchema.optional() + }); + /** One successfully loaded provider group. */ + const modelProviderGroupSchema = object({ + id: string().min(1), + name: string().min(1), + models: array(modelCatalogModelSchema) + }); + /** One provider-local catalog failure. */ + const modelCatalogFailureSchema = object({ + id: string().min(1), + name: string().min(1), + message: string() + }); + /** + * ToolEventView passthrough: lock only the `for` discriminant and the presence + * of a card-tagged `view` object. The view interior is a host-computed product + * the client reads without echoing back; deep-validating it would hand-copy + * the dsh-tools vocabulary into this schema and drift with it. + */ + const toolEventViewSchema = discriminatedUnion("for", [object({ + for: literal("call"), + view: looseObject({ card: string() }) + }), object({ + for: literal("result"), + view: looseObject({ card: string() }) + })]); + /** One session.history item: the session event plus its optional host-computed tool view. */ + const historyEntrySchema = object({ + event: sessionEventSchema, + view: toolEventViewSchema.optional() + }); + /** + * Projection baseline passthrough: `values` stays a wide record — each value + * was already parsed by its provider's own schema on the host side, and + * deep-validating here would import every domain's schema into the carrier. + */ + const sessionProjectionsBlockSchema = object({ + asOfSeq: number().int().min(-1), + values: record(string(), unknown()) + }); + object({ + blank: boolean(), + lastPromptAt: number().nullable() + }); + object({ + maxImageBytes: number().int().positive(), + maxImagesPerMessage: number().int().positive(), + maxMessageImageBytes: number().int().positive(), + maxImagePixels: number().int().positive(), + mediaTypes: array(string()) + }); + /** session.history response value (projections rides the tail page only). */ + const sessionHistoryValueSchema = object({ + events: array(historyEntrySchema), + hasMore: boolean(), + projections: sessionProjectionsBlockSchema.optional() + }); + object({ sessionId: sessionIdSchema }); + /** session.models response value. */ + const sessionModelsValueSchema = object({ + current: modelSelectionSchema, + routable: boolean(), + groups: array(modelProviderGroupSchema), + failures: array(modelCatalogFailureSchema) + }); + object({ + sessionId: sessionIdSchema, + provider: string().min(1), + model: string().min(1), + reasoningEffort: string().min(1).optional() + }); + /** session.selectModel response value. */ + const sessionSelectModelValueSchema = object({ selected: modelSelectionSchema }); + /** ContentBlock passthrough: core is merge-extensible — the type discriminant envelope is strict, the rest stays wide. */ + const contentBlockSchema = looseObject({ type: string() }); + /** Raster image media types accepted by the version-one browser wire. */ + const imageMediaTypeSchema = union([ + literal("image/png"), + literal("image/jpeg"), + literal("image/webp"), + literal("image/gif") + ]); + /** Prompt wire content is intentionally narrower than merge-extensible durable core content. */ + const promptContentPartSchema = discriminatedUnion("type", [object({ + type: literal("text"), + text: string() + }), object({ + type: literal("image"), + mediaType: imageMediaTypeSchema, + data: string(), + name: string().optional() + })]); + object({ + sessionId: sessionIdSchema, + mode: union([literal("queue"), literal("steer")]), + content: array(promptContentPartSchema), + clientTimeZone: string().optional() + }); + /** session.prompt response value (the command slot appears only when the prompt dispatched a slash command). */ + const sessionPromptValueSchema = object({ + accepted: literal(true), + command: object({ + kind: literal("success"), + text: string().optional() + }).optional() + }); + /** Opaque attachment id after string-shape validation. */ + const attachmentIdSchema = string().min(1); + /** Durable image reference returned from the authenticated session lookup. */ + const imageAttachmentRefSchema = object({ + attachmentId: attachmentIdSchema, + mediaType: imageMediaTypeSchema, + bytes: number().int().positive(), + width: number().int().positive(), + height: number().int().positive(), + name: string().optional() + }); + object({ + sessionId: sessionIdSchema, + attachmentId: attachmentIdSchema + }); + /** session.attachment response value. */ + const sessionAttachmentValueSchema = object({ + attachment: imageAttachmentRefSchema, + data: string() + }); + object({ + sessionId: sessionIdSchema, + itemId: messageIdSchema$1, + action: discriminatedUnion("kind", [ + object({ + kind: literal("edit"), + content: array(contentBlockSchema) + }), + object({ kind: literal("remove") }), + object({ kind: literal("steer") }) + ]) + }); + /** session.updateQueue response value. */ + const sessionUpdateQueueValueSchema = object({ accepted: literal(true) }); + object({ sessionId: sessionIdSchema }); + /** session.cancel response value. */ + const sessionCancelValueSchema = object({ accepted: literal(true) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/approvals.schema.js + /** + * approvals domain zod schemas (respond is a client-response; the payload schema serves + * the /api/respond endpoint's second parse after routing via the pending table). + * ApprovalRequestId brand cast point: one. + */ + /** ApprovalRequestId: one brand cast after schema validation (the only cast point in this domain). */ + const approvalRequestIdSchema = string().min(1); + object({ + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + outcome: union([literal("allowed-once"), literal("rejected")]) + }); + /** + * One wire task view. `kind` stays an open string because producer plugins + * extend the registry's kind map by declaration merging, so the closed set is + * not knowable at this boundary. + */ + const taskViewSchema = object({ + id: string().min(1), + kind: string().min(1), + label: string().min(1), + status: union([ + literal("running"), + literal("stopping"), + literal("completed"), + literal("killed"), + literal("failed") + ]), + detail: string().optional(), + startedAt: number().int().nonnegative(), + finishedAt: number().int().nonnegative().optional() + }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/workspace.schema.js + /** + * workspace domain zod schemas (names derived from map keys). The + * WorkspaceId brand cast lives in sessions.schema (see the note there) and + * is re-exported here as the domain-local name. + */ + /** WorkspaceView row of every workspace.* response. */ + const workspaceViewSchema = object({ + workspaceId: workspaceIdSchema, + path: string(), + title: string(), + sessionIds: array(sessionIdSchema), + createdAt: string(), + updatedAt: string() + }); + object({}); + /** workspace.list response value. */ + const workspaceListValueSchema = object({ + items: array(workspaceViewSchema), + archivedSessionIds: array(sessionIdSchema) + }); + object({ path: string() }); + /** workspace.create response value. */ + const workspaceCreateValueSchema = object({ + workspace: workspaceViewSchema, + created: boolean() + }); + object({ + workspaceId: workspaceIdSchema, + title: string() + }).refine((payload) => payload.title.trim() !== "", { message: "workspace.rename requires a non-blank title" }); + /** workspace.rename response value. */ + const workspaceRenameValueSchema = object({ workspace: workspaceViewSchema }); + object({ workspaceId: workspaceIdSchema }); + /** workspace.delete response value. */ + const workspaceDeleteValueSchema = object({ deleted: literal(true) }); + object({ + workspaceId: workspaceIdSchema, + beforeWorkspaceId: workspaceIdSchema.optional() + }); + /** workspace.insertBefore response value: the complete durable display order. */ + const workspaceInsertBeforeValueSchema = object({ workspaceIds: array(workspaceIdSchema) }); + object({ + workspaceId: workspaceIdSchema, + sessionId: sessionIdSchema, + beforeSessionId: sessionIdSchema.optional() + }); + /** workspace.insertSessionBefore response value. */ + const workspaceInsertSessionBeforeValueSchema = object({ workspace: workspaceViewSchema }); + object({ sessionId: sessionIdSchema }); + /** workspace.archiveSession response value: the full updated archive set. */ + const workspaceArchiveSessionValueSchema = object({ archivedSessionIds: array(sessionIdSchema) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/events.schema.js + /** + * events domain zod schemas: MuxFrame / HostFrame unions (discriminatedUnion('type')). + * A frame is the payload slot of the ServerRequest full form; the SessionEvent inside + * a session/event frame reuses sessions.schema's strict-envelope + wide-data passthrough branch. + */ + /** Question fields validated strictly against core dsh-user-questions. */ + const askUserQuestionItemSchema = object({ + id: string(), + question: string(), + header: string().optional(), + detail: string().optional(), + options: array(object({ + label: string(), + description: string().optional() + })).optional(), + multiSelect: boolean().optional(), + intent: discriminatedUnion("kind", [object({ + kind: literal("plan-review"), + approve: string() + })]).optional() + }); + /** Unified message envelope carried by transient queue frames. */ + const messageSchema = object({ + id: string().min(1), + role: union([ + literal("system"), + literal("user"), + literal("assistant") + ]), + content: array(contentBlockSchema), + source: looseObject({ kind: string() }) + }); + /** MuxFrame union (payload slot of a mux-stream ServerRequest). */ + const muxFrameSchema = discriminatedUnion("type", [ + object({ + type: literal("session/event"), + sessionId: sessionIdSchema, + event: sessionEventSchema, + view: toolEventViewSchema.optional() + }), + object({ + type: literal("session/subscribed"), + sessionId: sessionIdSchema, + lastSeq: number().int() + }), + object({ + type: literal("approval/requested"), + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + toolName: string(), + callId: string().optional(), + reason: string().optional() + }), + object({ + type: literal("approval/resolved"), + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + outcome: union([ + literal("allowed-once"), + literal("rejected"), + literal("cancelled"), + literal("unavailable") + ]) + }), + object({ + type: literal("question/requested"), + sessionId: sessionIdSchema, + questions: array(askUserQuestionItemSchema).min(1) + }), + object({ + type: literal("question/resolved"), + sessionId: sessionIdSchema, + questionRpcId: rpcIdSchema, + outcome: union([literal("answered"), literal("cancelled")]) + }), + object({ + type: literal("session/queue"), + sessionId: sessionIdSchema, + items: array(object({ + id: messageIdSchema$1, + placement: union([ + literal("queued"), + literal("steering"), + literal("context") + ]), + message: messageSchema + })) + }), + object({ + type: literal("session/jobs"), + sessionId: sessionIdSchema, + jobs: array(taskViewSchema) + }), + object({ + type: literal("session/projection"), + sessionId: sessionIdSchema, + key: string().min(1), + value: unknown(), + seq: number().int().nonnegative() + }), + object({ + type: literal("stream/error"), + error: rpcErrorSchema + }) + ]); + /** HostFrame union (payload slot of a host-stream ServerRequest). */ + const hostFrameSchema = discriminatedUnion("type", [ + object({ + type: literal("host/session-added"), + sessionId: sessionIdSchema, + blank: boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: literal("subagent").optional(), + cwd: string().optional(), + agentPreset: string().optional() + }), + object({ + type: literal("host/session-removed"), + sessionId: sessionIdSchema + }), + object({ + type: literal("host/session-status"), + sessionId: sessionIdSchema, + running: boolean() + }), + object({ + type: literal("host/agent-error"), + sessionId: sessionIdSchema, + message: string() + }), + object({ + type: literal("host/workspace-changed"), + workspace: workspaceViewSchema + }), + object({ + type: literal("host/workspace-removed"), + workspaceId: workspaceIdSchema + }), + object({ + type: literal("host/workspace-order-changed"), + workspaceIds: array(workspaceIdSchema) + }), + object({ + type: literal("host/archived-sessions-changed"), + archivedSessionIds: array(sessionIdSchema) + }), + object({ + type: literal("host/remote-event"), + event: string().min(1), + args: array(unknown()) + }), + object({ + type: literal("stream/error"), + error: rpcErrorSchema + }) + ]); + object({}); + /** host.describe response value. */ + const hostDescribeValueSchema = object({ + version: string(), + cwd: string(), + provider: string().optional(), + model: string().optional(), + attachedSessions: number().int().nonnegative(), + canOpenPath: boolean() + }); + object({}); + /** host.pickDirectory response value; null means the user cancelled. */ + const hostPickDirectoryValueSchema = object({ path: string().nullable() }); + /** Directory row shared by listing entries and breadcrumb crumbs. */ + const directoryEntrySchema = object({ + name: string(), + path: string(), + hidden: boolean() + }); + object({ path: string().optional() }); + /** host.listDirectory response value. */ + const hostListDirectoryValueSchema = object({ + path: string(), + home: string(), + crumbs: array(directoryEntrySchema), + entries: array(directoryEntrySchema), + truncated: boolean() + }); + object({ + path: string(), + name: string() + }).refine((payload) => payload.name.trim() !== "" && payload.name !== "." && payload.name !== ".." && !/[/\\]/.test(payload.name), { message: "host.createDirectory requires a single non-blank path segment name" }); + /** host.createDirectory response value: the created directory's absolute path. */ + const hostCreateDirectoryValueSchema = object({ path: string() }); + object({ path: string().min(1) }); + /** host.openPath response value. */ + const hostOpenPathValueSchema = object({ opened: literal(true) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/skills.schema.js + /** + * skills domain zod schemas (names derived from map keys: skillListRequestSchema / + * skillListValueSchema). + */ + /** SkillEntry row of skill.list. */ + const skillEntrySchema = object({ + name: string().min(1), + description: string(), + whenToUse: string().optional(), + modelInvocable: boolean() + }); + object({ sessionId: sessionIdSchema }); + /** skill.list response value. */ + const skillListValueSchema = object({ skills: array(skillEntrySchema) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/agent-presets.schema.js + /** + * agent-presets domain zod schemas (names derived from map keys: + * agentPresetListRequestSchema / agentPresetListValueSchema). + */ + /** AgentPresetEntry row of agentPreset.list. */ + const agentPresetEntrySchema = object({ + id: string().min(1), + trust: union([literal("system"), literal("user")]), + isDefault: boolean(), + name: string().optional(), + description: string().optional(), + broken: string().min(1).optional() + }); + object({}); + /** agentPreset.list response value. */ + const agentPresetListValueSchema = object({ + presets: array(agentPresetEntrySchema), + authorable: boolean(), + hasDocument: boolean() + }); + object({ + sessionId: sessionIdSchema, + agentPreset: string().min(1) + }); + /** agentPreset.select response value. */ + const agentPresetSelectValueSchema = object({ agentPreset: string() }); + object({ agentPreset: string().min(1) }); + /** agentPreset.read response value. */ + const agentPresetReadValueSchema = object({ + agentPreset: string(), + trust: union([literal("system"), literal("user")]), + content: string(), + name: string().optional(), + description: string().optional() + }); + object({ + from: string().min(1), + agentPreset: string().min(1), + name: string().optional() + }); + /** agentPreset.copy response value. */ + const agentPresetCopyValueSchema = object({ agentPreset: string() }); + object({ agentPreset: string().min(1) }); + /** agentPreset.openDocument response value. */ + const agentPresetOpenDocumentValueSchema = union([object({ opened: literal(true) }), object({ + opened: literal(false), + path: string() + })]); + object({ agentPreset: string().min(1) }); + /** agentPreset.remove response value. */ + const agentPresetRemoveValueSchema = object({}); + //#endregion + //#region ../../host/apiproxy/lib/types/api/goals.schema.js + /** + * goals domain zod schemas. Mutation-only shapes: every value schema is a + * `{ ref }` acknowledgement (clear: `{ cleared }`) — the current goal state + * travels exclusively on the 'goal' session projection. + */ + /** GoalRef schema. */ + const goalRefSchema = object({ + id: string(), + revision: number().int().positive() + }); + /** Shared `{ ref }` acknowledgement value of every non-clear mutation. */ + const goalRefValueSchema = object({ ref: goalRefSchema }); + object({ + sessionId: string(), + objective: string().min(1), + maxGoalRounds: number().int().positive().optional() + }); + /** goal.create response value. */ + const goalCreateValueSchema = goalRefValueSchema; + object({ + sessionId: string(), + ref: goalRefSchema, + objective: string().min(1).optional(), + maxGoalRounds: number().int().positive().optional() + }).refine((value) => value.objective !== void 0 || value.maxGoalRounds !== void 0, { message: "goal.edit requires objective or maxGoalRounds" }); + /** goal.edit response value. */ + const goalEditValueSchema = goalRefValueSchema; + object({ + sessionId: string(), + ref: goalRefSchema + }); + /** goal.pause response value. */ + const goalPauseValueSchema = goalRefValueSchema; + object({ + sessionId: string(), + ref: goalRefSchema + }); + /** goal.resume response value. */ + const goalResumeValueSchema = goalRefValueSchema; + object({ + sessionId: string(), + ref: goalRefSchema + }); + /** goal.complete response value. */ + const goalCompleteValueSchema = goalRefValueSchema; + object({ + sessionId: string(), + ref: goalRefSchema + }); + /** goal.clear response value. */ + const goalClearValueSchema = object({ cleared: literal(true) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/settings.schema.js + /** + * settings domain zod schemas (names derived from map keys: settingsDescribeRequestSchema / + * settingsDescribeValueSchema / settingsUpdate* / settingsReplace*). + */ + /** One redacted secret slot. */ + const settingsSecretViewSchema = object({ + path: array(string()), + set: boolean() + }); + /** SettingsNamespaceView row of settings.describe and the write responses. */ + const settingsNamespaceViewSchema = object({ + ns: string().min(1), + schema: unknown(), + value: unknown(), + base: unknown().optional(), + user: unknown().optional(), + applies: union([literal("live"), literal("restart")]), + secrets: array(settingsSecretViewSchema), + revision: number() + }); + object({}); + /** settings.describe response value. */ + const settingsDescribeValueSchema = object({ + writable: boolean(), + hasDocument: boolean(), + namespaces: array(settingsNamespaceViewSchema) + }); + object({}); + /** settings.openDocument response value. */ + const settingsOpenDocumentValueSchema = object({ opened: literal(true) }); + object({ + ns: string().min(1), + patch: record(string(), unknown()), + expectedRevision: number().optional() + }); + /** settings.update response value: the namespace's new redacted view. */ + const settingsUpdateValueSchema = settingsNamespaceViewSchema; + object({ + ns: string().min(1), + section: record(string(), unknown()), + expectedRevision: number().optional() + }); + /** One path-addressed edit of settings.mutate. */ + const settingsPathOpSchema = discriminatedUnion("op", [object({ + op: literal("set"), + path: array(string()), + value: unknown() + }), object({ + op: literal("unset"), + path: array(string()) + })]); + object({ + ns: string().min(1), + ops: array(settingsPathOpSchema), + expectedRevision: number().optional() + }); + /** settings.mutate response value: the namespace's new redacted view. */ + const settingsMutateValueSchema = settingsNamespaceViewSchema; + /** settings.replace response value. */ + const settingsReplaceValueSchema = settingsNamespaceViewSchema; + //#endregion + //#region ../../host/apiproxy/lib/types/api/credentials.schema.js + /** + * credentials domain zod schemas (names derived from map keys: + * credentialsDescribeRequestSchema / credentialsDescribeValueSchema / …). + * The reference-name pattern mirrors the seam's `credentialRef` guard so an + * invalid name fails as `bad-request` before reaching the service. + */ + /** POSIX-portable environment-variable name (the seam's `credentialRef` pattern). */ + const credentialRefNameSchema = string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/); + /** CredentialView entry of credentials.describe. */ + const credentialViewSchema = object({ + configured: boolean(), + source: string().optional(), + writable: boolean() + }); + object({ refs: array(credentialRefNameSchema).max(64) }); + /** credentials.describe response value. */ + const credentialsDescribeValueSchema = object({ credentials: record(string(), credentialViewSchema) }); + object({ + ref: credentialRefNameSchema, + value: string().min(1) + }); + /** credentials.set response value. */ + const credentialsSetValueSchema = object({}); + object({ ref: credentialRefNameSchema }); + /** credentials.unset response value. */ + const credentialsUnsetValueSchema = object({}); + //#endregion + //#region ../../host/apiproxy/lib/types/api/llm.schema.js + /** + * llm domain zod schemas (names derived from map keys: llmProvidersRequestSchema / + * llmProvidersValueSchema / llmModelsRequestSchema / llmModelsValueSchema). + */ + /** ConfigurableProviderView row of llm.providers. */ + const configurableProviderViewSchema = object({ + provider: string().min(1), + displayName: string().min(1), + settingsNs: string(), + settingsPath: array(string()), + active: boolean(), + declared: boolean().optional() + }); + object({}); + /** llm.providers response value. */ + const llmProvidersValueSchema = object({ providers: array(configurableProviderViewSchema) }); + object({}); + /** llm.models response value. */ + const llmModelsValueSchema = object({ + groups: array(modelProviderGroupSchema), + failures: array(modelCatalogFailureSchema) + }); + /** DiscoveredModelView row of llm.discoverModels. */ + const discoveredModelViewSchema = object({ + id: string().min(1), + name: string().min(1).optional(), + contextWindow: number().int().positive().optional(), + maxTokens: number().int().positive().optional() + }); + object({ + settingsNs: string().min(1), + provider: string().min(1).optional(), + baseURL: string().min(1).optional(), + api: string().min(1).optional(), + apiKey: string().min(1).optional() + }); + /** llm.discoverModels response value. */ + const llmDiscoverModelsValueSchema = object({ models: array(discoveredModelViewSchema) }); + //#endregion + //#region ../../host/apiproxy/lib/types/api/subagents.schema.js + /** Zod schemas for the browser-safe subagent domain. */ + /** Healthy and diagnostic durable catalog rows. */ + const subagentListEntrySchema = union([ + object({ + kind: literal("child"), + id: sessionIdSchema, + mode: literal("one-shot"), + activity: union([literal("running"), literal("inactive")]), + hasChildren: boolean(), + label: string().optional() + }), + object({ + kind: literal("child"), + id: sessionIdSchema, + mode: literal("continuable"), + activity: union([literal("running"), literal("inactive")]), + hasChildren: boolean(), + label: string() + }), + object({ + kind: literal("diagnostic"), + id: sessionIdSchema, + reason: union([ + literal("corrupt"), + literal("unsupported"), + literal("unavailable") + ]) + }) + ]); + object({ parentSessionId: sessionIdSchema }); + /** subagent.list response value. */ + const subagentListValueSchema = object({ + entries: array(subagentListEntrySchema), + parentAvailable: boolean() + }); + object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: union([literal("one-shot"), literal("continuable")]), + beforeSeq: number().int().nonnegative().optional(), + maxMessages: number().int().positive().optional() + }); + /** subagent.history response value. */ + const subagentHistoryValueSchema = object({ + events: array(historyEntrySchema), + hasMore: boolean(), + projections: sessionProjectionsBlockSchema.optional() + }); + object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: literal("continuable"), + content: array(contentBlockSchema), + clientTimeZone: string().optional() + }); + object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: literal("continuable") + }); + /** subagent.interrupt response value. */ + const subagentInterruptValueSchema = object({ accepted: literal(true) }); + //#endregion + //#region ../../host/apiproxy/lib/types/fetch/client.js + /** + * Client side of the fetch carrier. AbstractApiClient holds every protocol invariant: rpcId minting, + * four-quadrant envelope wrap/unwrap, zod parsing, in-process SSE frame decoding, and the payload-direct + * IApiClient domain methods (business code never mints). Platform differences ride two aspects: + * abstract doFetch (transport) + overridable onEnvelope (tap). ApiProxy (the impl face) is untouched. + */ + /** + * S→C second-level parse table: value schema by method (the response-path + * mirror of the handler's request table; key coverage compiler-enforced against RpcMethodMap). + */ + const UNARY_VALUE_SCHEMAS = { + "session.list": sessionListValueSchema, + "session.search": sessionSearchValueSchema, + "session.create": sessionCreateValueSchema, + "session.history": sessionHistoryValueSchema, + "session.models": sessionModelsValueSchema, + "session.selectModel": sessionSelectModelValueSchema, + "session.rename": sessionRenameValueSchema, + "session.fork": sessionForkValueSchema, + "session.prompt": sessionPromptValueSchema, + "session.attachment": sessionAttachmentValueSchema, + "session.updateQueue": sessionUpdateQueueValueSchema, + "session.cancel": sessionCancelValueSchema, + "subagent.list": subagentListValueSchema, + "subagent.history": subagentHistoryValueSchema, + "subagent.prompt": object({ messageId: string() }), + "subagent.interrupt": subagentInterruptValueSchema, + "host.describe": hostDescribeValueSchema, + "host.pickDirectory": hostPickDirectoryValueSchema, + "host.listDirectory": hostListDirectoryValueSchema, + "host.createDirectory": hostCreateDirectoryValueSchema, + "host.openPath": hostOpenPathValueSchema, + "workspace.list": workspaceListValueSchema, + "workspace.create": workspaceCreateValueSchema, + "workspace.rename": workspaceRenameValueSchema, + "workspace.delete": workspaceDeleteValueSchema, + "workspace.insertBefore": workspaceInsertBeforeValueSchema, + "workspace.insertSessionBefore": workspaceInsertSessionBeforeValueSchema, + "workspace.archiveSession": workspaceArchiveSessionValueSchema, + "skill.list": skillListValueSchema, + "agentPreset.list": agentPresetListValueSchema, + "agentPreset.select": agentPresetSelectValueSchema, + "agentPreset.read": agentPresetReadValueSchema, + "agentPreset.copy": agentPresetCopyValueSchema, + "agentPreset.openDocument": agentPresetOpenDocumentValueSchema, + "agentPreset.remove": agentPresetRemoveValueSchema, + "goal.create": goalCreateValueSchema, + "goal.edit": goalEditValueSchema, + "goal.pause": goalPauseValueSchema, + "goal.resume": goalResumeValueSchema, + "goal.complete": goalCompleteValueSchema, + "goal.clear": goalClearValueSchema, + "settings.describe": settingsDescribeValueSchema, + "settings.openDocument": settingsOpenDocumentValueSchema, + "settings.update": settingsUpdateValueSchema, + "settings.replace": settingsReplaceValueSchema, + "settings.mutate": settingsMutateValueSchema, + "credentials.describe": credentialsDescribeValueSchema, + "credentials.set": credentialsSetValueSchema, + "credentials.unset": credentialsUnsetValueSchema, + "llm.providers": llmProvidersValueSchema, + "llm.models": llmModelsValueSchema, + "llm.discoverModels": llmDiscoverModelsValueSchema + }; + /** Default timeout for bounded unary calls (rpc-compare 2026-07-19: a hung host must not leave callers pending forever). */ + const DEFAULT_TIMEOUT_MS = 3e4; + /** URL base for in-process handler injection (fake authority, opencode precedent). */ + const INTERNAL_BASE$1 = "http://dsh.internal"; + /** + * Abstract fetch-carrier client. Subclasses supply the transport (doFetch) and may refine the + * per-message tap (onEnvelope) — platform aspects stay in subclasses, protocol invariants stay + * here. Envelope observation is a first-class aspect of this data middle layer: the instance + * owns a microtask-batched buffer (frame storms must not cost one consumer update per frame), + * and observers subscribe via subscribeEnvelopes. The isomorphic point survives: an in-process + * subclass whose doFetch is toFetchHandler(api).fetch never touches the network. + */ + var AbstractApiClient = class { + timeoutMs; + /** Instance-owned observation buffer (module-level state would leak across instances/tests). */ + envelopeBatch = []; + flushScheduled = false; + envelopeListeners = /* @__PURE__ */ new Set(); + /** @param timeoutMs - timeout for bounded unary calls; user-paced calls and streams do not use it. */ + constructor(timeoutMs = DEFAULT_TIMEOUT_MS) { + this.timeoutMs = timeoutMs; + } + /** + * Subscribe to batched envelope observation (diagnostics/logging consumers). + * Batches follow microtask boundaries; a listener throw is isolated (observation + * must never break the carrier). + * @param listener - receives each flushed batch in arrival order. + * @returns unsubscribe function. + */ + subscribeEnvelopes(listener) { + this.envelopeListeners.add(listener); + return () => { + this.envelopeListeners.delete(listener); + }; + } + /** Per-message tap: feeds the instance buffer. Subclasses may override to observe unbatched (call super to keep batching). */ + onEnvelope(message) { + if (this.envelopeListeners.size === 0) return; + this.envelopeBatch.push(message); + if (this.flushScheduled) return; + this.flushScheduled = true; + queueMicrotask(() => { + this.flushScheduled = false; + const batch = this.envelopeBatch; + this.envelopeBatch = []; + for (const notify of this.envelopeListeners) try { + notify(batch); + } catch (error) { + console.error("[apiproxy] envelope listener threw:", error); + } + }); + } + /** Browser = same-origin (a fake authority would fail DNS on real requests); no-location env (Node) = fake authority. */ + resolveBase() { + const loc = globalThis.location; + return loc?.origin !== void 0 && loc.origin !== "null" ? loc.origin : INTERNAL_BASE$1; + } + mintRpcId() { + return RpcId(crypto.randomUUID()); + } + /** + * Shared POST leg of both C→S carriers (callUnary/respond): JSON body, + * optional default timeout merged with the caller's external signal, non-2xx → transport throw. + */ + async postJson(path, body, signal, timeoutPolicy = "default") { + const requestSignal = timeoutPolicy === "default" ? signal === void 0 ? AbortSignal.timeout(this.timeoutMs) : AbortSignal.any([AbortSignal.timeout(this.timeoutMs), signal]) : signal; + const response = await this.doFetch(new URL(path, this.resolveBase()), { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), + ...requestSignal === void 0 ? {} : { signal: requestSignal } + }); + if (!response.ok) throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + return response; + } + /** + * Unary protocol path: mint → tap → POST full form → envelope parse → verify + * echo → value parse → tap → narrow. Virtual so a fake carrier (fixture) can + * override transport at this layer. + */ + async callUnary(method, payload, signal, timeoutPolicy = "default") { + const message = { + type: "client-request", + rpcId: this.mintRpcId(), + method, + payload + }; + this.onEnvelope(message); + const response = await this.postJson(`/api/${method}`, message, signal, timeoutPolicy); + const full = serverResponseSchema.parse(await response.json()); + this.onEnvelope(full); + if (full.rpcId !== message.rpcId) throw new Error(`rpcId mismatch for ${method}: sent ${message.rpcId}, got ${full.rpcId}`); + if (!full.result.ok) return { + rpcId: full.rpcId, + result: full.result + }; + const value = UNARY_VALUE_SCHEMAS[method].parse(full.result.value); + return { + rpcId: full.rpcId, + result: { + ok: true, + value + } + }; + } + /** Mux stream opener; virtual for the same override reason as callUnary. */ + openMux(_payload, signal, onOpen) { + return this.readSse("/api/events.mux", signal, muxFrameSchema, onOpen); + } + /** Host stream opener; virtual. */ + openHost(_payload, signal, onOpen) { + return this.readSse("/api/events.host", signal, hostFrameSchema, onOpen); + } + /** + * SSE protocol path: streaming fetch (not EventSource), '\n\n' framing, ServerRequest envelope + + * frame-schema parse, tap, narrow yield. onOpen fires once the response headers are in and the + * body is readable — the stream-established signal, before any frame arrives. A frame that fails + * either parse level is reported and skipped (one corrupt frame must not kill the stream; the + * client's gap detection covers whatever the frame carried). + */ + async *readSse(path, signal, frameSchema, onOpen) { + const response = await this.doFetch(new URL(path, this.resolveBase()), { signal }); + if (!response.ok || response.body === null) throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + onOpen?.(); + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let buffer = ""; + try { + while (true) { + const { done, value } = await reader.read(); + if (done) return; + buffer += decoder.decode(value, { stream: true }); + let boundary; + while ((boundary = buffer.indexOf("\n\n")) !== -1) { + const chunk = buffer.slice(0, boundary); + buffer = buffer.slice(boundary + 2); + const data = chunk.split("\n").filter((line) => line.startsWith("data: ")).map((line) => line.slice(6)).join(""); + if (data === "") continue; + let full; + let frame; + try { + full = serverRequestSchema.parse(JSON.parse(data)); + frame = frameSchema.parse(full.payload); + } catch (error) { + console.error(`[apiproxy] dropping malformed SSE frame on ${path}:`, error); + continue; + } + this.onEnvelope(full); + yield { + rpcId: full.rpcId, + payload: frame + }; + } + } + } finally { + await reader.cancel().catch(() => void 0); + } + } + sessions = { + list: (payload, signal) => this.callUnary("session.list", payload, signal), + search: (payload, signal) => this.callUnary("session.search", payload, signal), + create: (payload, signal) => this.callUnary("session.create", payload, signal), + history: (payload, signal) => this.callUnary("session.history", payload, signal), + models: (payload, signal) => this.callUnary("session.models", payload, signal), + selectModel: (payload, signal) => this.callUnary("session.selectModel", payload, signal), + rename: (payload, signal) => this.callUnary("session.rename", payload, signal), + fork: (payload, signal) => this.callUnary("session.fork", payload, signal), + prompt: (payload, signal) => this.callUnary("session.prompt", payload, signal), + attachment: (payload, signal) => this.callUnary("session.attachment", payload, signal), + updateQueue: (payload, signal) => this.callUnary("session.updateQueue", payload, signal), + cancel: (payload, signal) => this.callUnary("session.cancel", payload, signal) + }; + subagents = { + list: (payload, signal) => this.callUnary("subagent.list", payload, signal), + history: (payload, signal) => this.callUnary("subagent.history", payload, signal), + prompt: (payload, signal) => this.callUnary("subagent.prompt", payload, signal), + interrupt: (payload, signal) => this.callUnary("subagent.interrupt", payload, signal) + }; + host = { + describe: (payload, signal) => this.callUnary("host.describe", payload, signal), + pickDirectory: (payload, signal) => this.callUnary("host.pickDirectory", payload, signal, "caller-signal-only"), + listDirectory: (payload, signal) => this.callUnary("host.listDirectory", payload, signal), + createDirectory: (payload, signal) => this.callUnary("host.createDirectory", payload, signal), + openPath: (payload, signal) => this.callUnary("host.openPath", payload, signal) + }; + workspace = { + list: (payload, signal) => this.callUnary("workspace.list", payload, signal), + create: (payload, signal) => this.callUnary("workspace.create", payload, signal), + rename: (payload, signal) => this.callUnary("workspace.rename", payload, signal), + delete: (payload, signal) => this.callUnary("workspace.delete", payload, signal), + insertBefore: (payload, signal) => this.callUnary("workspace.insertBefore", payload, signal), + insertSessionBefore: (payload, signal) => this.callUnary("workspace.insertSessionBefore", payload, signal), + archiveSession: (payload, signal) => this.callUnary("workspace.archiveSession", payload, signal) + }; + skills = { list: (payload, signal) => this.callUnary("skill.list", payload, signal) }; + agentPresets = { + list: (payload, signal) => this.callUnary("agentPreset.list", payload, signal), + select: (payload, signal) => this.callUnary("agentPreset.select", payload, signal), + read: (payload, signal) => this.callUnary("agentPreset.read", payload, signal), + copy: (payload, signal) => this.callUnary("agentPreset.copy", payload, signal), + openDocument: (payload, signal) => this.callUnary("agentPreset.openDocument", payload, signal), + remove: (payload, signal) => this.callUnary("agentPreset.remove", payload, signal) + }; + goals = { + create: (payload, signal) => this.callUnary("goal.create", payload, signal), + edit: (payload, signal) => this.callUnary("goal.edit", payload, signal), + pause: (payload, signal) => this.callUnary("goal.pause", payload, signal), + resume: (payload, signal) => this.callUnary("goal.resume", payload, signal), + complete: (payload, signal) => this.callUnary("goal.complete", payload, signal), + clear: (payload, signal) => this.callUnary("goal.clear", payload, signal) + }; + settings = { + describe: (payload, signal) => this.callUnary("settings.describe", payload, signal), + openDocument: (payload, signal) => this.callUnary("settings.openDocument", payload, signal), + update: (payload, signal) => this.callUnary("settings.update", payload, signal), + replace: (payload, signal) => this.callUnary("settings.replace", payload, signal), + mutate: (payload, signal) => this.callUnary("settings.mutate", payload, signal) + }; + credentials = { + describe: (payload, signal) => this.callUnary("credentials.describe", payload, signal), + set: (payload, signal) => this.callUnary("credentials.set", payload, signal), + unset: (payload, signal) => this.callUnary("credentials.unset", payload, signal) + }; + llm = { + providers: (payload, signal) => this.callUnary("llm.providers", payload, signal), + models: (payload, signal) => this.callUnary("llm.models", payload, signal), + discoverModels: (payload, signal) => this.callUnary("llm.discoverModels", payload, signal) + }; + events = { + mux: (payload, signal, onOpen) => this.openMux(payload, signal, onOpen), + host: (payload, signal, onOpen) => this.openHost(payload, signal, onOpen) + }; + async respond(message, signal) { + this.onEnvelope(message); + const response = await this.postJson("/api/respond", message, signal); + return rpcReceiptSchema.parse(await response.json()); + } + }; + //#endregion + //#region lib/types/client/random-uuid.js + /** Browser-safe UUID generation for client-side wire correlation. */ + /** + * Generate an RFC 4122 version 4 UUID without requiring a secure context. + * @returns a UUID backed by `crypto.getRandomValues()`, which browsers expose on insecure origins. + */ + function randomUuid() { + const bytes = globalThis.crypto.getRandomValues(new Uint8Array(16)); + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + view.setUint8(6, view.getUint8(6) & 15 | 64); + view.setUint8(8, view.getUint8(8) & 63 | 128); + const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(""); + return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`; + } + //#endregion + //#region lib/types/client/fixture.js + /** The fake carrier mints like a real one (business code never mints). */ + function rpcRequest(payload) { + return { + rpcId: RpcId(randomUuid()), + payload + }; + } + function text(t) { + return [{ + type: "text", + text: t + }]; + } + function userMessage(content, source = { kind: "user" }) { + return createUserMessage({ + content, + source + }); + } + function assistantMessage(content, model = "fx-1") { + return createAssistantMessage({ + content, + source: { + provider: "fixture", + model + } + }); + } + function toolResultMessage(callId, content, isError) { + return createToolResultMessage({ + callId: CallId(callId), + content, + isError + }); + } + const MARKDOWN_FIXTURE = [ + "# Markdown fixture", + "", + "Assistant output renders **strong text**, *emphasis*, and `inline code`.", + "", + "- first item", + " - nested item", + "", + "| Area | State |", + "| --- | --- |", + "| history | rendered |", + "| streaming | stable |", + "", + "[DeepSeek](https://www.deepseek.com)", + "", + "```ts", + "const markdown = true", + "```" + ].join("\n"); + const USER_MARKDOWN_LITERAL = "用户字面量:# 不渲染 `code` [link](https://example.com)"; + /** + * SGR wrapper for the terminal output sample below: authoring the escapes as + * `\u001b` keeps literal control bytes out of this source file. + * @param code - the SGR parameter (an ANSI color or attribute number). + * @param body - the text the attribute applies to. + * @returns the body wrapped in the attribute and a reset. + */ + function sgr(code, body) { + return `\u001b[${code}m${body}\u001b[0m`; + } + /** + * Terminal output sample for fixture turn 66, authored to carry every feature + * the terminal card draws that turn 60's two prompt rows cannot reach: + * basic-16 SGR foreground runs (green, red, bright-black) that must resolve to + * `--dsw-*` tokens, a bold run, column-aligned table rows that must scroll + * rather than fold, more than DEFAULT_TERMINAL_MAX_LINES (16) lines so the + * height cap collapses the middle. The exit status is authored separately in + * TERMINAL_EXIT_STATUS and deliberately absent from this text: the real bash + * presenter CONSUMES its `[exit code: N]` marker out of the body, because a + * terminal card shows the exit as its own pill and leaving the marker in would + * render it twice (packages/shell/tool-bash/src/render.ts). + */ + const TERMINAL_OUTPUT_FIXTURE = [ + sgr(1, "Running 4 checks"), + `${sgr(32, "✓")} typecheck 1.82s`, + `${sgr(32, "✓")} lint 0.94s`, + `${sgr(32, "✓")} duplication 2.10s`, + `${sgr(31, "✗")} unit 8.41s`, + "", + sgr(90, "packages/client/ui-primitives/tests/terminal-block.client.spec.tsx"), + ` ${sgr(31, "FAIL")} caps output at the configured line budget`, + " expected 16 lines, received 24", + "", + "NAME LINES BRANCHES FUNCTIONS UNCOVERED", + "TerminalBlock.tsx 100% 100% 100% -", + "ansi.ts 100% 100% 100% -", + "clipboard.ts 100% 100% 100% -", + "CodeBlock.tsx 98.4% 96.2% 100% 41-43", + "highlight.ts 100% 100% 100% -", + "Pill.tsx 100% 100% 100% -", + "StateDot.tsx 100% 100% 100% -", + "markdown/Markdown.tsx 100% 100% 100% -", + "", + sgr(31, "1 of 4 checks failed") + ].join("\n"); + /** + * Exit status for each terminal sample, keyed by its output text. Authored + * alongside the sample rather than parsed back out of its trailing marker, + * which is the bash tool's own job and not something to reimplement here. + */ + const TERMINAL_EXIT_STATUS = { [TERMINAL_OUTPUT_FIXTURE]: { exitCode: 1 } }; + /** + * Structured grep result for the search sample (turn 67): matches grouped by + * file, authored inline because the client-side fixture cannot import the tool + * that produces the canonical value. `truncated` with a larger `total` than the + * retained match count exercises the search card's capped indicator; the file + * with more than CHAT_SEARCH_MAX_LINES rows exercises its head/tail height cap. + */ + const SEARCH_MATCHES_FIXTURE = [ + { + path: "packages/client/ui-primitives/src/SearchBlock.tsx", + matches: [ + { + lineNumber: 16, + line: "export const DEFAULT_SEARCH_MAX_LINES = 16" + }, + { + lineNumber: 138, + line: "export function SearchBlock(props: SearchBlockProps) {" + }, + { + lineNumber: 141, + line: " const [collapsed, setCollapsed] = useState>(() => new Set())" + } + ] + }, + { + path: "packages/client/ui-tool/src/client/tool/models/search-card-model.ts", + matches: [{ + lineNumber: 45, + line: "export const CHAT_SEARCH_MAX_LINES = 8" + }, { + lineNumber: 130, + line: "export function searchCardModel(block: ToolCallBlock): SearchCardModel | null {" + }] + }, + { + path: "packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx", + matches: [ + { + lineNumber: 34, + line: "export function SearchRow({ toolName, block, inspect, t }: SearchRowProps) {" + }, + { + lineNumber: 36, + line: " const search = searchCardModel(block)" + }, + { + lineNumber: 56, + line: " search={search}" + }, + { + lineNumber: 78, + line: " yield ctx.slots.register({ name: 'tool.call.toolview', key: 'grep', locale: NS }, SearchRow)" + } + ] + } + ]; + /** + * The model-facing grep render text for the sample — what a UI without a search + * card shows, attached as the view's `content`. Mirrors the real grep + * presenter's shape (see formatGrepOutput in dsh-tool-fs-search): a + * `Found X of Y matches` header, the matches grouped under file headers with + * `Line N:` rows, then a spill-recovery footer. + */ + const SEARCH_MATCHES_TEXT = [ + "Found 9 of 42 matches", + "", + ...SEARCH_MATCHES_FIXTURE.map((file) => [file.path, ...file.matches.map((m) => `Line ${m.lineNumber}: ${m.line}`)].join("\n")), + "", + "(Full grep result stored at: fixture://spill/grep-66. Read it to see every match.)" + ].join("\n"); + /** + * Structured glob result for the search sample (turn 68): a flat path list, + * truncated with a larger `total` so the path card shows its capped indicator. + */ + const SEARCH_PATHS_FIXTURE = [ + "packages/client/ui-primitives/src/SearchBlock.tsx", + "packages/client/ui-primitives/src/SearchBlock.module.css", + "packages/client/ui-tool/src/client/tool/models/search-card-model.ts", + "packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx", + "packages/client/ui-tool/tests/search-card.client.spec.tsx" + ]; + /** + * The model-facing glob render text — the newline-joined path list plus a + * spill-recovery footer, mirroring the real glob presenter's shape (see + * formatGlobOutput in dsh-tool-fs-search). + */ + const SEARCH_PATHS_TEXT = [ + ...SEARCH_PATHS_FIXTURE, + "", + "(Showing 5 of 23 paths. Full sorted result stored at: fixture://spill/glob-67. Read it to see every path.)" + ].join("\n"); + /** + * Read-card sample for the read turn: a WINDOW past an offset, so the line + * numbers start above 1 (the card's gutter keeps the file's own numbering) and + * `totalLines` exceeds the window (the card shows a "showing N of M" note). The + * fixture is client-side and cannot import the read tool, so the structured + * window is authored inline exactly as the tool would project it through + * `presentationMeta`. `lang` is a `ts` hint so the shiki path highlights it. + */ + const READ_SAMPLE_FIRST_LINE = 41; + const READ_SAMPLE_SOURCE = [ + "export interface ReadBlockProps {", + " label?: string | undefined", + " lines: readonly ReadBlockLine[]", + " totalLines: number", + " lang?: string | undefined", + " maxLines?: number | undefined", + " className?: string | undefined", + "}", + "", + "// A windowed read keeps the file line numbers in the gutter.", + "const marker = \"fixture read sample\"" + ]; + const READ_SAMPLE_LINES = READ_SAMPLE_SOURCE.map((text, index) => ({ + number: READ_SAMPLE_FIRST_LINE + index, + text + })); + const READ_SAMPLE_PATH = "packages/client/ui-primitives/src/ReadBlock.tsx"; + const READ_SAMPLE_TOTAL = 180; + const READ_SAMPLE_TEXT = READ_SAMPLE_SOURCE.map((text, index) => `${READ_SAMPLE_FIRST_LINE + index}: ${text}`).join("\n"); + /** + * The structured `web_search` result view for the web-search turn, authored inline + * because this client-side fixture cannot import the web tool that projects it. + * The sources exercise the citation list's features: a titled source with a + * snippet and a date, a source with no title (its hostname labels the link) and + * a snippet but no date, and a source with a title and a date but no snippet. + * `truncated` marks the capped indicator. The shape is the contract's own + * search view minus its wire discriminants. + */ + const WEB_SEARCH_RESULT = { + answer: "DeepSeek Harness is a plugin-based agent harness on vendored Cordis where **every capability is a plugin**.", + sources: [ + { + url: "https://github.com/deepseek-ai/deepseek-harness", + title: "DeepSeek Harness — plugin-based agent harness", + snippet: "Everything is a plugin: session, tools, agent-loop, and LLM adapters all mount on the same Cordis context.", + publishedAt: "2026-07-01" + }, + { + url: "https://www.deepseek.com/blog/harness-architecture", + snippet: "The capability-seam pattern splits each capability into interface, implementation, and consumer packages." + }, + { + url: "https://docs.deepseek.com/harness/plugins", + title: "Writing a harness plugin", + publishedAt: "2026-06-15" + } + ], + truncated: true + }; + /** The `web_fetch` result view for the web-fetch turn, authored inline for the same reason. */ + const WEB_FETCH_RESULT = { + url: "https://www.deepseek.com/blog/harness-architecture", + statusCode: 200, + truncated: false + }; + const DEEPSEEK_REASONING = { + efforts: [ + { + id: "off", + name: "Off" + }, + { + id: "high", + name: "High" + }, + { + id: "max", + name: "Max" + } + ], + defaultEffort: "high" + }; + const OPENAI_REASONING = { + efforts: [ + { + id: "off", + name: "Off" + }, + { + id: "medium", + name: "Medium" + }, + { + id: "high", + name: "High" + }, + { + id: "max", + name: "Max" + } + ], + defaultEffort: "medium" + }; + /** Catalog served by `session.models` and `llm.models` alike (fresh copies per call). */ + function fixtureModelGroups() { + return [{ + id: "deepseek-official", + name: "DeepSeek", + models: [{ + id: "deepseek-v4-flash", + name: "DeepSeek-V4-Flash", + description: "快速响应", + reasoning: DEEPSEEK_REASONING + }, { + id: "deepseek-v4-pro", + name: "DeepSeek-V4-Pro", + description: "复杂任务", + reasoning: DEEPSEEK_REASONING + }] + }, { + id: "openai", + name: "OpenAI", + models: [{ + id: "gpt-5", + name: "GPT-5", + reasoning: OPENAI_REASONING + }] + }]; + } + function sid(id) { + return id; + } + const FIXTURE_IMAGE_DATA = "iVBORw0KGgoAAAANSUhEUgAAAKAAAABaCAYAAAA/xl1SAAAAvklEQVR42u3SMQ0AAAjAMIyhELM4AAe8PD1qYFlk9cCXEAEDYkAwIAYEA2JAMCAGBANiQDAgBgQDYkAwIAYEA2JAMCAGBANiQDAgBgQDYkAwIAYEA2JAMCAGxIBCYEAMCAbEgGBADAgGxIBgQAwIBsSAYEAMCAbEgGBADAgGxIBgQAwIBsSAYEAMCAbEgGBADAgGxIAYEAyIAcGAGBAMiAHBgBgQDIgBwYAYEAyIAcGAGBAMiAHBgBgQDIgB4bYWLb6pnOb1xAAAAABJRU5ErkJggg=="; + const FIXTURE_IMAGE_REF = { + attachmentId: "fixture:image", + mediaType: "image/png", + bytes: 247, + width: 160, + height: 90, + name: "fixture-image.png" + }; + /** Deterministic provider billing attached to fixture assistant messages. */ + function fixtureUsage(turn, step) { + return { + inputTokens: 20 + turn % 5, + outputTokens: 8 + step, + cacheReadTokens: turn === 0 ? 0 : 80, + cacheWriteTokens: turn % 10 === 0 ? 4 : 0 + }; + } + /** fx-alpha history script: 75 turns (~150+ messages -> 4 pages at PAGE_MESSAGES=50), + * mixing reasoning blocks / tool call+result / context. */ + function buildAlphaLog() { + const events = []; + let time = Date.now() - 36e5; + const push = (e) => { + const seq = events.length; + const data = e["data"]; + const authored = e["type"] === "assistant/message" && data !== void 0 ? { + ...e, + data: { + ...data, + usage: fixtureUsage(data["turn"], data["step"]) + } + } : e; + events.push({ + seq, + time: time += 800, + ...authored + }); + return seq; + }; + push({ + type: "request/context", + data: { + provider: "deepseek-official", + model: "deepseek-v4-flash", + contextWindow: 128e3 + } + }); + for (let turn = 0; turn < 60; turn++) { + push({ + type: "turn/start", + data: { turn } + }); + const userSeq = push({ + type: "user/message", + surfaceOp: "append", + data: userMessage(text(turn === 59 ? USER_MARKDOWN_LITERAL : `问题 ${turn}:fixture 历史消息,用于翻页与渲染验收。`)) + }); + if (turn === 0) push({ + type: "session/title", + data: { + title: "Fixture 历史会话", + messageSeqs: [userSeq], + source: { kind: "fallback" } + } + }); + if (turn % 9 === 4) push({ + type: "user/message", + surfaceOp: "append", + data: userMessage(text(`[fixture] 上下文注入(turn ${turn})`), { + kind: "plugin", + plugin: "fixture" + }) + }); + push({ + type: "step/start", + data: { + turn, + step: 0 + } + }); + const withTool = turn % 5 === 2; + const withReasoning = turn % 3 === 1; + const blocks = []; + if (withReasoning) blocks.push({ + type: "reasoning", + text: `思考过程 ${turn}:这是一段可折叠的 reasoning 内容。` + }); + blocks.push({ + type: "text", + text: turn === 59 ? MARKDOWN_FIXTURE : `回答 ${turn}:这是 fixture 生成的历史回复正文。` + }); + if (withTool) { + const callId = `fx-call-${turn}`; + blocks.push({ + type: "tool-call", + id: callId, + name: "echo", + arguments: `{"text":"turn ${turn}"}` + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step: 0, + message: assistantMessage(blocks) + } + }); + push({ + type: "tool/call", + data: { + turn, + step: 0, + callId, + name: "echo", + arguments: `{"text":"turn ${turn}"}` + } + }); + push({ + type: "tool/result", + surfaceOp: "append", + data: { + turn, + step: 0, + message: toolResultMessage(callId, text(`ECHO: TURN ${turn}`), turn % 25 === 12) + } + }); + push({ + type: "step/end", + data: { + turn, + step: 0 + } + }); + push({ + type: "step/start", + data: { + turn, + step: 1 + } + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step: 1, + message: assistantMessage(text(`工具结果已消化(turn ${turn})。`)) + } + }); + push({ + type: "step/end", + data: { + turn, + step: 1 + } + }); + } else { + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step: 0, + message: assistantMessage(blocks) + } + }); + push({ + type: "step/end", + data: { + turn, + step: 0 + } + }); + } + push({ + type: "turn/end", + data: { + turn, + reason: { kind: "completed" } + } + }); + } + const toolTurn = (turn, name, args, resultText) => { + const callId = `fx-call-${turn}`; + push({ + type: "turn/start", + data: { turn } + }); + push({ + type: "user/message", + surfaceOp: "append", + data: userMessage(text(`问题 ${turn}:${name} 样本。`)) + }); + push({ + type: "step/start", + data: { + turn, + step: 0 + } + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step: 0, + message: assistantMessage([{ + type: "tool-call", + id: callId, + name, + arguments: args + }]) + } + }); + push({ + type: "tool/call", + data: { + turn, + step: 0, + callId, + name, + arguments: args + } + }); + push({ + type: "tool/result", + surfaceOp: "append", + data: { + turn, + step: 0, + message: toolResultMessage(callId, text(resultText), false) + } + }); + push({ + type: "step/end", + data: { + turn, + step: 0 + } + }); + push({ + type: "turn/end", + data: { + turn, + reason: { kind: "completed" } + } + }); + }; + toolTurn(60, "fx-bash", "{\"command\":\"ls -la\\necho done\",\"cwd\":\"/tmp/fixture\"}", "total 2\ndrwxr-xr-x fixture\n-rw-r--r-- demo.txt"); + toolTurn(61, "fx-write", "{\"path\":\"notes/demo.txt\",\"content\":\"hello fixture\\n\"}", "wrote notes/demo.txt"); + toolTurn(62, "edit", "{\"file_path\":\"notes/demo.txt\",\"old_string\":\"hello\",\"new_string\":\"hello fixture\"}", "已编辑"); + toolTurn(63, "write", "{\"file_path\":\"notes/new-demo.txt\",\"content\":\"hello fixture\\n\"}", "已写入"); + toolTurn(64, "edit", "{\"file_path\":\"src/config.ts\",\"old_string\":\"const timeout = 30\",\"new_string\":\"const timeout = 60\"}", "已编辑"); + { + const turn = 65; + const callId = `fx-call-${turn}`; + const args = JSON.stringify({ + code: "const listing = await tools.bash({ command: \"ls notes\", description: \"List notes\" })\nconst demo = await tools.read({ file_path: \"notes/demo.txt\" })\nawait tools.read({ file_path: \"notes/missing.txt\" }).catch(() => \"tolerated\")\nreturn { listing, demo }", + description: "Read the notes files and summarize" + }); + push({ + type: "turn/start", + data: { turn } + }); + push({ + type: "user/message", + surfaceOp: "append", + data: userMessage(text(`问题 ${turn}:run_code 样本。`)) + }); + push({ + type: "step/start", + data: { + turn, + step: 0 + } + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step: 0, + message: assistantMessage([{ + type: "tool-call", + id: callId, + name: "run_code", + arguments: args + }]) + } + }); + push({ + type: "tool/call", + data: { + turn, + step: 0, + callId, + name: "run_code", + arguments: args + } + }); + const dispatchPair = (n, name, dispatchArgs, resultText, isError = false) => { + push({ + type: "tool/code-dispatch-start", + data: { + rootCallId: callId, + parentCallId: callId, + subCallId: `${callId}:code:${n}`, + name, + arguments: dispatchArgs + } + }); + push({ + type: "tool/code-dispatch", + data: { + rootCallId: callId, + parentCallId: callId, + subCallId: `${callId}:code:${n}`, + name, + arguments: dispatchArgs, + isError, + content: [{ + type: "text", + text: resultText + }] + } + }); + }; + dispatchPair(1, "bash", { + command: "ls notes", + description: "List notes" + }, "demo.txt\nnew-demo.txt"); + dispatchPair(2, "read", { file_path: "notes/demo.txt" }, "hello fixture\n"); + dispatchPair(3, "read", { file_path: "notes/missing.txt" }, "Error: ENOENT: notes/missing.txt not found", true); + push({ + type: "tool/result", + surfaceOp: "append", + data: { + turn, + step: 0, + message: toolResultMessage(callId, text("{\"listing\":\"demo.txt\\nnew-demo.txt\",\"demo\":\"hello fixture\\n\"}"), false) + } + }); + push({ + type: "step/end", + data: { + turn, + step: 0 + } + }); + push({ + type: "turn/end", + data: { + turn, + reason: { kind: "completed" } + } + }); + } + const fixtureTodos = [ + { + content: "梳理需求", + status: "completed" + }, + { + content: "实现 fixture 样本", + status: "in_progress" + }, + { + content: "跑后台构建", + status: "in_progress" + }, + { + content: "浏览器验收", + status: "pending" + } + ]; + toolTurn(66, "bash", "{\"command\":\"pnpm run check\",\"cwd\":\"/tmp/fixture/deep/nested\"}", TERMINAL_OUTPUT_FIXTURE); + toolTurn(67, "grep", "{\"pattern\":\"SEARCH_MAX_LINES\",\"path\":\"packages/client\"}", SEARCH_MATCHES_TEXT); + toolTurn(68, "glob", "{\"pattern\":\"**/SearchBlock*\",\"path\":\"packages/client\"}", SEARCH_PATHS_TEXT); + toolTurn(69, "read", `{"file_path":${JSON.stringify(READ_SAMPLE_PATH)},"offset":${READ_SAMPLE_FIRST_LINE}}`, READ_SAMPLE_TEXT); + toolTurn(70, "web_search", "{\"query\":\"deepseek harness architecture\"}", "Search results for deepseek harness architecture."); + toolTurn(71, "web_fetch", "{\"url\":\"https://www.deepseek.com/blog/harness-architecture\"}", "# Harness architecture\n\nEverything is a plugin."); + push({ + type: "turn/start", + data: { turn: 72 } + }); + push({ + type: "user/message", + surfaceOp: "append", + data: userMessage(text("问题 72:请完整列出全部一百条条目。")) + }); + push({ + type: "step/start", + data: { + turn: 72, + step: 0 + } + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn: 72, + step: 0, + message: assistantMessage(text("条目 1:第一条。条目 2:第二条。条目 3:这一条写到一半被")) + } + }); + push({ + type: "step/end", + data: { + turn: 72, + step: 0 + } + }); + push({ + type: "turn/end", + data: { + turn: 72, + reason: { kind: "max-tokens" } + } + }); + push({ + type: "turn/start", + data: { turn: 73 } + }); + push({ + type: "user/message", + surfaceOp: "append", + data: userMessage([{ + type: "image", + attachment: FIXTURE_IMAGE_REF + }, ...text("历史用户图片")]) + }); + push({ + type: "step/start", + data: { + turn: 73, + step: 0 + } + }); + push({ + type: "assistant/message", + surfaceOp: "append", + data: { + turn: 73, + step: 0, + message: assistantMessage([...text("结构化模型图片:"), { + type: "image", + attachment: FIXTURE_IMAGE_REF + }], "fx-vision") + } + }); + push({ + type: "step/end", + data: { + turn: 73, + step: 0 + } + }); + push({ + type: "turn/end", + data: { + turn: 73, + reason: { kind: "completed" } + } + }); + toolTurn(74, "todo_write", JSON.stringify({ todos: fixtureTodos }), "Updated todo list: 1 pending, 2 in progress, 1 completed."); + const callIndex = events.length - 4; + const callTime = events[callIndex]?.time; + events.splice(callIndex + 1, 0, { + type: "todo/write", + time: callTime + 400, + data: { todos: fixtureTodos } + }); + events.forEach((e, i) => { + e.seq = i; + }); + return events; + } + /** Narrows a parsed-JSON field to string; fixture args are authored in-file, so non-strings only mean a typo here. */ + /* v8 ignore next -- the fallback arm is the same in-file-typo guard as the JSON.parse catch above. */ + const str = (value, fallback = "") => typeof value === "string" ? value : fallback; + /** Fixture presenter registry (mirrors host viewFor): pure derivation, undefined = no view. */ + function presentCall(name, argsRaw) { + let args; + try { + args = JSON.parse(argsRaw); + } catch { + /* v8 ignore next 2 -- defensive: fixture args are authored in-file as valid JSON; only an in-file typo could reach the catch. */ + return; + } + switch (name) { + case "fx-bash": + case "bash": return { + card: "terminal", + title: str(args.command), + cwd: str(args.cwd, "/tmp/fixture"), + description: "fixture 终端样本" + }; + case "fx-write": return { + card: "diff", + title: `Write ${str(args.path)}`, + diffs: [{ + path: str(args.path), + oldText: null, + newText: str(args.content) + }] + }; + case "read": return { + card: "generic", + title: `Read ${str(args.file_path)}`, + kind: "read", + locations: [{ path: str(args.file_path) }] + }; + case "edit": + if (str(args.file_path) === "src/config.ts") return { + card: "diff", + title: `Edit ${str(args.file_path)}`, + diffs: [{ + path: str(args.file_path), + oldText: "const timeout = 30", + newText: "const timeout = 60" + }, { + path: str(args.file_path), + oldText: "retries: 1", + newText: "retries: 3" + }] + }; + return { + card: "diff", + title: `Edit ${str(args.file_path)}`, + diffs: [{ + path: str(args.file_path), + oldText: str(args.old_string), + newText: str(args.new_string) + }] + }; + case "write": return { + card: "diff", + title: `Write ${str(args.file_path)}`, + diffs: [{ + path: str(args.file_path), + oldText: null, + newText: str(args.content) + }] + }; + case "grep": return { + card: "generic", + title: `Grep ${str(args.pattern)}`, + kind: "search", + rawInput: args + }; + case "glob": return { + card: "generic", + title: `Glob ${str(args.pattern)}`, + kind: "search", + rawInput: args + }; + case "web_search": return { + card: "generic", + title: `Search ${str(args.query)}`, + kind: "search", + rawInput: args + }; + case "web_fetch": return { + card: "generic", + title: `Fetch ${str(args.url)}`, + kind: "fetch", + rawInput: args + }; + default: return; + } + } + function presentResult(name, argsRaw, resultText) { + const call = presentCall(name, argsRaw); + if (call === void 0) return void 0; + if (name === "grep") return { + card: "search", + shape: "matches", + files: SEARCH_MATCHES_FIXTURE, + truncated: true, + total: 42 + }; + if (name === "glob") return { + card: "search", + shape: "paths", + paths: SEARCH_PATHS_FIXTURE, + truncated: true, + total: 23 + }; + if (name === "read") return { + card: "read", + path: READ_SAMPLE_PATH, + offset: READ_SAMPLE_FIRST_LINE, + lines: READ_SAMPLE_LINES, + totalLines: READ_SAMPLE_TOTAL, + lang: "ts", + content: text(resultText) + }; + if (name === "web_search") return { + card: "web", + kind: "search", + ...WEB_SEARCH_RESULT + }; + if (name === "web_fetch") return { + card: "web", + kind: "fetch", + ...WEB_FETCH_RESULT + }; + switch (call.card) { + case "terminal": return { + card: "terminal", + output: resultText, + ...TERMINAL_EXIT_STATUS[resultText] ?? { exitCode: 0 } + }; + case "diff": return { + card: "diff", + diffs: call.diffs + }; + case "generic": return { + card: "generic", + content: text(resultText) + }; + } + } + /** Host-side viewFor mirror: tool/call presents from its own args; tool/result back-scans the log for the paired call. */ + function viewFor(event, log) { + if (event.type === "tool/call") { + const view = presentCall(event.data.name, event.data.arguments); + return view === void 0 ? void 0 : { + for: "call", + view + }; + } + if (event.type === "tool/result") { + const callId = String(event.data.message.source.callId); + for (let i = log.length - 1; i >= 0; i--) { + const candidate = log[i]; + /* v8 ignore next -- dense-array guard: i stays within [0, log.length), + so the undefined arm needs a sparse log no code path builds. */ + if (candidate !== void 0 && candidate.type === "tool/call" && String(candidate.data.callId) === callId) { + const resultText = event.data.message.content[0].content.map((b) => b.type === "text" ? b.text : "").join(""); + const view = presentResult(candidate.data.name, candidate.data.arguments, resultText); + return view === void 0 ? void 0 : { + for: "result", + view + }; + } + } + return; + } + } + /** + * Fixture parallel of the plan unit's double-event fold: `command/run` + * records named `plan` with recorded input set the wanted target (`off` → + * false, else true); `plan/mode` commits and clears it. `wanted` is exposed + * for the prompt boundary (the fixture's step/start parallel). + */ + function foldPlan(log) { + let active = false; + let wanted = null; + for (const event of log) { + const item = event; + if (item.type === "command/run" && item.data?.["name"] === "plan") { + const args = item.data["args"]; + if (typeof args !== "string") continue; + wanted = args.trim() !== "off"; + } else if (item.type === "plan/mode") { + active = item.data?.["active"] === true; + wanted = null; + } + } + return { + active, + pending: wanted !== null && wanted !== active, + wanted + }; + } + /** The plan projection's wire view over the full log. */ + function planViewOf(log) { + const plan = foldPlan(log); + return { + active: plan.active, + pending: plan.pending + }; + } + /** Fixture parallel of the host's projection units: whole current values per key over the full log. */ + /** Fixture preset table (the host PermissionPresetService defaults). */ + const PERMISSION_PRESETS = { + "workspace-write": { + sandbox: "workspace-write", + approval: "ask", + description: "Write inside the workspace and permitted temporary directories; wider retries require approval." + }, + "danger-full-access": { + sandbox: "danger-full-access", + approval: "never", + description: "Full file access without approval prompts." + } + }; + /** Host permissions-unit parallel: fold the three knob events, derive the select over the fixture defaults. */ + function permissionSelectOf(log) { + let preset = null; + let sandbox = "workspace-write"; + let approval = "ask"; + for (const event of log) { + const item = event; + if (item.type === "permission/preset") preset = item.data["preset"]; + else if (item.type === "sandbox/mode") sandbox = item.data["mode"]; + else if (item.type === "approval/policy") approval = item.data["policy"]; + } + const matches = (spec) => spec.sandbox === sandbox && spec.approval === approval; + let currentValue = "custom"; + const folded = preset === null ? void 0 : PERMISSION_PRESETS[preset]; + if (preset !== null && folded !== void 0 && matches(folded)) currentValue = preset; + else for (const [name, spec] of Object.entries(PERMISSION_PRESETS)) if (matches(spec)) { + currentValue = name; + break; + } + return { + options: [...Object.entries(PERMISSION_PRESETS).map(([value, spec]) => ({ + value, + name: value, + description: spec.description + })), ...currentValue === "custom" ? [{ + value: "custom", + name: "Custom", + description: "Current sandbox and approval settings do not match a preset." + }] : []], + currentValue + }; + } + /** Read one provider usage sample from either durable carrier. */ + function usageSampleOf(event) { + const item = event; + const usage = item.type === "assistant/chunk" && item.data.chunk?.type === "usage" ? item.data.chunk.usage : item.type === "assistant/message" ? item.data.usage : void 0; + return usage === void 0 || item.data.turn === void 0 || item.data.step === void 0 ? void 0 : { + turn: item.data.turn, + step: item.data.step, + usage + }; + } + /** Fixture parallel of token-meter's last-sample-replacing usage projection. */ + function tokenUsageOf(log) { + const totals = { + uncachedInputTokens: 0, + outputTokens: 0, + cacheReadTokens: 0, + cacheWriteTokens: 0 + }; + let last = null; + for (const event of log) { + const sample = usageSampleOf(event); + if (sample === void 0) continue; + const buckets = { + uncachedInputTokens: sample.usage.inputTokens, + outputTokens: sample.usage.outputTokens, + cacheReadTokens: sample.usage.cacheReadTokens ?? 0, + cacheWriteTokens: sample.usage.cacheWriteTokens ?? 0 + }; + const previous = last?.turn === sample.turn && last.step === sample.step ? last.buckets : void 0; + totals.uncachedInputTokens += buckets.uncachedInputTokens - (previous?.uncachedInputTokens ?? 0); + totals.outputTokens += buckets.outputTokens - (previous?.outputTokens ?? 0); + totals.cacheReadTokens += buckets.cacheReadTokens - (previous?.cacheReadTokens ?? 0); + totals.cacheWriteTokens += buckets.cacheWriteTokens - (previous?.cacheWriteTokens ?? 0); + last = { + turn: sample.turn, + step: sample.step, + buckets + }; + } + return totals; + } + /** Fixture parallel of session-stats' whole-log counting and wall-time fold. */ + function sessionStatsOf(log) { + const value = { + turns: 0, + steps: 0, + llmMs: 0, + toolMs: 0, + ttftMs: 0, + ttftSteps: 0, + decodeMs: 0, + decodeTokens: 0 + }; + let lastTurn = null; + let openStep = null; + const pendingCalls = /* @__PURE__ */ new Map(); + for (const event of log) switch (event.type) { + case "step/start": + openStep = { + turn: event.data.turn, + step: event.data.step, + startTime: event.time, + firstTokenTime: null + }; + break; + case "assistant/chunk": + if (openStep !== null && openStep.turn === event.data.turn && openStep.step === event.data.step && openStep.firstTokenTime === null && isTokenDelta(event.data.chunk)) openStep.firstTokenTime = event.time; + break; + case "assistant/message": + if (openStep === null || openStep.turn !== event.data.turn || openStep.step !== event.data.step) break; + value.llmMs += Math.max(0, event.time - openStep.startTime); + if (openStep.firstTokenTime !== null) { + value.ttftMs += Math.max(0, openStep.firstTokenTime - openStep.startTime); + value.ttftSteps += 1; + const outputTokens = event.data.usage?.outputTokens; + if (typeof outputTokens === "number" && Number.isFinite(outputTokens) && outputTokens >= 0) { + value.decodeMs += Math.max(0, event.time - openStep.firstTokenTime); + value.decodeTokens += outputTokens; + } + } + openStep = null; + break; + case "tool/call": + pendingCalls.set(event.data.callId, event.time); + break; + case "tool/result": { + const callId = event.data.message.source.callId; + const dispatched = pendingCalls.get(callId); + if (dispatched === void 0) break; + pendingCalls.delete(callId); + value.toolMs += Math.max(0, event.time - dispatched); + break; + } + case "step/end": + if (event.data.turn !== lastTurn) { + value.turns += 1; + lastTurn = event.data.turn; + } + value.steps += 1; + openStep = null; + break; + case "turn/end": + pendingCalls.clear(); + break; + default: break; + } + return value; + } + /** Fixed token-meter heuristic constants mirrored by this client-only fixture. */ + const CHARS_PER_TOKEN = 4; + const BLOCK_OVERHEAD = 4; + const ROLE_OVERHEAD = 4; + /** Price fixture content with token-meter's fixed-density heuristic. */ + function estimateFixtureContent(blocks) { + const densityPrice = (value) => Math.ceil(value.length / CHARS_PER_TOKEN); + return blocks.reduce((tokens, block) => { + if (block.type === "text" || block.type === "reasoning") return tokens + densityPrice(block.text) + BLOCK_OVERHEAD; + if (block.type === "tool-call") return tokens + densityPrice(block.name) + densityPrice(block.arguments) + BLOCK_OVERHEAD; + if (block.type === "tool-result") return tokens + estimateFixtureContent(block.content) + BLOCK_OVERHEAD; + return tokens + densityPrice(JSON.stringify(block)) + BLOCK_OVERHEAD; + }, 0); + } + /** Fixture parallel of token-meter's heuristic context-composition projection. */ + function contextBreakdownOf(log) { + const headerEvent = log.findLast((event) => event.type === "request/header"); + const header = headerEvent === void 0 ? void 0 : headerEvent.data.header; + let messageTokens = 0; + for (const seq of foldSurface(log).nodes) { + const event = log[seq]; + if (event === void 0) continue; + const message = deriveEventMessage(event); + if (message !== null) messageTokens += estimateFixtureContent(message.content) + ROLE_OVERHEAD; + } + return { + systemTokens: header?.system === void 0 ? 0 : Math.ceil(header.system.length / CHARS_PER_TOKEN) + ROLE_OVERHEAD, + toolsTokens: header?.tools === void 0 || header.tools.length === 0 ? 0 : Math.ceil(JSON.stringify(header.tools).length / CHARS_PER_TOKEN) + BLOCK_OVERHEAD, + messageTokens + }; + } + /** Latest log-only route context, or undefined before any request ran. */ + function lastRequestContext(log) { + const event = log.findLast((item) => item.type === "request/context"); + return event === void 0 ? void 0 : event.data; + } + /** + * Fixture parallel of token-meter's request-pressure projection: the last + * provider-reported prompt size paired with the last recorded capacity. The + * two need not come from one request — see the token-meter README. The host's + * `projectedTokens` is deliberately absent: reproducing it would mean + * reimplementing the estimator client-side, and every consumer falls back to + * the bare sample, so a fixture-driven view simply lags a compaction the way + * the projection did before that field existed. + */ + function contextPressureOf(log) { + let pressureTokens; + for (const event of log) { + const sample = usageSampleOf(event); + if (sample === void 0) continue; + pressureTokens = sample.usage.inputTokens + (sample.usage.cacheReadTokens ?? 0) + (sample.usage.cacheWriteTokens ?? 0); + } + const contextWindow = lastRequestContext(log)?.contextWindow; + return { + ...pressureTokens === void 0 ? {} : { pressureTokens }, + ...contextWindow === void 0 ? {} : { contextWindow } + }; + } + function projectionValuesOf(log) { + const values = {}; + const titleEvent = log.findLast((item) => item.type === "session/title"); + if (titleEvent !== void 0) values["title"] = titleEvent.data.title; + values["todos"] = backscanTodos(log) ?? null; + values["permissions"] = permissionSelectOf(log); + values["plan"] = planViewOf(log); + values["goal"] = backscanGoal(log); + values["tokenUsage"] = tokenUsageOf(log); + values["contextPressure"] = contextPressureOf(log); + values["contextBreakdown"] = contextBreakdownOf(log); + values["sessionStats"] = sessionStatsOf(log); + values["imageLimits"] = { + maxImageBytes: 5 * 1024 * 1024, + maxImagesPerMessage: 20, + maxMessageImageBytes: 100 * 1024 * 1024, + maxImagePixels: 4e7, + mediaTypes: [ + "image/png", + "image/jpeg", + "image/webp", + "image/gif" + ] + }; + return values; + } + /** Host push-frame parallel: emit one session/projection frame per key the given event advanced. */ + function projectionFramesOf(id, log, event) { + const type = event.type; + const frames = []; + if (usageSampleOf(event) !== void 0) frames.push({ + type: "session/projection", + sessionId: id, + key: "tokenUsage", + value: tokenUsageOf(log), + seq: event.seq + }, { + type: "session/projection", + sessionId: id, + key: "contextPressure", + value: contextPressureOf(log), + seq: event.seq + }); + if (type === "request/context") frames.push({ + type: "session/projection", + sessionId: id, + key: "contextPressure", + value: contextPressureOf(log), + seq: event.seq + }); + if (type === "request/header" || type === "user/message" || type === "assistant/message" || type === "tool/result") frames.push({ + type: "session/projection", + sessionId: id, + key: "contextBreakdown", + value: contextBreakdownOf(log), + seq: event.seq + }); + if (type === "assistant/message" || type === "tool/result" || type === "step/end") frames.push({ + type: "session/projection", + sessionId: id, + key: "sessionStats", + value: sessionStatsOf(log), + seq: event.seq + }); + if (frames.length > 0) return frames; + if (type === "session/title") { + const values = projectionValuesOf(log); + /* v8 ignore next -- the advancing title event is in the log, so the key is present. */ + if (!Object.hasOwn(values, "title")) return []; + return [{ + type: "session/projection", + sessionId: id, + key: "title", + value: values["title"], + seq: event.seq + }]; + } + if (type === "goal/change") return [{ + type: "session/projection", + sessionId: id, + key: "goal", + value: backscanGoal(log), + seq: event.seq + }]; + if (type === "todo/write" || type === "turn/start") return [{ + type: "session/projection", + sessionId: id, + key: "todos", + value: backscanTodos(log) ?? null, + seq: event.seq + }]; + if (type === "permission/preset" || type === "sandbox/mode" || type === "approval/policy") return [{ + type: "session/projection", + sessionId: id, + key: "permissions", + value: permissionSelectOf(log), + seq: event.seq + }]; + const commandData = event; + if (type === "plan/mode" || type === "command/run" && commandData.data.name === "plan" && typeof commandData.data.args === "string") return [{ + type: "session/projection", + sessionId: id, + key: "plan", + value: planViewOf(log), + seq: event.seq + }]; + return []; + } + /** + * Message-boundary paging (mirrors the host's paging contract): count + * maxMessages messages + * backwards from end, cut at a turn/start boundary. + Entries carry pagination-time views + * (the host analogue computes viewFor per entry at page time). */ + function pageOf(log, beforeSeq, maxMessages) { + const end = beforeSeq === void 0 ? log.length : Math.max(0, Math.min(beforeSeq, log.length)); + let start = 0; + let messages = 0; + for (let i = end - 1; i >= 0; i--) { + const event = log[i]; + /* v8 ignore next -- dense-array guard: log seqs are array indexes, i stays within [0, end). */ + if (event === void 0) break; + if (event.type === "user/message" || event.type === "assistant/message") messages++; + if (event.type === "turn/start" && messages >= maxMessages) { + start = i; + break; + } + } + return { + events: log.slice(start, end).map((event) => { + const view = viewFor(event, log); + return view === void 0 ? { event } : { + event, + view + }; + }), + hasMore: start > 0 + }; + } + /** Fixture mirror of host session-scoped attachment authorization. */ + function logReferencesAttachment(log, attachmentId) { + const visit = (value) => { + if (Array.isArray(value)) return value.some(visit); + if (typeof value !== "object" || value === null) return false; + const record = value; + if (record.attachmentId === attachmentId) return true; + return Object.values(record).some(visit); + }; + return log.some((event) => visit(event.data)); + } + /** Fixture mirror of first-party message extraction used by session-query. */ + function searchBlockText(block) { + switch (block.type) { + case "text": return [block.text]; + case "reasoning": return []; + case "tool-call": return [block.name, block.arguments]; + case "tool-result": return block.content.flatMap(searchBlockText); + default: return []; + } + } + /** One current-surface user/assistant document, if searchable. */ + function searchEventText(event) { + const content = event.type === "user/message" ? event.data.content : event.type === "assistant/message" ? event.data.message.content : void 0; + if (content === void 0) return ""; + return content.flatMap(searchBlockText).map((part) => part.trim()).filter(Boolean).join("\n"); + } + /** + * Browser-safe approximation of SQLite FTS5 unicode61 token boundaries. + * Keeping phrase matching token-based prevents the development fixture from + * promising arbitrary within-token substring behavior that production lacks. + */ + function searchTokenSpans(value) { + const text = value.replace(/\s+/gu, " ").trim(); + const characters = Array.from(text); + const tokens = []; + let start; + let raw = ""; + const flush = (end) => { + if (start !== void 0) { + const folded = raw.normalize("NFD").replace(/\p{M}+/gu, "").toLowerCase(); + if (folded !== "") tokens.push({ + value: folded, + start, + end + }); + } + start = void 0; + raw = ""; + }; + for (let index = 0; index < characters.length; index++) { + const character = characters[index]; + const tokenBase = character.normalize("NFD").replace(/\p{M}+/gu, ""); + if (tokenBase === "") { + if (start !== void 0) raw += character; + continue; + } + if (/^[\p{L}\p{N}\p{Co}]+$/u.test(tokenBase)) { + start ??= index; + raw += character; + } else flush(index); + } + flush(characters.length); + return { + text, + tokens + }; + } + /** Count exact contiguous token-phrase occurrences and retain the first display span. */ + function phraseMatch(document, phrase) { + if (phrase.length === 0 || phrase.length > document.length) return { + count: 0, + start: 0, + end: 0 + }; + let count = 0; + let firstStart = 0; + let firstEnd = 0; + for (let start = 0; start <= document.length - phrase.length; start++) { + if (!phrase.every((token, offset) => document[start + offset]?.value === token)) continue; + count++; + if (count === 1) { + firstStart = document[start]?.start ?? 0; + firstEnd = document[start + phrase.length - 1]?.end ?? firstStart; + } + } + return { + count, + start: firstStart, + end: firstEnd + }; + } + /** Match-centered fixture excerpt, bounded by Unicode code points for the sidebar. */ + function searchSnippet(value, matchStart, matchEnd) { + const characters = Array.from(value); + if (characters.length <= 120) return value; + const boundedStart = Math.min(Math.max(0, matchStart), characters.length - 1); + const boundedEnd = Math.min(characters.length, Math.max(boundedStart + 1, matchEnd)); + const center = Math.floor((boundedStart + boundedEnd) / 2); + let start = Math.min(characters.length - 118, Math.max(0, center - Math.floor(118 / 2))); + let end = start + 118; + if (start === 0) end = 119; + else if (end === characters.length) start = characters.length - 119; + return `${start > 0 ? "…" : ""}${characters.slice(start, end).join("")}${end < characters.length ? "…" : ""}`; + } + /** Mirrors `packages/session-query/session-query-sqlite/src/index.ts`; update both together. */ + function compareSearchCandidates(a, b) { + if (a.matchCount !== b.matchCount) return b.matchCount - a.matchCount; + if (a.documentLength !== b.documentLength) return a.documentLength - b.documentLength; + if (a.time !== b.time) return b.time - a.time; + if (a.sessionId !== b.sessionId) return a.sessionId < b.sessionId ? -1 : 1; + return b.seq - a.seq; + } + /** + * Current plan projection over the full log (host parallel: latest todo/write + * with no later turn/start; a new turn retires the previous plan). + */ + function backscanTodos(log) { + for (let i = log.length - 1; i >= 0; i--) { + const event = log[i]; + if (event === void 0) continue; + if (event.type === "turn/start") return void 0; + if (event.type === "todo/write") return event.data.todos; + } + } + /** + * Current goal projection over the full log (host parallel: the GoalService + * unit's last-wins fold of goal/change whole values; clear returns null). + */ + function backscanGoal(log) { + for (let i = log.length - 1; i >= 0; i--) { + const event = log[i]; + if (event === void 0 || event.type !== "goal/change" || event.data === void 0) continue; + const change = event.data; + if (change.operation === "clear") return null; + return { + goal: change.goal, + roundsStarted: change.roundsStarted, + createdAt: change.createdAt, + updatedAt: change.updatedAt + }; + } + return null; + } + /** Inbox pump shared by both stream generators (FrameQueue pattern: ONE abort listener hung + * outside the loop — a per-iteration {once:true} listener never fires for non-final rounds and + * piles up for the stream's lifetime). breakNow force-ends the stream without the + * client's signal (timing hook: simulated connection loss). */ + var FxInbox = class { + inbox = []; + wake = null; + broken = false; + push(envelope) { + this.inbox.push(envelope); + this.wake?.(); + } + breakNow() { + this.broken = true; + this.wake?.(); + } + /** Read through a method: breakNow()/abort flip state across yields, so narrowing from the loop condition must not stick. */ + isLive(signal) { + return !signal.aborted && !this.broken; + } + async *drain(signal) { + const onAbort = () => this.wake?.(); + signal.addEventListener("abort", onAbort); + try { + while (this.isLive(signal)) { + while (this.inbox.length > 0) yield this.inbox.shift(); + if (!this.isLive(signal)) break; + await new Promise((resolve) => { + this.wake = resolve; + }); + this.wake = null; + } + } finally { + signal.removeEventListener("abort", onAbort); + } + } + }; + /** Build the fixture's legacy API and Remote RPC faces over one state graph. */ + function createFixtureWorld(options) { + const sessions = options.empty ? [] : [ + { + sessionId: sid("fx-alpha"), + updatedAt: Date.now(), + running: true, + blank: false, + cwd: "/tmp/fixture" + }, + { + sessionId: sid("fx-beta"), + updatedAt: Date.now() - 6e4, + running: false, + blank: false, + parentSessionId: sid("fx-alpha"), + cwd: "/tmp/fixture" + }, + { + sessionId: sid("fx-gamma"), + updatedAt: Date.now() - 12e4, + running: false, + blank: false, + cwd: "/tmp/fixture" + } + ]; + const logs = new Map([[sid("fx-alpha"), buildAlphaLog()]]); + const modelSelections = new Map(sessions.map((session) => [session.sessionId, { + provider: "deepseek-official", + model: "deepseek-v4-flash" + }])); + const attachments = new Map([[String(FIXTURE_IMAGE_REF.attachmentId), { + attachment: FIXTURE_IMAGE_REF, + data: FIXTURE_IMAGE_DATA + }]]); + /** Credential store double: set/unset flip the describe badge, values never read back. */ + const fixtureCredentials = new Map([["DEEPSEEK_API_KEY", true]]); + /** + * Preset compositions the fixture serves. Held as state rather than + * constants so the settings editor's save and delete are exercisable: the + * roster a GUI journey sees after writing is the text it wrote. + */ + const fixturePresets = new Map([ + ["standard", { + trust: "system", + content: "- id: tool-bash\n name: '@deepseek-ai/dsh-tool-bash'\n" + }], + ["minimal", { + trust: "system", + content: "- id: tool-web-search\n name: '@deepseek-ai/dsh-tool-web-search'\n" + }], + ["my-agent", { + trust: "user", + content: "- id: tool-read\n name: '@deepseek-ai/dsh-tool-read'\n" + }] + ]); + let fixtureDefaultPreset = "standard"; + const nextTurn = new Map([[sid("fx-alpha"), 75]]); + let nextSession = 1; + let nextRpc = 1; + let attachedSessions = options.empty ? 0 : 1; + const wid = (raw) => raw; + const fixtureEpoch = (/* @__PURE__ */ new Date(Date.now() - 3e5)).toISOString(); + const workspaces = options.empty ? [] : [{ + workspaceId: wid("fx-ws-fixture"), + path: "/tmp/fixture", + title: "fixture", + sessionIds: [ + sid("fx-alpha"), + sid("fx-beta"), + sid("fx-gamma") + ], + createdAt: fixtureEpoch, + updatedAt: fixtureEpoch + }]; + let nextWorkspace = 1; + const archivedSessionIds = []; + const FIXTURE_HOME = "/home/fixture"; + const directoryTree = new Map([ + ["/", ["home"]], + ["/home", ["fixture"]], + [FIXTURE_HOME, [ + "Documents", + "Downloads", + ".config" + ]], + [`${FIXTURE_HOME}/Documents`, [ + "project", + "deepseek-iOS", + "deepseek-android", + "deepseek-platform", + "deepseek-web", + "deepseek-harness", + "deepseek-app", + "deepseek-landing-blog" + ]] + ]); + const childrenOf = (path) => { + const known = directoryTree.get(path); + if (known !== void 0) return known; + const parent = path.slice(0, path.lastIndexOf("/")) || "/"; + const name = path.slice(path.lastIndexOf("/") + 1); + return directoryTree.get(parent)?.includes(name) === true ? [] : void 0; + }; + const crumbsOf = (path) => { + const crumbs = [{ + name: "/", + path: "/", + hidden: false + }]; + let acc = ""; + for (const segment of path.split("/").filter(Boolean)) { + acc += `/${segment}`; + crumbs.push({ + name: segment, + path: acc, + hidden: false + }); + } + return crumbs; + }; + const mint = () => RpcId(`fx-rpc-${nextRpc++}`); + /** Resident pending approval (stable rpcId: every mux open replays the same id while unanswered, matching host replay semantics). */ + const pendingApprovalRpcId = mint(); + const pendingApprovalId = "fx-approval-1"; + /** Cleared once answered through respond; replay stops and approval/resolved is broadcast. */ + let approvalPending = true; + const pendingQuestionRpcId = mint(); + let questionPending = true; + const fixtureQuestions = [ + { + id: "harness-profile", + header: "偏好", + question: "你现在更想招哪类 Agent/Harness 候选人?", + options: [ + { + label: "工程落地型 (Recommended)", + description: "更看重能直接做 runtime、tool executor、sandbox、trace 和线上问题排查。" + }, + { + label: "研究潜力型", + description: "更看重 Agent 理解、训练评测思路和长期成长空间。" + }, + { + label: "均衡型", + description: "同时要求工程能力和 Agent 认知,但可能筛选门槛更高。" + } + ] + }, + { + id: "work-mode", + header: "方式", + question: "你希望候选人优先展示哪种工作方式?", + options: [{ + label: "先做小型原型 (Recommended)", + description: "用可运行结果尽快验证关键假设。" + }, { + label: "先写完整设计", + description: "先收敛边界、协议和风险,再开始实现。" + }] + }, + { + id: "signals", + header: "信号", + question: "哪些面试信号最重要?", + detail: "按当前招聘目标选择;跳过则视为不设偏好。", + multiSelect: true, + options: [ + { label: "系统设计" }, + { label: "代码质量" }, + { label: "Agent 产品判断" } + ] + } + ]; + const muxConns = /* @__PURE__ */ new Set(); + const hostConns = /* @__PURE__ */ new Set(); + const emitMux = (frame) => { + for (const conn of muxConns) conn.push({ + rpcId: mint(), + payload: frame + }); + }; + const emitHost = (frame) => { + for (const conn of hostConns) conn.push({ + rpcId: mint(), + payload: frame + }); + }; + /** OK response echoing the caller's rpcId (contract: responses always backfill, never mint). */ + function ok(request, value) { + return Promise.resolve({ + rpcId: request.rpcId, + result: { + ok: true, + value + } + }); + } + function err(request, error) { + return Promise.resolve({ + rpcId: request.rpcId, + result: { + ok: false, + error + } + }); + } + const summaryOf = (id) => sessions.find((s) => s.sessionId === id); + /** Shared session guard for sessionId-addressed catalog routes: the error + * response when the session is unknown, undefined when it exists. */ + const requireSession = (request) => { + if (summaryOf(request.payload.sessionId) !== void 0) return void 0; + return err(request, { + code: "session-not-found", + message: `no session ${request.payload.sessionId}`, + details: { sessionId: request.payload.sessionId } + }); + }; + const setRunning = (id, running) => { + const summary = summaryOf(id); + if (summary === void 0 || summary.running === running) return; + summary.running = running; + emitHost({ + type: "host/session-status", + sessionId: id, + running + }); + }; + const logOf = (id) => { + let log = logs.get(id); + if (log === void 0) { + log = []; + logs.set(id, log); + } + return log; + }; + const append = (id, e) => { + const log = logOf(id); + const event = { + seq: log.length, + time: Date.now(), + ...e + }; + log.push(event); + const view = viewFor(event, log); + /* v8 ignore next 3 -- the view-present arm needs a live tool/call emission, + but the fixture replay produces text-only turns; view vocabulary is + exercised through the history samples (turns 60-62). */ + emitMux(view === void 0 ? { + type: "session/event", + sessionId: id, + event + } : { + type: "session/event", + sessionId: id, + event, + view + }); + for (const frame of projectionFramesOf(id, log, event)) emitMux(frame); + }; + /** Append one durable goal/change (host GoalService parallel). */ + const appendGoalChange = (id, change) => { + const log = logOf(id); + append(id, { + type: "goal/change", + data: change + }); + return backscanGoal(log); + }; + const goalFailure = (message) => ({ + ok: false, + error: { + code: "internal", + message, + details: {} + } + }); + const requireGoalSession = (id) => summaryOf(id) === void 0 ? { + ok: false, + error: { + code: "session-not-found", + message: `no session ${id}`, + details: { sessionId: id } + } + } : void 0; + /** Canonical fixture implementation of the generated Commands Remote contract. */ + const commandRemotes = { + list(id) { + const missing = requireGoalSession(id); + if (missing !== void 0) return missing; + return { + ok: true, + value: [ + { + name: "compact", + description: "fixture:压缩当前会话上下文" + }, + { + name: "echo", + description: "fixture:回显参数", + input: { hint: "text to echo" } + }, + { + name: "goal", + description: "set or view the goal for a long-running task", + input: { hint: "" } + }, + { + name: "permission", + description: "Switch the permission preset (sandbox mode + approval policy)", + input: { hint: "" } + }, + { + name: "plan", + description: "Enter or leave plan mode", + input: { hint: "[off|message]" } + } + ] + }; + }, + execute(id, line) { + const missing = requireGoalSession(id); + if (missing !== void 0) return missing; + const match = /^\/(\S+)((?:\s.*)?)$/.exec(line.trim()); + const name = match?.[1]; + const args = match?.[2] ?? ""; + if (name === "permission") { + const preset = args.trim(); + const commandId = `fx-cmd-${logOf(id).length}`; + append(id, { + type: "command/run", + data: { + commandId, + name, + args, + source: { kind: "user" } + } + }); + const spec = PERMISSION_PRESETS[preset]; + let result; + if (preset === "") result = { + kind: "success", + text: `current preset ${permissionSelectOf(logOf(id)).currentValue} (available: ${Object.keys(PERMISSION_PRESETS).join(", ")})` + }; + else if (spec === void 0) result = { + kind: "error", + text: `unknown preset "${preset}" (available: ${Object.keys(PERMISSION_PRESETS).join(", ")})` + }; + else { + if (permissionSelectOf(logOf(id)).currentValue !== preset) append(id, { + type: "permission/preset", + data: { preset } + }); + append(id, { + type: "sandbox/mode", + data: { mode: spec.sandbox } + }); + append(id, { + type: "approval/policy", + data: { policy: spec.approval } + }); + result = { + kind: "success", + text: `preset ${preset}` + }; + } + append(id, { + type: "command/done", + data: { + commandId, + ...result + } + }); + return { + ok: true, + value: { + commandId, + result + } + }; + } + if (name === "goal") { + const commandId = `fx-cmd-${logOf(id).length}`; + append(id, { + type: "command/run", + data: { + commandId, + name, + args, + source: { kind: "user" } + } + }); + const objective = args.trim(); + const current = backscanGoal(logOf(id)); + let text; + if (objective === "") text = current === null ? "No goal is set. Usage: /goal " : `Current goal: ${current.goal.objective}`; + else if (current !== null && current.goal.phase !== "complete") text = `A goal already exists (${current.goal.objective}). Clear it first.`; + else text = `Goal created: ${appendGoalChange(id, { + kind: "goal/change", + version: 1, + operation: "create", + goal: { + id: `fx-goal-${logOf(id).length}`, + revision: 1, + objective, + phase: "active", + maxGoalRounds: 256 + }, + roundsStarted: 0, + createdAt: Date.now(), + updatedAt: Date.now() + }).goal.objective}`; + const result = { + kind: "success", + text + }; + append(id, { + type: "command/done", + data: { + commandId, + ...result + } + }); + return { + ok: true, + value: { + commandId, + result + } + }; + } + const running = summaryOf(id)?.running === true; + const outcomes = { + compact: "fixture:已压缩(假动作)", + echo: args.trim(), + plan: args.trim() === "off" ? running ? "Leaving plan mode (applies from the next step)." : "Plan mode off." : running ? "Entering plan mode (applies from the next step). Use /plan off to leave." : "Plan mode on. Use /plan off to leave." + }; + const text = name === void 0 ? void 0 : outcomes[name]; + if (name === void 0 || text === void 0) return { + ok: true, + value: void 0 + }; + const commandId = `fx-cmd-${logOf(id).length}`; + append(id, { + type: "command/run", + data: { + commandId, + name, + args, + source: { kind: "user" } + } + }); + if (name === "plan" && !running) { + const plan = foldPlan(logOf(id)); + if (plan.wanted !== null && plan.wanted !== plan.active) append(id, { + type: "plan/mode", + data: { active: plan.wanted } + }); + } + const result = { + kind: "success", + ...text === "" ? {} : { text } + }; + append(id, { + type: "command/done", + data: { + commandId, + ...result + } + }); + return { + ok: true, + value: { + commandId, + result + } + }; + } + }; + const goalView = (projection) => ({ + ...projection.goal, + roundsStarted: projection.roundsStarted, + createdAt: projection.createdAt, + updatedAt: projection.updatedAt, + activation: projection.goal.phase === "active" ? "armed" : "disarmed" + }); + /** Canonical fixture implementation of the generated Goal Remote contract. */ + const goalRemotes = { + create(id, request) { + const missing = requireGoalSession(id); + if (missing !== void 0) return missing; + const current = backscanGoal(logOf(id)); + if (current !== null && current.goal.phase !== "complete") return goalFailure(`goal "${current.goal.id}" already exists`); + const now = Date.now(); + const projection = appendGoalChange(id, { + kind: "goal/change", + version: 1, + operation: "create", + goal: { + id: `fx-goal-${logOf(id).length}`, + revision: 1, + objective: request.objective, + phase: "active", + maxGoalRounds: request.maxGoalRounds ?? 256 + }, + roundsStarted: 0, + createdAt: now, + updatedAt: now + }); + return { + ok: true, + value: { ref: { + id: projection.goal.id, + revision: projection.goal.revision + } } + }; + }, + edit(id, ref, request) { + return mutateGoal(id, ref, (current) => ({ + ...current.goal, + revision: current.goal.revision + 1, + ...request.objective === void 0 ? {} : { objective: request.objective }, + ...request.maxGoalRounds === void 0 ? {} : { maxGoalRounds: request.maxGoalRounds } + })); + }, + pause(id, ref) { + return mutateGoal(id, ref, (current) => current.goal.phase === "active" ? { + ...current.goal, + revision: current.goal.revision + 1, + phase: "paused" + } : void 0); + }, + resume(id, ref) { + return mutateGoal(id, ref, (current) => current.goal.phase === "paused" || current.goal.phase === "blocked" || current.goal.phase === "active" ? { + ...current.goal, + revision: current.goal.revision + 1, + phase: "active" + } : void 0); + }, + complete(id, ref) { + return mutateGoal(id, ref, (current) => current.goal.phase === "complete" ? void 0 : { + ...current.goal, + revision: current.goal.revision + 1, + phase: "complete" + }); + }, + clear(id, ref) { + const resolved = resolveGoal(id, ref); + if (!resolved.ok) return resolved; + const current = resolved.value; + const tombstone = { + id: current.goal.id, + revision: current.goal.revision + 1 + }; + appendGoalChange(id, { + kind: "goal/change", + version: 1, + operation: "clear", + cleared: tombstone, + clearedAt: Date.now() + }); + return { + ok: true, + value: tombstone + }; + } + }; + /** Resolve one current goal revision for a canonical Remote mutation. */ + function resolveGoal(id, ref) { + const missing = requireGoalSession(id); + if (missing !== void 0) return missing; + const current = backscanGoal(logOf(id)); + if (current === null || current.goal.id !== ref.id || current.goal.revision !== ref.revision) return goalFailure("stale or missing goal revision"); + return { + ok: true, + value: current + }; + } + /** Shared CAS mutation path behind the canonical Remote verbs. */ + function mutateGoal(id, ref, next) { + const resolved = resolveGoal(id, ref); + if (!resolved.ok) return resolved; + const current = resolved.value; + const goal = next(current); + if (goal === void 0) return goalFailure(`invalid goal transition from "${current.goal.phase}"`); + return { + ok: true, + value: goalView(appendGoalChange(id, { + kind: "goal/change", + version: 1, + operation: goal.phase === current.goal.phase ? "edit" : goal.phase === "paused" ? "pause" : goal.phase === "active" ? "resume" : "complete", + goal, + roundsStarted: current.roundsStarted, + createdAt: current.createdAt, + updatedAt: Date.now() + })) + }; + } + const mapGoalResult = (result, map) => result.ok ? { + ok: true, + value: map(result.value) + } : result; + const goalRefResult = (result) => mapGoalResult(result, (view) => ({ ref: { + id: view.id, + revision: view.revision + } })); + const legacyGoalResponse = (request, result) => Promise.resolve({ + rpcId: request.rpcId, + result + }); + /** At most one in-flight replay per session; cancel clears it. */ + const replays = /* @__PURE__ */ new Map(); + /** history transit delay (timing hooks below); the page snapshot is taken at request time, like a real host. */ + let historyDelayMs = 0; + /** One-shot history failure (timing hook: a pre-disconnect history request already doomed when reconnect lands). */ + let failNextHistory = false; + /** Force-enders for currently open stream generators (timing hook: simulated connection loss). */ + const streamBreakers = /* @__PURE__ */ new Set(); + /** Retry scenarios opened by timing hooks and completed in a later browser assertion phase. */ + const retryScenarios = /* @__PURE__ */ new Map(); + /** The single opt-in browser stress producer; normal fixture journeys never start it. */ + let activeReasoningChunkStorm = null; + globalThis.__fxTiming = { + setHistoryDelay(ms) { + historyDelayMs = ms; + }, + /** Fail the NEXT history call (after its transit delay) with a transport-level throw. */ + failNextHistory() { + failNextHistory = true; + }, + /** Log append + mux emit (the normal live path). */ + appendUser(id, msg) { + append(sid(id), { + type: "user/message", + surfaceOp: "append", + data: userMessage(text(msg)) + }); + }, + /** Append a later durable title revision through the normal raw-event + control-frame path. */ + appendTitle(id, title) { + const messageSeqs = logOf(sid(id)).filter((event) => event.type === "user/message").map((event) => event.seq); + append(sid(id), { + type: "session/title", + data: { + title, + messageSeqs, + source: { + kind: "provider", + provider: "fixture" + } + } + }); + }, + /** Start an externally paced reasoning stream for the opt-in browser stress lane. */ + startReasoningChunkStorm(id, chunkCount, chunksPerInterval, intervalMs) { + if (!Number.isSafeInteger(chunkCount) || chunkCount < 1) throw new Error("fixture: reasoning chunk count must be a positive safe integer"); + if (!Number.isSafeInteger(chunksPerInterval) || chunksPerInterval < 1) throw new Error("fixture: reasoning chunks per interval must be a positive safe integer"); + if (!Number.isSafeInteger(intervalMs) || intervalMs < 1) throw new Error("fixture: reasoning interval must be a positive safe integer"); + if (activeReasoningChunkStorm?.emitting === true) throw new Error("fixture: reasoning chunk storm already running"); + const sessionId = sid(id); + const log = logOf(sessionId); + let turn = nextTurn.get(sessionId) ?? 0; + for (const event of log) { + const candidate = event.data?.turn; + if (typeof candidate === "number") turn = Math.max(turn, candidate + 1); + } + nextTurn.set(sessionId, turn + 1); + const marker = `REASONING_STRESS_COMPLETE:${String(turn)}:${String(chunkCount)}`; + const state = { + sessionId: id, + chunkCount, + chunksPerInterval, + intervalMs, + emitted: 0, + marker, + emitting: true + }; + activeReasoningChunkStorm = state; + setRunning(sessionId, true); + append(sessionId, { + type: "turn/start", + data: { + turn, + trigger: { + kind: "message", + source: { kind: "user" } + } + } + }); + append(sessionId, { + type: "user/message", + surfaceOp: "append", + data: userMessage(text(`Reasoning chunk stress: ${String(chunkCount)} chunks.`)) + }); + append(sessionId, { + type: "step/start", + data: { + turn, + step: 0 + } + }); + append(sessionId, { + type: "assistant/chunk", + data: { + turn, + step: 0, + chunk: { + type: "block-start", + index: 0, + blockType: "reasoning" + } + } + }); + const startedAt = Date.now(); + const pump = () => { + const elapsedIntervals = Math.floor((Date.now() - startedAt) / intervalMs) + 1; + const due = Math.max(state.emitted + chunksPerInterval, elapsedIntervals * chunksPerInterval); + const end = Math.min(due, chunkCount); + for (let index = state.emitted; index < end; index++) { + const chunkText = index === chunkCount - 1 ? `\n${marker}` : index % 64 === 63 ? "推理\n" : "推理"; + append(sessionId, { + type: "assistant/chunk", + data: { + turn, + step: 0, + chunk: { + type: "reasoning-delta", + index: 0, + text: chunkText + } + } + }); + } + state.emitted = end; + if (end < chunkCount) setTimeout(pump, intervalMs); + else state.emitting = false; + }; + setTimeout(pump, 0); + return marker; + }, + /** Return a copy so browser probes cannot mutate the active producer. */ + reasoningChunkStormState() { + return activeReasoningChunkStorm === null ? null : { ...activeReasoningChunkStorm }; + }, + /** Open one failed model step whose partial remains visible until llm/retry arrives. */ + beginModelRetry(id) { + const sessionId = sid(id); + const turn = nextTurn.get(sessionId) ?? 0; + nextTurn.set(sessionId, turn + 1); + retryScenarios.set(sessionId, { + turn, + stepStarted: true + }); + setRunning(sessionId, true); + append(sessionId, { + type: "turn/start", + data: { turn } + }); + append(sessionId, { + type: "user/message", + surfaceOp: "append", + data: { + content: text("请重试这个请求"), + source: { kind: "user" } + } + }); + append(sessionId, { + type: "step/start", + data: { + turn, + step: 1 + } + }); + append(sessionId, { + type: "assistant/chunk", + data: { + turn, + step: 1, + chunk: { + type: "block-start", + index: 0, + blockType: "text" + } + } + }); + append(sessionId, { + type: "assistant/chunk", + data: { + turn, + step: 1, + chunk: { + type: "text-delta", + index: 0, + text: "应撤回的半截回复" + } + } + }); + }, + /** Record one retry decision; the next attempt remains in the same step. */ + scheduleModelRetry(id, retry = 1, delayMs = 450) { + const sessionId = sid(id); + const scenario = retryScenarios.get(sessionId); + if (scenario === void 0) throw new Error(`fixture: no model retry scenario for ${id}`); + if (!scenario.stepStarted) { + append(sessionId, { + type: "assistant/chunk", + data: { + turn: scenario.turn, + step: 1, + chunk: { + type: "block-start", + index: 0, + blockType: "text" + } + } + }); + append(sessionId, { + type: "assistant/chunk", + data: { + turn: scenario.turn, + step: 1, + chunk: { + type: "text-delta", + index: 0, + text: `第 ${String(retry)} 次应撤回的回复` + } + } + }); + scenario.stepStarted = true; + } + append(sessionId, { + type: "llm/retry", + data: { + turn: scenario.turn, + step: 1, + provider: "fixture", + mode: "normal", + policyKey: "fixture-normal", + retry, + maxRetries: 2, + delayMs, + failure: { + code: "TRANSPORT", + message: "连接被重置" + } + } + }); + scenario.stepStarted = false; + }, + /** Record one retry decision, then cancel its source turn before the retry starts. */ + cancelModelRetryDuringBackoff(id, delayMs = 450) { + const sessionId = sid(id); + const scenario = retryScenarios.get(sessionId); + if (scenario === void 0) throw new Error(`fixture: no model retry scenario for ${id}`); + append(sessionId, { + type: "llm/retry", + data: { + turn: scenario.turn, + step: 1, + provider: "fixture", + mode: "normal", + policyKey: "fixture-normal", + retry: 1, + maxRetries: 2, + delayMs, + failure: { + code: "TRANSPORT", + message: "连接被重置" + } + } + }); + append(sessionId, { + type: "step/end", + data: { + turn: scenario.turn, + step: 1 + } + }); + append(sessionId, { + type: "turn/end", + data: { + turn: scenario.turn, + reason: { + kind: "aborted", + reason: { kind: "user" } + } + } + }); + retryScenarios.delete(sessionId); + setRunning(sessionId, false); + }, + /** Finish the timing-hook retry with a finalized response in the open step. */ + completeModelRetry(id) { + const sessionId = sid(id); + const scenario = retryScenarios.get(sessionId); + if (scenario === void 0) throw new Error(`fixture: no model retry scenario for ${id}`); + retryScenarios.delete(sessionId); + append(sessionId, { + type: "assistant/chunk", + data: { + turn: scenario.turn, + step: 1, + chunk: { + type: "block-start", + index: 0, + blockType: "text" + } + } + }); + append(sessionId, { + type: "assistant/message", + surfaceOp: "append", + data: { + turn: scenario.turn, + step: 1, + message: assistantMessage(text("重试后的完整回复")) + } + }); + append(sessionId, { + type: "step/end", + data: { + turn: scenario.turn, + step: 1 + } + }); + append(sessionId, { + type: "turn/end", + data: { + turn: scenario.turn, + reason: { kind: "completed" } + } + }); + setRunning(sessionId, false); + }, + /** Log append WITHOUT the mux emit: a frame lost in transit — history still serves it, the client must repull. */ + appendSilent(id, msg) { + const log = logOf(sid(id)); + log.push({ + type: "user/message", + surfaceOp: "append", + seq: log.length, + time: Date.now(), + data: userMessage(text(msg)) + }); + }, + /** End every open stream generator (client sees both streams close -> reconnect + resync path). */ + breakStreams() { + for (const breakNow of [...streamBreakers]) breakNow(); + } + }; + /** Prompt replay: chunk typewriter (80ms/frame) -> assistant/message finalize -> turn/end + running flip. */ + const startReply = (id, turn, replyText) => { + const step = 0; + append(id, { + type: "step/start", + data: { + turn, + step + } + }); + append(id, { + type: "assistant/chunk", + data: { + turn, + step, + chunk: { + type: "block-start", + index: 0, + blockType: "text" + } + } + }); + /* v8 ignore next -- the ?? arm needs a null match, but every fixture reply is non-empty. */ + const pieces = replyText.match(/[\s\S]{1,6}/gu) ?? [replyText]; + let i = 0; + const finish = (aborted) => { + replays.delete(id); + const done = pieces.slice(0, i).join(""); + append(id, { + type: "assistant/chunk", + data: { + turn, + step, + chunk: { + type: "block-end", + index: 0, + block: { + type: "text", + text: done + } + } + } + }); + append(id, { + type: "assistant/message", + surfaceOp: "append", + data: { + turn, + step, + message: assistantMessage(text(aborted ? `${done}(已中断)` : done)), + usage: fixtureUsage(turn, step) + } + }); + append(id, { + type: "step/end", + data: { + turn, + step + } + }); + append(id, { + type: "turn/end", + data: { + turn, + reason: { kind: aborted ? "cancelled" : "completed" } + } + }); + setRunning(id, false); + }; + const tick = () => { + const piece = pieces[i]; + if (piece === void 0) { + finish(false); + return; + } + i++; + append(id, { + type: "assistant/chunk", + data: { + turn, + step, + chunk: { + type: "text-delta", + index: 0, + text: piece + } + } + }); + replays.set(id, { + timer: setTimeout(tick, 80), + finish + }); + }; + replays.set(id, { + timer: setTimeout(tick, 80), + finish + }); + }; + return { + api: { + sessions: { + list: (request) => ok(request, { items: [...sessions].sort((a, b) => b.updatedAt - a.updatedAt) }), + search: (request, signal) => { + if (signal.aborted) return err(request, { + code: "cancelled", + message: "fixture session search was aborted", + details: {} + }); + const query = searchTokenSpans(request.payload.query).tokens.map((token) => token.value); + const matches = sessions.flatMap((summary) => { + const log = logs.get(summary.sessionId) ?? []; + const current = new Set(foldSurface(log).nodes); + const best = log.flatMap((event) => { + if (!current.has(event.seq)) return []; + const eventText = searchEventText(event); + const document = searchTokenSpans(eventText); + const match = phraseMatch(document.tokens, query); + if (match.count === 0) return []; + return [{ + sessionId: summary.sessionId, + seq: event.seq, + time: event.time, + text: document.text, + matchCount: match.count, + matchStart: match.start, + matchEnd: match.end, + documentLength: Array.from(eventText).length + }]; + }).sort(compareSearchCandidates)[0]; + return best === void 0 ? [] : [best]; + }).sort(compareSearchCandidates); + return ok(request, { + items: matches.slice(0, 20).map((match) => ({ + sessionId: match.sessionId, + snippet: searchSnippet(match.text, match.matchStart, match.matchEnd) + })), + hasMore: matches.length > 20 + }); + }, + create: async (request) => { + const workspace = request.payload.workspaceId === void 0 ? void 0 : workspaces.find((w) => w.workspaceId === request.payload.workspaceId); + if (request.payload.workspaceId !== void 0 && workspace === void 0) return err(request, { + code: "workspace-not-found", + message: `no workspace ${request.payload.workspaceId}`, + details: { workspaceId: request.payload.workspaceId } + }); + const cwd = workspace?.path ?? request.payload.cwd ?? "/tmp/fixture"; + const requestedId = request.payload.sessionId; + const attachWorkspace = (sessionId) => { + /* v8 ignore next -- callers enter only when a target Workspace exists. */ + if (workspace === void 0 || workspace.sessionIds.includes(sessionId)) return; + workspace.sessionIds = [sessionId, ...workspace.sessionIds]; + workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString(); + emitHost({ + type: "host/workspace-changed", + workspace: { ...workspace } + }); + }; + const attachFailure = (sessionId, workspaceId) => err(request, { + code: "workspace-attach-failed", + message: `fixture rejected Workspace attachment for ${sessionId}`, + details: { + sessionId, + workspaceId + } + }); + if (requestedId !== void 0) { + const existing = summaryOf(requestedId); + if (existing !== void 0) { + if (existing.cwd !== cwd) return err(request, { + code: "session-conflict", + message: `session ${requestedId} already uses ${existing.cwd ?? "no cwd"}`, + details: { + sessionId: requestedId, + requestedCwd: cwd, + ...existing.cwd === void 0 ? {} : { existingCwd: existing.cwd } + } + }); + if (workspace !== void 0 && !workspace.sessionIds.includes(requestedId)) { + if (options.failWorkspaceAttach) return attachFailure(requestedId, workspace.workspaceId); + attachWorkspace(requestedId); + } + return ok(request, { sessionId: requestedId }); + } + } + const created = { + sessionId: requestedId ?? sid(`fx-${nextSession++}`), + updatedAt: Date.now(), + running: false, + blank: true, + cwd + }; + sessions.push(created); + modelSelections.set(created.sessionId, { + provider: "deepseek-official", + model: "deepseek-v4-flash" + }); + attachedSessions += 1; + const emitSession = () => { + emitHost({ + type: "host/session-added", + sessionId: created.sessionId, + blank: true, + cwd + }); + }; + if (workspace !== void 0 && options.failWorkspaceAttach) { + emitSession(); + return attachFailure(created.sessionId, workspace.workspaceId); + } + if (workspace !== void 0 && options.createFrameOrder === "workspace-first") { + attachWorkspace(created.sessionId); + emitSession(); + } else { + emitSession(); + if (workspace !== void 0) attachWorkspace(created.sessionId); + } + if (options.dropSessionCreateResponse) throw new Error("fixture: dropped session.create response after publication"); + return ok(request, { sessionId: created.sessionId }); + }, + rename: (request) => { + const missing = requireSession(request); + if (missing !== void 0) return missing; + const { sessionId, title } = request.payload; + const normalized = title.trim().replace(/\s+/g, " "); + if (normalized.length === 0) return err(request, { + code: "title-invalid", + message: "session title must contain visible characters", + details: { sessionId } + }); + append(sessionId, { + type: "session/title", + data: { + title: normalized, + messageSeqs: [], + source: { kind: "user" } + } + }); + return ok(request, { + title: normalized, + seq: logOf(sessionId).at(-1).seq + }); + }, + fork: (request) => { + const { sessionId, atSeq } = request.payload; + const source = summaryOf(sessionId); + if (source === void 0) return err(request, { + code: "session-not-found", + message: `no session ${sessionId}`, + details: { sessionId } + }); + const log = logs.get(sessionId) ?? []; + const lastSeq = log.at(-1)?.seq ?? -1; + const boundary = (atSeq === void 0 ? void 0 : log.find((e) => e.type === "turn/end" && e.seq >= atSeq)) ?? (atSeq === void 0 || atSeq > lastSeq ? log.findLast((e) => e.type === "turn/end") : void 0); + if (boundary === void 0) return err(request, { + code: "fork-unavailable", + message: atSeq !== void 0 && atSeq <= lastSeq ? `session ${sessionId} has not completed the turn containing event ${String(atSeq)}` : `session ${sessionId} has no completed turn`, + details: { sessionId } + }); + let cut = boundary.seq + 1; + while (cut < log.length && log[cut]?.type !== "turn/start") cut++; + const child = { + sessionId: sid(`fx-${nextSession++}`), + updatedAt: Date.now(), + running: false, + blank: false, + parentSessionId: sessionId, + ...source.cwd === void 0 ? {} : { cwd: source.cwd } + }; + logs.set(child.sessionId, log.slice(0, cut)); + sessions.push(child); + emitHost({ + type: "host/session-added", + sessionId: child.sessionId, + blank: false, + parentSessionId: sessionId, + ...source.cwd === void 0 ? {} : { cwd: source.cwd } + }); + const workspace = workspaces.find((w) => w.sessionIds.includes(sessionId)); + if (workspace !== void 0) { + workspace.sessionIds = [child.sessionId, ...workspace.sessionIds]; + workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString(); + emitHost({ + type: "host/workspace-changed", + workspace: { ...workspace } + }); + } + return ok(request, { sessionId: child.sessionId }); + }, + history: async (request) => { + const log = logs.get(request.payload.sessionId) ?? []; + const page = pageOf(log, request.payload.beforeSeq, request.payload.maxMessages ?? 50); + const projections = request.payload.beforeSeq === void 0 ? { + asOfSeq: log.length - 1, + values: projectionValuesOf(log) + } : void 0; + const doomed = failNextHistory; + failNextHistory = false; + const delay = historyDelayMs; + if (delay > 0) await new Promise((resolve) => setTimeout(resolve, delay)); + if (doomed) throw new Error("fixture: simulated history transport failure"); + return ok(request, { + ...page, + ...projections === void 0 ? {} : { projections } + }); + }, + models: (request) => ok(request, { + current: modelSelections.get(request.payload.sessionId) ?? { + provider: "deepseek-official", + model: "deepseek-v4-flash" + }, + routable: true, + groups: fixtureModelGroups(), + failures: [] + }), + selectModel: (request) => { + const selected = { + provider: request.payload.provider, + model: request.payload.model, + ...request.payload.reasoningEffort === void 0 ? {} : { reasoningEffort: request.payload.reasoningEffort } + }; + modelSelections.set(request.payload.sessionId, selected); + return ok(request, { selected }); + }, + prompt: (request) => { + const { sessionId: id, mode, content } = request.payload; + const summary = summaryOf(id); + if (summary === void 0) return err(request, { + code: "session-not-found", + message: `no session ${id}`, + details: { sessionId: id } + }); + if (options.rejectPrompt) return err(request, { + code: "agent-busy", + message: "fixture: prompt rejected before acceptance", + details: { reason: "fixture-prompt-rejection" } + }); + summary.updatedAt = Date.now(); + summary.blank = false; + const userText = content.map((b) => b.type === "text" ? b.text : "").join(""); + const durable = content.map((block) => { + if (block.type === "text") return block; + const attachment = { + attachmentId: `fixture:${randomUuid()}`, + mediaType: block.mediaType, + bytes: Math.max(1, Math.floor(block.data.length * 3 / 4) - (block.data.endsWith("==") ? 2 : block.data.endsWith("=") ? 1 : 0)), + width: 160, + height: 90, + ...block.name === void 0 ? {} : { name: block.name } + }; + attachments.set(String(attachment.attachmentId), { + attachment, + data: block.data + }); + return { + type: "image", + attachment + }; + }); + if (mode === "steer" && replays.has(id)) { + append(id, { + type: "user/message", + surfaceOp: "append", + data: userMessage(durable) + }); + return ok(request, { accepted: true }); + } + const turn = nextTurn.get(id) ?? 0; + nextTurn.set(id, turn + 1); + setRunning(id, true); + append(id, { + type: "turn/start", + data: { turn } + }); + const plan = foldPlan(logOf(id)); + if (plan.wanted !== null && plan.wanted !== plan.active) append(id, { + type: "plan/mode", + data: { active: plan.wanted } + }); + append(id, { + type: "user/message", + surfaceOp: "append", + data: userMessage(durable) + }); + const selection = modelSelections.get(id) ?? { + provider: "deepseek", + model: "deepseek-v4-flash" + }; + if (lastRequestContext(logOf(id))?.model !== selection.model) append(id, { + type: "request/context", + data: { + provider: selection.provider, + model: selection.model, + contextWindow: 128e3 + } + }); + startReply(id, turn, userText === "render markdown" ? MARKDOWN_FIXTURE : userText === "report model" ? (() => { + const selection = modelSelections.get(id); + return `当前模型:${selection?.provider ?? "unknown"}/${selection?.model ?? "unknown"}` + (selection?.reasoningEffort === void 0 ? "" : ` · 推理等级:${selection.reasoningEffort}`); + })() : `回声:${userText}。这是 fixture 的流式回复,用于验证打字机增长与定稿切换。`); + return ok(request, { accepted: true }); + }, + attachment: (request) => { + const stored = attachments.get(String(request.payload.attachmentId)); + if (stored === void 0) return err(request, { + code: "attachment-error", + message: "fixture attachment missing", + details: { reason: "ATTACHMENT_NOT_FOUND" } + }); + if (!logReferencesAttachment(logs.get(request.payload.sessionId) ?? [], String(request.payload.attachmentId))) return err(request, { + code: "attachment-error", + message: "fixture attachment is not referenced by this session", + details: { reason: "ATTACHMENT_NOT_REFERENCED" } + }); + return ok(request, stored); + }, + updateQueue: (request) => err(request, { + code: "queue-item-not-found", + message: "fixture has no pending queue item", + details: { itemId: request.payload.itemId } + }), + cancel: (request) => { + const replay = replays.get(request.payload.sessionId); + if (replay !== void 0) { + clearTimeout(replay.timer); + replay.finish(true); + } else setRunning(request.payload.sessionId, false); + return ok(request, { accepted: true }); + } + }, + subagents: { + list: (request) => ok(request, { + entries: [], + parentAvailable: true + }), + history: (request) => { + const log = logs.get(request.payload.childSessionId) ?? []; + return Promise.resolve(ok(request, pageOf(log, request.payload.beforeSeq, request.payload.maxMessages ?? 50))); + }, + prompt: (request) => Promise.resolve(ok(request, { messageId: `fixture-message-${request.payload.childSessionId}` })), + interrupt: (request) => Promise.resolve(ok(request, { accepted: true })) + }, + host: { + describe: (request) => ok(request, { + version: "0.0.0-fixture", + cwd: "/tmp/fixture", + attachedSessions, + canOpenPath: true + }), + pickDirectory: (request) => ok(request, { path: `${FIXTURE_HOME}/Documents/project` }), + listDirectory: (request) => { + const target = request.payload.path ?? FIXTURE_HOME; + const children = childrenOf(target); + if (children === void 0) return err(request, { + code: "directory-unreadable", + message: `cannot list ${target}: not in the fixture tree`, + details: { path: target } + }); + return ok(request, { + path: target, + home: FIXTURE_HOME, + crumbs: crumbsOf(target), + entries: [...children].sort((a, b) => a.localeCompare(b)).map((name) => ({ + name, + path: target === "/" ? `/${name}` : `${target}/${name}`, + hidden: name.startsWith(".") + })), + truncated: false + }); + }, + createDirectory: (request) => { + const parent = request.payload.path; + const children = childrenOf(parent); + if (children === void 0) return err(request, { + code: "directory-create-failed", + message: `missing parent ${parent}`, + details: { path: parent } + }); + const target = parent === "/" ? `/${request.payload.name}` : `${parent}/${request.payload.name}`; + if (children.includes(request.payload.name)) return err(request, { + code: "directory-exists", + message: `${target} already exists`, + details: { path: target } + }); + directoryTree.set(parent, [...children, request.payload.name]); + directoryTree.set(target, []); + return ok(request, { path: target }); + }, + openPath: (request) => ok(request, { opened: true }) + }, + workspace: { + list: (request) => ok(request, { + items: workspaces.map((w) => ({ ...w })), + archivedSessionIds: [...archivedSessionIds] + }), + create: (request) => { + const { path } = request.payload; + const existing = workspaces.find((w) => w.path === path); + if (existing !== void 0) return ok(request, { + workspace: { ...existing }, + created: false + }); + const now = (/* @__PURE__ */ new Date()).toISOString(); + const created = { + workspaceId: wid(`fx-ws-${nextWorkspace++}`), + path, + title: path.split("/").filter(Boolean).at(-1) ?? path, + sessionIds: [], + createdAt: now, + updatedAt: now + }; + workspaces.unshift(created); + emitHost({ + type: "host/workspace-changed", + workspace: { ...created } + }); + return ok(request, { + workspace: { ...created }, + created: true + }); + }, + rename: (request) => { + const { workspaceId, title } = request.payload; + const workspace = workspaces.find((w) => w.workspaceId === workspaceId); + if (workspace === void 0) return err(request, { + code: "workspace-not-found", + message: `no workspace ${workspaceId}`, + details: { workspaceId } + }); + const trimmed = title.trim(); + if (trimmed !== workspace.title) { + if (workspaces.some((w) => w.workspaceId !== workspaceId && w.title === trimmed)) return err(request, { + code: "workspace-name-conflict", + message: `workspace name '${trimmed}' is already in use`, + details: { name: trimmed } + }); + workspace.title = trimmed; + workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString(); + emitHost({ + type: "host/workspace-changed", + workspace: { ...workspace } + }); + } + return ok(request, { workspace: { ...workspace } }); + }, + delete: (request) => { + const { workspaceId } = request.payload; + const index = workspaces.findIndex((workspace) => workspace.workspaceId === workspaceId); + if (index === -1) return err(request, { + code: "workspace-not-found", + message: `no workspace ${workspaceId}`, + details: { workspaceId } + }); + workspaces.splice(index, 1); + emitHost({ + type: "host/workspace-removed", + workspaceId + }); + return ok(request, { deleted: true }); + }, + insertBefore: (request) => { + const { workspaceId, beforeWorkspaceId } = request.payload; + const source = workspaces.findIndex((workspace) => workspace.workspaceId === workspaceId); + const anchor = beforeWorkspaceId === void 0 ? workspaces.length : workspaces.findIndex((workspace) => workspace.workspaceId === beforeWorkspaceId); + const missing = source === -1 ? workspaceId : anchor === -1 ? beforeWorkspaceId : void 0; + if (missing !== void 0) return err(request, { + code: "workspace-not-found", + message: `no workspace ${missing}`, + details: { workspaceId: missing } + }); + if (beforeWorkspaceId !== workspaceId) { + const previousOrder = workspaces.map((candidate) => candidate.workspaceId); + const [workspace] = workspaces.splice(source, 1); + /* v8 ignore next -- source was resolved from the same array immediately above. */ + if (workspace === void 0) throw new Error(`fixture lost workspace ${workspaceId}`); + const at = beforeWorkspaceId === void 0 ? workspaces.length : workspaces.findIndex((candidate) => candidate.workspaceId === beforeWorkspaceId); + workspaces.splice(at, 0, workspace); + if (workspaces.some((candidate, index) => candidate.workspaceId !== previousOrder[index])) emitHost({ + type: "host/workspace-order-changed", + workspaceIds: workspaces.map((candidate) => candidate.workspaceId) + }); + } + return ok(request, { workspaceIds: workspaces.map((candidate) => candidate.workspaceId) }); + }, + insertSessionBefore: (request) => { + const { workspaceId, sessionId, beforeSessionId } = request.payload; + const workspace = workspaces.find((w) => w.workspaceId === workspaceId); + if (workspace === void 0) return err(request, { + code: "workspace-not-found", + message: `no workspace ${workspaceId}`, + details: { workspaceId } + }); + if (!workspace.sessionIds.includes(sessionId) || beforeSessionId !== void 0 && !workspace.sessionIds.includes(beforeSessionId)) return err(request, { + code: "workspace-move-invalid", + message: `session or anchor is not accounted by workspace ${workspaceId}`, + details: { + workspaceId, + sessionId, + ...beforeSessionId === void 0 ? {} : { beforeSessionId } + } + }); + const without = workspace.sessionIds.filter((id) => id !== sessionId); + const at = beforeSessionId === void 0 ? without.length : without.indexOf(beforeSessionId); + const sessionIds = [ + ...without.slice(0, at), + sessionId, + ...without.slice(at) + ]; + if (!sessionIds.every((id, index) => id === workspace.sessionIds[index])) { + workspace.sessionIds = sessionIds; + workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString(); + emitHost({ + type: "host/workspace-changed", + workspace: { ...workspace } + }); + } + return ok(request, { workspace: { ...workspace } }); + }, + archiveSession: (request) => { + const missing = requireSession(request); + if (missing !== void 0) return missing; + const { sessionId } = request.payload; + if (!archivedSessionIds.includes(sessionId)) { + archivedSessionIds.push(sessionId); + emitHost({ + type: "host/archived-sessions-changed", + archivedSessionIds: [...archivedSessionIds] + }); + } + return ok(request, { archivedSessionIds: [...archivedSessionIds] }); + } + }, + agentPresets: { + list: (request) => ok(request, { + presets: [...fixturePresets].map(([id, preset]) => ({ + id, + trust: preset.trust, + isDefault: id === fixtureDefaultPreset + })), + authorable: true, + hasDocument: true + }), + select: (request) => { + fixtureDefaultPreset = request.payload.agentPreset; + return ok(request, { agentPreset: request.payload.agentPreset }); + }, + read: (request) => { + const { agentPreset } = request.payload; + const preset = fixturePresets.get(agentPreset); + if (preset === void 0) return err(request, { + code: "agent-preset-not-found", + message: `unknown agent preset "${agentPreset}"`, + details: { + agentPreset, + available: [...fixturePresets.keys()] + } + }); + return ok(request, { + agentPreset, + trust: preset.trust, + content: preset.content + }); + }, + copy: (request) => { + const { from, agentPreset } = request.payload; + const source = fixturePresets.get(from); + if (source === void 0) return err(request, { + code: "agent-preset-not-found", + message: `unknown agent preset "${from}"`, + details: { + agentPreset: from, + available: [...fixturePresets.keys()] + } + }); + if (fixturePresets.has(agentPreset)) return err(request, { + code: "agent-preset-invalid", + message: `agent preset "${agentPreset}" already exists`, + details: { + agentPreset, + reason: "already exists" + } + }); + fixturePresets.set(agentPreset, { + trust: "user", + content: source.content + }); + return ok(request, { agentPreset }); + }, + openDocument: (request) => { + const { agentPreset } = request.payload; + const existing = fixturePresets.get(agentPreset); + if (existing === void 0 || existing.trust === "system") return err(request, { + code: "agent-preset-read-only", + message: `agent preset "${agentPreset}" ships with the deployment`, + details: { + agentPreset, + reason: "it ships with the deployment" + } + }); + return ok(request, { opened: true }); + }, + remove: (request) => { + const { agentPreset } = request.payload; + if (fixturePresets.get(agentPreset)?.trust === "system") return err(request, { + code: "agent-preset-read-only", + message: `agent preset "${agentPreset}" ships with the deployment`, + details: { + agentPreset, + reason: "it ships with the deployment" + } + }); + fixturePresets.delete(agentPreset); + return ok(request, {}); + } + }, + skills: { list: (request) => { + const missing = requireSession(request); + if (missing !== void 0) return missing; + return ok(request, { skills: [{ + name: "fixture-demo", + description: "fixture 技能样本", + whenToUse: "仅供 UI 目录渲染验收", + modelInvocable: true + }, { + name: "fixture-user-only", + description: "fixture 仅用户技能样本", + modelInvocable: false + }] }); + } }, + goals: { + create: (request) => legacyGoalResponse(request, mapGoalResult(goalRemotes.create(request.payload.sessionId, { + objective: request.payload.objective, + ...request.payload.maxGoalRounds === void 0 ? {} : { maxGoalRounds: request.payload.maxGoalRounds } + }), (value) => ({ ref: { + id: value.ref.id, + revision: value.ref.revision + } }))), + edit: (request) => legacyGoalResponse(request, goalRefResult(goalRemotes.edit(request.payload.sessionId, request.payload.ref, { + ...request.payload.objective === void 0 ? {} : { objective: request.payload.objective }, + ...request.payload.maxGoalRounds === void 0 ? {} : { maxGoalRounds: request.payload.maxGoalRounds } + }))), + pause: (request) => legacyGoalResponse(request, goalRefResult(goalRemotes.pause(request.payload.sessionId, request.payload.ref))), + resume: (request) => legacyGoalResponse(request, goalRefResult(goalRemotes.resume(request.payload.sessionId, request.payload.ref))), + complete: (request) => legacyGoalResponse(request, goalRefResult(goalRemotes.complete(request.payload.sessionId, request.payload.ref))), + clear: (request) => legacyGoalResponse(request, mapGoalResult(goalRemotes.clear(request.payload.sessionId, request.payload.ref), () => ({ cleared: true }))) + }, + events: { + async *mux(_request, signal) { + const conn = new FxInbox(); + muxConns.add(conn); + const breakNow = () => { + conn.breakNow(); + }; + streamBreakers.add(breakNow); + for (const s of sessions) { + if (!s.running) continue; + const log = logs.get(s.sessionId) ?? []; + conn.push({ + rpcId: mint(), + payload: { + type: "session/subscribed", + sessionId: s.sessionId, + lastSeq: log.length - 1 + } + }); + const values = projectionValuesOf(log); + for (const key of Object.keys(values)) conn.push({ + rpcId: mint(), + payload: { + type: "session/projection", + sessionId: s.sessionId, + key, + value: values[key], + seq: log.length - 1 + } + }); + } + if (approvalPending) conn.push({ + rpcId: pendingApprovalRpcId, + payload: { + type: "approval/requested", + sessionId: sid("fx-alpha"), + approvalId: pendingApprovalId, + toolName: "dangerous_tool", + reason: "fixture 常驻审批(可答:批准/拒绝后消失)" + } + }); + if (questionPending) conn.push({ + rpcId: pendingQuestionRpcId, + payload: { + type: "question/requested", + sessionId: sid("fx-alpha"), + questions: fixtureQuestions + } + }); + try { + yield* conn.drain(signal); + } finally { + streamBreakers.delete(breakNow); + muxConns.delete(conn); + } + }, + async *host(_request, signal) { + const conn = new FxInbox(); + hostConns.add(conn); + const breakNow = () => { + conn.breakNow(); + }; + streamBreakers.add(breakNow); + const timer = setInterval(() => { + const gamma = summaryOf(sid("fx-gamma")); + /* v8 ignore next -- the undefined arm needs fx-gamma deleted, but the fixture never removes sessions. */ + if (gamma !== void 0) setRunning(gamma.sessionId, !gamma.running); + }, 5e3); + try { + yield* conn.drain(signal); + } finally { + clearInterval(timer); + streamBreakers.delete(breakNow); + hostConns.delete(conn); + } + } + }, + settings: { + describe: (request) => ok(request, { + writable: true, + hasDocument: true, + namespaces: [{ + ns: "llm-deepseek", + schema: {}, + value: { apiKeyEnv: "DEEPSEEK_API_KEY" }, + applies: "live", + secrets: [{ + path: ["apiKey"], + set: false + }], + revision: 0 + }] + }), + openDocument: (request) => ok(request, { opened: true }), + update: (request) => err(request, { + code: "settings-rejected", + message: "fixture: the minimal readiness settings descriptor is read-only", + details: { ns: request.payload.ns } + }), + replace: (request) => err(request, { + code: "settings-rejected", + message: "fixture: the minimal readiness settings descriptor is read-only", + details: { ns: request.payload.ns } + }), + mutate: (request) => err(request, { + code: "settings-rejected", + message: "fixture: no settings namespaces are registered", + details: { ns: request.payload.ns } + }) + }, + credentials: { + describe: (request) => ok(request, { credentials: Object.fromEntries(request.payload.refs.map((ref) => [ref, { + configured: fixtureCredentials.has(ref), + ...fixtureCredentials.has(ref) ? { source: "file" } : {}, + writable: true + }])) }), + set: (request) => { + fixtureCredentials.set(request.payload.ref, true); + return ok(request, {}); + }, + unset: (request) => { + fixtureCredentials.delete(request.payload.ref); + return ok(request, {}); + } + }, + llm: { + providers: (request) => ok(request, { providers: [ + { + provider: "deepseek-official", + displayName: "DeepSeek", + settingsNs: "llm-deepseek", + settingsPath: [], + active: true + }, + { + provider: "openai", + displayName: "openai", + settingsNs: "llm-pi-ai", + settingsPath: ["providers", "openai"], + active: true, + declared: false + }, + { + provider: "anthropic", + displayName: "anthropic", + settingsNs: "llm-pi-ai", + settingsPath: ["providers", "anthropic"], + active: false, + declared: false + }, + { + provider: "acme-gateway", + displayName: "Acme Gateway", + settingsNs: "llm-pi-ai", + settingsPath: ["providers", "acme-gateway"], + active: true, + declared: true + } + ] }), + models: (request) => ok(request, { + groups: fixtureModelGroups(), + failures: [] + }), + discoverModels: (request) => ok(request, { models: fixtureModelGroups().flatMap((group) => group.models.map((model) => ({ + id: model.id, + name: model.name + }))) }) + }, + respond(message) { + if (message.rpcId === pendingApprovalRpcId) { + if (!approvalPending) return Promise.resolve({ + accepted: false, + reason: "not-pending" + }); + if (!message.result.ok) return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + const value = message.result.value; + if (value.approvalId !== pendingApprovalId || value.outcome !== "allowed-once" && value.outcome !== "rejected") return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + approvalPending = false; + emitMux({ + type: "approval/resolved", + sessionId: sid("fx-alpha"), + approvalId: pendingApprovalId, + outcome: value.outcome + }); + return Promise.resolve({ accepted: true }); + } + if (!questionPending || message.rpcId !== pendingQuestionRpcId) return Promise.resolve({ + accepted: false, + reason: "not-pending" + }); + questionPending = false; + emitMux({ + type: "question/resolved", + sessionId: sid("fx-alpha"), + questionRpcId: pendingQuestionRpcId, + outcome: message.result.ok ? "answered" : "cancelled" + }); + return Promise.resolve({ accepted: true }); + }, + downloads: { sessionLog: () => Promise.resolve(new Response("fixture mode does not serve session export", { status: 404 })) } + }, + rpc: { call(channel, endpoint, payload) { + if (channel !== "/api") return Promise.reject(/* @__PURE__ */ new Error(`fixture connection RPC channel ${JSON.stringify(channel)} is unavailable`)); + const args = payload.args; + const sessionId = args.agentId; + switch (endpoint) { + case "commands/list": return Promise.resolve(commandRemotes.list(sessionId)); + case "commands/execute": return Promise.resolve(commandRemotes.execute(sessionId, args.line)); + case "goals/create": return Promise.resolve(goalRemotes.create(sessionId, { + objective: args.request?.objective, + ...args.request?.maxGoalRounds === void 0 ? {} : { maxGoalRounds: args.request.maxGoalRounds } + })); + case "goals/edit": return Promise.resolve(goalRemotes.edit(sessionId, args.ref, args.request ?? {})); + case "goals/pause": return Promise.resolve(goalRemotes.pause(sessionId, args.ref)); + case "goals/resume": return Promise.resolve(goalRemotes.resume(sessionId, args.ref)); + case "goals/complete": return Promise.resolve(goalRemotes.complete(sessionId, args.ref)); + case "goals/clear": return Promise.resolve(goalRemotes.clear(sessionId, args.ref)); + default: return Promise.reject(/* @__PURE__ */ new Error(`fixture connection RPC endpoint ${JSON.stringify(endpoint)} is unavailable`)); + } + } } + }; + } + /** + * Fixture platform subclass: there is no HTTP at all, so instead of a doFetch transport it + * overrides the protocol-level virtuals (callUnary/openMux/openHost/respond) to dispatch + * straight into the in-memory ApiProxy — while still minting rpcIds, fabricating the four + * named full forms, and feeding the same tap as a real carrier. TODO: delete when the fixture + * moves to the isomorphic pipeline (InProcessApiClient over toFetchHandler(fixtureImpl)). + */ + var FixtureApiClient = class extends AbstractApiClient { + api; + /** Generic Remote caller backed by the same in-memory state as the legacy fixture API. */ + rpc; + constructor() { + super(); + const world = createFixtureWorld(fixtureOptionsFromLocation()); + this.api = world.api; + this.rpc = world.rpc; + } + doFetch() { + throw new Error("FixtureApiClient overrides all protocol paths; doFetch must be unreachable"); + } + async callUnary(method, payload, signal) { + const request = rpcRequest(payload); + const full = { + type: "client-request", + rpcId: request.rpcId, + method, + payload + }; + this.onEnvelope(full); + const response = await this.dispatch(method, request, signal ?? new AbortController().signal); + const fullResponse = { + type: "server-response", + rpcId: response.rpcId, + result: response.result + }; + this.onEnvelope(fullResponse); + return response; + } + /** Method-key dispatch into the in-memory contract impl (a real carrier routes by URL path instead). */ + dispatch(method, request, signal) { + switch (method) { + case "session.list": return this.api.sessions.list(request); + case "session.search": return this.api.sessions.search(request, signal); + case "session.create": return this.api.sessions.create(request); + case "session.history": return this.api.sessions.history(request); + case "session.models": return this.api.sessions.models(request); + case "session.selectModel": return this.api.sessions.selectModel(request); + case "session.rename": return this.api.sessions.rename(request); + case "session.fork": return this.api.sessions.fork(request); + case "session.prompt": return this.api.sessions.prompt(request); + case "session.attachment": return this.api.sessions.attachment(request); + case "session.updateQueue": return this.api.sessions.updateQueue(request); + case "session.cancel": return this.api.sessions.cancel(request); + case "subagent.list": return this.api.subagents.list(request); + case "subagent.history": return this.api.subagents.history(request); + case "subagent.prompt": return this.api.subagents.prompt(request, signal); + case "subagent.interrupt": return this.api.subagents.interrupt(request); + case "host.describe": return this.api.host.describe(request); + case "host.pickDirectory": return this.api.host.pickDirectory(request, new AbortController().signal); + case "host.listDirectory": return this.api.host.listDirectory(request, new AbortController().signal); + case "host.createDirectory": return this.api.host.createDirectory(request); + case "host.openPath": return this.api.host.openPath(request, new AbortController().signal); + case "workspace.list": return this.api.workspace.list(request); + case "workspace.create": return this.api.workspace.create(request); + case "workspace.rename": return this.api.workspace.rename(request); + case "workspace.delete": return this.api.workspace.delete(request); + case "workspace.insertBefore": return this.api.workspace.insertBefore(request); + case "workspace.insertSessionBefore": return this.api.workspace.insertSessionBefore(request); + case "workspace.archiveSession": return this.api.workspace.archiveSession(request); + case "skill.list": return this.api.skills.list(request); + case "agentPreset.list": return this.api.agentPresets.list(request); + case "agentPreset.select": return this.api.agentPresets.select(request); + case "agentPreset.read": return this.api.agentPresets.read(request); + case "agentPreset.copy": return this.api.agentPresets.copy(request); + case "agentPreset.openDocument": return this.api.agentPresets.openDocument(request, new AbortController().signal); + case "agentPreset.remove": return this.api.agentPresets.remove(request); + case "goal.create": return this.api.goals.create(request); + case "goal.edit": return this.api.goals.edit(request); + case "goal.pause": return this.api.goals.pause(request); + case "goal.resume": return this.api.goals.resume(request); + case "goal.complete": return this.api.goals.complete(request); + case "goal.clear": return this.api.goals.clear(request); + case "settings.describe": return this.api.settings.describe(request); + case "settings.openDocument": return this.api.settings.openDocument(request, signal); + case "settings.update": return this.api.settings.update(request); + case "settings.replace": return this.api.settings.replace(request); + case "settings.mutate": return this.api.settings.mutate(request); + case "credentials.describe": return this.api.credentials.describe(request); + case "credentials.set": return this.api.credentials.set(request); + case "credentials.unset": return this.api.credentials.unset(request); + case "llm.providers": return this.api.llm.providers(request); + case "llm.models": return this.api.llm.models(request); + case "llm.discoverModels": return this.api.llm.discoverModels(request, signal); + } + } + openMux(payload, signal, onOpen) { + return this.tapStream(this.api.events.mux(rpcRequest(payload), signal), onOpen); + } + openHost(payload, signal, onOpen) { + return this.tapStream(this.api.events.host(rpcRequest(payload), signal), onOpen); + } + async *tapStream(stream, onOpen) { + onOpen?.(); + for await (const envelope of stream) { + const full = { + type: "server-request", + rpcId: envelope.rpcId, + method: envelope.payload.type, + payload: envelope.payload + }; + this.onEnvelope(full); + yield envelope; + } + } + /** + * Deliver a client response to the in-memory contract impl (no HTTP POST), + * echoing the envelope to the observation tap like every other path. + * @param message - the client-response envelope answering a server request. + * @returns the carrier receipt from the fixture impl. + */ + async respond(message) { + this.onEnvelope(message); + return this.api.respond(message); + } + }; + /** Browser query mapping; direct unit callers pass FixtureOptions explicitly. */ + function fixtureOptionsFromLocation() { + if (typeof location === "undefined") return {}; + const query = new URLSearchParams(location.search); + return { + empty: query.get("fixture") === "empty", + rejectPrompt: query.get("fixturePrompt") === "reject", + failWorkspaceAttach: query.get("fixtureAttach") === "fail", + dropSessionCreateResponse: query.get("fixtureSessionCreate") === "drop-response", + createFrameOrder: query.get("fixtureFrames") === "workspace-first" ? "workspace-first" : "session-first" + }; + } + //#endregion + //#region lib/types/api-path.js + /** + * The /api URL prefix — single source for both halves of the web transport. + * The node half registers this prefix on the web server; both halves share the + * event paths below for the browser WebSocket downlinks. + */ + /** Route prefix owning every api request (`/api` and `/api/`). */ + const API_PATH = "/api"; + /** Browser mux-frame WebSocket pathname. */ + const MUX_EVENTS_PATH = `${API_PATH}/events.mux`; + /** Browser host-frame WebSocket pathname. */ + const HOST_EVENTS_PATH = `${API_PATH}/events.host`; + //#endregion + //#region lib/types/client/web-api-client.js + /** Browser API carrier: HTTP upstream plus one WebSocket per downstream event stream. */ + /** Browser platform subclass: unary/respond use fetch; mux/host use downlink-only WebSockets. */ + var WebApiClient = class extends AbstractApiClient { + doFetch(input, init) { + return globalThis.fetch(input, init); + } + openMux(_payload, signal, onOpen) { + return this.readWebSocket(MUX_EVENTS_PATH, signal, muxFrameSchema, onOpen); + } + openHost(_payload, signal, onOpen) { + return this.readWebSocket(HOST_EVENTS_PATH, signal, hostFrameSchema, onOpen); + } + async *readWebSocket(path, signal, frameSchema, onOpen) { + const url = new URL(path, this.resolveBase()); + url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; + const socket = new WebSocket(url); + const inbox = []; + let wake; + const enqueue = (item) => { + inbox.push(item); + wake?.(); + wake = void 0; + }; + const handleOpen = () => { + onOpen?.(); + }; + const handleMessage = (event) => { + let full; + let frame; + try { + if (typeof event.data !== "string") throw new Error("binary WebSocket frame"); + full = serverRequestSchema.parse(JSON.parse(event.data)); + frame = frameSchema.parse(full.payload); + } catch (error) { + console.error(`[client-connection] dropping malformed WebSocket frame on ${path}:`, error); + return; + } + this.onEnvelope(full); + enqueue({ + kind: "frame", + envelope: { + rpcId: full.rpcId, + payload: frame + } + }); + }; + const handleClose = () => { + enqueue({ kind: "end" }); + }; + const handleAbort = () => { + if (socket.readyState === WebSocket.CONNECTING || socket.readyState === WebSocket.OPEN) socket.close(); + }; + socket.addEventListener("open", handleOpen); + socket.addEventListener("message", handleMessage); + socket.addEventListener("close", handleClose, { once: true }); + signal.addEventListener("abort", handleAbort, { once: true }); + if (signal.aborted) handleAbort(); + try { + while (true) { + while (inbox.length > 0) { + const item = inbox.shift(); + if (item.kind === "end") return; + yield item.envelope; + } + await new Promise((resolve) => { + wake = resolve; + }); + } + } finally { + signal.removeEventListener("abort", handleAbort); + socket.removeEventListener("open", handleOpen); + socket.removeEventListener("message", handleMessage); + socket.removeEventListener("close", handleClose); + handleAbort(); + } + } + }; + //#endregion + //#region lib/types/client/rpc.js + /** Browser caller for generic Connection unary RPC channels. */ + const INTERNAL_BASE = "http://dsh.internal"; + const CHANNEL_PATTERN = /^\/[A-Za-z0-9._~-]+$/; + const ENDPOINT_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/; + /** + * Create the browser-backed generic RPC caller. + * @returns caller that owns request correlation and response-envelope validation. + */ + function createWebConnectionRpc() { + return { async call(channel, endpoint, payload, signal) { + assertTarget(channel, endpoint); + const rpcId = RpcId(randomUuid()); + const message = { + type: "client-request", + rpcId, + method: endpoint, + payload + }; + const response = await globalThis.fetch(new URL(`${channel}/${endpoint}`, resolveBase()), { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(message), + ...signal === void 0 ? {} : { signal } + }); + if (!response.ok) throw new Error(`transport failure for ${channel}/${endpoint}: HTTP ${response.status}`); + const full = serverResponseSchema.parse(await response.json()); + if (full.rpcId !== rpcId) throw new Error(`rpcId mismatch for ${endpoint}: sent ${rpcId}, got ${full.rpcId}`); + return full.result; + } }; + } + function resolveBase() { + const location = globalThis.location; + return location?.origin !== void 0 && location.origin !== "null" ? location.origin : INTERNAL_BASE; + } + function assertTarget(channel, endpoint) { + const segments = endpoint.split("/"); + if (!CHANNEL_PATTERN.test(channel) || segments.some((segment) => segment === "" || segment === "." || segment === ".." || !ENDPOINT_SEGMENT_PATTERN.test(segment))) throw new Error(`connection: invalid RPC target ${JSON.stringify(`${channel}/${endpoint}`)}`); + } + //#endregion + //#region lib/types/loopback-hostname.js + /** + * Browser-safe, zero-dependency loopback classification shared by the `/api` + * Host fence and the package's `ctx.connection` state. The predicate stays + * package-internal; client plugins consume the derived state through Cordis. + */ + /** + * Whether a normalized URL hostname names the local loopback authority. + * @param hostname - WHATWG URL hostname (IPv6 literals retain brackets). + * @returns true for localhost, IPv6 loopback, or any IPv4 address in 127/8. + */ + function isLoopbackHostname(hostname) { + if (hostname === "localhost" || hostname === "[::1]") return true; + const parts = hostname.split("."); + return parts.length === 4 && parts[0] === "127" && parts.every((part) => /^\d{1,3}$/.test(part) && Number(part) <= 255); + } + //#endregion + //#region lib/types/client/index.js + /** Required services (none — this is the wire root). */ + const inject = []; + /** + * Client plugin body: pick the api by page mode and provide ctx.connection. + * @param ctx - client cordis context. + */ + function apply(ctx) { + const pageLocation = typeof location === "undefined" ? void 0 : location; + const fixtureClient = pageLocation !== void 0 && new URLSearchParams(pageLocation.search).has("fixture") ? new FixtureApiClient() : void 0; + const api = fixtureClient ?? new WebApiClient(); + const rpc = fixtureClient?.rpc ?? createWebConnectionRpc(); + let started = false; + let description; + const descriptionListeners = /* @__PURE__ */ new Set(); + const publishDescription = (next) => { + if (Object.is(description, next)) return; + description = next; + for (const listener of [...descriptionListeners]) try { + listener(); + } catch (error) { + console.error("[web-runtime] host-description listener threw:", error); + } + }; + const handle = { + api, + isLoopback: pageLocation === void 0 || isLoopbackHostname(pageLocation.hostname), + hostDescription: { + getSnapshot: () => description, + subscribe: (listener) => { + descriptionListeners.add(listener); + return () => { + descriptionListeners.delete(listener); + }; + } + }, + rpc, + start(sinks, config) { + if (started) throw new Error("connection: the stream loop is already owned by another consumer"); + started = true; + const controller = new ConnectionController(api, { + ...sinks, + onConnected: (next) => { + publishDescription(next); + if (!Object.is(description, next)) return; + sinks.onConnected?.(next); + }, + onStateChange: (state) => { + if (state === "reconnecting") publishDescription(void 0); + sinks.onStateChange?.(state); + } + }, config ?? {}); + controller.start(); + return { stop: () => { + controller.stop(); + publishDescription(void 0); + } }; + } + }; + ctx.provide("connection", handle); + } + //#endregion + exports.AbstractApiClient = AbstractApiClient; + exports.RpcId = RpcId; + exports.apply = apply; + exports.inject = inject; + exports.transportError = transportError; + return module.exports; + } +}); + +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/index.js new file mode 100644 index 0000000..acf1cde --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/index.js @@ -0,0 +1,588 @@ +import z from "@deepseek-ai/schemastery"; +import { toFetchHandler } from "@deepseek-ai/dsh-host-apiproxy"; +import { Service } from "@deepseek-ai/cordis"; +import { RpcId, clientRequestSchema } from "@deepseek-ai/dsh-host-apiproxy/api"; +import { randomUUID } from "node:crypto"; +import WebSocket, { WebSocketServer } from "ws"; +//#region lib/types/api-path.js +/** +* The /api URL prefix — single source for both halves of the web transport. +* The node half registers this prefix on the web server; both halves share the +* event paths below for the browser WebSocket downlinks. +*/ +/** Route prefix owning every api request (`/api` and `/api/`). */ +const API_PATH = "/api"; +/** Browser mux-frame WebSocket pathname. */ +const MUX_EVENTS_PATH = `${API_PATH}/events.mux`; +/** Browser host-frame WebSocket pathname. */ +const HOST_EVENTS_PATH = `${API_PATH}/events.host`; +//#endregion +//#region lib/types/http-bridge.js +/** +* node:http ↔ WHATWG fetch bridge for the /api transport (host side of the +* web carrier; the fetch-shaped handler itself is transport-agnostic). +*/ +/** Default carrier cap for all HTTP RPC bodies: sized for the default +* aggregate image limit (100 MiB) after base64 expansion plus envelope +* headroom (~134.3 MiB required), rounded up for slack. The bridge buffers +* each body in memory, so this cap is also the per-request resident bound. */ +const DEFAULT_MAX_REQUEST_BODY_BYTES = 160 * 1024 * 1024; +/** +* Bridge one node:http request to the fetch-shaped handler (client close +* aborts; SSE bodies stream out chunk by chunk). +* @param req - incoming node:http request (fully read before dispatch). +* @param res - node:http response the bridge writes and owns to completion. +* @param apiHandler - fetch-shaped API carrier the request is dispatched to. +* @param maxRequestBodyBytes - maximum body bytes buffered before dispatch. +*/ +async function bridge(req, res, apiHandler, maxRequestBodyBytes = DEFAULT_MAX_REQUEST_BODY_BYTES) { + const abort = new AbortController(); + res.on("close", () => { + if (!res.writableEnded) abort.abort(); + }); + const declaredLength = req.headers["content-length"]; + if (declaredLength !== void 0 && Number(declaredLength) > maxRequestBodyBytes) { + res.writeHead(413, { connection: "close" }); + res.end(); + req.destroy(); + return; + } + const chunks = []; + let received = 0; + for await (const chunk of req) { + const buffer = chunk; + received += buffer.byteLength; + if (received > maxRequestBodyBytes) { + res.writeHead(413, { connection: "close" }); + res.end(); + req.destroy(); + return; + } + chunks.push(buffer); + } + /* v8 ignore next 3 -- `??` arms: node:http always sets url/method on server + requests; the fields are only optional on the client-side IncomingMessage type */ + const request = new Request(new URL(req.url ?? "/", "http://dsh.internal"), { + method: req.method ?? "GET", + headers: Object.fromEntries(Object.entries(req.headers).filter(([, v]) => typeof v === "string")), + ...chunks.length > 0 ? { body: Buffer.concat(chunks) } : {}, + signal: abort.signal + }); + const response = await apiHandler.fetch(request); + res.writeHead(response.status, Object.fromEntries(response.headers.entries())); + if (response.body === null) { + res.end(); + return; + } + for await (const chunk of response.body) if (!res.write(chunk)) await new Promise((resolve) => { + const done = () => { + res.off("drain", done); + res.off("close", done); + resolve(); + }; + res.once("drain", done); + res.once("close", done); + }); + res.end(); +} +//#endregion +//#region lib/types/loopback-hostname.js +/** +* Browser-safe, zero-dependency loopback classification shared by the `/api` +* Host fence and the package's `ctx.connection` state. The predicate stays +* package-internal; client plugins consume the derived state through Cordis. +*/ +/** +* Whether a normalized URL hostname names the local loopback authority. +* @param hostname - WHATWG URL hostname (IPv6 literals retain brackets). +* @returns true for localhost, IPv6 loopback, or any IPv4 address in 127/8. +*/ +function isLoopbackHostname(hostname) { + if (hostname === "localhost" || hostname === "[::1]") return true; + const parts = hostname.split("."); + return parts.length === 4 && parts[0] === "127" && parts.every((part) => /^\d{1,3}$/.test(part) && Number(part) <= 255); +} +//#endregion +//#region lib/types/api-request-trust.js +/** +* Browser-trust fence for every /api request. Defends the two confused-deputy +* paths a browser opens against a local HTTP API — DNS rebinding (Host names +* the attacker's domain while the socket reaches this server) and cross-site +* requests fired from a malicious page. The Host fence binds every request, +* browser-looking or not: over plain HTTP a browser attaches neither Origin +* nor Fetch-Metadata to reads (images and navigations — those +* headers go only to trustworthy destinations), so an unmarked request may +* still be a rebound browser read and Host is the one header rebinding cannot +* forge. Non-browser and remote clients pass the same fence via loopback, +* deployment-derived LAN IP literals, or a declared `trustedHosts` authority. +* Network reachability and authentication stay out of scope: binding policy +* belongs to the webserver config, and this fence is not an auth layer. +*/ +function header(headers, name) { + if (headers instanceof Headers) return headers.get(name) ?? void 0; + const value = headers[name]; + return typeof value === "string" ? value : void 0; +} +/** Normalized URL of a Host-header authority (hostname lowercased, default port stripped, IPv6 bracketed), or undefined when unparsable. */ +function parseAuthority(authority) { + try { + return new URL(`http://${authority}`); + } catch { + return; + } +} +/** +* Assert one configured `trustedHosts` entry is a bare authority (`host` or +* `host:port`) in canonical form: it must survive WHATWG parsing unchanged +* (case aside). Anything parsing would silently rewrite is refused as a typo +* that must fail the load loudly instead of being ignored until requests 403 +* or quietly changing the grant: URL parts beyond the authority +* (`harness.internal/path`, `user@harness.internal` — which would authorize +* the embedded hostname), stripped whitespace, a dangling colon or +* zero-padded port (which would broaden an intended exact-port grant to every +* port), and non-canonical host spellings (`0x7f.0.0.1`, percent-encoding, +* unbracketed IPv6; IDN hosts are declared in punycode, the form the wire +* carries). +* @param entry - the configured value, verbatim. +*/ +function assertTrustedAuthority(entry) { + const entryUrl = parseAuthority(entry); + if (entryUrl !== void 0 && canonicalAuthority(entry, entryUrl) === entry.toLowerCase()) return; + throw new Error(`client-connection: trustedHosts entry ${JSON.stringify(entry)} is not a bare host[:port] authority`); +} +/** +* Canonical form of a parsed authority: `hostname` when no port was written, +* else `hostname:port`. The port is judged from URL parses under both special +* schemes (their default ports differ, so `:80` and `:443` still count as +* explicit), never from the raw string, where WHATWG trimming would misread +* shapes like `host:port ` as port-less. +*/ +function canonicalAuthority(entry, entryUrl) { + const port = entryUrl.port !== "" ? entryUrl.port : new URL(`https://${entry}`).port; + return port === "" ? entryUrl.hostname : `${entryUrl.hostname}:${port}`; +} +/** +* Whether the request authority matches a `trustedHosts` entry. An entry with +* an explicit port matches that exact authority; a port-less entry matches the +* hostname on any port (the shape the CLI derives for IP-literal LAN serving, +* where the bound port may be OS-assigned). Both sides compare through WHATWG +* normalization, so case and a redundant `:80` never decide trust. +*/ +function isTrustedAuthority(hostUrl, trustedHosts) { + return trustedHosts.some((entry) => { + const entryUrl = parseAuthority(entry); + if (entryUrl === void 0) return false; + return canonicalAuthority(entry, entryUrl) === entryUrl.hostname ? entryUrl.hostname === hostUrl.hostname : entryUrl.host === hostUrl.host; + }); +} +/** +* Decide whether one /api request may reach the RPC bridge. +* @param request - Node HTTP or Fetch request facts (headers). +* @param trustedHosts - non-loopback authorities this deployment serves: exact `host:port`, or port-less `host` matching any port. +* @returns true when the Host is ours (loopback or trusted) and any attached browser markers are same-origin. +*/ +function isTrustedApiRequest(request, trustedHosts) { + const host = header(request.headers, "host"); + if (host === void 0) return false; + const hostUrl = parseAuthority(host); + if (hostUrl === void 0) return false; + if (!isLoopbackHostname(hostUrl.hostname) && !isTrustedAuthority(hostUrl, trustedHosts)) return false; + if (header(request.headers, "sec-fetch-site") === "cross-site") return false; + const origin = header(request.headers, "origin"); + if (origin === void 0) return true; + try { + return new URL(origin).host === hostUrl.host; + } catch { + return false; + } +} +//#endregion +//#region lib/types/rpc-host.js +/** Host registry and HTTP adapter for generic Connection RPC channels. */ +const INVALID_REQUEST_RPC_ID = RpcId("invalid-request"); +const CHANNEL_PATTERN = /^\/[A-Za-z0-9._~-]+$/; +const ENDPOINT_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/; +/** Host Connection service whose channel registrations belong to the caller fiber. */ +var HostConnectionService = class extends Service { + trustedHosts; + interceptors = /* @__PURE__ */ new Map(); + /** + * Provide the Host half over the active HTTP server. + * @param ctx - owning Connection plugin context. + * @param trustedHosts - deployment authorities accepted by trusted-host channels. + */ + constructor(ctx, trustedHosts) { + super(ctx, "connection"); + this.trustedHosts = trustedHosts; + } + /** Generic channel registry scoped to the Context reading this service. */ + get rpc() { + const owner = this.ctx; + return { + handle: (channel, handler, options) => this.register(owner, channel, handler, options), + intercept: (channel, matches, handler, options) => this.registerInterceptor(owner, channel, matches, handler, options) + }; + } + /** + * Compose one shared-channel Fetch handler from its interceptor and fallback. + * @param channel - shared channel mounted by Connection. + * @param fallback - handler for endpoints not claimed by the interceptor. + * @returns Fetch handler that selects exactly one target for each request. + */ + createSharedFetchHandler(channel, fallback) { + return { fetch: (request) => { + const endpoint = endpointFromPath(channel, new URL(request.url).pathname); + const interceptor = this.interceptors.get(channel); + if (endpoint === void 0 || interceptor === void 0 || !interceptor.matches(endpoint)) return fallback.fetch(request); + if (interceptor.options.authority === "loopback" && !isTrustedApiRequest(request, [])) return Promise.resolve(new Response("forbidden", { status: 403 })); + return interceptor.fetchHandler.fetch(request); + } }; + } + register(owner, channel, handler, options) { + assertChannel(channel); + const trustedHosts = options.authority === "loopback" ? [] : this.trustedHosts; + const fetchHandler = rpcFetchHandler(channel, handler); + const route = { + kind: "prefix", + path: channel, + handler: async (req, res) => { + if (!isTrustedApiRequest(req, trustedHosts)) { + res.writeHead(403); + res.end("forbidden"); + return; + } + await bridge(req, res, fetchHandler); + } + }; + return owner.effect(() => owner.webServer.register(route), `client-connection: ${channel} rpc channel`); + } + registerInterceptor(owner, channel, matches, handler, options) { + if (channel !== "/api") throw new Error(`connection: invalid shared RPC channel ${JSON.stringify(channel)}`); + const interceptor = { + matches, + fetchHandler: rpcFetchHandler(channel, handler), + options + }; + return owner.effect(() => { + if (this.interceptors.has(channel)) throw new Error(`connection: shared RPC channel ${JSON.stringify(channel)} already has an interceptor`); + this.interceptors.set(channel, interceptor); + return () => { + this.interceptors.delete(channel); + }; + }, `client-connection: ${channel} rpc interceptor`); + } +}; +function rpcFetchHandler(channel, handler) { + return { async fetch(request) { + const endpoint = endpointFromPath(channel, new URL(request.url).pathname); + if (request.method !== "POST" || endpoint === void 0) return new Response("not found", { status: 404 }); + if (request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() !== "application/json") return new Response("content type must be application/json", { status: 415 }); + let body; + try { + body = await request.json(); + } catch { + return new Response("body is not JSON", { status: 400 }); + } + const envelope = clientRequestSchema.safeParse(body); + if (!envelope.success) return invalidEnvelopeResponse(body, envelope.error.issues); + const message = envelope.data; + if (message.method !== endpoint) return errorResponse(message.rpcId, { + code: "bad-request", + message: `method ${JSON.stringify(message.method)} does not match endpoint ${JSON.stringify(endpoint)}`, + details: { issues: [] } + }); + try { + const result = await handler(endpoint, message.payload, request.signal); + return fullResponse(message.rpcId, result); + } catch (error) { + return new Response(`handler failure: ${String(error)}`, { status: 500 }); + } + } }; +} +function invalidEnvelopeResponse(body, issues) { + const rawId = body?.rpcId; + return errorResponse(typeof rawId === "string" ? RpcId(rawId) : INVALID_REQUEST_RPC_ID, { + code: "bad-request", + message: "invalid client-request message", + details: { issues } + }); +} +function endpointFromPath(channel, pathname) { + if (!pathname.startsWith(`${channel}/`)) return void 0; + const endpoint = pathname.slice(channel.length + 1); + if (endpoint.split("/").some((segment) => segment === "" || segment === "." || segment === ".." || !ENDPOINT_SEGMENT_PATTERN.test(segment))) return; + return endpoint; +} +function errorResponse(rpcId, error) { + return fullResponse(rpcId, { + ok: false, + error + }); +} +function fullResponse(rpcId, result) { + const body = { + type: "server-response", + rpcId, + result + }; + return Response.json(body); +} +function assertChannel(channel) { + if (!CHANNEL_PATTERN.test(channel) || channel === "/api") throw new Error(`connection: invalid or reserved RPC channel ${JSON.stringify(channel)}`); +} +//#endregion +//#region lib/types/websocket-downlink.js +/** Host-side WebSocket carrier for the two server-to-browser event streams. */ +function serverRequest(frame) { + return { + type: "server-request", + rpcId: frame.rpcId, + method: frame.payload.type, + payload: frame.payload + }; +} +function send(socket, frame) { + return new Promise((resolve, reject) => { + if (socket.readyState !== WebSocket.OPEN) { + reject(/* @__PURE__ */ new Error("websocket downlink closed before frame delivery")); + return; + } + socket.send(JSON.stringify(serverRequest(frame)), (error) => { + if (error) reject(error); + else resolve(); + }); + }); +} +function failureFrame(error) { + return { + rpcId: RpcId(randomUUID()), + payload: { + type: "stream/error", + error: { + code: "internal", + message: String(error), + details: {} + } + } + }; +} +/** +* Owns WebSocket negotiation and frame pumping for the connection plugin's +* two downlinks. Client messages are a protocol violation: upstream traffic +* remains on HTTP. +*/ +var WebSocketDownlinks = class { + api; + server = new WebSocketServer({ noServer: true }); + pumps = /* @__PURE__ */ new Set(); + /** @param api - host API supplying the typed event streams. */ + constructor(api) { + this.api = api; + } + /** + * Upgrade one socket and pump the mux stream until either side closes. + * @param req - HTTP upgrade request. + * @param socket - Raw socket transferred by the HTTP server. + * @param head - Bytes already read after the upgrade headers. + */ + handleMux(req, socket, head) { + this.upgrade(req, socket, head, (signal) => this.api.events.mux({ + rpcId: RpcId(randomUUID()), + payload: {} + }, signal)); + } + /** + * Upgrade one socket and pump the host stream until either side closes. + * @param req - HTTP upgrade request. + * @param socket - Raw socket transferred by the HTTP server. + * @param head - Bytes already read after the upgrade headers. + */ + handleHost(req, socket, head) { + this.upgrade(req, socket, head, (signal) => this.api.events.host({ + rpcId: RpcId(randomUUID()), + payload: {} + }, signal)); + } + /** + * Terminate owned sockets and await the no-server acceptor plus frame pumps. + * @returns A promise resolving after every socket and source iterator stops. + */ + async close() { + for (const socket of this.server.clients) socket.terminate(); + await new Promise((resolve, reject) => { + this.server.close((error) => { + if (error === void 0) resolve(); + else reject(error); + }); + }); + await Promise.all(this.pumps); + } + upgrade(req, socket, head, open) { + this.server.handleUpgrade(req, socket, head, (websocket) => { + const abort = new AbortController(); + websocket.once("close", () => { + abort.abort(); + }); + websocket.once("error", () => { + abort.abort(); + }); + websocket.once("message", () => { + websocket.close(1008, "downlink only"); + }); + const pump = this.pump(websocket, open(abort.signal), abort); + this.pumps.add(pump); + pump.then(() => { + this.pumps.delete(pump); + }); + }); + } + async pump(socket, frames, abort) { + try { + for await (const frame of frames) await send(socket, frame); + } catch (error) { + if (!abort.signal.aborted) try { + await send(socket, failureFrame(error)); + } catch {} + } finally { + abort.abort(); + if (socket.readyState === WebSocket.OPEN) socket.close(); + } + } +}; +/** +* Reject an untrusted upgrade before protocol negotiation. +* @param socket - Raw HTTP socket that remains owned by the caller. +*/ +function rejectWebSocketUpgrade(socket) { + socket.end([ + "HTTP/1.1 403 Forbidden", + "Connection: close", + "Content-Type: text/plain; charset=utf-8", + "Content-Length: 9", + "", + "forbidden" + ].join("\r\n")); +} +//#endregion +//#region lib/types/index.js +/** Stable Cordis plugin name. */ +const name = "client-connection"; +/** Headroom for RPC JSON fields around aggregate base64 image payloads. */ +const REQUEST_ENVELOPE_HEADROOM_BYTES = 1024 * 1024; +function assertImageBodyCapacity(ctx, maxRequestBodyBytes) { + const attachments = ctx.get("attachments"); + if (attachments === void 0) return; + const requiredImageBodyBytes = Math.ceil(attachments.imageLimits.maxMessageImageBytes * 4 / 3) + REQUEST_ENVELOPE_HEADROOM_BYTES; + if (maxRequestBodyBytes < requiredImageBodyBytes) throw new Error(`client-connection maxRequestBodyBytes (${String(maxRequestBodyBytes)}) must be at least ${String(requiredImageBodyBytes)} for the configured aggregate image limit`); +} +/** Services required before providing Connection; API Proxy is an optional `/api` fallback. */ +const inject = ["webServer"]; +const Config = z.object({ + trustedHosts: z.array(String).default([]), + maxRequestBodyBytes: z.natural().min(1).default(DEFAULT_MAX_REQUEST_BODY_BYTES) +}); +/** +* Methods gated to loopback even on a trusted-host deployment. Native dialogs +* act on the host machine; the settings and credential domains mutate the +* user's configuration and secret store, and READING them is equally +* privileged — `settings.describe` returns every exposed namespace's +* configuration and `credentials.describe` reports whether an arbitrary +* environment-variable name is configured and where from, which is +* reconnaissance no anonymous caller should have. `trustedHosts` is a +* DNS-rebinding fence, explicitly not authentication, so the whole +* configuration plane stays loopback-same-origin until a real authentication +* layer exists. `llm.discoverModels` belongs to that plane on both counts: it +* carries a draft credential, and it makes the HOST issue a GET to a URL the +* caller chose and reports back the status or the parsed body — an anonymous +* LAN caller would have a probe for whatever the host can reach and the +* browser cannot. +* +* The model catalog (`llm.providers`, `llm.models`) is deliberately NOT here: +* it carries provider ids, display names, and model lists — no endpoints, +* keys, or key state — and a LAN client's model picker legitimately needs it. +*/ +const PRIVILEGED_METHODS = new Set([ + "agentPreset.read", + "agentPreset.copy", + "agentPreset.openDocument", + "agentPreset.remove", + "host.pickDirectory", + "host.openPath", + "settings.describe", + "settings.openDocument", + "settings.update", + "settings.replace", + "settings.mutate", + "credentials.describe", + "credentials.set", + "credentials.unset", + "llm.discoverModels" +]); +/** +* Mounts the API gateway under the browser transport prefix. Every request on +* the prefix passes the browser-trust fence first (DNS-rebinding and +* cross-site defense — [api-request-trust](./api-request-trust.ts)); +* privileged methods additionally pass it with an empty trust list, which +* pins them to loopback. +* @param ctx - Host plugin context. +* @param config - resolved plugin config (schema defaults applied). +*/ +function apply(ctx, config) { + const trustedHosts = config?.trustedHosts ?? []; + const maxRequestBodyBytes = config?.maxRequestBodyBytes ?? 167772160; + for (const entry of trustedHosts) assertTrustedAuthority(entry); + if (ctx.get("apiProxy") !== void 0) assertImageBodyCapacity(ctx, maxRequestBodyBytes); + const fetchHandler = new HostConnectionService(ctx, trustedHosts).createSharedFetchHandler(API_PATH, { async fetch(request) { + const pathname = new URL(request.url).pathname; + const method = pathname.startsWith(`/api/`) ? pathname.slice(5) : void 0; + if (method !== void 0 && PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, [])) return new Response("forbidden", { status: 403 }); + if (request.method === "GET" && (pathname === MUX_EVENTS_PATH || pathname === HOST_EVENTS_PATH)) return new Response("upgrade required", { + status: 426, + headers: { + connection: "Upgrade", + upgrade: "websocket" + } + }); + const apiProxy = ctx.get("apiProxy"); + if (apiProxy === void 0) return new Response("not found", { status: 404 }); + return toFetchHandler(apiProxy).fetch(request); + } }); + const route = { + kind: "prefix", + path: API_PATH, + handler: async (req, res) => { + if (!isTrustedApiRequest(req, trustedHosts)) { + res.writeHead(403); + res.end("forbidden"); + return; + } + await bridge(req, res, fetchHandler, maxRequestBodyBytes); + } + }; + ctx.effect(() => ctx.webServer.register(route), "client-connection: /api route"); + ctx.inject(["apiProxy"], (apiCtx) => { + assertImageBodyCapacity(apiCtx, maxRequestBodyBytes); + const downlinks = new WebSocketDownlinks(apiCtx.apiProxy); + const registerDownlink = (path, handle) => { + apiCtx.effect(() => apiCtx.webServer.registerUpgrade({ + path, + handler: (req, socket, head) => { + if (!isTrustedApiRequest(req, trustedHosts)) { + rejectWebSocketUpgrade(socket); + return; + } + return handle(req, socket, head); + } + }), `client-connection: ${path} WebSocket`); + }; + apiCtx.effect(() => () => downlinks.close(), "client-connection: WebSocket downlinks"); + registerDownlink(MUX_EVENTS_PATH, (req, socket, head) => { + downlinks.handleMux(req, socket, head); + }); + registerDownlink(HOST_EVENTS_PATH, (req, socket, head) => { + downlinks.handleHost(req, socket, head); + }); + }); +} +//#endregion +export { API_PATH, Config, HOST_EVENTS_PATH, HostConnectionService, MUX_EVENTS_PATH, apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/invariant.js new file mode 100644 index 0000000..74291ab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/invariant.js @@ -0,0 +1,26 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-client-connection`. +* @module @deepseek-ai/dsh-client-connection/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-client-connection"; +/** Cordis companion plugin name. */ +const name = "client-connection-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the wire layer emits no cordis events and owns no +* mutable cross-plugin relation — stream/reconnect sequencing is exercised +* directly by its behavior specs, rpcId round-trip discipline is owned by the +* apiproxy contract layer, and the node half's single route registration's +* register/dispose symmetry is audited by the webserver package's invariant. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-path.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-path.d.ts new file mode 100644 index 0000000..6e5b34c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-path.d.ts @@ -0,0 +1,12 @@ +/** + * The /api URL prefix — single source for both halves of the web transport. + * The node half registers this prefix on the web server; both halves share the + * event paths below for the browser WebSocket downlinks. + */ +/** Route prefix owning every api request (`/api` and `/api/`). */ +export declare const API_PATH = "/api"; +/** Browser mux-frame WebSocket pathname. */ +export declare const MUX_EVENTS_PATH = "/api/events.mux"; +/** Browser host-frame WebSocket pathname. */ +export declare const HOST_EVENTS_PATH = "/api/events.host"; +//# sourceMappingURL=api-path.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-request-trust.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-request-trust.d.ts new file mode 100644 index 0000000..6836179 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/api-request-trust.d.ts @@ -0,0 +1,43 @@ +/** + * Browser-trust fence for every /api request. Defends the two confused-deputy + * paths a browser opens against a local HTTP API — DNS rebinding (Host names + * the attacker's domain while the socket reaches this server) and cross-site + * requests fired from a malicious page. The Host fence binds every request, + * browser-looking or not: over plain HTTP a browser attaches neither Origin + * nor Fetch-Metadata to reads (images and navigations — those + * headers go only to trustworthy destinations), so an unmarked request may + * still be a rebound browser read and Host is the one header rebinding cannot + * forge. Non-browser and remote clients pass the same fence via loopback, + * deployment-derived LAN IP literals, or a declared `trustedHosts` authority. + * Network reachability and authentication stay out of scope: binding policy + * belongs to the webserver config, and this fence is not an auth layer. + */ +import type { IncomingHttpHeaders } from 'node:http'; +/** The request facts the fence reads from either HTTP representation. */ +interface ApiTrustRequest { + headers: IncomingHttpHeaders | Headers; +} +/** + * Assert one configured `trustedHosts` entry is a bare authority (`host` or + * `host:port`) in canonical form: it must survive WHATWG parsing unchanged + * (case aside). Anything parsing would silently rewrite is refused as a typo + * that must fail the load loudly instead of being ignored until requests 403 + * or quietly changing the grant: URL parts beyond the authority + * (`harness.internal/path`, `user@harness.internal` — which would authorize + * the embedded hostname), stripped whitespace, a dangling colon or + * zero-padded port (which would broaden an intended exact-port grant to every + * port), and non-canonical host spellings (`0x7f.0.0.1`, percent-encoding, + * unbracketed IPv6; IDN hosts are declared in punycode, the form the wire + * carries). + * @param entry - the configured value, verbatim. + */ +export declare function assertTrustedAuthority(entry: string): void; +/** + * Decide whether one /api request may reach the RPC bridge. + * @param request - Node HTTP or Fetch request facts (headers). + * @param trustedHosts - non-loopback authorities this deployment serves: exact `host:port`, or port-less `host` matching any port. + * @returns true when the Host is ours (loopback or trusted) and any attached browser markers are same-origin. + */ +export declare function isTrustedApiRequest(request: ApiTrustRequest, trustedHosts: readonly string[]): boolean; +export {}; +//# sourceMappingURL=api-request-trust.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/api.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/api.d.ts new file mode 100644 index 0000000..1102985 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/api.d.ts @@ -0,0 +1,20 @@ +export type { ApiProxy, SessionsApi, SessionSearchItem, SessionSummary, PromptContentPart, HostApi, EventsApi, MuxFrame, HostFrame, ApprovalResponsePayload, QuestionResponsePayload, HistoryEntry, ToolEventView, DirectoryEntry, DirectoryListing, ResponseValue, WorkspaceApi, WorkspaceId, WorkspaceView, SkillsApi, SkillEntry, ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning, ModelReasoningEffort, ModelSelection, QueueAction, QueuedInboxItem, SessionModels, GoalsApi, GoalRef, SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView, CredentialsApi, CredentialView, ConfigurableProviderView, DiscoveredModelView, LlmApi, SubagentsApi, SubagentAddress, SubagentCatalog, SubagentListEntry, SubagentPromptReceipt, JobView, } from '@deepseek-ai/dsh-host-apiproxy/api'; +export type { ToolCallView, ToolResultView } from '@deepseek-ai/dsh-tools/presentation'; +export type { RpcRequest, RpcResponse, RpcResult, RpcError, RpcErrorCode, ClientRequest, ServerResponse, ServerRequest, ClientResponse, RpcMessage, RpcReceipt, } from '@deepseek-ai/dsh-host-apiproxy/api'; +export { RpcId, SESSION_SEARCH_RESULT_LIMIT, transportError, } from '@deepseek-ai/dsh-host-apiproxy/api'; +export { AbstractApiClient } from '@deepseek-ai/dsh-host-apiproxy/client'; +export type { IApiClient } from '@deepseek-ai/dsh-host-apiproxy/client'; +export type { SessionId, SessionEvent } from '@deepseek-ai/dsh-session/types'; +export type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +export type { ContentBlock, StreamChunk } from '@deepseek-ai/dsh-llm/types'; +/** Successful value returned by the connection-generation host handshake. */ +export type HostDescription = import('@deepseek-ai/dsh-host-apiproxy/api').ResponseValue<'host.describe'>; +import type { RpcResponse, RpcResult } from '@deepseek-ai/dsh-host-apiproxy/api'; +/** + * Unwrap a unary response: RpcResponse -> RpcResult (business code only + * cares about the result slot). + * @param response - the unary response. + * @returns its result slot. + */ +export declare function resultOf(response: RpcResponse): RpcResult; +//# sourceMappingURL=api.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/connection.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/connection.d.ts new file mode 100644 index 0000000..b6ae466 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/connection.d.ts @@ -0,0 +1,64 @@ +import type { HostDescription, IApiClient, HostFrame, MuxFrame, RpcRequest } from './api.ts'; +/** Reconnect/backoff tunables (deployment-varying — no hardcoded tunables; these become the + * future `ctx.connection` plugin's Config). All fields optional; defaults below. */ +export interface ConnectionConfig { + /** First-retry backoff cap in ms (jittered: actual delay is cap/2..cap). */ + backoffBaseMs?: number; + /** Exponential growth factor per consecutive failed attempt. */ + backoffFactor?: number; + /** Upper bound for the backoff cap in ms. */ + backoffMaxMs?: number; + /** Cap on waiting for both streams' onOpen before onConnected, in ms. The strict handshake + * waits for mux+host stream establishment plus describe; a carrier that never + * fires onOpen (misbehaving proxy) must not wedge the connection forever — on timeout the + * generation proceeds as connected and the live-gap repair path covers stragglers. */ + streamOpenTimeoutMs?: number; +} +/** Coarse connection state for the UI: 'connected' after each generation's handshake, + * 'reconnecting' the moment the generation fails (covers the whole backoff+retry span). */ +export type ConnectionState = 'connected' | 'reconnecting'; +/** Frame sink callbacks: the Controller owns the physical streams; business dispatch belongs to + * SessionManager. */ +export interface ConnectionSinks { + onMuxEnvelope?: (envelope: RpcRequest) => void; + onHostEnvelope?: (envelope: RpcRequest) => void; + /** After each connection generation is established (both streams open + describe succeeded), first connect included. */ + onConnected?: (description: HostDescription) => void; + /** Coarse state transitions (deduplicated: fires only on change). The initial pre-connect + * span reports nothing — the UI treats "no state yet" as connecting, not as an outage. */ + onStateChange?: (state: ConnectionState) => void; +} +/** + * Opens both streams and keeps iterating (pull mode: nothing reads the socket and the tap + * never fires unless someone for-awaits), reconnecting with exponential backoff on loss. + * State (generation/attempt) is instance-private, never in the store. + * The pump body feeds each frame to a sink (sink exceptions must + * not kill the pump — a broken business layer must not drag down the connection layer). + */ +export declare class ConnectionController { + private readonly api; + private readonly sinks; + private generation; + private attempt; + private current; + private running; + private lastState; + private readonly config; + constructor(api: IApiClient, sinks?: ConnectionSinks, config?: ConnectionConfig); + /** Idempotent: begin the connect/pump/reconnect loop. */ + start(): void; + /** Stop the loop and abort the current generation's streams. */ + stop(): void; + private backoffDelay; + /** Read through a method: stop() flips the flag across awaits, so narrowing from the loop condition must not stick. */ + private isRunning; + /** Re-read both mutable liveness guards after a potentially reentrant sink. */ + private isGenerationActive; + private loop; + /** Deduplicated state emission (sink isolation applies). */ + private emitState; + private pumpStream; + /** Sink exception isolation: a business-layer throw is logged only, never affecting pump or reconnect semantics. */ + private callSink; +} +//# sourceMappingURL=connection.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/fixture.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/fixture.d.ts new file mode 100644 index 0000000..6ff192d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/fixture.d.ts @@ -0,0 +1,68 @@ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { ApiProxy, ClientResponse, HostFrame, MuxFrame, RpcReceipt, RpcRequest, RpcResponse } from './api.ts'; +import type { RequestPayload, ResponseValue, RpcMethodMap } from '@deepseek-ai/dsh-host-apiproxy/api'; +import { AbstractApiClient } from './api.ts'; +import type { ClientConnectionRpc } from '../rpc.ts'; +/** Deterministic fixture branches used by keyless Web assembly tests. */ +export interface FixtureOptions { + /** Start with no real Workspace or Session. */ + empty?: boolean; + /** Reject every prompt before appending its user event. */ + rejectPrompt?: boolean; + /** Publish the Session but fail its Workspace account write. */ + failWorkspaceAttach?: boolean; + /** Publish and frame the Session, then throw instead of returning create. */ + dropSessionCreateResponse?: boolean; + /** Order of the two successful create frames. */ + createFrameOrder?: 'session-first' | 'workspace-first'; +} +/** + * In-memory fake host: fx-alpha carries history and replay scripts; fx-beta is fx-alpha's child session (lineage indent material). + * @param options - fixture branches for empty state and failure timing. + * @returns an ApiProxy backed entirely by in-memory state — no host process, no network. + */ +export declare function createFixtureApi(options?: FixtureOptions): ApiProxy; +/** Both fixture faces over one state graph. */ +export interface FixtureWorld { + /** Legacy unary/stream API the fixture still answers. */ + readonly api: ApiProxy; + /** Generic Remote caller for the endpoints business services own. */ + readonly rpc: ClientConnectionRpc; +} +/** + * Build both fixture faces so a caller can drive the Remote endpoints and the + * legacy API against one in-memory state graph. + * @param options - fixture branches for empty state and failure timing. + * @returns the legacy API face and the Remote RPC face. + */ +export declare function createFixtureFaces(options?: FixtureOptions): FixtureWorld; +/** + * Fixture platform subclass: there is no HTTP at all, so instead of a doFetch transport it + * overrides the protocol-level virtuals (callUnary/openMux/openHost/respond) to dispatch + * straight into the in-memory ApiProxy — while still minting rpcIds, fabricating the four + * named full forms, and feeding the same tap as a real carrier. TODO: delete when the fixture + * moves to the isomorphic pipeline (InProcessApiClient over toFetchHandler(fixtureImpl)). + */ +export declare class FixtureApiClient extends AbstractApiClient { + private readonly api; + /** Generic Remote caller backed by the same in-memory state as the legacy fixture API. */ + readonly rpc: ClientConnectionRpc; + constructor(); + protected doFetch(): Promise; + protected callUnary(method: K, payload: RequestPayload, signal?: AbortSignal): Promise>>; + /** Method-key dispatch into the in-memory contract impl (a real carrier routes by URL path instead). */ + private dispatch; + protected openMux(payload: { + since?: Record; + }, signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + protected openHost(payload: Record, signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + private tapStream; + /** + * Deliver a client response to the in-memory contract impl (no HTTP POST), + * echoing the envelope to the observation tap like every other path. + * @param message - the client-response envelope answering a server request. + * @returns the carrier receipt from the fixture impl. + */ + respond(message: ClientResponse): Promise; +} +//# sourceMappingURL=fixture.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/index.d.ts new file mode 100644 index 0000000..66def88 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/index.d.ts @@ -0,0 +1,54 @@ +/** + * Browser wire client. The plugin selects fixture or HTTP transport, provides + * the shared API client, and lets the runtime object layer start the stream + * controller with its sinks. + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { HostDescription, IApiClient } from './api.ts'; +import { type ConnectionConfig, type ConnectionSinks, type ConnectionState } from './connection.ts'; +import type { ClientConnectionRpc } from '../rpc.ts'; +export type { ApiProxy, SessionsApi, SessionSearchItem, SessionSummary, PromptContentPart, HostApi, EventsApi, MuxFrame, HostFrame, ApprovalResponsePayload, QuestionResponsePayload, HistoryEntry, ToolEventView, DirectoryEntry, DirectoryListing, ToolCallView, ToolResultView, WorkspaceApi, WorkspaceId, WorkspaceView, SkillsApi, SkillEntry, ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning, MessageId, ModelReasoningEffort, ModelSelection, QueueAction, QueuedInboxItem, SessionModels, SubagentsApi, SubagentAddress, SubagentCatalog, SubagentListEntry, SubagentPromptReceipt, JobView, RpcRequest, RpcResponse, RpcResult, RpcError, RpcErrorCode, ClientRequest, ServerResponse, ServerRequest, ClientResponse, RpcMessage, RpcReceipt, HostDescription, IApiClient, SessionId, SessionEvent, ContentBlock, StreamChunk, GoalsApi, GoalRef, SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView, CredentialsApi, CredentialView, ConfigurableProviderView, DiscoveredModelView, LlmApi, } from './api.ts'; +export { RpcId, AbstractApiClient, transportError, } from './api.ts'; +export type { ConnectionConfig, ConnectionSinks, ConnectionState }; +export type { ClientConnectionRpc } from '../rpc.ts'; +/** Observable Host description published by each completed connection handshake. */ +export interface HostDescriptionSource { + /** Latest connected-generation description; absent before connect and while reconnecting. */ + getSnapshot(): HostDescription | undefined; + /** Subscribe to description replacement and connection loss. */ + subscribe(listener: () => void): () => void; +} +/** Required services (none — this is the wire root). */ +export declare const inject: string[]; +/** + * The ctx.connection service API: the API client plus a one-shot + * controller starter (the runtime plugin supplies sinks when its object layer + * is ready — connection stays consumer-agnostic). + */ +export interface ConnectionHandle { + /** Shared api client (fixture or real, decided at boot from the page URL). */ + readonly api: IApiClient; + /** Whether the current page authority is loopback; non-browser contexts default to true. */ + readonly isLoopback: boolean; + /** Generation-scoped Host facts, including native path-open capability. */ + readonly hostDescription: HostDescriptionSource; + /** Generic logical RPC channels over the same Connection transport. */ + readonly rpc: ClientConnectionRpc; + /** + * Start the connect/pump/reconnect loop with the consumer's frame sinks. + * One consumer owns the streams (the runtime object layer); a second call + * throws. + * @param sinks - frame/state callbacks. + * @param config - reconnect/backoff tunables. + * @returns stop handle for the loop. + */ + start(sinks: ConnectionSinks, config?: ConnectionConfig): { + stop(): void; + }; +} +/** + * Client plugin body: pick the api by page mode and provide ctx.connection. + * @param ctx - client cordis context. + */ +export declare function apply(ctx: Context): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/random-uuid.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/random-uuid.d.ts new file mode 100644 index 0000000..9c14cda --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/random-uuid.d.ts @@ -0,0 +1,7 @@ +/** Browser-safe UUID generation for client-side wire correlation. */ +/** + * Generate an RFC 4122 version 4 UUID without requiring a secure context. + * @returns a UUID backed by `crypto.getRandomValues()`, which browsers expose on insecure origins. + */ +export declare function randomUuid(): string; +//# sourceMappingURL=random-uuid.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/rpc.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/rpc.d.ts new file mode 100644 index 0000000..f6af7ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/rpc.d.ts @@ -0,0 +1,8 @@ +/** Browser caller for generic Connection unary RPC channels. */ +import type { ClientConnectionRpc } from '../rpc.ts'; +/** + * Create the browser-backed generic RPC caller. + * @returns caller that owns request correlation and response-envelope validation. + */ +export declare function createWebConnectionRpc(): ClientConnectionRpc; +//# sourceMappingURL=rpc.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/web-api-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/web-api-client.d.ts new file mode 100644 index 0000000..7a27aed --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/client/web-api-client.d.ts @@ -0,0 +1,11 @@ +/** Browser API carrier: HTTP upstream plus one WebSocket per downstream event stream. */ +import type { ApiProxy, HostFrame, MuxFrame, RpcRequest } from './api.ts'; +import { AbstractApiClient } from './api.ts'; +/** Browser platform subclass: unary/respond use fetch; mux/host use downlink-only WebSockets. */ +export declare class WebApiClient extends AbstractApiClient { + protected doFetch(input: URL, init?: RequestInit): Promise; + protected openMux(_payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + protected openHost(_payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + private readWebSocket; +} +//# sourceMappingURL=web-api-client.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/http-bridge.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/http-bridge.d.ts new file mode 100644 index 0000000..f7d5515 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/http-bridge.d.ts @@ -0,0 +1,29 @@ +/** + * node:http ↔ WHATWG fetch bridge for the /api transport (host side of the + * web carrier; the fetch-shaped handler itself is transport-agnostic). + */ +import type { IncomingMessage, ServerResponse } from 'node:http'; +/** Default carrier cap for all HTTP RPC bodies: sized for the default + * aggregate image limit (100 MiB) after base64 expansion plus envelope + * headroom (~134.3 MiB required), rounded up for slack. The bridge buffers + * each body in memory, so this cap is also the per-request resident bound. */ +export declare const DEFAULT_MAX_REQUEST_BODY_BYTES: number; +/** Transport-independent request handler consumed by the Host HTTP bridge. */ +export interface FetchHandler { + /** + * Handle one standard Fetch request. + * @param request - request produced by the active transport bridge. + * @returns complete or streaming Fetch response. + */ + fetch(request: Request): Promise; +} +/** + * Bridge one node:http request to the fetch-shaped handler (client close + * aborts; SSE bodies stream out chunk by chunk). + * @param req - incoming node:http request (fully read before dispatch). + * @param res - node:http response the bridge writes and owns to completion. + * @param apiHandler - fetch-shaped API carrier the request is dispatched to. + * @param maxRequestBodyBytes - maximum body bytes buffered before dispatch. + */ +export declare function bridge(req: IncomingMessage, res: ServerResponse, apiHandler: FetchHandler, maxRequestBodyBytes?: number): Promise; +//# sourceMappingURL=http-bridge.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/index.d.ts new file mode 100644 index 0000000..58a76c5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/index.d.ts @@ -0,0 +1,36 @@ +/** Host HTTP bridge for browser-client RPC. */ +import type { Context } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +export type { ConnectionRpcAuthority, ConnectionRpcEndpointMatcher, ConnectionRpcHandler, ConnectionRpcHandlerOptions, HostConnectionHandle, HostConnectionRpc, } from './rpc.ts'; +export { HostConnectionService } from './rpc-host.ts'; +export { API_PATH, HOST_EVENTS_PATH, MUX_EVENTS_PATH } from './api-path.ts'; +/** Stable Cordis plugin name. */ +export declare const name = "client-connection"; +/** Services required before providing Connection; API Proxy is an optional `/api` fallback. */ +export declare const inject: string[]; +/** Plugin config: the deployment's non-loopback serving authorities. */ +export interface ConnectionConfig { + /** + * Authorities this deployment serves beyond loopback: exact `host:port`, or + * port-less `host` matching any port. The /api trust fence refuses any + * request whose Host is neither loopback nor listed here, so a + * non-loopback (`0.0.0.0`) deployment must declare the names it is reached + * by (the dsh CLI derives the machine's LAN IP literals itself). An entry + * that is not a bare, canonical authority fails the plugin load. + */ + trustedHosts?: string[]; + /** Maximum buffered JSON body for every `/api` request. */ + maxRequestBodyBytes?: number; +} +export declare const Config: z; +/** + * Mounts the API gateway under the browser transport prefix. Every request on + * the prefix passes the browser-trust fence first (DNS-rebinding and + * cross-site defense — [api-request-trust](./api-request-trust.ts)); + * privileged methods additionally pass it with an empty trust list, which + * pins them to loopback. + * @param ctx - Host plugin context. + * @param config - resolved plugin config (schema defaults applied). + */ +export declare function apply(ctx: Context, config?: ConnectionConfig): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/invariant.d.ts new file mode 100644 index 0000000..cdbfd40 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-client-connection`. + * @module @deepseek-ai/dsh-client-connection/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "client-connection-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/loopback-hostname.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/loopback-hostname.d.ts new file mode 100644 index 0000000..9ae9118 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/loopback-hostname.d.ts @@ -0,0 +1,12 @@ +/** + * Browser-safe, zero-dependency loopback classification shared by the `/api` + * Host fence and the package's `ctx.connection` state. The predicate stays + * package-internal; client plugins consume the derived state through Cordis. + */ +/** + * Whether a normalized URL hostname names the local loopback authority. + * @param hostname - WHATWG URL hostname (IPv6 literals retain brackets). + * @returns true for localhost, IPv6 loopback, or any IPv4 address in 127/8. + */ +export declare function isLoopbackHostname(hostname: string): boolean; +//# sourceMappingURL=loopback-hostname.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc-host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc-host.d.ts new file mode 100644 index 0000000..09df9d7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc-host.d.ts @@ -0,0 +1,33 @@ +/** Host registry and HTTP adapter for generic Connection RPC channels. */ +import { Context, Service } from '@deepseek-ai/cordis'; +import { type FetchHandler } from './http-bridge.ts'; +import type { HostConnectionHandle, HostConnectionRpc } from './rpc.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + /** Host Connection transport and RPC registrations. */ + connection: HostConnectionHandle; + } +} +/** Host Connection service whose channel registrations belong to the caller fiber. */ +export declare class HostConnectionService extends Service implements HostConnectionHandle { + private readonly trustedHosts; + private readonly interceptors; + /** + * Provide the Host half over the active HTTP server. + * @param ctx - owning Connection plugin context. + * @param trustedHosts - deployment authorities accepted by trusted-host channels. + */ + constructor(ctx: Context, trustedHosts: readonly string[]); + /** Generic channel registry scoped to the Context reading this service. */ + get rpc(): HostConnectionRpc; + /** + * Compose one shared-channel Fetch handler from its interceptor and fallback. + * @param channel - shared channel mounted by Connection. + * @param fallback - handler for endpoints not claimed by the interceptor. + * @returns Fetch handler that selects exactly one target for each request. + */ + createSharedFetchHandler(channel: '/api', fallback: FetchHandler): FetchHandler; + private register; + private registerInterceptor; +} +//# sourceMappingURL=rpc-host.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc.d.ts new file mode 100644 index 0000000..e19b4d3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/rpc.d.ts @@ -0,0 +1,51 @@ +/** Generic unary RPC contracts shared by the Host and Client Connection halves. */ +import type { RpcResult } from '@deepseek-ai/dsh-host-apiproxy/api'; +/** Trust fence applied before a Host RPC channel reaches its handler. */ +export type ConnectionRpcAuthority = 'trusted-host' | 'loopback'; +/** Registration policy for one logical RPC channel. */ +export interface ConnectionRpcHandlerOptions { + /** Browser authority accepted by every endpoint in this channel. */ + readonly authority: ConnectionRpcAuthority; +} +/** Handler invoked after Connection has decoded the transport envelope. */ +export type ConnectionRpcHandler = (endpoint: string, payload: unknown, signal: AbortSignal) => Promise>; +/** Synchronous ownership test for one endpoint on a shared RPC channel. */ +export type ConnectionRpcEndpointMatcher = (endpoint: string) => boolean; +/** Host registry for logical RPC channels carried by the current transport. */ +export interface HostConnectionRpc { + /** + * Register one absolute channel prefix and its trust policy. + * @param channel - absolute logical channel such as `/rpc`. + * @param handler - decoded endpoint handler returning the existing RPC result shape. + * @param options - channel trust policy. + * @returns asynchronous disposer removing the channel and its physical route. + */ + handle(channel: string, handler: ConnectionRpcHandler, options: ConnectionRpcHandlerOptions): () => Promise; + /** + * Intercept owned endpoints on the shared `/api` channel before its fallback. + * @param channel - reserved shared channel; currently `/api`. + * @param matches - synchronous endpoint ownership test. + * @param handler - decoded endpoint handler returning the existing RPC result shape. + * @param options - trust policy for every endpoint claimed by this interceptor. + * @returns asynchronous disposer removing the interceptor. + */ + intercept(channel: '/api', matches: ConnectionRpcEndpointMatcher, handler: ConnectionRpcHandler, options: ConnectionRpcHandlerOptions): () => Promise; +} +/** Host `ctx.connection` shape consumed by transport-independent adapters. */ +export interface HostConnectionHandle { + /** Generic RPC channel registry. */ + readonly rpc: HostConnectionRpc; +} +/** Client caller for logical RPC channels carried by the current transport. */ +export interface ClientConnectionRpc { + /** + * Call one endpoint through an already registered logical channel. + * @param channel - absolute logical channel such as `/api`. + * @param endpoint - channel-relative endpoint such as `goals/create`. + * @param payload - channel-owned request payload. + * @param signal - optional caller cancellation. + * @returns the existing RPC success/error result; correlation stays inside Connection. + */ + call(channel: string, endpoint: string, payload: unknown, signal?: AbortSignal): Promise>; +} +//# sourceMappingURL=rpc.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/websocket-downlink.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/websocket-downlink.d.ts new file mode 100644 index 0000000..a9d429e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/lib/types/websocket-downlink.d.ts @@ -0,0 +1,43 @@ +/** Host-side WebSocket carrier for the two server-to-browser event streams. */ +import type { IncomingMessage } from 'node:http'; +import type { Duplex } from 'node:stream'; +import type { ApiProxy } from '@deepseek-ai/dsh-host-apiproxy/api'; +/** + * Owns WebSocket negotiation and frame pumping for the connection plugin's + * two downlinks. Client messages are a protocol violation: upstream traffic + * remains on HTTP. + */ +export declare class WebSocketDownlinks { + private readonly api; + private readonly server; + private readonly pumps; + /** @param api - host API supplying the typed event streams. */ + constructor(api: ApiProxy); + /** + * Upgrade one socket and pump the mux stream until either side closes. + * @param req - HTTP upgrade request. + * @param socket - Raw socket transferred by the HTTP server. + * @param head - Bytes already read after the upgrade headers. + */ + handleMux(req: IncomingMessage, socket: Duplex, head: Buffer): void; + /** + * Upgrade one socket and pump the host stream until either side closes. + * @param req - HTTP upgrade request. + * @param socket - Raw socket transferred by the HTTP server. + * @param head - Bytes already read after the upgrade headers. + */ + handleHost(req: IncomingMessage, socket: Duplex, head: Buffer): void; + /** + * Terminate owned sockets and await the no-server acceptor plus frame pumps. + * @returns A promise resolving after every socket and source iterator stops. + */ + close(): Promise; + private upgrade; + private pump; +} +/** + * Reject an untrusted upgrade before protocol negotiation. + * @param socket - Raw HTTP socket that remains owned by the caller. + */ +export declare function rejectWebSocketUpgrade(socket: Duplex): void; +//# sourceMappingURL=websocket-downlink.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/package.json new file mode 100644 index 0000000..68ef7ff --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection/package.json @@ -0,0 +1,67 @@ +{ + "name": "@deepseek-ai/dsh-client-connection", + "description": "Wire consumer layer: HTTP-up/WebSocket-down client, ConnectionController dual streams with reconnect, and fixture api", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/client/connection" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client/index.d.ts", + "default": "./lib/client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "dsh": { + "client": { + "inject": [], + "platform": "web", + "immediately": true + } + }, + "license": "MIT", + "dependencies": { + "ws": "^8.21.0", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.7", + "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.7", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.7", + "@deepseek-ai/schemastery": "^3.18.1", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/client.js", + "lib/types/**/*.d.ts" + ], + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@types/ws": "^8.18.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-commands b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-commands new file mode 120000 index 0000000..75a57f5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-commands @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-host-apiproxy b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-host-apiproxy new file mode 120000 index 0000000..fe2bd92 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-host-apiproxy @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-host-webserver b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-host-webserver new file mode 120000 index 0000000..3946303 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-host-webserver @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-tools b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-tools new file mode 120000 index 0000000..df45afe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-tools @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/ws b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/ws new file mode 120000 index 0000000..7b83861 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/ws @@ -0,0 +1 @@ +../../ws@8.21.3/node_modules/ws \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.i18n.yaml new file mode 100644 index 0000000..de3ced0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/code-runtime/code-runtime/README.md +README.md: ee64f7a16295bcf31e40eb305ca35aa774dac8d2 +README.zh.md: 9aac1196085d12dfe240af7667e98787f445c534 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.md new file mode 100644 index 0000000..ee64f7a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.md @@ -0,0 +1,38 @@ +# @deepseek-ai/dsh-code-runtime + +English | [中文](README.zh.md) + +The **`CodeRuntime`** (`ctx.codeRuntime`) defines WHAT a code runtime does — run one model-written program against a set of host-provided async bindings and report `{ value, logs, error? }` — without saying HOW. + +This package owns the Service Definition role of the capability (the bash trio is the template — see [capability seams](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)): providers subclass `CodeRuntime` and register the service; the Consumer is the tool registry's Code Mode, which generates the model-facing SDK and bridges tool dispatch — both specified in the [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md), whose first provider is a Node worker-thread backend. The runtime knows nothing about tools or sessions: it is handed named async functions and a program string, and everything tool-shaped stays with the Consumer. + +## Service API (`ctx.codeRuntime`) + +| Member | Semantics | +|---|---| +| `run(request)` | Execute one program against the request's bindings. **Resolves with an error FIELD for every program outcome** — parse/transform failure, thrown exception, invalid completion, output overflow, budget expiry, abort, or substrate death (`CodeRunFailure`'s orthogonal `kind` taxonomy); it rejects only for caller misuse of the Service Definition contract (e.g. a run submitted after disposal). The program runs as the body of an async function: top-level `await`/`return` work, and a lossless JSON completion becomes `result.value`. | +| `language` | Readonly descriptor: the source language `run` expects. `'typescript'` and `'python'` are the well-known values — those `dsh-tools` presents; only `'typescript'` has a published backend. Informational, not gating — a consumer that generates language-specific presentation switches on it and fails loud on a language it cannot present. | +| `isolation` | Readonly descriptor: the execution substrate (`'worker-thread'`, `'process'`, `'container'`). A label for deployments and diagnostics, **not a security claim**. | + +Semantics every implementation must honor (contract details in the class JSDoc): binding calls bridge complete lossless-JSON arguments and resolutions with no seam-level byte cap; the program is treated as a hostile peer (arbitrary binding names are own properties, malformed traffic never crashes the host); no state survives between runs; disposal terminates in-flight runs AND awaits their exit before completing. + +## Vocabulary + +`CodeRunRequest` (`program`, `bindings`, `signal?`) carries everything the runtime acts on — defaulting (time budgets and outer-output cap) is the provider's validated config, never a hidden `??` inside `run()`. `bindings` is a list of `CodeBindingNamespace`s (`global` + `functions` + optional `errorClass`), each exposed to the program as one global object of async callables returning `CodeJsonValue`, the service-local structural equivalent of canonical `JsonValue` that keeps this Service Definition package independent of sessions. An `errorClass` descriptor names a real program-global constructor and the own property that receives the rejected member name; runtimes remain independent of Consumer terms such as `ToolCallError`. `CodeRunResult` reports the lossless JSON completion `value?`, ordered `logs: string[]`, and the `error?` (`CodeRunFailure`: `kind` + model-feedable `message`). See `src/types.ts` for the full contracts. + +Binding-global and error-class names are **language-portable**: they must match the identifier subset `[A-Za-z_][A-Za-z0-9_]*` (no JS-only `$`) and clear the seam-exported exclusion sets, so one `bindings` list is valid against every backend regardless of its `language`. The package exports the contract every backend enforces — `PORTABLE_RESERVED_WORDS` (ECMAScript ∪ Python reserved words), `RESERVED_BINDING_GLOBALS` (backend-owned globals such as `console`), `RESERVED_ERROR_MEMBERS` and `DUNDER_MEMBER` (error-member exclusions) — so a name like `$tools`, `lambda`, or `__dsh_main__` makes `run()` reject as seam misuse on any backend, not just some. See `src/index.ts` for the exact sets and rationale. + +## Model Experience + +Indirectly, through Code Mode in `dsh-tools`, which exposes `run_code` and returns program logs, values, or failures as retained tool-result tokens. + +#### KV Cache effect + +No direct invalidation; the named consumer owns any request-prefix changes. + +## Known Limitations and Deferred Work + +- **`run()` is one-shot** — `logs` arrive only on the resolved `CodeRunResult`; the seam exposes no streaming-log or progress API for a live program's output. +- **A persistent REPL-style kernel is recorded future work** — the no-state-between-runs contract stands until a persistent-kernel backend brings its own logging story ([Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)). +- **Only the worker-thread backend ships** — `'process'`/`'container'` are declared well-known `isolation` values with no implementation; a hard security boundary awaits a container backend. +- **Intermediate binding values have no byte cap** — implementations remain subject to structured-clone cost and process memory, while a provider or executor may already have imposed its own acquisition bound. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.zh.md new file mode 100644 index 0000000..9aac119 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/README.zh.md @@ -0,0 +1,38 @@ +# @deepseek-ai/dsh-code-runtime + +[English](README.md) | 中文 + +**`CodeRuntime`**(`ctx.codeRuntime`)定义代码运行时做什么,即针对宿主提供的一组异步绑定运行一段模型编写的程序,并报告 `{ value, logs, error? }`,而不规定如何实现。 + +此包承担该能力的 Service Definition 角色(以 bash 三包结构为模板,参见[能力 seam](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):提供方通过继承 `CodeRuntime` 并注册服务接入;Consumer 是工具注册表的 Code Mode,它生成面向模型的 SDK,并桥接工具分发。这两项职责均由 [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) 规定,首个提供方是 Node worker 线程后端。运行时不了解工具或会话:调用方只向它提供具名异步函数与程序字符串;所有与工具有关的内容都留在 Consumer。 + +## 服务 API(`ctx.codeRuntime`) + +| 成员 | 语义 | +|---|---| +| `run(request)` | 针对请求的绑定执行一段程序。**所有程序失败结果都通过 resolve 结果中的 error 字段报告**:包括解析/转换失败、抛出异常、无效完成值、输出溢出、预算到期、中止或执行基底终止(由 `CodeRunFailure` 的正交 `kind` 分类表示);只有调用方误用 Service Definition 约定时才 reject(例如 dispose(资源释放)后仍提交运行)。程序作为异步函数的函数体运行,因此顶层 `await`/`return` 可用,无损 JSON 完成值会成为 `result.value`。 | +| `language` | 只读描述符:`run` 期望的源语言。已知值为 `'typescript'` 与 `'python'`——`dsh-tools` 能呈现的那些;其中只有 `'typescript'` 有已发布的后端。仅供参考,不作门禁;生成语言专用呈现的消费方会根据该值选择分支,遇到无法呈现的语言时明确失败。 | +| `isolation` | 只读描述符:执行基底(`'worker-thread'`、`'process'`、`'container'`)。供部署与诊断使用,**不构成安全声明**。 | + +每个实现都必须遵守以下语义(完整约定见类 JSDoc):绑定调用会桥接完整的无损 JSON 参数与 resolve 值,seam 层不设字节上限;程序被视为敌对对等方(任意绑定名称都会成为自有属性,格式错误的通信绝不能使宿主崩溃);不同运行之间不保留任何状态;dispose 会终止进行中的运行,并且在完成前等待其退出。 + +## 词汇 + +`CodeRunRequest`(`program`、`bindings`、`signal?`)携带运行时操作所需的全部内容;默认值解析(时间预算与外层输出上限)属于提供方的已验证配置,绝不能是隐藏的 `??`,更不能藏在 `run()` 内部。`bindings` 是 `CodeBindingNamespace` 列表(`global` + `functions` + 可选 `errorClass`);每个命名空间会作为一个由异步可调用函数组成的全局对象公开给程序,这些函数返回 `CodeJsonValue`。后者是服务本地、与规范 `JsonValue` 结构等价的类型,使 Service Definition 包保持独立于会话。`errorClass` 描述符点名真实的程序全局构造器,以及用于接收被拒绝成员名称的自有属性;运行时不依赖 `ToolCallError` 等 Consumer 术语。`CodeRunResult` 报告无损 JSON 完成值 `value?`、有序的 `logs: string[]` 和 `error?`(`CodeRunFailure`:`kind` + 可反馈给模型的 `message`)。完整约定见 `src/types.ts`。 + +binding-global 与 error-class 名称是**语言可移植**的:必须匹配标识符子集 `[A-Za-z_][A-Za-z0-9_]*`(不含 JS 专有的 `$`)并通过 seam 导出的排除集,因此同一份 `bindings` 列表对每个后端都有效,无论其 `language` 为何。本包导出每个后端都执行的约定——`PORTABLE_RESERVED_WORDS`(ECMAScript ∪ Python 保留字)、`RESERVED_BINDING_GLOBALS`(如 `console` 等后端拥有的 global)、`RESERVED_ERROR_MEMBERS` 与 `DUNDER_MEMBER`(error-member 排除)——因此 `$tools`、`lambda`、`__dsh_main__` 之类的名称会让 `run()` 在任何后端上作为 seam 误用而 reject,而非只在某些后端。确切集合与理由见 `src/index.ts`。 + +## 模型体验 + +通过 `dsh-tools` 中的 Code Mode 间接提供;后者公开 `run_code`,并将程序日志、值或失败作为保留的工具结果 token 返回。 + +#### KV Cache 影响 + +不会直接失效;由上述消费方负责请求前缀变更。 + +## 已知限制与暂缓事项 + +- **`run()` 是一次性的**:`logs` 只有在 `CodeRunResult` resolve 后才能获得;seam 不提供正在运行的程序所产生输出的流式日志或进度接口。 +- **持久 REPL 风格内核已记录为未来工作**:在持久内核后端带来自己的日志方案前,运行之间不保留状态的约定继续有效(参见 [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md))。 +- **目前只提供 worker 线程后端**:`'process'`/`'container'` 是已经声明但没有实现的已知 `isolation` 值;强安全边界需要等待容器后端。 +- **中间绑定值没有字节上限**:实现仍受 structured-clone 成本与进程内存约束,而提供方或执行器可能已经应用自己的获取上限。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/index.js new file mode 100644 index 0000000..3c728f3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/index.js @@ -0,0 +1,154 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/index.js +/** +* Service Definition for the code-execution capability seam that runs one model-written program against host async bindings. +* Runtimes know nothing about tools or sessions; consumers own those concerns. +* @module @deepseek-ai/dsh-code-runtime +*/ +/** +* Binding globals EVERY backend refuses because SOME backend owns the slot in +* the program's namespace: `console` (the worker's log capture), and +* `__dsh_main__`/`__builtins__`/`__name__` (the Python backend's bootstrap +* wrapper and seeded module globals; see the [portable-identifier Agent +* Note](../../../../.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.md)), +* and `__debug__`. One shared set — rather than each backend refusing only its +* own slots — keeps the portability promise real: a namespace list valid on +* one backend is valid on all, so a caller cannot pick a name that works on +* the worker and collides on Python (or vice versa). `__name__` et al. ARE +* valid portable identifiers, so the identifier rule on +* `CodeBindingNamespace.global` never rejects them — hence this explicit set. +* (Error members differ: {@link DUNDER_MEMBER} refuses every dunder form +* wholesale; binding globals refuse only the names listed here.) `__debug__` +* is listed for a different reason than a collision: CPython compiles a bare +* `__debug__` reference to the constant `True` and rejects any assignment to +* the name at COMPILE time, so an injected global under that name is +* unreachable from the program — accepted by validation, unusable on the +* Python backend, which is exactly the split the shared set exists to prevent. +*/ +const RESERVED_BINDING_GLOBALS = new Set([ + "console", + "__dsh_main__", + "__builtins__", + "__name__", + "__debug__" +]); +/** +* `CodeBindingErrorClass.memberNameProperty` names EVERY backend refuses, as +* one shared contract so a request valid on one backend is valid on all. The +* JS `Error` exclusions (`name`, `message`, `stack`) and Python's +* exception-protocol members (`args`, `with_traceback`, `add_note`) are +* listed by name; dunder-form names (`__x__`, non-empty middle) are refused +* wholesale — several are constrained CPython descriptors whose `setattr` +* raises while constructing the rejection, and the exact set is an interpreter +* version detail. Any other non-empty own property name is accepted everywhere. +*/ +const RESERVED_ERROR_MEMBERS = new Set([ + "name", + "message", + "stack", + "args", + "with_traceback", + "add_note" +]); +/** +* Dunder form (`__x__`, non-empty middle): object-protocol slots in Python, +* refused as {@link RESERVED_ERROR_MEMBERS | error members} on every backend. +*/ +const DUNDER_MEMBER = /^__.+__$/; +/** +* Reserved words of every portable target language (ECMAScript ∪ Python), +* refused as {@link CodeBindingNamespace.global} / error-class names by all +* backends. Python is a portability target here even though only the +* TypeScript worker has a published backend. The portable-identifier contract +* promises a namespace list valid on one backend is valid on every backend; a +* per-language check would let `lambda` pass the TypeScript backend and fail +* the Python one. Extending the seam with a new language means widening this +* union (a breaking review of existing binding names, by design). +*/ +const PORTABLE_RESERVED_WORDS = new Set([ + "await", + "break", + "case", + "catch", + "class", + "const", + "continue", + "debugger", + "default", + "delete", + "do", + "else", + "enum", + "export", + "extends", + "false", + "finally", + "for", + "function", + "if", + "import", + "in", + "instanceof", + "new", + "null", + "return", + "super", + "switch", + "this", + "throw", + "true", + "try", + "typeof", + "var", + "void", + "while", + "with", + "yield", + "let", + "static", + "implements", + "interface", + "package", + "private", + "protected", + "public", + "arguments", + "eval", + "False", + "None", + "True", + "and", + "as", + "assert", + "async", + "def", + "del", + "elif", + "except", + "from", + "global", + "is", + "lambda", + "nonlocal", + "not", + "or", + "pass", + "raise", + "match", + "type", + "_" +]); +/** +* Registers one `ctx.codeRuntime` implementation. Program, budget, abort, and substrate +* failures resolve in {@link CodeRunResult}; only Service Definition contract misuse rejects. Implementations bridge +* structured-cloneable bindings, materialize each declared namespace rejection +* class, treat programs as hostile peers, isolate runs from one another, and +* terminate and await in-flight runs during disposal. +*/ +var CodeRuntime = class extends Service { + constructor(ctx) { + super(ctx, "codeRuntime"); + } +}; +//#endregion +export { CodeRuntime, CodeRuntime as default, DUNDER_MEMBER, PORTABLE_RESERVED_WORDS, RESERVED_BINDING_GLOBALS, RESERVED_ERROR_MEMBERS }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/invariant.js new file mode 100644 index 0000000..ff90644 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-code-runtime`. +* @module @deepseek-ai/dsh-code-runtime/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-code-runtime"; +/** Cordis companion plugin name. */ +const name = "code-runtime-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this package exposes no independent event sequence or mutable data relation +* beyond contracts enforced at its owning seam. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/index.d.ts new file mode 100644 index 0000000..97412b3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/index.d.ts @@ -0,0 +1,99 @@ +/** + * Service Definition for the code-execution capability seam that runs one model-written program against host async bindings. + * Runtimes know nothing about tools or sessions; consumers own those concerns. + * @module @deepseek-ai/dsh-code-runtime + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { CodeRunRequest, CodeRunResult } from './types.ts'; +export type { CodeBindingErrorClass, CodeBindingFunction, CodeBindingNamespace, CodeJsonValue, CodeRunFailure, CodeRunRequest, CodeRunResult, } from './types.ts'; +/** + * Binding globals EVERY backend refuses because SOME backend owns the slot in + * the program's namespace: `console` (the worker's log capture), and + * `__dsh_main__`/`__builtins__`/`__name__` (the Python backend's bootstrap + * wrapper and seeded module globals; see the [portable-identifier Agent + * Note](../../../../.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.md)), + * and `__debug__`. One shared set — rather than each backend refusing only its + * own slots — keeps the portability promise real: a namespace list valid on + * one backend is valid on all, so a caller cannot pick a name that works on + * the worker and collides on Python (or vice versa). `__name__` et al. ARE + * valid portable identifiers, so the identifier rule on + * `CodeBindingNamespace.global` never rejects them — hence this explicit set. + * (Error members differ: {@link DUNDER_MEMBER} refuses every dunder form + * wholesale; binding globals refuse only the names listed here.) `__debug__` + * is listed for a different reason than a collision: CPython compiles a bare + * `__debug__` reference to the constant `True` and rejects any assignment to + * the name at COMPILE time, so an injected global under that name is + * unreachable from the program — accepted by validation, unusable on the + * Python backend, which is exactly the split the shared set exists to prevent. + */ +export declare const RESERVED_BINDING_GLOBALS: ReadonlySet; +/** + * `CodeBindingErrorClass.memberNameProperty` names EVERY backend refuses, as + * one shared contract so a request valid on one backend is valid on all. The + * JS `Error` exclusions (`name`, `message`, `stack`) and Python's + * exception-protocol members (`args`, `with_traceback`, `add_note`) are + * listed by name; dunder-form names (`__x__`, non-empty middle) are refused + * wholesale — several are constrained CPython descriptors whose `setattr` + * raises while constructing the rejection, and the exact set is an interpreter + * version detail. Any other non-empty own property name is accepted everywhere. + */ +export declare const RESERVED_ERROR_MEMBERS: ReadonlySet; +/** + * Dunder form (`__x__`, non-empty middle): object-protocol slots in Python, + * refused as {@link RESERVED_ERROR_MEMBERS | error members} on every backend. + */ +export declare const DUNDER_MEMBER: RegExp; +/** + * Reserved words of every portable target language (ECMAScript ∪ Python), + * refused as {@link CodeBindingNamespace.global} / error-class names by all + * backends. Python is a portability target here even though only the + * TypeScript worker has a published backend. The portable-identifier contract + * promises a namespace list valid on one backend is valid on every backend; a + * per-language check would let `lambda` pass the TypeScript backend and fail + * the Python one. Extending the seam with a new language means widening this + * union (a breaking review of existing binding names, by design). + */ +export declare const PORTABLE_RESERVED_WORDS: ReadonlySet; +declare module '@deepseek-ai/cordis' { + interface Context { + codeRuntime: CodeRuntime; + } +} +/** + * Registers one `ctx.codeRuntime` implementation. Program, budget, abort, and substrate + * failures resolve in {@link CodeRunResult}; only Service Definition contract misuse rejects. Implementations bridge + * structured-cloneable bindings, materialize each declared namespace rejection + * class, treat programs as hostile peers, isolate runs from one another, and + * terminate and await in-flight runs during disposal. + */ +export declare abstract class CodeRuntime extends Service { + /** + * The source language {@link run} expects `program` to be written in, as a + * lowercase identifier. Informational, not gating — a consumer that + * generates language-specific presentation (typed SDK stubs, usage + * instructions) switches on it and fails loud on a language it cannot + * present. Well-known values: `'typescript'` and `'python'`, those + * `dsh-tools` presents; only `'typescript'` has a published backend. + */ + abstract readonly language: string; + /** + * The execution substrate, as a lowercase identifier. Informational, not + * gating — a descriptor so deployments and diagnostics can tell backends + * apart, not a security claim. Well-known values: `'worker-thread'`, + * `'process'`, `'container'`. + */ + abstract readonly isolation: string; + constructor(ctx: Context); + /** + * Execute one program against the request's bindings and capture what it + * emitted. See the class doc for the resolution contract (error is a result + * field; rejection means Service Definition contract misuse only). + * @param request - the program, its bindings, and the abort signal; the + * request carries everything the runtime acts on, with no hidden defaults. + * @returns the run's outcome: completion value (when transferable), the + * ordered log capture, and the failure (if any). + */ + abstract run(request: CodeRunRequest): Promise; +} +export default CodeRuntime; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/invariant.d.ts new file mode 100644 index 0000000..dc46765 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-code-runtime`. + * @module @deepseek-ai/dsh-code-runtime/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "code-runtime-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/types.d.ts new file mode 100644 index 0000000..715a654 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/types.d.ts @@ -0,0 +1,123 @@ +/** + * Vocabulary types for the code-execution seam: what a caller hands a + * {@link ../index.ts | CodeRuntime} and what it gets back. Pure types — no + * runtime code lives here. + * + * @module @deepseek-ai/dsh-code-runtime/src/types + */ +/** + * One host-side function exposed to the program as an async callable. The + * runtime bridges calls to it (possibly across a serialization boundary), so + * `args` and the resolution value MUST be lossless JSON. A runtime rejects a + * lossy or non-cloneable value with a descriptive error rather than corrupting + * the run. No seam-level byte cap applies to a binding resolution. A rejection + * of this function surfaces inside the program as a rejection of the + * corresponding call. + */ +export type CodeBindingFunction = (args: unknown) => Promise; +/** A lossless JSON value transferable through the dependency-light Service Definition. */ +export type CodeJsonValue = null | boolean | number | string | CodeJsonValue[] | { + [key: string]: CodeJsonValue; +}; +/** + * Program-visible typed rejection for one binding namespace. The runtime + * injects a real error constructor under `name`; rejected member calls become + * its instances and expose the exact member name through + * `memberNameProperty`. Both strings are runtime data rather than knowledge + * of a particular consumer such as Code Mode. + */ +export interface CodeBindingErrorClass { + /** Constructor global and resulting `Error.name`; same portable identifier rule as {@link CodeBindingNamespace.global}. */ + name: string; + /** + * Non-empty own property for the member name. The portable exclusion set is + * `RESERVED_ERROR_MEMBERS` plus dunder-form names (`__x__`, non-empty + * middle), enforced identically by every backend; any other name — + * identifiers or not — is accepted everywhere. + */ + memberNameProperty: string; +} +/** + * A named group of {@link CodeBindingFunction}s the runtime exposes to the + * program as one global object (e.g. `tools`). Function names are arbitrary + * strings — a runtime must treat names like `__proto__` or `constructor` as + * ordinary own properties (null-prototype construction), never as prototype + * collisions. + */ +export interface CodeBindingNamespace { + /** + * The global identifier the program sees. Must match the LANGUAGE-PORTABLE + * identifier subset `[A-Za-z_][A-Za-z0-9_]*` and no language's reserved + * words, so the same namespace list works against every backend regardless + * of `language` — a JS-only spelling like `$tools` is rejected by design, + * not just by the Python backend. Names that satisfy the identifier rule but + * name a backend-owned slot (`RESERVED_BINDING_GLOBALS`, e.g. `console`, + * `__dsh_main__`) are also refused everywhere; see its declaration for the + * exact set and why each entry is reserved. + */ + global: string; + /** The callable members, keyed by the exact name the program calls. */ + functions: Record; + /** Optional program-visible typed rejection contract for this namespace. */ + errorClass?: CodeBindingErrorClass; +} +/** + * One run: the program source plus everything the runtime acts on. Per the + * explicit-over-implicit convention, defaulting (time budgets, output caps) + * is the implementation's validated config — a request carries no optional + * tuning knobs for a hidden `??` to fill in. + */ +export interface CodeRunRequest { + /** + * The program source, in the runtime's {@link ../index.ts | language}. It + * runs as the body of an async function: top-level `await` and `return` + * are available, and the completion value becomes + * {@link CodeRunResult.value}. + */ + program: string; + /** Host functions exposed to the program, one global object per namespace. */ + bindings: CodeBindingNamespace[]; + /** + * Abort the run: the runtime stops the program (hard, even mid-loop) and + * resolves with a {@link CodeRunFailure} of kind `'abort'`. In-flight + * binding calls are the CALLER's to settle — the runtime only stops asking. + */ + signal?: AbortSignal; +} +/** + * Why a run failed. The kinds are orthogonal outcomes reported independently + * (per docs/defensive-patterns.md): a budget expiry is not an exception, an + * abort is not a timeout, and a substrate death is neither. + * + * - `'exception'` — the program threw or failed to parse/transform. + * - `'timeout'` — an implementation-owned budget expired; the message says which. + * - `'abort'` — {@link CodeRunRequest.signal} fired. + * - `'worker-exit'` — the execution substrate died without settling (e.g. OOM). + * - `'invalid-output'` — the completion value was not lossless JSON. + * - `'output-limit'` — the serialized outer logs/value/diagnostic exceeded the configured cap. + */ +export interface CodeRunFailure { + /** The failure class (see the interface doc for each kind's meaning). */ + kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' | 'invalid-output' | 'output-limit'; + /** Human-readable detail, suitable for feeding back to a model to self-correct. */ + message: string; +} +/** + * The outcome of one run. An error is a FIELD on a resolved result, never a + * rejection of `run()` — reporting a failed program is the caller's job, not + * an exception path. + */ +export interface CodeRunResult { + /** + * The program's completion value (its top-level `return`), when it ran to + * completion and the value crossed the runtime's lossless-JSON boundary. + * Invalid or over-limit completions fail the run instead of substituting a + * rendered string; a failed or value-less run leaves this absent. + */ + value?: CodeJsonValue; + /** Text the program emitted, in order, bounded only as part of the outer result. */ + logs: string[]; + /** Present iff the run failed; see {@link CodeRunFailure} for the taxonomy. */ + error?: CodeRunFailure; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/package.json new file mode 100644 index 0000000..f40e424 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-code-runtime", + "description": "Abstract code-execution seam (ctx.codeRuntime) for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/code-runtime/code-runtime" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.i18n.yaml new file mode 100644 index 0000000..de3ced0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/code-runtime/code-runtime/README.md +README.md: ee64f7a16295bcf31e40eb305ca35aa774dac8d2 +README.zh.md: 9aac1196085d12dfe240af7667e98787f445c534 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.md new file mode 100644 index 0000000..ee64f7a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.md @@ -0,0 +1,38 @@ +# @deepseek-ai/dsh-code-runtime + +English | [中文](README.zh.md) + +The **`CodeRuntime`** (`ctx.codeRuntime`) defines WHAT a code runtime does — run one model-written program against a set of host-provided async bindings and report `{ value, logs, error? }` — without saying HOW. + +This package owns the Service Definition role of the capability (the bash trio is the template — see [capability seams](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)): providers subclass `CodeRuntime` and register the service; the Consumer is the tool registry's Code Mode, which generates the model-facing SDK and bridges tool dispatch — both specified in the [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md), whose first provider is a Node worker-thread backend. The runtime knows nothing about tools or sessions: it is handed named async functions and a program string, and everything tool-shaped stays with the Consumer. + +## Service API (`ctx.codeRuntime`) + +| Member | Semantics | +|---|---| +| `run(request)` | Execute one program against the request's bindings. **Resolves with an error FIELD for every program outcome** — parse/transform failure, thrown exception, invalid completion, output overflow, budget expiry, abort, or substrate death (`CodeRunFailure`'s orthogonal `kind` taxonomy); it rejects only for caller misuse of the Service Definition contract (e.g. a run submitted after disposal). The program runs as the body of an async function: top-level `await`/`return` work, and a lossless JSON completion becomes `result.value`. | +| `language` | Readonly descriptor: the source language `run` expects. `'typescript'` and `'python'` are the well-known values — those `dsh-tools` presents; only `'typescript'` has a published backend. Informational, not gating — a consumer that generates language-specific presentation switches on it and fails loud on a language it cannot present. | +| `isolation` | Readonly descriptor: the execution substrate (`'worker-thread'`, `'process'`, `'container'`). A label for deployments and diagnostics, **not a security claim**. | + +Semantics every implementation must honor (contract details in the class JSDoc): binding calls bridge complete lossless-JSON arguments and resolutions with no seam-level byte cap; the program is treated as a hostile peer (arbitrary binding names are own properties, malformed traffic never crashes the host); no state survives between runs; disposal terminates in-flight runs AND awaits their exit before completing. + +## Vocabulary + +`CodeRunRequest` (`program`, `bindings`, `signal?`) carries everything the runtime acts on — defaulting (time budgets and outer-output cap) is the provider's validated config, never a hidden `??` inside `run()`. `bindings` is a list of `CodeBindingNamespace`s (`global` + `functions` + optional `errorClass`), each exposed to the program as one global object of async callables returning `CodeJsonValue`, the service-local structural equivalent of canonical `JsonValue` that keeps this Service Definition package independent of sessions. An `errorClass` descriptor names a real program-global constructor and the own property that receives the rejected member name; runtimes remain independent of Consumer terms such as `ToolCallError`. `CodeRunResult` reports the lossless JSON completion `value?`, ordered `logs: string[]`, and the `error?` (`CodeRunFailure`: `kind` + model-feedable `message`). See `src/types.ts` for the full contracts. + +Binding-global and error-class names are **language-portable**: they must match the identifier subset `[A-Za-z_][A-Za-z0-9_]*` (no JS-only `$`) and clear the seam-exported exclusion sets, so one `bindings` list is valid against every backend regardless of its `language`. The package exports the contract every backend enforces — `PORTABLE_RESERVED_WORDS` (ECMAScript ∪ Python reserved words), `RESERVED_BINDING_GLOBALS` (backend-owned globals such as `console`), `RESERVED_ERROR_MEMBERS` and `DUNDER_MEMBER` (error-member exclusions) — so a name like `$tools`, `lambda`, or `__dsh_main__` makes `run()` reject as seam misuse on any backend, not just some. See `src/index.ts` for the exact sets and rationale. + +## Model Experience + +Indirectly, through Code Mode in `dsh-tools`, which exposes `run_code` and returns program logs, values, or failures as retained tool-result tokens. + +#### KV Cache effect + +No direct invalidation; the named consumer owns any request-prefix changes. + +## Known Limitations and Deferred Work + +- **`run()` is one-shot** — `logs` arrive only on the resolved `CodeRunResult`; the seam exposes no streaming-log or progress API for a live program's output. +- **A persistent REPL-style kernel is recorded future work** — the no-state-between-runs contract stands until a persistent-kernel backend brings its own logging story ([Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)). +- **Only the worker-thread backend ships** — `'process'`/`'container'` are declared well-known `isolation` values with no implementation; a hard security boundary awaits a container backend. +- **Intermediate binding values have no byte cap** — implementations remain subject to structured-clone cost and process memory, while a provider or executor may already have imposed its own acquisition bound. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.zh.md new file mode 100644 index 0000000..9aac119 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/README.zh.md @@ -0,0 +1,38 @@ +# @deepseek-ai/dsh-code-runtime + +[English](README.md) | 中文 + +**`CodeRuntime`**(`ctx.codeRuntime`)定义代码运行时做什么,即针对宿主提供的一组异步绑定运行一段模型编写的程序,并报告 `{ value, logs, error? }`,而不规定如何实现。 + +此包承担该能力的 Service Definition 角色(以 bash 三包结构为模板,参见[能力 seam](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):提供方通过继承 `CodeRuntime` 并注册服务接入;Consumer 是工具注册表的 Code Mode,它生成面向模型的 SDK,并桥接工具分发。这两项职责均由 [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) 规定,首个提供方是 Node worker 线程后端。运行时不了解工具或会话:调用方只向它提供具名异步函数与程序字符串;所有与工具有关的内容都留在 Consumer。 + +## 服务 API(`ctx.codeRuntime`) + +| 成员 | 语义 | +|---|---| +| `run(request)` | 针对请求的绑定执行一段程序。**所有程序失败结果都通过 resolve 结果中的 error 字段报告**:包括解析/转换失败、抛出异常、无效完成值、输出溢出、预算到期、中止或执行基底终止(由 `CodeRunFailure` 的正交 `kind` 分类表示);只有调用方误用 Service Definition 约定时才 reject(例如 dispose(资源释放)后仍提交运行)。程序作为异步函数的函数体运行,因此顶层 `await`/`return` 可用,无损 JSON 完成值会成为 `result.value`。 | +| `language` | 只读描述符:`run` 期望的源语言。已知值为 `'typescript'` 与 `'python'`——`dsh-tools` 能呈现的那些;其中只有 `'typescript'` 有已发布的后端。仅供参考,不作门禁;生成语言专用呈现的消费方会根据该值选择分支,遇到无法呈现的语言时明确失败。 | +| `isolation` | 只读描述符:执行基底(`'worker-thread'`、`'process'`、`'container'`)。供部署与诊断使用,**不构成安全声明**。 | + +每个实现都必须遵守以下语义(完整约定见类 JSDoc):绑定调用会桥接完整的无损 JSON 参数与 resolve 值,seam 层不设字节上限;程序被视为敌对对等方(任意绑定名称都会成为自有属性,格式错误的通信绝不能使宿主崩溃);不同运行之间不保留任何状态;dispose 会终止进行中的运行,并且在完成前等待其退出。 + +## 词汇 + +`CodeRunRequest`(`program`、`bindings`、`signal?`)携带运行时操作所需的全部内容;默认值解析(时间预算与外层输出上限)属于提供方的已验证配置,绝不能是隐藏的 `??`,更不能藏在 `run()` 内部。`bindings` 是 `CodeBindingNamespace` 列表(`global` + `functions` + 可选 `errorClass`);每个命名空间会作为一个由异步可调用函数组成的全局对象公开给程序,这些函数返回 `CodeJsonValue`。后者是服务本地、与规范 `JsonValue` 结构等价的类型,使 Service Definition 包保持独立于会话。`errorClass` 描述符点名真实的程序全局构造器,以及用于接收被拒绝成员名称的自有属性;运行时不依赖 `ToolCallError` 等 Consumer 术语。`CodeRunResult` 报告无损 JSON 完成值 `value?`、有序的 `logs: string[]` 和 `error?`(`CodeRunFailure`:`kind` + 可反馈给模型的 `message`)。完整约定见 `src/types.ts`。 + +binding-global 与 error-class 名称是**语言可移植**的:必须匹配标识符子集 `[A-Za-z_][A-Za-z0-9_]*`(不含 JS 专有的 `$`)并通过 seam 导出的排除集,因此同一份 `bindings` 列表对每个后端都有效,无论其 `language` 为何。本包导出每个后端都执行的约定——`PORTABLE_RESERVED_WORDS`(ECMAScript ∪ Python 保留字)、`RESERVED_BINDING_GLOBALS`(如 `console` 等后端拥有的 global)、`RESERVED_ERROR_MEMBERS` 与 `DUNDER_MEMBER`(error-member 排除)——因此 `$tools`、`lambda`、`__dsh_main__` 之类的名称会让 `run()` 在任何后端上作为 seam 误用而 reject,而非只在某些后端。确切集合与理由见 `src/index.ts`。 + +## 模型体验 + +通过 `dsh-tools` 中的 Code Mode 间接提供;后者公开 `run_code`,并将程序日志、值或失败作为保留的工具结果 token 返回。 + +#### KV Cache 影响 + +不会直接失效;由上述消费方负责请求前缀变更。 + +## 已知限制与暂缓事项 + +- **`run()` 是一次性的**:`logs` 只有在 `CodeRunResult` resolve 后才能获得;seam 不提供正在运行的程序所产生输出的流式日志或进度接口。 +- **持久 REPL 风格内核已记录为未来工作**:在持久内核后端带来自己的日志方案前,运行之间不保留状态的约定继续有效(参见 [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md))。 +- **目前只提供 worker 线程后端**:`'process'`/`'container'` 是已经声明但没有实现的已知 `isolation` 值;强安全边界需要等待容器后端。 +- **中间绑定值没有字节上限**:实现仍受 structured-clone 成本与进程内存约束,而提供方或执行器可能已经应用自己的获取上限。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/index.js new file mode 100644 index 0000000..3c728f3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/index.js @@ -0,0 +1,154 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/index.js +/** +* Service Definition for the code-execution capability seam that runs one model-written program against host async bindings. +* Runtimes know nothing about tools or sessions; consumers own those concerns. +* @module @deepseek-ai/dsh-code-runtime +*/ +/** +* Binding globals EVERY backend refuses because SOME backend owns the slot in +* the program's namespace: `console` (the worker's log capture), and +* `__dsh_main__`/`__builtins__`/`__name__` (the Python backend's bootstrap +* wrapper and seeded module globals; see the [portable-identifier Agent +* Note](../../../../.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.md)), +* and `__debug__`. One shared set — rather than each backend refusing only its +* own slots — keeps the portability promise real: a namespace list valid on +* one backend is valid on all, so a caller cannot pick a name that works on +* the worker and collides on Python (or vice versa). `__name__` et al. ARE +* valid portable identifiers, so the identifier rule on +* `CodeBindingNamespace.global` never rejects them — hence this explicit set. +* (Error members differ: {@link DUNDER_MEMBER} refuses every dunder form +* wholesale; binding globals refuse only the names listed here.) `__debug__` +* is listed for a different reason than a collision: CPython compiles a bare +* `__debug__` reference to the constant `True` and rejects any assignment to +* the name at COMPILE time, so an injected global under that name is +* unreachable from the program — accepted by validation, unusable on the +* Python backend, which is exactly the split the shared set exists to prevent. +*/ +const RESERVED_BINDING_GLOBALS = new Set([ + "console", + "__dsh_main__", + "__builtins__", + "__name__", + "__debug__" +]); +/** +* `CodeBindingErrorClass.memberNameProperty` names EVERY backend refuses, as +* one shared contract so a request valid on one backend is valid on all. The +* JS `Error` exclusions (`name`, `message`, `stack`) and Python's +* exception-protocol members (`args`, `with_traceback`, `add_note`) are +* listed by name; dunder-form names (`__x__`, non-empty middle) are refused +* wholesale — several are constrained CPython descriptors whose `setattr` +* raises while constructing the rejection, and the exact set is an interpreter +* version detail. Any other non-empty own property name is accepted everywhere. +*/ +const RESERVED_ERROR_MEMBERS = new Set([ + "name", + "message", + "stack", + "args", + "with_traceback", + "add_note" +]); +/** +* Dunder form (`__x__`, non-empty middle): object-protocol slots in Python, +* refused as {@link RESERVED_ERROR_MEMBERS | error members} on every backend. +*/ +const DUNDER_MEMBER = /^__.+__$/; +/** +* Reserved words of every portable target language (ECMAScript ∪ Python), +* refused as {@link CodeBindingNamespace.global} / error-class names by all +* backends. Python is a portability target here even though only the +* TypeScript worker has a published backend. The portable-identifier contract +* promises a namespace list valid on one backend is valid on every backend; a +* per-language check would let `lambda` pass the TypeScript backend and fail +* the Python one. Extending the seam with a new language means widening this +* union (a breaking review of existing binding names, by design). +*/ +const PORTABLE_RESERVED_WORDS = new Set([ + "await", + "break", + "case", + "catch", + "class", + "const", + "continue", + "debugger", + "default", + "delete", + "do", + "else", + "enum", + "export", + "extends", + "false", + "finally", + "for", + "function", + "if", + "import", + "in", + "instanceof", + "new", + "null", + "return", + "super", + "switch", + "this", + "throw", + "true", + "try", + "typeof", + "var", + "void", + "while", + "with", + "yield", + "let", + "static", + "implements", + "interface", + "package", + "private", + "protected", + "public", + "arguments", + "eval", + "False", + "None", + "True", + "and", + "as", + "assert", + "async", + "def", + "del", + "elif", + "except", + "from", + "global", + "is", + "lambda", + "nonlocal", + "not", + "or", + "pass", + "raise", + "match", + "type", + "_" +]); +/** +* Registers one `ctx.codeRuntime` implementation. Program, budget, abort, and substrate +* failures resolve in {@link CodeRunResult}; only Service Definition contract misuse rejects. Implementations bridge +* structured-cloneable bindings, materialize each declared namespace rejection +* class, treat programs as hostile peers, isolate runs from one another, and +* terminate and await in-flight runs during disposal. +*/ +var CodeRuntime = class extends Service { + constructor(ctx) { + super(ctx, "codeRuntime"); + } +}; +//#endregion +export { CodeRuntime, CodeRuntime as default, DUNDER_MEMBER, PORTABLE_RESERVED_WORDS, RESERVED_BINDING_GLOBALS, RESERVED_ERROR_MEMBERS }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/invariant.js new file mode 100644 index 0000000..ff90644 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-code-runtime`. +* @module @deepseek-ai/dsh-code-runtime/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-code-runtime"; +/** Cordis companion plugin name. */ +const name = "code-runtime-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this package exposes no independent event sequence or mutable data relation +* beyond contracts enforced at its owning seam. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/index.d.ts new file mode 100644 index 0000000..97412b3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/index.d.ts @@ -0,0 +1,99 @@ +/** + * Service Definition for the code-execution capability seam that runs one model-written program against host async bindings. + * Runtimes know nothing about tools or sessions; consumers own those concerns. + * @module @deepseek-ai/dsh-code-runtime + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { CodeRunRequest, CodeRunResult } from './types.ts'; +export type { CodeBindingErrorClass, CodeBindingFunction, CodeBindingNamespace, CodeJsonValue, CodeRunFailure, CodeRunRequest, CodeRunResult, } from './types.ts'; +/** + * Binding globals EVERY backend refuses because SOME backend owns the slot in + * the program's namespace: `console` (the worker's log capture), and + * `__dsh_main__`/`__builtins__`/`__name__` (the Python backend's bootstrap + * wrapper and seeded module globals; see the [portable-identifier Agent + * Note](../../../../.agents/notes/implemented/architecture/2026-07-31-code-runtime-portable-identifier-seam.md)), + * and `__debug__`. One shared set — rather than each backend refusing only its + * own slots — keeps the portability promise real: a namespace list valid on + * one backend is valid on all, so a caller cannot pick a name that works on + * the worker and collides on Python (or vice versa). `__name__` et al. ARE + * valid portable identifiers, so the identifier rule on + * `CodeBindingNamespace.global` never rejects them — hence this explicit set. + * (Error members differ: {@link DUNDER_MEMBER} refuses every dunder form + * wholesale; binding globals refuse only the names listed here.) `__debug__` + * is listed for a different reason than a collision: CPython compiles a bare + * `__debug__` reference to the constant `True` and rejects any assignment to + * the name at COMPILE time, so an injected global under that name is + * unreachable from the program — accepted by validation, unusable on the + * Python backend, which is exactly the split the shared set exists to prevent. + */ +export declare const RESERVED_BINDING_GLOBALS: ReadonlySet; +/** + * `CodeBindingErrorClass.memberNameProperty` names EVERY backend refuses, as + * one shared contract so a request valid on one backend is valid on all. The + * JS `Error` exclusions (`name`, `message`, `stack`) and Python's + * exception-protocol members (`args`, `with_traceback`, `add_note`) are + * listed by name; dunder-form names (`__x__`, non-empty middle) are refused + * wholesale — several are constrained CPython descriptors whose `setattr` + * raises while constructing the rejection, and the exact set is an interpreter + * version detail. Any other non-empty own property name is accepted everywhere. + */ +export declare const RESERVED_ERROR_MEMBERS: ReadonlySet; +/** + * Dunder form (`__x__`, non-empty middle): object-protocol slots in Python, + * refused as {@link RESERVED_ERROR_MEMBERS | error members} on every backend. + */ +export declare const DUNDER_MEMBER: RegExp; +/** + * Reserved words of every portable target language (ECMAScript ∪ Python), + * refused as {@link CodeBindingNamespace.global} / error-class names by all + * backends. Python is a portability target here even though only the + * TypeScript worker has a published backend. The portable-identifier contract + * promises a namespace list valid on one backend is valid on every backend; a + * per-language check would let `lambda` pass the TypeScript backend and fail + * the Python one. Extending the seam with a new language means widening this + * union (a breaking review of existing binding names, by design). + */ +export declare const PORTABLE_RESERVED_WORDS: ReadonlySet; +declare module '@deepseek-ai/cordis' { + interface Context { + codeRuntime: CodeRuntime; + } +} +/** + * Registers one `ctx.codeRuntime` implementation. Program, budget, abort, and substrate + * failures resolve in {@link CodeRunResult}; only Service Definition contract misuse rejects. Implementations bridge + * structured-cloneable bindings, materialize each declared namespace rejection + * class, treat programs as hostile peers, isolate runs from one another, and + * terminate and await in-flight runs during disposal. + */ +export declare abstract class CodeRuntime extends Service { + /** + * The source language {@link run} expects `program` to be written in, as a + * lowercase identifier. Informational, not gating — a consumer that + * generates language-specific presentation (typed SDK stubs, usage + * instructions) switches on it and fails loud on a language it cannot + * present. Well-known values: `'typescript'` and `'python'`, those + * `dsh-tools` presents; only `'typescript'` has a published backend. + */ + abstract readonly language: string; + /** + * The execution substrate, as a lowercase identifier. Informational, not + * gating — a descriptor so deployments and diagnostics can tell backends + * apart, not a security claim. Well-known values: `'worker-thread'`, + * `'process'`, `'container'`. + */ + abstract readonly isolation: string; + constructor(ctx: Context); + /** + * Execute one program against the request's bindings and capture what it + * emitted. See the class doc for the resolution contract (error is a result + * field; rejection means Service Definition contract misuse only). + * @param request - the program, its bindings, and the abort signal; the + * request carries everything the runtime acts on, with no hidden defaults. + * @returns the run's outcome: completion value (when transferable), the + * ordered log capture, and the failure (if any). + */ + abstract run(request: CodeRunRequest): Promise; +} +export default CodeRuntime; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/invariant.d.ts new file mode 100644 index 0000000..dc46765 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-code-runtime`. + * @module @deepseek-ai/dsh-code-runtime/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "code-runtime-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/types.d.ts new file mode 100644 index 0000000..715a654 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/lib/types/types.d.ts @@ -0,0 +1,123 @@ +/** + * Vocabulary types for the code-execution seam: what a caller hands a + * {@link ../index.ts | CodeRuntime} and what it gets back. Pure types — no + * runtime code lives here. + * + * @module @deepseek-ai/dsh-code-runtime/src/types + */ +/** + * One host-side function exposed to the program as an async callable. The + * runtime bridges calls to it (possibly across a serialization boundary), so + * `args` and the resolution value MUST be lossless JSON. A runtime rejects a + * lossy or non-cloneable value with a descriptive error rather than corrupting + * the run. No seam-level byte cap applies to a binding resolution. A rejection + * of this function surfaces inside the program as a rejection of the + * corresponding call. + */ +export type CodeBindingFunction = (args: unknown) => Promise; +/** A lossless JSON value transferable through the dependency-light Service Definition. */ +export type CodeJsonValue = null | boolean | number | string | CodeJsonValue[] | { + [key: string]: CodeJsonValue; +}; +/** + * Program-visible typed rejection for one binding namespace. The runtime + * injects a real error constructor under `name`; rejected member calls become + * its instances and expose the exact member name through + * `memberNameProperty`. Both strings are runtime data rather than knowledge + * of a particular consumer such as Code Mode. + */ +export interface CodeBindingErrorClass { + /** Constructor global and resulting `Error.name`; same portable identifier rule as {@link CodeBindingNamespace.global}. */ + name: string; + /** + * Non-empty own property for the member name. The portable exclusion set is + * `RESERVED_ERROR_MEMBERS` plus dunder-form names (`__x__`, non-empty + * middle), enforced identically by every backend; any other name — + * identifiers or not — is accepted everywhere. + */ + memberNameProperty: string; +} +/** + * A named group of {@link CodeBindingFunction}s the runtime exposes to the + * program as one global object (e.g. `tools`). Function names are arbitrary + * strings — a runtime must treat names like `__proto__` or `constructor` as + * ordinary own properties (null-prototype construction), never as prototype + * collisions. + */ +export interface CodeBindingNamespace { + /** + * The global identifier the program sees. Must match the LANGUAGE-PORTABLE + * identifier subset `[A-Za-z_][A-Za-z0-9_]*` and no language's reserved + * words, so the same namespace list works against every backend regardless + * of `language` — a JS-only spelling like `$tools` is rejected by design, + * not just by the Python backend. Names that satisfy the identifier rule but + * name a backend-owned slot (`RESERVED_BINDING_GLOBALS`, e.g. `console`, + * `__dsh_main__`) are also refused everywhere; see its declaration for the + * exact set and why each entry is reserved. + */ + global: string; + /** The callable members, keyed by the exact name the program calls. */ + functions: Record; + /** Optional program-visible typed rejection contract for this namespace. */ + errorClass?: CodeBindingErrorClass; +} +/** + * One run: the program source plus everything the runtime acts on. Per the + * explicit-over-implicit convention, defaulting (time budgets, output caps) + * is the implementation's validated config — a request carries no optional + * tuning knobs for a hidden `??` to fill in. + */ +export interface CodeRunRequest { + /** + * The program source, in the runtime's {@link ../index.ts | language}. It + * runs as the body of an async function: top-level `await` and `return` + * are available, and the completion value becomes + * {@link CodeRunResult.value}. + */ + program: string; + /** Host functions exposed to the program, one global object per namespace. */ + bindings: CodeBindingNamespace[]; + /** + * Abort the run: the runtime stops the program (hard, even mid-loop) and + * resolves with a {@link CodeRunFailure} of kind `'abort'`. In-flight + * binding calls are the CALLER's to settle — the runtime only stops asking. + */ + signal?: AbortSignal; +} +/** + * Why a run failed. The kinds are orthogonal outcomes reported independently + * (per docs/defensive-patterns.md): a budget expiry is not an exception, an + * abort is not a timeout, and a substrate death is neither. + * + * - `'exception'` — the program threw or failed to parse/transform. + * - `'timeout'` — an implementation-owned budget expired; the message says which. + * - `'abort'` — {@link CodeRunRequest.signal} fired. + * - `'worker-exit'` — the execution substrate died without settling (e.g. OOM). + * - `'invalid-output'` — the completion value was not lossless JSON. + * - `'output-limit'` — the serialized outer logs/value/diagnostic exceeded the configured cap. + */ +export interface CodeRunFailure { + /** The failure class (see the interface doc for each kind's meaning). */ + kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' | 'invalid-output' | 'output-limit'; + /** Human-readable detail, suitable for feeding back to a model to self-correct. */ + message: string; +} +/** + * The outcome of one run. An error is a FIELD on a resolved result, never a + * rejection of `run()` — reporting a failed program is the caller's job, not + * an exception path. + */ +export interface CodeRunResult { + /** + * The program's completion value (its top-level `return`), when it ran to + * completion and the value crossed the runtime's lossless-JSON boundary. + * Invalid or over-limit completions fail the run instead of substituting a + * rendered string; a failed or value-less run leaves this absent. + */ + value?: CodeJsonValue; + /** Text the program emitted, in order, bounded only as part of the outer result. */ + logs: string[]; + /** Present iff the run failed; see {@link CodeRunFailure} for the taxonomy. */ + error?: CodeRunFailure; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/package.json new file mode 100644 index 0000000..87448a2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-code-runtime", + "description": "Abstract code-execution seam (ctx.codeRuntime) for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/code-runtime/code-runtime" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.i18n.yaml new file mode 100644 index 0000000..9a53413 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/interaction/commands/README.md +README.md: e1d7e5f4f626d062a16840bce6354ee3aac921c9 +README.zh.md: 6ce3ca9016e26537003ba85e0b2217bd37448fc5 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.md new file mode 100644 index 0000000..e1d7e5f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.md @@ -0,0 +1,40 @@ +# @deepseek-ai/dsh-commands + +English | [中文](README.zh.md) + +Plugin-owned human-command registry consumed by interactive UI adapters. The [plugin command registration Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-plugin-command-registration.md) owns the boundary and dispatch contract. + +## Service contract + +`ctx.commands.register(definition)` registers one lowercase command name, description, optional unstructured-input hint, optional `recordInput` policy, and abortable handler. `recordInput` defaults to true; a command whose authoritative domain event owns the payload sets it to false so `command/run` omits `args` instead of duplicating the input. A registered command is available to every composed command adapter; a plugin that is incompatible with a deployment does not register there. A plain-context registration is global. A command-producing plugin mounted beneath `agent.ctx` declares its own `commands` injection and creates an exact agent-scoped definition; it shadows a global definition with the same name. This child-injection shape preserves the agent scope without making the core agent loop depend on a UI service. Duplicate names within one layer fail during registration. Every disposer is the exact Cordis effect disposer, and registration or removal notifies every `commands/change` observer so live adapters can refresh discovery; observer failures are logged and cannot veto the registry mutation or starve later observers. + +`list(agent)` returns immutable, name-sorted descriptors after scoped shadowing. `find(agent, name)` returns the corresponding definition. `execute(agent, line, signal)` uses `parseCommand()` and runs only a known command, returning the settled `CommandExecution` (the normalized result plus the lifecycle pairing `commandId`) or `undefined` for invalid syntax or unknown names. A resolved command's lifecycle is logged on the receiving agent's session as the log-only pair `command/run` (before the handler, with a minted `commandId`, the parser's structured name, the issuing `CommandSource`, and `args` unless `recordInput` is false) and `command/done` (at settlement, with the outcome kind and verbatim text; a successful result may also name an earlier non-command authoritative domain event through `sourceEventSeq`; a thrown or aborted handler settles as `kind: 'error'`). Admission misses log nothing. Both are direct standalone appends on the receiving agent's session: no turn wraps them, and persistence drains them through ordinary checkpoints and teardown. + +`parseCommand()` recognizes a slash at byte zero, a lowercase name containing letters, digits, `_`, or `-`, and either end-of-input or whitespace. It returns every byte after the name as `rawInput`, including separator whitespace; consumers own their command-specific grammar and may normalize only what that grammar permits. + +Handlers return `success` or `error` plus optional UI text. A successful handler may also return `sourceEventSeq` when an earlier domain event owns a richer presentation; the lifecycle invariant requires that reference to be a prior non-command event in the same session. Results are rendered directly by the adapter and never enter model history. The registry never submits `rawInput` to the agent implicitly; a command producer may explicitly schedule model-visible work through the receiving `Agent`, in which case that producer owns the resulting message contract. The registry races handler completion against the supplied abort signal, but an uncooperative handler may continue its own external side effects after the caller stops awaiting it. + +## Composition + +The shipped `dsh` base mounts this service and the Web client dispatches through it. UI-less demo spines and ACP automation do not provide a command adapter. Custom interactive compositions and command producers mount `@deepseek-ai/dsh-commands` explicitly. + +## Model Experience + +### Direct human commands + +#### What the model sees + +The registry itself submits nothing. Known slash commands execute in the UI command plane, and their `CommandResult` text is not submitted as a user message. Unknown slash-command input is rejected by shipped adapters instead of becoming a model prompt. A command producer may explicitly use the receiving `Agent`; for example, [`dsh-plan-mode`](../../plan/plan-mode/README.md#model-and-human-interactions) submits the optional message in `/plan [message]` after selecting plan mode. + +#### Token effect + +Command discovery, execution, and UI output add no model tokens. Explicit agent work scheduled by a command producer has the same token effect as the corresponding agent input. + +#### KV Cache effect + +Registry metadata, command input, and direct output never enter a model request and do not affect its cache. A mutated domain owns any later cache effect. + +## Known Limitations and Deferred Work + +- **Only unstructured text input** — forms, completion schemas, and typed arguments remain command-owned parsing concerns. +- **Cooperative side-effect cancellation** — dispatch stops awaiting on abort; handlers must honor the signal to stop work that has already escaped into external systems. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.zh.md new file mode 100644 index 0000000..6ce3ca9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/README.zh.md @@ -0,0 +1,40 @@ +# @deepseek-ai/dsh-commands + +[English](README.md) | 中文 + +由插件负责、供交互式 UI 适配器使用的面向用户命令注册表。[插件命令注册 Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-plugin-command-registration.md)定义了其边界与分发约定。 + +## 服务约定 + +`ctx.commands.register(definition)` 注册一个小写命令名称、描述、可选的非结构化输入提示、可选的 `recordInput` 策略,以及可中止的处理器。`recordInput` 默认为 true;若载荷由命令的权威领域事件持有,该命令会将 `recordInput` 设为 false,让 `command/run` 省略 `args`,避免重复记录输入。每个已注册命令都可供所有已组合的命令适配器使用;与某项部署不兼容的插件不会在此注册。普通上下文中的注册全局生效。在 `agent.ctx` 下挂载的命令生产插件会声明自身的 `commands` 注入,并创建精确限定到该 agent(智能体)的定义;该定义会遮蔽同名的全局定义。这种子级注入形态保留了 agent 作用域,同时不会让核心 agent loop(智能体循环)依赖 UI 服务。同一层中的名称重复会在注册时失败。每个 disposer 都是 Cordis effect 返回的确切 disposer;注册或移除命令时,系统会通知每个 `commands/change` 观察者,使运行中的适配器能够刷新发现结果。观察者失败会写入日志,既不能否决注册表变更,也不能阻止后续观察者运行。 + +`list(agent)` 在应用作用域遮蔽后,返回按名称排序的不可变描述符。`find(agent, name)` 返回相应定义。`execute(agent, line, signal)` 使用 `parseCommand()`,且只运行已知命令,返回已结算的 `CommandExecution`(规范化结果加生命周期配对 `commandId`);语法无效或名称未知时返回 `undefined`。已解析命令的生命周期会以 log-only 事件对的形式记录在接收 agent 的会话日志中:`command/run`(进入处理器前记录,携带新生成的 `commandId`、解析器的结构化名称、发起方 `CommandSource`,以及 `args`(`recordInput` 为 false 时省略))与 `command/done`(结算时记录,携带结果类型与原样文本;成功结果还可通过 `sourceEventSeq` 指向更早的一条非命令权威领域事件;处理器抛出或被中止时以 `kind: 'error'` 结算)。未通过准入的输入不记录任何事件。两者都直接独立追加到接收 agent 的会话中:没有轮次包裹它们,持久化机制会在常规检查点和销毁期间排空这些事件。 + +`parseCommand()` 识别位于第 0 字节的斜杠、由小写字母、数字、`_` 或 `-` 构成的名称,以及名称后紧接输入末尾或空白的形式。它将名称后的每个字节作为 `rawInput` 返回,其中包括分隔空白;消费方负责各命令专用的语法,只能执行该语法允许的规范化。 + +处理器返回 `success` 或 `error`,并可附带 UI 文本。若更丰富的呈现由一条更早的领域事件持有,成功的处理器还可返回 `sourceEventSeq`;生命周期不变量要求该引用指向同一会话中更早的一条非命令事件。适配器直接渲染结果,结果绝不进入模型历史。注册表绝不会隐式地把 `rawInput` 提交给 agent;命令生产方可以通过接收命令的 `Agent` 显式安排模型可见工作,此时该生产方负责由此产生的消息约定。注册表会同时等待处理器完成和所提供的中止信号,以先发生者为准,但不响应中止的处理器可能在调用方停止等待后继续产生自身的外部副作用。 + +## 组合 + +随产品交付的 `dsh` 基础组合会挂载此服务,Web 客户端通过它分派命令。无 UI 的演示主干和 ACP(Agent Client Protocol)自动化不提供命令适配器。自定义交互式组合与命令生产方会显式挂载 `@deepseek-ai/dsh-commands`。 + +## 模型体验 + +### 直接面向用户的命令 + +#### 模型看到的内容 + +注册表自身不会提交任何内容。已知斜杠命令在 UI 命令平面执行,其 `CommandResult` 文本不会作为用户消息提交。已交付的适配器会拒绝未知斜杠命令输入,而不是将其变成模型提示词。命令生产方可以显式使用接收命令的 `Agent`;例如,[`dsh-plan-mode`](../../plan/plan-mode/README.md#model-and-human-interactions)在选择 plan mode 后,会提交 `/plan [message]` 中的可选消息。 + +#### Token 影响 + +命令发现、执行和 UI 输出不会增加模型 token。命令生产方显式安排的 agent 工作与相应 agent 输入具有相同的 token 影响。 + +#### KV Cache 影响 + +注册表元数据、命令输入和直接输出绝不会进入模型请求,也不会影响其缓存。发生变更的领域负责之后产生的所有缓存影响。 + +## 已知限制与暂缓事项 + +- **仅支持非结构化文本输入**:表单、补全 schema 和类型化参数仍由各命令自行解析。 +- **副作用采用协作式取消**:中止后,分发会停止等待;处理器必须遵循信号,才能停止已经进入外部系统的工作。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/index.js new file mode 100644 index 0000000..abfa641 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/index.js @@ -0,0 +1,360 @@ +import { NamedEntries, ScopedLayers } from "@deepseek-ai/dsh-scope"; +import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol"; +//#region lib/types/brand.js +/** +* dsh-commands' owned branded id: command lifecycle pairing across the +* session log, the wire admission response, and client-side flow pairing. +* +* The `Branded` primitive lives in `@deepseek-ai/dsh-brand`; this module +* is a pure type/constructor outlet (no cordis imports, no module +* augmentation) so wire and client programs can name the brand without +* loading the host plugin's Context merges — the `dsh-llm/brand` shape. +* +* @module @deepseek-ai/dsh-commands/brand +*/ +/** +* Brand a string as a {@link CommandId}. +* @param id - the executor-minted pairing id. +* @returns the same string, branded; no validation is performed. +*/ +function CommandId(id) { + return id; +} +//#endregion +//#region lib/types/index.js +/** +* Plugin-owned human-command registry shared by interactive UI adapters. +* @module @deepseek-ai/dsh-commands +*/ +var __runInitializers = function(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + return useValue ? value : void 0; +}; +var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function(f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +const name = "commands"; +const COMMAND_NAME = /^[a-z][a-z0-9_-]*$/u; +/** All command registrations owned by one global or scoped layer. */ +var CommandLayer = class { + commands; + /** + * Create one command layer with diagnostics specific to its ownership scope. + * @param scope - the scoped owner, or `undefined` for global registrations. + */ + constructor(scope) { + this.commands = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `command "${name}" is already registered (for a per-agent variant, mount a command-injected plugin under that agent's \`agent.ctx\`)` : `command "${name}" is already registered in this scope`)); + } + /** @returns whether this layer owns no command registrations. */ + isEmpty() { + return this.commands.isEmpty(); + } +}; +/** +* Parse an exact slash command without normalizing its trailing input. +* +* @param line - Complete candidate command line. +* @returns The parsed command, or `undefined` when the line is not a command. +*/ +function parseCommand(line) { + const match = /^\/([a-z][a-z0-9_-]*)(?=$|[\t\n\r ])/u.exec(line); + if (match === null) return void 0; + const name = match[1]; + /* v8 ignore next -- the first capture is required whenever the regular expression matches */ + if (name === void 0) return void 0; + return Object.freeze({ + name, + rawInput: line.slice(match[0].length) + }); +} +/** Convert arbitrary abort reasons to one stable rejected Error. */ +function abortError(signal) { + if (signal.reason instanceof Error) return signal.reason; + return new Error(typeof signal.reason === "string" ? signal.reason : "command aborted"); +} +/** Render arbitrary thrown values without trusting their string coercion. */ +function renderThrown(value) { + try { + return String(value); + } catch { + return ""; + } +} +/** Stop awaiting an uncooperative handler once its owning UI request aborts. */ +function withAbort(promise, signal) { + if (signal.aborted) return Promise.reject(abortError(signal)); + return new Promise((resolve, reject) => { + const onAbort = () => { + signal.removeEventListener("abort", onAbort); + reject(abortError(signal)); + }; + signal.addEventListener("abort", onAbort, { once: true }); + promise.then((value) => { + signal.removeEventListener("abort", onAbort); + resolve(value); + }, (error) => { + signal.removeEventListener("abort", onAbort); + reject(error instanceof Error ? error : new Error(`command handler rejected with a non-Error value: ${renderThrown(error)}`, { cause: error })); + }); + }); +} +/** Reject invalid command metadata before it can reach a UI protocol. */ +function normalizeDefinition(definition) { + if (!COMMAND_NAME.test(definition.name)) throw new TypeError(`command name "${definition.name}" must match ${String(COMMAND_NAME)}`); + if (typeof definition.description !== "string") throw new TypeError(`command "${definition.name}" description must be a string`); + if (definition.description.trim().length === 0) throw new TypeError(`command "${definition.name}" description must not be empty`); + if (typeof definition.handler !== "function") throw new TypeError(`command "${definition.name}" handler must be a function`); + const rawInput = definition.input; + let input; + if (rawInput !== void 0) { + if (typeof rawInput !== "object" || rawInput === null || !("hint" in rawInput) || typeof rawInput.hint !== "string") throw new TypeError(`command "${definition.name}" input hint must be a string`); + if (rawInput.hint.trim().length === 0) throw new TypeError(`command "${definition.name}" input hint must not be empty`); + input = Object.freeze({ hint: rawInput.hint }); + } + const normalized = Object.freeze({ + name: definition.name, + description: definition.description, + ...input === void 0 ? {} : { input }, + ...definition.recordInput === void 0 ? {} : { recordInput: definition.recordInput }, + handler: definition.handler + }); + return { + definition: normalized, + descriptor: Object.freeze({ + name: normalized.name, + description: normalized.description, + ...normalized.input === void 0 ? {} : { input: normalized.input } + }) + }; +} +/** Validate and detach an untrusted handler result at the registry boundary. */ +function normalizeResult(command, value) { + if (typeof value !== "object" || value === null || !("kind" in value)) throw new TypeError(`command "${command}" handler must return a CommandResult`); + const result = value; + if (result.kind === "success") { + if (result.text !== void 0 && typeof result.text !== "string") throw new TypeError(`command "${command}" success text must be a string when supplied`); + if (result.sourceEventSeq !== void 0 && (!Number.isSafeInteger(result.sourceEventSeq) || result.sourceEventSeq < 0)) throw new TypeError(`command "${command}" success sourceEventSeq must be a non-negative safe integer when supplied`); + return Object.freeze({ + kind: "success", + ...result.text === void 0 ? {} : { text: result.text }, + ...result.sourceEventSeq === void 0 ? {} : { sourceEventSeq: result.sourceEventSeq } + }); + } + if (result.kind === "error") { + if (typeof result.text !== "string" || result.text.trim().length === 0) throw new TypeError(`command "${command}" error text must be a non-empty string`); + return Object.freeze({ + kind: "error", + text: result.text + }); + } + throw new TypeError(`command "${command}" returned unknown result kind "${String(result.kind)}"`); +} +/** +* Human-command registry. Plain-context definitions are global; definitions +* registered through a command-injected child of an agent context shadow +* globals for that agent. +*/ +let CommandRuntime = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + let _execute_decorators; + return class CommandRuntime extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote]; + _execute_decorators = [Remote]; + __esDecorate(this, null, _list_decorators, { + kind: "method", + name: "list", + static: false, + private: false, + access: { + has: (obj) => "list" in obj, + get: (obj) => obj.list + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _execute_decorators, { + kind: "method", + name: "execute", + static: false, + private: false, + access: { + has: (obj) => "execute" in obj, + get: (obj) => obj.execute + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { + enumerable: true, + configurable: true, + writable: true, + value: _metadata + }); + } + layers = (__runInitializers(this, _instanceExtraInitializers), new ScopedLayers((scope) => new CommandLayer(scope), () => { + this.notifyChange(); + })); + /** Monotonic per-instance counter behind {@link mintCommandId}. */ + commandSeq = 0; + /** Instance token keeping minted ids unique across process restarts over one resumed log. */ + instanceToken = crypto.randomUUID().slice(0, 8); + constructor(ctx) { + super(ctx, "commands"); + } + /** + * Register a global or calling-agent-scoped command. + * @param definition - discovery metadata and direct UI handler. + * @returns the exact effect disposer that unregisters this definition. + */ + register(definition) { + const registered = normalizeDefinition(definition); + return this.layers.effect(this.ctx, (layer) => layer.commands.insert(registered.definition.name, registered), { label: "commands.register()" }); + } + /** + * List the effective immutable command descriptors for one agent. + * @param agent - exact receiving agent and scoped-layer key. + * @returns name-sorted descriptors after scoped shadowing. + */ + list(agent) { + return Object.freeze([...this.view(agent).values()].map((command) => command.descriptor).sort((left, right) => left.name < right.name ? -1 : 1)); + } + /** + * Resolve one effective command definition. + * @param agent - exact receiving agent and scoped-layer key. + * @param name - command name without a slash. + * @returns the scoped shadow or global definition. + */ + find(agent, name) { + return this.view(agent).get(name)?.definition; + } + /** + * Parse and execute a known command without sending it to the model. + * + * A resolved command's lifecycle is logged: `command/run` is appended + * before the handler is invoked and `command/done` after settlement (a + * thrown or aborted handler settles as `kind: 'error'`). Both are direct + * log-only appends — no turn wraps them, and persistence drains them at + * ordinary checkpoints. Admission misses (syntax or unknown name) log + * nothing — they never entered a handler. A `command/run` append failure + * fails the execution loud; a `command/done` append failure on the + * handler-failure path is contained so the handler's own error stays the + * reported failure. + * + * @param agent - exact receiving agent. + * @param line - complete slash-command line. + * @param signal - cancellation signal owned by the UI request. + * @returns the settled execution (result + lifecycle pairing id), or + * `undefined` when syntax or name does not resolve. + */ + async execute(agent, line, signal) { + const parsed = parseCommand(line); + if (parsed === void 0) return void 0; + const command = this.view(agent).get(parsed.name); + if (command === void 0) return void 0; + if (signal.aborted) throw abortError(signal); + const commandId = this.mintCommandId(); + this.appendLifecycle(agent.session, "command/run", { + commandId, + name: parsed.name, + ...command.definition.recordInput === false ? {} : { args: parsed.rawInput }, + source: { kind: "user" } + }); + const invocation = Object.freeze({ + commandId, + agent, + rawInput: parsed.rawInput, + signal + }); + let result; + try { + const output = command.definition.handler(invocation); + result = normalizeResult(parsed.name, await withAbort(Promise.resolve(output), signal)); + } catch (error) { + try { + this.appendLifecycle(agent.session, "command/done", { + commandId, + kind: "error", + text: error instanceof Error ? error.message : renderThrown(error) + }); + } catch (appendError) { + this.ctx.logger.warn(`command "${parsed.name}": command/done append failed: ${renderThrown(appendError)}`); + } + throw error; + } + this.appendLifecycle(agent.session, "command/done", { + commandId, + kind: result.kind, + ...result.text === void 0 ? {} : { text: result.text }, + ...result.kind === "success" && result.sourceEventSeq !== void 0 ? { sourceEventSeq: result.sourceEventSeq } : {} + }); + return Object.freeze({ + commandId, + result + }); + } + /** Mint the next pairing id (monotonic; instance-token-prefixed so a resumed log never repeats one). */ + mintCommandId() { + this.commandSeq += 1; + return CommandId(`cmd-${this.instanceToken}-${this.commandSeq}`); + } + /** + * Append one log-only lifecycle event directly: no turn is opened for it and + * no flush is forced — persistence observes the eager `session/event` path + * and drains at ordinary checkpoints and teardown, like every other + * standalone plugin event. + */ + appendLifecycle(session, type, data) { + return session.append.bind(session)(type, data); + } + /** Resolve global definitions followed by exact scoped shadows. */ + view(agent) { + return this.layers.merge(agent, (layer) => layer.commands); + } + /** Notify every registry observer without making UI refresh load-bearing. */ + notifyChange() { + for (const callback of this.ctx.events.dispatch("emit", ["commands/change"])) try { + const returned = callback(); + Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`commands/change listener rejected: ${renderThrown(error)}`); + }); + } catch (error) { + this.ctx.logger.warn(`commands/change listener threw: ${renderThrown(error)}`); + } + } + }; +})(); +//#endregion +export { CommandId, CommandRuntime, CommandRuntime as default, name, parseCommand }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/invariant.js new file mode 100644 index 0000000..c26fe24 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/invariant.js @@ -0,0 +1,43 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-commands`: +* command lifecycle events pair by commandId within one session log. +* @module @deepseek-ai/dsh-commands/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-commands"; +/** Cordis companion plugin name. */ +const name = "commands-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Install pairing validation over loaded logs and newly appended lifecycle events. */ +const install = Object.assign((ctx, fail) => { + const runIds = /* @__PURE__ */ new WeakMap(); + const validateEvent = (session, event) => { + if (event.type === "command/run") { + const ids = runIds.get(session) ?? /* @__PURE__ */ new Set(); + if (ids.has(event.data.commandId)) fail(`command/run repeats commandId ${JSON.stringify(event.data.commandId)}`); + ids.add(event.data.commandId); + runIds.set(session, ids); + return; + } + if (event.type !== "command/done") return; + if (runIds.get(session)?.has(event.data.commandId) !== true) fail(`command/done ${JSON.stringify(event.data.commandId)} pairs no prior command/run in this log`); + const source = event.data.sourceEventSeq; + const sourceEvent = source === void 0 ? void 0 : session.events[source]; + if (source !== void 0 && (event.data.kind !== "success" || !Number.isSafeInteger(source) || source < 0 || source >= event.seq || sourceEvent?.seq !== source || sourceEvent.type === "command/run" || sourceEvent.type === "command/done")) fail(`command/done ${JSON.stringify(event.data.commandId)} has invalid sourceEventSeq ${String(source)}`); + }; + for (const session of ctx.sessions.list()) for (const event of session.events) validateEvent(session, event); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName !== "session/event") return; + const [session, event] = args; + validateEvent(session, event); + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.d.ts new file mode 100644 index 0000000..dcf4919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.d.ts @@ -0,0 +1,3 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ + +export declare const TYPERT: unknown diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.js new file mode 100644 index 0000000..5f3d645 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.js @@ -0,0 +1,502 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema = z.string() +const _deepseek_ai_dsh_commands_commands_execute_result$schema = z.union([z.undefined(), z.object({ + 'commandId': z.intersection(z.string(), z.unknown()).readonly(), + 'result': z.union([z.object({ + 'kind': z.literal("success").readonly(), + 'text': z.string().readonly().optional(), + 'sourceEventSeq': z.number().readonly().optional(), +}), z.object({ + 'kind': z.literal("error").readonly(), + 'text': z.string().readonly(), +})]).readonly(), +})]) +const _deepseek_ai_dsh_commands_commands_list_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_commands_commands_list_result$schema = z.array(z.object({ + 'name': z.string().readonly(), + 'description': z.string().readonly(), + 'input': z.object({ + 'hint': z.string().readonly(), +}).readonly().optional(), +})) + +export const TYPERT = { + package: '@deepseek-ai/dsh-commands', + face: 'host', + schemas: [ + ], + invocations: [ + { + id: '@deepseek-ai/dsh-commands#commands/execute', + service: 'commands', + namespace: 'commands', + method: 'execute', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema, + }, + }, + { + name: 'line', + wire: 'line', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/execute:line', + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema, + }, + }, + ], + cancellation: { parameter: 'signal' }, + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/execute:result', + schema: _deepseek_ai_dsh_commands_commands_execute_result$schema, + }, + sourceLocation: {"file":"packages/interaction/commands/src/index.ts","line":297,"column":9}, + }, + { + id: '@deepseek-ai/dsh-commands#commands/list', + service: 'commands', + namespace: 'commands', + method: 'list', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_commands_commands_list_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/list:result', + schema: _deepseek_ai_dsh_commands_commands_list_result$schema, + }, + sourceLocation: {"file":"packages/interaction/commands/src/index.ts","line":260,"column":3}, + }, + ], + model: { + "services": [ + { + "description": "Human-command registry. Plain-context definitions are global; definitions registered through a command-injected child of an agent context shadow globals for that agent.", + "summary": "Human-command registry.", + "tags": [], + "jsDoc": "/**\n * Human-command registry. Plain-context definitions are global; definitions\n * registered through a command-injected child of an agent context shadow\n * globals for that agent.\n */", + "key": "commands", + "exportName": "CommandRuntime", + "members": [ + { + "kind": "method", + "name": "register", + "signature": "register(definition: CommandDefinition): () => void", + "summary": "Register a global or calling-agent-scoped command.", + "jsDoc": "/**\n * Register a global or calling-agent-scoped command.\n * @param definition - discovery metadata and direct UI handler.\n * @returns the exact effect disposer that unregisters this definition.\n */" + }, + { + "kind": "method", + "name": "list", + "signature": "@Remote list(agent: Agent): readonly CommandDescriptor[]", + "summary": "List the effective immutable command descriptors for one agent.", + "jsDoc": "/**\n * List the effective immutable command descriptors for one agent.\n * @param agent - exact receiving agent and scoped-layer key.\n * @returns name-sorted descriptors after scoped shadowing.\n */" + }, + { + "kind": "method", + "name": "find", + "signature": "find(agent: Agent, name: string): CommandDefinition | undefined", + "summary": "Resolve one effective command definition.", + "jsDoc": "/**\n * Resolve one effective command definition.\n * @param agent - exact receiving agent and scoped-layer key.\n * @param name - command name without a slash.\n * @returns the scoped shadow or global definition.\n */" + }, + { + "kind": "method", + "name": "execute", + "signature": "@Remote async execute( agent: Agent, line: string, signal: AbortSignal, ): Promise", + "summary": "Parse and execute a known command without sending it to the model.", + "jsDoc": "/**\n * Parse and execute a known command without sending it to the model.\n *\n * A resolved command's lifecycle is logged: `command/run` is appended\n * before the handler is invoked and `command/done` after settlement (a\n * thrown or aborted handler settles as `kind: 'error'`). Both are direct\n * log-only appends — no turn wraps them, and persistence drains them at\n * ordinary checkpoints. Admission misses (syntax or unknown name) log\n * nothing — they never entered a handler. A `command/run` append failure\n * fails the execution loud; a `command/done` append failure on the\n * handler-failure path is contained so the handler's own error stays the\n * reported failure.\n *\n * @param agent - exact receiving agent.\n * @param line - complete slash-command line.\n * @param signal - cancellation signal owned by the UI request.\n * @returns the settled execution (result + lifecycle pairing id), or\n * `undefined` when syntax or name does not resolve.\n */" + } + ], + "types": [ + { + "name": "Agent", + "declaration": "export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly inbox: Inbox;\n readonly status: AgentStatus;\n readonly ctx: Context;\n cancel(cause: AgentCancelCause, options?: CancelOptions): void;\n whenIdle(): Promise;\n runMaintenance(task: (signal: AbortSignal) => Promise): Promise;\n send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;\n followup(message: UserMessage): void;\n steer(message: UserMessage): void;\n inject(message: UserMessage): void;\n}" + }, + { + "name": "AgentCancelCause", + "declaration": "export type AgentCancelCause = { readonly kind: 'user'; } | { readonly kind: 'parent'; } | { readonly kind: 'hook'; readonly reason: string; } | { readonly kind: 'disposed'; };" + }, + { + "name": "AgentOptions", + "declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n maxTokens?: number;\n}" + }, + { + "name": "AgentStatus", + "declaration": "export type AgentStatus = 'idle' | 'running';" + }, + { + "name": "ApprovalOutcome", + "declaration": "export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';" + }, + { + "name": "ApprovalPolicy", + "declaration": "export type ApprovalPolicy = 'ask' | 'never';" + }, + { + "name": "ApprovalRequestId", + "declaration": "export type ApprovalRequestId = Branded<'ApprovalRequestId'>;" + }, + { + "name": "AssistantMessage", + "declaration": "export interface AssistantMessage extends Message {\n readonly role: 'assistant';\n readonly source: ModelMessageSource;\n}" + }, + { + "name": "AssistantProvenance", + "declaration": "export interface AssistantProvenance {\n provider: string;\n model: string;\n replayState?: unknown;\n}" + }, + { + "name": "AttachmentId", + "declaration": "export type AttachmentId = Branded<'AttachmentId'>;" + }, + { + "name": "Branded", + "declaration": "export type Branded = string & { readonly [BRAND]: B; };" + }, + { + "name": "CallId", + "declaration": "export type CallId = Branded<'CallId'>;" + }, + { + "name": "CancelOptions", + "declaration": "export interface CancelOptions {\n keepInbox?: boolean | undefined;\n}" + }, + { + "name": "CodeDispatchEventData", + "declaration": "export interface CodeDispatchEventData extends CodeDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}" + }, + { + "name": "CodeDispatchStartEventData", + "declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}" + }, + { + "name": "CommandDefinition", + "declaration": "export interface CommandDefinition {\n readonly name: string;\n readonly description: string;\n readonly input?: CommandInputDescriptor;\n readonly recordInput?: boolean;\n readonly handler: (invocation: CommandInvocation) => CommandResult | Promise;\n}" + }, + { + "name": "CommandDescriptor", + "declaration": "export interface CommandDescriptor {\n readonly name: string;\n readonly description: string;\n readonly input?: CommandInputDescriptor;\n}" + }, + { + "name": "CommandExecution", + "declaration": "export interface CommandExecution {\n readonly commandId: CommandId;\n readonly result: CommandResult;\n}" + }, + { + "name": "CommandId", + "declaration": "export type CommandId = Branded<'CommandId'>;" + }, + { + "name": "CommandInputDescriptor", + "declaration": "export interface CommandInputDescriptor {\n readonly hint: string;\n}" + }, + { + "name": "CommandInvocation", + "declaration": "export interface CommandInvocation {\n readonly commandId: CommandId;\n readonly agent: Agent;\n readonly rawInput: string;\n readonly signal: AbortSignal;\n}" + }, + { + "name": "CommandResult", + "declaration": "export type CommandResult = { readonly kind: 'success'; readonly text?: string; readonly sourceEventSeq?: number; } | { readonly kind: 'error'; readonly text: string; };" + }, + { + "name": "CommandSource", + "declaration": "export type CommandSource = CommandSourceMap[keyof CommandSourceMap];" + }, + { + "name": "CommandSourceMap", + "declaration": "export interface CommandSourceMap {\n user: { kind: 'user'; };\n}" + }, + { + "name": "ContentBlock", + "declaration": "export type ContentBlock = ContentBlockMap[ContentBlockType];" + }, + { + "name": "ContentBlockMap", + "declaration": "export interface ContentBlockMap {\n text: TextBlock;\n reasoning: ReasoningBlock;\n image: ImageBlock;\n 'tool-call': ToolCallBlock;\n 'tool-result': ToolResultBlock;\n}" + }, + { + "name": "ContentBlockType", + "declaration": "export type ContentBlockType = keyof ContentBlockMap;" + }, + { + "name": "ContextFormed", + "declaration": "export type ContextFormed = { readonly form?: never; } | { readonly form: 'instructions'; } | { readonly form: 'catalog'; } | { readonly form: 'snapshot'; readonly sections: readonly ContextSnapshotSection[]; } | { readonly form: 'notice'; readonly summary: string; } | { readonly form: 'relay'; } | { readonly form: 'recall'; };" + }, + { + "name": "ContextSnapshotSection", + "declaration": "export interface ContextSnapshotSection {\n readonly name: string;\n readonly text: string;\n}" + }, + { + "name": "EpochHeader", + "declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n system?: string;\n tools?: ToolSchema[];\n}" + }, + { + "name": "FinishReason", + "declaration": "export type FinishReason = FinishReasonMap[keyof FinishReasonMap];" + }, + { + "name": "FinishReasonMap", + "declaration": "export interface FinishReasonMap {\n stop: { kind: 'stop'; };\n 'tool-calls': { kind: 'tool-calls'; };\n 'max-tokens': { kind: 'max-tokens'; };\n aborted: { kind: 'aborted'; failure: LlmFailure; };\n error: { kind: 'error'; failure: LlmFailure; };\n}" + }, + { + "name": "GoalBlockReason", + "declaration": "export interface GoalBlockReason {\n readonly code: string;\n readonly message: string;\n}" + }, + { + "name": "GoalChangeMeta", + "declaration": "export type GoalChangeMeta = GoalSnapshotChangeMeta | GoalClearChangeMeta;" + }, + { + "name": "GoalClearChangeMeta", + "declaration": "export interface GoalClearChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: 'clear';\n readonly cleared: GoalRef;\n readonly clearedAt: number;\n}" + }, + { + "name": "GoalId", + "declaration": "export type GoalId = Branded<'GoalId'>;" + }, + { + "name": "GoalMessageSource", + "declaration": "export interface GoalMessageSource {\n readonly kind: 'goal';\n readonly goalId: GoalId;\n readonly revision: number;\n readonly round: number;\n}" + }, + { + "name": "GoalOperation", + "declaration": "export type GoalOperation = 'create' | 'edit' | 'pause' | 'resume' | 'complete' | 'block' | 'clear';" + }, + { + "name": "GoalPhase", + "declaration": "export type GoalPhase = 'active' | 'paused' | 'blocked' | 'complete';" + }, + { + "name": "GoalRef", + "declaration": "export interface GoalRef {\n readonly id: GoalId;\n readonly revision: number;\n}" + }, + { + "name": "GoalSnapshot", + "declaration": "export interface GoalSnapshot extends GoalRef {\n readonly objective: string;\n readonly phase: GoalPhase;\n readonly blockedReason?: GoalBlockReason;\n readonly maxGoalRounds: number;\n}" + }, + { + "name": "GoalSnapshotChangeMeta", + "declaration": "export interface GoalSnapshotChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: Exclude;\n readonly goal: GoalSnapshot;\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n}" + }, + { + "name": "ImageAttachmentRef", + "declaration": "export interface ImageAttachmentRef {\n attachmentId: AttachmentId;\n mediaType: ImageMediaType;\n bytes: number;\n width: number;\n height: number;\n name?: string;\n}" + }, + { + "name": "ImageBlock", + "declaration": "export interface ImageBlock {\n type: 'image';\n attachment: ImageAttachmentRef;\n}" + }, + { + "name": "ImageMediaType", + "declaration": "export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';" + }, + { + "name": "Inbox", + "declaration": "export class Inbox {\n get nextTurn(): readonly UserMessage[];\n get nextStep(): readonly UserMessage[];\n get hasPending(): boolean;\n clear(): void;\n claim(target: InboxTarget, turn: number): UserMessage[];\n append(target: InboxTarget, message: UserMessage): void;\n prepend(target: InboxTarget, message: UserMessage): void;\n replace(messageId: MessageId, newMessage: UserMessage): boolean;\n remove(messageId: MessageId): boolean;\n splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[];\n}" + }, + { + "name": "InboxTarget", + "declaration": "export type InboxTarget = 'next-turn' | 'next-step';" + }, + { + "name": "JsonValue", + "declaration": "export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue; };" + }, + { + "name": "LlmCallConfig", + "declaration": "export interface LlmCallConfig {\n provider: string;\n model: string;\n reasoningEffort?: ReasoningEffortId;\n temperature?: number;\n maxTokens?: number;\n stop?: string[];\n}" + }, + { + "name": "LlmCallConfigAdapterDefaults", + "declaration": "export interface LlmCallConfigAdapterDefaults {\n reasoningEffort?: true;\n maxTokens?: true;\n}" + }, + { + "name": "LlmFailure", + "declaration": "export interface LlmFailure {\n readonly message: string;\n readonly code: string;\n readonly status?: number;\n readonly providerRetryAfterMs?: number;\n readonly requestId?: ProviderRequestId;\n}" + }, + { + "name": "Message", + "declaration": "export interface Message {\n readonly id: MessageId;\n readonly role: 'system' | 'user' | 'assistant';\n readonly content: ContentBlock[];\n readonly source: MessageSource;\n}" + }, + { + "name": "MessageId", + "declaration": "export type MessageId = Branded<'MessageId'>;" + }, + { + "name": "MessageSource", + "declaration": "export type MessageSource = MessageSourceMap[keyof MessageSourceMap];" + }, + { + "name": "MessageSourceMap", + "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n goal: GoalMessageSource;\n}" + }, + { + "name": "ModelMessageSource", + "declaration": "export interface ModelMessageSource extends AssistantProvenance {\n kind: 'model';\n}" + }, + { + "name": "ProviderRequestId", + "declaration": "export type ProviderRequestId = Branded<'ProviderRequestId'>;" + }, + { + "name": "ReasoningBlock", + "declaration": "export interface ReasoningBlock {\n type: 'reasoning';\n text: string;\n}" + }, + { + "name": "ReasoningEffortId", + "declaration": "export type ReasoningEffortId = Branded<'ReasoningEffortId'>;" + }, + { + "name": "RequestContext", + "declaration": "export interface RequestContext {\n provider: string;\n model: string;\n contextWindow?: number;\n}" + }, + { + "name": "RequestHeaderReason", + "declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change';" + }, + { + "name": "Session", + "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n get id(): SessionId;\n readonly firstLiveSeq: number;\n get events(): readonly SessionEvent[];\n get seq(): number;\n append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}" + }, + { + "name": "SessionEvent", + "declaration": "export type SessionEvent = { [K in SessionEventType]: { type: K; seq: number; time: number; data: SessionEventMap[K]; ignorable?: true; } & (K extends SurfaceEventType ? { sourceEventSeqs?: number[]; surfaceOp?: SurfaceOp; } : object) }[T];" + }, + { + "name": "SessionEventMap", + "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: number; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n 'goal/change': GoalChangeMeta;\n}" + }, + { + "name": "SessionEventType", + "declaration": "export type SessionEventType = keyof SessionEventMap;" + }, + { + "name": "SessionHeader", + "declaration": "export interface SessionHeader {\n readonly version: number;\n readonly id: SessionId;\n readonly createdAt: number;\n readonly cwd?: string;\n readonly parentSession?: SessionId;\n readonly seedLength?: number;\n readonly origin?: 'subagent';\n readonly delegationDepth?: number;\n readonly agentPreset?: string;\n}" + }, + { + "name": "SessionId", + "declaration": "export type SessionId = Branded<'SessionId'>;" + }, + { + "name": "SessionSurface", + "declaration": "export interface SessionSurface {\n readonly nodes: readonly number[];\n readonly replaceGeneration: number;\n}" + }, + { + "name": "StreamChunk", + "declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: unknown; };" + }, + { + "name": "SurfaceEventType", + "declaration": "export type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result';" + }, + { + "name": "SurfaceIntent", + "declaration": "export interface SurfaceIntent {\n surfaceOp: SurfaceOp;\n sourceEventSeqs?: number[];\n}" + }, + { + "name": "SurfaceOp", + "declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: number; end: number; };" + }, + { + "name": "TextBlock", + "declaration": "export interface TextBlock {\n type: 'text';\n text: string;\n}" + }, + { + "name": "TodoItem", + "declaration": "export interface TodoItem {\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n}" + }, + { + "name": "TokenUsage", + "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}" + }, + { + "name": "ToolCallBlock", + "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: CallId;\n name: string;\n arguments: string;\n}" + }, + { + "name": "ToolMessageSource", + "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: CallId;\n}" + }, + { + "name": "ToolResultBlock", + "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: CallId;\n content: ContentBlock[];\n isError?: boolean;\n}" + }, + { + "name": "ToolResultMessage", + "declaration": "export interface ToolResultMessage extends Message {\n readonly role: 'user';\n readonly content: [ToolResultBlock];\n readonly source: ToolMessageSource;\n}" + }, + { + "name": "ToolSchema", + "declaration": "export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n}" + }, + { + "name": "TurnEndCancelCause", + "declaration": "export type TurnEndCancelCause = AgentCancelCause | { readonly kind: 'legacy'; };" + }, + { + "name": "TurnEndReason", + "declaration": "export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap];" + }, + { + "name": "TurnEndReasonMap", + "declaration": "export interface TurnEndReasonMap {\n completed: { kind: 'completed'; };\n aborted: { kind: 'aborted'; reason: TurnEndCancelCause; };\n blocked: { kind: 'blocked'; };\n error: { kind: 'error'; error: LlmFailure; };\n 'max-tokens': { kind: 'max-tokens'; };\n interrupted: { kind: 'interrupted'; };\n}" + }, + { + "name": "UserMessage", + "declaration": "export interface UserMessage extends Message {\n readonly role: 'user';\n}" + } + ] + } + ], + "events": [ + { + "description": "A command was registered or unregistered. This is an unfiltered registry notification because a global or scoped change may affect any UI view. Observer failures are contained and cannot veto the registry mutation.", + "summary": "A command was registered or unregistered.", + "tags": [ + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * A command was registered or unregistered. This is an unfiltered registry\n * notification because a global or scoped change may affect any UI view.\n * Observer failures are contained and cannot veto the registry mutation.\n * @mode emit\n */", + "name": "commands/change", + "mode": "emit", + "signature": "'commands/change'(): void" + } + ], + "objects": [] + }, +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.d.ts new file mode 100644 index 0000000..9407c56 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.d.ts @@ -0,0 +1,29 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import type { + RemoteResult, + TypertRemoteContribution, +} from '@deepseek-ai/dsh-typert-protocol' +import type { CommandDescriptor, CommandExecution } from '@deepseek-ai/dsh-commands/types' +import type { SessionId } from '@deepseek-ai/dsh-session/types' + +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteNamespace$636f6d6d616e6473 { + execute: (agentId: SessionId, line: string, signal?: AbortSignal) => Promise> + list: (agentId: SessionId) => Promise> + } + interface TypertRemoteMap { + 'commands/execute': (agentId: SessionId, line: string, signal?: AbortSignal) => Promise> + 'commands/list': (agentId: SessionId) => Promise> + } + interface TypertRemoteNamespaceMap { + 'commands': TypertRemoteNamespace$636f6d6d616e6473 + } + interface TypertRemoteScopeMap { + 'agent:commands/execute': (line: string, signal?: AbortSignal) => Promise> + 'agent:commands/list': () => Promise> + } +} + +export declare const TYPERT_REMOTE: TypertRemoteContribution +export default TYPERT_REMOTE +//# sourceMappingURL=typert.remote-client.d.ts.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.js new file mode 100644 index 0000000..6abc29d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.js @@ -0,0 +1,103 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema = z.string() +const _deepseek_ai_dsh_commands_commands_execute_result$schema = z.union([z.undefined(), z.object({ + 'commandId': z.intersection(z.string(), z.unknown()).readonly(), + 'result': z.union([z.object({ + 'kind': z.literal("success").readonly(), + 'text': z.string().readonly().optional(), + 'sourceEventSeq': z.number().readonly().optional(), +}), z.object({ + 'kind': z.literal("error").readonly(), + 'text': z.string().readonly(), +})]).readonly(), +})]) +const _deepseek_ai_dsh_commands_commands_list_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_commands_commands_list_result$schema = z.array(z.object({ + 'name': z.string().readonly(), + 'description': z.string().readonly(), + 'input': z.object({ + 'hint': z.string().readonly(), +}).readonly().optional(), +})) + +export const TYPERT_REMOTE = { + package: '@deepseek-ai/dsh-commands', + descriptors: [ + { + id: '@deepseek-ai/dsh-commands#commands/execute', + service: 'commands', + namespace: 'commands', + method: 'execute', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema, + }, + }, + { + name: 'line', + wire: 'line', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/execute:line', + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema, + }, + }, + ], + cancellation: { parameter: 'signal' }, + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/execute:result', + schema: _deepseek_ai_dsh_commands_commands_execute_result$schema, + }, + sourceLocation: {"file":"packages/interaction/commands/src/index.ts","line":297,"column":9}, + }, + { + id: '@deepseek-ai/dsh-commands#commands/list', + service: 'commands', + namespace: 'commands', + method: 'list', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_commands_commands_list_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/list:result', + schema: _deepseek_ai_dsh_commands_commands_list_result$schema, + }, + sourceLocation: {"file":"packages/interaction/commands/src/index.ts","line":260,"column":3}, + }, + ], +} + +export default TYPERT_REMOTE diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.d.ts new file mode 100644 index 0000000..9dd6273 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.d.ts @@ -0,0 +1,25 @@ +/** + * dsh-commands' owned branded id: command lifecycle pairing across the + * session log, the wire admission response, and client-side flow pairing. + * + * The `Branded` primitive lives in `@deepseek-ai/dsh-brand`; this module + * is a pure type/constructor outlet (no cordis imports, no module + * augmentation) so wire and client programs can name the brand without + * loading the host plugin's Context merges — the `dsh-llm/brand` shape. + * + * @module @deepseek-ai/dsh-commands/brand + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** + * Pairs one command execution's `command/run`/`command/done` lifecycle + * records with each other and with the `command.execute` admission response. + * Minted by the executor, monotonic per service instance. + */ +export type CommandId = Branded<'CommandId'>; +/** + * Brand a string as a {@link CommandId}. + * @param id - the executor-minted pairing id. + * @returns the same string, branded; no validation is performed. + */ +export declare function CommandId(id: string): CommandId; +//# sourceMappingURL=brand.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.js new file mode 100644 index 0000000..bd43ee4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.js @@ -0,0 +1,20 @@ +/** + * dsh-commands' owned branded id: command lifecycle pairing across the + * session log, the wire admission response, and client-side flow pairing. + * + * The `Branded` primitive lives in `@deepseek-ai/dsh-brand`; this module + * is a pure type/constructor outlet (no cordis imports, no module + * augmentation) so wire and client programs can name the brand without + * loading the host plugin's Context merges — the `dsh-llm/brand` shape. + * + * @module @deepseek-ai/dsh-commands/brand + */ +/** + * Brand a string as a {@link CommandId}. + * @param id - the executor-minted pairing id. + * @returns the same string, branded; no validation is performed. + */ +export function CommandId(id) { + return id; +} +//# sourceMappingURL=brand.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/index.d.ts new file mode 100644 index 0000000..04b02fb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/index.d.ts @@ -0,0 +1,126 @@ +/** + * Plugin-owned human-command registry shared by interactive UI adapters. + * @module @deepseek-ai/dsh-commands + */ +import { Context } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'; +import { CommandId } from './brand.ts'; +import type { CommandDescriptor, CommandExecution, CommandInputDescriptor, CommandResult } from './types.ts'; +export { CommandId } from './brand.ts'; +export type * from './types.ts'; +export declare const name = "commands"; +/** Invocation passed to one registered command handler. */ +export interface CommandInvocation { + /** Pairing id already written to this invocation's `command/run` event. */ + readonly commandId: CommandId; + /** Exact agent whose UI received the command. */ + readonly agent: Agent; + /** Exact text following the registered command name, including separator whitespace. */ + readonly rawInput: string; + /** Cancellation signal owned by the dispatching UI request. */ + readonly signal: AbortSignal; +} +/** Plugin-owned command registration. */ +export interface CommandDefinition { + /** Lowercase command name without the leading slash. */ + readonly name: string; + /** Human-readable summary used in discovery UI. */ + readonly description: string; + /** Optional free-form input hint advertised to capable clients. */ + readonly input?: CommandInputDescriptor; + /** + * Whether `command/run` records `rawInput`. Defaults to true. A command + * whose domain event owns the payload sets this false to avoid duplicating + * that payload in the session log. + */ + readonly recordInput?: boolean; + /** Execute against the receiving agent without sending the command to the model. */ + readonly handler: (invocation: CommandInvocation) => CommandResult | Promise; +} +/** Syntactically valid slash command before registry resolution. */ +export interface ParsedCommand { + /** Lowercase command name without the leading slash. */ + readonly name: string; + /** Exact text following the command name. */ + readonly rawInput: string; +} +declare module '@deepseek-ai/cordis' { + interface Context { + commands: CommandRuntime; + } +} +/** + * Parse an exact slash command without normalizing its trailing input. + * + * @param line - Complete candidate command line. + * @returns The parsed command, or `undefined` when the line is not a command. + */ +export declare function parseCommand(line: string): ParsedCommand | undefined; +/** + * Human-command registry. Plain-context definitions are global; definitions + * registered through a command-injected child of an agent context shadow + * globals for that agent. + */ +export declare class CommandRuntime extends TypertRemoteService { + private readonly layers; + /** Monotonic per-instance counter behind {@link mintCommandId}. */ + private commandSeq; + /** Instance token keeping minted ids unique across process restarts over one resumed log. */ + private readonly instanceToken; + constructor(ctx: Context); + /** + * Register a global or calling-agent-scoped command. + * @param definition - discovery metadata and direct UI handler. + * @returns the exact effect disposer that unregisters this definition. + */ + register(definition: CommandDefinition): () => void; + /** + * List the effective immutable command descriptors for one agent. + * @param agent - exact receiving agent and scoped-layer key. + * @returns name-sorted descriptors after scoped shadowing. + */ + list(agent: Agent): readonly CommandDescriptor[]; + /** + * Resolve one effective command definition. + * @param agent - exact receiving agent and scoped-layer key. + * @param name - command name without a slash. + * @returns the scoped shadow or global definition. + */ + find(agent: Agent, name: string): CommandDefinition | undefined; + /** + * Parse and execute a known command without sending it to the model. + * + * A resolved command's lifecycle is logged: `command/run` is appended + * before the handler is invoked and `command/done` after settlement (a + * thrown or aborted handler settles as `kind: 'error'`). Both are direct + * log-only appends — no turn wraps them, and persistence drains them at + * ordinary checkpoints. Admission misses (syntax or unknown name) log + * nothing — they never entered a handler. A `command/run` append failure + * fails the execution loud; a `command/done` append failure on the + * handler-failure path is contained so the handler's own error stays the + * reported failure. + * + * @param agent - exact receiving agent. + * @param line - complete slash-command line. + * @param signal - cancellation signal owned by the UI request. + * @returns the settled execution (result + lifecycle pairing id), or + * `undefined` when syntax or name does not resolve. + */ + execute(agent: Agent, line: string, signal: AbortSignal): Promise; + /** Mint the next pairing id (monotonic; instance-token-prefixed so a resumed log never repeats one). */ + private mintCommandId; + /** + * Append one log-only lifecycle event directly: no turn is opened for it and + * no flush is forced — persistence observes the eager `session/event` path + * and drains at ordinary checkpoints and teardown, like every other + * standalone plugin event. + */ + private appendLifecycle; + /** Resolve global definitions followed by exact scoped shadows. */ + private view; + /** Notify every registry observer without making UI refresh load-bearing. */ + private notifyChange; +} +export default CommandRuntime; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js new file mode 100644 index 0000000..77db261 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js @@ -0,0 +1,343 @@ +/** + * Plugin-owned human-command registry shared by interactive UI adapters. + * @module @deepseek-ai/dsh-commands + */ +var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; +var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +import { NamedEntries, ScopedLayers } from '@deepseek-ai/dsh-scope'; +import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'; +import { CommandId } from "./brand.js"; +export { CommandId } from "./brand.js"; +export const name = 'commands'; +const COMMAND_NAME = /^[a-z][a-z0-9_-]*$/u; +/** All command registrations owned by one global or scoped layer. */ +class CommandLayer { + commands; + /** + * Create one command layer with diagnostics specific to its ownership scope. + * @param scope - the scoped owner, or `undefined` for global registrations. + */ + constructor(scope) { + this.commands = new NamedEntries(name => new Error(scope === undefined + ? `command "${name}" is already registered (for a per-agent variant, mount a command-injected plugin under that agent's \`agent.ctx\`)` + : `command "${name}" is already registered in this scope`)); + } + /** @returns whether this layer owns no command registrations. */ + isEmpty() { + return this.commands.isEmpty(); + } +} +/** + * Parse an exact slash command without normalizing its trailing input. + * + * @param line - Complete candidate command line. + * @returns The parsed command, or `undefined` when the line is not a command. + */ +export function parseCommand(line) { + const match = /^\/([a-z][a-z0-9_-]*)(?=$|[\t\n\r ])/u.exec(line); + if (match === null) + return undefined; + const name = match[1]; + /* v8 ignore next -- the first capture is required whenever the regular expression matches */ + if (name === undefined) + return undefined; + return Object.freeze({ name, rawInput: line.slice(match[0].length) }); +} +/** Convert arbitrary abort reasons to one stable rejected Error. */ +function abortError(signal) { + if (signal.reason instanceof Error) + return signal.reason; + return new Error(typeof signal.reason === 'string' ? signal.reason : 'command aborted'); +} +/** Render arbitrary thrown values without trusting their string coercion. */ +function renderThrown(value) { + try { + return String(value); + } + catch { + return ''; + } +} +/** Stop awaiting an uncooperative handler once its owning UI request aborts. */ +function withAbort(promise, signal) { + if (signal.aborted) + return Promise.reject(abortError(signal)); + return new Promise((resolve, reject) => { + const onAbort = () => { + signal.removeEventListener('abort', onAbort); + reject(abortError(signal)); + }; + signal.addEventListener('abort', onAbort, { once: true }); + promise.then((value) => { + signal.removeEventListener('abort', onAbort); + resolve(value); + }, (error) => { + signal.removeEventListener('abort', onAbort); + reject(error instanceof Error + ? error + : new Error(`command handler rejected with a non-Error value: ${renderThrown(error)}`, { cause: error })); + }); + }); +} +/** Reject invalid command metadata before it can reach a UI protocol. */ +function normalizeDefinition(definition) { + if (!COMMAND_NAME.test(definition.name)) { + throw new TypeError(`command name "${definition.name}" must match ${String(COMMAND_NAME)}`); + } + if (typeof definition.description !== 'string') { + throw new TypeError(`command "${definition.name}" description must be a string`); + } + if (definition.description.trim().length === 0) { + throw new TypeError(`command "${definition.name}" description must not be empty`); + } + if (typeof definition.handler !== 'function') { + throw new TypeError(`command "${definition.name}" handler must be a function`); + } + const rawInput = definition.input; + let input; + if (rawInput !== undefined) { + if (typeof rawInput !== 'object' || rawInput === null || !('hint' in rawInput) + || typeof rawInput.hint !== 'string') { + throw new TypeError(`command "${definition.name}" input hint must be a string`); + } + if (rawInput.hint.trim().length === 0) { + throw new TypeError(`command "${definition.name}" input hint must not be empty`); + } + input = Object.freeze({ hint: rawInput.hint }); + } + const normalized = Object.freeze({ + name: definition.name, + description: definition.description, + ...input === undefined ? {} : { input }, + ...definition.recordInput === undefined ? {} : { recordInput: definition.recordInput }, + handler: definition.handler, + }); + const descriptor = Object.freeze({ + name: normalized.name, + description: normalized.description, + ...normalized.input === undefined ? {} : { input: normalized.input }, + }); + return { definition: normalized, descriptor }; +} +/** Validate and detach an untrusted handler result at the registry boundary. */ +function normalizeResult(command, value) { + if (typeof value !== 'object' || value === null || !('kind' in value)) { + throw new TypeError(`command "${command}" handler must return a CommandResult`); + } + const result = value; + if (result.kind === 'success') { + if (result.text !== undefined && typeof result.text !== 'string') { + throw new TypeError(`command "${command}" success text must be a string when supplied`); + } + if (result.sourceEventSeq !== undefined + && (!Number.isSafeInteger(result.sourceEventSeq) || result.sourceEventSeq < 0)) { + throw new TypeError(`command "${command}" success sourceEventSeq must be a non-negative safe integer when supplied`); + } + return Object.freeze({ + kind: 'success', + ...result.text === undefined ? {} : { text: result.text }, + ...result.sourceEventSeq === undefined ? {} : { sourceEventSeq: result.sourceEventSeq }, + }); + } + if (result.kind === 'error') { + if (typeof result.text !== 'string' || result.text.trim().length === 0) { + throw new TypeError(`command "${command}" error text must be a non-empty string`); + } + return Object.freeze({ kind: 'error', text: result.text }); + } + throw new TypeError(`command "${command}" returned unknown result kind "${String(result.kind)}"`); +} +/** + * Human-command registry. Plain-context definitions are global; definitions + * registered through a command-injected child of an agent context shadow + * globals for that agent. + */ +let CommandRuntime = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + let _execute_decorators; + return class CommandRuntime extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote]; + _execute_decorators = [Remote]; + __esDecorate(this, null, _list_decorators, { kind: "method", name: "list", static: false, private: false, access: { has: obj => "list" in obj, get: obj => obj.list }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _execute_decorators, { kind: "method", name: "execute", static: false, private: false, access: { has: obj => "execute" in obj, get: obj => obj.execute }, metadata: _metadata }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + layers = (__runInitializers(this, _instanceExtraInitializers), new ScopedLayers(scope => new CommandLayer(scope), () => { this.notifyChange(); })); + /** Monotonic per-instance counter behind {@link mintCommandId}. */ + commandSeq = 0; + /** Instance token keeping minted ids unique across process restarts over one resumed log. */ + instanceToken = crypto.randomUUID().slice(0, 8); + constructor(ctx) { + super(ctx, 'commands'); + } + /** + * Register a global or calling-agent-scoped command. + * @param definition - discovery metadata and direct UI handler. + * @returns the exact effect disposer that unregisters this definition. + */ + register(definition) { + const registered = normalizeDefinition(definition); + return this.layers.effect(this.ctx, layer => layer.commands.insert(registered.definition.name, registered), { label: 'commands.register()' }); + } + /** + * List the effective immutable command descriptors for one agent. + * @param agent - exact receiving agent and scoped-layer key. + * @returns name-sorted descriptors after scoped shadowing. + */ + list(agent) { + return Object.freeze([...this.view(agent).values()] + .map(command => command.descriptor) + // Names are unique in the effective view, so equality is impossible. + .sort((left, right) => left.name < right.name ? -1 : 1)); + } + /** + * Resolve one effective command definition. + * @param agent - exact receiving agent and scoped-layer key. + * @param name - command name without a slash. + * @returns the scoped shadow or global definition. + */ + find(agent, name) { + return this.view(agent).get(name)?.definition; + } + /** + * Parse and execute a known command without sending it to the model. + * + * A resolved command's lifecycle is logged: `command/run` is appended + * before the handler is invoked and `command/done` after settlement (a + * thrown or aborted handler settles as `kind: 'error'`). Both are direct + * log-only appends — no turn wraps them, and persistence drains them at + * ordinary checkpoints. Admission misses (syntax or unknown name) log + * nothing — they never entered a handler. A `command/run` append failure + * fails the execution loud; a `command/done` append failure on the + * handler-failure path is contained so the handler's own error stays the + * reported failure. + * + * @param agent - exact receiving agent. + * @param line - complete slash-command line. + * @param signal - cancellation signal owned by the UI request. + * @returns the settled execution (result + lifecycle pairing id), or + * `undefined` when syntax or name does not resolve. + */ + async execute(agent, line, signal) { + const parsed = parseCommand(line); + if (parsed === undefined) + return undefined; + const command = this.view(agent).get(parsed.name); + if (command === undefined) + return undefined; + if (signal.aborted) + throw abortError(signal); + const commandId = this.mintCommandId(); + this.appendLifecycle(agent.session, 'command/run', { + commandId, + name: parsed.name, + ...command.definition.recordInput === false ? {} : { args: parsed.rawInput }, + source: { kind: 'user' }, + }); + const invocation = Object.freeze({ commandId, agent, rawInput: parsed.rawInput, signal }); + let result; + try { + const output = command.definition.handler(invocation); + result = normalizeResult(parsed.name, await withAbort(Promise.resolve(output), signal)); + } + catch (error) { + try { + this.appendLifecycle(agent.session, 'command/done', { + commandId, kind: 'error', + text: error instanceof Error ? error.message : renderThrown(error), + }); + } + catch (appendError) { + this.ctx.logger.warn(`command "${parsed.name}": command/done append failed: ${renderThrown(appendError)}`); + } + throw error; + } + this.appendLifecycle(agent.session, 'command/done', { + commandId, kind: result.kind, + ...result.text === undefined ? {} : { text: result.text }, + ...result.kind === 'success' && result.sourceEventSeq !== undefined + ? { sourceEventSeq: result.sourceEventSeq } + : {}, + }); + return Object.freeze({ commandId, result }); + } + /** Mint the next pairing id (monotonic; instance-token-prefixed so a resumed log never repeats one). */ + mintCommandId() { + this.commandSeq += 1; + return CommandId(`cmd-${this.instanceToken}-${this.commandSeq}`); + } + /** + * Append one log-only lifecycle event directly: no turn is opened for it and + * no flush is forced — persistence observes the eager `session/event` path + * and drains at ordinary checkpoints and teardown, like every other + * standalone plugin event. + */ + appendLifecycle(session, type, data) { + // Both admitted types are log-only (non-surface), but TypeScript does not + // reduce Session.append's conditional rest parameter through a generic + // type parameter. Preserve the proven two-argument call shape. + const appendLogOnly = session.append.bind(session); + return appendLogOnly(type, data); + } + /** Resolve global definitions followed by exact scoped shadows. */ + view(agent) { + return this.layers.merge(agent, layer => layer.commands); + } + /** Notify every registry observer without making UI refresh load-bearing. */ + notifyChange() { + // Cordis emit uses Array.map: one synchronous throw starves later listeners, + // and returned promises are discarded. Registry notifications are + // non-vetoing, so contain each callback independently. + for (const callback of this.ctx.events.dispatch('emit', ['commands/change'])) { + try { + const returned = callback(); + void Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`commands/change listener rejected: ${renderThrown(error)}`); + }); + } + catch (error) { + this.ctx.logger.warn(`commands/change listener threw: ${renderThrown(error)}`); + } + } + } + }; +})(); +export { CommandRuntime }; +export default CommandRuntime; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.d.ts new file mode 100644 index 0000000..7c2418b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.d.ts @@ -0,0 +1,17 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-commands`: + * command lifecycle events pair by commandId within one session log. + * @module @deepseek-ai/dsh-commands/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "commands-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.js new file mode 100644 index 0000000..6f99562 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.js @@ -0,0 +1,60 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-commands`: + * command lifecycle events pair by commandId within one session log. + * @module @deepseek-ai/dsh-commands/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-commands'; +/** Cordis companion plugin name. */ +export const name = 'commands-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/* jscpd:ignore-start -- package companions share replay and dispatch plumbing */ +/** Install pairing validation over loaded logs and newly appended lifecycle events. */ +const install = Object.assign((ctx, fail) => { + // Install-scoped so a dispose/re-register cycle re-sweeps from a clean slate. + const runIds = new WeakMap(); + const validateEvent = (session, event) => { + if (event.type === 'command/run') { + const ids = runIds.get(session) ?? new Set(); + if (ids.has(event.data.commandId)) { + fail(`command/run repeats commandId ${JSON.stringify(event.data.commandId)}`); + } + ids.add(event.data.commandId); + runIds.set(session, ids); + return; + } + if (event.type !== 'command/done') + return; + if (runIds.get(session)?.has(event.data.commandId) !== true) { + fail(`command/done ${JSON.stringify(event.data.commandId)} pairs no prior command/run in this log`); + } + const source = event.data.sourceEventSeq; + const sourceEvent = source === undefined ? undefined : session.events[source]; + if (source !== undefined + && (event.data.kind !== 'success' + || !Number.isSafeInteger(source) || source < 0 || source >= event.seq + || sourceEvent?.seq !== source + || sourceEvent.type === 'command/run' + || sourceEvent.type === 'command/done')) { + fail(`command/done ${JSON.stringify(event.data.commandId)} has invalid sourceEventSeq ${String(source)}`); + } + }; + for (const session of ctx.sessions.list()) { + for (const event of session.events) + validateEvent(session, event); + } + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') + return; + const [session, event] = args; + validateEvent(session, event); + }, { global: true }); +}, { inject: ['sessions'] }); +/* jscpd:ignore-end */ +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/types.d.ts new file mode 100644 index 0000000..ec5e83d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/types.d.ts @@ -0,0 +1,102 @@ +/** + * Durable command event vocabulary and the registry's Cordis event + * declaration, shared with type-only consumers. Client-safe: nothing here + * reaches a Host-only symbol, so a Client compilation face reads the same + * `commands/change` signature the Host emits. + * + * @module @deepseek-ai/dsh-commands/types + */ +import type { CommandId } from './brand.ts'; +/** Immutable metadata for a command's optional unstructured input. */ +export interface CommandInputDescriptor { + /** Placeholder shown before the user supplies free-form input. */ + readonly hint: string; +} +/** Expected command outcome rendered directly by the dispatching UI. */ +export type CommandResult = { + readonly kind: 'success'; + readonly text?: string; + /** Earlier authoritative domain event that owns a richer presentation. */ + readonly sourceEventSeq?: number; +} | { + readonly kind: 'error'; + readonly text: string; +}; +/** + * One settled command execution: the handler's normalized result plus the + * lifecycle pairing id minted for its `command/run`/`command/done` records, + * so a dispatching surface can correlate the Remote acknowledgment with the + * flow node those events produce. + */ +export interface CommandExecution { + /** Pairing id carried by this execution's lifecycle events. */ + readonly commandId: CommandId; + /** The handler's normalized outcome. */ + readonly result: CommandResult; +} +/** Handler-free immutable command view returned to UI adapters. */ +export interface CommandDescriptor { + /** Lowercase command name without the leading slash. */ + readonly name: string; + /** Human-readable summary used in discovery UI. */ + readonly description: string; + /** Optional free-form input hint advertised to capable clients. */ + readonly input?: CommandInputDescriptor; +} +/** + * Producer record for one command invocation (the `command/run` event's + * source slot). Merge-extensible sum type mirroring `MessageSourceMap`'s + * shape; minimal today because every executor caller is a human-facing UI + * surface dispatching a human-typed line, so the sole variant is `user`. + */ +export interface CommandSourceMap { + user: { + kind: 'user'; + }; +} +/** The union over {@link CommandSourceMap} — who issued a command line. */ +export type CommandSource = CommandSourceMap[keyof CommandSourceMap]; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * A command was registered or unregistered. This is an unfiltered registry + * notification because a global or scoped change may affect any UI view. + * Observer failures are contained and cannot veto the registry mutation. + * @mode emit + */ + 'commands/change'(): void; + } +} +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * A resolved slash command entered its handler. Log-only (never model + * surface); paired with `command/done` by `commandId`, mirroring the + * `tool/call`↔`tool/result` pairing. The payload is structured — `name` + * and `args` are `parseCommand`'s own split (name and verbatim rawInput, + * separator whitespace included), so a consumer (a projection unit + * folding its own command records, a rich command card) never re-parses + * a line. `args` is absent when the definition sets `recordInput: false` + * because an authoritative domain event owns the input payload. + */ + 'command/run': { + commandId: CommandId; + name: string; + args?: string; + source: CommandSource; + }; + /** + * The paired command settled. `kind`/`text` carry the handler's verbatim + * outcome (a thrown/aborted handler settles as `kind: 'error'` with the + * rendered failure). A successful command may identify the earlier + * authoritative domain event for a richer client-computed presentation. + */ + 'command/done': { + commandId: CommandId; + kind: 'success' | 'error'; + text?: string; + sourceEventSeq?: number; + }; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/types.js new file mode 100644 index 0000000..14b7acc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/lib/types/types.js @@ -0,0 +1,10 @@ +/** + * Durable command event vocabulary and the registry's Cordis event + * declaration, shared with type-only consumers. Client-safe: nothing here + * reaches a Host-only symbol, so a Client compilation face reads the same + * `commands/change` signature the Host emits. + * + * @module @deepseek-ai/dsh-commands/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/package.json new file mode 100644 index 0000000..3c41844 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands/package.json @@ -0,0 +1,76 @@ +{ + "name": "@deepseek-ai/dsh-commands", + "description": "Plugin-owned human command registry for DeepSeek Harness UIs", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/interaction/commands" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./brand": { + "types": "./lib/types/brand.d.ts", + "default": "./lib/types/brand.js" + }, + "./typert": { + "types": "./lib/typert.host.d.ts", + "default": "./lib/typert.host.js" + }, + "./remote": { + "types": "./lib/typert.remote-client.d.ts", + "default": "./lib/typert.remote-client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts", + "lib/typert.host.js", + "lib/typert.host.d.ts", + "lib/typert.remote-client.js", + "lib/typert.remote-client.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "zod": "^4.4.3" + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..aa2ae83 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.i18n.yaml new file mode 100644 index 0000000..9a53413 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/interaction/commands/README.md +README.md: e1d7e5f4f626d062a16840bce6354ee3aac921c9 +README.zh.md: 6ce3ca9016e26537003ba85e0b2217bd37448fc5 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.md new file mode 100644 index 0000000..e1d7e5f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.md @@ -0,0 +1,40 @@ +# @deepseek-ai/dsh-commands + +English | [中文](README.zh.md) + +Plugin-owned human-command registry consumed by interactive UI adapters. The [plugin command registration Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-plugin-command-registration.md) owns the boundary and dispatch contract. + +## Service contract + +`ctx.commands.register(definition)` registers one lowercase command name, description, optional unstructured-input hint, optional `recordInput` policy, and abortable handler. `recordInput` defaults to true; a command whose authoritative domain event owns the payload sets it to false so `command/run` omits `args` instead of duplicating the input. A registered command is available to every composed command adapter; a plugin that is incompatible with a deployment does not register there. A plain-context registration is global. A command-producing plugin mounted beneath `agent.ctx` declares its own `commands` injection and creates an exact agent-scoped definition; it shadows a global definition with the same name. This child-injection shape preserves the agent scope without making the core agent loop depend on a UI service. Duplicate names within one layer fail during registration. Every disposer is the exact Cordis effect disposer, and registration or removal notifies every `commands/change` observer so live adapters can refresh discovery; observer failures are logged and cannot veto the registry mutation or starve later observers. + +`list(agent)` returns immutable, name-sorted descriptors after scoped shadowing. `find(agent, name)` returns the corresponding definition. `execute(agent, line, signal)` uses `parseCommand()` and runs only a known command, returning the settled `CommandExecution` (the normalized result plus the lifecycle pairing `commandId`) or `undefined` for invalid syntax or unknown names. A resolved command's lifecycle is logged on the receiving agent's session as the log-only pair `command/run` (before the handler, with a minted `commandId`, the parser's structured name, the issuing `CommandSource`, and `args` unless `recordInput` is false) and `command/done` (at settlement, with the outcome kind and verbatim text; a successful result may also name an earlier non-command authoritative domain event through `sourceEventSeq`; a thrown or aborted handler settles as `kind: 'error'`). Admission misses log nothing. Both are direct standalone appends on the receiving agent's session: no turn wraps them, and persistence drains them through ordinary checkpoints and teardown. + +`parseCommand()` recognizes a slash at byte zero, a lowercase name containing letters, digits, `_`, or `-`, and either end-of-input or whitespace. It returns every byte after the name as `rawInput`, including separator whitespace; consumers own their command-specific grammar and may normalize only what that grammar permits. + +Handlers return `success` or `error` plus optional UI text. A successful handler may also return `sourceEventSeq` when an earlier domain event owns a richer presentation; the lifecycle invariant requires that reference to be a prior non-command event in the same session. Results are rendered directly by the adapter and never enter model history. The registry never submits `rawInput` to the agent implicitly; a command producer may explicitly schedule model-visible work through the receiving `Agent`, in which case that producer owns the resulting message contract. The registry races handler completion against the supplied abort signal, but an uncooperative handler may continue its own external side effects after the caller stops awaiting it. + +## Composition + +The shipped `dsh` base mounts this service and the Web client dispatches through it. UI-less demo spines and ACP automation do not provide a command adapter. Custom interactive compositions and command producers mount `@deepseek-ai/dsh-commands` explicitly. + +## Model Experience + +### Direct human commands + +#### What the model sees + +The registry itself submits nothing. Known slash commands execute in the UI command plane, and their `CommandResult` text is not submitted as a user message. Unknown slash-command input is rejected by shipped adapters instead of becoming a model prompt. A command producer may explicitly use the receiving `Agent`; for example, [`dsh-plan-mode`](../../plan/plan-mode/README.md#model-and-human-interactions) submits the optional message in `/plan [message]` after selecting plan mode. + +#### Token effect + +Command discovery, execution, and UI output add no model tokens. Explicit agent work scheduled by a command producer has the same token effect as the corresponding agent input. + +#### KV Cache effect + +Registry metadata, command input, and direct output never enter a model request and do not affect its cache. A mutated domain owns any later cache effect. + +## Known Limitations and Deferred Work + +- **Only unstructured text input** — forms, completion schemas, and typed arguments remain command-owned parsing concerns. +- **Cooperative side-effect cancellation** — dispatch stops awaiting on abort; handlers must honor the signal to stop work that has already escaped into external systems. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.zh.md new file mode 100644 index 0000000..6ce3ca9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/README.zh.md @@ -0,0 +1,40 @@ +# @deepseek-ai/dsh-commands + +[English](README.md) | 中文 + +由插件负责、供交互式 UI 适配器使用的面向用户命令注册表。[插件命令注册 Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-plugin-command-registration.md)定义了其边界与分发约定。 + +## 服务约定 + +`ctx.commands.register(definition)` 注册一个小写命令名称、描述、可选的非结构化输入提示、可选的 `recordInput` 策略,以及可中止的处理器。`recordInput` 默认为 true;若载荷由命令的权威领域事件持有,该命令会将 `recordInput` 设为 false,让 `command/run` 省略 `args`,避免重复记录输入。每个已注册命令都可供所有已组合的命令适配器使用;与某项部署不兼容的插件不会在此注册。普通上下文中的注册全局生效。在 `agent.ctx` 下挂载的命令生产插件会声明自身的 `commands` 注入,并创建精确限定到该 agent(智能体)的定义;该定义会遮蔽同名的全局定义。这种子级注入形态保留了 agent 作用域,同时不会让核心 agent loop(智能体循环)依赖 UI 服务。同一层中的名称重复会在注册时失败。每个 disposer 都是 Cordis effect 返回的确切 disposer;注册或移除命令时,系统会通知每个 `commands/change` 观察者,使运行中的适配器能够刷新发现结果。观察者失败会写入日志,既不能否决注册表变更,也不能阻止后续观察者运行。 + +`list(agent)` 在应用作用域遮蔽后,返回按名称排序的不可变描述符。`find(agent, name)` 返回相应定义。`execute(agent, line, signal)` 使用 `parseCommand()`,且只运行已知命令,返回已结算的 `CommandExecution`(规范化结果加生命周期配对 `commandId`);语法无效或名称未知时返回 `undefined`。已解析命令的生命周期会以 log-only 事件对的形式记录在接收 agent 的会话日志中:`command/run`(进入处理器前记录,携带新生成的 `commandId`、解析器的结构化名称、发起方 `CommandSource`,以及 `args`(`recordInput` 为 false 时省略))与 `command/done`(结算时记录,携带结果类型与原样文本;成功结果还可通过 `sourceEventSeq` 指向更早的一条非命令权威领域事件;处理器抛出或被中止时以 `kind: 'error'` 结算)。未通过准入的输入不记录任何事件。两者都直接独立追加到接收 agent 的会话中:没有轮次包裹它们,持久化机制会在常规检查点和销毁期间排空这些事件。 + +`parseCommand()` 识别位于第 0 字节的斜杠、由小写字母、数字、`_` 或 `-` 构成的名称,以及名称后紧接输入末尾或空白的形式。它将名称后的每个字节作为 `rawInput` 返回,其中包括分隔空白;消费方负责各命令专用的语法,只能执行该语法允许的规范化。 + +处理器返回 `success` 或 `error`,并可附带 UI 文本。若更丰富的呈现由一条更早的领域事件持有,成功的处理器还可返回 `sourceEventSeq`;生命周期不变量要求该引用指向同一会话中更早的一条非命令事件。适配器直接渲染结果,结果绝不进入模型历史。注册表绝不会隐式地把 `rawInput` 提交给 agent;命令生产方可以通过接收命令的 `Agent` 显式安排模型可见工作,此时该生产方负责由此产生的消息约定。注册表会同时等待处理器完成和所提供的中止信号,以先发生者为准,但不响应中止的处理器可能在调用方停止等待后继续产生自身的外部副作用。 + +## 组合 + +随产品交付的 `dsh` 基础组合会挂载此服务,Web 客户端通过它分派命令。无 UI 的演示主干和 ACP(Agent Client Protocol)自动化不提供命令适配器。自定义交互式组合与命令生产方会显式挂载 `@deepseek-ai/dsh-commands`。 + +## 模型体验 + +### 直接面向用户的命令 + +#### 模型看到的内容 + +注册表自身不会提交任何内容。已知斜杠命令在 UI 命令平面执行,其 `CommandResult` 文本不会作为用户消息提交。已交付的适配器会拒绝未知斜杠命令输入,而不是将其变成模型提示词。命令生产方可以显式使用接收命令的 `Agent`;例如,[`dsh-plan-mode`](../../plan/plan-mode/README.md#model-and-human-interactions)在选择 plan mode 后,会提交 `/plan [message]` 中的可选消息。 + +#### Token 影响 + +命令发现、执行和 UI 输出不会增加模型 token。命令生产方显式安排的 agent 工作与相应 agent 输入具有相同的 token 影响。 + +#### KV Cache 影响 + +注册表元数据、命令输入和直接输出绝不会进入模型请求,也不会影响其缓存。发生变更的领域负责之后产生的所有缓存影响。 + +## 已知限制与暂缓事项 + +- **仅支持非结构化文本输入**:表单、补全 schema 和类型化参数仍由各命令自行解析。 +- **副作用采用协作式取消**:中止后,分发会停止等待;处理器必须遵循信号,才能停止已经进入外部系统的工作。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/index.js new file mode 100644 index 0000000..abfa641 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/index.js @@ -0,0 +1,360 @@ +import { NamedEntries, ScopedLayers } from "@deepseek-ai/dsh-scope"; +import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol"; +//#region lib/types/brand.js +/** +* dsh-commands' owned branded id: command lifecycle pairing across the +* session log, the wire admission response, and client-side flow pairing. +* +* The `Branded` primitive lives in `@deepseek-ai/dsh-brand`; this module +* is a pure type/constructor outlet (no cordis imports, no module +* augmentation) so wire and client programs can name the brand without +* loading the host plugin's Context merges — the `dsh-llm/brand` shape. +* +* @module @deepseek-ai/dsh-commands/brand +*/ +/** +* Brand a string as a {@link CommandId}. +* @param id - the executor-minted pairing id. +* @returns the same string, branded; no validation is performed. +*/ +function CommandId(id) { + return id; +} +//#endregion +//#region lib/types/index.js +/** +* Plugin-owned human-command registry shared by interactive UI adapters. +* @module @deepseek-ai/dsh-commands +*/ +var __runInitializers = function(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + return useValue ? value : void 0; +}; +var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function(f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +const name = "commands"; +const COMMAND_NAME = /^[a-z][a-z0-9_-]*$/u; +/** All command registrations owned by one global or scoped layer. */ +var CommandLayer = class { + commands; + /** + * Create one command layer with diagnostics specific to its ownership scope. + * @param scope - the scoped owner, or `undefined` for global registrations. + */ + constructor(scope) { + this.commands = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `command "${name}" is already registered (for a per-agent variant, mount a command-injected plugin under that agent's \`agent.ctx\`)` : `command "${name}" is already registered in this scope`)); + } + /** @returns whether this layer owns no command registrations. */ + isEmpty() { + return this.commands.isEmpty(); + } +}; +/** +* Parse an exact slash command without normalizing its trailing input. +* +* @param line - Complete candidate command line. +* @returns The parsed command, or `undefined` when the line is not a command. +*/ +function parseCommand(line) { + const match = /^\/([a-z][a-z0-9_-]*)(?=$|[\t\n\r ])/u.exec(line); + if (match === null) return void 0; + const name = match[1]; + /* v8 ignore next -- the first capture is required whenever the regular expression matches */ + if (name === void 0) return void 0; + return Object.freeze({ + name, + rawInput: line.slice(match[0].length) + }); +} +/** Convert arbitrary abort reasons to one stable rejected Error. */ +function abortError(signal) { + if (signal.reason instanceof Error) return signal.reason; + return new Error(typeof signal.reason === "string" ? signal.reason : "command aborted"); +} +/** Render arbitrary thrown values without trusting their string coercion. */ +function renderThrown(value) { + try { + return String(value); + } catch { + return ""; + } +} +/** Stop awaiting an uncooperative handler once its owning UI request aborts. */ +function withAbort(promise, signal) { + if (signal.aborted) return Promise.reject(abortError(signal)); + return new Promise((resolve, reject) => { + const onAbort = () => { + signal.removeEventListener("abort", onAbort); + reject(abortError(signal)); + }; + signal.addEventListener("abort", onAbort, { once: true }); + promise.then((value) => { + signal.removeEventListener("abort", onAbort); + resolve(value); + }, (error) => { + signal.removeEventListener("abort", onAbort); + reject(error instanceof Error ? error : new Error(`command handler rejected with a non-Error value: ${renderThrown(error)}`, { cause: error })); + }); + }); +} +/** Reject invalid command metadata before it can reach a UI protocol. */ +function normalizeDefinition(definition) { + if (!COMMAND_NAME.test(definition.name)) throw new TypeError(`command name "${definition.name}" must match ${String(COMMAND_NAME)}`); + if (typeof definition.description !== "string") throw new TypeError(`command "${definition.name}" description must be a string`); + if (definition.description.trim().length === 0) throw new TypeError(`command "${definition.name}" description must not be empty`); + if (typeof definition.handler !== "function") throw new TypeError(`command "${definition.name}" handler must be a function`); + const rawInput = definition.input; + let input; + if (rawInput !== void 0) { + if (typeof rawInput !== "object" || rawInput === null || !("hint" in rawInput) || typeof rawInput.hint !== "string") throw new TypeError(`command "${definition.name}" input hint must be a string`); + if (rawInput.hint.trim().length === 0) throw new TypeError(`command "${definition.name}" input hint must not be empty`); + input = Object.freeze({ hint: rawInput.hint }); + } + const normalized = Object.freeze({ + name: definition.name, + description: definition.description, + ...input === void 0 ? {} : { input }, + ...definition.recordInput === void 0 ? {} : { recordInput: definition.recordInput }, + handler: definition.handler + }); + return { + definition: normalized, + descriptor: Object.freeze({ + name: normalized.name, + description: normalized.description, + ...normalized.input === void 0 ? {} : { input: normalized.input } + }) + }; +} +/** Validate and detach an untrusted handler result at the registry boundary. */ +function normalizeResult(command, value) { + if (typeof value !== "object" || value === null || !("kind" in value)) throw new TypeError(`command "${command}" handler must return a CommandResult`); + const result = value; + if (result.kind === "success") { + if (result.text !== void 0 && typeof result.text !== "string") throw new TypeError(`command "${command}" success text must be a string when supplied`); + if (result.sourceEventSeq !== void 0 && (!Number.isSafeInteger(result.sourceEventSeq) || result.sourceEventSeq < 0)) throw new TypeError(`command "${command}" success sourceEventSeq must be a non-negative safe integer when supplied`); + return Object.freeze({ + kind: "success", + ...result.text === void 0 ? {} : { text: result.text }, + ...result.sourceEventSeq === void 0 ? {} : { sourceEventSeq: result.sourceEventSeq } + }); + } + if (result.kind === "error") { + if (typeof result.text !== "string" || result.text.trim().length === 0) throw new TypeError(`command "${command}" error text must be a non-empty string`); + return Object.freeze({ + kind: "error", + text: result.text + }); + } + throw new TypeError(`command "${command}" returned unknown result kind "${String(result.kind)}"`); +} +/** +* Human-command registry. Plain-context definitions are global; definitions +* registered through a command-injected child of an agent context shadow +* globals for that agent. +*/ +let CommandRuntime = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + let _execute_decorators; + return class CommandRuntime extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote]; + _execute_decorators = [Remote]; + __esDecorate(this, null, _list_decorators, { + kind: "method", + name: "list", + static: false, + private: false, + access: { + has: (obj) => "list" in obj, + get: (obj) => obj.list + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _execute_decorators, { + kind: "method", + name: "execute", + static: false, + private: false, + access: { + has: (obj) => "execute" in obj, + get: (obj) => obj.execute + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { + enumerable: true, + configurable: true, + writable: true, + value: _metadata + }); + } + layers = (__runInitializers(this, _instanceExtraInitializers), new ScopedLayers((scope) => new CommandLayer(scope), () => { + this.notifyChange(); + })); + /** Monotonic per-instance counter behind {@link mintCommandId}. */ + commandSeq = 0; + /** Instance token keeping minted ids unique across process restarts over one resumed log. */ + instanceToken = crypto.randomUUID().slice(0, 8); + constructor(ctx) { + super(ctx, "commands"); + } + /** + * Register a global or calling-agent-scoped command. + * @param definition - discovery metadata and direct UI handler. + * @returns the exact effect disposer that unregisters this definition. + */ + register(definition) { + const registered = normalizeDefinition(definition); + return this.layers.effect(this.ctx, (layer) => layer.commands.insert(registered.definition.name, registered), { label: "commands.register()" }); + } + /** + * List the effective immutable command descriptors for one agent. + * @param agent - exact receiving agent and scoped-layer key. + * @returns name-sorted descriptors after scoped shadowing. + */ + list(agent) { + return Object.freeze([...this.view(agent).values()].map((command) => command.descriptor).sort((left, right) => left.name < right.name ? -1 : 1)); + } + /** + * Resolve one effective command definition. + * @param agent - exact receiving agent and scoped-layer key. + * @param name - command name without a slash. + * @returns the scoped shadow or global definition. + */ + find(agent, name) { + return this.view(agent).get(name)?.definition; + } + /** + * Parse and execute a known command without sending it to the model. + * + * A resolved command's lifecycle is logged: `command/run` is appended + * before the handler is invoked and `command/done` after settlement (a + * thrown or aborted handler settles as `kind: 'error'`). Both are direct + * log-only appends — no turn wraps them, and persistence drains them at + * ordinary checkpoints. Admission misses (syntax or unknown name) log + * nothing — they never entered a handler. A `command/run` append failure + * fails the execution loud; a `command/done` append failure on the + * handler-failure path is contained so the handler's own error stays the + * reported failure. + * + * @param agent - exact receiving agent. + * @param line - complete slash-command line. + * @param signal - cancellation signal owned by the UI request. + * @returns the settled execution (result + lifecycle pairing id), or + * `undefined` when syntax or name does not resolve. + */ + async execute(agent, line, signal) { + const parsed = parseCommand(line); + if (parsed === void 0) return void 0; + const command = this.view(agent).get(parsed.name); + if (command === void 0) return void 0; + if (signal.aborted) throw abortError(signal); + const commandId = this.mintCommandId(); + this.appendLifecycle(agent.session, "command/run", { + commandId, + name: parsed.name, + ...command.definition.recordInput === false ? {} : { args: parsed.rawInput }, + source: { kind: "user" } + }); + const invocation = Object.freeze({ + commandId, + agent, + rawInput: parsed.rawInput, + signal + }); + let result; + try { + const output = command.definition.handler(invocation); + result = normalizeResult(parsed.name, await withAbort(Promise.resolve(output), signal)); + } catch (error) { + try { + this.appendLifecycle(agent.session, "command/done", { + commandId, + kind: "error", + text: error instanceof Error ? error.message : renderThrown(error) + }); + } catch (appendError) { + this.ctx.logger.warn(`command "${parsed.name}": command/done append failed: ${renderThrown(appendError)}`); + } + throw error; + } + this.appendLifecycle(agent.session, "command/done", { + commandId, + kind: result.kind, + ...result.text === void 0 ? {} : { text: result.text }, + ...result.kind === "success" && result.sourceEventSeq !== void 0 ? { sourceEventSeq: result.sourceEventSeq } : {} + }); + return Object.freeze({ + commandId, + result + }); + } + /** Mint the next pairing id (monotonic; instance-token-prefixed so a resumed log never repeats one). */ + mintCommandId() { + this.commandSeq += 1; + return CommandId(`cmd-${this.instanceToken}-${this.commandSeq}`); + } + /** + * Append one log-only lifecycle event directly: no turn is opened for it and + * no flush is forced — persistence observes the eager `session/event` path + * and drains at ordinary checkpoints and teardown, like every other + * standalone plugin event. + */ + appendLifecycle(session, type, data) { + return session.append.bind(session)(type, data); + } + /** Resolve global definitions followed by exact scoped shadows. */ + view(agent) { + return this.layers.merge(agent, (layer) => layer.commands); + } + /** Notify every registry observer without making UI refresh load-bearing. */ + notifyChange() { + for (const callback of this.ctx.events.dispatch("emit", ["commands/change"])) try { + const returned = callback(); + Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`commands/change listener rejected: ${renderThrown(error)}`); + }); + } catch (error) { + this.ctx.logger.warn(`commands/change listener threw: ${renderThrown(error)}`); + } + } + }; +})(); +//#endregion +export { CommandId, CommandRuntime, CommandRuntime as default, name, parseCommand }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/invariant.js new file mode 100644 index 0000000..c26fe24 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/invariant.js @@ -0,0 +1,43 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-commands`: +* command lifecycle events pair by commandId within one session log. +* @module @deepseek-ai/dsh-commands/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-commands"; +/** Cordis companion plugin name. */ +const name = "commands-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Install pairing validation over loaded logs and newly appended lifecycle events. */ +const install = Object.assign((ctx, fail) => { + const runIds = /* @__PURE__ */ new WeakMap(); + const validateEvent = (session, event) => { + if (event.type === "command/run") { + const ids = runIds.get(session) ?? /* @__PURE__ */ new Set(); + if (ids.has(event.data.commandId)) fail(`command/run repeats commandId ${JSON.stringify(event.data.commandId)}`); + ids.add(event.data.commandId); + runIds.set(session, ids); + return; + } + if (event.type !== "command/done") return; + if (runIds.get(session)?.has(event.data.commandId) !== true) fail(`command/done ${JSON.stringify(event.data.commandId)} pairs no prior command/run in this log`); + const source = event.data.sourceEventSeq; + const sourceEvent = source === void 0 ? void 0 : session.events[source]; + if (source !== void 0 && (event.data.kind !== "success" || !Number.isSafeInteger(source) || source < 0 || source >= event.seq || sourceEvent?.seq !== source || sourceEvent.type === "command/run" || sourceEvent.type === "command/done")) fail(`command/done ${JSON.stringify(event.data.commandId)} has invalid sourceEventSeq ${String(source)}`); + }; + for (const session of ctx.sessions.list()) for (const event of session.events) validateEvent(session, event); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName !== "session/event") return; + const [session, event] = args; + validateEvent(session, event); + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.d.ts new file mode 100644 index 0000000..dcf4919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.d.ts @@ -0,0 +1,3 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ + +export declare const TYPERT: unknown diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.js new file mode 100644 index 0000000..6a7a5f2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.js @@ -0,0 +1,506 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema = z.string() +const _deepseek_ai_dsh_commands_commands_execute_result$schema = z.union([z.undefined(), z.object({ + 'commandId': z.intersection(z.string(), z.unknown()).readonly(), + 'result': z.union([z.object({ + 'kind': z.literal("success").readonly(), + 'text': z.string().readonly().optional(), + 'sourceEventSeq': z.number().readonly().optional(), +}), z.object({ + 'kind': z.literal("error").readonly(), + 'text': z.string().readonly(), +})]).readonly(), +})]) +const _deepseek_ai_dsh_commands_commands_list_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_commands_commands_list_result$schema = z.array(z.object({ + 'name': z.string().readonly(), + 'description': z.string().readonly(), + 'input': z.object({ + 'hint': z.string().readonly(), +}).readonly().optional(), +})) + +export const TYPERT = { + package: '@deepseek-ai/dsh-commands', + face: 'host', + schemas: [ + ], + invocations: [ + { + id: '@deepseek-ai/dsh-commands#commands/execute', + service: 'commands', + namespace: 'commands', + method: 'execute', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema, + }, + }, + { + name: 'line', + wire: 'line', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/execute:line', + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema, + }, + }, + ], + cancellation: { parameter: 'signal' }, + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/execute:result', + schema: _deepseek_ai_dsh_commands_commands_execute_result$schema, + }, + sourceLocation: {"file":"packages/interaction/commands/src/index.ts","line":297,"column":9}, + }, + { + id: '@deepseek-ai/dsh-commands#commands/list', + service: 'commands', + namespace: 'commands', + method: 'list', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_commands_commands_list_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/list:result', + schema: _deepseek_ai_dsh_commands_commands_list_result$schema, + }, + sourceLocation: {"file":"packages/interaction/commands/src/index.ts","line":260,"column":3}, + }, + ], + model: { + "services": [ + { + "description": "Human-command registry. Plain-context definitions are global; definitions registered through a command-injected child of an agent context shadow globals for that agent.", + "summary": "Human-command registry.", + "tags": [], + "jsDoc": "/**\n * Human-command registry. Plain-context definitions are global; definitions\n * registered through a command-injected child of an agent context shadow\n * globals for that agent.\n */", + "key": "commands", + "exportName": "CommandRuntime", + "members": [ + { + "kind": "method", + "name": "register", + "signature": "register(definition: CommandDefinition): () => void", + "summary": "Register a global or calling-agent-scoped command.", + "jsDoc": "/**\n * Register a global or calling-agent-scoped command.\n * @param definition - discovery metadata and direct UI handler.\n * @returns the exact effect disposer that unregisters this definition.\n */" + }, + { + "kind": "method", + "name": "list", + "signature": "@Remote list(agent: Agent): readonly CommandDescriptor[]", + "summary": "List the effective immutable command descriptors for one agent.", + "jsDoc": "/**\n * List the effective immutable command descriptors for one agent.\n * @param agent - exact receiving agent and scoped-layer key.\n * @returns name-sorted descriptors after scoped shadowing.\n */" + }, + { + "kind": "method", + "name": "find", + "signature": "find(agent: Agent, name: string): CommandDefinition | undefined", + "summary": "Resolve one effective command definition.", + "jsDoc": "/**\n * Resolve one effective command definition.\n * @param agent - exact receiving agent and scoped-layer key.\n * @param name - command name without a slash.\n * @returns the scoped shadow or global definition.\n */" + }, + { + "kind": "method", + "name": "execute", + "signature": "@Remote async execute( agent: Agent, line: string, signal: AbortSignal, ): Promise", + "summary": "Parse and execute a known command without sending it to the model.", + "jsDoc": "/**\n * Parse and execute a known command without sending it to the model.\n *\n * A resolved command's lifecycle is logged: `command/run` is appended\n * before the handler is invoked and `command/done` after settlement (a\n * thrown or aborted handler settles as `kind: 'error'`). Both are direct\n * log-only appends — no turn wraps them, and persistence drains them at\n * ordinary checkpoints. Admission misses (syntax or unknown name) log\n * nothing — they never entered a handler. A `command/run` append failure\n * fails the execution loud; a `command/done` append failure on the\n * handler-failure path is contained so the handler's own error stays the\n * reported failure.\n *\n * @param agent - exact receiving agent.\n * @param line - complete slash-command line.\n * @param signal - cancellation signal owned by the UI request.\n * @returns the settled execution (result + lifecycle pairing id), or\n * `undefined` when syntax or name does not resolve.\n */" + } + ], + "types": [ + { + "name": "Agent", + "declaration": "export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly inbox: Inbox;\n readonly status: AgentStatus;\n readonly ctx: Context;\n cancel(cause: AgentCancelCause, options?: CancelOptions): void;\n whenIdle(): Promise;\n runMaintenance(task: (signal: AbortSignal) => Promise): Promise;\n send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;\n followup(message: UserMessage): void;\n steer(message: UserMessage): void;\n inject(message: UserMessage): void;\n}" + }, + { + "name": "AgentCancelCause", + "declaration": "export type AgentCancelCause = { readonly kind: 'user'; } | { readonly kind: 'parent'; } | { readonly kind: 'hook'; readonly reason: string; } | { readonly kind: 'disposed'; };" + }, + { + "name": "AgentOptions", + "declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n maxTokens?: number;\n}" + }, + { + "name": "AgentStatus", + "declaration": "export type AgentStatus = 'idle' | 'running';" + }, + { + "name": "ApprovalOutcome", + "declaration": "export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';" + }, + { + "name": "ApprovalPolicy", + "declaration": "export type ApprovalPolicy = 'ask' | 'never';" + }, + { + "name": "ApprovalRequestId", + "declaration": "export type ApprovalRequestId = Branded<'ApprovalRequestId'>;" + }, + { + "name": "AssistantMessage", + "declaration": "export interface AssistantMessage extends Message {\n readonly role: 'assistant';\n readonly source: ModelMessageSource;\n}" + }, + { + "name": "AssistantProvenance", + "declaration": "export interface AssistantProvenance {\n provider: string;\n model: string;\n replayState?: unknown;\n}" + }, + { + "name": "AttachmentId", + "declaration": "export type AttachmentId = Branded<'AttachmentId'>;" + }, + { + "name": "Branded", + "declaration": "export type Branded = string & { readonly [BRAND]: B; };" + }, + { + "name": "CallId", + "declaration": "export type CallId = Branded<'CallId'>;" + }, + { + "name": "CancelOptions", + "declaration": "export interface CancelOptions {\n keepInbox?: boolean | undefined;\n}" + }, + { + "name": "CodeDispatchEventData", + "declaration": "export interface CodeDispatchEventData extends CodeDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}" + }, + { + "name": "CodeDispatchStartEventData", + "declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}" + }, + { + "name": "CommandDefinition", + "declaration": "export interface CommandDefinition {\n readonly name: string;\n readonly description: string;\n readonly input?: CommandInputDescriptor;\n readonly recordInput?: boolean;\n readonly handler: (invocation: CommandInvocation) => CommandResult | Promise;\n}" + }, + { + "name": "CommandDescriptor", + "declaration": "export interface CommandDescriptor {\n readonly name: string;\n readonly description: string;\n readonly input?: CommandInputDescriptor;\n}" + }, + { + "name": "CommandExecution", + "declaration": "export interface CommandExecution {\n readonly commandId: CommandId;\n readonly result: CommandResult;\n}" + }, + { + "name": "CommandId", + "declaration": "export type CommandId = Branded<'CommandId'>;" + }, + { + "name": "CommandInputDescriptor", + "declaration": "export interface CommandInputDescriptor {\n readonly hint: string;\n}" + }, + { + "name": "CommandInvocation", + "declaration": "export interface CommandInvocation {\n readonly commandId: CommandId;\n readonly agent: Agent;\n readonly rawInput: string;\n readonly signal: AbortSignal;\n}" + }, + { + "name": "CommandResult", + "declaration": "export type CommandResult = { readonly kind: 'success'; readonly text?: string; readonly sourceEventSeq?: number; } | { readonly kind: 'error'; readonly text: string; };" + }, + { + "name": "CommandSource", + "declaration": "export type CommandSource = CommandSourceMap[keyof CommandSourceMap];" + }, + { + "name": "CommandSourceMap", + "declaration": "export interface CommandSourceMap {\n user: { kind: 'user'; };\n}" + }, + { + "name": "ContentBlock", + "declaration": "export type ContentBlock = ContentBlockMap[ContentBlockType];" + }, + { + "name": "ContentBlockMap", + "declaration": "export interface ContentBlockMap {\n text: TextBlock;\n reasoning: ReasoningBlock;\n image: ImageBlock;\n 'tool-call': ToolCallBlock;\n 'tool-result': ToolResultBlock;\n}" + }, + { + "name": "ContentBlockType", + "declaration": "export type ContentBlockType = keyof ContentBlockMap;" + }, + { + "name": "ContextFormed", + "declaration": "export type ContextFormed = { readonly form?: never; } | { readonly form: 'instructions'; } | { readonly form: 'catalog'; } | { readonly form: 'snapshot'; readonly sections: readonly ContextSnapshotSection[]; } | { readonly form: 'notice'; readonly summary: string; } | { readonly form: 'relay'; } | { readonly form: 'recall'; };" + }, + { + "name": "ContextSnapshotSection", + "declaration": "export interface ContextSnapshotSection {\n readonly name: string;\n readonly text: string;\n}" + }, + { + "name": "EpochHeader", + "declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n system?: string;\n tools?: ToolSchema[];\n}" + }, + { + "name": "FinishReason", + "declaration": "export type FinishReason = FinishReasonMap[keyof FinishReasonMap];" + }, + { + "name": "FinishReasonMap", + "declaration": "export interface FinishReasonMap {\n stop: { kind: 'stop'; };\n 'tool-calls': { kind: 'tool-calls'; };\n 'max-tokens': { kind: 'max-tokens'; };\n aborted: { kind: 'aborted'; failure: LlmFailure; };\n error: { kind: 'error'; failure: LlmFailure; };\n}" + }, + { + "name": "GoalBlockReason", + "declaration": "export interface GoalBlockReason {\n readonly code: string;\n readonly message: string;\n}" + }, + { + "name": "GoalChangeMeta", + "declaration": "export type GoalChangeMeta = GoalSnapshotChangeMeta | GoalClearChangeMeta;" + }, + { + "name": "GoalClearChangeMeta", + "declaration": "export interface GoalClearChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: 'clear';\n readonly cleared: GoalRef;\n readonly clearedAt: number;\n}" + }, + { + "name": "GoalId", + "declaration": "export type GoalId = Branded<'GoalId'>;" + }, + { + "name": "GoalMessageSource", + "declaration": "export interface GoalMessageSource {\n readonly kind: 'goal';\n readonly goalId: GoalId;\n readonly revision: number;\n readonly round: number;\n}" + }, + { + "name": "GoalOperation", + "declaration": "export type GoalOperation = 'create' | 'edit' | 'pause' | 'resume' | 'complete' | 'block' | 'clear';" + }, + { + "name": "GoalPhase", + "declaration": "export type GoalPhase = 'active' | 'paused' | 'blocked' | 'complete';" + }, + { + "name": "GoalRef", + "declaration": "export interface GoalRef {\n readonly id: GoalId;\n readonly revision: number;\n}" + }, + { + "name": "GoalSnapshot", + "declaration": "export interface GoalSnapshot extends GoalRef {\n readonly objective: string;\n readonly phase: GoalPhase;\n readonly blockedReason?: GoalBlockReason;\n readonly maxGoalRounds: number;\n}" + }, + { + "name": "GoalSnapshotChangeMeta", + "declaration": "export interface GoalSnapshotChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: Exclude;\n readonly goal: GoalSnapshot;\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n}" + }, + { + "name": "ImageAttachmentRef", + "declaration": "export interface ImageAttachmentRef {\n attachmentId: AttachmentId;\n mediaType: ImageMediaType;\n bytes: number;\n width: number;\n height: number;\n name?: string;\n}" + }, + { + "name": "ImageBlock", + "declaration": "export interface ImageBlock {\n type: 'image';\n attachment: ImageAttachmentRef;\n}" + }, + { + "name": "ImageMediaType", + "declaration": "export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';" + }, + { + "name": "Inbox", + "declaration": "export class Inbox {\n get nextTurn(): readonly UserMessage[];\n get nextStep(): readonly UserMessage[];\n get hasPending(): boolean;\n clear(): void;\n claim(target: InboxTarget, turn: number): UserMessage[];\n append(target: InboxTarget, message: UserMessage): void;\n prepend(target: InboxTarget, message: UserMessage): void;\n replace(messageId: MessageId, newMessage: UserMessage): boolean;\n remove(messageId: MessageId): boolean;\n splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[];\n}" + }, + { + "name": "InboxTarget", + "declaration": "export type InboxTarget = 'next-turn' | 'next-step';" + }, + { + "name": "JsonValue", + "declaration": "export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue; };" + }, + { + "name": "LlmCallConfig", + "declaration": "export interface LlmCallConfig {\n provider: string;\n model: string;\n reasoningEffort?: ReasoningEffortId;\n temperature?: number;\n maxTokens?: number;\n stop?: string[];\n}" + }, + { + "name": "LlmCallConfigAdapterDefaults", + "declaration": "export interface LlmCallConfigAdapterDefaults {\n reasoningEffort?: true;\n maxTokens?: true;\n}" + }, + { + "name": "LlmFailure", + "declaration": "export interface LlmFailure {\n readonly message: string;\n readonly code: string;\n readonly status?: number;\n readonly providerRetryAfterMs?: number;\n readonly requestId?: ProviderRequestId;\n}" + }, + { + "name": "Message", + "declaration": "export interface Message {\n readonly id: MessageId;\n readonly role: 'system' | 'user' | 'assistant';\n readonly content: ContentBlock[];\n readonly source: MessageSource;\n}" + }, + { + "name": "MessageId", + "declaration": "export type MessageId = Branded<'MessageId'>;" + }, + { + "name": "MessageSource", + "declaration": "export type MessageSource = MessageSourceMap[keyof MessageSourceMap];" + }, + { + "name": "MessageSourceMap", + "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n goal: GoalMessageSource;\n}" + }, + { + "name": "ModelMessageSource", + "declaration": "export interface ModelMessageSource extends AssistantProvenance {\n kind: 'model';\n}" + }, + { + "name": "ProviderRequestId", + "declaration": "export type ProviderRequestId = Branded<'ProviderRequestId'>;" + }, + { + "name": "ReasoningBlock", + "declaration": "export interface ReasoningBlock {\n type: 'reasoning';\n text: string;\n}" + }, + { + "name": "ReasoningEffortId", + "declaration": "export type ReasoningEffortId = Branded<'ReasoningEffortId'>;" + }, + { + "name": "ReplayEnvelope", + "declaration": "export interface ReplayEnvelope {\n response: unknown;\n blocks?: readonly unknown[];\n}" + }, + { + "name": "RequestContext", + "declaration": "export interface RequestContext {\n provider: string;\n model: string;\n contextWindow?: number;\n}" + }, + { + "name": "RequestHeaderReason", + "declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change';" + }, + { + "name": "Session", + "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n get id(): SessionId;\n readonly firstLiveSeq: number;\n get events(): readonly SessionEvent[];\n get seq(): number;\n append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}" + }, + { + "name": "SessionEvent", + "declaration": "export type SessionEvent = { [K in SessionEventType]: { type: K; seq: number; time: number; data: SessionEventMap[K]; ignorable?: true; } & (K extends SurfaceEventType ? { sourceEventSeqs?: number[]; surfaceOp?: SurfaceOp; } : object) }[T];" + }, + { + "name": "SessionEventMap", + "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: number; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n 'goal/change': GoalChangeMeta;\n}" + }, + { + "name": "SessionEventType", + "declaration": "export type SessionEventType = keyof SessionEventMap;" + }, + { + "name": "SessionHeader", + "declaration": "export interface SessionHeader {\n readonly version: number;\n readonly id: SessionId;\n readonly createdAt: number;\n readonly cwd?: string;\n readonly parentSession?: SessionId;\n readonly seedLength?: number;\n readonly origin?: 'subagent';\n readonly delegationDepth?: number;\n readonly agentPreset?: string;\n}" + }, + { + "name": "SessionId", + "declaration": "export type SessionId = Branded<'SessionId'>;" + }, + { + "name": "SessionSurface", + "declaration": "export interface SessionSurface {\n readonly nodes: readonly number[];\n readonly replaceGeneration: number;\n}" + }, + { + "name": "StreamChunk", + "declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: ReplayEnvelope; };" + }, + { + "name": "SurfaceEventType", + "declaration": "export type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result';" + }, + { + "name": "SurfaceIntent", + "declaration": "export interface SurfaceIntent {\n surfaceOp: SurfaceOp;\n sourceEventSeqs?: number[];\n}" + }, + { + "name": "SurfaceOp", + "declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: number; end: number; };" + }, + { + "name": "TextBlock", + "declaration": "export interface TextBlock {\n type: 'text';\n text: string;\n}" + }, + { + "name": "TodoItem", + "declaration": "export interface TodoItem {\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n}" + }, + { + "name": "TokenUsage", + "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}" + }, + { + "name": "ToolCallBlock", + "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: CallId;\n name: string;\n arguments: string;\n}" + }, + { + "name": "ToolMessageSource", + "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: CallId;\n}" + }, + { + "name": "ToolResultBlock", + "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: CallId;\n content: ContentBlock[];\n isError?: boolean;\n}" + }, + { + "name": "ToolResultMessage", + "declaration": "export interface ToolResultMessage extends Message {\n readonly role: 'user';\n readonly content: [ToolResultBlock];\n readonly source: ToolMessageSource;\n}" + }, + { + "name": "ToolSchema", + "declaration": "export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n}" + }, + { + "name": "TurnEndCancelCause", + "declaration": "export type TurnEndCancelCause = AgentCancelCause | { readonly kind: 'legacy'; };" + }, + { + "name": "TurnEndReason", + "declaration": "export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap];" + }, + { + "name": "TurnEndReasonMap", + "declaration": "export interface TurnEndReasonMap {\n completed: { kind: 'completed'; };\n aborted: { kind: 'aborted'; reason: TurnEndCancelCause; };\n blocked: { kind: 'blocked'; };\n error: { kind: 'error'; error: LlmFailure; };\n 'max-tokens': { kind: 'max-tokens'; };\n interrupted: { kind: 'interrupted'; };\n}" + }, + { + "name": "UserMessage", + "declaration": "export interface UserMessage extends Message {\n readonly role: 'user';\n}" + } + ] + } + ], + "events": [ + { + "description": "A command was registered or unregistered. This is an unfiltered registry notification because a global or scoped change may affect any UI view. Observer failures are contained and cannot veto the registry mutation.", + "summary": "A command was registered or unregistered.", + "tags": [ + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * A command was registered or unregistered. This is an unfiltered registry\n * notification because a global or scoped change may affect any UI view.\n * Observer failures are contained and cannot veto the registry mutation.\n * @mode emit\n */", + "name": "commands/change", + "mode": "emit", + "signature": "'commands/change'(): void" + } + ], + "objects": [] + }, +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.d.ts new file mode 100644 index 0000000..9407c56 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.d.ts @@ -0,0 +1,29 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import type { + RemoteResult, + TypertRemoteContribution, +} from '@deepseek-ai/dsh-typert-protocol' +import type { CommandDescriptor, CommandExecution } from '@deepseek-ai/dsh-commands/types' +import type { SessionId } from '@deepseek-ai/dsh-session/types' + +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteNamespace$636f6d6d616e6473 { + execute: (agentId: SessionId, line: string, signal?: AbortSignal) => Promise> + list: (agentId: SessionId) => Promise> + } + interface TypertRemoteMap { + 'commands/execute': (agentId: SessionId, line: string, signal?: AbortSignal) => Promise> + 'commands/list': (agentId: SessionId) => Promise> + } + interface TypertRemoteNamespaceMap { + 'commands': TypertRemoteNamespace$636f6d6d616e6473 + } + interface TypertRemoteScopeMap { + 'agent:commands/execute': (line: string, signal?: AbortSignal) => Promise> + 'agent:commands/list': () => Promise> + } +} + +export declare const TYPERT_REMOTE: TypertRemoteContribution +export default TYPERT_REMOTE +//# sourceMappingURL=typert.remote-client.d.ts.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.js new file mode 100644 index 0000000..6abc29d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.js @@ -0,0 +1,103 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema = z.string() +const _deepseek_ai_dsh_commands_commands_execute_result$schema = z.union([z.undefined(), z.object({ + 'commandId': z.intersection(z.string(), z.unknown()).readonly(), + 'result': z.union([z.object({ + 'kind': z.literal("success").readonly(), + 'text': z.string().readonly().optional(), + 'sourceEventSeq': z.number().readonly().optional(), +}), z.object({ + 'kind': z.literal("error").readonly(), + 'text': z.string().readonly(), +})]).readonly(), +})]) +const _deepseek_ai_dsh_commands_commands_list_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_commands_commands_list_result$schema = z.array(z.object({ + 'name': z.string().readonly(), + 'description': z.string().readonly(), + 'input': z.object({ + 'hint': z.string().readonly(), +}).readonly().optional(), +})) + +export const TYPERT_REMOTE = { + package: '@deepseek-ai/dsh-commands', + descriptors: [ + { + id: '@deepseek-ai/dsh-commands#commands/execute', + service: 'commands', + namespace: 'commands', + method: 'execute', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_0$schema, + }, + }, + { + name: 'line', + wire: 'line', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/execute:line', + schema: _deepseek_ai_dsh_commands_commands_execute_parameter_1$schema, + }, + }, + ], + cancellation: { parameter: 'signal' }, + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/execute:result', + schema: _deepseek_ai_dsh_commands_commands_execute_result$schema, + }, + sourceLocation: {"file":"packages/interaction/commands/src/index.ts","line":297,"column":9}, + }, + { + id: '@deepseek-ai/dsh-commands#commands/list', + service: 'commands', + namespace: 'commands', + method: 'list', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_commands_commands_list_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-commands#commands/list:result', + schema: _deepseek_ai_dsh_commands_commands_list_result$schema, + }, + sourceLocation: {"file":"packages/interaction/commands/src/index.ts","line":260,"column":3}, + }, + ], +} + +export default TYPERT_REMOTE diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.d.ts new file mode 100644 index 0000000..9dd6273 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.d.ts @@ -0,0 +1,25 @@ +/** + * dsh-commands' owned branded id: command lifecycle pairing across the + * session log, the wire admission response, and client-side flow pairing. + * + * The `Branded` primitive lives in `@deepseek-ai/dsh-brand`; this module + * is a pure type/constructor outlet (no cordis imports, no module + * augmentation) so wire and client programs can name the brand without + * loading the host plugin's Context merges — the `dsh-llm/brand` shape. + * + * @module @deepseek-ai/dsh-commands/brand + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** + * Pairs one command execution's `command/run`/`command/done` lifecycle + * records with each other and with the `command.execute` admission response. + * Minted by the executor, monotonic per service instance. + */ +export type CommandId = Branded<'CommandId'>; +/** + * Brand a string as a {@link CommandId}. + * @param id - the executor-minted pairing id. + * @returns the same string, branded; no validation is performed. + */ +export declare function CommandId(id: string): CommandId; +//# sourceMappingURL=brand.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.js new file mode 100644 index 0000000..bd43ee4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/brand.js @@ -0,0 +1,20 @@ +/** + * dsh-commands' owned branded id: command lifecycle pairing across the + * session log, the wire admission response, and client-side flow pairing. + * + * The `Branded` primitive lives in `@deepseek-ai/dsh-brand`; this module + * is a pure type/constructor outlet (no cordis imports, no module + * augmentation) so wire and client programs can name the brand without + * loading the host plugin's Context merges — the `dsh-llm/brand` shape. + * + * @module @deepseek-ai/dsh-commands/brand + */ +/** + * Brand a string as a {@link CommandId}. + * @param id - the executor-minted pairing id. + * @returns the same string, branded; no validation is performed. + */ +export function CommandId(id) { + return id; +} +//# sourceMappingURL=brand.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/index.d.ts new file mode 100644 index 0000000..04b02fb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/index.d.ts @@ -0,0 +1,126 @@ +/** + * Plugin-owned human-command registry shared by interactive UI adapters. + * @module @deepseek-ai/dsh-commands + */ +import { Context } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'; +import { CommandId } from './brand.ts'; +import type { CommandDescriptor, CommandExecution, CommandInputDescriptor, CommandResult } from './types.ts'; +export { CommandId } from './brand.ts'; +export type * from './types.ts'; +export declare const name = "commands"; +/** Invocation passed to one registered command handler. */ +export interface CommandInvocation { + /** Pairing id already written to this invocation's `command/run` event. */ + readonly commandId: CommandId; + /** Exact agent whose UI received the command. */ + readonly agent: Agent; + /** Exact text following the registered command name, including separator whitespace. */ + readonly rawInput: string; + /** Cancellation signal owned by the dispatching UI request. */ + readonly signal: AbortSignal; +} +/** Plugin-owned command registration. */ +export interface CommandDefinition { + /** Lowercase command name without the leading slash. */ + readonly name: string; + /** Human-readable summary used in discovery UI. */ + readonly description: string; + /** Optional free-form input hint advertised to capable clients. */ + readonly input?: CommandInputDescriptor; + /** + * Whether `command/run` records `rawInput`. Defaults to true. A command + * whose domain event owns the payload sets this false to avoid duplicating + * that payload in the session log. + */ + readonly recordInput?: boolean; + /** Execute against the receiving agent without sending the command to the model. */ + readonly handler: (invocation: CommandInvocation) => CommandResult | Promise; +} +/** Syntactically valid slash command before registry resolution. */ +export interface ParsedCommand { + /** Lowercase command name without the leading slash. */ + readonly name: string; + /** Exact text following the command name. */ + readonly rawInput: string; +} +declare module '@deepseek-ai/cordis' { + interface Context { + commands: CommandRuntime; + } +} +/** + * Parse an exact slash command without normalizing its trailing input. + * + * @param line - Complete candidate command line. + * @returns The parsed command, or `undefined` when the line is not a command. + */ +export declare function parseCommand(line: string): ParsedCommand | undefined; +/** + * Human-command registry. Plain-context definitions are global; definitions + * registered through a command-injected child of an agent context shadow + * globals for that agent. + */ +export declare class CommandRuntime extends TypertRemoteService { + private readonly layers; + /** Monotonic per-instance counter behind {@link mintCommandId}. */ + private commandSeq; + /** Instance token keeping minted ids unique across process restarts over one resumed log. */ + private readonly instanceToken; + constructor(ctx: Context); + /** + * Register a global or calling-agent-scoped command. + * @param definition - discovery metadata and direct UI handler. + * @returns the exact effect disposer that unregisters this definition. + */ + register(definition: CommandDefinition): () => void; + /** + * List the effective immutable command descriptors for one agent. + * @param agent - exact receiving agent and scoped-layer key. + * @returns name-sorted descriptors after scoped shadowing. + */ + list(agent: Agent): readonly CommandDescriptor[]; + /** + * Resolve one effective command definition. + * @param agent - exact receiving agent and scoped-layer key. + * @param name - command name without a slash. + * @returns the scoped shadow or global definition. + */ + find(agent: Agent, name: string): CommandDefinition | undefined; + /** + * Parse and execute a known command without sending it to the model. + * + * A resolved command's lifecycle is logged: `command/run` is appended + * before the handler is invoked and `command/done` after settlement (a + * thrown or aborted handler settles as `kind: 'error'`). Both are direct + * log-only appends — no turn wraps them, and persistence drains them at + * ordinary checkpoints. Admission misses (syntax or unknown name) log + * nothing — they never entered a handler. A `command/run` append failure + * fails the execution loud; a `command/done` append failure on the + * handler-failure path is contained so the handler's own error stays the + * reported failure. + * + * @param agent - exact receiving agent. + * @param line - complete slash-command line. + * @param signal - cancellation signal owned by the UI request. + * @returns the settled execution (result + lifecycle pairing id), or + * `undefined` when syntax or name does not resolve. + */ + execute(agent: Agent, line: string, signal: AbortSignal): Promise; + /** Mint the next pairing id (monotonic; instance-token-prefixed so a resumed log never repeats one). */ + private mintCommandId; + /** + * Append one log-only lifecycle event directly: no turn is opened for it and + * no flush is forced — persistence observes the eager `session/event` path + * and drains at ordinary checkpoints and teardown, like every other + * standalone plugin event. + */ + private appendLifecycle; + /** Resolve global definitions followed by exact scoped shadows. */ + private view; + /** Notify every registry observer without making UI refresh load-bearing. */ + private notifyChange; +} +export default CommandRuntime; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js new file mode 100644 index 0000000..77db261 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js @@ -0,0 +1,343 @@ +/** + * Plugin-owned human-command registry shared by interactive UI adapters. + * @module @deepseek-ai/dsh-commands + */ +var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; +var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +import { NamedEntries, ScopedLayers } from '@deepseek-ai/dsh-scope'; +import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'; +import { CommandId } from "./brand.js"; +export { CommandId } from "./brand.js"; +export const name = 'commands'; +const COMMAND_NAME = /^[a-z][a-z0-9_-]*$/u; +/** All command registrations owned by one global or scoped layer. */ +class CommandLayer { + commands; + /** + * Create one command layer with diagnostics specific to its ownership scope. + * @param scope - the scoped owner, or `undefined` for global registrations. + */ + constructor(scope) { + this.commands = new NamedEntries(name => new Error(scope === undefined + ? `command "${name}" is already registered (for a per-agent variant, mount a command-injected plugin under that agent's \`agent.ctx\`)` + : `command "${name}" is already registered in this scope`)); + } + /** @returns whether this layer owns no command registrations. */ + isEmpty() { + return this.commands.isEmpty(); + } +} +/** + * Parse an exact slash command without normalizing its trailing input. + * + * @param line - Complete candidate command line. + * @returns The parsed command, or `undefined` when the line is not a command. + */ +export function parseCommand(line) { + const match = /^\/([a-z][a-z0-9_-]*)(?=$|[\t\n\r ])/u.exec(line); + if (match === null) + return undefined; + const name = match[1]; + /* v8 ignore next -- the first capture is required whenever the regular expression matches */ + if (name === undefined) + return undefined; + return Object.freeze({ name, rawInput: line.slice(match[0].length) }); +} +/** Convert arbitrary abort reasons to one stable rejected Error. */ +function abortError(signal) { + if (signal.reason instanceof Error) + return signal.reason; + return new Error(typeof signal.reason === 'string' ? signal.reason : 'command aborted'); +} +/** Render arbitrary thrown values without trusting their string coercion. */ +function renderThrown(value) { + try { + return String(value); + } + catch { + return ''; + } +} +/** Stop awaiting an uncooperative handler once its owning UI request aborts. */ +function withAbort(promise, signal) { + if (signal.aborted) + return Promise.reject(abortError(signal)); + return new Promise((resolve, reject) => { + const onAbort = () => { + signal.removeEventListener('abort', onAbort); + reject(abortError(signal)); + }; + signal.addEventListener('abort', onAbort, { once: true }); + promise.then((value) => { + signal.removeEventListener('abort', onAbort); + resolve(value); + }, (error) => { + signal.removeEventListener('abort', onAbort); + reject(error instanceof Error + ? error + : new Error(`command handler rejected with a non-Error value: ${renderThrown(error)}`, { cause: error })); + }); + }); +} +/** Reject invalid command metadata before it can reach a UI protocol. */ +function normalizeDefinition(definition) { + if (!COMMAND_NAME.test(definition.name)) { + throw new TypeError(`command name "${definition.name}" must match ${String(COMMAND_NAME)}`); + } + if (typeof definition.description !== 'string') { + throw new TypeError(`command "${definition.name}" description must be a string`); + } + if (definition.description.trim().length === 0) { + throw new TypeError(`command "${definition.name}" description must not be empty`); + } + if (typeof definition.handler !== 'function') { + throw new TypeError(`command "${definition.name}" handler must be a function`); + } + const rawInput = definition.input; + let input; + if (rawInput !== undefined) { + if (typeof rawInput !== 'object' || rawInput === null || !('hint' in rawInput) + || typeof rawInput.hint !== 'string') { + throw new TypeError(`command "${definition.name}" input hint must be a string`); + } + if (rawInput.hint.trim().length === 0) { + throw new TypeError(`command "${definition.name}" input hint must not be empty`); + } + input = Object.freeze({ hint: rawInput.hint }); + } + const normalized = Object.freeze({ + name: definition.name, + description: definition.description, + ...input === undefined ? {} : { input }, + ...definition.recordInput === undefined ? {} : { recordInput: definition.recordInput }, + handler: definition.handler, + }); + const descriptor = Object.freeze({ + name: normalized.name, + description: normalized.description, + ...normalized.input === undefined ? {} : { input: normalized.input }, + }); + return { definition: normalized, descriptor }; +} +/** Validate and detach an untrusted handler result at the registry boundary. */ +function normalizeResult(command, value) { + if (typeof value !== 'object' || value === null || !('kind' in value)) { + throw new TypeError(`command "${command}" handler must return a CommandResult`); + } + const result = value; + if (result.kind === 'success') { + if (result.text !== undefined && typeof result.text !== 'string') { + throw new TypeError(`command "${command}" success text must be a string when supplied`); + } + if (result.sourceEventSeq !== undefined + && (!Number.isSafeInteger(result.sourceEventSeq) || result.sourceEventSeq < 0)) { + throw new TypeError(`command "${command}" success sourceEventSeq must be a non-negative safe integer when supplied`); + } + return Object.freeze({ + kind: 'success', + ...result.text === undefined ? {} : { text: result.text }, + ...result.sourceEventSeq === undefined ? {} : { sourceEventSeq: result.sourceEventSeq }, + }); + } + if (result.kind === 'error') { + if (typeof result.text !== 'string' || result.text.trim().length === 0) { + throw new TypeError(`command "${command}" error text must be a non-empty string`); + } + return Object.freeze({ kind: 'error', text: result.text }); + } + throw new TypeError(`command "${command}" returned unknown result kind "${String(result.kind)}"`); +} +/** + * Human-command registry. Plain-context definitions are global; definitions + * registered through a command-injected child of an agent context shadow + * globals for that agent. + */ +let CommandRuntime = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + let _execute_decorators; + return class CommandRuntime extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote]; + _execute_decorators = [Remote]; + __esDecorate(this, null, _list_decorators, { kind: "method", name: "list", static: false, private: false, access: { has: obj => "list" in obj, get: obj => obj.list }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _execute_decorators, { kind: "method", name: "execute", static: false, private: false, access: { has: obj => "execute" in obj, get: obj => obj.execute }, metadata: _metadata }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + layers = (__runInitializers(this, _instanceExtraInitializers), new ScopedLayers(scope => new CommandLayer(scope), () => { this.notifyChange(); })); + /** Monotonic per-instance counter behind {@link mintCommandId}. */ + commandSeq = 0; + /** Instance token keeping minted ids unique across process restarts over one resumed log. */ + instanceToken = crypto.randomUUID().slice(0, 8); + constructor(ctx) { + super(ctx, 'commands'); + } + /** + * Register a global or calling-agent-scoped command. + * @param definition - discovery metadata and direct UI handler. + * @returns the exact effect disposer that unregisters this definition. + */ + register(definition) { + const registered = normalizeDefinition(definition); + return this.layers.effect(this.ctx, layer => layer.commands.insert(registered.definition.name, registered), { label: 'commands.register()' }); + } + /** + * List the effective immutable command descriptors for one agent. + * @param agent - exact receiving agent and scoped-layer key. + * @returns name-sorted descriptors after scoped shadowing. + */ + list(agent) { + return Object.freeze([...this.view(agent).values()] + .map(command => command.descriptor) + // Names are unique in the effective view, so equality is impossible. + .sort((left, right) => left.name < right.name ? -1 : 1)); + } + /** + * Resolve one effective command definition. + * @param agent - exact receiving agent and scoped-layer key. + * @param name - command name without a slash. + * @returns the scoped shadow or global definition. + */ + find(agent, name) { + return this.view(agent).get(name)?.definition; + } + /** + * Parse and execute a known command without sending it to the model. + * + * A resolved command's lifecycle is logged: `command/run` is appended + * before the handler is invoked and `command/done` after settlement (a + * thrown or aborted handler settles as `kind: 'error'`). Both are direct + * log-only appends — no turn wraps them, and persistence drains them at + * ordinary checkpoints. Admission misses (syntax or unknown name) log + * nothing — they never entered a handler. A `command/run` append failure + * fails the execution loud; a `command/done` append failure on the + * handler-failure path is contained so the handler's own error stays the + * reported failure. + * + * @param agent - exact receiving agent. + * @param line - complete slash-command line. + * @param signal - cancellation signal owned by the UI request. + * @returns the settled execution (result + lifecycle pairing id), or + * `undefined` when syntax or name does not resolve. + */ + async execute(agent, line, signal) { + const parsed = parseCommand(line); + if (parsed === undefined) + return undefined; + const command = this.view(agent).get(parsed.name); + if (command === undefined) + return undefined; + if (signal.aborted) + throw abortError(signal); + const commandId = this.mintCommandId(); + this.appendLifecycle(agent.session, 'command/run', { + commandId, + name: parsed.name, + ...command.definition.recordInput === false ? {} : { args: parsed.rawInput }, + source: { kind: 'user' }, + }); + const invocation = Object.freeze({ commandId, agent, rawInput: parsed.rawInput, signal }); + let result; + try { + const output = command.definition.handler(invocation); + result = normalizeResult(parsed.name, await withAbort(Promise.resolve(output), signal)); + } + catch (error) { + try { + this.appendLifecycle(agent.session, 'command/done', { + commandId, kind: 'error', + text: error instanceof Error ? error.message : renderThrown(error), + }); + } + catch (appendError) { + this.ctx.logger.warn(`command "${parsed.name}": command/done append failed: ${renderThrown(appendError)}`); + } + throw error; + } + this.appendLifecycle(agent.session, 'command/done', { + commandId, kind: result.kind, + ...result.text === undefined ? {} : { text: result.text }, + ...result.kind === 'success' && result.sourceEventSeq !== undefined + ? { sourceEventSeq: result.sourceEventSeq } + : {}, + }); + return Object.freeze({ commandId, result }); + } + /** Mint the next pairing id (monotonic; instance-token-prefixed so a resumed log never repeats one). */ + mintCommandId() { + this.commandSeq += 1; + return CommandId(`cmd-${this.instanceToken}-${this.commandSeq}`); + } + /** + * Append one log-only lifecycle event directly: no turn is opened for it and + * no flush is forced — persistence observes the eager `session/event` path + * and drains at ordinary checkpoints and teardown, like every other + * standalone plugin event. + */ + appendLifecycle(session, type, data) { + // Both admitted types are log-only (non-surface), but TypeScript does not + // reduce Session.append's conditional rest parameter through a generic + // type parameter. Preserve the proven two-argument call shape. + const appendLogOnly = session.append.bind(session); + return appendLogOnly(type, data); + } + /** Resolve global definitions followed by exact scoped shadows. */ + view(agent) { + return this.layers.merge(agent, layer => layer.commands); + } + /** Notify every registry observer without making UI refresh load-bearing. */ + notifyChange() { + // Cordis emit uses Array.map: one synchronous throw starves later listeners, + // and returned promises are discarded. Registry notifications are + // non-vetoing, so contain each callback independently. + for (const callback of this.ctx.events.dispatch('emit', ['commands/change'])) { + try { + const returned = callback(); + void Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`commands/change listener rejected: ${renderThrown(error)}`); + }); + } + catch (error) { + this.ctx.logger.warn(`commands/change listener threw: ${renderThrown(error)}`); + } + } + } + }; +})(); +export { CommandRuntime }; +export default CommandRuntime; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.d.ts new file mode 100644 index 0000000..7c2418b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.d.ts @@ -0,0 +1,17 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-commands`: + * command lifecycle events pair by commandId within one session log. + * @module @deepseek-ai/dsh-commands/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "commands-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.js new file mode 100644 index 0000000..6f99562 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/invariant.js @@ -0,0 +1,60 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-commands`: + * command lifecycle events pair by commandId within one session log. + * @module @deepseek-ai/dsh-commands/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-commands'; +/** Cordis companion plugin name. */ +export const name = 'commands-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/* jscpd:ignore-start -- package companions share replay and dispatch plumbing */ +/** Install pairing validation over loaded logs and newly appended lifecycle events. */ +const install = Object.assign((ctx, fail) => { + // Install-scoped so a dispose/re-register cycle re-sweeps from a clean slate. + const runIds = new WeakMap(); + const validateEvent = (session, event) => { + if (event.type === 'command/run') { + const ids = runIds.get(session) ?? new Set(); + if (ids.has(event.data.commandId)) { + fail(`command/run repeats commandId ${JSON.stringify(event.data.commandId)}`); + } + ids.add(event.data.commandId); + runIds.set(session, ids); + return; + } + if (event.type !== 'command/done') + return; + if (runIds.get(session)?.has(event.data.commandId) !== true) { + fail(`command/done ${JSON.stringify(event.data.commandId)} pairs no prior command/run in this log`); + } + const source = event.data.sourceEventSeq; + const sourceEvent = source === undefined ? undefined : session.events[source]; + if (source !== undefined + && (event.data.kind !== 'success' + || !Number.isSafeInteger(source) || source < 0 || source >= event.seq + || sourceEvent?.seq !== source + || sourceEvent.type === 'command/run' + || sourceEvent.type === 'command/done')) { + fail(`command/done ${JSON.stringify(event.data.commandId)} has invalid sourceEventSeq ${String(source)}`); + } + }; + for (const session of ctx.sessions.list()) { + for (const event of session.events) + validateEvent(session, event); + } + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') + return; + const [session, event] = args; + validateEvent(session, event); + }, { global: true }); +}, { inject: ['sessions'] }); +/* jscpd:ignore-end */ +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/types.d.ts new file mode 100644 index 0000000..ec5e83d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/types.d.ts @@ -0,0 +1,102 @@ +/** + * Durable command event vocabulary and the registry's Cordis event + * declaration, shared with type-only consumers. Client-safe: nothing here + * reaches a Host-only symbol, so a Client compilation face reads the same + * `commands/change` signature the Host emits. + * + * @module @deepseek-ai/dsh-commands/types + */ +import type { CommandId } from './brand.ts'; +/** Immutable metadata for a command's optional unstructured input. */ +export interface CommandInputDescriptor { + /** Placeholder shown before the user supplies free-form input. */ + readonly hint: string; +} +/** Expected command outcome rendered directly by the dispatching UI. */ +export type CommandResult = { + readonly kind: 'success'; + readonly text?: string; + /** Earlier authoritative domain event that owns a richer presentation. */ + readonly sourceEventSeq?: number; +} | { + readonly kind: 'error'; + readonly text: string; +}; +/** + * One settled command execution: the handler's normalized result plus the + * lifecycle pairing id minted for its `command/run`/`command/done` records, + * so a dispatching surface can correlate the Remote acknowledgment with the + * flow node those events produce. + */ +export interface CommandExecution { + /** Pairing id carried by this execution's lifecycle events. */ + readonly commandId: CommandId; + /** The handler's normalized outcome. */ + readonly result: CommandResult; +} +/** Handler-free immutable command view returned to UI adapters. */ +export interface CommandDescriptor { + /** Lowercase command name without the leading slash. */ + readonly name: string; + /** Human-readable summary used in discovery UI. */ + readonly description: string; + /** Optional free-form input hint advertised to capable clients. */ + readonly input?: CommandInputDescriptor; +} +/** + * Producer record for one command invocation (the `command/run` event's + * source slot). Merge-extensible sum type mirroring `MessageSourceMap`'s + * shape; minimal today because every executor caller is a human-facing UI + * surface dispatching a human-typed line, so the sole variant is `user`. + */ +export interface CommandSourceMap { + user: { + kind: 'user'; + }; +} +/** The union over {@link CommandSourceMap} — who issued a command line. */ +export type CommandSource = CommandSourceMap[keyof CommandSourceMap]; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * A command was registered or unregistered. This is an unfiltered registry + * notification because a global or scoped change may affect any UI view. + * Observer failures are contained and cannot veto the registry mutation. + * @mode emit + */ + 'commands/change'(): void; + } +} +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * A resolved slash command entered its handler. Log-only (never model + * surface); paired with `command/done` by `commandId`, mirroring the + * `tool/call`↔`tool/result` pairing. The payload is structured — `name` + * and `args` are `parseCommand`'s own split (name and verbatim rawInput, + * separator whitespace included), so a consumer (a projection unit + * folding its own command records, a rich command card) never re-parses + * a line. `args` is absent when the definition sets `recordInput: false` + * because an authoritative domain event owns the input payload. + */ + 'command/run': { + commandId: CommandId; + name: string; + args?: string; + source: CommandSource; + }; + /** + * The paired command settled. `kind`/`text` carry the handler's verbatim + * outcome (a thrown/aborted handler settles as `kind: 'error'` with the + * rendered failure). A successful command may identify the earlier + * authoritative domain event for a richer client-computed presentation. + */ + 'command/done': { + commandId: CommandId; + kind: 'success' | 'error'; + text?: string; + sourceEventSeq?: number; + }; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/types.js new file mode 100644 index 0000000..14b7acc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/lib/types/types.js @@ -0,0 +1,10 @@ +/** + * Durable command event vocabulary and the registry's Cordis event + * declaration, shared with type-only consumers. Client-safe: nothing here + * reaches a Host-only symbol, so a Client compilation face reads the same + * `commands/change` signature the Host emits. + * + * @module @deepseek-ai/dsh-commands/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/package.json new file mode 100644 index 0000000..6848d50 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands/package.json @@ -0,0 +1,76 @@ +{ + "name": "@deepseek-ai/dsh-commands", + "description": "Plugin-owned human command registry for DeepSeek Harness UIs", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/interaction/commands" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./brand": { + "types": "./lib/types/brand.d.ts", + "default": "./lib/types/brand.js" + }, + "./typert": { + "types": "./lib/typert.host.d.ts", + "default": "./lib/typert.host.js" + }, + "./remote": { + "types": "./lib/typert.remote-client.d.ts", + "default": "./lib/typert.remote-client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts", + "lib/typert.host.js", + "lib/typert.host.d.ts", + "lib/typert.remote-client.js", + "lib/typert.remote-client.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "zod": "^4.4.3" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..a2fcff1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.i18n.yaml new file mode 100644 index 0000000..de2059d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/extensions/cordis-host-runner/README.md +README.md: f09e7506fe24676ea95b3ae490b55ae120bfad5f +README.zh.md: f60d3a64ecb1e90427b966c820a857e62d65b375 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.md new file mode 100644 index 0000000..f09e750 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.md @@ -0,0 +1,72 @@ +# @deepseek-ai/dsh-cordis-host-runner + +English | [中文](README.zh.md) + +The host half of model-mounted dynamic packages: the definition registry, the `node:vm` sandbox and fiber lifecycle for host halves, the invoke handler table, and the run round trip a browser page carries out. Provided as `ctx.dynamicCordisRunner`. The model-facing tools live in [`@deepseek-ai/dsh-tool-cordis`](../tool-cordis/README.md); the browser half is loaded by [`@deepseek-ai/dsh-cordis-client-runner`](../cordis-client-runner/README.md). + +## What it does + +Two phases: `define` only records, and everything with an effect hangs off a run. + +- `define` / `undefine` own a definition's life. `define` trims and requires the metadata, prechecks each half's syntax by compiling it (running nothing), mints `dyn-`, and records the definition against the session that asked — it has no effect to roll back, so unparseable code is refused before an id exists. `undefine` stops a running definition first, then forgets it. Neither crosses the wire: only the model's own tool call defines. +- `run` answers the model's request to run one definition, and its two shapes differ by whose business the package is. A host-only package is this process's own: the host half is evaluated in the vm under the `cordis-dynamic` group fiber and the call returns. A package with a browser half has to be carried out by a page, so `run` becomes an answerable round trip — it emits `cordis/request-run`, suspends, and is settled by a person allowing or declining it. There is no timer; the caller's `AbortSignal` (the asking turn was cancelled) is the only other way out, and it announces the cancellation so other pages stop offering an answer. Whether any page will answer is not knowable when the request is sent — a page that received it may still never answer, so a deployment with no page connected suspends like any other unanswered request and ends in `cancelled`. `run` has no wire face — `cordis_run` calls it in process. +- `runHostHalf` / `getClientCode` are the steps an allowed page walks, host half first, so a host-half failure short-circuits before the browser has moved. `runHostHalf` is idempotent by contract: a running package is bound rather than evaluated again, concurrent calls for one definition evaluate it once, and `startedHere` names the caller that did. `getClientCode` then hands that one page the browser-half source, refusing a definition that is gone, has no browser half, or is not running. Code never rides an announcement, so this is the only way it reaches a browser. +- `resolveRequestRun` closes the round trip with the answering page's verdict, and broadcasts `cordis/request-run-resolved` so every other page drops the pending affordance. The first answer wins; a later or unknown request id is accepted and ignored. A success naming a revision the registry has moved past is refused rather than applied (`accepted: false`, request still suspended), because the page that answered loaded a dispatch that is no longer live. A failing verdict unwinds the host half only when this same request evaluated it, so a page that cannot load its own half never stops a package the other pages are using. +- `stop` unwinds one live dispatch — handlers dropped, host-half fiber disposed to quiescence, `dynamicCordisRunner/retract` broadcast — and leaves the definition runnable. +- `inventory` answers the whole registry, unaddressed by session and with each row naming the session that owns it, because the run-control surface is global. Listing is not acting: every acting verb still checks that ownership. Each row also names whether the definition has a browser half, so a run-control surface offers loading it into the current page only when there is a half to load. `snapshot` is its session-scoped host-local counterpart, carrying each live host half's fiber so `cordis_inspect` can render provides/waiting/state itself (a fiber cannot cross the wire). +- `reportRenderFailure` records what a page saw a LOADED browser half do wrong at render time. Rendering happens strictly after a load succeeded, so a run has already answered `ok` by then: this report is fire-and-forget, carries no settle authority, and never touches `resolveRequestRun` or any part of the run outcome — **it is not the retired v2 `report`/ack**. The host keeps the last failure per definition across every page (a second page reporting overwrites), and a fresh run, a stop, or an undefine clears it, so the model is never shown a failure from a dispatch that no longer exists. The browser-half face keeps its own "what THIS page is showing now"; the two answer different questions rather than duplicating one. A report for a definition the reporting session does not own is dropped, because the reporting path must never fail a render. +- `invoke` routes one call from a package's browser half to a method its own host half registered with `harness.handle`. The infrastructure only routes — no host-to-browser direction exists. + +A refusal from `run` or `stop` names one of `definition-missing`, `host-half-failed`, `client-half-failed`, `rejected`, `cancelled`, or `not-running`; the last three are answers rather than defects — a person declined, the asking turn ended, or there was nothing running to stop. + +A definition another session defined reads as absent rather than forbidden, so nothing leaks across sessions. `invoke` and `resolveRequestRun` carry no session at all: a component's call and a page's answer are page-global facts, not one session's. + +Four forwarded events belong to this feature, declared by this package on its client-safe [`./types`](src/types.ts) subpath and allowlisted for delivery by [`@deepseek-ai/dsh-api-remotes`](../../api/remotes/README.md), which is what lets a browser reach them through `ctx.remote.$on`: `cordis/request-run` (`{requestId, agentId, id, name, purpose}` — metadata, never code), `cordis/request-run-resolved` (`{requestId, outcome}`), `dynamicCordisRunner/package` (`{id, name, rev}`), and `dynamicCordisRunner/retract` (`{id, rev}`). The last two are a symmetric pair announcing run state — every fresh start and every stop, whether or not the package has a browser half. + +## Storage stance + +The registry is process memory and the only source of truth. The session log carries a define call's metadata — never its code — so a restarted process legitimately has no definitions, and a card whose id no longer resolves says exactly that rather than pretending it can run. Nothing here is written to disk, and no definition is restored automatically; a reloaded page holds nothing until someone runs a package again, which is what makes it bind the live host half and re-fetch the browser half. + +## Trust stance + +The vm sandbox isolates globals but is not a security boundary: Node globals are absent or redirect to Cordis services (`ctx.fs`, `ctx.web`, `ctx.bash`, the timer helpers), and a host half receives a façade without framework internals, yet the services it declares reach the live runtime. Treat a dynamic package like bash access — see the [self-referential toolset Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). + +## Config + +| Field | Default | Meaning | +|---|---|---| +| `vmTimeoutMs` | `5000` | Milliseconds the synchronous portion of a host half may run in the vm before evaluation is aborted | + +One field is all there is: a run request waits for a person, so the round trip has no deadline of its own. + +## Export shape + +Service package: default-exports `DynamicCordisRunnerService` (service key `dynamicCordisRunner`), with `./types` carrying the payload shapes the `dynamicCordisRunner` remote namespace and its consumers share. The `define` / `undefine` shapes stay inside the package, because they never cross the wire. + +## Model Experience + +### Refusals and teaching errors relayed by the cordis tools + +#### What the model sees + +Nothing directly: this package registers no tool and injects no prompt. Its refusals reach the model through the `cordis_*` tool results that call it — an unparseable half names the offending line, a missing definition explains that definitions live in memory only, a `rejected` or `cancelled` run reports that a person declined or the turn ended rather than that anything failed, and a failed browser-half load carries the answering page's own error text. + +#### Token effect + +None of its own: every message above is carried by the calling tool's result. + +#### KV Cache effect + +A host half that registers tools changes the next request's tool view, which invalidates prefix reuse from the first changed schema token; running or stopping a package with no tool registrations is prefix-neutral. + +## Known Limitations and Deferred Work + +- **A successful run does not mean the UI rendered.** `run` returns once the answering page has LOADED the browser half; React renders afterwards, so a component that throws cannot possibly appear in the run receipt. The failure surfaces through `reportRenderFailure` and is read back with `cordis_inspect what:"temporary"`; the run result says so rather than implying success. + +- A package with a browser half **suspends where no page is connected** — headless and ACP deployments hold the run until the asking turn is cancelled, because a forwarded event reports nothing about who received it. Host-only packages are unaffected. +- A suspended run request has **no timeout**: it waits for a person until the asking turn is cancelled, so unattended automation cannot use packages with a browser half. +- `vmTimeoutMs` bounds only synchronous evaluation; an async host-half body escapes it, matching the toolset's cooperative trust stance. +- `runHostHalf` carries no request id, so "which request evaluated this host half" is attributed host-side to the most recently armed request for that definition; several concurrent run requests for one definition would need that rule revisited. +- A success answer naming a superseded revision is refused (`accepted: false`) and leaves the request suspended, so the model's call ends only through a valid answer or its own cancellation. Settling it would take a fresh orchestration against the live revision, and no page does that today — the [browser half](../cordis-client-runner/README.md) does not read the ack — so in practice such a request is closed by another page's answer or by the caller's cancellation. +- A browser half's declared `inject` is read from the plugin it returns in the page, so the announcement carries no service-declaration field at all. +- **`zod` is a runtime dependency of the generated TypeRT faces, not of `src`.** `./typert` and `./remote` resolve to `lib/typert.*.js`, which `tsc` emits unbundled with a bare `import { z } from 'zod'`, so the package must declare it (the `@deepseek-ai/dsh-goal` precedent) and `knip.json` must ignore it for this workspace — knip reads source, and these faces are build products. Nothing in `src` imports zod. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.zh.md new file mode 100644 index 0000000..f60d3a6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.zh.md @@ -0,0 +1,72 @@ +# @deepseek-ai/dsh-cordis-host-runner + +[English](README.md) | 中文 + +由模型挂载的动态包在 host 侧的那一半:定义注册表、host 半所用的 `node:vm` 沙箱与 fiber 生命周期、invoke handler 表,以及由某个浏览器页面执行的 run 往返。以 `ctx.dynamicCordisRunner` 提供。面向模型的工具在 [`@deepseek-ai/dsh-tool-cordis`](../tool-cordis/README.md) 中;浏览器半由 [`@deepseek-ai/dsh-cordis-client-runner`](../cordis-client-runner/README.md) 装载。 + +## 功能 + +分两个阶段:`define` 只做登记,一切带副作用的动作都挂在一次 run 上。 + +- `define`/`undefine` 掌管一个定义的生命周期。`define` 对元数据做首尾去空白与必填校验,通过编译预检每一半的语法(不执行任何代码),铸出 `dyn-`,并把该定义登记在发起调用的会话名下——它没有任何可回滚的副作用,所以无法解析的代码在拿到 id 之前就被拒绝。`undefine` 先停掉正在运行的定义,再把它忘掉。两者都不上 wire:只有模型自己的工具调用才会 define。 +- `run` 回答模型「运行某个定义」的请求,它的两种形态取决于这个包是谁的事。只有 host 半的包是本进程自己的事:host 半在 `cordis-dynamic` group fiber 之下于 vm 中求值,调用随即返回。带浏览器半的包必须由一个页面来执行,于是 `run` 变成一次可作答的往返——它 emit `cordis/request-run`、挂起,并由某个人允许或拒绝来结束。这里没有定时器;调用方的 `AbortSignal`(提问的那一轮次被取消)是唯一的另一条出路,而且它会把这次取消播报出去,让其他页面不再提供作答入口。请求发出时**并不知道**会不会有人作答——收到它的页面也可能永远不答,所以没有页面连接的部署与其他未作答请求一样挂起,最终以 `cancelled` 收场。`run` 没有 wire 面——`cordis_run` 在进程内调用它。 +- `runHostHalf`/`getClientCode` 是获得允许的页面依次走的步骤,host 半在先,因此 host 半失败会在浏览器还没动作之前短路。`runHostHalf` 在约定上是幂等的:已在运行的包只做绑定,不再求值;针对同一个定义的并发调用只求值一次,`startedHere` 指出求值的是哪一个调用方。随后 `getClientCode` 把浏览器半的源码交给这一个页面;定义已消失、没有浏览器半、或未在运行时,它会拒绝。代码从不搭乘任何播报,所以这是它到达浏览器的唯一途径。 +- `resolveRequestRun` 用作答页面的结论结束这次往返,并 emit `cordis/request-run-resolved`,让其他每个页面撤下待作答的入口。首答即成;更晚的或未知的 request id 会被接受并忽略。命名了注册表已越过的版本的成功结论会被拒绝而非应用(`accepted: false`,请求仍处于挂起),因为作答的那个页面装载的是一个已不再存活的下发。失败的结论只会在 host 半正是由这次请求求值时才将它回退,因此某个页面装不上自己那一半,绝不会把其他页面正在使用的包停掉。 +- `stop` 回退一次存活的下发——丢弃 handler、把 host 半 fiber dispose(资源释放)到完全停稳、emit `dynamicCordisRunner/retract`——并让该定义仍然可运行。 +- `inventory` 回答整个注册表,不按会话寻址,且每一行都指明拥有该定义的会话,因为运行控制面是全局的。能列出不等于能操作:每个有实际动作的动词仍会检查这份归属。每一行还会指明该定义有没有浏览器半,因此运行控制面只在确有可装载的半时,才提供「装入当前页面」。`snapshot` 是它按会话限定的 host 本地对侧,携带每个存活 host 半的 fiber,供 `cordis_inspect` 自行渲染 provides/waiting/state(fiber 无法跨 wire)。 +- `reportRenderFailure` 记录某个页面看到一个**已装载**的浏览器半在渲染时做错了什么。渲染严格发生在装载成功之后,因此到那时 run 早已回答了 `ok`:这份上报是 fire-and-forget 的,不带任何结算权威,也绝不触碰 `resolveRequestRun` 或 run 结论的任何部分——**它不是那个已退役的 v2 `report`/ack**。host 按定义保留跨所有页面的最后一次失败(第二个页面上报即覆盖),而一次全新的 run、一次 stop 或一次 undefine 都会清掉它,因此模型绝不会看到一次已不存在的下发留下的失败。浏览器半的契约面自己保留一份「**这个页面**当前正在显示什么」;两者回答的是不同的问题,不是同一个问题的两份答案。上报的会话若并不拥有该定义,这次上报会被丢弃,因为上报路径绝不能让一次渲染失败。 +- `invoke` 把一个包的浏览器半发起的一次调用,路由到它自己的 host 半用 `harness.handle` 注册的方法。这套基础设施只做路由:不存在 host 到浏览器的方向。 + +`run` 或 `stop` 的拒绝会给出 `definition-missing`、`host-half-failed`、`client-half-failed`、`rejected`、`cancelled`、`not-running` 之一;后三者是答复而非缺陷——有人拒绝了、提问的那一轮次已结束,或本来就没有在运行的东西可停。 + +别的会话登记的定义读起来是不存在,而不是被禁止,因此不会跨会话泄漏任何东西。`invoke` 与 `resolveRequestRun` 完全不携带会话:组件的一次调用和页面的一次作答都是页面全局的事实,不属于某一个会话。 + +本功能拥有四条转发事件,由本包在其 client-safe 的 [`./types`](src/types.ts) 子路径上声明,并由 [`@deepseek-ai/dsh-api-remotes`](../../api/remotes/README.md) 的白名单准许投递——正是这一点让浏览器能经 `ctx.remote.$on` 收到它们:`cordis/request-run`(`{requestId, agentId, id, name, purpose}`——只有元数据,绝无代码)、`cordis/request-run-resolved`(`{requestId, outcome}`)、`dynamicCordisRunner/package`(`{id, name, rev}`),以及 `dynamicCordisRunner/retract`(`{id, rev}`)。后两者是对称的一对运行状态播报:每次全新启动与每次停止都播,与该包有没有浏览器半无关。 + +## 存储立场 + +注册表就是进程内存,也是唯一真源。会话日志只承载一次 define 调用的元数据,绝不承载它的代码:因此进程重启后确实没有任何定义,这是合理的;而 id 已无法解析的卡片会如实说明这一点,不会假装自己还能运行。本包不向磁盘写任何东西,也不会自动恢复任何定义;刷新过的页面手上什么都没有,直到有人再次运行某个包——正是这一步让它绑定存活的 host 半并重新取回浏览器半。 + +## 信任立场 + +vm 沙箱隔离全局变量,但不是安全边界:Node 全局变量不存在,或重定向到 Cordis 服务(`ctx.fs`、`ctx.web`、`ctx.bash` 以及定时器 helper),host 半收到的是不含框架内部机制的 façade,但它声明的服务仍会触达存活运行时。应当像对待 bash 访问一样对待动态包,参见[自引用工具集 Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md)。 + +## 配置 + +| 字段 | 默认值 | 含义 | +|---|---|---| +| `vmTimeoutMs` | `5000` | host 半在 vm 中同步执行的那部分被中止求值前可运行的毫秒数 | + +就这一个字段:一次 run 请求等的是人,所以这趟往返本身没有任何截止期限。 + +## 导出形状 + +服务包:默认导出 `DynamicCordisRunnerService`(服务键 `dynamicCordisRunner`),`./types` 则承载 `dynamicCordisRunner` remote namespace 与其消费方共享的载荷形状。`define`/`undefine` 的形状留在包内部,因为它们从不跨 wire。 + +## 模型体验 + +### 经 cordis 工具转达的拒绝与教学式错误 + +#### 模型看到的内容 + +没有直接可见的内容:本包不注册任何工具,也不注入提示词。它的拒绝经调用它的 `cordis_*` 工具结果到达模型——无法解析的半会指出出错的那一行,缺失的定义会解释定义只活在内存里,`rejected` 或 `cancelled` 的 run 报告的是有人拒绝或该轮次已结束而非出了故障,浏览器半装载失败则带上作答页面自己的错误文本。 + +#### Token 影响 + +本包自身没有:上述每条消息都由调用它的那个工具的结果承载。 + +#### KV Cache 影响 + +注册工具的 host 半会改变下一次请求的工具视图,从第一个变化的 schema token 起使前缀复用失效;运行或停止一个不注册任何工具的包对前缀不产生影响。 + +## 已知限制与暂缓事项 + +- **run 成功不等于 UI 渲染成功。** 只要作答页面**已装载**浏览器半,`run` 就会返回;React 是随后才渲染的,因此一个抛异常的组件根本不可能出现在 run 的回执里。该失败经 `reportRenderFailure` 浮现,并通过 `cordis_inspect what:"temporary"` 读回;run 的结果会把这一点说出来,而不是暗示成功。 + +- 带浏览器半的包在**没有页面连接的地方会挂起**——headless 与 ACP(Agent Client Protocol)部署会把这次 run 一直挂到提问的轮次被取消,因为转发事件不回报谁收到了它。只有 host 半的包不受影响。 +- 挂起的 run 请求**没有超时**:它一直等人,直到提问的那一轮次被取消,因此无人值守的自动化用不了带浏览器半的包。 +- `vmTimeoutMs` 只约束同步求值;async 的 host 半函数体会逃出该上限,这与该工具集基于协作的信任立场一致。 +- `runHostHalf` 不携带 request id,因此「这个 host 半是哪次请求求值的」由 host 侧归因到该定义最近一次挂起的请求;若同一个定义出现多个并发 run 请求,这条规则需要重新审议。 +- 命名了已被取代版本的成功结论会被拒绝(`accepted: false`)并让该请求继续挂起,因此模型这次调用只能靠一次有效作答或自身被取消才结束。要把它结算掉,需要对着存活版本重新走一遍编排,而当前没有任何页面会这么做——[浏览器半](../cordis-client-runner/README.md)不读这个 ack——所以这类请求实际上由别的页面作答、或由调用方取消来收尾。 +- 浏览器半声明的 `inject` 是从它在页面里返回的插件上读出的,因此播报完全不携带服务声明字段。 +- **`zod` 是生成的 TypeRT 契约面的运行时依赖,不是 `src` 的依赖。** `./typert` 与 `./remote` 解析到 `lib/typert.*.js`,`tsc` 以不打包的形式产出它们,其中带有裸的 `import { z } from 'zod'`,所以本包必须声明它(沿用 `@deepseek-ai/dsh-goal` 的先例),而 `knip.json` 必须在这个 workspace 里忽略它:knip 读的是源码,而这些契约面是构建产物。`src` 里没有任何代码 import zod。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/index.js new file mode 100644 index 0000000..d435325 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/index.js @@ -0,0 +1,2573 @@ +import z from "@deepseek-ai/schemastery"; +import { createUserMessage } from "@deepseek-ai/dsh-llm"; +import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol"; +import { Context, Service } from "@deepseek-ai/cordis"; +import { scopeOf } from "@deepseek-ai/dsh-scope"; +import { assertSupportedJsonSchema, defineTool, validateJsonSchemaValue } from "@deepseek-ai/dsh-tools"; +import { snapshotJsonValue } from "@deepseek-ai/dsh-session"; +import { Script, createContext, runInContext } from "node:vm"; +//#region lib/types/guard.js +/** +* The registration boundary between a sandboxed host half and the real runtime: ParameterSchemaSpec +* normalization + validation with teaching errors, the marker-guarded `harness.defineTool` / +* `harness.registerTool` pair, the `harness.handle` invoke-handler normalizer, the SANDBOX CONTEXT +* FAÇADE a running plugin's `apply` receives in place of the real `ctx`, and the plugin-shape +* helpers the run lifecycle narrows sandbox return values with. The façade is a whitelist of +* lifecycle-safe verbs and declared services; framework internals and context-valued service +* returns are denied. +* +* VM-realm schemas and canonical values are rebuilt as host objects, while rendered content and +* presentation metadata are shape-checked before entering the registry. Common JSON-Schema spellings are normalized when they +* have one meaning; invalid vocabulary fails during registration with a teaching error. +* @module @deepseek-ai/dsh-cordis-host-runner/guard +*/ +const DYNAMIC_TOOL = Symbol("cordis-host-runner.dynamic-tool"); +const SCHEMA_TYPES = new Set([ + "string", + "number", + "integer", + "boolean", + "null", + "object", + "array", + "json" +]); +const VALID_TYPES = "'string' | 'number' | 'integer' | 'boolean' | 'null' | 'object' | 'array' | 'json'"; +const ANNOTATION_KEYS = [ + "description", + "title", + "default", + "examples" +]; +function isPlainRecord(value) { + if (typeof value !== "object" || value === null || Array.isArray(value)) return false; + const prototype = Object.getPrototypeOf(value); + return prototype === null || typeof prototype === "object" && Object.getPrototypeOf(prototype) === null && hasIntrinsicConstructor(prototype, "Object"); +} +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const constructor = Object.getOwnPropertyDescriptor(prototype, "constructor")?.value; + if (typeof constructor !== "function") return false; + try { + return constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } catch { + return false; + } +} +/** Whether an array uses one realm's intrinsic Array prototype rather than a subclass. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, "Array")) return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === "object" && objectPrototype !== null && Object.getPrototypeOf(objectPrototype) === null && hasIntrinsicConstructor(objectPrototype, "Object"); +} +/** Whether a schema list is a dense intrinsic array with no JSON-invisible decorations. */ +function isDensePlainArray(value) { + if (!Array.isArray(value) || !hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false; + for (let index = 0; index < value.length; index++) if (!Object.hasOwn(value, index)) return false; + return true; +} +/** Reject schema records whose declarations would disappear from object enumeration. */ +function assertSchemaContainerKeys(value, path) { + if (Reflect.ownKeys(value).some((key) => typeof key !== "string" || !Object.prototype.propertyIsEnumerable.call(value, key))) throw new Error(`harness.defineTool ${path} must contain only own enumerable string keys`); +} +/** Materialize realm-foreign lossless JSON without allowing JSON.stringify coercions; `path` carries the caller's own error prefix. */ +function cloneJson(value, path) { + const ancestors = /* @__PURE__ */ new Set(); + let root; + const assign = (destination, item) => { + if (destination.kind === "root") { + root = item; + return; + } + if (destination.kind === "array") { + destination.target[destination.index] = item; + return; + } + Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true + }); + }; + const reject = (at) => { + throw new Error(`${at} must be lossless JSON data (objects, arrays, strings, numbers, booleans, null) — not a class instance, function, Map/Set, Date, or undefined. Return a plain object built from the values you need, or \`return null\` when the caller needs no value back.`); + }; + const tasks = [{ + kind: "visit", + value, + path, + destination: { kind: "root" } + }]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "leave") { + ancestors.delete(task.source); + continue; + } + if (task.kind === "array-item") { + if (!Object.hasOwn(task.source, task.index)) reject(task.path); + tasks.push({ + kind: "visit", + value: task.source[task.index], + path: `${task.path}[${task.index}]`, + destination: { + kind: "array", + target: task.target, + index: task.index + } + }); + continue; + } + const current = task.value; + if (current === null || typeof current === "string" || typeof current === "boolean") { + assign(task.destination, current); + continue; + } + if (typeof current === "number") { + if (!Number.isFinite(current) || Object.is(current, -0)) reject(task.path); + assign(task.destination, current); + continue; + } + if (typeof current !== "object" || ancestors.has(current)) reject(task.path); + if (Array.isArray(current)) { + if (!hasPlainArrayPrototype(current) || Reflect.ownKeys(current).length !== current.length + 1) reject(task.path); + const output = []; + assign(task.destination, output); + ancestors.add(current); + tasks.push({ + kind: "leave", + source: current + }); + for (let index = current.length - 1; index >= 0; index--) tasks.push({ + kind: "array-item", + source: current, + index, + path: task.path, + target: output + }); + continue; + } + if (!isPlainRecord(current)) reject(task.path); + const record = current; + if (Reflect.ownKeys(record).some((key) => typeof key !== "string" || !Object.prototype.propertyIsEnumerable.call(record, key))) reject(task.path); + const output = {}; + assign(task.destination, output); + ancestors.add(record); + tasks.push({ + kind: "leave", + source: record + }); + const entries = Object.entries(record); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === void 0) continue; + tasks.push({ + kind: "visit", + value: entry[1], + path: `${task.path}.${entry[0]}`, + destination: { + kind: "object", + target: output, + key: entry[0] + } + }); + } + } + return root; +} +/** Copy and realm-materialize the shared annotation vocabulary. */ +function copyAnnotations(value, output, path) { + if (Object.hasOwn(value, "description")) output.description = value.description; + if (Object.hasOwn(value, "title")) output.title = value.title; + if (Object.hasOwn(value, "default")) output.default = cloneJson(value.default, `harness.defineTool ${path}.default`); + if (Object.hasOwn(value, "examples")) output.examples = cloneJson(value.examples, `harness.defineTool ${path}.examples`); +} +/** Reject sandbox schema keys that the unified DSL would otherwise ignore. */ +function assertSchemaKeys(value, path, allowed) { + assertSchemaContainerKeys(value, path); + for (const key of Object.keys(value)) if (!allowed.includes(key)) throw new Error(`harness.defineTool ${path}.${key} is not supported by the unified schema DSL`); +} +/** +* Normalize a sandbox-provided `parameters` value into a fresh host-realm +* ParameterSchemaSpec. A raw JSON-Schema object wrapper retains its open root +* default, while the direct DSL is already an implicit open property map. +*/ +function normalizeParameterSchemaSpec(value, path = "parameters") { + if (!isPlainRecord(value)) throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec object`); + if (value.type === "object") { + assertSchemaKeys(value, path, [ + "type", + "properties", + "required", + "additionalProperties", + ...ANNOTATION_KEYS + ]); + if (!isPlainRecord(value.properties)) throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`); + if (Object.hasOwn(value, "additionalProperties") && value.additionalProperties !== true) throw new Error(`harness.defineTool ${path}.additionalProperties must be true or omitted because the implicit parameter root is open`); + if (Object.hasOwn(value, "required") && value.required === void 0) throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`); + const required = normalizeRequiredNames(value.required, value.properties, `${path}.required`); + const rootAnnotations = {}; + copyAnnotations(value, rootAnnotations, path); + return { + spec: normalizePropertyMap(value.properties, path, required, true), + ...Object.keys(rootAnnotations).length === 0 ? {} : { rootAnnotations } + }; + } + return { spec: normalizePropertyMap(value, path, /* @__PURE__ */ new Set(), false) }; +} +/** Validate raw required names and return their lookup set. */ +function normalizeRequiredNames(value, properties, path) { + if (value === void 0) return /* @__PURE__ */ new Set(); + if (!isDensePlainArray(value)) throw new Error(`harness.defineTool ${path} must be an array of declared property names`); + const names = /* @__PURE__ */ new Set(); + for (let index = 0; index < value.length; index++) { + const name = value[index]; + if (typeof name !== "string") throw new Error(`harness.defineTool ${path} must be an array of declared property names`); + names.add(name); + if (!Object.hasOwn(properties, name)) throw new Error(`harness.defineTool ${path} names undeclared property ${JSON.stringify(name)}`); + } + return names; +} +/** Install one normalized node without `__proto__` assignment semantics. */ +function assignNormalizedValue(destination, value) { + if (destination.kind === "property") Object.defineProperty(destination.target, destination.key, { + value, + enumerable: true, + configurable: true, + writable: true + }); + else if (destination.kind === "item") destination.target.items = value; + else destination.target[destination.index] = value; +} +/** Install one normalized property map at its root or containing object. */ +function assignNormalizedMap(destination, value) { + if (destination.kind === "root") destination.holder.value = value; + else destination.target.properties = value; +} +/** Normalize one implicit property map and all descendants with explicit work frames. */ +function normalizePropertyMap(entries, path, requiredNames, raw) { + const holder = {}; + const ancestors = /* @__PURE__ */ new Set(); + const tasks = [{ + kind: "map", + entries, + path, + requiredNames, + raw, + destination: { + kind: "root", + holder + } + }]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "leave") { + ancestors.delete(task.value); + continue; + } + if (task.kind === "map") { + if (ancestors.has(task.entries)) throw new Error(`harness.defineTool ${task.path} is circular`); + assertSchemaContainerKeys(task.entries, task.path); + ancestors.add(task.entries); + const spec = {}; + assignNormalizedMap(task.destination, spec); + tasks.push({ + kind: "leave", + value: task.entries + }); + const mapEntries = Object.entries(task.entries); + for (let index = mapEntries.length - 1; index >= 0; index--) { + const entry = mapEntries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === void 0) continue; + tasks.push({ + kind: "value", + value: entry[1], + path: `${task.path}.${entry[0]}`, + forceRequired: task.requiredNames.has(entry[0]), + raw: task.raw, + parameterProperty: true, + destination: { + kind: "property", + target: spec, + key: entry[0] + } + }); + } + continue; + } + const { value, path } = task; + if (!isPlainRecord(value)) throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec property object`); + assertSchemaContainerKeys(value, path); + if (ancestors.has(value)) throw new Error(`harness.defineTool ${path} is circular`); + ancestors.add(value); + const requiredKey = task.parameterProperty && !task.raw ? ["required"] : []; + if (task.parameterProperty && task.raw && Object.hasOwn(value, "required") && value.type !== "object") throw new Error(`harness.defineTool ${path}.required belongs to the containing raw object schema`); + if (task.parameterProperty && !task.raw && Object.hasOwn(value, "required") && value.required !== true) throw new Error(`harness.defineTool ${path}.required must be true when present`); + const prop = {}; + assignNormalizedValue(task.destination, prop); + tasks.push({ + kind: "leave", + value + }); + if (task.forceRequired || value.required === true) prop.required = true; + copyAnnotations(value, prop, path); + if (Object.hasOwn(value, "oneOf")) { + assertSchemaKeys(value, path, [ + "oneOf", + ...requiredKey, + ...ANNOTATION_KEYS + ]); + if (!isDensePlainArray(value.oneOf) || value.oneOf.length < 2) throw new Error(`harness.defineTool ${path}.oneOf must contain at least two schemas`); + const oneOf = []; + prop.oneOf = oneOf; + for (let index = value.oneOf.length - 1; index >= 0; index--) tasks.push({ + kind: "value", + value: value.oneOf[index], + path: `${path}.oneOf[${index}]`, + forceRequired: false, + raw: task.raw, + parameterProperty: false, + destination: { + kind: "one-of", + target: oneOf, + index + } + }); + continue; + } + if (task.raw && !Object.hasOwn(value, "type")) { + assertSchemaKeys(value, path, ANNOTATION_KEYS); + prop.type = "json"; + continue; + } + if (!SCHEMA_TYPES.has(value.type) || task.raw && value.type === "json") throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES} (got ${JSON.stringify(value.type)})`); + const type = value.type; + prop.type = type; + switch (type) { + case "object": + assertSchemaKeys(value, path, [ + "type", + "properties", + "additionalProperties", + ...requiredKey, + ...task.raw ? ["required"] : [], + ...ANNOTATION_KEYS + ]); + if (!task.raw && (!Object.hasOwn(value, "additionalProperties") || typeof value.additionalProperties !== "boolean")) throw new Error(`harness.defineTool ${path}.additionalProperties must be explicitly true or false`); + if (task.raw && Object.hasOwn(value, "additionalProperties") && typeof value.additionalProperties !== "boolean") throw new Error(`harness.defineTool ${path}.additionalProperties must be a boolean`); + if (task.raw && Object.hasOwn(value, "required") && value.required === void 0) throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`); + prop.additionalProperties = task.raw ? value.additionalProperties ?? true : value.additionalProperties; + if (Object.hasOwn(value, "properties")) { + const properties = value.properties; + if (!isPlainRecord(properties)) throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`); + const nestedRequired = task.raw ? normalizeRequiredNames(value.required, properties, `${path}.required`) : /* @__PURE__ */ new Set(); + tasks.push({ + kind: "map", + entries: properties, + path: `${path}.properties`, + requiredNames: nestedRequired, + raw: task.raw, + destination: { + kind: "properties", + target: prop + } + }); + } else if (task.raw && value.required !== void 0) normalizeRequiredNames(value.required, {}, `${path}.required`); + break; + case "array": + assertSchemaKeys(value, path, [ + "type", + "items", + ...requiredKey, + ...ANNOTATION_KEYS + ]); + if (Object.hasOwn(value, "items")) tasks.push({ + kind: "value", + value: value.items, + path: `${path}.items`, + forceRequired: false, + raw: task.raw, + parameterProperty: false, + destination: { + kind: "item", + target: prop + } + }); + break; + case "string": + case "number": + case "integer": + case "boolean": + case "null": + assertSchemaKeys(value, path, [ + "type", + "enum", + "const", + ...requiredKey, + ...ANNOTATION_KEYS + ]); + if (Object.hasOwn(value, "enum")) { + if (!isDensePlainArray(value.enum) || value.enum.length === 0) throw new Error(`harness.defineTool ${path}.enum must be a non-empty array`); + prop.enum = cloneJson(value.enum, `harness.defineTool ${path}.enum`); + } + if (Object.hasOwn(value, "const")) prop.const = cloneJson(value.const, `harness.defineTool ${path}.const`); + break; + case "json": + assertSchemaKeys(value, path, [ + "type", + ...requiredKey, + ...ANNOTATION_KEYS + ]); + break; + /* v8 ignore next 2 -- SCHEMA_TYPES narrows this closed switch before dispatch. */ + default: throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES}`); + } + } + /* v8 ignore next -- the root map task assigns before scheduling descendants. */ + return holder.value ?? {}; +} +function markDynamicTool(tool) { + Object.defineProperty(tool, DYNAMIC_TOOL, { value: true }); + return tool; +} +function assertDynamicTool(tool) { + if (!isPlainRecord(tool) || tool[DYNAMIC_TOOL] !== true) throw new Error("dynamic tool registration must use a tool returned by harness.defineTool(...)"); +} +/** +* Structurally a content block, checked AFTER the JSON round-trip: a plain +* object carrying a string `type` tag. Deliberately nothing deeper — the +* ContentBlock union is merge-extensible (an unknown tag must pass), and every +* downstream consumer dispatches on `type` and falls through unknowns. +*/ +function isContentBlockShape(value) { + return isPlainRecord(value) && typeof value.type === "string"; +} +/** +* How much of an invalid execute return the teaching error echoes back — a +* huge blob would burn the model turn the error is trying to save. +*/ +const RETURN_PREVIEW_LIMIT = 120; +/** +* Compact JSON preview of an invalid execute return for the teaching error +* (`String(…)` for the un-stringifiable undefined case), truncated to +* {@link RETURN_PREVIEW_LIMIT}. +*/ +function describeReturn(value) { + const json = JSON.stringify(value); + return json.length > RETURN_PREVIEW_LIMIT ? `${json.slice(0, RETURN_PREVIEW_LIMIT)}…` : json; +} +/** +* Validate and host-materialize a sandbox renderer's content blocks. +*/ +function assertRenderedContent(value) { + if (Array.isArray(value) && value.every(isContentBlockShape)) return value; + throw new Error(`output.render returned ${describeReturn(value)} — it must return an ARRAY of content blocks:\n ✓ return [{ type: 'text', text: String(value) }]`); +} +/** +* The `harness.defineTool` handed into the sandbox: the real DSL, with `parameters` normalized +* into a fresh host-realm ParameterSchemaSpec (raw object wrappers unwrapped, +* required arrays mapped, and explicit DSL object openness enforced) and the tool's `execute` return normalized into the host realm +* via a JSON round-trip. Non-JSON or wrong-shape output fails that call instead of poisoning +* the session log. +* @param options - the standard `defineTool` options; `parameters` may be the ParameterSchemaSpec DSL or a JSON-Schema-style wrapper. +* @returns the marker-tagged definition `harness.registerTool` (and the guarded `ctx.tools.register`) accepts. +*/ +function sandboxDefineTool(options) { + if (!isPlainRecord(options)) throw new Error("harness.defineTool options must be an object"); + const normalized = normalizeParameterSchemaSpec(options.parameters); + if (!isPlainRecord(options.output)) throw new Error("harness.defineTool output must declare { schema, render, presentationMeta? }"); + const output = options.output; + if (typeof output.render !== "function") throw new Error("harness.defineTool output.render must be a function"); + if (output.presentationMeta !== void 0 && typeof output.presentationMeta !== "function") throw new Error("harness.defineTool output.presentationMeta must be a function when present"); + if (typeof options.execute !== "function") throw new Error("harness.defineTool execute must be a function"); + const schema = cloneJson(output.schema, "harness.defineTool output.schema"); + const rawExecute = options.execute; + const rawRender = output.render; + const rawPresentationMeta = output.presentationMeta; + const tool = defineTool({ + ...options, + parameters: normalized.spec, + output: { + schema, + render(args, value) { + return assertRenderedContent(cloneJson(rawRender(args, value), "harness.defineTool output.render result")); + }, + ...rawPresentationMeta !== void 0 ? { presentationMeta(args, value) { + return cloneJson(rawPresentationMeta(args, value), "harness.defineTool output.presentationMeta result"); + } } : {} + }, + async execute(args, exec) { + return cloneJson(await rawExecute(args, exec), "harness.defineTool execute result"); + } + }); + const parameters = { + ...tool.parameters, + ...normalized.rootAnnotations + }; + assertSupportedJsonSchema(parameters); + return markDynamicTool({ + ...tool, + parameters + }); +} +/** +* Normalize one `harness.handle` registration at the sandbox boundary: the +* method name must be a non-empty string and the handler a function whose +* result is host-materialized through the same cross-realm JSON clone as tool +* `execute` returns (a VM-realm object would otherwise escape the wire's +* plain-object contract). +* @param method - handler name the package's browser half calls through `host.call`. +* @param fn - sandbox handler receiving the wire-decoded JSON arguments. +* @returns the validated name and the clone-wrapped handler. +*/ +function normalizeHandler(method, fn) { + if (typeof method !== "string" || method.length === 0) throw new Error("harness.handle(method, fn) needs a non-empty string method name"); + if (typeof fn !== "function") throw new Error(`harness.handle("${method}") needs a handler function as its second argument`); + const rawHandler = fn; + return { + method, + handler: async (args) => cloneJson(await rawHandler(args), `harness.handle("${method}") result`) + }; +} +/** +* The `harness.registerTool` handed into the sandbox: registers a +* marker-verified dynamic tool on the given context's registry. +* @param ctx - the (guarded) context whose `tools` service receives the tool. +* @param tool - a definition produced by {@link sandboxDefineTool}; anything else is rejected. +* @returns the registry disposer for the registration. +*/ +function sandboxRegisterTool(ctx, tool) { + assertDynamicTool(tool); + return ctx.tools.register(tool); +} +/** +* The verbs a running host half may reach through the sandbox `ctx` façade, beyond its injected +* services. `on`/`once` observe events, `provide` exposes a service to other packages, and the +* timer helpers schedule work — each a fiber effect that unwinds when the package stops. +*/ +const CTX_VERBS = new Set([ + "effect", + "on", + "once", + "provide", + "timeout", + "interval", + "setTimeout", + "setInterval", + "throttle", + "debounce" +]); +const TIMER_VERBS = new Set([ + "timeout", + "interval", + "setTimeout", + "setInterval", + "throttle", + "debounce" +]); +/** +* The tool-registry façade: `register` (marker-guarded) plus READ-ONLY +* metadata (`schemas`, and `get` returning a schema view, never the live +* `ToolDefinition`). Exposing the raw definition would hand package code the +* tool's `execute` function, letting it call another tool directly and bypass +* `ToolRuntime.execute` — identity protection, pre-policy, monotonic guards, +* around dispatch, post-policy, final observation, and result normalization. So `get` returns the same +* name/description/parameters view as `schemas()`, and nothing invocable. +*/ +function sandboxTools(ctx) { + return { + register: (tool) => sandboxRegisterTool(ctx, tool), + schemas: () => ctx.tools.schemas(scopeOf(ctx)), + get: (name) => ctx.tools.schemas(scopeOf(ctx)).find((schema) => schema.name === name) + }; +} +/** +* Reject any injected-service return that is a cordis `Context`. Harness +* services return data, never a context; a value that is one would be a +* fresh, unguarded handle back into the runtime — the exact escape the façade +* exists to close — so it fails loud instead of reaching sandbox code. +*/ +function denyContext(value, service, reportFailure) { + if (value instanceof Context) return rejectGuard(reportFailure, `service "${service}" returned a cordis Context, which the sandbox does not expose. Operate through your own plugin ctx (ctx.on / ctx.provide / ctx.tools.register) and the services you inject — never another context.`); + return value; +} +/** +* Wrap an injected service so its methods forward to the real instance but +* their return values pass through {@link denyContext}. Non-function members +* (plain data) pass through as-is; a returned Promise is guarded on resolve. +*/ +function guardedService(service, name, reportFailure) { + return new Proxy(service, { get(target, prop) { + const value = Reflect.get(target, prop, target); + if (typeof value !== "function") return denyContext(value, name, reportFailure); + return (...args) => { + const result = Reflect.apply(value, target, args); + if (result instanceof Promise) return result.then((v) => denyContext(v, name, reportFailure)); + return denyContext(result, name, reportFailure); + }; + } }); +} +/** +* The service names a plugin declared in `inject`, as a lookup set. Whatever +* declaration style the plugin used — an `inject: ['bash', 'tools']` array or +* the `{ required, optional }` object form — cordis resolves it into a single +* name-keyed map on the fiber before `apply` runs (`{ bash: null, tools: null }`), +* so the gate just reads that map's keys. A host half may reach only the services +* it declared — that is what lets cordis park it when a declared provider +* goes away. +*/ +function declaredInjects(ctx) { + return new Set(Object.keys(ctx.fiber.inject)); +} +/** +* Whitelist context for running host halves: lifecycle-safe verbs, guarded +* tools, optional `ctx.get()` lookup, and declared-service property access. +* Framework plumbing is denied, and service methods cannot return a Context. +*/ +function sandboxContext(ctx, reportFailure) { + const tools = sandboxTools(ctx); + const declared = declaredInjects(ctx); + const denyRead = (prop) => { + if (ctx.get(prop) !== void 0) return rejectGuard(reportFailure, `service "${prop}" is not injected. Declare it: inject: ['${prop}', …] on your plugin, so cordis parks this dynamic package if the provider later goes away.`); + return rejectGuard(reportFailure, `sandbox ctx does not expose "${prop}". Available: ctx.tools.register / ctx.on / ctx.provide / the timer helpers after injecting timer, and any service you declared in inject. Framework internals (root, fiber, registry, extend, plugin, …) are withheld by design.`); + }; + const readService = (name, requireDeclaration) => { + if (name === "tools") return tools; + if (requireDeclaration && !declared.has(name)) return denyRead(name); + const service = denyContext(ctx.get(name), name, reportFailure); + if (service === null || typeof service !== "object" && typeof service !== "function") return service; + return guardedService(service, name, reportFailure); + }; + const get = (name) => readService(name, false); + return new Proxy({}, { + get(_target, prop) { + if (prop === "tools") return tools; + if (prop === "get") return get; + if (typeof prop !== "string") return void 0; + if (CTX_VERBS.has(prop)) return (...args) => { + if (TIMER_VERBS.has(prop) && !declared.has("timer")) return denyRead("timer"); + const method = ctx[prop]; + return Reflect.apply(method, ctx, args); + }; + return readService(prop, true); + }, + set(_target, prop) { + return rejectGuard(reportFailure, `sandbox ctx is read-only; cannot assign "${String(prop)}"`); + }, + has: (_target, prop) => prop === "tools" || prop === "get" || typeof prop === "string" && (CTX_VERBS.has(prop) && (!TIMER_VERBS.has(prop) || declared.has("timer")) || declared.has(prop)) + }); +} +/** +* Narrow an arbitrary sandbox return value to a runnable cordis plugin: a +* function, or an object with an `apply` function. (A bare function passes the +* first arm, so the object arm never sees `Function.prototype.apply`.) +* @param value - whatever the host half returned. +* @returns whether the value can be started via `ctx.plugin`. +*/ +function isPlugin(value) { + if (typeof value === "function") return true; + return typeof value === "object" && value !== null && typeof value.apply === "function"; +} +/** +* Wrap a plugin so `apply` receives the sandbox context while preserving injection metadata. +* @param plugin - the plugin the host half returned. +* @param reportFailure - reports a guard rejection to the owning Agent. +* @returns an equivalent plugin whose `apply` sees the sandbox context façade. +*/ +function guardedPlugin(plugin, reportFailure) { + if (typeof plugin === "function") { + const functionPlugin = plugin; + return { + name: pluginName(plugin), + apply(ctx, config) { + return functionPlugin(sandboxContext(ctx, reportFailure), config); + } + }; + } + const objectPlugin = plugin; + return { + ...plugin, + apply(ctx, config) { + return objectPlugin.apply(sandboxContext(ctx, reportFailure), config); + } + }; +} +function rejectGuard(reportFailure, message) { + const error = new Error(message); + reportFailure(error); + throw error; +} +/** +* Display name for a running plugin: its `name` property, else anonymous. +* @param plugin - the plugin the host half returned. +* @returns the human-readable name used in run results and inspect output. +*/ +function pluginName(plugin) { + const named = plugin.name; + if (typeof named === "string" && named.length > 0) return named; + return ""; +} +//#endregion +//#region lib/types/inspect-registry.js +/** Host registry for model-visible, read-only Cordis capability queries. */ +/** Registry and cross-page router behind the two model-facing inspect tools. */ +var CordisInspectRegistryService = class extends Service { + providers = /* @__PURE__ */ new Map(); + pending = /* @__PURE__ */ new Map(); + clientManifest; + nextRequest = 1; + /** Register the process-global Host registry. */ + constructor(ctx) { + super(ctx, "cordisInspect"); + } + /** + * Register one Host provider. + * @param registration - manifest and local query handler. + * @returns idempotent disposer. + */ + register(registration) { + const manifest = validateManifest(registration.manifest); + if (this.providers.has(manifest.id)) throw new Error(`Host Cordis inspect provider "${manifest.id}" is already registered`); + const stored = { + ...registration, + manifest + }; + this.providers.set(manifest.id, stored); + return () => { + if (this.providers.get(manifest.id) === stored) this.providers.delete(manifest.id); + }; + } + /** + * Replace the mirrored Client provider directory. + * @param providers - complete Client manifest snapshot. + */ + syncClientManifest(providers) { + const ids = /* @__PURE__ */ new Set(); + const validated = providers.map((provider) => { + const manifest = validateManifest(provider); + if (ids.has(manifest.id)) throw new Error(`Client Cordis inspect manifest repeats provider "${manifest.id}"`); + ids.add(manifest.id); + return manifest; + }); + this.clientManifest = Object.freeze(validated); + } + /** + * Return the complete known Host and Client provider directory. + * @returns Host providers followed by the Client providers. + */ + list() { + return [...[...this.providers.values()].map((provider) => view("host", provider.manifest)), ...(this.clientManifest ?? []).map((provider) => view("client", provider))]; + } + /** + * Execute one provider query on its owning platform. + * @param platform - Host or Client runtime. + * @param providerId - provider selected from {@link list}. + * @param methodName - declared method name. + * @param input - optional lossless JSON input. + * @param agent - requesting Agent and scope. + * @param signal - tool-call cancellation. + * @returns provider JSON data. + */ + async query(platform, providerId, methodName, input, agent, signal) { + if (platform === "host") { + const registration = this.providers.get(providerId); + if (registration === void 0) throw new Error(`Host Cordis inspect provider "${providerId}" is not registered`); + const method = findMethod(registration.manifest, methodName); + validateInput("Host", providerId, method, input); + signal.throwIfAborted(); + const data = await registration.query(methodName, input, { + agent, + signal + }); + signal.throwIfAborted(); + return validateOutput("Host", providerId, method, data); + } + return await this.queryClient(providerId, methodName, input, agent, signal); + } + /** + * Accept the first valid Client response for a pending query. + * @param agent - Agent whose Session owns the query. + * @param requestId - Pending Client query identity. + * @param resolution - Client provider result or failure. + * @returns whether this response settled the still-pending query. + */ + resolveClientQuery(agent, requestId, resolution) { + const pending = this.pending.get(requestId); + if (pending === void 0 || pending.request.agentId !== agent.id) return { accepted: false }; + if (!resolution.ok) return { accepted: false }; + try { + resolution = { + ok: true, + data: validateOutput("Client", pending.request.provider, pending.method, resolution.data) + }; + } catch { + return { accepted: false }; + } + this.pending.delete(requestId); + pending.settle(resolution); + this.ctx.emit("cordis/inspect-query-resolved", { requestId }); + return { accepted: true }; + } + async queryClient(providerId, methodName, input, agent, signal) { + const provider = this.clientManifest?.find((candidate) => candidate.id === providerId); + if (provider === void 0) throw new Error(`Client Cordis inspect provider "${providerId}" is not registered`); + const method = findMethod(provider, methodName); + validateInput("Client", providerId, method, input); + signal.throwIfAborted(); + const requestId = `inspect-${this.nextRequest++}`; + const request = { + requestId, + agentId: agent.id, + provider: providerId, + method: methodName, + ...input === void 0 ? {} : { input } + }; + const result = new Promise((resolve) => { + this.pending.set(requestId, { + request, + method, + settle: resolve + }); + }); + const onAbort = () => { + const pending = this.pending.get(requestId); + if (pending === void 0) return; + this.pending.delete(requestId); + pending.settle({ + ok: false, + reason: "cancelled", + message: `Client inspect query ${providerId}.${methodName} was cancelled` + }); + this.ctx.emit("cordis/inspect-query-resolved", { requestId }); + }; + signal.addEventListener("abort", onAbort, { once: true }); + if (signal.aborted) onAbort(); + else this.ctx.emit("cordis/inspect-query", request); + try { + const resolution = await result; + if (!resolution.ok) throw new Error(`${providerId}.${methodName}: ${resolution.message}`); + return resolution.data; + } finally { + signal.removeEventListener("abort", onAbort); + } + } +}; +function view(platform, manifest) { + return { + platform, + ...manifest, + methods: [...manifest.methods] + }; +} +function validateManifest(manifest) { + if (manifest.id.trim() === "") throw new Error("Cordis inspect provider id must not be empty"); + if (manifest.description.trim() === "") throw new Error(`Cordis inspect provider "${manifest.id}" needs a description`); + const names = /* @__PURE__ */ new Set(); + const methods = manifest.methods.map((method) => { + if (method.name.trim() === "") throw new Error(`Cordis inspect provider "${manifest.id}" has an empty method name`); + if (names.has(method.name)) throw new Error(`Cordis inspect provider "${manifest.id}" repeats method "${method.name}"`); + if (method.description.trim() === "") throw new Error(`Cordis inspect method ${manifest.id}.${method.name} needs a description`); + assertSupportedJsonSchema(method.inputSchema); + assertSupportedJsonSchema(method.outputSchema); + names.add(method.name); + return Object.freeze({ ...method }); + }); + return Object.freeze({ + ...manifest, + methods: Object.freeze(methods) + }); +} +function findMethod(manifest, name) { + const method = manifest.methods.find((candidate) => candidate.name === name); + if (method === void 0) throw new Error(`Cordis inspect provider "${manifest.id}" has no method "${name}"`); + return method; +} +function validateInput(platform, provider, method, input) { + const violations = validateJsonSchemaValue(method.inputSchema, input ?? {}, "input"); + if (violations.length > 0) throw new Error(`${platform} Cordis inspect ${provider}.${method.name} rejected input: ${violations.join("; ")}`); +} +function validateOutput(platform, provider, method, data) { + const snapshot = snapshotJsonValue(data); + if (snapshot === void 0) throw new Error(`${platform} Cordis inspect ${provider}.${method.name} returned a non-JSON value`); + const violations = validateJsonSchemaValue(method.outputSchema, snapshot, "output"); + if (violations.length > 0) throw new Error(`${platform} Cordis inspect ${provider}.${method.name} returned invalid output: ${violations.join("; ")}`); + return snapshot; +} +//#endregion +//#region lib/types/lifecycle.js +/** +* Host-half fiber lifecycle over the `cordis-dynamic` group: settle a +* sandbox-produced plugin as a child fiber (never leaving a failed fiber +* mounted), and report the services a settled-but-pending fiber still waits +* for. Stopping needs no helper — a host half unwinds through an ordinary +* awaited `fiber.dispose()`, because everything the plugin registered is an +* effect on its fiber. +* @module @deepseek-ai/dsh-cordis-host-runner/lifecycle +*/ +/** +* Await the group, start and settle one guarded child, and dispose it before rethrowing any +* startup failure so a failed run never lingers. A valid unresolved inject may remain pending. +* @param group - the `cordis-dynamic` group fiber every host half hangs under. +* @param plugin - the plugin the sandbox returned; wrapped with the registration guard before starting. +* @param reportGuardFailure - reports post-activation Host guard rejections to the owning Agent. +* @returns the settled child fiber (possibly pending on unsatisfied `inject`). +*/ +async function startHostHalf(group, plugin, reportGuardFailure) { + await group.await(); + const fiber = group.ctx.plugin(guardedPlugin(plugin, reportGuardFailure)); + try { + await fiber.await(); + } catch (error) { + await fiber.dispose(); + const message = error instanceof Error ? error.message : String(error); + if (message.includes("already registered")) throw new Error(`${message} — to REPLACE something an earlier dynamic package registered, first cordis_stop that package's id (find it with cordis_runtime_inspect what:"temporary"), then run the new version.`); + throw error instanceof Error ? error : new Error(message); + } + return fiber; +} +/** +* The services a fiber declared in `inject` that do not exist yet — a settled +* fiber that is not active is waiting on exactly these (legal cordis +* semantics: it activates when the service appears). +* @param ctx - the context to resolve service existence against. +* @param fiber - the host-half fiber whose `inject` declarations are checked. +* @returns the missing service names, in declaration order. +*/ +function missingServices(ctx, fiber) { + return Object.keys(fiber.inject).filter((service) => ctx.get(service) === void 0); +} +//#endregion +//#region lib/types/registry.js +/** +* Process-local dynamic Plugin registry and its opaque identity mints. +* @module @deepseek-ai/dsh-cordis-host-runner/registry +*/ +/** Registry, identity mints, and pending approval index. */ +var DynamicCordisRegistry = class { + plugins = /* @__PURE__ */ new Map(); + pendingRequests = /* @__PURE__ */ new Map(); + nextPlugin = 1; + nextPackage = 1; + nextRun = 1; + nextApproval = 1; + /** + * Mint a semantic plugin ID without reusing a prior suffix. + * @param prefix - validated lowercase semantic prefix proposed by the model. + * @returns a process-unique Plugin ID. + */ + mintPluginId(prefix) { + let id; + do + id = `${prefix}-${this.nextPlugin++}`; + while (this.plugins.has(id)); + return id; + } + /** + * Mint an immutable package ID. + * @returns a process-unique Package ID. + */ + mintPackageId() { + return `pkg-${this.nextPackage++}`; + } + /** + * Mint an activation ID. + * @returns a process-unique Plugin Run ID. + */ + mintPluginRunId() { + return `run-${this.nextRun++}`; + } + /** + * Mint an approval ID. + * @returns a process-unique approval request ID. + */ + mintApprovalRequestId() { + return `approval-${this.nextApproval++}`; + } + /** + * Add one stable plugin. + * @param plugin - Plugin record to retain under its stable ID. + */ + add(plugin) { + this.plugins.set(plugin.pluginId, plugin); + } + /** + * Read one plugin. + * @param id - stable Plugin ID. + * @returns the Plugin record, or `undefined` when absent. + */ + get(id) { + return this.plugins.get(id); + } + /** + * Delete one plugin and all package versions. + * @param id - stable Plugin ID to remove. + * @returns whether a Plugin record was removed. + */ + delete(id) { + return this.plugins.delete(id); + } + /** + * Read all plugins in creation order. + * @returns a snapshot of every Plugin record. + */ + all() { + return [...this.plugins.values()]; + } + /** + * Read one session's plugins in creation order. + * @param sessionId - owning session to filter by. + * @returns a snapshot of matching Plugin records. + */ + ofSession(sessionId) { + return this.all().filter((plugin) => plugin.sessionId === sessionId); + } + /** + * Publish one pending approval. + * @param id - approval request ID. + * @param pending - resolver and Plugin metadata retained until settlement. + */ + armRequest(id, pending) { + this.pendingRequests.set(id, pending); + } + /** + * Read one pending approval without claiming it. + * @param id - approval request ID. + * @returns the pending request, or `undefined` when absent. + */ + peekRequest(id) { + return this.pendingRequests.get(id); + } + /** + * Claim one pending approval; first answer wins. + * @param id - approval request ID. + * @returns the claimed request, or `undefined` when already settled. + */ + claimRequest(id) { + const pending = this.pendingRequests.get(id); + if (pending !== void 0) this.pendingRequests.delete(id); + return pending; + } + /** + * Cancel one pending approval. + * @param id - approval request ID to remove. + */ + disarmRequest(id) { + this.pendingRequests.delete(id); + } + /** + * Find a pending approval for one Plugin. + * @param pluginId - stable Plugin ID. + * @returns its approval request ID, or `undefined` when none is pending. + */ + pendingRequestFor(pluginId) { + for (const [requestId, request] of this.pendingRequests) if (request.pluginId === pluginId) return requestId; + } +}; +//#endregion +//#region lib/types/sandbox.js +/** +* The `node:vm` sandbox a dynamic package's HOST half evaluates in: a fresh realm whose globals +* are a tagged write-through console, the `harness` registration helpers, the encoding primitives +* a bare vm context lacks, and callable traps over the Node APIs the sandbox deliberately +* withholds. Traps steer filesystem, network, process, and timer work to `ctx.fs`, `ctx.web`, +* `ctx.bash`, and Cordis timers. This keeps cooperative packages inspectable and disposable but +* is not containment: host-realm helper functions remain an escape route. +* +* The browser half never reaches this module — it is evaluated by the client-side runner in a +* closure, with its own facade. +* @module @deepseek-ai/dsh-cordis-host-runner/sandbox +*/ +/** Exact Host closure symbols exposed by the sandbox and guarded Context. */ +const HOST_BUILTIN_INSPECTION = [ + { + name: "ctx", + description: "Restricted Cordis Context. Prefer ctx.get(name) with an undefined check; use inject for hard dependencies.", + signatures: [ + "ctx.get(name: string): unknown | undefined", + "ctx.on(name: string, listener: Function): () => void", + "ctx.provide(name: string, value: unknown): () => void", + "ctx.effect(callback: Function, label?: string): () => void" + ] + }, + { + name: "harness", + description: "Host helpers for Package-private Client RPC and model-visible dynamic Tools.", + signatures: [ + "harness.handle(method: string, handler: (args: JsonValue) => JsonValue | Promise): () => void", + "harness.defineTool(definition: ToolDefinition): ToolDefinition", + "harness.registerTool(ctx: Context, tool: ToolDefinition): () => void" + ] + }, + { + name: "console", + description: "Package-tagged Host logging.", + signatures: ["console.log(...values): void", "console.error(...values): void"] + }, + { + name: "btoa", + description: "Encode UTF-8 text as base64.", + signatures: ["btoa(value: string): string"] + }, + { + name: "atob", + description: "Decode base64 as UTF-8 text.", + signatures: ["atob(value: string): string"] + }, + { + name: "TextEncoder", + description: "Standard UTF-8 encoder constructor.", + signatures: ["new TextEncoder()"] + }, + { + name: "TextDecoder", + description: "Standard text decoder constructor.", + signatures: ["new TextDecoder(label?: string)"] + } +]; +/** +* A write-through console for one package, tagging every line with the package +* id. Write-through (host stdout/stderr), NOT buffered into the tool result: +* a registered listener fires long after the run call returned, and its output +* must land somewhere the user can see — for a terminal entry point, the host terminal. +*/ +function taggedConsole(id) { + const tag = `[cordis:${id}]`; + const log = (...args) => { + console.log(tag, ...args); + }; + const error = (...args) => { + console.error(tag, ...args); + }; + return { + log, + info: log, + warn: log, + debug: log, + error + }; +} +/** +* Patch only VM constructors so `instanceof` accepts both VM values and host values passed as +* arguments, events, or service results; host intrinsics remain untouched. +*/ +const DUAL_REALM_INSTANCEOF_PRELUDE = ` +(hostIntrinsics) => { + 'use strict' + const ordinary = Function.prototype[Symbol.hasInstance] + for (const name of Object.keys(hostIntrinsics)) { + const VmCtor = globalThis[name] + const HostCtor = hostIntrinsics[name] + if (typeof VmCtor !== 'function' || typeof HostCtor !== 'function') continue + Object.defineProperty(VmCtor, Symbol.hasInstance, { + value: (instance) => ordinary.call(VmCtor, instance) || ordinary.call(HostCtor, instance), + configurable: true, + }) + } +} +`; +/** Run {@link DUAL_REALM_INSTANCEOF_PRELUDE} in a freshly created sandbox, handing it the host intrinsics to pair up. */ +function patchDualRealmInstanceof(sandbox) { + runInContext(DUAL_REALM_INSTANCEOF_PRELUDE, sandbox)({ + Object, + Array, + Function, + Error, + TypeError, + RangeError, + SyntaxError, + Promise, + RegExp, + Date, + Map, + Set + }); +} +const TIMER_REDIRECT = "Node timers are unavailable. Use the cordis timer service instead: declare inject: ['timer'] on your plugin and call ctx.timeout / ctx.interval after querying Host Service.listService for the exact overloads. Those calls are fiber effects, cleaned up automatically when stopped."; +/** +* The callable Node APIs the sandbox deliberately disables, each mapped to the +* cordis alternative its trap error names. Only function-valued globals are +* trapped; a data-valued global such as `process` stays `undefined`, because a +* throwing accessor would detonate the common `typeof process` feature probe +* at resolution time. +*/ +const NODE_API_REDIRECTS = { + require: "Node modules are unavailable. Use the cordis services on ctx instead — e.g. inject: ['fs'] for files, ['web'] for HTTP, ['bash'] for processes; query Service.listService with cordis_inspect_query first.", + setTimeout: TIMER_REDIRECT, + setInterval: TIMER_REDIRECT, + setImmediate: TIMER_REDIRECT, + clearTimeout: TIMER_REDIRECT, + clearInterval: TIMER_REDIRECT, + fetch: "Network access goes through the cordis web service: declare inject: ['web'] and call ctx.web (query Host Service.listService with cordis_inspect_query for its methods)." +}; +/** Build the trap functions for {@link NODE_API_REDIRECTS}: calling one throws the redirect. */ +function nodeApiTraps() { + const traps = {}; + for (const [name, redirect] of Object.entries(NODE_API_REDIRECTS)) traps[name] = () => { + throw new Error(`${name} is not available in the dynamic package sandbox — ${redirect}`); + }; + return traps; +} +/** +* Build the vm context one host half evaluates in: the tagged console, the +* `harness` registration helpers, the encoding primitives, the Node-API traps, +* and the dual-realm `instanceof` patch, already `createContext`-ed. +* @param id - the package id (`dyn-`), used as the console tag and filename stem. +* @param harnessExtras - per-package `harness` verbs beyond the registration pair (`handle`). +* @returns the contextified sandbox object to pass to {@link evaluateHostCode}. +*/ +function createSandbox(id, harnessExtras = {}) { + const sandbox = { + ...nodeApiTraps(), + console: taggedConsole(id), + harness: { + defineTool: sandboxDefineTool, + registerTool: sandboxRegisterTool, + ...harnessExtras + }, + btoa: (s) => Buffer.from(s, "utf-8").toString("base64"), + atob: (s) => Buffer.from(s, "base64").toString("utf-8"), + TextEncoder, + TextDecoder + }; + createContext(sandbox); + patchDualRealmInstanceof(sandbox); + return sandbox; +} +/** +* Cross-realm SyntaxError detection: a compile failure inside `runInContext` +* constructs its error in the SANDBOX realm, so a host `instanceof +* SyntaxError` is silently false — the `name` property is the realm-safe tag. +*/ +function isSyntaxError(error) { + return typeof error === "object" && error !== null && error.name === "SyntaxError"; +} +/** +* The parse-failure context a vm `SyntaxError` carries: the vm prints the +* offending source line and a caret before the message, which is exactly what +* a model needs to self-correct — surface it instead of the bare message. +* Falls back to `String(error)` when the stack carries no such prelude. +* @param error - the `SyntaxError` (host- or sandbox-realm) thrown while compiling package code. +* @returns the stack prefix up to and including the `SyntaxError: …` line. +*/ +function syntaxErrorContext(error) { + const lines = (error.stack ?? "").split("\n"); + const messageIndex = lines.findIndex((line) => line.startsWith("SyntaxError")); + if (messageIndex === -1) return String(error); + return lines.slice(0, messageIndex + 1).join("\n"); +} +/** +* The teaching text one parse failure produces, shared by the define-time +* precheck and the run-time evaluation so a model reads the same diagnosis +* whichever verb caught it. +* @param half - which half failed to parse, named as the define argument that carried it. +* @param context - the {@link syntaxErrorContext} of the failure. +* @returns the model-facing error message. +*/ +function parseErrorMessage(half, context) { + const offendingLine = context.split("\n")[1] ?? ""; + if (/\bas\b/.test(offendingLine)) return `dynamic package \`${half}\` failed to parse:\n${context}\nThe sandbox runs plain JavaScript, not TypeScript. Remove type annotations: + ✗ { type: 'text' as const, text: x } + ✓ { type: 'text', text: x }`; + return `dynamic package \`${half}\` failed to parse:\n${context}\nNote: it runs as the BODY of an async function (line numbers are offset by the 1-line wrapper). Check bracket balance — ending the returned plugin object with \`});\` closes a call that was never opened; a plain \`return { … }\` ends with \`}\` (an optional \`;\`), never \`)\`.`; +} +/** +* Parse one half's source without running it: the define-time precheck that +* keeps unparseable code out of the registry, so a model fixes it and defines +* again instead of discovering the failure at run time. Compiling through `vm` +* rather than `new Function` is what makes the two agree — same wrapper, same +* compiler, and the same source-line-and-caret prelude in the failure. +* @param code - the model-written function body. +* @param half - which define argument carried it, for the error text. +* @throws when the body does not parse, with the offending line and a teaching hint. +*/ +function precheckCode(code, half) { + try { + new Script(`(async () => {\n${code}\n})()`, { filename: `cordis-dyn-${half}.js` }); + } catch (error) { + if (!isSyntaxError(error)) throw error; + throw new Error(parseErrorMessage(half, syntaxErrorContext(error))); + } +} +/** +* Evaluate a host half as the body of an async function inside the sandbox. `vmTimeoutMs` only +* bounds the SYNCHRONOUS portion; an async body escapes it — acceptable under the module's +* trust stance. Parse errors include the offending line and a TypeScript-removal or bracket- +* balance hint. +* @param sandbox - the contextified object from {@link createSandbox}. +* @param code - the model-written function body; must `return` a plugin. +* @param id - the package id, used as the vm filename (`cordis-dyn-.js`). +* @param vmTimeoutMs - the synchronous evaluation bound in milliseconds. +* @returns whatever the code returned, still un-narrowed (the run lifecycle checks plugin shape). +*/ +async function evaluateHostCode(sandbox, code, id, vmTimeoutMs) { + try { + return await runInContext(`(async () => {\n${code}\n})()`, sandbox, { + filename: `cordis-dyn-${id}.js`, + timeout: vmTimeoutMs + }); + } catch (error) { + if (!isSyntaxError(error)) throw error; + throw new Error(parseErrorMessage("code.host", syntaxErrorContext(error))); + } +} +//#endregion +//#region lib/types/index.js +/** +* Dynamic Cordis Plugin service: immutable package definitions, one active run +* per Plugin, human-approved Client activation, and Host/Client invocation. +* @module @deepseek-ai/dsh-cordis-host-runner +*/ +var __runInitializers = function(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + return useValue ? value : void 0; +}; +var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function(f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +/** +* Brand a Host-minted Plugin ID. +* @param id - opaque identifier minted by the Host registry. +* @returns the branded Plugin identifier. +*/ +function CordisDynamicPluginId(id) { + return id; +} +/** +* Brand a Host-minted Package ID. +* @param id - opaque identifier minted by the Host registry. +* @returns the branded Package identifier. +*/ +function CordisDynamicPackageId(id) { + return id; +} +/** +* Brand a Host-minted Plugin Run ID. +* @param id - opaque identifier minted by the Host registry. +* @returns the branded Plugin Run identifier. +*/ +function CordisDynamicPluginRunId(id) { + return id; +} +/** +* Brand a Host-minted approval request ID. +* @param id - opaque identifier minted by the Host registry. +* @returns the branded approval request identifier. +*/ +function ApprovalRequestId(id) { + return id; +} +/** Dynamic Plugin registry and Host-half lifecycle. */ +let DynamicCordisRunnerService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _undefineFromPanel_decorators; + let _runHostHalf_decorators; + let _getClientCode_decorators; + let _resolveRequestRun_decorators; + let _settleUserRun_decorators; + let _stopFromPanel_decorators; + let _syncInspectManifest_decorators; + let _resolveInspectQuery_decorators; + let _inventory_decorators; + let _reportRenderFailure_decorators; + let _reportClientGuardFailure_decorators; + let _invoke_decorators; + return class DynamicCordisRunnerService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _undefineFromPanel_decorators = [Remote("undefineFromPanel")]; + _runHostHalf_decorators = [Remote("runHostHalf")]; + _getClientCode_decorators = [Remote("getClientCode")]; + _resolveRequestRun_decorators = [Remote("resolveRequestRun")]; + _settleUserRun_decorators = [Remote("settleUserRun")]; + _stopFromPanel_decorators = [Remote("stopFromPanel")]; + _syncInspectManifest_decorators = [Remote("syncInspectManifest")]; + _resolveInspectQuery_decorators = [Remote("resolveInspectQuery")]; + _inventory_decorators = [Remote("inventory")]; + _reportRenderFailure_decorators = [Remote("reportRenderFailure")]; + _reportClientGuardFailure_decorators = [Remote("reportClientGuardFailure")]; + _invoke_decorators = [Remote("invoke")]; + __esDecorate(this, null, _undefineFromPanel_decorators, { + kind: "method", + name: "undefineFromPanel", + static: false, + private: false, + access: { + has: (obj) => "undefineFromPanel" in obj, + get: (obj) => obj.undefineFromPanel + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _runHostHalf_decorators, { + kind: "method", + name: "runHostHalf", + static: false, + private: false, + access: { + has: (obj) => "runHostHalf" in obj, + get: (obj) => obj.runHostHalf + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _getClientCode_decorators, { + kind: "method", + name: "getClientCode", + static: false, + private: false, + access: { + has: (obj) => "getClientCode" in obj, + get: (obj) => obj.getClientCode + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resolveRequestRun_decorators, { + kind: "method", + name: "resolveRequestRun", + static: false, + private: false, + access: { + has: (obj) => "resolveRequestRun" in obj, + get: (obj) => obj.resolveRequestRun + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _settleUserRun_decorators, { + kind: "method", + name: "settleUserRun", + static: false, + private: false, + access: { + has: (obj) => "settleUserRun" in obj, + get: (obj) => obj.settleUserRun + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _stopFromPanel_decorators, { + kind: "method", + name: "stopFromPanel", + static: false, + private: false, + access: { + has: (obj) => "stopFromPanel" in obj, + get: (obj) => obj.stopFromPanel + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _syncInspectManifest_decorators, { + kind: "method", + name: "syncInspectManifest", + static: false, + private: false, + access: { + has: (obj) => "syncInspectManifest" in obj, + get: (obj) => obj.syncInspectManifest + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resolveInspectQuery_decorators, { + kind: "method", + name: "resolveInspectQuery", + static: false, + private: false, + access: { + has: (obj) => "resolveInspectQuery" in obj, + get: (obj) => obj.resolveInspectQuery + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _inventory_decorators, { + kind: "method", + name: "inventory", + static: false, + private: false, + access: { + has: (obj) => "inventory" in obj, + get: (obj) => obj.inventory + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _reportRenderFailure_decorators, { + kind: "method", + name: "reportRenderFailure", + static: false, + private: false, + access: { + has: (obj) => "reportRenderFailure" in obj, + get: (obj) => obj.reportRenderFailure + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _reportClientGuardFailure_decorators, { + kind: "method", + name: "reportClientGuardFailure", + static: false, + private: false, + access: { + has: (obj) => "reportClientGuardFailure" in obj, + get: (obj) => obj.reportClientGuardFailure + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _invoke_decorators, { + kind: "method", + name: "invoke", + static: false, + private: false, + access: { + has: (obj) => "invoke" in obj, + get: (obj) => obj.invoke + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { + enumerable: true, + configurable: true, + writable: true, + value: _metadata + }); + } + static inject = ["tools"]; + static Config = z.object({ vmTimeoutMs: z.number().min(1).default(5e3) }); + rootCtx = __runInitializers(this, _instanceExtraInitializers); + registry = new DynamicCordisRegistry(); + inspectRegistry; + starting = /* @__PURE__ */ new Map(); + resolved; + group; + /** Create the service under the Host composition. */ + constructor(ctx, config) { + super(ctx, "dynamicCordisRunner"); + this.rootCtx = ctx; + this.resolved = config; + this.inspectRegistry = new CordisInspectRegistryService(ctx); + } + /** + * Define a new Plugin's first Package or append a Package to an existing Plugin. + * @param request - Session ownership, Plugin selection, metadata, and source code. + * @returns Host-minted Plugin and Package identities with declared-half metadata. + */ + define(request) { + const name = request.name.trim(); + const purpose = request.purpose.trim(); + if (name.length === 0) throw new Error("cordis_define needs a non-empty `name`"); + if (purpose.length === 0) throw new Error("cordis_define needs a non-empty `purpose`"); + if (request.code.host === void 0 && request.code.client === void 0) throw new Error("cordis_define needs `code.host`, `code.client`, or both"); + if (request.code.host !== void 0) precheckCode(request.code.host, "code.host"); + if (request.code.client !== void 0) precheckCode(request.code.client, "code.client"); + let plugin; + if (request.plugin.kind === "new") { + const prefix = request.plugin.idPrefix.trim(); + if (!/^[a-z]{3,6}$/.test(prefix)) throw new Error("cordis_define `plugin.idPrefix` must contain 3–6 lowercase English letters"); + plugin = { + pluginId: CordisDynamicPluginId(this.registry.mintPluginId(prefix)), + sessionId: request.sessionId, + packages: /* @__PURE__ */ new Map(), + approvedClientPackages: /* @__PURE__ */ new Set(), + clientVersionUpdatesApproved: false + }; + this.registry.add(plugin); + } else { + const found = this.registry.get(request.plugin.pluginId); + if (found === void 0 || found.sessionId !== request.sessionId) throw new Error(missingPluginMessage(request.plugin.pluginId)); + plugin = found; + } + const packageId = CordisDynamicPackageId(this.registry.mintPackageId()); + const definition = { + packageId, + name, + purpose, + ...request.code.host === void 0 ? {} : { hostCode: request.code.host }, + ...request.code.client === void 0 ? {} : { clientCode: request.code.client } + }; + plugin.packages.set(packageId, definition); + return { + pluginId: plugin.pluginId, + packageId, + name, + purpose, + hasHostHalf: definition.hostCode !== void 0, + hasClientHalf: definition.clientCode !== void 0 + }; + } + /** + * Remove a Plugin, its active run, and all immutable Packages. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + async undefine(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) return { + ok: false, + reason: "plugin-missing", + message: missingPluginMessage(pluginId) + }; + const wasRunning = plugin.run !== void 0; + this.cancelPending(pluginId, `dynamic plugin "${pluginId}" was removed before approval`); + if (plugin.run !== void 0) await this.retract(plugin); + this.registry.delete(pluginId); + return { + ok: true, + wasRunning + }; + } + /** + * Remove a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + async undefineFromPanel(agent, pluginId) { + const result = await this.undefine(agent, pluginId); + if (result.ok) this.injectUserContext(agent, `The user removed Cordis Plugin ${pluginId} and all of its Packages. The Plugin no longer exists.`); + return result; + } + /** + * Start or update one Package for a model tool call. An unauthorized Client + * Package waits for approval; Plugin-wide authorization covers later versions. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param signal - Tool-call cancellation signal while the activation request is being created. + * @returns The successful activation identity or an actionable refusal. + */ + async run(agent, pluginId, packageId, mode, signal) { + const plan = this.resolvePlan(agent, pluginId, packageId, mode); + if (!plan.ok) return plan.response; + if (signal?.aborted === true) return { + ok: false, + reason: "cancelled", + message: `the run request for dynamic plugin "${pluginId}" was cancelled before activation` + }; + if (this.registry.pendingRequestFor(pluginId) !== void 0) return { + ok: false, + reason: "transition-in-flight", + message: `dynamic plugin "${pluginId}" already has a pending run request` + }; + const attempt = this.createAttempt(plan); + plan.plugin.nextPackageId = packageId; + plan.plugin.latestRun = attempt; + if (plan.definition.clientCode === void 0) { + const started = await this.activate(plan, void 0, false, attempt); + if (started.ok) return this.runResponse(plan.plugin, started); + this.failAttempt(plan.plugin, attempt, "host-load", started); + return { + ...started, + reason: "host-half-failed" + }; + } + const requestId = ApprovalRequestId(this.registry.mintApprovalRequestId()); + const requiresApproval = !plan.plugin.clientVersionUpdatesApproved && !plan.plugin.approvedClientPackages.has(packageId); + attempt.approvalRequestId = requestId; + attempt.requiresApproval = requiresApproval; + attempt.status = requiresApproval ? "awaiting-approval" : "starting-host"; + this.registry.armRequest(requestId, { + agentId: agent.id, + pluginId, + packageId, + pluginRunId: attempt.pluginRunId, + mode, + requiresApproval + }); + this.ctx.emit("cordis/request-run", { + requestId, + agentId: agent.id, + pluginId, + packageId, + mode, + name: plan.definition.name, + purpose: plan.definition.purpose, + requiresApproval + }); + return { + ok: true, + status: requiresApproval ? "awaiting-approval" : "starting", + pluginId, + packageId, + pluginRunId: attempt.pluginRunId, + mode, + waitingFor: [], + ...plan.plugin.currentPackageId === void 0 ? {} : { currentPackageId: plan.plugin.currentPackageId }, + nextPackageId: packageId + }; + } + /** + * Start Host code for an approved request or a direct panel gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param requestId - Model-driven request identity, or null for a direct user gesture. + * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin. + * @returns The exact Host activation or a failure message. + */ + async runHostHalf(agent, pluginId, packageId, mode, requestId, approveFutureVersions) { + const plan = this.resolvePlan(agent, pluginId, packageId, mode, requestId === null); + if (!plan.ok) return { + ok: false, + message: plan.response.message + }; + let attempt; + if (requestId !== null) { + const pending = this.registry.peekRequest(requestId); + if (pending === void 0 || pending.pluginId !== pluginId || pending.packageId !== packageId || pending.mode !== mode) return { + ok: false, + message: `run request "${requestId}" does not authorize ${pluginId}/${packageId}` + }; + const latest = plan.plugin.latestRun; + const expectedStatus = pending.requiresApproval ? "awaiting-approval" : "starting-host"; + if (latest === void 0 || latest.pluginRunId !== pending.pluginRunId || latest.status !== expectedStatus && !pending.requiresApproval && latest.status !== "client-pending") return { + ok: false, + message: `run request "${requestId}" no longer identifies the latest run of ${pluginId}` + }; + attempt = latest; + if (pending.requiresApproval) { + plan.plugin.approvedClientPackages.add(packageId); + if (approveFutureVersions) plan.plugin.clientVersionUpdatesApproved = true; + } + } else { + const pending = this.registry.pendingRequestFor(pluginId); + if (pending !== void 0) return { + ok: false, + message: `dynamic plugin "${pluginId}" has pending run request ${pending}` + }; + const attached = plan.plugin.run?.packageId === packageId && plan.plugin.latestRun?.pluginRunId === plan.plugin.run.pluginRunId ? plan.plugin.latestRun : void 0; + attempt = attached ?? this.createAttempt(plan); + if (attached === void 0) { + plan.plugin.nextPackageId = packageId; + plan.plugin.latestRun = attempt; + } + if (plan.definition.clientCode !== void 0) plan.plugin.approvedClientPackages.add(packageId); + } + const attaching = attempt.pluginRunId === plan.plugin.run?.pluginRunId; + if (!attaching) { + attempt.status = "starting-host"; + if (attempt.host.status !== "absent") attempt.host = { + status: "pending", + waitingFor: [] + }; + } + const started = await this.activate(plan, requestId ?? void 0, attaching, attempt); + if (!started.ok) this.failAttempt(plan.plugin, attempt, "host-load", started); + return started; + } + /** + * Fetch Client code for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to read. + * @param pluginRunId - Exact active run authorized to receive source. + * @returns Client source and its Plugin, Package, and run identities. + */ + getClientCode(agent, pluginId, pluginRunId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) throw new Error(missingPluginMessage(pluginId)); + const run = plugin.run; + if (run === void 0 || run.pluginRunId !== pluginRunId) throw new Error(`dynamic plugin "${pluginId}" is not running activation "${pluginRunId}"`); + const definition = plugin.packages.get(run.packageId); + if (definition?.clientCode === void 0) throw new Error(`package "${run.packageId}" has no Client half`); + return { + code: definition.clientCode, + name: definition.name, + pluginId, + packageId: run.packageId, + pluginRunId + }; + } + /** + * Resolve one model-driven Client activation request. + * @param requestId - Request identity to settle once. + * @param resolution - Browser refusal or exact Client activation result. + * @returns Whether the still-pending request accepted this resolution. + */ + async resolveRequestRun(requestId, resolution) { + const pending = this.registry.peekRequest(requestId); + if (pending === void 0) return { accepted: false }; + const plugin = this.registry.get(pending.pluginId); + if (resolution.ok && plugin?.run?.pluginRunId !== resolution.pluginRunId) return { accepted: false }; + if (!resolution.ok && resolution.pluginRunId !== void 0 && plugin?.run?.pluginRunId !== resolution.pluginRunId) return { accepted: false }; + this.registry.claimRequest(requestId); + const settled = await this.settleActivation(plugin, resolution, requestId); + this.announceResolved(requestId, resolution, pending.requiresApproval ? void 0 : "completed"); + this.steerRunOutcome(pending, settled); + return { accepted: true }; + } + /** + * Settle a direct panel run after this page loaded or failed its Client half. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity being settled. + * @param resolution - Exact Client activation result from the acting page. + * @returns The committed activation or its failure. + */ + async settleUserRun(agent, pluginId, resolution) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) return { + ok: false, + reason: "plugin-missing", + message: missingPluginMessage(pluginId) + }; + const settled = await this.settleActivation(plugin, resolution); + this.injectUserRunOutcome(agent, pluginId, settled); + return settled; + } + /** + * Stop the active run while retaining every Package version. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + async stop(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) return { + ok: false, + reason: "plugin-missing", + message: missingPluginMessage(pluginId) + }; + const pending = this.registry.pendingRequestFor(pluginId); + if (plugin.run === void 0 && pending === void 0) return { + ok: false, + reason: "not-running", + message: `dynamic plugin "${pluginId}" is not running` + }; + if (pending !== void 0) this.cancelPending(pluginId, `dynamic plugin "${pluginId}" was stopped before approval`); + if (plugin.run !== void 0) await this.retract(plugin); + if (plugin.latestRun !== void 0) { + plugin.latestRun.status = "stopped"; + if (plugin.latestRun.host.status !== "absent") plugin.latestRun.host = { + status: "stopped", + waitingFor: [] + }; + if (plugin.latestRun.client.status !== "absent") plugin.latestRun.client = { + status: "stopped", + waitingFor: [] + }; + } + return { ok: true }; + } + /** + * Stop a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + async stopFromPanel(agent, pluginId) { + const result = await this.stop(agent, pluginId); + if (!result.ok) return result; + const plugin = this.owned(agent, pluginId); + this.injectUserContext(agent, `The user stopped Cordis Plugin ${pluginId}. Its Packages remain defined; currentPackageId is ${plugin?.currentPackageId ?? "none"}.`); + return result; + } + /** + * Replace the Host mirror of the Client inspect provider directory. + * @param providers - complete Client provider manifest. + * @returns null after accepting the manifest. + */ + syncInspectManifest(providers) { + this.inspectRegistry.syncClientManifest(providers); + return null; + } + /** + * Claim one pending Client inspect query with its live result. + * @param agent - Session that owns the query. + * @param requestId - exact pending query identity. + * @param resolution - provider result or structured refusal. + * @returns whether this answer won the query. + */ + resolveInspectQuery(agent, requestId, resolution) { + return this.inspectRegistry.resolveClientQuery(agent, requestId, resolution); + } + /** + * Frame-wide inventory, grouped as one row per stable Plugin. + * @returns Source-free metadata for every process-local Plugin. + */ + inventory() { + return this.registry.all().map((plugin) => ({ + pluginId: plugin.pluginId, + agentId: plugin.sessionId, + packages: [...plugin.packages.values()].map((definition) => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== void 0, + hasClientHalf: definition.clientCode !== void 0 + })), + ...plugin.currentPackageId === void 0 ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === void 0 ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === void 0 ? {} : { activeRun: { + pluginRunId: plugin.run.pluginRunId, + packageId: plugin.run.packageId + } }, + ...plugin.latestRun === void 0 ? {} : { latestRun: cloneAttempt(plugin.latestRun) } + })); + } + /** + * Read one Session's Host-rich state for inspection and result rendering. + * @param agent - Agent whose Session selects visible Plugins. + * @returns Plugin versions, active runs, Host fibers, and render failures. + */ + snapshot(agent) { + return this.registry.ofSession(agent.id).map((plugin) => ({ + pluginId: plugin.pluginId, + ...plugin.currentPackageId === void 0 ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === void 0 ? {} : { nextPackageId: plugin.nextPackageId }, + packages: [...plugin.packages.values()].map((definition) => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== void 0, + hasClientHalf: definition.clientCode !== void 0 + })), + ...plugin.run === void 0 ? {} : { activeRun: { + pluginRunId: plugin.run.pluginRunId, + packageId: plugin.run.packageId, + ...plugin.run.fiber === void 0 ? {} : { fiber: plugin.run.fiber }, + handlers: [...plugin.run.handlers.keys()], + ...plugin.run.renderFailure === void 0 ? {} : { renderFailure: plugin.run.renderFailure } + } }, + ...plugin.latestRun === void 0 ? {} : { latestRun: cloneAttempt(plugin.latestRun) } + })); + } + /** + * Read source-free context for an explicit `@pluginId` user gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity referenced by the user. + * @returns The preferred modification base, or undefined when unavailable. + */ + reference(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) return void 0; + const packageId = plugin.nextPackageId ?? plugin.currentPackageId ?? [...plugin.packages.keys()].at(-1); + if (packageId === void 0) return void 0; + const definition = plugin.packages.get(packageId); + if (definition === void 0) return void 0; + return { + pluginId, + packageId, + name: definition.name, + purpose: definition.purpose, + ...plugin.currentPackageId === void 0 ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === void 0 ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === void 0 ? {} : { activeRun: { + pluginRunId: plugin.run.pluginRunId, + packageId: plugin.run.packageId + } }, + ...plugin.latestRun === void 0 ? {} : { latestRun: cloneAttempt(plugin.latestRun) } + }; + } + /** + * List source-free Plugin summaries owned by one Session. + * @param agent - Agent whose Session selects visible Plugins. + * @returns one summary per Plugin in creation order. + */ + listPlugins(agent) { + return this.registry.ofSession(agent.id).map((plugin) => this.inspectPlugin(agent, plugin.pluginId)); + } + /** + * Inspect one Plugin without returning Package source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - stable Plugin identity. + * @returns version pointers, latest run, and all Package summaries. + */ + inspectPlugin(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) throw new Error(missingPluginMessage(pluginId)); + const reference = this.reference(agent, pluginId); + if (reference === void 0) throw new Error(`dynamic plugin "${pluginId}" has no package`); + return { + ...reference, + packages: [...plugin.packages.values()].map((definition) => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== void 0, + hasClientHalf: definition.clientCode !== void 0 + })) + }; + } + /** + * Read one exact immutable Package and its Host and Client source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that owns the Package. + * @param packageId - Exact immutable Package identity to inspect. + * @returns Package metadata, source, and the Plugin's lifecycle pointers. + */ + inspectPackage(agent, pluginId, packageId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) throw new Error(missingPluginMessage(pluginId)); + const definition = plugin.packages.get(packageId); + if (definition === void 0) throw new Error(`dynamic package "${packageId}" does not exist on plugin "${pluginId}"`); + return { + pluginId, + packageId, + name: definition.name, + purpose: definition.purpose, + code: { + ...definition.hostCode === void 0 ? {} : { host: definition.hostCode }, + ...definition.clientCode === void 0 ? {} : { client: definition.clientCode } + }, + ...plugin.currentPackageId === void 0 ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === void 0 ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === void 0 ? {} : { activeRun: { + pluginRunId: plugin.run.pluginRunId, + packageId: plugin.run.packageId + } }, + ...plugin.latestRun === void 0 ? {} : { latestRun: cloneAttempt(plugin.latestRun) } + }; + } + /** + * Record a post-load render failure for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that rendered. + * @param pluginRunId - Exact active run that produced the failure. + * @param failure - Slot, message, and entry-retirement result. + * @returns Null after recording or ignoring a stale report. + */ + async reportRenderFailure(agent, pluginId, pluginRunId, failure) { + const plugin = this.owned(agent, pluginId); + if (plugin?.run?.pluginRunId === pluginRunId) { + const run = plugin.run; + const definition = plugin.packages.get(plugin.run.packageId); + const shouldSteer = run.renderFailure === void 0; + run.renderFailure = failure; + const attempt = plugin.latestRun; + if (attempt?.pluginRunId === pluginRunId) { + attempt.error = this.diagnostic(plugin, attempt, "client-render", failure); + attempt.client = { + status: "failed", + waitingFor: attempt.client.waitingFor, + error: failure.message + }; + attempt.status = "failed"; + } + if (definition !== void 0 && shouldSteer) this.steerRenderFailure(agent, plugin, definition, pluginRunId, failure); + } + return await Promise.resolve(null); + } + /** + * Report a Client guard rejection that happened after the Package completed activation. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity whose Client code was rejected. + * @param pluginRunId - Exact active run that produced the rejection. + * @param failure - Original guard message and stack. + * @returns Null after reporting or ignoring a stale/startup failure. + */ + async reportClientGuardFailure(agent, pluginId, pluginRunId, failure) { + const plugin = this.owned(agent, pluginId); + const run = plugin?.run; + if (plugin !== void 0 && run?.pluginRunId === pluginRunId) this.steerGuardFailure(plugin, run, "Client", failure); + return await Promise.resolve(null); + } + /** + * Invoke an active Host method while rejecting stale Client runs. + * @param pluginId - Stable Plugin identity that owns the method. + * @param pluginRunId - Exact active run authorizing the call. + * @param method - Registered Host handler name. + * @param args - JSON argument delivered to the handler. + * @returns The JSON result or a typed invocation failure. + */ + async invoke(pluginId, pluginRunId, method, args) { + const plugin = this.registry.get(pluginId); + if (plugin === void 0 || plugin.run === void 0) return { + ok: false, + code: "plugin-not-running", + message: `dynamic plugin "${pluginId}" is not running` + }; + const run = plugin.run; + if (run.pluginRunId !== pluginRunId) return { + ok: false, + code: "stale-run", + message: `activation "${pluginRunId}" is no longer active` + }; + const handler = run.handlers.get(method); + if (handler === void 0) return { + ok: false, + code: "method-not-found", + message: `dynamic plugin "${pluginId}" registered no Host method "${method}"` + }; + try { + return { + ok: true, + value: await handler(args) + }; + } catch (error) { + const failure = errorDetails(error); + this.steerHostHandlerFailure(plugin, run, method, failure); + return { + ok: false, + code: "handler-error", + ...failure + }; + } + } + resolvePlan(agent, pluginId, packageId, mode, allowActiveAttach = false) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) return { + ok: false, + response: { + ok: false, + reason: "plugin-missing", + message: missingPluginMessage(pluginId) + } + }; + const definition = plugin.packages.get(packageId); + if (definition === void 0) return { + ok: false, + response: { + ok: false, + reason: "package-missing", + message: `plugin "${pluginId}" has no package "${packageId}"` + } + }; + const current = plugin.currentPackageId; + if (mode === "update" && (current === void 0 || current === packageId)) return { + ok: false, + response: { + ok: false, + reason: "invalid-mode", + message: current === void 0 ? `plugin "${pluginId}" has no successful version yet; start "${packageId}" with mode "run"` : `package "${packageId}" is already current; use mode "run"` + } + }; + if (mode === "run" && current !== void 0 && current !== packageId) return { + ok: false, + response: { + ok: false, + reason: "invalid-mode", + message: `package "${packageId}" differs from current "${current}"; use mode "update"` + } + }; + if (!allowActiveAttach && this.starting.has(pluginId)) return { + ok: false, + response: { + ok: false, + reason: "transition-in-flight", + message: `plugin "${pluginId}" is already starting` + } + }; + return { + ok: true, + plugin, + definition, + mode + }; + } + activate(plan, requestId, allowActiveAttach, attempt) { + const inFlight = this.starting.get(plan.plugin.pluginId); + if (inFlight !== void 0) return inFlight; + const starting = this.startFresh(plan, requestId, allowActiveAttach, attempt); + this.starting.set(plan.plugin.pluginId, starting); + return starting.finally(() => { + this.starting.delete(plan.plugin.pluginId); + }); + } + async startFresh(plan, requestId, allowActiveAttach, attempt) { + const { plugin, definition, mode } = plan; + if (allowActiveAttach && plugin.run?.packageId === definition.packageId && plugin.run.pluginRunId === attempt.pluginRunId) return { + ok: true, + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: plugin.run.pluginRunId, + waitingFor: missingFor(this.ctx, plugin.run), + startedHere: false + }; + if (plugin.run !== void 0) await this.retract(plugin); + if (mode === "update" || plugin.currentPackageId === void 0) plugin.nextPackageId = definition.packageId; + const run = { + pluginRunId: attempt.pluginRunId, + packageId: definition.packageId, + handlers: /* @__PURE__ */ new Map(), + handlerDisposers: [], + reportedRuntimeErrors: /* @__PURE__ */ new Set(), + ...requestId === void 0 ? {} : { startedForRequest: requestId } + }; + if (definition.hostCode !== void 0) { + const failure = await this.startHost(plugin, definition.hostCode, run); + if (failure !== void 0) return { + ok: false, + ...failure + }; + } + plugin.run = run; + this.ctx.emit("cordis/dynamic-package", { + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: run.pluginRunId, + name: definition.name + }); + attempt.host = { + status: run.fiber === void 0 ? "absent" : missingFor(this.ctx, run).length === 0 ? "running" : "waiting", + waitingFor: missingFor(this.ctx, run) + }; + if (definition.clientCode === void 0) this.commitActivation(plugin, run); + else { + attempt.status = "client-pending"; + attempt.client = { + status: "pending", + waitingFor: [] + }; + } + return { + ok: true, + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: run.pluginRunId, + waitingFor: missingFor(this.ctx, run), + startedHere: true + }; + } + async startHost(plugin, hostCode, run) { + const handle = (method, fn) => { + const normalized = normalizeHandler(method, fn); + run.handlers.set(normalized.method, normalized.handler); + const dispose = () => { + if (run.handlers.get(normalized.method) === normalized.handler) run.handlers.delete(normalized.method); + }; + run.handlerDisposers.push(dispose); + return dispose; + }; + try { + const evaluated = await evaluateHostCode(createSandbox(plugin.pluginId, { handle }), hostCode, plugin.pluginId, this.resolved.vmTimeoutMs); + if (!isPlugin(evaluated)) throw new Error(evaluated === void 0 ? "the Host half returned `undefined` — did you forget `return`?" : "the Host half must return a Plugin function or an object with apply(ctx)"); + run.fiber = await startHostHalf(this.requireGroup(), evaluated, (error) => { + this.steerGuardFailure(plugin, run, "Host", errorDetails(error)); + }); + return; + } catch (error) { + for (const dispose of run.handlerDisposers.splice(0)) dispose(); + return errorDetails(error); + } + } + async settleActivation(plugin, resolution, requestId) { + if (plugin === void 0) return { + ok: false, + reason: "plugin-missing", + message: "the dynamic plugin was removed during activation" + }; + const attempt = plugin.latestRun; + if (!resolution.ok) { + if (resolution.reason === "rejected") { + if (attempt !== void 0) { + attempt.status = "rejected"; + attempt.error = this.diagnostic(plugin, attempt, "approval", resolution.message ?? "the run request was declined"); + attempt.client = { + status: "stopped", + waitingFor: [] + }; + } + return { + ok: false, + reason: "rejected", + message: resolution.message ?? "the run request was declined" + }; + } + const run = plugin.run; + if (run !== void 0 && resolution.pluginRunId === run.pluginRunId && (requestId === void 0 || run.startedForRequest === requestId) && resolution.startedHere !== false) await this.retract(plugin); + if (attempt !== void 0 && (resolution.pluginRunId === void 0 || attempt.pluginRunId === resolution.pluginRunId)) this.failAttempt(plugin, attempt, resolution.reason === "host-half-failed" ? "host-apply" : "client-apply", { + message: resolution.message ?? resolution.reason, + ...resolution.stack === void 0 ? {} : { stack: resolution.stack } + }); + return { + ok: false, + reason: resolution.reason, + message: resolution.message ?? resolution.reason, + ...resolution.stack === void 0 ? {} : { stack: resolution.stack } + }; + } + const run = plugin.run; + if (run === void 0 || run.pluginRunId !== resolution.pluginRunId) return { + ok: false, + reason: "client-half-failed", + message: `activation "${resolution.pluginRunId}" is no longer active` + }; + if (attempt !== void 0 && attempt.pluginRunId === run.pluginRunId) attempt.client = { + status: resolution.waitingFor === void 0 || resolution.waitingFor.length === 0 ? "running" : "waiting", + waitingFor: resolution.waitingFor ?? [] + }; + this.commitActivation(plugin, run); + return { + ...this.runResponse(plugin, { + ok: true, + pluginId: plugin.pluginId, + packageId: run.packageId, + pluginRunId: run.pluginRunId, + waitingFor: missingFor(this.ctx, run), + startedHere: false + }), + ...resolution.waitingFor === void 0 ? {} : { clientWaitingFor: resolution.waitingFor } + }; + } + commitActivation(plugin, run) { + plugin.currentPackageId = run.packageId; + delete plugin.nextPackageId; + delete run.startedForRequest; + const attempt = plugin.latestRun; + if (attempt?.pluginRunId === run.pluginRunId) { + attempt.status = attempt.host.status === "waiting" || attempt.client.status === "waiting" ? "waiting" : "running"; + delete attempt.approvalRequestId; + delete attempt.requiresApproval; + delete attempt.error; + } + } + runResponse(plugin, started) { + return { + ok: true, + status: "running", + pluginId: plugin.pluginId, + packageId: started.packageId, + pluginRunId: started.pluginRunId, + waitingFor: started.waitingFor, + currentPackageId: started.packageId, + mode: plugin.latestRun?.pluginRunId === started.pluginRunId ? plugin.latestRun.mode : "run" + }; + } + announceResolved(requestId, resolution, override) { + const outcome = override ?? (resolution.ok ? "approved" : resolution.reason === "rejected" ? "rejected" : "failed"); + this.ctx.emit("cordis/request-run-resolved", { + requestId, + outcome + }); + } + steerRunOutcome(pending, settled) { + const agent = this.rootCtx.get("agents")?.get(pending.agentId); + if (agent === void 0) return; + const plugin = this.registry.get(pending.pluginId); + const identity = `${pending.pluginId}/${pending.packageId} (${pending.pluginRunId})`; + let text; + if (settled.ok) text = `Cordis ${pending.mode} ${identity} completed successfully. currentPackageId is ${settled.currentPackageId ?? pending.packageId}. Continue using the running Plugin.`; + else if (settled.reason === "rejected") text = `The user rejected Cordis ${pending.mode} ${identity}. Do not request the same activation again unless the user asks.`; + else { + const returnedStatus = pending.requiresApproval ? "awaiting-approval" : "starting"; + text = `Cordis ${pending.mode} ${identity} failed after cordis_run returned ${returnedStatus}: ${settled.reason}\n${formatErrorDetails(settled)}\ncurrentPackageId: ${plugin?.currentPackageId ?? "none"}\nnextPackageId: ${plugin?.nextPackageId ?? pending.packageId}\nInspect the failed Package, correct it on the same Plugin when needed, and retry the activation autonomously.`; + } + agent.steer(createUserMessage({ + content: [{ + type: "text", + text + }], + source: { + kind: "plugin", + plugin: "cordis-host-runner" + } + })); + } + steerRenderFailure(agent, plugin, definition, pluginRunId, failure) { + agent.steer(createUserMessage({ + content: [{ + type: "text", + text: `Cordis Client UI ${plugin.pluginId}/${definition.packageId} (${pluginRunId}) failed while rendering Slot "${failure.slot}" after activation.\n${formatErrorDetails(failure)}\nentryAbdicated: ${failure.abdicated}\nInspect the failed Package, fix the Client code by defining a new Package on the same Plugin, and activate that Package autonomously with cordis_run mode:"update".` + }], + source: { + kind: "plugin", + plugin: "cordis-host-runner" + } + })); + } + steerHostHandlerFailure(plugin, run, method, failure) { + const reportKey = `Host\u0000handler\u0000${method}\u0000${failure.message}`; + if (!this.claimRuntimeFailure(plugin, run, reportKey)) return; + const agent = this.rootCtx.get("agents")?.get(plugin.sessionId); + if (agent === void 0) return; + agent.steer(createUserMessage({ + content: [{ + type: "text", + text: `Cordis Host handler ${plugin.pluginId}/${run.packageId} (${run.pluginRunId}) failed when the Client called host.call(${JSON.stringify(method)}).\n${formatErrorDetails(failure)}\nThe Plugin remains running. Inspect this Package, correct the Host code on the same Plugin, and activate the new Package autonomously with cordis_run mode:"update". If the handler needs a Service, either declare that Service in the returned Plugin inject list or read it with ctx.get(name) and handle undefined.` + }], + source: { + kind: "plugin", + plugin: "cordis-host-runner" + } + })); + } + steerGuardFailure(plugin, run, platform, failure) { + const reportKey = `${platform}\u0000guard\u0000${failure.message}`; + if (!this.claimRuntimeFailure(plugin, run, reportKey)) return; + const agent = this.rootCtx.get("agents")?.get(plugin.sessionId); + if (agent === void 0) return; + agent.steer(createUserMessage({ + content: [{ + type: "text", + text: `Cordis ${platform} guard rejected runtime code in ${plugin.pluginId}/${run.packageId} (${run.pluginRunId}) after activation.\n${formatErrorDetails(failure)}\nThe Plugin remains running. Inspect this Package, define a corrected Package on the same Plugin, and activate it autonomously with cordis_run mode:"update".` + }], + source: { + kind: "plugin", + plugin: "cordis-host-runner" + } + })); + } + claimRuntimeFailure(plugin, run, key) { + const attempt = plugin.latestRun; + if (plugin.run !== run || attempt?.pluginRunId !== run.pluginRunId || attempt.status !== "running" && attempt.status !== "waiting") return false; + if (run.reportedRuntimeErrors.has(key)) return false; + run.reportedRuntimeErrors.add(key); + return true; + } + injectUserRunOutcome(agent, pluginId, settled) { + const plugin = this.owned(agent, pluginId); + let text; + if (settled.ok) text = `The user manually ran Cordis Plugin ${pluginId}, Package ${settled.packageId}, as ${settled.pluginRunId}. The activation succeeded; currentPackageId is ${settled.currentPackageId}.`; + else { + const attempt = plugin?.latestRun; + text = `The user manually ran Cordis Plugin ${pluginId}${attempt === void 0 ? "" : `, Package ${attempt.packageId}, as ${attempt.pluginRunId}`}, but it failed: ${settled.reason}\n${formatErrorDetails(settled)}\ncurrentPackageId: ${plugin?.currentPackageId ?? "none"}\nnextPackageId: ${plugin?.nextPackageId ?? "none"}`; + } + this.injectUserContext(agent, text); + } + injectUserContext(agent, text) { + if (this.rootCtx.get("agents")?.get(agent.id) !== agent) return; + agent.inject(createUserMessage({ + content: [{ + type: "text", + text + }], + source: { + kind: "plugin", + plugin: "cordis-host-runner" + } + })); + } + cancelPending(pluginId, message) { + const requestId = this.registry.pendingRequestFor(pluginId); + if (requestId === void 0) return; + const pending = this.registry.claimRequest(requestId); + if (pending === void 0) return; + const plugin = this.registry.get(pluginId); + if (plugin?.latestRun?.pluginRunId === pending.pluginRunId) { + plugin.latestRun.status = "cancelled"; + plugin.latestRun.error = this.diagnostic(plugin, plugin.latestRun, "approval", message); + delete plugin.latestRun.approvalRequestId; + delete plugin.latestRun.requiresApproval; + } + this.announceResolved(requestId, { + ok: false, + reason: "rejected" + }, "cancelled"); + } + createAttempt(plan) { + return { + pluginRunId: CordisDynamicPluginRunId(this.registry.mintPluginRunId()), + packageId: plan.definition.packageId, + mode: plan.mode, + status: "starting-host", + host: { + status: plan.definition.hostCode === void 0 ? "absent" : "pending", + waitingFor: [] + }, + client: { + status: plan.definition.clientCode === void 0 ? "absent" : "pending", + waitingFor: [] + } + }; + } + failAttempt(plugin, attempt, phase, failure) { + attempt.status = "failed"; + attempt.error = this.diagnostic(plugin, attempt, phase, failure); + if (phase.startsWith("host")) attempt.host = { + status: "failed", + waitingFor: [], + error: failure.message + }; + else attempt.client = { + status: "failed", + waitingFor: [], + error: failure.message + }; + } + diagnostic(plugin, attempt, phase, failure) { + return { + phase, + ...typeof failure === "string" ? { message: failure } : failure, + pluginId: plugin.pluginId, + packageId: attempt.packageId, + pluginRunId: attempt.pluginRunId + }; + } + async retract(plugin) { + const run = plugin.run; + if (run === void 0) return; + delete plugin.run; + for (const dispose of run.handlerDisposers.splice(0)) dispose(); + if (run.fiber !== void 0) await run.fiber.dispose(); + this.ctx.emit("cordis/dynamic-retract", { + pluginId: plugin.pluginId, + packageId: run.packageId, + pluginRunId: run.pluginRunId + }); + } + owned(agent, pluginId) { + const plugin = this.registry.get(pluginId); + return plugin?.sessionId === agent.id ? plugin : void 0; + } + requireGroup() { + this.group ??= this.rootCtx.plugin({ + name: "cordis-dynamic", + apply: () => {} + }); + return this.group; + } + }; +})(); +function missingFor(ctx, run) { + return run.fiber === void 0 ? [] : missingServices(ctx, run.fiber); +} +function missingPluginMessage(id) { + return `no dynamic plugin "${id}" in this process — it may have been removed or lost on DSH restart`; +} +function errorDetails(error) { + if (typeof error !== "object" || error === null) return { message: String(error) }; + const message = "message" in error && typeof error.message === "string" ? error.message : Object.prototype.toString.call(error); + const stack = "stack" in error && typeof error.stack === "string" ? error.stack : void 0; + return { + message, + ...stack === void 0 ? {} : { stack } + }; +} +function formatErrorDetails(failure) { + return `message: ${failure.message}` + (failure.stack === void 0 ? "" : `\nstack:\n${failure.stack}`); +} +function cloneAttempt(attempt) { + return { + ...attempt, + host: { + ...attempt.host, + waitingFor: [...attempt.host.waitingFor] + }, + client: { + ...attempt.client, + waitingFor: [...attempt.client.waitingFor] + }, + ...attempt.error === void 0 ? {} : { error: { ...attempt.error } } + }; +} +//#endregion +export { ApprovalRequestId, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisInspectRegistryService, DynamicCordisRunnerService, DynamicCordisRunnerService as default, HOST_BUILTIN_INSPECTION }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/invariant.js new file mode 100644 index 0000000..bd5d424 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/invariant.js @@ -0,0 +1,25 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-cordis-host-runner`. +* @module @deepseek-ai/dsh-cordis-host-runner/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-cordis-host-runner"; +/** Cordis companion plugin name. */ +const name = "cordis-host-runner-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the definition registry is process memory with no event +* stream to observe, and its one owned relation (a running definition owns a +* settled host-half fiber and its handler table) is established and unwound +* inside single awaited verbs, so package tests assert it directly. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.d.ts new file mode 100644 index 0000000..dcf4919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.d.ts @@ -0,0 +1,3 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ + +export declare const TYPERT: unknown diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.js new file mode 100644 index 0000000..151b708 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.js @@ -0,0 +1,1897 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ +import { z } from 'zod' + +const JsonValueRemoteCodec$schema = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]) +const JsonValueRemoteCodec$schema2 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]) +const JsonValueRemoteCodec$schema3 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]) +const JsonValueRemoteCodec$schema4 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema4)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema4))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema = z.object({ + 'code': z.string(), + 'name': z.string(), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema = z.array(z.object({ + 'pluginId': z.intersection(z.string(), z.unknown()), + 'agentId': z.intersection(z.string(), z.unknown()), + 'packages': z.array(z.object({ + 'packageId': z.intersection(z.string(), z.unknown()), + 'name': z.string(), + 'purpose': z.string(), + 'hasHostHalf': z.boolean(), + 'hasClientHalf': z.boolean(), +})), + 'currentPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'nextPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'activeRun': z.object({ + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), +}).optional(), + 'latestRun': z.object({ + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'mode': z.union([z.literal("run"), z.literal("update")]), + 'status': z.union([z.literal("rejected"), z.literal("awaiting-approval"), z.literal("running"), z.literal("cancelled"), z.literal("starting-host"), z.literal("client-pending"), z.literal("waiting"), z.literal("failed"), z.literal("stopped")]), + 'approvalRequestId': z.intersection(z.string(), z.unknown()).optional(), + 'requiresApproval': z.boolean().optional(), + 'host': z.object({ + 'status': z.union([z.literal("running"), z.literal("waiting"), z.literal("failed"), z.literal("stopped"), z.literal("absent"), z.literal("pending")]), + 'waitingFor': z.array(z.string()), + 'error': z.string().optional(), +}), + 'client': z.object({ + 'status': z.union([z.literal("running"), z.literal("waiting"), z.literal("failed"), z.literal("stopped"), z.literal("absent"), z.literal("pending")]), + 'waitingFor': z.array(z.string()), + 'error': z.string().optional(), +}), + 'error': z.object({ + 'phase': z.union([z.literal("approval"), z.literal("host-load"), z.literal("host-apply"), z.literal("client-load"), z.literal("client-apply"), z.literal("client-render")]), + 'message': z.string(), + 'stack': z.string().optional(), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), +}).optional(), +}).optional(), +})) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema = z.string() +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'value': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema4)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema4))]), +}), z.intersection(z.object({ + 'ok': z.literal(false), + 'code': z.union([z.literal("plugin-not-running"), z.literal("stale-run"), z.literal("method-not-found"), z.literal("handler-error")]), +}), z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema = z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema = z.object({ + 'slot': z.string(), + 'message': z.string(), + 'stack': z.string().optional(), + 'abdicated': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema = z.union([z.object({ + 'ok': z.literal(true), + 'data': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("cancelled"), z.literal("provider-missing"), z.literal("method-missing"), z.literal("invalid-input"), z.literal("provider-error")]), + 'message': z.string(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema = z.object({ + 'accepted': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()).optional(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed")]), + 'pluginRunId': z.intersection(z.string(), z.unknown()).optional(), + 'startedHere': z.boolean().optional(), + 'message': z.string().optional(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema = z.object({ + 'accepted': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema = z.union([z.literal("run"), z.literal("update")]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema = z.union([z.literal(null), z.intersection(z.string(), z.unknown())]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema = z.boolean() +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()), + 'startedHere': z.boolean(), +}), z.intersection(z.object({ + 'ok': z.literal(false), +}), z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()).optional(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed")]), + 'pluginRunId': z.intersection(z.string(), z.unknown()).optional(), + 'startedHere': z.boolean().optional(), + 'message': z.string().optional(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'status': z.union([z.literal("awaiting-approval"), z.literal("starting"), z.literal("running")]), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()), + 'clientWaitingFor': z.array(z.string()).optional(), + 'currentPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'nextPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'mode': z.union([z.literal("run"), z.literal("update")]), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("plugin-missing"), z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed"), z.literal("package-missing"), z.literal("invalid-mode"), z.literal("transition-in-flight"), z.literal("cancelled"), z.literal("not-running")]), + 'message': z.string(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema = z.union([z.object({ + 'ok': z.literal(true), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("plugin-missing"), z.literal("not-running")]), + 'message': z.string(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema = z.array(z.object({ + 'id': z.string(), + 'description': z.string(), + 'methods': z.array(z.object({ + 'name': z.string(), + 'description': z.string(), + 'inputSchema': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]), + 'outputSchema': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]), +})), +})) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'wasRunning': z.boolean(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.literal("plugin-missing"), + 'message': z.string(), +})]) + +export const TYPERT = { + package: '@deepseek-ai/dsh-cordis-host-runner', + face: 'host', + schemas: [ + ], + invocations: [ + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/getClientCode', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'getClientCode', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisClientSource', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":384,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'inventory', + invocation: { kind: 'direct' }, + parameters: [ + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":525,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'invoke', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema, + }, + }, + { + name: 'method', + wire: 'method', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke:method', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema, + }, + }, + { + name: 'args', + wire: 'args', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#JsonValue', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisInvokeResult', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":741,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'reportClientGuardFailure', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema, + }, + }, + { + name: 'failure', + wire: 'failure', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisErrorDetails', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":718,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'reportRenderFailure', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema, + }, + }, + { + name: 'failure', + wire: 'failure', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRenderFailure', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":684,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveInspectQuery', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'resolveInspectQuery', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema, + }, + }, + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectRequestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectQueryResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectResolveAck', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":511,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveRequestRun', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'resolveRequestRun', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#ApprovalRequestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisResolveAck', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":413,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'runHostHalf', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema, + }, + }, + { + name: 'packageId', + wire: 'packageId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPackageId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema, + }, + }, + { + name: 'mode', + wire: 'mode', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicRunMode', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema, + }, + }, + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:requestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema, + }, + }, + { + name: 'approveFutureVersions', + wire: 'approveFutureVersions', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:approveFutureVersions', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisHostHalfResult', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":325,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/settleUserRun', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'settleUserRun', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResponse', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":438,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/stopFromPanel', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'stopFromPanel', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisStopResponse', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":480,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'syncInspectManifest', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'providers', + wire: 'providers', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:providers', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":498,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/undefineFromPanel', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'undefineFromPanel', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisUndefineReceipt', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":227,"column":9}, + }, + ], + model: { + "services": [ + { + "description": "Registry and cross-page router behind the two model-facing inspect tools.", + "summary": "Registry and cross-page router behind the two model-facing inspect tools.", + "tags": [], + "jsDoc": "/** Registry and cross-page router behind the two model-facing inspect tools. */", + "key": "cordisInspect", + "exportName": "CordisInspectRegistryService", + "members": [ + { + "kind": "method", + "name": "register", + "signature": "register(registration: HostCordisInspectProviderRegistration): () => void", + "summary": "Register one Host provider.", + "jsDoc": "/**\n * Register one Host provider.\n * @param registration - manifest and local query handler.\n * @returns idempotent disposer.\n */" + }, + { + "kind": "method", + "name": "syncClientManifest", + "signature": "syncClientManifest(providers: readonly CordisInspectProviderManifest[]): void", + "summary": "Replace the mirrored Client provider directory.", + "jsDoc": "/**\n * Replace the mirrored Client provider directory.\n * @param providers - complete Client manifest snapshot.\n */" + }, + { + "kind": "method", + "name": "list", + "signature": "list(): CordisInspectProviderView[]", + "summary": "Return the complete known Host and Client provider directory.", + "jsDoc": "/**\n * Return the complete known Host and Client provider directory.\n * @returns Host providers followed by the Client providers.\n */" + }, + { + "kind": "method", + "name": "query", + "signature": "async query( platform: CordisInspectPlatform, providerId: string, methodName: string, input: JsonValue | undefined, agent: Agent, signal: AbortSignal, ): Promise", + "summary": "Execute one provider query on its owning platform.", + "jsDoc": "/**\n * Execute one provider query on its owning platform.\n * @param platform - Host or Client runtime.\n * @param providerId - provider selected from {@link list}.\n * @param methodName - declared method name.\n * @param input - optional lossless JSON input.\n * @param agent - requesting Agent and scope.\n * @param signal - tool-call cancellation.\n * @returns provider JSON data.\n */" + }, + { + "kind": "method", + "name": "resolveClientQuery", + "signature": "resolveClientQuery( agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution, ): CordisInspectResolveAck", + "summary": "Accept the first valid Client response for a pending query.", + "jsDoc": "/**\n * Accept the first valid Client response for a pending query.\n * @param agent - Agent whose Session owns the query.\n * @param requestId - Pending Client query identity.\n * @param resolution - Client provider result or failure.\n * @returns whether this response settled the still-pending query.\n */" + } + ], + "types": [ + { + "name": "Agent", + "declaration": "export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly inbox: Inbox;\n readonly status: AgentStatus;\n readonly ctx: Context;\n cancel(cause: AgentCancelCause, options?: CancelOptions): void;\n whenIdle(): Promise;\n runMaintenance(task: (signal: AbortSignal) => Promise): Promise;\n send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;\n followup(message: UserMessage): void;\n steer(message: UserMessage): void;\n inject(message: UserMessage): void;\n}" + }, + { + "name": "AgentCancelCause", + "declaration": "export type AgentCancelCause = { readonly kind: 'user'; } | { readonly kind: 'parent'; } | { readonly kind: 'hook'; readonly reason: string; } | { readonly kind: 'disposed'; };" + }, + { + "name": "AgentOptions", + "declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n maxTokens?: number;\n}" + }, + { + "name": "AgentStatus", + "declaration": "export type AgentStatus = 'idle' | 'running';" + }, + { + "name": "ApprovalOutcome", + "declaration": "export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';" + }, + { + "name": "ApprovalPolicy", + "declaration": "export type ApprovalPolicy = 'ask' | 'never';" + }, + { + "name": "ApprovalRequestId", + "declaration": "export type ApprovalRequestId = Branded<'ApprovalRequestId'>;" + }, + { + "name": "AssistantMessage", + "declaration": "export interface AssistantMessage extends Message {\n readonly role: 'assistant';\n readonly source: ModelMessageSource;\n}" + }, + { + "name": "AssistantProvenance", + "declaration": "export interface AssistantProvenance {\n provider: string;\n model: string;\n replayState?: unknown;\n}" + }, + { + "name": "AttachmentId", + "declaration": "export type AttachmentId = Branded<'AttachmentId'>;" + }, + { + "name": "Branded", + "declaration": "export type Branded = string & { readonly [BRAND]: B; };" + }, + { + "name": "CallId", + "declaration": "export type CallId = Branded<'CallId'>;" + }, + { + "name": "CancelOptions", + "declaration": "export interface CancelOptions {\n keepInbox?: boolean | undefined;\n}" + }, + { + "name": "CodeDispatchEventData", + "declaration": "export interface CodeDispatchEventData extends CodeDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}" + }, + { + "name": "CodeDispatchStartEventData", + "declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}" + }, + { + "name": "CommandId", + "declaration": "export type CommandId = Branded<'CommandId'>;" + }, + { + "name": "CommandSource", + "declaration": "export type CommandSource = CommandSourceMap[keyof CommandSourceMap];" + }, + { + "name": "CommandSourceMap", + "declaration": "export interface CommandSourceMap {\n user: { kind: 'user'; };\n}" + }, + { + "name": "ContentBlock", + "declaration": "export type ContentBlock = ContentBlockMap[ContentBlockType];" + }, + { + "name": "ContentBlockMap", + "declaration": "export interface ContentBlockMap {\n text: TextBlock;\n reasoning: ReasoningBlock;\n image: ImageBlock;\n 'tool-call': ToolCallBlock;\n 'tool-result': ToolResultBlock;\n}" + }, + { + "name": "ContentBlockType", + "declaration": "export type ContentBlockType = keyof ContentBlockMap;" + }, + { + "name": "ContextFormed", + "declaration": "export type ContextFormed = { readonly form?: never; } | { readonly form: 'instructions'; } | { readonly form: 'catalog'; } | { readonly form: 'snapshot'; readonly sections: readonly ContextSnapshotSection[]; } | { readonly form: 'notice'; readonly summary: string; } | { readonly form: 'relay'; } | { readonly form: 'recall'; };" + }, + { + "name": "ContextSnapshotSection", + "declaration": "export interface ContextSnapshotSection {\n readonly name: string;\n readonly text: string;\n}" + }, + { + "name": "CordisInspectMethodManifest", + "declaration": "export interface CordisInspectMethodManifest {\n name: string;\n description: string;\n inputSchema: JsonValue;\n outputSchema: JsonValue;\n}" + }, + { + "name": "CordisInspectPlatform", + "declaration": "export type CordisInspectPlatform = 'host' | 'client';" + }, + { + "name": "CordisInspectProviderManifest", + "declaration": "export interface CordisInspectProviderManifest {\n id: string;\n description: string;\n methods: readonly CordisInspectMethodManifest[];\n}" + }, + { + "name": "CordisInspectProviderView", + "declaration": "export interface CordisInspectProviderView extends CordisInspectProviderManifest {\n platform: CordisInspectPlatform;\n}" + }, + { + "name": "CordisInspectQueryResolution", + "declaration": "export type CordisInspectQueryResolution = { ok: true; data: JsonValue; } | { ok: false; reason: 'provider-missing' | 'method-missing' | 'invalid-input' | 'provider-error' | 'cancelled'; message: string; };" + }, + { + "name": "CordisInspectRequestId", + "declaration": "export type CordisInspectRequestId = Branded<'CordisInspectRequestId'>;" + }, + { + "name": "CordisInspectResolveAck", + "declaration": "export interface CordisInspectResolveAck {\n accepted: boolean;\n}" + }, + { + "name": "EpochHeader", + "declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n system?: string;\n tools?: ToolSchema[];\n}" + }, + { + "name": "FinishReason", + "declaration": "export type FinishReason = FinishReasonMap[keyof FinishReasonMap];" + }, + { + "name": "FinishReasonMap", + "declaration": "export interface FinishReasonMap {\n stop: { kind: 'stop'; };\n 'tool-calls': { kind: 'tool-calls'; };\n 'max-tokens': { kind: 'max-tokens'; };\n aborted: { kind: 'aborted'; failure: LlmFailure; };\n error: { kind: 'error'; failure: LlmFailure; };\n}" + }, + { + "name": "GoalBlockReason", + "declaration": "export interface GoalBlockReason {\n readonly code: string;\n readonly message: string;\n}" + }, + { + "name": "GoalChangeMeta", + "declaration": "export type GoalChangeMeta = GoalSnapshotChangeMeta | GoalClearChangeMeta;" + }, + { + "name": "GoalClearChangeMeta", + "declaration": "export interface GoalClearChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: 'clear';\n readonly cleared: GoalRef;\n readonly clearedAt: number;\n}" + }, + { + "name": "GoalId", + "declaration": "export type GoalId = Branded<'GoalId'>;" + }, + { + "name": "GoalMessageSource", + "declaration": "export interface GoalMessageSource {\n readonly kind: 'goal';\n readonly goalId: GoalId;\n readonly revision: number;\n readonly round: number;\n}" + }, + { + "name": "GoalOperation", + "declaration": "export type GoalOperation = 'create' | 'edit' | 'pause' | 'resume' | 'complete' | 'block' | 'clear';" + }, + { + "name": "GoalPhase", + "declaration": "export type GoalPhase = 'active' | 'paused' | 'blocked' | 'complete';" + }, + { + "name": "GoalRef", + "declaration": "export interface GoalRef {\n readonly id: GoalId;\n readonly revision: number;\n}" + }, + { + "name": "GoalSnapshot", + "declaration": "export interface GoalSnapshot extends GoalRef {\n readonly objective: string;\n readonly phase: GoalPhase;\n readonly blockedReason?: GoalBlockReason;\n readonly maxGoalRounds: number;\n}" + }, + { + "name": "GoalSnapshotChangeMeta", + "declaration": "export interface GoalSnapshotChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: Exclude;\n readonly goal: GoalSnapshot;\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n}" + }, + { + "name": "HostCordisInspectProviderRegistration", + "declaration": "export interface HostCordisInspectProviderRegistration {\n manifest: CordisInspectProviderManifest;\n query(method: string, input: JsonValue | undefined, context: HostCordisInspectQueryContext): Promise;\n}" + }, + { + "name": "HostCordisInspectQueryContext", + "declaration": "export interface HostCordisInspectQueryContext {\n signal: AbortSignal;\n agent: Agent;\n}" + }, + { + "name": "ImageAttachmentRef", + "declaration": "export interface ImageAttachmentRef {\n attachmentId: AttachmentId;\n mediaType: ImageMediaType;\n bytes: number;\n width: number;\n height: number;\n name?: string;\n}" + }, + { + "name": "ImageBlock", + "declaration": "export interface ImageBlock {\n type: 'image';\n attachment: ImageAttachmentRef;\n}" + }, + { + "name": "ImageMediaType", + "declaration": "export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';" + }, + { + "name": "Inbox", + "declaration": "export class Inbox {\n get nextTurn(): readonly UserMessage[];\n get nextStep(): readonly UserMessage[];\n get hasPending(): boolean;\n clear(): void;\n claim(target: InboxTarget, turn: number): UserMessage[];\n append(target: InboxTarget, message: UserMessage): void;\n prepend(target: InboxTarget, message: UserMessage): void;\n replace(messageId: MessageId, newMessage: UserMessage): boolean;\n remove(messageId: MessageId): boolean;\n splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[];\n}" + }, + { + "name": "InboxTarget", + "declaration": "export type InboxTarget = 'next-turn' | 'next-step';" + }, + { + "name": "JsonValue", + "declaration": "export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue; };" + }, + { + "name": "LlmCallConfig", + "declaration": "export interface LlmCallConfig {\n provider: string;\n model: string;\n reasoningEffort?: ReasoningEffortId;\n temperature?: number;\n maxTokens?: number;\n stop?: string[];\n}" + }, + { + "name": "LlmCallConfigAdapterDefaults", + "declaration": "export interface LlmCallConfigAdapterDefaults {\n reasoningEffort?: true;\n maxTokens?: true;\n}" + }, + { + "name": "LlmFailure", + "declaration": "export interface LlmFailure {\n readonly message: string;\n readonly code: string;\n readonly status?: number;\n readonly providerRetryAfterMs?: number;\n readonly requestId?: ProviderRequestId;\n}" + }, + { + "name": "Message", + "declaration": "export interface Message {\n readonly id: MessageId;\n readonly role: 'system' | 'user' | 'assistant';\n readonly content: ContentBlock[];\n readonly source: MessageSource;\n}" + }, + { + "name": "MessageId", + "declaration": "export type MessageId = Branded<'MessageId'>;" + }, + { + "name": "MessageSource", + "declaration": "export type MessageSource = MessageSourceMap[keyof MessageSourceMap];" + }, + { + "name": "MessageSourceMap", + "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n goal: GoalMessageSource;\n}" + }, + { + "name": "ModelMessageSource", + "declaration": "export interface ModelMessageSource extends AssistantProvenance {\n kind: 'model';\n}" + }, + { + "name": "ProviderRequestId", + "declaration": "export type ProviderRequestId = Branded<'ProviderRequestId'>;" + }, + { + "name": "ReasoningBlock", + "declaration": "export interface ReasoningBlock {\n type: 'reasoning';\n text: string;\n}" + }, + { + "name": "ReasoningEffortId", + "declaration": "export type ReasoningEffortId = Branded<'ReasoningEffortId'>;" + }, + { + "name": "RequestContext", + "declaration": "export interface RequestContext {\n provider: string;\n model: string;\n contextWindow?: number;\n}" + }, + { + "name": "RequestHeaderReason", + "declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change';" + }, + { + "name": "Session", + "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n get id(): SessionId;\n readonly firstLiveSeq: number;\n get events(): readonly SessionEvent[];\n get seq(): number;\n append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}" + }, + { + "name": "SessionEvent", + "declaration": "export type SessionEvent = { [K in SessionEventType]: { type: K; seq: number; time: number; data: SessionEventMap[K]; ignorable?: true; } & (K extends SurfaceEventType ? { sourceEventSeqs?: number[]; surfaceOp?: SurfaceOp; } : object) }[T];" + }, + { + "name": "SessionEventMap", + "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: number; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n 'goal/change': GoalChangeMeta;\n}" + }, + { + "name": "SessionEventType", + "declaration": "export type SessionEventType = keyof SessionEventMap;" + }, + { + "name": "SessionHeader", + "declaration": "export interface SessionHeader {\n readonly version: number;\n readonly id: SessionId;\n readonly createdAt: number;\n readonly cwd?: string;\n readonly parentSession?: SessionId;\n readonly seedLength?: number;\n readonly origin?: 'subagent';\n readonly delegationDepth?: number;\n readonly agentPreset?: string;\n}" + }, + { + "name": "SessionId", + "declaration": "export type SessionId = Branded<'SessionId'>;" + }, + { + "name": "SessionSurface", + "declaration": "export interface SessionSurface {\n readonly nodes: readonly number[];\n readonly replaceGeneration: number;\n}" + }, + { + "name": "StreamChunk", + "declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: unknown; };" + }, + { + "name": "SurfaceEventType", + "declaration": "export type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result';" + }, + { + "name": "SurfaceIntent", + "declaration": "export interface SurfaceIntent {\n surfaceOp: SurfaceOp;\n sourceEventSeqs?: number[];\n}" + }, + { + "name": "SurfaceOp", + "declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: number; end: number; };" + }, + { + "name": "TextBlock", + "declaration": "export interface TextBlock {\n type: 'text';\n text: string;\n}" + }, + { + "name": "TodoItem", + "declaration": "export interface TodoItem {\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n}" + }, + { + "name": "TokenUsage", + "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}" + }, + { + "name": "ToolCallBlock", + "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: CallId;\n name: string;\n arguments: string;\n}" + }, + { + "name": "ToolMessageSource", + "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: CallId;\n}" + }, + { + "name": "ToolResultBlock", + "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: CallId;\n content: ContentBlock[];\n isError?: boolean;\n}" + }, + { + "name": "ToolResultMessage", + "declaration": "export interface ToolResultMessage extends Message {\n readonly role: 'user';\n readonly content: [ToolResultBlock];\n readonly source: ToolMessageSource;\n}" + }, + { + "name": "ToolSchema", + "declaration": "export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n}" + }, + { + "name": "TurnEndCancelCause", + "declaration": "export type TurnEndCancelCause = AgentCancelCause | { readonly kind: 'legacy'; };" + }, + { + "name": "TurnEndReason", + "declaration": "export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap];" + }, + { + "name": "TurnEndReasonMap", + "declaration": "export interface TurnEndReasonMap {\n completed: { kind: 'completed'; };\n aborted: { kind: 'aborted'; reason: TurnEndCancelCause; };\n blocked: { kind: 'blocked'; };\n error: { kind: 'error'; error: LlmFailure; };\n 'max-tokens': { kind: 'max-tokens'; };\n interrupted: { kind: 'interrupted'; };\n}" + }, + { + "name": "UserMessage", + "declaration": "export interface UserMessage extends Message {\n readonly role: 'user';\n}" + } + ] + }, + { + "description": "Dynamic Plugin registry and Host-half lifecycle.", + "summary": "Dynamic Plugin registry and Host-half lifecycle.", + "tags": [], + "jsDoc": "/** Dynamic Plugin registry and Host-half lifecycle. */", + "key": "dynamicCordisRunner", + "exportName": "DynamicCordisRunnerService", + "members": [ + { + "kind": "method", + "name": "define", + "signature": "define(request: DynamicCordisDefineRequest): DynamicCordisDefineReceipt", + "summary": "Define a new Plugin's first Package or append a Package to an existing Plugin.", + "jsDoc": "/**\n * Define a new Plugin's first Package or append a Package to an existing Plugin.\n * @param request - Session ownership, Plugin selection, metadata, and source code.\n * @returns Host-minted Plugin and Package identities with declared-half metadata.\n */" + }, + { + "kind": "method", + "name": "undefine", + "signature": "async undefine(agent: Agent, pluginId: CordisDynamicPluginId): Promise", + "summary": "Remove a Plugin, its active run, and all immutable Packages.", + "jsDoc": "/**\n * Remove a Plugin, its active run, and all immutable Packages.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity to remove.\n * @returns Whether removal succeeded and whether it stopped an active run.\n */" + }, + { + "kind": "method", + "name": "undefineFromPanel", + "signature": "@Remote('undefineFromPanel') async undefineFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise", + "summary": "Remove a Plugin from the user panel and queue the resulting state change for the model's next step.", + "jsDoc": "/**\n * Remove a Plugin from the user panel and queue the resulting state change for the model's next step.\n * @param agent - Agent whose Session owns the Plugin and receives the context.\n * @param pluginId - Stable Plugin identity to remove.\n * @returns Whether removal succeeded and whether it stopped an active run.\n */" + }, + { + "kind": "method", + "name": "run", + "signature": "async run( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, signal?: AbortSignal, ): Promise", + "summary": "Start or update one Package for a model tool call.", + "jsDoc": "/**\n * Start or update one Package for a model tool call. An unauthorized Client\n * Package waits for approval; Plugin-wide authorization covers later versions.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity to activate.\n * @param packageId - Immutable Package version to activate.\n * @param mode - Whether to run the current version or switch versions.\n * @param signal - Tool-call cancellation signal while the activation request is being created.\n * @returns The successful activation identity or an actionable refusal.\n */" + }, + { + "kind": "method", + "name": "runHostHalf", + "signature": "@Remote('runHostHalf') async runHostHalf( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean, ): Promise", + "summary": "Start Host code for an approved request or a direct panel gesture.", + "jsDoc": "/**\n * Start Host code for an approved request or a direct panel gesture.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity to activate.\n * @param packageId - Immutable Package version to activate.\n * @param mode - Whether to run the current version or switch versions.\n * @param requestId - Model-driven request identity, or null for a direct user gesture.\n * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin.\n * @returns The exact Host activation or a failure message.\n */" + }, + { + "kind": "method", + "name": "getClientCode", + "signature": "@Remote('getClientCode') getClientCode( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, ): DynamicCordisClientSource", + "summary": "Fetch Client code for the exact active run.", + "jsDoc": "/**\n * Fetch Client code for the exact active run.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity to read.\n * @param pluginRunId - Exact active run authorized to receive source.\n * @returns Client source and its Plugin, Package, and run identities.\n */" + }, + { + "kind": "method", + "name": "resolveRequestRun", + "signature": "@Remote('resolveRequestRun') async resolveRequestRun( requestId: ApprovalRequestId, resolution: DynamicCordisRunResolution, ): Promise", + "summary": "Resolve one model-driven Client activation request.", + "jsDoc": "/**\n * Resolve one model-driven Client activation request.\n * @param requestId - Request identity to settle once.\n * @param resolution - Browser refusal or exact Client activation result.\n * @returns Whether the still-pending request accepted this resolution.\n */" + }, + { + "kind": "method", + "name": "settleUserRun", + "signature": "@Remote('settleUserRun') async settleUserRun( agent: Agent, pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution, ): Promise", + "summary": "Settle a direct panel run after this page loaded or failed its Client half.", + "jsDoc": "/**\n * Settle a direct panel run after this page loaded or failed its Client half.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity being settled.\n * @param resolution - Exact Client activation result from the acting page.\n * @returns The committed activation or its failure.\n */" + }, + { + "kind": "method", + "name": "stop", + "signature": "async stop(agent: Agent, pluginId: CordisDynamicPluginId): Promise", + "summary": "Stop the active run while retaining every Package version.", + "jsDoc": "/**\n * Stop the active run while retaining every Package version.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity to stop.\n * @returns Success or the reason no run was stopped.\n */" + }, + { + "kind": "method", + "name": "stopFromPanel", + "signature": "@Remote('stopFromPanel') async stopFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise", + "summary": "Stop a Plugin from the user panel and queue the resulting state change for the model's next step.", + "jsDoc": "/**\n * Stop a Plugin from the user panel and queue the resulting state change for the model's next step.\n * @param agent - Agent whose Session owns the Plugin and receives the context.\n * @param pluginId - Stable Plugin identity to stop.\n * @returns Success or the reason no run was stopped.\n */" + }, + { + "kind": "method", + "name": "syncInspectManifest", + "signature": "@Remote('syncInspectManifest') syncInspectManifest(providers: readonly CordisInspectProviderManifest[]): null", + "summary": "Replace the Host mirror of the Client inspect provider directory.", + "jsDoc": "/**\n * Replace the Host mirror of the Client inspect provider directory.\n * @param providers - complete Client provider manifest.\n * @returns null after accepting the manifest.\n */" + }, + { + "kind": "method", + "name": "resolveInspectQuery", + "signature": "@Remote('resolveInspectQuery') resolveInspectQuery( agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution, ): CordisInspectResolveAck", + "summary": "Claim one pending Client inspect query with its live result.", + "jsDoc": "/**\n * Claim one pending Client inspect query with its live result.\n * @param agent - Session that owns the query.\n * @param requestId - exact pending query identity.\n * @param resolution - provider result or structured refusal.\n * @returns whether this answer won the query.\n */" + }, + { + "kind": "method", + "name": "inventory", + "signature": "@Remote('inventory') inventory(): DynamicCordisInventoryRow[]", + "summary": "Frame-wide inventory, grouped as one row per stable Plugin.", + "jsDoc": "/**\n * Frame-wide inventory, grouped as one row per stable Plugin.\n * @returns Source-free metadata for every process-local Plugin.\n */" + }, + { + "kind": "method", + "name": "snapshot", + "signature": "snapshot(agent: Agent): DynamicCordisSnapshotRow[]", + "summary": "Read one Session's Host-rich state for inspection and result rendering.", + "jsDoc": "/**\n * Read one Session's Host-rich state for inspection and result rendering.\n * @param agent - Agent whose Session selects visible Plugins.\n * @returns Plugin versions, active runs, Host fibers, and render failures.\n */" + }, + { + "kind": "method", + "name": "reference", + "signature": "reference(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisReference | undefined", + "summary": "Read source-free context for an explicit `@pluginId` user gesture.", + "jsDoc": "/**\n * Read source-free context for an explicit `@pluginId` user gesture.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity referenced by the user.\n * @returns The preferred modification base, or undefined when unavailable.\n */" + }, + { + "kind": "method", + "name": "listPlugins", + "signature": "listPlugins(agent: Agent): DynamicCordisPluginInspection[]", + "summary": "List source-free Plugin summaries owned by one Session.", + "jsDoc": "/**\n * List source-free Plugin summaries owned by one Session.\n * @param agent - Agent whose Session selects visible Plugins.\n * @returns one summary per Plugin in creation order.\n */" + }, + { + "kind": "method", + "name": "inspectPlugin", + "signature": "inspectPlugin(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisPluginInspection", + "summary": "Inspect one Plugin without returning Package source.", + "jsDoc": "/**\n * Inspect one Plugin without returning Package source.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - stable Plugin identity.\n * @returns version pointers, latest run, and all Package summaries.\n */" + }, + { + "kind": "method", + "name": "inspectPackage", + "signature": "inspectPackage( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, ): DynamicCordisPackageInspection", + "summary": "Read one exact immutable Package and its Host and Client source.", + "jsDoc": "/**\n * Read one exact immutable Package and its Host and Client source.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity that owns the Package.\n * @param packageId - Exact immutable Package identity to inspect.\n * @returns Package metadata, source, and the Plugin's lifecycle pointers.\n */" + }, + { + "kind": "method", + "name": "reportRenderFailure", + "signature": "@Remote('reportRenderFailure') async reportRenderFailure( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure, ): Promise", + "summary": "Record a post-load render failure for the exact active run.", + "jsDoc": "/**\n * Record a post-load render failure for the exact active run.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity that rendered.\n * @param pluginRunId - Exact active run that produced the failure.\n * @param failure - Slot, message, and entry-retirement result.\n * @returns Null after recording or ignoring a stale report.\n */" + }, + { + "kind": "method", + "name": "reportClientGuardFailure", + "signature": "@Remote('reportClientGuardFailure') async reportClientGuardFailure( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails, ): Promise", + "summary": "Report a Client guard rejection that happened after the Package completed activation.", + "jsDoc": "/**\n * Report a Client guard rejection that happened after the Package completed activation.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity whose Client code was rejected.\n * @param pluginRunId - Exact active run that produced the rejection.\n * @param failure - Original guard message and stack.\n * @returns Null after reporting or ignoring a stale/startup failure.\n */" + }, + { + "kind": "method", + "name": "invoke", + "signature": "@Remote('invoke') async invoke( pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, method: string, args: JsonValue, ): Promise", + "summary": "Invoke an active Host method while rejecting stale Client runs.", + "jsDoc": "/**\n * Invoke an active Host method while rejecting stale Client runs.\n * @param pluginId - Stable Plugin identity that owns the method.\n * @param pluginRunId - Exact active run authorizing the call.\n * @param method - Registered Host handler name.\n * @param args - JSON argument delivered to the handler.\n * @returns The JSON result or a typed invocation failure.\n */" + } + ], + "types": [ + { + "name": "Agent", + "declaration": "export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly inbox: Inbox;\n readonly status: AgentStatus;\n readonly ctx: Context;\n cancel(cause: AgentCancelCause, options?: CancelOptions): void;\n whenIdle(): Promise;\n runMaintenance(task: (signal: AbortSignal) => Promise): Promise;\n send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;\n followup(message: UserMessage): void;\n steer(message: UserMessage): void;\n inject(message: UserMessage): void;\n}" + }, + { + "name": "AgentCancelCause", + "declaration": "export type AgentCancelCause = { readonly kind: 'user'; } | { readonly kind: 'parent'; } | { readonly kind: 'hook'; readonly reason: string; } | { readonly kind: 'disposed'; };" + }, + { + "name": "AgentOptions", + "declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n maxTokens?: number;\n}" + }, + { + "name": "AgentStatus", + "declaration": "export type AgentStatus = 'idle' | 'running';" + }, + { + "name": "ApprovalOutcome", + "declaration": "export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';" + }, + { + "name": "ApprovalPolicy", + "declaration": "export type ApprovalPolicy = 'ask' | 'never';" + }, + { + "name": "ApprovalRequestId", + "declaration": "export type ApprovalRequestId = Branded<'ApprovalRequestId'>;" + }, + { + "name": "ApprovalRequestId", + "declaration": "export type ApprovalRequestId = Branded<'ApprovalRequestId'>;" + }, + { + "name": "AssistantMessage", + "declaration": "export interface AssistantMessage extends Message {\n readonly role: 'assistant';\n readonly source: ModelMessageSource;\n}" + }, + { + "name": "AssistantProvenance", + "declaration": "export interface AssistantProvenance {\n provider: string;\n model: string;\n replayState?: unknown;\n}" + }, + { + "name": "AttachmentId", + "declaration": "export type AttachmentId = Branded<'AttachmentId'>;" + }, + { + "name": "Branded", + "declaration": "export type Branded = string & { readonly [BRAND]: B; };" + }, + { + "name": "CallId", + "declaration": "export type CallId = Branded<'CallId'>;" + }, + { + "name": "CancelOptions", + "declaration": "export interface CancelOptions {\n keepInbox?: boolean | undefined;\n}" + }, + { + "name": "CodeDispatchEventData", + "declaration": "export interface CodeDispatchEventData extends CodeDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}" + }, + { + "name": "CodeDispatchStartEventData", + "declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}" + }, + { + "name": "CommandId", + "declaration": "export type CommandId = Branded<'CommandId'>;" + }, + { + "name": "CommandSource", + "declaration": "export type CommandSource = CommandSourceMap[keyof CommandSourceMap];" + }, + { + "name": "CommandSourceMap", + "declaration": "export interface CommandSourceMap {\n user: { kind: 'user'; };\n}" + }, + { + "name": "ContentBlock", + "declaration": "export type ContentBlock = ContentBlockMap[ContentBlockType];" + }, + { + "name": "ContentBlockMap", + "declaration": "export interface ContentBlockMap {\n text: TextBlock;\n reasoning: ReasoningBlock;\n image: ImageBlock;\n 'tool-call': ToolCallBlock;\n 'tool-result': ToolResultBlock;\n}" + }, + { + "name": "ContentBlockType", + "declaration": "export type ContentBlockType = keyof ContentBlockMap;" + }, + { + "name": "ContextFormed", + "declaration": "export type ContextFormed = { readonly form?: never; } | { readonly form: 'instructions'; } | { readonly form: 'catalog'; } | { readonly form: 'snapshot'; readonly sections: readonly ContextSnapshotSection[]; } | { readonly form: 'notice'; readonly summary: string; } | { readonly form: 'relay'; } | { readonly form: 'recall'; };" + }, + { + "name": "ContextSnapshotSection", + "declaration": "export interface ContextSnapshotSection {\n readonly name: string;\n readonly text: string;\n}" + }, + { + "name": "CordisDynamicPackageId", + "declaration": "export type CordisDynamicPackageId = Branded<'CordisDynamicPackageId'>;" + }, + { + "name": "CordisDynamicPluginId", + "declaration": "export type CordisDynamicPluginId = Branded<'CordisDynamicPluginId'>;" + }, + { + "name": "CordisDynamicPluginRunId", + "declaration": "export type CordisDynamicPluginRunId = Branded<'CordisDynamicPluginRunId'>;" + }, + { + "name": "CordisDynamicRunMode", + "declaration": "export type CordisDynamicRunMode = 'run' | 'update';" + }, + { + "name": "CordisErrorDetails", + "declaration": "export interface CordisErrorDetails {\n message: string;\n stack?: string;\n}" + }, + { + "name": "CordisHalfState", + "declaration": "export interface CordisHalfState {\n status: 'absent' | 'pending' | 'stopped' | 'running' | 'waiting' | 'failed';\n waitingFor: readonly string[];\n error?: string;\n}" + }, + { + "name": "CordisInspectMethodManifest", + "declaration": "export interface CordisInspectMethodManifest {\n name: string;\n description: string;\n inputSchema: JsonValue;\n outputSchema: JsonValue;\n}" + }, + { + "name": "CordisInspectProviderManifest", + "declaration": "export interface CordisInspectProviderManifest {\n id: string;\n description: string;\n methods: readonly CordisInspectMethodManifest[];\n}" + }, + { + "name": "CordisInspectQueryResolution", + "declaration": "export type CordisInspectQueryResolution = { ok: true; data: JsonValue; } | { ok: false; reason: 'provider-missing' | 'method-missing' | 'invalid-input' | 'provider-error' | 'cancelled'; message: string; };" + }, + { + "name": "CordisInspectRequestId", + "declaration": "export type CordisInspectRequestId = Branded<'CordisInspectRequestId'>;" + }, + { + "name": "CordisInspectResolveAck", + "declaration": "export interface CordisInspectResolveAck {\n accepted: boolean;\n}" + }, + { + "name": "CordisRunDiagnostic", + "declaration": "export interface CordisRunDiagnostic {\n phase: 'approval' | 'host-load' | 'host-apply' | 'client-load' | 'client-apply' | 'client-render';\n message: string;\n stack?: string;\n pluginId: CordisDynamicPluginId;\n packageId: CordisDynamicPackageId;\n pluginRunId: CordisDynamicPluginRunId;\n}" + }, + { + "name": "CordisRunStatus", + "declaration": "export type CordisRunStatus = 'awaiting-approval' | 'starting-host' | 'client-pending' | 'running' | 'waiting' | 'rejected' | 'failed' | 'cancelled' | 'stopped';" + }, + { + "name": "DynamicCordisClientSource", + "declaration": "export interface DynamicCordisClientSource {\n code: string;\n name: string;\n pluginId: CordisDynamicPluginId;\n packageId: CordisDynamicPackageId;\n pluginRunId: CordisDynamicPluginRunId;\n}" + }, + { + "name": "DynamicCordisDefineReceipt", + "declaration": "export interface DynamicCordisDefineReceipt {\n pluginId: CordisDynamicPluginId;\n packageId: CordisDynamicPackageId;\n name: string;\n purpose: string;\n hasHostHalf: boolean;\n hasClientHalf: boolean;\n}" + }, + { + "name": "DynamicCordisDefineRequest", + "declaration": "export interface DynamicCordisDefineRequest {\n sessionId: SessionId;\n plugin: { kind: 'new'; idPrefix: string; } | { kind: 'existing'; pluginId: CordisDynamicPluginId; };\n name: string;\n purpose: string;\n code: { host?: string; client?: string; };\n}" + }, + { + "name": "DynamicCordisHostHalfResult", + "declaration": "export type DynamicCordisHostHalfResult = { ok: true; pluginId: CordisDynamicPluginId; packageId: CordisDynamicPackageId; pluginRunId: CordisDynamicPluginRunId; waitingFor: readonly string[]; startedHere: boolean; } | ({ ok: false; } & CordisErrorDetails);" + }, + { + "name": "DynamicCordisInventoryPackage", + "declaration": "export interface DynamicCordisInventoryPackage {\n packageId: CordisDynamicPackageId;\n name: string;\n purpose: string;\n hasHostHalf: boolean;\n hasClientHalf: boolean;\n}" + }, + { + "name": "DynamicCordisInventoryRow", + "declaration": "export interface DynamicCordisInventoryRow {\n pluginId: CordisDynamicPluginId;\n agentId: SessionId;\n packages: readonly DynamicCordisInventoryPackage[];\n currentPackageId?: CordisDynamicPackageId;\n nextPackageId?: CordisDynamicPackageId;\n activeRun?: { pluginRunId: CordisDynamicPluginRunId; packageId: CordisDynamicPackageId; };\n latestRun?: DynamicCordisRunAttempt;\n}" + }, + { + "name": "DynamicCordisInvokeResult", + "declaration": "export type DynamicCordisInvokeResult = { ok: true; value: JsonValue; } | ({ ok: false; code: 'plugin-not-running' | 'stale-run' | 'method-not-found' | 'handler-error'; } & CordisErrorDetails);" + }, + { + "name": "DynamicCordisPackageInspection", + "declaration": "export interface DynamicCordisPackageInspection extends DynamicCordisReference {\n code: { host?: string; client?: string; };\n}" + }, + { + "name": "DynamicCordisPluginInspection", + "declaration": "export interface DynamicCordisPluginInspection extends DynamicCordisReference {\n packages: Array<{ packageId: CordisDynamicPackageId; name: string; purpose: string; hasHostHalf: boolean; hasClientHalf: boolean; }>;\n}" + }, + { + "name": "DynamicCordisReference", + "declaration": "export interface DynamicCordisReference {\n pluginId: CordisDynamicPluginId;\n packageId: CordisDynamicPackageId;\n name: string;\n purpose: string;\n currentPackageId?: CordisDynamicPackageId;\n nextPackageId?: CordisDynamicPackageId;\n activeRun?: { pluginRunId: CordisDynamicPluginRunId; packageId: CordisDynamicPackageId; };\n latestRun?: DynamicCordisRunAttempt;\n}" + }, + { + "name": "DynamicCordisRenderFailure", + "declaration": "export interface DynamicCordisRenderFailure {\n slot: string;\n message: string;\n stack?: string;\n abdicated: boolean;\n}" + }, + { + "name": "DynamicCordisResolveAck", + "declaration": "export interface DynamicCordisResolveAck {\n accepted: boolean;\n}" + }, + { + "name": "DynamicCordisRunAttempt", + "declaration": "export interface DynamicCordisRunAttempt {\n pluginRunId: CordisDynamicPluginRunId;\n packageId: CordisDynamicPackageId;\n mode: CordisDynamicRunMode;\n status: CordisRunStatus;\n approvalRequestId?: ApprovalRequestId;\n requiresApproval?: boolean;\n host: CordisHalfState;\n client: CordisHalfState;\n error?: CordisRunDiagnostic;\n}" + }, + { + "name": "DynamicCordisRunResolution", + "declaration": "export type DynamicCordisRunResolution = { ok: true; pluginRunId: CordisDynamicPluginRunId; waitingFor?: readonly string[]; } | { ok: false; reason: 'rejected' | 'host-half-failed' | 'client-half-failed'; pluginRunId?: CordisDynamicPluginRunId; startedHere?: boolean; message?: string; stack?: string; };" + }, + { + "name": "DynamicCordisRunResponse", + "declaration": "export type DynamicCordisRunResponse = { ok: true; status: 'awaiting-approval' | 'starting' | 'running'; pluginId: CordisDynamicPluginId; packageId: CordisDynamicPackageId; pluginRunId: CordisDynamicPluginRunId; waitingFor: readonly string[]; clientWaitingFor?: readonly string[]; currentPackageId?: CordisDynamicPackageId; nextPackageId?: CordisDynamicPackageId; mode: CordisDynamicRunMode; } | { ok: false; reason: 'plugin-missing' | 'package-missing' | 'invalid-mode' | 'transition-in-flight' | 'host-half-failed' | 'client-half-failed' | 'rejected' | 'cancelled' | 'not-running'; message: string; stack?: string; };" + }, + { + "name": "DynamicCordisSnapshotRow", + "declaration": "export interface DynamicCordisSnapshotRow {\n pluginId: CordisDynamicPluginId;\n currentPackageId?: CordisDynamicPackageId;\n nextPackageId?: CordisDynamicPackageId;\n packages: Array<{ packageId: CordisDynamicPackageId; name: string; purpose: string; hasHostHalf: boolean; hasClientHalf: boolean; }>;\n activeRun?: { pluginRunId: CordisDynamicPluginRunId; packageId: CordisDynamicPackageId; fiber?: Fiber; handlers: string[]; renderFailure?: DynamicCordisRenderFailure; };\n latestRun?: DynamicCordisRunAttempt;\n}" + }, + { + "name": "DynamicCordisStopResponse", + "declaration": "export type DynamicCordisStopResponse = { ok: true; } | { ok: false; reason: 'plugin-missing' | 'not-running'; message: string; };" + }, + { + "name": "DynamicCordisUndefineReceipt", + "declaration": "export type DynamicCordisUndefineReceipt = { ok: true; wasRunning: boolean; } | { ok: false; reason: 'plugin-missing'; message: string; };" + }, + { + "name": "EpochHeader", + "declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n system?: string;\n tools?: ToolSchema[];\n}" + }, + { + "name": "FinishReason", + "declaration": "export type FinishReason = FinishReasonMap[keyof FinishReasonMap];" + }, + { + "name": "FinishReasonMap", + "declaration": "export interface FinishReasonMap {\n stop: { kind: 'stop'; };\n 'tool-calls': { kind: 'tool-calls'; };\n 'max-tokens': { kind: 'max-tokens'; };\n aborted: { kind: 'aborted'; failure: LlmFailure; };\n error: { kind: 'error'; failure: LlmFailure; };\n}" + }, + { + "name": "GoalBlockReason", + "declaration": "export interface GoalBlockReason {\n readonly code: string;\n readonly message: string;\n}" + }, + { + "name": "GoalChangeMeta", + "declaration": "export type GoalChangeMeta = GoalSnapshotChangeMeta | GoalClearChangeMeta;" + }, + { + "name": "GoalClearChangeMeta", + "declaration": "export interface GoalClearChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: 'clear';\n readonly cleared: GoalRef;\n readonly clearedAt: number;\n}" + }, + { + "name": "GoalId", + "declaration": "export type GoalId = Branded<'GoalId'>;" + }, + { + "name": "GoalMessageSource", + "declaration": "export interface GoalMessageSource {\n readonly kind: 'goal';\n readonly goalId: GoalId;\n readonly revision: number;\n readonly round: number;\n}" + }, + { + "name": "GoalOperation", + "declaration": "export type GoalOperation = 'create' | 'edit' | 'pause' | 'resume' | 'complete' | 'block' | 'clear';" + }, + { + "name": "GoalPhase", + "declaration": "export type GoalPhase = 'active' | 'paused' | 'blocked' | 'complete';" + }, + { + "name": "GoalRef", + "declaration": "export interface GoalRef {\n readonly id: GoalId;\n readonly revision: number;\n}" + }, + { + "name": "GoalSnapshot", + "declaration": "export interface GoalSnapshot extends GoalRef {\n readonly objective: string;\n readonly phase: GoalPhase;\n readonly blockedReason?: GoalBlockReason;\n readonly maxGoalRounds: number;\n}" + }, + { + "name": "GoalSnapshotChangeMeta", + "declaration": "export interface GoalSnapshotChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: Exclude;\n readonly goal: GoalSnapshot;\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n}" + }, + { + "name": "ImageAttachmentRef", + "declaration": "export interface ImageAttachmentRef {\n attachmentId: AttachmentId;\n mediaType: ImageMediaType;\n bytes: number;\n width: number;\n height: number;\n name?: string;\n}" + }, + { + "name": "ImageBlock", + "declaration": "export interface ImageBlock {\n type: 'image';\n attachment: ImageAttachmentRef;\n}" + }, + { + "name": "ImageMediaType", + "declaration": "export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';" + }, + { + "name": "Inbox", + "declaration": "export class Inbox {\n get nextTurn(): readonly UserMessage[];\n get nextStep(): readonly UserMessage[];\n get hasPending(): boolean;\n clear(): void;\n claim(target: InboxTarget, turn: number): UserMessage[];\n append(target: InboxTarget, message: UserMessage): void;\n prepend(target: InboxTarget, message: UserMessage): void;\n replace(messageId: MessageId, newMessage: UserMessage): boolean;\n remove(messageId: MessageId): boolean;\n splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[];\n}" + }, + { + "name": "InboxTarget", + "declaration": "export type InboxTarget = 'next-turn' | 'next-step';" + }, + { + "name": "JsonValue", + "declaration": "export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue; };" + }, + { + "name": "LlmCallConfig", + "declaration": "export interface LlmCallConfig {\n provider: string;\n model: string;\n reasoningEffort?: ReasoningEffortId;\n temperature?: number;\n maxTokens?: number;\n stop?: string[];\n}" + }, + { + "name": "LlmCallConfigAdapterDefaults", + "declaration": "export interface LlmCallConfigAdapterDefaults {\n reasoningEffort?: true;\n maxTokens?: true;\n}" + }, + { + "name": "LlmFailure", + "declaration": "export interface LlmFailure {\n readonly message: string;\n readonly code: string;\n readonly status?: number;\n readonly providerRetryAfterMs?: number;\n readonly requestId?: ProviderRequestId;\n}" + }, + { + "name": "Message", + "declaration": "export interface Message {\n readonly id: MessageId;\n readonly role: 'system' | 'user' | 'assistant';\n readonly content: ContentBlock[];\n readonly source: MessageSource;\n}" + }, + { + "name": "MessageId", + "declaration": "export type MessageId = Branded<'MessageId'>;" + }, + { + "name": "MessageSource", + "declaration": "export type MessageSource = MessageSourceMap[keyof MessageSourceMap];" + }, + { + "name": "MessageSourceMap", + "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n goal: GoalMessageSource;\n}" + }, + { + "name": "ModelMessageSource", + "declaration": "export interface ModelMessageSource extends AssistantProvenance {\n kind: 'model';\n}" + }, + { + "name": "ProviderRequestId", + "declaration": "export type ProviderRequestId = Branded<'ProviderRequestId'>;" + }, + { + "name": "ReasoningBlock", + "declaration": "export interface ReasoningBlock {\n type: 'reasoning';\n text: string;\n}" + }, + { + "name": "ReasoningEffortId", + "declaration": "export type ReasoningEffortId = Branded<'ReasoningEffortId'>;" + }, + { + "name": "RequestContext", + "declaration": "export interface RequestContext {\n provider: string;\n model: string;\n contextWindow?: number;\n}" + }, + { + "name": "RequestHeaderReason", + "declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change';" + }, + { + "name": "Session", + "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n get id(): SessionId;\n readonly firstLiveSeq: number;\n get events(): readonly SessionEvent[];\n get seq(): number;\n append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}" + }, + { + "name": "SessionEvent", + "declaration": "export type SessionEvent = { [K in SessionEventType]: { type: K; seq: number; time: number; data: SessionEventMap[K]; ignorable?: true; } & (K extends SurfaceEventType ? { sourceEventSeqs?: number[]; surfaceOp?: SurfaceOp; } : object) }[T];" + }, + { + "name": "SessionEventMap", + "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: number; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n 'goal/change': GoalChangeMeta;\n}" + }, + { + "name": "SessionEventType", + "declaration": "export type SessionEventType = keyof SessionEventMap;" + }, + { + "name": "SessionHeader", + "declaration": "export interface SessionHeader {\n readonly version: number;\n readonly id: SessionId;\n readonly createdAt: number;\n readonly cwd?: string;\n readonly parentSession?: SessionId;\n readonly seedLength?: number;\n readonly origin?: 'subagent';\n readonly delegationDepth?: number;\n readonly agentPreset?: string;\n}" + }, + { + "name": "SessionId", + "declaration": "export type SessionId = Branded<'SessionId'>;" + }, + { + "name": "SessionSurface", + "declaration": "export interface SessionSurface {\n readonly nodes: readonly number[];\n readonly replaceGeneration: number;\n}" + }, + { + "name": "StreamChunk", + "declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: unknown; };" + }, + { + "name": "SurfaceEventType", + "declaration": "export type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result';" + }, + { + "name": "SurfaceIntent", + "declaration": "export interface SurfaceIntent {\n surfaceOp: SurfaceOp;\n sourceEventSeqs?: number[];\n}" + }, + { + "name": "SurfaceOp", + "declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: number; end: number; };" + }, + { + "name": "TextBlock", + "declaration": "export interface TextBlock {\n type: 'text';\n text: string;\n}" + }, + { + "name": "TodoItem", + "declaration": "export interface TodoItem {\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n}" + }, + { + "name": "TokenUsage", + "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}" + }, + { + "name": "ToolCallBlock", + "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: CallId;\n name: string;\n arguments: string;\n}" + }, + { + "name": "ToolMessageSource", + "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: CallId;\n}" + }, + { + "name": "ToolResultBlock", + "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: CallId;\n content: ContentBlock[];\n isError?: boolean;\n}" + }, + { + "name": "ToolResultMessage", + "declaration": "export interface ToolResultMessage extends Message {\n readonly role: 'user';\n readonly content: [ToolResultBlock];\n readonly source: ToolMessageSource;\n}" + }, + { + "name": "ToolSchema", + "declaration": "export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n}" + }, + { + "name": "TurnEndCancelCause", + "declaration": "export type TurnEndCancelCause = AgentCancelCause | { readonly kind: 'legacy'; };" + }, + { + "name": "TurnEndReason", + "declaration": "export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap];" + }, + { + "name": "TurnEndReasonMap", + "declaration": "export interface TurnEndReasonMap {\n completed: { kind: 'completed'; };\n aborted: { kind: 'aborted'; reason: TurnEndCancelCause; };\n blocked: { kind: 'blocked'; };\n error: { kind: 'error'; error: LlmFailure; };\n 'max-tokens': { kind: 'max-tokens'; };\n interrupted: { kind: 'interrupted'; };\n}" + }, + { + "name": "UserMessage", + "declaration": "export interface UserMessage extends Message {\n readonly role: 'user';\n}" + } + ] + } + ], + "events": [ + { + "description": "One exact Plugin/Package activation is now live in the Host.", + "summary": "One exact Plugin/Package activation is now live in the Host.", + "tags": [ + { + "name": "param", + "argument": "pkg", + "comment": "- stable plugin, immutable package, run identity, and label.", + "text": "@param pkg - stable plugin, immutable package, run identity, and label.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * One exact Plugin/Package activation is now live in the Host.\n * @param pkg - stable plugin, immutable package, run identity, and label.\n * @mode emit\n */", + "name": "cordis/dynamic-package", + "mode": "emit", + "signature": "'cordis/dynamic-package'(pkg: DynamicCordisPackage): void" + }, + { + "description": "One exact activation was withdrawn.", + "summary": "One exact activation was withdrawn.", + "tags": [ + { + "name": "param", + "argument": "retracted", + "comment": "- plugin, package, and run identity.", + "text": "@param retracted - plugin, package, and run identity.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * One exact activation was withdrawn.\n * @param retracted - plugin, package, and run identity.\n * @mode emit\n */", + "name": "cordis/dynamic-retract", + "mode": "emit", + "signature": "'cordis/dynamic-retract'(retracted: DynamicCordisRetracted): void" + }, + { + "description": "Request a live read-only query from the Client inspect registry.", + "summary": "Request a live read-only query from the Client inspect registry.", + "tags": [ + { + "name": "param", + "argument": "request", + "comment": "- correlation, Session, provider, method, and JSON input.", + "text": "@param request - correlation, Session, provider, method, and JSON input.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * Request a live read-only query from the Client inspect registry.\n * @param request - correlation, Session, provider, method, and JSON input.\n * @mode emit\n */", + "name": "cordis/inspect-query", + "mode": "emit", + "signature": "'cordis/inspect-query'(request: CordisInspectQueryRequest): void" + }, + { + "description": "Notify every Client that an inspect query has settled or been cancelled.", + "summary": "Notify every Client that an inspect query has settled or been cancelled.", + "tags": [ + { + "name": "param", + "argument": "resolved", + "comment": "- exact query identity that is no longer answerable.", + "text": "@param resolved - exact query identity that is no longer answerable.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * Notify every Client that an inspect query has settled or been cancelled.\n * @param resolved - exact query identity that is no longer answerable.\n * @mode emit\n */", + "name": "cordis/inspect-query-resolved", + "mode": "emit", + "signature": "'cordis/inspect-query-resolved'(resolved: CordisInspectQueryResolved): void" + }, + { + "description": "A Client-bearing activation needs a browser page, and may require a user decision.", + "summary": "A Client-bearing activation needs a browser page, and may require a user decision.", + "tags": [ + { + "name": "param", + "argument": "request", + "comment": "- correlation identity, owner, target version, mode, and approval requirement.", + "text": "@param request - correlation identity, owner, target version, mode, and approval requirement.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * A Client-bearing activation needs a browser page, and may require a user decision.\n * @param request - correlation identity, owner, target version, mode, and approval requirement.\n * @mode emit\n */", + "name": "cordis/request-run", + "mode": "emit", + "signature": "'cordis/request-run'(request: DynamicCordisRunRequest): void" + }, + { + "description": "A pending Client activation request left the answerable state.", + "summary": "A pending Client activation request left the answerable state.", + "tags": [ + { + "name": "param", + "argument": "resolved", + "comment": "- request identity and outcome.", + "text": "@param resolved - request identity and outcome.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * A pending Client activation request left the answerable state.\n * @param resolved - request identity and outcome.\n * @mode emit\n */", + "name": "cordis/request-run-resolved", + "mode": "emit", + "signature": "'cordis/request-run-resolved'(resolved: DynamicCordisRequestResolved): void" + } + ], + "objects": [] + }, +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.d.ts new file mode 100644 index 0000000..bc67b40 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.d.ts @@ -0,0 +1,55 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import type { + RemoteResult, + TypertRemoteContribution, +} from '@deepseek-ai/dsh-typert-protocol' +import type { ApprovalRequestId, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisDynamicRunMode, CordisErrorDetails, CordisInspectProviderManifest, CordisInspectQueryResolution, CordisInspectRequestId, CordisInspectResolveAck, DynamicCordisClientSource, DynamicCordisHostHalfResult, DynamicCordisInventoryRow, DynamicCordisInvokeResult, DynamicCordisRenderFailure, DynamicCordisResolveAck, DynamicCordisRunResolution, DynamicCordisRunResponse, DynamicCordisStopResponse, DynamicCordisUndefineReceipt } from '@deepseek-ai/dsh-cordis-host-runner/types' +import type { JsonValue, SessionId } from '@deepseek-ai/dsh-session/types' + +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteNamespace$64796e616d6963436f7264697352756e6e6572 { + getClientCode: (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId) => Promise> + inventory: () => Promise> + invoke: (pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, method: string, args: JsonValue) => Promise> + reportClientGuardFailure: (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails) => Promise> + reportRenderFailure: (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure) => Promise> + resolveInspectQuery: (agentId: SessionId, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution) => Promise> + resolveRequestRun: (requestId: ApprovalRequestId, resolution: DynamicCordisRunResolution) => Promise> + runHostHalf: (agentId: SessionId, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean) => Promise> + settleUserRun: (agentId: SessionId, pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution) => Promise> + stopFromPanel: (agentId: SessionId, pluginId: CordisDynamicPluginId) => Promise> + syncInspectManifest: (providers: readonly CordisInspectProviderManifest[]) => Promise> + undefineFromPanel: (agentId: SessionId, pluginId: CordisDynamicPluginId) => Promise> + } + interface TypertRemoteMap { + 'dynamicCordisRunner/getClientCode': (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId) => Promise> + 'dynamicCordisRunner/inventory': () => Promise> + 'dynamicCordisRunner/invoke': (pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, method: string, args: JsonValue) => Promise> + 'dynamicCordisRunner/reportClientGuardFailure': (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails) => Promise> + 'dynamicCordisRunner/reportRenderFailure': (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure) => Promise> + 'dynamicCordisRunner/resolveInspectQuery': (agentId: SessionId, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution) => Promise> + 'dynamicCordisRunner/resolveRequestRun': (requestId: ApprovalRequestId, resolution: DynamicCordisRunResolution) => Promise> + 'dynamicCordisRunner/runHostHalf': (agentId: SessionId, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean) => Promise> + 'dynamicCordisRunner/settleUserRun': (agentId: SessionId, pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution) => Promise> + 'dynamicCordisRunner/stopFromPanel': (agentId: SessionId, pluginId: CordisDynamicPluginId) => Promise> + 'dynamicCordisRunner/syncInspectManifest': (providers: readonly CordisInspectProviderManifest[]) => Promise> + 'dynamicCordisRunner/undefineFromPanel': (agentId: SessionId, pluginId: CordisDynamicPluginId) => Promise> + } + interface TypertRemoteNamespaceMap { + 'dynamicCordisRunner': TypertRemoteNamespace$64796e616d6963436f7264697352756e6e6572 + } + interface TypertRemoteScopeMap { + 'agent:dynamicCordisRunner/getClientCode': (pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId) => Promise> + 'agent:dynamicCordisRunner/reportClientGuardFailure': (pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails) => Promise> + 'agent:dynamicCordisRunner/reportRenderFailure': (pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure) => Promise> + 'agent:dynamicCordisRunner/resolveInspectQuery': (requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution) => Promise> + 'agent:dynamicCordisRunner/runHostHalf': (pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean) => Promise> + 'agent:dynamicCordisRunner/settleUserRun': (pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution) => Promise> + 'agent:dynamicCordisRunner/stopFromPanel': (pluginId: CordisDynamicPluginId) => Promise> + 'agent:dynamicCordisRunner/undefineFromPanel': (pluginId: CordisDynamicPluginId) => Promise> + } +} + +export declare const TYPERT_REMOTE: TypertRemoteContribution +export default TYPERT_REMOTE +//# sourceMappingURL=typert.remote-client.d.ts.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.js new file mode 100644 index 0000000..278f622 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.js @@ -0,0 +1,769 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import { z } from 'zod' + +const JsonValueRemoteCodec$schema = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]) +const JsonValueRemoteCodec$schema2 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]) +const JsonValueRemoteCodec$schema3 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]) +const JsonValueRemoteCodec$schema4 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema4)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema4))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema = z.object({ + 'code': z.string(), + 'name': z.string(), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema = z.array(z.object({ + 'pluginId': z.intersection(z.string(), z.unknown()), + 'agentId': z.intersection(z.string(), z.unknown()), + 'packages': z.array(z.object({ + 'packageId': z.intersection(z.string(), z.unknown()), + 'name': z.string(), + 'purpose': z.string(), + 'hasHostHalf': z.boolean(), + 'hasClientHalf': z.boolean(), +})), + 'currentPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'nextPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'activeRun': z.object({ + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), +}).optional(), + 'latestRun': z.object({ + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'mode': z.union([z.literal("run"), z.literal("update")]), + 'status': z.union([z.literal("rejected"), z.literal("awaiting-approval"), z.literal("running"), z.literal("cancelled"), z.literal("starting-host"), z.literal("client-pending"), z.literal("waiting"), z.literal("failed"), z.literal("stopped")]), + 'approvalRequestId': z.intersection(z.string(), z.unknown()).optional(), + 'requiresApproval': z.boolean().optional(), + 'host': z.object({ + 'status': z.union([z.literal("running"), z.literal("waiting"), z.literal("failed"), z.literal("stopped"), z.literal("absent"), z.literal("pending")]), + 'waitingFor': z.array(z.string()), + 'error': z.string().optional(), +}), + 'client': z.object({ + 'status': z.union([z.literal("running"), z.literal("waiting"), z.literal("failed"), z.literal("stopped"), z.literal("absent"), z.literal("pending")]), + 'waitingFor': z.array(z.string()), + 'error': z.string().optional(), +}), + 'error': z.object({ + 'phase': z.union([z.literal("approval"), z.literal("host-load"), z.literal("host-apply"), z.literal("client-load"), z.literal("client-apply"), z.literal("client-render")]), + 'message': z.string(), + 'stack': z.string().optional(), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), +}).optional(), +}).optional(), +})) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema = z.string() +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'value': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema4)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema4))]), +}), z.intersection(z.object({ + 'ok': z.literal(false), + 'code': z.union([z.literal("plugin-not-running"), z.literal("stale-run"), z.literal("method-not-found"), z.literal("handler-error")]), +}), z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema = z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema = z.object({ + 'slot': z.string(), + 'message': z.string(), + 'stack': z.string().optional(), + 'abdicated': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema = z.union([z.object({ + 'ok': z.literal(true), + 'data': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("cancelled"), z.literal("provider-missing"), z.literal("method-missing"), z.literal("invalid-input"), z.literal("provider-error")]), + 'message': z.string(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema = z.object({ + 'accepted': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()).optional(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed")]), + 'pluginRunId': z.intersection(z.string(), z.unknown()).optional(), + 'startedHere': z.boolean().optional(), + 'message': z.string().optional(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema = z.object({ + 'accepted': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema = z.union([z.literal("run"), z.literal("update")]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema = z.union([z.literal(null), z.intersection(z.string(), z.unknown())]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema = z.boolean() +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()), + 'startedHere': z.boolean(), +}), z.intersection(z.object({ + 'ok': z.literal(false), +}), z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()).optional(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed")]), + 'pluginRunId': z.intersection(z.string(), z.unknown()).optional(), + 'startedHere': z.boolean().optional(), + 'message': z.string().optional(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'status': z.union([z.literal("awaiting-approval"), z.literal("starting"), z.literal("running")]), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()), + 'clientWaitingFor': z.array(z.string()).optional(), + 'currentPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'nextPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'mode': z.union([z.literal("run"), z.literal("update")]), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("plugin-missing"), z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed"), z.literal("package-missing"), z.literal("invalid-mode"), z.literal("transition-in-flight"), z.literal("cancelled"), z.literal("not-running")]), + 'message': z.string(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema = z.union([z.object({ + 'ok': z.literal(true), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("plugin-missing"), z.literal("not-running")]), + 'message': z.string(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema = z.array(z.object({ + 'id': z.string(), + 'description': z.string(), + 'methods': z.array(z.object({ + 'name': z.string(), + 'description': z.string(), + 'inputSchema': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]), + 'outputSchema': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]), +})), +})) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'wasRunning': z.boolean(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.literal("plugin-missing"), + 'message': z.string(), +})]) + +export const TYPERT_REMOTE = { + package: '@deepseek-ai/dsh-cordis-host-runner', + descriptors: [ + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/getClientCode', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'getClientCode', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisClientSource', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":384,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'inventory', + invocation: { kind: 'direct' }, + parameters: [ + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":525,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'invoke', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema, + }, + }, + { + name: 'method', + wire: 'method', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke:method', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema, + }, + }, + { + name: 'args', + wire: 'args', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#JsonValue', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisInvokeResult', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":741,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'reportClientGuardFailure', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema, + }, + }, + { + name: 'failure', + wire: 'failure', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisErrorDetails', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":718,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'reportRenderFailure', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema, + }, + }, + { + name: 'failure', + wire: 'failure', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRenderFailure', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":684,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveInspectQuery', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'resolveInspectQuery', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema, + }, + }, + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectRequestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectQueryResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectResolveAck', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":511,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveRequestRun', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'resolveRequestRun', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#ApprovalRequestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisResolveAck', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":413,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'runHostHalf', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema, + }, + }, + { + name: 'packageId', + wire: 'packageId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPackageId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema, + }, + }, + { + name: 'mode', + wire: 'mode', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicRunMode', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema, + }, + }, + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:requestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema, + }, + }, + { + name: 'approveFutureVersions', + wire: 'approveFutureVersions', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:approveFutureVersions', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisHostHalfResult', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":325,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/settleUserRun', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'settleUserRun', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResponse', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":438,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/stopFromPanel', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'stopFromPanel', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisStopResponse', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":480,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'syncInspectManifest', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'providers', + wire: 'providers', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:providers', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":498,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/undefineFromPanel', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'undefineFromPanel', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisUndefineReceipt', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":227,"column":9}, + }, + ], +} + +export default TYPERT_REMOTE diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.d.ts new file mode 100644 index 0000000..30a4157 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.d.ts @@ -0,0 +1,71 @@ +/** + * The registration boundary between a sandboxed host half and the real runtime: ParameterSchemaSpec + * normalization + validation with teaching errors, the marker-guarded `harness.defineTool` / + * `harness.registerTool` pair, the `harness.handle` invoke-handler normalizer, the SANDBOX CONTEXT + * FAÇADE a running plugin's `apply` receives in place of the real `ctx`, and the plugin-shape + * helpers the run lifecycle narrows sandbox return values with. The façade is a whitelist of + * lifecycle-safe verbs and declared services; framework internals and context-valued service + * returns are denied. + * + * VM-realm schemas and canonical values are rebuilt as host objects, while rendered content and + * presentation metadata are shape-checked before entering the registry. Common JSON-Schema spellings are normalized when they + * have one meaning; invalid vocabulary fails during registration with a teaching error. + * @module @deepseek-ai/dsh-cordis-host-runner/guard + */ +import { Context } from '@deepseek-ai/cordis'; +import type { Plugin } from '@deepseek-ai/cordis'; +import type { ToolDefinition } from '@deepseek-ai/dsh-tools'; +/** + * The `harness.defineTool` handed into the sandbox: the real DSL, with `parameters` normalized + * into a fresh host-realm ParameterSchemaSpec (raw object wrappers unwrapped, + * required arrays mapped, and explicit DSL object openness enforced) and the tool's `execute` return normalized into the host realm + * via a JSON round-trip. Non-JSON or wrong-shape output fails that call instead of poisoning + * the session log. + * @param options - the standard `defineTool` options; `parameters` may be the ParameterSchemaSpec DSL or a JSON-Schema-style wrapper. + * @returns the marker-tagged definition `harness.registerTool` (and the guarded `ctx.tools.register`) accepts. + */ +export declare function sandboxDefineTool(options: unknown): ToolDefinition; +/** + * Normalize one `harness.handle` registration at the sandbox boundary: the + * method name must be a non-empty string and the handler a function whose + * result is host-materialized through the same cross-realm JSON clone as tool + * `execute` returns (a VM-realm object would otherwise escape the wire's + * plain-object contract). + * @param method - handler name the package's browser half calls through `host.call`. + * @param fn - sandbox handler receiving the wire-decoded JSON arguments. + * @returns the validated name and the clone-wrapped handler. + */ +export declare function normalizeHandler(method: unknown, fn: unknown): { + method: string; + handler: (args: unknown) => Promise; +}; +/** + * The `harness.registerTool` handed into the sandbox: registers a + * marker-verified dynamic tool on the given context's registry. + * @param ctx - the (guarded) context whose `tools` service receives the tool. + * @param tool - a definition produced by {@link sandboxDefineTool}; anything else is rejected. + * @returns the registry disposer for the registration. + */ +export declare function sandboxRegisterTool(ctx: Context, tool: unknown): () => void; +/** + * Narrow an arbitrary sandbox return value to a runnable cordis plugin: a + * function, or an object with an `apply` function. (A bare function passes the + * first arm, so the object arm never sees `Function.prototype.apply`.) + * @param value - whatever the host half returned. + * @returns whether the value can be started via `ctx.plugin`. + */ +export declare function isPlugin(value: unknown): value is Plugin; +/** + * Wrap a plugin so `apply` receives the sandbox context while preserving injection metadata. + * @param plugin - the plugin the host half returned. + * @param reportFailure - reports a guard rejection to the owning Agent. + * @returns an equivalent plugin whose `apply` sees the sandbox context façade. + */ +export declare function guardedPlugin(plugin: Plugin, reportFailure: (error: Error) => void): Plugin; +/** + * Display name for a running plugin: its `name` property, else anonymous. + * @param plugin - the plugin the host half returned. + * @returns the human-readable name used in run results and inspect output. + */ +export declare function pluginName(plugin: Plugin): string; +//# sourceMappingURL=guard.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.js new file mode 100644 index 0000000..aa5d4f4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.js @@ -0,0 +1,766 @@ +/** + * The registration boundary between a sandboxed host half and the real runtime: ParameterSchemaSpec + * normalization + validation with teaching errors, the marker-guarded `harness.defineTool` / + * `harness.registerTool` pair, the `harness.handle` invoke-handler normalizer, the SANDBOX CONTEXT + * FAÇADE a running plugin's `apply` receives in place of the real `ctx`, and the plugin-shape + * helpers the run lifecycle narrows sandbox return values with. The façade is a whitelist of + * lifecycle-safe verbs and declared services; framework internals and context-valued service + * returns are denied. + * + * VM-realm schemas and canonical values are rebuilt as host objects, while rendered content and + * presentation metadata are shape-checked before entering the registry. Common JSON-Schema spellings are normalized when they + * have one meaning; invalid vocabulary fails during registration with a teaching error. + * @module @deepseek-ai/dsh-cordis-host-runner/guard + */ +import { Context } from '@deepseek-ai/cordis'; +import { scopeOf } from '@deepseek-ai/dsh-scope'; +import { assertSupportedJsonSchema, defineTool } from '@deepseek-ai/dsh-tools'; +const DYNAMIC_TOOL = Symbol('cordis-host-runner.dynamic-tool'); +const SCHEMA_TYPES = new Set(['string', 'number', 'integer', 'boolean', 'null', 'object', 'array', 'json']); +const VALID_TYPES = '\'string\' | \'number\' | \'integer\' | \'boolean\' | \'null\' | \'object\' | \'array\' | \'json\''; +const ANNOTATION_KEYS = ['description', 'title', 'default', 'examples']; +function isPlainRecord(value) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) + return false; + const prototype = Object.getPrototypeOf(value); + return prototype === null + || typeof prototype === 'object' + && Object.getPrototypeOf(prototype) === null + && hasIntrinsicConstructor(prototype, 'Object'); +} +/* jscpd:ignore-start -- this VM boundary mirrors the session-owned realm-safe intrinsic test */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor'); + const constructor = descriptor?.value; + if (typeof constructor !== 'function') + return false; + try { + return constructor.name === name + && constructor.prototype === prototype + && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } + catch { + return false; + } +} +/** Whether an array uses one realm's intrinsic Array prototype rather than a subclass. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) + return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === 'object' + && objectPrototype !== null + && Object.getPrototypeOf(objectPrototype) === null + && hasIntrinsicConstructor(objectPrototype, 'Object'); +} +/* jscpd:ignore-end */ +/** Whether a schema list is a dense intrinsic array with no JSON-invisible decorations. */ +function isDensePlainArray(value) { + if (!Array.isArray(value) || !hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) { + return false; + } + for (let index = 0; index < value.length; index++) { + if (!Object.hasOwn(value, index)) + return false; + } + return true; +} +/** Reject schema records whose declarations would disappear from object enumeration. */ +function assertSchemaContainerKeys(value, path) { + if (Reflect.ownKeys(value).some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) { + throw new Error(`harness.defineTool ${path} must contain only own enumerable string keys`); + } +} +/** Materialize realm-foreign lossless JSON without allowing JSON.stringify coercions; `path` carries the caller's own error prefix. */ +function cloneJson(value, path) { + const ancestors = new Set(); + let root; + const assign = (destination, item) => { + if (destination.kind === 'root') { + root = item; + return; + } + if (destination.kind === 'array') { + destination.target[destination.index] = item; + return; + } + Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true, + }); + }; + const reject = (at) => { + // Naming the executable next step matters more than naming the rule: the + // usual cause is a handler that returns whatever its last call produced, + // and the fix is one keyword. + throw new Error(`${at} must be lossless JSON data (objects, arrays, strings, numbers, booleans, null) — ` + + 'not a class instance, function, Map/Set, Date, or undefined. Return a plain object built from the ' + + 'values you need, or `return null` when the caller needs no value back.'); + }; + const tasks = [{ kind: 'visit', value, path, destination: { kind: 'root' } }]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + ancestors.delete(task.source); + continue; + } + if (task.kind === 'array-item') { + if (!Object.hasOwn(task.source, task.index)) + reject(task.path); + tasks.push({ + kind: 'visit', + value: task.source[task.index], + path: `${task.path}[${task.index}]`, + destination: { kind: 'array', target: task.target, index: task.index }, + }); + continue; + } + const current = task.value; + if (current === null || typeof current === 'string' || typeof current === 'boolean') { + assign(task.destination, current); + continue; + } + if (typeof current === 'number') { + if (!Number.isFinite(current) || Object.is(current, -0)) + reject(task.path); + assign(task.destination, current); + continue; + } + if (typeof current !== 'object' || ancestors.has(current)) + reject(task.path); + if (Array.isArray(current)) { + if (!hasPlainArrayPrototype(current) || Reflect.ownKeys(current).length !== current.length + 1) + reject(task.path); + const output = []; + assign(task.destination, output); + ancestors.add(current); + tasks.push({ kind: 'leave', source: current }); + for (let index = current.length - 1; index >= 0; index--) { + tasks.push({ kind: 'array-item', source: current, index, path: task.path, target: output }); + } + continue; + } + if (!isPlainRecord(current)) + reject(task.path); + const record = current; + if (Reflect.ownKeys(record).some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(record, key))) { + reject(task.path); + } + const output = {}; + assign(task.destination, output); + ancestors.add(record); + tasks.push({ kind: 'leave', source: record }); + const entries = Object.entries(record); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) + continue; + tasks.push({ + kind: 'visit', + value: entry[1], + path: `${task.path}.${entry[0]}`, + destination: { kind: 'object', target: output, key: entry[0] }, + }); + } + } + return root; +} +/** Copy and realm-materialize the shared annotation vocabulary. */ +function copyAnnotations(value, output, path) { + if (Object.hasOwn(value, 'description')) + output.description = value.description; + if (Object.hasOwn(value, 'title')) + output.title = value.title; + if (Object.hasOwn(value, 'default')) + output.default = cloneJson(value.default, `harness.defineTool ${path}.default`); + if (Object.hasOwn(value, 'examples')) + output.examples = cloneJson(value.examples, `harness.defineTool ${path}.examples`); +} +/** Reject sandbox schema keys that the unified DSL would otherwise ignore. */ +function assertSchemaKeys(value, path, allowed) { + assertSchemaContainerKeys(value, path); + for (const key of Object.keys(value)) { + if (!allowed.includes(key)) + throw new Error(`harness.defineTool ${path}.${key} is not supported by the unified schema DSL`); + } +} +/** + * Normalize a sandbox-provided `parameters` value into a fresh host-realm + * ParameterSchemaSpec. A raw JSON-Schema object wrapper retains its open root + * default, while the direct DSL is already an implicit open property map. + */ +function normalizeParameterSchemaSpec(value, path = 'parameters') { + if (!isPlainRecord(value)) { + throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec object`); + } + if (value.type === 'object') { + assertSchemaKeys(value, path, ['type', 'properties', 'required', 'additionalProperties', ...ANNOTATION_KEYS]); + if (!isPlainRecord(value.properties)) { + throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`); + } + if (Object.hasOwn(value, 'additionalProperties') && value.additionalProperties !== true) { + throw new Error(`harness.defineTool ${path}.additionalProperties must be true or omitted because the implicit parameter root is open`); + } + if (Object.hasOwn(value, 'required') && value.required === undefined) { + throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`); + } + const required = normalizeRequiredNames(value.required, value.properties, `${path}.required`); + const rootAnnotations = {}; + copyAnnotations(value, rootAnnotations, path); + return { + spec: normalizePropertyMap(value.properties, path, required, true), + ...(Object.keys(rootAnnotations).length === 0 ? {} : { rootAnnotations }), + }; + } + return { spec: normalizePropertyMap(value, path, new Set(), false) }; +} +/** Validate raw required names and return their lookup set. */ +function normalizeRequiredNames(value, properties, path) { + if (value === undefined) + return new Set(); + if (!isDensePlainArray(value)) { + throw new Error(`harness.defineTool ${path} must be an array of declared property names`); + } + const names = new Set(); + for (let index = 0; index < value.length; index++) { + const name = value[index]; + if (typeof name !== 'string') { + throw new Error(`harness.defineTool ${path} must be an array of declared property names`); + } + names.add(name); + if (!Object.hasOwn(properties, name)) + throw new Error(`harness.defineTool ${path} names undeclared property ${JSON.stringify(name)}`); + } + return names; +} +/** Install one normalized node without `__proto__` assignment semantics. */ +function assignNormalizedValue(destination, value) { + if (destination.kind === 'property') { + Object.defineProperty(destination.target, destination.key, { + value, + enumerable: true, + configurable: true, + writable: true, + }); + } + else if (destination.kind === 'item') { + destination.target.items = value; + } + else { + destination.target[destination.index] = value; + } +} +/** Install one normalized property map at its root or containing object. */ +function assignNormalizedMap(destination, value) { + if (destination.kind === 'root') + destination.holder.value = value; + else + destination.target.properties = value; +} +/** Normalize one implicit property map and all descendants with explicit work frames. */ +function normalizePropertyMap(entries, path, requiredNames, raw) { + const holder = {}; + const ancestors = new Set(); + const tasks = [{ + kind: 'map', + entries, + path, + requiredNames, + raw, + destination: { kind: 'root', holder }, + }]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + ancestors.delete(task.value); + continue; + } + if (task.kind === 'map') { + if (ancestors.has(task.entries)) + throw new Error(`harness.defineTool ${task.path} is circular`); + assertSchemaContainerKeys(task.entries, task.path); + ancestors.add(task.entries); + const spec = {}; + assignNormalizedMap(task.destination, spec); + tasks.push({ kind: 'leave', value: task.entries }); + const mapEntries = Object.entries(task.entries); + for (let index = mapEntries.length - 1; index >= 0; index--) { + const entry = mapEntries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) + continue; + tasks.push({ + kind: 'value', + value: entry[1], + path: `${task.path}.${entry[0]}`, + forceRequired: task.requiredNames.has(entry[0]), + raw: task.raw, + parameterProperty: true, + destination: { kind: 'property', target: spec, key: entry[0] }, + }); + } + continue; + } + const { value, path } = task; + if (!isPlainRecord(value)) { + throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec property object`); + } + assertSchemaContainerKeys(value, path); + if (ancestors.has(value)) + throw new Error(`harness.defineTool ${path} is circular`); + ancestors.add(value); + const requiredKey = task.parameterProperty && !task.raw ? ['required'] : []; + if (task.parameterProperty && task.raw && Object.hasOwn(value, 'required') && value.type !== 'object') { + throw new Error(`harness.defineTool ${path}.required belongs to the containing raw object schema`); + } + if (task.parameterProperty && !task.raw && Object.hasOwn(value, 'required') && value.required !== true) { + throw new Error(`harness.defineTool ${path}.required must be true when present`); + } + const prop = {}; + assignNormalizedValue(task.destination, prop); + tasks.push({ kind: 'leave', value }); + if (task.forceRequired || value.required === true) + prop.required = true; + copyAnnotations(value, prop, path); + if (Object.hasOwn(value, 'oneOf')) { + assertSchemaKeys(value, path, ['oneOf', ...requiredKey, ...ANNOTATION_KEYS]); + if (!isDensePlainArray(value.oneOf) || value.oneOf.length < 2) { + throw new Error(`harness.defineTool ${path}.oneOf must contain at least two schemas`); + } + const oneOf = []; + prop.oneOf = oneOf; + for (let index = value.oneOf.length - 1; index >= 0; index--) { + tasks.push({ + kind: 'value', + value: value.oneOf[index], + path: `${path}.oneOf[${index}]`, + forceRequired: false, + raw: task.raw, + parameterProperty: false, + destination: { kind: 'one-of', target: oneOf, index }, + }); + } + continue; + } + if (task.raw && !Object.hasOwn(value, 'type')) { + assertSchemaKeys(value, path, ANNOTATION_KEYS); + prop.type = 'json'; + continue; + } + if (!SCHEMA_TYPES.has(value.type) || task.raw && value.type === 'json') { + throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES} (got ${JSON.stringify(value.type)})`); + } + const type = value.type; + prop.type = type; + switch (type) { + case 'object': { + assertSchemaKeys(value, path, ['type', 'properties', 'additionalProperties', ...requiredKey, ...(task.raw ? ['required'] : []), ...ANNOTATION_KEYS]); + if (!task.raw && (!Object.hasOwn(value, 'additionalProperties') || typeof value.additionalProperties !== 'boolean')) { + throw new Error(`harness.defineTool ${path}.additionalProperties must be explicitly true or false`); + } + if (task.raw && Object.hasOwn(value, 'additionalProperties') && typeof value.additionalProperties !== 'boolean') { + throw new Error(`harness.defineTool ${path}.additionalProperties must be a boolean`); + } + if (task.raw && Object.hasOwn(value, 'required') && value.required === undefined) { + throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`); + } + prop.additionalProperties = task.raw ? value.additionalProperties ?? true : value.additionalProperties; + if (Object.hasOwn(value, 'properties')) { + const properties = value.properties; + if (!isPlainRecord(properties)) + throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`); + const nestedRequired = task.raw + ? normalizeRequiredNames(value.required, properties, `${path}.required`) + : new Set(); + tasks.push({ + kind: 'map', + entries: properties, + path: `${path}.properties`, + requiredNames: nestedRequired, + raw: task.raw, + destination: { kind: 'properties', target: prop }, + }); + } + else if (task.raw && value.required !== undefined) { + normalizeRequiredNames(value.required, {}, `${path}.required`); + } + break; + } + case 'array': + assertSchemaKeys(value, path, ['type', 'items', ...requiredKey, ...ANNOTATION_KEYS]); + if (Object.hasOwn(value, 'items')) { + tasks.push({ + kind: 'value', + value: value.items, + path: `${path}.items`, + forceRequired: false, + raw: task.raw, + parameterProperty: false, + destination: { kind: 'item', target: prop }, + }); + } + break; + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': + assertSchemaKeys(value, path, ['type', 'enum', 'const', ...requiredKey, ...ANNOTATION_KEYS]); + if (Object.hasOwn(value, 'enum')) { + if (!isDensePlainArray(value.enum) || value.enum.length === 0) { + throw new Error(`harness.defineTool ${path}.enum must be a non-empty array`); + } + prop.enum = cloneJson(value.enum, `harness.defineTool ${path}.enum`); + } + if (Object.hasOwn(value, 'const')) + prop.const = cloneJson(value.const, `harness.defineTool ${path}.const`); + break; + case 'json': + assertSchemaKeys(value, path, ['type', ...requiredKey, ...ANNOTATION_KEYS]); + break; + /* v8 ignore next 2 -- SCHEMA_TYPES narrows this closed switch before dispatch. */ + default: + throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES}`); + } + } + /* v8 ignore next -- the root map task assigns before scheduling descendants. */ + return holder.value ?? {}; +} +function markDynamicTool(tool) { + Object.defineProperty(tool, DYNAMIC_TOOL, { value: true }); + return tool; +} +function assertDynamicTool(tool) { + if (!isPlainRecord(tool) || tool[DYNAMIC_TOOL] !== true) { + throw new Error('dynamic tool registration must use a tool returned by harness.defineTool(...)'); + } +} +/** + * Structurally a content block, checked AFTER the JSON round-trip: a plain + * object carrying a string `type` tag. Deliberately nothing deeper — the + * ContentBlock union is merge-extensible (an unknown tag must pass), and every + * downstream consumer dispatches on `type` and falls through unknowns. + */ +function isContentBlockShape(value) { + return isPlainRecord(value) && typeof value.type === 'string'; +} +/** + * How much of an invalid execute return the teaching error echoes back — a + * huge blob would burn the model turn the error is trying to save. + */ +const RETURN_PREVIEW_LIMIT = 120; +/** + * Compact JSON preview of an invalid execute return for the teaching error + * (`String(…)` for the un-stringifiable undefined case), truncated to + * {@link RETURN_PREVIEW_LIMIT}. + */ +function describeReturn(value) { + // The caller has already crossed cloneJson, so this value is lossless JSON + // and serialization cannot produce undefined. + const json = JSON.stringify(value); + return json.length > RETURN_PREVIEW_LIMIT ? `${json.slice(0, RETURN_PREVIEW_LIMIT)}…` : json; +} +/** + * Validate and host-materialize a sandbox renderer's content blocks. + */ +function assertRenderedContent(value) { + if (Array.isArray(value) && value.every(isContentBlockShape)) { + return value; + } + throw new Error(`output.render returned ${describeReturn(value)} — it must return an ARRAY of content blocks:\n` + + ' ✓ return [{ type: \'text\', text: String(value) }]'); +} +/** + * The `harness.defineTool` handed into the sandbox: the real DSL, with `parameters` normalized + * into a fresh host-realm ParameterSchemaSpec (raw object wrappers unwrapped, + * required arrays mapped, and explicit DSL object openness enforced) and the tool's `execute` return normalized into the host realm + * via a JSON round-trip. Non-JSON or wrong-shape output fails that call instead of poisoning + * the session log. + * @param options - the standard `defineTool` options; `parameters` may be the ParameterSchemaSpec DSL or a JSON-Schema-style wrapper. + * @returns the marker-tagged definition `harness.registerTool` (and the guarded `ctx.tools.register`) accepts. + */ +export function sandboxDefineTool(options) { + if (!isPlainRecord(options)) + throw new Error('harness.defineTool options must be an object'); + const normalized = normalizeParameterSchemaSpec(options.parameters); + if (!isPlainRecord(options.output)) { + throw new Error('harness.defineTool output must declare { schema, render, presentationMeta? }'); + } + const output = options.output; + if (typeof output.render !== 'function') + throw new Error('harness.defineTool output.render must be a function'); + if (output.presentationMeta !== undefined && typeof output.presentationMeta !== 'function') { + throw new Error('harness.defineTool output.presentationMeta must be a function when present'); + } + if (typeof options.execute !== 'function') + throw new Error('harness.defineTool execute must be a function'); + const schema = cloneJson(output.schema, 'harness.defineTool output.schema'); + const rawExecute = options.execute; + const rawRender = output.render; + const rawPresentationMeta = output.presentationMeta; + const erasedDefineTool = defineTool; + const tool = erasedDefineTool({ + ...options, + parameters: normalized.spec, + output: { + schema, + render(args, value) { + return assertRenderedContent(cloneJson(rawRender(args, value), 'harness.defineTool output.render result')); + }, + ...rawPresentationMeta !== undefined ? { + presentationMeta(args, value) { + return cloneJson(rawPresentationMeta(args, value), 'harness.defineTool output.presentationMeta result'); + }, + } : {}, + }, + async execute(args, exec) { + return cloneJson(await rawExecute(args, exec), 'harness.defineTool execute result'); + }, + }); + const parameters = { ...tool.parameters, ...normalized.rootAnnotations }; + assertSupportedJsonSchema(parameters); + return markDynamicTool({ + ...tool, + parameters, + }); +} +/** + * Normalize one `harness.handle` registration at the sandbox boundary: the + * method name must be a non-empty string and the handler a function whose + * result is host-materialized through the same cross-realm JSON clone as tool + * `execute` returns (a VM-realm object would otherwise escape the wire's + * plain-object contract). + * @param method - handler name the package's browser half calls through `host.call`. + * @param fn - sandbox handler receiving the wire-decoded JSON arguments. + * @returns the validated name and the clone-wrapped handler. + */ +export function normalizeHandler(method, fn) { + if (typeof method !== 'string' || method.length === 0) { + throw new Error('harness.handle(method, fn) needs a non-empty string method name'); + } + if (typeof fn !== 'function') { + throw new Error(`harness.handle("${method}") needs a handler function as its second argument`); + } + const rawHandler = fn; + return { + method, + handler: async (args) => cloneJson(await rawHandler(args), `harness.handle("${method}") result`), + }; +} +/** + * The `harness.registerTool` handed into the sandbox: registers a + * marker-verified dynamic tool on the given context's registry. + * @param ctx - the (guarded) context whose `tools` service receives the tool. + * @param tool - a definition produced by {@link sandboxDefineTool}; anything else is rejected. + * @returns the registry disposer for the registration. + */ +export function sandboxRegisterTool(ctx, tool) { + assertDynamicTool(tool); + return ctx.tools.register(tool); +} +/** + * The verbs a running host half may reach through the sandbox `ctx` façade, beyond its injected + * services. `on`/`once` observe events, `provide` exposes a service to other packages, and the + * timer helpers schedule work — each a fiber effect that unwinds when the package stops. + */ +const CTX_VERBS = new Set(['effect', 'on', 'once', 'provide', 'timeout', 'interval', 'setTimeout', 'setInterval', 'throttle', 'debounce']); +const TIMER_VERBS = new Set(['timeout', 'interval', 'setTimeout', 'setInterval', 'throttle', 'debounce']); +/** + * The tool-registry façade: `register` (marker-guarded) plus READ-ONLY + * metadata (`schemas`, and `get` returning a schema view, never the live + * `ToolDefinition`). Exposing the raw definition would hand package code the + * tool's `execute` function, letting it call another tool directly and bypass + * `ToolRuntime.execute` — identity protection, pre-policy, monotonic guards, + * around dispatch, post-policy, final observation, and result normalization. So `get` returns the same + * name/description/parameters view as `schemas()`, and nothing invocable. + */ +function sandboxTools(ctx) { + // Resolve reads and writes through the package's own scope. + return { + register: (tool) => sandboxRegisterTool(ctx, tool), + schemas: () => ctx.tools.schemas(scopeOf(ctx)), + get: (name) => ctx.tools.schemas(scopeOf(ctx)).find(schema => schema.name === name), + }; +} +/** + * Reject any injected-service return that is a cordis `Context`. Harness + * services return data, never a context; a value that is one would be a + * fresh, unguarded handle back into the runtime — the exact escape the façade + * exists to close — so it fails loud instead of reaching sandbox code. + */ +// Twinned with the browser half's guard for the same reason as the ctx façade +// below: this is the rule "a service must never hand sandboxed code a Context", +// and each half must test against the Context class of ITS OWN face. Moving the +// rule into a shared package would move a security invariant out of the halves +// that enforce it, which is a design decision rather than a duplication fix. +/* jscpd:ignore-start */ +function denyContext(value, service, reportFailure) { + if (value instanceof Context) { + return rejectGuard(reportFailure, `service "${service}" returned a cordis Context, which the sandbox does not expose. ` + + 'Operate through your own plugin ctx (ctx.on / ctx.provide / ctx.tools.register) ' + + 'and the services you inject — never another context.'); + } + return value; +} +/** + * Wrap an injected service so its methods forward to the real instance but + * their return values pass through {@link denyContext}. Non-function members + * (plain data) pass through as-is; a returned Promise is guarded on resolve. + */ +function guardedService(service, name, reportFailure) { + return new Proxy(service, { + get(target, prop) { + const value = Reflect.get(target, prop, target); + if (typeof value !== 'function') + return denyContext(value, name, reportFailure); + return (...args) => { + const result = Reflect.apply(value, target, args); + if (result instanceof Promise) + return result.then(v => denyContext(v, name, reportFailure)); + return denyContext(result, name, reportFailure); + }; + }, + }); +} +/* jscpd:ignore-end */ +/** + * The service names a plugin declared in `inject`, as a lookup set. Whatever + * declaration style the plugin used — an `inject: ['bash', 'tools']` array or + * the `{ required, optional }` object form — cordis resolves it into a single + * name-keyed map on the fiber before `apply` runs (`{ bash: null, tools: null }`), + * so the gate just reads that map's keys. A host half may reach only the services + * it declared — that is what lets cordis park it when a declared provider + * goes away. + */ +function declaredInjects(ctx) { + return new Set(Object.keys(ctx.fiber.inject)); +} +/** + * Whitelist context for running host halves: lifecycle-safe verbs, guarded + * tools, optional `ctx.get()` lookup, and declared-service property access. + * Framework plumbing is denied, and service methods cannot return a Context. + */ +function sandboxContext(ctx, reportFailure) { + const tools = sandboxTools(ctx); + const declared = declaredInjects(ctx); + // A framework member or an undeclared service — distinguish the two so the + // error teaches the right fix (declare it in inject vs it is withheld). + const denyRead = (prop) => { + if (ctx.get(prop) !== undefined) { + return rejectGuard(reportFailure, `service "${prop}" is not injected. Declare it: inject: ['${prop}', …] on your plugin, ` + + 'so cordis parks this dynamic package if the provider later goes away.'); + } + return rejectGuard(reportFailure, `sandbox ctx does not expose "${prop}". Available: ctx.tools.register / ctx.on / ctx.provide / ` + + 'the timer helpers after injecting timer, and any service you declared in inject. ' + + 'Framework internals (root, fiber, registry, extend, plugin, …) are withheld by design.'); + }; + // `get` is optional lookup; property access requires a declaration. `tools` + // is the façade's own API on either path. + const readService = (name, requireDeclaration) => { + if (name === 'tools') + return tools; + if (requireDeclaration && !declared.has(name)) + return denyRead(name); + const service = denyContext(ctx.get(name), name, reportFailure); + if (service === null || (typeof service !== 'object' && typeof service !== 'function')) + return service; + return guardedService(service, name, reportFailure); + }; + const get = (name) => readService(name, false); + // The browser half builds the same façade over its own Context + // (`@deepseek-ai/dsh-cordis-client-runner`, whose CTX_VERBS names this one its + // twin), and the sameness is the point: a package author meets ONE contract on + // both halves. Folding them together is not available — the two halves compile + // in separate programs where `Context` merges different service keys — so the + // duplication is declared here instead of hidden behind a config exception. + /* jscpd:ignore-start */ + return new Proxy({}, { + get(_target, prop) { + if (prop === 'tools') + return tools; + if (prop === 'get') + return get; + if (typeof prop !== 'string') + return undefined; + // Lazy verb forwarder — reads `ctx[verb]` only when called. Timer mixins + // additionally require the Service declaration before Cordis resolves them. + if (CTX_VERBS.has(prop)) { + return (...args) => { + if (TIMER_VERBS.has(prop) && !declared.has('timer')) + return denyRead('timer'); + const method = ctx[prop]; + return Reflect.apply(method, ctx, args); + }; + } + return readService(prop, true); + }, + // A façade is not the real ctx; block writes rather than let package code + // stash state on a throwaway object and think it persisted. + set(_target, prop) { + return rejectGuard(reportFailure, `sandbox ctx is read-only; cannot assign "${String(prop)}"`); + }, + // `in` reflects reachability: the façade API plus DECLARED services + // (whether or not currently live). Does not resolve/wrap — no throw. + has: (_target, prop) => prop === 'tools' || prop === 'get' + || (typeof prop === 'string' + && ((CTX_VERBS.has(prop) && (!TIMER_VERBS.has(prop) || declared.has('timer'))) || declared.has(prop))), + }); + /* jscpd:ignore-end */ +} +/** + * Narrow an arbitrary sandbox return value to a runnable cordis plugin: a + * function, or an object with an `apply` function. (A bare function passes the + * first arm, so the object arm never sees `Function.prototype.apply`.) + * @param value - whatever the host half returned. + * @returns whether the value can be started via `ctx.plugin`. + */ +export function isPlugin(value) { + if (typeof value === 'function') + return true; + return typeof value === 'object' && value !== null + && typeof value.apply === 'function'; +} +/** + * Wrap a plugin so `apply` receives the sandbox context while preserving injection metadata. + * @param plugin - the plugin the host half returned. + * @param reportFailure - reports a guard rejection to the owning Agent. + * @returns an equivalent plugin whose `apply` sees the sandbox context façade. + */ +export function guardedPlugin(plugin, reportFailure) { + if (typeof plugin === 'function') { + const functionPlugin = plugin; + return { + name: pluginName(plugin), + apply(ctx, config) { + return functionPlugin(sandboxContext(ctx, reportFailure), config); + }, + }; + } + const objectPlugin = plugin; + return { + ...plugin, + apply(ctx, config) { + return objectPlugin.apply(sandboxContext(ctx, reportFailure), config); + }, + }; +} +function rejectGuard(reportFailure, message) { + const error = new Error(message); + reportFailure(error); + throw error; +} +/** + * Display name for a running plugin: its `name` property, else anonymous. + * @param plugin - the plugin the host half returned. + * @returns the human-readable name used in run results and inspect output. + */ +export function pluginName(plugin) { + const named = plugin.name; + if (typeof named === 'string' && named.length > 0) + return named; + return ''; +} +//# sourceMappingURL=guard.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.d.ts new file mode 100644 index 0000000..43b3afb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.d.ts @@ -0,0 +1,270 @@ +/** + * Dynamic Cordis Plugin service: immutable package definitions, one active run + * per Plugin, human-approved Client activation, and Host/Client invocation. + * @module @deepseek-ai/dsh-cordis-host-runner + */ +import { Context } from '@deepseek-ai/cordis'; +import type { Fiber } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { JsonValue } from '@deepseek-ai/dsh-session/types'; +import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'; +import type { DynamicCordisDefineReceipt, DynamicCordisDefineRequest, DynamicCordisPackageInspection, DynamicCordisPluginInspection, DynamicCordisReference } from './registry.ts'; +import type { ApprovalRequestId, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisErrorDetails, CordisDynamicRunMode, CordisInspectProviderManifest, CordisInspectQueryResolution, CordisInspectRequestId, CordisInspectResolveAck, DynamicCordisClientSource, DynamicCordisHostHalfResult, DynamicCordisInventoryRow, DynamicCordisInvokeResult, DynamicCordisRenderFailure, DynamicCordisResolveAck, DynamicCordisRunAttempt, DynamicCordisRunResolution, DynamicCordisRunResponse, DynamicCordisStopResponse, DynamicCordisUndefineReceipt } from './types.ts'; +export type * from './types.ts'; +export type { DynamicCordisDefineReceipt, DynamicCordisDefineRequest, DynamicCordisDefinition, DynamicCordisHandler, DynamicCordisPackageInspection, DynamicCordisPlugin, DynamicCordisPluginInspection, DynamicCordisReference, DynamicCordisRun, } from './registry.ts'; +export { CordisInspectRegistryService } from './inspect-registry.ts'; +export type { HostCordisInspectProviderRegistration } from './inspect-registry.ts'; +export { HOST_BUILTIN_INSPECTION } from './sandbox.ts'; +/** + * Brand a Host-minted Plugin ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Plugin identifier. + */ +export declare function CordisDynamicPluginId(id: string): CordisDynamicPluginId; +/** + * Brand a Host-minted Package ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Package identifier. + */ +export declare function CordisDynamicPackageId(id: string): CordisDynamicPackageId; +/** + * Brand a Host-minted Plugin Run ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Plugin Run identifier. + */ +export declare function CordisDynamicPluginRunId(id: string): CordisDynamicPluginRunId; +/** + * Brand a Host-minted approval request ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded approval request identifier. + */ +export declare function ApprovalRequestId(id: string): ApprovalRequestId; +declare module '@deepseek-ai/cordis' { + interface Context { + /** Process-local dynamic Plugin registry and lifecycle service. */ + dynamicCordisRunner: DynamicCordisRunnerService; + } +} +/** Runner configuration. */ +export interface Config { + /** Maximum synchronous VM evaluation time in milliseconds. */ + vmTimeoutMs?: number; +} +/** Host-only snapshot consumed by inspect and tool result rendering. */ +export interface DynamicCordisSnapshotRow { + pluginId: CordisDynamicPluginId; + currentPackageId?: CordisDynamicPackageId; + nextPackageId?: CordisDynamicPackageId; + packages: Array<{ + packageId: CordisDynamicPackageId; + name: string; + purpose: string; + hasHostHalf: boolean; + hasClientHalf: boolean; + }>; + activeRun?: { + pluginRunId: CordisDynamicPluginRunId; + packageId: CordisDynamicPackageId; + fiber?: Fiber; + handlers: string[]; + renderFailure?: DynamicCordisRenderFailure; + }; + latestRun?: DynamicCordisRunAttempt; +} +/** Dynamic Plugin registry and Host-half lifecycle. */ +export declare class DynamicCordisRunnerService extends TypertRemoteService { + static inject: string[]; + static Config: z; + private readonly rootCtx; + private readonly registry; + private readonly inspectRegistry; + private readonly starting; + private readonly resolved; + private group; + /** Create the service under the Host composition. */ + constructor(ctx: Context, config: Config); + /** + * Define a new Plugin's first Package or append a Package to an existing Plugin. + * @param request - Session ownership, Plugin selection, metadata, and source code. + * @returns Host-minted Plugin and Package identities with declared-half metadata. + */ + define(request: DynamicCordisDefineRequest): DynamicCordisDefineReceipt; + /** + * Remove a Plugin, its active run, and all immutable Packages. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + undefine(agent: Agent, pluginId: CordisDynamicPluginId): Promise; + /** + * Remove a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + undefineFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise; + /** + * Start or update one Package for a model tool call. An unauthorized Client + * Package waits for approval; Plugin-wide authorization covers later versions. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param signal - Tool-call cancellation signal while the activation request is being created. + * @returns The successful activation identity or an actionable refusal. + */ + run(agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, signal?: AbortSignal): Promise; + /** + * Start Host code for an approved request or a direct panel gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param requestId - Model-driven request identity, or null for a direct user gesture. + * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin. + * @returns The exact Host activation or a failure message. + */ + runHostHalf(agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean): Promise; + /** + * Fetch Client code for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to read. + * @param pluginRunId - Exact active run authorized to receive source. + * @returns Client source and its Plugin, Package, and run identities. + */ + getClientCode(agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId): DynamicCordisClientSource; + /** + * Resolve one model-driven Client activation request. + * @param requestId - Request identity to settle once. + * @param resolution - Browser refusal or exact Client activation result. + * @returns Whether the still-pending request accepted this resolution. + */ + resolveRequestRun(requestId: ApprovalRequestId, resolution: DynamicCordisRunResolution): Promise; + /** + * Settle a direct panel run after this page loaded or failed its Client half. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity being settled. + * @param resolution - Exact Client activation result from the acting page. + * @returns The committed activation or its failure. + */ + settleUserRun(agent: Agent, pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution): Promise; + /** + * Stop the active run while retaining every Package version. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + stop(agent: Agent, pluginId: CordisDynamicPluginId): Promise; + /** + * Stop a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + stopFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise; + /** + * Replace the Host mirror of the Client inspect provider directory. + * @param providers - complete Client provider manifest. + * @returns null after accepting the manifest. + */ + syncInspectManifest(providers: readonly CordisInspectProviderManifest[]): null; + /** + * Claim one pending Client inspect query with its live result. + * @param agent - Session that owns the query. + * @param requestId - exact pending query identity. + * @param resolution - provider result or structured refusal. + * @returns whether this answer won the query. + */ + resolveInspectQuery(agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution): CordisInspectResolveAck; + /** + * Frame-wide inventory, grouped as one row per stable Plugin. + * @returns Source-free metadata for every process-local Plugin. + */ + inventory(): DynamicCordisInventoryRow[]; + /** + * Read one Session's Host-rich state for inspection and result rendering. + * @param agent - Agent whose Session selects visible Plugins. + * @returns Plugin versions, active runs, Host fibers, and render failures. + */ + snapshot(agent: Agent): DynamicCordisSnapshotRow[]; + /** + * Read source-free context for an explicit `@pluginId` user gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity referenced by the user. + * @returns The preferred modification base, or undefined when unavailable. + */ + reference(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisReference | undefined; + /** + * List source-free Plugin summaries owned by one Session. + * @param agent - Agent whose Session selects visible Plugins. + * @returns one summary per Plugin in creation order. + */ + listPlugins(agent: Agent): DynamicCordisPluginInspection[]; + /** + * Inspect one Plugin without returning Package source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - stable Plugin identity. + * @returns version pointers, latest run, and all Package summaries. + */ + inspectPlugin(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisPluginInspection; + /** + * Read one exact immutable Package and its Host and Client source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that owns the Package. + * @param packageId - Exact immutable Package identity to inspect. + * @returns Package metadata, source, and the Plugin's lifecycle pointers. + */ + inspectPackage(agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId): DynamicCordisPackageInspection; + /** + * Record a post-load render failure for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that rendered. + * @param pluginRunId - Exact active run that produced the failure. + * @param failure - Slot, message, and entry-retirement result. + * @returns Null after recording or ignoring a stale report. + */ + reportRenderFailure(agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure): Promise; + /** + * Report a Client guard rejection that happened after the Package completed activation. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity whose Client code was rejected. + * @param pluginRunId - Exact active run that produced the rejection. + * @param failure - Original guard message and stack. + * @returns Null after reporting or ignoring a stale/startup failure. + */ + reportClientGuardFailure(agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails): Promise; + /** + * Invoke an active Host method while rejecting stale Client runs. + * @param pluginId - Stable Plugin identity that owns the method. + * @param pluginRunId - Exact active run authorizing the call. + * @param method - Registered Host handler name. + * @param args - JSON argument delivered to the handler. + * @returns The JSON result or a typed invocation failure. + */ + invoke(pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, method: string, args: JsonValue): Promise; + private resolvePlan; + private activate; + private startFresh; + private startHost; + private settleActivation; + private commitActivation; + private runResponse; + private announceResolved; + private steerRunOutcome; + private steerRenderFailure; + private steerHostHandlerFailure; + private steerGuardFailure; + private claimRuntimeFailure; + private injectUserRunOutcome; + private injectUserContext; + private cancelPending; + private createAttempt; + private failAttempt; + private diagnostic; + private retract; + private owned; + private requireGroup; +} +export default DynamicCordisRunnerService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.js new file mode 100644 index 0000000..8894191 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.js @@ -0,0 +1,1151 @@ +/** + * Dynamic Cordis Plugin service: immutable package definitions, one active run + * per Plugin, human-approved Client activation, and Host/Client invocation. + * @module @deepseek-ai/dsh-cordis-host-runner + */ +var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; +var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +import z from '@deepseek-ai/schemastery'; +import { createUserMessage } from '@deepseek-ai/dsh-llm'; +import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'; +import { isPlugin, normalizeHandler } from "./guard.js"; +import { CordisInspectRegistryService } from "./inspect-registry.js"; +import { missingServices, startHostHalf } from "./lifecycle.js"; +import { DynamicCordisRegistry } from "./registry.js"; +import { createSandbox, evaluateHostCode, precheckCode } from "./sandbox.js"; +export { CordisInspectRegistryService } from "./inspect-registry.js"; +export { HOST_BUILTIN_INSPECTION } from "./sandbox.js"; +/** + * Brand a Host-minted Plugin ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Plugin identifier. + */ +export function CordisDynamicPluginId(id) { + return id; +} +/** + * Brand a Host-minted Package ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Package identifier. + */ +export function CordisDynamicPackageId(id) { + return id; +} +/** + * Brand a Host-minted Plugin Run ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Plugin Run identifier. + */ +export function CordisDynamicPluginRunId(id) { + return id; +} +/** + * Brand a Host-minted approval request ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded approval request identifier. + */ +export function ApprovalRequestId(id) { + return id; +} +/** Dynamic Plugin registry and Host-half lifecycle. */ +let DynamicCordisRunnerService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _undefineFromPanel_decorators; + let _runHostHalf_decorators; + let _getClientCode_decorators; + let _resolveRequestRun_decorators; + let _settleUserRun_decorators; + let _stopFromPanel_decorators; + let _syncInspectManifest_decorators; + let _resolveInspectQuery_decorators; + let _inventory_decorators; + let _reportRenderFailure_decorators; + let _reportClientGuardFailure_decorators; + let _invoke_decorators; + return class DynamicCordisRunnerService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _undefineFromPanel_decorators = [Remote('undefineFromPanel')]; + _runHostHalf_decorators = [Remote('runHostHalf')]; + _getClientCode_decorators = [Remote('getClientCode')]; + _resolveRequestRun_decorators = [Remote('resolveRequestRun')]; + _settleUserRun_decorators = [Remote('settleUserRun')]; + _stopFromPanel_decorators = [Remote('stopFromPanel')]; + _syncInspectManifest_decorators = [Remote('syncInspectManifest')]; + _resolveInspectQuery_decorators = [Remote('resolveInspectQuery')]; + _inventory_decorators = [Remote('inventory')]; + _reportRenderFailure_decorators = [Remote('reportRenderFailure')]; + _reportClientGuardFailure_decorators = [Remote('reportClientGuardFailure')]; + _invoke_decorators = [Remote('invoke')]; + __esDecorate(this, null, _undefineFromPanel_decorators, { kind: "method", name: "undefineFromPanel", static: false, private: false, access: { has: obj => "undefineFromPanel" in obj, get: obj => obj.undefineFromPanel }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _runHostHalf_decorators, { kind: "method", name: "runHostHalf", static: false, private: false, access: { has: obj => "runHostHalf" in obj, get: obj => obj.runHostHalf }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _getClientCode_decorators, { kind: "method", name: "getClientCode", static: false, private: false, access: { has: obj => "getClientCode" in obj, get: obj => obj.getClientCode }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resolveRequestRun_decorators, { kind: "method", name: "resolveRequestRun", static: false, private: false, access: { has: obj => "resolveRequestRun" in obj, get: obj => obj.resolveRequestRun }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _settleUserRun_decorators, { kind: "method", name: "settleUserRun", static: false, private: false, access: { has: obj => "settleUserRun" in obj, get: obj => obj.settleUserRun }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _stopFromPanel_decorators, { kind: "method", name: "stopFromPanel", static: false, private: false, access: { has: obj => "stopFromPanel" in obj, get: obj => obj.stopFromPanel }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _syncInspectManifest_decorators, { kind: "method", name: "syncInspectManifest", static: false, private: false, access: { has: obj => "syncInspectManifest" in obj, get: obj => obj.syncInspectManifest }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resolveInspectQuery_decorators, { kind: "method", name: "resolveInspectQuery", static: false, private: false, access: { has: obj => "resolveInspectQuery" in obj, get: obj => obj.resolveInspectQuery }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _inventory_decorators, { kind: "method", name: "inventory", static: false, private: false, access: { has: obj => "inventory" in obj, get: obj => obj.inventory }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _reportRenderFailure_decorators, { kind: "method", name: "reportRenderFailure", static: false, private: false, access: { has: obj => "reportRenderFailure" in obj, get: obj => obj.reportRenderFailure }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _reportClientGuardFailure_decorators, { kind: "method", name: "reportClientGuardFailure", static: false, private: false, access: { has: obj => "reportClientGuardFailure" in obj, get: obj => obj.reportClientGuardFailure }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _invoke_decorators, { kind: "method", name: "invoke", static: false, private: false, access: { has: obj => "invoke" in obj, get: obj => obj.invoke }, metadata: _metadata }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + static inject = ['tools']; + static Config = z.object({ + vmTimeoutMs: z.number().min(1).default(5000), + }); + rootCtx = __runInitializers(this, _instanceExtraInitializers); + registry = new DynamicCordisRegistry(); + inspectRegistry; + starting = new Map(); + resolved; + group; + /** Create the service under the Host composition. */ + constructor(ctx, config) { + super(ctx, 'dynamicCordisRunner'); + this.rootCtx = ctx; + this.resolved = config; + this.inspectRegistry = new CordisInspectRegistryService(ctx); + } + /** + * Define a new Plugin's first Package or append a Package to an existing Plugin. + * @param request - Session ownership, Plugin selection, metadata, and source code. + * @returns Host-minted Plugin and Package identities with declared-half metadata. + */ + define(request) { + const name = request.name.trim(); + const purpose = request.purpose.trim(); + if (name.length === 0) + throw new Error('cordis_define needs a non-empty `name`'); + if (purpose.length === 0) + throw new Error('cordis_define needs a non-empty `purpose`'); + if (request.code.host === undefined && request.code.client === undefined) { + throw new Error('cordis_define needs `code.host`, `code.client`, or both'); + } + if (request.code.host !== undefined) + precheckCode(request.code.host, 'code.host'); + if (request.code.client !== undefined) + precheckCode(request.code.client, 'code.client'); + let plugin; + if (request.plugin.kind === 'new') { + const prefix = request.plugin.idPrefix.trim(); + if (!/^[a-z]{3,6}$/.test(prefix)) { + throw new Error('cordis_define `plugin.idPrefix` must contain 3–6 lowercase English letters'); + } + const pluginId = CordisDynamicPluginId(this.registry.mintPluginId(prefix)); + plugin = { + pluginId, + sessionId: request.sessionId, + packages: new Map(), + approvedClientPackages: new Set(), + clientVersionUpdatesApproved: false, + }; + this.registry.add(plugin); + } + else { + const found = this.registry.get(request.plugin.pluginId); + if (found === undefined || found.sessionId !== request.sessionId) { + throw new Error(missingPluginMessage(request.plugin.pluginId)); + } + plugin = found; + } + const packageId = CordisDynamicPackageId(this.registry.mintPackageId()); + const definition = { + packageId, + name, + purpose, + ...request.code.host === undefined ? {} : { hostCode: request.code.host }, + ...request.code.client === undefined ? {} : { clientCode: request.code.client }, + }; + plugin.packages.set(packageId, definition); + return { + pluginId: plugin.pluginId, + packageId, + name, + purpose, + hasHostHalf: definition.hostCode !== undefined, + hasClientHalf: definition.clientCode !== undefined, + }; + } + /** + * Remove a Plugin, its active run, and all immutable Packages. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + async undefine(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + return { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) }; + const wasRunning = plugin.run !== undefined; + this.cancelPending(pluginId, `dynamic plugin "${pluginId}" was removed before approval`); + if (plugin.run !== undefined) + await this.retract(plugin); + this.registry.delete(pluginId); + return { ok: true, wasRunning }; + } + /** + * Remove a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + async undefineFromPanel(agent, pluginId) { + const result = await this.undefine(agent, pluginId); + if (result.ok) { + this.injectUserContext(agent, `The user removed Cordis Plugin ${pluginId} and all of its Packages. The Plugin no longer exists.`); + } + return result; + } + /** + * Start or update one Package for a model tool call. An unauthorized Client + * Package waits for approval; Plugin-wide authorization covers later versions. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param signal - Tool-call cancellation signal while the activation request is being created. + * @returns The successful activation identity or an actionable refusal. + */ + async run(agent, pluginId, packageId, mode, signal) { + const plan = this.resolvePlan(agent, pluginId, packageId, mode); + if (!plan.ok) + return plan.response; + if (signal?.aborted === true) { + return { + ok: false, + reason: 'cancelled', + message: `the run request for dynamic plugin "${pluginId}" was cancelled before activation`, + }; + } + if (this.registry.pendingRequestFor(pluginId) !== undefined) { + return { ok: false, reason: 'transition-in-flight', message: `dynamic plugin "${pluginId}" already has a pending run request` }; + } + const attempt = this.createAttempt(plan); + plan.plugin.nextPackageId = packageId; + plan.plugin.latestRun = attempt; + if (plan.definition.clientCode === undefined) { + const started = await this.activate(plan, undefined, false, attempt); + if (started.ok) + return this.runResponse(plan.plugin, started); + this.failAttempt(plan.plugin, attempt, 'host-load', started); + return { ...started, reason: 'host-half-failed' }; + } + const requestId = ApprovalRequestId(this.registry.mintApprovalRequestId()); + const requiresApproval = !plan.plugin.clientVersionUpdatesApproved + && !plan.plugin.approvedClientPackages.has(packageId); + attempt.approvalRequestId = requestId; + attempt.requiresApproval = requiresApproval; + attempt.status = requiresApproval ? 'awaiting-approval' : 'starting-host'; + this.registry.armRequest(requestId, { + agentId: agent.id, + pluginId, + packageId, + pluginRunId: attempt.pluginRunId, + mode, + requiresApproval, + }); + this.ctx.emit('cordis/request-run', { + requestId, + agentId: agent.id, + pluginId, + packageId, + mode, + name: plan.definition.name, + purpose: plan.definition.purpose, + requiresApproval, + }); + return { + ok: true, + status: requiresApproval ? 'awaiting-approval' : 'starting', + pluginId, + packageId, + pluginRunId: attempt.pluginRunId, + mode, + waitingFor: [], + ...plan.plugin.currentPackageId === undefined ? {} : { currentPackageId: plan.plugin.currentPackageId }, + nextPackageId: packageId, + }; + } + /** + * Start Host code for an approved request or a direct panel gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param requestId - Model-driven request identity, or null for a direct user gesture. + * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin. + * @returns The exact Host activation or a failure message. + */ + async runHostHalf(agent, pluginId, packageId, mode, requestId, approveFutureVersions) { + const plan = this.resolvePlan(agent, pluginId, packageId, mode, requestId === null); + if (!plan.ok) + return { ok: false, message: plan.response.message }; + let attempt; + if (requestId !== null) { + const pending = this.registry.peekRequest(requestId); + if (pending === undefined || pending.pluginId !== pluginId || pending.packageId !== packageId || pending.mode !== mode) { + return { ok: false, message: `run request "${requestId}" does not authorize ${pluginId}/${packageId}` }; + } + const latest = plan.plugin.latestRun; + const expectedStatus = pending.requiresApproval ? 'awaiting-approval' : 'starting-host'; + if (latest === undefined || latest.pluginRunId !== pending.pluginRunId + || (latest.status !== expectedStatus && (!pending.requiresApproval && latest.status !== 'client-pending'))) { + return { ok: false, message: `run request "${requestId}" no longer identifies the latest run of ${pluginId}` }; + } + attempt = latest; + if (pending.requiresApproval) { + plan.plugin.approvedClientPackages.add(packageId); + if (approveFutureVersions) + plan.plugin.clientVersionUpdatesApproved = true; + } + } + else { + const pending = this.registry.pendingRequestFor(pluginId); + if (pending !== undefined) + return { ok: false, message: `dynamic plugin "${pluginId}" has pending run request ${pending}` }; + const attached = plan.plugin.run?.packageId === packageId + && plan.plugin.latestRun?.pluginRunId === plan.plugin.run.pluginRunId + ? plan.plugin.latestRun + : undefined; + attempt = attached ?? this.createAttempt(plan); + if (attached === undefined) { + plan.plugin.nextPackageId = packageId; + plan.plugin.latestRun = attempt; + } + if (plan.definition.clientCode !== undefined) + plan.plugin.approvedClientPackages.add(packageId); + } + const attaching = attempt.pluginRunId === plan.plugin.run?.pluginRunId; + if (!attaching) { + attempt.status = 'starting-host'; + if (attempt.host.status !== 'absent') + attempt.host = { status: 'pending', waitingFor: [] }; + } + const started = await this.activate(plan, requestId ?? undefined, attaching, attempt); + if (!started.ok) + this.failAttempt(plan.plugin, attempt, 'host-load', started); + return started; + } + /** + * Fetch Client code for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to read. + * @param pluginRunId - Exact active run authorized to receive source. + * @returns Client source and its Plugin, Package, and run identities. + */ + getClientCode(agent, pluginId, pluginRunId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + throw new Error(missingPluginMessage(pluginId)); + const run = plugin.run; + if (run === undefined || run.pluginRunId !== pluginRunId) { + throw new Error(`dynamic plugin "${pluginId}" is not running activation "${pluginRunId}"`); + } + const definition = plugin.packages.get(run.packageId); + if (definition?.clientCode === undefined) + throw new Error(`package "${run.packageId}" has no Client half`); + return { + code: definition.clientCode, + name: definition.name, + pluginId, + packageId: run.packageId, + pluginRunId, + }; + } + /** + * Resolve one model-driven Client activation request. + * @param requestId - Request identity to settle once. + * @param resolution - Browser refusal or exact Client activation result. + * @returns Whether the still-pending request accepted this resolution. + */ + async resolveRequestRun(requestId, resolution) { + const pending = this.registry.peekRequest(requestId); + if (pending === undefined) + return { accepted: false }; + const plugin = this.registry.get(pending.pluginId); + if (resolution.ok && plugin?.run?.pluginRunId !== resolution.pluginRunId) + return { accepted: false }; + if (!resolution.ok && resolution.pluginRunId !== undefined + && plugin?.run?.pluginRunId !== resolution.pluginRunId) + return { accepted: false }; + this.registry.claimRequest(requestId); + const settled = await this.settleActivation(plugin, resolution, requestId); + this.announceResolved(requestId, resolution, pending.requiresApproval ? undefined : 'completed'); + this.steerRunOutcome(pending, settled); + return { accepted: true }; + } + /** + * Settle a direct panel run after this page loaded or failed its Client half. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity being settled. + * @param resolution - Exact Client activation result from the acting page. + * @returns The committed activation or its failure. + */ + async settleUserRun(agent, pluginId, resolution) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + return { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) }; + const settled = await this.settleActivation(plugin, resolution); + this.injectUserRunOutcome(agent, pluginId, settled); + return settled; + } + /** + * Stop the active run while retaining every Package version. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + async stop(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + return { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) }; + const pending = this.registry.pendingRequestFor(pluginId); + if (plugin.run === undefined && pending === undefined) { + return { ok: false, reason: 'not-running', message: `dynamic plugin "${pluginId}" is not running` }; + } + if (pending !== undefined) + this.cancelPending(pluginId, `dynamic plugin "${pluginId}" was stopped before approval`); + if (plugin.run !== undefined) + await this.retract(plugin); + if (plugin.latestRun !== undefined) { + plugin.latestRun.status = 'stopped'; + if (plugin.latestRun.host.status !== 'absent') + plugin.latestRun.host = { status: 'stopped', waitingFor: [] }; + if (plugin.latestRun.client.status !== 'absent') + plugin.latestRun.client = { status: 'stopped', waitingFor: [] }; + } + return { ok: true }; + } + /** + * Stop a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + async stopFromPanel(agent, pluginId) { + const result = await this.stop(agent, pluginId); + if (!result.ok) + return result; + const plugin = this.owned(agent, pluginId); + this.injectUserContext(agent, `The user stopped Cordis Plugin ${pluginId}. Its Packages remain defined; currentPackageId is ` + + `${plugin?.currentPackageId ?? 'none'}.`); + return result; + } + /** + * Replace the Host mirror of the Client inspect provider directory. + * @param providers - complete Client provider manifest. + * @returns null after accepting the manifest. + */ + syncInspectManifest(providers) { + this.inspectRegistry.syncClientManifest(providers); + return null; + } + /** + * Claim one pending Client inspect query with its live result. + * @param agent - Session that owns the query. + * @param requestId - exact pending query identity. + * @param resolution - provider result or structured refusal. + * @returns whether this answer won the query. + */ + resolveInspectQuery(agent, requestId, resolution) { + return this.inspectRegistry.resolveClientQuery(agent, requestId, resolution); + } + /** + * Frame-wide inventory, grouped as one row per stable Plugin. + * @returns Source-free metadata for every process-local Plugin. + */ + /* jscpd:ignore-start */ + inventory() { + return this.registry.all().map(plugin => ({ + pluginId: plugin.pluginId, + agentId: plugin.sessionId, + packages: [...plugin.packages.values()].map(definition => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== undefined, + hasClientHalf: definition.clientCode !== undefined, + })), + ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === undefined ? {} : { + activeRun: { pluginRunId: plugin.run.pluginRunId, packageId: plugin.run.packageId }, + }, + ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) }, + })); + } + /* jscpd:ignore-end */ + /** + * Read one Session's Host-rich state for inspection and result rendering. + * @param agent - Agent whose Session selects visible Plugins. + * @returns Plugin versions, active runs, Host fibers, and render failures. + */ + snapshot(agent) { + return this.registry.ofSession(agent.id).map(plugin => ({ + pluginId: plugin.pluginId, + ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId }, + packages: [...plugin.packages.values()].map(definition => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== undefined, + hasClientHalf: definition.clientCode !== undefined, + })), + ...plugin.run === undefined ? {} : { + activeRun: { + pluginRunId: plugin.run.pluginRunId, + packageId: plugin.run.packageId, + ...plugin.run.fiber === undefined ? {} : { fiber: plugin.run.fiber }, + handlers: [...plugin.run.handlers.keys()], + ...plugin.run.renderFailure === undefined ? {} : { renderFailure: plugin.run.renderFailure }, + }, + }, + ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) }, + })); + } + /** + * Read source-free context for an explicit `@pluginId` user gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity referenced by the user. + * @returns The preferred modification base, or undefined when unavailable. + */ + reference(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + return undefined; + const packageId = plugin.nextPackageId + ?? plugin.currentPackageId + ?? [...plugin.packages.keys()].at(-1); + if (packageId === undefined) + return undefined; + const definition = plugin.packages.get(packageId); + if (definition === undefined) + return undefined; + return { + pluginId, + packageId, + name: definition.name, + purpose: definition.purpose, + ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === undefined ? {} : { + activeRun: { pluginRunId: plugin.run.pluginRunId, packageId: plugin.run.packageId }, + }, + ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) }, + }; + } + /** + * List source-free Plugin summaries owned by one Session. + * @param agent - Agent whose Session selects visible Plugins. + * @returns one summary per Plugin in creation order. + */ + listPlugins(agent) { + return this.registry.ofSession(agent.id).map(plugin => this.inspectPlugin(agent, plugin.pluginId)); + } + /** + * Inspect one Plugin without returning Package source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - stable Plugin identity. + * @returns version pointers, latest run, and all Package summaries. + */ + inspectPlugin(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + throw new Error(missingPluginMessage(pluginId)); + const reference = this.reference(agent, pluginId); + if (reference === undefined) + throw new Error(`dynamic plugin "${pluginId}" has no package`); + return { + ...reference, + packages: [...plugin.packages.values()].map(definition => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== undefined, + hasClientHalf: definition.clientCode !== undefined, + })), + }; + } + /** + * Read one exact immutable Package and its Host and Client source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that owns the Package. + * @param packageId - Exact immutable Package identity to inspect. + * @returns Package metadata, source, and the Plugin's lifecycle pointers. + */ + inspectPackage(agent, pluginId, packageId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + throw new Error(missingPluginMessage(pluginId)); + const definition = plugin.packages.get(packageId); + if (definition === undefined) { + throw new Error(`dynamic package "${packageId}" does not exist on plugin "${pluginId}"`); + } + return { + pluginId, + packageId, + name: definition.name, + purpose: definition.purpose, + code: { + ...definition.hostCode === undefined ? {} : { host: definition.hostCode }, + ...definition.clientCode === undefined ? {} : { client: definition.clientCode }, + }, + /* jscpd:ignore-start */ + ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === undefined ? {} : { + activeRun: { pluginRunId: plugin.run.pluginRunId, packageId: plugin.run.packageId }, + }, + ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) }, + /* jscpd:ignore-end */ + }; + } + /** + * Record a post-load render failure for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that rendered. + * @param pluginRunId - Exact active run that produced the failure. + * @param failure - Slot, message, and entry-retirement result. + * @returns Null after recording or ignoring a stale report. + */ + async reportRenderFailure(agent, pluginId, pluginRunId, failure) { + const plugin = this.owned(agent, pluginId); + if (plugin?.run?.pluginRunId === pluginRunId) { + const run = plugin.run; + const definition = plugin.packages.get(plugin.run.packageId); + const shouldSteer = run.renderFailure === undefined; + run.renderFailure = failure; + const attempt = plugin.latestRun; + if (attempt?.pluginRunId === pluginRunId) { + attempt.error = this.diagnostic(plugin, attempt, 'client-render', failure); + attempt.client = { status: 'failed', waitingFor: attempt.client.waitingFor, error: failure.message }; + attempt.status = 'failed'; + } + if (definition !== undefined && shouldSteer) { + this.steerRenderFailure(agent, plugin, definition, pluginRunId, failure); + } + } + return await Promise.resolve(null); + } + /** + * Report a Client guard rejection that happened after the Package completed activation. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity whose Client code was rejected. + * @param pluginRunId - Exact active run that produced the rejection. + * @param failure - Original guard message and stack. + * @returns Null after reporting or ignoring a stale/startup failure. + */ + async reportClientGuardFailure(agent, pluginId, pluginRunId, failure) { + const plugin = this.owned(agent, pluginId); + const run = plugin?.run; + if (plugin !== undefined && run?.pluginRunId === pluginRunId) { + this.steerGuardFailure(plugin, run, 'Client', failure); + } + return await Promise.resolve(null); + } + /** + * Invoke an active Host method while rejecting stale Client runs. + * @param pluginId - Stable Plugin identity that owns the method. + * @param pluginRunId - Exact active run authorizing the call. + * @param method - Registered Host handler name. + * @param args - JSON argument delivered to the handler. + * @returns The JSON result or a typed invocation failure. + */ + async invoke(pluginId, pluginRunId, method, args) { + const plugin = this.registry.get(pluginId); + if (plugin === undefined || plugin.run === undefined) { + return { ok: false, code: 'plugin-not-running', message: `dynamic plugin "${pluginId}" is not running` }; + } + const run = plugin.run; + if (run.pluginRunId !== pluginRunId) { + return { ok: false, code: 'stale-run', message: `activation "${pluginRunId}" is no longer active` }; + } + const handler = run.handlers.get(method); + if (handler === undefined) { + return { ok: false, code: 'method-not-found', message: `dynamic plugin "${pluginId}" registered no Host method "${method}"` }; + } + try { + return { ok: true, value: await handler(args) }; + } + catch (error) { + const failure = errorDetails(error); + this.steerHostHandlerFailure(plugin, run, method, failure); + return { ok: false, code: 'handler-error', ...failure }; + } + } + resolvePlan(agent, pluginId, packageId, mode, allowActiveAttach = false) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + return { ok: false, response: { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) } }; + const definition = plugin.packages.get(packageId); + if (definition === undefined) { + return { ok: false, response: { ok: false, reason: 'package-missing', message: `plugin "${pluginId}" has no package "${packageId}"` } }; + } + const current = plugin.currentPackageId; + if (mode === 'update' && (current === undefined || current === packageId)) { + return { + ok: false, + response: { + ok: false, + reason: 'invalid-mode', + message: current === undefined + ? `plugin "${pluginId}" has no successful version yet; start "${packageId}" with mode "run"` + : `package "${packageId}" is already current; use mode "run"`, + }, + }; + } + if (mode === 'run' && current !== undefined && current !== packageId) { + return { + ok: false, + response: { + ok: false, + reason: 'invalid-mode', + message: `package "${packageId}" differs from current "${current}"; use mode "update"`, + }, + }; + } + if (!allowActiveAttach && this.starting.has(pluginId)) { + return { ok: false, response: { ok: false, reason: 'transition-in-flight', message: `plugin "${pluginId}" is already starting` } }; + } + return { ok: true, plugin, definition, mode }; + } + activate(plan, requestId, allowActiveAttach, attempt) { + const inFlight = this.starting.get(plan.plugin.pluginId); + if (inFlight !== undefined) + return inFlight; + const starting = this.startFresh(plan, requestId, allowActiveAttach, attempt); + this.starting.set(plan.plugin.pluginId, starting); + return starting.finally(() => { this.starting.delete(plan.plugin.pluginId); }); + } + async startFresh(plan, requestId, allowActiveAttach, attempt) { + const { plugin, definition, mode } = plan; + if (allowActiveAttach + && plugin.run?.packageId === definition.packageId + && plugin.run.pluginRunId === attempt.pluginRunId) { + return { + ok: true, + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: plugin.run.pluginRunId, + waitingFor: missingFor(this.ctx, plugin.run), + startedHere: false, + }; + } + if (plugin.run !== undefined) + await this.retract(plugin); + if (mode === 'update' || plugin.currentPackageId === undefined) + plugin.nextPackageId = definition.packageId; + const run = { + pluginRunId: attempt.pluginRunId, + packageId: definition.packageId, + handlers: new Map(), + handlerDisposers: [], + reportedRuntimeErrors: new Set(), + ...requestId === undefined ? {} : { startedForRequest: requestId }, + }; + if (definition.hostCode !== undefined) { + const failure = await this.startHost(plugin, definition.hostCode, run); + if (failure !== undefined) + return { ok: false, ...failure }; + } + plugin.run = run; + this.ctx.emit('cordis/dynamic-package', { + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: run.pluginRunId, + name: definition.name, + }); + attempt.host = { + status: run.fiber === undefined ? 'absent' : missingFor(this.ctx, run).length === 0 ? 'running' : 'waiting', + waitingFor: missingFor(this.ctx, run), + }; + if (definition.clientCode === undefined) { + this.commitActivation(plugin, run); + } + else { + attempt.status = 'client-pending'; + attempt.client = { status: 'pending', waitingFor: [] }; + } + return { + ok: true, + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: run.pluginRunId, + waitingFor: missingFor(this.ctx, run), + startedHere: true, + }; + } + async startHost(plugin, hostCode, run) { + const handle = (method, fn) => { + const normalized = normalizeHandler(method, fn); + run.handlers.set(normalized.method, normalized.handler); + const dispose = () => { + if (run.handlers.get(normalized.method) === normalized.handler) + run.handlers.delete(normalized.method); + }; + run.handlerDisposers.push(dispose); + return dispose; + }; + try { + const sandbox = createSandbox(plugin.pluginId, { handle }); + const evaluated = await evaluateHostCode(sandbox, hostCode, plugin.pluginId, this.resolved.vmTimeoutMs); + if (!isPlugin(evaluated)) { + throw new Error(evaluated === undefined + ? 'the Host half returned `undefined` — did you forget `return`?' + : 'the Host half must return a Plugin function or an object with apply(ctx)'); + } + run.fiber = await startHostHalf(this.requireGroup(), evaluated, (error) => { this.steerGuardFailure(plugin, run, 'Host', errorDetails(error)); }); + return undefined; + } + catch (error) { + for (const dispose of run.handlerDisposers.splice(0)) + dispose(); + return errorDetails(error); + } + } + async settleActivation(plugin, resolution, requestId) { + if (plugin === undefined) + return { ok: false, reason: 'plugin-missing', message: 'the dynamic plugin was removed during activation' }; + const attempt = plugin.latestRun; + if (!resolution.ok) { + if (resolution.reason === 'rejected') { + if (attempt !== undefined) { + attempt.status = 'rejected'; + attempt.error = this.diagnostic(plugin, attempt, 'approval', resolution.message ?? 'the run request was declined'); + attempt.client = { status: 'stopped', waitingFor: [] }; + } + return { ok: false, reason: 'rejected', message: resolution.message ?? 'the run request was declined' }; + } + const run = plugin.run; + const ownsRun = run !== undefined + && resolution.pluginRunId === run.pluginRunId + && (requestId === undefined || run.startedForRequest === requestId) + && resolution.startedHere !== false; + if (ownsRun) + await this.retract(plugin); + if (attempt !== undefined && (resolution.pluginRunId === undefined || attempt.pluginRunId === resolution.pluginRunId)) { + this.failAttempt(plugin, attempt, resolution.reason === 'host-half-failed' ? 'host-apply' : 'client-apply', { + message: resolution.message ?? resolution.reason, + ...resolution.stack === undefined ? {} : { stack: resolution.stack }, + }); + } + return { + ok: false, + reason: resolution.reason, + message: resolution.message ?? resolution.reason, + ...resolution.stack === undefined ? {} : { stack: resolution.stack }, + }; + } + const run = plugin.run; + if (run === undefined || run.pluginRunId !== resolution.pluginRunId) { + return { ok: false, reason: 'client-half-failed', message: `activation "${resolution.pluginRunId}" is no longer active` }; + } + if (attempt !== undefined && attempt.pluginRunId === run.pluginRunId) { + attempt.client = { + status: resolution.waitingFor === undefined || resolution.waitingFor.length === 0 ? 'running' : 'waiting', + waitingFor: resolution.waitingFor ?? [], + }; + } + this.commitActivation(plugin, run); + return { + ...this.runResponse(plugin, { + ok: true, + pluginId: plugin.pluginId, + packageId: run.packageId, + pluginRunId: run.pluginRunId, + waitingFor: missingFor(this.ctx, run), + startedHere: false, + }), + ...resolution.waitingFor === undefined ? {} : { clientWaitingFor: resolution.waitingFor }, + }; + } + commitActivation(plugin, run) { + plugin.currentPackageId = run.packageId; + delete plugin.nextPackageId; + delete run.startedForRequest; + const attempt = plugin.latestRun; + if (attempt?.pluginRunId === run.pluginRunId) { + attempt.status = attempt.host.status === 'waiting' || attempt.client.status === 'waiting' ? 'waiting' : 'running'; + delete attempt.approvalRequestId; + delete attempt.requiresApproval; + delete attempt.error; + } + } + runResponse(plugin, started) { + return { + ok: true, + status: 'running', + pluginId: plugin.pluginId, + packageId: started.packageId, + pluginRunId: started.pluginRunId, + waitingFor: started.waitingFor, + currentPackageId: started.packageId, + mode: plugin.latestRun?.pluginRunId === started.pluginRunId ? plugin.latestRun.mode : 'run', + }; + } + announceResolved(requestId, resolution, override) { + const outcome = override ?? (resolution.ok ? 'approved' : resolution.reason === 'rejected' ? 'rejected' : 'failed'); + this.ctx.emit('cordis/request-run-resolved', { requestId, outcome }); + } + steerRunOutcome(pending, settled) { + const agents = this.rootCtx.get('agents'); + const agent = agents?.get(pending.agentId); + if (agent === undefined) + return; + const plugin = this.registry.get(pending.pluginId); + const identity = `${pending.pluginId}/${pending.packageId} (${pending.pluginRunId})`; + let text; + if (settled.ok) { + text = `Cordis ${pending.mode} ${identity} completed successfully. ` + + `currentPackageId is ${settled.currentPackageId ?? pending.packageId}. Continue using the running Plugin.`; + } + else if (settled.reason === 'rejected') { + text = `The user rejected Cordis ${pending.mode} ${identity}. ` + + 'Do not request the same activation again unless the user asks.'; + } + else { + const returnedStatus = pending.requiresApproval ? 'awaiting-approval' : 'starting'; + text = `Cordis ${pending.mode} ${identity} failed after cordis_run returned ${returnedStatus}: ` + + `${settled.reason}\n${formatErrorDetails(settled)}\n` + + `currentPackageId: ${plugin?.currentPackageId ?? 'none'}\n` + + `nextPackageId: ${plugin?.nextPackageId ?? pending.packageId}\n` + + 'Inspect the failed Package, correct it on the same Plugin when needed, and retry the activation autonomously.'; + } + agent.steer(createUserMessage({ + content: [{ type: 'text', text }], + source: { kind: 'plugin', plugin: 'cordis-host-runner' }, + })); + } + steerRenderFailure(agent, plugin, definition, pluginRunId, failure) { + agent.steer(createUserMessage({ + content: [{ + type: 'text', + text: `Cordis Client UI ${plugin.pluginId}/${definition.packageId} (${pluginRunId}) failed while rendering ` + + `Slot "${failure.slot}" after activation.\n` + + `${formatErrorDetails(failure)}\n` + + `entryAbdicated: ${failure.abdicated}\n` + + 'Inspect the failed Package, fix the Client code by defining a new Package on the same Plugin, and ' + + 'activate that Package autonomously with cordis_run mode:"update".', + }], + source: { kind: 'plugin', plugin: 'cordis-host-runner' }, + })); + } + steerHostHandlerFailure(plugin, run, method, failure) { + const reportKey = `Host\u0000handler\u0000${method}\u0000${failure.message}`; + if (!this.claimRuntimeFailure(plugin, run, reportKey)) + return; + const agents = this.rootCtx.get('agents'); + const agent = agents?.get(plugin.sessionId); + if (agent === undefined) + return; + agent.steer(createUserMessage({ + content: [{ + type: 'text', + text: `Cordis Host handler ${plugin.pluginId}/${run.packageId} (${run.pluginRunId}) failed when the Client called ` + + `host.call(${JSON.stringify(method)}).\n` + + `${formatErrorDetails(failure)}\n` + + 'The Plugin remains running. Inspect this Package, correct the Host code on the same Plugin, and activate ' + + 'the new Package autonomously with cordis_run mode:"update". If the handler needs a Service, either declare ' + + 'that Service in the returned Plugin inject list or read it with ctx.get(name) and handle undefined.', + }], + source: { kind: 'plugin', plugin: 'cordis-host-runner' }, + })); + } + /* jscpd:ignore-start */ + steerGuardFailure(plugin, run, platform, failure) { + const reportKey = `${platform}\u0000guard\u0000${failure.message}`; + if (!this.claimRuntimeFailure(plugin, run, reportKey)) + return; + const agents = this.rootCtx.get('agents'); + const agent = agents?.get(plugin.sessionId); + if (agent === undefined) + return; + agent.steer(createUserMessage({ + content: [{ + type: 'text', + text: `Cordis ${platform} guard rejected runtime code in ${plugin.pluginId}/${run.packageId} ` + + `(${run.pluginRunId}) after activation.\n${formatErrorDetails(failure)}\n` + + 'The Plugin remains running. Inspect this Package, define a corrected Package on the same Plugin, and ' + + 'activate it autonomously with cordis_run mode:"update".', + }], + source: { kind: 'plugin', plugin: 'cordis-host-runner' }, + })); + } + /* jscpd:ignore-end */ + claimRuntimeFailure(plugin, run, key) { + const attempt = plugin.latestRun; + if (plugin.run !== run || attempt?.pluginRunId !== run.pluginRunId + || (attempt.status !== 'running' && attempt.status !== 'waiting')) + return false; + if (run.reportedRuntimeErrors.has(key)) + return false; + run.reportedRuntimeErrors.add(key); + return true; + } + injectUserRunOutcome(agent, pluginId, settled) { + const plugin = this.owned(agent, pluginId); + let text; + if (settled.ok) { + text = `The user manually ran Cordis Plugin ${pluginId}, Package ${settled.packageId}, ` + + `as ${settled.pluginRunId}. The activation succeeded; currentPackageId is ${settled.currentPackageId}.`; + } + else { + const attempt = plugin?.latestRun; + text = `The user manually ran Cordis Plugin ${pluginId}` + + `${attempt === undefined ? '' : `, Package ${attempt.packageId}, as ${attempt.pluginRunId}`}, but it failed: ` + + `${settled.reason}\n${formatErrorDetails(settled)}\n` + + `currentPackageId: ${plugin?.currentPackageId ?? 'none'}\n` + + `nextPackageId: ${plugin?.nextPackageId ?? 'none'}`; + } + this.injectUserContext(agent, text); + } + injectUserContext(agent, text) { + const agents = this.rootCtx.get('agents'); + if (agents?.get(agent.id) !== agent) + return; + agent.inject(createUserMessage({ + content: [{ type: 'text', text }], + source: { kind: 'plugin', plugin: 'cordis-host-runner' }, + })); + } + cancelPending(pluginId, message) { + const requestId = this.registry.pendingRequestFor(pluginId); + if (requestId === undefined) + return; + const pending = this.registry.claimRequest(requestId); + if (pending === undefined) + return; + const plugin = this.registry.get(pluginId); + if (plugin?.latestRun?.pluginRunId === pending.pluginRunId) { + plugin.latestRun.status = 'cancelled'; + plugin.latestRun.error = this.diagnostic(plugin, plugin.latestRun, 'approval', message); + delete plugin.latestRun.approvalRequestId; + delete plugin.latestRun.requiresApproval; + } + this.announceResolved(requestId, { ok: false, reason: 'rejected' }, 'cancelled'); + } + createAttempt(plan) { + return { + pluginRunId: CordisDynamicPluginRunId(this.registry.mintPluginRunId()), + packageId: plan.definition.packageId, + mode: plan.mode, + status: 'starting-host', + host: { + status: plan.definition.hostCode === undefined ? 'absent' : 'pending', + waitingFor: [], + }, + client: { + status: plan.definition.clientCode === undefined ? 'absent' : 'pending', + waitingFor: [], + }, + }; + } + failAttempt(plugin, attempt, phase, failure) { + attempt.status = 'failed'; + attempt.error = this.diagnostic(plugin, attempt, phase, failure); + if (phase.startsWith('host')) + attempt.host = { status: 'failed', waitingFor: [], error: failure.message }; + else + attempt.client = { status: 'failed', waitingFor: [], error: failure.message }; + } + diagnostic(plugin, attempt, phase, failure) { + const details = typeof failure === 'string' ? { message: failure } : failure; + return { + phase, + ...details, + pluginId: plugin.pluginId, + packageId: attempt.packageId, + pluginRunId: attempt.pluginRunId, + }; + } + async retract(plugin) { + const run = plugin.run; + if (run === undefined) + return; + delete plugin.run; + for (const dispose of run.handlerDisposers.splice(0)) + dispose(); + if (run.fiber !== undefined) + await run.fiber.dispose(); + this.ctx.emit('cordis/dynamic-retract', { + pluginId: plugin.pluginId, + packageId: run.packageId, + pluginRunId: run.pluginRunId, + }); + } + owned(agent, pluginId) { + const plugin = this.registry.get(pluginId); + return plugin?.sessionId === agent.id ? plugin : undefined; + } + requireGroup() { + this.group ??= this.rootCtx.plugin({ name: 'cordis-dynamic', apply: () => { } }); + return this.group; + } + }; +})(); +export { DynamicCordisRunnerService }; +function missingFor(ctx, run) { + return run.fiber === undefined ? [] : missingServices(ctx, run.fiber); +} +function missingPluginMessage(id) { + return `no dynamic plugin "${id}" in this process — it may have been removed or lost on DSH restart`; +} +function errorDetails(error) { + if (typeof error !== 'object' || error === null) + return { message: String(error) }; + const message = 'message' in error && typeof error.message === 'string' + ? error.message + : Object.prototype.toString.call(error); + const stack = 'stack' in error && typeof error.stack === 'string' ? error.stack : undefined; + return { message, ...stack === undefined ? {} : { stack } }; +} +function formatErrorDetails(failure) { + return `message: ${failure.message}` + + (failure.stack === undefined ? '' : `\nstack:\n${failure.stack}`); +} +function cloneAttempt(attempt) { + return { + ...attempt, + host: { ...attempt.host, waitingFor: [...attempt.host.waitingFor] }, + client: { ...attempt.client, waitingFor: [...attempt.client.waitingFor] }, + ...attempt.error === undefined ? {} : { error: { ...attempt.error } }, + }; +} +export default DynamicCordisRunnerService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.d.ts new file mode 100644 index 0000000..cb382e2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.d.ts @@ -0,0 +1,72 @@ +/** Host registry for model-visible, read-only Cordis capability queries. */ +import { Service } from '@deepseek-ai/cordis'; +import type { Context } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { JsonValue } from '@deepseek-ai/dsh-session/types'; +import type { CordisInspectPlatform, CordisInspectProviderManifest, CordisInspectProviderView, CordisInspectQueryResolution, CordisInspectRequestId, CordisInspectResolveAck } from './types.ts'; +/** Context supplied to a Host inspect query. */ +export interface HostCordisInspectQueryContext { + /** Tool-call cancellation. */ + signal: AbortSignal; + /** Agent whose scoped runtime is being inspected. */ + agent: Agent; +} +/** Local registration paired with its serializable manifest. */ +export interface HostCordisInspectProviderRegistration { + /** Provider and explicit method directory. */ + manifest: CordisInspectProviderManifest; + /** Execute one declared method. */ + query(method: string, input: JsonValue | undefined, context: HostCordisInspectQueryContext): Promise; +} +declare module '@deepseek-ai/cordis' { + interface Context { + /** Host registry for Cordis inspect providers and Client manifest/query routing. */ + cordisInspect: CordisInspectRegistryService; + } +} +/** Registry and cross-page router behind the two model-facing inspect tools. */ +export declare class CordisInspectRegistryService extends Service { + private readonly providers; + private readonly pending; + private clientManifest; + private nextRequest; + /** Register the process-global Host registry. */ + constructor(ctx: Context); + /** + * Register one Host provider. + * @param registration - manifest and local query handler. + * @returns idempotent disposer. + */ + register(registration: HostCordisInspectProviderRegistration): () => void; + /** + * Replace the mirrored Client provider directory. + * @param providers - complete Client manifest snapshot. + */ + syncClientManifest(providers: readonly CordisInspectProviderManifest[]): void; + /** + * Return the complete known Host and Client provider directory. + * @returns Host providers followed by the Client providers. + */ + list(): CordisInspectProviderView[]; + /** + * Execute one provider query on its owning platform. + * @param platform - Host or Client runtime. + * @param providerId - provider selected from {@link list}. + * @param methodName - declared method name. + * @param input - optional lossless JSON input. + * @param agent - requesting Agent and scope. + * @param signal - tool-call cancellation. + * @returns provider JSON data. + */ + query(platform: CordisInspectPlatform, providerId: string, methodName: string, input: JsonValue | undefined, agent: Agent, signal: AbortSignal): Promise; + /** + * Accept the first valid Client response for a pending query. + * @param agent - Agent whose Session owns the query. + * @param requestId - Pending Client query identity. + * @param resolution - Client provider result or failure. + * @returns whether this response settled the still-pending query. + */ + resolveClientQuery(agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution): CordisInspectResolveAck; + private queryClient; +} +//# sourceMappingURL=inspect-registry.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.js new file mode 100644 index 0000000..09dd1ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.js @@ -0,0 +1,192 @@ +/** Host registry for model-visible, read-only Cordis capability queries. */ +import { Service } from '@deepseek-ai/cordis'; +import { snapshotJsonValue } from '@deepseek-ai/dsh-session'; +import { assertSupportedJsonSchema, validateJsonSchemaValue } from '@deepseek-ai/dsh-tools'; +/** Registry and cross-page router behind the two model-facing inspect tools. */ +export class CordisInspectRegistryService extends Service { + providers = new Map(); + pending = new Map(); + clientManifest; + nextRequest = 1; + /** Register the process-global Host registry. */ + constructor(ctx) { + super(ctx, 'cordisInspect'); + } + /** + * Register one Host provider. + * @param registration - manifest and local query handler. + * @returns idempotent disposer. + */ + register(registration) { + const manifest = validateManifest(registration.manifest); + if (this.providers.has(manifest.id)) + throw new Error(`Host Cordis inspect provider "${manifest.id}" is already registered`); + const stored = { ...registration, manifest }; + this.providers.set(manifest.id, stored); + return () => { + if (this.providers.get(manifest.id) === stored) + this.providers.delete(manifest.id); + }; + } + /** + * Replace the mirrored Client provider directory. + * @param providers - complete Client manifest snapshot. + */ + syncClientManifest(providers) { + const ids = new Set(); + const validated = providers.map((provider) => { + const manifest = validateManifest(provider); + if (ids.has(manifest.id)) + throw new Error(`Client Cordis inspect manifest repeats provider "${manifest.id}"`); + ids.add(manifest.id); + return manifest; + }); + this.clientManifest = Object.freeze(validated); + } + /** + * Return the complete known Host and Client provider directory. + * @returns Host providers followed by the Client providers. + */ + list() { + return [ + ...[...this.providers.values()].map(provider => view('host', provider.manifest)), + ...(this.clientManifest ?? []).map(provider => view('client', provider)), + ]; + } + /** + * Execute one provider query on its owning platform. + * @param platform - Host or Client runtime. + * @param providerId - provider selected from {@link list}. + * @param methodName - declared method name. + * @param input - optional lossless JSON input. + * @param agent - requesting Agent and scope. + * @param signal - tool-call cancellation. + * @returns provider JSON data. + */ + async query(platform, providerId, methodName, input, agent, signal) { + if (platform === 'host') { + const registration = this.providers.get(providerId); + if (registration === undefined) + throw new Error(`Host Cordis inspect provider "${providerId}" is not registered`); + const method = findMethod(registration.manifest, methodName); + validateInput('Host', providerId, method, input); + signal.throwIfAborted(); + const data = await registration.query(methodName, input, { agent, signal }); + signal.throwIfAborted(); + return validateOutput('Host', providerId, method, data); + } + return await this.queryClient(providerId, methodName, input, agent, signal); + } + /** + * Accept the first valid Client response for a pending query. + * @param agent - Agent whose Session owns the query. + * @param requestId - Pending Client query identity. + * @param resolution - Client provider result or failure. + * @returns whether this response settled the still-pending query. + */ + resolveClientQuery(agent, requestId, resolution) { + const pending = this.pending.get(requestId); + if (pending === undefined || pending.request.agentId !== agent.id) + return { accepted: false }; + if (!resolution.ok) + return { accepted: false }; + try { + resolution = { + ok: true, + data: validateOutput('Client', pending.request.provider, pending.method, resolution.data), + }; + } + catch { + return { accepted: false }; + } + this.pending.delete(requestId); + pending.settle(resolution); + this.ctx.emit('cordis/inspect-query-resolved', { requestId }); + return { accepted: true }; + } + async queryClient(providerId, methodName, input, agent, signal) { + const provider = this.clientManifest?.find(candidate => candidate.id === providerId); + if (provider === undefined) + throw new Error(`Client Cordis inspect provider "${providerId}" is not registered`); + const method = findMethod(provider, methodName); + validateInput('Client', providerId, method, input); + signal.throwIfAborted(); + const requestId = `inspect-${this.nextRequest++}`; + const request = { + requestId, + agentId: agent.id, + provider: providerId, + method: methodName, + ...input === undefined ? {} : { input }, + }; + const result = new Promise((resolve) => { + this.pending.set(requestId, { request, method, settle: resolve }); + }); + const onAbort = () => { + const pending = this.pending.get(requestId); + if (pending === undefined) + return; + this.pending.delete(requestId); + pending.settle({ ok: false, reason: 'cancelled', message: `Client inspect query ${providerId}.${methodName} was cancelled` }); + this.ctx.emit('cordis/inspect-query-resolved', { requestId }); + }; + signal.addEventListener('abort', onAbort, { once: true }); + if (signal.aborted) + onAbort(); + else + this.ctx.emit('cordis/inspect-query', request); + try { + const resolution = await result; + if (!resolution.ok) + throw new Error(`${providerId}.${methodName}: ${resolution.message}`); + return resolution.data; + } + finally { + signal.removeEventListener('abort', onAbort); + } + } +} +function view(platform, manifest) { + return { platform, ...manifest, methods: [...manifest.methods] }; +} +function validateManifest(manifest) { + if (manifest.id.trim() === '') + throw new Error('Cordis inspect provider id must not be empty'); + if (manifest.description.trim() === '') + throw new Error(`Cordis inspect provider "${manifest.id}" needs a description`); + const names = new Set(); + const methods = manifest.methods.map((method) => { + if (method.name.trim() === '') + throw new Error(`Cordis inspect provider "${manifest.id}" has an empty method name`); + if (names.has(method.name)) + throw new Error(`Cordis inspect provider "${manifest.id}" repeats method "${method.name}"`); + if (method.description.trim() === '') + throw new Error(`Cordis inspect method ${manifest.id}.${method.name} needs a description`); + assertSupportedJsonSchema(method.inputSchema); + assertSupportedJsonSchema(method.outputSchema); + names.add(method.name); + return Object.freeze({ ...method }); + }); + return Object.freeze({ ...manifest, methods: Object.freeze(methods) }); +} +function findMethod(manifest, name) { + const method = manifest.methods.find(candidate => candidate.name === name); + if (method === undefined) + throw new Error(`Cordis inspect provider "${manifest.id}" has no method "${name}"`); + return method; +} +function validateInput(platform, provider, method, input) { + const violations = validateJsonSchemaValue(method.inputSchema, input ?? {}, 'input'); + if (violations.length > 0) + throw new Error(`${platform} Cordis inspect ${provider}.${method.name} rejected input: ${violations.join('; ')}`); +} +function validateOutput(platform, provider, method, data) { + const snapshot = snapshotJsonValue(data); + if (snapshot === undefined) + throw new Error(`${platform} Cordis inspect ${provider}.${method.name} returned a non-JSON value`); + const violations = validateJsonSchemaValue(method.outputSchema, snapshot, 'output'); + if (violations.length > 0) + throw new Error(`${platform} Cordis inspect ${provider}.${method.name} returned invalid output: ${violations.join('; ')}`); + return snapshot; +} +//# sourceMappingURL=inspect-registry.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.d.ts new file mode 100644 index 0000000..fa92e19 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-cordis-host-runner`. + * @module @deepseek-ai/dsh-cordis-host-runner/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "cordis-host-runner-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.js new file mode 100644 index 0000000..72eaebd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.js @@ -0,0 +1,24 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-cordis-host-runner`. + * @module @deepseek-ai/dsh-cordis-host-runner/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-cordis-host-runner'; +/** Cordis companion plugin name. */ +export const name = 'cordis-host-runner-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: the definition registry is process memory with no event + * stream to observe, and its one owned relation (a running definition owns a + * settled host-half fiber and its handler table) is established and unwound + * inside single awaited verbs, so package tests assert it directly. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.d.ts new file mode 100644 index 0000000..8ce183f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.d.ts @@ -0,0 +1,29 @@ +/** + * Host-half fiber lifecycle over the `cordis-dynamic` group: settle a + * sandbox-produced plugin as a child fiber (never leaving a failed fiber + * mounted), and report the services a settled-but-pending fiber still waits + * for. Stopping needs no helper — a host half unwinds through an ordinary + * awaited `fiber.dispose()`, because everything the plugin registered is an + * effect on its fiber. + * @module @deepseek-ai/dsh-cordis-host-runner/lifecycle + */ +import type { Context, Fiber, Plugin } from '@deepseek-ai/cordis'; +/** + * Await the group, start and settle one guarded child, and dispose it before rethrowing any + * startup failure so a failed run never lingers. A valid unresolved inject may remain pending. + * @param group - the `cordis-dynamic` group fiber every host half hangs under. + * @param plugin - the plugin the sandbox returned; wrapped with the registration guard before starting. + * @param reportGuardFailure - reports post-activation Host guard rejections to the owning Agent. + * @returns the settled child fiber (possibly pending on unsatisfied `inject`). + */ +export declare function startHostHalf(group: Fiber, plugin: Plugin, reportGuardFailure: (error: Error) => void): Promise; +/** + * The services a fiber declared in `inject` that do not exist yet — a settled + * fiber that is not active is waiting on exactly these (legal cordis + * semantics: it activates when the service appears). + * @param ctx - the context to resolve service existence against. + * @param fiber - the host-half fiber whose `inject` declarations are checked. + * @returns the missing service names, in declaration order. + */ +export declare function missingServices(ctx: Context, fiber: Fiber): string[]; +//# sourceMappingURL=lifecycle.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.js new file mode 100644 index 0000000..5449aee --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.js @@ -0,0 +1,49 @@ +/** + * Host-half fiber lifecycle over the `cordis-dynamic` group: settle a + * sandbox-produced plugin as a child fiber (never leaving a failed fiber + * mounted), and report the services a settled-but-pending fiber still waits + * for. Stopping needs no helper — a host half unwinds through an ordinary + * awaited `fiber.dispose()`, because everything the plugin registered is an + * effect on its fiber. + * @module @deepseek-ai/dsh-cordis-host-runner/lifecycle + */ +import { guardedPlugin } from "./guard.js"; +/** + * Await the group, start and settle one guarded child, and dispose it before rethrowing any + * startup failure so a failed run never lingers. A valid unresolved inject may remain pending. + * @param group - the `cordis-dynamic` group fiber every host half hangs under. + * @param plugin - the plugin the sandbox returned; wrapped with the registration guard before starting. + * @param reportGuardFailure - reports post-activation Host guard rejections to the owning Agent. + * @returns the settled child fiber (possibly pending on unsatisfied `inject`). + */ +export async function startHostHalf(group, plugin, reportGuardFailure) { + await group.await(); + const fiber = group.ctx.plugin(guardedPlugin(plugin, reportGuardFailure)); + try { + await fiber.await(); + } + catch (error) { + await fiber.dispose(); + const message = error instanceof Error ? error.message : String(error); + // The commonest startup collision is running a NEW version of a package + // while the old run still holds the name — teach the replace recipe. + if (message.includes('already registered')) { + throw new Error(`${message} — to REPLACE something an earlier dynamic package registered, first cordis_stop that package's id ` + + '(find it with cordis_runtime_inspect what:"temporary"), then run the new version.'); + } + throw error instanceof Error ? error : new Error(message); + } + return fiber; +} +/** + * The services a fiber declared in `inject` that do not exist yet — a settled + * fiber that is not active is waiting on exactly these (legal cordis + * semantics: it activates when the service appears). + * @param ctx - the context to resolve service existence against. + * @param fiber - the host-half fiber whose `inject` declarations are checked. + * @returns the missing service names, in declaration order. + */ +export function missingServices(ctx, fiber) { + return Object.keys(fiber.inject).filter(service => ctx.get(service) === undefined); +} +//# sourceMappingURL=lifecycle.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.d.ts new file mode 100644 index 0000000..9a27112 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.d.ts @@ -0,0 +1,225 @@ +/** + * Process-local dynamic Plugin registry and its opaque identity mints. + * @module @deepseek-ai/dsh-cordis-host-runner/registry + */ +import type { Fiber } from '@deepseek-ai/cordis'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { ApprovalRequestId, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisDynamicRunMode, DynamicCordisRenderFailure, DynamicCordisRunAttempt } from './types.ts'; +/** One Host method exposed to this package's Client half. */ +export type DynamicCordisHandler = (args: unknown) => Promise; +/** One live activation and everything its teardown owns. */ +export interface DynamicCordisRun { + /** Exact activation identity. */ + pluginRunId: CordisDynamicPluginRunId; + /** Immutable package version being run. */ + packageId: CordisDynamicPackageId; + /** Host-half Fiber, absent for Client-only packages. */ + fiber?: Fiber; + /** Active Host methods. */ + handlers: Map; + /** Method registration cleanup. */ + handlerDisposers: (() => void)[]; + /** Runtime failures already sent to the owning Agent during this activation. */ + reportedRuntimeErrors: Set; + /** Last render failure observed for this version's current run. */ + renderFailure?: DynamicCordisRenderFailure; + /** Approval whose transition started this run, when model-driven. */ + startedForRequest?: ApprovalRequestId; +} +/** One immutable package version. */ +export interface DynamicCordisDefinition { + /** Package identity. */ + packageId: CordisDynamicPackageId; + /** Package label. */ + name: string; + /** User-facing purpose. */ + purpose: string; + /** Host source. */ + hostCode?: string; + /** Client source. */ + clientCode?: string; +} +/** Stable plugin instance containing immutable package versions. */ +export interface DynamicCordisPlugin { + /** Stable identity. */ + pluginId: CordisDynamicPluginId; + /** Owning session. */ + sessionId: SessionId; + /** Versions in define order. */ + packages: Map; + /** Client-bearing Packages individually authorized by the user. */ + approvedClientPackages: Set; + /** Whether one user decision authorized future Package versions of this Plugin. */ + clientVersionUpdatesApproved: boolean; + /** Last successfully activated version. */ + currentPackageId?: CordisDynamicPackageId; + /** Failed or in-progress target version. */ + nextPackageId?: CordisDynamicPackageId; + /** Current activation. */ + run?: DynamicCordisRun; + /** Latest activation attempt, including approval and asynchronous failure state. */ + latestRun?: DynamicCordisRunAttempt; +} +/** One suspended model-driven activation. */ +export interface DynamicCordisPendingRequest { + /** Session whose model requested this activation. */ + agentId: SessionId; + pluginId: CordisDynamicPluginId; + packageId: CordisDynamicPackageId; + pluginRunId: CordisDynamicPluginRunId; + mode: CordisDynamicRunMode; + /** Whether this request must wait for an explicit user decision. */ + requiresApproval: boolean; +} +/** Request accepted by `define`; it never crosses the Remote transport. */ +export interface DynamicCordisDefineRequest { + /** Session that owns the plugin. */ + sessionId: SessionId; + /** Create a plugin or append to an existing one. */ + plugin: { + kind: 'new'; + idPrefix: string; + } | { + kind: 'existing'; + pluginId: CordisDynamicPluginId; + }; + /** Package label. */ + name: string; + /** User-facing purpose. */ + purpose: string; + /** At least one source half. */ + code: { + host?: string; + client?: string; + }; +} +/** Successful `define` result. */ +export interface DynamicCordisDefineReceipt { + pluginId: CordisDynamicPluginId; + packageId: CordisDynamicPackageId; + name: string; + purpose: string; + hasHostHalf: boolean; + hasClientHalf: boolean; +} +/** Source-free modification context for an explicit `@pluginId` reference. */ +export interface DynamicCordisReference { + pluginId: CordisDynamicPluginId; + packageId: CordisDynamicPackageId; + name: string; + purpose: string; + currentPackageId?: CordisDynamicPackageId; + nextPackageId?: CordisDynamicPackageId; + activeRun?: { + pluginRunId: CordisDynamicPluginRunId; + packageId: CordisDynamicPackageId; + }; + latestRun?: DynamicCordisRunAttempt; +} +/** Source-free Plugin summary returned by layered self inspection. */ +export interface DynamicCordisPluginInspection extends DynamicCordisReference { + /** Immutable Package summaries in define order. */ + packages: Array<{ + packageId: CordisDynamicPackageId; + name: string; + purpose: string; + hasHostHalf: boolean; + hasClientHalf: boolean; + }>; +} +/** Exact immutable Package metadata and source returned by explicit inspection. */ +export interface DynamicCordisPackageInspection extends DynamicCordisReference { + /** Host and Client function bodies stored for this Package. */ + code: { + host?: string; + client?: string; + }; +} +/** Registry, identity mints, and pending approval index. */ +export declare class DynamicCordisRegistry { + private readonly plugins; + private readonly pendingRequests; + private nextPlugin; + private nextPackage; + private nextRun; + private nextApproval; + /** + * Mint a semantic plugin ID without reusing a prior suffix. + * @param prefix - validated lowercase semantic prefix proposed by the model. + * @returns a process-unique Plugin ID. + */ + mintPluginId(prefix: string): string; + /** + * Mint an immutable package ID. + * @returns a process-unique Package ID. + */ + mintPackageId(): string; + /** + * Mint an activation ID. + * @returns a process-unique Plugin Run ID. + */ + mintPluginRunId(): string; + /** + * Mint an approval ID. + * @returns a process-unique approval request ID. + */ + mintApprovalRequestId(): string; + /** + * Add one stable plugin. + * @param plugin - Plugin record to retain under its stable ID. + */ + add(plugin: DynamicCordisPlugin): void; + /** + * Read one plugin. + * @param id - stable Plugin ID. + * @returns the Plugin record, or `undefined` when absent. + */ + get(id: CordisDynamicPluginId): DynamicCordisPlugin | undefined; + /** + * Delete one plugin and all package versions. + * @param id - stable Plugin ID to remove. + * @returns whether a Plugin record was removed. + */ + delete(id: CordisDynamicPluginId): boolean; + /** + * Read all plugins in creation order. + * @returns a snapshot of every Plugin record. + */ + all(): DynamicCordisPlugin[]; + /** + * Read one session's plugins in creation order. + * @param sessionId - owning session to filter by. + * @returns a snapshot of matching Plugin records. + */ + ofSession(sessionId: SessionId): DynamicCordisPlugin[]; + /** + * Publish one pending approval. + * @param id - approval request ID. + * @param pending - resolver and Plugin metadata retained until settlement. + */ + armRequest(id: ApprovalRequestId, pending: DynamicCordisPendingRequest): void; + /** + * Read one pending approval without claiming it. + * @param id - approval request ID. + * @returns the pending request, or `undefined` when absent. + */ + peekRequest(id: ApprovalRequestId): DynamicCordisPendingRequest | undefined; + /** + * Claim one pending approval; first answer wins. + * @param id - approval request ID. + * @returns the claimed request, or `undefined` when already settled. + */ + claimRequest(id: ApprovalRequestId): DynamicCordisPendingRequest | undefined; + /** + * Cancel one pending approval. + * @param id - approval request ID to remove. + */ + disarmRequest(id: ApprovalRequestId): void; + /** + * Find a pending approval for one Plugin. + * @param pluginId - stable Plugin ID. + * @returns its approval request ID, or `undefined` when none is pending. + */ + pendingRequestFor(pluginId: CordisDynamicPluginId): ApprovalRequestId | undefined; +} +//# sourceMappingURL=registry.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.js new file mode 100644 index 0000000..cec4863 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.js @@ -0,0 +1,131 @@ +/** + * Process-local dynamic Plugin registry and its opaque identity mints. + * @module @deepseek-ai/dsh-cordis-host-runner/registry + */ +/** Registry, identity mints, and pending approval index. */ +export class DynamicCordisRegistry { + plugins = new Map(); + pendingRequests = new Map(); + nextPlugin = 1; + nextPackage = 1; + nextRun = 1; + nextApproval = 1; + /** + * Mint a semantic plugin ID without reusing a prior suffix. + * @param prefix - validated lowercase semantic prefix proposed by the model. + * @returns a process-unique Plugin ID. + */ + mintPluginId(prefix) { + let id; + do + id = `${prefix}-${this.nextPlugin++}`; + while (this.plugins.has(id)); + return id; + } + /** + * Mint an immutable package ID. + * @returns a process-unique Package ID. + */ + mintPackageId() { + return `pkg-${this.nextPackage++}`; + } + /** + * Mint an activation ID. + * @returns a process-unique Plugin Run ID. + */ + mintPluginRunId() { + return `run-${this.nextRun++}`; + } + /** + * Mint an approval ID. + * @returns a process-unique approval request ID. + */ + mintApprovalRequestId() { + return `approval-${this.nextApproval++}`; + } + /** + * Add one stable plugin. + * @param plugin - Plugin record to retain under its stable ID. + */ + add(plugin) { + this.plugins.set(plugin.pluginId, plugin); + } + /** + * Read one plugin. + * @param id - stable Plugin ID. + * @returns the Plugin record, or `undefined` when absent. + */ + get(id) { + return this.plugins.get(id); + } + /** + * Delete one plugin and all package versions. + * @param id - stable Plugin ID to remove. + * @returns whether a Plugin record was removed. + */ + delete(id) { + return this.plugins.delete(id); + } + /** + * Read all plugins in creation order. + * @returns a snapshot of every Plugin record. + */ + all() { + return [...this.plugins.values()]; + } + /** + * Read one session's plugins in creation order. + * @param sessionId - owning session to filter by. + * @returns a snapshot of matching Plugin records. + */ + ofSession(sessionId) { + return this.all().filter(plugin => plugin.sessionId === sessionId); + } + /** + * Publish one pending approval. + * @param id - approval request ID. + * @param pending - resolver and Plugin metadata retained until settlement. + */ + armRequest(id, pending) { + this.pendingRequests.set(id, pending); + } + /** + * Read one pending approval without claiming it. + * @param id - approval request ID. + * @returns the pending request, or `undefined` when absent. + */ + peekRequest(id) { + return this.pendingRequests.get(id); + } + /** + * Claim one pending approval; first answer wins. + * @param id - approval request ID. + * @returns the claimed request, or `undefined` when already settled. + */ + claimRequest(id) { + const pending = this.pendingRequests.get(id); + if (pending !== undefined) + this.pendingRequests.delete(id); + return pending; + } + /** + * Cancel one pending approval. + * @param id - approval request ID to remove. + */ + disarmRequest(id) { + this.pendingRequests.delete(id); + } + /** + * Find a pending approval for one Plugin. + * @param pluginId - stable Plugin ID. + * @returns its approval request ID, or `undefined` when none is pending. + */ + pendingRequestFor(pluginId) { + for (const [requestId, request] of this.pendingRequests) { + if (request.pluginId === pluginId) + return requestId; + } + return undefined; + } +} +//# sourceMappingURL=registry.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.d.ts new file mode 100644 index 0000000..21d6e17 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.d.ts @@ -0,0 +1,93 @@ +/** + * The `node:vm` sandbox a dynamic package's HOST half evaluates in: a fresh realm whose globals + * are a tagged write-through console, the `harness` registration helpers, the encoding primitives + * a bare vm context lacks, and callable traps over the Node APIs the sandbox deliberately + * withholds. Traps steer filesystem, network, process, and timer work to `ctx.fs`, `ctx.web`, + * `ctx.bash`, and Cordis timers. This keeps cooperative packages inspectable and disposable but + * is not containment: host-realm helper functions remain an escape route. + * + * The browser half never reaches this module — it is evaluated by the client-side runner in a + * closure, with its own facade. + * @module @deepseek-ai/dsh-cordis-host-runner/sandbox + */ +/** Exact Host closure symbols exposed by the sandbox and guarded Context. */ +export declare const HOST_BUILTIN_INSPECTION: readonly [{ + readonly name: "ctx"; + readonly description: "Restricted Cordis Context. Prefer ctx.get(name) with an undefined check; use inject for hard dependencies."; + readonly signatures: readonly ["ctx.get(name: string): unknown | undefined", "ctx.on(name: string, listener: Function): () => void", "ctx.provide(name: string, value: unknown): () => void", "ctx.effect(callback: Function, label?: string): () => void"]; +}, { + readonly name: "harness"; + readonly description: "Host helpers for Package-private Client RPC and model-visible dynamic Tools."; + readonly signatures: readonly ["harness.handle(method: string, handler: (args: JsonValue) => JsonValue | Promise): () => void", "harness.defineTool(definition: ToolDefinition): ToolDefinition", "harness.registerTool(ctx: Context, tool: ToolDefinition): () => void"]; +}, { + readonly name: "console"; + readonly description: "Package-tagged Host logging."; + readonly signatures: readonly ["console.log(...values): void", "console.error(...values): void"]; +}, { + readonly name: "btoa"; + readonly description: "Encode UTF-8 text as base64."; + readonly signatures: readonly ["btoa(value: string): string"]; +}, { + readonly name: "atob"; + readonly description: "Decode base64 as UTF-8 text."; + readonly signatures: readonly ["atob(value: string): string"]; +}, { + readonly name: "TextEncoder"; + readonly description: "Standard UTF-8 encoder constructor."; + readonly signatures: readonly ["new TextEncoder()"]; +}, { + readonly name: "TextDecoder"; + readonly description: "Standard text decoder constructor."; + readonly signatures: readonly ["new TextDecoder(label?: string)"]; +}]; +/** + * Build the vm context one host half evaluates in: the tagged console, the + * `harness` registration helpers, the encoding primitives, the Node-API traps, + * and the dual-realm `instanceof` patch, already `createContext`-ed. + * @param id - the package id (`dyn-`), used as the console tag and filename stem. + * @param harnessExtras - per-package `harness` verbs beyond the registration pair (`handle`). + * @returns the contextified sandbox object to pass to {@link evaluateHostCode}. + */ +export declare function createSandbox(id: string, harnessExtras?: Record): object; +/** + * The parse-failure context a vm `SyntaxError` carries: the vm prints the + * offending source line and a caret before the message, which is exactly what + * a model needs to self-correct — surface it instead of the bare message. + * Falls back to `String(error)` when the stack carries no such prelude. + * @param error - the `SyntaxError` (host- or sandbox-realm) thrown while compiling package code. + * @returns the stack prefix up to and including the `SyntaxError: …` line. + */ +export declare function syntaxErrorContext(error: Error): string; +/** + * The teaching text one parse failure produces, shared by the define-time + * precheck and the run-time evaluation so a model reads the same diagnosis + * whichever verb caught it. + * @param half - which half failed to parse, named as the define argument that carried it. + * @param context - the {@link syntaxErrorContext} of the failure. + * @returns the model-facing error message. + */ +export declare function parseErrorMessage(half: 'code.host' | 'code.client', context: string): string; +/** + * Parse one half's source without running it: the define-time precheck that + * keeps unparseable code out of the registry, so a model fixes it and defines + * again instead of discovering the failure at run time. Compiling through `vm` + * rather than `new Function` is what makes the two agree — same wrapper, same + * compiler, and the same source-line-and-caret prelude in the failure. + * @param code - the model-written function body. + * @param half - which define argument carried it, for the error text. + * @throws when the body does not parse, with the offending line and a teaching hint. + */ +export declare function precheckCode(code: string, half: 'code.host' | 'code.client'): void; +/** + * Evaluate a host half as the body of an async function inside the sandbox. `vmTimeoutMs` only + * bounds the SYNCHRONOUS portion; an async body escapes it — acceptable under the module's + * trust stance. Parse errors include the offending line and a TypeScript-removal or bracket- + * balance hint. + * @param sandbox - the contextified object from {@link createSandbox}. + * @param code - the model-written function body; must `return` a plugin. + * @param id - the package id, used as the vm filename (`cordis-dyn-.js`). + * @param vmTimeoutMs - the synchronous evaluation bound in milliseconds. + * @returns whatever the code returned, still un-narrowed (the run lifecycle checks plugin shape). + */ +export declare function evaluateHostCode(sandbox: object, code: string, id: string, vmTimeoutMs: number): Promise; +//# sourceMappingURL=sandbox.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.js new file mode 100644 index 0000000..f38d6f3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.js @@ -0,0 +1,223 @@ +/** + * The `node:vm` sandbox a dynamic package's HOST half evaluates in: a fresh realm whose globals + * are a tagged write-through console, the `harness` registration helpers, the encoding primitives + * a bare vm context lacks, and callable traps over the Node APIs the sandbox deliberately + * withholds. Traps steer filesystem, network, process, and timer work to `ctx.fs`, `ctx.web`, + * `ctx.bash`, and Cordis timers. This keeps cooperative packages inspectable and disposable but + * is not containment: host-realm helper functions remain an escape route. + * + * The browser half never reaches this module — it is evaluated by the client-side runner in a + * closure, with its own facade. + * @module @deepseek-ai/dsh-cordis-host-runner/sandbox + */ +import { createContext, runInContext, Script } from 'node:vm'; +import { sandboxDefineTool, sandboxRegisterTool } from "./guard.js"; +/** Exact Host closure symbols exposed by the sandbox and guarded Context. */ +export const HOST_BUILTIN_INSPECTION = [ + { + name: 'ctx', + description: 'Restricted Cordis Context. Prefer ctx.get(name) with an undefined check; use inject for hard dependencies.', + signatures: [ + 'ctx.get(name: string): unknown | undefined', + 'ctx.on(name: string, listener: Function): () => void', + 'ctx.provide(name: string, value: unknown): () => void', + 'ctx.effect(callback: Function, label?: string): () => void', + ], + }, + { + name: 'harness', + description: 'Host helpers for Package-private Client RPC and model-visible dynamic Tools.', + signatures: [ + 'harness.handle(method: string, handler: (args: JsonValue) => JsonValue | Promise): () => void', + 'harness.defineTool(definition: ToolDefinition): ToolDefinition', + 'harness.registerTool(ctx: Context, tool: ToolDefinition): () => void', + ], + }, + { name: 'console', description: 'Package-tagged Host logging.', signatures: ['console.log(...values): void', 'console.error(...values): void'] }, + { name: 'btoa', description: 'Encode UTF-8 text as base64.', signatures: ['btoa(value: string): string'] }, + { name: 'atob', description: 'Decode base64 as UTF-8 text.', signatures: ['atob(value: string): string'] }, + { name: 'TextEncoder', description: 'Standard UTF-8 encoder constructor.', signatures: ['new TextEncoder()'] }, + { name: 'TextDecoder', description: 'Standard text decoder constructor.', signatures: ['new TextDecoder(label?: string)'] }, +]; +/** + * A write-through console for one package, tagging every line with the package + * id. Write-through (host stdout/stderr), NOT buffered into the tool result: + * a registered listener fires long after the run call returned, and its output + * must land somewhere the user can see — for a terminal entry point, the host terminal. + */ +function taggedConsole(id) { + const tag = `[cordis:${id}]`; + const log = (...args) => { console.log(tag, ...args); }; + const error = (...args) => { console.error(tag, ...args); }; + return { log, info: log, warn: log, debug: log, error }; +} +/** + * Patch only VM constructors so `instanceof` accepts both VM values and host values passed as + * arguments, events, or service results; host intrinsics remain untouched. + */ +const DUAL_REALM_INSTANCEOF_PRELUDE = ` +(hostIntrinsics) => { + 'use strict' + const ordinary = Function.prototype[Symbol.hasInstance] + for (const name of Object.keys(hostIntrinsics)) { + const VmCtor = globalThis[name] + const HostCtor = hostIntrinsics[name] + if (typeof VmCtor !== 'function' || typeof HostCtor !== 'function') continue + Object.defineProperty(VmCtor, Symbol.hasInstance, { + value: (instance) => ordinary.call(VmCtor, instance) || ordinary.call(HostCtor, instance), + configurable: true, + }) + } +} +`; +/** Run {@link DUAL_REALM_INSTANCEOF_PRELUDE} in a freshly created sandbox, handing it the host intrinsics to pair up. */ +function patchDualRealmInstanceof(sandbox) { + const patch = runInContext(DUAL_REALM_INSTANCEOF_PRELUDE, sandbox); + patch({ Object, Array, Function, Error, TypeError, RangeError, SyntaxError, Promise, RegExp, Date, Map, Set }); +} +const TIMER_REDIRECT = 'Node timers are unavailable. Use the cordis timer service instead: declare inject: [\'timer\'] on your plugin ' + + 'and call ctx.timeout / ctx.interval after querying Host Service.listService for the exact overloads. ' + + 'Those calls are fiber effects, cleaned up automatically when stopped.'; +/** + * The callable Node APIs the sandbox deliberately disables, each mapped to the + * cordis alternative its trap error names. Only function-valued globals are + * trapped; a data-valued global such as `process` stays `undefined`, because a + * throwing accessor would detonate the common `typeof process` feature probe + * at resolution time. + */ +const NODE_API_REDIRECTS = { + require: 'Node modules are unavailable. Use the cordis services on ctx instead — e.g. inject: [\'fs\'] for files, ' + + '[\'web\'] for HTTP, [\'bash\'] for processes; query Service.listService with cordis_inspect_query first.', + setTimeout: TIMER_REDIRECT, + setInterval: TIMER_REDIRECT, + setImmediate: TIMER_REDIRECT, + clearTimeout: TIMER_REDIRECT, + clearInterval: TIMER_REDIRECT, + fetch: 'Network access goes through the cordis web service: declare inject: [\'web\'] and call ctx.web ' + + '(query Host Service.listService with cordis_inspect_query for its methods).', +}; +/** Build the trap functions for {@link NODE_API_REDIRECTS}: calling one throws the redirect. */ +function nodeApiTraps() { + const traps = {}; + for (const [name, redirect] of Object.entries(NODE_API_REDIRECTS)) { + traps[name] = () => { + throw new Error(`${name} is not available in the dynamic package sandbox — ${redirect}`); + }; + } + return traps; +} +/** + * Build the vm context one host half evaluates in: the tagged console, the + * `harness` registration helpers, the encoding primitives, the Node-API traps, + * and the dual-realm `instanceof` patch, already `createContext`-ed. + * @param id - the package id (`dyn-`), used as the console tag and filename stem. + * @param harnessExtras - per-package `harness` verbs beyond the registration pair (`handle`). + * @returns the contextified sandbox object to pass to {@link evaluateHostCode}. + */ +export function createSandbox(id, harnessExtras = {}) { + const sandbox = { + ...nodeApiTraps(), + console: taggedConsole(id), + harness: { defineTool: sandboxDefineTool, registerTool: sandboxRegisterTool, ...harnessExtras }, + // Web APIs absent from fresh vm contexts — made available so the model + // can encode/decode base64 without Buffer (which is also absent). Host + // closures over Buffer, never Buffer itself. + btoa: (s) => Buffer.from(s, 'utf-8').toString('base64'), + atob: (s) => Buffer.from(s, 'base64').toString('utf-8'), + TextEncoder, + TextDecoder, + }; + createContext(sandbox); + patchDualRealmInstanceof(sandbox); + return sandbox; +} +/** + * Cross-realm SyntaxError detection: a compile failure inside `runInContext` + * constructs its error in the SANDBOX realm, so a host `instanceof + * SyntaxError` is silently false — the `name` property is the realm-safe tag. + */ +function isSyntaxError(error) { + return typeof error === 'object' && error !== null && error.name === 'SyntaxError'; +} +/** + * The parse-failure context a vm `SyntaxError` carries: the vm prints the + * offending source line and a caret before the message, which is exactly what + * a model needs to self-correct — surface it instead of the bare message. + * Falls back to `String(error)` when the stack carries no such prelude. + * @param error - the `SyntaxError` (host- or sandbox-realm) thrown while compiling package code. + * @returns the stack prefix up to and including the `SyntaxError: …` line. + */ +export function syntaxErrorContext(error) { + const lines = (error.stack ?? '').split('\n'); + const messageIndex = lines.findIndex(line => line.startsWith('SyntaxError')); + if (messageIndex === -1) + return String(error); + return lines.slice(0, messageIndex + 1).join('\n'); +} +/** + * The teaching text one parse failure produces, shared by the define-time + * precheck and the run-time evaluation so a model reads the same diagnosis + * whichever verb caught it. + * @param half - which half failed to parse, named as the define argument that carried it. + * @param context - the {@link syntaxErrorContext} of the failure. + * @returns the model-facing error message. + */ +export function parseErrorMessage(half, context) { + // Scope the TypeScript heuristic to the OFFENDING line, not the whole code: + // an ` as ` inside an ordinary description string must not turn a plain + // syntax error into a misleading remove-annotations message. + const offendingLine = context.split('\n')[1] ?? ''; + if (/\bas\b/.test(offendingLine)) { + return `dynamic package \`${half}\` failed to parse:\n${context}\n` + + 'The sandbox runs plain JavaScript, not TypeScript. Remove type annotations:\n' + + ' ✗ { type: \'text\' as const, text: x }\n' + + ' ✓ { type: \'text\', text: x }'; + } + return `dynamic package \`${half}\` failed to parse:\n${context}\n` + + 'Note: it runs as the BODY of an async function (line numbers are offset by the 1-line wrapper). ' + + 'Check bracket balance — ending the returned plugin object with `});` closes a call that was never opened; ' + + 'a plain `return { … }` ends with `}` (an optional `;`), never `)`.'; +} +/** + * Parse one half's source without running it: the define-time precheck that + * keeps unparseable code out of the registry, so a model fixes it and defines + * again instead of discovering the failure at run time. Compiling through `vm` + * rather than `new Function` is what makes the two agree — same wrapper, same + * compiler, and the same source-line-and-caret prelude in the failure. + * @param code - the model-written function body. + * @param half - which define argument carried it, for the error text. + * @throws when the body does not parse, with the offending line and a teaching hint. + */ +export function precheckCode(code, half) { + try { + // Compile-only: constructing the Script parses the source and runs nothing. + new Script(`(async () => {\n${code}\n})()`, { filename: `cordis-dyn-${half}.js` }); + } + catch (error) { + if (!isSyntaxError(error)) + throw error; + throw new Error(parseErrorMessage(half, syntaxErrorContext(error))); + } +} +/** + * Evaluate a host half as the body of an async function inside the sandbox. `vmTimeoutMs` only + * bounds the SYNCHRONOUS portion; an async body escapes it — acceptable under the module's + * trust stance. Parse errors include the offending line and a TypeScript-removal or bracket- + * balance hint. + * @param sandbox - the contextified object from {@link createSandbox}. + * @param code - the model-written function body; must `return` a plugin. + * @param id - the package id, used as the vm filename (`cordis-dyn-.js`). + * @param vmTimeoutMs - the synchronous evaluation bound in milliseconds. + * @returns whatever the code returned, still un-narrowed (the run lifecycle checks plugin shape). + */ +export async function evaluateHostCode(sandbox, code, id, vmTimeoutMs) { + try { + return await runInContext(`(async () => {\n${code}\n})()`, sandbox, { filename: `cordis-dyn-${id}.js`, timeout: vmTimeoutMs }); + } + catch (error) { + if (!isSyntaxError(error)) + throw error; + throw new Error(parseErrorMessage('code.host', syntaxErrorContext(error))); + } +} +//# sourceMappingURL=sandbox.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.d.ts new file mode 100644 index 0000000..6b39635 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.d.ts @@ -0,0 +1,359 @@ +/** + * Client-safe wire vocabulary of the dynamic Cordis plugin runner. + * @module @deepseek-ai/dsh-cordis-host-runner/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { JsonValue, SessionId } from '@deepseek-ai/dsh-session/types'; +/** Stable identity of one dynamic plugin instance. */ +export type CordisDynamicPluginId = Branded<'CordisDynamicPluginId'>; +/** Identity of one immutable package version belonging to a dynamic plugin. */ +export type CordisDynamicPackageId = Branded<'CordisDynamicPackageId'>; +/** Identity of one successful activation attempt. */ +export type CordisDynamicPluginRunId = Branded<'CordisDynamicPluginRunId'>; +/** Identity of one human approval request. */ +export type ApprovalRequestId = Branded<'ApprovalRequestId'>; +/** Identity of one cross-page inspect query. */ +export type CordisInspectRequestId = Branded<'CordisInspectRequestId'>; +/** Runtime plane that owns an inspect provider. */ +export type CordisInspectPlatform = 'host' | 'client'; +/** One model-callable read-only query exposed by an inspect provider. */ +export interface CordisInspectMethodManifest { + /** Method name, unique within its provider. */ + name: string; + /** What the query returns and when to use it. */ + description: string; + /** JSON Schema accepted by the query. */ + inputSchema: JsonValue; + /** JSON Schema produced by the query. */ + outputSchema: JsonValue; +} +/** Serializable directory entry for one inspect provider. */ +export interface CordisInspectProviderManifest { + /** Provider identity, unique within one platform. */ + id: string; + /** Capability described by this provider. */ + description: string; + /** Explicit read-only queries. */ + methods: readonly CordisInspectMethodManifest[]; +} +/** Provider directory row returned by `cordis_inspect_list`. */ +export interface CordisInspectProviderView extends CordisInspectProviderManifest { + /** Runtime plane that executes these methods. */ + platform: CordisInspectPlatform; +} +/** Host broadcast requesting one live Client inspect result. */ +export interface CordisInspectQueryRequest { + /** Correlation identity. */ + requestId: CordisInspectRequestId; + /** Session whose model requested the query. */ + agentId: SessionId; + /** Provider selected from the Client manifest. */ + provider: string; + /** Method selected from the provider manifest. */ + method: string; + /** JSON query input, omitted when the method has no fields. */ + input?: JsonValue; +} +/** Result sent from a Client provider to the waiting Host query. */ +export type CordisInspectQueryResolution = { + ok: true; + data: JsonValue; +} | { + ok: false; + reason: 'provider-missing' | 'method-missing' | 'invalid-input' | 'provider-error' | 'cancelled'; + message: string; +}; +/** Notification that a Client inspect request can no longer be answered. */ +export interface CordisInspectQueryResolved { + /** Query that left the pending state. */ + requestId: CordisInspectRequestId; +} +/** Whether a Client answer claimed the still-pending query. */ +export interface CordisInspectResolveAck { + /** False for unknown, cancelled, stale, or late answers. */ + accepted: boolean; +} +/** Whether a package starts the current version or replaces it. */ +export type CordisDynamicRunMode = 'run' | 'update'; +/** How a model-driven Client activation request left the pending state. */ +export type RequestRunOutcome = 'approved' | 'completed' | 'rejected' | 'cancelled' | 'failed'; +/** Error fields preserved across the Host/Client transport. */ +export interface CordisErrorDetails { + /** Original error message. */ + message: string; + /** Original stack when the thrown value supplied one. */ + stack?: string; +} +/** Persisted state of the latest activation attempt. */ +export type CordisRunStatus = 'awaiting-approval' | 'starting-host' | 'client-pending' | 'running' | 'waiting' | 'rejected' | 'failed' | 'cancelled' | 'stopped'; +/** One platform half within an activation attempt. */ +export interface CordisHalfState { + /** Lifecycle state of this half. */ + status: 'absent' | 'pending' | 'stopped' | 'running' | 'waiting' | 'failed'; + /** Services still needed by a successfully created Fiber. */ + waitingFor: readonly string[]; + /** Failure text for this half. */ + error?: string; +} +/** Structured failure associated with an exact activation attempt. */ +export interface CordisRunDiagnostic { + /** Stage that failed. */ + phase: 'approval' | 'host-load' | 'host-apply' | 'client-load' | 'client-apply' | 'client-render'; + /** Original failure text. */ + message: string; + /** Original failure stack when available. */ + stack?: string; + /** Stable Plugin identity. */ + pluginId: CordisDynamicPluginId; + /** Immutable Package identity. */ + packageId: CordisDynamicPackageId; + /** Exact attempt identity. */ + pluginRunId: CordisDynamicPluginRunId; +} +/** Latest activation attempt retained independently from the physical run. */ +export interface DynamicCordisRunAttempt { + /** Exact attempt identity. */ + pluginRunId: CordisDynamicPluginRunId; + /** Target Package. */ + packageId: CordisDynamicPackageId; + /** Explicit run/update intent. */ + mode: CordisDynamicRunMode; + /** Current attempt state. */ + status: CordisRunStatus; + /** Pending Client activation request; it represents approval only when `requiresApproval` is true. */ + approvalRequestId?: ApprovalRequestId; + /** Whether the pending Client activation requires a user decision. */ + requiresApproval?: boolean; + /** Host-half state. */ + host: CordisHalfState; + /** Client-half state. */ + client: CordisHalfState; + /** Most recent failure. */ + error?: CordisRunDiagnostic; +} +/** One running package announced to browser pages. */ +export interface DynamicCordisPackage { + /** Stable plugin instance. */ + pluginId: CordisDynamicPluginId; + /** Immutable package version currently active. */ + packageId: CordisDynamicPackageId; + /** This activation's identity. */ + pluginRunId: CordisDynamicPluginRunId; + /** Package label. */ + name: string; +} +/** One pending model-driven Client activation forwarded to browser pages. */ +export interface DynamicCordisRunRequest { + /** Correlation identity of the activation request. */ + requestId: ApprovalRequestId; + /** Session whose plugin and tool call own the request. */ + agentId: SessionId; + /** Stable plugin instance being acted on. */ + pluginId: CordisDynamicPluginId; + /** Package version the request will activate. */ + packageId: CordisDynamicPackageId; + /** Explicit lifecycle intent. */ + mode: CordisDynamicRunMode; + /** Package label. */ + name: string; + /** User-facing reason supplied at define time. */ + purpose: string; + /** Whether a page must wait for an explicit user decision before activation. */ + requiresApproval: boolean; +} +/** One settled model-driven Client activation request broadcast to all pages. */ +export interface DynamicCordisRequestResolved { + /** Request that left the pending state. */ + requestId: ApprovalRequestId; + /** How the request settled. */ + outcome: RequestRunOutcome; +} +/** One activation withdrawn from every page. */ +export interface DynamicCordisRetracted { + /** Stable plugin instance. */ + pluginId: CordisDynamicPluginId; + /** Package version that was active. */ + packageId: CordisDynamicPackageId; + /** Exact activation being withdrawn. */ + pluginRunId: CordisDynamicPluginRunId; +} +/** Package metadata exposed by the inventory without source code. */ +export interface DynamicCordisInventoryPackage { + /** Immutable package version. */ + packageId: CordisDynamicPackageId; + /** Package label. */ + name: string; + /** User-facing purpose. */ + purpose: string; + /** Whether this version contains Host code. */ + hasHostHalf: boolean; + /** Whether this version contains Client code. */ + hasClientHalf: boolean; +} +/** One stable plugin row in the frame-wide inventory. */ +export interface DynamicCordisInventoryRow { + /** Stable plugin instance. */ + pluginId: CordisDynamicPluginId; + /** Session that owns this plugin. */ + agentId: SessionId; + /** Immutable versions in define order. */ + packages: readonly DynamicCordisInventoryPackage[]; + /** Last package that completed activation successfully. */ + currentPackageId?: CordisDynamicPackageId; + /** Package selected for a failed or in-progress transition. */ + nextPackageId?: CordisDynamicPackageId; + /** Current activation, absent while stopped. */ + activeRun?: { + pluginRunId: CordisDynamicPluginRunId; + packageId: CordisDynamicPackageId; + }; + /** Latest activation attempt, including pending approval and diagnostics. */ + latestRun?: DynamicCordisRunAttempt; +} +/** Answer to removing a plugin and all of its package versions. */ +export type DynamicCordisUndefineReceipt = { + ok: true; + wasRunning: boolean; +} | { + ok: false; + reason: 'plugin-missing'; + message: string; +}; +/** One render failure observed after a Client half loaded. */ +export interface DynamicCordisRenderFailure { + /** Slot whose component failed. */ + slot: string; + /** Render failure text. */ + message: string; + /** Original render failure stack when available. */ + stack?: string; + /** Whether the failing contribution relinquished its slot. */ + abdicated: boolean; +} +/** Result shared by model-driven and panel-driven activation. */ +export type DynamicCordisRunResponse = { + ok: true; + /** Whether activation completed synchronously, is starting in a Client, or awaits user approval. */ + status: 'awaiting-approval' | 'starting' | 'running'; + pluginId: CordisDynamicPluginId; + packageId: CordisDynamicPackageId; + pluginRunId: CordisDynamicPluginRunId; + /** Missing Host services; a parked Fiber is a successful activation. */ + waitingFor: readonly string[]; + /** Missing Client services reported by the approving page. */ + clientWaitingFor?: readonly string[]; + /** Last fully successful Package. */ + currentPackageId?: CordisDynamicPackageId; + /** Selected transition target. */ + nextPackageId?: CordisDynamicPackageId; + /** Explicit lifecycle intent. */ + mode: CordisDynamicRunMode; +} | { + ok: false; + reason: 'plugin-missing' | 'package-missing' | 'invalid-mode' | 'transition-in-flight' | 'host-half-failed' | 'client-half-failed' | 'rejected' | 'cancelled' | 'not-running'; + message: string; + /** Original failure stack when available. */ + stack?: string; +}; +/** Result of stopping a Plugin without deleting its Packages. */ +export type DynamicCordisStopResponse = { + ok: true; +} | { + ok: false; + reason: 'plugin-missing' | 'not-running'; + message: string; +}; +/** Result of bringing up the Host half before loading the Client half. */ +export type DynamicCordisHostHalfResult = { + ok: true; + pluginId: CordisDynamicPluginId; + packageId: CordisDynamicPackageId; + pluginRunId: CordisDynamicPluginRunId; + waitingFor: readonly string[]; + /** False when a panel merely attaches this page to an already active run. */ + startedHere: boolean; +} | ({ + ok: false; +} & CordisErrorDetails); +/** Client-half source for one exact activation. */ +export interface DynamicCordisClientSource { + /** Browser JavaScript body. */ + code: string; + /** Package label. */ + name: string; + /** Stable plugin instance. */ + pluginId: CordisDynamicPluginId; + /** Immutable source version. */ + packageId: CordisDynamicPackageId; + /** Exact activation the source belongs to. */ + pluginRunId: CordisDynamicPluginRunId; +} +/** Browser verdict used for both approved tool runs and panel runs. */ +export type DynamicCordisRunResolution = { + ok: true; + pluginRunId: CordisDynamicPluginRunId; + waitingFor?: readonly string[]; +} | { + ok: false; + reason: 'rejected' | 'host-half-failed' | 'client-half-failed'; + /** Activation that failed; absent for a refusal before activation. */ + pluginRunId?: CordisDynamicPluginRunId; + /** Whether this page created the failed activation instead of attaching to it. */ + startedHere?: boolean; + message?: string; + stack?: string; +}; +/** Whether a Client activation resolution reached the still-pending request. */ +export interface DynamicCordisResolveAck { + /** False for late, unknown, or stale answers. */ + accepted: boolean; +} +/** Result of routing one Client call to the active Host half. */ +export type DynamicCordisInvokeResult = { + ok: true; + value: JsonValue; +} | ({ + ok: false; + code: 'plugin-not-running' | 'stale-run' | 'method-not-found' | 'handler-error'; +} & CordisErrorDetails); +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * A Client-bearing activation needs a browser page, and may require a user decision. + * @param request - correlation identity, owner, target version, mode, and approval requirement. + * @mode emit + */ + 'cordis/request-run'(request: DynamicCordisRunRequest): void; + /** + * A pending Client activation request left the answerable state. + * @param resolved - request identity and outcome. + * @mode emit + */ + 'cordis/request-run-resolved'(resolved: DynamicCordisRequestResolved): void; + /** + * One exact Plugin/Package activation is now live in the Host. + * @param pkg - stable plugin, immutable package, run identity, and label. + * @mode emit + */ + 'cordis/dynamic-package'(pkg: DynamicCordisPackage): void; + /** + * One exact activation was withdrawn. + * @param retracted - plugin, package, and run identity. + * @mode emit + */ + 'cordis/dynamic-retract'(retracted: DynamicCordisRetracted): void; + /** + * Request a live read-only query from the Client inspect registry. + * @param request - correlation, Session, provider, method, and JSON input. + * @mode emit + */ + 'cordis/inspect-query'(request: CordisInspectQueryRequest): void; + /** + * Notify every Client that an inspect query has settled or been cancelled. + * @param resolved - exact query identity that is no longer answerable. + * @mode emit + */ + 'cordis/inspect-query-resolved'(resolved: CordisInspectQueryResolved): void; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.js new file mode 100644 index 0000000..a89d8f0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.js @@ -0,0 +1,6 @@ +/** + * Client-safe wire vocabulary of the dynamic Cordis plugin runner. + * @module @deepseek-ai/dsh-cordis-host-runner/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/package.json new file mode 100644 index 0000000..0e640c1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner/package.json @@ -0,0 +1,78 @@ +{ + "name": "@deepseek-ai/dsh-cordis-host-runner", + "description": "Dynamic package definition registry, host-half sandbox lifecycle, and invoke handler table for model-mounted dual-half packages", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/extensions/cordis-host-runner" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./typert": { + "types": "./lib/typert.host.d.ts", + "default": "./lib/typert.host.js" + }, + "./remote": { + "types": "./lib/typert.remote-client.d.ts", + "default": "./lib/typert.remote-client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts", + "lib/typert.host.js", + "lib/typert.host.d.ts", + "lib/typert.remote-client.js", + "lib/typert.remote-client.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/cordis-plugin-timer": "^1.1.3", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-tools b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-tools new file mode 120000 index 0000000..49af432 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-tools @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..aa2ae83 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.i18n.yaml new file mode 100644 index 0000000..de2059d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/extensions/cordis-host-runner/README.md +README.md: f09e7506fe24676ea95b3ae490b55ae120bfad5f +README.zh.md: f60d3a64ecb1e90427b966c820a857e62d65b375 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.md new file mode 100644 index 0000000..f09e750 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.md @@ -0,0 +1,72 @@ +# @deepseek-ai/dsh-cordis-host-runner + +English | [中文](README.zh.md) + +The host half of model-mounted dynamic packages: the definition registry, the `node:vm` sandbox and fiber lifecycle for host halves, the invoke handler table, and the run round trip a browser page carries out. Provided as `ctx.dynamicCordisRunner`. The model-facing tools live in [`@deepseek-ai/dsh-tool-cordis`](../tool-cordis/README.md); the browser half is loaded by [`@deepseek-ai/dsh-cordis-client-runner`](../cordis-client-runner/README.md). + +## What it does + +Two phases: `define` only records, and everything with an effect hangs off a run. + +- `define` / `undefine` own a definition's life. `define` trims and requires the metadata, prechecks each half's syntax by compiling it (running nothing), mints `dyn-`, and records the definition against the session that asked — it has no effect to roll back, so unparseable code is refused before an id exists. `undefine` stops a running definition first, then forgets it. Neither crosses the wire: only the model's own tool call defines. +- `run` answers the model's request to run one definition, and its two shapes differ by whose business the package is. A host-only package is this process's own: the host half is evaluated in the vm under the `cordis-dynamic` group fiber and the call returns. A package with a browser half has to be carried out by a page, so `run` becomes an answerable round trip — it emits `cordis/request-run`, suspends, and is settled by a person allowing or declining it. There is no timer; the caller's `AbortSignal` (the asking turn was cancelled) is the only other way out, and it announces the cancellation so other pages stop offering an answer. Whether any page will answer is not knowable when the request is sent — a page that received it may still never answer, so a deployment with no page connected suspends like any other unanswered request and ends in `cancelled`. `run` has no wire face — `cordis_run` calls it in process. +- `runHostHalf` / `getClientCode` are the steps an allowed page walks, host half first, so a host-half failure short-circuits before the browser has moved. `runHostHalf` is idempotent by contract: a running package is bound rather than evaluated again, concurrent calls for one definition evaluate it once, and `startedHere` names the caller that did. `getClientCode` then hands that one page the browser-half source, refusing a definition that is gone, has no browser half, or is not running. Code never rides an announcement, so this is the only way it reaches a browser. +- `resolveRequestRun` closes the round trip with the answering page's verdict, and broadcasts `cordis/request-run-resolved` so every other page drops the pending affordance. The first answer wins; a later or unknown request id is accepted and ignored. A success naming a revision the registry has moved past is refused rather than applied (`accepted: false`, request still suspended), because the page that answered loaded a dispatch that is no longer live. A failing verdict unwinds the host half only when this same request evaluated it, so a page that cannot load its own half never stops a package the other pages are using. +- `stop` unwinds one live dispatch — handlers dropped, host-half fiber disposed to quiescence, `dynamicCordisRunner/retract` broadcast — and leaves the definition runnable. +- `inventory` answers the whole registry, unaddressed by session and with each row naming the session that owns it, because the run-control surface is global. Listing is not acting: every acting verb still checks that ownership. Each row also names whether the definition has a browser half, so a run-control surface offers loading it into the current page only when there is a half to load. `snapshot` is its session-scoped host-local counterpart, carrying each live host half's fiber so `cordis_inspect` can render provides/waiting/state itself (a fiber cannot cross the wire). +- `reportRenderFailure` records what a page saw a LOADED browser half do wrong at render time. Rendering happens strictly after a load succeeded, so a run has already answered `ok` by then: this report is fire-and-forget, carries no settle authority, and never touches `resolveRequestRun` or any part of the run outcome — **it is not the retired v2 `report`/ack**. The host keeps the last failure per definition across every page (a second page reporting overwrites), and a fresh run, a stop, or an undefine clears it, so the model is never shown a failure from a dispatch that no longer exists. The browser-half face keeps its own "what THIS page is showing now"; the two answer different questions rather than duplicating one. A report for a definition the reporting session does not own is dropped, because the reporting path must never fail a render. +- `invoke` routes one call from a package's browser half to a method its own host half registered with `harness.handle`. The infrastructure only routes — no host-to-browser direction exists. + +A refusal from `run` or `stop` names one of `definition-missing`, `host-half-failed`, `client-half-failed`, `rejected`, `cancelled`, or `not-running`; the last three are answers rather than defects — a person declined, the asking turn ended, or there was nothing running to stop. + +A definition another session defined reads as absent rather than forbidden, so nothing leaks across sessions. `invoke` and `resolveRequestRun` carry no session at all: a component's call and a page's answer are page-global facts, not one session's. + +Four forwarded events belong to this feature, declared by this package on its client-safe [`./types`](src/types.ts) subpath and allowlisted for delivery by [`@deepseek-ai/dsh-api-remotes`](../../api/remotes/README.md), which is what lets a browser reach them through `ctx.remote.$on`: `cordis/request-run` (`{requestId, agentId, id, name, purpose}` — metadata, never code), `cordis/request-run-resolved` (`{requestId, outcome}`), `dynamicCordisRunner/package` (`{id, name, rev}`), and `dynamicCordisRunner/retract` (`{id, rev}`). The last two are a symmetric pair announcing run state — every fresh start and every stop, whether or not the package has a browser half. + +## Storage stance + +The registry is process memory and the only source of truth. The session log carries a define call's metadata — never its code — so a restarted process legitimately has no definitions, and a card whose id no longer resolves says exactly that rather than pretending it can run. Nothing here is written to disk, and no definition is restored automatically; a reloaded page holds nothing until someone runs a package again, which is what makes it bind the live host half and re-fetch the browser half. + +## Trust stance + +The vm sandbox isolates globals but is not a security boundary: Node globals are absent or redirect to Cordis services (`ctx.fs`, `ctx.web`, `ctx.bash`, the timer helpers), and a host half receives a façade without framework internals, yet the services it declares reach the live runtime. Treat a dynamic package like bash access — see the [self-referential toolset Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). + +## Config + +| Field | Default | Meaning | +|---|---|---| +| `vmTimeoutMs` | `5000` | Milliseconds the synchronous portion of a host half may run in the vm before evaluation is aborted | + +One field is all there is: a run request waits for a person, so the round trip has no deadline of its own. + +## Export shape + +Service package: default-exports `DynamicCordisRunnerService` (service key `dynamicCordisRunner`), with `./types` carrying the payload shapes the `dynamicCordisRunner` remote namespace and its consumers share. The `define` / `undefine` shapes stay inside the package, because they never cross the wire. + +## Model Experience + +### Refusals and teaching errors relayed by the cordis tools + +#### What the model sees + +Nothing directly: this package registers no tool and injects no prompt. Its refusals reach the model through the `cordis_*` tool results that call it — an unparseable half names the offending line, a missing definition explains that definitions live in memory only, a `rejected` or `cancelled` run reports that a person declined or the turn ended rather than that anything failed, and a failed browser-half load carries the answering page's own error text. + +#### Token effect + +None of its own: every message above is carried by the calling tool's result. + +#### KV Cache effect + +A host half that registers tools changes the next request's tool view, which invalidates prefix reuse from the first changed schema token; running or stopping a package with no tool registrations is prefix-neutral. + +## Known Limitations and Deferred Work + +- **A successful run does not mean the UI rendered.** `run` returns once the answering page has LOADED the browser half; React renders afterwards, so a component that throws cannot possibly appear in the run receipt. The failure surfaces through `reportRenderFailure` and is read back with `cordis_inspect what:"temporary"`; the run result says so rather than implying success. + +- A package with a browser half **suspends where no page is connected** — headless and ACP deployments hold the run until the asking turn is cancelled, because a forwarded event reports nothing about who received it. Host-only packages are unaffected. +- A suspended run request has **no timeout**: it waits for a person until the asking turn is cancelled, so unattended automation cannot use packages with a browser half. +- `vmTimeoutMs` bounds only synchronous evaluation; an async host-half body escapes it, matching the toolset's cooperative trust stance. +- `runHostHalf` carries no request id, so "which request evaluated this host half" is attributed host-side to the most recently armed request for that definition; several concurrent run requests for one definition would need that rule revisited. +- A success answer naming a superseded revision is refused (`accepted: false`) and leaves the request suspended, so the model's call ends only through a valid answer or its own cancellation. Settling it would take a fresh orchestration against the live revision, and no page does that today — the [browser half](../cordis-client-runner/README.md) does not read the ack — so in practice such a request is closed by another page's answer or by the caller's cancellation. +- A browser half's declared `inject` is read from the plugin it returns in the page, so the announcement carries no service-declaration field at all. +- **`zod` is a runtime dependency of the generated TypeRT faces, not of `src`.** `./typert` and `./remote` resolve to `lib/typert.*.js`, which `tsc` emits unbundled with a bare `import { z } from 'zod'`, so the package must declare it (the `@deepseek-ai/dsh-goal` precedent) and `knip.json` must ignore it for this workspace — knip reads source, and these faces are build products. Nothing in `src` imports zod. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.zh.md new file mode 100644 index 0000000..f60d3a6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/README.zh.md @@ -0,0 +1,72 @@ +# @deepseek-ai/dsh-cordis-host-runner + +[English](README.md) | 中文 + +由模型挂载的动态包在 host 侧的那一半:定义注册表、host 半所用的 `node:vm` 沙箱与 fiber 生命周期、invoke handler 表,以及由某个浏览器页面执行的 run 往返。以 `ctx.dynamicCordisRunner` 提供。面向模型的工具在 [`@deepseek-ai/dsh-tool-cordis`](../tool-cordis/README.md) 中;浏览器半由 [`@deepseek-ai/dsh-cordis-client-runner`](../cordis-client-runner/README.md) 装载。 + +## 功能 + +分两个阶段:`define` 只做登记,一切带副作用的动作都挂在一次 run 上。 + +- `define`/`undefine` 掌管一个定义的生命周期。`define` 对元数据做首尾去空白与必填校验,通过编译预检每一半的语法(不执行任何代码),铸出 `dyn-`,并把该定义登记在发起调用的会话名下——它没有任何可回滚的副作用,所以无法解析的代码在拿到 id 之前就被拒绝。`undefine` 先停掉正在运行的定义,再把它忘掉。两者都不上 wire:只有模型自己的工具调用才会 define。 +- `run` 回答模型「运行某个定义」的请求,它的两种形态取决于这个包是谁的事。只有 host 半的包是本进程自己的事:host 半在 `cordis-dynamic` group fiber 之下于 vm 中求值,调用随即返回。带浏览器半的包必须由一个页面来执行,于是 `run` 变成一次可作答的往返——它 emit `cordis/request-run`、挂起,并由某个人允许或拒绝来结束。这里没有定时器;调用方的 `AbortSignal`(提问的那一轮次被取消)是唯一的另一条出路,而且它会把这次取消播报出去,让其他页面不再提供作答入口。请求发出时**并不知道**会不会有人作答——收到它的页面也可能永远不答,所以没有页面连接的部署与其他未作答请求一样挂起,最终以 `cancelled` 收场。`run` 没有 wire 面——`cordis_run` 在进程内调用它。 +- `runHostHalf`/`getClientCode` 是获得允许的页面依次走的步骤,host 半在先,因此 host 半失败会在浏览器还没动作之前短路。`runHostHalf` 在约定上是幂等的:已在运行的包只做绑定,不再求值;针对同一个定义的并发调用只求值一次,`startedHere` 指出求值的是哪一个调用方。随后 `getClientCode` 把浏览器半的源码交给这一个页面;定义已消失、没有浏览器半、或未在运行时,它会拒绝。代码从不搭乘任何播报,所以这是它到达浏览器的唯一途径。 +- `resolveRequestRun` 用作答页面的结论结束这次往返,并 emit `cordis/request-run-resolved`,让其他每个页面撤下待作答的入口。首答即成;更晚的或未知的 request id 会被接受并忽略。命名了注册表已越过的版本的成功结论会被拒绝而非应用(`accepted: false`,请求仍处于挂起),因为作答的那个页面装载的是一个已不再存活的下发。失败的结论只会在 host 半正是由这次请求求值时才将它回退,因此某个页面装不上自己那一半,绝不会把其他页面正在使用的包停掉。 +- `stop` 回退一次存活的下发——丢弃 handler、把 host 半 fiber dispose(资源释放)到完全停稳、emit `dynamicCordisRunner/retract`——并让该定义仍然可运行。 +- `inventory` 回答整个注册表,不按会话寻址,且每一行都指明拥有该定义的会话,因为运行控制面是全局的。能列出不等于能操作:每个有实际动作的动词仍会检查这份归属。每一行还会指明该定义有没有浏览器半,因此运行控制面只在确有可装载的半时,才提供「装入当前页面」。`snapshot` 是它按会话限定的 host 本地对侧,携带每个存活 host 半的 fiber,供 `cordis_inspect` 自行渲染 provides/waiting/state(fiber 无法跨 wire)。 +- `reportRenderFailure` 记录某个页面看到一个**已装载**的浏览器半在渲染时做错了什么。渲染严格发生在装载成功之后,因此到那时 run 早已回答了 `ok`:这份上报是 fire-and-forget 的,不带任何结算权威,也绝不触碰 `resolveRequestRun` 或 run 结论的任何部分——**它不是那个已退役的 v2 `report`/ack**。host 按定义保留跨所有页面的最后一次失败(第二个页面上报即覆盖),而一次全新的 run、一次 stop 或一次 undefine 都会清掉它,因此模型绝不会看到一次已不存在的下发留下的失败。浏览器半的契约面自己保留一份「**这个页面**当前正在显示什么」;两者回答的是不同的问题,不是同一个问题的两份答案。上报的会话若并不拥有该定义,这次上报会被丢弃,因为上报路径绝不能让一次渲染失败。 +- `invoke` 把一个包的浏览器半发起的一次调用,路由到它自己的 host 半用 `harness.handle` 注册的方法。这套基础设施只做路由:不存在 host 到浏览器的方向。 + +`run` 或 `stop` 的拒绝会给出 `definition-missing`、`host-half-failed`、`client-half-failed`、`rejected`、`cancelled`、`not-running` 之一;后三者是答复而非缺陷——有人拒绝了、提问的那一轮次已结束,或本来就没有在运行的东西可停。 + +别的会话登记的定义读起来是不存在,而不是被禁止,因此不会跨会话泄漏任何东西。`invoke` 与 `resolveRequestRun` 完全不携带会话:组件的一次调用和页面的一次作答都是页面全局的事实,不属于某一个会话。 + +本功能拥有四条转发事件,由本包在其 client-safe 的 [`./types`](src/types.ts) 子路径上声明,并由 [`@deepseek-ai/dsh-api-remotes`](../../api/remotes/README.md) 的白名单准许投递——正是这一点让浏览器能经 `ctx.remote.$on` 收到它们:`cordis/request-run`(`{requestId, agentId, id, name, purpose}`——只有元数据,绝无代码)、`cordis/request-run-resolved`(`{requestId, outcome}`)、`dynamicCordisRunner/package`(`{id, name, rev}`),以及 `dynamicCordisRunner/retract`(`{id, rev}`)。后两者是对称的一对运行状态播报:每次全新启动与每次停止都播,与该包有没有浏览器半无关。 + +## 存储立场 + +注册表就是进程内存,也是唯一真源。会话日志只承载一次 define 调用的元数据,绝不承载它的代码:因此进程重启后确实没有任何定义,这是合理的;而 id 已无法解析的卡片会如实说明这一点,不会假装自己还能运行。本包不向磁盘写任何东西,也不会自动恢复任何定义;刷新过的页面手上什么都没有,直到有人再次运行某个包——正是这一步让它绑定存活的 host 半并重新取回浏览器半。 + +## 信任立场 + +vm 沙箱隔离全局变量,但不是安全边界:Node 全局变量不存在,或重定向到 Cordis 服务(`ctx.fs`、`ctx.web`、`ctx.bash` 以及定时器 helper),host 半收到的是不含框架内部机制的 façade,但它声明的服务仍会触达存活运行时。应当像对待 bash 访问一样对待动态包,参见[自引用工具集 Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md)。 + +## 配置 + +| 字段 | 默认值 | 含义 | +|---|---|---| +| `vmTimeoutMs` | `5000` | host 半在 vm 中同步执行的那部分被中止求值前可运行的毫秒数 | + +就这一个字段:一次 run 请求等的是人,所以这趟往返本身没有任何截止期限。 + +## 导出形状 + +服务包:默认导出 `DynamicCordisRunnerService`(服务键 `dynamicCordisRunner`),`./types` 则承载 `dynamicCordisRunner` remote namespace 与其消费方共享的载荷形状。`define`/`undefine` 的形状留在包内部,因为它们从不跨 wire。 + +## 模型体验 + +### 经 cordis 工具转达的拒绝与教学式错误 + +#### 模型看到的内容 + +没有直接可见的内容:本包不注册任何工具,也不注入提示词。它的拒绝经调用它的 `cordis_*` 工具结果到达模型——无法解析的半会指出出错的那一行,缺失的定义会解释定义只活在内存里,`rejected` 或 `cancelled` 的 run 报告的是有人拒绝或该轮次已结束而非出了故障,浏览器半装载失败则带上作答页面自己的错误文本。 + +#### Token 影响 + +本包自身没有:上述每条消息都由调用它的那个工具的结果承载。 + +#### KV Cache 影响 + +注册工具的 host 半会改变下一次请求的工具视图,从第一个变化的 schema token 起使前缀复用失效;运行或停止一个不注册任何工具的包对前缀不产生影响。 + +## 已知限制与暂缓事项 + +- **run 成功不等于 UI 渲染成功。** 只要作答页面**已装载**浏览器半,`run` 就会返回;React 是随后才渲染的,因此一个抛异常的组件根本不可能出现在 run 的回执里。该失败经 `reportRenderFailure` 浮现,并通过 `cordis_inspect what:"temporary"` 读回;run 的结果会把这一点说出来,而不是暗示成功。 + +- 带浏览器半的包在**没有页面连接的地方会挂起**——headless 与 ACP(Agent Client Protocol)部署会把这次 run 一直挂到提问的轮次被取消,因为转发事件不回报谁收到了它。只有 host 半的包不受影响。 +- 挂起的 run 请求**没有超时**:它一直等人,直到提问的那一轮次被取消,因此无人值守的自动化用不了带浏览器半的包。 +- `vmTimeoutMs` 只约束同步求值;async 的 host 半函数体会逃出该上限,这与该工具集基于协作的信任立场一致。 +- `runHostHalf` 不携带 request id,因此「这个 host 半是哪次请求求值的」由 host 侧归因到该定义最近一次挂起的请求;若同一个定义出现多个并发 run 请求,这条规则需要重新审议。 +- 命名了已被取代版本的成功结论会被拒绝(`accepted: false`)并让该请求继续挂起,因此模型这次调用只能靠一次有效作答或自身被取消才结束。要把它结算掉,需要对着存活版本重新走一遍编排,而当前没有任何页面会这么做——[浏览器半](../cordis-client-runner/README.md)不读这个 ack——所以这类请求实际上由别的页面作答、或由调用方取消来收尾。 +- 浏览器半声明的 `inject` 是从它在页面里返回的插件上读出的,因此播报完全不携带服务声明字段。 +- **`zod` 是生成的 TypeRT 契约面的运行时依赖,不是 `src` 的依赖。** `./typert` 与 `./remote` 解析到 `lib/typert.*.js`,`tsc` 以不打包的形式产出它们,其中带有裸的 `import { z } from 'zod'`,所以本包必须声明它(沿用 `@deepseek-ai/dsh-goal` 的先例),而 `knip.json` 必须在这个 workspace 里忽略它:knip 读的是源码,而这些契约面是构建产物。`src` 里没有任何代码 import zod。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/index.js new file mode 100644 index 0000000..d435325 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/index.js @@ -0,0 +1,2573 @@ +import z from "@deepseek-ai/schemastery"; +import { createUserMessage } from "@deepseek-ai/dsh-llm"; +import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol"; +import { Context, Service } from "@deepseek-ai/cordis"; +import { scopeOf } from "@deepseek-ai/dsh-scope"; +import { assertSupportedJsonSchema, defineTool, validateJsonSchemaValue } from "@deepseek-ai/dsh-tools"; +import { snapshotJsonValue } from "@deepseek-ai/dsh-session"; +import { Script, createContext, runInContext } from "node:vm"; +//#region lib/types/guard.js +/** +* The registration boundary between a sandboxed host half and the real runtime: ParameterSchemaSpec +* normalization + validation with teaching errors, the marker-guarded `harness.defineTool` / +* `harness.registerTool` pair, the `harness.handle` invoke-handler normalizer, the SANDBOX CONTEXT +* FAÇADE a running plugin's `apply` receives in place of the real `ctx`, and the plugin-shape +* helpers the run lifecycle narrows sandbox return values with. The façade is a whitelist of +* lifecycle-safe verbs and declared services; framework internals and context-valued service +* returns are denied. +* +* VM-realm schemas and canonical values are rebuilt as host objects, while rendered content and +* presentation metadata are shape-checked before entering the registry. Common JSON-Schema spellings are normalized when they +* have one meaning; invalid vocabulary fails during registration with a teaching error. +* @module @deepseek-ai/dsh-cordis-host-runner/guard +*/ +const DYNAMIC_TOOL = Symbol("cordis-host-runner.dynamic-tool"); +const SCHEMA_TYPES = new Set([ + "string", + "number", + "integer", + "boolean", + "null", + "object", + "array", + "json" +]); +const VALID_TYPES = "'string' | 'number' | 'integer' | 'boolean' | 'null' | 'object' | 'array' | 'json'"; +const ANNOTATION_KEYS = [ + "description", + "title", + "default", + "examples" +]; +function isPlainRecord(value) { + if (typeof value !== "object" || value === null || Array.isArray(value)) return false; + const prototype = Object.getPrototypeOf(value); + return prototype === null || typeof prototype === "object" && Object.getPrototypeOf(prototype) === null && hasIntrinsicConstructor(prototype, "Object"); +} +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const constructor = Object.getOwnPropertyDescriptor(prototype, "constructor")?.value; + if (typeof constructor !== "function") return false; + try { + return constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } catch { + return false; + } +} +/** Whether an array uses one realm's intrinsic Array prototype rather than a subclass. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, "Array")) return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === "object" && objectPrototype !== null && Object.getPrototypeOf(objectPrototype) === null && hasIntrinsicConstructor(objectPrototype, "Object"); +} +/** Whether a schema list is a dense intrinsic array with no JSON-invisible decorations. */ +function isDensePlainArray(value) { + if (!Array.isArray(value) || !hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false; + for (let index = 0; index < value.length; index++) if (!Object.hasOwn(value, index)) return false; + return true; +} +/** Reject schema records whose declarations would disappear from object enumeration. */ +function assertSchemaContainerKeys(value, path) { + if (Reflect.ownKeys(value).some((key) => typeof key !== "string" || !Object.prototype.propertyIsEnumerable.call(value, key))) throw new Error(`harness.defineTool ${path} must contain only own enumerable string keys`); +} +/** Materialize realm-foreign lossless JSON without allowing JSON.stringify coercions; `path` carries the caller's own error prefix. */ +function cloneJson(value, path) { + const ancestors = /* @__PURE__ */ new Set(); + let root; + const assign = (destination, item) => { + if (destination.kind === "root") { + root = item; + return; + } + if (destination.kind === "array") { + destination.target[destination.index] = item; + return; + } + Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true + }); + }; + const reject = (at) => { + throw new Error(`${at} must be lossless JSON data (objects, arrays, strings, numbers, booleans, null) — not a class instance, function, Map/Set, Date, or undefined. Return a plain object built from the values you need, or \`return null\` when the caller needs no value back.`); + }; + const tasks = [{ + kind: "visit", + value, + path, + destination: { kind: "root" } + }]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "leave") { + ancestors.delete(task.source); + continue; + } + if (task.kind === "array-item") { + if (!Object.hasOwn(task.source, task.index)) reject(task.path); + tasks.push({ + kind: "visit", + value: task.source[task.index], + path: `${task.path}[${task.index}]`, + destination: { + kind: "array", + target: task.target, + index: task.index + } + }); + continue; + } + const current = task.value; + if (current === null || typeof current === "string" || typeof current === "boolean") { + assign(task.destination, current); + continue; + } + if (typeof current === "number") { + if (!Number.isFinite(current) || Object.is(current, -0)) reject(task.path); + assign(task.destination, current); + continue; + } + if (typeof current !== "object" || ancestors.has(current)) reject(task.path); + if (Array.isArray(current)) { + if (!hasPlainArrayPrototype(current) || Reflect.ownKeys(current).length !== current.length + 1) reject(task.path); + const output = []; + assign(task.destination, output); + ancestors.add(current); + tasks.push({ + kind: "leave", + source: current + }); + for (let index = current.length - 1; index >= 0; index--) tasks.push({ + kind: "array-item", + source: current, + index, + path: task.path, + target: output + }); + continue; + } + if (!isPlainRecord(current)) reject(task.path); + const record = current; + if (Reflect.ownKeys(record).some((key) => typeof key !== "string" || !Object.prototype.propertyIsEnumerable.call(record, key))) reject(task.path); + const output = {}; + assign(task.destination, output); + ancestors.add(record); + tasks.push({ + kind: "leave", + source: record + }); + const entries = Object.entries(record); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === void 0) continue; + tasks.push({ + kind: "visit", + value: entry[1], + path: `${task.path}.${entry[0]}`, + destination: { + kind: "object", + target: output, + key: entry[0] + } + }); + } + } + return root; +} +/** Copy and realm-materialize the shared annotation vocabulary. */ +function copyAnnotations(value, output, path) { + if (Object.hasOwn(value, "description")) output.description = value.description; + if (Object.hasOwn(value, "title")) output.title = value.title; + if (Object.hasOwn(value, "default")) output.default = cloneJson(value.default, `harness.defineTool ${path}.default`); + if (Object.hasOwn(value, "examples")) output.examples = cloneJson(value.examples, `harness.defineTool ${path}.examples`); +} +/** Reject sandbox schema keys that the unified DSL would otherwise ignore. */ +function assertSchemaKeys(value, path, allowed) { + assertSchemaContainerKeys(value, path); + for (const key of Object.keys(value)) if (!allowed.includes(key)) throw new Error(`harness.defineTool ${path}.${key} is not supported by the unified schema DSL`); +} +/** +* Normalize a sandbox-provided `parameters` value into a fresh host-realm +* ParameterSchemaSpec. A raw JSON-Schema object wrapper retains its open root +* default, while the direct DSL is already an implicit open property map. +*/ +function normalizeParameterSchemaSpec(value, path = "parameters") { + if (!isPlainRecord(value)) throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec object`); + if (value.type === "object") { + assertSchemaKeys(value, path, [ + "type", + "properties", + "required", + "additionalProperties", + ...ANNOTATION_KEYS + ]); + if (!isPlainRecord(value.properties)) throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`); + if (Object.hasOwn(value, "additionalProperties") && value.additionalProperties !== true) throw new Error(`harness.defineTool ${path}.additionalProperties must be true or omitted because the implicit parameter root is open`); + if (Object.hasOwn(value, "required") && value.required === void 0) throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`); + const required = normalizeRequiredNames(value.required, value.properties, `${path}.required`); + const rootAnnotations = {}; + copyAnnotations(value, rootAnnotations, path); + return { + spec: normalizePropertyMap(value.properties, path, required, true), + ...Object.keys(rootAnnotations).length === 0 ? {} : { rootAnnotations } + }; + } + return { spec: normalizePropertyMap(value, path, /* @__PURE__ */ new Set(), false) }; +} +/** Validate raw required names and return their lookup set. */ +function normalizeRequiredNames(value, properties, path) { + if (value === void 0) return /* @__PURE__ */ new Set(); + if (!isDensePlainArray(value)) throw new Error(`harness.defineTool ${path} must be an array of declared property names`); + const names = /* @__PURE__ */ new Set(); + for (let index = 0; index < value.length; index++) { + const name = value[index]; + if (typeof name !== "string") throw new Error(`harness.defineTool ${path} must be an array of declared property names`); + names.add(name); + if (!Object.hasOwn(properties, name)) throw new Error(`harness.defineTool ${path} names undeclared property ${JSON.stringify(name)}`); + } + return names; +} +/** Install one normalized node without `__proto__` assignment semantics. */ +function assignNormalizedValue(destination, value) { + if (destination.kind === "property") Object.defineProperty(destination.target, destination.key, { + value, + enumerable: true, + configurable: true, + writable: true + }); + else if (destination.kind === "item") destination.target.items = value; + else destination.target[destination.index] = value; +} +/** Install one normalized property map at its root or containing object. */ +function assignNormalizedMap(destination, value) { + if (destination.kind === "root") destination.holder.value = value; + else destination.target.properties = value; +} +/** Normalize one implicit property map and all descendants with explicit work frames. */ +function normalizePropertyMap(entries, path, requiredNames, raw) { + const holder = {}; + const ancestors = /* @__PURE__ */ new Set(); + const tasks = [{ + kind: "map", + entries, + path, + requiredNames, + raw, + destination: { + kind: "root", + holder + } + }]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "leave") { + ancestors.delete(task.value); + continue; + } + if (task.kind === "map") { + if (ancestors.has(task.entries)) throw new Error(`harness.defineTool ${task.path} is circular`); + assertSchemaContainerKeys(task.entries, task.path); + ancestors.add(task.entries); + const spec = {}; + assignNormalizedMap(task.destination, spec); + tasks.push({ + kind: "leave", + value: task.entries + }); + const mapEntries = Object.entries(task.entries); + for (let index = mapEntries.length - 1; index >= 0; index--) { + const entry = mapEntries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === void 0) continue; + tasks.push({ + kind: "value", + value: entry[1], + path: `${task.path}.${entry[0]}`, + forceRequired: task.requiredNames.has(entry[0]), + raw: task.raw, + parameterProperty: true, + destination: { + kind: "property", + target: spec, + key: entry[0] + } + }); + } + continue; + } + const { value, path } = task; + if (!isPlainRecord(value)) throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec property object`); + assertSchemaContainerKeys(value, path); + if (ancestors.has(value)) throw new Error(`harness.defineTool ${path} is circular`); + ancestors.add(value); + const requiredKey = task.parameterProperty && !task.raw ? ["required"] : []; + if (task.parameterProperty && task.raw && Object.hasOwn(value, "required") && value.type !== "object") throw new Error(`harness.defineTool ${path}.required belongs to the containing raw object schema`); + if (task.parameterProperty && !task.raw && Object.hasOwn(value, "required") && value.required !== true) throw new Error(`harness.defineTool ${path}.required must be true when present`); + const prop = {}; + assignNormalizedValue(task.destination, prop); + tasks.push({ + kind: "leave", + value + }); + if (task.forceRequired || value.required === true) prop.required = true; + copyAnnotations(value, prop, path); + if (Object.hasOwn(value, "oneOf")) { + assertSchemaKeys(value, path, [ + "oneOf", + ...requiredKey, + ...ANNOTATION_KEYS + ]); + if (!isDensePlainArray(value.oneOf) || value.oneOf.length < 2) throw new Error(`harness.defineTool ${path}.oneOf must contain at least two schemas`); + const oneOf = []; + prop.oneOf = oneOf; + for (let index = value.oneOf.length - 1; index >= 0; index--) tasks.push({ + kind: "value", + value: value.oneOf[index], + path: `${path}.oneOf[${index}]`, + forceRequired: false, + raw: task.raw, + parameterProperty: false, + destination: { + kind: "one-of", + target: oneOf, + index + } + }); + continue; + } + if (task.raw && !Object.hasOwn(value, "type")) { + assertSchemaKeys(value, path, ANNOTATION_KEYS); + prop.type = "json"; + continue; + } + if (!SCHEMA_TYPES.has(value.type) || task.raw && value.type === "json") throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES} (got ${JSON.stringify(value.type)})`); + const type = value.type; + prop.type = type; + switch (type) { + case "object": + assertSchemaKeys(value, path, [ + "type", + "properties", + "additionalProperties", + ...requiredKey, + ...task.raw ? ["required"] : [], + ...ANNOTATION_KEYS + ]); + if (!task.raw && (!Object.hasOwn(value, "additionalProperties") || typeof value.additionalProperties !== "boolean")) throw new Error(`harness.defineTool ${path}.additionalProperties must be explicitly true or false`); + if (task.raw && Object.hasOwn(value, "additionalProperties") && typeof value.additionalProperties !== "boolean") throw new Error(`harness.defineTool ${path}.additionalProperties must be a boolean`); + if (task.raw && Object.hasOwn(value, "required") && value.required === void 0) throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`); + prop.additionalProperties = task.raw ? value.additionalProperties ?? true : value.additionalProperties; + if (Object.hasOwn(value, "properties")) { + const properties = value.properties; + if (!isPlainRecord(properties)) throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`); + const nestedRequired = task.raw ? normalizeRequiredNames(value.required, properties, `${path}.required`) : /* @__PURE__ */ new Set(); + tasks.push({ + kind: "map", + entries: properties, + path: `${path}.properties`, + requiredNames: nestedRequired, + raw: task.raw, + destination: { + kind: "properties", + target: prop + } + }); + } else if (task.raw && value.required !== void 0) normalizeRequiredNames(value.required, {}, `${path}.required`); + break; + case "array": + assertSchemaKeys(value, path, [ + "type", + "items", + ...requiredKey, + ...ANNOTATION_KEYS + ]); + if (Object.hasOwn(value, "items")) tasks.push({ + kind: "value", + value: value.items, + path: `${path}.items`, + forceRequired: false, + raw: task.raw, + parameterProperty: false, + destination: { + kind: "item", + target: prop + } + }); + break; + case "string": + case "number": + case "integer": + case "boolean": + case "null": + assertSchemaKeys(value, path, [ + "type", + "enum", + "const", + ...requiredKey, + ...ANNOTATION_KEYS + ]); + if (Object.hasOwn(value, "enum")) { + if (!isDensePlainArray(value.enum) || value.enum.length === 0) throw new Error(`harness.defineTool ${path}.enum must be a non-empty array`); + prop.enum = cloneJson(value.enum, `harness.defineTool ${path}.enum`); + } + if (Object.hasOwn(value, "const")) prop.const = cloneJson(value.const, `harness.defineTool ${path}.const`); + break; + case "json": + assertSchemaKeys(value, path, [ + "type", + ...requiredKey, + ...ANNOTATION_KEYS + ]); + break; + /* v8 ignore next 2 -- SCHEMA_TYPES narrows this closed switch before dispatch. */ + default: throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES}`); + } + } + /* v8 ignore next -- the root map task assigns before scheduling descendants. */ + return holder.value ?? {}; +} +function markDynamicTool(tool) { + Object.defineProperty(tool, DYNAMIC_TOOL, { value: true }); + return tool; +} +function assertDynamicTool(tool) { + if (!isPlainRecord(tool) || tool[DYNAMIC_TOOL] !== true) throw new Error("dynamic tool registration must use a tool returned by harness.defineTool(...)"); +} +/** +* Structurally a content block, checked AFTER the JSON round-trip: a plain +* object carrying a string `type` tag. Deliberately nothing deeper — the +* ContentBlock union is merge-extensible (an unknown tag must pass), and every +* downstream consumer dispatches on `type` and falls through unknowns. +*/ +function isContentBlockShape(value) { + return isPlainRecord(value) && typeof value.type === "string"; +} +/** +* How much of an invalid execute return the teaching error echoes back — a +* huge blob would burn the model turn the error is trying to save. +*/ +const RETURN_PREVIEW_LIMIT = 120; +/** +* Compact JSON preview of an invalid execute return for the teaching error +* (`String(…)` for the un-stringifiable undefined case), truncated to +* {@link RETURN_PREVIEW_LIMIT}. +*/ +function describeReturn(value) { + const json = JSON.stringify(value); + return json.length > RETURN_PREVIEW_LIMIT ? `${json.slice(0, RETURN_PREVIEW_LIMIT)}…` : json; +} +/** +* Validate and host-materialize a sandbox renderer's content blocks. +*/ +function assertRenderedContent(value) { + if (Array.isArray(value) && value.every(isContentBlockShape)) return value; + throw new Error(`output.render returned ${describeReturn(value)} — it must return an ARRAY of content blocks:\n ✓ return [{ type: 'text', text: String(value) }]`); +} +/** +* The `harness.defineTool` handed into the sandbox: the real DSL, with `parameters` normalized +* into a fresh host-realm ParameterSchemaSpec (raw object wrappers unwrapped, +* required arrays mapped, and explicit DSL object openness enforced) and the tool's `execute` return normalized into the host realm +* via a JSON round-trip. Non-JSON or wrong-shape output fails that call instead of poisoning +* the session log. +* @param options - the standard `defineTool` options; `parameters` may be the ParameterSchemaSpec DSL or a JSON-Schema-style wrapper. +* @returns the marker-tagged definition `harness.registerTool` (and the guarded `ctx.tools.register`) accepts. +*/ +function sandboxDefineTool(options) { + if (!isPlainRecord(options)) throw new Error("harness.defineTool options must be an object"); + const normalized = normalizeParameterSchemaSpec(options.parameters); + if (!isPlainRecord(options.output)) throw new Error("harness.defineTool output must declare { schema, render, presentationMeta? }"); + const output = options.output; + if (typeof output.render !== "function") throw new Error("harness.defineTool output.render must be a function"); + if (output.presentationMeta !== void 0 && typeof output.presentationMeta !== "function") throw new Error("harness.defineTool output.presentationMeta must be a function when present"); + if (typeof options.execute !== "function") throw new Error("harness.defineTool execute must be a function"); + const schema = cloneJson(output.schema, "harness.defineTool output.schema"); + const rawExecute = options.execute; + const rawRender = output.render; + const rawPresentationMeta = output.presentationMeta; + const tool = defineTool({ + ...options, + parameters: normalized.spec, + output: { + schema, + render(args, value) { + return assertRenderedContent(cloneJson(rawRender(args, value), "harness.defineTool output.render result")); + }, + ...rawPresentationMeta !== void 0 ? { presentationMeta(args, value) { + return cloneJson(rawPresentationMeta(args, value), "harness.defineTool output.presentationMeta result"); + } } : {} + }, + async execute(args, exec) { + return cloneJson(await rawExecute(args, exec), "harness.defineTool execute result"); + } + }); + const parameters = { + ...tool.parameters, + ...normalized.rootAnnotations + }; + assertSupportedJsonSchema(parameters); + return markDynamicTool({ + ...tool, + parameters + }); +} +/** +* Normalize one `harness.handle` registration at the sandbox boundary: the +* method name must be a non-empty string and the handler a function whose +* result is host-materialized through the same cross-realm JSON clone as tool +* `execute` returns (a VM-realm object would otherwise escape the wire's +* plain-object contract). +* @param method - handler name the package's browser half calls through `host.call`. +* @param fn - sandbox handler receiving the wire-decoded JSON arguments. +* @returns the validated name and the clone-wrapped handler. +*/ +function normalizeHandler(method, fn) { + if (typeof method !== "string" || method.length === 0) throw new Error("harness.handle(method, fn) needs a non-empty string method name"); + if (typeof fn !== "function") throw new Error(`harness.handle("${method}") needs a handler function as its second argument`); + const rawHandler = fn; + return { + method, + handler: async (args) => cloneJson(await rawHandler(args), `harness.handle("${method}") result`) + }; +} +/** +* The `harness.registerTool` handed into the sandbox: registers a +* marker-verified dynamic tool on the given context's registry. +* @param ctx - the (guarded) context whose `tools` service receives the tool. +* @param tool - a definition produced by {@link sandboxDefineTool}; anything else is rejected. +* @returns the registry disposer for the registration. +*/ +function sandboxRegisterTool(ctx, tool) { + assertDynamicTool(tool); + return ctx.tools.register(tool); +} +/** +* The verbs a running host half may reach through the sandbox `ctx` façade, beyond its injected +* services. `on`/`once` observe events, `provide` exposes a service to other packages, and the +* timer helpers schedule work — each a fiber effect that unwinds when the package stops. +*/ +const CTX_VERBS = new Set([ + "effect", + "on", + "once", + "provide", + "timeout", + "interval", + "setTimeout", + "setInterval", + "throttle", + "debounce" +]); +const TIMER_VERBS = new Set([ + "timeout", + "interval", + "setTimeout", + "setInterval", + "throttle", + "debounce" +]); +/** +* The tool-registry façade: `register` (marker-guarded) plus READ-ONLY +* metadata (`schemas`, and `get` returning a schema view, never the live +* `ToolDefinition`). Exposing the raw definition would hand package code the +* tool's `execute` function, letting it call another tool directly and bypass +* `ToolRuntime.execute` — identity protection, pre-policy, monotonic guards, +* around dispatch, post-policy, final observation, and result normalization. So `get` returns the same +* name/description/parameters view as `schemas()`, and nothing invocable. +*/ +function sandboxTools(ctx) { + return { + register: (tool) => sandboxRegisterTool(ctx, tool), + schemas: () => ctx.tools.schemas(scopeOf(ctx)), + get: (name) => ctx.tools.schemas(scopeOf(ctx)).find((schema) => schema.name === name) + }; +} +/** +* Reject any injected-service return that is a cordis `Context`. Harness +* services return data, never a context; a value that is one would be a +* fresh, unguarded handle back into the runtime — the exact escape the façade +* exists to close — so it fails loud instead of reaching sandbox code. +*/ +function denyContext(value, service, reportFailure) { + if (value instanceof Context) return rejectGuard(reportFailure, `service "${service}" returned a cordis Context, which the sandbox does not expose. Operate through your own plugin ctx (ctx.on / ctx.provide / ctx.tools.register) and the services you inject — never another context.`); + return value; +} +/** +* Wrap an injected service so its methods forward to the real instance but +* their return values pass through {@link denyContext}. Non-function members +* (plain data) pass through as-is; a returned Promise is guarded on resolve. +*/ +function guardedService(service, name, reportFailure) { + return new Proxy(service, { get(target, prop) { + const value = Reflect.get(target, prop, target); + if (typeof value !== "function") return denyContext(value, name, reportFailure); + return (...args) => { + const result = Reflect.apply(value, target, args); + if (result instanceof Promise) return result.then((v) => denyContext(v, name, reportFailure)); + return denyContext(result, name, reportFailure); + }; + } }); +} +/** +* The service names a plugin declared in `inject`, as a lookup set. Whatever +* declaration style the plugin used — an `inject: ['bash', 'tools']` array or +* the `{ required, optional }` object form — cordis resolves it into a single +* name-keyed map on the fiber before `apply` runs (`{ bash: null, tools: null }`), +* so the gate just reads that map's keys. A host half may reach only the services +* it declared — that is what lets cordis park it when a declared provider +* goes away. +*/ +function declaredInjects(ctx) { + return new Set(Object.keys(ctx.fiber.inject)); +} +/** +* Whitelist context for running host halves: lifecycle-safe verbs, guarded +* tools, optional `ctx.get()` lookup, and declared-service property access. +* Framework plumbing is denied, and service methods cannot return a Context. +*/ +function sandboxContext(ctx, reportFailure) { + const tools = sandboxTools(ctx); + const declared = declaredInjects(ctx); + const denyRead = (prop) => { + if (ctx.get(prop) !== void 0) return rejectGuard(reportFailure, `service "${prop}" is not injected. Declare it: inject: ['${prop}', …] on your plugin, so cordis parks this dynamic package if the provider later goes away.`); + return rejectGuard(reportFailure, `sandbox ctx does not expose "${prop}". Available: ctx.tools.register / ctx.on / ctx.provide / the timer helpers after injecting timer, and any service you declared in inject. Framework internals (root, fiber, registry, extend, plugin, …) are withheld by design.`); + }; + const readService = (name, requireDeclaration) => { + if (name === "tools") return tools; + if (requireDeclaration && !declared.has(name)) return denyRead(name); + const service = denyContext(ctx.get(name), name, reportFailure); + if (service === null || typeof service !== "object" && typeof service !== "function") return service; + return guardedService(service, name, reportFailure); + }; + const get = (name) => readService(name, false); + return new Proxy({}, { + get(_target, prop) { + if (prop === "tools") return tools; + if (prop === "get") return get; + if (typeof prop !== "string") return void 0; + if (CTX_VERBS.has(prop)) return (...args) => { + if (TIMER_VERBS.has(prop) && !declared.has("timer")) return denyRead("timer"); + const method = ctx[prop]; + return Reflect.apply(method, ctx, args); + }; + return readService(prop, true); + }, + set(_target, prop) { + return rejectGuard(reportFailure, `sandbox ctx is read-only; cannot assign "${String(prop)}"`); + }, + has: (_target, prop) => prop === "tools" || prop === "get" || typeof prop === "string" && (CTX_VERBS.has(prop) && (!TIMER_VERBS.has(prop) || declared.has("timer")) || declared.has(prop)) + }); +} +/** +* Narrow an arbitrary sandbox return value to a runnable cordis plugin: a +* function, or an object with an `apply` function. (A bare function passes the +* first arm, so the object arm never sees `Function.prototype.apply`.) +* @param value - whatever the host half returned. +* @returns whether the value can be started via `ctx.plugin`. +*/ +function isPlugin(value) { + if (typeof value === "function") return true; + return typeof value === "object" && value !== null && typeof value.apply === "function"; +} +/** +* Wrap a plugin so `apply` receives the sandbox context while preserving injection metadata. +* @param plugin - the plugin the host half returned. +* @param reportFailure - reports a guard rejection to the owning Agent. +* @returns an equivalent plugin whose `apply` sees the sandbox context façade. +*/ +function guardedPlugin(plugin, reportFailure) { + if (typeof plugin === "function") { + const functionPlugin = plugin; + return { + name: pluginName(plugin), + apply(ctx, config) { + return functionPlugin(sandboxContext(ctx, reportFailure), config); + } + }; + } + const objectPlugin = plugin; + return { + ...plugin, + apply(ctx, config) { + return objectPlugin.apply(sandboxContext(ctx, reportFailure), config); + } + }; +} +function rejectGuard(reportFailure, message) { + const error = new Error(message); + reportFailure(error); + throw error; +} +/** +* Display name for a running plugin: its `name` property, else anonymous. +* @param plugin - the plugin the host half returned. +* @returns the human-readable name used in run results and inspect output. +*/ +function pluginName(plugin) { + const named = plugin.name; + if (typeof named === "string" && named.length > 0) return named; + return ""; +} +//#endregion +//#region lib/types/inspect-registry.js +/** Host registry for model-visible, read-only Cordis capability queries. */ +/** Registry and cross-page router behind the two model-facing inspect tools. */ +var CordisInspectRegistryService = class extends Service { + providers = /* @__PURE__ */ new Map(); + pending = /* @__PURE__ */ new Map(); + clientManifest; + nextRequest = 1; + /** Register the process-global Host registry. */ + constructor(ctx) { + super(ctx, "cordisInspect"); + } + /** + * Register one Host provider. + * @param registration - manifest and local query handler. + * @returns idempotent disposer. + */ + register(registration) { + const manifest = validateManifest(registration.manifest); + if (this.providers.has(manifest.id)) throw new Error(`Host Cordis inspect provider "${manifest.id}" is already registered`); + const stored = { + ...registration, + manifest + }; + this.providers.set(manifest.id, stored); + return () => { + if (this.providers.get(manifest.id) === stored) this.providers.delete(manifest.id); + }; + } + /** + * Replace the mirrored Client provider directory. + * @param providers - complete Client manifest snapshot. + */ + syncClientManifest(providers) { + const ids = /* @__PURE__ */ new Set(); + const validated = providers.map((provider) => { + const manifest = validateManifest(provider); + if (ids.has(manifest.id)) throw new Error(`Client Cordis inspect manifest repeats provider "${manifest.id}"`); + ids.add(manifest.id); + return manifest; + }); + this.clientManifest = Object.freeze(validated); + } + /** + * Return the complete known Host and Client provider directory. + * @returns Host providers followed by the Client providers. + */ + list() { + return [...[...this.providers.values()].map((provider) => view("host", provider.manifest)), ...(this.clientManifest ?? []).map((provider) => view("client", provider))]; + } + /** + * Execute one provider query on its owning platform. + * @param platform - Host or Client runtime. + * @param providerId - provider selected from {@link list}. + * @param methodName - declared method name. + * @param input - optional lossless JSON input. + * @param agent - requesting Agent and scope. + * @param signal - tool-call cancellation. + * @returns provider JSON data. + */ + async query(platform, providerId, methodName, input, agent, signal) { + if (platform === "host") { + const registration = this.providers.get(providerId); + if (registration === void 0) throw new Error(`Host Cordis inspect provider "${providerId}" is not registered`); + const method = findMethod(registration.manifest, methodName); + validateInput("Host", providerId, method, input); + signal.throwIfAborted(); + const data = await registration.query(methodName, input, { + agent, + signal + }); + signal.throwIfAborted(); + return validateOutput("Host", providerId, method, data); + } + return await this.queryClient(providerId, methodName, input, agent, signal); + } + /** + * Accept the first valid Client response for a pending query. + * @param agent - Agent whose Session owns the query. + * @param requestId - Pending Client query identity. + * @param resolution - Client provider result or failure. + * @returns whether this response settled the still-pending query. + */ + resolveClientQuery(agent, requestId, resolution) { + const pending = this.pending.get(requestId); + if (pending === void 0 || pending.request.agentId !== agent.id) return { accepted: false }; + if (!resolution.ok) return { accepted: false }; + try { + resolution = { + ok: true, + data: validateOutput("Client", pending.request.provider, pending.method, resolution.data) + }; + } catch { + return { accepted: false }; + } + this.pending.delete(requestId); + pending.settle(resolution); + this.ctx.emit("cordis/inspect-query-resolved", { requestId }); + return { accepted: true }; + } + async queryClient(providerId, methodName, input, agent, signal) { + const provider = this.clientManifest?.find((candidate) => candidate.id === providerId); + if (provider === void 0) throw new Error(`Client Cordis inspect provider "${providerId}" is not registered`); + const method = findMethod(provider, methodName); + validateInput("Client", providerId, method, input); + signal.throwIfAborted(); + const requestId = `inspect-${this.nextRequest++}`; + const request = { + requestId, + agentId: agent.id, + provider: providerId, + method: methodName, + ...input === void 0 ? {} : { input } + }; + const result = new Promise((resolve) => { + this.pending.set(requestId, { + request, + method, + settle: resolve + }); + }); + const onAbort = () => { + const pending = this.pending.get(requestId); + if (pending === void 0) return; + this.pending.delete(requestId); + pending.settle({ + ok: false, + reason: "cancelled", + message: `Client inspect query ${providerId}.${methodName} was cancelled` + }); + this.ctx.emit("cordis/inspect-query-resolved", { requestId }); + }; + signal.addEventListener("abort", onAbort, { once: true }); + if (signal.aborted) onAbort(); + else this.ctx.emit("cordis/inspect-query", request); + try { + const resolution = await result; + if (!resolution.ok) throw new Error(`${providerId}.${methodName}: ${resolution.message}`); + return resolution.data; + } finally { + signal.removeEventListener("abort", onAbort); + } + } +}; +function view(platform, manifest) { + return { + platform, + ...manifest, + methods: [...manifest.methods] + }; +} +function validateManifest(manifest) { + if (manifest.id.trim() === "") throw new Error("Cordis inspect provider id must not be empty"); + if (manifest.description.trim() === "") throw new Error(`Cordis inspect provider "${manifest.id}" needs a description`); + const names = /* @__PURE__ */ new Set(); + const methods = manifest.methods.map((method) => { + if (method.name.trim() === "") throw new Error(`Cordis inspect provider "${manifest.id}" has an empty method name`); + if (names.has(method.name)) throw new Error(`Cordis inspect provider "${manifest.id}" repeats method "${method.name}"`); + if (method.description.trim() === "") throw new Error(`Cordis inspect method ${manifest.id}.${method.name} needs a description`); + assertSupportedJsonSchema(method.inputSchema); + assertSupportedJsonSchema(method.outputSchema); + names.add(method.name); + return Object.freeze({ ...method }); + }); + return Object.freeze({ + ...manifest, + methods: Object.freeze(methods) + }); +} +function findMethod(manifest, name) { + const method = manifest.methods.find((candidate) => candidate.name === name); + if (method === void 0) throw new Error(`Cordis inspect provider "${manifest.id}" has no method "${name}"`); + return method; +} +function validateInput(platform, provider, method, input) { + const violations = validateJsonSchemaValue(method.inputSchema, input ?? {}, "input"); + if (violations.length > 0) throw new Error(`${platform} Cordis inspect ${provider}.${method.name} rejected input: ${violations.join("; ")}`); +} +function validateOutput(platform, provider, method, data) { + const snapshot = snapshotJsonValue(data); + if (snapshot === void 0) throw new Error(`${platform} Cordis inspect ${provider}.${method.name} returned a non-JSON value`); + const violations = validateJsonSchemaValue(method.outputSchema, snapshot, "output"); + if (violations.length > 0) throw new Error(`${platform} Cordis inspect ${provider}.${method.name} returned invalid output: ${violations.join("; ")}`); + return snapshot; +} +//#endregion +//#region lib/types/lifecycle.js +/** +* Host-half fiber lifecycle over the `cordis-dynamic` group: settle a +* sandbox-produced plugin as a child fiber (never leaving a failed fiber +* mounted), and report the services a settled-but-pending fiber still waits +* for. Stopping needs no helper — a host half unwinds through an ordinary +* awaited `fiber.dispose()`, because everything the plugin registered is an +* effect on its fiber. +* @module @deepseek-ai/dsh-cordis-host-runner/lifecycle +*/ +/** +* Await the group, start and settle one guarded child, and dispose it before rethrowing any +* startup failure so a failed run never lingers. A valid unresolved inject may remain pending. +* @param group - the `cordis-dynamic` group fiber every host half hangs under. +* @param plugin - the plugin the sandbox returned; wrapped with the registration guard before starting. +* @param reportGuardFailure - reports post-activation Host guard rejections to the owning Agent. +* @returns the settled child fiber (possibly pending on unsatisfied `inject`). +*/ +async function startHostHalf(group, plugin, reportGuardFailure) { + await group.await(); + const fiber = group.ctx.plugin(guardedPlugin(plugin, reportGuardFailure)); + try { + await fiber.await(); + } catch (error) { + await fiber.dispose(); + const message = error instanceof Error ? error.message : String(error); + if (message.includes("already registered")) throw new Error(`${message} — to REPLACE something an earlier dynamic package registered, first cordis_stop that package's id (find it with cordis_runtime_inspect what:"temporary"), then run the new version.`); + throw error instanceof Error ? error : new Error(message); + } + return fiber; +} +/** +* The services a fiber declared in `inject` that do not exist yet — a settled +* fiber that is not active is waiting on exactly these (legal cordis +* semantics: it activates when the service appears). +* @param ctx - the context to resolve service existence against. +* @param fiber - the host-half fiber whose `inject` declarations are checked. +* @returns the missing service names, in declaration order. +*/ +function missingServices(ctx, fiber) { + return Object.keys(fiber.inject).filter((service) => ctx.get(service) === void 0); +} +//#endregion +//#region lib/types/registry.js +/** +* Process-local dynamic Plugin registry and its opaque identity mints. +* @module @deepseek-ai/dsh-cordis-host-runner/registry +*/ +/** Registry, identity mints, and pending approval index. */ +var DynamicCordisRegistry = class { + plugins = /* @__PURE__ */ new Map(); + pendingRequests = /* @__PURE__ */ new Map(); + nextPlugin = 1; + nextPackage = 1; + nextRun = 1; + nextApproval = 1; + /** + * Mint a semantic plugin ID without reusing a prior suffix. + * @param prefix - validated lowercase semantic prefix proposed by the model. + * @returns a process-unique Plugin ID. + */ + mintPluginId(prefix) { + let id; + do + id = `${prefix}-${this.nextPlugin++}`; + while (this.plugins.has(id)); + return id; + } + /** + * Mint an immutable package ID. + * @returns a process-unique Package ID. + */ + mintPackageId() { + return `pkg-${this.nextPackage++}`; + } + /** + * Mint an activation ID. + * @returns a process-unique Plugin Run ID. + */ + mintPluginRunId() { + return `run-${this.nextRun++}`; + } + /** + * Mint an approval ID. + * @returns a process-unique approval request ID. + */ + mintApprovalRequestId() { + return `approval-${this.nextApproval++}`; + } + /** + * Add one stable plugin. + * @param plugin - Plugin record to retain under its stable ID. + */ + add(plugin) { + this.plugins.set(plugin.pluginId, plugin); + } + /** + * Read one plugin. + * @param id - stable Plugin ID. + * @returns the Plugin record, or `undefined` when absent. + */ + get(id) { + return this.plugins.get(id); + } + /** + * Delete one plugin and all package versions. + * @param id - stable Plugin ID to remove. + * @returns whether a Plugin record was removed. + */ + delete(id) { + return this.plugins.delete(id); + } + /** + * Read all plugins in creation order. + * @returns a snapshot of every Plugin record. + */ + all() { + return [...this.plugins.values()]; + } + /** + * Read one session's plugins in creation order. + * @param sessionId - owning session to filter by. + * @returns a snapshot of matching Plugin records. + */ + ofSession(sessionId) { + return this.all().filter((plugin) => plugin.sessionId === sessionId); + } + /** + * Publish one pending approval. + * @param id - approval request ID. + * @param pending - resolver and Plugin metadata retained until settlement. + */ + armRequest(id, pending) { + this.pendingRequests.set(id, pending); + } + /** + * Read one pending approval without claiming it. + * @param id - approval request ID. + * @returns the pending request, or `undefined` when absent. + */ + peekRequest(id) { + return this.pendingRequests.get(id); + } + /** + * Claim one pending approval; first answer wins. + * @param id - approval request ID. + * @returns the claimed request, or `undefined` when already settled. + */ + claimRequest(id) { + const pending = this.pendingRequests.get(id); + if (pending !== void 0) this.pendingRequests.delete(id); + return pending; + } + /** + * Cancel one pending approval. + * @param id - approval request ID to remove. + */ + disarmRequest(id) { + this.pendingRequests.delete(id); + } + /** + * Find a pending approval for one Plugin. + * @param pluginId - stable Plugin ID. + * @returns its approval request ID, or `undefined` when none is pending. + */ + pendingRequestFor(pluginId) { + for (const [requestId, request] of this.pendingRequests) if (request.pluginId === pluginId) return requestId; + } +}; +//#endregion +//#region lib/types/sandbox.js +/** +* The `node:vm` sandbox a dynamic package's HOST half evaluates in: a fresh realm whose globals +* are a tagged write-through console, the `harness` registration helpers, the encoding primitives +* a bare vm context lacks, and callable traps over the Node APIs the sandbox deliberately +* withholds. Traps steer filesystem, network, process, and timer work to `ctx.fs`, `ctx.web`, +* `ctx.bash`, and Cordis timers. This keeps cooperative packages inspectable and disposable but +* is not containment: host-realm helper functions remain an escape route. +* +* The browser half never reaches this module — it is evaluated by the client-side runner in a +* closure, with its own facade. +* @module @deepseek-ai/dsh-cordis-host-runner/sandbox +*/ +/** Exact Host closure symbols exposed by the sandbox and guarded Context. */ +const HOST_BUILTIN_INSPECTION = [ + { + name: "ctx", + description: "Restricted Cordis Context. Prefer ctx.get(name) with an undefined check; use inject for hard dependencies.", + signatures: [ + "ctx.get(name: string): unknown | undefined", + "ctx.on(name: string, listener: Function): () => void", + "ctx.provide(name: string, value: unknown): () => void", + "ctx.effect(callback: Function, label?: string): () => void" + ] + }, + { + name: "harness", + description: "Host helpers for Package-private Client RPC and model-visible dynamic Tools.", + signatures: [ + "harness.handle(method: string, handler: (args: JsonValue) => JsonValue | Promise): () => void", + "harness.defineTool(definition: ToolDefinition): ToolDefinition", + "harness.registerTool(ctx: Context, tool: ToolDefinition): () => void" + ] + }, + { + name: "console", + description: "Package-tagged Host logging.", + signatures: ["console.log(...values): void", "console.error(...values): void"] + }, + { + name: "btoa", + description: "Encode UTF-8 text as base64.", + signatures: ["btoa(value: string): string"] + }, + { + name: "atob", + description: "Decode base64 as UTF-8 text.", + signatures: ["atob(value: string): string"] + }, + { + name: "TextEncoder", + description: "Standard UTF-8 encoder constructor.", + signatures: ["new TextEncoder()"] + }, + { + name: "TextDecoder", + description: "Standard text decoder constructor.", + signatures: ["new TextDecoder(label?: string)"] + } +]; +/** +* A write-through console for one package, tagging every line with the package +* id. Write-through (host stdout/stderr), NOT buffered into the tool result: +* a registered listener fires long after the run call returned, and its output +* must land somewhere the user can see — for a terminal entry point, the host terminal. +*/ +function taggedConsole(id) { + const tag = `[cordis:${id}]`; + const log = (...args) => { + console.log(tag, ...args); + }; + const error = (...args) => { + console.error(tag, ...args); + }; + return { + log, + info: log, + warn: log, + debug: log, + error + }; +} +/** +* Patch only VM constructors so `instanceof` accepts both VM values and host values passed as +* arguments, events, or service results; host intrinsics remain untouched. +*/ +const DUAL_REALM_INSTANCEOF_PRELUDE = ` +(hostIntrinsics) => { + 'use strict' + const ordinary = Function.prototype[Symbol.hasInstance] + for (const name of Object.keys(hostIntrinsics)) { + const VmCtor = globalThis[name] + const HostCtor = hostIntrinsics[name] + if (typeof VmCtor !== 'function' || typeof HostCtor !== 'function') continue + Object.defineProperty(VmCtor, Symbol.hasInstance, { + value: (instance) => ordinary.call(VmCtor, instance) || ordinary.call(HostCtor, instance), + configurable: true, + }) + } +} +`; +/** Run {@link DUAL_REALM_INSTANCEOF_PRELUDE} in a freshly created sandbox, handing it the host intrinsics to pair up. */ +function patchDualRealmInstanceof(sandbox) { + runInContext(DUAL_REALM_INSTANCEOF_PRELUDE, sandbox)({ + Object, + Array, + Function, + Error, + TypeError, + RangeError, + SyntaxError, + Promise, + RegExp, + Date, + Map, + Set + }); +} +const TIMER_REDIRECT = "Node timers are unavailable. Use the cordis timer service instead: declare inject: ['timer'] on your plugin and call ctx.timeout / ctx.interval after querying Host Service.listService for the exact overloads. Those calls are fiber effects, cleaned up automatically when stopped."; +/** +* The callable Node APIs the sandbox deliberately disables, each mapped to the +* cordis alternative its trap error names. Only function-valued globals are +* trapped; a data-valued global such as `process` stays `undefined`, because a +* throwing accessor would detonate the common `typeof process` feature probe +* at resolution time. +*/ +const NODE_API_REDIRECTS = { + require: "Node modules are unavailable. Use the cordis services on ctx instead — e.g. inject: ['fs'] for files, ['web'] for HTTP, ['bash'] for processes; query Service.listService with cordis_inspect_query first.", + setTimeout: TIMER_REDIRECT, + setInterval: TIMER_REDIRECT, + setImmediate: TIMER_REDIRECT, + clearTimeout: TIMER_REDIRECT, + clearInterval: TIMER_REDIRECT, + fetch: "Network access goes through the cordis web service: declare inject: ['web'] and call ctx.web (query Host Service.listService with cordis_inspect_query for its methods)." +}; +/** Build the trap functions for {@link NODE_API_REDIRECTS}: calling one throws the redirect. */ +function nodeApiTraps() { + const traps = {}; + for (const [name, redirect] of Object.entries(NODE_API_REDIRECTS)) traps[name] = () => { + throw new Error(`${name} is not available in the dynamic package sandbox — ${redirect}`); + }; + return traps; +} +/** +* Build the vm context one host half evaluates in: the tagged console, the +* `harness` registration helpers, the encoding primitives, the Node-API traps, +* and the dual-realm `instanceof` patch, already `createContext`-ed. +* @param id - the package id (`dyn-`), used as the console tag and filename stem. +* @param harnessExtras - per-package `harness` verbs beyond the registration pair (`handle`). +* @returns the contextified sandbox object to pass to {@link evaluateHostCode}. +*/ +function createSandbox(id, harnessExtras = {}) { + const sandbox = { + ...nodeApiTraps(), + console: taggedConsole(id), + harness: { + defineTool: sandboxDefineTool, + registerTool: sandboxRegisterTool, + ...harnessExtras + }, + btoa: (s) => Buffer.from(s, "utf-8").toString("base64"), + atob: (s) => Buffer.from(s, "base64").toString("utf-8"), + TextEncoder, + TextDecoder + }; + createContext(sandbox); + patchDualRealmInstanceof(sandbox); + return sandbox; +} +/** +* Cross-realm SyntaxError detection: a compile failure inside `runInContext` +* constructs its error in the SANDBOX realm, so a host `instanceof +* SyntaxError` is silently false — the `name` property is the realm-safe tag. +*/ +function isSyntaxError(error) { + return typeof error === "object" && error !== null && error.name === "SyntaxError"; +} +/** +* The parse-failure context a vm `SyntaxError` carries: the vm prints the +* offending source line and a caret before the message, which is exactly what +* a model needs to self-correct — surface it instead of the bare message. +* Falls back to `String(error)` when the stack carries no such prelude. +* @param error - the `SyntaxError` (host- or sandbox-realm) thrown while compiling package code. +* @returns the stack prefix up to and including the `SyntaxError: …` line. +*/ +function syntaxErrorContext(error) { + const lines = (error.stack ?? "").split("\n"); + const messageIndex = lines.findIndex((line) => line.startsWith("SyntaxError")); + if (messageIndex === -1) return String(error); + return lines.slice(0, messageIndex + 1).join("\n"); +} +/** +* The teaching text one parse failure produces, shared by the define-time +* precheck and the run-time evaluation so a model reads the same diagnosis +* whichever verb caught it. +* @param half - which half failed to parse, named as the define argument that carried it. +* @param context - the {@link syntaxErrorContext} of the failure. +* @returns the model-facing error message. +*/ +function parseErrorMessage(half, context) { + const offendingLine = context.split("\n")[1] ?? ""; + if (/\bas\b/.test(offendingLine)) return `dynamic package \`${half}\` failed to parse:\n${context}\nThe sandbox runs plain JavaScript, not TypeScript. Remove type annotations: + ✗ { type: 'text' as const, text: x } + ✓ { type: 'text', text: x }`; + return `dynamic package \`${half}\` failed to parse:\n${context}\nNote: it runs as the BODY of an async function (line numbers are offset by the 1-line wrapper). Check bracket balance — ending the returned plugin object with \`});\` closes a call that was never opened; a plain \`return { … }\` ends with \`}\` (an optional \`;\`), never \`)\`.`; +} +/** +* Parse one half's source without running it: the define-time precheck that +* keeps unparseable code out of the registry, so a model fixes it and defines +* again instead of discovering the failure at run time. Compiling through `vm` +* rather than `new Function` is what makes the two agree — same wrapper, same +* compiler, and the same source-line-and-caret prelude in the failure. +* @param code - the model-written function body. +* @param half - which define argument carried it, for the error text. +* @throws when the body does not parse, with the offending line and a teaching hint. +*/ +function precheckCode(code, half) { + try { + new Script(`(async () => {\n${code}\n})()`, { filename: `cordis-dyn-${half}.js` }); + } catch (error) { + if (!isSyntaxError(error)) throw error; + throw new Error(parseErrorMessage(half, syntaxErrorContext(error))); + } +} +/** +* Evaluate a host half as the body of an async function inside the sandbox. `vmTimeoutMs` only +* bounds the SYNCHRONOUS portion; an async body escapes it — acceptable under the module's +* trust stance. Parse errors include the offending line and a TypeScript-removal or bracket- +* balance hint. +* @param sandbox - the contextified object from {@link createSandbox}. +* @param code - the model-written function body; must `return` a plugin. +* @param id - the package id, used as the vm filename (`cordis-dyn-.js`). +* @param vmTimeoutMs - the synchronous evaluation bound in milliseconds. +* @returns whatever the code returned, still un-narrowed (the run lifecycle checks plugin shape). +*/ +async function evaluateHostCode(sandbox, code, id, vmTimeoutMs) { + try { + return await runInContext(`(async () => {\n${code}\n})()`, sandbox, { + filename: `cordis-dyn-${id}.js`, + timeout: vmTimeoutMs + }); + } catch (error) { + if (!isSyntaxError(error)) throw error; + throw new Error(parseErrorMessage("code.host", syntaxErrorContext(error))); + } +} +//#endregion +//#region lib/types/index.js +/** +* Dynamic Cordis Plugin service: immutable package definitions, one active run +* per Plugin, human-approved Client activation, and Host/Client invocation. +* @module @deepseek-ai/dsh-cordis-host-runner +*/ +var __runInitializers = function(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + return useValue ? value : void 0; +}; +var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function(f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +/** +* Brand a Host-minted Plugin ID. +* @param id - opaque identifier minted by the Host registry. +* @returns the branded Plugin identifier. +*/ +function CordisDynamicPluginId(id) { + return id; +} +/** +* Brand a Host-minted Package ID. +* @param id - opaque identifier minted by the Host registry. +* @returns the branded Package identifier. +*/ +function CordisDynamicPackageId(id) { + return id; +} +/** +* Brand a Host-minted Plugin Run ID. +* @param id - opaque identifier minted by the Host registry. +* @returns the branded Plugin Run identifier. +*/ +function CordisDynamicPluginRunId(id) { + return id; +} +/** +* Brand a Host-minted approval request ID. +* @param id - opaque identifier minted by the Host registry. +* @returns the branded approval request identifier. +*/ +function ApprovalRequestId(id) { + return id; +} +/** Dynamic Plugin registry and Host-half lifecycle. */ +let DynamicCordisRunnerService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _undefineFromPanel_decorators; + let _runHostHalf_decorators; + let _getClientCode_decorators; + let _resolveRequestRun_decorators; + let _settleUserRun_decorators; + let _stopFromPanel_decorators; + let _syncInspectManifest_decorators; + let _resolveInspectQuery_decorators; + let _inventory_decorators; + let _reportRenderFailure_decorators; + let _reportClientGuardFailure_decorators; + let _invoke_decorators; + return class DynamicCordisRunnerService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _undefineFromPanel_decorators = [Remote("undefineFromPanel")]; + _runHostHalf_decorators = [Remote("runHostHalf")]; + _getClientCode_decorators = [Remote("getClientCode")]; + _resolveRequestRun_decorators = [Remote("resolveRequestRun")]; + _settleUserRun_decorators = [Remote("settleUserRun")]; + _stopFromPanel_decorators = [Remote("stopFromPanel")]; + _syncInspectManifest_decorators = [Remote("syncInspectManifest")]; + _resolveInspectQuery_decorators = [Remote("resolveInspectQuery")]; + _inventory_decorators = [Remote("inventory")]; + _reportRenderFailure_decorators = [Remote("reportRenderFailure")]; + _reportClientGuardFailure_decorators = [Remote("reportClientGuardFailure")]; + _invoke_decorators = [Remote("invoke")]; + __esDecorate(this, null, _undefineFromPanel_decorators, { + kind: "method", + name: "undefineFromPanel", + static: false, + private: false, + access: { + has: (obj) => "undefineFromPanel" in obj, + get: (obj) => obj.undefineFromPanel + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _runHostHalf_decorators, { + kind: "method", + name: "runHostHalf", + static: false, + private: false, + access: { + has: (obj) => "runHostHalf" in obj, + get: (obj) => obj.runHostHalf + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _getClientCode_decorators, { + kind: "method", + name: "getClientCode", + static: false, + private: false, + access: { + has: (obj) => "getClientCode" in obj, + get: (obj) => obj.getClientCode + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resolveRequestRun_decorators, { + kind: "method", + name: "resolveRequestRun", + static: false, + private: false, + access: { + has: (obj) => "resolveRequestRun" in obj, + get: (obj) => obj.resolveRequestRun + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _settleUserRun_decorators, { + kind: "method", + name: "settleUserRun", + static: false, + private: false, + access: { + has: (obj) => "settleUserRun" in obj, + get: (obj) => obj.settleUserRun + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _stopFromPanel_decorators, { + kind: "method", + name: "stopFromPanel", + static: false, + private: false, + access: { + has: (obj) => "stopFromPanel" in obj, + get: (obj) => obj.stopFromPanel + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _syncInspectManifest_decorators, { + kind: "method", + name: "syncInspectManifest", + static: false, + private: false, + access: { + has: (obj) => "syncInspectManifest" in obj, + get: (obj) => obj.syncInspectManifest + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resolveInspectQuery_decorators, { + kind: "method", + name: "resolveInspectQuery", + static: false, + private: false, + access: { + has: (obj) => "resolveInspectQuery" in obj, + get: (obj) => obj.resolveInspectQuery + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _inventory_decorators, { + kind: "method", + name: "inventory", + static: false, + private: false, + access: { + has: (obj) => "inventory" in obj, + get: (obj) => obj.inventory + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _reportRenderFailure_decorators, { + kind: "method", + name: "reportRenderFailure", + static: false, + private: false, + access: { + has: (obj) => "reportRenderFailure" in obj, + get: (obj) => obj.reportRenderFailure + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _reportClientGuardFailure_decorators, { + kind: "method", + name: "reportClientGuardFailure", + static: false, + private: false, + access: { + has: (obj) => "reportClientGuardFailure" in obj, + get: (obj) => obj.reportClientGuardFailure + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _invoke_decorators, { + kind: "method", + name: "invoke", + static: false, + private: false, + access: { + has: (obj) => "invoke" in obj, + get: (obj) => obj.invoke + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { + enumerable: true, + configurable: true, + writable: true, + value: _metadata + }); + } + static inject = ["tools"]; + static Config = z.object({ vmTimeoutMs: z.number().min(1).default(5e3) }); + rootCtx = __runInitializers(this, _instanceExtraInitializers); + registry = new DynamicCordisRegistry(); + inspectRegistry; + starting = /* @__PURE__ */ new Map(); + resolved; + group; + /** Create the service under the Host composition. */ + constructor(ctx, config) { + super(ctx, "dynamicCordisRunner"); + this.rootCtx = ctx; + this.resolved = config; + this.inspectRegistry = new CordisInspectRegistryService(ctx); + } + /** + * Define a new Plugin's first Package or append a Package to an existing Plugin. + * @param request - Session ownership, Plugin selection, metadata, and source code. + * @returns Host-minted Plugin and Package identities with declared-half metadata. + */ + define(request) { + const name = request.name.trim(); + const purpose = request.purpose.trim(); + if (name.length === 0) throw new Error("cordis_define needs a non-empty `name`"); + if (purpose.length === 0) throw new Error("cordis_define needs a non-empty `purpose`"); + if (request.code.host === void 0 && request.code.client === void 0) throw new Error("cordis_define needs `code.host`, `code.client`, or both"); + if (request.code.host !== void 0) precheckCode(request.code.host, "code.host"); + if (request.code.client !== void 0) precheckCode(request.code.client, "code.client"); + let plugin; + if (request.plugin.kind === "new") { + const prefix = request.plugin.idPrefix.trim(); + if (!/^[a-z]{3,6}$/.test(prefix)) throw new Error("cordis_define `plugin.idPrefix` must contain 3–6 lowercase English letters"); + plugin = { + pluginId: CordisDynamicPluginId(this.registry.mintPluginId(prefix)), + sessionId: request.sessionId, + packages: /* @__PURE__ */ new Map(), + approvedClientPackages: /* @__PURE__ */ new Set(), + clientVersionUpdatesApproved: false + }; + this.registry.add(plugin); + } else { + const found = this.registry.get(request.plugin.pluginId); + if (found === void 0 || found.sessionId !== request.sessionId) throw new Error(missingPluginMessage(request.plugin.pluginId)); + plugin = found; + } + const packageId = CordisDynamicPackageId(this.registry.mintPackageId()); + const definition = { + packageId, + name, + purpose, + ...request.code.host === void 0 ? {} : { hostCode: request.code.host }, + ...request.code.client === void 0 ? {} : { clientCode: request.code.client } + }; + plugin.packages.set(packageId, definition); + return { + pluginId: plugin.pluginId, + packageId, + name, + purpose, + hasHostHalf: definition.hostCode !== void 0, + hasClientHalf: definition.clientCode !== void 0 + }; + } + /** + * Remove a Plugin, its active run, and all immutable Packages. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + async undefine(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) return { + ok: false, + reason: "plugin-missing", + message: missingPluginMessage(pluginId) + }; + const wasRunning = plugin.run !== void 0; + this.cancelPending(pluginId, `dynamic plugin "${pluginId}" was removed before approval`); + if (plugin.run !== void 0) await this.retract(plugin); + this.registry.delete(pluginId); + return { + ok: true, + wasRunning + }; + } + /** + * Remove a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + async undefineFromPanel(agent, pluginId) { + const result = await this.undefine(agent, pluginId); + if (result.ok) this.injectUserContext(agent, `The user removed Cordis Plugin ${pluginId} and all of its Packages. The Plugin no longer exists.`); + return result; + } + /** + * Start or update one Package for a model tool call. An unauthorized Client + * Package waits for approval; Plugin-wide authorization covers later versions. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param signal - Tool-call cancellation signal while the activation request is being created. + * @returns The successful activation identity or an actionable refusal. + */ + async run(agent, pluginId, packageId, mode, signal) { + const plan = this.resolvePlan(agent, pluginId, packageId, mode); + if (!plan.ok) return plan.response; + if (signal?.aborted === true) return { + ok: false, + reason: "cancelled", + message: `the run request for dynamic plugin "${pluginId}" was cancelled before activation` + }; + if (this.registry.pendingRequestFor(pluginId) !== void 0) return { + ok: false, + reason: "transition-in-flight", + message: `dynamic plugin "${pluginId}" already has a pending run request` + }; + const attempt = this.createAttempt(plan); + plan.plugin.nextPackageId = packageId; + plan.plugin.latestRun = attempt; + if (plan.definition.clientCode === void 0) { + const started = await this.activate(plan, void 0, false, attempt); + if (started.ok) return this.runResponse(plan.plugin, started); + this.failAttempt(plan.plugin, attempt, "host-load", started); + return { + ...started, + reason: "host-half-failed" + }; + } + const requestId = ApprovalRequestId(this.registry.mintApprovalRequestId()); + const requiresApproval = !plan.plugin.clientVersionUpdatesApproved && !plan.plugin.approvedClientPackages.has(packageId); + attempt.approvalRequestId = requestId; + attempt.requiresApproval = requiresApproval; + attempt.status = requiresApproval ? "awaiting-approval" : "starting-host"; + this.registry.armRequest(requestId, { + agentId: agent.id, + pluginId, + packageId, + pluginRunId: attempt.pluginRunId, + mode, + requiresApproval + }); + this.ctx.emit("cordis/request-run", { + requestId, + agentId: agent.id, + pluginId, + packageId, + mode, + name: plan.definition.name, + purpose: plan.definition.purpose, + requiresApproval + }); + return { + ok: true, + status: requiresApproval ? "awaiting-approval" : "starting", + pluginId, + packageId, + pluginRunId: attempt.pluginRunId, + mode, + waitingFor: [], + ...plan.plugin.currentPackageId === void 0 ? {} : { currentPackageId: plan.plugin.currentPackageId }, + nextPackageId: packageId + }; + } + /** + * Start Host code for an approved request or a direct panel gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param requestId - Model-driven request identity, or null for a direct user gesture. + * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin. + * @returns The exact Host activation or a failure message. + */ + async runHostHalf(agent, pluginId, packageId, mode, requestId, approveFutureVersions) { + const plan = this.resolvePlan(agent, pluginId, packageId, mode, requestId === null); + if (!plan.ok) return { + ok: false, + message: plan.response.message + }; + let attempt; + if (requestId !== null) { + const pending = this.registry.peekRequest(requestId); + if (pending === void 0 || pending.pluginId !== pluginId || pending.packageId !== packageId || pending.mode !== mode) return { + ok: false, + message: `run request "${requestId}" does not authorize ${pluginId}/${packageId}` + }; + const latest = plan.plugin.latestRun; + const expectedStatus = pending.requiresApproval ? "awaiting-approval" : "starting-host"; + if (latest === void 0 || latest.pluginRunId !== pending.pluginRunId || latest.status !== expectedStatus && !pending.requiresApproval && latest.status !== "client-pending") return { + ok: false, + message: `run request "${requestId}" no longer identifies the latest run of ${pluginId}` + }; + attempt = latest; + if (pending.requiresApproval) { + plan.plugin.approvedClientPackages.add(packageId); + if (approveFutureVersions) plan.plugin.clientVersionUpdatesApproved = true; + } + } else { + const pending = this.registry.pendingRequestFor(pluginId); + if (pending !== void 0) return { + ok: false, + message: `dynamic plugin "${pluginId}" has pending run request ${pending}` + }; + const attached = plan.plugin.run?.packageId === packageId && plan.plugin.latestRun?.pluginRunId === plan.plugin.run.pluginRunId ? plan.plugin.latestRun : void 0; + attempt = attached ?? this.createAttempt(plan); + if (attached === void 0) { + plan.plugin.nextPackageId = packageId; + plan.plugin.latestRun = attempt; + } + if (plan.definition.clientCode !== void 0) plan.plugin.approvedClientPackages.add(packageId); + } + const attaching = attempt.pluginRunId === plan.plugin.run?.pluginRunId; + if (!attaching) { + attempt.status = "starting-host"; + if (attempt.host.status !== "absent") attempt.host = { + status: "pending", + waitingFor: [] + }; + } + const started = await this.activate(plan, requestId ?? void 0, attaching, attempt); + if (!started.ok) this.failAttempt(plan.plugin, attempt, "host-load", started); + return started; + } + /** + * Fetch Client code for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to read. + * @param pluginRunId - Exact active run authorized to receive source. + * @returns Client source and its Plugin, Package, and run identities. + */ + getClientCode(agent, pluginId, pluginRunId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) throw new Error(missingPluginMessage(pluginId)); + const run = plugin.run; + if (run === void 0 || run.pluginRunId !== pluginRunId) throw new Error(`dynamic plugin "${pluginId}" is not running activation "${pluginRunId}"`); + const definition = plugin.packages.get(run.packageId); + if (definition?.clientCode === void 0) throw new Error(`package "${run.packageId}" has no Client half`); + return { + code: definition.clientCode, + name: definition.name, + pluginId, + packageId: run.packageId, + pluginRunId + }; + } + /** + * Resolve one model-driven Client activation request. + * @param requestId - Request identity to settle once. + * @param resolution - Browser refusal or exact Client activation result. + * @returns Whether the still-pending request accepted this resolution. + */ + async resolveRequestRun(requestId, resolution) { + const pending = this.registry.peekRequest(requestId); + if (pending === void 0) return { accepted: false }; + const plugin = this.registry.get(pending.pluginId); + if (resolution.ok && plugin?.run?.pluginRunId !== resolution.pluginRunId) return { accepted: false }; + if (!resolution.ok && resolution.pluginRunId !== void 0 && plugin?.run?.pluginRunId !== resolution.pluginRunId) return { accepted: false }; + this.registry.claimRequest(requestId); + const settled = await this.settleActivation(plugin, resolution, requestId); + this.announceResolved(requestId, resolution, pending.requiresApproval ? void 0 : "completed"); + this.steerRunOutcome(pending, settled); + return { accepted: true }; + } + /** + * Settle a direct panel run after this page loaded or failed its Client half. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity being settled. + * @param resolution - Exact Client activation result from the acting page. + * @returns The committed activation or its failure. + */ + async settleUserRun(agent, pluginId, resolution) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) return { + ok: false, + reason: "plugin-missing", + message: missingPluginMessage(pluginId) + }; + const settled = await this.settleActivation(plugin, resolution); + this.injectUserRunOutcome(agent, pluginId, settled); + return settled; + } + /** + * Stop the active run while retaining every Package version. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + async stop(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) return { + ok: false, + reason: "plugin-missing", + message: missingPluginMessage(pluginId) + }; + const pending = this.registry.pendingRequestFor(pluginId); + if (plugin.run === void 0 && pending === void 0) return { + ok: false, + reason: "not-running", + message: `dynamic plugin "${pluginId}" is not running` + }; + if (pending !== void 0) this.cancelPending(pluginId, `dynamic plugin "${pluginId}" was stopped before approval`); + if (plugin.run !== void 0) await this.retract(plugin); + if (plugin.latestRun !== void 0) { + plugin.latestRun.status = "stopped"; + if (plugin.latestRun.host.status !== "absent") plugin.latestRun.host = { + status: "stopped", + waitingFor: [] + }; + if (plugin.latestRun.client.status !== "absent") plugin.latestRun.client = { + status: "stopped", + waitingFor: [] + }; + } + return { ok: true }; + } + /** + * Stop a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + async stopFromPanel(agent, pluginId) { + const result = await this.stop(agent, pluginId); + if (!result.ok) return result; + const plugin = this.owned(agent, pluginId); + this.injectUserContext(agent, `The user stopped Cordis Plugin ${pluginId}. Its Packages remain defined; currentPackageId is ${plugin?.currentPackageId ?? "none"}.`); + return result; + } + /** + * Replace the Host mirror of the Client inspect provider directory. + * @param providers - complete Client provider manifest. + * @returns null after accepting the manifest. + */ + syncInspectManifest(providers) { + this.inspectRegistry.syncClientManifest(providers); + return null; + } + /** + * Claim one pending Client inspect query with its live result. + * @param agent - Session that owns the query. + * @param requestId - exact pending query identity. + * @param resolution - provider result or structured refusal. + * @returns whether this answer won the query. + */ + resolveInspectQuery(agent, requestId, resolution) { + return this.inspectRegistry.resolveClientQuery(agent, requestId, resolution); + } + /** + * Frame-wide inventory, grouped as one row per stable Plugin. + * @returns Source-free metadata for every process-local Plugin. + */ + inventory() { + return this.registry.all().map((plugin) => ({ + pluginId: plugin.pluginId, + agentId: plugin.sessionId, + packages: [...plugin.packages.values()].map((definition) => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== void 0, + hasClientHalf: definition.clientCode !== void 0 + })), + ...plugin.currentPackageId === void 0 ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === void 0 ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === void 0 ? {} : { activeRun: { + pluginRunId: plugin.run.pluginRunId, + packageId: plugin.run.packageId + } }, + ...plugin.latestRun === void 0 ? {} : { latestRun: cloneAttempt(plugin.latestRun) } + })); + } + /** + * Read one Session's Host-rich state for inspection and result rendering. + * @param agent - Agent whose Session selects visible Plugins. + * @returns Plugin versions, active runs, Host fibers, and render failures. + */ + snapshot(agent) { + return this.registry.ofSession(agent.id).map((plugin) => ({ + pluginId: plugin.pluginId, + ...plugin.currentPackageId === void 0 ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === void 0 ? {} : { nextPackageId: plugin.nextPackageId }, + packages: [...plugin.packages.values()].map((definition) => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== void 0, + hasClientHalf: definition.clientCode !== void 0 + })), + ...plugin.run === void 0 ? {} : { activeRun: { + pluginRunId: plugin.run.pluginRunId, + packageId: plugin.run.packageId, + ...plugin.run.fiber === void 0 ? {} : { fiber: plugin.run.fiber }, + handlers: [...plugin.run.handlers.keys()], + ...plugin.run.renderFailure === void 0 ? {} : { renderFailure: plugin.run.renderFailure } + } }, + ...plugin.latestRun === void 0 ? {} : { latestRun: cloneAttempt(plugin.latestRun) } + })); + } + /** + * Read source-free context for an explicit `@pluginId` user gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity referenced by the user. + * @returns The preferred modification base, or undefined when unavailable. + */ + reference(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) return void 0; + const packageId = plugin.nextPackageId ?? plugin.currentPackageId ?? [...plugin.packages.keys()].at(-1); + if (packageId === void 0) return void 0; + const definition = plugin.packages.get(packageId); + if (definition === void 0) return void 0; + return { + pluginId, + packageId, + name: definition.name, + purpose: definition.purpose, + ...plugin.currentPackageId === void 0 ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === void 0 ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === void 0 ? {} : { activeRun: { + pluginRunId: plugin.run.pluginRunId, + packageId: plugin.run.packageId + } }, + ...plugin.latestRun === void 0 ? {} : { latestRun: cloneAttempt(plugin.latestRun) } + }; + } + /** + * List source-free Plugin summaries owned by one Session. + * @param agent - Agent whose Session selects visible Plugins. + * @returns one summary per Plugin in creation order. + */ + listPlugins(agent) { + return this.registry.ofSession(agent.id).map((plugin) => this.inspectPlugin(agent, plugin.pluginId)); + } + /** + * Inspect one Plugin without returning Package source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - stable Plugin identity. + * @returns version pointers, latest run, and all Package summaries. + */ + inspectPlugin(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) throw new Error(missingPluginMessage(pluginId)); + const reference = this.reference(agent, pluginId); + if (reference === void 0) throw new Error(`dynamic plugin "${pluginId}" has no package`); + return { + ...reference, + packages: [...plugin.packages.values()].map((definition) => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== void 0, + hasClientHalf: definition.clientCode !== void 0 + })) + }; + } + /** + * Read one exact immutable Package and its Host and Client source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that owns the Package. + * @param packageId - Exact immutable Package identity to inspect. + * @returns Package metadata, source, and the Plugin's lifecycle pointers. + */ + inspectPackage(agent, pluginId, packageId) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) throw new Error(missingPluginMessage(pluginId)); + const definition = plugin.packages.get(packageId); + if (definition === void 0) throw new Error(`dynamic package "${packageId}" does not exist on plugin "${pluginId}"`); + return { + pluginId, + packageId, + name: definition.name, + purpose: definition.purpose, + code: { + ...definition.hostCode === void 0 ? {} : { host: definition.hostCode }, + ...definition.clientCode === void 0 ? {} : { client: definition.clientCode } + }, + ...plugin.currentPackageId === void 0 ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === void 0 ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === void 0 ? {} : { activeRun: { + pluginRunId: plugin.run.pluginRunId, + packageId: plugin.run.packageId + } }, + ...plugin.latestRun === void 0 ? {} : { latestRun: cloneAttempt(plugin.latestRun) } + }; + } + /** + * Record a post-load render failure for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that rendered. + * @param pluginRunId - Exact active run that produced the failure. + * @param failure - Slot, message, and entry-retirement result. + * @returns Null after recording or ignoring a stale report. + */ + async reportRenderFailure(agent, pluginId, pluginRunId, failure) { + const plugin = this.owned(agent, pluginId); + if (plugin?.run?.pluginRunId === pluginRunId) { + const run = plugin.run; + const definition = plugin.packages.get(plugin.run.packageId); + const shouldSteer = run.renderFailure === void 0; + run.renderFailure = failure; + const attempt = plugin.latestRun; + if (attempt?.pluginRunId === pluginRunId) { + attempt.error = this.diagnostic(plugin, attempt, "client-render", failure); + attempt.client = { + status: "failed", + waitingFor: attempt.client.waitingFor, + error: failure.message + }; + attempt.status = "failed"; + } + if (definition !== void 0 && shouldSteer) this.steerRenderFailure(agent, plugin, definition, pluginRunId, failure); + } + return await Promise.resolve(null); + } + /** + * Report a Client guard rejection that happened after the Package completed activation. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity whose Client code was rejected. + * @param pluginRunId - Exact active run that produced the rejection. + * @param failure - Original guard message and stack. + * @returns Null after reporting or ignoring a stale/startup failure. + */ + async reportClientGuardFailure(agent, pluginId, pluginRunId, failure) { + const plugin = this.owned(agent, pluginId); + const run = plugin?.run; + if (plugin !== void 0 && run?.pluginRunId === pluginRunId) this.steerGuardFailure(plugin, run, "Client", failure); + return await Promise.resolve(null); + } + /** + * Invoke an active Host method while rejecting stale Client runs. + * @param pluginId - Stable Plugin identity that owns the method. + * @param pluginRunId - Exact active run authorizing the call. + * @param method - Registered Host handler name. + * @param args - JSON argument delivered to the handler. + * @returns The JSON result or a typed invocation failure. + */ + async invoke(pluginId, pluginRunId, method, args) { + const plugin = this.registry.get(pluginId); + if (plugin === void 0 || plugin.run === void 0) return { + ok: false, + code: "plugin-not-running", + message: `dynamic plugin "${pluginId}" is not running` + }; + const run = plugin.run; + if (run.pluginRunId !== pluginRunId) return { + ok: false, + code: "stale-run", + message: `activation "${pluginRunId}" is no longer active` + }; + const handler = run.handlers.get(method); + if (handler === void 0) return { + ok: false, + code: "method-not-found", + message: `dynamic plugin "${pluginId}" registered no Host method "${method}"` + }; + try { + return { + ok: true, + value: await handler(args) + }; + } catch (error) { + const failure = errorDetails(error); + this.steerHostHandlerFailure(plugin, run, method, failure); + return { + ok: false, + code: "handler-error", + ...failure + }; + } + } + resolvePlan(agent, pluginId, packageId, mode, allowActiveAttach = false) { + const plugin = this.owned(agent, pluginId); + if (plugin === void 0) return { + ok: false, + response: { + ok: false, + reason: "plugin-missing", + message: missingPluginMessage(pluginId) + } + }; + const definition = plugin.packages.get(packageId); + if (definition === void 0) return { + ok: false, + response: { + ok: false, + reason: "package-missing", + message: `plugin "${pluginId}" has no package "${packageId}"` + } + }; + const current = plugin.currentPackageId; + if (mode === "update" && (current === void 0 || current === packageId)) return { + ok: false, + response: { + ok: false, + reason: "invalid-mode", + message: current === void 0 ? `plugin "${pluginId}" has no successful version yet; start "${packageId}" with mode "run"` : `package "${packageId}" is already current; use mode "run"` + } + }; + if (mode === "run" && current !== void 0 && current !== packageId) return { + ok: false, + response: { + ok: false, + reason: "invalid-mode", + message: `package "${packageId}" differs from current "${current}"; use mode "update"` + } + }; + if (!allowActiveAttach && this.starting.has(pluginId)) return { + ok: false, + response: { + ok: false, + reason: "transition-in-flight", + message: `plugin "${pluginId}" is already starting` + } + }; + return { + ok: true, + plugin, + definition, + mode + }; + } + activate(plan, requestId, allowActiveAttach, attempt) { + const inFlight = this.starting.get(plan.plugin.pluginId); + if (inFlight !== void 0) return inFlight; + const starting = this.startFresh(plan, requestId, allowActiveAttach, attempt); + this.starting.set(plan.plugin.pluginId, starting); + return starting.finally(() => { + this.starting.delete(plan.plugin.pluginId); + }); + } + async startFresh(plan, requestId, allowActiveAttach, attempt) { + const { plugin, definition, mode } = plan; + if (allowActiveAttach && plugin.run?.packageId === definition.packageId && plugin.run.pluginRunId === attempt.pluginRunId) return { + ok: true, + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: plugin.run.pluginRunId, + waitingFor: missingFor(this.ctx, plugin.run), + startedHere: false + }; + if (plugin.run !== void 0) await this.retract(plugin); + if (mode === "update" || plugin.currentPackageId === void 0) plugin.nextPackageId = definition.packageId; + const run = { + pluginRunId: attempt.pluginRunId, + packageId: definition.packageId, + handlers: /* @__PURE__ */ new Map(), + handlerDisposers: [], + reportedRuntimeErrors: /* @__PURE__ */ new Set(), + ...requestId === void 0 ? {} : { startedForRequest: requestId } + }; + if (definition.hostCode !== void 0) { + const failure = await this.startHost(plugin, definition.hostCode, run); + if (failure !== void 0) return { + ok: false, + ...failure + }; + } + plugin.run = run; + this.ctx.emit("cordis/dynamic-package", { + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: run.pluginRunId, + name: definition.name + }); + attempt.host = { + status: run.fiber === void 0 ? "absent" : missingFor(this.ctx, run).length === 0 ? "running" : "waiting", + waitingFor: missingFor(this.ctx, run) + }; + if (definition.clientCode === void 0) this.commitActivation(plugin, run); + else { + attempt.status = "client-pending"; + attempt.client = { + status: "pending", + waitingFor: [] + }; + } + return { + ok: true, + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: run.pluginRunId, + waitingFor: missingFor(this.ctx, run), + startedHere: true + }; + } + async startHost(plugin, hostCode, run) { + const handle = (method, fn) => { + const normalized = normalizeHandler(method, fn); + run.handlers.set(normalized.method, normalized.handler); + const dispose = () => { + if (run.handlers.get(normalized.method) === normalized.handler) run.handlers.delete(normalized.method); + }; + run.handlerDisposers.push(dispose); + return dispose; + }; + try { + const evaluated = await evaluateHostCode(createSandbox(plugin.pluginId, { handle }), hostCode, plugin.pluginId, this.resolved.vmTimeoutMs); + if (!isPlugin(evaluated)) throw new Error(evaluated === void 0 ? "the Host half returned `undefined` — did you forget `return`?" : "the Host half must return a Plugin function or an object with apply(ctx)"); + run.fiber = await startHostHalf(this.requireGroup(), evaluated, (error) => { + this.steerGuardFailure(plugin, run, "Host", errorDetails(error)); + }); + return; + } catch (error) { + for (const dispose of run.handlerDisposers.splice(0)) dispose(); + return errorDetails(error); + } + } + async settleActivation(plugin, resolution, requestId) { + if (plugin === void 0) return { + ok: false, + reason: "plugin-missing", + message: "the dynamic plugin was removed during activation" + }; + const attempt = plugin.latestRun; + if (!resolution.ok) { + if (resolution.reason === "rejected") { + if (attempt !== void 0) { + attempt.status = "rejected"; + attempt.error = this.diagnostic(plugin, attempt, "approval", resolution.message ?? "the run request was declined"); + attempt.client = { + status: "stopped", + waitingFor: [] + }; + } + return { + ok: false, + reason: "rejected", + message: resolution.message ?? "the run request was declined" + }; + } + const run = plugin.run; + if (run !== void 0 && resolution.pluginRunId === run.pluginRunId && (requestId === void 0 || run.startedForRequest === requestId) && resolution.startedHere !== false) await this.retract(plugin); + if (attempt !== void 0 && (resolution.pluginRunId === void 0 || attempt.pluginRunId === resolution.pluginRunId)) this.failAttempt(plugin, attempt, resolution.reason === "host-half-failed" ? "host-apply" : "client-apply", { + message: resolution.message ?? resolution.reason, + ...resolution.stack === void 0 ? {} : { stack: resolution.stack } + }); + return { + ok: false, + reason: resolution.reason, + message: resolution.message ?? resolution.reason, + ...resolution.stack === void 0 ? {} : { stack: resolution.stack } + }; + } + const run = plugin.run; + if (run === void 0 || run.pluginRunId !== resolution.pluginRunId) return { + ok: false, + reason: "client-half-failed", + message: `activation "${resolution.pluginRunId}" is no longer active` + }; + if (attempt !== void 0 && attempt.pluginRunId === run.pluginRunId) attempt.client = { + status: resolution.waitingFor === void 0 || resolution.waitingFor.length === 0 ? "running" : "waiting", + waitingFor: resolution.waitingFor ?? [] + }; + this.commitActivation(plugin, run); + return { + ...this.runResponse(plugin, { + ok: true, + pluginId: plugin.pluginId, + packageId: run.packageId, + pluginRunId: run.pluginRunId, + waitingFor: missingFor(this.ctx, run), + startedHere: false + }), + ...resolution.waitingFor === void 0 ? {} : { clientWaitingFor: resolution.waitingFor } + }; + } + commitActivation(plugin, run) { + plugin.currentPackageId = run.packageId; + delete plugin.nextPackageId; + delete run.startedForRequest; + const attempt = plugin.latestRun; + if (attempt?.pluginRunId === run.pluginRunId) { + attempt.status = attempt.host.status === "waiting" || attempt.client.status === "waiting" ? "waiting" : "running"; + delete attempt.approvalRequestId; + delete attempt.requiresApproval; + delete attempt.error; + } + } + runResponse(plugin, started) { + return { + ok: true, + status: "running", + pluginId: plugin.pluginId, + packageId: started.packageId, + pluginRunId: started.pluginRunId, + waitingFor: started.waitingFor, + currentPackageId: started.packageId, + mode: plugin.latestRun?.pluginRunId === started.pluginRunId ? plugin.latestRun.mode : "run" + }; + } + announceResolved(requestId, resolution, override) { + const outcome = override ?? (resolution.ok ? "approved" : resolution.reason === "rejected" ? "rejected" : "failed"); + this.ctx.emit("cordis/request-run-resolved", { + requestId, + outcome + }); + } + steerRunOutcome(pending, settled) { + const agent = this.rootCtx.get("agents")?.get(pending.agentId); + if (agent === void 0) return; + const plugin = this.registry.get(pending.pluginId); + const identity = `${pending.pluginId}/${pending.packageId} (${pending.pluginRunId})`; + let text; + if (settled.ok) text = `Cordis ${pending.mode} ${identity} completed successfully. currentPackageId is ${settled.currentPackageId ?? pending.packageId}. Continue using the running Plugin.`; + else if (settled.reason === "rejected") text = `The user rejected Cordis ${pending.mode} ${identity}. Do not request the same activation again unless the user asks.`; + else { + const returnedStatus = pending.requiresApproval ? "awaiting-approval" : "starting"; + text = `Cordis ${pending.mode} ${identity} failed after cordis_run returned ${returnedStatus}: ${settled.reason}\n${formatErrorDetails(settled)}\ncurrentPackageId: ${plugin?.currentPackageId ?? "none"}\nnextPackageId: ${plugin?.nextPackageId ?? pending.packageId}\nInspect the failed Package, correct it on the same Plugin when needed, and retry the activation autonomously.`; + } + agent.steer(createUserMessage({ + content: [{ + type: "text", + text + }], + source: { + kind: "plugin", + plugin: "cordis-host-runner" + } + })); + } + steerRenderFailure(agent, plugin, definition, pluginRunId, failure) { + agent.steer(createUserMessage({ + content: [{ + type: "text", + text: `Cordis Client UI ${plugin.pluginId}/${definition.packageId} (${pluginRunId}) failed while rendering Slot "${failure.slot}" after activation.\n${formatErrorDetails(failure)}\nentryAbdicated: ${failure.abdicated}\nInspect the failed Package, fix the Client code by defining a new Package on the same Plugin, and activate that Package autonomously with cordis_run mode:"update".` + }], + source: { + kind: "plugin", + plugin: "cordis-host-runner" + } + })); + } + steerHostHandlerFailure(plugin, run, method, failure) { + const reportKey = `Host\u0000handler\u0000${method}\u0000${failure.message}`; + if (!this.claimRuntimeFailure(plugin, run, reportKey)) return; + const agent = this.rootCtx.get("agents")?.get(plugin.sessionId); + if (agent === void 0) return; + agent.steer(createUserMessage({ + content: [{ + type: "text", + text: `Cordis Host handler ${plugin.pluginId}/${run.packageId} (${run.pluginRunId}) failed when the Client called host.call(${JSON.stringify(method)}).\n${formatErrorDetails(failure)}\nThe Plugin remains running. Inspect this Package, correct the Host code on the same Plugin, and activate the new Package autonomously with cordis_run mode:"update". If the handler needs a Service, either declare that Service in the returned Plugin inject list or read it with ctx.get(name) and handle undefined.` + }], + source: { + kind: "plugin", + plugin: "cordis-host-runner" + } + })); + } + steerGuardFailure(plugin, run, platform, failure) { + const reportKey = `${platform}\u0000guard\u0000${failure.message}`; + if (!this.claimRuntimeFailure(plugin, run, reportKey)) return; + const agent = this.rootCtx.get("agents")?.get(plugin.sessionId); + if (agent === void 0) return; + agent.steer(createUserMessage({ + content: [{ + type: "text", + text: `Cordis ${platform} guard rejected runtime code in ${plugin.pluginId}/${run.packageId} (${run.pluginRunId}) after activation.\n${formatErrorDetails(failure)}\nThe Plugin remains running. Inspect this Package, define a corrected Package on the same Plugin, and activate it autonomously with cordis_run mode:"update".` + }], + source: { + kind: "plugin", + plugin: "cordis-host-runner" + } + })); + } + claimRuntimeFailure(plugin, run, key) { + const attempt = plugin.latestRun; + if (plugin.run !== run || attempt?.pluginRunId !== run.pluginRunId || attempt.status !== "running" && attempt.status !== "waiting") return false; + if (run.reportedRuntimeErrors.has(key)) return false; + run.reportedRuntimeErrors.add(key); + return true; + } + injectUserRunOutcome(agent, pluginId, settled) { + const plugin = this.owned(agent, pluginId); + let text; + if (settled.ok) text = `The user manually ran Cordis Plugin ${pluginId}, Package ${settled.packageId}, as ${settled.pluginRunId}. The activation succeeded; currentPackageId is ${settled.currentPackageId}.`; + else { + const attempt = plugin?.latestRun; + text = `The user manually ran Cordis Plugin ${pluginId}${attempt === void 0 ? "" : `, Package ${attempt.packageId}, as ${attempt.pluginRunId}`}, but it failed: ${settled.reason}\n${formatErrorDetails(settled)}\ncurrentPackageId: ${plugin?.currentPackageId ?? "none"}\nnextPackageId: ${plugin?.nextPackageId ?? "none"}`; + } + this.injectUserContext(agent, text); + } + injectUserContext(agent, text) { + if (this.rootCtx.get("agents")?.get(agent.id) !== agent) return; + agent.inject(createUserMessage({ + content: [{ + type: "text", + text + }], + source: { + kind: "plugin", + plugin: "cordis-host-runner" + } + })); + } + cancelPending(pluginId, message) { + const requestId = this.registry.pendingRequestFor(pluginId); + if (requestId === void 0) return; + const pending = this.registry.claimRequest(requestId); + if (pending === void 0) return; + const plugin = this.registry.get(pluginId); + if (plugin?.latestRun?.pluginRunId === pending.pluginRunId) { + plugin.latestRun.status = "cancelled"; + plugin.latestRun.error = this.diagnostic(plugin, plugin.latestRun, "approval", message); + delete plugin.latestRun.approvalRequestId; + delete plugin.latestRun.requiresApproval; + } + this.announceResolved(requestId, { + ok: false, + reason: "rejected" + }, "cancelled"); + } + createAttempt(plan) { + return { + pluginRunId: CordisDynamicPluginRunId(this.registry.mintPluginRunId()), + packageId: plan.definition.packageId, + mode: plan.mode, + status: "starting-host", + host: { + status: plan.definition.hostCode === void 0 ? "absent" : "pending", + waitingFor: [] + }, + client: { + status: plan.definition.clientCode === void 0 ? "absent" : "pending", + waitingFor: [] + } + }; + } + failAttempt(plugin, attempt, phase, failure) { + attempt.status = "failed"; + attempt.error = this.diagnostic(plugin, attempt, phase, failure); + if (phase.startsWith("host")) attempt.host = { + status: "failed", + waitingFor: [], + error: failure.message + }; + else attempt.client = { + status: "failed", + waitingFor: [], + error: failure.message + }; + } + diagnostic(plugin, attempt, phase, failure) { + return { + phase, + ...typeof failure === "string" ? { message: failure } : failure, + pluginId: plugin.pluginId, + packageId: attempt.packageId, + pluginRunId: attempt.pluginRunId + }; + } + async retract(plugin) { + const run = plugin.run; + if (run === void 0) return; + delete plugin.run; + for (const dispose of run.handlerDisposers.splice(0)) dispose(); + if (run.fiber !== void 0) await run.fiber.dispose(); + this.ctx.emit("cordis/dynamic-retract", { + pluginId: plugin.pluginId, + packageId: run.packageId, + pluginRunId: run.pluginRunId + }); + } + owned(agent, pluginId) { + const plugin = this.registry.get(pluginId); + return plugin?.sessionId === agent.id ? plugin : void 0; + } + requireGroup() { + this.group ??= this.rootCtx.plugin({ + name: "cordis-dynamic", + apply: () => {} + }); + return this.group; + } + }; +})(); +function missingFor(ctx, run) { + return run.fiber === void 0 ? [] : missingServices(ctx, run.fiber); +} +function missingPluginMessage(id) { + return `no dynamic plugin "${id}" in this process — it may have been removed or lost on DSH restart`; +} +function errorDetails(error) { + if (typeof error !== "object" || error === null) return { message: String(error) }; + const message = "message" in error && typeof error.message === "string" ? error.message : Object.prototype.toString.call(error); + const stack = "stack" in error && typeof error.stack === "string" ? error.stack : void 0; + return { + message, + ...stack === void 0 ? {} : { stack } + }; +} +function formatErrorDetails(failure) { + return `message: ${failure.message}` + (failure.stack === void 0 ? "" : `\nstack:\n${failure.stack}`); +} +function cloneAttempt(attempt) { + return { + ...attempt, + host: { + ...attempt.host, + waitingFor: [...attempt.host.waitingFor] + }, + client: { + ...attempt.client, + waitingFor: [...attempt.client.waitingFor] + }, + ...attempt.error === void 0 ? {} : { error: { ...attempt.error } } + }; +} +//#endregion +export { ApprovalRequestId, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisInspectRegistryService, DynamicCordisRunnerService, DynamicCordisRunnerService as default, HOST_BUILTIN_INSPECTION }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/invariant.js new file mode 100644 index 0000000..bd5d424 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/invariant.js @@ -0,0 +1,25 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-cordis-host-runner`. +* @module @deepseek-ai/dsh-cordis-host-runner/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-cordis-host-runner"; +/** Cordis companion plugin name. */ +const name = "cordis-host-runner-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the definition registry is process memory with no event +* stream to observe, and its one owned relation (a running definition owns a +* settled host-half fiber and its handler table) is established and unwound +* inside single awaited verbs, so package tests assert it directly. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.d.ts new file mode 100644 index 0000000..dcf4919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.d.ts @@ -0,0 +1,3 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ + +export declare const TYPERT: unknown diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.js new file mode 100644 index 0000000..2255473 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.host.js @@ -0,0 +1,1905 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ +import { z } from 'zod' + +const JsonValueRemoteCodec$schema = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]) +const JsonValueRemoteCodec$schema2 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]) +const JsonValueRemoteCodec$schema3 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]) +const JsonValueRemoteCodec$schema4 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema4)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema4))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema = z.object({ + 'code': z.string(), + 'name': z.string(), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema = z.array(z.object({ + 'pluginId': z.intersection(z.string(), z.unknown()), + 'agentId': z.intersection(z.string(), z.unknown()), + 'packages': z.array(z.object({ + 'packageId': z.intersection(z.string(), z.unknown()), + 'name': z.string(), + 'purpose': z.string(), + 'hasHostHalf': z.boolean(), + 'hasClientHalf': z.boolean(), +})), + 'currentPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'nextPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'activeRun': z.object({ + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), +}).optional(), + 'latestRun': z.object({ + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'mode': z.union([z.literal("run"), z.literal("update")]), + 'status': z.union([z.literal("rejected"), z.literal("awaiting-approval"), z.literal("running"), z.literal("cancelled"), z.literal("starting-host"), z.literal("client-pending"), z.literal("waiting"), z.literal("failed"), z.literal("stopped")]), + 'approvalRequestId': z.intersection(z.string(), z.unknown()).optional(), + 'requiresApproval': z.boolean().optional(), + 'host': z.object({ + 'status': z.union([z.literal("running"), z.literal("waiting"), z.literal("failed"), z.literal("stopped"), z.literal("absent"), z.literal("pending")]), + 'waitingFor': z.array(z.string()), + 'error': z.string().optional(), +}), + 'client': z.object({ + 'status': z.union([z.literal("running"), z.literal("waiting"), z.literal("failed"), z.literal("stopped"), z.literal("absent"), z.literal("pending")]), + 'waitingFor': z.array(z.string()), + 'error': z.string().optional(), +}), + 'error': z.object({ + 'phase': z.union([z.literal("approval"), z.literal("host-load"), z.literal("host-apply"), z.literal("client-load"), z.literal("client-apply"), z.literal("client-render")]), + 'message': z.string(), + 'stack': z.string().optional(), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), +}).optional(), +}).optional(), +})) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema = z.string() +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'value': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema4)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema4))]), +}), z.intersection(z.object({ + 'ok': z.literal(false), + 'code': z.union([z.literal("plugin-not-running"), z.literal("stale-run"), z.literal("method-not-found"), z.literal("handler-error")]), +}), z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema = z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema = z.object({ + 'slot': z.string(), + 'message': z.string(), + 'stack': z.string().optional(), + 'abdicated': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema = z.union([z.object({ + 'ok': z.literal(true), + 'data': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("cancelled"), z.literal("provider-missing"), z.literal("method-missing"), z.literal("invalid-input"), z.literal("provider-error")]), + 'message': z.string(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema = z.object({ + 'accepted': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()).optional(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed")]), + 'pluginRunId': z.intersection(z.string(), z.unknown()).optional(), + 'startedHere': z.boolean().optional(), + 'message': z.string().optional(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema = z.object({ + 'accepted': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema = z.union([z.literal("run"), z.literal("update")]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema = z.union([z.literal(null), z.intersection(z.string(), z.unknown())]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema = z.boolean() +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()), + 'startedHere': z.boolean(), +}), z.intersection(z.object({ + 'ok': z.literal(false), +}), z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()).optional(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed")]), + 'pluginRunId': z.intersection(z.string(), z.unknown()).optional(), + 'startedHere': z.boolean().optional(), + 'message': z.string().optional(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'status': z.union([z.literal("awaiting-approval"), z.literal("starting"), z.literal("running")]), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()), + 'clientWaitingFor': z.array(z.string()).optional(), + 'currentPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'nextPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'mode': z.union([z.literal("run"), z.literal("update")]), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("plugin-missing"), z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed"), z.literal("package-missing"), z.literal("invalid-mode"), z.literal("transition-in-flight"), z.literal("cancelled"), z.literal("not-running")]), + 'message': z.string(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema = z.union([z.object({ + 'ok': z.literal(true), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("plugin-missing"), z.literal("not-running")]), + 'message': z.string(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema = z.array(z.object({ + 'id': z.string(), + 'description': z.string(), + 'methods': z.array(z.object({ + 'name': z.string(), + 'description': z.string(), + 'inputSchema': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]), + 'outputSchema': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]), +})), +})) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'wasRunning': z.boolean(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.literal("plugin-missing"), + 'message': z.string(), +})]) + +export const TYPERT = { + package: '@deepseek-ai/dsh-cordis-host-runner', + face: 'host', + schemas: [ + ], + invocations: [ + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/getClientCode', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'getClientCode', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisClientSource', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":384,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'inventory', + invocation: { kind: 'direct' }, + parameters: [ + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":525,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'invoke', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema, + }, + }, + { + name: 'method', + wire: 'method', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke:method', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema, + }, + }, + { + name: 'args', + wire: 'args', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#JsonValue', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisInvokeResult', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":741,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'reportClientGuardFailure', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema, + }, + }, + { + name: 'failure', + wire: 'failure', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisErrorDetails', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":718,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'reportRenderFailure', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema, + }, + }, + { + name: 'failure', + wire: 'failure', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRenderFailure', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":684,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveInspectQuery', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'resolveInspectQuery', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema, + }, + }, + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectRequestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectQueryResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectResolveAck', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":511,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveRequestRun', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'resolveRequestRun', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#ApprovalRequestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisResolveAck', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":413,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'runHostHalf', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema, + }, + }, + { + name: 'packageId', + wire: 'packageId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPackageId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema, + }, + }, + { + name: 'mode', + wire: 'mode', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicRunMode', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema, + }, + }, + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:requestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema, + }, + }, + { + name: 'approveFutureVersions', + wire: 'approveFutureVersions', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:approveFutureVersions', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisHostHalfResult', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":325,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/settleUserRun', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'settleUserRun', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResponse', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":438,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/stopFromPanel', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'stopFromPanel', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisStopResponse', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":480,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'syncInspectManifest', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'providers', + wire: 'providers', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:providers', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":498,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/undefineFromPanel', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'undefineFromPanel', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisUndefineReceipt', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":227,"column":9}, + }, + ], + model: { + "services": [ + { + "description": "Registry and cross-page router behind the two model-facing inspect tools.", + "summary": "Registry and cross-page router behind the two model-facing inspect tools.", + "tags": [], + "jsDoc": "/** Registry and cross-page router behind the two model-facing inspect tools. */", + "key": "cordisInspect", + "exportName": "CordisInspectRegistryService", + "members": [ + { + "kind": "method", + "name": "register", + "signature": "register(registration: HostCordisInspectProviderRegistration): () => void", + "summary": "Register one Host provider.", + "jsDoc": "/**\n * Register one Host provider.\n * @param registration - manifest and local query handler.\n * @returns idempotent disposer.\n */" + }, + { + "kind": "method", + "name": "syncClientManifest", + "signature": "syncClientManifest(providers: readonly CordisInspectProviderManifest[]): void", + "summary": "Replace the mirrored Client provider directory.", + "jsDoc": "/**\n * Replace the mirrored Client provider directory.\n * @param providers - complete Client manifest snapshot.\n */" + }, + { + "kind": "method", + "name": "list", + "signature": "list(): CordisInspectProviderView[]", + "summary": "Return the complete known Host and Client provider directory.", + "jsDoc": "/**\n * Return the complete known Host and Client provider directory.\n * @returns Host providers followed by the Client providers.\n */" + }, + { + "kind": "method", + "name": "query", + "signature": "async query( platform: CordisInspectPlatform, providerId: string, methodName: string, input: JsonValue | undefined, agent: Agent, signal: AbortSignal, ): Promise", + "summary": "Execute one provider query on its owning platform.", + "jsDoc": "/**\n * Execute one provider query on its owning platform.\n * @param platform - Host or Client runtime.\n * @param providerId - provider selected from {@link list}.\n * @param methodName - declared method name.\n * @param input - optional lossless JSON input.\n * @param agent - requesting Agent and scope.\n * @param signal - tool-call cancellation.\n * @returns provider JSON data.\n */" + }, + { + "kind": "method", + "name": "resolveClientQuery", + "signature": "resolveClientQuery( agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution, ): CordisInspectResolveAck", + "summary": "Accept the first valid Client response for a pending query.", + "jsDoc": "/**\n * Accept the first valid Client response for a pending query.\n * @param agent - Agent whose Session owns the query.\n * @param requestId - Pending Client query identity.\n * @param resolution - Client provider result or failure.\n * @returns whether this response settled the still-pending query.\n */" + } + ], + "types": [ + { + "name": "Agent", + "declaration": "export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly inbox: Inbox;\n readonly status: AgentStatus;\n readonly ctx: Context;\n cancel(cause: AgentCancelCause, options?: CancelOptions): void;\n whenIdle(): Promise;\n runMaintenance(task: (signal: AbortSignal) => Promise): Promise;\n send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;\n followup(message: UserMessage): void;\n steer(message: UserMessage): void;\n inject(message: UserMessage): void;\n}" + }, + { + "name": "AgentCancelCause", + "declaration": "export type AgentCancelCause = { readonly kind: 'user'; } | { readonly kind: 'parent'; } | { readonly kind: 'hook'; readonly reason: string; } | { readonly kind: 'disposed'; };" + }, + { + "name": "AgentOptions", + "declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n maxTokens?: number;\n}" + }, + { + "name": "AgentStatus", + "declaration": "export type AgentStatus = 'idle' | 'running';" + }, + { + "name": "ApprovalOutcome", + "declaration": "export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';" + }, + { + "name": "ApprovalPolicy", + "declaration": "export type ApprovalPolicy = 'ask' | 'never';" + }, + { + "name": "ApprovalRequestId", + "declaration": "export type ApprovalRequestId = Branded<'ApprovalRequestId'>;" + }, + { + "name": "AssistantMessage", + "declaration": "export interface AssistantMessage extends Message {\n readonly role: 'assistant';\n readonly source: ModelMessageSource;\n}" + }, + { + "name": "AssistantProvenance", + "declaration": "export interface AssistantProvenance {\n provider: string;\n model: string;\n replayState?: unknown;\n}" + }, + { + "name": "AttachmentId", + "declaration": "export type AttachmentId = Branded<'AttachmentId'>;" + }, + { + "name": "Branded", + "declaration": "export type Branded = string & { readonly [BRAND]: B; };" + }, + { + "name": "CallId", + "declaration": "export type CallId = Branded<'CallId'>;" + }, + { + "name": "CancelOptions", + "declaration": "export interface CancelOptions {\n keepInbox?: boolean | undefined;\n}" + }, + { + "name": "CodeDispatchEventData", + "declaration": "export interface CodeDispatchEventData extends CodeDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}" + }, + { + "name": "CodeDispatchStartEventData", + "declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}" + }, + { + "name": "CommandId", + "declaration": "export type CommandId = Branded<'CommandId'>;" + }, + { + "name": "CommandSource", + "declaration": "export type CommandSource = CommandSourceMap[keyof CommandSourceMap];" + }, + { + "name": "CommandSourceMap", + "declaration": "export interface CommandSourceMap {\n user: { kind: 'user'; };\n}" + }, + { + "name": "ContentBlock", + "declaration": "export type ContentBlock = ContentBlockMap[ContentBlockType];" + }, + { + "name": "ContentBlockMap", + "declaration": "export interface ContentBlockMap {\n text: TextBlock;\n reasoning: ReasoningBlock;\n image: ImageBlock;\n 'tool-call': ToolCallBlock;\n 'tool-result': ToolResultBlock;\n}" + }, + { + "name": "ContentBlockType", + "declaration": "export type ContentBlockType = keyof ContentBlockMap;" + }, + { + "name": "ContextFormed", + "declaration": "export type ContextFormed = { readonly form?: never; } | { readonly form: 'instructions'; } | { readonly form: 'catalog'; } | { readonly form: 'snapshot'; readonly sections: readonly ContextSnapshotSection[]; } | { readonly form: 'notice'; readonly summary: string; } | { readonly form: 'relay'; } | { readonly form: 'recall'; };" + }, + { + "name": "ContextSnapshotSection", + "declaration": "export interface ContextSnapshotSection {\n readonly name: string;\n readonly text: string;\n}" + }, + { + "name": "CordisInspectMethodManifest", + "declaration": "export interface CordisInspectMethodManifest {\n name: string;\n description: string;\n inputSchema: JsonValue;\n outputSchema: JsonValue;\n}" + }, + { + "name": "CordisInspectPlatform", + "declaration": "export type CordisInspectPlatform = 'host' | 'client';" + }, + { + "name": "CordisInspectProviderManifest", + "declaration": "export interface CordisInspectProviderManifest {\n id: string;\n description: string;\n methods: readonly CordisInspectMethodManifest[];\n}" + }, + { + "name": "CordisInspectProviderView", + "declaration": "export interface CordisInspectProviderView extends CordisInspectProviderManifest {\n platform: CordisInspectPlatform;\n}" + }, + { + "name": "CordisInspectQueryResolution", + "declaration": "export type CordisInspectQueryResolution = { ok: true; data: JsonValue; } | { ok: false; reason: 'provider-missing' | 'method-missing' | 'invalid-input' | 'provider-error' | 'cancelled'; message: string; };" + }, + { + "name": "CordisInspectRequestId", + "declaration": "export type CordisInspectRequestId = Branded<'CordisInspectRequestId'>;" + }, + { + "name": "CordisInspectResolveAck", + "declaration": "export interface CordisInspectResolveAck {\n accepted: boolean;\n}" + }, + { + "name": "EpochHeader", + "declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n system?: string;\n tools?: ToolSchema[];\n}" + }, + { + "name": "FinishReason", + "declaration": "export type FinishReason = FinishReasonMap[keyof FinishReasonMap];" + }, + { + "name": "FinishReasonMap", + "declaration": "export interface FinishReasonMap {\n stop: { kind: 'stop'; };\n 'tool-calls': { kind: 'tool-calls'; };\n 'max-tokens': { kind: 'max-tokens'; };\n aborted: { kind: 'aborted'; failure: LlmFailure; };\n error: { kind: 'error'; failure: LlmFailure; };\n}" + }, + { + "name": "GoalBlockReason", + "declaration": "export interface GoalBlockReason {\n readonly code: string;\n readonly message: string;\n}" + }, + { + "name": "GoalChangeMeta", + "declaration": "export type GoalChangeMeta = GoalSnapshotChangeMeta | GoalClearChangeMeta;" + }, + { + "name": "GoalClearChangeMeta", + "declaration": "export interface GoalClearChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: 'clear';\n readonly cleared: GoalRef;\n readonly clearedAt: number;\n}" + }, + { + "name": "GoalId", + "declaration": "export type GoalId = Branded<'GoalId'>;" + }, + { + "name": "GoalMessageSource", + "declaration": "export interface GoalMessageSource {\n readonly kind: 'goal';\n readonly goalId: GoalId;\n readonly revision: number;\n readonly round: number;\n}" + }, + { + "name": "GoalOperation", + "declaration": "export type GoalOperation = 'create' | 'edit' | 'pause' | 'resume' | 'complete' | 'block' | 'clear';" + }, + { + "name": "GoalPhase", + "declaration": "export type GoalPhase = 'active' | 'paused' | 'blocked' | 'complete';" + }, + { + "name": "GoalRef", + "declaration": "export interface GoalRef {\n readonly id: GoalId;\n readonly revision: number;\n}" + }, + { + "name": "GoalSnapshot", + "declaration": "export interface GoalSnapshot extends GoalRef {\n readonly objective: string;\n readonly phase: GoalPhase;\n readonly blockedReason?: GoalBlockReason;\n readonly maxGoalRounds: number;\n}" + }, + { + "name": "GoalSnapshotChangeMeta", + "declaration": "export interface GoalSnapshotChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: Exclude;\n readonly goal: GoalSnapshot;\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n}" + }, + { + "name": "HostCordisInspectProviderRegistration", + "declaration": "export interface HostCordisInspectProviderRegistration {\n manifest: CordisInspectProviderManifest;\n query(method: string, input: JsonValue | undefined, context: HostCordisInspectQueryContext): Promise;\n}" + }, + { + "name": "HostCordisInspectQueryContext", + "declaration": "export interface HostCordisInspectQueryContext {\n signal: AbortSignal;\n agent: Agent;\n}" + }, + { + "name": "ImageAttachmentRef", + "declaration": "export interface ImageAttachmentRef {\n attachmentId: AttachmentId;\n mediaType: ImageMediaType;\n bytes: number;\n width: number;\n height: number;\n name?: string;\n}" + }, + { + "name": "ImageBlock", + "declaration": "export interface ImageBlock {\n type: 'image';\n attachment: ImageAttachmentRef;\n}" + }, + { + "name": "ImageMediaType", + "declaration": "export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';" + }, + { + "name": "Inbox", + "declaration": "export class Inbox {\n get nextTurn(): readonly UserMessage[];\n get nextStep(): readonly UserMessage[];\n get hasPending(): boolean;\n clear(): void;\n claim(target: InboxTarget, turn: number): UserMessage[];\n append(target: InboxTarget, message: UserMessage): void;\n prepend(target: InboxTarget, message: UserMessage): void;\n replace(messageId: MessageId, newMessage: UserMessage): boolean;\n remove(messageId: MessageId): boolean;\n splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[];\n}" + }, + { + "name": "InboxTarget", + "declaration": "export type InboxTarget = 'next-turn' | 'next-step';" + }, + { + "name": "JsonValue", + "declaration": "export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue; };" + }, + { + "name": "LlmCallConfig", + "declaration": "export interface LlmCallConfig {\n provider: string;\n model: string;\n reasoningEffort?: ReasoningEffortId;\n temperature?: number;\n maxTokens?: number;\n stop?: string[];\n}" + }, + { + "name": "LlmCallConfigAdapterDefaults", + "declaration": "export interface LlmCallConfigAdapterDefaults {\n reasoningEffort?: true;\n maxTokens?: true;\n}" + }, + { + "name": "LlmFailure", + "declaration": "export interface LlmFailure {\n readonly message: string;\n readonly code: string;\n readonly status?: number;\n readonly providerRetryAfterMs?: number;\n readonly requestId?: ProviderRequestId;\n}" + }, + { + "name": "Message", + "declaration": "export interface Message {\n readonly id: MessageId;\n readonly role: 'system' | 'user' | 'assistant';\n readonly content: ContentBlock[];\n readonly source: MessageSource;\n}" + }, + { + "name": "MessageId", + "declaration": "export type MessageId = Branded<'MessageId'>;" + }, + { + "name": "MessageSource", + "declaration": "export type MessageSource = MessageSourceMap[keyof MessageSourceMap];" + }, + { + "name": "MessageSourceMap", + "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n goal: GoalMessageSource;\n}" + }, + { + "name": "ModelMessageSource", + "declaration": "export interface ModelMessageSource extends AssistantProvenance {\n kind: 'model';\n}" + }, + { + "name": "ProviderRequestId", + "declaration": "export type ProviderRequestId = Branded<'ProviderRequestId'>;" + }, + { + "name": "ReasoningBlock", + "declaration": "export interface ReasoningBlock {\n type: 'reasoning';\n text: string;\n}" + }, + { + "name": "ReasoningEffortId", + "declaration": "export type ReasoningEffortId = Branded<'ReasoningEffortId'>;" + }, + { + "name": "ReplayEnvelope", + "declaration": "export interface ReplayEnvelope {\n response: unknown;\n blocks?: readonly unknown[];\n}" + }, + { + "name": "RequestContext", + "declaration": "export interface RequestContext {\n provider: string;\n model: string;\n contextWindow?: number;\n}" + }, + { + "name": "RequestHeaderReason", + "declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change';" + }, + { + "name": "Session", + "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n get id(): SessionId;\n readonly firstLiveSeq: number;\n get events(): readonly SessionEvent[];\n get seq(): number;\n append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}" + }, + { + "name": "SessionEvent", + "declaration": "export type SessionEvent = { [K in SessionEventType]: { type: K; seq: number; time: number; data: SessionEventMap[K]; ignorable?: true; } & (K extends SurfaceEventType ? { sourceEventSeqs?: number[]; surfaceOp?: SurfaceOp; } : object) }[T];" + }, + { + "name": "SessionEventMap", + "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: number; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n 'goal/change': GoalChangeMeta;\n}" + }, + { + "name": "SessionEventType", + "declaration": "export type SessionEventType = keyof SessionEventMap;" + }, + { + "name": "SessionHeader", + "declaration": "export interface SessionHeader {\n readonly version: number;\n readonly id: SessionId;\n readonly createdAt: number;\n readonly cwd?: string;\n readonly parentSession?: SessionId;\n readonly seedLength?: number;\n readonly origin?: 'subagent';\n readonly delegationDepth?: number;\n readonly agentPreset?: string;\n}" + }, + { + "name": "SessionId", + "declaration": "export type SessionId = Branded<'SessionId'>;" + }, + { + "name": "SessionSurface", + "declaration": "export interface SessionSurface {\n readonly nodes: readonly number[];\n readonly replaceGeneration: number;\n}" + }, + { + "name": "StreamChunk", + "declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: ReplayEnvelope; };" + }, + { + "name": "SurfaceEventType", + "declaration": "export type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result';" + }, + { + "name": "SurfaceIntent", + "declaration": "export interface SurfaceIntent {\n surfaceOp: SurfaceOp;\n sourceEventSeqs?: number[];\n}" + }, + { + "name": "SurfaceOp", + "declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: number; end: number; };" + }, + { + "name": "TextBlock", + "declaration": "export interface TextBlock {\n type: 'text';\n text: string;\n}" + }, + { + "name": "TodoItem", + "declaration": "export interface TodoItem {\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n}" + }, + { + "name": "TokenUsage", + "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}" + }, + { + "name": "ToolCallBlock", + "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: CallId;\n name: string;\n arguments: string;\n}" + }, + { + "name": "ToolMessageSource", + "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: CallId;\n}" + }, + { + "name": "ToolResultBlock", + "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: CallId;\n content: ContentBlock[];\n isError?: boolean;\n}" + }, + { + "name": "ToolResultMessage", + "declaration": "export interface ToolResultMessage extends Message {\n readonly role: 'user';\n readonly content: [ToolResultBlock];\n readonly source: ToolMessageSource;\n}" + }, + { + "name": "ToolSchema", + "declaration": "export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n}" + }, + { + "name": "TurnEndCancelCause", + "declaration": "export type TurnEndCancelCause = AgentCancelCause | { readonly kind: 'legacy'; };" + }, + { + "name": "TurnEndReason", + "declaration": "export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap];" + }, + { + "name": "TurnEndReasonMap", + "declaration": "export interface TurnEndReasonMap {\n completed: { kind: 'completed'; };\n aborted: { kind: 'aborted'; reason: TurnEndCancelCause; };\n blocked: { kind: 'blocked'; };\n error: { kind: 'error'; error: LlmFailure; };\n 'max-tokens': { kind: 'max-tokens'; };\n interrupted: { kind: 'interrupted'; };\n}" + }, + { + "name": "UserMessage", + "declaration": "export interface UserMessage extends Message {\n readonly role: 'user';\n}" + } + ] + }, + { + "description": "Dynamic Plugin registry and Host-half lifecycle.", + "summary": "Dynamic Plugin registry and Host-half lifecycle.", + "tags": [], + "jsDoc": "/** Dynamic Plugin registry and Host-half lifecycle. */", + "key": "dynamicCordisRunner", + "exportName": "DynamicCordisRunnerService", + "members": [ + { + "kind": "method", + "name": "define", + "signature": "define(request: DynamicCordisDefineRequest): DynamicCordisDefineReceipt", + "summary": "Define a new Plugin's first Package or append a Package to an existing Plugin.", + "jsDoc": "/**\n * Define a new Plugin's first Package or append a Package to an existing Plugin.\n * @param request - Session ownership, Plugin selection, metadata, and source code.\n * @returns Host-minted Plugin and Package identities with declared-half metadata.\n */" + }, + { + "kind": "method", + "name": "undefine", + "signature": "async undefine(agent: Agent, pluginId: CordisDynamicPluginId): Promise", + "summary": "Remove a Plugin, its active run, and all immutable Packages.", + "jsDoc": "/**\n * Remove a Plugin, its active run, and all immutable Packages.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity to remove.\n * @returns Whether removal succeeded and whether it stopped an active run.\n */" + }, + { + "kind": "method", + "name": "undefineFromPanel", + "signature": "@Remote('undefineFromPanel') async undefineFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise", + "summary": "Remove a Plugin from the user panel and queue the resulting state change for the model's next step.", + "jsDoc": "/**\n * Remove a Plugin from the user panel and queue the resulting state change for the model's next step.\n * @param agent - Agent whose Session owns the Plugin and receives the context.\n * @param pluginId - Stable Plugin identity to remove.\n * @returns Whether removal succeeded and whether it stopped an active run.\n */" + }, + { + "kind": "method", + "name": "run", + "signature": "async run( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, signal?: AbortSignal, ): Promise", + "summary": "Start or update one Package for a model tool call.", + "jsDoc": "/**\n * Start or update one Package for a model tool call. An unauthorized Client\n * Package waits for approval; Plugin-wide authorization covers later versions.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity to activate.\n * @param packageId - Immutable Package version to activate.\n * @param mode - Whether to run the current version or switch versions.\n * @param signal - Tool-call cancellation signal while the activation request is being created.\n * @returns The successful activation identity or an actionable refusal.\n */" + }, + { + "kind": "method", + "name": "runHostHalf", + "signature": "@Remote('runHostHalf') async runHostHalf( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean, ): Promise", + "summary": "Start Host code for an approved request or a direct panel gesture.", + "jsDoc": "/**\n * Start Host code for an approved request or a direct panel gesture.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity to activate.\n * @param packageId - Immutable Package version to activate.\n * @param mode - Whether to run the current version or switch versions.\n * @param requestId - Model-driven request identity, or null for a direct user gesture.\n * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin.\n * @returns The exact Host activation or a failure message.\n */" + }, + { + "kind": "method", + "name": "getClientCode", + "signature": "@Remote('getClientCode') getClientCode( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, ): DynamicCordisClientSource", + "summary": "Fetch Client code for the exact active run.", + "jsDoc": "/**\n * Fetch Client code for the exact active run.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity to read.\n * @param pluginRunId - Exact active run authorized to receive source.\n * @returns Client source and its Plugin, Package, and run identities.\n */" + }, + { + "kind": "method", + "name": "resolveRequestRun", + "signature": "@Remote('resolveRequestRun') async resolveRequestRun( requestId: ApprovalRequestId, resolution: DynamicCordisRunResolution, ): Promise", + "summary": "Resolve one model-driven Client activation request.", + "jsDoc": "/**\n * Resolve one model-driven Client activation request.\n * @param requestId - Request identity to settle once.\n * @param resolution - Browser refusal or exact Client activation result.\n * @returns Whether the still-pending request accepted this resolution.\n */" + }, + { + "kind": "method", + "name": "settleUserRun", + "signature": "@Remote('settleUserRun') async settleUserRun( agent: Agent, pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution, ): Promise", + "summary": "Settle a direct panel run after this page loaded or failed its Client half.", + "jsDoc": "/**\n * Settle a direct panel run after this page loaded or failed its Client half.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity being settled.\n * @param resolution - Exact Client activation result from the acting page.\n * @returns The committed activation or its failure.\n */" + }, + { + "kind": "method", + "name": "stop", + "signature": "async stop(agent: Agent, pluginId: CordisDynamicPluginId): Promise", + "summary": "Stop the active run while retaining every Package version.", + "jsDoc": "/**\n * Stop the active run while retaining every Package version.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity to stop.\n * @returns Success or the reason no run was stopped.\n */" + }, + { + "kind": "method", + "name": "stopFromPanel", + "signature": "@Remote('stopFromPanel') async stopFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise", + "summary": "Stop a Plugin from the user panel and queue the resulting state change for the model's next step.", + "jsDoc": "/**\n * Stop a Plugin from the user panel and queue the resulting state change for the model's next step.\n * @param agent - Agent whose Session owns the Plugin and receives the context.\n * @param pluginId - Stable Plugin identity to stop.\n * @returns Success or the reason no run was stopped.\n */" + }, + { + "kind": "method", + "name": "syncInspectManifest", + "signature": "@Remote('syncInspectManifest') syncInspectManifest(providers: readonly CordisInspectProviderManifest[]): null", + "summary": "Replace the Host mirror of the Client inspect provider directory.", + "jsDoc": "/**\n * Replace the Host mirror of the Client inspect provider directory.\n * @param providers - complete Client provider manifest.\n * @returns null after accepting the manifest.\n */" + }, + { + "kind": "method", + "name": "resolveInspectQuery", + "signature": "@Remote('resolveInspectQuery') resolveInspectQuery( agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution, ): CordisInspectResolveAck", + "summary": "Claim one pending Client inspect query with its live result.", + "jsDoc": "/**\n * Claim one pending Client inspect query with its live result.\n * @param agent - Session that owns the query.\n * @param requestId - exact pending query identity.\n * @param resolution - provider result or structured refusal.\n * @returns whether this answer won the query.\n */" + }, + { + "kind": "method", + "name": "inventory", + "signature": "@Remote('inventory') inventory(): DynamicCordisInventoryRow[]", + "summary": "Frame-wide inventory, grouped as one row per stable Plugin.", + "jsDoc": "/**\n * Frame-wide inventory, grouped as one row per stable Plugin.\n * @returns Source-free metadata for every process-local Plugin.\n */" + }, + { + "kind": "method", + "name": "snapshot", + "signature": "snapshot(agent: Agent): DynamicCordisSnapshotRow[]", + "summary": "Read one Session's Host-rich state for inspection and result rendering.", + "jsDoc": "/**\n * Read one Session's Host-rich state for inspection and result rendering.\n * @param agent - Agent whose Session selects visible Plugins.\n * @returns Plugin versions, active runs, Host fibers, and render failures.\n */" + }, + { + "kind": "method", + "name": "reference", + "signature": "reference(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisReference | undefined", + "summary": "Read source-free context for an explicit `@pluginId` user gesture.", + "jsDoc": "/**\n * Read source-free context for an explicit `@pluginId` user gesture.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity referenced by the user.\n * @returns The preferred modification base, or undefined when unavailable.\n */" + }, + { + "kind": "method", + "name": "listPlugins", + "signature": "listPlugins(agent: Agent): DynamicCordisPluginInspection[]", + "summary": "List source-free Plugin summaries owned by one Session.", + "jsDoc": "/**\n * List source-free Plugin summaries owned by one Session.\n * @param agent - Agent whose Session selects visible Plugins.\n * @returns one summary per Plugin in creation order.\n */" + }, + { + "kind": "method", + "name": "inspectPlugin", + "signature": "inspectPlugin(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisPluginInspection", + "summary": "Inspect one Plugin without returning Package source.", + "jsDoc": "/**\n * Inspect one Plugin without returning Package source.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - stable Plugin identity.\n * @returns version pointers, latest run, and all Package summaries.\n */" + }, + { + "kind": "method", + "name": "inspectPackage", + "signature": "inspectPackage( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, ): DynamicCordisPackageInspection", + "summary": "Read one exact immutable Package and its Host and Client source.", + "jsDoc": "/**\n * Read one exact immutable Package and its Host and Client source.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity that owns the Package.\n * @param packageId - Exact immutable Package identity to inspect.\n * @returns Package metadata, source, and the Plugin's lifecycle pointers.\n */" + }, + { + "kind": "method", + "name": "reportRenderFailure", + "signature": "@Remote('reportRenderFailure') async reportRenderFailure( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure, ): Promise", + "summary": "Record a post-load render failure for the exact active run.", + "jsDoc": "/**\n * Record a post-load render failure for the exact active run.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity that rendered.\n * @param pluginRunId - Exact active run that produced the failure.\n * @param failure - Slot, message, and entry-retirement result.\n * @returns Null after recording or ignoring a stale report.\n */" + }, + { + "kind": "method", + "name": "reportClientGuardFailure", + "signature": "@Remote('reportClientGuardFailure') async reportClientGuardFailure( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails, ): Promise", + "summary": "Report a Client guard rejection that happened after the Package completed activation.", + "jsDoc": "/**\n * Report a Client guard rejection that happened after the Package completed activation.\n * @param agent - Agent whose Session must own the Plugin.\n * @param pluginId - Stable Plugin identity whose Client code was rejected.\n * @param pluginRunId - Exact active run that produced the rejection.\n * @param failure - Original guard message and stack.\n * @returns Null after reporting or ignoring a stale/startup failure.\n */" + }, + { + "kind": "method", + "name": "invoke", + "signature": "@Remote('invoke') async invoke( pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, method: string, args: JsonValue, ): Promise", + "summary": "Invoke an active Host method while rejecting stale Client runs.", + "jsDoc": "/**\n * Invoke an active Host method while rejecting stale Client runs.\n * @param pluginId - Stable Plugin identity that owns the method.\n * @param pluginRunId - Exact active run authorizing the call.\n * @param method - Registered Host handler name.\n * @param args - JSON argument delivered to the handler.\n * @returns The JSON result or a typed invocation failure.\n */" + } + ], + "types": [ + { + "name": "Agent", + "declaration": "export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly inbox: Inbox;\n readonly status: AgentStatus;\n readonly ctx: Context;\n cancel(cause: AgentCancelCause, options?: CancelOptions): void;\n whenIdle(): Promise;\n runMaintenance(task: (signal: AbortSignal) => Promise): Promise;\n send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;\n followup(message: UserMessage): void;\n steer(message: UserMessage): void;\n inject(message: UserMessage): void;\n}" + }, + { + "name": "AgentCancelCause", + "declaration": "export type AgentCancelCause = { readonly kind: 'user'; } | { readonly kind: 'parent'; } | { readonly kind: 'hook'; readonly reason: string; } | { readonly kind: 'disposed'; };" + }, + { + "name": "AgentOptions", + "declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n maxTokens?: number;\n}" + }, + { + "name": "AgentStatus", + "declaration": "export type AgentStatus = 'idle' | 'running';" + }, + { + "name": "ApprovalOutcome", + "declaration": "export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';" + }, + { + "name": "ApprovalPolicy", + "declaration": "export type ApprovalPolicy = 'ask' | 'never';" + }, + { + "name": "ApprovalRequestId", + "declaration": "export type ApprovalRequestId = Branded<'ApprovalRequestId'>;" + }, + { + "name": "ApprovalRequestId", + "declaration": "export type ApprovalRequestId = Branded<'ApprovalRequestId'>;" + }, + { + "name": "AssistantMessage", + "declaration": "export interface AssistantMessage extends Message {\n readonly role: 'assistant';\n readonly source: ModelMessageSource;\n}" + }, + { + "name": "AssistantProvenance", + "declaration": "export interface AssistantProvenance {\n provider: string;\n model: string;\n replayState?: unknown;\n}" + }, + { + "name": "AttachmentId", + "declaration": "export type AttachmentId = Branded<'AttachmentId'>;" + }, + { + "name": "Branded", + "declaration": "export type Branded = string & { readonly [BRAND]: B; };" + }, + { + "name": "CallId", + "declaration": "export type CallId = Branded<'CallId'>;" + }, + { + "name": "CancelOptions", + "declaration": "export interface CancelOptions {\n keepInbox?: boolean | undefined;\n}" + }, + { + "name": "CodeDispatchEventData", + "declaration": "export interface CodeDispatchEventData extends CodeDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}" + }, + { + "name": "CodeDispatchStartEventData", + "declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}" + }, + { + "name": "CommandId", + "declaration": "export type CommandId = Branded<'CommandId'>;" + }, + { + "name": "CommandSource", + "declaration": "export type CommandSource = CommandSourceMap[keyof CommandSourceMap];" + }, + { + "name": "CommandSourceMap", + "declaration": "export interface CommandSourceMap {\n user: { kind: 'user'; };\n}" + }, + { + "name": "ContentBlock", + "declaration": "export type ContentBlock = ContentBlockMap[ContentBlockType];" + }, + { + "name": "ContentBlockMap", + "declaration": "export interface ContentBlockMap {\n text: TextBlock;\n reasoning: ReasoningBlock;\n image: ImageBlock;\n 'tool-call': ToolCallBlock;\n 'tool-result': ToolResultBlock;\n}" + }, + { + "name": "ContentBlockType", + "declaration": "export type ContentBlockType = keyof ContentBlockMap;" + }, + { + "name": "ContextFormed", + "declaration": "export type ContextFormed = { readonly form?: never; } | { readonly form: 'instructions'; } | { readonly form: 'catalog'; } | { readonly form: 'snapshot'; readonly sections: readonly ContextSnapshotSection[]; } | { readonly form: 'notice'; readonly summary: string; } | { readonly form: 'relay'; } | { readonly form: 'recall'; };" + }, + { + "name": "ContextSnapshotSection", + "declaration": "export interface ContextSnapshotSection {\n readonly name: string;\n readonly text: string;\n}" + }, + { + "name": "CordisDynamicPackageId", + "declaration": "export type CordisDynamicPackageId = Branded<'CordisDynamicPackageId'>;" + }, + { + "name": "CordisDynamicPluginId", + "declaration": "export type CordisDynamicPluginId = Branded<'CordisDynamicPluginId'>;" + }, + { + "name": "CordisDynamicPluginRunId", + "declaration": "export type CordisDynamicPluginRunId = Branded<'CordisDynamicPluginRunId'>;" + }, + { + "name": "CordisDynamicRunMode", + "declaration": "export type CordisDynamicRunMode = 'run' | 'update';" + }, + { + "name": "CordisErrorDetails", + "declaration": "export interface CordisErrorDetails {\n message: string;\n stack?: string;\n}" + }, + { + "name": "CordisHalfState", + "declaration": "export interface CordisHalfState {\n status: 'absent' | 'pending' | 'stopped' | 'running' | 'waiting' | 'failed';\n waitingFor: readonly string[];\n error?: string;\n}" + }, + { + "name": "CordisInspectMethodManifest", + "declaration": "export interface CordisInspectMethodManifest {\n name: string;\n description: string;\n inputSchema: JsonValue;\n outputSchema: JsonValue;\n}" + }, + { + "name": "CordisInspectProviderManifest", + "declaration": "export interface CordisInspectProviderManifest {\n id: string;\n description: string;\n methods: readonly CordisInspectMethodManifest[];\n}" + }, + { + "name": "CordisInspectQueryResolution", + "declaration": "export type CordisInspectQueryResolution = { ok: true; data: JsonValue; } | { ok: false; reason: 'provider-missing' | 'method-missing' | 'invalid-input' | 'provider-error' | 'cancelled'; message: string; };" + }, + { + "name": "CordisInspectRequestId", + "declaration": "export type CordisInspectRequestId = Branded<'CordisInspectRequestId'>;" + }, + { + "name": "CordisInspectResolveAck", + "declaration": "export interface CordisInspectResolveAck {\n accepted: boolean;\n}" + }, + { + "name": "CordisRunDiagnostic", + "declaration": "export interface CordisRunDiagnostic {\n phase: 'approval' | 'host-load' | 'host-apply' | 'client-load' | 'client-apply' | 'client-render';\n message: string;\n stack?: string;\n pluginId: CordisDynamicPluginId;\n packageId: CordisDynamicPackageId;\n pluginRunId: CordisDynamicPluginRunId;\n}" + }, + { + "name": "CordisRunStatus", + "declaration": "export type CordisRunStatus = 'awaiting-approval' | 'starting-host' | 'client-pending' | 'running' | 'waiting' | 'rejected' | 'failed' | 'cancelled' | 'stopped';" + }, + { + "name": "DynamicCordisClientSource", + "declaration": "export interface DynamicCordisClientSource {\n code: string;\n name: string;\n pluginId: CordisDynamicPluginId;\n packageId: CordisDynamicPackageId;\n pluginRunId: CordisDynamicPluginRunId;\n}" + }, + { + "name": "DynamicCordisDefineReceipt", + "declaration": "export interface DynamicCordisDefineReceipt {\n pluginId: CordisDynamicPluginId;\n packageId: CordisDynamicPackageId;\n name: string;\n purpose: string;\n hasHostHalf: boolean;\n hasClientHalf: boolean;\n}" + }, + { + "name": "DynamicCordisDefineRequest", + "declaration": "export interface DynamicCordisDefineRequest {\n sessionId: SessionId;\n plugin: { kind: 'new'; idPrefix: string; } | { kind: 'existing'; pluginId: CordisDynamicPluginId; };\n name: string;\n purpose: string;\n code: { host?: string; client?: string; };\n}" + }, + { + "name": "DynamicCordisHostHalfResult", + "declaration": "export type DynamicCordisHostHalfResult = { ok: true; pluginId: CordisDynamicPluginId; packageId: CordisDynamicPackageId; pluginRunId: CordisDynamicPluginRunId; waitingFor: readonly string[]; startedHere: boolean; } | ({ ok: false; } & CordisErrorDetails);" + }, + { + "name": "DynamicCordisInventoryPackage", + "declaration": "export interface DynamicCordisInventoryPackage {\n packageId: CordisDynamicPackageId;\n name: string;\n purpose: string;\n hasHostHalf: boolean;\n hasClientHalf: boolean;\n}" + }, + { + "name": "DynamicCordisInventoryRow", + "declaration": "export interface DynamicCordisInventoryRow {\n pluginId: CordisDynamicPluginId;\n agentId: SessionId;\n packages: readonly DynamicCordisInventoryPackage[];\n currentPackageId?: CordisDynamicPackageId;\n nextPackageId?: CordisDynamicPackageId;\n activeRun?: { pluginRunId: CordisDynamicPluginRunId; packageId: CordisDynamicPackageId; };\n latestRun?: DynamicCordisRunAttempt;\n}" + }, + { + "name": "DynamicCordisInvokeResult", + "declaration": "export type DynamicCordisInvokeResult = { ok: true; value: JsonValue; } | ({ ok: false; code: 'plugin-not-running' | 'stale-run' | 'method-not-found' | 'handler-error'; } & CordisErrorDetails);" + }, + { + "name": "DynamicCordisPackageInspection", + "declaration": "export interface DynamicCordisPackageInspection extends DynamicCordisReference {\n code: { host?: string; client?: string; };\n}" + }, + { + "name": "DynamicCordisPluginInspection", + "declaration": "export interface DynamicCordisPluginInspection extends DynamicCordisReference {\n packages: Array<{ packageId: CordisDynamicPackageId; name: string; purpose: string; hasHostHalf: boolean; hasClientHalf: boolean; }>;\n}" + }, + { + "name": "DynamicCordisReference", + "declaration": "export interface DynamicCordisReference {\n pluginId: CordisDynamicPluginId;\n packageId: CordisDynamicPackageId;\n name: string;\n purpose: string;\n currentPackageId?: CordisDynamicPackageId;\n nextPackageId?: CordisDynamicPackageId;\n activeRun?: { pluginRunId: CordisDynamicPluginRunId; packageId: CordisDynamicPackageId; };\n latestRun?: DynamicCordisRunAttempt;\n}" + }, + { + "name": "DynamicCordisRenderFailure", + "declaration": "export interface DynamicCordisRenderFailure {\n slot: string;\n message: string;\n stack?: string;\n abdicated: boolean;\n}" + }, + { + "name": "DynamicCordisResolveAck", + "declaration": "export interface DynamicCordisResolveAck {\n accepted: boolean;\n}" + }, + { + "name": "DynamicCordisRunAttempt", + "declaration": "export interface DynamicCordisRunAttempt {\n pluginRunId: CordisDynamicPluginRunId;\n packageId: CordisDynamicPackageId;\n mode: CordisDynamicRunMode;\n status: CordisRunStatus;\n approvalRequestId?: ApprovalRequestId;\n requiresApproval?: boolean;\n host: CordisHalfState;\n client: CordisHalfState;\n error?: CordisRunDiagnostic;\n}" + }, + { + "name": "DynamicCordisRunResolution", + "declaration": "export type DynamicCordisRunResolution = { ok: true; pluginRunId: CordisDynamicPluginRunId; waitingFor?: readonly string[]; } | { ok: false; reason: 'rejected' | 'host-half-failed' | 'client-half-failed'; pluginRunId?: CordisDynamicPluginRunId; startedHere?: boolean; message?: string; stack?: string; };" + }, + { + "name": "DynamicCordisRunResponse", + "declaration": "export type DynamicCordisRunResponse = { ok: true; status: 'awaiting-approval' | 'starting' | 'running'; pluginId: CordisDynamicPluginId; packageId: CordisDynamicPackageId; pluginRunId: CordisDynamicPluginRunId; waitingFor: readonly string[]; clientWaitingFor?: readonly string[]; currentPackageId?: CordisDynamicPackageId; nextPackageId?: CordisDynamicPackageId; mode: CordisDynamicRunMode; } | { ok: false; reason: 'plugin-missing' | 'package-missing' | 'invalid-mode' | 'transition-in-flight' | 'host-half-failed' | 'client-half-failed' | 'rejected' | 'cancelled' | 'not-running'; message: string; stack?: string; };" + }, + { + "name": "DynamicCordisSnapshotRow", + "declaration": "export interface DynamicCordisSnapshotRow {\n pluginId: CordisDynamicPluginId;\n currentPackageId?: CordisDynamicPackageId;\n nextPackageId?: CordisDynamicPackageId;\n packages: Array<{ packageId: CordisDynamicPackageId; name: string; purpose: string; hasHostHalf: boolean; hasClientHalf: boolean; }>;\n activeRun?: { pluginRunId: CordisDynamicPluginRunId; packageId: CordisDynamicPackageId; fiber?: Fiber; handlers: string[]; renderFailure?: DynamicCordisRenderFailure; };\n latestRun?: DynamicCordisRunAttempt;\n}" + }, + { + "name": "DynamicCordisStopResponse", + "declaration": "export type DynamicCordisStopResponse = { ok: true; } | { ok: false; reason: 'plugin-missing' | 'not-running'; message: string; };" + }, + { + "name": "DynamicCordisUndefineReceipt", + "declaration": "export type DynamicCordisUndefineReceipt = { ok: true; wasRunning: boolean; } | { ok: false; reason: 'plugin-missing'; message: string; };" + }, + { + "name": "EpochHeader", + "declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n system?: string;\n tools?: ToolSchema[];\n}" + }, + { + "name": "FinishReason", + "declaration": "export type FinishReason = FinishReasonMap[keyof FinishReasonMap];" + }, + { + "name": "FinishReasonMap", + "declaration": "export interface FinishReasonMap {\n stop: { kind: 'stop'; };\n 'tool-calls': { kind: 'tool-calls'; };\n 'max-tokens': { kind: 'max-tokens'; };\n aborted: { kind: 'aborted'; failure: LlmFailure; };\n error: { kind: 'error'; failure: LlmFailure; };\n}" + }, + { + "name": "GoalBlockReason", + "declaration": "export interface GoalBlockReason {\n readonly code: string;\n readonly message: string;\n}" + }, + { + "name": "GoalChangeMeta", + "declaration": "export type GoalChangeMeta = GoalSnapshotChangeMeta | GoalClearChangeMeta;" + }, + { + "name": "GoalClearChangeMeta", + "declaration": "export interface GoalClearChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: 'clear';\n readonly cleared: GoalRef;\n readonly clearedAt: number;\n}" + }, + { + "name": "GoalId", + "declaration": "export type GoalId = Branded<'GoalId'>;" + }, + { + "name": "GoalMessageSource", + "declaration": "export interface GoalMessageSource {\n readonly kind: 'goal';\n readonly goalId: GoalId;\n readonly revision: number;\n readonly round: number;\n}" + }, + { + "name": "GoalOperation", + "declaration": "export type GoalOperation = 'create' | 'edit' | 'pause' | 'resume' | 'complete' | 'block' | 'clear';" + }, + { + "name": "GoalPhase", + "declaration": "export type GoalPhase = 'active' | 'paused' | 'blocked' | 'complete';" + }, + { + "name": "GoalRef", + "declaration": "export interface GoalRef {\n readonly id: GoalId;\n readonly revision: number;\n}" + }, + { + "name": "GoalSnapshot", + "declaration": "export interface GoalSnapshot extends GoalRef {\n readonly objective: string;\n readonly phase: GoalPhase;\n readonly blockedReason?: GoalBlockReason;\n readonly maxGoalRounds: number;\n}" + }, + { + "name": "GoalSnapshotChangeMeta", + "declaration": "export interface GoalSnapshotChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: Exclude;\n readonly goal: GoalSnapshot;\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n}" + }, + { + "name": "ImageAttachmentRef", + "declaration": "export interface ImageAttachmentRef {\n attachmentId: AttachmentId;\n mediaType: ImageMediaType;\n bytes: number;\n width: number;\n height: number;\n name?: string;\n}" + }, + { + "name": "ImageBlock", + "declaration": "export interface ImageBlock {\n type: 'image';\n attachment: ImageAttachmentRef;\n}" + }, + { + "name": "ImageMediaType", + "declaration": "export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';" + }, + { + "name": "Inbox", + "declaration": "export class Inbox {\n get nextTurn(): readonly UserMessage[];\n get nextStep(): readonly UserMessage[];\n get hasPending(): boolean;\n clear(): void;\n claim(target: InboxTarget, turn: number): UserMessage[];\n append(target: InboxTarget, message: UserMessage): void;\n prepend(target: InboxTarget, message: UserMessage): void;\n replace(messageId: MessageId, newMessage: UserMessage): boolean;\n remove(messageId: MessageId): boolean;\n splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[];\n}" + }, + { + "name": "InboxTarget", + "declaration": "export type InboxTarget = 'next-turn' | 'next-step';" + }, + { + "name": "JsonValue", + "declaration": "export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue; };" + }, + { + "name": "LlmCallConfig", + "declaration": "export interface LlmCallConfig {\n provider: string;\n model: string;\n reasoningEffort?: ReasoningEffortId;\n temperature?: number;\n maxTokens?: number;\n stop?: string[];\n}" + }, + { + "name": "LlmCallConfigAdapterDefaults", + "declaration": "export interface LlmCallConfigAdapterDefaults {\n reasoningEffort?: true;\n maxTokens?: true;\n}" + }, + { + "name": "LlmFailure", + "declaration": "export interface LlmFailure {\n readonly message: string;\n readonly code: string;\n readonly status?: number;\n readonly providerRetryAfterMs?: number;\n readonly requestId?: ProviderRequestId;\n}" + }, + { + "name": "Message", + "declaration": "export interface Message {\n readonly id: MessageId;\n readonly role: 'system' | 'user' | 'assistant';\n readonly content: ContentBlock[];\n readonly source: MessageSource;\n}" + }, + { + "name": "MessageId", + "declaration": "export type MessageId = Branded<'MessageId'>;" + }, + { + "name": "MessageSource", + "declaration": "export type MessageSource = MessageSourceMap[keyof MessageSourceMap];" + }, + { + "name": "MessageSourceMap", + "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n goal: GoalMessageSource;\n}" + }, + { + "name": "ModelMessageSource", + "declaration": "export interface ModelMessageSource extends AssistantProvenance {\n kind: 'model';\n}" + }, + { + "name": "ProviderRequestId", + "declaration": "export type ProviderRequestId = Branded<'ProviderRequestId'>;" + }, + { + "name": "ReasoningBlock", + "declaration": "export interface ReasoningBlock {\n type: 'reasoning';\n text: string;\n}" + }, + { + "name": "ReasoningEffortId", + "declaration": "export type ReasoningEffortId = Branded<'ReasoningEffortId'>;" + }, + { + "name": "ReplayEnvelope", + "declaration": "export interface ReplayEnvelope {\n response: unknown;\n blocks?: readonly unknown[];\n}" + }, + { + "name": "RequestContext", + "declaration": "export interface RequestContext {\n provider: string;\n model: string;\n contextWindow?: number;\n}" + }, + { + "name": "RequestHeaderReason", + "declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change';" + }, + { + "name": "Session", + "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n get id(): SessionId;\n readonly firstLiveSeq: number;\n get events(): readonly SessionEvent[];\n get seq(): number;\n append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}" + }, + { + "name": "SessionEvent", + "declaration": "export type SessionEvent = { [K in SessionEventType]: { type: K; seq: number; time: number; data: SessionEventMap[K]; ignorable?: true; } & (K extends SurfaceEventType ? { sourceEventSeqs?: number[]; surfaceOp?: SurfaceOp; } : object) }[T];" + }, + { + "name": "SessionEventMap", + "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: number; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n 'goal/change': GoalChangeMeta;\n}" + }, + { + "name": "SessionEventType", + "declaration": "export type SessionEventType = keyof SessionEventMap;" + }, + { + "name": "SessionHeader", + "declaration": "export interface SessionHeader {\n readonly version: number;\n readonly id: SessionId;\n readonly createdAt: number;\n readonly cwd?: string;\n readonly parentSession?: SessionId;\n readonly seedLength?: number;\n readonly origin?: 'subagent';\n readonly delegationDepth?: number;\n readonly agentPreset?: string;\n}" + }, + { + "name": "SessionId", + "declaration": "export type SessionId = Branded<'SessionId'>;" + }, + { + "name": "SessionSurface", + "declaration": "export interface SessionSurface {\n readonly nodes: readonly number[];\n readonly replaceGeneration: number;\n}" + }, + { + "name": "StreamChunk", + "declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: ReplayEnvelope; };" + }, + { + "name": "SurfaceEventType", + "declaration": "export type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result';" + }, + { + "name": "SurfaceIntent", + "declaration": "export interface SurfaceIntent {\n surfaceOp: SurfaceOp;\n sourceEventSeqs?: number[];\n}" + }, + { + "name": "SurfaceOp", + "declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: number; end: number; };" + }, + { + "name": "TextBlock", + "declaration": "export interface TextBlock {\n type: 'text';\n text: string;\n}" + }, + { + "name": "TodoItem", + "declaration": "export interface TodoItem {\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n}" + }, + { + "name": "TokenUsage", + "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}" + }, + { + "name": "ToolCallBlock", + "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: CallId;\n name: string;\n arguments: string;\n}" + }, + { + "name": "ToolMessageSource", + "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: CallId;\n}" + }, + { + "name": "ToolResultBlock", + "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: CallId;\n content: ContentBlock[];\n isError?: boolean;\n}" + }, + { + "name": "ToolResultMessage", + "declaration": "export interface ToolResultMessage extends Message {\n readonly role: 'user';\n readonly content: [ToolResultBlock];\n readonly source: ToolMessageSource;\n}" + }, + { + "name": "ToolSchema", + "declaration": "export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n}" + }, + { + "name": "TurnEndCancelCause", + "declaration": "export type TurnEndCancelCause = AgentCancelCause | { readonly kind: 'legacy'; };" + }, + { + "name": "TurnEndReason", + "declaration": "export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap];" + }, + { + "name": "TurnEndReasonMap", + "declaration": "export interface TurnEndReasonMap {\n completed: { kind: 'completed'; };\n aborted: { kind: 'aborted'; reason: TurnEndCancelCause; };\n blocked: { kind: 'blocked'; };\n error: { kind: 'error'; error: LlmFailure; };\n 'max-tokens': { kind: 'max-tokens'; };\n interrupted: { kind: 'interrupted'; };\n}" + }, + { + "name": "UserMessage", + "declaration": "export interface UserMessage extends Message {\n readonly role: 'user';\n}" + } + ] + } + ], + "events": [ + { + "description": "One exact Plugin/Package activation is now live in the Host.", + "summary": "One exact Plugin/Package activation is now live in the Host.", + "tags": [ + { + "name": "param", + "argument": "pkg", + "comment": "- stable plugin, immutable package, run identity, and label.", + "text": "@param pkg - stable plugin, immutable package, run identity, and label.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * One exact Plugin/Package activation is now live in the Host.\n * @param pkg - stable plugin, immutable package, run identity, and label.\n * @mode emit\n */", + "name": "cordis/dynamic-package", + "mode": "emit", + "signature": "'cordis/dynamic-package'(pkg: DynamicCordisPackage): void" + }, + { + "description": "One exact activation was withdrawn.", + "summary": "One exact activation was withdrawn.", + "tags": [ + { + "name": "param", + "argument": "retracted", + "comment": "- plugin, package, and run identity.", + "text": "@param retracted - plugin, package, and run identity.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * One exact activation was withdrawn.\n * @param retracted - plugin, package, and run identity.\n * @mode emit\n */", + "name": "cordis/dynamic-retract", + "mode": "emit", + "signature": "'cordis/dynamic-retract'(retracted: DynamicCordisRetracted): void" + }, + { + "description": "Request a live read-only query from the Client inspect registry.", + "summary": "Request a live read-only query from the Client inspect registry.", + "tags": [ + { + "name": "param", + "argument": "request", + "comment": "- correlation, Session, provider, method, and JSON input.", + "text": "@param request - correlation, Session, provider, method, and JSON input.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * Request a live read-only query from the Client inspect registry.\n * @param request - correlation, Session, provider, method, and JSON input.\n * @mode emit\n */", + "name": "cordis/inspect-query", + "mode": "emit", + "signature": "'cordis/inspect-query'(request: CordisInspectQueryRequest): void" + }, + { + "description": "Notify every Client that an inspect query has settled or been cancelled.", + "summary": "Notify every Client that an inspect query has settled or been cancelled.", + "tags": [ + { + "name": "param", + "argument": "resolved", + "comment": "- exact query identity that is no longer answerable.", + "text": "@param resolved - exact query identity that is no longer answerable.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * Notify every Client that an inspect query has settled or been cancelled.\n * @param resolved - exact query identity that is no longer answerable.\n * @mode emit\n */", + "name": "cordis/inspect-query-resolved", + "mode": "emit", + "signature": "'cordis/inspect-query-resolved'(resolved: CordisInspectQueryResolved): void" + }, + { + "description": "A Client-bearing activation needs a browser page, and may require a user decision.", + "summary": "A Client-bearing activation needs a browser page, and may require a user decision.", + "tags": [ + { + "name": "param", + "argument": "request", + "comment": "- correlation identity, owner, target version, mode, and approval requirement.", + "text": "@param request - correlation identity, owner, target version, mode, and approval requirement.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * A Client-bearing activation needs a browser page, and may require a user decision.\n * @param request - correlation identity, owner, target version, mode, and approval requirement.\n * @mode emit\n */", + "name": "cordis/request-run", + "mode": "emit", + "signature": "'cordis/request-run'(request: DynamicCordisRunRequest): void" + }, + { + "description": "A pending Client activation request left the answerable state.", + "summary": "A pending Client activation request left the answerable state.", + "tags": [ + { + "name": "param", + "argument": "resolved", + "comment": "- request identity and outcome.", + "text": "@param resolved - request identity and outcome.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * A pending Client activation request left the answerable state.\n * @param resolved - request identity and outcome.\n * @mode emit\n */", + "name": "cordis/request-run-resolved", + "mode": "emit", + "signature": "'cordis/request-run-resolved'(resolved: DynamicCordisRequestResolved): void" + } + ], + "objects": [] + }, +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.d.ts new file mode 100644 index 0000000..bc67b40 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.d.ts @@ -0,0 +1,55 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import type { + RemoteResult, + TypertRemoteContribution, +} from '@deepseek-ai/dsh-typert-protocol' +import type { ApprovalRequestId, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisDynamicRunMode, CordisErrorDetails, CordisInspectProviderManifest, CordisInspectQueryResolution, CordisInspectRequestId, CordisInspectResolveAck, DynamicCordisClientSource, DynamicCordisHostHalfResult, DynamicCordisInventoryRow, DynamicCordisInvokeResult, DynamicCordisRenderFailure, DynamicCordisResolveAck, DynamicCordisRunResolution, DynamicCordisRunResponse, DynamicCordisStopResponse, DynamicCordisUndefineReceipt } from '@deepseek-ai/dsh-cordis-host-runner/types' +import type { JsonValue, SessionId } from '@deepseek-ai/dsh-session/types' + +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteNamespace$64796e616d6963436f7264697352756e6e6572 { + getClientCode: (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId) => Promise> + inventory: () => Promise> + invoke: (pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, method: string, args: JsonValue) => Promise> + reportClientGuardFailure: (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails) => Promise> + reportRenderFailure: (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure) => Promise> + resolveInspectQuery: (agentId: SessionId, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution) => Promise> + resolveRequestRun: (requestId: ApprovalRequestId, resolution: DynamicCordisRunResolution) => Promise> + runHostHalf: (agentId: SessionId, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean) => Promise> + settleUserRun: (agentId: SessionId, pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution) => Promise> + stopFromPanel: (agentId: SessionId, pluginId: CordisDynamicPluginId) => Promise> + syncInspectManifest: (providers: readonly CordisInspectProviderManifest[]) => Promise> + undefineFromPanel: (agentId: SessionId, pluginId: CordisDynamicPluginId) => Promise> + } + interface TypertRemoteMap { + 'dynamicCordisRunner/getClientCode': (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId) => Promise> + 'dynamicCordisRunner/inventory': () => Promise> + 'dynamicCordisRunner/invoke': (pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, method: string, args: JsonValue) => Promise> + 'dynamicCordisRunner/reportClientGuardFailure': (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails) => Promise> + 'dynamicCordisRunner/reportRenderFailure': (agentId: SessionId, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure) => Promise> + 'dynamicCordisRunner/resolveInspectQuery': (agentId: SessionId, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution) => Promise> + 'dynamicCordisRunner/resolveRequestRun': (requestId: ApprovalRequestId, resolution: DynamicCordisRunResolution) => Promise> + 'dynamicCordisRunner/runHostHalf': (agentId: SessionId, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean) => Promise> + 'dynamicCordisRunner/settleUserRun': (agentId: SessionId, pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution) => Promise> + 'dynamicCordisRunner/stopFromPanel': (agentId: SessionId, pluginId: CordisDynamicPluginId) => Promise> + 'dynamicCordisRunner/syncInspectManifest': (providers: readonly CordisInspectProviderManifest[]) => Promise> + 'dynamicCordisRunner/undefineFromPanel': (agentId: SessionId, pluginId: CordisDynamicPluginId) => Promise> + } + interface TypertRemoteNamespaceMap { + 'dynamicCordisRunner': TypertRemoteNamespace$64796e616d6963436f7264697352756e6e6572 + } + interface TypertRemoteScopeMap { + 'agent:dynamicCordisRunner/getClientCode': (pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId) => Promise> + 'agent:dynamicCordisRunner/reportClientGuardFailure': (pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails) => Promise> + 'agent:dynamicCordisRunner/reportRenderFailure': (pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure) => Promise> + 'agent:dynamicCordisRunner/resolveInspectQuery': (requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution) => Promise> + 'agent:dynamicCordisRunner/runHostHalf': (pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean) => Promise> + 'agent:dynamicCordisRunner/settleUserRun': (pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution) => Promise> + 'agent:dynamicCordisRunner/stopFromPanel': (pluginId: CordisDynamicPluginId) => Promise> + 'agent:dynamicCordisRunner/undefineFromPanel': (pluginId: CordisDynamicPluginId) => Promise> + } +} + +export declare const TYPERT_REMOTE: TypertRemoteContribution +export default TYPERT_REMOTE +//# sourceMappingURL=typert.remote-client.d.ts.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.js new file mode 100644 index 0000000..278f622 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/typert.remote-client.js @@ -0,0 +1,769 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import { z } from 'zod' + +const JsonValueRemoteCodec$schema = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]) +const JsonValueRemoteCodec$schema2 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]) +const JsonValueRemoteCodec$schema3 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]) +const JsonValueRemoteCodec$schema4 = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema4)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema4))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema = z.object({ + 'code': z.string(), + 'name': z.string(), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema = z.array(z.object({ + 'pluginId': z.intersection(z.string(), z.unknown()), + 'agentId': z.intersection(z.string(), z.unknown()), + 'packages': z.array(z.object({ + 'packageId': z.intersection(z.string(), z.unknown()), + 'name': z.string(), + 'purpose': z.string(), + 'hasHostHalf': z.boolean(), + 'hasClientHalf': z.boolean(), +})), + 'currentPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'nextPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'activeRun': z.object({ + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), +}).optional(), + 'latestRun': z.object({ + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'mode': z.union([z.literal("run"), z.literal("update")]), + 'status': z.union([z.literal("rejected"), z.literal("awaiting-approval"), z.literal("running"), z.literal("cancelled"), z.literal("starting-host"), z.literal("client-pending"), z.literal("waiting"), z.literal("failed"), z.literal("stopped")]), + 'approvalRequestId': z.intersection(z.string(), z.unknown()).optional(), + 'requiresApproval': z.boolean().optional(), + 'host': z.object({ + 'status': z.union([z.literal("running"), z.literal("waiting"), z.literal("failed"), z.literal("stopped"), z.literal("absent"), z.literal("pending")]), + 'waitingFor': z.array(z.string()), + 'error': z.string().optional(), +}), + 'client': z.object({ + 'status': z.union([z.literal("running"), z.literal("waiting"), z.literal("failed"), z.literal("stopped"), z.literal("absent"), z.literal("pending")]), + 'waitingFor': z.array(z.string()), + 'error': z.string().optional(), +}), + 'error': z.object({ + 'phase': z.union([z.literal("approval"), z.literal("host-load"), z.literal("host-apply"), z.literal("client-load"), z.literal("client-apply"), z.literal("client-render")]), + 'message': z.string(), + 'stack': z.string().optional(), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), +}).optional(), +}).optional(), +})) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema = z.string() +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema = z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'value': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema4)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema4))]), +}), z.intersection(z.object({ + 'ok': z.literal(false), + 'code': z.union([z.literal("plugin-not-running"), z.literal("stale-run"), z.literal("method-not-found"), z.literal("handler-error")]), +}), z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema = z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema = z.object({ + 'slot': z.string(), + 'message': z.string(), + 'stack': z.string().optional(), + 'abdicated': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema = z.union([z.object({ + 'ok': z.literal(true), + 'data': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("cancelled"), z.literal("provider-missing"), z.literal("method-missing"), z.literal("invalid-input"), z.literal("provider-error")]), + 'message': z.string(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema = z.object({ + 'accepted': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()).optional(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed")]), + 'pluginRunId': z.intersection(z.string(), z.unknown()).optional(), + 'startedHere': z.boolean().optional(), + 'message': z.string().optional(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema = z.object({ + 'accepted': z.boolean(), +}) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema = z.union([z.literal("run"), z.literal("update")]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema = z.union([z.literal(null), z.intersection(z.string(), z.unknown())]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema = z.boolean() +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()), + 'startedHere': z.boolean(), +}), z.intersection(z.object({ + 'ok': z.literal(false), +}), z.object({ + 'message': z.string(), + 'stack': z.string().optional(), +}))]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema = z.union([z.object({ + 'ok': z.literal(true), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()).optional(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed")]), + 'pluginRunId': z.intersection(z.string(), z.unknown()).optional(), + 'startedHere': z.boolean().optional(), + 'message': z.string().optional(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'status': z.union([z.literal("awaiting-approval"), z.literal("starting"), z.literal("running")]), + 'pluginId': z.intersection(z.string(), z.unknown()), + 'packageId': z.intersection(z.string(), z.unknown()), + 'pluginRunId': z.intersection(z.string(), z.unknown()), + 'waitingFor': z.array(z.string()), + 'clientWaitingFor': z.array(z.string()).optional(), + 'currentPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'nextPackageId': z.intersection(z.string(), z.unknown()).optional(), + 'mode': z.union([z.literal("run"), z.literal("update")]), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("plugin-missing"), z.literal("rejected"), z.literal("host-half-failed"), z.literal("client-half-failed"), z.literal("package-missing"), z.literal("invalid-mode"), z.literal("transition-in-flight"), z.literal("cancelled"), z.literal("not-running")]), + 'message': z.string(), + 'stack': z.string().optional(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema = z.union([z.object({ + 'ok': z.literal(true), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.union([z.literal("plugin-missing"), z.literal("not-running")]), + 'message': z.string(), +})]) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema = z.array(z.object({ + 'id': z.string(), + 'description': z.string(), + 'methods': z.array(z.object({ + 'name': z.string(), + 'description': z.string(), + 'inputSchema': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]), + 'outputSchema': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))]), +})), +})) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema = z.literal(null) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema = z.union([z.object({ + 'ok': z.literal(true), + 'wasRunning': z.boolean(), +}), z.object({ + 'ok': z.literal(false), + 'reason': z.literal("plugin-missing"), + 'message': z.string(), +})]) + +export const TYPERT_REMOTE = { + package: '@deepseek-ai/dsh-cordis-host-runner', + descriptors: [ + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/getClientCode', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'getClientCode', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisClientSource', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_getClientCode_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":384,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'inventory', + invocation: { kind: 'direct' }, + parameters: [ + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/inventory:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_inventory_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":525,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'invoke', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_0$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_1$schema, + }, + }, + { + name: 'method', + wire: 'method', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/invoke:method', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_2$schema, + }, + }, + { + name: 'args', + wire: 'args', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#JsonValue', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisInvokeResult', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_invoke_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":741,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'reportClientGuardFailure', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_2$schema, + }, + }, + { + name: 'failure', + wire: 'failure', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisErrorDetails', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportClientGuardFailure:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportClientGuardFailure_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":718,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'reportRenderFailure', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_1$schema, + }, + }, + { + name: 'pluginRunId', + wire: 'pluginRunId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginRunId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_2$schema, + }, + }, + { + name: 'failure', + wire: 'failure', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRenderFailure', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_parameter_3$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/reportRenderFailure:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_reportRenderFailure_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":684,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveInspectQuery', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'resolveInspectQuery', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_0$schema, + }, + }, + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectRequestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_1$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectQueryResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisInspectResolveAck', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveInspectQuery_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":511,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/resolveRequestRun', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'resolveRequestRun', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#ApprovalRequestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_0$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisResolveAck', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_resolveRequestRun_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":413,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'runHostHalf', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_1$schema, + }, + }, + { + name: 'packageId', + wire: 'packageId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPackageId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_2$schema, + }, + }, + { + name: 'mode', + wire: 'mode', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicRunMode', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_3$schema, + }, + }, + { + name: 'requestId', + wire: 'requestId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:requestId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_4$schema, + }, + }, + { + name: 'approveFutureVersions', + wire: 'approveFutureVersions', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/runHostHalf:approveFutureVersions', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_parameter_5$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisHostHalfResult', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_runHostHalf_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":325,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/settleUserRun', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'settleUserRun', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_1$schema, + }, + }, + { + name: 'resolution', + wire: 'resolution', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResolution', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisRunResponse', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_settleUserRun_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":438,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/stopFromPanel', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'stopFromPanel', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisStopResponse', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_stopFromPanel_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":480,"column":9}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'syncInspectManifest', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'providers', + wire: 'providers', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:providers', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/syncInspectManifest:result', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_syncInspectManifest_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":498,"column":3}, + }, + { + id: '@deepseek-ai/dsh-cordis-host-runner#dynamicCordisRunner/undefineFromPanel', + service: 'dynamicCordisRunner', + namespace: 'dynamicCordisRunner', + method: 'undefineFromPanel', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_0$schema, + }, + }, + { + name: 'pluginId', + wire: 'pluginId', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#CordisDynamicPluginId', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-cordis-host-runner/types#DynamicCordisUndefineReceipt', + schema: _deepseek_ai_dsh_cordis_host_runner_dynamicCordisRunner_undefineFromPanel_result$schema, + }, + sourceLocation: {"file":"packages/extensions/cordis-host-runner/src/index.ts","line":227,"column":9}, + }, + ], +} + +export default TYPERT_REMOTE diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.d.ts new file mode 100644 index 0000000..30a4157 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.d.ts @@ -0,0 +1,71 @@ +/** + * The registration boundary between a sandboxed host half and the real runtime: ParameterSchemaSpec + * normalization + validation with teaching errors, the marker-guarded `harness.defineTool` / + * `harness.registerTool` pair, the `harness.handle` invoke-handler normalizer, the SANDBOX CONTEXT + * FAÇADE a running plugin's `apply` receives in place of the real `ctx`, and the plugin-shape + * helpers the run lifecycle narrows sandbox return values with. The façade is a whitelist of + * lifecycle-safe verbs and declared services; framework internals and context-valued service + * returns are denied. + * + * VM-realm schemas and canonical values are rebuilt as host objects, while rendered content and + * presentation metadata are shape-checked before entering the registry. Common JSON-Schema spellings are normalized when they + * have one meaning; invalid vocabulary fails during registration with a teaching error. + * @module @deepseek-ai/dsh-cordis-host-runner/guard + */ +import { Context } from '@deepseek-ai/cordis'; +import type { Plugin } from '@deepseek-ai/cordis'; +import type { ToolDefinition } from '@deepseek-ai/dsh-tools'; +/** + * The `harness.defineTool` handed into the sandbox: the real DSL, with `parameters` normalized + * into a fresh host-realm ParameterSchemaSpec (raw object wrappers unwrapped, + * required arrays mapped, and explicit DSL object openness enforced) and the tool's `execute` return normalized into the host realm + * via a JSON round-trip. Non-JSON or wrong-shape output fails that call instead of poisoning + * the session log. + * @param options - the standard `defineTool` options; `parameters` may be the ParameterSchemaSpec DSL or a JSON-Schema-style wrapper. + * @returns the marker-tagged definition `harness.registerTool` (and the guarded `ctx.tools.register`) accepts. + */ +export declare function sandboxDefineTool(options: unknown): ToolDefinition; +/** + * Normalize one `harness.handle` registration at the sandbox boundary: the + * method name must be a non-empty string and the handler a function whose + * result is host-materialized through the same cross-realm JSON clone as tool + * `execute` returns (a VM-realm object would otherwise escape the wire's + * plain-object contract). + * @param method - handler name the package's browser half calls through `host.call`. + * @param fn - sandbox handler receiving the wire-decoded JSON arguments. + * @returns the validated name and the clone-wrapped handler. + */ +export declare function normalizeHandler(method: unknown, fn: unknown): { + method: string; + handler: (args: unknown) => Promise; +}; +/** + * The `harness.registerTool` handed into the sandbox: registers a + * marker-verified dynamic tool on the given context's registry. + * @param ctx - the (guarded) context whose `tools` service receives the tool. + * @param tool - a definition produced by {@link sandboxDefineTool}; anything else is rejected. + * @returns the registry disposer for the registration. + */ +export declare function sandboxRegisterTool(ctx: Context, tool: unknown): () => void; +/** + * Narrow an arbitrary sandbox return value to a runnable cordis plugin: a + * function, or an object with an `apply` function. (A bare function passes the + * first arm, so the object arm never sees `Function.prototype.apply`.) + * @param value - whatever the host half returned. + * @returns whether the value can be started via `ctx.plugin`. + */ +export declare function isPlugin(value: unknown): value is Plugin; +/** + * Wrap a plugin so `apply` receives the sandbox context while preserving injection metadata. + * @param plugin - the plugin the host half returned. + * @param reportFailure - reports a guard rejection to the owning Agent. + * @returns an equivalent plugin whose `apply` sees the sandbox context façade. + */ +export declare function guardedPlugin(plugin: Plugin, reportFailure: (error: Error) => void): Plugin; +/** + * Display name for a running plugin: its `name` property, else anonymous. + * @param plugin - the plugin the host half returned. + * @returns the human-readable name used in run results and inspect output. + */ +export declare function pluginName(plugin: Plugin): string; +//# sourceMappingURL=guard.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.js new file mode 100644 index 0000000..aa5d4f4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/guard.js @@ -0,0 +1,766 @@ +/** + * The registration boundary between a sandboxed host half and the real runtime: ParameterSchemaSpec + * normalization + validation with teaching errors, the marker-guarded `harness.defineTool` / + * `harness.registerTool` pair, the `harness.handle` invoke-handler normalizer, the SANDBOX CONTEXT + * FAÇADE a running plugin's `apply` receives in place of the real `ctx`, and the plugin-shape + * helpers the run lifecycle narrows sandbox return values with. The façade is a whitelist of + * lifecycle-safe verbs and declared services; framework internals and context-valued service + * returns are denied. + * + * VM-realm schemas and canonical values are rebuilt as host objects, while rendered content and + * presentation metadata are shape-checked before entering the registry. Common JSON-Schema spellings are normalized when they + * have one meaning; invalid vocabulary fails during registration with a teaching error. + * @module @deepseek-ai/dsh-cordis-host-runner/guard + */ +import { Context } from '@deepseek-ai/cordis'; +import { scopeOf } from '@deepseek-ai/dsh-scope'; +import { assertSupportedJsonSchema, defineTool } from '@deepseek-ai/dsh-tools'; +const DYNAMIC_TOOL = Symbol('cordis-host-runner.dynamic-tool'); +const SCHEMA_TYPES = new Set(['string', 'number', 'integer', 'boolean', 'null', 'object', 'array', 'json']); +const VALID_TYPES = '\'string\' | \'number\' | \'integer\' | \'boolean\' | \'null\' | \'object\' | \'array\' | \'json\''; +const ANNOTATION_KEYS = ['description', 'title', 'default', 'examples']; +function isPlainRecord(value) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) + return false; + const prototype = Object.getPrototypeOf(value); + return prototype === null + || typeof prototype === 'object' + && Object.getPrototypeOf(prototype) === null + && hasIntrinsicConstructor(prototype, 'Object'); +} +/* jscpd:ignore-start -- this VM boundary mirrors the session-owned realm-safe intrinsic test */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor'); + const constructor = descriptor?.value; + if (typeof constructor !== 'function') + return false; + try { + return constructor.name === name + && constructor.prototype === prototype + && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } + catch { + return false; + } +} +/** Whether an array uses one realm's intrinsic Array prototype rather than a subclass. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) + return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === 'object' + && objectPrototype !== null + && Object.getPrototypeOf(objectPrototype) === null + && hasIntrinsicConstructor(objectPrototype, 'Object'); +} +/* jscpd:ignore-end */ +/** Whether a schema list is a dense intrinsic array with no JSON-invisible decorations. */ +function isDensePlainArray(value) { + if (!Array.isArray(value) || !hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) { + return false; + } + for (let index = 0; index < value.length; index++) { + if (!Object.hasOwn(value, index)) + return false; + } + return true; +} +/** Reject schema records whose declarations would disappear from object enumeration. */ +function assertSchemaContainerKeys(value, path) { + if (Reflect.ownKeys(value).some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) { + throw new Error(`harness.defineTool ${path} must contain only own enumerable string keys`); + } +} +/** Materialize realm-foreign lossless JSON without allowing JSON.stringify coercions; `path` carries the caller's own error prefix. */ +function cloneJson(value, path) { + const ancestors = new Set(); + let root; + const assign = (destination, item) => { + if (destination.kind === 'root') { + root = item; + return; + } + if (destination.kind === 'array') { + destination.target[destination.index] = item; + return; + } + Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true, + }); + }; + const reject = (at) => { + // Naming the executable next step matters more than naming the rule: the + // usual cause is a handler that returns whatever its last call produced, + // and the fix is one keyword. + throw new Error(`${at} must be lossless JSON data (objects, arrays, strings, numbers, booleans, null) — ` + + 'not a class instance, function, Map/Set, Date, or undefined. Return a plain object built from the ' + + 'values you need, or `return null` when the caller needs no value back.'); + }; + const tasks = [{ kind: 'visit', value, path, destination: { kind: 'root' } }]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + ancestors.delete(task.source); + continue; + } + if (task.kind === 'array-item') { + if (!Object.hasOwn(task.source, task.index)) + reject(task.path); + tasks.push({ + kind: 'visit', + value: task.source[task.index], + path: `${task.path}[${task.index}]`, + destination: { kind: 'array', target: task.target, index: task.index }, + }); + continue; + } + const current = task.value; + if (current === null || typeof current === 'string' || typeof current === 'boolean') { + assign(task.destination, current); + continue; + } + if (typeof current === 'number') { + if (!Number.isFinite(current) || Object.is(current, -0)) + reject(task.path); + assign(task.destination, current); + continue; + } + if (typeof current !== 'object' || ancestors.has(current)) + reject(task.path); + if (Array.isArray(current)) { + if (!hasPlainArrayPrototype(current) || Reflect.ownKeys(current).length !== current.length + 1) + reject(task.path); + const output = []; + assign(task.destination, output); + ancestors.add(current); + tasks.push({ kind: 'leave', source: current }); + for (let index = current.length - 1; index >= 0; index--) { + tasks.push({ kind: 'array-item', source: current, index, path: task.path, target: output }); + } + continue; + } + if (!isPlainRecord(current)) + reject(task.path); + const record = current; + if (Reflect.ownKeys(record).some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(record, key))) { + reject(task.path); + } + const output = {}; + assign(task.destination, output); + ancestors.add(record); + tasks.push({ kind: 'leave', source: record }); + const entries = Object.entries(record); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) + continue; + tasks.push({ + kind: 'visit', + value: entry[1], + path: `${task.path}.${entry[0]}`, + destination: { kind: 'object', target: output, key: entry[0] }, + }); + } + } + return root; +} +/** Copy and realm-materialize the shared annotation vocabulary. */ +function copyAnnotations(value, output, path) { + if (Object.hasOwn(value, 'description')) + output.description = value.description; + if (Object.hasOwn(value, 'title')) + output.title = value.title; + if (Object.hasOwn(value, 'default')) + output.default = cloneJson(value.default, `harness.defineTool ${path}.default`); + if (Object.hasOwn(value, 'examples')) + output.examples = cloneJson(value.examples, `harness.defineTool ${path}.examples`); +} +/** Reject sandbox schema keys that the unified DSL would otherwise ignore. */ +function assertSchemaKeys(value, path, allowed) { + assertSchemaContainerKeys(value, path); + for (const key of Object.keys(value)) { + if (!allowed.includes(key)) + throw new Error(`harness.defineTool ${path}.${key} is not supported by the unified schema DSL`); + } +} +/** + * Normalize a sandbox-provided `parameters` value into a fresh host-realm + * ParameterSchemaSpec. A raw JSON-Schema object wrapper retains its open root + * default, while the direct DSL is already an implicit open property map. + */ +function normalizeParameterSchemaSpec(value, path = 'parameters') { + if (!isPlainRecord(value)) { + throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec object`); + } + if (value.type === 'object') { + assertSchemaKeys(value, path, ['type', 'properties', 'required', 'additionalProperties', ...ANNOTATION_KEYS]); + if (!isPlainRecord(value.properties)) { + throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`); + } + if (Object.hasOwn(value, 'additionalProperties') && value.additionalProperties !== true) { + throw new Error(`harness.defineTool ${path}.additionalProperties must be true or omitted because the implicit parameter root is open`); + } + if (Object.hasOwn(value, 'required') && value.required === undefined) { + throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`); + } + const required = normalizeRequiredNames(value.required, value.properties, `${path}.required`); + const rootAnnotations = {}; + copyAnnotations(value, rootAnnotations, path); + return { + spec: normalizePropertyMap(value.properties, path, required, true), + ...(Object.keys(rootAnnotations).length === 0 ? {} : { rootAnnotations }), + }; + } + return { spec: normalizePropertyMap(value, path, new Set(), false) }; +} +/** Validate raw required names and return their lookup set. */ +function normalizeRequiredNames(value, properties, path) { + if (value === undefined) + return new Set(); + if (!isDensePlainArray(value)) { + throw new Error(`harness.defineTool ${path} must be an array of declared property names`); + } + const names = new Set(); + for (let index = 0; index < value.length; index++) { + const name = value[index]; + if (typeof name !== 'string') { + throw new Error(`harness.defineTool ${path} must be an array of declared property names`); + } + names.add(name); + if (!Object.hasOwn(properties, name)) + throw new Error(`harness.defineTool ${path} names undeclared property ${JSON.stringify(name)}`); + } + return names; +} +/** Install one normalized node without `__proto__` assignment semantics. */ +function assignNormalizedValue(destination, value) { + if (destination.kind === 'property') { + Object.defineProperty(destination.target, destination.key, { + value, + enumerable: true, + configurable: true, + writable: true, + }); + } + else if (destination.kind === 'item') { + destination.target.items = value; + } + else { + destination.target[destination.index] = value; + } +} +/** Install one normalized property map at its root or containing object. */ +function assignNormalizedMap(destination, value) { + if (destination.kind === 'root') + destination.holder.value = value; + else + destination.target.properties = value; +} +/** Normalize one implicit property map and all descendants with explicit work frames. */ +function normalizePropertyMap(entries, path, requiredNames, raw) { + const holder = {}; + const ancestors = new Set(); + const tasks = [{ + kind: 'map', + entries, + path, + requiredNames, + raw, + destination: { kind: 'root', holder }, + }]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + ancestors.delete(task.value); + continue; + } + if (task.kind === 'map') { + if (ancestors.has(task.entries)) + throw new Error(`harness.defineTool ${task.path} is circular`); + assertSchemaContainerKeys(task.entries, task.path); + ancestors.add(task.entries); + const spec = {}; + assignNormalizedMap(task.destination, spec); + tasks.push({ kind: 'leave', value: task.entries }); + const mapEntries = Object.entries(task.entries); + for (let index = mapEntries.length - 1; index >= 0; index--) { + const entry = mapEntries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) + continue; + tasks.push({ + kind: 'value', + value: entry[1], + path: `${task.path}.${entry[0]}`, + forceRequired: task.requiredNames.has(entry[0]), + raw: task.raw, + parameterProperty: true, + destination: { kind: 'property', target: spec, key: entry[0] }, + }); + } + continue; + } + const { value, path } = task; + if (!isPlainRecord(value)) { + throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec property object`); + } + assertSchemaContainerKeys(value, path); + if (ancestors.has(value)) + throw new Error(`harness.defineTool ${path} is circular`); + ancestors.add(value); + const requiredKey = task.parameterProperty && !task.raw ? ['required'] : []; + if (task.parameterProperty && task.raw && Object.hasOwn(value, 'required') && value.type !== 'object') { + throw new Error(`harness.defineTool ${path}.required belongs to the containing raw object schema`); + } + if (task.parameterProperty && !task.raw && Object.hasOwn(value, 'required') && value.required !== true) { + throw new Error(`harness.defineTool ${path}.required must be true when present`); + } + const prop = {}; + assignNormalizedValue(task.destination, prop); + tasks.push({ kind: 'leave', value }); + if (task.forceRequired || value.required === true) + prop.required = true; + copyAnnotations(value, prop, path); + if (Object.hasOwn(value, 'oneOf')) { + assertSchemaKeys(value, path, ['oneOf', ...requiredKey, ...ANNOTATION_KEYS]); + if (!isDensePlainArray(value.oneOf) || value.oneOf.length < 2) { + throw new Error(`harness.defineTool ${path}.oneOf must contain at least two schemas`); + } + const oneOf = []; + prop.oneOf = oneOf; + for (let index = value.oneOf.length - 1; index >= 0; index--) { + tasks.push({ + kind: 'value', + value: value.oneOf[index], + path: `${path}.oneOf[${index}]`, + forceRequired: false, + raw: task.raw, + parameterProperty: false, + destination: { kind: 'one-of', target: oneOf, index }, + }); + } + continue; + } + if (task.raw && !Object.hasOwn(value, 'type')) { + assertSchemaKeys(value, path, ANNOTATION_KEYS); + prop.type = 'json'; + continue; + } + if (!SCHEMA_TYPES.has(value.type) || task.raw && value.type === 'json') { + throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES} (got ${JSON.stringify(value.type)})`); + } + const type = value.type; + prop.type = type; + switch (type) { + case 'object': { + assertSchemaKeys(value, path, ['type', 'properties', 'additionalProperties', ...requiredKey, ...(task.raw ? ['required'] : []), ...ANNOTATION_KEYS]); + if (!task.raw && (!Object.hasOwn(value, 'additionalProperties') || typeof value.additionalProperties !== 'boolean')) { + throw new Error(`harness.defineTool ${path}.additionalProperties must be explicitly true or false`); + } + if (task.raw && Object.hasOwn(value, 'additionalProperties') && typeof value.additionalProperties !== 'boolean') { + throw new Error(`harness.defineTool ${path}.additionalProperties must be a boolean`); + } + if (task.raw && Object.hasOwn(value, 'required') && value.required === undefined) { + throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`); + } + prop.additionalProperties = task.raw ? value.additionalProperties ?? true : value.additionalProperties; + if (Object.hasOwn(value, 'properties')) { + const properties = value.properties; + if (!isPlainRecord(properties)) + throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`); + const nestedRequired = task.raw + ? normalizeRequiredNames(value.required, properties, `${path}.required`) + : new Set(); + tasks.push({ + kind: 'map', + entries: properties, + path: `${path}.properties`, + requiredNames: nestedRequired, + raw: task.raw, + destination: { kind: 'properties', target: prop }, + }); + } + else if (task.raw && value.required !== undefined) { + normalizeRequiredNames(value.required, {}, `${path}.required`); + } + break; + } + case 'array': + assertSchemaKeys(value, path, ['type', 'items', ...requiredKey, ...ANNOTATION_KEYS]); + if (Object.hasOwn(value, 'items')) { + tasks.push({ + kind: 'value', + value: value.items, + path: `${path}.items`, + forceRequired: false, + raw: task.raw, + parameterProperty: false, + destination: { kind: 'item', target: prop }, + }); + } + break; + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': + assertSchemaKeys(value, path, ['type', 'enum', 'const', ...requiredKey, ...ANNOTATION_KEYS]); + if (Object.hasOwn(value, 'enum')) { + if (!isDensePlainArray(value.enum) || value.enum.length === 0) { + throw new Error(`harness.defineTool ${path}.enum must be a non-empty array`); + } + prop.enum = cloneJson(value.enum, `harness.defineTool ${path}.enum`); + } + if (Object.hasOwn(value, 'const')) + prop.const = cloneJson(value.const, `harness.defineTool ${path}.const`); + break; + case 'json': + assertSchemaKeys(value, path, ['type', ...requiredKey, ...ANNOTATION_KEYS]); + break; + /* v8 ignore next 2 -- SCHEMA_TYPES narrows this closed switch before dispatch. */ + default: + throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES}`); + } + } + /* v8 ignore next -- the root map task assigns before scheduling descendants. */ + return holder.value ?? {}; +} +function markDynamicTool(tool) { + Object.defineProperty(tool, DYNAMIC_TOOL, { value: true }); + return tool; +} +function assertDynamicTool(tool) { + if (!isPlainRecord(tool) || tool[DYNAMIC_TOOL] !== true) { + throw new Error('dynamic tool registration must use a tool returned by harness.defineTool(...)'); + } +} +/** + * Structurally a content block, checked AFTER the JSON round-trip: a plain + * object carrying a string `type` tag. Deliberately nothing deeper — the + * ContentBlock union is merge-extensible (an unknown tag must pass), and every + * downstream consumer dispatches on `type` and falls through unknowns. + */ +function isContentBlockShape(value) { + return isPlainRecord(value) && typeof value.type === 'string'; +} +/** + * How much of an invalid execute return the teaching error echoes back — a + * huge blob would burn the model turn the error is trying to save. + */ +const RETURN_PREVIEW_LIMIT = 120; +/** + * Compact JSON preview of an invalid execute return for the teaching error + * (`String(…)` for the un-stringifiable undefined case), truncated to + * {@link RETURN_PREVIEW_LIMIT}. + */ +function describeReturn(value) { + // The caller has already crossed cloneJson, so this value is lossless JSON + // and serialization cannot produce undefined. + const json = JSON.stringify(value); + return json.length > RETURN_PREVIEW_LIMIT ? `${json.slice(0, RETURN_PREVIEW_LIMIT)}…` : json; +} +/** + * Validate and host-materialize a sandbox renderer's content blocks. + */ +function assertRenderedContent(value) { + if (Array.isArray(value) && value.every(isContentBlockShape)) { + return value; + } + throw new Error(`output.render returned ${describeReturn(value)} — it must return an ARRAY of content blocks:\n` + + ' ✓ return [{ type: \'text\', text: String(value) }]'); +} +/** + * The `harness.defineTool` handed into the sandbox: the real DSL, with `parameters` normalized + * into a fresh host-realm ParameterSchemaSpec (raw object wrappers unwrapped, + * required arrays mapped, and explicit DSL object openness enforced) and the tool's `execute` return normalized into the host realm + * via a JSON round-trip. Non-JSON or wrong-shape output fails that call instead of poisoning + * the session log. + * @param options - the standard `defineTool` options; `parameters` may be the ParameterSchemaSpec DSL or a JSON-Schema-style wrapper. + * @returns the marker-tagged definition `harness.registerTool` (and the guarded `ctx.tools.register`) accepts. + */ +export function sandboxDefineTool(options) { + if (!isPlainRecord(options)) + throw new Error('harness.defineTool options must be an object'); + const normalized = normalizeParameterSchemaSpec(options.parameters); + if (!isPlainRecord(options.output)) { + throw new Error('harness.defineTool output must declare { schema, render, presentationMeta? }'); + } + const output = options.output; + if (typeof output.render !== 'function') + throw new Error('harness.defineTool output.render must be a function'); + if (output.presentationMeta !== undefined && typeof output.presentationMeta !== 'function') { + throw new Error('harness.defineTool output.presentationMeta must be a function when present'); + } + if (typeof options.execute !== 'function') + throw new Error('harness.defineTool execute must be a function'); + const schema = cloneJson(output.schema, 'harness.defineTool output.schema'); + const rawExecute = options.execute; + const rawRender = output.render; + const rawPresentationMeta = output.presentationMeta; + const erasedDefineTool = defineTool; + const tool = erasedDefineTool({ + ...options, + parameters: normalized.spec, + output: { + schema, + render(args, value) { + return assertRenderedContent(cloneJson(rawRender(args, value), 'harness.defineTool output.render result')); + }, + ...rawPresentationMeta !== undefined ? { + presentationMeta(args, value) { + return cloneJson(rawPresentationMeta(args, value), 'harness.defineTool output.presentationMeta result'); + }, + } : {}, + }, + async execute(args, exec) { + return cloneJson(await rawExecute(args, exec), 'harness.defineTool execute result'); + }, + }); + const parameters = { ...tool.parameters, ...normalized.rootAnnotations }; + assertSupportedJsonSchema(parameters); + return markDynamicTool({ + ...tool, + parameters, + }); +} +/** + * Normalize one `harness.handle` registration at the sandbox boundary: the + * method name must be a non-empty string and the handler a function whose + * result is host-materialized through the same cross-realm JSON clone as tool + * `execute` returns (a VM-realm object would otherwise escape the wire's + * plain-object contract). + * @param method - handler name the package's browser half calls through `host.call`. + * @param fn - sandbox handler receiving the wire-decoded JSON arguments. + * @returns the validated name and the clone-wrapped handler. + */ +export function normalizeHandler(method, fn) { + if (typeof method !== 'string' || method.length === 0) { + throw new Error('harness.handle(method, fn) needs a non-empty string method name'); + } + if (typeof fn !== 'function') { + throw new Error(`harness.handle("${method}") needs a handler function as its second argument`); + } + const rawHandler = fn; + return { + method, + handler: async (args) => cloneJson(await rawHandler(args), `harness.handle("${method}") result`), + }; +} +/** + * The `harness.registerTool` handed into the sandbox: registers a + * marker-verified dynamic tool on the given context's registry. + * @param ctx - the (guarded) context whose `tools` service receives the tool. + * @param tool - a definition produced by {@link sandboxDefineTool}; anything else is rejected. + * @returns the registry disposer for the registration. + */ +export function sandboxRegisterTool(ctx, tool) { + assertDynamicTool(tool); + return ctx.tools.register(tool); +} +/** + * The verbs a running host half may reach through the sandbox `ctx` façade, beyond its injected + * services. `on`/`once` observe events, `provide` exposes a service to other packages, and the + * timer helpers schedule work — each a fiber effect that unwinds when the package stops. + */ +const CTX_VERBS = new Set(['effect', 'on', 'once', 'provide', 'timeout', 'interval', 'setTimeout', 'setInterval', 'throttle', 'debounce']); +const TIMER_VERBS = new Set(['timeout', 'interval', 'setTimeout', 'setInterval', 'throttle', 'debounce']); +/** + * The tool-registry façade: `register` (marker-guarded) plus READ-ONLY + * metadata (`schemas`, and `get` returning a schema view, never the live + * `ToolDefinition`). Exposing the raw definition would hand package code the + * tool's `execute` function, letting it call another tool directly and bypass + * `ToolRuntime.execute` — identity protection, pre-policy, monotonic guards, + * around dispatch, post-policy, final observation, and result normalization. So `get` returns the same + * name/description/parameters view as `schemas()`, and nothing invocable. + */ +function sandboxTools(ctx) { + // Resolve reads and writes through the package's own scope. + return { + register: (tool) => sandboxRegisterTool(ctx, tool), + schemas: () => ctx.tools.schemas(scopeOf(ctx)), + get: (name) => ctx.tools.schemas(scopeOf(ctx)).find(schema => schema.name === name), + }; +} +/** + * Reject any injected-service return that is a cordis `Context`. Harness + * services return data, never a context; a value that is one would be a + * fresh, unguarded handle back into the runtime — the exact escape the façade + * exists to close — so it fails loud instead of reaching sandbox code. + */ +// Twinned with the browser half's guard for the same reason as the ctx façade +// below: this is the rule "a service must never hand sandboxed code a Context", +// and each half must test against the Context class of ITS OWN face. Moving the +// rule into a shared package would move a security invariant out of the halves +// that enforce it, which is a design decision rather than a duplication fix. +/* jscpd:ignore-start */ +function denyContext(value, service, reportFailure) { + if (value instanceof Context) { + return rejectGuard(reportFailure, `service "${service}" returned a cordis Context, which the sandbox does not expose. ` + + 'Operate through your own plugin ctx (ctx.on / ctx.provide / ctx.tools.register) ' + + 'and the services you inject — never another context.'); + } + return value; +} +/** + * Wrap an injected service so its methods forward to the real instance but + * their return values pass through {@link denyContext}. Non-function members + * (plain data) pass through as-is; a returned Promise is guarded on resolve. + */ +function guardedService(service, name, reportFailure) { + return new Proxy(service, { + get(target, prop) { + const value = Reflect.get(target, prop, target); + if (typeof value !== 'function') + return denyContext(value, name, reportFailure); + return (...args) => { + const result = Reflect.apply(value, target, args); + if (result instanceof Promise) + return result.then(v => denyContext(v, name, reportFailure)); + return denyContext(result, name, reportFailure); + }; + }, + }); +} +/* jscpd:ignore-end */ +/** + * The service names a plugin declared in `inject`, as a lookup set. Whatever + * declaration style the plugin used — an `inject: ['bash', 'tools']` array or + * the `{ required, optional }` object form — cordis resolves it into a single + * name-keyed map on the fiber before `apply` runs (`{ bash: null, tools: null }`), + * so the gate just reads that map's keys. A host half may reach only the services + * it declared — that is what lets cordis park it when a declared provider + * goes away. + */ +function declaredInjects(ctx) { + return new Set(Object.keys(ctx.fiber.inject)); +} +/** + * Whitelist context for running host halves: lifecycle-safe verbs, guarded + * tools, optional `ctx.get()` lookup, and declared-service property access. + * Framework plumbing is denied, and service methods cannot return a Context. + */ +function sandboxContext(ctx, reportFailure) { + const tools = sandboxTools(ctx); + const declared = declaredInjects(ctx); + // A framework member or an undeclared service — distinguish the two so the + // error teaches the right fix (declare it in inject vs it is withheld). + const denyRead = (prop) => { + if (ctx.get(prop) !== undefined) { + return rejectGuard(reportFailure, `service "${prop}" is not injected. Declare it: inject: ['${prop}', …] on your plugin, ` + + 'so cordis parks this dynamic package if the provider later goes away.'); + } + return rejectGuard(reportFailure, `sandbox ctx does not expose "${prop}". Available: ctx.tools.register / ctx.on / ctx.provide / ` + + 'the timer helpers after injecting timer, and any service you declared in inject. ' + + 'Framework internals (root, fiber, registry, extend, plugin, …) are withheld by design.'); + }; + // `get` is optional lookup; property access requires a declaration. `tools` + // is the façade's own API on either path. + const readService = (name, requireDeclaration) => { + if (name === 'tools') + return tools; + if (requireDeclaration && !declared.has(name)) + return denyRead(name); + const service = denyContext(ctx.get(name), name, reportFailure); + if (service === null || (typeof service !== 'object' && typeof service !== 'function')) + return service; + return guardedService(service, name, reportFailure); + }; + const get = (name) => readService(name, false); + // The browser half builds the same façade over its own Context + // (`@deepseek-ai/dsh-cordis-client-runner`, whose CTX_VERBS names this one its + // twin), and the sameness is the point: a package author meets ONE contract on + // both halves. Folding them together is not available — the two halves compile + // in separate programs where `Context` merges different service keys — so the + // duplication is declared here instead of hidden behind a config exception. + /* jscpd:ignore-start */ + return new Proxy({}, { + get(_target, prop) { + if (prop === 'tools') + return tools; + if (prop === 'get') + return get; + if (typeof prop !== 'string') + return undefined; + // Lazy verb forwarder — reads `ctx[verb]` only when called. Timer mixins + // additionally require the Service declaration before Cordis resolves them. + if (CTX_VERBS.has(prop)) { + return (...args) => { + if (TIMER_VERBS.has(prop) && !declared.has('timer')) + return denyRead('timer'); + const method = ctx[prop]; + return Reflect.apply(method, ctx, args); + }; + } + return readService(prop, true); + }, + // A façade is not the real ctx; block writes rather than let package code + // stash state on a throwaway object and think it persisted. + set(_target, prop) { + return rejectGuard(reportFailure, `sandbox ctx is read-only; cannot assign "${String(prop)}"`); + }, + // `in` reflects reachability: the façade API plus DECLARED services + // (whether or not currently live). Does not resolve/wrap — no throw. + has: (_target, prop) => prop === 'tools' || prop === 'get' + || (typeof prop === 'string' + && ((CTX_VERBS.has(prop) && (!TIMER_VERBS.has(prop) || declared.has('timer'))) || declared.has(prop))), + }); + /* jscpd:ignore-end */ +} +/** + * Narrow an arbitrary sandbox return value to a runnable cordis plugin: a + * function, or an object with an `apply` function. (A bare function passes the + * first arm, so the object arm never sees `Function.prototype.apply`.) + * @param value - whatever the host half returned. + * @returns whether the value can be started via `ctx.plugin`. + */ +export function isPlugin(value) { + if (typeof value === 'function') + return true; + return typeof value === 'object' && value !== null + && typeof value.apply === 'function'; +} +/** + * Wrap a plugin so `apply` receives the sandbox context while preserving injection metadata. + * @param plugin - the plugin the host half returned. + * @param reportFailure - reports a guard rejection to the owning Agent. + * @returns an equivalent plugin whose `apply` sees the sandbox context façade. + */ +export function guardedPlugin(plugin, reportFailure) { + if (typeof plugin === 'function') { + const functionPlugin = plugin; + return { + name: pluginName(plugin), + apply(ctx, config) { + return functionPlugin(sandboxContext(ctx, reportFailure), config); + }, + }; + } + const objectPlugin = plugin; + return { + ...plugin, + apply(ctx, config) { + return objectPlugin.apply(sandboxContext(ctx, reportFailure), config); + }, + }; +} +function rejectGuard(reportFailure, message) { + const error = new Error(message); + reportFailure(error); + throw error; +} +/** + * Display name for a running plugin: its `name` property, else anonymous. + * @param plugin - the plugin the host half returned. + * @returns the human-readable name used in run results and inspect output. + */ +export function pluginName(plugin) { + const named = plugin.name; + if (typeof named === 'string' && named.length > 0) + return named; + return ''; +} +//# sourceMappingURL=guard.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.d.ts new file mode 100644 index 0000000..43b3afb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.d.ts @@ -0,0 +1,270 @@ +/** + * Dynamic Cordis Plugin service: immutable package definitions, one active run + * per Plugin, human-approved Client activation, and Host/Client invocation. + * @module @deepseek-ai/dsh-cordis-host-runner + */ +import { Context } from '@deepseek-ai/cordis'; +import type { Fiber } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { JsonValue } from '@deepseek-ai/dsh-session/types'; +import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'; +import type { DynamicCordisDefineReceipt, DynamicCordisDefineRequest, DynamicCordisPackageInspection, DynamicCordisPluginInspection, DynamicCordisReference } from './registry.ts'; +import type { ApprovalRequestId, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisErrorDetails, CordisDynamicRunMode, CordisInspectProviderManifest, CordisInspectQueryResolution, CordisInspectRequestId, CordisInspectResolveAck, DynamicCordisClientSource, DynamicCordisHostHalfResult, DynamicCordisInventoryRow, DynamicCordisInvokeResult, DynamicCordisRenderFailure, DynamicCordisResolveAck, DynamicCordisRunAttempt, DynamicCordisRunResolution, DynamicCordisRunResponse, DynamicCordisStopResponse, DynamicCordisUndefineReceipt } from './types.ts'; +export type * from './types.ts'; +export type { DynamicCordisDefineReceipt, DynamicCordisDefineRequest, DynamicCordisDefinition, DynamicCordisHandler, DynamicCordisPackageInspection, DynamicCordisPlugin, DynamicCordisPluginInspection, DynamicCordisReference, DynamicCordisRun, } from './registry.ts'; +export { CordisInspectRegistryService } from './inspect-registry.ts'; +export type { HostCordisInspectProviderRegistration } from './inspect-registry.ts'; +export { HOST_BUILTIN_INSPECTION } from './sandbox.ts'; +/** + * Brand a Host-minted Plugin ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Plugin identifier. + */ +export declare function CordisDynamicPluginId(id: string): CordisDynamicPluginId; +/** + * Brand a Host-minted Package ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Package identifier. + */ +export declare function CordisDynamicPackageId(id: string): CordisDynamicPackageId; +/** + * Brand a Host-minted Plugin Run ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Plugin Run identifier. + */ +export declare function CordisDynamicPluginRunId(id: string): CordisDynamicPluginRunId; +/** + * Brand a Host-minted approval request ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded approval request identifier. + */ +export declare function ApprovalRequestId(id: string): ApprovalRequestId; +declare module '@deepseek-ai/cordis' { + interface Context { + /** Process-local dynamic Plugin registry and lifecycle service. */ + dynamicCordisRunner: DynamicCordisRunnerService; + } +} +/** Runner configuration. */ +export interface Config { + /** Maximum synchronous VM evaluation time in milliseconds. */ + vmTimeoutMs?: number; +} +/** Host-only snapshot consumed by inspect and tool result rendering. */ +export interface DynamicCordisSnapshotRow { + pluginId: CordisDynamicPluginId; + currentPackageId?: CordisDynamicPackageId; + nextPackageId?: CordisDynamicPackageId; + packages: Array<{ + packageId: CordisDynamicPackageId; + name: string; + purpose: string; + hasHostHalf: boolean; + hasClientHalf: boolean; + }>; + activeRun?: { + pluginRunId: CordisDynamicPluginRunId; + packageId: CordisDynamicPackageId; + fiber?: Fiber; + handlers: string[]; + renderFailure?: DynamicCordisRenderFailure; + }; + latestRun?: DynamicCordisRunAttempt; +} +/** Dynamic Plugin registry and Host-half lifecycle. */ +export declare class DynamicCordisRunnerService extends TypertRemoteService { + static inject: string[]; + static Config: z; + private readonly rootCtx; + private readonly registry; + private readonly inspectRegistry; + private readonly starting; + private readonly resolved; + private group; + /** Create the service under the Host composition. */ + constructor(ctx: Context, config: Config); + /** + * Define a new Plugin's first Package or append a Package to an existing Plugin. + * @param request - Session ownership, Plugin selection, metadata, and source code. + * @returns Host-minted Plugin and Package identities with declared-half metadata. + */ + define(request: DynamicCordisDefineRequest): DynamicCordisDefineReceipt; + /** + * Remove a Plugin, its active run, and all immutable Packages. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + undefine(agent: Agent, pluginId: CordisDynamicPluginId): Promise; + /** + * Remove a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + undefineFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise; + /** + * Start or update one Package for a model tool call. An unauthorized Client + * Package waits for approval; Plugin-wide authorization covers later versions. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param signal - Tool-call cancellation signal while the activation request is being created. + * @returns The successful activation identity or an actionable refusal. + */ + run(agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, signal?: AbortSignal): Promise; + /** + * Start Host code for an approved request or a direct panel gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param requestId - Model-driven request identity, or null for a direct user gesture. + * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin. + * @returns The exact Host activation or a failure message. + */ + runHostHalf(agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean): Promise; + /** + * Fetch Client code for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to read. + * @param pluginRunId - Exact active run authorized to receive source. + * @returns Client source and its Plugin, Package, and run identities. + */ + getClientCode(agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId): DynamicCordisClientSource; + /** + * Resolve one model-driven Client activation request. + * @param requestId - Request identity to settle once. + * @param resolution - Browser refusal or exact Client activation result. + * @returns Whether the still-pending request accepted this resolution. + */ + resolveRequestRun(requestId: ApprovalRequestId, resolution: DynamicCordisRunResolution): Promise; + /** + * Settle a direct panel run after this page loaded or failed its Client half. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity being settled. + * @param resolution - Exact Client activation result from the acting page. + * @returns The committed activation or its failure. + */ + settleUserRun(agent: Agent, pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution): Promise; + /** + * Stop the active run while retaining every Package version. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + stop(agent: Agent, pluginId: CordisDynamicPluginId): Promise; + /** + * Stop a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + stopFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise; + /** + * Replace the Host mirror of the Client inspect provider directory. + * @param providers - complete Client provider manifest. + * @returns null after accepting the manifest. + */ + syncInspectManifest(providers: readonly CordisInspectProviderManifest[]): null; + /** + * Claim one pending Client inspect query with its live result. + * @param agent - Session that owns the query. + * @param requestId - exact pending query identity. + * @param resolution - provider result or structured refusal. + * @returns whether this answer won the query. + */ + resolveInspectQuery(agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution): CordisInspectResolveAck; + /** + * Frame-wide inventory, grouped as one row per stable Plugin. + * @returns Source-free metadata for every process-local Plugin. + */ + inventory(): DynamicCordisInventoryRow[]; + /** + * Read one Session's Host-rich state for inspection and result rendering. + * @param agent - Agent whose Session selects visible Plugins. + * @returns Plugin versions, active runs, Host fibers, and render failures. + */ + snapshot(agent: Agent): DynamicCordisSnapshotRow[]; + /** + * Read source-free context for an explicit `@pluginId` user gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity referenced by the user. + * @returns The preferred modification base, or undefined when unavailable. + */ + reference(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisReference | undefined; + /** + * List source-free Plugin summaries owned by one Session. + * @param agent - Agent whose Session selects visible Plugins. + * @returns one summary per Plugin in creation order. + */ + listPlugins(agent: Agent): DynamicCordisPluginInspection[]; + /** + * Inspect one Plugin without returning Package source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - stable Plugin identity. + * @returns version pointers, latest run, and all Package summaries. + */ + inspectPlugin(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisPluginInspection; + /** + * Read one exact immutable Package and its Host and Client source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that owns the Package. + * @param packageId - Exact immutable Package identity to inspect. + * @returns Package metadata, source, and the Plugin's lifecycle pointers. + */ + inspectPackage(agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId): DynamicCordisPackageInspection; + /** + * Record a post-load render failure for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that rendered. + * @param pluginRunId - Exact active run that produced the failure. + * @param failure - Slot, message, and entry-retirement result. + * @returns Null after recording or ignoring a stale report. + */ + reportRenderFailure(agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure): Promise; + /** + * Report a Client guard rejection that happened after the Package completed activation. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity whose Client code was rejected. + * @param pluginRunId - Exact active run that produced the rejection. + * @param failure - Original guard message and stack. + * @returns Null after reporting or ignoring a stale/startup failure. + */ + reportClientGuardFailure(agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails): Promise; + /** + * Invoke an active Host method while rejecting stale Client runs. + * @param pluginId - Stable Plugin identity that owns the method. + * @param pluginRunId - Exact active run authorizing the call. + * @param method - Registered Host handler name. + * @param args - JSON argument delivered to the handler. + * @returns The JSON result or a typed invocation failure. + */ + invoke(pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, method: string, args: JsonValue): Promise; + private resolvePlan; + private activate; + private startFresh; + private startHost; + private settleActivation; + private commitActivation; + private runResponse; + private announceResolved; + private steerRunOutcome; + private steerRenderFailure; + private steerHostHandlerFailure; + private steerGuardFailure; + private claimRuntimeFailure; + private injectUserRunOutcome; + private injectUserContext; + private cancelPending; + private createAttempt; + private failAttempt; + private diagnostic; + private retract; + private owned; + private requireGroup; +} +export default DynamicCordisRunnerService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.js new file mode 100644 index 0000000..8894191 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/index.js @@ -0,0 +1,1151 @@ +/** + * Dynamic Cordis Plugin service: immutable package definitions, one active run + * per Plugin, human-approved Client activation, and Host/Client invocation. + * @module @deepseek-ai/dsh-cordis-host-runner + */ +var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; +var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +import z from '@deepseek-ai/schemastery'; +import { createUserMessage } from '@deepseek-ai/dsh-llm'; +import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'; +import { isPlugin, normalizeHandler } from "./guard.js"; +import { CordisInspectRegistryService } from "./inspect-registry.js"; +import { missingServices, startHostHalf } from "./lifecycle.js"; +import { DynamicCordisRegistry } from "./registry.js"; +import { createSandbox, evaluateHostCode, precheckCode } from "./sandbox.js"; +export { CordisInspectRegistryService } from "./inspect-registry.js"; +export { HOST_BUILTIN_INSPECTION } from "./sandbox.js"; +/** + * Brand a Host-minted Plugin ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Plugin identifier. + */ +export function CordisDynamicPluginId(id) { + return id; +} +/** + * Brand a Host-minted Package ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Package identifier. + */ +export function CordisDynamicPackageId(id) { + return id; +} +/** + * Brand a Host-minted Plugin Run ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded Plugin Run identifier. + */ +export function CordisDynamicPluginRunId(id) { + return id; +} +/** + * Brand a Host-minted approval request ID. + * @param id - opaque identifier minted by the Host registry. + * @returns the branded approval request identifier. + */ +export function ApprovalRequestId(id) { + return id; +} +/** Dynamic Plugin registry and Host-half lifecycle. */ +let DynamicCordisRunnerService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _undefineFromPanel_decorators; + let _runHostHalf_decorators; + let _getClientCode_decorators; + let _resolveRequestRun_decorators; + let _settleUserRun_decorators; + let _stopFromPanel_decorators; + let _syncInspectManifest_decorators; + let _resolveInspectQuery_decorators; + let _inventory_decorators; + let _reportRenderFailure_decorators; + let _reportClientGuardFailure_decorators; + let _invoke_decorators; + return class DynamicCordisRunnerService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _undefineFromPanel_decorators = [Remote('undefineFromPanel')]; + _runHostHalf_decorators = [Remote('runHostHalf')]; + _getClientCode_decorators = [Remote('getClientCode')]; + _resolveRequestRun_decorators = [Remote('resolveRequestRun')]; + _settleUserRun_decorators = [Remote('settleUserRun')]; + _stopFromPanel_decorators = [Remote('stopFromPanel')]; + _syncInspectManifest_decorators = [Remote('syncInspectManifest')]; + _resolveInspectQuery_decorators = [Remote('resolveInspectQuery')]; + _inventory_decorators = [Remote('inventory')]; + _reportRenderFailure_decorators = [Remote('reportRenderFailure')]; + _reportClientGuardFailure_decorators = [Remote('reportClientGuardFailure')]; + _invoke_decorators = [Remote('invoke')]; + __esDecorate(this, null, _undefineFromPanel_decorators, { kind: "method", name: "undefineFromPanel", static: false, private: false, access: { has: obj => "undefineFromPanel" in obj, get: obj => obj.undefineFromPanel }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _runHostHalf_decorators, { kind: "method", name: "runHostHalf", static: false, private: false, access: { has: obj => "runHostHalf" in obj, get: obj => obj.runHostHalf }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _getClientCode_decorators, { kind: "method", name: "getClientCode", static: false, private: false, access: { has: obj => "getClientCode" in obj, get: obj => obj.getClientCode }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resolveRequestRun_decorators, { kind: "method", name: "resolveRequestRun", static: false, private: false, access: { has: obj => "resolveRequestRun" in obj, get: obj => obj.resolveRequestRun }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _settleUserRun_decorators, { kind: "method", name: "settleUserRun", static: false, private: false, access: { has: obj => "settleUserRun" in obj, get: obj => obj.settleUserRun }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _stopFromPanel_decorators, { kind: "method", name: "stopFromPanel", static: false, private: false, access: { has: obj => "stopFromPanel" in obj, get: obj => obj.stopFromPanel }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _syncInspectManifest_decorators, { kind: "method", name: "syncInspectManifest", static: false, private: false, access: { has: obj => "syncInspectManifest" in obj, get: obj => obj.syncInspectManifest }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resolveInspectQuery_decorators, { kind: "method", name: "resolveInspectQuery", static: false, private: false, access: { has: obj => "resolveInspectQuery" in obj, get: obj => obj.resolveInspectQuery }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _inventory_decorators, { kind: "method", name: "inventory", static: false, private: false, access: { has: obj => "inventory" in obj, get: obj => obj.inventory }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _reportRenderFailure_decorators, { kind: "method", name: "reportRenderFailure", static: false, private: false, access: { has: obj => "reportRenderFailure" in obj, get: obj => obj.reportRenderFailure }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _reportClientGuardFailure_decorators, { kind: "method", name: "reportClientGuardFailure", static: false, private: false, access: { has: obj => "reportClientGuardFailure" in obj, get: obj => obj.reportClientGuardFailure }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _invoke_decorators, { kind: "method", name: "invoke", static: false, private: false, access: { has: obj => "invoke" in obj, get: obj => obj.invoke }, metadata: _metadata }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + static inject = ['tools']; + static Config = z.object({ + vmTimeoutMs: z.number().min(1).default(5000), + }); + rootCtx = __runInitializers(this, _instanceExtraInitializers); + registry = new DynamicCordisRegistry(); + inspectRegistry; + starting = new Map(); + resolved; + group; + /** Create the service under the Host composition. */ + constructor(ctx, config) { + super(ctx, 'dynamicCordisRunner'); + this.rootCtx = ctx; + this.resolved = config; + this.inspectRegistry = new CordisInspectRegistryService(ctx); + } + /** + * Define a new Plugin's first Package or append a Package to an existing Plugin. + * @param request - Session ownership, Plugin selection, metadata, and source code. + * @returns Host-minted Plugin and Package identities with declared-half metadata. + */ + define(request) { + const name = request.name.trim(); + const purpose = request.purpose.trim(); + if (name.length === 0) + throw new Error('cordis_define needs a non-empty `name`'); + if (purpose.length === 0) + throw new Error('cordis_define needs a non-empty `purpose`'); + if (request.code.host === undefined && request.code.client === undefined) { + throw new Error('cordis_define needs `code.host`, `code.client`, or both'); + } + if (request.code.host !== undefined) + precheckCode(request.code.host, 'code.host'); + if (request.code.client !== undefined) + precheckCode(request.code.client, 'code.client'); + let plugin; + if (request.plugin.kind === 'new') { + const prefix = request.plugin.idPrefix.trim(); + if (!/^[a-z]{3,6}$/.test(prefix)) { + throw new Error('cordis_define `plugin.idPrefix` must contain 3–6 lowercase English letters'); + } + const pluginId = CordisDynamicPluginId(this.registry.mintPluginId(prefix)); + plugin = { + pluginId, + sessionId: request.sessionId, + packages: new Map(), + approvedClientPackages: new Set(), + clientVersionUpdatesApproved: false, + }; + this.registry.add(plugin); + } + else { + const found = this.registry.get(request.plugin.pluginId); + if (found === undefined || found.sessionId !== request.sessionId) { + throw new Error(missingPluginMessage(request.plugin.pluginId)); + } + plugin = found; + } + const packageId = CordisDynamicPackageId(this.registry.mintPackageId()); + const definition = { + packageId, + name, + purpose, + ...request.code.host === undefined ? {} : { hostCode: request.code.host }, + ...request.code.client === undefined ? {} : { clientCode: request.code.client }, + }; + plugin.packages.set(packageId, definition); + return { + pluginId: plugin.pluginId, + packageId, + name, + purpose, + hasHostHalf: definition.hostCode !== undefined, + hasClientHalf: definition.clientCode !== undefined, + }; + } + /** + * Remove a Plugin, its active run, and all immutable Packages. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + async undefine(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + return { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) }; + const wasRunning = plugin.run !== undefined; + this.cancelPending(pluginId, `dynamic plugin "${pluginId}" was removed before approval`); + if (plugin.run !== undefined) + await this.retract(plugin); + this.registry.delete(pluginId); + return { ok: true, wasRunning }; + } + /** + * Remove a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to remove. + * @returns Whether removal succeeded and whether it stopped an active run. + */ + async undefineFromPanel(agent, pluginId) { + const result = await this.undefine(agent, pluginId); + if (result.ok) { + this.injectUserContext(agent, `The user removed Cordis Plugin ${pluginId} and all of its Packages. The Plugin no longer exists.`); + } + return result; + } + /** + * Start or update one Package for a model tool call. An unauthorized Client + * Package waits for approval; Plugin-wide authorization covers later versions. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param signal - Tool-call cancellation signal while the activation request is being created. + * @returns The successful activation identity or an actionable refusal. + */ + async run(agent, pluginId, packageId, mode, signal) { + const plan = this.resolvePlan(agent, pluginId, packageId, mode); + if (!plan.ok) + return plan.response; + if (signal?.aborted === true) { + return { + ok: false, + reason: 'cancelled', + message: `the run request for dynamic plugin "${pluginId}" was cancelled before activation`, + }; + } + if (this.registry.pendingRequestFor(pluginId) !== undefined) { + return { ok: false, reason: 'transition-in-flight', message: `dynamic plugin "${pluginId}" already has a pending run request` }; + } + const attempt = this.createAttempt(plan); + plan.plugin.nextPackageId = packageId; + plan.plugin.latestRun = attempt; + if (plan.definition.clientCode === undefined) { + const started = await this.activate(plan, undefined, false, attempt); + if (started.ok) + return this.runResponse(plan.plugin, started); + this.failAttempt(plan.plugin, attempt, 'host-load', started); + return { ...started, reason: 'host-half-failed' }; + } + const requestId = ApprovalRequestId(this.registry.mintApprovalRequestId()); + const requiresApproval = !plan.plugin.clientVersionUpdatesApproved + && !plan.plugin.approvedClientPackages.has(packageId); + attempt.approvalRequestId = requestId; + attempt.requiresApproval = requiresApproval; + attempt.status = requiresApproval ? 'awaiting-approval' : 'starting-host'; + this.registry.armRequest(requestId, { + agentId: agent.id, + pluginId, + packageId, + pluginRunId: attempt.pluginRunId, + mode, + requiresApproval, + }); + this.ctx.emit('cordis/request-run', { + requestId, + agentId: agent.id, + pluginId, + packageId, + mode, + name: plan.definition.name, + purpose: plan.definition.purpose, + requiresApproval, + }); + return { + ok: true, + status: requiresApproval ? 'awaiting-approval' : 'starting', + pluginId, + packageId, + pluginRunId: attempt.pluginRunId, + mode, + waitingFor: [], + ...plan.plugin.currentPackageId === undefined ? {} : { currentPackageId: plan.plugin.currentPackageId }, + nextPackageId: packageId, + }; + } + /** + * Start Host code for an approved request or a direct panel gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to activate. + * @param packageId - Immutable Package version to activate. + * @param mode - Whether to run the current version or switch versions. + * @param requestId - Model-driven request identity, or null for a direct user gesture. + * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin. + * @returns The exact Host activation or a failure message. + */ + async runHostHalf(agent, pluginId, packageId, mode, requestId, approveFutureVersions) { + const plan = this.resolvePlan(agent, pluginId, packageId, mode, requestId === null); + if (!plan.ok) + return { ok: false, message: plan.response.message }; + let attempt; + if (requestId !== null) { + const pending = this.registry.peekRequest(requestId); + if (pending === undefined || pending.pluginId !== pluginId || pending.packageId !== packageId || pending.mode !== mode) { + return { ok: false, message: `run request "${requestId}" does not authorize ${pluginId}/${packageId}` }; + } + const latest = plan.plugin.latestRun; + const expectedStatus = pending.requiresApproval ? 'awaiting-approval' : 'starting-host'; + if (latest === undefined || latest.pluginRunId !== pending.pluginRunId + || (latest.status !== expectedStatus && (!pending.requiresApproval && latest.status !== 'client-pending'))) { + return { ok: false, message: `run request "${requestId}" no longer identifies the latest run of ${pluginId}` }; + } + attempt = latest; + if (pending.requiresApproval) { + plan.plugin.approvedClientPackages.add(packageId); + if (approveFutureVersions) + plan.plugin.clientVersionUpdatesApproved = true; + } + } + else { + const pending = this.registry.pendingRequestFor(pluginId); + if (pending !== undefined) + return { ok: false, message: `dynamic plugin "${pluginId}" has pending run request ${pending}` }; + const attached = plan.plugin.run?.packageId === packageId + && plan.plugin.latestRun?.pluginRunId === plan.plugin.run.pluginRunId + ? plan.plugin.latestRun + : undefined; + attempt = attached ?? this.createAttempt(plan); + if (attached === undefined) { + plan.plugin.nextPackageId = packageId; + plan.plugin.latestRun = attempt; + } + if (plan.definition.clientCode !== undefined) + plan.plugin.approvedClientPackages.add(packageId); + } + const attaching = attempt.pluginRunId === plan.plugin.run?.pluginRunId; + if (!attaching) { + attempt.status = 'starting-host'; + if (attempt.host.status !== 'absent') + attempt.host = { status: 'pending', waitingFor: [] }; + } + const started = await this.activate(plan, requestId ?? undefined, attaching, attempt); + if (!started.ok) + this.failAttempt(plan.plugin, attempt, 'host-load', started); + return started; + } + /** + * Fetch Client code for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to read. + * @param pluginRunId - Exact active run authorized to receive source. + * @returns Client source and its Plugin, Package, and run identities. + */ + getClientCode(agent, pluginId, pluginRunId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + throw new Error(missingPluginMessage(pluginId)); + const run = plugin.run; + if (run === undefined || run.pluginRunId !== pluginRunId) { + throw new Error(`dynamic plugin "${pluginId}" is not running activation "${pluginRunId}"`); + } + const definition = plugin.packages.get(run.packageId); + if (definition?.clientCode === undefined) + throw new Error(`package "${run.packageId}" has no Client half`); + return { + code: definition.clientCode, + name: definition.name, + pluginId, + packageId: run.packageId, + pluginRunId, + }; + } + /** + * Resolve one model-driven Client activation request. + * @param requestId - Request identity to settle once. + * @param resolution - Browser refusal or exact Client activation result. + * @returns Whether the still-pending request accepted this resolution. + */ + async resolveRequestRun(requestId, resolution) { + const pending = this.registry.peekRequest(requestId); + if (pending === undefined) + return { accepted: false }; + const plugin = this.registry.get(pending.pluginId); + if (resolution.ok && plugin?.run?.pluginRunId !== resolution.pluginRunId) + return { accepted: false }; + if (!resolution.ok && resolution.pluginRunId !== undefined + && plugin?.run?.pluginRunId !== resolution.pluginRunId) + return { accepted: false }; + this.registry.claimRequest(requestId); + const settled = await this.settleActivation(plugin, resolution, requestId); + this.announceResolved(requestId, resolution, pending.requiresApproval ? undefined : 'completed'); + this.steerRunOutcome(pending, settled); + return { accepted: true }; + } + /** + * Settle a direct panel run after this page loaded or failed its Client half. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity being settled. + * @param resolution - Exact Client activation result from the acting page. + * @returns The committed activation or its failure. + */ + async settleUserRun(agent, pluginId, resolution) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + return { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) }; + const settled = await this.settleActivation(plugin, resolution); + this.injectUserRunOutcome(agent, pluginId, settled); + return settled; + } + /** + * Stop the active run while retaining every Package version. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + async stop(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + return { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) }; + const pending = this.registry.pendingRequestFor(pluginId); + if (plugin.run === undefined && pending === undefined) { + return { ok: false, reason: 'not-running', message: `dynamic plugin "${pluginId}" is not running` }; + } + if (pending !== undefined) + this.cancelPending(pluginId, `dynamic plugin "${pluginId}" was stopped before approval`); + if (plugin.run !== undefined) + await this.retract(plugin); + if (plugin.latestRun !== undefined) { + plugin.latestRun.status = 'stopped'; + if (plugin.latestRun.host.status !== 'absent') + plugin.latestRun.host = { status: 'stopped', waitingFor: [] }; + if (plugin.latestRun.client.status !== 'absent') + plugin.latestRun.client = { status: 'stopped', waitingFor: [] }; + } + return { ok: true }; + } + /** + * Stop a Plugin from the user panel and queue the resulting state change for the model's next step. + * @param agent - Agent whose Session owns the Plugin and receives the context. + * @param pluginId - Stable Plugin identity to stop. + * @returns Success or the reason no run was stopped. + */ + async stopFromPanel(agent, pluginId) { + const result = await this.stop(agent, pluginId); + if (!result.ok) + return result; + const plugin = this.owned(agent, pluginId); + this.injectUserContext(agent, `The user stopped Cordis Plugin ${pluginId}. Its Packages remain defined; currentPackageId is ` + + `${plugin?.currentPackageId ?? 'none'}.`); + return result; + } + /** + * Replace the Host mirror of the Client inspect provider directory. + * @param providers - complete Client provider manifest. + * @returns null after accepting the manifest. + */ + syncInspectManifest(providers) { + this.inspectRegistry.syncClientManifest(providers); + return null; + } + /** + * Claim one pending Client inspect query with its live result. + * @param agent - Session that owns the query. + * @param requestId - exact pending query identity. + * @param resolution - provider result or structured refusal. + * @returns whether this answer won the query. + */ + resolveInspectQuery(agent, requestId, resolution) { + return this.inspectRegistry.resolveClientQuery(agent, requestId, resolution); + } + /** + * Frame-wide inventory, grouped as one row per stable Plugin. + * @returns Source-free metadata for every process-local Plugin. + */ + /* jscpd:ignore-start */ + inventory() { + return this.registry.all().map(plugin => ({ + pluginId: plugin.pluginId, + agentId: plugin.sessionId, + packages: [...plugin.packages.values()].map(definition => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== undefined, + hasClientHalf: definition.clientCode !== undefined, + })), + ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === undefined ? {} : { + activeRun: { pluginRunId: plugin.run.pluginRunId, packageId: plugin.run.packageId }, + }, + ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) }, + })); + } + /* jscpd:ignore-end */ + /** + * Read one Session's Host-rich state for inspection and result rendering. + * @param agent - Agent whose Session selects visible Plugins. + * @returns Plugin versions, active runs, Host fibers, and render failures. + */ + snapshot(agent) { + return this.registry.ofSession(agent.id).map(plugin => ({ + pluginId: plugin.pluginId, + ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId }, + packages: [...plugin.packages.values()].map(definition => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== undefined, + hasClientHalf: definition.clientCode !== undefined, + })), + ...plugin.run === undefined ? {} : { + activeRun: { + pluginRunId: plugin.run.pluginRunId, + packageId: plugin.run.packageId, + ...plugin.run.fiber === undefined ? {} : { fiber: plugin.run.fiber }, + handlers: [...plugin.run.handlers.keys()], + ...plugin.run.renderFailure === undefined ? {} : { renderFailure: plugin.run.renderFailure }, + }, + }, + ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) }, + })); + } + /** + * Read source-free context for an explicit `@pluginId` user gesture. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity referenced by the user. + * @returns The preferred modification base, or undefined when unavailable. + */ + reference(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + return undefined; + const packageId = plugin.nextPackageId + ?? plugin.currentPackageId + ?? [...plugin.packages.keys()].at(-1); + if (packageId === undefined) + return undefined; + const definition = plugin.packages.get(packageId); + if (definition === undefined) + return undefined; + return { + pluginId, + packageId, + name: definition.name, + purpose: definition.purpose, + ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === undefined ? {} : { + activeRun: { pluginRunId: plugin.run.pluginRunId, packageId: plugin.run.packageId }, + }, + ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) }, + }; + } + /** + * List source-free Plugin summaries owned by one Session. + * @param agent - Agent whose Session selects visible Plugins. + * @returns one summary per Plugin in creation order. + */ + listPlugins(agent) { + return this.registry.ofSession(agent.id).map(plugin => this.inspectPlugin(agent, plugin.pluginId)); + } + /** + * Inspect one Plugin without returning Package source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - stable Plugin identity. + * @returns version pointers, latest run, and all Package summaries. + */ + inspectPlugin(agent, pluginId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + throw new Error(missingPluginMessage(pluginId)); + const reference = this.reference(agent, pluginId); + if (reference === undefined) + throw new Error(`dynamic plugin "${pluginId}" has no package`); + return { + ...reference, + packages: [...plugin.packages.values()].map(definition => ({ + packageId: definition.packageId, + name: definition.name, + purpose: definition.purpose, + hasHostHalf: definition.hostCode !== undefined, + hasClientHalf: definition.clientCode !== undefined, + })), + }; + } + /** + * Read one exact immutable Package and its Host and Client source. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that owns the Package. + * @param packageId - Exact immutable Package identity to inspect. + * @returns Package metadata, source, and the Plugin's lifecycle pointers. + */ + inspectPackage(agent, pluginId, packageId) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + throw new Error(missingPluginMessage(pluginId)); + const definition = plugin.packages.get(packageId); + if (definition === undefined) { + throw new Error(`dynamic package "${packageId}" does not exist on plugin "${pluginId}"`); + } + return { + pluginId, + packageId, + name: definition.name, + purpose: definition.purpose, + code: { + ...definition.hostCode === undefined ? {} : { host: definition.hostCode }, + ...definition.clientCode === undefined ? {} : { client: definition.clientCode }, + }, + /* jscpd:ignore-start */ + ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId }, + ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId }, + ...plugin.run === undefined ? {} : { + activeRun: { pluginRunId: plugin.run.pluginRunId, packageId: plugin.run.packageId }, + }, + ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) }, + /* jscpd:ignore-end */ + }; + } + /** + * Record a post-load render failure for the exact active run. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity that rendered. + * @param pluginRunId - Exact active run that produced the failure. + * @param failure - Slot, message, and entry-retirement result. + * @returns Null after recording or ignoring a stale report. + */ + async reportRenderFailure(agent, pluginId, pluginRunId, failure) { + const plugin = this.owned(agent, pluginId); + if (plugin?.run?.pluginRunId === pluginRunId) { + const run = plugin.run; + const definition = plugin.packages.get(plugin.run.packageId); + const shouldSteer = run.renderFailure === undefined; + run.renderFailure = failure; + const attempt = plugin.latestRun; + if (attempt?.pluginRunId === pluginRunId) { + attempt.error = this.diagnostic(plugin, attempt, 'client-render', failure); + attempt.client = { status: 'failed', waitingFor: attempt.client.waitingFor, error: failure.message }; + attempt.status = 'failed'; + } + if (definition !== undefined && shouldSteer) { + this.steerRenderFailure(agent, plugin, definition, pluginRunId, failure); + } + } + return await Promise.resolve(null); + } + /** + * Report a Client guard rejection that happened after the Package completed activation. + * @param agent - Agent whose Session must own the Plugin. + * @param pluginId - Stable Plugin identity whose Client code was rejected. + * @param pluginRunId - Exact active run that produced the rejection. + * @param failure - Original guard message and stack. + * @returns Null after reporting or ignoring a stale/startup failure. + */ + async reportClientGuardFailure(agent, pluginId, pluginRunId, failure) { + const plugin = this.owned(agent, pluginId); + const run = plugin?.run; + if (plugin !== undefined && run?.pluginRunId === pluginRunId) { + this.steerGuardFailure(plugin, run, 'Client', failure); + } + return await Promise.resolve(null); + } + /** + * Invoke an active Host method while rejecting stale Client runs. + * @param pluginId - Stable Plugin identity that owns the method. + * @param pluginRunId - Exact active run authorizing the call. + * @param method - Registered Host handler name. + * @param args - JSON argument delivered to the handler. + * @returns The JSON result or a typed invocation failure. + */ + async invoke(pluginId, pluginRunId, method, args) { + const plugin = this.registry.get(pluginId); + if (plugin === undefined || plugin.run === undefined) { + return { ok: false, code: 'plugin-not-running', message: `dynamic plugin "${pluginId}" is not running` }; + } + const run = plugin.run; + if (run.pluginRunId !== pluginRunId) { + return { ok: false, code: 'stale-run', message: `activation "${pluginRunId}" is no longer active` }; + } + const handler = run.handlers.get(method); + if (handler === undefined) { + return { ok: false, code: 'method-not-found', message: `dynamic plugin "${pluginId}" registered no Host method "${method}"` }; + } + try { + return { ok: true, value: await handler(args) }; + } + catch (error) { + const failure = errorDetails(error); + this.steerHostHandlerFailure(plugin, run, method, failure); + return { ok: false, code: 'handler-error', ...failure }; + } + } + resolvePlan(agent, pluginId, packageId, mode, allowActiveAttach = false) { + const plugin = this.owned(agent, pluginId); + if (plugin === undefined) + return { ok: false, response: { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) } }; + const definition = plugin.packages.get(packageId); + if (definition === undefined) { + return { ok: false, response: { ok: false, reason: 'package-missing', message: `plugin "${pluginId}" has no package "${packageId}"` } }; + } + const current = plugin.currentPackageId; + if (mode === 'update' && (current === undefined || current === packageId)) { + return { + ok: false, + response: { + ok: false, + reason: 'invalid-mode', + message: current === undefined + ? `plugin "${pluginId}" has no successful version yet; start "${packageId}" with mode "run"` + : `package "${packageId}" is already current; use mode "run"`, + }, + }; + } + if (mode === 'run' && current !== undefined && current !== packageId) { + return { + ok: false, + response: { + ok: false, + reason: 'invalid-mode', + message: `package "${packageId}" differs from current "${current}"; use mode "update"`, + }, + }; + } + if (!allowActiveAttach && this.starting.has(pluginId)) { + return { ok: false, response: { ok: false, reason: 'transition-in-flight', message: `plugin "${pluginId}" is already starting` } }; + } + return { ok: true, plugin, definition, mode }; + } + activate(plan, requestId, allowActiveAttach, attempt) { + const inFlight = this.starting.get(plan.plugin.pluginId); + if (inFlight !== undefined) + return inFlight; + const starting = this.startFresh(plan, requestId, allowActiveAttach, attempt); + this.starting.set(plan.plugin.pluginId, starting); + return starting.finally(() => { this.starting.delete(plan.plugin.pluginId); }); + } + async startFresh(plan, requestId, allowActiveAttach, attempt) { + const { plugin, definition, mode } = plan; + if (allowActiveAttach + && plugin.run?.packageId === definition.packageId + && plugin.run.pluginRunId === attempt.pluginRunId) { + return { + ok: true, + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: plugin.run.pluginRunId, + waitingFor: missingFor(this.ctx, plugin.run), + startedHere: false, + }; + } + if (plugin.run !== undefined) + await this.retract(plugin); + if (mode === 'update' || plugin.currentPackageId === undefined) + plugin.nextPackageId = definition.packageId; + const run = { + pluginRunId: attempt.pluginRunId, + packageId: definition.packageId, + handlers: new Map(), + handlerDisposers: [], + reportedRuntimeErrors: new Set(), + ...requestId === undefined ? {} : { startedForRequest: requestId }, + }; + if (definition.hostCode !== undefined) { + const failure = await this.startHost(plugin, definition.hostCode, run); + if (failure !== undefined) + return { ok: false, ...failure }; + } + plugin.run = run; + this.ctx.emit('cordis/dynamic-package', { + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: run.pluginRunId, + name: definition.name, + }); + attempt.host = { + status: run.fiber === undefined ? 'absent' : missingFor(this.ctx, run).length === 0 ? 'running' : 'waiting', + waitingFor: missingFor(this.ctx, run), + }; + if (definition.clientCode === undefined) { + this.commitActivation(plugin, run); + } + else { + attempt.status = 'client-pending'; + attempt.client = { status: 'pending', waitingFor: [] }; + } + return { + ok: true, + pluginId: plugin.pluginId, + packageId: definition.packageId, + pluginRunId: run.pluginRunId, + waitingFor: missingFor(this.ctx, run), + startedHere: true, + }; + } + async startHost(plugin, hostCode, run) { + const handle = (method, fn) => { + const normalized = normalizeHandler(method, fn); + run.handlers.set(normalized.method, normalized.handler); + const dispose = () => { + if (run.handlers.get(normalized.method) === normalized.handler) + run.handlers.delete(normalized.method); + }; + run.handlerDisposers.push(dispose); + return dispose; + }; + try { + const sandbox = createSandbox(plugin.pluginId, { handle }); + const evaluated = await evaluateHostCode(sandbox, hostCode, plugin.pluginId, this.resolved.vmTimeoutMs); + if (!isPlugin(evaluated)) { + throw new Error(evaluated === undefined + ? 'the Host half returned `undefined` — did you forget `return`?' + : 'the Host half must return a Plugin function or an object with apply(ctx)'); + } + run.fiber = await startHostHalf(this.requireGroup(), evaluated, (error) => { this.steerGuardFailure(plugin, run, 'Host', errorDetails(error)); }); + return undefined; + } + catch (error) { + for (const dispose of run.handlerDisposers.splice(0)) + dispose(); + return errorDetails(error); + } + } + async settleActivation(plugin, resolution, requestId) { + if (plugin === undefined) + return { ok: false, reason: 'plugin-missing', message: 'the dynamic plugin was removed during activation' }; + const attempt = plugin.latestRun; + if (!resolution.ok) { + if (resolution.reason === 'rejected') { + if (attempt !== undefined) { + attempt.status = 'rejected'; + attempt.error = this.diagnostic(plugin, attempt, 'approval', resolution.message ?? 'the run request was declined'); + attempt.client = { status: 'stopped', waitingFor: [] }; + } + return { ok: false, reason: 'rejected', message: resolution.message ?? 'the run request was declined' }; + } + const run = plugin.run; + const ownsRun = run !== undefined + && resolution.pluginRunId === run.pluginRunId + && (requestId === undefined || run.startedForRequest === requestId) + && resolution.startedHere !== false; + if (ownsRun) + await this.retract(plugin); + if (attempt !== undefined && (resolution.pluginRunId === undefined || attempt.pluginRunId === resolution.pluginRunId)) { + this.failAttempt(plugin, attempt, resolution.reason === 'host-half-failed' ? 'host-apply' : 'client-apply', { + message: resolution.message ?? resolution.reason, + ...resolution.stack === undefined ? {} : { stack: resolution.stack }, + }); + } + return { + ok: false, + reason: resolution.reason, + message: resolution.message ?? resolution.reason, + ...resolution.stack === undefined ? {} : { stack: resolution.stack }, + }; + } + const run = plugin.run; + if (run === undefined || run.pluginRunId !== resolution.pluginRunId) { + return { ok: false, reason: 'client-half-failed', message: `activation "${resolution.pluginRunId}" is no longer active` }; + } + if (attempt !== undefined && attempt.pluginRunId === run.pluginRunId) { + attempt.client = { + status: resolution.waitingFor === undefined || resolution.waitingFor.length === 0 ? 'running' : 'waiting', + waitingFor: resolution.waitingFor ?? [], + }; + } + this.commitActivation(plugin, run); + return { + ...this.runResponse(plugin, { + ok: true, + pluginId: plugin.pluginId, + packageId: run.packageId, + pluginRunId: run.pluginRunId, + waitingFor: missingFor(this.ctx, run), + startedHere: false, + }), + ...resolution.waitingFor === undefined ? {} : { clientWaitingFor: resolution.waitingFor }, + }; + } + commitActivation(plugin, run) { + plugin.currentPackageId = run.packageId; + delete plugin.nextPackageId; + delete run.startedForRequest; + const attempt = plugin.latestRun; + if (attempt?.pluginRunId === run.pluginRunId) { + attempt.status = attempt.host.status === 'waiting' || attempt.client.status === 'waiting' ? 'waiting' : 'running'; + delete attempt.approvalRequestId; + delete attempt.requiresApproval; + delete attempt.error; + } + } + runResponse(plugin, started) { + return { + ok: true, + status: 'running', + pluginId: plugin.pluginId, + packageId: started.packageId, + pluginRunId: started.pluginRunId, + waitingFor: started.waitingFor, + currentPackageId: started.packageId, + mode: plugin.latestRun?.pluginRunId === started.pluginRunId ? plugin.latestRun.mode : 'run', + }; + } + announceResolved(requestId, resolution, override) { + const outcome = override ?? (resolution.ok ? 'approved' : resolution.reason === 'rejected' ? 'rejected' : 'failed'); + this.ctx.emit('cordis/request-run-resolved', { requestId, outcome }); + } + steerRunOutcome(pending, settled) { + const agents = this.rootCtx.get('agents'); + const agent = agents?.get(pending.agentId); + if (agent === undefined) + return; + const plugin = this.registry.get(pending.pluginId); + const identity = `${pending.pluginId}/${pending.packageId} (${pending.pluginRunId})`; + let text; + if (settled.ok) { + text = `Cordis ${pending.mode} ${identity} completed successfully. ` + + `currentPackageId is ${settled.currentPackageId ?? pending.packageId}. Continue using the running Plugin.`; + } + else if (settled.reason === 'rejected') { + text = `The user rejected Cordis ${pending.mode} ${identity}. ` + + 'Do not request the same activation again unless the user asks.'; + } + else { + const returnedStatus = pending.requiresApproval ? 'awaiting-approval' : 'starting'; + text = `Cordis ${pending.mode} ${identity} failed after cordis_run returned ${returnedStatus}: ` + + `${settled.reason}\n${formatErrorDetails(settled)}\n` + + `currentPackageId: ${plugin?.currentPackageId ?? 'none'}\n` + + `nextPackageId: ${plugin?.nextPackageId ?? pending.packageId}\n` + + 'Inspect the failed Package, correct it on the same Plugin when needed, and retry the activation autonomously.'; + } + agent.steer(createUserMessage({ + content: [{ type: 'text', text }], + source: { kind: 'plugin', plugin: 'cordis-host-runner' }, + })); + } + steerRenderFailure(agent, plugin, definition, pluginRunId, failure) { + agent.steer(createUserMessage({ + content: [{ + type: 'text', + text: `Cordis Client UI ${plugin.pluginId}/${definition.packageId} (${pluginRunId}) failed while rendering ` + + `Slot "${failure.slot}" after activation.\n` + + `${formatErrorDetails(failure)}\n` + + `entryAbdicated: ${failure.abdicated}\n` + + 'Inspect the failed Package, fix the Client code by defining a new Package on the same Plugin, and ' + + 'activate that Package autonomously with cordis_run mode:"update".', + }], + source: { kind: 'plugin', plugin: 'cordis-host-runner' }, + })); + } + steerHostHandlerFailure(plugin, run, method, failure) { + const reportKey = `Host\u0000handler\u0000${method}\u0000${failure.message}`; + if (!this.claimRuntimeFailure(plugin, run, reportKey)) + return; + const agents = this.rootCtx.get('agents'); + const agent = agents?.get(plugin.sessionId); + if (agent === undefined) + return; + agent.steer(createUserMessage({ + content: [{ + type: 'text', + text: `Cordis Host handler ${plugin.pluginId}/${run.packageId} (${run.pluginRunId}) failed when the Client called ` + + `host.call(${JSON.stringify(method)}).\n` + + `${formatErrorDetails(failure)}\n` + + 'The Plugin remains running. Inspect this Package, correct the Host code on the same Plugin, and activate ' + + 'the new Package autonomously with cordis_run mode:"update". If the handler needs a Service, either declare ' + + 'that Service in the returned Plugin inject list or read it with ctx.get(name) and handle undefined.', + }], + source: { kind: 'plugin', plugin: 'cordis-host-runner' }, + })); + } + /* jscpd:ignore-start */ + steerGuardFailure(plugin, run, platform, failure) { + const reportKey = `${platform}\u0000guard\u0000${failure.message}`; + if (!this.claimRuntimeFailure(plugin, run, reportKey)) + return; + const agents = this.rootCtx.get('agents'); + const agent = agents?.get(plugin.sessionId); + if (agent === undefined) + return; + agent.steer(createUserMessage({ + content: [{ + type: 'text', + text: `Cordis ${platform} guard rejected runtime code in ${plugin.pluginId}/${run.packageId} ` + + `(${run.pluginRunId}) after activation.\n${formatErrorDetails(failure)}\n` + + 'The Plugin remains running. Inspect this Package, define a corrected Package on the same Plugin, and ' + + 'activate it autonomously with cordis_run mode:"update".', + }], + source: { kind: 'plugin', plugin: 'cordis-host-runner' }, + })); + } + /* jscpd:ignore-end */ + claimRuntimeFailure(plugin, run, key) { + const attempt = plugin.latestRun; + if (plugin.run !== run || attempt?.pluginRunId !== run.pluginRunId + || (attempt.status !== 'running' && attempt.status !== 'waiting')) + return false; + if (run.reportedRuntimeErrors.has(key)) + return false; + run.reportedRuntimeErrors.add(key); + return true; + } + injectUserRunOutcome(agent, pluginId, settled) { + const plugin = this.owned(agent, pluginId); + let text; + if (settled.ok) { + text = `The user manually ran Cordis Plugin ${pluginId}, Package ${settled.packageId}, ` + + `as ${settled.pluginRunId}. The activation succeeded; currentPackageId is ${settled.currentPackageId}.`; + } + else { + const attempt = plugin?.latestRun; + text = `The user manually ran Cordis Plugin ${pluginId}` + + `${attempt === undefined ? '' : `, Package ${attempt.packageId}, as ${attempt.pluginRunId}`}, but it failed: ` + + `${settled.reason}\n${formatErrorDetails(settled)}\n` + + `currentPackageId: ${plugin?.currentPackageId ?? 'none'}\n` + + `nextPackageId: ${plugin?.nextPackageId ?? 'none'}`; + } + this.injectUserContext(agent, text); + } + injectUserContext(agent, text) { + const agents = this.rootCtx.get('agents'); + if (agents?.get(agent.id) !== agent) + return; + agent.inject(createUserMessage({ + content: [{ type: 'text', text }], + source: { kind: 'plugin', plugin: 'cordis-host-runner' }, + })); + } + cancelPending(pluginId, message) { + const requestId = this.registry.pendingRequestFor(pluginId); + if (requestId === undefined) + return; + const pending = this.registry.claimRequest(requestId); + if (pending === undefined) + return; + const plugin = this.registry.get(pluginId); + if (plugin?.latestRun?.pluginRunId === pending.pluginRunId) { + plugin.latestRun.status = 'cancelled'; + plugin.latestRun.error = this.diagnostic(plugin, plugin.latestRun, 'approval', message); + delete plugin.latestRun.approvalRequestId; + delete plugin.latestRun.requiresApproval; + } + this.announceResolved(requestId, { ok: false, reason: 'rejected' }, 'cancelled'); + } + createAttempt(plan) { + return { + pluginRunId: CordisDynamicPluginRunId(this.registry.mintPluginRunId()), + packageId: plan.definition.packageId, + mode: plan.mode, + status: 'starting-host', + host: { + status: plan.definition.hostCode === undefined ? 'absent' : 'pending', + waitingFor: [], + }, + client: { + status: plan.definition.clientCode === undefined ? 'absent' : 'pending', + waitingFor: [], + }, + }; + } + failAttempt(plugin, attempt, phase, failure) { + attempt.status = 'failed'; + attempt.error = this.diagnostic(plugin, attempt, phase, failure); + if (phase.startsWith('host')) + attempt.host = { status: 'failed', waitingFor: [], error: failure.message }; + else + attempt.client = { status: 'failed', waitingFor: [], error: failure.message }; + } + diagnostic(plugin, attempt, phase, failure) { + const details = typeof failure === 'string' ? { message: failure } : failure; + return { + phase, + ...details, + pluginId: plugin.pluginId, + packageId: attempt.packageId, + pluginRunId: attempt.pluginRunId, + }; + } + async retract(plugin) { + const run = plugin.run; + if (run === undefined) + return; + delete plugin.run; + for (const dispose of run.handlerDisposers.splice(0)) + dispose(); + if (run.fiber !== undefined) + await run.fiber.dispose(); + this.ctx.emit('cordis/dynamic-retract', { + pluginId: plugin.pluginId, + packageId: run.packageId, + pluginRunId: run.pluginRunId, + }); + } + owned(agent, pluginId) { + const plugin = this.registry.get(pluginId); + return plugin?.sessionId === agent.id ? plugin : undefined; + } + requireGroup() { + this.group ??= this.rootCtx.plugin({ name: 'cordis-dynamic', apply: () => { } }); + return this.group; + } + }; +})(); +export { DynamicCordisRunnerService }; +function missingFor(ctx, run) { + return run.fiber === undefined ? [] : missingServices(ctx, run.fiber); +} +function missingPluginMessage(id) { + return `no dynamic plugin "${id}" in this process — it may have been removed or lost on DSH restart`; +} +function errorDetails(error) { + if (typeof error !== 'object' || error === null) + return { message: String(error) }; + const message = 'message' in error && typeof error.message === 'string' + ? error.message + : Object.prototype.toString.call(error); + const stack = 'stack' in error && typeof error.stack === 'string' ? error.stack : undefined; + return { message, ...stack === undefined ? {} : { stack } }; +} +function formatErrorDetails(failure) { + return `message: ${failure.message}` + + (failure.stack === undefined ? '' : `\nstack:\n${failure.stack}`); +} +function cloneAttempt(attempt) { + return { + ...attempt, + host: { ...attempt.host, waitingFor: [...attempt.host.waitingFor] }, + client: { ...attempt.client, waitingFor: [...attempt.client.waitingFor] }, + ...attempt.error === undefined ? {} : { error: { ...attempt.error } }, + }; +} +export default DynamicCordisRunnerService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.d.ts new file mode 100644 index 0000000..cb382e2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.d.ts @@ -0,0 +1,72 @@ +/** Host registry for model-visible, read-only Cordis capability queries. */ +import { Service } from '@deepseek-ai/cordis'; +import type { Context } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { JsonValue } from '@deepseek-ai/dsh-session/types'; +import type { CordisInspectPlatform, CordisInspectProviderManifest, CordisInspectProviderView, CordisInspectQueryResolution, CordisInspectRequestId, CordisInspectResolveAck } from './types.ts'; +/** Context supplied to a Host inspect query. */ +export interface HostCordisInspectQueryContext { + /** Tool-call cancellation. */ + signal: AbortSignal; + /** Agent whose scoped runtime is being inspected. */ + agent: Agent; +} +/** Local registration paired with its serializable manifest. */ +export interface HostCordisInspectProviderRegistration { + /** Provider and explicit method directory. */ + manifest: CordisInspectProviderManifest; + /** Execute one declared method. */ + query(method: string, input: JsonValue | undefined, context: HostCordisInspectQueryContext): Promise; +} +declare module '@deepseek-ai/cordis' { + interface Context { + /** Host registry for Cordis inspect providers and Client manifest/query routing. */ + cordisInspect: CordisInspectRegistryService; + } +} +/** Registry and cross-page router behind the two model-facing inspect tools. */ +export declare class CordisInspectRegistryService extends Service { + private readonly providers; + private readonly pending; + private clientManifest; + private nextRequest; + /** Register the process-global Host registry. */ + constructor(ctx: Context); + /** + * Register one Host provider. + * @param registration - manifest and local query handler. + * @returns idempotent disposer. + */ + register(registration: HostCordisInspectProviderRegistration): () => void; + /** + * Replace the mirrored Client provider directory. + * @param providers - complete Client manifest snapshot. + */ + syncClientManifest(providers: readonly CordisInspectProviderManifest[]): void; + /** + * Return the complete known Host and Client provider directory. + * @returns Host providers followed by the Client providers. + */ + list(): CordisInspectProviderView[]; + /** + * Execute one provider query on its owning platform. + * @param platform - Host or Client runtime. + * @param providerId - provider selected from {@link list}. + * @param methodName - declared method name. + * @param input - optional lossless JSON input. + * @param agent - requesting Agent and scope. + * @param signal - tool-call cancellation. + * @returns provider JSON data. + */ + query(platform: CordisInspectPlatform, providerId: string, methodName: string, input: JsonValue | undefined, agent: Agent, signal: AbortSignal): Promise; + /** + * Accept the first valid Client response for a pending query. + * @param agent - Agent whose Session owns the query. + * @param requestId - Pending Client query identity. + * @param resolution - Client provider result or failure. + * @returns whether this response settled the still-pending query. + */ + resolveClientQuery(agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution): CordisInspectResolveAck; + private queryClient; +} +//# sourceMappingURL=inspect-registry.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.js new file mode 100644 index 0000000..09dd1ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.js @@ -0,0 +1,192 @@ +/** Host registry for model-visible, read-only Cordis capability queries. */ +import { Service } from '@deepseek-ai/cordis'; +import { snapshotJsonValue } from '@deepseek-ai/dsh-session'; +import { assertSupportedJsonSchema, validateJsonSchemaValue } from '@deepseek-ai/dsh-tools'; +/** Registry and cross-page router behind the two model-facing inspect tools. */ +export class CordisInspectRegistryService extends Service { + providers = new Map(); + pending = new Map(); + clientManifest; + nextRequest = 1; + /** Register the process-global Host registry. */ + constructor(ctx) { + super(ctx, 'cordisInspect'); + } + /** + * Register one Host provider. + * @param registration - manifest and local query handler. + * @returns idempotent disposer. + */ + register(registration) { + const manifest = validateManifest(registration.manifest); + if (this.providers.has(manifest.id)) + throw new Error(`Host Cordis inspect provider "${manifest.id}" is already registered`); + const stored = { ...registration, manifest }; + this.providers.set(manifest.id, stored); + return () => { + if (this.providers.get(manifest.id) === stored) + this.providers.delete(manifest.id); + }; + } + /** + * Replace the mirrored Client provider directory. + * @param providers - complete Client manifest snapshot. + */ + syncClientManifest(providers) { + const ids = new Set(); + const validated = providers.map((provider) => { + const manifest = validateManifest(provider); + if (ids.has(manifest.id)) + throw new Error(`Client Cordis inspect manifest repeats provider "${manifest.id}"`); + ids.add(manifest.id); + return manifest; + }); + this.clientManifest = Object.freeze(validated); + } + /** + * Return the complete known Host and Client provider directory. + * @returns Host providers followed by the Client providers. + */ + list() { + return [ + ...[...this.providers.values()].map(provider => view('host', provider.manifest)), + ...(this.clientManifest ?? []).map(provider => view('client', provider)), + ]; + } + /** + * Execute one provider query on its owning platform. + * @param platform - Host or Client runtime. + * @param providerId - provider selected from {@link list}. + * @param methodName - declared method name. + * @param input - optional lossless JSON input. + * @param agent - requesting Agent and scope. + * @param signal - tool-call cancellation. + * @returns provider JSON data. + */ + async query(platform, providerId, methodName, input, agent, signal) { + if (platform === 'host') { + const registration = this.providers.get(providerId); + if (registration === undefined) + throw new Error(`Host Cordis inspect provider "${providerId}" is not registered`); + const method = findMethod(registration.manifest, methodName); + validateInput('Host', providerId, method, input); + signal.throwIfAborted(); + const data = await registration.query(methodName, input, { agent, signal }); + signal.throwIfAborted(); + return validateOutput('Host', providerId, method, data); + } + return await this.queryClient(providerId, methodName, input, agent, signal); + } + /** + * Accept the first valid Client response for a pending query. + * @param agent - Agent whose Session owns the query. + * @param requestId - Pending Client query identity. + * @param resolution - Client provider result or failure. + * @returns whether this response settled the still-pending query. + */ + resolveClientQuery(agent, requestId, resolution) { + const pending = this.pending.get(requestId); + if (pending === undefined || pending.request.agentId !== agent.id) + return { accepted: false }; + if (!resolution.ok) + return { accepted: false }; + try { + resolution = { + ok: true, + data: validateOutput('Client', pending.request.provider, pending.method, resolution.data), + }; + } + catch { + return { accepted: false }; + } + this.pending.delete(requestId); + pending.settle(resolution); + this.ctx.emit('cordis/inspect-query-resolved', { requestId }); + return { accepted: true }; + } + async queryClient(providerId, methodName, input, agent, signal) { + const provider = this.clientManifest?.find(candidate => candidate.id === providerId); + if (provider === undefined) + throw new Error(`Client Cordis inspect provider "${providerId}" is not registered`); + const method = findMethod(provider, methodName); + validateInput('Client', providerId, method, input); + signal.throwIfAborted(); + const requestId = `inspect-${this.nextRequest++}`; + const request = { + requestId, + agentId: agent.id, + provider: providerId, + method: methodName, + ...input === undefined ? {} : { input }, + }; + const result = new Promise((resolve) => { + this.pending.set(requestId, { request, method, settle: resolve }); + }); + const onAbort = () => { + const pending = this.pending.get(requestId); + if (pending === undefined) + return; + this.pending.delete(requestId); + pending.settle({ ok: false, reason: 'cancelled', message: `Client inspect query ${providerId}.${methodName} was cancelled` }); + this.ctx.emit('cordis/inspect-query-resolved', { requestId }); + }; + signal.addEventListener('abort', onAbort, { once: true }); + if (signal.aborted) + onAbort(); + else + this.ctx.emit('cordis/inspect-query', request); + try { + const resolution = await result; + if (!resolution.ok) + throw new Error(`${providerId}.${methodName}: ${resolution.message}`); + return resolution.data; + } + finally { + signal.removeEventListener('abort', onAbort); + } + } +} +function view(platform, manifest) { + return { platform, ...manifest, methods: [...manifest.methods] }; +} +function validateManifest(manifest) { + if (manifest.id.trim() === '') + throw new Error('Cordis inspect provider id must not be empty'); + if (manifest.description.trim() === '') + throw new Error(`Cordis inspect provider "${manifest.id}" needs a description`); + const names = new Set(); + const methods = manifest.methods.map((method) => { + if (method.name.trim() === '') + throw new Error(`Cordis inspect provider "${manifest.id}" has an empty method name`); + if (names.has(method.name)) + throw new Error(`Cordis inspect provider "${manifest.id}" repeats method "${method.name}"`); + if (method.description.trim() === '') + throw new Error(`Cordis inspect method ${manifest.id}.${method.name} needs a description`); + assertSupportedJsonSchema(method.inputSchema); + assertSupportedJsonSchema(method.outputSchema); + names.add(method.name); + return Object.freeze({ ...method }); + }); + return Object.freeze({ ...manifest, methods: Object.freeze(methods) }); +} +function findMethod(manifest, name) { + const method = manifest.methods.find(candidate => candidate.name === name); + if (method === undefined) + throw new Error(`Cordis inspect provider "${manifest.id}" has no method "${name}"`); + return method; +} +function validateInput(platform, provider, method, input) { + const violations = validateJsonSchemaValue(method.inputSchema, input ?? {}, 'input'); + if (violations.length > 0) + throw new Error(`${platform} Cordis inspect ${provider}.${method.name} rejected input: ${violations.join('; ')}`); +} +function validateOutput(platform, provider, method, data) { + const snapshot = snapshotJsonValue(data); + if (snapshot === undefined) + throw new Error(`${platform} Cordis inspect ${provider}.${method.name} returned a non-JSON value`); + const violations = validateJsonSchemaValue(method.outputSchema, snapshot, 'output'); + if (violations.length > 0) + throw new Error(`${platform} Cordis inspect ${provider}.${method.name} returned invalid output: ${violations.join('; ')}`); + return snapshot; +} +//# sourceMappingURL=inspect-registry.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.d.ts new file mode 100644 index 0000000..fa92e19 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-cordis-host-runner`. + * @module @deepseek-ai/dsh-cordis-host-runner/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "cordis-host-runner-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.js new file mode 100644 index 0000000..72eaebd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/invariant.js @@ -0,0 +1,24 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-cordis-host-runner`. + * @module @deepseek-ai/dsh-cordis-host-runner/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-cordis-host-runner'; +/** Cordis companion plugin name. */ +export const name = 'cordis-host-runner-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: the definition registry is process memory with no event + * stream to observe, and its one owned relation (a running definition owns a + * settled host-half fiber and its handler table) is established and unwound + * inside single awaited verbs, so package tests assert it directly. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.d.ts new file mode 100644 index 0000000..8ce183f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.d.ts @@ -0,0 +1,29 @@ +/** + * Host-half fiber lifecycle over the `cordis-dynamic` group: settle a + * sandbox-produced plugin as a child fiber (never leaving a failed fiber + * mounted), and report the services a settled-but-pending fiber still waits + * for. Stopping needs no helper — a host half unwinds through an ordinary + * awaited `fiber.dispose()`, because everything the plugin registered is an + * effect on its fiber. + * @module @deepseek-ai/dsh-cordis-host-runner/lifecycle + */ +import type { Context, Fiber, Plugin } from '@deepseek-ai/cordis'; +/** + * Await the group, start and settle one guarded child, and dispose it before rethrowing any + * startup failure so a failed run never lingers. A valid unresolved inject may remain pending. + * @param group - the `cordis-dynamic` group fiber every host half hangs under. + * @param plugin - the plugin the sandbox returned; wrapped with the registration guard before starting. + * @param reportGuardFailure - reports post-activation Host guard rejections to the owning Agent. + * @returns the settled child fiber (possibly pending on unsatisfied `inject`). + */ +export declare function startHostHalf(group: Fiber, plugin: Plugin, reportGuardFailure: (error: Error) => void): Promise; +/** + * The services a fiber declared in `inject` that do not exist yet — a settled + * fiber that is not active is waiting on exactly these (legal cordis + * semantics: it activates when the service appears). + * @param ctx - the context to resolve service existence against. + * @param fiber - the host-half fiber whose `inject` declarations are checked. + * @returns the missing service names, in declaration order. + */ +export declare function missingServices(ctx: Context, fiber: Fiber): string[]; +//# sourceMappingURL=lifecycle.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.js new file mode 100644 index 0000000..5449aee --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/lifecycle.js @@ -0,0 +1,49 @@ +/** + * Host-half fiber lifecycle over the `cordis-dynamic` group: settle a + * sandbox-produced plugin as a child fiber (never leaving a failed fiber + * mounted), and report the services a settled-but-pending fiber still waits + * for. Stopping needs no helper — a host half unwinds through an ordinary + * awaited `fiber.dispose()`, because everything the plugin registered is an + * effect on its fiber. + * @module @deepseek-ai/dsh-cordis-host-runner/lifecycle + */ +import { guardedPlugin } from "./guard.js"; +/** + * Await the group, start and settle one guarded child, and dispose it before rethrowing any + * startup failure so a failed run never lingers. A valid unresolved inject may remain pending. + * @param group - the `cordis-dynamic` group fiber every host half hangs under. + * @param plugin - the plugin the sandbox returned; wrapped with the registration guard before starting. + * @param reportGuardFailure - reports post-activation Host guard rejections to the owning Agent. + * @returns the settled child fiber (possibly pending on unsatisfied `inject`). + */ +export async function startHostHalf(group, plugin, reportGuardFailure) { + await group.await(); + const fiber = group.ctx.plugin(guardedPlugin(plugin, reportGuardFailure)); + try { + await fiber.await(); + } + catch (error) { + await fiber.dispose(); + const message = error instanceof Error ? error.message : String(error); + // The commonest startup collision is running a NEW version of a package + // while the old run still holds the name — teach the replace recipe. + if (message.includes('already registered')) { + throw new Error(`${message} — to REPLACE something an earlier dynamic package registered, first cordis_stop that package's id ` + + '(find it with cordis_runtime_inspect what:"temporary"), then run the new version.'); + } + throw error instanceof Error ? error : new Error(message); + } + return fiber; +} +/** + * The services a fiber declared in `inject` that do not exist yet — a settled + * fiber that is not active is waiting on exactly these (legal cordis + * semantics: it activates when the service appears). + * @param ctx - the context to resolve service existence against. + * @param fiber - the host-half fiber whose `inject` declarations are checked. + * @returns the missing service names, in declaration order. + */ +export function missingServices(ctx, fiber) { + return Object.keys(fiber.inject).filter(service => ctx.get(service) === undefined); +} +//# sourceMappingURL=lifecycle.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.d.ts new file mode 100644 index 0000000..9a27112 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.d.ts @@ -0,0 +1,225 @@ +/** + * Process-local dynamic Plugin registry and its opaque identity mints. + * @module @deepseek-ai/dsh-cordis-host-runner/registry + */ +import type { Fiber } from '@deepseek-ai/cordis'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { ApprovalRequestId, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisDynamicRunMode, DynamicCordisRenderFailure, DynamicCordisRunAttempt } from './types.ts'; +/** One Host method exposed to this package's Client half. */ +export type DynamicCordisHandler = (args: unknown) => Promise; +/** One live activation and everything its teardown owns. */ +export interface DynamicCordisRun { + /** Exact activation identity. */ + pluginRunId: CordisDynamicPluginRunId; + /** Immutable package version being run. */ + packageId: CordisDynamicPackageId; + /** Host-half Fiber, absent for Client-only packages. */ + fiber?: Fiber; + /** Active Host methods. */ + handlers: Map; + /** Method registration cleanup. */ + handlerDisposers: (() => void)[]; + /** Runtime failures already sent to the owning Agent during this activation. */ + reportedRuntimeErrors: Set; + /** Last render failure observed for this version's current run. */ + renderFailure?: DynamicCordisRenderFailure; + /** Approval whose transition started this run, when model-driven. */ + startedForRequest?: ApprovalRequestId; +} +/** One immutable package version. */ +export interface DynamicCordisDefinition { + /** Package identity. */ + packageId: CordisDynamicPackageId; + /** Package label. */ + name: string; + /** User-facing purpose. */ + purpose: string; + /** Host source. */ + hostCode?: string; + /** Client source. */ + clientCode?: string; +} +/** Stable plugin instance containing immutable package versions. */ +export interface DynamicCordisPlugin { + /** Stable identity. */ + pluginId: CordisDynamicPluginId; + /** Owning session. */ + sessionId: SessionId; + /** Versions in define order. */ + packages: Map; + /** Client-bearing Packages individually authorized by the user. */ + approvedClientPackages: Set; + /** Whether one user decision authorized future Package versions of this Plugin. */ + clientVersionUpdatesApproved: boolean; + /** Last successfully activated version. */ + currentPackageId?: CordisDynamicPackageId; + /** Failed or in-progress target version. */ + nextPackageId?: CordisDynamicPackageId; + /** Current activation. */ + run?: DynamicCordisRun; + /** Latest activation attempt, including approval and asynchronous failure state. */ + latestRun?: DynamicCordisRunAttempt; +} +/** One suspended model-driven activation. */ +export interface DynamicCordisPendingRequest { + /** Session whose model requested this activation. */ + agentId: SessionId; + pluginId: CordisDynamicPluginId; + packageId: CordisDynamicPackageId; + pluginRunId: CordisDynamicPluginRunId; + mode: CordisDynamicRunMode; + /** Whether this request must wait for an explicit user decision. */ + requiresApproval: boolean; +} +/** Request accepted by `define`; it never crosses the Remote transport. */ +export interface DynamicCordisDefineRequest { + /** Session that owns the plugin. */ + sessionId: SessionId; + /** Create a plugin or append to an existing one. */ + plugin: { + kind: 'new'; + idPrefix: string; + } | { + kind: 'existing'; + pluginId: CordisDynamicPluginId; + }; + /** Package label. */ + name: string; + /** User-facing purpose. */ + purpose: string; + /** At least one source half. */ + code: { + host?: string; + client?: string; + }; +} +/** Successful `define` result. */ +export interface DynamicCordisDefineReceipt { + pluginId: CordisDynamicPluginId; + packageId: CordisDynamicPackageId; + name: string; + purpose: string; + hasHostHalf: boolean; + hasClientHalf: boolean; +} +/** Source-free modification context for an explicit `@pluginId` reference. */ +export interface DynamicCordisReference { + pluginId: CordisDynamicPluginId; + packageId: CordisDynamicPackageId; + name: string; + purpose: string; + currentPackageId?: CordisDynamicPackageId; + nextPackageId?: CordisDynamicPackageId; + activeRun?: { + pluginRunId: CordisDynamicPluginRunId; + packageId: CordisDynamicPackageId; + }; + latestRun?: DynamicCordisRunAttempt; +} +/** Source-free Plugin summary returned by layered self inspection. */ +export interface DynamicCordisPluginInspection extends DynamicCordisReference { + /** Immutable Package summaries in define order. */ + packages: Array<{ + packageId: CordisDynamicPackageId; + name: string; + purpose: string; + hasHostHalf: boolean; + hasClientHalf: boolean; + }>; +} +/** Exact immutable Package metadata and source returned by explicit inspection. */ +export interface DynamicCordisPackageInspection extends DynamicCordisReference { + /** Host and Client function bodies stored for this Package. */ + code: { + host?: string; + client?: string; + }; +} +/** Registry, identity mints, and pending approval index. */ +export declare class DynamicCordisRegistry { + private readonly plugins; + private readonly pendingRequests; + private nextPlugin; + private nextPackage; + private nextRun; + private nextApproval; + /** + * Mint a semantic plugin ID without reusing a prior suffix. + * @param prefix - validated lowercase semantic prefix proposed by the model. + * @returns a process-unique Plugin ID. + */ + mintPluginId(prefix: string): string; + /** + * Mint an immutable package ID. + * @returns a process-unique Package ID. + */ + mintPackageId(): string; + /** + * Mint an activation ID. + * @returns a process-unique Plugin Run ID. + */ + mintPluginRunId(): string; + /** + * Mint an approval ID. + * @returns a process-unique approval request ID. + */ + mintApprovalRequestId(): string; + /** + * Add one stable plugin. + * @param plugin - Plugin record to retain under its stable ID. + */ + add(plugin: DynamicCordisPlugin): void; + /** + * Read one plugin. + * @param id - stable Plugin ID. + * @returns the Plugin record, or `undefined` when absent. + */ + get(id: CordisDynamicPluginId): DynamicCordisPlugin | undefined; + /** + * Delete one plugin and all package versions. + * @param id - stable Plugin ID to remove. + * @returns whether a Plugin record was removed. + */ + delete(id: CordisDynamicPluginId): boolean; + /** + * Read all plugins in creation order. + * @returns a snapshot of every Plugin record. + */ + all(): DynamicCordisPlugin[]; + /** + * Read one session's plugins in creation order. + * @param sessionId - owning session to filter by. + * @returns a snapshot of matching Plugin records. + */ + ofSession(sessionId: SessionId): DynamicCordisPlugin[]; + /** + * Publish one pending approval. + * @param id - approval request ID. + * @param pending - resolver and Plugin metadata retained until settlement. + */ + armRequest(id: ApprovalRequestId, pending: DynamicCordisPendingRequest): void; + /** + * Read one pending approval without claiming it. + * @param id - approval request ID. + * @returns the pending request, or `undefined` when absent. + */ + peekRequest(id: ApprovalRequestId): DynamicCordisPendingRequest | undefined; + /** + * Claim one pending approval; first answer wins. + * @param id - approval request ID. + * @returns the claimed request, or `undefined` when already settled. + */ + claimRequest(id: ApprovalRequestId): DynamicCordisPendingRequest | undefined; + /** + * Cancel one pending approval. + * @param id - approval request ID to remove. + */ + disarmRequest(id: ApprovalRequestId): void; + /** + * Find a pending approval for one Plugin. + * @param pluginId - stable Plugin ID. + * @returns its approval request ID, or `undefined` when none is pending. + */ + pendingRequestFor(pluginId: CordisDynamicPluginId): ApprovalRequestId | undefined; +} +//# sourceMappingURL=registry.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.js new file mode 100644 index 0000000..cec4863 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/registry.js @@ -0,0 +1,131 @@ +/** + * Process-local dynamic Plugin registry and its opaque identity mints. + * @module @deepseek-ai/dsh-cordis-host-runner/registry + */ +/** Registry, identity mints, and pending approval index. */ +export class DynamicCordisRegistry { + plugins = new Map(); + pendingRequests = new Map(); + nextPlugin = 1; + nextPackage = 1; + nextRun = 1; + nextApproval = 1; + /** + * Mint a semantic plugin ID without reusing a prior suffix. + * @param prefix - validated lowercase semantic prefix proposed by the model. + * @returns a process-unique Plugin ID. + */ + mintPluginId(prefix) { + let id; + do + id = `${prefix}-${this.nextPlugin++}`; + while (this.plugins.has(id)); + return id; + } + /** + * Mint an immutable package ID. + * @returns a process-unique Package ID. + */ + mintPackageId() { + return `pkg-${this.nextPackage++}`; + } + /** + * Mint an activation ID. + * @returns a process-unique Plugin Run ID. + */ + mintPluginRunId() { + return `run-${this.nextRun++}`; + } + /** + * Mint an approval ID. + * @returns a process-unique approval request ID. + */ + mintApprovalRequestId() { + return `approval-${this.nextApproval++}`; + } + /** + * Add one stable plugin. + * @param plugin - Plugin record to retain under its stable ID. + */ + add(plugin) { + this.plugins.set(plugin.pluginId, plugin); + } + /** + * Read one plugin. + * @param id - stable Plugin ID. + * @returns the Plugin record, or `undefined` when absent. + */ + get(id) { + return this.plugins.get(id); + } + /** + * Delete one plugin and all package versions. + * @param id - stable Plugin ID to remove. + * @returns whether a Plugin record was removed. + */ + delete(id) { + return this.plugins.delete(id); + } + /** + * Read all plugins in creation order. + * @returns a snapshot of every Plugin record. + */ + all() { + return [...this.plugins.values()]; + } + /** + * Read one session's plugins in creation order. + * @param sessionId - owning session to filter by. + * @returns a snapshot of matching Plugin records. + */ + ofSession(sessionId) { + return this.all().filter(plugin => plugin.sessionId === sessionId); + } + /** + * Publish one pending approval. + * @param id - approval request ID. + * @param pending - resolver and Plugin metadata retained until settlement. + */ + armRequest(id, pending) { + this.pendingRequests.set(id, pending); + } + /** + * Read one pending approval without claiming it. + * @param id - approval request ID. + * @returns the pending request, or `undefined` when absent. + */ + peekRequest(id) { + return this.pendingRequests.get(id); + } + /** + * Claim one pending approval; first answer wins. + * @param id - approval request ID. + * @returns the claimed request, or `undefined` when already settled. + */ + claimRequest(id) { + const pending = this.pendingRequests.get(id); + if (pending !== undefined) + this.pendingRequests.delete(id); + return pending; + } + /** + * Cancel one pending approval. + * @param id - approval request ID to remove. + */ + disarmRequest(id) { + this.pendingRequests.delete(id); + } + /** + * Find a pending approval for one Plugin. + * @param pluginId - stable Plugin ID. + * @returns its approval request ID, or `undefined` when none is pending. + */ + pendingRequestFor(pluginId) { + for (const [requestId, request] of this.pendingRequests) { + if (request.pluginId === pluginId) + return requestId; + } + return undefined; + } +} +//# sourceMappingURL=registry.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.d.ts new file mode 100644 index 0000000..21d6e17 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.d.ts @@ -0,0 +1,93 @@ +/** + * The `node:vm` sandbox a dynamic package's HOST half evaluates in: a fresh realm whose globals + * are a tagged write-through console, the `harness` registration helpers, the encoding primitives + * a bare vm context lacks, and callable traps over the Node APIs the sandbox deliberately + * withholds. Traps steer filesystem, network, process, and timer work to `ctx.fs`, `ctx.web`, + * `ctx.bash`, and Cordis timers. This keeps cooperative packages inspectable and disposable but + * is not containment: host-realm helper functions remain an escape route. + * + * The browser half never reaches this module — it is evaluated by the client-side runner in a + * closure, with its own facade. + * @module @deepseek-ai/dsh-cordis-host-runner/sandbox + */ +/** Exact Host closure symbols exposed by the sandbox and guarded Context. */ +export declare const HOST_BUILTIN_INSPECTION: readonly [{ + readonly name: "ctx"; + readonly description: "Restricted Cordis Context. Prefer ctx.get(name) with an undefined check; use inject for hard dependencies."; + readonly signatures: readonly ["ctx.get(name: string): unknown | undefined", "ctx.on(name: string, listener: Function): () => void", "ctx.provide(name: string, value: unknown): () => void", "ctx.effect(callback: Function, label?: string): () => void"]; +}, { + readonly name: "harness"; + readonly description: "Host helpers for Package-private Client RPC and model-visible dynamic Tools."; + readonly signatures: readonly ["harness.handle(method: string, handler: (args: JsonValue) => JsonValue | Promise): () => void", "harness.defineTool(definition: ToolDefinition): ToolDefinition", "harness.registerTool(ctx: Context, tool: ToolDefinition): () => void"]; +}, { + readonly name: "console"; + readonly description: "Package-tagged Host logging."; + readonly signatures: readonly ["console.log(...values): void", "console.error(...values): void"]; +}, { + readonly name: "btoa"; + readonly description: "Encode UTF-8 text as base64."; + readonly signatures: readonly ["btoa(value: string): string"]; +}, { + readonly name: "atob"; + readonly description: "Decode base64 as UTF-8 text."; + readonly signatures: readonly ["atob(value: string): string"]; +}, { + readonly name: "TextEncoder"; + readonly description: "Standard UTF-8 encoder constructor."; + readonly signatures: readonly ["new TextEncoder()"]; +}, { + readonly name: "TextDecoder"; + readonly description: "Standard text decoder constructor."; + readonly signatures: readonly ["new TextDecoder(label?: string)"]; +}]; +/** + * Build the vm context one host half evaluates in: the tagged console, the + * `harness` registration helpers, the encoding primitives, the Node-API traps, + * and the dual-realm `instanceof` patch, already `createContext`-ed. + * @param id - the package id (`dyn-`), used as the console tag and filename stem. + * @param harnessExtras - per-package `harness` verbs beyond the registration pair (`handle`). + * @returns the contextified sandbox object to pass to {@link evaluateHostCode}. + */ +export declare function createSandbox(id: string, harnessExtras?: Record): object; +/** + * The parse-failure context a vm `SyntaxError` carries: the vm prints the + * offending source line and a caret before the message, which is exactly what + * a model needs to self-correct — surface it instead of the bare message. + * Falls back to `String(error)` when the stack carries no such prelude. + * @param error - the `SyntaxError` (host- or sandbox-realm) thrown while compiling package code. + * @returns the stack prefix up to and including the `SyntaxError: …` line. + */ +export declare function syntaxErrorContext(error: Error): string; +/** + * The teaching text one parse failure produces, shared by the define-time + * precheck and the run-time evaluation so a model reads the same diagnosis + * whichever verb caught it. + * @param half - which half failed to parse, named as the define argument that carried it. + * @param context - the {@link syntaxErrorContext} of the failure. + * @returns the model-facing error message. + */ +export declare function parseErrorMessage(half: 'code.host' | 'code.client', context: string): string; +/** + * Parse one half's source without running it: the define-time precheck that + * keeps unparseable code out of the registry, so a model fixes it and defines + * again instead of discovering the failure at run time. Compiling through `vm` + * rather than `new Function` is what makes the two agree — same wrapper, same + * compiler, and the same source-line-and-caret prelude in the failure. + * @param code - the model-written function body. + * @param half - which define argument carried it, for the error text. + * @throws when the body does not parse, with the offending line and a teaching hint. + */ +export declare function precheckCode(code: string, half: 'code.host' | 'code.client'): void; +/** + * Evaluate a host half as the body of an async function inside the sandbox. `vmTimeoutMs` only + * bounds the SYNCHRONOUS portion; an async body escapes it — acceptable under the module's + * trust stance. Parse errors include the offending line and a TypeScript-removal or bracket- + * balance hint. + * @param sandbox - the contextified object from {@link createSandbox}. + * @param code - the model-written function body; must `return` a plugin. + * @param id - the package id, used as the vm filename (`cordis-dyn-.js`). + * @param vmTimeoutMs - the synchronous evaluation bound in milliseconds. + * @returns whatever the code returned, still un-narrowed (the run lifecycle checks plugin shape). + */ +export declare function evaluateHostCode(sandbox: object, code: string, id: string, vmTimeoutMs: number): Promise; +//# sourceMappingURL=sandbox.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.js new file mode 100644 index 0000000..f38d6f3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/sandbox.js @@ -0,0 +1,223 @@ +/** + * The `node:vm` sandbox a dynamic package's HOST half evaluates in: a fresh realm whose globals + * are a tagged write-through console, the `harness` registration helpers, the encoding primitives + * a bare vm context lacks, and callable traps over the Node APIs the sandbox deliberately + * withholds. Traps steer filesystem, network, process, and timer work to `ctx.fs`, `ctx.web`, + * `ctx.bash`, and Cordis timers. This keeps cooperative packages inspectable and disposable but + * is not containment: host-realm helper functions remain an escape route. + * + * The browser half never reaches this module — it is evaluated by the client-side runner in a + * closure, with its own facade. + * @module @deepseek-ai/dsh-cordis-host-runner/sandbox + */ +import { createContext, runInContext, Script } from 'node:vm'; +import { sandboxDefineTool, sandboxRegisterTool } from "./guard.js"; +/** Exact Host closure symbols exposed by the sandbox and guarded Context. */ +export const HOST_BUILTIN_INSPECTION = [ + { + name: 'ctx', + description: 'Restricted Cordis Context. Prefer ctx.get(name) with an undefined check; use inject for hard dependencies.', + signatures: [ + 'ctx.get(name: string): unknown | undefined', + 'ctx.on(name: string, listener: Function): () => void', + 'ctx.provide(name: string, value: unknown): () => void', + 'ctx.effect(callback: Function, label?: string): () => void', + ], + }, + { + name: 'harness', + description: 'Host helpers for Package-private Client RPC and model-visible dynamic Tools.', + signatures: [ + 'harness.handle(method: string, handler: (args: JsonValue) => JsonValue | Promise): () => void', + 'harness.defineTool(definition: ToolDefinition): ToolDefinition', + 'harness.registerTool(ctx: Context, tool: ToolDefinition): () => void', + ], + }, + { name: 'console', description: 'Package-tagged Host logging.', signatures: ['console.log(...values): void', 'console.error(...values): void'] }, + { name: 'btoa', description: 'Encode UTF-8 text as base64.', signatures: ['btoa(value: string): string'] }, + { name: 'atob', description: 'Decode base64 as UTF-8 text.', signatures: ['atob(value: string): string'] }, + { name: 'TextEncoder', description: 'Standard UTF-8 encoder constructor.', signatures: ['new TextEncoder()'] }, + { name: 'TextDecoder', description: 'Standard text decoder constructor.', signatures: ['new TextDecoder(label?: string)'] }, +]; +/** + * A write-through console for one package, tagging every line with the package + * id. Write-through (host stdout/stderr), NOT buffered into the tool result: + * a registered listener fires long after the run call returned, and its output + * must land somewhere the user can see — for a terminal entry point, the host terminal. + */ +function taggedConsole(id) { + const tag = `[cordis:${id}]`; + const log = (...args) => { console.log(tag, ...args); }; + const error = (...args) => { console.error(tag, ...args); }; + return { log, info: log, warn: log, debug: log, error }; +} +/** + * Patch only VM constructors so `instanceof` accepts both VM values and host values passed as + * arguments, events, or service results; host intrinsics remain untouched. + */ +const DUAL_REALM_INSTANCEOF_PRELUDE = ` +(hostIntrinsics) => { + 'use strict' + const ordinary = Function.prototype[Symbol.hasInstance] + for (const name of Object.keys(hostIntrinsics)) { + const VmCtor = globalThis[name] + const HostCtor = hostIntrinsics[name] + if (typeof VmCtor !== 'function' || typeof HostCtor !== 'function') continue + Object.defineProperty(VmCtor, Symbol.hasInstance, { + value: (instance) => ordinary.call(VmCtor, instance) || ordinary.call(HostCtor, instance), + configurable: true, + }) + } +} +`; +/** Run {@link DUAL_REALM_INSTANCEOF_PRELUDE} in a freshly created sandbox, handing it the host intrinsics to pair up. */ +function patchDualRealmInstanceof(sandbox) { + const patch = runInContext(DUAL_REALM_INSTANCEOF_PRELUDE, sandbox); + patch({ Object, Array, Function, Error, TypeError, RangeError, SyntaxError, Promise, RegExp, Date, Map, Set }); +} +const TIMER_REDIRECT = 'Node timers are unavailable. Use the cordis timer service instead: declare inject: [\'timer\'] on your plugin ' + + 'and call ctx.timeout / ctx.interval after querying Host Service.listService for the exact overloads. ' + + 'Those calls are fiber effects, cleaned up automatically when stopped.'; +/** + * The callable Node APIs the sandbox deliberately disables, each mapped to the + * cordis alternative its trap error names. Only function-valued globals are + * trapped; a data-valued global such as `process` stays `undefined`, because a + * throwing accessor would detonate the common `typeof process` feature probe + * at resolution time. + */ +const NODE_API_REDIRECTS = { + require: 'Node modules are unavailable. Use the cordis services on ctx instead — e.g. inject: [\'fs\'] for files, ' + + '[\'web\'] for HTTP, [\'bash\'] for processes; query Service.listService with cordis_inspect_query first.', + setTimeout: TIMER_REDIRECT, + setInterval: TIMER_REDIRECT, + setImmediate: TIMER_REDIRECT, + clearTimeout: TIMER_REDIRECT, + clearInterval: TIMER_REDIRECT, + fetch: 'Network access goes through the cordis web service: declare inject: [\'web\'] and call ctx.web ' + + '(query Host Service.listService with cordis_inspect_query for its methods).', +}; +/** Build the trap functions for {@link NODE_API_REDIRECTS}: calling one throws the redirect. */ +function nodeApiTraps() { + const traps = {}; + for (const [name, redirect] of Object.entries(NODE_API_REDIRECTS)) { + traps[name] = () => { + throw new Error(`${name} is not available in the dynamic package sandbox — ${redirect}`); + }; + } + return traps; +} +/** + * Build the vm context one host half evaluates in: the tagged console, the + * `harness` registration helpers, the encoding primitives, the Node-API traps, + * and the dual-realm `instanceof` patch, already `createContext`-ed. + * @param id - the package id (`dyn-`), used as the console tag and filename stem. + * @param harnessExtras - per-package `harness` verbs beyond the registration pair (`handle`). + * @returns the contextified sandbox object to pass to {@link evaluateHostCode}. + */ +export function createSandbox(id, harnessExtras = {}) { + const sandbox = { + ...nodeApiTraps(), + console: taggedConsole(id), + harness: { defineTool: sandboxDefineTool, registerTool: sandboxRegisterTool, ...harnessExtras }, + // Web APIs absent from fresh vm contexts — made available so the model + // can encode/decode base64 without Buffer (which is also absent). Host + // closures over Buffer, never Buffer itself. + btoa: (s) => Buffer.from(s, 'utf-8').toString('base64'), + atob: (s) => Buffer.from(s, 'base64').toString('utf-8'), + TextEncoder, + TextDecoder, + }; + createContext(sandbox); + patchDualRealmInstanceof(sandbox); + return sandbox; +} +/** + * Cross-realm SyntaxError detection: a compile failure inside `runInContext` + * constructs its error in the SANDBOX realm, so a host `instanceof + * SyntaxError` is silently false — the `name` property is the realm-safe tag. + */ +function isSyntaxError(error) { + return typeof error === 'object' && error !== null && error.name === 'SyntaxError'; +} +/** + * The parse-failure context a vm `SyntaxError` carries: the vm prints the + * offending source line and a caret before the message, which is exactly what + * a model needs to self-correct — surface it instead of the bare message. + * Falls back to `String(error)` when the stack carries no such prelude. + * @param error - the `SyntaxError` (host- or sandbox-realm) thrown while compiling package code. + * @returns the stack prefix up to and including the `SyntaxError: …` line. + */ +export function syntaxErrorContext(error) { + const lines = (error.stack ?? '').split('\n'); + const messageIndex = lines.findIndex(line => line.startsWith('SyntaxError')); + if (messageIndex === -1) + return String(error); + return lines.slice(0, messageIndex + 1).join('\n'); +} +/** + * The teaching text one parse failure produces, shared by the define-time + * precheck and the run-time evaluation so a model reads the same diagnosis + * whichever verb caught it. + * @param half - which half failed to parse, named as the define argument that carried it. + * @param context - the {@link syntaxErrorContext} of the failure. + * @returns the model-facing error message. + */ +export function parseErrorMessage(half, context) { + // Scope the TypeScript heuristic to the OFFENDING line, not the whole code: + // an ` as ` inside an ordinary description string must not turn a plain + // syntax error into a misleading remove-annotations message. + const offendingLine = context.split('\n')[1] ?? ''; + if (/\bas\b/.test(offendingLine)) { + return `dynamic package \`${half}\` failed to parse:\n${context}\n` + + 'The sandbox runs plain JavaScript, not TypeScript. Remove type annotations:\n' + + ' ✗ { type: \'text\' as const, text: x }\n' + + ' ✓ { type: \'text\', text: x }'; + } + return `dynamic package \`${half}\` failed to parse:\n${context}\n` + + 'Note: it runs as the BODY of an async function (line numbers are offset by the 1-line wrapper). ' + + 'Check bracket balance — ending the returned plugin object with `});` closes a call that was never opened; ' + + 'a plain `return { … }` ends with `}` (an optional `;`), never `)`.'; +} +/** + * Parse one half's source without running it: the define-time precheck that + * keeps unparseable code out of the registry, so a model fixes it and defines + * again instead of discovering the failure at run time. Compiling through `vm` + * rather than `new Function` is what makes the two agree — same wrapper, same + * compiler, and the same source-line-and-caret prelude in the failure. + * @param code - the model-written function body. + * @param half - which define argument carried it, for the error text. + * @throws when the body does not parse, with the offending line and a teaching hint. + */ +export function precheckCode(code, half) { + try { + // Compile-only: constructing the Script parses the source and runs nothing. + new Script(`(async () => {\n${code}\n})()`, { filename: `cordis-dyn-${half}.js` }); + } + catch (error) { + if (!isSyntaxError(error)) + throw error; + throw new Error(parseErrorMessage(half, syntaxErrorContext(error))); + } +} +/** + * Evaluate a host half as the body of an async function inside the sandbox. `vmTimeoutMs` only + * bounds the SYNCHRONOUS portion; an async body escapes it — acceptable under the module's + * trust stance. Parse errors include the offending line and a TypeScript-removal or bracket- + * balance hint. + * @param sandbox - the contextified object from {@link createSandbox}. + * @param code - the model-written function body; must `return` a plugin. + * @param id - the package id, used as the vm filename (`cordis-dyn-.js`). + * @param vmTimeoutMs - the synchronous evaluation bound in milliseconds. + * @returns whatever the code returned, still un-narrowed (the run lifecycle checks plugin shape). + */ +export async function evaluateHostCode(sandbox, code, id, vmTimeoutMs) { + try { + return await runInContext(`(async () => {\n${code}\n})()`, sandbox, { filename: `cordis-dyn-${id}.js`, timeout: vmTimeoutMs }); + } + catch (error) { + if (!isSyntaxError(error)) + throw error; + throw new Error(parseErrorMessage('code.host', syntaxErrorContext(error))); + } +} +//# sourceMappingURL=sandbox.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.d.ts new file mode 100644 index 0000000..6b39635 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.d.ts @@ -0,0 +1,359 @@ +/** + * Client-safe wire vocabulary of the dynamic Cordis plugin runner. + * @module @deepseek-ai/dsh-cordis-host-runner/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { JsonValue, SessionId } from '@deepseek-ai/dsh-session/types'; +/** Stable identity of one dynamic plugin instance. */ +export type CordisDynamicPluginId = Branded<'CordisDynamicPluginId'>; +/** Identity of one immutable package version belonging to a dynamic plugin. */ +export type CordisDynamicPackageId = Branded<'CordisDynamicPackageId'>; +/** Identity of one successful activation attempt. */ +export type CordisDynamicPluginRunId = Branded<'CordisDynamicPluginRunId'>; +/** Identity of one human approval request. */ +export type ApprovalRequestId = Branded<'ApprovalRequestId'>; +/** Identity of one cross-page inspect query. */ +export type CordisInspectRequestId = Branded<'CordisInspectRequestId'>; +/** Runtime plane that owns an inspect provider. */ +export type CordisInspectPlatform = 'host' | 'client'; +/** One model-callable read-only query exposed by an inspect provider. */ +export interface CordisInspectMethodManifest { + /** Method name, unique within its provider. */ + name: string; + /** What the query returns and when to use it. */ + description: string; + /** JSON Schema accepted by the query. */ + inputSchema: JsonValue; + /** JSON Schema produced by the query. */ + outputSchema: JsonValue; +} +/** Serializable directory entry for one inspect provider. */ +export interface CordisInspectProviderManifest { + /** Provider identity, unique within one platform. */ + id: string; + /** Capability described by this provider. */ + description: string; + /** Explicit read-only queries. */ + methods: readonly CordisInspectMethodManifest[]; +} +/** Provider directory row returned by `cordis_inspect_list`. */ +export interface CordisInspectProviderView extends CordisInspectProviderManifest { + /** Runtime plane that executes these methods. */ + platform: CordisInspectPlatform; +} +/** Host broadcast requesting one live Client inspect result. */ +export interface CordisInspectQueryRequest { + /** Correlation identity. */ + requestId: CordisInspectRequestId; + /** Session whose model requested the query. */ + agentId: SessionId; + /** Provider selected from the Client manifest. */ + provider: string; + /** Method selected from the provider manifest. */ + method: string; + /** JSON query input, omitted when the method has no fields. */ + input?: JsonValue; +} +/** Result sent from a Client provider to the waiting Host query. */ +export type CordisInspectQueryResolution = { + ok: true; + data: JsonValue; +} | { + ok: false; + reason: 'provider-missing' | 'method-missing' | 'invalid-input' | 'provider-error' | 'cancelled'; + message: string; +}; +/** Notification that a Client inspect request can no longer be answered. */ +export interface CordisInspectQueryResolved { + /** Query that left the pending state. */ + requestId: CordisInspectRequestId; +} +/** Whether a Client answer claimed the still-pending query. */ +export interface CordisInspectResolveAck { + /** False for unknown, cancelled, stale, or late answers. */ + accepted: boolean; +} +/** Whether a package starts the current version or replaces it. */ +export type CordisDynamicRunMode = 'run' | 'update'; +/** How a model-driven Client activation request left the pending state. */ +export type RequestRunOutcome = 'approved' | 'completed' | 'rejected' | 'cancelled' | 'failed'; +/** Error fields preserved across the Host/Client transport. */ +export interface CordisErrorDetails { + /** Original error message. */ + message: string; + /** Original stack when the thrown value supplied one. */ + stack?: string; +} +/** Persisted state of the latest activation attempt. */ +export type CordisRunStatus = 'awaiting-approval' | 'starting-host' | 'client-pending' | 'running' | 'waiting' | 'rejected' | 'failed' | 'cancelled' | 'stopped'; +/** One platform half within an activation attempt. */ +export interface CordisHalfState { + /** Lifecycle state of this half. */ + status: 'absent' | 'pending' | 'stopped' | 'running' | 'waiting' | 'failed'; + /** Services still needed by a successfully created Fiber. */ + waitingFor: readonly string[]; + /** Failure text for this half. */ + error?: string; +} +/** Structured failure associated with an exact activation attempt. */ +export interface CordisRunDiagnostic { + /** Stage that failed. */ + phase: 'approval' | 'host-load' | 'host-apply' | 'client-load' | 'client-apply' | 'client-render'; + /** Original failure text. */ + message: string; + /** Original failure stack when available. */ + stack?: string; + /** Stable Plugin identity. */ + pluginId: CordisDynamicPluginId; + /** Immutable Package identity. */ + packageId: CordisDynamicPackageId; + /** Exact attempt identity. */ + pluginRunId: CordisDynamicPluginRunId; +} +/** Latest activation attempt retained independently from the physical run. */ +export interface DynamicCordisRunAttempt { + /** Exact attempt identity. */ + pluginRunId: CordisDynamicPluginRunId; + /** Target Package. */ + packageId: CordisDynamicPackageId; + /** Explicit run/update intent. */ + mode: CordisDynamicRunMode; + /** Current attempt state. */ + status: CordisRunStatus; + /** Pending Client activation request; it represents approval only when `requiresApproval` is true. */ + approvalRequestId?: ApprovalRequestId; + /** Whether the pending Client activation requires a user decision. */ + requiresApproval?: boolean; + /** Host-half state. */ + host: CordisHalfState; + /** Client-half state. */ + client: CordisHalfState; + /** Most recent failure. */ + error?: CordisRunDiagnostic; +} +/** One running package announced to browser pages. */ +export interface DynamicCordisPackage { + /** Stable plugin instance. */ + pluginId: CordisDynamicPluginId; + /** Immutable package version currently active. */ + packageId: CordisDynamicPackageId; + /** This activation's identity. */ + pluginRunId: CordisDynamicPluginRunId; + /** Package label. */ + name: string; +} +/** One pending model-driven Client activation forwarded to browser pages. */ +export interface DynamicCordisRunRequest { + /** Correlation identity of the activation request. */ + requestId: ApprovalRequestId; + /** Session whose plugin and tool call own the request. */ + agentId: SessionId; + /** Stable plugin instance being acted on. */ + pluginId: CordisDynamicPluginId; + /** Package version the request will activate. */ + packageId: CordisDynamicPackageId; + /** Explicit lifecycle intent. */ + mode: CordisDynamicRunMode; + /** Package label. */ + name: string; + /** User-facing reason supplied at define time. */ + purpose: string; + /** Whether a page must wait for an explicit user decision before activation. */ + requiresApproval: boolean; +} +/** One settled model-driven Client activation request broadcast to all pages. */ +export interface DynamicCordisRequestResolved { + /** Request that left the pending state. */ + requestId: ApprovalRequestId; + /** How the request settled. */ + outcome: RequestRunOutcome; +} +/** One activation withdrawn from every page. */ +export interface DynamicCordisRetracted { + /** Stable plugin instance. */ + pluginId: CordisDynamicPluginId; + /** Package version that was active. */ + packageId: CordisDynamicPackageId; + /** Exact activation being withdrawn. */ + pluginRunId: CordisDynamicPluginRunId; +} +/** Package metadata exposed by the inventory without source code. */ +export interface DynamicCordisInventoryPackage { + /** Immutable package version. */ + packageId: CordisDynamicPackageId; + /** Package label. */ + name: string; + /** User-facing purpose. */ + purpose: string; + /** Whether this version contains Host code. */ + hasHostHalf: boolean; + /** Whether this version contains Client code. */ + hasClientHalf: boolean; +} +/** One stable plugin row in the frame-wide inventory. */ +export interface DynamicCordisInventoryRow { + /** Stable plugin instance. */ + pluginId: CordisDynamicPluginId; + /** Session that owns this plugin. */ + agentId: SessionId; + /** Immutable versions in define order. */ + packages: readonly DynamicCordisInventoryPackage[]; + /** Last package that completed activation successfully. */ + currentPackageId?: CordisDynamicPackageId; + /** Package selected for a failed or in-progress transition. */ + nextPackageId?: CordisDynamicPackageId; + /** Current activation, absent while stopped. */ + activeRun?: { + pluginRunId: CordisDynamicPluginRunId; + packageId: CordisDynamicPackageId; + }; + /** Latest activation attempt, including pending approval and diagnostics. */ + latestRun?: DynamicCordisRunAttempt; +} +/** Answer to removing a plugin and all of its package versions. */ +export type DynamicCordisUndefineReceipt = { + ok: true; + wasRunning: boolean; +} | { + ok: false; + reason: 'plugin-missing'; + message: string; +}; +/** One render failure observed after a Client half loaded. */ +export interface DynamicCordisRenderFailure { + /** Slot whose component failed. */ + slot: string; + /** Render failure text. */ + message: string; + /** Original render failure stack when available. */ + stack?: string; + /** Whether the failing contribution relinquished its slot. */ + abdicated: boolean; +} +/** Result shared by model-driven and panel-driven activation. */ +export type DynamicCordisRunResponse = { + ok: true; + /** Whether activation completed synchronously, is starting in a Client, or awaits user approval. */ + status: 'awaiting-approval' | 'starting' | 'running'; + pluginId: CordisDynamicPluginId; + packageId: CordisDynamicPackageId; + pluginRunId: CordisDynamicPluginRunId; + /** Missing Host services; a parked Fiber is a successful activation. */ + waitingFor: readonly string[]; + /** Missing Client services reported by the approving page. */ + clientWaitingFor?: readonly string[]; + /** Last fully successful Package. */ + currentPackageId?: CordisDynamicPackageId; + /** Selected transition target. */ + nextPackageId?: CordisDynamicPackageId; + /** Explicit lifecycle intent. */ + mode: CordisDynamicRunMode; +} | { + ok: false; + reason: 'plugin-missing' | 'package-missing' | 'invalid-mode' | 'transition-in-flight' | 'host-half-failed' | 'client-half-failed' | 'rejected' | 'cancelled' | 'not-running'; + message: string; + /** Original failure stack when available. */ + stack?: string; +}; +/** Result of stopping a Plugin without deleting its Packages. */ +export type DynamicCordisStopResponse = { + ok: true; +} | { + ok: false; + reason: 'plugin-missing' | 'not-running'; + message: string; +}; +/** Result of bringing up the Host half before loading the Client half. */ +export type DynamicCordisHostHalfResult = { + ok: true; + pluginId: CordisDynamicPluginId; + packageId: CordisDynamicPackageId; + pluginRunId: CordisDynamicPluginRunId; + waitingFor: readonly string[]; + /** False when a panel merely attaches this page to an already active run. */ + startedHere: boolean; +} | ({ + ok: false; +} & CordisErrorDetails); +/** Client-half source for one exact activation. */ +export interface DynamicCordisClientSource { + /** Browser JavaScript body. */ + code: string; + /** Package label. */ + name: string; + /** Stable plugin instance. */ + pluginId: CordisDynamicPluginId; + /** Immutable source version. */ + packageId: CordisDynamicPackageId; + /** Exact activation the source belongs to. */ + pluginRunId: CordisDynamicPluginRunId; +} +/** Browser verdict used for both approved tool runs and panel runs. */ +export type DynamicCordisRunResolution = { + ok: true; + pluginRunId: CordisDynamicPluginRunId; + waitingFor?: readonly string[]; +} | { + ok: false; + reason: 'rejected' | 'host-half-failed' | 'client-half-failed'; + /** Activation that failed; absent for a refusal before activation. */ + pluginRunId?: CordisDynamicPluginRunId; + /** Whether this page created the failed activation instead of attaching to it. */ + startedHere?: boolean; + message?: string; + stack?: string; +}; +/** Whether a Client activation resolution reached the still-pending request. */ +export interface DynamicCordisResolveAck { + /** False for late, unknown, or stale answers. */ + accepted: boolean; +} +/** Result of routing one Client call to the active Host half. */ +export type DynamicCordisInvokeResult = { + ok: true; + value: JsonValue; +} | ({ + ok: false; + code: 'plugin-not-running' | 'stale-run' | 'method-not-found' | 'handler-error'; +} & CordisErrorDetails); +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * A Client-bearing activation needs a browser page, and may require a user decision. + * @param request - correlation identity, owner, target version, mode, and approval requirement. + * @mode emit + */ + 'cordis/request-run'(request: DynamicCordisRunRequest): void; + /** + * A pending Client activation request left the answerable state. + * @param resolved - request identity and outcome. + * @mode emit + */ + 'cordis/request-run-resolved'(resolved: DynamicCordisRequestResolved): void; + /** + * One exact Plugin/Package activation is now live in the Host. + * @param pkg - stable plugin, immutable package, run identity, and label. + * @mode emit + */ + 'cordis/dynamic-package'(pkg: DynamicCordisPackage): void; + /** + * One exact activation was withdrawn. + * @param retracted - plugin, package, and run identity. + * @mode emit + */ + 'cordis/dynamic-retract'(retracted: DynamicCordisRetracted): void; + /** + * Request a live read-only query from the Client inspect registry. + * @param request - correlation, Session, provider, method, and JSON input. + * @mode emit + */ + 'cordis/inspect-query'(request: CordisInspectQueryRequest): void; + /** + * Notify every Client that an inspect query has settled or been cancelled. + * @param resolved - exact query identity that is no longer answerable. + * @mode emit + */ + 'cordis/inspect-query-resolved'(resolved: CordisInspectQueryResolved): void; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.js new file mode 100644 index 0000000..a89d8f0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/lib/types/types.js @@ -0,0 +1,6 @@ +/** + * Client-safe wire vocabulary of the dynamic Cordis plugin runner. + * @module @deepseek-ai/dsh-cordis-host-runner/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/package.json new file mode 100644 index 0000000..dd95548 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner/package.json @@ -0,0 +1,78 @@ +{ + "name": "@deepseek-ai/dsh-cordis-host-runner", + "description": "Dynamic package definition registry, host-half sandbox lifecycle, and invoke handler table for model-mounted dual-half packages", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/extensions/cordis-host-runner" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./typert": { + "types": "./lib/typert.host.d.ts", + "default": "./lib/typert.host.js" + }, + "./remote": { + "types": "./lib/typert.remote-client.d.ts", + "default": "./lib/typert.remote-client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts", + "lib/typert.host.js", + "lib/typert.host.d.ts", + "lib/typert.remote-client.js", + "lib/typert.remote-client.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-timer": "^1.1.3", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-tools b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-tools new file mode 120000 index 0000000..df45afe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-tools @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..a2fcff1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.i18n.yaml new file mode 100644 index 0000000..55069ea --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/credentials/credentials/README.md +README.md: 62f5c6318ec04e9820a3d18ffa159d1561215760 +README.zh.md: 3c6ca0b454d4ff8a78bfcd29d1031584da27a5f1 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.md new file mode 100644 index 0000000..62f5c63 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.md @@ -0,0 +1,48 @@ +# dsh-credentials + +English | [中文](README.zh.md) + +Credential Service Definition (`ctx.credentials`). One doctrine, three consequences: + +**Configuration carries references to secrets, never the secrets.** A settings section or `cordis.yml` entry says `apiKeyEnv: DEEPSEEK_API_KEY`; the value behind that reference lives with a credential provider. So the settings document stays safe to sync and to render in a configuration UI, `describe()` can answer "is this configured, where from, can I write it" without ever holding a value, and rotating a secret touches no configuration file. + +**Consumers resolve per operation.** `resolve(ref)` is called at the start of each operation (the LLM adapters resolve once per model request) and never cached across operations — that read is what makes a changed credential reach the very next request without restarting any plugin. + +**An empty stored value is absent.** Everywhere: `resolve` skips it, `describe` reports it unconfigured. A blank can never masquerade as a configured secret. + +## Surface + +```ts +import type { Context } from '@deepseek-ai/cordis' +import { credentialRef } from '@deepseek-ai/dsh-credentials' + +declare const ctx: Context + +const ref = credentialRef('DEEPSEEK_API_KEY') // POSIX shell identifier, branded +const hit = await ctx.credentials.resolve(ref) // { value, source } | undefined +const info = await ctx.credentials.describe(ref) // { configured, source?, writable } — never the value +await ctx.credentials.set(ref, 'sk-…') // rejects while a read-only source shadows the ref +await ctx.credentials.unset(ref) // no-op when absent; same shadowing rule +``` + +`credentials/updated (ref)` fires after a committed change to a provider-managed source — a `set`, an `unset`, or an external edit observed in storage. Ambient process-environment changes are not observable and never emit. Consumers do not need the event (they re-resolve per operation); it exists for configuration UIs refreshing a "configured" badge. Its declaration lives in the client-safe `./types` subpath export together with the `CredentialRef` type it names (the package root re-exports the type), so a consumer outside the Host compilation face reads the very signature the Host emits instead of restating it. + +The shadowing rule on `set`/`unset` is deliberate fail-loud: when a read-only source (the live process environment, in the local provider) currently supplies the reference, a write would appear to succeed while resolution keeps returning the shadowing value — the seam rejects instead, and `describe().writable` lets a UI render the reference read-only up front. + +## Providers + +[`dsh-credentials-local`](../credentials-local/README.md) layers the inherited process environment over its managed `$DSH_HOME/.credentials.yaml` document, with the launcher's project and user `.env` layers as fallbacks. The seam shape leaves room for keyring-, helper-command-, and KMS-backed providers; a remote settings provider never needs to carry secrets. + +## Model Experience + +Indirectly, through the consuming LLM adapters: a resolved value authorizes their provider requests, and the adapter owns every model-visible surface. + +#### KV Cache effect + +No direct invalidation; credentials never enter a request prefix. + +## Known Limitations and Deferred Work + +- **No enumeration** — the seam answers questions about references it is given; configuration surfaces learn the references from settings schemas, so a `list()` has no current consumer. +- **References are environment-variable-shaped** — one flat POSIX-identifier namespace until a provider needs richer addressing. +- **Process-environment changes are invisible** — no event can fire for them; a UI only re-reads `describe()` on its own navigation. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.zh.md new file mode 100644 index 0000000..3c6ca0b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/README.zh.md @@ -0,0 +1,48 @@ +# dsh-credentials + +[English](README.md) | 中文 + +凭据 Service Definition(`ctx.credentials`)。一条准则,三个推论: + +**配置只携带对机密的引用,绝不携带机密本身。** settings 分节或 `cordis.yml` 条目写 `apiKeyEnv: DEEPSEEK_API_KEY`,引用背后的值存放在凭据提供方处。于是设置文档可以放心同步、放心渲染进配置界面;`describe()` 无需持有值就能回答「配置了吗、来自哪层、能否写入」;轮换机密不触碰任何配置文件。 + +**消费方按操作解析。** `resolve(ref)` 在每个操作开始时调用(LLM(大语言模型)适配器每次模型请求解析一次),绝不跨操作缓存——正是这次读取让改过的凭据无需重启任何插件就作用于下一次请求。 + +**空的存储值等于不存在。** 处处如此:`resolve` 跳过它,`describe` 报告未配置。空白永远不会伪装成已配置的机密。 + +## 接口 + +```ts +import type { Context } from '@deepseek-ai/cordis' +import { credentialRef } from '@deepseek-ai/dsh-credentials' + +declare const ctx: Context + +const ref = credentialRef('DEEPSEEK_API_KEY') // POSIX shell identifier, branded +const hit = await ctx.credentials.resolve(ref) // { value, source } | undefined +const info = await ctx.credentials.describe(ref) // { configured, source?, writable } — never the value +await ctx.credentials.set(ref, 'sk-…') // rejects while a read-only source shadows the ref +await ctx.credentials.unset(ref) // no-op when absent; same shadowing rule +``` + +`credentials/updated (ref)` 在提供方管理的来源发生已提交变更后触发——`set`、`unset` 或在存储中观察到的外部编辑。进程环境变量的变化不可观测,永不触发。消费方不需要该事件(它们按操作重新解析);它服务于配置界面刷新「已配置」徽标。它的声明住在 client-safe 的 `./types` 子路径出口,与其点名的 `CredentialRef` 类型同处一处(包根继续 re-export 该类型),于是 Host 编译面之外的消费方读到的正是 Host 发射的那一份签名,而不必再写一遍。 + +`set`/`unset` 的遮蔽规则有意采用明确报错的方式:当只读来源(本地提供方中即当前进程环境)正在提供该引用时,写入会表面成功而解析仍返回遮蔽值——seam 选择直接拒绝,并通过 `describe().writable` 让界面提前把该引用渲染为只读。 + +## 提供方 + +[`dsh-credentials-local`](../credentials-local/README.md) 把继承的进程环境叠加在其受管 `$DSH_HOME/.credentials.yaml` 文档之上,并以启动器的项目和用户 `.env` 层作为后备。该 seam 的接口为 keyring、辅助命令和 KMS 后端提供方预留了扩展空间;远端设置提供方永远不必携带机密。 + +## 模型体验 + +经由消费它的 LLM 适配器间接生效:解析出的值为适配器的提供方请求授权,所有模型可见接口都由适配器负责。 + +#### KV Cache 影响 + +无直接失效;凭据绝不进入请求前缀。 + +## 已知限制与暂缓事项 + +- **不提供枚举**——seam 只回答被问到的引用;配置界面从 settings schema 得知引用集合,`list()` 没有当前消费方。 +- **引用限定为环境变量形状**——在有提供方需要更丰富的寻址方式前,保持单一扁平的 POSIX 标识符命名空间。 +- **进程环境变化不可见**——不可能为其发事件;界面只能在自身导航时重新读取 `describe()`。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/index.js new file mode 100644 index 0000000..c812f7e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/index.js @@ -0,0 +1,67 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/index.js +/** +* Service Definition for the credential-reference capability seam (`ctx.credentials`). Settings and composition files carry +* *references* to secrets — environment-variable names — while providers own +* the actual values and their storage. Consumers resolve a reference once per +* operation, so a changed credential reaches the next operation without any +* plugin restart, and configuration surfaces describe a reference without +* ever seeing its value. +* @module @deepseek-ai/dsh-credentials +*/ +const REF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/; +/** +* Brand a raw string as a {@link CredentialRef}. +* @param value - candidate reference; a POSIX shell identifier such as `DEEPSEEK_API_KEY`. +* @returns the branded reference. +*/ +function credentialRef(value) { + if (!REF_PATTERN.test(value)) throw new TypeError(`credential ref "${value}" must match ${String(REF_PATTERN)}`); + return value; +} +/** +* Abstract credential service. Providers implement the four operations over +* their source layers; one seam-wide rule binds them all: an empty stored +* value is absent everywhere — `resolve` skips it, `describe` reports it +* unconfigured — so a blank never masquerades as a configured secret. +*/ +var CredentialProvider = class extends Service { + constructor(ctx) { + super(ctx, "credentials"); + } + /** + * Fan `credentials/updated` out with contained listener failures: every + * listener runs, and a sync throw or async rejection is logged without + * changing the committed operation's outcome — except `INVARIANT`-coded + * failures, which rethrow after every listener ran (the rethrow reaches the + * caller only from synchronous listeners, so invariant checks on this event + * must not be async functions). Providers call this only after the write or + * reload actually committed, so a broken observer can never make a durable + * change look failed. + * @param ref - the reference whose stored value changed. + */ + notifyUpdated(ref) { + let invariantFailure; + const args = ["credentials/updated", ref]; + for (const listener of this.ctx.events.dispatch("emit", args)) try { + const returned = listener(ref); + if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => { + this.warnListenerFailure(ref, error); + }); + } catch (error) { + if (error?.code === "INVARIANT") { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(ref, error); + } + if (invariantFailure !== void 0) throw invariantFailure; + } + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnListenerFailure(ref, error) { + this.ctx.logger.warn("credentials: a credentials/updated listener for \"%s\" failed", ref); + this.ctx.logger.warn(error); + } +}; +//#endregion +export { CredentialProvider, CredentialProvider as default, credentialRef }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/invariant.js new file mode 100644 index 0000000..3025ff7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/invariant.js @@ -0,0 +1,31 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-credentials`. +* @module @deepseek-ai/dsh-credentials/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-credentials"; +/** Cordis companion plugin name. */ +const name = "credentials-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* Install the commit-event lifecycle contract: `credentials/updated` names a +* committed provider-source change, so it can only fire while a credentials +* service is live — an emission after disposal means a provider leaked work +* past its teardown quiescence. The value relation itself (`describe` +* agreeing with `resolve`) is asynchronous provider I/O and stays pinned by +* each provider's own suite. +*/ +const install = (ctx, fail) => { + ctx.on("credentials/updated", (ref) => { + if (ctx.get("credentials") === void 0) fail(`credentials/updated for "${ref}" emitted without a live credentials service`); + }); +}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.d.ts new file mode 100644 index 0000000..b29288b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.d.ts @@ -0,0 +1,96 @@ +/** + * Service Definition for the credential-reference capability seam (`ctx.credentials`). Settings and composition files carry + * *references* to secrets — environment-variable names — while providers own + * the actual values and their storage. Consumers resolve a reference once per + * operation, so a changed credential reaches the next operation without any + * plugin restart, and configuration surfaces describe a reference without + * ever seeing its value. + * @module @deepseek-ai/dsh-credentials + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { CredentialRef } from './types.ts'; +export type { CredentialRef } from './types.ts'; +/** + * Brand a raw string as a {@link CredentialRef}. + * @param value - candidate reference; a POSIX shell identifier such as `DEEPSEEK_API_KEY`. + * @returns the branded reference. + */ +export declare function credentialRef(value: string): CredentialRef; +/** One resolved credential value and the source layer that supplied it. */ +export interface ResolvedCredential { + /** The non-empty secret value. */ + value: string; + /** Provider-defined source layer id (the local provider uses `env`, `file`, `project-env`, and `user-env`). */ + source: string; +} +/** Source and writability facts for one reference, safe for configuration UIs — never the value. */ +export interface CredentialInfo { + /** Whether {@link CredentialProvider.resolve} would currently return a value. */ + configured: boolean; + /** Source layer currently supplying the value; absent while unconfigured. */ + source?: string; + /** Whether {@link CredentialProvider.set} would currently succeed for this reference. */ + writable: boolean; +} +declare module '@deepseek-ai/cordis' { + interface Context { + credentials: CredentialProvider; + } +} +/** + * Abstract credential service. Providers implement the four operations over + * their source layers; one seam-wide rule binds them all: an empty stored + * value is absent everywhere — `resolve` skips it, `describe` reports it + * unconfigured — so a blank never masquerades as a configured secret. + */ +export declare abstract class CredentialProvider extends Service { + constructor(ctx: Context); + /** + * Resolve one reference to its current value. Resolution is per call: + * consumers re-resolve at each operation and must not cache across + * operations — that per-operation read is what makes a changed credential + * reach the next operation without a restart. + * @param ref - the reference to resolve. + * @returns the value and its source, or `undefined` while unconfigured. + */ + abstract resolve(ref: CredentialRef): Promise; + /** + * Describe one reference for configuration surfaces without exposing the + * value. + * @param ref - the reference to describe. + * @returns configured state, supplying source, and writability. + */ + abstract describe(ref: CredentialRef): Promise; + /** + * Durably store one value in the provider-managed writable source. Rejects + * while a read-only source shadows the reference — the write would appear + * to succeed while resolution keeps returning the shadowing value — and + * rejects an empty value (use {@link unset}). + * @param ref - the reference to store. + * @param value - the non-empty secret value. + */ + abstract set(ref: CredentialRef, value: string): Promise; + /** + * Remove one reference from the provider-managed writable source; removing + * an absent reference is a no-op. Rejects while a read-only source shadows + * the reference, like {@link set}. + * @param ref - the reference to remove. + */ + abstract unset(ref: CredentialRef): Promise; + /** + * Fan `credentials/updated` out with contained listener failures: every + * listener runs, and a sync throw or async rejection is logged without + * changing the committed operation's outcome — except `INVARIANT`-coded + * failures, which rethrow after every listener ran (the rethrow reaches the + * caller only from synchronous listeners, so invariant checks on this event + * must not be async functions). Providers call this only after the write or + * reload actually committed, so a broken observer can never make a durable + * change look failed. + * @param ref - the reference whose stored value changed. + */ + protected notifyUpdated(ref: CredentialRef): void; + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + private warnListenerFailure; +} +export default CredentialProvider; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.js new file mode 100644 index 0000000..e923e4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.js @@ -0,0 +1,78 @@ +/** + * Service Definition for the credential-reference capability seam (`ctx.credentials`). Settings and composition files carry + * *references* to secrets — environment-variable names — while providers own + * the actual values and their storage. Consumers resolve a reference once per + * operation, so a changed credential reaches the next operation without any + * plugin restart, and configuration surfaces describe a reference without + * ever seeing its value. + * @module @deepseek-ai/dsh-credentials + */ +import { Service } from '@deepseek-ai/cordis'; +const REF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/; +/** + * Brand a raw string as a {@link CredentialRef}. + * @param value - candidate reference; a POSIX shell identifier such as `DEEPSEEK_API_KEY`. + * @returns the branded reference. + */ +export function credentialRef(value) { + if (!REF_PATTERN.test(value)) { + throw new TypeError(`credential ref "${value}" must match ${String(REF_PATTERN)}`); + } + return value; +} +/** + * Abstract credential service. Providers implement the four operations over + * their source layers; one seam-wide rule binds them all: an empty stored + * value is absent everywhere — `resolve` skips it, `describe` reports it + * unconfigured — so a blank never masquerades as a configured secret. + */ +export class CredentialProvider extends Service { + constructor(ctx) { + super(ctx, 'credentials'); + } + /* jscpd:ignore-start -- deliberate symmetry with the settings seam's commit + fan-out: the contained-dispatch shape is the reviewed listener-lifecycle + contract, and extracting it would couple the two seams' event semantics. */ + /** + * Fan `credentials/updated` out with contained listener failures: every + * listener runs, and a sync throw or async rejection is logged without + * changing the committed operation's outcome — except `INVARIANT`-coded + * failures, which rethrow after every listener ran (the rethrow reaches the + * caller only from synchronous listeners, so invariant checks on this event + * must not be async functions). Providers call this only after the write or + * reload actually committed, so a broken observer can never make a durable + * change look failed. + * @param ref - the reference whose stored value changed. + */ + notifyUpdated(ref) { + let invariantFailure; + const args = ['credentials/updated', ref]; + for (const listener of this.ctx.events.dispatch('emit', args)) { + try { + const returned = listener(ref); + if (returned != null && typeof returned.then === 'function') { + void Promise.resolve(returned).then(undefined, (error) => { + this.warnListenerFailure(ref, error); + }); + } + } + catch (error) { + if (error?.code === 'INVARIANT') { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(ref, error); + } + } + if (invariantFailure !== undefined) + throw invariantFailure; + } + /* jscpd:ignore-end */ + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnListenerFailure(ref, error) { + this.ctx.logger.warn('credentials: a credentials/updated listener for "%s" failed', ref); + this.ctx.logger.warn(error); + } +} +export default CredentialProvider; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.d.ts new file mode 100644 index 0000000..900d083 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-credentials`. + * @module @deepseek-ai/dsh-credentials/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "credentials-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.js new file mode 100644 index 0000000..a63e9b7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.js @@ -0,0 +1,31 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-credentials`. + * @module @deepseek-ai/dsh-credentials/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-credentials'; +/** Cordis companion plugin name. */ +export const name = 'credentials-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * Install the commit-event lifecycle contract: `credentials/updated` names a + * committed provider-source change, so it can only fire while a credentials + * service is live — an emission after disposal means a provider leaked work + * past its teardown quiescence. The value relation itself (`describe` + * agreeing with `resolve`) is asynchronous provider I/O and stays pinned by + * each provider's own suite. + */ +const install = (ctx, fail) => { + ctx.on('credentials/updated', (ref) => { + if (ctx.get('credentials') === undefined) { + fail(`credentials/updated for "${ref}" emitted without a live credentials service`); + } + }); +}; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.d.ts new file mode 100644 index 0000000..47bca85 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.d.ts @@ -0,0 +1,29 @@ +/** + * Client-safe type surface of the credential-reference seam: the reference + * brand and the seam's Cordis event declaration. Types only — no runtime code, + * and nothing here reaches a Host-only symbol, so a Client compilation face + * reads exactly the signature the Host emits. + * + * @module @deepseek-ai/dsh-credentials/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Nominal reference to one credential: a POSIX-style environment-variable name. */ +export type CredentialRef = Branded<'CredentialRef'>; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * Committed change to a provider-managed credential source: a `set`, an + * `unset`, or an external edit observed in storage. Ambient + * process-environment changes are not observable and never emit. Listener + * failures are contained and logged — a sync throw and an async rejection + * alike — without changing the committed operation's outcome, except + * `INVARIANT`-coded failures, which rethrow after every listener ran; + * that rethrow reaches the emitter only from synchronous listeners, so + * invariant checks on this event must not be async functions. + * @param ref - the reference whose stored value changed. + * @mode emit + */ + 'credentials/updated'(ref: CredentialRef): void; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.js new file mode 100644 index 0000000..fdf8e86 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.js @@ -0,0 +1,10 @@ +/** + * Client-safe type surface of the credential-reference seam: the reference + * brand and the seam's Cordis event declaration. Types only — no runtime code, + * and nothing here reaches a Host-only symbol, so a Client compilation face + * reads exactly the signature the Host emits. + * + * @module @deepseek-ai/dsh-credentials/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/package.json new file mode 100644 index 0000000..e5f41be --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials/package.json @@ -0,0 +1,49 @@ +{ + "name": "@deepseek-ai/dsh-credentials", + "description": "Abstract credential seam (ctx.credentials): settings carry references to secrets, providers own the values", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/credentials/credentials" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.i18n.yaml new file mode 100644 index 0000000..55069ea --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/credentials/credentials/README.md +README.md: 62f5c6318ec04e9820a3d18ffa159d1561215760 +README.zh.md: 3c6ca0b454d4ff8a78bfcd29d1031584da27a5f1 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.md new file mode 100644 index 0000000..62f5c63 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.md @@ -0,0 +1,48 @@ +# dsh-credentials + +English | [中文](README.zh.md) + +Credential Service Definition (`ctx.credentials`). One doctrine, three consequences: + +**Configuration carries references to secrets, never the secrets.** A settings section or `cordis.yml` entry says `apiKeyEnv: DEEPSEEK_API_KEY`; the value behind that reference lives with a credential provider. So the settings document stays safe to sync and to render in a configuration UI, `describe()` can answer "is this configured, where from, can I write it" without ever holding a value, and rotating a secret touches no configuration file. + +**Consumers resolve per operation.** `resolve(ref)` is called at the start of each operation (the LLM adapters resolve once per model request) and never cached across operations — that read is what makes a changed credential reach the very next request without restarting any plugin. + +**An empty stored value is absent.** Everywhere: `resolve` skips it, `describe` reports it unconfigured. A blank can never masquerade as a configured secret. + +## Surface + +```ts +import type { Context } from '@deepseek-ai/cordis' +import { credentialRef } from '@deepseek-ai/dsh-credentials' + +declare const ctx: Context + +const ref = credentialRef('DEEPSEEK_API_KEY') // POSIX shell identifier, branded +const hit = await ctx.credentials.resolve(ref) // { value, source } | undefined +const info = await ctx.credentials.describe(ref) // { configured, source?, writable } — never the value +await ctx.credentials.set(ref, 'sk-…') // rejects while a read-only source shadows the ref +await ctx.credentials.unset(ref) // no-op when absent; same shadowing rule +``` + +`credentials/updated (ref)` fires after a committed change to a provider-managed source — a `set`, an `unset`, or an external edit observed in storage. Ambient process-environment changes are not observable and never emit. Consumers do not need the event (they re-resolve per operation); it exists for configuration UIs refreshing a "configured" badge. Its declaration lives in the client-safe `./types` subpath export together with the `CredentialRef` type it names (the package root re-exports the type), so a consumer outside the Host compilation face reads the very signature the Host emits instead of restating it. + +The shadowing rule on `set`/`unset` is deliberate fail-loud: when a read-only source (the live process environment, in the local provider) currently supplies the reference, a write would appear to succeed while resolution keeps returning the shadowing value — the seam rejects instead, and `describe().writable` lets a UI render the reference read-only up front. + +## Providers + +[`dsh-credentials-local`](../credentials-local/README.md) layers the inherited process environment over its managed `$DSH_HOME/.credentials.yaml` document, with the launcher's project and user `.env` layers as fallbacks. The seam shape leaves room for keyring-, helper-command-, and KMS-backed providers; a remote settings provider never needs to carry secrets. + +## Model Experience + +Indirectly, through the consuming LLM adapters: a resolved value authorizes their provider requests, and the adapter owns every model-visible surface. + +#### KV Cache effect + +No direct invalidation; credentials never enter a request prefix. + +## Known Limitations and Deferred Work + +- **No enumeration** — the seam answers questions about references it is given; configuration surfaces learn the references from settings schemas, so a `list()` has no current consumer. +- **References are environment-variable-shaped** — one flat POSIX-identifier namespace until a provider needs richer addressing. +- **Process-environment changes are invisible** — no event can fire for them; a UI only re-reads `describe()` on its own navigation. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.zh.md new file mode 100644 index 0000000..3c6ca0b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/README.zh.md @@ -0,0 +1,48 @@ +# dsh-credentials + +[English](README.md) | 中文 + +凭据 Service Definition(`ctx.credentials`)。一条准则,三个推论: + +**配置只携带对机密的引用,绝不携带机密本身。** settings 分节或 `cordis.yml` 条目写 `apiKeyEnv: DEEPSEEK_API_KEY`,引用背后的值存放在凭据提供方处。于是设置文档可以放心同步、放心渲染进配置界面;`describe()` 无需持有值就能回答「配置了吗、来自哪层、能否写入」;轮换机密不触碰任何配置文件。 + +**消费方按操作解析。** `resolve(ref)` 在每个操作开始时调用(LLM(大语言模型)适配器每次模型请求解析一次),绝不跨操作缓存——正是这次读取让改过的凭据无需重启任何插件就作用于下一次请求。 + +**空的存储值等于不存在。** 处处如此:`resolve` 跳过它,`describe` 报告未配置。空白永远不会伪装成已配置的机密。 + +## 接口 + +```ts +import type { Context } from '@deepseek-ai/cordis' +import { credentialRef } from '@deepseek-ai/dsh-credentials' + +declare const ctx: Context + +const ref = credentialRef('DEEPSEEK_API_KEY') // POSIX shell identifier, branded +const hit = await ctx.credentials.resolve(ref) // { value, source } | undefined +const info = await ctx.credentials.describe(ref) // { configured, source?, writable } — never the value +await ctx.credentials.set(ref, 'sk-…') // rejects while a read-only source shadows the ref +await ctx.credentials.unset(ref) // no-op when absent; same shadowing rule +``` + +`credentials/updated (ref)` 在提供方管理的来源发生已提交变更后触发——`set`、`unset` 或在存储中观察到的外部编辑。进程环境变量的变化不可观测,永不触发。消费方不需要该事件(它们按操作重新解析);它服务于配置界面刷新「已配置」徽标。它的声明住在 client-safe 的 `./types` 子路径出口,与其点名的 `CredentialRef` 类型同处一处(包根继续 re-export 该类型),于是 Host 编译面之外的消费方读到的正是 Host 发射的那一份签名,而不必再写一遍。 + +`set`/`unset` 的遮蔽规则有意采用明确报错的方式:当只读来源(本地提供方中即当前进程环境)正在提供该引用时,写入会表面成功而解析仍返回遮蔽值——seam 选择直接拒绝,并通过 `describe().writable` 让界面提前把该引用渲染为只读。 + +## 提供方 + +[`dsh-credentials-local`](../credentials-local/README.md) 把继承的进程环境叠加在其受管 `$DSH_HOME/.credentials.yaml` 文档之上,并以启动器的项目和用户 `.env` 层作为后备。该 seam 的接口为 keyring、辅助命令和 KMS 后端提供方预留了扩展空间;远端设置提供方永远不必携带机密。 + +## 模型体验 + +经由消费它的 LLM 适配器间接生效:解析出的值为适配器的提供方请求授权,所有模型可见接口都由适配器负责。 + +#### KV Cache 影响 + +无直接失效;凭据绝不进入请求前缀。 + +## 已知限制与暂缓事项 + +- **不提供枚举**——seam 只回答被问到的引用;配置界面从 settings schema 得知引用集合,`list()` 没有当前消费方。 +- **引用限定为环境变量形状**——在有提供方需要更丰富的寻址方式前,保持单一扁平的 POSIX 标识符命名空间。 +- **进程环境变化不可见**——不可能为其发事件;界面只能在自身导航时重新读取 `describe()`。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/index.js new file mode 100644 index 0000000..c812f7e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/index.js @@ -0,0 +1,67 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/index.js +/** +* Service Definition for the credential-reference capability seam (`ctx.credentials`). Settings and composition files carry +* *references* to secrets — environment-variable names — while providers own +* the actual values and their storage. Consumers resolve a reference once per +* operation, so a changed credential reaches the next operation without any +* plugin restart, and configuration surfaces describe a reference without +* ever seeing its value. +* @module @deepseek-ai/dsh-credentials +*/ +const REF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/; +/** +* Brand a raw string as a {@link CredentialRef}. +* @param value - candidate reference; a POSIX shell identifier such as `DEEPSEEK_API_KEY`. +* @returns the branded reference. +*/ +function credentialRef(value) { + if (!REF_PATTERN.test(value)) throw new TypeError(`credential ref "${value}" must match ${String(REF_PATTERN)}`); + return value; +} +/** +* Abstract credential service. Providers implement the four operations over +* their source layers; one seam-wide rule binds them all: an empty stored +* value is absent everywhere — `resolve` skips it, `describe` reports it +* unconfigured — so a blank never masquerades as a configured secret. +*/ +var CredentialProvider = class extends Service { + constructor(ctx) { + super(ctx, "credentials"); + } + /** + * Fan `credentials/updated` out with contained listener failures: every + * listener runs, and a sync throw or async rejection is logged without + * changing the committed operation's outcome — except `INVARIANT`-coded + * failures, which rethrow after every listener ran (the rethrow reaches the + * caller only from synchronous listeners, so invariant checks on this event + * must not be async functions). Providers call this only after the write or + * reload actually committed, so a broken observer can never make a durable + * change look failed. + * @param ref - the reference whose stored value changed. + */ + notifyUpdated(ref) { + let invariantFailure; + const args = ["credentials/updated", ref]; + for (const listener of this.ctx.events.dispatch("emit", args)) try { + const returned = listener(ref); + if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => { + this.warnListenerFailure(ref, error); + }); + } catch (error) { + if (error?.code === "INVARIANT") { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(ref, error); + } + if (invariantFailure !== void 0) throw invariantFailure; + } + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnListenerFailure(ref, error) { + this.ctx.logger.warn("credentials: a credentials/updated listener for \"%s\" failed", ref); + this.ctx.logger.warn(error); + } +}; +//#endregion +export { CredentialProvider, CredentialProvider as default, credentialRef }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/invariant.js new file mode 100644 index 0000000..3025ff7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/invariant.js @@ -0,0 +1,31 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-credentials`. +* @module @deepseek-ai/dsh-credentials/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-credentials"; +/** Cordis companion plugin name. */ +const name = "credentials-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* Install the commit-event lifecycle contract: `credentials/updated` names a +* committed provider-source change, so it can only fire while a credentials +* service is live — an emission after disposal means a provider leaked work +* past its teardown quiescence. The value relation itself (`describe` +* agreeing with `resolve`) is asynchronous provider I/O and stays pinned by +* each provider's own suite. +*/ +const install = (ctx, fail) => { + ctx.on("credentials/updated", (ref) => { + if (ctx.get("credentials") === void 0) fail(`credentials/updated for "${ref}" emitted without a live credentials service`); + }); +}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.d.ts new file mode 100644 index 0000000..b29288b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.d.ts @@ -0,0 +1,96 @@ +/** + * Service Definition for the credential-reference capability seam (`ctx.credentials`). Settings and composition files carry + * *references* to secrets — environment-variable names — while providers own + * the actual values and their storage. Consumers resolve a reference once per + * operation, so a changed credential reaches the next operation without any + * plugin restart, and configuration surfaces describe a reference without + * ever seeing its value. + * @module @deepseek-ai/dsh-credentials + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { CredentialRef } from './types.ts'; +export type { CredentialRef } from './types.ts'; +/** + * Brand a raw string as a {@link CredentialRef}. + * @param value - candidate reference; a POSIX shell identifier such as `DEEPSEEK_API_KEY`. + * @returns the branded reference. + */ +export declare function credentialRef(value: string): CredentialRef; +/** One resolved credential value and the source layer that supplied it. */ +export interface ResolvedCredential { + /** The non-empty secret value. */ + value: string; + /** Provider-defined source layer id (the local provider uses `env`, `file`, `project-env`, and `user-env`). */ + source: string; +} +/** Source and writability facts for one reference, safe for configuration UIs — never the value. */ +export interface CredentialInfo { + /** Whether {@link CredentialProvider.resolve} would currently return a value. */ + configured: boolean; + /** Source layer currently supplying the value; absent while unconfigured. */ + source?: string; + /** Whether {@link CredentialProvider.set} would currently succeed for this reference. */ + writable: boolean; +} +declare module '@deepseek-ai/cordis' { + interface Context { + credentials: CredentialProvider; + } +} +/** + * Abstract credential service. Providers implement the four operations over + * their source layers; one seam-wide rule binds them all: an empty stored + * value is absent everywhere — `resolve` skips it, `describe` reports it + * unconfigured — so a blank never masquerades as a configured secret. + */ +export declare abstract class CredentialProvider extends Service { + constructor(ctx: Context); + /** + * Resolve one reference to its current value. Resolution is per call: + * consumers re-resolve at each operation and must not cache across + * operations — that per-operation read is what makes a changed credential + * reach the next operation without a restart. + * @param ref - the reference to resolve. + * @returns the value and its source, or `undefined` while unconfigured. + */ + abstract resolve(ref: CredentialRef): Promise; + /** + * Describe one reference for configuration surfaces without exposing the + * value. + * @param ref - the reference to describe. + * @returns configured state, supplying source, and writability. + */ + abstract describe(ref: CredentialRef): Promise; + /** + * Durably store one value in the provider-managed writable source. Rejects + * while a read-only source shadows the reference — the write would appear + * to succeed while resolution keeps returning the shadowing value — and + * rejects an empty value (use {@link unset}). + * @param ref - the reference to store. + * @param value - the non-empty secret value. + */ + abstract set(ref: CredentialRef, value: string): Promise; + /** + * Remove one reference from the provider-managed writable source; removing + * an absent reference is a no-op. Rejects while a read-only source shadows + * the reference, like {@link set}. + * @param ref - the reference to remove. + */ + abstract unset(ref: CredentialRef): Promise; + /** + * Fan `credentials/updated` out with contained listener failures: every + * listener runs, and a sync throw or async rejection is logged without + * changing the committed operation's outcome — except `INVARIANT`-coded + * failures, which rethrow after every listener ran (the rethrow reaches the + * caller only from synchronous listeners, so invariant checks on this event + * must not be async functions). Providers call this only after the write or + * reload actually committed, so a broken observer can never make a durable + * change look failed. + * @param ref - the reference whose stored value changed. + */ + protected notifyUpdated(ref: CredentialRef): void; + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + private warnListenerFailure; +} +export default CredentialProvider; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.js new file mode 100644 index 0000000..e923e4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/index.js @@ -0,0 +1,78 @@ +/** + * Service Definition for the credential-reference capability seam (`ctx.credentials`). Settings and composition files carry + * *references* to secrets — environment-variable names — while providers own + * the actual values and their storage. Consumers resolve a reference once per + * operation, so a changed credential reaches the next operation without any + * plugin restart, and configuration surfaces describe a reference without + * ever seeing its value. + * @module @deepseek-ai/dsh-credentials + */ +import { Service } from '@deepseek-ai/cordis'; +const REF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/; +/** + * Brand a raw string as a {@link CredentialRef}. + * @param value - candidate reference; a POSIX shell identifier such as `DEEPSEEK_API_KEY`. + * @returns the branded reference. + */ +export function credentialRef(value) { + if (!REF_PATTERN.test(value)) { + throw new TypeError(`credential ref "${value}" must match ${String(REF_PATTERN)}`); + } + return value; +} +/** + * Abstract credential service. Providers implement the four operations over + * their source layers; one seam-wide rule binds them all: an empty stored + * value is absent everywhere — `resolve` skips it, `describe` reports it + * unconfigured — so a blank never masquerades as a configured secret. + */ +export class CredentialProvider extends Service { + constructor(ctx) { + super(ctx, 'credentials'); + } + /* jscpd:ignore-start -- deliberate symmetry with the settings seam's commit + fan-out: the contained-dispatch shape is the reviewed listener-lifecycle + contract, and extracting it would couple the two seams' event semantics. */ + /** + * Fan `credentials/updated` out with contained listener failures: every + * listener runs, and a sync throw or async rejection is logged without + * changing the committed operation's outcome — except `INVARIANT`-coded + * failures, which rethrow after every listener ran (the rethrow reaches the + * caller only from synchronous listeners, so invariant checks on this event + * must not be async functions). Providers call this only after the write or + * reload actually committed, so a broken observer can never make a durable + * change look failed. + * @param ref - the reference whose stored value changed. + */ + notifyUpdated(ref) { + let invariantFailure; + const args = ['credentials/updated', ref]; + for (const listener of this.ctx.events.dispatch('emit', args)) { + try { + const returned = listener(ref); + if (returned != null && typeof returned.then === 'function') { + void Promise.resolve(returned).then(undefined, (error) => { + this.warnListenerFailure(ref, error); + }); + } + } + catch (error) { + if (error?.code === 'INVARIANT') { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(ref, error); + } + } + if (invariantFailure !== undefined) + throw invariantFailure; + } + /* jscpd:ignore-end */ + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnListenerFailure(ref, error) { + this.ctx.logger.warn('credentials: a credentials/updated listener for "%s" failed', ref); + this.ctx.logger.warn(error); + } +} +export default CredentialProvider; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.d.ts new file mode 100644 index 0000000..900d083 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-credentials`. + * @module @deepseek-ai/dsh-credentials/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "credentials-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.js new file mode 100644 index 0000000..a63e9b7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/invariant.js @@ -0,0 +1,31 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-credentials`. + * @module @deepseek-ai/dsh-credentials/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-credentials'; +/** Cordis companion plugin name. */ +export const name = 'credentials-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * Install the commit-event lifecycle contract: `credentials/updated` names a + * committed provider-source change, so it can only fire while a credentials + * service is live — an emission after disposal means a provider leaked work + * past its teardown quiescence. The value relation itself (`describe` + * agreeing with `resolve`) is asynchronous provider I/O and stays pinned by + * each provider's own suite. + */ +const install = (ctx, fail) => { + ctx.on('credentials/updated', (ref) => { + if (ctx.get('credentials') === undefined) { + fail(`credentials/updated for "${ref}" emitted without a live credentials service`); + } + }); +}; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.d.ts new file mode 100644 index 0000000..47bca85 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.d.ts @@ -0,0 +1,29 @@ +/** + * Client-safe type surface of the credential-reference seam: the reference + * brand and the seam's Cordis event declaration. Types only — no runtime code, + * and nothing here reaches a Host-only symbol, so a Client compilation face + * reads exactly the signature the Host emits. + * + * @module @deepseek-ai/dsh-credentials/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Nominal reference to one credential: a POSIX-style environment-variable name. */ +export type CredentialRef = Branded<'CredentialRef'>; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * Committed change to a provider-managed credential source: a `set`, an + * `unset`, or an external edit observed in storage. Ambient + * process-environment changes are not observable and never emit. Listener + * failures are contained and logged — a sync throw and an async rejection + * alike — without changing the committed operation's outcome, except + * `INVARIANT`-coded failures, which rethrow after every listener ran; + * that rethrow reaches the emitter only from synchronous listeners, so + * invariant checks on this event must not be async functions. + * @param ref - the reference whose stored value changed. + * @mode emit + */ + 'credentials/updated'(ref: CredentialRef): void; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.js new file mode 100644 index 0000000..fdf8e86 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/lib/types/types.js @@ -0,0 +1,10 @@ +/** + * Client-safe type surface of the credential-reference seam: the reference + * brand and the seam's Cordis event declaration. Types only — no runtime code, + * and nothing here reaches a Host-only symbol, so a Client compilation face + * reads exactly the signature the Host emits. + * + * @module @deepseek-ai/dsh-credentials/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/package.json new file mode 100644 index 0000000..106e57d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials/package.json @@ -0,0 +1,49 @@ +{ + "name": "@deepseek-ai/dsh-credentials", + "description": "Abstract credential seam (ctx.credentials): settings carry references to secrets, providers own the values", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/credentials/credentials" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.i18n.yaml new file mode 100644 index 0000000..3fee674 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/goal/goal/README.md +README.md: 98765a809820bcd4aeba31e1dd4ef6e92eb30760 +README.zh.md: d133cb154523dcf47b8a033cc60411ac6f6e9c9e diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.md new file mode 100644 index 0000000..98765a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.md @@ -0,0 +1,58 @@ +# @deepseek-ai/dsh-goal + +English | [中文](README.zh.md) + +Event-sourced same-session goal state. The service retains one current completion objective in an agent's existing session while keeping permission to continue as process-local activation. The [goal-domain Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-persisted-same-session-goal-domain.md) owns the design rationale; the [goal type catalog](../../../docs/subsystems/goal.md) records the literal data shapes. + +## Config + +```yaml +- id: goal + name: '@deepseek-ai/dsh-goal' + config: + defaultMaxGoalRounds: 256 +``` + +`defaultMaxGoalRounds` must be a positive safe integer. `create()` materializes this deployment default internally before committing a goal; a request-level value overrides it. + +## Service contract + +`ctx.goals` accepts only the exact live `Agent` instance registered under its id. `get()` returns a detached `GoalView`; mutations use a `GoalRef { id, revision }` compare-and-set fence and reject stale refs. The service exposes create, edit, pause, resume, complete, block, and clear verbs through the generated region of [goal.md](../../../docs/subsystems/goal.md#cordis-surface). Creation default resolution is internal. `disarm()` is the lifecycle-only exception: it removes process-local continuation authority without writing a revision or emitting a mutation. + +At most one goal is current. Creation produces an active revision-one goal and arms it. A non-complete goal must be edited, transitioned, or cleared; a completed goal may be replaced by a globally fresh id. Edits retain phase, blocker reason, and activation. Pause, completion, blocking, and clear disarm activation. A block records a policy-owned lower-kebab-case code plus a normalized free-form explanation; provider limits, configured budgets, execution errors, and requests for human input all use this one durable phase rather than multiplying lifecycle states. Resume accepts a stopped phase or a disarmed active goal only while the configured round cap has remaining capacity; it clears any former blocker reason. An active armed goal rejects the redundant operation. + +Every mutation appends a durable `goal/change` event carrying the complete post-mutation snapshot; clear uses a revisioned tombstone. Goal state therefore does not depend on inbox placement, claim, admission, or discard. The session log is the only durable authority. + +Strict replay derives lifecycle mutations only from `goal/change` and rejects malformed shapes, discontinuous revisions, illegal lifecycle transitions, non-monotonic per-goal timestamps, and non-sequential admitted goal rounds. Positive rounds advance only on admitted goal-sourced `user/message` events. Mutation timestamps clamp against the preceding goal update when wall time moves backward. Incremental replay retains its cursor at the first corrupt event, and `goal/changed` fires after the durable event commits with listener failures contained. + +Activation is never persisted. A fresh cache and every `agent/session-start` edge disarm it even when replay finds an active durable phase. A continuation driver also calls `disarm()` before unload or after durability uncertainty. Session resume, fork, and driver replacement therefore retain the objective, phase, revisions, and admitted-round count without initiating work; a later explicit resume mutation must arm continuation. + +The separately published `./invariant` companion maintains an independent fold of each attached session. It rejects malformed goal changes, discontinuous revisions, illegal lifecycle transitions, timestamp regressions, and non-sequential admitted rounds before the candidate event enters the durable log. + +## Extension points + +Policy plugins call the service verbs and react to the scoped `goal/changed` event. A continuation consumer admits rounds as `user/message` events with `GoalMessageSource`; ordinary human turns never increment `roundsStarted`. Consumers use the `Agent` interface and events rather than importing `dsh-agent-loop`. + +## Model Experience + +### Goal-state mutation + +#### What the model sees + +Goal mutations do not inject model context. Tools such as `get_goal` return the current state, and a continuation consumer may render the objective and round state when it schedules model work. A future always-visible goal context belongs in a separate context plugin rather than the persistence path. + +#### Token effect + +Goal mutation events add no model tokens by themselves. Tool results and scheduled continuation prompts account for their own visible state. + +#### KV Cache effect + +There is no KV-cache effect until another component exposes goal state in model-visible input. + +## Known Limitations and Deferred Work + +- **State, not scheduling** — this package does not decide when an armed goal continues, retry abnormal failures, or cancel an active turn; those policies belong to agent-seam consumers. +- **Round-count budget only** — `maxGoalRounds` does not meter tokens, currency, wall time, or provider quotas. +- **No independent evaluator** — the caller that records completion or blocking is authoritative; evaluator-backed certification is deferred to a separate policy layer. +- **One current goal** — parallel objectives and a separate goal database are intentionally absent; history remains available in the session log after replacement or clear. +- **Trusted in-process producers** — a plugin with direct `Session` access can append counterfeit `goal/change` data. Strict replay detects malformed or inconsistent records and leaves goal access failed at that record until the log is repaired; this is integrity detection, not plugin isolation. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.zh.md new file mode 100644 index 0000000..d133cb1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/README.zh.md @@ -0,0 +1,58 @@ +# @deepseek-ai/dsh-goal + +[English](README.md) | 中文 + +事件溯源的同会话目标状态。该服务在 agent(智能体)的现有会话中保留一个当前待完成目标,同时将继续执行的权限作为进程本地续行启用状态。[goal 领域 Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-persisted-same-session-goal-domain.md) 负责设计理由;[goal 类型目录](../../../docs/subsystems/goal.md)记录具体的数据形状。 + +## 配置 + +```yaml +- id: goal + name: '@deepseek-ai/dsh-goal' + config: + defaultMaxGoalRounds: 256 +``` + +`defaultMaxGoalRounds` 必须是正的安全整数。`create()` 会在提交目标前于内部物化这项部署默认值;请求级取值可以覆盖它。 + +## 服务约定 + +`ctx.goals` 只接受以对应 id 注册的完全相同的活跃 `Agent` 实例。`get()` 返回与内部状态脱离的 `GoalView`;变更以 `GoalRef { id, revision }` 作为比较并设置防护,并拒绝陈旧引用。服务通过 [goal.md](../../../docs/subsystems/goal.md#cordis-surface) 的生成区块公开 create、edit、pause、resume、complete、block 和 clear 动词。创建默认值在内部解析。`disarm()` 是仅供生命周期使用的例外:它移除进程本地续行权限,不写入新 revision,也不发出变更事件。 + +最多只有一个当前目标。创建操作会生成 revision 为 1、phase 为 active 的目标并启用续行。未完成的目标必须编辑、转换或清除;已完成目标可以由拥有全局未使用过的 id 的目标替换。编辑会保留 phase、blocker reason 与 activation。暂停、完成、阻塞和清除都会停用续行。阻塞会记录策略自有的 lower-kebab-case 代码和规范化的自由文本说明;提供方限制、配置预算、执行错误与请求人工输入都使用这一种持久 phase,不会扩增生命周期状态。只有配置的 Round 上限仍有剩余容量时,resume 才接受已停止 phase 或 phase 为 active 但已停用续行的目标;它会清除原 blocker reason。phase 为 active 且已启用续行的目标会拒绝冗余操作。 + +每次变更都会追加持久的 `goal/change` 事件,其中携带变更后的完整快照;clear 使用带 revision 的 tombstone。因此,goal 状态不依赖 inbox 放置、领取、准入或丢弃。会话日志是唯一的持久权威。 + +严格回放只从 `goal/change` 派生生命周期变更,并拒绝形状错误、不连续 revision、非法生命周期转换、每目标时间戳非单调,以及不连续的已准入 Goal Round。只有来源为 goal 且已准入的 `user/message` 事件会推进正数 Round。挂钟时间倒退时,变更时间戳会限制在不早于上一次目标更新的值。增量回放会把游标保留在第一个损坏事件处;`goal/changed` 会在持久事件提交后触发,监听器失败会被隔离处理。 + +续行启用状态绝不持久化。新缓存与每次触发 `agent/session-start` 时都会停用续行,即使回放找到了持久 phase 为 active 的目标。续行驱动器在卸载前或持久性不确定后也会调用 `disarm()`。因此,会话恢复、fork 与驱动器替换会保留目标、phase、revision 和已准入 Round 数量,却不会启动工作;之后必须通过显式 resume 变更重新启用续行。 + +单独发布的 `./invariant` 配套模块会为每个已挂接会话维护独立折叠。它会在候选事件进入持久日志前拒绝格式错误的 goal 变更、不连续 revision、非法生命周期转换、时间戳回退,以及不连续的已准入 Round。 + +## 扩展点 + +策略插件调用服务动词,并响应限定范围的 `goal/changed` 事件。续行消费方将 Round 准入为 `user/message` 事件,并携带 `GoalMessageSource`;普通的人类轮次绝不会增加 `roundsStarted`。消费方使用 `Agent` 接口和事件,不导入 `dsh-agent-loop`。 + +## 模型体验 + +### 目标状态变更 + +#### 模型看到的内容 + +Goal 变更不会注入模型上下文。`get_goal` 等工具返回当前状态;继续执行消费方可以在调度模型工作时渲染目标描述与 Round 状态。未来如果需要始终可见的 goal 上下文,应由独立上下文插件实现,而不是放在持久化路径中。 + +#### Token 影响 + +Goal 变更事件本身不增加模型 token。工具结果和续行调度提示词各自暴露的状态会分别计入 token 用量。 + +#### KV Cache 影响 + +在其他组件把 goal 状态暴露为模型可见输入之前,不会影响 KV Cache。 + +## 已知限制与暂缓事项 + +- **只负责状态,不负责任务调度**:此包不决定已启用续行的目标何时继续,不重试异常失败,也不取消活跃轮次;这些策略属于 agent seam 消费方。 +- **只有 Round 数量预算**:`maxGoalRounds` 不计量 token、货币、挂钟时间或提供方配额。 +- **没有独立评估器**:记录完成或阻塞的调用方拥有最终决定权;由评估器支持的认证暂缓到独立策略层。 +- **只有一个当前目标**:系统有意不支持并行目标或独立目标数据库;替换或清除后,历史仍可在会话日志中读取。 +- **信任进程内生产方**:能直接访问 `Session` 的插件可以追加伪造的 `goal/change` 数据。严格回放会检测格式错误或不一致的记录,并使 goal 访问从该记录起失败,直到日志修复;这是完整性检测,不是插件隔离。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/index.js new file mode 100644 index 0000000..914d0eb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/index.js @@ -0,0 +1,827 @@ +import { randomUUID } from "node:crypto"; +import z from "@deepseek-ai/schemastery"; +import { z as z$1 } from "zod"; +import { agentEvents } from "@deepseek-ai/dsh-agent"; +import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol"; +import { HarnessError } from "@deepseek-ai/dsh-llm"; +//#region lib/types/runtime.js +/** Runtime constructors and protocol constants for the goal domain. */ +/** Version of the goal change embedded in a round-zero message source. */ +const GOAL_CHANGE_VERSION = 1; +/** +* Brand a string as a goal id. +* @param id - raw goal identifier. +* @returns the same string with the compile-time brand. +*/ +function GoalId(id) { + return id; +} +/** Error returned by the goal domain boundary. */ +var GoalError = class extends HarnessError { + /** + * @param message - human-readable rejection reason. + * @param code - stable machine-routable classification. + */ + constructor(message, code) { + super(message, code); + } +}; +//#endregion +//#region lib/types/fold.js +/** Pure replay fold and strict decoder for durable goal changes. */ +const SNAPSHOT_OPERATIONS = new Set([ + "create", + "edit", + "pause", + "resume", + "complete", + "block" +]); +const PHASES = new Set([ + "active", + "paused", + "blocked", + "complete" +]); +/** +* Build an empty replay accumulator. +* @returns mutable state with no current goal or prior ref. +*/ +function emptyGoalFoldState() { + return { + goal: void 0, + roundsStarted: 0, + createdAt: void 0, + updatedAt: void 0, + lastRef: void 0, + seenGoalIds: /* @__PURE__ */ new Set() + }; +} +/** Whether a value is a JSON record rather than an array. */ +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +/** Require one positive safe integer. */ +function positiveInteger(value, field) { + if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) throw new Error(`goal change ${field} must be a positive safe integer`); + return value; +} +/** Require one non-negative safe integer. */ +function nonNegativeInteger(value, field) { + if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new Error(`goal change ${field} must be a non-negative safe integer`); + return value; +} +/** Decode one canonical blocker explanation. */ +function decodeBlockReason(value) { + if (!isRecord(value) || Object.keys(value).sort().join(",") !== "code,message") throw new Error("goal change goal.blockedReason must have exactly code and message fields"); + if (typeof value["code"] !== "string" || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(value["code"])) throw new Error("goal change goal.blockedReason.code must be lower-kebab-case"); + if (typeof value["message"] !== "string" || value["message"].trim().length === 0 || value["message"] !== value["message"].trim()) throw new Error("goal change goal.blockedReason.message must be non-empty and normalized"); + return { + code: value["code"], + message: value["message"] + }; +} +/** Decode and validate one snapshot. */ +function decodeSnapshot(value) { + if (!isRecord(value)) throw new Error("goal change goal must be a record"); + if (typeof value["id"] !== "string" || value["id"].length === 0) throw new Error("goal change goal.id must be a non-empty string"); + if (typeof value["objective"] !== "string" || value["objective"].trim().length === 0 || value["objective"] !== value["objective"].trim()) throw new Error("goal change goal.objective must be non-empty and normalized"); + if (typeof value["phase"] !== "string" || !PHASES.has(value["phase"])) throw new Error("goal change goal.phase is invalid"); + const phase = value["phase"]; + const expectedKeys = phase === "blocked" ? "blockedReason,id,maxGoalRounds,objective,phase,revision" : "id,maxGoalRounds,objective,phase,revision"; + if (Object.keys(value).sort().join(",") !== expectedKeys) throw new Error(`goal change goal for phase ${phase} must have exactly ${expectedKeys} fields`); + return { + id: GoalId(value["id"]), + revision: positiveInteger(value["revision"], "goal.revision"), + objective: value["objective"], + phase, + maxGoalRounds: positiveInteger(value["maxGoalRounds"], "goal.maxGoalRounds"), + ...phase === "blocked" ? { blockedReason: decodeBlockReason(value["blockedReason"]) } : {} + }; +} +/** Decode and validate one ref. */ +function decodeRef(value) { + if (!isRecord(value) || Object.keys(value).sort().join(",") !== "id,revision") throw new Error("goal clear tombstone must have exactly id and revision fields"); + if (typeof value["id"] !== "string" || value["id"].length === 0) throw new Error("goal clear tombstone id must be a non-empty string"); + return { + id: GoalId(value["id"]), + revision: positiveInteger(value["revision"], "cleared.revision") + }; +} +/** +* Decode a value that declares itself as a goal change. Unrelated values +* return `undefined`; malformed goal changes fail replay loudly. +* @param value - candidate source change. +* @returns validated goal change or `undefined` for another value kind. +*/ +function decodeGoalChange(value) { + if (!isRecord(value) || value["kind"] !== "goal/change") return void 0; + if (value["version"] !== 1) throw new Error(`unsupported goal change version ${String(value["version"])}`); + if (value["operation"] === "clear") { + const allowed = [ + "cleared", + "clearedAt", + "kind", + "operation", + "version" + ]; + if (Object.keys(value).sort().join(",") !== allowed.sort().join(",")) throw new Error(`goal clear change must have exactly ${allowed.sort().join(",")} fields`); + return { + kind: "goal/change", + version: 1, + operation: "clear", + cleared: decodeRef(value["cleared"]), + clearedAt: nonNegativeInteger(value["clearedAt"], "clearedAt") + }; + } + if (typeof value["operation"] !== "string" || !SNAPSHOT_OPERATIONS.has(value["operation"])) throw new Error("goal change operation is invalid"); + const allowed = [ + "createdAt", + "goal", + "kind", + "operation", + "roundsStarted", + "updatedAt", + "version" + ]; + if (Object.keys(value).sort().join(",") !== allowed.sort().join(",")) throw new Error(`goal snapshot change must have exactly ${allowed.sort().join(",")} fields`); + const createdAt = nonNegativeInteger(value["createdAt"], "createdAt"); + const updatedAt = nonNegativeInteger(value["updatedAt"], "updatedAt"); + if (updatedAt < createdAt) throw new Error("goal change updatedAt cannot precede createdAt"); + return { + kind: "goal/change", + version: 1, + operation: value["operation"], + goal: decodeSnapshot(value["goal"]), + roundsStarted: nonNegativeInteger(value["roundsStarted"], "roundsStarted"), + createdAt, + updatedAt + }; +} +/** Narrow model attribution to a valid goal source. */ +function goalSource(source) { + if (source.kind !== "goal") return void 0; + if (typeof source.goalId !== "string" || source.goalId.length === 0 || !Number.isSafeInteger(source.revision) || source.revision < 1 || !Number.isSafeInteger(source.round) || source.round < 1) throw new Error("goal message source is invalid"); + return source; +} +/** Require two snapshots to retain fields that only `edit` may replace. */ +function requireSameDefinition(current, next, operation) { + if (next.objective !== current.objective || next.maxGoalRounds !== current.maxGoalRounds) throw new Error(`goal ${operation} cannot change objective or maxGoalRounds`); +} +/** Require one exact next revision of the current goal. */ +function requireNextRevision(current, next, operation) { + if (next.id !== current.id || next.revision !== current.revision + 1) throw new Error(`goal ${operation} must advance the current goal by one revision`); +} +/** Validate one non-create snapshot operation against the preceding projection. */ +function validateSnapshotTransition(state, change, current) { + const next = change.goal; + requireNextRevision(current, next, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === void 0) throw new Error("current goal fold lacks updatedAt"); + if (change.createdAt !== state.createdAt || change.updatedAt < state.updatedAt || change.roundsStarted !== state.roundsStarted) throw new Error(`goal ${change.operation} does not preserve the current counters and timestamps`); + switch (change.operation) { + case "edit": + if (next.phase !== current.phase || JSON.stringify(next.blockedReason) !== JSON.stringify(current.blockedReason)) throw new Error("goal edit cannot change phase or blocked reason"); + break; + case "pause": + requireSameDefinition(current, next, change.operation); + if (current.phase !== "active" || next.phase !== "paused") throw new Error("goal pause has an invalid phase transition"); + break; + case "resume": + requireSameDefinition(current, next, change.operation); + if (!new Set([ + "active", + "paused", + "blocked" + ]).has(current.phase) || next.phase !== "active" || state.roundsStarted >= next.maxGoalRounds) throw new Error("goal resume has an invalid phase transition or exhausted round budget"); + break; + case "complete": + requireSameDefinition(current, next, change.operation); + if (current.phase === "complete" || next.phase !== "complete") throw new Error("goal complete has an invalid phase transition"); + break; + case "block": + requireSameDefinition(current, next, change.operation); + if (current.phase !== "active" || next.phase !== "blocked") throw new Error("goal block has an invalid phase transition"); + break; + /* v8 ignore start -- the caller excludes create and GoalOperation is closed; these arms retain fail-loud exhaustiveness */ + case "create": throw new Error("goal create cannot be validated as a current-goal transition"); + default: + change.operation; + throw new Error("unknown goal snapshot operation"); + } +} +/** +* Return the revision identity carried by a snapshot or tombstone. +* @param change - decoded goal mutation. +* @returns stable identity used to reconcile a deferred change with its log event. +*/ +function goalChangeRef(change) { + return change.operation === "clear" ? change.cleared : { + id: change.goal.id, + revision: change.goal.revision + }; +} +/** +* Validate and apply one decoded change to a mutable accumulator. +* @param state - preceding durable goal projection. +* @param change - decoded full snapshot or clear tombstone. +*/ +function applyGoalChange(state, change) { + const ref = goalChangeRef(change); + if (change.operation === "clear") { + const current = state.goal; + if (current === void 0) throw new Error("goal clear requires a current goal"); + requireNextRevision(current, change.cleared, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === void 0) throw new Error("current goal fold lacks updatedAt"); + if (change.clearedAt < state.updatedAt) throw new Error("goal clear timestamp cannot precede the current goal update"); + state.goal = void 0; + state.roundsStarted = 0; + state.createdAt = void 0; + state.updatedAt = void 0; + state.lastRef = ref; + return; + } + if (change.operation === "create") { + if (change.goal.revision !== 1 || change.goal.phase !== "active" || change.roundsStarted !== 0 || state.goal !== void 0 && state.goal.phase !== "complete" || state.seenGoalIds.has(change.goal.id)) throw new Error("goal create requires a fresh active revision-one goal with zero rounds"); + state.seenGoalIds.add(change.goal.id); + } else { + const current = state.goal; + if (current === void 0) throw new Error(`goal ${change.operation} requires a current goal`); + validateSnapshotTransition(state, change, current); + } + state.goal = change.goal; + state.roundsStarted = change.roundsStarted; + state.createdAt = change.createdAt; + state.updatedAt = change.updatedAt; + state.lastRef = ref; +} +/** +* Apply one session event to the strict durable goal fold. +* @param state - mutable fold accumulator. +* @param event - next event in sequence order. +*/ +function applyGoalEvent(state, event) { + if (event.type === "goal/change") { + const change = decodeGoalChange(event.data); + /* v8 ignore next -- the event's declared payload always identifies itself as a goal change. */ + if (change === void 0) throw new Error(`goal change at session event ${event.seq} has an invalid kind`); + applyGoalChange(state, change); + return; + } + if (event.type === "user/message") { + const source = goalSource(event.data.source); + if (source === void 0) return; + const current = state.goal; + if (current === void 0 || current.phase !== "active" || source.goalId !== current.id || source.revision !== current.revision || source.round !== state.roundsStarted + 1 || source.round > current.maxGoalRounds) throw new Error(`goal round at session event ${event.seq} is not the next admitted round of the active goal`); + state.roundsStarted = source.round; + } +} +/** +* Fold current goal state from a contiguous session event log. +* @param events - session events in sequence order. +* @returns a fresh durable projection; activation is deliberately absent. +*/ +function foldGoal(events) { + const state = emptyGoalFoldState(); + for (const event of events) applyGoalEvent(state, event); + return { + ...state.goal === void 0 ? {} : { goal: { ...state.goal } }, + roundsStarted: state.roundsStarted, + ...state.createdAt === void 0 ? {} : { createdAt: state.createdAt }, + ...state.updatedAt === void 0 ? {} : { updatedAt: state.updatedAt }, + ...state.lastRef === void 0 ? {} : { lastRef: { ...state.lastRef } } + }; +} +//#endregion +//#region lib/types/index.js +/** +* Same-session goal domain: event-sourced state, compare-and-set mutations, +* and process-local continuation activation. +* @module @deepseek-ai/dsh-goal +*/ +var __runInitializers = function(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + return useValue ? value : void 0; +}; +var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function(f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +/** Wire payload schema of the `goal` projection (whole current goal or pre-create/cleared null). */ +const goalProjectionSchema = z$1.union([z$1.object({ + goal: z$1.object({ + id: z$1.string().min(1), + revision: z$1.number().int().positive(), + objective: z$1.string().min(1), + phase: z$1.union([ + z$1.literal("active"), + z$1.literal("paused"), + z$1.literal("blocked"), + z$1.literal("complete") + ]), + blockedReason: z$1.object({ + code: z$1.string(), + message: z$1.string() + }).optional(), + maxGoalRounds: z$1.number().int().positive() + }), + roundsStarted: z$1.number().int().nonnegative(), + createdAt: z$1.number(), + updatedAt: z$1.number() +}), z$1.null()]); +/** +* Light last-wins fold of the `goal` projection unit. Unlike the strict +* replay fold (fold.ts: transition validation, fail-loud on malformed +* changes, Set-typed state), this transition is projection-grade: the state +* is plain JSON (persisted-cache precondition), any non-goal or malformed +* event returns the same reference (the registry's Object.is gate — the +* title/todos posture), and correctness of the written change is the write +* side's job (GoalService validated it before appending; the package +* invariant rejects a violating stream fail-loud where it is installed). +* @param state - the projection covering all prior events. +* @param event - the next committed session event. +* @returns the next projection (same reference when the event is not a goal change). +*/ +function applyGoalProjection(state, event) { + if (event.type !== "goal/change") return state; + let change; + try { + change = decodeGoalChange(event.data); + } catch (_invalidPersistedGoalChange) { + return state; + } + if (change === void 0) return state; + return change.operation === "clear" ? null : { + goal: change.goal, + roundsStarted: change.roundsStarted, + createdAt: change.createdAt, + updatedAt: change.updatedAt + }; +} +/** Validate a caller-visible positive safe-integer round cap. */ +function resolveMaxGoalRounds(value) { + if (!Number.isSafeInteger(value) || value < 1) throw new GoalError("maxGoalRounds must be a positive safe integer", "GOAL_INVALID_MAX_ROUNDS"); + return value; +} +/** Validate and normalize an objective at the domain boundary. */ +function resolveObjective(value) { + if (typeof value !== "string" || value.trim().length === 0) throw new GoalError("goal objective must be a non-empty string", "GOAL_INVALID_OBJECTIVE"); + return value.trim(); +} +/** Materialize deployment defaults and validate one create request. */ +function resolveCreateGoal(request, defaultMaxGoalRounds) { + return { + objective: resolveObjective(request.objective), + maxGoalRounds: resolveMaxGoalRounds(request.maxGoalRounds ?? defaultMaxGoalRounds) + }; +} +/** Validate and detach one policy-owned blocker explanation. */ +function resolveBlockReason(reason) { + const record = typeof reason === "object" && reason !== null && !Array.isArray(reason) ? reason : void 0; + const code = record?.["code"]; + const message = record?.["message"]; + if (typeof code !== "string" || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(code) || typeof message !== "string" || message.trim().length === 0) throw new GoalError("goal block reason requires a lower-kebab-case code and a non-empty message", "GOAL_INVALID_BLOCK_REASON"); + return { + code, + message: message.trim() + }; +} +/** Goal service (`ctx.goals`) backed exclusively by the owning session log. */ +let GoalService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _edit_decorators; + let _pause_decorators; + let _resume_decorators; + let _complete_decorators; + let _clear_decorators; + let _remoteExportCreate_decorators; + return class GoalService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _edit_decorators = [Remote("edit")]; + _pause_decorators = [Remote("pause")]; + _resume_decorators = [Remote("resume")]; + _complete_decorators = [Remote("complete")]; + _clear_decorators = [Remote("clear")]; + _remoteExportCreate_decorators = [Remote("create")]; + __esDecorate(this, null, _edit_decorators, { + kind: "method", + name: "edit", + static: false, + private: false, + access: { + has: (obj) => "edit" in obj, + get: (obj) => obj.edit + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _pause_decorators, { + kind: "method", + name: "pause", + static: false, + private: false, + access: { + has: (obj) => "pause" in obj, + get: (obj) => obj.pause + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resume_decorators, { + kind: "method", + name: "resume", + static: false, + private: false, + access: { + has: (obj) => "resume" in obj, + get: (obj) => obj.resume + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _complete_decorators, { + kind: "method", + name: "complete", + static: false, + private: false, + access: { + has: (obj) => "complete" in obj, + get: (obj) => obj.complete + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _clear_decorators, { + kind: "method", + name: "clear", + static: false, + private: false, + access: { + has: (obj) => "clear" in obj, + get: (obj) => obj.clear + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _remoteExportCreate_decorators, { + kind: "method", + name: "remoteExportCreate", + static: false, + private: false, + access: { + has: (obj) => "remoteExportCreate" in obj, + get: (obj) => obj.remoteExportCreate + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { + enumerable: true, + configurable: true, + writable: true, + value: _metadata + }); + } + static inject = ["agents"]; + static Config = z.object({ defaultMaxGoalRounds: z.number().default(256) }); + resolved = __runInitializers(this, _instanceExtraInitializers); + caches = /* @__PURE__ */ new WeakMap(); + constructor(ctx, config = {}) { + super(ctx, "goals"); + this.resolved = { defaultMaxGoalRounds: resolveMaxGoalRounds(config.defaultMaxGoalRounds ?? 256) }; + ctx.on("agent/session-start", ({ agent }) => { + this.cache(agent.session).activation = "disarmed"; + }); + ctx.inject(["sessionProjections"], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: "goal", + schema: goalProjectionSchema, + init: () => null, + apply: applyGoalProjection, + view: (state) => state, + stateVersion: 4 + }); + }); + } + /** + * Read the current goal for one exact live agent. + * @param agent - owning live agent. + * @returns a fresh view or `undefined` when no goal is current. + * @throws {@link GoalError} when the agent is not the registry's live instance. + */ + get(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + return this.view(cache); + } + /** + * Remove process-local continuation authority without changing durable goal + * phase or revision. Lifecycle owners use this before unloading a driver; + * a later human-authorized {@link resume} records the new activation edge. + * @param agent - owning live agent. + * @returns a fresh disarmed view, or `undefined` when no goal is current. + */ + disarm(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + cache.activation = "disarmed"; + return this.view(cache); + } + /** + * Create and arm a goal. A completed goal may be replaced; every other + * current phase must be cleared or resumed instead. + * @param agent - owning live agent. + * @param request - objective and optional round cap. + * @returns the created live view. + */ + create(agent, request) { + const spec = resolveCreateGoal(request, this.resolved.defaultMaxGoalRounds); + const cache = this.prepareMutation(agent); + const current = cache.state.goal; + if (current !== void 0 && current.phase !== "complete") throw new GoalError(`goal "${current.id}" already exists with phase "${current.phase}"`, "GOAL_ALREADY_EXISTS"); + const now = Date.now(); + const goal = { + id: GoalId(`goal-${randomUUID()}`), + revision: 1, + objective: spec.objective, + phase: "active", + maxGoalRounds: spec.maxGoalRounds + }; + return this.commitSnapshot(agent, cache, "create", goal, 0, now, now, "armed"); + } + /** + * Edit objective and/or round cap without changing phase. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param request - at least one replacement field. + * @returns the edited view. + */ + edit(agent, ref, request) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (request.objective === void 0 && request.maxGoalRounds === void 0) throw new GoalError("goal edit requires objective and/or maxGoalRounds", "GOAL_INVALID_EDIT"); + const goal = { + ...current, + revision: current.revision + 1, + ...request.objective === void 0 ? {} : { objective: resolveObjective(request.objective) }, + ...request.maxGoalRounds === void 0 ? {} : { maxGoalRounds: resolveMaxGoalRounds(request.maxGoalRounds) } + }; + return this.commitCurrent(agent, cache, "edit", goal, cache.activation); + } + /** + * Pause an active goal and disarm automatic continuation. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the paused view. + */ + pause(agent, ref) { + return this.transition(agent, ref, "pause", ["active"], "paused", "disarmed"); + } + /** + * Resume and arm a stopped goal, or rearm an active goal after a + * session-start edge, while its round budget still has capacity. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the active view. + */ + resume(agent, ref) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + const resumable = [ + "active", + "paused", + "blocked" + ]; + if (!resumable.includes(current.phase)) throw this.transitionError(current, "resume", resumable); + if (current.phase === "active" && cache.activation === "armed") throw new GoalError(`goal "${current.id}" is already active and armed`, "GOAL_INVALID_TRANSITION"); + if (cache.state.roundsStarted >= current.maxGoalRounds) throw new GoalError(`goal "${current.id}" exhausted ${current.maxGoalRounds} goal rounds; increase maxGoalRounds before resuming`, "GOAL_INVALID_TRANSITION"); + return this.commitCurrent(agent, cache, "resume", this.withPhase(current, "active"), "armed"); + } + /** + * Mark a current non-complete goal complete and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the completed view. + */ + complete(agent, ref) { + return this.transition(agent, ref, "complete", [ + "active", + "paused", + "blocked" + ], "complete", "disarmed"); + } + /** + * Mark an active goal blocked and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param reason - policy-owned stable code and human-readable explanation. + * @returns the blocked view with its durable reason. + */ + block(agent, ref, reason) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (current.phase !== "active") throw this.transitionError(current, "block", ["active"]); + return this.commitCurrent(agent, cache, "block", { + ...this.withPhase(current, "blocked"), + blockedReason: resolveBlockReason(reason) + }, "disarmed"); + } + /** + * Clear the current goal while retaining a durable tombstone and history. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the tombstone ref whose revision is one past the cleared snapshot. + */ + clear(agent, ref) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + const tombstone = { + id: current.id, + revision: current.revision + 1 + }; + const change = { + kind: "goal/change", + version: 1, + operation: "clear", + cleared: tombstone, + clearedAt: this.nextMutationTime(cache) + }; + this.commit(agent, cache, change, "disarmed"); + return { ...tombstone }; + } + /** Resolve and validate the cache used by a mutation. */ + prepareMutation(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + return cache; + } + /** Reject stale or missing current-state refs. */ + expectCurrent(cache, ref) { + const current = cache.state.goal; + if (current === void 0) throw new GoalError("no current goal", "GOAL_NOT_FOUND"); + if (ref.id !== current.id || ref.revision !== current.revision) throw new GoalError(`stale goal ref "${ref.id}" revision ${ref.revision}; current is "${current.id}" revision ${current.revision}`, "GOAL_STALE_REVISION"); + return current; + } + /** Enforce exact live-agent identity rather than trusting a matching id. */ + assertLive(agent) { + if (this.ctx.agents.get(agent.id) !== agent) throw new GoalError(`agent "${agent.id}" is not live in this registry`, "GOAL_AGENT_NOT_LIVE"); + } + /** Return the per-session cache, folding a seed once with activation disarmed. */ + cache(session) { + let cache = this.caches.get(session); + if (cache !== void 0) return cache; + const state = emptyGoalFoldState(); + for (const event of session.events) applyGoalEvent(state, event); + cache = { + state, + activation: "disarmed", + observedSeq: session.seq, + pendingActivation: void 0 + }; + this.caches.set(session, cache); + return cache; + } + /** Incrementally observe durable events and reconcile local activation intent. */ + sync(session, cache) { + for (const event of session.events.slice(cache.observedSeq)) { + applyGoalEvent(cache.state, event); + if (event.type === "goal/change") cache.activation = cache.pendingActivation?.seq === event.seq ? cache.pendingActivation.activation : "disarmed"; + cache.observedSeq += 1; + } + } + /** Build a new revision with one replacement phase. */ + withPhase(current, phase) { + return { + id: current.id, + revision: current.revision + 1, + objective: current.objective, + phase, + maxGoalRounds: current.maxGoalRounds + }; + } + /** Shared validated phase transition. */ + transition(agent, ref, operation, allowed, phase, activation) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (!allowed.includes(current.phase)) throw this.transitionError(current, operation, allowed); + return this.commitCurrent(agent, cache, operation, this.withPhase(current, phase), activation); + } + /** Render a stable invalid-transition error. */ + transitionError(current, operation, allowed) { + return new GoalError(`cannot ${operation} goal "${current.id}" from phase "${current.phase}"; expected ${allowed.join(" or ")}`, "GOAL_INVALID_TRANSITION"); + } + /** Commit a mutation that retains the current goal's derived counters/times. */ + commitCurrent(agent, cache, operation, goal, activation) { + const createdAt = cache.state.createdAt; + /* v8 ignore next -- strict replay and every snapshot commit set createdAt whenever a current goal exists */ + if (createdAt === void 0) throw new Error("current goal cache lacks createdAt"); + return this.commitSnapshot(agent, cache, operation, goal, cache.state.roundsStarted, createdAt, this.nextMutationTime(cache), activation); + } + /** Clamp a current goal's next timestamp across backward wall-clock movement. */ + nextMutationTime(cache) { + const updatedAt = cache.state.updatedAt; + /* v8 ignore next -- strict replay and every snapshot commit set updatedAt whenever a current goal exists */ + if (updatedAt === void 0) throw new Error("current goal cache lacks updatedAt"); + return Math.max(Date.now(), updatedAt); + } + /** Build and commit one full-snapshot mutation. */ + commitSnapshot(agent, cache, operation, goal, roundsStarted, createdAt, updatedAt, activation) { + const change = { + kind: "goal/change", + version: 1, + operation, + goal, + roundsStarted, + createdAt, + updatedAt + }; + this.commit(agent, cache, change, activation); + const view = this.view(cache); + /* v8 ignore next -- the durable goal event installs the snapshot before this read */ + if (view === void 0) throw new Error("snapshot commit cleared the goal unexpectedly"); + return view; + } + /** Commit one mutation into the goal log, cache, and live event stream. */ + commit(agent, cache, change, activation) { + const ref = goalChangeRef(change); + cache.pendingActivation = { + seq: agent.session.seq, + activation + }; + try { + agent.session.append("goal/change", change); + this.sync(agent.session, cache); + } finally { + cache.pendingActivation = void 0; + } + const goal = this.view(cache); + const notification = { + operation: change.operation, + ref: { ...ref }, + ...goal === void 0 ? {} : { goal } + }; + agentEvents(this.ctx, agent).emit("goal/changed", { change: notification }); + } + /** Build a detached current view. */ + view(cache) { + const goal = cache.state.goal; + const createdAt = cache.state.createdAt; + const updatedAt = cache.state.updatedAt; + if (goal === void 0) return void 0; + /* v8 ignore next 3 -- strict replay and snapshot commits establish both timestamps with every current goal */ + if (createdAt === void 0 || updatedAt === void 0) throw new Error(`goal "${goal.id}" cache lacks timestamps`); + return { + ...goal, + roundsStarted: cache.state.roundsStarted, + createdAt, + updatedAt, + activation: cache.activation + }; + } + /** + * Create one Goal through the remote boundary. + * @param agent - exact live Agent resolved from the wire identity. + * @param request - objective and optional round cap. + * @returns the created Goal identity. + */ + remoteExportCreate(agent, request) { + const view = this.create(agent, request); + return { ref: { + id: view.id, + revision: view.revision + } }; + } + }; +})(); +//#endregion +export { GOAL_CHANGE_VERSION, GoalError, GoalId, GoalService, GoalService as default, applyGoalProjection, decodeGoalChange, foldGoal, goalChangeRef }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/invariant.js new file mode 100644 index 0000000..a0ea81c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/invariant.js @@ -0,0 +1,332 @@ +import "@deepseek-ai/dsh-llm"; +//#region lib/types/runtime.js +/** +* Brand a string as a goal id. +* @param id - raw goal identifier. +* @returns the same string with the compile-time brand. +*/ +function GoalId(id) { + return id; +} +//#endregion +//#region lib/types/fold.js +/** Pure replay fold and strict decoder for durable goal changes. */ +const SNAPSHOT_OPERATIONS = new Set([ + "create", + "edit", + "pause", + "resume", + "complete", + "block" +]); +const PHASES = new Set([ + "active", + "paused", + "blocked", + "complete" +]); +/** +* Build an empty replay accumulator. +* @returns mutable state with no current goal or prior ref. +*/ +function emptyGoalFoldState() { + return { + goal: void 0, + roundsStarted: 0, + createdAt: void 0, + updatedAt: void 0, + lastRef: void 0, + seenGoalIds: /* @__PURE__ */ new Set() + }; +} +/** Whether a value is a JSON record rather than an array. */ +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +/** Require one positive safe integer. */ +function positiveInteger(value, field) { + if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) throw new Error(`goal change ${field} must be a positive safe integer`); + return value; +} +/** Require one non-negative safe integer. */ +function nonNegativeInteger(value, field) { + if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new Error(`goal change ${field} must be a non-negative safe integer`); + return value; +} +/** Decode one canonical blocker explanation. */ +function decodeBlockReason(value) { + if (!isRecord(value) || Object.keys(value).sort().join(",") !== "code,message") throw new Error("goal change goal.blockedReason must have exactly code and message fields"); + if (typeof value["code"] !== "string" || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(value["code"])) throw new Error("goal change goal.blockedReason.code must be lower-kebab-case"); + if (typeof value["message"] !== "string" || value["message"].trim().length === 0 || value["message"] !== value["message"].trim()) throw new Error("goal change goal.blockedReason.message must be non-empty and normalized"); + return { + code: value["code"], + message: value["message"] + }; +} +/** Decode and validate one snapshot. */ +function decodeSnapshot(value) { + if (!isRecord(value)) throw new Error("goal change goal must be a record"); + if (typeof value["id"] !== "string" || value["id"].length === 0) throw new Error("goal change goal.id must be a non-empty string"); + if (typeof value["objective"] !== "string" || value["objective"].trim().length === 0 || value["objective"] !== value["objective"].trim()) throw new Error("goal change goal.objective must be non-empty and normalized"); + if (typeof value["phase"] !== "string" || !PHASES.has(value["phase"])) throw new Error("goal change goal.phase is invalid"); + const phase = value["phase"]; + const expectedKeys = phase === "blocked" ? "blockedReason,id,maxGoalRounds,objective,phase,revision" : "id,maxGoalRounds,objective,phase,revision"; + if (Object.keys(value).sort().join(",") !== expectedKeys) throw new Error(`goal change goal for phase ${phase} must have exactly ${expectedKeys} fields`); + return { + id: GoalId(value["id"]), + revision: positiveInteger(value["revision"], "goal.revision"), + objective: value["objective"], + phase, + maxGoalRounds: positiveInteger(value["maxGoalRounds"], "goal.maxGoalRounds"), + ...phase === "blocked" ? { blockedReason: decodeBlockReason(value["blockedReason"]) } : {} + }; +} +/** Decode and validate one ref. */ +function decodeRef(value) { + if (!isRecord(value) || Object.keys(value).sort().join(",") !== "id,revision") throw new Error("goal clear tombstone must have exactly id and revision fields"); + if (typeof value["id"] !== "string" || value["id"].length === 0) throw new Error("goal clear tombstone id must be a non-empty string"); + return { + id: GoalId(value["id"]), + revision: positiveInteger(value["revision"], "cleared.revision") + }; +} +/** +* Decode a value that declares itself as a goal change. Unrelated values +* return `undefined`; malformed goal changes fail replay loudly. +* @param value - candidate source change. +* @returns validated goal change or `undefined` for another value kind. +*/ +function decodeGoalChange(value) { + if (!isRecord(value) || value["kind"] !== "goal/change") return void 0; + if (value["version"] !== 1) throw new Error(`unsupported goal change version ${String(value["version"])}`); + if (value["operation"] === "clear") { + const allowed = [ + "cleared", + "clearedAt", + "kind", + "operation", + "version" + ]; + if (Object.keys(value).sort().join(",") !== allowed.sort().join(",")) throw new Error(`goal clear change must have exactly ${allowed.sort().join(",")} fields`); + return { + kind: "goal/change", + version: 1, + operation: "clear", + cleared: decodeRef(value["cleared"]), + clearedAt: nonNegativeInteger(value["clearedAt"], "clearedAt") + }; + } + if (typeof value["operation"] !== "string" || !SNAPSHOT_OPERATIONS.has(value["operation"])) throw new Error("goal change operation is invalid"); + const allowed = [ + "createdAt", + "goal", + "kind", + "operation", + "roundsStarted", + "updatedAt", + "version" + ]; + if (Object.keys(value).sort().join(",") !== allowed.sort().join(",")) throw new Error(`goal snapshot change must have exactly ${allowed.sort().join(",")} fields`); + const createdAt = nonNegativeInteger(value["createdAt"], "createdAt"); + const updatedAt = nonNegativeInteger(value["updatedAt"], "updatedAt"); + if (updatedAt < createdAt) throw new Error("goal change updatedAt cannot precede createdAt"); + return { + kind: "goal/change", + version: 1, + operation: value["operation"], + goal: decodeSnapshot(value["goal"]), + roundsStarted: nonNegativeInteger(value["roundsStarted"], "roundsStarted"), + createdAt, + updatedAt + }; +} +/** Narrow model attribution to a valid goal source. */ +function goalSource(source) { + if (source.kind !== "goal") return void 0; + if (typeof source.goalId !== "string" || source.goalId.length === 0 || !Number.isSafeInteger(source.revision) || source.revision < 1 || !Number.isSafeInteger(source.round) || source.round < 1) throw new Error("goal message source is invalid"); + return source; +} +/** Require two snapshots to retain fields that only `edit` may replace. */ +function requireSameDefinition(current, next, operation) { + if (next.objective !== current.objective || next.maxGoalRounds !== current.maxGoalRounds) throw new Error(`goal ${operation} cannot change objective or maxGoalRounds`); +} +/** Require one exact next revision of the current goal. */ +function requireNextRevision(current, next, operation) { + if (next.id !== current.id || next.revision !== current.revision + 1) throw new Error(`goal ${operation} must advance the current goal by one revision`); +} +/** Validate one non-create snapshot operation against the preceding projection. */ +function validateSnapshotTransition(state, change, current) { + const next = change.goal; + requireNextRevision(current, next, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === void 0) throw new Error("current goal fold lacks updatedAt"); + if (change.createdAt !== state.createdAt || change.updatedAt < state.updatedAt || change.roundsStarted !== state.roundsStarted) throw new Error(`goal ${change.operation} does not preserve the current counters and timestamps`); + switch (change.operation) { + case "edit": + if (next.phase !== current.phase || JSON.stringify(next.blockedReason) !== JSON.stringify(current.blockedReason)) throw new Error("goal edit cannot change phase or blocked reason"); + break; + case "pause": + requireSameDefinition(current, next, change.operation); + if (current.phase !== "active" || next.phase !== "paused") throw new Error("goal pause has an invalid phase transition"); + break; + case "resume": + requireSameDefinition(current, next, change.operation); + if (!new Set([ + "active", + "paused", + "blocked" + ]).has(current.phase) || next.phase !== "active" || state.roundsStarted >= next.maxGoalRounds) throw new Error("goal resume has an invalid phase transition or exhausted round budget"); + break; + case "complete": + requireSameDefinition(current, next, change.operation); + if (current.phase === "complete" || next.phase !== "complete") throw new Error("goal complete has an invalid phase transition"); + break; + case "block": + requireSameDefinition(current, next, change.operation); + if (current.phase !== "active" || next.phase !== "blocked") throw new Error("goal block has an invalid phase transition"); + break; + /* v8 ignore start -- the caller excludes create and GoalOperation is closed; these arms retain fail-loud exhaustiveness */ + case "create": throw new Error("goal create cannot be validated as a current-goal transition"); + default: + change.operation; + throw new Error("unknown goal snapshot operation"); + } +} +/** +* Return the revision identity carried by a snapshot or tombstone. +* @param change - decoded goal mutation. +* @returns stable identity used to reconcile a deferred change with its log event. +*/ +function goalChangeRef(change) { + return change.operation === "clear" ? change.cleared : { + id: change.goal.id, + revision: change.goal.revision + }; +} +/** +* Validate and apply one decoded change to a mutable accumulator. +* @param state - preceding durable goal projection. +* @param change - decoded full snapshot or clear tombstone. +*/ +function applyGoalChange(state, change) { + const ref = goalChangeRef(change); + if (change.operation === "clear") { + const current = state.goal; + if (current === void 0) throw new Error("goal clear requires a current goal"); + requireNextRevision(current, change.cleared, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === void 0) throw new Error("current goal fold lacks updatedAt"); + if (change.clearedAt < state.updatedAt) throw new Error("goal clear timestamp cannot precede the current goal update"); + state.goal = void 0; + state.roundsStarted = 0; + state.createdAt = void 0; + state.updatedAt = void 0; + state.lastRef = ref; + return; + } + if (change.operation === "create") { + if (change.goal.revision !== 1 || change.goal.phase !== "active" || change.roundsStarted !== 0 || state.goal !== void 0 && state.goal.phase !== "complete" || state.seenGoalIds.has(change.goal.id)) throw new Error("goal create requires a fresh active revision-one goal with zero rounds"); + state.seenGoalIds.add(change.goal.id); + } else { + const current = state.goal; + if (current === void 0) throw new Error(`goal ${change.operation} requires a current goal`); + validateSnapshotTransition(state, change, current); + } + state.goal = change.goal; + state.roundsStarted = change.roundsStarted; + state.createdAt = change.createdAt; + state.updatedAt = change.updatedAt; + state.lastRef = ref; +} +/** +* Apply one session event to the strict durable goal fold. +* @param state - mutable fold accumulator. +* @param event - next event in sequence order. +*/ +function applyGoalEvent(state, event) { + if (event.type === "goal/change") { + const change = decodeGoalChange(event.data); + /* v8 ignore next -- the event's declared payload always identifies itself as a goal change. */ + if (change === void 0) throw new Error(`goal change at session event ${event.seq} has an invalid kind`); + applyGoalChange(state, change); + return; + } + if (event.type === "user/message") { + const source = goalSource(event.data.source); + if (source === void 0) return; + const current = state.goal; + if (current === void 0 || current.phase !== "active" || source.goalId !== current.id || source.revision !== current.revision || source.round !== state.roundsStarted + 1 || source.round > current.maxGoalRounds) throw new Error(`goal round at session event ${event.seq} is not the next admitted round of the active goal`); + state.roundsStarted = source.round; + } +} +//#endregion +//#region lib/types/invariant.js +/** Package-owned durable goal-stream invariants. @module @deepseek-ai/dsh-goal/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-goal"; +/** Cordis companion plugin name. */ +const name = "goal-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Copy the independent fold before validating one candidate event. */ +function cloneState(state) { + return { + goal: state.goal, + roundsStarted: state.roundsStarted, + createdAt: state.createdAt, + updatedAt: state.updatedAt, + lastRef: state.lastRef, + seenGoalIds: new Set(state.seenGoalIds) + }; +} +/** Apply one event through the strict goal decoder and attribute failures. */ +function applyChecked(state, event, fail) { + try { + applyGoalEvent(state, event); + } catch (error) { + /* v8 ignore next -- the strict goal decoder throws Error instances */ + const message = error instanceof Error ? error.message : String(error); + fail(`session event ${event.seq} violates the durable goal stream: ${message}`); + } +} +/** Install an independent incremental fold over every attached session. */ +const install = Object.assign((ctx, fail) => { + const states = /* @__PURE__ */ new WeakMap(); + const staged = /* @__PURE__ */ new WeakMap(); + const seed = (session) => { + const state = emptyGoalFoldState(); + for (const event of session.events) applyChecked(state, event, fail); + states.set(session, state); + return state; + }; + /* v8 ignore next -- session/event always follows list() or session/created seeding */ + const stateFor = (session) => states.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) seed(session); + ctx.on("session/created", (session) => { + seed(session); + }, { global: true }); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName !== "session/event") return; + const [session, event] = args; + const state = cloneState(stateFor(session)); + applyChecked(state, event, fail); + staged.set(event, { + session, + state + }); + }, { global: true }); + ctx.on("session/event", (session, event) => { + const candidate = staged.get(event); + /* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */ + if (candidate === void 0 || candidate.session !== session) return fail("session/event reached publication without matching goal-fold validation"); + staged.delete(event); + states.set(session, candidate.state); + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register the goal-stream invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.d.ts new file mode 100644 index 0000000..dcf4919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.d.ts @@ -0,0 +1,3 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ + +export declare const TYPERT: unknown diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.js new file mode 100644 index 0000000..ff058ef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.js @@ -0,0 +1,815 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_clear_result$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_complete_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_create_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_create_parameter_1$schema = z.object({ + 'objective': z.string().readonly(), + 'maxGoalRounds': z.number().readonly().optional(), +}) +const _deepseek_ai_dsh_goal_goals_create_result$schema = z.object({ + 'ref': z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}).readonly(), +}) +const _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema = z.object({ + 'objective': z.string().readonly().optional(), + 'maxGoalRounds': z.number().readonly().optional(), +}) +const _deepseek_ai_dsh_goal_goals_edit_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_pause_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_resume_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) + +export const TYPERT = { + package: '@deepseek-ai/dsh-goal', + face: 'host', + schemas: [ + ], + invocations: [ + { + id: '@deepseek-ai/dsh-goal#goals/clear', + service: 'goals', + namespace: 'goals', + method: 'clear', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_clear_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":377,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/complete', + service: 'goals', + namespace: 'goals', + method: 'complete', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_complete_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":337,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/create', + service: 'goals', + namespace: 'goals', + method: 'create', + implementation: 'remoteExportCreate', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_create_parameter_0$schema, + }, + }, + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#CreateGoalRequest', + schema: _deepseek_ai_dsh_goal_goals_create_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#CreateGoalResult', + schema: _deepseek_ai_dsh_goal_goals_create_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":586,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/edit', + service: 'goals', + namespace: 'goals', + method: 'edit', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema, + }, + }, + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#EditGoalRequest', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_edit_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":277,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/pause', + service: 'goals', + namespace: 'goals', + method: 'pause', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_pause_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":299,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/resume', + service: 'goals', + namespace: 'goals', + method: 'resume', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_resume_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":311,"column":3}, + }, + ], + model: { + "services": [ + { + "description": "Goal service (`ctx.goals`) backed exclusively by the owning session log.", + "summary": "Goal service (`ctx.goals`) backed exclusively by the owning session log.", + "tags": [], + "jsDoc": "/** Goal service (`ctx.goals`) backed exclusively by the owning session log. */", + "key": "goals", + "exportName": "GoalService", + "members": [ + { + "kind": "method", + "name": "get", + "signature": "get(agent: Agent): GoalView | undefined", + "summary": "Read the current goal for one exact live agent.", + "jsDoc": "/**\n * Read the current goal for one exact live agent.\n * @param agent - owning live agent.\n * @returns a fresh view or `undefined` when no goal is current.\n * @throws {@link GoalError} when the agent is not the registry's live instance.\n */" + }, + { + "kind": "method", + "name": "disarm", + "signature": "disarm(agent: Agent): GoalView | undefined", + "summary": "Remove process-local continuation authority without changing durable goal phase or revision.", + "jsDoc": "/**\n * Remove process-local continuation authority without changing durable goal\n * phase or revision. Lifecycle owners use this before unloading a driver;\n * a later human-authorized {@link resume} records the new activation edge.\n * @param agent - owning live agent.\n * @returns a fresh disarmed view, or `undefined` when no goal is current.\n */" + }, + { + "kind": "method", + "name": "create", + "signature": "create(agent: Agent, request: CreateGoalRequest): GoalView", + "summary": "Create and arm a goal.", + "jsDoc": "/**\n * Create and arm a goal. A completed goal may be replaced; every other\n * current phase must be cleared or resumed instead.\n * @param agent - owning live agent.\n * @param request - objective and optional round cap.\n * @returns the created live view.\n */" + }, + { + "kind": "method", + "name": "edit", + "signature": "@Remote('edit') edit(agent: Agent, ref: GoalRef, request: EditGoalRequest): GoalView", + "summary": "Edit objective and/or round cap without changing phase.", + "jsDoc": "/**\n * Edit objective and/or round cap without changing phase.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @param request - at least one replacement field.\n * @returns the edited view.\n */" + }, + { + "kind": "method", + "name": "pause", + "signature": "@Remote('pause') pause(agent: Agent, ref: GoalRef): GoalView", + "summary": "Pause an active goal and disarm automatic continuation.", + "jsDoc": "/**\n * Pause an active goal and disarm automatic continuation.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @returns the paused view.\n */" + }, + { + "kind": "method", + "name": "resume", + "signature": "@Remote('resume') resume(agent: Agent, ref: GoalRef): GoalView", + "summary": "Resume and arm a stopped goal, or rearm an active goal after a session-start edge, while its round budget still has capacity.", + "jsDoc": "/**\n * Resume and arm a stopped goal, or rearm an active goal after a\n * session-start edge, while its round budget still has capacity.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @returns the active view.\n */" + }, + { + "kind": "method", + "name": "complete", + "signature": "@Remote('complete') complete(agent: Agent, ref: GoalRef): GoalView", + "summary": "Mark a current non-complete goal complete and disarm it.", + "jsDoc": "/**\n * Mark a current non-complete goal complete and disarm it.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @returns the completed view.\n */" + }, + { + "kind": "method", + "name": "block", + "signature": "block(agent: Agent, ref: GoalRef, reason: GoalBlockReason): GoalView", + "summary": "Mark an active goal blocked and disarm it.", + "jsDoc": "/**\n * Mark an active goal blocked and disarm it.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @param reason - policy-owned stable code and human-readable explanation.\n * @returns the blocked view with its durable reason.\n */" + }, + { + "kind": "method", + "name": "clear", + "signature": "@Remote('clear') clear(agent: Agent, ref: GoalRef): GoalRef", + "summary": "Clear the current goal while retaining a durable tombstone and history.", + "jsDoc": "/**\n * Clear the current goal while retaining a durable tombstone and history.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @returns the tombstone ref whose revision is one past the cleared snapshot.\n */" + }, + { + "kind": "method", + "name": "remoteExportCreate", + "signature": "@Remote('create') remoteExportCreate(agent: Agent, request: CreateGoalRequest): CreateGoalResult", + "summary": "Create one Goal through the remote boundary.", + "jsDoc": "/**\n * Create one Goal through the remote boundary.\n * @param agent - exact live Agent resolved from the wire identity.\n * @param request - objective and optional round cap.\n * @returns the created Goal identity.\n */" + } + ], + "types": [ + { + "name": "Agent", + "declaration": "export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly inbox: Inbox;\n readonly status: AgentStatus;\n readonly ctx: Context;\n cancel(cause: AgentCancelCause, options?: CancelOptions): void;\n whenIdle(): Promise;\n runMaintenance(task: (signal: AbortSignal) => Promise): Promise;\n send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;\n followup(message: UserMessage): void;\n steer(message: UserMessage): void;\n inject(message: UserMessage): void;\n}" + }, + { + "name": "AgentCancelCause", + "declaration": "export type AgentCancelCause = { readonly kind: 'user'; } | { readonly kind: 'parent'; } | { readonly kind: 'hook'; readonly reason: string; } | { readonly kind: 'disposed'; };" + }, + { + "name": "AgentOptions", + "declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n maxTokens?: number;\n}" + }, + { + "name": "AgentStatus", + "declaration": "export type AgentStatus = 'idle' | 'running';" + }, + { + "name": "ApprovalOutcome", + "declaration": "export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';" + }, + { + "name": "ApprovalPolicy", + "declaration": "export type ApprovalPolicy = 'ask' | 'never';" + }, + { + "name": "ApprovalRequestId", + "declaration": "export type ApprovalRequestId = Branded<'ApprovalRequestId'>;" + }, + { + "name": "AssistantMessage", + "declaration": "export interface AssistantMessage extends Message {\n readonly role: 'assistant';\n readonly source: ModelMessageSource;\n}" + }, + { + "name": "AssistantProvenance", + "declaration": "export interface AssistantProvenance {\n provider: string;\n model: string;\n replayState?: unknown;\n}" + }, + { + "name": "AttachmentId", + "declaration": "export type AttachmentId = Branded<'AttachmentId'>;" + }, + { + "name": "Branded", + "declaration": "export type Branded = string & { readonly [BRAND]: B; };" + }, + { + "name": "CallId", + "declaration": "export type CallId = Branded<'CallId'>;" + }, + { + "name": "CancelOptions", + "declaration": "export interface CancelOptions {\n keepInbox?: boolean | undefined;\n}" + }, + { + "name": "CodeDispatchEventData", + "declaration": "export interface CodeDispatchEventData extends CodeDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}" + }, + { + "name": "CodeDispatchStartEventData", + "declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}" + }, + { + "name": "CommandId", + "declaration": "export type CommandId = Branded<'CommandId'>;" + }, + { + "name": "CommandSource", + "declaration": "export type CommandSource = CommandSourceMap[keyof CommandSourceMap];" + }, + { + "name": "CommandSourceMap", + "declaration": "export interface CommandSourceMap {\n user: { kind: 'user'; };\n}" + }, + { + "name": "ContentBlock", + "declaration": "export type ContentBlock = ContentBlockMap[ContentBlockType];" + }, + { + "name": "ContentBlockMap", + "declaration": "export interface ContentBlockMap {\n text: TextBlock;\n reasoning: ReasoningBlock;\n image: ImageBlock;\n 'tool-call': ToolCallBlock;\n 'tool-result': ToolResultBlock;\n}" + }, + { + "name": "ContentBlockType", + "declaration": "export type ContentBlockType = keyof ContentBlockMap;" + }, + { + "name": "ContextFormed", + "declaration": "export type ContextFormed = { readonly form?: never; } | { readonly form: 'instructions'; } | { readonly form: 'catalog'; } | { readonly form: 'snapshot'; readonly sections: readonly ContextSnapshotSection[]; } | { readonly form: 'notice'; readonly summary: string; } | { readonly form: 'relay'; } | { readonly form: 'recall'; };" + }, + { + "name": "ContextSnapshotSection", + "declaration": "export interface ContextSnapshotSection {\n readonly name: string;\n readonly text: string;\n}" + }, + { + "name": "CreateGoalRequest", + "declaration": "export interface CreateGoalRequest {\n readonly objective: string;\n readonly maxGoalRounds?: number;\n}" + }, + { + "name": "CreateGoalResult", + "declaration": "export interface CreateGoalResult {\n readonly ref: GoalRef;\n}" + }, + { + "name": "EditGoalRequest", + "declaration": "export interface EditGoalRequest {\n readonly objective?: string;\n readonly maxGoalRounds?: number;\n}" + }, + { + "name": "EpochHeader", + "declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n system?: string;\n tools?: ToolSchema[];\n}" + }, + { + "name": "FinishReason", + "declaration": "export type FinishReason = FinishReasonMap[keyof FinishReasonMap];" + }, + { + "name": "FinishReasonMap", + "declaration": "export interface FinishReasonMap {\n stop: { kind: 'stop'; };\n 'tool-calls': { kind: 'tool-calls'; };\n 'max-tokens': { kind: 'max-tokens'; };\n aborted: { kind: 'aborted'; failure: LlmFailure; };\n error: { kind: 'error'; failure: LlmFailure; };\n}" + }, + { + "name": "GoalActivation", + "declaration": "export type GoalActivation = 'armed' | 'disarmed';" + }, + { + "name": "GoalBlockReason", + "declaration": "export interface GoalBlockReason {\n readonly code: string;\n readonly message: string;\n}" + }, + { + "name": "GoalChangeMeta", + "declaration": "export type GoalChangeMeta = GoalSnapshotChangeMeta | GoalClearChangeMeta;" + }, + { + "name": "GoalClearChangeMeta", + "declaration": "export interface GoalClearChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: 'clear';\n readonly cleared: GoalRef;\n readonly clearedAt: number;\n}" + }, + { + "name": "GoalId", + "declaration": "export type GoalId = Branded<'GoalId'>;" + }, + { + "name": "GoalMessageSource", + "declaration": "export interface GoalMessageSource {\n readonly kind: 'goal';\n readonly goalId: GoalId;\n readonly revision: number;\n readonly round: number;\n}" + }, + { + "name": "GoalOperation", + "declaration": "export type GoalOperation = 'create' | 'edit' | 'pause' | 'resume' | 'complete' | 'block' | 'clear';" + }, + { + "name": "GoalPhase", + "declaration": "export type GoalPhase = 'active' | 'paused' | 'blocked' | 'complete';" + }, + { + "name": "GoalRef", + "declaration": "export interface GoalRef {\n readonly id: GoalId;\n readonly revision: number;\n}" + }, + { + "name": "GoalSnapshot", + "declaration": "export interface GoalSnapshot extends GoalRef {\n readonly objective: string;\n readonly phase: GoalPhase;\n readonly blockedReason?: GoalBlockReason;\n readonly maxGoalRounds: number;\n}" + }, + { + "name": "GoalSnapshotChangeMeta", + "declaration": "export interface GoalSnapshotChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: Exclude;\n readonly goal: GoalSnapshot;\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n}" + }, + { + "name": "GoalView", + "declaration": "export interface GoalView extends GoalSnapshot {\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n readonly activation: GoalActivation;\n}" + }, + { + "name": "ImageAttachmentRef", + "declaration": "export interface ImageAttachmentRef {\n attachmentId: AttachmentId;\n mediaType: ImageMediaType;\n bytes: number;\n width: number;\n height: number;\n name?: string;\n}" + }, + { + "name": "ImageBlock", + "declaration": "export interface ImageBlock {\n type: 'image';\n attachment: ImageAttachmentRef;\n}" + }, + { + "name": "ImageMediaType", + "declaration": "export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';" + }, + { + "name": "Inbox", + "declaration": "export class Inbox {\n get nextTurn(): readonly UserMessage[];\n get nextStep(): readonly UserMessage[];\n get hasPending(): boolean;\n clear(): void;\n claim(target: InboxTarget, turn: number): UserMessage[];\n append(target: InboxTarget, message: UserMessage): void;\n prepend(target: InboxTarget, message: UserMessage): void;\n replace(messageId: MessageId, newMessage: UserMessage): boolean;\n remove(messageId: MessageId): boolean;\n splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[];\n}" + }, + { + "name": "InboxTarget", + "declaration": "export type InboxTarget = 'next-turn' | 'next-step';" + }, + { + "name": "JsonValue", + "declaration": "export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue; };" + }, + { + "name": "LlmCallConfig", + "declaration": "export interface LlmCallConfig {\n provider: string;\n model: string;\n reasoningEffort?: ReasoningEffortId;\n temperature?: number;\n maxTokens?: number;\n stop?: string[];\n}" + }, + { + "name": "LlmCallConfigAdapterDefaults", + "declaration": "export interface LlmCallConfigAdapterDefaults {\n reasoningEffort?: true;\n maxTokens?: true;\n}" + }, + { + "name": "LlmFailure", + "declaration": "export interface LlmFailure {\n readonly message: string;\n readonly code: string;\n readonly status?: number;\n readonly providerRetryAfterMs?: number;\n readonly requestId?: ProviderRequestId;\n}" + }, + { + "name": "Message", + "declaration": "export interface Message {\n readonly id: MessageId;\n readonly role: 'system' | 'user' | 'assistant';\n readonly content: ContentBlock[];\n readonly source: MessageSource;\n}" + }, + { + "name": "MessageId", + "declaration": "export type MessageId = Branded<'MessageId'>;" + }, + { + "name": "MessageSource", + "declaration": "export type MessageSource = MessageSourceMap[keyof MessageSourceMap];" + }, + { + "name": "MessageSourceMap", + "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n goal: GoalMessageSource;\n}" + }, + { + "name": "ModelMessageSource", + "declaration": "export interface ModelMessageSource extends AssistantProvenance {\n kind: 'model';\n}" + }, + { + "name": "ProviderRequestId", + "declaration": "export type ProviderRequestId = Branded<'ProviderRequestId'>;" + }, + { + "name": "ReasoningBlock", + "declaration": "export interface ReasoningBlock {\n type: 'reasoning';\n text: string;\n}" + }, + { + "name": "ReasoningEffortId", + "declaration": "export type ReasoningEffortId = Branded<'ReasoningEffortId'>;" + }, + { + "name": "RequestContext", + "declaration": "export interface RequestContext {\n provider: string;\n model: string;\n contextWindow?: number;\n}" + }, + { + "name": "RequestHeaderReason", + "declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change';" + }, + { + "name": "Session", + "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n get id(): SessionId;\n readonly firstLiveSeq: number;\n get events(): readonly SessionEvent[];\n get seq(): number;\n append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}" + }, + { + "name": "SessionEvent", + "declaration": "export type SessionEvent = { [K in SessionEventType]: { type: K; seq: number; time: number; data: SessionEventMap[K]; ignorable?: true; } & (K extends SurfaceEventType ? { sourceEventSeqs?: number[]; surfaceOp?: SurfaceOp; } : object) }[T];" + }, + { + "name": "SessionEventMap", + "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: number; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n 'goal/change': GoalChangeMeta;\n}" + }, + { + "name": "SessionEventType", + "declaration": "export type SessionEventType = keyof SessionEventMap;" + }, + { + "name": "SessionHeader", + "declaration": "export interface SessionHeader {\n readonly version: number;\n readonly id: SessionId;\n readonly createdAt: number;\n readonly cwd?: string;\n readonly parentSession?: SessionId;\n readonly seedLength?: number;\n readonly origin?: 'subagent';\n readonly delegationDepth?: number;\n readonly agentPreset?: string;\n}" + }, + { + "name": "SessionId", + "declaration": "export type SessionId = Branded<'SessionId'>;" + }, + { + "name": "SessionSurface", + "declaration": "export interface SessionSurface {\n readonly nodes: readonly number[];\n readonly replaceGeneration: number;\n}" + }, + { + "name": "StreamChunk", + "declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: unknown; };" + }, + { + "name": "SurfaceEventType", + "declaration": "export type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result';" + }, + { + "name": "SurfaceIntent", + "declaration": "export interface SurfaceIntent {\n surfaceOp: SurfaceOp;\n sourceEventSeqs?: number[];\n}" + }, + { + "name": "SurfaceOp", + "declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: number; end: number; };" + }, + { + "name": "TextBlock", + "declaration": "export interface TextBlock {\n type: 'text';\n text: string;\n}" + }, + { + "name": "TodoItem", + "declaration": "export interface TodoItem {\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n}" + }, + { + "name": "TokenUsage", + "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}" + }, + { + "name": "ToolCallBlock", + "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: CallId;\n name: string;\n arguments: string;\n}" + }, + { + "name": "ToolMessageSource", + "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: CallId;\n}" + }, + { + "name": "ToolResultBlock", + "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: CallId;\n content: ContentBlock[];\n isError?: boolean;\n}" + }, + { + "name": "ToolResultMessage", + "declaration": "export interface ToolResultMessage extends Message {\n readonly role: 'user';\n readonly content: [ToolResultBlock];\n readonly source: ToolMessageSource;\n}" + }, + { + "name": "ToolSchema", + "declaration": "export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n}" + }, + { + "name": "TurnEndCancelCause", + "declaration": "export type TurnEndCancelCause = AgentCancelCause | { readonly kind: 'legacy'; };" + }, + { + "name": "TurnEndReason", + "declaration": "export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap];" + }, + { + "name": "TurnEndReasonMap", + "declaration": "export interface TurnEndReasonMap {\n completed: { kind: 'completed'; };\n aborted: { kind: 'aborted'; reason: TurnEndCancelCause; };\n blocked: { kind: 'blocked'; };\n error: { kind: 'error'; error: LlmFailure; };\n 'max-tokens': { kind: 'max-tokens'; };\n interrupted: { kind: 'interrupted'; };\n}" + }, + { + "name": "UserMessage", + "declaration": "export interface UserMessage extends Message {\n readonly role: 'user';\n}" + } + ] + } + ], + "events": [ + { + "description": "Goal mutation accepted by one live agent. The matching `goal/change` session event has already committed. Listener failures are contained. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.", + "summary": "Goal mutation accepted by one live agent.", + "tags": [ + { + "name": "param", + "argument": "payload.agent", + "comment": "- agent whose session owns the goal.", + "text": "@param payload.agent - agent whose session owns the goal.\n *" + }, + { + "name": "param", + "argument": "payload.change", + "comment": "- fresh current projection or clear tombstone.", + "text": "@param payload.change - fresh current projection or clear tombstone.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * Goal mutation accepted by one live agent. The matching `goal/change`\n * session event has already committed. Listener failures are contained.\n * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.\n * @param payload.agent - agent whose session owns the goal.\n * @param payload.change - fresh current projection or clear tombstone.\n * @mode emit\n */", + "name": "goal/changed", + "mode": "emit", + "signature": "'goal/changed'(this: import('@deepseek-ai/dsh-scope').Scoped, payload: { agent: Agent; change: GoalChanged; }): void" + } + ], + "objects": [] + }, +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.d.ts new file mode 100644 index 0000000..a2dc168 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.d.ts @@ -0,0 +1,41 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import type { + RemoteResult, + TypertRemoteContribution, +} from '@deepseek-ai/dsh-typert-protocol' +import type { CreateGoalRequest, CreateGoalResult, EditGoalRequest, GoalRef, GoalView } from '@deepseek-ai/dsh-goal/client' +import type { SessionId } from '@deepseek-ai/dsh-session/types' + +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteNamespace$676f616c73 { + clear: (agentId: SessionId, ref: GoalRef) => Promise> + complete: (agentId: SessionId, ref: GoalRef) => Promise> + create: (agentId: SessionId, request: CreateGoalRequest) => Promise> + edit: (agentId: SessionId, ref: GoalRef, request: EditGoalRequest) => Promise> + pause: (agentId: SessionId, ref: GoalRef) => Promise> + resume: (agentId: SessionId, ref: GoalRef) => Promise> + } + interface TypertRemoteMap { + 'goals/clear': (agentId: SessionId, ref: GoalRef) => Promise> + 'goals/complete': (agentId: SessionId, ref: GoalRef) => Promise> + 'goals/create': (agentId: SessionId, request: CreateGoalRequest) => Promise> + 'goals/edit': (agentId: SessionId, ref: GoalRef, request: EditGoalRequest) => Promise> + 'goals/pause': (agentId: SessionId, ref: GoalRef) => Promise> + 'goals/resume': (agentId: SessionId, ref: GoalRef) => Promise> + } + interface TypertRemoteNamespaceMap { + 'goals': TypertRemoteNamespace$676f616c73 + } + interface TypertRemoteScopeMap { + 'agent:goals/clear': (ref: GoalRef) => Promise> + 'agent:goals/complete': (ref: GoalRef) => Promise> + 'agent:goals/create': (request: CreateGoalRequest) => Promise> + 'agent:goals/edit': (ref: GoalRef, request: EditGoalRequest) => Promise> + 'agent:goals/pause': (ref: GoalRef) => Promise> + 'agent:goals/resume': (ref: GoalRef) => Promise> + } +} + +export declare const TYPERT_REMOTE: TypertRemoteContribution +export default TYPERT_REMOTE +//# sourceMappingURL=typert.remote-client.d.ts.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.js new file mode 100644 index 0000000..9450fb3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.js @@ -0,0 +1,366 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_clear_result$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_complete_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_create_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_create_parameter_1$schema = z.object({ + 'objective': z.string().readonly(), + 'maxGoalRounds': z.number().readonly().optional(), +}) +const _deepseek_ai_dsh_goal_goals_create_result$schema = z.object({ + 'ref': z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}).readonly(), +}) +const _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema = z.object({ + 'objective': z.string().readonly().optional(), + 'maxGoalRounds': z.number().readonly().optional(), +}) +const _deepseek_ai_dsh_goal_goals_edit_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_pause_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_resume_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) + +export const TYPERT_REMOTE = { + package: '@deepseek-ai/dsh-goal', + descriptors: [ + { + id: '@deepseek-ai/dsh-goal#goals/clear', + service: 'goals', + namespace: 'goals', + method: 'clear', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_clear_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":377,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/complete', + service: 'goals', + namespace: 'goals', + method: 'complete', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_complete_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":337,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/create', + service: 'goals', + namespace: 'goals', + method: 'create', + implementation: 'remoteExportCreate', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_create_parameter_0$schema, + }, + }, + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#CreateGoalRequest', + schema: _deepseek_ai_dsh_goal_goals_create_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#CreateGoalResult', + schema: _deepseek_ai_dsh_goal_goals_create_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":586,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/edit', + service: 'goals', + namespace: 'goals', + method: 'edit', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema, + }, + }, + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#EditGoalRequest', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_edit_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":277,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/pause', + service: 'goals', + namespace: 'goals', + method: 'pause', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_pause_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":299,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/resume', + service: 'goals', + namespace: 'goals', + method: 'resume', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_resume_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":311,"column":3}, + }, + ], +} + +export default TYPERT_REMOTE diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/client.d.ts new file mode 100644 index 0000000..982d8fb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/client.d.ts @@ -0,0 +1,10 @@ +/** + * Client-namespace projection of the goal domain: a pure re-export of the + * package's types outlet. Client code imports ONLY the client namespace + * (repo discipline), so `./client` projects the same single-source content + * `./types` serves to host consumers — zero duplication. + * + * @module @deepseek-ai/dsh-goal/client + */ +export type * from './types.ts'; +//# sourceMappingURL=client.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/client.js new file mode 100644 index 0000000..a755a80 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/client.js @@ -0,0 +1,10 @@ +/** + * Client-namespace projection of the goal domain: a pure re-export of the + * package's types outlet. Client code imports ONLY the client namespace + * (repo discipline), so `./client` projects the same single-source content + * `./types` serves to host consumers — zero duplication. + * + * @module @deepseek-ai/dsh-goal/client + */ +export {}; +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.d.ts new file mode 100644 index 0000000..b578565 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.d.ts @@ -0,0 +1,92 @@ +/** + * Host-side vocabulary of the goal domain: live views, durable change + * payloads, message attribution, replay folds, and the scoped `goal/changed` + * event. Kept separate from ./types.ts (the pure client-safe outlet) because + * these declarations pull dsh-agent, dsh-llm, and cordis into the program — + * the one-program-per-side layout forbids that on client aggregates. + * @module @deepseek-ai/dsh-goal + */ +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { GoalId, GoalRef, GoalSnapshot, GoalView } from './types.ts'; +/** Goal state-changing verbs recorded in the durable source change. */ +export type GoalOperation = 'create' | 'edit' | 'pause' | 'resume' | 'complete' | 'block' | 'clear'; +/** Full-snapshot goal mutation committed by a durable `goal/change` event. */ +export interface GoalSnapshotChangeMeta { + readonly kind: 'goal/change'; + readonly version: 1; + readonly operation: Exclude; + readonly goal: GoalSnapshot; + readonly roundsStarted: number; + readonly createdAt: number; + readonly updatedAt: number; +} +/** Tombstone retained when the current goal is cleared. */ +export interface GoalClearChangeMeta { + readonly kind: 'goal/change'; + readonly version: 1; + readonly operation: 'clear'; + readonly cleared: GoalRef; + readonly clearedAt: number; +} +/** Durable change union carried by the goal domain's own session event. */ +export type GoalChangeMeta = GoalSnapshotChangeMeta | GoalClearChangeMeta; +/** Message attribution for admitted continuation rounds. */ +export interface GoalMessageSource { + readonly kind: 'goal'; + readonly goalId: GoalId; + readonly revision: number; + /** Positive admitted continuation round. */ + readonly round: number; +} +declare module '@deepseek-ai/dsh-llm' { + interface MessageSourceMap { + goal: GoalMessageSource; + } +} +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * Complete post-mutation goal state or clear tombstone. + */ + 'goal/change': GoalChangeMeta; + } +} +/** Pure replay fold of durable goal facts. */ +export interface FoldedGoal { + /** Current goal, absent after a clear or before the first create. */ + readonly goal?: GoalSnapshot; + /** Highest admitted round for the current goal. */ + readonly roundsStarted: number; + /** Current goal creation time, absent without a current goal. */ + readonly createdAt?: number; + /** Current goal mutation time, absent without a current goal. */ + readonly updatedAt?: number; + /** Latest mutation ref, including a clear tombstone. */ + readonly lastRef?: GoalRef; +} +/** Live notification after one durable goal mutation commits. */ +export interface GoalChanged { + readonly operation: GoalOperation; + readonly ref: GoalRef; + /** Absent for a clear tombstone. */ + readonly goal?: GoalView; +} +/** Stable error codes for rejected goal reads and mutations. */ +export type GoalErrorCode = 'GOAL_AGENT_NOT_LIVE' | 'GOAL_NOT_FOUND' | 'GOAL_ALREADY_EXISTS' | 'GOAL_STALE_REVISION' | 'GOAL_INVALID_OBJECTIVE' | 'GOAL_INVALID_MAX_ROUNDS' | 'GOAL_INVALID_BLOCK_REASON' | 'GOAL_INVALID_EDIT' | 'GOAL_INVALID_TRANSITION'; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * Goal mutation accepted by one live agent. The matching `goal/change` + * session event has already committed. Listener failures are contained. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @param payload.agent - agent whose session owns the goal. + * @param payload.change - fresh current projection or clear tombstone. + * @mode emit + */ + 'goal/changed'(this: import('@deepseek-ai/dsh-scope').Scoped, payload: { + agent: Agent; + change: GoalChanged; + }): void; + } +} +//# sourceMappingURL=domain.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.js new file mode 100644 index 0000000..625e287 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.js @@ -0,0 +1,10 @@ +/** + * Host-side vocabulary of the goal domain: live views, durable change + * payloads, message attribution, replay folds, and the scoped `goal/changed` + * event. Kept separate from ./types.ts (the pure client-safe outlet) because + * these declarations pull dsh-agent, dsh-llm, and cordis into the program — + * the one-program-per-side layout forbids that on client aggregates. + * @module @deepseek-ai/dsh-goal + */ +export {}; +//# sourceMappingURL=domain.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.d.ts new file mode 100644 index 0000000..da0c7da --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.d.ts @@ -0,0 +1,50 @@ +/** Pure replay fold and strict decoder for durable goal changes. */ +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +import type { GoalRef, GoalSnapshot } from './types.ts'; +import type { FoldedGoal, GoalChangeMeta } from './domain.ts'; +/** Mutable accumulator kept private to the pure fold. */ +export interface GoalFoldState { + goal: GoalSnapshot | undefined; + roundsStarted: number; + createdAt: number | undefined; + updatedAt: number | undefined; + lastRef: GoalRef | undefined; + seenGoalIds: Set; +} +/** + * Build an empty replay accumulator. + * @returns mutable state with no current goal or prior ref. + */ +export declare function emptyGoalFoldState(): GoalFoldState; +/** + * Decode a value that declares itself as a goal change. Unrelated values + * return `undefined`; malformed goal changes fail replay loudly. + * @param value - candidate source change. + * @returns validated goal change or `undefined` for another value kind. + */ +export declare function decodeGoalChange(value: unknown): GoalChangeMeta | undefined; +/** + * Return the revision identity carried by a snapshot or tombstone. + * @param change - decoded goal mutation. + * @returns stable identity used to reconcile a deferred change with its log event. + */ +export declare function goalChangeRef(change: GoalChangeMeta): GoalRef; +/** + * Validate and apply one decoded change to a mutable accumulator. + * @param state - preceding durable goal projection. + * @param change - decoded full snapshot or clear tombstone. + */ +export declare function applyGoalChange(state: GoalFoldState, change: GoalChangeMeta): void; +/** + * Apply one session event to the strict durable goal fold. + * @param state - mutable fold accumulator. + * @param event - next event in sequence order. + */ +export declare function applyGoalEvent(state: GoalFoldState, event: SessionEvent): void; +/** + * Fold current goal state from a contiguous session event log. + * @param events - session events in sequence order. + * @returns a fresh durable projection; activation is deliberately absent. + */ +export declare function foldGoal(events: readonly SessionEvent[]): FoldedGoal; +//# sourceMappingURL=fold.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.js new file mode 100644 index 0000000..0e1aa4c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.js @@ -0,0 +1,322 @@ +/** Pure replay fold and strict decoder for durable goal changes. */ +import { GOAL_CHANGE_VERSION, GoalId } from "./runtime.js"; +const SNAPSHOT_OPERATIONS = new Set([ + 'create', + 'edit', + 'pause', + 'resume', + 'complete', + 'block', +]); +const PHASES = new Set(['active', 'paused', 'blocked', 'complete']); +/** + * Build an empty replay accumulator. + * @returns mutable state with no current goal or prior ref. + */ +export function emptyGoalFoldState() { + return { + goal: undefined, + roundsStarted: 0, + createdAt: undefined, + updatedAt: undefined, + lastRef: undefined, + seenGoalIds: new Set(), + }; +} +/** Whether a value is a JSON record rather than an array. */ +function isRecord(value) { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} +/** Require one positive safe integer. */ +function positiveInteger(value, field) { + if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1) { + throw new Error(`goal change ${field} must be a positive safe integer`); + } + return value; +} +/** Require one non-negative safe integer. */ +function nonNegativeInteger(value, field) { + if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) { + throw new Error(`goal change ${field} must be a non-negative safe integer`); + } + return value; +} +/** Decode one canonical blocker explanation. */ +function decodeBlockReason(value) { + if (!isRecord(value) || Object.keys(value).sort().join(',') !== 'code,message') { + throw new Error('goal change goal.blockedReason must have exactly code and message fields'); + } + if (typeof value['code'] !== 'string' || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(value['code'])) { + throw new Error('goal change goal.blockedReason.code must be lower-kebab-case'); + } + if (typeof value['message'] !== 'string' || value['message'].trim().length === 0 + || value['message'] !== value['message'].trim()) { + throw new Error('goal change goal.blockedReason.message must be non-empty and normalized'); + } + return { code: value['code'], message: value['message'] }; +} +/** Decode and validate one snapshot. */ +function decodeSnapshot(value) { + if (!isRecord(value)) + throw new Error('goal change goal must be a record'); + if (typeof value['id'] !== 'string' || value['id'].length === 0) { + throw new Error('goal change goal.id must be a non-empty string'); + } + if (typeof value['objective'] !== 'string' || value['objective'].trim().length === 0 + || value['objective'] !== value['objective'].trim()) { + throw new Error('goal change goal.objective must be non-empty and normalized'); + } + if (typeof value['phase'] !== 'string' || !PHASES.has(value['phase'])) { + throw new Error('goal change goal.phase is invalid'); + } + const phase = value['phase']; + const expectedKeys = phase === 'blocked' + ? 'blockedReason,id,maxGoalRounds,objective,phase,revision' + : 'id,maxGoalRounds,objective,phase,revision'; + if (Object.keys(value).sort().join(',') !== expectedKeys) { + throw new Error(`goal change goal for phase ${phase} must have exactly ${expectedKeys} fields`); + } + return { + id: GoalId(value['id']), + revision: positiveInteger(value['revision'], 'goal.revision'), + objective: value['objective'], + phase, + maxGoalRounds: positiveInteger(value['maxGoalRounds'], 'goal.maxGoalRounds'), + ...phase === 'blocked' ? { blockedReason: decodeBlockReason(value['blockedReason']) } : {}, + }; +} +/** Decode and validate one ref. */ +function decodeRef(value) { + if (!isRecord(value) || Object.keys(value).sort().join(',') !== 'id,revision') { + throw new Error('goal clear tombstone must have exactly id and revision fields'); + } + if (typeof value['id'] !== 'string' || value['id'].length === 0) { + throw new Error('goal clear tombstone id must be a non-empty string'); + } + return { id: GoalId(value['id']), revision: positiveInteger(value['revision'], 'cleared.revision') }; +} +/** + * Decode a value that declares itself as a goal change. Unrelated values + * return `undefined`; malformed goal changes fail replay loudly. + * @param value - candidate source change. + * @returns validated goal change or `undefined` for another value kind. + */ +export function decodeGoalChange(value) { + if (!isRecord(value) || value['kind'] !== 'goal/change') + return undefined; + if (value['version'] !== GOAL_CHANGE_VERSION) { + throw new Error(`unsupported goal change version ${String(value['version'])}`); + } + if (value['operation'] === 'clear') { + const allowed = ['cleared', 'clearedAt', 'kind', 'operation', 'version']; + if (Object.keys(value).sort().join(',') !== allowed.sort().join(',')) { + throw new Error(`goal clear change must have exactly ${allowed.sort().join(',')} fields`); + } + return { + kind: 'goal/change', + version: GOAL_CHANGE_VERSION, + operation: 'clear', + cleared: decodeRef(value['cleared']), + clearedAt: nonNegativeInteger(value['clearedAt'], 'clearedAt'), + }; + } + if (typeof value['operation'] !== 'string' + || !SNAPSHOT_OPERATIONS.has(value['operation'])) { + throw new Error('goal change operation is invalid'); + } + const allowed = ['createdAt', 'goal', 'kind', 'operation', 'roundsStarted', 'updatedAt', 'version']; + if (Object.keys(value).sort().join(',') !== allowed.sort().join(',')) { + throw new Error(`goal snapshot change must have exactly ${allowed.sort().join(',')} fields`); + } + const createdAt = nonNegativeInteger(value['createdAt'], 'createdAt'); + const updatedAt = nonNegativeInteger(value['updatedAt'], 'updatedAt'); + if (updatedAt < createdAt) + throw new Error('goal change updatedAt cannot precede createdAt'); + return { + kind: 'goal/change', + version: GOAL_CHANGE_VERSION, + operation: value['operation'], + goal: decodeSnapshot(value['goal']), + roundsStarted: nonNegativeInteger(value['roundsStarted'], 'roundsStarted'), + createdAt, + updatedAt, + }; +} +/** Narrow model attribution to a valid goal source. */ +function goalSource(source) { + if (source.kind !== 'goal') + return undefined; + if (typeof source.goalId !== 'string' || source.goalId.length === 0 + || !Number.isSafeInteger(source.revision) || source.revision < 1 + || !Number.isSafeInteger(source.round) || source.round < 1) { + throw new Error('goal message source is invalid'); + } + return source; +} +/** Require two snapshots to retain fields that only `edit` may replace. */ +function requireSameDefinition(current, next, operation) { + if (next.objective !== current.objective || next.maxGoalRounds !== current.maxGoalRounds) { + throw new Error(`goal ${operation} cannot change objective or maxGoalRounds`); + } +} +/** Require one exact next revision of the current goal. */ +function requireNextRevision(current, next, operation) { + if (next.id !== current.id || next.revision !== current.revision + 1) { + throw new Error(`goal ${operation} must advance the current goal by one revision`); + } +} +/** Validate one non-create snapshot operation against the preceding projection. */ +function validateSnapshotTransition(state, change, current) { + const next = change.goal; + requireNextRevision(current, next, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === undefined) + throw new Error('current goal fold lacks updatedAt'); + if (change.createdAt !== state.createdAt + || change.updatedAt < state.updatedAt + || change.roundsStarted !== state.roundsStarted) { + throw new Error(`goal ${change.operation} does not preserve the current counters and timestamps`); + } + switch (change.operation) { + case 'edit': + if (next.phase !== current.phase + || JSON.stringify(next.blockedReason) !== JSON.stringify(current.blockedReason)) { + throw new Error('goal edit cannot change phase or blocked reason'); + } + break; + case 'pause': + requireSameDefinition(current, next, change.operation); + if (current.phase !== 'active' || next.phase !== 'paused') + throw new Error('goal pause has an invalid phase transition'); + break; + case 'resume': { + requireSameDefinition(current, next, change.operation); + const resumable = new Set([ + 'active', + 'paused', + 'blocked', + ]); + if (!resumable.has(current.phase) || next.phase !== 'active' || state.roundsStarted >= next.maxGoalRounds) { + throw new Error('goal resume has an invalid phase transition or exhausted round budget'); + } + break; + } + case 'complete': + requireSameDefinition(current, next, change.operation); + if (current.phase === 'complete' || next.phase !== 'complete') + throw new Error('goal complete has an invalid phase transition'); + break; + case 'block': + requireSameDefinition(current, next, change.operation); + if (current.phase !== 'active' || next.phase !== 'blocked') + throw new Error('goal block has an invalid phase transition'); + break; + /* v8 ignore start -- the caller excludes create and GoalOperation is closed; these arms retain fail-loud exhaustiveness */ + case 'create': + throw new Error('goal create cannot be validated as a current-goal transition'); + default: + change.operation; + throw new Error('unknown goal snapshot operation'); + /* v8 ignore stop */ + } +} +/** + * Return the revision identity carried by a snapshot or tombstone. + * @param change - decoded goal mutation. + * @returns stable identity used to reconcile a deferred change with its log event. + */ +export function goalChangeRef(change) { + return change.operation === 'clear' + ? change.cleared + : { id: change.goal.id, revision: change.goal.revision }; +} +/** + * Validate and apply one decoded change to a mutable accumulator. + * @param state - preceding durable goal projection. + * @param change - decoded full snapshot or clear tombstone. + */ +export function applyGoalChange(state, change) { + const ref = goalChangeRef(change); + if (change.operation === 'clear') { + const current = state.goal; + if (current === undefined) + throw new Error('goal clear requires a current goal'); + requireNextRevision(current, change.cleared, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === undefined) + throw new Error('current goal fold lacks updatedAt'); + if (change.clearedAt < state.updatedAt) { + throw new Error('goal clear timestamp cannot precede the current goal update'); + } + state.goal = undefined; + state.roundsStarted = 0; + state.createdAt = undefined; + state.updatedAt = undefined; + state.lastRef = ref; + return; + } + if (change.operation === 'create') { + if (change.goal.revision !== 1 || change.goal.phase !== 'active' || change.roundsStarted !== 0 + || (state.goal !== undefined && state.goal.phase !== 'complete') + || state.seenGoalIds.has(change.goal.id)) { + throw new Error('goal create requires a fresh active revision-one goal with zero rounds'); + } + state.seenGoalIds.add(change.goal.id); + } + else { + const current = state.goal; + if (current === undefined) + throw new Error(`goal ${change.operation} requires a current goal`); + validateSnapshotTransition(state, change, current); + } + state.goal = change.goal; + state.roundsStarted = change.roundsStarted; + state.createdAt = change.createdAt; + state.updatedAt = change.updatedAt; + state.lastRef = ref; +} +/** + * Apply one session event to the strict durable goal fold. + * @param state - mutable fold accumulator. + * @param event - next event in sequence order. + */ +export function applyGoalEvent(state, event) { + if (event.type === 'goal/change') { + const change = decodeGoalChange(event.data); + /* v8 ignore next -- the event's declared payload always identifies itself as a goal change. */ + if (change === undefined) + throw new Error(`goal change at session event ${event.seq} has an invalid kind`); + applyGoalChange(state, change); + return; + } + if (event.type === 'user/message') { + const source = goalSource(event.data.source); + if (source === undefined) + return; + const current = state.goal; + if (current === undefined || current.phase !== 'active' || source.goalId !== current.id + || source.revision !== current.revision || source.round !== state.roundsStarted + 1 + || source.round > current.maxGoalRounds) { + throw new Error(`goal round at session event ${event.seq} is not the next admitted round of the active goal`); + } + state.roundsStarted = source.round; + } +} +/** + * Fold current goal state from a contiguous session event log. + * @param events - session events in sequence order. + * @returns a fresh durable projection; activation is deliberately absent. + */ +export function foldGoal(events) { + const state = emptyGoalFoldState(); + for (const event of events) + applyGoalEvent(state, event); + return { + ...state.goal === undefined ? {} : { goal: { ...state.goal } }, + roundsStarted: state.roundsStarted, + ...state.createdAt === undefined ? {} : { createdAt: state.createdAt }, + ...state.updatedAt === undefined ? {} : { updatedAt: state.updatedAt }, + ...state.lastRef === undefined ? {} : { lastRef: { ...state.lastRef } }, + }; +} +//# sourceMappingURL=fold.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/index.d.ts new file mode 100644 index 0000000..a6cd541 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/index.d.ts @@ -0,0 +1,155 @@ +/** + * Same-session goal domain: event-sourced state, compare-and-set mutations, + * and process-local continuation activation. + * @module @deepseek-ai/dsh-goal + */ +import { Context } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'; +import type { CreateGoalRequest, CreateGoalResult, EditGoalRequest, GoalBlockReason, GoalProjection, GoalRef, GoalView } from './types.ts'; +export type * from './types.ts'; +export type * from './domain.ts'; +export { GOAL_CHANGE_VERSION, GoalError, GoalId } from './runtime.ts'; +export { decodeGoalChange, foldGoal, goalChangeRef } from './fold.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + goals: GoalService; + } +} +/** + * Light last-wins fold of the `goal` projection unit. Unlike the strict + * replay fold (fold.ts: transition validation, fail-loud on malformed + * changes, Set-typed state), this transition is projection-grade: the state + * is plain JSON (persisted-cache precondition), any non-goal or malformed + * event returns the same reference (the registry's Object.is gate — the + * title/todos posture), and correctness of the written change is the write + * side's job (GoalService validated it before appending; the package + * invariant rejects a violating stream fail-loud where it is installed). + * @param state - the projection covering all prior events. + * @param event - the next committed session event. + * @returns the next projection (same reference when the event is not a goal change). + */ +export declare function applyGoalProjection(state: GoalProjection | null, event: SessionEvent): GoalProjection | null; +/** Deployment defaults for goal creation. */ +export interface Config { + /** Total rounds used when a create request omits its own cap. */ + defaultMaxGoalRounds?: number; +} +/** Resolved defaults. */ +export interface ResolvedConfig { + /** Validated positive safe-integer default round cap. */ + defaultMaxGoalRounds: number; +} +/** Goal service (`ctx.goals`) backed exclusively by the owning session log. */ +export declare class GoalService extends TypertRemoteService { + static inject: string[]; + static Config: z; + private readonly resolved; + private readonly caches; + constructor(ctx: Context, config?: Config); + /** + * Read the current goal for one exact live agent. + * @param agent - owning live agent. + * @returns a fresh view or `undefined` when no goal is current. + * @throws {@link GoalError} when the agent is not the registry's live instance. + */ + get(agent: Agent): GoalView | undefined; + /** + * Remove process-local continuation authority without changing durable goal + * phase or revision. Lifecycle owners use this before unloading a driver; + * a later human-authorized {@link resume} records the new activation edge. + * @param agent - owning live agent. + * @returns a fresh disarmed view, or `undefined` when no goal is current. + */ + disarm(agent: Agent): GoalView | undefined; + /** + * Create and arm a goal. A completed goal may be replaced; every other + * current phase must be cleared or resumed instead. + * @param agent - owning live agent. + * @param request - objective and optional round cap. + * @returns the created live view. + */ + create(agent: Agent, request: CreateGoalRequest): GoalView; + /** + * Edit objective and/or round cap without changing phase. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param request - at least one replacement field. + * @returns the edited view. + */ + edit(agent: Agent, ref: GoalRef, request: EditGoalRequest): GoalView; + /** + * Pause an active goal and disarm automatic continuation. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the paused view. + */ + pause(agent: Agent, ref: GoalRef): GoalView; + /** + * Resume and arm a stopped goal, or rearm an active goal after a + * session-start edge, while its round budget still has capacity. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the active view. + */ + resume(agent: Agent, ref: GoalRef): GoalView; + /** + * Mark a current non-complete goal complete and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the completed view. + */ + complete(agent: Agent, ref: GoalRef): GoalView; + /** + * Mark an active goal blocked and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param reason - policy-owned stable code and human-readable explanation. + * @returns the blocked view with its durable reason. + */ + block(agent: Agent, ref: GoalRef, reason: GoalBlockReason): GoalView; + /** + * Clear the current goal while retaining a durable tombstone and history. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the tombstone ref whose revision is one past the cleared snapshot. + */ + clear(agent: Agent, ref: GoalRef): GoalRef; + /** Resolve and validate the cache used by a mutation. */ + private prepareMutation; + /** Reject stale or missing current-state refs. */ + private expectCurrent; + /** Enforce exact live-agent identity rather than trusting a matching id. */ + private assertLive; + /** Return the per-session cache, folding a seed once with activation disarmed. */ + private cache; + /** Incrementally observe durable events and reconcile local activation intent. */ + private sync; + /** Build a new revision with one replacement phase. */ + private withPhase; + /** Shared validated phase transition. */ + private transition; + /** Render a stable invalid-transition error. */ + private transitionError; + /** Commit a mutation that retains the current goal's derived counters/times. */ + private commitCurrent; + /** Clamp a current goal's next timestamp across backward wall-clock movement. */ + private nextMutationTime; + /** Build and commit one full-snapshot mutation. */ + private commitSnapshot; + /** Commit one mutation into the goal log, cache, and live event stream. */ + private commit; + /** Build a detached current view. */ + private view; + /** + * Create one Goal through the remote boundary. + * @param agent - exact live Agent resolved from the wire identity. + * @param request - objective and optional round cap. + * @returns the created Goal identity. + */ + remoteExportCreate(agent: Agent, request: CreateGoalRequest): CreateGoalResult; +} +export default GoalService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/index.js new file mode 100644 index 0000000..8ad9f44 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/index.js @@ -0,0 +1,495 @@ +/** + * Same-session goal domain: event-sourced state, compare-and-set mutations, + * and process-local continuation activation. + * @module @deepseek-ai/dsh-goal + */ +var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; +var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +import { randomUUID } from 'node:crypto'; +import z from '@deepseek-ai/schemastery'; +import { z as zod } from 'zod'; +import { agentEvents } from '@deepseek-ai/dsh-agent'; +import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'; +import { applyGoalEvent, decodeGoalChange, emptyGoalFoldState, goalChangeRef, } from "./fold.js"; +import { GOAL_CHANGE_VERSION, GoalError, GoalId, } from "./runtime.js"; +export { GOAL_CHANGE_VERSION, GoalError, GoalId } from "./runtime.js"; +export { decodeGoalChange, foldGoal, goalChangeRef } from "./fold.js"; +/** Wire payload schema of the `goal` projection (whole current goal or pre-create/cleared null). */ +const goalProjectionSchema = zod.union([ + zod.object({ + goal: zod.object({ + id: zod.string().min(1), + revision: zod.number().int().positive(), + objective: zod.string().min(1), + phase: zod.union([zod.literal('active'), zod.literal('paused'), zod.literal('blocked'), zod.literal('complete')]), + blockedReason: zod.object({ code: zod.string(), message: zod.string() }).optional(), + maxGoalRounds: zod.number().int().positive(), + }), + roundsStarted: zod.number().int().nonnegative(), + createdAt: zod.number(), + updatedAt: zod.number(), + }), + zod.null(), +]); +/** + * Light last-wins fold of the `goal` projection unit. Unlike the strict + * replay fold (fold.ts: transition validation, fail-loud on malformed + * changes, Set-typed state), this transition is projection-grade: the state + * is plain JSON (persisted-cache precondition), any non-goal or malformed + * event returns the same reference (the registry's Object.is gate — the + * title/todos posture), and correctness of the written change is the write + * side's job (GoalService validated it before appending; the package + * invariant rejects a violating stream fail-loud where it is installed). + * @param state - the projection covering all prior events. + * @param event - the next committed session event. + * @returns the next projection (same reference when the event is not a goal change). + */ +export function applyGoalProjection(state, event) { + if (event.type !== 'goal/change') + return state; + let change; + try { + change = decodeGoalChange(event.data); + } + catch (_invalidPersistedGoalChange) { + return state; + } + if (change === undefined) + return state; + return change.operation === 'clear' + ? null + : { + goal: change.goal, + roundsStarted: change.roundsStarted, + createdAt: change.createdAt, + updatedAt: change.updatedAt, + }; +} +/** Validate a caller-visible positive safe-integer round cap. */ +function resolveMaxGoalRounds(value) { + if (!Number.isSafeInteger(value) || value < 1) { + throw new GoalError('maxGoalRounds must be a positive safe integer', 'GOAL_INVALID_MAX_ROUNDS'); + } + return value; +} +/** Validate and normalize an objective at the domain boundary. */ +function resolveObjective(value) { + if (typeof value !== 'string' || value.trim().length === 0) { + throw new GoalError('goal objective must be a non-empty string', 'GOAL_INVALID_OBJECTIVE'); + } + return value.trim(); +} +/** Materialize deployment defaults and validate one create request. */ +function resolveCreateGoal(request, defaultMaxGoalRounds) { + return { + objective: resolveObjective(request.objective), + maxGoalRounds: resolveMaxGoalRounds(request.maxGoalRounds ?? defaultMaxGoalRounds), + }; +} +/** Validate and detach one policy-owned blocker explanation. */ +function resolveBlockReason(reason) { + const record = typeof reason === 'object' && reason !== null && !Array.isArray(reason) + ? reason + : undefined; + const code = record?.['code']; + const message = record?.['message']; + if (typeof code !== 'string' || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(code) + || typeof message !== 'string' || message.trim().length === 0) { + throw new GoalError('goal block reason requires a lower-kebab-case code and a non-empty message', 'GOAL_INVALID_BLOCK_REASON'); + } + return { code, message: message.trim() }; +} +/** Goal service (`ctx.goals`) backed exclusively by the owning session log. */ +let GoalService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _edit_decorators; + let _pause_decorators; + let _resume_decorators; + let _complete_decorators; + let _clear_decorators; + let _remoteExportCreate_decorators; + return class GoalService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _edit_decorators = [Remote('edit')]; + _pause_decorators = [Remote('pause')]; + _resume_decorators = [Remote('resume')]; + _complete_decorators = [Remote('complete')]; + _clear_decorators = [Remote('clear')]; + _remoteExportCreate_decorators = [Remote('create')]; + __esDecorate(this, null, _edit_decorators, { kind: "method", name: "edit", static: false, private: false, access: { has: obj => "edit" in obj, get: obj => obj.edit }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _pause_decorators, { kind: "method", name: "pause", static: false, private: false, access: { has: obj => "pause" in obj, get: obj => obj.pause }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resume_decorators, { kind: "method", name: "resume", static: false, private: false, access: { has: obj => "resume" in obj, get: obj => obj.resume }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _complete_decorators, { kind: "method", name: "complete", static: false, private: false, access: { has: obj => "complete" in obj, get: obj => obj.complete }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _clear_decorators, { kind: "method", name: "clear", static: false, private: false, access: { has: obj => "clear" in obj, get: obj => obj.clear }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _remoteExportCreate_decorators, { kind: "method", name: "remoteExportCreate", static: false, private: false, access: { has: obj => "remoteExportCreate" in obj, get: obj => obj.remoteExportCreate }, metadata: _metadata }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + static inject = ['agents']; + static Config = z.object({ + defaultMaxGoalRounds: z.number().default(256), + }); + resolved = __runInitializers(this, _instanceExtraInitializers); + caches = new WeakMap(); + constructor(ctx, config = {}) { + super(ctx, 'goals'); + this.resolved = { + defaultMaxGoalRounds: resolveMaxGoalRounds(config.defaultMaxGoalRounds ?? 256), + }; + ctx.on('agent/session-start', ({ agent }) => { + this.cache(agent.session).activation = 'disarmed'; + }); + // The `goal` projection unit: last-wins fold of goal/change whole values + // (see applyGoalProjection). The unit child activates only when a + // projection registry is composed (headless assemblies stay unaffected). + ctx.inject(['sessionProjections'], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: 'goal', + schema: goalProjectionSchema, + init: () => null, + apply: applyGoalProjection, + view: state => state, + stateVersion: 4, + }); + }); + } + /** + * Read the current goal for one exact live agent. + * @param agent - owning live agent. + * @returns a fresh view or `undefined` when no goal is current. + * @throws {@link GoalError} when the agent is not the registry's live instance. + */ + get(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + return this.view(cache); + } + /** + * Remove process-local continuation authority without changing durable goal + * phase or revision. Lifecycle owners use this before unloading a driver; + * a later human-authorized {@link resume} records the new activation edge. + * @param agent - owning live agent. + * @returns a fresh disarmed view, or `undefined` when no goal is current. + */ + disarm(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + cache.activation = 'disarmed'; + return this.view(cache); + } + /** + * Create and arm a goal. A completed goal may be replaced; every other + * current phase must be cleared or resumed instead. + * @param agent - owning live agent. + * @param request - objective and optional round cap. + * @returns the created live view. + */ + create(agent, request) { + const spec = resolveCreateGoal(request, this.resolved.defaultMaxGoalRounds); + const cache = this.prepareMutation(agent); + const current = cache.state.goal; + if (current !== undefined && current.phase !== 'complete') { + throw new GoalError(`goal "${current.id}" already exists with phase "${current.phase}"`, 'GOAL_ALREADY_EXISTS'); + } + const now = Date.now(); + const goal = { + id: GoalId(`goal-${randomUUID()}`), + revision: 1, + objective: spec.objective, + phase: 'active', + maxGoalRounds: spec.maxGoalRounds, + }; + return this.commitSnapshot(agent, cache, 'create', goal, 0, now, now, 'armed'); + } + /** + * Edit objective and/or round cap without changing phase. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param request - at least one replacement field. + * @returns the edited view. + */ + edit(agent, ref, request) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (request.objective === undefined && request.maxGoalRounds === undefined) { + throw new GoalError('goal edit requires objective and/or maxGoalRounds', 'GOAL_INVALID_EDIT'); + } + const goal = { + ...current, + revision: current.revision + 1, + ...request.objective === undefined ? {} : { objective: resolveObjective(request.objective) }, + ...request.maxGoalRounds === undefined ? {} : { maxGoalRounds: resolveMaxGoalRounds(request.maxGoalRounds) }, + }; + return this.commitCurrent(agent, cache, 'edit', goal, cache.activation); + } + /** + * Pause an active goal and disarm automatic continuation. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the paused view. + */ + pause(agent, ref) { + return this.transition(agent, ref, 'pause', ['active'], 'paused', 'disarmed'); + } + /** + * Resume and arm a stopped goal, or rearm an active goal after a + * session-start edge, while its round budget still has capacity. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the active view. + */ + resume(agent, ref) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + const resumable = ['active', 'paused', 'blocked']; + if (!resumable.includes(current.phase)) { + throw this.transitionError(current, 'resume', resumable); + } + if (current.phase === 'active' && cache.activation === 'armed') { + throw new GoalError(`goal "${current.id}" is already active and armed`, 'GOAL_INVALID_TRANSITION'); + } + if (cache.state.roundsStarted >= current.maxGoalRounds) { + throw new GoalError(`goal "${current.id}" exhausted ${current.maxGoalRounds} goal rounds; increase maxGoalRounds before resuming`, 'GOAL_INVALID_TRANSITION'); + } + return this.commitCurrent(agent, cache, 'resume', this.withPhase(current, 'active'), 'armed'); + } + /** + * Mark a current non-complete goal complete and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the completed view. + */ + complete(agent, ref) { + return this.transition(agent, ref, 'complete', ['active', 'paused', 'blocked'], 'complete', 'disarmed'); + } + /** + * Mark an active goal blocked and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param reason - policy-owned stable code and human-readable explanation. + * @returns the blocked view with its durable reason. + */ + block(agent, ref, reason) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (current.phase !== 'active') { + throw this.transitionError(current, 'block', ['active']); + } + return this.commitCurrent(agent, cache, 'block', { ...this.withPhase(current, 'blocked'), blockedReason: resolveBlockReason(reason) }, 'disarmed'); + } + /** + * Clear the current goal while retaining a durable tombstone and history. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the tombstone ref whose revision is one past the cleared snapshot. + */ + clear(agent, ref) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + const tombstone = { id: current.id, revision: current.revision + 1 }; + const change = { + kind: 'goal/change', + version: GOAL_CHANGE_VERSION, + operation: 'clear', + cleared: tombstone, + clearedAt: this.nextMutationTime(cache), + }; + this.commit(agent, cache, change, 'disarmed'); + return { ...tombstone }; + } + /** Resolve and validate the cache used by a mutation. */ + prepareMutation(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + return cache; + } + /** Reject stale or missing current-state refs. */ + expectCurrent(cache, ref) { + const current = cache.state.goal; + if (current === undefined) + throw new GoalError('no current goal', 'GOAL_NOT_FOUND'); + if (ref.id !== current.id || ref.revision !== current.revision) { + throw new GoalError(`stale goal ref "${ref.id}" revision ${ref.revision}; current is "${current.id}" revision ${current.revision}`, 'GOAL_STALE_REVISION'); + } + return current; + } + /** Enforce exact live-agent identity rather than trusting a matching id. */ + assertLive(agent) { + if (this.ctx.agents.get(agent.id) !== agent) { + throw new GoalError(`agent "${agent.id}" is not live in this registry`, 'GOAL_AGENT_NOT_LIVE'); + } + } + /** Return the per-session cache, folding a seed once with activation disarmed. */ + cache(session) { + let cache = this.caches.get(session); + if (cache !== undefined) + return cache; + const state = emptyGoalFoldState(); + for (const event of session.events) + applyGoalEvent(state, event); + cache = { + state, + activation: 'disarmed', + observedSeq: session.seq, + pendingActivation: undefined, + }; + this.caches.set(session, cache); + return cache; + } + /** Incrementally observe durable events and reconcile local activation intent. */ + sync(session, cache) { + for (const event of session.events.slice(cache.observedSeq)) { + applyGoalEvent(cache.state, event); + if (event.type === 'goal/change') { + cache.activation = cache.pendingActivation?.seq === event.seq + ? cache.pendingActivation.activation + : 'disarmed'; + } + cache.observedSeq += 1; + } + } + /** Build a new revision with one replacement phase. */ + withPhase(current, phase) { + return { + id: current.id, + revision: current.revision + 1, + objective: current.objective, + phase, + maxGoalRounds: current.maxGoalRounds, + }; + } + /** Shared validated phase transition. */ + transition(agent, ref, operation, allowed, phase, activation) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (!allowed.includes(current.phase)) + throw this.transitionError(current, operation, allowed); + return this.commitCurrent(agent, cache, operation, this.withPhase(current, phase), activation); + } + /** Render a stable invalid-transition error. */ + transitionError(current, operation, allowed) { + return new GoalError(`cannot ${operation} goal "${current.id}" from phase "${current.phase}"; expected ${allowed.join(' or ')}`, 'GOAL_INVALID_TRANSITION'); + } + /** Commit a mutation that retains the current goal's derived counters/times. */ + commitCurrent(agent, cache, operation, goal, activation) { + const createdAt = cache.state.createdAt; + /* v8 ignore next -- strict replay and every snapshot commit set createdAt whenever a current goal exists */ + if (createdAt === undefined) + throw new Error('current goal cache lacks createdAt'); + return this.commitSnapshot(agent, cache, operation, goal, cache.state.roundsStarted, createdAt, this.nextMutationTime(cache), activation); + } + /** Clamp a current goal's next timestamp across backward wall-clock movement. */ + nextMutationTime(cache) { + const updatedAt = cache.state.updatedAt; + /* v8 ignore next -- strict replay and every snapshot commit set updatedAt whenever a current goal exists */ + if (updatedAt === undefined) + throw new Error('current goal cache lacks updatedAt'); + return Math.max(Date.now(), updatedAt); + } + /** Build and commit one full-snapshot mutation. */ + commitSnapshot(agent, cache, operation, goal, roundsStarted, createdAt, updatedAt, activation) { + const change = { + kind: 'goal/change', + version: GOAL_CHANGE_VERSION, + operation, + goal, + roundsStarted, + createdAt, + updatedAt, + }; + this.commit(agent, cache, change, activation); + const view = this.view(cache); + /* v8 ignore next -- the durable goal event installs the snapshot before this read */ + if (view === undefined) + throw new Error('snapshot commit cleared the goal unexpectedly'); + return view; + } + /** Commit one mutation into the goal log, cache, and live event stream. */ + commit(agent, cache, change, activation) { + const ref = goalChangeRef(change); + cache.pendingActivation = { seq: agent.session.seq, activation }; + try { + agent.session.append('goal/change', change); + this.sync(agent.session, cache); + } + finally { + cache.pendingActivation = undefined; + } + const goal = this.view(cache); + const notification = { + operation: change.operation, + ref: { ...ref }, + ...goal === undefined ? {} : { goal }, + }; + agentEvents(this.ctx, agent).emit('goal/changed', { change: notification }); + } + /** Build a detached current view. */ + view(cache) { + const goal = cache.state.goal; + const createdAt = cache.state.createdAt; + const updatedAt = cache.state.updatedAt; + if (goal === undefined) + return undefined; + /* v8 ignore next 3 -- strict replay and snapshot commits establish both timestamps with every current goal */ + if (createdAt === undefined || updatedAt === undefined) { + throw new Error(`goal "${goal.id}" cache lacks timestamps`); + } + return { + ...goal, + roundsStarted: cache.state.roundsStarted, + createdAt, + updatedAt, + activation: cache.activation, + }; + } + /** + * Create one Goal through the remote boundary. + * @param agent - exact live Agent resolved from the wire identity. + * @param request - objective and optional round cap. + * @returns the created Goal identity. + */ + remoteExportCreate(agent, request) { + const view = this.create(agent, request); + return { ref: { id: view.id, revision: view.revision } }; + } + }; +})(); +export { GoalService }; +export default GoalService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.d.ts new file mode 100644 index 0000000..e0e557b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned durable goal-stream invariants. @module @deepseek-ai/dsh-goal/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "goal-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the goal-stream invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.js new file mode 100644 index 0000000..93b34f5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.js @@ -0,0 +1,70 @@ +/** Package-owned durable goal-stream invariants. @module @deepseek-ai/dsh-goal/invariant */ +import { applyGoalEvent, emptyGoalFoldState } from "./fold.js"; +const PACKAGE_NAME = '@deepseek-ai/dsh-goal'; +/** Cordis companion plugin name. */ +export const name = 'goal-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Copy the independent fold before validating one candidate event. */ +function cloneState(state) { + return { + goal: state.goal, + roundsStarted: state.roundsStarted, + createdAt: state.createdAt, + updatedAt: state.updatedAt, + lastRef: state.lastRef, + seenGoalIds: new Set(state.seenGoalIds), + }; +} +/** Apply one event through the strict goal decoder and attribute failures. */ +function applyChecked(state, event, fail) { + try { + applyGoalEvent(state, event); + } + catch (error) { + /* v8 ignore next -- the strict goal decoder throws Error instances */ + const message = error instanceof Error ? error.message : String(error); + fail(`session event ${event.seq} violates the durable goal stream: ${message}`); + } +} +/** Install an independent incremental fold over every attached session. */ +const install = Object.assign((ctx, fail) => { + const states = new WeakMap(); + const staged = new WeakMap(); + const seed = (session) => { + const state = emptyGoalFoldState(); + for (const event of session.events) + applyChecked(state, event, fail); + states.set(session, state); + return state; + }; + /* v8 ignore next -- session/event always follows list() or session/created seeding */ + const stateFor = (session) => states.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) + seed(session); + ctx.on('session/created', (session) => { seed(session); }, { global: true }); + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') + return; + const [session, event] = args; + const state = cloneState(stateFor(session)); + applyChecked(state, event, fail); + staged.set(event, { session, state }); + }, { global: true }); + ctx.on('session/event', (session, event) => { + const candidate = staged.get(event); + /* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */ + if (candidate === undefined || candidate.session !== session) { + return fail('session/event reached publication without matching goal-fold validation'); + } + staged.delete(event); + states.set(session, candidate.state); + }, { global: true }); +}, { inject: ['sessions'] }); +/** + * Register the goal-stream invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.d.ts new file mode 100644 index 0000000..206ace0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.d.ts @@ -0,0 +1,21 @@ +/** Runtime constructors and protocol constants for the goal domain. */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import type { GoalId as GoalIdType } from './types.ts'; +import type { GoalErrorCode } from './domain.ts'; +/** Version of the goal change embedded in a round-zero message source. */ +export declare const GOAL_CHANGE_VERSION = 1; +/** + * Brand a string as a goal id. + * @param id - raw goal identifier. + * @returns the same string with the compile-time brand. + */ +export declare function GoalId(id: string): GoalIdType; +/** Error returned by the goal domain boundary. */ +export declare class GoalError extends HarnessError { + /** + * @param message - human-readable rejection reason. + * @param code - stable machine-routable classification. + */ + constructor(message: string, code: GoalErrorCode); +} +//# sourceMappingURL=runtime.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.js new file mode 100644 index 0000000..2a11eb6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.js @@ -0,0 +1,25 @@ +/** Runtime constructors and protocol constants for the goal domain. */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +/** Version of the goal change embedded in a round-zero message source. */ +export const GOAL_CHANGE_VERSION = 1; +/** + * Brand a string as a goal id. + * @param id - raw goal identifier. + * @returns the same string with the compile-time brand. + */ +export function GoalId(id) { + return id; +} +/** Error returned by the goal domain boundary. */ +export class GoalError extends HarnessError { + /** + * @param message - human-readable rejection reason. + * @param code - stable machine-routable classification. + */ + // Keep the constructor to narrow HarnessError's string code at this boundary. + // oxlint-disable-next-line typescript/no-useless-constructor -- type-only narrowing + constructor(message, code) { + super(message, code); + } +} +//# sourceMappingURL=runtime.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/types.d.ts new file mode 100644 index 0000000..3cb595a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/types.d.ts @@ -0,0 +1,96 @@ +/** + * Pure types of the goal domain: the ONE home of the `goal` projection-key + * declaration plus the durable payload vocabulary it carries, free of this + * package's host-side imports (cordis events, dsh-agent, dsh-llm, the + * service). Two namespace projections serve it — `./types` for host + * consumers, `./client` (the browser half-entry's re-export) for client + * aggregates — with zero content duplication. Host-coupled domain + * vocabulary (message sources, events, fold shapes) lives in ./domain.ts. + * + * @module @deepseek-ai/dsh-goal/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Identifies one goal across its durable revisions. */ +export type GoalId = Branded<'GoalId'>; +/** Compare-and-set identity for one exact goal revision. */ +export interface GoalRef { + /** Stable goal identity. */ + readonly id: GoalId; + /** Positive revision; every durable mutation increments it. */ + readonly revision: number; +} +/** Input whose omitted round cap is resolved by the service configuration. */ +export interface CreateGoalRequest { + readonly objective: string; + readonly maxGoalRounds?: number; +} +/** Wire-safe acknowledgement of one created goal. */ +export interface CreateGoalResult { + readonly ref: GoalRef; +} +/** Fields changed by an edit; at least one must be present. */ +export interface EditGoalRequest { + readonly objective?: string; + readonly maxGoalRounds?: number; +} +/** Durable continuation phase. Activation is process-local and separate. */ +export type GoalPhase = 'active' | 'paused' | 'blocked' | 'complete'; +/** Machine-routable and human-readable explanation for a blocked goal. */ +export interface GoalBlockReason { + /** Stable lower-kebab-case classification chosen by the blocking policy. */ + readonly code: string; + /** Non-empty explanation shown to humans and models. */ + readonly message: string; +} +/** Full durable state written by every non-clear goal mutation. */ +export interface GoalSnapshot extends GoalRef { + /** Human-requested completion objective. */ + readonly objective: string; + /** Durable lifecycle phase. */ + readonly phase: GoalPhase; + /** Present exactly while `phase` is `blocked`. */ + readonly blockedReason?: GoalBlockReason; + /** Total admitted goal-round cap. */ + readonly maxGoalRounds: number; +} +/** Whether this live process may automatically continue an active goal. */ +export type GoalActivation = 'armed' | 'disarmed'; +/** Current goal projection, including values derived from the session log. */ +export interface GoalView extends GoalSnapshot { + /** Highest admitted round number for this goal. */ + readonly roundsStarted: number; + /** Epoch milliseconds of the create mutation. */ + readonly createdAt: number; + /** Epoch milliseconds of the latest mutation. */ + readonly updatedAt: number; + /** Process-local continuation eligibility; never persisted. */ + readonly activation: GoalActivation; +} +/** + * The `goal` projection value: the current durable goal with its replay + * counters, exactly as the latest `goal/change` event carried them. + * Activation is process-local (never persisted) and deliberately absent — + * the projection reflects durable phase only. + */ +export interface GoalProjection { + /** Current durable goal snapshot (the CAS ref for mutations rides on it). */ + readonly goal: GoalSnapshot; + /** Highest admitted round number for this goal. */ + readonly roundsStarted: number; + /** Epoch milliseconds of the create mutation. */ + readonly createdAt: number; + /** Epoch milliseconds of the latest mutation. */ + readonly updatedAt: number; +} +declare module '@deepseek-ai/dsh-session-projection/types' { + interface SessionProjectionMap { + /** + * The session's current goal (the latest `goal/change` whole value), or + * `null` before the first create and after a clear tombstone. + * Whole-value rule: every goal change carries the complete post-change + * state, so the fold is last-wins. + */ + goal: GoalProjection | null; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/types.js new file mode 100644 index 0000000..4fec899 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/lib/types/types.js @@ -0,0 +1,13 @@ +/** + * Pure types of the goal domain: the ONE home of the `goal` projection-key + * declaration plus the durable payload vocabulary it carries, free of this + * package's host-side imports (cordis events, dsh-agent, dsh-llm, the + * service). Two namespace projections serve it — `./types` for host + * consumers, `./client` (the browser half-entry's re-export) for client + * aggregates — with zero content duplication. Host-coupled domain + * vocabulary (message sources, events, fold shapes) lives in ./domain.ts. + * + * @module @deepseek-ai/dsh-goal/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/package.json new file mode 100644 index 0000000..65d023b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal/package.json @@ -0,0 +1,82 @@ +{ + "name": "@deepseek-ai/dsh-goal", + "description": "Event-sourced same-session goal state and lifecycle service for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/goal/goal" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./client": { + "types": "./lib/types/client.d.ts", + "default": "./lib/types/client.js" + }, + "./typert": { + "types": "./lib/typert.host.d.ts", + "default": "./lib/typert.host.js" + }, + "./remote": { + "types": "./lib/typert.remote-client.d.ts", + "default": "./lib/typert.remote-client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts", + "lib/typert.host.js", + "lib/typert.host.d.ts", + "lib/typert.remote-client.js", + "lib/typert.remote-client.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-loader-smoke": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..fb5edd1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..aa2ae83 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.i18n.yaml new file mode 100644 index 0000000..3fee674 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/goal/goal/README.md +README.md: 98765a809820bcd4aeba31e1dd4ef6e92eb30760 +README.zh.md: d133cb154523dcf47b8a033cc60411ac6f6e9c9e diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.md new file mode 100644 index 0000000..98765a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.md @@ -0,0 +1,58 @@ +# @deepseek-ai/dsh-goal + +English | [中文](README.zh.md) + +Event-sourced same-session goal state. The service retains one current completion objective in an agent's existing session while keeping permission to continue as process-local activation. The [goal-domain Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-persisted-same-session-goal-domain.md) owns the design rationale; the [goal type catalog](../../../docs/subsystems/goal.md) records the literal data shapes. + +## Config + +```yaml +- id: goal + name: '@deepseek-ai/dsh-goal' + config: + defaultMaxGoalRounds: 256 +``` + +`defaultMaxGoalRounds` must be a positive safe integer. `create()` materializes this deployment default internally before committing a goal; a request-level value overrides it. + +## Service contract + +`ctx.goals` accepts only the exact live `Agent` instance registered under its id. `get()` returns a detached `GoalView`; mutations use a `GoalRef { id, revision }` compare-and-set fence and reject stale refs. The service exposes create, edit, pause, resume, complete, block, and clear verbs through the generated region of [goal.md](../../../docs/subsystems/goal.md#cordis-surface). Creation default resolution is internal. `disarm()` is the lifecycle-only exception: it removes process-local continuation authority without writing a revision or emitting a mutation. + +At most one goal is current. Creation produces an active revision-one goal and arms it. A non-complete goal must be edited, transitioned, or cleared; a completed goal may be replaced by a globally fresh id. Edits retain phase, blocker reason, and activation. Pause, completion, blocking, and clear disarm activation. A block records a policy-owned lower-kebab-case code plus a normalized free-form explanation; provider limits, configured budgets, execution errors, and requests for human input all use this one durable phase rather than multiplying lifecycle states. Resume accepts a stopped phase or a disarmed active goal only while the configured round cap has remaining capacity; it clears any former blocker reason. An active armed goal rejects the redundant operation. + +Every mutation appends a durable `goal/change` event carrying the complete post-mutation snapshot; clear uses a revisioned tombstone. Goal state therefore does not depend on inbox placement, claim, admission, or discard. The session log is the only durable authority. + +Strict replay derives lifecycle mutations only from `goal/change` and rejects malformed shapes, discontinuous revisions, illegal lifecycle transitions, non-monotonic per-goal timestamps, and non-sequential admitted goal rounds. Positive rounds advance only on admitted goal-sourced `user/message` events. Mutation timestamps clamp against the preceding goal update when wall time moves backward. Incremental replay retains its cursor at the first corrupt event, and `goal/changed` fires after the durable event commits with listener failures contained. + +Activation is never persisted. A fresh cache and every `agent/session-start` edge disarm it even when replay finds an active durable phase. A continuation driver also calls `disarm()` before unload or after durability uncertainty. Session resume, fork, and driver replacement therefore retain the objective, phase, revisions, and admitted-round count without initiating work; a later explicit resume mutation must arm continuation. + +The separately published `./invariant` companion maintains an independent fold of each attached session. It rejects malformed goal changes, discontinuous revisions, illegal lifecycle transitions, timestamp regressions, and non-sequential admitted rounds before the candidate event enters the durable log. + +## Extension points + +Policy plugins call the service verbs and react to the scoped `goal/changed` event. A continuation consumer admits rounds as `user/message` events with `GoalMessageSource`; ordinary human turns never increment `roundsStarted`. Consumers use the `Agent` interface and events rather than importing `dsh-agent-loop`. + +## Model Experience + +### Goal-state mutation + +#### What the model sees + +Goal mutations do not inject model context. Tools such as `get_goal` return the current state, and a continuation consumer may render the objective and round state when it schedules model work. A future always-visible goal context belongs in a separate context plugin rather than the persistence path. + +#### Token effect + +Goal mutation events add no model tokens by themselves. Tool results and scheduled continuation prompts account for their own visible state. + +#### KV Cache effect + +There is no KV-cache effect until another component exposes goal state in model-visible input. + +## Known Limitations and Deferred Work + +- **State, not scheduling** — this package does not decide when an armed goal continues, retry abnormal failures, or cancel an active turn; those policies belong to agent-seam consumers. +- **Round-count budget only** — `maxGoalRounds` does not meter tokens, currency, wall time, or provider quotas. +- **No independent evaluator** — the caller that records completion or blocking is authoritative; evaluator-backed certification is deferred to a separate policy layer. +- **One current goal** — parallel objectives and a separate goal database are intentionally absent; history remains available in the session log after replacement or clear. +- **Trusted in-process producers** — a plugin with direct `Session` access can append counterfeit `goal/change` data. Strict replay detects malformed or inconsistent records and leaves goal access failed at that record until the log is repaired; this is integrity detection, not plugin isolation. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.zh.md new file mode 100644 index 0000000..d133cb1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/README.zh.md @@ -0,0 +1,58 @@ +# @deepseek-ai/dsh-goal + +[English](README.md) | 中文 + +事件溯源的同会话目标状态。该服务在 agent(智能体)的现有会话中保留一个当前待完成目标,同时将继续执行的权限作为进程本地续行启用状态。[goal 领域 Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-persisted-same-session-goal-domain.md) 负责设计理由;[goal 类型目录](../../../docs/subsystems/goal.md)记录具体的数据形状。 + +## 配置 + +```yaml +- id: goal + name: '@deepseek-ai/dsh-goal' + config: + defaultMaxGoalRounds: 256 +``` + +`defaultMaxGoalRounds` 必须是正的安全整数。`create()` 会在提交目标前于内部物化这项部署默认值;请求级取值可以覆盖它。 + +## 服务约定 + +`ctx.goals` 只接受以对应 id 注册的完全相同的活跃 `Agent` 实例。`get()` 返回与内部状态脱离的 `GoalView`;变更以 `GoalRef { id, revision }` 作为比较并设置防护,并拒绝陈旧引用。服务通过 [goal.md](../../../docs/subsystems/goal.md#cordis-surface) 的生成区块公开 create、edit、pause、resume、complete、block 和 clear 动词。创建默认值在内部解析。`disarm()` 是仅供生命周期使用的例外:它移除进程本地续行权限,不写入新 revision,也不发出变更事件。 + +最多只有一个当前目标。创建操作会生成 revision 为 1、phase 为 active 的目标并启用续行。未完成的目标必须编辑、转换或清除;已完成目标可以由拥有全局未使用过的 id 的目标替换。编辑会保留 phase、blocker reason 与 activation。暂停、完成、阻塞和清除都会停用续行。阻塞会记录策略自有的 lower-kebab-case 代码和规范化的自由文本说明;提供方限制、配置预算、执行错误与请求人工输入都使用这一种持久 phase,不会扩增生命周期状态。只有配置的 Round 上限仍有剩余容量时,resume 才接受已停止 phase 或 phase 为 active 但已停用续行的目标;它会清除原 blocker reason。phase 为 active 且已启用续行的目标会拒绝冗余操作。 + +每次变更都会追加持久的 `goal/change` 事件,其中携带变更后的完整快照;clear 使用带 revision 的 tombstone。因此,goal 状态不依赖 inbox 放置、领取、准入或丢弃。会话日志是唯一的持久权威。 + +严格回放只从 `goal/change` 派生生命周期变更,并拒绝形状错误、不连续 revision、非法生命周期转换、每目标时间戳非单调,以及不连续的已准入 Goal Round。只有来源为 goal 且已准入的 `user/message` 事件会推进正数 Round。挂钟时间倒退时,变更时间戳会限制在不早于上一次目标更新的值。增量回放会把游标保留在第一个损坏事件处;`goal/changed` 会在持久事件提交后触发,监听器失败会被隔离处理。 + +续行启用状态绝不持久化。新缓存与每次触发 `agent/session-start` 时都会停用续行,即使回放找到了持久 phase 为 active 的目标。续行驱动器在卸载前或持久性不确定后也会调用 `disarm()`。因此,会话恢复、fork 与驱动器替换会保留目标、phase、revision 和已准入 Round 数量,却不会启动工作;之后必须通过显式 resume 变更重新启用续行。 + +单独发布的 `./invariant` 配套模块会为每个已挂接会话维护独立折叠。它会在候选事件进入持久日志前拒绝格式错误的 goal 变更、不连续 revision、非法生命周期转换、时间戳回退,以及不连续的已准入 Round。 + +## 扩展点 + +策略插件调用服务动词,并响应限定范围的 `goal/changed` 事件。续行消费方将 Round 准入为 `user/message` 事件,并携带 `GoalMessageSource`;普通的人类轮次绝不会增加 `roundsStarted`。消费方使用 `Agent` 接口和事件,不导入 `dsh-agent-loop`。 + +## 模型体验 + +### 目标状态变更 + +#### 模型看到的内容 + +Goal 变更不会注入模型上下文。`get_goal` 等工具返回当前状态;继续执行消费方可以在调度模型工作时渲染目标描述与 Round 状态。未来如果需要始终可见的 goal 上下文,应由独立上下文插件实现,而不是放在持久化路径中。 + +#### Token 影响 + +Goal 变更事件本身不增加模型 token。工具结果和续行调度提示词各自暴露的状态会分别计入 token 用量。 + +#### KV Cache 影响 + +在其他组件把 goal 状态暴露为模型可见输入之前,不会影响 KV Cache。 + +## 已知限制与暂缓事项 + +- **只负责状态,不负责任务调度**:此包不决定已启用续行的目标何时继续,不重试异常失败,也不取消活跃轮次;这些策略属于 agent seam 消费方。 +- **只有 Round 数量预算**:`maxGoalRounds` 不计量 token、货币、挂钟时间或提供方配额。 +- **没有独立评估器**:记录完成或阻塞的调用方拥有最终决定权;由评估器支持的认证暂缓到独立策略层。 +- **只有一个当前目标**:系统有意不支持并行目标或独立目标数据库;替换或清除后,历史仍可在会话日志中读取。 +- **信任进程内生产方**:能直接访问 `Session` 的插件可以追加伪造的 `goal/change` 数据。严格回放会检测格式错误或不一致的记录,并使 goal 访问从该记录起失败,直到日志修复;这是完整性检测,不是插件隔离。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/index.js new file mode 100644 index 0000000..914d0eb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/index.js @@ -0,0 +1,827 @@ +import { randomUUID } from "node:crypto"; +import z from "@deepseek-ai/schemastery"; +import { z as z$1 } from "zod"; +import { agentEvents } from "@deepseek-ai/dsh-agent"; +import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol"; +import { HarnessError } from "@deepseek-ai/dsh-llm"; +//#region lib/types/runtime.js +/** Runtime constructors and protocol constants for the goal domain. */ +/** Version of the goal change embedded in a round-zero message source. */ +const GOAL_CHANGE_VERSION = 1; +/** +* Brand a string as a goal id. +* @param id - raw goal identifier. +* @returns the same string with the compile-time brand. +*/ +function GoalId(id) { + return id; +} +/** Error returned by the goal domain boundary. */ +var GoalError = class extends HarnessError { + /** + * @param message - human-readable rejection reason. + * @param code - stable machine-routable classification. + */ + constructor(message, code) { + super(message, code); + } +}; +//#endregion +//#region lib/types/fold.js +/** Pure replay fold and strict decoder for durable goal changes. */ +const SNAPSHOT_OPERATIONS = new Set([ + "create", + "edit", + "pause", + "resume", + "complete", + "block" +]); +const PHASES = new Set([ + "active", + "paused", + "blocked", + "complete" +]); +/** +* Build an empty replay accumulator. +* @returns mutable state with no current goal or prior ref. +*/ +function emptyGoalFoldState() { + return { + goal: void 0, + roundsStarted: 0, + createdAt: void 0, + updatedAt: void 0, + lastRef: void 0, + seenGoalIds: /* @__PURE__ */ new Set() + }; +} +/** Whether a value is a JSON record rather than an array. */ +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +/** Require one positive safe integer. */ +function positiveInteger(value, field) { + if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) throw new Error(`goal change ${field} must be a positive safe integer`); + return value; +} +/** Require one non-negative safe integer. */ +function nonNegativeInteger(value, field) { + if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new Error(`goal change ${field} must be a non-negative safe integer`); + return value; +} +/** Decode one canonical blocker explanation. */ +function decodeBlockReason(value) { + if (!isRecord(value) || Object.keys(value).sort().join(",") !== "code,message") throw new Error("goal change goal.blockedReason must have exactly code and message fields"); + if (typeof value["code"] !== "string" || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(value["code"])) throw new Error("goal change goal.blockedReason.code must be lower-kebab-case"); + if (typeof value["message"] !== "string" || value["message"].trim().length === 0 || value["message"] !== value["message"].trim()) throw new Error("goal change goal.blockedReason.message must be non-empty and normalized"); + return { + code: value["code"], + message: value["message"] + }; +} +/** Decode and validate one snapshot. */ +function decodeSnapshot(value) { + if (!isRecord(value)) throw new Error("goal change goal must be a record"); + if (typeof value["id"] !== "string" || value["id"].length === 0) throw new Error("goal change goal.id must be a non-empty string"); + if (typeof value["objective"] !== "string" || value["objective"].trim().length === 0 || value["objective"] !== value["objective"].trim()) throw new Error("goal change goal.objective must be non-empty and normalized"); + if (typeof value["phase"] !== "string" || !PHASES.has(value["phase"])) throw new Error("goal change goal.phase is invalid"); + const phase = value["phase"]; + const expectedKeys = phase === "blocked" ? "blockedReason,id,maxGoalRounds,objective,phase,revision" : "id,maxGoalRounds,objective,phase,revision"; + if (Object.keys(value).sort().join(",") !== expectedKeys) throw new Error(`goal change goal for phase ${phase} must have exactly ${expectedKeys} fields`); + return { + id: GoalId(value["id"]), + revision: positiveInteger(value["revision"], "goal.revision"), + objective: value["objective"], + phase, + maxGoalRounds: positiveInteger(value["maxGoalRounds"], "goal.maxGoalRounds"), + ...phase === "blocked" ? { blockedReason: decodeBlockReason(value["blockedReason"]) } : {} + }; +} +/** Decode and validate one ref. */ +function decodeRef(value) { + if (!isRecord(value) || Object.keys(value).sort().join(",") !== "id,revision") throw new Error("goal clear tombstone must have exactly id and revision fields"); + if (typeof value["id"] !== "string" || value["id"].length === 0) throw new Error("goal clear tombstone id must be a non-empty string"); + return { + id: GoalId(value["id"]), + revision: positiveInteger(value["revision"], "cleared.revision") + }; +} +/** +* Decode a value that declares itself as a goal change. Unrelated values +* return `undefined`; malformed goal changes fail replay loudly. +* @param value - candidate source change. +* @returns validated goal change or `undefined` for another value kind. +*/ +function decodeGoalChange(value) { + if (!isRecord(value) || value["kind"] !== "goal/change") return void 0; + if (value["version"] !== 1) throw new Error(`unsupported goal change version ${String(value["version"])}`); + if (value["operation"] === "clear") { + const allowed = [ + "cleared", + "clearedAt", + "kind", + "operation", + "version" + ]; + if (Object.keys(value).sort().join(",") !== allowed.sort().join(",")) throw new Error(`goal clear change must have exactly ${allowed.sort().join(",")} fields`); + return { + kind: "goal/change", + version: 1, + operation: "clear", + cleared: decodeRef(value["cleared"]), + clearedAt: nonNegativeInteger(value["clearedAt"], "clearedAt") + }; + } + if (typeof value["operation"] !== "string" || !SNAPSHOT_OPERATIONS.has(value["operation"])) throw new Error("goal change operation is invalid"); + const allowed = [ + "createdAt", + "goal", + "kind", + "operation", + "roundsStarted", + "updatedAt", + "version" + ]; + if (Object.keys(value).sort().join(",") !== allowed.sort().join(",")) throw new Error(`goal snapshot change must have exactly ${allowed.sort().join(",")} fields`); + const createdAt = nonNegativeInteger(value["createdAt"], "createdAt"); + const updatedAt = nonNegativeInteger(value["updatedAt"], "updatedAt"); + if (updatedAt < createdAt) throw new Error("goal change updatedAt cannot precede createdAt"); + return { + kind: "goal/change", + version: 1, + operation: value["operation"], + goal: decodeSnapshot(value["goal"]), + roundsStarted: nonNegativeInteger(value["roundsStarted"], "roundsStarted"), + createdAt, + updatedAt + }; +} +/** Narrow model attribution to a valid goal source. */ +function goalSource(source) { + if (source.kind !== "goal") return void 0; + if (typeof source.goalId !== "string" || source.goalId.length === 0 || !Number.isSafeInteger(source.revision) || source.revision < 1 || !Number.isSafeInteger(source.round) || source.round < 1) throw new Error("goal message source is invalid"); + return source; +} +/** Require two snapshots to retain fields that only `edit` may replace. */ +function requireSameDefinition(current, next, operation) { + if (next.objective !== current.objective || next.maxGoalRounds !== current.maxGoalRounds) throw new Error(`goal ${operation} cannot change objective or maxGoalRounds`); +} +/** Require one exact next revision of the current goal. */ +function requireNextRevision(current, next, operation) { + if (next.id !== current.id || next.revision !== current.revision + 1) throw new Error(`goal ${operation} must advance the current goal by one revision`); +} +/** Validate one non-create snapshot operation against the preceding projection. */ +function validateSnapshotTransition(state, change, current) { + const next = change.goal; + requireNextRevision(current, next, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === void 0) throw new Error("current goal fold lacks updatedAt"); + if (change.createdAt !== state.createdAt || change.updatedAt < state.updatedAt || change.roundsStarted !== state.roundsStarted) throw new Error(`goal ${change.operation} does not preserve the current counters and timestamps`); + switch (change.operation) { + case "edit": + if (next.phase !== current.phase || JSON.stringify(next.blockedReason) !== JSON.stringify(current.blockedReason)) throw new Error("goal edit cannot change phase or blocked reason"); + break; + case "pause": + requireSameDefinition(current, next, change.operation); + if (current.phase !== "active" || next.phase !== "paused") throw new Error("goal pause has an invalid phase transition"); + break; + case "resume": + requireSameDefinition(current, next, change.operation); + if (!new Set([ + "active", + "paused", + "blocked" + ]).has(current.phase) || next.phase !== "active" || state.roundsStarted >= next.maxGoalRounds) throw new Error("goal resume has an invalid phase transition or exhausted round budget"); + break; + case "complete": + requireSameDefinition(current, next, change.operation); + if (current.phase === "complete" || next.phase !== "complete") throw new Error("goal complete has an invalid phase transition"); + break; + case "block": + requireSameDefinition(current, next, change.operation); + if (current.phase !== "active" || next.phase !== "blocked") throw new Error("goal block has an invalid phase transition"); + break; + /* v8 ignore start -- the caller excludes create and GoalOperation is closed; these arms retain fail-loud exhaustiveness */ + case "create": throw new Error("goal create cannot be validated as a current-goal transition"); + default: + change.operation; + throw new Error("unknown goal snapshot operation"); + } +} +/** +* Return the revision identity carried by a snapshot or tombstone. +* @param change - decoded goal mutation. +* @returns stable identity used to reconcile a deferred change with its log event. +*/ +function goalChangeRef(change) { + return change.operation === "clear" ? change.cleared : { + id: change.goal.id, + revision: change.goal.revision + }; +} +/** +* Validate and apply one decoded change to a mutable accumulator. +* @param state - preceding durable goal projection. +* @param change - decoded full snapshot or clear tombstone. +*/ +function applyGoalChange(state, change) { + const ref = goalChangeRef(change); + if (change.operation === "clear") { + const current = state.goal; + if (current === void 0) throw new Error("goal clear requires a current goal"); + requireNextRevision(current, change.cleared, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === void 0) throw new Error("current goal fold lacks updatedAt"); + if (change.clearedAt < state.updatedAt) throw new Error("goal clear timestamp cannot precede the current goal update"); + state.goal = void 0; + state.roundsStarted = 0; + state.createdAt = void 0; + state.updatedAt = void 0; + state.lastRef = ref; + return; + } + if (change.operation === "create") { + if (change.goal.revision !== 1 || change.goal.phase !== "active" || change.roundsStarted !== 0 || state.goal !== void 0 && state.goal.phase !== "complete" || state.seenGoalIds.has(change.goal.id)) throw new Error("goal create requires a fresh active revision-one goal with zero rounds"); + state.seenGoalIds.add(change.goal.id); + } else { + const current = state.goal; + if (current === void 0) throw new Error(`goal ${change.operation} requires a current goal`); + validateSnapshotTransition(state, change, current); + } + state.goal = change.goal; + state.roundsStarted = change.roundsStarted; + state.createdAt = change.createdAt; + state.updatedAt = change.updatedAt; + state.lastRef = ref; +} +/** +* Apply one session event to the strict durable goal fold. +* @param state - mutable fold accumulator. +* @param event - next event in sequence order. +*/ +function applyGoalEvent(state, event) { + if (event.type === "goal/change") { + const change = decodeGoalChange(event.data); + /* v8 ignore next -- the event's declared payload always identifies itself as a goal change. */ + if (change === void 0) throw new Error(`goal change at session event ${event.seq} has an invalid kind`); + applyGoalChange(state, change); + return; + } + if (event.type === "user/message") { + const source = goalSource(event.data.source); + if (source === void 0) return; + const current = state.goal; + if (current === void 0 || current.phase !== "active" || source.goalId !== current.id || source.revision !== current.revision || source.round !== state.roundsStarted + 1 || source.round > current.maxGoalRounds) throw new Error(`goal round at session event ${event.seq} is not the next admitted round of the active goal`); + state.roundsStarted = source.round; + } +} +/** +* Fold current goal state from a contiguous session event log. +* @param events - session events in sequence order. +* @returns a fresh durable projection; activation is deliberately absent. +*/ +function foldGoal(events) { + const state = emptyGoalFoldState(); + for (const event of events) applyGoalEvent(state, event); + return { + ...state.goal === void 0 ? {} : { goal: { ...state.goal } }, + roundsStarted: state.roundsStarted, + ...state.createdAt === void 0 ? {} : { createdAt: state.createdAt }, + ...state.updatedAt === void 0 ? {} : { updatedAt: state.updatedAt }, + ...state.lastRef === void 0 ? {} : { lastRef: { ...state.lastRef } } + }; +} +//#endregion +//#region lib/types/index.js +/** +* Same-session goal domain: event-sourced state, compare-and-set mutations, +* and process-local continuation activation. +* @module @deepseek-ai/dsh-goal +*/ +var __runInitializers = function(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + return useValue ? value : void 0; +}; +var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function(f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +/** Wire payload schema of the `goal` projection (whole current goal or pre-create/cleared null). */ +const goalProjectionSchema = z$1.union([z$1.object({ + goal: z$1.object({ + id: z$1.string().min(1), + revision: z$1.number().int().positive(), + objective: z$1.string().min(1), + phase: z$1.union([ + z$1.literal("active"), + z$1.literal("paused"), + z$1.literal("blocked"), + z$1.literal("complete") + ]), + blockedReason: z$1.object({ + code: z$1.string(), + message: z$1.string() + }).optional(), + maxGoalRounds: z$1.number().int().positive() + }), + roundsStarted: z$1.number().int().nonnegative(), + createdAt: z$1.number(), + updatedAt: z$1.number() +}), z$1.null()]); +/** +* Light last-wins fold of the `goal` projection unit. Unlike the strict +* replay fold (fold.ts: transition validation, fail-loud on malformed +* changes, Set-typed state), this transition is projection-grade: the state +* is plain JSON (persisted-cache precondition), any non-goal or malformed +* event returns the same reference (the registry's Object.is gate — the +* title/todos posture), and correctness of the written change is the write +* side's job (GoalService validated it before appending; the package +* invariant rejects a violating stream fail-loud where it is installed). +* @param state - the projection covering all prior events. +* @param event - the next committed session event. +* @returns the next projection (same reference when the event is not a goal change). +*/ +function applyGoalProjection(state, event) { + if (event.type !== "goal/change") return state; + let change; + try { + change = decodeGoalChange(event.data); + } catch (_invalidPersistedGoalChange) { + return state; + } + if (change === void 0) return state; + return change.operation === "clear" ? null : { + goal: change.goal, + roundsStarted: change.roundsStarted, + createdAt: change.createdAt, + updatedAt: change.updatedAt + }; +} +/** Validate a caller-visible positive safe-integer round cap. */ +function resolveMaxGoalRounds(value) { + if (!Number.isSafeInteger(value) || value < 1) throw new GoalError("maxGoalRounds must be a positive safe integer", "GOAL_INVALID_MAX_ROUNDS"); + return value; +} +/** Validate and normalize an objective at the domain boundary. */ +function resolveObjective(value) { + if (typeof value !== "string" || value.trim().length === 0) throw new GoalError("goal objective must be a non-empty string", "GOAL_INVALID_OBJECTIVE"); + return value.trim(); +} +/** Materialize deployment defaults and validate one create request. */ +function resolveCreateGoal(request, defaultMaxGoalRounds) { + return { + objective: resolveObjective(request.objective), + maxGoalRounds: resolveMaxGoalRounds(request.maxGoalRounds ?? defaultMaxGoalRounds) + }; +} +/** Validate and detach one policy-owned blocker explanation. */ +function resolveBlockReason(reason) { + const record = typeof reason === "object" && reason !== null && !Array.isArray(reason) ? reason : void 0; + const code = record?.["code"]; + const message = record?.["message"]; + if (typeof code !== "string" || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(code) || typeof message !== "string" || message.trim().length === 0) throw new GoalError("goal block reason requires a lower-kebab-case code and a non-empty message", "GOAL_INVALID_BLOCK_REASON"); + return { + code, + message: message.trim() + }; +} +/** Goal service (`ctx.goals`) backed exclusively by the owning session log. */ +let GoalService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _edit_decorators; + let _pause_decorators; + let _resume_decorators; + let _complete_decorators; + let _clear_decorators; + let _remoteExportCreate_decorators; + return class GoalService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _edit_decorators = [Remote("edit")]; + _pause_decorators = [Remote("pause")]; + _resume_decorators = [Remote("resume")]; + _complete_decorators = [Remote("complete")]; + _clear_decorators = [Remote("clear")]; + _remoteExportCreate_decorators = [Remote("create")]; + __esDecorate(this, null, _edit_decorators, { + kind: "method", + name: "edit", + static: false, + private: false, + access: { + has: (obj) => "edit" in obj, + get: (obj) => obj.edit + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _pause_decorators, { + kind: "method", + name: "pause", + static: false, + private: false, + access: { + has: (obj) => "pause" in obj, + get: (obj) => obj.pause + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resume_decorators, { + kind: "method", + name: "resume", + static: false, + private: false, + access: { + has: (obj) => "resume" in obj, + get: (obj) => obj.resume + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _complete_decorators, { + kind: "method", + name: "complete", + static: false, + private: false, + access: { + has: (obj) => "complete" in obj, + get: (obj) => obj.complete + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _clear_decorators, { + kind: "method", + name: "clear", + static: false, + private: false, + access: { + has: (obj) => "clear" in obj, + get: (obj) => obj.clear + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _remoteExportCreate_decorators, { + kind: "method", + name: "remoteExportCreate", + static: false, + private: false, + access: { + has: (obj) => "remoteExportCreate" in obj, + get: (obj) => obj.remoteExportCreate + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { + enumerable: true, + configurable: true, + writable: true, + value: _metadata + }); + } + static inject = ["agents"]; + static Config = z.object({ defaultMaxGoalRounds: z.number().default(256) }); + resolved = __runInitializers(this, _instanceExtraInitializers); + caches = /* @__PURE__ */ new WeakMap(); + constructor(ctx, config = {}) { + super(ctx, "goals"); + this.resolved = { defaultMaxGoalRounds: resolveMaxGoalRounds(config.defaultMaxGoalRounds ?? 256) }; + ctx.on("agent/session-start", ({ agent }) => { + this.cache(agent.session).activation = "disarmed"; + }); + ctx.inject(["sessionProjections"], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: "goal", + schema: goalProjectionSchema, + init: () => null, + apply: applyGoalProjection, + view: (state) => state, + stateVersion: 4 + }); + }); + } + /** + * Read the current goal for one exact live agent. + * @param agent - owning live agent. + * @returns a fresh view or `undefined` when no goal is current. + * @throws {@link GoalError} when the agent is not the registry's live instance. + */ + get(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + return this.view(cache); + } + /** + * Remove process-local continuation authority without changing durable goal + * phase or revision. Lifecycle owners use this before unloading a driver; + * a later human-authorized {@link resume} records the new activation edge. + * @param agent - owning live agent. + * @returns a fresh disarmed view, or `undefined` when no goal is current. + */ + disarm(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + cache.activation = "disarmed"; + return this.view(cache); + } + /** + * Create and arm a goal. A completed goal may be replaced; every other + * current phase must be cleared or resumed instead. + * @param agent - owning live agent. + * @param request - objective and optional round cap. + * @returns the created live view. + */ + create(agent, request) { + const spec = resolveCreateGoal(request, this.resolved.defaultMaxGoalRounds); + const cache = this.prepareMutation(agent); + const current = cache.state.goal; + if (current !== void 0 && current.phase !== "complete") throw new GoalError(`goal "${current.id}" already exists with phase "${current.phase}"`, "GOAL_ALREADY_EXISTS"); + const now = Date.now(); + const goal = { + id: GoalId(`goal-${randomUUID()}`), + revision: 1, + objective: spec.objective, + phase: "active", + maxGoalRounds: spec.maxGoalRounds + }; + return this.commitSnapshot(agent, cache, "create", goal, 0, now, now, "armed"); + } + /** + * Edit objective and/or round cap without changing phase. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param request - at least one replacement field. + * @returns the edited view. + */ + edit(agent, ref, request) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (request.objective === void 0 && request.maxGoalRounds === void 0) throw new GoalError("goal edit requires objective and/or maxGoalRounds", "GOAL_INVALID_EDIT"); + const goal = { + ...current, + revision: current.revision + 1, + ...request.objective === void 0 ? {} : { objective: resolveObjective(request.objective) }, + ...request.maxGoalRounds === void 0 ? {} : { maxGoalRounds: resolveMaxGoalRounds(request.maxGoalRounds) } + }; + return this.commitCurrent(agent, cache, "edit", goal, cache.activation); + } + /** + * Pause an active goal and disarm automatic continuation. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the paused view. + */ + pause(agent, ref) { + return this.transition(agent, ref, "pause", ["active"], "paused", "disarmed"); + } + /** + * Resume and arm a stopped goal, or rearm an active goal after a + * session-start edge, while its round budget still has capacity. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the active view. + */ + resume(agent, ref) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + const resumable = [ + "active", + "paused", + "blocked" + ]; + if (!resumable.includes(current.phase)) throw this.transitionError(current, "resume", resumable); + if (current.phase === "active" && cache.activation === "armed") throw new GoalError(`goal "${current.id}" is already active and armed`, "GOAL_INVALID_TRANSITION"); + if (cache.state.roundsStarted >= current.maxGoalRounds) throw new GoalError(`goal "${current.id}" exhausted ${current.maxGoalRounds} goal rounds; increase maxGoalRounds before resuming`, "GOAL_INVALID_TRANSITION"); + return this.commitCurrent(agent, cache, "resume", this.withPhase(current, "active"), "armed"); + } + /** + * Mark a current non-complete goal complete and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the completed view. + */ + complete(agent, ref) { + return this.transition(agent, ref, "complete", [ + "active", + "paused", + "blocked" + ], "complete", "disarmed"); + } + /** + * Mark an active goal blocked and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param reason - policy-owned stable code and human-readable explanation. + * @returns the blocked view with its durable reason. + */ + block(agent, ref, reason) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (current.phase !== "active") throw this.transitionError(current, "block", ["active"]); + return this.commitCurrent(agent, cache, "block", { + ...this.withPhase(current, "blocked"), + blockedReason: resolveBlockReason(reason) + }, "disarmed"); + } + /** + * Clear the current goal while retaining a durable tombstone and history. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the tombstone ref whose revision is one past the cleared snapshot. + */ + clear(agent, ref) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + const tombstone = { + id: current.id, + revision: current.revision + 1 + }; + const change = { + kind: "goal/change", + version: 1, + operation: "clear", + cleared: tombstone, + clearedAt: this.nextMutationTime(cache) + }; + this.commit(agent, cache, change, "disarmed"); + return { ...tombstone }; + } + /** Resolve and validate the cache used by a mutation. */ + prepareMutation(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + return cache; + } + /** Reject stale or missing current-state refs. */ + expectCurrent(cache, ref) { + const current = cache.state.goal; + if (current === void 0) throw new GoalError("no current goal", "GOAL_NOT_FOUND"); + if (ref.id !== current.id || ref.revision !== current.revision) throw new GoalError(`stale goal ref "${ref.id}" revision ${ref.revision}; current is "${current.id}" revision ${current.revision}`, "GOAL_STALE_REVISION"); + return current; + } + /** Enforce exact live-agent identity rather than trusting a matching id. */ + assertLive(agent) { + if (this.ctx.agents.get(agent.id) !== agent) throw new GoalError(`agent "${agent.id}" is not live in this registry`, "GOAL_AGENT_NOT_LIVE"); + } + /** Return the per-session cache, folding a seed once with activation disarmed. */ + cache(session) { + let cache = this.caches.get(session); + if (cache !== void 0) return cache; + const state = emptyGoalFoldState(); + for (const event of session.events) applyGoalEvent(state, event); + cache = { + state, + activation: "disarmed", + observedSeq: session.seq, + pendingActivation: void 0 + }; + this.caches.set(session, cache); + return cache; + } + /** Incrementally observe durable events and reconcile local activation intent. */ + sync(session, cache) { + for (const event of session.events.slice(cache.observedSeq)) { + applyGoalEvent(cache.state, event); + if (event.type === "goal/change") cache.activation = cache.pendingActivation?.seq === event.seq ? cache.pendingActivation.activation : "disarmed"; + cache.observedSeq += 1; + } + } + /** Build a new revision with one replacement phase. */ + withPhase(current, phase) { + return { + id: current.id, + revision: current.revision + 1, + objective: current.objective, + phase, + maxGoalRounds: current.maxGoalRounds + }; + } + /** Shared validated phase transition. */ + transition(agent, ref, operation, allowed, phase, activation) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (!allowed.includes(current.phase)) throw this.transitionError(current, operation, allowed); + return this.commitCurrent(agent, cache, operation, this.withPhase(current, phase), activation); + } + /** Render a stable invalid-transition error. */ + transitionError(current, operation, allowed) { + return new GoalError(`cannot ${operation} goal "${current.id}" from phase "${current.phase}"; expected ${allowed.join(" or ")}`, "GOAL_INVALID_TRANSITION"); + } + /** Commit a mutation that retains the current goal's derived counters/times. */ + commitCurrent(agent, cache, operation, goal, activation) { + const createdAt = cache.state.createdAt; + /* v8 ignore next -- strict replay and every snapshot commit set createdAt whenever a current goal exists */ + if (createdAt === void 0) throw new Error("current goal cache lacks createdAt"); + return this.commitSnapshot(agent, cache, operation, goal, cache.state.roundsStarted, createdAt, this.nextMutationTime(cache), activation); + } + /** Clamp a current goal's next timestamp across backward wall-clock movement. */ + nextMutationTime(cache) { + const updatedAt = cache.state.updatedAt; + /* v8 ignore next -- strict replay and every snapshot commit set updatedAt whenever a current goal exists */ + if (updatedAt === void 0) throw new Error("current goal cache lacks updatedAt"); + return Math.max(Date.now(), updatedAt); + } + /** Build and commit one full-snapshot mutation. */ + commitSnapshot(agent, cache, operation, goal, roundsStarted, createdAt, updatedAt, activation) { + const change = { + kind: "goal/change", + version: 1, + operation, + goal, + roundsStarted, + createdAt, + updatedAt + }; + this.commit(agent, cache, change, activation); + const view = this.view(cache); + /* v8 ignore next -- the durable goal event installs the snapshot before this read */ + if (view === void 0) throw new Error("snapshot commit cleared the goal unexpectedly"); + return view; + } + /** Commit one mutation into the goal log, cache, and live event stream. */ + commit(agent, cache, change, activation) { + const ref = goalChangeRef(change); + cache.pendingActivation = { + seq: agent.session.seq, + activation + }; + try { + agent.session.append("goal/change", change); + this.sync(agent.session, cache); + } finally { + cache.pendingActivation = void 0; + } + const goal = this.view(cache); + const notification = { + operation: change.operation, + ref: { ...ref }, + ...goal === void 0 ? {} : { goal } + }; + agentEvents(this.ctx, agent).emit("goal/changed", { change: notification }); + } + /** Build a detached current view. */ + view(cache) { + const goal = cache.state.goal; + const createdAt = cache.state.createdAt; + const updatedAt = cache.state.updatedAt; + if (goal === void 0) return void 0; + /* v8 ignore next 3 -- strict replay and snapshot commits establish both timestamps with every current goal */ + if (createdAt === void 0 || updatedAt === void 0) throw new Error(`goal "${goal.id}" cache lacks timestamps`); + return { + ...goal, + roundsStarted: cache.state.roundsStarted, + createdAt, + updatedAt, + activation: cache.activation + }; + } + /** + * Create one Goal through the remote boundary. + * @param agent - exact live Agent resolved from the wire identity. + * @param request - objective and optional round cap. + * @returns the created Goal identity. + */ + remoteExportCreate(agent, request) { + const view = this.create(agent, request); + return { ref: { + id: view.id, + revision: view.revision + } }; + } + }; +})(); +//#endregion +export { GOAL_CHANGE_VERSION, GoalError, GoalId, GoalService, GoalService as default, applyGoalProjection, decodeGoalChange, foldGoal, goalChangeRef }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/invariant.js new file mode 100644 index 0000000..a0ea81c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/invariant.js @@ -0,0 +1,332 @@ +import "@deepseek-ai/dsh-llm"; +//#region lib/types/runtime.js +/** +* Brand a string as a goal id. +* @param id - raw goal identifier. +* @returns the same string with the compile-time brand. +*/ +function GoalId(id) { + return id; +} +//#endregion +//#region lib/types/fold.js +/** Pure replay fold and strict decoder for durable goal changes. */ +const SNAPSHOT_OPERATIONS = new Set([ + "create", + "edit", + "pause", + "resume", + "complete", + "block" +]); +const PHASES = new Set([ + "active", + "paused", + "blocked", + "complete" +]); +/** +* Build an empty replay accumulator. +* @returns mutable state with no current goal or prior ref. +*/ +function emptyGoalFoldState() { + return { + goal: void 0, + roundsStarted: 0, + createdAt: void 0, + updatedAt: void 0, + lastRef: void 0, + seenGoalIds: /* @__PURE__ */ new Set() + }; +} +/** Whether a value is a JSON record rather than an array. */ +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +/** Require one positive safe integer. */ +function positiveInteger(value, field) { + if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) throw new Error(`goal change ${field} must be a positive safe integer`); + return value; +} +/** Require one non-negative safe integer. */ +function nonNegativeInteger(value, field) { + if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new Error(`goal change ${field} must be a non-negative safe integer`); + return value; +} +/** Decode one canonical blocker explanation. */ +function decodeBlockReason(value) { + if (!isRecord(value) || Object.keys(value).sort().join(",") !== "code,message") throw new Error("goal change goal.blockedReason must have exactly code and message fields"); + if (typeof value["code"] !== "string" || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(value["code"])) throw new Error("goal change goal.blockedReason.code must be lower-kebab-case"); + if (typeof value["message"] !== "string" || value["message"].trim().length === 0 || value["message"] !== value["message"].trim()) throw new Error("goal change goal.blockedReason.message must be non-empty and normalized"); + return { + code: value["code"], + message: value["message"] + }; +} +/** Decode and validate one snapshot. */ +function decodeSnapshot(value) { + if (!isRecord(value)) throw new Error("goal change goal must be a record"); + if (typeof value["id"] !== "string" || value["id"].length === 0) throw new Error("goal change goal.id must be a non-empty string"); + if (typeof value["objective"] !== "string" || value["objective"].trim().length === 0 || value["objective"] !== value["objective"].trim()) throw new Error("goal change goal.objective must be non-empty and normalized"); + if (typeof value["phase"] !== "string" || !PHASES.has(value["phase"])) throw new Error("goal change goal.phase is invalid"); + const phase = value["phase"]; + const expectedKeys = phase === "blocked" ? "blockedReason,id,maxGoalRounds,objective,phase,revision" : "id,maxGoalRounds,objective,phase,revision"; + if (Object.keys(value).sort().join(",") !== expectedKeys) throw new Error(`goal change goal for phase ${phase} must have exactly ${expectedKeys} fields`); + return { + id: GoalId(value["id"]), + revision: positiveInteger(value["revision"], "goal.revision"), + objective: value["objective"], + phase, + maxGoalRounds: positiveInteger(value["maxGoalRounds"], "goal.maxGoalRounds"), + ...phase === "blocked" ? { blockedReason: decodeBlockReason(value["blockedReason"]) } : {} + }; +} +/** Decode and validate one ref. */ +function decodeRef(value) { + if (!isRecord(value) || Object.keys(value).sort().join(",") !== "id,revision") throw new Error("goal clear tombstone must have exactly id and revision fields"); + if (typeof value["id"] !== "string" || value["id"].length === 0) throw new Error("goal clear tombstone id must be a non-empty string"); + return { + id: GoalId(value["id"]), + revision: positiveInteger(value["revision"], "cleared.revision") + }; +} +/** +* Decode a value that declares itself as a goal change. Unrelated values +* return `undefined`; malformed goal changes fail replay loudly. +* @param value - candidate source change. +* @returns validated goal change or `undefined` for another value kind. +*/ +function decodeGoalChange(value) { + if (!isRecord(value) || value["kind"] !== "goal/change") return void 0; + if (value["version"] !== 1) throw new Error(`unsupported goal change version ${String(value["version"])}`); + if (value["operation"] === "clear") { + const allowed = [ + "cleared", + "clearedAt", + "kind", + "operation", + "version" + ]; + if (Object.keys(value).sort().join(",") !== allowed.sort().join(",")) throw new Error(`goal clear change must have exactly ${allowed.sort().join(",")} fields`); + return { + kind: "goal/change", + version: 1, + operation: "clear", + cleared: decodeRef(value["cleared"]), + clearedAt: nonNegativeInteger(value["clearedAt"], "clearedAt") + }; + } + if (typeof value["operation"] !== "string" || !SNAPSHOT_OPERATIONS.has(value["operation"])) throw new Error("goal change operation is invalid"); + const allowed = [ + "createdAt", + "goal", + "kind", + "operation", + "roundsStarted", + "updatedAt", + "version" + ]; + if (Object.keys(value).sort().join(",") !== allowed.sort().join(",")) throw new Error(`goal snapshot change must have exactly ${allowed.sort().join(",")} fields`); + const createdAt = nonNegativeInteger(value["createdAt"], "createdAt"); + const updatedAt = nonNegativeInteger(value["updatedAt"], "updatedAt"); + if (updatedAt < createdAt) throw new Error("goal change updatedAt cannot precede createdAt"); + return { + kind: "goal/change", + version: 1, + operation: value["operation"], + goal: decodeSnapshot(value["goal"]), + roundsStarted: nonNegativeInteger(value["roundsStarted"], "roundsStarted"), + createdAt, + updatedAt + }; +} +/** Narrow model attribution to a valid goal source. */ +function goalSource(source) { + if (source.kind !== "goal") return void 0; + if (typeof source.goalId !== "string" || source.goalId.length === 0 || !Number.isSafeInteger(source.revision) || source.revision < 1 || !Number.isSafeInteger(source.round) || source.round < 1) throw new Error("goal message source is invalid"); + return source; +} +/** Require two snapshots to retain fields that only `edit` may replace. */ +function requireSameDefinition(current, next, operation) { + if (next.objective !== current.objective || next.maxGoalRounds !== current.maxGoalRounds) throw new Error(`goal ${operation} cannot change objective or maxGoalRounds`); +} +/** Require one exact next revision of the current goal. */ +function requireNextRevision(current, next, operation) { + if (next.id !== current.id || next.revision !== current.revision + 1) throw new Error(`goal ${operation} must advance the current goal by one revision`); +} +/** Validate one non-create snapshot operation against the preceding projection. */ +function validateSnapshotTransition(state, change, current) { + const next = change.goal; + requireNextRevision(current, next, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === void 0) throw new Error("current goal fold lacks updatedAt"); + if (change.createdAt !== state.createdAt || change.updatedAt < state.updatedAt || change.roundsStarted !== state.roundsStarted) throw new Error(`goal ${change.operation} does not preserve the current counters and timestamps`); + switch (change.operation) { + case "edit": + if (next.phase !== current.phase || JSON.stringify(next.blockedReason) !== JSON.stringify(current.blockedReason)) throw new Error("goal edit cannot change phase or blocked reason"); + break; + case "pause": + requireSameDefinition(current, next, change.operation); + if (current.phase !== "active" || next.phase !== "paused") throw new Error("goal pause has an invalid phase transition"); + break; + case "resume": + requireSameDefinition(current, next, change.operation); + if (!new Set([ + "active", + "paused", + "blocked" + ]).has(current.phase) || next.phase !== "active" || state.roundsStarted >= next.maxGoalRounds) throw new Error("goal resume has an invalid phase transition or exhausted round budget"); + break; + case "complete": + requireSameDefinition(current, next, change.operation); + if (current.phase === "complete" || next.phase !== "complete") throw new Error("goal complete has an invalid phase transition"); + break; + case "block": + requireSameDefinition(current, next, change.operation); + if (current.phase !== "active" || next.phase !== "blocked") throw new Error("goal block has an invalid phase transition"); + break; + /* v8 ignore start -- the caller excludes create and GoalOperation is closed; these arms retain fail-loud exhaustiveness */ + case "create": throw new Error("goal create cannot be validated as a current-goal transition"); + default: + change.operation; + throw new Error("unknown goal snapshot operation"); + } +} +/** +* Return the revision identity carried by a snapshot or tombstone. +* @param change - decoded goal mutation. +* @returns stable identity used to reconcile a deferred change with its log event. +*/ +function goalChangeRef(change) { + return change.operation === "clear" ? change.cleared : { + id: change.goal.id, + revision: change.goal.revision + }; +} +/** +* Validate and apply one decoded change to a mutable accumulator. +* @param state - preceding durable goal projection. +* @param change - decoded full snapshot or clear tombstone. +*/ +function applyGoalChange(state, change) { + const ref = goalChangeRef(change); + if (change.operation === "clear") { + const current = state.goal; + if (current === void 0) throw new Error("goal clear requires a current goal"); + requireNextRevision(current, change.cleared, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === void 0) throw new Error("current goal fold lacks updatedAt"); + if (change.clearedAt < state.updatedAt) throw new Error("goal clear timestamp cannot precede the current goal update"); + state.goal = void 0; + state.roundsStarted = 0; + state.createdAt = void 0; + state.updatedAt = void 0; + state.lastRef = ref; + return; + } + if (change.operation === "create") { + if (change.goal.revision !== 1 || change.goal.phase !== "active" || change.roundsStarted !== 0 || state.goal !== void 0 && state.goal.phase !== "complete" || state.seenGoalIds.has(change.goal.id)) throw new Error("goal create requires a fresh active revision-one goal with zero rounds"); + state.seenGoalIds.add(change.goal.id); + } else { + const current = state.goal; + if (current === void 0) throw new Error(`goal ${change.operation} requires a current goal`); + validateSnapshotTransition(state, change, current); + } + state.goal = change.goal; + state.roundsStarted = change.roundsStarted; + state.createdAt = change.createdAt; + state.updatedAt = change.updatedAt; + state.lastRef = ref; +} +/** +* Apply one session event to the strict durable goal fold. +* @param state - mutable fold accumulator. +* @param event - next event in sequence order. +*/ +function applyGoalEvent(state, event) { + if (event.type === "goal/change") { + const change = decodeGoalChange(event.data); + /* v8 ignore next -- the event's declared payload always identifies itself as a goal change. */ + if (change === void 0) throw new Error(`goal change at session event ${event.seq} has an invalid kind`); + applyGoalChange(state, change); + return; + } + if (event.type === "user/message") { + const source = goalSource(event.data.source); + if (source === void 0) return; + const current = state.goal; + if (current === void 0 || current.phase !== "active" || source.goalId !== current.id || source.revision !== current.revision || source.round !== state.roundsStarted + 1 || source.round > current.maxGoalRounds) throw new Error(`goal round at session event ${event.seq} is not the next admitted round of the active goal`); + state.roundsStarted = source.round; + } +} +//#endregion +//#region lib/types/invariant.js +/** Package-owned durable goal-stream invariants. @module @deepseek-ai/dsh-goal/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-goal"; +/** Cordis companion plugin name. */ +const name = "goal-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Copy the independent fold before validating one candidate event. */ +function cloneState(state) { + return { + goal: state.goal, + roundsStarted: state.roundsStarted, + createdAt: state.createdAt, + updatedAt: state.updatedAt, + lastRef: state.lastRef, + seenGoalIds: new Set(state.seenGoalIds) + }; +} +/** Apply one event through the strict goal decoder and attribute failures. */ +function applyChecked(state, event, fail) { + try { + applyGoalEvent(state, event); + } catch (error) { + /* v8 ignore next -- the strict goal decoder throws Error instances */ + const message = error instanceof Error ? error.message : String(error); + fail(`session event ${event.seq} violates the durable goal stream: ${message}`); + } +} +/** Install an independent incremental fold over every attached session. */ +const install = Object.assign((ctx, fail) => { + const states = /* @__PURE__ */ new WeakMap(); + const staged = /* @__PURE__ */ new WeakMap(); + const seed = (session) => { + const state = emptyGoalFoldState(); + for (const event of session.events) applyChecked(state, event, fail); + states.set(session, state); + return state; + }; + /* v8 ignore next -- session/event always follows list() or session/created seeding */ + const stateFor = (session) => states.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) seed(session); + ctx.on("session/created", (session) => { + seed(session); + }, { global: true }); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName !== "session/event") return; + const [session, event] = args; + const state = cloneState(stateFor(session)); + applyChecked(state, event, fail); + staged.set(event, { + session, + state + }); + }, { global: true }); + ctx.on("session/event", (session, event) => { + const candidate = staged.get(event); + /* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */ + if (candidate === void 0 || candidate.session !== session) return fail("session/event reached publication without matching goal-fold validation"); + staged.delete(event); + states.set(session, candidate.state); + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register the goal-stream invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.d.ts new file mode 100644 index 0000000..dcf4919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.d.ts @@ -0,0 +1,3 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ + +export declare const TYPERT: unknown diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.js new file mode 100644 index 0000000..4029bc8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.host.js @@ -0,0 +1,819 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_clear_result$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_complete_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_create_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_create_parameter_1$schema = z.object({ + 'objective': z.string().readonly(), + 'maxGoalRounds': z.number().readonly().optional(), +}) +const _deepseek_ai_dsh_goal_goals_create_result$schema = z.object({ + 'ref': z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}).readonly(), +}) +const _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema = z.object({ + 'objective': z.string().readonly().optional(), + 'maxGoalRounds': z.number().readonly().optional(), +}) +const _deepseek_ai_dsh_goal_goals_edit_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_pause_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_resume_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) + +export const TYPERT = { + package: '@deepseek-ai/dsh-goal', + face: 'host', + schemas: [ + ], + invocations: [ + { + id: '@deepseek-ai/dsh-goal#goals/clear', + service: 'goals', + namespace: 'goals', + method: 'clear', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_clear_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":377,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/complete', + service: 'goals', + namespace: 'goals', + method: 'complete', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_complete_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":337,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/create', + service: 'goals', + namespace: 'goals', + method: 'create', + implementation: 'remoteExportCreate', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_create_parameter_0$schema, + }, + }, + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#CreateGoalRequest', + schema: _deepseek_ai_dsh_goal_goals_create_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#CreateGoalResult', + schema: _deepseek_ai_dsh_goal_goals_create_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":586,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/edit', + service: 'goals', + namespace: 'goals', + method: 'edit', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema, + }, + }, + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#EditGoalRequest', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_edit_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":277,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/pause', + service: 'goals', + namespace: 'goals', + method: 'pause', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_pause_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":299,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/resume', + service: 'goals', + namespace: 'goals', + method: 'resume', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_resume_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":311,"column":3}, + }, + ], + model: { + "services": [ + { + "description": "Goal service (`ctx.goals`) backed exclusively by the owning session log.", + "summary": "Goal service (`ctx.goals`) backed exclusively by the owning session log.", + "tags": [], + "jsDoc": "/** Goal service (`ctx.goals`) backed exclusively by the owning session log. */", + "key": "goals", + "exportName": "GoalService", + "members": [ + { + "kind": "method", + "name": "get", + "signature": "get(agent: Agent): GoalView | undefined", + "summary": "Read the current goal for one exact live agent.", + "jsDoc": "/**\n * Read the current goal for one exact live agent.\n * @param agent - owning live agent.\n * @returns a fresh view or `undefined` when no goal is current.\n * @throws {@link GoalError} when the agent is not the registry's live instance.\n */" + }, + { + "kind": "method", + "name": "disarm", + "signature": "disarm(agent: Agent): GoalView | undefined", + "summary": "Remove process-local continuation authority without changing durable goal phase or revision.", + "jsDoc": "/**\n * Remove process-local continuation authority without changing durable goal\n * phase or revision. Lifecycle owners use this before unloading a driver;\n * a later human-authorized {@link resume} records the new activation edge.\n * @param agent - owning live agent.\n * @returns a fresh disarmed view, or `undefined` when no goal is current.\n */" + }, + { + "kind": "method", + "name": "create", + "signature": "create(agent: Agent, request: CreateGoalRequest): GoalView", + "summary": "Create and arm a goal.", + "jsDoc": "/**\n * Create and arm a goal. A completed goal may be replaced; every other\n * current phase must be cleared or resumed instead.\n * @param agent - owning live agent.\n * @param request - objective and optional round cap.\n * @returns the created live view.\n */" + }, + { + "kind": "method", + "name": "edit", + "signature": "@Remote('edit') edit(agent: Agent, ref: GoalRef, request: EditGoalRequest): GoalView", + "summary": "Edit objective and/or round cap without changing phase.", + "jsDoc": "/**\n * Edit objective and/or round cap without changing phase.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @param request - at least one replacement field.\n * @returns the edited view.\n */" + }, + { + "kind": "method", + "name": "pause", + "signature": "@Remote('pause') pause(agent: Agent, ref: GoalRef): GoalView", + "summary": "Pause an active goal and disarm automatic continuation.", + "jsDoc": "/**\n * Pause an active goal and disarm automatic continuation.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @returns the paused view.\n */" + }, + { + "kind": "method", + "name": "resume", + "signature": "@Remote('resume') resume(agent: Agent, ref: GoalRef): GoalView", + "summary": "Resume and arm a stopped goal, or rearm an active goal after a session-start edge, while its round budget still has capacity.", + "jsDoc": "/**\n * Resume and arm a stopped goal, or rearm an active goal after a\n * session-start edge, while its round budget still has capacity.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @returns the active view.\n */" + }, + { + "kind": "method", + "name": "complete", + "signature": "@Remote('complete') complete(agent: Agent, ref: GoalRef): GoalView", + "summary": "Mark a current non-complete goal complete and disarm it.", + "jsDoc": "/**\n * Mark a current non-complete goal complete and disarm it.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @returns the completed view.\n */" + }, + { + "kind": "method", + "name": "block", + "signature": "block(agent: Agent, ref: GoalRef, reason: GoalBlockReason): GoalView", + "summary": "Mark an active goal blocked and disarm it.", + "jsDoc": "/**\n * Mark an active goal blocked and disarm it.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @param reason - policy-owned stable code and human-readable explanation.\n * @returns the blocked view with its durable reason.\n */" + }, + { + "kind": "method", + "name": "clear", + "signature": "@Remote('clear') clear(agent: Agent, ref: GoalRef): GoalRef", + "summary": "Clear the current goal while retaining a durable tombstone and history.", + "jsDoc": "/**\n * Clear the current goal while retaining a durable tombstone and history.\n * @param agent - owning live agent.\n * @param ref - expected current revision.\n * @returns the tombstone ref whose revision is one past the cleared snapshot.\n */" + }, + { + "kind": "method", + "name": "remoteExportCreate", + "signature": "@Remote('create') remoteExportCreate(agent: Agent, request: CreateGoalRequest): CreateGoalResult", + "summary": "Create one Goal through the remote boundary.", + "jsDoc": "/**\n * Create one Goal through the remote boundary.\n * @param agent - exact live Agent resolved from the wire identity.\n * @param request - objective and optional round cap.\n * @returns the created Goal identity.\n */" + } + ], + "types": [ + { + "name": "Agent", + "declaration": "export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly inbox: Inbox;\n readonly status: AgentStatus;\n readonly ctx: Context;\n cancel(cause: AgentCancelCause, options?: CancelOptions): void;\n whenIdle(): Promise;\n runMaintenance(task: (signal: AbortSignal) => Promise): Promise;\n send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;\n followup(message: UserMessage): void;\n steer(message: UserMessage): void;\n inject(message: UserMessage): void;\n}" + }, + { + "name": "AgentCancelCause", + "declaration": "export type AgentCancelCause = { readonly kind: 'user'; } | { readonly kind: 'parent'; } | { readonly kind: 'hook'; readonly reason: string; } | { readonly kind: 'disposed'; };" + }, + { + "name": "AgentOptions", + "declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n maxTokens?: number;\n}" + }, + { + "name": "AgentStatus", + "declaration": "export type AgentStatus = 'idle' | 'running';" + }, + { + "name": "ApprovalOutcome", + "declaration": "export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';" + }, + { + "name": "ApprovalPolicy", + "declaration": "export type ApprovalPolicy = 'ask' | 'never';" + }, + { + "name": "ApprovalRequestId", + "declaration": "export type ApprovalRequestId = Branded<'ApprovalRequestId'>;" + }, + { + "name": "AssistantMessage", + "declaration": "export interface AssistantMessage extends Message {\n readonly role: 'assistant';\n readonly source: ModelMessageSource;\n}" + }, + { + "name": "AssistantProvenance", + "declaration": "export interface AssistantProvenance {\n provider: string;\n model: string;\n replayState?: unknown;\n}" + }, + { + "name": "AttachmentId", + "declaration": "export type AttachmentId = Branded<'AttachmentId'>;" + }, + { + "name": "Branded", + "declaration": "export type Branded = string & { readonly [BRAND]: B; };" + }, + { + "name": "CallId", + "declaration": "export type CallId = Branded<'CallId'>;" + }, + { + "name": "CancelOptions", + "declaration": "export interface CancelOptions {\n keepInbox?: boolean | undefined;\n}" + }, + { + "name": "CodeDispatchEventData", + "declaration": "export interface CodeDispatchEventData extends CodeDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}" + }, + { + "name": "CodeDispatchStartEventData", + "declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}" + }, + { + "name": "CommandId", + "declaration": "export type CommandId = Branded<'CommandId'>;" + }, + { + "name": "CommandSource", + "declaration": "export type CommandSource = CommandSourceMap[keyof CommandSourceMap];" + }, + { + "name": "CommandSourceMap", + "declaration": "export interface CommandSourceMap {\n user: { kind: 'user'; };\n}" + }, + { + "name": "ContentBlock", + "declaration": "export type ContentBlock = ContentBlockMap[ContentBlockType];" + }, + { + "name": "ContentBlockMap", + "declaration": "export interface ContentBlockMap {\n text: TextBlock;\n reasoning: ReasoningBlock;\n image: ImageBlock;\n 'tool-call': ToolCallBlock;\n 'tool-result': ToolResultBlock;\n}" + }, + { + "name": "ContentBlockType", + "declaration": "export type ContentBlockType = keyof ContentBlockMap;" + }, + { + "name": "ContextFormed", + "declaration": "export type ContextFormed = { readonly form?: never; } | { readonly form: 'instructions'; } | { readonly form: 'catalog'; } | { readonly form: 'snapshot'; readonly sections: readonly ContextSnapshotSection[]; } | { readonly form: 'notice'; readonly summary: string; } | { readonly form: 'relay'; } | { readonly form: 'recall'; };" + }, + { + "name": "ContextSnapshotSection", + "declaration": "export interface ContextSnapshotSection {\n readonly name: string;\n readonly text: string;\n}" + }, + { + "name": "CreateGoalRequest", + "declaration": "export interface CreateGoalRequest {\n readonly objective: string;\n readonly maxGoalRounds?: number;\n}" + }, + { + "name": "CreateGoalResult", + "declaration": "export interface CreateGoalResult {\n readonly ref: GoalRef;\n}" + }, + { + "name": "EditGoalRequest", + "declaration": "export interface EditGoalRequest {\n readonly objective?: string;\n readonly maxGoalRounds?: number;\n}" + }, + { + "name": "EpochHeader", + "declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n system?: string;\n tools?: ToolSchema[];\n}" + }, + { + "name": "FinishReason", + "declaration": "export type FinishReason = FinishReasonMap[keyof FinishReasonMap];" + }, + { + "name": "FinishReasonMap", + "declaration": "export interface FinishReasonMap {\n stop: { kind: 'stop'; };\n 'tool-calls': { kind: 'tool-calls'; };\n 'max-tokens': { kind: 'max-tokens'; };\n aborted: { kind: 'aborted'; failure: LlmFailure; };\n error: { kind: 'error'; failure: LlmFailure; };\n}" + }, + { + "name": "GoalActivation", + "declaration": "export type GoalActivation = 'armed' | 'disarmed';" + }, + { + "name": "GoalBlockReason", + "declaration": "export interface GoalBlockReason {\n readonly code: string;\n readonly message: string;\n}" + }, + { + "name": "GoalChangeMeta", + "declaration": "export type GoalChangeMeta = GoalSnapshotChangeMeta | GoalClearChangeMeta;" + }, + { + "name": "GoalClearChangeMeta", + "declaration": "export interface GoalClearChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: 'clear';\n readonly cleared: GoalRef;\n readonly clearedAt: number;\n}" + }, + { + "name": "GoalId", + "declaration": "export type GoalId = Branded<'GoalId'>;" + }, + { + "name": "GoalMessageSource", + "declaration": "export interface GoalMessageSource {\n readonly kind: 'goal';\n readonly goalId: GoalId;\n readonly revision: number;\n readonly round: number;\n}" + }, + { + "name": "GoalOperation", + "declaration": "export type GoalOperation = 'create' | 'edit' | 'pause' | 'resume' | 'complete' | 'block' | 'clear';" + }, + { + "name": "GoalPhase", + "declaration": "export type GoalPhase = 'active' | 'paused' | 'blocked' | 'complete';" + }, + { + "name": "GoalRef", + "declaration": "export interface GoalRef {\n readonly id: GoalId;\n readonly revision: number;\n}" + }, + { + "name": "GoalSnapshot", + "declaration": "export interface GoalSnapshot extends GoalRef {\n readonly objective: string;\n readonly phase: GoalPhase;\n readonly blockedReason?: GoalBlockReason;\n readonly maxGoalRounds: number;\n}" + }, + { + "name": "GoalSnapshotChangeMeta", + "declaration": "export interface GoalSnapshotChangeMeta {\n readonly kind: 'goal/change';\n readonly version: 1;\n readonly operation: Exclude;\n readonly goal: GoalSnapshot;\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n}" + }, + { + "name": "GoalView", + "declaration": "export interface GoalView extends GoalSnapshot {\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n readonly activation: GoalActivation;\n}" + }, + { + "name": "ImageAttachmentRef", + "declaration": "export interface ImageAttachmentRef {\n attachmentId: AttachmentId;\n mediaType: ImageMediaType;\n bytes: number;\n width: number;\n height: number;\n name?: string;\n}" + }, + { + "name": "ImageBlock", + "declaration": "export interface ImageBlock {\n type: 'image';\n attachment: ImageAttachmentRef;\n}" + }, + { + "name": "ImageMediaType", + "declaration": "export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';" + }, + { + "name": "Inbox", + "declaration": "export class Inbox {\n get nextTurn(): readonly UserMessage[];\n get nextStep(): readonly UserMessage[];\n get hasPending(): boolean;\n clear(): void;\n claim(target: InboxTarget, turn: number): UserMessage[];\n append(target: InboxTarget, message: UserMessage): void;\n prepend(target: InboxTarget, message: UserMessage): void;\n replace(messageId: MessageId, newMessage: UserMessage): boolean;\n remove(messageId: MessageId): boolean;\n splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[];\n}" + }, + { + "name": "InboxTarget", + "declaration": "export type InboxTarget = 'next-turn' | 'next-step';" + }, + { + "name": "JsonValue", + "declaration": "export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue; };" + }, + { + "name": "LlmCallConfig", + "declaration": "export interface LlmCallConfig {\n provider: string;\n model: string;\n reasoningEffort?: ReasoningEffortId;\n temperature?: number;\n maxTokens?: number;\n stop?: string[];\n}" + }, + { + "name": "LlmCallConfigAdapterDefaults", + "declaration": "export interface LlmCallConfigAdapterDefaults {\n reasoningEffort?: true;\n maxTokens?: true;\n}" + }, + { + "name": "LlmFailure", + "declaration": "export interface LlmFailure {\n readonly message: string;\n readonly code: string;\n readonly status?: number;\n readonly providerRetryAfterMs?: number;\n readonly requestId?: ProviderRequestId;\n}" + }, + { + "name": "Message", + "declaration": "export interface Message {\n readonly id: MessageId;\n readonly role: 'system' | 'user' | 'assistant';\n readonly content: ContentBlock[];\n readonly source: MessageSource;\n}" + }, + { + "name": "MessageId", + "declaration": "export type MessageId = Branded<'MessageId'>;" + }, + { + "name": "MessageSource", + "declaration": "export type MessageSource = MessageSourceMap[keyof MessageSourceMap];" + }, + { + "name": "MessageSourceMap", + "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n goal: GoalMessageSource;\n}" + }, + { + "name": "ModelMessageSource", + "declaration": "export interface ModelMessageSource extends AssistantProvenance {\n kind: 'model';\n}" + }, + { + "name": "ProviderRequestId", + "declaration": "export type ProviderRequestId = Branded<'ProviderRequestId'>;" + }, + { + "name": "ReasoningBlock", + "declaration": "export interface ReasoningBlock {\n type: 'reasoning';\n text: string;\n}" + }, + { + "name": "ReasoningEffortId", + "declaration": "export type ReasoningEffortId = Branded<'ReasoningEffortId'>;" + }, + { + "name": "ReplayEnvelope", + "declaration": "export interface ReplayEnvelope {\n response: unknown;\n blocks?: readonly unknown[];\n}" + }, + { + "name": "RequestContext", + "declaration": "export interface RequestContext {\n provider: string;\n model: string;\n contextWindow?: number;\n}" + }, + { + "name": "RequestHeaderReason", + "declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change';" + }, + { + "name": "Session", + "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n get id(): SessionId;\n readonly firstLiveSeq: number;\n get events(): readonly SessionEvent[];\n get seq(): number;\n append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}" + }, + { + "name": "SessionEvent", + "declaration": "export type SessionEvent = { [K in SessionEventType]: { type: K; seq: number; time: number; data: SessionEventMap[K]; ignorable?: true; } & (K extends SurfaceEventType ? { sourceEventSeqs?: number[]; surfaceOp?: SurfaceOp; } : object) }[T];" + }, + { + "name": "SessionEventMap", + "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: number; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n 'goal/change': GoalChangeMeta;\n}" + }, + { + "name": "SessionEventType", + "declaration": "export type SessionEventType = keyof SessionEventMap;" + }, + { + "name": "SessionHeader", + "declaration": "export interface SessionHeader {\n readonly version: number;\n readonly id: SessionId;\n readonly createdAt: number;\n readonly cwd?: string;\n readonly parentSession?: SessionId;\n readonly seedLength?: number;\n readonly origin?: 'subagent';\n readonly delegationDepth?: number;\n readonly agentPreset?: string;\n}" + }, + { + "name": "SessionId", + "declaration": "export type SessionId = Branded<'SessionId'>;" + }, + { + "name": "SessionSurface", + "declaration": "export interface SessionSurface {\n readonly nodes: readonly number[];\n readonly replaceGeneration: number;\n}" + }, + { + "name": "StreamChunk", + "declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: ReplayEnvelope; };" + }, + { + "name": "SurfaceEventType", + "declaration": "export type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result';" + }, + { + "name": "SurfaceIntent", + "declaration": "export interface SurfaceIntent {\n surfaceOp: SurfaceOp;\n sourceEventSeqs?: number[];\n}" + }, + { + "name": "SurfaceOp", + "declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: number; end: number; };" + }, + { + "name": "TextBlock", + "declaration": "export interface TextBlock {\n type: 'text';\n text: string;\n}" + }, + { + "name": "TodoItem", + "declaration": "export interface TodoItem {\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n}" + }, + { + "name": "TokenUsage", + "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}" + }, + { + "name": "ToolCallBlock", + "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: CallId;\n name: string;\n arguments: string;\n}" + }, + { + "name": "ToolMessageSource", + "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: CallId;\n}" + }, + { + "name": "ToolResultBlock", + "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: CallId;\n content: ContentBlock[];\n isError?: boolean;\n}" + }, + { + "name": "ToolResultMessage", + "declaration": "export interface ToolResultMessage extends Message {\n readonly role: 'user';\n readonly content: [ToolResultBlock];\n readonly source: ToolMessageSource;\n}" + }, + { + "name": "ToolSchema", + "declaration": "export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n}" + }, + { + "name": "TurnEndCancelCause", + "declaration": "export type TurnEndCancelCause = AgentCancelCause | { readonly kind: 'legacy'; };" + }, + { + "name": "TurnEndReason", + "declaration": "export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap];" + }, + { + "name": "TurnEndReasonMap", + "declaration": "export interface TurnEndReasonMap {\n completed: { kind: 'completed'; };\n aborted: { kind: 'aborted'; reason: TurnEndCancelCause; };\n blocked: { kind: 'blocked'; };\n error: { kind: 'error'; error: LlmFailure; };\n 'max-tokens': { kind: 'max-tokens'; };\n interrupted: { kind: 'interrupted'; };\n}" + }, + { + "name": "UserMessage", + "declaration": "export interface UserMessage extends Message {\n readonly role: 'user';\n}" + } + ] + } + ], + "events": [ + { + "description": "Goal mutation accepted by one live agent. The matching `goal/change` session event has already committed. Listener failures are contained. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.", + "summary": "Goal mutation accepted by one live agent.", + "tags": [ + { + "name": "param", + "argument": "payload.agent", + "comment": "- agent whose session owns the goal.", + "text": "@param payload.agent - agent whose session owns the goal.\n *" + }, + { + "name": "param", + "argument": "payload.change", + "comment": "- fresh current projection or clear tombstone.", + "text": "@param payload.change - fresh current projection or clear tombstone.\n *" + }, + { + "name": "mode", + "comment": "emit", + "text": "@mode emit" + } + ], + "jsDoc": "/**\n * Goal mutation accepted by one live agent. The matching `goal/change`\n * session event has already committed. Listener failures are contained.\n * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.\n * @param payload.agent - agent whose session owns the goal.\n * @param payload.change - fresh current projection or clear tombstone.\n * @mode emit\n */", + "name": "goal/changed", + "mode": "emit", + "signature": "'goal/changed'(this: import('@deepseek-ai/dsh-scope').Scoped, payload: { agent: Agent; change: GoalChanged; }): void" + } + ], + "objects": [] + }, +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.d.ts new file mode 100644 index 0000000..a2dc168 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.d.ts @@ -0,0 +1,41 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import type { + RemoteResult, + TypertRemoteContribution, +} from '@deepseek-ai/dsh-typert-protocol' +import type { CreateGoalRequest, CreateGoalResult, EditGoalRequest, GoalRef, GoalView } from '@deepseek-ai/dsh-goal/client' +import type { SessionId } from '@deepseek-ai/dsh-session/types' + +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteNamespace$676f616c73 { + clear: (agentId: SessionId, ref: GoalRef) => Promise> + complete: (agentId: SessionId, ref: GoalRef) => Promise> + create: (agentId: SessionId, request: CreateGoalRequest) => Promise> + edit: (agentId: SessionId, ref: GoalRef, request: EditGoalRequest) => Promise> + pause: (agentId: SessionId, ref: GoalRef) => Promise> + resume: (agentId: SessionId, ref: GoalRef) => Promise> + } + interface TypertRemoteMap { + 'goals/clear': (agentId: SessionId, ref: GoalRef) => Promise> + 'goals/complete': (agentId: SessionId, ref: GoalRef) => Promise> + 'goals/create': (agentId: SessionId, request: CreateGoalRequest) => Promise> + 'goals/edit': (agentId: SessionId, ref: GoalRef, request: EditGoalRequest) => Promise> + 'goals/pause': (agentId: SessionId, ref: GoalRef) => Promise> + 'goals/resume': (agentId: SessionId, ref: GoalRef) => Promise> + } + interface TypertRemoteNamespaceMap { + 'goals': TypertRemoteNamespace$676f616c73 + } + interface TypertRemoteScopeMap { + 'agent:goals/clear': (ref: GoalRef) => Promise> + 'agent:goals/complete': (ref: GoalRef) => Promise> + 'agent:goals/create': (request: CreateGoalRequest) => Promise> + 'agent:goals/edit': (ref: GoalRef, request: EditGoalRequest) => Promise> + 'agent:goals/pause': (ref: GoalRef) => Promise> + 'agent:goals/resume': (ref: GoalRef) => Promise> + } +} + +export declare const TYPERT_REMOTE: TypertRemoteContribution +export default TYPERT_REMOTE +//# sourceMappingURL=typert.remote-client.d.ts.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.js new file mode 100644 index 0000000..9450fb3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/typert.remote-client.js @@ -0,0 +1,366 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_clear_result$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_complete_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_create_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_create_parameter_1$schema = z.object({ + 'objective': z.string().readonly(), + 'maxGoalRounds': z.number().readonly().optional(), +}) +const _deepseek_ai_dsh_goal_goals_create_result$schema = z.object({ + 'ref': z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}).readonly(), +}) +const _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema = z.object({ + 'objective': z.string().readonly().optional(), + 'maxGoalRounds': z.number().readonly().optional(), +}) +const _deepseek_ai_dsh_goal_goals_edit_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_pause_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema = z.intersection(z.string(), z.unknown()) +const _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema = z.object({ + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) +const _deepseek_ai_dsh_goal_goals_resume_result$schema = z.object({ + 'roundsStarted': z.number().readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), + 'activation': z.union([z.literal("armed"), z.literal("disarmed")]).readonly(), + 'objective': z.string().readonly(), + 'phase': z.union([z.literal("active"), z.literal("paused"), z.literal("blocked"), z.literal("complete")]).readonly(), + 'blockedReason': z.object({ + 'code': z.string().readonly(), + 'message': z.string().readonly(), +}).readonly().optional(), + 'maxGoalRounds': z.number().readonly(), + 'id': z.intersection(z.string(), z.unknown()).readonly(), + 'revision': z.number().readonly(), +}) + +export const TYPERT_REMOTE = { + package: '@deepseek-ai/dsh-goal', + descriptors: [ + { + id: '@deepseek-ai/dsh-goal#goals/clear', + service: 'goals', + namespace: 'goals', + method: 'clear', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_clear_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_clear_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":377,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/complete', + service: 'goals', + namespace: 'goals', + method: 'complete', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_complete_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_complete_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":337,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/create', + service: 'goals', + namespace: 'goals', + method: 'create', + implementation: 'remoteExportCreate', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_create_parameter_0$schema, + }, + }, + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#CreateGoalRequest', + schema: _deepseek_ai_dsh_goal_goals_create_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#CreateGoalResult', + schema: _deepseek_ai_dsh_goal_goals_create_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":586,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/edit', + service: 'goals', + namespace: 'goals', + method: 'edit', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_1$schema, + }, + }, + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#EditGoalRequest', + schema: _deepseek_ai_dsh_goal_goals_edit_parameter_2$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_edit_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":277,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/pause', + service: 'goals', + namespace: 'goals', + method: 'pause', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_pause_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_pause_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":299,"column":3}, + }, + { + id: '@deepseek-ai/dsh-goal#goals/resume', + service: 'goals', + namespace: 'goals', + method: 'resume', + invocation: { kind: 'direct' }, + scope: { + context: 'agent', + wire: 'agentId', + }, + parameters: [ + { + name: 'agent', + wire: 'agentId', + source: 'lookup', + lookup: 'agent', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_0$schema, + }, + }, + { + name: 'ref', + wire: 'ref', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalRef', + schema: _deepseek_ai_dsh_goal_goals_resume_parameter_1$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-goal/client#GoalView', + schema: _deepseek_ai_dsh_goal_goals_resume_result$schema, + }, + sourceLocation: {"file":"packages/goal/goal/src/index.ts","line":311,"column":3}, + }, + ], +} + +export default TYPERT_REMOTE diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/client.d.ts new file mode 100644 index 0000000..982d8fb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/client.d.ts @@ -0,0 +1,10 @@ +/** + * Client-namespace projection of the goal domain: a pure re-export of the + * package's types outlet. Client code imports ONLY the client namespace + * (repo discipline), so `./client` projects the same single-source content + * `./types` serves to host consumers — zero duplication. + * + * @module @deepseek-ai/dsh-goal/client + */ +export type * from './types.ts'; +//# sourceMappingURL=client.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/client.js new file mode 100644 index 0000000..a755a80 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/client.js @@ -0,0 +1,10 @@ +/** + * Client-namespace projection of the goal domain: a pure re-export of the + * package's types outlet. Client code imports ONLY the client namespace + * (repo discipline), so `./client` projects the same single-source content + * `./types` serves to host consumers — zero duplication. + * + * @module @deepseek-ai/dsh-goal/client + */ +export {}; +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.d.ts new file mode 100644 index 0000000..b578565 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.d.ts @@ -0,0 +1,92 @@ +/** + * Host-side vocabulary of the goal domain: live views, durable change + * payloads, message attribution, replay folds, and the scoped `goal/changed` + * event. Kept separate from ./types.ts (the pure client-safe outlet) because + * these declarations pull dsh-agent, dsh-llm, and cordis into the program — + * the one-program-per-side layout forbids that on client aggregates. + * @module @deepseek-ai/dsh-goal + */ +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { GoalId, GoalRef, GoalSnapshot, GoalView } from './types.ts'; +/** Goal state-changing verbs recorded in the durable source change. */ +export type GoalOperation = 'create' | 'edit' | 'pause' | 'resume' | 'complete' | 'block' | 'clear'; +/** Full-snapshot goal mutation committed by a durable `goal/change` event. */ +export interface GoalSnapshotChangeMeta { + readonly kind: 'goal/change'; + readonly version: 1; + readonly operation: Exclude; + readonly goal: GoalSnapshot; + readonly roundsStarted: number; + readonly createdAt: number; + readonly updatedAt: number; +} +/** Tombstone retained when the current goal is cleared. */ +export interface GoalClearChangeMeta { + readonly kind: 'goal/change'; + readonly version: 1; + readonly operation: 'clear'; + readonly cleared: GoalRef; + readonly clearedAt: number; +} +/** Durable change union carried by the goal domain's own session event. */ +export type GoalChangeMeta = GoalSnapshotChangeMeta | GoalClearChangeMeta; +/** Message attribution for admitted continuation rounds. */ +export interface GoalMessageSource { + readonly kind: 'goal'; + readonly goalId: GoalId; + readonly revision: number; + /** Positive admitted continuation round. */ + readonly round: number; +} +declare module '@deepseek-ai/dsh-llm' { + interface MessageSourceMap { + goal: GoalMessageSource; + } +} +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * Complete post-mutation goal state or clear tombstone. + */ + 'goal/change': GoalChangeMeta; + } +} +/** Pure replay fold of durable goal facts. */ +export interface FoldedGoal { + /** Current goal, absent after a clear or before the first create. */ + readonly goal?: GoalSnapshot; + /** Highest admitted round for the current goal. */ + readonly roundsStarted: number; + /** Current goal creation time, absent without a current goal. */ + readonly createdAt?: number; + /** Current goal mutation time, absent without a current goal. */ + readonly updatedAt?: number; + /** Latest mutation ref, including a clear tombstone. */ + readonly lastRef?: GoalRef; +} +/** Live notification after one durable goal mutation commits. */ +export interface GoalChanged { + readonly operation: GoalOperation; + readonly ref: GoalRef; + /** Absent for a clear tombstone. */ + readonly goal?: GoalView; +} +/** Stable error codes for rejected goal reads and mutations. */ +export type GoalErrorCode = 'GOAL_AGENT_NOT_LIVE' | 'GOAL_NOT_FOUND' | 'GOAL_ALREADY_EXISTS' | 'GOAL_STALE_REVISION' | 'GOAL_INVALID_OBJECTIVE' | 'GOAL_INVALID_MAX_ROUNDS' | 'GOAL_INVALID_BLOCK_REASON' | 'GOAL_INVALID_EDIT' | 'GOAL_INVALID_TRANSITION'; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * Goal mutation accepted by one live agent. The matching `goal/change` + * session event has already committed. Listener failures are contained. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @param payload.agent - agent whose session owns the goal. + * @param payload.change - fresh current projection or clear tombstone. + * @mode emit + */ + 'goal/changed'(this: import('@deepseek-ai/dsh-scope').Scoped, payload: { + agent: Agent; + change: GoalChanged; + }): void; + } +} +//# sourceMappingURL=domain.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.js new file mode 100644 index 0000000..625e287 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/domain.js @@ -0,0 +1,10 @@ +/** + * Host-side vocabulary of the goal domain: live views, durable change + * payloads, message attribution, replay folds, and the scoped `goal/changed` + * event. Kept separate from ./types.ts (the pure client-safe outlet) because + * these declarations pull dsh-agent, dsh-llm, and cordis into the program — + * the one-program-per-side layout forbids that on client aggregates. + * @module @deepseek-ai/dsh-goal + */ +export {}; +//# sourceMappingURL=domain.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.d.ts new file mode 100644 index 0000000..da0c7da --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.d.ts @@ -0,0 +1,50 @@ +/** Pure replay fold and strict decoder for durable goal changes. */ +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +import type { GoalRef, GoalSnapshot } from './types.ts'; +import type { FoldedGoal, GoalChangeMeta } from './domain.ts'; +/** Mutable accumulator kept private to the pure fold. */ +export interface GoalFoldState { + goal: GoalSnapshot | undefined; + roundsStarted: number; + createdAt: number | undefined; + updatedAt: number | undefined; + lastRef: GoalRef | undefined; + seenGoalIds: Set; +} +/** + * Build an empty replay accumulator. + * @returns mutable state with no current goal or prior ref. + */ +export declare function emptyGoalFoldState(): GoalFoldState; +/** + * Decode a value that declares itself as a goal change. Unrelated values + * return `undefined`; malformed goal changes fail replay loudly. + * @param value - candidate source change. + * @returns validated goal change or `undefined` for another value kind. + */ +export declare function decodeGoalChange(value: unknown): GoalChangeMeta | undefined; +/** + * Return the revision identity carried by a snapshot or tombstone. + * @param change - decoded goal mutation. + * @returns stable identity used to reconcile a deferred change with its log event. + */ +export declare function goalChangeRef(change: GoalChangeMeta): GoalRef; +/** + * Validate and apply one decoded change to a mutable accumulator. + * @param state - preceding durable goal projection. + * @param change - decoded full snapshot or clear tombstone. + */ +export declare function applyGoalChange(state: GoalFoldState, change: GoalChangeMeta): void; +/** + * Apply one session event to the strict durable goal fold. + * @param state - mutable fold accumulator. + * @param event - next event in sequence order. + */ +export declare function applyGoalEvent(state: GoalFoldState, event: SessionEvent): void; +/** + * Fold current goal state from a contiguous session event log. + * @param events - session events in sequence order. + * @returns a fresh durable projection; activation is deliberately absent. + */ +export declare function foldGoal(events: readonly SessionEvent[]): FoldedGoal; +//# sourceMappingURL=fold.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.js new file mode 100644 index 0000000..0e1aa4c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/fold.js @@ -0,0 +1,322 @@ +/** Pure replay fold and strict decoder for durable goal changes. */ +import { GOAL_CHANGE_VERSION, GoalId } from "./runtime.js"; +const SNAPSHOT_OPERATIONS = new Set([ + 'create', + 'edit', + 'pause', + 'resume', + 'complete', + 'block', +]); +const PHASES = new Set(['active', 'paused', 'blocked', 'complete']); +/** + * Build an empty replay accumulator. + * @returns mutable state with no current goal or prior ref. + */ +export function emptyGoalFoldState() { + return { + goal: undefined, + roundsStarted: 0, + createdAt: undefined, + updatedAt: undefined, + lastRef: undefined, + seenGoalIds: new Set(), + }; +} +/** Whether a value is a JSON record rather than an array. */ +function isRecord(value) { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} +/** Require one positive safe integer. */ +function positiveInteger(value, field) { + if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1) { + throw new Error(`goal change ${field} must be a positive safe integer`); + } + return value; +} +/** Require one non-negative safe integer. */ +function nonNegativeInteger(value, field) { + if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) { + throw new Error(`goal change ${field} must be a non-negative safe integer`); + } + return value; +} +/** Decode one canonical blocker explanation. */ +function decodeBlockReason(value) { + if (!isRecord(value) || Object.keys(value).sort().join(',') !== 'code,message') { + throw new Error('goal change goal.blockedReason must have exactly code and message fields'); + } + if (typeof value['code'] !== 'string' || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(value['code'])) { + throw new Error('goal change goal.blockedReason.code must be lower-kebab-case'); + } + if (typeof value['message'] !== 'string' || value['message'].trim().length === 0 + || value['message'] !== value['message'].trim()) { + throw new Error('goal change goal.blockedReason.message must be non-empty and normalized'); + } + return { code: value['code'], message: value['message'] }; +} +/** Decode and validate one snapshot. */ +function decodeSnapshot(value) { + if (!isRecord(value)) + throw new Error('goal change goal must be a record'); + if (typeof value['id'] !== 'string' || value['id'].length === 0) { + throw new Error('goal change goal.id must be a non-empty string'); + } + if (typeof value['objective'] !== 'string' || value['objective'].trim().length === 0 + || value['objective'] !== value['objective'].trim()) { + throw new Error('goal change goal.objective must be non-empty and normalized'); + } + if (typeof value['phase'] !== 'string' || !PHASES.has(value['phase'])) { + throw new Error('goal change goal.phase is invalid'); + } + const phase = value['phase']; + const expectedKeys = phase === 'blocked' + ? 'blockedReason,id,maxGoalRounds,objective,phase,revision' + : 'id,maxGoalRounds,objective,phase,revision'; + if (Object.keys(value).sort().join(',') !== expectedKeys) { + throw new Error(`goal change goal for phase ${phase} must have exactly ${expectedKeys} fields`); + } + return { + id: GoalId(value['id']), + revision: positiveInteger(value['revision'], 'goal.revision'), + objective: value['objective'], + phase, + maxGoalRounds: positiveInteger(value['maxGoalRounds'], 'goal.maxGoalRounds'), + ...phase === 'blocked' ? { blockedReason: decodeBlockReason(value['blockedReason']) } : {}, + }; +} +/** Decode and validate one ref. */ +function decodeRef(value) { + if (!isRecord(value) || Object.keys(value).sort().join(',') !== 'id,revision') { + throw new Error('goal clear tombstone must have exactly id and revision fields'); + } + if (typeof value['id'] !== 'string' || value['id'].length === 0) { + throw new Error('goal clear tombstone id must be a non-empty string'); + } + return { id: GoalId(value['id']), revision: positiveInteger(value['revision'], 'cleared.revision') }; +} +/** + * Decode a value that declares itself as a goal change. Unrelated values + * return `undefined`; malformed goal changes fail replay loudly. + * @param value - candidate source change. + * @returns validated goal change or `undefined` for another value kind. + */ +export function decodeGoalChange(value) { + if (!isRecord(value) || value['kind'] !== 'goal/change') + return undefined; + if (value['version'] !== GOAL_CHANGE_VERSION) { + throw new Error(`unsupported goal change version ${String(value['version'])}`); + } + if (value['operation'] === 'clear') { + const allowed = ['cleared', 'clearedAt', 'kind', 'operation', 'version']; + if (Object.keys(value).sort().join(',') !== allowed.sort().join(',')) { + throw new Error(`goal clear change must have exactly ${allowed.sort().join(',')} fields`); + } + return { + kind: 'goal/change', + version: GOAL_CHANGE_VERSION, + operation: 'clear', + cleared: decodeRef(value['cleared']), + clearedAt: nonNegativeInteger(value['clearedAt'], 'clearedAt'), + }; + } + if (typeof value['operation'] !== 'string' + || !SNAPSHOT_OPERATIONS.has(value['operation'])) { + throw new Error('goal change operation is invalid'); + } + const allowed = ['createdAt', 'goal', 'kind', 'operation', 'roundsStarted', 'updatedAt', 'version']; + if (Object.keys(value).sort().join(',') !== allowed.sort().join(',')) { + throw new Error(`goal snapshot change must have exactly ${allowed.sort().join(',')} fields`); + } + const createdAt = nonNegativeInteger(value['createdAt'], 'createdAt'); + const updatedAt = nonNegativeInteger(value['updatedAt'], 'updatedAt'); + if (updatedAt < createdAt) + throw new Error('goal change updatedAt cannot precede createdAt'); + return { + kind: 'goal/change', + version: GOAL_CHANGE_VERSION, + operation: value['operation'], + goal: decodeSnapshot(value['goal']), + roundsStarted: nonNegativeInteger(value['roundsStarted'], 'roundsStarted'), + createdAt, + updatedAt, + }; +} +/** Narrow model attribution to a valid goal source. */ +function goalSource(source) { + if (source.kind !== 'goal') + return undefined; + if (typeof source.goalId !== 'string' || source.goalId.length === 0 + || !Number.isSafeInteger(source.revision) || source.revision < 1 + || !Number.isSafeInteger(source.round) || source.round < 1) { + throw new Error('goal message source is invalid'); + } + return source; +} +/** Require two snapshots to retain fields that only `edit` may replace. */ +function requireSameDefinition(current, next, operation) { + if (next.objective !== current.objective || next.maxGoalRounds !== current.maxGoalRounds) { + throw new Error(`goal ${operation} cannot change objective or maxGoalRounds`); + } +} +/** Require one exact next revision of the current goal. */ +function requireNextRevision(current, next, operation) { + if (next.id !== current.id || next.revision !== current.revision + 1) { + throw new Error(`goal ${operation} must advance the current goal by one revision`); + } +} +/** Validate one non-create snapshot operation against the preceding projection. */ +function validateSnapshotTransition(state, change, current) { + const next = change.goal; + requireNextRevision(current, next, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === undefined) + throw new Error('current goal fold lacks updatedAt'); + if (change.createdAt !== state.createdAt + || change.updatedAt < state.updatedAt + || change.roundsStarted !== state.roundsStarted) { + throw new Error(`goal ${change.operation} does not preserve the current counters and timestamps`); + } + switch (change.operation) { + case 'edit': + if (next.phase !== current.phase + || JSON.stringify(next.blockedReason) !== JSON.stringify(current.blockedReason)) { + throw new Error('goal edit cannot change phase or blocked reason'); + } + break; + case 'pause': + requireSameDefinition(current, next, change.operation); + if (current.phase !== 'active' || next.phase !== 'paused') + throw new Error('goal pause has an invalid phase transition'); + break; + case 'resume': { + requireSameDefinition(current, next, change.operation); + const resumable = new Set([ + 'active', + 'paused', + 'blocked', + ]); + if (!resumable.has(current.phase) || next.phase !== 'active' || state.roundsStarted >= next.maxGoalRounds) { + throw new Error('goal resume has an invalid phase transition or exhausted round budget'); + } + break; + } + case 'complete': + requireSameDefinition(current, next, change.operation); + if (current.phase === 'complete' || next.phase !== 'complete') + throw new Error('goal complete has an invalid phase transition'); + break; + case 'block': + requireSameDefinition(current, next, change.operation); + if (current.phase !== 'active' || next.phase !== 'blocked') + throw new Error('goal block has an invalid phase transition'); + break; + /* v8 ignore start -- the caller excludes create and GoalOperation is closed; these arms retain fail-loud exhaustiveness */ + case 'create': + throw new Error('goal create cannot be validated as a current-goal transition'); + default: + change.operation; + throw new Error('unknown goal snapshot operation'); + /* v8 ignore stop */ + } +} +/** + * Return the revision identity carried by a snapshot or tombstone. + * @param change - decoded goal mutation. + * @returns stable identity used to reconcile a deferred change with its log event. + */ +export function goalChangeRef(change) { + return change.operation === 'clear' + ? change.cleared + : { id: change.goal.id, revision: change.goal.revision }; +} +/** + * Validate and apply one decoded change to a mutable accumulator. + * @param state - preceding durable goal projection. + * @param change - decoded full snapshot or clear tombstone. + */ +export function applyGoalChange(state, change) { + const ref = goalChangeRef(change); + if (change.operation === 'clear') { + const current = state.goal; + if (current === undefined) + throw new Error('goal clear requires a current goal'); + requireNextRevision(current, change.cleared, change.operation); + /* v8 ignore next -- a current goal established by this fold always has an updatedAt */ + if (state.updatedAt === undefined) + throw new Error('current goal fold lacks updatedAt'); + if (change.clearedAt < state.updatedAt) { + throw new Error('goal clear timestamp cannot precede the current goal update'); + } + state.goal = undefined; + state.roundsStarted = 0; + state.createdAt = undefined; + state.updatedAt = undefined; + state.lastRef = ref; + return; + } + if (change.operation === 'create') { + if (change.goal.revision !== 1 || change.goal.phase !== 'active' || change.roundsStarted !== 0 + || (state.goal !== undefined && state.goal.phase !== 'complete') + || state.seenGoalIds.has(change.goal.id)) { + throw new Error('goal create requires a fresh active revision-one goal with zero rounds'); + } + state.seenGoalIds.add(change.goal.id); + } + else { + const current = state.goal; + if (current === undefined) + throw new Error(`goal ${change.operation} requires a current goal`); + validateSnapshotTransition(state, change, current); + } + state.goal = change.goal; + state.roundsStarted = change.roundsStarted; + state.createdAt = change.createdAt; + state.updatedAt = change.updatedAt; + state.lastRef = ref; +} +/** + * Apply one session event to the strict durable goal fold. + * @param state - mutable fold accumulator. + * @param event - next event in sequence order. + */ +export function applyGoalEvent(state, event) { + if (event.type === 'goal/change') { + const change = decodeGoalChange(event.data); + /* v8 ignore next -- the event's declared payload always identifies itself as a goal change. */ + if (change === undefined) + throw new Error(`goal change at session event ${event.seq} has an invalid kind`); + applyGoalChange(state, change); + return; + } + if (event.type === 'user/message') { + const source = goalSource(event.data.source); + if (source === undefined) + return; + const current = state.goal; + if (current === undefined || current.phase !== 'active' || source.goalId !== current.id + || source.revision !== current.revision || source.round !== state.roundsStarted + 1 + || source.round > current.maxGoalRounds) { + throw new Error(`goal round at session event ${event.seq} is not the next admitted round of the active goal`); + } + state.roundsStarted = source.round; + } +} +/** + * Fold current goal state from a contiguous session event log. + * @param events - session events in sequence order. + * @returns a fresh durable projection; activation is deliberately absent. + */ +export function foldGoal(events) { + const state = emptyGoalFoldState(); + for (const event of events) + applyGoalEvent(state, event); + return { + ...state.goal === undefined ? {} : { goal: { ...state.goal } }, + roundsStarted: state.roundsStarted, + ...state.createdAt === undefined ? {} : { createdAt: state.createdAt }, + ...state.updatedAt === undefined ? {} : { updatedAt: state.updatedAt }, + ...state.lastRef === undefined ? {} : { lastRef: { ...state.lastRef } }, + }; +} +//# sourceMappingURL=fold.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/index.d.ts new file mode 100644 index 0000000..a6cd541 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/index.d.ts @@ -0,0 +1,155 @@ +/** + * Same-session goal domain: event-sourced state, compare-and-set mutations, + * and process-local continuation activation. + * @module @deepseek-ai/dsh-goal + */ +import { Context } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'; +import type { CreateGoalRequest, CreateGoalResult, EditGoalRequest, GoalBlockReason, GoalProjection, GoalRef, GoalView } from './types.ts'; +export type * from './types.ts'; +export type * from './domain.ts'; +export { GOAL_CHANGE_VERSION, GoalError, GoalId } from './runtime.ts'; +export { decodeGoalChange, foldGoal, goalChangeRef } from './fold.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + goals: GoalService; + } +} +/** + * Light last-wins fold of the `goal` projection unit. Unlike the strict + * replay fold (fold.ts: transition validation, fail-loud on malformed + * changes, Set-typed state), this transition is projection-grade: the state + * is plain JSON (persisted-cache precondition), any non-goal or malformed + * event returns the same reference (the registry's Object.is gate — the + * title/todos posture), and correctness of the written change is the write + * side's job (GoalService validated it before appending; the package + * invariant rejects a violating stream fail-loud where it is installed). + * @param state - the projection covering all prior events. + * @param event - the next committed session event. + * @returns the next projection (same reference when the event is not a goal change). + */ +export declare function applyGoalProjection(state: GoalProjection | null, event: SessionEvent): GoalProjection | null; +/** Deployment defaults for goal creation. */ +export interface Config { + /** Total rounds used when a create request omits its own cap. */ + defaultMaxGoalRounds?: number; +} +/** Resolved defaults. */ +export interface ResolvedConfig { + /** Validated positive safe-integer default round cap. */ + defaultMaxGoalRounds: number; +} +/** Goal service (`ctx.goals`) backed exclusively by the owning session log. */ +export declare class GoalService extends TypertRemoteService { + static inject: string[]; + static Config: z; + private readonly resolved; + private readonly caches; + constructor(ctx: Context, config?: Config); + /** + * Read the current goal for one exact live agent. + * @param agent - owning live agent. + * @returns a fresh view or `undefined` when no goal is current. + * @throws {@link GoalError} when the agent is not the registry's live instance. + */ + get(agent: Agent): GoalView | undefined; + /** + * Remove process-local continuation authority without changing durable goal + * phase or revision. Lifecycle owners use this before unloading a driver; + * a later human-authorized {@link resume} records the new activation edge. + * @param agent - owning live agent. + * @returns a fresh disarmed view, or `undefined` when no goal is current. + */ + disarm(agent: Agent): GoalView | undefined; + /** + * Create and arm a goal. A completed goal may be replaced; every other + * current phase must be cleared or resumed instead. + * @param agent - owning live agent. + * @param request - objective and optional round cap. + * @returns the created live view. + */ + create(agent: Agent, request: CreateGoalRequest): GoalView; + /** + * Edit objective and/or round cap without changing phase. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param request - at least one replacement field. + * @returns the edited view. + */ + edit(agent: Agent, ref: GoalRef, request: EditGoalRequest): GoalView; + /** + * Pause an active goal and disarm automatic continuation. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the paused view. + */ + pause(agent: Agent, ref: GoalRef): GoalView; + /** + * Resume and arm a stopped goal, or rearm an active goal after a + * session-start edge, while its round budget still has capacity. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the active view. + */ + resume(agent: Agent, ref: GoalRef): GoalView; + /** + * Mark a current non-complete goal complete and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the completed view. + */ + complete(agent: Agent, ref: GoalRef): GoalView; + /** + * Mark an active goal blocked and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param reason - policy-owned stable code and human-readable explanation. + * @returns the blocked view with its durable reason. + */ + block(agent: Agent, ref: GoalRef, reason: GoalBlockReason): GoalView; + /** + * Clear the current goal while retaining a durable tombstone and history. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the tombstone ref whose revision is one past the cleared snapshot. + */ + clear(agent: Agent, ref: GoalRef): GoalRef; + /** Resolve and validate the cache used by a mutation. */ + private prepareMutation; + /** Reject stale or missing current-state refs. */ + private expectCurrent; + /** Enforce exact live-agent identity rather than trusting a matching id. */ + private assertLive; + /** Return the per-session cache, folding a seed once with activation disarmed. */ + private cache; + /** Incrementally observe durable events and reconcile local activation intent. */ + private sync; + /** Build a new revision with one replacement phase. */ + private withPhase; + /** Shared validated phase transition. */ + private transition; + /** Render a stable invalid-transition error. */ + private transitionError; + /** Commit a mutation that retains the current goal's derived counters/times. */ + private commitCurrent; + /** Clamp a current goal's next timestamp across backward wall-clock movement. */ + private nextMutationTime; + /** Build and commit one full-snapshot mutation. */ + private commitSnapshot; + /** Commit one mutation into the goal log, cache, and live event stream. */ + private commit; + /** Build a detached current view. */ + private view; + /** + * Create one Goal through the remote boundary. + * @param agent - exact live Agent resolved from the wire identity. + * @param request - objective and optional round cap. + * @returns the created Goal identity. + */ + remoteExportCreate(agent: Agent, request: CreateGoalRequest): CreateGoalResult; +} +export default GoalService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/index.js new file mode 100644 index 0000000..8ad9f44 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/index.js @@ -0,0 +1,495 @@ +/** + * Same-session goal domain: event-sourced state, compare-and-set mutations, + * and process-local continuation activation. + * @module @deepseek-ai/dsh-goal + */ +var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; +var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +import { randomUUID } from 'node:crypto'; +import z from '@deepseek-ai/schemastery'; +import { z as zod } from 'zod'; +import { agentEvents } from '@deepseek-ai/dsh-agent'; +import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'; +import { applyGoalEvent, decodeGoalChange, emptyGoalFoldState, goalChangeRef, } from "./fold.js"; +import { GOAL_CHANGE_VERSION, GoalError, GoalId, } from "./runtime.js"; +export { GOAL_CHANGE_VERSION, GoalError, GoalId } from "./runtime.js"; +export { decodeGoalChange, foldGoal, goalChangeRef } from "./fold.js"; +/** Wire payload schema of the `goal` projection (whole current goal or pre-create/cleared null). */ +const goalProjectionSchema = zod.union([ + zod.object({ + goal: zod.object({ + id: zod.string().min(1), + revision: zod.number().int().positive(), + objective: zod.string().min(1), + phase: zod.union([zod.literal('active'), zod.literal('paused'), zod.literal('blocked'), zod.literal('complete')]), + blockedReason: zod.object({ code: zod.string(), message: zod.string() }).optional(), + maxGoalRounds: zod.number().int().positive(), + }), + roundsStarted: zod.number().int().nonnegative(), + createdAt: zod.number(), + updatedAt: zod.number(), + }), + zod.null(), +]); +/** + * Light last-wins fold of the `goal` projection unit. Unlike the strict + * replay fold (fold.ts: transition validation, fail-loud on malformed + * changes, Set-typed state), this transition is projection-grade: the state + * is plain JSON (persisted-cache precondition), any non-goal or malformed + * event returns the same reference (the registry's Object.is gate — the + * title/todos posture), and correctness of the written change is the write + * side's job (GoalService validated it before appending; the package + * invariant rejects a violating stream fail-loud where it is installed). + * @param state - the projection covering all prior events. + * @param event - the next committed session event. + * @returns the next projection (same reference when the event is not a goal change). + */ +export function applyGoalProjection(state, event) { + if (event.type !== 'goal/change') + return state; + let change; + try { + change = decodeGoalChange(event.data); + } + catch (_invalidPersistedGoalChange) { + return state; + } + if (change === undefined) + return state; + return change.operation === 'clear' + ? null + : { + goal: change.goal, + roundsStarted: change.roundsStarted, + createdAt: change.createdAt, + updatedAt: change.updatedAt, + }; +} +/** Validate a caller-visible positive safe-integer round cap. */ +function resolveMaxGoalRounds(value) { + if (!Number.isSafeInteger(value) || value < 1) { + throw new GoalError('maxGoalRounds must be a positive safe integer', 'GOAL_INVALID_MAX_ROUNDS'); + } + return value; +} +/** Validate and normalize an objective at the domain boundary. */ +function resolveObjective(value) { + if (typeof value !== 'string' || value.trim().length === 0) { + throw new GoalError('goal objective must be a non-empty string', 'GOAL_INVALID_OBJECTIVE'); + } + return value.trim(); +} +/** Materialize deployment defaults and validate one create request. */ +function resolveCreateGoal(request, defaultMaxGoalRounds) { + return { + objective: resolveObjective(request.objective), + maxGoalRounds: resolveMaxGoalRounds(request.maxGoalRounds ?? defaultMaxGoalRounds), + }; +} +/** Validate and detach one policy-owned blocker explanation. */ +function resolveBlockReason(reason) { + const record = typeof reason === 'object' && reason !== null && !Array.isArray(reason) + ? reason + : undefined; + const code = record?.['code']; + const message = record?.['message']; + if (typeof code !== 'string' || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(code) + || typeof message !== 'string' || message.trim().length === 0) { + throw new GoalError('goal block reason requires a lower-kebab-case code and a non-empty message', 'GOAL_INVALID_BLOCK_REASON'); + } + return { code, message: message.trim() }; +} +/** Goal service (`ctx.goals`) backed exclusively by the owning session log. */ +let GoalService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _edit_decorators; + let _pause_decorators; + let _resume_decorators; + let _complete_decorators; + let _clear_decorators; + let _remoteExportCreate_decorators; + return class GoalService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _edit_decorators = [Remote('edit')]; + _pause_decorators = [Remote('pause')]; + _resume_decorators = [Remote('resume')]; + _complete_decorators = [Remote('complete')]; + _clear_decorators = [Remote('clear')]; + _remoteExportCreate_decorators = [Remote('create')]; + __esDecorate(this, null, _edit_decorators, { kind: "method", name: "edit", static: false, private: false, access: { has: obj => "edit" in obj, get: obj => obj.edit }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _pause_decorators, { kind: "method", name: "pause", static: false, private: false, access: { has: obj => "pause" in obj, get: obj => obj.pause }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _resume_decorators, { kind: "method", name: "resume", static: false, private: false, access: { has: obj => "resume" in obj, get: obj => obj.resume }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _complete_decorators, { kind: "method", name: "complete", static: false, private: false, access: { has: obj => "complete" in obj, get: obj => obj.complete }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _clear_decorators, { kind: "method", name: "clear", static: false, private: false, access: { has: obj => "clear" in obj, get: obj => obj.clear }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _remoteExportCreate_decorators, { kind: "method", name: "remoteExportCreate", static: false, private: false, access: { has: obj => "remoteExportCreate" in obj, get: obj => obj.remoteExportCreate }, metadata: _metadata }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + static inject = ['agents']; + static Config = z.object({ + defaultMaxGoalRounds: z.number().default(256), + }); + resolved = __runInitializers(this, _instanceExtraInitializers); + caches = new WeakMap(); + constructor(ctx, config = {}) { + super(ctx, 'goals'); + this.resolved = { + defaultMaxGoalRounds: resolveMaxGoalRounds(config.defaultMaxGoalRounds ?? 256), + }; + ctx.on('agent/session-start', ({ agent }) => { + this.cache(agent.session).activation = 'disarmed'; + }); + // The `goal` projection unit: last-wins fold of goal/change whole values + // (see applyGoalProjection). The unit child activates only when a + // projection registry is composed (headless assemblies stay unaffected). + ctx.inject(['sessionProjections'], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: 'goal', + schema: goalProjectionSchema, + init: () => null, + apply: applyGoalProjection, + view: state => state, + stateVersion: 4, + }); + }); + } + /** + * Read the current goal for one exact live agent. + * @param agent - owning live agent. + * @returns a fresh view or `undefined` when no goal is current. + * @throws {@link GoalError} when the agent is not the registry's live instance. + */ + get(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + return this.view(cache); + } + /** + * Remove process-local continuation authority without changing durable goal + * phase or revision. Lifecycle owners use this before unloading a driver; + * a later human-authorized {@link resume} records the new activation edge. + * @param agent - owning live agent. + * @returns a fresh disarmed view, or `undefined` when no goal is current. + */ + disarm(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + cache.activation = 'disarmed'; + return this.view(cache); + } + /** + * Create and arm a goal. A completed goal may be replaced; every other + * current phase must be cleared or resumed instead. + * @param agent - owning live agent. + * @param request - objective and optional round cap. + * @returns the created live view. + */ + create(agent, request) { + const spec = resolveCreateGoal(request, this.resolved.defaultMaxGoalRounds); + const cache = this.prepareMutation(agent); + const current = cache.state.goal; + if (current !== undefined && current.phase !== 'complete') { + throw new GoalError(`goal "${current.id}" already exists with phase "${current.phase}"`, 'GOAL_ALREADY_EXISTS'); + } + const now = Date.now(); + const goal = { + id: GoalId(`goal-${randomUUID()}`), + revision: 1, + objective: spec.objective, + phase: 'active', + maxGoalRounds: spec.maxGoalRounds, + }; + return this.commitSnapshot(agent, cache, 'create', goal, 0, now, now, 'armed'); + } + /** + * Edit objective and/or round cap without changing phase. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param request - at least one replacement field. + * @returns the edited view. + */ + edit(agent, ref, request) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (request.objective === undefined && request.maxGoalRounds === undefined) { + throw new GoalError('goal edit requires objective and/or maxGoalRounds', 'GOAL_INVALID_EDIT'); + } + const goal = { + ...current, + revision: current.revision + 1, + ...request.objective === undefined ? {} : { objective: resolveObjective(request.objective) }, + ...request.maxGoalRounds === undefined ? {} : { maxGoalRounds: resolveMaxGoalRounds(request.maxGoalRounds) }, + }; + return this.commitCurrent(agent, cache, 'edit', goal, cache.activation); + } + /** + * Pause an active goal and disarm automatic continuation. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the paused view. + */ + pause(agent, ref) { + return this.transition(agent, ref, 'pause', ['active'], 'paused', 'disarmed'); + } + /** + * Resume and arm a stopped goal, or rearm an active goal after a + * session-start edge, while its round budget still has capacity. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the active view. + */ + resume(agent, ref) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + const resumable = ['active', 'paused', 'blocked']; + if (!resumable.includes(current.phase)) { + throw this.transitionError(current, 'resume', resumable); + } + if (current.phase === 'active' && cache.activation === 'armed') { + throw new GoalError(`goal "${current.id}" is already active and armed`, 'GOAL_INVALID_TRANSITION'); + } + if (cache.state.roundsStarted >= current.maxGoalRounds) { + throw new GoalError(`goal "${current.id}" exhausted ${current.maxGoalRounds} goal rounds; increase maxGoalRounds before resuming`, 'GOAL_INVALID_TRANSITION'); + } + return this.commitCurrent(agent, cache, 'resume', this.withPhase(current, 'active'), 'armed'); + } + /** + * Mark a current non-complete goal complete and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the completed view. + */ + complete(agent, ref) { + return this.transition(agent, ref, 'complete', ['active', 'paused', 'blocked'], 'complete', 'disarmed'); + } + /** + * Mark an active goal blocked and disarm it. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @param reason - policy-owned stable code and human-readable explanation. + * @returns the blocked view with its durable reason. + */ + block(agent, ref, reason) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (current.phase !== 'active') { + throw this.transitionError(current, 'block', ['active']); + } + return this.commitCurrent(agent, cache, 'block', { ...this.withPhase(current, 'blocked'), blockedReason: resolveBlockReason(reason) }, 'disarmed'); + } + /** + * Clear the current goal while retaining a durable tombstone and history. + * @param agent - owning live agent. + * @param ref - expected current revision. + * @returns the tombstone ref whose revision is one past the cleared snapshot. + */ + clear(agent, ref) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + const tombstone = { id: current.id, revision: current.revision + 1 }; + const change = { + kind: 'goal/change', + version: GOAL_CHANGE_VERSION, + operation: 'clear', + cleared: tombstone, + clearedAt: this.nextMutationTime(cache), + }; + this.commit(agent, cache, change, 'disarmed'); + return { ...tombstone }; + } + /** Resolve and validate the cache used by a mutation. */ + prepareMutation(agent) { + this.assertLive(agent); + const cache = this.cache(agent.session); + this.sync(agent.session, cache); + return cache; + } + /** Reject stale or missing current-state refs. */ + expectCurrent(cache, ref) { + const current = cache.state.goal; + if (current === undefined) + throw new GoalError('no current goal', 'GOAL_NOT_FOUND'); + if (ref.id !== current.id || ref.revision !== current.revision) { + throw new GoalError(`stale goal ref "${ref.id}" revision ${ref.revision}; current is "${current.id}" revision ${current.revision}`, 'GOAL_STALE_REVISION'); + } + return current; + } + /** Enforce exact live-agent identity rather than trusting a matching id. */ + assertLive(agent) { + if (this.ctx.agents.get(agent.id) !== agent) { + throw new GoalError(`agent "${agent.id}" is not live in this registry`, 'GOAL_AGENT_NOT_LIVE'); + } + } + /** Return the per-session cache, folding a seed once with activation disarmed. */ + cache(session) { + let cache = this.caches.get(session); + if (cache !== undefined) + return cache; + const state = emptyGoalFoldState(); + for (const event of session.events) + applyGoalEvent(state, event); + cache = { + state, + activation: 'disarmed', + observedSeq: session.seq, + pendingActivation: undefined, + }; + this.caches.set(session, cache); + return cache; + } + /** Incrementally observe durable events and reconcile local activation intent. */ + sync(session, cache) { + for (const event of session.events.slice(cache.observedSeq)) { + applyGoalEvent(cache.state, event); + if (event.type === 'goal/change') { + cache.activation = cache.pendingActivation?.seq === event.seq + ? cache.pendingActivation.activation + : 'disarmed'; + } + cache.observedSeq += 1; + } + } + /** Build a new revision with one replacement phase. */ + withPhase(current, phase) { + return { + id: current.id, + revision: current.revision + 1, + objective: current.objective, + phase, + maxGoalRounds: current.maxGoalRounds, + }; + } + /** Shared validated phase transition. */ + transition(agent, ref, operation, allowed, phase, activation) { + const cache = this.prepareMutation(agent); + const current = this.expectCurrent(cache, ref); + if (!allowed.includes(current.phase)) + throw this.transitionError(current, operation, allowed); + return this.commitCurrent(agent, cache, operation, this.withPhase(current, phase), activation); + } + /** Render a stable invalid-transition error. */ + transitionError(current, operation, allowed) { + return new GoalError(`cannot ${operation} goal "${current.id}" from phase "${current.phase}"; expected ${allowed.join(' or ')}`, 'GOAL_INVALID_TRANSITION'); + } + /** Commit a mutation that retains the current goal's derived counters/times. */ + commitCurrent(agent, cache, operation, goal, activation) { + const createdAt = cache.state.createdAt; + /* v8 ignore next -- strict replay and every snapshot commit set createdAt whenever a current goal exists */ + if (createdAt === undefined) + throw new Error('current goal cache lacks createdAt'); + return this.commitSnapshot(agent, cache, operation, goal, cache.state.roundsStarted, createdAt, this.nextMutationTime(cache), activation); + } + /** Clamp a current goal's next timestamp across backward wall-clock movement. */ + nextMutationTime(cache) { + const updatedAt = cache.state.updatedAt; + /* v8 ignore next -- strict replay and every snapshot commit set updatedAt whenever a current goal exists */ + if (updatedAt === undefined) + throw new Error('current goal cache lacks updatedAt'); + return Math.max(Date.now(), updatedAt); + } + /** Build and commit one full-snapshot mutation. */ + commitSnapshot(agent, cache, operation, goal, roundsStarted, createdAt, updatedAt, activation) { + const change = { + kind: 'goal/change', + version: GOAL_CHANGE_VERSION, + operation, + goal, + roundsStarted, + createdAt, + updatedAt, + }; + this.commit(agent, cache, change, activation); + const view = this.view(cache); + /* v8 ignore next -- the durable goal event installs the snapshot before this read */ + if (view === undefined) + throw new Error('snapshot commit cleared the goal unexpectedly'); + return view; + } + /** Commit one mutation into the goal log, cache, and live event stream. */ + commit(agent, cache, change, activation) { + const ref = goalChangeRef(change); + cache.pendingActivation = { seq: agent.session.seq, activation }; + try { + agent.session.append('goal/change', change); + this.sync(agent.session, cache); + } + finally { + cache.pendingActivation = undefined; + } + const goal = this.view(cache); + const notification = { + operation: change.operation, + ref: { ...ref }, + ...goal === undefined ? {} : { goal }, + }; + agentEvents(this.ctx, agent).emit('goal/changed', { change: notification }); + } + /** Build a detached current view. */ + view(cache) { + const goal = cache.state.goal; + const createdAt = cache.state.createdAt; + const updatedAt = cache.state.updatedAt; + if (goal === undefined) + return undefined; + /* v8 ignore next 3 -- strict replay and snapshot commits establish both timestamps with every current goal */ + if (createdAt === undefined || updatedAt === undefined) { + throw new Error(`goal "${goal.id}" cache lacks timestamps`); + } + return { + ...goal, + roundsStarted: cache.state.roundsStarted, + createdAt, + updatedAt, + activation: cache.activation, + }; + } + /** + * Create one Goal through the remote boundary. + * @param agent - exact live Agent resolved from the wire identity. + * @param request - objective and optional round cap. + * @returns the created Goal identity. + */ + remoteExportCreate(agent, request) { + const view = this.create(agent, request); + return { ref: { id: view.id, revision: view.revision } }; + } + }; +})(); +export { GoalService }; +export default GoalService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.d.ts new file mode 100644 index 0000000..e0e557b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned durable goal-stream invariants. @module @deepseek-ai/dsh-goal/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "goal-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the goal-stream invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.js new file mode 100644 index 0000000..93b34f5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/invariant.js @@ -0,0 +1,70 @@ +/** Package-owned durable goal-stream invariants. @module @deepseek-ai/dsh-goal/invariant */ +import { applyGoalEvent, emptyGoalFoldState } from "./fold.js"; +const PACKAGE_NAME = '@deepseek-ai/dsh-goal'; +/** Cordis companion plugin name. */ +export const name = 'goal-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Copy the independent fold before validating one candidate event. */ +function cloneState(state) { + return { + goal: state.goal, + roundsStarted: state.roundsStarted, + createdAt: state.createdAt, + updatedAt: state.updatedAt, + lastRef: state.lastRef, + seenGoalIds: new Set(state.seenGoalIds), + }; +} +/** Apply one event through the strict goal decoder and attribute failures. */ +function applyChecked(state, event, fail) { + try { + applyGoalEvent(state, event); + } + catch (error) { + /* v8 ignore next -- the strict goal decoder throws Error instances */ + const message = error instanceof Error ? error.message : String(error); + fail(`session event ${event.seq} violates the durable goal stream: ${message}`); + } +} +/** Install an independent incremental fold over every attached session. */ +const install = Object.assign((ctx, fail) => { + const states = new WeakMap(); + const staged = new WeakMap(); + const seed = (session) => { + const state = emptyGoalFoldState(); + for (const event of session.events) + applyChecked(state, event, fail); + states.set(session, state); + return state; + }; + /* v8 ignore next -- session/event always follows list() or session/created seeding */ + const stateFor = (session) => states.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) + seed(session); + ctx.on('session/created', (session) => { seed(session); }, { global: true }); + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') + return; + const [session, event] = args; + const state = cloneState(stateFor(session)); + applyChecked(state, event, fail); + staged.set(event, { session, state }); + }, { global: true }); + ctx.on('session/event', (session, event) => { + const candidate = staged.get(event); + /* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */ + if (candidate === undefined || candidate.session !== session) { + return fail('session/event reached publication without matching goal-fold validation'); + } + staged.delete(event); + states.set(session, candidate.state); + }, { global: true }); +}, { inject: ['sessions'] }); +/** + * Register the goal-stream invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.d.ts new file mode 100644 index 0000000..206ace0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.d.ts @@ -0,0 +1,21 @@ +/** Runtime constructors and protocol constants for the goal domain. */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import type { GoalId as GoalIdType } from './types.ts'; +import type { GoalErrorCode } from './domain.ts'; +/** Version of the goal change embedded in a round-zero message source. */ +export declare const GOAL_CHANGE_VERSION = 1; +/** + * Brand a string as a goal id. + * @param id - raw goal identifier. + * @returns the same string with the compile-time brand. + */ +export declare function GoalId(id: string): GoalIdType; +/** Error returned by the goal domain boundary. */ +export declare class GoalError extends HarnessError { + /** + * @param message - human-readable rejection reason. + * @param code - stable machine-routable classification. + */ + constructor(message: string, code: GoalErrorCode); +} +//# sourceMappingURL=runtime.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.js new file mode 100644 index 0000000..2a11eb6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/runtime.js @@ -0,0 +1,25 @@ +/** Runtime constructors and protocol constants for the goal domain. */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +/** Version of the goal change embedded in a round-zero message source. */ +export const GOAL_CHANGE_VERSION = 1; +/** + * Brand a string as a goal id. + * @param id - raw goal identifier. + * @returns the same string with the compile-time brand. + */ +export function GoalId(id) { + return id; +} +/** Error returned by the goal domain boundary. */ +export class GoalError extends HarnessError { + /** + * @param message - human-readable rejection reason. + * @param code - stable machine-routable classification. + */ + // Keep the constructor to narrow HarnessError's string code at this boundary. + // oxlint-disable-next-line typescript/no-useless-constructor -- type-only narrowing + constructor(message, code) { + super(message, code); + } +} +//# sourceMappingURL=runtime.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/types.d.ts new file mode 100644 index 0000000..3cb595a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/types.d.ts @@ -0,0 +1,96 @@ +/** + * Pure types of the goal domain: the ONE home of the `goal` projection-key + * declaration plus the durable payload vocabulary it carries, free of this + * package's host-side imports (cordis events, dsh-agent, dsh-llm, the + * service). Two namespace projections serve it — `./types` for host + * consumers, `./client` (the browser half-entry's re-export) for client + * aggregates — with zero content duplication. Host-coupled domain + * vocabulary (message sources, events, fold shapes) lives in ./domain.ts. + * + * @module @deepseek-ai/dsh-goal/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Identifies one goal across its durable revisions. */ +export type GoalId = Branded<'GoalId'>; +/** Compare-and-set identity for one exact goal revision. */ +export interface GoalRef { + /** Stable goal identity. */ + readonly id: GoalId; + /** Positive revision; every durable mutation increments it. */ + readonly revision: number; +} +/** Input whose omitted round cap is resolved by the service configuration. */ +export interface CreateGoalRequest { + readonly objective: string; + readonly maxGoalRounds?: number; +} +/** Wire-safe acknowledgement of one created goal. */ +export interface CreateGoalResult { + readonly ref: GoalRef; +} +/** Fields changed by an edit; at least one must be present. */ +export interface EditGoalRequest { + readonly objective?: string; + readonly maxGoalRounds?: number; +} +/** Durable continuation phase. Activation is process-local and separate. */ +export type GoalPhase = 'active' | 'paused' | 'blocked' | 'complete'; +/** Machine-routable and human-readable explanation for a blocked goal. */ +export interface GoalBlockReason { + /** Stable lower-kebab-case classification chosen by the blocking policy. */ + readonly code: string; + /** Non-empty explanation shown to humans and models. */ + readonly message: string; +} +/** Full durable state written by every non-clear goal mutation. */ +export interface GoalSnapshot extends GoalRef { + /** Human-requested completion objective. */ + readonly objective: string; + /** Durable lifecycle phase. */ + readonly phase: GoalPhase; + /** Present exactly while `phase` is `blocked`. */ + readonly blockedReason?: GoalBlockReason; + /** Total admitted goal-round cap. */ + readonly maxGoalRounds: number; +} +/** Whether this live process may automatically continue an active goal. */ +export type GoalActivation = 'armed' | 'disarmed'; +/** Current goal projection, including values derived from the session log. */ +export interface GoalView extends GoalSnapshot { + /** Highest admitted round number for this goal. */ + readonly roundsStarted: number; + /** Epoch milliseconds of the create mutation. */ + readonly createdAt: number; + /** Epoch milliseconds of the latest mutation. */ + readonly updatedAt: number; + /** Process-local continuation eligibility; never persisted. */ + readonly activation: GoalActivation; +} +/** + * The `goal` projection value: the current durable goal with its replay + * counters, exactly as the latest `goal/change` event carried them. + * Activation is process-local (never persisted) and deliberately absent — + * the projection reflects durable phase only. + */ +export interface GoalProjection { + /** Current durable goal snapshot (the CAS ref for mutations rides on it). */ + readonly goal: GoalSnapshot; + /** Highest admitted round number for this goal. */ + readonly roundsStarted: number; + /** Epoch milliseconds of the create mutation. */ + readonly createdAt: number; + /** Epoch milliseconds of the latest mutation. */ + readonly updatedAt: number; +} +declare module '@deepseek-ai/dsh-session-projection/types' { + interface SessionProjectionMap { + /** + * The session's current goal (the latest `goal/change` whole value), or + * `null` before the first create and after a clear tombstone. + * Whole-value rule: every goal change carries the complete post-change + * state, so the fold is last-wins. + */ + goal: GoalProjection | null; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/types.js new file mode 100644 index 0000000..4fec899 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/lib/types/types.js @@ -0,0 +1,13 @@ +/** + * Pure types of the goal domain: the ONE home of the `goal` projection-key + * declaration plus the durable payload vocabulary it carries, free of this + * package's host-side imports (cordis events, dsh-agent, dsh-llm, the + * service). Two namespace projections serve it — `./types` for host + * consumers, `./client` (the browser half-entry's re-export) for client + * aggregates — with zero content duplication. Host-coupled domain + * vocabulary (message sources, events, fold shapes) lives in ./domain.ts. + * + * @module @deepseek-ai/dsh-goal/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/package.json new file mode 100644 index 0000000..d318619 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal/package.json @@ -0,0 +1,82 @@ +{ + "name": "@deepseek-ai/dsh-goal", + "description": "Event-sourced same-session goal state and lifecycle service for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/goal/goal" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./client": { + "types": "./lib/types/client.d.ts", + "default": "./lib/types/client.js" + }, + "./typert": { + "types": "./lib/typert.host.d.ts", + "default": "./lib/typert.host.js" + }, + "./remote": { + "types": "./lib/typert.remote-client.d.ts", + "default": "./lib/typert.remote-client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts", + "lib/typert.host.js", + "lib/typert.host.d.ts", + "lib/typert.remote-client.js", + "lib/typert.remote-client.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-loader-smoke": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..ed04634 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..a2fcff1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.i18n.yaml new file mode 100644 index 0000000..64ce9af --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/home-paths/README.md +README.md: edcab2dcab6fa8957cde965ab8221df71dbe69f7 +README.zh.md: 842d8351f2165f759c56a1153b758577ff1fc0bb diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.md new file mode 100644 index 0000000..edcab2d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.md @@ -0,0 +1,30 @@ +# dsh-home-paths + +English | [中文](README.zh.md) + +Shared filesystem path helpers for DeepSeek Harness user data. + +## DSH home + +`resolveDshHome()` resolves the single-root DeepSeek Harness home. Precedence, highest first: an explicit configured path, `$DSH_HOME`, then `~/.dsh`. The harness keeps all user data under one root. + +`dshHomePath(...segments)` joins child segments onto that resolved home with Node's platform path rules. With no segments it returns the home itself. + +`dshHomeDisplay()` names an active root symbolically for user-facing paths: `~/.dsh` for the default home, `$DSH_HOME` for any configured home. It never leaks an absolute machine path. + +`DSH_HOME_DIR_NAME` owns the default user-data directory name: `.dsh`. + +`defaultDshHome()` returns the default DeepSeek Harness home by joining the operating-system home directory with `.dsh`, using Node's platform path rules. + +`expandHomePath()` expands `~`, `~/...`, and Windows-style `~\...` prefixes against the operating-system home directory. It leaves non-tilde paths and `~user/...` untouched. + +## Watch paths + +`canonicalizeWatchPath()` gives a native filesystem watcher one stable spelling of its target. It resolves the deepest existing ancestor through `fs.realpath()` and restores any missing suffix, so a file or directory may still be watched before it is created. In particular, Windows 8.3 aliases cannot be mixed with the long paths emitted by the native watcher backend. + +This package is intentionally small and harness-dep-free so product packages can share user-data path conventions without depending on one another. + +## Known Limitations and Deferred Work + +- **Expansion is deliberately narrow** — only bare `~`, `~/...`, and `~\...` use the current operating-system home; named-user forms such as `~alice/...`, environment variables, and shell expressions remain unchanged. +- **Canonicalization reads but never mutates** — `canonicalizeWatchPath()` performs `realpath` probes and propagates errors other than absence; callers still own directory creation, permissions, and trust policy for the resulting path. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.zh.md new file mode 100644 index 0000000..842d835 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/README.zh.md @@ -0,0 +1,30 @@ +# dsh-home-paths + +[English](README.md) | 中文 + +DeepSeek Harness 用户数据的共享文件系统路径辅助工具。 + +## DSH 主目录 + +`resolveDshHome()` 解析 DeepSeek Harness 的单根主目录。优先级从高到低为:显式配置的路径、`$DSH_HOME`、`~/.dsh`。harness 将所有用户数据保存在同一根目录下。 + +`dshHomePath(...segments)` 使用 Node 的平台路径规则,将子路径段拼接到解析后的主目录下。不传入任何路径段时,返回主目录本身。 + +`dshHomeDisplay()` 以符号方式表示当前根目录,用于面向用户的路径:默认主目录表示为 `~/.dsh`,任何已配置的主目录表示为 `$DSH_HOME`。它绝不会泄露机器的绝对路径。 + +`DSH_HOME_DIR_NAME` 定义默认用户数据目录名:`.dsh`。 + +`defaultDshHome()` 使用 Node 的平台路径规则,将操作系统主目录与 `.dsh` 拼接,并返回默认 DeepSeek Harness 主目录。 + +`expandHomePath()` 使用操作系统主目录展开 `~`、`~/...` 和 Windows 风格的 `~\...` 前缀。它会保留非波浪号路径和 `~user/...` 原样不变。 + +## 监听路径 + +`canonicalizeWatchPath()` 为原生文件系统 watcher 提供一种稳定的目标路径表示。它通过 `fs.realpath()` 解析层级最深的现有祖先路径,再拼回缺失的后缀,因此即使文件或目录尚未创建也仍可监听。尤其是,Windows 8.3 别名不能与原生 watcher 后端发出的长路径混用。 + +该包刻意保持规模小且不依赖 harness,以便产品包共享用户数据路径约定,而不必彼此依赖。 + +## 已知限制与暂缓事项 + +- **展开范围刻意保持狭窄**:只有单独的 `~`、`~/...` 和 `~\...` 使用当前操作系统主目录;`~alice/...` 等指定用户的形式、环境变量和 shell 表达式保持不变。 +- **规范化会读取,但绝不修改**:`canonicalizeWatchPath()` 会执行 `realpath` 探测,并传播除路径不存在以外的错误;调用方仍负责目录创建、权限,以及对结果路径应用信任策略。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js new file mode 100644 index 0000000..071d2f2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js @@ -0,0 +1,97 @@ +import { opendir, realpath } from "node:fs/promises"; +import { homedir } from "node:os"; +import { basename, dirname, join, resolve } from "node:path"; +//#region lib/types/index.js +/** +* Shared filesystem path helpers for DeepSeek Harness user data. +* +* @module @deepseek-ai/dsh-home-paths +*/ +/** Directory name for the default DeepSeek Harness home under the OS home. */ +const DSH_HOME_DIR_NAME = ".dsh"; +/** Stable user-facing display form for the default DeepSeek Harness home. */ +const DEFAULT_DSH_HOME_DISPLAY = `~/${DSH_HOME_DIR_NAME}`; +/** Environment variable that overrides the default DeepSeek Harness home. */ +const DSH_HOME_ENV = "DSH_HOME"; +/** +* Give a native filesystem watcher one canonical spelling of a path, even +* when its final components do not exist yet. The deepest existing ancestor +* is resolved through {@link realpath}; when a suffix is missing, that +* ancestor is also proved to be an enumerable directory before the suffix is +* restored. This prevents Windows from treating a regular-file ancestor as +* ordinary absence, and prevents short-name aliases from being mixed with +* long paths emitted by the native watcher backend. +* @param path - Watch target or root, resolved against the current directory. +* @returns the target with its existing ancestor canonicalized. +* @throws when ancestor traversal encounters an error other than absence, or +* the existing ancestor of a missing suffix is not an enumerable directory. +*/ +async function canonicalizeWatchPath(path) { + let current = resolve(path); + const missing = []; + while (true) try { + const canonical = await realpath(current); + if (missing.length > 0) await (await opendir(canonical)).close(); + return join(canonical, ...missing.reverse()); + } catch (error) { + if (error.code !== "ENOENT") throw error; + const parent = dirname(current); + /* v8 ignore next -- a filesystem root exists, so traversal resolves before this guard */ + if (parent === current) throw error; + missing.push(basename(current)); + current = parent; + } +} +/** +* Resolve the default DeepSeek Harness home using Node's platform path rules. +* @returns the absolute default harness home path. +*/ +function defaultDshHome() { + return join(homedir(), DSH_HOME_DIR_NAME); +} +/** +* Expand supported tilde prefixes against the operating-system home. +* @param path - configured path that may begin with `~`, `~/`, or `~\`. +* @returns the expanded path, or the original value when no supported prefix is present. +*/ +function expandHomePath(path) { + if (path === "~") return homedir(); + if (path.startsWith("~/") || path.startsWith("~\\")) return join(homedir(), path.slice(2)); + return path; +} +/** +* Resolve the single-root DeepSeek Harness home. +* +* Precedence, highest first: an explicit configured path, `$DSH_HOME`, then +* `~/.dsh`. The harness keeps all user data under one root. An empty or +* whitespace-only `$DSH_HOME` is treated as unset, so a blank override never +* resolves the home to the current working directory. +* @param configured - explicit harness-home override, which has highest precedence. +* @param env - environment mapping used to read `DSH_HOME`. +* @returns the normalized absolute harness home path. +*/ +function resolveDshHome(configured, env = process.env) { + const fromEnv = env[DSH_HOME_ENV]; + return resolve(expandHomePath(configured ?? (fromEnv !== void 0 && fromEnv.trim().length > 0 ? fromEnv : defaultDshHome()))); +} +/** +* Join path segments onto the resolved DeepSeek Harness home. +* @param segments - path segments appended to the Harness home; an empty list returns the home itself. +* @returns the normalized absolute joined path. +*/ +function dshHomePath(...segments) { + return join(resolveDshHome(), ...segments); +} +/** +* Describe a resolved harness home symbolically for user-facing display. +* +* It never returns an absolute machine path: the default home is labelled +* `~/.dsh`, and any configured home is labelled `$DSH_HOME`. +* @param resolvedHome - the absolute path returned by {@link resolveDshHome}. +* @returns `~/.dsh` for the default home, otherwise `$DSH_HOME`. +*/ +function dshHomeDisplay(resolvedHome) { + return resolvedHome === resolve(defaultDshHome()) ? DEFAULT_DSH_HOME_DISPLAY : `$${DSH_HOME_ENV}`; +} +//#endregion +export { DEFAULT_DSH_HOME_DISPLAY, DSH_HOME_DIR_NAME, DSH_HOME_ENV, canonicalizeWatchPath, defaultDshHome, dshHomeDisplay, dshHomePath, expandHomePath, resolveDshHome }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/invariant.js new file mode 100644 index 0000000..3fda7ab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-home-paths`. +* @module @deepseek-ai/dsh-home-paths/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-home-paths"; +/** Cordis companion plugin name. */ +const name = "home-paths-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value +* algebra is enforced by unit tests. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/types/index.d.ts new file mode 100644 index 0000000..eb5f8d0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/types/index.d.ts @@ -0,0 +1,64 @@ +/** + * Shared filesystem path helpers for DeepSeek Harness user data. + * + * @module @deepseek-ai/dsh-home-paths + */ +/** Directory name for the default DeepSeek Harness home under the OS home. */ +export declare const DSH_HOME_DIR_NAME = ".dsh"; +/** Stable user-facing display form for the default DeepSeek Harness home. */ +export declare const DEFAULT_DSH_HOME_DISPLAY = "~/.dsh"; +/** Environment variable that overrides the default DeepSeek Harness home. */ +export declare const DSH_HOME_ENV = "DSH_HOME"; +/** + * Give a native filesystem watcher one canonical spelling of a path, even + * when its final components do not exist yet. The deepest existing ancestor + * is resolved through {@link realpath}; when a suffix is missing, that + * ancestor is also proved to be an enumerable directory before the suffix is + * restored. This prevents Windows from treating a regular-file ancestor as + * ordinary absence, and prevents short-name aliases from being mixed with + * long paths emitted by the native watcher backend. + * @param path - Watch target or root, resolved against the current directory. + * @returns the target with its existing ancestor canonicalized. + * @throws when ancestor traversal encounters an error other than absence, or + * the existing ancestor of a missing suffix is not an enumerable directory. + */ +export declare function canonicalizeWatchPath(path: string): Promise; +/** + * Resolve the default DeepSeek Harness home using Node's platform path rules. + * @returns the absolute default harness home path. + */ +export declare function defaultDshHome(): string; +/** + * Expand supported tilde prefixes against the operating-system home. + * @param path - configured path that may begin with `~`, `~/`, or `~\`. + * @returns the expanded path, or the original value when no supported prefix is present. + */ +export declare function expandHomePath(path: string): string; +/** + * Resolve the single-root DeepSeek Harness home. + * + * Precedence, highest first: an explicit configured path, `$DSH_HOME`, then + * `~/.dsh`. The harness keeps all user data under one root. An empty or + * whitespace-only `$DSH_HOME` is treated as unset, so a blank override never + * resolves the home to the current working directory. + * @param configured - explicit harness-home override, which has highest precedence. + * @param env - environment mapping used to read `DSH_HOME`. + * @returns the normalized absolute harness home path. + */ +export declare function resolveDshHome(configured?: string, env?: Record): string; +/** + * Join path segments onto the resolved DeepSeek Harness home. + * @param segments - path segments appended to the Harness home; an empty list returns the home itself. + * @returns the normalized absolute joined path. + */ +export declare function dshHomePath(...segments: string[]): string; +/** + * Describe a resolved harness home symbolically for user-facing display. + * + * It never returns an absolute machine path: the default home is labelled + * `~/.dsh`, and any configured home is labelled `$DSH_HOME`. + * @param resolvedHome - the absolute path returned by {@link resolveDshHome}. + * @returns `~/.dsh` for the default home, otherwise `$DSH_HOME`. + */ +export declare function dshHomeDisplay(resolvedHome: string): string; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/types/invariant.d.ts new file mode 100644 index 0000000..90f177d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-home-paths`. + * @module @deepseek-ai/dsh-home-paths/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "home-paths-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/package.json new file mode 100644 index 0000000..354c41b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-home-paths/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-home-paths", + "description": "Shared filesystem path helpers for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/util/home-paths" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_7bedd37cd7bfa44a7560ebd321630d86/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.i18n.yaml new file mode 100644 index 0000000..64ce9af --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/home-paths/README.md +README.md: edcab2dcab6fa8957cde965ab8221df71dbe69f7 +README.zh.md: 842d8351f2165f759c56a1153b758577ff1fc0bb diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.md new file mode 100644 index 0000000..edcab2d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.md @@ -0,0 +1,30 @@ +# dsh-home-paths + +English | [中文](README.zh.md) + +Shared filesystem path helpers for DeepSeek Harness user data. + +## DSH home + +`resolveDshHome()` resolves the single-root DeepSeek Harness home. Precedence, highest first: an explicit configured path, `$DSH_HOME`, then `~/.dsh`. The harness keeps all user data under one root. + +`dshHomePath(...segments)` joins child segments onto that resolved home with Node's platform path rules. With no segments it returns the home itself. + +`dshHomeDisplay()` names an active root symbolically for user-facing paths: `~/.dsh` for the default home, `$DSH_HOME` for any configured home. It never leaks an absolute machine path. + +`DSH_HOME_DIR_NAME` owns the default user-data directory name: `.dsh`. + +`defaultDshHome()` returns the default DeepSeek Harness home by joining the operating-system home directory with `.dsh`, using Node's platform path rules. + +`expandHomePath()` expands `~`, `~/...`, and Windows-style `~\...` prefixes against the operating-system home directory. It leaves non-tilde paths and `~user/...` untouched. + +## Watch paths + +`canonicalizeWatchPath()` gives a native filesystem watcher one stable spelling of its target. It resolves the deepest existing ancestor through `fs.realpath()` and restores any missing suffix, so a file or directory may still be watched before it is created. In particular, Windows 8.3 aliases cannot be mixed with the long paths emitted by the native watcher backend. + +This package is intentionally small and harness-dep-free so product packages can share user-data path conventions without depending on one another. + +## Known Limitations and Deferred Work + +- **Expansion is deliberately narrow** — only bare `~`, `~/...`, and `~\...` use the current operating-system home; named-user forms such as `~alice/...`, environment variables, and shell expressions remain unchanged. +- **Canonicalization reads but never mutates** — `canonicalizeWatchPath()` performs `realpath` probes and propagates errors other than absence; callers still own directory creation, permissions, and trust policy for the resulting path. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.zh.md new file mode 100644 index 0000000..842d835 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/README.zh.md @@ -0,0 +1,30 @@ +# dsh-home-paths + +[English](README.md) | 中文 + +DeepSeek Harness 用户数据的共享文件系统路径辅助工具。 + +## DSH 主目录 + +`resolveDshHome()` 解析 DeepSeek Harness 的单根主目录。优先级从高到低为:显式配置的路径、`$DSH_HOME`、`~/.dsh`。harness 将所有用户数据保存在同一根目录下。 + +`dshHomePath(...segments)` 使用 Node 的平台路径规则,将子路径段拼接到解析后的主目录下。不传入任何路径段时,返回主目录本身。 + +`dshHomeDisplay()` 以符号方式表示当前根目录,用于面向用户的路径:默认主目录表示为 `~/.dsh`,任何已配置的主目录表示为 `$DSH_HOME`。它绝不会泄露机器的绝对路径。 + +`DSH_HOME_DIR_NAME` 定义默认用户数据目录名:`.dsh`。 + +`defaultDshHome()` 使用 Node 的平台路径规则,将操作系统主目录与 `.dsh` 拼接,并返回默认 DeepSeek Harness 主目录。 + +`expandHomePath()` 使用操作系统主目录展开 `~`、`~/...` 和 Windows 风格的 `~\...` 前缀。它会保留非波浪号路径和 `~user/...` 原样不变。 + +## 监听路径 + +`canonicalizeWatchPath()` 为原生文件系统 watcher 提供一种稳定的目标路径表示。它通过 `fs.realpath()` 解析层级最深的现有祖先路径,再拼回缺失的后缀,因此即使文件或目录尚未创建也仍可监听。尤其是,Windows 8.3 别名不能与原生 watcher 后端发出的长路径混用。 + +该包刻意保持规模小且不依赖 harness,以便产品包共享用户数据路径约定,而不必彼此依赖。 + +## 已知限制与暂缓事项 + +- **展开范围刻意保持狭窄**:只有单独的 `~`、`~/...` 和 `~\...` 使用当前操作系统主目录;`~alice/...` 等指定用户的形式、环境变量和 shell 表达式保持不变。 +- **规范化会读取,但绝不修改**:`canonicalizeWatchPath()` 会执行 `realpath` 探测,并传播除路径不存在以外的错误;调用方仍负责目录创建、权限,以及对结果路径应用信任策略。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js new file mode 100644 index 0000000..071d2f2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js @@ -0,0 +1,97 @@ +import { opendir, realpath } from "node:fs/promises"; +import { homedir } from "node:os"; +import { basename, dirname, join, resolve } from "node:path"; +//#region lib/types/index.js +/** +* Shared filesystem path helpers for DeepSeek Harness user data. +* +* @module @deepseek-ai/dsh-home-paths +*/ +/** Directory name for the default DeepSeek Harness home under the OS home. */ +const DSH_HOME_DIR_NAME = ".dsh"; +/** Stable user-facing display form for the default DeepSeek Harness home. */ +const DEFAULT_DSH_HOME_DISPLAY = `~/${DSH_HOME_DIR_NAME}`; +/** Environment variable that overrides the default DeepSeek Harness home. */ +const DSH_HOME_ENV = "DSH_HOME"; +/** +* Give a native filesystem watcher one canonical spelling of a path, even +* when its final components do not exist yet. The deepest existing ancestor +* is resolved through {@link realpath}; when a suffix is missing, that +* ancestor is also proved to be an enumerable directory before the suffix is +* restored. This prevents Windows from treating a regular-file ancestor as +* ordinary absence, and prevents short-name aliases from being mixed with +* long paths emitted by the native watcher backend. +* @param path - Watch target or root, resolved against the current directory. +* @returns the target with its existing ancestor canonicalized. +* @throws when ancestor traversal encounters an error other than absence, or +* the existing ancestor of a missing suffix is not an enumerable directory. +*/ +async function canonicalizeWatchPath(path) { + let current = resolve(path); + const missing = []; + while (true) try { + const canonical = await realpath(current); + if (missing.length > 0) await (await opendir(canonical)).close(); + return join(canonical, ...missing.reverse()); + } catch (error) { + if (error.code !== "ENOENT") throw error; + const parent = dirname(current); + /* v8 ignore next -- a filesystem root exists, so traversal resolves before this guard */ + if (parent === current) throw error; + missing.push(basename(current)); + current = parent; + } +} +/** +* Resolve the default DeepSeek Harness home using Node's platform path rules. +* @returns the absolute default harness home path. +*/ +function defaultDshHome() { + return join(homedir(), DSH_HOME_DIR_NAME); +} +/** +* Expand supported tilde prefixes against the operating-system home. +* @param path - configured path that may begin with `~`, `~/`, or `~\`. +* @returns the expanded path, or the original value when no supported prefix is present. +*/ +function expandHomePath(path) { + if (path === "~") return homedir(); + if (path.startsWith("~/") || path.startsWith("~\\")) return join(homedir(), path.slice(2)); + return path; +} +/** +* Resolve the single-root DeepSeek Harness home. +* +* Precedence, highest first: an explicit configured path, `$DSH_HOME`, then +* `~/.dsh`. The harness keeps all user data under one root. An empty or +* whitespace-only `$DSH_HOME` is treated as unset, so a blank override never +* resolves the home to the current working directory. +* @param configured - explicit harness-home override, which has highest precedence. +* @param env - environment mapping used to read `DSH_HOME`. +* @returns the normalized absolute harness home path. +*/ +function resolveDshHome(configured, env = process.env) { + const fromEnv = env[DSH_HOME_ENV]; + return resolve(expandHomePath(configured ?? (fromEnv !== void 0 && fromEnv.trim().length > 0 ? fromEnv : defaultDshHome()))); +} +/** +* Join path segments onto the resolved DeepSeek Harness home. +* @param segments - path segments appended to the Harness home; an empty list returns the home itself. +* @returns the normalized absolute joined path. +*/ +function dshHomePath(...segments) { + return join(resolveDshHome(), ...segments); +} +/** +* Describe a resolved harness home symbolically for user-facing display. +* +* It never returns an absolute machine path: the default home is labelled +* `~/.dsh`, and any configured home is labelled `$DSH_HOME`. +* @param resolvedHome - the absolute path returned by {@link resolveDshHome}. +* @returns `~/.dsh` for the default home, otherwise `$DSH_HOME`. +*/ +function dshHomeDisplay(resolvedHome) { + return resolvedHome === resolve(defaultDshHome()) ? DEFAULT_DSH_HOME_DISPLAY : `$${DSH_HOME_ENV}`; +} +//#endregion +export { DEFAULT_DSH_HOME_DISPLAY, DSH_HOME_DIR_NAME, DSH_HOME_ENV, canonicalizeWatchPath, defaultDshHome, dshHomeDisplay, dshHomePath, expandHomePath, resolveDshHome }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/invariant.js new file mode 100644 index 0000000..3fda7ab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-home-paths`. +* @module @deepseek-ai/dsh-home-paths/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-home-paths"; +/** Cordis companion plugin name. */ +const name = "home-paths-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value +* algebra is enforced by unit tests. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/types/index.d.ts new file mode 100644 index 0000000..eb5f8d0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/types/index.d.ts @@ -0,0 +1,64 @@ +/** + * Shared filesystem path helpers for DeepSeek Harness user data. + * + * @module @deepseek-ai/dsh-home-paths + */ +/** Directory name for the default DeepSeek Harness home under the OS home. */ +export declare const DSH_HOME_DIR_NAME = ".dsh"; +/** Stable user-facing display form for the default DeepSeek Harness home. */ +export declare const DEFAULT_DSH_HOME_DISPLAY = "~/.dsh"; +/** Environment variable that overrides the default DeepSeek Harness home. */ +export declare const DSH_HOME_ENV = "DSH_HOME"; +/** + * Give a native filesystem watcher one canonical spelling of a path, even + * when its final components do not exist yet. The deepest existing ancestor + * is resolved through {@link realpath}; when a suffix is missing, that + * ancestor is also proved to be an enumerable directory before the suffix is + * restored. This prevents Windows from treating a regular-file ancestor as + * ordinary absence, and prevents short-name aliases from being mixed with + * long paths emitted by the native watcher backend. + * @param path - Watch target or root, resolved against the current directory. + * @returns the target with its existing ancestor canonicalized. + * @throws when ancestor traversal encounters an error other than absence, or + * the existing ancestor of a missing suffix is not an enumerable directory. + */ +export declare function canonicalizeWatchPath(path: string): Promise; +/** + * Resolve the default DeepSeek Harness home using Node's platform path rules. + * @returns the absolute default harness home path. + */ +export declare function defaultDshHome(): string; +/** + * Expand supported tilde prefixes against the operating-system home. + * @param path - configured path that may begin with `~`, `~/`, or `~\`. + * @returns the expanded path, or the original value when no supported prefix is present. + */ +export declare function expandHomePath(path: string): string; +/** + * Resolve the single-root DeepSeek Harness home. + * + * Precedence, highest first: an explicit configured path, `$DSH_HOME`, then + * `~/.dsh`. The harness keeps all user data under one root. An empty or + * whitespace-only `$DSH_HOME` is treated as unset, so a blank override never + * resolves the home to the current working directory. + * @param configured - explicit harness-home override, which has highest precedence. + * @param env - environment mapping used to read `DSH_HOME`. + * @returns the normalized absolute harness home path. + */ +export declare function resolveDshHome(configured?: string, env?: Record): string; +/** + * Join path segments onto the resolved DeepSeek Harness home. + * @param segments - path segments appended to the Harness home; an empty list returns the home itself. + * @returns the normalized absolute joined path. + */ +export declare function dshHomePath(...segments: string[]): string; +/** + * Describe a resolved harness home symbolically for user-facing display. + * + * It never returns an absolute machine path: the default home is labelled + * `~/.dsh`, and any configured home is labelled `$DSH_HOME`. + * @param resolvedHome - the absolute path returned by {@link resolveDshHome}. + * @returns `~/.dsh` for the default home, otherwise `$DSH_HOME`. + */ +export declare function dshHomeDisplay(resolvedHome: string): string; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/types/invariant.d.ts new file mode 100644 index 0000000..90f177d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-home-paths`. + * @module @deepseek-ai/dsh-home-paths/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "home-paths-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/package.json new file mode 100644 index 0000000..671244d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-home-paths", + "description": "Shared filesystem path helpers for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/util/home-paths" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent-default-model b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent-default-model new file mode 120000 index 0000000..36c16b0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent-default-model @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent-default-model@0.1.0-rc.6_8bffb997b64260f42aff4629c695b626/node_modules/@deepseek-ai/dsh-agent-default-model \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent-presets b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent-presets new file mode 120000 index 0000000..485bbde --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-agent-presets @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-api-remotes b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-api-remotes new file mode 120000 index 0000000..c247381 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-api-remotes @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-api-remotes@0.1.0-rc.6_963f21f11cddd09def26a2473cddd8c5/node_modules/@deepseek-ai/dsh-api-remotes \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-attachment b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-attachment new file mode 120000 index 0000000..ad086eb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-attachment @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-commands b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-commands new file mode 120000 index 0000000..fff701f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-commands @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-commands@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_f18bd7aa4aa916b517165061977dda49/node_modules/@deepseek-ai/dsh-commands \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-cordis-host-runner b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-cordis-host-runner new file mode 120000 index 0000000..e7009aa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-cordis-host-runner @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.6_2a68b6a2e3f14f86835048b212eef386/node_modules/@deepseek-ai/dsh-cordis-host-runner \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-credentials b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-credentials new file mode 120000 index 0000000..ea853b1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-credentials @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-credentials@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_cb4e897fa6df50478cd9a096f850da93/node_modules/@deepseek-ai/dsh-credentials \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-goal b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-goal new file mode 120000 index 0000000..2465185 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-goal @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-goal@0.1.0-rc.6_3f17eb6754612fc564ecc2cacddc7a21/node_modules/@deepseek-ai/dsh-goal \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.i18n.yaml new file mode 100644 index 0000000..2ae197d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/host/apiproxy/README.md +README.md: b7dee9488c1b123172c225d4d4235bdb3c76911d +README.zh.md: 46835a84254c4bbc45300a18d29aae5a6ac66f14 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.md new file mode 100644 index 0000000..b7dee94 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.md @@ -0,0 +1,83 @@ +# @deepseek-ai/dsh-host-apiproxy + +English | [中文](README.zh.md) + +The API gateway shared by every client consists of the TypeScript API contract (`src/api/`, zero Node dependencies, importable from the browser), the fetch carrier pair (`src/fetch/`: `toFetchHandler` on the host side, `AbstractApiClient` plus platform subclasses on the client side), and the host-side implementation (`src/api-proxy.ts`: `createApiProxy` plus the default-exported `ApiProxyService` gateway plugin — config `{nativeOpen?, sessionExportCompressionLevel?, coldBlankProbeMaxBytes?}`, provides `ctx.apiProxy`). This package registers no routes; carriers such as HTTP wrap `ctx.apiProxy` themselves. The shipped Web composition lives in [`packages/bundle/web-app/cordis.patch.yml`](../../bundle/web-app/cordis.patch.yml), while its default Agent model selection belongs to [`@deepseek-ai/dsh-agent-default-model`](../../core/agent-default-model/README.md) in the base bundle. + +## The shared Agent default (`agent-default-model` Settings section) + +`ApiProxyService` consumes `ctx.agentDefaultModel`; it does not own a provider/model config or settings section. The shared service registers `{provider, model, reasoningEffort?}` under `agent-default-model`: the base bundle's composition entry is the lower layer and `settings.yaml` layers the user's choice over it. + +A session resolves its model selection from three tiers on every access: a selection made in this process, otherwise the session's latest logged `request/header`, otherwise this default. A session that has run a turn derives its selection from its log, while a blank session observes a default saved after it was created. + +`session.selectModel` saves an accepted switch as the deployment default; there is no separate gesture. It stores the resolved `ModelSelection`, including an adapter-materialized default effort. The complete-section write clears a stored effort when the selected model has none. A storage failure is logged without undoing the session selection. A deployment with no settings provider keeps the composition entry and the switch remains session-local. + +The section's `reasoningEffort` has no counterpart in the agent-default-model plugin config, deliberately: the seam merges the user layer over the composition entry per field, so an absent key cannot override a present one and a composition-set effort would survive every later switch to a model without one. A deployment default for effort belongs on the adapter profile, which resolves per model. + +The stored selection is independent of catalog membership. A default naming an unavailable provider still reaches `session.models` as the session's `current`, allowing the selector to request a replacement instead of silently choosing another model. Conversely, an adapter may serve a model that its catalog does not advertise. + +## Contract layer (`/api`) + +Wire messages form a four-quadrant discriminated union — who initiates × request/response — decoupled from the physical channel: `ClientRequest` (POST `/api/` body), `ServerResponse` (that POST's response body), `ServerRequest` (SSE frame), `ClientResponse` (POST `/api/respond` body). Responses always echo the matching request's `rpcId` and never mint a new one. Method parameter/return structures live only in the domain interface signatures (`SessionsApi`, `HostApi`, `EventsApi`); `RpcMethodMap` registers the methods and every other position derives via `RequestPayload`/`ResponseValue`. Zod schemas anchor `satisfies z.ZodType>` and parse at two levels: envelope first, business payload second, dispatched per method. Business errors ride `RpcResult`'s error branch (`RpcErrorDetailsMap` closes the code set); HTTP status expresses only the carrier. Every `/api` POST must declare the `application/json` media type — anything else is refused with 415 before dispatch, so cross-site "simple" requests (which browsers send without a CORS preflight) can never execute a side-effectful method blind. + +The layering/protocol decisions are recorded in the [GUI layering and RPC protocol RFC](../../../.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md); the browser-side consumption architecture in the [web client architecture RFC](../../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md). + +Question responses are validated against their pending request before the first answer claims it. A multi-select item may carry both requested option labels in `selected` and non-empty `custom` text; a single-select item must use one or the other. Duplicate labels, unknown labels, mismatched ids, incomplete batches, and empty custom text are rejected as `bad-response`. + +`session.history` reads an attached Session in memory or inspects a cold log through persistence without resuming or publishing an Agent, then pages on append-origin message boundaries. `maxMessages` counts `user/message` and `assistant/message` events that entered the surface by appending, so a model-only replacement copy consumes no quota. Each page stays one contiguous raw event range, which keeps a compaction's log-only `compaction/summary` record on the same page as the replacement that cites it. + +`session.history`'s tail page (`beforeSeq` absent) additionally carries an optional `projections` block — the watermark snapshot of every unit registered on `ctx.sessionProjections` (`@deepseek-ai/dsh-session-projection`), with `asOfSeq` = the last event seq the values reflect (`-1` on an empty log). The gateway also subscribes to the registry's change feed and mints a `session/projection` mux frame per changed unit (`{sessionId, key, value, seq}` — live push state, never logged; clients hold one generic per-session value store under higher-seq-wins). The carrier holds no other domain's knowledge (each value passed its unit's own schema inside the registry; the wire schemas keep `values`/`value` wide); loadOlder pages never carry the block, and a composition without the registry serves histories without either surface. The gateway owns two units: `sessionListMetadata` caches the monotonic blank-to-nonblank transition and latest human prompt time used by `session.list`, while `imageLimits` publishes the attachments config enforced at prompt admission as a per-boot constant (`apply` keeps the state reference, so baselines alone carry it — no change frames) so clients can refuse an over-limit intake before submit and label upload affordances; the latter activates only while both the registry and the attachments service are composed. + +Session-log export is a host-only download surface, not an RPC: `GET /api/session.export?sessionId=…&includeDescendants=true` streams a ZIP whose files are each session's stored artifact text verbatim (the persistence backend's `readRaw` — exact durable bytes decoded from the physical encoding, never a reconstruction from parsed events), root under its original base name plus each subagent descendant under `subagents//`, and every image any included log references under `media/.` (read and verified from the attachment store; a shared image appears once). `HEAD` runs the same root preparation and returns its status and headers without a response body, so browser clients can detect pre-stream failures before handing the GET to the native download manager. Each live root or descendant crosses the authoritative `SessionStore.flush` durability barrier immediately before its raw artifact read; cold sessions have no in-memory work to flush. Compression runs on the host with fflate's streaming Zip API at validated `sessionExportCompressionLevel` 0–9 (default 6), so deployments can trade CPU and latency against archive size; the response is chunked as it is produced and the host never holds the whole archive in one buffer. Once the response queue reaches its 64 KiB byte high-water mark, production waits until consumer pull restores positive capacity; fflate's synchronous callback can overshoot that bound only by the output of one bounded input push. Request abort and response-body cancellation stop lineage and artifact work, terminate the active compressor, and propagate as cancellation rather than an HTTP 500. It requires the persistence, session-query, and attachment services: a deployment without any answers 500, a persistence backend without per-session raw artifacts answers 501, a missing root session answers 404, and a descendant without a stored artifact or a referenced image that cannot be read fails the stream (fail-loud, never silent under-export). The carrier mounts the endpoint; `ApiProxy.downloads.sessionLog` implements it. + +Session titles ride the generic projection pair like every other domain — the history-tail `projections` block plus `session/projection` frames under the `title` key. Titles do not join `session.list`; cold sessions remain metadata-only there until opening or resuming attaches their logs. `session.rename` accepts an explicit user title (resuming a cold session first), delegating to `ctx.sessionTitle.rename` — the accepted `session/title` event pins the title against automatic regeneration — and returns the normalized title plus its event seq so a client settles its `title` projection cell ahead of the push frame; a title that normalizes to empty returns `title-invalid`. + +`session.fork` maps an optional event anchor to the first `turn/end` at or after it, letting a message action include that message's whole turn. An omitted or past-end anchor selects the last completed turn; an in-log anchor whose turn remains open returns `fork-unavailable` rather than clipping backward. The published child inherits the source's seeded history, cwd, latest logged `ModelSelection`, and lineage before joining the source Workspace. If Workspace attachment fails, `workspace-attach-failed` carries the already-published child id so clients can reconcile it. The [SessionStore fork decision](../../../.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.md) records why the anchor maps to that `turn/end`. + +Session model selection is a session-domain contract. `session.models` returns the current `ModelSelection` separately from provider-grouped advisory models, exact-model reasoning metadata, and provider-local lookup failures. The selection may be absent from the groups and is never injected as a synthetic row; clients can prompt for another selection without turning the directory into a routing whitelist. `session.selectModel` validates the optional adapter-owned reasoning effort and assigns the complete selection for the next prompt assembly. Catalog membership is not validation: an adapter may resolve an unlisted model, while an unavailable provider or unsupported effort returns `model-unavailable`. `session.models` additionally reports `routable`: whether an adapter currently serves the selected provider. This is deliberately not derivable from the groups because an adapter may serve an unadvertised model. `session.prompt` refuses on the same fact with `model-unavailable` before opening a turn; a disabled composer is a client affordance, and the method remains callable. + +`session.prompt` and `subagent.prompt` accept optional request-local `clientTimeZone` provenance. When present, the Host validates and canonicalizes `UTC` or an IANA Area/Location before Agent entry, rejects invalid input with `invalid-time-zone`, and records the canonical value on that exact `user-rpc` message beside its `rpcId`. The value is not Session, connection, create, resume, or fork state; non-browser callers may omit it. + +Pending queued input is a live control-plane contract, not conversation history. The gateway derives the complete `next-turn` queue from durable `agent/inbox/spliced` mutations and broadcasts authoritative `session/queue` snapshots after each change and on reconnect; pending `next-step` steering stays outside this Web projection. Within `next-step`, user-origin messages carry the `steering` placement while injected context (approval notices, task completion, attached snapshots) carries `context` and is not surfaced until claimed. The message-local `agent/inbox/inserted`, `claimed`, and `discarded` notifications remain available to lifecycle observers but do not build the queue view. `session.updateQueue` addresses one `MessageId`; edit and remove mutate the attached Agent through `Inbox.splice()`. A claim's pure deletion splice wins races before pre-step admission, so a later operation returns `queue-item-not-found`. `session.cancel` aborts only the active turn and preserves pending inbox work; after cancellation reaches quiescence and the closing turn flushes, AgentLoop claims the next waking message in FIFO order, and the browser never resends or promotes it. Queue operations never resume a cold session, and the client never infers retirement from turn or status events. + +Background jobs ride the same live-push posture. When `ctx.jobs` is composed, the gateway subscribes to its change feed and broadcasts a whole `session/jobs` snapshot after every registry commit that alters what a session can see — registration, the stopping transition, settlement, and owner-disposal removal — plus a subscription baseline for each session that already has tasks (an absent baseline is the empty set; a change that empties a set still sends `[]`). A change carrying an owner reads through that exact `Agent`, so a push stays correct while its scope tears down; the baseline reads `ctx.agents.get(sessionId)`, which yields only unowned tasks for a session with no live Agent and never resumes a cold one. An unowned change fans out to every subscribed session, because unowned tasks are visible to every caller. The wire `JobView` drops `ownerSession`, `reported`, and `outputLimitBytes`: the frame's own `sessionId` carries the first, and the other two are internal notice and model-presentation policy. A composition without the registry emits no such frames. + +Workspace and Session lists are separate reconnect baselines. `workspace.create({ path })` adopts an existing canonical directory and permits basename-derived titles to repeat. `workspace.insertBefore({ workspaceId, beforeWorkspaceId? })` commits one registry-order move and answers the complete order; a pure reorder emits `host/workspace-order-changed` with that complete order, while unknown sources or anchors return `workspace-not-found`. `workspace.delete` removes only the Workspace registration, `session.create` accepts an optional preallocated Session id, and `host/workspace-changed`, `host/workspace-removed`, plus `host/session-added` carry committed increments in either arrival order. `workspace.archiveSession` adds one session to the registry-global archive set and answers the full updated set; `workspace.list` carries that set as the reconnect baseline and `host/archived-sessions-changed` pushes the full snapshot after every durable change. Archiving hides the session from grouping surfaces without touching its log or its workspace account; a session neither live nor persisted fails with `session-not-found`. Registration deletion preserves the directory and session logs; its Sessions remain in `session.list` and become Ungrouped. `SessionSummary.blank` and the `host/session-added` frame carry whether a turn has started: clients hide blank sessions and reuse them per workspace, flip blank on the first `host/session-status(running:true)`, and treat `session.list` as the reconnect authority. Attached summaries fold the live log. A cold summary trusts cached `blank: false`, but treats cached `true` and a cache miss as unverified; when `locate()` reports an artifact no larger than the `coldBlankProbeMaxBytes` eligibility threshold (default 1 KiB), the gateway reads that Session with `readFrom()` and folds both blankness and the latest human prompt. A larger, location-less, vanished, or unreadable artifact remains visible. After an asynchronous cold read, a Session that attached meanwhile is summarized from its live log instead. `updatedAt` uses the live fold, the exact small-artifact fold, or the projection cache in that order, falling back to `createdAt`; pickup boundaries and other writes never promote a Session. + +`session.search` is a bounded content-search projection over the sessions visible through `session.list`. The gateway asks the optional `ctx.sessionQuery` service for globally ranked current-surface user, assistant, and steering matches, consumes that stream until it has at most 20 visible session/snippet pairs plus one lookahead, and revalidates every hit against the list-derived authorization set before returning it. Provider pages start at 20 hits; when a first-page request rejects that limit, the gateway probes 10, 5, 2, then 1 and retains the learned size for continuation and stale-generation restarts. Returned snippets contain at most 240 Unicode code points, and the response schema independently enforces that bound at each client boundary. Keeping the authorization set in Host memory avoids SQLite's variable ceiling for large valid corpora without weakening visibility or ranking. + +A stale continuation discards every partial result, deduplication entry, and cursor from that provider attempt, then restarts at the first page against the original list-derived visibility snapshot without discarding the learned provider page size. Limit probes and stale retries share the same limit of at most 100 provider calls (and therefore at most 2,000 inspected hits); a page larger than its requested limit, a repeated continuation cursor, or a still-unexhausted stream at that call budget fails closed as an `internal` business error. The carrier request signal cancels persistence listing, cold-summary collection, and every search call, including a limit or stale rejection observed concurrently with cancellation. A deployment without the service, or any unrecovered index/query failure, also returns an `internal` business error so clients can retain metadata-only matches. + +Directory picking delegates to the composed `ctx.directoryPicker` backend ([the directory-picker seam](../directory-picker/README.md)); a method called outside the composed capability's kind fails with `directory-picker-unavailable` (the client needs no advertisement — the composed picker package's own client half renders the matching interaction). Under `native`, `host.pickDirectory` opens one native chooser and returns its selected path (`null` on cancel); this user-paced method does not use the default 30-second unary timeout, while caller/connection aborts still propagate to the native process. Under `browse`, `host.listDirectory` returns one name-sorted directory level with breadcrumb ancestry, a `home` anchor, and host-owned `hidden` flags (absent path = home directory), and `host.createDirectory` creates one validated child segment; the backend's typed failures map 1:1 onto the `directory-unreadable`/`directory-exists`/`directory-create-failed` codes. The browser carrier's prefix-wide trust fence (dsh-client-connection) covers all of these like every other `/api` request. + +`host.openPath` opens a filesystem path with the operating system's default application (`open` on macOS, `Invoke-Item` on Windows, and `xdg-open` on desktop Linux). For `.html`, `.htm`, `.xhtml`, and `.svg`, macOS and desktop Linux prefer a named default browser and fall back to that application handoff when none can be named. WSL translates every Linux path through `wslpath -w` and hands the resulting Windows/UNC path to Windows `Invoke-Item`, including browser-renderable documents, instead of assuming a Linux desktop association. `host.describe.canOpenPath` advertises whether that handoff can reach a user-visible desktop: explicit gateway `nativeOpen` wins, an injected opener is usable by definition, and platform detection otherwise accepts macOS, Windows, WSL, or Linux with a display while rejecting headless/container Linux. The browser carrier applies the same loopback, same-origin restriction as `host.pickDirectory`; clients combine both facts before presenting a native action. + +The `agentPreset.list` domain exposes the deployment's preset roster so a browser can offer a choice when starting a session; each row carries its `trust` (a `user` preset is exactly as privileged as the plugins it names), whether it is the current default, and — when the preset cannot compose a session — a `broken` reason, because a damaged directory still occupies its id and a surface must be able to show and delete it rather than offer it and fail the session start. A deployment composing no presets answers with an empty roster rather than an error, because sharing the host composition is a valid deployment. `agentPreset.select` recomposes one session's agent from a different preset, and is allowed only while the session is blank: once a turn has run, that history was produced under the preset's tools and swapping them would strand logged tool calls, so the attempt answers `agent-preset-locked`. The agent and the session survive — only the composition is swapped, and a failed swap restores the previous one. + +`agentPreset.read`, `copy`, `openDocument`, and `remove` manage the compositions themselves. `read` reports the text with its `trust`, for the read-only viewer. Authoring is copy-only: `copy` takes `{ from, agentPreset, name? }` — two ids the Host resolves against its own roots plus an optional display name — and copies the source's whole directory, so no composition text crosses the wire and a copy is exactly as loadable as its source; an uncontainable or already-taken id answers `agent-preset-invalid`, and `remove` refuses a shipped preset as `agent-preset-read-only`. `openDocument` hands one locally authored preset's DIRECTORY to the platform opener — the request carries an id, never a path, so no browser payload can select an arbitrary filesystem target; where the deployment has no native opener the reply is `{ opened: false, path }` for the surface to show as text, a shipped preset is refused like `remove`, and the gateway's `nativeOpen` config pins the capability where platform detection (`canOpenNativePath`) would mislead. These four are loopback-pinned in [`dsh-client-connection`](../../client/connection/README.md): a composition names the plugins a session runs, so reading one is reconnaissance, and copy/remove/openDocument manage the roster and drive the host desktop. `list` and `select` stay ordinary — the roster carries ids and trust and every preset picker needs it, and choosing a preset grants nothing `session.create`'s own `agentPreset` did not, over a default that already carries bash. `list` reports two path-free capability flags: `authorable`, whether the deployment configures a root a new preset could be copied to, and `hasDocument`, whether `openDocument` would open natively rather than answer a path. + +The `command.*` and `skill.*` domains expose the host command registry and skill catalog to clients. Every method addresses one session's agent by `sessionId` (a served session always has an Agent; `command.*` resumes cold sessions through the same path as `session.*`, while `skill.list` resolves the project root from the session header without touching the Agent registry). `skill.list` serves the composer's menu: it returns every user-invocable skill with its `modelInvocable` flag, so menus can mark user-only (`disable-model-invocation`) entries whose only invocation path is the slash gesture. Listing is the skill domain's only RPC — invocation itself is an ordinary `session.prompt` whose whitespace-bounded `/name` tokens `dsh-tool-skill` recognizes at the pre-step boundary and answers with injected `` context, so every entry point (Web, TUI, and ACP) shares one deterministic path—including for hand-typed text—with no dedicated invocation wire. `command.execute` runs a slash-command line host-side with pure admission semantics: the response reports whether the line resolved to a handler plus the minted lifecycle `commandId` when it did (correlating the acknowledgment with the flow node), while the outcome rides the durably logged `command/run`/`command/done` lifecycle pair broadcast on the mux stream. Command handlers may legitimately outlast the 30-second transport health deadline, so `command.execute` carries only caller/connection cancellation; that signal cancels the running handler. `commands/change` rides the forwarded-event frame as the registry-wide catalog invalidation signal: clients refetch `command.list` instead of diffing. Forwarded `agent-preset/selected` is its per-session counterpart, emitted from the logged selection commit: recomposing a blank session's agent re-parents its scope without registering anything, so both catalogs that session's composition decides (`command.list`, `skill.list`) go stale with no registry change to announce it. + +The `settings.*`, `credentials.*`, and `llm.*` domains are the configuration-page wire. The settings domain serves the namespaces addressed by registered configurable providers (`ctx.llm.listConfigurableProviders()`) plus a small explicit allowlist — the Web preferences `locale`, `permission`, `ui-conversation`, and `ui-theme`, the host-plane plugin sections `agent-loop`, `bash`, and `web-search-deepseek` that the plugin configuration page edits, and the product-owned `ui-onboarding`; adding a Settings registration alone never makes it remotely readable or writable. Any other namespace answers `settings-not-exposed` — the same answer an unregistered namespace gets, so no caller can enumerate the registry by probing. `settings.describe` returns each exposed namespace's serialized schemastery schema, redacted layered values (resolved/`base`/`user` — a field's presence in `user` marks it user-overridden), the `secrets` slot list, the section's `revision`, and the boolean `hasDocument` capability flag. The browser receives no Host path: pathless `settings.openDocument` asks the provider to materialize its document and then hands the Host-resolved result to the native opener, so no browser payload can select any filesystem target. `settings.update`/`settings.replace` write the user layer; `settings.mutate` applies path ops (`set`/`unset`) against the section as stored, which is the removal path for a client holding the redacted view — rebuilding a section from it and replacing wholesale would delete the secrets the wire never returned. Any write may carry `expectedRevision`; a stale one answers `settings-conflict` with both revisions rather than overwriting the writer that landed first, and every other seam refusal folds into `settings-rejected`. Secret-role values never ride any response in any layer; a secret crosses the wire in exactly one direction — inside an `update`/`mutate` payload or `credentials.set`. `credentials.describe` returns value-free views (`configured`/`source`/`writable`), and `credentials.set`/`credentials.unset` map a shadowed-reference refusal onto `credential-rejected`. `llm.providers` merges the configurable-provider directory with live routes (dormant entries carry `active: false`; undeclared live routes append with no settings address) and `llm.models` is the session-independent catalog. `llm.discoverModels` interrogates a provider endpoint the page is still drafting: `settingsNs` selects the adapter family that knows how to read the listing, and the endpoint, protocol, and key come from the form rather than from storage. It writes nothing — the reply is candidates, and only a later `settings.mutate` decides what a route serves — so its `apiKey` is the third payload on which a secret may ride, alongside `settings.update`/`mutate` and `credentials.set`. The host never stores or returns it; like the other two it does ride the client's outgoing envelope, which `subscribeEnvelopes()` observers can see, and redacting that tap is a configuration-plane-wide change rather than this method's to make alone. Every refusal (an unserved namespace, a protocol with no readable listing, an unreachable endpoint, a rejected credential) folds into `model-discovery-failed`, whose message is the adapter's own text and whose details name the endpoint asked but never the credential offered. Invalidations keep every surface converged without polling. `settings/document-updated` and `credentials/updated` ride the verbatim forwarded-event frame (see below), so a raw settings change whose resolved value is unchanged still reaches clients, and a credential invalidation still carries reference names only, never values. `llm/adapters-updated` is forwarded beside `settings/document-updated`; concrete model consumers subscribe to both owner events directly because topology commits and settings documents can independently change their directories. The browser carrier restricts the whole configuration plane, reads and native actions included (`settings.describe`/`openDocument`/`update`/`replace`/`mutate`, `credentials.describe`/`set`/`unset`), to loopback same-origin requests — the `host.pickDirectory` privileged set. A composition without a settings or credential provider answers those domains with an actionable `internal` error naming the missing plugin. + +## Carrier layer (`/client` + root) + +`AbstractApiClient` holds every protocol invariant — rpcId minting, envelope wrap/unwrap, zod parsing, SSE frame decoding, unary timeout, microtask-batched envelope observation (`subscribeEnvelopes`) — while platform subclasses supply only the `doFetch` transport aspect. `InProcessApiClient` over `toFetchHandler(api)` remains the isomorphic point for callers and carrier tests that need the full wire serialization/validation path without a network. Product `dsh --profile headless` is a direct core entry point and does not mount this package. + +## Model Experience + +None, as the package defines the client↔host wire contract and carriers; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **Forwarded Remote events are parasitic on this legacy frame union** — `host/remote-event` lives in `HostFrame` so the delivery path could reuse the existing host stream instead of opening a third downlink, which makes it read as if this package owned the Remote event contract. It does not: the allowlist is `dsh-api-remotes`' and the consumer verb is `ctx.remote.$on`. When the host stream moves off this package, the frame moves with it and the consumer contract is unaffected ([rationale](../../../.agents/notes/implemented/architecture/2026-08-10-remote-event-delivery.md)). +- **Pending-interaction state is host-side** — the wire uses POST `/api/respond` plus `RpcReceipt`; the table in `src/api-proxy.ts` handles questions only and has no approval entries. +- **Reserved seams stay out of `RpcMethodMap`** — `prompt.mode: 'inject'`, `job.list`, and a describe `hostInstanceId` are documented reservations; model discovery uses `llm.models`. An unknown method fails loud at envelope parse rather than getting a not-implemented code. +- **No protocol version field** — client and host ship together; `host.describe` gains a version negotiation field only when an independently released client exists. +- **Search failures include provider diagnostics** — the gateway is a single-user local service. A carrier that exposes it to multiple users must replace internal search details with a public-safe diagnostic. +- **Linux native picker requires desktop tooling** — under the `native` capability, `host.pickDirectory` reports an actionable error when neither Zenity nor KDialog is installed; the browse backend is the composition-level fallback (see the [native backend README](../directory-picker-native/README.md)). +- **Cold-list hints degrade only toward visibility and older ordering** — a projection-cache miss or stale `lastPromptAt` falls back to `createdAt` unless an eligible small artifact supplies an exact fold, so a recently worked large Session may sort too low until the next checkpoint. A blank artifact larger than `coldBlankProbeMaxBytes`, or one from a backend without `locate()`, remains visible. The threshold is checked before `readFrom()` rather than enforced by persistence, so concurrent artifact growth may increase one probe's read cost without changing blankness safety. The [bounded blank-verification decision](../../../.agents/notes/implemented/bug-fix/2026-08-13-bounded-cold-blank-verification.md) owns this safety direction; an authoritative exact recency index remains scoped in the [last-activity-index proposal](../../../.agents/notes/proposed/architecture/2026-07-29-durable-last-activity-index.md). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.zh.md new file mode 100644 index 0000000..46835a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/README.zh.md @@ -0,0 +1,83 @@ +# @deepseek-ai/dsh-host-apiproxy + +[English](README.md) | 中文 + +所有客户端共用的 API 网关由三部分组成:TypeScript API 约定(`src/api/`,不依赖 Node,可从浏览器导入)、fetch 载体对(`src/fetch/`:宿主侧的 `toFetchHandler`,以及客户端侧的 `AbstractApiClient` 与平台子类)和宿主侧实现(`src/api-proxy.ts`:`createApiProxy` 加上默认导出的 `ApiProxyService` 网关插件,其配置为 `{nativeOpen?, sessionExportCompressionLevel?, coldBlankProbeMaxBytes?}`,提供 `ctx.apiProxy`)。该包不注册任何路由;HTTP 等载体自行包装 `ctx.apiProxy`。随发行版交付的 Web 组合位于 [`packages/bundle/web-app/cordis.patch.yml`](../../bundle/web-app/cordis.patch.yml),其默认 Agent(智能体)模型选择属于 base 组合包中的 [`@deepseek-ai/dsh-agent-default-model`](../../core/agent-default-model/README.md)。 + +## 共享 Agent 默认值(`agent-default-model` Settings 分节) + +`ApiProxyService` 消费 `ctx.agentDefaultModel`;它不持有提供方/模型配置或 Settings 分节。共享服务在 `agent-default-model` 下注册 `{provider, model, reasoningEffort?}`:base 组合包的组合条目是底层,`settings.yaml` 把用户选择叠加其上。 + +会话每次访问时都按三级解析模型选择:本进程内作出的选择,其次是该会话日志中最新的 `request/header`,最后是这个默认值。已经跑过一轮的会话从自己的日志推导选择,空白会话则能观察到创建之后保存的默认值。 + +`session.selectModel` 会把接受的切换保存为部署默认值;没有单独的选择动作。它存储已解析的 `ModelSelection`,包括适配器实体化的默认推理(reasoning)强度。完整分节写入会在所选模型没有推理强度时清除已存值。存储失败只记日志,不会撤销会话选择。没有设置提供方的部署保留组合条目,切换只对当前会话生效。 + +Settings 分节中的 `reasoningEffort` 在 agent-default-model 插件配置中刻意没有对应字段:seam 按字段把用户层合并到组合条目之上,因此缺席的键无法覆盖已有键,组合层中的推理强度会在以后选择没有推理强度的模型时继续存在。推理强度的部署默认值属于按模型解析的适配器 profile。 + +存储的选择独立于目录成员关系。默认值指向不可用的提供方时,它仍会作为会话的 `current` 送到 `session.models`,让选择器请求用户重新选择,而不是静默选用其他模型。反过来,适配器也可以服务其目录中未公布的模型。 + +## 约定层(`/api`) + +协议消息组成一个四象限可辨识联合:发起方 × 请求/响应,与物理通道解耦。四种消息分别是 `ClientRequest`(POST `/api/` 的请求体)、`ServerResponse`(该 POST 的响应体)、`ServerRequest`(SSE(Server-Sent Events)帧)和 `ClientResponse`(POST `/api/respond` 的请求体)。响应始终回显对应请求的 `rpcId`,绝不签发新值。方法的参数与返回值结构只存在于领域接口签名(`SessionsApi`、`HostApi`、`EventsApi`)中;`RpcMethodMap` 注册方法,其他所有位置均通过 `RequestPayload`/`ResponseValue` 派生。Zod schema 以 `satisfies z.ZodType>` 锚定类型,并分两层解析:先解析信封,再解析业务载荷,随后按方法分发。业务错误由 `RpcResult` 的错误分支承载(`RpcErrorDetailsMap` 封闭错误码集合);HTTP 状态只表达载体层结果。每个 `/api` POST 都必须声明 `application/json` 媒体类型——否则在分发前即以 415 拒绝,因此跨站「简单请求」(浏览器不经 CORS 预检就会发出)永远无法盲目执行有副作用的方法。 + +分层与协议决策记录在 [GUI 分层与 RPC 协议 RFC](../../../.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md) 中;浏览器侧消费架构记录在 [Web 客户端架构 RFC](../../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md) 中。 + +首个回答认领待处理请求之前,系统会对照该请求校验问题响应。多选题的回答项可以同时携带 `selected` 中的请求选项标签与非空 `custom` 文本;单选题的回答项必须二选一。标签重复、标签未知、id 不匹配、批次不完整以及自定义文本为空都会以 `bad-response` 拒绝。 + +`session.history` 会读取已附加 Session 的内存状态,或通过持久化检查冷日志,而不会恢复或发布 agent,然后按追加来源的消息边界分页:`maxMessages` 统计以追加方式进入 surface 的 `user/message` 和 `assistant/message` 事件,因此仅供模型使用的替换副本不占用配额。每一页仍是一段连续的原始事件区间,从而让压缩(compaction)的仅日志 `compaction/summary` 记录与引用它的替换留在同一页。 + +`session.history` 的尾页(不带 `beforeSeq`)额外携带一个可选的 `projections` 块——`ctx.sessionProjections`(`@deepseek-ai/dsh-session-projection`)上每个已注册单元的水位线快照,`asOfSeq` = 这些值共同反映到的最后一个事件 seq(空日志为 `-1`)。网关还订阅注册表的变更流,为每个状态发生变化的单元生成一个 `session/projection` mux 帧(`{sessionId, key, value, seq}`——实时推送状态,绝不入日志;客户端按 seq 高者胜维护一个按会话的通用值仓)。载体不持有其他领域的知识(每个值在注册表内部已过其单元自己的 schema;协议 schema 对 `values`/`value` 保持宽松);loadOlder 页永不携带该块,未装注册表的组合则两个面都不提供。网关拥有两个单元:`sessionListMetadata` 缓存用于 `session.list` 的单调 blank→nonblank 转换与最新真人 prompt 时间;`imageLimits` 则把 prompt 准入时执行的 attachments 配置作为每次启动恒定的值发布(`apply` 保持状态引用不变,因此只靠基线携带、绝不产生变更帧),供客户端在提交前拒绝超限的加入并给上传入口标注上限,后者仅在注册表与 attachments 服务同时组合时激活。 + +会话日志导出是宿主侧的下载面,不是 RPC:`GET /api/session.export?sessionId=…&includeDescendants=true` 流式返回一个 ZIP,其中每个文件都是会话存储工件的逐字原文(持久化后端的 `readRaw`——按物理编码解码的确切持久化字节,绝非从解析后事件重建),根会话放在其原始基础文件名下,每个子代理后代放在 `subagents//` 下,每个被任何包含的日志引用的图片放在 `media/.` 下(从附件存储读取并校验;共享图片只出现一次)。`HEAD` 会执行相同的根工件准备,并在没有响应 body 的情况下返回状态与响应头,使浏览器 Client 可以在把 GET 交给原生下载管理器前发现流式传输前的失败。每个实时根会话或后代都会在读取原始工件前立即通过权威的 `SessionStore.flush` 持久性屏障;冷会话没有需要 flush 的内存工作。压缩在宿主侧使用 fflate 流式 Zip API 和已验证的 `sessionExportCompressionLevel` 0–9(默认 6),使部署可以在 CPU/延迟与归档大小之间取舍;响应边生成边分块写出,宿主从不把整个归档放进单个缓冲区。响应队列达到 64 KiB 字节高水位后,生产会等待 Consumer pull 恢复正容量;fflate 的同步回调最多只会让该界限多出一次有界输入 push 的输出。请求中止或响应 body 取消会停止血缘与工件工作、终止活跃压缩器,并继续按取消传播,而不会变成 HTTP 500。它要求同时挂载持久化、session-query 与附件服务:任一缺失应答 500,持久化后端不提供每会话原始工件时应答 501,根会话缺失时应答 404,后代缺少存储工件或引用的图片无法读取则整个流失败(fail-loud,绝不静默少导出)。端点由传输层挂载,`ApiProxy.downloads.sessionLog` 实现它。 + +会话标题与其他所有领域一样搭乘这对通用投影机制——历史尾页的 `projections` 块外加 `title` 键下的 `session/projection` 帧。标题不会加入 `session.list`;冷会话在其中仍只有元数据,直到打开或恢复操作附加其日志。`session.rename` 接受用户显式标题(冷会话先恢复),委托给 `ctx.sessionTitle.rename`——被接受的 `session/title` 事件将标题钉住、不再被自动生成覆盖——并返回规范化后的标题及其事件 seq,让 client 在推送帧到达前就结算自己的 `title` 投影格;规范化后为空的标题返回 `title-invalid`。 + +`session.fork` 将可选事件锚点映射到该锚点处或其后的首个 `turn/end`,使消息操作可包含该消息所在的完整轮次。锚点省略或超过末尾时,选择最后一个已完成轮次;若锚点已在日志中,而其所在轮次仍开放,则返回 `fork-unavailable`,不会向较早位置裁剪。发布后的子会话会先继承源会话的种子历史、cwd、日志中最新的 `ModelSelection` 及谱系,再加入源 Workspace。如果附加到 Workspace 失败,`workspace-attach-failed` 会携带已发布的子会话 id,供客户端对账。[SessionStore fork 决策](../../../.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.md)记录了为何锚点要映射到该 `turn/end`。 + +会话模型选择属于会话领域约定。`session.models` 将当前 `ModelSelection` 与按提供方分组的建议性模型、精确模型的推理元数据和逐提供方查询失败记录分开返回。该选择可能不在这些分组中,也绝不会作为合成行注入;客户端可以提示用户作出另一项选择,而无需把目录变成路由白名单。`session.selectModel` 校验由适配器持有的可选推理强度,并指定下次组装提示词时使用的完整选择。目录成员关系不构成校验:适配器可以解析未列出的模型,而不可用的提供方或不受支持的推理强度会返回 `model-unavailable`。`session.models` 还会报告 `routable`,即当前是否有适配器为所选提供方提供服务。该值刻意不从分组推导,因为适配器可以服务未公布的模型。`session.prompt` 会依据同一事实,在开启轮次之前以 `model-unavailable` 拒绝;客户端禁用 composer 只是提示性设计,这个方法始终可被调用。 + +`session.prompt` 和 `subagent.prompt` 接受可选的请求本地 `clientTimeZone` 来源信息。若提供该值,Host 会在进入 Agent 前校验 `UTC` 或 IANA Area/Location 并将其规范化;无效输入以 `invalid-time-zone` 拒绝,规范值则与 `rpcId` 一起记录在这条确切的 `user-rpc` 消息上。该值不属于 Session、连接、create、resume 或 fork 状态;非浏览器调用方可以省略它。 + +待处理的 queued 输入属于实时控制平面约定,而非对话历史。网关根据持久 `agent/inbox/spliced` 变更派生完整的 `next-turn` 队列,并在每次变更后及重连时广播权威 `session/queue` 快照;待处理的 `next-step` steering(中途引导)不进入此 Web 投影。在 `next-step` 内,用户来源的消息携带 `steering` placement,而注入上下文(审批通知、任务完成、附加快照)携带 `context`,领取前不对外呈现。面向单条消息的 `agent/inbox/inserted`、`claimed` 与 `discarded` 通知仍供生命周期观察方使用,但不用于构建队列视图。`session.updateQueue` 通过 `MessageId` 寻址单个项;编辑和移除经已挂载 Agent 的 `Inbox.splice()` 修改队列。认领操作的纯删除 splice 会在 pre-step 准入前赢得竞态,因此之后的操作返回 `queue-item-not-found`。`session.cancel` 仅中止活动轮次并保留待处理 inbox 工作;取消达到完全停稳且结束中的轮次完成 flush 后,AgentLoop 按 FIFO 顺序认领下一条可唤醒消息,浏览器绝不重发或提升它。队列操作绝不恢复冷会话,客户端也绝不根据轮次或状态事件推断某项已退出队列。 + +后台任务沿用同一种实时推送姿态。当组合中有 `ctx.jobs` 时,网关订阅它的变更订阅,并在注册表每一次改变某个会话可见内容的提交后——注册、转入 stopping、结算,以及 owner 销毁时的移除——广播一份完整的 `session/jobs` 快照,另外为每个已经有任务的会话发送订阅 baseline(没有 baseline 即表示空集;把集合清空的那次变更仍然发送 `[]`)。带 owner 的变更通过那个确切的 `Agent` 读取,因此推送在其 scope 拆除期间依然正确;baseline 读 `ctx.agents.get(sessionId)`,对没有活体 Agent 的会话只得到无主任务,且绝不恢复冷会话。无主变更向每一个已订阅会话扇出,因为无主任务对所有调用方可见。线路上的 `JobView` 丢弃 `ownerSession`、`reported` 和 `outputLimitBytes`:第一个由帧自身的 `sessionId` 携带,另外两个分别是内部通知位和模型呈现策略。没有该注册表的组合不发出这类帧。 + +Workspace 列表与 Session 列表是相互独立的重连基线。`workspace.create({ path })` 会接纳已有的规范目录,并允许由 basename 派生的标题重复。`workspace.insertBefore({ workspaceId, beforeWorkspaceId? })` 提交一次注册表顺序移动并应答完整顺序;单纯重排序会通过 `host/workspace-order-changed` 推送同一份完整顺序,而未知来源或锚点返回 `workspace-not-found`。`workspace.delete` 只移除 Workspace 注册记录,`session.create` 接受可选的预分配 Session id,`host/workspace-changed`、`host/workspace-removed` 与 `host/session-added` 则以任意到达顺序携带已提交的增量。`workspace.archiveSession` 向注册表级全局归档集合添加一个会话,并应答完整的更新后集合;`workspace.list` 携带该集合作为重连基线,`host/archived-sessions-changed` 在每次持久变更后推送完整快照。归档只把会话从各分组视图中隐藏,不触碰其日志和 workspace 记账;既非活动会话也未持久化的会话以 `session-not-found` 失败。删除注册记录会保留目录和会话日志;相关 Session 仍留在 `session.list` 中,并进入 Ungrouped。`SessionSummary.blank` 与 `host/session-added` 帧携带是否已开始过轮次:客户端隐藏空白会话并按 workspace 复用它们,在首个 `host/session-status(running:true)` 时翻转 blank,并以 `session.list` 作为重连权威。已附加摘要折叠实时日志。冷摘要信任缓存的 `blank: false`,但把缓存的 `true` 与 cache miss 都视为未经验证;当 `locate()` 报告的工件不大于 `coldBlankProbeMaxBytes` 资格阈值(默认 1 KiB)时,网关通过 `readFrom()` 读取该 Session,同时折叠空白状态与最新真人 prompt。更大、无位置、已消失或不可读的工件保持可见。异步冷读取结束后,期间已附加的 Session 会改用实时日志生成摘要。`updatedAt` 依次采用实时折叠、小工件精确折叠或 projection cache,缺失时回退到 `createdAt`;拾起边界及其他写入都不会提升 Session 排序。 + +`session.search` 是以 `session.list` 所列会话为范围的有界内容搜索投影。网关向可选的 `ctx.sessionQuery` 服务请求全局排序后的当前内容视图中的 user、assistant 和 steering 匹配项,并持续消费该结果流,直到获得至多 20 个可见会话/snippet 对及一个前瞻项;返回前仍会依据从列表推导的授权集合重新校验每个命中。提供方分页初始请求 20 个命中;如果第一页请求因这一上限被拒绝,网关会依次探测 10、5、2、1,并在续传和陈旧世代重启中沿用探测所得的页面大小。返回的 snippet 最多包含 240 个 Unicode 码点,响应 schema 则会在每个客户端边界独立强制执行该上限。将授权集合保留在宿主内存中,可在不削弱可见性或排序的前提下避开有效大型语料库的 SQLite 变量上限。 + +陈旧的续传会丢弃该提供方尝试中的所有部分结果、去重条目和游标,然后依据最初从列表推导的可见性快照从第一页重新开始,但不会丢弃探测所得的提供方页面大小。上限探测与陈旧重试共用最多 100 次提供方调用的限制(因此最多检查 2,000 个命中);如果某页命中数超过其请求的上限、续传游标重复,或用尽该调用预算后结果流仍未耗尽,都会直接返回 `internal` 业务错误,不返回部分结果。载体请求信号可取消持久化列表枚举、冷会话摘要收集和每一次搜索调用;即使同时收到上限拒绝或陈旧拒绝,也以取消为准。部署若未挂载该服务,或索引/查询故障无法恢复,也会返回 `internal` 业务错误,以便客户端保留仅基于元数据的匹配项。 + +目录选择委托给组合的 `ctx.directoryPicker` 后端([目录选择 seam](../directory-picker/README.md));调用组合能力 kind 之外的方法会以 `directory-picker-unavailable` 失败(客户端不需要广播——组合的选择器包自己的 client half 渲染匹配的交互)。在 `native` 下,`host.pickDirectory` 打开一个原生选择器并返回选中路径(取消为 `null`);该方法需等待用户完成操作,不使用默认的 30 秒一元调用超时,而调用方与连接的中止仍会传播至原生进程。在 `browse` 下,`host.listDirectory` 返回一个按名称排序的目录层级,携带面包屑祖先链、`home` 锚点与宿主判定的 `hidden` 标志(不带路径即家目录),`host.createDirectory` 创建一个经校验的子段;后端的类型化失败 1:1 映射为 `directory-unreadable`/`directory-exists`/`directory-create-failed` 错误码。浏览器载体的前缀级信任栅栏(dsh-client-connection)像覆盖其他所有 `/api` 请求一样覆盖上述全部方法。 + +`host.openPath` 会用操作系统的默认应用打开一个文件系统路径(macOS 为 `open`,Windows 为 `Invoke-Item`,桌面 Linux 为 `xdg-open`)。对于 `.html`、`.htm`、`.xhtml` 与 `.svg`,macOS 和桌面 Linux 会优先使用能够确定的默认浏览器;无法确定时回退到上述应用交接。WSL 会通过 `wslpath -w` 转换每个 Linux 路径,并将所得 Windows/UNC 路径交给 Windows `Invoke-Item`,浏览器可渲染的文档也不例外,而非假定存在 Linux 桌面文件关联。`host.describe.canOpenPath` 会宣告这次交接能否抵达用户可见的桌面:网关显式配置的 `nativeOpen` 优先,注入的 opener 按定义可用,否则平台检测接受 macOS、Windows、WSL 或带 display 的 Linux,并拒绝 headless/容器 Linux。浏览器载体对其施加与 `host.pickDirectory` 相同的回环、同源限制;客户端会组合这两个事实后再呈现原生操作。 + +`agentPreset.list` 领域向浏览器暴露部署的 preset 名单,使其在开启会话时能够提供选择;每一行携带它的 `trust`(`user` preset 的权限恰好等于它所引用的插件)、它是否为当前默认值,以及——当该 preset 无法组装会话时——一条 `broken` 原因:损坏的目录仍占着它的 id,界面必须能展示并删除它,而不是把它端出来然后在会话启动时失败。未组装任何 preset 的部署返回空名单而非错误,因为共用宿主组装本身就是一种有效部署。`agentPreset.select` 用另一个 preset 重组某个会话的 agent,且仅在会话空白时允许:一旦跑过任何轮次,那段历史就是在该 preset 的工具下产生的,替换会留下无法执行的已记录的工具调用,此时返回 `agent-preset-locked`。agent 与会话都不销毁——只替换组装,且替换失败会恢复原来的组装。 + +`agentPreset.read`、`copy`、`openDocument` 与 `remove` 负责管理组装本身。`read` 返回文本连同它的 `trust`,供只读查看器使用。创作只有复制一种写入:`copy` 接收 `{ from, agentPreset, name? }`——两个由 Host 对照自身根目录解析的 id 加一个可选显示名——并整目录复制来源,因此组装文本不经过传输层,副本与其来源同等可加载;不可约束或已被占用的 id 回答 `agent-preset-invalid`,`remove` 对随附 preset 回答 `agent-preset-read-only`。`openDocument` 把一个本地创作 preset 的**目录**交给平台打开器——请求只携带 id、绝不携带路径,因此没有任何浏览器载荷能选中任意文件系统目标;部署没有原生打开器时回答 `{ opened: false, path }` 供界面以文本展示,随附 preset 与 `remove` 一样被拒绝,而网关的 `nativeOpen` 配置可在平台探测(`canOpenNativePath`)失真处钉死该能力。这四个方法在 [`dsh-client-connection`](../../client/connection/README.md) 中被固定在环回地址:组装指明了一个会话所运行的插件,因此读取它是侦察,而 copy/remove/openDocument 管理名单并驱动宿主桌面。`list` 与 `select` 保持为普通方法——名单只携带 id 与信任级别,每个 preset 选择器都需要它;而选择一个 preset 并不比 `session.create` 自带的 `agentPreset` 多给任何能力,何况默认 preset 本就带着 bash。`list` 报告两个不含路径的能力标志:`authorable`,即部署是否配置了可供复制新 preset 的根目录;`hasDocument`,即 `openDocument` 会原生打开、还是回答一个路径。 + +`command.*` 与 `skill.*` 领域向客户端暴露宿主命令注册表和 skill(技能)目录。每个方法都通过 `sessionId` 寻址一个会话的 Agent(被服务的会话必有 Agent;`command.*` 经由与 `session.*` 相同的路径恢复冷会话,而 `skill.list` 从会话头解析项目根目录,不触碰 Agent 注册表)。`skill.list` 服务于 composer 的菜单:它返回每一个用户可调用的 skill 及其 `modelInvocable` 标志,让菜单能够标出仅限用户(`disable-model-invocation`)的条目——斜杠手势是这类条目唯一的调用路径。列表是 skill 领域唯一的 RPC——调用本身就是一次普通的 `session.prompt`,`dsh-tool-skill` 会在 pre-step 边界识别其中以空白为界的 `/name` token,并以注入的 `` 上下文作答,因此所有入口(Web、TUI 与 ACP(Agent Client Protocol))共享同一条确定性路径,手动键入的文本也走该路径,且没有专设的调用协议。`command.execute` 在宿主侧运行一条斜杠命令行,语义为纯准入:响应报告该行是否解析到处理器,并在解析到时回带铸造的生命周期 `commandId`(将本次确认与流节点关联);结局经由持久落账并在 mux 流广播的 `command/run`/`command/done` 生命周期事件对承载。命令处理器运行超过 30 秒的传输健康时限仍属正常,因此 `command.execute` 仅携带调用方/连接取消信号;该信号可取消正在运行的处理器。`commands/change` 搭乘转发事件帧作为注册表级目录失效信号:客户端重新拉取 `command.list` 而不是做差分。转发的 `agent-preset/selected` 是它按会话粒度的对应物,由落账的选择提交点发出:重组空会话的 agent 只是重新挂接其 scope,不产生任何注册,因此该会话组成所决定的两份目录(`command.list`、`skill.list`)都会失效,却没有任何注册表变化来宣告它。 + +`settings.*`、`credentials.*` 与 `llm.*` 领域是配置页协议。settings 领域服务于已注册可配置提供方所指向的 namespace(`ctx.llm.listConfigurableProviders()`),并额外服务于一份小型、显式的 allowlist——Web 偏好 `locale`、`permission`、`ui-conversation` 与 `ui-theme`、插件配置页所编辑的宿主平面插件分节 `agent-loop`、`bash` 与 `web-search-deepseek`,以及产品持有的 `ui-onboarding`;仅新增一项 Settings 注册,绝不会使其可被远程读取或写入。其他任何 namespace 都只会得到 `settings-not-exposed`——未注册的 namespace 得到的是同一个答复,因此没有调用方能靠逐个探测把注册表枚举出来。`settings.describe` 为每个已暴露 namespace 提供其序列化 schemastery schema、脱敏后的分层值(resolved/`base`/`user`——字段出现在 `user` 中即标记其被用户覆盖)、`secrets` 槽位列表、该分节的 `revision`,以及布尔型 `hasDocument` 能力标志。浏览器不会收到 Host 路径:无路径参数的 `settings.openDocument` 会请求提供方准备文档,再把由 Host 解析出的结果交给原生打开器,因此任何浏览器载荷都无法选择任意文件系统目标。`settings.update`/`settings.replace` 写入用户层;`settings.mutate` 则在已存分节上施加路径 op(`set`/`unset`),这是持有脱敏视图的客户端的删除路径——据此重建分节再整体替换,会删掉协议从未回传过的那些机密。任何写入都可携带 `expectedRevision`;陈旧的期望值会以 `settings-conflict` 连同两个 revision 作答,而不是覆盖先落地的那个写方,其余每种 seam 拒绝则折叠为 `settings-rejected`。secret 角色的值绝不在任何一层搭乘任何响应;secret 只沿一个方向跨越协议——在 `update`/`mutate` 载荷或 `credentials.set` 之内。`credentials.describe` 返回不含值的视图(`configured`/`source`/`writable`),`credentials.set`/`credentials.unset` 则把被遮蔽引用的拒绝映射为 `credential-rejected`。`llm.providers` 把可配置提供方目录与存活路由合并(休眠条目携带 `active: false`;未声明的存活路由追加在后,不带 settings 地址),`llm.models` 则是与会话无关的目录。`llm.discoverModels` 询问页面尚在起草的提供方端点:`settingsNs` 选出懂得读取该列表的适配器家族,端点、协议与密钥则来自表单而非存储。它什么都不写——回复是候选,只有随后的 `settings.mutate` 才决定路由服务什么——因此其 `apiKey` 是 secret 可以搭乘的第三个载荷(另两个是 `settings.update`/`mutate` 与 `credentials.set`),且绝不被存储或回显。host 从不存储或回传它;与另两者一样,它确实会搭乘客户端的出站信封,`subscribeEnvelopes()` 的观察者能看到——为该 tap 做脱敏是整个配置面的改动,而非本方法一家的事。每一种拒绝(无人服务的 namespace、没有可读列表的协议、不可达端点、被拒凭据)都折叠为 `model-discovery-failed`,其消息是适配器自己的文本,details 点名被询问的端点,绝不点名所提供的凭据。失效通知让每个面无需轮询即保持收敛。`settings/document-updated` 与 `credentials/updated` 搭乘原样转发事件帧(见下),因此解析值未变的原始设置变更同样能到达客户端,凭据失效通知也仍然只带引用名、绝不带值。`llm/adapters-updated` 与 `settings/document-updated` 一并原样转发;具体模型消费方直接订阅这两个 owner 事件,因为拓扑提交和设置文档都能独立改变其目录。浏览器载体把整个配置面(含读取与原生操作:`settings.describe`/`openDocument`/`update`/`replace`/`mutate` 与 `credentials.describe`/`set`/`unset`)限制为仅接受来自回环地址的同源请求——即 `host.pickDirectory` 所在的特权集合。未装 settings 或凭据提供方的组合会以指名缺失插件、包含解决建议的 `internal` 错误应答这些领域。 + +## 载体层(`/client` + 根路径) + +`AbstractApiClient` 持有全部协议不变量:签发 rpcId、包装/解包信封、Zod 解析、SSE 帧解码、一元请求超时,以及按微任务批处理的信封观测(`subscribeEnvelopes`);平台子类只提供 `doFetch` 传输环节。`InProcessApiClient` 以 `toFetchHandler(api)` 为基础,仍是同构接点:它运行完整的协议序列化与校验路径而不经过网络,供需要该路径的调用方和载体测试使用。产品的 `dsh --profile headless` 是直连 core 的入口,不挂载本包。 + +## 模型体验 + +无。该包定义客户端与宿主间的 wire 约定和载体,其中没有任何内容会进入模型请求。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **转发的 Remote 事件寄居在这套 legacy 帧联合里**:`host/remote-event` 住在 `HostFrame` 中,是为了让投递路径复用现有宿主流、不必新开第三条下行通道,因此读起来像是本包拥有 Remote 事件契约。并非如此:名单归 `dsh-api-remotes`,消费端动词是 `ctx.remote.$on`。将来宿主流整体搬离本包时,该帧随之搬走,消费端契约不受影响([原委](../../../.agents/notes/implemented/architecture/2026-08-10-remote-event-delivery.md))。 +- **待处理交互状态位于宿主侧**:wire 使用 POST `/api/respond` 加 `RpcReceipt`;`src/api-proxy.ts` 中的表只处理问题,不包含审批条目。 +- **预留 seam 不进入 `RpcMethodMap`**:`prompt.mode: 'inject'`、`job.list` 和描述字段 `hostInstanceId` 都是已记录的预留项;模型发现使用 `llm.models`。未知方法会在信封解析时直接失败,而不会返回「尚未实现」错误码。 +- **没有协议版本字段**:客户端与宿主一同发布;只有出现独立发布的客户端后,`host.describe` 才会增加版本协商字段。 +- **搜索失败会包含提供方诊断信息**:网关是单用户本地服务。将其暴露给多名用户的载体必须用可安全公开的诊断信息替代内部搜索细节。 +- **Linux 原生选择器依赖桌面工具**:在 `native` 能力下,Zenity 和 KDialog 均未安装时,`host.pickDirectory` 会给出包含解决建议的错误提示;组合层面的回退是 browse 后端(见 [native 后端 README](../directory-picker-native/README.md))。 +- **冷列表提示只向“保持可见、排序偏旧”降级**:projection cache miss 或陈旧的 `lastPromptAt` 会回退到 `createdAt`,除非符合资格的小工件提供精确折叠,因此最近工作过的大 Session 可能在下一个 checkpoint 前排得偏低。大于 `coldBlankProbeMaxBytes` 的空白工件,或来自不提供 `locate()` 的后端的空白工件会保持可见。该阈值在 `readFrom()` 前检查,而非由 persistence 强制,因此工件并发增长可能增加一次探测的读取成本,但不会改变空白状态的安全方向。[有界空白验证决策](../../../.agents/notes/implemented/bug-fix/2026-08-13-bounded-cold-blank-verification.md)规定了这个安全方向;权威且精确的最近时间索引仍属于[最后活动索引提案](../../../.agents/notes/proposed/architecture/2026-07-29-durable-last-activity-index.md)的范围。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/index.js new file mode 100644 index 0000000..9e3afa7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/index.js @@ -0,0 +1,5648 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { randomUUID } from "node:crypto"; +import { mkdir, stat } from "node:fs/promises"; +import { dirname, extname } from "node:path"; +import { installModelSelection } from "@deepseek-ai/dsh-agent"; +import { AttachmentError } from "@deepseek-ai/dsh-attachment"; +import { ReasoningEffortId, contentHasImage, createUserMessage, errorChain, freezeMessage } from "@deepseek-ai/dsh-llm"; +import { isAppendSurfaceEvent, isJsonValue } from "@deepseek-ai/dsh-session"; +import { SessionQueryError } from "@deepseek-ai/dsh-session-query"; +import { SubagentError } from "@deepseek-ai/dsh-subagent"; +import { isUserInvocable } from "@deepseek-ai/dsh-skill"; +import { WorkspaceId, WorkspaceMoveInvalidError, WorkspaceOrderInvalidError, WorkspaceUnknownSessionError, workspaceDomainState, workspaceRecord } from "@deepseek-ai/dsh-workspace"; +import { InvalidPresetIdError, PresetExistsError, PresetMountError, PresetNotWritableError, SETTINGS_NAMESPACE, UnknownPresetError, resolveSessionPreset } from "@deepseek-ai/dsh-agent-presets"; +import { Zip, ZipDeflate } from "fflate"; +import { GoalError } from "@deepseek-ai/dsh-goal"; +import { SettingsConflictError, settingsNamespace } from "@deepseek-ai/dsh-settings"; +import { credentialRef } from "@deepseek-ai/dsh-credentials"; +import { SessionTitleInvalidError } from "@deepseek-ai/dsh-session-title"; +import { z as z$1 } from "zod"; +import { UserQuestionError } from "@deepseek-ai/dsh-user-questions"; +import { DirectoryPickerError } from "@deepseek-ai/dsh-host-directory-picker"; +import { API_REMOTE_FORWARDED_EVENTS, ApiRemoteSessionNotFound, ApiRemoteSubagentSessionOwnership, apiRemoteSubagentOwnershipError, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession } from "@deepseek-ai/dsh-api-remotes"; +import { release } from "node:os"; +import { runNativeCommand } from "@deepseek-ai/dsh-native-command"; +//#region lib/types/session-export.js +/** +* Host-side session-log download: streams one ZIP archive whose files are the +* sessions' stored artifact text verbatim plus every referenced media object. +* The root artifact sits under its original base name (`session.jsonl`); each +* subagent descendant under `subagents//`; each image referenced +* by any included log under `media/.` (content-addressed, +* so one archive never duplicates a shared image). No manifest is written — +* every file is byte-identical to the backend's durable artifact or attachment +* store and self-describing through its own header line or media type. Before +* each live session's artifact read, the SessionStore flush barrier makes the +* current in-memory log durable; cold sessions need no barrier. Request abort +* and response-consumer cancellation share one producer signal and terminate +* the active compressor. +* Compression runs on the host with fflate's streaming Zip API, so the archive +* bytes are produced incrementally and the host never holds the whole archive +* in one buffer; production waits for consumer pull whenever the response queue +* reaches its byte high-water mark, so a slow consumer bounds accumulation to +* the fixed 64 KiB response queue plus one synchronous fflate push. +* @module +*/ +/** +* Resolve the persistence, session-query, and attachment services a log export needs. +* @param ctx - the composed host context. +* @returns the export services (absent when the deployment does not mount them). +*/ +function sessionLogExportDeps(ctx) { + return { + sessionQuery: ctx.get("sessionQuery"), + sessionPersistence: ctx.get("sessionPersistence"), + attachments: ctx.get("attachments"), + sessions: ctx.get("sessions") + }; +} +/** +* Flush one currently live session through the store's authoritative durability +* barrier immediately before its raw artifact is read. A cold or absent id has +* no in-memory work to flush. +* @param deps - export services, including the optional live-session store. +* @param id - the session whose artifact is about to be read. +* @param signal - optional cancellation observed around the flush barrier. +*/ +async function flushLiveSessionLog(deps, id, signal) { + signal?.throwIfAborted(); + const sessions = deps.sessions; + if (sessions === void 0) return; + const session = sessions.get(id); + if (session === void 0) return; + await sessions.flush(session); + signal?.throwIfAborted(); +} +/** Zip extension for each accepted raster media type. */ +const MEDIA_TYPE_EXTENSIONS = { + "image/png": "png", + "image/jpeg": "jpg", + "image/webp": "webp", + "image/gif": "gif" +}; +/** +* The zip path for one media object: content-addressed by the opaque +* attachment id so shared images land once and the id in the log maps back to +* the archive entry without a manifest. +* @param ref - the durable reference from a session log. +* @returns the archive path. +*/ +function mediaEntryPath(ref) { + return `media/${String(ref.attachmentId)}.${MEDIA_TYPE_EXTENSIONS[ref.mediaType]}`; +} +/** +* Collect every image reference inside one content array, descending into +* nested tool results the way the live attachment route does. +* @param content - an event content array (or nested tool-result content). +* @param refs - the dedupe map being filled (keyed by attachment id). +*/ +function collectImageRefs(content, refs) { + if (!Array.isArray(content)) return; + const pending = []; + for (const item of content) pending.push(item); + while (pending.length > 0) { + const value = pending.pop(); + if (typeof value !== "object" || value === null || Array.isArray(value)) continue; + const block = value; + if (block.type === "image" && typeof block.attachment === "object" && block.attachment !== null) { + const ref = block.attachment; + refs.set(String(ref.attachmentId), ref); + } + if (Array.isArray(block.content)) for (const item of block.content) pending.push(item); + } +} +/** +* Collect every image reference one session event carries, across the same +* carriers the live attachment route scans (direct content, message content, +* inserted messages, and completed assistant chunk blocks). +* @param event - one parsed JSONL event object. +* @param refs - the dedupe map being filled (keyed by attachment id). +*/ +function collectEventImageRefs(event, refs) { + const data = event.data; + if (typeof data !== "object" || data === null) return; + const carrier = data; + collectImageRefs(carrier.content, refs); + if (carrier.message !== void 0) collectImageRefs(carrier.message.content, refs); + if (carrier.inserted !== void 0) for (const message of carrier.inserted) collectImageRefs(message.content, refs); + if (carrier.chunk?.type === "block-end") collectImageRefs([carrier.chunk.block], refs); +} +/** +* Collect the distinct media references one stored artifact text names. +* Lines that fail to parse cannot reference media and are skipped (the +* artifact text itself is exported verbatim regardless). +* @param content - the stored artifact text. +* @returns the dedupe map keyed by attachment id. +*/ +function imageRefsInArtifact(content) { + const refs = /* @__PURE__ */ new Map(); + for (const line of content.split("\n")) { + if (line === "") continue; + let event; + try { + event = JSON.parse(line); + } catch { + continue; + } + collectEventImageRefs(event, refs); + } + return refs; +} +/** +* One safe zip path segment from an untrusted session id. Session ids are +* host-controlled, but the brand allows any non-empty string, so `../`, dot +* segments, and separator characters are neutralized before they can shape +* archive entries. Distinct ids may collapse onto one segment (id collision +* is impossible for the host-minted UUIDs, so no uniqueness suffix is kept). +* @param id - the raw session id. +* @returns a filesystem-safe single path segment. +*/ +function safeSessionIdSegment(id) { + return id.replace(/[^A-Za-z0-9_-]/g, "_"); +} +/** +* The export archive filename for one root session. +* @param sessionId - the root session id (sanitized to one safe path segment). +* @returns the attachment filename for the session's export archive. +*/ +function sessionLogZipFilename(sessionId) { + return `dsh-session-${safeSessionIdSegment(sessionId)}.zip`; +} +/** +* Yield the export entries in zip order: the preloaded root artifact first, +* then every subagent descendant in lineage order (each flushed when live, +* read from the persistence backend right before it is yielded, and dropped +* after the consumer moves on), then every distinct media object referenced by any of +* the included logs (read and verified from the attachment store, one archive +* entry per attachment id). The host holds at most one descendant's artifact +* text and one media object at a time beyond the root. +* @param deps - the mounted export services (the caller answered 500 before this runs). +* @param root - the already-read root artifact (read by the caller so the +* missing-session path can answer cleanly before streaming starts). +* @param sessionId - the root session id. +* @param includeDescendants - whether to include every subagent descendant. +* @param signal - optional cancellation forwarded to lineage, persistence, and attachment reads. +* @returns the export entries in zip order. +*/ +async function* sessionLogZipEntries(deps, root, sessionId, includeDescendants, signal) { + const media = /* @__PURE__ */ new Map(); + const rememberMedia = (content) => { + for (const [id, ref] of imageRefsInArtifact(content)) media.set(id, ref); + }; + rememberMedia(root.content); + yield { + path: root.filename, + content: root.content + }; + if (includeDescendants) { + const seen = new Set([sessionId]); + const collect = async function* (nodes) { + for (const node of nodes) { + signal?.throwIfAborted(); + const id = node.session.header.id; + if (seen.has(id)) continue; + seen.add(id); + await flushLiveSessionLog(deps, id, signal); + const raw = await deps.sessionPersistence.readRaw(id, signal); + signal?.throwIfAborted(); + if (raw === void 0) throw new Error(`subagent "${id}" has no stored log artifact`); + rememberMedia(raw.content); + yield { + path: `subagents/${safeSessionIdSegment(id)}/${raw.filename}`, + content: raw.content + }; + yield* collect(node.descendants); + } + }; + const lineage = await deps.sessionQuery.traceSession(sessionId, signal); + signal?.throwIfAborted(); + yield* collect(lineage.descendants); + } + for (const ref of media.values()) { + signal?.throwIfAborted(); + const stored = await deps.attachments.readImage(ref, signal); + signal?.throwIfAborted(); + yield { + path: mediaEntryPath(ref), + data: stored.data + }; + } +} +/** How many code units of artifact text one zip push carries (bounded encode memory). */ +const PUSH_CHUNK_CODE_UNITS = 65536; +/** How many bytes of media one zip push carries (bounded memory; images are already size-capped). */ +const PUSH_CHUNK_BYTES = 65536; +/** Byte capacity retained by the response stream before ZIP production waits for pull. */ +const RESPONSE_HIGH_WATER_MARK_BYTES = 65536; +/** One producer waiter released only when ReadableStream pull restores capacity. */ +var ResponseCapacityGate = class { + releasePending; + /** + * Wait until the response queue has positive byte capacity or cancellation wins. + * @param controller - response controller whose desired size owns capacity. + * @param signal - combined request/consumer cancellation. + */ + async wait(controller, signal) { + signal.throwIfAborted(); + if (controller.desiredSize === null || controller.desiredSize > 0) return; + await new Promise((resolve) => { + const release = () => { + this.releasePending = void 0; + signal.removeEventListener("abort", release); + resolve(); + }; + this.releasePending = release; + signal.addEventListener("abort", release, { once: true }); + }); + signal.throwIfAborted(); + } + /** Release the current producer waiter after a consumer pull. */ + pulled() { + this.releasePending?.(); + } +}; +/** +* Push one media object's bytes into a deflate stream in bounded chunks, +* waiting for consumer capacity between chunks like the artifact path does. +* @param deflate - the zip entry's deflate stream. +* @param data - the stored image bytes. +* @param controller - response queue controller. +* @param capacity - pull-driven response-capacity gate. +* @param signal - cancellation; throws when aborted. +*/ +async function pushBinaryChunks(deflate, data, controller, capacity, signal) { + let offset = 0; + do { + signal.throwIfAborted(); + const end = Math.min(offset + PUSH_CHUNK_BYTES, data.byteLength); + const finalChunk = end >= data.byteLength; + deflate.push(data.subarray(offset, end), finalChunk); + offset = end; + await capacity.wait(controller, signal); + } while (offset < data.byteLength); +} +/** +* Push one artifact's text into a deflate stream in bounded chunks, never +* splitting a surrogate pair across a chunk boundary (a lone high surrogate +* re-encodes as U+FFFD and would silently corrupt the exported artifact). +* @param deflate - the zip entry's deflate stream. +* @param content - the artifact text verbatim. +* @param controller - response queue controller. +* @param capacity - pull-driven response-capacity gate. +* @param signal - cancellation; throws when aborted. +*/ +async function pushArtifactChunks(deflate, content, controller, capacity, signal) { + const encoder = new TextEncoder(); + let offset = 0; + let finalChunk; + do { + signal.throwIfAborted(); + let end = Math.min(offset + PUSH_CHUNK_CODE_UNITS, content.length); + if (end < content.length && end - offset > 1) { + const last = content.charCodeAt(end - 1); + if (last >= 55296 && last <= 56319) end -= 1; + } + finalChunk = end >= content.length; + deflate.push(encoder.encode(content.slice(offset, end)), finalChunk); + offset = end; + await capacity.wait(controller, signal); + } while (!finalChunk); +} +/** +* Stream one session-log ZIP as a WHATWG ReadableStream. The root artifact is +* read and validated by the caller before this is called (missing root or +* missing services answer cleanly before any byte is produced); each entry is +* then encoded and deflated in bounded chunks as it is produced, so the +* archive bytes arrive incrementally. A descendant that fails to read errors +* the stream (fail-loud, never silent under-export). +* @param deps - the mounted export services (the caller answered 500 before this runs). +* @param root - the already-read root artifact (first zip entry). +* @param sessionId - the root session id. +* @param includeDescendants - whether to include every subagent descendant. +* @param compressionLevel - validated fflate DEFLATE level for every ZIP entry. +* @param signal - request cancellation combined with response-consumer cancellation. +* @returns the zip byte stream. +*/ +function streamSessionLogZip(deps, root, sessionId, includeDescendants, compressionLevel, signal) { + const consumerAbort = new AbortController(); + const producerSignal = AbortSignal.any([signal, consumerAbort.signal]); + let zip; + let zipTerminated = false; + const capacity = new ResponseCapacityGate(); + const terminateZip = () => { + if (zip === void 0 || zipTerminated) return; + zipTerminated = true; + zip.terminate(); + }; + return new ReadableStream({ + start(controller) { + const archive = new Zip((error, data, final) => { + /* v8 ignore next 3 -- fflate reports only internal zip failures, unreachable for valid inputs */ + if (error) { + controller.error(error); + return; + } + /* v8 ignore next -- fflate may emit empty chunks; not controllable from tests */ + if (data.byteLength > 0) controller.enqueue(data); + if (final) controller.close(); + }); + zip = archive; + (async () => { + try { + for await (const entry of sessionLogZipEntries(deps, root, sessionId, includeDescendants, producerSignal)) { + const deflate = new ZipDeflate(entry.path, { level: compressionLevel }); + archive.add(deflate); + if ("content" in entry) await pushArtifactChunks(deflate, entry.content, controller, capacity, producerSignal); + else await pushBinaryChunks(deflate, entry.data, controller, capacity, producerSignal); + } + archive.end(); + } catch (error) { + /* v8 ignore next -- typed backends reject with Error, and DOMException is one in Node */ + terminateZip(); + controller.error(error instanceof Error ? error : new Error(String(error))); + } + })(); + }, + pull() { + capacity.pulled(); + }, + cancel(reason) { + consumerAbort.abort(reason instanceof Error ? reason : /* @__PURE__ */ new Error("session log export stream cancelled")); + terminateZip(); + } + }, { + highWaterMark: RESPONSE_HIGH_WATER_MARK_BYTES, + size: (chunk) => chunk.byteLength + }); +} +//#endregion +//#region lib/types/api/session-search.js +/** +* Return the longest prefix containing at most `maximum` Unicode code points. +* @param value - text to bound. +* @param maximum - non-negative code-point limit. +* @returns `value` unchanged when it fits, otherwise a code-point-safe prefix. +*/ +function truncateUnicodeCodePoints(value, maximum) { + let count = 0; + let end = 0; + for (const codePoint of value) { + if (count === maximum) return value.slice(0, end); + count++; + end += codePoint.length; + } + return value; +} +//#endregion +//#region lib/types/api/sessions.schema.js +/** +* sessions domain zod schemas (names derived from map keys: sessionListRequestSchema / +* sessionListValueSchema). SessionEvent passthrough = strict envelope (type/seq/time) + wide +* data: the merge-extensible event API keeps an unknown-type branch at the union level, +* with no field-level passthrough. SessionId brand cast point: sessionIdSchema, and only there. +*/ +/** SessionId: one brand cast after schema validation (the only cast point in this domain). */ +const sessionIdSchema = z$1.string().min(1); +/** MessageId: one brand cast after non-empty string validation. */ +const messageIdSchema$1 = z$1.string().min(1); +/** +* WorkspaceId: the workspace domain's one brand cast. Hosted here rather +* than in workspace.schema because session.create references it while +* workspace.schema references sessionIdSchema — schema modules must stay a +* DAG (both casts used at module top level; a cycle is a load-time TDZ). +*/ +const workspaceIdSchema = z$1.string().min(1); +/** SessionEvent passthrough: strict envelope, wide data (the client fold handles unknown types via its documented default). */ +const sessionEventSchema = z$1.object({ + type: z$1.string(), + seq: z$1.number().int().nonnegative(), + time: z$1.number(), + data: z$1.unknown(), + sourceEventSeqs: z$1.array(z$1.number()).optional(), + surfaceOp: z$1.unknown().optional(), + ignorable: z$1.literal(true).optional() +}); +/** SessionSummary row of session.list (`projections` reuses the history block's shape and schema). */ +const sessionSummarySchema = z$1.object({ + sessionId: sessionIdSchema, + updatedAt: z$1.number(), + running: z$1.boolean(), + blank: z$1.boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: z$1.literal("subagent").optional(), + cwd: z$1.string().optional(), + agentPreset: z$1.string().optional(), + projections: z$1.lazy(() => sessionProjectionsBlockSchema).optional() +}); +/** session.list request payload (cursor is a reserved seat, unimplemented in v1). */ +const sessionListRequestSchema = z$1.object({ cursor: z$1.string().optional() }); +/** session.list response value. */ +const sessionListValueSchema = z$1.object({ items: z$1.array(sessionSummarySchema) }); +/** session.search request payload. */ +const sessionSearchRequestSchema = z$1.object({ query: z$1.string().trim().min(1).max(500).refine((query) => !query.includes("\0"), { message: "search query must not contain NUL" }) }); +/** One session.search result. */ +const sessionSearchItemSchema = z$1.object({ + sessionId: sessionIdSchema, + snippet: z$1.string().refine((snippet) => truncateUnicodeCodePoints(snippet, 240) === snippet, { message: `search snippet must contain at most 240 Unicode code points` }) +}); +/** session.search response value. */ +const sessionSearchValueSchema = z$1.object({ + items: z$1.array(sessionSearchItemSchema).max(20), + hasMore: z$1.boolean() +}); +/** session.create request payload (at most one of workspaceId / cwd). */ +const sessionCreateRequestSchema = z$1.object({ + workspaceId: workspaceIdSchema.optional(), + cwd: z$1.string().optional(), + sessionId: sessionIdSchema.optional(), + agentPreset: z$1.string().optional() +}).refine((payload) => payload.workspaceId === void 0 || payload.cwd === void 0, { message: "session.create accepts workspaceId or cwd, not both" }); +/** session.create response value. */ +const sessionCreateValueSchema = z$1.object({ + sessionId: sessionIdSchema, + agentPreset: z$1.string().optional() +}); +/** session.rename request payload (raw title; host-side normalization decides acceptance). */ +const sessionRenameRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + title: z$1.string() +}); +/** session.rename response value (the normalized accepted title and its event seq). */ +const sessionRenameValueSchema = z$1.object({ + title: z$1.string().min(1), + seq: z$1.number().int().nonnegative() +}); +/** session.fork request payload (atSeq anchors the completed-turn cut). */ +const sessionForkRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + atSeq: z$1.number().int().nonnegative().optional() +}); +/** session.fork response value (the child session id). */ +const sessionForkValueSchema = z$1.object({ sessionId: sessionIdSchema }); +/** session.history request payload (beforeSeq/maxMessages page backwards from the window tail). */ +const sessionHistoryRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + beforeSeq: z$1.number().int().nonnegative().optional(), + maxMessages: z$1.number().int().positive().optional() +}); +/** Complete provider/model selection. */ +const modelSelectionSchema = z$1.object({ + provider: z$1.string().min(1), + model: z$1.string().min(1), + reasoningEffort: z$1.string().min(1).optional() +}); +/** One adapter-owned reasoning effort. */ +const modelReasoningEffortSchema = z$1.object({ + id: z$1.string().min(1), + name: z$1.string().min(1), + description: z$1.string().optional() +}); +/** Exact-model reasoning metadata. */ +const modelReasoningSchema = z$1.object({ + efforts: z$1.array(modelReasoningEffortSchema).min(1), + defaultEffort: z$1.string().min(1).optional() +}); +/** One advisory model entry inside a provider group. */ +const modelCatalogModelSchema = z$1.object({ + id: z$1.string().min(1), + name: z$1.string().min(1), + description: z$1.string().optional(), + reasoning: modelReasoningSchema.optional() +}); +/** One successfully loaded provider group. */ +const modelProviderGroupSchema = z$1.object({ + id: z$1.string().min(1), + name: z$1.string().min(1), + models: z$1.array(modelCatalogModelSchema) +}); +/** One provider-local catalog failure. */ +const modelCatalogFailureSchema = z$1.object({ + id: z$1.string().min(1), + name: z$1.string().min(1), + message: z$1.string() +}); +/** +* ToolEventView passthrough: lock only the `for` discriminant and the presence +* of a card-tagged `view` object. The view interior is a host-computed product +* the client reads without echoing back; deep-validating it would hand-copy +* the dsh-tools vocabulary into this schema and drift with it. +*/ +const toolEventViewSchema = z$1.discriminatedUnion("for", [z$1.object({ + for: z$1.literal("call"), + view: z$1.looseObject({ card: z$1.string() }) +}), z$1.object({ + for: z$1.literal("result"), + view: z$1.looseObject({ card: z$1.string() }) +})]); +/** One session.history item: the session event plus its optional host-computed tool view. */ +const historyEntrySchema = z$1.object({ + event: sessionEventSchema, + view: toolEventViewSchema.optional() +}); +/** +* Projection baseline passthrough: `values` stays a wide record — each value +* was already parsed by its provider's own schema on the host side, and +* deep-validating here would import every domain's schema into the carrier. +*/ +const sessionProjectionsBlockSchema = z$1.object({ + asOfSeq: z$1.number().int().min(-1), + values: z$1.record(z$1.string(), z$1.unknown()) +}); +/** Host-side validation for the persisted Session-list projection. */ +const sessionListMetadataProjectionSchema = z$1.object({ + blank: z$1.boolean(), + lastPromptAt: z$1.number().nullable() +}); +/** +* imageLimits projection unit schema (host-side view validation). zod widens +* `readonly ImageMediaType[]` to `string[]`; on the JSON wire the two +* serialize identically, so the cast records exactly that widening. +*/ +const imageLimitsProjectionSchema = z$1.object({ + maxImageBytes: z$1.number().int().positive(), + maxImagesPerMessage: z$1.number().int().positive(), + maxMessageImageBytes: z$1.number().int().positive(), + maxImagePixels: z$1.number().int().positive(), + mediaTypes: z$1.array(z$1.string()) +}); +/** session.history response value (projections rides the tail page only). */ +const sessionHistoryValueSchema = z$1.object({ + events: z$1.array(historyEntrySchema), + hasMore: z$1.boolean(), + projections: sessionProjectionsBlockSchema.optional() +}); +/** session.models request payload. */ +const sessionModelsRequestSchema = z$1.object({ sessionId: sessionIdSchema }); +/** session.models response value. */ +const sessionModelsValueSchema = z$1.object({ + current: modelSelectionSchema, + routable: z$1.boolean(), + groups: z$1.array(modelProviderGroupSchema), + failures: z$1.array(modelCatalogFailureSchema) +}); +/** session.selectModel request payload. */ +const sessionSelectModelRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + provider: z$1.string().min(1), + model: z$1.string().min(1), + reasoningEffort: z$1.string().min(1).optional() +}); +/** session.selectModel response value. */ +const sessionSelectModelValueSchema = z$1.object({ selected: modelSelectionSchema }); +/** ContentBlock passthrough: core is merge-extensible — the type discriminant envelope is strict, the rest stays wide. */ +const contentBlockSchema = z$1.looseObject({ type: z$1.string() }); +/** Raster image media types accepted by the version-one browser wire. */ +const imageMediaTypeSchema = z$1.union([ + z$1.literal("image/png"), + z$1.literal("image/jpeg"), + z$1.literal("image/webp"), + z$1.literal("image/gif") +]); +/** Prompt wire content is intentionally narrower than merge-extensible durable core content. */ +const promptContentPartSchema = z$1.discriminatedUnion("type", [z$1.object({ + type: z$1.literal("text"), + text: z$1.string() +}), z$1.object({ + type: z$1.literal("image"), + mediaType: imageMediaTypeSchema, + data: z$1.string(), + name: z$1.string().optional() +})]); +/** session.prompt request payload, including optional browser-local request provenance. */ +const sessionPromptRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + mode: z$1.union([z$1.literal("queue"), z$1.literal("steer")]), + content: z$1.array(promptContentPartSchema), + clientTimeZone: z$1.string().optional() +}); +/** session.prompt response value (the command slot appears only when the prompt dispatched a slash command). */ +const sessionPromptValueSchema = z$1.object({ + accepted: z$1.literal(true), + command: z$1.object({ + kind: z$1.literal("success"), + text: z$1.string().optional() + }).optional() +}); +/** Opaque attachment id after string-shape validation. */ +const attachmentIdSchema = z$1.string().min(1); +/** Durable image reference returned from the authenticated session lookup. */ +const imageAttachmentRefSchema = z$1.object({ + attachmentId: attachmentIdSchema, + mediaType: imageMediaTypeSchema, + bytes: z$1.number().int().positive(), + width: z$1.number().int().positive(), + height: z$1.number().int().positive(), + name: z$1.string().optional() +}); +/** session.attachment request payload. */ +const sessionAttachmentRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + attachmentId: attachmentIdSchema +}); +/** session.attachment response value. */ +const sessionAttachmentValueSchema = z$1.object({ + attachment: imageAttachmentRefSchema, + data: z$1.string() +}); +/** session.updateQueue request payload. */ +const sessionUpdateQueueRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + itemId: messageIdSchema$1, + action: z$1.discriminatedUnion("kind", [ + z$1.object({ + kind: z$1.literal("edit"), + content: z$1.array(contentBlockSchema) + }), + z$1.object({ kind: z$1.literal("remove") }), + z$1.object({ kind: z$1.literal("steer") }) + ]) +}); +/** session.updateQueue response value. */ +const sessionUpdateQueueValueSchema = z$1.object({ accepted: z$1.literal(true) }); +/** session.cancel request payload. */ +const sessionCancelRequestSchema = z$1.object({ sessionId: sessionIdSchema }); +/** session.cancel response value. */ +const sessionCancelValueSchema = z$1.object({ accepted: z$1.literal(true) }); +//#endregion +//#region lib/types/api/approvals.schema.js +/** +* approvals domain zod schemas (respond is a client-response; the payload schema serves +* the /api/respond endpoint's second parse after routing via the pending table). +* ApprovalRequestId brand cast point: one. +*/ +/** ApprovalRequestId: one brand cast after schema validation (the only cast point in this domain). */ +const approvalRequestIdSchema = z$1.string().min(1); +/** Approval answer payload (the result.value slot of a client-response). */ +const approvalResponsePayloadSchema = z$1.object({ + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + outcome: z$1.union([z$1.literal("allowed-once"), z$1.literal("rejected")]) +}); +//#endregion +//#region lib/types/api/questions.schema.js +/** +* questions domain zod schemas (respond is a client-response; the payload schema serves +* the /api/respond endpoint's second parse after routing via the pending table). The question +* identifier is the echoed rpcId; the payload carries no resource id. +*/ +/** AskUserQuestionAnswer validated strictly against core dsh-user-questions. */ +const askUserQuestionAnswerSchema = z$1.object({ answers: z$1.array(z$1.object({ + id: z$1.string(), + selected: z$1.array(z$1.string()), + custom: z$1.string().optional() +})) }); +/** Question answer payload (the result.value slot of a client-response). */ +const questionResponsePayloadSchema = z$1.object({ + sessionId: sessionIdSchema, + answer: askUserQuestionAnswerSchema +}); +//#endregion +//#region lib/types/api/rpc.js +/** +* Four-quadrant RPC message model. Channels and messages are decoupled: HTTP, +* WebSocket, and in-process SSE are physical carriers, while logical messages +* are channel-independent and form a four-member discriminated union. +* api/ contract layer: zero Node dependencies, importable from the browser. +*/ +/** +* Brands a string as RpcId (same precedent as core `SessionId()`). Minted by the initiator: +* client-request → client mints; server-request → host mints (answerable frames get a stable +* logical id, pure pushes mint a fresh one each time). +* @param id - Raw id string (implementations mint UUIDs; tests may pass fixtures). +* @returns The same string, branded (compile-time cast, zero runtime cost). +*/ +function RpcId(id) { + return id; +} +//#endregion +//#region lib/types/native-path-opener.js +/** +* Cross-platform native path and text-document openers used by the local GUI +* carrier. +* +* The default intent prefers the default browser for documents it renders when +* the platform can name one, then falls back to the default application. WSL +* translates every path for the Windows desktop instead of assuming a Linux +* GUI. The text-editor intent never consults the browser. +*/ +/** Documents a browser renders, as opposed to ones an editor merely edits. */ +const BROWSER_DOCUMENTS = new Set([ + ".html", + ".htm", + ".xhtml", + ".svg" +]); +/** +* The macOS bundle registered for `https` — the default browser, as +* LaunchServices records it. The nested version dict is stripped first +* because it carries its own `LSHandlerRoleAll`. +*/ +function macBundleForHttps(plist) { + const stripped = plist.replace(/LSHandlerPreferredVersions\s*=\s*\{[^}]*\};/g, ""); + const block = /\{[^{}]*LSHandlerURLScheme\s*=\s*"?https"?;[^{}]*\}/.exec(stripped)?.[0]; + if (block === void 0) return void 0; + return /LSHandlerRoleAll\s*=\s*"?([\w.-]+)"?;/.exec(block)?.[1]; +} +/** +* Open one browser-renderable document with the default browser. +* @returns true when a browser took it; false when this platform cannot name +* one, or naming it failed — the caller then uses the default application. +*/ +async function openInBrowser(path, signal, platform, run, env) { + if (platform === "darwin") { + let bundle; + try { + const { stdout } = await run("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure"], signal); + bundle = macBundleForHttps(stdout); + } catch { + return false; + } + if (bundle === void 0) return false; + await run("open", [ + "-b", + bundle, + path + ], signal); + return true; + } + if (platform === "linux") { + const browser = env.BROWSER; + if (browser === void 0 || browser === "") return false; + await run(browser, [path], signal); + return true; + } + return false; +} +/** PowerShell single-quoted literal (doubles embedded quotes). */ +function powershellLiteral(path) { + return `'${path.replace(/'/g, "''")}'`; +} +/** Whether one environment marker is set to a non-empty value. */ +function present(value) { + return value !== void 0 && value !== ""; +} +/** Distinguish WSL from desktop Linux using its process and kernel markers. */ +function isWsl(internals) { + const env = internals.env ?? process.env; + if (present(env.WSL_DISTRO_NAME) || present(env.WSL_INTEROP)) return true; + return (internals.osRelease ?? release()).toLowerCase().includes("microsoft"); +} +/** Open one Windows-resolvable path through its registered desktop application. */ +async function openWindowsPath(path, signal, run) { + await run("powershell.exe", [ + "-NoProfile", + "-Command", + `Invoke-Item -LiteralPath ${powershellLiteral(path)}` + ], signal); +} +/** Translate a WSL path before handing it to the Windows desktop. */ +async function openWslPath(path, signal, run) { + const translated = await run("wslpath", ["-w", path], signal); + signal.throwIfAborted(); + const windowsPath = translated.stdout.replace(/[\r\n]+$/, ""); + if (windowsPath === "") throw new Error("wslpath returned no Windows path"); + await openWindowsPath(windowsPath, signal, run); +} +/** Dispatch one shell-free platform command for the requested open intent. */ +async function openNativePathWithIntent(path, signal, intent, internals = {}) { + const platform = internals.platform ?? process.platform; + const run = internals.run ?? runNativeCommand; + const env = internals.env ?? process.env; + const wsl = platform === "linux" && isWsl(internals); + if (!wsl && intent === "default" && BROWSER_DOCUMENTS.has(extname(path).toLowerCase()) && await openInBrowser(path, signal, platform, run, env)) return; + if (platform === "darwin") { + await run("open", intent === "text-editor" ? ["-t", path] : [path], signal); + return; + } + if (platform === "win32") { + await openWindowsPath(path, signal, run); + return; + } + if (platform === "linux") { + if (wsl) { + await openWslPath(path, signal, run); + return; + } + await run("xdg-open", [path], signal); + return; + } + throw new Error(`native path opener is unsupported on ${platform}`); +} +/** +* Whether {@link openNativePath} plausibly reaches a desktop on this host. +* +* macOS and Windows always carry a desktop opener; Linux does when it is WSL +* (the Windows desktop takes the path) or a display server is announced. +* A headless or containerised Linux host answers false, which is what lets a +* surface show a path as text instead of offering a button that would spawn +* `xdg-open` into nothing. +* @param internals - platform and environment seam for deterministic tests. +* @returns true when handing a path to the native opener can work at all. +*/ +function canOpenNativePath(internals = {}) { + const platform = internals.platform ?? process.platform; + if (platform === "darwin" || platform === "win32") return true; + if (platform !== "linux") return false; + const env = internals.env ?? process.env; + return isWsl(internals) || present(env.DISPLAY) || present(env.WAYLAND_DISPLAY); +} +/** +* Open a filesystem path with the operating system's default application, or +* with the default browser when the path names a document a browser renders. +* @param path - absolute or host-resolvable path (caller owns resolution). +* @param signal - caller/connection lifetime; abort terminates the native command. +* @param internals - Platform, environment, and runner hooks for deterministic tests. +*/ +function openNativePath(path, signal, internals = {}) { + return openNativePathWithIntent(path, signal, "default", internals); +} +/** +* Open a text document for editing; macOS bypasses the file-type association +* so a YAML association with a browser cannot consume the gesture. +* @param path - absolute or host-resolvable text-document path. +* @param signal - caller/connection lifetime; abort terminates the native command. +* @param internals - Platform and runner hooks for deterministic tests. +*/ +function openNativeTextFile(path, signal, internals = {}) { + return openNativePathWithIntent(path, signal, "text-editor", internals); +} +//#endregion +//#region lib/types/api-proxy.js +/** +* Host-side ApiProxy implementation. Signature discipline: unary takes the +* narrow RpcRequest

and echoes request.rpcId on the RpcResponse. +*/ +/** Page size when history is called without maxMessages. */ +const DEFAULT_MAX_MESSAGES = 50; +/** +* Non-model settings namespaces intentionally served to the Web client. The +* plugin-owned entries (`agent-loop`, `bash`, `web-search-deepseek`) are the +* host-plane sections the plugin configuration page edits; a namespace absent +* here answers `settings-not-exposed` even when its owner registered it, so +* adding a section to that page is a decision made here rather than by the +* registering plugin. Moving that declaration to `settings.register()`, so a +* plugin can expose its own configuration without a change in this package, +* is deferred work. +*/ +const WEB_SETTINGS_NAMESPACES = [ + "agent-loop", + "shell", + "locale", + "permission", + "ui-conversation", + "ui-theme", + "web-search-deepseek" +]; +/** Provider work budget: at most 100 calls and 2,000 inspected hits. */ +const SESSION_SEARCH_PROVIDER_CALL_LIMIT = 100; +/** Bound cold-log stat fan-out and settle each started batch before cancellation returns. */ +const COLD_SUMMARY_BATCH_SIZE = 16; +/** Default maximum artifact size eligible for one cold blankness read. */ +const DEFAULT_COLD_BLANK_PROBE_MAX_BYTES = 1024; +/** Conversation message event types (the pagination counting unit). */ +const MESSAGE_TYPES = new Set(["user/message", "assistant/message"]); +/** Decode the browser payload while rejecting non-canonical base64 forms. */ +function decodeBase64(data) { + const decoded = Buffer.from(data, "base64"); + if (data.length === 0 || decoded.toString("base64") !== data) throw new AttachmentError("Image upload is not canonical base64.", "INVALID_IMAGE_BASE64"); + return new Uint8Array(decoded); +} +/** Validate one prompt as a batch before publishing any durable image object. */ +async function durablePromptContent(ctx, content) { + if (content.every((part) => part.type === "text")) return content.map((part) => ({ + type: "text", + text: part.text + })); + const limits = ctx.attachments.imageLimits; + if (content.filter((part) => part.type === "image").length > limits.maxImagesPerMessage) throw new AttachmentError("Prompt exceeds the configured image-count limit.", "TOO_MANY_IMAGES"); + const prepared = content.map((part) => part.type === "text" ? part : { + part, + data: decodeBase64(part.data) + }); + const images = prepared.filter((part) => "data" in part); + if (images.reduce((sum, image) => sum + image.data.byteLength, 0) > limits.maxMessageImageBytes) throw new AttachmentError("Prompt exceeds the configured aggregate image-byte limit.", "IMAGES_TOO_LARGE"); + for (const image of images) await ctx.attachments.validateImage({ + data: image.data, + mediaType: image.part.mediaType, + ...image.part.name === void 0 ? {} : { name: image.part.name } + }); + const blocks = []; + for (const item of prepared) { + if (!("data" in item)) { + blocks.push({ + type: "text", + text: item.text + }); + continue; + } + const attachment = await ctx.attachments.saveImage({ + data: item.data, + mediaType: item.part.mediaType, + ...item.part.name === void 0 ? {} : { name: item.part.name } + }); + blocks.push({ + type: "image", + attachment + }); + } + return blocks; +} +/** Search durable content for an image reference, including nested tool results. */ +function imageBlockIn(content, match) { + if (!Array.isArray(content)) return void 0; + for (const value of content) { + if (typeof value !== "object" || value === null || Array.isArray(value)) continue; + const block = value; + if (block.type === "image" && typeof block.attachment === "object" && block.attachment !== null) { + const ref = block.attachment; + if (match(ref)) return ref; + } + if (block.type === "tool-result") { + const nested = imageBlockIn(block.content, match); + if (nested !== void 0) return nested; + } + } +} +/** Search every durable event carrier that can own model-visible content. */ +function imageInEvent(event, match) { + const data = event.data; + const direct = imageBlockIn(data.content, match); + if (direct !== void 0) return direct; + if (data.message !== void 0) { + const wrapped = imageBlockIn(data.message.content, match); + if (wrapped !== void 0) return wrapped; + } + if (data.inserted !== void 0) for (const message of data.inserted) { + const inserted = imageBlockIn(message.content, match); + if (inserted !== void 0) return inserted; + } + if (event.type === "assistant/chunk" && data.chunk?.type === "block-end") return imageBlockIn([data.chunk.block], match); +} +/** True when the current model-visible surface contains an image. */ +function messagesHaveImage(messages) { + return messages.some((message) => contentHasImage(message.content)); +} +/** Resolve the first reference matching one opaque id. */ +function referencedImage(events, attachmentId) { + for (const event of events) { + const found = imageInEvent(event, (ref) => String(ref.attachmentId) === attachmentId); + if (found !== void 0) return found; + } +} +/** +* Product settings intentionally exposed beside model-provider namespaces. +* +* The agent-preset namespace carries one field — which preset a session with +* no explicit choice is composed from — and both browser surfaces that offer +* that choice write it through `settings.update`, so it has to cross the +* configuration boundary or the pickers silently fail to persist. +*/ +const PRODUCT_SETTINGS_NAMESPACES = new Set(["ui-onboarding", SETTINGS_NAMESPACE]); +/** Strict browser-zone profile: UTC or an IANA Area/Location-style identifier. */ +const IANA_TIME_ZONE = /^[A-Za-z][A-Za-z0-9_+.-]*(?:\/[A-Za-z0-9_+.-]+)+$/; +/** Validate and canonicalize one browser-supplied IANA zone at the wire boundary. */ +function canonicalClientTimeZone(value) { + if (value.length === 0 || value.trim() !== value || value !== "UTC" && !IANA_TIME_ZONE.test(value)) return void 0; + try { + const canonical = new Intl.DateTimeFormat("en-US", { timeZone: value }).resolvedOptions().timeZone; + /* v8 ignore next -- Intl returns UTC or a canonical IANA Area/Location for accepted input. */ + if (canonical !== "UTC" && !IANA_TIME_ZONE.test(canonical)) return void 0; + return canonical; + } catch { + return; + } +} +/** Read live abort state across awaits without treating it as synchronously immutable. */ +function isAborted(signal) { + return signal.aborted; +} +/** +* Message-boundary pagination: count maxMessages append-origin messages +* backwards from the window tail. Replacement copies never entered the +* conversation a reader sees — they restate a shadowed range for the model +* alone — so they consume no quota; the page stays one contiguous raw range, +* which keeps a compaction's log-only `compaction/summary` record on the same page as its +* replacement. The cut is the starting seq of the oldest message group (chunks +* group via sourceEventSeqs — never cut mid-message). The tail page naturally +* includes the in-progress partial. +*/ +function paginate(events, beforeSeq, maxMessages) { + const window = beforeSeq === void 0 ? [...events] : events.filter((event) => event.seq < beforeSeq); + let count = 0; + let cut = 0; + for (let i = window.length - 1; i >= 0; i--) { + const event = window[i]; + if (!MESSAGE_TYPES.has(event.type) || !isAppendSurfaceEvent(event)) continue; + count++; + const sources = event.sourceEventSeqs; + const groupStart = sources !== void 0 && sources.length > 0 ? Math.min(event.seq, ...sources) : event.seq; + if (count >= maxMessages) { + cut = groupStart; + break; + } + } + return { + events: window.filter((event) => event.seq >= cut), + hasMore: cut > 0 + }; +} +/** Wrap an ok result echoing the request's rpcId. */ +function ok(request, value) { + return { + rpcId: request.rpcId, + result: { + ok: true, + value + } + }; +} +/** +* Build the provider/model catalog over every registered route. Shared by the +* session-scoped `session.models` and host-scoped `llm.models`. Catalog +* membership stays advisory: an unlisted session selection remains valid for +* provider dispatch, but is not injected back into the selector after its +* owning catalog stops advertising it. Per-provider failures ride `failures` +* without failing the sound groups; groups that advertise nothing are dropped. +*/ +async function buildModelCatalog(ctx) { + const catalog = await Promise.all(ctx.llm.listProviders().map(async (provider) => { + try { + const models = await ctx.llm.listModels(provider.id); + const entries = await Promise.all(models.map(async (model) => { + const resolved = await ctx.llm.resolveModelInfo(provider.id, model.id); + const reasoning = resolved.reasoning === void 0 ? void 0 : { + efforts: resolved.reasoning.efforts.map((effort) => ({ + id: effort.id, + name: effort.name, + ...effort.description === void 0 ? {} : { description: effort.description } + })), + ...resolved.reasoning.defaultEffort === void 0 ? {} : { defaultEffort: resolved.reasoning.defaultEffort } + }; + return { + id: model.id, + name: model.name, + ...model.description === void 0 ? {} : { description: model.description }, + ...reasoning === void 0 ? {} : { reasoning } + }; + })); + return { + kind: "group", + group: { + id: provider.id, + name: provider.name, + models: entries + } + }; + } catch (error) { + return { + kind: "failure", + failure: { + id: provider.id, + name: provider.name, + message: error instanceof Error ? error.message : String(error) + } + }; + } + })); + return { + groups: catalog.flatMap((item) => item.kind === "group" ? [item.group] : []).filter((group) => group.models.length > 0), + failures: catalog.flatMap((item) => item.kind === "failure" ? [item.failure] : []) + }; +} +/** Wrap an error result echoing the request's rpcId. */ +function err(request, error) { + return { + rpcId: request.rpcId, + result: { + ok: false, + error + } + }; +} +/** +* The RPC refusal a preset failure becomes, or undefined when the failure is +* about something else. +* +* Both the session-create path and the switch path can be handed the same two +* failures, and a client that has to branch on the code needs them worded the +* same from either. +* @param request - the request being answered. +* @param error - the thrown value. +* @returns the refusal, or undefined when the caller should keep handling. +*/ +function presetFailure(request, error) { + if (error instanceof UnknownPresetError) return err(request, { + code: "agent-preset-not-found", + message: error.message, + details: { + agentPreset: error.presetId, + available: [...error.available] + } + }); + if (error instanceof PresetMountError) return err(request, { + code: "agent-preset-invalid", + message: error.message, + details: { + agentPreset: error.presetId, + reason: error.reason + } + }); +} +/** Simple async queue: core callbacks push, the AsyncIterable pulls; abort/return cleans up. */ +var FrameQueue = class { + buffer = []; + waiter; + done = false; + push(item) { + if (this.done) return; + this.buffer.push(item); + this.waiter?.(); + } + end() { + this.done = true; + this.waiter?.(); + } + async *iterate(signal, cleanup) { + const onAbort = () => { + this.end(); + }; + signal.addEventListener("abort", onAbort, { once: true }); + try { + while (true) { + while (this.buffer.length > 0) yield this.buffer.shift(); + if (this.done || signal.aborted) return; + await new Promise((resolve) => { + this.waiter = resolve; + }); + this.waiter = void 0; + } + } finally { + signal.removeEventListener("abort", onAbort); + cleanup(); + } + } +}; +/** +* Server-side frame mint: pure pushes get a fresh rpcId per frame (answerable +* frames — approval/question requested — mint their stable id in their +* pending registries instead). +*/ +function frame(payload) { + return { + rpcId: RpcId(randomUUID()), + payload + }; +} +/** +* Narrow one allowlisted host event's argument list to the JSON values the +* wrapper frame carries. A rejected argument is an allowlist mistake (the +* forwarded path applies no projection), not hostile input, so it throws rather +* than degrading to a lossy frame. The throw surfaces where the forwarding +* listener runs, so the emitter's own listener containment logs it and drops +* that frame — loud in the Host log, not at load or at the emit. Exported for +* the test that owns this decision: every currently allowlisted event has a +* statically JSON-safe payload, so a type-legal `ctx.emit` cannot reach the +* rejection branch. +* @param event - forwarded host event name, named in the failure. +* @param args - the emitter's argument list. +* @returns the same arguments typed as JSON values. +*/ +function assertJsonArgs(event, args) { + for (const [index, arg] of args.entries()) if (!isJsonValue(arg)) throw new Error(`forwarded host event "${event}" argument ${index} is not lossless JSON data`); + return args; +} +/** Queue the subscription baseline frame. */ +function subscribeSession(queue, session) { + queue.push(frame({ + type: "session/subscribed", + sessionId: session.id, + lastSeq: session.seq - 1 + })); +} +/** +* Project registry snapshots onto the wire view, dropping the three internal +* fields {@link JobView} documents as absent. +*/ +function jobViews(snapshots) { + return snapshots.map((job) => ({ + id: job.id, + kind: job.kind, + label: job.label, + status: job.status, + ...job.detail === void 0 ? {} : { detail: job.detail }, + startedAt: job.startedAt, + ...job.finishedAt === void 0 ? {} : { finishedAt: job.finishedAt } + })); +} +/** +* Whether the session's conversation has started: no turn has run yet (a +* turn is one model-loop execution). Standalone plugin events — command +* lifecycle records, plan/mode, titles, goals — never open a turn, so +* running `/plan` or `/goal` on a fresh session keeps it blank +* (list-hidden, reusable). +*/ +function sessionBlank(session) { + return !session.events.some((event) => event.type === "turn/start"); +} +/** Advance the Session-list hint projection by one committed event. */ +function applySessionListMetadata(state, event) { + const blank = state.blank && event.type !== "turn/start"; + const lastPromptAt = event.type === "user/message" && event.data.source.kind === "user" ? event.time : state.lastPromptAt; + return blank === state.blank && lastPromptAt === state.lastPromptAt ? state : { + blank, + lastPromptAt + }; +} +/** Fold exact list metadata for an attached Session. */ +function sessionListMetadata(events) { + let state = { + blank: true, + lastPromptAt: null + }; + for (const event of events) state = applySessionListMetadata(state, event); + return state; +} +/** Sort by creation or latest human prompt, whichever is newer. */ +function sessionListUpdatedAt(header, metadata) { + return Math.max(header.createdAt, metadata?.lastPromptAt ?? 0); +} +/** Shared Session-header projection for list baselines and creation frames. */ +function sessionListFields(header, events = []) { + const agentPreset = resolveSessionPreset({ + header, + events + }); + return { + ...header.parentSession === void 0 ? {} : { parentSessionId: header.parentSession }, + ...header.origin === void 0 ? {} : { origin: header.origin }, + ...header.cwd === void 0 ? {} : { cwd: header.cwd }, + ...agentPreset === void 0 ? {} : { agentPreset } + }; +} +/** SessionSummary projection for attached (in-memory) sessions. */ +function summarize(session, running) { + const metadata = sessionListMetadata(session.events); + return { + sessionId: session.id, + updatedAt: sessionListUpdatedAt(session.header, metadata), + running, + blank: metadata.blank, + ...sessionListFields(session.header, session.events) + }; +} +/** +* Verify a possibly blank cold Session only when its physical artifact passes +* the configured per-Session size check. A stale `blank: true`, an +* absent cache row, a large or location-less artifact, and read failures all +* resolve to visible (`false`); listing must never hide a conversation on a +* cache hint or an unavailable optimization. +*/ +async function probeColdSessionMetadata(ctx, persistence, meta, maxBytes, signal) { + if (maxBytes === 0) return void 0; + signal?.throwIfAborted(); + const location = persistence.locate(meta); + if (location === void 0) return void 0; + signal?.throwIfAborted(); + let size; + try { + size = (await stat(location.path)).size; + } catch { + signal?.throwIfAborted(); + return; + } + if (size > maxBytes) return void 0; + try { + const { events } = await persistence.readFrom(meta.id, 0, signal); + signal?.throwIfAborted(); + return sessionListMetadata(events); + } catch (error) { + signal?.throwIfAborted(); + ctx.logger.warn(`session.list: blank probe for "${meta.id}" failed (serving it as visible): ${String(error)}`); + return; + } +} +/** SessionSummary projection for a cold persisted Session. */ +async function summarizeCold(ctx, persistence, meta, metadata, blankProbeMaxBytes, signal) { + const probed = metadata?.blank === false ? void 0 : await probeColdSessionMetadata(ctx, persistence, meta, blankProbeMaxBytes, signal); + return { + sessionId: meta.id, + updatedAt: sessionListUpdatedAt(meta, probed ?? metadata), + running: false, + blank: metadata?.blank === false ? false : probed?.blank ?? false, + ...sessionListFields(meta) + }; +} +/** Map a browse-primitive failure onto the wire error vocabulary (unknown throws stay internal). */ +function directoryError(error) { + if (error instanceof DirectoryPickerError) return { + code: error.code, + message: error.message, + details: { path: error.path } + }; + return { + code: "internal", + message: error instanceof Error ? error.message : String(error), + details: {} + }; +} +/** Project a pending entry into its answerable mux frame (initial push and mux-open replay share it). */ +function requestedFrame(pending) { + return { + rpcId: pending.rpcId, + payload: { + type: "approval/requested", + sessionId: pending.sessionId, + approvalId: pending.approvalId, + toolName: pending.toolName, + ...pending.callId === void 0 ? {} : { callId: pending.callId }, + ...pending.reason === void 0 ? {} : { reason: pending.reason } + } + }; +} +/** Validate one answer batch against the exact question request it resolves. */ +function matchesQuestions(payload, pending) { + if (payload.sessionId !== pending.sessionId) return false; + const answers = payload.answer.answers; + if (answers.length !== pending.questions.length) return false; + return answers.every((answer, index) => { + const question = pending.questions[index]; + if (answer.id !== question.id) return false; + if (new Set(answer.selected).size !== answer.selected.length) return false; + const custom = answer.custom?.trim(); + if (custom !== void 0 && custom === "") return false; + if (question.multiSelect !== true) { + if (custom !== void 0 && answer.selected.length > 0) return false; + if (answer.selected.length > 1) return false; + } + const labels = new Set(question.options?.map((option) => option.label) ?? []); + return answer.selected.every((label) => labels.has(label)); + }); +} +/** +* Compute the render intent for a tool/call or tool/result event through the +* presenters registered at this moment; every other event type gets none. A +* result's presenter needs its call's parsed args — `argsFor` supplies them +* (live: the per-session call table; history: an in-page backscan), returning +* undefined when the pairing is unavailable (e.g. the call fell off the page), +* which soft-falls to no view. Presenter or JSON.parse throws also soft-fall: +* the client's documented default (generic JSON card) covers every miss. +*/ +function viewFor(ctx, event, argsFor, scope) { + try { + if (event.type === "tool/call") { + const { name, arguments: raw } = event.data; + const view = ctx.tools.get(name, scope)?.presentCall?.(JSON.parse(raw)); + return view === void 0 ? void 0 : { + for: "call", + view + }; + } + if (event.type === "tool/result") { + const { message, meta } = event.data; + const [result] = message.content; + const callId = message.source.callId; + const call = argsFor(callId); + if (call === void 0) return void 0; + const view = ctx.tools.get(call.name, scope)?.presentResult?.(call.args, { + content: result.content, + isError: result.isError === true, + ...meta === void 0 ? {} : { meta } + }); + return view === void 0 ? void 0 : { + for: "result", + view + }; + } + } catch (error) { + console.error(`api-proxy: presenter failed for ${event.type}, falling back to generic: ${String(error)}`); + } +} +/** +* Resolve a tool/result's call pairing by scanning a window of events backwards +* for the matching tool/call. Used by the history path (the page is the +* window — a cross-page pairing soft-falls to no view) and by live-path table +* misses after a reconnect-eviction. +*/ +function backscanArgs(events, callId) { + for (let i = events.length - 1; i >= 0; i--) { + const event = events[i]; + if (event.type !== "tool/call") continue; + const data = event.data; + if (data.callId !== callId) continue; + try { + return { + name: data.name, + args: JSON.parse(data.arguments) + }; + } catch { + return; + } + } +} +/** Render one detached history page through the same presenter path as ordinary history. */ +function historyPage(ctx, events, beforeSeq, maxMessages, scope) { + const page = paginate(events, beforeSeq, maxMessages ?? DEFAULT_MAX_MESSAGES); + return { + events: page.events.map((event) => { + const view = viewFor(ctx, event, (callId) => backscanArgs(page.events, callId), scope); + return { + event, + ...view === void 0 ? {} : { view } + }; + }), + hasMore: page.hasMore + }; +} +function projectionsFor(ctx, session) { + const registry = ctx.get("sessionProjections"); + if (registry === void 0) return void 0; + return registry.snapshot(session); +} +/** +* The projection baseline of one session.list row, fail-soft: attached +* sessions cut the registry's live watermark cache; cold sessions view the +* persisted projection cache's identity-checked stored rows (zero log loads +* either way — the listing use case the cache exists for). The block shape +* (values + asOfSeq) matches the history tail's, so a client seeds its +* value store under the same higher-seq-wins rule. Any failure — and an +* empty value set — yields an absent block: a listing without projections +* is degraded, never broken. +*/ +function listProjectionsFor(ctx, meta, session) { + try { + const block = session !== void 0 ? ctx.get("sessionProjections")?.snapshot(session) : ctx.get("sessionProjectionCache")?.cachedSnapshot(meta); + return block !== void 0 && Object.keys(block.values).length > 0 ? block : void 0; + } catch (error) { + ctx.logger.warn(`session.list: projection column for "${meta.id}" failed (serving the row without it): ${String(error)}`); + return; + } +} +/** Projection baseline for a detached history tail without Agent activation. */ +function detachedProjectionsFor(ctx, events) { + const registry = ctx.get("sessionProjections"); + if (registry === void 0) return void 0; + return registry.restore({}, events, 0).snapshot; +} +/** +* Best-effort projections for one subagent history page, fail-soft like +* {@link listProjectionsFor}: a registered unit throwing on a corrupt payload +* never blocks transcript reading — the page is served without the block. +* @param ctx - context carrying the logger for the degradation warning. +* @param childSessionId - the child whose page is being decorated. +* @param compute - the arm-specific fold (live watermark or detached restore). +* @returns the projections block, or undefined when the fold failed. +*/ +function subagentHistoryProjections(ctx, childSessionId, compute) { + try { + return compute(); + } catch (error) { + ctx.logger.warn(`subagent.history: projections for "${childSessionId}" failed (serving the page without them): ${String(error)}`); + return; + } +} +/** Map continuation admission failures without exposing provider details. */ +function subagentPromptError(request, error, signal) { + const childSessionId = request.payload.childSessionId; + if (signal.aborted) return err(request, { + code: "cancelled", + message: "subagent prompt was cancelled", + details: {} + }); + if (error instanceof SubagentError) switch (error.code) { + case "NOT_RESUMABLE": return err(request, { + code: "subagent-not-resumable", + message: "subagent cannot be resumed", + details: { childSessionId } + }); + case "UNAUTHORIZED": return err(request, { + code: "subagent-unauthorized", + message: "subagent does not belong to this parent", + details: { childSessionId } + }); + case "DRAINING": + case "ACTIVATION_CLOSING": + case "CONTINUATION_UNAVAILABLE": + case "PERSISTENCE_UNAVAILABLE": return err(request, { + code: "subagent-delivery-unavailable", + message: "subagent follow-up is temporarily unavailable", + details: { childSessionId } + }); + default: break; + } + return err(request, { + code: "internal", + message: "subagent prompt failed", + details: {} + }); +} +/** Stable RPC face of the missing projections capability, shared by every catalog read path. */ +function projectionsUnavailableError() { + return { + code: "internal", + message: "subagent catalog is unavailable: this deployment does not mount the sessionProjections registry (load @deepseek-ai/dsh-session-projection)", + details: {} + }; +} +/** Verify one address and mode against the complete direct-child catalog. */ +async function catalogChild(ctx, address, signal) { + const { parentSessionId, childSessionId, mode } = address; + try { + const entry = (await ctx.subagents.listChildren(parentSessionId, signal)).find((candidate) => candidate.id === childSessionId); + if (entry === void 0 || entry.kind === "child" && entry.mode !== mode) return { error: { + code: "subagent-not-found", + message: `session "${childSessionId}" is not a ${mode} direct child of "${parentSessionId}"`, + details: { + parentSessionId, + childSessionId + } + } }; + if (entry.kind === "diagnostic") return { error: { + code: "subagent-catalog-diagnostic", + message: `subagent "${childSessionId}" is ${entry.reason}`, + details: { + parentSessionId, + childSessionId, + reason: entry.reason + } + } }; + return { entry }; + } catch (error) { + if (signal?.aborted || error instanceof SubagentError && error.code === "CANCELLED") return { error: { + code: "cancelled", + message: "subagent catalog read was cancelled", + details: {} + } }; + if (error instanceof SubagentError && error.code === "SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE") return { error: projectionsUnavailableError() }; + return { error: { + code: "internal", + message: "subagent catalog read failed", + details: {} + } }; + } +} +/** +* The requested preset differs from the one this session already runs. +* +* A session's composition is fixed at creation: its history was produced under +* that preset's tools, so adopting the identity under a different one would +* replay tool calls the rebuilt agent cannot make. Naming a different preset +* is therefore a caller error rather than a switch. +*/ +/** The roster is absent: this deployment composes no agent presets at all. */ +function noRoster(agentPreset) { + return { + code: "agent-preset-not-found", + message: "this deployment composes no agent presets", + details: { + agentPreset, + available: [] + } + }; +} +/** Map one authoring/roster failure onto its wire code. */ +function presetError(agentPreset, error) { + if (error instanceof UnknownPresetError) return { + code: "agent-preset-not-found", + message: error.message, + details: { + agentPreset: error.presetId, + available: [...error.available] + } + }; + if (error instanceof PresetNotWritableError) return { + code: "agent-preset-read-only", + message: error.message, + details: { + agentPreset, + reason: error.message + } + }; + if (error instanceof InvalidPresetIdError || error instanceof PresetExistsError) return { + code: "agent-preset-invalid", + message: error.message, + details: { + agentPreset, + reason: error.message + } + }; + return { + code: "internal", + message: `agent preset "${agentPreset}": ${String(error)}`, + details: {} + }; +} +var AgentPresetConflict = class extends Error { + sessionId; + requestedPreset; + existingPreset; + constructor(sessionId, requestedPreset, existingPreset) { + super(existingPreset === void 0 ? `session "${sessionId}" records no agent preset, so it cannot be adopted under one; a deployment composing no roster records none on any session — ` : `session "${sessionId}" already runs agent preset ${JSON.stringify(existingPreset)}; requested ${JSON.stringify(requestedPreset)}. A session's preset is fixed at creation.`); + this.sessionId = sessionId; + this.requestedPreset = requestedPreset; + this.existingPreset = existingPreset; + } +}; +/** Requested identity already belongs to a session with another project cwd. */ +var SessionCwdConflict = class extends Error { + sessionId; + requestedCwd; + existingCwd; + constructor(sessionId, requestedCwd, existingCwd) { + super(`session "${sessionId}" already exists with cwd ${JSON.stringify(existingCwd)}; requested ${JSON.stringify(requestedCwd)}`); + this.sessionId = sessionId; + this.requestedCwd = requestedCwd; + this.existingCwd = existingCwd; + } +}; +/** An explicit Host naming operation would duplicate another Workspace title. */ +var WorkspaceNameConflictError = class extends Error { + workspaceName; + constructor(workspaceName) { + super(`workspace name '${workspaceName}' is already in use`); + this.workspaceName = workspaceName; + this.name = "WorkspaceNameConflictError"; + } +}; +/** Shared workspace-not-found error response of the workspace.* mutation rows. */ +function workspaceNotFound(request, workspaceId) { + return err(request, { + code: "workspace-not-found", + message: `workspace "${workspaceId}" not found`, + details: { workspaceId } + }); +} +/** Wire projection of one workspace entity (the workspace.* value row). */ +function workspaceView(workspace) { + return { + workspaceId: workspace.id, + path: workspace.path, + title: workspace.title, + sessionIds: [...workspace.sessionIds], + createdAt: workspace.createdAt, + updatedAt: workspace.updatedAt + }; +} +/** Wire projection of the durable record carried by `domain/changed`. */ +function changedWorkspaceView(workspaceId, value) { + const record = workspaceRecord.parse(value); + return { + workspaceId, + path: record.path, + title: record.title, + sessionIds: [...record.sessionIds], + createdAt: record.createdAt, + updatedAt: record.updatedAt + }; +} +/** +* Implement ApiProxy over a composed host context. +* @param ctx - a context with the Host spine and Workspace registry mounted. +* @param defaults - host routing and project-directory defaults. +* @returns the ApiProxy implementation. +*/ +function createApiProxy(ctx, defaults) { + const sessionExportCompressionLevel = defaults.sessionExportCompressionLevel ?? 6; + const coldBlankProbeMaxBytes = defaults.coldBlankProbeMaxBytes ?? 1024; + /** The seed model each create/resume declares; re-read so it never goes stale. */ + const agentOptions = () => { + const { provider, model } = defaults.defaultModelSelection(); + return { + provider, + model + }; + }; + const selections = /* @__PURE__ */ new WeakMap(); + /** + * Serializes `agentPreset.select` per session. Two concurrent selects both + * pass the blank check, and the second `unmountPresetFor` then finds nothing + * to unmount because the first already removed the record — leaving two + * compositions registered into one agent layer. The client's `busy` flag is + * not enforcement: the wire is reachable directly. + */ + const presetSwitches = /* @__PURE__ */ new Map(); + /** Client-chosen identity creation/resume, deduplicated across concurrent retries. */ + const sessionCreations = /* @__PURE__ */ new Map(); + /** Serializes path ownership and explicit title checks with Workspace mutations. */ + let workspaceCreationChain = Promise.resolve(); + const pendingQuestions = /* @__PURE__ */ new Map(); + const pendingApprovals = /* @__PURE__ */ new Map(); + const muxQueues = /* @__PURE__ */ new Set(); + const imageAdmissionChains = /* @__PURE__ */ new WeakMap(); + /** Serialize image admission with model selection for one agent. */ + function serializeImageAdmission(agent, operation) { + const result = (imageAdmissionChains.get(agent) ?? Promise.resolve()).then(operation); + imageAdmissionChains.set(agent, result.then(() => void 0, () => void 0)); + return result; + } + /** + * Install or return the session-local model selection that prompt assembly snapshots. + * + * Precedence, resolved on EVERY read rather than seeded once: a selection + * made in this process, else the session's own latest logged request/header, + * else the live Agent default. Re-reading keeps the two tiers exact in both + * directions: a session with a recorded request derives its selection from + * its log, while a blank session (New Session reuses one rather than minting + * another) reads any default saved after it was created. There is no create-time + * per-session override tier on this wire — if one returns (a create-options + * contribution), it must fold in between the selection and the log. + */ + function selectionFor(agent) { + const installed = selections.get(agent); + if (installed !== void 0) return installed; + let picked; + const selection = { + get current() { + if (picked !== void 0) return picked; + const logged = agent.session.requestHeader()?.config; + if (logged === void 0) return defaults.defaultModelSelection(); + return { + provider: logged.provider, + model: logged.model, + ...logged.reasoningEffort === void 0 ? {} : { reasoningEffort: logged.reasoningEffort } + }; + }, + set current(next) { + picked = next; + }, + assembled: void 0 + }; + installModelSelection(agent.ctx, selection); + selections.set(agent, selection); + return selection; + } + /** Pre-publication setup used by both fresh and resumed Web agents. */ + function installSelection(agentCtx) { + const agent = agentCtx.agent; + if (agent === void 0) throw new Error("api-proxy: agent setup has no scoped agent"); + selectionFor(agent); + } + /** + * Reject an attempt to run an existing session under a different preset. + * + * A caller that names no preset always adopts the session as it is, so the + * common paths — reconnecting, resuming, retrying a create — are unaffected. + * @param sessionId - the identity being adopted. + * @param requested - the preset the request named, if any. + * @param existing - the preset the session RUNS, if any; both callers resolve + * it from the log, which differs from the creation header once a blank + * session has switched. + * @throws when both are present and differ. + */ + function assertPresetUnchanged(sessionId, requested, existing) { + if (requested === void 0 || requested === existing) return; + throw new AgentPresetConflict(sessionId, requested, existing); + } + /** + * Resolve the preset an agent will be composed from, and the setup that + * installs it. + * + * The id is resolved BEFORE the session exists because the session boundary + * snapshots `meta` before asynchronous setup begins — a preset discovered + * during setup could never reach the header. Mounting still happens in + * setup, where a failure rolls the whole creation back rather than leaving a + * published session whose capabilities are half-installed. + * + * A deployment with no preset roster composes nothing and every session + * shares the host composition, which is the behavior before presets existed. + * @param presetId - the requested preset, or `undefined` for the default. + * @returns the id to record on the header (absent without a roster) and the setup callback. + * @throws when the roster supplies no such preset. + */ + async function composeAgent(presetId) { + const presets = ctx.get("agentPresets"); + if (presets === void 0) return { setup: (agentCtx) => { + installSelection(agentCtx); + return Promise.resolve(); + } }; + const resolvedId = (await presets.resolve(presetId)).id; + return { + agentPreset: resolvedId, + setup: async (agentCtx) => { + installSelection(agentCtx); + await presets.mount(agentCtx, resolvedId); + } + }; + } + const hasSubagentOwner = (session, agent) => hasApiRemoteSubagentOwner(ctx, session, agent); + const subagentOwnershipError = (sessionId) => apiRemoteSubagentOwnershipError(sessionId); + const inspectServable = (sessionId) => inspectApiRemoteSession(ctx, sessionId); + const agentFor = createApiRemoteAgentResolver(ctx, { + agentOptions, + setup: async ({ meta, events }) => (await composeAgent(resolveSessionPreset({ + header: meta, + events + }))).setup + }); + /** Send one transient frame to every connected mux consumer. */ + function broadcast(payload) { + const envelope = frame(payload); + for (const queue of muxQueues) queue.push(envelope); + } + ctx.inject(["sessionProjections"], (projectionCtx) => { + projectionCtx.sessionProjections.onChanged((session, key, value, seq) => { + broadcast({ + type: "session/projection", + sessionId: session.id, + key, + value, + seq + }); + }); + }); + ctx.inject(["sessionProjections"], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: "sessionListMetadata", + schema: sessionListMetadataProjectionSchema, + init: () => ({ + blank: true, + lastPromptAt: null + }), + apply: applySessionListMetadata, + view: (state) => state, + stateVersion: 1 + }); + }); + ctx.inject(["sessionProjections", "attachments"], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: "imageLimits", + schema: imageLimitsProjectionSchema, + init: () => null, + apply: (state) => state, + view: () => projectionCtx.attachments.imageLimits, + stateVersion: 1 + }); + }); + /** Project both durable inbox lists, optionally including the splice currently being emitted. */ + const queueItems = (agent, splice) => { + const project = (target) => { + const messages = target === "next-turn" ? agent.inbox.nextTurn : agent.inbox.nextStep; + return splice?.target === target ? messages.toSpliced(splice.start, splice.removedCount ?? 0, ...splice.inserted) : messages; + }; + return [...project("next-turn").map((message) => ({ + id: message.id, + placement: "queued", + message + })), ...project("next-step").map((message) => ({ + id: message.id, + placement: message.source.kind === "user" ? "steering" : "context", + message + }))]; + }; + ctx.on("session/event", (session, event) => { + if (event.type !== "agent/inbox/spliced") return; + const agent = ctx.agents.get(session.id); + if (agent?.session !== session) return; + broadcast({ + type: "session/queue", + sessionId: session.id, + items: queueItems(agent, event.data) + }); + }); + /** Remove a wait before settling it: synchronous deletion makes the first claimant win. */ + function claimQuestion(pending, outcome) { + pendingQuestions.delete(pending.rpcId); + if (pending.signal !== void 0 && pending.onAbort !== void 0) pending.signal.removeEventListener("abort", pending.onAbort); + broadcast({ + type: "question/resolved", + sessionId: pending.sessionId, + questionRpcId: pending.rpcId, + outcome + }); + } + const disposeProvider = ctx.userQuestions.registerProvider({ ask(request) { + const sessionId = request.agent?.id; + if (sessionId === void 0) return Promise.reject(new UserQuestionError("web user interaction requires an agent-owned session", "ASK_MISSING_AGENT")); + return new Promise((resolve, reject) => { + const rpcId = RpcId(randomUUID()); + const pending = { + rpcId, + sessionId, + questions: request.questions, + resolve, + reject, + ...request.signal === void 0 ? {} : { signal: request.signal } + }; + const onAbort = () => { + claimQuestion(pending, "cancelled"); + reject(new UserQuestionError("ask_user_question was aborted before the user answered", "ASK_ABORTED")); + }; + pending.onAbort = onAbort; + pendingQuestions.set(rpcId, pending); + request.signal?.addEventListener("abort", onAbort, { once: true }); + const envelope = { + rpcId, + payload: { + type: "question/requested", + sessionId, + questions: request.questions + } + }; + for (const queue of muxQueues) queue.push(envelope); + }); + } }); + ctx.effect(() => () => { + disposeProvider(); + for (const pending of [...pendingQuestions.values()]) { + claimQuestion(pending, "cancelled"); + pending.reject(new UserQuestionError("web user-questions provider was disposed", "ASK_ABORTED")); + } + }, "api-proxy: user-questions provider"); + if (ctx.get("approval") !== void 0) { + ctx.effect(() => () => { + for (const pending of [...pendingApprovals.values()]) pending.resolve("cancelled"); + }, "api-proxy: approval registry teardown"); + ctx.on("approval/request", (req, next) => { + if (req.signal?.aborted === true) return Promise.resolve("cancelled"); + const events = req.agent.session.events; + const claimed = /* @__PURE__ */ new Set(); + for (const entry of pendingApprovals.values()) claimed.add(entry.approvalId); + const decided = /* @__PURE__ */ new Set(); + let approvalId; + for (let i = events.length - 1; i >= 0; i -= 1) { + const event = events[i]; + if (event.type === "approval/decided") decided.add(event.data.id); + else if (event.type === "approval/asked") { + if (decided.has(event.data.id) || claimed.has(event.data.id)) continue; + if ((req.callId ?? null) !== (event.data.callId ?? null)) continue; + approvalId = event.data.id; + break; + } + } + if (approvalId === void 0) return next(); + const id = approvalId; + return new Promise((resolve) => { + const settle = (outcome) => { + /* v8 ignore next 3 -- defensive double-settle guard: respond() routes + through the pending table (a settled id is not-pending before it can + re-settle) and the first settle removes the abort listener, so no + reachable path settles twice; kept against future settle callers. */ + if (!pendingApprovals.delete(pending.rpcId)) return; + req.signal?.removeEventListener("abort", onAbort); + broadcast({ + type: "approval/resolved", + sessionId: pending.sessionId, + approvalId: id, + outcome + }); + resolve(outcome); + }; + const onAbort = () => { + settle("cancelled"); + }; + const pending = { + rpcId: RpcId(randomUUID()), + sessionId: req.agent.session.id, + approvalId: id, + toolName: req.toolName, + ...req.callId === void 0 ? {} : { callId: req.callId }, + ...req.reason === void 0 ? {} : { reason: req.reason }, + resolve: settle + }; + pendingApprovals.set(pending.rpcId, pending); + req.signal?.addEventListener("abort", onAbort, { once: true }); + const envelope = requestedFrame(pending); + for (const queue of muxQueues) queue.push(envelope); + }); + }); + } + /** Read one stable session prefix without acquiring an Agent owner. */ + async function readSessionState(sessionId) { + const attached = ctx.sessions.get(sessionId); + if (attached !== void 0) return { + id: attached.id, + header: attached.header, + events: [...attached.events] + }; + const inspected = await inspectServable(sessionId); + return { + id: inspected.meta.id, + header: inspected.meta, + events: inspected.events + }; + } + /** Resolve the Workspace inherited by a fork without making ordinary loose lineage grouped. */ + async function forkWorkspace(source) { + const workspaces = ctx.workspaceRegistry.list(); + const direct = workspaces.find((workspace) => workspace.sessionIds.includes(source.id)); + if (direct !== void 0 || source.header.origin !== "subagent") return direct; + const lineage = await ctx.sessionQuery.traceSession(source.id); + for (const ancestor of lineage.ancestors) { + const workspace = workspaces.find((candidate) => candidate.sessionIds.includes(ancestor.header.id)); + if (workspace !== void 0) return workspace; + } + } + /** + * Resolve which session one transcript read is served from, without + * acquiring an Agent owner. This is the read's only asynchronous step + * besides ensuring the composition; {@link historyCutOf} takes the cut. + * @param sessionId - the transcript being read. + * @returns the attached session, or the inspected detached header and events. + * @throws {@link ApiRemoteSessionNotFound} when no project-backed session has that identity. + */ + async function historySourceFor(sessionId) { + const attached = ctx.sessions.get(sessionId); + if (attached !== void 0) return { + kind: "attached", + session: attached + }; + const inspected = await inspectServable(sessionId); + return { + kind: "detached", + header: inspected.meta, + events: inspected.events + }; + } + /** + * The header and events {@link presenterScopeFor} reads to decide which + * composition a transcript ran under. + * @param source - the live or detached session this read is served from. + * @returns that session's creation header and its events. + */ + function sourceSession(source) { + if (source.kind === "detached") return { + header: source.header, + events: source.events + }; + return { + header: source.session.header, + events: source.session.events + }; + } + /** + * One transcript cut: the events and the projection baseline that describe + * the SAME log position. + * + * Synchronous, and the two reads sit next to each other, because an attached + * session keeps appending: an `await` between them would serve events cut at + * N beside a baseline folded to N+1, which is one response describing two + * moments. The caller does its awaiting before this call. + * @param source - the live or detached session this read is served from. + * @param includeProjections - whether the caller asked for the baseline (a tail page does). + * @returns the events and, when asked, the baseline for that same position. + */ + function historyCutOf(source, includeProjections) { + if (source.kind === "detached") { + const projections = includeProjections ? detachedProjectionsFor(ctx, source.events) : void 0; + return { + events: source.events, + ...projections === void 0 ? {} : { projections } + }; + } + const events = [...source.session.events]; + const projections = includeProjections ? projectionsFor(ctx, source.session) : void 0; + return { + events, + ...projections === void 0 ? {} : { projections } + }; + } + /** + * The registry view scope a transcript's presenters resolve in. + * + * A live agent is that scope itself (its chain passes through its preset's + * standing layer). A cold session resolves its preset from the LOG, and the + * preset's STANDING key serves without resuming anything — ensuring the + * mount composes plugins but starts no agent, session, or turn. No roster, + * no recorded preset, or a preset the roster no longer supplies all fall + * back to the global layer: the transcript still serves, with the generic + * cards a viewless entry renders. + * + * Reading the header alone would render a session that switched while blank + * through the composition it was CREATED with. Every tool only the newer + * preset registers resolves to no presenter there, and the transcript + * silently degrades to generic cards for exactly the calls its history is + * made of. + * @param sessionId - the transcript being read. + * @param session - that session's header and log (attached or inspected). + * @returns the scope to pass to presenter lookups, or undefined for global. + */ + async function presenterScopeFor(sessionId, session) { + const live = ctx.get("agents")?.get(sessionId); + if (live !== void 0) return live; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return void 0; + try { + return await presets.standingKeyFor(resolveSessionPreset(session)); + } catch { + return; + } + } + /** Resolve one requested identity to a live agent, creating or resuming it once. */ + async function ensureSession(sessionId, cwd, checkPersistedIdentity, presetId) { + let creation = sessionCreations.get(sessionId); + if (creation === void 0) { + creation = (async () => { + const attached = ctx.sessions.get(sessionId); + const live = ctx.agents.get(sessionId); + if (attached !== void 0 && hasSubagentOwner(attached, live)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + if (live !== void 0) return live; + const persistence = checkPersistedIdentity ? ctx.get("sessionPersistence") : void 0; + const stored = persistence === void 0 ? void 0 : (await persistence.list()).find((header) => header.id === sessionId); + if (persistence !== void 0 && stored !== void 0) { + const inspected = await persistence.inspect(sessionId); + if (hasSubagentOwner({ header: inspected.meta }, void 0)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + if (inspected.meta.cwd !== cwd) throw new SessionCwdConflict(sessionId, cwd, inspected.meta.cwd); + const storedPreset = resolveSessionPreset({ + header: inspected.meta, + events: inspected.events + }); + assertPresetUnchanged(sessionId, presetId, storedPreset); + return (await ctx.agents.resume({ + resumeSessionId: sessionId, + agentOptions: agentOptions(), + setup: (await composeAgent(storedPreset)).setup + })).agent; + } + try { + await mkdir(cwd, { recursive: true }); + } catch (error) { + throw new Error(`failed to ensure project directory "${cwd}": ${String(error)}`, { cause: error }); + } + const composition = await composeAgent(presetId); + return (await ctx.agents.create({ + sessionId, + agentOptions: agentOptions(), + meta: { + cwd, + ...composition.agentPreset === void 0 ? {} : { agentPreset: composition.agentPreset } + }, + setup: composition.setup + })).agent; + })().catch((error) => { + const live = ctx.agents.get(sessionId); + if (live !== void 0) { + if (hasSubagentOwner(live.session, live)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + return live; + } + const attached = ctx.sessions.get(sessionId); + if (attached !== void 0 && hasSubagentOwner(attached, void 0)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + throw error; + }).finally(() => { + sessionCreations.delete(sessionId); + }); + sessionCreations.set(sessionId, creation); + } + const agent = await creation; + if (hasSubagentOwner(agent.session, agent)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + assertPresetUnchanged(sessionId, presetId, resolveSessionPreset(agent.session)); + if (agent.session.header.cwd !== cwd) throw new SessionCwdConflict(sessionId, cwd, agent.session.header.cwd); + return agent; + } + /** Resolve or create one path while holding the Host's workspace-create chain. */ + function ensureWorkspace(path) { + const operation = workspaceCreationChain.then(async () => { + const existing = await ctx.workspaceRegistry.resolveByPath(path); + if (existing !== void 0) return { + workspace: existing, + created: false + }; + return { + workspace: await ctx.workspaceRegistry.create(path), + created: true + }; + }); + workspaceCreationChain = operation.then(() => void 0, () => void 0); + return operation; + } + /** + * Build the session.list baseline shared by listing and search visibility. + * Attached sessions come from memory; servable cold sessions merge from + * persistence, and the final order is newest-first. + */ + async function listVisibleSessionSummaries(signal) { + signal?.throwIfAborted(); + const summarizeAttached = (session) => { + const agent = ctx.agents.get(session.id); + const projections = listProjectionsFor(ctx, session.header, session); + return { + ...summarize(session, agent?.status === "running"), + ...projections === void 0 ? {} : { projections } + }; + }; + const items = ctx.sessions.list().map(summarizeAttached); + signal?.throwIfAborted(); + const attached = new Set(items.map((item) => item.sessionId)); + const persistence = ctx.get("sessionPersistence"); + if (persistence !== void 0) { + const cold = (await persistence.list(signal)).filter((meta) => !attached.has(meta.id) && meta.cwd !== void 0); + signal?.throwIfAborted(); + for (let offset = 0; offset < cold.length; offset += COLD_SUMMARY_BATCH_SIZE) { + signal?.throwIfAborted(); + const batch = cold.slice(offset, offset + COLD_SUMMARY_BATCH_SIZE); + const settled = await Promise.allSettled(batch.map(async (meta) => { + const projections = listProjectionsFor(ctx, meta, void 0); + const summary = await summarizeCold(ctx, persistence, meta, projections?.values.sessionListMetadata, coldBlankProbeMaxBytes, signal); + const attachedSession = ctx.sessions.get(meta.id); + if (attachedSession !== void 0) return summarizeAttached(attachedSession); + return { + ...summary, + ...projections === void 0 ? {} : { projections } + }; + })); + const summaries = []; + let rejected = false; + let failure; + for (const result of settled) if (result.status === "fulfilled") summaries.push(result.value); + else if (!rejected) { + rejected = true; + failure = result.reason; + } + if (rejected) throw failure; + signal?.throwIfAborted(); + items.push(...summaries); + } + } + items.sort((a, b) => b.updatedAt - a.updatedAt); + return items; + } + /** + * Resolve the goal service THIS agent runs. + * + * The service is per session: an agent preset mounts it behind an `isolate` + * realm, which no host context resolves. Reading it from the root would + * answer "absent" for a session whose composition mounts it — so the lookup + * is keyed by the agent, and only a deployment composing it nowhere is + * genuinely absent. + */ + function goalServiceFor(agent) { + const goals = ctx.get("agentPresets")?.serviceFor(agent, "goals") ?? ctx.get("goals"); + if (goals === void 0) return { error: { + code: "internal", + message: "goal service is absent: neither this session's agent preset nor the host composition mounts @deepseek-ai/dsh-goal", + details: {} + } }; + return goals; + } + /** Map one goal-domain rejection to the wire error (stable GoalError codes ride in details). */ + function goalError(request, error) { + const details = error instanceof GoalError ? { goalCode: error.code } : {}; + return err(request, { + code: "internal", + message: String(error), + details + }); + } + /** Resolve a session's agent, apply one goal mutation, and acknowledge with the new CAS ref. */ + async function mutateGoal(request, mutation) { + const found = await agentFor(request.payload.sessionId); + if ("error" in found) return err(request, found.error); + const goals = goalServiceFor(found.agent); + if ("error" in goals) return err(request, goals.error); + try { + const ref = mutation(goals, found.agent); + return ok(request, { ref: { + id: ref.id, + revision: ref.revision + } }); + } catch (error) { + return goalError(request, error); + } + } + /** + * Whether an adapter currently serves this provider, and therefore whether + * a session selecting it can start a turn. Catalog membership cannot answer + * it: an adapter may serve a model its own catalog stopped advertising, so + * a provider missing from the groups is not the same as one nothing serves. + * A composition with no llm registry at all cannot judge and says yes — + * the dispatch it would have refused fails on its own terms. + */ + function routeServed(provider) { + const llm = ctx.get("llm"); + return llm === void 0 || llm.listProviders().some((entry) => entry.id === provider); + } + /** + * Resolve the addressed agent for a turn-starting method and refuse when no + * adapter serves its current selection: a provider nothing serves cannot start a + * turn, and letting it try spends the whole pre-step path to fail inside + * the adapter with a message about registration. Refusing here names the + * model the session is pointed at while the draft is still in the composer. + * This is `session.prompt`'s enforcement boundary: a client that disables + * its input is an affordance, and the method stays callable regardless. + */ + async function turnAgentFor(request, sessionId) { + const found = await agentFor(sessionId); + if ("error" in found) return { refused: err(request, found.error) }; + const agent = found.agent; + const selection = selectionFor(agent).current; + if (!routeServed(selection.provider)) return { refused: err(request, { + code: "model-unavailable", + message: `no adapter serves provider "${selection.provider}"; select a model for this session`, + details: { + provider: selection.provider, + model: selection.model + } + }) }; + return { agent }; + } + /** Missing-service report shared by the settings domain (skills-domain stance). */ + function settingsAbsent() { + return { + code: "internal", + message: "settings service is absent: this deployment does not mount a settings provider (e.g. @deepseek-ai/dsh-settings-file) in its composition", + details: {} + }; + } + /** Open one Host-resolved target and map native failures onto the wire vocabulary. */ + async function openTarget(request, path, signal, open) { + try { + await open(path, signal); + return ok(request, { opened: true }); + } catch (error) { + if (signal.aborted) return err(request, { + code: "cancelled", + message: "path open was aborted", + details: {} + }); + return err(request, { + code: "internal", + message: `path open failed: ${error instanceof Error ? error.message : String(error)}`, + details: {} + }); + } + } + /** Open one Host-resolved path with its default application. */ + function openPath(request, path, signal) { + return openTarget(request, path, signal, defaults.openPath ?? ((target, openSignal) => openNativePath(target, openSignal))); + } + /** Open one Host-resolved text document in a native editor. */ + function openTextFile(request, path, signal) { + return openTarget(request, path, signal, defaults.openTextFile ?? ((target, openSignal) => openNativeTextFile(target, openSignal))); + } + /** Whether this deployment can hand a path to a native opener at all. */ + function canOpenPaths() { + if (defaults.canOpenPath !== void 0) return defaults.canOpenPath(); + return defaults.openPath !== void 0 || canOpenNativePath(); + } + /** Missing-service report shared by the credentials domain. */ + function credentialsAbsent() { + return { + code: "internal", + message: "credentials service is absent: this deployment does not mount a credential provider (e.g. @deepseek-ai/dsh-credentials-local) in its composition", + details: {} + }; + } + /** Map one redacted settings descriptor to its wire view. */ + function namespaceView(descriptor) { + return { + ns: String(descriptor.ns), + schema: descriptor.schema, + value: descriptor.value, + ...descriptor.base === void 0 ? {} : { base: descriptor.base }, + ...descriptor.user === void 0 ? {} : { user: descriptor.user }, + applies: descriptor.applies, + secrets: (descriptor.secrets ?? []).map((secret) => ({ + path: [...secret.path], + set: secret.set + })), + revision: descriptor.revision + }; + } + /** Settings namespaces whose changes can invalidate the model catalog. */ + function modelProviderNamespaces() { + return new Set(ctx.llm.listConfigurableProviders().map((entry) => entry.settingsNs)); + } + /** + * The settings namespaces this proxy serves: configurable model providers + * plus the small explicit Web preference and product-owned allowlists. The + * settings seam remains general; a future registration does not become + * remotely readable or writable by default. + */ + function exposedNamespaces() { + const exposed = modelProviderNamespaces(); + for (const ns of WEB_SETTINGS_NAMESPACES) exposed.add(ns); + for (const ns of PRODUCT_SETTINGS_NAMESPACES) exposed.add(ns); + return exposed; + } + /** Refuse a namespace outside the explicit configuration-client boundary. */ + function notExposed(request, ns) { + return err(request, { + code: "settings-not-exposed", + message: `settings namespace "${ns}" is not exposed to configuration clients`, + details: { ns } + }); + } + /** + * Run one settings write (merge or wholesale replace) and acknowledge with + * the namespace's new redacted view. A namespace outside the configuration + * boundary is refused before the seam is touched; every seam refusal — + * unknown or invalid namespace, read-only provider, schema validation, + * storage — becomes one `settings-rejected` carrying the seam's own message. + */ + async function settingsWrite(request, ns, mode, section, expectedRevision) { + const settings = ctx.get("settings"); + if (settings === void 0) return err(request, settingsAbsent()); + const rejected = (error) => { + if (error instanceof SettingsConflictError) return err(request, { + code: "settings-conflict", + message: error.message, + details: { + ns, + expected: error.expected, + actual: error.actual + } + }); + return err(request, { + code: "settings-rejected", + message: error instanceof Error ? error.message : String(error), + details: { ns } + }); + }; + let branded; + try { + branded = settingsNamespace(ns); + } catch (error) { + return rejected(error); + } + if (!exposedNamespaces().has(ns)) return notExposed(request, ns); + try { + if (mode === "update") await settings.update(branded, section, expectedRevision); + else if (mode === "replace") await settings.replace(branded, section, expectedRevision); + else await settings.mutate(branded, section, expectedRevision); + } catch (error) { + return rejected(error); + } + const descriptor = settings.describe({ redactSecrets: true }).find((candidate) => candidate.ns === branded); + if (descriptor === void 0) return err(request, { + code: "internal", + message: `settings namespace "${ns}" was disposed after the ${mode}`, + details: {} + }); + return ok(request, namespaceView(descriptor)); + } + return { + sessions: { + async list(request) { + return ok(request, { items: await listVisibleSessionSummaries() }); + }, + async search(request, signal) { + const cancelled = () => err(request, { + code: "cancelled", + message: "session search was aborted", + details: {} + }); + if (isAborted(signal)) return cancelled(); + const sessionQuery = ctx.get("sessionQuery"); + if (sessionQuery === void 0) return err(request, { + code: "internal", + message: "session search is unavailable: this deployment does not mount @deepseek-ai/dsh-session-query", + details: {} + }); + try { + const visible = await listVisibleSessionSummaries(signal); + if (isAborted(signal)) return cancelled(); + if (visible.length === 0) return ok(request, { + items: [], + hasMore: false + }); + const visibleIds = new Set(visible.map((item) => item.sessionId)); + const authorized = []; + const acceptedIds = /* @__PURE__ */ new Set(); + const seenCursors = /* @__PURE__ */ new Set(); + let cursor; + let providerCallCount = 0; + let providerPageLimit = 20; + while (authorized.length <= 20) { + if (isAborted(signal)) return cancelled(); + if (providerCallCount >= SESSION_SEARCH_PROVIDER_CALL_LIMIT) throw new Error(`session search provider exceeded the ${SESSION_SEARCH_PROVIDER_CALL_LIMIT}-call work budget`); + providerCallCount++; + const requestedCursor = cursor; + const requestedPageLimit = providerPageLimit; + let page; + try { + page = await sessionQuery.searchSessions({ + query: request.payload.query, + eventFilters: [{ + kind: "type", + values: ["user/message", "assistant/message"] + }, { + kind: "surface", + values: ["current"] + }], + limit: requestedPageLimit, + ...requestedCursor === void 0 ? {} : { cursor: requestedCursor } + }, { signal }); + } catch (error) { + if (isAborted(signal)) return cancelled(); + if (requestedCursor === void 0 && error instanceof SessionQueryError && error.code === "SESSION_QUERY_INVALID_LIMIT" && requestedPageLimit > 1) { + providerPageLimit = Math.max(1, Math.floor(requestedPageLimit / 2)); + continue; + } + if (requestedCursor !== void 0 && error instanceof SessionQueryError && error.code === "SESSION_QUERY_STALE_CURSOR") { + authorized.length = 0; + acceptedIds.clear(); + seenCursors.clear(); + cursor = void 0; + continue; + } + throw error; + } + if (isAborted(signal)) return cancelled(); + const providerItemCount = page.items.length; + if (providerItemCount > requestedPageLimit) throw new Error(`session search provider returned ${providerItemCount} items; maximum is ${requestedPageLimit}`); + for (const hit of page.items) { + if (authorized.length > 20) continue; + if (!visibleIds.has(hit.header.id) || hit.bestMatch.sessionId !== hit.header.id || hit.bestMatch.surface !== "current" || !MESSAGE_TYPES.has(hit.bestMatch.type) || acceptedIds.has(hit.header.id)) continue; + const snippet = truncateUnicodeCodePoints(hit.bestMatch.snippet, 240); + acceptedIds.add(hit.header.id); + authorized.push({ + sessionId: hit.header.id, + snippet + }); + } + const nextCursor = page.nextCursor; + if (nextCursor !== void 0) { + if (seenCursors.has(nextCursor)) throw new Error("session search provider repeated a continuation cursor"); + seenCursors.add(nextCursor); + } + if (authorized.length > 20 || nextCursor === void 0) break; + cursor = nextCursor; + } + return ok(request, { + items: authorized.slice(0, 20), + hasMore: authorized.length > 20 + }); + } catch (error) { + if (isAborted(signal) || error instanceof SessionQueryError && error.code === "SESSION_QUERY_ABORTED") return cancelled(); + return err(request, { + code: "internal", + message: `session search failed: ${String(error)}`, + details: {} + }); + } + }, + async create(request) { + const sessionId = request.payload.sessionId ?? `session-${randomUUID()}`; + let workspace; + if (request.payload.workspaceId !== void 0) { + workspace = ctx.workspaceRegistry.get(WorkspaceId(request.payload.workspaceId)); + if (workspace === void 0) return err(request, { + code: "workspace-not-found", + message: `workspace "${request.payload.workspaceId}" not found`, + details: { workspaceId: request.payload.workspaceId } + }); + } + const cwd = workspace?.path ?? request.payload.cwd ?? defaults.cwd; + const requestedPreset = request.payload.agentPreset; + try { + await ensureSession(sessionId, cwd, request.payload.sessionId !== void 0, requestedPreset); + } catch (error) { + if (error instanceof AgentPresetConflict) return err(request, { + code: "agent-preset-conflict", + message: error.message, + details: { + sessionId: error.sessionId, + requestedPreset: error.requestedPreset, + ...error.existingPreset === void 0 ? {} : { existingPreset: error.existingPreset } + } + }); + const refused = presetFailure(request, error); + if (refused !== void 0) return refused; + if (error instanceof SessionCwdConflict) return err(request, { + code: "session-conflict", + message: error.message, + details: { + sessionId: error.sessionId, + requestedCwd: error.requestedCwd, + ...error.existingCwd === void 0 ? {} : { existingCwd: error.existingCwd } + } + }); + if (error instanceof ApiRemoteSubagentSessionOwnership) return err(request, subagentOwnershipError(error.sessionId)); + return err(request, { + code: "internal", + message: `failed to create session "${sessionId}": ${String(error)}`, + details: {} + }); + } + if (workspace !== void 0) try { + await workspace.attachSession(sessionId); + } catch (error) { + return err(request, { + code: "workspace-attach-failed", + message: `session "${sessionId}" was created but could not attach to workspace "${workspace.id}": ${String(error)}`, + details: { + sessionId, + workspaceId: workspace.id + } + }); + } + const created = ctx.agents.get(sessionId); + const createdPreset = created === void 0 ? void 0 : resolveSessionPreset(created.session); + return ok(request, { + sessionId, + ...createdPreset === void 0 ? {} : { agentPreset: createdPreset } + }); + }, + async history(request) { + const { sessionId, beforeSeq, maxMessages } = request.payload; + try { + const source = await historySourceFor(sessionId); + const scope = await presenterScopeFor(sessionId, sourceSession(source)); + const cut = historyCutOf(source, beforeSeq === void 0); + const page = historyPage(ctx, cut.events, beforeSeq, maxMessages, scope); + return ok(request, { + events: page.events, + hasMore: page.hasMore, + ...cut.projections === void 0 ? {} : { projections: cut.projections } + }); + } catch (error) { + if (error instanceof ApiRemoteSessionNotFound) return err(request, { + code: "session-not-found", + message: error.message, + details: { sessionId } + }); + return err(request, { + code: "internal", + message: `history unavailable for session "${sessionId}": ${String(error)}`, + details: {} + }); + } + }, + async models(request) { + const { sessionId } = request.payload; + const found = await agentFor(sessionId); + if ("error" in found) return err(request, found.error); + const current = selectionFor(found.agent).current; + const { groups, failures } = await buildModelCatalog(ctx); + const routable = routeServed(current.provider); + return ok(request, { + current: { ...current }, + routable, + groups, + failures + }); + }, + async selectModel(request) { + const { sessionId, provider, model, reasoningEffort } = request.payload; + const found = await agentFor(sessionId); + if ("error" in found) return err(request, found.error); + return serializeImageAdmission(found.agent, async () => { + try { + const resolved = await ctx.llm.resolveCallConfig({ + provider, + model, + ...reasoningEffort === void 0 ? {} : { reasoningEffort: ReasoningEffortId(reasoningEffort) } + }); + if ([...found.agent.inbox.nextTurn, ...found.agent.inbox.nextStep].some((message) => contentHasImage(message.content)) || messagesHaveImage(found.agent.session.deriveMessages())) { + const info = await ctx.llm.resolveModelInfo(resolved.provider, resolved.model); + if (info.inputModalities !== void 0 && !info.inputModalities.includes("image")) return err(request, { + code: "model-unavailable", + message: `Model "${resolved.model}" does not accept image input, but this session already contains images; select an image-capable model.`, + details: { + provider, + model + } + }); + } + const selected = { + provider: resolved.provider, + model: resolved.model, + ...resolved.reasoningEffort === void 0 ? {} : { reasoningEffort: resolved.reasoningEffort } + }; + selectionFor(found.agent).current = selected; + try { + await defaults.saveDefaultModelSelection?.(selected); + } catch (error) { + ctx.logger.warn(`api-proxy: the model switch applies to this session but was not saved as the default: ${String(error)}`); + } + return ok(request, { selected: { ...selected } }); + } catch (error) { + return err(request, { + code: "model-unavailable", + message: error instanceof Error ? error.message : String(error), + details: { + provider, + model + } + }); + } + }); + }, + async rename(request) { + const { sessionId, title } = request.payload; + const found = await agentFor(sessionId); + if ("error" in found) return err(request, found.error); + const titles = ctx.get("sessionTitle"); + if (titles === void 0) return err(request, { + code: "internal", + message: "renaming is unavailable: this deployment mounts no session-title service", + details: {} + }); + try { + const accepted = titles.rename(found.agent.session, title); + return ok(request, { + title: accepted.title, + seq: accepted.eventSeq + }); + } catch (error) { + if (error instanceof SessionTitleInvalidError) return err(request, { + code: "title-invalid", + message: error.message, + details: { sessionId } + }); + return err(request, { + code: "internal", + message: `failed to rename session "${sessionId}": ${String(error)}`, + details: {} + }); + } + }, + async fork(request) { + const { sessionId, atSeq } = request.payload; + let source; + try { + source = await readSessionState(sessionId); + } catch (error) { + if (error instanceof ApiRemoteSessionNotFound) return err(request, { + code: "session-not-found", + message: error.message, + details: { sessionId } + }); + return err(request, { + code: "internal", + message: `fork source unavailable for session "${sessionId}": ${String(error)}`, + details: {} + }); + } + const events = source.events; + const lastSeq = events.at(-1)?.seq ?? -1; + const boundary = (atSeq === void 0 ? void 0 : events.find((e) => e.type === "turn/end" && e.seq >= atSeq)) ?? (atSeq === void 0 || atSeq > lastSeq ? events.findLast((e) => e.type === "turn/end") : void 0); + if (boundary === void 0) return err(request, { + code: "fork-unavailable", + message: atSeq !== void 0 && atSeq <= lastSeq ? `session "${sessionId}" has not completed the turn containing event ${String(atSeq)}` : `session "${sessionId}" has no completed turn to fork from`, + details: { sessionId } + }); + let cut = boundary.seq + 1; + while (cut < events.length && events[cut]?.type !== "turn/start") cut++; + let workspace; + try { + workspace = await forkWorkspace(source); + } catch (error) { + return err(request, { + code: "internal", + message: `failed to resolve fork workspace for session "${sessionId}": ${String(error)}`, + details: {} + }); + } + const childId = `session-${randomUUID()}`; + const forkComposition = await composeAgent(resolveSessionPreset(source)); + try { + await ctx.agents.create({ + sessionId: childId, + seed: events.slice(0, cut), + meta: { + ...source.header.cwd === void 0 ? {} : { cwd: source.header.cwd }, + parentSession: source.id, + seedLength: cut, + ...forkComposition.agentPreset === void 0 ? {} : { agentPreset: forkComposition.agentPreset } + }, + agentOptions: agentOptions(), + setup: forkComposition.setup + }); + } catch (error) { + return err(request, { + code: "internal", + message: `failed to fork session "${sessionId}": ${String(error)}`, + details: {} + }); + } + if (workspace !== void 0) try { + await workspace.attachSession(childId); + } catch (error) { + return err(request, { + code: "workspace-attach-failed", + message: `session "${childId}" was forked but could not attach to workspace "${workspace.id}": ${String(error)}`, + details: { + sessionId: childId, + workspaceId: workspace.id + } + }); + } + return ok(request, { sessionId: childId }); + }, + async prompt(request) { + const { sessionId, mode, content, clientTimeZone } = request.payload; + const canonicalTimeZone = clientTimeZone === void 0 ? void 0 : canonicalClientTimeZone(clientTimeZone); + if (clientTimeZone !== void 0 && canonicalTimeZone === void 0) return err(request, { + code: "invalid-time-zone", + message: "clientTimeZone must be UTC or a valid IANA Area/Location name", + details: { value: clientTimeZone } + }); + const resolved = await turnAgentFor(request, sessionId); + if ("refused" in resolved) return resolved.refused; + const agent = resolved.agent; + const source = { + kind: "user", + rpcId: request.rpcId, + ...canonicalTimeZone === void 0 ? {} : { clientTimeZone: canonicalTimeZone } + }; + const hasImage = content.some((part) => part.type === "image"); + const admit = async () => { + try { + if (hasImage) { + const current = selectionFor(agent).current; + const modelInfo = await ctx.llm.resolveModelInfo(current.provider, current.model); + if (modelInfo.inputModalities !== void 0 && !modelInfo.inputModalities.includes("image")) return err(request, { + code: "attachment-error", + message: `Model "${current.model}" does not support image input.`, + details: { reason: "MODEL_DOES_NOT_SUPPORT_IMAGES" } + }); + } + const message = createUserMessage({ + content: await durablePromptContent(ctx, content), + source + }); + if (mode === "steer") agent.steer(message); + else agent.followup(message); + } catch (error) { + if (error instanceof AttachmentError) return err(request, { + code: "attachment-error", + message: error.message, + details: { reason: error.code } + }); + return err(request, { + code: "agent-busy", + message: "prompt rejected", + details: { reason: String(error) } + }); + } + return ok(request, { accepted: true }); + }; + return hasImage ? serializeImageAdmission(agent, admit) : admit(); + }, + async attachment(request) { + const { sessionId, attachmentId } = request.payload; + let state; + try { + state = await readSessionState(sessionId); + } catch (error) { + if (error instanceof ApiRemoteSessionNotFound) return err(request, { + code: "session-not-found", + message: error.message, + details: { sessionId } + }); + return err(request, { + code: "internal", + message: `attachment authorization unavailable for session "${sessionId}": ${String(error)}`, + details: {} + }); + } + const ref = referencedImage(state.events, String(attachmentId)); + if (ref === void 0) return err(request, { + code: "attachment-error", + message: "Image is not referenced by this session.", + details: { reason: "ATTACHMENT_NOT_REFERENCED" } + }); + try { + const stored = await ctx.attachments.readImage(ref); + return ok(request, { + attachment: stored.ref, + data: Buffer.from(stored.data).toString("base64") + }); + } catch (error) { + if (error instanceof AttachmentError) return err(request, { + code: "attachment-error", + message: error.message, + details: { reason: error.code } + }); + return err(request, { + code: "internal", + message: "Unable to read image attachment.", + details: {} + }); + } + }, + updateQueue(request) { + const { sessionId, itemId, action } = request.payload; + if (action.kind === "edit" && action.content.some((block) => block.type !== "text")) return Promise.resolve(err(request, { + code: "attachment-error", + message: "queue edits accept text content only", + details: { reason: "QUEUE_EDIT_NON_TEXT" } + })); + const agent = ctx.agents.get(sessionId); + if (agent !== void 0 && hasSubagentOwner(agent.session, agent)) return Promise.resolve(err(request, subagentOwnershipError(sessionId))); + if (agent === void 0) return Promise.resolve(err(request, { + code: "queue-item-not-found", + message: "queued item is no longer pending", + details: { itemId } + })); + const target = agent.inbox.nextTurn.some((message) => message.id === itemId) ? "next-turn" : agent.inbox.nextStep.some((message) => message.id === itemId) ? "next-step" : void 0; + const message = target === void 0 ? void 0 : (target === "next-turn" ? agent.inbox.nextTurn : agent.inbox.nextStep).find((candidate) => candidate.id === itemId); + if (target === void 0 || message === void 0) return Promise.resolve(err(request, { + code: "queue-item-not-found", + message: "queued item is no longer pending", + details: { itemId } + })); + if (action.kind === "steer" && (target !== "next-turn" || agent.status !== "running")) return Promise.resolve(err(request, { + code: "steer-unavailable", + message: "current turn no longer accepts steering", + details: { itemId } + })); + if (action.kind === "edit") agent.inbox.replace(itemId, freezeMessage({ + ...message, + content: action.content + })); + else { + agent.inbox.remove(itemId); + if (action.kind === "steer") agent.steer(message); + } + return Promise.resolve(ok(request, { accepted: true })); + }, + cancel(request) { + const { sessionId } = request.payload; + const agent = ctx.agents.get(sessionId); + if (agent === void 0) return Promise.resolve(err(request, { + code: "session-not-found", + message: `session "${sessionId}" not found (not attached)`, + details: { sessionId } + })); + if (hasSubagentOwner(agent.session, agent)) return Promise.resolve(err(request, subagentOwnershipError(sessionId))); + agent.cancel({ kind: "user" }, { keepInbox: true }); + return Promise.resolve(ok(request, { accepted: true })); + } + }, + subagents: { + async list(request, signal) { + try { + return ok(request, { + entries: (await ctx.subagents.listChildren(request.payload.parentSessionId, signal)).map((entry) => entry.kind === "child" ? { + ...entry, + activity: ctx.agents.get(entry.id)?.status === "running" ? "running" : "inactive" + } : entry), + parentAvailable: ctx.agents.get(request.payload.parentSessionId) !== void 0 + }); + } catch (error) { + if (signal?.aborted || error instanceof SubagentError && error.code === "CANCELLED") return err(request, { + code: "cancelled", + message: "subagent catalog read was cancelled", + details: {} + }); + if (error instanceof SubagentError && error.code === "SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE") return err(request, projectionsUnavailableError()); + return err(request, { + code: "internal", + message: "subagent catalog read failed", + details: {} + }); + } + }, + async history(request, signal) { + const { parentSessionId, childSessionId, mode, beforeSeq, maxMessages } = request.payload; + const verified = await catalogChild(ctx, { + parentSessionId, + childSessionId, + mode + }, signal); + if (verified.error !== void 0) return err(request, verified.error); + let header; + let events; + let projections; + const attached = ctx.sessions.get(childSessionId); + if (attached !== void 0) { + header = attached.header; + events = [...attached.events]; + projections = beforeSeq === void 0 ? subagentHistoryProjections(ctx, childSessionId, () => projectionsFor(ctx, attached)) : void 0; + } else try { + const inspected = await inspectServable(childSessionId); + header = inspected.meta; + events = inspected.events; + projections = beforeSeq === void 0 ? subagentHistoryProjections(ctx, childSessionId, () => detachedProjectionsFor(ctx, inspected.events)) : void 0; + } catch (error) { + if (signal?.aborted) return err(request, { + code: "cancelled", + message: "subagent history read was cancelled", + details: {} + }); + if (error instanceof ApiRemoteSessionNotFound) return err(request, { + code: "subagent-not-found", + message: "subagent disappeared during history read", + details: { + parentSessionId, + childSessionId + } + }); + return err(request, { + code: "internal", + message: "subagent history read failed", + details: {} + }); + } + if (signal?.aborted) return err(request, { + code: "cancelled", + message: "subagent history read was cancelled", + details: {} + }); + if (header.parentSession !== parentSessionId) return err(request, { + code: "subagent-unauthorized", + message: "subagent parent changed during history read", + details: { childSessionId } + }); + return ok(request, { + ...historyPage(ctx, events, beforeSeq, maxMessages), + ...projections === void 0 ? {} : { projections } + }); + }, + async prompt(request, signal) { + const { parentSessionId, childSessionId, content, clientTimeZone } = request.payload; + const canonicalTimeZone = clientTimeZone === void 0 ? void 0 : canonicalClientTimeZone(clientTimeZone); + if (clientTimeZone !== void 0 && canonicalTimeZone === void 0) return err(request, { + code: "invalid-time-zone", + message: "clientTimeZone must be UTC or a valid IANA Area/Location name", + details: { value: clientTimeZone } + }); + const parent = ctx.agents.get(parentSessionId); + if (parent === void 0) return err(request, { + code: "subagent-parent-unavailable", + message: `parent session "${parentSessionId}" is not live`, + details: { parentSessionId } + }); + const verified = await catalogChild(ctx, { + parentSessionId, + childSessionId, + mode: "continuable" + }, signal); + if (verified.error !== void 0) return err(request, verified.error); + try { + return ok(request, { messageId: await ctx.subagents.followup(parent, childSessionId, content, { + source: { + kind: "user", + rpcId: request.rpcId, + ...canonicalTimeZone === void 0 ? {} : { clientTimeZone: canonicalTimeZone } + }, + signal + }) }); + } catch (error) { + return subagentPromptError(request, error, signal); + } + }, + interrupt(request) { + const { parentSessionId, childSessionId } = request.payload; + try { + ctx.subagents.interrupt(childSessionId, { + kind: "user", + parentSessionId + }); + } catch (error) { + if (error instanceof SubagentError && error.code === "UNAUTHORIZED") return Promise.resolve(err(request, { + code: "subagent-unauthorized", + message: "subagent does not belong to this parent", + details: { childSessionId } + })); + return Promise.resolve(err(request, { + code: "internal", + message: "subagent interrupt failed", + details: {} + })); + } + return Promise.resolve(ok(request, { accepted: true })); + } + }, + workspace: { + list(request) { + return Promise.resolve(ok(request, { + items: ctx.workspaceRegistry.list().map(workspaceView), + archivedSessionIds: [...ctx.workspaceRegistry.archivedSessionIds] + })); + }, + async create(request) { + const { path } = request.payload; + try { + const { workspace, created } = await ensureWorkspace(path); + return ok(request, { + workspace: workspaceView(workspace), + created + }); + } catch (error) { + return err(request, { + code: "workspace-invalid-path", + message: `cannot create a workspace at "${path}": ${error instanceof Error ? error.message : String(error)}`, + details: { path } + }); + } + }, + async rename(request) { + const { payload } = request; + const workspace = ctx.workspaceRegistry.get(WorkspaceId(payload.workspaceId)); + if (workspace === void 0) return workspaceNotFound(request, payload.workspaceId); + const title = payload.title.trim(); + const operation = workspaceCreationChain.then(async () => { + if (title === workspace.title) return; + if (ctx.workspaceRegistry.list().some((other) => other.id !== workspace.id && other.title === title)) throw new WorkspaceNameConflictError(title); + await workspace.setTitle(title); + }); + workspaceCreationChain = operation.then(() => void 0, () => void 0); + try { + await operation; + } catch (error) { + if (error instanceof WorkspaceNameConflictError) return err(request, { + code: "workspace-name-conflict", + message: error.message, + details: { name: error.workspaceName } + }); + throw error; + } + return ok(request, { workspace: workspaceView(workspace) }); + }, + async delete(request) { + const { workspaceId } = request.payload; + const operation = workspaceCreationChain.then(() => ctx.workspaceRegistry.delete(WorkspaceId(workspaceId))); + workspaceCreationChain = operation.then(() => void 0, () => void 0); + if (!await operation) return workspaceNotFound(request, workspaceId); + return ok(request, { deleted: true }); + }, + async insertBefore(request) { + const { workspaceId, beforeWorkspaceId } = request.payload; + try { + return ok(request, { workspaceIds: [...await ctx.workspaceRegistry.insertBefore(WorkspaceId(workspaceId), beforeWorkspaceId === void 0 ? void 0 : WorkspaceId(beforeWorkspaceId))] }); + } catch (error) { + if (!(error instanceof WorkspaceOrderInvalidError)) throw error; + return workspaceNotFound(request, error.workspaceId); + } + }, + async insertSessionBefore(request) { + const { payload } = request; + const workspace = ctx.workspaceRegistry.get(WorkspaceId(payload.workspaceId)); + if (workspace === void 0) return workspaceNotFound(request, payload.workspaceId); + try { + await workspace.insertSessionBefore(payload.sessionId, payload.beforeSessionId); + } catch (error) { + if (!(error instanceof WorkspaceMoveInvalidError)) throw error; + return err(request, { + code: "workspace-move-invalid", + message: error.message, + details: { + workspaceId: payload.workspaceId, + sessionId: payload.sessionId, + ...payload.beforeSessionId === void 0 ? {} : { beforeSessionId: payload.beforeSessionId } + } + }); + } + return ok(request, { workspace: workspaceView(workspace) }); + }, + async archiveSession(request) { + const { sessionId } = request.payload; + try { + await ctx.workspaceRegistry.archiveSession(sessionId); + } catch (error) { + if (!(error instanceof WorkspaceUnknownSessionError)) throw error; + return err(request, { + code: "session-not-found", + message: error.message, + details: { sessionId } + }); + } + return ok(request, { archivedSessionIds: [...ctx.workspaceRegistry.archivedSessionIds] }); + } + }, + host: { + describe(request) { + const selection = defaults.defaultModelSelection(); + return Promise.resolve(ok(request, { + version: "0.0.1", + cwd: defaults.cwd, + provider: selection.provider, + model: selection.model, + attachedSessions: ctx.agents.list().length, + canOpenPath: canOpenPaths() + })); + }, + async pickDirectory(request, signal) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== "native") return err(request, { + code: "directory-picker-unavailable", + message: `host.pickDirectory needs the native capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind } + }); + try { + return ok(request, { path: await capability.pick(signal) }); + } catch (error) { + if (signal.aborted) return err(request, { + code: "cancelled", + message: "directory picker was aborted", + details: {} + }); + return err(request, { + code: "internal", + message: `directory picker failed: ${error instanceof Error ? error.message : String(error)}`, + details: {} + }); + } + }, + async listDirectory(request, signal) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== "browse") return err(request, { + code: "directory-picker-unavailable", + message: `host.listDirectory needs the browse capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind } + }); + try { + return ok(request, await capability.list(request.payload.path, signal)); + } catch (error) { + if (signal.aborted) return err(request, { + code: "cancelled", + message: "directory listing was aborted", + details: {} + }); + return err(request, directoryError(error)); + } + }, + async createDirectory(request) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== "browse") return err(request, { + code: "directory-picker-unavailable", + message: `host.createDirectory needs the browse capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind } + }); + try { + return ok(request, { path: await capability.createDirectory(request.payload.path, request.payload.name) }); + } catch (error) { + return err(request, directoryError(error)); + } + }, + async openPath(request, signal) { + return openPath(request, request.payload.path, signal); + } + }, + goals: { + async create(request) { + const { objective, maxGoalRounds } = request.payload; + return mutateGoal(request, (goals, agent) => goals.create(agent, { + objective, + ...maxGoalRounds !== void 0 ? { maxGoalRounds } : {} + })); + }, + async edit(request) { + const { ref, objective, maxGoalRounds } = request.payload; + return mutateGoal(request, (goals, agent) => goals.edit(agent, ref, { + ...objective !== void 0 ? { objective } : {}, + ...maxGoalRounds !== void 0 ? { maxGoalRounds } : {} + })); + }, + async pause(request) { + return mutateGoal(request, (goals, agent) => goals.pause(agent, request.payload.ref)); + }, + async resume(request) { + return mutateGoal(request, (goals, agent) => goals.resume(agent, request.payload.ref)); + }, + async complete(request) { + return mutateGoal(request, (goals, agent) => goals.complete(agent, request.payload.ref)); + }, + async clear(request) { + const found = await agentFor(request.payload.sessionId); + if ("error" in found) return err(request, found.error); + const goals = goalServiceFor(found.agent); + if ("error" in goals) return err(request, goals.error); + try { + goals.clear(found.agent, request.payload.ref); + return ok(request, { cleared: true }); + } catch (error) { + return goalError(request, error); + } + } + }, + agentPresets: { + async list(request) { + const presets = ctx.get("agentPresets"); + if (presets === void 0) return ok(request, { + presets: [], + authorable: false, + hasDocument: false + }); + const defaultId = presets.defaultId; + return ok(request, { + presets: (await presets.list()).map((preset) => ({ + id: preset.id, + trust: preset.trust, + isDefault: preset.id === defaultId, + ...preset.name === void 0 ? {} : { name: preset.name }, + ...preset.description === void 0 ? {} : { description: preset.description }, + ...preset.broken === void 0 ? {} : { broken: preset.broken } + })), + authorable: presets.authorable, + hasDocument: canOpenPaths() + }); + }, + async select(request) { + const { sessionId, agentPreset } = request.payload; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return err(request, { + code: "agent-preset-not-found", + message: "this deployment composes no agent presets", + details: { + agentPreset, + available: [] + } + }); + const found = await agentFor(sessionId); + if ("error" in found) return err(request, found.error); + const { agent } = found; + const swap = async () => { + if (!sessionBlank(agent.session)) return err(request, { + code: "agent-preset-locked", + message: `session "${sessionId}" has already started; its agent preset is fixed`, + details: { + sessionId, + agentPreset + } + }); + try { + const preset = await presets.recompose(agent.ctx, agentPreset); + agent.session.append("agent-preset/selected", { agentPreset: preset.id }); + return ok(request, { agentPreset: preset.id }); + } catch (error) { + const refused = presetFailure(request, error); + if (refused !== void 0) return refused; + return err(request, { + code: "internal", + message: `failed to select agent preset "${agentPreset}": ${String(error)}`, + details: {} + }); + } + }; + const turn = (presetSwitches.get(sessionId) ?? Promise.resolve()).then(swap); + presetSwitches.set(sessionId, turn.catch(() => void 0)); + try { + return await turn; + } finally { + if (presetSwitches.get(sessionId) === turn) presetSwitches.delete(sessionId); + } + }, + async read(request) { + const { agentPreset } = request.payload; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return err(request, noRoster(agentPreset)); + try { + const preset = await presets.resolve(agentPreset); + return ok(request, { + agentPreset: preset.id, + trust: preset.trust, + content: await presets.read(preset.id), + ...preset.name === void 0 ? {} : { name: preset.name }, + ...preset.description === void 0 ? {} : { description: preset.description } + }); + } catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async copy(request) { + const { from, agentPreset, name } = request.payload; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return err(request, noRoster(agentPreset)); + try { + await presets.copy(from, agentPreset, name); + return ok(request, { agentPreset }); + } catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async openDocument(request, signal) { + const { agentPreset } = request.payload; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return err(request, noRoster(agentPreset)); + try { + const preset = await presets.resolve(agentPreset); + if (preset.trust !== "user") throw new PresetNotWritableError(preset.id, "it ships with the deployment"); + const directory = dirname(preset.path); + if (!canOpenPaths()) return ok(request, { + opened: false, + path: directory + }); + return await openPath(request, directory, signal); + } catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async remove(request) { + const { agentPreset } = request.payload; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return err(request, noRoster(agentPreset)); + try { + await presets.remove(agentPreset); + return ok(request, {}); + } catch (error) { + return err(request, presetError(agentPreset, error)); + } + } + }, + skills: { async list(request) { + const { sessionId } = request.payload; + const session = ctx.sessions.get(sessionId); + if (session === void 0) return err(request, { + code: "session-not-found", + message: `session "${sessionId}" not found (not attached)`, + details: { sessionId } + }); + if (session.header.cwd === void 0) return err(request, { + code: "internal", + message: `session "${sessionId}" has no project cwd`, + details: {} + }); + const cwd = session.header.cwd; + const live = ctx.agents.get(sessionId); + const presets = ctx.get("agentPresets"); + const skillRegistry = (live === void 0 ? void 0 : presets?.serviceFor(live, "skills")) ?? ctx.get("skills"); + if (skillRegistry === void 0) return err(request, { + code: "internal", + message: "skill registry is absent: neither this session's agent preset nor the host composition mounts @deepseek-ai/dsh-skill", + details: {} + }); + const scope = await presenterScopeFor(sessionId, session); + try { + return ok(request, { skills: (await skillRegistry.list({ + cwd, + scope + })).filter(isUserInvocable).map((skill) => ({ + name: skill.name, + description: skill.description, + ...skill.whenToUse === void 0 ? {} : { whenToUse: skill.whenToUse }, + modelInvocable: skill.invocation.modelInvocable + })) }); + } catch (error) { + return err(request, { + code: "internal", + message: `skill listing failed: ${String(error)}`, + details: {} + }); + } + } }, + settings: { + describe(request) { + const settings = ctx.get("settings"); + if (settings === void 0) return Promise.resolve(err(request, settingsAbsent())); + const exposed = exposedNamespaces(); + return Promise.resolve(ok(request, { + writable: settings.writable, + hasDocument: settings.documentPath !== void 0, + namespaces: settings.describe({ redactSecrets: true }).filter((descriptor) => exposed.has(String(descriptor.ns))).map(namespaceView) + })); + }, + async openDocument(request, signal) { + const settings = ctx.get("settings"); + if (settings === void 0) return err(request, settingsAbsent()); + if (isAborted(signal)) return err(request, { + code: "cancelled", + message: "settings document open was aborted", + details: {} + }); + let path; + try { + path = await settings.prepareDocument(); + } catch (error) { + if (isAborted(signal)) return err(request, { + code: "cancelled", + message: "settings document preparation was aborted", + details: {} + }); + return err(request, { + code: "internal", + message: `settings document preparation failed: ${error instanceof Error ? error.message : String(error)}`, + details: {} + }); + } + if (path === void 0) return err(request, { + code: "internal", + message: "settings provider has no local document to open", + details: {} + }); + if (isAborted(signal)) return err(request, { + code: "cancelled", + message: "settings document open was aborted", + details: {} + }); + return openTextFile(request, path, signal); + }, + update: (request) => settingsWrite(request, request.payload.ns, "update", request.payload.patch, request.payload.expectedRevision), + replace: (request) => settingsWrite(request, request.payload.ns, "replace", request.payload.section, request.payload.expectedRevision), + mutate: (request) => settingsWrite(request, request.payload.ns, "mutate", request.payload.ops, request.payload.expectedRevision) + }, + credentials: { + async describe(request) { + const credentials = ctx.get("credentials"); + if (credentials === void 0) return err(request, credentialsAbsent()); + const entries = await Promise.all(request.payload.refs.map(async (ref) => { + const info = await credentials.describe(credentialRef(ref)); + return [ref, { + configured: info.configured, + ...info.source === void 0 ? {} : { source: info.source }, + writable: info.writable + }]; + })); + return ok(request, { credentials: Object.fromEntries(entries) }); + }, + async set(request) { + const credentials = ctx.get("credentials"); + if (credentials === void 0) return err(request, credentialsAbsent()); + const { ref, value } = request.payload; + try { + await credentials.set(credentialRef(ref), value); + } catch (error) { + return err(request, { + code: "credential-rejected", + message: error instanceof Error ? error.message : String(error), + details: { ref } + }); + } + return ok(request, {}); + }, + async unset(request) { + const credentials = ctx.get("credentials"); + if (credentials === void 0) return err(request, credentialsAbsent()); + const { ref } = request.payload; + try { + await credentials.unset(credentialRef(ref)); + } catch (error) { + return err(request, { + code: "credential-rejected", + message: error instanceof Error ? error.message : String(error), + details: { ref } + }); + } + return ok(request, {}); + } + }, + llm: { + providers(request) { + const registered = ctx.llm.listProviders(); + const active = new Set(registered.map((provider) => provider.id)); + const directory = ctx.llm.listConfigurableProviders(); + const declared = new Set(directory.map((entry) => entry.provider)); + const views = directory.map((entry) => ({ + provider: entry.provider, + displayName: entry.displayName, + settingsNs: entry.settingsNs, + settingsPath: [...entry.settingsPath], + active: active.has(entry.provider), + ...entry.declared === void 0 ? {} : { declared: entry.declared } + })); + for (const provider of registered) { + if (declared.has(provider.id)) continue; + views.push({ + provider: provider.id, + displayName: provider.name, + settingsNs: "", + settingsPath: [], + active: true + }); + } + return Promise.resolve(ok(request, { providers: views })); + }, + async models(request) { + return ok(request, await buildModelCatalog(ctx)); + }, + async discoverModels(request, signal) { + const { settingsNs, provider, baseURL, api, apiKey } = request.payload; + try { + return ok(request, { models: await ctx.llm.discoverModels(settingsNs, { + ...provider === void 0 ? {} : { provider }, + ...baseURL === void 0 ? {} : { baseURL }, + ...api === void 0 ? {} : { api }, + ...apiKey === void 0 ? {} : { apiKey }, + ...signal === void 0 ? {} : { signal } + }) }); + } catch (error) { + return err(request, { + code: "model-discovery-failed", + message: error instanceof Error ? error.message : String(error), + details: { + settingsNs, + ...baseURL === void 0 ? {} : { baseURL } + } + }); + } + } + }, + events: { + mux(_request, signal) { + const queue = new FrameQueue(); + muxQueues.add(queue); + for (const session of ctx.sessions.list()) subscribeSession(queue, session); + for (const pending of pendingQuestions.values()) queue.push({ + rpcId: pending.rpcId, + payload: { + type: "question/requested", + sessionId: pending.sessionId, + questions: pending.questions + } + }); + for (const pending of pendingApprovals.values()) queue.push(requestedFrame(pending)); + for (const session of ctx.sessions.list()) { + const agent = ctx.agents.get(session.id); + if (agent?.session === session && agent.inbox.hasPending) queue.push(frame({ + type: "session/queue", + sessionId: session.id, + items: queueItems(agent) + })); + } + const jobs = ctx.get("jobs"); + if (jobs !== void 0) for (const session of ctx.sessions.list()) { + const views = jobViews(jobs.list(ctx.agents.get(session.id))); + if (views.length > 0) queue.push(frame({ + type: "session/jobs", + sessionId: session.id, + jobs: views + })); + } + const openCalls = /* @__PURE__ */ new Map(); + const disposers = [ + ctx.on("session/event", (session, event) => { + if (event.type === "tool/call") { + const data = event.data; + try { + let table = openCalls.get(session.id); + if (table === void 0) openCalls.set(session.id, table = /* @__PURE__ */ new Map()); + table.set(data.callId, { + name: data.name, + args: JSON.parse(data.arguments) + }); + } catch {} + } else if (event.type === "turn/end") openCalls.delete(session.id); + const view = viewFor(ctx, event, (callId) => openCalls.get(session.id)?.get(callId) ?? backscanArgs(session.events, callId), ctx.agents.get(session.id)); + queue.push(frame({ + type: "session/event", + sessionId: session.id, + event, + ...view === void 0 ? {} : { view } + })); + }), + ctx.on("session/created", (session) => { + subscribeSession(queue, session); + const views = jobs === void 0 ? [] : jobViews(jobs.list(ctx.agents.get(session.id))); + if (views.length > 0) queue.push(frame({ + type: "session/jobs", + sessionId: session.id, + jobs: views + })); + }), + ctx.on("session/disposed", (session) => { + openCalls.delete(session.id); + }), + ...jobs === void 0 ? [] : [jobs.onJobsChanged((owner) => { + if (owner !== void 0) { + queue.push(frame({ + type: "session/jobs", + sessionId: owner.id, + jobs: jobViews(jobs.list(owner)) + })); + return; + } + for (const session of ctx.sessions.list()) queue.push(frame({ + type: "session/jobs", + sessionId: session.id, + jobs: jobViews(jobs.list(ctx.agents.get(session.id))) + })); + })] + ]; + return queue.iterate(signal, () => { + muxQueues.delete(queue); + for (const dispose of disposers) dispose(); + }); + }, + host(_request, signal) { + const queue = new FrameQueue(); + const committedWorkspaces = ctx.workspaceRegistry.list(); + const committedWorkspaceIds = new Set(committedWorkspaces.map((workspace) => String(workspace.id))); + let committedWorkspaceOrder = committedWorkspaces.map((workspace) => workspace.id); + let archivedSessionIds = ctx.workspaceRegistry.archivedSessionIds; + const disposers = [ + ctx.on("session/created", (session) => { + queue.push(frame({ + type: "host/session-added", + sessionId: session.id, + blank: sessionBlank(session), + ...sessionListFields(session.header, session.events) + })); + }), + ctx.on("session/disposed", (session) => { + queue.push(frame({ + type: "host/session-removed", + sessionId: session.id + })); + }), + ctx.on("agent/status", ({ agent, status }) => { + queue.push(frame({ + type: "host/session-status", + sessionId: agent.id, + running: status === "running" + })); + }), + ctx.on("agent/error", ({ agent, error }) => { + queue.push(frame({ + type: "host/agent-error", + sessionId: agent.id, + message: errorChain(error) + })); + }), + ctx.on("domain/changed", (change) => { + if (change.domain !== "workspace") return; + if (change.table === "") { + if (change.operation !== "put") return; + const state = workspaceDomainState.parse(change.value); + const orderChanged = state.workspaceIds.length === committedWorkspaceOrder.length && state.workspaceIds.every((workspaceId) => committedWorkspaceIds.has(String(workspaceId))) && state.workspaceIds.some((workspaceId, index) => workspaceId !== committedWorkspaceOrder[index]); + for (const workspaceId of state.workspaceIds) { + if (committedWorkspaceIds.has(workspaceId)) continue; + const workspace = ctx.workspaceRegistry.get(workspaceId); + if (workspace === void 0) throw new Error(`committed workspace registry references missing workspace "${workspaceId}"`); + committedWorkspaceIds.add(workspaceId); + queue.push(frame({ + type: "host/workspace-changed", + workspace: workspaceView(workspace) + })); + } + committedWorkspaceOrder = [...state.workspaceIds]; + if (orderChanged) queue.push(frame({ + type: "host/workspace-order-changed", + workspaceIds: [...state.workspaceIds] + })); + if (state.archivedSessionIds.length !== archivedSessionIds.length || state.archivedSessionIds.some((id, index) => id !== archivedSessionIds[index])) { + archivedSessionIds = state.archivedSessionIds; + queue.push(frame({ + type: "host/archived-sessions-changed", + archivedSessionIds: [...state.archivedSessionIds] + })); + } + return; + } + if (change.table !== "workspaces") return; + if (change.operation === "deleted") { + if (!committedWorkspaceIds.delete(change.key)) return; + queue.push(frame({ + type: "host/workspace-removed", + workspaceId: change.key + })); + return; + } + if (!committedWorkspaceIds.has(change.key)) return; + queue.push(frame({ + type: "host/workspace-changed", + workspace: changedWorkspaceView(change.key, change.value) + })); + }), + ...API_REMOTE_FORWARDED_EVENTS.map((name) => ctx.on(name, ((...args) => { + queue.push(frame({ + type: "host/remote-event", + event: name, + args: assertJsonArgs(name, args) + })); + }))) + ]; + return queue.iterate(signal, () => { + for (const dispose of disposers) dispose(); + }); + } + }, + downloads: { async sessionLog(request, signal) { + const deps = sessionLogExportDeps(ctx); + if (deps.sessionQuery === void 0 || deps.sessionPersistence === void 0 || deps.attachments === void 0) return new Response("session log export is unavailable: missing session-query, session-persistence, or attachments service", { status: 500 }); + if (!deps.sessionPersistence.supportsRawArtifacts) return new Response("session log export is unavailable: the persistence backend does not expose per-session raw artifacts", { status: 501 }); + const ready = { + sessionQuery: deps.sessionQuery, + sessionPersistence: deps.sessionPersistence, + attachments: deps.attachments, + sessions: deps.sessions + }; + let root; + try { + await flushLiveSessionLog(deps, request.sessionId, signal); + root = await deps.sessionPersistence.readRaw(request.sessionId, signal); + signal.throwIfAborted(); + } catch { + signal.throwIfAborted(); + return new Response("session log export failed to prepare the stored artifact", { status: 500 }); + } + if (root === void 0) return new Response("session not found", { status: 404 }); + return new Response(streamSessionLogZip(ready, root, request.sessionId, request.includeDescendants === true, sessionExportCompressionLevel, signal), { headers: { + "content-type": "application/zip", + "content-disposition": `attachment; filename="${sessionLogZipFilename(request.sessionId)}"` + } }); + } }, + respond(message) { + const approval = pendingApprovals.get(message.rpcId); + if (approval !== void 0) { + if (!message.result.ok) return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + const parsed = approvalResponsePayloadSchema.safeParse(message.result.value); + if (!parsed.success || parsed.data.approvalId !== approval.approvalId || parsed.data.sessionId !== approval.sessionId) return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + approval.resolve(parsed.data.outcome); + return Promise.resolve({ accepted: true }); + } + const pending = pendingQuestions.get(message.rpcId); + if (pending === void 0) return Promise.resolve({ + accepted: false, + reason: "not-pending" + }); + if (!message.result.ok) { + if (message.result.error.code !== "cancelled") return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + claimQuestion(pending, "cancelled"); + pending.reject(new UserQuestionError("the user cancelled ask_user_question", "ASK_CANCELLED")); + return Promise.resolve({ accepted: true }); + } + const parsed = questionResponsePayloadSchema.safeParse(message.result.value); + if (!parsed.success) return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + const payload = { + sessionId: parsed.data.sessionId, + answer: { answers: parsed.data.answer.answers.map((answer) => ({ + id: answer.id, + selected: answer.selected, + ...answer.custom === void 0 ? {} : { custom: answer.custom } + })) } + }; + if (!matchesQuestions(payload, pending)) return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + claimQuestion(pending, "answered"); + pending.resolve(payload.answer); + return Promise.resolve({ accepted: true }); + } + }; +} +//#endregion +//#region lib/types/api/downloads.schema.js +/** +* downloads domain zod schemas. The download surface has no wire +* envelope: the request arrives as query parameters (all strings), so its +* request schema parses the raw query-parameter object into the method's +* exact request shape. SessionId brand cast point: sessionIdSchema, and only +* there (hosted in sessions.schema like every other cast). +*/ +/** +* session.export query params → the sessionLog request. `includeDescendants` +* accepts exactly `true`/`false`/absent; any other value is rejected (400) so +* a misspelled flag cannot silently under-export. +*/ +const sessionLogQuerySchema = z$1.object({ + sessionId: sessionIdSchema, + includeDescendants: z$1.union([z$1.literal("true"), z$1.literal("false")]).optional() +}).transform((query) => ({ + sessionId: query.sessionId, + ...query.includeDescendants === "true" ? { includeDescendants: true } : {} +})); +//#endregion +//#region lib/types/api/rpc.schema.js +/** +* Message-layer zod schemas: the four wire full forms + error body + +* carrier receipt. The payload slot is unknown in the full-form schemas — business payloads +* get a second parse dispatched by method (two-level parse discipline). +* Brand cast point: rpcIdSchema, and only there. +*/ +/** +* RpcId: one brand cast after schema validation (the only cast point in this +* file). No min-length: the id is an opaque echo token, and rejecting values +* here would only turn a correlatable error report into a client-side parse +* failure (the handler substitutes a sentinel when a request's id is unreadable). +*/ +const rpcIdSchema = z$1.string(); +/** Error body: discriminated by code, per-branch details aligned to RpcErrorDetailsMap; details is required. */ +const rpcErrorSchema = z$1.discriminatedUnion("code", [ + z$1.object({ + code: z$1.literal("bad-request"), + message: z$1.string(), + details: z$1.object({ issues: z$1.array(z$1.custom()) }) + }), + z$1.object({ + code: z$1.literal("cancelled"), + message: z$1.string(), + details: z$1.object({}) + }), + z$1.object({ + code: z$1.literal("session-not-found"), + message: z$1.string(), + details: z$1.object({ sessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("model-unavailable"), + message: z$1.string(), + details: z$1.object({ + provider: z$1.string(), + model: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("session-conflict"), + message: z$1.string(), + details: z$1.object({ + sessionId: z$1.string(), + requestedCwd: z$1.string(), + existingCwd: z$1.string().optional() + }) + }), + z$1.object({ + code: z$1.literal("invalid-time-zone"), + message: z$1.string(), + details: z$1.object({ value: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("workspace-attach-failed"), + message: z$1.string(), + details: z$1.object({ + sessionId: z$1.string(), + workspaceId: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("workspace-not-found"), + message: z$1.string(), + details: z$1.object({ workspaceId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("workspace-invalid-path"), + message: z$1.string(), + details: z$1.object({ path: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("workspace-name-conflict"), + message: z$1.string(), + details: z$1.object({ name: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("workspace-move-invalid"), + message: z$1.string(), + details: z$1.object({ + workspaceId: z$1.string(), + sessionId: z$1.string(), + beforeSessionId: z$1.string().optional() + }) + }), + z$1.object({ + code: z$1.literal("directory-unreadable"), + message: z$1.string(), + details: z$1.object({ path: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("directory-exists"), + message: z$1.string(), + details: z$1.object({ path: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("directory-create-failed"), + message: z$1.string(), + details: z$1.object({ path: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("directory-picker-unavailable"), + message: z$1.string(), + details: z$1.object({ capability: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("agent-preset-read-only"), + message: z$1.string(), + details: z$1.object({ + agentPreset: z$1.string(), + reason: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("agent-preset-locked"), + message: z$1.string(), + details: z$1.object({ + sessionId: z$1.string(), + agentPreset: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("agent-preset-conflict"), + message: z$1.string(), + details: z$1.object({ + sessionId: z$1.string(), + requestedPreset: z$1.string(), + existingPreset: z$1.string().optional() + }) + }), + z$1.object({ + code: z$1.literal("agent-preset-not-found"), + message: z$1.string(), + details: z$1.object({ + agentPreset: z$1.string(), + available: z$1.array(z$1.string()) + }) + }), + z$1.object({ + code: z$1.literal("agent-preset-invalid"), + message: z$1.string(), + details: z$1.object({ + agentPreset: z$1.string(), + reason: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("agent-busy"), + message: z$1.string(), + details: z$1.object({ reason: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("attachment-error"), + message: z$1.string(), + details: z$1.object({ reason: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("queue-item-not-found"), + message: z$1.string(), + details: z$1.object({ itemId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("steer-unavailable"), + message: z$1.string(), + details: z$1.object({ itemId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("command-error"), + message: z$1.string(), + details: z$1.object({}) + }), + z$1.object({ + code: z$1.literal("unknown-command"), + message: z$1.string(), + details: z$1.object({}) + }), + z$1.object({ + code: z$1.literal("settings-rejected"), + message: z$1.string(), + details: z$1.object({ ns: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("settings-not-exposed"), + message: z$1.string(), + details: z$1.object({ ns: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("settings-conflict"), + message: z$1.string(), + details: z$1.object({ + ns: z$1.string(), + expected: z$1.number(), + actual: z$1.number() + }) + }), + z$1.object({ + code: z$1.literal("credential-rejected"), + message: z$1.string(), + details: z$1.object({ ref: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("model-discovery-failed"), + message: z$1.string(), + details: z$1.object({ + settingsNs: z$1.string(), + baseURL: z$1.string().optional() + }) + }), + z$1.object({ + code: z$1.literal("title-invalid"), + message: z$1.string(), + details: z$1.object({ sessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("fork-unavailable"), + message: z$1.string(), + details: z$1.object({ sessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("subagent-parent-unavailable"), + message: z$1.string(), + details: z$1.object({ parentSessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("subagent-not-found"), + message: z$1.string(), + details: z$1.object({ + parentSessionId: z$1.string(), + childSessionId: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("subagent-catalog-diagnostic"), + message: z$1.string(), + details: z$1.object({ + parentSessionId: z$1.string(), + childSessionId: z$1.string(), + reason: z$1.union([ + z$1.literal("corrupt"), + z$1.literal("unsupported"), + z$1.literal("unavailable") + ]) + }) + }), + z$1.object({ + code: z$1.literal("subagent-not-resumable"), + message: z$1.string(), + details: z$1.object({ childSessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("subagent-unauthorized"), + message: z$1.string(), + details: z$1.object({ childSessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("subagent-delivery-unavailable"), + message: z$1.string(), + details: z$1.object({ childSessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("internal"), + message: z$1.string(), + details: z$1.object({}) + }) +]); +/** +* Business success/failure result schema (generic, reusable). +* @param value - Schema for the business value. +* @returns Schema for RpcResult. +*/ +function rpcResultSchema(value) { + return z$1.union([z$1.object({ + ok: z$1.literal(true), + value + }), z$1.object({ + ok: z$1.literal(false), + error: rpcErrorSchema + })]); +} +/** ClientRequest full form (payload stays wide — the business layer runs the second parse). */ +const clientRequestSchema = z$1.object({ + type: z$1.literal("client-request"), + rpcId: rpcIdSchema, + method: z$1.string(), + payload: z$1.unknown() +}); +/** ServerResponse full form (result.value stays wide). */ +const serverResponseSchema = z$1.object({ + type: z$1.literal("server-response"), + rpcId: rpcIdSchema, + result: rpcResultSchema(z$1.unknown().optional()) +}); +/** ServerRequest full form (payload stays wide). */ +const serverRequestSchema = z$1.object({ + type: z$1.literal("server-request"), + rpcId: rpcIdSchema, + method: z$1.string(), + payload: z$1.unknown() +}); +/** ClientResponse full form (result.value stays wide). */ +const clientResponseSchema = z$1.object({ + type: z$1.literal("client-response"), + rpcId: rpcIdSchema, + result: rpcResultSchema(z$1.unknown().optional()) +}); +z$1.discriminatedUnion("type", [ + clientRequestSchema, + serverResponseSchema, + serverRequestSchema, + clientResponseSchema +]); +/** Carrier receipt schema. */ +const rpcReceiptSchema = z$1.union([z$1.object({ accepted: z$1.literal(true) }), z$1.object({ + accepted: z$1.literal(false), + reason: z$1.union([z$1.literal("not-pending"), z$1.literal("bad-response")]) +})]); +//#endregion +//#region lib/types/api/host.schema.js +/** +* host domain zod schemas (names derived from map keys). +*/ +/** host.describe request payload (empty object literal). */ +const hostDescribeRequestSchema = z$1.object({}); +/** host.describe response value. */ +const hostDescribeValueSchema = z$1.object({ + version: z$1.string(), + cwd: z$1.string(), + provider: z$1.string().optional(), + model: z$1.string().optional(), + attachedSessions: z$1.number().int().nonnegative(), + canOpenPath: z$1.boolean() +}); +/** host.pickDirectory request payload (empty object literal). */ +const hostPickDirectoryRequestSchema = z$1.object({}); +/** host.pickDirectory response value; null means the user cancelled. */ +const hostPickDirectoryValueSchema = z$1.object({ path: z$1.string().nullable() }); +/** Directory row shared by listing entries and breadcrumb crumbs. */ +const directoryEntrySchema = z$1.object({ + name: z$1.string(), + path: z$1.string(), + hidden: z$1.boolean() +}); +/** host.listDirectory request payload; an absent path lists the home directory. */ +const hostListDirectoryRequestSchema = z$1.object({ path: z$1.string().optional() }); +/** host.listDirectory response value. */ +const hostListDirectoryValueSchema = z$1.object({ + path: z$1.string(), + home: z$1.string(), + crumbs: z$1.array(directoryEntrySchema), + entries: z$1.array(directoryEntrySchema), + truncated: z$1.boolean() +}); +/** host.createDirectory request payload: name must be one plain path segment. */ +const hostCreateDirectoryRequestSchema = z$1.object({ + path: z$1.string(), + name: z$1.string() +}).refine((payload) => payload.name.trim() !== "" && payload.name !== "." && payload.name !== ".." && !/[/\\]/.test(payload.name), { message: "host.createDirectory requires a single non-blank path segment name" }); +/** host.createDirectory response value: the created directory's absolute path. */ +const hostCreateDirectoryValueSchema = z$1.object({ path: z$1.string() }); +/** host.openPath request payload. */ +const hostOpenPathRequestSchema = z$1.object({ path: z$1.string().min(1) }); +/** host.openPath response value. */ +const hostOpenPathValueSchema = z$1.object({ opened: z$1.literal(true) }); +//#endregion +//#region lib/types/api/workspace.schema.js +/** +* workspace domain zod schemas (names derived from map keys). The +* WorkspaceId brand cast lives in sessions.schema (see the note there) and +* is re-exported here as the domain-local name. +*/ +/** WorkspaceView row of every workspace.* response. */ +const workspaceViewSchema = z$1.object({ + workspaceId: workspaceIdSchema, + path: z$1.string(), + title: z$1.string(), + sessionIds: z$1.array(sessionIdSchema), + createdAt: z$1.string(), + updatedAt: z$1.string() +}); +/** workspace.list request payload (empty object literal). */ +const workspaceListRequestSchema = z$1.object({}); +/** workspace.list response value. */ +const workspaceListValueSchema = z$1.object({ + items: z$1.array(workspaceViewSchema), + archivedSessionIds: z$1.array(sessionIdSchema) +}); +/** workspace.create request payload: the existing directory to adopt. */ +const workspaceCreateRequestSchema = z$1.object({ path: z$1.string() }); +/** workspace.create response value. */ +const workspaceCreateValueSchema = z$1.object({ + workspace: workspaceViewSchema, + created: z$1.boolean() +}); +/** workspace.rename request payload: the new title must be non-blank. */ +const workspaceRenameRequestSchema = z$1.object({ + workspaceId: workspaceIdSchema, + title: z$1.string() +}).refine((payload) => payload.title.trim() !== "", { message: "workspace.rename requires a non-blank title" }); +/** workspace.rename response value. */ +const workspaceRenameValueSchema = z$1.object({ workspace: workspaceViewSchema }); +/** workspace.delete request payload. */ +const workspaceDeleteRequestSchema = z$1.object({ workspaceId: workspaceIdSchema }); +/** workspace.delete response value. */ +const workspaceDeleteValueSchema = z$1.object({ deleted: z$1.literal(true) }); +/** workspace.insertBefore request payload (anchor omitted = append to end). */ +const workspaceInsertBeforeRequestSchema = z$1.object({ + workspaceId: workspaceIdSchema, + beforeWorkspaceId: workspaceIdSchema.optional() +}); +/** workspace.insertBefore response value: the complete durable display order. */ +const workspaceInsertBeforeValueSchema = z$1.object({ workspaceIds: z$1.array(workspaceIdSchema) }); +/** workspace.insertSessionBefore request payload (anchor omitted = append to end). */ +const workspaceInsertSessionBeforeRequestSchema = z$1.object({ + workspaceId: workspaceIdSchema, + sessionId: sessionIdSchema, + beforeSessionId: sessionIdSchema.optional() +}); +/** workspace.insertSessionBefore response value. */ +const workspaceInsertSessionBeforeValueSchema = z$1.object({ workspace: workspaceViewSchema }); +/** workspace.archiveSession request payload. */ +const workspaceArchiveSessionRequestSchema = z$1.object({ sessionId: sessionIdSchema }); +/** workspace.archiveSession response value: the full updated archive set. */ +const workspaceArchiveSessionValueSchema = z$1.object({ archivedSessionIds: z$1.array(sessionIdSchema) }); +//#endregion +//#region lib/types/api/skills.schema.js +/** +* skills domain zod schemas (names derived from map keys: skillListRequestSchema / +* skillListValueSchema). +*/ +/** SkillEntry row of skill.list. */ +const skillEntrySchema = z$1.object({ + name: z$1.string().min(1), + description: z$1.string(), + whenToUse: z$1.string().optional(), + modelInvocable: z$1.boolean() +}); +/** skill.list request payload. */ +const skillListRequestSchema = z$1.object({ sessionId: sessionIdSchema }); +/** skill.list response value. */ +const skillListValueSchema = z$1.object({ skills: z$1.array(skillEntrySchema) }); +//#endregion +//#region lib/types/api/agent-presets.schema.js +/** +* agent-presets domain zod schemas (names derived from map keys: +* agentPresetListRequestSchema / agentPresetListValueSchema). +*/ +/** AgentPresetEntry row of agentPreset.list. */ +const agentPresetEntrySchema = z$1.object({ + id: z$1.string().min(1), + trust: z$1.union([z$1.literal("system"), z$1.literal("user")]), + isDefault: z$1.boolean(), + name: z$1.string().optional(), + description: z$1.string().optional(), + broken: z$1.string().min(1).optional() +}); +/** agentPreset.list request payload. */ +const agentPresetListRequestSchema = z$1.object({}); +/** agentPreset.list response value. */ +const agentPresetListValueSchema = z$1.object({ + presets: z$1.array(agentPresetEntrySchema), + authorable: z$1.boolean(), + hasDocument: z$1.boolean() +}); +/** agentPreset.select request payload. */ +const agentPresetSelectRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + agentPreset: z$1.string().min(1) +}); +/** agentPreset.select response value. */ +const agentPresetSelectValueSchema = z$1.object({ agentPreset: z$1.string() }); +/** agentPreset.read request payload. */ +const agentPresetReadRequestSchema = z$1.object({ agentPreset: z$1.string().min(1) }); +/** agentPreset.read response value. */ +const agentPresetReadValueSchema = z$1.object({ + agentPreset: z$1.string(), + trust: z$1.union([z$1.literal("system"), z$1.literal("user")]), + content: z$1.string(), + name: z$1.string().optional(), + description: z$1.string().optional() +}); +/** agentPreset.copy request payload. */ +const agentPresetCopyRequestSchema = z$1.object({ + from: z$1.string().min(1), + agentPreset: z$1.string().min(1), + name: z$1.string().optional() +}); +/** agentPreset.copy response value. */ +const agentPresetCopyValueSchema = z$1.object({ agentPreset: z$1.string() }); +/** agentPreset.openDocument request payload. */ +const agentPresetOpenDocumentRequestSchema = z$1.object({ agentPreset: z$1.string().min(1) }); +/** agentPreset.openDocument response value. */ +const agentPresetOpenDocumentValueSchema = z$1.union([z$1.object({ opened: z$1.literal(true) }), z$1.object({ + opened: z$1.literal(false), + path: z$1.string() +})]); +/** agentPreset.remove request payload. */ +const agentPresetRemoveRequestSchema = z$1.object({ agentPreset: z$1.string().min(1) }); +/** agentPreset.remove response value. */ +const agentPresetRemoveValueSchema = z$1.object({}); +//#endregion +//#region lib/types/api/goals.schema.js +/** +* goals domain zod schemas. Mutation-only shapes: every value schema is a +* `{ ref }` acknowledgement (clear: `{ cleared }`) — the current goal state +* travels exclusively on the 'goal' session projection. +*/ +/** GoalRef schema. */ +const goalRefSchema = z$1.object({ + id: z$1.string(), + revision: z$1.number().int().positive() +}); +/** Shared `{ ref }` acknowledgement value of every non-clear mutation. */ +const goalRefValueSchema = z$1.object({ ref: goalRefSchema }); +/** goal.create request payload. */ +const goalCreateRequestSchema = z$1.object({ + sessionId: z$1.string(), + objective: z$1.string().min(1), + maxGoalRounds: z$1.number().int().positive().optional() +}); +/** goal.create response value. */ +const goalCreateValueSchema = goalRefValueSchema; +/** goal.edit request payload. */ +const goalEditRequestSchema = z$1.object({ + sessionId: z$1.string(), + ref: goalRefSchema, + objective: z$1.string().min(1).optional(), + maxGoalRounds: z$1.number().int().positive().optional() +}).refine((value) => value.objective !== void 0 || value.maxGoalRounds !== void 0, { message: "goal.edit requires objective or maxGoalRounds" }); +/** goal.edit response value. */ +const goalEditValueSchema = goalRefValueSchema; +/** goal.pause request payload. */ +const goalPauseRequestSchema = z$1.object({ + sessionId: z$1.string(), + ref: goalRefSchema +}); +/** goal.pause response value. */ +const goalPauseValueSchema = goalRefValueSchema; +/** goal.resume request payload. */ +const goalResumeRequestSchema = z$1.object({ + sessionId: z$1.string(), + ref: goalRefSchema +}); +/** goal.resume response value. */ +const goalResumeValueSchema = goalRefValueSchema; +/** goal.complete request payload. */ +const goalCompleteRequestSchema = z$1.object({ + sessionId: z$1.string(), + ref: goalRefSchema +}); +/** goal.complete response value. */ +const goalCompleteValueSchema = goalRefValueSchema; +/** goal.clear request payload. */ +const goalClearRequestSchema = z$1.object({ + sessionId: z$1.string(), + ref: goalRefSchema +}); +/** goal.clear response value. */ +const goalClearValueSchema = z$1.object({ cleared: z$1.literal(true) }); +//#endregion +//#region lib/types/api/settings.schema.js +/** +* settings domain zod schemas (names derived from map keys: settingsDescribeRequestSchema / +* settingsDescribeValueSchema / settingsUpdate* / settingsReplace*). +*/ +/** One redacted secret slot. */ +const settingsSecretViewSchema = z$1.object({ + path: z$1.array(z$1.string()), + set: z$1.boolean() +}); +/** SettingsNamespaceView row of settings.describe and the write responses. */ +const settingsNamespaceViewSchema = z$1.object({ + ns: z$1.string().min(1), + schema: z$1.unknown(), + value: z$1.unknown(), + base: z$1.unknown().optional(), + user: z$1.unknown().optional(), + applies: z$1.union([z$1.literal("live"), z$1.literal("restart")]), + secrets: z$1.array(settingsSecretViewSchema), + revision: z$1.number() +}); +/** settings.describe request payload. */ +const settingsDescribeRequestSchema = z$1.object({}); +/** settings.describe response value. */ +const settingsDescribeValueSchema = z$1.object({ + writable: z$1.boolean(), + hasDocument: z$1.boolean(), + namespaces: z$1.array(settingsNamespaceViewSchema) +}); +/** settings.openDocument request payload. */ +const settingsOpenDocumentRequestSchema = z$1.object({}); +/** settings.openDocument response value. */ +const settingsOpenDocumentValueSchema = z$1.object({ opened: z$1.literal(true) }); +/** settings.update request payload. */ +const settingsUpdateRequestSchema = z$1.object({ + ns: z$1.string().min(1), + patch: z$1.record(z$1.string(), z$1.unknown()), + expectedRevision: z$1.number().optional() +}); +/** settings.update response value: the namespace's new redacted view. */ +const settingsUpdateValueSchema = settingsNamespaceViewSchema; +/** settings.replace request payload. */ +const settingsReplaceRequestSchema = z$1.object({ + ns: z$1.string().min(1), + section: z$1.record(z$1.string(), z$1.unknown()), + expectedRevision: z$1.number().optional() +}); +/** One path-addressed edit of settings.mutate. */ +const settingsPathOpSchema = z$1.discriminatedUnion("op", [z$1.object({ + op: z$1.literal("set"), + path: z$1.array(z$1.string()), + value: z$1.unknown() +}), z$1.object({ + op: z$1.literal("unset"), + path: z$1.array(z$1.string()) +})]); +/** settings.mutate request payload. */ +const settingsMutateRequestSchema = z$1.object({ + ns: z$1.string().min(1), + ops: z$1.array(settingsPathOpSchema), + expectedRevision: z$1.number().optional() +}); +/** settings.mutate response value: the namespace's new redacted view. */ +const settingsMutateValueSchema = settingsNamespaceViewSchema; +/** settings.replace response value. */ +const settingsReplaceValueSchema = settingsNamespaceViewSchema; +//#endregion +//#region lib/types/api/credentials.schema.js +/** +* credentials domain zod schemas (names derived from map keys: +* credentialsDescribeRequestSchema / credentialsDescribeValueSchema / …). +* The reference-name pattern mirrors the seam's `credentialRef` guard so an +* invalid name fails as `bad-request` before reaching the service. +*/ +/** POSIX-portable environment-variable name (the seam's `credentialRef` pattern). */ +const credentialRefNameSchema = z$1.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/); +/** CredentialView entry of credentials.describe. */ +const credentialViewSchema = z$1.object({ + configured: z$1.boolean(), + source: z$1.string().optional(), + writable: z$1.boolean() +}); +/** credentials.describe request payload. */ +const credentialsDescribeRequestSchema = z$1.object({ refs: z$1.array(credentialRefNameSchema).max(64) }); +/** credentials.describe response value. */ +const credentialsDescribeValueSchema = z$1.object({ credentials: z$1.record(z$1.string(), credentialViewSchema) }); +/** credentials.set request payload: the one direction a value crosses this wire. */ +const credentialsSetRequestSchema = z$1.object({ + ref: credentialRefNameSchema, + value: z$1.string().min(1) +}); +/** credentials.set response value. */ +const credentialsSetValueSchema = z$1.object({}); +/** credentials.unset request payload. */ +const credentialsUnsetRequestSchema = z$1.object({ ref: credentialRefNameSchema }); +/** credentials.unset response value. */ +const credentialsUnsetValueSchema = z$1.object({}); +//#endregion +//#region lib/types/api/llm.schema.js +/** +* llm domain zod schemas (names derived from map keys: llmProvidersRequestSchema / +* llmProvidersValueSchema / llmModelsRequestSchema / llmModelsValueSchema). +*/ +/** ConfigurableProviderView row of llm.providers. */ +const configurableProviderViewSchema = z$1.object({ + provider: z$1.string().min(1), + displayName: z$1.string().min(1), + settingsNs: z$1.string(), + settingsPath: z$1.array(z$1.string()), + active: z$1.boolean(), + declared: z$1.boolean().optional() +}); +/** llm.providers request payload. */ +const llmProvidersRequestSchema = z$1.object({}); +/** llm.providers response value. */ +const llmProvidersValueSchema = z$1.object({ providers: z$1.array(configurableProviderViewSchema) }); +/** llm.models request payload. */ +const llmModelsRequestSchema = z$1.object({}); +/** llm.models response value. */ +const llmModelsValueSchema = z$1.object({ + groups: z$1.array(modelProviderGroupSchema), + failures: z$1.array(modelCatalogFailureSchema) +}); +/** DiscoveredModelView row of llm.discoverModels. */ +const discoveredModelViewSchema = z$1.object({ + id: z$1.string().min(1), + name: z$1.string().min(1).optional(), + contextWindow: z$1.number().int().positive().optional(), + maxTokens: z$1.number().int().positive().optional() +}); +/** llm.discoverModels request payload. */ +const llmDiscoverModelsRequestSchema = z$1.object({ + settingsNs: z$1.string().min(1), + provider: z$1.string().min(1).optional(), + baseURL: z$1.string().min(1).optional(), + api: z$1.string().min(1).optional(), + apiKey: z$1.string().min(1).optional() +}); +/** llm.discoverModels response value. */ +const llmDiscoverModelsValueSchema = z$1.object({ models: z$1.array(discoveredModelViewSchema) }); +//#endregion +//#region lib/types/api/subagents.schema.js +/** Zod schemas for the browser-safe subagent domain. */ +/** Healthy and diagnostic durable catalog rows. */ +const subagentListEntrySchema = z$1.union([ + z$1.object({ + kind: z$1.literal("child"), + id: sessionIdSchema, + mode: z$1.literal("one-shot"), + activity: z$1.union([z$1.literal("running"), z$1.literal("inactive")]), + hasChildren: z$1.boolean(), + label: z$1.string().optional() + }), + z$1.object({ + kind: z$1.literal("child"), + id: sessionIdSchema, + mode: z$1.literal("continuable"), + activity: z$1.union([z$1.literal("running"), z$1.literal("inactive")]), + hasChildren: z$1.boolean(), + label: z$1.string() + }), + z$1.object({ + kind: z$1.literal("diagnostic"), + id: sessionIdSchema, + reason: z$1.union([ + z$1.literal("corrupt"), + z$1.literal("unsupported"), + z$1.literal("unavailable") + ]) + }) +]); +/** subagent.list request payload. */ +const subagentListRequestSchema = z$1.object({ parentSessionId: sessionIdSchema }); +/** subagent.list response value. */ +const subagentListValueSchema = z$1.object({ + entries: z$1.array(subagentListEntrySchema), + parentAvailable: z$1.boolean() +}); +/** subagent.history request payload. */ +const subagentHistoryRequestSchema = z$1.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z$1.union([z$1.literal("one-shot"), z$1.literal("continuable")]), + beforeSeq: z$1.number().int().nonnegative().optional(), + maxMessages: z$1.number().int().positive().optional() +}); +/** subagent.history response value. */ +const subagentHistoryValueSchema = z$1.object({ + events: z$1.array(historyEntrySchema), + hasMore: z$1.boolean(), + projections: sessionProjectionsBlockSchema.optional() +}); +/** subagent.prompt request payload. */ +const subagentPromptRequestSchema = z$1.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z$1.literal("continuable"), + content: z$1.array(contentBlockSchema), + clientTimeZone: z$1.string().optional() +}); +/** subagent.interrupt request payload. */ +const subagentInterruptRequestSchema = z$1.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z$1.literal("continuable") +}); +/** subagent.interrupt response value. */ +const subagentInterruptValueSchema = z$1.object({ accepted: z$1.literal(true) }); +const messageIdSchema = z$1.string(); +/** subagent.prompt response value. */ +const subagentPromptValueSchema = z$1.object({ messageId: messageIdSchema }); +//#endregion +//#region lib/types/fetch/handler.js +/** +* Server side of the fetch carrier: maps an ApiProxy onto a pure +* WHATWG Request->Response function. Two-level parse: full form (type/rpcId/method + +* path==method) -> payload dispatched per method. HTTP status expresses only the carrier +* (404 unknown path / 415 non-JSON media type / 400 non-JSON body / 500 handler crash); +* business errors are always 200 + ServerResponse. +*/ +const UNARY_ROUTES = { + "session.list": { + schema: sessionListRequestSchema, + invoke: (api, r) => api.sessions.list(r) + }, + "session.search": { + schema: sessionSearchRequestSchema, + invoke: (api, r, signal) => api.sessions.search(r, signal) + }, + "session.create": { + schema: sessionCreateRequestSchema, + invoke: (api, r) => api.sessions.create(r) + }, + "session.history": { + schema: sessionHistoryRequestSchema, + invoke: (api, r) => api.sessions.history(r) + }, + "session.models": { + schema: sessionModelsRequestSchema, + invoke: (api, r) => api.sessions.models(r) + }, + "session.selectModel": { + schema: sessionSelectModelRequestSchema, + invoke: (api, r) => api.sessions.selectModel(r) + }, + "session.rename": { + schema: sessionRenameRequestSchema, + invoke: (api, r) => api.sessions.rename(r) + }, + "session.fork": { + schema: sessionForkRequestSchema, + invoke: (api, r) => api.sessions.fork(r) + }, + "session.prompt": { + schema: sessionPromptRequestSchema, + invoke: (api, r) => api.sessions.prompt(r) + }, + "session.attachment": { + schema: sessionAttachmentRequestSchema, + invoke: (api, r) => api.sessions.attachment(r) + }, + "session.updateQueue": { + schema: sessionUpdateQueueRequestSchema, + invoke: (api, r) => api.sessions.updateQueue(r) + }, + "session.cancel": { + schema: sessionCancelRequestSchema, + invoke: (api, r) => api.sessions.cancel(r) + }, + "subagent.list": { + schema: subagentListRequestSchema, + invoke: (api, r, signal) => api.subagents.list(r, signal) + }, + "subagent.history": { + schema: subagentHistoryRequestSchema, + invoke: (api, r, signal) => api.subagents.history(r, signal) + }, + "subagent.prompt": { + schema: subagentPromptRequestSchema, + invoke: (api, r, signal) => api.subagents.prompt(r, signal) + }, + "subagent.interrupt": { + schema: subagentInterruptRequestSchema, + invoke: (api, r) => api.subagents.interrupt(r) + }, + "host.describe": { + schema: hostDescribeRequestSchema, + invoke: (api, r) => api.host.describe(r) + }, + "host.pickDirectory": { + schema: hostPickDirectoryRequestSchema, + invoke: (api, r, signal) => api.host.pickDirectory(r, signal) + }, + "host.listDirectory": { + schema: hostListDirectoryRequestSchema, + invoke: (api, r, signal) => api.host.listDirectory(r, signal) + }, + "host.createDirectory": { + schema: hostCreateDirectoryRequestSchema, + invoke: (api, r) => api.host.createDirectory(r) + }, + "host.openPath": { + schema: hostOpenPathRequestSchema, + invoke: (api, r, signal) => api.host.openPath(r, signal) + }, + "workspace.list": { + schema: workspaceListRequestSchema, + invoke: (api, r) => api.workspace.list(r) + }, + "workspace.create": { + schema: workspaceCreateRequestSchema, + invoke: (api, r) => api.workspace.create(r) + }, + "workspace.rename": { + schema: workspaceRenameRequestSchema, + invoke: (api, r) => api.workspace.rename(r) + }, + "workspace.delete": { + schema: workspaceDeleteRequestSchema, + invoke: (api, r) => api.workspace.delete(r) + }, + "workspace.insertBefore": { + schema: workspaceInsertBeforeRequestSchema, + invoke: (api, r) => api.workspace.insertBefore(r) + }, + "workspace.insertSessionBefore": { + schema: workspaceInsertSessionBeforeRequestSchema, + invoke: (api, r) => api.workspace.insertSessionBefore(r) + }, + "workspace.archiveSession": { + schema: workspaceArchiveSessionRequestSchema, + invoke: (api, r) => api.workspace.archiveSession(r) + }, + "skill.list": { + schema: skillListRequestSchema, + invoke: (api, r) => api.skills.list(r) + }, + "agentPreset.list": { + schema: agentPresetListRequestSchema, + invoke: (api, r) => api.agentPresets.list(r) + }, + "agentPreset.select": { + schema: agentPresetSelectRequestSchema, + invoke: (api, r) => api.agentPresets.select(r) + }, + "agentPreset.read": { + schema: agentPresetReadRequestSchema, + invoke: (api, r) => api.agentPresets.read(r) + }, + "agentPreset.copy": { + schema: agentPresetCopyRequestSchema, + invoke: (api, r) => api.agentPresets.copy(r) + }, + "agentPreset.openDocument": { + schema: agentPresetOpenDocumentRequestSchema, + invoke: (api, r, signal) => api.agentPresets.openDocument(r, signal) + }, + "agentPreset.remove": { + schema: agentPresetRemoveRequestSchema, + invoke: (api, r) => api.agentPresets.remove(r) + }, + "goal.create": { + schema: goalCreateRequestSchema, + invoke: (api, r) => api.goals.create(r) + }, + "goal.edit": { + schema: goalEditRequestSchema, + invoke: (api, r) => api.goals.edit(r) + }, + "goal.pause": { + schema: goalPauseRequestSchema, + invoke: (api, r) => api.goals.pause(r) + }, + "goal.resume": { + schema: goalResumeRequestSchema, + invoke: (api, r) => api.goals.resume(r) + }, + "goal.complete": { + schema: goalCompleteRequestSchema, + invoke: (api, r) => api.goals.complete(r) + }, + "goal.clear": { + schema: goalClearRequestSchema, + invoke: (api, r) => api.goals.clear(r) + }, + "settings.describe": { + schema: settingsDescribeRequestSchema, + invoke: (api, r) => api.settings.describe(r) + }, + "settings.openDocument": { + schema: settingsOpenDocumentRequestSchema, + invoke: (api, r, signal) => api.settings.openDocument(r, signal) + }, + "settings.update": { + schema: settingsUpdateRequestSchema, + invoke: (api, r) => api.settings.update(r) + }, + "settings.replace": { + schema: settingsReplaceRequestSchema, + invoke: (api, r) => api.settings.replace(r) + }, + "settings.mutate": { + schema: settingsMutateRequestSchema, + invoke: (api, r) => api.settings.mutate(r) + }, + "credentials.describe": { + schema: credentialsDescribeRequestSchema, + invoke: (api, r) => api.credentials.describe(r) + }, + "credentials.set": { + schema: credentialsSetRequestSchema, + invoke: (api, r) => api.credentials.set(r) + }, + "credentials.unset": { + schema: credentialsUnsetRequestSchema, + invoke: (api, r) => api.credentials.unset(r) + }, + "llm.providers": { + schema: llmProvidersRequestSchema, + invoke: (api, r) => api.llm.providers(r) + }, + "llm.models": { + schema: llmModelsRequestSchema, + invoke: (api, r) => api.llm.models(r) + }, + "llm.discoverModels": { + schema: llmDiscoverModelsRequestSchema, + invoke: (api, r, signal) => api.llm.discoverModels(r, signal) + } +}; +/** Route lookup that narrows an arbitrary path segment to a map key (single cast point for the string→key refinement). */ +function methodFor(path) { + return Object.hasOwn(UNARY_ROUTES, path) ? path : void 0; +} +/** +* Sentinel rpcId for error responses to envelopes whose own rpcId is unreadable: the response +* must still be a valid ServerResponse (a self-violating shape would turn the server's explicit +* bad-request report into a client-side parse failure). Fixed value, documented here as wire contract. +*/ +const INVALID_REQUEST_RPC_ID = RpcId("invalid-request"); +/** Wrap a business error as a ServerResponse full form (rpcId backfilled; an unreadable rpcId uses the invalid-request sentinel). */ +function errorResponse(rpcId, error) { + const body = { + type: "server-response", + rpcId, + result: { + ok: false, + error + } + }; + return Response.json(body); +} +/** Complete the impl's narrow form into a ServerResponse full form. */ +function fullResponse(narrow) { + const body = { + type: "server-response", + rpcId: narrow.rpcId, + result: narrow.result + }; + return Response.json(body); +} +/** +* Parse the payload and invoke one unary route. Generic over the map key so +* the row's schema/invoke pairing typechecks; the only cast collapses the +* Wire<> widening back to the exact payload (undefined-valued properties and +* absent ones are indistinguishable after JSON transport). +*/ +async function handleUnary(api, method, message, signal) { + const route = UNARY_ROUTES[method]; + const payload = route.schema.safeParse(message.payload); + if (!payload.success) return errorResponse(message.rpcId, { + code: "bad-request", + message: `invalid payload for ${method}`, + details: { issues: payload.error.issues } + }); + try { + return fullResponse(await route.invoke(api, { + rpcId: message.rpcId, + payload: payload.data + }, signal)); + } catch (error) { + return new Response(`handler failure: ${String(error)}`, { status: 500 }); + } +} +/** SSE frame: complete the narrow RpcRequest into a ServerRequest full form (method = frame type). */ +function fullFrame(narrow) { + return { + type: "server-request", + rpcId: narrow.rpcId, + method: narrow.payload.type, + payload: narrow.payload + }; +} +/** +* Wrap a frame stream as an SSE Response; stops when req.signal aborts. An +* impl throw mid-stream emits one stream/error frame and then closes. +*/ +function sseResponse(frames) { + const encoder = new TextEncoder(); + const stream = new ReadableStream({ async start(controller) { + try { + controller.enqueue(encoder.encode(": connected\n\n")); + for await (const narrow of frames) controller.enqueue(encoder.encode(`data: ${JSON.stringify(fullFrame(narrow))}\n\n`)); + } catch (error) { + const failure = { + type: "stream/error", + error: { + code: "internal", + message: String(error), + details: {} + } + }; + try { + controller.enqueue(encoder.encode(`data: ${JSON.stringify(fullFrame({ + rpcId: RpcId(randomUUID()), + payload: failure + }))}\n\n`)); + } catch {} + } finally { + try { + controller.close(); + } catch {} + } + } }); + return new Response(stream, { headers: { + "content-type": "text/event-stream", + "cache-control": "no-cache" + } }); +} +/** +* Wraps an ApiProxy into a pure fetch function (isomorphic point: feed the returned fetch straight to InProcessApiClient). +* @param api - the host-side ApiProxy implementation. +* @returns an object holding `fetch(Request)`; paths outside /api/ return 404. +*/ +function toFetchHandler(api) { + return { async fetch(input, init) { + const req = input instanceof Request ? input : new Request(input, init); + const url = new URL(req.url); + const path = url.pathname; + if (path === "/api/events.mux" && req.method === "GET") return sseResponse(api.events.mux({ + rpcId: RpcId(randomUUID()), + payload: {} + }, req.signal)); + if (path === "/api/events.host" && req.method === "GET") return sseResponse(api.events.host({ + rpcId: RpcId(randomUUID()), + payload: {} + }, req.signal)); + if (path === "/api/session.export" && (req.method === "GET" || req.method === "HEAD")) { + const parsed = sessionLogQuerySchema.safeParse(Object.fromEntries(url.searchParams)); + if (!parsed.success) return new Response("missing or invalid sessionId query parameter", { status: 400 }); + const response = await api.downloads.sessionLog(parsed.data, req.signal); + if (req.method === "GET") return response; + await response.body?.cancel(); + return new Response(null, { + status: response.status, + headers: response.headers + }); + } + if (req.method !== "POST" || !path.startsWith("/api/")) return new Response("not found", { status: 404 }); + if (req.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() !== "application/json") return new Response("content type must be application/json", { status: 415 }); + let body; + try { + body = await req.json(); + } catch { + return new Response("body is not JSON", { status: 400 }); + } + if (path === "/api/respond") { + const parsed = clientResponseSchema.safeParse(body); + if (!parsed.success) return Response.json({ + accepted: false, + reason: "bad-response" + }); + return Response.json(await api.respond(parsed.data)); + } + const method = methodFor(path.slice(5)); + if (method === void 0) return new Response("not found", { status: 404 }); + const envelope = clientRequestSchema.safeParse(body); + if (!envelope.success) { + const rawId = body?.rpcId; + return errorResponse(typeof rawId === "string" ? RpcId(rawId) : INVALID_REQUEST_RPC_ID, { + code: "bad-request", + message: "invalid client-request message", + details: { issues: envelope.error.issues } + }); + } + const message = envelope.data; + if (message.method !== method) return errorResponse(message.rpcId, { + code: "bad-request", + message: `method "${message.method}" does not match path "${method}"`, + details: { issues: [] } + }); + return handleUnary(api, method, message, req.signal); + } }; +} +//#endregion +//#region lib/types/api/jobs.schema.js +/** +* tasks domain zod schemas: the branded job id and the wire view carried by +* `session/jobs` frames. +*/ +/** JobId: one brand cast after non-empty string validation. */ +const taskIdSchema = z$1.string().min(1); +/** +* One wire task view. `kind` stays an open string because producer plugins +* extend the registry's kind map by declaration merging, so the closed set is +* not knowable at this boundary. +*/ +const taskViewSchema = z$1.object({ + id: taskIdSchema, + kind: z$1.string().min(1), + label: z$1.string().min(1), + status: z$1.union([ + z$1.literal("running"), + z$1.literal("stopping"), + z$1.literal("completed"), + z$1.literal("killed"), + z$1.literal("failed") + ]), + detail: z$1.string().optional(), + startedAt: z$1.number().int().nonnegative(), + finishedAt: z$1.number().int().nonnegative().optional() +}); +//#endregion +//#region lib/types/api/events.schema.js +/** +* events domain zod schemas: MuxFrame / HostFrame unions (discriminatedUnion('type')). +* A frame is the payload slot of the ServerRequest full form; the SessionEvent inside +* a session/event frame reuses sessions.schema's strict-envelope + wide-data passthrough branch. +*/ +/** Question fields validated strictly against core dsh-user-questions. */ +const askUserQuestionItemSchema = z$1.object({ + id: z$1.string(), + question: z$1.string(), + header: z$1.string().optional(), + detail: z$1.string().optional(), + options: z$1.array(z$1.object({ + label: z$1.string(), + description: z$1.string().optional() + })).optional(), + multiSelect: z$1.boolean().optional(), + intent: z$1.discriminatedUnion("kind", [z$1.object({ + kind: z$1.literal("plan-review"), + approve: z$1.string() + })]).optional() +}); +/** Unified message envelope carried by transient queue frames. */ +const messageSchema = z$1.object({ + id: z$1.string().min(1), + role: z$1.union([ + z$1.literal("system"), + z$1.literal("user"), + z$1.literal("assistant") + ]), + content: z$1.array(contentBlockSchema), + source: z$1.looseObject({ kind: z$1.string() }) +}); +/** MuxFrame union (payload slot of a mux-stream ServerRequest). */ +const muxFrameSchema = z$1.discriminatedUnion("type", [ + z$1.object({ + type: z$1.literal("session/event"), + sessionId: sessionIdSchema, + event: sessionEventSchema, + view: toolEventViewSchema.optional() + }), + z$1.object({ + type: z$1.literal("session/subscribed"), + sessionId: sessionIdSchema, + lastSeq: z$1.number().int() + }), + z$1.object({ + type: z$1.literal("approval/requested"), + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + toolName: z$1.string(), + callId: z$1.string().optional(), + reason: z$1.string().optional() + }), + z$1.object({ + type: z$1.literal("approval/resolved"), + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + outcome: z$1.union([ + z$1.literal("allowed-once"), + z$1.literal("rejected"), + z$1.literal("cancelled"), + z$1.literal("unavailable") + ]) + }), + z$1.object({ + type: z$1.literal("question/requested"), + sessionId: sessionIdSchema, + questions: z$1.array(askUserQuestionItemSchema).min(1) + }), + z$1.object({ + type: z$1.literal("question/resolved"), + sessionId: sessionIdSchema, + questionRpcId: rpcIdSchema, + outcome: z$1.union([z$1.literal("answered"), z$1.literal("cancelled")]) + }), + z$1.object({ + type: z$1.literal("session/queue"), + sessionId: sessionIdSchema, + items: z$1.array(z$1.object({ + id: messageIdSchema$1, + placement: z$1.union([ + z$1.literal("queued"), + z$1.literal("steering"), + z$1.literal("context") + ]), + message: messageSchema + })) + }), + z$1.object({ + type: z$1.literal("session/jobs"), + sessionId: sessionIdSchema, + jobs: z$1.array(taskViewSchema) + }), + z$1.object({ + type: z$1.literal("session/projection"), + sessionId: sessionIdSchema, + key: z$1.string().min(1), + value: z$1.unknown(), + seq: z$1.number().int().nonnegative() + }), + z$1.object({ + type: z$1.literal("stream/error"), + error: rpcErrorSchema + }) +]); +/** HostFrame union (payload slot of a host-stream ServerRequest). */ +const hostFrameSchema = z$1.discriminatedUnion("type", [ + z$1.object({ + type: z$1.literal("host/session-added"), + sessionId: sessionIdSchema, + blank: z$1.boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: z$1.literal("subagent").optional(), + cwd: z$1.string().optional(), + agentPreset: z$1.string().optional() + }), + z$1.object({ + type: z$1.literal("host/session-removed"), + sessionId: sessionIdSchema + }), + z$1.object({ + type: z$1.literal("host/session-status"), + sessionId: sessionIdSchema, + running: z$1.boolean() + }), + z$1.object({ + type: z$1.literal("host/agent-error"), + sessionId: sessionIdSchema, + message: z$1.string() + }), + z$1.object({ + type: z$1.literal("host/workspace-changed"), + workspace: workspaceViewSchema + }), + z$1.object({ + type: z$1.literal("host/workspace-removed"), + workspaceId: workspaceIdSchema + }), + z$1.object({ + type: z$1.literal("host/workspace-order-changed"), + workspaceIds: z$1.array(workspaceIdSchema) + }), + z$1.object({ + type: z$1.literal("host/archived-sessions-changed"), + archivedSessionIds: z$1.array(sessionIdSchema) + }), + z$1.object({ + type: z$1.literal("host/remote-event"), + event: z$1.string().min(1), + args: z$1.array(z$1.unknown()) + }), + z$1.object({ + type: z$1.literal("stream/error"), + error: rpcErrorSchema + }) +]); +//#endregion +//#region lib/types/fetch/client.js +/** +* Client side of the fetch carrier. AbstractApiClient holds every protocol invariant: rpcId minting, +* four-quadrant envelope wrap/unwrap, zod parsing, in-process SSE frame decoding, and the payload-direct +* IApiClient domain methods (business code never mints). Platform differences ride two aspects: +* abstract doFetch (transport) + overridable onEnvelope (tap). ApiProxy (the impl face) is untouched. +*/ +/** +* S→C second-level parse table: value schema by method (the response-path +* mirror of the handler's request table; key coverage compiler-enforced against RpcMethodMap). +*/ +const UNARY_VALUE_SCHEMAS = { + "session.list": sessionListValueSchema, + "session.search": sessionSearchValueSchema, + "session.create": sessionCreateValueSchema, + "session.history": sessionHistoryValueSchema, + "session.models": sessionModelsValueSchema, + "session.selectModel": sessionSelectModelValueSchema, + "session.rename": sessionRenameValueSchema, + "session.fork": sessionForkValueSchema, + "session.prompt": sessionPromptValueSchema, + "session.attachment": sessionAttachmentValueSchema, + "session.updateQueue": sessionUpdateQueueValueSchema, + "session.cancel": sessionCancelValueSchema, + "subagent.list": subagentListValueSchema, + "subagent.history": subagentHistoryValueSchema, + "subagent.prompt": subagentPromptValueSchema, + "subagent.interrupt": subagentInterruptValueSchema, + "host.describe": hostDescribeValueSchema, + "host.pickDirectory": hostPickDirectoryValueSchema, + "host.listDirectory": hostListDirectoryValueSchema, + "host.createDirectory": hostCreateDirectoryValueSchema, + "host.openPath": hostOpenPathValueSchema, + "workspace.list": workspaceListValueSchema, + "workspace.create": workspaceCreateValueSchema, + "workspace.rename": workspaceRenameValueSchema, + "workspace.delete": workspaceDeleteValueSchema, + "workspace.insertBefore": workspaceInsertBeforeValueSchema, + "workspace.insertSessionBefore": workspaceInsertSessionBeforeValueSchema, + "workspace.archiveSession": workspaceArchiveSessionValueSchema, + "skill.list": skillListValueSchema, + "agentPreset.list": agentPresetListValueSchema, + "agentPreset.select": agentPresetSelectValueSchema, + "agentPreset.read": agentPresetReadValueSchema, + "agentPreset.copy": agentPresetCopyValueSchema, + "agentPreset.openDocument": agentPresetOpenDocumentValueSchema, + "agentPreset.remove": agentPresetRemoveValueSchema, + "goal.create": goalCreateValueSchema, + "goal.edit": goalEditValueSchema, + "goal.pause": goalPauseValueSchema, + "goal.resume": goalResumeValueSchema, + "goal.complete": goalCompleteValueSchema, + "goal.clear": goalClearValueSchema, + "settings.describe": settingsDescribeValueSchema, + "settings.openDocument": settingsOpenDocumentValueSchema, + "settings.update": settingsUpdateValueSchema, + "settings.replace": settingsReplaceValueSchema, + "settings.mutate": settingsMutateValueSchema, + "credentials.describe": credentialsDescribeValueSchema, + "credentials.set": credentialsSetValueSchema, + "credentials.unset": credentialsUnsetValueSchema, + "llm.providers": llmProvidersValueSchema, + "llm.models": llmModelsValueSchema, + "llm.discoverModels": llmDiscoverModelsValueSchema +}; +/** Default timeout for bounded unary calls (rpc-compare 2026-07-19: a hung host must not leave callers pending forever). */ +const DEFAULT_TIMEOUT_MS = 3e4; +/** URL base for in-process handler injection (fake authority, opencode precedent). */ +const INTERNAL_BASE = "http://dsh.internal"; +/** +* Abstract fetch-carrier client. Subclasses supply the transport (doFetch) and may refine the +* per-message tap (onEnvelope) — platform aspects stay in subclasses, protocol invariants stay +* here. Envelope observation is a first-class aspect of this data middle layer: the instance +* owns a microtask-batched buffer (frame storms must not cost one consumer update per frame), +* and observers subscribe via subscribeEnvelopes. The isomorphic point survives: an in-process +* subclass whose doFetch is toFetchHandler(api).fetch never touches the network. +*/ +var AbstractApiClient = class { + timeoutMs; + /** Instance-owned observation buffer (module-level state would leak across instances/tests). */ + envelopeBatch = []; + flushScheduled = false; + envelopeListeners = /* @__PURE__ */ new Set(); + /** @param timeoutMs - timeout for bounded unary calls; user-paced calls and streams do not use it. */ + constructor(timeoutMs = DEFAULT_TIMEOUT_MS) { + this.timeoutMs = timeoutMs; + } + /** + * Subscribe to batched envelope observation (diagnostics/logging consumers). + * Batches follow microtask boundaries; a listener throw is isolated (observation + * must never break the carrier). + * @param listener - receives each flushed batch in arrival order. + * @returns unsubscribe function. + */ + subscribeEnvelopes(listener) { + this.envelopeListeners.add(listener); + return () => { + this.envelopeListeners.delete(listener); + }; + } + /** Per-message tap: feeds the instance buffer. Subclasses may override to observe unbatched (call super to keep batching). */ + onEnvelope(message) { + if (this.envelopeListeners.size === 0) return; + this.envelopeBatch.push(message); + if (this.flushScheduled) return; + this.flushScheduled = true; + queueMicrotask(() => { + this.flushScheduled = false; + const batch = this.envelopeBatch; + this.envelopeBatch = []; + for (const notify of this.envelopeListeners) try { + notify(batch); + } catch (error) { + console.error("[apiproxy] envelope listener threw:", error); + } + }); + } + /** Browser = same-origin (a fake authority would fail DNS on real requests); no-location env (Node) = fake authority. */ + resolveBase() { + const loc = globalThis.location; + return loc?.origin !== void 0 && loc.origin !== "null" ? loc.origin : INTERNAL_BASE; + } + mintRpcId() { + return RpcId(crypto.randomUUID()); + } + /** + * Shared POST leg of both C→S carriers (callUnary/respond): JSON body, + * optional default timeout merged with the caller's external signal, non-2xx → transport throw. + */ + async postJson(path, body, signal, timeoutPolicy = "default") { + const requestSignal = timeoutPolicy === "default" ? signal === void 0 ? AbortSignal.timeout(this.timeoutMs) : AbortSignal.any([AbortSignal.timeout(this.timeoutMs), signal]) : signal; + const response = await this.doFetch(new URL(path, this.resolveBase()), { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), + ...requestSignal === void 0 ? {} : { signal: requestSignal } + }); + if (!response.ok) throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + return response; + } + /** + * Unary protocol path: mint → tap → POST full form → envelope parse → verify + * echo → value parse → tap → narrow. Virtual so a fake carrier (fixture) can + * override transport at this layer. + */ + async callUnary(method, payload, signal, timeoutPolicy = "default") { + const message = { + type: "client-request", + rpcId: this.mintRpcId(), + method, + payload + }; + this.onEnvelope(message); + const response = await this.postJson(`/api/${method}`, message, signal, timeoutPolicy); + const full = serverResponseSchema.parse(await response.json()); + this.onEnvelope(full); + if (full.rpcId !== message.rpcId) throw new Error(`rpcId mismatch for ${method}: sent ${message.rpcId}, got ${full.rpcId}`); + if (!full.result.ok) return { + rpcId: full.rpcId, + result: full.result + }; + const value = UNARY_VALUE_SCHEMAS[method].parse(full.result.value); + return { + rpcId: full.rpcId, + result: { + ok: true, + value + } + }; + } + /** Mux stream opener; virtual for the same override reason as callUnary. */ + openMux(_payload, signal, onOpen) { + return this.readSse("/api/events.mux", signal, muxFrameSchema, onOpen); + } + /** Host stream opener; virtual. */ + openHost(_payload, signal, onOpen) { + return this.readSse("/api/events.host", signal, hostFrameSchema, onOpen); + } + /** + * SSE protocol path: streaming fetch (not EventSource), '\n\n' framing, ServerRequest envelope + + * frame-schema parse, tap, narrow yield. onOpen fires once the response headers are in and the + * body is readable — the stream-established signal, before any frame arrives. A frame that fails + * either parse level is reported and skipped (one corrupt frame must not kill the stream; the + * client's gap detection covers whatever the frame carried). + */ + async *readSse(path, signal, frameSchema, onOpen) { + const response = await this.doFetch(new URL(path, this.resolveBase()), { signal }); + if (!response.ok || response.body === null) throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + onOpen?.(); + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let buffer = ""; + try { + while (true) { + const { done, value } = await reader.read(); + if (done) return; + buffer += decoder.decode(value, { stream: true }); + let boundary; + while ((boundary = buffer.indexOf("\n\n")) !== -1) { + const chunk = buffer.slice(0, boundary); + buffer = buffer.slice(boundary + 2); + const data = chunk.split("\n").filter((line) => line.startsWith("data: ")).map((line) => line.slice(6)).join(""); + if (data === "") continue; + let full; + let frame; + try { + full = serverRequestSchema.parse(JSON.parse(data)); + frame = frameSchema.parse(full.payload); + } catch (error) { + console.error(`[apiproxy] dropping malformed SSE frame on ${path}:`, error); + continue; + } + this.onEnvelope(full); + yield { + rpcId: full.rpcId, + payload: frame + }; + } + } + } finally { + await reader.cancel().catch(() => void 0); + } + } + sessions = { + list: (payload, signal) => this.callUnary("session.list", payload, signal), + search: (payload, signal) => this.callUnary("session.search", payload, signal), + create: (payload, signal) => this.callUnary("session.create", payload, signal), + history: (payload, signal) => this.callUnary("session.history", payload, signal), + models: (payload, signal) => this.callUnary("session.models", payload, signal), + selectModel: (payload, signal) => this.callUnary("session.selectModel", payload, signal), + rename: (payload, signal) => this.callUnary("session.rename", payload, signal), + fork: (payload, signal) => this.callUnary("session.fork", payload, signal), + prompt: (payload, signal) => this.callUnary("session.prompt", payload, signal), + attachment: (payload, signal) => this.callUnary("session.attachment", payload, signal), + updateQueue: (payload, signal) => this.callUnary("session.updateQueue", payload, signal), + cancel: (payload, signal) => this.callUnary("session.cancel", payload, signal) + }; + subagents = { + list: (payload, signal) => this.callUnary("subagent.list", payload, signal), + history: (payload, signal) => this.callUnary("subagent.history", payload, signal), + prompt: (payload, signal) => this.callUnary("subagent.prompt", payload, signal), + interrupt: (payload, signal) => this.callUnary("subagent.interrupt", payload, signal) + }; + host = { + describe: (payload, signal) => this.callUnary("host.describe", payload, signal), + pickDirectory: (payload, signal) => this.callUnary("host.pickDirectory", payload, signal, "caller-signal-only"), + listDirectory: (payload, signal) => this.callUnary("host.listDirectory", payload, signal), + createDirectory: (payload, signal) => this.callUnary("host.createDirectory", payload, signal), + openPath: (payload, signal) => this.callUnary("host.openPath", payload, signal) + }; + workspace = { + list: (payload, signal) => this.callUnary("workspace.list", payload, signal), + create: (payload, signal) => this.callUnary("workspace.create", payload, signal), + rename: (payload, signal) => this.callUnary("workspace.rename", payload, signal), + delete: (payload, signal) => this.callUnary("workspace.delete", payload, signal), + insertBefore: (payload, signal) => this.callUnary("workspace.insertBefore", payload, signal), + insertSessionBefore: (payload, signal) => this.callUnary("workspace.insertSessionBefore", payload, signal), + archiveSession: (payload, signal) => this.callUnary("workspace.archiveSession", payload, signal) + }; + skills = { list: (payload, signal) => this.callUnary("skill.list", payload, signal) }; + agentPresets = { + list: (payload, signal) => this.callUnary("agentPreset.list", payload, signal), + select: (payload, signal) => this.callUnary("agentPreset.select", payload, signal), + read: (payload, signal) => this.callUnary("agentPreset.read", payload, signal), + copy: (payload, signal) => this.callUnary("agentPreset.copy", payload, signal), + openDocument: (payload, signal) => this.callUnary("agentPreset.openDocument", payload, signal), + remove: (payload, signal) => this.callUnary("agentPreset.remove", payload, signal) + }; + goals = { + create: (payload, signal) => this.callUnary("goal.create", payload, signal), + edit: (payload, signal) => this.callUnary("goal.edit", payload, signal), + pause: (payload, signal) => this.callUnary("goal.pause", payload, signal), + resume: (payload, signal) => this.callUnary("goal.resume", payload, signal), + complete: (payload, signal) => this.callUnary("goal.complete", payload, signal), + clear: (payload, signal) => this.callUnary("goal.clear", payload, signal) + }; + settings = { + describe: (payload, signal) => this.callUnary("settings.describe", payload, signal), + openDocument: (payload, signal) => this.callUnary("settings.openDocument", payload, signal), + update: (payload, signal) => this.callUnary("settings.update", payload, signal), + replace: (payload, signal) => this.callUnary("settings.replace", payload, signal), + mutate: (payload, signal) => this.callUnary("settings.mutate", payload, signal) + }; + credentials = { + describe: (payload, signal) => this.callUnary("credentials.describe", payload, signal), + set: (payload, signal) => this.callUnary("credentials.set", payload, signal), + unset: (payload, signal) => this.callUnary("credentials.unset", payload, signal) + }; + llm = { + providers: (payload, signal) => this.callUnary("llm.providers", payload, signal), + models: (payload, signal) => this.callUnary("llm.models", payload, signal), + discoverModels: (payload, signal) => this.callUnary("llm.discoverModels", payload, signal) + }; + events = { + mux: (payload, signal, onOpen) => this.openMux(payload, signal, onOpen), + host: (payload, signal, onOpen) => this.openHost(payload, signal, onOpen) + }; + async respond(message, signal) { + this.onEnvelope(message); + const response = await this.postJson("/api/respond", message, signal); + return rpcReceiptSchema.parse(await response.json()); + } +}; +/** +* In-process client over an injected fetch-shaped handler (the isomorphic point: +* `new InProcessApiClient(toFetchHandler(api))` never touches the network). Lives here because +* in-process injection is this package's own capability (handler and client are both local). +*/ +var InProcessApiClient = class extends AbstractApiClient { + handler; + constructor(handler, timeoutMs) { + super(timeoutMs); + this.handler = handler; + } + /** + * Faithful to real fetch: reject on signal abort even when the in-process + * handler ignores the signal (a hung impl must not defeat timeout/cancel). + */ + doFetch(input, init) { + const signal = init?.signal ?? void 0; + if (signal === void 0) return this.handler.fetch(input, init); + if (signal.aborted) return Promise.reject(abortError(signal)); + return new Promise((resolve, reject) => { + const onAbort = () => { + reject(abortError(signal)); + }; + signal.addEventListener("abort", onAbort, { once: true }); + this.handler.fetch(input, init).then(resolve, reject).finally(() => { + signal.removeEventListener("abort", onAbort); + }); + }); + } +}; +/** Mirror fetch's abort rejection: the signal's reason when present, else a DOMException-style AbortError. */ +function abortError(signal) { + const reason = signal.reason; + if (reason instanceof Error) return reason; + if (typeof reason === "string") return new Error(reason); + return /* @__PURE__ */ new Error("This operation was aborted"); +} +//#endregion +//#region lib/types/index.js +/** +* @deepseek-ai/dsh-host-apiproxy — the API gateway every client shape shares: +* the ApiProxy contract (api/: types + zod schemas, browser-safe), the fetch +* carrier pair (fetch/: toFetchHandler on the host side, AbstractApiClient + +* platform subclasses on the client side), and the host-side implementation +* (api-proxy.ts: createApiProxy + the ApiProxyService gateway plugin providing +* `ctx.apiProxy`). Transport-agnostic by design: this package registers no +* routes — physical carriers wrap `ctx.apiProxy` themselves. +* +* The gateway consumes `ctx.agentDefaultModel`, the transport-independent default +* shared with direct entry points. Switching models persists through that +* service; sessions that have already logged a selection remain unchanged. +*/ +/** +* The API gateway service: implements the ApiProxy contract over the composed +* host context and provides it as `ctx.apiProxy`. The Host cwd is the default +* project directory. +*/ +var ApiProxyService = class extends Service { + static inject = [ + "agentDefaultModel", + "agents", + "attachments", + "directoryPicker", + "llm", + "sessions", + "subagents", + "sessionQuery", + "tools", + "userQuestions", + "workspaceRegistry" + ]; + static Config = z.object({ + nativeOpen: z.boolean(), + sessionExportCompressionLevel: z.number().step(1).min(0).max(9).default(6), + coldBlankProbeMaxBytes: z.natural().default(DEFAULT_COLD_BLANK_PROBE_MAX_BYTES) + }); + sessions; + subagents; + workspace; + host; + goals; + skills; + agentPresets; + settings; + credentials; + llm; + events; + downloads; + respond; + constructor(ctx, config) { + super(ctx, "apiProxy"); + const api = createApiProxy(ctx, { + defaultModelSelection: () => ctx.agentDefaultModel.currentSelection(), + saveDefaultModelSelection: (selection) => ctx.agentDefaultModel.saveSelection(selection), + cwd: process.cwd(), + ...config.nativeOpen === void 0 ? {} : { canOpenPath: () => config.nativeOpen }, + ...config.sessionExportCompressionLevel === void 0 ? {} : { sessionExportCompressionLevel: config.sessionExportCompressionLevel }, + ...config.coldBlankProbeMaxBytes === void 0 ? {} : { coldBlankProbeMaxBytes: config.coldBlankProbeMaxBytes } + }); + this.sessions = api.sessions; + this.subagents = api.subagents; + this.workspace = api.workspace; + this.host = api.host; + this.goals = api.goals; + this.skills = api.skills; + this.agentPresets = api.agentPresets; + this.settings = api.settings; + this.credentials = api.credentials; + this.llm = api.llm; + this.events = api.events; + this.downloads = api.downloads; + this.respond = api.respond.bind(api); + } +}; +//#endregion +export { AbstractApiClient, ApiProxyService, ApiProxyService as default, InProcessApiClient, RpcId, createApiProxy, toFetchHandler }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/invariant.js new file mode 100644 index 0000000..afea97a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/invariant.js @@ -0,0 +1,27 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-host-apiproxy`. +* @module @deepseek-ai/dsh-host-apiproxy/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-host-apiproxy"; +/** Cordis companion plugin name. */ +const name = "host-apiproxy-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this package is the wire contract layer plus the +* host-side gateway over services owned elsewhere — it emits no cordis events +* of its own; the session/agent event streams it projects are asserted by +* their owning packages' companions. rpcId round-trip and schema acceptance +* are enforced at the carrier boundary and exercised by the +* protocol-isomorphism suite. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.d.ts new file mode 100644 index 0000000..c59634a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.d.ts @@ -0,0 +1,70 @@ +/** + * Host-side ApiProxy implementation. Signature discipline: unary takes the + * narrow RpcRequest

and echoes request.rpcId on the RpcResponse. + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { ModelSelection } from '@deepseek-ai/dsh-agent'; +import type { JsonValue } from '@deepseek-ai/dsh-session'; +import type { ApiProxy } from './api/index.ts'; +import { type SessionLogCompressionLevel } from './session-export.ts'; +/** Default maximum artifact size eligible for one cold blankness read. */ +export declare const DEFAULT_COLD_BLANK_PROBE_MAX_BYTES = 1024; +/** + * Narrow one allowlisted host event's argument list to the JSON values the + * wrapper frame carries. A rejected argument is an allowlist mistake (the + * forwarded path applies no projection), not hostile input, so it throws rather + * than degrading to a lossy frame. The throw surfaces where the forwarding + * listener runs, so the emitter's own listener containment logs it and drops + * that frame — loud in the Host log, not at load or at the emit. Exported for + * the test that owns this decision: every currently allowlisted event has a + * statically JSON-safe payload, so a type-legal `ctx.emit` cannot reach the + * rejection branch. + * @param event - forwarded host event name, named in the failure. + * @param args - the emitter's argument list. + * @returns the same arguments typed as JSON values. + */ +export declare function assertJsonArgs(event: string, args: readonly unknown[]): JsonValue[]; +/** Resolved Agent model and project-directory defaults consumed by the API implementation. */ +export interface ApiProxyDefaults { + /** + * The model selection a session starts from when its own log names none. Read on + * every access rather than captured, so a default saved during this process + * reaches the sessions that have not run a turn yet. + */ + defaultModelSelection: () => ModelSelection; + /** + * Record a selection as the new default. Either absent, or a closure that + * may itself decline — the gateway plugin always passes one, and it no-ops + * when the deployment mounts no settings provider or when the write races + * service teardown. A switch then stays process-local. A rejection is + * reported and swallowed: the switch already applies to its own session, + * and undoing it because storage failed would be the worse outcome. + */ + saveDefaultModelSelection?: (selection: ModelSelection) => Promise; + /** Default project directory for new sessions whose create request carries no cwd. */ + cwd: string; + /** Native open-with-default-application; injectable for carrier tests. */ + openPath?: (path: string, signal: AbortSignal) => Promise; + /** Native text-editor handoff; injectable for settings-document tests. */ + openTextFile?: (path: string, signal: AbortSignal) => Promise; + /** Validated DEFLATE level for session-log ZIP entries; defaults to 6. */ + sessionExportCompressionLevel?: SessionLogCompressionLevel; + /** Maximum artifact size eligible for one cold blankness read. */ + coldBlankProbeMaxBytes?: number; + /** + * Whether handing a path to the native opener can work at all — the + * `hasDocument` capability the preset roster reports, and the switch + * between opening a preset directory and answering its path as text. + * Absent, an injected `openPath` counts as openable and everything else + * falls back to platform detection ({@link canOpenNativePath}). + */ + canOpenPath?: () => boolean; +} +/** + * Implement ApiProxy over a composed host context. + * @param ctx - a context with the Host spine and Workspace registry mounted. + * @param defaults - host routing and project-directory defaults. + * @returns the ApiProxy implementation. + */ +export declare function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiProxy; +//# sourceMappingURL=api-proxy.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.js new file mode 100644 index 0000000..44f1a61 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.js @@ -0,0 +1,3455 @@ +/** + * Host-side ApiProxy implementation. Signature discipline: unary takes the + * narrow RpcRequest

and echoes request.rpcId on the RpcResponse. + */ +import { randomUUID } from 'node:crypto'; +import { mkdir, stat } from 'node:fs/promises'; +import { dirname } from 'node:path'; +import { installModelSelection } from '@deepseek-ai/dsh-agent'; +import { AttachmentError } from '@deepseek-ai/dsh-attachment'; +import { contentHasImage, createUserMessage, freezeMessage, ReasoningEffortId } from '@deepseek-ai/dsh-llm'; +import { errorChain } from '@deepseek-ai/dsh-llm'; +import { isAppendSurfaceEvent, isJsonValue } from '@deepseek-ai/dsh-session'; +import { SessionQueryError } from '@deepseek-ai/dsh-session-query'; +import { SubagentError } from '@deepseek-ai/dsh-subagent'; +import { isUserInvocable } from '@deepseek-ai/dsh-skill'; +import { workspaceDomainState, workspaceRecord, WorkspaceId as brandWorkspaceId, WorkspaceMoveInvalidError, WorkspaceOrderInvalidError, WorkspaceUnknownSessionError, } from '@deepseek-ai/dsh-workspace'; +// Type-only: brings the `ctx.tools` Context merge into this program (viewFor reads presenters). +import { InvalidPresetIdError, PresetExistsError, PresetMountError, PresetNotWritableError, resolveSessionPreset, SETTINGS_NAMESPACE as AGENT_PRESET_SETTINGS_NAMESPACE, UnknownPresetError, } from '@deepseek-ai/dsh-agent-presets'; +import { DEFAULT_SESSION_LOG_COMPRESSION_LEVEL, flushLiveSessionLog, sessionLogExportDeps, sessionLogZipFilename, streamSessionLogZip, } from "./session-export.js"; +import { SESSION_SEARCH_RESULT_LIMIT, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS, truncateUnicodeCodePoints, } from "./api/session-search.js"; +// GoalError narrows domain rejections to their stable codes at the wire boundary. +import { GoalError } from '@deepseek-ai/dsh-goal'; +// The settings/credentials seams: brand guards run at this wire boundary; the +// service reads stay optional (`ctx.get`) so a composition without either +// provider still serves every other domain. +import { SettingsConflictError, settingsNamespace } from '@deepseek-ai/dsh-settings'; +import { credentialRef } from '@deepseek-ai/dsh-credentials'; +// Value edge: the rename impl narrows the title service's validation failure; the import also resolves `ctx.get('sessionTitle')`. +import { SessionTitleInvalidError } from '@deepseek-ai/dsh-session-title'; +import { approvalResponsePayloadSchema } from "./api/approvals.schema.js"; +import { imageLimitsProjectionSchema, sessionListMetadataProjectionSchema } from "./api/sessions.schema.js"; +import { questionResponsePayloadSchema } from "./api/questions.schema.js"; +import { RpcId } from "./api/rpc.js"; +import { UserQuestionError } from '@deepseek-ai/dsh-user-questions'; +import { DirectoryPickerError } from '@deepseek-ai/dsh-host-directory-picker'; +import { ApiRemoteSessionNotFound as SessionNotFound, ApiRemoteSubagentSessionOwnership as SubagentSessionOwnership, API_REMOTE_FORWARDED_EVENTS, apiRemoteSubagentOwnershipError, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession, } from '@deepseek-ai/dsh-api-remotes'; +import { canOpenNativePath, openNativePath, openNativeTextFile } from "./native-path-opener.js"; +/** Page size when history is called without maxMessages. */ +const DEFAULT_MAX_MESSAGES = 50; +/** + * Non-model settings namespaces intentionally served to the Web client. The + * plugin-owned entries (`agent-loop`, `bash`, `web-search-deepseek`) are the + * host-plane sections the plugin configuration page edits; a namespace absent + * here answers `settings-not-exposed` even when its owner registered it, so + * adding a section to that page is a decision made here rather than by the + * registering plugin. Moving that declaration to `settings.register()`, so a + * plugin can expose its own configuration without a change in this package, + * is deferred work. + */ +const WEB_SETTINGS_NAMESPACES = [ + 'agent-loop', 'shell', 'locale', 'permission', 'ui-conversation', 'ui-theme', 'web-search-deepseek', +]; +/** Provider work budget: at most 100 calls and 2,000 inspected hits. */ +const SESSION_SEARCH_PROVIDER_CALL_LIMIT = 100; +/** Bound cold-log stat fan-out and settle each started batch before cancellation returns. */ +const COLD_SUMMARY_BATCH_SIZE = 16; +/** Default maximum artifact size eligible for one cold blankness read. */ +export const DEFAULT_COLD_BLANK_PROBE_MAX_BYTES = 1024; +/** Conversation message event types (the pagination counting unit). */ +const MESSAGE_TYPES = new Set(['user/message', 'assistant/message']); +/** Decode the browser payload while rejecting non-canonical base64 forms. */ +function decodeBase64(data) { + const decoded = Buffer.from(data, 'base64'); + if (data.length === 0 || decoded.toString('base64') !== data) { + throw new AttachmentError('Image upload is not canonical base64.', 'INVALID_IMAGE_BASE64'); + } + return new Uint8Array(decoded); +} +/** Validate one prompt as a batch before publishing any durable image object. */ +async function durablePromptContent(ctx, content) { + if (content.every(part => part.type === 'text')) { + return content.map(part => ({ type: 'text', text: part.text })); + } + const limits = ctx.attachments.imageLimits; + if (content.filter(part => part.type === 'image').length > limits.maxImagesPerMessage) { + throw new AttachmentError('Prompt exceeds the configured image-count limit.', 'TOO_MANY_IMAGES'); + } + const prepared = content.map(part => part.type === 'text' + ? part + : { part, data: decodeBase64(part.data) }); + const images = prepared.filter((part) => 'data' in part); + const totalBytes = images.reduce((sum, image) => sum + image.data.byteLength, 0); + if (totalBytes > limits.maxMessageImageBytes) { + throw new AttachmentError('Prompt exceeds the configured aggregate image-byte limit.', 'IMAGES_TOO_LARGE'); + } + for (const image of images) { + await ctx.attachments.validateImage({ + data: image.data, + mediaType: image.part.mediaType, + ...image.part.name === undefined ? {} : { name: image.part.name }, + }); + } + const blocks = []; + for (const item of prepared) { + if (!('data' in item)) { + blocks.push({ type: 'text', text: item.text }); + continue; + } + const attachment = await ctx.attachments.saveImage({ + data: item.data, + mediaType: item.part.mediaType, + ...item.part.name === undefined ? {} : { name: item.part.name }, + }); + blocks.push({ type: 'image', attachment }); + } + return blocks; +} +/** Search durable content for an image reference, including nested tool results. */ +function imageBlockIn(content, match) { + if (!Array.isArray(content)) + return undefined; + for (const value of content) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) + continue; + const block = value; + if (block.type === 'image' && typeof block.attachment === 'object' && block.attachment !== null) { + const ref = block.attachment; + if (match(ref)) + return ref; + } + if (block.type === 'tool-result') { + const nested = imageBlockIn(block.content, match); + if (nested !== undefined) + return nested; + } + } + return undefined; +} +/** Search every durable event carrier that can own model-visible content. */ +function imageInEvent(event, match) { + const data = event.data; + const direct = imageBlockIn(data.content, match); + if (direct !== undefined) + return direct; + if (data.message !== undefined) { + const wrapped = imageBlockIn(data.message.content, match); + if (wrapped !== undefined) + return wrapped; + } + if (data.inserted !== undefined) { + for (const message of data.inserted) { + const inserted = imageBlockIn(message.content, match); + if (inserted !== undefined) + return inserted; + } + } + if (event.type === 'assistant/chunk' && data.chunk?.type === 'block-end') { + return imageBlockIn([data.chunk.block], match); + } + return undefined; +} +/** True when the current model-visible surface contains an image. */ +function messagesHaveImage(messages) { + return messages.some(message => contentHasImage(message.content)); +} +/** Resolve the first reference matching one opaque id. */ +function referencedImage(events, attachmentId) { + for (const event of events) { + const found = imageInEvent(event, ref => String(ref.attachmentId) === attachmentId); + if (found !== undefined) + return found; + } + return undefined; +} +/** + * Product settings intentionally exposed beside model-provider namespaces. + * + * The agent-preset namespace carries one field — which preset a session with + * no explicit choice is composed from — and both browser surfaces that offer + * that choice write it through `settings.update`, so it has to cross the + * configuration boundary or the pickers silently fail to persist. + */ +const PRODUCT_SETTINGS_NAMESPACES = new Set(['ui-onboarding', AGENT_PRESET_SETTINGS_NAMESPACE]); +/** Strict browser-zone profile: UTC or an IANA Area/Location-style identifier. */ +const IANA_TIME_ZONE = /^[A-Za-z][A-Za-z0-9_+.-]*(?:\/[A-Za-z0-9_+.-]+)+$/; +/** Validate and canonicalize one browser-supplied IANA zone at the wire boundary. */ +function canonicalClientTimeZone(value) { + if (value.length === 0 || value.trim() !== value + || (value !== 'UTC' && !IANA_TIME_ZONE.test(value))) + return undefined; + try { + const canonical = new Intl.DateTimeFormat('en-US', { timeZone: value }) + .resolvedOptions().timeZone; + /* v8 ignore next -- Intl returns UTC or a canonical IANA Area/Location for accepted input. */ + if (canonical !== 'UTC' && !IANA_TIME_ZONE.test(canonical)) + return undefined; + return canonical; + } + catch { + // Intl rejects unsupported zone names; the RPC maps that parser rejection below. + return undefined; + } +} +/** Read live abort state across awaits without treating it as synchronously immutable. */ +function isAborted(signal) { + return signal.aborted; +} +/** + * Message-boundary pagination: count maxMessages append-origin messages + * backwards from the window tail. Replacement copies never entered the + * conversation a reader sees — they restate a shadowed range for the model + * alone — so they consume no quota; the page stays one contiguous raw range, + * which keeps a compaction's log-only `compaction/summary` record on the same page as its + * replacement. The cut is the starting seq of the oldest message group (chunks + * group via sourceEventSeqs — never cut mid-message). The tail page naturally + * includes the in-progress partial. + */ +function paginate(events, beforeSeq, maxMessages) { + const window = beforeSeq === undefined ? [...events] : events.filter(event => event.seq < beforeSeq); + let count = 0; + let cut = 0; + for (let i = window.length - 1; i >= 0; i--) { + const event = window[i]; + if (!MESSAGE_TYPES.has(event.type) || !isAppendSurfaceEvent(event)) + continue; + count++; + const sources = event.sourceEventSeqs; + const groupStart = sources !== undefined && sources.length > 0 ? Math.min(event.seq, ...sources) : event.seq; + if (count >= maxMessages) { + cut = groupStart; + break; + } + } + const page = window.filter(event => event.seq >= cut); + return { events: page, hasMore: cut > 0 }; +} +/** Wrap an ok result echoing the request's rpcId. */ +function ok(request, value) { + return { rpcId: request.rpcId, result: { ok: true, value } }; +} +/** + * Build the provider/model catalog over every registered route. Shared by the + * session-scoped `session.models` and host-scoped `llm.models`. Catalog + * membership stays advisory: an unlisted session selection remains valid for + * provider dispatch, but is not injected back into the selector after its + * owning catalog stops advertising it. Per-provider failures ride `failures` + * without failing the sound groups; groups that advertise nothing are dropped. + */ +async function buildModelCatalog(ctx) { + const catalog = await Promise.all(ctx.llm.listProviders().map(async (provider) => { + try { + const models = await ctx.llm.listModels(provider.id); + const entries = await Promise.all(models.map(async (model) => { + const resolved = await ctx.llm.resolveModelInfo(provider.id, model.id); + const reasoning = resolved.reasoning === undefined + ? undefined + : { + efforts: resolved.reasoning.efforts.map(effort => ({ + id: effort.id, + name: effort.name, + ...effort.description === undefined + ? {} + : { description: effort.description }, + })), + ...resolved.reasoning.defaultEffort === undefined + ? {} + : { defaultEffort: resolved.reasoning.defaultEffort }, + }; + return { + id: model.id, + name: model.name, + ...model.description === undefined ? {} : { description: model.description }, + ...reasoning === undefined ? {} : { reasoning }, + }; + })); + const group = { + id: provider.id, + name: provider.name, + models: entries, + }; + return { kind: 'group', group }; + } + catch (error) { + const failure = { + id: provider.id, + name: provider.name, + message: error instanceof Error ? error.message : String(error), + }; + return { kind: 'failure', failure }; + } + })); + return { + groups: catalog.flatMap(item => item.kind === 'group' ? [item.group] : []).filter(group => group.models.length > 0), + failures: catalog.flatMap(item => item.kind === 'failure' ? [item.failure] : []), + }; +} +/** Wrap an error result echoing the request's rpcId. */ +function err(request, error) { + return { rpcId: request.rpcId, result: { ok: false, error } }; +} +/** + * The RPC refusal a preset failure becomes, or undefined when the failure is + * about something else. + * + * Both the session-create path and the switch path can be handed the same two + * failures, and a client that has to branch on the code needs them worded the + * same from either. + * @param request - the request being answered. + * @param error - the thrown value. + * @returns the refusal, or undefined when the caller should keep handling. + */ +function presetFailure(request, error) { + if (error instanceof UnknownPresetError) { + return err(request, { + code: 'agent-preset-not-found', + message: error.message, + details: { agentPreset: error.presetId, available: [...error.available] }, + }); + } + if (error instanceof PresetMountError) { + return err(request, { + code: 'agent-preset-invalid', + message: error.message, + details: { agentPreset: error.presetId, reason: error.reason }, + }); + } + return undefined; +} +/** Simple async queue: core callbacks push, the AsyncIterable pulls; abort/return cleans up. */ +class FrameQueue { + buffer = []; + waiter; + done = false; + push(item) { + if (this.done) + return; + this.buffer.push(item); + this.waiter?.(); + } + end() { + this.done = true; + this.waiter?.(); + } + async *iterate(signal, cleanup) { + const onAbort = () => { this.end(); }; + signal.addEventListener('abort', onAbort, { once: true }); + try { + while (true) { + while (this.buffer.length > 0) + yield this.buffer.shift(); + if (this.done || signal.aborted) + return; + await new Promise((resolve) => { this.waiter = resolve; }); + this.waiter = undefined; + } + } + finally { + signal.removeEventListener('abort', onAbort); + cleanup(); + } + } +} +/** + * Server-side frame mint: pure pushes get a fresh rpcId per frame (answerable + * frames — approval/question requested — mint their stable id in their + * pending registries instead). + */ +function frame(payload) { + return { rpcId: RpcId(randomUUID()), payload }; +} +/** + * Narrow one allowlisted host event's argument list to the JSON values the + * wrapper frame carries. A rejected argument is an allowlist mistake (the + * forwarded path applies no projection), not hostile input, so it throws rather + * than degrading to a lossy frame. The throw surfaces where the forwarding + * listener runs, so the emitter's own listener containment logs it and drops + * that frame — loud in the Host log, not at load or at the emit. Exported for + * the test that owns this decision: every currently allowlisted event has a + * statically JSON-safe payload, so a type-legal `ctx.emit` cannot reach the + * rejection branch. + * @param event - forwarded host event name, named in the failure. + * @param args - the emitter's argument list. + * @returns the same arguments typed as JSON values. + */ +export function assertJsonArgs(event, args) { + for (const [index, arg] of args.entries()) { + if (!isJsonValue(arg)) { + throw new Error(`forwarded host event "${event}" argument ${index} is not lossless JSON data`); + } + } + return args; +} +/** Queue the subscription baseline frame. */ +function subscribeSession(queue, session) { + queue.push(frame({ type: 'session/subscribed', sessionId: session.id, lastSeq: session.seq - 1 })); +} +/** + * Project registry snapshots onto the wire view, dropping the three internal + * fields {@link JobView} documents as absent. + */ +function jobViews(snapshots) { + return snapshots.map(job => ({ + id: job.id, + kind: job.kind, + label: job.label, + status: job.status, + ...job.detail === undefined ? {} : { detail: job.detail }, + startedAt: job.startedAt, + ...job.finishedAt === undefined ? {} : { finishedAt: job.finishedAt }, + })); +} +/** + * Whether the session's conversation has started: no turn has run yet (a + * turn is one model-loop execution). Standalone plugin events — command + * lifecycle records, plan/mode, titles, goals — never open a turn, so + * running `/plan` or `/goal` on a fresh session keeps it blank + * (list-hidden, reusable). + */ +function sessionBlank(session) { + return !session.events.some(event => event.type === 'turn/start'); +} +/** Advance the Session-list hint projection by one committed event. */ +function applySessionListMetadata(state, event) { + const blank = state.blank && event.type !== 'turn/start'; + const lastPromptAt = event.type === 'user/message' && event.data.source.kind === 'user' + ? event.time + : state.lastPromptAt; + return blank === state.blank && lastPromptAt === state.lastPromptAt + ? state + : { blank, lastPromptAt }; +} +/** Fold exact list metadata for an attached Session. */ +function sessionListMetadata(events) { + let state = { blank: true, lastPromptAt: null }; + for (const event of events) + state = applySessionListMetadata(state, event); + return state; +} +/** Sort by creation or latest human prompt, whichever is newer. */ +function sessionListUpdatedAt(header, metadata) { + return Math.max(header.createdAt, metadata?.lastPromptAt ?? 0); +} +/** Shared Session-header projection for list baselines and creation frames. */ +function sessionListFields(header, events = []) { + // The preset comes from the log, not the header: a session that switched + // while blank ran its turns under the newer composition, and a picker + // showing the creation-time value would contradict what the model saw. + const agentPreset = resolveSessionPreset({ header, events }); + return { + ...header.parentSession === undefined ? {} : { parentSessionId: header.parentSession }, + ...header.origin === undefined ? {} : { origin: header.origin }, + ...header.cwd === undefined ? {} : { cwd: header.cwd }, + ...agentPreset === undefined ? {} : { agentPreset }, + }; +} +/** SessionSummary projection for attached (in-memory) sessions. */ +function summarize(session, running) { + const metadata = sessionListMetadata(session.events); + return { + sessionId: session.id, + updatedAt: sessionListUpdatedAt(session.header, metadata), + running, + blank: metadata.blank, + ...sessionListFields(session.header, session.events), + }; +} +/** + * Verify a possibly blank cold Session only when its physical artifact passes + * the configured per-Session size check. A stale `blank: true`, an + * absent cache row, a large or location-less artifact, and read failures all + * resolve to visible (`false`); listing must never hide a conversation on a + * cache hint or an unavailable optimization. + */ +async function probeColdSessionMetadata(ctx, persistence, meta, maxBytes, signal) { + if (maxBytes === 0) + return undefined; + signal?.throwIfAborted(); + const location = persistence.locate(meta); + if (location === undefined) + return undefined; + signal?.throwIfAborted(); + let size; + try { + size = (await stat(location.path)).size; + } + catch { + signal?.throwIfAborted(); + return undefined; + } + if (size > maxBytes) + return undefined; + try { + const { events } = await persistence.readFrom(meta.id, 0, signal); + signal?.throwIfAborted(); + return sessionListMetadata(events); + } + catch (error) { + signal?.throwIfAborted(); + ctx.logger.warn(`session.list: blank probe for "${meta.id}" failed (serving it as visible): ${String(error)}`); + return undefined; + } +} +/** SessionSummary projection for a cold persisted Session. */ +async function summarizeCold(ctx, persistence, meta, metadata, blankProbeMaxBytes, signal) { + const probed = metadata?.blank === false + ? undefined + : await probeColdSessionMetadata(ctx, persistence, meta, blankProbeMaxBytes, signal); + return { + sessionId: meta.id, + updatedAt: sessionListUpdatedAt(meta, probed ?? metadata), + running: false, + blank: metadata?.blank === false ? false : probed?.blank ?? false, + // Header-only: reading the log for a blank-window preset switch would + // defeat the same index read, and attaching the session replaces this row + // with `summarize()`, which resolves the switch from the events. + ...sessionListFields(meta), + }; +} +/** Map a browse-primitive failure onto the wire error vocabulary (unknown throws stay internal). */ +function directoryError(error) { + if (error instanceof DirectoryPickerError) { + return { code: error.code, message: error.message, details: { path: error.path } }; + } + return { code: 'internal', message: error instanceof Error ? error.message : String(error), details: {} }; +} +/** Project a pending entry into its answerable mux frame (initial push and mux-open replay share it). */ +function requestedFrame(pending) { + return { + rpcId: pending.rpcId, + payload: { + type: 'approval/requested', + sessionId: pending.sessionId, + approvalId: pending.approvalId, + toolName: pending.toolName, + ...pending.callId === undefined ? {} : { callId: pending.callId }, + ...pending.reason === undefined ? {} : { reason: pending.reason }, + }, + }; +} +/** Validate one answer batch against the exact question request it resolves. */ +function matchesQuestions(payload, pending) { + if (payload.sessionId !== pending.sessionId) + return false; + const answers = payload.answer.answers; + if (answers.length !== pending.questions.length) + return false; + return answers.every((answer, index) => { + const question = pending.questions[index]; + if (answer.id !== question.id) + return false; + if (new Set(answer.selected).size !== answer.selected.length) + return false; + const custom = answer.custom?.trim(); + if (custom !== undefined && custom === '') + return false; + if (question.multiSelect !== true) { + if (custom !== undefined && answer.selected.length > 0) + return false; + if (answer.selected.length > 1) + return false; + } + const labels = new Set(question.options?.map(option => option.label) ?? []); + return answer.selected.every(label => labels.has(label)); + }); +} +/** + * Compute the render intent for a tool/call or tool/result event through the + * presenters registered at this moment; every other event type gets none. A + * result's presenter needs its call's parsed args — `argsFor` supplies them + * (live: the per-session call table; history: an in-page backscan), returning + * undefined when the pairing is unavailable (e.g. the call fell off the page), + * which soft-falls to no view. Presenter or JSON.parse throws also soft-fall: + * the client's documented default (generic JSON card) covers every miss. + */ +function viewFor(ctx, event, argsFor, +// Presenters live with the definitions, and definitions live in the scope +// chain: a preset registers its tools into its standing layer. A live agent +// is a scope whose chain passes through its preset; a cold read passes the +// preset's standing key directly — no agent, no resume. An undefined scope +// sees only the global layer, which is the pre-preset deployment shape. +scope) { + try { + if (event.type === 'tool/call') { + const { name, arguments: raw } = event.data; + const view = ctx.tools.get(name, scope)?.presentCall?.(JSON.parse(raw)); + return view === undefined ? undefined : { for: 'call', view }; + } + if (event.type === 'tool/result') { + const { message, meta } = event.data; + const [result] = message.content; + const callId = message.source.callId; + const call = argsFor(callId); + if (call === undefined) + return undefined; + const view = ctx.tools.get(call.name, scope)?.presentResult?.(call.args, { + content: result.content, + isError: result.isError === true, + ...meta === undefined ? {} : { meta }, + }); + return view === undefined ? undefined : { for: 'result', view }; + } + } + catch (error) { + // A throwing presenter (or unparseable arguments) must not break delivery; + // the event still ships, just without a view. + console.error(`api-proxy: presenter failed for ${event.type}, falling back to generic: ${String(error)}`); + } + return undefined; +} +/** + * Resolve a tool/result's call pairing by scanning a window of events backwards + * for the matching tool/call. Used by the history path (the page is the + * window — a cross-page pairing soft-falls to no view) and by live-path table + * misses after a reconnect-eviction. + */ +function backscanArgs(events, callId) { + for (let i = events.length - 1; i >= 0; i--) { + const event = events[i]; + if (event.type !== 'tool/call') + continue; + const data = event.data; + if (data.callId !== callId) + continue; + try { + return { name: data.name, args: JSON.parse(data.arguments) }; + } + catch { + // Unparseable stored arguments: same soft-fall as a live parse failure. + return undefined; + } + } + return undefined; +} +/** Render one detached history page through the same presenter path as ordinary history. */ +function historyPage(ctx, events, beforeSeq, maxMessages, scope) { + const page = paginate(events, beforeSeq, maxMessages ?? DEFAULT_MAX_MESSAGES); + return { + events: page.events.map((event) => { + const view = viewFor(ctx, event, callId => backscanArgs(page.events, callId), scope); + return { event, ...view === undefined ? {} : { view } }; + }), + hasMore: page.hasMore, + }; +} +function projectionsFor(ctx, session) { + const registry = ctx.get('sessionProjections'); + if (registry === undefined) + return undefined; + return registry.snapshot(session); +} +/** + * The projection baseline of one session.list row, fail-soft: attached + * sessions cut the registry's live watermark cache; cold sessions view the + * persisted projection cache's identity-checked stored rows (zero log loads + * either way — the listing use case the cache exists for). The block shape + * (values + asOfSeq) matches the history tail's, so a client seeds its + * value store under the same higher-seq-wins rule. Any failure — and an + * empty value set — yields an absent block: a listing without projections + * is degraded, never broken. + */ +function listProjectionsFor(ctx, meta, session) { + try { + const block = session !== undefined + ? ctx.get('sessionProjections')?.snapshot(session) + : ctx.get('sessionProjectionCache')?.cachedSnapshot(meta); + return block !== undefined && Object.keys(block.values).length > 0 ? block : undefined; + } + catch (error) { + ctx.logger.warn(`session.list: projection column for "${meta.id}" failed (serving the row without it): ${String(error)}`); + return undefined; + } +} +/** Projection baseline for a detached history tail without Agent activation. */ +function detachedProjectionsFor(ctx, events) { + const registry = ctx.get('sessionProjections'); + if (registry === undefined) + return undefined; + return registry.restore({}, events, 0).snapshot; +} +/** + * Best-effort projections for one subagent history page, fail-soft like + * {@link listProjectionsFor}: a registered unit throwing on a corrupt payload + * never blocks transcript reading — the page is served without the block. + * @param ctx - context carrying the logger for the degradation warning. + * @param childSessionId - the child whose page is being decorated. + * @param compute - the arm-specific fold (live watermark or detached restore). + * @returns the projections block, or undefined when the fold failed. + */ +function subagentHistoryProjections(ctx, childSessionId, compute) { + try { + return compute(); + } + catch (error) { + ctx.logger.warn(`subagent.history: projections for "${childSessionId}" failed (serving the page without them): ${String(error)}`); + return undefined; + } +} +/** Map continuation admission failures without exposing provider details. */ +function subagentPromptError(request, error, signal) { + const childSessionId = request.payload.childSessionId; + if (signal.aborted) { + return err(request, { code: 'cancelled', message: 'subagent prompt was cancelled', details: {} }); + } + if (error instanceof SubagentError) { + switch (error.code) { + case 'NOT_RESUMABLE': + return err(request, { + code: 'subagent-not-resumable', + message: 'subagent cannot be resumed', + details: { childSessionId }, + }); + case 'UNAUTHORIZED': + return err(request, { + code: 'subagent-unauthorized', + message: 'subagent does not belong to this parent', + details: { childSessionId }, + }); + case 'DRAINING': + case 'ACTIVATION_CLOSING': + case 'CONTINUATION_UNAVAILABLE': + case 'PERSISTENCE_UNAVAILABLE': + return err(request, { + code: 'subagent-delivery-unavailable', + message: 'subagent follow-up is temporarily unavailable', + details: { childSessionId }, + }); + default: + break; + } + } + return err(request, { code: 'internal', message: 'subagent prompt failed', details: {} }); +} +/** Stable RPC face of the missing projections capability, shared by every catalog read path. */ +function projectionsUnavailableError() { + return { + code: 'internal', + message: 'subagent catalog is unavailable: this deployment does not mount the sessionProjections registry (load @deepseek-ai/dsh-session-projection)', + details: {}, + }; +} +/** Verify one address and mode against the complete direct-child catalog. */ +async function catalogChild(ctx, address, signal) { + const { parentSessionId, childSessionId, mode } = address; + try { + const entries = await ctx.subagents.listChildren(parentSessionId, signal); + const entry = entries.find(candidate => candidate.id === childSessionId); + if (entry === undefined || (entry.kind === 'child' && entry.mode !== mode)) { + return { + error: { + code: 'subagent-not-found', + message: `session "${childSessionId}" is not a ${mode} direct child of "${parentSessionId}"`, + details: { parentSessionId, childSessionId }, + }, + }; + } + if (entry.kind === 'diagnostic') { + return { + error: { + code: 'subagent-catalog-diagnostic', + message: `subagent "${childSessionId}" is ${entry.reason}`, + details: { parentSessionId, childSessionId, reason: entry.reason }, + }, + }; + } + return { entry }; + } + catch (error) { + if (signal?.aborted || (error instanceof SubagentError && error.code === 'CANCELLED')) { + return { error: { code: 'cancelled', message: 'subagent catalog read was cancelled', details: {} } }; + } + if (error instanceof SubagentError && error.code === 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE') { + return { error: projectionsUnavailableError() }; + } + return { error: { code: 'internal', message: 'subagent catalog read failed', details: {} } }; + } +} +/** + * The requested preset differs from the one this session already runs. + * + * A session's composition is fixed at creation: its history was produced under + * that preset's tools, so adopting the identity under a different one would + * replay tool calls the rebuilt agent cannot make. Naming a different preset + * is therefore a caller error rather than a switch. + */ +/** The roster is absent: this deployment composes no agent presets at all. */ +function noRoster(agentPreset) { + return { + code: 'agent-preset-not-found', + message: 'this deployment composes no agent presets', + details: { agentPreset, available: [] }, + }; +} +/** Map one authoring/roster failure onto its wire code. */ +function presetError(agentPreset, error) { + if (error instanceof UnknownPresetError) { + return { + code: 'agent-preset-not-found', + message: error.message, + details: { agentPreset: error.presetId, available: [...error.available] }, + }; + } + if (error instanceof PresetNotWritableError) { + return { code: 'agent-preset-read-only', message: error.message, details: { agentPreset, reason: error.message } }; + } + if (error instanceof InvalidPresetIdError || error instanceof PresetExistsError) { + return { code: 'agent-preset-invalid', message: error.message, details: { agentPreset, reason: error.message } }; + } + return { code: 'internal', message: `agent preset "${agentPreset}": ${String(error)}`, details: {} }; +} +class AgentPresetConflict extends Error { + sessionId; + requestedPreset; + existingPreset; + constructor(sessionId, requestedPreset, existingPreset) { + super(existingPreset === undefined + ? `session "${sessionId}" records no agent preset, so it cannot be adopted under one; ` + + 'a deployment composing no roster records none on any session — ' + : `session "${sessionId}" already runs agent preset ${JSON.stringify(existingPreset)}; ` + + `requested ${JSON.stringify(requestedPreset)}. A session's preset is fixed at creation.`); + this.sessionId = sessionId; + this.requestedPreset = requestedPreset; + this.existingPreset = existingPreset; + } +} +/** Requested identity already belongs to a session with another project cwd. */ +class SessionCwdConflict extends Error { + sessionId; + requestedCwd; + existingCwd; + constructor(sessionId, requestedCwd, existingCwd) { + super(`session "${sessionId}" already exists with cwd ${JSON.stringify(existingCwd)}; ` + + `requested ${JSON.stringify(requestedCwd)}`); + this.sessionId = sessionId; + this.requestedCwd = requestedCwd; + this.existingCwd = existingCwd; + } +} +/** An explicit Host naming operation would duplicate another Workspace title. */ +class WorkspaceNameConflictError extends Error { + workspaceName; + constructor(workspaceName) { + super(`workspace name '${workspaceName}' is already in use`); + this.workspaceName = workspaceName; + this.name = 'WorkspaceNameConflictError'; + } +} +/** Shared workspace-not-found error response of the workspace.* mutation rows. */ +function workspaceNotFound(request, workspaceId) { + return err(request, { + code: 'workspace-not-found', + message: `workspace "${workspaceId}" not found`, + details: { workspaceId }, + }); +} +/** Wire projection of one workspace entity (the workspace.* value row). */ +function workspaceView(workspace) { + return { + workspaceId: workspace.id, + path: workspace.path, + title: workspace.title, + sessionIds: [...workspace.sessionIds], + createdAt: workspace.createdAt, + updatedAt: workspace.updatedAt, + }; +} +/** Wire projection of the durable record carried by `domain/changed`. */ +function changedWorkspaceView(workspaceId, value) { + const record = workspaceRecord.parse(value); + return { + workspaceId: workspaceId, + path: record.path, + title: record.title, + sessionIds: [...record.sessionIds], + createdAt: record.createdAt, + updatedAt: record.updatedAt, + }; +} +/** + * Implement ApiProxy over a composed host context. + * @param ctx - a context with the Host spine and Workspace registry mounted. + * @param defaults - host routing and project-directory defaults. + * @returns the ApiProxy implementation. + */ +export function createApiProxy(ctx, defaults) { + const sessionExportCompressionLevel = defaults.sessionExportCompressionLevel + ?? DEFAULT_SESSION_LOG_COMPRESSION_LEVEL; + const coldBlankProbeMaxBytes = defaults.coldBlankProbeMaxBytes + ?? DEFAULT_COLD_BLANK_PROBE_MAX_BYTES; + /** The seed model each create/resume declares; re-read so it never goes stale. */ + const agentOptions = () => { + const { provider, model } = defaults.defaultModelSelection(); + return { provider, model }; + }; + const selections = new WeakMap(); + /** + * Serializes `agentPreset.select` per session. Two concurrent selects both + * pass the blank check, and the second `unmountPresetFor` then finds nothing + * to unmount because the first already removed the record — leaving two + * compositions registered into one agent layer. The client's `busy` flag is + * not enforcement: the wire is reachable directly. + */ + const presetSwitches = new Map(); + /** Client-chosen identity creation/resume, deduplicated across concurrent retries. */ + const sessionCreations = new Map(); + /** Serializes path ownership and explicit title checks with Workspace mutations. */ + let workspaceCreationChain = Promise.resolve(); + const pendingQuestions = new Map(); + const pendingApprovals = new Map(); + const muxQueues = new Set(); + const imageAdmissionChains = new WeakMap(); + /** Serialize image admission with model selection for one agent. */ + function serializeImageAdmission(agent, operation) { + const result = (imageAdmissionChains.get(agent) ?? Promise.resolve()).then(operation); + imageAdmissionChains.set(agent, result.then(() => undefined, () => undefined)); + return result; + } + /** + * Install or return the session-local model selection that prompt assembly snapshots. + * + * Precedence, resolved on EVERY read rather than seeded once: a selection + * made in this process, else the session's own latest logged request/header, + * else the live Agent default. Re-reading keeps the two tiers exact in both + * directions: a session with a recorded request derives its selection from + * its log, while a blank session (New Session reuses one rather than minting + * another) reads any default saved after it was created. There is no create-time + * per-session override tier on this wire — if one returns (a create-options + * contribution), it must fold in between the selection and the log. + */ + function selectionFor(agent) { + const installed = selections.get(agent); + if (installed !== undefined) + return installed; + let picked; + const selection = { + get current() { + if (picked !== undefined) + return picked; + // Incrementally folded by the session, so a per-step read costs + // O(new events) rather than a rescan. + const logged = agent.session.requestHeader()?.config; + if (logged === undefined) + return defaults.defaultModelSelection(); + return { + provider: logged.provider, + model: logged.model, + ...logged.reasoningEffort === undefined + ? {} + : { reasoningEffort: logged.reasoningEffort }, + }; + }, + set current(next) { + picked = next; + }, + assembled: undefined, + }; + installModelSelection(agent.ctx, selection); + selections.set(agent, selection); + return selection; + } + /** Pre-publication setup used by both fresh and resumed Web agents. */ + function installSelection(agentCtx) { + const agent = agentCtx.agent; + if (agent === undefined) + throw new Error('api-proxy: agent setup has no scoped agent'); + selectionFor(agent); + } + /** + * Reject an attempt to run an existing session under a different preset. + * + * A caller that names no preset always adopts the session as it is, so the + * common paths — reconnecting, resuming, retrying a create — are unaffected. + * @param sessionId - the identity being adopted. + * @param requested - the preset the request named, if any. + * @param existing - the preset the session RUNS, if any; both callers resolve + * it from the log, which differs from the creation header once a blank + * session has switched. + * @throws when both are present and differ. + */ + function assertPresetUnchanged(sessionId, requested, existing) { + if (requested === undefined || requested === existing) + return; + throw new AgentPresetConflict(sessionId, requested, existing); + } + /** + * Resolve the preset an agent will be composed from, and the setup that + * installs it. + * + * The id is resolved BEFORE the session exists because the session boundary + * snapshots `meta` before asynchronous setup begins — a preset discovered + * during setup could never reach the header. Mounting still happens in + * setup, where a failure rolls the whole creation back rather than leaving a + * published session whose capabilities are half-installed. + * + * A deployment with no preset roster composes nothing and every session + * shares the host composition, which is the behavior before presets existed. + * @param presetId - the requested preset, or `undefined` for the default. + * @returns the id to record on the header (absent without a roster) and the setup callback. + * @throws when the roster supplies no such preset. + */ + async function composeAgent(presetId) { + const presets = ctx.get('agentPresets'); + if (presets === undefined) { + return { + setup: (agentCtx) => { + installSelection(agentCtx); + return Promise.resolve(); + }, + }; + } + const resolvedId = (await presets.resolve(presetId)).id; + return { + agentPreset: resolvedId, + setup: async (agentCtx) => { + installSelection(agentCtx); + await presets.mount(agentCtx, resolvedId); + }, + }; + } + const hasSubagentOwner = (session, agent) => hasApiRemoteSubagentOwner(ctx, session, agent); + const subagentOwnershipError = (sessionId) => apiRemoteSubagentOwnershipError(sessionId); + const inspectServable = (sessionId) => inspectApiRemoteSession(ctx, sessionId); + // Cold resume composes the preset the session recorded, for the same reason + // `session.create` does: its history was produced under that composition. + // Every generic entry point — prompt, models, commands — arrives here, so + // leaving it out meant a session opened after a restart ran on host tools + // and the deployment persona. Resolved from the LOG, not the header: a + // session that switched while blank ran its turns under the newer + // composition, and the header is written once at creation. Reading the + // header here would silently undo the switch on the next restart and + // restore that history under the old tool set. + const agentFor = createApiRemoteAgentResolver(ctx, { + agentOptions, + setup: async ({ meta, events }) => (await composeAgent(resolveSessionPreset({ header: meta, events }))).setup, + }); + /** Send one transient frame to every connected mux consumer. */ + function broadcast(payload) { + const envelope = frame(payload); + for (const queue of muxQueues) + queue.push(envelope); + } + // Projection change feed → session/projection push frames. The carrier + // mints the wire frame (the Service Definition package holds no wire vocabulary); the + // child activates only when a projection registry is composed, and the + // subscription unwinds with this gateway's fiber. + ctx.inject(['sessionProjections'], (projectionCtx) => { + projectionCtx.sessionProjections.onChanged((session, key, value, seq) => { + broadcast({ type: 'session/projection', sessionId: session.id, key, value, seq }); + }); + }); + // The cache supplies recency and a monotonic non-blank hint. A cached + // `blank: true` remains only a prefix fact and is verified on the cold path. + ctx.inject(['sessionProjections'], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: 'sessionListMetadata', + schema: sessionListMetadataProjectionSchema, + init: () => ({ blank: true, lastPromptAt: null }), + apply: applySessionListMetadata, + view: state => state, + stateVersion: 1, + }); + }); + // The imageLimits projection unit: the attachments config this proxy + // enforces at prompt admission, constant per host boot. `apply` keeps the + // same state reference for every event, so no change frames are ever + // pushed — baselines alone carry the value — and clients pre-check intake + // and label upload affordances from it. Registered here, not in the + // attachment Service Definition: dsh-llm depends on dsh-attachment, so the + // seam package cannot reference the projection registry without a cycle, + // and the per-message rules the value describes are this proxy's own + // admission checks. The child activates only while both seams are composed. + // `view` reading the live service instead of the (null) state is sanctioned + // exactly for boot-constant units: the value cannot change within a process + // lifetime, so the fold stays observationally pure, and a stale persisted + // cache row re-viewing to the current config is the correct outcome. + ctx.inject(['sessionProjections', 'attachments'], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: 'imageLimits', + schema: imageLimitsProjectionSchema, + init: () => null, + apply: state => state, + view: () => projectionCtx.attachments.imageLimits, + stateVersion: 1, + }); + }); + /** Project both durable inbox lists, optionally including the splice currently being emitted. */ + const queueItems = (agent, splice) => { + const project = (target) => { + const messages = target === 'next-turn' ? agent.inbox.nextTurn : agent.inbox.nextStep; + return splice?.target === target + ? messages.toSpliced(splice.start, splice.removedCount ?? 0, ...splice.inserted) + : messages; + }; + return [ + ...project('next-turn').map(message => ({ id: message.id, placement: 'queued', message })), + ...project('next-step').map(message => ({ + id: message.id, + // Only user-origin messages are steering; injected context (approval + // notices, task completion, attached snapshots) is not a user action + // and must not render as a pending steering bubble. + placement: message.source.kind === 'user' ? 'steering' : 'context', + message, + })), + ]; + }; + ctx.on('session/event', (session, event) => { + if (event.type !== 'agent/inbox/spliced') + return; + const agent = ctx.agents.get(session.id); + if (agent?.session !== session) + return; + broadcast({ type: 'session/queue', sessionId: session.id, items: queueItems(agent, event.data) }); + }); + /** Remove a wait before settling it: synchronous deletion makes the first claimant win. */ + function claimQuestion(pending, outcome) { + pendingQuestions.delete(pending.rpcId); + if (pending.signal !== undefined && pending.onAbort !== undefined) { + pending.signal.removeEventListener('abort', pending.onAbort); + } + broadcast({ + type: 'question/resolved', sessionId: pending.sessionId, + questionRpcId: pending.rpcId, outcome, + }); + } + const disposeProvider = ctx.userQuestions.registerProvider({ + ask(request) { + const sessionId = request.agent?.id; + if (sessionId === undefined) { + return Promise.reject(new UserQuestionError('web user interaction requires an agent-owned session', 'ASK_MISSING_AGENT')); + } + return new Promise((resolve, reject) => { + const rpcId = RpcId(randomUUID()); + const pending = { + rpcId, sessionId, questions: request.questions, resolve, reject, + ...(request.signal === undefined ? {} : { signal: request.signal }), + }; + const onAbort = () => { + claimQuestion(pending, 'cancelled'); + reject(new UserQuestionError('ask_user_question was aborted before the user answered', 'ASK_ABORTED')); + }; + pending.onAbort = onAbort; + pendingQuestions.set(rpcId, pending); + request.signal?.addEventListener('abort', onAbort, { once: true }); + const envelope = { + rpcId, + payload: { type: 'question/requested', sessionId, questions: request.questions }, + }; + for (const queue of muxQueues) + queue.push(envelope); + }); + }, + }); + ctx.effect(() => () => { + disposeProvider(); + for (const pending of [...pendingQuestions.values()]) { + claimQuestion(pending, 'cancelled'); + pending.reject(new UserQuestionError('web user-questions provider was disposed', 'ASK_ABORTED')); + } + }, 'api-proxy: user-questions provider'); + // --- Approval pending registry ------------------------------------------ + // The proxy is the approval channel for every agent this host owns: an ask + // through `ctx.approval` becomes an answerable server-request on the mux + // stream (stable rpcId), settled by POST /api/respond. The entry survives + // client disconnects — mux-open replays still-pending requested frames with + // the same rpcId (the refresh-recovery baseline) — and withdraws on the + // ask's own abort signal (turn cancel), pushing `cancelled` to subscribers. + if (ctx.get('approval') !== undefined) { + // Teardown parity with the question provider above: a gateway disposed + // while approvals are pending settles every entry as 'cancelled' (the + // service's fail-closed vocabulary), so no ask promise dangles past the + // proxy's lifetime and subscribers see the withdrawal. + ctx.effect(() => () => { + for (const pending of [...pendingApprovals.values()]) + pending.resolve('cancelled'); + }, 'api-proxy: approval registry teardown'); + ctx.on('approval/request', (req, next) => { + // Dispatch rides a microtask behind the service's own signal check: an + // abort landing in that window would register the abort listener AFTER + // the signal fired — never invoked, entry pending forever, zombie frame + // on every mux replay. Settle synchronously instead of publishing. + if (req.signal?.aborted === true) + return Promise.resolve('cancelled'); + // The audit pair `approval/asked` is already appended by the service + // before dispatch, but dispatch rides a microtask: parallel tool calls + // can append several asked events before any answerer runs. THIS + // request's event is therefore the newest asked event that is still + // undecided, unclaimed by another pending entry, and — when the ask + // names a call — carries the same callId. + const events = req.agent.session.events; + const claimed = new Set(); + for (const entry of pendingApprovals.values()) + claimed.add(entry.approvalId); + const decided = new Set(); + let approvalId; + for (let i = events.length - 1; i >= 0; i -= 1) { + const event = events[i]; + if (event.type === 'approval/decided') { + decided.add(event.data.id); + } + else if (event.type === 'approval/asked') { + if (decided.has(event.data.id) || claimed.has(event.data.id)) + continue; + // Symmetric pairing: a callId-bearing ask only takes its own call's + // record, and a callId-less ask only takes a callId-less record — + // so neither shape can steal the other's audit id under parallel + // asks. (Today every producer — the tool executor — passes callId; + // the callId-less arm guards any future non-tool asker.) + if ((req.callId ?? null) !== (event.data.callId ?? null)) + continue; + approvalId = event.data.id; + break; + } + } + // No asked event means the request bypassed the service's audit path — + // not this channel's question; delegate to the fail-closed default. + if (approvalId === undefined) + return next(); + const id = approvalId; + return new Promise((resolve) => { + const settle = (outcome) => { + /* v8 ignore next 3 -- defensive double-settle guard: respond() routes + through the pending table (a settled id is not-pending before it can + re-settle) and the first settle removes the abort listener, so no + reachable path settles twice; kept against future settle callers. */ + if (!pendingApprovals.delete(pending.rpcId)) + return; + req.signal?.removeEventListener('abort', onAbort); + broadcast({ type: 'approval/resolved', sessionId: pending.sessionId, approvalId: id, outcome }); + // A cancelled ask was already settled by the service's own signal + // race, which discards this late resolution; resolving is a no-op + // there and keeps this promise from dangling forever. + resolve(outcome); + }; + const onAbort = () => { settle('cancelled'); }; + const pending = { + rpcId: RpcId(randomUUID()), + sessionId: req.agent.session.id, + approvalId: id, + toolName: req.toolName, + ...req.callId === undefined ? {} : { callId: req.callId }, + ...req.reason === undefined ? {} : { reason: req.reason }, + resolve: settle, + }; + pendingApprovals.set(pending.rpcId, pending); + req.signal?.addEventListener('abort', onAbort, { once: true }); + const envelope = requestedFrame(pending); + for (const queue of muxQueues) + queue.push(envelope); + }); + }); + } + /** Read one stable session prefix without acquiring an Agent owner. */ + async function readSessionState(sessionId) { + const attached = ctx.sessions.get(sessionId); + if (attached !== undefined) { + return { + id: attached.id, + header: attached.header, + events: [...attached.events], + }; + } + const inspected = await inspectServable(sessionId); + return { id: inspected.meta.id, header: inspected.meta, events: inspected.events }; + } + /** Resolve the Workspace inherited by a fork without making ordinary loose lineage grouped. */ + async function forkWorkspace(source) { + const workspaces = ctx.workspaceRegistry.list(); + const direct = workspaces.find(workspace => workspace.sessionIds.includes(source.id)); + if (direct !== undefined || source.header.origin !== 'subagent') + return direct; + const lineage = await ctx.sessionQuery.traceSession(source.id); + for (const ancestor of lineage.ancestors) { + const workspace = workspaces.find(candidate => candidate.sessionIds.includes(ancestor.header.id)); + if (workspace !== undefined) + return workspace; + } + return undefined; + } + /** + * Resolve which session one transcript read is served from, without + * acquiring an Agent owner. This is the read's only asynchronous step + * besides ensuring the composition; {@link historyCutOf} takes the cut. + * @param sessionId - the transcript being read. + * @returns the attached session, or the inspected detached header and events. + * @throws {@link ApiRemoteSessionNotFound} when no project-backed session has that identity. + */ + async function historySourceFor(sessionId) { + const attached = ctx.sessions.get(sessionId); + if (attached !== undefined) + return { kind: 'attached', session: attached }; + const inspected = await inspectServable(sessionId); + return { kind: 'detached', header: inspected.meta, events: inspected.events }; + } + /** + * The header and events {@link presenterScopeFor} reads to decide which + * composition a transcript ran under. + * @param source - the live or detached session this read is served from. + * @returns that session's creation header and its events. + */ + function sourceSession(source) { + if (source.kind === 'detached') + return { header: source.header, events: source.events }; + return { header: source.session.header, events: source.session.events }; + } + /** + * One transcript cut: the events and the projection baseline that describe + * the SAME log position. + * + * Synchronous, and the two reads sit next to each other, because an attached + * session keeps appending: an `await` between them would serve events cut at + * N beside a baseline folded to N+1, which is one response describing two + * moments. The caller does its awaiting before this call. + * @param source - the live or detached session this read is served from. + * @param includeProjections - whether the caller asked for the baseline (a tail page does). + * @returns the events and, when asked, the baseline for that same position. + */ + function historyCutOf(source, includeProjections) { + if (source.kind === 'detached') { + const projections = includeProjections ? detachedProjectionsFor(ctx, source.events) : undefined; + return { events: source.events, ...projections === undefined ? {} : { projections } }; + } + const events = [...source.session.events]; + const projections = includeProjections ? projectionsFor(ctx, source.session) : undefined; + return { events, ...projections === undefined ? {} : { projections } }; + } + /** + * The registry view scope a transcript's presenters resolve in. + * + * A live agent is that scope itself (its chain passes through its preset's + * standing layer). A cold session resolves its preset from the LOG, and the + * preset's STANDING key serves without resuming anything — ensuring the + * mount composes plugins but starts no agent, session, or turn. No roster, + * no recorded preset, or a preset the roster no longer supplies all fall + * back to the global layer: the transcript still serves, with the generic + * cards a viewless entry renders. + * + * Reading the header alone would render a session that switched while blank + * through the composition it was CREATED with. Every tool only the newer + * preset registers resolves to no presenter there, and the transcript + * silently degrades to generic cards for exactly the calls its history is + * made of. + * @param sessionId - the transcript being read. + * @param session - that session's header and log (attached or inspected). + * @returns the scope to pass to presenter lookups, or undefined for global. + */ + async function presenterScopeFor(sessionId, session) { + const live = ctx.get('agents')?.get(sessionId); + if (live !== undefined) + return live; + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return undefined; + try { + // An unrecorded preset (a log from before the roster existed) renders + // through the DEFAULT preset's standing layer: that is the composition + // an unnamed session composes today, and presenters are pure display, + // so the worst a mismatch produces is the generic card it had anyway. + return await presets.standingKeyFor(resolveSessionPreset(session)); + } + catch { + // Swallows only the unknown/unusable-preset rejection from the roster: + // a deleted or broken preset must degrade this read, never fail it. + return undefined; + } + } + /** Resolve one requested identity to a live agent, creating or resuming it once. */ + async function ensureSession(sessionId, cwd, checkPersistedIdentity, presetId) { + let creation = sessionCreations.get(sessionId); + if (creation === undefined) { + creation = (async () => { + const attached = ctx.sessions.get(sessionId); + const live = ctx.agents.get(sessionId); + if (attached !== undefined && hasSubagentOwner(attached, live)) { + throw new SubagentSessionOwnership(sessionId); + } + if (live !== undefined) + return live; + const persistence = checkPersistedIdentity ? ctx.get('sessionPersistence') : undefined; + const stored = persistence === undefined + ? undefined + : (await persistence.list()).find(header => header.id === sessionId); + if (persistence !== undefined && stored !== undefined) { + const inspected = await persistence.inspect(sessionId); + // Ownership first: explicit-id adoption of a session-backed + // subagent must answer `agent-busy` regardless of the requested + // cwd (the api/commands.ts contract), not a cwd conflict. + if (hasSubagentOwner({ header: inspected.meta }, undefined)) { + throw new SubagentSessionOwnership(sessionId); + } + if (inspected.meta.cwd !== cwd) { + throw new SessionCwdConflict(sessionId, cwd, inspected.meta.cwd); + } + // Resolved from the log, not the header: a session that switched + // while blank ran every turn under the newer composition. + const storedPreset = resolveSessionPreset({ header: inspected.meta, events: inspected.events }); + assertPresetUnchanged(sessionId, presetId, storedPreset); + // The stored preset wins over anything the request names: a resumed + // session's history was produced under that composition, and + // rebuilding it differently would replay tool calls the model can no + // longer make. + return (await ctx.agents.resume({ + resumeSessionId: sessionId, + agentOptions: agentOptions(), + setup: (await composeAgent(storedPreset)).setup, + })).agent; + } + try { + await mkdir(cwd, { recursive: true }); + } + catch (error) { + throw new Error(`failed to ensure project directory "${cwd}": ${String(error)}`, { cause: error }); + } + const composition = await composeAgent(presetId); + return (await ctx.agents.create({ + sessionId, + agentOptions: agentOptions(), + meta: { + cwd, + ...composition.agentPreset === undefined ? {} : { agentPreset: composition.agentPreset }, + }, + setup: composition.setup, + })).agent; + })().catch((error) => { + // Another Host entry path may have published the same identity while + // this operation crossed an asynchronous persistence/filesystem step. + const live = ctx.agents.get(sessionId); + if (live !== undefined) { + if (hasSubagentOwner(live.session, live)) + throw new SubagentSessionOwnership(sessionId); + return live; + } + const attached = ctx.sessions.get(sessionId); + if (attached !== undefined && hasSubagentOwner(attached, undefined)) { + throw new SubagentSessionOwnership(sessionId); + } + throw error; + }).finally(() => { + sessionCreations.delete(sessionId); + }); + sessionCreations.set(sessionId, creation); + } + const agent = await creation; + if (hasSubagentOwner(agent.session, agent)) + throw new SubagentSessionOwnership(sessionId); + // Beside the cwd check for the same reason, and after the await so it + // covers every path that yields a live agent — freshly created, adopted + // live, resumed from disk, or recovered by the concurrent-creation catch. + assertPresetUnchanged(sessionId, presetId, resolveSessionPreset(agent.session)); + if (agent.session.header.cwd !== cwd) { + throw new SessionCwdConflict(sessionId, cwd, agent.session.header.cwd); + } + return agent; + } + /** Resolve or create one path while holding the Host's workspace-create chain. */ + function ensureWorkspace(path) { + const operation = workspaceCreationChain.then(async () => { + const existing = await ctx.workspaceRegistry.resolveByPath(path); + if (existing !== undefined) + return { workspace: existing, created: false }; + return { workspace: await ctx.workspaceRegistry.create(path), created: true }; + }); + workspaceCreationChain = operation.then(() => undefined, () => undefined); + return operation; + } + /** + * Build the session.list baseline shared by listing and search visibility. + * Attached sessions come from memory; servable cold sessions merge from + * persistence, and the final order is newest-first. + */ + async function listVisibleSessionSummaries(signal) { + signal?.throwIfAborted(); + const summarizeAttached = (session) => { + const agent = ctx.agents.get(session.id); + const projections = listProjectionsFor(ctx, session.header, session); + return { + ...summarize(session, agent?.status === 'running'), + ...projections === undefined ? {} : { projections }, + }; + }; + const items = ctx.sessions.list().map(summarizeAttached); + signal?.throwIfAborted(); + const attached = new Set(items.map(item => item.sessionId)); + const persistence = ctx.get('sessionPersistence'); + if (persistence !== undefined) { + const cold = (await persistence.list(signal)) + .filter(meta => !attached.has(meta.id) && meta.cwd !== undefined); + signal?.throwIfAborted(); + for (let offset = 0; offset < cold.length; offset += COLD_SUMMARY_BATCH_SIZE) { + signal?.throwIfAborted(); + const batch = cold.slice(offset, offset + COLD_SUMMARY_BATCH_SIZE); + const settled = await Promise.allSettled(batch.map(async (meta) => { + // Projection hints remain optional. Blank verification may read + // this Session's artifact only when it passes the configured size check. + const projections = listProjectionsFor(ctx, meta, undefined); + const summary = await summarizeCold(ctx, persistence, meta, projections?.values.sessionListMetadata, coldBlankProbeMaxBytes, signal); + const attachedSession = ctx.sessions.get(meta.id); + if (attachedSession !== undefined) + return summarizeAttached(attachedSession); + return { + ...summary, + ...projections === undefined ? {} : { projections }, + }; + })); + const summaries = []; + let rejected = false; + let failure; + for (const result of settled) { + if (result.status === 'fulfilled') { + summaries.push(result.value); + } + else if (!rejected) { + rejected = true; + failure = result.reason; + } + } + if (rejected) + throw failure; + signal?.throwIfAborted(); + items.push(...summaries); + } + } + items.sort((a, b) => b.updatedAt - a.updatedAt); + return items; + } + /** + * Resolve the goal service THIS agent runs. + * + * The service is per session: an agent preset mounts it behind an `isolate` + * realm, which no host context resolves. Reading it from the root would + * answer "absent" for a session whose composition mounts it — so the lookup + * is keyed by the agent, and only a deployment composing it nowhere is + * genuinely absent. + */ + function goalServiceFor(agent) { + const presets = ctx.get('agentPresets'); + const goals = presets?.serviceFor(agent, 'goals') ?? ctx.get('goals'); + if (goals === undefined) { + return { error: { code: 'internal', message: 'goal service is absent: neither this session\'s agent preset nor the host composition mounts @deepseek-ai/dsh-goal', details: {} } }; + } + return goals; + } + /** Map one goal-domain rejection to the wire error (stable GoalError codes ride in details). */ + function goalError(request, error) { + const details = error instanceof GoalError ? { goalCode: error.code } : {}; + return err(request, { code: 'internal', message: String(error), details }); + } + /** Resolve a session's agent, apply one goal mutation, and acknowledge with the new CAS ref. */ + async function mutateGoal(request, mutation) { + const found = await agentFor(request.payload.sessionId); + if ('error' in found) + return err(request, found.error); + const goals = goalServiceFor(found.agent); + if ('error' in goals) + return err(request, goals.error); + try { + const ref = mutation(goals, found.agent); + return ok(request, { ref: { id: ref.id, revision: ref.revision } }); + } + catch (error) { + return goalError(request, error); + } + } + /** + * Whether an adapter currently serves this provider, and therefore whether + * a session selecting it can start a turn. Catalog membership cannot answer + * it: an adapter may serve a model its own catalog stopped advertising, so + * a provider missing from the groups is not the same as one nothing serves. + * A composition with no llm registry at all cannot judge and says yes — + * the dispatch it would have refused fails on its own terms. + */ + function routeServed(provider) { + const llm = ctx.get('llm'); + return llm === undefined || llm.listProviders().some(entry => entry.id === provider); + } + /** + * Resolve the addressed agent for a turn-starting method and refuse when no + * adapter serves its current selection: a provider nothing serves cannot start a + * turn, and letting it try spends the whole pre-step path to fail inside + * the adapter with a message about registration. Refusing here names the + * model the session is pointed at while the draft is still in the composer. + * This is `session.prompt`'s enforcement boundary: a client that disables + * its input is an affordance, and the method stays callable regardless. + */ + async function turnAgentFor(request, sessionId) { + const found = await agentFor(sessionId); + if ('error' in found) + return { refused: err(request, found.error) }; + const agent = found.agent; + const selection = selectionFor(agent).current; + if (!routeServed(selection.provider)) { + return { + refused: err(request, { + code: 'model-unavailable', + message: `no adapter serves provider "${selection.provider}"; select a model for this session`, + details: { provider: selection.provider, model: selection.model }, + }), + }; + } + return { agent }; + } + /** Missing-service report shared by the settings domain (skills-domain stance). */ + function settingsAbsent() { + return { code: 'internal', message: 'settings service is absent: this deployment does not mount a settings provider (e.g. @deepseek-ai/dsh-settings-file) in its composition', details: {} }; + } + /** Open one Host-resolved target and map native failures onto the wire vocabulary. */ + async function openTarget(request, path, signal, open) { + try { + await open(path, signal); + return ok(request, { opened: true }); + } + catch (error) { + if (signal.aborted) { + return err(request, { + code: 'cancelled', + message: 'path open was aborted', + details: {}, + }); + } + return err(request, { + code: 'internal', + message: `path open failed: ${error instanceof Error ? error.message : String(error)}`, + details: {}, + }); + } + } + /** Open one Host-resolved path with its default application. */ + function openPath(request, path, signal) { + const open = defaults.openPath + ?? ((target, openSignal) => openNativePath(target, openSignal)); + return openTarget(request, path, signal, open); + } + /** Open one Host-resolved text document in a native editor. */ + function openTextFile(request, path, signal) { + const open = defaults.openTextFile + ?? ((target, openSignal) => openNativeTextFile(target, openSignal)); + return openTarget(request, path, signal, open); + } + /** Whether this deployment can hand a path to a native opener at all. */ + function canOpenPaths() { + if (defaults.canOpenPath !== undefined) + return defaults.canOpenPath(); + // An injected opener is by definition usable; otherwise ask the platform. + return defaults.openPath !== undefined || canOpenNativePath(); + } + /** Missing-service report shared by the credentials domain. */ + function credentialsAbsent() { + return { code: 'internal', message: 'credentials service is absent: this deployment does not mount a credential provider (e.g. @deepseek-ai/dsh-credentials-local) in its composition', details: {} }; + } + /** Map one redacted settings descriptor to its wire view. */ + function namespaceView(descriptor) { + return { + ns: String(descriptor.ns), + schema: descriptor.schema, + value: descriptor.value, + ...descriptor.base === undefined ? {} : { base: descriptor.base }, + ...descriptor.user === undefined ? {} : { user: descriptor.user }, + applies: descriptor.applies, + secrets: (descriptor.secrets ?? []).map(secret => ({ path: [...secret.path], set: secret.set })), + revision: descriptor.revision, + }; + } + /** Settings namespaces whose changes can invalidate the model catalog. */ + function modelProviderNamespaces() { + return new Set(ctx.llm.listConfigurableProviders().map(entry => entry.settingsNs)); + } + /** + * The settings namespaces this proxy serves: configurable model providers + * plus the small explicit Web preference and product-owned allowlists. The + * settings seam remains general; a future registration does not become + * remotely readable or writable by default. + */ + function exposedNamespaces() { + const exposed = modelProviderNamespaces(); + for (const ns of WEB_SETTINGS_NAMESPACES) + exposed.add(ns); + for (const ns of PRODUCT_SETTINGS_NAMESPACES) + exposed.add(ns); + return exposed; + } + /** Refuse a namespace outside the explicit configuration-client boundary. */ + function notExposed(request, ns) { + return err(request, { + code: 'settings-not-exposed', + message: `settings namespace "${ns}" is not exposed to configuration clients`, + details: { ns }, + }); + } + /** + * Run one settings write (merge or wholesale replace) and acknowledge with + * the namespace's new redacted view. A namespace outside the configuration + * boundary is refused before the seam is touched; every seam refusal — + * unknown or invalid namespace, read-only provider, schema validation, + * storage — becomes one `settings-rejected` carrying the seam's own message. + */ + async function settingsWrite(request, ns, mode, section, expectedRevision) { + const settings = ctx.get('settings'); + if (settings === undefined) + return err(request, settingsAbsent()); + const rejected = (error) => { + // A stale writer is its own outcome, not a malformed request: the client + // must re-read and re-apply rather than treat the write as invalid. + if (error instanceof SettingsConflictError) { + return err(request, { + code: 'settings-conflict', + message: error.message, + details: { ns, expected: error.expected, actual: error.actual }, + }); + } + return err(request, { + code: 'settings-rejected', + message: error instanceof Error ? error.message : String(error), + details: { ns }, + }); + }; + let branded; + try { + branded = settingsNamespace(ns); + } + catch (error) { + // A malformed name is a client bug, reported as such; it could never be + // in the exposed set either, so naming the real fault costs no ground. + return rejected(error); + } + if (!exposedNamespaces().has(ns)) + return notExposed(request, ns); + try { + if (mode === 'update') + await settings.update(branded, section, expectedRevision); + else if (mode === 'replace') + await settings.replace(branded, section, expectedRevision); + else + await settings.mutate(branded, section, expectedRevision); + } + catch (error) { + return rejected(error); + } + const descriptor = settings.describe({ redactSecrets: true }).find(candidate => candidate.ns === branded); + if (descriptor === undefined) { + // The write committed but the namespace vanished before this read: only + // a concurrent registrant disposal can produce it. + return err(request, { code: 'internal', message: `settings namespace "${ns}" was disposed after the ${mode}`, details: {} }); + } + return ok(request, namespaceView(descriptor)); + } + return { + sessions: { + // Attached sessions summarize from memory; persisted-but-unattached (cold) + // sessions merge in from the persistence store so history survives restarts. + // Logs without a cwd are not served; every session records its project + // at create time. + async list(request) { + return ok(request, { items: await listVisibleSessionSummaries() }); + }, + async search(request, signal) { + const cancelled = () => err(request, { + code: 'cancelled', + message: 'session search was aborted', + details: {}, + }); + if (isAborted(signal)) + return cancelled(); + const sessionQuery = ctx.get('sessionQuery'); + if (sessionQuery === undefined) { + return err(request, { + code: 'internal', + message: 'session search is unavailable: this deployment does not mount @deepseek-ai/dsh-session-query', + details: {}, + }); + } + try { + const visible = await listVisibleSessionSummaries(signal); + if (isAborted(signal)) + return cancelled(); + if (visible.length === 0) + return ok(request, { items: [], hasMore: false }); + const visibleIds = new Set(visible.map(item => item.sessionId)); + const authorized = []; + const acceptedIds = new Set(); + const seenCursors = new Set(); + let cursor; + let providerCallCount = 0; + let providerPageLimit = SESSION_SEARCH_RESULT_LIMIT; + while (authorized.length <= SESSION_SEARCH_RESULT_LIMIT) { + if (isAborted(signal)) + return cancelled(); + if (providerCallCount >= SESSION_SEARCH_PROVIDER_CALL_LIMIT) { + throw new Error(`session search provider exceeded the ${SESSION_SEARCH_PROVIDER_CALL_LIMIT}-call work budget`); + } + providerCallCount++; + const requestedCursor = cursor; + const requestedPageLimit = providerPageLimit; + let page; + try { + page = await sessionQuery.searchSessions({ + query: request.payload.query, + eventFilters: [ + { kind: 'type', values: ['user/message', 'assistant/message'] }, + { kind: 'surface', values: ['current'] }, + ], + limit: requestedPageLimit, + ...requestedCursor === undefined ? {} : { cursor: requestedCursor }, + }, { signal }); + } + catch (error) { + if (isAborted(signal)) + return cancelled(); + if (requestedCursor === undefined + && error instanceof SessionQueryError + && error.code === 'SESSION_QUERY_INVALID_LIMIT' + && requestedPageLimit > 1) { + providerPageLimit = Math.max(1, Math.floor(requestedPageLimit / 2)); + continue; + } + if (requestedCursor !== undefined + && error instanceof SessionQueryError + && error.code === 'SESSION_QUERY_STALE_CURSOR') { + authorized.length = 0; + acceptedIds.clear(); + seenCursors.clear(); + cursor = undefined; + continue; + } + throw error; + } + if (isAborted(signal)) + return cancelled(); + const providerItemCount = page.items.length; + if (providerItemCount > requestedPageLimit) { + throw new Error(`session search provider returned ${providerItemCount} items; maximum is ${requestedPageLimit}`); + } + // Host visibility is the authorization boundary. Consume the + // provider's globally ranked results rather than binding every + // visible id into one SQLite statement, then require each hit to + // name a visible session and a current message from that same + // session before emitting its snippet. + for (const hit of page.items) { + if (authorized.length > SESSION_SEARCH_RESULT_LIMIT) + continue; + if (!visibleIds.has(hit.header.id) + || hit.bestMatch.sessionId !== hit.header.id + || hit.bestMatch.surface !== 'current' + || !MESSAGE_TYPES.has(hit.bestMatch.type) + || acceptedIds.has(hit.header.id)) + continue; + const snippet = truncateUnicodeCodePoints(hit.bestMatch.snippet, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS); + acceptedIds.add(hit.header.id); + authorized.push({ + sessionId: hit.header.id, + snippet, + }); + } + const nextCursor = page.nextCursor; + if (nextCursor !== undefined) { + if (seenCursors.has(nextCursor)) { + throw new Error('session search provider repeated a continuation cursor'); + } + seenCursors.add(nextCursor); + } + if (authorized.length > SESSION_SEARCH_RESULT_LIMIT || nextCursor === undefined) + break; + cursor = nextCursor; + } + return ok(request, { + items: authorized.slice(0, SESSION_SEARCH_RESULT_LIMIT), + hasMore: authorized.length > SESSION_SEARCH_RESULT_LIMIT, + }); + } + catch (error) { + if (isAborted(signal) + || (error instanceof SessionQueryError && error.code === 'SESSION_QUERY_ABORTED')) + return cancelled(); + // XXX: Redact provider details before exposing this gateway beyond + // its current single-user local deployment. + return err(request, { + code: 'internal', + message: `session search failed: ${String(error)}`, + details: {}, + }); + } + }, + async create(request) { + const sessionId = request.payload.sessionId ?? `session-${randomUUID()}`; + let workspace; + if (request.payload.workspaceId !== undefined) { + workspace = ctx.workspaceRegistry.get(brandWorkspaceId(request.payload.workspaceId)); + if (workspace === undefined) { + return err(request, { + code: 'workspace-not-found', + message: `workspace "${request.payload.workspaceId}" not found`, + details: { workspaceId: request.payload.workspaceId }, + }); + } + } + const cwd = workspace?.path ?? request.payload.cwd ?? defaults.cwd; + const requestedPreset = request.payload.agentPreset; + try { + await ensureSession(sessionId, cwd, request.payload.sessionId !== undefined, requestedPreset); + } + catch (error) { + if (error instanceof AgentPresetConflict) { + return err(request, { + code: 'agent-preset-conflict', + message: error.message, + details: { + sessionId: error.sessionId, + requestedPreset: error.requestedPreset, + ...error.existingPreset === undefined ? {} : { existingPreset: error.existingPreset }, + }, + }); + } + const refused = presetFailure(request, error); + if (refused !== undefined) + return refused; + if (error instanceof SessionCwdConflict) { + return err(request, { + code: 'session-conflict', + message: error.message, + details: { + sessionId: error.sessionId, + requestedCwd: error.requestedCwd, + ...error.existingCwd === undefined ? {} : { existingCwd: error.existingCwd }, + }, + }); + } + if (error instanceof SubagentSessionOwnership) { + return err(request, subagentOwnershipError(error.sessionId)); + } + return err(request, { + code: 'internal', + message: `failed to create session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + if (workspace !== undefined) { + try { + await workspace.attachSession(sessionId); + } + catch (error) { + return err(request, { + code: 'workspace-attach-failed', + message: `session "${sessionId}" was created but could not attach to workspace "${workspace.id}": ${String(error)}`, + details: { sessionId, workspaceId: workspace.id }, + }); + } + } + // Echo the composition the session RUNS so a client can label it + // without waiting for the next list refresh — the create is the commit + // point that knows it (a caller that named none gets the default). + // Resolved from the log for the same reason `sessionListFields()` is: + // this handler also adopts an already-live session, and one that + // switched while blank runs a preset its header no longer names, so + // echoing the header would contradict both the adoption this call just + // allowed and the row `session.list` serves for the same session. + const created = ctx.agents.get(sessionId); + const createdPreset = created === undefined ? undefined : resolveSessionPreset(created.session); + return ok(request, { sessionId, ...createdPreset === undefined ? {} : { agentPreset: createdPreset } }); + }, + async history(request) { + const { sessionId, beforeSeq, maxMessages } = request.payload; + try { + const source = await historySourceFor(sessionId); + // Both awaits happen BEFORE the cut. Ensuring the recorded + // composition's standing mount is what registers its projection + // units, so a first cold read would otherwise serve a baseline + // missing every preset-owned key; and an attached session keeps + // appending, so awaiting between the two reads would pair events cut + // at N with a baseline folded to N+1. + const scope = await presenterScopeFor(sessionId, sourceSession(source)); + const cut = historyCutOf(source, beforeSeq === undefined); + const page = historyPage(ctx, cut.events, beforeSeq, maxMessages, scope); + return ok(request, { + events: page.events, + hasMore: page.hasMore, + ...cut.projections === undefined ? {} : { projections: cut.projections }, + }); + } + catch (error) { + if (error instanceof SessionNotFound) { + return err(request, { code: 'session-not-found', message: error.message, details: { sessionId } }); + } + return err(request, { + code: 'internal', + message: `history unavailable for session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + }, + async models(request) { + const { sessionId } = request.payload; + const found = await agentFor(sessionId); + if ('error' in found) + return err(request, found.error); + const current = selectionFor(found.agent).current; + const { groups, failures } = await buildModelCatalog(ctx); + const routable = routeServed(current.provider); + return ok(request, { current: { ...current }, routable, groups, failures }); + }, + async selectModel(request) { + const { sessionId, provider, model, reasoningEffort } = request.payload; + const found = await agentFor(sessionId); + if ('error' in found) + return err(request, found.error); + return serializeImageAdmission(found.agent, async () => { + try { + const resolved = await ctx.llm.resolveCallConfig({ + provider, + model, + ...reasoningEffort === undefined + ? {} + : { reasoningEffort: ReasoningEffortId(reasoningEffort) }, + }); + const pendingImage = [...found.agent.inbox.nextTurn, ...found.agent.inbox.nextStep] + .some(message => contentHasImage(message.content)); + if (pendingImage || messagesHaveImage(found.agent.session.deriveMessages())) { + const info = await ctx.llm.resolveModelInfo(resolved.provider, resolved.model); + if (info.inputModalities !== undefined && !info.inputModalities.includes('image')) { + return err(request, { + code: 'model-unavailable', + message: `Model "${resolved.model}" does not accept image input, but this session already contains images; select an image-capable model.`, + details: { provider, model }, + }); + } + } + const selected = { + provider: resolved.provider, + model: resolved.model, + ...resolved.reasoningEffort === undefined + ? {} + : { reasoningEffort: resolved.reasoningEffort }, + }; + selectionFor(found.agent).current = selected; + try { + await defaults.saveDefaultModelSelection?.(selected); + } + catch (error) { + ctx.logger.warn(`api-proxy: the model switch applies to this session but was not saved as the default: ${String(error)}`); + } + return ok(request, { selected: { ...selected } }); + } + catch (error) { + return err(request, { + code: 'model-unavailable', + message: error instanceof Error ? error.message : String(error), + details: { provider, model }, + }); + } + }); + }, + async rename(request) { + const { sessionId, title } = request.payload; + const found = await agentFor(sessionId); + if ('error' in found) + return err(request, found.error); + const titles = ctx.get('sessionTitle'); + if (titles === undefined) { + return err(request, { code: 'internal', message: 'renaming is unavailable: this deployment mounts no session-title service', details: {} }); + } + try { + const accepted = titles.rename(found.agent.session, title); + return ok(request, { title: accepted.title, seq: accepted.eventSeq }); + } + catch (error) { + // Only the input's fault maps to title-invalid (the message is + // product-user-visible in the rename dialog); liveness and disposal + // races are deployment trouble, not a bad title. + if (error instanceof SessionTitleInvalidError) { + return err(request, { + code: 'title-invalid', + message: error.message, + details: { sessionId }, + }); + } + return err(request, { + code: 'internal', + message: `failed to rename session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + }, + async fork(request) { + const { sessionId, atSeq } = request.payload; + let source; + try { + source = await readSessionState(sessionId); + } + catch (error) { + if (error instanceof SessionNotFound) { + return err(request, { code: 'session-not-found', message: error.message, details: { sessionId } }); + } + return err(request, { + code: 'internal', + message: `fork source unavailable for session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + const events = source.events; + // An in-log anchor belongs to the turn containing it and must never + // clip backward to an earlier completed turn. Omitted and past-end + // anchors retain the last-completed-turn shortcut. + const lastSeq = events.at(-1)?.seq ?? -1; + const anchoredBoundary = atSeq === undefined + ? undefined + : events.find(e => e.type === 'turn/end' && e.seq >= atSeq); + const boundary = anchoredBoundary + ?? (atSeq === undefined || atSeq > lastSeq + ? events.findLast(e => e.type === 'turn/end') + : undefined); + if (boundary === undefined) { + return err(request, { + code: 'fork-unavailable', + message: atSeq !== undefined && atSeq <= lastSeq + ? `session "${sessionId}" has not completed the turn containing event ${String(atSeq)}` + : `session "${sessionId}" has no completed turn to fork from`, + details: { sessionId }, + }); + } + // Extend the cut through trailing out-of-band appends (session/title, + // injections) up to the next turn/start: they are standalone events, so + // the seed stays balanced, and the child inherits a title generated + // right after the boundary turn. + let cut = boundary.seq + 1; + while (cut < events.length && events[cut]?.type !== 'turn/start') + cut++; + let workspace; + try { + workspace = await forkWorkspace(source); + } + catch (error) { + return err(request, { + code: 'internal', + message: `failed to resolve fork workspace for session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + const childId = `session-${randomUUID()}`; + // The child inherits the parent's composition for the same reason a + // resumed session keeps its own: the seeded history was produced under + // those tools, and composing anything else would strand the tool calls + // it already carries. Now that no model-facing row sits in the host + // plane, composing nothing would leave the child with no tools at all. + const forkComposition = await composeAgent(resolveSessionPreset(source)); + try { + await ctx.agents.create({ + sessionId: childId, + seed: events.slice(0, cut), + meta: { + ...source.header.cwd === undefined ? {} : { cwd: source.header.cwd }, + parentSession: source.id, + seedLength: cut, + ...forkComposition.agentPreset === undefined + ? {} + : { agentPreset: forkComposition.agentPreset }, + }, + agentOptions: agentOptions(), + setup: forkComposition.setup, + }); + } + catch (error) { + return err(request, { + code: 'internal', + message: `failed to fork session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + // An ordinary source keeps its direct Workspace. A subagent source is + // not listed there, so its ordinary fork joins the nearest owning + // ancestor instead. The child is already published if attach fails. + if (workspace !== undefined) { + try { + await workspace.attachSession(childId); + } + catch (error) { + return err(request, { + code: 'workspace-attach-failed', + message: `session "${childId}" was forked but could not attach to workspace "${workspace.id}": ${String(error)}`, + details: { sessionId: childId, workspaceId: workspace.id }, + }); + } + } + return ok(request, { sessionId: childId }); + }, + async prompt(request) { + const { sessionId, mode, content, clientTimeZone } = request.payload; + const canonicalTimeZone = clientTimeZone === undefined + ? undefined + : canonicalClientTimeZone(clientTimeZone); + if (clientTimeZone !== undefined && canonicalTimeZone === undefined) { + return err(request, { + code: 'invalid-time-zone', + message: 'clientTimeZone must be UTC or a valid IANA Area/Location name', + details: { value: clientTimeZone }, + }); + } + const resolved = await turnAgentFor(request, sessionId); + if ('refused' in resolved) + return resolved.refused; + const agent = resolved.agent; + // Request identity and optional browser zone ride the exact durable user message. + const source = { + kind: 'user', + rpcId: request.rpcId, + ...(canonicalTimeZone === undefined ? {} : { clientTimeZone: canonicalTimeZone }), + }; + const hasImage = content.some(part => part.type === 'image'); + const admit = async () => { + try { + if (hasImage) { + const current = selectionFor(agent).current; + const modelInfo = await ctx.llm.resolveModelInfo(current.provider, current.model); + if (modelInfo.inputModalities !== undefined && !modelInfo.inputModalities.includes('image')) { + return err(request, { + code: 'attachment-error', + message: `Model "${current.model}" does not support image input.`, + details: { reason: 'MODEL_DOES_NOT_SUPPORT_IMAGES' }, + }); + } + } + const durable = await durablePromptContent(ctx, content); + const message = createUserMessage({ content: durable, source }); + if (mode === 'steer') + agent.steer(message); + else + agent.followup(message); + } + catch (error) { + if (error instanceof AttachmentError) { + return err(request, { + code: 'attachment-error', + message: error.message, + details: { reason: error.code }, + }); + } + return err(request, { + code: 'agent-busy', + message: 'prompt rejected', + details: { reason: String(error) }, + }); + } + return ok(request, { accepted: true }); + }; + return hasImage ? serializeImageAdmission(agent, admit) : admit(); + }, + async attachment(request) { + const { sessionId, attachmentId } = request.payload; + let state; + try { + state = await readSessionState(sessionId); + } + catch (error) { + if (error instanceof SessionNotFound) { + return err(request, { + code: 'session-not-found', + message: error.message, + details: { sessionId }, + }); + } + return err(request, { + code: 'internal', + message: `attachment authorization unavailable for session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + const ref = referencedImage(state.events, String(attachmentId)); + if (ref === undefined) { + return err(request, { + code: 'attachment-error', + message: 'Image is not referenced by this session.', + details: { reason: 'ATTACHMENT_NOT_REFERENCED' }, + }); + } + try { + const stored = await ctx.attachments.readImage(ref); + return ok(request, { + attachment: stored.ref, + data: Buffer.from(stored.data).toString('base64'), + }); + } + catch (error) { + if (error instanceof AttachmentError) { + return err(request, { + code: 'attachment-error', + message: error.message, + details: { reason: error.code }, + }); + } + return err(request, { + code: 'internal', + message: 'Unable to read image attachment.', + details: {}, + }); + } + }, + updateQueue(request) { + const { sessionId, itemId, action } = request.payload; + if (action.kind === 'edit' && action.content.some(block => block.type !== 'text')) { + return Promise.resolve(err(request, { + code: 'attachment-error', + message: 'queue edits accept text content only', + details: { reason: 'QUEUE_EDIT_NON_TEXT' }, + })); + } + const agent = ctx.agents.get(sessionId); + if (agent !== undefined && hasSubagentOwner(agent.session, agent)) { + return Promise.resolve(err(request, subagentOwnershipError(sessionId))); + } + if (agent === undefined) { + return Promise.resolve(err(request, { + code: 'queue-item-not-found', + message: 'queued item is no longer pending', + details: { itemId }, + })); + } + const target = agent.inbox.nextTurn.some(message => message.id === itemId) + ? 'next-turn' + : agent.inbox.nextStep.some(message => message.id === itemId) ? 'next-step' : undefined; + const message = target === undefined + ? undefined + : (target === 'next-turn' ? agent.inbox.nextTurn : agent.inbox.nextStep) + .find(candidate => candidate.id === itemId); + if (target === undefined || message === undefined) { + return Promise.resolve(err(request, { + code: 'queue-item-not-found', + message: 'queued item is no longer pending', + details: { itemId }, + })); + } + if (action.kind === 'steer' && (target !== 'next-turn' || agent.status !== 'running')) { + return Promise.resolve(err(request, { + code: 'steer-unavailable', + message: 'current turn no longer accepts steering', + details: { itemId }, + })); + } + if (action.kind === 'edit') { + agent.inbox.replace(itemId, freezeMessage({ ...message, content: action.content })); + } + else { + agent.inbox.remove(itemId); + if (action.kind === 'steer') + agent.steer(message); + } + return Promise.resolve(ok(request, { accepted: true })); + }, + cancel(request) { + const { sessionId } = request.payload; + const agent = ctx.agents.get(sessionId); + if (agent === undefined) { + return Promise.resolve(err(request, { + code: 'session-not-found', + message: `session "${sessionId}" not found (not attached)`, + details: { sessionId }, + })); + } + if (hasSubagentOwner(agent.session, agent)) { + return Promise.resolve(err(request, subagentOwnershipError(sessionId))); + } + agent.cancel({ kind: 'user' }, { keepInbox: true }); + return Promise.resolve(ok(request, { accepted: true })); + }, + }, + subagents: { + async list(request, signal) { + try { + const entries = await ctx.subagents.listChildren(request.payload.parentSessionId, signal); + return ok(request, { + entries: entries.map(entry => entry.kind === 'child' + ? { + ...entry, + activity: ctx.agents.get(entry.id)?.status === 'running' ? 'running' : 'inactive', + } + : entry), + parentAvailable: ctx.agents.get(request.payload.parentSessionId) !== undefined, + }); + } + catch (error) { + if (signal?.aborted || (error instanceof SubagentError && error.code === 'CANCELLED')) { + return err(request, { + code: 'cancelled', + message: 'subagent catalog read was cancelled', + details: {}, + }); + } + if (error instanceof SubagentError && error.code === 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE') { + return err(request, projectionsUnavailableError()); + } + return err(request, { + code: 'internal', + message: 'subagent catalog read failed', + details: {}, + }); + } + }, + async history(request, signal) { + const { parentSessionId, childSessionId, mode, beforeSeq, maxMessages, } = request.payload; + const verified = await catalogChild(ctx, { + parentSessionId, childSessionId, mode, + }, signal); + if (verified.error !== undefined) + return err(request, verified.error); + // The generic-history data plane: an attached child serves its + // in-memory snapshot and the registry's live watermark projections; a + // cold child is one persistence inspection plus a detached fold. + let header; + let events; + let projections; + const attached = ctx.sessions.get(childSessionId); + if (attached !== undefined) { + header = attached.header; + events = [...attached.events]; + projections = beforeSeq === undefined + ? subagentHistoryProjections(ctx, childSessionId, () => projectionsFor(ctx, attached)) + : undefined; + } + else { + try { + const inspected = await inspectServable(childSessionId); + header = inspected.meta; + events = inspected.events; + projections = beforeSeq === undefined + ? subagentHistoryProjections(ctx, childSessionId, () => detachedProjectionsFor(ctx, inspected.events)) + : undefined; + } + catch (error) { + if (signal?.aborted) { + return err(request, { + code: 'cancelled', + message: 'subagent history read was cancelled', + details: {}, + }); + } + if (error instanceof SessionNotFound) { + return err(request, { + code: 'subagent-not-found', + message: 'subagent disappeared during history read', + details: { parentSessionId, childSessionId }, + }); + } + return err(request, { + code: 'internal', + message: 'subagent history read failed', + details: {}, + }); + } + } + if (signal?.aborted) { + return err(request, { + code: 'cancelled', + message: 'subagent history read was cancelled', + details: {}, + }); + } + if (header.parentSession !== parentSessionId) { + return err(request, { + code: 'subagent-unauthorized', + message: 'subagent parent changed during history read', + details: { childSessionId }, + }); + } + const page = historyPage(ctx, events, beforeSeq, maxMessages); + return ok(request, { ...page, ...projections === undefined ? {} : { projections } }); + }, + async prompt(request, signal) { + const { parentSessionId, childSessionId, content, clientTimeZone } = request.payload; + const canonicalTimeZone = clientTimeZone === undefined + ? undefined + : canonicalClientTimeZone(clientTimeZone); + if (clientTimeZone !== undefined && canonicalTimeZone === undefined) { + return err(request, { + code: 'invalid-time-zone', + message: 'clientTimeZone must be UTC or a valid IANA Area/Location name', + details: { value: clientTimeZone }, + }); + } + const parent = ctx.agents.get(parentSessionId); + if (parent === undefined) { + return err(request, { + code: 'subagent-parent-unavailable', + message: `parent session "${parentSessionId}" is not live`, + details: { parentSessionId }, + }); + } + const verified = await catalogChild(ctx, { + parentSessionId, childSessionId, mode: 'continuable', + }, signal); + if (verified.error !== undefined) + return err(request, verified.error); + try { + const messageId = await ctx.subagents.followup(parent, childSessionId, content, { + source: { + kind: 'user', + rpcId: request.rpcId, + ...(canonicalTimeZone === undefined ? {} : { clientTimeZone: canonicalTimeZone }), + }, + signal, + }); + return ok(request, { messageId }); + } + catch (error) { + return subagentPromptError(request, error, signal); + } + }, + // Deliberately no catalog, history, persistence, or parent Agent lookup: + // the core primitive alone authorizes the durable address against the + // live Activation, which is what keeps a live child interruptible while + // its parent Agent is offline. Absent targets are accepted no-ops there. + interrupt(request) { + const { parentSessionId, childSessionId } = request.payload; + try { + ctx.subagents.interrupt(childSessionId, { kind: 'user', parentSessionId }); + } + catch (error) { + if (error instanceof SubagentError && error.code === 'UNAUTHORIZED') { + return Promise.resolve(err(request, { + code: 'subagent-unauthorized', + message: 'subagent does not belong to this parent', + details: { childSessionId }, + })); + } + return Promise.resolve(err(request, { + code: 'internal', + message: 'subagent interrupt failed', + details: {}, + })); + } + return Promise.resolve(ok(request, { accepted: true })); + }, + }, + workspace: { + list(request) { + return Promise.resolve(ok(request, { + items: ctx.workspaceRegistry.list().map(workspaceView), + archivedSessionIds: [...ctx.workspaceRegistry.archivedSessionIds], + })); + }, + async create(request) { + const { path } = request.payload; + try { + const { workspace, created } = await ensureWorkspace(path); + return ok(request, { workspace: workspaceView(workspace), created }); + } + catch (error) { + // The registry rejects a path that does not resolve to an existing + // directory (realpath ENOENT / not-a-directory) — the business + // error of the typed-path flow, surfaced as a validation failure. + return err(request, { + code: 'workspace-invalid-path', + message: `cannot create a workspace at "${path}": ${error instanceof Error ? error.message : String(error)}`, + details: { path }, + }); + } + }, + async rename(request) { + const { payload } = request; + const workspace = ctx.workspaceRegistry.get(brandWorkspaceId(payload.workspaceId)); + if (workspace === undefined) + return workspaceNotFound(request, payload.workspaceId); + const title = payload.title.trim(); + // Uniqueness AND the same-title no-op both ride the create chain so + // they observe the state left by earlier queued renames — checked + // up front, a queued A→A could report success while an earlier A→B + // still lands afterwards. + const operation = workspaceCreationChain.then(async () => { + if (title === workspace.title) + return; + if (ctx.workspaceRegistry.list().some(other => other.id !== workspace.id && other.title === title)) { + throw new WorkspaceNameConflictError(title); + } + await workspace.setTitle(title); + }); + workspaceCreationChain = operation.then(() => undefined, () => undefined); + try { + await operation; + } + catch (error) { + if (error instanceof WorkspaceNameConflictError) { + return err(request, { + code: 'workspace-name-conflict', + message: error.message, + details: { name: error.workspaceName }, + }); + } + throw error; + } + return ok(request, { workspace: workspaceView(workspace) }); + }, + async delete(request) { + const { workspaceId } = request.payload; + const operation = workspaceCreationChain.then(() => ctx.workspaceRegistry.delete(brandWorkspaceId(workspaceId))); + workspaceCreationChain = operation.then(() => undefined, () => undefined); + if (!await operation) + return workspaceNotFound(request, workspaceId); + return ok(request, { deleted: true }); + }, + async insertBefore(request) { + const { workspaceId, beforeWorkspaceId } = request.payload; + try { + const workspaceIds = await ctx.workspaceRegistry.insertBefore(brandWorkspaceId(workspaceId), beforeWorkspaceId === undefined ? undefined : brandWorkspaceId(beforeWorkspaceId)); + return ok(request, { workspaceIds: [...workspaceIds] }); + } + catch (error) { + if (!(error instanceof WorkspaceOrderInvalidError)) + throw error; + return workspaceNotFound(request, error.workspaceId); + } + }, + async insertSessionBefore(request) { + const { payload } = request; + const workspace = ctx.workspaceRegistry.get(brandWorkspaceId(payload.workspaceId)); + if (workspace === undefined) + return workspaceNotFound(request, payload.workspaceId); + try { + await workspace.insertSessionBefore(payload.sessionId, payload.beforeSessionId); + } + catch (error) { + // Only the entity's unaccounted-id rejection is the business code; + // storage/durability failures propagate as internal errors. + if (!(error instanceof WorkspaceMoveInvalidError)) + throw error; + return err(request, { + code: 'workspace-move-invalid', + message: error.message, + details: { + workspaceId: payload.workspaceId, + sessionId: payload.sessionId, + ...payload.beforeSessionId === undefined ? {} : { beforeSessionId: payload.beforeSessionId }, + }, + }); + } + return ok(request, { workspace: workspaceView(workspace) }); + }, + async archiveSession(request) { + const { sessionId } = request.payload; + try { + await ctx.workspaceRegistry.archiveSession(sessionId); + } + catch (error) { + // Only the registry's unknown-session rejection is the business + // code; storage/durability failures propagate as internal errors. + if (!(error instanceof WorkspaceUnknownSessionError)) + throw error; + return err(request, { + code: 'session-not-found', + message: error.message, + details: { sessionId }, + }); + } + return ok(request, { archivedSessionIds: [...ctx.workspaceRegistry.archivedSessionIds] }); + }, + }, + host: { + describe(request) { + // TODO: version should read apps/cli's package.json; placeholder for now. + const selection = defaults.defaultModelSelection(); + return Promise.resolve(ok(request, { + version: '0.0.1', + // Same source as session.create's fallback: the UI's default project + // must match where an unspecified-cwd session actually lands. + cwd: defaults.cwd, + // Read live for the same reason: this is what the NEXT session will + // start from, so a saved default has to be what it reports. + provider: selection.provider, + model: selection.model, + attachedSessions: ctx.agents.list().length, + canOpenPath: canOpenPaths(), + })); + }, + async pickDirectory(request, signal) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== 'native') { + return err(request, { + code: 'directory-picker-unavailable', + message: `host.pickDirectory needs the native capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind }, + }); + } + try { + const path = await capability.pick(signal); + return ok(request, { path }); + } + catch (error) { + if (signal.aborted) { + return err(request, { + code: 'cancelled', + message: 'directory picker was aborted', + details: {}, + }); + } + return err(request, { + code: 'internal', + message: `directory picker failed: ${error instanceof Error ? error.message : String(error)}`, + details: {}, + }); + } + }, + async listDirectory(request, signal) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== 'browse') { + return err(request, { + code: 'directory-picker-unavailable', + message: `host.listDirectory needs the browse capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind }, + }); + } + try { + // The carrier's signal follows the caller: a disconnect or timeout + // stops the backend's directory scan instead of outliving it. + return ok(request, await capability.list(request.payload.path, signal)); + } + catch (error) { + // An abort is the caller's own timeout/disconnect, not a server + // failure — same code pickDirectory and command.execute report. + if (signal.aborted) { + return err(request, { code: 'cancelled', message: 'directory listing was aborted', details: {} }); + } + return err(request, directoryError(error)); + } + }, + async createDirectory(request) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== 'browse') { + return err(request, { + code: 'directory-picker-unavailable', + message: `host.createDirectory needs the browse capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind }, + }); + } + try { + return ok(request, { path: await capability.createDirectory(request.payload.path, request.payload.name) }); + } + catch (error) { + return err(request, directoryError(error)); + } + }, + async openPath(request, signal) { + return openPath(request, request.payload.path, signal); + }, + }, + goals: { + // Mutations only — the read side is the 'goal' session projection. + // Every verb resolves the session's agent (agentFor: implicit cold + // resume, the command.* precedent) and acknowledges with the new CAS + // ref; the committed goal/change event carries the whole value to every + // client through the projection frames. + async create(request) { + const { objective, maxGoalRounds } = request.payload; + return mutateGoal(request, (goals, agent) => goals.create(agent, { + objective, + ...(maxGoalRounds !== undefined ? { maxGoalRounds } : {}), + })); + }, + async edit(request) { + const { ref, objective, maxGoalRounds } = request.payload; + return mutateGoal(request, (goals, agent) => goals.edit(agent, ref, { + ...(objective !== undefined ? { objective } : {}), + ...(maxGoalRounds !== undefined ? { maxGoalRounds } : {}), + })); + }, + async pause(request) { + return mutateGoal(request, (goals, agent) => goals.pause(agent, request.payload.ref)); + }, + async resume(request) { + return mutateGoal(request, (goals, agent) => goals.resume(agent, request.payload.ref)); + }, + async complete(request) { + return mutateGoal(request, (goals, agent) => goals.complete(agent, request.payload.ref)); + }, + async clear(request) { + const found = await agentFor(request.payload.sessionId); + if ('error' in found) + return err(request, found.error); + const goals = goalServiceFor(found.agent); + if ('error' in goals) + return err(request, goals.error); + try { + goals.clear(found.agent, request.payload.ref); + return ok(request, { cleared: true }); + } + catch (error) { + return goalError(request, error); + } + }, + }, + agentPresets: { + // A deployment with no roster answers with an empty list rather than an + // error: composing no presets is a valid deployment, and the browser + // simply offers no choice. + async list(request) { + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return ok(request, { presets: [], authorable: false, hasDocument: false }); + const defaultId = presets.defaultId; + return ok(request, { + presets: (await presets.list()).map(preset => ({ + id: preset.id, + trust: preset.trust, + isDefault: preset.id === defaultId, + ...preset.name === undefined ? {} : { name: preset.name }, + ...preset.description === undefined ? {} : { description: preset.description }, + ...preset.broken === undefined ? {} : { broken: preset.broken }, + })), + authorable: presets.authorable, + hasDocument: canOpenPaths(), + }); + }, + // Recomposing is limited to a blank session because a started + // conversation's history was produced under its preset's tools; the + // agent and the session survive, only the composition is swapped. + async select(request) { + const { sessionId, agentPreset } = request.payload; + const presets = ctx.get('agentPresets'); + if (presets === undefined) { + return err(request, { + code: 'agent-preset-not-found', + message: 'this deployment composes no agent presets', + details: { agentPreset, available: [] }, + }); + } + const found = await agentFor(sessionId); + if ('error' in found) + return err(request, found.error); + const { agent } = found; + const swap = async () => { + // Re-read inside the queue: an earlier switch may have run, and a + // conversation may have started, since this request arrived. + if (!sessionBlank(agent.session)) { + return err(request, { + code: 'agent-preset-locked', + message: `session "${sessionId}" has already started; its agent preset is fixed`, + details: { sessionId, agentPreset }, + }); + } + try { + const preset = await presets.recompose(agent.ctx, agentPreset); + // Recorded only after the swap committed: the log states what the + // agent runs, and a rejected mount leaves the previous composition. + agent.session.append('agent-preset/selected', { agentPreset: preset.id }); + return ok(request, { agentPreset: preset.id }); + } + catch (error) { + const refused = presetFailure(request, error); + if (refused !== undefined) + return refused; + return err(request, { + code: 'internal', + message: `failed to select agent preset "${agentPreset}": ${String(error)}`, + details: {}, + }); + } + }; + const queued = presetSwitches.get(sessionId) ?? Promise.resolve(); + const turn = queued.then(swap); + presetSwitches.set(sessionId, turn.catch(() => undefined)); + try { + return await turn; + } + finally { + if (presetSwitches.get(sessionId) === turn) + presetSwitches.delete(sessionId); + } + }, + // Authoring is privileged (see PRIVILEGED_METHODS in dsh-client-connection): + // a composition names the plugins a session runs, so reading one is + // reconnaissance, and copy/remove/openDocument manage the roster and + // drive the host desktop. + async read(request) { + const { agentPreset } = request.payload; + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return err(request, noRoster(agentPreset)); + try { + const preset = await presets.resolve(agentPreset); + return ok(request, { + agentPreset: preset.id, + trust: preset.trust, + content: await presets.read(preset.id), + ...preset.name === undefined ? {} : { name: preset.name }, + ...preset.description === undefined ? {} : { description: preset.description }, + }); + } + catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async copy(request) { + const { from, agentPreset, name } = request.payload; + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return err(request, noRoster(agentPreset)); + try { + await presets.copy(from, agentPreset, name); + return ok(request, { agentPreset }); + } + catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async openDocument(request, signal) { + const { agentPreset } = request.payload; + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return err(request, noRoster(agentPreset)); + try { + const preset = await presets.resolve(agentPreset); + // Same line as copy/remove draw: the shipped install is not the + // user's to manage, and pointing an editor into it invites edits an + // upgrade will silently overwrite. + if (preset.trust !== 'user') { + throw new PresetNotWritableError(preset.id, 'it ships with the deployment'); + } + // The id resolved against the Host's own roots is what selects the + // directory — no browser payload carries a path in either direction + // unless the deployment has no opener to hand it to. + const directory = dirname(preset.path); + if (!canOpenPaths()) + return ok(request, { opened: false, path: directory }); + return await openPath(request, directory, signal); + } + catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async remove(request) { + const { agentPreset } = request.payload; + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return err(request, noRoster(agentPreset)); + try { + await presets.remove(agentPreset); + return ok(request, {}); + } + catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + }, + skills: { + // Skill lookup never creates or resumes an agent: the session address + // resolves to a canonical cwd from the host-resident session header, and + // the view scope is the live agent or the preset's standing key. + async list(request) { + const { sessionId } = request.payload; + const session = ctx.sessions.get(sessionId); + if (session === undefined) { + return err(request, { + code: 'session-not-found', + message: `session "${sessionId}" not found (not attached)`, + details: { sessionId }, + }); + } + if (session.header.cwd === undefined) { + // Every served session records its project at create time; a + // cwd-less header is a pre-project legacy log (not served). + return err(request, { code: 'internal', message: `session "${sessionId}" has no project cwd`, details: {} }); + } + const cwd = session.header.cwd; + // The host registry is layered per scope and serves every session. A + // composition may still realm-mount its own registry instead; that + // instance is invisible to host contexts, so address it through the + // live agent (`agents.get` keeps the no-side-effect stance above). + const live = ctx.agents.get(sessionId); + const presets = ctx.get('agentPresets'); + const scoped = live === undefined ? undefined : presets?.serviceFor(live, 'skills'); + // Same stance as the commands domain: a missing service means no + // composition mounts dsh-skill, not an empty catalog. `ctx.get` also + // keeps this handler independent of the gateway plugin's inject list + // (an undeclared `ctx.skills` property read fails the reflect proxy). + const skillRegistry = scoped ?? ctx.get('skills'); + if (skillRegistry === undefined) { + return err(request, { code: 'internal', message: 'skill registry is absent: neither this session\'s agent preset nor the host composition mounts @deepseek-ai/dsh-skill', details: {} }); + } + // The scope presenters resolve in — the live agent, else the recorded + // preset's standing key, else the global layer — so a cold session's + // '/' popup lists the catalog its composition actually serves. + const scope = await presenterScopeFor(sessionId, session); + try { + const skills = (await skillRegistry.list({ cwd, scope })).filter(isUserInvocable); + return ok(request, { + skills: skills.map(skill => ({ + name: skill.name, + description: skill.description, + ...skill.whenToUse === undefined ? {} : { whenToUse: skill.whenToUse }, + modelInvocable: skill.invocation.modelInvocable, + })), + }); + } + catch (error) { + return err(request, { code: 'internal', message: `skill listing failed: ${String(error)}`, details: {} }); + } + }, + }, + settings: { + describe(request) { + const settings = ctx.get('settings'); + if (settings === undefined) + return Promise.resolve(err(request, settingsAbsent())); + const exposed = exposedNamespaces(); + return Promise.resolve(ok(request, { + writable: settings.writable, + hasDocument: settings.documentPath !== undefined, + namespaces: settings.describe({ redactSecrets: true }) + .filter(descriptor => exposed.has(String(descriptor.ns))) + .map(namespaceView), + })); + }, + async openDocument(request, signal) { + const settings = ctx.get('settings'); + if (settings === undefined) + return err(request, settingsAbsent()); + if (isAborted(signal)) { + return err(request, { + code: 'cancelled', + message: 'settings document open was aborted', + details: {}, + }); + } + let path; + try { + path = await settings.prepareDocument(); + } + catch (error) { + if (isAborted(signal)) { + return err(request, { + code: 'cancelled', + message: 'settings document preparation was aborted', + details: {}, + }); + } + return err(request, { + code: 'internal', + message: `settings document preparation failed: ${error instanceof Error ? error.message : String(error)}`, + details: {}, + }); + } + if (path === undefined) { + return err(request, { + code: 'internal', + message: 'settings provider has no local document to open', + details: {}, + }); + } + if (isAborted(signal)) { + return err(request, { + code: 'cancelled', + message: 'settings document open was aborted', + details: {}, + }); + } + return openTextFile(request, path, signal); + }, + update: request => settingsWrite(request, request.payload.ns, 'update', request.payload.patch, request.payload.expectedRevision), + replace: request => settingsWrite(request, request.payload.ns, 'replace', request.payload.section, request.payload.expectedRevision), + mutate: request => settingsWrite(request, request.payload.ns, 'mutate', request.payload.ops, request.payload.expectedRevision), + }, + credentials: { + async describe(request) { + const credentials = ctx.get('credentials'); + if (credentials === undefined) + return err(request, credentialsAbsent()); + const entries = await Promise.all(request.payload.refs.map(async (ref) => { + const info = await credentials.describe(credentialRef(ref)); + const view = { + configured: info.configured, + ...info.source === undefined ? {} : { source: info.source }, + writable: info.writable, + }; + return [ref, view]; + })); + return ok(request, { credentials: Object.fromEntries(entries) }); + }, + async set(request) { + const credentials = ctx.get('credentials'); + if (credentials === undefined) + return err(request, credentialsAbsent()); + const { ref, value } = request.payload; + try { + await credentials.set(credentialRef(ref), value); + } + catch (error) { + return err(request, { + code: 'credential-rejected', + message: error instanceof Error ? error.message : String(error), + details: { ref }, + }); + } + return ok(request, {}); + }, + async unset(request) { + const credentials = ctx.get('credentials'); + if (credentials === undefined) + return err(request, credentialsAbsent()); + const { ref } = request.payload; + try { + await credentials.unset(credentialRef(ref)); + } + catch (error) { + return err(request, { + code: 'credential-rejected', + message: error instanceof Error ? error.message : String(error), + details: { ref }, + }); + } + return ok(request, {}); + }, + }, + llm: { + providers(request) { + const registered = ctx.llm.listProviders(); + const active = new Set(registered.map(provider => provider.id)); + const directory = ctx.llm.listConfigurableProviders(); + const declared = new Set(directory.map(entry => entry.provider)); + const views = directory.map(entry => ({ + provider: entry.provider, + displayName: entry.displayName, + settingsNs: entry.settingsNs, + settingsPath: [...entry.settingsPath], + active: active.has(entry.provider), + ...entry.declared === undefined ? {} : { declared: entry.declared }, + })); + // Routes registered without a directory declaration still appear — + // they exist and serve models — just with no settings address. No + // adapter claimed them, so nothing can say whether they are shipped. + for (const provider of registered) { + if (declared.has(provider.id)) + continue; + views.push({ + provider: provider.id, + displayName: provider.name, + settingsNs: '', + settingsPath: [], + active: true, + }); + } + return Promise.resolve(ok(request, { providers: views })); + }, + async models(request) { + return ok(request, await buildModelCatalog(ctx)); + }, + async discoverModels(request, signal) { + const { settingsNs, provider, baseURL, api, apiKey } = request.payload; + try { + const models = await ctx.llm.discoverModels(settingsNs, { + ...provider === undefined ? {} : { provider }, + ...baseURL === undefined ? {} : { baseURL }, + ...api === undefined ? {} : { api }, + ...apiKey === undefined ? {} : { apiKey }, + ...signal === undefined ? {} : { signal }, + }); + return ok(request, { models }); + } + catch (error) { + // Every failure here is the user's next move, not a transport fault: + // a wrong endpoint, a rejected key, or a protocol with no listing all + // end at the same place — fill the models in by hand. The details + // repeat only what the caller already sent, never the credential. + return err(request, { + code: 'model-discovery-failed', + message: error instanceof Error ? error.message : String(error), + details: { settingsNs, ...baseURL === undefined ? {} : { baseURL } }, + }); + } + }, + }, + events: { + mux(_request, signal) { + const queue = new FrameQueue(); + muxQueues.add(queue); + for (const session of ctx.sessions.list()) { + subscribeSession(queue, session); + } + for (const pending of pendingQuestions.values()) { + queue.push({ + rpcId: pending.rpcId, + payload: { + type: 'question/requested', sessionId: pending.sessionId, + questions: pending.questions, + }, + }); + } + // Refresh recovery: still-pending approval questions replay with their + // stable rpcId so a reconnecting client can still answer them. + for (const pending of pendingApprovals.values()) + queue.push(requestedFrame(pending)); + // Queue snapshot baseline (pendingQuestions precedent): frames replayed + // in arrival order per session; a reconnecting client rebuilds its + // queue view from these alone. + for (const session of ctx.sessions.list()) { + const agent = ctx.agents.get(session.id); + if (agent?.session === session && agent.inbox.hasPending) { + queue.push(frame({ type: 'session/queue', sessionId: session.id, items: queueItems(agent) })); + } + } + // Background-task baseline. `ctx.agents.get` is the non-resuming read: + // a session with no live Agent owns no tasks, so it correctly sees only + // the unowned ones, and listing never revives a cold session. An empty + // set sends nothing — absence is how the client reads "no tasks". + const jobs = ctx.get('jobs'); + if (jobs !== undefined) { + for (const session of ctx.sessions.list()) { + const views = jobViews(jobs.list(ctx.agents.get(session.id))); + if (views.length > 0) { + queue.push(frame({ type: 'session/jobs', sessionId: session.id, jobs: views })); + } + } + } + // Per-session open-call table for result-view pairing. Bounded by the + // per-turn call count: entries clear on turn/end; a table miss (stream + // opened mid-turn) backscans the session's in-memory events instead. + const openCalls = new Map(); + const disposers = [ + ctx.on('session/event', (session, event) => { + if (event.type === 'tool/call') { + const data = event.data; + try { + let table = openCalls.get(session.id); + if (table === undefined) + openCalls.set(session.id, table = new Map()); + table.set(data.callId, { name: data.name, args: JSON.parse(data.arguments) }); + } + catch { + // Unparseable model arguments: leave the table unset; the result view soft-falls. + } + } + else if (event.type === 'turn/end') { + openCalls.delete(session.id); + } + const view = viewFor(ctx, event, callId => openCalls.get(session.id)?.get(callId) ?? backscanArgs(session.events, callId), ctx.agents.get(session.id)); + queue.push(frame({ type: 'session/event', sessionId: session.id, event, ...view === undefined ? {} : { view } })); + }), + ctx.on('session/created', (session) => { + subscribeSession(queue, session); + // The subscribe frame clears the client's task mirror, and a + // session born after the stream opened missed the baseline loop. + // Unowned tasks are visible to it from birth, so without this it + // would show none until the next registry change. + const views = jobs === undefined ? [] : jobViews(jobs.list(ctx.agents.get(session.id))); + if (views.length > 0) { + queue.push(frame({ type: 'session/jobs', sessionId: session.id, jobs: views })); + } + }), + ctx.on('session/disposed', (session) => { + openCalls.delete(session.id); + }), + ...jobs === undefined ? [] : [jobs.onJobsChanged((owner) => { + if (owner !== undefined) { + // The exact owner instance the fence compares against, so the + // push stays correct even while that Agent's scope is tearing + // down and a lookup by id would already miss. + queue.push(frame({ type: 'session/jobs', sessionId: owner.id, jobs: jobViews(jobs.list(owner)) })); + return; + } + // An unowned task is visible to every caller, so every subscribed + // session's set changed with it. + for (const session of ctx.sessions.list()) { + queue.push(frame({ + type: 'session/jobs', + sessionId: session.id, + jobs: jobViews(jobs.list(ctx.agents.get(session.id))), + })); + } + })], + ]; + return queue.iterate(signal, () => { + muxQueues.delete(queue); + for (const dispose of disposers) + dispose(); + }); + }, + host(_request, signal) { + const queue = new FrameQueue(); + const committedWorkspaces = ctx.workspaceRegistry.list(); + const committedWorkspaceIds = new Set(committedWorkspaces.map(workspace => String(workspace.id))); + let committedWorkspaceOrder = committedWorkspaces.map(workspace => workspace.id); + // Frame-dedup baseline, same posture as committedWorkspaceIds: the + // stream opens against the current set; workspace.list re-baselines + // reconnecting clients, so only later changes need frames. + let archivedSessionIds = ctx.workspaceRegistry.archivedSessionIds; + const disposers = [ + ctx.on('session/created', (session) => { + queue.push(frame({ + type: 'host/session-added', + sessionId: session.id, + // Derived at frame time like summarize(); a just-created session + // has run no turn yet, so this is constantly true in practice. + blank: sessionBlank(session), + // Including cwd lets the client group the new session without refreshing the list. + ...sessionListFields(session.header, session.events), + })); + }), + ctx.on('session/disposed', (session) => { + queue.push(frame({ type: 'host/session-removed', sessionId: session.id })); + }), + ctx.on('agent/status', ({ agent, status }) => { + queue.push(frame({ type: 'host/session-status', sessionId: agent.id, running: status === 'running' })); + }), + ctx.on('agent/error', ({ agent, error }) => { + queue.push(frame({ type: 'host/agent-error', sessionId: agent.id, message: errorChain(error) })); + }), + ctx.on('domain/changed', (change) => { + if (change.domain !== 'workspace') + return; + if (change.table === '') { + if (change.operation !== 'put') + return; + const state = workspaceDomainState.parse(change.value); + const orderChanged = state.workspaceIds.length === committedWorkspaceOrder.length + && state.workspaceIds.every(workspaceId => committedWorkspaceIds.has(String(workspaceId))) + && state.workspaceIds.some((workspaceId, index) => workspaceId !== committedWorkspaceOrder[index]); + for (const workspaceId of state.workspaceIds) { + if (committedWorkspaceIds.has(workspaceId)) + continue; + const workspace = ctx.workspaceRegistry.get(workspaceId); + if (workspace === undefined) { + throw new Error(`committed workspace registry references missing workspace "${workspaceId}"`); + } + committedWorkspaceIds.add(workspaceId); + queue.push(frame({ type: 'host/workspace-changed', workspace: workspaceView(workspace) })); + } + committedWorkspaceOrder = [...state.workspaceIds]; + if (orderChanged) { + queue.push(frame({ + type: 'host/workspace-order-changed', + workspaceIds: [...state.workspaceIds], + })); + } + if (state.archivedSessionIds.length !== archivedSessionIds.length + || state.archivedSessionIds.some((id, index) => id !== archivedSessionIds[index])) { + archivedSessionIds = state.archivedSessionIds; + queue.push(frame({ + type: 'host/archived-sessions-changed', + archivedSessionIds: [...state.archivedSessionIds], + })); + } + return; + } + if (change.table !== 'workspaces') + return; + if (change.operation === 'deleted') { + if (!committedWorkspaceIds.delete(change.key)) + return; + queue.push(frame({ + type: 'host/workspace-removed', + workspaceId: change.key, + })); + return; + } + if (!committedWorkspaceIds.has(change.key)) + return; + // Existing-entity table writes are complete attach/touch commits. + // A new entity's first put waits for the global registry write above. + queue.push(frame({ + type: 'host/workspace-changed', + workspace: changedWorkspaceView(change.key, change.value), + })); + }), + // Allowlisted host events ride one verbatim wrapper frame each. The + // allowlist is api-remotes', and `ctx.remote.$on` is the consumer + // face; nothing here projects, redacts, or renames. + ...API_REMOTE_FORWARDED_EVENTS.map(name => ctx.on(name, + // The allowlist's shape assertion proves each name is a real, + // non-scoped, void-returning event, so the rest-parameter handler + // satisfies every member of the union `on` accepts here; + // assertJsonArgs proves the payload is JSON-safe before it queues. + ((...args) => { + queue.push(frame({ + type: 'host/remote-event', + event: name, + args: assertJsonArgs(name, args), + })); + }))), + ]; + return queue.iterate(signal, () => { for (const dispose of disposers) + dispose(); }); + }, + }, + downloads: { + async sessionLog(request, signal) { + // Clean error path first: missing services answer 500 and a missing + // root artifact 404 before any zip byte is produced. The root content + // read here is reused as the first zip entry, so nothing is read twice. + const deps = sessionLogExportDeps(ctx); + if (deps.sessionQuery === undefined || deps.sessionPersistence === undefined || deps.attachments === undefined) { + return new Response('session log export is unavailable: missing session-query, session-persistence, or attachments service', { status: 500 }); + } + if (!deps.sessionPersistence.supportsRawArtifacts) { + return new Response('session log export is unavailable: the persistence backend does not expose per-session raw artifacts', { status: 501 }); + } + const ready = { + sessionQuery: deps.sessionQuery, + sessionPersistence: deps.sessionPersistence, + attachments: deps.attachments, + sessions: deps.sessions, + }; + let root; + try { + await flushLiveSessionLog(deps, request.sessionId, signal); + root = await deps.sessionPersistence.readRaw(request.sessionId, signal); + signal.throwIfAborted(); + } + catch { + signal.throwIfAborted(); + // Root preparation failure: answer 500 without echoing the error, + // which may carry absolute host paths into the browser error bar. + return new Response('session log export failed to prepare the stored artifact', { status: 500 }); + } + if (root === undefined) { + return new Response('session not found', { status: 404 }); + } + return new Response(streamSessionLogZip(ready, root, request.sessionId, request.includeDescendants === true, sessionExportCompressionLevel, signal), { + headers: { + 'content-type': 'application/zip', + 'content-disposition': `attachment; filename="${sessionLogZipFilename(request.sessionId)}"`, + }, + }); + }, + }, + respond(message) { + // Route by the echoed rpcId (the wire correlation): approvals first, + // then questions — the two registries share one id space of UUIDs. + const approval = pendingApprovals.get(message.rpcId); + if (approval !== undefined) { + if (!message.result.ok) + return Promise.resolve({ accepted: false, reason: 'bad-response' }); + const parsed = approvalResponsePayloadSchema.safeParse(message.result.value); + // The payload's audit correlation must match the entry the rpcId routed + // to — a mismatched answer is malformed, not merely late. + if (!parsed.success || parsed.data.approvalId !== approval.approvalId || parsed.data.sessionId !== approval.sessionId) { + return Promise.resolve({ accepted: false, reason: 'bad-response' }); + } + approval.resolve(parsed.data.outcome); + return Promise.resolve({ accepted: true }); + } + const pending = pendingQuestions.get(message.rpcId); + if (pending === undefined) + return Promise.resolve({ accepted: false, reason: 'not-pending' }); + if (!message.result.ok) { + if (message.result.error.code !== 'cancelled') { + return Promise.resolve({ accepted: false, reason: 'bad-response' }); + } + claimQuestion(pending, 'cancelled'); + pending.reject(new UserQuestionError('the user cancelled ask_user_question', 'ASK_CANCELLED')); + return Promise.resolve({ accepted: true }); + } + const parsed = questionResponsePayloadSchema.safeParse(message.result.value); + if (!parsed.success) { + return Promise.resolve({ accepted: false, reason: 'bad-response' }); + } + const payload = { + sessionId: parsed.data.sessionId, + answer: { + answers: parsed.data.answer.answers.map(answer => ({ + id: answer.id, + selected: answer.selected, + ...(answer.custom === undefined ? {} : { custom: answer.custom }), + })), + }, + }; + if (!matchesQuestions(payload, pending)) { + return Promise.resolve({ accepted: false, reason: 'bad-response' }); + } + claimQuestion(pending, 'answered'); + pending.resolve(payload.answer); + return Promise.resolve({ accepted: true }); + }, + }; +} +//# sourceMappingURL=api-proxy.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.d.ts new file mode 100644 index 0000000..0f55636 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.d.ts @@ -0,0 +1,130 @@ +/** + * agent-presets domain contract: the roster a browser offers when starting a + * session, plus the authoring calls behind it. + * + * `list` is ordinary: it carries ids and trust, and every preset picker needs + * it. The authoring calls are privileged and loopback-pinned — a composition + * names the plugins a session runs, so reading one is reconnaissance, and + * although authoring is copy-only (no caller supplies composition text or a + * path), copying and deleting still rearrange what the deployment offers. + */ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** One preset the deployment can compose a session's agent from. */ +export interface AgentPresetEntry { + /** Stable identifier, also the display name until presets carry metadata. */ + readonly id: string; + /** + * Whether the preset ships with the deployment or was authored locally. + * A `user` preset is exactly as privileged as the plugins it names, so a + * surface offering one should say so rather than present it as vetted. + */ + readonly trust: 'system' | 'user'; + /** Whether a session that names no preset gets this one. */ + readonly isDefault: boolean; + /** + * Display name the preset published, absent when it published none. A + * surface falls back to {@link id}; it is never a second identity, and it + * never decides trust — a locally authored preset cannot name itself into + * the shipped set. + */ + readonly name?: string; + /** One sentence on what the preset is for, when it published one. */ + readonly description?: string; + /** + * Why this preset cannot compose a session, absent when it can. A broken + * preset stays listed — its directory still occupies the id, so a surface + * must be able to show and delete it — but offering it for selection would + * only defer this reason to a failed session start. + */ + readonly broken?: string; +} +/** agent-preset-domain unary methods (the map key agentPreset.* of RpcMethodMap). */ +export interface AgentPresetsApi { + /** + * Lists every preset the deployment currently supplies, in root-precedence + * order — the roots as configured, each root's own presets sorted by id, + * and the first root to supply an id wins. The order is not globally + * sorted: a user root's preset sits in that root's block, not among the + * shipped ids. + * An empty roster means the deployment composes no presets at all, and + * every session shares the host composition. `authorable` reports whether + * the deployment configures a root new presets can be written to, and + * `hasDocument` whether `openDocument` can hand a preset directory to a + * native opener — both deployment facts rather than per-preset ones, and + * neither exposes a Host path. + */ + list(request: RpcRequest<{}>): Promise>; + /** + * Recompose one session's agent from a different preset. + * + * Allowed only while the session is blank — no turn has run. Once a + * conversation starts, its history was produced under that preset's tools, + * and swapping them would leave logged tool calls the new composition cannot + * make; the attempt answers `agent-preset-locked`. + */ + select(request: RpcRequest<{ + sessionId: SessionId; + agentPreset: string; + }>): Promise>; + /** + * Read one preset's composition text, for the read-only viewer. + * + * Privileged: a composition names the plugins a session runs, so reading + * one is reconnaissance. + */ + read(request: RpcRequest<{ + agentPreset: string; + }>): Promise>; + /** + * Create a locally authored preset by copying an existing one whole. + * + * The only authoring write. No composition text and no path crosses the + * wire: `from` and `agentPreset` are ids the Host resolves against its own + * roots, so a copy is exactly as loadable as its source and grants nothing + * the roster did not already carry. The copy keeps the source's description + * (the file is the author's to edit afterwards) but not its name — `name` + * here or the id fallback is what distinguishes the rows. + */ + copy(request: RpcRequest<{ + from: string; + agentPreset: string; + name?: string; + }>): Promise>; + /** + * Hand one locally authored preset's DIRECTORY to the platform opener, for + * editing the files that are now the only composition editor. The request + * carries an id, never a path — the Host resolves it — so no browser + * payload can select an arbitrary filesystem target. Where the deployment + * has no native opener (`hasDocument: false` on `list`), the reply carries + * the resolved directory for the surface to show as text instead. Shipped + * presets are refused: their install is not the user's to manage. + */ + openDocument(request: RpcRequest<{ + agentPreset: string; + }>, signal: AbortSignal): Promise>; + /** Delete a locally authored preset. Shipped presets are refused. */ + remove(request: RpcRequest<{ + agentPreset: string; + }>): Promise>; +} +//# sourceMappingURL=agent-presets.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.js new file mode 100644 index 0000000..67fc843 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.js @@ -0,0 +1,12 @@ +/** + * agent-presets domain contract: the roster a browser offers when starting a + * session, plus the authoring calls behind it. + * + * `list` is ordinary: it carries ids and trust, and every preset picker needs + * it. The authoring calls are privileged and loopback-pinned — a composition + * names the plugins a session runs, so reading one is reconnaissance, and + * although authoring is copy-only (no caller supplies composition text or a + * path), copying and deleting still rearrange what the deployment offers. + */ +export {}; +//# sourceMappingURL=agent-presets.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.d.ts new file mode 100644 index 0000000..0604ffb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.d.ts @@ -0,0 +1,78 @@ +/** + * agent-presets domain zod schemas (names derived from map keys: + * agentPresetListRequestSchema / agentPresetListValueSchema). + */ +import { z } from 'zod'; +/** AgentPresetEntry row of agentPreset.list. */ +export declare const agentPresetEntrySchema: z.ZodObject<{ + id: z.ZodString; + trust: z.ZodUnion, z.ZodLiteral<"user">]>; + isDefault: z.ZodBoolean; + name: z.ZodOptional; + description: z.ZodOptional; + broken: z.ZodOptional; +}, z.core.$strip>; +/** agentPreset.list request payload. */ +export declare const agentPresetListRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** agentPreset.list response value. */ +export declare const agentPresetListValueSchema: z.ZodObject<{ + presets: z.ZodArray, z.ZodLiteral<"user">]>; + isDefault: z.ZodBoolean; + name: z.ZodOptional; + description: z.ZodOptional; + broken: z.ZodOptional; + }, z.core.$strip>>; + authorable: z.ZodBoolean; + hasDocument: z.ZodBoolean; +}, z.core.$strip>; +/** agentPreset.select request payload. */ +export declare const agentPresetSelectRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.select response value. */ +export declare const agentPresetSelectValueSchema: z.ZodObject<{ + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.read request payload. */ +export declare const agentPresetReadRequestSchema: z.ZodObject<{ + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.read response value. */ +export declare const agentPresetReadValueSchema: z.ZodObject<{ + agentPreset: z.ZodString; + trust: z.ZodUnion, z.ZodLiteral<"user">]>; + content: z.ZodString; + name: z.ZodOptional; + description: z.ZodOptional; +}, z.core.$strip>; +/** agentPreset.copy request payload. */ +export declare const agentPresetCopyRequestSchema: z.ZodObject<{ + from: z.ZodString; + agentPreset: z.ZodString; + name: z.ZodOptional; +}, z.core.$strip>; +/** agentPreset.copy response value. */ +export declare const agentPresetCopyValueSchema: z.ZodObject<{ + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.openDocument request payload. */ +export declare const agentPresetOpenDocumentRequestSchema: z.ZodObject<{ + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.openDocument response value. */ +export declare const agentPresetOpenDocumentValueSchema: z.ZodUnion; +}, z.core.$strip>, z.ZodObject<{ + opened: z.ZodLiteral; + path: z.ZodString; +}, z.core.$strip>]>; +/** agentPreset.remove request payload. */ +export declare const agentPresetRemoveRequestSchema: z.ZodObject<{ + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.remove response value. */ +export declare const agentPresetRemoveValueSchema: z.ZodObject<{}, z.core.$strip>; +//# sourceMappingURL=agent-presets.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.js new file mode 100644 index 0000000..94621f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.js @@ -0,0 +1,70 @@ +/** + * agent-presets domain zod schemas (names derived from map keys: + * agentPresetListRequestSchema / agentPresetListValueSchema). + */ +import { z } from 'zod'; +import { sessionIdSchema } from "./sessions.schema.js"; +/** AgentPresetEntry row of agentPreset.list. */ +export const agentPresetEntrySchema = z.object({ + id: z.string().min(1), + trust: z.union([z.literal('system'), z.literal('user')]), + isDefault: z.boolean(), + name: z.string().optional(), + description: z.string().optional(), + broken: z.string().min(1).optional(), +}); +/** agentPreset.list request payload. */ +export const agentPresetListRequestSchema = z.object({}); +/** agentPreset.list response value. */ +export const agentPresetListValueSchema = z.object({ + presets: z.array(agentPresetEntrySchema), + authorable: z.boolean(), + hasDocument: z.boolean(), +}); +/** agentPreset.select request payload. */ +export const agentPresetSelectRequestSchema = z.object({ + sessionId: sessionIdSchema, + agentPreset: z.string().min(1), +}); +/** agentPreset.select response value. */ +export const agentPresetSelectValueSchema = z.object({ + agentPreset: z.string(), +}); +/** agentPreset.read request payload. */ +export const agentPresetReadRequestSchema = z.object({ + agentPreset: z.string().min(1), +}); +/** agentPreset.read response value. */ +export const agentPresetReadValueSchema = z.object({ + agentPreset: z.string(), + trust: z.union([z.literal('system'), z.literal('user')]), + content: z.string(), + name: z.string().optional(), + description: z.string().optional(), +}); +/** agentPreset.copy request payload. */ +export const agentPresetCopyRequestSchema = z.object({ + from: z.string().min(1), + agentPreset: z.string().min(1), + name: z.string().optional(), +}); +/** agentPreset.copy response value. */ +export const agentPresetCopyValueSchema = z.object({ + agentPreset: z.string(), +}); +/** agentPreset.openDocument request payload. */ +export const agentPresetOpenDocumentRequestSchema = z.object({ + agentPreset: z.string().min(1), +}); +/** agentPreset.openDocument response value. */ +export const agentPresetOpenDocumentValueSchema = z.union([ + z.object({ opened: z.literal(true) }), + z.object({ opened: z.literal(false), path: z.string() }), +]); +/** agentPreset.remove request payload. */ +export const agentPresetRemoveRequestSchema = z.object({ + agentPreset: z.string().min(1), +}); +/** agentPreset.remove response value. */ +export const agentPresetRemoveValueSchema = z.object({}); +//# sourceMappingURL=agent-presets.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.d.ts new file mode 100644 index 0000000..056dfd2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.d.ts @@ -0,0 +1,20 @@ +/** + * approvals domain contract. The approval requested frame is a + * server-request (stable rpcId); the answer is a client-response echoing that rpcId (not a + * unary method, not in RpcMethodMap, mints no new id), carried on POST /api/respond with an + * RpcReceipt carrier receipt as the HTTP response body; the final outcome arrives in the resolved frame. + */ +import type { ApprovalRequestId } from '@deepseek-ai/dsh-user-approval/types'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +/** + * Approval answer payload (the result.value slot of a client-response). outcome accepts only + * the two values a client can give (cancelled/unavailable are host-side outcomes). approvalId + * is the core audit correlation (used by the impl to reconcile `approval/asked`/`decided`; + * passes through core's existing brand); wire correlation is governed by the echoed rpcId. + */ +export interface ApprovalResponsePayload { + sessionId: SessionId; + approvalId: ApprovalRequestId; + outcome: 'allowed-once' | 'rejected'; +} +//# sourceMappingURL=approvals.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.js new file mode 100644 index 0000000..40af5b4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.js @@ -0,0 +1,8 @@ +/** + * approvals domain contract. The approval requested frame is a + * server-request (stable rpcId); the answer is a client-response echoing that rpcId (not a + * unary method, not in RpcMethodMap, mints no new id), carried on POST /api/respond with an + * RpcReceipt carrier receipt as the HTTP response body; the final outcome arrives in the resolved frame. + */ +export {}; +//# sourceMappingURL=approvals.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.d.ts new file mode 100644 index 0000000..74f6fab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.d.ts @@ -0,0 +1,16 @@ +/** + * approvals domain zod schemas (respond is a client-response; the payload schema serves + * the /api/respond endpoint's second parse after routing via the pending table). + * ApprovalRequestId brand cast point: one. + */ +import { z } from 'zod'; +import type { ApprovalRequestId } from '@deepseek-ai/dsh-user-approval/types'; +/** ApprovalRequestId: one brand cast after schema validation (the only cast point in this domain). */ +export declare const approvalRequestIdSchema: z.ZodType; +/** Approval answer payload (the result.value slot of a client-response). */ +export declare const approvalResponsePayloadSchema: z.ZodObject<{ + sessionId: z.ZodType>; + approvalId: z.ZodType>; + outcome: z.ZodUnion, z.ZodLiteral<"rejected">]>; +}, z.core.$strip>; +//# sourceMappingURL=approvals.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js new file mode 100644 index 0000000..e7589a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js @@ -0,0 +1,16 @@ +/** + * approvals domain zod schemas (respond is a client-response; the payload schema serves + * the /api/respond endpoint's second parse after routing via the pending table). + * ApprovalRequestId brand cast point: one. + */ +import { z } from 'zod'; +import { sessionIdSchema } from "./sessions.schema.js"; +/** ApprovalRequestId: one brand cast after schema validation (the only cast point in this domain). */ +export const approvalRequestIdSchema = z.string().min(1); +/** Approval answer payload (the result.value slot of a client-response). */ +export const approvalResponsePayloadSchema = z.object({ + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + outcome: z.union([z.literal('allowed-once'), z.literal('rejected')]), +}); +//# sourceMappingURL=approvals.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.d.ts new file mode 100644 index 0000000..f3f200f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.d.ts @@ -0,0 +1,49 @@ +/** + * credentials domain contract: the web face of the credential-reference seam + * (`ctx.credentials`). Reads are structurally value-free — a credential view + * carries configured/source/writable and has no slot for the value — and the + * value crosses the wire in exactly one direction, inside `credentials.set`. + * There is no enumeration method by design: clients learn which references + * exist from settings schemas and values (`apiKeyEnv` fields). + */ +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** Wire view of one credential reference's state. */ +export interface CredentialView { + /** Whether any layer currently supplies a non-empty value. */ + configured: boolean; + /** Winning layer when configured (`env`, `file`, …); provider vocabulary. */ + source?: string; + /** Whether `credentials.set`/`credentials.unset` can affect this reference. */ + writable: boolean; +} +/** Credentials-domain unary methods (the map keys credentials.* of RpcMethodMap). */ +export interface CredentialsApi { + /** + * Describe the named references (batch): configured state, winning source, + * and writability — never values. An invalid reference name is a + * `bad-request`; an unknown-but-valid one describes as unconfigured. + */ + describe(request: RpcRequest<{ + refs: string[]; + }>): Promise; + }>>; + /** + * Store one credential value in the writable layer. Rejected with + * `credential-rejected` while a read-only layer (the live environment) + * shadows the reference — the write would otherwise appear to succeed while + * resolution keeps returning the shadowing value. + */ + set(request: RpcRequest<{ + ref: string; + value: string; + }>): Promise>; + /** + * Remove one credential from the writable layer; same shadowing rejection + * as `set`. Unsetting an absent reference succeeds (idempotent). + */ + unset(request: RpcRequest<{ + ref: string; + }>): Promise>; +} +//# sourceMappingURL=credentials.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.js new file mode 100644 index 0000000..7b5b346 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.js @@ -0,0 +1,10 @@ +/** + * credentials domain contract: the web face of the credential-reference seam + * (`ctx.credentials`). Reads are structurally value-free — a credential view + * carries configured/source/writable and has no slot for the value — and the + * value crosses the wire in exactly one direction, inside `credentials.set`. + * There is no enumeration method by design: clients learn which references + * exist from settings schemas and values (`apiKeyEnv` fields). + */ +export {}; +//# sourceMappingURL=credentials.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.d.ts new file mode 100644 index 0000000..af57295 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.d.ts @@ -0,0 +1,41 @@ +/** + * credentials domain zod schemas (names derived from map keys: + * credentialsDescribeRequestSchema / credentialsDescribeValueSchema / …). + * The reference-name pattern mirrors the seam's `credentialRef` guard so an + * invalid name fails as `bad-request` before reaching the service. + */ +import { z } from 'zod'; +/** POSIX-portable environment-variable name (the seam's `credentialRef` pattern). */ +export declare const credentialRefNameSchema: z.ZodString; +/** CredentialView entry of credentials.describe. */ +export declare const credentialViewSchema: z.ZodObject<{ + configured: z.ZodBoolean; + source: z.ZodOptional; + writable: z.ZodBoolean; +}, z.core.$strip>; +/** credentials.describe request payload. */ +export declare const credentialsDescribeRequestSchema: z.ZodObject<{ + refs: z.ZodArray; +}, z.core.$strip>; +/** credentials.describe response value. */ +export declare const credentialsDescribeValueSchema: z.ZodObject<{ + credentials: z.ZodRecord; + writable: z.ZodBoolean; + }, z.core.$strip>>; +}, z.core.$strip>; +/** credentials.set request payload: the one direction a value crosses this wire. */ +export declare const credentialsSetRequestSchema: z.ZodObject<{ + ref: z.ZodString; + value: z.ZodString; +}, z.core.$strip>; +/** credentials.set response value. */ +export declare const credentialsSetValueSchema: z.ZodObject<{}, z.core.$strip>; +/** credentials.unset request payload. */ +export declare const credentialsUnsetRequestSchema: z.ZodObject<{ + ref: z.ZodString; +}, z.core.$strip>; +/** credentials.unset response value. */ +export declare const credentialsUnsetValueSchema: z.ZodObject<{}, z.core.$strip>; +//# sourceMappingURL=credentials.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.js new file mode 100644 index 0000000..cbcbe0c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.js @@ -0,0 +1,37 @@ +/** + * credentials domain zod schemas (names derived from map keys: + * credentialsDescribeRequestSchema / credentialsDescribeValueSchema / …). + * The reference-name pattern mirrors the seam's `credentialRef` guard so an + * invalid name fails as `bad-request` before reaching the service. + */ +import { z } from 'zod'; +/** POSIX-portable environment-variable name (the seam's `credentialRef` pattern). */ +export const credentialRefNameSchema = z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/); +/** CredentialView entry of credentials.describe. */ +export const credentialViewSchema = z.object({ + configured: z.boolean(), + source: z.string().optional(), + writable: z.boolean(), +}); +/** credentials.describe request payload. */ +export const credentialsDescribeRequestSchema = z.object({ + refs: z.array(credentialRefNameSchema).max(64), +}); +/** credentials.describe response value. */ +export const credentialsDescribeValueSchema = z.object({ + credentials: z.record(z.string(), credentialViewSchema), +}); +/** credentials.set request payload: the one direction a value crosses this wire. */ +export const credentialsSetRequestSchema = z.object({ + ref: credentialRefNameSchema, + value: z.string().min(1), +}); +/** credentials.set response value. */ +export const credentialsSetValueSchema = z.object({}); +/** credentials.unset request payload. */ +export const credentialsUnsetRequestSchema = z.object({ + ref: credentialRefNameSchema, +}); +/** credentials.unset response value. */ +export const credentialsUnsetValueSchema = z.object({}); +//# sourceMappingURL=credentials.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.d.ts new file mode 100644 index 0000000..bd0cd08 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.d.ts @@ -0,0 +1,24 @@ +/** + * downloads domain contract: host-only download surfaces — the GET-download + * channel family, the mirror of the SSE-stream `events` domain. No wire + * envelope: the carrier's GET routes answer these directly, and the browser + * `IApiClient` never exposes them. + */ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +/** Host-only download surfaces (no wire envelope; absent from IApiClient). */ +export interface DownloadsApi { + /** + * Stream one session-log ZIP — the root artifact verbatim plus each subagent + * descendant's — as an attachment response. The carrier's GET route answers + * this directly; the browser never calls it. + * @param request - the root session id and whether to include descendants. + * @param signal - cancellation for the underlying reads. + * @returns the ZIP attachment response; missing services answer 500 and a + * missing root session 404 before any byte is produced. + */ + sessionLog(request: { + sessionId: SessionId; + includeDescendants?: boolean; + }, signal: AbortSignal): Promise; +} +//# sourceMappingURL=downloads.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.js new file mode 100644 index 0000000..b9bd0f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.js @@ -0,0 +1,8 @@ +/** + * downloads domain contract: host-only download surfaces — the GET-download + * channel family, the mirror of the SSE-stream `events` domain. No wire + * envelope: the carrier's GET routes answer these directly, and the browser + * `IApiClient` never exposes them. + */ +export {}; +//# sourceMappingURL=downloads.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.d.ts new file mode 100644 index 0000000..f1d7cc7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.d.ts @@ -0,0 +1,24 @@ +/** + * downloads domain zod schemas. The download surface has no wire + * envelope: the request arrives as query parameters (all strings), so its + * request schema parses the raw query-parameter object into the method's + * exact request shape. SessionId brand cast point: sessionIdSchema, and only + * there (hosted in sessions.schema like every other cast). + */ +import { z } from 'zod'; +/** + * session.export query params → the sessionLog request. `includeDescendants` + * accepts exactly `true`/`false`/absent; any other value is rejected (400) so + * a misspelled flag cannot silently under-export. + */ +export declare const sessionLogQuerySchema: z.ZodPipe>; + includeDescendants: z.ZodOptional, z.ZodLiteral<"false">]>>; +}, z.core.$strip>, z.ZodTransform<{ + includeDescendants?: true; + sessionId: import("@deepseek-ai/dsh-session").SessionId; +}, { + sessionId: import("@deepseek-ai/dsh-session").SessionId; + includeDescendants?: "true" | "false" | undefined; +}>>; +//# sourceMappingURL=downloads.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.js new file mode 100644 index 0000000..e9a17be --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.js @@ -0,0 +1,24 @@ +/** + * downloads domain zod schemas. The download surface has no wire + * envelope: the request arrives as query parameters (all strings), so its + * request schema parses the raw query-parameter object into the method's + * exact request shape. SessionId brand cast point: sessionIdSchema, and only + * there (hosted in sessions.schema like every other cast). + */ +import { z } from 'zod'; +import { sessionIdSchema } from "./sessions.schema.js"; +/** + * session.export query params → the sessionLog request. `includeDescendants` + * accepts exactly `true`/`false`/absent; any other value is rejected (400) so + * a misspelled flag cannot silently under-export. + */ +export const sessionLogQuerySchema = z + .object({ + sessionId: sessionIdSchema, + includeDescendants: z.union([z.literal('true'), z.literal('false')]).optional(), +}) + .transform(query => ({ + sessionId: query.sessionId, + ...(query.includeDescendants === 'true' ? { includeDescendants: true } : {}), +})); +//# sourceMappingURL=downloads.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.d.ts new file mode 100644 index 0000000..5b82d8d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.d.ts @@ -0,0 +1,213 @@ +/** + * events domain contract: signatures and frame unions for the two logical + * streams. Four-quadrant: streams yield the narrow form `RpcRequest` (server-request + * view) — rpcId must be exposed to the business layer, because responses to answerable frames + * (approval/question requested) echo it; for pure pushes it identifies that one push. + * signal is a local stream-control parameter, independent of the request (never on the wire). + */ +import type { AskUserQuestionItem } from '@deepseek-ai/dsh-user-questions/types'; +import type { ApprovalOutcome, ApprovalRequestId } from '@deepseek-ai/dsh-user-approval/types'; +import type { Message } from '@deepseek-ai/dsh-llm/types'; +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { CallId } from '@deepseek-ai/dsh-llm/brand'; +import type { JsonValue, SessionEvent, SessionId } from '@deepseek-ai/dsh-session/types'; +import type { ToolCallView, ToolResultView } from '@deepseek-ai/dsh-tools/presentation'; +import type { RpcError, RpcId, RpcRequest } from './rpc.ts'; +import type { JobView } from './jobs.ts'; +import type { WorkspaceView } from './workspace.ts'; +export type { ToolCallView, ToolResultView } from '@deepseek-ai/dsh-tools/presentation'; +/** + * Host-computed render intent accompanying a `tool/call` or `tool/result` + * event. A pure derivation of args/result through the presenter registered at + * emission time — never persisted (the session log carries only the event), so + * the same event may carry a different view (or none) on a later delivery. + * `for` names which vocabulary applies without re-inspecting the event type. + * An absent view means the client's documented default (generic JSON card). + */ +export type ToolEventView = { + for: 'call'; + view: ToolCallView; +} | { + for: 'result'; + view: ToolResultView; +}; +/** One pending inbox occurrence in the authoritative `session/queue` snapshot. */ +export interface QueuedInboxItem { + /** Message identity used by inbox mutations. */ + id: MessageId; + /** Agent-resolved FIFO placement; queued and steering items render on different surfaces, context items stay invisible until claimed. */ + placement: 'queued' | 'steering' | 'context'; + /** Complete pending message; it is not durable until the Agent claims it. */ + message: Message; +} +/** Streaming face of the contract: the two logical stream openers (mux + host). */ +export interface EventsApi { + /** + * All-session aggregated mux stream. On open, emits a subscribed control frame for every + * attached session, then replays each session's still-pending approval/question requested + * frames (rpcId reused verbatim — the refresh-recovery baseline). Session titles ride the + * generic projection pair (history-tail projections block + session/projection frames). + * since: resume hook, unimplemented in v1 (ignored if passed); reconnection = reopen the + * stream + refetch history. + */ + mux(request: RpcRequest<{ + since?: Record; + }>, signal: AbortSignal): AsyncIterable>; + /** + * Host-level info stream: session create/destroy, running-status flips, and + * agent failures with no turn position. Empty payload uses `{}`. + */ + host(request: RpcRequest<{}>, signal: AbortSignal): AsyncIterable>; +} +/** + * Mux stream frames: raw session-event passthrough + control frames + + * approval/question frames (requested = answerable server-request, the rest are pure pushes). + */ +export type MuxFrame = { + type: 'session/event'; + sessionId: SessionId; + event: SessionEvent; + view?: ToolEventView; +} | { + type: 'session/subscribed'; + sessionId: SessionId; + lastSeq: number; +} | { + type: 'approval/requested'; + sessionId: SessionId; + approvalId: ApprovalRequestId; + toolName: string; + callId?: CallId; + reason?: string; +} | { + type: 'approval/resolved'; + sessionId: SessionId; + approvalId: ApprovalRequestId; + outcome: ApprovalOutcome; +} | { + type: 'question/requested'; + sessionId: SessionId; + questions: AskUserQuestionItem[]; +} | { + type: 'question/resolved'; + sessionId: SessionId; + questionRpcId: RpcId; + outcome: 'answered' | 'cancelled'; +} +/** + * Complete transient inbox state after every enqueue, mutation, claim, or + * discard. Pending work is not model-visible and therefore has no durable + * session event; the whole snapshot makes edit, deletion, cancel, and + * reconnect converge through one authoritative signal. `session/queue` + * covers both resolved placements: queued items render + * in QueueDock, while pending steering renders at the conversation tail. + */ + | { + type: 'session/queue'; + sessionId: SessionId; + items: QueuedInboxItem[]; +} +/** + * Complete set of background jobs this session can see, after every registry + * commit that changes it: registration, the stopping transition, settlement, + * and owner-disposal removal. The registry is process-local and holds no + * durable event, so — exactly like `session/queue` — the whole snapshot is + * what makes a start, a kill, a reconnect, and a second tab converge on one + * authoritative value. + * + * Sent as a subscription baseline only for a session that currently has + * tasks; an absent key means an empty set. A change that empties the set + * still sends `[]`, since that transition is the only one absence cannot + * express. + */ + | { + type: 'session/jobs'; + sessionId: SessionId; + jobs: JobView[]; +} +/** + * One projection unit's finished value changed (session-projection RFC). + * Live push state, never logged — replay recomputes on the host (the + * tool-view posture). `value` is the unit's schema-validated view output; + * `seq` is the unit's watermark at emission. Clients keep one generic + * per-session value store under higher-seq-wins, seeded by the history + * tail page's projections block. + */ + | { + type: 'session/projection'; + sessionId: SessionId; + key: string; + value: unknown; + seq: number; +} | { + type: 'stream/error'; + error: RpcError; +}; +/** + * Host stream frames. session-added carries the lineage anchor, product + * origin, project cwd, and blank bit (the list-summary fields a client cannot + * wait for a refresh to learn); the frame fires at session/created, so blank is + * constantly true — clients flip it on the session's first + * `host/session-status(running:true)` (a blank session never runs), and a + * reconnecting client takes `session.list`'s summary.blank as authoritative. + * agent-error is the only outlet for live failures with no turn position; + * workspace-changed pushes the full new snapshot after every durable + * workspace mutation (create/attach/order change — the client upserts, while + * `workspace.list` provides the reconnect baseline); workspace-removed is the + * committed registration-deletion increment and never implies directory or + * session-log deletion; workspace-order-changed pushes the complete durable + * registry order after a reorder; archived-sessions-changed pushes the full registry + * archive set after every durable change (same full-snapshot posture as + * workspace-changed — `workspace.list` re-baselines it on reconnect). + */ +export type HostFrame = { + type: 'host/session-added'; + sessionId: SessionId; + blank: boolean; + parentSessionId?: SessionId; + origin?: 'subagent'; + cwd?: string; + agentPreset?: string; +} | { + type: 'host/session-removed'; + sessionId: SessionId; +} | { + type: 'host/session-status'; + sessionId: SessionId; + running: boolean; +} | { + type: 'host/agent-error'; + sessionId: SessionId; + message: string; +} | { + type: 'host/workspace-changed'; + workspace: WorkspaceView; +} | { + type: 'host/workspace-removed'; + workspaceId: WorkspaceView['workspaceId']; +} | { + type: 'host/workspace-order-changed'; + workspaceIds: WorkspaceView['workspaceId'][]; +} | { + type: 'host/archived-sessions-changed'; + archivedSessionIds: SessionId[]; +} +/** + * One allowlisted host cordis event forwarded verbatim. The allowlist is + * owned by `@deepseek-ai/dsh-api-remotes` (`API_REMOTE_FORWARDED_EVENTS`), + * which is also the only control point over what a consumer can receive. + * `event` is the host's own event name and `args` its argument list: this + * path applies no projection, no redaction, and no renaming, so the payload + * contract is the owner package's cordis `Events` declaration rather than + * anything stated here. Delivery lands on `ctx.remote.$on`, not on a + * per-event frame variant. + */ + | { + type: 'host/remote-event'; + event: string; + args: JsonValue[]; +} | { + type: 'stream/error'; + error: RpcError; +}; +//# sourceMappingURL=events.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.js new file mode 100644 index 0000000..78f5f73 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.js @@ -0,0 +1,9 @@ +/** + * events domain contract: signatures and frame unions for the two logical + * streams. Four-quadrant: streams yield the narrow form `RpcRequest` (server-request + * view) — rpcId must be exposed to the business layer, because responses to answerable frames + * (approval/question requested) echo it; for pure pushes it identifies that one push. + * signal is a local stream-control parameter, independent of the request (never on the wire). + */ +export {}; +//# sourceMappingURL=events.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.d.ts new file mode 100644 index 0000000..257de37 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.d.ts @@ -0,0 +1,28 @@ +/** + * events domain zod schemas: MuxFrame / HostFrame unions (discriminatedUnion('type')). + * A frame is the payload slot of the ServerRequest full form; the SessionEvent inside + * a session/event frame reuses sessions.schema's strict-envelope + wide-data passthrough branch. + */ +import { z } from 'zod'; +import type { HostFrame, MuxFrame } from './events.ts'; +/** Question fields validated strictly against core dsh-user-questions. */ +export declare const askUserQuestionItemSchema: z.ZodObject<{ + id: z.ZodString; + question: z.ZodString; + header: z.ZodOptional; + detail: z.ZodOptional; + options: z.ZodOptional; + }, z.core.$strip>>>; + multiSelect: z.ZodOptional; + intent: z.ZodOptional; + approve: z.ZodString; + }, z.core.$strip>], "kind">>; +}, z.core.$strip>; +/** MuxFrame union (payload slot of a mux-stream ServerRequest). */ +export declare const muxFrameSchema: z.ZodType; +/** HostFrame union (payload slot of a host-stream ServerRequest). */ +export declare const hostFrameSchema: z.ZodType; +//# sourceMappingURL=events.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js new file mode 100644 index 0000000..adcd82d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js @@ -0,0 +1,84 @@ +/** + * events domain zod schemas: MuxFrame / HostFrame unions (discriminatedUnion('type')). + * A frame is the payload slot of the ServerRequest full form; the SessionEvent inside + * a session/event frame reuses sessions.schema's strict-envelope + wide-data passthrough branch. + */ +import { z } from 'zod'; +import { rpcErrorSchema, rpcIdSchema } from "./rpc.schema.js"; +import { approvalRequestIdSchema } from "./approvals.schema.js"; +import { contentBlockSchema, messageIdSchema, sessionEventSchema, sessionIdSchema, toolEventViewSchema, } from "./sessions.schema.js"; +import { taskViewSchema } from "./jobs.schema.js"; +import { workspaceIdSchema, workspaceViewSchema } from "./workspace.schema.js"; +/** Question fields validated strictly against core dsh-user-questions. */ +export const askUserQuestionItemSchema = z.object({ + id: z.string(), + question: z.string(), + header: z.string().optional(), + detail: z.string().optional(), + options: z.array(z.object({ label: z.string(), description: z.string().optional() })).optional(), + multiSelect: z.boolean().optional(), + // Presentation intent: a tagged union on the wire, so an unknown tag is a + // rejected frame rather than a silently generic render. + intent: z.discriminatedUnion('kind', [ + z.object({ kind: z.literal('plan-review'), approve: z.string() }), + ]).optional(), +}); +/** Unified message envelope carried by transient queue frames. */ +const messageSchema = z.object({ + id: z.string().min(1), + role: z.union([z.literal('system'), z.literal('user'), z.literal('assistant')]), + content: z.array(contentBlockSchema), + source: z.looseObject({ kind: z.string() }), +}); +/** MuxFrame union (payload slot of a mux-stream ServerRequest). */ +export const muxFrameSchema = z.discriminatedUnion('type', [ + z.object({ type: z.literal('session/event'), sessionId: sessionIdSchema, event: sessionEventSchema, view: toolEventViewSchema.optional() }), + z.object({ type: z.literal('session/subscribed'), sessionId: sessionIdSchema, lastSeq: z.number().int() }), + z.object({ type: z.literal('approval/requested'), sessionId: sessionIdSchema, approvalId: approvalRequestIdSchema, toolName: z.string(), callId: z.string().optional(), reason: z.string().optional() }), + z.object({ type: z.literal('approval/resolved'), sessionId: sessionIdSchema, approvalId: approvalRequestIdSchema, outcome: z.union([z.literal('allowed-once'), z.literal('rejected'), z.literal('cancelled'), z.literal('unavailable')]) }), + // Non-empty by wire contract: the user-questions service rejects empty + // batches at ask() (EMPTY_QUESTIONS), so an empty frame is host breakage + // and must fail loud here, not reach the composer. + z.object({ type: z.literal('question/requested'), sessionId: sessionIdSchema, questions: z.array(askUserQuestionItemSchema).min(1) }), + z.object({ type: z.literal('question/resolved'), sessionId: sessionIdSchema, questionRpcId: rpcIdSchema, outcome: z.union([z.literal('answered'), z.literal('cancelled')]) }), + z.object({ + type: z.literal('session/queue'), + sessionId: sessionIdSchema, + items: z.array(z.object({ + id: messageIdSchema, + placement: z.union([z.literal('queued'), z.literal('steering'), z.literal('context')]), + message: messageSchema, + })), + }), + z.object({ type: z.literal('session/jobs'), sessionId: sessionIdSchema, jobs: z.array(taskViewSchema) }), + // value stays wide: it already passed its unit's own schema on the host, + // and deep-validating here would import every domain's schema into the carrier. + z.object({ type: z.literal('session/projection'), sessionId: sessionIdSchema, key: z.string().min(1), value: z.unknown(), seq: z.number().int().nonnegative() }), + z.object({ type: z.literal('stream/error'), error: rpcErrorSchema }), +]); +/** HostFrame union (payload slot of a host-stream ServerRequest). */ +export const hostFrameSchema = z.discriminatedUnion('type', [ + z.object({ + type: z.literal('host/session-added'), + sessionId: sessionIdSchema, + blank: z.boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: z.literal('subagent').optional(), + cwd: z.string().optional(), + agentPreset: z.string().optional(), + }), + z.object({ type: z.literal('host/session-removed'), sessionId: sessionIdSchema }), + z.object({ type: z.literal('host/session-status'), sessionId: sessionIdSchema, running: z.boolean() }), + z.object({ type: z.literal('host/agent-error'), sessionId: sessionIdSchema, message: z.string() }), + z.object({ type: z.literal('host/workspace-changed'), workspace: workspaceViewSchema }), + z.object({ type: z.literal('host/workspace-removed'), workspaceId: workspaceIdSchema }), + z.object({ type: z.literal('host/workspace-order-changed'), workspaceIds: z.array(workspaceIdSchema) }), + z.object({ type: z.literal('host/archived-sessions-changed'), archivedSessionIds: z.array(sessionIdSchema) }), + // args stays wide, the same posture as session/projection's value: the frame + // arrives from JSON.parse, so every element is already a JSON value, and the + // structural contract belongs to the owner package's cordis `Events` + // declaration — the host validated JSON-safety before forwarding. + z.object({ type: z.literal('host/remote-event'), event: z.string().min(1), args: z.array(z.unknown()) }), + z.object({ type: z.literal('stream/error'), error: rpcErrorSchema }), +]); +//# sourceMappingURL=events.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.d.ts new file mode 100644 index 0000000..ad435c3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.d.ts @@ -0,0 +1,73 @@ +/** + * goals domain contract. Method signatures are the source of truth: + * unary methods take the RpcRequest

narrow form and the impl echoes rpcId. + * + * Mutations only: the read side is the 'goal' session projection (history + * tail-page projections block + session/projection frames), so there is no + * goal.get and no wire goal view — responses acknowledge with the new CAS + * ref and never feed client state (the committed goal/change event reaches + * every client through the mux stream carrying the same whole value). + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** Identifies one goal across its durable revisions. */ +export type GoalId = Branded<'GoalId'>; +/** Compare-and-set identity for one exact goal revision. */ +export interface GoalRef { + readonly id: GoalId; + readonly revision: number; +} +/** + * Goal-domain unary methods. Every mutation resolves an ordinary session's + * Agent and applies one CAS-guarded verb; session-backed subagents reject with + * `agent-busy`. + */ +export interface GoalsApi { + /** Create and arm a goal. */ + create(request: RpcRequest<{ + sessionId: SessionId; + objective: string; + maxGoalRounds?: number; + }>): Promise>; + /** Edit objective and/or round cap without changing phase. */ + edit(request: RpcRequest<{ + sessionId: SessionId; + ref: GoalRef; + objective?: string; + maxGoalRounds?: number; + }>): Promise>; + /** Pause an active goal and disarm automatic continuation. */ + pause(request: RpcRequest<{ + sessionId: SessionId; + ref: GoalRef; + }>): Promise>; + /** Resume and arm a stopped goal. */ + resume(request: RpcRequest<{ + sessionId: SessionId; + ref: GoalRef; + }>): Promise>; + /** Mark a current non-complete goal complete and disarm it. */ + complete(request: RpcRequest<{ + sessionId: SessionId; + ref: GoalRef; + }>): Promise>; + /** Clear the current goal while retaining a durable tombstone and history. */ + clear(request: RpcRequest<{ + sessionId: SessionId; + ref: GoalRef; + }>): Promise>; +} +//# sourceMappingURL=goals.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.js new file mode 100644 index 0000000..8cb936b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.js @@ -0,0 +1,12 @@ +/** + * goals domain contract. Method signatures are the source of truth: + * unary methods take the RpcRequest

narrow form and the impl echoes rpcId. + * + * Mutations only: the read side is the 'goal' session projection (history + * tail-page projections block + session/projection frames), so there is no + * goal.get and no wire goal view — responses acknowledge with the new CAS + * ref and never feed client state (the committed goal/change event reaches + * every client through the mux stream carrying the same whole value). + */ +export {}; +//# sourceMappingURL=goals.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.d.ts new file mode 100644 index 0000000..47fe478 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.d.ts @@ -0,0 +1,35 @@ +/** + * goals domain zod schemas. Mutation-only shapes: every value schema is a + * `{ ref }` acknowledgement (clear: `{ cleared }`) — the current goal state + * travels exclusively on the 'goal' session projection. + */ +import { z } from 'zod'; +import type { Wire } from './rpc.schema.ts'; +import type { GoalRef, RequestPayload, ResponseValue } from './index.ts'; +/** GoalRef schema. */ +export declare const goalRefSchema: z.ZodType>; +/** goal.create request payload. */ +export declare const goalCreateRequestSchema: z.ZodType>>; +/** goal.create response value. */ +export declare const goalCreateValueSchema: z.ZodType>>; +/** goal.edit request payload. */ +export declare const goalEditRequestSchema: z.ZodType>>; +/** goal.edit response value. */ +export declare const goalEditValueSchema: z.ZodType>>; +/** goal.pause request payload. */ +export declare const goalPauseRequestSchema: z.ZodType>>; +/** goal.pause response value. */ +export declare const goalPauseValueSchema: z.ZodType>>; +/** goal.resume request payload. */ +export declare const goalResumeRequestSchema: z.ZodType>>; +/** goal.resume response value. */ +export declare const goalResumeValueSchema: z.ZodType>>; +/** goal.complete request payload. */ +export declare const goalCompleteRequestSchema: z.ZodType>>; +/** goal.complete response value. */ +export declare const goalCompleteValueSchema: z.ZodType>>; +/** goal.clear request payload. */ +export declare const goalClearRequestSchema: z.ZodType>>; +/** goal.clear response value. */ +export declare const goalClearValueSchema: z.ZodType>>; +//# sourceMappingURL=goals.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.js new file mode 100644 index 0000000..d0dc101 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.js @@ -0,0 +1,63 @@ +/** + * goals domain zod schemas. Mutation-only shapes: every value schema is a + * `{ ref }` acknowledgement (clear: `{ cleared }`) — the current goal state + * travels exclusively on the 'goal' session projection. + */ +import { z } from 'zod'; +/** GoalRef schema. */ +export const goalRefSchema = z.object({ + id: z.string(), + revision: z.number().int().positive(), +}); +/** Shared `{ ref }` acknowledgement value of every non-clear mutation. */ +const goalRefValueSchema = z.object({ ref: goalRefSchema }); +/** goal.create request payload. */ +export const goalCreateRequestSchema = z.object({ + sessionId: z.string(), + objective: z.string().min(1), + maxGoalRounds: z.number().int().positive().optional(), +}); +/** goal.create response value. */ +export const goalCreateValueSchema = goalRefValueSchema; +/** goal.edit request payload. */ +export const goalEditRequestSchema = z.object({ + sessionId: z.string(), + ref: goalRefSchema, + objective: z.string().min(1).optional(), + maxGoalRounds: z.number().int().positive().optional(), +}).refine(value => value.objective !== undefined || value.maxGoalRounds !== undefined, { + message: 'goal.edit requires objective or maxGoalRounds', +}); +/** goal.edit response value. */ +export const goalEditValueSchema = goalRefValueSchema; +/** goal.pause request payload. */ +export const goalPauseRequestSchema = z.object({ + sessionId: z.string(), + ref: goalRefSchema, +}); +/** goal.pause response value. */ +export const goalPauseValueSchema = goalRefValueSchema; +/** goal.resume request payload. */ +export const goalResumeRequestSchema = z.object({ + sessionId: z.string(), + ref: goalRefSchema, +}); +/** goal.resume response value. */ +export const goalResumeValueSchema = goalRefValueSchema; +/** goal.complete request payload. */ +export const goalCompleteRequestSchema = z.object({ + sessionId: z.string(), + ref: goalRefSchema, +}); +/** goal.complete response value. */ +export const goalCompleteValueSchema = goalRefValueSchema; +/** goal.clear request payload. */ +export const goalClearRequestSchema = z.object({ + sessionId: z.string(), + ref: goalRefSchema, +}); +/** goal.clear response value. */ +export const goalClearValueSchema = z.object({ + cleared: z.literal(true), +}); +//# sourceMappingURL=goals.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.d.ts new file mode 100644 index 0000000..11ba5f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.d.ts @@ -0,0 +1,91 @@ +/** + * host domain contract. No protocol version: client and host ship + * together; introduce protocolVersion only when an independently released client appears. + */ +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** One directory row of a listing: a child entry or a breadcrumb ancestor. */ +export interface DirectoryEntry { + /** Base name shown in a browser row (a root crumb carries its full path). */ + name: string; + /** Absolute host path — the client never joins path segments itself. */ + path: string; + /** Hidden by the host platform's convention (dot-prefixed on POSIX); the client owns whether to show it. */ + hidden: boolean; +} +/** host.listDirectory response value: one directory level plus its ancestry. */ +export interface DirectoryListing { + /** Absolute path of the listed directory. */ + path: string; + /** The host account's home directory (breadcrumb "Home" rooting). */ + home: string; + /** + * Ancestor chain from the filesystem root to the listed directory + * inclusive; every crumb is a jump target (crumb `hidden` is always false). + */ + crumbs: DirectoryEntry[]; + /** Direct child directories, name-sorted; symlinks to directories included. */ + entries: DirectoryEntry[]; + /** True when the backend cut `entries` at its complete-result bound (the name-sorted tail is absent). */ + truncated: boolean; +} +/** Host-level unary methods. */ +export interface HostApi { + /** + * One-shot host snapshot. Empty payload uses the literal `{}` (extend in place when fields arrive). + * version = the host app's (apps/cli) package.json version; cwd = the host process working + * directory (root for session persistence and tool execution); provider/model = the defaults + * applied when a new agent doesn't specify them explicitly, absent when the host configures + * no explicit default (the adapter falls back internally); + * attachedSessions = count of currently attached sessions (those with a live agent); + * canOpenPath = whether this deployment can hand a path to a user-visible native desktop. + */ + describe(request: RpcRequest<{}>): Promise>; + /** + * Open the operating system's single-directory picker; cancellation returns + * null. Only served under the `native` capability. + */ + pickDirectory(request: RpcRequest<{}>, signal: AbortSignal): Promise>; + /** + * List one directory level for the in-app browser; an absent path lists the + * host account's home directory. Only served under the `browse` capability; + * unreadable or missing targets fail with `directory-unreadable`. The + * carrier's request signal follows the caller, stopping the backend's scan + * on disconnect or timeout. + */ + listDirectory(request: RpcRequest<{ + path?: string; + }>, signal: AbortSignal): Promise>; + /** + * Create one child directory under an existing parent (the browser's + * "New folder"). Only served under the `browse` capability; an existing + * child fails with `directory-exists`, every other filesystem failure with + * `directory-create-failed`. + */ + createDirectory(request: RpcRequest<{ + path: string; + name: string; + }>): Promise>; + /** + * Open a filesystem path with the operating system's default application + * (Finder / Explorer / xdg-open hand-off). The browser carrier's + * prefix-wide trust fence covers this privileged method like every other + * `/api` request. + */ + openPath(request: RpcRequest<{ + path: string; + }>, signal: AbortSignal): Promise>; +} +//# sourceMappingURL=host.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.js new file mode 100644 index 0000000..e0ea541 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.js @@ -0,0 +1,6 @@ +/** + * host domain contract. No protocol version: client and host ship + * together; introduce protocolVersion only when an independently released client appears. + */ +export {}; +//# sourceMappingURL=host.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.d.ts new file mode 100644 index 0000000..556953c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.d.ts @@ -0,0 +1,65 @@ +/** + * host domain zod schemas (names derived from map keys). + */ +import { z } from 'zod'; +/** host.describe request payload (empty object literal). */ +export declare const hostDescribeRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** host.describe response value. */ +export declare const hostDescribeValueSchema: z.ZodObject<{ + version: z.ZodString; + cwd: z.ZodString; + provider: z.ZodOptional; + model: z.ZodOptional; + attachedSessions: z.ZodNumber; + canOpenPath: z.ZodBoolean; +}, z.core.$strip>; +/** host.pickDirectory request payload (empty object literal). */ +export declare const hostPickDirectoryRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** host.pickDirectory response value; null means the user cancelled. */ +export declare const hostPickDirectoryValueSchema: z.ZodObject<{ + path: z.ZodNullable; +}, z.core.$strip>; +/** Directory row shared by listing entries and breadcrumb crumbs. */ +export declare const directoryEntrySchema: z.ZodObject<{ + name: z.ZodString; + path: z.ZodString; + hidden: z.ZodBoolean; +}, z.core.$strip>; +/** host.listDirectory request payload; an absent path lists the home directory. */ +export declare const hostListDirectoryRequestSchema: z.ZodObject<{ + path: z.ZodOptional; +}, z.core.$strip>; +/** host.listDirectory response value. */ +export declare const hostListDirectoryValueSchema: z.ZodObject<{ + path: z.ZodString; + home: z.ZodString; + crumbs: z.ZodArray>; + entries: z.ZodArray>; + truncated: z.ZodBoolean; +}, z.core.$strip>; +/** host.createDirectory request payload: name must be one plain path segment. */ +export declare const hostCreateDirectoryRequestSchema: z.ZodObject<{ + path: z.ZodString; + name: z.ZodString; +}, z.core.$strip>; +/** host.createDirectory response value: the created directory's absolute path. */ +export declare const hostCreateDirectoryValueSchema: z.ZodObject<{ + path: z.ZodString; +}, z.core.$strip>; +/** host.openPath request payload. */ +export declare const hostOpenPathRequestSchema: z.ZodObject<{ + path: z.ZodString; +}, z.core.$strip>; +/** host.openPath response value. */ +export declare const hostOpenPathValueSchema: z.ZodObject<{ + opened: z.ZodLiteral; +}, z.core.$strip>; +//# sourceMappingURL=host.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.js new file mode 100644 index 0000000..5f3b496 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.js @@ -0,0 +1,58 @@ +/** + * host domain zod schemas (names derived from map keys). + */ +import { z } from 'zod'; +/** host.describe request payload (empty object literal). */ +export const hostDescribeRequestSchema = z.object({}); +/** host.describe response value. */ +export const hostDescribeValueSchema = z.object({ + version: z.string(), + cwd: z.string(), + provider: z.string().optional(), + model: z.string().optional(), + attachedSessions: z.number().int().nonnegative(), + canOpenPath: z.boolean(), +}); +/** host.pickDirectory request payload (empty object literal). */ +export const hostPickDirectoryRequestSchema = z.object({}); +/** host.pickDirectory response value; null means the user cancelled. */ +export const hostPickDirectoryValueSchema = z.object({ + path: z.string().nullable(), +}); +/** Directory row shared by listing entries and breadcrumb crumbs. */ +export const directoryEntrySchema = z.object({ + name: z.string(), + path: z.string(), + hidden: z.boolean(), +}); +/** host.listDirectory request payload; an absent path lists the home directory. */ +export const hostListDirectoryRequestSchema = z.object({ + path: z.string().optional(), +}); +/** host.listDirectory response value. */ +export const hostListDirectoryValueSchema = z.object({ + path: z.string(), + home: z.string(), + crumbs: z.array(directoryEntrySchema), + entries: z.array(directoryEntrySchema), + truncated: z.boolean(), +}); +/** host.createDirectory request payload: name must be one plain path segment. */ +export const hostCreateDirectoryRequestSchema = z.object({ + path: z.string(), + name: z.string(), +}).refine(payload => payload.name.trim() !== '' && payload.name !== '.' && payload.name !== '..' + && !/[/\\]/.test(payload.name), { message: 'host.createDirectory requires a single non-blank path segment name' }); +/** host.createDirectory response value: the created directory's absolute path. */ +export const hostCreateDirectoryValueSchema = z.object({ + path: z.string(), +}); +/** host.openPath request payload. */ +export const hostOpenPathRequestSchema = z.object({ + path: z.string().min(1), +}); +/** host.openPath response value. */ +export const hostOpenPathValueSchema = z.object({ + opened: z.literal(true), +}); +//# sourceMappingURL=host.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.d.ts new file mode 100644 index 0000000..ebaa5e8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.d.ts @@ -0,0 +1,63 @@ +/** + * apiproxy contract-layer barrel. api/ has zero Node dependencies and is + * importable from the browser; the TS interfaces are the authoritative contract, while HTTP, + * WebSocket, and in-process SSE are merely physical channels (four-quadrant message model). + */ +import type { SessionsApi } from './sessions.ts'; +import type { HostApi } from './host.ts'; +import type { WorkspaceApi } from './workspace.ts'; +import type { AgentPresetsApi } from './agent-presets.ts'; +import type { SkillsApi } from './skills.ts'; +import type { SubagentsApi } from './subagents.ts'; +import type { EventsApi } from './events.ts'; +import type { GoalsApi } from './goals.ts'; +import type { SettingsApi } from './settings.ts'; +import type { CredentialsApi } from './credentials.ts'; +import type { LlmApi } from './llm.ts'; +import type { DownloadsApi } from './downloads.ts'; +import type { ClientResponse, RpcReceipt } from './rpc.ts'; +/** Root interface of the unified API. New client-request domain = one new file pair + one field here + one map row. */ +export interface ApiProxy { + sessions: SessionsApi; + subagents: SubagentsApi; + host: HostApi; + workspace: WorkspaceApi; + skills: SkillsApi; + agentPresets: AgentPresetsApi; + events: EventsApi; + goals: GoalsApi; + settings: SettingsApi; + credentials: CredentialsApi; + llm: LlmApi; + /** Host-only download surfaces (GET, no wire envelope); absent from IApiClient. */ + downloads: DownloadsApi; + /** + * Response entry for server requests; not a domain method. + * @param message - Client response carrying the server request's rpcId. + * @returns Transport receipt for the response delivery. + */ + respond(message: ClientResponse): Promise; +} +export type { HistoryEntry, ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning, ModelReasoningEffort, ModelSelection, PromptContentPart, QueueAction, SessionModels, SessionListMetadata, SessionProjectionsBlock, SessionSearchItem, SessionsApi, SessionSummary, } from './sessions.ts'; +export type { DirectoryEntry, DirectoryListing, HostApi } from './host.ts'; +export type { SubagentAddress, SubagentCatalog, SubagentInterruptReceipt, SubagentListEntry, SubagentPromptReceipt, SubagentsApi, } from './subagents.ts'; +export type { JobView } from './jobs.ts'; +export type { WorkspaceApi, WorkspaceId, WorkspaceView } from './workspace.ts'; +export type { SkillsApi, SkillEntry } from './skills.ts'; +export type { AgentPresetsApi, AgentPresetEntry } from './agent-presets.ts'; +export type { EventsApi, MuxFrame, HostFrame, QueuedInboxItem, ToolCallView, ToolEventView, ToolResultView } from './events.ts'; +export type { GoalsApi, GoalId, GoalRef } from './goals.ts'; +export type { SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView } from './settings.ts'; +export type { CredentialsApi, CredentialView } from './credentials.ts'; +export type { ConfigurableProviderView, DiscoveredModelView, LlmApi } from './llm.ts'; +export type { DownloadsApi } from './downloads.ts'; +export type { ApprovalResponsePayload } from './approvals.ts'; +export type { QuestionResponsePayload } from './questions.ts'; +export type { RpcRequest, RpcResponse } from './rpc.ts'; +export type { ClientRequest, ClientResponse, RpcMessage, RpcReceipt, ServerRequest, ServerResponse, } from './rpc.ts'; +export { RpcId, transportError } from './rpc.ts'; +export type { RpcError, RpcErrorCode, RpcErrorDetailsMap, RpcResult } from './rpc.ts'; +export { clientRequestSchema, serverRequestSchema, serverResponseSchema, } from './rpc.schema.ts'; +export { SESSION_SEARCH_RESULT_LIMIT, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS, } from './session-search.ts'; +export type { RequestPayload, ResponseValue, RpcMethodMap } from './rpc-map.ts'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.js new file mode 100644 index 0000000..b03cb5f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.js @@ -0,0 +1,11 @@ +/** + * apiproxy contract-layer barrel. api/ has zero Node dependencies and is + * importable from the browser; the TS interfaces are the authoritative contract, while HTTP, + * WebSocket, and in-process SSE are merely physical channels (four-quadrant message model). + */ +// ---- Errors and ids ---- +export { RpcId, transportError } from "./rpc.js"; +export { clientRequestSchema, serverRequestSchema, serverResponseSchema, } from "./rpc.schema.js"; +// ---- Fixed session-search product bounds ---- +export { SESSION_SEARCH_RESULT_LIMIT, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS, } from "./session-search.js"; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.d.ts new file mode 100644 index 0000000..44bf62d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.d.ts @@ -0,0 +1,35 @@ +/** + * Browser-safe background-job domain contract. The registry's live records + * never cross the wire; a view is the subset a human list needs, minted fresh + * per push. + */ +import type { JobId } from '@deepseek-ai/dsh-jobs/brand'; +/** + * One background job as the client sees it. + * + * Three registry fields are deliberately absent. `ownerSession` is redundant + * beside the frame's own `sessionId`; `reported` is an internal notice-delivery + * bit with no user meaning; `outputLimitBytes` is producer-owned model + * presentation policy that never reaches a human surface. + */ +export interface JobView { + /** Registry-issued `-N` identity, stable for the task's whole life. */ + id: JobId; + /** + * Producer kind (`bash`, `pwsh`, `pty-send`, `subagent`, …). Kept as a bare + * string because producer plugins extend the kind map by declaration merging, + * so no client build can enumerate the closed set. + */ + kind: string; + /** Producer-supplied one-line label: the command, or the delegation description. */ + label: string; + /** Current lifecycle state. */ + status: 'running' | 'stopping' | 'completed' | 'killed' | 'failed'; + /** Kind-specific status detail ('exit code: 3'), present once the producer supplied one. */ + detail?: string; + /** Epoch ms when the task was registered. */ + startedAt: number; + /** Epoch ms when the task settled; absent while live. */ + finishedAt?: number; +} +//# sourceMappingURL=jobs.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.js new file mode 100644 index 0000000..445aa97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.js @@ -0,0 +1,7 @@ +/** + * Browser-safe background-job domain contract. The registry's live records + * never cross the wire; a view is the subset a human list needs, minted fresh + * per push. + */ +export {}; +//# sourceMappingURL=jobs.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.d.ts new file mode 100644 index 0000000..fb751a9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.d.ts @@ -0,0 +1,23 @@ +/** + * tasks domain zod schemas: the branded job id and the wire view carried by + * `session/jobs` frames. + */ +import { z } from 'zod'; +import type { JobId } from '@deepseek-ai/dsh-jobs/brand'; +/** JobId: one brand cast after non-empty string validation. */ +export declare const taskIdSchema: z.ZodType; +/** + * One wire task view. `kind` stays an open string because producer plugins + * extend the registry's kind map by declaration merging, so the closed set is + * not knowable at this boundary. + */ +export declare const taskViewSchema: z.ZodObject<{ + id: z.ZodType>; + kind: z.ZodString; + label: z.ZodString; + status: z.ZodUnion, z.ZodLiteral<"stopping">, z.ZodLiteral<"completed">, z.ZodLiteral<"killed">, z.ZodLiteral<"failed">]>; + detail: z.ZodOptional; + startedAt: z.ZodNumber; + finishedAt: z.ZodOptional; +}, z.core.$strip>; +//# sourceMappingURL=jobs.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.js new file mode 100644 index 0000000..5617c2b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.js @@ -0,0 +1,28 @@ +/** + * tasks domain zod schemas: the branded job id and the wire view carried by + * `session/jobs` frames. + */ +import { z } from 'zod'; +/** JobId: one brand cast after non-empty string validation. */ +export const taskIdSchema = z.string().min(1); +/** + * One wire task view. `kind` stays an open string because producer plugins + * extend the registry's kind map by declaration merging, so the closed set is + * not knowable at this boundary. + */ +export const taskViewSchema = z.object({ + id: taskIdSchema, + kind: z.string().min(1), + label: z.string().min(1), + status: z.union([ + z.literal('running'), + z.literal('stopping'), + z.literal('completed'), + z.literal('killed'), + z.literal('failed'), + ]), + detail: z.string().optional(), + startedAt: z.number().int().nonnegative(), + finishedAt: z.number().int().nonnegative().optional(), +}); +//# sourceMappingURL=jobs.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.d.ts new file mode 100644 index 0000000..6cffa55 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.d.ts @@ -0,0 +1,88 @@ +/** + * llm domain contract: host-scoped provider topology for configuration + * surfaces. `llm.providers` merges the configurable-provider directory + * (which providers CAN be configured, and where their settings live) with the + * live route registry; `llm.models` is the session-independent model catalog + * (the same groups as `session.models`, without a per-session selection). + * Clients invalidate from the forwarded `llm/adapters-updated` and + * `settings/document-updated` owner events. + */ +import type { RpcRequest, RpcResponse } from './rpc.ts'; +import type { ModelCatalogFailure, ModelProviderGroup } from './sessions.ts'; +/** Wire view of one configurable provider. */ +export interface ConfigurableProviderView { + /** Provider route key (`deepseek-official`, `openai`, …). */ + provider: string; + /** Human-readable name for configuration surfaces. */ + displayName: string; + /** Settings namespace whose section configures this provider. */ + settingsNs: string; + /** Path from that section's root to the provider's profile object (empty = whole section). */ + settingsPath: string[]; + /** Whether the route is currently registered (its models are requestable). */ + active: boolean; + /** + * Whether the owning adapter knows this route only because configuration + * declared it. Absent when the adapter draws no such distinction, so a + * surface must treat absence as "unknown", not as "shipped". + */ + declared?: boolean; +} +/** Llm-domain unary methods (the map keys llm.* of RpcMethodMap). */ +export interface LlmApi { + /** + * List every configurable provider with its live/dormant state, in + * directory declaration order. Routes registered outside the directory + * (an adapter that never declared configurability) are appended with their + * registration identity and no settings address. + */ + providers(request: RpcRequest<{}>): Promise>; + /** + * Host-scoped model catalog over every registered provider route: the + * settings surface's models view, needing no session. Per-provider listing + * failures ride `failures` without failing the sound groups. + */ + models(request: RpcRequest<{}>): Promise>; + /** + * Interrogate a provider endpoint the configuration surface is still + * drafting, and return the models it advertises for the user to adopt. + * + * The payload is the draft, not a stored route: `settingsNs` selects the + * adapter family that answers, and the rest comes from the form. `provider` + * names the route being edited when there is one — an adapter that already + * describes that route answers from its own registry, with better metadata + * and no network call, and needs no endpoint. A route it does not describe is + * asked over the wire, which is what `baseURL`, `api`, and `apiKey` are for. + * + * Nothing is written — the reply is candidates, and only a later + * `settings.mutate` decides what a route serves. `apiKey` is accepted here + * but never stored or returned; a provider whose key is already stored omits + * it and the endpoint answers unauthenticated or refuses. + */ + discoverModels(request: RpcRequest<{ + settingsNs: string; + provider?: string; + baseURL?: string; + api?: string; + apiKey?: string; + }>, signal?: AbortSignal): Promise>; +} +/** Wire view of one model an interrogated endpoint advertises. */ +export interface DiscoveredModelView { + /** Model id the endpoint accepts. */ + id: string; + /** Human-readable name when the endpoint supplies one. */ + name?: string; + /** Maximum combined request and response context, when disclosed. */ + contextWindow?: number; + /** Maximum output tokens, when disclosed. */ + maxTokens?: number; +} +//# sourceMappingURL=llm.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.js new file mode 100644 index 0000000..d434c9d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.js @@ -0,0 +1,11 @@ +/** + * llm domain contract: host-scoped provider topology for configuration + * surfaces. `llm.providers` merges the configurable-provider directory + * (which providers CAN be configured, and where their settings live) with the + * live route registry; `llm.models` is the session-independent model catalog + * (the same groups as `session.models`, without a per-session selection). + * Clients invalidate from the forwarded `llm/adapters-updated` and + * `settings/document-updated` owner events. + */ +export {}; +//# sourceMappingURL=llm.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.d.ts new file mode 100644 index 0000000..1452ae8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.d.ts @@ -0,0 +1,79 @@ +/** + * llm domain zod schemas (names derived from map keys: llmProvidersRequestSchema / + * llmProvidersValueSchema / llmModelsRequestSchema / llmModelsValueSchema). + */ +import { z } from 'zod'; +/** ConfigurableProviderView row of llm.providers. */ +export declare const configurableProviderViewSchema: z.ZodObject<{ + provider: z.ZodString; + displayName: z.ZodString; + settingsNs: z.ZodString; + settingsPath: z.ZodArray; + active: z.ZodBoolean; + declared: z.ZodOptional; +}, z.core.$strip>; +/** llm.providers request payload. */ +export declare const llmProvidersRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** llm.providers response value. */ +export declare const llmProvidersValueSchema: z.ZodObject<{ + providers: z.ZodArray; + active: z.ZodBoolean; + declared: z.ZodOptional; + }, z.core.$strip>>; +}, z.core.$strip>; +/** llm.models request payload. */ +export declare const llmModelsRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** llm.models response value. */ +export declare const llmModelsValueSchema: z.ZodObject<{ + groups: z.ZodArray; + reasoning: z.ZodOptional; + }, z.core.$strip>>; + defaultEffort: z.ZodOptional; + }, z.core.$strip>>; + }, z.core.$strip>>; + }, z.core.$strip>>; + failures: z.ZodArray>; +}, z.core.$strip>; +/** DiscoveredModelView row of llm.discoverModels. */ +export declare const discoveredModelViewSchema: z.ZodObject<{ + id: z.ZodString; + name: z.ZodOptional; + contextWindow: z.ZodOptional; + maxTokens: z.ZodOptional; +}, z.core.$strip>; +/** llm.discoverModels request payload. */ +export declare const llmDiscoverModelsRequestSchema: z.ZodObject<{ + settingsNs: z.ZodString; + provider: z.ZodOptional; + baseURL: z.ZodOptional; + api: z.ZodOptional; + apiKey: z.ZodOptional; +}, z.core.$strip>; +/** llm.discoverModels response value. */ +export declare const llmDiscoverModelsValueSchema: z.ZodObject<{ + models: z.ZodArray; + contextWindow: z.ZodOptional; + maxTokens: z.ZodOptional; + }, z.core.$strip>>; +}, z.core.$strip>; +//# sourceMappingURL=llm.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.js new file mode 100644 index 0000000..68938c1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.js @@ -0,0 +1,53 @@ +/** + * llm domain zod schemas (names derived from map keys: llmProvidersRequestSchema / + * llmProvidersValueSchema / llmModelsRequestSchema / llmModelsValueSchema). + */ +import { z } from 'zod'; +import { modelCatalogFailureSchema, modelProviderGroupSchema } from "./sessions.schema.js"; +/** ConfigurableProviderView row of llm.providers. */ +export const configurableProviderViewSchema = z.object({ + provider: z.string().min(1), + displayName: z.string().min(1), + settingsNs: z.string(), + settingsPath: z.array(z.string()), + active: z.boolean(), + declared: z.boolean().optional(), +}); +/** llm.providers request payload. */ +export const llmProvidersRequestSchema = z.object({}); +/** llm.providers response value. */ +export const llmProvidersValueSchema = z.object({ + providers: z.array(configurableProviderViewSchema), +}); +/** llm.models request payload. */ +export const llmModelsRequestSchema = z.object({}); +/** llm.models response value. */ +export const llmModelsValueSchema = z.object({ + groups: z.array(modelProviderGroupSchema), + failures: z.array(modelCatalogFailureSchema), +}); +/** DiscoveredModelView row of llm.discoverModels. */ +export const discoveredModelViewSchema = z.object({ + id: z.string().min(1), + name: z.string().min(1).optional(), + contextWindow: z.number().int().positive().optional(), + maxTokens: z.number().int().positive().optional(), +}); +/** llm.discoverModels request payload. */ +export const llmDiscoverModelsRequestSchema = z.object({ + settingsNs: z.string().min(1), + provider: z.string().min(1).optional(), + baseURL: z.string().min(1).optional(), + api: z.string().min(1).optional(), + // Write-only at the host: used for this one interrogation, never stored and + // never returned. It does ride the client's outgoing envelope like every + // other secret-bearing payload (`credentials.set`, `settings.update`), which + // `subscribeEnvelopes()` observers can see — redacting that tap is a + // configuration-plane-wide change, not this method's to make alone. + apiKey: z.string().min(1).optional(), +}); +/** llm.discoverModels response value. */ +export const llmDiscoverModelsValueSchema = z.object({ + models: z.array(discoveredModelViewSchema), +}); +//# sourceMappingURL=llm.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.d.ts new file mode 100644 index 0000000..99e0872 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.d.ts @@ -0,0 +1,18 @@ +/** + * questions domain contract. The question requested frame is a + * server-request whose rpcId is the question's stable logical id (minted when the host accepts + * ask(); core user-questions has no request-level id); the answer is a client-response + * echoing that rpcId, with no resource id in the payload (rpcId suffices). + */ +import type { AskUserQuestionAnswer } from '@deepseek-ai/dsh-user-questions/types'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +/** + * Question answer payload (the result.value slot of a client-response): + * answers one ask() as a whole batch (core: one ask, many questions, one + * answer — never split per question). + */ +export interface QuestionResponsePayload { + sessionId: SessionId; + answer: AskUserQuestionAnswer; +} +//# sourceMappingURL=questions.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.js new file mode 100644 index 0000000..17a6e2d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.js @@ -0,0 +1,8 @@ +/** + * questions domain contract. The question requested frame is a + * server-request whose rpcId is the question's stable logical id (minted when the host accepts + * ask(); core user-questions has no request-level id); the answer is a client-response + * echoing that rpcId, with no resource id in the payload (rpcId suffices). + */ +export {}; +//# sourceMappingURL=questions.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.d.ts new file mode 100644 index 0000000..c2673ef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.d.ts @@ -0,0 +1,26 @@ +/** + * questions domain zod schemas (respond is a client-response; the payload schema serves + * the /api/respond endpoint's second parse after routing via the pending table). The question + * identifier is the echoed rpcId; the payload carries no resource id. + */ +import { z } from 'zod'; +/** AskUserQuestionAnswer validated strictly against core dsh-user-questions. */ +export declare const askUserQuestionAnswerSchema: z.ZodObject<{ + answers: z.ZodArray; + custom: z.ZodOptional; + }, z.core.$strip>>; +}, z.core.$strip>; +/** Question answer payload (the result.value slot of a client-response). */ +export declare const questionResponsePayloadSchema: z.ZodObject<{ + sessionId: z.ZodType>; + answer: z.ZodObject<{ + answers: z.ZodArray; + custom: z.ZodOptional; + }, z.core.$strip>>; + }, z.core.$strip>; +}, z.core.$strip>; +//# sourceMappingURL=questions.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.js new file mode 100644 index 0000000..d05435c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.js @@ -0,0 +1,21 @@ +/** + * questions domain zod schemas (respond is a client-response; the payload schema serves + * the /api/respond endpoint's second parse after routing via the pending table). The question + * identifier is the echoed rpcId; the payload carries no resource id. + */ +import { z } from 'zod'; +import { sessionIdSchema } from "./sessions.schema.js"; +/** AskUserQuestionAnswer validated strictly against core dsh-user-questions. */ +export const askUserQuestionAnswerSchema = z.object({ + answers: z.array(z.object({ + id: z.string(), + selected: z.array(z.string()), + custom: z.string().optional(), + })), +}); +/** Question answer payload (the result.value slot of a client-response). */ +export const questionResponsePayloadSchema = z.object({ + sessionId: sessionIdSchema, + answer: askUserQuestionAnswerSchema, +}); +//# sourceMappingURL=questions.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.d.ts new file mode 100644 index 0000000..351987e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.d.ts @@ -0,0 +1,80 @@ +/** + * RPC method registry and signature-derived generics. The map + * registers only client-request methods (respond is a client-response, so it is absent); + * map keys are the wire path segments (POST /api/session.list). + */ +import type { SessionsApi } from './sessions.ts'; +import type { HostApi } from './host.ts'; +import type { WorkspaceApi } from './workspace.ts'; +import type { AgentPresetsApi } from './agent-presets.ts'; +import type { SkillsApi } from './skills.ts'; +import type { GoalsApi } from './goals.ts'; +import type { SettingsApi } from './settings.ts'; +import type { CredentialsApi } from './credentials.ts'; +import type { LlmApi } from './llm.ts'; +import type { SubagentsApi } from './subagents.ts'; +import type { RpcResponse } from './rpc.ts'; +/** + * Method name → method signature. Signatures are the single source of truth; payload/value + * types are always derived from here. A method may declare a trailing AbortSignal after the + * request (command.execute): the carrier passes its request signal, never a wire field. + */ +export interface RpcMethodMap { + 'session.list': SessionsApi['list']; + 'session.search': SessionsApi['search']; + 'session.create': SessionsApi['create']; + 'session.history': SessionsApi['history']; + 'session.models': SessionsApi['models']; + 'session.selectModel': SessionsApi['selectModel']; + 'session.rename': SessionsApi['rename']; + 'session.fork': SessionsApi['fork']; + 'session.prompt': SessionsApi['prompt']; + 'session.attachment': SessionsApi['attachment']; + 'session.updateQueue': SessionsApi['updateQueue']; + 'session.cancel': SessionsApi['cancel']; + 'subagent.list': SubagentsApi['list']; + 'subagent.history': SubagentsApi['history']; + 'subagent.prompt': SubagentsApi['prompt']; + 'subagent.interrupt': SubagentsApi['interrupt']; + 'host.describe': HostApi['describe']; + 'host.pickDirectory': HostApi['pickDirectory']; + 'host.listDirectory': HostApi['listDirectory']; + 'host.createDirectory': HostApi['createDirectory']; + 'host.openPath': HostApi['openPath']; + 'workspace.list': WorkspaceApi['list']; + 'workspace.create': WorkspaceApi['create']; + 'workspace.rename': WorkspaceApi['rename']; + 'workspace.delete': WorkspaceApi['delete']; + 'workspace.insertBefore': WorkspaceApi['insertBefore']; + 'workspace.insertSessionBefore': WorkspaceApi['insertSessionBefore']; + 'workspace.archiveSession': WorkspaceApi['archiveSession']; + 'skill.list': SkillsApi['list']; + 'agentPreset.list': AgentPresetsApi['list']; + 'agentPreset.select': AgentPresetsApi['select']; + 'agentPreset.read': AgentPresetsApi['read']; + 'agentPreset.copy': AgentPresetsApi['copy']; + 'agentPreset.openDocument': AgentPresetsApi['openDocument']; + 'agentPreset.remove': AgentPresetsApi['remove']; + 'goal.create': GoalsApi['create']; + 'goal.edit': GoalsApi['edit']; + 'goal.pause': GoalsApi['pause']; + 'goal.resume': GoalsApi['resume']; + 'goal.complete': GoalsApi['complete']; + 'goal.clear': GoalsApi['clear']; + 'settings.describe': SettingsApi['describe']; + 'settings.openDocument': SettingsApi['openDocument']; + 'settings.update': SettingsApi['update']; + 'settings.replace': SettingsApi['replace']; + 'settings.mutate': SettingsApi['mutate']; + 'credentials.describe': CredentialsApi['describe']; + 'credentials.set': CredentialsApi['set']; + 'credentials.unset': CredentialsApi['unset']; + 'llm.providers': LlmApi['providers']; + 'llm.models': LlmApi['models']; + 'llm.discoverModels': LlmApi['discoverModels']; +} +/** Business request payload of method K (reaches through the RpcRequest narrow form to payload). */ +export type RequestPayload = Parameters[0]['payload']; +/** Business return value of method K (reaches through the RpcResponse narrow form to infer the ok value of result). */ +export type ResponseValue = Awaited> extends RpcResponse ? T : never; +//# sourceMappingURL=rpc-map.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.js new file mode 100644 index 0000000..74c509d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.js @@ -0,0 +1,7 @@ +/** + * RPC method registry and signature-derived generics. The map + * registers only client-request methods (respond is a client-response, so it is absent); + * map keys are the wire path segments (POST /api/session.list). + */ +export {}; +//# sourceMappingURL=rpc-map.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.d.ts new file mode 100644 index 0000000..b26961f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.d.ts @@ -0,0 +1,271 @@ +/** + * Four-quadrant RPC message model. Channels and messages are decoupled: HTTP, + * WebSocket, and in-process SSE are physical carriers, while logical messages + * are channel-independent and form a four-member discriminated union. + * api/ contract layer: zero Node dependencies, importable from the browser. + */ +import type { z as zCore } from 'zod'; +type ZodIssue = zCore.core.$ZodIssue; +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +/** + * Message correlation id: the initiator mints it on a request; a response + * echoes the matching request's rpcId and never mints a new one. + */ +export type RpcId = Branded<'rpc-id'>; +/** + * Brands a string as RpcId (same precedent as core `SessionId()`). Minted by the initiator: + * client-request → client mints; server-request → host mints (answerable frames get a stable + * logical id, pure pushes mint a fresh one each time). + * @param id - Raw id string (implementations mint UUIDs; tests may pass fixtures). + * @returns The same string, branded (compile-time cast, zero runtime cost). + */ +export declare function RpcId(id: string): RpcId; +/** Error code → details type map (a second table isomorphic to RpcMethodMap). New code = one row here + one branch in the error schema. */ +export interface RpcErrorDetailsMap { + 'bad-request': { + issues: ZodIssue[]; + }; + 'cancelled': {}; + 'session-not-found': { + sessionId: SessionId; + }; + 'model-unavailable': { + provider: string; + model: string; + }; + 'session-conflict': { + sessionId: SessionId; + requestedCwd: string; + existingCwd?: string; + }; + 'invalid-time-zone': { + value: string; + }; + 'workspace-attach-failed': { + sessionId: SessionId; + workspaceId: string; + }; + 'workspace-not-found': { + workspaceId: string; + }; + 'workspace-invalid-path': { + path: string; + }; + 'workspace-name-conflict': { + name: string; + }; + 'workspace-move-invalid': { + workspaceId: string; + sessionId: SessionId; + beforeSessionId?: SessionId; + }; + 'directory-unreadable': { + path: string; + }; + 'directory-exists': { + path: string; + }; + 'directory-create-failed': { + path: string; + }; + 'directory-picker-unavailable': { + capability: string; + }; + 'agent-preset-read-only': { + agentPreset: string; + reason: string; + }; + 'agent-preset-locked': { + sessionId: SessionId; + agentPreset: string; + }; + 'agent-preset-conflict': { + sessionId: SessionId; + requestedPreset: string; + existingPreset?: string; + }; + 'agent-preset-not-found': { + agentPreset: string; + available: string[]; + }; + 'agent-preset-invalid': { + agentPreset: string; + reason: string; + }; + 'agent-busy': { + reason: string; + }; + 'attachment-error': { + reason: string; + }; + 'queue-item-not-found': { + itemId: MessageId; + }; + 'steer-unavailable': { + itemId: MessageId; + }; + /** A known slash command reported a usage/state error; the message is the command's own text. */ + 'command-error': {}; + /** A leading-/ prompt named no registered command; the message names the token. */ + 'unknown-command': {}; + /** + * A settings write was refused (schema validation, unknown namespace, + * read-only provider, or storage failure); the message is the seam's text. + */ + 'settings-rejected': { + ns: string; + }; + /** + * A settings namespace exists in the seam but is outside the configuration + * plane's model-provider boundary, so this proxy neither reads nor writes + * it; the message names the namespace. + */ + 'settings-not-exposed': { + ns: string; + }; + /** + * A settings write carried an `expectedRevision` the namespace has already + * moved past: another writer (tab, editor, or an external file edit) landed + * first. The details carry both revisions so a client can re-read and retry. + */ + 'settings-conflict': { + ns: string; + expected: number; + actual: number; + }; + /** A credential write was refused (read-only shadowing layer or storage failure); the message is the seam's own text. */ + 'credential-rejected': { + ref: string; + }; + /** + * Interrogating a draft provider endpoint did not produce a model listing: + * no adapter family serves the namespace, the protocol has no listing this + * build can read, or the endpoint was unreachable, refused the credential, + * or answered with something else. The message is the adapter's own text — + * it is what the form shows before falling back to hand-entry — and the + * details name the endpoint asked, never the credential offered. + */ + 'model-discovery-failed': { + settingsNs: string; + baseURL?: string; + }; + 'title-invalid': { + sessionId: SessionId; + }; + 'fork-unavailable': { + sessionId: SessionId; + }; + 'subagent-parent-unavailable': { + parentSessionId: SessionId; + }; + 'subagent-not-found': { + parentSessionId: SessionId; + childSessionId: SessionId; + }; + 'subagent-catalog-diagnostic': { + parentSessionId: SessionId; + childSessionId: SessionId; + reason: 'corrupt' | 'unsupported' | 'unavailable'; + }; + 'subagent-not-resumable': { + childSessionId: SessionId; + }; + 'subagent-unauthorized': { + childSessionId: SessionId; + }; + 'subagent-delivery-unavailable': { + childSessionId: SessionId; + }; + 'internal': {}; +} +/** Closed error-code union (the keys of RpcErrorDetailsMap). */ +export type RpcErrorCode = keyof RpcErrorDetailsMap; +/** + * Distributive union expanded from the map: code is the discriminant, so + * `switch (error.code)` narrows details. details is required (internal uses an explicit {}). + */ +export type RpcError = { + [C in RpcErrorCode]: { + code: C; + message: string; + details: RpcErrorDetailsMap[C]; + }; +}[RpcErrorCode]; +/** Business success/failure result: the result slot of a unary response; methods never throw business errors. */ +export type RpcResult = { + ok: true; + value: T; +} | { + ok: false; + error: RpcError; +}; +/** + * Fold a transport exception into the RpcResult error branch (unified error + * API; 'internal' as the catch-all code). Lives with RpcResult so every + * carrier consumer folds the same way. + * @param error - the thrown value from the carrier. + * @returns the error branch of an RpcResult. + */ +export declare function transportError(error: unknown): RpcResult; +/** + * Signature-layer narrow form, request side (domain-interface view, shared by + * both directions): rpcId is explicit in the signature, never mixed into the + * business payload; the type tag and method are filled in by the carrier layer. + */ +export interface RpcRequest

{ + rpcId: RpcId; + payload: P; +} +/** Signature-layer narrow form, response side: rpcId always echoes the matching request. */ +export interface RpcResponse { + rpcId: RpcId; + result: RpcResult; +} +/** Call initiated by the client (wire carrier: POST /api/ body). */ +export interface ClientRequest { + type: 'client-request'; + rpcId: RpcId; + method: string; + payload: unknown; +} +/** Response to a ClientRequest (wire carrier: the HTTP response body of that POST); rpcId echoed. */ +export interface ServerResponse { + type: 'server-response'; + rpcId: RpcId; + result: RpcResult; +} +/** + * Message initiated by the server (wire carrier: downstream stream frame). Answerable interactions + * (approval/question requested — stable rpcId, reused on replay) and pure pushes + * (session/event etc. — rpcId identifies that one push) share this shape; whether a + * response is expected is determined statically by method (a strict dichotomy, no third kind). + */ +export interface ServerRequest { + type: 'server-request'; + rpcId: RpcId; + method: string; + payload: unknown; +} +/** Response to a ServerRequest (wire carrier: POST /api/respond body); rpcId echoed, never minted anew. */ +export interface ClientResponse { + type: 'client-response'; + rpcId: RpcId; + result: RpcResult; +} +/** Authoritative wire full-form union; narrow via `switch (message.type)`. */ +export type RpcMessage = ClientRequest | ServerResponse | ServerRequest | ClientResponse; +/** + * Carrier receipt (not an RpcMessage — it belongs to the carrier layer, same + * discipline as "HTTP status describes only the carrier"): the HTTP response + * body of the POST carrying a client-response. Late/duplicate responses yield not-pending. + */ +export type RpcReceipt = { + accepted: true; +} | { + accepted: false; + reason: 'not-pending' | 'bad-response'; +}; +export {}; +//# sourceMappingURL=rpc.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.js new file mode 100644 index 0000000..1485a2f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.js @@ -0,0 +1,30 @@ +/** + * Four-quadrant RPC message model. Channels and messages are decoupled: HTTP, + * WebSocket, and in-process SSE are physical carriers, while logical messages + * are channel-independent and form a four-member discriminated union. + * api/ contract layer: zero Node dependencies, importable from the browser. + */ +/** + * Brands a string as RpcId (same precedent as core `SessionId()`). Minted by the initiator: + * client-request → client mints; server-request → host mints (answerable frames get a stable + * logical id, pure pushes mint a fresh one each time). + * @param id - Raw id string (implementations mint UUIDs; tests may pass fixtures). + * @returns The same string, branded (compile-time cast, zero runtime cost). + */ +export function RpcId(id) { + return id; +} +/** + * Fold a transport exception into the RpcResult error branch (unified error + * API; 'internal' as the catch-all code). Lives with RpcResult so every + * carrier consumer folds the same way. + * @param error - the thrown value from the carrier. + * @returns the error branch of an RpcResult. + */ +export function transportError(error) { + return { + ok: false, + error: { code: 'internal', message: error instanceof Error ? error.message : String(error), details: {} }, + }; +} +//# sourceMappingURL=rpc.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.d.ts new file mode 100644 index 0000000..b9a572f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.d.ts @@ -0,0 +1,60 @@ +/** + * Message-layer zod schemas: the four wire full forms + error body + + * carrier receipt. The payload slot is unknown in the full-form schemas — business payloads + * get a second parse dispatched by method (two-level parse discipline). + * Brand cast point: rpcIdSchema, and only there. + */ +import { z } from 'zod'; +import type { ClientRequest, ClientResponse, RpcError, RpcId, ServerRequest, ServerResponse } from './rpc.ts'; +/** + * Wire widening of a contract type: widens every property (deeply) to `original | undefined`. + * The repo enables exactOptionalPropertyTypes while zod `.optional()` outputs `T | undefined`, + * so `satisfies z.ZodType` is unusable across the board; anchoring is always + * written `satisfies z.ZodType>` — the widening only adds undefined, so + * missing fields / wrong types still fail to compile. On the JSON wire, "absent" and + * "value undefined" serialize identically, so the widening loses no validation semantics. + */ +export type Wire = T extends readonly (infer E)[] ? Wire[] : T extends object ? { + [K in keyof T]: Wire | undefined; +} : T; +/** + * RpcId: one brand cast after schema validation (the only cast point in this + * file). No min-length: the id is an opaque echo token, and rejecting values + * here would only turn a correlatable error report into a client-side parse + * failure (the handler substitutes a sentinel when a request's id is unreadable). + */ +export declare const rpcIdSchema: z.ZodType; +/** Error body: discriminated by code, per-branch details aligned to RpcErrorDetailsMap; details is required. */ +export declare const rpcErrorSchema: z.ZodType; +/** + * Business success/failure result schema (generic, reusable). + * @param value - Schema for the business value. + * @returns Schema for RpcResult. + */ +export declare function rpcResultSchema(value: z.ZodType): z.ZodUnion; +/** ClientRequest full form (payload stays wide — the business layer runs the second parse). */ +export declare const clientRequestSchema: z.ZodType; +/** ServerResponse full form (result.value stays wide). */ +export declare const serverResponseSchema: z.ZodType; +/** ServerRequest full form (payload stays wide). */ +export declare const serverRequestSchema: z.ZodType; +/** ClientResponse full form (result.value stays wide). */ +export declare const clientResponseSchema: z.ZodType; +/** Wire full-form union (discriminated by type). */ +export declare const rpcMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject>; +}>, z.core.$strip>, z.ZodObject>; +}>, z.core.$strip>, z.ZodObject>; +}>, z.core.$strip>, z.ZodObject>; +}>, z.core.$strip>], "type">; +/** Carrier receipt schema. */ +export declare const rpcReceiptSchema: z.ZodUnion; +}, z.core.$strip>, z.ZodObject<{ + accepted: z.ZodLiteral; + reason: z.ZodUnion, z.ZodLiteral<"bad-response">]>; +}, z.core.$strip>]>; +//# sourceMappingURL=rpc.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js new file mode 100644 index 0000000..6370f48 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js @@ -0,0 +1,115 @@ +/** + * Message-layer zod schemas: the four wire full forms + error body + + * carrier receipt. The payload slot is unknown in the full-form schemas — business payloads + * get a second parse dispatched by method (two-level parse discipline). + * Brand cast point: rpcIdSchema, and only there. + */ +import { z } from 'zod'; +/** + * RpcId: one brand cast after schema validation (the only cast point in this + * file). No min-length: the id is an opaque echo token, and rejecting values + * here would only turn a correlatable error report into a client-side parse + * failure (the handler substitutes a sentinel when a request's id is unreadable). + */ +export const rpcIdSchema = z.string(); +/** Error body: discriminated by code, per-branch details aligned to RpcErrorDetailsMap; details is required. */ +export const rpcErrorSchema = z.discriminatedUnion('code', [ + z.object({ code: z.literal('bad-request'), message: z.string(), details: z.object({ issues: z.array(z.custom()) }) }), + z.object({ code: z.literal('cancelled'), message: z.string(), details: z.object({}) }), + z.object({ code: z.literal('session-not-found'), message: z.string(), details: z.object({ sessionId: z.string() }) }), + z.object({ code: z.literal('model-unavailable'), message: z.string(), details: z.object({ provider: z.string(), model: z.string() }) }), + z.object({ code: z.literal('session-conflict'), message: z.string(), details: z.object({ sessionId: z.string(), requestedCwd: z.string(), existingCwd: z.string().optional() }) }), + z.object({ code: z.literal('invalid-time-zone'), message: z.string(), details: z.object({ value: z.string() }) }), + z.object({ code: z.literal('workspace-attach-failed'), message: z.string(), details: z.object({ sessionId: z.string(), workspaceId: z.string() }) }), + z.object({ code: z.literal('workspace-not-found'), message: z.string(), details: z.object({ workspaceId: z.string() }) }), + z.object({ code: z.literal('workspace-invalid-path'), message: z.string(), details: z.object({ path: z.string() }) }), + z.object({ code: z.literal('workspace-name-conflict'), message: z.string(), details: z.object({ name: z.string() }) }), + z.object({ code: z.literal('workspace-move-invalid'), message: z.string(), details: z.object({ workspaceId: z.string(), sessionId: z.string(), beforeSessionId: z.string().optional() }) }), + z.object({ code: z.literal('directory-unreadable'), message: z.string(), details: z.object({ path: z.string() }) }), + z.object({ code: z.literal('directory-exists'), message: z.string(), details: z.object({ path: z.string() }) }), + z.object({ code: z.literal('directory-create-failed'), message: z.string(), details: z.object({ path: z.string() }) }), + z.object({ code: z.literal('directory-picker-unavailable'), message: z.string(), details: z.object({ capability: z.string() }) }), + z.object({ code: z.literal('agent-preset-read-only'), message: z.string(), details: z.object({ agentPreset: z.string(), reason: z.string() }) }), + z.object({ code: z.literal('agent-preset-locked'), message: z.string(), details: z.object({ sessionId: z.string(), agentPreset: z.string() }) }), + z.object({ code: z.literal('agent-preset-conflict'), message: z.string(), details: z.object({ sessionId: z.string(), requestedPreset: z.string(), existingPreset: z.string().optional() }) }), + z.object({ code: z.literal('agent-preset-not-found'), message: z.string(), details: z.object({ agentPreset: z.string(), available: z.array(z.string()) }) }), + z.object({ code: z.literal('agent-preset-invalid'), message: z.string(), details: z.object({ agentPreset: z.string(), reason: z.string() }) }), + z.object({ code: z.literal('agent-busy'), message: z.string(), details: z.object({ reason: z.string() }) }), + z.object({ code: z.literal('attachment-error'), message: z.string(), details: z.object({ reason: z.string() }) }), + z.object({ code: z.literal('queue-item-not-found'), message: z.string(), details: z.object({ itemId: z.string() }) }), + z.object({ code: z.literal('steer-unavailable'), message: z.string(), details: z.object({ itemId: z.string() }) }), + z.object({ code: z.literal('command-error'), message: z.string(), details: z.object({}) }), + z.object({ code: z.literal('unknown-command'), message: z.string(), details: z.object({}) }), + z.object({ code: z.literal('settings-rejected'), message: z.string(), details: z.object({ ns: z.string() }) }), + z.object({ code: z.literal('settings-not-exposed'), message: z.string(), details: z.object({ ns: z.string() }) }), + z.object({ code: z.literal('settings-conflict'), message: z.string(), details: z.object({ ns: z.string(), expected: z.number(), actual: z.number() }) }), + z.object({ code: z.literal('credential-rejected'), message: z.string(), details: z.object({ ref: z.string() }) }), + z.object({ code: z.literal('model-discovery-failed'), message: z.string(), details: z.object({ settingsNs: z.string(), baseURL: z.string().optional() }) }), + z.object({ code: z.literal('title-invalid'), message: z.string(), details: z.object({ sessionId: z.string() }) }), + z.object({ code: z.literal('fork-unavailable'), message: z.string(), details: z.object({ sessionId: z.string() }) }), + z.object({ code: z.literal('subagent-parent-unavailable'), message: z.string(), details: z.object({ parentSessionId: z.string() }) }), + z.object({ code: z.literal('subagent-not-found'), message: z.string(), details: z.object({ parentSessionId: z.string(), childSessionId: z.string() }) }), + z.object({ code: z.literal('subagent-catalog-diagnostic'), message: z.string(), details: z.object({ + parentSessionId: z.string(), + childSessionId: z.string(), + reason: z.union([z.literal('corrupt'), z.literal('unsupported'), z.literal('unavailable')]), + }) }), + z.object({ code: z.literal('subagent-not-resumable'), message: z.string(), details: z.object({ childSessionId: z.string() }) }), + z.object({ code: z.literal('subagent-unauthorized'), message: z.string(), details: z.object({ childSessionId: z.string() }) }), + z.object({ code: z.literal('subagent-delivery-unavailable'), message: z.string(), details: z.object({ childSessionId: z.string() }) }), + z.object({ code: z.literal('internal'), message: z.string(), details: z.object({}) }), +]); +/** + * Business success/failure result schema (generic, reusable). + * @param value - Schema for the business value. + * @returns Schema for RpcResult. + */ +export function rpcResultSchema(value) { + return z.union([ + z.object({ ok: z.literal(true), value }), + z.object({ ok: z.literal(false), error: rpcErrorSchema }), + ]); +} +// ---- The four wire full-form schemas (payload/result.value slots stay wide — business layer does the second parse) ---- +// The wide value slot is optional: a void business result serializes with no +// `value` field at all. Each endpoint's own second parse still requires its +// declared value, so absence never passes for a method that returns data. +/** ClientRequest full form (payload stays wide — the business layer runs the second parse). */ +export const clientRequestSchema = z.object({ + type: z.literal('client-request'), + rpcId: rpcIdSchema, + method: z.string(), + payload: z.unknown(), +}); +/** ServerResponse full form (result.value stays wide). */ +export const serverResponseSchema = z.object({ + type: z.literal('server-response'), + rpcId: rpcIdSchema, + result: rpcResultSchema(z.unknown().optional()), +}); +/** ServerRequest full form (payload stays wide). */ +export const serverRequestSchema = z.object({ + type: z.literal('server-request'), + rpcId: rpcIdSchema, + method: z.string(), + payload: z.unknown(), +}); +/** ClientResponse full form (result.value stays wide). */ +export const clientResponseSchema = z.object({ + type: z.literal('client-response'), + rpcId: rpcIdSchema, + result: rpcResultSchema(z.unknown().optional()), +}); +/** Wire full-form union (discriminated by type). */ +export const rpcMessageSchema = z.discriminatedUnion('type', [ + clientRequestSchema, + serverResponseSchema, + serverRequestSchema, + clientResponseSchema, +]); +/** Carrier receipt schema. */ +export const rpcReceiptSchema = z.union([ + z.object({ accepted: z.literal(true) }), + z.object({ accepted: z.literal(false), reason: z.union([z.literal('not-pending'), z.literal('bad-response')]) }), +]); +//# sourceMappingURL=rpc.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.d.ts new file mode 100644 index 0000000..de81826 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.d.ts @@ -0,0 +1,12 @@ +/** Maximum number of sessions returned by one sidebar search. */ +export declare const SESSION_SEARCH_RESULT_LIMIT = 20; +/** Maximum snippet length in Unicode code points. */ +export declare const SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS = 240; +/** + * Return the longest prefix containing at most `maximum` Unicode code points. + * @param value - text to bound. + * @param maximum - non-negative code-point limit. + * @returns `value` unchanged when it fits, otherwise a code-point-safe prefix. + */ +export declare function truncateUnicodeCodePoints(value: string, maximum: number): string; +//# sourceMappingURL=session-search.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js new file mode 100644 index 0000000..14063a3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js @@ -0,0 +1,22 @@ +/** Maximum number of sessions returned by one sidebar search. */ +export const SESSION_SEARCH_RESULT_LIMIT = 20; +/** Maximum snippet length in Unicode code points. */ +export const SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS = 240; +/** + * Return the longest prefix containing at most `maximum` Unicode code points. + * @param value - text to bound. + * @param maximum - non-negative code-point limit. + * @returns `value` unchanged when it fits, otherwise a code-point-safe prefix. + */ +export function truncateUnicodeCodePoints(value, maximum) { + let count = 0; + let end = 0; + for (const codePoint of value) { + if (count === maximum) + return value.slice(0, end); + count++; + end += codePoint.length; + } + return value; +} +//# sourceMappingURL=session-search.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.d.ts new file mode 100644 index 0000000..48132be --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.d.ts @@ -0,0 +1,407 @@ +/** + * sessions domain contract. Method signatures are the source of truth: + * unary methods take the RpcRequest

narrow form and the impl echoes rpcId; everything + * else references RequestPayload<'session.*'> / ResponseValue<'session.*'>. + */ +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { AttachmentIdType, ImageAttachmentLimits, ImageAttachmentRef, ImageMediaType } from '@deepseek-ai/dsh-attachment'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm/types'; +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session/types'; +import type { SessionProjectionMap } from '@deepseek-ai/dsh-session-projection/types'; +import type { RpcId, RpcRequest, RpcResponse } from './rpc.ts'; +import type { ToolEventView } from './events.ts'; +import type { WorkspaceId } from './workspace.ts'; +declare module '@deepseek-ai/dsh-session-projection/types' { + interface SessionProjectionMap { + /** + * Session-list hints persisted by the projection cache. `blank: false` + * is monotonic and may suppress a cold-log probe; `blank: true` is only a + * checkpoint-prefix fact and must not hide a cold Session without direct + * verification. `lastPromptAt` is the latest human-authored prompt time. + */ + sessionListMetadata: SessionListMetadata; + /** + * The deployment's image-intake limits: the attachments service's config + * as this proxy enforces it at prompt admission, constant per host boot. + * Clients pre-check count and bytes at intake and show the limits in + * upload affordances. Key absence means no attachment service is + * composed — clients skip the pre-check and let the host answer. + */ + imageLimits: ImageAttachmentLimits; + } +} +/** Persisted hints used to summarize a cold Session without reading a large log. */ +export interface SessionListMetadata { + /** Whether the checkpoint prefix contains no turn/start event. */ + blank: boolean; + /** Latest source.kind=user message time in the checkpoint prefix. */ + lastPromptAt: number | null; +} +declare module '@deepseek-ai/dsh-llm' { + interface MessageSourceMap { + /** + * The prompt's rpcId is passed through MessageSource into the `user/message` event + * (the client uses it to reconcile the optimistically + * echoed provisional message with the event stream). kind stays `'user'` — the model face + * carries no transport vocabulary; rpcId and the optional Host-validated browser zone are + * durable JSON fields passed back to the client with the event. + */ + 'user-rpc': { + kind: 'user'; + rpcId: RpcId; + clientTimeZone?: string; + }; + } +} +/** + * One history page entry: the raw event plus the optional host-computed render + * intent (same semantics as the mux frame's `view` slot — a pagination-time + * derivation, never persisted). + */ +export interface HistoryEntry { + event: SessionEvent; + view?: ToolEventView; +} +/** + * The projection baseline riding the history tail page: one synchronous cut + * over every registered projection unit, read from the registry's watermark + * cache. `asOfSeq` is the seq of the last committed event every value + * reflects — the window tail event seq (`-1` for an empty log, mirroring + * `session/subscribed.lastSeq`), directly comparable with + * `session/projection` frame seqs under the client's higher-seq-wins rule. A + * key absent from `values` means the capability is absent (its domain plugin + * is unmounted). + */ +export interface SessionProjectionsBlock { + /** Seq of the last event the values reflect; -1 for an empty log. */ + asOfSeq: number; + /** Whole current value per registered projection key. */ + values: Partial; +} +/** Browser-submitted prompt content; the host promotes image bytes to durable references. */ +export type PromptContentPart = { + type: 'text'; + text: string; +} | { + type: 'image'; + mediaType: ImageMediaType; + data: string; + name?: string; +}; +/** Complete model selection for one session. */ +export interface ModelSelection { + /** Registered provider route. */ + provider: string; + /** Provider-owned model id. */ + model: string; + /** Adapter-owned reasoning effort; absence preserves adapter/provider default behavior. */ + reasoningEffort?: string; +} +/** One adapter-owned reasoning effort displayed for an exact model route. */ +export interface ModelReasoningEffort { + /** Opaque value submitted back to the owning adapter. */ + id: string; + /** Adapter-supplied display name. */ + name: string; + /** Optional adapter-supplied description. */ + description?: string; +} +/** Selectable reasoning metadata for one exact model route. */ +export interface ModelReasoning { + /** Efforts in adapter-preferred display order. */ + efforts: ModelReasoningEffort[]; + /** Adapter-configured default; absence preserves the provider default. */ + defaultEffort?: string; +} +/** One model displayed inside its provider group. */ +export interface ModelCatalogModel { + /** Provider-owned model id. */ + id: string; + /** Provider-supplied display name. */ + name: string; + /** Optional provider-supplied description. */ + description?: string; + /** Exact-route reasoning metadata when the adapter exposes it. */ + reasoning?: ModelReasoning; +} +/** One provider and the models it advertised successfully. */ +export interface ModelProviderGroup { + /** Provider route id used for requests. */ + id: string; + /** Provider display name. */ + name: string; + /** Models in provider-preferred order. */ + models: ModelCatalogModel[]; +} +/** A provider whose asynchronous catalog lookup failed. */ +export interface ModelCatalogFailure { + /** Provider route id. */ + id: string; + /** Provider display name. */ + name: string; + /** Lookup failure diagnostic. */ + message: string; +} +/** Detached model-directory snapshot for one session. */ +export interface SessionModels { + /** Model selection for the session's next assembled step. */ + current: ModelSelection; + /** + * Whether an adapter currently serves `current.provider`, and therefore + * whether this session can start a turn at all. Deliberately NOT derivable + * from `groups`: catalog membership is advisory, so a route serving a model + * it stopped advertising is absent from the groups yet perfectly usable, + * while a route whose adapter is gone can serve nothing. A surface that + * blocks input must read this rather than the groups. + */ + routable: boolean; + /** Successfully loaded provider groups. */ + groups: ModelProviderGroup[]; + /** Provider-local failures; successful groups remain usable. */ + failures: ModelCatalogFailure[]; +} +/** A client-requested mutation of one still-pending queue item. */ +export type QueueAction = { + kind: 'edit'; + content: ContentBlock[]; +} | { + kind: 'remove'; +} | { + kind: 'steer'; +}; +/** One Session list entry. */ +export interface SessionSummary { + sessionId: SessionId; + /** + * The later of creation and the latest human-authored prompt. Attached + * Sessions fold their live log; cold Sessions use a projection-cache hint or + * an exact small-artifact read, falling back to creation time. + */ + updatedAt: number; + /** Status of the attached agent; always false for cold (unattached) sessions. */ + running: boolean; + /** + * Derived conversation-not-started bit: true while no turn has run. + * Standalone plugin events — command lifecycle + * records, plan/mode, titles, goals — do not open a turn and therefore do + * not clear it. Clients hide blank Sessions from lists and reuse them for + * New Session on the same workspace. A cold Session is true only when a + * small-artifact read verifies that no `turn/start` exists; unavailable + * or oversized artifacts conservatively report false. + */ + blank: boolean; + /** fork/spawn lineage (session.header.parentSession passthrough); absent for root sessions. */ + parentSessionId?: SessionId; + /** Coarse durable origin used by navigation surfaces; never proves resumability. */ + origin?: 'subagent'; + /** Session working directory (header.cwd passthrough); absent when unrecorded. */ + cwd?: string; + /** + * Agent preset this session's agent was composed from (header passthrough); + * absent when the deployment composes no presets. A surface offering a + * switch reads this to show what the session actually runs rather than what + * the deployment currently defaults to. + */ + agentPreset?: string; + /** + * Projection baseline for this row, with zero log loads: attached sessions + * read the registry's live watermark cut; cold sessions read the persisted + * projection cache's stored rows — as stale as that session's last durable + * checkpoint (`asOfSeq` says exactly how stale), never wrong, and directly + * seedable into the client's per-session value store under its + * higher-seq-wins rule (a list baseline can never overwrite a newer push + * frame). Absent when no value is available (no registry, no cache row for + * a cold session, or a fail-soft cache read miss); a listing client treats + * absence as "no title yet", exactly like a blank session. + */ + projections?: SessionProjectionsBlock; +} +/** One session-content search result; display metadata stays owned by `session.list`. */ +export interface SessionSearchItem { + sessionId: SessionId; + /** Plain-text excerpt around the strongest matching visible message. */ + snippet: string; +} +/** Session-domain unary methods (the map keys session.* of RpcMethodMap). */ +export interface SessionsApi { + /** Lists persisted sessions (updatedAt descending). v1 returns everything; cursor is a reserved seat, unimplemented. */ + list(request: RpcRequest<{ + cursor?: string; + }>): Promise>; + /** + * Searches the current user/assistant/steering message surface across + * sessions visible to `list`. Results contain at most 20 sessions and carry + * no continuation cursor; `hasMore` asks the client to refine the query. + */ + search(request: RpcRequest<{ + query: string; + }>, signal: AbortSignal): Promise>; + /** + * Creates a real session and its idle agent. At most one of `workspaceId` / + * `cwd` is accepted; an omitted project uses the Host cwd. A caller may + * preallocate `sessionId`: retries with the same id and cwd return the same + * session, while a different cwd fails with `session-conflict`. Workspace + * creation attaches the session after publication; an attach failure + * returns `workspace-attach-failed` with the published session id. + * + * `agentPreset` names the composition the new session's agent is built + * from; omitted, the effective default applies — the user's stored choice + * where one exists, else the deployment's own. The resolved id is stored on + * the session header, so a later resume rebuilds the same agent. An unknown + * id fails with `agent-preset-not-found`, and a preset whose composition + * cannot be mounted fails with `agent-preset-invalid`. + */ + create(request: RpcRequest<{ + workspaceId?: WorkspaceId; + cwd?: string; + sessionId?: SessionId; + agentPreset?: string; + }>): Promise>; + /** + * Reads a window of history events; page boundaries align to append-origin message + * boundaries: one page = all raw events owned by a whole number of such messages (including + * their chunk / tool events), never cut mid-message. Model-only replacement copies consume no + * `maxMessages`, so a compaction's `compaction/summary` record stays on the page of its replacement. The tail + * page (beforeSeq absent) additionally carries the in-flight + * partial — chunk events already emitted for the last unfinalized message. + * Each entry pairs the raw SessionEvent with the host-computed view (tool events whose + * presenter produced one, evaluated against the registry at pagination time); the client + * rebuilds the surface from the events with the shared fold. + * The tail page — and only the tail page — additionally carries `projections` + * when the deployment mounts the session-projection registry: every moment + * the client needs a fresh baseline already pulls the tail page, and + * loadOlder (the only beforeSeq path) is the only path that never needs one. + * A deployment without the registry serves histories without the block. + * Reading history uses an attached Session or persistence inspection and + * never resumes or publishes an Agent. + */ + history(request: RpcRequest<{ + sessionId: SessionId; + beforeSeq?: number; + maxMessages?: number; + }>): Promise>; + /** + * Reads a fresh advisory model directory for an ordinary session. Provider + * lookups run independently; subagents reject with `agent-busy`. + */ + models(request: RpcRequest<{ + sessionId: SessionId; + }>): Promise>; + /** + * Selects the complete model selection for this session. Exact model metadata + * validates an optional reasoning effort, while catalog membership remains + * advisory. Session-backed subagents reject with `agent-busy`. + */ + selectModel(request: RpcRequest<{ + sessionId: SessionId; + provider: string; + model: string; + reasoningEffort?: string; + }>): Promise>; + /** + * Renames a session: appends a `session/title` event with the `user` + * source, which pins the title against automatic regeneration. The + * normalized accepted title and the title event's seq return so the caller + * can settle its projection cell without waiting for the push frame. A + * title that normalizes to empty fails with `title-invalid`. + * Session-backed subagents reject with `agent-busy`. + */ + rename(request: RpcRequest<{ + sessionId: SessionId; + title: string; + }>): Promise>; + /** + * Sends a message. content is core's ContentBlock[] verbatim; mode maps 1:1 — queue→send, steer→steer. + * A prompt whose content is exactly one text block starting with '/' is a slash command: the host + * executes it through the command registry (mode-agnostic) and it is never sent to the model. A + * successful command returns ok with the command slot (its success text, when the command produced + * one — carried for future rendering; the state change is the feedback). A usage/state error is an + * RPC error with code command-error; an unrecognized name is an RPC error with code unknown-command. + */ + /** + * Forks a new session from a completed-turn prefix of the source. `atSeq` + * anchors the cut: the boundary is the first `turn/end` at or after it + * (a message's fork button passes the message seq, so the fork includes + * that whole turn); a boundary past the log end, or an omitted `atSeq`, + * falls back to the source's last completed turn. An in-log anchor whose + * turn is still open fails with `fork-unavailable` instead of clipping to + * an earlier turn. The child inherits the source cwd, latest logged model + * target and `parentSessionId` lineage; the seed prefix carries the source + * title. Reading the source uses attached state or persistence inspection + * without acquiring an Agent. Workspace attachment follows the source + * directly, or the nearest workspace-owning ancestor when the source is a + * subagent. + */ + fork(request: RpcRequest<{ + sessionId: SessionId; + atSeq?: number; + }>): Promise>; + /** + * Sends text and temporary image bytes to an ordinary session Agent after durable host admission. + * Browser callers attach their current IANA zone; + * the Host validates, canonicalizes, and records it on that exact user message. Omission remains + * valid for non-browser callers. Session-backed subagents reject with `agent-busy` and use + * `subagent.prompt`. + */ + prompt(request: RpcRequest<{ + sessionId: SessionId; + mode: 'queue' | 'steer'; + content: PromptContentPart[]; + clientTimeZone?: string; + }>): Promise>; + /** Reads one durable image after proving that this session's log references its id. */ + attachment(request: RpcRequest<{ + sessionId: SessionId; + attachmentId: AttachmentIdType; + }>): Promise>; + /** + * Edits, removes, or strictly steers one pending queued occurrence on an ordinary session. + * Session-backed subagents reject with `agent-busy`. + */ + updateQueue(request: RpcRequest<{ + sessionId: SessionId; + itemId: MessageId; + action: QueueAction; + }>): Promise>; + /** + * Stops an ordinary session's active turn, preserving pending inbox work + * that resumes in FIFO order after cancellation settles. Session-backed + * subagents reject with `agent-busy`. + */ + cancel(request: RpcRequest<{ + sessionId: SessionId; + }>): Promise>; +} +//# sourceMappingURL=sessions.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.js new file mode 100644 index 0000000..41e4489 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.js @@ -0,0 +1,7 @@ +/** + * sessions domain contract. Method signatures are the source of truth: + * unary methods take the RpcRequest

narrow form and the impl echoes rpcId; everything + * else references RequestPayload<'session.*'> / ResponseValue<'session.*'>. + */ +export {}; +//# sourceMappingURL=sessions.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.d.ts new file mode 100644 index 0000000..f638b0d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.d.ts @@ -0,0 +1,279 @@ +/** + * sessions domain zod schemas (names derived from map keys: sessionListRequestSchema / + * sessionListValueSchema). SessionEvent passthrough = strict envelope (type/seq/time) + wide + * data: the merge-extensible event API keeps an unknown-type branch at the union level, + * with no field-level passthrough. SessionId brand cast point: sessionIdSchema, and only there. + */ +import { z } from 'zod'; +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session/types'; +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { RequestPayload, ResponseValue } from './rpc-map.ts'; +import type { Wire } from './rpc.schema.ts'; +import type { HistoryEntry, SessionListMetadata, SessionProjectionsBlock, SessionSummary } from './sessions.ts'; +import type { ToolEventView } from './events.ts'; +import type { AttachmentIdType, ImageAttachmentLimits, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'; +import type { WorkspaceId } from './workspace.ts'; +/** SessionId: one brand cast after schema validation (the only cast point in this domain). */ +export declare const sessionIdSchema: z.ZodType; +/** MessageId: one brand cast after non-empty string validation. */ +export declare const messageIdSchema: z.ZodType; +/** + * WorkspaceId: the workspace domain's one brand cast. Hosted here rather + * than in workspace.schema because session.create references it while + * workspace.schema references sessionIdSchema — schema modules must stay a + * DAG (both casts used at module top level; a cycle is a load-time TDZ). + */ +export declare const workspaceIdSchema: z.ZodType; +/** SessionEvent passthrough: strict envelope, wide data (the client fold handles unknown types via its documented default). */ +export declare const sessionEventSchema: z.ZodType; +/** SessionSummary row of session.list (`projections` reuses the history block's shape and schema). */ +export declare const sessionSummarySchema: z.ZodType>; +/** session.list request payload (cursor is a reserved seat, unimplemented in v1). */ +export declare const sessionListRequestSchema: z.ZodObject<{ + cursor: z.ZodOptional; +}, z.core.$strip>; +/** session.list response value. */ +export declare const sessionListValueSchema: z.ZodType>>; +/** session.search request payload. */ +export declare const sessionSearchRequestSchema: z.ZodObject<{ + query: z.ZodString; +}, z.core.$strip>; +/** One session.search result. */ +export declare const sessionSearchItemSchema: z.ZodObject<{ + sessionId: z.ZodType>; + snippet: z.ZodString; +}, z.core.$strip>; +/** session.search response value. */ +export declare const sessionSearchValueSchema: z.ZodObject<{ + items: z.ZodArray>; + snippet: z.ZodString; + }, z.core.$strip>>; + hasMore: z.ZodBoolean; +}, z.core.$strip>; +/** session.create request payload (at most one of workspaceId / cwd). */ +export declare const sessionCreateRequestSchema: z.ZodObject<{ + workspaceId: z.ZodOptional>>; + cwd: z.ZodOptional; + sessionId: z.ZodOptional>>; + agentPreset: z.ZodOptional; +}, z.core.$strip>; +/** session.create response value. */ +export declare const sessionCreateValueSchema: z.ZodObject<{ + sessionId: z.ZodType>; + agentPreset: z.ZodOptional; +}, z.core.$strip>; +/** session.rename request payload (raw title; host-side normalization decides acceptance). */ +export declare const sessionRenameRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + title: z.ZodString; +}, z.core.$strip>; +/** session.rename response value (the normalized accepted title and its event seq). */ +export declare const sessionRenameValueSchema: z.ZodObject<{ + title: z.ZodString; + seq: z.ZodNumber; +}, z.core.$strip>; +/** session.fork request payload (atSeq anchors the completed-turn cut). */ +export declare const sessionForkRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + atSeq: z.ZodOptional; +}, z.core.$strip>; +/** session.fork response value (the child session id). */ +export declare const sessionForkValueSchema: z.ZodObject<{ + sessionId: z.ZodType>; +}, z.core.$strip>; +/** session.history request payload (beforeSeq/maxMessages page backwards from the window tail). */ +export declare const sessionHistoryRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + beforeSeq: z.ZodOptional; + maxMessages: z.ZodOptional; +}, z.core.$strip>; +/** Complete provider/model selection. */ +export declare const modelSelectionSchema: z.ZodObject<{ + provider: z.ZodString; + model: z.ZodString; + reasoningEffort: z.ZodOptional; +}, z.core.$strip>; +/** One adapter-owned reasoning effort. */ +export declare const modelReasoningEffortSchema: z.ZodObject<{ + id: z.ZodString; + name: z.ZodString; + description: z.ZodOptional; +}, z.core.$strip>; +/** Exact-model reasoning metadata. */ +export declare const modelReasoningSchema: z.ZodObject<{ + efforts: z.ZodArray; + }, z.core.$strip>>; + defaultEffort: z.ZodOptional; +}, z.core.$strip>; +/** One advisory model entry inside a provider group. */ +export declare const modelCatalogModelSchema: z.ZodObject<{ + id: z.ZodString; + name: z.ZodString; + description: z.ZodOptional; + reasoning: z.ZodOptional; + }, z.core.$strip>>; + defaultEffort: z.ZodOptional; + }, z.core.$strip>>; +}, z.core.$strip>; +/** One successfully loaded provider group. */ +export declare const modelProviderGroupSchema: z.ZodObject<{ + id: z.ZodString; + name: z.ZodString; + models: z.ZodArray; + reasoning: z.ZodOptional; + }, z.core.$strip>>; + defaultEffort: z.ZodOptional; + }, z.core.$strip>>; + }, z.core.$strip>>; +}, z.core.$strip>; +/** One provider-local catalog failure. */ +export declare const modelCatalogFailureSchema: z.ZodObject<{ + id: z.ZodString; + name: z.ZodString; + message: z.ZodString; +}, z.core.$strip>; +/** + * ToolEventView passthrough: lock only the `for` discriminant and the presence + * of a card-tagged `view` object. The view interior is a host-computed product + * the client reads without echoing back; deep-validating it would hand-copy + * the dsh-tools vocabulary into this schema and drift with it. + */ +export declare const toolEventViewSchema: z.ZodType; +/** One session.history item: the session event plus its optional host-computed tool view. */ +export declare const historyEntrySchema: z.ZodType>; +/** + * Projection baseline passthrough: `values` stays a wide record — each value + * was already parsed by its provider's own schema on the host side, and + * deep-validating here would import every domain's schema into the carrier. + */ +export declare const sessionProjectionsBlockSchema: z.ZodType>; +/** Host-side validation for the persisted Session-list projection. */ +export declare const sessionListMetadataProjectionSchema: z.ZodType; +/** + * imageLimits projection unit schema (host-side view validation). zod widens + * `readonly ImageMediaType[]` to `string[]`; on the JSON wire the two + * serialize identically, so the cast records exactly that widening. + */ +export declare const imageLimitsProjectionSchema: z.ZodType; +/** session.history response value (projections rides the tail page only). */ +export declare const sessionHistoryValueSchema: z.ZodType>>; +/** session.models request payload. */ +export declare const sessionModelsRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; +}, z.core.$strip>; +/** session.models response value. */ +export declare const sessionModelsValueSchema: z.ZodObject<{ + current: z.ZodObject<{ + provider: z.ZodString; + model: z.ZodString; + reasoningEffort: z.ZodOptional; + }, z.core.$strip>; + routable: z.ZodBoolean; + groups: z.ZodArray; + reasoning: z.ZodOptional; + }, z.core.$strip>>; + defaultEffort: z.ZodOptional; + }, z.core.$strip>>; + }, z.core.$strip>>; + }, z.core.$strip>>; + failures: z.ZodArray>; +}, z.core.$strip>; +/** session.selectModel request payload. */ +export declare const sessionSelectModelRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + provider: z.ZodString; + model: z.ZodString; + reasoningEffort: z.ZodOptional; +}, z.core.$strip>; +/** session.selectModel response value. */ +export declare const sessionSelectModelValueSchema: z.ZodObject<{ + selected: z.ZodObject<{ + provider: z.ZodString; + model: z.ZodString; + reasoningEffort: z.ZodOptional; + }, z.core.$strip>; +}, z.core.$strip>; +/** ContentBlock passthrough: core is merge-extensible — the type discriminant envelope is strict, the rest stays wide. */ +export declare const contentBlockSchema: z.ZodObject<{ + type: z.ZodString; +}, z.core.$loose>; +/** Raster image media types accepted by the version-one browser wire. */ +export declare const imageMediaTypeSchema: z.ZodUnion, z.ZodLiteral<"image/jpeg">, z.ZodLiteral<"image/webp">, z.ZodLiteral<"image/gif">]>; +/** Prompt wire content is intentionally narrower than merge-extensible durable core content. */ +export declare const promptContentPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{ + type: z.ZodLiteral<"text">; + text: z.ZodString; +}, z.core.$strip>, z.ZodObject<{ + type: z.ZodLiteral<"image">; + mediaType: z.ZodUnion, z.ZodLiteral<"image/jpeg">, z.ZodLiteral<"image/webp">, z.ZodLiteral<"image/gif">]>; + data: z.ZodString; + name: z.ZodOptional; +}, z.core.$strip>], "type">; +/** session.prompt request payload, including optional browser-local request provenance. */ +export declare const sessionPromptRequestSchema: z.ZodType>; +/** session.prompt response value (the command slot appears only when the prompt dispatched a slash command). */ +export declare const sessionPromptValueSchema: z.ZodObject<{ + accepted: z.ZodLiteral; + command: z.ZodOptional; + text: z.ZodOptional; + }, z.core.$strip>>; +}, z.core.$strip>; +/** Opaque attachment id after string-shape validation. */ +export declare const attachmentIdSchema: z.ZodType; +/** Durable image reference returned from the authenticated session lookup. */ +export declare const imageAttachmentRefSchema: z.ZodType; +/** session.attachment request payload. */ +export declare const sessionAttachmentRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + attachmentId: z.ZodType>; +}, z.core.$strip>; +/** session.attachment response value. */ +export declare const sessionAttachmentValueSchema: z.ZodObject<{ + attachment: z.ZodType>; + data: z.ZodString; +}, z.core.$strip>; +/** session.updateQueue request payload. */ +export declare const sessionUpdateQueueRequestSchema: z.ZodType>; +/** session.updateQueue response value. */ +export declare const sessionUpdateQueueValueSchema: z.ZodObject<{ + accepted: z.ZodLiteral; +}, z.core.$strip>; +/** session.cancel request payload. */ +export declare const sessionCancelRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; +}, z.core.$strip>; +/** session.cancel response value. */ +export declare const sessionCancelValueSchema: z.ZodObject<{ + accepted: z.ZodLiteral; +}, z.core.$strip>; +//# sourceMappingURL=sessions.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js new file mode 100644 index 0000000..026ffb3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js @@ -0,0 +1,282 @@ +/** + * sessions domain zod schemas (names derived from map keys: sessionListRequestSchema / + * sessionListValueSchema). SessionEvent passthrough = strict envelope (type/seq/time) + wide + * data: the merge-extensible event API keeps an unknown-type branch at the union level, + * with no field-level passthrough. SessionId brand cast point: sessionIdSchema, and only there. + */ +import { z } from 'zod'; +import { SESSION_SEARCH_RESULT_LIMIT, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS, truncateUnicodeCodePoints, } from "./session-search.js"; +/** SessionId: one brand cast after schema validation (the only cast point in this domain). */ +export const sessionIdSchema = z.string().min(1); +/** MessageId: one brand cast after non-empty string validation. */ +export const messageIdSchema = z.string().min(1); +/** + * WorkspaceId: the workspace domain's one brand cast. Hosted here rather + * than in workspace.schema because session.create references it while + * workspace.schema references sessionIdSchema — schema modules must stay a + * DAG (both casts used at module top level; a cycle is a load-time TDZ). + */ +export const workspaceIdSchema = z.string().min(1); +/** SessionEvent passthrough: strict envelope, wide data (the client fold handles unknown types via its documented default). */ +export const sessionEventSchema = z.object({ + type: z.string(), + seq: z.number().int().nonnegative(), + time: z.number(), + data: z.unknown(), + sourceEventSeqs: z.array(z.number()).optional(), + surfaceOp: z.unknown().optional(), + ignorable: z.literal(true).optional(), +}); +/** SessionSummary row of session.list (`projections` reuses the history block's shape and schema). */ +export const sessionSummarySchema = z.object({ + sessionId: sessionIdSchema, + updatedAt: z.number(), + running: z.boolean(), + blank: z.boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: z.literal('subagent').optional(), + cwd: z.string().optional(), + agentPreset: z.string().optional(), + projections: z.lazy(() => sessionProjectionsBlockSchema).optional(), +}); +/** session.list request payload (cursor is a reserved seat, unimplemented in v1). */ +export const sessionListRequestSchema = z.object({ + cursor: z.string().optional(), +}); +/** session.list response value. */ +export const sessionListValueSchema = z.object({ + items: z.array(sessionSummarySchema), +}); +/** Fixed wire bound for one interactive sidebar query. */ +const SESSION_SEARCH_QUERY_MAX_CHARS = 500; +/** session.search request payload. */ +export const sessionSearchRequestSchema = z.object({ + query: z.string().trim().min(1).max(SESSION_SEARCH_QUERY_MAX_CHARS) + .refine(query => !query.includes('\0'), { message: 'search query must not contain NUL' }), +}); +/** One session.search result. */ +export const sessionSearchItemSchema = z.object({ + sessionId: sessionIdSchema, + snippet: z.string().refine(snippet => truncateUnicodeCodePoints(snippet, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS) === snippet, { message: `search snippet must contain at most ${SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS} Unicode code points` }), +}); +/** session.search response value. */ +export const sessionSearchValueSchema = z.object({ + items: z.array(sessionSearchItemSchema).max(SESSION_SEARCH_RESULT_LIMIT), + hasMore: z.boolean(), +}); +/** session.create request payload (at most one of workspaceId / cwd). */ +export const sessionCreateRequestSchema = z.object({ + workspaceId: workspaceIdSchema.optional(), + cwd: z.string().optional(), + sessionId: sessionIdSchema.optional(), + agentPreset: z.string().optional(), +}).refine(payload => payload.workspaceId === undefined || payload.cwd === undefined, { message: 'session.create accepts workspaceId or cwd, not both' }); +/** session.create response value. */ +export const sessionCreateValueSchema = z.object({ + sessionId: sessionIdSchema, + agentPreset: z.string().optional(), +}); +/** session.rename request payload (raw title; host-side normalization decides acceptance). */ +export const sessionRenameRequestSchema = z.object({ + sessionId: sessionIdSchema, + title: z.string(), +}); +/** session.rename response value (the normalized accepted title and its event seq). */ +export const sessionRenameValueSchema = z.object({ + title: z.string().min(1), + seq: z.number().int().nonnegative(), +}); +/** session.fork request payload (atSeq anchors the completed-turn cut). */ +export const sessionForkRequestSchema = z.object({ + sessionId: sessionIdSchema, + atSeq: z.number().int().nonnegative().optional(), +}); +/** session.fork response value (the child session id). */ +export const sessionForkValueSchema = z.object({ + sessionId: sessionIdSchema, +}); +/** session.history request payload (beforeSeq/maxMessages page backwards from the window tail). */ +export const sessionHistoryRequestSchema = z.object({ + sessionId: sessionIdSchema, + beforeSeq: z.number().int().nonnegative().optional(), + maxMessages: z.number().int().positive().optional(), +}); +/** Complete provider/model selection. */ +export const modelSelectionSchema = z.object({ + provider: z.string().min(1), + model: z.string().min(1), + reasoningEffort: z.string().min(1).optional(), +}); +/** One adapter-owned reasoning effort. */ +export const modelReasoningEffortSchema = z.object({ + id: z.string().min(1), + name: z.string().min(1), + description: z.string().optional(), +}); +/** Exact-model reasoning metadata. */ +export const modelReasoningSchema = z.object({ + efforts: z.array(modelReasoningEffortSchema).min(1), + defaultEffort: z.string().min(1).optional(), +}); +/** One advisory model entry inside a provider group. */ +export const modelCatalogModelSchema = z.object({ + id: z.string().min(1), + name: z.string().min(1), + description: z.string().optional(), + reasoning: modelReasoningSchema.optional(), +}); +/** One successfully loaded provider group. */ +export const modelProviderGroupSchema = z.object({ + id: z.string().min(1), + name: z.string().min(1), + models: z.array(modelCatalogModelSchema), +}); +/** One provider-local catalog failure. */ +export const modelCatalogFailureSchema = z.object({ + id: z.string().min(1), + name: z.string().min(1), + message: z.string(), +}); +/** + * ToolEventView passthrough: lock only the `for` discriminant and the presence + * of a card-tagged `view` object. The view interior is a host-computed product + * the client reads without echoing back; deep-validating it would hand-copy + * the dsh-tools vocabulary into this schema and drift with it. + */ +export const toolEventViewSchema = z.discriminatedUnion('for', [ + z.object({ for: z.literal('call'), view: z.looseObject({ card: z.string() }) }), + z.object({ for: z.literal('result'), view: z.looseObject({ card: z.string() }) }), +]); +/** One session.history item: the session event plus its optional host-computed tool view. */ +export const historyEntrySchema = z.object({ + event: sessionEventSchema, + view: toolEventViewSchema.optional(), +}); +/** + * Projection baseline passthrough: `values` stays a wide record — each value + * was already parsed by its provider's own schema on the host side, and + * deep-validating here would import every domain's schema into the carrier. + */ +export const sessionProjectionsBlockSchema = z.object({ + // -1 = empty log (the lastSeq convention of session/subscribed). + asOfSeq: z.number().int().min(-1), + values: z.record(z.string(), z.unknown()), +}); +/** Host-side validation for the persisted Session-list projection. */ +export const sessionListMetadataProjectionSchema = z.object({ + blank: z.boolean(), + lastPromptAt: z.number().nullable(), +}); +/** + * imageLimits projection unit schema (host-side view validation). zod widens + * `readonly ImageMediaType[]` to `string[]`; on the JSON wire the two + * serialize identically, so the cast records exactly that widening. + */ +export const imageLimitsProjectionSchema = z.object({ + maxImageBytes: z.number().int().positive(), + maxImagesPerMessage: z.number().int().positive(), + maxMessageImageBytes: z.number().int().positive(), + maxImagePixels: z.number().int().positive(), + mediaTypes: z.array(z.string()), +}); +/** session.history response value (projections rides the tail page only). */ +export const sessionHistoryValueSchema = z.object({ + events: z.array(historyEntrySchema), + hasMore: z.boolean(), + projections: sessionProjectionsBlockSchema.optional(), +}); +/** session.models request payload. */ +export const sessionModelsRequestSchema = z.object({ + sessionId: sessionIdSchema, +}); +/** session.models response value. */ +export const sessionModelsValueSchema = z.object({ + current: modelSelectionSchema, + routable: z.boolean(), + groups: z.array(modelProviderGroupSchema), + failures: z.array(modelCatalogFailureSchema), +}); +/** session.selectModel request payload. */ +export const sessionSelectModelRequestSchema = z.object({ + sessionId: sessionIdSchema, + provider: z.string().min(1), + model: z.string().min(1), + reasoningEffort: z.string().min(1).optional(), +}); +/** session.selectModel response value. */ +export const sessionSelectModelValueSchema = z.object({ + selected: modelSelectionSchema, +}); +/** ContentBlock passthrough: core is merge-extensible — the type discriminant envelope is strict, the rest stays wide. */ +export const contentBlockSchema = z.looseObject({ type: z.string() }); +/** Raster image media types accepted by the version-one browser wire. */ +export const imageMediaTypeSchema = z.union([ + z.literal('image/png'), + z.literal('image/jpeg'), + z.literal('image/webp'), + z.literal('image/gif'), +]); +/** Prompt wire content is intentionally narrower than merge-extensible durable core content. */ +export const promptContentPartSchema = z.discriminatedUnion('type', [ + z.object({ type: z.literal('text'), text: z.string() }), + z.object({ type: z.literal('image'), mediaType: imageMediaTypeSchema, data: z.string(), name: z.string().optional() }), +]); +/** session.prompt request payload, including optional browser-local request provenance. */ +export const sessionPromptRequestSchema = z.object({ + sessionId: sessionIdSchema, + mode: z.union([z.literal('queue'), z.literal('steer')]), + content: z.array(promptContentPartSchema), + clientTimeZone: z.string().optional(), +}); +/** session.prompt response value (the command slot appears only when the prompt dispatched a slash command). */ +export const sessionPromptValueSchema = z.object({ + accepted: z.literal(true), + command: z.object({ + kind: z.literal('success'), + text: z.string().optional(), + }).optional(), +}); +/** Opaque attachment id after string-shape validation. */ +export const attachmentIdSchema = z.string().min(1); +/** Durable image reference returned from the authenticated session lookup. */ +export const imageAttachmentRefSchema = z.object({ + attachmentId: attachmentIdSchema, + mediaType: imageMediaTypeSchema, + bytes: z.number().int().positive(), + width: z.number().int().positive(), + height: z.number().int().positive(), + name: z.string().optional(), +}); +/** session.attachment request payload. */ +export const sessionAttachmentRequestSchema = z.object({ + sessionId: sessionIdSchema, + attachmentId: attachmentIdSchema, +}); +/** session.attachment response value. */ +export const sessionAttachmentValueSchema = z.object({ + attachment: imageAttachmentRefSchema, + data: z.string(), +}); +/** session.updateQueue request payload. */ +export const sessionUpdateQueueRequestSchema = z.object({ + sessionId: sessionIdSchema, + itemId: messageIdSchema, + action: z.discriminatedUnion('kind', [ + z.object({ kind: z.literal('edit'), content: z.array(contentBlockSchema) }), + z.object({ kind: z.literal('remove') }), + z.object({ kind: z.literal('steer') }), + ]), +}); +/** session.updateQueue response value. */ +export const sessionUpdateQueueValueSchema = z.object({ + accepted: z.literal(true), +}); +/** session.cancel request payload. */ +export const sessionCancelRequestSchema = z.object({ + sessionId: sessionIdSchema, +}); +/** session.cancel response value. */ +export const sessionCancelValueSchema = z.object({ + accepted: z.literal(true), +}); +//# sourceMappingURL=sessions.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.d.ts new file mode 100644 index 0000000..c9a56c5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.d.ts @@ -0,0 +1,113 @@ +/** + * settings domain contract: the web face of the user-settings seam + * (`ctx.settings`). Every payload that leaves this domain is redacted by the + * seam (`describe({ redactSecrets: true })` semantics): `role('secret')` + * fields never ride a response in any layer, and the `secrets` slot list is + * how a form learns a write-only field exists and whether it is configured. + */ +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** One schema-declared secret slot inside a redacted namespace value. */ +export interface SettingsSecretView { + /** Path from the section root to the removed field. */ + path: string[]; + /** Whether the slot currently holds a value (the value itself never rides). */ + set: boolean; +} +/** Wire view of one registered settings namespace. */ +export interface SettingsNamespaceView { + /** Namespace key (`llm-deepseek`, `llm-pi-ai`, …). */ + ns: string; + /** Serialized schemastery schema envelope (`schema.toJSON()`); rehydrate with `new Schema(json)`. */ + schema: unknown; + /** Redacted resolved value (schema defaults → composition base → user layer). */ + value: unknown; + /** Redacted composition base layer, when the registrant declared one. */ + base?: unknown; + /** Redacted raw user section, when one exists; a field's presence here marks it user-overridden. */ + user?: unknown; + /** When the owner applies changes. */ + applies: 'live' | 'restart'; + /** Every schema-declared secret slot with its configured state. */ + secrets: SettingsSecretView[]; + /** + * Monotonic revision of the raw user section this view was read at. Send it + * back as `expectedRevision` on a write so a stale editor is refused rather + * than silently overwriting a concurrent change. + */ + revision: number; +} +/** + * One path-addressed edit carried by `settings.mutate`. `set` writes the + * value at the path (creating intermediate objects); `unset` removes it. The + * empty path addresses the section root. + */ +export type SettingsPathOpView = { + op: 'set'; + path: string[]; + value: unknown; +} | { + op: 'unset'; + path: string[]; +}; +/** Settings-domain unary methods (the map keys settings.* of RpcMethodMap). */ +export interface SettingsApi { + /** + * Describe every registered namespace: redacted layered values plus the + * serialized schema a client renders its form from. `hasDocument` reports + * whether a file-backed provider owns a local document without exposing its + * Host path. This method is loopback-only; `writable: false` (read-only + * provider) tells the client to disable every write control. + */ + describe(request: RpcRequest<{}>): Promise>; + /** + * Materialize the configured local document when absent and ask the Host to + * hand it to the platform text-document opener. macOS forces a text editor; + * Linux and Windows use the desktop file association. The request carries + * no path, so the browser cannot choose an arbitrary Host filesystem target. + */ + openDocument(request: RpcRequest<{}>, signal: AbortSignal): Promise>; + /** + * Merge a patch into one namespace's user layer (validate → persist → + * commit). Secret-role fields may be INCLUDED in the patch (write-only + * direction); a form that leaves a secret untouched simply omits it and the + * merge preserves the stored value. Responds with the namespace's new + * redacted view; a schema or storage rejection is `settings-rejected`. + */ + update(request: RpcRequest<{ + ns: string; + patch: object; + expectedRevision?: number; + }>): Promise>; + /** + * Replace one namespace's user section wholesale — the removal/reset path a + * merge cannot express (`section: {}` resets to composition defaults). Keys + * absent from `section` are dropped, secrets included: a client must first + * fold the descriptor's `user` layer (and re-supply any secret it wants to + * keep) or accept the reset. + */ + replace(request: RpcRequest<{ + ns: string; + section: object; + expectedRevision?: number; + }>): Promise>; + /** + * Apply path-addressed edits to one namespace's user section, resolved + * against the section as stored — NOT against whatever the caller last + * read. This is the removal path for any client holding the redacted + * descriptor: it names the field it means, so a secret the wire never + * returned cannot be deleted as a side effect. `replace` remains the + * deliberate wholesale reset. + */ + mutate(request: RpcRequest<{ + ns: string; + ops: SettingsPathOpView[]; + expectedRevision?: number; + }>): Promise>; +} +//# sourceMappingURL=settings.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.js new file mode 100644 index 0000000..d3fe50c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.js @@ -0,0 +1,9 @@ +/** + * settings domain contract: the web face of the user-settings seam + * (`ctx.settings`). Every payload that leaves this domain is redacted by the + * seam (`describe({ redactSecrets: true })` semantics): `role('secret')` + * fields never ride a response in any layer, and the `secrets` slot list is + * how a form learns a write-only field exists and whether it is configured. + */ +export {}; +//# sourceMappingURL=settings.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.d.ts new file mode 100644 index 0000000..c8b9698 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.d.ts @@ -0,0 +1,115 @@ +/** + * settings domain zod schemas (names derived from map keys: settingsDescribeRequestSchema / + * settingsDescribeValueSchema / settingsUpdate* / settingsReplace*). + */ +import { z } from 'zod'; +import type { Wire } from './rpc.schema.ts'; +import type { SettingsPathOpView } from './settings.ts'; +/** One redacted secret slot. */ +export declare const settingsSecretViewSchema: z.ZodObject<{ + path: z.ZodArray; + set: z.ZodBoolean; +}, z.core.$strip>; +/** SettingsNamespaceView row of settings.describe and the write responses. */ +export declare const settingsNamespaceViewSchema: z.ZodObject<{ + ns: z.ZodString; + schema: z.ZodUnknown; + value: z.ZodUnknown; + base: z.ZodOptional; + user: z.ZodOptional; + applies: z.ZodUnion, z.ZodLiteral<"restart">]>; + secrets: z.ZodArray; + set: z.ZodBoolean; + }, z.core.$strip>>; + revision: z.ZodNumber; +}, z.core.$strip>; +/** settings.describe request payload. */ +export declare const settingsDescribeRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** settings.describe response value. */ +export declare const settingsDescribeValueSchema: z.ZodObject<{ + writable: z.ZodBoolean; + hasDocument: z.ZodBoolean; + namespaces: z.ZodArray; + user: z.ZodOptional; + applies: z.ZodUnion, z.ZodLiteral<"restart">]>; + secrets: z.ZodArray; + set: z.ZodBoolean; + }, z.core.$strip>>; + revision: z.ZodNumber; + }, z.core.$strip>>; +}, z.core.$strip>; +/** settings.openDocument request payload. */ +export declare const settingsOpenDocumentRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** settings.openDocument response value. */ +export declare const settingsOpenDocumentValueSchema: z.ZodObject<{ + opened: z.ZodLiteral; +}, z.core.$strip>; +/** settings.update request payload. */ +export declare const settingsUpdateRequestSchema: z.ZodObject<{ + ns: z.ZodString; + patch: z.ZodRecord; + expectedRevision: z.ZodOptional; +}, z.core.$strip>; +/** settings.update response value: the namespace's new redacted view. */ +export declare const settingsUpdateValueSchema: z.ZodObject<{ + ns: z.ZodString; + schema: z.ZodUnknown; + value: z.ZodUnknown; + base: z.ZodOptional; + user: z.ZodOptional; + applies: z.ZodUnion, z.ZodLiteral<"restart">]>; + secrets: z.ZodArray; + set: z.ZodBoolean; + }, z.core.$strip>>; + revision: z.ZodNumber; +}, z.core.$strip>; +/** settings.replace request payload. */ +export declare const settingsReplaceRequestSchema: z.ZodObject<{ + ns: z.ZodString; + section: z.ZodRecord; + expectedRevision: z.ZodOptional; +}, z.core.$strip>; +/** One path-addressed edit of settings.mutate. */ +export declare const settingsPathOpSchema: z.ZodType>; +/** settings.mutate request payload. */ +export declare const settingsMutateRequestSchema: z.ZodObject<{ + ns: z.ZodString; + ops: z.ZodArray, unknown, z.core.$ZodTypeInternals, unknown>>>; + expectedRevision: z.ZodOptional; +}, z.core.$strip>; +/** settings.mutate response value: the namespace's new redacted view. */ +export declare const settingsMutateValueSchema: z.ZodObject<{ + ns: z.ZodString; + schema: z.ZodUnknown; + value: z.ZodUnknown; + base: z.ZodOptional; + user: z.ZodOptional; + applies: z.ZodUnion, z.ZodLiteral<"restart">]>; + secrets: z.ZodArray; + set: z.ZodBoolean; + }, z.core.$strip>>; + revision: z.ZodNumber; +}, z.core.$strip>; +/** settings.replace response value. */ +export declare const settingsReplaceValueSchema: z.ZodObject<{ + ns: z.ZodString; + schema: z.ZodUnknown; + value: z.ZodUnknown; + base: z.ZodOptional; + user: z.ZodOptional; + applies: z.ZodUnion, z.ZodLiteral<"restart">]>; + secrets: z.ZodArray; + set: z.ZodBoolean; + }, z.core.$strip>>; + revision: z.ZodNumber; +}, z.core.$strip>; +//# sourceMappingURL=settings.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.js new file mode 100644 index 0000000..aaf76f6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.js @@ -0,0 +1,65 @@ +/** + * settings domain zod schemas (names derived from map keys: settingsDescribeRequestSchema / + * settingsDescribeValueSchema / settingsUpdate* / settingsReplace*). + */ +import { z } from 'zod'; +/** One redacted secret slot. */ +export const settingsSecretViewSchema = z.object({ + path: z.array(z.string()), + set: z.boolean(), +}); +/** SettingsNamespaceView row of settings.describe and the write responses. */ +export const settingsNamespaceViewSchema = z.object({ + ns: z.string().min(1), + schema: z.unknown(), + value: z.unknown(), + base: z.unknown().optional(), + user: z.unknown().optional(), + applies: z.union([z.literal('live'), z.literal('restart')]), + secrets: z.array(settingsSecretViewSchema), + revision: z.number(), +}); +/** settings.describe request payload. */ +export const settingsDescribeRequestSchema = z.object({}); +/** settings.describe response value. */ +export const settingsDescribeValueSchema = z.object({ + writable: z.boolean(), + hasDocument: z.boolean(), + namespaces: z.array(settingsNamespaceViewSchema), +}); +/** settings.openDocument request payload. */ +export const settingsOpenDocumentRequestSchema = z.object({}); +/** settings.openDocument response value. */ +export const settingsOpenDocumentValueSchema = z.object({ + opened: z.literal(true), +}); +/** settings.update request payload. */ +export const settingsUpdateRequestSchema = z.object({ + ns: z.string().min(1), + patch: z.record(z.string(), z.unknown()), + expectedRevision: z.number().optional(), +}); +/** settings.update response value: the namespace's new redacted view. */ +export const settingsUpdateValueSchema = settingsNamespaceViewSchema; +/** settings.replace request payload. */ +export const settingsReplaceRequestSchema = z.object({ + ns: z.string().min(1), + section: z.record(z.string(), z.unknown()), + expectedRevision: z.number().optional(), +}); +/** One path-addressed edit of settings.mutate. */ +export const settingsPathOpSchema = z.discriminatedUnion('op', [ + z.object({ op: z.literal('set'), path: z.array(z.string()), value: z.unknown() }), + z.object({ op: z.literal('unset'), path: z.array(z.string()) }), +]); +/** settings.mutate request payload. */ +export const settingsMutateRequestSchema = z.object({ + ns: z.string().min(1), + ops: z.array(settingsPathOpSchema), + expectedRevision: z.number().optional(), +}); +/** settings.mutate response value: the namespace's new redacted view. */ +export const settingsMutateValueSchema = settingsNamespaceViewSchema; +/** settings.replace response value. */ +export const settingsReplaceValueSchema = settingsNamespaceViewSchema; +//# sourceMappingURL=settings.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.d.ts new file mode 100644 index 0000000..ad7edb0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.d.ts @@ -0,0 +1,35 @@ +/** + * skills domain contract: read-only skill catalog lookup addressed by session. + * The session's header cwd resolves to the canonical project root host-side — + * the client never submits a raw path, and skill lookup never creates or + * resumes an Agent. + */ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** Skill catalog row (wire projection of the host SkillSummary; provider/source vocabulary stays host-side). */ +export interface SkillEntry { + /** Kebab-case identifier the user references as `/name` in the composer. */ + readonly name: string; + /** Short routing description. */ + readonly description: string; + /** Optional extra routing guidance. */ + readonly whenToUse?: string; + /** False marks a user-only skill (`disable-model-invocation`): invocable here, absent from the model catalog. */ + readonly modelInvocable: boolean; +} +/** + * Skill-domain unary methods (the map key skill.* of RpcMethodMap). Listing + * is the domain's only RPC: invocation itself is a plain `session.prompt` + * whose leading `/name` token the host recognizes at the pre-step boundary + * (`dsh-tool-skill` injects the rendered body there), so every client shares + * one deterministic path with no dedicated invocation wire. + */ +export interface SkillsApi { + /** Lists the user-invocable skill catalog for the session's project. */ + list(request: RpcRequest<{ + sessionId: SessionId; + }>): Promise>; +} +//# sourceMappingURL=skills.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.js new file mode 100644 index 0000000..dd59471 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.js @@ -0,0 +1,8 @@ +/** + * skills domain contract: read-only skill catalog lookup addressed by session. + * The session's header cwd resolves to the canonical project root host-side — + * the client never submits a raw path, and skill lookup never creates or + * resumes an Agent. + */ +export {}; +//# sourceMappingURL=skills.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.d.ts new file mode 100644 index 0000000..903831c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.d.ts @@ -0,0 +1,26 @@ +/** + * skills domain zod schemas (names derived from map keys: skillListRequestSchema / + * skillListValueSchema). + */ +import { z } from 'zod'; +/** SkillEntry row of skill.list. */ +export declare const skillEntrySchema: z.ZodObject<{ + name: z.ZodString; + description: z.ZodString; + whenToUse: z.ZodOptional; + modelInvocable: z.ZodBoolean; +}, z.core.$strip>; +/** skill.list request payload. */ +export declare const skillListRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; +}, z.core.$strip>; +/** skill.list response value. */ +export declare const skillListValueSchema: z.ZodObject<{ + skills: z.ZodArray; + modelInvocable: z.ZodBoolean; + }, z.core.$strip>>; +}, z.core.$strip>; +//# sourceMappingURL=skills.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.js new file mode 100644 index 0000000..53ab52c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.js @@ -0,0 +1,22 @@ +/** + * skills domain zod schemas (names derived from map keys: skillListRequestSchema / + * skillListValueSchema). + */ +import { z } from 'zod'; +import { sessionIdSchema } from "./sessions.schema.js"; +/** SkillEntry row of skill.list. */ +export const skillEntrySchema = z.object({ + name: z.string().min(1), + description: z.string(), + whenToUse: z.string().optional(), + modelInvocable: z.boolean(), +}); +/** skill.list request payload. */ +export const skillListRequestSchema = z.object({ + sessionId: sessionIdSchema, +}); +/** skill.list response value. */ +export const skillListValueSchema = z.object({ + skills: z.array(skillEntrySchema), +}); +//# sourceMappingURL=skills.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.d.ts new file mode 100644 index 0000000..05ebaed --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.d.ts @@ -0,0 +1,101 @@ +/** + * Browser-safe subagent domain contract. Persisted transcript reads never + * activate an Agent, while continuable prompts route through the exact live + * direct parent into the child's Agent inbox. + */ +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm/types'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { RpcRequest, RpcResponse } from './rpc.ts'; +import type { HistoryEntry, SessionProjectionsBlock } from './sessions.ts'; +/** Complete durable direct-child catalog row. */ +export type SubagentListEntry = { + kind: 'child'; + id: SessionId; + /** Whether the child Agent driver is running at the Host sampling boundary. */ + activity: 'running' | 'inactive'; + /** Whether a direct descendant has durable `origin: 'subagent'`. */ + hasChildren: boolean; +} & ({ + mode: 'one-shot'; + label?: string; +} | { + mode: 'continuable'; + label: string; +}) | { + kind: 'diagnostic'; + id: SessionId; + reason: 'corrupt' | 'unsupported' | 'unavailable'; +}; +/** Inbox identity returned once the continuation accepts one human message. */ +export interface SubagentPromptReceipt { + messageId: MessageId; +} +/** Uniform acknowledgement that one interrupt request was admitted. */ +export interface SubagentInterruptReceipt { + accepted: true; +} +/** Durable parent/child address that selects subagent transport in the client. */ +export type SubagentAddress = { + parentSessionId: SessionId; + childSessionId: SessionId; +} & ({ + mode: 'one-shot'; +} | { + mode: 'continuable'; +}); +/** Complete direct-child catalog plus the delivery-time parent availability hint. */ +export interface SubagentCatalog { + entries: SubagentListEntry[]; + parentAvailable: boolean; +} +/** Subagent-domain unary methods. */ +export interface SubagentsApi { + /** + * Lists direct session-backed children without loading either side. Parent + * availability is a hint; continuable prompt performs the authoritative + * check. + */ + list(request: RpcRequest<{ + parentSessionId: SessionId; + }>, signal?: AbortSignal): Promise>; + /** + * Reads one healthy catalog child's transcript — the in-memory snapshot of + * a live child, the persisted log of a cold one — with ordinary + * message-aligned pagination and render intents, without Agent activation. + */ + history(request: RpcRequest, signal?: AbortSignal): Promise>; + /** + * Delivers human content to a continuable child through the exact live + * parent's continuation owner. Success identifies the message accepted by + * the child's FIFO inbox; later execution is independent of this request. + * Optional browser-zone provenance is validated and logged on that message. + */ + prompt(request: RpcRequest & { + content: ContentBlock[]; + /** Optional browser zone sampled for this exact human prompt. */ + clientTimeZone?: string; + }>, signal: AbortSignal): Promise>; + /** + * Interrupts a live continuable child's current turn under the address's + * durable direct-parent authority, without requiring a live parent Agent, + * consulting the catalog, or resuming anything. Fire-and-return: `accepted` + * acknowledges the admitted cancel signal, not target quiescence, so the + * child may remain visibly running briefly. Unclaimed queued follow-ups are + * kept and parked; an absent, idle, or already-completed target is likewise + * `accepted`. + */ + interrupt(request: RpcRequest>): Promise>; +} +//# sourceMappingURL=subagents.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.js new file mode 100644 index 0000000..2c1d873 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.js @@ -0,0 +1,7 @@ +/** + * Browser-safe subagent domain contract. Persisted transcript reads never + * activate an Agent, while continuable prompts route through the exact live + * direct parent into the child's Agent inbox. + */ +export {}; +//# sourceMappingURL=subagents.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.d.ts new file mode 100644 index 0000000..c1bb55f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.d.ts @@ -0,0 +1,79 @@ +/** Zod schemas for the browser-safe subagent domain. */ +import { z } from 'zod'; +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { RequestPayload, ResponseValue } from './rpc-map.ts'; +import type { Wire } from './rpc.schema.ts'; +/** Healthy and diagnostic durable catalog rows. */ +export declare const subagentListEntrySchema: z.ZodUnion; + id: z.ZodType>; + mode: z.ZodLiteral<"one-shot">; + activity: z.ZodUnion, z.ZodLiteral<"inactive">]>; + hasChildren: z.ZodBoolean; + label: z.ZodOptional; +}, z.core.$strip>, z.ZodObject<{ + kind: z.ZodLiteral<"child">; + id: z.ZodType>; + mode: z.ZodLiteral<"continuable">; + activity: z.ZodUnion, z.ZodLiteral<"inactive">]>; + hasChildren: z.ZodBoolean; + label: z.ZodString; +}, z.core.$strip>, z.ZodObject<{ + kind: z.ZodLiteral<"diagnostic">; + id: z.ZodType>; + reason: z.ZodUnion, z.ZodLiteral<"unsupported">, z.ZodLiteral<"unavailable">]>; +}, z.core.$strip>]>; +/** subagent.list request payload. */ +export declare const subagentListRequestSchema: z.ZodObject<{ + parentSessionId: z.ZodType>; +}, z.core.$strip>; +/** subagent.list response value. */ +export declare const subagentListValueSchema: z.ZodObject<{ + entries: z.ZodArray; + id: z.ZodType>; + mode: z.ZodLiteral<"one-shot">; + activity: z.ZodUnion, z.ZodLiteral<"inactive">]>; + hasChildren: z.ZodBoolean; + label: z.ZodOptional; + }, z.core.$strip>, z.ZodObject<{ + kind: z.ZodLiteral<"child">; + id: z.ZodType>; + mode: z.ZodLiteral<"continuable">; + activity: z.ZodUnion, z.ZodLiteral<"inactive">]>; + hasChildren: z.ZodBoolean; + label: z.ZodString; + }, z.core.$strip>, z.ZodObject<{ + kind: z.ZodLiteral<"diagnostic">; + id: z.ZodType>; + reason: z.ZodUnion, z.ZodLiteral<"unsupported">, z.ZodLiteral<"unavailable">]>; + }, z.core.$strip>]>>; + parentAvailable: z.ZodBoolean; +}, z.core.$strip>; +/** subagent.history request payload. */ +export declare const subagentHistoryRequestSchema: z.ZodObject<{ + parentSessionId: z.ZodType>; + childSessionId: z.ZodType>; + mode: z.ZodUnion, z.ZodLiteral<"continuable">]>; + beforeSeq: z.ZodOptional; + maxMessages: z.ZodOptional; +}, z.core.$strip>; +/** subagent.history response value. */ +export declare const subagentHistoryValueSchema: z.ZodType>>; +/** subagent.prompt request payload. */ +export declare const subagentPromptRequestSchema: z.ZodType>; +/** subagent.interrupt request payload. */ +export declare const subagentInterruptRequestSchema: z.ZodObject<{ + parentSessionId: z.ZodType>; + childSessionId: z.ZodType>; + mode: z.ZodLiteral<"continuable">; +}, z.core.$strip>; +/** subagent.interrupt response value. */ +export declare const subagentInterruptValueSchema: z.ZodObject<{ + accepted: z.ZodLiteral; +}, z.core.$strip>; +/** subagent.prompt response value. */ +export declare const subagentPromptValueSchema: z.ZodObject<{ + messageId: z.ZodType>; +}, z.core.$strip>; +//# sourceMappingURL=subagents.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.js new file mode 100644 index 0000000..3648b4a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.js @@ -0,0 +1,74 @@ +/** Zod schemas for the browser-safe subagent domain. */ +import { z } from 'zod'; +import { contentBlockSchema, historyEntrySchema, sessionIdSchema, sessionProjectionsBlockSchema, } from "./sessions.schema.js"; +/** Healthy and diagnostic durable catalog rows. */ +export const subagentListEntrySchema = z.union([ + z.object({ + kind: z.literal('child'), + id: sessionIdSchema, + mode: z.literal('one-shot'), + activity: z.union([z.literal('running'), z.literal('inactive')]), + hasChildren: z.boolean(), + label: z.string().optional(), + }), + z.object({ + kind: z.literal('child'), + id: sessionIdSchema, + mode: z.literal('continuable'), + activity: z.union([z.literal('running'), z.literal('inactive')]), + hasChildren: z.boolean(), + label: z.string(), + }), + z.object({ + kind: z.literal('diagnostic'), + id: sessionIdSchema, + reason: z.union([z.literal('corrupt'), z.literal('unsupported'), z.literal('unavailable')]), + }), +]); +/** subagent.list request payload. */ +export const subagentListRequestSchema = z.object({ + parentSessionId: sessionIdSchema, +}); +/** subagent.list response value. */ +export const subagentListValueSchema = z.object({ + entries: z.array(subagentListEntrySchema), + parentAvailable: z.boolean(), +}); +/** subagent.history request payload. */ +export const subagentHistoryRequestSchema = z.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z.union([z.literal('one-shot'), z.literal('continuable')]), + beforeSeq: z.number().int().nonnegative().optional(), + maxMessages: z.number().int().positive().optional(), +}); +/** subagent.history response value. */ +export const subagentHistoryValueSchema = z.object({ + events: z.array(historyEntrySchema), + hasMore: z.boolean(), + projections: sessionProjectionsBlockSchema.optional(), +}); +/** subagent.prompt request payload. */ +export const subagentPromptRequestSchema = z.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z.literal('continuable'), + content: z.array(contentBlockSchema), + clientTimeZone: z.string().optional(), +}); +/** subagent.interrupt request payload. */ +export const subagentInterruptRequestSchema = z.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z.literal('continuable'), +}); +/** subagent.interrupt response value. */ +export const subagentInterruptValueSchema = z.object({ + accepted: z.literal(true), +}); +const messageIdSchema = z.string(); +/** subagent.prompt response value. */ +export const subagentPromptValueSchema = z.object({ + messageId: messageIdSchema, +}); +//# sourceMappingURL=subagents.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.d.ts new file mode 100644 index 0000000..dfa5944 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.d.ts @@ -0,0 +1,121 @@ +/** + * workspace domain contract. Wire projection of the host-side workspace + * entity (@deepseek-ai/dsh-workspace): a stable id over a directory path, + * a display title, and the ordered session account. Method signatures are the + * source of truth, same as the sessions domain. + */ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** + * Wire-side workspace id brand. Deliberately re-declared here rather than + * imported from dsh-workspace: api/ must stay browser-importable with zero + * host-package dependencies, and the brand string matches, so both sides + * agree structurally. + */ +export type WorkspaceId = Branded<'WorkspaceId'>; +/** One workspace row: the record projection every workspace.* value carries. */ +export interface WorkspaceView { + workspaceId: WorkspaceId; + /** Canonical directory path (host-side realpath canon). */ + path: string; + /** Display title (defaults to the path basename at create). */ + title: string; + /** + * Sessions accounted under this workspace, in manually owned order + * (attach prepends, insertSessionBefore reorders; activity never does). + */ + sessionIds: SessionId[]; + /** ISO-8601 creation instant. */ + createdAt: string; + /** ISO-8601 last-mutation instant. */ + updatedAt: string; +} +/** Workspace-domain unary methods (the map keys workspace.* of RpcMethodMap). */ +export interface WorkspaceApi { + /** + * Lists all workspaces in the registry's durable display order, plus the + * registry-global archive set (the reconnect baseline of + * `host/archived-sessions-changed`). Archived sessions stay in their + * workspace's `sessionIds` account; grouping surfaces hide them. + */ + list(request: RpcRequest<{}>): Promise>; + /** + * Creates (or idempotently resolves) a workspace over an EXISTING directory + * (no mkdir — a missing or non-directory path fails with + * `workspace-invalid-path`). A path resolving to a directory already owned + * by a workspace returns that workspace (`created: false`). Adoption allows + * distinct canonical paths whose basenames produce the same display title; + * the registry's basename title default names the new workspace. + */ + create(request: RpcRequest<{ + path: string; + }>): Promise>; + /** + * Renames a workspace. `title` is trimmed and must be non-empty + * (schema-enforced). An unknown id fails with `workspace-not-found`; a + * title equal to another workspace's fails with `workspace-name-conflict`. + * Renaming to the current title is a no-op success (no durable write). + */ + rename(request: RpcRequest<{ + workspaceId: WorkspaceId; + title: string; + }>): Promise>; + /** + * Removes one Workspace registration. The directory, every user file, and + * every session log remain untouched; those Sessions consequently become + * ungrouped. An unknown id fails with `workspace-not-found`. + */ + delete(request: RpcRequest<{ + workspaceId: WorkspaceId; + }>): Promise>; + /** + * Moves one Workspace within the registry display order, + * DOM-insertBefore-like. An omitted anchor appends to the end. + */ + insertBefore(request: RpcRequest<{ + workspaceId: WorkspaceId; + beforeWorkspaceId?: WorkspaceId; + }>): Promise>; + /** + * Moves an accounted session within its workspace's manual order, + * DOM-insertBefore-like: with `beforeSessionId` the session is inserted + * before that anchor; omitted appends to the end. An unknown workspace + * fails with `workspace-not-found`; a session or anchor not accounted by + * the workspace fails with `workspace-move-invalid`. A move to the current + * position is a no-op success. + */ + insertSessionBefore(request: RpcRequest<{ + workspaceId: WorkspaceId; + sessionId: SessionId; + beforeSessionId?: SessionId; + }>): Promise>; + /** + * Adds one session to the registry-global archive set: the session + * disappears from every grouping surface but keeps its session log and its + * workspace accounting slot (a future unarchive restores its position). + * Idempotent for an already archived id. A session neither live nor in + * session persistence fails with `session-not-found`. Returns the full + * updated set (same snapshot the changed frame carries). + */ + archiveSession(request: RpcRequest<{ + sessionId: SessionId; + }>): Promise>; +} +//# sourceMappingURL=workspace.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.js new file mode 100644 index 0000000..1369d3b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.js @@ -0,0 +1,8 @@ +/** + * workspace domain contract. Wire projection of the host-side workspace + * entity (@deepseek-ai/dsh-workspace): a stable id over a directory path, + * a display title, and the ordered session account. Method signatures are the + * source of truth, same as the sessions domain. + */ +export {}; +//# sourceMappingURL=workspace.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.d.ts new file mode 100644 index 0000000..f7a4911 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.d.ts @@ -0,0 +1,105 @@ +/** + * workspace domain zod schemas (names derived from map keys). The + * WorkspaceId brand cast lives in sessions.schema (see the note there) and + * is re-exported here as the domain-local name. + */ +import { z } from 'zod'; +export { workspaceIdSchema } from './sessions.schema.ts'; +/** WorkspaceView row of every workspace.* response. */ +export declare const workspaceViewSchema: z.ZodObject<{ + workspaceId: z.ZodType>; + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; +}, z.core.$strip>; +/** workspace.list request payload (empty object literal). */ +export declare const workspaceListRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** workspace.list response value. */ +export declare const workspaceListValueSchema: z.ZodObject<{ + items: z.ZodArray>; + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; + }, z.core.$strip>>; + archivedSessionIds: z.ZodArray>>; +}, z.core.$strip>; +/** workspace.create request payload: the existing directory to adopt. */ +export declare const workspaceCreateRequestSchema: z.ZodObject<{ + path: z.ZodString; +}, z.core.$strip>; +/** workspace.create response value. */ +export declare const workspaceCreateValueSchema: z.ZodObject<{ + workspace: z.ZodObject<{ + workspaceId: z.ZodType>; + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; + }, z.core.$strip>; + created: z.ZodBoolean; +}, z.core.$strip>; +/** workspace.rename request payload: the new title must be non-blank. */ +export declare const workspaceRenameRequestSchema: z.ZodObject<{ + workspaceId: z.ZodType>; + title: z.ZodString; +}, z.core.$strip>; +/** workspace.rename response value. */ +export declare const workspaceRenameValueSchema: z.ZodObject<{ + workspace: z.ZodObject<{ + workspaceId: z.ZodType>; + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; + }, z.core.$strip>; +}, z.core.$strip>; +/** workspace.delete request payload. */ +export declare const workspaceDeleteRequestSchema: z.ZodObject<{ + workspaceId: z.ZodType>; +}, z.core.$strip>; +/** workspace.delete response value. */ +export declare const workspaceDeleteValueSchema: z.ZodObject<{ + deleted: z.ZodLiteral; +}, z.core.$strip>; +/** workspace.insertBefore request payload (anchor omitted = append to end). */ +export declare const workspaceInsertBeforeRequestSchema: z.ZodObject<{ + workspaceId: z.ZodType>; + beforeWorkspaceId: z.ZodOptional>>; +}, z.core.$strip>; +/** workspace.insertBefore response value: the complete durable display order. */ +export declare const workspaceInsertBeforeValueSchema: z.ZodObject<{ + workspaceIds: z.ZodArray>>; +}, z.core.$strip>; +/** workspace.insertSessionBefore request payload (anchor omitted = append to end). */ +export declare const workspaceInsertSessionBeforeRequestSchema: z.ZodObject<{ + workspaceId: z.ZodType>; + sessionId: z.ZodType>; + beforeSessionId: z.ZodOptional>>; +}, z.core.$strip>; +/** workspace.insertSessionBefore response value. */ +export declare const workspaceInsertSessionBeforeValueSchema: z.ZodObject<{ + workspace: z.ZodObject<{ + workspaceId: z.ZodType>; + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; + }, z.core.$strip>; +}, z.core.$strip>; +/** workspace.archiveSession request payload. */ +export declare const workspaceArchiveSessionRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; +}, z.core.$strip>; +/** workspace.archiveSession response value: the full updated archive set. */ +export declare const workspaceArchiveSessionValueSchema: z.ZodObject<{ + archivedSessionIds: z.ZodArray>>; +}, z.core.$strip>; +//# sourceMappingURL=workspace.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js new file mode 100644 index 0000000..1752304 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js @@ -0,0 +1,78 @@ +/** + * workspace domain zod schemas (names derived from map keys). The + * WorkspaceId brand cast lives in sessions.schema (see the note there) and + * is re-exported here as the domain-local name. + */ +import { z } from 'zod'; +import { sessionIdSchema, workspaceIdSchema } from "./sessions.schema.js"; +export { workspaceIdSchema } from "./sessions.schema.js"; +/** WorkspaceView row of every workspace.* response. */ +export const workspaceViewSchema = z.object({ + workspaceId: workspaceIdSchema, + path: z.string(), + title: z.string(), + sessionIds: z.array(sessionIdSchema), + createdAt: z.string(), + updatedAt: z.string(), +}); +/** workspace.list request payload (empty object literal). */ +export const workspaceListRequestSchema = z.object({}); +/** workspace.list response value. */ +export const workspaceListValueSchema = z.object({ + items: z.array(workspaceViewSchema), + archivedSessionIds: z.array(sessionIdSchema), +}); +/** workspace.create request payload: the existing directory to adopt. */ +export const workspaceCreateRequestSchema = z.object({ + path: z.string(), +}); +/** workspace.create response value. */ +export const workspaceCreateValueSchema = z.object({ + workspace: workspaceViewSchema, + created: z.boolean(), +}); +/** workspace.rename request payload: the new title must be non-blank. */ +export const workspaceRenameRequestSchema = z.object({ + workspaceId: workspaceIdSchema, + title: z.string(), +}).refine(payload => payload.title.trim() !== '', { message: 'workspace.rename requires a non-blank title' }); +/** workspace.rename response value. */ +export const workspaceRenameValueSchema = z.object({ + workspace: workspaceViewSchema, +}); +/** workspace.delete request payload. */ +export const workspaceDeleteRequestSchema = z.object({ + workspaceId: workspaceIdSchema, +}); +/** workspace.delete response value. */ +export const workspaceDeleteValueSchema = z.object({ + deleted: z.literal(true), +}); +/** workspace.insertBefore request payload (anchor omitted = append to end). */ +export const workspaceInsertBeforeRequestSchema = z.object({ + workspaceId: workspaceIdSchema, + beforeWorkspaceId: workspaceIdSchema.optional(), +}); +/** workspace.insertBefore response value: the complete durable display order. */ +export const workspaceInsertBeforeValueSchema = z.object({ + workspaceIds: z.array(workspaceIdSchema), +}); +/** workspace.insertSessionBefore request payload (anchor omitted = append to end). */ +export const workspaceInsertSessionBeforeRequestSchema = z.object({ + workspaceId: workspaceIdSchema, + sessionId: sessionIdSchema, + beforeSessionId: sessionIdSchema.optional(), +}); +/** workspace.insertSessionBefore response value. */ +export const workspaceInsertSessionBeforeValueSchema = z.object({ + workspace: workspaceViewSchema, +}); +/** workspace.archiveSession request payload. */ +export const workspaceArchiveSessionRequestSchema = z.object({ + sessionId: sessionIdSchema, +}); +/** workspace.archiveSession response value: the full updated archive set. */ +export const workspaceArchiveSessionValueSchema = z.object({ + archivedSessionIds: z.array(sessionIdSchema), +}); +//# sourceMappingURL=workspace.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.d.ts new file mode 100644 index 0000000..e3d0480 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.d.ts @@ -0,0 +1,194 @@ +/** + * Client side of the fetch carrier. AbstractApiClient holds every protocol invariant: rpcId minting, + * four-quadrant envelope wrap/unwrap, zod parsing, in-process SSE frame decoding, and the payload-direct + * IApiClient domain methods (business code never mints). Platform differences ride two aspects: + * abstract doFetch (transport) + overridable onEnvelope (tap). ApiProxy (the impl face) is untouched. + */ +import type { z } from 'zod'; +import type { ApiProxy, HostFrame, MuxFrame } from '../api/index.ts'; +import type { RequestPayload, ResponseValue, RpcMethodMap } from '../api/rpc-map.ts'; +import type { ClientResponse, RpcMessage, RpcReceipt, RpcRequest, RpcResponse } from '../api/rpc.ts'; +import { RpcId } from '../api/rpc.ts'; +/** + * Client consumption face of the contract (shape a): same domain tree as ApiProxy, but unary + * methods take the business payload directly — the carrier mints the rpcId and wraps the + * envelope. Business code needing the call's rpcId reads it from the RpcResponse echo. + * Unary methods and respond accept an optional external AbortSignal as the last parameter. + * Bounded calls merge it with the instance timeout via AbortSignal.any; user-paced calls + * carry only that external signal. In both cases the signal rides beside the request, never + * on the wire, like the stream signatures. + * Stream methods accept an optional onOpen callback: it fires once the physical transport is + * readable (before any frame) — the "stream established" signal + * connection controllers need for the readiness handshake. Generators are lazy, so the + * underlying fetch (and therefore onOpen) only happens once iteration starts. + * Relationship: ApiProxy is the narrow-form signature contract the impl side implements; + * IApiClient is the payload-direct view clients consume; AbstractApiClient bridges the two. + * Derived per method key from RpcMethodMap so a map row addition updates this mechanically. + */ +export interface IApiClient { + sessions: { + list(payload: RequestPayload<'session.list'>, signal?: AbortSignal): Promise>>; + search(payload: RequestPayload<'session.search'>, signal?: AbortSignal): Promise>>; + create(payload: RequestPayload<'session.create'>, signal?: AbortSignal): Promise>>; + history(payload: RequestPayload<'session.history'>, signal?: AbortSignal): Promise>>; + models(payload: RequestPayload<'session.models'>, signal?: AbortSignal): Promise>>; + selectModel(payload: RequestPayload<'session.selectModel'>, signal?: AbortSignal): Promise>>; + rename(payload: RequestPayload<'session.rename'>, signal?: AbortSignal): Promise>>; + fork(payload: RequestPayload<'session.fork'>, signal?: AbortSignal): Promise>>; + prompt(payload: RequestPayload<'session.prompt'>, signal?: AbortSignal): Promise>>; + attachment(payload: RequestPayload<'session.attachment'>, signal?: AbortSignal): Promise>>; + updateQueue(payload: RequestPayload<'session.updateQueue'>, signal?: AbortSignal): Promise>>; + cancel(payload: RequestPayload<'session.cancel'>, signal?: AbortSignal): Promise>>; + }; + subagents: { + list(payload: RequestPayload<'subagent.list'>, signal?: AbortSignal): Promise>>; + history(payload: RequestPayload<'subagent.history'>, signal?: AbortSignal): Promise>>; + prompt(payload: RequestPayload<'subagent.prompt'>, signal?: AbortSignal): Promise>>; + interrupt(payload: RequestPayload<'subagent.interrupt'>, signal?: AbortSignal): Promise>>; + }; + host: { + describe(payload: RequestPayload<'host.describe'>, signal?: AbortSignal): Promise>>; + pickDirectory(payload: RequestPayload<'host.pickDirectory'>, signal?: AbortSignal): Promise>>; + listDirectory(payload: RequestPayload<'host.listDirectory'>, signal?: AbortSignal): Promise>>; + createDirectory(payload: RequestPayload<'host.createDirectory'>, signal?: AbortSignal): Promise>>; + openPath(payload: RequestPayload<'host.openPath'>, signal?: AbortSignal): Promise>>; + }; + workspace: { + list(payload: RequestPayload<'workspace.list'>, signal?: AbortSignal): Promise>>; + create(payload: RequestPayload<'workspace.create'>, signal?: AbortSignal): Promise>>; + rename(payload: RequestPayload<'workspace.rename'>, signal?: AbortSignal): Promise>>; + delete(payload: RequestPayload<'workspace.delete'>, signal?: AbortSignal): Promise>>; + insertBefore(payload: RequestPayload<'workspace.insertBefore'>, signal?: AbortSignal): Promise>>; + insertSessionBefore(payload: RequestPayload<'workspace.insertSessionBefore'>, signal?: AbortSignal): Promise>>; + archiveSession(payload: RequestPayload<'workspace.archiveSession'>, signal?: AbortSignal): Promise>>; + }; + skills: { + list(payload: RequestPayload<'skill.list'>, signal?: AbortSignal): Promise>>; + }; + agentPresets: { + list(payload: RequestPayload<'agentPreset.list'>, signal?: AbortSignal): Promise>>; + select(payload: RequestPayload<'agentPreset.select'>, signal?: AbortSignal): Promise>>; + read(payload: RequestPayload<'agentPreset.read'>, signal?: AbortSignal): Promise>>; + copy(payload: RequestPayload<'agentPreset.copy'>, signal?: AbortSignal): Promise>>; + openDocument(payload: RequestPayload<'agentPreset.openDocument'>, signal?: AbortSignal): Promise>>; + remove(payload: RequestPayload<'agentPreset.remove'>, signal?: AbortSignal): Promise>>; + }; + events: { + mux(payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + host(payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + }; + goals: { + create(payload: RequestPayload<'goal.create'>, signal?: AbortSignal): Promise>>; + edit(payload: RequestPayload<'goal.edit'>, signal?: AbortSignal): Promise>>; + pause(payload: RequestPayload<'goal.pause'>, signal?: AbortSignal): Promise>>; + resume(payload: RequestPayload<'goal.resume'>, signal?: AbortSignal): Promise>>; + complete(payload: RequestPayload<'goal.complete'>, signal?: AbortSignal): Promise>>; + clear(payload: RequestPayload<'goal.clear'>, signal?: AbortSignal): Promise>>; + }; + settings: { + describe(payload: RequestPayload<'settings.describe'>, signal?: AbortSignal): Promise>>; + openDocument(payload: RequestPayload<'settings.openDocument'>, signal?: AbortSignal): Promise>>; + update(payload: RequestPayload<'settings.update'>, signal?: AbortSignal): Promise>>; + replace(payload: RequestPayload<'settings.replace'>, signal?: AbortSignal): Promise>>; + mutate(payload: RequestPayload<'settings.mutate'>, signal?: AbortSignal): Promise>>; + }; + credentials: { + describe(payload: RequestPayload<'credentials.describe'>, signal?: AbortSignal): Promise>>; + set(payload: RequestPayload<'credentials.set'>, signal?: AbortSignal): Promise>>; + unset(payload: RequestPayload<'credentials.unset'>, signal?: AbortSignal): Promise>>; + }; + llm: { + providers(payload: RequestPayload<'llm.providers'>, signal?: AbortSignal): Promise>>; + models(payload: RequestPayload<'llm.models'>, signal?: AbortSignal): Promise>>; + discoverModels(payload: RequestPayload<'llm.discoverModels'>, signal?: AbortSignal): Promise>>; + }; + /** client-response passthrough (rpcId is a backfill of the server-request's id — never minted here). */ + respond(message: ClientResponse, signal?: AbortSignal): Promise; +} +/** Whether a unary call uses the transport health deadline or only caller/connection cancellation. */ +type UnaryTimeoutPolicy = 'default' | 'caller-signal-only'; +/** + * Abstract fetch-carrier client. Subclasses supply the transport (doFetch) and may refine the + * per-message tap (onEnvelope) — platform aspects stay in subclasses, protocol invariants stay + * here. Envelope observation is a first-class aspect of this data middle layer: the instance + * owns a microtask-batched buffer (frame storms must not cost one consumer update per frame), + * and observers subscribe via subscribeEnvelopes. The isomorphic point survives: an in-process + * subclass whose doFetch is toFetchHandler(api).fetch never touches the network. + */ +export declare abstract class AbstractApiClient implements IApiClient { + protected readonly timeoutMs: number; + /** Instance-owned observation buffer (module-level state would leak across instances/tests). */ + private envelopeBatch; + private flushScheduled; + private readonly envelopeListeners; + /** @param timeoutMs - timeout for bounded unary calls; user-paced calls and streams do not use it. */ + constructor(timeoutMs?: number); + /** Transport aspect: browser fetch, injected handler.fetch, IPC bridge, ... */ + protected abstract doFetch(input: URL, init?: RequestInit): Promise; + /** + * Subscribe to batched envelope observation (diagnostics/logging consumers). + * Batches follow microtask boundaries; a listener throw is isolated (observation + * must never break the carrier). + * @param listener - receives each flushed batch in arrival order. + * @returns unsubscribe function. + */ + subscribeEnvelopes(listener: (batch: readonly RpcMessage[]) => void): () => void; + /** Per-message tap: feeds the instance buffer. Subclasses may override to observe unbatched (call super to keep batching). */ + protected onEnvelope(message: RpcMessage): void; + /** Browser = same-origin (a fake authority would fail DNS on real requests); no-location env (Node) = fake authority. */ + protected resolveBase(): string; + protected mintRpcId(): RpcId; + /** + * Shared POST leg of both C→S carriers (callUnary/respond): JSON body, + * optional default timeout merged with the caller's external signal, non-2xx → transport throw. + */ + private postJson; + /** + * Unary protocol path: mint → tap → POST full form → envelope parse → verify + * echo → value parse → tap → narrow. Virtual so a fake carrier (fixture) can + * override transport at this layer. + */ + protected callUnary(method: K, payload: RequestPayload, signal?: AbortSignal, timeoutPolicy?: UnaryTimeoutPolicy): Promise>>; + /** Mux stream opener; virtual for the same override reason as callUnary. */ + protected openMux(_payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + /** Host stream opener; virtual. */ + protected openHost(_payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + /** + * SSE protocol path: streaming fetch (not EventSource), '\n\n' framing, ServerRequest envelope + + * frame-schema parse, tap, narrow yield. onOpen fires once the response headers are in and the + * body is readable — the stream-established signal, before any frame arrives. A frame that fails + * either parse level is reported and skipped (one corrupt frame must not kill the stream; the + * client's gap detection covers whatever the frame carried). + */ + protected readSse(path: string, signal: AbortSignal, frameSchema: z.ZodType, onOpen?: () => void): AsyncGenerator>; + readonly sessions: IApiClient['sessions']; + readonly subagents: IApiClient['subagents']; + readonly host: IApiClient['host']; + readonly workspace: IApiClient['workspace']; + readonly skills: IApiClient['skills']; + readonly agentPresets: IApiClient['agentPresets']; + readonly goals: IApiClient['goals']; + readonly settings: IApiClient['settings']; + readonly credentials: IApiClient['credentials']; + readonly llm: IApiClient['llm']; + readonly events: IApiClient['events']; + respond(message: ClientResponse, signal?: AbortSignal): Promise; +} +/** + * In-process client over an injected fetch-shaped handler (the isomorphic point: + * `new InProcessApiClient(toFetchHandler(api))` never touches the network). Lives here because + * in-process injection is this package's own capability (handler and client are both local). + */ +export declare class InProcessApiClient extends AbstractApiClient { + private readonly handler; + constructor(handler: { + fetch: typeof fetch; + }, timeoutMs?: number); + /** + * Faithful to real fetch: reject on signal abort even when the in-process + * handler ignores the signal (a hung impl must not defeat timeout/cancel). + */ + protected doFetch(input: URL, init?: RequestInit): Promise; +} +export {}; +//# sourceMappingURL=client.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.js new file mode 100644 index 0000000..1b4e874 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.js @@ -0,0 +1,370 @@ +/** + * Client side of the fetch carrier. AbstractApiClient holds every protocol invariant: rpcId minting, + * four-quadrant envelope wrap/unwrap, zod parsing, in-process SSE frame decoding, and the payload-direct + * IApiClient domain methods (business code never mints). Platform differences ride two aspects: + * abstract doFetch (transport) + overridable onEnvelope (tap). ApiProxy (the impl face) is untouched. + */ +import { RpcId } from "../api/rpc.js"; +import { rpcReceiptSchema, serverRequestSchema, serverResponseSchema } from "../api/rpc.schema.js"; +import { hostFrameSchema, muxFrameSchema } from "../api/events.schema.js"; +import { hostCreateDirectoryValueSchema, hostDescribeValueSchema, hostListDirectoryValueSchema, hostOpenPathValueSchema, hostPickDirectoryValueSchema, } from "../api/host.schema.js"; +import { sessionCancelValueSchema, sessionAttachmentValueSchema, sessionCreateValueSchema, sessionForkValueSchema, sessionHistoryValueSchema, sessionListValueSchema, sessionModelsValueSchema, sessionPromptValueSchema, sessionRenameValueSchema, sessionSearchValueSchema, sessionSelectModelValueSchema, sessionUpdateQueueValueSchema, } from "../api/sessions.schema.js"; +import { workspaceArchiveSessionValueSchema, workspaceCreateValueSchema, workspaceDeleteValueSchema, workspaceInsertBeforeValueSchema, workspaceInsertSessionBeforeValueSchema, workspaceListValueSchema, workspaceRenameValueSchema, } from "../api/workspace.schema.js"; +import { skillListValueSchema } from "../api/skills.schema.js"; +import { agentPresetCopyValueSchema, agentPresetListValueSchema, agentPresetOpenDocumentValueSchema, agentPresetReadValueSchema, agentPresetRemoveValueSchema, agentPresetSelectValueSchema, } from "../api/agent-presets.schema.js"; +import { goalCreateValueSchema, goalEditValueSchema, goalPauseValueSchema, goalResumeValueSchema, goalCompleteValueSchema, goalClearValueSchema, } from "../api/goals.schema.js"; +import { settingsDescribeValueSchema, settingsMutateValueSchema, settingsOpenDocumentValueSchema, settingsReplaceValueSchema, settingsUpdateValueSchema, } from "../api/settings.schema.js"; +import { credentialsDescribeValueSchema, credentialsSetValueSchema, credentialsUnsetValueSchema, } from "../api/credentials.schema.js"; +import { llmDiscoverModelsValueSchema, llmModelsValueSchema, llmProvidersValueSchema } from "../api/llm.schema.js"; +import { subagentHistoryValueSchema, subagentInterruptValueSchema, subagentListValueSchema, subagentPromptValueSchema, } from "../api/subagents.schema.js"; +/** + * S→C second-level parse table: value schema by method (the response-path + * mirror of the handler's request table; key coverage compiler-enforced against RpcMethodMap). + */ +const UNARY_VALUE_SCHEMAS = { + 'session.list': sessionListValueSchema, + 'session.search': sessionSearchValueSchema, + 'session.create': sessionCreateValueSchema, + 'session.history': sessionHistoryValueSchema, + 'session.models': sessionModelsValueSchema, + 'session.selectModel': sessionSelectModelValueSchema, + 'session.rename': sessionRenameValueSchema, + 'session.fork': sessionForkValueSchema, + 'session.prompt': sessionPromptValueSchema, + 'session.attachment': sessionAttachmentValueSchema, + 'session.updateQueue': sessionUpdateQueueValueSchema, + 'session.cancel': sessionCancelValueSchema, + 'subagent.list': subagentListValueSchema, + 'subagent.history': subagentHistoryValueSchema, + 'subagent.prompt': subagentPromptValueSchema, + 'subagent.interrupt': subagentInterruptValueSchema, + 'host.describe': hostDescribeValueSchema, + 'host.pickDirectory': hostPickDirectoryValueSchema, + 'host.listDirectory': hostListDirectoryValueSchema, + 'host.createDirectory': hostCreateDirectoryValueSchema, + 'host.openPath': hostOpenPathValueSchema, + 'workspace.list': workspaceListValueSchema, + 'workspace.create': workspaceCreateValueSchema, + 'workspace.rename': workspaceRenameValueSchema, + 'workspace.delete': workspaceDeleteValueSchema, + 'workspace.insertBefore': workspaceInsertBeforeValueSchema, + 'workspace.insertSessionBefore': workspaceInsertSessionBeforeValueSchema, + 'workspace.archiveSession': workspaceArchiveSessionValueSchema, + 'skill.list': skillListValueSchema, + 'agentPreset.list': agentPresetListValueSchema, + 'agentPreset.select': agentPresetSelectValueSchema, + 'agentPreset.read': agentPresetReadValueSchema, + 'agentPreset.copy': agentPresetCopyValueSchema, + 'agentPreset.openDocument': agentPresetOpenDocumentValueSchema, + 'agentPreset.remove': agentPresetRemoveValueSchema, + 'goal.create': goalCreateValueSchema, + 'goal.edit': goalEditValueSchema, + 'goal.pause': goalPauseValueSchema, + 'goal.resume': goalResumeValueSchema, + 'goal.complete': goalCompleteValueSchema, + 'goal.clear': goalClearValueSchema, + 'settings.describe': settingsDescribeValueSchema, + 'settings.openDocument': settingsOpenDocumentValueSchema, + 'settings.update': settingsUpdateValueSchema, + 'settings.replace': settingsReplaceValueSchema, + 'settings.mutate': settingsMutateValueSchema, + 'credentials.describe': credentialsDescribeValueSchema, + 'credentials.set': credentialsSetValueSchema, + 'credentials.unset': credentialsUnsetValueSchema, + 'llm.providers': llmProvidersValueSchema, + 'llm.models': llmModelsValueSchema, + 'llm.discoverModels': llmDiscoverModelsValueSchema, +}; +/** Default timeout for bounded unary calls (rpc-compare 2026-07-19: a hung host must not leave callers pending forever). */ +const DEFAULT_TIMEOUT_MS = 30_000; +/** URL base for in-process handler injection (fake authority, opencode precedent). */ +const INTERNAL_BASE = 'http://dsh.internal'; +/** + * Abstract fetch-carrier client. Subclasses supply the transport (doFetch) and may refine the + * per-message tap (onEnvelope) — platform aspects stay in subclasses, protocol invariants stay + * here. Envelope observation is a first-class aspect of this data middle layer: the instance + * owns a microtask-batched buffer (frame storms must not cost one consumer update per frame), + * and observers subscribe via subscribeEnvelopes. The isomorphic point survives: an in-process + * subclass whose doFetch is toFetchHandler(api).fetch never touches the network. + */ +export class AbstractApiClient { + timeoutMs; + /** Instance-owned observation buffer (module-level state would leak across instances/tests). */ + envelopeBatch = []; + flushScheduled = false; + envelopeListeners = new Set(); + /** @param timeoutMs - timeout for bounded unary calls; user-paced calls and streams do not use it. */ + constructor(timeoutMs = DEFAULT_TIMEOUT_MS) { + this.timeoutMs = timeoutMs; + } + /** + * Subscribe to batched envelope observation (diagnostics/logging consumers). + * Batches follow microtask boundaries; a listener throw is isolated (observation + * must never break the carrier). + * @param listener - receives each flushed batch in arrival order. + * @returns unsubscribe function. + */ + subscribeEnvelopes(listener) { + this.envelopeListeners.add(listener); + return () => { + this.envelopeListeners.delete(listener); + }; + } + /** Per-message tap: feeds the instance buffer. Subclasses may override to observe unbatched (call super to keep batching). */ + onEnvelope(message) { + if (this.envelopeListeners.size === 0) + return; + this.envelopeBatch.push(message); + if (this.flushScheduled) + return; + this.flushScheduled = true; + queueMicrotask(() => { + this.flushScheduled = false; + // Never empty here: a flush is only ever scheduled by the push above, + // and this callback is the sole drain point. + const batch = this.envelopeBatch; + this.envelopeBatch = []; + for (const notify of this.envelopeListeners) { + try { + notify(batch); + } + catch (error) { + console.error('[apiproxy] envelope listener threw:', error); + } + } + }); + } + /** Browser = same-origin (a fake authority would fail DNS on real requests); no-location env (Node) = fake authority. */ + resolveBase() { + const loc = globalThis.location; + return loc?.origin !== undefined && loc.origin !== 'null' ? loc.origin : INTERNAL_BASE; + } + mintRpcId() { + // crypto.randomUUID is a Web API (browser + Node ≥19): keeps this base platform-neutral. + return RpcId(crypto.randomUUID()); + } + /** + * Shared POST leg of both C→S carriers (callUnary/respond): JSON body, + * optional default timeout merged with the caller's external signal, non-2xx → transport throw. + */ + async postJson(path, body, signal, timeoutPolicy = 'default') { + const requestSignal = timeoutPolicy === 'default' + ? signal === undefined + ? AbortSignal.timeout(this.timeoutMs) + : AbortSignal.any([AbortSignal.timeout(this.timeoutMs), signal]) + : signal; + const response = await this.doFetch(new URL(path, this.resolveBase()), { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(body), + ...requestSignal === undefined ? {} : { signal: requestSignal }, + }); + if (!response.ok) + throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + return response; + } + /** + * Unary protocol path: mint → tap → POST full form → envelope parse → verify + * echo → value parse → tap → narrow. Virtual so a fake carrier (fixture) can + * override transport at this layer. + */ + async callUnary(method, payload, signal, timeoutPolicy = 'default') { + const message = { type: 'client-request', rpcId: this.mintRpcId(), method, payload }; + this.onEnvelope(message); + const response = await this.postJson(`/api/${method}`, message, signal, timeoutPolicy); + const full = serverResponseSchema.parse(await response.json()); + this.onEnvelope(full); + if (full.rpcId !== message.rpcId) + throw new Error(`rpcId mismatch for ${method}: sent ${message.rpcId}, got ${full.rpcId}`); + if (!full.result.ok) + return { rpcId: full.rpcId, result: full.result }; + // Second-level S→C parse: the ok value must match the method's Value schema (mirror of the + // handler's request-payload parse). The cast collapses the Wire<> widening, same as the handler side. + const value = UNARY_VALUE_SCHEMAS[method].parse(full.result.value); + return { rpcId: full.rpcId, result: { ok: true, value } }; + } + /** Mux stream opener; virtual for the same override reason as callUnary. */ + openMux(_payload, signal, onOpen) { + return this.readSse('/api/events.mux', signal, muxFrameSchema, onOpen); + } + /** Host stream opener; virtual. */ + openHost(_payload, signal, onOpen) { + return this.readSse('/api/events.host', signal, hostFrameSchema, onOpen); + } + /** + * SSE protocol path: streaming fetch (not EventSource), '\n\n' framing, ServerRequest envelope + + * frame-schema parse, tap, narrow yield. onOpen fires once the response headers are in and the + * body is readable — the stream-established signal, before any frame arrives. A frame that fails + * either parse level is reported and skipped (one corrupt frame must not kill the stream; the + * client's gap detection covers whatever the frame carried). + */ + async *readSse(path, signal, frameSchema, onOpen) { + const response = await this.doFetch(new URL(path, this.resolveBase()), { signal }); + if (!response.ok || response.body === null) + throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + onOpen?.(); + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let buffer = ''; + try { + while (true) { + const { done, value } = await reader.read(); + if (done) + return; + buffer += decoder.decode(value, { stream: true }); + let boundary; + while ((boundary = buffer.indexOf('\n\n')) !== -1) { + const chunk = buffer.slice(0, boundary); + buffer = buffer.slice(boundary + 2); + const data = chunk.split('\n').filter(line => line.startsWith('data: ')).map(line => line.slice(6)).join(''); + if (data === '') + continue; + let full; + let frame; + try { + full = serverRequestSchema.parse(JSON.parse(data)); + frame = frameSchema.parse(full.payload); + } + catch (error) { + console.error(`[apiproxy] dropping malformed SSE frame on ${path}:`, error); + continue; + } + this.onEnvelope(full); + yield { rpcId: full.rpcId, payload: frame }; + } + } + } + finally { + await reader.cancel().catch(() => undefined); + } + } + // ---- IApiClient API (arrow properties so destructured/passed references stay bound) ---- + sessions = { + list: (payload, signal) => this.callUnary('session.list', payload, signal), + search: (payload, signal) => this.callUnary('session.search', payload, signal), + create: (payload, signal) => this.callUnary('session.create', payload, signal), + history: (payload, signal) => this.callUnary('session.history', payload, signal), + models: (payload, signal) => this.callUnary('session.models', payload, signal), + selectModel: (payload, signal) => this.callUnary('session.selectModel', payload, signal), + rename: (payload, signal) => this.callUnary('session.rename', payload, signal), + fork: (payload, signal) => this.callUnary('session.fork', payload, signal), + prompt: (payload, signal) => this.callUnary('session.prompt', payload, signal), + attachment: (payload, signal) => this.callUnary('session.attachment', payload, signal), + updateQueue: (payload, signal) => this.callUnary('session.updateQueue', payload, signal), + cancel: (payload, signal) => this.callUnary('session.cancel', payload, signal), + }; + subagents = { + list: (payload, signal) => this.callUnary('subagent.list', payload, signal), + history: (payload, signal) => this.callUnary('subagent.history', payload, signal), + prompt: (payload, signal) => this.callUnary('subagent.prompt', payload, signal), + interrupt: (payload, signal) => this.callUnary('subagent.interrupt', payload, signal), + }; + host = { + describe: (payload, signal) => this.callUnary('host.describe', payload, signal), + // A native system dialog is user-paced and may legitimately stay open + // longer than the normal unary deadline. Caller/connection aborts remain. + pickDirectory: (payload, signal) => this.callUnary('host.pickDirectory', payload, signal, 'caller-signal-only'), + listDirectory: (payload, signal) => this.callUnary('host.listDirectory', payload, signal), + createDirectory: (payload, signal) => this.callUnary('host.createDirectory', payload, signal), + openPath: (payload, signal) => this.callUnary('host.openPath', payload, signal), + }; + workspace = { + list: (payload, signal) => this.callUnary('workspace.list', payload, signal), + create: (payload, signal) => this.callUnary('workspace.create', payload, signal), + rename: (payload, signal) => this.callUnary('workspace.rename', payload, signal), + delete: (payload, signal) => this.callUnary('workspace.delete', payload, signal), + insertBefore: (payload, signal) => this.callUnary('workspace.insertBefore', payload, signal), + insertSessionBefore: (payload, signal) => this.callUnary('workspace.insertSessionBefore', payload, signal), + archiveSession: (payload, signal) => this.callUnary('workspace.archiveSession', payload, signal), + }; + skills = { + list: (payload, signal) => this.callUnary('skill.list', payload, signal), + }; + // Annotated like every sibling, and load-bearing rather than cosmetic: + // inferring this member inlines `AgentPresetEntry` into the emitted + // declaration by the specifier TS picks — the host `index.ts` — which drags + // the whole gateway, and with it the host `Context` merges, into every + // Client program that imports this carrier. + agentPresets = { + list: (payload, signal) => this.callUnary('agentPreset.list', payload, signal), + select: (payload, signal) => this.callUnary('agentPreset.select', payload, signal), + read: (payload, signal) => this.callUnary('agentPreset.read', payload, signal), + copy: (payload, signal) => this.callUnary('agentPreset.copy', payload, signal), + openDocument: (payload, signal) => this.callUnary('agentPreset.openDocument', payload, signal), + remove: (payload, signal) => this.callUnary('agentPreset.remove', payload, signal), + }; + goals = { + create: (payload, signal) => this.callUnary('goal.create', payload, signal), + edit: (payload, signal) => this.callUnary('goal.edit', payload, signal), + pause: (payload, signal) => this.callUnary('goal.pause', payload, signal), + resume: (payload, signal) => this.callUnary('goal.resume', payload, signal), + complete: (payload, signal) => this.callUnary('goal.complete', payload, signal), + clear: (payload, signal) => this.callUnary('goal.clear', payload, signal), + }; + settings = { + describe: (payload, signal) => this.callUnary('settings.describe', payload, signal), + openDocument: (payload, signal) => this.callUnary('settings.openDocument', payload, signal), + update: (payload, signal) => this.callUnary('settings.update', payload, signal), + replace: (payload, signal) => this.callUnary('settings.replace', payload, signal), + mutate: (payload, signal) => this.callUnary('settings.mutate', payload, signal), + }; + credentials = { + describe: (payload, signal) => this.callUnary('credentials.describe', payload, signal), + set: (payload, signal) => this.callUnary('credentials.set', payload, signal), + unset: (payload, signal) => this.callUnary('credentials.unset', payload, signal), + }; + llm = { + providers: (payload, signal) => this.callUnary('llm.providers', payload, signal), + models: (payload, signal) => this.callUnary('llm.models', payload, signal), + discoverModels: (payload, signal) => this.callUnary('llm.discoverModels', payload, signal), + }; + events = { + mux: (payload, signal, onOpen) => this.openMux(payload, signal, onOpen), + host: (payload, signal, onOpen) => this.openHost(payload, signal, onOpen), + }; + async respond(message, signal) { + this.onEnvelope(message); + const response = await this.postJson('/api/respond', message, signal); + return rpcReceiptSchema.parse(await response.json()); + } +} +/** + * In-process client over an injected fetch-shaped handler (the isomorphic point: + * `new InProcessApiClient(toFetchHandler(api))` never touches the network). Lives here because + * in-process injection is this package's own capability (handler and client are both local). + */ +export class InProcessApiClient extends AbstractApiClient { + handler; + constructor(handler, timeoutMs) { + super(timeoutMs); + this.handler = handler; + } + /** + * Faithful to real fetch: reject on signal abort even when the in-process + * handler ignores the signal (a hung impl must not defeat timeout/cancel). + */ + doFetch(input, init) { + const signal = init?.signal ?? undefined; + if (signal === undefined) + return this.handler.fetch(input, init); + if (signal.aborted) + return Promise.reject(abortError(signal)); + return new Promise((resolve, reject) => { + const onAbort = () => { reject(abortError(signal)); }; + signal.addEventListener('abort', onAbort, { once: true }); + this.handler.fetch(input, init) + .then(resolve, reject) + .finally(() => { signal.removeEventListener('abort', onAbort); }); + }); + } +} +/** Mirror fetch's abort rejection: the signal's reason when present, else a DOMException-style AbortError. */ +function abortError(signal) { + const reason = signal.reason; + if (reason instanceof Error) + return reason; + if (typeof reason === 'string') + return new Error(reason); + return new Error('This operation was aborted'); +} +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.d.ts new file mode 100644 index 0000000..7facaf2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.d.ts @@ -0,0 +1,17 @@ +/** + * Server side of the fetch carrier: maps an ApiProxy onto a pure + * WHATWG Request->Response function. Two-level parse: full form (type/rpcId/method + + * path==method) -> payload dispatched per method. HTTP status expresses only the carrier + * (404 unknown path / 415 non-JSON media type / 400 non-JSON body / 500 handler crash); + * business errors are always 200 + ServerResponse. + */ +import type { ApiProxy } from '../api/index.ts'; +/** + * Wraps an ApiProxy into a pure fetch function (isomorphic point: feed the returned fetch straight to InProcessApiClient). + * @param api - the host-side ApiProxy implementation. + * @returns an object holding `fetch(Request)`; paths outside /api/ return 404. + */ +export declare function toFetchHandler(api: ApiProxy): { + fetch: typeof fetch; +}; +//# sourceMappingURL=handler.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.js new file mode 100644 index 0000000..9d72e02 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.js @@ -0,0 +1,245 @@ +/** + * Server side of the fetch carrier: maps an ApiProxy onto a pure + * WHATWG Request->Response function. Two-level parse: full form (type/rpcId/method + + * path==method) -> payload dispatched per method. HTTP status expresses only the carrier + * (404 unknown path / 415 non-JSON media type / 400 non-JSON body / 500 handler crash); + * business errors are always 200 + ServerResponse. + */ +import { randomUUID } from 'node:crypto'; +import { sessionLogQuerySchema } from "../api/downloads.schema.js"; +import { RpcId } from "../api/rpc.js"; +import { clientRequestSchema, clientResponseSchema } from "../api/rpc.schema.js"; +import { sessionCancelRequestSchema, sessionAttachmentRequestSchema, sessionCreateRequestSchema, sessionForkRequestSchema, sessionHistoryRequestSchema, sessionListRequestSchema, sessionModelsRequestSchema, sessionPromptRequestSchema, sessionRenameRequestSchema, sessionSearchRequestSchema, sessionSelectModelRequestSchema, sessionUpdateQueueRequestSchema, } from "../api/sessions.schema.js"; +import { hostCreateDirectoryRequestSchema, hostDescribeRequestSchema, hostListDirectoryRequestSchema, hostOpenPathRequestSchema, hostPickDirectoryRequestSchema, } from "../api/host.schema.js"; +import { workspaceArchiveSessionRequestSchema, workspaceCreateRequestSchema, workspaceDeleteRequestSchema, workspaceInsertBeforeRequestSchema, workspaceInsertSessionBeforeRequestSchema, workspaceListRequestSchema, workspaceRenameRequestSchema, } from "../api/workspace.schema.js"; +import { skillListRequestSchema } from "../api/skills.schema.js"; +import { agentPresetCopyRequestSchema, agentPresetListRequestSchema, agentPresetOpenDocumentRequestSchema, agentPresetReadRequestSchema, agentPresetRemoveRequestSchema, agentPresetSelectRequestSchema, } from "../api/agent-presets.schema.js"; +import { goalCreateRequestSchema, goalEditRequestSchema, goalPauseRequestSchema, goalResumeRequestSchema, goalCompleteRequestSchema, goalClearRequestSchema, } from "../api/goals.schema.js"; +import { settingsDescribeRequestSchema, settingsMutateRequestSchema, settingsOpenDocumentRequestSchema, settingsReplaceRequestSchema, settingsUpdateRequestSchema, } from "../api/settings.schema.js"; +import { credentialsDescribeRequestSchema, credentialsSetRequestSchema, credentialsUnsetRequestSchema, } from "../api/credentials.schema.js"; +import { llmDiscoverModelsRequestSchema, llmModelsRequestSchema, llmProvidersRequestSchema } from "../api/llm.schema.js"; +import { subagentHistoryRequestSchema, subagentInterruptRequestSchema, subagentListRequestSchema, subagentPromptRequestSchema, } from "../api/subagents.schema.js"; +const UNARY_ROUTES = { + 'session.list': { schema: sessionListRequestSchema, invoke: (api, r) => api.sessions.list(r) }, + 'session.search': { schema: sessionSearchRequestSchema, invoke: (api, r, signal) => api.sessions.search(r, signal) }, + 'session.create': { schema: sessionCreateRequestSchema, invoke: (api, r) => api.sessions.create(r) }, + 'session.history': { schema: sessionHistoryRequestSchema, invoke: (api, r) => api.sessions.history(r) }, + 'session.models': { schema: sessionModelsRequestSchema, invoke: (api, r) => api.sessions.models(r) }, + 'session.selectModel': { schema: sessionSelectModelRequestSchema, invoke: (api, r) => api.sessions.selectModel(r) }, + 'session.rename': { schema: sessionRenameRequestSchema, invoke: (api, r) => api.sessions.rename(r) }, + 'session.fork': { schema: sessionForkRequestSchema, invoke: (api, r) => api.sessions.fork(r) }, + 'session.prompt': { schema: sessionPromptRequestSchema, invoke: (api, r) => api.sessions.prompt(r) }, + 'session.attachment': { schema: sessionAttachmentRequestSchema, invoke: (api, r) => api.sessions.attachment(r) }, + 'session.updateQueue': { schema: sessionUpdateQueueRequestSchema, invoke: (api, r) => api.sessions.updateQueue(r) }, + 'session.cancel': { schema: sessionCancelRequestSchema, invoke: (api, r) => api.sessions.cancel(r) }, + 'subagent.list': { schema: subagentListRequestSchema, invoke: (api, r, signal) => api.subagents.list(r, signal) }, + 'subagent.history': { schema: subagentHistoryRequestSchema, invoke: (api, r, signal) => api.subagents.history(r, signal) }, + 'subagent.prompt': { schema: subagentPromptRequestSchema, invoke: (api, r, signal) => api.subagents.prompt(r, signal) }, + 'subagent.interrupt': { schema: subagentInterruptRequestSchema, invoke: (api, r) => api.subagents.interrupt(r) }, + 'host.describe': { schema: hostDescribeRequestSchema, invoke: (api, r) => api.host.describe(r) }, + 'host.pickDirectory': { schema: hostPickDirectoryRequestSchema, invoke: (api, r, signal) => api.host.pickDirectory(r, signal) }, + 'host.listDirectory': { schema: hostListDirectoryRequestSchema, invoke: (api, r, signal) => api.host.listDirectory(r, signal) }, + 'host.createDirectory': { schema: hostCreateDirectoryRequestSchema, invoke: (api, r) => api.host.createDirectory(r) }, + 'host.openPath': { schema: hostOpenPathRequestSchema, invoke: (api, r, signal) => api.host.openPath(r, signal) }, + 'workspace.list': { schema: workspaceListRequestSchema, invoke: (api, r) => api.workspace.list(r) }, + 'workspace.create': { schema: workspaceCreateRequestSchema, invoke: (api, r) => api.workspace.create(r) }, + 'workspace.rename': { schema: workspaceRenameRequestSchema, invoke: (api, r) => api.workspace.rename(r) }, + 'workspace.delete': { schema: workspaceDeleteRequestSchema, invoke: (api, r) => api.workspace.delete(r) }, + 'workspace.insertBefore': { schema: workspaceInsertBeforeRequestSchema, invoke: (api, r) => api.workspace.insertBefore(r) }, + 'workspace.insertSessionBefore': { schema: workspaceInsertSessionBeforeRequestSchema, invoke: (api, r) => api.workspace.insertSessionBefore(r) }, + 'workspace.archiveSession': { schema: workspaceArchiveSessionRequestSchema, invoke: (api, r) => api.workspace.archiveSession(r) }, + 'skill.list': { schema: skillListRequestSchema, invoke: (api, r) => api.skills.list(r) }, + 'agentPreset.list': { schema: agentPresetListRequestSchema, invoke: (api, r) => api.agentPresets.list(r) }, + 'agentPreset.select': { schema: agentPresetSelectRequestSchema, invoke: (api, r) => api.agentPresets.select(r) }, + 'agentPreset.read': { schema: agentPresetReadRequestSchema, invoke: (api, r) => api.agentPresets.read(r) }, + 'agentPreset.copy': { schema: agentPresetCopyRequestSchema, invoke: (api, r) => api.agentPresets.copy(r) }, + 'agentPreset.openDocument': { schema: agentPresetOpenDocumentRequestSchema, invoke: (api, r, signal) => api.agentPresets.openDocument(r, signal) }, + 'agentPreset.remove': { schema: agentPresetRemoveRequestSchema, invoke: (api, r) => api.agentPresets.remove(r) }, + 'goal.create': { schema: goalCreateRequestSchema, invoke: (api, r) => api.goals.create(r) }, + 'goal.edit': { schema: goalEditRequestSchema, invoke: (api, r) => api.goals.edit(r) }, + 'goal.pause': { schema: goalPauseRequestSchema, invoke: (api, r) => api.goals.pause(r) }, + 'goal.resume': { schema: goalResumeRequestSchema, invoke: (api, r) => api.goals.resume(r) }, + 'goal.complete': { schema: goalCompleteRequestSchema, invoke: (api, r) => api.goals.complete(r) }, + 'goal.clear': { schema: goalClearRequestSchema, invoke: (api, r) => api.goals.clear(r) }, + 'settings.describe': { schema: settingsDescribeRequestSchema, invoke: (api, r) => api.settings.describe(r) }, + 'settings.openDocument': { schema: settingsOpenDocumentRequestSchema, invoke: (api, r, signal) => api.settings.openDocument(r, signal) }, + 'settings.update': { schema: settingsUpdateRequestSchema, invoke: (api, r) => api.settings.update(r) }, + 'settings.replace': { schema: settingsReplaceRequestSchema, invoke: (api, r) => api.settings.replace(r) }, + 'settings.mutate': { schema: settingsMutateRequestSchema, invoke: (api, r) => api.settings.mutate(r) }, + 'credentials.describe': { schema: credentialsDescribeRequestSchema, invoke: (api, r) => api.credentials.describe(r) }, + 'credentials.set': { schema: credentialsSetRequestSchema, invoke: (api, r) => api.credentials.set(r) }, + 'credentials.unset': { schema: credentialsUnsetRequestSchema, invoke: (api, r) => api.credentials.unset(r) }, + 'llm.providers': { schema: llmProvidersRequestSchema, invoke: (api, r) => api.llm.providers(r) }, + 'llm.models': { schema: llmModelsRequestSchema, invoke: (api, r) => api.llm.models(r) }, + 'llm.discoverModels': { schema: llmDiscoverModelsRequestSchema, invoke: (api, r, signal) => api.llm.discoverModels(r, signal) }, +}; +/** Route lookup that narrows an arbitrary path segment to a map key (single cast point for the string→key refinement). */ +function methodFor(path) { + return Object.hasOwn(UNARY_ROUTES, path) ? path : undefined; +} +/** + * Sentinel rpcId for error responses to envelopes whose own rpcId is unreadable: the response + * must still be a valid ServerResponse (a self-violating shape would turn the server's explicit + * bad-request report into a client-side parse failure). Fixed value, documented here as wire contract. + */ +const INVALID_REQUEST_RPC_ID = RpcId('invalid-request'); +/** Wrap a business error as a ServerResponse full form (rpcId backfilled; an unreadable rpcId uses the invalid-request sentinel). */ +function errorResponse(rpcId, error) { + const body = { type: 'server-response', rpcId, result: { ok: false, error } }; + return Response.json(body); +} +/** Complete the impl's narrow form into a ServerResponse full form. */ +function fullResponse(narrow) { + const body = { type: 'server-response', rpcId: narrow.rpcId, result: narrow.result }; + return Response.json(body); +} +/** + * Parse the payload and invoke one unary route. Generic over the map key so + * the row's schema/invoke pairing typechecks; the only cast collapses the + * Wire<> widening back to the exact payload (undefined-valued properties and + * absent ones are indistinguishable after JSON transport). + */ +// K appears once in the signature but ties the UNARY_ROUTES[K] row lookup to its own +// schema/invoke pairing; a union parameter degrades the row to an uninvokable intersection. +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters +async function handleUnary(api, method, message, signal) { + const route = UNARY_ROUTES[method]; + const payload = route.schema.safeParse(message.payload); + if (!payload.success) { + return errorResponse(message.rpcId, { code: 'bad-request', message: `invalid payload for ${method}`, details: { issues: payload.error.issues } }); + } + try { + return fullResponse(await route.invoke(api, { rpcId: message.rpcId, payload: payload.data }, signal)); + } + catch (error) { + // The impl never throws business errors; reaching here means the implementation itself crashed — 500, carrier layer. + return new Response(`handler failure: ${String(error)}`, { status: 500 }); + } +} +/** SSE frame: complete the narrow RpcRequest into a ServerRequest full form (method = frame type). */ +function fullFrame(narrow) { + return { type: 'server-request', rpcId: narrow.rpcId, method: narrow.payload.type, payload: narrow.payload }; +} +/** + * Wrap a frame stream as an SSE Response; stops when req.signal aborts. An + * impl throw mid-stream emits one stream/error frame and then closes. + */ +function sseResponse(frames) { + const encoder = new TextEncoder(); + const stream = new ReadableStream({ + async start(controller) { + try { + // Send an SSE comment line on open so clients/proxies see a live channel (the host + // stream has no baseline frames and would otherwise emit zero bytes while idle; + // a comment line is not a frame, so client frame parsing skips it naturally). + controller.enqueue(encoder.encode(': connected\n\n')); + for await (const narrow of frames) { + controller.enqueue(encoder.encode(`data: ${JSON.stringify(fullFrame(narrow))}\n\n`)); + } + } + catch (error) { + // Mid-stream impl failure → one stream/error frame, then close: the client must see + // the failure instead of a silent end (which reads as a normal disconnect). A fresh + // rpcId is minted — this is a server-initiated push like any other frame. + const failure = { type: 'stream/error', error: { code: 'internal', message: String(error), details: {} } }; + try { + controller.enqueue(encoder.encode(`data: ${JSON.stringify(fullFrame({ rpcId: RpcId(randomUUID()), payload: failure }))}\n\n`)); + } + catch { + // Consumer already cancelled the stream: enqueue-after-cancel is the + // only reachable error, and there is no one left to tell. + } + } + finally { + try { + controller.close(); + } + catch { /* already cancelled by the consumer: a double close is the only reachable error */ } + } + }, + }); + return new Response(stream, { + headers: { 'content-type': 'text/event-stream', 'cache-control': 'no-cache' }, + }); +} +/** + * Wraps an ApiProxy into a pure fetch function (isomorphic point: feed the returned fetch straight to InProcessApiClient). + * @param api - the host-side ApiProxy implementation. + * @returns an object holding `fetch(Request)`; paths outside /api/ return 404. + */ +export function toFetchHandler(api) { + return { + // Signature matches global fetch: the isomorphic point hands this function to InProcessApiClient as its transport aspect, + // Clients call in (url, init) form — normalize to Request before handling. + async fetch(input, init) { + const req = input instanceof Request ? input : new Request(input, init); + const url = new URL(req.url); + const path = url.pathname; + // No-envelope read channels (SSE GET streams + host-only download): + // physical routes that answer directly, without a wire envelope. + if (path === '/api/events.mux' && req.method === 'GET') { + return sseResponse(api.events.mux({ rpcId: RpcId(randomUUID()), payload: {} }, req.signal)); + } + if (path === '/api/events.host' && req.method === 'GET') { + return sseResponse(api.events.host({ rpcId: RpcId(randomUUID()), payload: {} }, req.signal)); + } + if (path === '/api/session.export' && (req.method === 'GET' || req.method === 'HEAD')) { + // Query params are a different boundary from the POST envelope, but + // the request still casts its brands only through the domain schema. + const parsed = sessionLogQuerySchema.safeParse(Object.fromEntries(url.searchParams)); + if (!parsed.success) { + return new Response('missing or invalid sessionId query parameter', { status: 400 }); + } + const response = await api.downloads.sessionLog(parsed.data, req.signal); + if (req.method === 'GET') + return response; + await response.body?.cancel(); + return new Response(null, { status: response.status, headers: response.headers }); + } + if (req.method !== 'POST' || !path.startsWith('/api/')) { + return new Response('not found', { status: 404 }); + } + // Cross-site write fence: browsers send "simple" POSTs (text/plain, + // form encodings) without a CORS preflight, so a malicious page could + // otherwise execute side-effectful RPCs blind — the response stays + // unreadable cross-origin, but session.prompt would still run. Only the + // JSON media type is accepted; anything else is forced into a preflight + // this server never answers. 415 = carrier layer, like the 400 below. + const mediaType = req.headers.get('content-type')?.split(';', 1)[0]?.trim().toLowerCase(); + if (mediaType !== 'application/json') { + return new Response('content type must be application/json', { status: 415 }); + } + let body; + try { + body = await req.json(); + } + catch { + // 400 = carrier layer (body is not even JSON); valid JSON with a bad shape goes 200 + bad-request. + return new Response('body is not JSON', { status: 400 }); + } + if (path === '/api/respond') { + const parsed = clientResponseSchema.safeParse(body); + if (!parsed.success) + return Response.json({ accepted: false, reason: 'bad-response' }); + return Response.json(await api.respond(parsed.data)); + } + const method = methodFor(path.slice('/api/'.length)); + if (method === undefined) + return new Response('not found', { status: 404 }); + const envelope = clientRequestSchema.safeParse(body); + if (!envelope.success) { + // Best effort at correlation: salvage a string rpcId from the raw body; + // otherwise the fixed sentinel keeps the response a valid ServerResponse. + const rawId = body?.rpcId; + const rpcId = typeof rawId === 'string' ? RpcId(rawId) : INVALID_REQUEST_RPC_ID; + return errorResponse(rpcId, { code: 'bad-request', message: 'invalid client-request message', details: { issues: envelope.error.issues } }); + } + const message = envelope.data; + if (message.method !== method) { + return errorResponse(message.rpcId, { code: 'bad-request', message: `method "${message.method}" does not match path "${method}"`, details: { issues: [] } }); + } + return handleUnary(api, method, message, req.signal); + }, + }; +} +//# sourceMappingURL=handler.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.d.ts new file mode 100644 index 0000000..6737e91 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.d.ts @@ -0,0 +1,77 @@ +/** + * @deepseek-ai/dsh-host-apiproxy — the API gateway every client shape shares: + * the ApiProxy contract (api/: types + zod schemas, browser-safe), the fetch + * carrier pair (fetch/: toFetchHandler on the host side, AbstractApiClient + + * platform subclasses on the client side), and the host-side implementation + * (api-proxy.ts: createApiProxy + the ApiProxyService gateway plugin providing + * `ctx.apiProxy`). Transport-agnostic by design: this package registers no + * routes — physical carriers wrap `ctx.apiProxy` themselves. + * + * The gateway consumes `ctx.agentDefaultModel`, the transport-independent default + * shared with direct entry points. Switching models persists through that + * service; sessions that have already logged a selection remain unchanged. + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { ApiProxy } from './api/index.ts'; +export type * from './api/index.ts'; +export { RpcId } from './api/rpc.ts'; +export { toFetchHandler } from './fetch/handler.ts'; +export { AbstractApiClient, InProcessApiClient } from './fetch/client.ts'; +export type { IApiClient } from './fetch/client.ts'; +export { createApiProxy } from './api-proxy.ts'; +export type { ApiProxyDefaults } from './api-proxy.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + /** The host-side ApiProxy implementation (the transport-agnostic gateway face). */ + apiProxy: ApiProxy; + } +} +/** Gateway plugin configuration. */ +export interface Config { + /** + * Whether this deployment can hand paths to a native desktop opener — + * the `hasDocument` capability the agent-preset roster reports. Absent, + * the platform is asked (macOS/Windows/WSL yes; Linux only with a display + * server); set it explicitly where detection misleads, e.g. `false` in a + * container whose DISPLAY points nowhere a user can see. + */ + nativeOpen?: boolean; + /** + * DEFLATE level for every session-log ZIP entry: `0` stores without + * compression, `1` favors CPU/latency, and `9` favors archive size. + * @default 6 + */ + sessionExportCompressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; + /** + * Maximum physical size of a cold Session artifact eligible for blankness + * verification. Zero disables probes. + * @default 1024 + */ + coldBlankProbeMaxBytes?: number; +} +/** + * The API gateway service: implements the ApiProxy contract over the composed + * host context and provides it as `ctx.apiProxy`. The Host cwd is the default + * project directory. + */ +export declare class ApiProxyService extends Service implements ApiProxy { + static inject: string[]; + static Config: z; + readonly sessions: ApiProxy['sessions']; + readonly subagents: ApiProxy['subagents']; + readonly workspace: ApiProxy['workspace']; + readonly host: ApiProxy['host']; + readonly goals: ApiProxy['goals']; + readonly skills: ApiProxy['skills']; + readonly agentPresets: ApiProxy['agentPresets']; + readonly settings: ApiProxy['settings']; + readonly credentials: ApiProxy['credentials']; + readonly llm: ApiProxy['llm']; + readonly events: ApiProxy['events']; + readonly downloads: ApiProxy['downloads']; + readonly respond: ApiProxy['respond']; + constructor(ctx: Context, config: Config); +} +export default ApiProxyService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.js new file mode 100644 index 0000000..2b8862e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.js @@ -0,0 +1,83 @@ +/** + * @deepseek-ai/dsh-host-apiproxy — the API gateway every client shape shares: + * the ApiProxy contract (api/: types + zod schemas, browser-safe), the fetch + * carrier pair (fetch/: toFetchHandler on the host side, AbstractApiClient + + * platform subclasses on the client side), and the host-side implementation + * (api-proxy.ts: createApiProxy + the ApiProxyService gateway plugin providing + * `ctx.apiProxy`). Transport-agnostic by design: this package registers no + * routes — physical carriers wrap `ctx.apiProxy` themselves. + * + * The gateway consumes `ctx.agentDefaultModel`, the transport-independent default + * shared with direct entry points. Switching models persists through that + * service; sessions that have already logged a selection remain unchanged. + */ +import { Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { createApiProxy, DEFAULT_COLD_BLANK_PROBE_MAX_BYTES } from "./api-proxy.js"; +import { DEFAULT_SESSION_LOG_COMPRESSION_LEVEL, } from "./session-export.js"; +export { RpcId } from "./api/rpc.js"; +export { toFetchHandler } from "./fetch/handler.js"; +export { AbstractApiClient, InProcessApiClient } from "./fetch/client.js"; +export { createApiProxy } from "./api-proxy.js"; +/** + * The API gateway service: implements the ApiProxy contract over the composed + * host context and provides it as `ctx.apiProxy`. The Host cwd is the default + * project directory. + */ +export class ApiProxyService extends Service { + static inject = [ + 'agentDefaultModel', 'agents', 'attachments', 'directoryPicker', 'llm', 'sessions', 'subagents', 'sessionQuery', + 'tools', 'userQuestions', 'workspaceRegistry', + ]; + static Config = z.object({ + nativeOpen: z.boolean(), + sessionExportCompressionLevel: z.number().step(1).min(0).max(9) + .default(DEFAULT_SESSION_LOG_COMPRESSION_LEVEL), + coldBlankProbeMaxBytes: z.natural().default(DEFAULT_COLD_BLANK_PROBE_MAX_BYTES), + }); + sessions; + subagents; + workspace; + host; + goals; + skills; + agentPresets; + settings; + credentials; + llm; + events; + downloads; + respond; + constructor(ctx, config) { + super(ctx, 'apiProxy'); + const api = createApiProxy(ctx, { + defaultModelSelection: () => ctx.agentDefaultModel.currentSelection(), + saveDefaultModelSelection: selection => ctx.agentDefaultModel.saveSelection(selection), + cwd: process.cwd(), + ...config.nativeOpen === undefined ? {} : { canOpenPath: () => config.nativeOpen }, + ...(config.sessionExportCompressionLevel === undefined + ? {} + : { sessionExportCompressionLevel: config.sessionExportCompressionLevel }), + ...(config.coldBlankProbeMaxBytes === undefined + ? {} + : { coldBlankProbeMaxBytes: config.coldBlankProbeMaxBytes }), + }); + this.sessions = api.sessions; + this.subagents = api.subagents; + this.workspace = api.workspace; + this.host = api.host; + this.goals = api.goals; + this.skills = api.skills; + this.agentPresets = api.agentPresets; + this.settings = api.settings; + this.credentials = api.credentials; + this.llm = api.llm; + this.events = api.events; + this.downloads = api.downloads; + // createApiProxy returns closures (no `this` capture), so the bind is + // behavior-neutral. + this.respond = api.respond.bind(api); + } +} +export default ApiProxyService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.d.ts new file mode 100644 index 0000000..c1a26ef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-host-apiproxy`. + * @module @deepseek-ai/dsh-host-apiproxy/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "host-apiproxy-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.js new file mode 100644 index 0000000..465c9f8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.js @@ -0,0 +1,26 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-host-apiproxy`. + * @module @deepseek-ai/dsh-host-apiproxy/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-host-apiproxy'; +/** Cordis companion plugin name. */ +export const name = 'host-apiproxy-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: this package is the wire contract layer plus the + * host-side gateway over services owned elsewhere — it emits no cordis events + * of its own; the session/agent event streams it projects are asserted by + * their owning packages' companions. rpcId round-trip and schema acceptance + * are enforced at the carrier boundary and exercised by the + * protocol-isomorphism suite. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.d.ts new file mode 100644 index 0000000..526850f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.d.ts @@ -0,0 +1,50 @@ +/** + * Cross-platform native path and text-document openers used by the local GUI + * carrier. + * + * The default intent prefers the default browser for documents it renders when + * the platform can name one, then falls back to the default application. WSL + * translates every path for the Windows desktop instead of assuming a Linux + * GUI. The text-editor intent never consults the browser. + */ +import { type NativeCommandRunner } from '@deepseek-ai/dsh-native-command'; +/** Testable command boundary; native implementations never invoke a shell. */ +export type PathOpenerRunner = NativeCommandRunner; +/** Injectable platform facts for deterministic adapter tests. */ +export interface PathOpenerInternals { + platform?: NodeJS.Platform; + /** Kernel release override used to distinguish WSL from desktop Linux. */ + osRelease?: string; + /** Environment used for WSL markers and the desktop Linux browser convention. */ + env?: NodeJS.ProcessEnv; + run?: PathOpenerRunner; +} +/** + * Whether {@link openNativePath} plausibly reaches a desktop on this host. + * + * macOS and Windows always carry a desktop opener; Linux does when it is WSL + * (the Windows desktop takes the path) or a display server is announced. + * A headless or containerised Linux host answers false, which is what lets a + * surface show a path as text instead of offering a button that would spawn + * `xdg-open` into nothing. + * @param internals - platform and environment seam for deterministic tests. + * @returns true when handing a path to the native opener can work at all. + */ +export declare function canOpenNativePath(internals?: PathOpenerInternals): boolean; +/** + * Open a filesystem path with the operating system's default application, or + * with the default browser when the path names a document a browser renders. + * @param path - absolute or host-resolvable path (caller owns resolution). + * @param signal - caller/connection lifetime; abort terminates the native command. + * @param internals - Platform, environment, and runner hooks for deterministic tests. + */ +export declare function openNativePath(path: string, signal: AbortSignal, internals?: PathOpenerInternals): Promise; +/** + * Open a text document for editing; macOS bypasses the file-type association + * so a YAML association with a browser cannot consume the gesture. + * @param path - absolute or host-resolvable text-document path. + * @param signal - caller/connection lifetime; abort terminates the native command. + * @param internals - Platform and runner hooks for deterministic tests. + */ +export declare function openNativeTextFile(path: string, signal: AbortSignal, internals?: PathOpenerInternals): Promise; +//# sourceMappingURL=native-path-opener.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.js new file mode 100644 index 0000000..52bd294 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.js @@ -0,0 +1,161 @@ +/** + * Cross-platform native path and text-document openers used by the local GUI + * carrier. + * + * The default intent prefers the default browser for documents it renders when + * the platform can name one, then falls back to the default application. WSL + * translates every path for the Windows desktop instead of assuming a Linux + * GUI. The text-editor intent never consults the browser. + */ +import { release as osRelease } from 'node:os'; +import { extname } from 'node:path'; +import { runNativeCommand } from '@deepseek-ai/dsh-native-command'; +/** Documents a browser renders, as opposed to ones an editor merely edits. */ +const BROWSER_DOCUMENTS = new Set(['.html', '.htm', '.xhtml', '.svg']); +/** + * The macOS bundle registered for `https` — the default browser, as + * LaunchServices records it. The nested version dict is stripped first + * because it carries its own `LSHandlerRoleAll`. + */ +function macBundleForHttps(plist) { + const stripped = plist.replace(/LSHandlerPreferredVersions\s*=\s*\{[^}]*\};/g, ''); + const block = /\{[^{}]*LSHandlerURLScheme\s*=\s*"?https"?;[^{}]*\}/.exec(stripped)?.[0]; + if (block === undefined) + return undefined; + return /LSHandlerRoleAll\s*=\s*"?([\w.-]+)"?;/.exec(block)?.[1]; +} +/** + * Open one browser-renderable document with the default browser. + * @returns true when a browser took it; false when this platform cannot name + * one, or naming it failed — the caller then uses the default application. + */ +async function openInBrowser(path, signal, platform, run, env) { + if (platform === 'darwin') { + let bundle; + try { + const { stdout } = await run('defaults', ['read', 'com.apple.LaunchServices/com.apple.launchservices.secure'], signal); + bundle = macBundleForHttps(stdout); + } + catch { + // No LaunchServices record (a fresh account never changed a default): + // the content-type handler is then the system's own choice anyway. + return false; + } + if (bundle === undefined) + return false; + await run('open', ['-b', bundle, path], signal); + return true; + } + if (platform === 'linux') { + // $BROWSER is the portable convention; desktop-entry resolution through + // xdg-settings needs a launcher this package has no business shipping. + const browser = env.BROWSER; + if (browser === undefined || browser === '') + return false; + await run(browser, [path], signal); + return true; + } + // Windows names no browser without reading the UserChoice registry, and its + // .html association is the browser in the ordinary case. + return false; +} +/** PowerShell single-quoted literal (doubles embedded quotes). */ +function powershellLiteral(path) { + return `'${path.replace(/'/g, "''")}'`; +} +/** Whether one environment marker is set to a non-empty value. */ +function present(value) { + return value !== undefined && value !== ''; +} +/** Distinguish WSL from desktop Linux using its process and kernel markers. */ +function isWsl(internals) { + const env = internals.env ?? process.env; + if (present(env.WSL_DISTRO_NAME) || present(env.WSL_INTEROP)) + return true; + return (internals.osRelease ?? osRelease()).toLowerCase().includes('microsoft'); +} +/** Open one Windows-resolvable path through its registered desktop application. */ +async function openWindowsPath(path, signal, run) { + await run('powershell.exe', [ + '-NoProfile', + '-Command', + `Invoke-Item -LiteralPath ${powershellLiteral(path)}`, + ], signal); +} +/** Translate a WSL path before handing it to the Windows desktop. */ +async function openWslPath(path, signal, run) { + const translated = await run('wslpath', ['-w', path], signal); + signal.throwIfAborted(); + const windowsPath = translated.stdout.replace(/[\r\n]+$/, ''); + if (windowsPath === '') + throw new Error('wslpath returned no Windows path'); + await openWindowsPath(windowsPath, signal, run); +} +/** Dispatch one shell-free platform command for the requested open intent. */ +async function openNativePathWithIntent(path, signal, intent, internals = {}) { + const platform = internals.platform ?? process.platform; + const run = internals.run ?? runNativeCommand; + const env = internals.env ?? process.env; + const wsl = platform === 'linux' && isWsl(internals); + if (!wsl && intent === 'default' && BROWSER_DOCUMENTS.has(extname(path).toLowerCase()) + && await openInBrowser(path, signal, platform, run, env)) + return; + if (platform === 'darwin') { + await run('open', intent === 'text-editor' ? ['-t', path] : [path], signal); + return; + } + if (platform === 'win32') { + await openWindowsPath(path, signal, run); + return; + } + if (platform === 'linux') { + if (wsl) { + await openWslPath(path, signal, run); + return; + } + await run('xdg-open', [path], signal); + return; + } + throw new Error(`native path opener is unsupported on ${platform}`); +} +/** + * Whether {@link openNativePath} plausibly reaches a desktop on this host. + * + * macOS and Windows always carry a desktop opener; Linux does when it is WSL + * (the Windows desktop takes the path) or a display server is announced. + * A headless or containerised Linux host answers false, which is what lets a + * surface show a path as text instead of offering a button that would spawn + * `xdg-open` into nothing. + * @param internals - platform and environment seam for deterministic tests. + * @returns true when handing a path to the native opener can work at all. + */ +export function canOpenNativePath(internals = {}) { + const platform = internals.platform ?? process.platform; + if (platform === 'darwin' || platform === 'win32') + return true; + if (platform !== 'linux') + return false; + const env = internals.env ?? process.env; + return isWsl(internals) || present(env.DISPLAY) || present(env.WAYLAND_DISPLAY); +} +/** + * Open a filesystem path with the operating system's default application, or + * with the default browser when the path names a document a browser renders. + * @param path - absolute or host-resolvable path (caller owns resolution). + * @param signal - caller/connection lifetime; abort terminates the native command. + * @param internals - Platform, environment, and runner hooks for deterministic tests. + */ +export function openNativePath(path, signal, internals = {}) { + return openNativePathWithIntent(path, signal, 'default', internals); +} +/** + * Open a text document for editing; macOS bypasses the file-type association + * so a YAML association with a browser cannot consume the gesture. + * @param path - absolute or host-resolvable text-document path. + * @param signal - caller/connection lifetime; abort terminates the native command. + * @param internals - Platform and runner hooks for deterministic tests. + */ +export function openNativeTextFile(path, signal, internals = {}) { + return openNativePathWithIntent(path, signal, 'text-editor', internals); +} +//# sourceMappingURL=native-path-opener.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.d.ts new file mode 100644 index 0000000..285a26b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.d.ts @@ -0,0 +1,106 @@ +/** + * Host-side session-log download: streams one ZIP archive whose files are the + * sessions' stored artifact text verbatim plus every referenced media object. + * The root artifact sits under its original base name (`session.jsonl`); each + * subagent descendant under `subagents//`; each image referenced + * by any included log under `media/.` (content-addressed, + * so one archive never duplicates a shared image). No manifest is written — + * every file is byte-identical to the backend's durable artifact or attachment + * store and self-describing through its own header line or media type. Before + * each live session's artifact read, the SessionStore flush barrier makes the + * current in-memory log durable; cold sessions need no barrier. Request abort + * and response-consumer cancellation share one producer signal and terminate + * the active compressor. + * Compression runs on the host with fflate's streaming Zip API, so the archive + * bytes are produced incrementally and the host never holds the whole archive + * in one buffer; production waits for consumer pull whenever the response queue + * reaches its byte high-water mark, so a slow consumer bounds accumulation to + * the fixed 64 KiB response queue plus one synchronous fflate push. + * @module + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { AttachmentStore } from '@deepseek-ai/dsh-attachment'; +import type { SessionQueryEngine } from '@deepseek-ai/dsh-session-query'; +import type { SessionId, SessionStore } from '@deepseek-ai/dsh-session'; +import type { SessionPersistence, SessionRawArtifact } from '@deepseek-ai/dsh-session-persistence'; +/** Valid fflate DEFLATE levels accepted by session-log export. */ +export type SessionLogCompressionLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; +/** Balanced default used when a direct createApiProxy caller omits deployment config. */ +export declare const DEFAULT_SESSION_LOG_COMPRESSION_LEVEL: SessionLogCompressionLevel; +/** The services a session-log export needs (the live-session store is optional). */ +export interface SessionLogExportDeps { + readonly sessionQuery: SessionQueryEngine | undefined; + readonly sessionPersistence: SessionPersistence | undefined; + readonly attachments: AttachmentStore | undefined; + readonly sessions: SessionStore | undefined; +} +/** The export services narrowed to the mounted ones streaming actually reads. */ +export interface SessionLogExportReady { + readonly sessionQuery: SessionQueryEngine; + readonly sessionPersistence: SessionPersistence; + readonly attachments: AttachmentStore; + readonly sessions: SessionStore | undefined; +} +/** + * Resolve the persistence, session-query, and attachment services a log export needs. + * @param ctx - the composed host context. + * @returns the export services (absent when the deployment does not mount them). + */ +export declare function sessionLogExportDeps(ctx: Context): SessionLogExportDeps; +/** + * Flush one currently live session through the store's authoritative durability + * barrier immediately before its raw artifact is read. A cold or absent id has + * no in-memory work to flush. + * @param deps - export services, including the optional live-session store. + * @param id - the session whose artifact is about to be read. + * @param signal - optional cancellation observed around the flush barrier. + */ +export declare function flushLiveSessionLog(deps: Pick, id: SessionId, signal?: AbortSignal): Promise; +/** One exported file: a stored artifact text or one referenced media object. */ +export type SessionLogZipEntry = { + readonly path: string; + readonly content: string; +} | { + readonly path: string; + readonly data: Uint8Array; +}; +/** + * The export archive filename for one root session. + * @param sessionId - the root session id (sanitized to one safe path segment). + * @returns the attachment filename for the session's export archive. + */ +export declare function sessionLogZipFilename(sessionId: string): string; +/** + * Yield the export entries in zip order: the preloaded root artifact first, + * then every subagent descendant in lineage order (each flushed when live, + * read from the persistence backend right before it is yielded, and dropped + * after the consumer moves on), then every distinct media object referenced by any of + * the included logs (read and verified from the attachment store, one archive + * entry per attachment id). The host holds at most one descendant's artifact + * text and one media object at a time beyond the root. + * @param deps - the mounted export services (the caller answered 500 before this runs). + * @param root - the already-read root artifact (read by the caller so the + * missing-session path can answer cleanly before streaming starts). + * @param sessionId - the root session id. + * @param includeDescendants - whether to include every subagent descendant. + * @param signal - optional cancellation forwarded to lineage, persistence, and attachment reads. + * @returns the export entries in zip order. + */ +export declare function sessionLogZipEntries(deps: SessionLogExportReady, root: SessionRawArtifact, sessionId: SessionId, includeDescendants: boolean, signal?: AbortSignal): AsyncGenerator; +/** + * Stream one session-log ZIP as a WHATWG ReadableStream. The root artifact is + * read and validated by the caller before this is called (missing root or + * missing services answer cleanly before any byte is produced); each entry is + * then encoded and deflated in bounded chunks as it is produced, so the + * archive bytes arrive incrementally. A descendant that fails to read errors + * the stream (fail-loud, never silent under-export). + * @param deps - the mounted export services (the caller answered 500 before this runs). + * @param root - the already-read root artifact (first zip entry). + * @param sessionId - the root session id. + * @param includeDescendants - whether to include every subagent descendant. + * @param compressionLevel - validated fflate DEFLATE level for every ZIP entry. + * @param signal - request cancellation combined with response-consumer cancellation. + * @returns the zip byte stream. + */ +export declare function streamSessionLogZip(deps: SessionLogExportReady, root: SessionRawArtifact, sessionId: SessionId, includeDescendants: boolean, compressionLevel: SessionLogCompressionLevel, signal: AbortSignal): ReadableStream; +//# sourceMappingURL=session-export.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.js new file mode 100644 index 0000000..0ce469c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.js @@ -0,0 +1,388 @@ +/** + * Host-side session-log download: streams one ZIP archive whose files are the + * sessions' stored artifact text verbatim plus every referenced media object. + * The root artifact sits under its original base name (`session.jsonl`); each + * subagent descendant under `subagents//`; each image referenced + * by any included log under `media/.` (content-addressed, + * so one archive never duplicates a shared image). No manifest is written — + * every file is byte-identical to the backend's durable artifact or attachment + * store and self-describing through its own header line or media type. Before + * each live session's artifact read, the SessionStore flush barrier makes the + * current in-memory log durable; cold sessions need no barrier. Request abort + * and response-consumer cancellation share one producer signal and terminate + * the active compressor. + * Compression runs on the host with fflate's streaming Zip API, so the archive + * bytes are produced incrementally and the host never holds the whole archive + * in one buffer; production waits for consumer pull whenever the response queue + * reaches its byte high-water mark, so a slow consumer bounds accumulation to + * the fixed 64 KiB response queue plus one synchronous fflate push. + * @module + */ +import { Zip, ZipDeflate } from 'fflate'; +/** Balanced default used when a direct createApiProxy caller omits deployment config. */ +export const DEFAULT_SESSION_LOG_COMPRESSION_LEVEL = 6; +/** + * Resolve the persistence, session-query, and attachment services a log export needs. + * @param ctx - the composed host context. + * @returns the export services (absent when the deployment does not mount them). + */ +export function sessionLogExportDeps(ctx) { + return { + sessionQuery: ctx.get('sessionQuery'), + sessionPersistence: ctx.get('sessionPersistence'), + attachments: ctx.get('attachments'), + sessions: ctx.get('sessions'), + }; +} +/** + * Flush one currently live session through the store's authoritative durability + * barrier immediately before its raw artifact is read. A cold or absent id has + * no in-memory work to flush. + * @param deps - export services, including the optional live-session store. + * @param id - the session whose artifact is about to be read. + * @param signal - optional cancellation observed around the flush barrier. + */ +export async function flushLiveSessionLog(deps, id, signal) { + signal?.throwIfAborted(); + const sessions = deps.sessions; + if (sessions === undefined) + return; + const session = sessions.get(id); + if (session === undefined) + return; + await sessions.flush(session); + signal?.throwIfAborted(); +} +/** Zip extension for each accepted raster media type. */ +const MEDIA_TYPE_EXTENSIONS = { + 'image/png': 'png', + 'image/jpeg': 'jpg', + 'image/webp': 'webp', + 'image/gif': 'gif', +}; +/** + * The zip path for one media object: content-addressed by the opaque + * attachment id so shared images land once and the id in the log maps back to + * the archive entry without a manifest. + * @param ref - the durable reference from a session log. + * @returns the archive path. + */ +function mediaEntryPath(ref) { + return `media/${String(ref.attachmentId)}.${MEDIA_TYPE_EXTENSIONS[ref.mediaType]}`; +} +/** + * Collect every image reference inside one content array, descending into + * nested tool results the way the live attachment route does. + * @param content - an event content array (or nested tool-result content). + * @param refs - the dedupe map being filled (keyed by attachment id). + */ +function collectImageRefs(content, refs) { + if (!Array.isArray(content)) + return; + const pending = []; + for (const item of content) + pending.push(item); + while (pending.length > 0) { + const value = pending.pop(); + if (typeof value !== 'object' || value === null || Array.isArray(value)) + continue; + const block = value; + if (block.type === 'image' && typeof block.attachment === 'object' && block.attachment !== null) { + const ref = block.attachment; + refs.set(String(ref.attachmentId), ref); + } + if (Array.isArray(block.content)) { + for (const item of block.content) + pending.push(item); + } + } +} +/** + * Collect every image reference one session event carries, across the same + * carriers the live attachment route scans (direct content, message content, + * inserted messages, and completed assistant chunk blocks). + * @param event - one parsed JSONL event object. + * @param refs - the dedupe map being filled (keyed by attachment id). + */ +function collectEventImageRefs(event, refs) { + const data = event.data; + if (typeof data !== 'object' || data === null) + return; + const carrier = data; + collectImageRefs(carrier.content, refs); + if (carrier.message !== undefined) + collectImageRefs(carrier.message.content, refs); + if (carrier.inserted !== undefined) { + for (const message of carrier.inserted) + collectImageRefs(message.content, refs); + } + if (carrier.chunk?.type === 'block-end') + collectImageRefs([carrier.chunk.block], refs); +} +/** + * Collect the distinct media references one stored artifact text names. + * Lines that fail to parse cannot reference media and are skipped (the + * artifact text itself is exported verbatim regardless). + * @param content - the stored artifact text. + * @returns the dedupe map keyed by attachment id. + */ +function imageRefsInArtifact(content) { + const refs = new Map(); + for (const line of content.split('\n')) { + if (line === '') + continue; + let event; + try { + event = JSON.parse(line); + } + catch { + continue; + } + collectEventImageRefs(event, refs); + } + return refs; +} +/** + * One safe zip path segment from an untrusted session id. Session ids are + * host-controlled, but the brand allows any non-empty string, so `../`, dot + * segments, and separator characters are neutralized before they can shape + * archive entries. Distinct ids may collapse onto one segment (id collision + * is impossible for the host-minted UUIDs, so no uniqueness suffix is kept). + * @param id - the raw session id. + * @returns a filesystem-safe single path segment. + */ +function safeSessionIdSegment(id) { + return id.replace(/[^A-Za-z0-9_-]/g, '_'); +} +/** + * The export archive filename for one root session. + * @param sessionId - the root session id (sanitized to one safe path segment). + * @returns the attachment filename for the session's export archive. + */ +export function sessionLogZipFilename(sessionId) { + return `dsh-session-${safeSessionIdSegment(sessionId)}.zip`; +} +/** + * Yield the export entries in zip order: the preloaded root artifact first, + * then every subagent descendant in lineage order (each flushed when live, + * read from the persistence backend right before it is yielded, and dropped + * after the consumer moves on), then every distinct media object referenced by any of + * the included logs (read and verified from the attachment store, one archive + * entry per attachment id). The host holds at most one descendant's artifact + * text and one media object at a time beyond the root. + * @param deps - the mounted export services (the caller answered 500 before this runs). + * @param root - the already-read root artifact (read by the caller so the + * missing-session path can answer cleanly before streaming starts). + * @param sessionId - the root session id. + * @param includeDescendants - whether to include every subagent descendant. + * @param signal - optional cancellation forwarded to lineage, persistence, and attachment reads. + * @returns the export entries in zip order. + */ +export async function* sessionLogZipEntries(deps, root, sessionId, includeDescendants, signal) { + const media = new Map(); + const rememberMedia = (content) => { + for (const [id, ref] of imageRefsInArtifact(content)) + media.set(id, ref); + }; + rememberMedia(root.content); + yield { path: root.filename, content: root.content }; + if (includeDescendants) { + const seen = new Set([sessionId]); + const collect = async function* (nodes) { + for (const node of nodes) { + signal?.throwIfAborted(); + const id = node.session.header.id; + if (seen.has(id)) + continue; + seen.add(id); + await flushLiveSessionLog(deps, id, signal); + const raw = await deps.sessionPersistence.readRaw(id, signal); + signal?.throwIfAborted(); + if (raw === undefined) { + throw new Error(`subagent "${id}" has no stored log artifact`); + } + rememberMedia(raw.content); + yield { + path: `subagents/${safeSessionIdSegment(id)}/${raw.filename}`, + content: raw.content, + }; + yield* collect(node.descendants); + } + }; + const lineage = await deps.sessionQuery.traceSession(sessionId, signal); + signal?.throwIfAborted(); + yield* collect(lineage.descendants); + } + for (const ref of media.values()) { + signal?.throwIfAborted(); + const stored = await deps.attachments.readImage(ref, signal); + signal?.throwIfAborted(); + yield { path: mediaEntryPath(ref), data: stored.data }; + } +} +/** How many code units of artifact text one zip push carries (bounded encode memory). */ +const PUSH_CHUNK_CODE_UNITS = 1 << 16; +/** How many bytes of media one zip push carries (bounded memory; images are already size-capped). */ +const PUSH_CHUNK_BYTES = 1 << 16; +/** Byte capacity retained by the response stream before ZIP production waits for pull. */ +const RESPONSE_HIGH_WATER_MARK_BYTES = 1 << 16; +/** One producer waiter released only when ReadableStream pull restores capacity. */ +class ResponseCapacityGate { + releasePending; + /** + * Wait until the response queue has positive byte capacity or cancellation wins. + * @param controller - response controller whose desired size owns capacity. + * @param signal - combined request/consumer cancellation. + */ + async wait(controller, signal) { + signal.throwIfAborted(); + if (controller.desiredSize === null || controller.desiredSize > 0) + return; + await new Promise((resolve) => { + const release = () => { + this.releasePending = undefined; + signal.removeEventListener('abort', release); + resolve(); + }; + this.releasePending = release; + signal.addEventListener('abort', release, { once: true }); + }); + signal.throwIfAborted(); + } + /** Release the current producer waiter after a consumer pull. */ + pulled() { + this.releasePending?.(); + } +} +/** + * Push one media object's bytes into a deflate stream in bounded chunks, + * waiting for consumer capacity between chunks like the artifact path does. + * @param deflate - the zip entry's deflate stream. + * @param data - the stored image bytes. + * @param controller - response queue controller. + * @param capacity - pull-driven response-capacity gate. + * @param signal - cancellation; throws when aborted. + */ +async function pushBinaryChunks(deflate, data, controller, capacity, signal) { + let offset = 0; + do { + signal.throwIfAborted(); + const end = Math.min(offset + PUSH_CHUNK_BYTES, data.byteLength); + const finalChunk = end >= data.byteLength; + deflate.push(data.subarray(offset, end), finalChunk); + offset = end; + await capacity.wait(controller, signal); + } while (offset < data.byteLength); +} +/** + * Push one artifact's text into a deflate stream in bounded chunks, never + * splitting a surrogate pair across a chunk boundary (a lone high surrogate + * re-encodes as U+FFFD and would silently corrupt the exported artifact). + * @param deflate - the zip entry's deflate stream. + * @param content - the artifact text verbatim. + * @param controller - response queue controller. + * @param capacity - pull-driven response-capacity gate. + * @param signal - cancellation; throws when aborted. + */ +async function pushArtifactChunks(deflate, content, controller, capacity, signal) { + const encoder = new TextEncoder(); + let offset = 0; + let finalChunk; + do { + signal.throwIfAborted(); + let end = Math.min(offset + PUSH_CHUNK_CODE_UNITS, content.length); + if (end < content.length && end - offset > 1) { + // Back off one code unit when the boundary lands inside a surrogate + // pair: the pair then starts the next chunk whole. + const last = content.charCodeAt(end - 1); + if (last >= 0xd800 && last <= 0xdbff) + end -= 1; + } + finalChunk = end >= content.length; + deflate.push(encoder.encode(content.slice(offset, end)), finalChunk); + offset = end; + await capacity.wait(controller, signal); + } while (!finalChunk); +} +/** + * Stream one session-log ZIP as a WHATWG ReadableStream. The root artifact is + * read and validated by the caller before this is called (missing root or + * missing services answer cleanly before any byte is produced); each entry is + * then encoded and deflated in bounded chunks as it is produced, so the + * archive bytes arrive incrementally. A descendant that fails to read errors + * the stream (fail-loud, never silent under-export). + * @param deps - the mounted export services (the caller answered 500 before this runs). + * @param root - the already-read root artifact (first zip entry). + * @param sessionId - the root session id. + * @param includeDescendants - whether to include every subagent descendant. + * @param compressionLevel - validated fflate DEFLATE level for every ZIP entry. + * @param signal - request cancellation combined with response-consumer cancellation. + * @returns the zip byte stream. + */ +export function streamSessionLogZip(deps, root, sessionId, includeDescendants, compressionLevel, signal) { + const consumerAbort = new AbortController(); + const producerSignal = AbortSignal.any([signal, consumerAbort.signal]); + let zip; + let zipTerminated = false; + const capacity = new ResponseCapacityGate(); + const terminateZip = () => { + if (zip === undefined || zipTerminated) + return; + zipTerminated = true; + zip.terminate(); + }; + return new ReadableStream({ + start(controller) { + // fflate invokes the callback synchronously per compressed chunk, so a + // single push can enqueue ahead of a slow consumer; the capacity gate + // waits for pull between pushes once the byte queue is full, bounding + // accumulation to the queue high-water mark plus one synchronous push. + const archive = new Zip((error, data, final) => { + /* v8 ignore next 3 -- fflate reports only internal zip failures, unreachable for valid inputs */ + if (error) { + controller.error(error); + return; + } + /* v8 ignore next -- fflate may emit empty chunks; not controllable from tests */ + if (data.byteLength > 0) + controller.enqueue(data); + if (final) + controller.close(); + }); + zip = archive; + void (async () => { + try { + for await (const entry of sessionLogZipEntries(deps, root, sessionId, includeDescendants, producerSignal)) { + const deflate = new ZipDeflate(entry.path, { level: compressionLevel }); + archive.add(deflate); + if ('content' in entry) { + await pushArtifactChunks(deflate, entry.content, controller, capacity, producerSignal); + } + else { + await pushBinaryChunks(deflate, entry.data, controller, capacity, producerSignal); + } + } + archive.end(); + } + catch (error) { + // A mid-stream failure (missing descendant, cancellation, read + // error) must fail the download rather than ship a truncated archive. + /* v8 ignore next -- typed backends reject with Error, and DOMException is one in Node */ + terminateZip(); + controller.error(error instanceof Error ? error : new Error(String(error))); + } + })(); + }, + pull() { + capacity.pulled(); + }, + cancel(reason) { + consumerAbort.abort(reason instanceof Error ? reason : new Error('session log export stream cancelled')); + terminateZip(); + }, + }, { + highWaterMark: RESPONSE_HIGH_WATER_MARK_BYTES, + size: chunk => chunk.byteLength, + }); +} +//# sourceMappingURL=session-export.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/package.json new file mode 100644 index 0000000..8cc7d6d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-apiproxy/package.json @@ -0,0 +1,93 @@ +{ + "name": "@deepseek-ai/dsh-host-apiproxy", + "description": "API gateway: the ApiProxy contract (api/), the fetch carrier pair (fetch/), and the host-side gateway plugin providing ctx.apiProxy", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/host/apiproxy" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json", + "./api": { + "types": "./lib/types/api/index.d.ts", + "default": "./lib/types/api/index.js" + }, + "./api/*": { + "types": "./lib/types/api/*.d.ts", + "default": "./lib/types/api/*.js" + }, + "./client": { + "types": "./lib/types/fetch/client.d.ts", + "default": "./lib/types/fetch/client.js" + } + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "fflate": "^0.8.2", + "zod": "^4.4.3", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.6", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.6", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.6", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.6", + "@deepseek-ai/dsh-native-command": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.6", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.6", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.6", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.6", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.6", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.6", + "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6", + "@deepseek-ai/dsh-workspace": "^0.1.0-rc.6", + "@deepseek-ai/schemastery": "^3.18.1", + "@deepseek-ai/dsh-session-query": "^0.1.0-rc.6" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-directory-picker b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-directory-picker new file mode 120000 index 0000000..82acc8f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-host-directory-picker @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-jobs b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-jobs new file mode 120000 index 0000000..e453c9c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-jobs @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-native-command b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-native-command new file mode 120000 index 0000000..b83e5a0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-native-command @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..a0535b0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..fb5edd1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-projection-cache b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-projection-cache new file mode 120000 index 0000000..4edc1ab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-projection-cache @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-query b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-query new file mode 120000 index 0000000..05cbba2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-query @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-title b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-title new file mode 120000 index 0000000..f2e65bb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-session-title @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-settings b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-settings new file mode 120000 index 0000000..810b363 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-settings @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-skill b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-skill new file mode 120000 index 0000000..381aed6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-skill @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-subagent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-subagent new file mode 120000 index 0000000..c407abb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-subagent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-tools b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-tools new file mode 120000 index 0000000..49af432 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-tools @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-user-approval b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-user-approval new file mode 120000 index 0000000..fd6eee4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-user-approval @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-user-questions b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-user-questions new file mode 120000 index 0000000..e74a1dc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-user-questions @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-workspace b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-workspace new file mode 120000 index 0000000..0a486b1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/dsh-workspace @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/fflate b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/fflate new file mode 120000 index 0000000..bb2f645 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/fflate @@ -0,0 +1 @@ +../../fflate@0.8.3/node_modules/fflate \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_e9efce95e5e57cd2168691beebd30eb1/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent-default-model b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent-default-model new file mode 120000 index 0000000..d9509fa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent-default-model @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent-presets b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent-presets new file mode 120000 index 0000000..dff57a0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-agent-presets @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-api-remotes b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-api-remotes new file mode 120000 index 0000000..1ea0a49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-api-remotes @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-attachment b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-attachment new file mode 120000 index 0000000..dc64562 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-attachment @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-commands b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-commands new file mode 120000 index 0000000..75a57f5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-commands @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-cordis-host-runner b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-cordis-host-runner new file mode 120000 index 0000000..a8f80c4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-cordis-host-runner @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-credentials b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-credentials new file mode 120000 index 0000000..a0353d6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-credentials @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-goal b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-goal new file mode 120000 index 0000000..0ededa6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-goal @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.i18n.yaml new file mode 100644 index 0000000..5826f75 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/host/apiproxy/README.md +README.md: 607cd4e4176631b64daf4a298b5d86a75ccdce68 +README.zh.md: cdfb5aa65b3ad5b00596487aae6c99e2f9d4e433 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.md new file mode 100644 index 0000000..607cd4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.md @@ -0,0 +1,83 @@ +# @deepseek-ai/dsh-host-apiproxy + +English | [中文](README.zh.md) + +The API gateway shared by every client consists of the TypeScript API contract (`src/api/`, zero Node dependencies, importable from the browser), the fetch carrier pair (`src/fetch/`: `toFetchHandler` on the host side, `AbstractApiClient` plus platform subclasses on the client side), and the host-side implementation (`src/api-proxy.ts`: `createApiProxy` plus the default-exported `ApiProxyService` gateway plugin — config `{nativeOpen?, sessionExportCompressionLevel?, coldBlankProbeMaxBytes?}`, provides `ctx.apiProxy`). This package registers no routes; carriers such as HTTP wrap `ctx.apiProxy` themselves. The shipped Web composition lives in [`packages/bundle/web-app/cordis.patch.yml`](../../bundle/web-app/cordis.patch.yml), while its default Agent model selection belongs to [`@deepseek-ai/dsh-agent-default-model`](../../core/agent-default-model/README.md) in the base bundle. + +## The shared Agent default (`agent-default-model` Settings section) + +`ApiProxyService` consumes `ctx.agentDefaultModel`; it does not own a provider/model config or settings section. The shared service registers `{provider, model, reasoningEffort?}` under `agent-default-model`: the base bundle's composition entry is the lower layer and `settings.yaml` layers the user's choice over it. + +A session resolves its model selection from three tiers on every access: a selection made in this process, otherwise the session's latest logged `request/header`, otherwise this default. A session that has run a turn derives its selection from its log, while a blank session observes a default saved after it was created. + +`session.selectModel` saves an accepted switch as the deployment default; there is no separate gesture. It stores the resolved `ModelSelection`, including an adapter-materialized default effort. The complete-section write clears a stored effort when the selected model has none. A storage failure is logged without undoing the session selection. A deployment with no settings provider keeps the composition entry and the switch remains session-local. + +The section's `reasoningEffort` has no counterpart in the agent-default-model plugin config, deliberately: the seam merges the user layer over the composition entry per field, so an absent key cannot override a present one and a composition-set effort would survive every later switch to a model without one. A deployment default for effort belongs on the adapter profile, which resolves per model. + +The stored selection is independent of catalog membership. A default naming an unavailable provider still reaches `session.models` as the session's `current`, allowing the selector to request a replacement instead of silently choosing another model. Conversely, an adapter may serve a model that its catalog does not advertise. + +## Contract layer (`/api`) + +Wire messages form a four-quadrant discriminated union — who initiates × request/response — decoupled from the physical channel: `ClientRequest` (POST `/api/` body), `ServerResponse` (that POST's response body), `ServerRequest` (SSE frame), `ClientResponse` (POST `/api/respond` body). Responses always echo the matching request's `rpcId` and never mint a new one. Method parameter/return structures live only in the domain interface signatures (`SessionsApi`, `HostApi`, `EventsApi`); `RpcMethodMap` registers the methods and every other position derives via `RequestPayload`/`ResponseValue`. Zod schemas anchor `satisfies z.ZodType>` and parse at two levels: envelope first, business payload second, dispatched per method. Business errors ride `RpcResult`'s error branch (`RpcErrorDetailsMap` closes the code set); HTTP status expresses only the carrier. Every `/api` POST must declare the `application/json` media type — anything else is refused with 415 before dispatch, so cross-site "simple" requests (which browsers send without a CORS preflight) can never execute a side-effectful method blind. + +The layering/protocol decisions are recorded in the [GUI layering and RPC protocol RFC](../../../.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md); the browser-side consumption architecture in the [web client architecture RFC](../../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md). + +Question responses are validated against their pending request before the first answer claims it. A multi-select item may carry both requested option labels in `selected` and non-empty `custom` text; a single-select item must use one or the other. Duplicate labels, unknown labels, mismatched ids, incomplete batches, and empty custom text are rejected as `bad-response`. + +`session.history` reads an attached Session in memory or inspects a cold log through persistence without resuming or publishing an Agent, then pages on append-origin message boundaries. `maxMessages` counts `user/message` and `assistant/message` events that entered the surface by appending, so a model-only replacement copy consumes no quota. Each page stays one contiguous raw event range, which keeps a compaction's log-only `compaction/summary` record on the same page as the replacement that cites it. + +`session.history`'s tail page (`beforeSeq` absent) additionally carries an optional `projections` block — the watermark snapshot of every unit registered on `ctx.sessionProjections` (`@deepseek-ai/dsh-session-projection`), with `asOfSeq` = the last event seq the values reflect (`-1` on an empty log). The gateway also subscribes to the registry's change feed and mints a `session/projection` mux frame per changed unit (`{sessionId, key, value, seq}` — live push state, never logged; clients hold one generic per-session value store under higher-seq-wins). The carrier holds no other domain's knowledge (each value passed its unit's own schema inside the registry; the wire schemas keep `values`/`value` wide); loadOlder pages never carry the block, and a composition without the registry serves histories without either surface. The gateway owns two units: `sessionListMetadata` caches the monotonic blank-to-nonblank transition and latest human prompt time used by `session.list`, while `imageLimits` publishes the attachments config enforced at prompt admission as a per-boot constant (`apply` keeps the state reference, so baselines alone carry it — no change frames) so clients can refuse an over-limit intake before submit and label upload affordances; the latter activates only while both the registry and the attachments service are composed. + +Session-log export is a host-only download surface, not an RPC: `GET /api/session.export?sessionId=…&includeDescendants=true` streams a ZIP whose files are each session's stored artifact text verbatim (the persistence backend's `readRaw` — exact durable bytes decoded from the physical encoding, never a reconstruction from parsed events), root under its original base name plus each subagent descendant under `subagents//`, and every image any included log references under `media/.` (read and verified from the attachment store; a shared image appears once). `HEAD` runs the same root preparation and returns its status and headers without a response body, so browser clients can detect pre-stream failures before handing the GET to the native download manager. Each live root or descendant crosses the authoritative `SessionStore.flush` durability barrier immediately before its raw artifact read; cold sessions have no in-memory work to flush. Compression runs on the host with fflate's streaming Zip API at validated `sessionExportCompressionLevel` 0–9 (default 6), so deployments can trade CPU and latency against archive size; the response is chunked as it is produced and the host never holds the whole archive in one buffer. Once the response queue reaches its 64 KiB byte high-water mark, production waits until consumer pull restores positive capacity; fflate's synchronous callback can overshoot that bound only by the output of one bounded input push. Request abort and response-body cancellation stop lineage and artifact work, terminate the active compressor, and propagate as cancellation rather than an HTTP 500. It requires the persistence, session-query, and attachment services: a deployment without any answers 500, a persistence backend without per-session raw artifacts answers 501, a missing root session answers 404, and a descendant without a stored artifact or a referenced image that cannot be read fails the stream (fail-loud, never silent under-export). The carrier mounts the endpoint; `ApiProxy.downloads.sessionLog` implements it. + +Session titles ride the generic projection pair like every other domain — the history-tail `projections` block plus `session/projection` frames under the `title` key. Titles do not join `session.list`; cold sessions remain metadata-only there until opening or resuming attaches their logs. `session.rename` accepts an explicit user title (resuming a cold session first), delegating to `ctx.sessionTitle.rename` — the accepted `session/title` event pins the title against automatic regeneration — and returns the normalized title plus its event seq so a client settles its `title` projection cell ahead of the push frame; a title that normalizes to empty returns `title-invalid`. + +`session.fork` maps an optional event anchor to the first `turn/end` at or after it, letting a message action include that message's whole turn. An omitted or past-end anchor selects the last completed turn; an in-log anchor whose turn remains open returns `fork-unavailable` rather than clipping backward. The published child inherits the source's seeded history, cwd, latest logged `ModelSelection`, and lineage before joining the source Workspace. If Workspace attachment fails, `workspace-attach-failed` carries the already-published child id so clients can reconcile it. The [SessionStore fork decision](../../../.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.md) records why the anchor maps to that `turn/end`. + +Session model selection is a session-domain contract. `session.models` returns the current `ModelSelection` separately from provider-grouped advisory models, exact-model reasoning metadata, and provider-local lookup failures. The selection may be absent from the groups and is never injected as a synthetic row; clients can prompt for another selection without turning the directory into a routing whitelist. `session.selectModel` validates the optional adapter-owned reasoning effort and assigns the complete selection for the next prompt assembly. Catalog membership is not validation: an adapter may resolve an unlisted model, while an unavailable provider or unsupported effort returns `model-unavailable`. `session.models` additionally reports `routable`: whether an adapter currently serves the selected provider. This is deliberately not derivable from the groups because an adapter may serve an unadvertised model. `session.prompt` refuses on the same fact with `model-unavailable` before opening a turn; a disabled composer is a client affordance, and the method remains callable. + +`session.prompt` and `subagent.prompt` accept optional request-local `clientTimeZone` provenance. When present, the Host validates and canonicalizes `UTC` or an IANA Area/Location before Agent entry, rejects invalid input with `invalid-time-zone`, and records the canonical value on that exact `user-rpc` message beside its `rpcId`. The value is not Session, connection, create, resume, or fork state; non-browser callers may omit it. + +Pending queued input is a live control-plane contract, not conversation history. The gateway derives the complete `next-turn` queue from durable `agent/inbox/spliced` mutations and broadcasts authoritative `session/queue` snapshots after each change and on reconnect; pending `next-step` steering stays outside this Web projection. Within `next-step`, user-origin messages carry the `steering` placement while injected context (approval notices, task completion, attached snapshots) carries `context` and is not surfaced until claimed. The message-local `agent/inbox/inserted`, `claimed`, and `discarded` notifications remain available to lifecycle observers but do not build the queue view. `session.updateQueue` addresses one `MessageId`; edit and remove mutate the attached Agent through `Inbox.splice()`. A claim's pure deletion splice wins races before pre-step admission, so a later operation returns `queue-item-not-found`. `session.cancel` aborts only the active turn and preserves pending inbox work; after cancellation reaches quiescence and the closing turn flushes, AgentLoop claims the next waking message in FIFO order, and the browser never resends or promotes it. Queue operations never resume a cold session, and the client never infers retirement from turn or status events. + +Background jobs ride the same live-push posture. When `ctx.jobs` is composed, the gateway subscribes to its change feed and broadcasts a whole `session/jobs` snapshot after every registry commit that alters what a session can see — registration, the stopping transition, settlement, and owner-disposal removal — plus a subscription baseline for each session that already has tasks (an absent baseline is the empty set; a change that empties a set still sends `[]`). A change carrying an owner reads through that exact `Agent`, so a push stays correct while its scope tears down; the baseline reads `ctx.agents.get(sessionId)`, which yields only unowned tasks for a session with no live Agent and never resumes a cold one. An unowned change fans out to every subscribed session, because unowned tasks are visible to every caller. The wire `JobView` drops `ownerSession`, `reported`, and `outputLimitBytes`: the frame's own `sessionId` carries the first, and the other two are internal notice and model-presentation policy. A composition without the registry emits no such frames. + +Workspace and Session lists are separate reconnect baselines. `workspace.create({ path })` adopts an existing canonical directory and permits basename-derived titles to repeat. `workspace.insertBefore({ workspaceId, beforeWorkspaceId? })` commits one registry-order move and answers the complete order; a pure reorder emits `host/workspace-order-changed` with that complete order, while unknown sources or anchors return `workspace-not-found`. `workspace.delete` removes only the Workspace registration, `session.create` accepts an optional preallocated Session id, and `host/workspace-changed`, `host/workspace-removed`, plus `host/session-added` carry committed increments in either arrival order. `workspace.archiveSession` adds one session to the registry-global archive set and answers the full updated set; `workspace.list` carries that set as the reconnect baseline and `host/archived-sessions-changed` pushes the full snapshot after every durable change. Archiving hides the session from grouping surfaces without touching its log or its workspace account; a session neither live nor persisted fails with `session-not-found`. Registration deletion preserves the directory and session logs; its Sessions remain in `session.list` and become Ungrouped. `SessionSummary.blank` and the `host/session-added` frame carry whether a turn has started: clients hide blank sessions and reuse them per workspace, flip blank on the first `host/session-status(running:true)`, and treat `session.list` as the reconnect authority. Attached summaries fold the live log. A cold summary trusts cached `blank: false`, but treats cached `true` and a cache miss as unverified; when `locate()` reports an artifact no larger than the `coldBlankProbeMaxBytes` eligibility threshold (default 1 KiB), the gateway reads that Session with `readFrom()` and folds both blankness and the latest human prompt. A larger, location-less, vanished, or unreadable artifact remains visible. After an asynchronous cold read, a Session that attached meanwhile is summarized from its live log instead. `updatedAt` uses the live fold, the exact small-artifact fold, or the projection cache in that order, falling back to `createdAt`; pickup boundaries and other writes never promote a Session. + +`session.search` is a bounded content-search projection over the sessions visible through `session.list`. The gateway asks the optional `ctx.sessionQuery` service for globally ranked current-surface user, assistant, and steering matches, consumes that stream until it has at most 20 visible session/snippet pairs plus one lookahead, and revalidates every hit against the list-derived authorization set before returning it. Provider pages start at 20 hits; when a first-page request rejects that limit, the gateway probes 10, 5, 2, then 1 and retains the learned size for continuation and stale-generation restarts. Returned snippets contain at most 240 Unicode code points, and the response schema independently enforces that bound at each client boundary. Keeping the authorization set in Host memory avoids SQLite's variable ceiling for large valid corpora without weakening visibility or ranking. + +A stale continuation discards every partial result, deduplication entry, and cursor from that provider attempt, then restarts at the first page against the original list-derived visibility snapshot without discarding the learned provider page size. Limit probes and stale retries share the same limit of at most 100 provider calls (and therefore at most 2,000 inspected hits); a page larger than its requested limit, a repeated continuation cursor, or a still-unexhausted stream at that call budget fails closed as an `internal` business error. The carrier request signal cancels persistence listing, cold-summary collection, and every search call, including a limit or stale rejection observed concurrently with cancellation. A deployment without the service, or any unrecovered index/query failure, also returns an `internal` business error so clients can retain metadata-only matches. + +Directory picking delegates to the composed `ctx.directoryPicker` backend ([the directory-picker seam](../directory-picker/README.md)); a method called outside the composed capability's kind fails with `directory-picker-unavailable` (the client needs no advertisement — the composed picker package's own client half renders the matching interaction). Under `native`, `host.pickDirectory` opens one native chooser and returns its selected path (`null` on cancel); this user-paced method does not use the default 30-second unary timeout, while caller/connection aborts still propagate to the native process. Under `browse`, `host.listDirectory` returns one name-sorted directory level with breadcrumb ancestry, a `home` anchor, and host-owned `hidden` flags (absent path = home directory), and `host.createDirectory` creates one validated child segment; the backend's typed failures map 1:1 onto the `directory-unreadable`/`directory-exists`/`directory-create-failed` codes. The browser carrier's prefix-wide trust fence (dsh-client-connection) covers all of these like every other `/api` request. + +`host.openPath` opens a filesystem path with the operating system's default application (`open` on macOS, `Invoke-Item` on Windows, and `xdg-open` on desktop Linux). For `.html`, `.htm`, `.xhtml`, and `.svg`, macOS and desktop Linux prefer a named default browser and fall back to that application handoff when none can be named. WSL translates every Linux path through `wslpath -w` and hands the resulting Windows/UNC path to Windows `Invoke-Item`, including browser-renderable documents, instead of assuming a Linux desktop association. `host.describe.canOpenPath` advertises whether that handoff can reach a user-visible desktop: explicit gateway `nativeOpen` wins, an injected opener is usable by definition, and platform detection otherwise accepts macOS, Windows, WSL, or Linux with a display while rejecting headless/container Linux. The browser carrier applies the same loopback, same-origin restriction as `host.pickDirectory`; clients combine both facts before presenting a native action. + +The `agentPreset.list` domain exposes the deployment's preset roster so a browser can offer a choice when starting a session; each row carries its `trust` (a `user` preset is exactly as privileged as the plugins it names), whether it is the current default, and — when the preset cannot compose a session — a `broken` reason, because a damaged directory still occupies its id and a surface must be able to show and delete it rather than offer it and fail the session start. A deployment composing no presets answers with an empty roster rather than an error, because sharing the host composition is a valid deployment. `agentPreset.select` recomposes one session's agent from a different preset, and is allowed only while the session is blank: once a turn has run, that history was produced under the preset's tools and swapping them would strand logged tool calls, so the attempt answers `agent-preset-locked`. The agent and the session survive — only the composition is swapped, and a failed swap restores the previous one. + +`agentPreset.read`, `copy`, `openDocument`, and `remove` manage the compositions themselves. `read` reports the text with its `trust`, for the read-only viewer. Authoring is copy-only: `copy` takes `{ from, agentPreset, name? }` — two ids the Host resolves against its own roots plus an optional display name — and copies the source's whole directory, so no composition text crosses the wire and a copy is exactly as loadable as its source; an uncontainable or already-taken id answers `agent-preset-invalid`, and `remove` refuses a shipped preset as `agent-preset-read-only`. `openDocument` hands one locally authored preset's DIRECTORY to the platform opener — the request carries an id, never a path, so no browser payload can select an arbitrary filesystem target; where the deployment has no native opener the reply is `{ opened: false, path }` for the surface to show as text, a shipped preset is refused like `remove`, and the gateway's `nativeOpen` config pins the capability where platform detection (`canOpenNativePath`) would mislead. These four are loopback-pinned in [`dsh-client-connection`](../../client/connection/README.md): a composition names the plugins a session runs, so reading one is reconnaissance, and copy/remove/openDocument manage the roster and drive the host desktop. `list` and `select` stay ordinary — the roster carries ids and trust and every preset picker needs it, and choosing a preset grants nothing `session.create`'s own `agentPreset` did not, over a default that already carries bash. `list` reports two path-free capability flags: `authorable`, whether the deployment configures a root a new preset could be copied to, and `hasDocument`, whether `openDocument` would open natively rather than answer a path. + +The `command.*` and `skill.*` domains expose the host command registry and skill catalog to clients. Every method addresses one session's agent by `sessionId` (a served session always has an Agent; `command.*` resumes cold sessions through the same path as `session.*`, while `skill.list` resolves the project root from the session header without touching the Agent registry). `skill.list` serves the composer's menu: it returns every user-invocable skill with its `modelInvocable` flag, so menus can mark user-only (`disable-model-invocation`) entries whose only invocation path is the slash gesture. Listing is the skill domain's only RPC — invocation itself is an ordinary `session.prompt` whose whitespace-bounded `/name` tokens `dsh-tool-skill` recognizes at the pre-step boundary and answers with injected `` context, so every entry point (Web, TUI, and ACP) shares one deterministic path—including for hand-typed text—with no dedicated invocation wire. `command.execute` runs a slash-command line host-side with pure admission semantics: the response reports whether the line resolved to a handler plus the minted lifecycle `commandId` when it did (correlating the acknowledgment with the flow node), while the outcome rides the durably logged `command/run`/`command/done` lifecycle pair broadcast on the mux stream. Command handlers may legitimately outlast the 30-second transport health deadline, so `command.execute` carries only caller/connection cancellation; that signal cancels the running handler. `commands/change` rides the forwarded-event frame as the registry-wide catalog invalidation signal: clients refetch `command.list` instead of diffing. Forwarded `agent-preset/selected` is its per-session counterpart, emitted from the logged selection commit: recomposing a blank session's agent re-parents its scope without registering anything, so both catalogs that session's composition decides (`command.list`, `skill.list`) go stale with no registry change to announce it. + +The `settings.*`, `credentials.*`, and `llm.*` domains are the configuration-page wire. The settings domain serves every registered namespace: a plugin distributed outside this repository becomes browser-configurable by registering its section, with no change here, and this proxy adds no boundary of its own — a name no registration answers folds into the seam's own `settings-rejected`. Which surface renders a namespace is the browser's decision (the plugin configuration page keys its cards on the namespace), never this proxy's. `settings.describe` returns each namespace's serialized schemastery schema, redacted layered values (resolved/`base`/`user` — a field's presence in `user` marks it user-overridden), the `secrets` slot list, the section's `revision`, and the boolean `hasDocument` capability flag. The browser receives no Host path: pathless `settings.openDocument` asks the provider to materialize its document and then hands the Host-resolved result to the native opener, so no browser payload can select any filesystem target. `settings.update`/`settings.replace` write the user layer; `settings.mutate` applies path ops (`set`/`unset`) against the section as stored, which is the removal path for a client holding the redacted view — rebuilding a section from it and replacing wholesale would delete the secrets the wire never returned. Any write may carry `expectedRevision`; a stale one answers `settings-conflict` with both revisions rather than overwriting the writer that landed first, and every other seam refusal folds into `settings-rejected`. Secret-role values never ride any response in any layer; a secret crosses the wire in exactly one direction — inside an `update`/`mutate` payload or `credentials.set`. `credentials.describe` returns value-free views (`configured`/`source`/`writable`), and `credentials.set`/`credentials.unset` map a shadowed-reference refusal onto `credential-rejected`. `llm.providers` merges the configurable-provider directory with live routes (dormant entries carry `active: false`; undeclared live routes append with no settings address) and `llm.models` is the session-independent catalog. `llm.discoverModels` interrogates a provider endpoint the page is still drafting: `settingsNs` selects the adapter family that knows how to read the listing, and the endpoint, protocol, and key come from the form rather than from storage. It writes nothing — the reply is candidates, and only a later `settings.mutate` decides what a route serves — so its `apiKey` is the third payload on which a secret may ride, alongside `settings.update`/`mutate` and `credentials.set`. The host never stores or returns it; like the other two it does ride the client's outgoing envelope, which `subscribeEnvelopes()` observers can see, and redacting that tap is a configuration-plane-wide change rather than this method's to make alone. Every refusal (an unserved namespace, a protocol with no readable listing, an unreachable endpoint, a rejected credential) folds into `model-discovery-failed`, whose message is the adapter's own text and whose details name the endpoint asked but never the credential offered. Invalidations keep every surface converged without polling. `settings/document-updated` and `credentials/updated` ride the verbatim forwarded-event frame (see below), so a raw settings change whose resolved value is unchanged still reaches clients, and a credential invalidation still carries reference names only, never values. `llm/adapters-updated` is forwarded beside `settings/document-updated`; concrete model consumers subscribe to both owner events directly because topology commits and settings documents can independently change their directories. The browser carrier restricts the whole configuration plane, reads and native actions included (`settings.describe`/`openDocument`/`update`/`replace`/`mutate`, `credentials.describe`/`set`/`unset`), to loopback same-origin requests — the `host.pickDirectory` privileged set. A composition without a settings or credential provider answers those domains with an actionable `internal` error naming the missing plugin. + +## Carrier layer (`/client` + root) + +`AbstractApiClient` holds every protocol invariant — rpcId minting, envelope wrap/unwrap, zod parsing, SSE frame decoding, unary timeout, microtask-batched envelope observation (`subscribeEnvelopes`) — while platform subclasses supply only the `doFetch` transport aspect. `InProcessApiClient` over `toFetchHandler(api)` remains the isomorphic point for callers and carrier tests that need the full wire serialization/validation path without a network. Product `dsh --profile headless` is a direct core entry point and does not mount this package. + +## Model Experience + +None, as the package defines the client↔host wire contract and carriers; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **Forwarded Remote events are parasitic on this legacy frame union** — `host/remote-event` lives in `HostFrame` so the delivery path could reuse the existing host stream instead of opening a third downlink, which makes it read as if this package owned the Remote event contract. It does not: the allowlist is `dsh-api-remotes`' and the consumer verb is `ctx.remote.$on`. When the host stream moves off this package, the frame moves with it and the consumer contract is unaffected ([rationale](../../../.agents/notes/implemented/architecture/2026-08-10-remote-event-delivery.md)). +- **Pending-interaction state is host-side** — the wire uses POST `/api/respond` plus `RpcReceipt`; the table in `src/api-proxy.ts` handles questions only and has no approval entries. +- **Reserved seams stay out of `RpcMethodMap`** — `prompt.mode: 'inject'`, `job.list`, and a describe `hostInstanceId` are documented reservations; model discovery uses `llm.models`. An unknown method fails loud at envelope parse rather than getting a not-implemented code. +- **No protocol version field** — client and host ship together; `host.describe` gains a version negotiation field only when an independently released client exists. +- **Search failures include provider diagnostics** — the gateway is a single-user local service. A carrier that exposes it to multiple users must replace internal search details with a public-safe diagnostic. +- **Linux native picker requires desktop tooling** — under the `native` capability, `host.pickDirectory` reports an actionable error when neither Zenity nor KDialog is installed; the browse backend is the composition-level fallback (see the [native backend README](../directory-picker-native/README.md)). +- **Cold-list hints degrade only toward visibility and older ordering** — a projection-cache miss or stale `lastPromptAt` falls back to `createdAt` unless an eligible small artifact supplies an exact fold, so a recently worked large Session may sort too low until the next checkpoint. A blank artifact larger than `coldBlankProbeMaxBytes`, or one from a backend without `locate()`, remains visible. The threshold is checked before `readFrom()` rather than enforced by persistence, so concurrent artifact growth may increase one probe's read cost without changing blankness safety. The [bounded blank-verification decision](../../../.agents/notes/implemented/bug-fix/2026-08-13-bounded-cold-blank-verification.md) owns this safety direction; an authoritative exact recency index remains scoped in the [last-activity-index proposal](../../../.agents/notes/proposed/architecture/2026-07-29-durable-last-activity-index.md). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.zh.md new file mode 100644 index 0000000..cdfb5aa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/README.zh.md @@ -0,0 +1,83 @@ +# @deepseek-ai/dsh-host-apiproxy + +[English](README.md) | 中文 + +所有客户端共用的 API 网关由三部分组成:TypeScript API 约定(`src/api/`,不依赖 Node,可从浏览器导入)、fetch 载体对(`src/fetch/`:宿主侧的 `toFetchHandler`,以及客户端侧的 `AbstractApiClient` 与平台子类)和宿主侧实现(`src/api-proxy.ts`:`createApiProxy` 加上默认导出的 `ApiProxyService` 网关插件,其配置为 `{nativeOpen?, sessionExportCompressionLevel?, coldBlankProbeMaxBytes?}`,提供 `ctx.apiProxy`)。该包不注册任何路由;HTTP 等载体自行包装 `ctx.apiProxy`。随发行版交付的 Web 组合位于 [`packages/bundle/web-app/cordis.patch.yml`](../../bundle/web-app/cordis.patch.yml),其默认 Agent(智能体)模型选择属于 base 组合包中的 [`@deepseek-ai/dsh-agent-default-model`](../../core/agent-default-model/README.md)。 + +## 共享 Agent 默认值(`agent-default-model` Settings 分节) + +`ApiProxyService` 消费 `ctx.agentDefaultModel`;它不持有提供方/模型配置或 Settings 分节。共享服务在 `agent-default-model` 下注册 `{provider, model, reasoningEffort?}`:base 组合包的组合条目是底层,`settings.yaml` 把用户选择叠加其上。 + +会话每次访问时都按三级解析模型选择:本进程内作出的选择,其次是该会话日志中最新的 `request/header`,最后是这个默认值。已经跑过一轮的会话从自己的日志推导选择,空白会话则能观察到创建之后保存的默认值。 + +`session.selectModel` 会把接受的切换保存为部署默认值;没有单独的选择动作。它存储已解析的 `ModelSelection`,包括适配器实体化的默认推理(reasoning)强度。完整分节写入会在所选模型没有推理强度时清除已存值。存储失败只记日志,不会撤销会话选择。没有设置提供方的部署保留组合条目,切换只对当前会话生效。 + +Settings 分节中的 `reasoningEffort` 在 agent-default-model 插件配置中刻意没有对应字段:seam 按字段把用户层合并到组合条目之上,因此缺席的键无法覆盖已有键,组合层中的推理强度会在以后选择没有推理强度的模型时继续存在。推理强度的部署默认值属于按模型解析的适配器 profile。 + +存储的选择独立于目录成员关系。默认值指向不可用的提供方时,它仍会作为会话的 `current` 送到 `session.models`,让选择器请求用户重新选择,而不是静默选用其他模型。反过来,适配器也可以服务其目录中未公布的模型。 + +## 约定层(`/api`) + +协议消息组成一个四象限可辨识联合:发起方 × 请求/响应,与物理通道解耦。四种消息分别是 `ClientRequest`(POST `/api/` 的请求体)、`ServerResponse`(该 POST 的响应体)、`ServerRequest`(SSE(Server-Sent Events)帧)和 `ClientResponse`(POST `/api/respond` 的请求体)。响应始终回显对应请求的 `rpcId`,绝不签发新值。方法的参数与返回值结构只存在于领域接口签名(`SessionsApi`、`HostApi`、`EventsApi`)中;`RpcMethodMap` 注册方法,其他所有位置均通过 `RequestPayload`/`ResponseValue` 派生。Zod schema 以 `satisfies z.ZodType>` 锚定类型,并分两层解析:先解析信封,再解析业务载荷,随后按方法分发。业务错误由 `RpcResult` 的错误分支承载(`RpcErrorDetailsMap` 封闭错误码集合);HTTP 状态只表达载体层结果。每个 `/api` POST 都必须声明 `application/json` 媒体类型——否则在分发前即以 415 拒绝,因此跨站「简单请求」(浏览器不经 CORS 预检就会发出)永远无法盲目执行有副作用的方法。 + +分层与协议决策记录在 [GUI 分层与 RPC 协议 RFC](../../../.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md) 中;浏览器侧消费架构记录在 [Web 客户端架构 RFC](../../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md) 中。 + +首个回答认领待处理请求之前,系统会对照该请求校验问题响应。多选题的回答项可以同时携带 `selected` 中的请求选项标签与非空 `custom` 文本;单选题的回答项必须二选一。标签重复、标签未知、id 不匹配、批次不完整以及自定义文本为空都会以 `bad-response` 拒绝。 + +`session.history` 会读取已附加 Session 的内存状态,或通过持久化检查冷日志,而不会恢复或发布 agent,然后按追加来源的消息边界分页:`maxMessages` 统计以追加方式进入 surface 的 `user/message` 和 `assistant/message` 事件,因此仅供模型使用的替换副本不占用配额。每一页仍是一段连续的原始事件区间,从而让压缩(compaction)的仅日志 `compaction/summary` 记录与引用它的替换留在同一页。 + +`session.history` 的尾页(不带 `beforeSeq`)额外携带一个可选的 `projections` 块——`ctx.sessionProjections`(`@deepseek-ai/dsh-session-projection`)上每个已注册单元的水位线快照,`asOfSeq` = 这些值共同反映到的最后一个事件 seq(空日志为 `-1`)。网关还订阅注册表的变更流,为每个状态发生变化的单元生成一个 `session/projection` mux 帧(`{sessionId, key, value, seq}`——实时推送状态,绝不入日志;客户端按 seq 高者胜维护一个按会话的通用值仓)。载体不持有其他领域的知识(每个值在注册表内部已过其单元自己的 schema;协议 schema 对 `values`/`value` 保持宽松);loadOlder 页永不携带该块,未装注册表的组合则两个面都不提供。网关拥有两个单元:`sessionListMetadata` 缓存用于 `session.list` 的单调 blank→nonblank 转换与最新真人 prompt 时间;`imageLimits` 则把 prompt 准入时执行的 attachments 配置作为每次启动恒定的值发布(`apply` 保持状态引用不变,因此只靠基线携带、绝不产生变更帧),供客户端在提交前拒绝超限的加入并给上传入口标注上限,后者仅在注册表与 attachments 服务同时组合时激活。 + +会话日志导出是宿主侧的下载面,不是 RPC:`GET /api/session.export?sessionId=…&includeDescendants=true` 流式返回一个 ZIP,其中每个文件都是会话存储工件的逐字原文(持久化后端的 `readRaw`——按物理编码解码的确切持久化字节,绝非从解析后事件重建),根会话放在其原始基础文件名下,每个子代理后代放在 `subagents//` 下,每个被任何包含的日志引用的图片放在 `media/.` 下(从附件存储读取并校验;共享图片只出现一次)。`HEAD` 会执行相同的根工件准备,并在没有响应 body 的情况下返回状态与响应头,使浏览器 Client 可以在把 GET 交给原生下载管理器前发现流式传输前的失败。每个实时根会话或后代都会在读取原始工件前立即通过权威的 `SessionStore.flush` 持久性屏障;冷会话没有需要 flush 的内存工作。压缩在宿主侧使用 fflate 流式 Zip API 和已验证的 `sessionExportCompressionLevel` 0–9(默认 6),使部署可以在 CPU/延迟与归档大小之间取舍;响应边生成边分块写出,宿主从不把整个归档放进单个缓冲区。响应队列达到 64 KiB 字节高水位后,生产会等待 Consumer pull 恢复正容量;fflate 的同步回调最多只会让该界限多出一次有界输入 push 的输出。请求中止或响应 body 取消会停止血缘与工件工作、终止活跃压缩器,并继续按取消传播,而不会变成 HTTP 500。它要求同时挂载持久化、session-query 与附件服务:任一缺失应答 500,持久化后端不提供每会话原始工件时应答 501,根会话缺失时应答 404,后代缺少存储工件或引用的图片无法读取则整个流失败(fail-loud,绝不静默少导出)。端点由传输层挂载,`ApiProxy.downloads.sessionLog` 实现它。 + +会话标题与其他所有领域一样搭乘这对通用投影机制——历史尾页的 `projections` 块外加 `title` 键下的 `session/projection` 帧。标题不会加入 `session.list`;冷会话在其中仍只有元数据,直到打开或恢复操作附加其日志。`session.rename` 接受用户显式标题(冷会话先恢复),委托给 `ctx.sessionTitle.rename`——被接受的 `session/title` 事件将标题钉住、不再被自动生成覆盖——并返回规范化后的标题及其事件 seq,让 client 在推送帧到达前就结算自己的 `title` 投影格;规范化后为空的标题返回 `title-invalid`。 + +`session.fork` 将可选事件锚点映射到该锚点处或其后的首个 `turn/end`,使消息操作可包含该消息所在的完整轮次。锚点省略或超过末尾时,选择最后一个已完成轮次;若锚点已在日志中,而其所在轮次仍开放,则返回 `fork-unavailable`,不会向较早位置裁剪。发布后的子会话会先继承源会话的种子历史、cwd、日志中最新的 `ModelSelection` 及谱系,再加入源 Workspace。如果附加到 Workspace 失败,`workspace-attach-failed` 会携带已发布的子会话 id,供客户端对账。[SessionStore fork 决策](../../../.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.md)记录了为何锚点要映射到该 `turn/end`。 + +会话模型选择属于会话领域约定。`session.models` 将当前 `ModelSelection` 与按提供方分组的建议性模型、精确模型的推理元数据和逐提供方查询失败记录分开返回。该选择可能不在这些分组中,也绝不会作为合成行注入;客户端可以提示用户作出另一项选择,而无需把目录变成路由白名单。`session.selectModel` 校验由适配器持有的可选推理强度,并指定下次组装提示词时使用的完整选择。目录成员关系不构成校验:适配器可以解析未列出的模型,而不可用的提供方或不受支持的推理强度会返回 `model-unavailable`。`session.models` 还会报告 `routable`,即当前是否有适配器为所选提供方提供服务。该值刻意不从分组推导,因为适配器可以服务未公布的模型。`session.prompt` 会依据同一事实,在开启轮次之前以 `model-unavailable` 拒绝;客户端禁用 composer 只是提示性设计,这个方法始终可被调用。 + +`session.prompt` 和 `subagent.prompt` 接受可选的请求本地 `clientTimeZone` 来源信息。若提供该值,Host 会在进入 Agent 前校验 `UTC` 或 IANA Area/Location 并将其规范化;无效输入以 `invalid-time-zone` 拒绝,规范值则与 `rpcId` 一起记录在这条确切的 `user-rpc` 消息上。该值不属于 Session、连接、create、resume 或 fork 状态;非浏览器调用方可以省略它。 + +待处理的 queued 输入属于实时控制平面约定,而非对话历史。网关根据持久 `agent/inbox/spliced` 变更派生完整的 `next-turn` 队列,并在每次变更后及重连时广播权威 `session/queue` 快照;待处理的 `next-step` steering(中途引导)不进入此 Web 投影。在 `next-step` 内,用户来源的消息携带 `steering` placement,而注入上下文(审批通知、任务完成、附加快照)携带 `context`,领取前不对外呈现。面向单条消息的 `agent/inbox/inserted`、`claimed` 与 `discarded` 通知仍供生命周期观察方使用,但不用于构建队列视图。`session.updateQueue` 通过 `MessageId` 寻址单个项;编辑和移除经已挂载 Agent 的 `Inbox.splice()` 修改队列。认领操作的纯删除 splice 会在 pre-step 准入前赢得竞态,因此之后的操作返回 `queue-item-not-found`。`session.cancel` 仅中止活动轮次并保留待处理 inbox 工作;取消达到完全停稳且结束中的轮次完成 flush 后,AgentLoop 按 FIFO 顺序认领下一条可唤醒消息,浏览器绝不重发或提升它。队列操作绝不恢复冷会话,客户端也绝不根据轮次或状态事件推断某项已退出队列。 + +后台任务沿用同一种实时推送姿态。当组合中有 `ctx.jobs` 时,网关订阅它的变更订阅,并在注册表每一次改变某个会话可见内容的提交后——注册、转入 stopping、结算,以及 owner 销毁时的移除——广播一份完整的 `session/jobs` 快照,另外为每个已经有任务的会话发送订阅 baseline(没有 baseline 即表示空集;把集合清空的那次变更仍然发送 `[]`)。带 owner 的变更通过那个确切的 `Agent` 读取,因此推送在其 scope 拆除期间依然正确;baseline 读 `ctx.agents.get(sessionId)`,对没有活体 Agent 的会话只得到无主任务,且绝不恢复冷会话。无主变更向每一个已订阅会话扇出,因为无主任务对所有调用方可见。线路上的 `JobView` 丢弃 `ownerSession`、`reported` 和 `outputLimitBytes`:第一个由帧自身的 `sessionId` 携带,另外两个分别是内部通知位和模型呈现策略。没有该注册表的组合不发出这类帧。 + +Workspace 列表与 Session 列表是相互独立的重连基线。`workspace.create({ path })` 会接纳已有的规范目录,并允许由 basename 派生的标题重复。`workspace.insertBefore({ workspaceId, beforeWorkspaceId? })` 提交一次注册表顺序移动并应答完整顺序;单纯重排序会通过 `host/workspace-order-changed` 推送同一份完整顺序,而未知来源或锚点返回 `workspace-not-found`。`workspace.delete` 只移除 Workspace 注册记录,`session.create` 接受可选的预分配 Session id,`host/workspace-changed`、`host/workspace-removed` 与 `host/session-added` 则以任意到达顺序携带已提交的增量。`workspace.archiveSession` 向注册表级全局归档集合添加一个会话,并应答完整的更新后集合;`workspace.list` 携带该集合作为重连基线,`host/archived-sessions-changed` 在每次持久变更后推送完整快照。归档只把会话从各分组视图中隐藏,不触碰其日志和 workspace 记账;既非活动会话也未持久化的会话以 `session-not-found` 失败。删除注册记录会保留目录和会话日志;相关 Session 仍留在 `session.list` 中,并进入 Ungrouped。`SessionSummary.blank` 与 `host/session-added` 帧携带是否已开始过轮次:客户端隐藏空白会话并按 workspace 复用它们,在首个 `host/session-status(running:true)` 时翻转 blank,并以 `session.list` 作为重连权威。已附加摘要折叠实时日志。冷摘要信任缓存的 `blank: false`,但把缓存的 `true` 与 cache miss 都视为未经验证;当 `locate()` 报告的工件不大于 `coldBlankProbeMaxBytes` 资格阈值(默认 1 KiB)时,网关通过 `readFrom()` 读取该 Session,同时折叠空白状态与最新真人 prompt。更大、无位置、已消失或不可读的工件保持可见。异步冷读取结束后,期间已附加的 Session 会改用实时日志生成摘要。`updatedAt` 依次采用实时折叠、小工件精确折叠或 projection cache,缺失时回退到 `createdAt`;拾起边界及其他写入都不会提升 Session 排序。 + +`session.search` 是以 `session.list` 所列会话为范围的有界内容搜索投影。网关向可选的 `ctx.sessionQuery` 服务请求全局排序后的当前内容视图中的 user、assistant 和 steering 匹配项,并持续消费该结果流,直到获得至多 20 个可见会话/snippet 对及一个前瞻项;返回前仍会依据从列表推导的授权集合重新校验每个命中。提供方分页初始请求 20 个命中;如果第一页请求因这一上限被拒绝,网关会依次探测 10、5、2、1,并在续传和陈旧世代重启中沿用探测所得的页面大小。返回的 snippet 最多包含 240 个 Unicode 码点,响应 schema 则会在每个客户端边界独立强制执行该上限。将授权集合保留在宿主内存中,可在不削弱可见性或排序的前提下避开有效大型语料库的 SQLite 变量上限。 + +陈旧的续传会丢弃该提供方尝试中的所有部分结果、去重条目和游标,然后依据最初从列表推导的可见性快照从第一页重新开始,但不会丢弃探测所得的提供方页面大小。上限探测与陈旧重试共用最多 100 次提供方调用的限制(因此最多检查 2,000 个命中);如果某页命中数超过其请求的上限、续传游标重复,或用尽该调用预算后结果流仍未耗尽,都会直接返回 `internal` 业务错误,不返回部分结果。载体请求信号可取消持久化列表枚举、冷会话摘要收集和每一次搜索调用;即使同时收到上限拒绝或陈旧拒绝,也以取消为准。部署若未挂载该服务,或索引/查询故障无法恢复,也会返回 `internal` 业务错误,以便客户端保留仅基于元数据的匹配项。 + +目录选择委托给组合的 `ctx.directoryPicker` 后端([目录选择 seam](../directory-picker/README.md));调用组合能力 kind 之外的方法会以 `directory-picker-unavailable` 失败(客户端不需要广播——组合的选择器包自己的 client half 渲染匹配的交互)。在 `native` 下,`host.pickDirectory` 打开一个原生选择器并返回选中路径(取消为 `null`);该方法需等待用户完成操作,不使用默认的 30 秒一元调用超时,而调用方与连接的中止仍会传播至原生进程。在 `browse` 下,`host.listDirectory` 返回一个按名称排序的目录层级,携带面包屑祖先链、`home` 锚点与宿主判定的 `hidden` 标志(不带路径即家目录),`host.createDirectory` 创建一个经校验的子段;后端的类型化失败 1:1 映射为 `directory-unreadable`/`directory-exists`/`directory-create-failed` 错误码。浏览器载体的前缀级信任栅栏(dsh-client-connection)像覆盖其他所有 `/api` 请求一样覆盖上述全部方法。 + +`host.openPath` 会用操作系统的默认应用打开一个文件系统路径(macOS 为 `open`,Windows 为 `Invoke-Item`,桌面 Linux 为 `xdg-open`)。对于 `.html`、`.htm`、`.xhtml` 与 `.svg`,macOS 和桌面 Linux 会优先使用能够确定的默认浏览器;无法确定时回退到上述应用交接。WSL 会通过 `wslpath -w` 转换每个 Linux 路径,并将所得 Windows/UNC 路径交给 Windows `Invoke-Item`,浏览器可渲染的文档也不例外,而非假定存在 Linux 桌面文件关联。`host.describe.canOpenPath` 会宣告这次交接能否抵达用户可见的桌面:网关显式配置的 `nativeOpen` 优先,注入的 opener 按定义可用,否则平台检测接受 macOS、Windows、WSL 或带 display 的 Linux,并拒绝 headless/容器 Linux。浏览器载体对其施加与 `host.pickDirectory` 相同的回环、同源限制;客户端会组合这两个事实后再呈现原生操作。 + +`agentPreset.list` 领域向浏览器暴露部署的 preset 名单,使其在开启会话时能够提供选择;每一行携带它的 `trust`(`user` preset 的权限恰好等于它所引用的插件)、它是否为当前默认值,以及——当该 preset 无法组装会话时——一条 `broken` 原因:损坏的目录仍占着它的 id,界面必须能展示并删除它,而不是把它端出来然后在会话启动时失败。未组装任何 preset 的部署返回空名单而非错误,因为共用宿主组装本身就是一种有效部署。`agentPreset.select` 用另一个 preset 重组某个会话的 agent,且仅在会话空白时允许:一旦跑过任何轮次,那段历史就是在该 preset 的工具下产生的,替换会留下无法执行的已记录的工具调用,此时返回 `agent-preset-locked`。agent 与会话都不销毁——只替换组装,且替换失败会恢复原来的组装。 + +`agentPreset.read`、`copy`、`openDocument` 与 `remove` 负责管理组装本身。`read` 返回文本连同它的 `trust`,供只读查看器使用。创作只有复制一种写入:`copy` 接收 `{ from, agentPreset, name? }`——两个由 Host 对照自身根目录解析的 id 加一个可选显示名——并整目录复制来源,因此组装文本不经过传输层,副本与其来源同等可加载;不可约束或已被占用的 id 回答 `agent-preset-invalid`,`remove` 对随附 preset 回答 `agent-preset-read-only`。`openDocument` 把一个本地创作 preset 的**目录**交给平台打开器——请求只携带 id、绝不携带路径,因此没有任何浏览器载荷能选中任意文件系统目标;部署没有原生打开器时回答 `{ opened: false, path }` 供界面以文本展示,随附 preset 与 `remove` 一样被拒绝,而网关的 `nativeOpen` 配置可在平台探测(`canOpenNativePath`)失真处钉死该能力。这四个方法在 [`dsh-client-connection`](../../client/connection/README.md) 中被固定在环回地址:组装指明了一个会话所运行的插件,因此读取它是侦察,而 copy/remove/openDocument 管理名单并驱动宿主桌面。`list` 与 `select` 保持为普通方法——名单只携带 id 与信任级别,每个 preset 选择器都需要它;而选择一个 preset 并不比 `session.create` 自带的 `agentPreset` 多给任何能力,何况默认 preset 本就带着 bash。`list` 报告两个不含路径的能力标志:`authorable`,即部署是否配置了可供复制新 preset 的根目录;`hasDocument`,即 `openDocument` 会原生打开、还是回答一个路径。 + +`command.*` 与 `skill.*` 领域向客户端暴露宿主命令注册表和 skill(技能)目录。每个方法都通过 `sessionId` 寻址一个会话的 Agent(被服务的会话必有 Agent;`command.*` 经由与 `session.*` 相同的路径恢复冷会话,而 `skill.list` 从会话头解析项目根目录,不触碰 Agent 注册表)。`skill.list` 服务于 composer 的菜单:它返回每一个用户可调用的 skill 及其 `modelInvocable` 标志,让菜单能够标出仅限用户(`disable-model-invocation`)的条目——斜杠手势是这类条目唯一的调用路径。列表是 skill 领域唯一的 RPC——调用本身就是一次普通的 `session.prompt`,`dsh-tool-skill` 会在 pre-step 边界识别其中以空白为界的 `/name` token,并以注入的 `` 上下文作答,因此所有入口(Web、TUI 与 ACP(Agent Client Protocol))共享同一条确定性路径,手动键入的文本也走该路径,且没有专设的调用协议。`command.execute` 在宿主侧运行一条斜杠命令行,语义为纯准入:响应报告该行是否解析到处理器,并在解析到时回带铸造的生命周期 `commandId`(将本次确认与流节点关联);结局经由持久落账并在 mux 流广播的 `command/run`/`command/done` 生命周期事件对承载。命令处理器运行超过 30 秒的传输健康时限仍属正常,因此 `command.execute` 仅携带调用方/连接取消信号;该信号可取消正在运行的处理器。`commands/change` 搭乘转发事件帧作为注册表级目录失效信号:客户端重新拉取 `command.list` 而不是做差分。转发的 `agent-preset/selected` 是它按会话粒度的对应物,由落账的选择提交点发出:重组空会话的 agent 只是重新挂接其 scope,不产生任何注册,因此该会话组成所决定的两份目录(`command.list`、`skill.list`)都会失效,却没有任何注册表变化来宣告它。 + +`settings.*`、`credentials.*` 与 `llm.*` 领域是配置页协议。settings 领域服务于每一个已注册 namespace:在本仓库之外分发的插件只要注册自己的分节即可变得可从浏览器配置,无需改动这里;本代理也不再自设边界——没有任何注册应答的名字会折叠为 seam 自己的 `settings-rejected`。由哪个界面渲染某个 namespace 是浏览器的决定(插件配置页按 namespace 为其卡片编键),从不由本代理决定。`settings.describe` 为每个 namespace 提供其序列化 schemastery schema、脱敏后的分层值(resolved/`base`/`user`——字段出现在 `user` 中即标记其被用户覆盖)、`secrets` 槽位列表、该分节的 `revision`,以及布尔型 `hasDocument` 能力标志。浏览器不会收到 Host 路径:无路径参数的 `settings.openDocument` 会请求提供方准备文档,再把由 Host 解析出的结果交给原生打开器,因此任何浏览器载荷都无法选择任意文件系统目标。`settings.update`/`settings.replace` 写入用户层;`settings.mutate` 则在已存分节上施加路径 op(`set`/`unset`),这是持有脱敏视图的客户端的删除路径——据此重建分节再整体替换,会删掉协议从未回传过的那些机密。任何写入都可携带 `expectedRevision`;陈旧的期望值会以 `settings-conflict` 连同两个 revision 作答,而不是覆盖先落地的那个写方,其余每种 seam 拒绝则折叠为 `settings-rejected`。secret 角色的值绝不在任何一层搭乘任何响应;secret 只沿一个方向跨越协议——在 `update`/`mutate` 载荷或 `credentials.set` 之内。`credentials.describe` 返回不含值的视图(`configured`/`source`/`writable`),`credentials.set`/`credentials.unset` 则把被遮蔽引用的拒绝映射为 `credential-rejected`。`llm.providers` 把可配置提供方目录与存活路由合并(休眠条目携带 `active: false`;未声明的存活路由追加在后,不带 settings 地址),`llm.models` 则是与会话无关的目录。`llm.discoverModels` 询问页面尚在起草的提供方端点:`settingsNs` 选出懂得读取该列表的适配器家族,端点、协议与密钥则来自表单而非存储。它什么都不写——回复是候选,只有随后的 `settings.mutate` 才决定路由服务什么——因此其 `apiKey` 是 secret 可以搭乘的第三个载荷(另两个是 `settings.update`/`mutate` 与 `credentials.set`),且绝不被存储或回显。host 从不存储或回传它;与另两者一样,它确实会搭乘客户端的出站信封,`subscribeEnvelopes()` 的观察者能看到——为该 tap 做脱敏是整个配置面的改动,而非本方法一家的事。每一种拒绝(无人服务的 namespace、没有可读列表的协议、不可达端点、被拒凭据)都折叠为 `model-discovery-failed`,其消息是适配器自己的文本,details 点名被询问的端点,绝不点名所提供的凭据。失效通知让每个面无需轮询即保持收敛。`settings/document-updated` 与 `credentials/updated` 搭乘原样转发事件帧(见下),因此解析值未变的原始设置变更同样能到达客户端,凭据失效通知也仍然只带引用名、绝不带值。`llm/adapters-updated` 与 `settings/document-updated` 一并原样转发;具体模型消费方直接订阅这两个 owner 事件,因为拓扑提交和设置文档都能独立改变其目录。浏览器载体把整个配置面(含读取与原生操作:`settings.describe`/`openDocument`/`update`/`replace`/`mutate` 与 `credentials.describe`/`set`/`unset`)限制为仅接受来自回环地址的同源请求——即 `host.pickDirectory` 所在的特权集合。未装 settings 或凭据提供方的组合会以指名缺失插件、包含解决建议的 `internal` 错误应答这些领域。 + +## 载体层(`/client` + 根路径) + +`AbstractApiClient` 持有全部协议不变量:签发 rpcId、包装/解包信封、Zod 解析、SSE 帧解码、一元请求超时,以及按微任务批处理的信封观测(`subscribeEnvelopes`);平台子类只提供 `doFetch` 传输环节。`InProcessApiClient` 以 `toFetchHandler(api)` 为基础,仍是同构接点:它运行完整的协议序列化与校验路径而不经过网络,供需要该路径的调用方和载体测试使用。产品的 `dsh --profile headless` 是直连 core 的入口,不挂载本包。 + +## 模型体验 + +无。该包定义客户端与宿主间的 wire 约定和载体,其中没有任何内容会进入模型请求。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **转发的 Remote 事件寄居在这套 legacy 帧联合里**:`host/remote-event` 住在 `HostFrame` 中,是为了让投递路径复用现有宿主流、不必新开第三条下行通道,因此读起来像是本包拥有 Remote 事件契约。并非如此:名单归 `dsh-api-remotes`,消费端动词是 `ctx.remote.$on`。将来宿主流整体搬离本包时,该帧随之搬走,消费端契约不受影响([原委](../../../.agents/notes/implemented/architecture/2026-08-10-remote-event-delivery.md))。 +- **待处理交互状态位于宿主侧**:wire 使用 POST `/api/respond` 加 `RpcReceipt`;`src/api-proxy.ts` 中的表只处理问题,不包含审批条目。 +- **预留 seam 不进入 `RpcMethodMap`**:`prompt.mode: 'inject'`、`job.list` 和描述字段 `hostInstanceId` 都是已记录的预留项;模型发现使用 `llm.models`。未知方法会在信封解析时直接失败,而不会返回「尚未实现」错误码。 +- **没有协议版本字段**:客户端与宿主一同发布;只有出现独立发布的客户端后,`host.describe` 才会增加版本协商字段。 +- **搜索失败会包含提供方诊断信息**:网关是单用户本地服务。将其暴露给多名用户的载体必须用可安全公开的诊断信息替代内部搜索细节。 +- **Linux 原生选择器依赖桌面工具**:在 `native` 能力下,Zenity 和 KDialog 均未安装时,`host.pickDirectory` 会给出包含解决建议的错误提示;组合层面的回退是 browse 后端(见 [native 后端 README](../directory-picker-native/README.md))。 +- **冷列表提示只向“保持可见、排序偏旧”降级**:projection cache miss 或陈旧的 `lastPromptAt` 会回退到 `createdAt`,除非符合资格的小工件提供精确折叠,因此最近工作过的大 Session 可能在下一个 checkpoint 前排得偏低。大于 `coldBlankProbeMaxBytes` 的空白工件,或来自不提供 `locate()` 的后端的空白工件会保持可见。该阈值在 `readFrom()` 前检查,而非由 persistence 强制,因此工件并发增长可能增加一次探测的读取成本,但不会改变空白状态的安全方向。[有界空白验证决策](../../../.agents/notes/implemented/bug-fix/2026-08-13-bounded-cold-blank-verification.md)规定了这个安全方向;权威且精确的最近时间索引仍属于[最后活动索引提案](../../../.agents/notes/proposed/architecture/2026-07-29-durable-last-activity-index.md)的范围。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/index.js new file mode 100644 index 0000000..11ee6c4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/index.js @@ -0,0 +1,5587 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { randomUUID } from "node:crypto"; +import { mkdir, stat } from "node:fs/promises"; +import { dirname, extname } from "node:path"; +import { installModelSelection } from "@deepseek-ai/dsh-agent"; +import { AttachmentError } from "@deepseek-ai/dsh-attachment"; +import { ReasoningEffortId, contentHasImage, createUserMessage, errorChain, freezeMessage } from "@deepseek-ai/dsh-llm"; +import { isAppendSurfaceEvent, isJsonValue } from "@deepseek-ai/dsh-session"; +import { SessionQueryError } from "@deepseek-ai/dsh-session-query"; +import { SubagentError } from "@deepseek-ai/dsh-subagent"; +import { isUserInvocable } from "@deepseek-ai/dsh-skill"; +import { WorkspaceId, WorkspaceMoveInvalidError, WorkspaceOrderInvalidError, WorkspaceUnknownSessionError, workspaceDomainState, workspaceRecord } from "@deepseek-ai/dsh-workspace"; +import { InvalidPresetIdError, PresetExistsError, PresetMountError, PresetNotWritableError, UnknownPresetError, resolveSessionPreset } from "@deepseek-ai/dsh-agent-presets"; +import { Zip, ZipDeflate } from "fflate"; +import { GoalError } from "@deepseek-ai/dsh-goal"; +import { SettingsConflictError, settingsNamespace } from "@deepseek-ai/dsh-settings"; +import { credentialRef } from "@deepseek-ai/dsh-credentials"; +import { SessionTitleInvalidError } from "@deepseek-ai/dsh-session-title"; +import { z as z$1 } from "zod"; +import { UserQuestionError } from "@deepseek-ai/dsh-user-questions"; +import { DirectoryPickerError } from "@deepseek-ai/dsh-host-directory-picker"; +import { API_REMOTE_FORWARDED_EVENTS, ApiRemoteSessionNotFound, ApiRemoteSubagentSessionOwnership, apiRemoteSubagentOwnershipError, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession } from "@deepseek-ai/dsh-api-remotes"; +import { release } from "node:os"; +import { runNativeCommand } from "@deepseek-ai/dsh-native-command"; +//#region lib/types/session-export.js +/** +* Host-side session-log download: streams one ZIP archive whose files are the +* sessions' stored artifact text verbatim plus every referenced media object. +* The root artifact sits under its original base name (`session.jsonl`); each +* subagent descendant under `subagents//`; each image referenced +* by any included log under `media/.` (content-addressed, +* so one archive never duplicates a shared image). No manifest is written — +* every file is byte-identical to the backend's durable artifact or attachment +* store and self-describing through its own header line or media type. Before +* each live session's artifact read, the SessionStore flush barrier makes the +* current in-memory log durable; cold sessions need no barrier. Request abort +* and response-consumer cancellation share one producer signal and terminate +* the active compressor. +* Compression runs on the host with fflate's streaming Zip API, so the archive +* bytes are produced incrementally and the host never holds the whole archive +* in one buffer; production waits for consumer pull whenever the response queue +* reaches its byte high-water mark, so a slow consumer bounds accumulation to +* the fixed 64 KiB response queue plus one synchronous fflate push. +* @module +*/ +/** +* Resolve the persistence, session-query, and attachment services a log export needs. +* @param ctx - the composed host context. +* @returns the export services (absent when the deployment does not mount them). +*/ +function sessionLogExportDeps(ctx) { + return { + sessionQuery: ctx.get("sessionQuery"), + sessionPersistence: ctx.get("sessionPersistence"), + attachments: ctx.get("attachments"), + sessions: ctx.get("sessions") + }; +} +/** +* Flush one currently live session through the store's authoritative durability +* barrier immediately before its raw artifact is read. A cold or absent id has +* no in-memory work to flush. +* @param deps - export services, including the optional live-session store. +* @param id - the session whose artifact is about to be read. +* @param signal - optional cancellation observed around the flush barrier. +*/ +async function flushLiveSessionLog(deps, id, signal) { + signal?.throwIfAborted(); + const sessions = deps.sessions; + if (sessions === void 0) return; + const session = sessions.get(id); + if (session === void 0) return; + await sessions.flush(session); + signal?.throwIfAborted(); +} +/** Zip extension for each accepted raster media type. */ +const MEDIA_TYPE_EXTENSIONS = { + "image/png": "png", + "image/jpeg": "jpg", + "image/webp": "webp", + "image/gif": "gif" +}; +/** +* The zip path for one media object: content-addressed by the opaque +* attachment id so shared images land once and the id in the log maps back to +* the archive entry without a manifest. +* @param ref - the durable reference from a session log. +* @returns the archive path. +*/ +function mediaEntryPath(ref) { + return `media/${String(ref.attachmentId)}.${MEDIA_TYPE_EXTENSIONS[ref.mediaType]}`; +} +/** +* Collect every image reference inside one content array, descending into +* nested tool results the way the live attachment route does. +* @param content - an event content array (or nested tool-result content). +* @param refs - the dedupe map being filled (keyed by attachment id). +*/ +function collectImageRefs(content, refs) { + if (!Array.isArray(content)) return; + const pending = []; + for (const item of content) pending.push(item); + while (pending.length > 0) { + const value = pending.pop(); + if (typeof value !== "object" || value === null || Array.isArray(value)) continue; + const block = value; + if (block.type === "image" && typeof block.attachment === "object" && block.attachment !== null) { + const ref = block.attachment; + refs.set(String(ref.attachmentId), ref); + } + if (Array.isArray(block.content)) for (const item of block.content) pending.push(item); + } +} +/** +* Collect every image reference one session event carries, across the same +* carriers the live attachment route scans (direct content, message content, +* inserted messages, and completed assistant chunk blocks). +* @param event - one parsed JSONL event object. +* @param refs - the dedupe map being filled (keyed by attachment id). +*/ +function collectEventImageRefs(event, refs) { + const data = event.data; + if (typeof data !== "object" || data === null) return; + const carrier = data; + collectImageRefs(carrier.content, refs); + if (carrier.message !== void 0) collectImageRefs(carrier.message.content, refs); + if (carrier.inserted !== void 0) for (const message of carrier.inserted) collectImageRefs(message.content, refs); + if (carrier.chunk?.type === "block-end") collectImageRefs([carrier.chunk.block], refs); +} +/** +* Collect the distinct media references one stored artifact text names. +* Lines that fail to parse cannot reference media and are skipped (the +* artifact text itself is exported verbatim regardless). +* @param content - the stored artifact text. +* @returns the dedupe map keyed by attachment id. +*/ +function imageRefsInArtifact(content) { + const refs = /* @__PURE__ */ new Map(); + for (const line of content.split("\n")) { + if (line === "") continue; + let event; + try { + event = JSON.parse(line); + } catch { + continue; + } + collectEventImageRefs(event, refs); + } + return refs; +} +/** +* One safe zip path segment from an untrusted session id. Session ids are +* host-controlled, but the brand allows any non-empty string, so `../`, dot +* segments, and separator characters are neutralized before they can shape +* archive entries. Distinct ids may collapse onto one segment (id collision +* is impossible for the host-minted UUIDs, so no uniqueness suffix is kept). +* @param id - the raw session id. +* @returns a filesystem-safe single path segment. +*/ +function safeSessionIdSegment(id) { + return id.replace(/[^A-Za-z0-9_-]/g, "_"); +} +/** +* The export archive filename for one root session. +* @param sessionId - the root session id (sanitized to one safe path segment). +* @returns the attachment filename for the session's export archive. +*/ +function sessionLogZipFilename(sessionId) { + return `dsh-session-${safeSessionIdSegment(sessionId)}.zip`; +} +/** +* Yield the export entries in zip order: the preloaded root artifact first, +* then every subagent descendant in lineage order (each flushed when live, +* read from the persistence backend right before it is yielded, and dropped +* after the consumer moves on), then every distinct media object referenced by any of +* the included logs (read and verified from the attachment store, one archive +* entry per attachment id). The host holds at most one descendant's artifact +* text and one media object at a time beyond the root. +* @param deps - the mounted export services (the caller answered 500 before this runs). +* @param root - the already-read root artifact (read by the caller so the +* missing-session path can answer cleanly before streaming starts). +* @param sessionId - the root session id. +* @param includeDescendants - whether to include every subagent descendant. +* @param signal - optional cancellation forwarded to lineage, persistence, and attachment reads. +* @returns the export entries in zip order. +*/ +async function* sessionLogZipEntries(deps, root, sessionId, includeDescendants, signal) { + const media = /* @__PURE__ */ new Map(); + const rememberMedia = (content) => { + for (const [id, ref] of imageRefsInArtifact(content)) media.set(id, ref); + }; + rememberMedia(root.content); + yield { + path: root.filename, + content: root.content + }; + if (includeDescendants) { + const seen = new Set([sessionId]); + const collect = async function* (nodes) { + for (const node of nodes) { + signal?.throwIfAborted(); + const id = node.session.header.id; + if (seen.has(id)) continue; + seen.add(id); + await flushLiveSessionLog(deps, id, signal); + const raw = await deps.sessionPersistence.readRaw(id, signal); + signal?.throwIfAborted(); + if (raw === void 0) throw new Error(`subagent "${id}" has no stored log artifact`); + rememberMedia(raw.content); + yield { + path: `subagents/${safeSessionIdSegment(id)}/${raw.filename}`, + content: raw.content + }; + yield* collect(node.descendants); + } + }; + const lineage = await deps.sessionQuery.traceSession(sessionId, signal); + signal?.throwIfAborted(); + yield* collect(lineage.descendants); + } + for (const ref of media.values()) { + signal?.throwIfAborted(); + const stored = await deps.attachments.readImage(ref, signal); + signal?.throwIfAborted(); + yield { + path: mediaEntryPath(ref), + data: stored.data + }; + } +} +/** How many code units of artifact text one zip push carries (bounded encode memory). */ +const PUSH_CHUNK_CODE_UNITS = 65536; +/** How many bytes of media one zip push carries (bounded memory; images are already size-capped). */ +const PUSH_CHUNK_BYTES = 65536; +/** Byte capacity retained by the response stream before ZIP production waits for pull. */ +const RESPONSE_HIGH_WATER_MARK_BYTES = 65536; +/** One producer waiter released only when ReadableStream pull restores capacity. */ +var ResponseCapacityGate = class { + releasePending; + /** + * Wait until the response queue has positive byte capacity or cancellation wins. + * @param controller - response controller whose desired size owns capacity. + * @param signal - combined request/consumer cancellation. + */ + async wait(controller, signal) { + signal.throwIfAborted(); + if (controller.desiredSize === null || controller.desiredSize > 0) return; + await new Promise((resolve) => { + const release = () => { + this.releasePending = void 0; + signal.removeEventListener("abort", release); + resolve(); + }; + this.releasePending = release; + signal.addEventListener("abort", release, { once: true }); + }); + signal.throwIfAborted(); + } + /** Release the current producer waiter after a consumer pull. */ + pulled() { + this.releasePending?.(); + } +}; +/** +* Push one media object's bytes into a deflate stream in bounded chunks, +* waiting for consumer capacity between chunks like the artifact path does. +* @param deflate - the zip entry's deflate stream. +* @param data - the stored image bytes. +* @param controller - response queue controller. +* @param capacity - pull-driven response-capacity gate. +* @param signal - cancellation; throws when aborted. +*/ +async function pushBinaryChunks(deflate, data, controller, capacity, signal) { + let offset = 0; + do { + signal.throwIfAborted(); + const end = Math.min(offset + PUSH_CHUNK_BYTES, data.byteLength); + const finalChunk = end >= data.byteLength; + deflate.push(data.subarray(offset, end), finalChunk); + offset = end; + await capacity.wait(controller, signal); + } while (offset < data.byteLength); +} +/** +* Push one artifact's text into a deflate stream in bounded chunks, never +* splitting a surrogate pair across a chunk boundary (a lone high surrogate +* re-encodes as U+FFFD and would silently corrupt the exported artifact). +* @param deflate - the zip entry's deflate stream. +* @param content - the artifact text verbatim. +* @param controller - response queue controller. +* @param capacity - pull-driven response-capacity gate. +* @param signal - cancellation; throws when aborted. +*/ +async function pushArtifactChunks(deflate, content, controller, capacity, signal) { + const encoder = new TextEncoder(); + let offset = 0; + let finalChunk; + do { + signal.throwIfAborted(); + let end = Math.min(offset + PUSH_CHUNK_CODE_UNITS, content.length); + if (end < content.length && end - offset > 1) { + const last = content.charCodeAt(end - 1); + if (last >= 55296 && last <= 56319) end -= 1; + } + finalChunk = end >= content.length; + deflate.push(encoder.encode(content.slice(offset, end)), finalChunk); + offset = end; + await capacity.wait(controller, signal); + } while (!finalChunk); +} +/** +* Stream one session-log ZIP as a WHATWG ReadableStream. The root artifact is +* read and validated by the caller before this is called (missing root or +* missing services answer cleanly before any byte is produced); each entry is +* then encoded and deflated in bounded chunks as it is produced, so the +* archive bytes arrive incrementally. A descendant that fails to read errors +* the stream (fail-loud, never silent under-export). +* @param deps - the mounted export services (the caller answered 500 before this runs). +* @param root - the already-read root artifact (first zip entry). +* @param sessionId - the root session id. +* @param includeDescendants - whether to include every subagent descendant. +* @param compressionLevel - validated fflate DEFLATE level for every ZIP entry. +* @param signal - request cancellation combined with response-consumer cancellation. +* @returns the zip byte stream. +*/ +function streamSessionLogZip(deps, root, sessionId, includeDescendants, compressionLevel, signal) { + const consumerAbort = new AbortController(); + const producerSignal = AbortSignal.any([signal, consumerAbort.signal]); + let zip; + let zipTerminated = false; + const capacity = new ResponseCapacityGate(); + const terminateZip = () => { + if (zip === void 0 || zipTerminated) return; + zipTerminated = true; + zip.terminate(); + }; + return new ReadableStream({ + start(controller) { + const archive = new Zip((error, data, final) => { + /* v8 ignore next 3 -- fflate reports only internal zip failures, unreachable for valid inputs */ + if (error) { + controller.error(error); + return; + } + /* v8 ignore next -- fflate may emit empty chunks; not controllable from tests */ + if (data.byteLength > 0) controller.enqueue(data); + if (final) controller.close(); + }); + zip = archive; + (async () => { + try { + for await (const entry of sessionLogZipEntries(deps, root, sessionId, includeDescendants, producerSignal)) { + const deflate = new ZipDeflate(entry.path, { level: compressionLevel }); + archive.add(deflate); + if ("content" in entry) await pushArtifactChunks(deflate, entry.content, controller, capacity, producerSignal); + else await pushBinaryChunks(deflate, entry.data, controller, capacity, producerSignal); + } + archive.end(); + } catch (error) { + /* v8 ignore next -- typed backends reject with Error, and DOMException is one in Node */ + terminateZip(); + controller.error(error instanceof Error ? error : new Error(String(error))); + } + })(); + }, + pull() { + capacity.pulled(); + }, + cancel(reason) { + consumerAbort.abort(reason instanceof Error ? reason : /* @__PURE__ */ new Error("session log export stream cancelled")); + terminateZip(); + } + }, { + highWaterMark: RESPONSE_HIGH_WATER_MARK_BYTES, + size: (chunk) => chunk.byteLength + }); +} +//#endregion +//#region lib/types/api/session-search.js +/** +* Return the longest prefix containing at most `maximum` Unicode code points. +* @param value - text to bound. +* @param maximum - non-negative code-point limit. +* @returns `value` unchanged when it fits, otherwise a code-point-safe prefix. +*/ +function truncateUnicodeCodePoints(value, maximum) { + let count = 0; + let end = 0; + for (const codePoint of value) { + if (count === maximum) return value.slice(0, end); + count++; + end += codePoint.length; + } + return value; +} +//#endregion +//#region lib/types/api/sessions.schema.js +/** +* sessions domain zod schemas (names derived from map keys: sessionListRequestSchema / +* sessionListValueSchema). SessionEvent passthrough = strict envelope (type/seq/time) + wide +* data: the merge-extensible event API keeps an unknown-type branch at the union level, +* with no field-level passthrough. SessionId brand cast point: sessionIdSchema, and only there. +*/ +/** SessionId: one brand cast after schema validation (the only cast point in this domain). */ +const sessionIdSchema = z$1.string().min(1); +/** MessageId: one brand cast after non-empty string validation. */ +const messageIdSchema$1 = z$1.string().min(1); +/** +* WorkspaceId: the workspace domain's one brand cast. Hosted here rather +* than in workspace.schema because session.create references it while +* workspace.schema references sessionIdSchema — schema modules must stay a +* DAG (both casts used at module top level; a cycle is a load-time TDZ). +*/ +const workspaceIdSchema = z$1.string().min(1); +/** SessionEvent passthrough: strict envelope, wide data (the client fold handles unknown types via its documented default). */ +const sessionEventSchema = z$1.object({ + type: z$1.string(), + seq: z$1.number().int().nonnegative(), + time: z$1.number(), + data: z$1.unknown(), + sourceEventSeqs: z$1.array(z$1.number()).optional(), + surfaceOp: z$1.unknown().optional(), + ignorable: z$1.literal(true).optional() +}); +/** SessionSummary row of session.list (`projections` reuses the history block's shape and schema). */ +const sessionSummarySchema = z$1.object({ + sessionId: sessionIdSchema, + updatedAt: z$1.number(), + running: z$1.boolean(), + blank: z$1.boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: z$1.literal("subagent").optional(), + cwd: z$1.string().optional(), + agentPreset: z$1.string().optional(), + projections: z$1.lazy(() => sessionProjectionsBlockSchema).optional() +}); +/** session.list request payload (cursor is a reserved seat, unimplemented in v1). */ +const sessionListRequestSchema = z$1.object({ cursor: z$1.string().optional() }); +/** session.list response value. */ +const sessionListValueSchema = z$1.object({ items: z$1.array(sessionSummarySchema) }); +/** session.search request payload. */ +const sessionSearchRequestSchema = z$1.object({ query: z$1.string().trim().min(1).max(500).refine((query) => !query.includes("\0"), { message: "search query must not contain NUL" }) }); +/** One session.search result. */ +const sessionSearchItemSchema = z$1.object({ + sessionId: sessionIdSchema, + snippet: z$1.string().refine((snippet) => truncateUnicodeCodePoints(snippet, 240) === snippet, { message: `search snippet must contain at most 240 Unicode code points` }) +}); +/** session.search response value. */ +const sessionSearchValueSchema = z$1.object({ + items: z$1.array(sessionSearchItemSchema).max(20), + hasMore: z$1.boolean() +}); +/** session.create request payload (at most one of workspaceId / cwd). */ +const sessionCreateRequestSchema = z$1.object({ + workspaceId: workspaceIdSchema.optional(), + cwd: z$1.string().optional(), + sessionId: sessionIdSchema.optional(), + agentPreset: z$1.string().optional() +}).refine((payload) => payload.workspaceId === void 0 || payload.cwd === void 0, { message: "session.create accepts workspaceId or cwd, not both" }); +/** session.create response value. */ +const sessionCreateValueSchema = z$1.object({ + sessionId: sessionIdSchema, + agentPreset: z$1.string().optional() +}); +/** session.rename request payload (raw title; host-side normalization decides acceptance). */ +const sessionRenameRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + title: z$1.string() +}); +/** session.rename response value (the normalized accepted title and its event seq). */ +const sessionRenameValueSchema = z$1.object({ + title: z$1.string().min(1), + seq: z$1.number().int().nonnegative() +}); +/** session.fork request payload (atSeq anchors the completed-turn cut). */ +const sessionForkRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + atSeq: z$1.number().int().nonnegative().optional() +}); +/** session.fork response value (the child session id). */ +const sessionForkValueSchema = z$1.object({ sessionId: sessionIdSchema }); +/** session.history request payload (beforeSeq/maxMessages page backwards from the window tail). */ +const sessionHistoryRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + beforeSeq: z$1.number().int().nonnegative().optional(), + maxMessages: z$1.number().int().positive().optional() +}); +/** Complete provider/model selection. */ +const modelSelectionSchema = z$1.object({ + provider: z$1.string().min(1), + model: z$1.string().min(1), + reasoningEffort: z$1.string().min(1).optional() +}); +/** One adapter-owned reasoning effort. */ +const modelReasoningEffortSchema = z$1.object({ + id: z$1.string().min(1), + name: z$1.string().min(1), + description: z$1.string().optional() +}); +/** Exact-model reasoning metadata. */ +const modelReasoningSchema = z$1.object({ + efforts: z$1.array(modelReasoningEffortSchema).min(1), + defaultEffort: z$1.string().min(1).optional() +}); +/** One advisory model entry inside a provider group. */ +const modelCatalogModelSchema = z$1.object({ + id: z$1.string().min(1), + name: z$1.string().min(1), + description: z$1.string().optional(), + reasoning: modelReasoningSchema.optional() +}); +/** One successfully loaded provider group. */ +const modelProviderGroupSchema = z$1.object({ + id: z$1.string().min(1), + name: z$1.string().min(1), + models: z$1.array(modelCatalogModelSchema) +}); +/** One provider-local catalog failure. */ +const modelCatalogFailureSchema = z$1.object({ + id: z$1.string().min(1), + name: z$1.string().min(1), + message: z$1.string() +}); +/** +* ToolEventView passthrough: lock only the `for` discriminant and the presence +* of a card-tagged `view` object. The view interior is a host-computed product +* the client reads without echoing back; deep-validating it would hand-copy +* the dsh-tools vocabulary into this schema and drift with it. +*/ +const toolEventViewSchema = z$1.discriminatedUnion("for", [z$1.object({ + for: z$1.literal("call"), + view: z$1.looseObject({ card: z$1.string() }) +}), z$1.object({ + for: z$1.literal("result"), + view: z$1.looseObject({ card: z$1.string() }) +})]); +/** One session.history item: the session event plus its optional host-computed tool view. */ +const historyEntrySchema = z$1.object({ + event: sessionEventSchema, + view: toolEventViewSchema.optional() +}); +/** +* Projection baseline passthrough: `values` stays a wide record — each value +* was already parsed by its provider's own schema on the host side, and +* deep-validating here would import every domain's schema into the carrier. +*/ +const sessionProjectionsBlockSchema = z$1.object({ + asOfSeq: z$1.number().int().min(-1), + values: z$1.record(z$1.string(), z$1.unknown()) +}); +/** Host-side validation for the persisted Session-list projection. */ +const sessionListMetadataProjectionSchema = z$1.object({ + blank: z$1.boolean(), + lastPromptAt: z$1.number().nullable() +}); +/** +* imageLimits projection unit schema (host-side view validation). zod widens +* `readonly ImageMediaType[]` to `string[]`; on the JSON wire the two +* serialize identically, so the cast records exactly that widening. +*/ +const imageLimitsProjectionSchema = z$1.object({ + maxImageBytes: z$1.number().int().positive(), + maxImagesPerMessage: z$1.number().int().positive(), + maxMessageImageBytes: z$1.number().int().positive(), + maxImagePixels: z$1.number().int().positive(), + mediaTypes: z$1.array(z$1.string()) +}); +/** session.history response value (projections rides the tail page only). */ +const sessionHistoryValueSchema = z$1.object({ + events: z$1.array(historyEntrySchema), + hasMore: z$1.boolean(), + projections: sessionProjectionsBlockSchema.optional() +}); +/** session.models request payload. */ +const sessionModelsRequestSchema = z$1.object({ sessionId: sessionIdSchema }); +/** session.models response value. */ +const sessionModelsValueSchema = z$1.object({ + current: modelSelectionSchema, + routable: z$1.boolean(), + groups: z$1.array(modelProviderGroupSchema), + failures: z$1.array(modelCatalogFailureSchema) +}); +/** session.selectModel request payload. */ +const sessionSelectModelRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + provider: z$1.string().min(1), + model: z$1.string().min(1), + reasoningEffort: z$1.string().min(1).optional() +}); +/** session.selectModel response value. */ +const sessionSelectModelValueSchema = z$1.object({ selected: modelSelectionSchema }); +/** ContentBlock passthrough: core is merge-extensible — the type discriminant envelope is strict, the rest stays wide. */ +const contentBlockSchema = z$1.looseObject({ type: z$1.string() }); +/** Raster image media types accepted by the version-one browser wire. */ +const imageMediaTypeSchema = z$1.union([ + z$1.literal("image/png"), + z$1.literal("image/jpeg"), + z$1.literal("image/webp"), + z$1.literal("image/gif") +]); +/** Prompt wire content is intentionally narrower than merge-extensible durable core content. */ +const promptContentPartSchema = z$1.discriminatedUnion("type", [z$1.object({ + type: z$1.literal("text"), + text: z$1.string() +}), z$1.object({ + type: z$1.literal("image"), + mediaType: imageMediaTypeSchema, + data: z$1.string(), + name: z$1.string().optional() +})]); +/** session.prompt request payload, including optional browser-local request provenance. */ +const sessionPromptRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + mode: z$1.union([z$1.literal("queue"), z$1.literal("steer")]), + content: z$1.array(promptContentPartSchema), + clientTimeZone: z$1.string().optional() +}); +/** session.prompt response value (the command slot appears only when the prompt dispatched a slash command). */ +const sessionPromptValueSchema = z$1.object({ + accepted: z$1.literal(true), + command: z$1.object({ + kind: z$1.literal("success"), + text: z$1.string().optional() + }).optional() +}); +/** Opaque attachment id after string-shape validation. */ +const attachmentIdSchema = z$1.string().min(1); +/** Durable image reference returned from the authenticated session lookup. */ +const imageAttachmentRefSchema = z$1.object({ + attachmentId: attachmentIdSchema, + mediaType: imageMediaTypeSchema, + bytes: z$1.number().int().positive(), + width: z$1.number().int().positive(), + height: z$1.number().int().positive(), + name: z$1.string().optional() +}); +/** session.attachment request payload. */ +const sessionAttachmentRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + attachmentId: attachmentIdSchema +}); +/** session.attachment response value. */ +const sessionAttachmentValueSchema = z$1.object({ + attachment: imageAttachmentRefSchema, + data: z$1.string() +}); +/** session.updateQueue request payload. */ +const sessionUpdateQueueRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + itemId: messageIdSchema$1, + action: z$1.discriminatedUnion("kind", [ + z$1.object({ + kind: z$1.literal("edit"), + content: z$1.array(contentBlockSchema) + }), + z$1.object({ kind: z$1.literal("remove") }), + z$1.object({ kind: z$1.literal("steer") }) + ]) +}); +/** session.updateQueue response value. */ +const sessionUpdateQueueValueSchema = z$1.object({ accepted: z$1.literal(true) }); +/** session.cancel request payload. */ +const sessionCancelRequestSchema = z$1.object({ sessionId: sessionIdSchema }); +/** session.cancel response value. */ +const sessionCancelValueSchema = z$1.object({ accepted: z$1.literal(true) }); +//#endregion +//#region lib/types/api/approvals.schema.js +/** +* approvals domain zod schemas (respond is a client-response; the payload schema serves +* the /api/respond endpoint's second parse after routing via the pending table). +* ApprovalRequestId brand cast point: one. +*/ +/** ApprovalRequestId: one brand cast after schema validation (the only cast point in this domain). */ +const approvalRequestIdSchema = z$1.string().min(1); +/** Approval answer payload (the result.value slot of a client-response). */ +const approvalResponsePayloadSchema = z$1.object({ + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + outcome: z$1.union([z$1.literal("allowed-once"), z$1.literal("rejected")]) +}); +//#endregion +//#region lib/types/api/questions.schema.js +/** +* questions domain zod schemas (respond is a client-response; the payload schema serves +* the /api/respond endpoint's second parse after routing via the pending table). The question +* identifier is the echoed rpcId; the payload carries no resource id. +*/ +/** AskUserQuestionAnswer validated strictly against core dsh-user-questions. */ +const askUserQuestionAnswerSchema = z$1.object({ answers: z$1.array(z$1.object({ + id: z$1.string(), + selected: z$1.array(z$1.string()), + custom: z$1.string().optional() +})) }); +/** Question answer payload (the result.value slot of a client-response). */ +const questionResponsePayloadSchema = z$1.object({ + sessionId: sessionIdSchema, + answer: askUserQuestionAnswerSchema +}); +//#endregion +//#region lib/types/api/rpc.js +/** +* Four-quadrant RPC message model. Channels and messages are decoupled: HTTP, +* WebSocket, and in-process SSE are physical carriers, while logical messages +* are channel-independent and form a four-member discriminated union. +* api/ contract layer: zero Node dependencies, importable from the browser. +*/ +/** +* Brands a string as RpcId (same precedent as core `SessionId()`). Minted by the initiator: +* client-request → client mints; server-request → host mints (answerable frames get a stable +* logical id, pure pushes mint a fresh one each time). +* @param id - Raw id string (implementations mint UUIDs; tests may pass fixtures). +* @returns The same string, branded (compile-time cast, zero runtime cost). +*/ +function RpcId(id) { + return id; +} +//#endregion +//#region lib/types/native-path-opener.js +/** +* Cross-platform native path and text-document openers used by the local GUI +* carrier. +* +* The default intent prefers the default browser for documents it renders when +* the platform can name one, then falls back to the default application. WSL +* translates every path for the Windows desktop instead of assuming a Linux +* GUI. The text-editor intent never consults the browser. +*/ +/** Documents a browser renders, as opposed to ones an editor merely edits. */ +const BROWSER_DOCUMENTS = new Set([ + ".html", + ".htm", + ".xhtml", + ".svg" +]); +/** +* The macOS bundle registered for `https` — the default browser, as +* LaunchServices records it. The nested version dict is stripped first +* because it carries its own `LSHandlerRoleAll`. +*/ +function macBundleForHttps(plist) { + const stripped = plist.replace(/LSHandlerPreferredVersions\s*=\s*\{[^}]*\};/g, ""); + const block = /\{[^{}]*LSHandlerURLScheme\s*=\s*"?https"?;[^{}]*\}/.exec(stripped)?.[0]; + if (block === void 0) return void 0; + return /LSHandlerRoleAll\s*=\s*"?([\w.-]+)"?;/.exec(block)?.[1]; +} +/** +* Open one browser-renderable document with the default browser. +* @returns true when a browser took it; false when this platform cannot name +* one, or naming it failed — the caller then uses the default application. +*/ +async function openInBrowser(path, signal, platform, run, env) { + if (platform === "darwin") { + let bundle; + try { + const { stdout } = await run("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure"], signal); + bundle = macBundleForHttps(stdout); + } catch { + return false; + } + if (bundle === void 0) return false; + await run("open", [ + "-b", + bundle, + path + ], signal); + return true; + } + if (platform === "linux") { + const browser = env.BROWSER; + if (browser === void 0 || browser === "") return false; + await run(browser, [path], signal); + return true; + } + return false; +} +/** PowerShell single-quoted literal (doubles embedded quotes). */ +function powershellLiteral(path) { + return `'${path.replace(/'/g, "''")}'`; +} +/** Whether one environment marker is set to a non-empty value. */ +function present(value) { + return value !== void 0 && value !== ""; +} +/** Distinguish WSL from desktop Linux using its process and kernel markers. */ +function isWsl(internals) { + const env = internals.env ?? process.env; + if (present(env.WSL_DISTRO_NAME) || present(env.WSL_INTEROP)) return true; + return (internals.osRelease ?? release()).toLowerCase().includes("microsoft"); +} +/** Open one Windows-resolvable path through its registered desktop application. */ +async function openWindowsPath(path, signal, run) { + await run("powershell.exe", [ + "-NoProfile", + "-Command", + `Invoke-Item -LiteralPath ${powershellLiteral(path)}` + ], signal); +} +/** Translate a WSL path before handing it to the Windows desktop. */ +async function openWslPath(path, signal, run) { + const translated = await run("wslpath", ["-w", path], signal); + signal.throwIfAborted(); + const windowsPath = translated.stdout.replace(/[\r\n]+$/, ""); + if (windowsPath === "") throw new Error("wslpath returned no Windows path"); + await openWindowsPath(windowsPath, signal, run); +} +/** Dispatch one shell-free platform command for the requested open intent. */ +async function openNativePathWithIntent(path, signal, intent, internals = {}) { + const platform = internals.platform ?? process.platform; + const run = internals.run ?? runNativeCommand; + const env = internals.env ?? process.env; + const wsl = platform === "linux" && isWsl(internals); + if (!wsl && intent === "default" && BROWSER_DOCUMENTS.has(extname(path).toLowerCase()) && await openInBrowser(path, signal, platform, run, env)) return; + if (platform === "darwin") { + await run("open", intent === "text-editor" ? ["-t", path] : [path], signal); + return; + } + if (platform === "win32") { + await openWindowsPath(path, signal, run); + return; + } + if (platform === "linux") { + if (wsl) { + await openWslPath(path, signal, run); + return; + } + await run("xdg-open", [path], signal); + return; + } + throw new Error(`native path opener is unsupported on ${platform}`); +} +/** +* Whether {@link openNativePath} plausibly reaches a desktop on this host. +* +* macOS and Windows always carry a desktop opener; Linux does when it is WSL +* (the Windows desktop takes the path) or a display server is announced. +* A headless or containerised Linux host answers false, which is what lets a +* surface show a path as text instead of offering a button that would spawn +* `xdg-open` into nothing. +* @param internals - platform and environment seam for deterministic tests. +* @returns true when handing a path to the native opener can work at all. +*/ +function canOpenNativePath(internals = {}) { + const platform = internals.platform ?? process.platform; + if (platform === "darwin" || platform === "win32") return true; + if (platform !== "linux") return false; + const env = internals.env ?? process.env; + return isWsl(internals) || present(env.DISPLAY) || present(env.WAYLAND_DISPLAY); +} +/** +* Open a filesystem path with the operating system's default application, or +* with the default browser when the path names a document a browser renders. +* @param path - absolute or host-resolvable path (caller owns resolution). +* @param signal - caller/connection lifetime; abort terminates the native command. +* @param internals - Platform, environment, and runner hooks for deterministic tests. +*/ +function openNativePath(path, signal, internals = {}) { + return openNativePathWithIntent(path, signal, "default", internals); +} +/** +* Open a text document for editing; macOS bypasses the file-type association +* so a YAML association with a browser cannot consume the gesture. +* @param path - absolute or host-resolvable text-document path. +* @param signal - caller/connection lifetime; abort terminates the native command. +* @param internals - Platform and runner hooks for deterministic tests. +*/ +function openNativeTextFile(path, signal, internals = {}) { + return openNativePathWithIntent(path, signal, "text-editor", internals); +} +//#endregion +//#region lib/types/api-proxy.js +/** +* Host-side ApiProxy implementation. Signature discipline: unary takes the +* narrow RpcRequest

and echoes request.rpcId on the RpcResponse. +*/ +/** Page size when history is called without maxMessages. */ +const DEFAULT_MAX_MESSAGES = 50; +/** Provider work budget: at most 100 calls and 2,000 inspected hits. */ +const SESSION_SEARCH_PROVIDER_CALL_LIMIT = 100; +/** Bound cold-log stat fan-out and settle each started batch before cancellation returns. */ +const COLD_SUMMARY_BATCH_SIZE = 16; +/** Default maximum artifact size eligible for one cold blankness read. */ +const DEFAULT_COLD_BLANK_PROBE_MAX_BYTES = 1024; +/** Conversation message event types (the pagination counting unit). */ +const MESSAGE_TYPES = new Set(["user/message", "assistant/message"]); +/** Decode the browser payload while rejecting non-canonical base64 forms. */ +function decodeBase64(data) { + const decoded = Buffer.from(data, "base64"); + if (data.length === 0 || decoded.toString("base64") !== data) throw new AttachmentError("Image upload is not canonical base64.", "INVALID_IMAGE_BASE64"); + return new Uint8Array(decoded); +} +/** Validate one prompt as a batch before publishing any durable image object. */ +async function durablePromptContent(ctx, content) { + if (content.every((part) => part.type === "text")) return content.map((part) => ({ + type: "text", + text: part.text + })); + const prepared = content.map((part) => part.type === "text" ? part : { + part, + data: decodeBase64(part.data) + }); + const images = prepared.filter((part) => "data" in part); + const refs = await ctx.attachments.saveImages(images.map((image) => ({ + data: image.data, + mediaType: image.part.mediaType, + ...image.part.name === void 0 ? {} : { name: image.part.name } + }))); + const blocks = []; + let imageIndex = 0; + for (const item of prepared) { + if (!("data" in item)) { + blocks.push({ + type: "text", + text: item.text + }); + continue; + } + const attachment = refs[imageIndex++]; + /* v8 ignore next -- each prepared image supplied exactly one saveImages input and therefore one ordered ref. */ + if (attachment === void 0) throw new Error("attachment batch result did not preserve input cardinality"); + blocks.push({ + type: "image", + attachment + }); + } + return blocks; +} +/** Search durable content for an image reference, including nested tool results. */ +function imageBlockIn(content, match) { + if (!Array.isArray(content)) return void 0; + for (const value of content) { + if (typeof value !== "object" || value === null || Array.isArray(value)) continue; + const block = value; + if (block.type === "image" && typeof block.attachment === "object" && block.attachment !== null) { + const ref = block.attachment; + if (match(ref)) return ref; + } + if (block.type === "tool-result") { + const nested = imageBlockIn(block.content, match); + if (nested !== void 0) return nested; + } + } +} +/** Search every durable event carrier that can own model-visible content. */ +function imageInEvent(event, match) { + const data = event.data; + const direct = imageBlockIn(data.content, match); + if (direct !== void 0) return direct; + if (data.message !== void 0) { + const wrapped = imageBlockIn(data.message.content, match); + if (wrapped !== void 0) return wrapped; + } + if (data.inserted !== void 0) for (const message of data.inserted) { + const inserted = imageBlockIn(message.content, match); + if (inserted !== void 0) return inserted; + } + if (event.type === "assistant/chunk" && data.chunk?.type === "block-end") return imageBlockIn([data.chunk.block], match); +} +/** True when the current model-visible surface contains an image. */ +function messagesHaveImage(messages) { + return messages.some((message) => contentHasImage(message.content)); +} +/** Resolve the first reference matching one opaque id. */ +function referencedImage(events, attachmentId) { + for (const event of events) { + const found = imageInEvent(event, (ref) => String(ref.attachmentId) === attachmentId); + if (found !== void 0) return found; + } +} +/** Strict browser-zone profile: UTC or an IANA Area/Location-style identifier. */ +const IANA_TIME_ZONE = /^[A-Za-z][A-Za-z0-9_+.-]*(?:\/[A-Za-z0-9_+.-]+)+$/; +/** Validate and canonicalize one browser-supplied IANA zone at the wire boundary. */ +function canonicalClientTimeZone(value) { + if (value.length === 0 || value.trim() !== value || value !== "UTC" && !IANA_TIME_ZONE.test(value)) return void 0; + try { + const canonical = new Intl.DateTimeFormat("en-US", { timeZone: value }).resolvedOptions().timeZone; + /* v8 ignore next -- Intl returns UTC or a canonical IANA Area/Location for accepted input. */ + if (canonical !== "UTC" && !IANA_TIME_ZONE.test(canonical)) return void 0; + return canonical; + } catch { + return; + } +} +/** Read live abort state across awaits without treating it as synchronously immutable. */ +function isAborted(signal) { + return signal.aborted; +} +/** +* Message-boundary pagination: count maxMessages append-origin messages +* backwards from the window tail. Replacement copies never entered the +* conversation a reader sees — they restate a shadowed range for the model +* alone — so they consume no quota; the page stays one contiguous raw range, +* which keeps a compaction's log-only `compaction/summary` record on the same page as its +* replacement. The cut is the starting seq of the oldest message group (chunks +* group via sourceEventSeqs — never cut mid-message). The tail page naturally +* includes the in-progress partial. +*/ +function paginate(events, beforeSeq, maxMessages) { + const window = beforeSeq === void 0 ? [...events] : events.filter((event) => event.seq < beforeSeq); + let count = 0; + let cut = 0; + for (let i = window.length - 1; i >= 0; i--) { + const event = window[i]; + if (!MESSAGE_TYPES.has(event.type) || !isAppendSurfaceEvent(event)) continue; + count++; + const sources = event.sourceEventSeqs; + let groupStart = event.seq; + if (sources !== void 0) { + for (const source of sources) if (source < groupStart) groupStart = source; + } + if (count >= maxMessages) { + cut = groupStart; + break; + } + } + return { + events: window.filter((event) => event.seq >= cut), + hasMore: cut > 0 + }; +} +/** Wrap an ok result echoing the request's rpcId. */ +function ok(request, value) { + return { + rpcId: request.rpcId, + result: { + ok: true, + value + } + }; +} +/** +* Build the provider/model catalog over every registered route. Shared by the +* session-scoped `session.models` and host-scoped `llm.models`. Catalog +* membership stays advisory: an unlisted session selection remains valid for +* provider dispatch, but is not injected back into the selector after its +* owning catalog stops advertising it. Per-provider failures ride `failures` +* without failing the sound groups; groups that advertise nothing are dropped. +*/ +async function buildModelCatalog(ctx) { + const catalog = await Promise.all(ctx.llm.listProviders().map(async (provider) => { + try { + const models = await ctx.llm.listModels(provider.id); + const entries = await Promise.all(models.map(async (model) => { + const resolved = await ctx.llm.resolveModelInfo(provider.id, model.id); + const reasoning = resolved.reasoning === void 0 ? void 0 : { + efforts: resolved.reasoning.efforts.map((effort) => ({ + id: effort.id, + name: effort.name, + ...effort.description === void 0 ? {} : { description: effort.description } + })), + ...resolved.reasoning.defaultEffort === void 0 ? {} : { defaultEffort: resolved.reasoning.defaultEffort } + }; + return { + id: model.id, + name: model.name, + ...model.description === void 0 ? {} : { description: model.description }, + ...reasoning === void 0 ? {} : { reasoning } + }; + })); + return { + kind: "group", + group: { + id: provider.id, + name: provider.name, + models: entries + } + }; + } catch (error) { + return { + kind: "failure", + failure: { + id: provider.id, + name: provider.name, + message: error instanceof Error ? error.message : String(error) + } + }; + } + })); + return { + groups: catalog.flatMap((item) => item.kind === "group" ? [item.group] : []).filter((group) => group.models.length > 0), + failures: catalog.flatMap((item) => item.kind === "failure" ? [item.failure] : []) + }; +} +/** Wrap an error result echoing the request's rpcId. */ +function err(request, error) { + return { + rpcId: request.rpcId, + result: { + ok: false, + error + } + }; +} +/** +* The RPC refusal a preset failure becomes, or undefined when the failure is +* about something else. +* +* Both the session-create path and the switch path can be handed the same two +* failures, and a client that has to branch on the code needs them worded the +* same from either. +* @param request - the request being answered. +* @param error - the thrown value. +* @returns the refusal, or undefined when the caller should keep handling. +*/ +function presetFailure(request, error) { + if (error instanceof UnknownPresetError) return err(request, { + code: "agent-preset-not-found", + message: error.message, + details: { + agentPreset: error.presetId, + available: [...error.available] + } + }); + if (error instanceof PresetMountError) return err(request, { + code: "agent-preset-invalid", + message: error.message, + details: { + agentPreset: error.presetId, + reason: error.reason + } + }); +} +/** Simple async queue: core callbacks push, the AsyncIterable pulls; abort/return cleans up. */ +var FrameQueue = class { + buffer = []; + waiter; + done = false; + push(item) { + if (this.done) return; + this.buffer.push(item); + this.waiter?.(); + } + end() { + this.done = true; + this.waiter?.(); + } + async *iterate(signal, cleanup) { + const onAbort = () => { + this.end(); + }; + signal.addEventListener("abort", onAbort, { once: true }); + try { + while (true) { + while (this.buffer.length > 0) yield this.buffer.shift(); + if (this.done || signal.aborted) return; + await new Promise((resolve) => { + this.waiter = resolve; + }); + this.waiter = void 0; + } + } finally { + signal.removeEventListener("abort", onAbort); + cleanup(); + } + } +}; +/** +* Server-side frame mint: pure pushes get a fresh rpcId per frame (answerable +* frames — approval/question requested — mint their stable id in their +* pending registries instead). +*/ +function frame(payload) { + return { + rpcId: RpcId(randomUUID()), + payload + }; +} +/** +* Narrow one allowlisted host event's argument list to the JSON values the +* wrapper frame carries. A rejected argument is an allowlist mistake (the +* forwarded path applies no projection), not hostile input, so it throws rather +* than degrading to a lossy frame. The throw surfaces where the forwarding +* listener runs, so the emitter's own listener containment logs it and drops +* that frame — loud in the Host log, not at load or at the emit. Exported for +* the test that owns this decision: every currently allowlisted event has a +* statically JSON-safe payload, so a type-legal `ctx.emit` cannot reach the +* rejection branch. +* @param event - forwarded host event name, named in the failure. +* @param args - the emitter's argument list. +* @returns the same arguments typed as JSON values. +*/ +function assertJsonArgs(event, args) { + for (const [index, arg] of args.entries()) if (!isJsonValue(arg)) throw new Error(`forwarded host event "${event}" argument ${index} is not lossless JSON data`); + return args; +} +/** Queue the subscription baseline frame. */ +function subscribeSession(queue, session) { + queue.push(frame({ + type: "session/subscribed", + sessionId: session.id, + lastSeq: session.seq - 1 + })); +} +/** +* Project registry snapshots onto the wire view, dropping the three internal +* fields {@link JobView} documents as absent. +*/ +function jobViews(snapshots) { + return snapshots.map((job) => ({ + id: job.id, + kind: job.kind, + label: job.label, + status: job.status, + ...job.detail === void 0 ? {} : { detail: job.detail }, + startedAt: job.startedAt, + ...job.finishedAt === void 0 ? {} : { finishedAt: job.finishedAt } + })); +} +/** +* Whether the session's conversation has started: no turn has run yet (a +* turn is one model-loop execution). Standalone plugin events — command +* lifecycle records, plan/mode, titles, goals — never open a turn, so +* running `/plan` or `/goal` on a fresh session keeps it blank +* (list-hidden, reusable). +*/ +function sessionBlank(session) { + return !session.events.some((event) => event.type === "turn/start"); +} +/** Advance the Session-list hint projection by one committed event. */ +function applySessionListMetadata(state, event) { + const blank = state.blank && event.type !== "turn/start"; + const lastPromptAt = event.type === "user/message" && event.data.source.kind === "user" ? event.time : state.lastPromptAt; + return blank === state.blank && lastPromptAt === state.lastPromptAt ? state : { + blank, + lastPromptAt + }; +} +/** Fold exact list metadata for an attached Session. */ +function sessionListMetadata(events) { + let state = { + blank: true, + lastPromptAt: null + }; + for (const event of events) state = applySessionListMetadata(state, event); + return state; +} +/** Sort by creation or latest human prompt, whichever is newer. */ +function sessionListUpdatedAt(header, metadata) { + return Math.max(header.createdAt, metadata?.lastPromptAt ?? 0); +} +/** Shared Session-header projection for list baselines and creation frames. */ +function sessionListFields(header, events = []) { + const agentPreset = resolveSessionPreset({ + header, + events + }); + return { + ...header.parentSession === void 0 ? {} : { parentSessionId: header.parentSession }, + ...header.origin === void 0 ? {} : { origin: header.origin }, + ...header.cwd === void 0 ? {} : { cwd: header.cwd }, + ...agentPreset === void 0 ? {} : { agentPreset } + }; +} +/** SessionSummary projection for attached (in-memory) sessions. */ +function summarize(session, running) { + const metadata = sessionListMetadata(session.events); + return { + sessionId: session.id, + updatedAt: sessionListUpdatedAt(session.header, metadata), + running, + blank: metadata.blank, + ...sessionListFields(session.header, session.events) + }; +} +/** +* Verify a possibly blank cold Session only when its physical artifact passes +* the configured per-Session size check. A stale `blank: true`, an +* absent cache row, a large or location-less artifact, and read failures all +* resolve to visible (`false`); listing must never hide a conversation on a +* cache hint or an unavailable optimization. +*/ +async function probeColdSessionMetadata(ctx, persistence, meta, maxBytes, signal) { + if (maxBytes === 0) return void 0; + signal?.throwIfAborted(); + const location = persistence.locate(meta); + if (location === void 0) return void 0; + signal?.throwIfAborted(); + let size; + try { + size = (await stat(location.path)).size; + } catch { + signal?.throwIfAborted(); + return; + } + if (size > maxBytes) return void 0; + try { + const { events } = await persistence.readFrom(meta.id, 0, signal); + signal?.throwIfAborted(); + return sessionListMetadata(events); + } catch (error) { + signal?.throwIfAborted(); + ctx.logger.warn(`session.list: blank probe for "${meta.id}" failed (serving it as visible): ${String(error)}`); + return; + } +} +/** SessionSummary projection for a cold persisted Session. */ +async function summarizeCold(ctx, persistence, meta, metadata, blankProbeMaxBytes, signal) { + const probed = metadata?.blank === false ? void 0 : await probeColdSessionMetadata(ctx, persistence, meta, blankProbeMaxBytes, signal); + return { + sessionId: meta.id, + updatedAt: sessionListUpdatedAt(meta, probed ?? metadata), + running: false, + blank: metadata?.blank === false ? false : probed?.blank ?? false, + ...sessionListFields(meta) + }; +} +/** Map a browse-primitive failure onto the wire error vocabulary (unknown throws stay internal). */ +function directoryError(error) { + if (error instanceof DirectoryPickerError) return { + code: error.code, + message: error.message, + details: { path: error.path } + }; + return { + code: "internal", + message: error instanceof Error ? error.message : String(error), + details: {} + }; +} +/** Project a pending entry into its answerable mux frame (initial push and mux-open replay share it). */ +function requestedFrame(pending) { + return { + rpcId: pending.rpcId, + payload: { + type: "approval/requested", + sessionId: pending.sessionId, + approvalId: pending.approvalId, + toolName: pending.toolName, + ...pending.callId === void 0 ? {} : { callId: pending.callId }, + ...pending.reason === void 0 ? {} : { reason: pending.reason } + } + }; +} +/** Validate one answer batch against the exact question request it resolves. */ +function matchesQuestions(payload, pending) { + if (payload.sessionId !== pending.sessionId) return false; + const answers = payload.answer.answers; + if (answers.length !== pending.questions.length) return false; + return answers.every((answer, index) => { + const question = pending.questions[index]; + if (answer.id !== question.id) return false; + if (new Set(answer.selected).size !== answer.selected.length) return false; + const custom = answer.custom?.trim(); + if (custom !== void 0 && custom === "") return false; + if (question.multiSelect !== true) { + if (custom !== void 0 && answer.selected.length > 0) return false; + if (answer.selected.length > 1) return false; + } + const labels = new Set(question.options?.map((option) => option.label) ?? []); + return answer.selected.every((label) => labels.has(label)); + }); +} +/** +* Compute the render intent for a tool/call or tool/result event through the +* presenters registered at this moment; every other event type gets none. A +* result's presenter needs its call's parsed args — `argsFor` supplies them +* (live: the per-session call table; history: an in-page backscan), returning +* undefined when the pairing is unavailable (e.g. the call fell off the page), +* which soft-falls to no view. Presenter or JSON.parse throws also soft-fall: +* the client's documented default (generic JSON card) covers every miss. +*/ +function viewFor(ctx, event, argsFor, scope) { + try { + if (event.type === "tool/call") { + const { name, arguments: raw } = event.data; + const view = ctx.tools.get(name, scope)?.presentCall?.(JSON.parse(raw)); + return view === void 0 ? void 0 : { + for: "call", + view + }; + } + if (event.type === "tool/result") { + const { message, meta } = event.data; + const [result] = message.content; + const callId = message.source.callId; + const call = argsFor(callId); + if (call === void 0) return void 0; + const view = ctx.tools.get(call.name, scope)?.presentResult?.(call.args, { + content: result.content, + isError: result.isError === true, + ...meta === void 0 ? {} : { meta } + }); + return view === void 0 ? void 0 : { + for: "result", + view + }; + } + } catch (error) { + console.error(`api-proxy: presenter failed for ${event.type}, falling back to generic: ${String(error)}`); + } +} +/** +* Resolve a tool/result's call pairing by scanning a window of events backwards +* for the matching tool/call. Used by the history path (the page is the +* window — a cross-page pairing soft-falls to no view) and by live-path table +* misses after a reconnect-eviction. +*/ +function backscanArgs(events, callId) { + for (let i = events.length - 1; i >= 0; i--) { + const event = events[i]; + if (event.type !== "tool/call") continue; + const data = event.data; + if (data.callId !== callId) continue; + try { + return { + name: data.name, + args: JSON.parse(data.arguments) + }; + } catch { + return; + } + } +} +/** Render one detached history page through the same presenter path as ordinary history. */ +function historyPage(ctx, events, beforeSeq, maxMessages, scope) { + const page = paginate(events, beforeSeq, maxMessages ?? DEFAULT_MAX_MESSAGES); + return { + events: page.events.map((event) => { + const view = viewFor(ctx, event, (callId) => backscanArgs(page.events, callId), scope); + return { + event, + ...view === void 0 ? {} : { view } + }; + }), + hasMore: page.hasMore + }; +} +function projectionsFor(ctx, session) { + const registry = ctx.get("sessionProjections"); + if (registry === void 0) return void 0; + return registry.snapshot(session); +} +/** +* The projection baseline of one session.list row, fail-soft: attached +* sessions cut the registry's live watermark cache; cold sessions view the +* persisted projection cache's identity-checked stored rows (zero log loads +* either way — the listing use case the cache exists for). The block shape +* (values + asOfSeq) matches the history tail's, so a client seeds its +* value store under the same higher-seq-wins rule. Any failure — and an +* empty value set — yields an absent block: a listing without projections +* is degraded, never broken. +*/ +function listProjectionsFor(ctx, meta, session) { + try { + const block = session !== void 0 ? ctx.get("sessionProjections")?.snapshot(session) : ctx.get("sessionProjectionCache")?.cachedSnapshot(meta); + return block !== void 0 && Object.keys(block.values).length > 0 ? block : void 0; + } catch (error) { + ctx.logger.warn(`session.list: projection column for "${meta.id}" failed (serving the row without it): ${String(error)}`); + return; + } +} +/** Projection baseline for a detached history tail without Agent activation. */ +function detachedProjectionsFor(ctx, events) { + const registry = ctx.get("sessionProjections"); + if (registry === void 0) return void 0; + return registry.restore({}, events, 0).snapshot; +} +/** +* Best-effort projections for one subagent history page, fail-soft like +* {@link listProjectionsFor}: a registered unit throwing on a corrupt payload +* never blocks transcript reading — the page is served without the block. +* @param ctx - context carrying the logger for the degradation warning. +* @param childSessionId - the child whose page is being decorated. +* @param compute - the arm-specific fold (live watermark or detached restore). +* @returns the projections block, or undefined when the fold failed. +*/ +function subagentHistoryProjections(ctx, childSessionId, compute) { + try { + return compute(); + } catch (error) { + ctx.logger.warn(`subagent.history: projections for "${childSessionId}" failed (serving the page without them): ${String(error)}`); + return; + } +} +/** Map continuation admission failures without exposing provider details. */ +function subagentPromptError(request, error, signal) { + const childSessionId = request.payload.childSessionId; + if (signal.aborted) return err(request, { + code: "cancelled", + message: "subagent prompt was cancelled", + details: {} + }); + if (error instanceof SubagentError) switch (error.code) { + case "NOT_RESUMABLE": return err(request, { + code: "subagent-not-resumable", + message: "subagent cannot be resumed", + details: { childSessionId } + }); + case "UNAUTHORIZED": return err(request, { + code: "subagent-unauthorized", + message: "subagent does not belong to this parent", + details: { childSessionId } + }); + case "DRAINING": + case "ACTIVATION_CLOSING": + case "CONTINUATION_UNAVAILABLE": + case "PERSISTENCE_UNAVAILABLE": return err(request, { + code: "subagent-delivery-unavailable", + message: "subagent follow-up is temporarily unavailable", + details: { childSessionId } + }); + default: break; + } + return err(request, { + code: "internal", + message: "subagent prompt failed", + details: {} + }); +} +/** Stable RPC face of the missing projections capability, shared by every catalog read path. */ +function projectionsUnavailableError() { + return { + code: "internal", + message: "subagent catalog is unavailable: this deployment does not mount the sessionProjections registry (load @deepseek-ai/dsh-session-projection)", + details: {} + }; +} +/** Verify one address and mode against the complete direct-child catalog. */ +async function catalogChild(ctx, address, signal) { + const { parentSessionId, childSessionId, mode } = address; + try { + const entry = (await ctx.subagents.listChildren(parentSessionId, signal)).find((candidate) => candidate.id === childSessionId); + if (entry === void 0 || entry.kind === "child" && entry.mode !== mode) return { error: { + code: "subagent-not-found", + message: `session "${childSessionId}" is not a ${mode} direct child of "${parentSessionId}"`, + details: { + parentSessionId, + childSessionId + } + } }; + if (entry.kind === "diagnostic") return { error: { + code: "subagent-catalog-diagnostic", + message: `subagent "${childSessionId}" is ${entry.reason}`, + details: { + parentSessionId, + childSessionId, + reason: entry.reason + } + } }; + return { entry }; + } catch (error) { + if (signal?.aborted || error instanceof SubagentError && error.code === "CANCELLED") return { error: { + code: "cancelled", + message: "subagent catalog read was cancelled", + details: {} + } }; + if (error instanceof SubagentError && error.code === "SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE") return { error: projectionsUnavailableError() }; + return { error: { + code: "internal", + message: "subagent catalog read failed", + details: {} + } }; + } +} +/** +* The requested preset differs from the one this session already runs. +* +* A session's composition is fixed at creation: its history was produced under +* that preset's tools, so adopting the identity under a different one would +* replay tool calls the rebuilt agent cannot make. Naming a different preset +* is therefore a caller error rather than a switch. +*/ +/** The roster is absent: this deployment composes no agent presets at all. */ +function noRoster(agentPreset) { + return { + code: "agent-preset-not-found", + message: "this deployment composes no agent presets", + details: { + agentPreset, + available: [] + } + }; +} +/** Map one authoring/roster failure onto its wire code. */ +function presetError(agentPreset, error) { + if (error instanceof UnknownPresetError) return { + code: "agent-preset-not-found", + message: error.message, + details: { + agentPreset: error.presetId, + available: [...error.available] + } + }; + if (error instanceof PresetNotWritableError) return { + code: "agent-preset-read-only", + message: error.message, + details: { + agentPreset, + reason: error.message + } + }; + if (error instanceof InvalidPresetIdError || error instanceof PresetExistsError) return { + code: "agent-preset-invalid", + message: error.message, + details: { + agentPreset, + reason: error.message + } + }; + return { + code: "internal", + message: `agent preset "${agentPreset}": ${String(error)}`, + details: {} + }; +} +var AgentPresetConflict = class extends Error { + sessionId; + requestedPreset; + existingPreset; + constructor(sessionId, requestedPreset, existingPreset) { + super(existingPreset === void 0 ? `session "${sessionId}" records no agent preset, so it cannot be adopted under one; a deployment composing no roster records none on any session — ` : `session "${sessionId}" already runs agent preset ${JSON.stringify(existingPreset)}; requested ${JSON.stringify(requestedPreset)}. A session's preset is fixed at creation.`); + this.sessionId = sessionId; + this.requestedPreset = requestedPreset; + this.existingPreset = existingPreset; + } +}; +/** Requested identity already belongs to a session with another project cwd. */ +var SessionCwdConflict = class extends Error { + sessionId; + requestedCwd; + existingCwd; + constructor(sessionId, requestedCwd, existingCwd) { + super(`session "${sessionId}" already exists with cwd ${JSON.stringify(existingCwd)}; requested ${JSON.stringify(requestedCwd)}`); + this.sessionId = sessionId; + this.requestedCwd = requestedCwd; + this.existingCwd = existingCwd; + } +}; +/** An explicit Host naming operation would duplicate another Workspace title. */ +var WorkspaceNameConflictError = class extends Error { + workspaceName; + constructor(workspaceName) { + super(`workspace name '${workspaceName}' is already in use`); + this.workspaceName = workspaceName; + this.name = "WorkspaceNameConflictError"; + } +}; +/** Shared workspace-not-found error response of the workspace.* mutation rows. */ +function workspaceNotFound(request, workspaceId) { + return err(request, { + code: "workspace-not-found", + message: `workspace "${workspaceId}" not found`, + details: { workspaceId } + }); +} +/** Wire projection of one workspace entity (the workspace.* value row). */ +function workspaceView(workspace) { + return { + workspaceId: workspace.id, + path: workspace.path, + title: workspace.title, + sessionIds: [...workspace.sessionIds], + createdAt: workspace.createdAt, + updatedAt: workspace.updatedAt + }; +} +/** Wire projection of the durable record carried by `domain/changed`. */ +function changedWorkspaceView(workspaceId, value) { + const record = workspaceRecord.parse(value); + return { + workspaceId, + path: record.path, + title: record.title, + sessionIds: [...record.sessionIds], + createdAt: record.createdAt, + updatedAt: record.updatedAt + }; +} +/** +* Implement ApiProxy over a composed host context. +* @param ctx - a context with the Host spine and Workspace registry mounted. +* @param defaults - host routing and project-directory defaults. +* @returns the ApiProxy implementation. +*/ +function createApiProxy(ctx, defaults) { + const sessionExportCompressionLevel = defaults.sessionExportCompressionLevel ?? 6; + const coldBlankProbeMaxBytes = defaults.coldBlankProbeMaxBytes ?? 1024; + /** The seed model each create/resume declares; re-read so it never goes stale. */ + const agentOptions = () => { + const { provider, model } = defaults.defaultModelSelection(); + return { + provider, + model + }; + }; + const selections = /* @__PURE__ */ new WeakMap(); + /** + * Serializes `agentPreset.select` per session. Two concurrent selects both + * pass the blank check, and the second `unmountPresetFor` then finds nothing + * to unmount because the first already removed the record — leaving two + * compositions registered into one agent layer. The client's `busy` flag is + * not enforcement: the wire is reachable directly. + */ + const presetSwitches = /* @__PURE__ */ new Map(); + /** Client-chosen identity creation/resume, deduplicated across concurrent retries. */ + const sessionCreations = /* @__PURE__ */ new Map(); + /** Serializes path ownership and explicit title checks with Workspace mutations. */ + let workspaceCreationChain = Promise.resolve(); + const pendingQuestions = /* @__PURE__ */ new Map(); + const pendingApprovals = /* @__PURE__ */ new Map(); + const muxQueues = /* @__PURE__ */ new Set(); + const imageAdmissionChains = /* @__PURE__ */ new WeakMap(); + /** Serialize image admission with model selection for one agent. */ + function serializeImageAdmission(agent, operation) { + const result = (imageAdmissionChains.get(agent) ?? Promise.resolve()).then(operation); + imageAdmissionChains.set(agent, result.then(() => void 0, () => void 0)); + return result; + } + /** + * Install or return the session-local model selection that prompt assembly snapshots. + * + * Precedence, resolved on EVERY read rather than seeded once: a selection + * made in this process, else the session's own latest logged request/header, + * else the live Agent default. Re-reading keeps the two tiers exact in both + * directions: a session with a recorded request derives its selection from + * its log, while a blank session (New Session reuses one rather than minting + * another) reads any default saved after it was created. There is no create-time + * per-session override tier on this wire — if one returns (a create-options + * contribution), it must fold in between the selection and the log. + */ + function selectionFor(agent) { + const installed = selections.get(agent); + if (installed !== void 0) return installed; + let picked; + const selection = { + get current() { + if (picked !== void 0) return picked; + const logged = agent.session.requestHeader()?.config; + if (logged === void 0) return defaults.defaultModelSelection(); + return { + provider: logged.provider, + model: logged.model, + ...logged.reasoningEffort === void 0 ? {} : { reasoningEffort: logged.reasoningEffort } + }; + }, + set current(next) { + picked = next; + }, + assembled: void 0 + }; + installModelSelection(agent.ctx, selection); + selections.set(agent, selection); + return selection; + } + /** Pre-publication setup used by both fresh and resumed Web agents. */ + function installSelection(agentCtx) { + const agent = agentCtx.agent; + if (agent === void 0) throw new Error("api-proxy: agent setup has no scoped agent"); + selectionFor(agent); + } + /** + * Reject an attempt to run an existing session under a different preset. + * + * A caller that names no preset always adopts the session as it is, so the + * common paths — reconnecting, resuming, retrying a create — are unaffected. + * @param sessionId - the identity being adopted. + * @param requested - the preset the request named, if any. + * @param existing - the preset the session RUNS, if any; both callers resolve + * it from the log, which differs from the creation header once a blank + * session has switched. + * @throws when both are present and differ. + */ + function assertPresetUnchanged(sessionId, requested, existing) { + if (requested === void 0 || requested === existing) return; + throw new AgentPresetConflict(sessionId, requested, existing); + } + /** + * Resolve the preset an agent will be composed from, and the setup that + * installs it. + * + * The id is resolved BEFORE the session exists because the session boundary + * snapshots `meta` before asynchronous setup begins — a preset discovered + * during setup could never reach the header. Mounting still happens in + * setup, where a failure rolls the whole creation back rather than leaving a + * published session whose capabilities are half-installed. + * + * A deployment with no preset roster composes nothing and every session + * shares the host composition, which is the behavior before presets existed. + * @param presetId - the requested preset, or `undefined` for the default. + * @returns the id to record on the header (absent without a roster) and the setup callback. + * @throws when the roster supplies no such preset. + */ + async function composeAgent(presetId) { + const presets = ctx.get("agentPresets"); + if (presets === void 0) return { setup: (agentCtx) => { + installSelection(agentCtx); + return Promise.resolve(); + } }; + const resolvedId = (await presets.resolve(presetId)).id; + return { + agentPreset: resolvedId, + setup: async (agentCtx) => { + installSelection(agentCtx); + await presets.mount(agentCtx, resolvedId); + } + }; + } + const hasSubagentOwner = (session, agent) => hasApiRemoteSubagentOwner(ctx, session, agent); + const subagentOwnershipError = (sessionId) => apiRemoteSubagentOwnershipError(sessionId); + const inspectServable = (sessionId) => inspectApiRemoteSession(ctx, sessionId); + const agentFor = createApiRemoteAgentResolver(ctx, { + agentOptions, + setup: async ({ meta, events }) => (await composeAgent(resolveSessionPreset({ + header: meta, + events + }))).setup + }); + /** Send one transient frame to every connected mux consumer. */ + function broadcast(payload) { + const envelope = frame(payload); + for (const queue of muxQueues) queue.push(envelope); + } + ctx.inject(["sessionProjections"], (projectionCtx) => { + projectionCtx.sessionProjections.onChanged((session, key, value, seq) => { + broadcast({ + type: "session/projection", + sessionId: session.id, + key, + value, + seq + }); + }); + }); + ctx.inject(["sessionProjections"], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: "sessionListMetadata", + schema: sessionListMetadataProjectionSchema, + init: () => ({ + blank: true, + lastPromptAt: null + }), + apply: applySessionListMetadata, + view: (state) => state, + stateVersion: 1 + }); + }); + ctx.inject(["sessionProjections", "attachments"], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: "imageLimits", + schema: imageLimitsProjectionSchema, + init: () => null, + apply: (state) => state, + view: () => projectionCtx.attachments.imageLimits, + stateVersion: 1 + }); + }); + /** Project both durable inbox lists, optionally including the splice currently being emitted. */ + const queueItems = (agent, splice) => { + const project = (target) => { + const messages = target === "next-turn" ? agent.inbox.nextTurn : agent.inbox.nextStep; + return splice?.target === target ? messages.toSpliced(splice.start, splice.removedCount ?? 0, ...splice.inserted) : messages; + }; + return [...project("next-turn").map((message) => ({ + id: message.id, + placement: "queued", + message + })), ...project("next-step").map((message) => ({ + id: message.id, + placement: message.source.kind === "user" ? "steering" : "context", + message + }))]; + }; + ctx.on("session/event", (session, event) => { + if (event.type !== "agent/inbox/spliced") return; + const agent = ctx.agents.get(session.id); + if (agent?.session !== session) return; + broadcast({ + type: "session/queue", + sessionId: session.id, + items: queueItems(agent, event.data) + }); + }); + /** Remove a wait before settling it: synchronous deletion makes the first claimant win. */ + function claimQuestion(pending, outcome) { + pendingQuestions.delete(pending.rpcId); + if (pending.signal !== void 0 && pending.onAbort !== void 0) pending.signal.removeEventListener("abort", pending.onAbort); + broadcast({ + type: "question/resolved", + sessionId: pending.sessionId, + questionRpcId: pending.rpcId, + outcome + }); + } + const disposeProvider = ctx.userQuestions.registerProvider({ ask(request) { + const sessionId = request.agent?.id; + if (sessionId === void 0) return Promise.reject(new UserQuestionError("web user interaction requires an agent-owned session", "ASK_MISSING_AGENT")); + return new Promise((resolve, reject) => { + const rpcId = RpcId(randomUUID()); + const pending = { + rpcId, + sessionId, + questions: request.questions, + resolve, + reject, + ...request.signal === void 0 ? {} : { signal: request.signal } + }; + const onAbort = () => { + claimQuestion(pending, "cancelled"); + reject(new UserQuestionError("ask_user_question was aborted before the user answered", "ASK_ABORTED")); + }; + pending.onAbort = onAbort; + pendingQuestions.set(rpcId, pending); + request.signal?.addEventListener("abort", onAbort, { once: true }); + const envelope = { + rpcId, + payload: { + type: "question/requested", + sessionId, + questions: request.questions + } + }; + for (const queue of muxQueues) queue.push(envelope); + }); + } }); + ctx.effect(() => () => { + disposeProvider(); + for (const pending of [...pendingQuestions.values()]) { + claimQuestion(pending, "cancelled"); + pending.reject(new UserQuestionError("web user-questions provider was disposed", "ASK_ABORTED")); + } + }, "api-proxy: user-questions provider"); + if (ctx.get("approval") !== void 0) { + ctx.effect(() => () => { + for (const pending of [...pendingApprovals.values()]) pending.resolve("cancelled"); + }, "api-proxy: approval registry teardown"); + ctx.on("approval/request", (req, next) => { + if (req.signal?.aborted === true) return Promise.resolve("cancelled"); + const events = req.agent.session.events; + const claimed = /* @__PURE__ */ new Set(); + for (const entry of pendingApprovals.values()) claimed.add(entry.approvalId); + const decided = /* @__PURE__ */ new Set(); + let approvalId; + for (let i = events.length - 1; i >= 0; i -= 1) { + const event = events[i]; + if (event.type === "approval/decided") decided.add(event.data.id); + else if (event.type === "approval/asked") { + if (decided.has(event.data.id) || claimed.has(event.data.id)) continue; + if ((req.callId ?? null) !== (event.data.callId ?? null)) continue; + approvalId = event.data.id; + break; + } + } + if (approvalId === void 0) return next(); + const id = approvalId; + return new Promise((resolve) => { + const settle = (outcome) => { + /* v8 ignore next 3 -- defensive double-settle guard: respond() routes + through the pending table (a settled id is not-pending before it can + re-settle) and the first settle removes the abort listener, so no + reachable path settles twice; kept against future settle callers. */ + if (!pendingApprovals.delete(pending.rpcId)) return; + req.signal?.removeEventListener("abort", onAbort); + broadcast({ + type: "approval/resolved", + sessionId: pending.sessionId, + approvalId: id, + outcome + }); + resolve(outcome); + }; + const onAbort = () => { + settle("cancelled"); + }; + const pending = { + rpcId: RpcId(randomUUID()), + sessionId: req.agent.session.id, + approvalId: id, + toolName: req.toolName, + ...req.callId === void 0 ? {} : { callId: req.callId }, + ...req.reason === void 0 ? {} : { reason: req.reason }, + resolve: settle + }; + pendingApprovals.set(pending.rpcId, pending); + req.signal?.addEventListener("abort", onAbort, { once: true }); + const envelope = requestedFrame(pending); + for (const queue of muxQueues) queue.push(envelope); + }); + }); + } + /** Read one stable session prefix without acquiring an Agent owner. */ + async function readSessionState(sessionId) { + const attached = ctx.sessions.get(sessionId); + if (attached !== void 0) return { + id: attached.id, + header: attached.header, + events: [...attached.events] + }; + const inspected = await inspectServable(sessionId); + return { + id: inspected.meta.id, + header: inspected.meta, + events: inspected.events + }; + } + /** Resolve the Workspace inherited by a fork without making ordinary loose lineage grouped. */ + async function forkWorkspace(source) { + const workspaces = ctx.workspaceRegistry.list(); + const direct = workspaces.find((workspace) => workspace.sessionIds.includes(source.id)); + if (direct !== void 0 || source.header.origin !== "subagent") return direct; + const lineage = await ctx.sessionQuery.traceSession(source.id); + for (const ancestor of lineage.ancestors) { + const workspace = workspaces.find((candidate) => candidate.sessionIds.includes(ancestor.header.id)); + if (workspace !== void 0) return workspace; + } + } + /** + * Resolve which session one transcript read is served from, without + * acquiring an Agent owner. This is the read's only asynchronous step + * besides ensuring the composition; {@link historyCutOf} takes the cut. + * @param sessionId - the transcript being read. + * @returns the attached session, or the inspected detached header and events. + * @throws {@link ApiRemoteSessionNotFound} when no project-backed session has that identity. + */ + async function historySourceFor(sessionId) { + const attached = ctx.sessions.get(sessionId); + if (attached !== void 0) return { + kind: "attached", + session: attached + }; + const inspected = await inspectServable(sessionId); + return { + kind: "detached", + header: inspected.meta, + events: inspected.events + }; + } + /** + * The header and events {@link presenterScopeFor} reads to decide which + * composition a transcript ran under. + * @param source - the live or detached session this read is served from. + * @returns that session's creation header and its events. + */ + function sourceSession(source) { + if (source.kind === "detached") return { + header: source.header, + events: source.events + }; + return { + header: source.session.header, + events: source.session.events + }; + } + /** + * One transcript cut: the events and the projection baseline that describe + * the SAME log position. + * + * Synchronous, and the two reads sit next to each other, because an attached + * session keeps appending: an `await` between them would serve events cut at + * N beside a baseline folded to N+1, which is one response describing two + * moments. The caller does its awaiting before this call. + * @param source - the live or detached session this read is served from. + * @param includeProjections - whether the caller asked for the baseline (a tail page does). + * @returns the events and, when asked, the baseline for that same position. + */ + function historyCutOf(source, includeProjections) { + if (source.kind === "detached") { + const projections = includeProjections ? detachedProjectionsFor(ctx, source.events) : void 0; + return { + events: source.events, + ...projections === void 0 ? {} : { projections } + }; + } + const events = [...source.session.events]; + const projections = includeProjections ? projectionsFor(ctx, source.session) : void 0; + return { + events, + ...projections === void 0 ? {} : { projections } + }; + } + /** + * The registry view scope a transcript's presenters resolve in. + * + * A live agent is that scope itself (its chain passes through its preset's + * standing layer). A cold session resolves its preset from the LOG, and the + * preset's STANDING key serves without resuming anything — ensuring the + * mount composes plugins but starts no agent, session, or turn. No roster, + * no recorded preset, or a preset the roster no longer supplies all fall + * back to the global layer: the transcript still serves, with the generic + * cards a viewless entry renders. + * + * Reading the header alone would render a session that switched while blank + * through the composition it was CREATED with. Every tool only the newer + * preset registers resolves to no presenter there, and the transcript + * silently degrades to generic cards for exactly the calls its history is + * made of. + * @param sessionId - the transcript being read. + * @param session - that session's header and log (attached or inspected). + * @returns the scope to pass to presenter lookups, or undefined for global. + */ + async function presenterScopeFor(sessionId, session) { + const live = ctx.get("agents")?.get(sessionId); + if (live !== void 0) return live; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return void 0; + try { + return await presets.standingKeyFor(resolveSessionPreset(session)); + } catch { + return; + } + } + /** Resolve one requested identity to a live agent, creating or resuming it once. */ + async function ensureSession(sessionId, cwd, checkPersistedIdentity, presetId) { + let creation = sessionCreations.get(sessionId); + if (creation === void 0) { + creation = (async () => { + const attached = ctx.sessions.get(sessionId); + const live = ctx.agents.get(sessionId); + if (attached !== void 0 && hasSubagentOwner(attached, live)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + if (live !== void 0) return live; + const persistence = checkPersistedIdentity ? ctx.get("sessionPersistence") : void 0; + const stored = persistence === void 0 ? void 0 : (await persistence.list()).find((header) => header.id === sessionId); + if (persistence !== void 0 && stored !== void 0) { + const inspected = await persistence.inspect(sessionId); + if (hasSubagentOwner({ header: inspected.meta }, void 0)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + if (inspected.meta.cwd !== cwd) throw new SessionCwdConflict(sessionId, cwd, inspected.meta.cwd); + const storedPreset = resolveSessionPreset({ + header: inspected.meta, + events: inspected.events + }); + assertPresetUnchanged(sessionId, presetId, storedPreset); + return (await ctx.agents.resume({ + resumeSessionId: sessionId, + agentOptions: agentOptions(), + setup: (await composeAgent(storedPreset)).setup + })).agent; + } + try { + await mkdir(cwd, { recursive: true }); + } catch (error) { + throw new Error(`failed to ensure project directory "${cwd}": ${String(error)}`, { cause: error }); + } + const composition = await composeAgent(presetId); + return (await ctx.agents.create({ + sessionId, + agentOptions: agentOptions(), + meta: { + cwd, + ...composition.agentPreset === void 0 ? {} : { agentPreset: composition.agentPreset } + }, + setup: composition.setup + })).agent; + })().catch((error) => { + const live = ctx.agents.get(sessionId); + if (live !== void 0) { + if (hasSubagentOwner(live.session, live)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + return live; + } + const attached = ctx.sessions.get(sessionId); + if (attached !== void 0 && hasSubagentOwner(attached, void 0)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + throw error; + }).finally(() => { + sessionCreations.delete(sessionId); + }); + sessionCreations.set(sessionId, creation); + } + const agent = await creation; + if (hasSubagentOwner(agent.session, agent)) throw new ApiRemoteSubagentSessionOwnership(sessionId); + assertPresetUnchanged(sessionId, presetId, resolveSessionPreset(agent.session)); + if (agent.session.header.cwd !== cwd) throw new SessionCwdConflict(sessionId, cwd, agent.session.header.cwd); + return agent; + } + /** Resolve or create one path while holding the Host's workspace-create chain. */ + function ensureWorkspace(path) { + const operation = workspaceCreationChain.then(async () => { + const existing = await ctx.workspaceRegistry.resolveByPath(path); + if (existing !== void 0) return { + workspace: existing, + created: false + }; + return { + workspace: await ctx.workspaceRegistry.create(path), + created: true + }; + }); + workspaceCreationChain = operation.then(() => void 0, () => void 0); + return operation; + } + /** + * Build the session.list baseline shared by listing and search visibility. + * Attached sessions come from memory; servable cold sessions merge from + * persistence, and the final order is newest-first. + */ + async function listVisibleSessionSummaries(signal) { + signal?.throwIfAborted(); + const summarizeAttached = (session) => { + const agent = ctx.agents.get(session.id); + const projections = listProjectionsFor(ctx, session.header, session); + return { + ...summarize(session, agent?.status === "running"), + ...projections === void 0 ? {} : { projections } + }; + }; + const items = ctx.sessions.list().map(summarizeAttached); + signal?.throwIfAborted(); + const attached = new Set(items.map((item) => item.sessionId)); + const persistence = ctx.get("sessionPersistence"); + if (persistence !== void 0) { + const cold = (await persistence.list(signal)).filter((meta) => !attached.has(meta.id) && meta.cwd !== void 0); + signal?.throwIfAborted(); + for (let offset = 0; offset < cold.length; offset += COLD_SUMMARY_BATCH_SIZE) { + signal?.throwIfAborted(); + const batch = cold.slice(offset, offset + COLD_SUMMARY_BATCH_SIZE); + const settled = await Promise.allSettled(batch.map(async (meta) => { + const projections = listProjectionsFor(ctx, meta, void 0); + const summary = await summarizeCold(ctx, persistence, meta, projections?.values.sessionListMetadata, coldBlankProbeMaxBytes, signal); + const attachedSession = ctx.sessions.get(meta.id); + if (attachedSession !== void 0) return summarizeAttached(attachedSession); + return { + ...summary, + ...projections === void 0 ? {} : { projections } + }; + })); + const summaries = []; + let rejected = false; + let failure; + for (const result of settled) if (result.status === "fulfilled") summaries.push(result.value); + else if (!rejected) { + rejected = true; + failure = result.reason; + } + if (rejected) throw failure; + signal?.throwIfAborted(); + items.push(...summaries); + } + } + items.sort((a, b) => b.updatedAt - a.updatedAt); + return items; + } + /** + * Resolve the goal service THIS agent runs. + * + * The service is per session: an agent preset mounts it behind an `isolate` + * realm, which no host context resolves. Reading it from the root would + * answer "absent" for a session whose composition mounts it — so the lookup + * is keyed by the agent, and only a deployment composing it nowhere is + * genuinely absent. + */ + function goalServiceFor(agent) { + const goals = ctx.get("agentPresets")?.serviceFor(agent, "goals") ?? ctx.get("goals"); + if (goals === void 0) return { error: { + code: "internal", + message: "goal service is absent: neither this session's agent preset nor the host composition mounts @deepseek-ai/dsh-goal", + details: {} + } }; + return goals; + } + /** Map one goal-domain rejection to the wire error (stable GoalError codes ride in details). */ + function goalError(request, error) { + const details = error instanceof GoalError ? { goalCode: error.code } : {}; + return err(request, { + code: "internal", + message: String(error), + details + }); + } + /** Resolve a session's agent, apply one goal mutation, and acknowledge with the new CAS ref. */ + async function mutateGoal(request, mutation) { + const found = await agentFor(request.payload.sessionId); + if ("error" in found) return err(request, found.error); + const goals = goalServiceFor(found.agent); + if ("error" in goals) return err(request, goals.error); + try { + const ref = mutation(goals, found.agent); + return ok(request, { ref: { + id: ref.id, + revision: ref.revision + } }); + } catch (error) { + return goalError(request, error); + } + } + /** + * Whether an adapter currently serves this provider, and therefore whether + * a session selecting it can start a turn. Catalog membership cannot answer + * it: an adapter may serve a model its own catalog stopped advertising, so + * a provider missing from the groups is not the same as one nothing serves. + * A composition with no llm registry at all cannot judge and says yes — + * the dispatch it would have refused fails on its own terms. + */ + function routeServed(provider) { + const llm = ctx.get("llm"); + return llm === void 0 || llm.listProviders().some((entry) => entry.id === provider); + } + /** + * Resolve the addressed agent for a turn-starting method and refuse when no + * adapter serves its current selection: a provider nothing serves cannot start a + * turn, and letting it try spends the whole pre-step path to fail inside + * the adapter with a message about registration. Refusing here names the + * model the session is pointed at while the draft is still in the composer. + * This is `session.prompt`'s enforcement boundary: a client that disables + * its input is an affordance, and the method stays callable regardless. + */ + async function turnAgentFor(request, sessionId) { + const found = await agentFor(sessionId); + if ("error" in found) return { refused: err(request, found.error) }; + const agent = found.agent; + const selection = selectionFor(agent).current; + if (!routeServed(selection.provider)) return { refused: err(request, { + code: "model-unavailable", + message: `no adapter serves provider "${selection.provider}"; select a model for this session`, + details: { + provider: selection.provider, + model: selection.model + } + }) }; + return { agent }; + } + /** Missing-service report shared by the settings domain (skills-domain stance). */ + function settingsAbsent() { + return { + code: "internal", + message: "settings service is absent: this deployment does not mount a settings provider (e.g. @deepseek-ai/dsh-settings-file) in its composition", + details: {} + }; + } + /** Open one Host-resolved target and map native failures onto the wire vocabulary. */ + async function openTarget(request, path, signal, open) { + try { + await open(path, signal); + return ok(request, { opened: true }); + } catch (error) { + if (signal.aborted) return err(request, { + code: "cancelled", + message: "path open was aborted", + details: {} + }); + return err(request, { + code: "internal", + message: `path open failed: ${error instanceof Error ? error.message : String(error)}`, + details: {} + }); + } + } + /** Open one Host-resolved path with its default application. */ + function openPath(request, path, signal) { + return openTarget(request, path, signal, defaults.openPath ?? ((target, openSignal) => openNativePath(target, openSignal))); + } + /** Open one Host-resolved text document in a native editor. */ + function openTextFile(request, path, signal) { + return openTarget(request, path, signal, defaults.openTextFile ?? ((target, openSignal) => openNativeTextFile(target, openSignal))); + } + /** Whether this deployment can hand a path to a native opener at all. */ + function canOpenPaths() { + if (defaults.canOpenPath !== void 0) return defaults.canOpenPath(); + return defaults.openPath !== void 0 || canOpenNativePath(); + } + /** Missing-service report shared by the credentials domain. */ + function credentialsAbsent() { + return { + code: "internal", + message: "credentials service is absent: this deployment does not mount a credential provider (e.g. @deepseek-ai/dsh-credentials-local) in its composition", + details: {} + }; + } + /** Map one redacted settings descriptor to its wire view. */ + function namespaceView(descriptor) { + return { + ns: String(descriptor.ns), + schema: descriptor.schema, + value: descriptor.value, + ...descriptor.base === void 0 ? {} : { base: descriptor.base }, + ...descriptor.user === void 0 ? {} : { user: descriptor.user }, + applies: descriptor.applies, + secrets: (descriptor.secrets ?? []).map((secret) => ({ + path: [...secret.path], + set: secret.set + })), + revision: descriptor.revision + }; + } + /** + * Run one settings write (merge or wholesale replace) and acknowledge with + * the namespace's new redacted view. Every seam refusal — unknown or invalid + * namespace, read-only provider, schema validation, storage — becomes one + * `settings-rejected` carrying the seam's own message. + */ + async function settingsWrite(request, ns, mode, section, expectedRevision) { + const settings = ctx.get("settings"); + if (settings === void 0) return err(request, settingsAbsent()); + const rejected = (error) => { + if (error instanceof SettingsConflictError) return err(request, { + code: "settings-conflict", + message: error.message, + details: { + ns, + expected: error.expected, + actual: error.actual + } + }); + return err(request, { + code: "settings-rejected", + message: error instanceof Error ? error.message : String(error), + details: { ns } + }); + }; + let branded; + try { + branded = settingsNamespace(ns); + } catch (error) { + return rejected(error); + } + try { + if (mode === "update") await settings.update(branded, section, expectedRevision); + else if (mode === "replace") await settings.replace(branded, section, expectedRevision); + else await settings.mutate(branded, section, expectedRevision); + } catch (error) { + return rejected(error); + } + const descriptor = settings.describe({ redactSecrets: true }).find((candidate) => candidate.ns === branded); + if (descriptor === void 0) return err(request, { + code: "internal", + message: `settings namespace "${ns}" was disposed after the ${mode}`, + details: {} + }); + return ok(request, namespaceView(descriptor)); + } + return { + sessions: { + async list(request) { + return ok(request, { items: await listVisibleSessionSummaries() }); + }, + async search(request, signal) { + const cancelled = () => err(request, { + code: "cancelled", + message: "session search was aborted", + details: {} + }); + if (isAborted(signal)) return cancelled(); + const sessionQuery = ctx.get("sessionQuery"); + if (sessionQuery === void 0) return err(request, { + code: "internal", + message: "session search is unavailable: this deployment does not mount @deepseek-ai/dsh-session-query", + details: {} + }); + try { + const visible = await listVisibleSessionSummaries(signal); + if (isAborted(signal)) return cancelled(); + if (visible.length === 0) return ok(request, { + items: [], + hasMore: false + }); + const visibleIds = new Set(visible.map((item) => item.sessionId)); + const authorized = []; + const acceptedIds = /* @__PURE__ */ new Set(); + const seenCursors = /* @__PURE__ */ new Set(); + let cursor; + let providerCallCount = 0; + let providerPageLimit = 20; + while (authorized.length <= 20) { + if (isAborted(signal)) return cancelled(); + if (providerCallCount >= SESSION_SEARCH_PROVIDER_CALL_LIMIT) throw new Error(`session search provider exceeded the ${SESSION_SEARCH_PROVIDER_CALL_LIMIT}-call work budget`); + providerCallCount++; + const requestedCursor = cursor; + const requestedPageLimit = providerPageLimit; + let page; + try { + page = await sessionQuery.searchSessions({ + query: request.payload.query, + eventFilters: [{ + kind: "type", + values: ["user/message", "assistant/message"] + }, { + kind: "surface", + values: ["current"] + }], + limit: requestedPageLimit, + ...requestedCursor === void 0 ? {} : { cursor: requestedCursor } + }, { signal }); + } catch (error) { + if (isAborted(signal)) return cancelled(); + if (requestedCursor === void 0 && error instanceof SessionQueryError && error.code === "SESSION_QUERY_INVALID_LIMIT" && requestedPageLimit > 1) { + providerPageLimit = Math.max(1, Math.floor(requestedPageLimit / 2)); + continue; + } + if (requestedCursor !== void 0 && error instanceof SessionQueryError && error.code === "SESSION_QUERY_STALE_CURSOR") { + authorized.length = 0; + acceptedIds.clear(); + seenCursors.clear(); + cursor = void 0; + continue; + } + throw error; + } + if (isAborted(signal)) return cancelled(); + const providerItemCount = page.items.length; + if (providerItemCount > requestedPageLimit) throw new Error(`session search provider returned ${providerItemCount} items; maximum is ${requestedPageLimit}`); + for (const hit of page.items) { + if (authorized.length > 20) continue; + if (!visibleIds.has(hit.header.id) || hit.bestMatch.sessionId !== hit.header.id || hit.bestMatch.surface !== "current" || !MESSAGE_TYPES.has(hit.bestMatch.type) || acceptedIds.has(hit.header.id)) continue; + const snippet = truncateUnicodeCodePoints(hit.bestMatch.snippet, 240); + acceptedIds.add(hit.header.id); + authorized.push({ + sessionId: hit.header.id, + snippet + }); + } + const nextCursor = page.nextCursor; + if (nextCursor !== void 0) { + if (seenCursors.has(nextCursor)) throw new Error("session search provider repeated a continuation cursor"); + seenCursors.add(nextCursor); + } + if (authorized.length > 20 || nextCursor === void 0) break; + cursor = nextCursor; + } + return ok(request, { + items: authorized.slice(0, 20), + hasMore: authorized.length > 20 + }); + } catch (error) { + if (isAborted(signal) || error instanceof SessionQueryError && error.code === "SESSION_QUERY_ABORTED") return cancelled(); + return err(request, { + code: "internal", + message: `session search failed: ${String(error)}`, + details: {} + }); + } + }, + async create(request) { + const sessionId = request.payload.sessionId ?? `session-${randomUUID()}`; + let workspace; + if (request.payload.workspaceId !== void 0) { + workspace = ctx.workspaceRegistry.get(WorkspaceId(request.payload.workspaceId)); + if (workspace === void 0) return err(request, { + code: "workspace-not-found", + message: `workspace "${request.payload.workspaceId}" not found`, + details: { workspaceId: request.payload.workspaceId } + }); + } + const cwd = workspace?.path ?? request.payload.cwd ?? defaults.cwd; + const requestedPreset = request.payload.agentPreset; + try { + await ensureSession(sessionId, cwd, request.payload.sessionId !== void 0, requestedPreset); + } catch (error) { + if (error instanceof AgentPresetConflict) return err(request, { + code: "agent-preset-conflict", + message: error.message, + details: { + sessionId: error.sessionId, + requestedPreset: error.requestedPreset, + ...error.existingPreset === void 0 ? {} : { existingPreset: error.existingPreset } + } + }); + const refused = presetFailure(request, error); + if (refused !== void 0) return refused; + if (error instanceof SessionCwdConflict) return err(request, { + code: "session-conflict", + message: error.message, + details: { + sessionId: error.sessionId, + requestedCwd: error.requestedCwd, + ...error.existingCwd === void 0 ? {} : { existingCwd: error.existingCwd } + } + }); + if (error instanceof ApiRemoteSubagentSessionOwnership) return err(request, subagentOwnershipError(error.sessionId)); + return err(request, { + code: "internal", + message: `failed to create session "${sessionId}": ${String(error)}`, + details: {} + }); + } + if (workspace !== void 0) try { + await workspace.attachSession(sessionId); + } catch (error) { + return err(request, { + code: "workspace-attach-failed", + message: `session "${sessionId}" was created but could not attach to workspace "${workspace.id}": ${String(error)}`, + details: { + sessionId, + workspaceId: workspace.id + } + }); + } + const created = ctx.agents.get(sessionId); + const createdPreset = created === void 0 ? void 0 : resolveSessionPreset(created.session); + return ok(request, { + sessionId, + ...createdPreset === void 0 ? {} : { agentPreset: createdPreset } + }); + }, + async history(request) { + const { sessionId, beforeSeq, maxMessages } = request.payload; + try { + const source = await historySourceFor(sessionId); + const scope = await presenterScopeFor(sessionId, sourceSession(source)); + const cut = historyCutOf(source, beforeSeq === void 0); + const page = historyPage(ctx, cut.events, beforeSeq, maxMessages, scope); + return ok(request, { + events: page.events, + hasMore: page.hasMore, + ...cut.projections === void 0 ? {} : { projections: cut.projections } + }); + } catch (error) { + if (error instanceof ApiRemoteSessionNotFound) return err(request, { + code: "session-not-found", + message: error.message, + details: { sessionId } + }); + return err(request, { + code: "internal", + message: `history unavailable for session "${sessionId}": ${String(error)}`, + details: {} + }); + } + }, + async models(request) { + const { sessionId } = request.payload; + const found = await agentFor(sessionId); + if ("error" in found) return err(request, found.error); + const current = selectionFor(found.agent).current; + const { groups, failures } = await buildModelCatalog(ctx); + const routable = routeServed(current.provider); + return ok(request, { + current: { ...current }, + routable, + groups, + failures + }); + }, + async selectModel(request) { + const { sessionId, provider, model, reasoningEffort } = request.payload; + const found = await agentFor(sessionId); + if ("error" in found) return err(request, found.error); + return serializeImageAdmission(found.agent, async () => { + try { + const resolved = await ctx.llm.resolveCallConfig({ + provider, + model, + ...reasoningEffort === void 0 ? {} : { reasoningEffort: ReasoningEffortId(reasoningEffort) } + }); + if ([...found.agent.inbox.nextTurn, ...found.agent.inbox.nextStep].some((message) => contentHasImage(message.content)) || messagesHaveImage(found.agent.session.deriveMessages())) { + const info = await ctx.llm.resolveModelInfo(resolved.provider, resolved.model); + if (info.inputModalities !== void 0 && !info.inputModalities.includes("image")) return err(request, { + code: "model-unavailable", + message: `Model "${resolved.model}" does not accept image input, but this session already contains images; select an image-capable model.`, + details: { + provider, + model + } + }); + } + const selected = { + provider: resolved.provider, + model: resolved.model, + ...resolved.reasoningEffort === void 0 ? {} : { reasoningEffort: resolved.reasoningEffort } + }; + selectionFor(found.agent).current = selected; + try { + await defaults.saveDefaultModelSelection?.(selected); + } catch (error) { + ctx.logger.warn(`api-proxy: the model switch applies to this session but was not saved as the default: ${String(error)}`); + } + return ok(request, { selected: { ...selected } }); + } catch (error) { + return err(request, { + code: "model-unavailable", + message: error instanceof Error ? error.message : String(error), + details: { + provider, + model + } + }); + } + }); + }, + async rename(request) { + const { sessionId, title } = request.payload; + const found = await agentFor(sessionId); + if ("error" in found) return err(request, found.error); + const titles = ctx.get("sessionTitle"); + if (titles === void 0) return err(request, { + code: "internal", + message: "renaming is unavailable: this deployment mounts no session-title service", + details: {} + }); + try { + const accepted = titles.rename(found.agent.session, title); + return ok(request, { + title: accepted.title, + seq: accepted.eventSeq + }); + } catch (error) { + if (error instanceof SessionTitleInvalidError) return err(request, { + code: "title-invalid", + message: error.message, + details: { sessionId } + }); + return err(request, { + code: "internal", + message: `failed to rename session "${sessionId}": ${String(error)}`, + details: {} + }); + } + }, + async fork(request) { + const { sessionId, atSeq } = request.payload; + let source; + try { + source = await readSessionState(sessionId); + } catch (error) { + if (error instanceof ApiRemoteSessionNotFound) return err(request, { + code: "session-not-found", + message: error.message, + details: { sessionId } + }); + return err(request, { + code: "internal", + message: `fork source unavailable for session "${sessionId}": ${String(error)}`, + details: {} + }); + } + const events = source.events; + const lastSeq = events.at(-1)?.seq ?? -1; + const boundary = (atSeq === void 0 ? void 0 : events.find((e) => e.type === "turn/end" && e.seq >= atSeq)) ?? (atSeq === void 0 || atSeq > lastSeq ? events.findLast((e) => e.type === "turn/end") : void 0); + if (boundary === void 0) return err(request, { + code: "fork-unavailable", + message: atSeq !== void 0 && atSeq <= lastSeq ? `session "${sessionId}" has not completed the turn containing event ${String(atSeq)}` : `session "${sessionId}" has no completed turn to fork from`, + details: { sessionId } + }); + let cut = boundary.seq + 1; + while (cut < events.length && events[cut]?.type !== "turn/start") cut++; + let workspace; + try { + workspace = await forkWorkspace(source); + } catch (error) { + return err(request, { + code: "internal", + message: `failed to resolve fork workspace for session "${sessionId}": ${String(error)}`, + details: {} + }); + } + const childId = `session-${randomUUID()}`; + const forkComposition = await composeAgent(resolveSessionPreset(source)); + try { + await ctx.agents.create({ + sessionId: childId, + seed: events.slice(0, cut), + meta: { + ...source.header.cwd === void 0 ? {} : { cwd: source.header.cwd }, + parentSession: source.id, + seedLength: cut, + ...forkComposition.agentPreset === void 0 ? {} : { agentPreset: forkComposition.agentPreset } + }, + agentOptions: agentOptions(), + setup: forkComposition.setup + }); + } catch (error) { + return err(request, { + code: "internal", + message: `failed to fork session "${sessionId}": ${String(error)}`, + details: {} + }); + } + if (workspace !== void 0) try { + await workspace.attachSession(childId); + } catch (error) { + return err(request, { + code: "workspace-attach-failed", + message: `session "${childId}" was forked but could not attach to workspace "${workspace.id}": ${String(error)}`, + details: { + sessionId: childId, + workspaceId: workspace.id + } + }); + } + return ok(request, { sessionId: childId }); + }, + async prompt(request) { + const { sessionId, mode, content, clientTimeZone } = request.payload; + const canonicalTimeZone = clientTimeZone === void 0 ? void 0 : canonicalClientTimeZone(clientTimeZone); + if (clientTimeZone !== void 0 && canonicalTimeZone === void 0) return err(request, { + code: "invalid-time-zone", + message: "clientTimeZone must be UTC or a valid IANA Area/Location name", + details: { value: clientTimeZone } + }); + const resolved = await turnAgentFor(request, sessionId); + if ("refused" in resolved) return resolved.refused; + const agent = resolved.agent; + const source = { + kind: "user", + rpcId: request.rpcId, + ...canonicalTimeZone === void 0 ? {} : { clientTimeZone: canonicalTimeZone } + }; + const hasImage = content.some((part) => part.type === "image"); + const admit = async () => { + try { + if (hasImage) { + const current = selectionFor(agent).current; + const modelInfo = await ctx.llm.resolveModelInfo(current.provider, current.model); + if (modelInfo.inputModalities !== void 0 && !modelInfo.inputModalities.includes("image")) return err(request, { + code: "attachment-error", + message: `Model "${current.model}" does not support image input.`, + details: { reason: "MODEL_DOES_NOT_SUPPORT_IMAGES" } + }); + } + const message = createUserMessage({ + content: await durablePromptContent(ctx, content), + source + }); + if (mode === "steer") agent.steer(message); + else agent.followup(message); + } catch (error) { + if (error instanceof AttachmentError) return err(request, { + code: "attachment-error", + message: error.message, + details: { reason: error.code } + }); + return err(request, { + code: "agent-busy", + message: "prompt rejected", + details: { reason: String(error) } + }); + } + return ok(request, { accepted: true }); + }; + return hasImage ? serializeImageAdmission(agent, admit) : admit(); + }, + async attachment(request) { + const { sessionId, attachmentId } = request.payload; + let state; + try { + state = await readSessionState(sessionId); + } catch (error) { + if (error instanceof ApiRemoteSessionNotFound) return err(request, { + code: "session-not-found", + message: error.message, + details: { sessionId } + }); + return err(request, { + code: "internal", + message: `attachment authorization unavailable for session "${sessionId}": ${String(error)}`, + details: {} + }); + } + const ref = referencedImage(state.events, String(attachmentId)); + if (ref === void 0) return err(request, { + code: "attachment-error", + message: "Image is not referenced by this session.", + details: { reason: "ATTACHMENT_NOT_REFERENCED" } + }); + try { + const stored = await ctx.attachments.readImage(ref); + return ok(request, { + attachment: stored.ref, + data: Buffer.from(stored.data).toString("base64") + }); + } catch (error) { + if (error instanceof AttachmentError) return err(request, { + code: "attachment-error", + message: error.message, + details: { reason: error.code } + }); + return err(request, { + code: "internal", + message: "Unable to read image attachment.", + details: {} + }); + } + }, + updateQueue(request) { + const { sessionId, itemId, action } = request.payload; + if (action.kind === "edit" && action.content.some((block) => block.type !== "text")) return Promise.resolve(err(request, { + code: "attachment-error", + message: "queue edits accept text content only", + details: { reason: "QUEUE_EDIT_NON_TEXT" } + })); + const agent = ctx.agents.get(sessionId); + if (agent !== void 0 && hasSubagentOwner(agent.session, agent)) return Promise.resolve(err(request, subagentOwnershipError(sessionId))); + if (agent === void 0) return Promise.resolve(err(request, { + code: "queue-item-not-found", + message: "queued item is no longer pending", + details: { itemId } + })); + const target = agent.inbox.nextTurn.some((message) => message.id === itemId) ? "next-turn" : agent.inbox.nextStep.some((message) => message.id === itemId) ? "next-step" : void 0; + const message = target === void 0 ? void 0 : (target === "next-turn" ? agent.inbox.nextTurn : agent.inbox.nextStep).find((candidate) => candidate.id === itemId); + if (target === void 0 || message === void 0) return Promise.resolve(err(request, { + code: "queue-item-not-found", + message: "queued item is no longer pending", + details: { itemId } + })); + if (action.kind === "steer" && (target !== "next-turn" || agent.status !== "running")) return Promise.resolve(err(request, { + code: "steer-unavailable", + message: "current turn no longer accepts steering", + details: { itemId } + })); + if (action.kind === "edit") agent.inbox.replace(itemId, freezeMessage({ + ...message, + content: action.content + })); + else { + agent.inbox.remove(itemId); + if (action.kind === "steer") agent.steer(message); + } + return Promise.resolve(ok(request, { accepted: true })); + }, + cancel(request) { + const { sessionId } = request.payload; + const agent = ctx.agents.get(sessionId); + if (agent === void 0) return Promise.resolve(err(request, { + code: "session-not-found", + message: `session "${sessionId}" not found (not attached)`, + details: { sessionId } + })); + if (hasSubagentOwner(agent.session, agent)) return Promise.resolve(err(request, subagentOwnershipError(sessionId))); + agent.cancel({ kind: "user" }, { keepInbox: true }); + return Promise.resolve(ok(request, { accepted: true })); + } + }, + subagents: { + async list(request, signal) { + try { + return ok(request, { + entries: (await ctx.subagents.listChildren(request.payload.parentSessionId, signal)).map((entry) => entry.kind === "child" ? { + ...entry, + activity: ctx.agents.get(entry.id)?.status === "running" ? "running" : "inactive" + } : entry), + parentAvailable: ctx.agents.get(request.payload.parentSessionId) !== void 0 + }); + } catch (error) { + if (signal?.aborted || error instanceof SubagentError && error.code === "CANCELLED") return err(request, { + code: "cancelled", + message: "subagent catalog read was cancelled", + details: {} + }); + if (error instanceof SubagentError && error.code === "SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE") return err(request, projectionsUnavailableError()); + return err(request, { + code: "internal", + message: "subagent catalog read failed", + details: {} + }); + } + }, + async history(request, signal) { + const { parentSessionId, childSessionId, mode, beforeSeq, maxMessages } = request.payload; + const verified = await catalogChild(ctx, { + parentSessionId, + childSessionId, + mode + }, signal); + if (verified.error !== void 0) return err(request, verified.error); + let header; + let events; + let projections; + const attached = ctx.sessions.get(childSessionId); + if (attached !== void 0) { + header = attached.header; + events = [...attached.events]; + projections = beforeSeq === void 0 ? subagentHistoryProjections(ctx, childSessionId, () => projectionsFor(ctx, attached)) : void 0; + } else try { + const inspected = await inspectServable(childSessionId); + header = inspected.meta; + events = inspected.events; + projections = beforeSeq === void 0 ? subagentHistoryProjections(ctx, childSessionId, () => detachedProjectionsFor(ctx, inspected.events)) : void 0; + } catch (error) { + if (signal?.aborted) return err(request, { + code: "cancelled", + message: "subagent history read was cancelled", + details: {} + }); + if (error instanceof ApiRemoteSessionNotFound) return err(request, { + code: "subagent-not-found", + message: "subagent disappeared during history read", + details: { + parentSessionId, + childSessionId + } + }); + return err(request, { + code: "internal", + message: "subagent history read failed", + details: {} + }); + } + if (signal?.aborted) return err(request, { + code: "cancelled", + message: "subagent history read was cancelled", + details: {} + }); + if (header.parentSession !== parentSessionId) return err(request, { + code: "subagent-unauthorized", + message: "subagent parent changed during history read", + details: { childSessionId } + }); + return ok(request, { + ...historyPage(ctx, events, beforeSeq, maxMessages), + ...projections === void 0 ? {} : { projections } + }); + }, + async prompt(request, signal) { + const { parentSessionId, childSessionId, content, clientTimeZone } = request.payload; + const canonicalTimeZone = clientTimeZone === void 0 ? void 0 : canonicalClientTimeZone(clientTimeZone); + if (clientTimeZone !== void 0 && canonicalTimeZone === void 0) return err(request, { + code: "invalid-time-zone", + message: "clientTimeZone must be UTC or a valid IANA Area/Location name", + details: { value: clientTimeZone } + }); + const parent = ctx.agents.get(parentSessionId); + if (parent === void 0) return err(request, { + code: "subagent-parent-unavailable", + message: `parent session "${parentSessionId}" is not live`, + details: { parentSessionId } + }); + const verified = await catalogChild(ctx, { + parentSessionId, + childSessionId, + mode: "continuable" + }, signal); + if (verified.error !== void 0) return err(request, verified.error); + try { + return ok(request, { messageId: await ctx.subagents.followup(parent, childSessionId, content, { + source: { + kind: "user", + rpcId: request.rpcId, + ...canonicalTimeZone === void 0 ? {} : { clientTimeZone: canonicalTimeZone } + }, + signal + }) }); + } catch (error) { + return subagentPromptError(request, error, signal); + } + }, + interrupt(request) { + const { parentSessionId, childSessionId } = request.payload; + try { + ctx.subagents.interrupt(childSessionId, { + kind: "user", + parentSessionId + }); + } catch (error) { + if (error instanceof SubagentError && error.code === "UNAUTHORIZED") return Promise.resolve(err(request, { + code: "subagent-unauthorized", + message: "subagent does not belong to this parent", + details: { childSessionId } + })); + return Promise.resolve(err(request, { + code: "internal", + message: "subagent interrupt failed", + details: {} + })); + } + return Promise.resolve(ok(request, { accepted: true })); + } + }, + workspace: { + list(request) { + return Promise.resolve(ok(request, { + items: ctx.workspaceRegistry.list().map(workspaceView), + archivedSessionIds: [...ctx.workspaceRegistry.archivedSessionIds] + })); + }, + async create(request) { + const { path } = request.payload; + try { + const { workspace, created } = await ensureWorkspace(path); + return ok(request, { + workspace: workspaceView(workspace), + created + }); + } catch (error) { + return err(request, { + code: "workspace-invalid-path", + message: `cannot create a workspace at "${path}": ${error instanceof Error ? error.message : String(error)}`, + details: { path } + }); + } + }, + async rename(request) { + const { payload } = request; + const workspace = ctx.workspaceRegistry.get(WorkspaceId(payload.workspaceId)); + if (workspace === void 0) return workspaceNotFound(request, payload.workspaceId); + const title = payload.title.trim(); + const operation = workspaceCreationChain.then(async () => { + if (title === workspace.title) return; + if (ctx.workspaceRegistry.list().some((other) => other.id !== workspace.id && other.title === title)) throw new WorkspaceNameConflictError(title); + await workspace.setTitle(title); + }); + workspaceCreationChain = operation.then(() => void 0, () => void 0); + try { + await operation; + } catch (error) { + if (error instanceof WorkspaceNameConflictError) return err(request, { + code: "workspace-name-conflict", + message: error.message, + details: { name: error.workspaceName } + }); + throw error; + } + return ok(request, { workspace: workspaceView(workspace) }); + }, + async delete(request) { + const { workspaceId } = request.payload; + const operation = workspaceCreationChain.then(() => ctx.workspaceRegistry.delete(WorkspaceId(workspaceId))); + workspaceCreationChain = operation.then(() => void 0, () => void 0); + if (!await operation) return workspaceNotFound(request, workspaceId); + return ok(request, { deleted: true }); + }, + async insertBefore(request) { + const { workspaceId, beforeWorkspaceId } = request.payload; + try { + return ok(request, { workspaceIds: [...await ctx.workspaceRegistry.insertBefore(WorkspaceId(workspaceId), beforeWorkspaceId === void 0 ? void 0 : WorkspaceId(beforeWorkspaceId))] }); + } catch (error) { + if (!(error instanceof WorkspaceOrderInvalidError)) throw error; + return workspaceNotFound(request, error.workspaceId); + } + }, + async insertSessionBefore(request) { + const { payload } = request; + const workspace = ctx.workspaceRegistry.get(WorkspaceId(payload.workspaceId)); + if (workspace === void 0) return workspaceNotFound(request, payload.workspaceId); + try { + await workspace.insertSessionBefore(payload.sessionId, payload.beforeSessionId); + } catch (error) { + if (!(error instanceof WorkspaceMoveInvalidError)) throw error; + return err(request, { + code: "workspace-move-invalid", + message: error.message, + details: { + workspaceId: payload.workspaceId, + sessionId: payload.sessionId, + ...payload.beforeSessionId === void 0 ? {} : { beforeSessionId: payload.beforeSessionId } + } + }); + } + return ok(request, { workspace: workspaceView(workspace) }); + }, + async archiveSession(request) { + const { sessionId } = request.payload; + try { + await ctx.workspaceRegistry.archiveSession(sessionId); + } catch (error) { + if (!(error instanceof WorkspaceUnknownSessionError)) throw error; + return err(request, { + code: "session-not-found", + message: error.message, + details: { sessionId } + }); + } + return ok(request, { archivedSessionIds: [...ctx.workspaceRegistry.archivedSessionIds] }); + } + }, + host: { + describe(request) { + const selection = defaults.defaultModelSelection(); + return Promise.resolve(ok(request, { + version: "0.0.1", + cwd: defaults.cwd, + provider: selection.provider, + model: selection.model, + attachedSessions: ctx.agents.list().length, + canOpenPath: canOpenPaths() + })); + }, + async pickDirectory(request, signal) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== "native") return err(request, { + code: "directory-picker-unavailable", + message: `host.pickDirectory needs the native capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind } + }); + try { + return ok(request, { path: await capability.pick(signal) }); + } catch (error) { + if (signal.aborted) return err(request, { + code: "cancelled", + message: "directory picker was aborted", + details: {} + }); + return err(request, { + code: "internal", + message: `directory picker failed: ${error instanceof Error ? error.message : String(error)}`, + details: {} + }); + } + }, + async listDirectory(request, signal) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== "browse") return err(request, { + code: "directory-picker-unavailable", + message: `host.listDirectory needs the browse capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind } + }); + try { + return ok(request, await capability.list(request.payload.path, signal)); + } catch (error) { + if (signal.aborted) return err(request, { + code: "cancelled", + message: "directory listing was aborted", + details: {} + }); + return err(request, directoryError(error)); + } + }, + async createDirectory(request) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== "browse") return err(request, { + code: "directory-picker-unavailable", + message: `host.createDirectory needs the browse capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind } + }); + try { + return ok(request, { path: await capability.createDirectory(request.payload.path, request.payload.name) }); + } catch (error) { + return err(request, directoryError(error)); + } + }, + async openPath(request, signal) { + return openPath(request, request.payload.path, signal); + } + }, + goals: { + async create(request) { + const { objective, maxGoalRounds } = request.payload; + return mutateGoal(request, (goals, agent) => goals.create(agent, { + objective, + ...maxGoalRounds !== void 0 ? { maxGoalRounds } : {} + })); + }, + async edit(request) { + const { ref, objective, maxGoalRounds } = request.payload; + return mutateGoal(request, (goals, agent) => goals.edit(agent, ref, { + ...objective !== void 0 ? { objective } : {}, + ...maxGoalRounds !== void 0 ? { maxGoalRounds } : {} + })); + }, + async pause(request) { + return mutateGoal(request, (goals, agent) => goals.pause(agent, request.payload.ref)); + }, + async resume(request) { + return mutateGoal(request, (goals, agent) => goals.resume(agent, request.payload.ref)); + }, + async complete(request) { + return mutateGoal(request, (goals, agent) => goals.complete(agent, request.payload.ref)); + }, + async clear(request) { + const found = await agentFor(request.payload.sessionId); + if ("error" in found) return err(request, found.error); + const goals = goalServiceFor(found.agent); + if ("error" in goals) return err(request, goals.error); + try { + goals.clear(found.agent, request.payload.ref); + return ok(request, { cleared: true }); + } catch (error) { + return goalError(request, error); + } + } + }, + agentPresets: { + async list(request) { + const presets = ctx.get("agentPresets"); + if (presets === void 0) return ok(request, { + presets: [], + authorable: false, + hasDocument: false + }); + const defaultId = presets.defaultId; + return ok(request, { + presets: (await presets.list()).map((preset) => ({ + id: preset.id, + trust: preset.trust, + isDefault: preset.id === defaultId, + ...preset.name === void 0 ? {} : { name: preset.name }, + ...preset.description === void 0 ? {} : { description: preset.description }, + ...preset.broken === void 0 ? {} : { broken: preset.broken } + })), + authorable: presets.authorable, + hasDocument: canOpenPaths() + }); + }, + async select(request) { + const { sessionId, agentPreset } = request.payload; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return err(request, { + code: "agent-preset-not-found", + message: "this deployment composes no agent presets", + details: { + agentPreset, + available: [] + } + }); + const found = await agentFor(sessionId); + if ("error" in found) return err(request, found.error); + const { agent } = found; + const swap = async () => { + if (!sessionBlank(agent.session)) return err(request, { + code: "agent-preset-locked", + message: `session "${sessionId}" has already started; its agent preset is fixed`, + details: { + sessionId, + agentPreset + } + }); + try { + const preset = await presets.recompose(agent.ctx, agentPreset); + agent.session.append("agent-preset/selected", { agentPreset: preset.id }); + return ok(request, { agentPreset: preset.id }); + } catch (error) { + const refused = presetFailure(request, error); + if (refused !== void 0) return refused; + return err(request, { + code: "internal", + message: `failed to select agent preset "${agentPreset}": ${String(error)}`, + details: {} + }); + } + }; + const turn = (presetSwitches.get(sessionId) ?? Promise.resolve()).then(swap); + presetSwitches.set(sessionId, turn.catch(() => void 0)); + try { + return await turn; + } finally { + if (presetSwitches.get(sessionId) === turn) presetSwitches.delete(sessionId); + } + }, + async read(request) { + const { agentPreset } = request.payload; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return err(request, noRoster(agentPreset)); + try { + const preset = await presets.resolve(agentPreset); + return ok(request, { + agentPreset: preset.id, + trust: preset.trust, + content: await presets.read(preset.id), + ...preset.name === void 0 ? {} : { name: preset.name }, + ...preset.description === void 0 ? {} : { description: preset.description } + }); + } catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async copy(request) { + const { from, agentPreset, name } = request.payload; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return err(request, noRoster(agentPreset)); + try { + await presets.copy(from, agentPreset, name); + return ok(request, { agentPreset }); + } catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async openDocument(request, signal) { + const { agentPreset } = request.payload; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return err(request, noRoster(agentPreset)); + try { + const preset = await presets.resolve(agentPreset); + if (preset.trust !== "user") throw new PresetNotWritableError(preset.id, "it ships with the deployment"); + const directory = dirname(preset.path); + if (!canOpenPaths()) return ok(request, { + opened: false, + path: directory + }); + return await openPath(request, directory, signal); + } catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async remove(request) { + const { agentPreset } = request.payload; + const presets = ctx.get("agentPresets"); + if (presets === void 0) return err(request, noRoster(agentPreset)); + try { + await presets.remove(agentPreset); + return ok(request, {}); + } catch (error) { + return err(request, presetError(agentPreset, error)); + } + } + }, + skills: { async list(request) { + const { sessionId } = request.payload; + const session = ctx.sessions.get(sessionId); + if (session === void 0) return err(request, { + code: "session-not-found", + message: `session "${sessionId}" not found (not attached)`, + details: { sessionId } + }); + if (session.header.cwd === void 0) return err(request, { + code: "internal", + message: `session "${sessionId}" has no project cwd`, + details: {} + }); + const cwd = session.header.cwd; + const live = ctx.agents.get(sessionId); + const presets = ctx.get("agentPresets"); + const skillRegistry = (live === void 0 ? void 0 : presets?.serviceFor(live, "skills")) ?? ctx.get("skills"); + if (skillRegistry === void 0) return err(request, { + code: "internal", + message: "skill registry is absent: neither this session's agent preset nor the host composition mounts @deepseek-ai/dsh-skill", + details: {} + }); + const scope = await presenterScopeFor(sessionId, session); + try { + return ok(request, { skills: (await skillRegistry.list({ + cwd, + scope + })).filter(isUserInvocable).map((skill) => ({ + name: skill.name, + description: skill.description, + ...skill.whenToUse === void 0 ? {} : { whenToUse: skill.whenToUse }, + modelInvocable: skill.invocation.modelInvocable + })) }); + } catch (error) { + return err(request, { + code: "internal", + message: `skill listing failed: ${String(error)}`, + details: {} + }); + } + } }, + settings: { + describe(request) { + const settings = ctx.get("settings"); + if (settings === void 0) return Promise.resolve(err(request, settingsAbsent())); + return Promise.resolve(ok(request, { + writable: settings.writable, + hasDocument: settings.documentPath !== void 0, + namespaces: settings.describe({ redactSecrets: true }).map(namespaceView) + })); + }, + async openDocument(request, signal) { + const settings = ctx.get("settings"); + if (settings === void 0) return err(request, settingsAbsent()); + if (isAborted(signal)) return err(request, { + code: "cancelled", + message: "settings document open was aborted", + details: {} + }); + let path; + try { + path = await settings.prepareDocument(); + } catch (error) { + if (isAborted(signal)) return err(request, { + code: "cancelled", + message: "settings document preparation was aborted", + details: {} + }); + return err(request, { + code: "internal", + message: `settings document preparation failed: ${error instanceof Error ? error.message : String(error)}`, + details: {} + }); + } + if (path === void 0) return err(request, { + code: "internal", + message: "settings provider has no local document to open", + details: {} + }); + if (isAborted(signal)) return err(request, { + code: "cancelled", + message: "settings document open was aborted", + details: {} + }); + return openTextFile(request, path, signal); + }, + update: (request) => settingsWrite(request, request.payload.ns, "update", request.payload.patch, request.payload.expectedRevision), + replace: (request) => settingsWrite(request, request.payload.ns, "replace", request.payload.section, request.payload.expectedRevision), + mutate: (request) => settingsWrite(request, request.payload.ns, "mutate", request.payload.ops, request.payload.expectedRevision) + }, + credentials: { + async describe(request) { + const credentials = ctx.get("credentials"); + if (credentials === void 0) return err(request, credentialsAbsent()); + const entries = await Promise.all(request.payload.refs.map(async (ref) => { + const info = await credentials.describe(credentialRef(ref)); + return [ref, { + configured: info.configured, + ...info.source === void 0 ? {} : { source: info.source }, + writable: info.writable + }]; + })); + return ok(request, { credentials: Object.fromEntries(entries) }); + }, + async set(request) { + const credentials = ctx.get("credentials"); + if (credentials === void 0) return err(request, credentialsAbsent()); + const { ref, value } = request.payload; + try { + await credentials.set(credentialRef(ref), value); + } catch (error) { + return err(request, { + code: "credential-rejected", + message: error instanceof Error ? error.message : String(error), + details: { ref } + }); + } + return ok(request, {}); + }, + async unset(request) { + const credentials = ctx.get("credentials"); + if (credentials === void 0) return err(request, credentialsAbsent()); + const { ref } = request.payload; + try { + await credentials.unset(credentialRef(ref)); + } catch (error) { + return err(request, { + code: "credential-rejected", + message: error instanceof Error ? error.message : String(error), + details: { ref } + }); + } + return ok(request, {}); + } + }, + llm: { + providers(request) { + const registered = ctx.llm.listProviders(); + const active = new Set(registered.map((provider) => provider.id)); + const directory = ctx.llm.listConfigurableProviders(); + const declared = new Set(directory.map((entry) => entry.provider)); + const views = directory.map((entry) => ({ + provider: entry.provider, + displayName: entry.displayName, + settingsNs: entry.settingsNs, + settingsPath: [...entry.settingsPath], + active: active.has(entry.provider), + ...entry.declared === void 0 ? {} : { declared: entry.declared } + })); + for (const provider of registered) { + if (declared.has(provider.id)) continue; + views.push({ + provider: provider.id, + displayName: provider.name, + settingsNs: "", + settingsPath: [], + active: true + }); + } + return Promise.resolve(ok(request, { providers: views })); + }, + async models(request) { + return ok(request, await buildModelCatalog(ctx)); + }, + async discoverModels(request, signal) { + const { settingsNs, provider, baseURL, api, apiKey } = request.payload; + try { + return ok(request, { models: await ctx.llm.discoverModels(settingsNs, { + ...provider === void 0 ? {} : { provider }, + ...baseURL === void 0 ? {} : { baseURL }, + ...api === void 0 ? {} : { api }, + ...apiKey === void 0 ? {} : { apiKey }, + ...signal === void 0 ? {} : { signal } + }) }); + } catch (error) { + return err(request, { + code: "model-discovery-failed", + message: error instanceof Error ? error.message : String(error), + details: { + settingsNs, + ...baseURL === void 0 ? {} : { baseURL } + } + }); + } + } + }, + events: { + mux(_request, signal) { + const queue = new FrameQueue(); + muxQueues.add(queue); + for (const session of ctx.sessions.list()) subscribeSession(queue, session); + for (const pending of pendingQuestions.values()) queue.push({ + rpcId: pending.rpcId, + payload: { + type: "question/requested", + sessionId: pending.sessionId, + questions: pending.questions + } + }); + for (const pending of pendingApprovals.values()) queue.push(requestedFrame(pending)); + for (const session of ctx.sessions.list()) { + const agent = ctx.agents.get(session.id); + if (agent?.session === session && agent.inbox.hasPending) queue.push(frame({ + type: "session/queue", + sessionId: session.id, + items: queueItems(agent) + })); + } + const jobs = ctx.get("jobs"); + if (jobs !== void 0) for (const session of ctx.sessions.list()) { + const views = jobViews(jobs.list(ctx.agents.get(session.id))); + if (views.length > 0) queue.push(frame({ + type: "session/jobs", + sessionId: session.id, + jobs: views + })); + } + const openCalls = /* @__PURE__ */ new Map(); + const disposers = [ + ctx.on("session/event", (session, event) => { + if (event.type === "tool/call") { + const data = event.data; + try { + let table = openCalls.get(session.id); + if (table === void 0) openCalls.set(session.id, table = /* @__PURE__ */ new Map()); + table.set(data.callId, { + name: data.name, + args: JSON.parse(data.arguments) + }); + } catch {} + } else if (event.type === "turn/end") openCalls.delete(session.id); + const view = viewFor(ctx, event, (callId) => openCalls.get(session.id)?.get(callId) ?? backscanArgs(session.events, callId), ctx.agents.get(session.id)); + queue.push(frame({ + type: "session/event", + sessionId: session.id, + event, + ...view === void 0 ? {} : { view } + })); + }), + ctx.on("session/created", (session) => { + subscribeSession(queue, session); + const views = jobs === void 0 ? [] : jobViews(jobs.list(ctx.agents.get(session.id))); + if (views.length > 0) queue.push(frame({ + type: "session/jobs", + sessionId: session.id, + jobs: views + })); + }), + ctx.on("session/disposed", (session) => { + openCalls.delete(session.id); + }), + ...jobs === void 0 ? [] : [jobs.onJobsChanged((owner) => { + if (owner !== void 0) { + queue.push(frame({ + type: "session/jobs", + sessionId: owner.id, + jobs: jobViews(jobs.list(owner)) + })); + return; + } + for (const session of ctx.sessions.list()) queue.push(frame({ + type: "session/jobs", + sessionId: session.id, + jobs: jobViews(jobs.list(ctx.agents.get(session.id))) + })); + })] + ]; + return queue.iterate(signal, () => { + muxQueues.delete(queue); + for (const dispose of disposers) dispose(); + }); + }, + host(_request, signal) { + const queue = new FrameQueue(); + const committedWorkspaces = ctx.workspaceRegistry.list(); + const committedWorkspaceIds = new Set(committedWorkspaces.map((workspace) => String(workspace.id))); + let committedWorkspaceOrder = committedWorkspaces.map((workspace) => workspace.id); + let archivedSessionIds = ctx.workspaceRegistry.archivedSessionIds; + const disposers = [ + ctx.on("session/created", (session) => { + queue.push(frame({ + type: "host/session-added", + sessionId: session.id, + blank: sessionBlank(session), + ...sessionListFields(session.header, session.events) + })); + }), + ctx.on("session/disposed", (session) => { + queue.push(frame({ + type: "host/session-removed", + sessionId: session.id + })); + }), + ctx.on("agent/status", ({ agent, status }) => { + queue.push(frame({ + type: "host/session-status", + sessionId: agent.id, + running: status === "running" + })); + }), + ctx.on("agent/error", ({ agent, error }) => { + queue.push(frame({ + type: "host/agent-error", + sessionId: agent.id, + message: errorChain(error) + })); + }), + ctx.on("domain/changed", (change) => { + if (change.domain !== "workspace") return; + if (change.table === "") { + if (change.operation !== "put") return; + const state = workspaceDomainState.parse(change.value); + const orderChanged = state.workspaceIds.length === committedWorkspaceOrder.length && state.workspaceIds.every((workspaceId) => committedWorkspaceIds.has(String(workspaceId))) && state.workspaceIds.some((workspaceId, index) => workspaceId !== committedWorkspaceOrder[index]); + for (const workspaceId of state.workspaceIds) { + if (committedWorkspaceIds.has(workspaceId)) continue; + const workspace = ctx.workspaceRegistry.get(workspaceId); + if (workspace === void 0) throw new Error(`committed workspace registry references missing workspace "${workspaceId}"`); + committedWorkspaceIds.add(workspaceId); + queue.push(frame({ + type: "host/workspace-changed", + workspace: workspaceView(workspace) + })); + } + committedWorkspaceOrder = [...state.workspaceIds]; + if (orderChanged) queue.push(frame({ + type: "host/workspace-order-changed", + workspaceIds: [...state.workspaceIds] + })); + if (state.archivedSessionIds.length !== archivedSessionIds.length || state.archivedSessionIds.some((id, index) => id !== archivedSessionIds[index])) { + archivedSessionIds = state.archivedSessionIds; + queue.push(frame({ + type: "host/archived-sessions-changed", + archivedSessionIds: [...state.archivedSessionIds] + })); + } + return; + } + if (change.table !== "workspaces") return; + if (change.operation === "deleted") { + if (!committedWorkspaceIds.delete(change.key)) return; + queue.push(frame({ + type: "host/workspace-removed", + workspaceId: change.key + })); + return; + } + if (!committedWorkspaceIds.has(change.key)) return; + queue.push(frame({ + type: "host/workspace-changed", + workspace: changedWorkspaceView(change.key, change.value) + })); + }), + ...API_REMOTE_FORWARDED_EVENTS.map((name) => ctx.on(name, ((...args) => { + queue.push(frame({ + type: "host/remote-event", + event: name, + args: assertJsonArgs(name, args) + })); + }))) + ]; + return queue.iterate(signal, () => { + for (const dispose of disposers) dispose(); + }); + } + }, + downloads: { async sessionLog(request, signal) { + const deps = sessionLogExportDeps(ctx); + if (deps.sessionQuery === void 0 || deps.sessionPersistence === void 0 || deps.attachments === void 0) return new Response("session log export is unavailable: missing session-query, session-persistence, or attachments service", { status: 500 }); + if (!deps.sessionPersistence.supportsRawArtifacts) return new Response("session log export is unavailable: the persistence backend does not expose per-session raw artifacts", { status: 501 }); + const ready = { + sessionQuery: deps.sessionQuery, + sessionPersistence: deps.sessionPersistence, + attachments: deps.attachments, + sessions: deps.sessions + }; + let root; + try { + await flushLiveSessionLog(deps, request.sessionId, signal); + root = await deps.sessionPersistence.readRaw(request.sessionId, signal); + signal.throwIfAborted(); + } catch { + signal.throwIfAborted(); + return new Response("session log export failed to prepare the stored artifact", { status: 500 }); + } + if (root === void 0) return new Response("session not found", { status: 404 }); + return new Response(streamSessionLogZip(ready, root, request.sessionId, request.includeDescendants === true, sessionExportCompressionLevel, signal), { headers: { + "content-type": "application/zip", + "content-disposition": `attachment; filename="${sessionLogZipFilename(request.sessionId)}"` + } }); + } }, + respond(message) { + const approval = pendingApprovals.get(message.rpcId); + if (approval !== void 0) { + if (!message.result.ok) return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + const parsed = approvalResponsePayloadSchema.safeParse(message.result.value); + if (!parsed.success || parsed.data.approvalId !== approval.approvalId || parsed.data.sessionId !== approval.sessionId) return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + approval.resolve(parsed.data.outcome); + return Promise.resolve({ accepted: true }); + } + const pending = pendingQuestions.get(message.rpcId); + if (pending === void 0) return Promise.resolve({ + accepted: false, + reason: "not-pending" + }); + if (!message.result.ok) { + if (message.result.error.code !== "cancelled") return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + claimQuestion(pending, "cancelled"); + pending.reject(new UserQuestionError("the user cancelled ask_user_question", "ASK_CANCELLED")); + return Promise.resolve({ accepted: true }); + } + const parsed = questionResponsePayloadSchema.safeParse(message.result.value); + if (!parsed.success) return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + const payload = { + sessionId: parsed.data.sessionId, + answer: { answers: parsed.data.answer.answers.map((answer) => ({ + id: answer.id, + selected: answer.selected, + ...answer.custom === void 0 ? {} : { custom: answer.custom } + })) } + }; + if (!matchesQuestions(payload, pending)) return Promise.resolve({ + accepted: false, + reason: "bad-response" + }); + claimQuestion(pending, "answered"); + pending.resolve(payload.answer); + return Promise.resolve({ accepted: true }); + } + }; +} +//#endregion +//#region lib/types/api/downloads.schema.js +/** +* downloads domain zod schemas. The download surface has no wire +* envelope: the request arrives as query parameters (all strings), so its +* request schema parses the raw query-parameter object into the method's +* exact request shape. SessionId brand cast point: sessionIdSchema, and only +* there (hosted in sessions.schema like every other cast). +*/ +/** +* session.export query params → the sessionLog request. `includeDescendants` +* accepts exactly `true`/`false`/absent; any other value is rejected (400) so +* a misspelled flag cannot silently under-export. +*/ +const sessionLogQuerySchema = z$1.object({ + sessionId: sessionIdSchema, + includeDescendants: z$1.union([z$1.literal("true"), z$1.literal("false")]).optional() +}).transform((query) => ({ + sessionId: query.sessionId, + ...query.includeDescendants === "true" ? { includeDescendants: true } : {} +})); +//#endregion +//#region lib/types/api/rpc.schema.js +/** +* Message-layer zod schemas: the four wire full forms + error body + +* carrier receipt. The payload slot is unknown in the full-form schemas — business payloads +* get a second parse dispatched by method (two-level parse discipline). +* Brand cast point: rpcIdSchema, and only there. +*/ +/** +* RpcId: one brand cast after schema validation (the only cast point in this +* file). No min-length: the id is an opaque echo token, and rejecting values +* here would only turn a correlatable error report into a client-side parse +* failure (the handler substitutes a sentinel when a request's id is unreadable). +*/ +const rpcIdSchema = z$1.string(); +/** Error body: discriminated by code, per-branch details aligned to RpcErrorDetailsMap; details is required. */ +const rpcErrorSchema = z$1.discriminatedUnion("code", [ + z$1.object({ + code: z$1.literal("bad-request"), + message: z$1.string(), + details: z$1.object({ issues: z$1.array(z$1.custom()) }) + }), + z$1.object({ + code: z$1.literal("cancelled"), + message: z$1.string(), + details: z$1.object({}) + }), + z$1.object({ + code: z$1.literal("session-not-found"), + message: z$1.string(), + details: z$1.object({ sessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("model-unavailable"), + message: z$1.string(), + details: z$1.object({ + provider: z$1.string(), + model: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("session-conflict"), + message: z$1.string(), + details: z$1.object({ + sessionId: z$1.string(), + requestedCwd: z$1.string(), + existingCwd: z$1.string().optional() + }) + }), + z$1.object({ + code: z$1.literal("invalid-time-zone"), + message: z$1.string(), + details: z$1.object({ value: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("workspace-attach-failed"), + message: z$1.string(), + details: z$1.object({ + sessionId: z$1.string(), + workspaceId: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("workspace-not-found"), + message: z$1.string(), + details: z$1.object({ workspaceId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("workspace-invalid-path"), + message: z$1.string(), + details: z$1.object({ path: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("workspace-name-conflict"), + message: z$1.string(), + details: z$1.object({ name: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("workspace-move-invalid"), + message: z$1.string(), + details: z$1.object({ + workspaceId: z$1.string(), + sessionId: z$1.string(), + beforeSessionId: z$1.string().optional() + }) + }), + z$1.object({ + code: z$1.literal("directory-unreadable"), + message: z$1.string(), + details: z$1.object({ path: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("directory-exists"), + message: z$1.string(), + details: z$1.object({ path: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("directory-create-failed"), + message: z$1.string(), + details: z$1.object({ path: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("directory-picker-unavailable"), + message: z$1.string(), + details: z$1.object({ capability: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("agent-preset-read-only"), + message: z$1.string(), + details: z$1.object({ + agentPreset: z$1.string(), + reason: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("agent-preset-locked"), + message: z$1.string(), + details: z$1.object({ + sessionId: z$1.string(), + agentPreset: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("agent-preset-conflict"), + message: z$1.string(), + details: z$1.object({ + sessionId: z$1.string(), + requestedPreset: z$1.string(), + existingPreset: z$1.string().optional() + }) + }), + z$1.object({ + code: z$1.literal("agent-preset-not-found"), + message: z$1.string(), + details: z$1.object({ + agentPreset: z$1.string(), + available: z$1.array(z$1.string()) + }) + }), + z$1.object({ + code: z$1.literal("agent-preset-invalid"), + message: z$1.string(), + details: z$1.object({ + agentPreset: z$1.string(), + reason: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("agent-busy"), + message: z$1.string(), + details: z$1.object({ reason: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("attachment-error"), + message: z$1.string(), + details: z$1.object({ reason: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("queue-item-not-found"), + message: z$1.string(), + details: z$1.object({ itemId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("steer-unavailable"), + message: z$1.string(), + details: z$1.object({ itemId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("command-error"), + message: z$1.string(), + details: z$1.object({}) + }), + z$1.object({ + code: z$1.literal("unknown-command"), + message: z$1.string(), + details: z$1.object({}) + }), + z$1.object({ + code: z$1.literal("settings-rejected"), + message: z$1.string(), + details: z$1.object({ ns: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("settings-conflict"), + message: z$1.string(), + details: z$1.object({ + ns: z$1.string(), + expected: z$1.number(), + actual: z$1.number() + }) + }), + z$1.object({ + code: z$1.literal("credential-rejected"), + message: z$1.string(), + details: z$1.object({ ref: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("model-discovery-failed"), + message: z$1.string(), + details: z$1.object({ + settingsNs: z$1.string(), + baseURL: z$1.string().optional() + }) + }), + z$1.object({ + code: z$1.literal("title-invalid"), + message: z$1.string(), + details: z$1.object({ sessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("fork-unavailable"), + message: z$1.string(), + details: z$1.object({ sessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("subagent-parent-unavailable"), + message: z$1.string(), + details: z$1.object({ parentSessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("subagent-not-found"), + message: z$1.string(), + details: z$1.object({ + parentSessionId: z$1.string(), + childSessionId: z$1.string() + }) + }), + z$1.object({ + code: z$1.literal("subagent-catalog-diagnostic"), + message: z$1.string(), + details: z$1.object({ + parentSessionId: z$1.string(), + childSessionId: z$1.string(), + reason: z$1.union([ + z$1.literal("corrupt"), + z$1.literal("unsupported"), + z$1.literal("unavailable") + ]) + }) + }), + z$1.object({ + code: z$1.literal("subagent-not-resumable"), + message: z$1.string(), + details: z$1.object({ childSessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("subagent-unauthorized"), + message: z$1.string(), + details: z$1.object({ childSessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("subagent-delivery-unavailable"), + message: z$1.string(), + details: z$1.object({ childSessionId: z$1.string() }) + }), + z$1.object({ + code: z$1.literal("internal"), + message: z$1.string(), + details: z$1.object({}) + }) +]); +/** +* Business success/failure result schema (generic, reusable). +* @param value - Schema for the business value. +* @returns Schema for RpcResult. +*/ +function rpcResultSchema(value) { + return z$1.union([z$1.object({ + ok: z$1.literal(true), + value + }), z$1.object({ + ok: z$1.literal(false), + error: rpcErrorSchema + })]); +} +/** ClientRequest full form (payload stays wide — the business layer runs the second parse). */ +const clientRequestSchema = z$1.object({ + type: z$1.literal("client-request"), + rpcId: rpcIdSchema, + method: z$1.string(), + payload: z$1.unknown() +}); +/** ServerResponse full form (result.value stays wide). */ +const serverResponseSchema = z$1.object({ + type: z$1.literal("server-response"), + rpcId: rpcIdSchema, + result: rpcResultSchema(z$1.unknown().optional()) +}); +/** ServerRequest full form (payload stays wide). */ +const serverRequestSchema = z$1.object({ + type: z$1.literal("server-request"), + rpcId: rpcIdSchema, + method: z$1.string(), + payload: z$1.unknown() +}); +/** ClientResponse full form (result.value stays wide). */ +const clientResponseSchema = z$1.object({ + type: z$1.literal("client-response"), + rpcId: rpcIdSchema, + result: rpcResultSchema(z$1.unknown().optional()) +}); +z$1.discriminatedUnion("type", [ + clientRequestSchema, + serverResponseSchema, + serverRequestSchema, + clientResponseSchema +]); +/** Carrier receipt schema. */ +const rpcReceiptSchema = z$1.union([z$1.object({ accepted: z$1.literal(true) }), z$1.object({ + accepted: z$1.literal(false), + reason: z$1.union([z$1.literal("not-pending"), z$1.literal("bad-response")]) +})]); +//#endregion +//#region lib/types/api/host.schema.js +/** +* host domain zod schemas (names derived from map keys). +*/ +/** host.describe request payload (empty object literal). */ +const hostDescribeRequestSchema = z$1.object({}); +/** host.describe response value. */ +const hostDescribeValueSchema = z$1.object({ + version: z$1.string(), + cwd: z$1.string(), + provider: z$1.string().optional(), + model: z$1.string().optional(), + attachedSessions: z$1.number().int().nonnegative(), + canOpenPath: z$1.boolean() +}); +/** host.pickDirectory request payload (empty object literal). */ +const hostPickDirectoryRequestSchema = z$1.object({}); +/** host.pickDirectory response value; null means the user cancelled. */ +const hostPickDirectoryValueSchema = z$1.object({ path: z$1.string().nullable() }); +/** Directory row shared by listing entries and breadcrumb crumbs. */ +const directoryEntrySchema = z$1.object({ + name: z$1.string(), + path: z$1.string(), + hidden: z$1.boolean() +}); +/** host.listDirectory request payload; an absent path lists the home directory. */ +const hostListDirectoryRequestSchema = z$1.object({ path: z$1.string().optional() }); +/** host.listDirectory response value. */ +const hostListDirectoryValueSchema = z$1.object({ + path: z$1.string(), + home: z$1.string(), + crumbs: z$1.array(directoryEntrySchema), + entries: z$1.array(directoryEntrySchema), + truncated: z$1.boolean() +}); +/** host.createDirectory request payload: name must be one plain path segment. */ +const hostCreateDirectoryRequestSchema = z$1.object({ + path: z$1.string(), + name: z$1.string() +}).refine((payload) => payload.name.trim() !== "" && payload.name !== "." && payload.name !== ".." && !/[/\\]/.test(payload.name), { message: "host.createDirectory requires a single non-blank path segment name" }); +/** host.createDirectory response value: the created directory's absolute path. */ +const hostCreateDirectoryValueSchema = z$1.object({ path: z$1.string() }); +/** host.openPath request payload. */ +const hostOpenPathRequestSchema = z$1.object({ path: z$1.string().min(1) }); +/** host.openPath response value. */ +const hostOpenPathValueSchema = z$1.object({ opened: z$1.literal(true) }); +//#endregion +//#region lib/types/api/workspace.schema.js +/** +* workspace domain zod schemas (names derived from map keys). The +* WorkspaceId brand cast lives in sessions.schema (see the note there) and +* is re-exported here as the domain-local name. +*/ +/** WorkspaceView row of every workspace.* response. */ +const workspaceViewSchema = z$1.object({ + workspaceId: workspaceIdSchema, + path: z$1.string(), + title: z$1.string(), + sessionIds: z$1.array(sessionIdSchema), + createdAt: z$1.string(), + updatedAt: z$1.string() +}); +/** workspace.list request payload (empty object literal). */ +const workspaceListRequestSchema = z$1.object({}); +/** workspace.list response value. */ +const workspaceListValueSchema = z$1.object({ + items: z$1.array(workspaceViewSchema), + archivedSessionIds: z$1.array(sessionIdSchema) +}); +/** workspace.create request payload: the existing directory to adopt. */ +const workspaceCreateRequestSchema = z$1.object({ path: z$1.string() }); +/** workspace.create response value. */ +const workspaceCreateValueSchema = z$1.object({ + workspace: workspaceViewSchema, + created: z$1.boolean() +}); +/** workspace.rename request payload: the new title must be non-blank. */ +const workspaceRenameRequestSchema = z$1.object({ + workspaceId: workspaceIdSchema, + title: z$1.string() +}).refine((payload) => payload.title.trim() !== "", { message: "workspace.rename requires a non-blank title" }); +/** workspace.rename response value. */ +const workspaceRenameValueSchema = z$1.object({ workspace: workspaceViewSchema }); +/** workspace.delete request payload. */ +const workspaceDeleteRequestSchema = z$1.object({ workspaceId: workspaceIdSchema }); +/** workspace.delete response value. */ +const workspaceDeleteValueSchema = z$1.object({ deleted: z$1.literal(true) }); +/** workspace.insertBefore request payload (anchor omitted = append to end). */ +const workspaceInsertBeforeRequestSchema = z$1.object({ + workspaceId: workspaceIdSchema, + beforeWorkspaceId: workspaceIdSchema.optional() +}); +/** workspace.insertBefore response value: the complete durable display order. */ +const workspaceInsertBeforeValueSchema = z$1.object({ workspaceIds: z$1.array(workspaceIdSchema) }); +/** workspace.insertSessionBefore request payload (anchor omitted = append to end). */ +const workspaceInsertSessionBeforeRequestSchema = z$1.object({ + workspaceId: workspaceIdSchema, + sessionId: sessionIdSchema, + beforeSessionId: sessionIdSchema.optional() +}); +/** workspace.insertSessionBefore response value. */ +const workspaceInsertSessionBeforeValueSchema = z$1.object({ workspace: workspaceViewSchema }); +/** workspace.archiveSession request payload. */ +const workspaceArchiveSessionRequestSchema = z$1.object({ sessionId: sessionIdSchema }); +/** workspace.archiveSession response value: the full updated archive set. */ +const workspaceArchiveSessionValueSchema = z$1.object({ archivedSessionIds: z$1.array(sessionIdSchema) }); +//#endregion +//#region lib/types/api/skills.schema.js +/** +* skills domain zod schemas (names derived from map keys: skillListRequestSchema / +* skillListValueSchema). +*/ +/** SkillEntry row of skill.list. */ +const skillEntrySchema = z$1.object({ + name: z$1.string().min(1), + description: z$1.string(), + whenToUse: z$1.string().optional(), + modelInvocable: z$1.boolean() +}); +/** skill.list request payload. */ +const skillListRequestSchema = z$1.object({ sessionId: sessionIdSchema }); +/** skill.list response value. */ +const skillListValueSchema = z$1.object({ skills: z$1.array(skillEntrySchema) }); +//#endregion +//#region lib/types/api/agent-presets.schema.js +/** +* agent-presets domain zod schemas (names derived from map keys: +* agentPresetListRequestSchema / agentPresetListValueSchema). +*/ +/** AgentPresetEntry row of agentPreset.list. */ +const agentPresetEntrySchema = z$1.object({ + id: z$1.string().min(1), + trust: z$1.union([z$1.literal("system"), z$1.literal("user")]), + isDefault: z$1.boolean(), + name: z$1.string().optional(), + description: z$1.string().optional(), + broken: z$1.string().min(1).optional() +}); +/** agentPreset.list request payload. */ +const agentPresetListRequestSchema = z$1.object({}); +/** agentPreset.list response value. */ +const agentPresetListValueSchema = z$1.object({ + presets: z$1.array(agentPresetEntrySchema), + authorable: z$1.boolean(), + hasDocument: z$1.boolean() +}); +/** agentPreset.select request payload. */ +const agentPresetSelectRequestSchema = z$1.object({ + sessionId: sessionIdSchema, + agentPreset: z$1.string().min(1) +}); +/** agentPreset.select response value. */ +const agentPresetSelectValueSchema = z$1.object({ agentPreset: z$1.string() }); +/** agentPreset.read request payload. */ +const agentPresetReadRequestSchema = z$1.object({ agentPreset: z$1.string().min(1) }); +/** agentPreset.read response value. */ +const agentPresetReadValueSchema = z$1.object({ + agentPreset: z$1.string(), + trust: z$1.union([z$1.literal("system"), z$1.literal("user")]), + content: z$1.string(), + name: z$1.string().optional(), + description: z$1.string().optional() +}); +/** agentPreset.copy request payload. */ +const agentPresetCopyRequestSchema = z$1.object({ + from: z$1.string().min(1), + agentPreset: z$1.string().min(1), + name: z$1.string().optional() +}); +/** agentPreset.copy response value. */ +const agentPresetCopyValueSchema = z$1.object({ agentPreset: z$1.string() }); +/** agentPreset.openDocument request payload. */ +const agentPresetOpenDocumentRequestSchema = z$1.object({ agentPreset: z$1.string().min(1) }); +/** agentPreset.openDocument response value. */ +const agentPresetOpenDocumentValueSchema = z$1.union([z$1.object({ opened: z$1.literal(true) }), z$1.object({ + opened: z$1.literal(false), + path: z$1.string() +})]); +/** agentPreset.remove request payload. */ +const agentPresetRemoveRequestSchema = z$1.object({ agentPreset: z$1.string().min(1) }); +/** agentPreset.remove response value. */ +const agentPresetRemoveValueSchema = z$1.object({}); +//#endregion +//#region lib/types/api/goals.schema.js +/** +* goals domain zod schemas. Mutation-only shapes: every value schema is a +* `{ ref }` acknowledgement (clear: `{ cleared }`) — the current goal state +* travels exclusively on the 'goal' session projection. +*/ +/** GoalRef schema. */ +const goalRefSchema = z$1.object({ + id: z$1.string(), + revision: z$1.number().int().positive() +}); +/** Shared `{ ref }` acknowledgement value of every non-clear mutation. */ +const goalRefValueSchema = z$1.object({ ref: goalRefSchema }); +/** goal.create request payload. */ +const goalCreateRequestSchema = z$1.object({ + sessionId: z$1.string(), + objective: z$1.string().min(1), + maxGoalRounds: z$1.number().int().positive().optional() +}); +/** goal.create response value. */ +const goalCreateValueSchema = goalRefValueSchema; +/** goal.edit request payload. */ +const goalEditRequestSchema = z$1.object({ + sessionId: z$1.string(), + ref: goalRefSchema, + objective: z$1.string().min(1).optional(), + maxGoalRounds: z$1.number().int().positive().optional() +}).refine((value) => value.objective !== void 0 || value.maxGoalRounds !== void 0, { message: "goal.edit requires objective or maxGoalRounds" }); +/** goal.edit response value. */ +const goalEditValueSchema = goalRefValueSchema; +/** goal.pause request payload. */ +const goalPauseRequestSchema = z$1.object({ + sessionId: z$1.string(), + ref: goalRefSchema +}); +/** goal.pause response value. */ +const goalPauseValueSchema = goalRefValueSchema; +/** goal.resume request payload. */ +const goalResumeRequestSchema = z$1.object({ + sessionId: z$1.string(), + ref: goalRefSchema +}); +/** goal.resume response value. */ +const goalResumeValueSchema = goalRefValueSchema; +/** goal.complete request payload. */ +const goalCompleteRequestSchema = z$1.object({ + sessionId: z$1.string(), + ref: goalRefSchema +}); +/** goal.complete response value. */ +const goalCompleteValueSchema = goalRefValueSchema; +/** goal.clear request payload. */ +const goalClearRequestSchema = z$1.object({ + sessionId: z$1.string(), + ref: goalRefSchema +}); +/** goal.clear response value. */ +const goalClearValueSchema = z$1.object({ cleared: z$1.literal(true) }); +//#endregion +//#region lib/types/api/settings.schema.js +/** +* settings domain zod schemas (names derived from map keys: settingsDescribeRequestSchema / +* settingsDescribeValueSchema / settingsUpdate* / settingsReplace*). +*/ +/** One redacted secret slot. */ +const settingsSecretViewSchema = z$1.object({ + path: z$1.array(z$1.string()), + set: z$1.boolean() +}); +/** SettingsNamespaceView row of settings.describe and the write responses. */ +const settingsNamespaceViewSchema = z$1.object({ + ns: z$1.string().min(1), + schema: z$1.unknown(), + value: z$1.unknown(), + base: z$1.unknown().optional(), + user: z$1.unknown().optional(), + applies: z$1.union([z$1.literal("live"), z$1.literal("restart")]), + secrets: z$1.array(settingsSecretViewSchema), + revision: z$1.number() +}); +/** settings.describe request payload. */ +const settingsDescribeRequestSchema = z$1.object({}); +/** settings.describe response value. */ +const settingsDescribeValueSchema = z$1.object({ + writable: z$1.boolean(), + hasDocument: z$1.boolean(), + namespaces: z$1.array(settingsNamespaceViewSchema) +}); +/** settings.openDocument request payload. */ +const settingsOpenDocumentRequestSchema = z$1.object({}); +/** settings.openDocument response value. */ +const settingsOpenDocumentValueSchema = z$1.object({ opened: z$1.literal(true) }); +/** settings.update request payload. */ +const settingsUpdateRequestSchema = z$1.object({ + ns: z$1.string().min(1), + patch: z$1.record(z$1.string(), z$1.unknown()), + expectedRevision: z$1.number().optional() +}); +/** settings.update response value: the namespace's new redacted view. */ +const settingsUpdateValueSchema = settingsNamespaceViewSchema; +/** settings.replace request payload. */ +const settingsReplaceRequestSchema = z$1.object({ + ns: z$1.string().min(1), + section: z$1.record(z$1.string(), z$1.unknown()), + expectedRevision: z$1.number().optional() +}); +/** One path-addressed edit of settings.mutate. */ +const settingsPathOpSchema = z$1.discriminatedUnion("op", [z$1.object({ + op: z$1.literal("set"), + path: z$1.array(z$1.string()), + value: z$1.unknown() +}), z$1.object({ + op: z$1.literal("unset"), + path: z$1.array(z$1.string()) +})]); +/** settings.mutate request payload. */ +const settingsMutateRequestSchema = z$1.object({ + ns: z$1.string().min(1), + ops: z$1.array(settingsPathOpSchema), + expectedRevision: z$1.number().optional() +}); +/** settings.mutate response value: the namespace's new redacted view. */ +const settingsMutateValueSchema = settingsNamespaceViewSchema; +/** settings.replace response value. */ +const settingsReplaceValueSchema = settingsNamespaceViewSchema; +//#endregion +//#region lib/types/api/credentials.schema.js +/** +* credentials domain zod schemas (names derived from map keys: +* credentialsDescribeRequestSchema / credentialsDescribeValueSchema / …). +* The reference-name pattern mirrors the seam's `credentialRef` guard so an +* invalid name fails as `bad-request` before reaching the service. +*/ +/** POSIX-portable environment-variable name (the seam's `credentialRef` pattern). */ +const credentialRefNameSchema = z$1.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/); +/** CredentialView entry of credentials.describe. */ +const credentialViewSchema = z$1.object({ + configured: z$1.boolean(), + source: z$1.string().optional(), + writable: z$1.boolean() +}); +/** credentials.describe request payload. */ +const credentialsDescribeRequestSchema = z$1.object({ refs: z$1.array(credentialRefNameSchema).max(64) }); +/** credentials.describe response value. */ +const credentialsDescribeValueSchema = z$1.object({ credentials: z$1.record(z$1.string(), credentialViewSchema) }); +/** credentials.set request payload: the one direction a value crosses this wire. */ +const credentialsSetRequestSchema = z$1.object({ + ref: credentialRefNameSchema, + value: z$1.string().min(1) +}); +/** credentials.set response value. */ +const credentialsSetValueSchema = z$1.object({}); +/** credentials.unset request payload. */ +const credentialsUnsetRequestSchema = z$1.object({ ref: credentialRefNameSchema }); +/** credentials.unset response value. */ +const credentialsUnsetValueSchema = z$1.object({}); +//#endregion +//#region lib/types/api/llm.schema.js +/** +* llm domain zod schemas (names derived from map keys: llmProvidersRequestSchema / +* llmProvidersValueSchema / llmModelsRequestSchema / llmModelsValueSchema). +*/ +/** ConfigurableProviderView row of llm.providers. */ +const configurableProviderViewSchema = z$1.object({ + provider: z$1.string().min(1), + displayName: z$1.string().min(1), + settingsNs: z$1.string(), + settingsPath: z$1.array(z$1.string()), + active: z$1.boolean(), + declared: z$1.boolean().optional() +}); +/** llm.providers request payload. */ +const llmProvidersRequestSchema = z$1.object({}); +/** llm.providers response value. */ +const llmProvidersValueSchema = z$1.object({ providers: z$1.array(configurableProviderViewSchema) }); +/** llm.models request payload. */ +const llmModelsRequestSchema = z$1.object({}); +/** llm.models response value. */ +const llmModelsValueSchema = z$1.object({ + groups: z$1.array(modelProviderGroupSchema), + failures: z$1.array(modelCatalogFailureSchema) +}); +/** DiscoveredModelView row of llm.discoverModels. */ +const discoveredModelViewSchema = z$1.object({ + id: z$1.string().min(1), + name: z$1.string().min(1).optional(), + contextWindow: z$1.number().int().positive().optional(), + maxTokens: z$1.number().int().positive().optional() +}); +/** llm.discoverModels request payload. */ +const llmDiscoverModelsRequestSchema = z$1.object({ + settingsNs: z$1.string().min(1), + provider: z$1.string().min(1).optional(), + baseURL: z$1.string().min(1).optional(), + api: z$1.string().min(1).optional(), + apiKey: z$1.string().min(1).optional() +}); +/** llm.discoverModels response value. */ +const llmDiscoverModelsValueSchema = z$1.object({ models: z$1.array(discoveredModelViewSchema) }); +//#endregion +//#region lib/types/api/subagents.schema.js +/** Zod schemas for the browser-safe subagent domain. */ +/** Healthy and diagnostic durable catalog rows. */ +const subagentListEntrySchema = z$1.union([ + z$1.object({ + kind: z$1.literal("child"), + id: sessionIdSchema, + mode: z$1.literal("one-shot"), + activity: z$1.union([z$1.literal("running"), z$1.literal("inactive")]), + hasChildren: z$1.boolean(), + label: z$1.string().optional() + }), + z$1.object({ + kind: z$1.literal("child"), + id: sessionIdSchema, + mode: z$1.literal("continuable"), + activity: z$1.union([z$1.literal("running"), z$1.literal("inactive")]), + hasChildren: z$1.boolean(), + label: z$1.string() + }), + z$1.object({ + kind: z$1.literal("diagnostic"), + id: sessionIdSchema, + reason: z$1.union([ + z$1.literal("corrupt"), + z$1.literal("unsupported"), + z$1.literal("unavailable") + ]) + }) +]); +/** subagent.list request payload. */ +const subagentListRequestSchema = z$1.object({ parentSessionId: sessionIdSchema }); +/** subagent.list response value. */ +const subagentListValueSchema = z$1.object({ + entries: z$1.array(subagentListEntrySchema), + parentAvailable: z$1.boolean() +}); +/** subagent.history request payload. */ +const subagentHistoryRequestSchema = z$1.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z$1.union([z$1.literal("one-shot"), z$1.literal("continuable")]), + beforeSeq: z$1.number().int().nonnegative().optional(), + maxMessages: z$1.number().int().positive().optional() +}); +/** subagent.history response value. */ +const subagentHistoryValueSchema = z$1.object({ + events: z$1.array(historyEntrySchema), + hasMore: z$1.boolean(), + projections: sessionProjectionsBlockSchema.optional() +}); +/** subagent.prompt request payload. */ +const subagentPromptRequestSchema = z$1.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z$1.literal("continuable"), + content: z$1.array(contentBlockSchema), + clientTimeZone: z$1.string().optional() +}); +/** subagent.interrupt request payload. */ +const subagentInterruptRequestSchema = z$1.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z$1.literal("continuable") +}); +/** subagent.interrupt response value. */ +const subagentInterruptValueSchema = z$1.object({ accepted: z$1.literal(true) }); +const messageIdSchema = z$1.string(); +/** subagent.prompt response value. */ +const subagentPromptValueSchema = z$1.object({ messageId: messageIdSchema }); +//#endregion +//#region lib/types/fetch/handler.js +/** +* Server side of the fetch carrier: maps an ApiProxy onto a pure +* WHATWG Request->Response function. Two-level parse: full form (type/rpcId/method + +* path==method) -> payload dispatched per method. HTTP status expresses only the carrier +* (404 unknown path / 415 non-JSON media type / 400 non-JSON body / 500 handler crash); +* business errors are always 200 + ServerResponse. +*/ +const UNARY_ROUTES = { + "session.list": { + schema: sessionListRequestSchema, + invoke: (api, r) => api.sessions.list(r) + }, + "session.search": { + schema: sessionSearchRequestSchema, + invoke: (api, r, signal) => api.sessions.search(r, signal) + }, + "session.create": { + schema: sessionCreateRequestSchema, + invoke: (api, r) => api.sessions.create(r) + }, + "session.history": { + schema: sessionHistoryRequestSchema, + invoke: (api, r) => api.sessions.history(r) + }, + "session.models": { + schema: sessionModelsRequestSchema, + invoke: (api, r) => api.sessions.models(r) + }, + "session.selectModel": { + schema: sessionSelectModelRequestSchema, + invoke: (api, r) => api.sessions.selectModel(r) + }, + "session.rename": { + schema: sessionRenameRequestSchema, + invoke: (api, r) => api.sessions.rename(r) + }, + "session.fork": { + schema: sessionForkRequestSchema, + invoke: (api, r) => api.sessions.fork(r) + }, + "session.prompt": { + schema: sessionPromptRequestSchema, + invoke: (api, r) => api.sessions.prompt(r) + }, + "session.attachment": { + schema: sessionAttachmentRequestSchema, + invoke: (api, r) => api.sessions.attachment(r) + }, + "session.updateQueue": { + schema: sessionUpdateQueueRequestSchema, + invoke: (api, r) => api.sessions.updateQueue(r) + }, + "session.cancel": { + schema: sessionCancelRequestSchema, + invoke: (api, r) => api.sessions.cancel(r) + }, + "subagent.list": { + schema: subagentListRequestSchema, + invoke: (api, r, signal) => api.subagents.list(r, signal) + }, + "subagent.history": { + schema: subagentHistoryRequestSchema, + invoke: (api, r, signal) => api.subagents.history(r, signal) + }, + "subagent.prompt": { + schema: subagentPromptRequestSchema, + invoke: (api, r, signal) => api.subagents.prompt(r, signal) + }, + "subagent.interrupt": { + schema: subagentInterruptRequestSchema, + invoke: (api, r) => api.subagents.interrupt(r) + }, + "host.describe": { + schema: hostDescribeRequestSchema, + invoke: (api, r) => api.host.describe(r) + }, + "host.pickDirectory": { + schema: hostPickDirectoryRequestSchema, + invoke: (api, r, signal) => api.host.pickDirectory(r, signal) + }, + "host.listDirectory": { + schema: hostListDirectoryRequestSchema, + invoke: (api, r, signal) => api.host.listDirectory(r, signal) + }, + "host.createDirectory": { + schema: hostCreateDirectoryRequestSchema, + invoke: (api, r) => api.host.createDirectory(r) + }, + "host.openPath": { + schema: hostOpenPathRequestSchema, + invoke: (api, r, signal) => api.host.openPath(r, signal) + }, + "workspace.list": { + schema: workspaceListRequestSchema, + invoke: (api, r) => api.workspace.list(r) + }, + "workspace.create": { + schema: workspaceCreateRequestSchema, + invoke: (api, r) => api.workspace.create(r) + }, + "workspace.rename": { + schema: workspaceRenameRequestSchema, + invoke: (api, r) => api.workspace.rename(r) + }, + "workspace.delete": { + schema: workspaceDeleteRequestSchema, + invoke: (api, r) => api.workspace.delete(r) + }, + "workspace.insertBefore": { + schema: workspaceInsertBeforeRequestSchema, + invoke: (api, r) => api.workspace.insertBefore(r) + }, + "workspace.insertSessionBefore": { + schema: workspaceInsertSessionBeforeRequestSchema, + invoke: (api, r) => api.workspace.insertSessionBefore(r) + }, + "workspace.archiveSession": { + schema: workspaceArchiveSessionRequestSchema, + invoke: (api, r) => api.workspace.archiveSession(r) + }, + "skill.list": { + schema: skillListRequestSchema, + invoke: (api, r) => api.skills.list(r) + }, + "agentPreset.list": { + schema: agentPresetListRequestSchema, + invoke: (api, r) => api.agentPresets.list(r) + }, + "agentPreset.select": { + schema: agentPresetSelectRequestSchema, + invoke: (api, r) => api.agentPresets.select(r) + }, + "agentPreset.read": { + schema: agentPresetReadRequestSchema, + invoke: (api, r) => api.agentPresets.read(r) + }, + "agentPreset.copy": { + schema: agentPresetCopyRequestSchema, + invoke: (api, r) => api.agentPresets.copy(r) + }, + "agentPreset.openDocument": { + schema: agentPresetOpenDocumentRequestSchema, + invoke: (api, r, signal) => api.agentPresets.openDocument(r, signal) + }, + "agentPreset.remove": { + schema: agentPresetRemoveRequestSchema, + invoke: (api, r) => api.agentPresets.remove(r) + }, + "goal.create": { + schema: goalCreateRequestSchema, + invoke: (api, r) => api.goals.create(r) + }, + "goal.edit": { + schema: goalEditRequestSchema, + invoke: (api, r) => api.goals.edit(r) + }, + "goal.pause": { + schema: goalPauseRequestSchema, + invoke: (api, r) => api.goals.pause(r) + }, + "goal.resume": { + schema: goalResumeRequestSchema, + invoke: (api, r) => api.goals.resume(r) + }, + "goal.complete": { + schema: goalCompleteRequestSchema, + invoke: (api, r) => api.goals.complete(r) + }, + "goal.clear": { + schema: goalClearRequestSchema, + invoke: (api, r) => api.goals.clear(r) + }, + "settings.describe": { + schema: settingsDescribeRequestSchema, + invoke: (api, r) => api.settings.describe(r) + }, + "settings.openDocument": { + schema: settingsOpenDocumentRequestSchema, + invoke: (api, r, signal) => api.settings.openDocument(r, signal) + }, + "settings.update": { + schema: settingsUpdateRequestSchema, + invoke: (api, r) => api.settings.update(r) + }, + "settings.replace": { + schema: settingsReplaceRequestSchema, + invoke: (api, r) => api.settings.replace(r) + }, + "settings.mutate": { + schema: settingsMutateRequestSchema, + invoke: (api, r) => api.settings.mutate(r) + }, + "credentials.describe": { + schema: credentialsDescribeRequestSchema, + invoke: (api, r) => api.credentials.describe(r) + }, + "credentials.set": { + schema: credentialsSetRequestSchema, + invoke: (api, r) => api.credentials.set(r) + }, + "credentials.unset": { + schema: credentialsUnsetRequestSchema, + invoke: (api, r) => api.credentials.unset(r) + }, + "llm.providers": { + schema: llmProvidersRequestSchema, + invoke: (api, r) => api.llm.providers(r) + }, + "llm.models": { + schema: llmModelsRequestSchema, + invoke: (api, r) => api.llm.models(r) + }, + "llm.discoverModels": { + schema: llmDiscoverModelsRequestSchema, + invoke: (api, r, signal) => api.llm.discoverModels(r, signal) + } +}; +/** Route lookup that narrows an arbitrary path segment to a map key (single cast point for the string→key refinement). */ +function methodFor(path) { + return Object.hasOwn(UNARY_ROUTES, path) ? path : void 0; +} +/** +* Sentinel rpcId for error responses to envelopes whose own rpcId is unreadable: the response +* must still be a valid ServerResponse (a self-violating shape would turn the server's explicit +* bad-request report into a client-side parse failure). Fixed value, documented here as wire contract. +*/ +const INVALID_REQUEST_RPC_ID = RpcId("invalid-request"); +/** Wrap a business error as a ServerResponse full form (rpcId backfilled; an unreadable rpcId uses the invalid-request sentinel). */ +function errorResponse(rpcId, error) { + const body = { + type: "server-response", + rpcId, + result: { + ok: false, + error + } + }; + return Response.json(body); +} +/** Complete the impl's narrow form into a ServerResponse full form. */ +function fullResponse(narrow) { + const body = { + type: "server-response", + rpcId: narrow.rpcId, + result: narrow.result + }; + return Response.json(body); +} +/** +* Parse the payload and invoke one unary route. Generic over the map key so +* the row's schema/invoke pairing typechecks; the only cast collapses the +* Wire<> widening back to the exact payload (undefined-valued properties and +* absent ones are indistinguishable after JSON transport). +*/ +async function handleUnary(api, method, message, signal) { + const route = UNARY_ROUTES[method]; + const payload = route.schema.safeParse(message.payload); + if (!payload.success) return errorResponse(message.rpcId, { + code: "bad-request", + message: `invalid payload for ${method}`, + details: { issues: payload.error.issues } + }); + try { + return fullResponse(await route.invoke(api, { + rpcId: message.rpcId, + payload: payload.data + }, signal)); + } catch (error) { + return new Response(`handler failure: ${String(error)}`, { status: 500 }); + } +} +/** SSE frame: complete the narrow RpcRequest into a ServerRequest full form (method = frame type). */ +function fullFrame(narrow) { + return { + type: "server-request", + rpcId: narrow.rpcId, + method: narrow.payload.type, + payload: narrow.payload + }; +} +/** +* Wrap a frame stream as an SSE Response; stops when req.signal aborts. An +* impl throw mid-stream emits one stream/error frame and then closes. +*/ +function sseResponse(frames) { + const encoder = new TextEncoder(); + const stream = new ReadableStream({ async start(controller) { + try { + controller.enqueue(encoder.encode(": connected\n\n")); + for await (const narrow of frames) controller.enqueue(encoder.encode(`data: ${JSON.stringify(fullFrame(narrow))}\n\n`)); + } catch (error) { + const failure = { + type: "stream/error", + error: { + code: "internal", + message: String(error), + details: {} + } + }; + try { + controller.enqueue(encoder.encode(`data: ${JSON.stringify(fullFrame({ + rpcId: RpcId(randomUUID()), + payload: failure + }))}\n\n`)); + } catch {} + } finally { + try { + controller.close(); + } catch {} + } + } }); + return new Response(stream, { headers: { + "content-type": "text/event-stream", + "cache-control": "no-cache" + } }); +} +/** +* Wraps an ApiProxy into a pure fetch function (isomorphic point: feed the returned fetch straight to InProcessApiClient). +* @param api - the host-side ApiProxy implementation. +* @returns an object holding `fetch(Request)`; paths outside /api/ return 404. +*/ +function toFetchHandler(api) { + return { async fetch(input, init) { + const req = input instanceof Request ? input : new Request(input, init); + const url = new URL(req.url); + const path = url.pathname; + if (path === "/api/events.mux" && req.method === "GET") return sseResponse(api.events.mux({ + rpcId: RpcId(randomUUID()), + payload: {} + }, req.signal)); + if (path === "/api/events.host" && req.method === "GET") return sseResponse(api.events.host({ + rpcId: RpcId(randomUUID()), + payload: {} + }, req.signal)); + if (path === "/api/session.export" && (req.method === "GET" || req.method === "HEAD")) { + const parsed = sessionLogQuerySchema.safeParse(Object.fromEntries(url.searchParams)); + if (!parsed.success) return new Response("missing or invalid sessionId query parameter", { status: 400 }); + const response = await api.downloads.sessionLog(parsed.data, req.signal); + if (req.method === "GET") return response; + await response.body?.cancel(); + return new Response(null, { + status: response.status, + headers: response.headers + }); + } + if (req.method !== "POST" || !path.startsWith("/api/")) return new Response("not found", { status: 404 }); + if (req.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() !== "application/json") return new Response("content type must be application/json", { status: 415 }); + let body; + try { + body = await req.json(); + } catch { + return new Response("body is not JSON", { status: 400 }); + } + if (path === "/api/respond") { + const parsed = clientResponseSchema.safeParse(body); + if (!parsed.success) return Response.json({ + accepted: false, + reason: "bad-response" + }); + return Response.json(await api.respond(parsed.data)); + } + const method = methodFor(path.slice(5)); + if (method === void 0) return new Response("not found", { status: 404 }); + const envelope = clientRequestSchema.safeParse(body); + if (!envelope.success) { + const rawId = body?.rpcId; + return errorResponse(typeof rawId === "string" ? RpcId(rawId) : INVALID_REQUEST_RPC_ID, { + code: "bad-request", + message: "invalid client-request message", + details: { issues: envelope.error.issues } + }); + } + const message = envelope.data; + if (message.method !== method) return errorResponse(message.rpcId, { + code: "bad-request", + message: `method "${message.method}" does not match path "${method}"`, + details: { issues: [] } + }); + return handleUnary(api, method, message, req.signal); + } }; +} +//#endregion +//#region lib/types/api/jobs.schema.js +/** +* tasks domain zod schemas: the branded job id and the wire view carried by +* `session/jobs` frames. +*/ +/** JobId: one brand cast after non-empty string validation. */ +const taskIdSchema = z$1.string().min(1); +/** +* One wire task view. `kind` stays an open string because producer plugins +* extend the registry's kind map by declaration merging, so the closed set is +* not knowable at this boundary. +*/ +const taskViewSchema = z$1.object({ + id: taskIdSchema, + kind: z$1.string().min(1), + label: z$1.string().min(1), + status: z$1.union([ + z$1.literal("running"), + z$1.literal("stopping"), + z$1.literal("completed"), + z$1.literal("killed"), + z$1.literal("failed") + ]), + detail: z$1.string().optional(), + startedAt: z$1.number().int().nonnegative(), + finishedAt: z$1.number().int().nonnegative().optional() +}); +//#endregion +//#region lib/types/api/events.schema.js +/** +* events domain zod schemas: MuxFrame / HostFrame unions (discriminatedUnion('type')). +* A frame is the payload slot of the ServerRequest full form; the SessionEvent inside +* a session/event frame reuses sessions.schema's strict-envelope + wide-data passthrough branch. +*/ +/** Question fields validated strictly against core dsh-user-questions. */ +const askUserQuestionItemSchema = z$1.object({ + id: z$1.string(), + question: z$1.string(), + header: z$1.string().optional(), + detail: z$1.string().optional(), + options: z$1.array(z$1.object({ + label: z$1.string(), + description: z$1.string().optional() + })).optional(), + multiSelect: z$1.boolean().optional(), + intent: z$1.discriminatedUnion("kind", [z$1.object({ + kind: z$1.literal("plan-review"), + approve: z$1.string() + })]).optional() +}); +/** Unified message envelope carried by transient queue frames. */ +const messageSchema = z$1.object({ + id: z$1.string().min(1), + role: z$1.union([ + z$1.literal("system"), + z$1.literal("user"), + z$1.literal("assistant") + ]), + content: z$1.array(contentBlockSchema), + source: z$1.looseObject({ kind: z$1.string() }) +}); +/** MuxFrame union (payload slot of a mux-stream ServerRequest). */ +const muxFrameSchema = z$1.discriminatedUnion("type", [ + z$1.object({ + type: z$1.literal("session/event"), + sessionId: sessionIdSchema, + event: sessionEventSchema, + view: toolEventViewSchema.optional() + }), + z$1.object({ + type: z$1.literal("session/subscribed"), + sessionId: sessionIdSchema, + lastSeq: z$1.number().int() + }), + z$1.object({ + type: z$1.literal("approval/requested"), + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + toolName: z$1.string(), + callId: z$1.string().optional(), + reason: z$1.string().optional() + }), + z$1.object({ + type: z$1.literal("approval/resolved"), + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + outcome: z$1.union([ + z$1.literal("allowed-once"), + z$1.literal("rejected"), + z$1.literal("cancelled"), + z$1.literal("unavailable") + ]) + }), + z$1.object({ + type: z$1.literal("question/requested"), + sessionId: sessionIdSchema, + questions: z$1.array(askUserQuestionItemSchema).min(1) + }), + z$1.object({ + type: z$1.literal("question/resolved"), + sessionId: sessionIdSchema, + questionRpcId: rpcIdSchema, + outcome: z$1.union([z$1.literal("answered"), z$1.literal("cancelled")]) + }), + z$1.object({ + type: z$1.literal("session/queue"), + sessionId: sessionIdSchema, + items: z$1.array(z$1.object({ + id: messageIdSchema$1, + placement: z$1.union([ + z$1.literal("queued"), + z$1.literal("steering"), + z$1.literal("context") + ]), + message: messageSchema + })) + }), + z$1.object({ + type: z$1.literal("session/jobs"), + sessionId: sessionIdSchema, + jobs: z$1.array(taskViewSchema) + }), + z$1.object({ + type: z$1.literal("session/projection"), + sessionId: sessionIdSchema, + key: z$1.string().min(1), + value: z$1.unknown(), + seq: z$1.number().int().nonnegative() + }), + z$1.object({ + type: z$1.literal("stream/error"), + error: rpcErrorSchema + }) +]); +/** HostFrame union (payload slot of a host-stream ServerRequest). */ +const hostFrameSchema = z$1.discriminatedUnion("type", [ + z$1.object({ + type: z$1.literal("host/session-added"), + sessionId: sessionIdSchema, + blank: z$1.boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: z$1.literal("subagent").optional(), + cwd: z$1.string().optional(), + agentPreset: z$1.string().optional() + }), + z$1.object({ + type: z$1.literal("host/session-removed"), + sessionId: sessionIdSchema + }), + z$1.object({ + type: z$1.literal("host/session-status"), + sessionId: sessionIdSchema, + running: z$1.boolean() + }), + z$1.object({ + type: z$1.literal("host/agent-error"), + sessionId: sessionIdSchema, + message: z$1.string() + }), + z$1.object({ + type: z$1.literal("host/workspace-changed"), + workspace: workspaceViewSchema + }), + z$1.object({ + type: z$1.literal("host/workspace-removed"), + workspaceId: workspaceIdSchema + }), + z$1.object({ + type: z$1.literal("host/workspace-order-changed"), + workspaceIds: z$1.array(workspaceIdSchema) + }), + z$1.object({ + type: z$1.literal("host/archived-sessions-changed"), + archivedSessionIds: z$1.array(sessionIdSchema) + }), + z$1.object({ + type: z$1.literal("host/remote-event"), + event: z$1.string().min(1), + args: z$1.array(z$1.unknown()) + }), + z$1.object({ + type: z$1.literal("stream/error"), + error: rpcErrorSchema + }) +]); +//#endregion +//#region lib/types/fetch/client.js +/** +* Client side of the fetch carrier. AbstractApiClient holds every protocol invariant: rpcId minting, +* four-quadrant envelope wrap/unwrap, zod parsing, in-process SSE frame decoding, and the payload-direct +* IApiClient domain methods (business code never mints). Platform differences ride two aspects: +* abstract doFetch (transport) + overridable onEnvelope (tap). ApiProxy (the impl face) is untouched. +*/ +/** +* S→C second-level parse table: value schema by method (the response-path +* mirror of the handler's request table; key coverage compiler-enforced against RpcMethodMap). +*/ +const UNARY_VALUE_SCHEMAS = { + "session.list": sessionListValueSchema, + "session.search": sessionSearchValueSchema, + "session.create": sessionCreateValueSchema, + "session.history": sessionHistoryValueSchema, + "session.models": sessionModelsValueSchema, + "session.selectModel": sessionSelectModelValueSchema, + "session.rename": sessionRenameValueSchema, + "session.fork": sessionForkValueSchema, + "session.prompt": sessionPromptValueSchema, + "session.attachment": sessionAttachmentValueSchema, + "session.updateQueue": sessionUpdateQueueValueSchema, + "session.cancel": sessionCancelValueSchema, + "subagent.list": subagentListValueSchema, + "subagent.history": subagentHistoryValueSchema, + "subagent.prompt": subagentPromptValueSchema, + "subagent.interrupt": subagentInterruptValueSchema, + "host.describe": hostDescribeValueSchema, + "host.pickDirectory": hostPickDirectoryValueSchema, + "host.listDirectory": hostListDirectoryValueSchema, + "host.createDirectory": hostCreateDirectoryValueSchema, + "host.openPath": hostOpenPathValueSchema, + "workspace.list": workspaceListValueSchema, + "workspace.create": workspaceCreateValueSchema, + "workspace.rename": workspaceRenameValueSchema, + "workspace.delete": workspaceDeleteValueSchema, + "workspace.insertBefore": workspaceInsertBeforeValueSchema, + "workspace.insertSessionBefore": workspaceInsertSessionBeforeValueSchema, + "workspace.archiveSession": workspaceArchiveSessionValueSchema, + "skill.list": skillListValueSchema, + "agentPreset.list": agentPresetListValueSchema, + "agentPreset.select": agentPresetSelectValueSchema, + "agentPreset.read": agentPresetReadValueSchema, + "agentPreset.copy": agentPresetCopyValueSchema, + "agentPreset.openDocument": agentPresetOpenDocumentValueSchema, + "agentPreset.remove": agentPresetRemoveValueSchema, + "goal.create": goalCreateValueSchema, + "goal.edit": goalEditValueSchema, + "goal.pause": goalPauseValueSchema, + "goal.resume": goalResumeValueSchema, + "goal.complete": goalCompleteValueSchema, + "goal.clear": goalClearValueSchema, + "settings.describe": settingsDescribeValueSchema, + "settings.openDocument": settingsOpenDocumentValueSchema, + "settings.update": settingsUpdateValueSchema, + "settings.replace": settingsReplaceValueSchema, + "settings.mutate": settingsMutateValueSchema, + "credentials.describe": credentialsDescribeValueSchema, + "credentials.set": credentialsSetValueSchema, + "credentials.unset": credentialsUnsetValueSchema, + "llm.providers": llmProvidersValueSchema, + "llm.models": llmModelsValueSchema, + "llm.discoverModels": llmDiscoverModelsValueSchema +}; +/** Default timeout for bounded unary calls (rpc-compare 2026-07-19: a hung host must not leave callers pending forever). */ +const DEFAULT_TIMEOUT_MS = 3e4; +/** URL base for in-process handler injection (fake authority, opencode precedent). */ +const INTERNAL_BASE = "http://dsh.internal"; +/** +* Abstract fetch-carrier client. Subclasses supply the transport (doFetch) and may refine the +* per-message tap (onEnvelope) — platform aspects stay in subclasses, protocol invariants stay +* here. Envelope observation is a first-class aspect of this data middle layer: the instance +* owns a microtask-batched buffer (frame storms must not cost one consumer update per frame), +* and observers subscribe via subscribeEnvelopes. The isomorphic point survives: an in-process +* subclass whose doFetch is toFetchHandler(api).fetch never touches the network. +*/ +var AbstractApiClient = class { + timeoutMs; + /** Instance-owned observation buffer (module-level state would leak across instances/tests). */ + envelopeBatch = []; + flushScheduled = false; + envelopeListeners = /* @__PURE__ */ new Set(); + /** @param timeoutMs - timeout for bounded unary calls; user-paced calls and streams do not use it. */ + constructor(timeoutMs = DEFAULT_TIMEOUT_MS) { + this.timeoutMs = timeoutMs; + } + /** + * Subscribe to batched envelope observation (diagnostics/logging consumers). + * Batches follow microtask boundaries; a listener throw is isolated (observation + * must never break the carrier). + * @param listener - receives each flushed batch in arrival order. + * @returns unsubscribe function. + */ + subscribeEnvelopes(listener) { + this.envelopeListeners.add(listener); + return () => { + this.envelopeListeners.delete(listener); + }; + } + /** Per-message tap: feeds the instance buffer. Subclasses may override to observe unbatched (call super to keep batching). */ + onEnvelope(message) { + if (this.envelopeListeners.size === 0) return; + this.envelopeBatch.push(message); + if (this.flushScheduled) return; + this.flushScheduled = true; + queueMicrotask(() => { + this.flushScheduled = false; + const batch = this.envelopeBatch; + this.envelopeBatch = []; + for (const notify of this.envelopeListeners) try { + notify(batch); + } catch (error) { + console.error("[apiproxy] envelope listener threw:", error); + } + }); + } + /** Browser = same-origin (a fake authority would fail DNS on real requests); no-location env (Node) = fake authority. */ + resolveBase() { + const loc = globalThis.location; + return loc?.origin !== void 0 && loc.origin !== "null" ? loc.origin : INTERNAL_BASE; + } + mintRpcId() { + return RpcId(crypto.randomUUID()); + } + /** + * Shared POST leg of both C→S carriers (callUnary/respond): JSON body, + * optional default timeout merged with the caller's external signal, non-2xx → transport throw. + */ + async postJson(path, body, signal, timeoutPolicy = "default") { + const requestSignal = timeoutPolicy === "default" ? signal === void 0 ? AbortSignal.timeout(this.timeoutMs) : AbortSignal.any([AbortSignal.timeout(this.timeoutMs), signal]) : signal; + const response = await this.doFetch(new URL(path, this.resolveBase()), { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), + ...requestSignal === void 0 ? {} : { signal: requestSignal } + }); + if (!response.ok) throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + return response; + } + /** + * Unary protocol path: mint → tap → POST full form → envelope parse → verify + * echo → value parse → tap → narrow. Virtual so a fake carrier (fixture) can + * override transport at this layer. + */ + async callUnary(method, payload, signal, timeoutPolicy = "default") { + const message = { + type: "client-request", + rpcId: this.mintRpcId(), + method, + payload + }; + this.onEnvelope(message); + const response = await this.postJson(`/api/${method}`, message, signal, timeoutPolicy); + const full = serverResponseSchema.parse(await response.json()); + this.onEnvelope(full); + if (full.rpcId !== message.rpcId) throw new Error(`rpcId mismatch for ${method}: sent ${message.rpcId}, got ${full.rpcId}`); + if (!full.result.ok) return { + rpcId: full.rpcId, + result: full.result + }; + const value = UNARY_VALUE_SCHEMAS[method].parse(full.result.value); + return { + rpcId: full.rpcId, + result: { + ok: true, + value + } + }; + } + /** Mux stream opener; virtual for the same override reason as callUnary. */ + openMux(_payload, signal, onOpen) { + return this.readSse("/api/events.mux", signal, muxFrameSchema, onOpen); + } + /** Host stream opener; virtual. */ + openHost(_payload, signal, onOpen) { + return this.readSse("/api/events.host", signal, hostFrameSchema, onOpen); + } + /** + * SSE protocol path: streaming fetch (not EventSource), '\n\n' framing, ServerRequest envelope + + * frame-schema parse, tap, narrow yield. onOpen fires once the response headers are in and the + * body is readable — the stream-established signal, before any frame arrives. A frame that fails + * either parse level is reported and skipped (one corrupt frame must not kill the stream; the + * client's gap detection covers whatever the frame carried). + */ + async *readSse(path, signal, frameSchema, onOpen) { + const response = await this.doFetch(new URL(path, this.resolveBase()), { signal }); + if (!response.ok || response.body === null) throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + onOpen?.(); + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let buffer = ""; + try { + while (true) { + const { done, value } = await reader.read(); + if (done) return; + buffer += decoder.decode(value, { stream: true }); + let boundary; + while ((boundary = buffer.indexOf("\n\n")) !== -1) { + const chunk = buffer.slice(0, boundary); + buffer = buffer.slice(boundary + 2); + const data = chunk.split("\n").filter((line) => line.startsWith("data: ")).map((line) => line.slice(6)).join(""); + if (data === "") continue; + let full; + let frame; + try { + full = serverRequestSchema.parse(JSON.parse(data)); + frame = frameSchema.parse(full.payload); + } catch (error) { + console.error(`[apiproxy] dropping malformed SSE frame on ${path}:`, error); + continue; + } + this.onEnvelope(full); + yield { + rpcId: full.rpcId, + payload: frame + }; + } + } + } finally { + await reader.cancel().catch(() => void 0); + } + } + sessions = { + list: (payload, signal) => this.callUnary("session.list", payload, signal), + search: (payload, signal) => this.callUnary("session.search", payload, signal), + create: (payload, signal) => this.callUnary("session.create", payload, signal), + history: (payload, signal) => this.callUnary("session.history", payload, signal), + models: (payload, signal) => this.callUnary("session.models", payload, signal), + selectModel: (payload, signal) => this.callUnary("session.selectModel", payload, signal), + rename: (payload, signal) => this.callUnary("session.rename", payload, signal), + fork: (payload, signal) => this.callUnary("session.fork", payload, signal), + prompt: (payload, signal) => this.callUnary("session.prompt", payload, signal), + attachment: (payload, signal) => this.callUnary("session.attachment", payload, signal), + updateQueue: (payload, signal) => this.callUnary("session.updateQueue", payload, signal), + cancel: (payload, signal) => this.callUnary("session.cancel", payload, signal) + }; + subagents = { + list: (payload, signal) => this.callUnary("subagent.list", payload, signal), + history: (payload, signal) => this.callUnary("subagent.history", payload, signal), + prompt: (payload, signal) => this.callUnary("subagent.prompt", payload, signal), + interrupt: (payload, signal) => this.callUnary("subagent.interrupt", payload, signal) + }; + host = { + describe: (payload, signal) => this.callUnary("host.describe", payload, signal), + pickDirectory: (payload, signal) => this.callUnary("host.pickDirectory", payload, signal, "caller-signal-only"), + listDirectory: (payload, signal) => this.callUnary("host.listDirectory", payload, signal), + createDirectory: (payload, signal) => this.callUnary("host.createDirectory", payload, signal), + openPath: (payload, signal) => this.callUnary("host.openPath", payload, signal) + }; + workspace = { + list: (payload, signal) => this.callUnary("workspace.list", payload, signal), + create: (payload, signal) => this.callUnary("workspace.create", payload, signal), + rename: (payload, signal) => this.callUnary("workspace.rename", payload, signal), + delete: (payload, signal) => this.callUnary("workspace.delete", payload, signal), + insertBefore: (payload, signal) => this.callUnary("workspace.insertBefore", payload, signal), + insertSessionBefore: (payload, signal) => this.callUnary("workspace.insertSessionBefore", payload, signal), + archiveSession: (payload, signal) => this.callUnary("workspace.archiveSession", payload, signal) + }; + skills = { list: (payload, signal) => this.callUnary("skill.list", payload, signal) }; + agentPresets = { + list: (payload, signal) => this.callUnary("agentPreset.list", payload, signal), + select: (payload, signal) => this.callUnary("agentPreset.select", payload, signal), + read: (payload, signal) => this.callUnary("agentPreset.read", payload, signal), + copy: (payload, signal) => this.callUnary("agentPreset.copy", payload, signal), + openDocument: (payload, signal) => this.callUnary("agentPreset.openDocument", payload, signal), + remove: (payload, signal) => this.callUnary("agentPreset.remove", payload, signal) + }; + goals = { + create: (payload, signal) => this.callUnary("goal.create", payload, signal), + edit: (payload, signal) => this.callUnary("goal.edit", payload, signal), + pause: (payload, signal) => this.callUnary("goal.pause", payload, signal), + resume: (payload, signal) => this.callUnary("goal.resume", payload, signal), + complete: (payload, signal) => this.callUnary("goal.complete", payload, signal), + clear: (payload, signal) => this.callUnary("goal.clear", payload, signal) + }; + settings = { + describe: (payload, signal) => this.callUnary("settings.describe", payload, signal), + openDocument: (payload, signal) => this.callUnary("settings.openDocument", payload, signal), + update: (payload, signal) => this.callUnary("settings.update", payload, signal), + replace: (payload, signal) => this.callUnary("settings.replace", payload, signal), + mutate: (payload, signal) => this.callUnary("settings.mutate", payload, signal) + }; + credentials = { + describe: (payload, signal) => this.callUnary("credentials.describe", payload, signal), + set: (payload, signal) => this.callUnary("credentials.set", payload, signal), + unset: (payload, signal) => this.callUnary("credentials.unset", payload, signal) + }; + llm = { + providers: (payload, signal) => this.callUnary("llm.providers", payload, signal), + models: (payload, signal) => this.callUnary("llm.models", payload, signal), + discoverModels: (payload, signal) => this.callUnary("llm.discoverModels", payload, signal) + }; + events = { + mux: (payload, signal, onOpen) => this.openMux(payload, signal, onOpen), + host: (payload, signal, onOpen) => this.openHost(payload, signal, onOpen) + }; + async respond(message, signal) { + this.onEnvelope(message); + const response = await this.postJson("/api/respond", message, signal); + return rpcReceiptSchema.parse(await response.json()); + } +}; +/** +* In-process client over an injected fetch-shaped handler (the isomorphic point: +* `new InProcessApiClient(toFetchHandler(api))` never touches the network). Lives here because +* in-process injection is this package's own capability (handler and client are both local). +*/ +var InProcessApiClient = class extends AbstractApiClient { + handler; + constructor(handler, timeoutMs) { + super(timeoutMs); + this.handler = handler; + } + /** + * Faithful to real fetch: reject on signal abort even when the in-process + * handler ignores the signal (a hung impl must not defeat timeout/cancel). + */ + doFetch(input, init) { + const signal = init?.signal ?? void 0; + if (signal === void 0) return this.handler.fetch(input, init); + if (signal.aborted) return Promise.reject(abortError(signal)); + return new Promise((resolve, reject) => { + const onAbort = () => { + reject(abortError(signal)); + }; + signal.addEventListener("abort", onAbort, { once: true }); + this.handler.fetch(input, init).then(resolve, reject).finally(() => { + signal.removeEventListener("abort", onAbort); + }); + }); + } +}; +/** Mirror fetch's abort rejection: the signal's reason when present, else a DOMException-style AbortError. */ +function abortError(signal) { + const reason = signal.reason; + if (reason instanceof Error) return reason; + if (typeof reason === "string") return new Error(reason); + return /* @__PURE__ */ new Error("This operation was aborted"); +} +//#endregion +//#region lib/types/index.js +/** +* @deepseek-ai/dsh-host-apiproxy — the API gateway every client shape shares: +* the ApiProxy contract (api/: types + zod schemas, browser-safe), the fetch +* carrier pair (fetch/: toFetchHandler on the host side, AbstractApiClient + +* platform subclasses on the client side), and the host-side implementation +* (api-proxy.ts: createApiProxy + the ApiProxyService gateway plugin providing +* `ctx.apiProxy`). Transport-agnostic by design: this package registers no +* routes — physical carriers wrap `ctx.apiProxy` themselves. +* +* The gateway consumes `ctx.agentDefaultModel`, the transport-independent default +* shared with direct entry points. Switching models persists through that +* service; sessions that have already logged a selection remain unchanged. +*/ +/** +* The API gateway service: implements the ApiProxy contract over the composed +* host context and provides it as `ctx.apiProxy`. The Host cwd is the default +* project directory. +*/ +var ApiProxyService = class extends Service { + static inject = [ + "agentDefaultModel", + "agents", + "attachments", + "directoryPicker", + "llm", + "sessions", + "subagents", + "sessionQuery", + "tools", + "userQuestions", + "workspaceRegistry" + ]; + static Config = z.object({ + nativeOpen: z.boolean(), + sessionExportCompressionLevel: z.number().step(1).min(0).max(9).default(6), + coldBlankProbeMaxBytes: z.natural().default(DEFAULT_COLD_BLANK_PROBE_MAX_BYTES) + }); + sessions; + subagents; + workspace; + host; + goals; + skills; + agentPresets; + settings; + credentials; + llm; + events; + downloads; + respond; + constructor(ctx, config) { + super(ctx, "apiProxy"); + const api = createApiProxy(ctx, { + defaultModelSelection: () => ctx.agentDefaultModel.currentSelection(), + saveDefaultModelSelection: (selection) => ctx.agentDefaultModel.saveSelection(selection), + cwd: process.cwd(), + ...config.nativeOpen === void 0 ? {} : { canOpenPath: () => config.nativeOpen }, + ...config.sessionExportCompressionLevel === void 0 ? {} : { sessionExportCompressionLevel: config.sessionExportCompressionLevel }, + ...config.coldBlankProbeMaxBytes === void 0 ? {} : { coldBlankProbeMaxBytes: config.coldBlankProbeMaxBytes } + }); + this.sessions = api.sessions; + this.subagents = api.subagents; + this.workspace = api.workspace; + this.host = api.host; + this.goals = api.goals; + this.skills = api.skills; + this.agentPresets = api.agentPresets; + this.settings = api.settings; + this.credentials = api.credentials; + this.llm = api.llm; + this.events = api.events; + this.downloads = api.downloads; + this.respond = api.respond.bind(api); + } +}; +//#endregion +export { AbstractApiClient, ApiProxyService, ApiProxyService as default, InProcessApiClient, RpcId, createApiProxy, toFetchHandler }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/invariant.js new file mode 100644 index 0000000..afea97a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/invariant.js @@ -0,0 +1,27 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-host-apiproxy`. +* @module @deepseek-ai/dsh-host-apiproxy/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-host-apiproxy"; +/** Cordis companion plugin name. */ +const name = "host-apiproxy-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this package is the wire contract layer plus the +* host-side gateway over services owned elsewhere — it emits no cordis events +* of its own; the session/agent event streams it projects are asserted by +* their owning packages' companions. rpcId round-trip and schema acceptance +* are enforced at the carrier boundary and exercised by the +* protocol-isomorphism suite. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.d.ts new file mode 100644 index 0000000..c59634a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.d.ts @@ -0,0 +1,70 @@ +/** + * Host-side ApiProxy implementation. Signature discipline: unary takes the + * narrow RpcRequest

and echoes request.rpcId on the RpcResponse. + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { ModelSelection } from '@deepseek-ai/dsh-agent'; +import type { JsonValue } from '@deepseek-ai/dsh-session'; +import type { ApiProxy } from './api/index.ts'; +import { type SessionLogCompressionLevel } from './session-export.ts'; +/** Default maximum artifact size eligible for one cold blankness read. */ +export declare const DEFAULT_COLD_BLANK_PROBE_MAX_BYTES = 1024; +/** + * Narrow one allowlisted host event's argument list to the JSON values the + * wrapper frame carries. A rejected argument is an allowlist mistake (the + * forwarded path applies no projection), not hostile input, so it throws rather + * than degrading to a lossy frame. The throw surfaces where the forwarding + * listener runs, so the emitter's own listener containment logs it and drops + * that frame — loud in the Host log, not at load or at the emit. Exported for + * the test that owns this decision: every currently allowlisted event has a + * statically JSON-safe payload, so a type-legal `ctx.emit` cannot reach the + * rejection branch. + * @param event - forwarded host event name, named in the failure. + * @param args - the emitter's argument list. + * @returns the same arguments typed as JSON values. + */ +export declare function assertJsonArgs(event: string, args: readonly unknown[]): JsonValue[]; +/** Resolved Agent model and project-directory defaults consumed by the API implementation. */ +export interface ApiProxyDefaults { + /** + * The model selection a session starts from when its own log names none. Read on + * every access rather than captured, so a default saved during this process + * reaches the sessions that have not run a turn yet. + */ + defaultModelSelection: () => ModelSelection; + /** + * Record a selection as the new default. Either absent, or a closure that + * may itself decline — the gateway plugin always passes one, and it no-ops + * when the deployment mounts no settings provider or when the write races + * service teardown. A switch then stays process-local. A rejection is + * reported and swallowed: the switch already applies to its own session, + * and undoing it because storage failed would be the worse outcome. + */ + saveDefaultModelSelection?: (selection: ModelSelection) => Promise; + /** Default project directory for new sessions whose create request carries no cwd. */ + cwd: string; + /** Native open-with-default-application; injectable for carrier tests. */ + openPath?: (path: string, signal: AbortSignal) => Promise; + /** Native text-editor handoff; injectable for settings-document tests. */ + openTextFile?: (path: string, signal: AbortSignal) => Promise; + /** Validated DEFLATE level for session-log ZIP entries; defaults to 6. */ + sessionExportCompressionLevel?: SessionLogCompressionLevel; + /** Maximum artifact size eligible for one cold blankness read. */ + coldBlankProbeMaxBytes?: number; + /** + * Whether handing a path to the native opener can work at all — the + * `hasDocument` capability the preset roster reports, and the switch + * between opening a preset directory and answering its path as text. + * Absent, an injected `openPath` counts as openable and everything else + * falls back to platform detection ({@link canOpenNativePath}). + */ + canOpenPath?: () => boolean; +} +/** + * Implement ApiProxy over a composed host context. + * @param ctx - a context with the Host spine and Workspace registry mounted. + * @param defaults - host routing and project-directory defaults. + * @returns the ApiProxy implementation. + */ +export declare function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiProxy; +//# sourceMappingURL=api-proxy.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.js new file mode 100644 index 0000000..18e57d9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api-proxy.js @@ -0,0 +1,3397 @@ +/** + * Host-side ApiProxy implementation. Signature discipline: unary takes the + * narrow RpcRequest

and echoes request.rpcId on the RpcResponse. + */ +import { randomUUID } from 'node:crypto'; +import { mkdir, stat } from 'node:fs/promises'; +import { dirname } from 'node:path'; +import { installModelSelection } from '@deepseek-ai/dsh-agent'; +import { AttachmentError } from '@deepseek-ai/dsh-attachment'; +import { contentHasImage, createUserMessage, freezeMessage, ReasoningEffortId } from '@deepseek-ai/dsh-llm'; +import { errorChain } from '@deepseek-ai/dsh-llm'; +import { isAppendSurfaceEvent, isJsonValue } from '@deepseek-ai/dsh-session'; +import { SessionQueryError } from '@deepseek-ai/dsh-session-query'; +import { SubagentError } from '@deepseek-ai/dsh-subagent'; +import { isUserInvocable } from '@deepseek-ai/dsh-skill'; +import { workspaceDomainState, workspaceRecord, WorkspaceId as brandWorkspaceId, WorkspaceMoveInvalidError, WorkspaceOrderInvalidError, WorkspaceUnknownSessionError, } from '@deepseek-ai/dsh-workspace'; +// Type-only: brings the `ctx.tools` Context merge into this program (viewFor reads presenters). +import { InvalidPresetIdError, PresetExistsError, PresetMountError, PresetNotWritableError, resolveSessionPreset, UnknownPresetError, } from '@deepseek-ai/dsh-agent-presets'; +import { DEFAULT_SESSION_LOG_COMPRESSION_LEVEL, flushLiveSessionLog, sessionLogExportDeps, sessionLogZipFilename, streamSessionLogZip, } from "./session-export.js"; +import { SESSION_SEARCH_RESULT_LIMIT, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS, truncateUnicodeCodePoints, } from "./api/session-search.js"; +// GoalError narrows domain rejections to their stable codes at the wire boundary. +import { GoalError } from '@deepseek-ai/dsh-goal'; +// The settings/credentials seams: brand guards run at this wire boundary; the +// service reads stay optional (`ctx.get`) so a composition without either +// provider still serves every other domain. +import { SettingsConflictError, settingsNamespace } from '@deepseek-ai/dsh-settings'; +import { credentialRef } from '@deepseek-ai/dsh-credentials'; +// Value edge: the rename impl narrows the title service's validation failure; the import also resolves `ctx.get('sessionTitle')`. +import { SessionTitleInvalidError } from '@deepseek-ai/dsh-session-title'; +import { approvalResponsePayloadSchema } from "./api/approvals.schema.js"; +import { imageLimitsProjectionSchema, sessionListMetadataProjectionSchema } from "./api/sessions.schema.js"; +import { questionResponsePayloadSchema } from "./api/questions.schema.js"; +import { RpcId } from "./api/rpc.js"; +import { UserQuestionError } from '@deepseek-ai/dsh-user-questions'; +import { DirectoryPickerError } from '@deepseek-ai/dsh-host-directory-picker'; +import { ApiRemoteSessionNotFound as SessionNotFound, ApiRemoteSubagentSessionOwnership as SubagentSessionOwnership, API_REMOTE_FORWARDED_EVENTS, apiRemoteSubagentOwnershipError, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession, } from '@deepseek-ai/dsh-api-remotes'; +import { canOpenNativePath, openNativePath, openNativeTextFile } from "./native-path-opener.js"; +/** Page size when history is called without maxMessages. */ +const DEFAULT_MAX_MESSAGES = 50; +/** Provider work budget: at most 100 calls and 2,000 inspected hits. */ +const SESSION_SEARCH_PROVIDER_CALL_LIMIT = 100; +/** Bound cold-log stat fan-out and settle each started batch before cancellation returns. */ +const COLD_SUMMARY_BATCH_SIZE = 16; +/** Default maximum artifact size eligible for one cold blankness read. */ +export const DEFAULT_COLD_BLANK_PROBE_MAX_BYTES = 1024; +/** Conversation message event types (the pagination counting unit). */ +const MESSAGE_TYPES = new Set(['user/message', 'assistant/message']); +/** Decode the browser payload while rejecting non-canonical base64 forms. */ +function decodeBase64(data) { + const decoded = Buffer.from(data, 'base64'); + if (data.length === 0 || decoded.toString('base64') !== data) { + throw new AttachmentError('Image upload is not canonical base64.', 'INVALID_IMAGE_BASE64'); + } + return new Uint8Array(decoded); +} +/** Validate one prompt as a batch before publishing any durable image object. */ +async function durablePromptContent(ctx, content) { + if (content.every(part => part.type === 'text')) { + return content.map(part => ({ type: 'text', text: part.text })); + } + const prepared = content.map(part => part.type === 'text' + ? part + : { part, data: decodeBase64(part.data) }); + const images = prepared.filter((part) => 'data' in part); + const refs = await ctx.attachments.saveImages(images.map(image => ({ + data: image.data, + mediaType: image.part.mediaType, + ...image.part.name === undefined ? {} : { name: image.part.name }, + }))); + const blocks = []; + let imageIndex = 0; + for (const item of prepared) { + if (!('data' in item)) { + blocks.push({ type: 'text', text: item.text }); + continue; + } + const attachment = refs[imageIndex++]; + /* v8 ignore next -- each prepared image supplied exactly one saveImages input and therefore one ordered ref. */ + if (attachment === undefined) + throw new Error('attachment batch result did not preserve input cardinality'); + blocks.push({ type: 'image', attachment }); + } + return blocks; +} +/** Search durable content for an image reference, including nested tool results. */ +function imageBlockIn(content, match) { + if (!Array.isArray(content)) + return undefined; + for (const value of content) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) + continue; + const block = value; + if (block.type === 'image' && typeof block.attachment === 'object' && block.attachment !== null) { + const ref = block.attachment; + if (match(ref)) + return ref; + } + if (block.type === 'tool-result') { + const nested = imageBlockIn(block.content, match); + if (nested !== undefined) + return nested; + } + } + return undefined; +} +/** Search every durable event carrier that can own model-visible content. */ +function imageInEvent(event, match) { + const data = event.data; + const direct = imageBlockIn(data.content, match); + if (direct !== undefined) + return direct; + if (data.message !== undefined) { + const wrapped = imageBlockIn(data.message.content, match); + if (wrapped !== undefined) + return wrapped; + } + if (data.inserted !== undefined) { + for (const message of data.inserted) { + const inserted = imageBlockIn(message.content, match); + if (inserted !== undefined) + return inserted; + } + } + if (event.type === 'assistant/chunk' && data.chunk?.type === 'block-end') { + return imageBlockIn([data.chunk.block], match); + } + return undefined; +} +/** True when the current model-visible surface contains an image. */ +function messagesHaveImage(messages) { + return messages.some(message => contentHasImage(message.content)); +} +/** Resolve the first reference matching one opaque id. */ +function referencedImage(events, attachmentId) { + for (const event of events) { + const found = imageInEvent(event, ref => String(ref.attachmentId) === attachmentId); + if (found !== undefined) + return found; + } + return undefined; +} +/** Strict browser-zone profile: UTC or an IANA Area/Location-style identifier. */ +const IANA_TIME_ZONE = /^[A-Za-z][A-Za-z0-9_+.-]*(?:\/[A-Za-z0-9_+.-]+)+$/; +/** Validate and canonicalize one browser-supplied IANA zone at the wire boundary. */ +function canonicalClientTimeZone(value) { + if (value.length === 0 || value.trim() !== value + || (value !== 'UTC' && !IANA_TIME_ZONE.test(value))) + return undefined; + try { + const canonical = new Intl.DateTimeFormat('en-US', { timeZone: value }) + .resolvedOptions().timeZone; + /* v8 ignore next -- Intl returns UTC or a canonical IANA Area/Location for accepted input. */ + if (canonical !== 'UTC' && !IANA_TIME_ZONE.test(canonical)) + return undefined; + return canonical; + } + catch { + // Intl rejects unsupported zone names; the RPC maps that parser rejection below. + return undefined; + } +} +/** Read live abort state across awaits without treating it as synchronously immutable. */ +function isAborted(signal) { + return signal.aborted; +} +/** + * Message-boundary pagination: count maxMessages append-origin messages + * backwards from the window tail. Replacement copies never entered the + * conversation a reader sees — they restate a shadowed range for the model + * alone — so they consume no quota; the page stays one contiguous raw range, + * which keeps a compaction's log-only `compaction/summary` record on the same page as its + * replacement. The cut is the starting seq of the oldest message group (chunks + * group via sourceEventSeqs — never cut mid-message). The tail page naturally + * includes the in-progress partial. + */ +function paginate(events, beforeSeq, maxMessages) { + const window = beforeSeq === undefined ? [...events] : events.filter(event => event.seq < beforeSeq); + let count = 0; + let cut = 0; + for (let i = window.length - 1; i >= 0; i--) { + const event = window[i]; + if (!MESSAGE_TYPES.has(event.type) || !isAppendSurfaceEvent(event)) + continue; + count++; + const sources = event.sourceEventSeqs; + let groupStart = event.seq; + if (sources !== undefined) { + for (const source of sources) { + if (source < groupStart) + groupStart = source; + } + } + if (count >= maxMessages) { + cut = groupStart; + break; + } + } + const page = window.filter(event => event.seq >= cut); + return { events: page, hasMore: cut > 0 }; +} +/** Wrap an ok result echoing the request's rpcId. */ +function ok(request, value) { + return { rpcId: request.rpcId, result: { ok: true, value } }; +} +/** + * Build the provider/model catalog over every registered route. Shared by the + * session-scoped `session.models` and host-scoped `llm.models`. Catalog + * membership stays advisory: an unlisted session selection remains valid for + * provider dispatch, but is not injected back into the selector after its + * owning catalog stops advertising it. Per-provider failures ride `failures` + * without failing the sound groups; groups that advertise nothing are dropped. + */ +async function buildModelCatalog(ctx) { + const catalog = await Promise.all(ctx.llm.listProviders().map(async (provider) => { + try { + const models = await ctx.llm.listModels(provider.id); + const entries = await Promise.all(models.map(async (model) => { + const resolved = await ctx.llm.resolveModelInfo(provider.id, model.id); + const reasoning = resolved.reasoning === undefined + ? undefined + : { + efforts: resolved.reasoning.efforts.map(effort => ({ + id: effort.id, + name: effort.name, + ...effort.description === undefined + ? {} + : { description: effort.description }, + })), + ...resolved.reasoning.defaultEffort === undefined + ? {} + : { defaultEffort: resolved.reasoning.defaultEffort }, + }; + return { + id: model.id, + name: model.name, + ...model.description === undefined ? {} : { description: model.description }, + ...reasoning === undefined ? {} : { reasoning }, + }; + })); + const group = { + id: provider.id, + name: provider.name, + models: entries, + }; + return { kind: 'group', group }; + } + catch (error) { + const failure = { + id: provider.id, + name: provider.name, + message: error instanceof Error ? error.message : String(error), + }; + return { kind: 'failure', failure }; + } + })); + return { + groups: catalog.flatMap(item => item.kind === 'group' ? [item.group] : []).filter(group => group.models.length > 0), + failures: catalog.flatMap(item => item.kind === 'failure' ? [item.failure] : []), + }; +} +/** Wrap an error result echoing the request's rpcId. */ +function err(request, error) { + return { rpcId: request.rpcId, result: { ok: false, error } }; +} +/** + * The RPC refusal a preset failure becomes, or undefined when the failure is + * about something else. + * + * Both the session-create path and the switch path can be handed the same two + * failures, and a client that has to branch on the code needs them worded the + * same from either. + * @param request - the request being answered. + * @param error - the thrown value. + * @returns the refusal, or undefined when the caller should keep handling. + */ +function presetFailure(request, error) { + if (error instanceof UnknownPresetError) { + return err(request, { + code: 'agent-preset-not-found', + message: error.message, + details: { agentPreset: error.presetId, available: [...error.available] }, + }); + } + if (error instanceof PresetMountError) { + return err(request, { + code: 'agent-preset-invalid', + message: error.message, + details: { agentPreset: error.presetId, reason: error.reason }, + }); + } + return undefined; +} +/** Simple async queue: core callbacks push, the AsyncIterable pulls; abort/return cleans up. */ +class FrameQueue { + buffer = []; + waiter; + done = false; + push(item) { + if (this.done) + return; + this.buffer.push(item); + this.waiter?.(); + } + end() { + this.done = true; + this.waiter?.(); + } + async *iterate(signal, cleanup) { + const onAbort = () => { this.end(); }; + signal.addEventListener('abort', onAbort, { once: true }); + try { + while (true) { + while (this.buffer.length > 0) + yield this.buffer.shift(); + if (this.done || signal.aborted) + return; + await new Promise((resolve) => { this.waiter = resolve; }); + this.waiter = undefined; + } + } + finally { + signal.removeEventListener('abort', onAbort); + cleanup(); + } + } +} +/** + * Server-side frame mint: pure pushes get a fresh rpcId per frame (answerable + * frames — approval/question requested — mint their stable id in their + * pending registries instead). + */ +function frame(payload) { + return { rpcId: RpcId(randomUUID()), payload }; +} +/** + * Narrow one allowlisted host event's argument list to the JSON values the + * wrapper frame carries. A rejected argument is an allowlist mistake (the + * forwarded path applies no projection), not hostile input, so it throws rather + * than degrading to a lossy frame. The throw surfaces where the forwarding + * listener runs, so the emitter's own listener containment logs it and drops + * that frame — loud in the Host log, not at load or at the emit. Exported for + * the test that owns this decision: every currently allowlisted event has a + * statically JSON-safe payload, so a type-legal `ctx.emit` cannot reach the + * rejection branch. + * @param event - forwarded host event name, named in the failure. + * @param args - the emitter's argument list. + * @returns the same arguments typed as JSON values. + */ +export function assertJsonArgs(event, args) { + for (const [index, arg] of args.entries()) { + if (!isJsonValue(arg)) { + throw new Error(`forwarded host event "${event}" argument ${index} is not lossless JSON data`); + } + } + return args; +} +/** Queue the subscription baseline frame. */ +function subscribeSession(queue, session) { + queue.push(frame({ type: 'session/subscribed', sessionId: session.id, lastSeq: session.seq - 1 })); +} +/** + * Project registry snapshots onto the wire view, dropping the three internal + * fields {@link JobView} documents as absent. + */ +function jobViews(snapshots) { + return snapshots.map(job => ({ + id: job.id, + kind: job.kind, + label: job.label, + status: job.status, + ...job.detail === undefined ? {} : { detail: job.detail }, + startedAt: job.startedAt, + ...job.finishedAt === undefined ? {} : { finishedAt: job.finishedAt }, + })); +} +/** + * Whether the session's conversation has started: no turn has run yet (a + * turn is one model-loop execution). Standalone plugin events — command + * lifecycle records, plan/mode, titles, goals — never open a turn, so + * running `/plan` or `/goal` on a fresh session keeps it blank + * (list-hidden, reusable). + */ +function sessionBlank(session) { + return !session.events.some(event => event.type === 'turn/start'); +} +/** Advance the Session-list hint projection by one committed event. */ +function applySessionListMetadata(state, event) { + const blank = state.blank && event.type !== 'turn/start'; + const lastPromptAt = event.type === 'user/message' && event.data.source.kind === 'user' + ? event.time + : state.lastPromptAt; + return blank === state.blank && lastPromptAt === state.lastPromptAt + ? state + : { blank, lastPromptAt }; +} +/** Fold exact list metadata for an attached Session. */ +function sessionListMetadata(events) { + let state = { blank: true, lastPromptAt: null }; + for (const event of events) + state = applySessionListMetadata(state, event); + return state; +} +/** Sort by creation or latest human prompt, whichever is newer. */ +function sessionListUpdatedAt(header, metadata) { + return Math.max(header.createdAt, metadata?.lastPromptAt ?? 0); +} +/** Shared Session-header projection for list baselines and creation frames. */ +function sessionListFields(header, events = []) { + // The preset comes from the log, not the header: a session that switched + // while blank ran its turns under the newer composition, and a picker + // showing the creation-time value would contradict what the model saw. + const agentPreset = resolveSessionPreset({ header, events }); + return { + ...header.parentSession === undefined ? {} : { parentSessionId: header.parentSession }, + ...header.origin === undefined ? {} : { origin: header.origin }, + ...header.cwd === undefined ? {} : { cwd: header.cwd }, + ...agentPreset === undefined ? {} : { agentPreset }, + }; +} +/** SessionSummary projection for attached (in-memory) sessions. */ +function summarize(session, running) { + const metadata = sessionListMetadata(session.events); + return { + sessionId: session.id, + updatedAt: sessionListUpdatedAt(session.header, metadata), + running, + blank: metadata.blank, + ...sessionListFields(session.header, session.events), + }; +} +/** + * Verify a possibly blank cold Session only when its physical artifact passes + * the configured per-Session size check. A stale `blank: true`, an + * absent cache row, a large or location-less artifact, and read failures all + * resolve to visible (`false`); listing must never hide a conversation on a + * cache hint or an unavailable optimization. + */ +async function probeColdSessionMetadata(ctx, persistence, meta, maxBytes, signal) { + if (maxBytes === 0) + return undefined; + signal?.throwIfAborted(); + const location = persistence.locate(meta); + if (location === undefined) + return undefined; + signal?.throwIfAborted(); + let size; + try { + size = (await stat(location.path)).size; + } + catch { + signal?.throwIfAborted(); + return undefined; + } + if (size > maxBytes) + return undefined; + try { + const { events } = await persistence.readFrom(meta.id, 0, signal); + signal?.throwIfAborted(); + return sessionListMetadata(events); + } + catch (error) { + signal?.throwIfAborted(); + ctx.logger.warn(`session.list: blank probe for "${meta.id}" failed (serving it as visible): ${String(error)}`); + return undefined; + } +} +/** SessionSummary projection for a cold persisted Session. */ +async function summarizeCold(ctx, persistence, meta, metadata, blankProbeMaxBytes, signal) { + const probed = metadata?.blank === false + ? undefined + : await probeColdSessionMetadata(ctx, persistence, meta, blankProbeMaxBytes, signal); + return { + sessionId: meta.id, + updatedAt: sessionListUpdatedAt(meta, probed ?? metadata), + running: false, + blank: metadata?.blank === false ? false : probed?.blank ?? false, + // Header-only: reading the log for a blank-window preset switch would + // defeat the same index read, and attaching the session replaces this row + // with `summarize()`, which resolves the switch from the events. + ...sessionListFields(meta), + }; +} +/** Map a browse-primitive failure onto the wire error vocabulary (unknown throws stay internal). */ +function directoryError(error) { + if (error instanceof DirectoryPickerError) { + return { code: error.code, message: error.message, details: { path: error.path } }; + } + return { code: 'internal', message: error instanceof Error ? error.message : String(error), details: {} }; +} +/** Project a pending entry into its answerable mux frame (initial push and mux-open replay share it). */ +function requestedFrame(pending) { + return { + rpcId: pending.rpcId, + payload: { + type: 'approval/requested', + sessionId: pending.sessionId, + approvalId: pending.approvalId, + toolName: pending.toolName, + ...pending.callId === undefined ? {} : { callId: pending.callId }, + ...pending.reason === undefined ? {} : { reason: pending.reason }, + }, + }; +} +/** Validate one answer batch against the exact question request it resolves. */ +function matchesQuestions(payload, pending) { + if (payload.sessionId !== pending.sessionId) + return false; + const answers = payload.answer.answers; + if (answers.length !== pending.questions.length) + return false; + return answers.every((answer, index) => { + const question = pending.questions[index]; + if (answer.id !== question.id) + return false; + if (new Set(answer.selected).size !== answer.selected.length) + return false; + const custom = answer.custom?.trim(); + if (custom !== undefined && custom === '') + return false; + if (question.multiSelect !== true) { + if (custom !== undefined && answer.selected.length > 0) + return false; + if (answer.selected.length > 1) + return false; + } + const labels = new Set(question.options?.map(option => option.label) ?? []); + return answer.selected.every(label => labels.has(label)); + }); +} +/** + * Compute the render intent for a tool/call or tool/result event through the + * presenters registered at this moment; every other event type gets none. A + * result's presenter needs its call's parsed args — `argsFor` supplies them + * (live: the per-session call table; history: an in-page backscan), returning + * undefined when the pairing is unavailable (e.g. the call fell off the page), + * which soft-falls to no view. Presenter or JSON.parse throws also soft-fall: + * the client's documented default (generic JSON card) covers every miss. + */ +function viewFor(ctx, event, argsFor, +// Presenters live with the definitions, and definitions live in the scope +// chain: a preset registers its tools into its standing layer. A live agent +// is a scope whose chain passes through its preset; a cold read passes the +// preset's standing key directly — no agent, no resume. An undefined scope +// sees only the global layer, which is the pre-preset deployment shape. +scope) { + try { + if (event.type === 'tool/call') { + const { name, arguments: raw } = event.data; + const view = ctx.tools.get(name, scope)?.presentCall?.(JSON.parse(raw)); + return view === undefined ? undefined : { for: 'call', view }; + } + if (event.type === 'tool/result') { + const { message, meta } = event.data; + const [result] = message.content; + const callId = message.source.callId; + const call = argsFor(callId); + if (call === undefined) + return undefined; + const view = ctx.tools.get(call.name, scope)?.presentResult?.(call.args, { + content: result.content, + isError: result.isError === true, + ...meta === undefined ? {} : { meta }, + }); + return view === undefined ? undefined : { for: 'result', view }; + } + } + catch (error) { + // A throwing presenter (or unparseable arguments) must not break delivery; + // the event still ships, just without a view. + console.error(`api-proxy: presenter failed for ${event.type}, falling back to generic: ${String(error)}`); + } + return undefined; +} +/** + * Resolve a tool/result's call pairing by scanning a window of events backwards + * for the matching tool/call. Used by the history path (the page is the + * window — a cross-page pairing soft-falls to no view) and by live-path table + * misses after a reconnect-eviction. + */ +function backscanArgs(events, callId) { + for (let i = events.length - 1; i >= 0; i--) { + const event = events[i]; + if (event.type !== 'tool/call') + continue; + const data = event.data; + if (data.callId !== callId) + continue; + try { + return { name: data.name, args: JSON.parse(data.arguments) }; + } + catch { + // Unparseable stored arguments: same soft-fall as a live parse failure. + return undefined; + } + } + return undefined; +} +/** Render one detached history page through the same presenter path as ordinary history. */ +function historyPage(ctx, events, beforeSeq, maxMessages, scope) { + const page = paginate(events, beforeSeq, maxMessages ?? DEFAULT_MAX_MESSAGES); + return { + events: page.events.map((event) => { + const view = viewFor(ctx, event, callId => backscanArgs(page.events, callId), scope); + return { event, ...view === undefined ? {} : { view } }; + }), + hasMore: page.hasMore, + }; +} +function projectionsFor(ctx, session) { + const registry = ctx.get('sessionProjections'); + if (registry === undefined) + return undefined; + return registry.snapshot(session); +} +/** + * The projection baseline of one session.list row, fail-soft: attached + * sessions cut the registry's live watermark cache; cold sessions view the + * persisted projection cache's identity-checked stored rows (zero log loads + * either way — the listing use case the cache exists for). The block shape + * (values + asOfSeq) matches the history tail's, so a client seeds its + * value store under the same higher-seq-wins rule. Any failure — and an + * empty value set — yields an absent block: a listing without projections + * is degraded, never broken. + */ +function listProjectionsFor(ctx, meta, session) { + try { + const block = session !== undefined + ? ctx.get('sessionProjections')?.snapshot(session) + : ctx.get('sessionProjectionCache')?.cachedSnapshot(meta); + return block !== undefined && Object.keys(block.values).length > 0 ? block : undefined; + } + catch (error) { + ctx.logger.warn(`session.list: projection column for "${meta.id}" failed (serving the row without it): ${String(error)}`); + return undefined; + } +} +/** Projection baseline for a detached history tail without Agent activation. */ +function detachedProjectionsFor(ctx, events) { + const registry = ctx.get('sessionProjections'); + if (registry === undefined) + return undefined; + return registry.restore({}, events, 0).snapshot; +} +/** + * Best-effort projections for one subagent history page, fail-soft like + * {@link listProjectionsFor}: a registered unit throwing on a corrupt payload + * never blocks transcript reading — the page is served without the block. + * @param ctx - context carrying the logger for the degradation warning. + * @param childSessionId - the child whose page is being decorated. + * @param compute - the arm-specific fold (live watermark or detached restore). + * @returns the projections block, or undefined when the fold failed. + */ +function subagentHistoryProjections(ctx, childSessionId, compute) { + try { + return compute(); + } + catch (error) { + ctx.logger.warn(`subagent.history: projections for "${childSessionId}" failed (serving the page without them): ${String(error)}`); + return undefined; + } +} +/** Map continuation admission failures without exposing provider details. */ +function subagentPromptError(request, error, signal) { + const childSessionId = request.payload.childSessionId; + if (signal.aborted) { + return err(request, { code: 'cancelled', message: 'subagent prompt was cancelled', details: {} }); + } + if (error instanceof SubagentError) { + switch (error.code) { + case 'NOT_RESUMABLE': + return err(request, { + code: 'subagent-not-resumable', + message: 'subagent cannot be resumed', + details: { childSessionId }, + }); + case 'UNAUTHORIZED': + return err(request, { + code: 'subagent-unauthorized', + message: 'subagent does not belong to this parent', + details: { childSessionId }, + }); + case 'DRAINING': + case 'ACTIVATION_CLOSING': + case 'CONTINUATION_UNAVAILABLE': + case 'PERSISTENCE_UNAVAILABLE': + return err(request, { + code: 'subagent-delivery-unavailable', + message: 'subagent follow-up is temporarily unavailable', + details: { childSessionId }, + }); + default: + break; + } + } + return err(request, { code: 'internal', message: 'subagent prompt failed', details: {} }); +} +/** Stable RPC face of the missing projections capability, shared by every catalog read path. */ +function projectionsUnavailableError() { + return { + code: 'internal', + message: 'subagent catalog is unavailable: this deployment does not mount the sessionProjections registry (load @deepseek-ai/dsh-session-projection)', + details: {}, + }; +} +/** Verify one address and mode against the complete direct-child catalog. */ +async function catalogChild(ctx, address, signal) { + const { parentSessionId, childSessionId, mode } = address; + try { + const entries = await ctx.subagents.listChildren(parentSessionId, signal); + const entry = entries.find(candidate => candidate.id === childSessionId); + if (entry === undefined || (entry.kind === 'child' && entry.mode !== mode)) { + return { + error: { + code: 'subagent-not-found', + message: `session "${childSessionId}" is not a ${mode} direct child of "${parentSessionId}"`, + details: { parentSessionId, childSessionId }, + }, + }; + } + if (entry.kind === 'diagnostic') { + return { + error: { + code: 'subagent-catalog-diagnostic', + message: `subagent "${childSessionId}" is ${entry.reason}`, + details: { parentSessionId, childSessionId, reason: entry.reason }, + }, + }; + } + return { entry }; + } + catch (error) { + if (signal?.aborted || (error instanceof SubagentError && error.code === 'CANCELLED')) { + return { error: { code: 'cancelled', message: 'subagent catalog read was cancelled', details: {} } }; + } + if (error instanceof SubagentError && error.code === 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE') { + return { error: projectionsUnavailableError() }; + } + return { error: { code: 'internal', message: 'subagent catalog read failed', details: {} } }; + } +} +/** + * The requested preset differs from the one this session already runs. + * + * A session's composition is fixed at creation: its history was produced under + * that preset's tools, so adopting the identity under a different one would + * replay tool calls the rebuilt agent cannot make. Naming a different preset + * is therefore a caller error rather than a switch. + */ +/** The roster is absent: this deployment composes no agent presets at all. */ +function noRoster(agentPreset) { + return { + code: 'agent-preset-not-found', + message: 'this deployment composes no agent presets', + details: { agentPreset, available: [] }, + }; +} +/** Map one authoring/roster failure onto its wire code. */ +function presetError(agentPreset, error) { + if (error instanceof UnknownPresetError) { + return { + code: 'agent-preset-not-found', + message: error.message, + details: { agentPreset: error.presetId, available: [...error.available] }, + }; + } + if (error instanceof PresetNotWritableError) { + return { code: 'agent-preset-read-only', message: error.message, details: { agentPreset, reason: error.message } }; + } + if (error instanceof InvalidPresetIdError || error instanceof PresetExistsError) { + return { code: 'agent-preset-invalid', message: error.message, details: { agentPreset, reason: error.message } }; + } + return { code: 'internal', message: `agent preset "${agentPreset}": ${String(error)}`, details: {} }; +} +class AgentPresetConflict extends Error { + sessionId; + requestedPreset; + existingPreset; + constructor(sessionId, requestedPreset, existingPreset) { + super(existingPreset === undefined + ? `session "${sessionId}" records no agent preset, so it cannot be adopted under one; ` + + 'a deployment composing no roster records none on any session — ' + : `session "${sessionId}" already runs agent preset ${JSON.stringify(existingPreset)}; ` + + `requested ${JSON.stringify(requestedPreset)}. A session's preset is fixed at creation.`); + this.sessionId = sessionId; + this.requestedPreset = requestedPreset; + this.existingPreset = existingPreset; + } +} +/** Requested identity already belongs to a session with another project cwd. */ +class SessionCwdConflict extends Error { + sessionId; + requestedCwd; + existingCwd; + constructor(sessionId, requestedCwd, existingCwd) { + super(`session "${sessionId}" already exists with cwd ${JSON.stringify(existingCwd)}; ` + + `requested ${JSON.stringify(requestedCwd)}`); + this.sessionId = sessionId; + this.requestedCwd = requestedCwd; + this.existingCwd = existingCwd; + } +} +/** An explicit Host naming operation would duplicate another Workspace title. */ +class WorkspaceNameConflictError extends Error { + workspaceName; + constructor(workspaceName) { + super(`workspace name '${workspaceName}' is already in use`); + this.workspaceName = workspaceName; + this.name = 'WorkspaceNameConflictError'; + } +} +/** Shared workspace-not-found error response of the workspace.* mutation rows. */ +function workspaceNotFound(request, workspaceId) { + return err(request, { + code: 'workspace-not-found', + message: `workspace "${workspaceId}" not found`, + details: { workspaceId }, + }); +} +/** Wire projection of one workspace entity (the workspace.* value row). */ +function workspaceView(workspace) { + return { + workspaceId: workspace.id, + path: workspace.path, + title: workspace.title, + sessionIds: [...workspace.sessionIds], + createdAt: workspace.createdAt, + updatedAt: workspace.updatedAt, + }; +} +/** Wire projection of the durable record carried by `domain/changed`. */ +function changedWorkspaceView(workspaceId, value) { + const record = workspaceRecord.parse(value); + return { + workspaceId: workspaceId, + path: record.path, + title: record.title, + sessionIds: [...record.sessionIds], + createdAt: record.createdAt, + updatedAt: record.updatedAt, + }; +} +/** + * Implement ApiProxy over a composed host context. + * @param ctx - a context with the Host spine and Workspace registry mounted. + * @param defaults - host routing and project-directory defaults. + * @returns the ApiProxy implementation. + */ +export function createApiProxy(ctx, defaults) { + const sessionExportCompressionLevel = defaults.sessionExportCompressionLevel + ?? DEFAULT_SESSION_LOG_COMPRESSION_LEVEL; + const coldBlankProbeMaxBytes = defaults.coldBlankProbeMaxBytes + ?? DEFAULT_COLD_BLANK_PROBE_MAX_BYTES; + /** The seed model each create/resume declares; re-read so it never goes stale. */ + const agentOptions = () => { + const { provider, model } = defaults.defaultModelSelection(); + return { provider, model }; + }; + const selections = new WeakMap(); + /** + * Serializes `agentPreset.select` per session. Two concurrent selects both + * pass the blank check, and the second `unmountPresetFor` then finds nothing + * to unmount because the first already removed the record — leaving two + * compositions registered into one agent layer. The client's `busy` flag is + * not enforcement: the wire is reachable directly. + */ + const presetSwitches = new Map(); + /** Client-chosen identity creation/resume, deduplicated across concurrent retries. */ + const sessionCreations = new Map(); + /** Serializes path ownership and explicit title checks with Workspace mutations. */ + let workspaceCreationChain = Promise.resolve(); + const pendingQuestions = new Map(); + const pendingApprovals = new Map(); + const muxQueues = new Set(); + const imageAdmissionChains = new WeakMap(); + /** Serialize image admission with model selection for one agent. */ + function serializeImageAdmission(agent, operation) { + const result = (imageAdmissionChains.get(agent) ?? Promise.resolve()).then(operation); + imageAdmissionChains.set(agent, result.then(() => undefined, () => undefined)); + return result; + } + /** + * Install or return the session-local model selection that prompt assembly snapshots. + * + * Precedence, resolved on EVERY read rather than seeded once: a selection + * made in this process, else the session's own latest logged request/header, + * else the live Agent default. Re-reading keeps the two tiers exact in both + * directions: a session with a recorded request derives its selection from + * its log, while a blank session (New Session reuses one rather than minting + * another) reads any default saved after it was created. There is no create-time + * per-session override tier on this wire — if one returns (a create-options + * contribution), it must fold in between the selection and the log. + */ + function selectionFor(agent) { + const installed = selections.get(agent); + if (installed !== undefined) + return installed; + let picked; + const selection = { + get current() { + if (picked !== undefined) + return picked; + // Incrementally folded by the session, so a per-step read costs + // O(new events) rather than a rescan. + const logged = agent.session.requestHeader()?.config; + if (logged === undefined) + return defaults.defaultModelSelection(); + return { + provider: logged.provider, + model: logged.model, + ...logged.reasoningEffort === undefined + ? {} + : { reasoningEffort: logged.reasoningEffort }, + }; + }, + set current(next) { + picked = next; + }, + assembled: undefined, + }; + installModelSelection(agent.ctx, selection); + selections.set(agent, selection); + return selection; + } + /** Pre-publication setup used by both fresh and resumed Web agents. */ + function installSelection(agentCtx) { + const agent = agentCtx.agent; + if (agent === undefined) + throw new Error('api-proxy: agent setup has no scoped agent'); + selectionFor(agent); + } + /** + * Reject an attempt to run an existing session under a different preset. + * + * A caller that names no preset always adopts the session as it is, so the + * common paths — reconnecting, resuming, retrying a create — are unaffected. + * @param sessionId - the identity being adopted. + * @param requested - the preset the request named, if any. + * @param existing - the preset the session RUNS, if any; both callers resolve + * it from the log, which differs from the creation header once a blank + * session has switched. + * @throws when both are present and differ. + */ + function assertPresetUnchanged(sessionId, requested, existing) { + if (requested === undefined || requested === existing) + return; + throw new AgentPresetConflict(sessionId, requested, existing); + } + /** + * Resolve the preset an agent will be composed from, and the setup that + * installs it. + * + * The id is resolved BEFORE the session exists because the session boundary + * snapshots `meta` before asynchronous setup begins — a preset discovered + * during setup could never reach the header. Mounting still happens in + * setup, where a failure rolls the whole creation back rather than leaving a + * published session whose capabilities are half-installed. + * + * A deployment with no preset roster composes nothing and every session + * shares the host composition, which is the behavior before presets existed. + * @param presetId - the requested preset, or `undefined` for the default. + * @returns the id to record on the header (absent without a roster) and the setup callback. + * @throws when the roster supplies no such preset. + */ + async function composeAgent(presetId) { + const presets = ctx.get('agentPresets'); + if (presets === undefined) { + return { + setup: (agentCtx) => { + installSelection(agentCtx); + return Promise.resolve(); + }, + }; + } + const resolvedId = (await presets.resolve(presetId)).id; + return { + agentPreset: resolvedId, + setup: async (agentCtx) => { + installSelection(agentCtx); + await presets.mount(agentCtx, resolvedId); + }, + }; + } + const hasSubagentOwner = (session, agent) => hasApiRemoteSubagentOwner(ctx, session, agent); + const subagentOwnershipError = (sessionId) => apiRemoteSubagentOwnershipError(sessionId); + const inspectServable = (sessionId) => inspectApiRemoteSession(ctx, sessionId); + // Cold resume composes the preset the session recorded, for the same reason + // `session.create` does: its history was produced under that composition. + // Every generic entry point — prompt, models, commands — arrives here, so + // leaving it out meant a session opened after a restart ran on host tools + // and the deployment persona. Resolved from the LOG, not the header: a + // session that switched while blank ran its turns under the newer + // composition, and the header is written once at creation. Reading the + // header here would silently undo the switch on the next restart and + // restore that history under the old tool set. + const agentFor = createApiRemoteAgentResolver(ctx, { + agentOptions, + setup: async ({ meta, events }) => (await composeAgent(resolveSessionPreset({ header: meta, events }))).setup, + }); + /** Send one transient frame to every connected mux consumer. */ + function broadcast(payload) { + const envelope = frame(payload); + for (const queue of muxQueues) + queue.push(envelope); + } + // Projection change feed → session/projection push frames. The carrier + // mints the wire frame (the Service Definition package holds no wire vocabulary); the + // child activates only when a projection registry is composed, and the + // subscription unwinds with this gateway's fiber. + ctx.inject(['sessionProjections'], (projectionCtx) => { + projectionCtx.sessionProjections.onChanged((session, key, value, seq) => { + broadcast({ type: 'session/projection', sessionId: session.id, key, value, seq }); + }); + }); + // The cache supplies recency and a monotonic non-blank hint. A cached + // `blank: true` remains only a prefix fact and is verified on the cold path. + ctx.inject(['sessionProjections'], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: 'sessionListMetadata', + schema: sessionListMetadataProjectionSchema, + init: () => ({ blank: true, lastPromptAt: null }), + apply: applySessionListMetadata, + view: state => state, + stateVersion: 1, + }); + }); + // The imageLimits projection unit: the attachments config this proxy + // enforces at prompt admission, constant per host boot. `apply` keeps the + // same state reference for every event, so no change frames are ever + // pushed — baselines alone carry the value — and clients pre-check intake + // and label upload affordances from it. Registered here, not in the + // attachment Service Definition: dsh-llm depends on dsh-attachment, so the + // seam package cannot reference the projection registry without a cycle, + // and the per-message rules the value describes are this proxy's own + // admission checks. The child activates only while both seams are composed. + // `view` reading the live service instead of the (null) state is sanctioned + // exactly for boot-constant units: the value cannot change within a process + // lifetime, so the fold stays observationally pure, and a stale persisted + // cache row re-viewing to the current config is the correct outcome. + ctx.inject(['sessionProjections', 'attachments'], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: 'imageLimits', + schema: imageLimitsProjectionSchema, + init: () => null, + apply: state => state, + view: () => projectionCtx.attachments.imageLimits, + stateVersion: 1, + }); + }); + /** Project both durable inbox lists, optionally including the splice currently being emitted. */ + const queueItems = (agent, splice) => { + const project = (target) => { + const messages = target === 'next-turn' ? agent.inbox.nextTurn : agent.inbox.nextStep; + return splice?.target === target + ? messages.toSpliced(splice.start, splice.removedCount ?? 0, ...splice.inserted) + : messages; + }; + return [ + ...project('next-turn').map(message => ({ id: message.id, placement: 'queued', message })), + ...project('next-step').map(message => ({ + id: message.id, + // Only user-origin messages are steering; injected context (approval + // notices, task completion, attached snapshots) is not a user action + // and must not render as a pending steering bubble. + placement: message.source.kind === 'user' ? 'steering' : 'context', + message, + })), + ]; + }; + ctx.on('session/event', (session, event) => { + if (event.type !== 'agent/inbox/spliced') + return; + const agent = ctx.agents.get(session.id); + if (agent?.session !== session) + return; + broadcast({ type: 'session/queue', sessionId: session.id, items: queueItems(agent, event.data) }); + }); + /** Remove a wait before settling it: synchronous deletion makes the first claimant win. */ + function claimQuestion(pending, outcome) { + pendingQuestions.delete(pending.rpcId); + if (pending.signal !== undefined && pending.onAbort !== undefined) { + pending.signal.removeEventListener('abort', pending.onAbort); + } + broadcast({ + type: 'question/resolved', sessionId: pending.sessionId, + questionRpcId: pending.rpcId, outcome, + }); + } + const disposeProvider = ctx.userQuestions.registerProvider({ + ask(request) { + const sessionId = request.agent?.id; + if (sessionId === undefined) { + return Promise.reject(new UserQuestionError('web user interaction requires an agent-owned session', 'ASK_MISSING_AGENT')); + } + return new Promise((resolve, reject) => { + const rpcId = RpcId(randomUUID()); + const pending = { + rpcId, sessionId, questions: request.questions, resolve, reject, + ...(request.signal === undefined ? {} : { signal: request.signal }), + }; + const onAbort = () => { + claimQuestion(pending, 'cancelled'); + reject(new UserQuestionError('ask_user_question was aborted before the user answered', 'ASK_ABORTED')); + }; + pending.onAbort = onAbort; + pendingQuestions.set(rpcId, pending); + request.signal?.addEventListener('abort', onAbort, { once: true }); + const envelope = { + rpcId, + payload: { type: 'question/requested', sessionId, questions: request.questions }, + }; + for (const queue of muxQueues) + queue.push(envelope); + }); + }, + }); + ctx.effect(() => () => { + disposeProvider(); + for (const pending of [...pendingQuestions.values()]) { + claimQuestion(pending, 'cancelled'); + pending.reject(new UserQuestionError('web user-questions provider was disposed', 'ASK_ABORTED')); + } + }, 'api-proxy: user-questions provider'); + // --- Approval pending registry ------------------------------------------ + // The proxy is the approval channel for every agent this host owns: an ask + // through `ctx.approval` becomes an answerable server-request on the mux + // stream (stable rpcId), settled by POST /api/respond. The entry survives + // client disconnects — mux-open replays still-pending requested frames with + // the same rpcId (the refresh-recovery baseline) — and withdraws on the + // ask's own abort signal (turn cancel), pushing `cancelled` to subscribers. + if (ctx.get('approval') !== undefined) { + // Teardown parity with the question provider above: a gateway disposed + // while approvals are pending settles every entry as 'cancelled' (the + // service's fail-closed vocabulary), so no ask promise dangles past the + // proxy's lifetime and subscribers see the withdrawal. + ctx.effect(() => () => { + for (const pending of [...pendingApprovals.values()]) + pending.resolve('cancelled'); + }, 'api-proxy: approval registry teardown'); + ctx.on('approval/request', (req, next) => { + // Dispatch rides a microtask behind the service's own signal check: an + // abort landing in that window would register the abort listener AFTER + // the signal fired — never invoked, entry pending forever, zombie frame + // on every mux replay. Settle synchronously instead of publishing. + if (req.signal?.aborted === true) + return Promise.resolve('cancelled'); + // The audit pair `approval/asked` is already appended by the service + // before dispatch, but dispatch rides a microtask: parallel tool calls + // can append several asked events before any answerer runs. THIS + // request's event is therefore the newest asked event that is still + // undecided, unclaimed by another pending entry, and — when the ask + // names a call — carries the same callId. + const events = req.agent.session.events; + const claimed = new Set(); + for (const entry of pendingApprovals.values()) + claimed.add(entry.approvalId); + const decided = new Set(); + let approvalId; + for (let i = events.length - 1; i >= 0; i -= 1) { + const event = events[i]; + if (event.type === 'approval/decided') { + decided.add(event.data.id); + } + else if (event.type === 'approval/asked') { + if (decided.has(event.data.id) || claimed.has(event.data.id)) + continue; + // Symmetric pairing: a callId-bearing ask only takes its own call's + // record, and a callId-less ask only takes a callId-less record — + // so neither shape can steal the other's audit id under parallel + // asks. (Today every producer — the tool executor — passes callId; + // the callId-less arm guards any future non-tool asker.) + if ((req.callId ?? null) !== (event.data.callId ?? null)) + continue; + approvalId = event.data.id; + break; + } + } + // No asked event means the request bypassed the service's audit path — + // not this channel's question; delegate to the fail-closed default. + if (approvalId === undefined) + return next(); + const id = approvalId; + return new Promise((resolve) => { + const settle = (outcome) => { + /* v8 ignore next 3 -- defensive double-settle guard: respond() routes + through the pending table (a settled id is not-pending before it can + re-settle) and the first settle removes the abort listener, so no + reachable path settles twice; kept against future settle callers. */ + if (!pendingApprovals.delete(pending.rpcId)) + return; + req.signal?.removeEventListener('abort', onAbort); + broadcast({ type: 'approval/resolved', sessionId: pending.sessionId, approvalId: id, outcome }); + // A cancelled ask was already settled by the service's own signal + // race, which discards this late resolution; resolving is a no-op + // there and keeps this promise from dangling forever. + resolve(outcome); + }; + const onAbort = () => { settle('cancelled'); }; + const pending = { + rpcId: RpcId(randomUUID()), + sessionId: req.agent.session.id, + approvalId: id, + toolName: req.toolName, + ...req.callId === undefined ? {} : { callId: req.callId }, + ...req.reason === undefined ? {} : { reason: req.reason }, + resolve: settle, + }; + pendingApprovals.set(pending.rpcId, pending); + req.signal?.addEventListener('abort', onAbort, { once: true }); + const envelope = requestedFrame(pending); + for (const queue of muxQueues) + queue.push(envelope); + }); + }); + } + /** Read one stable session prefix without acquiring an Agent owner. */ + async function readSessionState(sessionId) { + const attached = ctx.sessions.get(sessionId); + if (attached !== undefined) { + return { + id: attached.id, + header: attached.header, + events: [...attached.events], + }; + } + const inspected = await inspectServable(sessionId); + return { id: inspected.meta.id, header: inspected.meta, events: inspected.events }; + } + /** Resolve the Workspace inherited by a fork without making ordinary loose lineage grouped. */ + async function forkWorkspace(source) { + const workspaces = ctx.workspaceRegistry.list(); + const direct = workspaces.find(workspace => workspace.sessionIds.includes(source.id)); + if (direct !== undefined || source.header.origin !== 'subagent') + return direct; + const lineage = await ctx.sessionQuery.traceSession(source.id); + for (const ancestor of lineage.ancestors) { + const workspace = workspaces.find(candidate => candidate.sessionIds.includes(ancestor.header.id)); + if (workspace !== undefined) + return workspace; + } + return undefined; + } + /** + * Resolve which session one transcript read is served from, without + * acquiring an Agent owner. This is the read's only asynchronous step + * besides ensuring the composition; {@link historyCutOf} takes the cut. + * @param sessionId - the transcript being read. + * @returns the attached session, or the inspected detached header and events. + * @throws {@link ApiRemoteSessionNotFound} when no project-backed session has that identity. + */ + async function historySourceFor(sessionId) { + const attached = ctx.sessions.get(sessionId); + if (attached !== undefined) + return { kind: 'attached', session: attached }; + const inspected = await inspectServable(sessionId); + return { kind: 'detached', header: inspected.meta, events: inspected.events }; + } + /** + * The header and events {@link presenterScopeFor} reads to decide which + * composition a transcript ran under. + * @param source - the live or detached session this read is served from. + * @returns that session's creation header and its events. + */ + function sourceSession(source) { + if (source.kind === 'detached') + return { header: source.header, events: source.events }; + return { header: source.session.header, events: source.session.events }; + } + /** + * One transcript cut: the events and the projection baseline that describe + * the SAME log position. + * + * Synchronous, and the two reads sit next to each other, because an attached + * session keeps appending: an `await` between them would serve events cut at + * N beside a baseline folded to N+1, which is one response describing two + * moments. The caller does its awaiting before this call. + * @param source - the live or detached session this read is served from. + * @param includeProjections - whether the caller asked for the baseline (a tail page does). + * @returns the events and, when asked, the baseline for that same position. + */ + function historyCutOf(source, includeProjections) { + if (source.kind === 'detached') { + const projections = includeProjections ? detachedProjectionsFor(ctx, source.events) : undefined; + return { events: source.events, ...projections === undefined ? {} : { projections } }; + } + const events = [...source.session.events]; + const projections = includeProjections ? projectionsFor(ctx, source.session) : undefined; + return { events, ...projections === undefined ? {} : { projections } }; + } + /** + * The registry view scope a transcript's presenters resolve in. + * + * A live agent is that scope itself (its chain passes through its preset's + * standing layer). A cold session resolves its preset from the LOG, and the + * preset's STANDING key serves without resuming anything — ensuring the + * mount composes plugins but starts no agent, session, or turn. No roster, + * no recorded preset, or a preset the roster no longer supplies all fall + * back to the global layer: the transcript still serves, with the generic + * cards a viewless entry renders. + * + * Reading the header alone would render a session that switched while blank + * through the composition it was CREATED with. Every tool only the newer + * preset registers resolves to no presenter there, and the transcript + * silently degrades to generic cards for exactly the calls its history is + * made of. + * @param sessionId - the transcript being read. + * @param session - that session's header and log (attached or inspected). + * @returns the scope to pass to presenter lookups, or undefined for global. + */ + async function presenterScopeFor(sessionId, session) { + const live = ctx.get('agents')?.get(sessionId); + if (live !== undefined) + return live; + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return undefined; + try { + // An unrecorded preset (a log from before the roster existed) renders + // through the DEFAULT preset's standing layer: that is the composition + // an unnamed session composes today, and presenters are pure display, + // so the worst a mismatch produces is the generic card it had anyway. + return await presets.standingKeyFor(resolveSessionPreset(session)); + } + catch { + // Swallows only the unknown/unusable-preset rejection from the roster: + // a deleted or broken preset must degrade this read, never fail it. + return undefined; + } + } + /** Resolve one requested identity to a live agent, creating or resuming it once. */ + async function ensureSession(sessionId, cwd, checkPersistedIdentity, presetId) { + let creation = sessionCreations.get(sessionId); + if (creation === undefined) { + creation = (async () => { + const attached = ctx.sessions.get(sessionId); + const live = ctx.agents.get(sessionId); + if (attached !== undefined && hasSubagentOwner(attached, live)) { + throw new SubagentSessionOwnership(sessionId); + } + if (live !== undefined) + return live; + const persistence = checkPersistedIdentity ? ctx.get('sessionPersistence') : undefined; + const stored = persistence === undefined + ? undefined + : (await persistence.list()).find(header => header.id === sessionId); + if (persistence !== undefined && stored !== undefined) { + const inspected = await persistence.inspect(sessionId); + // Ownership first: explicit-id adoption of a session-backed + // subagent must answer `agent-busy` regardless of the requested + // cwd (the api/commands.ts contract), not a cwd conflict. + if (hasSubagentOwner({ header: inspected.meta }, undefined)) { + throw new SubagentSessionOwnership(sessionId); + } + if (inspected.meta.cwd !== cwd) { + throw new SessionCwdConflict(sessionId, cwd, inspected.meta.cwd); + } + // Resolved from the log, not the header: a session that switched + // while blank ran every turn under the newer composition. + const storedPreset = resolveSessionPreset({ header: inspected.meta, events: inspected.events }); + assertPresetUnchanged(sessionId, presetId, storedPreset); + // The stored preset wins over anything the request names: a resumed + // session's history was produced under that composition, and + // rebuilding it differently would replay tool calls the model can no + // longer make. + return (await ctx.agents.resume({ + resumeSessionId: sessionId, + agentOptions: agentOptions(), + setup: (await composeAgent(storedPreset)).setup, + })).agent; + } + try { + await mkdir(cwd, { recursive: true }); + } + catch (error) { + throw new Error(`failed to ensure project directory "${cwd}": ${String(error)}`, { cause: error }); + } + const composition = await composeAgent(presetId); + return (await ctx.agents.create({ + sessionId, + agentOptions: agentOptions(), + meta: { + cwd, + ...composition.agentPreset === undefined ? {} : { agentPreset: composition.agentPreset }, + }, + setup: composition.setup, + })).agent; + })().catch((error) => { + // Another Host entry path may have published the same identity while + // this operation crossed an asynchronous persistence/filesystem step. + const live = ctx.agents.get(sessionId); + if (live !== undefined) { + if (hasSubagentOwner(live.session, live)) + throw new SubagentSessionOwnership(sessionId); + return live; + } + const attached = ctx.sessions.get(sessionId); + if (attached !== undefined && hasSubagentOwner(attached, undefined)) { + throw new SubagentSessionOwnership(sessionId); + } + throw error; + }).finally(() => { + sessionCreations.delete(sessionId); + }); + sessionCreations.set(sessionId, creation); + } + const agent = await creation; + if (hasSubagentOwner(agent.session, agent)) + throw new SubagentSessionOwnership(sessionId); + // Beside the cwd check for the same reason, and after the await so it + // covers every path that yields a live agent — freshly created, adopted + // live, resumed from disk, or recovered by the concurrent-creation catch. + assertPresetUnchanged(sessionId, presetId, resolveSessionPreset(agent.session)); + if (agent.session.header.cwd !== cwd) { + throw new SessionCwdConflict(sessionId, cwd, agent.session.header.cwd); + } + return agent; + } + /** Resolve or create one path while holding the Host's workspace-create chain. */ + function ensureWorkspace(path) { + const operation = workspaceCreationChain.then(async () => { + const existing = await ctx.workspaceRegistry.resolveByPath(path); + if (existing !== undefined) + return { workspace: existing, created: false }; + return { workspace: await ctx.workspaceRegistry.create(path), created: true }; + }); + workspaceCreationChain = operation.then(() => undefined, () => undefined); + return operation; + } + /** + * Build the session.list baseline shared by listing and search visibility. + * Attached sessions come from memory; servable cold sessions merge from + * persistence, and the final order is newest-first. + */ + async function listVisibleSessionSummaries(signal) { + signal?.throwIfAborted(); + const summarizeAttached = (session) => { + const agent = ctx.agents.get(session.id); + const projections = listProjectionsFor(ctx, session.header, session); + return { + ...summarize(session, agent?.status === 'running'), + ...projections === undefined ? {} : { projections }, + }; + }; + const items = ctx.sessions.list().map(summarizeAttached); + signal?.throwIfAborted(); + const attached = new Set(items.map(item => item.sessionId)); + const persistence = ctx.get('sessionPersistence'); + if (persistence !== undefined) { + const cold = (await persistence.list(signal)) + .filter(meta => !attached.has(meta.id) && meta.cwd !== undefined); + signal?.throwIfAborted(); + for (let offset = 0; offset < cold.length; offset += COLD_SUMMARY_BATCH_SIZE) { + signal?.throwIfAborted(); + const batch = cold.slice(offset, offset + COLD_SUMMARY_BATCH_SIZE); + const settled = await Promise.allSettled(batch.map(async (meta) => { + // Projection hints remain optional. Blank verification may read + // this Session's artifact only when it passes the configured size check. + const projections = listProjectionsFor(ctx, meta, undefined); + const summary = await summarizeCold(ctx, persistence, meta, projections?.values.sessionListMetadata, coldBlankProbeMaxBytes, signal); + const attachedSession = ctx.sessions.get(meta.id); + if (attachedSession !== undefined) + return summarizeAttached(attachedSession); + return { + ...summary, + ...projections === undefined ? {} : { projections }, + }; + })); + const summaries = []; + let rejected = false; + let failure; + for (const result of settled) { + if (result.status === 'fulfilled') { + summaries.push(result.value); + } + else if (!rejected) { + rejected = true; + failure = result.reason; + } + } + if (rejected) + throw failure; + signal?.throwIfAborted(); + items.push(...summaries); + } + } + items.sort((a, b) => b.updatedAt - a.updatedAt); + return items; + } + /** + * Resolve the goal service THIS agent runs. + * + * The service is per session: an agent preset mounts it behind an `isolate` + * realm, which no host context resolves. Reading it from the root would + * answer "absent" for a session whose composition mounts it — so the lookup + * is keyed by the agent, and only a deployment composing it nowhere is + * genuinely absent. + */ + function goalServiceFor(agent) { + const presets = ctx.get('agentPresets'); + const goals = presets?.serviceFor(agent, 'goals') ?? ctx.get('goals'); + if (goals === undefined) { + return { error: { code: 'internal', message: 'goal service is absent: neither this session\'s agent preset nor the host composition mounts @deepseek-ai/dsh-goal', details: {} } }; + } + return goals; + } + /** Map one goal-domain rejection to the wire error (stable GoalError codes ride in details). */ + function goalError(request, error) { + const details = error instanceof GoalError ? { goalCode: error.code } : {}; + return err(request, { code: 'internal', message: String(error), details }); + } + /** Resolve a session's agent, apply one goal mutation, and acknowledge with the new CAS ref. */ + async function mutateGoal(request, mutation) { + const found = await agentFor(request.payload.sessionId); + if ('error' in found) + return err(request, found.error); + const goals = goalServiceFor(found.agent); + if ('error' in goals) + return err(request, goals.error); + try { + const ref = mutation(goals, found.agent); + return ok(request, { ref: { id: ref.id, revision: ref.revision } }); + } + catch (error) { + return goalError(request, error); + } + } + /** + * Whether an adapter currently serves this provider, and therefore whether + * a session selecting it can start a turn. Catalog membership cannot answer + * it: an adapter may serve a model its own catalog stopped advertising, so + * a provider missing from the groups is not the same as one nothing serves. + * A composition with no llm registry at all cannot judge and says yes — + * the dispatch it would have refused fails on its own terms. + */ + function routeServed(provider) { + const llm = ctx.get('llm'); + return llm === undefined || llm.listProviders().some(entry => entry.id === provider); + } + /** + * Resolve the addressed agent for a turn-starting method and refuse when no + * adapter serves its current selection: a provider nothing serves cannot start a + * turn, and letting it try spends the whole pre-step path to fail inside + * the adapter with a message about registration. Refusing here names the + * model the session is pointed at while the draft is still in the composer. + * This is `session.prompt`'s enforcement boundary: a client that disables + * its input is an affordance, and the method stays callable regardless. + */ + async function turnAgentFor(request, sessionId) { + const found = await agentFor(sessionId); + if ('error' in found) + return { refused: err(request, found.error) }; + const agent = found.agent; + const selection = selectionFor(agent).current; + if (!routeServed(selection.provider)) { + return { + refused: err(request, { + code: 'model-unavailable', + message: `no adapter serves provider "${selection.provider}"; select a model for this session`, + details: { provider: selection.provider, model: selection.model }, + }), + }; + } + return { agent }; + } + /** Missing-service report shared by the settings domain (skills-domain stance). */ + function settingsAbsent() { + return { code: 'internal', message: 'settings service is absent: this deployment does not mount a settings provider (e.g. @deepseek-ai/dsh-settings-file) in its composition', details: {} }; + } + /** Open one Host-resolved target and map native failures onto the wire vocabulary. */ + async function openTarget(request, path, signal, open) { + try { + await open(path, signal); + return ok(request, { opened: true }); + } + catch (error) { + if (signal.aborted) { + return err(request, { + code: 'cancelled', + message: 'path open was aborted', + details: {}, + }); + } + return err(request, { + code: 'internal', + message: `path open failed: ${error instanceof Error ? error.message : String(error)}`, + details: {}, + }); + } + } + /** Open one Host-resolved path with its default application. */ + function openPath(request, path, signal) { + const open = defaults.openPath + ?? ((target, openSignal) => openNativePath(target, openSignal)); + return openTarget(request, path, signal, open); + } + /** Open one Host-resolved text document in a native editor. */ + function openTextFile(request, path, signal) { + const open = defaults.openTextFile + ?? ((target, openSignal) => openNativeTextFile(target, openSignal)); + return openTarget(request, path, signal, open); + } + /** Whether this deployment can hand a path to a native opener at all. */ + function canOpenPaths() { + if (defaults.canOpenPath !== undefined) + return defaults.canOpenPath(); + // An injected opener is by definition usable; otherwise ask the platform. + return defaults.openPath !== undefined || canOpenNativePath(); + } + /** Missing-service report shared by the credentials domain. */ + function credentialsAbsent() { + return { code: 'internal', message: 'credentials service is absent: this deployment does not mount a credential provider (e.g. @deepseek-ai/dsh-credentials-local) in its composition', details: {} }; + } + /** Map one redacted settings descriptor to its wire view. */ + function namespaceView(descriptor) { + return { + ns: String(descriptor.ns), + schema: descriptor.schema, + value: descriptor.value, + ...descriptor.base === undefined ? {} : { base: descriptor.base }, + ...descriptor.user === undefined ? {} : { user: descriptor.user }, + applies: descriptor.applies, + secrets: (descriptor.secrets ?? []).map(secret => ({ path: [...secret.path], set: secret.set })), + revision: descriptor.revision, + }; + } + /** + * Run one settings write (merge or wholesale replace) and acknowledge with + * the namespace's new redacted view. Every seam refusal — unknown or invalid + * namespace, read-only provider, schema validation, storage — becomes one + * `settings-rejected` carrying the seam's own message. + */ + async function settingsWrite(request, ns, mode, section, expectedRevision) { + const settings = ctx.get('settings'); + if (settings === undefined) + return err(request, settingsAbsent()); + const rejected = (error) => { + // A stale writer is its own outcome, not a malformed request: the client + // must re-read and re-apply rather than treat the write as invalid. + if (error instanceof SettingsConflictError) { + return err(request, { + code: 'settings-conflict', + message: error.message, + details: { ns, expected: error.expected, actual: error.actual }, + }); + } + return err(request, { + code: 'settings-rejected', + message: error instanceof Error ? error.message : String(error), + details: { ns }, + }); + }; + let branded; + try { + branded = settingsNamespace(ns); + } + catch (error) { + // A malformed name can address no registration, so it fails exactly as + // an unregistered one does. + return rejected(error); + } + try { + if (mode === 'update') + await settings.update(branded, section, expectedRevision); + else if (mode === 'replace') + await settings.replace(branded, section, expectedRevision); + else + await settings.mutate(branded, section, expectedRevision); + } + catch (error) { + return rejected(error); + } + const descriptor = settings.describe({ redactSecrets: true }).find(candidate => candidate.ns === branded); + if (descriptor === undefined) { + // The write committed but the namespace vanished before this read: only + // a concurrent registrant disposal can produce it. + return err(request, { code: 'internal', message: `settings namespace "${ns}" was disposed after the ${mode}`, details: {} }); + } + return ok(request, namespaceView(descriptor)); + } + return { + sessions: { + // Attached sessions summarize from memory; persisted-but-unattached (cold) + // sessions merge in from the persistence store so history survives restarts. + // Logs without a cwd are not served; every session records its project + // at create time. + async list(request) { + return ok(request, { items: await listVisibleSessionSummaries() }); + }, + async search(request, signal) { + const cancelled = () => err(request, { + code: 'cancelled', + message: 'session search was aborted', + details: {}, + }); + if (isAborted(signal)) + return cancelled(); + const sessionQuery = ctx.get('sessionQuery'); + if (sessionQuery === undefined) { + return err(request, { + code: 'internal', + message: 'session search is unavailable: this deployment does not mount @deepseek-ai/dsh-session-query', + details: {}, + }); + } + try { + const visible = await listVisibleSessionSummaries(signal); + if (isAborted(signal)) + return cancelled(); + if (visible.length === 0) + return ok(request, { items: [], hasMore: false }); + const visibleIds = new Set(visible.map(item => item.sessionId)); + const authorized = []; + const acceptedIds = new Set(); + const seenCursors = new Set(); + let cursor; + let providerCallCount = 0; + let providerPageLimit = SESSION_SEARCH_RESULT_LIMIT; + while (authorized.length <= SESSION_SEARCH_RESULT_LIMIT) { + if (isAborted(signal)) + return cancelled(); + if (providerCallCount >= SESSION_SEARCH_PROVIDER_CALL_LIMIT) { + throw new Error(`session search provider exceeded the ${SESSION_SEARCH_PROVIDER_CALL_LIMIT}-call work budget`); + } + providerCallCount++; + const requestedCursor = cursor; + const requestedPageLimit = providerPageLimit; + let page; + try { + page = await sessionQuery.searchSessions({ + query: request.payload.query, + eventFilters: [ + { kind: 'type', values: ['user/message', 'assistant/message'] }, + { kind: 'surface', values: ['current'] }, + ], + limit: requestedPageLimit, + ...requestedCursor === undefined ? {} : { cursor: requestedCursor }, + }, { signal }); + } + catch (error) { + if (isAborted(signal)) + return cancelled(); + if (requestedCursor === undefined + && error instanceof SessionQueryError + && error.code === 'SESSION_QUERY_INVALID_LIMIT' + && requestedPageLimit > 1) { + providerPageLimit = Math.max(1, Math.floor(requestedPageLimit / 2)); + continue; + } + if (requestedCursor !== undefined + && error instanceof SessionQueryError + && error.code === 'SESSION_QUERY_STALE_CURSOR') { + authorized.length = 0; + acceptedIds.clear(); + seenCursors.clear(); + cursor = undefined; + continue; + } + throw error; + } + if (isAborted(signal)) + return cancelled(); + const providerItemCount = page.items.length; + if (providerItemCount > requestedPageLimit) { + throw new Error(`session search provider returned ${providerItemCount} items; maximum is ${requestedPageLimit}`); + } + // Host visibility is the authorization boundary. Consume the + // provider's globally ranked results rather than binding every + // visible id into one SQLite statement, then require each hit to + // name a visible session and a current message from that same + // session before emitting its snippet. + for (const hit of page.items) { + if (authorized.length > SESSION_SEARCH_RESULT_LIMIT) + continue; + if (!visibleIds.has(hit.header.id) + || hit.bestMatch.sessionId !== hit.header.id + || hit.bestMatch.surface !== 'current' + || !MESSAGE_TYPES.has(hit.bestMatch.type) + || acceptedIds.has(hit.header.id)) + continue; + const snippet = truncateUnicodeCodePoints(hit.bestMatch.snippet, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS); + acceptedIds.add(hit.header.id); + authorized.push({ + sessionId: hit.header.id, + snippet, + }); + } + const nextCursor = page.nextCursor; + if (nextCursor !== undefined) { + if (seenCursors.has(nextCursor)) { + throw new Error('session search provider repeated a continuation cursor'); + } + seenCursors.add(nextCursor); + } + if (authorized.length > SESSION_SEARCH_RESULT_LIMIT || nextCursor === undefined) + break; + cursor = nextCursor; + } + return ok(request, { + items: authorized.slice(0, SESSION_SEARCH_RESULT_LIMIT), + hasMore: authorized.length > SESSION_SEARCH_RESULT_LIMIT, + }); + } + catch (error) { + if (isAborted(signal) + || (error instanceof SessionQueryError && error.code === 'SESSION_QUERY_ABORTED')) + return cancelled(); + // XXX: Redact provider details before exposing this gateway beyond + // its current single-user local deployment. + return err(request, { + code: 'internal', + message: `session search failed: ${String(error)}`, + details: {}, + }); + } + }, + async create(request) { + const sessionId = request.payload.sessionId ?? `session-${randomUUID()}`; + let workspace; + if (request.payload.workspaceId !== undefined) { + workspace = ctx.workspaceRegistry.get(brandWorkspaceId(request.payload.workspaceId)); + if (workspace === undefined) { + return err(request, { + code: 'workspace-not-found', + message: `workspace "${request.payload.workspaceId}" not found`, + details: { workspaceId: request.payload.workspaceId }, + }); + } + } + const cwd = workspace?.path ?? request.payload.cwd ?? defaults.cwd; + const requestedPreset = request.payload.agentPreset; + try { + await ensureSession(sessionId, cwd, request.payload.sessionId !== undefined, requestedPreset); + } + catch (error) { + if (error instanceof AgentPresetConflict) { + return err(request, { + code: 'agent-preset-conflict', + message: error.message, + details: { + sessionId: error.sessionId, + requestedPreset: error.requestedPreset, + ...error.existingPreset === undefined ? {} : { existingPreset: error.existingPreset }, + }, + }); + } + const refused = presetFailure(request, error); + if (refused !== undefined) + return refused; + if (error instanceof SessionCwdConflict) { + return err(request, { + code: 'session-conflict', + message: error.message, + details: { + sessionId: error.sessionId, + requestedCwd: error.requestedCwd, + ...error.existingCwd === undefined ? {} : { existingCwd: error.existingCwd }, + }, + }); + } + if (error instanceof SubagentSessionOwnership) { + return err(request, subagentOwnershipError(error.sessionId)); + } + return err(request, { + code: 'internal', + message: `failed to create session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + if (workspace !== undefined) { + try { + await workspace.attachSession(sessionId); + } + catch (error) { + return err(request, { + code: 'workspace-attach-failed', + message: `session "${sessionId}" was created but could not attach to workspace "${workspace.id}": ${String(error)}`, + details: { sessionId, workspaceId: workspace.id }, + }); + } + } + // Echo the composition the session RUNS so a client can label it + // without waiting for the next list refresh — the create is the commit + // point that knows it (a caller that named none gets the default). + // Resolved from the log for the same reason `sessionListFields()` is: + // this handler also adopts an already-live session, and one that + // switched while blank runs a preset its header no longer names, so + // echoing the header would contradict both the adoption this call just + // allowed and the row `session.list` serves for the same session. + const created = ctx.agents.get(sessionId); + const createdPreset = created === undefined ? undefined : resolveSessionPreset(created.session); + return ok(request, { sessionId, ...createdPreset === undefined ? {} : { agentPreset: createdPreset } }); + }, + async history(request) { + const { sessionId, beforeSeq, maxMessages } = request.payload; + try { + const source = await historySourceFor(sessionId); + // Both awaits happen BEFORE the cut. Ensuring the recorded + // composition's standing mount is what registers its projection + // units, so a first cold read would otherwise serve a baseline + // missing every preset-owned key; and an attached session keeps + // appending, so awaiting between the two reads would pair events cut + // at N with a baseline folded to N+1. + const scope = await presenterScopeFor(sessionId, sourceSession(source)); + const cut = historyCutOf(source, beforeSeq === undefined); + const page = historyPage(ctx, cut.events, beforeSeq, maxMessages, scope); + return ok(request, { + events: page.events, + hasMore: page.hasMore, + ...cut.projections === undefined ? {} : { projections: cut.projections }, + }); + } + catch (error) { + if (error instanceof SessionNotFound) { + return err(request, { code: 'session-not-found', message: error.message, details: { sessionId } }); + } + return err(request, { + code: 'internal', + message: `history unavailable for session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + }, + async models(request) { + const { sessionId } = request.payload; + const found = await agentFor(sessionId); + if ('error' in found) + return err(request, found.error); + const current = selectionFor(found.agent).current; + const { groups, failures } = await buildModelCatalog(ctx); + const routable = routeServed(current.provider); + return ok(request, { current: { ...current }, routable, groups, failures }); + }, + async selectModel(request) { + const { sessionId, provider, model, reasoningEffort } = request.payload; + const found = await agentFor(sessionId); + if ('error' in found) + return err(request, found.error); + return serializeImageAdmission(found.agent, async () => { + try { + const resolved = await ctx.llm.resolveCallConfig({ + provider, + model, + ...reasoningEffort === undefined + ? {} + : { reasoningEffort: ReasoningEffortId(reasoningEffort) }, + }); + const pendingImage = [...found.agent.inbox.nextTurn, ...found.agent.inbox.nextStep] + .some(message => contentHasImage(message.content)); + if (pendingImage || messagesHaveImage(found.agent.session.deriveMessages())) { + const info = await ctx.llm.resolveModelInfo(resolved.provider, resolved.model); + if (info.inputModalities !== undefined && !info.inputModalities.includes('image')) { + return err(request, { + code: 'model-unavailable', + message: `Model "${resolved.model}" does not accept image input, but this session already contains images; select an image-capable model.`, + details: { provider, model }, + }); + } + } + const selected = { + provider: resolved.provider, + model: resolved.model, + ...resolved.reasoningEffort === undefined + ? {} + : { reasoningEffort: resolved.reasoningEffort }, + }; + selectionFor(found.agent).current = selected; + try { + await defaults.saveDefaultModelSelection?.(selected); + } + catch (error) { + ctx.logger.warn(`api-proxy: the model switch applies to this session but was not saved as the default: ${String(error)}`); + } + return ok(request, { selected: { ...selected } }); + } + catch (error) { + return err(request, { + code: 'model-unavailable', + message: error instanceof Error ? error.message : String(error), + details: { provider, model }, + }); + } + }); + }, + async rename(request) { + const { sessionId, title } = request.payload; + const found = await agentFor(sessionId); + if ('error' in found) + return err(request, found.error); + const titles = ctx.get('sessionTitle'); + if (titles === undefined) { + return err(request, { code: 'internal', message: 'renaming is unavailable: this deployment mounts no session-title service', details: {} }); + } + try { + const accepted = titles.rename(found.agent.session, title); + return ok(request, { title: accepted.title, seq: accepted.eventSeq }); + } + catch (error) { + // Only the input's fault maps to title-invalid (the message is + // product-user-visible in the rename dialog); liveness and disposal + // races are deployment trouble, not a bad title. + if (error instanceof SessionTitleInvalidError) { + return err(request, { + code: 'title-invalid', + message: error.message, + details: { sessionId }, + }); + } + return err(request, { + code: 'internal', + message: `failed to rename session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + }, + async fork(request) { + const { sessionId, atSeq } = request.payload; + let source; + try { + source = await readSessionState(sessionId); + } + catch (error) { + if (error instanceof SessionNotFound) { + return err(request, { code: 'session-not-found', message: error.message, details: { sessionId } }); + } + return err(request, { + code: 'internal', + message: `fork source unavailable for session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + const events = source.events; + // An in-log anchor belongs to the turn containing it and must never + // clip backward to an earlier completed turn. Omitted and past-end + // anchors retain the last-completed-turn shortcut. + const lastSeq = events.at(-1)?.seq ?? -1; + const anchoredBoundary = atSeq === undefined + ? undefined + : events.find(e => e.type === 'turn/end' && e.seq >= atSeq); + const boundary = anchoredBoundary + ?? (atSeq === undefined || atSeq > lastSeq + ? events.findLast(e => e.type === 'turn/end') + : undefined); + if (boundary === undefined) { + return err(request, { + code: 'fork-unavailable', + message: atSeq !== undefined && atSeq <= lastSeq + ? `session "${sessionId}" has not completed the turn containing event ${String(atSeq)}` + : `session "${sessionId}" has no completed turn to fork from`, + details: { sessionId }, + }); + } + // Extend the cut through trailing out-of-band appends (session/title, + // injections) up to the next turn/start: they are standalone events, so + // the seed stays balanced, and the child inherits a title generated + // right after the boundary turn. + let cut = boundary.seq + 1; + while (cut < events.length && events[cut]?.type !== 'turn/start') + cut++; + let workspace; + try { + workspace = await forkWorkspace(source); + } + catch (error) { + return err(request, { + code: 'internal', + message: `failed to resolve fork workspace for session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + const childId = `session-${randomUUID()}`; + // The child inherits the parent's composition for the same reason a + // resumed session keeps its own: the seeded history was produced under + // those tools, and composing anything else would strand the tool calls + // it already carries. Now that no model-facing row sits in the host + // plane, composing nothing would leave the child with no tools at all. + const forkComposition = await composeAgent(resolveSessionPreset(source)); + try { + await ctx.agents.create({ + sessionId: childId, + seed: events.slice(0, cut), + meta: { + ...source.header.cwd === undefined ? {} : { cwd: source.header.cwd }, + parentSession: source.id, + seedLength: cut, + ...forkComposition.agentPreset === undefined + ? {} + : { agentPreset: forkComposition.agentPreset }, + }, + agentOptions: agentOptions(), + setup: forkComposition.setup, + }); + } + catch (error) { + return err(request, { + code: 'internal', + message: `failed to fork session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + // An ordinary source keeps its direct Workspace. A subagent source is + // not listed there, so its ordinary fork joins the nearest owning + // ancestor instead. The child is already published if attach fails. + if (workspace !== undefined) { + try { + await workspace.attachSession(childId); + } + catch (error) { + return err(request, { + code: 'workspace-attach-failed', + message: `session "${childId}" was forked but could not attach to workspace "${workspace.id}": ${String(error)}`, + details: { sessionId: childId, workspaceId: workspace.id }, + }); + } + } + return ok(request, { sessionId: childId }); + }, + async prompt(request) { + const { sessionId, mode, content, clientTimeZone } = request.payload; + const canonicalTimeZone = clientTimeZone === undefined + ? undefined + : canonicalClientTimeZone(clientTimeZone); + if (clientTimeZone !== undefined && canonicalTimeZone === undefined) { + return err(request, { + code: 'invalid-time-zone', + message: 'clientTimeZone must be UTC or a valid IANA Area/Location name', + details: { value: clientTimeZone }, + }); + } + const resolved = await turnAgentFor(request, sessionId); + if ('refused' in resolved) + return resolved.refused; + const agent = resolved.agent; + // Request identity and optional browser zone ride the exact durable user message. + const source = { + kind: 'user', + rpcId: request.rpcId, + ...(canonicalTimeZone === undefined ? {} : { clientTimeZone: canonicalTimeZone }), + }; + const hasImage = content.some(part => part.type === 'image'); + const admit = async () => { + try { + if (hasImage) { + const current = selectionFor(agent).current; + const modelInfo = await ctx.llm.resolveModelInfo(current.provider, current.model); + if (modelInfo.inputModalities !== undefined && !modelInfo.inputModalities.includes('image')) { + return err(request, { + code: 'attachment-error', + message: `Model "${current.model}" does not support image input.`, + details: { reason: 'MODEL_DOES_NOT_SUPPORT_IMAGES' }, + }); + } + } + const durable = await durablePromptContent(ctx, content); + const message = createUserMessage({ content: durable, source }); + if (mode === 'steer') + agent.steer(message); + else + agent.followup(message); + } + catch (error) { + if (error instanceof AttachmentError) { + return err(request, { + code: 'attachment-error', + message: error.message, + details: { reason: error.code }, + }); + } + return err(request, { + code: 'agent-busy', + message: 'prompt rejected', + details: { reason: String(error) }, + }); + } + return ok(request, { accepted: true }); + }; + return hasImage ? serializeImageAdmission(agent, admit) : admit(); + }, + async attachment(request) { + const { sessionId, attachmentId } = request.payload; + let state; + try { + state = await readSessionState(sessionId); + } + catch (error) { + if (error instanceof SessionNotFound) { + return err(request, { + code: 'session-not-found', + message: error.message, + details: { sessionId }, + }); + } + return err(request, { + code: 'internal', + message: `attachment authorization unavailable for session "${sessionId}": ${String(error)}`, + details: {}, + }); + } + const ref = referencedImage(state.events, String(attachmentId)); + if (ref === undefined) { + return err(request, { + code: 'attachment-error', + message: 'Image is not referenced by this session.', + details: { reason: 'ATTACHMENT_NOT_REFERENCED' }, + }); + } + try { + const stored = await ctx.attachments.readImage(ref); + return ok(request, { + attachment: stored.ref, + data: Buffer.from(stored.data).toString('base64'), + }); + } + catch (error) { + if (error instanceof AttachmentError) { + return err(request, { + code: 'attachment-error', + message: error.message, + details: { reason: error.code }, + }); + } + return err(request, { + code: 'internal', + message: 'Unable to read image attachment.', + details: {}, + }); + } + }, + updateQueue(request) { + const { sessionId, itemId, action } = request.payload; + if (action.kind === 'edit' && action.content.some(block => block.type !== 'text')) { + return Promise.resolve(err(request, { + code: 'attachment-error', + message: 'queue edits accept text content only', + details: { reason: 'QUEUE_EDIT_NON_TEXT' }, + })); + } + const agent = ctx.agents.get(sessionId); + if (agent !== undefined && hasSubagentOwner(agent.session, agent)) { + return Promise.resolve(err(request, subagentOwnershipError(sessionId))); + } + if (agent === undefined) { + return Promise.resolve(err(request, { + code: 'queue-item-not-found', + message: 'queued item is no longer pending', + details: { itemId }, + })); + } + const target = agent.inbox.nextTurn.some(message => message.id === itemId) + ? 'next-turn' + : agent.inbox.nextStep.some(message => message.id === itemId) ? 'next-step' : undefined; + const message = target === undefined + ? undefined + : (target === 'next-turn' ? agent.inbox.nextTurn : agent.inbox.nextStep) + .find(candidate => candidate.id === itemId); + if (target === undefined || message === undefined) { + return Promise.resolve(err(request, { + code: 'queue-item-not-found', + message: 'queued item is no longer pending', + details: { itemId }, + })); + } + if (action.kind === 'steer' && (target !== 'next-turn' || agent.status !== 'running')) { + return Promise.resolve(err(request, { + code: 'steer-unavailable', + message: 'current turn no longer accepts steering', + details: { itemId }, + })); + } + if (action.kind === 'edit') { + agent.inbox.replace(itemId, freezeMessage({ ...message, content: action.content })); + } + else { + agent.inbox.remove(itemId); + if (action.kind === 'steer') + agent.steer(message); + } + return Promise.resolve(ok(request, { accepted: true })); + }, + cancel(request) { + const { sessionId } = request.payload; + const agent = ctx.agents.get(sessionId); + if (agent === undefined) { + return Promise.resolve(err(request, { + code: 'session-not-found', + message: `session "${sessionId}" not found (not attached)`, + details: { sessionId }, + })); + } + if (hasSubagentOwner(agent.session, agent)) { + return Promise.resolve(err(request, subagentOwnershipError(sessionId))); + } + agent.cancel({ kind: 'user' }, { keepInbox: true }); + return Promise.resolve(ok(request, { accepted: true })); + }, + }, + subagents: { + async list(request, signal) { + try { + const entries = await ctx.subagents.listChildren(request.payload.parentSessionId, signal); + return ok(request, { + entries: entries.map(entry => entry.kind === 'child' + ? { + ...entry, + activity: ctx.agents.get(entry.id)?.status === 'running' ? 'running' : 'inactive', + } + : entry), + parentAvailable: ctx.agents.get(request.payload.parentSessionId) !== undefined, + }); + } + catch (error) { + if (signal?.aborted || (error instanceof SubagentError && error.code === 'CANCELLED')) { + return err(request, { + code: 'cancelled', + message: 'subagent catalog read was cancelled', + details: {}, + }); + } + if (error instanceof SubagentError && error.code === 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE') { + return err(request, projectionsUnavailableError()); + } + return err(request, { + code: 'internal', + message: 'subagent catalog read failed', + details: {}, + }); + } + }, + async history(request, signal) { + const { parentSessionId, childSessionId, mode, beforeSeq, maxMessages, } = request.payload; + const verified = await catalogChild(ctx, { + parentSessionId, childSessionId, mode, + }, signal); + if (verified.error !== undefined) + return err(request, verified.error); + // The generic-history data plane: an attached child serves its + // in-memory snapshot and the registry's live watermark projections; a + // cold child is one persistence inspection plus a detached fold. + let header; + let events; + let projections; + const attached = ctx.sessions.get(childSessionId); + if (attached !== undefined) { + header = attached.header; + events = [...attached.events]; + projections = beforeSeq === undefined + ? subagentHistoryProjections(ctx, childSessionId, () => projectionsFor(ctx, attached)) + : undefined; + } + else { + try { + const inspected = await inspectServable(childSessionId); + header = inspected.meta; + events = inspected.events; + projections = beforeSeq === undefined + ? subagentHistoryProjections(ctx, childSessionId, () => detachedProjectionsFor(ctx, inspected.events)) + : undefined; + } + catch (error) { + if (signal?.aborted) { + return err(request, { + code: 'cancelled', + message: 'subagent history read was cancelled', + details: {}, + }); + } + if (error instanceof SessionNotFound) { + return err(request, { + code: 'subagent-not-found', + message: 'subagent disappeared during history read', + details: { parentSessionId, childSessionId }, + }); + } + return err(request, { + code: 'internal', + message: 'subagent history read failed', + details: {}, + }); + } + } + if (signal?.aborted) { + return err(request, { + code: 'cancelled', + message: 'subagent history read was cancelled', + details: {}, + }); + } + if (header.parentSession !== parentSessionId) { + return err(request, { + code: 'subagent-unauthorized', + message: 'subagent parent changed during history read', + details: { childSessionId }, + }); + } + const page = historyPage(ctx, events, beforeSeq, maxMessages); + return ok(request, { ...page, ...projections === undefined ? {} : { projections } }); + }, + async prompt(request, signal) { + const { parentSessionId, childSessionId, content, clientTimeZone } = request.payload; + const canonicalTimeZone = clientTimeZone === undefined + ? undefined + : canonicalClientTimeZone(clientTimeZone); + if (clientTimeZone !== undefined && canonicalTimeZone === undefined) { + return err(request, { + code: 'invalid-time-zone', + message: 'clientTimeZone must be UTC or a valid IANA Area/Location name', + details: { value: clientTimeZone }, + }); + } + const parent = ctx.agents.get(parentSessionId); + if (parent === undefined) { + return err(request, { + code: 'subagent-parent-unavailable', + message: `parent session "${parentSessionId}" is not live`, + details: { parentSessionId }, + }); + } + const verified = await catalogChild(ctx, { + parentSessionId, childSessionId, mode: 'continuable', + }, signal); + if (verified.error !== undefined) + return err(request, verified.error); + try { + const messageId = await ctx.subagents.followup(parent, childSessionId, content, { + source: { + kind: 'user', + rpcId: request.rpcId, + ...(canonicalTimeZone === undefined ? {} : { clientTimeZone: canonicalTimeZone }), + }, + signal, + }); + return ok(request, { messageId }); + } + catch (error) { + return subagentPromptError(request, error, signal); + } + }, + // Deliberately no catalog, history, persistence, or parent Agent lookup: + // the core primitive alone authorizes the durable address against the + // live Activation, which is what keeps a live child interruptible while + // its parent Agent is offline. Absent targets are accepted no-ops there. + interrupt(request) { + const { parentSessionId, childSessionId } = request.payload; + try { + ctx.subagents.interrupt(childSessionId, { kind: 'user', parentSessionId }); + } + catch (error) { + if (error instanceof SubagentError && error.code === 'UNAUTHORIZED') { + return Promise.resolve(err(request, { + code: 'subagent-unauthorized', + message: 'subagent does not belong to this parent', + details: { childSessionId }, + })); + } + return Promise.resolve(err(request, { + code: 'internal', + message: 'subagent interrupt failed', + details: {}, + })); + } + return Promise.resolve(ok(request, { accepted: true })); + }, + }, + workspace: { + list(request) { + return Promise.resolve(ok(request, { + items: ctx.workspaceRegistry.list().map(workspaceView), + archivedSessionIds: [...ctx.workspaceRegistry.archivedSessionIds], + })); + }, + async create(request) { + const { path } = request.payload; + try { + const { workspace, created } = await ensureWorkspace(path); + return ok(request, { workspace: workspaceView(workspace), created }); + } + catch (error) { + // The registry rejects a path that does not resolve to an existing + // directory (realpath ENOENT / not-a-directory) — the business + // error of the typed-path flow, surfaced as a validation failure. + return err(request, { + code: 'workspace-invalid-path', + message: `cannot create a workspace at "${path}": ${error instanceof Error ? error.message : String(error)}`, + details: { path }, + }); + } + }, + async rename(request) { + const { payload } = request; + const workspace = ctx.workspaceRegistry.get(brandWorkspaceId(payload.workspaceId)); + if (workspace === undefined) + return workspaceNotFound(request, payload.workspaceId); + const title = payload.title.trim(); + // Uniqueness AND the same-title no-op both ride the create chain so + // they observe the state left by earlier queued renames — checked + // up front, a queued A→A could report success while an earlier A→B + // still lands afterwards. + const operation = workspaceCreationChain.then(async () => { + if (title === workspace.title) + return; + if (ctx.workspaceRegistry.list().some(other => other.id !== workspace.id && other.title === title)) { + throw new WorkspaceNameConflictError(title); + } + await workspace.setTitle(title); + }); + workspaceCreationChain = operation.then(() => undefined, () => undefined); + try { + await operation; + } + catch (error) { + if (error instanceof WorkspaceNameConflictError) { + return err(request, { + code: 'workspace-name-conflict', + message: error.message, + details: { name: error.workspaceName }, + }); + } + throw error; + } + return ok(request, { workspace: workspaceView(workspace) }); + }, + async delete(request) { + const { workspaceId } = request.payload; + const operation = workspaceCreationChain.then(() => ctx.workspaceRegistry.delete(brandWorkspaceId(workspaceId))); + workspaceCreationChain = operation.then(() => undefined, () => undefined); + if (!await operation) + return workspaceNotFound(request, workspaceId); + return ok(request, { deleted: true }); + }, + async insertBefore(request) { + const { workspaceId, beforeWorkspaceId } = request.payload; + try { + const workspaceIds = await ctx.workspaceRegistry.insertBefore(brandWorkspaceId(workspaceId), beforeWorkspaceId === undefined ? undefined : brandWorkspaceId(beforeWorkspaceId)); + return ok(request, { workspaceIds: [...workspaceIds] }); + } + catch (error) { + if (!(error instanceof WorkspaceOrderInvalidError)) + throw error; + return workspaceNotFound(request, error.workspaceId); + } + }, + async insertSessionBefore(request) { + const { payload } = request; + const workspace = ctx.workspaceRegistry.get(brandWorkspaceId(payload.workspaceId)); + if (workspace === undefined) + return workspaceNotFound(request, payload.workspaceId); + try { + await workspace.insertSessionBefore(payload.sessionId, payload.beforeSessionId); + } + catch (error) { + // Only the entity's unaccounted-id rejection is the business code; + // storage/durability failures propagate as internal errors. + if (!(error instanceof WorkspaceMoveInvalidError)) + throw error; + return err(request, { + code: 'workspace-move-invalid', + message: error.message, + details: { + workspaceId: payload.workspaceId, + sessionId: payload.sessionId, + ...payload.beforeSessionId === undefined ? {} : { beforeSessionId: payload.beforeSessionId }, + }, + }); + } + return ok(request, { workspace: workspaceView(workspace) }); + }, + async archiveSession(request) { + const { sessionId } = request.payload; + try { + await ctx.workspaceRegistry.archiveSession(sessionId); + } + catch (error) { + // Only the registry's unknown-session rejection is the business + // code; storage/durability failures propagate as internal errors. + if (!(error instanceof WorkspaceUnknownSessionError)) + throw error; + return err(request, { + code: 'session-not-found', + message: error.message, + details: { sessionId }, + }); + } + return ok(request, { archivedSessionIds: [...ctx.workspaceRegistry.archivedSessionIds] }); + }, + }, + host: { + describe(request) { + // TODO: version should read apps/cli's package.json; placeholder for now. + const selection = defaults.defaultModelSelection(); + return Promise.resolve(ok(request, { + version: '0.0.1', + // Same source as session.create's fallback: the UI's default project + // must match where an unspecified-cwd session actually lands. + cwd: defaults.cwd, + // Read live for the same reason: this is what the NEXT session will + // start from, so a saved default has to be what it reports. + provider: selection.provider, + model: selection.model, + attachedSessions: ctx.agents.list().length, + canOpenPath: canOpenPaths(), + })); + }, + async pickDirectory(request, signal) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== 'native') { + return err(request, { + code: 'directory-picker-unavailable', + message: `host.pickDirectory needs the native capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind }, + }); + } + try { + const path = await capability.pick(signal); + return ok(request, { path }); + } + catch (error) { + if (signal.aborted) { + return err(request, { + code: 'cancelled', + message: 'directory picker was aborted', + details: {}, + }); + } + return err(request, { + code: 'internal', + message: `directory picker failed: ${error instanceof Error ? error.message : String(error)}`, + details: {}, + }); + } + }, + async listDirectory(request, signal) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== 'browse') { + return err(request, { + code: 'directory-picker-unavailable', + message: `host.listDirectory needs the browse capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind }, + }); + } + try { + // The carrier's signal follows the caller: a disconnect or timeout + // stops the backend's directory scan instead of outliving it. + return ok(request, await capability.list(request.payload.path, signal)); + } + catch (error) { + // An abort is the caller's own timeout/disconnect, not a server + // failure — same code pickDirectory and command.execute report. + if (signal.aborted) { + return err(request, { code: 'cancelled', message: 'directory listing was aborted', details: {} }); + } + return err(request, directoryError(error)); + } + }, + async createDirectory(request) { + const capability = ctx.directoryPicker.capability(); + if (capability.kind !== 'browse') { + return err(request, { + code: 'directory-picker-unavailable', + message: `host.createDirectory needs the browse capability; the composed picker serves "${capability.kind}"`, + details: { capability: capability.kind }, + }); + } + try { + return ok(request, { path: await capability.createDirectory(request.payload.path, request.payload.name) }); + } + catch (error) { + return err(request, directoryError(error)); + } + }, + async openPath(request, signal) { + return openPath(request, request.payload.path, signal); + }, + }, + goals: { + // Mutations only — the read side is the 'goal' session projection. + // Every verb resolves the session's agent (agentFor: implicit cold + // resume, the command.* precedent) and acknowledges with the new CAS + // ref; the committed goal/change event carries the whole value to every + // client through the projection frames. + async create(request) { + const { objective, maxGoalRounds } = request.payload; + return mutateGoal(request, (goals, agent) => goals.create(agent, { + objective, + ...(maxGoalRounds !== undefined ? { maxGoalRounds } : {}), + })); + }, + async edit(request) { + const { ref, objective, maxGoalRounds } = request.payload; + return mutateGoal(request, (goals, agent) => goals.edit(agent, ref, { + ...(objective !== undefined ? { objective } : {}), + ...(maxGoalRounds !== undefined ? { maxGoalRounds } : {}), + })); + }, + async pause(request) { + return mutateGoal(request, (goals, agent) => goals.pause(agent, request.payload.ref)); + }, + async resume(request) { + return mutateGoal(request, (goals, agent) => goals.resume(agent, request.payload.ref)); + }, + async complete(request) { + return mutateGoal(request, (goals, agent) => goals.complete(agent, request.payload.ref)); + }, + async clear(request) { + const found = await agentFor(request.payload.sessionId); + if ('error' in found) + return err(request, found.error); + const goals = goalServiceFor(found.agent); + if ('error' in goals) + return err(request, goals.error); + try { + goals.clear(found.agent, request.payload.ref); + return ok(request, { cleared: true }); + } + catch (error) { + return goalError(request, error); + } + }, + }, + agentPresets: { + // A deployment with no roster answers with an empty list rather than an + // error: composing no presets is a valid deployment, and the browser + // simply offers no choice. + async list(request) { + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return ok(request, { presets: [], authorable: false, hasDocument: false }); + const defaultId = presets.defaultId; + return ok(request, { + presets: (await presets.list()).map(preset => ({ + id: preset.id, + trust: preset.trust, + isDefault: preset.id === defaultId, + ...preset.name === undefined ? {} : { name: preset.name }, + ...preset.description === undefined ? {} : { description: preset.description }, + ...preset.broken === undefined ? {} : { broken: preset.broken }, + })), + authorable: presets.authorable, + hasDocument: canOpenPaths(), + }); + }, + // Recomposing is limited to a blank session because a started + // conversation's history was produced under its preset's tools; the + // agent and the session survive, only the composition is swapped. + async select(request) { + const { sessionId, agentPreset } = request.payload; + const presets = ctx.get('agentPresets'); + if (presets === undefined) { + return err(request, { + code: 'agent-preset-not-found', + message: 'this deployment composes no agent presets', + details: { agentPreset, available: [] }, + }); + } + const found = await agentFor(sessionId); + if ('error' in found) + return err(request, found.error); + const { agent } = found; + const swap = async () => { + // Re-read inside the queue: an earlier switch may have run, and a + // conversation may have started, since this request arrived. + if (!sessionBlank(agent.session)) { + return err(request, { + code: 'agent-preset-locked', + message: `session "${sessionId}" has already started; its agent preset is fixed`, + details: { sessionId, agentPreset }, + }); + } + try { + const preset = await presets.recompose(agent.ctx, agentPreset); + // Recorded only after the swap committed: the log states what the + // agent runs, and a rejected mount leaves the previous composition. + agent.session.append('agent-preset/selected', { agentPreset: preset.id }); + return ok(request, { agentPreset: preset.id }); + } + catch (error) { + const refused = presetFailure(request, error); + if (refused !== undefined) + return refused; + return err(request, { + code: 'internal', + message: `failed to select agent preset "${agentPreset}": ${String(error)}`, + details: {}, + }); + } + }; + const queued = presetSwitches.get(sessionId) ?? Promise.resolve(); + const turn = queued.then(swap); + presetSwitches.set(sessionId, turn.catch(() => undefined)); + try { + return await turn; + } + finally { + if (presetSwitches.get(sessionId) === turn) + presetSwitches.delete(sessionId); + } + }, + // Authoring is privileged (see PRIVILEGED_METHODS in dsh-client-connection): + // a composition names the plugins a session runs, so reading one is + // reconnaissance, and copy/remove/openDocument manage the roster and + // drive the host desktop. + async read(request) { + const { agentPreset } = request.payload; + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return err(request, noRoster(agentPreset)); + try { + const preset = await presets.resolve(agentPreset); + return ok(request, { + agentPreset: preset.id, + trust: preset.trust, + content: await presets.read(preset.id), + ...preset.name === undefined ? {} : { name: preset.name }, + ...preset.description === undefined ? {} : { description: preset.description }, + }); + } + catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async copy(request) { + const { from, agentPreset, name } = request.payload; + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return err(request, noRoster(agentPreset)); + try { + await presets.copy(from, agentPreset, name); + return ok(request, { agentPreset }); + } + catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async openDocument(request, signal) { + const { agentPreset } = request.payload; + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return err(request, noRoster(agentPreset)); + try { + const preset = await presets.resolve(agentPreset); + // Same line as copy/remove draw: the shipped install is not the + // user's to manage, and pointing an editor into it invites edits an + // upgrade will silently overwrite. + if (preset.trust !== 'user') { + throw new PresetNotWritableError(preset.id, 'it ships with the deployment'); + } + // The id resolved against the Host's own roots is what selects the + // directory — no browser payload carries a path in either direction + // unless the deployment has no opener to hand it to. + const directory = dirname(preset.path); + if (!canOpenPaths()) + return ok(request, { opened: false, path: directory }); + return await openPath(request, directory, signal); + } + catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + async remove(request) { + const { agentPreset } = request.payload; + const presets = ctx.get('agentPresets'); + if (presets === undefined) + return err(request, noRoster(agentPreset)); + try { + await presets.remove(agentPreset); + return ok(request, {}); + } + catch (error) { + return err(request, presetError(agentPreset, error)); + } + }, + }, + skills: { + // Skill lookup never creates or resumes an agent: the session address + // resolves to a canonical cwd from the host-resident session header, and + // the view scope is the live agent or the preset's standing key. + async list(request) { + const { sessionId } = request.payload; + const session = ctx.sessions.get(sessionId); + if (session === undefined) { + return err(request, { + code: 'session-not-found', + message: `session "${sessionId}" not found (not attached)`, + details: { sessionId }, + }); + } + if (session.header.cwd === undefined) { + // Every served session records its project at create time; a + // cwd-less header is a pre-project legacy log (not served). + return err(request, { code: 'internal', message: `session "${sessionId}" has no project cwd`, details: {} }); + } + const cwd = session.header.cwd; + // The host registry is layered per scope and serves every session. A + // composition may still realm-mount its own registry instead; that + // instance is invisible to host contexts, so address it through the + // live agent (`agents.get` keeps the no-side-effect stance above). + const live = ctx.agents.get(sessionId); + const presets = ctx.get('agentPresets'); + const scoped = live === undefined ? undefined : presets?.serviceFor(live, 'skills'); + // Same stance as the commands domain: a missing service means no + // composition mounts dsh-skill, not an empty catalog. `ctx.get` also + // keeps this handler independent of the gateway plugin's inject list + // (an undeclared `ctx.skills` property read fails the reflect proxy). + const skillRegistry = scoped ?? ctx.get('skills'); + if (skillRegistry === undefined) { + return err(request, { code: 'internal', message: 'skill registry is absent: neither this session\'s agent preset nor the host composition mounts @deepseek-ai/dsh-skill', details: {} }); + } + // The scope presenters resolve in — the live agent, else the recorded + // preset's standing key, else the global layer — so a cold session's + // '/' popup lists the catalog its composition actually serves. + const scope = await presenterScopeFor(sessionId, session); + try { + const skills = (await skillRegistry.list({ cwd, scope })).filter(isUserInvocable); + return ok(request, { + skills: skills.map(skill => ({ + name: skill.name, + description: skill.description, + ...skill.whenToUse === undefined ? {} : { whenToUse: skill.whenToUse }, + modelInvocable: skill.invocation.modelInvocable, + })), + }); + } + catch (error) { + return err(request, { code: 'internal', message: `skill listing failed: ${String(error)}`, details: {} }); + } + }, + }, + settings: { + describe(request) { + const settings = ctx.get('settings'); + if (settings === undefined) + return Promise.resolve(err(request, settingsAbsent())); + return Promise.resolve(ok(request, { + writable: settings.writable, + hasDocument: settings.documentPath !== undefined, + namespaces: settings.describe({ redactSecrets: true }).map(namespaceView), + })); + }, + async openDocument(request, signal) { + const settings = ctx.get('settings'); + if (settings === undefined) + return err(request, settingsAbsent()); + if (isAborted(signal)) { + return err(request, { + code: 'cancelled', + message: 'settings document open was aborted', + details: {}, + }); + } + let path; + try { + path = await settings.prepareDocument(); + } + catch (error) { + if (isAborted(signal)) { + return err(request, { + code: 'cancelled', + message: 'settings document preparation was aborted', + details: {}, + }); + } + return err(request, { + code: 'internal', + message: `settings document preparation failed: ${error instanceof Error ? error.message : String(error)}`, + details: {}, + }); + } + if (path === undefined) { + return err(request, { + code: 'internal', + message: 'settings provider has no local document to open', + details: {}, + }); + } + if (isAborted(signal)) { + return err(request, { + code: 'cancelled', + message: 'settings document open was aborted', + details: {}, + }); + } + return openTextFile(request, path, signal); + }, + update: request => settingsWrite(request, request.payload.ns, 'update', request.payload.patch, request.payload.expectedRevision), + replace: request => settingsWrite(request, request.payload.ns, 'replace', request.payload.section, request.payload.expectedRevision), + mutate: request => settingsWrite(request, request.payload.ns, 'mutate', request.payload.ops, request.payload.expectedRevision), + }, + credentials: { + async describe(request) { + const credentials = ctx.get('credentials'); + if (credentials === undefined) + return err(request, credentialsAbsent()); + const entries = await Promise.all(request.payload.refs.map(async (ref) => { + const info = await credentials.describe(credentialRef(ref)); + const view = { + configured: info.configured, + ...info.source === undefined ? {} : { source: info.source }, + writable: info.writable, + }; + return [ref, view]; + })); + return ok(request, { credentials: Object.fromEntries(entries) }); + }, + async set(request) { + const credentials = ctx.get('credentials'); + if (credentials === undefined) + return err(request, credentialsAbsent()); + const { ref, value } = request.payload; + try { + await credentials.set(credentialRef(ref), value); + } + catch (error) { + return err(request, { + code: 'credential-rejected', + message: error instanceof Error ? error.message : String(error), + details: { ref }, + }); + } + return ok(request, {}); + }, + async unset(request) { + const credentials = ctx.get('credentials'); + if (credentials === undefined) + return err(request, credentialsAbsent()); + const { ref } = request.payload; + try { + await credentials.unset(credentialRef(ref)); + } + catch (error) { + return err(request, { + code: 'credential-rejected', + message: error instanceof Error ? error.message : String(error), + details: { ref }, + }); + } + return ok(request, {}); + }, + }, + llm: { + providers(request) { + const registered = ctx.llm.listProviders(); + const active = new Set(registered.map(provider => provider.id)); + const directory = ctx.llm.listConfigurableProviders(); + const declared = new Set(directory.map(entry => entry.provider)); + const views = directory.map(entry => ({ + provider: entry.provider, + displayName: entry.displayName, + settingsNs: entry.settingsNs, + settingsPath: [...entry.settingsPath], + active: active.has(entry.provider), + ...entry.declared === undefined ? {} : { declared: entry.declared }, + })); + // Routes registered without a directory declaration still appear — + // they exist and serve models — just with no settings address. No + // adapter claimed them, so nothing can say whether they are shipped. + for (const provider of registered) { + if (declared.has(provider.id)) + continue; + views.push({ + provider: provider.id, + displayName: provider.name, + settingsNs: '', + settingsPath: [], + active: true, + }); + } + return Promise.resolve(ok(request, { providers: views })); + }, + async models(request) { + return ok(request, await buildModelCatalog(ctx)); + }, + async discoverModels(request, signal) { + const { settingsNs, provider, baseURL, api, apiKey } = request.payload; + try { + const models = await ctx.llm.discoverModels(settingsNs, { + ...provider === undefined ? {} : { provider }, + ...baseURL === undefined ? {} : { baseURL }, + ...api === undefined ? {} : { api }, + ...apiKey === undefined ? {} : { apiKey }, + ...signal === undefined ? {} : { signal }, + }); + return ok(request, { models }); + } + catch (error) { + // Every failure here is the user's next move, not a transport fault: + // a wrong endpoint, a rejected key, or a protocol with no listing all + // end at the same place — fill the models in by hand. The details + // repeat only what the caller already sent, never the credential. + return err(request, { + code: 'model-discovery-failed', + message: error instanceof Error ? error.message : String(error), + details: { settingsNs, ...baseURL === undefined ? {} : { baseURL } }, + }); + } + }, + }, + events: { + mux(_request, signal) { + const queue = new FrameQueue(); + muxQueues.add(queue); + for (const session of ctx.sessions.list()) { + subscribeSession(queue, session); + } + for (const pending of pendingQuestions.values()) { + queue.push({ + rpcId: pending.rpcId, + payload: { + type: 'question/requested', sessionId: pending.sessionId, + questions: pending.questions, + }, + }); + } + // Refresh recovery: still-pending approval questions replay with their + // stable rpcId so a reconnecting client can still answer them. + for (const pending of pendingApprovals.values()) + queue.push(requestedFrame(pending)); + // Queue snapshot baseline (pendingQuestions precedent): frames replayed + // in arrival order per session; a reconnecting client rebuilds its + // queue view from these alone. + for (const session of ctx.sessions.list()) { + const agent = ctx.agents.get(session.id); + if (agent?.session === session && agent.inbox.hasPending) { + queue.push(frame({ type: 'session/queue', sessionId: session.id, items: queueItems(agent) })); + } + } + // Background-task baseline. `ctx.agents.get` is the non-resuming read: + // a session with no live Agent owns no tasks, so it correctly sees only + // the unowned ones, and listing never revives a cold session. An empty + // set sends nothing — absence is how the client reads "no tasks". + const jobs = ctx.get('jobs'); + if (jobs !== undefined) { + for (const session of ctx.sessions.list()) { + const views = jobViews(jobs.list(ctx.agents.get(session.id))); + if (views.length > 0) { + queue.push(frame({ type: 'session/jobs', sessionId: session.id, jobs: views })); + } + } + } + // Per-session open-call table for result-view pairing. Bounded by the + // per-turn call count: entries clear on turn/end; a table miss (stream + // opened mid-turn) backscans the session's in-memory events instead. + const openCalls = new Map(); + const disposers = [ + ctx.on('session/event', (session, event) => { + if (event.type === 'tool/call') { + const data = event.data; + try { + let table = openCalls.get(session.id); + if (table === undefined) + openCalls.set(session.id, table = new Map()); + table.set(data.callId, { name: data.name, args: JSON.parse(data.arguments) }); + } + catch { + // Unparseable model arguments: leave the table unset; the result view soft-falls. + } + } + else if (event.type === 'turn/end') { + openCalls.delete(session.id); + } + const view = viewFor(ctx, event, callId => openCalls.get(session.id)?.get(callId) ?? backscanArgs(session.events, callId), ctx.agents.get(session.id)); + queue.push(frame({ type: 'session/event', sessionId: session.id, event, ...view === undefined ? {} : { view } })); + }), + ctx.on('session/created', (session) => { + subscribeSession(queue, session); + // The subscribe frame clears the client's task mirror, and a + // session born after the stream opened missed the baseline loop. + // Unowned tasks are visible to it from birth, so without this it + // would show none until the next registry change. + const views = jobs === undefined ? [] : jobViews(jobs.list(ctx.agents.get(session.id))); + if (views.length > 0) { + queue.push(frame({ type: 'session/jobs', sessionId: session.id, jobs: views })); + } + }), + ctx.on('session/disposed', (session) => { + openCalls.delete(session.id); + }), + ...jobs === undefined ? [] : [jobs.onJobsChanged((owner) => { + if (owner !== undefined) { + // The exact owner instance the fence compares against, so the + // push stays correct even while that Agent's scope is tearing + // down and a lookup by id would already miss. + queue.push(frame({ type: 'session/jobs', sessionId: owner.id, jobs: jobViews(jobs.list(owner)) })); + return; + } + // An unowned task is visible to every caller, so every subscribed + // session's set changed with it. + for (const session of ctx.sessions.list()) { + queue.push(frame({ + type: 'session/jobs', + sessionId: session.id, + jobs: jobViews(jobs.list(ctx.agents.get(session.id))), + })); + } + })], + ]; + return queue.iterate(signal, () => { + muxQueues.delete(queue); + for (const dispose of disposers) + dispose(); + }); + }, + host(_request, signal) { + const queue = new FrameQueue(); + const committedWorkspaces = ctx.workspaceRegistry.list(); + const committedWorkspaceIds = new Set(committedWorkspaces.map(workspace => String(workspace.id))); + let committedWorkspaceOrder = committedWorkspaces.map(workspace => workspace.id); + // Frame-dedup baseline, same posture as committedWorkspaceIds: the + // stream opens against the current set; workspace.list re-baselines + // reconnecting clients, so only later changes need frames. + let archivedSessionIds = ctx.workspaceRegistry.archivedSessionIds; + const disposers = [ + ctx.on('session/created', (session) => { + queue.push(frame({ + type: 'host/session-added', + sessionId: session.id, + // Derived at frame time like summarize(); a just-created session + // has run no turn yet, so this is constantly true in practice. + blank: sessionBlank(session), + // Including cwd lets the client group the new session without refreshing the list. + ...sessionListFields(session.header, session.events), + })); + }), + ctx.on('session/disposed', (session) => { + queue.push(frame({ type: 'host/session-removed', sessionId: session.id })); + }), + ctx.on('agent/status', ({ agent, status }) => { + queue.push(frame({ type: 'host/session-status', sessionId: agent.id, running: status === 'running' })); + }), + ctx.on('agent/error', ({ agent, error }) => { + queue.push(frame({ type: 'host/agent-error', sessionId: agent.id, message: errorChain(error) })); + }), + ctx.on('domain/changed', (change) => { + if (change.domain !== 'workspace') + return; + if (change.table === '') { + if (change.operation !== 'put') + return; + const state = workspaceDomainState.parse(change.value); + const orderChanged = state.workspaceIds.length === committedWorkspaceOrder.length + && state.workspaceIds.every(workspaceId => committedWorkspaceIds.has(String(workspaceId))) + && state.workspaceIds.some((workspaceId, index) => workspaceId !== committedWorkspaceOrder[index]); + for (const workspaceId of state.workspaceIds) { + if (committedWorkspaceIds.has(workspaceId)) + continue; + const workspace = ctx.workspaceRegistry.get(workspaceId); + if (workspace === undefined) { + throw new Error(`committed workspace registry references missing workspace "${workspaceId}"`); + } + committedWorkspaceIds.add(workspaceId); + queue.push(frame({ type: 'host/workspace-changed', workspace: workspaceView(workspace) })); + } + committedWorkspaceOrder = [...state.workspaceIds]; + if (orderChanged) { + queue.push(frame({ + type: 'host/workspace-order-changed', + workspaceIds: [...state.workspaceIds], + })); + } + if (state.archivedSessionIds.length !== archivedSessionIds.length + || state.archivedSessionIds.some((id, index) => id !== archivedSessionIds[index])) { + archivedSessionIds = state.archivedSessionIds; + queue.push(frame({ + type: 'host/archived-sessions-changed', + archivedSessionIds: [...state.archivedSessionIds], + })); + } + return; + } + if (change.table !== 'workspaces') + return; + if (change.operation === 'deleted') { + if (!committedWorkspaceIds.delete(change.key)) + return; + queue.push(frame({ + type: 'host/workspace-removed', + workspaceId: change.key, + })); + return; + } + if (!committedWorkspaceIds.has(change.key)) + return; + // Existing-entity table writes are complete attach/touch commits. + // A new entity's first put waits for the global registry write above. + queue.push(frame({ + type: 'host/workspace-changed', + workspace: changedWorkspaceView(change.key, change.value), + })); + }), + // Allowlisted host events ride one verbatim wrapper frame each. The + // allowlist is api-remotes', and `ctx.remote.$on` is the consumer + // face; nothing here projects, redacts, or renames. + ...API_REMOTE_FORWARDED_EVENTS.map(name => ctx.on(name, + // The allowlist's shape assertion proves each name is a real, + // non-scoped, void-returning event, so the rest-parameter handler + // satisfies every member of the union `on` accepts here; + // assertJsonArgs proves the payload is JSON-safe before it queues. + ((...args) => { + queue.push(frame({ + type: 'host/remote-event', + event: name, + args: assertJsonArgs(name, args), + })); + }))), + ]; + return queue.iterate(signal, () => { for (const dispose of disposers) + dispose(); }); + }, + }, + downloads: { + async sessionLog(request, signal) { + // Clean error path first: missing services answer 500 and a missing + // root artifact 404 before any zip byte is produced. The root content + // read here is reused as the first zip entry, so nothing is read twice. + const deps = sessionLogExportDeps(ctx); + if (deps.sessionQuery === undefined || deps.sessionPersistence === undefined || deps.attachments === undefined) { + return new Response('session log export is unavailable: missing session-query, session-persistence, or attachments service', { status: 500 }); + } + if (!deps.sessionPersistence.supportsRawArtifacts) { + return new Response('session log export is unavailable: the persistence backend does not expose per-session raw artifacts', { status: 501 }); + } + const ready = { + sessionQuery: deps.sessionQuery, + sessionPersistence: deps.sessionPersistence, + attachments: deps.attachments, + sessions: deps.sessions, + }; + let root; + try { + await flushLiveSessionLog(deps, request.sessionId, signal); + root = await deps.sessionPersistence.readRaw(request.sessionId, signal); + signal.throwIfAborted(); + } + catch { + signal.throwIfAborted(); + // Root preparation failure: answer 500 without echoing the error, + // which may carry absolute host paths into the browser error bar. + return new Response('session log export failed to prepare the stored artifact', { status: 500 }); + } + if (root === undefined) { + return new Response('session not found', { status: 404 }); + } + return new Response(streamSessionLogZip(ready, root, request.sessionId, request.includeDescendants === true, sessionExportCompressionLevel, signal), { + headers: { + 'content-type': 'application/zip', + 'content-disposition': `attachment; filename="${sessionLogZipFilename(request.sessionId)}"`, + }, + }); + }, + }, + respond(message) { + // Route by the echoed rpcId (the wire correlation): approvals first, + // then questions — the two registries share one id space of UUIDs. + const approval = pendingApprovals.get(message.rpcId); + if (approval !== undefined) { + if (!message.result.ok) + return Promise.resolve({ accepted: false, reason: 'bad-response' }); + const parsed = approvalResponsePayloadSchema.safeParse(message.result.value); + // The payload's audit correlation must match the entry the rpcId routed + // to — a mismatched answer is malformed, not merely late. + if (!parsed.success || parsed.data.approvalId !== approval.approvalId || parsed.data.sessionId !== approval.sessionId) { + return Promise.resolve({ accepted: false, reason: 'bad-response' }); + } + approval.resolve(parsed.data.outcome); + return Promise.resolve({ accepted: true }); + } + const pending = pendingQuestions.get(message.rpcId); + if (pending === undefined) + return Promise.resolve({ accepted: false, reason: 'not-pending' }); + if (!message.result.ok) { + if (message.result.error.code !== 'cancelled') { + return Promise.resolve({ accepted: false, reason: 'bad-response' }); + } + claimQuestion(pending, 'cancelled'); + pending.reject(new UserQuestionError('the user cancelled ask_user_question', 'ASK_CANCELLED')); + return Promise.resolve({ accepted: true }); + } + const parsed = questionResponsePayloadSchema.safeParse(message.result.value); + if (!parsed.success) { + return Promise.resolve({ accepted: false, reason: 'bad-response' }); + } + const payload = { + sessionId: parsed.data.sessionId, + answer: { + answers: parsed.data.answer.answers.map(answer => ({ + id: answer.id, + selected: answer.selected, + ...(answer.custom === undefined ? {} : { custom: answer.custom }), + })), + }, + }; + if (!matchesQuestions(payload, pending)) { + return Promise.resolve({ accepted: false, reason: 'bad-response' }); + } + claimQuestion(pending, 'answered'); + pending.resolve(payload.answer); + return Promise.resolve({ accepted: true }); + }, + }; +} +//# sourceMappingURL=api-proxy.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.d.ts new file mode 100644 index 0000000..0f55636 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.d.ts @@ -0,0 +1,130 @@ +/** + * agent-presets domain contract: the roster a browser offers when starting a + * session, plus the authoring calls behind it. + * + * `list` is ordinary: it carries ids and trust, and every preset picker needs + * it. The authoring calls are privileged and loopback-pinned — a composition + * names the plugins a session runs, so reading one is reconnaissance, and + * although authoring is copy-only (no caller supplies composition text or a + * path), copying and deleting still rearrange what the deployment offers. + */ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** One preset the deployment can compose a session's agent from. */ +export interface AgentPresetEntry { + /** Stable identifier, also the display name until presets carry metadata. */ + readonly id: string; + /** + * Whether the preset ships with the deployment or was authored locally. + * A `user` preset is exactly as privileged as the plugins it names, so a + * surface offering one should say so rather than present it as vetted. + */ + readonly trust: 'system' | 'user'; + /** Whether a session that names no preset gets this one. */ + readonly isDefault: boolean; + /** + * Display name the preset published, absent when it published none. A + * surface falls back to {@link id}; it is never a second identity, and it + * never decides trust — a locally authored preset cannot name itself into + * the shipped set. + */ + readonly name?: string; + /** One sentence on what the preset is for, when it published one. */ + readonly description?: string; + /** + * Why this preset cannot compose a session, absent when it can. A broken + * preset stays listed — its directory still occupies the id, so a surface + * must be able to show and delete it — but offering it for selection would + * only defer this reason to a failed session start. + */ + readonly broken?: string; +} +/** agent-preset-domain unary methods (the map key agentPreset.* of RpcMethodMap). */ +export interface AgentPresetsApi { + /** + * Lists every preset the deployment currently supplies, in root-precedence + * order — the roots as configured, each root's own presets sorted by id, + * and the first root to supply an id wins. The order is not globally + * sorted: a user root's preset sits in that root's block, not among the + * shipped ids. + * An empty roster means the deployment composes no presets at all, and + * every session shares the host composition. `authorable` reports whether + * the deployment configures a root new presets can be written to, and + * `hasDocument` whether `openDocument` can hand a preset directory to a + * native opener — both deployment facts rather than per-preset ones, and + * neither exposes a Host path. + */ + list(request: RpcRequest<{}>): Promise>; + /** + * Recompose one session's agent from a different preset. + * + * Allowed only while the session is blank — no turn has run. Once a + * conversation starts, its history was produced under that preset's tools, + * and swapping them would leave logged tool calls the new composition cannot + * make; the attempt answers `agent-preset-locked`. + */ + select(request: RpcRequest<{ + sessionId: SessionId; + agentPreset: string; + }>): Promise>; + /** + * Read one preset's composition text, for the read-only viewer. + * + * Privileged: a composition names the plugins a session runs, so reading + * one is reconnaissance. + */ + read(request: RpcRequest<{ + agentPreset: string; + }>): Promise>; + /** + * Create a locally authored preset by copying an existing one whole. + * + * The only authoring write. No composition text and no path crosses the + * wire: `from` and `agentPreset` are ids the Host resolves against its own + * roots, so a copy is exactly as loadable as its source and grants nothing + * the roster did not already carry. The copy keeps the source's description + * (the file is the author's to edit afterwards) but not its name — `name` + * here or the id fallback is what distinguishes the rows. + */ + copy(request: RpcRequest<{ + from: string; + agentPreset: string; + name?: string; + }>): Promise>; + /** + * Hand one locally authored preset's DIRECTORY to the platform opener, for + * editing the files that are now the only composition editor. The request + * carries an id, never a path — the Host resolves it — so no browser + * payload can select an arbitrary filesystem target. Where the deployment + * has no native opener (`hasDocument: false` on `list`), the reply carries + * the resolved directory for the surface to show as text instead. Shipped + * presets are refused: their install is not the user's to manage. + */ + openDocument(request: RpcRequest<{ + agentPreset: string; + }>, signal: AbortSignal): Promise>; + /** Delete a locally authored preset. Shipped presets are refused. */ + remove(request: RpcRequest<{ + agentPreset: string; + }>): Promise>; +} +//# sourceMappingURL=agent-presets.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.js new file mode 100644 index 0000000..67fc843 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.js @@ -0,0 +1,12 @@ +/** + * agent-presets domain contract: the roster a browser offers when starting a + * session, plus the authoring calls behind it. + * + * `list` is ordinary: it carries ids and trust, and every preset picker needs + * it. The authoring calls are privileged and loopback-pinned — a composition + * names the plugins a session runs, so reading one is reconnaissance, and + * although authoring is copy-only (no caller supplies composition text or a + * path), copying and deleting still rearrange what the deployment offers. + */ +export {}; +//# sourceMappingURL=agent-presets.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.d.ts new file mode 100644 index 0000000..0604ffb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.d.ts @@ -0,0 +1,78 @@ +/** + * agent-presets domain zod schemas (names derived from map keys: + * agentPresetListRequestSchema / agentPresetListValueSchema). + */ +import { z } from 'zod'; +/** AgentPresetEntry row of agentPreset.list. */ +export declare const agentPresetEntrySchema: z.ZodObject<{ + id: z.ZodString; + trust: z.ZodUnion, z.ZodLiteral<"user">]>; + isDefault: z.ZodBoolean; + name: z.ZodOptional; + description: z.ZodOptional; + broken: z.ZodOptional; +}, z.core.$strip>; +/** agentPreset.list request payload. */ +export declare const agentPresetListRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** agentPreset.list response value. */ +export declare const agentPresetListValueSchema: z.ZodObject<{ + presets: z.ZodArray, z.ZodLiteral<"user">]>; + isDefault: z.ZodBoolean; + name: z.ZodOptional; + description: z.ZodOptional; + broken: z.ZodOptional; + }, z.core.$strip>>; + authorable: z.ZodBoolean; + hasDocument: z.ZodBoolean; +}, z.core.$strip>; +/** agentPreset.select request payload. */ +export declare const agentPresetSelectRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.select response value. */ +export declare const agentPresetSelectValueSchema: z.ZodObject<{ + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.read request payload. */ +export declare const agentPresetReadRequestSchema: z.ZodObject<{ + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.read response value. */ +export declare const agentPresetReadValueSchema: z.ZodObject<{ + agentPreset: z.ZodString; + trust: z.ZodUnion, z.ZodLiteral<"user">]>; + content: z.ZodString; + name: z.ZodOptional; + description: z.ZodOptional; +}, z.core.$strip>; +/** agentPreset.copy request payload. */ +export declare const agentPresetCopyRequestSchema: z.ZodObject<{ + from: z.ZodString; + agentPreset: z.ZodString; + name: z.ZodOptional; +}, z.core.$strip>; +/** agentPreset.copy response value. */ +export declare const agentPresetCopyValueSchema: z.ZodObject<{ + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.openDocument request payload. */ +export declare const agentPresetOpenDocumentRequestSchema: z.ZodObject<{ + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.openDocument response value. */ +export declare const agentPresetOpenDocumentValueSchema: z.ZodUnion; +}, z.core.$strip>, z.ZodObject<{ + opened: z.ZodLiteral; + path: z.ZodString; +}, z.core.$strip>]>; +/** agentPreset.remove request payload. */ +export declare const agentPresetRemoveRequestSchema: z.ZodObject<{ + agentPreset: z.ZodString; +}, z.core.$strip>; +/** agentPreset.remove response value. */ +export declare const agentPresetRemoveValueSchema: z.ZodObject<{}, z.core.$strip>; +//# sourceMappingURL=agent-presets.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.js new file mode 100644 index 0000000..94621f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/agent-presets.schema.js @@ -0,0 +1,70 @@ +/** + * agent-presets domain zod schemas (names derived from map keys: + * agentPresetListRequestSchema / agentPresetListValueSchema). + */ +import { z } from 'zod'; +import { sessionIdSchema } from "./sessions.schema.js"; +/** AgentPresetEntry row of agentPreset.list. */ +export const agentPresetEntrySchema = z.object({ + id: z.string().min(1), + trust: z.union([z.literal('system'), z.literal('user')]), + isDefault: z.boolean(), + name: z.string().optional(), + description: z.string().optional(), + broken: z.string().min(1).optional(), +}); +/** agentPreset.list request payload. */ +export const agentPresetListRequestSchema = z.object({}); +/** agentPreset.list response value. */ +export const agentPresetListValueSchema = z.object({ + presets: z.array(agentPresetEntrySchema), + authorable: z.boolean(), + hasDocument: z.boolean(), +}); +/** agentPreset.select request payload. */ +export const agentPresetSelectRequestSchema = z.object({ + sessionId: sessionIdSchema, + agentPreset: z.string().min(1), +}); +/** agentPreset.select response value. */ +export const agentPresetSelectValueSchema = z.object({ + agentPreset: z.string(), +}); +/** agentPreset.read request payload. */ +export const agentPresetReadRequestSchema = z.object({ + agentPreset: z.string().min(1), +}); +/** agentPreset.read response value. */ +export const agentPresetReadValueSchema = z.object({ + agentPreset: z.string(), + trust: z.union([z.literal('system'), z.literal('user')]), + content: z.string(), + name: z.string().optional(), + description: z.string().optional(), +}); +/** agentPreset.copy request payload. */ +export const agentPresetCopyRequestSchema = z.object({ + from: z.string().min(1), + agentPreset: z.string().min(1), + name: z.string().optional(), +}); +/** agentPreset.copy response value. */ +export const agentPresetCopyValueSchema = z.object({ + agentPreset: z.string(), +}); +/** agentPreset.openDocument request payload. */ +export const agentPresetOpenDocumentRequestSchema = z.object({ + agentPreset: z.string().min(1), +}); +/** agentPreset.openDocument response value. */ +export const agentPresetOpenDocumentValueSchema = z.union([ + z.object({ opened: z.literal(true) }), + z.object({ opened: z.literal(false), path: z.string() }), +]); +/** agentPreset.remove request payload. */ +export const agentPresetRemoveRequestSchema = z.object({ + agentPreset: z.string().min(1), +}); +/** agentPreset.remove response value. */ +export const agentPresetRemoveValueSchema = z.object({}); +//# sourceMappingURL=agent-presets.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.d.ts new file mode 100644 index 0000000..056dfd2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.d.ts @@ -0,0 +1,20 @@ +/** + * approvals domain contract. The approval requested frame is a + * server-request (stable rpcId); the answer is a client-response echoing that rpcId (not a + * unary method, not in RpcMethodMap, mints no new id), carried on POST /api/respond with an + * RpcReceipt carrier receipt as the HTTP response body; the final outcome arrives in the resolved frame. + */ +import type { ApprovalRequestId } from '@deepseek-ai/dsh-user-approval/types'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +/** + * Approval answer payload (the result.value slot of a client-response). outcome accepts only + * the two values a client can give (cancelled/unavailable are host-side outcomes). approvalId + * is the core audit correlation (used by the impl to reconcile `approval/asked`/`decided`; + * passes through core's existing brand); wire correlation is governed by the echoed rpcId. + */ +export interface ApprovalResponsePayload { + sessionId: SessionId; + approvalId: ApprovalRequestId; + outcome: 'allowed-once' | 'rejected'; +} +//# sourceMappingURL=approvals.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.js new file mode 100644 index 0000000..40af5b4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.js @@ -0,0 +1,8 @@ +/** + * approvals domain contract. The approval requested frame is a + * server-request (stable rpcId); the answer is a client-response echoing that rpcId (not a + * unary method, not in RpcMethodMap, mints no new id), carried on POST /api/respond with an + * RpcReceipt carrier receipt as the HTTP response body; the final outcome arrives in the resolved frame. + */ +export {}; +//# sourceMappingURL=approvals.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.d.ts new file mode 100644 index 0000000..74f6fab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.d.ts @@ -0,0 +1,16 @@ +/** + * approvals domain zod schemas (respond is a client-response; the payload schema serves + * the /api/respond endpoint's second parse after routing via the pending table). + * ApprovalRequestId brand cast point: one. + */ +import { z } from 'zod'; +import type { ApprovalRequestId } from '@deepseek-ai/dsh-user-approval/types'; +/** ApprovalRequestId: one brand cast after schema validation (the only cast point in this domain). */ +export declare const approvalRequestIdSchema: z.ZodType; +/** Approval answer payload (the result.value slot of a client-response). */ +export declare const approvalResponsePayloadSchema: z.ZodObject<{ + sessionId: z.ZodType>; + approvalId: z.ZodType>; + outcome: z.ZodUnion, z.ZodLiteral<"rejected">]>; +}, z.core.$strip>; +//# sourceMappingURL=approvals.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js new file mode 100644 index 0000000..e7589a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js @@ -0,0 +1,16 @@ +/** + * approvals domain zod schemas (respond is a client-response; the payload schema serves + * the /api/respond endpoint's second parse after routing via the pending table). + * ApprovalRequestId brand cast point: one. + */ +import { z } from 'zod'; +import { sessionIdSchema } from "./sessions.schema.js"; +/** ApprovalRequestId: one brand cast after schema validation (the only cast point in this domain). */ +export const approvalRequestIdSchema = z.string().min(1); +/** Approval answer payload (the result.value slot of a client-response). */ +export const approvalResponsePayloadSchema = z.object({ + sessionId: sessionIdSchema, + approvalId: approvalRequestIdSchema, + outcome: z.union([z.literal('allowed-once'), z.literal('rejected')]), +}); +//# sourceMappingURL=approvals.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.d.ts new file mode 100644 index 0000000..f3f200f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.d.ts @@ -0,0 +1,49 @@ +/** + * credentials domain contract: the web face of the credential-reference seam + * (`ctx.credentials`). Reads are structurally value-free — a credential view + * carries configured/source/writable and has no slot for the value — and the + * value crosses the wire in exactly one direction, inside `credentials.set`. + * There is no enumeration method by design: clients learn which references + * exist from settings schemas and values (`apiKeyEnv` fields). + */ +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** Wire view of one credential reference's state. */ +export interface CredentialView { + /** Whether any layer currently supplies a non-empty value. */ + configured: boolean; + /** Winning layer when configured (`env`, `file`, …); provider vocabulary. */ + source?: string; + /** Whether `credentials.set`/`credentials.unset` can affect this reference. */ + writable: boolean; +} +/** Credentials-domain unary methods (the map keys credentials.* of RpcMethodMap). */ +export interface CredentialsApi { + /** + * Describe the named references (batch): configured state, winning source, + * and writability — never values. An invalid reference name is a + * `bad-request`; an unknown-but-valid one describes as unconfigured. + */ + describe(request: RpcRequest<{ + refs: string[]; + }>): Promise; + }>>; + /** + * Store one credential value in the writable layer. Rejected with + * `credential-rejected` while a read-only layer (the live environment) + * shadows the reference — the write would otherwise appear to succeed while + * resolution keeps returning the shadowing value. + */ + set(request: RpcRequest<{ + ref: string; + value: string; + }>): Promise>; + /** + * Remove one credential from the writable layer; same shadowing rejection + * as `set`. Unsetting an absent reference succeeds (idempotent). + */ + unset(request: RpcRequest<{ + ref: string; + }>): Promise>; +} +//# sourceMappingURL=credentials.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.js new file mode 100644 index 0000000..7b5b346 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.js @@ -0,0 +1,10 @@ +/** + * credentials domain contract: the web face of the credential-reference seam + * (`ctx.credentials`). Reads are structurally value-free — a credential view + * carries configured/source/writable and has no slot for the value — and the + * value crosses the wire in exactly one direction, inside `credentials.set`. + * There is no enumeration method by design: clients learn which references + * exist from settings schemas and values (`apiKeyEnv` fields). + */ +export {}; +//# sourceMappingURL=credentials.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.d.ts new file mode 100644 index 0000000..af57295 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.d.ts @@ -0,0 +1,41 @@ +/** + * credentials domain zod schemas (names derived from map keys: + * credentialsDescribeRequestSchema / credentialsDescribeValueSchema / …). + * The reference-name pattern mirrors the seam's `credentialRef` guard so an + * invalid name fails as `bad-request` before reaching the service. + */ +import { z } from 'zod'; +/** POSIX-portable environment-variable name (the seam's `credentialRef` pattern). */ +export declare const credentialRefNameSchema: z.ZodString; +/** CredentialView entry of credentials.describe. */ +export declare const credentialViewSchema: z.ZodObject<{ + configured: z.ZodBoolean; + source: z.ZodOptional; + writable: z.ZodBoolean; +}, z.core.$strip>; +/** credentials.describe request payload. */ +export declare const credentialsDescribeRequestSchema: z.ZodObject<{ + refs: z.ZodArray; +}, z.core.$strip>; +/** credentials.describe response value. */ +export declare const credentialsDescribeValueSchema: z.ZodObject<{ + credentials: z.ZodRecord; + writable: z.ZodBoolean; + }, z.core.$strip>>; +}, z.core.$strip>; +/** credentials.set request payload: the one direction a value crosses this wire. */ +export declare const credentialsSetRequestSchema: z.ZodObject<{ + ref: z.ZodString; + value: z.ZodString; +}, z.core.$strip>; +/** credentials.set response value. */ +export declare const credentialsSetValueSchema: z.ZodObject<{}, z.core.$strip>; +/** credentials.unset request payload. */ +export declare const credentialsUnsetRequestSchema: z.ZodObject<{ + ref: z.ZodString; +}, z.core.$strip>; +/** credentials.unset response value. */ +export declare const credentialsUnsetValueSchema: z.ZodObject<{}, z.core.$strip>; +//# sourceMappingURL=credentials.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.js new file mode 100644 index 0000000..cbcbe0c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/credentials.schema.js @@ -0,0 +1,37 @@ +/** + * credentials domain zod schemas (names derived from map keys: + * credentialsDescribeRequestSchema / credentialsDescribeValueSchema / …). + * The reference-name pattern mirrors the seam's `credentialRef` guard so an + * invalid name fails as `bad-request` before reaching the service. + */ +import { z } from 'zod'; +/** POSIX-portable environment-variable name (the seam's `credentialRef` pattern). */ +export const credentialRefNameSchema = z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/); +/** CredentialView entry of credentials.describe. */ +export const credentialViewSchema = z.object({ + configured: z.boolean(), + source: z.string().optional(), + writable: z.boolean(), +}); +/** credentials.describe request payload. */ +export const credentialsDescribeRequestSchema = z.object({ + refs: z.array(credentialRefNameSchema).max(64), +}); +/** credentials.describe response value. */ +export const credentialsDescribeValueSchema = z.object({ + credentials: z.record(z.string(), credentialViewSchema), +}); +/** credentials.set request payload: the one direction a value crosses this wire. */ +export const credentialsSetRequestSchema = z.object({ + ref: credentialRefNameSchema, + value: z.string().min(1), +}); +/** credentials.set response value. */ +export const credentialsSetValueSchema = z.object({}); +/** credentials.unset request payload. */ +export const credentialsUnsetRequestSchema = z.object({ + ref: credentialRefNameSchema, +}); +/** credentials.unset response value. */ +export const credentialsUnsetValueSchema = z.object({}); +//# sourceMappingURL=credentials.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.d.ts new file mode 100644 index 0000000..bd0cd08 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.d.ts @@ -0,0 +1,24 @@ +/** + * downloads domain contract: host-only download surfaces — the GET-download + * channel family, the mirror of the SSE-stream `events` domain. No wire + * envelope: the carrier's GET routes answer these directly, and the browser + * `IApiClient` never exposes them. + */ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +/** Host-only download surfaces (no wire envelope; absent from IApiClient). */ +export interface DownloadsApi { + /** + * Stream one session-log ZIP — the root artifact verbatim plus each subagent + * descendant's — as an attachment response. The carrier's GET route answers + * this directly; the browser never calls it. + * @param request - the root session id and whether to include descendants. + * @param signal - cancellation for the underlying reads. + * @returns the ZIP attachment response; missing services answer 500 and a + * missing root session 404 before any byte is produced. + */ + sessionLog(request: { + sessionId: SessionId; + includeDescendants?: boolean; + }, signal: AbortSignal): Promise; +} +//# sourceMappingURL=downloads.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.js new file mode 100644 index 0000000..b9bd0f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.js @@ -0,0 +1,8 @@ +/** + * downloads domain contract: host-only download surfaces — the GET-download + * channel family, the mirror of the SSE-stream `events` domain. No wire + * envelope: the carrier's GET routes answer these directly, and the browser + * `IApiClient` never exposes them. + */ +export {}; +//# sourceMappingURL=downloads.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.d.ts new file mode 100644 index 0000000..f1d7cc7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.d.ts @@ -0,0 +1,24 @@ +/** + * downloads domain zod schemas. The download surface has no wire + * envelope: the request arrives as query parameters (all strings), so its + * request schema parses the raw query-parameter object into the method's + * exact request shape. SessionId brand cast point: sessionIdSchema, and only + * there (hosted in sessions.schema like every other cast). + */ +import { z } from 'zod'; +/** + * session.export query params → the sessionLog request. `includeDescendants` + * accepts exactly `true`/`false`/absent; any other value is rejected (400) so + * a misspelled flag cannot silently under-export. + */ +export declare const sessionLogQuerySchema: z.ZodPipe>; + includeDescendants: z.ZodOptional, z.ZodLiteral<"false">]>>; +}, z.core.$strip>, z.ZodTransform<{ + includeDescendants?: true; + sessionId: import("@deepseek-ai/dsh-session").SessionId; +}, { + sessionId: import("@deepseek-ai/dsh-session").SessionId; + includeDescendants?: "true" | "false" | undefined; +}>>; +//# sourceMappingURL=downloads.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.js new file mode 100644 index 0000000..e9a17be --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/downloads.schema.js @@ -0,0 +1,24 @@ +/** + * downloads domain zod schemas. The download surface has no wire + * envelope: the request arrives as query parameters (all strings), so its + * request schema parses the raw query-parameter object into the method's + * exact request shape. SessionId brand cast point: sessionIdSchema, and only + * there (hosted in sessions.schema like every other cast). + */ +import { z } from 'zod'; +import { sessionIdSchema } from "./sessions.schema.js"; +/** + * session.export query params → the sessionLog request. `includeDescendants` + * accepts exactly `true`/`false`/absent; any other value is rejected (400) so + * a misspelled flag cannot silently under-export. + */ +export const sessionLogQuerySchema = z + .object({ + sessionId: sessionIdSchema, + includeDescendants: z.union([z.literal('true'), z.literal('false')]).optional(), +}) + .transform(query => ({ + sessionId: query.sessionId, + ...(query.includeDescendants === 'true' ? { includeDescendants: true } : {}), +})); +//# sourceMappingURL=downloads.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.d.ts new file mode 100644 index 0000000..5b82d8d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.d.ts @@ -0,0 +1,213 @@ +/** + * events domain contract: signatures and frame unions for the two logical + * streams. Four-quadrant: streams yield the narrow form `RpcRequest` (server-request + * view) — rpcId must be exposed to the business layer, because responses to answerable frames + * (approval/question requested) echo it; for pure pushes it identifies that one push. + * signal is a local stream-control parameter, independent of the request (never on the wire). + */ +import type { AskUserQuestionItem } from '@deepseek-ai/dsh-user-questions/types'; +import type { ApprovalOutcome, ApprovalRequestId } from '@deepseek-ai/dsh-user-approval/types'; +import type { Message } from '@deepseek-ai/dsh-llm/types'; +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { CallId } from '@deepseek-ai/dsh-llm/brand'; +import type { JsonValue, SessionEvent, SessionId } from '@deepseek-ai/dsh-session/types'; +import type { ToolCallView, ToolResultView } from '@deepseek-ai/dsh-tools/presentation'; +import type { RpcError, RpcId, RpcRequest } from './rpc.ts'; +import type { JobView } from './jobs.ts'; +import type { WorkspaceView } from './workspace.ts'; +export type { ToolCallView, ToolResultView } from '@deepseek-ai/dsh-tools/presentation'; +/** + * Host-computed render intent accompanying a `tool/call` or `tool/result` + * event. A pure derivation of args/result through the presenter registered at + * emission time — never persisted (the session log carries only the event), so + * the same event may carry a different view (or none) on a later delivery. + * `for` names which vocabulary applies without re-inspecting the event type. + * An absent view means the client's documented default (generic JSON card). + */ +export type ToolEventView = { + for: 'call'; + view: ToolCallView; +} | { + for: 'result'; + view: ToolResultView; +}; +/** One pending inbox occurrence in the authoritative `session/queue` snapshot. */ +export interface QueuedInboxItem { + /** Message identity used by inbox mutations. */ + id: MessageId; + /** Agent-resolved FIFO placement; queued and steering items render on different surfaces, context items stay invisible until claimed. */ + placement: 'queued' | 'steering' | 'context'; + /** Complete pending message; it is not durable until the Agent claims it. */ + message: Message; +} +/** Streaming face of the contract: the two logical stream openers (mux + host). */ +export interface EventsApi { + /** + * All-session aggregated mux stream. On open, emits a subscribed control frame for every + * attached session, then replays each session's still-pending approval/question requested + * frames (rpcId reused verbatim — the refresh-recovery baseline). Session titles ride the + * generic projection pair (history-tail projections block + session/projection frames). + * since: resume hook, unimplemented in v1 (ignored if passed); reconnection = reopen the + * stream + refetch history. + */ + mux(request: RpcRequest<{ + since?: Record; + }>, signal: AbortSignal): AsyncIterable>; + /** + * Host-level info stream: session create/destroy, running-status flips, and + * agent failures with no turn position. Empty payload uses `{}`. + */ + host(request: RpcRequest<{}>, signal: AbortSignal): AsyncIterable>; +} +/** + * Mux stream frames: raw session-event passthrough + control frames + + * approval/question frames (requested = answerable server-request, the rest are pure pushes). + */ +export type MuxFrame = { + type: 'session/event'; + sessionId: SessionId; + event: SessionEvent; + view?: ToolEventView; +} | { + type: 'session/subscribed'; + sessionId: SessionId; + lastSeq: number; +} | { + type: 'approval/requested'; + sessionId: SessionId; + approvalId: ApprovalRequestId; + toolName: string; + callId?: CallId; + reason?: string; +} | { + type: 'approval/resolved'; + sessionId: SessionId; + approvalId: ApprovalRequestId; + outcome: ApprovalOutcome; +} | { + type: 'question/requested'; + sessionId: SessionId; + questions: AskUserQuestionItem[]; +} | { + type: 'question/resolved'; + sessionId: SessionId; + questionRpcId: RpcId; + outcome: 'answered' | 'cancelled'; +} +/** + * Complete transient inbox state after every enqueue, mutation, claim, or + * discard. Pending work is not model-visible and therefore has no durable + * session event; the whole snapshot makes edit, deletion, cancel, and + * reconnect converge through one authoritative signal. `session/queue` + * covers both resolved placements: queued items render + * in QueueDock, while pending steering renders at the conversation tail. + */ + | { + type: 'session/queue'; + sessionId: SessionId; + items: QueuedInboxItem[]; +} +/** + * Complete set of background jobs this session can see, after every registry + * commit that changes it: registration, the stopping transition, settlement, + * and owner-disposal removal. The registry is process-local and holds no + * durable event, so — exactly like `session/queue` — the whole snapshot is + * what makes a start, a kill, a reconnect, and a second tab converge on one + * authoritative value. + * + * Sent as a subscription baseline only for a session that currently has + * tasks; an absent key means an empty set. A change that empties the set + * still sends `[]`, since that transition is the only one absence cannot + * express. + */ + | { + type: 'session/jobs'; + sessionId: SessionId; + jobs: JobView[]; +} +/** + * One projection unit's finished value changed (session-projection RFC). + * Live push state, never logged — replay recomputes on the host (the + * tool-view posture). `value` is the unit's schema-validated view output; + * `seq` is the unit's watermark at emission. Clients keep one generic + * per-session value store under higher-seq-wins, seeded by the history + * tail page's projections block. + */ + | { + type: 'session/projection'; + sessionId: SessionId; + key: string; + value: unknown; + seq: number; +} | { + type: 'stream/error'; + error: RpcError; +}; +/** + * Host stream frames. session-added carries the lineage anchor, product + * origin, project cwd, and blank bit (the list-summary fields a client cannot + * wait for a refresh to learn); the frame fires at session/created, so blank is + * constantly true — clients flip it on the session's first + * `host/session-status(running:true)` (a blank session never runs), and a + * reconnecting client takes `session.list`'s summary.blank as authoritative. + * agent-error is the only outlet for live failures with no turn position; + * workspace-changed pushes the full new snapshot after every durable + * workspace mutation (create/attach/order change — the client upserts, while + * `workspace.list` provides the reconnect baseline); workspace-removed is the + * committed registration-deletion increment and never implies directory or + * session-log deletion; workspace-order-changed pushes the complete durable + * registry order after a reorder; archived-sessions-changed pushes the full registry + * archive set after every durable change (same full-snapshot posture as + * workspace-changed — `workspace.list` re-baselines it on reconnect). + */ +export type HostFrame = { + type: 'host/session-added'; + sessionId: SessionId; + blank: boolean; + parentSessionId?: SessionId; + origin?: 'subagent'; + cwd?: string; + agentPreset?: string; +} | { + type: 'host/session-removed'; + sessionId: SessionId; +} | { + type: 'host/session-status'; + sessionId: SessionId; + running: boolean; +} | { + type: 'host/agent-error'; + sessionId: SessionId; + message: string; +} | { + type: 'host/workspace-changed'; + workspace: WorkspaceView; +} | { + type: 'host/workspace-removed'; + workspaceId: WorkspaceView['workspaceId']; +} | { + type: 'host/workspace-order-changed'; + workspaceIds: WorkspaceView['workspaceId'][]; +} | { + type: 'host/archived-sessions-changed'; + archivedSessionIds: SessionId[]; +} +/** + * One allowlisted host cordis event forwarded verbatim. The allowlist is + * owned by `@deepseek-ai/dsh-api-remotes` (`API_REMOTE_FORWARDED_EVENTS`), + * which is also the only control point over what a consumer can receive. + * `event` is the host's own event name and `args` its argument list: this + * path applies no projection, no redaction, and no renaming, so the payload + * contract is the owner package's cordis `Events` declaration rather than + * anything stated here. Delivery lands on `ctx.remote.$on`, not on a + * per-event frame variant. + */ + | { + type: 'host/remote-event'; + event: string; + args: JsonValue[]; +} | { + type: 'stream/error'; + error: RpcError; +}; +//# sourceMappingURL=events.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.js new file mode 100644 index 0000000..78f5f73 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.js @@ -0,0 +1,9 @@ +/** + * events domain contract: signatures and frame unions for the two logical + * streams. Four-quadrant: streams yield the narrow form `RpcRequest` (server-request + * view) — rpcId must be exposed to the business layer, because responses to answerable frames + * (approval/question requested) echo it; for pure pushes it identifies that one push. + * signal is a local stream-control parameter, independent of the request (never on the wire). + */ +export {}; +//# sourceMappingURL=events.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.d.ts new file mode 100644 index 0000000..257de37 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.d.ts @@ -0,0 +1,28 @@ +/** + * events domain zod schemas: MuxFrame / HostFrame unions (discriminatedUnion('type')). + * A frame is the payload slot of the ServerRequest full form; the SessionEvent inside + * a session/event frame reuses sessions.schema's strict-envelope + wide-data passthrough branch. + */ +import { z } from 'zod'; +import type { HostFrame, MuxFrame } from './events.ts'; +/** Question fields validated strictly against core dsh-user-questions. */ +export declare const askUserQuestionItemSchema: z.ZodObject<{ + id: z.ZodString; + question: z.ZodString; + header: z.ZodOptional; + detail: z.ZodOptional; + options: z.ZodOptional; + }, z.core.$strip>>>; + multiSelect: z.ZodOptional; + intent: z.ZodOptional; + approve: z.ZodString; + }, z.core.$strip>], "kind">>; +}, z.core.$strip>; +/** MuxFrame union (payload slot of a mux-stream ServerRequest). */ +export declare const muxFrameSchema: z.ZodType; +/** HostFrame union (payload slot of a host-stream ServerRequest). */ +export declare const hostFrameSchema: z.ZodType; +//# sourceMappingURL=events.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js new file mode 100644 index 0000000..adcd82d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js @@ -0,0 +1,84 @@ +/** + * events domain zod schemas: MuxFrame / HostFrame unions (discriminatedUnion('type')). + * A frame is the payload slot of the ServerRequest full form; the SessionEvent inside + * a session/event frame reuses sessions.schema's strict-envelope + wide-data passthrough branch. + */ +import { z } from 'zod'; +import { rpcErrorSchema, rpcIdSchema } from "./rpc.schema.js"; +import { approvalRequestIdSchema } from "./approvals.schema.js"; +import { contentBlockSchema, messageIdSchema, sessionEventSchema, sessionIdSchema, toolEventViewSchema, } from "./sessions.schema.js"; +import { taskViewSchema } from "./jobs.schema.js"; +import { workspaceIdSchema, workspaceViewSchema } from "./workspace.schema.js"; +/** Question fields validated strictly against core dsh-user-questions. */ +export const askUserQuestionItemSchema = z.object({ + id: z.string(), + question: z.string(), + header: z.string().optional(), + detail: z.string().optional(), + options: z.array(z.object({ label: z.string(), description: z.string().optional() })).optional(), + multiSelect: z.boolean().optional(), + // Presentation intent: a tagged union on the wire, so an unknown tag is a + // rejected frame rather than a silently generic render. + intent: z.discriminatedUnion('kind', [ + z.object({ kind: z.literal('plan-review'), approve: z.string() }), + ]).optional(), +}); +/** Unified message envelope carried by transient queue frames. */ +const messageSchema = z.object({ + id: z.string().min(1), + role: z.union([z.literal('system'), z.literal('user'), z.literal('assistant')]), + content: z.array(contentBlockSchema), + source: z.looseObject({ kind: z.string() }), +}); +/** MuxFrame union (payload slot of a mux-stream ServerRequest). */ +export const muxFrameSchema = z.discriminatedUnion('type', [ + z.object({ type: z.literal('session/event'), sessionId: sessionIdSchema, event: sessionEventSchema, view: toolEventViewSchema.optional() }), + z.object({ type: z.literal('session/subscribed'), sessionId: sessionIdSchema, lastSeq: z.number().int() }), + z.object({ type: z.literal('approval/requested'), sessionId: sessionIdSchema, approvalId: approvalRequestIdSchema, toolName: z.string(), callId: z.string().optional(), reason: z.string().optional() }), + z.object({ type: z.literal('approval/resolved'), sessionId: sessionIdSchema, approvalId: approvalRequestIdSchema, outcome: z.union([z.literal('allowed-once'), z.literal('rejected'), z.literal('cancelled'), z.literal('unavailable')]) }), + // Non-empty by wire contract: the user-questions service rejects empty + // batches at ask() (EMPTY_QUESTIONS), so an empty frame is host breakage + // and must fail loud here, not reach the composer. + z.object({ type: z.literal('question/requested'), sessionId: sessionIdSchema, questions: z.array(askUserQuestionItemSchema).min(1) }), + z.object({ type: z.literal('question/resolved'), sessionId: sessionIdSchema, questionRpcId: rpcIdSchema, outcome: z.union([z.literal('answered'), z.literal('cancelled')]) }), + z.object({ + type: z.literal('session/queue'), + sessionId: sessionIdSchema, + items: z.array(z.object({ + id: messageIdSchema, + placement: z.union([z.literal('queued'), z.literal('steering'), z.literal('context')]), + message: messageSchema, + })), + }), + z.object({ type: z.literal('session/jobs'), sessionId: sessionIdSchema, jobs: z.array(taskViewSchema) }), + // value stays wide: it already passed its unit's own schema on the host, + // and deep-validating here would import every domain's schema into the carrier. + z.object({ type: z.literal('session/projection'), sessionId: sessionIdSchema, key: z.string().min(1), value: z.unknown(), seq: z.number().int().nonnegative() }), + z.object({ type: z.literal('stream/error'), error: rpcErrorSchema }), +]); +/** HostFrame union (payload slot of a host-stream ServerRequest). */ +export const hostFrameSchema = z.discriminatedUnion('type', [ + z.object({ + type: z.literal('host/session-added'), + sessionId: sessionIdSchema, + blank: z.boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: z.literal('subagent').optional(), + cwd: z.string().optional(), + agentPreset: z.string().optional(), + }), + z.object({ type: z.literal('host/session-removed'), sessionId: sessionIdSchema }), + z.object({ type: z.literal('host/session-status'), sessionId: sessionIdSchema, running: z.boolean() }), + z.object({ type: z.literal('host/agent-error'), sessionId: sessionIdSchema, message: z.string() }), + z.object({ type: z.literal('host/workspace-changed'), workspace: workspaceViewSchema }), + z.object({ type: z.literal('host/workspace-removed'), workspaceId: workspaceIdSchema }), + z.object({ type: z.literal('host/workspace-order-changed'), workspaceIds: z.array(workspaceIdSchema) }), + z.object({ type: z.literal('host/archived-sessions-changed'), archivedSessionIds: z.array(sessionIdSchema) }), + // args stays wide, the same posture as session/projection's value: the frame + // arrives from JSON.parse, so every element is already a JSON value, and the + // structural contract belongs to the owner package's cordis `Events` + // declaration — the host validated JSON-safety before forwarding. + z.object({ type: z.literal('host/remote-event'), event: z.string().min(1), args: z.array(z.unknown()) }), + z.object({ type: z.literal('stream/error'), error: rpcErrorSchema }), +]); +//# sourceMappingURL=events.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.d.ts new file mode 100644 index 0000000..ad435c3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.d.ts @@ -0,0 +1,73 @@ +/** + * goals domain contract. Method signatures are the source of truth: + * unary methods take the RpcRequest

narrow form and the impl echoes rpcId. + * + * Mutations only: the read side is the 'goal' session projection (history + * tail-page projections block + session/projection frames), so there is no + * goal.get and no wire goal view — responses acknowledge with the new CAS + * ref and never feed client state (the committed goal/change event reaches + * every client through the mux stream carrying the same whole value). + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** Identifies one goal across its durable revisions. */ +export type GoalId = Branded<'GoalId'>; +/** Compare-and-set identity for one exact goal revision. */ +export interface GoalRef { + readonly id: GoalId; + readonly revision: number; +} +/** + * Goal-domain unary methods. Every mutation resolves an ordinary session's + * Agent and applies one CAS-guarded verb; session-backed subagents reject with + * `agent-busy`. + */ +export interface GoalsApi { + /** Create and arm a goal. */ + create(request: RpcRequest<{ + sessionId: SessionId; + objective: string; + maxGoalRounds?: number; + }>): Promise>; + /** Edit objective and/or round cap without changing phase. */ + edit(request: RpcRequest<{ + sessionId: SessionId; + ref: GoalRef; + objective?: string; + maxGoalRounds?: number; + }>): Promise>; + /** Pause an active goal and disarm automatic continuation. */ + pause(request: RpcRequest<{ + sessionId: SessionId; + ref: GoalRef; + }>): Promise>; + /** Resume and arm a stopped goal. */ + resume(request: RpcRequest<{ + sessionId: SessionId; + ref: GoalRef; + }>): Promise>; + /** Mark a current non-complete goal complete and disarm it. */ + complete(request: RpcRequest<{ + sessionId: SessionId; + ref: GoalRef; + }>): Promise>; + /** Clear the current goal while retaining a durable tombstone and history. */ + clear(request: RpcRequest<{ + sessionId: SessionId; + ref: GoalRef; + }>): Promise>; +} +//# sourceMappingURL=goals.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.js new file mode 100644 index 0000000..8cb936b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.js @@ -0,0 +1,12 @@ +/** + * goals domain contract. Method signatures are the source of truth: + * unary methods take the RpcRequest

narrow form and the impl echoes rpcId. + * + * Mutations only: the read side is the 'goal' session projection (history + * tail-page projections block + session/projection frames), so there is no + * goal.get and no wire goal view — responses acknowledge with the new CAS + * ref and never feed client state (the committed goal/change event reaches + * every client through the mux stream carrying the same whole value). + */ +export {}; +//# sourceMappingURL=goals.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.d.ts new file mode 100644 index 0000000..47fe478 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.d.ts @@ -0,0 +1,35 @@ +/** + * goals domain zod schemas. Mutation-only shapes: every value schema is a + * `{ ref }` acknowledgement (clear: `{ cleared }`) — the current goal state + * travels exclusively on the 'goal' session projection. + */ +import { z } from 'zod'; +import type { Wire } from './rpc.schema.ts'; +import type { GoalRef, RequestPayload, ResponseValue } from './index.ts'; +/** GoalRef schema. */ +export declare const goalRefSchema: z.ZodType>; +/** goal.create request payload. */ +export declare const goalCreateRequestSchema: z.ZodType>>; +/** goal.create response value. */ +export declare const goalCreateValueSchema: z.ZodType>>; +/** goal.edit request payload. */ +export declare const goalEditRequestSchema: z.ZodType>>; +/** goal.edit response value. */ +export declare const goalEditValueSchema: z.ZodType>>; +/** goal.pause request payload. */ +export declare const goalPauseRequestSchema: z.ZodType>>; +/** goal.pause response value. */ +export declare const goalPauseValueSchema: z.ZodType>>; +/** goal.resume request payload. */ +export declare const goalResumeRequestSchema: z.ZodType>>; +/** goal.resume response value. */ +export declare const goalResumeValueSchema: z.ZodType>>; +/** goal.complete request payload. */ +export declare const goalCompleteRequestSchema: z.ZodType>>; +/** goal.complete response value. */ +export declare const goalCompleteValueSchema: z.ZodType>>; +/** goal.clear request payload. */ +export declare const goalClearRequestSchema: z.ZodType>>; +/** goal.clear response value. */ +export declare const goalClearValueSchema: z.ZodType>>; +//# sourceMappingURL=goals.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.js new file mode 100644 index 0000000..d0dc101 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/goals.schema.js @@ -0,0 +1,63 @@ +/** + * goals domain zod schemas. Mutation-only shapes: every value schema is a + * `{ ref }` acknowledgement (clear: `{ cleared }`) — the current goal state + * travels exclusively on the 'goal' session projection. + */ +import { z } from 'zod'; +/** GoalRef schema. */ +export const goalRefSchema = z.object({ + id: z.string(), + revision: z.number().int().positive(), +}); +/** Shared `{ ref }` acknowledgement value of every non-clear mutation. */ +const goalRefValueSchema = z.object({ ref: goalRefSchema }); +/** goal.create request payload. */ +export const goalCreateRequestSchema = z.object({ + sessionId: z.string(), + objective: z.string().min(1), + maxGoalRounds: z.number().int().positive().optional(), +}); +/** goal.create response value. */ +export const goalCreateValueSchema = goalRefValueSchema; +/** goal.edit request payload. */ +export const goalEditRequestSchema = z.object({ + sessionId: z.string(), + ref: goalRefSchema, + objective: z.string().min(1).optional(), + maxGoalRounds: z.number().int().positive().optional(), +}).refine(value => value.objective !== undefined || value.maxGoalRounds !== undefined, { + message: 'goal.edit requires objective or maxGoalRounds', +}); +/** goal.edit response value. */ +export const goalEditValueSchema = goalRefValueSchema; +/** goal.pause request payload. */ +export const goalPauseRequestSchema = z.object({ + sessionId: z.string(), + ref: goalRefSchema, +}); +/** goal.pause response value. */ +export const goalPauseValueSchema = goalRefValueSchema; +/** goal.resume request payload. */ +export const goalResumeRequestSchema = z.object({ + sessionId: z.string(), + ref: goalRefSchema, +}); +/** goal.resume response value. */ +export const goalResumeValueSchema = goalRefValueSchema; +/** goal.complete request payload. */ +export const goalCompleteRequestSchema = z.object({ + sessionId: z.string(), + ref: goalRefSchema, +}); +/** goal.complete response value. */ +export const goalCompleteValueSchema = goalRefValueSchema; +/** goal.clear request payload. */ +export const goalClearRequestSchema = z.object({ + sessionId: z.string(), + ref: goalRefSchema, +}); +/** goal.clear response value. */ +export const goalClearValueSchema = z.object({ + cleared: z.literal(true), +}); +//# sourceMappingURL=goals.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.d.ts new file mode 100644 index 0000000..11ba5f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.d.ts @@ -0,0 +1,91 @@ +/** + * host domain contract. No protocol version: client and host ship + * together; introduce protocolVersion only when an independently released client appears. + */ +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** One directory row of a listing: a child entry or a breadcrumb ancestor. */ +export interface DirectoryEntry { + /** Base name shown in a browser row (a root crumb carries its full path). */ + name: string; + /** Absolute host path — the client never joins path segments itself. */ + path: string; + /** Hidden by the host platform's convention (dot-prefixed on POSIX); the client owns whether to show it. */ + hidden: boolean; +} +/** host.listDirectory response value: one directory level plus its ancestry. */ +export interface DirectoryListing { + /** Absolute path of the listed directory. */ + path: string; + /** The host account's home directory (breadcrumb "Home" rooting). */ + home: string; + /** + * Ancestor chain from the filesystem root to the listed directory + * inclusive; every crumb is a jump target (crumb `hidden` is always false). + */ + crumbs: DirectoryEntry[]; + /** Direct child directories, name-sorted; symlinks to directories included. */ + entries: DirectoryEntry[]; + /** True when the backend cut `entries` at its complete-result bound (the name-sorted tail is absent). */ + truncated: boolean; +} +/** Host-level unary methods. */ +export interface HostApi { + /** + * One-shot host snapshot. Empty payload uses the literal `{}` (extend in place when fields arrive). + * version = the host app's (apps/cli) package.json version; cwd = the host process working + * directory (root for session persistence and tool execution); provider/model = the defaults + * applied when a new agent doesn't specify them explicitly, absent when the host configures + * no explicit default (the adapter falls back internally); + * attachedSessions = count of currently attached sessions (those with a live agent); + * canOpenPath = whether this deployment can hand a path to a user-visible native desktop. + */ + describe(request: RpcRequest<{}>): Promise>; + /** + * Open the operating system's single-directory picker; cancellation returns + * null. Only served under the `native` capability. + */ + pickDirectory(request: RpcRequest<{}>, signal: AbortSignal): Promise>; + /** + * List one directory level for the in-app browser; an absent path lists the + * host account's home directory. Only served under the `browse` capability; + * unreadable or missing targets fail with `directory-unreadable`. The + * carrier's request signal follows the caller, stopping the backend's scan + * on disconnect or timeout. + */ + listDirectory(request: RpcRequest<{ + path?: string; + }>, signal: AbortSignal): Promise>; + /** + * Create one child directory under an existing parent (the browser's + * "New folder"). Only served under the `browse` capability; an existing + * child fails with `directory-exists`, every other filesystem failure with + * `directory-create-failed`. + */ + createDirectory(request: RpcRequest<{ + path: string; + name: string; + }>): Promise>; + /** + * Open a filesystem path with the operating system's default application + * (Finder / Explorer / xdg-open hand-off). The browser carrier's + * prefix-wide trust fence covers this privileged method like every other + * `/api` request. + */ + openPath(request: RpcRequest<{ + path: string; + }>, signal: AbortSignal): Promise>; +} +//# sourceMappingURL=host.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.js new file mode 100644 index 0000000..e0ea541 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.js @@ -0,0 +1,6 @@ +/** + * host domain contract. No protocol version: client and host ship + * together; introduce protocolVersion only when an independently released client appears. + */ +export {}; +//# sourceMappingURL=host.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.d.ts new file mode 100644 index 0000000..556953c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.d.ts @@ -0,0 +1,65 @@ +/** + * host domain zod schemas (names derived from map keys). + */ +import { z } from 'zod'; +/** host.describe request payload (empty object literal). */ +export declare const hostDescribeRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** host.describe response value. */ +export declare const hostDescribeValueSchema: z.ZodObject<{ + version: z.ZodString; + cwd: z.ZodString; + provider: z.ZodOptional; + model: z.ZodOptional; + attachedSessions: z.ZodNumber; + canOpenPath: z.ZodBoolean; +}, z.core.$strip>; +/** host.pickDirectory request payload (empty object literal). */ +export declare const hostPickDirectoryRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** host.pickDirectory response value; null means the user cancelled. */ +export declare const hostPickDirectoryValueSchema: z.ZodObject<{ + path: z.ZodNullable; +}, z.core.$strip>; +/** Directory row shared by listing entries and breadcrumb crumbs. */ +export declare const directoryEntrySchema: z.ZodObject<{ + name: z.ZodString; + path: z.ZodString; + hidden: z.ZodBoolean; +}, z.core.$strip>; +/** host.listDirectory request payload; an absent path lists the home directory. */ +export declare const hostListDirectoryRequestSchema: z.ZodObject<{ + path: z.ZodOptional; +}, z.core.$strip>; +/** host.listDirectory response value. */ +export declare const hostListDirectoryValueSchema: z.ZodObject<{ + path: z.ZodString; + home: z.ZodString; + crumbs: z.ZodArray>; + entries: z.ZodArray>; + truncated: z.ZodBoolean; +}, z.core.$strip>; +/** host.createDirectory request payload: name must be one plain path segment. */ +export declare const hostCreateDirectoryRequestSchema: z.ZodObject<{ + path: z.ZodString; + name: z.ZodString; +}, z.core.$strip>; +/** host.createDirectory response value: the created directory's absolute path. */ +export declare const hostCreateDirectoryValueSchema: z.ZodObject<{ + path: z.ZodString; +}, z.core.$strip>; +/** host.openPath request payload. */ +export declare const hostOpenPathRequestSchema: z.ZodObject<{ + path: z.ZodString; +}, z.core.$strip>; +/** host.openPath response value. */ +export declare const hostOpenPathValueSchema: z.ZodObject<{ + opened: z.ZodLiteral; +}, z.core.$strip>; +//# sourceMappingURL=host.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.js new file mode 100644 index 0000000..5f3b496 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/host.schema.js @@ -0,0 +1,58 @@ +/** + * host domain zod schemas (names derived from map keys). + */ +import { z } from 'zod'; +/** host.describe request payload (empty object literal). */ +export const hostDescribeRequestSchema = z.object({}); +/** host.describe response value. */ +export const hostDescribeValueSchema = z.object({ + version: z.string(), + cwd: z.string(), + provider: z.string().optional(), + model: z.string().optional(), + attachedSessions: z.number().int().nonnegative(), + canOpenPath: z.boolean(), +}); +/** host.pickDirectory request payload (empty object literal). */ +export const hostPickDirectoryRequestSchema = z.object({}); +/** host.pickDirectory response value; null means the user cancelled. */ +export const hostPickDirectoryValueSchema = z.object({ + path: z.string().nullable(), +}); +/** Directory row shared by listing entries and breadcrumb crumbs. */ +export const directoryEntrySchema = z.object({ + name: z.string(), + path: z.string(), + hidden: z.boolean(), +}); +/** host.listDirectory request payload; an absent path lists the home directory. */ +export const hostListDirectoryRequestSchema = z.object({ + path: z.string().optional(), +}); +/** host.listDirectory response value. */ +export const hostListDirectoryValueSchema = z.object({ + path: z.string(), + home: z.string(), + crumbs: z.array(directoryEntrySchema), + entries: z.array(directoryEntrySchema), + truncated: z.boolean(), +}); +/** host.createDirectory request payload: name must be one plain path segment. */ +export const hostCreateDirectoryRequestSchema = z.object({ + path: z.string(), + name: z.string(), +}).refine(payload => payload.name.trim() !== '' && payload.name !== '.' && payload.name !== '..' + && !/[/\\]/.test(payload.name), { message: 'host.createDirectory requires a single non-blank path segment name' }); +/** host.createDirectory response value: the created directory's absolute path. */ +export const hostCreateDirectoryValueSchema = z.object({ + path: z.string(), +}); +/** host.openPath request payload. */ +export const hostOpenPathRequestSchema = z.object({ + path: z.string().min(1), +}); +/** host.openPath response value. */ +export const hostOpenPathValueSchema = z.object({ + opened: z.literal(true), +}); +//# sourceMappingURL=host.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.d.ts new file mode 100644 index 0000000..ebaa5e8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.d.ts @@ -0,0 +1,63 @@ +/** + * apiproxy contract-layer barrel. api/ has zero Node dependencies and is + * importable from the browser; the TS interfaces are the authoritative contract, while HTTP, + * WebSocket, and in-process SSE are merely physical channels (four-quadrant message model). + */ +import type { SessionsApi } from './sessions.ts'; +import type { HostApi } from './host.ts'; +import type { WorkspaceApi } from './workspace.ts'; +import type { AgentPresetsApi } from './agent-presets.ts'; +import type { SkillsApi } from './skills.ts'; +import type { SubagentsApi } from './subagents.ts'; +import type { EventsApi } from './events.ts'; +import type { GoalsApi } from './goals.ts'; +import type { SettingsApi } from './settings.ts'; +import type { CredentialsApi } from './credentials.ts'; +import type { LlmApi } from './llm.ts'; +import type { DownloadsApi } from './downloads.ts'; +import type { ClientResponse, RpcReceipt } from './rpc.ts'; +/** Root interface of the unified API. New client-request domain = one new file pair + one field here + one map row. */ +export interface ApiProxy { + sessions: SessionsApi; + subagents: SubagentsApi; + host: HostApi; + workspace: WorkspaceApi; + skills: SkillsApi; + agentPresets: AgentPresetsApi; + events: EventsApi; + goals: GoalsApi; + settings: SettingsApi; + credentials: CredentialsApi; + llm: LlmApi; + /** Host-only download surfaces (GET, no wire envelope); absent from IApiClient. */ + downloads: DownloadsApi; + /** + * Response entry for server requests; not a domain method. + * @param message - Client response carrying the server request's rpcId. + * @returns Transport receipt for the response delivery. + */ + respond(message: ClientResponse): Promise; +} +export type { HistoryEntry, ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning, ModelReasoningEffort, ModelSelection, PromptContentPart, QueueAction, SessionModels, SessionListMetadata, SessionProjectionsBlock, SessionSearchItem, SessionsApi, SessionSummary, } from './sessions.ts'; +export type { DirectoryEntry, DirectoryListing, HostApi } from './host.ts'; +export type { SubagentAddress, SubagentCatalog, SubagentInterruptReceipt, SubagentListEntry, SubagentPromptReceipt, SubagentsApi, } from './subagents.ts'; +export type { JobView } from './jobs.ts'; +export type { WorkspaceApi, WorkspaceId, WorkspaceView } from './workspace.ts'; +export type { SkillsApi, SkillEntry } from './skills.ts'; +export type { AgentPresetsApi, AgentPresetEntry } from './agent-presets.ts'; +export type { EventsApi, MuxFrame, HostFrame, QueuedInboxItem, ToolCallView, ToolEventView, ToolResultView } from './events.ts'; +export type { GoalsApi, GoalId, GoalRef } from './goals.ts'; +export type { SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView } from './settings.ts'; +export type { CredentialsApi, CredentialView } from './credentials.ts'; +export type { ConfigurableProviderView, DiscoveredModelView, LlmApi } from './llm.ts'; +export type { DownloadsApi } from './downloads.ts'; +export type { ApprovalResponsePayload } from './approvals.ts'; +export type { QuestionResponsePayload } from './questions.ts'; +export type { RpcRequest, RpcResponse } from './rpc.ts'; +export type { ClientRequest, ClientResponse, RpcMessage, RpcReceipt, ServerRequest, ServerResponse, } from './rpc.ts'; +export { RpcId, transportError } from './rpc.ts'; +export type { RpcError, RpcErrorCode, RpcErrorDetailsMap, RpcResult } from './rpc.ts'; +export { clientRequestSchema, serverRequestSchema, serverResponseSchema, } from './rpc.schema.ts'; +export { SESSION_SEARCH_RESULT_LIMIT, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS, } from './session-search.ts'; +export type { RequestPayload, ResponseValue, RpcMethodMap } from './rpc-map.ts'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.js new file mode 100644 index 0000000..b03cb5f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/index.js @@ -0,0 +1,11 @@ +/** + * apiproxy contract-layer barrel. api/ has zero Node dependencies and is + * importable from the browser; the TS interfaces are the authoritative contract, while HTTP, + * WebSocket, and in-process SSE are merely physical channels (four-quadrant message model). + */ +// ---- Errors and ids ---- +export { RpcId, transportError } from "./rpc.js"; +export { clientRequestSchema, serverRequestSchema, serverResponseSchema, } from "./rpc.schema.js"; +// ---- Fixed session-search product bounds ---- +export { SESSION_SEARCH_RESULT_LIMIT, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS, } from "./session-search.js"; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.d.ts new file mode 100644 index 0000000..44bf62d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.d.ts @@ -0,0 +1,35 @@ +/** + * Browser-safe background-job domain contract. The registry's live records + * never cross the wire; a view is the subset a human list needs, minted fresh + * per push. + */ +import type { JobId } from '@deepseek-ai/dsh-jobs/brand'; +/** + * One background job as the client sees it. + * + * Three registry fields are deliberately absent. `ownerSession` is redundant + * beside the frame's own `sessionId`; `reported` is an internal notice-delivery + * bit with no user meaning; `outputLimitBytes` is producer-owned model + * presentation policy that never reaches a human surface. + */ +export interface JobView { + /** Registry-issued `-N` identity, stable for the task's whole life. */ + id: JobId; + /** + * Producer kind (`bash`, `pwsh`, `pty-send`, `subagent`, …). Kept as a bare + * string because producer plugins extend the kind map by declaration merging, + * so no client build can enumerate the closed set. + */ + kind: string; + /** Producer-supplied one-line label: the command, or the delegation description. */ + label: string; + /** Current lifecycle state. */ + status: 'running' | 'stopping' | 'completed' | 'killed' | 'failed'; + /** Kind-specific status detail ('exit code: 3'), present once the producer supplied one. */ + detail?: string; + /** Epoch ms when the task was registered. */ + startedAt: number; + /** Epoch ms when the task settled; absent while live. */ + finishedAt?: number; +} +//# sourceMappingURL=jobs.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.js new file mode 100644 index 0000000..445aa97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.js @@ -0,0 +1,7 @@ +/** + * Browser-safe background-job domain contract. The registry's live records + * never cross the wire; a view is the subset a human list needs, minted fresh + * per push. + */ +export {}; +//# sourceMappingURL=jobs.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.d.ts new file mode 100644 index 0000000..fb751a9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.d.ts @@ -0,0 +1,23 @@ +/** + * tasks domain zod schemas: the branded job id and the wire view carried by + * `session/jobs` frames. + */ +import { z } from 'zod'; +import type { JobId } from '@deepseek-ai/dsh-jobs/brand'; +/** JobId: one brand cast after non-empty string validation. */ +export declare const taskIdSchema: z.ZodType; +/** + * One wire task view. `kind` stays an open string because producer plugins + * extend the registry's kind map by declaration merging, so the closed set is + * not knowable at this boundary. + */ +export declare const taskViewSchema: z.ZodObject<{ + id: z.ZodType>; + kind: z.ZodString; + label: z.ZodString; + status: z.ZodUnion, z.ZodLiteral<"stopping">, z.ZodLiteral<"completed">, z.ZodLiteral<"killed">, z.ZodLiteral<"failed">]>; + detail: z.ZodOptional; + startedAt: z.ZodNumber; + finishedAt: z.ZodOptional; +}, z.core.$strip>; +//# sourceMappingURL=jobs.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.js new file mode 100644 index 0000000..5617c2b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/jobs.schema.js @@ -0,0 +1,28 @@ +/** + * tasks domain zod schemas: the branded job id and the wire view carried by + * `session/jobs` frames. + */ +import { z } from 'zod'; +/** JobId: one brand cast after non-empty string validation. */ +export const taskIdSchema = z.string().min(1); +/** + * One wire task view. `kind` stays an open string because producer plugins + * extend the registry's kind map by declaration merging, so the closed set is + * not knowable at this boundary. + */ +export const taskViewSchema = z.object({ + id: taskIdSchema, + kind: z.string().min(1), + label: z.string().min(1), + status: z.union([ + z.literal('running'), + z.literal('stopping'), + z.literal('completed'), + z.literal('killed'), + z.literal('failed'), + ]), + detail: z.string().optional(), + startedAt: z.number().int().nonnegative(), + finishedAt: z.number().int().nonnegative().optional(), +}); +//# sourceMappingURL=jobs.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.d.ts new file mode 100644 index 0000000..6cffa55 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.d.ts @@ -0,0 +1,88 @@ +/** + * llm domain contract: host-scoped provider topology for configuration + * surfaces. `llm.providers` merges the configurable-provider directory + * (which providers CAN be configured, and where their settings live) with the + * live route registry; `llm.models` is the session-independent model catalog + * (the same groups as `session.models`, without a per-session selection). + * Clients invalidate from the forwarded `llm/adapters-updated` and + * `settings/document-updated` owner events. + */ +import type { RpcRequest, RpcResponse } from './rpc.ts'; +import type { ModelCatalogFailure, ModelProviderGroup } from './sessions.ts'; +/** Wire view of one configurable provider. */ +export interface ConfigurableProviderView { + /** Provider route key (`deepseek-official`, `openai`, …). */ + provider: string; + /** Human-readable name for configuration surfaces. */ + displayName: string; + /** Settings namespace whose section configures this provider. */ + settingsNs: string; + /** Path from that section's root to the provider's profile object (empty = whole section). */ + settingsPath: string[]; + /** Whether the route is currently registered (its models are requestable). */ + active: boolean; + /** + * Whether the owning adapter knows this route only because configuration + * declared it. Absent when the adapter draws no such distinction, so a + * surface must treat absence as "unknown", not as "shipped". + */ + declared?: boolean; +} +/** Llm-domain unary methods (the map keys llm.* of RpcMethodMap). */ +export interface LlmApi { + /** + * List every configurable provider with its live/dormant state, in + * directory declaration order. Routes registered outside the directory + * (an adapter that never declared configurability) are appended with their + * registration identity and no settings address. + */ + providers(request: RpcRequest<{}>): Promise>; + /** + * Host-scoped model catalog over every registered provider route: the + * settings surface's models view, needing no session. Per-provider listing + * failures ride `failures` without failing the sound groups. + */ + models(request: RpcRequest<{}>): Promise>; + /** + * Interrogate a provider endpoint the configuration surface is still + * drafting, and return the models it advertises for the user to adopt. + * + * The payload is the draft, not a stored route: `settingsNs` selects the + * adapter family that answers, and the rest comes from the form. `provider` + * names the route being edited when there is one — an adapter that already + * describes that route answers from its own registry, with better metadata + * and no network call, and needs no endpoint. A route it does not describe is + * asked over the wire, which is what `baseURL`, `api`, and `apiKey` are for. + * + * Nothing is written — the reply is candidates, and only a later + * `settings.mutate` decides what a route serves. `apiKey` is accepted here + * but never stored or returned; a provider whose key is already stored omits + * it and the endpoint answers unauthenticated or refuses. + */ + discoverModels(request: RpcRequest<{ + settingsNs: string; + provider?: string; + baseURL?: string; + api?: string; + apiKey?: string; + }>, signal?: AbortSignal): Promise>; +} +/** Wire view of one model an interrogated endpoint advertises. */ +export interface DiscoveredModelView { + /** Model id the endpoint accepts. */ + id: string; + /** Human-readable name when the endpoint supplies one. */ + name?: string; + /** Maximum combined request and response context, when disclosed. */ + contextWindow?: number; + /** Maximum output tokens, when disclosed. */ + maxTokens?: number; +} +//# sourceMappingURL=llm.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.js new file mode 100644 index 0000000..d434c9d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.js @@ -0,0 +1,11 @@ +/** + * llm domain contract: host-scoped provider topology for configuration + * surfaces. `llm.providers` merges the configurable-provider directory + * (which providers CAN be configured, and where their settings live) with the + * live route registry; `llm.models` is the session-independent model catalog + * (the same groups as `session.models`, without a per-session selection). + * Clients invalidate from the forwarded `llm/adapters-updated` and + * `settings/document-updated` owner events. + */ +export {}; +//# sourceMappingURL=llm.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.d.ts new file mode 100644 index 0000000..1452ae8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.d.ts @@ -0,0 +1,79 @@ +/** + * llm domain zod schemas (names derived from map keys: llmProvidersRequestSchema / + * llmProvidersValueSchema / llmModelsRequestSchema / llmModelsValueSchema). + */ +import { z } from 'zod'; +/** ConfigurableProviderView row of llm.providers. */ +export declare const configurableProviderViewSchema: z.ZodObject<{ + provider: z.ZodString; + displayName: z.ZodString; + settingsNs: z.ZodString; + settingsPath: z.ZodArray; + active: z.ZodBoolean; + declared: z.ZodOptional; +}, z.core.$strip>; +/** llm.providers request payload. */ +export declare const llmProvidersRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** llm.providers response value. */ +export declare const llmProvidersValueSchema: z.ZodObject<{ + providers: z.ZodArray; + active: z.ZodBoolean; + declared: z.ZodOptional; + }, z.core.$strip>>; +}, z.core.$strip>; +/** llm.models request payload. */ +export declare const llmModelsRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** llm.models response value. */ +export declare const llmModelsValueSchema: z.ZodObject<{ + groups: z.ZodArray; + reasoning: z.ZodOptional; + }, z.core.$strip>>; + defaultEffort: z.ZodOptional; + }, z.core.$strip>>; + }, z.core.$strip>>; + }, z.core.$strip>>; + failures: z.ZodArray>; +}, z.core.$strip>; +/** DiscoveredModelView row of llm.discoverModels. */ +export declare const discoveredModelViewSchema: z.ZodObject<{ + id: z.ZodString; + name: z.ZodOptional; + contextWindow: z.ZodOptional; + maxTokens: z.ZodOptional; +}, z.core.$strip>; +/** llm.discoverModels request payload. */ +export declare const llmDiscoverModelsRequestSchema: z.ZodObject<{ + settingsNs: z.ZodString; + provider: z.ZodOptional; + baseURL: z.ZodOptional; + api: z.ZodOptional; + apiKey: z.ZodOptional; +}, z.core.$strip>; +/** llm.discoverModels response value. */ +export declare const llmDiscoverModelsValueSchema: z.ZodObject<{ + models: z.ZodArray; + contextWindow: z.ZodOptional; + maxTokens: z.ZodOptional; + }, z.core.$strip>>; +}, z.core.$strip>; +//# sourceMappingURL=llm.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.js new file mode 100644 index 0000000..68938c1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/llm.schema.js @@ -0,0 +1,53 @@ +/** + * llm domain zod schemas (names derived from map keys: llmProvidersRequestSchema / + * llmProvidersValueSchema / llmModelsRequestSchema / llmModelsValueSchema). + */ +import { z } from 'zod'; +import { modelCatalogFailureSchema, modelProviderGroupSchema } from "./sessions.schema.js"; +/** ConfigurableProviderView row of llm.providers. */ +export const configurableProviderViewSchema = z.object({ + provider: z.string().min(1), + displayName: z.string().min(1), + settingsNs: z.string(), + settingsPath: z.array(z.string()), + active: z.boolean(), + declared: z.boolean().optional(), +}); +/** llm.providers request payload. */ +export const llmProvidersRequestSchema = z.object({}); +/** llm.providers response value. */ +export const llmProvidersValueSchema = z.object({ + providers: z.array(configurableProviderViewSchema), +}); +/** llm.models request payload. */ +export const llmModelsRequestSchema = z.object({}); +/** llm.models response value. */ +export const llmModelsValueSchema = z.object({ + groups: z.array(modelProviderGroupSchema), + failures: z.array(modelCatalogFailureSchema), +}); +/** DiscoveredModelView row of llm.discoverModels. */ +export const discoveredModelViewSchema = z.object({ + id: z.string().min(1), + name: z.string().min(1).optional(), + contextWindow: z.number().int().positive().optional(), + maxTokens: z.number().int().positive().optional(), +}); +/** llm.discoverModels request payload. */ +export const llmDiscoverModelsRequestSchema = z.object({ + settingsNs: z.string().min(1), + provider: z.string().min(1).optional(), + baseURL: z.string().min(1).optional(), + api: z.string().min(1).optional(), + // Write-only at the host: used for this one interrogation, never stored and + // never returned. It does ride the client's outgoing envelope like every + // other secret-bearing payload (`credentials.set`, `settings.update`), which + // `subscribeEnvelopes()` observers can see — redacting that tap is a + // configuration-plane-wide change, not this method's to make alone. + apiKey: z.string().min(1).optional(), +}); +/** llm.discoverModels response value. */ +export const llmDiscoverModelsValueSchema = z.object({ + models: z.array(discoveredModelViewSchema), +}); +//# sourceMappingURL=llm.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.d.ts new file mode 100644 index 0000000..99e0872 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.d.ts @@ -0,0 +1,18 @@ +/** + * questions domain contract. The question requested frame is a + * server-request whose rpcId is the question's stable logical id (minted when the host accepts + * ask(); core user-questions has no request-level id); the answer is a client-response + * echoing that rpcId, with no resource id in the payload (rpcId suffices). + */ +import type { AskUserQuestionAnswer } from '@deepseek-ai/dsh-user-questions/types'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +/** + * Question answer payload (the result.value slot of a client-response): + * answers one ask() as a whole batch (core: one ask, many questions, one + * answer — never split per question). + */ +export interface QuestionResponsePayload { + sessionId: SessionId; + answer: AskUserQuestionAnswer; +} +//# sourceMappingURL=questions.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.js new file mode 100644 index 0000000..17a6e2d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.js @@ -0,0 +1,8 @@ +/** + * questions domain contract. The question requested frame is a + * server-request whose rpcId is the question's stable logical id (minted when the host accepts + * ask(); core user-questions has no request-level id); the answer is a client-response + * echoing that rpcId, with no resource id in the payload (rpcId suffices). + */ +export {}; +//# sourceMappingURL=questions.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.d.ts new file mode 100644 index 0000000..c2673ef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.d.ts @@ -0,0 +1,26 @@ +/** + * questions domain zod schemas (respond is a client-response; the payload schema serves + * the /api/respond endpoint's second parse after routing via the pending table). The question + * identifier is the echoed rpcId; the payload carries no resource id. + */ +import { z } from 'zod'; +/** AskUserQuestionAnswer validated strictly against core dsh-user-questions. */ +export declare const askUserQuestionAnswerSchema: z.ZodObject<{ + answers: z.ZodArray; + custom: z.ZodOptional; + }, z.core.$strip>>; +}, z.core.$strip>; +/** Question answer payload (the result.value slot of a client-response). */ +export declare const questionResponsePayloadSchema: z.ZodObject<{ + sessionId: z.ZodType>; + answer: z.ZodObject<{ + answers: z.ZodArray; + custom: z.ZodOptional; + }, z.core.$strip>>; + }, z.core.$strip>; +}, z.core.$strip>; +//# sourceMappingURL=questions.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.js new file mode 100644 index 0000000..d05435c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/questions.schema.js @@ -0,0 +1,21 @@ +/** + * questions domain zod schemas (respond is a client-response; the payload schema serves + * the /api/respond endpoint's second parse after routing via the pending table). The question + * identifier is the echoed rpcId; the payload carries no resource id. + */ +import { z } from 'zod'; +import { sessionIdSchema } from "./sessions.schema.js"; +/** AskUserQuestionAnswer validated strictly against core dsh-user-questions. */ +export const askUserQuestionAnswerSchema = z.object({ + answers: z.array(z.object({ + id: z.string(), + selected: z.array(z.string()), + custom: z.string().optional(), + })), +}); +/** Question answer payload (the result.value slot of a client-response). */ +export const questionResponsePayloadSchema = z.object({ + sessionId: sessionIdSchema, + answer: askUserQuestionAnswerSchema, +}); +//# sourceMappingURL=questions.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.d.ts new file mode 100644 index 0000000..351987e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.d.ts @@ -0,0 +1,80 @@ +/** + * RPC method registry and signature-derived generics. The map + * registers only client-request methods (respond is a client-response, so it is absent); + * map keys are the wire path segments (POST /api/session.list). + */ +import type { SessionsApi } from './sessions.ts'; +import type { HostApi } from './host.ts'; +import type { WorkspaceApi } from './workspace.ts'; +import type { AgentPresetsApi } from './agent-presets.ts'; +import type { SkillsApi } from './skills.ts'; +import type { GoalsApi } from './goals.ts'; +import type { SettingsApi } from './settings.ts'; +import type { CredentialsApi } from './credentials.ts'; +import type { LlmApi } from './llm.ts'; +import type { SubagentsApi } from './subagents.ts'; +import type { RpcResponse } from './rpc.ts'; +/** + * Method name → method signature. Signatures are the single source of truth; payload/value + * types are always derived from here. A method may declare a trailing AbortSignal after the + * request (command.execute): the carrier passes its request signal, never a wire field. + */ +export interface RpcMethodMap { + 'session.list': SessionsApi['list']; + 'session.search': SessionsApi['search']; + 'session.create': SessionsApi['create']; + 'session.history': SessionsApi['history']; + 'session.models': SessionsApi['models']; + 'session.selectModel': SessionsApi['selectModel']; + 'session.rename': SessionsApi['rename']; + 'session.fork': SessionsApi['fork']; + 'session.prompt': SessionsApi['prompt']; + 'session.attachment': SessionsApi['attachment']; + 'session.updateQueue': SessionsApi['updateQueue']; + 'session.cancel': SessionsApi['cancel']; + 'subagent.list': SubagentsApi['list']; + 'subagent.history': SubagentsApi['history']; + 'subagent.prompt': SubagentsApi['prompt']; + 'subagent.interrupt': SubagentsApi['interrupt']; + 'host.describe': HostApi['describe']; + 'host.pickDirectory': HostApi['pickDirectory']; + 'host.listDirectory': HostApi['listDirectory']; + 'host.createDirectory': HostApi['createDirectory']; + 'host.openPath': HostApi['openPath']; + 'workspace.list': WorkspaceApi['list']; + 'workspace.create': WorkspaceApi['create']; + 'workspace.rename': WorkspaceApi['rename']; + 'workspace.delete': WorkspaceApi['delete']; + 'workspace.insertBefore': WorkspaceApi['insertBefore']; + 'workspace.insertSessionBefore': WorkspaceApi['insertSessionBefore']; + 'workspace.archiveSession': WorkspaceApi['archiveSession']; + 'skill.list': SkillsApi['list']; + 'agentPreset.list': AgentPresetsApi['list']; + 'agentPreset.select': AgentPresetsApi['select']; + 'agentPreset.read': AgentPresetsApi['read']; + 'agentPreset.copy': AgentPresetsApi['copy']; + 'agentPreset.openDocument': AgentPresetsApi['openDocument']; + 'agentPreset.remove': AgentPresetsApi['remove']; + 'goal.create': GoalsApi['create']; + 'goal.edit': GoalsApi['edit']; + 'goal.pause': GoalsApi['pause']; + 'goal.resume': GoalsApi['resume']; + 'goal.complete': GoalsApi['complete']; + 'goal.clear': GoalsApi['clear']; + 'settings.describe': SettingsApi['describe']; + 'settings.openDocument': SettingsApi['openDocument']; + 'settings.update': SettingsApi['update']; + 'settings.replace': SettingsApi['replace']; + 'settings.mutate': SettingsApi['mutate']; + 'credentials.describe': CredentialsApi['describe']; + 'credentials.set': CredentialsApi['set']; + 'credentials.unset': CredentialsApi['unset']; + 'llm.providers': LlmApi['providers']; + 'llm.models': LlmApi['models']; + 'llm.discoverModels': LlmApi['discoverModels']; +} +/** Business request payload of method K (reaches through the RpcRequest narrow form to payload). */ +export type RequestPayload = Parameters[0]['payload']; +/** Business return value of method K (reaches through the RpcResponse narrow form to infer the ok value of result). */ +export type ResponseValue = Awaited> extends RpcResponse ? T : never; +//# sourceMappingURL=rpc-map.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.js new file mode 100644 index 0000000..74c509d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc-map.js @@ -0,0 +1,7 @@ +/** + * RPC method registry and signature-derived generics. The map + * registers only client-request methods (respond is a client-response, so it is absent); + * map keys are the wire path segments (POST /api/session.list). + */ +export {}; +//# sourceMappingURL=rpc-map.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.d.ts new file mode 100644 index 0000000..7ae0b94 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.d.ts @@ -0,0 +1,263 @@ +/** + * Four-quadrant RPC message model. Channels and messages are decoupled: HTTP, + * WebSocket, and in-process SSE are physical carriers, while logical messages + * are channel-independent and form a four-member discriminated union. + * api/ contract layer: zero Node dependencies, importable from the browser. + */ +import type { z as zCore } from 'zod'; +type ZodIssue = zCore.core.$ZodIssue; +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +/** + * Message correlation id: the initiator mints it on a request; a response + * echoes the matching request's rpcId and never mints a new one. + */ +export type RpcId = Branded<'rpc-id'>; +/** + * Brands a string as RpcId (same precedent as core `SessionId()`). Minted by the initiator: + * client-request → client mints; server-request → host mints (answerable frames get a stable + * logical id, pure pushes mint a fresh one each time). + * @param id - Raw id string (implementations mint UUIDs; tests may pass fixtures). + * @returns The same string, branded (compile-time cast, zero runtime cost). + */ +export declare function RpcId(id: string): RpcId; +/** Error code → details type map (a second table isomorphic to RpcMethodMap). New code = one row here + one branch in the error schema. */ +export interface RpcErrorDetailsMap { + 'bad-request': { + issues: ZodIssue[]; + }; + 'cancelled': {}; + 'session-not-found': { + sessionId: SessionId; + }; + 'model-unavailable': { + provider: string; + model: string; + }; + 'session-conflict': { + sessionId: SessionId; + requestedCwd: string; + existingCwd?: string; + }; + 'invalid-time-zone': { + value: string; + }; + 'workspace-attach-failed': { + sessionId: SessionId; + workspaceId: string; + }; + 'workspace-not-found': { + workspaceId: string; + }; + 'workspace-invalid-path': { + path: string; + }; + 'workspace-name-conflict': { + name: string; + }; + 'workspace-move-invalid': { + workspaceId: string; + sessionId: SessionId; + beforeSessionId?: SessionId; + }; + 'directory-unreadable': { + path: string; + }; + 'directory-exists': { + path: string; + }; + 'directory-create-failed': { + path: string; + }; + 'directory-picker-unavailable': { + capability: string; + }; + 'agent-preset-read-only': { + agentPreset: string; + reason: string; + }; + 'agent-preset-locked': { + sessionId: SessionId; + agentPreset: string; + }; + 'agent-preset-conflict': { + sessionId: SessionId; + requestedPreset: string; + existingPreset?: string; + }; + 'agent-preset-not-found': { + agentPreset: string; + available: string[]; + }; + 'agent-preset-invalid': { + agentPreset: string; + reason: string; + }; + 'agent-busy': { + reason: string; + }; + 'attachment-error': { + reason: string; + }; + 'queue-item-not-found': { + itemId: MessageId; + }; + 'steer-unavailable': { + itemId: MessageId; + }; + /** A known slash command reported a usage/state error; the message is the command's own text. */ + 'command-error': {}; + /** A leading-/ prompt named no registered command; the message names the token. */ + 'unknown-command': {}; + /** + * A settings write was refused (schema validation, unknown namespace, + * read-only provider, or storage failure); the message is the seam's text. + */ + 'settings-rejected': { + ns: string; + }; + /** + * A settings write carried an `expectedRevision` the namespace has already + * moved past: another writer (tab, editor, or an external file edit) landed + * first. The details carry both revisions so a client can re-read and retry. + */ + 'settings-conflict': { + ns: string; + expected: number; + actual: number; + }; + /** A credential write was refused (read-only shadowing layer or storage failure); the message is the seam's own text. */ + 'credential-rejected': { + ref: string; + }; + /** + * Interrogating a draft provider endpoint did not produce a model listing: + * no adapter family serves the namespace, the protocol has no listing this + * build can read, or the endpoint was unreachable, refused the credential, + * or answered with something else. The message is the adapter's own text — + * it is what the form shows before falling back to hand-entry — and the + * details name the endpoint asked, never the credential offered. + */ + 'model-discovery-failed': { + settingsNs: string; + baseURL?: string; + }; + 'title-invalid': { + sessionId: SessionId; + }; + 'fork-unavailable': { + sessionId: SessionId; + }; + 'subagent-parent-unavailable': { + parentSessionId: SessionId; + }; + 'subagent-not-found': { + parentSessionId: SessionId; + childSessionId: SessionId; + }; + 'subagent-catalog-diagnostic': { + parentSessionId: SessionId; + childSessionId: SessionId; + reason: 'corrupt' | 'unsupported' | 'unavailable'; + }; + 'subagent-not-resumable': { + childSessionId: SessionId; + }; + 'subagent-unauthorized': { + childSessionId: SessionId; + }; + 'subagent-delivery-unavailable': { + childSessionId: SessionId; + }; + 'internal': {}; +} +/** Closed error-code union (the keys of RpcErrorDetailsMap). */ +export type RpcErrorCode = keyof RpcErrorDetailsMap; +/** + * Distributive union expanded from the map: code is the discriminant, so + * `switch (error.code)` narrows details. details is required (internal uses an explicit {}). + */ +export type RpcError = { + [C in RpcErrorCode]: { + code: C; + message: string; + details: RpcErrorDetailsMap[C]; + }; +}[RpcErrorCode]; +/** Business success/failure result: the result slot of a unary response; methods never throw business errors. */ +export type RpcResult = { + ok: true; + value: T; +} | { + ok: false; + error: RpcError; +}; +/** + * Fold a transport exception into the RpcResult error branch (unified error + * API; 'internal' as the catch-all code). Lives with RpcResult so every + * carrier consumer folds the same way. + * @param error - the thrown value from the carrier. + * @returns the error branch of an RpcResult. + */ +export declare function transportError(error: unknown): RpcResult; +/** + * Signature-layer narrow form, request side (domain-interface view, shared by + * both directions): rpcId is explicit in the signature, never mixed into the + * business payload; the type tag and method are filled in by the carrier layer. + */ +export interface RpcRequest

{ + rpcId: RpcId; + payload: P; +} +/** Signature-layer narrow form, response side: rpcId always echoes the matching request. */ +export interface RpcResponse { + rpcId: RpcId; + result: RpcResult; +} +/** Call initiated by the client (wire carrier: POST /api/ body). */ +export interface ClientRequest { + type: 'client-request'; + rpcId: RpcId; + method: string; + payload: unknown; +} +/** Response to a ClientRequest (wire carrier: the HTTP response body of that POST); rpcId echoed. */ +export interface ServerResponse { + type: 'server-response'; + rpcId: RpcId; + result: RpcResult; +} +/** + * Message initiated by the server (wire carrier: downstream stream frame). Answerable interactions + * (approval/question requested — stable rpcId, reused on replay) and pure pushes + * (session/event etc. — rpcId identifies that one push) share this shape; whether a + * response is expected is determined statically by method (a strict dichotomy, no third kind). + */ +export interface ServerRequest { + type: 'server-request'; + rpcId: RpcId; + method: string; + payload: unknown; +} +/** Response to a ServerRequest (wire carrier: POST /api/respond body); rpcId echoed, never minted anew. */ +export interface ClientResponse { + type: 'client-response'; + rpcId: RpcId; + result: RpcResult; +} +/** Authoritative wire full-form union; narrow via `switch (message.type)`. */ +export type RpcMessage = ClientRequest | ServerResponse | ServerRequest | ClientResponse; +/** + * Carrier receipt (not an RpcMessage — it belongs to the carrier layer, same + * discipline as "HTTP status describes only the carrier"): the HTTP response + * body of the POST carrying a client-response. Late/duplicate responses yield not-pending. + */ +export type RpcReceipt = { + accepted: true; +} | { + accepted: false; + reason: 'not-pending' | 'bad-response'; +}; +export {}; +//# sourceMappingURL=rpc.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.js new file mode 100644 index 0000000..1485a2f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.js @@ -0,0 +1,30 @@ +/** + * Four-quadrant RPC message model. Channels and messages are decoupled: HTTP, + * WebSocket, and in-process SSE are physical carriers, while logical messages + * are channel-independent and form a four-member discriminated union. + * api/ contract layer: zero Node dependencies, importable from the browser. + */ +/** + * Brands a string as RpcId (same precedent as core `SessionId()`). Minted by the initiator: + * client-request → client mints; server-request → host mints (answerable frames get a stable + * logical id, pure pushes mint a fresh one each time). + * @param id - Raw id string (implementations mint UUIDs; tests may pass fixtures). + * @returns The same string, branded (compile-time cast, zero runtime cost). + */ +export function RpcId(id) { + return id; +} +/** + * Fold a transport exception into the RpcResult error branch (unified error + * API; 'internal' as the catch-all code). Lives with RpcResult so every + * carrier consumer folds the same way. + * @param error - the thrown value from the carrier. + * @returns the error branch of an RpcResult. + */ +export function transportError(error) { + return { + ok: false, + error: { code: 'internal', message: error instanceof Error ? error.message : String(error), details: {} }, + }; +} +//# sourceMappingURL=rpc.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.d.ts new file mode 100644 index 0000000..b9a572f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.d.ts @@ -0,0 +1,60 @@ +/** + * Message-layer zod schemas: the four wire full forms + error body + + * carrier receipt. The payload slot is unknown in the full-form schemas — business payloads + * get a second parse dispatched by method (two-level parse discipline). + * Brand cast point: rpcIdSchema, and only there. + */ +import { z } from 'zod'; +import type { ClientRequest, ClientResponse, RpcError, RpcId, ServerRequest, ServerResponse } from './rpc.ts'; +/** + * Wire widening of a contract type: widens every property (deeply) to `original | undefined`. + * The repo enables exactOptionalPropertyTypes while zod `.optional()` outputs `T | undefined`, + * so `satisfies z.ZodType` is unusable across the board; anchoring is always + * written `satisfies z.ZodType>` — the widening only adds undefined, so + * missing fields / wrong types still fail to compile. On the JSON wire, "absent" and + * "value undefined" serialize identically, so the widening loses no validation semantics. + */ +export type Wire = T extends readonly (infer E)[] ? Wire[] : T extends object ? { + [K in keyof T]: Wire | undefined; +} : T; +/** + * RpcId: one brand cast after schema validation (the only cast point in this + * file). No min-length: the id is an opaque echo token, and rejecting values + * here would only turn a correlatable error report into a client-side parse + * failure (the handler substitutes a sentinel when a request's id is unreadable). + */ +export declare const rpcIdSchema: z.ZodType; +/** Error body: discriminated by code, per-branch details aligned to RpcErrorDetailsMap; details is required. */ +export declare const rpcErrorSchema: z.ZodType; +/** + * Business success/failure result schema (generic, reusable). + * @param value - Schema for the business value. + * @returns Schema for RpcResult. + */ +export declare function rpcResultSchema(value: z.ZodType): z.ZodUnion; +/** ClientRequest full form (payload stays wide — the business layer runs the second parse). */ +export declare const clientRequestSchema: z.ZodType; +/** ServerResponse full form (result.value stays wide). */ +export declare const serverResponseSchema: z.ZodType; +/** ServerRequest full form (payload stays wide). */ +export declare const serverRequestSchema: z.ZodType; +/** ClientResponse full form (result.value stays wide). */ +export declare const clientResponseSchema: z.ZodType; +/** Wire full-form union (discriminated by type). */ +export declare const rpcMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject>; +}>, z.core.$strip>, z.ZodObject>; +}>, z.core.$strip>, z.ZodObject>; +}>, z.core.$strip>, z.ZodObject>; +}>, z.core.$strip>], "type">; +/** Carrier receipt schema. */ +export declare const rpcReceiptSchema: z.ZodUnion; +}, z.core.$strip>, z.ZodObject<{ + accepted: z.ZodLiteral; + reason: z.ZodUnion, z.ZodLiteral<"bad-response">]>; +}, z.core.$strip>]>; +//# sourceMappingURL=rpc.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js new file mode 100644 index 0000000..e4c9aff --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js @@ -0,0 +1,114 @@ +/** + * Message-layer zod schemas: the four wire full forms + error body + + * carrier receipt. The payload slot is unknown in the full-form schemas — business payloads + * get a second parse dispatched by method (two-level parse discipline). + * Brand cast point: rpcIdSchema, and only there. + */ +import { z } from 'zod'; +/** + * RpcId: one brand cast after schema validation (the only cast point in this + * file). No min-length: the id is an opaque echo token, and rejecting values + * here would only turn a correlatable error report into a client-side parse + * failure (the handler substitutes a sentinel when a request's id is unreadable). + */ +export const rpcIdSchema = z.string(); +/** Error body: discriminated by code, per-branch details aligned to RpcErrorDetailsMap; details is required. */ +export const rpcErrorSchema = z.discriminatedUnion('code', [ + z.object({ code: z.literal('bad-request'), message: z.string(), details: z.object({ issues: z.array(z.custom()) }) }), + z.object({ code: z.literal('cancelled'), message: z.string(), details: z.object({}) }), + z.object({ code: z.literal('session-not-found'), message: z.string(), details: z.object({ sessionId: z.string() }) }), + z.object({ code: z.literal('model-unavailable'), message: z.string(), details: z.object({ provider: z.string(), model: z.string() }) }), + z.object({ code: z.literal('session-conflict'), message: z.string(), details: z.object({ sessionId: z.string(), requestedCwd: z.string(), existingCwd: z.string().optional() }) }), + z.object({ code: z.literal('invalid-time-zone'), message: z.string(), details: z.object({ value: z.string() }) }), + z.object({ code: z.literal('workspace-attach-failed'), message: z.string(), details: z.object({ sessionId: z.string(), workspaceId: z.string() }) }), + z.object({ code: z.literal('workspace-not-found'), message: z.string(), details: z.object({ workspaceId: z.string() }) }), + z.object({ code: z.literal('workspace-invalid-path'), message: z.string(), details: z.object({ path: z.string() }) }), + z.object({ code: z.literal('workspace-name-conflict'), message: z.string(), details: z.object({ name: z.string() }) }), + z.object({ code: z.literal('workspace-move-invalid'), message: z.string(), details: z.object({ workspaceId: z.string(), sessionId: z.string(), beforeSessionId: z.string().optional() }) }), + z.object({ code: z.literal('directory-unreadable'), message: z.string(), details: z.object({ path: z.string() }) }), + z.object({ code: z.literal('directory-exists'), message: z.string(), details: z.object({ path: z.string() }) }), + z.object({ code: z.literal('directory-create-failed'), message: z.string(), details: z.object({ path: z.string() }) }), + z.object({ code: z.literal('directory-picker-unavailable'), message: z.string(), details: z.object({ capability: z.string() }) }), + z.object({ code: z.literal('agent-preset-read-only'), message: z.string(), details: z.object({ agentPreset: z.string(), reason: z.string() }) }), + z.object({ code: z.literal('agent-preset-locked'), message: z.string(), details: z.object({ sessionId: z.string(), agentPreset: z.string() }) }), + z.object({ code: z.literal('agent-preset-conflict'), message: z.string(), details: z.object({ sessionId: z.string(), requestedPreset: z.string(), existingPreset: z.string().optional() }) }), + z.object({ code: z.literal('agent-preset-not-found'), message: z.string(), details: z.object({ agentPreset: z.string(), available: z.array(z.string()) }) }), + z.object({ code: z.literal('agent-preset-invalid'), message: z.string(), details: z.object({ agentPreset: z.string(), reason: z.string() }) }), + z.object({ code: z.literal('agent-busy'), message: z.string(), details: z.object({ reason: z.string() }) }), + z.object({ code: z.literal('attachment-error'), message: z.string(), details: z.object({ reason: z.string() }) }), + z.object({ code: z.literal('queue-item-not-found'), message: z.string(), details: z.object({ itemId: z.string() }) }), + z.object({ code: z.literal('steer-unavailable'), message: z.string(), details: z.object({ itemId: z.string() }) }), + z.object({ code: z.literal('command-error'), message: z.string(), details: z.object({}) }), + z.object({ code: z.literal('unknown-command'), message: z.string(), details: z.object({}) }), + z.object({ code: z.literal('settings-rejected'), message: z.string(), details: z.object({ ns: z.string() }) }), + z.object({ code: z.literal('settings-conflict'), message: z.string(), details: z.object({ ns: z.string(), expected: z.number(), actual: z.number() }) }), + z.object({ code: z.literal('credential-rejected'), message: z.string(), details: z.object({ ref: z.string() }) }), + z.object({ code: z.literal('model-discovery-failed'), message: z.string(), details: z.object({ settingsNs: z.string(), baseURL: z.string().optional() }) }), + z.object({ code: z.literal('title-invalid'), message: z.string(), details: z.object({ sessionId: z.string() }) }), + z.object({ code: z.literal('fork-unavailable'), message: z.string(), details: z.object({ sessionId: z.string() }) }), + z.object({ code: z.literal('subagent-parent-unavailable'), message: z.string(), details: z.object({ parentSessionId: z.string() }) }), + z.object({ code: z.literal('subagent-not-found'), message: z.string(), details: z.object({ parentSessionId: z.string(), childSessionId: z.string() }) }), + z.object({ code: z.literal('subagent-catalog-diagnostic'), message: z.string(), details: z.object({ + parentSessionId: z.string(), + childSessionId: z.string(), + reason: z.union([z.literal('corrupt'), z.literal('unsupported'), z.literal('unavailable')]), + }) }), + z.object({ code: z.literal('subagent-not-resumable'), message: z.string(), details: z.object({ childSessionId: z.string() }) }), + z.object({ code: z.literal('subagent-unauthorized'), message: z.string(), details: z.object({ childSessionId: z.string() }) }), + z.object({ code: z.literal('subagent-delivery-unavailable'), message: z.string(), details: z.object({ childSessionId: z.string() }) }), + z.object({ code: z.literal('internal'), message: z.string(), details: z.object({}) }), +]); +/** + * Business success/failure result schema (generic, reusable). + * @param value - Schema for the business value. + * @returns Schema for RpcResult. + */ +export function rpcResultSchema(value) { + return z.union([ + z.object({ ok: z.literal(true), value }), + z.object({ ok: z.literal(false), error: rpcErrorSchema }), + ]); +} +// ---- The four wire full-form schemas (payload/result.value slots stay wide — business layer does the second parse) ---- +// The wide value slot is optional: a void business result serializes with no +// `value` field at all. Each endpoint's own second parse still requires its +// declared value, so absence never passes for a method that returns data. +/** ClientRequest full form (payload stays wide — the business layer runs the second parse). */ +export const clientRequestSchema = z.object({ + type: z.literal('client-request'), + rpcId: rpcIdSchema, + method: z.string(), + payload: z.unknown(), +}); +/** ServerResponse full form (result.value stays wide). */ +export const serverResponseSchema = z.object({ + type: z.literal('server-response'), + rpcId: rpcIdSchema, + result: rpcResultSchema(z.unknown().optional()), +}); +/** ServerRequest full form (payload stays wide). */ +export const serverRequestSchema = z.object({ + type: z.literal('server-request'), + rpcId: rpcIdSchema, + method: z.string(), + payload: z.unknown(), +}); +/** ClientResponse full form (result.value stays wide). */ +export const clientResponseSchema = z.object({ + type: z.literal('client-response'), + rpcId: rpcIdSchema, + result: rpcResultSchema(z.unknown().optional()), +}); +/** Wire full-form union (discriminated by type). */ +export const rpcMessageSchema = z.discriminatedUnion('type', [ + clientRequestSchema, + serverResponseSchema, + serverRequestSchema, + clientResponseSchema, +]); +/** Carrier receipt schema. */ +export const rpcReceiptSchema = z.union([ + z.object({ accepted: z.literal(true) }), + z.object({ accepted: z.literal(false), reason: z.union([z.literal('not-pending'), z.literal('bad-response')]) }), +]); +//# sourceMappingURL=rpc.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.d.ts new file mode 100644 index 0000000..de81826 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.d.ts @@ -0,0 +1,12 @@ +/** Maximum number of sessions returned by one sidebar search. */ +export declare const SESSION_SEARCH_RESULT_LIMIT = 20; +/** Maximum snippet length in Unicode code points. */ +export declare const SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS = 240; +/** + * Return the longest prefix containing at most `maximum` Unicode code points. + * @param value - text to bound. + * @param maximum - non-negative code-point limit. + * @returns `value` unchanged when it fits, otherwise a code-point-safe prefix. + */ +export declare function truncateUnicodeCodePoints(value: string, maximum: number): string; +//# sourceMappingURL=session-search.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js new file mode 100644 index 0000000..14063a3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js @@ -0,0 +1,22 @@ +/** Maximum number of sessions returned by one sidebar search. */ +export const SESSION_SEARCH_RESULT_LIMIT = 20; +/** Maximum snippet length in Unicode code points. */ +export const SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS = 240; +/** + * Return the longest prefix containing at most `maximum` Unicode code points. + * @param value - text to bound. + * @param maximum - non-negative code-point limit. + * @returns `value` unchanged when it fits, otherwise a code-point-safe prefix. + */ +export function truncateUnicodeCodePoints(value, maximum) { + let count = 0; + let end = 0; + for (const codePoint of value) { + if (count === maximum) + return value.slice(0, end); + count++; + end += codePoint.length; + } + return value; +} +//# sourceMappingURL=session-search.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.d.ts new file mode 100644 index 0000000..48132be --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.d.ts @@ -0,0 +1,407 @@ +/** + * sessions domain contract. Method signatures are the source of truth: + * unary methods take the RpcRequest

narrow form and the impl echoes rpcId; everything + * else references RequestPayload<'session.*'> / ResponseValue<'session.*'>. + */ +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { AttachmentIdType, ImageAttachmentLimits, ImageAttachmentRef, ImageMediaType } from '@deepseek-ai/dsh-attachment'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm/types'; +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session/types'; +import type { SessionProjectionMap } from '@deepseek-ai/dsh-session-projection/types'; +import type { RpcId, RpcRequest, RpcResponse } from './rpc.ts'; +import type { ToolEventView } from './events.ts'; +import type { WorkspaceId } from './workspace.ts'; +declare module '@deepseek-ai/dsh-session-projection/types' { + interface SessionProjectionMap { + /** + * Session-list hints persisted by the projection cache. `blank: false` + * is monotonic and may suppress a cold-log probe; `blank: true` is only a + * checkpoint-prefix fact and must not hide a cold Session without direct + * verification. `lastPromptAt` is the latest human-authored prompt time. + */ + sessionListMetadata: SessionListMetadata; + /** + * The deployment's image-intake limits: the attachments service's config + * as this proxy enforces it at prompt admission, constant per host boot. + * Clients pre-check count and bytes at intake and show the limits in + * upload affordances. Key absence means no attachment service is + * composed — clients skip the pre-check and let the host answer. + */ + imageLimits: ImageAttachmentLimits; + } +} +/** Persisted hints used to summarize a cold Session without reading a large log. */ +export interface SessionListMetadata { + /** Whether the checkpoint prefix contains no turn/start event. */ + blank: boolean; + /** Latest source.kind=user message time in the checkpoint prefix. */ + lastPromptAt: number | null; +} +declare module '@deepseek-ai/dsh-llm' { + interface MessageSourceMap { + /** + * The prompt's rpcId is passed through MessageSource into the `user/message` event + * (the client uses it to reconcile the optimistically + * echoed provisional message with the event stream). kind stays `'user'` — the model face + * carries no transport vocabulary; rpcId and the optional Host-validated browser zone are + * durable JSON fields passed back to the client with the event. + */ + 'user-rpc': { + kind: 'user'; + rpcId: RpcId; + clientTimeZone?: string; + }; + } +} +/** + * One history page entry: the raw event plus the optional host-computed render + * intent (same semantics as the mux frame's `view` slot — a pagination-time + * derivation, never persisted). + */ +export interface HistoryEntry { + event: SessionEvent; + view?: ToolEventView; +} +/** + * The projection baseline riding the history tail page: one synchronous cut + * over every registered projection unit, read from the registry's watermark + * cache. `asOfSeq` is the seq of the last committed event every value + * reflects — the window tail event seq (`-1` for an empty log, mirroring + * `session/subscribed.lastSeq`), directly comparable with + * `session/projection` frame seqs under the client's higher-seq-wins rule. A + * key absent from `values` means the capability is absent (its domain plugin + * is unmounted). + */ +export interface SessionProjectionsBlock { + /** Seq of the last event the values reflect; -1 for an empty log. */ + asOfSeq: number; + /** Whole current value per registered projection key. */ + values: Partial; +} +/** Browser-submitted prompt content; the host promotes image bytes to durable references. */ +export type PromptContentPart = { + type: 'text'; + text: string; +} | { + type: 'image'; + mediaType: ImageMediaType; + data: string; + name?: string; +}; +/** Complete model selection for one session. */ +export interface ModelSelection { + /** Registered provider route. */ + provider: string; + /** Provider-owned model id. */ + model: string; + /** Adapter-owned reasoning effort; absence preserves adapter/provider default behavior. */ + reasoningEffort?: string; +} +/** One adapter-owned reasoning effort displayed for an exact model route. */ +export interface ModelReasoningEffort { + /** Opaque value submitted back to the owning adapter. */ + id: string; + /** Adapter-supplied display name. */ + name: string; + /** Optional adapter-supplied description. */ + description?: string; +} +/** Selectable reasoning metadata for one exact model route. */ +export interface ModelReasoning { + /** Efforts in adapter-preferred display order. */ + efforts: ModelReasoningEffort[]; + /** Adapter-configured default; absence preserves the provider default. */ + defaultEffort?: string; +} +/** One model displayed inside its provider group. */ +export interface ModelCatalogModel { + /** Provider-owned model id. */ + id: string; + /** Provider-supplied display name. */ + name: string; + /** Optional provider-supplied description. */ + description?: string; + /** Exact-route reasoning metadata when the adapter exposes it. */ + reasoning?: ModelReasoning; +} +/** One provider and the models it advertised successfully. */ +export interface ModelProviderGroup { + /** Provider route id used for requests. */ + id: string; + /** Provider display name. */ + name: string; + /** Models in provider-preferred order. */ + models: ModelCatalogModel[]; +} +/** A provider whose asynchronous catalog lookup failed. */ +export interface ModelCatalogFailure { + /** Provider route id. */ + id: string; + /** Provider display name. */ + name: string; + /** Lookup failure diagnostic. */ + message: string; +} +/** Detached model-directory snapshot for one session. */ +export interface SessionModels { + /** Model selection for the session's next assembled step. */ + current: ModelSelection; + /** + * Whether an adapter currently serves `current.provider`, and therefore + * whether this session can start a turn at all. Deliberately NOT derivable + * from `groups`: catalog membership is advisory, so a route serving a model + * it stopped advertising is absent from the groups yet perfectly usable, + * while a route whose adapter is gone can serve nothing. A surface that + * blocks input must read this rather than the groups. + */ + routable: boolean; + /** Successfully loaded provider groups. */ + groups: ModelProviderGroup[]; + /** Provider-local failures; successful groups remain usable. */ + failures: ModelCatalogFailure[]; +} +/** A client-requested mutation of one still-pending queue item. */ +export type QueueAction = { + kind: 'edit'; + content: ContentBlock[]; +} | { + kind: 'remove'; +} | { + kind: 'steer'; +}; +/** One Session list entry. */ +export interface SessionSummary { + sessionId: SessionId; + /** + * The later of creation and the latest human-authored prompt. Attached + * Sessions fold their live log; cold Sessions use a projection-cache hint or + * an exact small-artifact read, falling back to creation time. + */ + updatedAt: number; + /** Status of the attached agent; always false for cold (unattached) sessions. */ + running: boolean; + /** + * Derived conversation-not-started bit: true while no turn has run. + * Standalone plugin events — command lifecycle + * records, plan/mode, titles, goals — do not open a turn and therefore do + * not clear it. Clients hide blank Sessions from lists and reuse them for + * New Session on the same workspace. A cold Session is true only when a + * small-artifact read verifies that no `turn/start` exists; unavailable + * or oversized artifacts conservatively report false. + */ + blank: boolean; + /** fork/spawn lineage (session.header.parentSession passthrough); absent for root sessions. */ + parentSessionId?: SessionId; + /** Coarse durable origin used by navigation surfaces; never proves resumability. */ + origin?: 'subagent'; + /** Session working directory (header.cwd passthrough); absent when unrecorded. */ + cwd?: string; + /** + * Agent preset this session's agent was composed from (header passthrough); + * absent when the deployment composes no presets. A surface offering a + * switch reads this to show what the session actually runs rather than what + * the deployment currently defaults to. + */ + agentPreset?: string; + /** + * Projection baseline for this row, with zero log loads: attached sessions + * read the registry's live watermark cut; cold sessions read the persisted + * projection cache's stored rows — as stale as that session's last durable + * checkpoint (`asOfSeq` says exactly how stale), never wrong, and directly + * seedable into the client's per-session value store under its + * higher-seq-wins rule (a list baseline can never overwrite a newer push + * frame). Absent when no value is available (no registry, no cache row for + * a cold session, or a fail-soft cache read miss); a listing client treats + * absence as "no title yet", exactly like a blank session. + */ + projections?: SessionProjectionsBlock; +} +/** One session-content search result; display metadata stays owned by `session.list`. */ +export interface SessionSearchItem { + sessionId: SessionId; + /** Plain-text excerpt around the strongest matching visible message. */ + snippet: string; +} +/** Session-domain unary methods (the map keys session.* of RpcMethodMap). */ +export interface SessionsApi { + /** Lists persisted sessions (updatedAt descending). v1 returns everything; cursor is a reserved seat, unimplemented. */ + list(request: RpcRequest<{ + cursor?: string; + }>): Promise>; + /** + * Searches the current user/assistant/steering message surface across + * sessions visible to `list`. Results contain at most 20 sessions and carry + * no continuation cursor; `hasMore` asks the client to refine the query. + */ + search(request: RpcRequest<{ + query: string; + }>, signal: AbortSignal): Promise>; + /** + * Creates a real session and its idle agent. At most one of `workspaceId` / + * `cwd` is accepted; an omitted project uses the Host cwd. A caller may + * preallocate `sessionId`: retries with the same id and cwd return the same + * session, while a different cwd fails with `session-conflict`. Workspace + * creation attaches the session after publication; an attach failure + * returns `workspace-attach-failed` with the published session id. + * + * `agentPreset` names the composition the new session's agent is built + * from; omitted, the effective default applies — the user's stored choice + * where one exists, else the deployment's own. The resolved id is stored on + * the session header, so a later resume rebuilds the same agent. An unknown + * id fails with `agent-preset-not-found`, and a preset whose composition + * cannot be mounted fails with `agent-preset-invalid`. + */ + create(request: RpcRequest<{ + workspaceId?: WorkspaceId; + cwd?: string; + sessionId?: SessionId; + agentPreset?: string; + }>): Promise>; + /** + * Reads a window of history events; page boundaries align to append-origin message + * boundaries: one page = all raw events owned by a whole number of such messages (including + * their chunk / tool events), never cut mid-message. Model-only replacement copies consume no + * `maxMessages`, so a compaction's `compaction/summary` record stays on the page of its replacement. The tail + * page (beforeSeq absent) additionally carries the in-flight + * partial — chunk events already emitted for the last unfinalized message. + * Each entry pairs the raw SessionEvent with the host-computed view (tool events whose + * presenter produced one, evaluated against the registry at pagination time); the client + * rebuilds the surface from the events with the shared fold. + * The tail page — and only the tail page — additionally carries `projections` + * when the deployment mounts the session-projection registry: every moment + * the client needs a fresh baseline already pulls the tail page, and + * loadOlder (the only beforeSeq path) is the only path that never needs one. + * A deployment without the registry serves histories without the block. + * Reading history uses an attached Session or persistence inspection and + * never resumes or publishes an Agent. + */ + history(request: RpcRequest<{ + sessionId: SessionId; + beforeSeq?: number; + maxMessages?: number; + }>): Promise>; + /** + * Reads a fresh advisory model directory for an ordinary session. Provider + * lookups run independently; subagents reject with `agent-busy`. + */ + models(request: RpcRequest<{ + sessionId: SessionId; + }>): Promise>; + /** + * Selects the complete model selection for this session. Exact model metadata + * validates an optional reasoning effort, while catalog membership remains + * advisory. Session-backed subagents reject with `agent-busy`. + */ + selectModel(request: RpcRequest<{ + sessionId: SessionId; + provider: string; + model: string; + reasoningEffort?: string; + }>): Promise>; + /** + * Renames a session: appends a `session/title` event with the `user` + * source, which pins the title against automatic regeneration. The + * normalized accepted title and the title event's seq return so the caller + * can settle its projection cell without waiting for the push frame. A + * title that normalizes to empty fails with `title-invalid`. + * Session-backed subagents reject with `agent-busy`. + */ + rename(request: RpcRequest<{ + sessionId: SessionId; + title: string; + }>): Promise>; + /** + * Sends a message. content is core's ContentBlock[] verbatim; mode maps 1:1 — queue→send, steer→steer. + * A prompt whose content is exactly one text block starting with '/' is a slash command: the host + * executes it through the command registry (mode-agnostic) and it is never sent to the model. A + * successful command returns ok with the command slot (its success text, when the command produced + * one — carried for future rendering; the state change is the feedback). A usage/state error is an + * RPC error with code command-error; an unrecognized name is an RPC error with code unknown-command. + */ + /** + * Forks a new session from a completed-turn prefix of the source. `atSeq` + * anchors the cut: the boundary is the first `turn/end` at or after it + * (a message's fork button passes the message seq, so the fork includes + * that whole turn); a boundary past the log end, or an omitted `atSeq`, + * falls back to the source's last completed turn. An in-log anchor whose + * turn is still open fails with `fork-unavailable` instead of clipping to + * an earlier turn. The child inherits the source cwd, latest logged model + * target and `parentSessionId` lineage; the seed prefix carries the source + * title. Reading the source uses attached state or persistence inspection + * without acquiring an Agent. Workspace attachment follows the source + * directly, or the nearest workspace-owning ancestor when the source is a + * subagent. + */ + fork(request: RpcRequest<{ + sessionId: SessionId; + atSeq?: number; + }>): Promise>; + /** + * Sends text and temporary image bytes to an ordinary session Agent after durable host admission. + * Browser callers attach their current IANA zone; + * the Host validates, canonicalizes, and records it on that exact user message. Omission remains + * valid for non-browser callers. Session-backed subagents reject with `agent-busy` and use + * `subagent.prompt`. + */ + prompt(request: RpcRequest<{ + sessionId: SessionId; + mode: 'queue' | 'steer'; + content: PromptContentPart[]; + clientTimeZone?: string; + }>): Promise>; + /** Reads one durable image after proving that this session's log references its id. */ + attachment(request: RpcRequest<{ + sessionId: SessionId; + attachmentId: AttachmentIdType; + }>): Promise>; + /** + * Edits, removes, or strictly steers one pending queued occurrence on an ordinary session. + * Session-backed subagents reject with `agent-busy`. + */ + updateQueue(request: RpcRequest<{ + sessionId: SessionId; + itemId: MessageId; + action: QueueAction; + }>): Promise>; + /** + * Stops an ordinary session's active turn, preserving pending inbox work + * that resumes in FIFO order after cancellation settles. Session-backed + * subagents reject with `agent-busy`. + */ + cancel(request: RpcRequest<{ + sessionId: SessionId; + }>): Promise>; +} +//# sourceMappingURL=sessions.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.js new file mode 100644 index 0000000..41e4489 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.js @@ -0,0 +1,7 @@ +/** + * sessions domain contract. Method signatures are the source of truth: + * unary methods take the RpcRequest

narrow form and the impl echoes rpcId; everything + * else references RequestPayload<'session.*'> / ResponseValue<'session.*'>. + */ +export {}; +//# sourceMappingURL=sessions.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.d.ts new file mode 100644 index 0000000..f638b0d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.d.ts @@ -0,0 +1,279 @@ +/** + * sessions domain zod schemas (names derived from map keys: sessionListRequestSchema / + * sessionListValueSchema). SessionEvent passthrough = strict envelope (type/seq/time) + wide + * data: the merge-extensible event API keeps an unknown-type branch at the union level, + * with no field-level passthrough. SessionId brand cast point: sessionIdSchema, and only there. + */ +import { z } from 'zod'; +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session/types'; +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { RequestPayload, ResponseValue } from './rpc-map.ts'; +import type { Wire } from './rpc.schema.ts'; +import type { HistoryEntry, SessionListMetadata, SessionProjectionsBlock, SessionSummary } from './sessions.ts'; +import type { ToolEventView } from './events.ts'; +import type { AttachmentIdType, ImageAttachmentLimits, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'; +import type { WorkspaceId } from './workspace.ts'; +/** SessionId: one brand cast after schema validation (the only cast point in this domain). */ +export declare const sessionIdSchema: z.ZodType; +/** MessageId: one brand cast after non-empty string validation. */ +export declare const messageIdSchema: z.ZodType; +/** + * WorkspaceId: the workspace domain's one brand cast. Hosted here rather + * than in workspace.schema because session.create references it while + * workspace.schema references sessionIdSchema — schema modules must stay a + * DAG (both casts used at module top level; a cycle is a load-time TDZ). + */ +export declare const workspaceIdSchema: z.ZodType; +/** SessionEvent passthrough: strict envelope, wide data (the client fold handles unknown types via its documented default). */ +export declare const sessionEventSchema: z.ZodType; +/** SessionSummary row of session.list (`projections` reuses the history block's shape and schema). */ +export declare const sessionSummarySchema: z.ZodType>; +/** session.list request payload (cursor is a reserved seat, unimplemented in v1). */ +export declare const sessionListRequestSchema: z.ZodObject<{ + cursor: z.ZodOptional; +}, z.core.$strip>; +/** session.list response value. */ +export declare const sessionListValueSchema: z.ZodType>>; +/** session.search request payload. */ +export declare const sessionSearchRequestSchema: z.ZodObject<{ + query: z.ZodString; +}, z.core.$strip>; +/** One session.search result. */ +export declare const sessionSearchItemSchema: z.ZodObject<{ + sessionId: z.ZodType>; + snippet: z.ZodString; +}, z.core.$strip>; +/** session.search response value. */ +export declare const sessionSearchValueSchema: z.ZodObject<{ + items: z.ZodArray>; + snippet: z.ZodString; + }, z.core.$strip>>; + hasMore: z.ZodBoolean; +}, z.core.$strip>; +/** session.create request payload (at most one of workspaceId / cwd). */ +export declare const sessionCreateRequestSchema: z.ZodObject<{ + workspaceId: z.ZodOptional>>; + cwd: z.ZodOptional; + sessionId: z.ZodOptional>>; + agentPreset: z.ZodOptional; +}, z.core.$strip>; +/** session.create response value. */ +export declare const sessionCreateValueSchema: z.ZodObject<{ + sessionId: z.ZodType>; + agentPreset: z.ZodOptional; +}, z.core.$strip>; +/** session.rename request payload (raw title; host-side normalization decides acceptance). */ +export declare const sessionRenameRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + title: z.ZodString; +}, z.core.$strip>; +/** session.rename response value (the normalized accepted title and its event seq). */ +export declare const sessionRenameValueSchema: z.ZodObject<{ + title: z.ZodString; + seq: z.ZodNumber; +}, z.core.$strip>; +/** session.fork request payload (atSeq anchors the completed-turn cut). */ +export declare const sessionForkRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + atSeq: z.ZodOptional; +}, z.core.$strip>; +/** session.fork response value (the child session id). */ +export declare const sessionForkValueSchema: z.ZodObject<{ + sessionId: z.ZodType>; +}, z.core.$strip>; +/** session.history request payload (beforeSeq/maxMessages page backwards from the window tail). */ +export declare const sessionHistoryRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + beforeSeq: z.ZodOptional; + maxMessages: z.ZodOptional; +}, z.core.$strip>; +/** Complete provider/model selection. */ +export declare const modelSelectionSchema: z.ZodObject<{ + provider: z.ZodString; + model: z.ZodString; + reasoningEffort: z.ZodOptional; +}, z.core.$strip>; +/** One adapter-owned reasoning effort. */ +export declare const modelReasoningEffortSchema: z.ZodObject<{ + id: z.ZodString; + name: z.ZodString; + description: z.ZodOptional; +}, z.core.$strip>; +/** Exact-model reasoning metadata. */ +export declare const modelReasoningSchema: z.ZodObject<{ + efforts: z.ZodArray; + }, z.core.$strip>>; + defaultEffort: z.ZodOptional; +}, z.core.$strip>; +/** One advisory model entry inside a provider group. */ +export declare const modelCatalogModelSchema: z.ZodObject<{ + id: z.ZodString; + name: z.ZodString; + description: z.ZodOptional; + reasoning: z.ZodOptional; + }, z.core.$strip>>; + defaultEffort: z.ZodOptional; + }, z.core.$strip>>; +}, z.core.$strip>; +/** One successfully loaded provider group. */ +export declare const modelProviderGroupSchema: z.ZodObject<{ + id: z.ZodString; + name: z.ZodString; + models: z.ZodArray; + reasoning: z.ZodOptional; + }, z.core.$strip>>; + defaultEffort: z.ZodOptional; + }, z.core.$strip>>; + }, z.core.$strip>>; +}, z.core.$strip>; +/** One provider-local catalog failure. */ +export declare const modelCatalogFailureSchema: z.ZodObject<{ + id: z.ZodString; + name: z.ZodString; + message: z.ZodString; +}, z.core.$strip>; +/** + * ToolEventView passthrough: lock only the `for` discriminant and the presence + * of a card-tagged `view` object. The view interior is a host-computed product + * the client reads without echoing back; deep-validating it would hand-copy + * the dsh-tools vocabulary into this schema and drift with it. + */ +export declare const toolEventViewSchema: z.ZodType; +/** One session.history item: the session event plus its optional host-computed tool view. */ +export declare const historyEntrySchema: z.ZodType>; +/** + * Projection baseline passthrough: `values` stays a wide record — each value + * was already parsed by its provider's own schema on the host side, and + * deep-validating here would import every domain's schema into the carrier. + */ +export declare const sessionProjectionsBlockSchema: z.ZodType>; +/** Host-side validation for the persisted Session-list projection. */ +export declare const sessionListMetadataProjectionSchema: z.ZodType; +/** + * imageLimits projection unit schema (host-side view validation). zod widens + * `readonly ImageMediaType[]` to `string[]`; on the JSON wire the two + * serialize identically, so the cast records exactly that widening. + */ +export declare const imageLimitsProjectionSchema: z.ZodType; +/** session.history response value (projections rides the tail page only). */ +export declare const sessionHistoryValueSchema: z.ZodType>>; +/** session.models request payload. */ +export declare const sessionModelsRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; +}, z.core.$strip>; +/** session.models response value. */ +export declare const sessionModelsValueSchema: z.ZodObject<{ + current: z.ZodObject<{ + provider: z.ZodString; + model: z.ZodString; + reasoningEffort: z.ZodOptional; + }, z.core.$strip>; + routable: z.ZodBoolean; + groups: z.ZodArray; + reasoning: z.ZodOptional; + }, z.core.$strip>>; + defaultEffort: z.ZodOptional; + }, z.core.$strip>>; + }, z.core.$strip>>; + }, z.core.$strip>>; + failures: z.ZodArray>; +}, z.core.$strip>; +/** session.selectModel request payload. */ +export declare const sessionSelectModelRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + provider: z.ZodString; + model: z.ZodString; + reasoningEffort: z.ZodOptional; +}, z.core.$strip>; +/** session.selectModel response value. */ +export declare const sessionSelectModelValueSchema: z.ZodObject<{ + selected: z.ZodObject<{ + provider: z.ZodString; + model: z.ZodString; + reasoningEffort: z.ZodOptional; + }, z.core.$strip>; +}, z.core.$strip>; +/** ContentBlock passthrough: core is merge-extensible — the type discriminant envelope is strict, the rest stays wide. */ +export declare const contentBlockSchema: z.ZodObject<{ + type: z.ZodString; +}, z.core.$loose>; +/** Raster image media types accepted by the version-one browser wire. */ +export declare const imageMediaTypeSchema: z.ZodUnion, z.ZodLiteral<"image/jpeg">, z.ZodLiteral<"image/webp">, z.ZodLiteral<"image/gif">]>; +/** Prompt wire content is intentionally narrower than merge-extensible durable core content. */ +export declare const promptContentPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{ + type: z.ZodLiteral<"text">; + text: z.ZodString; +}, z.core.$strip>, z.ZodObject<{ + type: z.ZodLiteral<"image">; + mediaType: z.ZodUnion, z.ZodLiteral<"image/jpeg">, z.ZodLiteral<"image/webp">, z.ZodLiteral<"image/gif">]>; + data: z.ZodString; + name: z.ZodOptional; +}, z.core.$strip>], "type">; +/** session.prompt request payload, including optional browser-local request provenance. */ +export declare const sessionPromptRequestSchema: z.ZodType>; +/** session.prompt response value (the command slot appears only when the prompt dispatched a slash command). */ +export declare const sessionPromptValueSchema: z.ZodObject<{ + accepted: z.ZodLiteral; + command: z.ZodOptional; + text: z.ZodOptional; + }, z.core.$strip>>; +}, z.core.$strip>; +/** Opaque attachment id after string-shape validation. */ +export declare const attachmentIdSchema: z.ZodType; +/** Durable image reference returned from the authenticated session lookup. */ +export declare const imageAttachmentRefSchema: z.ZodType; +/** session.attachment request payload. */ +export declare const sessionAttachmentRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; + attachmentId: z.ZodType>; +}, z.core.$strip>; +/** session.attachment response value. */ +export declare const sessionAttachmentValueSchema: z.ZodObject<{ + attachment: z.ZodType>; + data: z.ZodString; +}, z.core.$strip>; +/** session.updateQueue request payload. */ +export declare const sessionUpdateQueueRequestSchema: z.ZodType>; +/** session.updateQueue response value. */ +export declare const sessionUpdateQueueValueSchema: z.ZodObject<{ + accepted: z.ZodLiteral; +}, z.core.$strip>; +/** session.cancel request payload. */ +export declare const sessionCancelRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; +}, z.core.$strip>; +/** session.cancel response value. */ +export declare const sessionCancelValueSchema: z.ZodObject<{ + accepted: z.ZodLiteral; +}, z.core.$strip>; +//# sourceMappingURL=sessions.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js new file mode 100644 index 0000000..026ffb3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js @@ -0,0 +1,282 @@ +/** + * sessions domain zod schemas (names derived from map keys: sessionListRequestSchema / + * sessionListValueSchema). SessionEvent passthrough = strict envelope (type/seq/time) + wide + * data: the merge-extensible event API keeps an unknown-type branch at the union level, + * with no field-level passthrough. SessionId brand cast point: sessionIdSchema, and only there. + */ +import { z } from 'zod'; +import { SESSION_SEARCH_RESULT_LIMIT, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS, truncateUnicodeCodePoints, } from "./session-search.js"; +/** SessionId: one brand cast after schema validation (the only cast point in this domain). */ +export const sessionIdSchema = z.string().min(1); +/** MessageId: one brand cast after non-empty string validation. */ +export const messageIdSchema = z.string().min(1); +/** + * WorkspaceId: the workspace domain's one brand cast. Hosted here rather + * than in workspace.schema because session.create references it while + * workspace.schema references sessionIdSchema — schema modules must stay a + * DAG (both casts used at module top level; a cycle is a load-time TDZ). + */ +export const workspaceIdSchema = z.string().min(1); +/** SessionEvent passthrough: strict envelope, wide data (the client fold handles unknown types via its documented default). */ +export const sessionEventSchema = z.object({ + type: z.string(), + seq: z.number().int().nonnegative(), + time: z.number(), + data: z.unknown(), + sourceEventSeqs: z.array(z.number()).optional(), + surfaceOp: z.unknown().optional(), + ignorable: z.literal(true).optional(), +}); +/** SessionSummary row of session.list (`projections` reuses the history block's shape and schema). */ +export const sessionSummarySchema = z.object({ + sessionId: sessionIdSchema, + updatedAt: z.number(), + running: z.boolean(), + blank: z.boolean(), + parentSessionId: sessionIdSchema.optional(), + origin: z.literal('subagent').optional(), + cwd: z.string().optional(), + agentPreset: z.string().optional(), + projections: z.lazy(() => sessionProjectionsBlockSchema).optional(), +}); +/** session.list request payload (cursor is a reserved seat, unimplemented in v1). */ +export const sessionListRequestSchema = z.object({ + cursor: z.string().optional(), +}); +/** session.list response value. */ +export const sessionListValueSchema = z.object({ + items: z.array(sessionSummarySchema), +}); +/** Fixed wire bound for one interactive sidebar query. */ +const SESSION_SEARCH_QUERY_MAX_CHARS = 500; +/** session.search request payload. */ +export const sessionSearchRequestSchema = z.object({ + query: z.string().trim().min(1).max(SESSION_SEARCH_QUERY_MAX_CHARS) + .refine(query => !query.includes('\0'), { message: 'search query must not contain NUL' }), +}); +/** One session.search result. */ +export const sessionSearchItemSchema = z.object({ + sessionId: sessionIdSchema, + snippet: z.string().refine(snippet => truncateUnicodeCodePoints(snippet, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS) === snippet, { message: `search snippet must contain at most ${SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS} Unicode code points` }), +}); +/** session.search response value. */ +export const sessionSearchValueSchema = z.object({ + items: z.array(sessionSearchItemSchema).max(SESSION_SEARCH_RESULT_LIMIT), + hasMore: z.boolean(), +}); +/** session.create request payload (at most one of workspaceId / cwd). */ +export const sessionCreateRequestSchema = z.object({ + workspaceId: workspaceIdSchema.optional(), + cwd: z.string().optional(), + sessionId: sessionIdSchema.optional(), + agentPreset: z.string().optional(), +}).refine(payload => payload.workspaceId === undefined || payload.cwd === undefined, { message: 'session.create accepts workspaceId or cwd, not both' }); +/** session.create response value. */ +export const sessionCreateValueSchema = z.object({ + sessionId: sessionIdSchema, + agentPreset: z.string().optional(), +}); +/** session.rename request payload (raw title; host-side normalization decides acceptance). */ +export const sessionRenameRequestSchema = z.object({ + sessionId: sessionIdSchema, + title: z.string(), +}); +/** session.rename response value (the normalized accepted title and its event seq). */ +export const sessionRenameValueSchema = z.object({ + title: z.string().min(1), + seq: z.number().int().nonnegative(), +}); +/** session.fork request payload (atSeq anchors the completed-turn cut). */ +export const sessionForkRequestSchema = z.object({ + sessionId: sessionIdSchema, + atSeq: z.number().int().nonnegative().optional(), +}); +/** session.fork response value (the child session id). */ +export const sessionForkValueSchema = z.object({ + sessionId: sessionIdSchema, +}); +/** session.history request payload (beforeSeq/maxMessages page backwards from the window tail). */ +export const sessionHistoryRequestSchema = z.object({ + sessionId: sessionIdSchema, + beforeSeq: z.number().int().nonnegative().optional(), + maxMessages: z.number().int().positive().optional(), +}); +/** Complete provider/model selection. */ +export const modelSelectionSchema = z.object({ + provider: z.string().min(1), + model: z.string().min(1), + reasoningEffort: z.string().min(1).optional(), +}); +/** One adapter-owned reasoning effort. */ +export const modelReasoningEffortSchema = z.object({ + id: z.string().min(1), + name: z.string().min(1), + description: z.string().optional(), +}); +/** Exact-model reasoning metadata. */ +export const modelReasoningSchema = z.object({ + efforts: z.array(modelReasoningEffortSchema).min(1), + defaultEffort: z.string().min(1).optional(), +}); +/** One advisory model entry inside a provider group. */ +export const modelCatalogModelSchema = z.object({ + id: z.string().min(1), + name: z.string().min(1), + description: z.string().optional(), + reasoning: modelReasoningSchema.optional(), +}); +/** One successfully loaded provider group. */ +export const modelProviderGroupSchema = z.object({ + id: z.string().min(1), + name: z.string().min(1), + models: z.array(modelCatalogModelSchema), +}); +/** One provider-local catalog failure. */ +export const modelCatalogFailureSchema = z.object({ + id: z.string().min(1), + name: z.string().min(1), + message: z.string(), +}); +/** + * ToolEventView passthrough: lock only the `for` discriminant and the presence + * of a card-tagged `view` object. The view interior is a host-computed product + * the client reads without echoing back; deep-validating it would hand-copy + * the dsh-tools vocabulary into this schema and drift with it. + */ +export const toolEventViewSchema = z.discriminatedUnion('for', [ + z.object({ for: z.literal('call'), view: z.looseObject({ card: z.string() }) }), + z.object({ for: z.literal('result'), view: z.looseObject({ card: z.string() }) }), +]); +/** One session.history item: the session event plus its optional host-computed tool view. */ +export const historyEntrySchema = z.object({ + event: sessionEventSchema, + view: toolEventViewSchema.optional(), +}); +/** + * Projection baseline passthrough: `values` stays a wide record — each value + * was already parsed by its provider's own schema on the host side, and + * deep-validating here would import every domain's schema into the carrier. + */ +export const sessionProjectionsBlockSchema = z.object({ + // -1 = empty log (the lastSeq convention of session/subscribed). + asOfSeq: z.number().int().min(-1), + values: z.record(z.string(), z.unknown()), +}); +/** Host-side validation for the persisted Session-list projection. */ +export const sessionListMetadataProjectionSchema = z.object({ + blank: z.boolean(), + lastPromptAt: z.number().nullable(), +}); +/** + * imageLimits projection unit schema (host-side view validation). zod widens + * `readonly ImageMediaType[]` to `string[]`; on the JSON wire the two + * serialize identically, so the cast records exactly that widening. + */ +export const imageLimitsProjectionSchema = z.object({ + maxImageBytes: z.number().int().positive(), + maxImagesPerMessage: z.number().int().positive(), + maxMessageImageBytes: z.number().int().positive(), + maxImagePixels: z.number().int().positive(), + mediaTypes: z.array(z.string()), +}); +/** session.history response value (projections rides the tail page only). */ +export const sessionHistoryValueSchema = z.object({ + events: z.array(historyEntrySchema), + hasMore: z.boolean(), + projections: sessionProjectionsBlockSchema.optional(), +}); +/** session.models request payload. */ +export const sessionModelsRequestSchema = z.object({ + sessionId: sessionIdSchema, +}); +/** session.models response value. */ +export const sessionModelsValueSchema = z.object({ + current: modelSelectionSchema, + routable: z.boolean(), + groups: z.array(modelProviderGroupSchema), + failures: z.array(modelCatalogFailureSchema), +}); +/** session.selectModel request payload. */ +export const sessionSelectModelRequestSchema = z.object({ + sessionId: sessionIdSchema, + provider: z.string().min(1), + model: z.string().min(1), + reasoningEffort: z.string().min(1).optional(), +}); +/** session.selectModel response value. */ +export const sessionSelectModelValueSchema = z.object({ + selected: modelSelectionSchema, +}); +/** ContentBlock passthrough: core is merge-extensible — the type discriminant envelope is strict, the rest stays wide. */ +export const contentBlockSchema = z.looseObject({ type: z.string() }); +/** Raster image media types accepted by the version-one browser wire. */ +export const imageMediaTypeSchema = z.union([ + z.literal('image/png'), + z.literal('image/jpeg'), + z.literal('image/webp'), + z.literal('image/gif'), +]); +/** Prompt wire content is intentionally narrower than merge-extensible durable core content. */ +export const promptContentPartSchema = z.discriminatedUnion('type', [ + z.object({ type: z.literal('text'), text: z.string() }), + z.object({ type: z.literal('image'), mediaType: imageMediaTypeSchema, data: z.string(), name: z.string().optional() }), +]); +/** session.prompt request payload, including optional browser-local request provenance. */ +export const sessionPromptRequestSchema = z.object({ + sessionId: sessionIdSchema, + mode: z.union([z.literal('queue'), z.literal('steer')]), + content: z.array(promptContentPartSchema), + clientTimeZone: z.string().optional(), +}); +/** session.prompt response value (the command slot appears only when the prompt dispatched a slash command). */ +export const sessionPromptValueSchema = z.object({ + accepted: z.literal(true), + command: z.object({ + kind: z.literal('success'), + text: z.string().optional(), + }).optional(), +}); +/** Opaque attachment id after string-shape validation. */ +export const attachmentIdSchema = z.string().min(1); +/** Durable image reference returned from the authenticated session lookup. */ +export const imageAttachmentRefSchema = z.object({ + attachmentId: attachmentIdSchema, + mediaType: imageMediaTypeSchema, + bytes: z.number().int().positive(), + width: z.number().int().positive(), + height: z.number().int().positive(), + name: z.string().optional(), +}); +/** session.attachment request payload. */ +export const sessionAttachmentRequestSchema = z.object({ + sessionId: sessionIdSchema, + attachmentId: attachmentIdSchema, +}); +/** session.attachment response value. */ +export const sessionAttachmentValueSchema = z.object({ + attachment: imageAttachmentRefSchema, + data: z.string(), +}); +/** session.updateQueue request payload. */ +export const sessionUpdateQueueRequestSchema = z.object({ + sessionId: sessionIdSchema, + itemId: messageIdSchema, + action: z.discriminatedUnion('kind', [ + z.object({ kind: z.literal('edit'), content: z.array(contentBlockSchema) }), + z.object({ kind: z.literal('remove') }), + z.object({ kind: z.literal('steer') }), + ]), +}); +/** session.updateQueue response value. */ +export const sessionUpdateQueueValueSchema = z.object({ + accepted: z.literal(true), +}); +/** session.cancel request payload. */ +export const sessionCancelRequestSchema = z.object({ + sessionId: sessionIdSchema, +}); +/** session.cancel response value. */ +export const sessionCancelValueSchema = z.object({ + accepted: z.literal(true), +}); +//# sourceMappingURL=sessions.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.d.ts new file mode 100644 index 0000000..c9a56c5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.d.ts @@ -0,0 +1,113 @@ +/** + * settings domain contract: the web face of the user-settings seam + * (`ctx.settings`). Every payload that leaves this domain is redacted by the + * seam (`describe({ redactSecrets: true })` semantics): `role('secret')` + * fields never ride a response in any layer, and the `secrets` slot list is + * how a form learns a write-only field exists and whether it is configured. + */ +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** One schema-declared secret slot inside a redacted namespace value. */ +export interface SettingsSecretView { + /** Path from the section root to the removed field. */ + path: string[]; + /** Whether the slot currently holds a value (the value itself never rides). */ + set: boolean; +} +/** Wire view of one registered settings namespace. */ +export interface SettingsNamespaceView { + /** Namespace key (`llm-deepseek`, `llm-pi-ai`, …). */ + ns: string; + /** Serialized schemastery schema envelope (`schema.toJSON()`); rehydrate with `new Schema(json)`. */ + schema: unknown; + /** Redacted resolved value (schema defaults → composition base → user layer). */ + value: unknown; + /** Redacted composition base layer, when the registrant declared one. */ + base?: unknown; + /** Redacted raw user section, when one exists; a field's presence here marks it user-overridden. */ + user?: unknown; + /** When the owner applies changes. */ + applies: 'live' | 'restart'; + /** Every schema-declared secret slot with its configured state. */ + secrets: SettingsSecretView[]; + /** + * Monotonic revision of the raw user section this view was read at. Send it + * back as `expectedRevision` on a write so a stale editor is refused rather + * than silently overwriting a concurrent change. + */ + revision: number; +} +/** + * One path-addressed edit carried by `settings.mutate`. `set` writes the + * value at the path (creating intermediate objects); `unset` removes it. The + * empty path addresses the section root. + */ +export type SettingsPathOpView = { + op: 'set'; + path: string[]; + value: unknown; +} | { + op: 'unset'; + path: string[]; +}; +/** Settings-domain unary methods (the map keys settings.* of RpcMethodMap). */ +export interface SettingsApi { + /** + * Describe every registered namespace: redacted layered values plus the + * serialized schema a client renders its form from. `hasDocument` reports + * whether a file-backed provider owns a local document without exposing its + * Host path. This method is loopback-only; `writable: false` (read-only + * provider) tells the client to disable every write control. + */ + describe(request: RpcRequest<{}>): Promise>; + /** + * Materialize the configured local document when absent and ask the Host to + * hand it to the platform text-document opener. macOS forces a text editor; + * Linux and Windows use the desktop file association. The request carries + * no path, so the browser cannot choose an arbitrary Host filesystem target. + */ + openDocument(request: RpcRequest<{}>, signal: AbortSignal): Promise>; + /** + * Merge a patch into one namespace's user layer (validate → persist → + * commit). Secret-role fields may be INCLUDED in the patch (write-only + * direction); a form that leaves a secret untouched simply omits it and the + * merge preserves the stored value. Responds with the namespace's new + * redacted view; a schema or storage rejection is `settings-rejected`. + */ + update(request: RpcRequest<{ + ns: string; + patch: object; + expectedRevision?: number; + }>): Promise>; + /** + * Replace one namespace's user section wholesale — the removal/reset path a + * merge cannot express (`section: {}` resets to composition defaults). Keys + * absent from `section` are dropped, secrets included: a client must first + * fold the descriptor's `user` layer (and re-supply any secret it wants to + * keep) or accept the reset. + */ + replace(request: RpcRequest<{ + ns: string; + section: object; + expectedRevision?: number; + }>): Promise>; + /** + * Apply path-addressed edits to one namespace's user section, resolved + * against the section as stored — NOT against whatever the caller last + * read. This is the removal path for any client holding the redacted + * descriptor: it names the field it means, so a secret the wire never + * returned cannot be deleted as a side effect. `replace` remains the + * deliberate wholesale reset. + */ + mutate(request: RpcRequest<{ + ns: string; + ops: SettingsPathOpView[]; + expectedRevision?: number; + }>): Promise>; +} +//# sourceMappingURL=settings.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.js new file mode 100644 index 0000000..d3fe50c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.js @@ -0,0 +1,9 @@ +/** + * settings domain contract: the web face of the user-settings seam + * (`ctx.settings`). Every payload that leaves this domain is redacted by the + * seam (`describe({ redactSecrets: true })` semantics): `role('secret')` + * fields never ride a response in any layer, and the `secrets` slot list is + * how a form learns a write-only field exists and whether it is configured. + */ +export {}; +//# sourceMappingURL=settings.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.d.ts new file mode 100644 index 0000000..c8b9698 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.d.ts @@ -0,0 +1,115 @@ +/** + * settings domain zod schemas (names derived from map keys: settingsDescribeRequestSchema / + * settingsDescribeValueSchema / settingsUpdate* / settingsReplace*). + */ +import { z } from 'zod'; +import type { Wire } from './rpc.schema.ts'; +import type { SettingsPathOpView } from './settings.ts'; +/** One redacted secret slot. */ +export declare const settingsSecretViewSchema: z.ZodObject<{ + path: z.ZodArray; + set: z.ZodBoolean; +}, z.core.$strip>; +/** SettingsNamespaceView row of settings.describe and the write responses. */ +export declare const settingsNamespaceViewSchema: z.ZodObject<{ + ns: z.ZodString; + schema: z.ZodUnknown; + value: z.ZodUnknown; + base: z.ZodOptional; + user: z.ZodOptional; + applies: z.ZodUnion, z.ZodLiteral<"restart">]>; + secrets: z.ZodArray; + set: z.ZodBoolean; + }, z.core.$strip>>; + revision: z.ZodNumber; +}, z.core.$strip>; +/** settings.describe request payload. */ +export declare const settingsDescribeRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** settings.describe response value. */ +export declare const settingsDescribeValueSchema: z.ZodObject<{ + writable: z.ZodBoolean; + hasDocument: z.ZodBoolean; + namespaces: z.ZodArray; + user: z.ZodOptional; + applies: z.ZodUnion, z.ZodLiteral<"restart">]>; + secrets: z.ZodArray; + set: z.ZodBoolean; + }, z.core.$strip>>; + revision: z.ZodNumber; + }, z.core.$strip>>; +}, z.core.$strip>; +/** settings.openDocument request payload. */ +export declare const settingsOpenDocumentRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** settings.openDocument response value. */ +export declare const settingsOpenDocumentValueSchema: z.ZodObject<{ + opened: z.ZodLiteral; +}, z.core.$strip>; +/** settings.update request payload. */ +export declare const settingsUpdateRequestSchema: z.ZodObject<{ + ns: z.ZodString; + patch: z.ZodRecord; + expectedRevision: z.ZodOptional; +}, z.core.$strip>; +/** settings.update response value: the namespace's new redacted view. */ +export declare const settingsUpdateValueSchema: z.ZodObject<{ + ns: z.ZodString; + schema: z.ZodUnknown; + value: z.ZodUnknown; + base: z.ZodOptional; + user: z.ZodOptional; + applies: z.ZodUnion, z.ZodLiteral<"restart">]>; + secrets: z.ZodArray; + set: z.ZodBoolean; + }, z.core.$strip>>; + revision: z.ZodNumber; +}, z.core.$strip>; +/** settings.replace request payload. */ +export declare const settingsReplaceRequestSchema: z.ZodObject<{ + ns: z.ZodString; + section: z.ZodRecord; + expectedRevision: z.ZodOptional; +}, z.core.$strip>; +/** One path-addressed edit of settings.mutate. */ +export declare const settingsPathOpSchema: z.ZodType>; +/** settings.mutate request payload. */ +export declare const settingsMutateRequestSchema: z.ZodObject<{ + ns: z.ZodString; + ops: z.ZodArray, unknown, z.core.$ZodTypeInternals, unknown>>>; + expectedRevision: z.ZodOptional; +}, z.core.$strip>; +/** settings.mutate response value: the namespace's new redacted view. */ +export declare const settingsMutateValueSchema: z.ZodObject<{ + ns: z.ZodString; + schema: z.ZodUnknown; + value: z.ZodUnknown; + base: z.ZodOptional; + user: z.ZodOptional; + applies: z.ZodUnion, z.ZodLiteral<"restart">]>; + secrets: z.ZodArray; + set: z.ZodBoolean; + }, z.core.$strip>>; + revision: z.ZodNumber; +}, z.core.$strip>; +/** settings.replace response value. */ +export declare const settingsReplaceValueSchema: z.ZodObject<{ + ns: z.ZodString; + schema: z.ZodUnknown; + value: z.ZodUnknown; + base: z.ZodOptional; + user: z.ZodOptional; + applies: z.ZodUnion, z.ZodLiteral<"restart">]>; + secrets: z.ZodArray; + set: z.ZodBoolean; + }, z.core.$strip>>; + revision: z.ZodNumber; +}, z.core.$strip>; +//# sourceMappingURL=settings.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.js new file mode 100644 index 0000000..aaf76f6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/settings.schema.js @@ -0,0 +1,65 @@ +/** + * settings domain zod schemas (names derived from map keys: settingsDescribeRequestSchema / + * settingsDescribeValueSchema / settingsUpdate* / settingsReplace*). + */ +import { z } from 'zod'; +/** One redacted secret slot. */ +export const settingsSecretViewSchema = z.object({ + path: z.array(z.string()), + set: z.boolean(), +}); +/** SettingsNamespaceView row of settings.describe and the write responses. */ +export const settingsNamespaceViewSchema = z.object({ + ns: z.string().min(1), + schema: z.unknown(), + value: z.unknown(), + base: z.unknown().optional(), + user: z.unknown().optional(), + applies: z.union([z.literal('live'), z.literal('restart')]), + secrets: z.array(settingsSecretViewSchema), + revision: z.number(), +}); +/** settings.describe request payload. */ +export const settingsDescribeRequestSchema = z.object({}); +/** settings.describe response value. */ +export const settingsDescribeValueSchema = z.object({ + writable: z.boolean(), + hasDocument: z.boolean(), + namespaces: z.array(settingsNamespaceViewSchema), +}); +/** settings.openDocument request payload. */ +export const settingsOpenDocumentRequestSchema = z.object({}); +/** settings.openDocument response value. */ +export const settingsOpenDocumentValueSchema = z.object({ + opened: z.literal(true), +}); +/** settings.update request payload. */ +export const settingsUpdateRequestSchema = z.object({ + ns: z.string().min(1), + patch: z.record(z.string(), z.unknown()), + expectedRevision: z.number().optional(), +}); +/** settings.update response value: the namespace's new redacted view. */ +export const settingsUpdateValueSchema = settingsNamespaceViewSchema; +/** settings.replace request payload. */ +export const settingsReplaceRequestSchema = z.object({ + ns: z.string().min(1), + section: z.record(z.string(), z.unknown()), + expectedRevision: z.number().optional(), +}); +/** One path-addressed edit of settings.mutate. */ +export const settingsPathOpSchema = z.discriminatedUnion('op', [ + z.object({ op: z.literal('set'), path: z.array(z.string()), value: z.unknown() }), + z.object({ op: z.literal('unset'), path: z.array(z.string()) }), +]); +/** settings.mutate request payload. */ +export const settingsMutateRequestSchema = z.object({ + ns: z.string().min(1), + ops: z.array(settingsPathOpSchema), + expectedRevision: z.number().optional(), +}); +/** settings.mutate response value: the namespace's new redacted view. */ +export const settingsMutateValueSchema = settingsNamespaceViewSchema; +/** settings.replace response value. */ +export const settingsReplaceValueSchema = settingsNamespaceViewSchema; +//# sourceMappingURL=settings.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.d.ts new file mode 100644 index 0000000..ad7edb0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.d.ts @@ -0,0 +1,35 @@ +/** + * skills domain contract: read-only skill catalog lookup addressed by session. + * The session's header cwd resolves to the canonical project root host-side — + * the client never submits a raw path, and skill lookup never creates or + * resumes an Agent. + */ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** Skill catalog row (wire projection of the host SkillSummary; provider/source vocabulary stays host-side). */ +export interface SkillEntry { + /** Kebab-case identifier the user references as `/name` in the composer. */ + readonly name: string; + /** Short routing description. */ + readonly description: string; + /** Optional extra routing guidance. */ + readonly whenToUse?: string; + /** False marks a user-only skill (`disable-model-invocation`): invocable here, absent from the model catalog. */ + readonly modelInvocable: boolean; +} +/** + * Skill-domain unary methods (the map key skill.* of RpcMethodMap). Listing + * is the domain's only RPC: invocation itself is a plain `session.prompt` + * whose leading `/name` token the host recognizes at the pre-step boundary + * (`dsh-tool-skill` injects the rendered body there), so every client shares + * one deterministic path with no dedicated invocation wire. + */ +export interface SkillsApi { + /** Lists the user-invocable skill catalog for the session's project. */ + list(request: RpcRequest<{ + sessionId: SessionId; + }>): Promise>; +} +//# sourceMappingURL=skills.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.js new file mode 100644 index 0000000..dd59471 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.js @@ -0,0 +1,8 @@ +/** + * skills domain contract: read-only skill catalog lookup addressed by session. + * The session's header cwd resolves to the canonical project root host-side — + * the client never submits a raw path, and skill lookup never creates or + * resumes an Agent. + */ +export {}; +//# sourceMappingURL=skills.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.d.ts new file mode 100644 index 0000000..903831c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.d.ts @@ -0,0 +1,26 @@ +/** + * skills domain zod schemas (names derived from map keys: skillListRequestSchema / + * skillListValueSchema). + */ +import { z } from 'zod'; +/** SkillEntry row of skill.list. */ +export declare const skillEntrySchema: z.ZodObject<{ + name: z.ZodString; + description: z.ZodString; + whenToUse: z.ZodOptional; + modelInvocable: z.ZodBoolean; +}, z.core.$strip>; +/** skill.list request payload. */ +export declare const skillListRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; +}, z.core.$strip>; +/** skill.list response value. */ +export declare const skillListValueSchema: z.ZodObject<{ + skills: z.ZodArray; + modelInvocable: z.ZodBoolean; + }, z.core.$strip>>; +}, z.core.$strip>; +//# sourceMappingURL=skills.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.js new file mode 100644 index 0000000..53ab52c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/skills.schema.js @@ -0,0 +1,22 @@ +/** + * skills domain zod schemas (names derived from map keys: skillListRequestSchema / + * skillListValueSchema). + */ +import { z } from 'zod'; +import { sessionIdSchema } from "./sessions.schema.js"; +/** SkillEntry row of skill.list. */ +export const skillEntrySchema = z.object({ + name: z.string().min(1), + description: z.string(), + whenToUse: z.string().optional(), + modelInvocable: z.boolean(), +}); +/** skill.list request payload. */ +export const skillListRequestSchema = z.object({ + sessionId: sessionIdSchema, +}); +/** skill.list response value. */ +export const skillListValueSchema = z.object({ + skills: z.array(skillEntrySchema), +}); +//# sourceMappingURL=skills.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.d.ts new file mode 100644 index 0000000..05ebaed --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.d.ts @@ -0,0 +1,101 @@ +/** + * Browser-safe subagent domain contract. Persisted transcript reads never + * activate an Agent, while continuable prompts route through the exact live + * direct parent into the child's Agent inbox. + */ +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm/types'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { RpcRequest, RpcResponse } from './rpc.ts'; +import type { HistoryEntry, SessionProjectionsBlock } from './sessions.ts'; +/** Complete durable direct-child catalog row. */ +export type SubagentListEntry = { + kind: 'child'; + id: SessionId; + /** Whether the child Agent driver is running at the Host sampling boundary. */ + activity: 'running' | 'inactive'; + /** Whether a direct descendant has durable `origin: 'subagent'`. */ + hasChildren: boolean; +} & ({ + mode: 'one-shot'; + label?: string; +} | { + mode: 'continuable'; + label: string; +}) | { + kind: 'diagnostic'; + id: SessionId; + reason: 'corrupt' | 'unsupported' | 'unavailable'; +}; +/** Inbox identity returned once the continuation accepts one human message. */ +export interface SubagentPromptReceipt { + messageId: MessageId; +} +/** Uniform acknowledgement that one interrupt request was admitted. */ +export interface SubagentInterruptReceipt { + accepted: true; +} +/** Durable parent/child address that selects subagent transport in the client. */ +export type SubagentAddress = { + parentSessionId: SessionId; + childSessionId: SessionId; +} & ({ + mode: 'one-shot'; +} | { + mode: 'continuable'; +}); +/** Complete direct-child catalog plus the delivery-time parent availability hint. */ +export interface SubagentCatalog { + entries: SubagentListEntry[]; + parentAvailable: boolean; +} +/** Subagent-domain unary methods. */ +export interface SubagentsApi { + /** + * Lists direct session-backed children without loading either side. Parent + * availability is a hint; continuable prompt performs the authoritative + * check. + */ + list(request: RpcRequest<{ + parentSessionId: SessionId; + }>, signal?: AbortSignal): Promise>; + /** + * Reads one healthy catalog child's transcript — the in-memory snapshot of + * a live child, the persisted log of a cold one — with ordinary + * message-aligned pagination and render intents, without Agent activation. + */ + history(request: RpcRequest, signal?: AbortSignal): Promise>; + /** + * Delivers human content to a continuable child through the exact live + * parent's continuation owner. Success identifies the message accepted by + * the child's FIFO inbox; later execution is independent of this request. + * Optional browser-zone provenance is validated and logged on that message. + */ + prompt(request: RpcRequest & { + content: ContentBlock[]; + /** Optional browser zone sampled for this exact human prompt. */ + clientTimeZone?: string; + }>, signal: AbortSignal): Promise>; + /** + * Interrupts a live continuable child's current turn under the address's + * durable direct-parent authority, without requiring a live parent Agent, + * consulting the catalog, or resuming anything. Fire-and-return: `accepted` + * acknowledges the admitted cancel signal, not target quiescence, so the + * child may remain visibly running briefly. Unclaimed queued follow-ups are + * kept and parked; an absent, idle, or already-completed target is likewise + * `accepted`. + */ + interrupt(request: RpcRequest>): Promise>; +} +//# sourceMappingURL=subagents.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.js new file mode 100644 index 0000000..2c1d873 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.js @@ -0,0 +1,7 @@ +/** + * Browser-safe subagent domain contract. Persisted transcript reads never + * activate an Agent, while continuable prompts route through the exact live + * direct parent into the child's Agent inbox. + */ +export {}; +//# sourceMappingURL=subagents.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.d.ts new file mode 100644 index 0000000..c1bb55f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.d.ts @@ -0,0 +1,79 @@ +/** Zod schemas for the browser-safe subagent domain. */ +import { z } from 'zod'; +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { RequestPayload, ResponseValue } from './rpc-map.ts'; +import type { Wire } from './rpc.schema.ts'; +/** Healthy and diagnostic durable catalog rows. */ +export declare const subagentListEntrySchema: z.ZodUnion; + id: z.ZodType>; + mode: z.ZodLiteral<"one-shot">; + activity: z.ZodUnion, z.ZodLiteral<"inactive">]>; + hasChildren: z.ZodBoolean; + label: z.ZodOptional; +}, z.core.$strip>, z.ZodObject<{ + kind: z.ZodLiteral<"child">; + id: z.ZodType>; + mode: z.ZodLiteral<"continuable">; + activity: z.ZodUnion, z.ZodLiteral<"inactive">]>; + hasChildren: z.ZodBoolean; + label: z.ZodString; +}, z.core.$strip>, z.ZodObject<{ + kind: z.ZodLiteral<"diagnostic">; + id: z.ZodType>; + reason: z.ZodUnion, z.ZodLiteral<"unsupported">, z.ZodLiteral<"unavailable">]>; +}, z.core.$strip>]>; +/** subagent.list request payload. */ +export declare const subagentListRequestSchema: z.ZodObject<{ + parentSessionId: z.ZodType>; +}, z.core.$strip>; +/** subagent.list response value. */ +export declare const subagentListValueSchema: z.ZodObject<{ + entries: z.ZodArray; + id: z.ZodType>; + mode: z.ZodLiteral<"one-shot">; + activity: z.ZodUnion, z.ZodLiteral<"inactive">]>; + hasChildren: z.ZodBoolean; + label: z.ZodOptional; + }, z.core.$strip>, z.ZodObject<{ + kind: z.ZodLiteral<"child">; + id: z.ZodType>; + mode: z.ZodLiteral<"continuable">; + activity: z.ZodUnion, z.ZodLiteral<"inactive">]>; + hasChildren: z.ZodBoolean; + label: z.ZodString; + }, z.core.$strip>, z.ZodObject<{ + kind: z.ZodLiteral<"diagnostic">; + id: z.ZodType>; + reason: z.ZodUnion, z.ZodLiteral<"unsupported">, z.ZodLiteral<"unavailable">]>; + }, z.core.$strip>]>>; + parentAvailable: z.ZodBoolean; +}, z.core.$strip>; +/** subagent.history request payload. */ +export declare const subagentHistoryRequestSchema: z.ZodObject<{ + parentSessionId: z.ZodType>; + childSessionId: z.ZodType>; + mode: z.ZodUnion, z.ZodLiteral<"continuable">]>; + beforeSeq: z.ZodOptional; + maxMessages: z.ZodOptional; +}, z.core.$strip>; +/** subagent.history response value. */ +export declare const subagentHistoryValueSchema: z.ZodType>>; +/** subagent.prompt request payload. */ +export declare const subagentPromptRequestSchema: z.ZodType>; +/** subagent.interrupt request payload. */ +export declare const subagentInterruptRequestSchema: z.ZodObject<{ + parentSessionId: z.ZodType>; + childSessionId: z.ZodType>; + mode: z.ZodLiteral<"continuable">; +}, z.core.$strip>; +/** subagent.interrupt response value. */ +export declare const subagentInterruptValueSchema: z.ZodObject<{ + accepted: z.ZodLiteral; +}, z.core.$strip>; +/** subagent.prompt response value. */ +export declare const subagentPromptValueSchema: z.ZodObject<{ + messageId: z.ZodType>; +}, z.core.$strip>; +//# sourceMappingURL=subagents.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.js new file mode 100644 index 0000000..3648b4a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/subagents.schema.js @@ -0,0 +1,74 @@ +/** Zod schemas for the browser-safe subagent domain. */ +import { z } from 'zod'; +import { contentBlockSchema, historyEntrySchema, sessionIdSchema, sessionProjectionsBlockSchema, } from "./sessions.schema.js"; +/** Healthy and diagnostic durable catalog rows. */ +export const subagentListEntrySchema = z.union([ + z.object({ + kind: z.literal('child'), + id: sessionIdSchema, + mode: z.literal('one-shot'), + activity: z.union([z.literal('running'), z.literal('inactive')]), + hasChildren: z.boolean(), + label: z.string().optional(), + }), + z.object({ + kind: z.literal('child'), + id: sessionIdSchema, + mode: z.literal('continuable'), + activity: z.union([z.literal('running'), z.literal('inactive')]), + hasChildren: z.boolean(), + label: z.string(), + }), + z.object({ + kind: z.literal('diagnostic'), + id: sessionIdSchema, + reason: z.union([z.literal('corrupt'), z.literal('unsupported'), z.literal('unavailable')]), + }), +]); +/** subagent.list request payload. */ +export const subagentListRequestSchema = z.object({ + parentSessionId: sessionIdSchema, +}); +/** subagent.list response value. */ +export const subagentListValueSchema = z.object({ + entries: z.array(subagentListEntrySchema), + parentAvailable: z.boolean(), +}); +/** subagent.history request payload. */ +export const subagentHistoryRequestSchema = z.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z.union([z.literal('one-shot'), z.literal('continuable')]), + beforeSeq: z.number().int().nonnegative().optional(), + maxMessages: z.number().int().positive().optional(), +}); +/** subagent.history response value. */ +export const subagentHistoryValueSchema = z.object({ + events: z.array(historyEntrySchema), + hasMore: z.boolean(), + projections: sessionProjectionsBlockSchema.optional(), +}); +/** subagent.prompt request payload. */ +export const subagentPromptRequestSchema = z.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z.literal('continuable'), + content: z.array(contentBlockSchema), + clientTimeZone: z.string().optional(), +}); +/** subagent.interrupt request payload. */ +export const subagentInterruptRequestSchema = z.object({ + parentSessionId: sessionIdSchema, + childSessionId: sessionIdSchema, + mode: z.literal('continuable'), +}); +/** subagent.interrupt response value. */ +export const subagentInterruptValueSchema = z.object({ + accepted: z.literal(true), +}); +const messageIdSchema = z.string(); +/** subagent.prompt response value. */ +export const subagentPromptValueSchema = z.object({ + messageId: messageIdSchema, +}); +//# sourceMappingURL=subagents.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.d.ts new file mode 100644 index 0000000..dfa5944 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.d.ts @@ -0,0 +1,121 @@ +/** + * workspace domain contract. Wire projection of the host-side workspace + * entity (@deepseek-ai/dsh-workspace): a stable id over a directory path, + * a display title, and the ordered session account. Method signatures are the + * source of truth, same as the sessions domain. + */ +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { RpcRequest, RpcResponse } from './rpc.ts'; +/** + * Wire-side workspace id brand. Deliberately re-declared here rather than + * imported from dsh-workspace: api/ must stay browser-importable with zero + * host-package dependencies, and the brand string matches, so both sides + * agree structurally. + */ +export type WorkspaceId = Branded<'WorkspaceId'>; +/** One workspace row: the record projection every workspace.* value carries. */ +export interface WorkspaceView { + workspaceId: WorkspaceId; + /** Canonical directory path (host-side realpath canon). */ + path: string; + /** Display title (defaults to the path basename at create). */ + title: string; + /** + * Sessions accounted under this workspace, in manually owned order + * (attach prepends, insertSessionBefore reorders; activity never does). + */ + sessionIds: SessionId[]; + /** ISO-8601 creation instant. */ + createdAt: string; + /** ISO-8601 last-mutation instant. */ + updatedAt: string; +} +/** Workspace-domain unary methods (the map keys workspace.* of RpcMethodMap). */ +export interface WorkspaceApi { + /** + * Lists all workspaces in the registry's durable display order, plus the + * registry-global archive set (the reconnect baseline of + * `host/archived-sessions-changed`). Archived sessions stay in their + * workspace's `sessionIds` account; grouping surfaces hide them. + */ + list(request: RpcRequest<{}>): Promise>; + /** + * Creates (or idempotently resolves) a workspace over an EXISTING directory + * (no mkdir — a missing or non-directory path fails with + * `workspace-invalid-path`). A path resolving to a directory already owned + * by a workspace returns that workspace (`created: false`). Adoption allows + * distinct canonical paths whose basenames produce the same display title; + * the registry's basename title default names the new workspace. + */ + create(request: RpcRequest<{ + path: string; + }>): Promise>; + /** + * Renames a workspace. `title` is trimmed and must be non-empty + * (schema-enforced). An unknown id fails with `workspace-not-found`; a + * title equal to another workspace's fails with `workspace-name-conflict`. + * Renaming to the current title is a no-op success (no durable write). + */ + rename(request: RpcRequest<{ + workspaceId: WorkspaceId; + title: string; + }>): Promise>; + /** + * Removes one Workspace registration. The directory, every user file, and + * every session log remain untouched; those Sessions consequently become + * ungrouped. An unknown id fails with `workspace-not-found`. + */ + delete(request: RpcRequest<{ + workspaceId: WorkspaceId; + }>): Promise>; + /** + * Moves one Workspace within the registry display order, + * DOM-insertBefore-like. An omitted anchor appends to the end. + */ + insertBefore(request: RpcRequest<{ + workspaceId: WorkspaceId; + beforeWorkspaceId?: WorkspaceId; + }>): Promise>; + /** + * Moves an accounted session within its workspace's manual order, + * DOM-insertBefore-like: with `beforeSessionId` the session is inserted + * before that anchor; omitted appends to the end. An unknown workspace + * fails with `workspace-not-found`; a session or anchor not accounted by + * the workspace fails with `workspace-move-invalid`. A move to the current + * position is a no-op success. + */ + insertSessionBefore(request: RpcRequest<{ + workspaceId: WorkspaceId; + sessionId: SessionId; + beforeSessionId?: SessionId; + }>): Promise>; + /** + * Adds one session to the registry-global archive set: the session + * disappears from every grouping surface but keeps its session log and its + * workspace accounting slot (a future unarchive restores its position). + * Idempotent for an already archived id. A session neither live nor in + * session persistence fails with `session-not-found`. Returns the full + * updated set (same snapshot the changed frame carries). + */ + archiveSession(request: RpcRequest<{ + sessionId: SessionId; + }>): Promise>; +} +//# sourceMappingURL=workspace.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.js new file mode 100644 index 0000000..1369d3b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.js @@ -0,0 +1,8 @@ +/** + * workspace domain contract. Wire projection of the host-side workspace + * entity (@deepseek-ai/dsh-workspace): a stable id over a directory path, + * a display title, and the ordered session account. Method signatures are the + * source of truth, same as the sessions domain. + */ +export {}; +//# sourceMappingURL=workspace.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.d.ts new file mode 100644 index 0000000..f7a4911 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.d.ts @@ -0,0 +1,105 @@ +/** + * workspace domain zod schemas (names derived from map keys). The + * WorkspaceId brand cast lives in sessions.schema (see the note there) and + * is re-exported here as the domain-local name. + */ +import { z } from 'zod'; +export { workspaceIdSchema } from './sessions.schema.ts'; +/** WorkspaceView row of every workspace.* response. */ +export declare const workspaceViewSchema: z.ZodObject<{ + workspaceId: z.ZodType>; + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; +}, z.core.$strip>; +/** workspace.list request payload (empty object literal). */ +export declare const workspaceListRequestSchema: z.ZodObject<{}, z.core.$strip>; +/** workspace.list response value. */ +export declare const workspaceListValueSchema: z.ZodObject<{ + items: z.ZodArray>; + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; + }, z.core.$strip>>; + archivedSessionIds: z.ZodArray>>; +}, z.core.$strip>; +/** workspace.create request payload: the existing directory to adopt. */ +export declare const workspaceCreateRequestSchema: z.ZodObject<{ + path: z.ZodString; +}, z.core.$strip>; +/** workspace.create response value. */ +export declare const workspaceCreateValueSchema: z.ZodObject<{ + workspace: z.ZodObject<{ + workspaceId: z.ZodType>; + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; + }, z.core.$strip>; + created: z.ZodBoolean; +}, z.core.$strip>; +/** workspace.rename request payload: the new title must be non-blank. */ +export declare const workspaceRenameRequestSchema: z.ZodObject<{ + workspaceId: z.ZodType>; + title: z.ZodString; +}, z.core.$strip>; +/** workspace.rename response value. */ +export declare const workspaceRenameValueSchema: z.ZodObject<{ + workspace: z.ZodObject<{ + workspaceId: z.ZodType>; + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; + }, z.core.$strip>; +}, z.core.$strip>; +/** workspace.delete request payload. */ +export declare const workspaceDeleteRequestSchema: z.ZodObject<{ + workspaceId: z.ZodType>; +}, z.core.$strip>; +/** workspace.delete response value. */ +export declare const workspaceDeleteValueSchema: z.ZodObject<{ + deleted: z.ZodLiteral; +}, z.core.$strip>; +/** workspace.insertBefore request payload (anchor omitted = append to end). */ +export declare const workspaceInsertBeforeRequestSchema: z.ZodObject<{ + workspaceId: z.ZodType>; + beforeWorkspaceId: z.ZodOptional>>; +}, z.core.$strip>; +/** workspace.insertBefore response value: the complete durable display order. */ +export declare const workspaceInsertBeforeValueSchema: z.ZodObject<{ + workspaceIds: z.ZodArray>>; +}, z.core.$strip>; +/** workspace.insertSessionBefore request payload (anchor omitted = append to end). */ +export declare const workspaceInsertSessionBeforeRequestSchema: z.ZodObject<{ + workspaceId: z.ZodType>; + sessionId: z.ZodType>; + beforeSessionId: z.ZodOptional>>; +}, z.core.$strip>; +/** workspace.insertSessionBefore response value. */ +export declare const workspaceInsertSessionBeforeValueSchema: z.ZodObject<{ + workspace: z.ZodObject<{ + workspaceId: z.ZodType>; + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; + }, z.core.$strip>; +}, z.core.$strip>; +/** workspace.archiveSession request payload. */ +export declare const workspaceArchiveSessionRequestSchema: z.ZodObject<{ + sessionId: z.ZodType>; +}, z.core.$strip>; +/** workspace.archiveSession response value: the full updated archive set. */ +export declare const workspaceArchiveSessionValueSchema: z.ZodObject<{ + archivedSessionIds: z.ZodArray>>; +}, z.core.$strip>; +//# sourceMappingURL=workspace.schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js new file mode 100644 index 0000000..1752304 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js @@ -0,0 +1,78 @@ +/** + * workspace domain zod schemas (names derived from map keys). The + * WorkspaceId brand cast lives in sessions.schema (see the note there) and + * is re-exported here as the domain-local name. + */ +import { z } from 'zod'; +import { sessionIdSchema, workspaceIdSchema } from "./sessions.schema.js"; +export { workspaceIdSchema } from "./sessions.schema.js"; +/** WorkspaceView row of every workspace.* response. */ +export const workspaceViewSchema = z.object({ + workspaceId: workspaceIdSchema, + path: z.string(), + title: z.string(), + sessionIds: z.array(sessionIdSchema), + createdAt: z.string(), + updatedAt: z.string(), +}); +/** workspace.list request payload (empty object literal). */ +export const workspaceListRequestSchema = z.object({}); +/** workspace.list response value. */ +export const workspaceListValueSchema = z.object({ + items: z.array(workspaceViewSchema), + archivedSessionIds: z.array(sessionIdSchema), +}); +/** workspace.create request payload: the existing directory to adopt. */ +export const workspaceCreateRequestSchema = z.object({ + path: z.string(), +}); +/** workspace.create response value. */ +export const workspaceCreateValueSchema = z.object({ + workspace: workspaceViewSchema, + created: z.boolean(), +}); +/** workspace.rename request payload: the new title must be non-blank. */ +export const workspaceRenameRequestSchema = z.object({ + workspaceId: workspaceIdSchema, + title: z.string(), +}).refine(payload => payload.title.trim() !== '', { message: 'workspace.rename requires a non-blank title' }); +/** workspace.rename response value. */ +export const workspaceRenameValueSchema = z.object({ + workspace: workspaceViewSchema, +}); +/** workspace.delete request payload. */ +export const workspaceDeleteRequestSchema = z.object({ + workspaceId: workspaceIdSchema, +}); +/** workspace.delete response value. */ +export const workspaceDeleteValueSchema = z.object({ + deleted: z.literal(true), +}); +/** workspace.insertBefore request payload (anchor omitted = append to end). */ +export const workspaceInsertBeforeRequestSchema = z.object({ + workspaceId: workspaceIdSchema, + beforeWorkspaceId: workspaceIdSchema.optional(), +}); +/** workspace.insertBefore response value: the complete durable display order. */ +export const workspaceInsertBeforeValueSchema = z.object({ + workspaceIds: z.array(workspaceIdSchema), +}); +/** workspace.insertSessionBefore request payload (anchor omitted = append to end). */ +export const workspaceInsertSessionBeforeRequestSchema = z.object({ + workspaceId: workspaceIdSchema, + sessionId: sessionIdSchema, + beforeSessionId: sessionIdSchema.optional(), +}); +/** workspace.insertSessionBefore response value. */ +export const workspaceInsertSessionBeforeValueSchema = z.object({ + workspace: workspaceViewSchema, +}); +/** workspace.archiveSession request payload. */ +export const workspaceArchiveSessionRequestSchema = z.object({ + sessionId: sessionIdSchema, +}); +/** workspace.archiveSession response value: the full updated archive set. */ +export const workspaceArchiveSessionValueSchema = z.object({ + archivedSessionIds: z.array(sessionIdSchema), +}); +//# sourceMappingURL=workspace.schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.d.ts new file mode 100644 index 0000000..e3d0480 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.d.ts @@ -0,0 +1,194 @@ +/** + * Client side of the fetch carrier. AbstractApiClient holds every protocol invariant: rpcId minting, + * four-quadrant envelope wrap/unwrap, zod parsing, in-process SSE frame decoding, and the payload-direct + * IApiClient domain methods (business code never mints). Platform differences ride two aspects: + * abstract doFetch (transport) + overridable onEnvelope (tap). ApiProxy (the impl face) is untouched. + */ +import type { z } from 'zod'; +import type { ApiProxy, HostFrame, MuxFrame } from '../api/index.ts'; +import type { RequestPayload, ResponseValue, RpcMethodMap } from '../api/rpc-map.ts'; +import type { ClientResponse, RpcMessage, RpcReceipt, RpcRequest, RpcResponse } from '../api/rpc.ts'; +import { RpcId } from '../api/rpc.ts'; +/** + * Client consumption face of the contract (shape a): same domain tree as ApiProxy, but unary + * methods take the business payload directly — the carrier mints the rpcId and wraps the + * envelope. Business code needing the call's rpcId reads it from the RpcResponse echo. + * Unary methods and respond accept an optional external AbortSignal as the last parameter. + * Bounded calls merge it with the instance timeout via AbortSignal.any; user-paced calls + * carry only that external signal. In both cases the signal rides beside the request, never + * on the wire, like the stream signatures. + * Stream methods accept an optional onOpen callback: it fires once the physical transport is + * readable (before any frame) — the "stream established" signal + * connection controllers need for the readiness handshake. Generators are lazy, so the + * underlying fetch (and therefore onOpen) only happens once iteration starts. + * Relationship: ApiProxy is the narrow-form signature contract the impl side implements; + * IApiClient is the payload-direct view clients consume; AbstractApiClient bridges the two. + * Derived per method key from RpcMethodMap so a map row addition updates this mechanically. + */ +export interface IApiClient { + sessions: { + list(payload: RequestPayload<'session.list'>, signal?: AbortSignal): Promise>>; + search(payload: RequestPayload<'session.search'>, signal?: AbortSignal): Promise>>; + create(payload: RequestPayload<'session.create'>, signal?: AbortSignal): Promise>>; + history(payload: RequestPayload<'session.history'>, signal?: AbortSignal): Promise>>; + models(payload: RequestPayload<'session.models'>, signal?: AbortSignal): Promise>>; + selectModel(payload: RequestPayload<'session.selectModel'>, signal?: AbortSignal): Promise>>; + rename(payload: RequestPayload<'session.rename'>, signal?: AbortSignal): Promise>>; + fork(payload: RequestPayload<'session.fork'>, signal?: AbortSignal): Promise>>; + prompt(payload: RequestPayload<'session.prompt'>, signal?: AbortSignal): Promise>>; + attachment(payload: RequestPayload<'session.attachment'>, signal?: AbortSignal): Promise>>; + updateQueue(payload: RequestPayload<'session.updateQueue'>, signal?: AbortSignal): Promise>>; + cancel(payload: RequestPayload<'session.cancel'>, signal?: AbortSignal): Promise>>; + }; + subagents: { + list(payload: RequestPayload<'subagent.list'>, signal?: AbortSignal): Promise>>; + history(payload: RequestPayload<'subagent.history'>, signal?: AbortSignal): Promise>>; + prompt(payload: RequestPayload<'subagent.prompt'>, signal?: AbortSignal): Promise>>; + interrupt(payload: RequestPayload<'subagent.interrupt'>, signal?: AbortSignal): Promise>>; + }; + host: { + describe(payload: RequestPayload<'host.describe'>, signal?: AbortSignal): Promise>>; + pickDirectory(payload: RequestPayload<'host.pickDirectory'>, signal?: AbortSignal): Promise>>; + listDirectory(payload: RequestPayload<'host.listDirectory'>, signal?: AbortSignal): Promise>>; + createDirectory(payload: RequestPayload<'host.createDirectory'>, signal?: AbortSignal): Promise>>; + openPath(payload: RequestPayload<'host.openPath'>, signal?: AbortSignal): Promise>>; + }; + workspace: { + list(payload: RequestPayload<'workspace.list'>, signal?: AbortSignal): Promise>>; + create(payload: RequestPayload<'workspace.create'>, signal?: AbortSignal): Promise>>; + rename(payload: RequestPayload<'workspace.rename'>, signal?: AbortSignal): Promise>>; + delete(payload: RequestPayload<'workspace.delete'>, signal?: AbortSignal): Promise>>; + insertBefore(payload: RequestPayload<'workspace.insertBefore'>, signal?: AbortSignal): Promise>>; + insertSessionBefore(payload: RequestPayload<'workspace.insertSessionBefore'>, signal?: AbortSignal): Promise>>; + archiveSession(payload: RequestPayload<'workspace.archiveSession'>, signal?: AbortSignal): Promise>>; + }; + skills: { + list(payload: RequestPayload<'skill.list'>, signal?: AbortSignal): Promise>>; + }; + agentPresets: { + list(payload: RequestPayload<'agentPreset.list'>, signal?: AbortSignal): Promise>>; + select(payload: RequestPayload<'agentPreset.select'>, signal?: AbortSignal): Promise>>; + read(payload: RequestPayload<'agentPreset.read'>, signal?: AbortSignal): Promise>>; + copy(payload: RequestPayload<'agentPreset.copy'>, signal?: AbortSignal): Promise>>; + openDocument(payload: RequestPayload<'agentPreset.openDocument'>, signal?: AbortSignal): Promise>>; + remove(payload: RequestPayload<'agentPreset.remove'>, signal?: AbortSignal): Promise>>; + }; + events: { + mux(payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + host(payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + }; + goals: { + create(payload: RequestPayload<'goal.create'>, signal?: AbortSignal): Promise>>; + edit(payload: RequestPayload<'goal.edit'>, signal?: AbortSignal): Promise>>; + pause(payload: RequestPayload<'goal.pause'>, signal?: AbortSignal): Promise>>; + resume(payload: RequestPayload<'goal.resume'>, signal?: AbortSignal): Promise>>; + complete(payload: RequestPayload<'goal.complete'>, signal?: AbortSignal): Promise>>; + clear(payload: RequestPayload<'goal.clear'>, signal?: AbortSignal): Promise>>; + }; + settings: { + describe(payload: RequestPayload<'settings.describe'>, signal?: AbortSignal): Promise>>; + openDocument(payload: RequestPayload<'settings.openDocument'>, signal?: AbortSignal): Promise>>; + update(payload: RequestPayload<'settings.update'>, signal?: AbortSignal): Promise>>; + replace(payload: RequestPayload<'settings.replace'>, signal?: AbortSignal): Promise>>; + mutate(payload: RequestPayload<'settings.mutate'>, signal?: AbortSignal): Promise>>; + }; + credentials: { + describe(payload: RequestPayload<'credentials.describe'>, signal?: AbortSignal): Promise>>; + set(payload: RequestPayload<'credentials.set'>, signal?: AbortSignal): Promise>>; + unset(payload: RequestPayload<'credentials.unset'>, signal?: AbortSignal): Promise>>; + }; + llm: { + providers(payload: RequestPayload<'llm.providers'>, signal?: AbortSignal): Promise>>; + models(payload: RequestPayload<'llm.models'>, signal?: AbortSignal): Promise>>; + discoverModels(payload: RequestPayload<'llm.discoverModels'>, signal?: AbortSignal): Promise>>; + }; + /** client-response passthrough (rpcId is a backfill of the server-request's id — never minted here). */ + respond(message: ClientResponse, signal?: AbortSignal): Promise; +} +/** Whether a unary call uses the transport health deadline or only caller/connection cancellation. */ +type UnaryTimeoutPolicy = 'default' | 'caller-signal-only'; +/** + * Abstract fetch-carrier client. Subclasses supply the transport (doFetch) and may refine the + * per-message tap (onEnvelope) — platform aspects stay in subclasses, protocol invariants stay + * here. Envelope observation is a first-class aspect of this data middle layer: the instance + * owns a microtask-batched buffer (frame storms must not cost one consumer update per frame), + * and observers subscribe via subscribeEnvelopes. The isomorphic point survives: an in-process + * subclass whose doFetch is toFetchHandler(api).fetch never touches the network. + */ +export declare abstract class AbstractApiClient implements IApiClient { + protected readonly timeoutMs: number; + /** Instance-owned observation buffer (module-level state would leak across instances/tests). */ + private envelopeBatch; + private flushScheduled; + private readonly envelopeListeners; + /** @param timeoutMs - timeout for bounded unary calls; user-paced calls and streams do not use it. */ + constructor(timeoutMs?: number); + /** Transport aspect: browser fetch, injected handler.fetch, IPC bridge, ... */ + protected abstract doFetch(input: URL, init?: RequestInit): Promise; + /** + * Subscribe to batched envelope observation (diagnostics/logging consumers). + * Batches follow microtask boundaries; a listener throw is isolated (observation + * must never break the carrier). + * @param listener - receives each flushed batch in arrival order. + * @returns unsubscribe function. + */ + subscribeEnvelopes(listener: (batch: readonly RpcMessage[]) => void): () => void; + /** Per-message tap: feeds the instance buffer. Subclasses may override to observe unbatched (call super to keep batching). */ + protected onEnvelope(message: RpcMessage): void; + /** Browser = same-origin (a fake authority would fail DNS on real requests); no-location env (Node) = fake authority. */ + protected resolveBase(): string; + protected mintRpcId(): RpcId; + /** + * Shared POST leg of both C→S carriers (callUnary/respond): JSON body, + * optional default timeout merged with the caller's external signal, non-2xx → transport throw. + */ + private postJson; + /** + * Unary protocol path: mint → tap → POST full form → envelope parse → verify + * echo → value parse → tap → narrow. Virtual so a fake carrier (fixture) can + * override transport at this layer. + */ + protected callUnary(method: K, payload: RequestPayload, signal?: AbortSignal, timeoutPolicy?: UnaryTimeoutPolicy): Promise>>; + /** Mux stream opener; virtual for the same override reason as callUnary. */ + protected openMux(_payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + /** Host stream opener; virtual. */ + protected openHost(_payload: Parameters[0]['payload'], signal: AbortSignal, onOpen?: () => void): AsyncIterable>; + /** + * SSE protocol path: streaming fetch (not EventSource), '\n\n' framing, ServerRequest envelope + + * frame-schema parse, tap, narrow yield. onOpen fires once the response headers are in and the + * body is readable — the stream-established signal, before any frame arrives. A frame that fails + * either parse level is reported and skipped (one corrupt frame must not kill the stream; the + * client's gap detection covers whatever the frame carried). + */ + protected readSse(path: string, signal: AbortSignal, frameSchema: z.ZodType, onOpen?: () => void): AsyncGenerator>; + readonly sessions: IApiClient['sessions']; + readonly subagents: IApiClient['subagents']; + readonly host: IApiClient['host']; + readonly workspace: IApiClient['workspace']; + readonly skills: IApiClient['skills']; + readonly agentPresets: IApiClient['agentPresets']; + readonly goals: IApiClient['goals']; + readonly settings: IApiClient['settings']; + readonly credentials: IApiClient['credentials']; + readonly llm: IApiClient['llm']; + readonly events: IApiClient['events']; + respond(message: ClientResponse, signal?: AbortSignal): Promise; +} +/** + * In-process client over an injected fetch-shaped handler (the isomorphic point: + * `new InProcessApiClient(toFetchHandler(api))` never touches the network). Lives here because + * in-process injection is this package's own capability (handler and client are both local). + */ +export declare class InProcessApiClient extends AbstractApiClient { + private readonly handler; + constructor(handler: { + fetch: typeof fetch; + }, timeoutMs?: number); + /** + * Faithful to real fetch: reject on signal abort even when the in-process + * handler ignores the signal (a hung impl must not defeat timeout/cancel). + */ + protected doFetch(input: URL, init?: RequestInit): Promise; +} +export {}; +//# sourceMappingURL=client.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.js new file mode 100644 index 0000000..1b4e874 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/client.js @@ -0,0 +1,370 @@ +/** + * Client side of the fetch carrier. AbstractApiClient holds every protocol invariant: rpcId minting, + * four-quadrant envelope wrap/unwrap, zod parsing, in-process SSE frame decoding, and the payload-direct + * IApiClient domain methods (business code never mints). Platform differences ride two aspects: + * abstract doFetch (transport) + overridable onEnvelope (tap). ApiProxy (the impl face) is untouched. + */ +import { RpcId } from "../api/rpc.js"; +import { rpcReceiptSchema, serverRequestSchema, serverResponseSchema } from "../api/rpc.schema.js"; +import { hostFrameSchema, muxFrameSchema } from "../api/events.schema.js"; +import { hostCreateDirectoryValueSchema, hostDescribeValueSchema, hostListDirectoryValueSchema, hostOpenPathValueSchema, hostPickDirectoryValueSchema, } from "../api/host.schema.js"; +import { sessionCancelValueSchema, sessionAttachmentValueSchema, sessionCreateValueSchema, sessionForkValueSchema, sessionHistoryValueSchema, sessionListValueSchema, sessionModelsValueSchema, sessionPromptValueSchema, sessionRenameValueSchema, sessionSearchValueSchema, sessionSelectModelValueSchema, sessionUpdateQueueValueSchema, } from "../api/sessions.schema.js"; +import { workspaceArchiveSessionValueSchema, workspaceCreateValueSchema, workspaceDeleteValueSchema, workspaceInsertBeforeValueSchema, workspaceInsertSessionBeforeValueSchema, workspaceListValueSchema, workspaceRenameValueSchema, } from "../api/workspace.schema.js"; +import { skillListValueSchema } from "../api/skills.schema.js"; +import { agentPresetCopyValueSchema, agentPresetListValueSchema, agentPresetOpenDocumentValueSchema, agentPresetReadValueSchema, agentPresetRemoveValueSchema, agentPresetSelectValueSchema, } from "../api/agent-presets.schema.js"; +import { goalCreateValueSchema, goalEditValueSchema, goalPauseValueSchema, goalResumeValueSchema, goalCompleteValueSchema, goalClearValueSchema, } from "../api/goals.schema.js"; +import { settingsDescribeValueSchema, settingsMutateValueSchema, settingsOpenDocumentValueSchema, settingsReplaceValueSchema, settingsUpdateValueSchema, } from "../api/settings.schema.js"; +import { credentialsDescribeValueSchema, credentialsSetValueSchema, credentialsUnsetValueSchema, } from "../api/credentials.schema.js"; +import { llmDiscoverModelsValueSchema, llmModelsValueSchema, llmProvidersValueSchema } from "../api/llm.schema.js"; +import { subagentHistoryValueSchema, subagentInterruptValueSchema, subagentListValueSchema, subagentPromptValueSchema, } from "../api/subagents.schema.js"; +/** + * S→C second-level parse table: value schema by method (the response-path + * mirror of the handler's request table; key coverage compiler-enforced against RpcMethodMap). + */ +const UNARY_VALUE_SCHEMAS = { + 'session.list': sessionListValueSchema, + 'session.search': sessionSearchValueSchema, + 'session.create': sessionCreateValueSchema, + 'session.history': sessionHistoryValueSchema, + 'session.models': sessionModelsValueSchema, + 'session.selectModel': sessionSelectModelValueSchema, + 'session.rename': sessionRenameValueSchema, + 'session.fork': sessionForkValueSchema, + 'session.prompt': sessionPromptValueSchema, + 'session.attachment': sessionAttachmentValueSchema, + 'session.updateQueue': sessionUpdateQueueValueSchema, + 'session.cancel': sessionCancelValueSchema, + 'subagent.list': subagentListValueSchema, + 'subagent.history': subagentHistoryValueSchema, + 'subagent.prompt': subagentPromptValueSchema, + 'subagent.interrupt': subagentInterruptValueSchema, + 'host.describe': hostDescribeValueSchema, + 'host.pickDirectory': hostPickDirectoryValueSchema, + 'host.listDirectory': hostListDirectoryValueSchema, + 'host.createDirectory': hostCreateDirectoryValueSchema, + 'host.openPath': hostOpenPathValueSchema, + 'workspace.list': workspaceListValueSchema, + 'workspace.create': workspaceCreateValueSchema, + 'workspace.rename': workspaceRenameValueSchema, + 'workspace.delete': workspaceDeleteValueSchema, + 'workspace.insertBefore': workspaceInsertBeforeValueSchema, + 'workspace.insertSessionBefore': workspaceInsertSessionBeforeValueSchema, + 'workspace.archiveSession': workspaceArchiveSessionValueSchema, + 'skill.list': skillListValueSchema, + 'agentPreset.list': agentPresetListValueSchema, + 'agentPreset.select': agentPresetSelectValueSchema, + 'agentPreset.read': agentPresetReadValueSchema, + 'agentPreset.copy': agentPresetCopyValueSchema, + 'agentPreset.openDocument': agentPresetOpenDocumentValueSchema, + 'agentPreset.remove': agentPresetRemoveValueSchema, + 'goal.create': goalCreateValueSchema, + 'goal.edit': goalEditValueSchema, + 'goal.pause': goalPauseValueSchema, + 'goal.resume': goalResumeValueSchema, + 'goal.complete': goalCompleteValueSchema, + 'goal.clear': goalClearValueSchema, + 'settings.describe': settingsDescribeValueSchema, + 'settings.openDocument': settingsOpenDocumentValueSchema, + 'settings.update': settingsUpdateValueSchema, + 'settings.replace': settingsReplaceValueSchema, + 'settings.mutate': settingsMutateValueSchema, + 'credentials.describe': credentialsDescribeValueSchema, + 'credentials.set': credentialsSetValueSchema, + 'credentials.unset': credentialsUnsetValueSchema, + 'llm.providers': llmProvidersValueSchema, + 'llm.models': llmModelsValueSchema, + 'llm.discoverModels': llmDiscoverModelsValueSchema, +}; +/** Default timeout for bounded unary calls (rpc-compare 2026-07-19: a hung host must not leave callers pending forever). */ +const DEFAULT_TIMEOUT_MS = 30_000; +/** URL base for in-process handler injection (fake authority, opencode precedent). */ +const INTERNAL_BASE = 'http://dsh.internal'; +/** + * Abstract fetch-carrier client. Subclasses supply the transport (doFetch) and may refine the + * per-message tap (onEnvelope) — platform aspects stay in subclasses, protocol invariants stay + * here. Envelope observation is a first-class aspect of this data middle layer: the instance + * owns a microtask-batched buffer (frame storms must not cost one consumer update per frame), + * and observers subscribe via subscribeEnvelopes. The isomorphic point survives: an in-process + * subclass whose doFetch is toFetchHandler(api).fetch never touches the network. + */ +export class AbstractApiClient { + timeoutMs; + /** Instance-owned observation buffer (module-level state would leak across instances/tests). */ + envelopeBatch = []; + flushScheduled = false; + envelopeListeners = new Set(); + /** @param timeoutMs - timeout for bounded unary calls; user-paced calls and streams do not use it. */ + constructor(timeoutMs = DEFAULT_TIMEOUT_MS) { + this.timeoutMs = timeoutMs; + } + /** + * Subscribe to batched envelope observation (diagnostics/logging consumers). + * Batches follow microtask boundaries; a listener throw is isolated (observation + * must never break the carrier). + * @param listener - receives each flushed batch in arrival order. + * @returns unsubscribe function. + */ + subscribeEnvelopes(listener) { + this.envelopeListeners.add(listener); + return () => { + this.envelopeListeners.delete(listener); + }; + } + /** Per-message tap: feeds the instance buffer. Subclasses may override to observe unbatched (call super to keep batching). */ + onEnvelope(message) { + if (this.envelopeListeners.size === 0) + return; + this.envelopeBatch.push(message); + if (this.flushScheduled) + return; + this.flushScheduled = true; + queueMicrotask(() => { + this.flushScheduled = false; + // Never empty here: a flush is only ever scheduled by the push above, + // and this callback is the sole drain point. + const batch = this.envelopeBatch; + this.envelopeBatch = []; + for (const notify of this.envelopeListeners) { + try { + notify(batch); + } + catch (error) { + console.error('[apiproxy] envelope listener threw:', error); + } + } + }); + } + /** Browser = same-origin (a fake authority would fail DNS on real requests); no-location env (Node) = fake authority. */ + resolveBase() { + const loc = globalThis.location; + return loc?.origin !== undefined && loc.origin !== 'null' ? loc.origin : INTERNAL_BASE; + } + mintRpcId() { + // crypto.randomUUID is a Web API (browser + Node ≥19): keeps this base platform-neutral. + return RpcId(crypto.randomUUID()); + } + /** + * Shared POST leg of both C→S carriers (callUnary/respond): JSON body, + * optional default timeout merged with the caller's external signal, non-2xx → transport throw. + */ + async postJson(path, body, signal, timeoutPolicy = 'default') { + const requestSignal = timeoutPolicy === 'default' + ? signal === undefined + ? AbortSignal.timeout(this.timeoutMs) + : AbortSignal.any([AbortSignal.timeout(this.timeoutMs), signal]) + : signal; + const response = await this.doFetch(new URL(path, this.resolveBase()), { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(body), + ...requestSignal === undefined ? {} : { signal: requestSignal }, + }); + if (!response.ok) + throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + return response; + } + /** + * Unary protocol path: mint → tap → POST full form → envelope parse → verify + * echo → value parse → tap → narrow. Virtual so a fake carrier (fixture) can + * override transport at this layer. + */ + async callUnary(method, payload, signal, timeoutPolicy = 'default') { + const message = { type: 'client-request', rpcId: this.mintRpcId(), method, payload }; + this.onEnvelope(message); + const response = await this.postJson(`/api/${method}`, message, signal, timeoutPolicy); + const full = serverResponseSchema.parse(await response.json()); + this.onEnvelope(full); + if (full.rpcId !== message.rpcId) + throw new Error(`rpcId mismatch for ${method}: sent ${message.rpcId}, got ${full.rpcId}`); + if (!full.result.ok) + return { rpcId: full.rpcId, result: full.result }; + // Second-level S→C parse: the ok value must match the method's Value schema (mirror of the + // handler's request-payload parse). The cast collapses the Wire<> widening, same as the handler side. + const value = UNARY_VALUE_SCHEMAS[method].parse(full.result.value); + return { rpcId: full.rpcId, result: { ok: true, value } }; + } + /** Mux stream opener; virtual for the same override reason as callUnary. */ + openMux(_payload, signal, onOpen) { + return this.readSse('/api/events.mux', signal, muxFrameSchema, onOpen); + } + /** Host stream opener; virtual. */ + openHost(_payload, signal, onOpen) { + return this.readSse('/api/events.host', signal, hostFrameSchema, onOpen); + } + /** + * SSE protocol path: streaming fetch (not EventSource), '\n\n' framing, ServerRequest envelope + + * frame-schema parse, tap, narrow yield. onOpen fires once the response headers are in and the + * body is readable — the stream-established signal, before any frame arrives. A frame that fails + * either parse level is reported and skipped (one corrupt frame must not kill the stream; the + * client's gap detection covers whatever the frame carried). + */ + async *readSse(path, signal, frameSchema, onOpen) { + const response = await this.doFetch(new URL(path, this.resolveBase()), { signal }); + if (!response.ok || response.body === null) + throw new Error(`transport failure for ${path}: HTTP ${response.status}`); + onOpen?.(); + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let buffer = ''; + try { + while (true) { + const { done, value } = await reader.read(); + if (done) + return; + buffer += decoder.decode(value, { stream: true }); + let boundary; + while ((boundary = buffer.indexOf('\n\n')) !== -1) { + const chunk = buffer.slice(0, boundary); + buffer = buffer.slice(boundary + 2); + const data = chunk.split('\n').filter(line => line.startsWith('data: ')).map(line => line.slice(6)).join(''); + if (data === '') + continue; + let full; + let frame; + try { + full = serverRequestSchema.parse(JSON.parse(data)); + frame = frameSchema.parse(full.payload); + } + catch (error) { + console.error(`[apiproxy] dropping malformed SSE frame on ${path}:`, error); + continue; + } + this.onEnvelope(full); + yield { rpcId: full.rpcId, payload: frame }; + } + } + } + finally { + await reader.cancel().catch(() => undefined); + } + } + // ---- IApiClient API (arrow properties so destructured/passed references stay bound) ---- + sessions = { + list: (payload, signal) => this.callUnary('session.list', payload, signal), + search: (payload, signal) => this.callUnary('session.search', payload, signal), + create: (payload, signal) => this.callUnary('session.create', payload, signal), + history: (payload, signal) => this.callUnary('session.history', payload, signal), + models: (payload, signal) => this.callUnary('session.models', payload, signal), + selectModel: (payload, signal) => this.callUnary('session.selectModel', payload, signal), + rename: (payload, signal) => this.callUnary('session.rename', payload, signal), + fork: (payload, signal) => this.callUnary('session.fork', payload, signal), + prompt: (payload, signal) => this.callUnary('session.prompt', payload, signal), + attachment: (payload, signal) => this.callUnary('session.attachment', payload, signal), + updateQueue: (payload, signal) => this.callUnary('session.updateQueue', payload, signal), + cancel: (payload, signal) => this.callUnary('session.cancel', payload, signal), + }; + subagents = { + list: (payload, signal) => this.callUnary('subagent.list', payload, signal), + history: (payload, signal) => this.callUnary('subagent.history', payload, signal), + prompt: (payload, signal) => this.callUnary('subagent.prompt', payload, signal), + interrupt: (payload, signal) => this.callUnary('subagent.interrupt', payload, signal), + }; + host = { + describe: (payload, signal) => this.callUnary('host.describe', payload, signal), + // A native system dialog is user-paced and may legitimately stay open + // longer than the normal unary deadline. Caller/connection aborts remain. + pickDirectory: (payload, signal) => this.callUnary('host.pickDirectory', payload, signal, 'caller-signal-only'), + listDirectory: (payload, signal) => this.callUnary('host.listDirectory', payload, signal), + createDirectory: (payload, signal) => this.callUnary('host.createDirectory', payload, signal), + openPath: (payload, signal) => this.callUnary('host.openPath', payload, signal), + }; + workspace = { + list: (payload, signal) => this.callUnary('workspace.list', payload, signal), + create: (payload, signal) => this.callUnary('workspace.create', payload, signal), + rename: (payload, signal) => this.callUnary('workspace.rename', payload, signal), + delete: (payload, signal) => this.callUnary('workspace.delete', payload, signal), + insertBefore: (payload, signal) => this.callUnary('workspace.insertBefore', payload, signal), + insertSessionBefore: (payload, signal) => this.callUnary('workspace.insertSessionBefore', payload, signal), + archiveSession: (payload, signal) => this.callUnary('workspace.archiveSession', payload, signal), + }; + skills = { + list: (payload, signal) => this.callUnary('skill.list', payload, signal), + }; + // Annotated like every sibling, and load-bearing rather than cosmetic: + // inferring this member inlines `AgentPresetEntry` into the emitted + // declaration by the specifier TS picks — the host `index.ts` — which drags + // the whole gateway, and with it the host `Context` merges, into every + // Client program that imports this carrier. + agentPresets = { + list: (payload, signal) => this.callUnary('agentPreset.list', payload, signal), + select: (payload, signal) => this.callUnary('agentPreset.select', payload, signal), + read: (payload, signal) => this.callUnary('agentPreset.read', payload, signal), + copy: (payload, signal) => this.callUnary('agentPreset.copy', payload, signal), + openDocument: (payload, signal) => this.callUnary('agentPreset.openDocument', payload, signal), + remove: (payload, signal) => this.callUnary('agentPreset.remove', payload, signal), + }; + goals = { + create: (payload, signal) => this.callUnary('goal.create', payload, signal), + edit: (payload, signal) => this.callUnary('goal.edit', payload, signal), + pause: (payload, signal) => this.callUnary('goal.pause', payload, signal), + resume: (payload, signal) => this.callUnary('goal.resume', payload, signal), + complete: (payload, signal) => this.callUnary('goal.complete', payload, signal), + clear: (payload, signal) => this.callUnary('goal.clear', payload, signal), + }; + settings = { + describe: (payload, signal) => this.callUnary('settings.describe', payload, signal), + openDocument: (payload, signal) => this.callUnary('settings.openDocument', payload, signal), + update: (payload, signal) => this.callUnary('settings.update', payload, signal), + replace: (payload, signal) => this.callUnary('settings.replace', payload, signal), + mutate: (payload, signal) => this.callUnary('settings.mutate', payload, signal), + }; + credentials = { + describe: (payload, signal) => this.callUnary('credentials.describe', payload, signal), + set: (payload, signal) => this.callUnary('credentials.set', payload, signal), + unset: (payload, signal) => this.callUnary('credentials.unset', payload, signal), + }; + llm = { + providers: (payload, signal) => this.callUnary('llm.providers', payload, signal), + models: (payload, signal) => this.callUnary('llm.models', payload, signal), + discoverModels: (payload, signal) => this.callUnary('llm.discoverModels', payload, signal), + }; + events = { + mux: (payload, signal, onOpen) => this.openMux(payload, signal, onOpen), + host: (payload, signal, onOpen) => this.openHost(payload, signal, onOpen), + }; + async respond(message, signal) { + this.onEnvelope(message); + const response = await this.postJson('/api/respond', message, signal); + return rpcReceiptSchema.parse(await response.json()); + } +} +/** + * In-process client over an injected fetch-shaped handler (the isomorphic point: + * `new InProcessApiClient(toFetchHandler(api))` never touches the network). Lives here because + * in-process injection is this package's own capability (handler and client are both local). + */ +export class InProcessApiClient extends AbstractApiClient { + handler; + constructor(handler, timeoutMs) { + super(timeoutMs); + this.handler = handler; + } + /** + * Faithful to real fetch: reject on signal abort even when the in-process + * handler ignores the signal (a hung impl must not defeat timeout/cancel). + */ + doFetch(input, init) { + const signal = init?.signal ?? undefined; + if (signal === undefined) + return this.handler.fetch(input, init); + if (signal.aborted) + return Promise.reject(abortError(signal)); + return new Promise((resolve, reject) => { + const onAbort = () => { reject(abortError(signal)); }; + signal.addEventListener('abort', onAbort, { once: true }); + this.handler.fetch(input, init) + .then(resolve, reject) + .finally(() => { signal.removeEventListener('abort', onAbort); }); + }); + } +} +/** Mirror fetch's abort rejection: the signal's reason when present, else a DOMException-style AbortError. */ +function abortError(signal) { + const reason = signal.reason; + if (reason instanceof Error) + return reason; + if (typeof reason === 'string') + return new Error(reason); + return new Error('This operation was aborted'); +} +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.d.ts new file mode 100644 index 0000000..7facaf2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.d.ts @@ -0,0 +1,17 @@ +/** + * Server side of the fetch carrier: maps an ApiProxy onto a pure + * WHATWG Request->Response function. Two-level parse: full form (type/rpcId/method + + * path==method) -> payload dispatched per method. HTTP status expresses only the carrier + * (404 unknown path / 415 non-JSON media type / 400 non-JSON body / 500 handler crash); + * business errors are always 200 + ServerResponse. + */ +import type { ApiProxy } from '../api/index.ts'; +/** + * Wraps an ApiProxy into a pure fetch function (isomorphic point: feed the returned fetch straight to InProcessApiClient). + * @param api - the host-side ApiProxy implementation. + * @returns an object holding `fetch(Request)`; paths outside /api/ return 404. + */ +export declare function toFetchHandler(api: ApiProxy): { + fetch: typeof fetch; +}; +//# sourceMappingURL=handler.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.js new file mode 100644 index 0000000..9d72e02 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/fetch/handler.js @@ -0,0 +1,245 @@ +/** + * Server side of the fetch carrier: maps an ApiProxy onto a pure + * WHATWG Request->Response function. Two-level parse: full form (type/rpcId/method + + * path==method) -> payload dispatched per method. HTTP status expresses only the carrier + * (404 unknown path / 415 non-JSON media type / 400 non-JSON body / 500 handler crash); + * business errors are always 200 + ServerResponse. + */ +import { randomUUID } from 'node:crypto'; +import { sessionLogQuerySchema } from "../api/downloads.schema.js"; +import { RpcId } from "../api/rpc.js"; +import { clientRequestSchema, clientResponseSchema } from "../api/rpc.schema.js"; +import { sessionCancelRequestSchema, sessionAttachmentRequestSchema, sessionCreateRequestSchema, sessionForkRequestSchema, sessionHistoryRequestSchema, sessionListRequestSchema, sessionModelsRequestSchema, sessionPromptRequestSchema, sessionRenameRequestSchema, sessionSearchRequestSchema, sessionSelectModelRequestSchema, sessionUpdateQueueRequestSchema, } from "../api/sessions.schema.js"; +import { hostCreateDirectoryRequestSchema, hostDescribeRequestSchema, hostListDirectoryRequestSchema, hostOpenPathRequestSchema, hostPickDirectoryRequestSchema, } from "../api/host.schema.js"; +import { workspaceArchiveSessionRequestSchema, workspaceCreateRequestSchema, workspaceDeleteRequestSchema, workspaceInsertBeforeRequestSchema, workspaceInsertSessionBeforeRequestSchema, workspaceListRequestSchema, workspaceRenameRequestSchema, } from "../api/workspace.schema.js"; +import { skillListRequestSchema } from "../api/skills.schema.js"; +import { agentPresetCopyRequestSchema, agentPresetListRequestSchema, agentPresetOpenDocumentRequestSchema, agentPresetReadRequestSchema, agentPresetRemoveRequestSchema, agentPresetSelectRequestSchema, } from "../api/agent-presets.schema.js"; +import { goalCreateRequestSchema, goalEditRequestSchema, goalPauseRequestSchema, goalResumeRequestSchema, goalCompleteRequestSchema, goalClearRequestSchema, } from "../api/goals.schema.js"; +import { settingsDescribeRequestSchema, settingsMutateRequestSchema, settingsOpenDocumentRequestSchema, settingsReplaceRequestSchema, settingsUpdateRequestSchema, } from "../api/settings.schema.js"; +import { credentialsDescribeRequestSchema, credentialsSetRequestSchema, credentialsUnsetRequestSchema, } from "../api/credentials.schema.js"; +import { llmDiscoverModelsRequestSchema, llmModelsRequestSchema, llmProvidersRequestSchema } from "../api/llm.schema.js"; +import { subagentHistoryRequestSchema, subagentInterruptRequestSchema, subagentListRequestSchema, subagentPromptRequestSchema, } from "../api/subagents.schema.js"; +const UNARY_ROUTES = { + 'session.list': { schema: sessionListRequestSchema, invoke: (api, r) => api.sessions.list(r) }, + 'session.search': { schema: sessionSearchRequestSchema, invoke: (api, r, signal) => api.sessions.search(r, signal) }, + 'session.create': { schema: sessionCreateRequestSchema, invoke: (api, r) => api.sessions.create(r) }, + 'session.history': { schema: sessionHistoryRequestSchema, invoke: (api, r) => api.sessions.history(r) }, + 'session.models': { schema: sessionModelsRequestSchema, invoke: (api, r) => api.sessions.models(r) }, + 'session.selectModel': { schema: sessionSelectModelRequestSchema, invoke: (api, r) => api.sessions.selectModel(r) }, + 'session.rename': { schema: sessionRenameRequestSchema, invoke: (api, r) => api.sessions.rename(r) }, + 'session.fork': { schema: sessionForkRequestSchema, invoke: (api, r) => api.sessions.fork(r) }, + 'session.prompt': { schema: sessionPromptRequestSchema, invoke: (api, r) => api.sessions.prompt(r) }, + 'session.attachment': { schema: sessionAttachmentRequestSchema, invoke: (api, r) => api.sessions.attachment(r) }, + 'session.updateQueue': { schema: sessionUpdateQueueRequestSchema, invoke: (api, r) => api.sessions.updateQueue(r) }, + 'session.cancel': { schema: sessionCancelRequestSchema, invoke: (api, r) => api.sessions.cancel(r) }, + 'subagent.list': { schema: subagentListRequestSchema, invoke: (api, r, signal) => api.subagents.list(r, signal) }, + 'subagent.history': { schema: subagentHistoryRequestSchema, invoke: (api, r, signal) => api.subagents.history(r, signal) }, + 'subagent.prompt': { schema: subagentPromptRequestSchema, invoke: (api, r, signal) => api.subagents.prompt(r, signal) }, + 'subagent.interrupt': { schema: subagentInterruptRequestSchema, invoke: (api, r) => api.subagents.interrupt(r) }, + 'host.describe': { schema: hostDescribeRequestSchema, invoke: (api, r) => api.host.describe(r) }, + 'host.pickDirectory': { schema: hostPickDirectoryRequestSchema, invoke: (api, r, signal) => api.host.pickDirectory(r, signal) }, + 'host.listDirectory': { schema: hostListDirectoryRequestSchema, invoke: (api, r, signal) => api.host.listDirectory(r, signal) }, + 'host.createDirectory': { schema: hostCreateDirectoryRequestSchema, invoke: (api, r) => api.host.createDirectory(r) }, + 'host.openPath': { schema: hostOpenPathRequestSchema, invoke: (api, r, signal) => api.host.openPath(r, signal) }, + 'workspace.list': { schema: workspaceListRequestSchema, invoke: (api, r) => api.workspace.list(r) }, + 'workspace.create': { schema: workspaceCreateRequestSchema, invoke: (api, r) => api.workspace.create(r) }, + 'workspace.rename': { schema: workspaceRenameRequestSchema, invoke: (api, r) => api.workspace.rename(r) }, + 'workspace.delete': { schema: workspaceDeleteRequestSchema, invoke: (api, r) => api.workspace.delete(r) }, + 'workspace.insertBefore': { schema: workspaceInsertBeforeRequestSchema, invoke: (api, r) => api.workspace.insertBefore(r) }, + 'workspace.insertSessionBefore': { schema: workspaceInsertSessionBeforeRequestSchema, invoke: (api, r) => api.workspace.insertSessionBefore(r) }, + 'workspace.archiveSession': { schema: workspaceArchiveSessionRequestSchema, invoke: (api, r) => api.workspace.archiveSession(r) }, + 'skill.list': { schema: skillListRequestSchema, invoke: (api, r) => api.skills.list(r) }, + 'agentPreset.list': { schema: agentPresetListRequestSchema, invoke: (api, r) => api.agentPresets.list(r) }, + 'agentPreset.select': { schema: agentPresetSelectRequestSchema, invoke: (api, r) => api.agentPresets.select(r) }, + 'agentPreset.read': { schema: agentPresetReadRequestSchema, invoke: (api, r) => api.agentPresets.read(r) }, + 'agentPreset.copy': { schema: agentPresetCopyRequestSchema, invoke: (api, r) => api.agentPresets.copy(r) }, + 'agentPreset.openDocument': { schema: agentPresetOpenDocumentRequestSchema, invoke: (api, r, signal) => api.agentPresets.openDocument(r, signal) }, + 'agentPreset.remove': { schema: agentPresetRemoveRequestSchema, invoke: (api, r) => api.agentPresets.remove(r) }, + 'goal.create': { schema: goalCreateRequestSchema, invoke: (api, r) => api.goals.create(r) }, + 'goal.edit': { schema: goalEditRequestSchema, invoke: (api, r) => api.goals.edit(r) }, + 'goal.pause': { schema: goalPauseRequestSchema, invoke: (api, r) => api.goals.pause(r) }, + 'goal.resume': { schema: goalResumeRequestSchema, invoke: (api, r) => api.goals.resume(r) }, + 'goal.complete': { schema: goalCompleteRequestSchema, invoke: (api, r) => api.goals.complete(r) }, + 'goal.clear': { schema: goalClearRequestSchema, invoke: (api, r) => api.goals.clear(r) }, + 'settings.describe': { schema: settingsDescribeRequestSchema, invoke: (api, r) => api.settings.describe(r) }, + 'settings.openDocument': { schema: settingsOpenDocumentRequestSchema, invoke: (api, r, signal) => api.settings.openDocument(r, signal) }, + 'settings.update': { schema: settingsUpdateRequestSchema, invoke: (api, r) => api.settings.update(r) }, + 'settings.replace': { schema: settingsReplaceRequestSchema, invoke: (api, r) => api.settings.replace(r) }, + 'settings.mutate': { schema: settingsMutateRequestSchema, invoke: (api, r) => api.settings.mutate(r) }, + 'credentials.describe': { schema: credentialsDescribeRequestSchema, invoke: (api, r) => api.credentials.describe(r) }, + 'credentials.set': { schema: credentialsSetRequestSchema, invoke: (api, r) => api.credentials.set(r) }, + 'credentials.unset': { schema: credentialsUnsetRequestSchema, invoke: (api, r) => api.credentials.unset(r) }, + 'llm.providers': { schema: llmProvidersRequestSchema, invoke: (api, r) => api.llm.providers(r) }, + 'llm.models': { schema: llmModelsRequestSchema, invoke: (api, r) => api.llm.models(r) }, + 'llm.discoverModels': { schema: llmDiscoverModelsRequestSchema, invoke: (api, r, signal) => api.llm.discoverModels(r, signal) }, +}; +/** Route lookup that narrows an arbitrary path segment to a map key (single cast point for the string→key refinement). */ +function methodFor(path) { + return Object.hasOwn(UNARY_ROUTES, path) ? path : undefined; +} +/** + * Sentinel rpcId for error responses to envelopes whose own rpcId is unreadable: the response + * must still be a valid ServerResponse (a self-violating shape would turn the server's explicit + * bad-request report into a client-side parse failure). Fixed value, documented here as wire contract. + */ +const INVALID_REQUEST_RPC_ID = RpcId('invalid-request'); +/** Wrap a business error as a ServerResponse full form (rpcId backfilled; an unreadable rpcId uses the invalid-request sentinel). */ +function errorResponse(rpcId, error) { + const body = { type: 'server-response', rpcId, result: { ok: false, error } }; + return Response.json(body); +} +/** Complete the impl's narrow form into a ServerResponse full form. */ +function fullResponse(narrow) { + const body = { type: 'server-response', rpcId: narrow.rpcId, result: narrow.result }; + return Response.json(body); +} +/** + * Parse the payload and invoke one unary route. Generic over the map key so + * the row's schema/invoke pairing typechecks; the only cast collapses the + * Wire<> widening back to the exact payload (undefined-valued properties and + * absent ones are indistinguishable after JSON transport). + */ +// K appears once in the signature but ties the UNARY_ROUTES[K] row lookup to its own +// schema/invoke pairing; a union parameter degrades the row to an uninvokable intersection. +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters +async function handleUnary(api, method, message, signal) { + const route = UNARY_ROUTES[method]; + const payload = route.schema.safeParse(message.payload); + if (!payload.success) { + return errorResponse(message.rpcId, { code: 'bad-request', message: `invalid payload for ${method}`, details: { issues: payload.error.issues } }); + } + try { + return fullResponse(await route.invoke(api, { rpcId: message.rpcId, payload: payload.data }, signal)); + } + catch (error) { + // The impl never throws business errors; reaching here means the implementation itself crashed — 500, carrier layer. + return new Response(`handler failure: ${String(error)}`, { status: 500 }); + } +} +/** SSE frame: complete the narrow RpcRequest into a ServerRequest full form (method = frame type). */ +function fullFrame(narrow) { + return { type: 'server-request', rpcId: narrow.rpcId, method: narrow.payload.type, payload: narrow.payload }; +} +/** + * Wrap a frame stream as an SSE Response; stops when req.signal aborts. An + * impl throw mid-stream emits one stream/error frame and then closes. + */ +function sseResponse(frames) { + const encoder = new TextEncoder(); + const stream = new ReadableStream({ + async start(controller) { + try { + // Send an SSE comment line on open so clients/proxies see a live channel (the host + // stream has no baseline frames and would otherwise emit zero bytes while idle; + // a comment line is not a frame, so client frame parsing skips it naturally). + controller.enqueue(encoder.encode(': connected\n\n')); + for await (const narrow of frames) { + controller.enqueue(encoder.encode(`data: ${JSON.stringify(fullFrame(narrow))}\n\n`)); + } + } + catch (error) { + // Mid-stream impl failure → one stream/error frame, then close: the client must see + // the failure instead of a silent end (which reads as a normal disconnect). A fresh + // rpcId is minted — this is a server-initiated push like any other frame. + const failure = { type: 'stream/error', error: { code: 'internal', message: String(error), details: {} } }; + try { + controller.enqueue(encoder.encode(`data: ${JSON.stringify(fullFrame({ rpcId: RpcId(randomUUID()), payload: failure }))}\n\n`)); + } + catch { + // Consumer already cancelled the stream: enqueue-after-cancel is the + // only reachable error, and there is no one left to tell. + } + } + finally { + try { + controller.close(); + } + catch { /* already cancelled by the consumer: a double close is the only reachable error */ } + } + }, + }); + return new Response(stream, { + headers: { 'content-type': 'text/event-stream', 'cache-control': 'no-cache' }, + }); +} +/** + * Wraps an ApiProxy into a pure fetch function (isomorphic point: feed the returned fetch straight to InProcessApiClient). + * @param api - the host-side ApiProxy implementation. + * @returns an object holding `fetch(Request)`; paths outside /api/ return 404. + */ +export function toFetchHandler(api) { + return { + // Signature matches global fetch: the isomorphic point hands this function to InProcessApiClient as its transport aspect, + // Clients call in (url, init) form — normalize to Request before handling. + async fetch(input, init) { + const req = input instanceof Request ? input : new Request(input, init); + const url = new URL(req.url); + const path = url.pathname; + // No-envelope read channels (SSE GET streams + host-only download): + // physical routes that answer directly, without a wire envelope. + if (path === '/api/events.mux' && req.method === 'GET') { + return sseResponse(api.events.mux({ rpcId: RpcId(randomUUID()), payload: {} }, req.signal)); + } + if (path === '/api/events.host' && req.method === 'GET') { + return sseResponse(api.events.host({ rpcId: RpcId(randomUUID()), payload: {} }, req.signal)); + } + if (path === '/api/session.export' && (req.method === 'GET' || req.method === 'HEAD')) { + // Query params are a different boundary from the POST envelope, but + // the request still casts its brands only through the domain schema. + const parsed = sessionLogQuerySchema.safeParse(Object.fromEntries(url.searchParams)); + if (!parsed.success) { + return new Response('missing or invalid sessionId query parameter', { status: 400 }); + } + const response = await api.downloads.sessionLog(parsed.data, req.signal); + if (req.method === 'GET') + return response; + await response.body?.cancel(); + return new Response(null, { status: response.status, headers: response.headers }); + } + if (req.method !== 'POST' || !path.startsWith('/api/')) { + return new Response('not found', { status: 404 }); + } + // Cross-site write fence: browsers send "simple" POSTs (text/plain, + // form encodings) without a CORS preflight, so a malicious page could + // otherwise execute side-effectful RPCs blind — the response stays + // unreadable cross-origin, but session.prompt would still run. Only the + // JSON media type is accepted; anything else is forced into a preflight + // this server never answers. 415 = carrier layer, like the 400 below. + const mediaType = req.headers.get('content-type')?.split(';', 1)[0]?.trim().toLowerCase(); + if (mediaType !== 'application/json') { + return new Response('content type must be application/json', { status: 415 }); + } + let body; + try { + body = await req.json(); + } + catch { + // 400 = carrier layer (body is not even JSON); valid JSON with a bad shape goes 200 + bad-request. + return new Response('body is not JSON', { status: 400 }); + } + if (path === '/api/respond') { + const parsed = clientResponseSchema.safeParse(body); + if (!parsed.success) + return Response.json({ accepted: false, reason: 'bad-response' }); + return Response.json(await api.respond(parsed.data)); + } + const method = methodFor(path.slice('/api/'.length)); + if (method === undefined) + return new Response('not found', { status: 404 }); + const envelope = clientRequestSchema.safeParse(body); + if (!envelope.success) { + // Best effort at correlation: salvage a string rpcId from the raw body; + // otherwise the fixed sentinel keeps the response a valid ServerResponse. + const rawId = body?.rpcId; + const rpcId = typeof rawId === 'string' ? RpcId(rawId) : INVALID_REQUEST_RPC_ID; + return errorResponse(rpcId, { code: 'bad-request', message: 'invalid client-request message', details: { issues: envelope.error.issues } }); + } + const message = envelope.data; + if (message.method !== method) { + return errorResponse(message.rpcId, { code: 'bad-request', message: `method "${message.method}" does not match path "${method}"`, details: { issues: [] } }); + } + return handleUnary(api, method, message, req.signal); + }, + }; +} +//# sourceMappingURL=handler.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.d.ts new file mode 100644 index 0000000..6737e91 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.d.ts @@ -0,0 +1,77 @@ +/** + * @deepseek-ai/dsh-host-apiproxy — the API gateway every client shape shares: + * the ApiProxy contract (api/: types + zod schemas, browser-safe), the fetch + * carrier pair (fetch/: toFetchHandler on the host side, AbstractApiClient + + * platform subclasses on the client side), and the host-side implementation + * (api-proxy.ts: createApiProxy + the ApiProxyService gateway plugin providing + * `ctx.apiProxy`). Transport-agnostic by design: this package registers no + * routes — physical carriers wrap `ctx.apiProxy` themselves. + * + * The gateway consumes `ctx.agentDefaultModel`, the transport-independent default + * shared with direct entry points. Switching models persists through that + * service; sessions that have already logged a selection remain unchanged. + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { ApiProxy } from './api/index.ts'; +export type * from './api/index.ts'; +export { RpcId } from './api/rpc.ts'; +export { toFetchHandler } from './fetch/handler.ts'; +export { AbstractApiClient, InProcessApiClient } from './fetch/client.ts'; +export type { IApiClient } from './fetch/client.ts'; +export { createApiProxy } from './api-proxy.ts'; +export type { ApiProxyDefaults } from './api-proxy.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + /** The host-side ApiProxy implementation (the transport-agnostic gateway face). */ + apiProxy: ApiProxy; + } +} +/** Gateway plugin configuration. */ +export interface Config { + /** + * Whether this deployment can hand paths to a native desktop opener — + * the `hasDocument` capability the agent-preset roster reports. Absent, + * the platform is asked (macOS/Windows/WSL yes; Linux only with a display + * server); set it explicitly where detection misleads, e.g. `false` in a + * container whose DISPLAY points nowhere a user can see. + */ + nativeOpen?: boolean; + /** + * DEFLATE level for every session-log ZIP entry: `0` stores without + * compression, `1` favors CPU/latency, and `9` favors archive size. + * @default 6 + */ + sessionExportCompressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; + /** + * Maximum physical size of a cold Session artifact eligible for blankness + * verification. Zero disables probes. + * @default 1024 + */ + coldBlankProbeMaxBytes?: number; +} +/** + * The API gateway service: implements the ApiProxy contract over the composed + * host context and provides it as `ctx.apiProxy`. The Host cwd is the default + * project directory. + */ +export declare class ApiProxyService extends Service implements ApiProxy { + static inject: string[]; + static Config: z; + readonly sessions: ApiProxy['sessions']; + readonly subagents: ApiProxy['subagents']; + readonly workspace: ApiProxy['workspace']; + readonly host: ApiProxy['host']; + readonly goals: ApiProxy['goals']; + readonly skills: ApiProxy['skills']; + readonly agentPresets: ApiProxy['agentPresets']; + readonly settings: ApiProxy['settings']; + readonly credentials: ApiProxy['credentials']; + readonly llm: ApiProxy['llm']; + readonly events: ApiProxy['events']; + readonly downloads: ApiProxy['downloads']; + readonly respond: ApiProxy['respond']; + constructor(ctx: Context, config: Config); +} +export default ApiProxyService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.js new file mode 100644 index 0000000..2b8862e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/index.js @@ -0,0 +1,83 @@ +/** + * @deepseek-ai/dsh-host-apiproxy — the API gateway every client shape shares: + * the ApiProxy contract (api/: types + zod schemas, browser-safe), the fetch + * carrier pair (fetch/: toFetchHandler on the host side, AbstractApiClient + + * platform subclasses on the client side), and the host-side implementation + * (api-proxy.ts: createApiProxy + the ApiProxyService gateway plugin providing + * `ctx.apiProxy`). Transport-agnostic by design: this package registers no + * routes — physical carriers wrap `ctx.apiProxy` themselves. + * + * The gateway consumes `ctx.agentDefaultModel`, the transport-independent default + * shared with direct entry points. Switching models persists through that + * service; sessions that have already logged a selection remain unchanged. + */ +import { Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { createApiProxy, DEFAULT_COLD_BLANK_PROBE_MAX_BYTES } from "./api-proxy.js"; +import { DEFAULT_SESSION_LOG_COMPRESSION_LEVEL, } from "./session-export.js"; +export { RpcId } from "./api/rpc.js"; +export { toFetchHandler } from "./fetch/handler.js"; +export { AbstractApiClient, InProcessApiClient } from "./fetch/client.js"; +export { createApiProxy } from "./api-proxy.js"; +/** + * The API gateway service: implements the ApiProxy contract over the composed + * host context and provides it as `ctx.apiProxy`. The Host cwd is the default + * project directory. + */ +export class ApiProxyService extends Service { + static inject = [ + 'agentDefaultModel', 'agents', 'attachments', 'directoryPicker', 'llm', 'sessions', 'subagents', 'sessionQuery', + 'tools', 'userQuestions', 'workspaceRegistry', + ]; + static Config = z.object({ + nativeOpen: z.boolean(), + sessionExportCompressionLevel: z.number().step(1).min(0).max(9) + .default(DEFAULT_SESSION_LOG_COMPRESSION_LEVEL), + coldBlankProbeMaxBytes: z.natural().default(DEFAULT_COLD_BLANK_PROBE_MAX_BYTES), + }); + sessions; + subagents; + workspace; + host; + goals; + skills; + agentPresets; + settings; + credentials; + llm; + events; + downloads; + respond; + constructor(ctx, config) { + super(ctx, 'apiProxy'); + const api = createApiProxy(ctx, { + defaultModelSelection: () => ctx.agentDefaultModel.currentSelection(), + saveDefaultModelSelection: selection => ctx.agentDefaultModel.saveSelection(selection), + cwd: process.cwd(), + ...config.nativeOpen === undefined ? {} : { canOpenPath: () => config.nativeOpen }, + ...(config.sessionExportCompressionLevel === undefined + ? {} + : { sessionExportCompressionLevel: config.sessionExportCompressionLevel }), + ...(config.coldBlankProbeMaxBytes === undefined + ? {} + : { coldBlankProbeMaxBytes: config.coldBlankProbeMaxBytes }), + }); + this.sessions = api.sessions; + this.subagents = api.subagents; + this.workspace = api.workspace; + this.host = api.host; + this.goals = api.goals; + this.skills = api.skills; + this.agentPresets = api.agentPresets; + this.settings = api.settings; + this.credentials = api.credentials; + this.llm = api.llm; + this.events = api.events; + this.downloads = api.downloads; + // createApiProxy returns closures (no `this` capture), so the bind is + // behavior-neutral. + this.respond = api.respond.bind(api); + } +} +export default ApiProxyService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.d.ts new file mode 100644 index 0000000..c1a26ef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-host-apiproxy`. + * @module @deepseek-ai/dsh-host-apiproxy/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "host-apiproxy-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.js new file mode 100644 index 0000000..465c9f8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/invariant.js @@ -0,0 +1,26 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-host-apiproxy`. + * @module @deepseek-ai/dsh-host-apiproxy/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-host-apiproxy'; +/** Cordis companion plugin name. */ +export const name = 'host-apiproxy-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: this package is the wire contract layer plus the + * host-side gateway over services owned elsewhere — it emits no cordis events + * of its own; the session/agent event streams it projects are asserted by + * their owning packages' companions. rpcId round-trip and schema acceptance + * are enforced at the carrier boundary and exercised by the + * protocol-isomorphism suite. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.d.ts new file mode 100644 index 0000000..526850f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.d.ts @@ -0,0 +1,50 @@ +/** + * Cross-platform native path and text-document openers used by the local GUI + * carrier. + * + * The default intent prefers the default browser for documents it renders when + * the platform can name one, then falls back to the default application. WSL + * translates every path for the Windows desktop instead of assuming a Linux + * GUI. The text-editor intent never consults the browser. + */ +import { type NativeCommandRunner } from '@deepseek-ai/dsh-native-command'; +/** Testable command boundary; native implementations never invoke a shell. */ +export type PathOpenerRunner = NativeCommandRunner; +/** Injectable platform facts for deterministic adapter tests. */ +export interface PathOpenerInternals { + platform?: NodeJS.Platform; + /** Kernel release override used to distinguish WSL from desktop Linux. */ + osRelease?: string; + /** Environment used for WSL markers and the desktop Linux browser convention. */ + env?: NodeJS.ProcessEnv; + run?: PathOpenerRunner; +} +/** + * Whether {@link openNativePath} plausibly reaches a desktop on this host. + * + * macOS and Windows always carry a desktop opener; Linux does when it is WSL + * (the Windows desktop takes the path) or a display server is announced. + * A headless or containerised Linux host answers false, which is what lets a + * surface show a path as text instead of offering a button that would spawn + * `xdg-open` into nothing. + * @param internals - platform and environment seam for deterministic tests. + * @returns true when handing a path to the native opener can work at all. + */ +export declare function canOpenNativePath(internals?: PathOpenerInternals): boolean; +/** + * Open a filesystem path with the operating system's default application, or + * with the default browser when the path names a document a browser renders. + * @param path - absolute or host-resolvable path (caller owns resolution). + * @param signal - caller/connection lifetime; abort terminates the native command. + * @param internals - Platform, environment, and runner hooks for deterministic tests. + */ +export declare function openNativePath(path: string, signal: AbortSignal, internals?: PathOpenerInternals): Promise; +/** + * Open a text document for editing; macOS bypasses the file-type association + * so a YAML association with a browser cannot consume the gesture. + * @param path - absolute or host-resolvable text-document path. + * @param signal - caller/connection lifetime; abort terminates the native command. + * @param internals - Platform and runner hooks for deterministic tests. + */ +export declare function openNativeTextFile(path: string, signal: AbortSignal, internals?: PathOpenerInternals): Promise; +//# sourceMappingURL=native-path-opener.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.js new file mode 100644 index 0000000..52bd294 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/native-path-opener.js @@ -0,0 +1,161 @@ +/** + * Cross-platform native path and text-document openers used by the local GUI + * carrier. + * + * The default intent prefers the default browser for documents it renders when + * the platform can name one, then falls back to the default application. WSL + * translates every path for the Windows desktop instead of assuming a Linux + * GUI. The text-editor intent never consults the browser. + */ +import { release as osRelease } from 'node:os'; +import { extname } from 'node:path'; +import { runNativeCommand } from '@deepseek-ai/dsh-native-command'; +/** Documents a browser renders, as opposed to ones an editor merely edits. */ +const BROWSER_DOCUMENTS = new Set(['.html', '.htm', '.xhtml', '.svg']); +/** + * The macOS bundle registered for `https` — the default browser, as + * LaunchServices records it. The nested version dict is stripped first + * because it carries its own `LSHandlerRoleAll`. + */ +function macBundleForHttps(plist) { + const stripped = plist.replace(/LSHandlerPreferredVersions\s*=\s*\{[^}]*\};/g, ''); + const block = /\{[^{}]*LSHandlerURLScheme\s*=\s*"?https"?;[^{}]*\}/.exec(stripped)?.[0]; + if (block === undefined) + return undefined; + return /LSHandlerRoleAll\s*=\s*"?([\w.-]+)"?;/.exec(block)?.[1]; +} +/** + * Open one browser-renderable document with the default browser. + * @returns true when a browser took it; false when this platform cannot name + * one, or naming it failed — the caller then uses the default application. + */ +async function openInBrowser(path, signal, platform, run, env) { + if (platform === 'darwin') { + let bundle; + try { + const { stdout } = await run('defaults', ['read', 'com.apple.LaunchServices/com.apple.launchservices.secure'], signal); + bundle = macBundleForHttps(stdout); + } + catch { + // No LaunchServices record (a fresh account never changed a default): + // the content-type handler is then the system's own choice anyway. + return false; + } + if (bundle === undefined) + return false; + await run('open', ['-b', bundle, path], signal); + return true; + } + if (platform === 'linux') { + // $BROWSER is the portable convention; desktop-entry resolution through + // xdg-settings needs a launcher this package has no business shipping. + const browser = env.BROWSER; + if (browser === undefined || browser === '') + return false; + await run(browser, [path], signal); + return true; + } + // Windows names no browser without reading the UserChoice registry, and its + // .html association is the browser in the ordinary case. + return false; +} +/** PowerShell single-quoted literal (doubles embedded quotes). */ +function powershellLiteral(path) { + return `'${path.replace(/'/g, "''")}'`; +} +/** Whether one environment marker is set to a non-empty value. */ +function present(value) { + return value !== undefined && value !== ''; +} +/** Distinguish WSL from desktop Linux using its process and kernel markers. */ +function isWsl(internals) { + const env = internals.env ?? process.env; + if (present(env.WSL_DISTRO_NAME) || present(env.WSL_INTEROP)) + return true; + return (internals.osRelease ?? osRelease()).toLowerCase().includes('microsoft'); +} +/** Open one Windows-resolvable path through its registered desktop application. */ +async function openWindowsPath(path, signal, run) { + await run('powershell.exe', [ + '-NoProfile', + '-Command', + `Invoke-Item -LiteralPath ${powershellLiteral(path)}`, + ], signal); +} +/** Translate a WSL path before handing it to the Windows desktop. */ +async function openWslPath(path, signal, run) { + const translated = await run('wslpath', ['-w', path], signal); + signal.throwIfAborted(); + const windowsPath = translated.stdout.replace(/[\r\n]+$/, ''); + if (windowsPath === '') + throw new Error('wslpath returned no Windows path'); + await openWindowsPath(windowsPath, signal, run); +} +/** Dispatch one shell-free platform command for the requested open intent. */ +async function openNativePathWithIntent(path, signal, intent, internals = {}) { + const platform = internals.platform ?? process.platform; + const run = internals.run ?? runNativeCommand; + const env = internals.env ?? process.env; + const wsl = platform === 'linux' && isWsl(internals); + if (!wsl && intent === 'default' && BROWSER_DOCUMENTS.has(extname(path).toLowerCase()) + && await openInBrowser(path, signal, platform, run, env)) + return; + if (platform === 'darwin') { + await run('open', intent === 'text-editor' ? ['-t', path] : [path], signal); + return; + } + if (platform === 'win32') { + await openWindowsPath(path, signal, run); + return; + } + if (platform === 'linux') { + if (wsl) { + await openWslPath(path, signal, run); + return; + } + await run('xdg-open', [path], signal); + return; + } + throw new Error(`native path opener is unsupported on ${platform}`); +} +/** + * Whether {@link openNativePath} plausibly reaches a desktop on this host. + * + * macOS and Windows always carry a desktop opener; Linux does when it is WSL + * (the Windows desktop takes the path) or a display server is announced. + * A headless or containerised Linux host answers false, which is what lets a + * surface show a path as text instead of offering a button that would spawn + * `xdg-open` into nothing. + * @param internals - platform and environment seam for deterministic tests. + * @returns true when handing a path to the native opener can work at all. + */ +export function canOpenNativePath(internals = {}) { + const platform = internals.platform ?? process.platform; + if (platform === 'darwin' || platform === 'win32') + return true; + if (platform !== 'linux') + return false; + const env = internals.env ?? process.env; + return isWsl(internals) || present(env.DISPLAY) || present(env.WAYLAND_DISPLAY); +} +/** + * Open a filesystem path with the operating system's default application, or + * with the default browser when the path names a document a browser renders. + * @param path - absolute or host-resolvable path (caller owns resolution). + * @param signal - caller/connection lifetime; abort terminates the native command. + * @param internals - Platform, environment, and runner hooks for deterministic tests. + */ +export function openNativePath(path, signal, internals = {}) { + return openNativePathWithIntent(path, signal, 'default', internals); +} +/** + * Open a text document for editing; macOS bypasses the file-type association + * so a YAML association with a browser cannot consume the gesture. + * @param path - absolute or host-resolvable text-document path. + * @param signal - caller/connection lifetime; abort terminates the native command. + * @param internals - Platform and runner hooks for deterministic tests. + */ +export function openNativeTextFile(path, signal, internals = {}) { + return openNativePathWithIntent(path, signal, 'text-editor', internals); +} +//# sourceMappingURL=native-path-opener.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.d.ts new file mode 100644 index 0000000..285a26b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.d.ts @@ -0,0 +1,106 @@ +/** + * Host-side session-log download: streams one ZIP archive whose files are the + * sessions' stored artifact text verbatim plus every referenced media object. + * The root artifact sits under its original base name (`session.jsonl`); each + * subagent descendant under `subagents//`; each image referenced + * by any included log under `media/.` (content-addressed, + * so one archive never duplicates a shared image). No manifest is written — + * every file is byte-identical to the backend's durable artifact or attachment + * store and self-describing through its own header line or media type. Before + * each live session's artifact read, the SessionStore flush barrier makes the + * current in-memory log durable; cold sessions need no barrier. Request abort + * and response-consumer cancellation share one producer signal and terminate + * the active compressor. + * Compression runs on the host with fflate's streaming Zip API, so the archive + * bytes are produced incrementally and the host never holds the whole archive + * in one buffer; production waits for consumer pull whenever the response queue + * reaches its byte high-water mark, so a slow consumer bounds accumulation to + * the fixed 64 KiB response queue plus one synchronous fflate push. + * @module + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { AttachmentStore } from '@deepseek-ai/dsh-attachment'; +import type { SessionQueryEngine } from '@deepseek-ai/dsh-session-query'; +import type { SessionId, SessionStore } from '@deepseek-ai/dsh-session'; +import type { SessionPersistence, SessionRawArtifact } from '@deepseek-ai/dsh-session-persistence'; +/** Valid fflate DEFLATE levels accepted by session-log export. */ +export type SessionLogCompressionLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; +/** Balanced default used when a direct createApiProxy caller omits deployment config. */ +export declare const DEFAULT_SESSION_LOG_COMPRESSION_LEVEL: SessionLogCompressionLevel; +/** The services a session-log export needs (the live-session store is optional). */ +export interface SessionLogExportDeps { + readonly sessionQuery: SessionQueryEngine | undefined; + readonly sessionPersistence: SessionPersistence | undefined; + readonly attachments: AttachmentStore | undefined; + readonly sessions: SessionStore | undefined; +} +/** The export services narrowed to the mounted ones streaming actually reads. */ +export interface SessionLogExportReady { + readonly sessionQuery: SessionQueryEngine; + readonly sessionPersistence: SessionPersistence; + readonly attachments: AttachmentStore; + readonly sessions: SessionStore | undefined; +} +/** + * Resolve the persistence, session-query, and attachment services a log export needs. + * @param ctx - the composed host context. + * @returns the export services (absent when the deployment does not mount them). + */ +export declare function sessionLogExportDeps(ctx: Context): SessionLogExportDeps; +/** + * Flush one currently live session through the store's authoritative durability + * barrier immediately before its raw artifact is read. A cold or absent id has + * no in-memory work to flush. + * @param deps - export services, including the optional live-session store. + * @param id - the session whose artifact is about to be read. + * @param signal - optional cancellation observed around the flush barrier. + */ +export declare function flushLiveSessionLog(deps: Pick, id: SessionId, signal?: AbortSignal): Promise; +/** One exported file: a stored artifact text or one referenced media object. */ +export type SessionLogZipEntry = { + readonly path: string; + readonly content: string; +} | { + readonly path: string; + readonly data: Uint8Array; +}; +/** + * The export archive filename for one root session. + * @param sessionId - the root session id (sanitized to one safe path segment). + * @returns the attachment filename for the session's export archive. + */ +export declare function sessionLogZipFilename(sessionId: string): string; +/** + * Yield the export entries in zip order: the preloaded root artifact first, + * then every subagent descendant in lineage order (each flushed when live, + * read from the persistence backend right before it is yielded, and dropped + * after the consumer moves on), then every distinct media object referenced by any of + * the included logs (read and verified from the attachment store, one archive + * entry per attachment id). The host holds at most one descendant's artifact + * text and one media object at a time beyond the root. + * @param deps - the mounted export services (the caller answered 500 before this runs). + * @param root - the already-read root artifact (read by the caller so the + * missing-session path can answer cleanly before streaming starts). + * @param sessionId - the root session id. + * @param includeDescendants - whether to include every subagent descendant. + * @param signal - optional cancellation forwarded to lineage, persistence, and attachment reads. + * @returns the export entries in zip order. + */ +export declare function sessionLogZipEntries(deps: SessionLogExportReady, root: SessionRawArtifact, sessionId: SessionId, includeDescendants: boolean, signal?: AbortSignal): AsyncGenerator; +/** + * Stream one session-log ZIP as a WHATWG ReadableStream. The root artifact is + * read and validated by the caller before this is called (missing root or + * missing services answer cleanly before any byte is produced); each entry is + * then encoded and deflated in bounded chunks as it is produced, so the + * archive bytes arrive incrementally. A descendant that fails to read errors + * the stream (fail-loud, never silent under-export). + * @param deps - the mounted export services (the caller answered 500 before this runs). + * @param root - the already-read root artifact (first zip entry). + * @param sessionId - the root session id. + * @param includeDescendants - whether to include every subagent descendant. + * @param compressionLevel - validated fflate DEFLATE level for every ZIP entry. + * @param signal - request cancellation combined with response-consumer cancellation. + * @returns the zip byte stream. + */ +export declare function streamSessionLogZip(deps: SessionLogExportReady, root: SessionRawArtifact, sessionId: SessionId, includeDescendants: boolean, compressionLevel: SessionLogCompressionLevel, signal: AbortSignal): ReadableStream; +//# sourceMappingURL=session-export.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.js new file mode 100644 index 0000000..0ce469c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/session-export.js @@ -0,0 +1,388 @@ +/** + * Host-side session-log download: streams one ZIP archive whose files are the + * sessions' stored artifact text verbatim plus every referenced media object. + * The root artifact sits under its original base name (`session.jsonl`); each + * subagent descendant under `subagents//`; each image referenced + * by any included log under `media/.` (content-addressed, + * so one archive never duplicates a shared image). No manifest is written — + * every file is byte-identical to the backend's durable artifact or attachment + * store and self-describing through its own header line or media type. Before + * each live session's artifact read, the SessionStore flush barrier makes the + * current in-memory log durable; cold sessions need no barrier. Request abort + * and response-consumer cancellation share one producer signal and terminate + * the active compressor. + * Compression runs on the host with fflate's streaming Zip API, so the archive + * bytes are produced incrementally and the host never holds the whole archive + * in one buffer; production waits for consumer pull whenever the response queue + * reaches its byte high-water mark, so a slow consumer bounds accumulation to + * the fixed 64 KiB response queue plus one synchronous fflate push. + * @module + */ +import { Zip, ZipDeflate } from 'fflate'; +/** Balanced default used when a direct createApiProxy caller omits deployment config. */ +export const DEFAULT_SESSION_LOG_COMPRESSION_LEVEL = 6; +/** + * Resolve the persistence, session-query, and attachment services a log export needs. + * @param ctx - the composed host context. + * @returns the export services (absent when the deployment does not mount them). + */ +export function sessionLogExportDeps(ctx) { + return { + sessionQuery: ctx.get('sessionQuery'), + sessionPersistence: ctx.get('sessionPersistence'), + attachments: ctx.get('attachments'), + sessions: ctx.get('sessions'), + }; +} +/** + * Flush one currently live session through the store's authoritative durability + * barrier immediately before its raw artifact is read. A cold or absent id has + * no in-memory work to flush. + * @param deps - export services, including the optional live-session store. + * @param id - the session whose artifact is about to be read. + * @param signal - optional cancellation observed around the flush barrier. + */ +export async function flushLiveSessionLog(deps, id, signal) { + signal?.throwIfAborted(); + const sessions = deps.sessions; + if (sessions === undefined) + return; + const session = sessions.get(id); + if (session === undefined) + return; + await sessions.flush(session); + signal?.throwIfAborted(); +} +/** Zip extension for each accepted raster media type. */ +const MEDIA_TYPE_EXTENSIONS = { + 'image/png': 'png', + 'image/jpeg': 'jpg', + 'image/webp': 'webp', + 'image/gif': 'gif', +}; +/** + * The zip path for one media object: content-addressed by the opaque + * attachment id so shared images land once and the id in the log maps back to + * the archive entry without a manifest. + * @param ref - the durable reference from a session log. + * @returns the archive path. + */ +function mediaEntryPath(ref) { + return `media/${String(ref.attachmentId)}.${MEDIA_TYPE_EXTENSIONS[ref.mediaType]}`; +} +/** + * Collect every image reference inside one content array, descending into + * nested tool results the way the live attachment route does. + * @param content - an event content array (or nested tool-result content). + * @param refs - the dedupe map being filled (keyed by attachment id). + */ +function collectImageRefs(content, refs) { + if (!Array.isArray(content)) + return; + const pending = []; + for (const item of content) + pending.push(item); + while (pending.length > 0) { + const value = pending.pop(); + if (typeof value !== 'object' || value === null || Array.isArray(value)) + continue; + const block = value; + if (block.type === 'image' && typeof block.attachment === 'object' && block.attachment !== null) { + const ref = block.attachment; + refs.set(String(ref.attachmentId), ref); + } + if (Array.isArray(block.content)) { + for (const item of block.content) + pending.push(item); + } + } +} +/** + * Collect every image reference one session event carries, across the same + * carriers the live attachment route scans (direct content, message content, + * inserted messages, and completed assistant chunk blocks). + * @param event - one parsed JSONL event object. + * @param refs - the dedupe map being filled (keyed by attachment id). + */ +function collectEventImageRefs(event, refs) { + const data = event.data; + if (typeof data !== 'object' || data === null) + return; + const carrier = data; + collectImageRefs(carrier.content, refs); + if (carrier.message !== undefined) + collectImageRefs(carrier.message.content, refs); + if (carrier.inserted !== undefined) { + for (const message of carrier.inserted) + collectImageRefs(message.content, refs); + } + if (carrier.chunk?.type === 'block-end') + collectImageRefs([carrier.chunk.block], refs); +} +/** + * Collect the distinct media references one stored artifact text names. + * Lines that fail to parse cannot reference media and are skipped (the + * artifact text itself is exported verbatim regardless). + * @param content - the stored artifact text. + * @returns the dedupe map keyed by attachment id. + */ +function imageRefsInArtifact(content) { + const refs = new Map(); + for (const line of content.split('\n')) { + if (line === '') + continue; + let event; + try { + event = JSON.parse(line); + } + catch { + continue; + } + collectEventImageRefs(event, refs); + } + return refs; +} +/** + * One safe zip path segment from an untrusted session id. Session ids are + * host-controlled, but the brand allows any non-empty string, so `../`, dot + * segments, and separator characters are neutralized before they can shape + * archive entries. Distinct ids may collapse onto one segment (id collision + * is impossible for the host-minted UUIDs, so no uniqueness suffix is kept). + * @param id - the raw session id. + * @returns a filesystem-safe single path segment. + */ +function safeSessionIdSegment(id) { + return id.replace(/[^A-Za-z0-9_-]/g, '_'); +} +/** + * The export archive filename for one root session. + * @param sessionId - the root session id (sanitized to one safe path segment). + * @returns the attachment filename for the session's export archive. + */ +export function sessionLogZipFilename(sessionId) { + return `dsh-session-${safeSessionIdSegment(sessionId)}.zip`; +} +/** + * Yield the export entries in zip order: the preloaded root artifact first, + * then every subagent descendant in lineage order (each flushed when live, + * read from the persistence backend right before it is yielded, and dropped + * after the consumer moves on), then every distinct media object referenced by any of + * the included logs (read and verified from the attachment store, one archive + * entry per attachment id). The host holds at most one descendant's artifact + * text and one media object at a time beyond the root. + * @param deps - the mounted export services (the caller answered 500 before this runs). + * @param root - the already-read root artifact (read by the caller so the + * missing-session path can answer cleanly before streaming starts). + * @param sessionId - the root session id. + * @param includeDescendants - whether to include every subagent descendant. + * @param signal - optional cancellation forwarded to lineage, persistence, and attachment reads. + * @returns the export entries in zip order. + */ +export async function* sessionLogZipEntries(deps, root, sessionId, includeDescendants, signal) { + const media = new Map(); + const rememberMedia = (content) => { + for (const [id, ref] of imageRefsInArtifact(content)) + media.set(id, ref); + }; + rememberMedia(root.content); + yield { path: root.filename, content: root.content }; + if (includeDescendants) { + const seen = new Set([sessionId]); + const collect = async function* (nodes) { + for (const node of nodes) { + signal?.throwIfAborted(); + const id = node.session.header.id; + if (seen.has(id)) + continue; + seen.add(id); + await flushLiveSessionLog(deps, id, signal); + const raw = await deps.sessionPersistence.readRaw(id, signal); + signal?.throwIfAborted(); + if (raw === undefined) { + throw new Error(`subagent "${id}" has no stored log artifact`); + } + rememberMedia(raw.content); + yield { + path: `subagents/${safeSessionIdSegment(id)}/${raw.filename}`, + content: raw.content, + }; + yield* collect(node.descendants); + } + }; + const lineage = await deps.sessionQuery.traceSession(sessionId, signal); + signal?.throwIfAborted(); + yield* collect(lineage.descendants); + } + for (const ref of media.values()) { + signal?.throwIfAborted(); + const stored = await deps.attachments.readImage(ref, signal); + signal?.throwIfAborted(); + yield { path: mediaEntryPath(ref), data: stored.data }; + } +} +/** How many code units of artifact text one zip push carries (bounded encode memory). */ +const PUSH_CHUNK_CODE_UNITS = 1 << 16; +/** How many bytes of media one zip push carries (bounded memory; images are already size-capped). */ +const PUSH_CHUNK_BYTES = 1 << 16; +/** Byte capacity retained by the response stream before ZIP production waits for pull. */ +const RESPONSE_HIGH_WATER_MARK_BYTES = 1 << 16; +/** One producer waiter released only when ReadableStream pull restores capacity. */ +class ResponseCapacityGate { + releasePending; + /** + * Wait until the response queue has positive byte capacity or cancellation wins. + * @param controller - response controller whose desired size owns capacity. + * @param signal - combined request/consumer cancellation. + */ + async wait(controller, signal) { + signal.throwIfAborted(); + if (controller.desiredSize === null || controller.desiredSize > 0) + return; + await new Promise((resolve) => { + const release = () => { + this.releasePending = undefined; + signal.removeEventListener('abort', release); + resolve(); + }; + this.releasePending = release; + signal.addEventListener('abort', release, { once: true }); + }); + signal.throwIfAborted(); + } + /** Release the current producer waiter after a consumer pull. */ + pulled() { + this.releasePending?.(); + } +} +/** + * Push one media object's bytes into a deflate stream in bounded chunks, + * waiting for consumer capacity between chunks like the artifact path does. + * @param deflate - the zip entry's deflate stream. + * @param data - the stored image bytes. + * @param controller - response queue controller. + * @param capacity - pull-driven response-capacity gate. + * @param signal - cancellation; throws when aborted. + */ +async function pushBinaryChunks(deflate, data, controller, capacity, signal) { + let offset = 0; + do { + signal.throwIfAborted(); + const end = Math.min(offset + PUSH_CHUNK_BYTES, data.byteLength); + const finalChunk = end >= data.byteLength; + deflate.push(data.subarray(offset, end), finalChunk); + offset = end; + await capacity.wait(controller, signal); + } while (offset < data.byteLength); +} +/** + * Push one artifact's text into a deflate stream in bounded chunks, never + * splitting a surrogate pair across a chunk boundary (a lone high surrogate + * re-encodes as U+FFFD and would silently corrupt the exported artifact). + * @param deflate - the zip entry's deflate stream. + * @param content - the artifact text verbatim. + * @param controller - response queue controller. + * @param capacity - pull-driven response-capacity gate. + * @param signal - cancellation; throws when aborted. + */ +async function pushArtifactChunks(deflate, content, controller, capacity, signal) { + const encoder = new TextEncoder(); + let offset = 0; + let finalChunk; + do { + signal.throwIfAborted(); + let end = Math.min(offset + PUSH_CHUNK_CODE_UNITS, content.length); + if (end < content.length && end - offset > 1) { + // Back off one code unit when the boundary lands inside a surrogate + // pair: the pair then starts the next chunk whole. + const last = content.charCodeAt(end - 1); + if (last >= 0xd800 && last <= 0xdbff) + end -= 1; + } + finalChunk = end >= content.length; + deflate.push(encoder.encode(content.slice(offset, end)), finalChunk); + offset = end; + await capacity.wait(controller, signal); + } while (!finalChunk); +} +/** + * Stream one session-log ZIP as a WHATWG ReadableStream. The root artifact is + * read and validated by the caller before this is called (missing root or + * missing services answer cleanly before any byte is produced); each entry is + * then encoded and deflated in bounded chunks as it is produced, so the + * archive bytes arrive incrementally. A descendant that fails to read errors + * the stream (fail-loud, never silent under-export). + * @param deps - the mounted export services (the caller answered 500 before this runs). + * @param root - the already-read root artifact (first zip entry). + * @param sessionId - the root session id. + * @param includeDescendants - whether to include every subagent descendant. + * @param compressionLevel - validated fflate DEFLATE level for every ZIP entry. + * @param signal - request cancellation combined with response-consumer cancellation. + * @returns the zip byte stream. + */ +export function streamSessionLogZip(deps, root, sessionId, includeDescendants, compressionLevel, signal) { + const consumerAbort = new AbortController(); + const producerSignal = AbortSignal.any([signal, consumerAbort.signal]); + let zip; + let zipTerminated = false; + const capacity = new ResponseCapacityGate(); + const terminateZip = () => { + if (zip === undefined || zipTerminated) + return; + zipTerminated = true; + zip.terminate(); + }; + return new ReadableStream({ + start(controller) { + // fflate invokes the callback synchronously per compressed chunk, so a + // single push can enqueue ahead of a slow consumer; the capacity gate + // waits for pull between pushes once the byte queue is full, bounding + // accumulation to the queue high-water mark plus one synchronous push. + const archive = new Zip((error, data, final) => { + /* v8 ignore next 3 -- fflate reports only internal zip failures, unreachable for valid inputs */ + if (error) { + controller.error(error); + return; + } + /* v8 ignore next -- fflate may emit empty chunks; not controllable from tests */ + if (data.byteLength > 0) + controller.enqueue(data); + if (final) + controller.close(); + }); + zip = archive; + void (async () => { + try { + for await (const entry of sessionLogZipEntries(deps, root, sessionId, includeDescendants, producerSignal)) { + const deflate = new ZipDeflate(entry.path, { level: compressionLevel }); + archive.add(deflate); + if ('content' in entry) { + await pushArtifactChunks(deflate, entry.content, controller, capacity, producerSignal); + } + else { + await pushBinaryChunks(deflate, entry.data, controller, capacity, producerSignal); + } + } + archive.end(); + } + catch (error) { + // A mid-stream failure (missing descendant, cancellation, read + // error) must fail the download rather than ship a truncated archive. + /* v8 ignore next -- typed backends reject with Error, and DOMException is one in Node */ + terminateZip(); + controller.error(error instanceof Error ? error : new Error(String(error))); + } + })(); + }, + pull() { + capacity.pulled(); + }, + cancel(reason) { + consumerAbort.abort(reason instanceof Error ? reason : new Error('session log export stream cancelled')); + terminateZip(); + }, + }, { + highWaterMark: RESPONSE_HIGH_WATER_MARK_BYTES, + size: chunk => chunk.byteLength, + }); +} +//# sourceMappingURL=session-export.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/package.json new file mode 100644 index 0000000..509dd37 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-apiproxy/package.json @@ -0,0 +1,93 @@ +{ + "name": "@deepseek-ai/dsh-host-apiproxy", + "description": "API gateway: the ApiProxy contract (api/), the fetch carrier pair (fetch/), and the host-side gateway plugin providing ctx.apiProxy", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/host/apiproxy" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json", + "./api": { + "types": "./lib/types/api/index.d.ts", + "default": "./lib/types/api/index.js" + }, + "./api/*": { + "types": "./lib/types/api/*.d.ts", + "default": "./lib/types/api/*.js" + }, + "./client": { + "types": "./lib/types/fetch/client.d.ts", + "default": "./lib/types/fetch/client.js" + } + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "fflate": "^0.8.2", + "zod": "^4.4.3", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.7", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.7", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.7", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.7", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.7", + "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-native-command": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-query": "^0.1.0-rc.7", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.7", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.7", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.7", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.7", + "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.7", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.7", + "@deepseek-ai/dsh-workspace": "^0.1.0-rc.7", + "@deepseek-ai/schemastery": "^3.18.1", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.7" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.7", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.7", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-directory-picker b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-directory-picker new file mode 120000 index 0000000..8c06aa3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-host-directory-picker @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-jobs b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-jobs new file mode 120000 index 0000000..95f3330 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-jobs @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-native-command b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-native-command new file mode 120000 index 0000000..c66e799 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-native-command @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..5362978 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..ed04634 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-projection-cache b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-projection-cache new file mode 120000 index 0000000..f44faa3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-projection-cache @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-query b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-query new file mode 120000 index 0000000..3f8a5f2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-query @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-title b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-title new file mode 120000 index 0000000..dbf95ad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-session-title @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-settings b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-settings new file mode 120000 index 0000000..a0d8497 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-settings @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-skill b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-skill new file mode 120000 index 0000000..1ede795 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-skill @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-subagent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-subagent new file mode 120000 index 0000000..3bcf1da --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-subagent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-tools b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-tools new file mode 120000 index 0000000..df45afe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-tools @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-user-approval b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-user-approval new file mode 120000 index 0000000..7a0ea6d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-user-approval @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-user-questions b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-user-questions new file mode 120000 index 0000000..cf2c8be --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-user-questions @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-workspace b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-workspace new file mode 120000 index 0000000..2ff30ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/dsh-workspace @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/fflate b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/fflate new file mode 120000 index 0000000..bb2f645 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/fflate @@ -0,0 +1 @@ +../../fflate@0.8.3/node_modules/fflate \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_227e91a6307a4a5d4a380ed795ce9271/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.i18n.yaml new file mode 100644 index 0000000..757d9c3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/host/directory-picker/README.md +README.md: d90f939aca57b6bc520bb96b56b8a7738b69a522 +README.zh.md: 3a46874f03f56c1f673ea63bd19b833cfb128741 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.md new file mode 100644 index 0000000..d90f939 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.md @@ -0,0 +1,19 @@ +# @deepseek-ai/dsh-host-directory-picker + +English | [中文](README.zh.md) + +The web GUI host's workspace-directory picker is a capability seam. The abstract `DirectoryPicker` service (`ctx.directoryPicker`) is its Service Definition. Its only method, `capability()`, returns a discriminated union describing how an operator selects a directory. Backends differ in user interaction, not just implementation: `{ kind: 'native', pick(signal) }` opens one native OS chooser on the host display ([`-native`](../directory-picker-native/README.md)); `{ kind: 'browse', list(path?), createDirectory(path, name) }` provides listing and creation operations for an in-app browser, which works for remote clients that cannot reach an OS chooser ([`-browse`](../directory-picker-browse/README.md)). Consumers switch on `capability().kind`; the union derives from the merge-extensible `DirectoryPickerCapabilities` map, and a new backend adds its variant there through declaration merging. For an unknown kind, consumers hide directory picking rather than fail. The capability object must be stable for the service lifetime. Each backend package also has a browser entrypoint that registers the matching interaction in ui-workspace's directory-flow slots, so one composition row selects both the host capability and the client flow. A composition that should choose at runtime mounts [`-auto`](../directory-picker-auto/README.md), which inspects the host once at boot and mounts the matching backend row. + +Browse primitives fail with the typed `DirectoryPickerError` (`directory-unreadable` / `directory-exists` / `directory-create-failed`, each carrying the subject `path`), which the consuming gateway maps 1:1 onto wire error codes. `DirectoryEntry` rows carry a host-owned `hidden` flag (POSIX dot convention) so display policy stays client-side; `DirectoryListing.crumbs` is the ancestor chain from the filesystem root, every crumb a jump target. Design rationale, the `ctx.fs` separation, and the policy decisions live in [the directory-picker capability seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-28-directory-picker-capability-seam.md). + +## Model Experience + +None, as the seam serves the GUI host's directory selection; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **No multi-root support** — the browse contract exposes one ancestry chain per listing; per-deployment root scoping (and Windows drive-root enumeration above a drive) waits for a consumer that needs it, per the DirectoryPicker Agent Note. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.zh.md new file mode 100644 index 0000000..3a46874 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/README.zh.md @@ -0,0 +1,19 @@ +# @deepseek-ai/dsh-host-directory-picker + +[English](README.md) | 中文 + +web GUI 宿主的工作区目录选择是一项能力 seam。抽象的 `DirectoryPicker` 服务(`ctx.directoryPicker`)是其 Service Definition。该服务只提供一个方法:`capability()`,它返回一个可辨识联合类型,说明操作者如何选择目录。后端之间的用户交互不同,不只是实现不同:`{ kind: 'native', pick(signal) }` 在宿主屏幕上打开一个原生 OS 选择器([`-native`](../directory-picker-native/README.md));`{ kind: 'browse', list(path?), createDirectory(path, name) }` 提供应用内浏览器使用的列举与创建操作,也能服务于无法访问 OS 对话框的远程客户端([`-browse`](../directory-picker-browse/README.md))。消费方按 `capability().kind` 分支;联合类型由可合并扩展的 `DirectoryPickerCapabilities` 映射派生,新后端通过声明合并在其中加入自己的变体。遇到未知 kind 时,消费方会隐藏目录选择入口,而不是失败。能力对象在服务生命周期内必须保持稳定。每个后端包还提供 browser 入口,在 ui-workspace 的 directory-flow slot 中注册匹配的交互,因此一项组合配置会同时选择宿主能力与 client 流程。需要在运行时选择交互的组合挂载 [`-auto`](../directory-picker-auto/README.md),它在启动时检查一次宿主情况,并挂载匹配的后端行。 + +浏览原语失败时会抛出带类型的 `DirectoryPickerError`(`directory-unreadable`/`directory-exists`/`directory-create-failed`,各自携带出错对象的 `path`),消费网关将其 1:1 映射为协议错误码。`DirectoryEntry` 行携带宿主判定的 `hidden` 标志(POSIX 点前缀约定),展示策略留在客户端;`DirectoryListing.crumbs` 是从文件系统根开始的祖先链,每个 crumb 都是跳转目标。设计依据、与 `ctx.fs` 的切分、策略裁决见 [目录选择能力 seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-28-directory-picker-capability-seam.md)。 + +## 模型体验 + +无。该 seam 服务于 GUI 宿主的目录选择;这里没有任何内容进入模型请求。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **不支持多根目录**——浏览约定每次列举只公开一条祖先链;按部署限定可浏览根(以及在盘符根的上一级枚举 Windows 各盘符根目录)等到出现需要它的消费方再做,见 DirectoryPicker Agent Note。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/index.js new file mode 100644 index 0000000..dbeb7a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/index.js @@ -0,0 +1,44 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/index.js +/** +* Service Definition for the `ctx.directoryPicker` capability seam: how the web-GUI host lets an operator +* select a workspace directory. Backends differ in interaction shape, not +* just mechanism, so the service exposes a discriminated capability instead +* of one method set: a `native` backend opens one OS chooser on the +* host's display, while a `browse` backend serves listing/creation primitives +* for an in-app browser (and thereby works for remote clients no OS dialog +* can reach). Consumers switch on `capability().kind`; the union is +* merge-extensible, and the documented default for an unknown kind is to +* hide the picking affordance rather than fail. +* @module @deepseek-ai/dsh-host-directory-picker +*/ +/** Typed failure thrown by browse primitives so consumers can map business codes without string matching. */ +var DirectoryPickerError = class extends Error { + code; + path; + /** + * @param code - closed business code of the failure. + * @param path - the absolute path the failure is about. + * @param message - operator-facing description. + */ + constructor(code, path, message) { + super(message); + this.code = code; + this.path = path; + this.name = "DirectoryPickerError"; + } +}; +/** +* Abstract directory-picking service. Subclass, implement `capability()`, and +* load the subclass as a plugin — it registers as `ctx.directoryPicker` (one +* implementation per context; loading a second throws, cordis' standard +* duplicate-service behavior). The capability object must be stable for the +* service lifetime: consumers may capture it across calls. +*/ +var DirectoryPicker = class extends Service { + constructor(ctx) { + super(ctx, "directoryPicker"); + } +}; +//#endregion +export { DirectoryPicker, DirectoryPicker as default, DirectoryPickerError }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/invariant.js new file mode 100644 index 0000000..d706fb3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/invariant.js @@ -0,0 +1,20 @@ +//#region lib/types/invariant.js +/** Package-owned invariant companion for the directory-picker seam. @module @deepseek-ai/dsh-host-directory-picker/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-host-directory-picker"; +/** Cordis companion plugin name. */ +const name = "host-directory-picker-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this stateless Service Definition owns the capability +* vocabulary, while backends and the RPC consumer own observations. +*/ +const install = () => {}; +/** +* Register the directory-picker invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/index.d.ts new file mode 100644 index 0000000..bcb3edb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/index.d.ts @@ -0,0 +1,128 @@ +/** + * Service Definition for the `ctx.directoryPicker` capability seam: how the web-GUI host lets an operator + * select a workspace directory. Backends differ in interaction shape, not + * just mechanism, so the service exposes a discriminated capability instead + * of one method set: a `native` backend opens one OS chooser on the + * host's display, while a `browse` backend serves listing/creation primitives + * for an in-app browser (and thereby works for remote clients no OS dialog + * can reach). Consumers switch on `capability().kind`; the union is + * merge-extensible, and the documented default for an unknown kind is to + * hide the picking affordance rather than fail. + * @module @deepseek-ai/dsh-host-directory-picker + */ +import { Context, Service } from '@deepseek-ai/cordis'; +/** The native interaction: one OS directory chooser on the host display. */ +export interface DirectoryPickerNativeCapability { + kind: 'native'; + /** + * Open the chooser and wait for the operator. + * @param signal - caller/connection lifetime; abort terminates the chooser. + * @returns the chosen absolute path, or null when the operator cancels. + */ + pick(signal: AbortSignal): Promise; +} +/** One directory row: a listing child or a breadcrumb ancestor. */ +export interface DirectoryEntry { + /** Base name shown in a browser row (a root crumb carries its full path). */ + name: string; + /** Absolute host path — clients never join path segments themselves. */ + path: string; + /** Hidden by the host platform's convention (dot-prefixed on POSIX); the client owns whether to show it. */ + hidden: boolean; +} +/** One directory level plus its ancestry, as a browse backend reports it. */ +export interface DirectoryListing { + /** Absolute path of the listed directory. */ + path: string; + /** The host account's home directory (breadcrumb "Home" rooting). */ + home: string; + /** + * Ancestor chain from the filesystem root to the listed directory + * inclusive; every crumb is a jump target (crumb `hidden` is always false). + */ + crumbs: DirectoryEntry[]; + /** Direct child directories, name-sorted; symlinks to directories included. */ + entries: DirectoryEntry[]; + /** + * True when the backend cut `entries` at its complete-result bound: the + * level has more child directories than reported, and the missing rows are + * the name-sorted tail (hidden rows count toward the bound). + */ + truncated: boolean; +} +/** + * The browse interaction: listing/creation primitives an in-app browser + * drives one level at a time. Works for remote clients — nothing renders on + * the host display. + */ +export interface DirectoryPickerBrowseCapability { + kind: 'browse'; + /** + * List one directory level. + * @param path - absolute directory to list; absent lists the home directory. + * @param signal - caller lifetime; abort stops the scan (a stalled network + * directory must not outlive a disconnected caller) and rejects with the + * abort reason. + * @returns the level's listing with ancestry; backends bound the complete + * result, and a cut level reports `truncated`. + * @throws {DirectoryPickerError} `directory-unreadable` when the target is not fully + * qualified (a wire value must never resolve against the host cwd or, on + * Windows, its current drive) or cannot be listed. + */ + list(path?: string, signal?: AbortSignal): Promise; + /** + * Create one child directory under an existing parent. + * @param path - absolute existing parent directory. + * @param name - single non-blank path segment (no separators, not `.`/`..`). + * @returns the created directory's absolute path. + * @throws {DirectoryPickerError} `directory-exists` for an existing child, + * `directory-create-failed` for a parent that is not fully qualified or any other failure. + */ + createDirectory(path: string, name: string): Promise; +} +/** + * Merge-extensible registry of interaction shapes keyed by capability kind: a + * new backend declaration-merges its shape here (the entry's `kind` literal + * must equal its key) instead of editing this package. + */ +export interface DirectoryPickerCapabilities { + native: DirectoryPickerNativeCapability; + browse: DirectoryPickerBrowseCapability; +} +/** Union of interaction shapes a backend can provide, derived from the merge-extensible {@link DirectoryPickerCapabilities} map. */ +export type DirectoryPickerCapability = DirectoryPickerCapabilities[keyof DirectoryPickerCapabilities]; +/** Closed failure vocabulary of the browse primitives (mirrored onto the wire by consumers). */ +export type DirectoryPickerErrorCode = 'directory-unreadable' | 'directory-exists' | 'directory-create-failed'; +/** Typed failure thrown by browse primitives so consumers can map business codes without string matching. */ +export declare class DirectoryPickerError extends Error { + readonly code: DirectoryPickerErrorCode; + readonly path: string; + /** + * @param code - closed business code of the failure. + * @param path - the absolute path the failure is about. + * @param message - operator-facing description. + */ + constructor(code: DirectoryPickerErrorCode, path: string, message: string); +} +declare module '@deepseek-ai/cordis' { + interface Context { + directoryPicker: DirectoryPicker; + } +} +/** + * Abstract directory-picking service. Subclass, implement `capability()`, and + * load the subclass as a plugin — it registers as `ctx.directoryPicker` (one + * implementation per context; loading a second throws, cordis' standard + * duplicate-service behavior). The capability object must be stable for the + * service lifetime: consumers may capture it across calls. + */ +export declare abstract class DirectoryPicker extends Service { + constructor(ctx: Context); + /** + * The backend's interaction capability. + * @returns the discriminated capability consumers switch on. + */ + abstract capability(): DirectoryPickerCapability; +} +export default DirectoryPicker; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/invariant.d.ts new file mode 100644 index 0000000..cfaf6e4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned invariant companion for the directory-picker seam. @module @deepseek-ai/dsh-host-directory-picker/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "host-directory-picker-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the directory-picker invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/package.json new file mode 100644 index 0000000..28c5423 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-host-directory-picker/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-host-directory-picker", + "description": "Abstract workspace-directory picking seam (ctx.directoryPicker) for the DeepSeek Harness web GUI host", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/host/directory-picker" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-a_1dffb787bcebd9d6ce501b8862df7337/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.i18n.yaml new file mode 100644 index 0000000..757d9c3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/host/directory-picker/README.md +README.md: d90f939aca57b6bc520bb96b56b8a7738b69a522 +README.zh.md: 3a46874f03f56c1f673ea63bd19b833cfb128741 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.md new file mode 100644 index 0000000..d90f939 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.md @@ -0,0 +1,19 @@ +# @deepseek-ai/dsh-host-directory-picker + +English | [中文](README.zh.md) + +The web GUI host's workspace-directory picker is a capability seam. The abstract `DirectoryPicker` service (`ctx.directoryPicker`) is its Service Definition. Its only method, `capability()`, returns a discriminated union describing how an operator selects a directory. Backends differ in user interaction, not just implementation: `{ kind: 'native', pick(signal) }` opens one native OS chooser on the host display ([`-native`](../directory-picker-native/README.md)); `{ kind: 'browse', list(path?), createDirectory(path, name) }` provides listing and creation operations for an in-app browser, which works for remote clients that cannot reach an OS chooser ([`-browse`](../directory-picker-browse/README.md)). Consumers switch on `capability().kind`; the union derives from the merge-extensible `DirectoryPickerCapabilities` map, and a new backend adds its variant there through declaration merging. For an unknown kind, consumers hide directory picking rather than fail. The capability object must be stable for the service lifetime. Each backend package also has a browser entrypoint that registers the matching interaction in ui-workspace's directory-flow slots, so one composition row selects both the host capability and the client flow. A composition that should choose at runtime mounts [`-auto`](../directory-picker-auto/README.md), which inspects the host once at boot and mounts the matching backend row. + +Browse primitives fail with the typed `DirectoryPickerError` (`directory-unreadable` / `directory-exists` / `directory-create-failed`, each carrying the subject `path`), which the consuming gateway maps 1:1 onto wire error codes. `DirectoryEntry` rows carry a host-owned `hidden` flag (POSIX dot convention) so display policy stays client-side; `DirectoryListing.crumbs` is the ancestor chain from the filesystem root, every crumb a jump target. Design rationale, the `ctx.fs` separation, and the policy decisions live in [the directory-picker capability seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-28-directory-picker-capability-seam.md). + +## Model Experience + +None, as the seam serves the GUI host's directory selection; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **No multi-root support** — the browse contract exposes one ancestry chain per listing; per-deployment root scoping (and Windows drive-root enumeration above a drive) waits for a consumer that needs it, per the DirectoryPicker Agent Note. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.zh.md new file mode 100644 index 0000000..3a46874 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/README.zh.md @@ -0,0 +1,19 @@ +# @deepseek-ai/dsh-host-directory-picker + +[English](README.md) | 中文 + +web GUI 宿主的工作区目录选择是一项能力 seam。抽象的 `DirectoryPicker` 服务(`ctx.directoryPicker`)是其 Service Definition。该服务只提供一个方法:`capability()`,它返回一个可辨识联合类型,说明操作者如何选择目录。后端之间的用户交互不同,不只是实现不同:`{ kind: 'native', pick(signal) }` 在宿主屏幕上打开一个原生 OS 选择器([`-native`](../directory-picker-native/README.md));`{ kind: 'browse', list(path?), createDirectory(path, name) }` 提供应用内浏览器使用的列举与创建操作,也能服务于无法访问 OS 对话框的远程客户端([`-browse`](../directory-picker-browse/README.md))。消费方按 `capability().kind` 分支;联合类型由可合并扩展的 `DirectoryPickerCapabilities` 映射派生,新后端通过声明合并在其中加入自己的变体。遇到未知 kind 时,消费方会隐藏目录选择入口,而不是失败。能力对象在服务生命周期内必须保持稳定。每个后端包还提供 browser 入口,在 ui-workspace 的 directory-flow slot 中注册匹配的交互,因此一项组合配置会同时选择宿主能力与 client 流程。需要在运行时选择交互的组合挂载 [`-auto`](../directory-picker-auto/README.md),它在启动时检查一次宿主情况,并挂载匹配的后端行。 + +浏览原语失败时会抛出带类型的 `DirectoryPickerError`(`directory-unreadable`/`directory-exists`/`directory-create-failed`,各自携带出错对象的 `path`),消费网关将其 1:1 映射为协议错误码。`DirectoryEntry` 行携带宿主判定的 `hidden` 标志(POSIX 点前缀约定),展示策略留在客户端;`DirectoryListing.crumbs` 是从文件系统根开始的祖先链,每个 crumb 都是跳转目标。设计依据、与 `ctx.fs` 的切分、策略裁决见 [目录选择能力 seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-28-directory-picker-capability-seam.md)。 + +## 模型体验 + +无。该 seam 服务于 GUI 宿主的目录选择;这里没有任何内容进入模型请求。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **不支持多根目录**——浏览约定每次列举只公开一条祖先链;按部署限定可浏览根(以及在盘符根的上一级枚举 Windows 各盘符根目录)等到出现需要它的消费方再做,见 DirectoryPicker Agent Note。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/index.js new file mode 100644 index 0000000..dbeb7a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/index.js @@ -0,0 +1,44 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/index.js +/** +* Service Definition for the `ctx.directoryPicker` capability seam: how the web-GUI host lets an operator +* select a workspace directory. Backends differ in interaction shape, not +* just mechanism, so the service exposes a discriminated capability instead +* of one method set: a `native` backend opens one OS chooser on the +* host's display, while a `browse` backend serves listing/creation primitives +* for an in-app browser (and thereby works for remote clients no OS dialog +* can reach). Consumers switch on `capability().kind`; the union is +* merge-extensible, and the documented default for an unknown kind is to +* hide the picking affordance rather than fail. +* @module @deepseek-ai/dsh-host-directory-picker +*/ +/** Typed failure thrown by browse primitives so consumers can map business codes without string matching. */ +var DirectoryPickerError = class extends Error { + code; + path; + /** + * @param code - closed business code of the failure. + * @param path - the absolute path the failure is about. + * @param message - operator-facing description. + */ + constructor(code, path, message) { + super(message); + this.code = code; + this.path = path; + this.name = "DirectoryPickerError"; + } +}; +/** +* Abstract directory-picking service. Subclass, implement `capability()`, and +* load the subclass as a plugin — it registers as `ctx.directoryPicker` (one +* implementation per context; loading a second throws, cordis' standard +* duplicate-service behavior). The capability object must be stable for the +* service lifetime: consumers may capture it across calls. +*/ +var DirectoryPicker = class extends Service { + constructor(ctx) { + super(ctx, "directoryPicker"); + } +}; +//#endregion +export { DirectoryPicker, DirectoryPicker as default, DirectoryPickerError }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/invariant.js new file mode 100644 index 0000000..d706fb3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/invariant.js @@ -0,0 +1,20 @@ +//#region lib/types/invariant.js +/** Package-owned invariant companion for the directory-picker seam. @module @deepseek-ai/dsh-host-directory-picker/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-host-directory-picker"; +/** Cordis companion plugin name. */ +const name = "host-directory-picker-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this stateless Service Definition owns the capability +* vocabulary, while backends and the RPC consumer own observations. +*/ +const install = () => {}; +/** +* Register the directory-picker invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/index.d.ts new file mode 100644 index 0000000..bcb3edb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/index.d.ts @@ -0,0 +1,128 @@ +/** + * Service Definition for the `ctx.directoryPicker` capability seam: how the web-GUI host lets an operator + * select a workspace directory. Backends differ in interaction shape, not + * just mechanism, so the service exposes a discriminated capability instead + * of one method set: a `native` backend opens one OS chooser on the + * host's display, while a `browse` backend serves listing/creation primitives + * for an in-app browser (and thereby works for remote clients no OS dialog + * can reach). Consumers switch on `capability().kind`; the union is + * merge-extensible, and the documented default for an unknown kind is to + * hide the picking affordance rather than fail. + * @module @deepseek-ai/dsh-host-directory-picker + */ +import { Context, Service } from '@deepseek-ai/cordis'; +/** The native interaction: one OS directory chooser on the host display. */ +export interface DirectoryPickerNativeCapability { + kind: 'native'; + /** + * Open the chooser and wait for the operator. + * @param signal - caller/connection lifetime; abort terminates the chooser. + * @returns the chosen absolute path, or null when the operator cancels. + */ + pick(signal: AbortSignal): Promise; +} +/** One directory row: a listing child or a breadcrumb ancestor. */ +export interface DirectoryEntry { + /** Base name shown in a browser row (a root crumb carries its full path). */ + name: string; + /** Absolute host path — clients never join path segments themselves. */ + path: string; + /** Hidden by the host platform's convention (dot-prefixed on POSIX); the client owns whether to show it. */ + hidden: boolean; +} +/** One directory level plus its ancestry, as a browse backend reports it. */ +export interface DirectoryListing { + /** Absolute path of the listed directory. */ + path: string; + /** The host account's home directory (breadcrumb "Home" rooting). */ + home: string; + /** + * Ancestor chain from the filesystem root to the listed directory + * inclusive; every crumb is a jump target (crumb `hidden` is always false). + */ + crumbs: DirectoryEntry[]; + /** Direct child directories, name-sorted; symlinks to directories included. */ + entries: DirectoryEntry[]; + /** + * True when the backend cut `entries` at its complete-result bound: the + * level has more child directories than reported, and the missing rows are + * the name-sorted tail (hidden rows count toward the bound). + */ + truncated: boolean; +} +/** + * The browse interaction: listing/creation primitives an in-app browser + * drives one level at a time. Works for remote clients — nothing renders on + * the host display. + */ +export interface DirectoryPickerBrowseCapability { + kind: 'browse'; + /** + * List one directory level. + * @param path - absolute directory to list; absent lists the home directory. + * @param signal - caller lifetime; abort stops the scan (a stalled network + * directory must not outlive a disconnected caller) and rejects with the + * abort reason. + * @returns the level's listing with ancestry; backends bound the complete + * result, and a cut level reports `truncated`. + * @throws {DirectoryPickerError} `directory-unreadable` when the target is not fully + * qualified (a wire value must never resolve against the host cwd or, on + * Windows, its current drive) or cannot be listed. + */ + list(path?: string, signal?: AbortSignal): Promise; + /** + * Create one child directory under an existing parent. + * @param path - absolute existing parent directory. + * @param name - single non-blank path segment (no separators, not `.`/`..`). + * @returns the created directory's absolute path. + * @throws {DirectoryPickerError} `directory-exists` for an existing child, + * `directory-create-failed` for a parent that is not fully qualified or any other failure. + */ + createDirectory(path: string, name: string): Promise; +} +/** + * Merge-extensible registry of interaction shapes keyed by capability kind: a + * new backend declaration-merges its shape here (the entry's `kind` literal + * must equal its key) instead of editing this package. + */ +export interface DirectoryPickerCapabilities { + native: DirectoryPickerNativeCapability; + browse: DirectoryPickerBrowseCapability; +} +/** Union of interaction shapes a backend can provide, derived from the merge-extensible {@link DirectoryPickerCapabilities} map. */ +export type DirectoryPickerCapability = DirectoryPickerCapabilities[keyof DirectoryPickerCapabilities]; +/** Closed failure vocabulary of the browse primitives (mirrored onto the wire by consumers). */ +export type DirectoryPickerErrorCode = 'directory-unreadable' | 'directory-exists' | 'directory-create-failed'; +/** Typed failure thrown by browse primitives so consumers can map business codes without string matching. */ +export declare class DirectoryPickerError extends Error { + readonly code: DirectoryPickerErrorCode; + readonly path: string; + /** + * @param code - closed business code of the failure. + * @param path - the absolute path the failure is about. + * @param message - operator-facing description. + */ + constructor(code: DirectoryPickerErrorCode, path: string, message: string); +} +declare module '@deepseek-ai/cordis' { + interface Context { + directoryPicker: DirectoryPicker; + } +} +/** + * Abstract directory-picking service. Subclass, implement `capability()`, and + * load the subclass as a plugin — it registers as `ctx.directoryPicker` (one + * implementation per context; loading a second throws, cordis' standard + * duplicate-service behavior). The capability object must be stable for the + * service lifetime: consumers may capture it across calls. + */ +export declare abstract class DirectoryPicker extends Service { + constructor(ctx: Context); + /** + * The backend's interaction capability. + * @returns the discriminated capability consumers switch on. + */ + abstract capability(): DirectoryPickerCapability; +} +export default DirectoryPicker; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/invariant.d.ts new file mode 100644 index 0000000..cfaf6e4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned invariant companion for the directory-picker seam. @module @deepseek-ai/dsh-host-directory-picker/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "host-directory-picker-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the directory-picker invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/package.json new file mode 100644 index 0000000..4b98a9b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-host-directory-picker", + "description": "Abstract workspace-directory picking seam (ctx.directoryPicker) for the DeepSeek Harness web GUI host", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/host/directory-picker" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/cordis-plugin-loader b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/cordis-plugin-loader new file mode 120000 index 0000000..614b839 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/cordis-plugin-loader @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.i18n.yaml new file mode 100644 index 0000000..90c94cd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/host/plugin-inventory/README.md +README.md: a91c02df5e7a57db89c9a63af6c4355573b843da +README.zh.md: 261db0b92cf025606b7fc18c5754d54f8cd34e48 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.md new file mode 100644 index 0000000..a91c02d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.md @@ -0,0 +1,22 @@ +# @deepseek-ai/dsh-host-plugin-inventory + +English | [中文](README.zh.md) + +Read-only Host projection of the current Cordis Loader tree. `PluginInventoryGateway` registers the `pluginInventory` service and publishes one generated direct Remote, `pluginInventory/list`. Every call reads `ctx.loader.entries()` directly, skips structural group rows, and returns the remaining entries in Loader order with only their Loader entry id, module specifier, effective enablement, and current root Fiber phase. + +The phase is `pending`, `loading`, `active`, `failed`, or `unloading`; it is `null` when the entry has no live root Fiber. The snapshot is intentionally point-in-time: Loader remains the sole lifecycle authority, while this package owns no cache, history, provenance model, event stream, or mutation path. Its public payload types live under `./types`, and Typert generates the Host and Client Remote artifacts exposed by `./typert` and `./remote`. + +The service is Remote-only and deliberately declares no same-process Cordis `Context` merge. Client packages consume it through the explicit [`api-remotes`](../../api/remotes/README.md) assembly rather than importing the Host implementation. + +## Model Experience + +None, as this Host-only inventory projection registers no prompt, tool, message, or provider request. + +#### KV Cache effect + +None; this package never assembles model input. + +## Known Limitations and Deferred Work + +- **Point-in-time state only** — the result contains no durable failure history or subscription; a missing root Fiber is reported as `null`, regardless of why no live root exists. +- **No provenance or mutation** — the service does not identify which bundle, profile, or override introduced an entry, and it cannot enable, disable, add, or remove plugins. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.zh.md new file mode 100644 index 0000000..261db0b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.zh.md @@ -0,0 +1,22 @@ +# @deepseek-ai/dsh-host-plugin-inventory + +[English](README.md) | 中文 + +当前 Cordis Loader 树的只读 Host 投影。`PluginInventoryGateway` 注册 `pluginInventory` 服务,并发布一个由 Typert 生成的直接 Remote:`pluginInventory/list`。每次调用都直接读取 `ctx.loader.entries()`,跳过结构性的 group 行,再按 Loader 顺序返回其余条目,并且只包含 Loader 条目 id、模块标识、有效启用状态与当前根 Fiber 阶段。 + +阶段为 `pending`、`loading`、`active`、`failed` 或 `unloading`;条目没有存活的根 Fiber 时则为 `null`。该快照刻意只表示调用当下:Loader 仍是唯一的生命周期权威,本包不拥有缓存、历史、来源模型、事件流或修改路径。公开 payload 类型位于 `./types`,Typert 生成由 `./typert` 与 `./remote` 导出的 Host 和 Client Remote 产物。 + +该服务仅供 Remote 使用,刻意不声明同进程 Cordis `Context` merge。Client 包通过显式的 [`api-remotes`](../../api/remotes/README.md) 组合消费它,而不导入 Host 实现。 + +## 模型体验 + +无,因为这个仅限 Host 的清单投影不注册提示词、工具、消息或提供方请求。 + +#### KV Cache 影响 + +无;本包从不组装模型输入。 + +## 已知限制与暂缓事项 + +- **仅表示调用当下** —— 结果不包含持久的失败历史或订阅;只要不存在存活的根 Fiber,就会报告 `null`,而不区分其原因。 +- **无来源与修改能力** —— 服务不识别条目由哪个 bundle、profile 或 override 引入,也不能启用、停用、添加或移除插件。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/index.js new file mode 100644 index 0000000..33faa6a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/index.js @@ -0,0 +1,118 @@ +import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol"; +//#region lib/types/index.js +/** Read-only projection of the current Cordis Loader plugin entries. */ +var __runInitializers = function(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + return useValue ? value : void 0; +}; +var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function(f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +/** Brand an existing Loader-tree entry id at the owning boundary. */ +function pluginEntryId(value) { + return value; +} +/** Runtime mirror: FiberState is a cross-package const enum. */ +const FIBER_STATE = { + PENDING: 0, + LOADING: 1, + ACTIVE: 2, + FAILED: 3, + DISPOSED: 4, + UNLOADING: 5 +}; +/** Complete public projection of Cordis Fiber states. */ +const FIBER_PHASE = { + [FIBER_STATE.PENDING]: "pending", + [FIBER_STATE.LOADING]: "loading", + [FIBER_STATE.ACTIVE]: "active", + [FIBER_STATE.FAILED]: "failed", + [FIBER_STATE.DISPOSED]: null, + [FIBER_STATE.UNLOADING]: "unloading" +}; +/** Remote-only service exposing the Loader's current non-group entry state. */ +let PluginInventoryGateway = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + return class PluginInventoryGateway extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote("list")]; + __esDecorate(this, null, _list_decorators, { + kind: "method", + name: "list", + static: false, + private: false, + access: { + has: (obj) => "list" in obj, + get: (obj) => obj.list + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { + enumerable: true, + configurable: true, + writable: true, + value: _metadata + }); + } + static inject = ["loader"]; + constructor(ctx) { + super(ctx, "pluginInventory"); + __runInitializers(this, _instanceExtraInitializers); + } + /** + * Read the Loader directly on every call. Cordis's internal plugin/status + * events already maintain Entry.fiber and Fiber.state, so a second cache + * would only add another lifecycle truth to keep synchronized. + * @returns Current non-group Loader entries in Loader order. + */ + list() { + const entries = []; + for (const entry of this.ctx.loader.entries()) { + if (entry.options.group) continue; + entries.push({ + entryId: pluginEntryId(entry.id), + moduleName: entry.options.name, + enabled: !entry.disabled, + fiberPhase: entry.fiber === void 0 ? null : FIBER_PHASE[entry.fiber.state] + }); + } + return { entries }; + } + }; +})(); +//#endregion +export { PluginInventoryGateway, PluginInventoryGateway as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/invariant.js new file mode 100644 index 0000000..d8c9f38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/invariant.js @@ -0,0 +1,13 @@ +//#region lib/types/invariant.js +/** Package-owned invariant companion. @module @deepseek-ai/dsh-host-plugin-inventory/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-host-plugin-inventory"; +/** Cordis companion plugin name. */ +const name = "host-plugin-inventory-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** No runtime invariant: every snapshot is projected directly from Loader-owned state. */ +const install = () => {}; +/** Register this package's invariant companion. */ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.d.ts new file mode 100644 index 0000000..dcf4919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.d.ts @@ -0,0 +1,3 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ + +export declare const TYPERT: unknown diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.js new file mode 100644 index 0000000..58fd022 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.js @@ -0,0 +1,40 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema = z.object({ + 'entries': z.array(z.object({ + 'entryId': z.intersection(z.string(), z.unknown()).readonly(), + 'moduleName': z.string().readonly(), + 'enabled': z.boolean().readonly(), + 'fiberPhase': z.union([z.literal(null), z.literal("failed"), z.literal("pending"), z.literal("active"), z.literal("loading"), z.literal("unloading")]).readonly(), +})).readonly(), +}) + +export const TYPERT = { + package: '@deepseek-ai/dsh-host-plugin-inventory', + face: 'host', + schemas: [ + ], + invocations: [ + { + id: '@deepseek-ai/dsh-host-plugin-inventory#pluginInventory/list', + service: 'pluginInventory', + namespace: 'pluginInventory', + method: 'list', + invocation: { kind: 'direct' }, + parameters: [ + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-host-plugin-inventory/types#PluginInventorySnapshot', + schema: _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema, + }, + sourceLocation: {"file":"packages/host/plugin-inventory/src/index.ts","line":57,"column":3}, + }, + ], + model: { + "services": [], + "events": [], + "objects": [] + }, +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.d.ts new file mode 100644 index 0000000..839cae8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.d.ts @@ -0,0 +1,22 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import type { + RemoteResult, + TypertRemoteContribution, +} from '@deepseek-ai/dsh-typert-protocol' +import type { PluginInventorySnapshot } from '@deepseek-ai/dsh-host-plugin-inventory/types' + +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteNamespace$706c7567696e496e76656e746f7279 { + list: () => Promise> + } + interface TypertRemoteMap { + 'pluginInventory/list': () => Promise> + } + interface TypertRemoteNamespaceMap { + 'pluginInventory': TypertRemoteNamespace$706c7567696e496e76656e746f7279 + } +} + +export declare const TYPERT_REMOTE: TypertRemoteContribution +export default TYPERT_REMOTE +//# sourceMappingURL=typert.remote-client.d.ts.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.js new file mode 100644 index 0000000..8d5d67f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.js @@ -0,0 +1,34 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema = z.object({ + 'entries': z.array(z.object({ + 'entryId': z.intersection(z.string(), z.unknown()).readonly(), + 'moduleName': z.string().readonly(), + 'enabled': z.boolean().readonly(), + 'fiberPhase': z.union([z.literal(null), z.literal("failed"), z.literal("pending"), z.literal("active"), z.literal("loading"), z.literal("unloading")]).readonly(), +})).readonly(), +}) + +export const TYPERT_REMOTE = { + package: '@deepseek-ai/dsh-host-plugin-inventory', + descriptors: [ + { + id: '@deepseek-ai/dsh-host-plugin-inventory#pluginInventory/list', + service: 'pluginInventory', + namespace: 'pluginInventory', + method: 'list', + invocation: { kind: 'direct' }, + parameters: [ + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-host-plugin-inventory/types#PluginInventorySnapshot', + schema: _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema, + }, + sourceLocation: {"file":"packages/host/plugin-inventory/src/index.ts","line":57,"column":3}, + }, + ], +} + +export default TYPERT_REMOTE diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.d.ts new file mode 100644 index 0000000..ffadbd4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.d.ts @@ -0,0 +1,19 @@ +/** Read-only projection of the current Cordis Loader plugin entries. */ +import type { Context } from '@deepseek-ai/cordis'; +import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'; +import type { PluginInventorySnapshot } from './types.ts'; +export type * from './types.ts'; +/** Remote-only service exposing the Loader's current non-group entry state. */ +export declare class PluginInventoryGateway extends TypertRemoteService { + static inject: string[]; + constructor(ctx: Context); + /** + * Read the Loader directly on every call. Cordis's internal plugin/status + * events already maintain Entry.fiber and Fiber.state, so a second cache + * would only add another lifecycle truth to keep synchronized. + * @returns Current non-group Loader entries in Loader order. + */ + list(): PluginInventorySnapshot; +} +export default PluginInventoryGateway; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.js new file mode 100644 index 0000000..0b8f6d9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.js @@ -0,0 +1,100 @@ +/** Read-only projection of the current Cordis Loader plugin entries. */ +var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; +var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'; +/** Brand an existing Loader-tree entry id at the owning boundary. */ +function pluginEntryId(value) { + return value; +} +/** Runtime mirror: FiberState is a cross-package const enum. */ +const FIBER_STATE = { + PENDING: 0, + LOADING: 1, + ACTIVE: 2, + FAILED: 3, + DISPOSED: 4, + UNLOADING: 5, +}; +/** Complete public projection of Cordis Fiber states. */ +const FIBER_PHASE = { + [FIBER_STATE.PENDING]: 'pending', + [FIBER_STATE.LOADING]: 'loading', + [FIBER_STATE.ACTIVE]: 'active', + [FIBER_STATE.FAILED]: 'failed', + [FIBER_STATE.DISPOSED]: null, + [FIBER_STATE.UNLOADING]: 'unloading', +}; +/** Remote-only service exposing the Loader's current non-group entry state. */ +let PluginInventoryGateway = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + return class PluginInventoryGateway extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote('list')]; + __esDecorate(this, null, _list_decorators, { kind: "method", name: "list", static: false, private: false, access: { has: obj => "list" in obj, get: obj => obj.list }, metadata: _metadata }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + static inject = ['loader']; + constructor(ctx) { + super(ctx, 'pluginInventory'); + __runInitializers(this, _instanceExtraInitializers); + } + /** + * Read the Loader directly on every call. Cordis's internal plugin/status + * events already maintain Entry.fiber and Fiber.state, so a second cache + * would only add another lifecycle truth to keep synchronized. + * @returns Current non-group Loader entries in Loader order. + */ + list() { + const entries = []; + for (const entry of this.ctx.loader.entries()) { + if (entry.options.group) + continue; + entries.push({ + entryId: pluginEntryId(entry.id), + moduleName: entry.options.name, + enabled: !entry.disabled, + fiberPhase: entry.fiber === undefined ? null : FIBER_PHASE[entry.fiber.state], + }); + } + return { entries }; + } + }; +})(); +export { PluginInventoryGateway }; +export default PluginInventoryGateway; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.d.ts new file mode 100644 index 0000000..f2ca856 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.d.ts @@ -0,0 +1,9 @@ +/** Package-owned invariant companion. @module @deepseek-ai/dsh-host-plugin-inventory/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "host-plugin-inventory-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** Register this package's invariant companion. */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.js new file mode 100644 index 0000000..358c4e7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.js @@ -0,0 +1,12 @@ +/** Package-owned invariant companion. @module @deepseek-ai/dsh-host-plugin-inventory/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-host-plugin-inventory'; +/** Cordis companion plugin name. */ +export const name = 'host-plugin-inventory-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** No runtime invariant: every snapshot is projected directly from Loader-owned state. */ +const install = () => { }; +/** Register this package's invariant companion. */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.d.ts new file mode 100644 index 0000000..f52a591 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.d.ts @@ -0,0 +1,19 @@ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Stable Loader-tree identity of one configured plugin entry. */ +export type PluginEntryId = Branded<'PluginEntryId'>; +/** Lifecycle state of an entry's root Fiber, or null when it has no live root Fiber. */ +export type PluginFiberPhase = 'pending' | 'loading' | 'active' | 'failed' | 'unloading' | null; +/** One non-group Loader entry exposed to trusted clients. */ +export interface PluginInventoryEntry { + readonly entryId: PluginEntryId; + /** Exact module specifier imported by the Loader entry. */ + readonly moduleName: string; + /** Effective Loader enablement, including disabled ancestor groups. */ + readonly enabled: boolean; + readonly fiberPhase: PluginFiberPhase; +} +/** Point-in-time inventory returned by the plugin inventory Remote. */ +export interface PluginInventorySnapshot { + readonly entries: readonly PluginInventoryEntry[]; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.js new file mode 100644 index 0000000..718fd38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/package.json new file mode 100644 index 0000000..0a57cca --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-host-plugin-inventory/package.json @@ -0,0 +1,68 @@ +{ + "name": "@deepseek-ai/dsh-host-plugin-inventory", + "description": "Read-only Remote projection of current Cordis Loader plugin state", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/host/plugin-inventory" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./typert": { + "types": "./lib/typert.host.d.ts", + "default": "./lib/typert.host.js" + }, + "./remote": { + "types": "./lib/typert.remote-client.d.ts", + "default": "./lib/typert.remote-client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts", + "lib/typert.host.js", + "lib/typert.host.d.ts", + "lib/typert.remote-client.js", + "lib/typert.remote-client.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..aa2ae83 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.6_@deepseek-ai+cordis-plugin-loader@1.0_a33844441aba7e573dfa46a8ea41019c/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/cordis-plugin-loader b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/cordis-plugin-loader new file mode 120000 index 0000000..614b839 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/cordis-plugin-loader @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.i18n.yaml new file mode 100644 index 0000000..90c94cd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/host/plugin-inventory/README.md +README.md: a91c02df5e7a57db89c9a63af6c4355573b843da +README.zh.md: 261db0b92cf025606b7fc18c5754d54f8cd34e48 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.md new file mode 100644 index 0000000..a91c02d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.md @@ -0,0 +1,22 @@ +# @deepseek-ai/dsh-host-plugin-inventory + +English | [中文](README.zh.md) + +Read-only Host projection of the current Cordis Loader tree. `PluginInventoryGateway` registers the `pluginInventory` service and publishes one generated direct Remote, `pluginInventory/list`. Every call reads `ctx.loader.entries()` directly, skips structural group rows, and returns the remaining entries in Loader order with only their Loader entry id, module specifier, effective enablement, and current root Fiber phase. + +The phase is `pending`, `loading`, `active`, `failed`, or `unloading`; it is `null` when the entry has no live root Fiber. The snapshot is intentionally point-in-time: Loader remains the sole lifecycle authority, while this package owns no cache, history, provenance model, event stream, or mutation path. Its public payload types live under `./types`, and Typert generates the Host and Client Remote artifacts exposed by `./typert` and `./remote`. + +The service is Remote-only and deliberately declares no same-process Cordis `Context` merge. Client packages consume it through the explicit [`api-remotes`](../../api/remotes/README.md) assembly rather than importing the Host implementation. + +## Model Experience + +None, as this Host-only inventory projection registers no prompt, tool, message, or provider request. + +#### KV Cache effect + +None; this package never assembles model input. + +## Known Limitations and Deferred Work + +- **Point-in-time state only** — the result contains no durable failure history or subscription; a missing root Fiber is reported as `null`, regardless of why no live root exists. +- **No provenance or mutation** — the service does not identify which bundle, profile, or override introduced an entry, and it cannot enable, disable, add, or remove plugins. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.zh.md new file mode 100644 index 0000000..261db0b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/README.zh.md @@ -0,0 +1,22 @@ +# @deepseek-ai/dsh-host-plugin-inventory + +[English](README.md) | 中文 + +当前 Cordis Loader 树的只读 Host 投影。`PluginInventoryGateway` 注册 `pluginInventory` 服务,并发布一个由 Typert 生成的直接 Remote:`pluginInventory/list`。每次调用都直接读取 `ctx.loader.entries()`,跳过结构性的 group 行,再按 Loader 顺序返回其余条目,并且只包含 Loader 条目 id、模块标识、有效启用状态与当前根 Fiber 阶段。 + +阶段为 `pending`、`loading`、`active`、`failed` 或 `unloading`;条目没有存活的根 Fiber 时则为 `null`。该快照刻意只表示调用当下:Loader 仍是唯一的生命周期权威,本包不拥有缓存、历史、来源模型、事件流或修改路径。公开 payload 类型位于 `./types`,Typert 生成由 `./typert` 与 `./remote` 导出的 Host 和 Client Remote 产物。 + +该服务仅供 Remote 使用,刻意不声明同进程 Cordis `Context` merge。Client 包通过显式的 [`api-remotes`](../../api/remotes/README.md) 组合消费它,而不导入 Host 实现。 + +## 模型体验 + +无,因为这个仅限 Host 的清单投影不注册提示词、工具、消息或提供方请求。 + +#### KV Cache 影响 + +无;本包从不组装模型输入。 + +## 已知限制与暂缓事项 + +- **仅表示调用当下** —— 结果不包含持久的失败历史或订阅;只要不存在存活的根 Fiber,就会报告 `null`,而不区分其原因。 +- **无来源与修改能力** —— 服务不识别条目由哪个 bundle、profile 或 override 引入,也不能启用、停用、添加或移除插件。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/index.js new file mode 100644 index 0000000..33faa6a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/index.js @@ -0,0 +1,118 @@ +import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol"; +//#region lib/types/index.js +/** Read-only projection of the current Cordis Loader plugin entries. */ +var __runInitializers = function(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + return useValue ? value : void 0; +}; +var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function(f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +/** Brand an existing Loader-tree entry id at the owning boundary. */ +function pluginEntryId(value) { + return value; +} +/** Runtime mirror: FiberState is a cross-package const enum. */ +const FIBER_STATE = { + PENDING: 0, + LOADING: 1, + ACTIVE: 2, + FAILED: 3, + DISPOSED: 4, + UNLOADING: 5 +}; +/** Complete public projection of Cordis Fiber states. */ +const FIBER_PHASE = { + [FIBER_STATE.PENDING]: "pending", + [FIBER_STATE.LOADING]: "loading", + [FIBER_STATE.ACTIVE]: "active", + [FIBER_STATE.FAILED]: "failed", + [FIBER_STATE.DISPOSED]: null, + [FIBER_STATE.UNLOADING]: "unloading" +}; +/** Remote-only service exposing the Loader's current non-group entry state. */ +let PluginInventoryGateway = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + return class PluginInventoryGateway extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote("list")]; + __esDecorate(this, null, _list_decorators, { + kind: "method", + name: "list", + static: false, + private: false, + access: { + has: (obj) => "list" in obj, + get: (obj) => obj.list + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { + enumerable: true, + configurable: true, + writable: true, + value: _metadata + }); + } + static inject = ["loader"]; + constructor(ctx) { + super(ctx, "pluginInventory"); + __runInitializers(this, _instanceExtraInitializers); + } + /** + * Read the Loader directly on every call. Cordis's internal plugin/status + * events already maintain Entry.fiber and Fiber.state, so a second cache + * would only add another lifecycle truth to keep synchronized. + * @returns Current non-group Loader entries in Loader order. + */ + list() { + const entries = []; + for (const entry of this.ctx.loader.entries()) { + if (entry.options.group) continue; + entries.push({ + entryId: pluginEntryId(entry.id), + moduleName: entry.options.name, + enabled: !entry.disabled, + fiberPhase: entry.fiber === void 0 ? null : FIBER_PHASE[entry.fiber.state] + }); + } + return { entries }; + } + }; +})(); +//#endregion +export { PluginInventoryGateway, PluginInventoryGateway as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/invariant.js new file mode 100644 index 0000000..d8c9f38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/invariant.js @@ -0,0 +1,13 @@ +//#region lib/types/invariant.js +/** Package-owned invariant companion. @module @deepseek-ai/dsh-host-plugin-inventory/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-host-plugin-inventory"; +/** Cordis companion plugin name. */ +const name = "host-plugin-inventory-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** No runtime invariant: every snapshot is projected directly from Loader-owned state. */ +const install = () => {}; +/** Register this package's invariant companion. */ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.d.ts new file mode 100644 index 0000000..dcf4919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.d.ts @@ -0,0 +1,3 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ + +export declare const TYPERT: unknown diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.js new file mode 100644 index 0000000..58fd022 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.host.js @@ -0,0 +1,40 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema = z.object({ + 'entries': z.array(z.object({ + 'entryId': z.intersection(z.string(), z.unknown()).readonly(), + 'moduleName': z.string().readonly(), + 'enabled': z.boolean().readonly(), + 'fiberPhase': z.union([z.literal(null), z.literal("failed"), z.literal("pending"), z.literal("active"), z.literal("loading"), z.literal("unloading")]).readonly(), +})).readonly(), +}) + +export const TYPERT = { + package: '@deepseek-ai/dsh-host-plugin-inventory', + face: 'host', + schemas: [ + ], + invocations: [ + { + id: '@deepseek-ai/dsh-host-plugin-inventory#pluginInventory/list', + service: 'pluginInventory', + namespace: 'pluginInventory', + method: 'list', + invocation: { kind: 'direct' }, + parameters: [ + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-host-plugin-inventory/types#PluginInventorySnapshot', + schema: _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema, + }, + sourceLocation: {"file":"packages/host/plugin-inventory/src/index.ts","line":57,"column":3}, + }, + ], + model: { + "services": [], + "events": [], + "objects": [] + }, +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.d.ts new file mode 100644 index 0000000..839cae8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.d.ts @@ -0,0 +1,22 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import type { + RemoteResult, + TypertRemoteContribution, +} from '@deepseek-ai/dsh-typert-protocol' +import type { PluginInventorySnapshot } from '@deepseek-ai/dsh-host-plugin-inventory/types' + +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteNamespace$706c7567696e496e76656e746f7279 { + list: () => Promise> + } + interface TypertRemoteMap { + 'pluginInventory/list': () => Promise> + } + interface TypertRemoteNamespaceMap { + 'pluginInventory': TypertRemoteNamespace$706c7567696e496e76656e746f7279 + } +} + +export declare const TYPERT_REMOTE: TypertRemoteContribution +export default TYPERT_REMOTE +//# sourceMappingURL=typert.remote-client.d.ts.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.js new file mode 100644 index 0000000..8d5d67f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/typert.remote-client.js @@ -0,0 +1,34 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema = z.object({ + 'entries': z.array(z.object({ + 'entryId': z.intersection(z.string(), z.unknown()).readonly(), + 'moduleName': z.string().readonly(), + 'enabled': z.boolean().readonly(), + 'fiberPhase': z.union([z.literal(null), z.literal("failed"), z.literal("pending"), z.literal("active"), z.literal("loading"), z.literal("unloading")]).readonly(), +})).readonly(), +}) + +export const TYPERT_REMOTE = { + package: '@deepseek-ai/dsh-host-plugin-inventory', + descriptors: [ + { + id: '@deepseek-ai/dsh-host-plugin-inventory#pluginInventory/list', + service: 'pluginInventory', + namespace: 'pluginInventory', + method: 'list', + invocation: { kind: 'direct' }, + parameters: [ + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-host-plugin-inventory/types#PluginInventorySnapshot', + schema: _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema, + }, + sourceLocation: {"file":"packages/host/plugin-inventory/src/index.ts","line":57,"column":3}, + }, + ], +} + +export default TYPERT_REMOTE diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.d.ts new file mode 100644 index 0000000..ffadbd4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.d.ts @@ -0,0 +1,19 @@ +/** Read-only projection of the current Cordis Loader plugin entries. */ +import type { Context } from '@deepseek-ai/cordis'; +import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'; +import type { PluginInventorySnapshot } from './types.ts'; +export type * from './types.ts'; +/** Remote-only service exposing the Loader's current non-group entry state. */ +export declare class PluginInventoryGateway extends TypertRemoteService { + static inject: string[]; + constructor(ctx: Context); + /** + * Read the Loader directly on every call. Cordis's internal plugin/status + * events already maintain Entry.fiber and Fiber.state, so a second cache + * would only add another lifecycle truth to keep synchronized. + * @returns Current non-group Loader entries in Loader order. + */ + list(): PluginInventorySnapshot; +} +export default PluginInventoryGateway; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.js new file mode 100644 index 0000000..0b8f6d9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/index.js @@ -0,0 +1,100 @@ +/** Read-only projection of the current Cordis Loader plugin entries. */ +var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; +var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'; +/** Brand an existing Loader-tree entry id at the owning boundary. */ +function pluginEntryId(value) { + return value; +} +/** Runtime mirror: FiberState is a cross-package const enum. */ +const FIBER_STATE = { + PENDING: 0, + LOADING: 1, + ACTIVE: 2, + FAILED: 3, + DISPOSED: 4, + UNLOADING: 5, +}; +/** Complete public projection of Cordis Fiber states. */ +const FIBER_PHASE = { + [FIBER_STATE.PENDING]: 'pending', + [FIBER_STATE.LOADING]: 'loading', + [FIBER_STATE.ACTIVE]: 'active', + [FIBER_STATE.FAILED]: 'failed', + [FIBER_STATE.DISPOSED]: null, + [FIBER_STATE.UNLOADING]: 'unloading', +}; +/** Remote-only service exposing the Loader's current non-group entry state. */ +let PluginInventoryGateway = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + return class PluginInventoryGateway extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote('list')]; + __esDecorate(this, null, _list_decorators, { kind: "method", name: "list", static: false, private: false, access: { has: obj => "list" in obj, get: obj => obj.list }, metadata: _metadata }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + static inject = ['loader']; + constructor(ctx) { + super(ctx, 'pluginInventory'); + __runInitializers(this, _instanceExtraInitializers); + } + /** + * Read the Loader directly on every call. Cordis's internal plugin/status + * events already maintain Entry.fiber and Fiber.state, so a second cache + * would only add another lifecycle truth to keep synchronized. + * @returns Current non-group Loader entries in Loader order. + */ + list() { + const entries = []; + for (const entry of this.ctx.loader.entries()) { + if (entry.options.group) + continue; + entries.push({ + entryId: pluginEntryId(entry.id), + moduleName: entry.options.name, + enabled: !entry.disabled, + fiberPhase: entry.fiber === undefined ? null : FIBER_PHASE[entry.fiber.state], + }); + } + return { entries }; + } + }; +})(); +export { PluginInventoryGateway }; +export default PluginInventoryGateway; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.d.ts new file mode 100644 index 0000000..f2ca856 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.d.ts @@ -0,0 +1,9 @@ +/** Package-owned invariant companion. @module @deepseek-ai/dsh-host-plugin-inventory/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "host-plugin-inventory-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** Register this package's invariant companion. */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.js new file mode 100644 index 0000000..358c4e7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/invariant.js @@ -0,0 +1,12 @@ +/** Package-owned invariant companion. @module @deepseek-ai/dsh-host-plugin-inventory/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-host-plugin-inventory'; +/** Cordis companion plugin name. */ +export const name = 'host-plugin-inventory-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** No runtime invariant: every snapshot is projected directly from Loader-owned state. */ +const install = () => { }; +/** Register this package's invariant companion. */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.d.ts new file mode 100644 index 0000000..f52a591 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.d.ts @@ -0,0 +1,19 @@ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Stable Loader-tree identity of one configured plugin entry. */ +export type PluginEntryId = Branded<'PluginEntryId'>; +/** Lifecycle state of an entry's root Fiber, or null when it has no live root Fiber. */ +export type PluginFiberPhase = 'pending' | 'loading' | 'active' | 'failed' | 'unloading' | null; +/** One non-group Loader entry exposed to trusted clients. */ +export interface PluginInventoryEntry { + readonly entryId: PluginEntryId; + /** Exact module specifier imported by the Loader entry. */ + readonly moduleName: string; + /** Effective Loader enablement, including disabled ancestor groups. */ + readonly enabled: boolean; + readonly fiberPhase: PluginFiberPhase; +} +/** Point-in-time inventory returned by the plugin inventory Remote. */ +export interface PluginInventorySnapshot { + readonly entries: readonly PluginInventoryEntry[]; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.js new file mode 100644 index 0000000..718fd38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/lib/types/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/package.json new file mode 100644 index 0000000..a85284a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory/package.json @@ -0,0 +1,68 @@ +{ + "name": "@deepseek-ai/dsh-host-plugin-inventory", + "description": "Read-only Remote projection of current Cordis Loader plugin state", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/host/plugin-inventory" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./typert": { + "types": "./lib/typert.host.d.ts", + "default": "./lib/typert.host.js" + }, + "./remote": { + "types": "./lib/typert.remote-client.d.ts", + "default": "./lib/typert.remote-client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts", + "lib/typert.host.js", + "lib/typert.host.d.ts", + "lib/typert.remote-client.js", + "lib/typert.remote-client.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..a2fcff1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.i18n.yaml new file mode 100644 index 0000000..591ca04 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/host/webserver/README.md +README.md: 7927c791a809ad272edce1310b3c50bbe30720a5 +README.zh.md: 82252adb3945f22c83abddbd3bbdd11556383add diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.md new file mode 100644 index 0000000..7927c79 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.md @@ -0,0 +1,22 @@ +# @deepseek-ai/dsh-host-webserver + +English | [中文](README.zh.md) + +Web HTTP and upgrade-route registration plugin (default-exported `WebServer`, config `{host, port}`): a `node:http` server that listens on activation and provides `ctx.webServer`. `register(route)` adds a named `exact`/`prefix` HTTP route; `registerUpgrade(route)` adds an upgrade route for an exact pathname. A duplicate path within either table throws because route patterns are a composition-level contract and a collision is a misconfiguration; both methods return a disposer that removes the registration. `registerFallback(handler)` registers the one handler for requests that match no named route. A second registration throws; the SPA dist server [`dsh-host-frontend-static`](../frontend-static/README.md) is the shipped owner, and the server returns 404 while none is registered. `tapIndex(transform)` adds an index.html transform, and `applyIndexTaps(html)` runs a body through the registered transforms in order; the fallback handler calls it on every index response. `port` reads the listening port (the OS-assigned value when `port` is 0), and `host` reads the configured bind host (composition-time facts other plugins adapt to, e.g. the directory-picker chooser). HTTP match order is fixed: exact over the whole table, then longest prefix, then the fallback handler. Upgrades match exactly and unmatched connections are closed; registration order carries no request-facing semantics. + +The package knows no harness concepts and serves no files: the `/api` HTTP bridge and downlink WebSockets are routes owned by the connection plugin, plugin bundles and the HMR event stream are routes owned by the modules/hmr plugins, and dist serving belongs to the fallback owner. The upgrade handler owns the protocol handshake and connection contents; the webserver only delivers the raw socket and request. `host` accepts only `127.0.0.1` (default posture) and `0.0.0.0` (deliberate network exposure). This server serves browsers only; Electron loads dist over `file://` and carries fetch over an IPC bridge. This package never prints; the URL line belongs to the shell. + +A listen failure (EADDRINUSE…) throws out of activation and rejects Loader composition with the bind diagnostic; the failed candidate fiber is disposed. An HTTP request whose handling throws (a fallback owner's `decodeURIComponent` on a malformed %-escape, a client dropping mid-body) is answered 400 — or the socket destroyed when headers are already out — and logged as a warning; it never exits the process. An upgrade-handler exception or upgraded-socket transport error is logged as a warning and destroys its socket. Disposal starts `close()` and `closeAllConnections()`, destroys every tracked upgraded socket, and returns only after the HTTP server and those sockets have closed. + +## Model Experience + +None, as the package is a Web carrier between the browser and the HTTP/upgrade routes other plugins register; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **No TLS, auth, or origin policy** — binding a non-loopback address exposes the server to that network; deployment hardening (or fronting it with a real reverse proxy) is deliberately out of scope for the dev-facing v1. +- **Socket options are fixed** — config selects the bind host and port, while backlog and other socket settings remain internal until a deployment needs them. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.zh.md new file mode 100644 index 0000000..82252ad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/README.zh.md @@ -0,0 +1,22 @@ +# @deepseek-ai/dsh-host-webserver + +[English](README.md) | 中文 + +Web HTTP 与 upgrade route 注册插件(默认导出 `WebServer`,配置为 `{host, port}`):一个在激活时开始监听的 `node:http` 服务器,提供 `ctx.webServer`。`register(route)` 添加具名的 `exact`/`prefix` HTTP route;`registerUpgrade(route)` 添加精确 pathname 的 upgrade route;同一张表内的重复路径会抛错,因为 route 模式是组合层约定,冲突即配置错误;两者返回的 disposer 都会移除注册。`registerFallback(handler)` 注册一个 handler,处理所有未被具名 route 命中的请求。第二次注册会抛错;随附的 SPA dist 服务器 [`dsh-host-frontend-static`](../frontend-static/README.md) 是该 handler 的所有者,没有注册 handler 时服务器返回 404。`tapIndex(transform)` 添加一个 index.html 转换,`applyIndexTaps(html)` 按注册顺序对一段响应体运行已注册的转换;fallback handler 在每次 index 响应时调用它。`port` 读取正在监听的端口(当 `port` 为 0 时读取 OS 分配的值),`host` 读取配置的绑定宿主(这些是其他插件据以自适应的组合期事实,例如 directory-picker 选择器)。HTTP 匹配顺序固定不变:先在整张表中匹配精确 route,再匹配最长前缀,最后交给 fallback handler。upgrade 只做精确匹配,未命中连接直接关闭;注册顺序不影响请求处理。 + +该包不了解任何 harness 概念,也不提供任何文件服务:`/api` HTTP 桥接与下行 WebSocket 是 connection 插件的 route,插件 bundle 与 HMR(热模块替换)事件流是 modules/hmr 插件的 route,dist 服务则属于 fallback 持有者。upgrade handler 拥有协议握手与连接内容;webserver 只交付原始 socket 与 request。`host` 只接受 `127.0.0.1`(默认安全姿态)和 `0.0.0.0`(有意向网络开放)。该服务器只服务浏览器;Electron 通过 `file://` 加载 dist,并经 IPC 桥接承载 fetch。该包从不打印内容;URL 行属于 shell。 + +监听失败(EADDRINUSE……)会从激活过程抛出,并以绑定诊断信息拒绝 Loader 组合;失败的候选 fiber 会被 dispose(资源释放)。处理 HTTP 请求时抛错(例如 fallback 持有者的 `decodeURIComponent` 收到格式错误的百分号转义,或客户端在请求体传输中途断开)时,服务器会响应 400;若响应头已经发出,则销毁 socket,并记录 warning,但绝不会退出进程。upgrade handler 抛错或升级 socket 出现传输错误时,会记录 warning 并销毁对应 socket。资源释放会启动 `close()` 与 `closeAllConnections()`,销毁所有受跟踪的升级 socket,并仅在 HTTP server 与这些 socket 均已关闭后返回。 + +## 模型体验 + +无。该包只是浏览器与其他插件所注册 HTTP/upgrade route 之间的 Web 载体,其中没有任何内容会进入模型请求。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **不提供 TLS、认证或来源策略**:绑定非回环地址会向对应网络公开服务器;面向部署的加固措施(或在前方放置真正的反向代理)有意不纳入面向开发环境的 v1。 +- **Socket 选项固定不变**:配置只选择绑定宿主与端口;在具体部署产生需求前,backlog 和其他 socket 设置仍保持内部实现。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/index.js new file mode 100644 index 0000000..ce0b497 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/index.js @@ -0,0 +1,217 @@ +import { createServer } from "node:http"; +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +//#region lib/types/index.js +/** +* @deepseek-ai/dsh-host-webserver — Web route-registration plugin: a node:http +* server plus the `webServer` service (HTTP and upgrade route registries, +* index transform taps, and the single fallback seat for everything no route +* claims). Knows no harness concepts and serves no files; the composing +* application's frontend plugin owns dist serving through the fallback hook. +* Web shape only — Electron loads dist over file:// and carries fetch over an +* IPC bridge. This package never prints: the URL line belongs to the shell. +*/ +/** +* The browser HTTP carrier service. Activation listens immediately. Route +* registration order does not affect requests because configured named routes +* must be distinct, and the fallback handler answers anything not yet claimed +* during startup with 404 until its owner registers. A listen failure rejects +* initialization, and the boot process reports the failed fiber. +*/ +var WebServer = class extends Service { + config; + static Config = z.object({ + host: z.union([z.const("127.0.0.1"), z.const("0.0.0.0")]).required(), + port: z.natural().max(65535).required() + }); + exact = /* @__PURE__ */ new Map(); + prefixes = /* @__PURE__ */ new Map(); + upgrades = /* @__PURE__ */ new Map(); + upgradedSockets = /* @__PURE__ */ new Set(); + indexTaps = []; + fallback; + server; + listenedPort; + constructor(ctx, config) { + super(ctx, "webServer"); + this.config = config; + } + /** The listening port (the OS-assigned value when config.port is 0). */ + get port() { + return this.listenedPort; + } + /** The configured bind host (the loopback or all-interfaces literal). */ + get host() { + return this.config.host; + } + /** + * Register a named route. Duplicate (kind, path) throws — route patterns are + * a composition-level contract, so a collision is a misconfiguration. + * @param route - kind, path, and the owning handler. + * @returns the disposer removing the route. + */ + register(route) { + const table = route.kind === "exact" ? this.exact : this.prefixes; + if (table.has(route.path)) throw new Error(`webserver: duplicate ${route.kind} route "${route.path}"`); + table.set(route.path, route); + return () => { + table.delete(route.path); + }; + } + /** + * Register an exact-path HTTP upgrade route. Duplicate paths throw because + * one socket can have only one protocol owner. + * @param route - pathname and handler owning negotiation plus socket use. + * @returns the disposer removing the route. + */ + registerUpgrade(route) { + if (this.upgrades.has(route.path)) throw new Error(`webserver: duplicate upgrade route "${route.path}"`); + this.upgrades.set(route.path, route); + return () => { + this.upgrades.delete(route.path); + }; + } + /** + * Claim the fallback seat: the handler answering every request no named + * route matches (the SPA dist server in the shipped Web composition). One + * owner only — a second registration throws, because two fallbacks cannot + * compose. + * @param handler - owns the full response lifecycle of unmatched requests. + * @returns the disposer releasing the seat. + */ + registerFallback(handler) { + if (this.fallback !== void 0) throw new Error("webserver: fallback already registered"); + this.fallback = handler; + return () => { + this.fallback = void 0; + }; + } + /** + * Register an index.html transform, applied by the fallback owner to every + * index response ({@link applyIndexTaps}) in registration order. + * @param transform - pure html-to-html function. + * @returns the disposer removing the transform. + */ + tapIndex(transform) { + this.indexTaps.push(transform); + return () => { + const at = this.indexTaps.indexOf(transform); + if (at !== -1) this.indexTaps.splice(at, 1); + }; + } + /** Listen; resolves once the socket is bound (rejection = FAILED fiber). */ + async [Service.init]() { + const handle = async (req, res) => { + /* v8 ignore next -- `?? '/'` arm: node:http always sets url on server + requests; the field is only optional on the client-side IncomingMessage type */ + const rawPath = new URL(req.url ?? "/", "http://x").pathname; + const route = this.match(rawPath); + if (route !== void 0) { + await route.handler(req, res); + return; + } + const fallback = this.fallback; + if (fallback === void 0) { + res.writeHead(404); + res.end(); + return; + } + await fallback(req, res); + }; + this.server = createServer((req, res) => { + handle(req, res).catch((err) => { + this.ctx.logger.warn(err instanceof Error ? err : new Error(String(err))); + if (res.headersSent) { + res.destroy(); + return; + } + res.writeHead(400); + res.end(); + }); + }); + this.server.on("upgrade", (req, socket, head) => { + const onError = (error) => { + this.ctx.logger.warn(error); + socket.destroy(); + }; + socket.on("error", onError); + socket.once("close", () => { + socket.off("error", onError); + this.upgradedSockets.delete(socket); + }); + let route; + try { + /* v8 ignore next -- node:http always sets url on server requests. */ + route = this.upgrades.get(new URL(req.url ?? "/", "http://x").pathname); + } catch (error) { + this.ctx.logger.warn(error instanceof Error ? error : new Error(String(error))); + socket.destroy(); + return; + } + if (route === void 0) { + socket.destroy(); + return; + } + this.upgradedSockets.add(socket); + try { + Promise.resolve(route.handler(req, socket, head)).catch((error) => { + this.ctx.logger.warn(error instanceof Error ? error : new Error(String(error))); + socket.destroy(); + }); + } catch (error) { + this.ctx.logger.warn(error instanceof Error ? error : new Error(String(error))); + socket.destroy(); + } + }); + await new Promise((resolve, reject) => { + this.server.once("error", reject); + this.server.listen(this.config.port, this.config.host, () => { + this.server.off("error", reject); + this.server.on("error", (err) => { + this.ctx.logger.error(err); + }); + this.listenedPort = this.server.address().port; + resolve(); + }); + }); + this.ctx.effect(() => async () => { + const serverClosed = new Promise((resolve) => { + this.server.close(() => { + resolve(); + }); + }); + this.server.closeAllConnections(); + const upgradedClosed = [...this.upgradedSockets].map((socket) => new Promise((resolve) => { + socket.once("close", () => { + resolve(); + }); + socket.destroy(); + })); + await Promise.all([serverClosed, ...upgradedClosed]); + }, "webServer.listen"); + } + /** Longest-prefix-wins over the prefix table after an exact-table miss. */ + match(pathname) { + const exact = this.exact.get(pathname); + if (exact !== void 0) return exact; + let best; + for (const [prefix, route] of this.prefixes) { + if (pathname !== prefix && !pathname.startsWith(`${prefix}/`)) continue; + if (best === void 0 || prefix.length > best.path.length) best = route; + } + return best; + } + /** + * Run an index.html body through the registered taps in registration order + * — called by the fallback owner on every index response it renders. + * @param html - the raw index.html body. + * @returns the transformed body. + */ + applyIndexTaps(html) { + let out = html; + for (const transform of this.indexTaps) out = transform(out); + return out; + } +}; +//#endregion +export { WebServer, WebServer as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/invariant.js new file mode 100644 index 0000000..dc4eff7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/invariant.js @@ -0,0 +1,50 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-host-webserver`. +* @module @deepseek-ai/dsh-host-webserver/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-host-webserver"; +/** Cordis companion plugin name. */ +const name = "host-webserver-invariant"; +/** Service required before the companion can register. */ +const inject = ["invariants"]; +/** +* Owned relation: HTTP and upgrade route registrations and their disposers must stay +* symmetric — after the owning fiber of a registered route unloads, the +* route table must no longer answer for its path (a stale route would keep +* serving a disposed plugin's handler). Checked on every fiber teardown +* (cordis 'internal/plugin'): the service's own registry state is compared +* against the set of live fibers' registrations indirectly, by probing that +* dispose really removed the entry — the register() disposer contract. +*/ +const install = (ctx, fail) => { + ctx.on("internal/plugin", () => { + const server = ctx.get("webServer"); + if (server === void 0) return; + const probe = { + kind: "exact", + path: "/__dsh_invariant_probe__", + handler: () => {} + }; + try { + server.register(probe)(); + server.register(probe)(); + const upgradeProbe = { + path: "/__dsh_invariant_upgrade_probe__", + handler: () => {} + }; + server.registerUpgrade(upgradeProbe)(); + server.registerUpgrade(upgradeProbe)(); + } catch { + fail("webServer route disposer left a route registered — route tables and fiber lifecycles diverged"); + } + }, { global: true }); +}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/index.d.ts new file mode 100644 index 0000000..d256d36 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/index.d.ts @@ -0,0 +1,109 @@ +/** + * @deepseek-ai/dsh-host-webserver — Web route-registration plugin: a node:http + * server plus the `webServer` service (HTTP and upgrade route registries, + * index transform taps, and the single fallback seat for everything no route + * claims). Knows no harness concepts and serves no files; the composing + * application's frontend plugin owns dist serving through the fallback hook. + * Web shape only — Electron loads dist over file:// and carries fetch over an + * IPC bridge. This package never prints: the URL line belongs to the shell. + */ +import type { IncomingMessage, ServerResponse } from 'node:http'; +import type { Duplex } from 'node:stream'; +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +declare module '@deepseek-ai/cordis' { + interface Context { + webServer: WebServer; + } +} +/** Route match kind: 'exact' matches the pathname verbatim; 'prefix' p matches p and p/. */ +export type WebRouteKind = 'exact' | 'prefix'; +/** One named route registration. */ +export interface WebRoute { + kind: WebRouteKind; + /** Absolute pathname, no trailing slash. */ + path: string; + /** Owns the full response lifecycle (may hold the response open, e.g. SSE). */ + handler: (req: IncomingMessage, res: ServerResponse) => void | Promise; +} +/** One exact-path HTTP upgrade registration. */ +export interface WebUpgradeRoute { + /** Absolute pathname, no trailing slash. */ + path: string; + /** Owns protocol negotiation and the upgraded socket after dispatch. */ + handler: (req: IncomingMessage, socket: Duplex, head: Buffer) => void | Promise; +} +/** Gateway config: the listen address. */ +export interface Config { + /** Listen host; the two supported values are loopback and all-interfaces. */ + host: '127.0.0.1' | '0.0.0.0'; + /** Listen port; zero requests an OS-assigned port. */ + port: number; +} +/** + * The browser HTTP carrier service. Activation listens immediately. Route + * registration order does not affect requests because configured named routes + * must be distinct, and the fallback handler answers anything not yet claimed + * during startup with 404 until its owner registers. A listen failure rejects + * initialization, and the boot process reports the failed fiber. + */ +export declare class WebServer extends Service { + private config; + static Config: z; + private readonly exact; + private readonly prefixes; + private readonly upgrades; + private readonly upgradedSockets; + private readonly indexTaps; + private fallback; + private server; + private listenedPort; + constructor(ctx: Context, config: Config); + /** The listening port (the OS-assigned value when config.port is 0). */ + get port(): number; + /** The configured bind host (the loopback or all-interfaces literal). */ + get host(): Config['host']; + /** + * Register a named route. Duplicate (kind, path) throws — route patterns are + * a composition-level contract, so a collision is a misconfiguration. + * @param route - kind, path, and the owning handler. + * @returns the disposer removing the route. + */ + register(route: WebRoute): () => void; + /** + * Register an exact-path HTTP upgrade route. Duplicate paths throw because + * one socket can have only one protocol owner. + * @param route - pathname and handler owning negotiation plus socket use. + * @returns the disposer removing the route. + */ + registerUpgrade(route: WebUpgradeRoute): () => void; + /** + * Claim the fallback seat: the handler answering every request no named + * route matches (the SPA dist server in the shipped Web composition). One + * owner only — a second registration throws, because two fallbacks cannot + * compose. + * @param handler - owns the full response lifecycle of unmatched requests. + * @returns the disposer releasing the seat. + */ + registerFallback(handler: WebRoute['handler']): () => void; + /** + * Register an index.html transform, applied by the fallback owner to every + * index response ({@link applyIndexTaps}) in registration order. + * @param transform - pure html-to-html function. + * @returns the disposer removing the transform. + */ + tapIndex(transform: (html: string) => string): () => void; + /** Listen; resolves once the socket is bound (rejection = FAILED fiber). */ + [Service.init](): Promise; + /** Longest-prefix-wins over the prefix table after an exact-table miss. */ + private match; + /** + * Run an index.html body through the registered taps in registration order + * — called by the fallback owner on every index response it renders. + * @param html - the raw index.html body. + * @returns the transformed body. + */ + applyIndexTaps(html: string): string; +} +export default WebServer; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/invariant.d.ts new file mode 100644 index 0000000..9d15199 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-host-webserver`. + * @module @deepseek-ai/dsh-host-webserver/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "host-webserver-invariant"; +/** Service required before the companion can register. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/package.json new file mode 100644 index 0000000..eefa486 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-host-webserver/package.json @@ -0,0 +1,45 @@ +{ + "name": "@deepseek-ai/dsh-host-webserver", + "description": "Web route-registration plugin: HTTP and upgrade routes, index transform taps, and static dist fallback; knows no harness concepts", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/host/webserver" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_4e83f049ed8dee9b8d2facc78c419c22/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.i18n.yaml new file mode 100644 index 0000000..591ca04 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/host/webserver/README.md +README.md: 7927c791a809ad272edce1310b3c50bbe30720a5 +README.zh.md: 82252adb3945f22c83abddbd3bbdd11556383add diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.md new file mode 100644 index 0000000..7927c79 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.md @@ -0,0 +1,22 @@ +# @deepseek-ai/dsh-host-webserver + +English | [中文](README.zh.md) + +Web HTTP and upgrade-route registration plugin (default-exported `WebServer`, config `{host, port}`): a `node:http` server that listens on activation and provides `ctx.webServer`. `register(route)` adds a named `exact`/`prefix` HTTP route; `registerUpgrade(route)` adds an upgrade route for an exact pathname. A duplicate path within either table throws because route patterns are a composition-level contract and a collision is a misconfiguration; both methods return a disposer that removes the registration. `registerFallback(handler)` registers the one handler for requests that match no named route. A second registration throws; the SPA dist server [`dsh-host-frontend-static`](../frontend-static/README.md) is the shipped owner, and the server returns 404 while none is registered. `tapIndex(transform)` adds an index.html transform, and `applyIndexTaps(html)` runs a body through the registered transforms in order; the fallback handler calls it on every index response. `port` reads the listening port (the OS-assigned value when `port` is 0), and `host` reads the configured bind host (composition-time facts other plugins adapt to, e.g. the directory-picker chooser). HTTP match order is fixed: exact over the whole table, then longest prefix, then the fallback handler. Upgrades match exactly and unmatched connections are closed; registration order carries no request-facing semantics. + +The package knows no harness concepts and serves no files: the `/api` HTTP bridge and downlink WebSockets are routes owned by the connection plugin, plugin bundles and the HMR event stream are routes owned by the modules/hmr plugins, and dist serving belongs to the fallback owner. The upgrade handler owns the protocol handshake and connection contents; the webserver only delivers the raw socket and request. `host` accepts only `127.0.0.1` (default posture) and `0.0.0.0` (deliberate network exposure). This server serves browsers only; Electron loads dist over `file://` and carries fetch over an IPC bridge. This package never prints; the URL line belongs to the shell. + +A listen failure (EADDRINUSE…) throws out of activation and rejects Loader composition with the bind diagnostic; the failed candidate fiber is disposed. An HTTP request whose handling throws (a fallback owner's `decodeURIComponent` on a malformed %-escape, a client dropping mid-body) is answered 400 — or the socket destroyed when headers are already out — and logged as a warning; it never exits the process. An upgrade-handler exception or upgraded-socket transport error is logged as a warning and destroys its socket. Disposal starts `close()` and `closeAllConnections()`, destroys every tracked upgraded socket, and returns only after the HTTP server and those sockets have closed. + +## Model Experience + +None, as the package is a Web carrier between the browser and the HTTP/upgrade routes other plugins register; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **No TLS, auth, or origin policy** — binding a non-loopback address exposes the server to that network; deployment hardening (or fronting it with a real reverse proxy) is deliberately out of scope for the dev-facing v1. +- **Socket options are fixed** — config selects the bind host and port, while backlog and other socket settings remain internal until a deployment needs them. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.zh.md new file mode 100644 index 0000000..82252ad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/README.zh.md @@ -0,0 +1,22 @@ +# @deepseek-ai/dsh-host-webserver + +[English](README.md) | 中文 + +Web HTTP 与 upgrade route 注册插件(默认导出 `WebServer`,配置为 `{host, port}`):一个在激活时开始监听的 `node:http` 服务器,提供 `ctx.webServer`。`register(route)` 添加具名的 `exact`/`prefix` HTTP route;`registerUpgrade(route)` 添加精确 pathname 的 upgrade route;同一张表内的重复路径会抛错,因为 route 模式是组合层约定,冲突即配置错误;两者返回的 disposer 都会移除注册。`registerFallback(handler)` 注册一个 handler,处理所有未被具名 route 命中的请求。第二次注册会抛错;随附的 SPA dist 服务器 [`dsh-host-frontend-static`](../frontend-static/README.md) 是该 handler 的所有者,没有注册 handler 时服务器返回 404。`tapIndex(transform)` 添加一个 index.html 转换,`applyIndexTaps(html)` 按注册顺序对一段响应体运行已注册的转换;fallback handler 在每次 index 响应时调用它。`port` 读取正在监听的端口(当 `port` 为 0 时读取 OS 分配的值),`host` 读取配置的绑定宿主(这些是其他插件据以自适应的组合期事实,例如 directory-picker 选择器)。HTTP 匹配顺序固定不变:先在整张表中匹配精确 route,再匹配最长前缀,最后交给 fallback handler。upgrade 只做精确匹配,未命中连接直接关闭;注册顺序不影响请求处理。 + +该包不了解任何 harness 概念,也不提供任何文件服务:`/api` HTTP 桥接与下行 WebSocket 是 connection 插件的 route,插件 bundle 与 HMR(热模块替换)事件流是 modules/hmr 插件的 route,dist 服务则属于 fallback 持有者。upgrade handler 拥有协议握手与连接内容;webserver 只交付原始 socket 与 request。`host` 只接受 `127.0.0.1`(默认安全姿态)和 `0.0.0.0`(有意向网络开放)。该服务器只服务浏览器;Electron 通过 `file://` 加载 dist,并经 IPC 桥接承载 fetch。该包从不打印内容;URL 行属于 shell。 + +监听失败(EADDRINUSE……)会从激活过程抛出,并以绑定诊断信息拒绝 Loader 组合;失败的候选 fiber 会被 dispose(资源释放)。处理 HTTP 请求时抛错(例如 fallback 持有者的 `decodeURIComponent` 收到格式错误的百分号转义,或客户端在请求体传输中途断开)时,服务器会响应 400;若响应头已经发出,则销毁 socket,并记录 warning,但绝不会退出进程。upgrade handler 抛错或升级 socket 出现传输错误时,会记录 warning 并销毁对应 socket。资源释放会启动 `close()` 与 `closeAllConnections()`,销毁所有受跟踪的升级 socket,并仅在 HTTP server 与这些 socket 均已关闭后返回。 + +## 模型体验 + +无。该包只是浏览器与其他插件所注册 HTTP/upgrade route 之间的 Web 载体,其中没有任何内容会进入模型请求。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **不提供 TLS、认证或来源策略**:绑定非回环地址会向对应网络公开服务器;面向部署的加固措施(或在前方放置真正的反向代理)有意不纳入面向开发环境的 v1。 +- **Socket 选项固定不变**:配置只选择绑定宿主与端口;在具体部署产生需求前,backlog 和其他 socket 设置仍保持内部实现。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/index.js new file mode 100644 index 0000000..ce0b497 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/index.js @@ -0,0 +1,217 @@ +import { createServer } from "node:http"; +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +//#region lib/types/index.js +/** +* @deepseek-ai/dsh-host-webserver — Web route-registration plugin: a node:http +* server plus the `webServer` service (HTTP and upgrade route registries, +* index transform taps, and the single fallback seat for everything no route +* claims). Knows no harness concepts and serves no files; the composing +* application's frontend plugin owns dist serving through the fallback hook. +* Web shape only — Electron loads dist over file:// and carries fetch over an +* IPC bridge. This package never prints: the URL line belongs to the shell. +*/ +/** +* The browser HTTP carrier service. Activation listens immediately. Route +* registration order does not affect requests because configured named routes +* must be distinct, and the fallback handler answers anything not yet claimed +* during startup with 404 until its owner registers. A listen failure rejects +* initialization, and the boot process reports the failed fiber. +*/ +var WebServer = class extends Service { + config; + static Config = z.object({ + host: z.union([z.const("127.0.0.1"), z.const("0.0.0.0")]).required(), + port: z.natural().max(65535).required() + }); + exact = /* @__PURE__ */ new Map(); + prefixes = /* @__PURE__ */ new Map(); + upgrades = /* @__PURE__ */ new Map(); + upgradedSockets = /* @__PURE__ */ new Set(); + indexTaps = []; + fallback; + server; + listenedPort; + constructor(ctx, config) { + super(ctx, "webServer"); + this.config = config; + } + /** The listening port (the OS-assigned value when config.port is 0). */ + get port() { + return this.listenedPort; + } + /** The configured bind host (the loopback or all-interfaces literal). */ + get host() { + return this.config.host; + } + /** + * Register a named route. Duplicate (kind, path) throws — route patterns are + * a composition-level contract, so a collision is a misconfiguration. + * @param route - kind, path, and the owning handler. + * @returns the disposer removing the route. + */ + register(route) { + const table = route.kind === "exact" ? this.exact : this.prefixes; + if (table.has(route.path)) throw new Error(`webserver: duplicate ${route.kind} route "${route.path}"`); + table.set(route.path, route); + return () => { + table.delete(route.path); + }; + } + /** + * Register an exact-path HTTP upgrade route. Duplicate paths throw because + * one socket can have only one protocol owner. + * @param route - pathname and handler owning negotiation plus socket use. + * @returns the disposer removing the route. + */ + registerUpgrade(route) { + if (this.upgrades.has(route.path)) throw new Error(`webserver: duplicate upgrade route "${route.path}"`); + this.upgrades.set(route.path, route); + return () => { + this.upgrades.delete(route.path); + }; + } + /** + * Claim the fallback seat: the handler answering every request no named + * route matches (the SPA dist server in the shipped Web composition). One + * owner only — a second registration throws, because two fallbacks cannot + * compose. + * @param handler - owns the full response lifecycle of unmatched requests. + * @returns the disposer releasing the seat. + */ + registerFallback(handler) { + if (this.fallback !== void 0) throw new Error("webserver: fallback already registered"); + this.fallback = handler; + return () => { + this.fallback = void 0; + }; + } + /** + * Register an index.html transform, applied by the fallback owner to every + * index response ({@link applyIndexTaps}) in registration order. + * @param transform - pure html-to-html function. + * @returns the disposer removing the transform. + */ + tapIndex(transform) { + this.indexTaps.push(transform); + return () => { + const at = this.indexTaps.indexOf(transform); + if (at !== -1) this.indexTaps.splice(at, 1); + }; + } + /** Listen; resolves once the socket is bound (rejection = FAILED fiber). */ + async [Service.init]() { + const handle = async (req, res) => { + /* v8 ignore next -- `?? '/'` arm: node:http always sets url on server + requests; the field is only optional on the client-side IncomingMessage type */ + const rawPath = new URL(req.url ?? "/", "http://x").pathname; + const route = this.match(rawPath); + if (route !== void 0) { + await route.handler(req, res); + return; + } + const fallback = this.fallback; + if (fallback === void 0) { + res.writeHead(404); + res.end(); + return; + } + await fallback(req, res); + }; + this.server = createServer((req, res) => { + handle(req, res).catch((err) => { + this.ctx.logger.warn(err instanceof Error ? err : new Error(String(err))); + if (res.headersSent) { + res.destroy(); + return; + } + res.writeHead(400); + res.end(); + }); + }); + this.server.on("upgrade", (req, socket, head) => { + const onError = (error) => { + this.ctx.logger.warn(error); + socket.destroy(); + }; + socket.on("error", onError); + socket.once("close", () => { + socket.off("error", onError); + this.upgradedSockets.delete(socket); + }); + let route; + try { + /* v8 ignore next -- node:http always sets url on server requests. */ + route = this.upgrades.get(new URL(req.url ?? "/", "http://x").pathname); + } catch (error) { + this.ctx.logger.warn(error instanceof Error ? error : new Error(String(error))); + socket.destroy(); + return; + } + if (route === void 0) { + socket.destroy(); + return; + } + this.upgradedSockets.add(socket); + try { + Promise.resolve(route.handler(req, socket, head)).catch((error) => { + this.ctx.logger.warn(error instanceof Error ? error : new Error(String(error))); + socket.destroy(); + }); + } catch (error) { + this.ctx.logger.warn(error instanceof Error ? error : new Error(String(error))); + socket.destroy(); + } + }); + await new Promise((resolve, reject) => { + this.server.once("error", reject); + this.server.listen(this.config.port, this.config.host, () => { + this.server.off("error", reject); + this.server.on("error", (err) => { + this.ctx.logger.error(err); + }); + this.listenedPort = this.server.address().port; + resolve(); + }); + }); + this.ctx.effect(() => async () => { + const serverClosed = new Promise((resolve) => { + this.server.close(() => { + resolve(); + }); + }); + this.server.closeAllConnections(); + const upgradedClosed = [...this.upgradedSockets].map((socket) => new Promise((resolve) => { + socket.once("close", () => { + resolve(); + }); + socket.destroy(); + })); + await Promise.all([serverClosed, ...upgradedClosed]); + }, "webServer.listen"); + } + /** Longest-prefix-wins over the prefix table after an exact-table miss. */ + match(pathname) { + const exact = this.exact.get(pathname); + if (exact !== void 0) return exact; + let best; + for (const [prefix, route] of this.prefixes) { + if (pathname !== prefix && !pathname.startsWith(`${prefix}/`)) continue; + if (best === void 0 || prefix.length > best.path.length) best = route; + } + return best; + } + /** + * Run an index.html body through the registered taps in registration order + * — called by the fallback owner on every index response it renders. + * @param html - the raw index.html body. + * @returns the transformed body. + */ + applyIndexTaps(html) { + let out = html; + for (const transform of this.indexTaps) out = transform(out); + return out; + } +}; +//#endregion +export { WebServer, WebServer as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/invariant.js new file mode 100644 index 0000000..dc4eff7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/invariant.js @@ -0,0 +1,50 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-host-webserver`. +* @module @deepseek-ai/dsh-host-webserver/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-host-webserver"; +/** Cordis companion plugin name. */ +const name = "host-webserver-invariant"; +/** Service required before the companion can register. */ +const inject = ["invariants"]; +/** +* Owned relation: HTTP and upgrade route registrations and their disposers must stay +* symmetric — after the owning fiber of a registered route unloads, the +* route table must no longer answer for its path (a stale route would keep +* serving a disposed plugin's handler). Checked on every fiber teardown +* (cordis 'internal/plugin'): the service's own registry state is compared +* against the set of live fibers' registrations indirectly, by probing that +* dispose really removed the entry — the register() disposer contract. +*/ +const install = (ctx, fail) => { + ctx.on("internal/plugin", () => { + const server = ctx.get("webServer"); + if (server === void 0) return; + const probe = { + kind: "exact", + path: "/__dsh_invariant_probe__", + handler: () => {} + }; + try { + server.register(probe)(); + server.register(probe)(); + const upgradeProbe = { + path: "/__dsh_invariant_upgrade_probe__", + handler: () => {} + }; + server.registerUpgrade(upgradeProbe)(); + server.registerUpgrade(upgradeProbe)(); + } catch { + fail("webServer route disposer left a route registered — route tables and fiber lifecycles diverged"); + } + }, { global: true }); +}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/index.d.ts new file mode 100644 index 0000000..d256d36 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/index.d.ts @@ -0,0 +1,109 @@ +/** + * @deepseek-ai/dsh-host-webserver — Web route-registration plugin: a node:http + * server plus the `webServer` service (HTTP and upgrade route registries, + * index transform taps, and the single fallback seat for everything no route + * claims). Knows no harness concepts and serves no files; the composing + * application's frontend plugin owns dist serving through the fallback hook. + * Web shape only — Electron loads dist over file:// and carries fetch over an + * IPC bridge. This package never prints: the URL line belongs to the shell. + */ +import type { IncomingMessage, ServerResponse } from 'node:http'; +import type { Duplex } from 'node:stream'; +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +declare module '@deepseek-ai/cordis' { + interface Context { + webServer: WebServer; + } +} +/** Route match kind: 'exact' matches the pathname verbatim; 'prefix' p matches p and p/. */ +export type WebRouteKind = 'exact' | 'prefix'; +/** One named route registration. */ +export interface WebRoute { + kind: WebRouteKind; + /** Absolute pathname, no trailing slash. */ + path: string; + /** Owns the full response lifecycle (may hold the response open, e.g. SSE). */ + handler: (req: IncomingMessage, res: ServerResponse) => void | Promise; +} +/** One exact-path HTTP upgrade registration. */ +export interface WebUpgradeRoute { + /** Absolute pathname, no trailing slash. */ + path: string; + /** Owns protocol negotiation and the upgraded socket after dispatch. */ + handler: (req: IncomingMessage, socket: Duplex, head: Buffer) => void | Promise; +} +/** Gateway config: the listen address. */ +export interface Config { + /** Listen host; the two supported values are loopback and all-interfaces. */ + host: '127.0.0.1' | '0.0.0.0'; + /** Listen port; zero requests an OS-assigned port. */ + port: number; +} +/** + * The browser HTTP carrier service. Activation listens immediately. Route + * registration order does not affect requests because configured named routes + * must be distinct, and the fallback handler answers anything not yet claimed + * during startup with 404 until its owner registers. A listen failure rejects + * initialization, and the boot process reports the failed fiber. + */ +export declare class WebServer extends Service { + private config; + static Config: z; + private readonly exact; + private readonly prefixes; + private readonly upgrades; + private readonly upgradedSockets; + private readonly indexTaps; + private fallback; + private server; + private listenedPort; + constructor(ctx: Context, config: Config); + /** The listening port (the OS-assigned value when config.port is 0). */ + get port(): number; + /** The configured bind host (the loopback or all-interfaces literal). */ + get host(): Config['host']; + /** + * Register a named route. Duplicate (kind, path) throws — route patterns are + * a composition-level contract, so a collision is a misconfiguration. + * @param route - kind, path, and the owning handler. + * @returns the disposer removing the route. + */ + register(route: WebRoute): () => void; + /** + * Register an exact-path HTTP upgrade route. Duplicate paths throw because + * one socket can have only one protocol owner. + * @param route - pathname and handler owning negotiation plus socket use. + * @returns the disposer removing the route. + */ + registerUpgrade(route: WebUpgradeRoute): () => void; + /** + * Claim the fallback seat: the handler answering every request no named + * route matches (the SPA dist server in the shipped Web composition). One + * owner only — a second registration throws, because two fallbacks cannot + * compose. + * @param handler - owns the full response lifecycle of unmatched requests. + * @returns the disposer releasing the seat. + */ + registerFallback(handler: WebRoute['handler']): () => void; + /** + * Register an index.html transform, applied by the fallback owner to every + * index response ({@link applyIndexTaps}) in registration order. + * @param transform - pure html-to-html function. + * @returns the disposer removing the transform. + */ + tapIndex(transform: (html: string) => string): () => void; + /** Listen; resolves once the socket is bound (rejection = FAILED fiber). */ + [Service.init](): Promise; + /** Longest-prefix-wins over the prefix table after an exact-table miss. */ + private match; + /** + * Run an index.html body through the registered taps in registration order + * — called by the fallback owner on every index response it renders. + * @param html - the raw index.html body. + * @returns the transformed body. + */ + applyIndexTaps(html: string): string; +} +export default WebServer; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/invariant.d.ts new file mode 100644 index 0000000..9d15199 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-host-webserver`. + * @module @deepseek-ai/dsh-host-webserver/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "host-webserver-invariant"; +/** Service required before the companion can register. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/package.json new file mode 100644 index 0000000..4a86680 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver/package.json @@ -0,0 +1,45 @@ +{ + "name": "@deepseek-ai/dsh-host-webserver", + "description": "Web route-registration plugin: HTTP and upgrade routes, index transform taps, and static dist fallback; knows no harness concepts", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/host/webserver" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.i18n.yaml new file mode 100644 index 0000000..1d1bab4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/runtime-diagnostics/invariants/README.md +README.md: 1435a7ad9a4e994ad2c89b5a94e18e86889a831f +README.zh.md: 09ee5006c7d9b43c97468778632239780c49949b diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.md new file mode 100644 index 0000000..1435a7a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.md @@ -0,0 +1,85 @@ +# dsh-invariants + +English | [中文](README.zh.md) + +Configurable registry service for package-owned runtime invariant checks. The root plugin registers `ctx.invariants`; it contains no product checks or product-package imports. Every workspace package publishes a `./invariant` companion that registers its exact npm package name. + +## Service: `InvariantRegistry` (`ctx.invariants`) + +```ts +interface Config { + enabled?: boolean + package_allowlist?: string[] + package_blocklist?: string[] +} +``` + +Defaults are `enabled: true`, `package_allowlist: []`, and `package_blocklist: []`. A package is selected only when the service is enabled, the allowlist is empty or at least one allowlist pattern matches its full npm name, and no blocklist pattern matches. Blocklist matches therefore override allowlist matches. + +Each entry is a case-sensitive JavaScript regular-expression source compiled with `new RegExp(pattern)`. Matching is unanchored unless the source supplies `^` and `$`; `/pattern/flags` syntax is not parsed. Blank, whitespace-padded, invalid, or duplicate entries within one list fail service startup. A valid pattern may match no currently loaded package so later loading and HMR remain deterministic. + +`ctx.invariants.register(packageName, installer)` reserves one active registration for the full npm package name, including when filters keep its installer inactive, and returns its disposer. An enabled contribution runs in a dedicated child Cordis fiber. The installer can declare its required services through `installer.inject` and receives `fail(message)`, which throws an `InvariantError` bound to the registering package. Synchronous or asynchronous installer completion is joined before registration succeeds; failure disposes the child and releases ownership atomically. + +The service owns every registration fiber, while the returned disposer also belongs to the companion fiber. Unloading either side removes listeners, trace state, and the reservation. A companion can therefore reload and register the same package name without retaining its previous state. Session-backed companions rebuild their baseline from durable events; live-only companions observe operations that begin after reload. + +`InvariantError` extends `Error`, carries stable `code: 'INVARIANT'`, and exposes the owning `packageName` without adding a product dependency to the service. + +Session itself owns immutable, surface-valid log storage in every composition: it takes one lossless JSON snapshot of each candidate, validates complete cited source-event coverage and positional replacement, restricts `tool/result` replacement to one current result's `content`, deep-freezes the accepted record, and exposes the log through immutable array snapshots. The `dsh-session` invariant companion checks the remaining cross-record rules that Session does not own. + +## Package companions + +Publication and registration are exhaustive; runtime assertions are deliberately not synthetic. A companion installs a check only when its package owns an observable event relationship or relevant mutable-data relationship. Confirming a required method, plugin name, injection, effect, or fixed pure-function result is a type, load, or unit-test concern rather than a runtime invariant. + +When no plausible runtime relationship exists, the companion uses an empty installer with a package-specific leading `No runtime invariant:` comment explaining why. This is common for pure utilities, thin implementations whose behavior is already observed through their interface package, composition-only packages, binaries, persistence adapters whose contracts require crash and round-trip tests, and test-support packages. The explanation must be revisited when the owner gains mutable state or an event protocol. + +The current executable companions protect these relationships: + +| Companion | Checks | +|---|---| +| `dsh-session`, `dsh-agent`, `dsh-scope`, `dsh-agent-loop` | Session enclosure and call/result trace, agent-status transitions, inbox FIFO conservation, scoped subjects, and model-request reconstruction. | +| `dsh-llm`, `dsh-llm-retry`, `dsh-tools`, `dsh-system-prompt` | Stream grammar, durable retry position and bounds, tool-pipeline stages and frozen results, and authoritative prompt-assembly data. | +| `dsh-compaction`, `dsh-hook-protocol`, `dsh-sandbox-policy` | Durable compaction and hook pairing, compaction metadata, and sandbox-mode vocabulary. | +| `dsh-fs`, `dsh-subagent`, `dsh-workflow` | Filesystem event identity, provider/child pairing, and workflow/agent lifecycle identity. | +| `dsh-goal`, `dsh-goal-round-driver` | Durable goal source/content agreement, revision and lifecycle transitions, timestamps, sequential admitted rounds, and reconstructed continuation prompts. | +| `dsh-permission-presets`, `dsh-user-approval` | Active-preset references and approval asked/decided audit pairing. | +| `dsh-jobs`, `dsh-tool-todo` | Task snapshot lifecycle/ownership fields and durable whole-list todo structure. | +| `dsh-time-context` | Durable clock readings agree with the session's open turn and next pre-step position and elapsed baseline; rendered time parses and does not postdate its event. | + +The root entrypoint of each owner remains independent of diagnostics. Loading the service alone installs no product checks, and loading a companion without the service waits on its declared `invariants` injection. + +`pnpm run verify-package-invariants` discovers all workspace packages. It rejects generated markers, unexplained empty installers, non-empty installers that omit or ignore the reporter, incorrect registration names, and incomplete export, publication, dependency, TypeScript-reference, or bundle wiring. This source rule is a minimum ownership check; focused tests prove each executable companion's semantics. + +## Composition + +```ts +import type { Context } from '@deepseek-ai/cordis' +import InvariantRegistry from '@deepseek-ai/dsh-invariants' +import * as SessionInvariant from '@deepseek-ai/dsh-session/invariant' + +declare const ctx: Context + +ctx.plugin(InvariantRegistry, { + enabled: true, + package_allowlist: ['^@deepseek-ai/dsh-'], + package_blocklist: ['^@deepseek-ai/dsh-agent-loop$'], +}) +ctx.plugin(SessionInvariant) +``` + +The standard agent composition mounts the service and its four core stateful companions. Custom compositions explicitly add companions for other loaded packages whose contracts they want checked; filters can disable or select registrations without changing package entrypoints. + +Every ordinary Vitest topology mounts an explicitly enabled service and the current test package's companion. Focused suites cover valid and invalid observations for executable companions, while one exhaustive topology mounts all companions to prove registration and disposal wiring. + +## Model Experience + +None, as the service and companions observe runtime events and mutable snapshots without altering prompts, messages, schemas, streams, or tool results. + +#### KV Cache effect + +None; invariant checks do not assemble or send provider requests. + +## Known Limitations and Deferred Work + +- Request reconstruction covers requests explicitly marked by the loop before freezing; direct one-shot LLM calls remain outside that marker contract even when callers freeze them or attach a session id. +- Live-only lifecycle companions cannot reconstruct operations that began before their own reload. Standard and test compositions mount them before the corresponding operations begin. +- Regular-expression filters are fixed for the service lifetime; changing them requires ordinary Cordis plugin reload. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.zh.md new file mode 100644 index 0000000..09ee500 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.zh.md @@ -0,0 +1,85 @@ +# dsh-invariants + +[English](README.md) | 中文 + +用于包自有运行时不变量检查的可配置注册表服务。根插件注册 `ctx.invariants`;它不包含产品检查或产品包导入。每个工作区包都发布一个 `./invariant` 配套入口,用于注册其精确 npm 包名。 + +## 服务:`InvariantRegistry`(`ctx.invariants`) + +```ts +interface Config { + enabled?: boolean + package_allowlist?: string[] + package_blocklist?: string[] +} +``` + +默认值为 `enabled: true`、`package_allowlist: []` 和 `package_blocklist: []`。只有在服务启用、allowlist 为空或至少一个 allowlist pattern 匹配完整 npm 名称,且没有 blocklist pattern 匹配时,包才被选中。因此,blocklist 匹配优先于 allowlist 匹配。 + +每个条目都是区分大小写的 JavaScript 正则表达式源,使用 `new RegExp(pattern)` 编译。除非源提供 `^` 和 `$`,否则匹配不锚定;不解析 `/pattern/flags` 语法。同一列表中的空白、带前后空白、无效或重复条目会使服务启动失败。有效 pattern 可以不匹配任何当前已加载包,以使后续加载和 HMR(热模块替换)保持确定性。 + +`ctx.invariants.register(packageName, installer)` 为完整 npm 包名保留一个活动注册,即使过滤器使其 installer 保持非活动,并返回 disposer。已启用贡献在专用子 Cordis fiber 中运行。installer 可以通过 `installer.inject` 声明所需服务接口,并收到 `fail(message)`;后者抛出绑定到注册包的 `InvariantError`。在注册成功前,系统会等待同步或异步 installer 完成;失败会原子地 dispose(资源释放)子级并释放归属。 + +服务拥有每个注册 fiber,返回的 disposer 同时属于配套 fiber。卸载任一侧都会移除监听器、跟踪状态和保留。因此,配套入口可以重新加载并注册同一包名,而不保留旧状态。由会话支撑的配套入口从持久事件重建 baseline;仅实时配套入口观察重新加载后开始的操作。 + +`InvariantError` 扩展 `Error`,携带稳定 `code: 'INVARIANT'`,并公开所属 `packageName`,而不向服务添加产品依赖。 + +在每个组合中,Session 自身负责不可变且在对外接口层面有效的日志存储:它对每个候选项制作一份无损 JSON 快照,验证引用的源事件是否齐全以及位置替换是否合法,将 `tool/result` 替换限制为一个当前结果的 `content`,深度冻结已接受记录,并通过不可变数组快照公开日志。`dsh-session` 不变量配套入口检查 Session 不负责的其余跨记录规则。 + +## 包配套入口 + +发布和注册覆盖全部包;但不会为了覆盖全部包而人为编造运行时断言。只有当包拥有可观察事件关系或相关可变数据关系时,配套入口才安装检查。确认必需方法、插件名称、注入、effect 或固定纯函数结果属于类型、加载或单元测试关注点,而非运行时不变量。 + +如果不存在合理的运行时关系,配套入口使用空 installer,并以包专用的前置 `No runtime invariant:` 注释说明原因。纯工具、行为已通过其接口包观察的薄实现、仅组合包、二进制程序、需要通过崩溃测试和往返测试验证其约定的持久化适配器和测试支持包通常属于此类。当 owner 获得可变状态或事件协议时,必须重新审视该说明。 + +当前可执行配套入口保护以下关系: + +| 配套入口 | 检查 | +|---|---| +| `dsh-session`、`dsh-agent`、`dsh-scope`、`dsh-agent-loop` | 会话包含关系和调用/结果跟踪、agent(智能体)状态转换、inbox FIFO 守恒、作用域 subject 和模型请求重建。 | +| `dsh-llm`、`dsh-llm-retry`、`dsh-tools`、`dsh-system-prompt` | 流语法、持久重试位置和边界、工具流水线阶段与冻结结果,以及权威提示词组装数据。 | +| `dsh-compaction`、`dsh-hook-protocol`、`dsh-sandbox-policy` | 持久压缩(compaction)与钩子配对、压缩元数据和沙箱 mode 词汇。 | +| `dsh-fs`、`dsh-subagent`、`dsh-workflow` | 文件系统事件身份、提供方/子级配对和工作流/agent 生命周期身份。 | +| `dsh-goal`、`dsh-goal-round-driver` | 持久 goal 来源/内容一致性、修订和生命周期转换、时间戳、依次获准的 Round 和重建的继续提示词。 | +| `dsh-permission-presets`、`dsh-user-approval` | 活动 preset 引用和审批询问/决定审计配对。 | +| `dsh-jobs`、`dsh-tool-todo` | 任务快照生命周期/归属字段和持久整表 todo 结构。 | +| `dsh-time-context` | 持久化时钟读数与会话中正在进行的轮次、下一步骤开始前的位置及已用时间 baseline 一致;渲染时间可解析,且不晚于其事件。 | + +每个 owner 的根入口仍独立于诊断。单独加载服务不会安装产品检查;在没有服务时加载配套入口,会等待其声明的 `invariants` 注入。 + +`pnpm run verify-package-invariants` 发现全部工作区包。它拒绝生成标记、未说明的空 installer、省略或忽略 reporter 的非空 installer、错误注册名称,以及不完整的导出、发布、依赖、TypeScript 引用或 bundle 接线。该源码规则是最低归属检查;聚焦测试证明每个可执行配套入口的语义。 + +## 组合 + +```ts +import type { Context } from '@deepseek-ai/cordis' +import InvariantRegistry from '@deepseek-ai/dsh-invariants' +import * as SessionInvariant from '@deepseek-ai/dsh-session/invariant' + +declare const ctx: Context + +ctx.plugin(InvariantRegistry, { + enabled: true, + package_allowlist: ['^@deepseek-ai/dsh-'], + package_blocklist: ['^@deepseek-ai/dsh-agent-loop$'], +}) +ctx.plugin(SessionInvariant) +``` + +标准 agent 组合挂载服务和 4 个核心有状态配套入口。自定义组合为希望检查其约定的其他已加载包显式添加配套入口;过滤器可以在不改变包入口的情况下禁用或选择注册。 + +每个普通 Vitest 拓扑都挂载显式启用的服务和当前测试包的配套入口。聚焦套件覆盖可执行配套入口的合法与违规观测,一个穷尽拓扑则挂载全部配套入口,以证明注册和 dispose 接线。 + +## 模型体验 + +无。服务和配套入口观察运行时事件和可变快照,不会更改提示词、消息、schema、流或工具结果。 + +#### KV Cache 影响 + +无;不变量检查不组装或发送提供方请求。 + +## 已知限制与暂缓事项 + +- 请求重建覆盖 loop 在冻结前显式标记的请求;直接一次性 LLM(大语言模型)调用即使由调用方冻结或附加会话 id,仍不在该标记约定内。 +- 仅实时生命周期配套入口无法重建自身重新加载前开始的操作。标准组合和测试组合会在相应操作开始前挂载它们。 +- 正则表达式过滤器在服务生命周期内固定;更改它们需要执行普通 Cordis 插件重新加载。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/index.js new file mode 100644 index 0000000..8a8f9d8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/index.js @@ -0,0 +1,123 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +//#region lib/types/index.js +/** +* Configurable registry for package-owned runtime invariant contributions. +* Every workspace package registers checks from a `./invariant` companion; +* ordinary package entrypoints stay independent of diagnostics. +* +* @module @deepseek-ai/dsh-invariants +*/ +/** Thrown when a package-owned runtime invariant is violated. */ +var InvariantError = class extends Error { + /** Stable machine-readable invariant failure code. */ + code = "INVARIANT"; + /** Full npm package name that owns the violated invariant. */ + packageName; + /** + * Construct a package-attributed invariant failure. + * @param packageName - full npm package name that registered the check. + * @param message - violated contract, without the standard error prefix. + */ + constructor(packageName, message) { + super(`invariant violated by "${packageName}": ${message}`); + this.name = "InvariantError"; + this.packageName = packageName; + } +}; +/** Compile and validate one package-filter list. */ +function compilePatterns(field, values) { + const seen = /* @__PURE__ */ new Set(); + return values.map((value) => { + if (value.length === 0 || value.trim() !== value) throw new Error(`invariants: ${field} entries must be non-blank and have no surrounding whitespace`); + if (seen.has(value)) throw new Error(`invariants: ${field} contains duplicate regex ${JSON.stringify(value)}`); + seen.add(value); + try { + return new RegExp(value); + } catch (cause) { + throw new Error(`invariants: ${field} contains invalid regex ${JSON.stringify(value)}`, { cause }); + } + }); +} +/** Package-owned invariant registry with global and regex-based selection. */ +var InvariantRegistry = class extends Service { + static Config = z.object({ + enabled: z.boolean().default(true), + package_allowlist: z.array(z.string()).default([]), + package_blocklist: z.array(z.string()).default([]) + }); + enabled; + ownerCtx; + packageAllowlist; + packageBlocklist; + registrations = /* @__PURE__ */ new Set(); + /** + * Create and install the invariant registry. + * @param ctx - Cordis context that owns the service. + * @param config - global enablement and package-name regex filters. + */ + constructor(ctx, config = {}) { + super(ctx, "invariants"); + this.ownerCtx = ctx; + this.enabled = config.enabled ?? true; + this.packageAllowlist = compilePatterns("package_allowlist", config.package_allowlist ?? []); + this.packageBlocklist = compilePatterns("package_blocklist", config.package_blocklist ?? []); + } + /** Return whether one full package name passes the configured filters. */ + selected(packageName) { + if (!this.enabled) return false; + if (this.packageAllowlist.length > 0 && !this.packageAllowlist.some((pattern) => pattern.test(packageName))) return false; + return !this.packageBlocklist.some((pattern) => pattern.test(packageName)); + } + /** + * Register one package's invariant installer. The package name is reserved + * even when filtering disables its checks. Enabled installers run in a child + * fiber; failure disposes that fiber and releases the reservation. + * @param packageName - full npm package name that owns the contribution. + * @param installer - listener or startup-check installer for the child context. + * @returns an effect-scoped disposer for the registration. + */ + register(packageName, installer) { + if (packageName.length === 0 || packageName.trim() !== packageName || /\s/.test(packageName)) throw new Error("invariants: packageName must be non-blank and contain no whitespace"); + if (this.registrations.has(packageName)) throw new Error(`invariants: package "${packageName}" is already registered`); + const ctx = this.ownerCtx; + const registrations = this.registrations; + registrations.add(packageName); + let registration; + try { + registration = ctx.effect(async () => { + if (!this.selected(packageName)) return () => { + registrations.delete(packageName); + }; + const installInvariant = (childCtx) => installer(childCtx, (message) => { + throw new InvariantError(packageName, message); + }); + try { + const child = ctx.plugin(installer.inject === void 0 ? installInvariant : Object.assign(installInvariant, { inject: installer.inject })); + try { + await child; + } catch (error) { + await child.dispose(); + throw error; + } + return async () => { + try { + await child.dispose(); + } finally { + registrations.delete(packageName); + } + }; + } catch (error) { + registrations.delete(packageName); + throw error; + } + }, `invariants.register(${JSON.stringify(packageName)})`); + } catch (error) { + registrations.delete(packageName); + throw error; + } + return registration; + } +}; +//#endregion +export { InvariantError, InvariantRegistry, InvariantRegistry as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/invariant.js new file mode 100644 index 0000000..ed30af2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-invariants`. +* @module @deepseek-ai/dsh-invariants/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-invariants"; +/** Cordis companion plugin name. */ +const name = "invariants-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: registration ownership and child lifecycle are the service's mutation +* boundary itself; observing them from the same registry would only duplicate its implementation. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/index.d.ts new file mode 100644 index 0000000..6e8d23e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/index.d.ts @@ -0,0 +1,83 @@ +/** + * Configurable registry for package-owned runtime invariant contributions. + * Every workspace package registers checks from a `./invariant` companion; + * ordinary package entrypoints stay independent of diagnostics. + * + * @module @deepseek-ai/dsh-invariants + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { Inject } from '@deepseek-ai/cordis'; +import type Schema from '@deepseek-ai/schemastery'; +/** Runtime invariant selection configured on the service plugin. */ +export interface Config { + /** Global switch; defaults to `true`. */ + readonly enabled?: boolean; + /** Case-sensitive JavaScript regex sources that admit package names; empty admits all. */ + readonly package_allowlist?: string[]; + /** Case-sensitive JavaScript regex sources that exclude package names after allowlist matching. */ + readonly package_blocklist?: string[]; +} +/** + * Throw a package-attributed invariant failure. + * @param message - violated package contract without the standard prefix. + * @returns never because reporting a violation throws. + */ +export type InvariantFailure = (message: string) => never; +/** Install one package's checks into the registration's child context. */ +export interface InvariantInstaller { + /** + * Install the package contribution. + * @param ctx - child context owned by this invariant registration. + * @param fail - reporter bound to the registering package name. + * @returns nothing, or a promise settling after asynchronous checks finish. + */ + (ctx: Context, fail: InvariantFailure): void | Promise; + /** Services the child installer fiber may access. */ + readonly inject?: Inject; +} +/** Thrown when a package-owned runtime invariant is violated. */ +export declare class InvariantError extends Error { + /** Stable machine-readable invariant failure code. */ + readonly code: "INVARIANT"; + /** Full npm package name that owns the violated invariant. */ + readonly packageName: string; + /** + * Construct a package-attributed invariant failure. + * @param packageName - full npm package name that registered the check. + * @param message - violated contract, without the standard error prefix. + */ + constructor(packageName: string, message: string); +} +declare module '@deepseek-ai/cordis' { + interface Context { + invariants: InvariantRegistry; + } +} +/** Package-owned invariant registry with global and regex-based selection. */ +export declare class InvariantRegistry extends Service { + static Config: Schema; + private readonly enabled; + private readonly ownerCtx; + private readonly packageAllowlist; + private readonly packageBlocklist; + private readonly registrations; + /** + * Create and install the invariant registry. + * @param ctx - Cordis context that owns the service. + * @param config - global enablement and package-name regex filters. + */ + constructor(ctx: Context, config?: Config); + /** Return whether one full package name passes the configured filters. */ + private selected; + /** + * Register one package's invariant installer. The package name is reserved + * even when filtering disables its checks. Enabled installers run in a child + * fiber; failure disposes that fiber and releases the reservation. + * @param packageName - full npm package name that owns the contribution. + * @param installer - listener or startup-check installer for the child context. + * @returns an effect-scoped disposer for the registration. + */ + register(packageName: string, installer: InvariantInstaller): () => void; +} +export default InvariantRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/invariant.d.ts new file mode 100644 index 0000000..adc4b40 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-invariants`. + * @module @deepseek-ai/dsh-invariants/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "invariants-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/package.json new file mode 100644 index 0000000..f33f7de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/package.json @@ -0,0 +1,43 @@ +{ + "name": "@deepseek-ai/dsh-invariants", + "description": "Registry service for package-owned DeepSeek Harness runtime invariants", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/runtime-diagnostics/invariants" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.i18n.yaml new file mode 100644 index 0000000..1d1bab4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/runtime-diagnostics/invariants/README.md +README.md: 1435a7ad9a4e994ad2c89b5a94e18e86889a831f +README.zh.md: 09ee5006c7d9b43c97468778632239780c49949b diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.md new file mode 100644 index 0000000..1435a7a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.md @@ -0,0 +1,85 @@ +# dsh-invariants + +English | [中文](README.zh.md) + +Configurable registry service for package-owned runtime invariant checks. The root plugin registers `ctx.invariants`; it contains no product checks or product-package imports. Every workspace package publishes a `./invariant` companion that registers its exact npm package name. + +## Service: `InvariantRegistry` (`ctx.invariants`) + +```ts +interface Config { + enabled?: boolean + package_allowlist?: string[] + package_blocklist?: string[] +} +``` + +Defaults are `enabled: true`, `package_allowlist: []`, and `package_blocklist: []`. A package is selected only when the service is enabled, the allowlist is empty or at least one allowlist pattern matches its full npm name, and no blocklist pattern matches. Blocklist matches therefore override allowlist matches. + +Each entry is a case-sensitive JavaScript regular-expression source compiled with `new RegExp(pattern)`. Matching is unanchored unless the source supplies `^` and `$`; `/pattern/flags` syntax is not parsed. Blank, whitespace-padded, invalid, or duplicate entries within one list fail service startup. A valid pattern may match no currently loaded package so later loading and HMR remain deterministic. + +`ctx.invariants.register(packageName, installer)` reserves one active registration for the full npm package name, including when filters keep its installer inactive, and returns its disposer. An enabled contribution runs in a dedicated child Cordis fiber. The installer can declare its required services through `installer.inject` and receives `fail(message)`, which throws an `InvariantError` bound to the registering package. Synchronous or asynchronous installer completion is joined before registration succeeds; failure disposes the child and releases ownership atomically. + +The service owns every registration fiber, while the returned disposer also belongs to the companion fiber. Unloading either side removes listeners, trace state, and the reservation. A companion can therefore reload and register the same package name without retaining its previous state. Session-backed companions rebuild their baseline from durable events; live-only companions observe operations that begin after reload. + +`InvariantError` extends `Error`, carries stable `code: 'INVARIANT'`, and exposes the owning `packageName` without adding a product dependency to the service. + +Session itself owns immutable, surface-valid log storage in every composition: it takes one lossless JSON snapshot of each candidate, validates complete cited source-event coverage and positional replacement, restricts `tool/result` replacement to one current result's `content`, deep-freezes the accepted record, and exposes the log through immutable array snapshots. The `dsh-session` invariant companion checks the remaining cross-record rules that Session does not own. + +## Package companions + +Publication and registration are exhaustive; runtime assertions are deliberately not synthetic. A companion installs a check only when its package owns an observable event relationship or relevant mutable-data relationship. Confirming a required method, plugin name, injection, effect, or fixed pure-function result is a type, load, or unit-test concern rather than a runtime invariant. + +When no plausible runtime relationship exists, the companion uses an empty installer with a package-specific leading `No runtime invariant:` comment explaining why. This is common for pure utilities, thin implementations whose behavior is already observed through their interface package, composition-only packages, binaries, persistence adapters whose contracts require crash and round-trip tests, and test-support packages. The explanation must be revisited when the owner gains mutable state or an event protocol. + +The current executable companions protect these relationships: + +| Companion | Checks | +|---|---| +| `dsh-session`, `dsh-agent`, `dsh-scope`, `dsh-agent-loop` | Session enclosure and call/result trace, agent-status transitions, inbox FIFO conservation, scoped subjects, and model-request reconstruction. | +| `dsh-llm`, `dsh-llm-retry`, `dsh-tools`, `dsh-system-prompt` | Stream grammar, durable retry position and bounds, tool-pipeline stages and frozen results, and authoritative prompt-assembly data. | +| `dsh-compaction`, `dsh-hook-protocol`, `dsh-sandbox-policy` | Durable compaction and hook pairing, compaction metadata, and sandbox-mode vocabulary. | +| `dsh-fs`, `dsh-subagent`, `dsh-workflow` | Filesystem event identity, provider/child pairing, and workflow/agent lifecycle identity. | +| `dsh-goal`, `dsh-goal-round-driver` | Durable goal source/content agreement, revision and lifecycle transitions, timestamps, sequential admitted rounds, and reconstructed continuation prompts. | +| `dsh-permission-presets`, `dsh-user-approval` | Active-preset references and approval asked/decided audit pairing. | +| `dsh-jobs`, `dsh-tool-todo` | Task snapshot lifecycle/ownership fields and durable whole-list todo structure. | +| `dsh-time-context` | Durable clock readings agree with the session's open turn and next pre-step position and elapsed baseline; rendered time parses and does not postdate its event. | + +The root entrypoint of each owner remains independent of diagnostics. Loading the service alone installs no product checks, and loading a companion without the service waits on its declared `invariants` injection. + +`pnpm run verify-package-invariants` discovers all workspace packages. It rejects generated markers, unexplained empty installers, non-empty installers that omit or ignore the reporter, incorrect registration names, and incomplete export, publication, dependency, TypeScript-reference, or bundle wiring. This source rule is a minimum ownership check; focused tests prove each executable companion's semantics. + +## Composition + +```ts +import type { Context } from '@deepseek-ai/cordis' +import InvariantRegistry from '@deepseek-ai/dsh-invariants' +import * as SessionInvariant from '@deepseek-ai/dsh-session/invariant' + +declare const ctx: Context + +ctx.plugin(InvariantRegistry, { + enabled: true, + package_allowlist: ['^@deepseek-ai/dsh-'], + package_blocklist: ['^@deepseek-ai/dsh-agent-loop$'], +}) +ctx.plugin(SessionInvariant) +``` + +The standard agent composition mounts the service and its four core stateful companions. Custom compositions explicitly add companions for other loaded packages whose contracts they want checked; filters can disable or select registrations without changing package entrypoints. + +Every ordinary Vitest topology mounts an explicitly enabled service and the current test package's companion. Focused suites cover valid and invalid observations for executable companions, while one exhaustive topology mounts all companions to prove registration and disposal wiring. + +## Model Experience + +None, as the service and companions observe runtime events and mutable snapshots without altering prompts, messages, schemas, streams, or tool results. + +#### KV Cache effect + +None; invariant checks do not assemble or send provider requests. + +## Known Limitations and Deferred Work + +- Request reconstruction covers requests explicitly marked by the loop before freezing; direct one-shot LLM calls remain outside that marker contract even when callers freeze them or attach a session id. +- Live-only lifecycle companions cannot reconstruct operations that began before their own reload. Standard and test compositions mount them before the corresponding operations begin. +- Regular-expression filters are fixed for the service lifetime; changing them requires ordinary Cordis plugin reload. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.zh.md new file mode 100644 index 0000000..09ee500 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/README.zh.md @@ -0,0 +1,85 @@ +# dsh-invariants + +[English](README.md) | 中文 + +用于包自有运行时不变量检查的可配置注册表服务。根插件注册 `ctx.invariants`;它不包含产品检查或产品包导入。每个工作区包都发布一个 `./invariant` 配套入口,用于注册其精确 npm 包名。 + +## 服务:`InvariantRegistry`(`ctx.invariants`) + +```ts +interface Config { + enabled?: boolean + package_allowlist?: string[] + package_blocklist?: string[] +} +``` + +默认值为 `enabled: true`、`package_allowlist: []` 和 `package_blocklist: []`。只有在服务启用、allowlist 为空或至少一个 allowlist pattern 匹配完整 npm 名称,且没有 blocklist pattern 匹配时,包才被选中。因此,blocklist 匹配优先于 allowlist 匹配。 + +每个条目都是区分大小写的 JavaScript 正则表达式源,使用 `new RegExp(pattern)` 编译。除非源提供 `^` 和 `$`,否则匹配不锚定;不解析 `/pattern/flags` 语法。同一列表中的空白、带前后空白、无效或重复条目会使服务启动失败。有效 pattern 可以不匹配任何当前已加载包,以使后续加载和 HMR(热模块替换)保持确定性。 + +`ctx.invariants.register(packageName, installer)` 为完整 npm 包名保留一个活动注册,即使过滤器使其 installer 保持非活动,并返回 disposer。已启用贡献在专用子 Cordis fiber 中运行。installer 可以通过 `installer.inject` 声明所需服务接口,并收到 `fail(message)`;后者抛出绑定到注册包的 `InvariantError`。在注册成功前,系统会等待同步或异步 installer 完成;失败会原子地 dispose(资源释放)子级并释放归属。 + +服务拥有每个注册 fiber,返回的 disposer 同时属于配套 fiber。卸载任一侧都会移除监听器、跟踪状态和保留。因此,配套入口可以重新加载并注册同一包名,而不保留旧状态。由会话支撑的配套入口从持久事件重建 baseline;仅实时配套入口观察重新加载后开始的操作。 + +`InvariantError` 扩展 `Error`,携带稳定 `code: 'INVARIANT'`,并公开所属 `packageName`,而不向服务添加产品依赖。 + +在每个组合中,Session 自身负责不可变且在对外接口层面有效的日志存储:它对每个候选项制作一份无损 JSON 快照,验证引用的源事件是否齐全以及位置替换是否合法,将 `tool/result` 替换限制为一个当前结果的 `content`,深度冻结已接受记录,并通过不可变数组快照公开日志。`dsh-session` 不变量配套入口检查 Session 不负责的其余跨记录规则。 + +## 包配套入口 + +发布和注册覆盖全部包;但不会为了覆盖全部包而人为编造运行时断言。只有当包拥有可观察事件关系或相关可变数据关系时,配套入口才安装检查。确认必需方法、插件名称、注入、effect 或固定纯函数结果属于类型、加载或单元测试关注点,而非运行时不变量。 + +如果不存在合理的运行时关系,配套入口使用空 installer,并以包专用的前置 `No runtime invariant:` 注释说明原因。纯工具、行为已通过其接口包观察的薄实现、仅组合包、二进制程序、需要通过崩溃测试和往返测试验证其约定的持久化适配器和测试支持包通常属于此类。当 owner 获得可变状态或事件协议时,必须重新审视该说明。 + +当前可执行配套入口保护以下关系: + +| 配套入口 | 检查 | +|---|---| +| `dsh-session`、`dsh-agent`、`dsh-scope`、`dsh-agent-loop` | 会话包含关系和调用/结果跟踪、agent(智能体)状态转换、inbox FIFO 守恒、作用域 subject 和模型请求重建。 | +| `dsh-llm`、`dsh-llm-retry`、`dsh-tools`、`dsh-system-prompt` | 流语法、持久重试位置和边界、工具流水线阶段与冻结结果,以及权威提示词组装数据。 | +| `dsh-compaction`、`dsh-hook-protocol`、`dsh-sandbox-policy` | 持久压缩(compaction)与钩子配对、压缩元数据和沙箱 mode 词汇。 | +| `dsh-fs`、`dsh-subagent`、`dsh-workflow` | 文件系统事件身份、提供方/子级配对和工作流/agent 生命周期身份。 | +| `dsh-goal`、`dsh-goal-round-driver` | 持久 goal 来源/内容一致性、修订和生命周期转换、时间戳、依次获准的 Round 和重建的继续提示词。 | +| `dsh-permission-presets`、`dsh-user-approval` | 活动 preset 引用和审批询问/决定审计配对。 | +| `dsh-jobs`、`dsh-tool-todo` | 任务快照生命周期/归属字段和持久整表 todo 结构。 | +| `dsh-time-context` | 持久化时钟读数与会话中正在进行的轮次、下一步骤开始前的位置及已用时间 baseline 一致;渲染时间可解析,且不晚于其事件。 | + +每个 owner 的根入口仍独立于诊断。单独加载服务不会安装产品检查;在没有服务时加载配套入口,会等待其声明的 `invariants` 注入。 + +`pnpm run verify-package-invariants` 发现全部工作区包。它拒绝生成标记、未说明的空 installer、省略或忽略 reporter 的非空 installer、错误注册名称,以及不完整的导出、发布、依赖、TypeScript 引用或 bundle 接线。该源码规则是最低归属检查;聚焦测试证明每个可执行配套入口的语义。 + +## 组合 + +```ts +import type { Context } from '@deepseek-ai/cordis' +import InvariantRegistry from '@deepseek-ai/dsh-invariants' +import * as SessionInvariant from '@deepseek-ai/dsh-session/invariant' + +declare const ctx: Context + +ctx.plugin(InvariantRegistry, { + enabled: true, + package_allowlist: ['^@deepseek-ai/dsh-'], + package_blocklist: ['^@deepseek-ai/dsh-agent-loop$'], +}) +ctx.plugin(SessionInvariant) +``` + +标准 agent 组合挂载服务和 4 个核心有状态配套入口。自定义组合为希望检查其约定的其他已加载包显式添加配套入口;过滤器可以在不改变包入口的情况下禁用或选择注册。 + +每个普通 Vitest 拓扑都挂载显式启用的服务和当前测试包的配套入口。聚焦套件覆盖可执行配套入口的合法与违规观测,一个穷尽拓扑则挂载全部配套入口,以证明注册和 dispose 接线。 + +## 模型体验 + +无。服务和配套入口观察运行时事件和可变快照,不会更改提示词、消息、schema、流或工具结果。 + +#### KV Cache 影响 + +无;不变量检查不组装或发送提供方请求。 + +## 已知限制与暂缓事项 + +- 请求重建覆盖 loop 在冻结前显式标记的请求;直接一次性 LLM(大语言模型)调用即使由调用方冻结或附加会话 id,仍不在该标记约定内。 +- 仅实时生命周期配套入口无法重建自身重新加载前开始的操作。标准组合和测试组合会在相应操作开始前挂载它们。 +- 正则表达式过滤器在服务生命周期内固定;更改它们需要执行普通 Cordis 插件重新加载。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/index.js new file mode 100644 index 0000000..8a8f9d8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/index.js @@ -0,0 +1,123 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +//#region lib/types/index.js +/** +* Configurable registry for package-owned runtime invariant contributions. +* Every workspace package registers checks from a `./invariant` companion; +* ordinary package entrypoints stay independent of diagnostics. +* +* @module @deepseek-ai/dsh-invariants +*/ +/** Thrown when a package-owned runtime invariant is violated. */ +var InvariantError = class extends Error { + /** Stable machine-readable invariant failure code. */ + code = "INVARIANT"; + /** Full npm package name that owns the violated invariant. */ + packageName; + /** + * Construct a package-attributed invariant failure. + * @param packageName - full npm package name that registered the check. + * @param message - violated contract, without the standard error prefix. + */ + constructor(packageName, message) { + super(`invariant violated by "${packageName}": ${message}`); + this.name = "InvariantError"; + this.packageName = packageName; + } +}; +/** Compile and validate one package-filter list. */ +function compilePatterns(field, values) { + const seen = /* @__PURE__ */ new Set(); + return values.map((value) => { + if (value.length === 0 || value.trim() !== value) throw new Error(`invariants: ${field} entries must be non-blank and have no surrounding whitespace`); + if (seen.has(value)) throw new Error(`invariants: ${field} contains duplicate regex ${JSON.stringify(value)}`); + seen.add(value); + try { + return new RegExp(value); + } catch (cause) { + throw new Error(`invariants: ${field} contains invalid regex ${JSON.stringify(value)}`, { cause }); + } + }); +} +/** Package-owned invariant registry with global and regex-based selection. */ +var InvariantRegistry = class extends Service { + static Config = z.object({ + enabled: z.boolean().default(true), + package_allowlist: z.array(z.string()).default([]), + package_blocklist: z.array(z.string()).default([]) + }); + enabled; + ownerCtx; + packageAllowlist; + packageBlocklist; + registrations = /* @__PURE__ */ new Set(); + /** + * Create and install the invariant registry. + * @param ctx - Cordis context that owns the service. + * @param config - global enablement and package-name regex filters. + */ + constructor(ctx, config = {}) { + super(ctx, "invariants"); + this.ownerCtx = ctx; + this.enabled = config.enabled ?? true; + this.packageAllowlist = compilePatterns("package_allowlist", config.package_allowlist ?? []); + this.packageBlocklist = compilePatterns("package_blocklist", config.package_blocklist ?? []); + } + /** Return whether one full package name passes the configured filters. */ + selected(packageName) { + if (!this.enabled) return false; + if (this.packageAllowlist.length > 0 && !this.packageAllowlist.some((pattern) => pattern.test(packageName))) return false; + return !this.packageBlocklist.some((pattern) => pattern.test(packageName)); + } + /** + * Register one package's invariant installer. The package name is reserved + * even when filtering disables its checks. Enabled installers run in a child + * fiber; failure disposes that fiber and releases the reservation. + * @param packageName - full npm package name that owns the contribution. + * @param installer - listener or startup-check installer for the child context. + * @returns an effect-scoped disposer for the registration. + */ + register(packageName, installer) { + if (packageName.length === 0 || packageName.trim() !== packageName || /\s/.test(packageName)) throw new Error("invariants: packageName must be non-blank and contain no whitespace"); + if (this.registrations.has(packageName)) throw new Error(`invariants: package "${packageName}" is already registered`); + const ctx = this.ownerCtx; + const registrations = this.registrations; + registrations.add(packageName); + let registration; + try { + registration = ctx.effect(async () => { + if (!this.selected(packageName)) return () => { + registrations.delete(packageName); + }; + const installInvariant = (childCtx) => installer(childCtx, (message) => { + throw new InvariantError(packageName, message); + }); + try { + const child = ctx.plugin(installer.inject === void 0 ? installInvariant : Object.assign(installInvariant, { inject: installer.inject })); + try { + await child; + } catch (error) { + await child.dispose(); + throw error; + } + return async () => { + try { + await child.dispose(); + } finally { + registrations.delete(packageName); + } + }; + } catch (error) { + registrations.delete(packageName); + throw error; + } + }, `invariants.register(${JSON.stringify(packageName)})`); + } catch (error) { + registrations.delete(packageName); + throw error; + } + return registration; + } +}; +//#endregion +export { InvariantError, InvariantRegistry, InvariantRegistry as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/invariant.js new file mode 100644 index 0000000..ed30af2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-invariants`. +* @module @deepseek-ai/dsh-invariants/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-invariants"; +/** Cordis companion plugin name. */ +const name = "invariants-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: registration ownership and child lifecycle are the service's mutation +* boundary itself; observing them from the same registry would only duplicate its implementation. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/index.d.ts new file mode 100644 index 0000000..6e8d23e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/index.d.ts @@ -0,0 +1,83 @@ +/** + * Configurable registry for package-owned runtime invariant contributions. + * Every workspace package registers checks from a `./invariant` companion; + * ordinary package entrypoints stay independent of diagnostics. + * + * @module @deepseek-ai/dsh-invariants + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { Inject } from '@deepseek-ai/cordis'; +import type Schema from '@deepseek-ai/schemastery'; +/** Runtime invariant selection configured on the service plugin. */ +export interface Config { + /** Global switch; defaults to `true`. */ + readonly enabled?: boolean; + /** Case-sensitive JavaScript regex sources that admit package names; empty admits all. */ + readonly package_allowlist?: string[]; + /** Case-sensitive JavaScript regex sources that exclude package names after allowlist matching. */ + readonly package_blocklist?: string[]; +} +/** + * Throw a package-attributed invariant failure. + * @param message - violated package contract without the standard prefix. + * @returns never because reporting a violation throws. + */ +export type InvariantFailure = (message: string) => never; +/** Install one package's checks into the registration's child context. */ +export interface InvariantInstaller { + /** + * Install the package contribution. + * @param ctx - child context owned by this invariant registration. + * @param fail - reporter bound to the registering package name. + * @returns nothing, or a promise settling after asynchronous checks finish. + */ + (ctx: Context, fail: InvariantFailure): void | Promise; + /** Services the child installer fiber may access. */ + readonly inject?: Inject; +} +/** Thrown when a package-owned runtime invariant is violated. */ +export declare class InvariantError extends Error { + /** Stable machine-readable invariant failure code. */ + readonly code: "INVARIANT"; + /** Full npm package name that owns the violated invariant. */ + readonly packageName: string; + /** + * Construct a package-attributed invariant failure. + * @param packageName - full npm package name that registered the check. + * @param message - violated contract, without the standard error prefix. + */ + constructor(packageName: string, message: string); +} +declare module '@deepseek-ai/cordis' { + interface Context { + invariants: InvariantRegistry; + } +} +/** Package-owned invariant registry with global and regex-based selection. */ +export declare class InvariantRegistry extends Service { + static Config: Schema; + private readonly enabled; + private readonly ownerCtx; + private readonly packageAllowlist; + private readonly packageBlocklist; + private readonly registrations; + /** + * Create and install the invariant registry. + * @param ctx - Cordis context that owns the service. + * @param config - global enablement and package-name regex filters. + */ + constructor(ctx: Context, config?: Config); + /** Return whether one full package name passes the configured filters. */ + private selected; + /** + * Register one package's invariant installer. The package name is reserved + * even when filtering disables its checks. Enabled installers run in a child + * fiber; failure disposes that fiber and releases the reservation. + * @param packageName - full npm package name that owns the contribution. + * @param installer - listener or startup-check installer for the child context. + * @returns an effect-scoped disposer for the registration. + */ + register(packageName: string, installer: InvariantInstaller): () => void; +} +export default InvariantRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/invariant.d.ts new file mode 100644 index 0000000..adc4b40 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-invariants`. + * @module @deepseek-ai/dsh-invariants/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "invariants-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/package.json new file mode 100644 index 0000000..c9840d1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants/package.json @@ -0,0 +1,43 @@ +{ + "name": "@deepseek-ai/dsh-invariants", + "description": "Registry service for package-owned DeepSeek Harness runtime invariants", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/runtime-diagnostics/invariants" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.i18n.yaml new file mode 100644 index 0000000..0473d97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/jobs/jobs/README.md +README.md: f4469286603f687be5789bd016ab462dba26e664 +README.zh.md: 30d8e4cb1e298bb4a3a0a3e65bb0858b2458a277 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.md new file mode 100644 index 0000000..f446928 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.md @@ -0,0 +1,40 @@ +# @deepseek-ai/dsh-jobs + +English | [中文](README.zh.md) + +The background job registry contract (`ctx.jobs`). The abstract `JobRegistry` and its vocabulary types give long-running producers shared ids, owner isolation, reads, cancellation, waiting, notices, and cleanup under one contract; the process-local registry lives in [`dsh-jobs-local`](../jobs-local/README.md). Producer plugins extend `JobKindMap` with their opaque id namespace. + +## Service contract + +- `start(spec): JobId` validates the attached controller, spec, exact live owner, optional positive `outputLimitBytes`, and any provider-owned admission policy before calling the producer's `run()` once. A preflight rejection or starter throw leaves no job id or registered work; successful return commits without another failable step. +- `get(id, caller?)` and `list(caller?)` return non-consuming snapshots. Listing includes only caller-owned and unowned jobs. +- `read(id, caller?)` consumes the single cursor for stream jobs and reads terminal output idempotently for final-output jobs. +- `kill(id, caller?, reason?)` invokes producer cancellation before changing status. A cancellation throw leaves the job running; success changes it to `stopping` and marks terminal delivery reported. +- `wait(id, timeoutMs, caller?, signal?)` returns a terminal snapshot or the live snapshot at timeout. Aborting stops only the wait; settlement wins once it has committed terminal delivery to that waiter. +- `onJobDone(listener)` observes each terminal record with the exact owner. Listener throws and rejections are contained; listener work is not awaited. +- `onJobsChanged(listener)` observes visible-set changes — registration, every stopping transition (teardown's included, before it awaits a slow producer), settlement, owner-disposal removal, and the emptying service disposal commits — carrying only the owner whose set moved, or `undefined` when an unowned job changed and every caller's set moved with it. It is owner-granular because removal is a change no per-job record can express, and it is not a superset of `onJobDone`: it carries no delivery meaning and marks nothing reported. The registration binds to the calling fiber, so an observer mounted outside the registry still sees the disposal emptying. +- `attachController(name)` declares a job controller for its effect lifetime. `start()` fails before producer execution when no attached controller serves the spec's owner. + +All three registrations are owner-relative, because one registry serves every composition in the process. A controller or listener registered from an unscoped context serves every owner; one registered under an agent composition's scope serves exactly the agents composed under it. So a composition that loads no controller cannot start background work on the strength of another composition's controls, and one settlement notifies only the listeners its owner's composition registered. + +Owned access compares the job's `SessionId` with the caller's. Ids such as `bash-1` are predictable, so this fence is the boundary. Unowned jobs are open to callers and last until service disposal. + +`outputLimitBytes` is producer-owned model-presentation policy carried unchanged into snapshots. A controller applies it after adding status or notice metadata; the registry does not rewrite producer output or invent a default for producers that omit it. + +Implementations also owe the lifecycle semantics of the contract: registrations outlive producer and controller fibers, owner and service disposal cancel live work and await compliant producers, and settlement is first-wins — one terminal record, one round of contained listener notification, released waiters. + +See the [job type catalog](../../../docs/subsystems/jobs.md), the [runtime Agent Note](../../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md), and the [seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.md). + +## Model Experience + +Indirectly, through producer plugins and [`dsh-tool-jobs`](../tool-jobs/README.md), which render job ids, output, status, cancellation, and completion notices. + +#### KV Cache effect + +No direct invalidation; the named consumer owns any request-prefix changes. + +## Known Limitations and Deferred Work + +- **Stream output has one consuming cursor** — independent observers need a cursor or snapshot API. +- **Foreground work cannot be promoted** — producers choose foreground or background before starting. +- **The contract is in-process** — `JobStart.run()` passes callbacks and exact `Agent` objects; a durable or cross-process backend must reshape identity, restart, ownership, and observation semantics before it can implement this seam. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.zh.md new file mode 100644 index 0000000..30d8e4c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/README.zh.md @@ -0,0 +1,40 @@ +# @deepseek-ai/dsh-jobs + +[English](README.md) | 中文 + +后台任务注册表约定(`ctx.jobs`)。抽象的 `JobRegistry` 及其词汇类型在同一份约定下为长时间运行的生产方提供共享 id、owner 隔离、读取、取消、等待、通知和清理;进程局部注册表位于 [`dsh-jobs-local`](../jobs-local/README.md)。生产方插件使用其不透明 id namespace 扩展 `JobKindMap`。 + +## 服务约定 + +- `start(spec): JobId` 验证已附加的任务控制器、spec、确切且仍存活的 owner、可选的正数 `outputLimitBytes`,以及 Service Provider 所拥有的准入策略,然后只调用生产方的 `run()` 一次。预检拒绝或启动方抛出异常时都不会生成 job id 或注册工作;成功返回会直接提交,不再执行其他可能失败的步骤。 +- `get(id, caller?)` 和 `list(caller?)` 返回非消费式快照。列表只包含调用方拥有及无 owner 的任务。 +- `read(id, caller?)` 消费流任务的唯一游标;对于最终输出任务,则以幂等方式读取终止输出。 +- `kill(id, caller?, reason?)` 在更改状态前调用生产方取消。取消抛出异常时任务保持运行;成功则把状态改为 `stopping`,并将终止交付标记为已报告。 +- `wait(id, timeoutMs, caller?, signal?)` 返回终止快照,或在超时时返回存活快照。中止只会停止等待;一旦终止交付已向该等待方提交,终止结果优先。 +- `onJobDone(listener)` 观察每条终止记录及其精确 owner。监听器抛出的异常和产生的拒绝都会被隔离;系统不会等待监听器工作。 +- `onJobsChanged(listener)` 观察可见集合的变化——注册、每一次转入 stopping(包括 teardown 在等待缓慢生产者之前的那一次)、结算、owner 销毁时的移除,以及服务销毁提交的清空——只携带集合发生变化的那个 owner,或在无主任务变化、因而每个调用方的集合都随之变化时携带 `undefined`。它按 owner 分粒度,因为移除是任何逐任务记录都无法表达的变化;它也不是 `onJobDone` 的超集:它不含任何投递含义,也不把任何东西标为已上报。注册绑定的是调用方 fiber,因此挂在注册表之外的观察者仍能收到销毁时的清空。 +- `attachController(name)` 在其 effect 生命周期内声明任务控制器。当没有任何已附加的控制器服务于 spec 的所有者时,`start()` 会在生产方执行前失败。 + +这三类注册都是相对于所有者的,因为一个注册表要服务进程内的每一套组合。从不带 scope 的上下文注册的控制器或监听器服务于每个所有者;在某套 agent 组合的 scope 下注册的,则恰好服务于在该组合下组合出的 agent。因此,未加载任何控制器的组合无法借另一套组合的控制工具启动后台工作,而一次结算也只会通知其所有者所属组合注册的监听器。 + +有 owner 的访问会比较任务的 `SessionId` 与调用方。`bash-1` 等 id 可预测,因此这道隔离是安全边界。无 owner 的任务向调用方开放,并持续到服务 dispose(资源释放)为止。 + +`outputLimitBytes` 是生产方拥有的模型呈现策略,会原样携带到快照中。控制器在添加状态或通知元数据后应用它;注册表不会重写生产方输出,也不会为省略此字段的生产方虚构默认值。 + +实现还必须兑现约定的生命周期语义:注册的存续期长于生产方 fiber 与控制器 fiber,owner 释放和服务释放会取消仍在运行的工作并等待守约的生产方,结算遵循首次结果优先(一条终止记录、一轮异常受到隔离的监听器通知,然后释放等待方)。 + +参见[任务类型目录](../../../docs/subsystems/jobs.md)、[运行时 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md)和 [seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.md)。 + +## 模型体验 + +通过生产方插件和 [`dsh-tool-jobs`](../tool-jobs/README.md) 间接影响;它们会渲染 job id、输出、状态、取消和完成通知。 + +#### KV Cache 影响 + +不会直接导致 KV Cache 失效;请求前缀变更由上述消费方负责。 + +## 已知限制与暂缓事项 + +- **流输出只有一个消费游标**:独立观察者需要游标或快照 API。 +- **前台工作无法转为后台**:生产方在启动前选择前台或后台。 +- **约定是进程内的**:`JobStart.run()` 传入回调和确切的 `Agent` 对象;持久化或跨进程后端必须先重塑身份、重启、所有权与观察语义,才能实现此 seam。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/index.js new file mode 100644 index 0000000..e147062 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/index.js @@ -0,0 +1,65 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/brand.js +/** +* dsh-jobs' owned branded id, carried across the registry, the model-facing +* control surface, and the client wire. +* +* It lives in its own leaf because the package root and `./types` both reach +* `dsh-agent` through the owner and listener signatures, which a Client program +* cannot resolve even as a type. A browser-safe consumer imports the id here; +* `Branded` itself comes from the zero-dependency `@deepseek-ai/dsh-brand`. +* +* @module @deepseek-ai/dsh-jobs/brand +*/ +/** +* Brand a string as a {@link JobId}. +* @param id - the raw job-id string (the registry generates `-N`). +* @returns the same string, branded; no validation is performed. +*/ +function JobId(id) { + return id; +} +//#endregion +//#region lib/types/index.js +/** +* The background-job Service Definition (`ctx.jobs`). It owns the contract for +* job ids, session-scoped access, lifecycle state, completion listeners, and +* owner cleanup while producers retain their execution resources. The +* process-local registry lives in `@deepseek-ai/dsh-jobs-local`. +* @module @deepseek-ai/dsh-jobs +*/ +/** +* Abstract background job registry. Subclass, implement the abstract methods, +* and load the subclass as a plugin — it registers as `ctx.jobs` (one +* implementation per context; loading a second throws, which is cordis' +* standard duplicate-service behavior). +* +* Implementations must honor these semantics: +* - Registrations outlive producer and controller fibers. Owner and +* service disposal cancel live work and await compliant producers; a +* throwing teardown cancel force-fails only the record. Teardown +* cancellation also marks the record reported, because a record its owner +* is being destroyed for has no reader left. +* - Owned-job access is fenced by the owner's session id. Ids are +* predictable, so authorization — not secrecy — is the boundary. +* - Settlement is first-wins: one terminal record, released waiters, and one +* round of contained listener notification, even against a late producer +* outcome. Completion is announced last, after the record is committed and +* every other observer of the settlement has seen it, because a reporter +* may open a model turn synchronously. +* - {@link start} refuses work while no attached job controller serves the +* spec's owner, so a producer cannot start work that owner cannot collect +* or stop. One registry serves every composition in the process, so this +* question — and completion-listener delivery — is owner-relative rather +* than process-wide: registrations made from an unscoped context serve +* every owner, and registrations made under an agent composition's scope +* serve exactly the agents composed under it. +*/ +var JobRegistry = class JobRegistry extends Service { + constructor(ctx) { + if (new.target === JobRegistry) throw new Error("@deepseek-ai/dsh-jobs is the abstract job registry seam; load an implementation such as @deepseek-ai/dsh-jobs-local instead"); + super(ctx, "jobs"); + } +}; +//#endregion +export { JobId, JobRegistry, JobRegistry as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/invariant.js new file mode 100644 index 0000000..b716a73 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/invariant.js @@ -0,0 +1,40 @@ +//#region lib/types/invariant.js +/** Package-owned background-job snapshot invariants. @module @deepseek-ai/dsh-jobs/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-jobs"; +const TERMINAL_STATUSES = new Set([ + "completed", + "killed", + "failed" +]); +/** Cordis companion plugin name. */ +const name = "jobs-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Validate the cross-field relationships in one registry snapshot. */ +function validateSnapshot(snapshot, owner, fail) { + const id = String(snapshot.id); + const prefix = `${snapshot.kind}-`; + const ordinal = Number(id.slice(prefix.length)); + if (snapshot.kind.length === 0 || !id.startsWith(prefix) || !Number.isSafeInteger(ordinal) || ordinal < 1) fail(`job snapshot id ${JSON.stringify(id)} must be ${JSON.stringify(prefix)} followed by a positive ordinal`); + if (snapshot.label.length === 0) fail(`job ${JSON.stringify(id)} label must be non-empty`); + if (!Number.isSafeInteger(snapshot.startedAt) || snapshot.startedAt < 0) fail(`job ${JSON.stringify(id)} startedAt must be a non-negative epoch integer`); + if (TERMINAL_STATUSES.has(snapshot.status) !== (snapshot.finishedAt !== void 0)) fail(`job ${JSON.stringify(id)} finishedAt must be present exactly for a terminal status`); + if (snapshot.finishedAt !== void 0 && (!Number.isSafeInteger(snapshot.finishedAt) || snapshot.finishedAt < snapshot.startedAt)) fail(`job ${JSON.stringify(id)} finishedAt must be an epoch integer no earlier than startedAt`); + const expectedOwner = owner?.id; + if (snapshot.ownerSession !== expectedOwner) fail(`job ${JSON.stringify(id)} ownerSession does not match its completion owner`); +} +/** Install checks over current unowned records and every terminal snapshot. */ +const install = Object.assign((ctx, fail) => { + for (const snapshot of ctx.jobs.list()) validateSnapshot(snapshot, void 0, fail); + ctx.jobs.onJobDone((snapshot, owner) => { + validateSnapshot(snapshot, owner, fail); + }); +}, { inject: ["jobs"] }); +/** +* Register the job-registry invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.d.ts new file mode 100644 index 0000000..fba87fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.d.ts @@ -0,0 +1,24 @@ +/** + * dsh-jobs' owned branded id, carried across the registry, the model-facing + * control surface, and the client wire. + * + * It lives in its own leaf because the package root and `./types` both reach + * `dsh-agent` through the owner and listener signatures, which a Client program + * cannot resolve even as a type. A browser-safe consumer imports the id here; + * `Branded` itself comes from the zero-dependency `@deepseek-ai/dsh-brand`. + * + * @module @deepseek-ai/dsh-jobs/brand + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** + * Identifies a background job. The registry generates `-N`; predictable + * ids rely on owner authorization rather than secrecy. + */ +export type JobId = Branded<'JobId'>; +/** + * Brand a string as a {@link JobId}. + * @param id - the raw job-id string (the registry generates `-N`). + * @returns the same string, branded; no validation is performed. + */ +export declare function JobId(id: string): JobId; +//# sourceMappingURL=brand.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.js new file mode 100644 index 0000000..656b6bd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.js @@ -0,0 +1,20 @@ +/** + * dsh-jobs' owned branded id, carried across the registry, the model-facing + * control surface, and the client wire. + * + * It lives in its own leaf because the package root and `./types` both reach + * `dsh-agent` through the owner and listener signatures, which a Client program + * cannot resolve even as a type. A browser-safe consumer imports the id here; + * `Branded` itself comes from the zero-dependency `@deepseek-ai/dsh-brand`. + * + * @module @deepseek-ai/dsh-jobs/brand + */ +/** + * Brand a string as a {@link JobId}. + * @param id - the raw job-id string (the registry generates `-N`). + * @returns the same string, branded; no validation is performed. + */ +export function JobId(id) { + return id; +} +//# sourceMappingURL=brand.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.d.ts new file mode 100644 index 0000000..267d1a4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.d.ts @@ -0,0 +1,145 @@ +/** + * The background-job Service Definition (`ctx.jobs`). It owns the contract for + * job ids, session-scoped access, lifecycle state, completion listeners, and + * owner cleanup while producers retain their execution resources. The + * process-local registry lives in `@deepseek-ai/dsh-jobs-local`. + * @module @deepseek-ai/dsh-jobs + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { JobDoneListener, JobId, JobRead, JobSnapshot, JobStart, JobsChangedListener } from './types.ts'; +export { JobId } from './types.ts'; +export type { JobDoneListener, JobHooks, JobKind, JobKindMap, JobOutcome, JobRead, JobSnapshot, JobStart, JobStatus, JobsChangedListener, } from './types.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + jobs: JobRegistry; + } +} +/** + * Abstract background job registry. Subclass, implement the abstract methods, + * and load the subclass as a plugin — it registers as `ctx.jobs` (one + * implementation per context; loading a second throws, which is cordis' + * standard duplicate-service behavior). + * + * Implementations must honor these semantics: + * - Registrations outlive producer and controller fibers. Owner and + * service disposal cancel live work and await compliant producers; a + * throwing teardown cancel force-fails only the record. Teardown + * cancellation also marks the record reported, because a record its owner + * is being destroyed for has no reader left. + * - Owned-job access is fenced by the owner's session id. Ids are + * predictable, so authorization — not secrecy — is the boundary. + * - Settlement is first-wins: one terminal record, released waiters, and one + * round of contained listener notification, even against a late producer + * outcome. Completion is announced last, after the record is committed and + * every other observer of the settlement has seen it, because a reporter + * may open a model turn synchronously. + * - {@link start} refuses work while no attached job controller serves the + * spec's owner, so a producer cannot start work that owner cannot collect + * or stop. One registry serves every composition in the process, so this + * question — and completion-listener delivery — is owner-relative rather + * than process-wide: registrations made from an unscoped context serve + * every owner, and registrations made under an agent composition's scope + * serve exactly the agents composed under it. + */ +export declare abstract class JobRegistry extends Service { + constructor(ctx: Context); + /** + * Preflight access, validation, owner cleanup, and implementation-owned + * admission before starting and atomically registering work. Any preflight + * rejection leaves no job id or execution resource. A throwing starter + * leaves nothing registered; after it returns, registration cannot fail. + * Settlement records the outcome, notifies listeners, and releases waiters. + * @param spec - job identity, owner, and synchronous starter. + * @returns the registry-issued `-N` id. + */ + abstract start(spec: JobStart): JobId; + /** + * List caller-owned and unowned jobs in registration order without exposing + * another session's labels. + * @param caller - reading agent; a non-agent caller sees only unowned jobs. + * @returns fresh snapshots. + */ + abstract list(caller?: Agent): JobSnapshot[]; + /** + * Return a non-consuming snapshot without changing its read cursor or notice + * state. Throws for an unknown or foreign job. + * @param id - job to look up. + * @param caller - reading agent checked against the owner. + * @returns a fresh snapshot. + */ + abstract get(id: JobId, caller?: Agent): JobSnapshot; + /** + * Read the next stream delta, or the idempotent final output after settlement. + * A terminal read marks the job reported. Throws for an unknown or foreign + * job. + * @param id - job to read. + * @param caller - reading agent checked against the owner. + * @returns output text and the post-read snapshot. + */ + abstract read(id: JobId, caller?: Agent): JobRead; + /** + * Request cancellation, then mark the job stopping and reported. A producer + * throw propagates without changing job state. Throws for an unknown or + * foreign job. + * @param id - job to cancel. + * @param caller - killing agent checked against the owner. + * @param reason - logged reason forwarded to the producer. + * @returns `requested` for live work, otherwise `already-finished`. + */ + abstract kill(id: JobId, caller?: Agent, reason?: string): 'requested' | 'already-finished'; + /** + * Wait for settlement or timeout without cancelling the job. Caller abort + * rejects only while the job is live; after settlement the terminal + * snapshot wins so a notice suppressed for this waiter is still delivered. + * Throws for invalid, unknown, or foreign input. + * @param id - job to wait for. + * @param timeoutMs - positive finite wait bound in milliseconds. + * @param caller - waiting agent checked against the owner. + * @param signal - optional cancellation of the wait itself. + * @returns snapshot at settlement or timeout. + */ + abstract wait(id: JobId, timeoutMs: number, caller?: Agent, signal?: AbortSignal): Promise; + /** + * Register an effect-scoped completion listener. It receives the settlements + * of the owners its registering context's scope covers; each listener is + * contained; returned promises are observed but not awaited. No listener runs + * after service disposal. + * @param listener - receives each terminal snapshot and its exact owner. + * @returns disposer that unregisters the listener. + */ + abstract onJobDone(listener: JobDoneListener): () => void; + /** + /** + * Register an effect-scoped observer of visible-set changes. It fires after + * every commit that changes what {@link list} returns for that owner — + * registration, every stopping transition (including the one teardown + * performs before it awaits a slow producer), settlement, owner-disposal + * removal, and the emptying that service disposal commits — so an observer + * re-reads rather than accumulating deltas. + * + * Delivery is owner-relative on the same terms as {@link onJobDone}: an + * observer registered from an unscoped context — a host composition's own + * carrier — sees every owner, while one registered under an agent + * composition's scope sees exactly the agents composed under it. + * + * This is not a superset of {@link onJobDone}: that one delivers the terminal + * record under first-wins semantics a job controller couples to notice + * delivery, while this one carries no delivery meaning and marks nothing + * reported. Listeners are contained and never awaited. + * @param listener - receives the owner whose visible set changed, or + * `undefined` when an unowned job changed and every caller's set did. + * @returns disposer that unregisters the listener. + */ + abstract onJobsChanged(listener: JobsChangedListener): () => void; + /** + * Attach an effect-scoped controller that can read and stop jobs. It serves the + * owners its registering context's scope covers, and {@link start} refuses an + * owner no attached controller serves. + * @param name - diagnostic label; duplicate names remain independent. + * @returns disposer that detaches this controller. + */ + abstract attachController(name: string): () => void; +} +export default JobRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.js new file mode 100644 index 0000000..e498d0c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.js @@ -0,0 +1,49 @@ +/** + * The background-job Service Definition (`ctx.jobs`). It owns the contract for + * job ids, session-scoped access, lifecycle state, completion listeners, and + * owner cleanup while producers retain their execution resources. The + * process-local registry lives in `@deepseek-ai/dsh-jobs-local`. + * @module @deepseek-ai/dsh-jobs + */ +import { Service } from '@deepseek-ai/cordis'; +export { JobId } from "./types.js"; +/** + * Abstract background job registry. Subclass, implement the abstract methods, + * and load the subclass as a plugin — it registers as `ctx.jobs` (one + * implementation per context; loading a second throws, which is cordis' + * standard duplicate-service behavior). + * + * Implementations must honor these semantics: + * - Registrations outlive producer and controller fibers. Owner and + * service disposal cancel live work and await compliant producers; a + * throwing teardown cancel force-fails only the record. Teardown + * cancellation also marks the record reported, because a record its owner + * is being destroyed for has no reader left. + * - Owned-job access is fenced by the owner's session id. Ids are + * predictable, so authorization — not secrecy — is the boundary. + * - Settlement is first-wins: one terminal record, released waiters, and one + * round of contained listener notification, even against a late producer + * outcome. Completion is announced last, after the record is committed and + * every other observer of the settlement has seen it, because a reporter + * may open a model turn synchronously. + * - {@link start} refuses work while no attached job controller serves the + * spec's owner, so a producer cannot start work that owner cannot collect + * or stop. One registry serves every composition in the process, so this + * question — and completion-listener delivery — is owner-relative rather + * than process-wide: registrations made from an unscoped context serve + * every owner, and registrations made under an agent composition's scope + * serve exactly the agents composed under it. + */ +export class JobRegistry extends Service { + constructor(ctx) { + // `abstract` erases at runtime, so a composition row naming this package + // would register a ctx.jobs with no method implementations and fail far + // from the misconfiguration. Fail loud at load instead. + if (new.target === JobRegistry) { + throw new Error('@deepseek-ai/dsh-jobs is the abstract job registry seam; load an implementation such as @deepseek-ai/dsh-jobs-local instead'); + } + super(ctx, 'jobs'); + } +} +export default JobRegistry; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.d.ts new file mode 100644 index 0000000..7e48486 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned background-job snapshot invariants. @module @deepseek-ai/dsh-jobs/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "jobs-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the job-registry invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.js new file mode 100644 index 0000000..bb54b67 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.js @@ -0,0 +1,47 @@ +/** Package-owned background-job snapshot invariants. @module @deepseek-ai/dsh-jobs/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-jobs'; +const TERMINAL_STATUSES = new Set(['completed', 'killed', 'failed']); +/** Cordis companion plugin name. */ +export const name = 'jobs-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Validate the cross-field relationships in one registry snapshot. */ +function validateSnapshot(snapshot, owner, fail) { + const id = String(snapshot.id); + const prefix = `${snapshot.kind}-`; + const ordinal = Number(id.slice(prefix.length)); + if (snapshot.kind.length === 0 || !id.startsWith(prefix) + || !Number.isSafeInteger(ordinal) || ordinal < 1) { + fail(`job snapshot id ${JSON.stringify(id)} must be ${JSON.stringify(prefix)} followed by a positive ordinal`); + } + if (snapshot.label.length === 0) + fail(`job ${JSON.stringify(id)} label must be non-empty`); + if (!Number.isSafeInteger(snapshot.startedAt) || snapshot.startedAt < 0) { + fail(`job ${JSON.stringify(id)} startedAt must be a non-negative epoch integer`); + } + const terminal = TERMINAL_STATUSES.has(snapshot.status); + if (terminal !== (snapshot.finishedAt !== undefined)) { + fail(`job ${JSON.stringify(id)} finishedAt must be present exactly for a terminal status`); + } + if (snapshot.finishedAt !== undefined + && (!Number.isSafeInteger(snapshot.finishedAt) || snapshot.finishedAt < snapshot.startedAt)) { + fail(`job ${JSON.stringify(id)} finishedAt must be an epoch integer no earlier than startedAt`); + } + const expectedOwner = owner?.id; + if (snapshot.ownerSession !== expectedOwner) { + fail(`job ${JSON.stringify(id)} ownerSession does not match its completion owner`); + } +} +/** Install checks over current unowned records and every terminal snapshot. */ +const install = Object.assign((ctx, fail) => { + for (const snapshot of ctx.jobs.list()) + validateSnapshot(snapshot, undefined, fail); + ctx.jobs.onJobDone((snapshot, owner) => { validateSnapshot(snapshot, owner, fail); }); +}, { inject: ['jobs'] }); +/** + * Register the job-registry invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.d.ts new file mode 100644 index 0000000..b070dd9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.d.ts @@ -0,0 +1,146 @@ +/** + * Types shared by job producers, the registry, and controllers. The + * service implementation lives in `./index.ts`. + * @module @deepseek-ai/dsh-jobs/types + */ +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +import type { JobId } from './brand.ts'; +export { JobId } from './brand.ts'; +/** + * Task lifecycle: `running`, optionally `stopping`, then exactly one terminal + * status. Producer-specific facts belong in {@link JobSnapshot.detail}. + */ +export type JobStatus = 'running' | 'stopping' | 'completed' | 'killed' | 'failed'; +/** + * Producer-defined job kinds. Plugins extend this map by declaration merging; + * the registry treats every value as an opaque id namespace. + */ +export interface JobKindMap { + bash: 'bash'; + subagent: 'subagent'; +} +/** The merge-extensible union of registered producer kind names. */ +export type JobKind = JobKindMap[keyof JobKindMap]; +/** Terminal result supplied by a producer through {@link JobHooks.done}. */ +export interface JobOutcome { + /** How the job ended: finished (`completed`), cancelled (`killed`), or broke (`failed`). */ + status: 'completed' | 'killed' | 'failed'; + /** Kind-specific detail rendered into status lines ('exit code: 3', 'max-tokens'). */ + detail?: string; + /** Final output for jobs without `readOutput`; stream jobs leave it unset. */ + output?: string; +} +/** + * Producer declaration passed to {@link JobRegistry.start}. The runtime + * preflights access and cleanup before invoking {@link run}; the producer owns + * execution resources while the runtime owns identity and lifecycle state. + */ +export interface JobStart { + /** Producer kind — also the id prefix (`bash`, `subagent`, …). */ + kind: JobKind; + /** One-line model-facing label (the command; the delegation description). */ + label: string; + /** + * Optional UTF-8 byte cap for each complete model-facing completion notice or + * output read, including controller status metadata. + */ + outputLimitBytes?: number; + /** + * Owning live agent. Access is fenced by its session id, and agent disposal + * cancels and awaits the job. The instance must be the one currently + * registered under its agent id. Omitting the owner creates an unowned job, + * open to any caller until service disposal. + */ + owner?: Agent; + /** + * Start the work after preflight and synchronously return its hooks. Called + * once; a throw leaves nothing registered, and the producer must clean up any + * partially started resources. + */ + run(): JobHooks; +} +/** Hooks through which the runtime controls and observes producer work. */ +export interface JobHooks { + /** + * Request termination. Must be synchronous, idempotent, and eventually settle + * {@link done}; throws propagate. The optional reason is forwarded verbatim. + */ + cancel(reason?: string): void; + /** + * Resolves after the producer releases its resources, not merely when work + * finishes. Must not reject; the runtime converts a rejection to `failed`. + * If teardown cancellation throws, the runtime may force-fail only the + * registry record without claiming that the work stopped. + */ + done: Promise; + /** + * Consume output produced since the previous call. The producer formats + * truncation and spill notices. Absence marks a final-output-only job; each + * job has one consuming cursor. + */ + readOutput?(): string; +} +/** + * A read-only projection of one job, safe to hand to listeners and tools — + * a fresh object per call, never live registry state. + */ +export interface JobSnapshot { + /** The registry-issued id (`-N`). */ + id: JobId; + /** The producer kind the job was registered with. */ + kind: JobKind; + /** The producer-supplied one-line label. */ + label: string; + /** Producer-owned cap for complete model-facing notices and output reads. */ + outputLimitBytes?: number; + /** + * Owner session id used for authorization and correlation; absent for + * unowned jobs. Completion listeners receive the exact {@link Agent} + * separately through {@link JobDoneListener}. + */ + ownerSession?: SessionId; + /** Current lifecycle state. */ + status: JobStatus; + /** Kind-specific status detail, present once the producer supplied one (usually terminal). */ + detail?: string; + /** Epoch ms when the job was registered. */ + startedAt: number; + /** Epoch ms when the job settled; absent while `running`/`stopping`. */ + finishedAt?: number; + /** + * True when a kill, read, wait, or teardown cancel has reported or committed + * to report the terminal state. Completion reporters suppress redundant + * notices when set. Teardown claims it because the owner or service being + * destroyed leaves no reader: a reporter that opens a turn on notice would + * otherwise spend a model request per teardown layer. + */ + reported: boolean; +} +/** Output and post-read state returned by {@link JobRegistry.read}. */ +export interface JobRead { + /** + * Stream kinds: the consuming delta since the previous read. Final-output + * kinds: empty while live, the terminal {@link JobOutcome.output} (or + * empty) once settled — idempotent, never consumed. + */ + text: string; + /** The job's state at read time. */ + snapshot: JobSnapshot; +} +/** + * Completion callback with the exact owner supplied at start, or `undefined` + * for an unowned job. Returned promises are observed but not awaited. + */ +export type JobDoneListener = (snapshot: JobSnapshot, owner: Agent | undefined) => void | PromiseLike; +/** + * Observation callback for a change to what one owner's {@link JobRegistry.list} + * would return. It is owner-granular rather than job-granular because the + * change may be a removal, which no per-job record can express, and because + * its consumers re-read the whole visible set anyway. + * + * An `undefined` owner means an unowned job changed, so every caller's visible + * set changed with it. + */ +export type JobsChangedListener = (owner: Agent | undefined) => void; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.js new file mode 100644 index 0000000..e89acec --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Types shared by job producers, the registry, and controllers. The + * service implementation lives in `./index.ts`. + * @module @deepseek-ai/dsh-jobs/types + */ +export { JobId } from "./brand.js"; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/package.json new file mode 100644 index 0000000..75d46eb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs/package.json @@ -0,0 +1,53 @@ +{ + "name": "@deepseek-ai/dsh-jobs", + "description": "Background job registry (ctx.jobs) for the DeepSeek Harness — shared ids, owner isolation, polling, cancellation, and completion listeners for long-running tool work", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/jobs/jobs" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./brand": { + "types": "./lib/types/brand.d.ts", + "default": "./lib/types/brand.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.i18n.yaml new file mode 100644 index 0000000..0473d97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/jobs/jobs/README.md +README.md: f4469286603f687be5789bd016ab462dba26e664 +README.zh.md: 30d8e4cb1e298bb4a3a0a3e65bb0858b2458a277 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.md new file mode 100644 index 0000000..f446928 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.md @@ -0,0 +1,40 @@ +# @deepseek-ai/dsh-jobs + +English | [中文](README.zh.md) + +The background job registry contract (`ctx.jobs`). The abstract `JobRegistry` and its vocabulary types give long-running producers shared ids, owner isolation, reads, cancellation, waiting, notices, and cleanup under one contract; the process-local registry lives in [`dsh-jobs-local`](../jobs-local/README.md). Producer plugins extend `JobKindMap` with their opaque id namespace. + +## Service contract + +- `start(spec): JobId` validates the attached controller, spec, exact live owner, optional positive `outputLimitBytes`, and any provider-owned admission policy before calling the producer's `run()` once. A preflight rejection or starter throw leaves no job id or registered work; successful return commits without another failable step. +- `get(id, caller?)` and `list(caller?)` return non-consuming snapshots. Listing includes only caller-owned and unowned jobs. +- `read(id, caller?)` consumes the single cursor for stream jobs and reads terminal output idempotently for final-output jobs. +- `kill(id, caller?, reason?)` invokes producer cancellation before changing status. A cancellation throw leaves the job running; success changes it to `stopping` and marks terminal delivery reported. +- `wait(id, timeoutMs, caller?, signal?)` returns a terminal snapshot or the live snapshot at timeout. Aborting stops only the wait; settlement wins once it has committed terminal delivery to that waiter. +- `onJobDone(listener)` observes each terminal record with the exact owner. Listener throws and rejections are contained; listener work is not awaited. +- `onJobsChanged(listener)` observes visible-set changes — registration, every stopping transition (teardown's included, before it awaits a slow producer), settlement, owner-disposal removal, and the emptying service disposal commits — carrying only the owner whose set moved, or `undefined` when an unowned job changed and every caller's set moved with it. It is owner-granular because removal is a change no per-job record can express, and it is not a superset of `onJobDone`: it carries no delivery meaning and marks nothing reported. The registration binds to the calling fiber, so an observer mounted outside the registry still sees the disposal emptying. +- `attachController(name)` declares a job controller for its effect lifetime. `start()` fails before producer execution when no attached controller serves the spec's owner. + +All three registrations are owner-relative, because one registry serves every composition in the process. A controller or listener registered from an unscoped context serves every owner; one registered under an agent composition's scope serves exactly the agents composed under it. So a composition that loads no controller cannot start background work on the strength of another composition's controls, and one settlement notifies only the listeners its owner's composition registered. + +Owned access compares the job's `SessionId` with the caller's. Ids such as `bash-1` are predictable, so this fence is the boundary. Unowned jobs are open to callers and last until service disposal. + +`outputLimitBytes` is producer-owned model-presentation policy carried unchanged into snapshots. A controller applies it after adding status or notice metadata; the registry does not rewrite producer output or invent a default for producers that omit it. + +Implementations also owe the lifecycle semantics of the contract: registrations outlive producer and controller fibers, owner and service disposal cancel live work and await compliant producers, and settlement is first-wins — one terminal record, one round of contained listener notification, released waiters. + +See the [job type catalog](../../../docs/subsystems/jobs.md), the [runtime Agent Note](../../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md), and the [seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.md). + +## Model Experience + +Indirectly, through producer plugins and [`dsh-tool-jobs`](../tool-jobs/README.md), which render job ids, output, status, cancellation, and completion notices. + +#### KV Cache effect + +No direct invalidation; the named consumer owns any request-prefix changes. + +## Known Limitations and Deferred Work + +- **Stream output has one consuming cursor** — independent observers need a cursor or snapshot API. +- **Foreground work cannot be promoted** — producers choose foreground or background before starting. +- **The contract is in-process** — `JobStart.run()` passes callbacks and exact `Agent` objects; a durable or cross-process backend must reshape identity, restart, ownership, and observation semantics before it can implement this seam. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.zh.md new file mode 100644 index 0000000..30d8e4c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/README.zh.md @@ -0,0 +1,40 @@ +# @deepseek-ai/dsh-jobs + +[English](README.md) | 中文 + +后台任务注册表约定(`ctx.jobs`)。抽象的 `JobRegistry` 及其词汇类型在同一份约定下为长时间运行的生产方提供共享 id、owner 隔离、读取、取消、等待、通知和清理;进程局部注册表位于 [`dsh-jobs-local`](../jobs-local/README.md)。生产方插件使用其不透明 id namespace 扩展 `JobKindMap`。 + +## 服务约定 + +- `start(spec): JobId` 验证已附加的任务控制器、spec、确切且仍存活的 owner、可选的正数 `outputLimitBytes`,以及 Service Provider 所拥有的准入策略,然后只调用生产方的 `run()` 一次。预检拒绝或启动方抛出异常时都不会生成 job id 或注册工作;成功返回会直接提交,不再执行其他可能失败的步骤。 +- `get(id, caller?)` 和 `list(caller?)` 返回非消费式快照。列表只包含调用方拥有及无 owner 的任务。 +- `read(id, caller?)` 消费流任务的唯一游标;对于最终输出任务,则以幂等方式读取终止输出。 +- `kill(id, caller?, reason?)` 在更改状态前调用生产方取消。取消抛出异常时任务保持运行;成功则把状态改为 `stopping`,并将终止交付标记为已报告。 +- `wait(id, timeoutMs, caller?, signal?)` 返回终止快照,或在超时时返回存活快照。中止只会停止等待;一旦终止交付已向该等待方提交,终止结果优先。 +- `onJobDone(listener)` 观察每条终止记录及其精确 owner。监听器抛出的异常和产生的拒绝都会被隔离;系统不会等待监听器工作。 +- `onJobsChanged(listener)` 观察可见集合的变化——注册、每一次转入 stopping(包括 teardown 在等待缓慢生产者之前的那一次)、结算、owner 销毁时的移除,以及服务销毁提交的清空——只携带集合发生变化的那个 owner,或在无主任务变化、因而每个调用方的集合都随之变化时携带 `undefined`。它按 owner 分粒度,因为移除是任何逐任务记录都无法表达的变化;它也不是 `onJobDone` 的超集:它不含任何投递含义,也不把任何东西标为已上报。注册绑定的是调用方 fiber,因此挂在注册表之外的观察者仍能收到销毁时的清空。 +- `attachController(name)` 在其 effect 生命周期内声明任务控制器。当没有任何已附加的控制器服务于 spec 的所有者时,`start()` 会在生产方执行前失败。 + +这三类注册都是相对于所有者的,因为一个注册表要服务进程内的每一套组合。从不带 scope 的上下文注册的控制器或监听器服务于每个所有者;在某套 agent 组合的 scope 下注册的,则恰好服务于在该组合下组合出的 agent。因此,未加载任何控制器的组合无法借另一套组合的控制工具启动后台工作,而一次结算也只会通知其所有者所属组合注册的监听器。 + +有 owner 的访问会比较任务的 `SessionId` 与调用方。`bash-1` 等 id 可预测,因此这道隔离是安全边界。无 owner 的任务向调用方开放,并持续到服务 dispose(资源释放)为止。 + +`outputLimitBytes` 是生产方拥有的模型呈现策略,会原样携带到快照中。控制器在添加状态或通知元数据后应用它;注册表不会重写生产方输出,也不会为省略此字段的生产方虚构默认值。 + +实现还必须兑现约定的生命周期语义:注册的存续期长于生产方 fiber 与控制器 fiber,owner 释放和服务释放会取消仍在运行的工作并等待守约的生产方,结算遵循首次结果优先(一条终止记录、一轮异常受到隔离的监听器通知,然后释放等待方)。 + +参见[任务类型目录](../../../docs/subsystems/jobs.md)、[运行时 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md)和 [seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-26-job-registry-seam.md)。 + +## 模型体验 + +通过生产方插件和 [`dsh-tool-jobs`](../tool-jobs/README.md) 间接影响;它们会渲染 job id、输出、状态、取消和完成通知。 + +#### KV Cache 影响 + +不会直接导致 KV Cache 失效;请求前缀变更由上述消费方负责。 + +## 已知限制与暂缓事项 + +- **流输出只有一个消费游标**:独立观察者需要游标或快照 API。 +- **前台工作无法转为后台**:生产方在启动前选择前台或后台。 +- **约定是进程内的**:`JobStart.run()` 传入回调和确切的 `Agent` 对象;持久化或跨进程后端必须先重塑身份、重启、所有权与观察语义,才能实现此 seam。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/index.js new file mode 100644 index 0000000..e147062 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/index.js @@ -0,0 +1,65 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/brand.js +/** +* dsh-jobs' owned branded id, carried across the registry, the model-facing +* control surface, and the client wire. +* +* It lives in its own leaf because the package root and `./types` both reach +* `dsh-agent` through the owner and listener signatures, which a Client program +* cannot resolve even as a type. A browser-safe consumer imports the id here; +* `Branded` itself comes from the zero-dependency `@deepseek-ai/dsh-brand`. +* +* @module @deepseek-ai/dsh-jobs/brand +*/ +/** +* Brand a string as a {@link JobId}. +* @param id - the raw job-id string (the registry generates `-N`). +* @returns the same string, branded; no validation is performed. +*/ +function JobId(id) { + return id; +} +//#endregion +//#region lib/types/index.js +/** +* The background-job Service Definition (`ctx.jobs`). It owns the contract for +* job ids, session-scoped access, lifecycle state, completion listeners, and +* owner cleanup while producers retain their execution resources. The +* process-local registry lives in `@deepseek-ai/dsh-jobs-local`. +* @module @deepseek-ai/dsh-jobs +*/ +/** +* Abstract background job registry. Subclass, implement the abstract methods, +* and load the subclass as a plugin — it registers as `ctx.jobs` (one +* implementation per context; loading a second throws, which is cordis' +* standard duplicate-service behavior). +* +* Implementations must honor these semantics: +* - Registrations outlive producer and controller fibers. Owner and +* service disposal cancel live work and await compliant producers; a +* throwing teardown cancel force-fails only the record. Teardown +* cancellation also marks the record reported, because a record its owner +* is being destroyed for has no reader left. +* - Owned-job access is fenced by the owner's session id. Ids are +* predictable, so authorization — not secrecy — is the boundary. +* - Settlement is first-wins: one terminal record, released waiters, and one +* round of contained listener notification, even against a late producer +* outcome. Completion is announced last, after the record is committed and +* every other observer of the settlement has seen it, because a reporter +* may open a model turn synchronously. +* - {@link start} refuses work while no attached job controller serves the +* spec's owner, so a producer cannot start work that owner cannot collect +* or stop. One registry serves every composition in the process, so this +* question — and completion-listener delivery — is owner-relative rather +* than process-wide: registrations made from an unscoped context serve +* every owner, and registrations made under an agent composition's scope +* serve exactly the agents composed under it. +*/ +var JobRegistry = class JobRegistry extends Service { + constructor(ctx) { + if (new.target === JobRegistry) throw new Error("@deepseek-ai/dsh-jobs is the abstract job registry seam; load an implementation such as @deepseek-ai/dsh-jobs-local instead"); + super(ctx, "jobs"); + } +}; +//#endregion +export { JobId, JobRegistry, JobRegistry as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/invariant.js new file mode 100644 index 0000000..b716a73 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/invariant.js @@ -0,0 +1,40 @@ +//#region lib/types/invariant.js +/** Package-owned background-job snapshot invariants. @module @deepseek-ai/dsh-jobs/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-jobs"; +const TERMINAL_STATUSES = new Set([ + "completed", + "killed", + "failed" +]); +/** Cordis companion plugin name. */ +const name = "jobs-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Validate the cross-field relationships in one registry snapshot. */ +function validateSnapshot(snapshot, owner, fail) { + const id = String(snapshot.id); + const prefix = `${snapshot.kind}-`; + const ordinal = Number(id.slice(prefix.length)); + if (snapshot.kind.length === 0 || !id.startsWith(prefix) || !Number.isSafeInteger(ordinal) || ordinal < 1) fail(`job snapshot id ${JSON.stringify(id)} must be ${JSON.stringify(prefix)} followed by a positive ordinal`); + if (snapshot.label.length === 0) fail(`job ${JSON.stringify(id)} label must be non-empty`); + if (!Number.isSafeInteger(snapshot.startedAt) || snapshot.startedAt < 0) fail(`job ${JSON.stringify(id)} startedAt must be a non-negative epoch integer`); + if (TERMINAL_STATUSES.has(snapshot.status) !== (snapshot.finishedAt !== void 0)) fail(`job ${JSON.stringify(id)} finishedAt must be present exactly for a terminal status`); + if (snapshot.finishedAt !== void 0 && (!Number.isSafeInteger(snapshot.finishedAt) || snapshot.finishedAt < snapshot.startedAt)) fail(`job ${JSON.stringify(id)} finishedAt must be an epoch integer no earlier than startedAt`); + const expectedOwner = owner?.id; + if (snapshot.ownerSession !== expectedOwner) fail(`job ${JSON.stringify(id)} ownerSession does not match its completion owner`); +} +/** Install checks over current unowned records and every terminal snapshot. */ +const install = Object.assign((ctx, fail) => { + for (const snapshot of ctx.jobs.list()) validateSnapshot(snapshot, void 0, fail); + ctx.jobs.onJobDone((snapshot, owner) => { + validateSnapshot(snapshot, owner, fail); + }); +}, { inject: ["jobs"] }); +/** +* Register the job-registry invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.d.ts new file mode 100644 index 0000000..fba87fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.d.ts @@ -0,0 +1,24 @@ +/** + * dsh-jobs' owned branded id, carried across the registry, the model-facing + * control surface, and the client wire. + * + * It lives in its own leaf because the package root and `./types` both reach + * `dsh-agent` through the owner and listener signatures, which a Client program + * cannot resolve even as a type. A browser-safe consumer imports the id here; + * `Branded` itself comes from the zero-dependency `@deepseek-ai/dsh-brand`. + * + * @module @deepseek-ai/dsh-jobs/brand + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** + * Identifies a background job. The registry generates `-N`; predictable + * ids rely on owner authorization rather than secrecy. + */ +export type JobId = Branded<'JobId'>; +/** + * Brand a string as a {@link JobId}. + * @param id - the raw job-id string (the registry generates `-N`). + * @returns the same string, branded; no validation is performed. + */ +export declare function JobId(id: string): JobId; +//# sourceMappingURL=brand.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.js new file mode 100644 index 0000000..656b6bd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/brand.js @@ -0,0 +1,20 @@ +/** + * dsh-jobs' owned branded id, carried across the registry, the model-facing + * control surface, and the client wire. + * + * It lives in its own leaf because the package root and `./types` both reach + * `dsh-agent` through the owner and listener signatures, which a Client program + * cannot resolve even as a type. A browser-safe consumer imports the id here; + * `Branded` itself comes from the zero-dependency `@deepseek-ai/dsh-brand`. + * + * @module @deepseek-ai/dsh-jobs/brand + */ +/** + * Brand a string as a {@link JobId}. + * @param id - the raw job-id string (the registry generates `-N`). + * @returns the same string, branded; no validation is performed. + */ +export function JobId(id) { + return id; +} +//# sourceMappingURL=brand.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.d.ts new file mode 100644 index 0000000..267d1a4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.d.ts @@ -0,0 +1,145 @@ +/** + * The background-job Service Definition (`ctx.jobs`). It owns the contract for + * job ids, session-scoped access, lifecycle state, completion listeners, and + * owner cleanup while producers retain their execution resources. The + * process-local registry lives in `@deepseek-ai/dsh-jobs-local`. + * @module @deepseek-ai/dsh-jobs + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { JobDoneListener, JobId, JobRead, JobSnapshot, JobStart, JobsChangedListener } from './types.ts'; +export { JobId } from './types.ts'; +export type { JobDoneListener, JobHooks, JobKind, JobKindMap, JobOutcome, JobRead, JobSnapshot, JobStart, JobStatus, JobsChangedListener, } from './types.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + jobs: JobRegistry; + } +} +/** + * Abstract background job registry. Subclass, implement the abstract methods, + * and load the subclass as a plugin — it registers as `ctx.jobs` (one + * implementation per context; loading a second throws, which is cordis' + * standard duplicate-service behavior). + * + * Implementations must honor these semantics: + * - Registrations outlive producer and controller fibers. Owner and + * service disposal cancel live work and await compliant producers; a + * throwing teardown cancel force-fails only the record. Teardown + * cancellation also marks the record reported, because a record its owner + * is being destroyed for has no reader left. + * - Owned-job access is fenced by the owner's session id. Ids are + * predictable, so authorization — not secrecy — is the boundary. + * - Settlement is first-wins: one terminal record, released waiters, and one + * round of contained listener notification, even against a late producer + * outcome. Completion is announced last, after the record is committed and + * every other observer of the settlement has seen it, because a reporter + * may open a model turn synchronously. + * - {@link start} refuses work while no attached job controller serves the + * spec's owner, so a producer cannot start work that owner cannot collect + * or stop. One registry serves every composition in the process, so this + * question — and completion-listener delivery — is owner-relative rather + * than process-wide: registrations made from an unscoped context serve + * every owner, and registrations made under an agent composition's scope + * serve exactly the agents composed under it. + */ +export declare abstract class JobRegistry extends Service { + constructor(ctx: Context); + /** + * Preflight access, validation, owner cleanup, and implementation-owned + * admission before starting and atomically registering work. Any preflight + * rejection leaves no job id or execution resource. A throwing starter + * leaves nothing registered; after it returns, registration cannot fail. + * Settlement records the outcome, notifies listeners, and releases waiters. + * @param spec - job identity, owner, and synchronous starter. + * @returns the registry-issued `-N` id. + */ + abstract start(spec: JobStart): JobId; + /** + * List caller-owned and unowned jobs in registration order without exposing + * another session's labels. + * @param caller - reading agent; a non-agent caller sees only unowned jobs. + * @returns fresh snapshots. + */ + abstract list(caller?: Agent): JobSnapshot[]; + /** + * Return a non-consuming snapshot without changing its read cursor or notice + * state. Throws for an unknown or foreign job. + * @param id - job to look up. + * @param caller - reading agent checked against the owner. + * @returns a fresh snapshot. + */ + abstract get(id: JobId, caller?: Agent): JobSnapshot; + /** + * Read the next stream delta, or the idempotent final output after settlement. + * A terminal read marks the job reported. Throws for an unknown or foreign + * job. + * @param id - job to read. + * @param caller - reading agent checked against the owner. + * @returns output text and the post-read snapshot. + */ + abstract read(id: JobId, caller?: Agent): JobRead; + /** + * Request cancellation, then mark the job stopping and reported. A producer + * throw propagates without changing job state. Throws for an unknown or + * foreign job. + * @param id - job to cancel. + * @param caller - killing agent checked against the owner. + * @param reason - logged reason forwarded to the producer. + * @returns `requested` for live work, otherwise `already-finished`. + */ + abstract kill(id: JobId, caller?: Agent, reason?: string): 'requested' | 'already-finished'; + /** + * Wait for settlement or timeout without cancelling the job. Caller abort + * rejects only while the job is live; after settlement the terminal + * snapshot wins so a notice suppressed for this waiter is still delivered. + * Throws for invalid, unknown, or foreign input. + * @param id - job to wait for. + * @param timeoutMs - positive finite wait bound in milliseconds. + * @param caller - waiting agent checked against the owner. + * @param signal - optional cancellation of the wait itself. + * @returns snapshot at settlement or timeout. + */ + abstract wait(id: JobId, timeoutMs: number, caller?: Agent, signal?: AbortSignal): Promise; + /** + * Register an effect-scoped completion listener. It receives the settlements + * of the owners its registering context's scope covers; each listener is + * contained; returned promises are observed but not awaited. No listener runs + * after service disposal. + * @param listener - receives each terminal snapshot and its exact owner. + * @returns disposer that unregisters the listener. + */ + abstract onJobDone(listener: JobDoneListener): () => void; + /** + /** + * Register an effect-scoped observer of visible-set changes. It fires after + * every commit that changes what {@link list} returns for that owner — + * registration, every stopping transition (including the one teardown + * performs before it awaits a slow producer), settlement, owner-disposal + * removal, and the emptying that service disposal commits — so an observer + * re-reads rather than accumulating deltas. + * + * Delivery is owner-relative on the same terms as {@link onJobDone}: an + * observer registered from an unscoped context — a host composition's own + * carrier — sees every owner, while one registered under an agent + * composition's scope sees exactly the agents composed under it. + * + * This is not a superset of {@link onJobDone}: that one delivers the terminal + * record under first-wins semantics a job controller couples to notice + * delivery, while this one carries no delivery meaning and marks nothing + * reported. Listeners are contained and never awaited. + * @param listener - receives the owner whose visible set changed, or + * `undefined` when an unowned job changed and every caller's set did. + * @returns disposer that unregisters the listener. + */ + abstract onJobsChanged(listener: JobsChangedListener): () => void; + /** + * Attach an effect-scoped controller that can read and stop jobs. It serves the + * owners its registering context's scope covers, and {@link start} refuses an + * owner no attached controller serves. + * @param name - diagnostic label; duplicate names remain independent. + * @returns disposer that detaches this controller. + */ + abstract attachController(name: string): () => void; +} +export default JobRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.js new file mode 100644 index 0000000..e498d0c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/index.js @@ -0,0 +1,49 @@ +/** + * The background-job Service Definition (`ctx.jobs`). It owns the contract for + * job ids, session-scoped access, lifecycle state, completion listeners, and + * owner cleanup while producers retain their execution resources. The + * process-local registry lives in `@deepseek-ai/dsh-jobs-local`. + * @module @deepseek-ai/dsh-jobs + */ +import { Service } from '@deepseek-ai/cordis'; +export { JobId } from "./types.js"; +/** + * Abstract background job registry. Subclass, implement the abstract methods, + * and load the subclass as a plugin — it registers as `ctx.jobs` (one + * implementation per context; loading a second throws, which is cordis' + * standard duplicate-service behavior). + * + * Implementations must honor these semantics: + * - Registrations outlive producer and controller fibers. Owner and + * service disposal cancel live work and await compliant producers; a + * throwing teardown cancel force-fails only the record. Teardown + * cancellation also marks the record reported, because a record its owner + * is being destroyed for has no reader left. + * - Owned-job access is fenced by the owner's session id. Ids are + * predictable, so authorization — not secrecy — is the boundary. + * - Settlement is first-wins: one terminal record, released waiters, and one + * round of contained listener notification, even against a late producer + * outcome. Completion is announced last, after the record is committed and + * every other observer of the settlement has seen it, because a reporter + * may open a model turn synchronously. + * - {@link start} refuses work while no attached job controller serves the + * spec's owner, so a producer cannot start work that owner cannot collect + * or stop. One registry serves every composition in the process, so this + * question — and completion-listener delivery — is owner-relative rather + * than process-wide: registrations made from an unscoped context serve + * every owner, and registrations made under an agent composition's scope + * serve exactly the agents composed under it. + */ +export class JobRegistry extends Service { + constructor(ctx) { + // `abstract` erases at runtime, so a composition row naming this package + // would register a ctx.jobs with no method implementations and fail far + // from the misconfiguration. Fail loud at load instead. + if (new.target === JobRegistry) { + throw new Error('@deepseek-ai/dsh-jobs is the abstract job registry seam; load an implementation such as @deepseek-ai/dsh-jobs-local instead'); + } + super(ctx, 'jobs'); + } +} +export default JobRegistry; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.d.ts new file mode 100644 index 0000000..7e48486 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned background-job snapshot invariants. @module @deepseek-ai/dsh-jobs/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "jobs-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the job-registry invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.js new file mode 100644 index 0000000..bb54b67 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/invariant.js @@ -0,0 +1,47 @@ +/** Package-owned background-job snapshot invariants. @module @deepseek-ai/dsh-jobs/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-jobs'; +const TERMINAL_STATUSES = new Set(['completed', 'killed', 'failed']); +/** Cordis companion plugin name. */ +export const name = 'jobs-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Validate the cross-field relationships in one registry snapshot. */ +function validateSnapshot(snapshot, owner, fail) { + const id = String(snapshot.id); + const prefix = `${snapshot.kind}-`; + const ordinal = Number(id.slice(prefix.length)); + if (snapshot.kind.length === 0 || !id.startsWith(prefix) + || !Number.isSafeInteger(ordinal) || ordinal < 1) { + fail(`job snapshot id ${JSON.stringify(id)} must be ${JSON.stringify(prefix)} followed by a positive ordinal`); + } + if (snapshot.label.length === 0) + fail(`job ${JSON.stringify(id)} label must be non-empty`); + if (!Number.isSafeInteger(snapshot.startedAt) || snapshot.startedAt < 0) { + fail(`job ${JSON.stringify(id)} startedAt must be a non-negative epoch integer`); + } + const terminal = TERMINAL_STATUSES.has(snapshot.status); + if (terminal !== (snapshot.finishedAt !== undefined)) { + fail(`job ${JSON.stringify(id)} finishedAt must be present exactly for a terminal status`); + } + if (snapshot.finishedAt !== undefined + && (!Number.isSafeInteger(snapshot.finishedAt) || snapshot.finishedAt < snapshot.startedAt)) { + fail(`job ${JSON.stringify(id)} finishedAt must be an epoch integer no earlier than startedAt`); + } + const expectedOwner = owner?.id; + if (snapshot.ownerSession !== expectedOwner) { + fail(`job ${JSON.stringify(id)} ownerSession does not match its completion owner`); + } +} +/** Install checks over current unowned records and every terminal snapshot. */ +const install = Object.assign((ctx, fail) => { + for (const snapshot of ctx.jobs.list()) + validateSnapshot(snapshot, undefined, fail); + ctx.jobs.onJobDone((snapshot, owner) => { validateSnapshot(snapshot, owner, fail); }); +}, { inject: ['jobs'] }); +/** + * Register the job-registry invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.d.ts new file mode 100644 index 0000000..b070dd9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.d.ts @@ -0,0 +1,146 @@ +/** + * Types shared by job producers, the registry, and controllers. The + * service implementation lives in `./index.ts`. + * @module @deepseek-ai/dsh-jobs/types + */ +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +import type { JobId } from './brand.ts'; +export { JobId } from './brand.ts'; +/** + * Task lifecycle: `running`, optionally `stopping`, then exactly one terminal + * status. Producer-specific facts belong in {@link JobSnapshot.detail}. + */ +export type JobStatus = 'running' | 'stopping' | 'completed' | 'killed' | 'failed'; +/** + * Producer-defined job kinds. Plugins extend this map by declaration merging; + * the registry treats every value as an opaque id namespace. + */ +export interface JobKindMap { + bash: 'bash'; + subagent: 'subagent'; +} +/** The merge-extensible union of registered producer kind names. */ +export type JobKind = JobKindMap[keyof JobKindMap]; +/** Terminal result supplied by a producer through {@link JobHooks.done}. */ +export interface JobOutcome { + /** How the job ended: finished (`completed`), cancelled (`killed`), or broke (`failed`). */ + status: 'completed' | 'killed' | 'failed'; + /** Kind-specific detail rendered into status lines ('exit code: 3', 'max-tokens'). */ + detail?: string; + /** Final output for jobs without `readOutput`; stream jobs leave it unset. */ + output?: string; +} +/** + * Producer declaration passed to {@link JobRegistry.start}. The runtime + * preflights access and cleanup before invoking {@link run}; the producer owns + * execution resources while the runtime owns identity and lifecycle state. + */ +export interface JobStart { + /** Producer kind — also the id prefix (`bash`, `subagent`, …). */ + kind: JobKind; + /** One-line model-facing label (the command; the delegation description). */ + label: string; + /** + * Optional UTF-8 byte cap for each complete model-facing completion notice or + * output read, including controller status metadata. + */ + outputLimitBytes?: number; + /** + * Owning live agent. Access is fenced by its session id, and agent disposal + * cancels and awaits the job. The instance must be the one currently + * registered under its agent id. Omitting the owner creates an unowned job, + * open to any caller until service disposal. + */ + owner?: Agent; + /** + * Start the work after preflight and synchronously return its hooks. Called + * once; a throw leaves nothing registered, and the producer must clean up any + * partially started resources. + */ + run(): JobHooks; +} +/** Hooks through which the runtime controls and observes producer work. */ +export interface JobHooks { + /** + * Request termination. Must be synchronous, idempotent, and eventually settle + * {@link done}; throws propagate. The optional reason is forwarded verbatim. + */ + cancel(reason?: string): void; + /** + * Resolves after the producer releases its resources, not merely when work + * finishes. Must not reject; the runtime converts a rejection to `failed`. + * If teardown cancellation throws, the runtime may force-fail only the + * registry record without claiming that the work stopped. + */ + done: Promise; + /** + * Consume output produced since the previous call. The producer formats + * truncation and spill notices. Absence marks a final-output-only job; each + * job has one consuming cursor. + */ + readOutput?(): string; +} +/** + * A read-only projection of one job, safe to hand to listeners and tools — + * a fresh object per call, never live registry state. + */ +export interface JobSnapshot { + /** The registry-issued id (`-N`). */ + id: JobId; + /** The producer kind the job was registered with. */ + kind: JobKind; + /** The producer-supplied one-line label. */ + label: string; + /** Producer-owned cap for complete model-facing notices and output reads. */ + outputLimitBytes?: number; + /** + * Owner session id used for authorization and correlation; absent for + * unowned jobs. Completion listeners receive the exact {@link Agent} + * separately through {@link JobDoneListener}. + */ + ownerSession?: SessionId; + /** Current lifecycle state. */ + status: JobStatus; + /** Kind-specific status detail, present once the producer supplied one (usually terminal). */ + detail?: string; + /** Epoch ms when the job was registered. */ + startedAt: number; + /** Epoch ms when the job settled; absent while `running`/`stopping`. */ + finishedAt?: number; + /** + * True when a kill, read, wait, or teardown cancel has reported or committed + * to report the terminal state. Completion reporters suppress redundant + * notices when set. Teardown claims it because the owner or service being + * destroyed leaves no reader: a reporter that opens a turn on notice would + * otherwise spend a model request per teardown layer. + */ + reported: boolean; +} +/** Output and post-read state returned by {@link JobRegistry.read}. */ +export interface JobRead { + /** + * Stream kinds: the consuming delta since the previous read. Final-output + * kinds: empty while live, the terminal {@link JobOutcome.output} (or + * empty) once settled — idempotent, never consumed. + */ + text: string; + /** The job's state at read time. */ + snapshot: JobSnapshot; +} +/** + * Completion callback with the exact owner supplied at start, or `undefined` + * for an unowned job. Returned promises are observed but not awaited. + */ +export type JobDoneListener = (snapshot: JobSnapshot, owner: Agent | undefined) => void | PromiseLike; +/** + * Observation callback for a change to what one owner's {@link JobRegistry.list} + * would return. It is owner-granular rather than job-granular because the + * change may be a removal, which no per-job record can express, and because + * its consumers re-read the whole visible set anyway. + * + * An `undefined` owner means an unowned job changed, so every caller's visible + * set changed with it. + */ +export type JobsChangedListener = (owner: Agent | undefined) => void; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.js new file mode 100644 index 0000000..e89acec --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Types shared by job producers, the registry, and controllers. The + * service implementation lives in `./index.ts`. + * @module @deepseek-ai/dsh-jobs/types + */ +export { JobId } from "./brand.js"; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/package.json new file mode 100644 index 0000000..efccea4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs/package.json @@ -0,0 +1,53 @@ +{ + "name": "@deepseek-ai/dsh-jobs", + "description": "Background job registry (ctx.jobs) for the DeepSeek Harness — shared ids, owner isolation, polling, cancellation, and completion listeners for long-running tool work", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/jobs/jobs" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./brand": { + "types": "./lib/types/brand.d.ts", + "default": "./lib/types/brand.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-attachment b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-attachment new file mode 120000 index 0000000..ad086eb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-attachment @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-attachment@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_5463d1d16dfeb8cbf43fe361fb2eba74/node_modules/@deepseek-ai/dsh-attachment \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.i18n.yaml new file mode 100644 index 0000000..2d0d68e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/llm/llm/README.md +README.md: 2cae9a05a58295b06d25382729a3304dbdc9a6fa +README.zh.md: 110cc128f1c19bef1741ae59d8106139c4a72649 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.md new file mode 100644 index 0000000..2cae9a0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.md @@ -0,0 +1,101 @@ +# dsh-llm + +English | [中文](README.zh.md) + +Provider-neutral LLM vocabulary and abstract service. This package defines the canonical language spoken by the agent loop, session logs, and every plugin. + +## Service: `LlmRuntime` (ctx key: `llm`) + +An adapter registry plus a single streaming call API, interceptable via a waterfall event. + +### Public API + +- `ctx.llm.registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHandle` Register one adapter instance for the given provider routes. Registration is all-or-nothing, and is disposed with the calling fiber. The returned disposer also carries `replace(providers)`: the candidate route set is validated in full before anything moves, so a conflict with another adapter leaves the current routes registered and serving, and the swap itself is one synchronous section with no observable gap. `replace([])` is legal — a registration holding zero routes — unlike an empty initial registration. +- `ctx.llm.listProviders(): LlmProviderInfo[]` Describe registered provider routes in registration order. +- `ctx.llm.registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): DirectoryRegistrationHandle` Declare provider routes an adapter plugin can activate through configuration — registered or dormant — each naming its owning settings namespace and the path to its profile inside that section. All-or-nothing (`INVALID_DIRECTORY`/`DUPLICATE_DIRECTORY`), disposed with the calling fiber. The handle also carries `replace(entries)`: the candidate set is validated in full before anything moves, so an entry another registration already declares leaves the current set intact, and an empty array is legal there. A plugin whose declared set follows its configuration must use `replace` rather than disposing and re-registering — the latter strands the directory empty whenever the new set is refused. +- `ctx.llm.listConfigurableProviders(): LlmConfigurableProvider[]` List the declared directory in declaration order; configuration surfaces merge it with `listProviders()` to mark each entry live or dormant. An entry may carry `declared` — whether the owning adapter knows that route only because configuration named it. Only the adapter can answer, so absence means "this adapter draws no such distinction", never "shipped". +- `ctx.llm.registerModelDiscovery(settingsNs: string, discover): () => void` Offer to interrogate provider endpoints for the settings namespace this plugin owns. One offer per namespace (`INVALID_DISCOVERY`/`DUPLICATE_DISCOVERY`), disposed with the calling fiber. +- `ctx.llm.listModelDiscoveryNamespaces(): string[]` List the namespaces that can interrogate an endpoint, so a surface offers the action only where it works. +- `ctx.llm.discoverModels(settingsNs: string, request: LlmModelDiscoveryRequest): Promise` Ask one endpoint which models it advertises. +- `ctx.llm.providerRetryPolicy(provider: string): ResolvedRetryPolicy` Return the provider-owned retry policy captured during registration, with normal defaults resolved. +- `ctx.llm.listModels(provider: string): Promise` Discover the models one registered provider currently advertises. +- `ctx.llm.resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise` Resolve validated exact-model identity plus available context, output-default, and reasoning metadata from the owning adapter, with optional cancellation for asynchronous adapters. +- `ctx.llm.resolveCallConfig(config: LlmCallConfig, signal?: AbortSignal): Promise` Validate an explicit effort and materialize adapter-configured call defaults without clamping. +- `ctx.llm.prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise` Resolve a config plus detached context metadata and markers for fields supplied by adapter defaults in one exact-model lookup, then capture its current adapter registration and immutable retry policy as one cancellable, one-shot call. +- `ctx.llm.stream(options: GenerateOptions): AsyncIterable` Stream one model call as raw chunks (token-level deltas). Consumers assemble the chunks into blocks/messages with `BlockAssembler`. + +`LlmRuntime` normalizes failures from final adapter selection, synchronous dispatch, iterator construction, and iteration into the stream protocol's single terminal form: `finish { kind: 'error' | 'aborted', failure }`. A failure after partial deltas may leave content blocks open; consumers discard that incomplete output. Errors from `llm/stream` middleware, nested calls, adapter cleanup, and downstream consumers remain thrown because they are plugin or consumer failures rather than model-request outcomes. A prepared call exposes the immutable retry policy captured with its exact adapter registration; a route handled entirely by middleware has no serving policy. + +Interrogating an endpoint is configuration-time work over a *draft*, keyed by settings namespace rather than by provider route — the provider a surface is adding does not exist yet, so there is no route to name. The request may still *name* a route it is editing, and an adapter that already describes that route answers from its own knowledge without a network call; `baseURL` is optional and one of the two is required. The request otherwise carries the endpoint, the protocol, and a credential the harness uses for that one interrogation and never stores — nothing here reads or writes settings or credentials, and the reply is candidate metadata a surface may offer for adoption, never a registered catalog. `LlmDiscoveredModel` makes every field but `id` optional because most provider listings disclose an id and nothing else; a surface adopting one still owes the capacities its adapter requires. Duplicate and unusable ids are dropped, an unserved namespace fails with `NO_DISCOVERY`, and a request naming neither a route nor an endpoint fails with `INVALID_DISCOVERY`. + +Provider and model metadata is a discovery surface, not a routing whitelist. `registerAdapter()` still owns provider exclusivity and captures the adapter's retry policy for each route, while an adapter may accept model ids absent from `listModels()`; consumers must not reject a request because its model is unlisted. Returned selector metadata is detached and invalid or duplicate adapter entries fail with `INVALID_ADAPTER` or `INVALID_CATALOG`. + +Every topology commit point — adapter routes registering or disposing, directory entries appearing or withdrawing — emits the payload-free `llm/adapters-updated` event after the mutation, so consumers re-read `listProviders()`/`listModels()`/`listConfigurableProviders()` instead of polling. Observer failures are contained (logged, non-vetoing); only `INVARIANT`-coded failures rethrow after the fan-out. + +Exact-model metadata is a separate correctness query, not a catalog decoration or global LLM setting. `resolveModelInfo()` asks the adapter that owns the exact provider/model route once; an adapter can describe an unlisted dynamic model, and absent `context`, `defaultMaxTokens`, or `reasoning` fields preserve unknown capacity, provider-owned output defaults, or unavailable reasoning capability. Invalid identity, context, output default, or reasoning metadata fails with `INVALID_MODEL_INFO`, `INVALID_MODEL_CONTEXT`, `INVALID_MODEL_MAX_TOKENS`, or `INVALID_MODEL_REASONING`. + +`defaultMaxTokens` is an adapter-configured per-request output cap, not a model hard limit. `resolveCallConfig()` materializes it only when the request omits `maxTokens`; an explicit cap wins. Reasoning identifiers are opaque adapter-owned strings rather than a core enum: the same resolution accepts only an exact advertised identifier, materializes `defaultEffort` when present, and otherwise preserves the provider default. Asynchronous model resolvers receive the caller's signal and must settle promptly after cancellation. `prepareCall()` additionally exposes detached context metadata from the same lookup, reports which `maxTokens` and `reasoningEffort` fields it materialized in `adapterDefaults`, and retains the exact adapter registration through header logging and terminal dispatch, so HMR cannot combine one adapter's capability result with another adapter's request; reusing its one-shot handle or changing its call-config fields fails with `INVALID_PREPARED_CALL`. An unsupported explicit or configured effort fails with `UNSUPPORTED_REASONING_EFFORT` before provider I/O. + +### Events + +| Event | Mode | Purpose | +|---|---|---| +| `llm/stream` | waterfall | Intercept/wrap every streaming model call for caching, logging, or routing | + +### Extension points + +- Subclass `LlmAdapter` and call `ctx.llm.registerAdapter(providers, adapter)` to add one or more provider routes. `GenerateOptions.provider` selects the adapter; `GenerateOptions.model` is adapter-owned and may be resolved dynamically. Override `providerRetryPolicy()` to supply provider-owned recovery configuration, `providerInfo()` and asynchronous `listModels()` to expose selector metadata, then implement `resolveModel()` when exact identity, capacity, an output default, or selectable reasoning efforts are available; an asynchronous resolver must honor its optional cancellation signal. The defaults use bounded normal retry policy, use the route and model ids as names, advertise no models, and return no capacity, output default, or reasoning metadata. +- Wrap `llm/stream` via `ctx.on()` waterfall listeners for caching, logging, or routing. A wrapper that retries after emitting a chunk has no durable attempt boundary; shipped agent retry policy therefore uses `agent/request-error` instead. + +### Messages (`message.ts`) and content blocks (`types.ts`) + +`Message` is the shared immutable value used by delivery, durable history, and model requests. Every message has a required `MessageId`, role, content, and typed source from creation onward. `createMessage(input)` mints the identity and returns a detached deep-frozen value; `createUserMessage({ content, source })` fixes the user role; `createAssistantMessage({ content, source })` fixes the assistant role and model source kind; `createToolResultMessage({ callId, content, isError })` fixes the user role and couples the tool source to its result block; `freezeMessage(message)` imports an identity that already exists and never replaces it. Message rewrites preserve the identity and produce another frozen value. Browser code imports these value constructors from the dependency-minimal `@deepseek-ai/dsh-llm/message` entry instead of the service-bearing package root. + +Message content is an array of typed blocks: `text`, `reasoning`, `tool-call`, `tool-result`. The union is derived from the merge-extensible `ContentBlockMap`, so plugins can add block types via declaration merging. Assistant messages use a model source carrying the provider and model that produced them plus optional adapter-private replay state. Before dispatch, `LlmRuntime` retains that state only when the historical provider route and target provider route are currently owned by the exact same adapter instance; the adapter then decides whether it can restore or convert the state across models/providers. The core block set is limited to blocks every shipping path honors — multimodal content (images, audio, …) has no core block type; a feature that needs one adds it via the map together with the adapter/UI/compaction support that honors it. + +Streaming is a raw chunk protocol (`block-start`, `text-delta`, `reasoning-delta`, `tool-call-delta`, `block-end`, `usage`, `finish`). Every adapter outcome reaches consumers as one terminal `finish`; operational failure uses its `error` or `aborted` reason rather than throwing across the stream API. `BlockAssembler` is the single shared implementation that assembles chunks into blocks/messages. + +### Call configuration (`call-config.ts`) + +`LlmCallConfig` is the provider, model, optional adapter-owned reasoning effort, and sampling scalars of one conversation's requests (`provider`, `model`, `reasoningEffort`, `temperature`, `maxTokens`, `stop` — each mapping 1:1 onto the same-named `GenerateOptions` field). It is per-conversation state recorded in the session log as part of the request header (see the dsh-session `request/header` events), never a silently-adjustable per-call knob: the `agent/request` waterfall proposes a replacement, `prepareCall()` validates it and materializes adapter defaults under the turn signal, and the loop logs the effective value plus markers for fields supplied by adapter defaults before using the prepared call's registration-bound stream. The next proposal omits marked defaults so a changed route resolves its own values; unmarked explicit fields persist. `callConfigEquals(a, b)` is the field-wise real-change detector; `deepFreeze(value)` is the ownership helper the loop applies to every built request before dispatch (`llm/stream` listeners and adapters read, never rewrite). `markAgentLoopRequest()` marks that exact object as created by the process-local agent loop, and `isAgentLoopRequest()` lets observers distinguish it from independently logged auxiliary calls that may also be frozen and session-associated. `GenerateOptions.purpose` classifies logged auxiliary compaction and session-title calls so adapters can apply purpose-specific transport policy without changing ordinary conversation requests. + +### App attribution (`attribution.ts`) + +Every product adapter sends application identity on provider HTTP requests. `attributionHeaders(identity?)` builds the standard `User-Agent`, defaulting to public `APP_IDENTITY`; white-label deployments may replace but not suppress it. Adapters verify the wire header directly or through their library hook. See [the attribution Agent Note](../../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md). + +### API key validation (`api-key.ts`) + +Every adapter that puts a credential in an HTTP header judges it the same way before use. `normalizeApiKey(raw)` trims surrounding whitespace, then accepts any non-empty printable-ASCII value (`/^[\x21-\x7E]+$/`, space excluded) or reports why not as an `ApiKeyRejection` (`'empty'` | `'illegalCharacters'`), both carried in the `ApiKeyCheck` result. Absence is never judged: a caller decides whether a value was supplied before asking, since a profile naming no credential authenticates through the provider's own ambient discovery or OAuth. + +### Classes + +- `LlmAdapter` — abstract base class for provider adapters. The only required method is `stream()`. +- `BlockAssembler` — incrementally assembles raw chunks into complete content blocks and can create an identified, frozen assistant message from them. The agent loop feeds it raw chunks (logging them for replay) while reading the assembled blocks for history. +- `HarnessError` — base class for the harness error taxonomy: a stable `code` string (distinct from the human `message`) plus `cause` chaining. Lives here, in the leaf package every other imports, so a single base is shared without a new dependency edge. Per-package errors (`LlmError`, `ToolArgsError`, `InvariantError`, …) extend it. `isHarnessError(value)` narrows at process boundaries. +- `LlmError` — extends `HarnessError`; its stable `code` string (`NO_ADAPTER`, `DUPLICATE_ADAPTER`, and adapter codes like `AUTH`/`RATE_LIMIT`) matches its frozen serializable `failure.code`. The payload may also retain validated status, `Retry-After`, and branded provider request id facts; policy remains outside the error. +- `errorChain(value)` — renders a thrown value with its full `cause` chain and AggregateError members for diagnostic outputs (UI notices, logger lines, durable `turn/end` messages), so transport wrappers like undici's `TypeError: fetch failed` surface the underlying `ECONNREFUSED`/DNS/TLS detail instead of masking it. Rendering only — route on `code`, never by parsing the result. +- `CONTEXT_WINDOW_EXCEEDED_CODE` — the provider-neutral code both DeepSeek adapters use when a request exceeds the model context window, regardless of thrown-HTTP versus in-band finish delivery. `isContextWindowExceededError(detail)` is their shared conservative classifier for OpenAI-compatible provider detail. +- `QUOTA_EXCEEDED_CODE` — the non-transient provider-neutral code for exhausted account quota, balance, credits, budget, or usage limits. `isQuotaExceededError(detail)` keeps those failures distinct from request-rate limits. +- `EMPTY_RESPONSE_CODE` — the provider-neutral code both adapters use for a degenerate provider completion: a terminal `stop` that carried no content blocks at all. Classified as an error finish (not a successful empty message) because the attempt produced nothing durable; `dsh-llm-retry` retries it by default. +- `INVALID_CREDENTIAL_CODE` — the provider-neutral code for a credential that was supplied but cannot be used: malformed rather than absent, so the fix is to correct the stored value rather than supply one — the distinction from `MISSING_CREDENTIAL`. Deliberately excluded from the default retryable set, since a malformed credential fails identically on every attempt. `assertUsableApiKey(raw, pkg, ref)` throws `LlmError` with this code, the one shared diagnosis every adapter uses for an unusable stored credential. + +### Real adapters + +Two adapters implement `LlmAdapter` on different internals: [`@deepseek-ai/dsh-llm-deepseek`](../llm-deepseek) uses direct fetch with `eventsource-parser` SSE framing for the `deepseek-official` route, while [`@deepseek-ai/dsh-llm-pi-ai`](../llm-pi-ai) dynamically resolves configured provider/model pairs through `@earendil-works/pi-ai`. Both follow the `StreamChunk` conventions in `types.ts`: usage precedes finish and tool arguments remain raw strings. Adapter implementations may throw or emit a failure finish internally; `LlmRuntime` exposes both as a terminal failure finish. See [the twin LLM adapters](../../../.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.md) for the adapter rationale and [the terminal-failure decision](../../../.agents/notes/implemented/architecture/2026-07-29-terminal-llm-stream-failures.md) for the service boundary. + +## Model Experience + +None, as the service adds no model-bound text, schema, or message; it only materializes and logs an adapter-configured reasoning effort. + +#### KV Cache effect + +Pass-through; the registry preserves the assembled request prefix, while the selected adapter and provider own cache reuse and routing boundaries. + +## Known Limitations and Deferred Work + +- **No retry execution, caching, or rate limiting ships in this service** — provider registration stores retry policy, but `llm/stream` remains a single-attempt call wrapper. The agent loop separately offers proven model-request failures to `agent/request-error`, whose default preserves the original failure; `@deepseek-ai/dsh-llm-retry` is the optional executor loaded by the shared example spine. +- **`GenerateOptions` sampling is `temperature`/`maxTokens`/`stop` only** — no `tool_choice`, `top_p`, or penalty fields; the vocabulary grows when a producer lands ([dropped inert knobs](../../../.agents/notes/archived/simplification/2026-07-04-drop-inert-request-knobs.md)). +- **Producer-gated variants stay out until produced** — `prefill`, per-tool `strict`, block `cache` hints, and the `agent` message-source variant were pruned as producerless ([Agent Note](../../../.agents/notes/archived/simplification/2026-07-04-prune-producerless-vocabulary-variants.md)). +- **`BlockAssembler` handles core block kinds only** — a plugin-added block type whose stream is never closed by `block-end` makes `blocks()` throw. +- **`APP_IDENTITY.url` names a repository that does not exist yet** — the public home must be reachable before release. +- **`GenerateOptions.sessionId` is a locally-declared brand** — importing dsh-session's `SessionId` would cycle; a future ids-owning package would dissolve the workaround. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.zh.md new file mode 100644 index 0000000..110cc12 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/README.zh.md @@ -0,0 +1,101 @@ +# dsh-llm + +[English](README.md) | 中文 + +提供方无关的 LLM(大语言模型)词汇与抽象服务。本包定义 agent loop(智能体循环)、会话日志和所有插件共同使用的规范词汇。 + +## 服务:`LlmRuntime`(ctx key:`llm`) + +一个适配器注册表加单一流式调用接口,可通过 waterfall(瀑布式事件)拦截。 + +### 公开 API + +- `ctx.llm.registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHandle` 为给定提供方路由注册一个适配器实例。注册要么全部成功,要么全部不生效,并且会随调用 fiber 一起 dispose(资源释放)。返回的句柄还提供 `replace(providers)`:候选路由集合会在注册状态发生任何变化前完成整体验证,因此与另一适配器发生冲突时,当前路由仍保持注册并继续提供服务。替换会在一次同步操作中完成,不会出现可观察的空档。`replace([])` 合法,表示保留注册但不持有任何路由;初始注册则不得为空。 +- `ctx.llm.listProviders(): LlmProviderInfo[]` 按注册顺序描述已注册提供方路由。 +- `ctx.llm.registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): DirectoryRegistrationHandle` 声明适配器插件可通过配置激活的提供方路由——无论已注册还是休眠——每个条目指明其所属 settings namespace,以及 profile 在该分节内的路径。要么全部成功,要么全部不生效(`INVALID_DIRECTORY`/`DUPLICATE_DIRECTORY`),并随调用 fiber dispose。该句柄还带 `replace(entries)`:候选集合会先被整体校验,因此其中若有条目已被另一个注册声明,当前集合原封不动;此处允许传空数组。声明集合随配置变化的插件必须使用 `replace`,而不是先 dispose 再重新注册——后者会在新集合被拒时让目录整个落空。 +- `ctx.llm.listConfigurableProviders(): LlmConfigurableProvider[]` 按声明顺序列出可配置提供方目录;配置界面将其与 `listProviders()` 合并,为每个条目标注存活或休眠。条目可携带 `declared`,表示拥有该路由的适配器是否只因配置点名才知道它。只有适配器能回答这一点:该字段缺失时,只表示该适配器不区分这两种来源,不能据此判断路由是否随产品交付。 +- `ctx.llm.registerModelDiscovery(settingsNs: string, discover): () => void` 为本插件拥有的 settings namespace 提供查询提供方端点的能力。每个 namespace 只能有一个(`INVALID_DISCOVERY`/`DUPLICATE_DISCOVERY`),并随调用 fiber dispose。 +- `ctx.llm.listModelDiscoveryNamespaces(): string[]` 列出可以询问端点的 namespace,让界面只在可用之处提供该动作。 +- `ctx.llm.discoverModels(settingsNs: string, request: LlmModelDiscoveryRequest): Promise` 询问某个端点它公布了哪些模型。 +- `ctx.llm.providerRetryPolicy(provider: string): ResolvedRetryPolicy` 返回注册时捕获的提供方自身的重试策略,并解析 normal 默认值。 +- `ctx.llm.listModels(provider: string): Promise` 发现某个已注册提供方当前公布的模型。 +- `ctx.llm.resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise` 从拥有该精确路由的适配器中,解析并校验确切模型身份,以及可用上下文、输出默认值和推理(reasoning)元数据;异步适配器可选地支持取消。 +- `ctx.llm.resolveCallConfig(config: LlmCallConfig, signal?: AbortSignal): Promise` 校验显式推理强度,并填入适配器配置的调用默认值,但不自动调整。 +- `ctx.llm.prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise` 在一次精确模型查询中解析配置、脱耦的上下文元数据以及标明哪些字段由适配器默认值填入的标记,再将当前适配器注册和不可变重试策略捕获为一次可取消、一次性调用。 +- `ctx.llm.stream(options: GenerateOptions): AsyncIterable` 将一次模型调用流式输出为原始分片(token 级增量)。消费方使用 `BlockAssembler` 将分片组装为块/消息。 + +`LlmRuntime` 将最终适配器选择、同步分发、迭代器构造和迭代期间的失败,统一转换为流协议唯一的终止形式:`finish { kind: 'error' | 'aborted', failure }`。部分增量输出后发生失败时,内容块可能仍未闭合;消费方会丢弃这些不完整输出。`llm/stream` middleware、嵌套调用、适配器清理和下游消费方的错误仍会抛出,因为它们属于插件或消费方失败,而非模型请求结果。已准备调用会暴露随其确切适配器注册一同捕获的不可变重试策略;完全由 middleware 处理的路由没有服务策略。 + +询问端点属于配置期针对**草稿**的操作,以 settings namespace 而非提供方路由为键——界面正在新增的提供方还不存在,也就没有路由可点名。但请求仍可**点名**它正在编辑的路由,而已经描述该路由的适配器会用自己的知识作答,无需联网;路由名称和 `baseURL` 至少需要提供一项。除此之外,请求携带端点、协议,以及一条 harness 只用于这一次询问、绝不存储的凭据。这里既不读取也不写入 settings 或 credentials;返回内容是界面可以提供给用户采纳的候选元数据,而不是已注册的 catalog。`LlmDiscoveredModel` 除 `id` 外每个字段都是可选的,因为大多数提供方列表只公布 id;采纳其中一条的界面仍要补上其适配器所需的容量。重复与不可用的 id 会被丢弃,无人服务的 namespace 以 `NO_DISCOVERY` 失败,既不点名路由也不给端点的请求以 `INVALID_DISCOVERY` 失败。 + +提供方和模型元数据用于发现,不构成路由白名单。`registerAdapter()` 仍拥有提供方路由的排他性,并为每条路由捕获适配器的重试策略;适配器可以接受未出现在 `listModels()` 中的模型 id,消费方不得仅因模型未列出而拒绝请求。返回的 selector 元数据已分离;无效或重复的适配器条目会以 `INVALID_ADAPTER` 或 `INVALID_CATALOG` 失败。 + +每个拓扑提交点——适配器路由注册或 dispose、目录条目出现或撤回——都会在变更之后发出无载荷的 `llm/adapters-updated` 事件,消费方因此会重新读取 `listProviders()`/`listModels()`/`listConfigurableProviders()`,而不是轮询。观察者故障会被记录并隔离,不能否决变更;只有带 `INVARIANT` 码的故障会在通知完所有观察者后重新抛出。 + +确切模型元数据是独立的正确性查询,不是 catalog 装饰或全局 LLM 设置。`resolveModelInfo()` 会向拥有精确提供方/模型路由的适配器查询一次;适配器可以描述未列出的动态模型。缺少 `context` 表示模型容量未知;缺少 `defaultMaxTokens` 表示继续沿用提供方自身的输出默认值;缺少 `reasoning` 则表示推理能力不可用。无效的身份、上下文、输出默认值或推理元数据会以 `INVALID_MODEL_INFO`、`INVALID_MODEL_CONTEXT`、`INVALID_MODEL_MAX_TOKENS` 或 `INVALID_MODEL_REASONING` 失败。 + +`defaultMaxTokens` 是适配器配置的单次请求输出上限,不是模型硬上限。仅当请求省略 `maxTokens` 时,`resolveCallConfig()` 才会填入该值;显式上限优先。推理标识符是由适配器定义的不透明字符串,而非核心枚举:同一次解析只接受与已公布标识符完全一致的值,在存在 `defaultEffort` 时填入它,否则保留提供方默认值。异步模型解析器会接收调用方信号,并且必须在取消后尽快结算。`prepareCall()` 还会返回同一次查询得到的、与适配器内部状态分离的上下文元数据,通过 `adapterDefaults` 标明填入了哪些 `maxTokens` 和 `reasoningEffort` 字段,并在请求头记录和最终分发期间始终保留同一项精确的适配器注册。因此,HMR(热模块替换)不会把一个适配器的能力结果与另一个适配器的请求混用;复用其一次性句柄或更改调用配置字段会以 `INVALID_PREPARED_CALL` 失败。不支持的显式或配置推理强度会在提供方 I/O 前以 `UNSUPPORTED_REASONING_EFFORT` 失败。 + +### 事件 + +| 事件 | 模式 | 用途 | +|---|---|---| +| `llm/stream` | waterfall | 拦截/包装每次流式模型调用,用于缓存、日志或路由 | + +### 扩展点 + +- 继承 `LlmAdapter` 并调用 `ctx.llm.registerAdapter(providers, adapter)`,添加一条或多条提供方路由。`GenerateOptions.provider` 选择适配器;`GenerateOptions.model` 属于适配器,可以动态解析。覆盖 `providerRetryPolicy()` 以提供由提供方定义的恢复配置,覆盖 `providerInfo()` 和异步 `listModels()` 以公开 selector 元数据;精确身份、容量、输出默认值或可选推理强度可用时,实现 `resolveModel()`;异步解析器必须响应其可选的取消 signal。默认实现使用有界的 normal 重试策略,将路由和模型 id 用作名称,不公布模型,也不返回容量、输出默认值或推理元数据。 +- 包装 `llm/stream` 时,通过 `ctx.on()` waterfall listener 实现缓存、日志或路由。包装层如果在已经发出分片后重试,就没有可持久记录的尝试边界;因此,随产品交付的 agent 重试策略改用 `agent/request-error`。 + +### 消息(`message.ts`)与内容块(`types.ts`) + +`Message` 是投递、持久历史和模型请求共享的不可变值。每条消息从创建起都必须具有 `MessageId`、角色、内容和带类型的来源。`createMessage(input)` 生成标识,并返回与输入分离且深度冻结的值;`createUserMessage({ content, source })` 固定 user 角色;`createAssistantMessage({ content, source })` 固定 assistant 角色与模型来源类别;`createToolResultMessage({ callId, content, isError })` 固定 user 角色,并将工具来源与其结果块耦合;`freezeMessage(message)` 导入已有标识,绝不将其替换。改写消息时会保留标识,并产生另一个冻结值。浏览器端代码会从依赖最少的 `@deepseek-ai/dsh-llm/message` 入口导入这些值构造函数,而不是从包含服务的包根入口导入。 + +消息内容是类型化内容块数组:`text`、`reasoning`、`tool-call`、`tool-result`。联合从可合并扩展的 `ContentBlockMap` 派生,因此插件可以通过 declaration merging 添加块类型。assistant 消息使用模型来源,其中携带生成该消息的提供方和模型,以及可选的适配器私有回放状态。dispatch 前,`LlmRuntime` 只在历史提供方路由与目标提供方路由当前由完全相同的适配器实例拥有时才保留该状态;随后由适配器判定能否在模型/提供方间恢复或转换该状态。核心块集只包含每条已发布路径都支持的块。多模态内容(图像、音频等)没有核心块类型;需要它的功能会通过 map 添加,并一并添加相应的适配器/UI/压缩(compaction)支持。 + +流式输出是原始分片协议(`block-start`、`text-delta`、`reasoning-delta`、`tool-call-delta`、`block-end`、`usage`、`finish`)。每个适配器结果都以一个终止 `finish` 到达消费方;运行故障使用 `error` 或 `aborted` 作为结束原因,而不会跨流 API 抛出。`BlockAssembler` 是将分片组装为块/消息的唯一共享实现。 + +### 调用配置(`call-config.ts`) + +`LlmCallConfig` 记录一个会话的模型请求所使用的提供方、模型、由适配器定义的可选推理强度,以及采样参数(`provider`、`model`、`reasoningEffort`、`temperature`、`maxTokens`、`stop`,分别与同名 `GenerateOptions` 字段一一对应)。它是作为请求标头一部分记录在会话日志中的每会话状态(见 dsh-session `request/header` 事件),绝不是可静默调整的每次调用旋钮:`agent/request` waterfall 会提议替换,`prepareCall()` 在轮次 signal 控制下校验它并填入适配器默认值,loop 随后记录生效值以及标明哪些字段由适配器默认值填入的标记,再使用已准备调用中与注册绑定的流。下一次提议会省略带标记的默认值,使变更后的路由解析自身的值;未带标记的显式字段会保留。`callConfigEquals(a, b)` 是逐字段真实变更检测器;`deepFreeze(value)` 是 loop 使用的请求所有权辅助函数:每个构造完成的请求都会在分发前深度冻结;`llm/stream` 监听器和适配器只能读取,绝不能改写。`markAgentLoopRequest()` 将该精确对象标记为由进程本地 agent loop 创建,`isAgentLoopRequest()` 让观测方可以将其与同样可能冻结并关联会话、但独立记录的辅助调用区分。`GenerateOptions.purpose` 会对已记录的辅助压缩和会话标题调用进行分类,使适配器可以按调用目的应用不同的传输策略,而不改变普通会话请求。 + +### 应用归因(`attribution.ts`) + +每个产品适配器都会在提供方 HTTP 请求上发送应用身份。`attributionHeaders(identity?)` 构建标准 `User-Agent`,默认为公开 `APP_IDENTITY`;白标部署可以替换它,但不能抑制它。适配器会直接验证 wire 标头,或通过自身库 hook 验证。详见 [归因 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 + +### API 密钥校验(`api-key.ts`) + +每个要把凭据放进 HTTP 标头的适配器,使用前都以同一套规则校验它。`normalizeApiKey(raw)` 会先去除首尾空白,然后接受任意非空的可打印 ASCII 值(`/^[\x21-\x7E]+$/`,不含空格),或通过 `ApiKeyRejection`(`'empty'` | `'illegalCharacters'`)说明拒绝原因。这些结果一并包含在 `ApiKeyCheck` 中。缺失从不参与校验:调用方会在询问之前自行判断是否提供了值——未点名凭据的 profile 会转由提供方自身的环境发现或 OAuth 完成认证。 + +### 类 + +- `LlmAdapter`:提供方适配器的抽象基类。唯一必需方法是 `stream()`。 +- `BlockAssembler`:将原始分片逐步组装为完整内容块,并能据此创建带标识且冻结的 assistant 消息。agent loop 向它提供原始分片(同时记录以供回放),并读取已组装块以构建历史。 +- `HarnessError`:harness 错误分类体系的基类,包含稳定 `code` 字符串(与面向人的 `message` 不同)以及 `cause` 链。它位于所有其他包都从中导入的叶子包中,因此可以共享单一基类,无需新的依赖边。各包的错误(`LlmError`、`ToolArgsError`、`InvariantError` 等)都继承自它。`isHarnessError(value)` 在进程边界处收窄类型。 +- `LlmError`:继承自 `HarnessError`;其稳定 `code` 字符串(`NO_ADAPTER`、`DUPLICATE_ADAPTER` 与 `AUTH`/`RATE_LIMIT` 等适配器 code)与冻结可序列化 `failure.code` 匹配。Payload 还可以保留已验证状态、`Retry-After` 和品牌化提供方请求 id 事实;策略位于错误之外。 +- `errorChain(value)`:渲染抛出值的完整 `cause` 链与 AggregateError 成员,供诊断输出使用,包括 UI 通知、logger 行和持久 `turn/end` 消息。因此 undici 的 `TypeError: fetch failed` 等传输包装层会显示底层 `ECONNREFUSED`/DNS/TLS 详细信息,而不是将其遮蔽。该函数只负责生成诊断文本。调用方必须依据稳定的 `code` 选择错误处理路径,绝不能通过解析渲染后的文本作出判断。 +- `CONTEXT_WINDOW_EXCEEDED_CODE`:当请求超过模型上下文窗口时,无论通过 HTTP 异常抛出还是带内 finish 交付,两个 DeepSeek 适配器都使用的提供方无关 code。`isContextWindowExceededError(detail)` 是它们针对 OpenAI 兼容提供方详细信息的共享保守分类器。 +- `QUOTA_EXCEEDED_CODE`:帐户配额、余额、点数、预算或用量限制耗尽时使用的非暂时性提供方无关 code。`isQuotaExceededError(detail)` 使这些失败与请求速率限制保持区分。 +- `EMPTY_RESPONSE_CODE`:两个适配器都使用的提供方无关 code,用于表示退化的提供方生成结果:一个未携带任何内容块的终止 `stop`。它会被分类为错误 finish(而非成功空消息),因为尝试未产生持久内容;`dsh-llm-retry` 默认重试它。 +- `INVALID_CREDENTIAL_CODE`:已提供但无法使用的凭据所用的提供方无关 code——格式错误而非缺失,修复方式是改正已存储的值,而不是补充一个凭据,这正是它与 `MISSING_CREDENTIAL` 的区别。它被刻意排除在默认可重试集合之外:格式错误的凭据每次尝试都会以同样方式失败。`assertUsableApiKey(raw, pkg, ref)` 会以该 code 抛出 `LlmError`,是每个适配器判定已存储凭据不可用时共用的诊断。 + +### 真实适配器 + +两个适配器使用不同内部机制实现 `LlmAdapter`:[`@deepseek-ai/dsh-llm-deepseek`](../llm-deepseek) 针对 `deepseek-official` 路由使用直接 fetch 加 `eventsource-parser` SSE(Server-Sent Events)分帧,[`@deepseek-ai/dsh-llm-pi-ai`](../llm-pi-ai) 则通过 `@earendil-works/pi-ai` 动态解析已配置提供方/模型对。两者都遵循 `types.ts` 中的 `StreamChunk` 约定:usage 先于 finish,工具参数保持原始字符串。适配器实现在内部可以抛出异常或发出失败 finish;`LlmRuntime` 会将两者都暴露为终止失败 finish。适配器理由见[双 LLM 适配器](../../../.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.md),服务边界见[终止失败决策](../../../.agents/notes/implemented/architecture/2026-07-29-terminal-llm-stream-failures.md)。 + +## 模型体验 + +无。服务不添加任何与模型绑定的文本、schema 或消息;它只会填入并记录适配器配置的推理强度。 + +#### KV Cache 影响 + +透传;注册表保留已组装请求前缀,cache 复用与路由边界属于所选适配器和提供方。 + +## 已知限制与暂缓事项 + +- **本服务不执行重试、缓存或速率限制**:提供方注册会存储重试策略,但 `llm/stream` 仍是单次尝试调用包装层。agent loop 会将已验证模型请求失败单独提供给 `agent/request-error`,其默认行为是保留原始失败;`@deepseek-ai/dsh-llm-retry` 是共享示例主干加载的可选执行器。 +- **`GenerateOptions` 采样只包含 `temperature`/`maxTokens`/`stop`**:没有 `tool_choice`、`top_p` 或 penalty 字段;有产生方落地时词汇才会增长(见 [已删除惰性旋钮](../../../.agents/notes/archived/simplification/2026-07-04-drop-inert-request-knobs.md))。 +- **只有出现实际产生方后,相应变体才会加入**:`prefill`、逐工具 `strict`、内容块 `cache` 提示和 `agent` 消息来源变体,都因当前没有产生方而被移除(见 [Agent Note](../../../.agents/notes/archived/simplification/2026-07-04-prune-producerless-vocabulary-variants.md))。 +- **`BlockAssembler` 只处理核心块类型**:如果插件添加块类型的流从未由 `block-end` 关闭,`blocks()` 会抛出异常。 +- **`APP_IDENTITY.url` 指向一个尚不存在的仓库**:该公开主页必须在发布前可访问。 +- **`GenerateOptions.sessionId` 是本地声明的品牌类型**:导入 dsh-session 的 `SessionId` 会产生循环;未来拥有 id 的包可以消除该权宜之计。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/index.js new file mode 100644 index 0000000..3cb45fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/index.js @@ -0,0 +1,1407 @@ +import { createRequire } from "node:module"; +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { MAX_TIMER_DELAY_MS } from "@deepseek-ai/dsh-timeout"; +//#region lib/types/brand.js +/** +* dsh-llm's owned branded ids: tool-call correlation and provider request +* diagnostics. +* +* The `Branded` primitive itself lives in `@deepseek-ai/dsh-brand` (a +* zero-dependency type-only package) so every owner of a cross-boundary id can +* brand it without depending on dsh-llm; see that package's README for the +* nominal-typing policy. +* +* @module @deepseek-ai/dsh-llm/brand +*/ +/** +* Brand a message identifier. +* @param id - the opaque message identifier. +* @returns the same string, branded; no validation is performed. +*/ +function MessageId(id) { + return id; +} +/** +* Brand a string as a {@link CallId}. +* @param id - the provider-issued (or synthesized) call id. +* @returns the same string, branded; no validation is performed. +*/ +function CallId(id) { + return id; +} +/** +* Brand a provider-issued request identifier. +* @param id - the opaque provider-issued string. +* @returns the same string, branded; no validation is performed. +*/ +function ProviderRequestId(id) { + return id; +} +/** +* Brand an adapter-owned reasoning-effort identifier. +* @param id - the opaque identifier exposed by one model capability. +* @returns the same string, branded; no validation is performed. +*/ +function ReasoningEffortId(id) { + return id; +} +//#endregion +//#region lib/types/call-config.js +/** +* Conversation call configuration and freeze utilities. Provider routing, +* model, reasoning effort, and sampling values are request-header state that +* can affect cache reuse; request waterfalls replace them and the loop logs +* changed snapshots instead of allowing silent per-call drift. +* @module dsh-llm/call-config +*/ +/** Process-local identities of request objects assembled by dsh-agent-loop. */ +const AGENT_LOOP_REQUESTS = /* @__PURE__ */ new WeakSet(); +/** +* Field-wise equality over {@link LlmCallConfig} — the comparison a caller +* runs to decide whether a proposed configuration is a real change (worth a +* logged header snapshot) or the held one restated. +* @param a - one configuration. +* @param b - the other. +* @returns whether every field (including the `stop` list, element-wise) matches. +*/ +function callConfigEquals(a, b) { + if (a.provider !== b.provider || a.model !== b.model || a.reasoningEffort !== b.reasoningEffort || a.temperature !== b.temperature || a.maxTokens !== b.maxTokens) return false; + if (a.stop === void 0 || b.stop === void 0) return a.stop === b.stop; + return a.stop.length === b.stop.length && a.stop.every((s, i) => s === b.stop?.[i]); +} +/** +* Mark one exact request object as assembled by dsh-agent-loop. +* @param request - loop-owned request envelope before LLM dispatch. +* @returns the same request object marked as created by the process-local agent loop. +*/ +function markAgentLoopRequest(request) { + AGENT_LOOP_REQUESTS.add(request); + return request; +} +/** +* Test whether the exact request object was assembled by dsh-agent-loop. +* @param request - request envelope observed at the LLM waterfall. +* @returns whether {@link markAgentLoopRequest} recorded this object. +*/ +function isAgentLoopRequest(request) { + return AGENT_LOOP_REQUESTS.has(request); +} +/** +* Deep-freeze a value in place with an iterative traversal, guarding cycles, +* so later mutation throws without imposing a JavaScript call-stack depth cap. +* {@link AbortSignal} objects are deliberately skipped because they are the +* request's live cancellation channel and freezing them breaks abort. +* @param value - the value to freeze in place. +* @returns the same value, frozen. +*/ +function deepFreeze(value) { + const seen = /* @__PURE__ */ new WeakSet(); + const pending = [{ + kind: "visit", + node: value + }]; + while (pending.length > 0) { + const task = pending.pop(); + /* v8 ignore next -- the loop condition guarantees one pending task. */ + if (task === void 0) continue; + if (task.kind === "property") { + pending.push({ + kind: "visit", + node: task.source[task.key] + }); + continue; + } + const node = task.node; + if (node === null || typeof node !== "object") continue; + if (node instanceof AbortSignal) continue; + if (seen.has(node)) continue; + seen.add(node); + Object.freeze(node); + const keys = Object.keys(node); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === void 0) continue; + pending.push({ + kind: "property", + source: node, + key + }); + } + } + return value; +} +//#endregion +//#region lib/types/message.js +/** Message value types, identity, and immutable construction helpers. */ +/** +* Bound for a `notice` summary. The account rides a collapsed transcript row +* and is committed to the durable log, while its inputs — task labels, goal +* objectives, tool arguments — are caller text with no length of their own. +*/ +const CONTEXT_SUMMARY_MAX_CHARS = 120; +/** +* Bound one `notice` summary to {@link CONTEXT_SUMMARY_MAX_CHARS}. +* @param summary - the producer's one-line account, of any length. +* @returns the account, ellipsized when it exceeds the bound. +*/ +function boundContextSummary(summary) { + return summary.length <= 120 ? summary : `${summary.slice(0, 119)}…`; +} +/** +* Detach and deep-freeze a message whose identity already exists. +* @param message - complete message, including its stable identity. +* @returns an immutable snapshot that preserves the identity. +*/ +function freezeMessage(message) { + return deepFreeze(structuredClone(message)); +} +/** +* Create one identified message and freeze it before publication. +* @param input - complete role, content, and source for a new message. +* @returns an immutable message with a fresh stable identity. +*/ +function createMessage(input) { + return freezeMessage({ + ...input, + id: MessageId(crypto.randomUUID()) + }); +} +/** +* Create one identified user-role message and freeze it before publication. +* @param input - complete content and source for a new user message. +* @returns an immutable user message with a fresh stable identity. +*/ +function createUserMessage(input) { + return createMessage({ + ...input, + role: "user" + }); +} +/** +* Create one identified model-produced assistant message and freeze it before publication. +* @param input - complete content plus the provider, model, and optional replay state for a new assistant message. +* @returns an immutable assistant message with fixed role/source tags and a fresh stable identity. +*/ +function createAssistantMessage(input) { + return createMessage({ + role: "assistant", + content: input.content, + source: { + kind: "model", + ...input.source + } + }); +} +/** +* Create and freeze one identified tool-result message. +* @param input - call identity, raw result blocks, and outcome. +* @returns an immutable user-role tool-result message. +*/ +function createToolResultMessage(input) { + return createUserMessage({ + source: { + kind: "tool", + callId: input.callId + }, + content: [{ + type: "tool-result", + toolCallId: input.callId, + content: input.content, + isError: input.isError + }] + }); +} +/** +* Whether a stream chunk carries visible model output (the first-token +* boundary shared by client step timing and the whole-log sessionStats +* projection). Empty deltas (heartbeats, empty tool-call frames) do not count +* as a first token. +* @param chunk - the stream chunk to test. +* @returns true when the chunk contains a non-empty text/reasoning/tool delta. +*/ +function isTokenDelta(chunk) { + switch (chunk.type) { + case "text-delta": + case "reasoning-delta": return chunk.text !== ""; + case "tool-call-delta": return chunk.argumentsDelta !== "" || chunk.name !== void 0; + default: return false; + } +} +//#endregion +//#region lib/types/error.js +/** +* Harness error base with a stable machine-routable code and chained cause. +* Package errors extend it so tool results and replay can retain failure class. +* @module @deepseek-ai/dsh-llm/error +*/ +/** +* Base class for all harness errors. Carries a `code` (stable, programmatic — +* e.g. `NO_ADAPTER`, `INVALID_ARGS`, `INVARIANT`) distinct from the +* human-readable `message`, and supports `cause` chaining via the standard +* `ErrorOptions`. `name` defaults to the subclass constructor name. +*/ +var HarnessError = class extends Error { + /** Stable machine-routable failure class (e.g. `RATE_LIMIT`); route on this, never by parsing `message`. */ + code; + constructor(message, code, options) { + super(message, options); + this.code = code; + this.name = new.target.name; + } +}; +/** Canonical provider-neutral code for a model request rejected because its context window was exceeded. */ +const CONTEXT_WINDOW_EXCEEDED_CODE = "CONTEXT_WINDOW_EXCEEDED"; +/** Canonical provider-neutral code for an exhausted account quota or balance. */ +const QUOTA_EXCEEDED_CODE = "QUOTA"; +/** +* Canonical provider-neutral code for a response that completed normally but +* carried no content blocks at all. Providers occasionally emit a degenerate +* completion (a terminal stop with zero output); adapters classify it as this +* failure instead of yielding an empty assistant message, because an empty +* message silently ends the turn with nothing for the user or the loop to act +* on. The attempt produced nothing durable, so retry policy treats it as safe +* to repeat. +*/ +const EMPTY_RESPONSE_CODE = "EMPTY_RESPONSE"; +/** +* Canonical provider-neutral code for a credential that was supplied but +* cannot be used — malformed rather than absent. Distinct from +* `MISSING_CREDENTIAL` because the fix differs: correct the stored value +* rather than supply one. Deliberately outside the default retryable set — +* a malformed credential fails identically on every attempt. +*/ +const INVALID_CREDENTIAL_CODE = "INVALID_CREDENTIAL"; +/** Structured codes and plain phrases that explicitly name a context bound being exceeded. */ +const STRUCTURED_CONTEXT_OVERFLOW = new RegExp(String.raw`(?:^|[^a-z0-9])context[\s_-](?:length|window)[\s_-]` + String.raw`(?:exceed(?:ed|s)?|overflow(?:ed)?|limit[\s_-]exceeded)(?:$|[^a-z0-9])`, "i"); +/** Request-size wording that ties "too large" directly to model context capacity. */ +const TOO_LARGE_FOR_CONTEXT = new RegExp(String.raw`\b(?:request|prompt|input|messages?)\s+(?:is\s+|are\s+)?` + String.raw`too\s+(?:large|long)\s+for\s+(?:(?:this|the)\s+)?` + String.raw`(?:model(?:'s)?\s+)?context(?:\s+window)?\b`, "i"); +/** "Exceeds" wording is safe only when its object is explicitly the model context. */ +const EXCEEDS_MODEL_CONTEXT = new RegExp(String.raw`\b(?:input|prompt|request|messages?)\b.{0,40}` + String.raw`\b(?:exceed(?:s|ed)?|overflows?|is\s+larger\s+than)\b.{0,40}` + String.raw`\b(?:the\s+)?(?:model(?:'s)?\s+)?context(?:\s+(?:length|window))?\b`, "i"); +/** +* Recognize the context-overflow wording used by OpenAI-compatible providers +* and library adapters. Adapters pass all available provider code, type, and +* message text so both thrown and in-band delivery styles share one classifier. +* @param detail - provider error code/type/message text joined into one string. +* @returns true when the detail identifies a request exceeding the model context window. +*/ +function isContextWindowExceededError(detail) { + return STRUCTURED_CONTEXT_OVERFLOW.test(detail) || /\b(?:maximum|max)(?:\s+(?:allowed|supported))?\s+context\s+(?:length|window)\b/i.test(detail) || TOO_LARGE_FOR_CONTEXT.test(detail) || /\b(?:input|prompt|request)\s+(?:is\s+)?too\s+(?:long|large)\s+for\s+(?:this|the)\s+model\b/i.test(detail) || EXCEEDS_MODEL_CONTEXT.test(detail); +} +/** +* Recognize provider wording that identifies an exhausted account quota rather +* than a transient request-rate limit. +* @param detail - provider error code/type/message text joined into one string. +* @returns true only for terminal quota, balance, credit, budget, or usage-limit wording. +*/ +function isQuotaExceededError(detail) { + return /\binsufficient[\s_-]+(?:quota|balance|credits?)\b/i.test(detail) || /\b(?:quota|usage[\s_-]+limit)[\s_-]+(?:exceeded|exhausted|reached)\b/i.test(detail) || /\bexceed(?:ed|s)?[\s_-]+(?:(?:your|the)[\s_-]+)?(?:current[\s_-]+)?quota\b/i.test(detail) || /\b(?:balance|credits?)[\s_-]+(?:exhausted|depleted)\b/i.test(detail) || /\bout[\s_-]+of[\s_-]+(?:credits?|budget)\b/i.test(detail); +} +/** +* Render a thrown value with its full `cause` chain and AggregateError +* members, so transport wrappers like undici's `TypeError: fetch failed` +* surface the underlying failure instead of masking it. Plain structured +* failures render their own data-backed `message`. Diagnostic-surface +* rendering only (messages, notices, logs) — never parse the result; route on +* {@link HarnessError.code}. +* @param value - the caught value (`unknown` in catch clauses). +* @returns the outermost message first, each cause appended with `: ` (skipped +* when it repeats the wrapper message verbatim), and AggregateError members +* bracketed and `; `-joined. +*/ +function errorChain(value) { + const path = /* @__PURE__ */ new Set(); + const render = (current) => { + if (path.has(current)) return ""; + path.add(current); + try { + if (!(current instanceof Error)) { + if (typeof current === "object" && current !== null) { + const descriptor = Object.getOwnPropertyDescriptor(current, "message"); + if (descriptor !== void 0 && "value" in descriptor && typeof descriptor.value === "string") return descriptor.value; + } + return String(current); + } + const message = current.message === "" ? current.name : current.message; + const members = current instanceof AggregateError && current.errors.length > 0 ? ` [${current.errors.map(render).join("; ")}]` : ""; + const causeText = current.cause === void 0 || current.cause === null ? "" : render(current.cause); + return `${message}${members}${causeText === "" || causeText === message ? "" : `: ${causeText}`}`; + } catch { + return ""; + } finally { + path.delete(current); + } + }; + return render(value); +} +/** +* Narrow an arbitrary thrown value to a HarnessError (for `instanceof` at runtime boundaries). +* @param value - the caught value (`unknown` in catch clauses). +* @returns true only for real instances; duck-typed or cross-realm errors do not narrow. +*/ +function isHarnessError(value) { + return value instanceof HarnessError; +} +//#endregion +//#region lib/types/retry-policy.js +/** +* Provider-owned request-retry policy configuration and resolution. +* +* Adapters expose one resolved policy per registered provider route; the +* optional dsh-llm-retry plugin executes it on the agent's failed-step extension point. +* +* @module @deepseek-ai/dsh-llm/retry-policy +*/ +const DEFAULT_MAX_RETRIES = 2; +const DEFAULT_INITIAL_DELAY_MS = 500; +const DEFAULT_MAX_DELAY_MS = 1e4; +const DEFAULT_JITTER_RATIO = .1; +const DEFAULT_RETRYABLE_CODES = Object.freeze([ + EMPTY_RESPONSE_CODE, + "RATE_LIMIT", + "SERVER", + "TIMEOUT", + "TRANSPORT" +]); +const backoffSchema = z.object({ + initialDelayMs: z.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_INITIAL_DELAY_MS), + maxDelayMs: z.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_MAX_DELAY_MS), + jitterRatio: z.number().min(0).max(1).default(DEFAULT_JITTER_RATIO) +}); +const normalPolicySchema = z.object({ + mode: z.const("normal").required(), + maxRetries: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_MAX_RETRIES), + retryableCodes: z.array(z.string()).default([...DEFAULT_RETRYABLE_CODES]), + backoff: backoffSchema +}); +const alwaysPolicySchema = z.object({ + mode: z.const("always").required(), + backoff: backoffSchema +}); +/** Cordis schema embedded by each concrete provider configuration. */ +const RetryPolicySchema = z.union([normalPolicySchema, alwaysPolicySchema]); +const NORMAL_POLICY_KEYS = new Set([ + "mode", + "maxRetries", + "retryableCodes", + "backoff" +]); +const ALWAYS_POLICY_KEYS = new Set(["mode", "backoff"]); +const BACKOFF_KEYS = new Set([ + "initialDelayMs", + "maxDelayMs", + "jitterRatio" +]); +function validateKeys(value, allowed, path) { + for (const key of Object.keys(value)) if (!allowed.has(key)) throw new Error(`${path}: unknown key "${key}"`); +} +function resolveBackoff(config, path) { + if (config !== void 0) validateKeys(config, BACKOFF_KEYS, path); + const initialDelayMs = config?.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS; + const maxDelayMs = config?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS; + const jitterRatio = config?.jitterRatio ?? DEFAULT_JITTER_RATIO; + if (!Number.isFinite(initialDelayMs) || initialDelayMs <= 0 || initialDelayMs > MAX_TIMER_DELAY_MS) throw new Error(`${path}.initialDelayMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`); + if (!Number.isFinite(maxDelayMs) || maxDelayMs <= 0 || maxDelayMs > MAX_TIMER_DELAY_MS) throw new Error(`${path}.maxDelayMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`); + if (initialDelayMs > maxDelayMs) throw new Error(`${path}.initialDelayMs must be less than or equal to maxDelayMs`); + if (!Number.isFinite(jitterRatio) || jitterRatio < 0 || jitterRatio > 1) throw new Error(`${path}.jitterRatio must be between 0 and 1`); + return Object.freeze({ + initialDelayMs, + maxDelayMs, + jitterRatio + }); +} +/** +* Validate, default, and detach one provider-owned retry policy. +* @param config - optional provider configuration; omission selects normal defaults. +* @param path - diagnostic path naming the provider config that owns the value. +* @returns an immutable policy safe to capture in provider registration state. +*/ +function resolveRetryPolicy(config, path) { + if (config === void 0) return Object.freeze({ + mode: "normal", + maxRetries: DEFAULT_MAX_RETRIES, + retryableCodes: DEFAULT_RETRYABLE_CODES, + ...resolveBackoff(void 0, `${path}.backoff`) + }); + switch (config.mode) { + case "normal": { + validateKeys(config, NORMAL_POLICY_KEYS, path); + const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES; + const retryableCodes = config.retryableCodes ?? [...DEFAULT_RETRYABLE_CODES]; + if (!Number.isSafeInteger(maxRetries) || maxRetries < 0) throw new Error(`${path}.maxRetries must be a non-negative safe integer`); + if (retryableCodes.length === 0) throw new Error(`${path}.retryableCodes must not be empty`); + if (retryableCodes.some((code) => typeof code !== "string" || code.length === 0)) throw new Error(`${path}.retryableCodes must contain only non-empty strings`); + if (new Set(retryableCodes).size !== retryableCodes.length) throw new Error(`${path}.retryableCodes must not contain duplicates`); + return Object.freeze({ + mode: "normal", + maxRetries, + retryableCodes: Object.freeze([...retryableCodes]), + ...resolveBackoff(config.backoff, `${path}.backoff`) + }); + } + case "always": + validateKeys(config, ALWAYS_POLICY_KEYS, path); + return Object.freeze({ + mode: "always", + ...resolveBackoff(config.backoff, `${path}.backoff`) + }); + default: throw new Error(`${path}.mode must be "normal" or "always"`); + } +} +//#endregion +//#region lib/types/adapter-failure.js +/** +* Normalization for values thrown by a final LLM adapter boundary. +* +* @module @deepseek-ai/dsh-llm/adapter-failure +*/ +/** +* Detach serializable provider facts from a value thrown by an adapter. +* @param value - arbitrary value thrown during adapter dispatch or iteration. +* @returns immutable provider-neutral facts suitable for a terminal finish chunk. +* @internal +*/ +function normalizeLlmFailure(value) { + const error = value instanceof Error ? value : new HarnessError(thrownMessage(value), "UNKNOWN", { cause: value }); + const carried = ownFailureSnapshot(error); + if (carried !== void 0 && carried.code === ownErrorCode(error)) return carried; + return Object.freeze({ + message: errorMessage(error), + code: harnessErrorCode(error) + }); +} +/** Render a non-Error throw without letting hostile coercion escape normalization. */ +function thrownMessage(value) { + try { + const message = String(value); + return message.length > 0 ? message : "LLM adapter failed"; + } catch (_hostileThrownValue) { + return "LLM adapter failed"; + } +} +/** Read a foreign error's own data-backed `code` without invoking accessors. */ +function ownErrorCode(error) { + try { + const descriptor = Object.getOwnPropertyDescriptor(error, "code"); + return descriptor !== void 0 && "value" in descriptor ? descriptor.value : void 0; + } catch (_sdkPropertyTrap) { + return; + } +} +/** Snapshot an own data property without invoking an SDK-defined accessor. */ +function ownFailureSnapshot(error) { + try { + const descriptor = Object.getOwnPropertyDescriptor(error, "failure"); + return descriptor !== void 0 && "value" in descriptor ? failureSnapshot(descriptor.value) : void 0; + } catch (_sdkPropertyTrap) { + return; + } +} +/** Validate and detach an arbitrary serializable failure payload. */ +function failureSnapshot(value) { + if (typeof value !== "object" || value === null) return void 0; + try { + const candidate = value; + const message = candidate.message; + const code = candidate.code; + const status = candidate.status; + const providerRetryAfterMs = candidate.providerRetryAfterMs; + const requestId = candidate.requestId; + if (typeof message !== "string" || message.length === 0 || typeof code !== "string" || code.length === 0 || status !== void 0 && (!Number.isInteger(status) || status < 100 || status > 599) || providerRetryAfterMs !== void 0 && (!Number.isFinite(providerRetryAfterMs) || providerRetryAfterMs <= 0) || requestId !== void 0 && (typeof requestId !== "string" || requestId.length === 0)) return void 0; + return Object.freeze({ + message, + code, + ...status === void 0 ? {} : { status }, + ...providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs }, + ...requestId === void 0 ? {} : { requestId } + }); + } catch (_sdkFailureGetter) { + return; + } +} +/** Read an SDK error message without letting an accessor replace the primary failure. */ +function errorMessage(error) { + try { + const message = error.message; + if (typeof message === "string" && message.length > 0) return message; + } catch (_sdkMessageGetter) {} + return "LLM adapter failed"; +} +/** Trust only Harness-owned codes; third-party SDK codes are not our taxonomy. */ +function harnessErrorCode(error) { + return error instanceof HarnessError ? error.code : "UNKNOWN"; +} +//#endregion +//#region lib/types/api-key.js +/** +* The one definition of a well-formed provider API key, shared by every +* adapter that puts one in an HTTP header. +* @module @deepseek-ai/dsh-llm/api-key +*/ +/** +* Characters an HTTP header value carries verbatim and every known provider +* key uses: printable ASCII, space excluded. A key outside this set cannot +* reach any provider — `fetch` refuses to build the header — so this is a +* transport invariant rather than one provider's policy. Latin-1 is excluded +* deliberately: a header could carry it, but no provider issues it, and +* admitting it trades a local explained refusal for an opaque 401. +*/ +const LEGAL_API_KEY = /^[\x21-\x7E]+$/; +/** +* Judge one *supplied* API key, trimming surrounding whitespace first. +* +* Trimming is silent because a padded key has one unambiguous reading; every +* other defect is reported. Absence is a configuration state this function +* never sees — a profile naming no credential authenticates through the +* provider's own ambient discovery or OAuth — so callers decide whether a +* value was supplied before asking. +* @param raw - the key exactly as configured, stored, or typed. +* @returns the trimmed key, or why it cannot be used. +*/ +function normalizeApiKey(raw) { + const value = raw.trim(); + if (value.length === 0) return { + ok: false, + reason: "empty" + }; + if (!LEGAL_API_KEY.test(value)) return { + ok: false, + reason: "illegalCharacters" + }; + return { + ok: true, + value + }; +} +//#endregion +//#region lib/types/attribution.js +/** +* Centralize the non-secret product identity every provider request sends as `User-Agent`, keeping +* adapters from drifting. See +* `.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md`. +* +* App-attribution vocabulary for provider requests. +* @module @deepseek-ai/dsh-llm/attribution +*/ +const { version } = createRequire(import.meta.url)("../package.json"); +/** +* The harness's own identity: the default every adapter sends. Deployments +* that need a white-label identity pass their own {@link AppIdentity} to +* {@link attributionHeaders} — omission falls back to this default; nothing +* can suppress attribution entirely. +*/ +const APP_IDENTITY = { + product: "deepseek-harness", + version, + url: "https://github.com/deepseek-ai/deepseek-harness" +}; +/** +* The standard `User-Agent` value: `product/version (+url)`. The +* parenthesized `+url` comment is the conventional self-identification form +* (RFC 9110 §10.1.5 product + comment syntax). +* @param identity - the identity to render; defaults to {@link APP_IDENTITY}. +* @returns the ready-to-send header value. +*/ +function userAgent(identity = APP_IDENTITY) { + return `${identity.product}/${identity.version} (+${identity.url})`; +} +/** +* Build the attribution headers an adapter must send on every provider +* request. Header names are lowercase (HTTP field names are case-insensitive +* on the wire). +* @param identity - the identity to send; defaults to {@link APP_IDENTITY} — omission cannot suppress attribution. +* @returns headers to merge into the provider request (currently just `user-agent`). +*/ +function attributionHeaders(identity = APP_IDENTITY) { + return { "user-agent": userAgent(identity) }; +} +//#endregion +//#region lib/types/never.js +/** +* Exhaustiveness helper for closed core unions. Use {@link assertNever} at the default branch so a +* new variant fails compilation at every required handler. Do not use it for declaration-merged +* unions such as session events or content blocks: handle known variants and explicitly fall +* through because plugins may add valid unknown cases. +* @module @deepseek-ai/dsh-llm/never +*/ +/** +* Mark an unreachable closed-union branch. A newly unhandled typed variant fails at the call site; +* a value that escaped its type throws with diagnostics at runtime. +* @param value - the impossible value; typed `never` so an unhandled variant fails compilation at the call site. +* @param context - optional label (e.g. the switch site) prefixed into the throw message. +* @returns never — it always throws, with the offending value JSON-rendered in the message. +*/ +function assertNever(value, context) { + const rendered = JSON.stringify(value) ?? String(value); + throw new Error(`unreachable variant${context ? ` in ${context}` : ""}: ${rendered}`); +} +//#endregion +//#region lib/types/content.js +/** Content-block structure helpers. @module @deepseek-ai/dsh-llm/content */ +/** +* True when typed model content contains an image block, walking nested +* tool-result content. This is the one recursive image walk shared by every +* image policy (capability gating, text-only serialization, compaction +* survey), so a consumer cannot silently diverge on nesting depth. +* @param content - typed model content blocks. +* @returns whether any nested block is an image. +*/ +function contentHasImage(content) { + return content.some((block) => block.type === "image" || block.type === "tool-result" && contentHasImage(block.content)); +} +//#endregion +//#region lib/types/assembler.js +/** +* Incremental chunk-to-message assembler. This is the single canonical assembly +* algorithm used by the agent loop to build an assistant message from a chunk +* stream while logging the raw chunks for replay fidelity. +* +* @module @deepseek-ai/dsh-llm/assembler +*/ +/** +* Incrementally assembles raw {@link StreamChunk}s into complete +* {@link ContentBlock}s and a final assistant {@link Message}. +* +* The agent loop feeds it while logging raw chunks for replay fidelity, then +* reads `blocks()` / `message()` / `usage` / `finish` once the stream ends. +* +* Tolerant of delta-only protocols (no block-start/end); deltas arriving for +* an index already closed by `block-end` are ignored (malformed stream) so a +* misbehaving adapter cannot grow memory or corrupt a completed block. +*/ +var BlockAssembler = class { + partials = /* @__PURE__ */ new Map(); + order = []; + _usage; + _finish; + _replayState = void 0; + /** + * Feed one chunk into the assembly state. + * @param chunk - the next raw chunk, in stream order. + */ + push(chunk) { + switch (chunk.type) { + case "block-start": + if (!this.partials.has(chunk.index)) { + this.order.push(chunk.index); + this.partials.set(chunk.index, { + blockType: chunk.blockType, + text: "", + toolCallArguments: "" + }); + } + return; + case "text-delta": + case "reasoning-delta": { + const partial = this.ensure(chunk.index, chunk.type === "text-delta" ? "text" : "reasoning"); + if (partial.block) return; + partial.text += chunk.text; + return; + } + case "tool-call-delta": { + const partial = this.ensure(chunk.index, "tool-call"); + if (partial.block) return; + partial.toolCallId = chunk.id; + if (chunk.name) partial.toolCallName = chunk.name; + partial.toolCallArguments += chunk.argumentsDelta; + return; + } + case "block-end": { + const partial = this.ensure(chunk.index, chunk.block.type); + if (partial.block) return; + partial.block = chunk.block; + return; + } + case "usage": + this._usage = chunk.usage; + return; + case "finish": + this._finish = chunk.reason; + this._replayState = chunk.replayState; + return; + default: return assertNever(chunk, "BlockAssembler.push"); + } + } + ensure(index, blockType) { + let partial = this.partials.get(index); + if (!partial) { + partial = { + blockType, + text: "", + toolCallArguments: "" + }; + this.partials.set(index, partial); + this.order.push(index); + } + return partial; + } + assemble(partial, index) { + if (partial.block) return partial.block; + switch (partial.blockType) { + case "text": return { + type: "text", + text: partial.text + }; + case "reasoning": return { + type: "reasoning", + text: partial.text + }; + case "tool-call": return { + type: "tool-call", + id: partial.toolCallId ?? CallId(`call-${index}`), + name: partial.toolCallName ?? "", + arguments: partial.toolCallArguments + }; + default: throw new Error(`cannot assemble incomplete block of type "${partial.blockType}"`); + } + } + /** Invariant accessor: every index in `order` has a partial. */ + mustGet(index) { + const partial = this.partials.get(index); + if (!partial) throw new Error(`BlockAssembler invariant violated: no partial for index ${index}`); + return partial; + } + /** + * Assemble all blocks seen so far, in stream order. + * @returns one block per seen index, except that max-token truncation drops + * tool calls that cannot be executed safely; an open block assembles from + * its accumulated deltas (an unknown block type never closed by `block-end` throws). + */ + blocks() { + const blocks = this.order.map((index) => this.assemble(this.mustGet(index), index)); + return this.finish.kind === "max-tokens" ? blocks.filter((block) => block.type !== "tool-call") : blocks; + } + /** Usage from the `usage` chunk; undefined until one arrives. */ + get usage() { + return this._usage; + } + /** Finish reason from the `finish` chunk; `{kind: 'stop'}` when the stream ended without one. */ + get finish() { + return this._finish ?? { kind: "stop" }; + } + /** Adapter-private replay state from the terminal finish chunk, if any. */ + get replayState() { + return this._replayState; + } + /** + * The assembled assistant message. + * @param source - producer attribution for the assembled message. + * @returns a frozen assistant-role message over `blocks()` (same open-block assembly rules). + */ + message(source = { + kind: "plugin", + plugin: "dsh-llm/assembler" + }) { + return createMessage({ + role: "assistant", + content: this.blocks(), + source + }); + } +}; +//#endregion +//#region lib/types/index.js +/** +* LLM service: adapter registry with a waterfall-interceptable streaming call +* API. Exports the `LlmRuntime` default, the abstract `LlmAdapter` for +* provider backends, and `BlockAssembler` for chunk assembly. +* +* @module @deepseek-ai/dsh-llm +*/ +/** +* Typed error for LLM-related failures. Extends {@link HarnessError}, so the +* `code` string (e.g. `AUTH`, `RATE_LIMIT`, `NO_ADAPTER`) is shared taxonomy. +*/ +var LlmError = class extends HarnessError { + /** Serializable facts retained beside this live Error. */ + failure; + /** + * @param message - non-empty human-readable failure summary. + * @param code - non-empty stable provider-neutral machine code. + * @param options - optional cause and validated serializable provider facts. + */ + constructor(message, code, options) { + if (typeof message !== "string" || message.length === 0) throw new Error("LlmError message must be a non-empty string"); + if (typeof code !== "string" || code.length === 0) throw new Error("LlmError code must be a non-empty string"); + if (options?.status !== void 0 && (!Number.isInteger(options.status) || options.status < 100 || options.status > 599)) throw new Error("LlmError status must be an integer from 100 through 599"); + if (options?.providerRetryAfterMs !== void 0 && (!Number.isFinite(options.providerRetryAfterMs) || options.providerRetryAfterMs <= 0)) throw new Error("LlmError providerRetryAfterMs must be a positive finite number"); + if (options?.requestId !== void 0 && (typeof options.requestId !== "string" || options.requestId.length === 0)) throw new Error("LlmError requestId must be a non-empty string"); + super(message, code, options); + this.name = "LlmError"; + this.failure = Object.freeze({ + message, + code, + ...options?.status === void 0 ? {} : { status: options.status }, + ...options?.providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs: options.providerRetryAfterMs }, + ...options?.requestId === void 0 ? {} : { requestId: options.requestId } + }); + } +}; +/** +* Accept one supplied credential, or refuse it as unusable. +* +* A stored key arrives from the credentials seam, a `.env` line, or a shell +* export, all of which pick up surrounding whitespace, so trimming is silent. +* Anything else fails here rather than inside `fetch`, whose ByteString +* refusal names a UTF-16 code point instead of the setting to change. The key +* never enters the message: `ref` names where to fix it, and echoing any part +* of a secret into a log or a UI is the failure this diagnosis avoids. +* +* Lives beside {@link LlmError} rather than in `./api-key.ts` so the predicate +* module stays dependency-free; both adapters share this one diagnosis instead +* of keeping near-identical local copies. +* @param raw - the credential exactly as supplied. +* @param pkg - the refusing package name, prefixed to the diagnostic. +* @param ref - the credential reference the value resolved through. +* @returns the trimmed, usable key. +*/ +function assertUsableApiKey(raw, pkg, ref) { + const checked = normalizeApiKey(raw); + if (checked.ok) return checked.value; + throw new LlmError(checked.reason === "empty" ? `${pkg}: the API key resolved from ${ref} is blank; set ${ref} to the raw key (the web Models page writes it) or export it in the launching environment` : `${pkg}: the API key resolved from ${ref} contains characters no HTTP header can carry; set ${ref} to the raw key alone (the web Models page writes it)`, INVALID_CREDENTIAL_CODE); +} +/** +* Provider-wire adapter for the harness message and stream vocabulary. Register implementations +* with `ctx.llm.registerAdapter(providers, adapter)`. Every provider HTTP request must include +* `attributionHeaders()`; prove the headers are added in the wire request or library header hook. The direct-fetch +* DeepSeek and library-backed pi-ai adapters meet this contract through different internals. +*/ +var LlmAdapter = class { + /** + * Describe one provider route owned by this adapter. + * @param provider - a route passed to `registerAdapter()` for this instance. + * @returns detached display metadata whose id must equal `provider`. + */ + providerInfo(provider) { + return { + id: provider, + name: provider + }; + } + /** + * Return the provider-owned retry policy captured with this route. + * @param _provider - a route passed to `registerAdapter()` for this instance. + * @returns a resolved policy, or `undefined` to use the normal defaults. + */ + providerRetryPolicy(_provider) {} + /** + * List models this adapter can currently advertise for one owned provider. + * The result is advisory: an adapter may accept unlisted model ids, and + * consumers must not turn absence into request rejection. + * @param _provider - one provider route owned by this adapter. + * @returns discoverable models in adapter-preferred order. + */ + listModels(_provider) { + return Promise.resolve([]); + } + /** + * Resolve all metadata available for one exact model. This query is + * independent of the advisory catalog and does not validate request routing. + * @param provider - one provider route owned by this adapter. + * @param model - exact model id passed to {@link GenerateOptions.model}. + * @param _signal - cancellation for this exact-model lookup; asynchronous + * implementations must settle promptly after it aborts. + * @returns provider/model identity plus any context, call-default, and reasoning metadata. + */ + resolveModel(provider, model, _signal) { + return Promise.resolve({ + provider, + id: model, + name: model + }); + } +}; +/** +* The abstract `llm` service: an adapter registry plus a streaming model-call +* API, interceptable via the `llm/stream` waterfall. +*/ +var LlmRuntime = class extends Service { + adapters = /* @__PURE__ */ new Map(); + directory = /* @__PURE__ */ new Map(); + discoveries = /* @__PURE__ */ new Map(); + constructor(ctx) { + super(ctx, "llm"); + } + /** Notify topology observers without letting one broken listener veto the commit. */ + emitAdaptersUpdated() { + let invariantFailure; + for (const listener of this.ctx.events.dispatch("emit", ["llm/adapters-updated"])) try { + const returned = listener(); + if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => { + this.warnAdaptersListenerFailure(error); + }); + } catch (error) { + if (error?.code === "INVARIANT") { + invariantFailure ??= error; + continue; + } + this.warnAdaptersListenerFailure(error); + } + if (invariantFailure !== void 0) throw invariantFailure; + } + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnAdaptersListenerFailure(error) { + this.ctx.logger.warn("llm: an llm/adapters-updated listener failed"); + this.ctx.logger.warn(error); + } + /** + * Register an adapter for the given provider routes. Throws `LlmError` with code + * `DUPLICATE_ADAPTER` if any provider already has an adapter (all-or-nothing). + * Disposed with the fiber. + * @param providers - every provider route this adapter should serve. + * @param adapter - the adapter that streams calls for those providers. + * @returns the disposer, carrying {@link AdapterRegistrationHandle.replace}. + */ + registerAdapter(providers, adapter) { + const owned = /* @__PURE__ */ new Set(); + let released = false; + const dispose = this.ctx.effect(function* () { + if (providers.length === 0) throw new LlmError("an adapter must register at least one provider", "INVALID_ADAPTER"); + this.commitRoutes(owned, this.prepareRoutes(providers, adapter, owned)); + yield () => { + released = true; + for (const provider of owned) this.adapters.delete(provider); + owned.clear(); + this.emitAdaptersUpdated(); + }; + }.bind(this), "llm.registerAdapter()"); + const handle = (() => void dispose()); + handle.replace = (next) => { + if (released) throw new LlmError("a disposed adapter registration cannot replace its routes", "REGISTRATION_DISPOSED"); + this.commitRoutes(owned, this.prepareRoutes(next, adapter, owned)); + }; + return handle; + } + /** + * Validate one candidate route set for `adapter`, treating routes this + * registration already holds as available. Nothing is mutated: a rejected + * candidate leaves the registry exactly as it was. + */ + prepareRoutes(providers, adapter, owned) { + const unique = /* @__PURE__ */ new Set(); + const registrations = []; + for (const provider of providers) { + if (provider.length === 0) throw new LlmError("adapter provider names must be non-empty", "INVALID_ADAPTER"); + if (unique.has(provider) || this.adapters.has(provider) && !owned.has(provider)) throw new LlmError(`an adapter for provider "${provider}" is already registered`, "DUPLICATE_ADAPTER"); + const info = adapter.providerInfo(provider); + if (typeof info.id !== "string" || info.id !== provider || typeof info.name !== "string" || info.name.length === 0) throw new LlmError(`adapter metadata for provider "${provider}" must preserve its id and have a non-empty name`, "INVALID_ADAPTER"); + unique.add(provider); + const retryPolicy = adapter.providerRetryPolicy(provider) ?? resolveRetryPolicy(void 0, `llm: provider "${provider}" retryPolicy`); + registrations.push({ + adapter, + provider: { + id: info.id, + name: info.name + }, + retryPolicy + }); + } + return registrations; + } + /** + * Swap this registration's routes for the prepared ones in one synchronous + * section, so no observer can see the registry between the release and the + * re-registration. The route set's one mutation point is also where + * `llm/adapters-updated` is published, so a `replace` announces itself + * exactly like a first registration. + */ + commitRoutes(owned, registrations) { + for (const provider of owned) this.adapters.delete(provider); + owned.clear(); + for (const registration of registrations) { + this.adapters.set(registration.provider.id, registration); + owned.add(registration.provider.id); + } + this.emitAdaptersUpdated(); + } + /** + * Describe provider routes with a registered adapter. + * @returns detached provider metadata in registration order. + */ + listProviders() { + return [...this.adapters.values()].map(({ provider }) => ({ ...provider })); + } + /** + * Declare provider routes an adapter plugin can activate through + * configuration. Registration is all-or-nothing: an empty list, invalid + * entry, or a provider already declared by any registration throws + * `LlmError` without registering the rest. Disposed with the fiber. + * @param entries - every configurable provider this plugin owns. + * @returns a handle that withdraws all of them, and can atomically replace them. + */ + registerConfigurableProviders(entries) { + let held = []; + let disposed = false; + /** + * Validate a candidate set in full against everything this registration + * does not already hold, then publish it. Nothing is written until the + * whole set passes, so a refused candidate leaves the current entries in + * place — the property that makes `replace` a swap rather than a + * delete-then-add that can strand the directory empty. + */ + const commit = (candidates) => { + const detached = []; + const own = new Set(held.map((entry) => entry.provider)); + for (const entry of candidates) { + if (entry.provider.length === 0 || entry.displayName.length === 0 || entry.settingsNs.length === 0) throw new LlmError("configurable providers need a non-empty provider, displayName, and settingsNs", "INVALID_DIRECTORY"); + if (entry.settingsPath.some((segment) => segment.length === 0)) throw new LlmError(`configurable provider "${entry.provider}" has an empty settingsPath segment`, "INVALID_DIRECTORY"); + if (this.directory.has(entry.provider) && !own.has(entry.provider) || detached.some((seen) => seen.provider === entry.provider)) throw new LlmError(`configurable provider "${entry.provider}" is already declared`, "DUPLICATE_DIRECTORY"); + detached.push({ + ...entry, + settingsPath: [...entry.settingsPath] + }); + } + for (const entry of held) this.directory.delete(entry.provider); + for (const entry of detached) this.directory.set(entry.provider, entry); + held = detached; + this.emitAdaptersUpdated(); + }; + const dispose = this.ctx.effect(function* () { + if (entries.length === 0) throw new LlmError("a configurable-provider registration must declare at least one provider", "INVALID_DIRECTORY"); + commit(entries); + yield () => { + disposed = true; + for (const entry of held) this.directory.delete(entry.provider); + held = []; + this.emitAdaptersUpdated(); + }; + }.bind(this), "llm.registerConfigurableProviders()"); + const handle = (() => void dispose()); + handle.replace = (next) => { + if (disposed) throw new LlmError("this configurable-provider registration was disposed", "REGISTRATION_DISPOSED"); + commit(next); + }; + return handle; + } + /** + * List every declared configurable provider, registered or dormant. + * @returns detached directory entries in declaration order. + */ + listConfigurableProviders() { + return [...this.directory.values()].map((entry) => ({ + ...entry, + settingsPath: [...entry.settingsPath] + })); + } + /** + * Offer to interrogate provider endpoints on behalf of the settings + * namespace this plugin owns. The namespace is the key because that is what + * a configuration surface already holds from the configurable-provider + * directory, and because a provider being *added* has no route to name yet. + * Disposed with the fiber. + * @param settingsNs - the namespace whose profiles this discovery serves. + * @param discover - interrogates one endpoint; must honor `request.signal`. + * @returns the disposer that withdraws the offer. + */ + registerModelDiscovery(settingsNs, discover) { + const dispose = this.ctx.effect(function* () { + if (settingsNs.length === 0) throw new LlmError("model discovery needs a non-empty settings namespace", "INVALID_DISCOVERY"); + if (this.discoveries.has(settingsNs)) throw new LlmError(`model discovery for "${settingsNs}" is already registered`, "DUPLICATE_DISCOVERY"); + this.discoveries.set(settingsNs, discover); + yield () => { + this.discoveries.delete(settingsNs); + }; + }.bind(this), "llm.registerModelDiscovery()"); + return () => void dispose(); + } + /** + * Interrogate one provider endpoint for the models it advertises. The + * request describes a draft, not a stored route, so nothing here reads or + * writes settings or credentials — the caller owns both, and the reply is + * candidate metadata a surface may offer for adoption. + * @param settingsNs - namespace whose registered discovery serves this draft. + * @param request - the endpoint, protocol, and one-shot credential to use. + * @returns the advertised models, deduplicated in endpoint order. + */ + async discoverModels(settingsNs, request) { + const discover = this.discoveries.get(settingsNs); + if (discover === void 0) throw new LlmError(`no model discovery is registered for "${settingsNs}"`, "NO_DISCOVERY"); + if ((request.provider ?? "").length === 0 && (request.baseURL ?? "").length === 0) throw new LlmError("model discovery needs a provider route or a baseURL", "INVALID_DISCOVERY"); + const discovered = await discover(request); + const seen = /* @__PURE__ */ new Set(); + const models = []; + for (const model of discovered) { + if (typeof model.id !== "string" || model.id.length === 0 || seen.has(model.id)) continue; + seen.add(model.id); + models.push({ + id: model.id, + ...model.name === void 0 ? {} : { name: model.name }, + ...model.contextWindow === void 0 ? {} : { contextWindow: model.contextWindow }, + ...model.maxTokens === void 0 ? {} : { maxTokens: model.maxTokens } + }); + } + return models; + } + /** + * Resolve the retry policy captured when one provider route was registered. + * @param provider - registered provider route to inspect. + * @returns the provider-owned policy, with normal defaults already resolved. + */ + providerRetryPolicy(provider) { + return this.registration(provider).retryPolicy; + } + /** Detach typed adapter-owned modality metadata. */ + detachedModalities(modalities) { + return modalities === void 0 ? void 0 : [...modalities]; + } + /** + * Discover models advertised by one registered provider. Catalog membership + * is advisory and never changes routing or request validation. + * @param provider - registered provider route to inspect. + * @returns detached model metadata in adapter-preferred order. + */ + async listModels(provider) { + const models = await this.registration(provider).adapter.listModels(provider); + const seen = /* @__PURE__ */ new Set(); + return models.map((model) => { + if (typeof model.provider !== "string" || model.provider !== provider || typeof model.id !== "string" || model.id.length === 0 || typeof model.name !== "string" || model.name.length === 0 || model.description !== void 0 && typeof model.description !== "string" || seen.has(model.id)) throw new LlmError(`adapter returned invalid or duplicate model metadata for provider "${provider}"`, "INVALID_CATALOG"); + seen.add(model.id); + const inputModalities = this.detachedModalities(model.inputModalities); + return { + provider: model.provider, + id: model.id, + name: model.name, + ...model.description === void 0 ? {} : { description: model.description }, + ...inputModalities === void 0 ? {} : { inputModalities } + }; + }); + } + /** + * Resolve and validate all metadata from the adapter that owns one exact + * route. The result is detached from adapter-owned objects; catalog + * membership remains advisory and does not control request routing. + * @param provider - registered provider route to inspect. + * @param model - exact model id passed to the adapter. + * @param signal - optional cancellation for adapter-owned asynchronous lookup. + * @returns exact model identity plus available context and reasoning metadata. + */ + async resolveModelInfo(provider, model, signal) { + return this.resolveModelInfoFor(this.registration(provider), model, signal); + } + async resolveModelInfoFor(registration, model, signal) { + const provider = registration.provider.id; + const resolved = await registration.adapter.resolveModel(provider, model, signal); + if (typeof resolved.provider !== "string" || resolved.provider !== provider || typeof resolved.id !== "string" || resolved.id !== model || typeof resolved.name !== "string" || resolved.name.length === 0 || resolved.description !== void 0 && typeof resolved.description !== "string") throw new LlmError(`adapter returned invalid exact model metadata for provider "${provider}" model "${model}"`, "INVALID_MODEL_INFO"); + const context = resolved.context; + if (context !== void 0 && (!Number.isInteger(context.contextWindow) || context.contextWindow <= 0)) throw new LlmError(`adapter returned invalid context metadata for provider "${provider}" model "${model}"`, "INVALID_MODEL_CONTEXT"); + const inputModalities = this.detachedModalities(resolved.inputModalities); + const defaultMaxTokens = resolved.defaultMaxTokens; + if (defaultMaxTokens !== void 0 && (!Number.isSafeInteger(defaultMaxTokens) || defaultMaxTokens <= 0)) throw new LlmError(`adapter returned invalid default maxTokens for provider "${provider}" model "${model}"`, "INVALID_MODEL_MAX_TOKENS"); + const info = { + provider, + id: model, + name: resolved.name, + ...resolved.description === void 0 ? {} : { description: resolved.description }, + ...inputModalities === void 0 ? {} : { inputModalities }, + ...context === void 0 ? {} : { context: { contextWindow: context.contextWindow } }, + ...defaultMaxTokens === void 0 ? {} : { defaultMaxTokens } + }; + const reasoning = resolved.reasoning; + if (reasoning === void 0) return info; + if (reasoning.efforts.length === 0) throw new LlmError(`adapter returned invalid reasoning metadata for provider "${provider}" model "${model}"`, "INVALID_MODEL_REASONING"); + const seen = /* @__PURE__ */ new Set(); + const efforts = reasoning.efforts.map((effort) => { + if (typeof effort.id !== "string" || effort.id.length === 0 || typeof effort.name !== "string" || effort.name.length === 0 || effort.description !== void 0 && typeof effort.description !== "string" || seen.has(effort.id)) throw new LlmError(`adapter returned invalid or duplicate reasoning effort metadata for provider "${provider}" model "${model}"`, "INVALID_MODEL_REASONING"); + seen.add(effort.id); + return { + id: effort.id, + name: effort.name, + ...effort.description === void 0 ? {} : { description: effort.description } + }; + }); + if (reasoning.defaultEffort !== void 0 && !seen.has(reasoning.defaultEffort)) throw new LlmError(`adapter returned an unknown default reasoning effort for provider "${provider}" model "${model}"`, "INVALID_MODEL_REASONING"); + return { + ...info, + reasoning: { + efforts, + ...reasoning.defaultEffort === void 0 ? {} : { defaultEffort: reasoning.defaultEffort } + } + }; + } + /** + * Validate a conversation call config against its exact model capability and + * materialize adapter-configured defaults. Unsupported explicit efforts + * reject before provider I/O; no clamping or aliasing is performed. This + * standalone query does not bind a later dispatch; use {@link prepareCall} + * when logging and streaming must share one adapter registration. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a detached config only when a default must be materialized. + */ + async resolveCallConfig(config, signal) { + return (await this.resolveCallFor(this.registration(config.provider), config, signal)).config; + } + async resolveCallFor(registration, config, signal) { + const info = await this.resolveModelInfoFor(registration, config.model, signal); + const defaulted = config.maxTokens === void 0 && info.defaultMaxTokens !== void 0 ? { + ...config, + maxTokens: info.defaultMaxTokens + } : config; + const reasoning = info.reasoning; + const requested = defaulted.reasoningEffort; + let resolvedConfig = defaulted; + if (reasoning === void 0) { + if (requested !== void 0) throw new LlmError(`provider "${config.provider}" model "${config.model}" does not support reasoning effort "${requested}"`, "UNSUPPORTED_REASONING_EFFORT"); + } else { + const effective = requested ?? reasoning.defaultEffort; + if (effective !== void 0) { + if (!reasoning.efforts.some((effort) => effort.id === effective)) throw new LlmError(`provider "${config.provider}" model "${config.model}" does not support reasoning effort "${effective}"`, "UNSUPPORTED_REASONING_EFFORT"); + if (requested !== effective) resolvedConfig = { + ...defaulted, + reasoningEffort: effective + }; + } + } + return { + config: resolvedConfig, + ...info.context === void 0 ? {} : { context: info.context } + }; + } + /** + * Resolve one call under its current adapter registration. The returned + * one-shot handle keeps that registration across header logging and dispatch, + * so HMR cannot combine one adapter's capability result with another adapter. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a prepared config and its registration-bound stream entry point. + */ + async prepareCall(config, signal) { + const registration = this.registration(config.provider); + const resolved = await this.resolveCallFor(registration, config, signal); + const resolvedConfig = deepFreeze(structuredClone(resolved.config)); + const context = resolved.context === void 0 ? void 0 : deepFreeze(structuredClone(resolved.context)); + const adapterDefaults = deepFreeze({ + ...config.reasoningEffort === void 0 && resolvedConfig.reasoningEffort !== void 0 ? { reasoningEffort: true } : {}, + ...config.maxTokens === void 0 && resolvedConfig.maxTokens !== void 0 ? { maxTokens: true } : {} + }); + let dispatched = false; + return Object.freeze({ + config: resolvedConfig, + retryPolicy: registration.retryPolicy, + adapterDefaults, + ...context === void 0 ? {} : { context }, + stream: (options) => { + if (dispatched) throw new LlmError("a prepared LLM call can only be dispatched once", "INVALID_PREPARED_CALL"); + if (!callConfigEquals(options, resolvedConfig)) throw new LlmError("prepared LLM call config changed before adapter dispatch", "INVALID_PREPARED_CALL"); + dispatched = true; + return this.streamWithRegistration(options, { + registration, + config: resolvedConfig + }); + } + }); + } + registration(provider) { + const registration = this.adapters.get(provider); + if (!registration) throw new LlmError(`no adapter registered for provider "${provider}"`, "NO_ADAPTER"); + return registration; + } + /** Remove replay state whose historical route is owned by another adapter. */ + forAdapter(options, adapter) { + const messages = options.messages.map((message) => { + const source = message.source; + if (message.role !== "assistant" || source.kind !== "model" || source.replayState === void 0) return message; + if (this.adapters.get(source.provider)?.adapter === adapter) return message; + return freezeMessage({ + ...message, + source: { + kind: "model", + provider: source.provider, + model: source.model + } + }); + }); + if (messages.every((message, index) => message === options.messages[index])) return options; + const filtered = { + ...options, + messages + }; + return Object.isFrozen(options) ? deepFreeze(filtered) : filtered; + } + /** + * Final adapter boundary. Adapter selection, dispatch, iterator construction, + * and iteration failures become one terminal failure chunk. Middleware and + * downstream consumer failures remain thrown plugin or consumer errors. + */ + async *adapterStream(options, prepared) { + let iterator; + try { + const registration = prepared?.registration ?? this.registration(options.provider); + const resolvedConfig = prepared === void 0 ? (await this.resolveCallFor(registration, options, options.signal)).config : prepared.config; + if (prepared !== void 0 && !callConfigEquals(options, resolvedConfig)) throw new LlmError("prepared LLM call config changed before adapter dispatch", "INVALID_PREPARED_CALL"); + const resolvedOptions = callConfigEquals(options, resolvedConfig) ? options : Object.isFrozen(options) ? deepFreeze({ + ...options, + ...resolvedConfig + }) : { + ...options, + ...resolvedConfig + }; + const adapter = registration.adapter; + iterator = adapter.stream(this.forAdapter(resolvedOptions, adapter))[Symbol.asyncIterator](); + } catch (error) { + yield adapterFailureChunk(error, options.signal); + return; + } + let completed = false; + try { + while (true) { + let item; + try { + const next = await iterator.next(); + item = next.done ? { done: true } : { + done: false, + value: next.value + }; + } catch (error) { + completed = true; + yield adapterFailureChunk(error, options.signal); + return; + } + if (item.done) { + completed = true; + return; + } + yield item.value; + } + } finally { + if (!completed) { + const close = iterator.return?.bind(iterator); + if (close) await close(); + } + } + } + /** + * Stream one model call as raw chunks (token-level deltas). Replay state is + * retained only when the same adapter instance owns its historical provider + * and the target provider. Final adapter selection remains fixed through + * asynchronous exact-model resolution and dispatch. Adapter selection, + * dispatch, and iteration failures become terminal `error` or `aborted` + * finish chunks; middleware, nested-call, cleanup, and consumer failures + * remain thrown. + * @param options - the full request; `options.provider` selects the adapter. + * @returns the chunk stream, possibly wrapped by `llm/stream` listeners. + */ + stream(options) { + return this.streamWithRegistration(options); + } + streamWithRegistration(options, prepared) { + return this.ctx.waterfall(this, "llm/stream", options, () => this.adapterStream(options, prepared)); + } +}; +/** Convert one adapter throw into the stream protocol's terminal outcome. */ +function adapterFailureChunk(error, signal) { + const failure = normalizeLlmFailure(error); + return { + type: "finish", + reason: signal?.aborted || failure.code === "ABORTED" ? { + kind: "aborted", + failure + } : { + kind: "error", + failure + } + }; +} +//#endregion +export { APP_IDENTITY, BlockAssembler, CONTEXT_SUMMARY_MAX_CHARS, CONTEXT_WINDOW_EXCEEDED_CODE, CallId, EMPTY_RESPONSE_CODE, HarnessError, INVALID_CREDENTIAL_CODE, LlmAdapter, LlmError, LlmRuntime, LlmRuntime as default, MessageId, ProviderRequestId, QUOTA_EXCEEDED_CODE, ReasoningEffortId, RetryPolicySchema, assertNever, assertUsableApiKey, attributionHeaders, boundContextSummary, callConfigEquals, contentHasImage, createAssistantMessage, createMessage, createToolResultMessage, createUserMessage, deepFreeze, errorChain, freezeMessage, isAgentLoopRequest, isContextWindowExceededError, isHarnessError, isQuotaExceededError, isTokenDelta, markAgentLoopRequest, normalizeApiKey, resolveRetryPolicy, userAgent }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/invariant.js new file mode 100644 index 0000000..8b97724 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/invariant.js @@ -0,0 +1,84 @@ +//#region lib/types/invariant.js +/** Package-owned LLM stream-protocol invariants. @module @deepseek-ai/dsh-llm/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-llm"; +/** Cordis companion plugin name. */ +const name = "llm-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Require one chunk index to be a non-negative safe integer. */ +function validateIndex(index, fail) { + if (!Number.isSafeInteger(index) || index < 0) fail(`LLM stream block index must be a non-negative safe integer, got ${index}`); +} +/** Require a delta to address an open block of its matching type. */ +function validateDelta(open, index, expected, fail) { + validateIndex(index, fail); + const actual = open.get(index); + if (actual !== expected) fail(`${expected} delta at index ${index} requires an open ${expected} block, got ${String(actual)}`); +} +/** Wrap one provider stream and enforce its grammar as chunks are consumed. */ +async function* validateStream(source, fail) { + const open = /* @__PURE__ */ new Map(); + let usageSeen = false; + let finished = false; + for await (const chunk of source) { + if (finished) fail(`LLM stream emitted ${chunk.type} after terminal finish`); + switch (chunk.type) { + case "block-start": + validateIndex(chunk.index, fail); + if (open.has(chunk.index)) fail(`LLM stream repeated block-start index ${chunk.index}`); + open.set(chunk.index, chunk.blockType); + break; + case "text-delta": + validateDelta(open, chunk.index, "text", fail); + break; + case "reasoning-delta": + validateDelta(open, chunk.index, "reasoning", fail); + break; + case "tool-call-delta": + validateDelta(open, chunk.index, "tool-call", fail); + break; + case "block-end": { + validateIndex(chunk.index, fail); + const blockType = open.get(chunk.index); + if (blockType === void 0) fail(`LLM stream block-end index ${chunk.index} has no open block`); + if (chunk.block.type !== blockType) fail(`LLM stream block-end index ${chunk.index} closes ${chunk.block.type}, expected ${blockType}`); + open.delete(chunk.index); + break; + } + case "usage": + if (usageSeen) fail("LLM stream emitted usage more than once"); + usageSeen = true; + break; + case "finish": + if (open.size > 0 && chunk.reason.kind !== "error" && chunk.reason.kind !== "aborted") fail(`LLM stream finished with ${open.size} open block(s)`); + finished = true; + break; + } + yield chunk; + } + if (!finished) fail("LLM stream ended without a terminal finish chunk"); +} +/** Install validation around every provider stream. */ +const install = (ctx, fail) => { + ctx.on("llm/stream", (_options, next) => validateStream(next(), fail), { + global: true, + prepend: true + }); + ctx.on("llm/adapters-updated", () => { + const llm = ctx.get("llm"); + if (llm === void 0) return; + for (const provider of llm.listProviders()) try { + llm.providerRetryPolicy(provider.id); + } catch { + fail(`llm/adapters-updated fired while provider "${provider.id}" has no readable registration`); + } + }, { global: true }); +}; +/** +* Register the LLM invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.d.ts new file mode 100644 index 0000000..2bde887 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.d.ts @@ -0,0 +1,14 @@ +/** + * Normalization for values thrown by a final LLM adapter boundary. + * + * @module @deepseek-ai/dsh-llm/adapter-failure + */ +import type { LlmFailure } from './types.ts'; +/** + * Detach serializable provider facts from a value thrown by an adapter. + * @param value - arbitrary value thrown during adapter dispatch or iteration. + * @returns immutable provider-neutral facts suitable for a terminal finish chunk. + * @internal + */ +export declare function normalizeLlmFailure(value: unknown): LlmFailure; +//# sourceMappingURL=adapter-failure.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.js new file mode 100644 index 0000000..86ad05d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.js @@ -0,0 +1,105 @@ +/** + * Normalization for values thrown by a final LLM adapter boundary. + * + * @module @deepseek-ai/dsh-llm/adapter-failure + */ +import { HarnessError } from "./error.js"; +/** + * Detach serializable provider facts from a value thrown by an adapter. + * @param value - arbitrary value thrown during adapter dispatch or iteration. + * @returns immutable provider-neutral facts suitable for a terminal finish chunk. + * @internal + */ +export function normalizeLlmFailure(value) { + const error = value instanceof Error + ? value + : new HarnessError(thrownMessage(value), 'UNKNOWN', { cause: value }); + // Cross-package copies preserve own data but not class identity. Trust the + // carried facts only when both own properties agree after validation. + const carried = ownFailureSnapshot(error); + if (carried !== undefined && carried.code === ownErrorCode(error)) + return carried; + return Object.freeze({ + message: errorMessage(error), + code: harnessErrorCode(error), + }); +} +/** Render a non-Error throw without letting hostile coercion escape normalization. */ +function thrownMessage(value) { + try { + const message = String(value); + return message.length > 0 ? message : 'LLM adapter failed'; + } + catch (_hostileThrownValue) { + return 'LLM adapter failed'; + } +} +/** Read a foreign error's own data-backed `code` without invoking accessors. */ +function ownErrorCode(error) { + try { + const descriptor = Object.getOwnPropertyDescriptor(error, 'code'); + return descriptor !== undefined && 'value' in descriptor ? descriptor.value : undefined; + } + catch (_sdkPropertyTrap) { + return undefined; + } +} +/** Snapshot an own data property without invoking an SDK-defined accessor. */ +function ownFailureSnapshot(error) { + try { + const descriptor = Object.getOwnPropertyDescriptor(error, 'failure'); + return descriptor !== undefined && 'value' in descriptor + ? failureSnapshot(descriptor.value) + : undefined; + } + catch (_sdkPropertyTrap) { + return undefined; + } +} +/** Validate and detach an arbitrary serializable failure payload. */ +function failureSnapshot(value) { + if (typeof value !== 'object' || value === null) + return undefined; + try { + const candidate = value; + const message = candidate.message; + const code = candidate.code; + const status = candidate.status; + const providerRetryAfterMs = candidate.providerRetryAfterMs; + const requestId = candidate.requestId; + if (typeof message !== 'string' || message.length === 0 + || typeof code !== 'string' || code.length === 0 + || (status !== undefined && (!Number.isInteger(status) || status < 100 || status > 599)) + || (providerRetryAfterMs !== undefined + && (!Number.isFinite(providerRetryAfterMs) || providerRetryAfterMs <= 0)) + || (requestId !== undefined && (typeof requestId !== 'string' || requestId.length === 0))) + return undefined; + return Object.freeze({ + message, + code, + ...status === undefined ? {} : { status }, + ...providerRetryAfterMs === undefined ? {} : { providerRetryAfterMs }, + ...requestId === undefined ? {} : { requestId }, + }); + } + catch (_sdkFailureGetter) { + return undefined; + } +} +/** Read an SDK error message without letting an accessor replace the primary failure. */ +function errorMessage(error) { + try { + const message = error.message; + if (typeof message === 'string' && message.length > 0) + return message; + } + catch (_sdkMessageGetter) { + // The fallback below preserves a serializable failure beside the original Error. + } + return 'LLM adapter failed'; +} +/** Trust only Harness-owned codes; third-party SDK codes are not our taxonomy. */ +function harnessErrorCode(error) { + return error instanceof HarnessError ? error.code : 'UNKNOWN'; +} +//# sourceMappingURL=adapter-failure.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.d.ts new file mode 100644 index 0000000..dfad49c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.d.ts @@ -0,0 +1,28 @@ +/** + * The one definition of a well-formed provider API key, shared by every + * adapter that puts one in an HTTP header. + * @module @deepseek-ai/dsh-llm/api-key + */ +/** Why a supplied API key cannot be used. */ +export type ApiKeyRejection = 'empty' | 'illegalCharacters'; +/** The verdict on one supplied API key. */ +export type ApiKeyCheck = { + readonly ok: true; + readonly value: string; +} | { + readonly ok: false; + readonly reason: ApiKeyRejection; +}; +/** + * Judge one *supplied* API key, trimming surrounding whitespace first. + * + * Trimming is silent because a padded key has one unambiguous reading; every + * other defect is reported. Absence is a configuration state this function + * never sees — a profile naming no credential authenticates through the + * provider's own ambient discovery or OAuth — so callers decide whether a + * value was supplied before asking. + * @param raw - the key exactly as configured, stored, or typed. + * @returns the trimmed key, or why it cannot be used. + */ +export declare function normalizeApiKey(raw: string): ApiKeyCheck; +//# sourceMappingURL=api-key.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.js new file mode 100644 index 0000000..37e78db --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.js @@ -0,0 +1,34 @@ +/** + * The one definition of a well-formed provider API key, shared by every + * adapter that puts one in an HTTP header. + * @module @deepseek-ai/dsh-llm/api-key + */ +/** + * Characters an HTTP header value carries verbatim and every known provider + * key uses: printable ASCII, space excluded. A key outside this set cannot + * reach any provider — `fetch` refuses to build the header — so this is a + * transport invariant rather than one provider's policy. Latin-1 is excluded + * deliberately: a header could carry it, but no provider issues it, and + * admitting it trades a local explained refusal for an opaque 401. + */ +const LEGAL_API_KEY = /^[\x21-\x7E]+$/; +/** + * Judge one *supplied* API key, trimming surrounding whitespace first. + * + * Trimming is silent because a padded key has one unambiguous reading; every + * other defect is reported. Absence is a configuration state this function + * never sees — a profile naming no credential authenticates through the + * provider's own ambient discovery or OAuth — so callers decide whether a + * value was supplied before asking. + * @param raw - the key exactly as configured, stored, or typed. + * @returns the trimmed key, or why it cannot be used. + */ +export function normalizeApiKey(raw) { + const value = raw.trim(); + if (value.length === 0) + return { ok: false, reason: 'empty' }; + if (!LEGAL_API_KEY.test(value)) + return { ok: false, reason: 'illegalCharacters' }; + return { ok: true, value }; +} +//# sourceMappingURL=api-key.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.d.ts new file mode 100644 index 0000000..dbbf35b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.d.ts @@ -0,0 +1,56 @@ +/** + * Incremental chunk-to-message assembler. This is the single canonical assembly + * algorithm used by the agent loop to build an assistant message from a chunk + * stream while logging the raw chunks for replay fidelity. + * + * @module @deepseek-ai/dsh-llm/assembler + */ +import type { Message, MessageSource } from './message.ts'; +import type { ContentBlock, FinishReason, StreamChunk, TokenUsage } from './types.ts'; +/** + * Incrementally assembles raw {@link StreamChunk}s into complete + * {@link ContentBlock}s and a final assistant {@link Message}. + * + * The agent loop feeds it while logging raw chunks for replay fidelity, then + * reads `blocks()` / `message()` / `usage` / `finish` once the stream ends. + * + * Tolerant of delta-only protocols (no block-start/end); deltas arriving for + * an index already closed by `block-end` are ignored (malformed stream) so a + * misbehaving adapter cannot grow memory or corrupt a completed block. + */ +export declare class BlockAssembler { + private partials; + private order; + private _usage; + private _finish; + private _replayState; + /** + * Feed one chunk into the assembly state. + * @param chunk - the next raw chunk, in stream order. + */ + push(chunk: StreamChunk): void; + private ensure; + private assemble; + /** Invariant accessor: every index in `order` has a partial. */ + private mustGet; + /** + * Assemble all blocks seen so far, in stream order. + * @returns one block per seen index, except that max-token truncation drops + * tool calls that cannot be executed safely; an open block assembles from + * its accumulated deltas (an unknown block type never closed by `block-end` throws). + */ + blocks(): ContentBlock[]; + /** Usage from the `usage` chunk; undefined until one arrives. */ + get usage(): TokenUsage | undefined; + /** Finish reason from the `finish` chunk; `{kind: 'stop'}` when the stream ended without one. */ + get finish(): FinishReason; + /** Adapter-private replay state from the terminal finish chunk, if any. */ + get replayState(): unknown; + /** + * The assembled assistant message. + * @param source - producer attribution for the assembled message. + * @returns a frozen assistant-role message over `blocks()` (same open-block assembly rules). + */ + message(source?: MessageSource): Message; +} +//# sourceMappingURL=assembler.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.js new file mode 100644 index 0000000..7990811 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.js @@ -0,0 +1,148 @@ +/** + * Incremental chunk-to-message assembler. This is the single canonical assembly + * algorithm used by the agent loop to build an assistant message from a chunk + * stream while logging the raw chunks for replay fidelity. + * + * @module @deepseek-ai/dsh-llm/assembler + */ +import { CallId } from "./brand.js"; +import { assertNever } from "./never.js"; +import { createMessage } from "./message.js"; +/** + * Incrementally assembles raw {@link StreamChunk}s into complete + * {@link ContentBlock}s and a final assistant {@link Message}. + * + * The agent loop feeds it while logging raw chunks for replay fidelity, then + * reads `blocks()` / `message()` / `usage` / `finish` once the stream ends. + * + * Tolerant of delta-only protocols (no block-start/end); deltas arriving for + * an index already closed by `block-end` are ignored (malformed stream) so a + * misbehaving adapter cannot grow memory or corrupt a completed block. + */ +export class BlockAssembler { + partials = new Map(); + order = []; + _usage; + _finish; + _replayState = undefined; + /** + * Feed one chunk into the assembly state. + * @param chunk - the next raw chunk, in stream order. + */ + push(chunk) { + switch (chunk.type) { + case 'block-start': { + if (!this.partials.has(chunk.index)) { + this.order.push(chunk.index); + this.partials.set(chunk.index, { + blockType: chunk.blockType, + text: '', + toolCallArguments: '', + }); + } + return; + } + case 'text-delta': + case 'reasoning-delta': { + const partial = this.ensure(chunk.index, chunk.type === 'text-delta' ? 'text' : 'reasoning'); + if (partial.block) + return; // closed by block-end; ignore stragglers + partial.text += chunk.text; + return; + } + case 'tool-call-delta': { + const partial = this.ensure(chunk.index, 'tool-call'); + if (partial.block) + return; // closed by block-end; ignore stragglers + partial.toolCallId = chunk.id; + if (chunk.name) + partial.toolCallName = chunk.name; + partial.toolCallArguments += chunk.argumentsDelta; + return; + } + case 'block-end': { + const partial = this.ensure(chunk.index, chunk.block.type); + // First close wins; ignoring re-close stragglers keeps streamed output + // and the final assembled block in agreement. + if (partial.block) + return; + partial.block = chunk.block; + return; + } + case 'usage': { + this._usage = chunk.usage; + return; + } + case 'finish': { + this._finish = chunk.reason; + this._replayState = chunk.replayState; + return; + } + default: return assertNever(chunk, 'BlockAssembler.push'); + } + } + ensure(index, blockType) { + let partial = this.partials.get(index); + if (!partial) { + partial = { blockType, text: '', toolCallArguments: '' }; + this.partials.set(index, partial); + this.order.push(index); + } + return partial; + } + assemble(partial, index) { + if (partial.block) + return partial.block; + switch (partial.blockType) { + case 'text': return { type: 'text', text: partial.text }; + case 'reasoning': return { type: 'reasoning', text: partial.text }; + case 'tool-call': return { + type: 'tool-call', + id: partial.toolCallId ?? CallId(`call-${index}`), + name: partial.toolCallName ?? '', + arguments: partial.toolCallArguments, + }; + default: throw new Error(`cannot assemble incomplete block of type "${partial.blockType}"`); + } + } + /** Invariant accessor: every index in `order` has a partial. */ + mustGet(index) { + const partial = this.partials.get(index); + if (!partial) + throw new Error(`BlockAssembler invariant violated: no partial for index ${index}`); + return partial; + } + /** + * Assemble all blocks seen so far, in stream order. + * @returns one block per seen index, except that max-token truncation drops + * tool calls that cannot be executed safely; an open block assembles from + * its accumulated deltas (an unknown block type never closed by `block-end` throws). + */ + blocks() { + const blocks = this.order.map(index => this.assemble(this.mustGet(index), index)); + return this.finish.kind === 'max-tokens' + ? blocks.filter(block => block.type !== 'tool-call') + : blocks; + } + /** Usage from the `usage` chunk; undefined until one arrives. */ + get usage() { + return this._usage; + } + /** Finish reason from the `finish` chunk; `{kind: 'stop'}` when the stream ended without one. */ + get finish() { + return this._finish ?? { kind: 'stop' }; + } + /** Adapter-private replay state from the terminal finish chunk, if any. */ + get replayState() { + return this._replayState; + } + /** + * The assembled assistant message. + * @param source - producer attribution for the assembled message. + * @returns a frozen assistant-role message over `blocks()` (same open-block assembly rules). + */ + message(source = { kind: 'plugin', plugin: 'dsh-llm/assembler' }) { + return createMessage({ role: 'assistant', content: this.blocks(), source }); + } +} +//# sourceMappingURL=assembler.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.d.ts new file mode 100644 index 0000000..e4aa2a3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.d.ts @@ -0,0 +1,47 @@ +/** + * Centralize the non-secret product identity every provider request sends as `User-Agent`, keeping + * adapters from drifting. See + * `.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md`. + * + * App-attribution vocabulary for provider requests. + * @module @deepseek-ai/dsh-llm/attribution + */ +/** + * Static public application identity sent to LLM providers. + * + * Every field is a public product fact, safe on every request: no secrets, + * local paths, session ids, prompt text, or per-user identifiers belong here, + * and nothing per-request may influence the values. + */ +export interface AppIdentity { + /** `User-Agent` product token (lowercase, hyphenated). */ + product: string; + /** Product version; sourced from package metadata, never hand-copied. */ + version: string; + /** Repository home URL of the app, used as the `User-Agent` comment. */ + url: string; +} +/** + * The harness's own identity: the default every adapter sends. Deployments + * that need a white-label identity pass their own {@link AppIdentity} to + * {@link attributionHeaders} — omission falls back to this default; nothing + * can suppress attribution entirely. + */ +export declare const APP_IDENTITY: AppIdentity; +/** + * The standard `User-Agent` value: `product/version (+url)`. The + * parenthesized `+url` comment is the conventional self-identification form + * (RFC 9110 §10.1.5 product + comment syntax). + * @param identity - the identity to render; defaults to {@link APP_IDENTITY}. + * @returns the ready-to-send header value. + */ +export declare function userAgent(identity?: AppIdentity): string; +/** + * Build the attribution headers an adapter must send on every provider + * request. Header names are lowercase (HTTP field names are case-insensitive + * on the wire). + * @param identity - the identity to send; defaults to {@link APP_IDENTITY} — omission cannot suppress attribution. + * @returns headers to merge into the provider request (currently just `user-agent`). + */ +export declare function attributionHeaders(identity?: AppIdentity): Record; +//# sourceMappingURL=attribution.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.js new file mode 100644 index 0000000..a09678f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.js @@ -0,0 +1,46 @@ +/** + * Centralize the non-secret product identity every provider request sends as `User-Agent`, keeping + * adapters from drifting. See + * `.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md`. + * + * App-attribution vocabulary for provider requests. + * @module @deepseek-ai/dsh-llm/attribution + */ +import { createRequire } from 'node:module'; +// The package's own manifest is the single source of the version so the +// User-Agent cannot drift from what is published (`./package.json` is an +// export of this package; the relative path resolves from both `src/` and +// the bundled `lib/`). +const { version } = createRequire(import.meta.url)('../package.json'); +/** + * The harness's own identity: the default every adapter sends. Deployments + * that need a white-label identity pass their own {@link AppIdentity} to + * {@link attributionHeaders} — omission falls back to this default; nothing + * can suppress attribution entirely. + */ +export const APP_IDENTITY = { + product: 'deepseek-harness', + version, + url: 'https://github.com/deepseek-ai/deepseek-harness', +}; +/** + * The standard `User-Agent` value: `product/version (+url)`. The + * parenthesized `+url` comment is the conventional self-identification form + * (RFC 9110 §10.1.5 product + comment syntax). + * @param identity - the identity to render; defaults to {@link APP_IDENTITY}. + * @returns the ready-to-send header value. + */ +export function userAgent(identity = APP_IDENTITY) { + return `${identity.product}/${identity.version} (+${identity.url})`; +} +/** + * Build the attribution headers an adapter must send on every provider + * request. Header names are lowercase (HTTP field names are case-insensitive + * on the wire). + * @param identity - the identity to send; defaults to {@link APP_IDENTITY} — omission cannot suppress attribution. + * @returns headers to merge into the provider request (currently just `user-agent`). + */ +export function attributionHeaders(identity = APP_IDENTITY) { + return { 'user-agent': userAgent(identity) }; +} +//# sourceMappingURL=attribution.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.d.ts new file mode 100644 index 0000000..50599a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.d.ts @@ -0,0 +1,48 @@ +/** + * dsh-llm's owned branded ids: tool-call correlation and provider request + * diagnostics. + * + * The `Branded` primitive itself lives in `@deepseek-ai/dsh-brand` (a + * zero-dependency type-only package) so every owner of a cross-boundary id can + * brand it without depending on dsh-llm; see that package's README for the + * nominal-typing policy. + * + * @module @deepseek-ai/dsh-llm/brand + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Stable identity carried by one message across inbox, log, and model-request boundaries. */ +export type MessageId = Branded<'MessageId'>; +/** + * Brand a message identifier. + * @param id - the opaque message identifier. + * @returns the same string, branded; no validation is performed. + */ +export declare function MessageId(id: string): MessageId; +/** + * Correlates a model-issued tool call with its result. Provider-issued for + * real adapters; synthesized by mocks/assembler fallbacks. + */ +export type CallId = Branded<'CallId'>; +/** + * Brand a string as a {@link CallId}. + * @param id - the provider-issued (or synthesized) call id. + * @returns the same string, branded; no validation is performed. + */ +export declare function CallId(id: string): CallId; +/** Provider-issued request identifier retained for diagnostics across package boundaries. */ +export type ProviderRequestId = Branded<'ProviderRequestId'>; +/** + * Brand a provider-issued request identifier. + * @param id - the opaque provider-issued string. + * @returns the same string, branded; no validation is performed. + */ +export declare function ProviderRequestId(id: string): ProviderRequestId; +/** Adapter-owned identifier for one model's selectable reasoning effort. */ +export type ReasoningEffortId = Branded<'ReasoningEffortId'>; +/** + * Brand an adapter-owned reasoning-effort identifier. + * @param id - the opaque identifier exposed by one model capability. + * @returns the same string, branded; no validation is performed. + */ +export declare function ReasoningEffortId(id: string): ReasoningEffortId; +//# sourceMappingURL=brand.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.js new file mode 100644 index 0000000..a6eee43 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.js @@ -0,0 +1,44 @@ +/** + * dsh-llm's owned branded ids: tool-call correlation and provider request + * diagnostics. + * + * The `Branded` primitive itself lives in `@deepseek-ai/dsh-brand` (a + * zero-dependency type-only package) so every owner of a cross-boundary id can + * brand it without depending on dsh-llm; see that package's README for the + * nominal-typing policy. + * + * @module @deepseek-ai/dsh-llm/brand + */ +/** + * Brand a message identifier. + * @param id - the opaque message identifier. + * @returns the same string, branded; no validation is performed. + */ +export function MessageId(id) { + return id; +} +/** + * Brand a string as a {@link CallId}. + * @param id - the provider-issued (or synthesized) call id. + * @returns the same string, branded; no validation is performed. + */ +export function CallId(id) { + return id; +} +/** + * Brand a provider-issued request identifier. + * @param id - the opaque provider-issued string. + * @returns the same string, branded; no validation is performed. + */ +export function ProviderRequestId(id) { + return id; +} +/** + * Brand an adapter-owned reasoning-effort identifier. + * @param id - the opaque identifier exposed by one model capability. + * @returns the same string, branded; no validation is performed. + */ +export function ReasoningEffortId(id) { + return id; +} +//# sourceMappingURL=brand.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.d.ts new file mode 100644 index 0000000..b157e27 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.d.ts @@ -0,0 +1,62 @@ +/** + * Conversation call configuration and freeze utilities. Provider routing, + * model, reasoning effort, and sampling values are request-header state that + * can affect cache reuse; request waterfalls replace them and the loop logs + * changed snapshots instead of allowing silent per-call drift. + * @module dsh-llm/call-config + */ +import type { GenerateOptions } from './types.ts'; +import type { ReasoningEffortId } from './brand.ts'; +/** + * Provider, model, reasoning effort, and sampling scalars of one conversation's + * requests. Every field maps 1:1 onto the same-named `GenerateOptions` field; + * the loop builds requests from the logged header rather than accepting these + * per call. + */ +export interface LlmCallConfig { + provider: string; + model: string; + reasoningEffort?: ReasoningEffortId; + temperature?: number; + maxTokens?: number; + stop?: string[]; +} +/** + * Effective config fields supplied by exact-model adapter resolution rather + * than by the caller's request proposal. + */ +export interface LlmCallConfigAdapterDefaults { + reasoningEffort?: true; + maxTokens?: true; +} +/** + * Field-wise equality over {@link LlmCallConfig} — the comparison a caller + * runs to decide whether a proposed configuration is a real change (worth a + * logged header snapshot) or the held one restated. + * @param a - one configuration. + * @param b - the other. + * @returns whether every field (including the `stop` list, element-wise) matches. + */ +export declare function callConfigEquals(a: LlmCallConfig, b: LlmCallConfig): boolean; +/** + * Mark one exact request object as assembled by dsh-agent-loop. + * @param request - loop-owned request envelope before LLM dispatch. + * @returns the same request object marked as created by the process-local agent loop. + */ +export declare function markAgentLoopRequest(request: T): T; +/** + * Test whether the exact request object was assembled by dsh-agent-loop. + * @param request - request envelope observed at the LLM waterfall. + * @returns whether {@link markAgentLoopRequest} recorded this object. + */ +export declare function isAgentLoopRequest(request: GenerateOptions): boolean; +/** + * Deep-freeze a value in place with an iterative traversal, guarding cycles, + * so later mutation throws without imposing a JavaScript call-stack depth cap. + * {@link AbortSignal} objects are deliberately skipped because they are the + * request's live cancellation channel and freezing them breaks abort. + * @param value - the value to freeze in place. + * @returns the same value, frozen. + */ +export declare function deepFreeze(value: T): T; +//# sourceMappingURL=call-config.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.js new file mode 100644 index 0000000..75b0874 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.js @@ -0,0 +1,86 @@ +/** + * Conversation call configuration and freeze utilities. Provider routing, + * model, reasoning effort, and sampling values are request-header state that + * can affect cache reuse; request waterfalls replace them and the loop logs + * changed snapshots instead of allowing silent per-call drift. + * @module dsh-llm/call-config + */ +/** Process-local identities of request objects assembled by dsh-agent-loop. */ +const AGENT_LOOP_REQUESTS = new WeakSet(); +/** + * Field-wise equality over {@link LlmCallConfig} — the comparison a caller + * runs to decide whether a proposed configuration is a real change (worth a + * logged header snapshot) or the held one restated. + * @param a - one configuration. + * @param b - the other. + * @returns whether every field (including the `stop` list, element-wise) matches. + */ +export function callConfigEquals(a, b) { + if (a.provider !== b.provider + || a.model !== b.model + || a.reasoningEffort !== b.reasoningEffort + || a.temperature !== b.temperature + || a.maxTokens !== b.maxTokens) + return false; + if (a.stop === undefined || b.stop === undefined) + return a.stop === b.stop; + return a.stop.length === b.stop.length && a.stop.every((s, i) => s === b.stop?.[i]); +} +/** + * Mark one exact request object as assembled by dsh-agent-loop. + * @param request - loop-owned request envelope before LLM dispatch. + * @returns the same request object marked as created by the process-local agent loop. + */ +export function markAgentLoopRequest(request) { + AGENT_LOOP_REQUESTS.add(request); + return request; +} +/** + * Test whether the exact request object was assembled by dsh-agent-loop. + * @param request - request envelope observed at the LLM waterfall. + * @returns whether {@link markAgentLoopRequest} recorded this object. + */ +export function isAgentLoopRequest(request) { + return AGENT_LOOP_REQUESTS.has(request); +} +/** + * Deep-freeze a value in place with an iterative traversal, guarding cycles, + * so later mutation throws without imposing a JavaScript call-stack depth cap. + * {@link AbortSignal} objects are deliberately skipped because they are the + * request's live cancellation channel and freezing them breaks abort. + * @param value - the value to freeze in place. + * @returns the same value, frozen. + */ +export function deepFreeze(value) { + const seen = new WeakSet(); + const pending = [{ kind: 'visit', node: value }]; + while (pending.length > 0) { + const task = pending.pop(); + /* v8 ignore next -- the loop condition guarantees one pending task. */ + if (task === undefined) + continue; + if (task.kind === 'property') { + pending.push({ kind: 'visit', node: task.source[task.key] }); + continue; + } + const node = task.node; + if (node === null || typeof node !== 'object') + continue; + if (node instanceof AbortSignal) + continue; + if (seen.has(node)) + continue; + seen.add(node); + Object.freeze(node); + const keys = Object.keys(node); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) + continue; + pending.push({ kind: 'property', source: node, key }); + } + } + return value; +} +//# sourceMappingURL=call-config.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/content.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/content.d.ts new file mode 100644 index 0000000..b9f5187 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/content.d.ts @@ -0,0 +1,12 @@ +/** Content-block structure helpers. @module @deepseek-ai/dsh-llm/content */ +import type { ContentBlock } from './types.ts'; +/** + * True when typed model content contains an image block, walking nested + * tool-result content. This is the one recursive image walk shared by every + * image policy (capability gating, text-only serialization, compaction + * survey), so a consumer cannot silently diverge on nesting depth. + * @param content - typed model content blocks. + * @returns whether any nested block is an image. + */ +export declare function contentHasImage(content: readonly ContentBlock[]): boolean; +//# sourceMappingURL=content.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/content.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/content.js new file mode 100644 index 0000000..1c057ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/content.js @@ -0,0 +1,14 @@ +/** Content-block structure helpers. @module @deepseek-ai/dsh-llm/content */ +/** + * True when typed model content contains an image block, walking nested + * tool-result content. This is the one recursive image walk shared by every + * image policy (capability gating, text-only serialization, compaction + * survey), so a consumer cannot silently diverge on nesting depth. + * @param content - typed model content blocks. + * @returns whether any nested block is an image. + */ +export function contentHasImage(content) { + return content.some(block => block.type === 'image' + || (block.type === 'tool-result' && contentHasImage(block.content))); +} +//# sourceMappingURL=content.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/error.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/error.d.ts new file mode 100644 index 0000000..7f522bd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/error.d.ts @@ -0,0 +1,73 @@ +/** + * Harness error base with a stable machine-routable code and chained cause. + * Package errors extend it so tool results and replay can retain failure class. + * @module @deepseek-ai/dsh-llm/error + */ +/** + * Base class for all harness errors. Carries a `code` (stable, programmatic — + * e.g. `NO_ADAPTER`, `INVALID_ARGS`, `INVARIANT`) distinct from the + * human-readable `message`, and supports `cause` chaining via the standard + * `ErrorOptions`. `name` defaults to the subclass constructor name. + */ +export declare class HarnessError extends Error { + /** Stable machine-routable failure class (e.g. `RATE_LIMIT`); route on this, never by parsing `message`. */ + readonly code: string; + constructor(message: string, code: string, options?: ErrorOptions); +} +/** Canonical provider-neutral code for a model request rejected because its context window was exceeded. */ +export declare const CONTEXT_WINDOW_EXCEEDED_CODE = "CONTEXT_WINDOW_EXCEEDED"; +/** Canonical provider-neutral code for an exhausted account quota or balance. */ +export declare const QUOTA_EXCEEDED_CODE = "QUOTA"; +/** + * Canonical provider-neutral code for a response that completed normally but + * carried no content blocks at all. Providers occasionally emit a degenerate + * completion (a terminal stop with zero output); adapters classify it as this + * failure instead of yielding an empty assistant message, because an empty + * message silently ends the turn with nothing for the user or the loop to act + * on. The attempt produced nothing durable, so retry policy treats it as safe + * to repeat. + */ +export declare const EMPTY_RESPONSE_CODE = "EMPTY_RESPONSE"; +/** + * Canonical provider-neutral code for a credential that was supplied but + * cannot be used — malformed rather than absent. Distinct from + * `MISSING_CREDENTIAL` because the fix differs: correct the stored value + * rather than supply one. Deliberately outside the default retryable set — + * a malformed credential fails identically on every attempt. + */ +export declare const INVALID_CREDENTIAL_CODE = "INVALID_CREDENTIAL"; +/** + * Recognize the context-overflow wording used by OpenAI-compatible providers + * and library adapters. Adapters pass all available provider code, type, and + * message text so both thrown and in-band delivery styles share one classifier. + * @param detail - provider error code/type/message text joined into one string. + * @returns true when the detail identifies a request exceeding the model context window. + */ +export declare function isContextWindowExceededError(detail: string): boolean; +/** + * Recognize provider wording that identifies an exhausted account quota rather + * than a transient request-rate limit. + * @param detail - provider error code/type/message text joined into one string. + * @returns true only for terminal quota, balance, credit, budget, or usage-limit wording. + */ +export declare function isQuotaExceededError(detail: string): boolean; +/** + * Render a thrown value with its full `cause` chain and AggregateError + * members, so transport wrappers like undici's `TypeError: fetch failed` + * surface the underlying failure instead of masking it. Plain structured + * failures render their own data-backed `message`. Diagnostic-surface + * rendering only (messages, notices, logs) — never parse the result; route on + * {@link HarnessError.code}. + * @param value - the caught value (`unknown` in catch clauses). + * @returns the outermost message first, each cause appended with `: ` (skipped + * when it repeats the wrapper message verbatim), and AggregateError members + * bracketed and `; `-joined. + */ +export declare function errorChain(value: unknown): string; +/** + * Narrow an arbitrary thrown value to a HarnessError (for `instanceof` at runtime boundaries). + * @param value - the caught value (`unknown` in catch clauses). + * @returns true only for real instances; duck-typed or cross-realm errors do not narrow. + */ +export declare function isHarnessError(value: unknown): value is HarnessError; +//# sourceMappingURL=error.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/error.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/error.js new file mode 100644 index 0000000..5a78c0f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/error.js @@ -0,0 +1,145 @@ +/** + * Harness error base with a stable machine-routable code and chained cause. + * Package errors extend it so tool results and replay can retain failure class. + * @module @deepseek-ai/dsh-llm/error + */ +/** + * Base class for all harness errors. Carries a `code` (stable, programmatic — + * e.g. `NO_ADAPTER`, `INVALID_ARGS`, `INVARIANT`) distinct from the + * human-readable `message`, and supports `cause` chaining via the standard + * `ErrorOptions`. `name` defaults to the subclass constructor name. + */ +export class HarnessError extends Error { + /** Stable machine-routable failure class (e.g. `RATE_LIMIT`); route on this, never by parsing `message`. */ + code; + constructor(message, code, options) { + super(message, options); + this.code = code; + this.name = new.target.name; + } +} +/** Canonical provider-neutral code for a model request rejected because its context window was exceeded. */ +export const CONTEXT_WINDOW_EXCEEDED_CODE = 'CONTEXT_WINDOW_EXCEEDED'; +/** Canonical provider-neutral code for an exhausted account quota or balance. */ +export const QUOTA_EXCEEDED_CODE = 'QUOTA'; +/** + * Canonical provider-neutral code for a response that completed normally but + * carried no content blocks at all. Providers occasionally emit a degenerate + * completion (a terminal stop with zero output); adapters classify it as this + * failure instead of yielding an empty assistant message, because an empty + * message silently ends the turn with nothing for the user or the loop to act + * on. The attempt produced nothing durable, so retry policy treats it as safe + * to repeat. + */ +export const EMPTY_RESPONSE_CODE = 'EMPTY_RESPONSE'; +/** + * Canonical provider-neutral code for a credential that was supplied but + * cannot be used — malformed rather than absent. Distinct from + * `MISSING_CREDENTIAL` because the fix differs: correct the stored value + * rather than supply one. Deliberately outside the default retryable set — + * a malformed credential fails identically on every attempt. + */ +export const INVALID_CREDENTIAL_CODE = 'INVALID_CREDENTIAL'; +/** Structured codes and plain phrases that explicitly name a context bound being exceeded. */ +const STRUCTURED_CONTEXT_OVERFLOW = new RegExp(String.raw `(?:^|[^a-z0-9])context[\s_-](?:length|window)[\s_-]` + + String.raw `(?:exceed(?:ed|s)?|overflow(?:ed)?|limit[\s_-]exceeded)(?:$|[^a-z0-9])`, 'i'); +/** Request-size wording that ties "too large" directly to model context capacity. */ +const TOO_LARGE_FOR_CONTEXT = new RegExp(String.raw `\b(?:request|prompt|input|messages?)\s+(?:is\s+|are\s+)?` + + String.raw `too\s+(?:large|long)\s+for\s+(?:(?:this|the)\s+)?` + + String.raw `(?:model(?:'s)?\s+)?context(?:\s+window)?\b`, 'i'); +/** "Exceeds" wording is safe only when its object is explicitly the model context. */ +const EXCEEDS_MODEL_CONTEXT = new RegExp(String.raw `\b(?:input|prompt|request|messages?)\b.{0,40}` + + String.raw `\b(?:exceed(?:s|ed)?|overflows?|is\s+larger\s+than)\b.{0,40}` + + String.raw `\b(?:the\s+)?(?:model(?:'s)?\s+)?context(?:\s+(?:length|window))?\b`, 'i'); +/** + * Recognize the context-overflow wording used by OpenAI-compatible providers + * and library adapters. Adapters pass all available provider code, type, and + * message text so both thrown and in-band delivery styles share one classifier. + * @param detail - provider error code/type/message text joined into one string. + * @returns true when the detail identifies a request exceeding the model context window. + */ +export function isContextWindowExceededError(detail) { + return STRUCTURED_CONTEXT_OVERFLOW.test(detail) + || /\b(?:maximum|max)(?:\s+(?:allowed|supported))?\s+context\s+(?:length|window)\b/i.test(detail) + || TOO_LARGE_FOR_CONTEXT.test(detail) + || /\b(?:input|prompt|request)\s+(?:is\s+)?too\s+(?:long|large)\s+for\s+(?:this|the)\s+model\b/i.test(detail) + || EXCEEDS_MODEL_CONTEXT.test(detail); +} +/** + * Recognize provider wording that identifies an exhausted account quota rather + * than a transient request-rate limit. + * @param detail - provider error code/type/message text joined into one string. + * @returns true only for terminal quota, balance, credit, budget, or usage-limit wording. + */ +export function isQuotaExceededError(detail) { + return /\binsufficient[\s_-]+(?:quota|balance|credits?)\b/i.test(detail) + || /\b(?:quota|usage[\s_-]+limit)[\s_-]+(?:exceeded|exhausted|reached)\b/i.test(detail) + || /\bexceed(?:ed|s)?[\s_-]+(?:(?:your|the)[\s_-]+)?(?:current[\s_-]+)?quota\b/i.test(detail) + || /\b(?:balance|credits?)[\s_-]+(?:exhausted|depleted)\b/i.test(detail) + || /\bout[\s_-]+of[\s_-]+(?:credits?|budget)\b/i.test(detail); +} +/** + * Render a thrown value with its full `cause` chain and AggregateError + * members, so transport wrappers like undici's `TypeError: fetch failed` + * surface the underlying failure instead of masking it. Plain structured + * failures render their own data-backed `message`. Diagnostic-surface + * rendering only (messages, notices, logs) — never parse the result; route on + * {@link HarnessError.code}. + * @param value - the caught value (`unknown` in catch clauses). + * @returns the outermost message first, each cause appended with `: ` (skipped + * when it repeats the wrapper message verbatim), and AggregateError members + * bracketed and `; `-joined. + */ +export function errorChain(value) { + // Tracks the active recursion path (entries removed on exit), so only true + // cycles are flagged and a diamond-shared cause still renders in full. + const path = new Set(); + const render = (current) => { + if (path.has(current)) + return ''; + path.add(current); + try { + if (!(current instanceof Error)) { + if (typeof current === 'object' && current !== null) { + const descriptor = Object.getOwnPropertyDescriptor(current, 'message'); + if (descriptor !== undefined && 'value' in descriptor && typeof descriptor.value === 'string') { + return descriptor.value; + } + } + return String(current); + } + const message = current.message === '' ? current.name : current.message; + const members = current instanceof AggregateError && current.errors.length > 0 + ? ` [${current.errors.map(render).join('; ')}]` + : ''; + const causeText = current.cause === undefined || current.cause === null + ? '' + : render(current.cause); + // Wrappers like `new HarnessError(String(value), code, { cause: value })` + // repeat their cause verbatim; rendering it again would only add noise. + const cause = causeText === '' || causeText === message ? '' : `: ${causeText}`; + return `${message}${members}${cause}`; + } + catch { + // Only hostile coercion or hostile accessors (a throwing toString / + // Symbol.toPrimitive on a non-Error, or a throwing message/name/cause/ + // errors getter on an Error subclass): this renderer feeds UI notices + // and logs, so nothing may escape. Inner frames catch their own throws, + // so only the hostile node collapses, not the whole chain. + return ''; + } + finally { + path.delete(current); + } + }; + return render(value); +} +/** + * Narrow an arbitrary thrown value to a HarnessError (for `instanceof` at runtime boundaries). + * @param value - the caught value (`unknown` in catch clauses). + * @returns true only for real instances; duck-typed or cross-realm errors do not narrow. + */ +export function isHarnessError(value) { + return value instanceof HarnessError; +} +//# sourceMappingURL=error.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/index.d.ts new file mode 100644 index 0000000..9692be1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/index.d.ts @@ -0,0 +1,341 @@ +/** + * LLM service: adapter registry with a waterfall-interceptable streaming call + * API. Exports the `LlmRuntime` default, the abstract `LlmAdapter` for + * provider backends, and `BlockAssembler` for chunk assembly. + * + * @module @deepseek-ai/dsh-llm + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { GenerateOptions, LlmConfigurableProvider, LlmDiscoveredModel, LlmFailure, LlmModelContext, LlmModelDiscoveryRequest, LlmModelInfo, LlmResolvedModelInfo, LlmProviderInfo, StreamChunk } from './types.ts'; +import type { ResolvedRetryPolicy } from './retry-policy.ts'; +import type { ProviderRequestId } from './brand.ts'; +import type { LlmCallConfig, LlmCallConfigAdapterDefaults } from './call-config.ts'; +import { HarnessError } from './error.ts'; +export * from './attribution.ts'; +export * from './brand.ts'; +export * from './never.ts'; +export * from './error.ts'; +export * from './api-key.ts'; +export * from './types.ts'; +export * from './content.ts'; +export * from './message.ts'; +export * from './retry-policy.ts'; +export { BlockAssembler } from './assembler.ts'; +export { callConfigEquals, deepFreeze, isAgentLoopRequest, markAgentLoopRequest } from './call-config.ts'; +export type { LlmCallConfig, LlmCallConfigAdapterDefaults } from './call-config.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + llm: LlmRuntime; + } + interface Events { + /** + * Waterfall around every streaming model call (retry, replay, routing). + * Bound to the {@link LlmRuntime}; call `next()` to reach the resolved + * adapter's stream, or yield your own chunks to short-circuit. + * @param options - the full request. A LOOP-built request carries the + * process-local {@link markAgentLoopRequest} identity and arrives deep-frozen + * (mutation throws): its content is a pure function of the session log (the + * reconstructability Agent Note), so listeners read it, never rewrite it. + * Hand-built calls do not carry that marker; their messages already obey + * the immutable creation contract. + * @mode waterfall + */ + 'llm/stream'(this: LlmRuntime, options: GenerateOptions, next: () => AsyncIterable): AsyncIterable; + } +} +/** Structured provider facts and cause accepted by {@link LlmError}. */ +export interface LlmErrorOptions extends ErrorOptions { + /** Valid HTTP status observed at the provider boundary. */ + status?: number; + /** Positive finite provider-requested delay in milliseconds. */ + providerRetryAfterMs?: number; + /** Non-empty opaque provider request id. */ + requestId?: ProviderRequestId; +} +/** + * Typed error for LLM-related failures. Extends {@link HarnessError}, so the + * `code` string (e.g. `AUTH`, `RATE_LIMIT`, `NO_ADAPTER`) is shared taxonomy. + */ +export declare class LlmError extends HarnessError { + /** Serializable facts retained beside this live Error. */ + readonly failure: LlmFailure; + /** + * @param message - non-empty human-readable failure summary. + * @param code - non-empty stable provider-neutral machine code. + * @param options - optional cause and validated serializable provider facts. + */ + constructor(message: string, code: string, options?: LlmErrorOptions); +} +/** + * Accept one supplied credential, or refuse it as unusable. + * + * A stored key arrives from the credentials seam, a `.env` line, or a shell + * export, all of which pick up surrounding whitespace, so trimming is silent. + * Anything else fails here rather than inside `fetch`, whose ByteString + * refusal names a UTF-16 code point instead of the setting to change. The key + * never enters the message: `ref` names where to fix it, and echoing any part + * of a secret into a log or a UI is the failure this diagnosis avoids. + * + * Lives beside {@link LlmError} rather than in `./api-key.ts` so the predicate + * module stays dependency-free; both adapters share this one diagnosis instead + * of keeping near-identical local copies. + * @param raw - the credential exactly as supplied. + * @param pkg - the refusing package name, prefixed to the diagnostic. + * @param ref - the credential reference the value resolved through. + * @returns the trimmed, usable key. + */ +export declare function assertUsableApiKey(raw: string, pkg: string, ref: string): string; +/** One model call whose config and adapter registration were resolved together. */ +export interface PreparedLlmCall { + /** Detached, deep-frozen config with any adapter-owned default materialized. */ + readonly config: LlmCallConfig; + /** Immutable retry policy captured with the adapter registration. */ + readonly retryPolicy: ResolvedRetryPolicy; + /** Detached context metadata resolved with the registration-bound call. */ + readonly context?: LlmModelContext; + /** Config fields materialized by the captured adapter rather than proposed by the caller. */ + readonly adapterDefaults: LlmCallConfigAdapterDefaults; + /** + * Dispatch this call once through the registration captured during + * preparation. The request's call-config fields must match {@link config}; + * reuse or mismatch fails with `INVALID_PREPARED_CALL`. + * @param options - fully assembled request carrying the prepared config. + * @returns the chunk stream, including the `llm/stream` waterfall. + */ + stream(options: GenerateOptions): AsyncIterable; +} +/** + * Provider-wire adapter for the harness message and stream vocabulary. Register implementations + * with `ctx.llm.registerAdapter(providers, adapter)`. Every provider HTTP request must include + * `attributionHeaders()`; prove the headers are added in the wire request or library header hook. The direct-fetch + * DeepSeek and library-backed pi-ai adapters meet this contract through different internals. + */ +export declare abstract class LlmAdapter { + /** + * Describe one provider route owned by this adapter. + * @param provider - a route passed to `registerAdapter()` for this instance. + * @returns detached display metadata whose id must equal `provider`. + */ + providerInfo(provider: string): LlmProviderInfo; + /** + * Return the provider-owned retry policy captured with this route. + * @param _provider - a route passed to `registerAdapter()` for this instance. + * @returns a resolved policy, or `undefined` to use the normal defaults. + */ + providerRetryPolicy(_provider: string): ResolvedRetryPolicy | undefined; + /** + * List models this adapter can currently advertise for one owned provider. + * The result is advisory: an adapter may accept unlisted model ids, and + * consumers must not turn absence into request rejection. + * @param _provider - one provider route owned by this adapter. + * @returns discoverable models in adapter-preferred order. + */ + listModels(_provider: string): Promise; + /** + * Resolve all metadata available for one exact model. This query is + * independent of the advisory catalog and does not validate request routing. + * @param provider - one provider route owned by this adapter. + * @param model - exact model id passed to {@link GenerateOptions.model}. + * @param _signal - cancellation for this exact-model lookup; asynchronous + * implementations must settle promptly after it aborts. + * @returns provider/model identity plus any context, call-default, and reasoning metadata. + */ + resolveModel(provider: string, model: string, _signal?: AbortSignal): Promise; + /** + * Stream one model call as raw chunks. The only required method. + * @param options - the fully-assembled request; implementations must honor `options.signal`. + * @returns the chunk stream, obeying the adapter contract documented on `StreamChunk`. + */ + abstract stream(options: GenerateOptions): AsyncIterable; +} +/** + * What {@link LlmRuntime.registerAdapter} returns: the disposer, plus an + * atomic route replacement for the same adapter instance. + */ +export interface AdapterRegistrationHandle { + /** Release every route this registration currently holds. */ + (): void; + /** + * Replace this registration's routes with `providers`, keeping the same + * adapter instance. The candidate set is validated in full first — a + * conflict with another adapter, an invalid name, or bad provider metadata + * throws and leaves the current routes untouched — and the swap itself is + * one synchronous section, so no request can observe a gap. An empty array + * is legal here (a settings section that emptied holds zero routes while + * staying registered), unlike an empty initial registration. + * + * Throws `LlmError` with code `REGISTRATION_DISPOSED` once the registration + * has been released: its routes are gone and its disposer has already run, + * so anything registered afterwards would have no owner left to release it. + * @param providers - the complete next route set for this registration. + */ + replace(providers: string[]): void; +} +/** + * A live configurable-provider registration, disposable and atomically + * replaceable — the directory counterpart of {@link AdapterRegistrationHandle}. + */ +export interface DirectoryRegistrationHandle { + /** Withdraw every entry this registration currently holds. */ + (): void; + /** + * Replace this registration's entries with `entries`. The candidate set is + * validated in full first — an entry another registration already declares, + * a duplicate within the set, or invalid metadata throws and leaves the + * current entries untouched — and the swap is one synchronous section, so no + * reader observes a gap. An empty array is legal here, unlike an empty + * initial registration. + * + * Throws `LlmError` with code `REGISTRATION_DISPOSED` once the registration + * has been disposed. + */ + replace(entries: readonly LlmConfigurableProvider[]): void; +} +/** + * The abstract `llm` service: an adapter registry plus a streaming model-call + * API, interceptable via the `llm/stream` waterfall. + */ +export declare class LlmRuntime extends Service { + private adapters; + private directory; + private discoveries; + constructor(ctx: Context); + /** Notify topology observers without letting one broken listener veto the commit. */ + private emitAdaptersUpdated; + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + private warnAdaptersListenerFailure; + /** + * Register an adapter for the given provider routes. Throws `LlmError` with code + * `DUPLICATE_ADAPTER` if any provider already has an adapter (all-or-nothing). + * Disposed with the fiber. + * @param providers - every provider route this adapter should serve. + * @param adapter - the adapter that streams calls for those providers. + * @returns the disposer, carrying {@link AdapterRegistrationHandle.replace}. + */ + registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHandle; + /** + * Validate one candidate route set for `adapter`, treating routes this + * registration already holds as available. Nothing is mutated: a rejected + * candidate leaves the registry exactly as it was. + */ + private prepareRoutes; + /** + * Swap this registration's routes for the prepared ones in one synchronous + * section, so no observer can see the registry between the release and the + * re-registration. The route set's one mutation point is also where + * `llm/adapters-updated` is published, so a `replace` announces itself + * exactly like a first registration. + */ + private commitRoutes; + /** + * Describe provider routes with a registered adapter. + * @returns detached provider metadata in registration order. + */ + listProviders(): LlmProviderInfo[]; + /** + * Declare provider routes an adapter plugin can activate through + * configuration. Registration is all-or-nothing: an empty list, invalid + * entry, or a provider already declared by any registration throws + * `LlmError` without registering the rest. Disposed with the fiber. + * @param entries - every configurable provider this plugin owns. + * @returns a handle that withdraws all of them, and can atomically replace them. + */ + registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): DirectoryRegistrationHandle; + /** + * List every declared configurable provider, registered or dormant. + * @returns detached directory entries in declaration order. + */ + listConfigurableProviders(): LlmConfigurableProvider[]; + /** + * Offer to interrogate provider endpoints on behalf of the settings + * namespace this plugin owns. The namespace is the key because that is what + * a configuration surface already holds from the configurable-provider + * directory, and because a provider being *added* has no route to name yet. + * Disposed with the fiber. + * @param settingsNs - the namespace whose profiles this discovery serves. + * @param discover - interrogates one endpoint; must honor `request.signal`. + * @returns the disposer that withdraws the offer. + */ + registerModelDiscovery(settingsNs: string, discover: (request: LlmModelDiscoveryRequest) => Promise): () => void; + /** + * Interrogate one provider endpoint for the models it advertises. The + * request describes a draft, not a stored route, so nothing here reads or + * writes settings or credentials — the caller owns both, and the reply is + * candidate metadata a surface may offer for adoption. + * @param settingsNs - namespace whose registered discovery serves this draft. + * @param request - the endpoint, protocol, and one-shot credential to use. + * @returns the advertised models, deduplicated in endpoint order. + */ + discoverModels(settingsNs: string, request: LlmModelDiscoveryRequest): Promise; + /** + * Resolve the retry policy captured when one provider route was registered. + * @param provider - registered provider route to inspect. + * @returns the provider-owned policy, with normal defaults already resolved. + */ + providerRetryPolicy(provider: string): ResolvedRetryPolicy; + /** Detach typed adapter-owned modality metadata. */ + private detachedModalities; + /** + * Discover models advertised by one registered provider. Catalog membership + * is advisory and never changes routing or request validation. + * @param provider - registered provider route to inspect. + * @returns detached model metadata in adapter-preferred order. + */ + listModels(provider: string): Promise; + /** + * Resolve and validate all metadata from the adapter that owns one exact + * route. The result is detached from adapter-owned objects; catalog + * membership remains advisory and does not control request routing. + * @param provider - registered provider route to inspect. + * @param model - exact model id passed to the adapter. + * @param signal - optional cancellation for adapter-owned asynchronous lookup. + * @returns exact model identity plus available context and reasoning metadata. + */ + resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise; + private resolveModelInfoFor; + /** + * Validate a conversation call config against its exact model capability and + * materialize adapter-configured defaults. Unsupported explicit efforts + * reject before provider I/O; no clamping or aliasing is performed. This + * standalone query does not bind a later dispatch; use {@link prepareCall} + * when logging and streaming must share one adapter registration. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a detached config only when a default must be materialized. + */ + resolveCallConfig(config: LlmCallConfig, signal?: AbortSignal): Promise; + private resolveCallFor; + /** + * Resolve one call under its current adapter registration. The returned + * one-shot handle keeps that registration across header logging and dispatch, + * so HMR cannot combine one adapter's capability result with another adapter. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a prepared config and its registration-bound stream entry point. + */ + prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise; + private registration; + /** Remove replay state whose historical route is owned by another adapter. */ + private forAdapter; + /** + * Final adapter boundary. Adapter selection, dispatch, iterator construction, + * and iteration failures become one terminal failure chunk. Middleware and + * downstream consumer failures remain thrown plugin or consumer errors. + */ + private adapterStream; + /** + * Stream one model call as raw chunks (token-level deltas). Replay state is + * retained only when the same adapter instance owns its historical provider + * and the target provider. Final adapter selection remains fixed through + * asynchronous exact-model resolution and dispatch. Adapter selection, + * dispatch, and iteration failures become terminal `error` or `aborted` + * finish chunks; middleware, nested-call, cleanup, and consumer failures + * remain thrown. + * @param options - the full request; `options.provider` selects the adapter. + * @returns the chunk stream, possibly wrapped by `llm/stream` listeners. + */ + stream(options: GenerateOptions): AsyncIterable; + private streamWithRegistration; +} +export default LlmRuntime; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/index.js new file mode 100644 index 0000000..584c7eb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/index.js @@ -0,0 +1,730 @@ +/** + * LLM service: adapter registry with a waterfall-interceptable streaming call + * API. Exports the `LlmRuntime` default, the abstract `LlmAdapter` for + * provider backends, and `BlockAssembler` for chunk assembly. + * + * @module @deepseek-ai/dsh-llm + */ +import { Service } from '@deepseek-ai/cordis'; +import { freezeMessage } from "./message.js"; +import { resolveRetryPolicy } from "./retry-policy.js"; +import { callConfigEquals, deepFreeze } from "./call-config.js"; +import { HarnessError, INVALID_CREDENTIAL_CODE } from "./error.js"; +import { normalizeLlmFailure } from "./adapter-failure.js"; +import { normalizeApiKey } from "./api-key.js"; +export * from "./attribution.js"; +export * from "./brand.js"; +export * from "./never.js"; +export * from "./error.js"; +export * from "./api-key.js"; +export * from "./types.js"; +export * from "./content.js"; +export * from "./message.js"; +export * from "./retry-policy.js"; +export { BlockAssembler } from "./assembler.js"; +export { callConfigEquals, deepFreeze, isAgentLoopRequest, markAgentLoopRequest } from "./call-config.js"; +/** + * Typed error for LLM-related failures. Extends {@link HarnessError}, so the + * `code` string (e.g. `AUTH`, `RATE_LIMIT`, `NO_ADAPTER`) is shared taxonomy. + */ +export class LlmError extends HarnessError { + /** Serializable facts retained beside this live Error. */ + failure; + /** + * @param message - non-empty human-readable failure summary. + * @param code - non-empty stable provider-neutral machine code. + * @param options - optional cause and validated serializable provider facts. + */ + constructor(message, code, options) { + if (typeof message !== 'string' || message.length === 0) + throw new Error('LlmError message must be a non-empty string'); + if (typeof code !== 'string' || code.length === 0) + throw new Error('LlmError code must be a non-empty string'); + if (options?.status !== undefined + && (!Number.isInteger(options.status) || options.status < 100 || options.status > 599)) { + throw new Error('LlmError status must be an integer from 100 through 599'); + } + if (options?.providerRetryAfterMs !== undefined + && (!Number.isFinite(options.providerRetryAfterMs) || options.providerRetryAfterMs <= 0)) { + throw new Error('LlmError providerRetryAfterMs must be a positive finite number'); + } + if (options?.requestId !== undefined + && (typeof options.requestId !== 'string' || options.requestId.length === 0)) { + throw new Error('LlmError requestId must be a non-empty string'); + } + super(message, code, options); + this.name = 'LlmError'; + this.failure = Object.freeze({ + message, + code, + ...options?.status === undefined ? {} : { status: options.status }, + ...options?.providerRetryAfterMs === undefined ? {} : { providerRetryAfterMs: options.providerRetryAfterMs }, + ...options?.requestId === undefined ? {} : { requestId: options.requestId }, + }); + } +} +/** + * Accept one supplied credential, or refuse it as unusable. + * + * A stored key arrives from the credentials seam, a `.env` line, or a shell + * export, all of which pick up surrounding whitespace, so trimming is silent. + * Anything else fails here rather than inside `fetch`, whose ByteString + * refusal names a UTF-16 code point instead of the setting to change. The key + * never enters the message: `ref` names where to fix it, and echoing any part + * of a secret into a log or a UI is the failure this diagnosis avoids. + * + * Lives beside {@link LlmError} rather than in `./api-key.ts` so the predicate + * module stays dependency-free; both adapters share this one diagnosis instead + * of keeping near-identical local copies. + * @param raw - the credential exactly as supplied. + * @param pkg - the refusing package name, prefixed to the diagnostic. + * @param ref - the credential reference the value resolved through. + * @returns the trimmed, usable key. + */ +export function assertUsableApiKey(raw, pkg, ref) { + const checked = normalizeApiKey(raw); + if (checked.ok) + return checked.value; + // The Models page is named as the writer it usually is, not as the only one: + // the same value can arrive from a hand-edited .env or a shell export in a + // composition that mounts no credentials seam at all, where directing the + // user to a page that deployment does not serve would be a dead end. + throw new LlmError(checked.reason === 'empty' + ? `${pkg}: the API key resolved from ${ref} is blank; set ${ref} to the raw key` + + ' (the web Models page writes it) or export it in the launching environment' + : `${pkg}: the API key resolved from ${ref} contains characters no HTTP header can carry;` + + ` set ${ref} to the raw key alone (the web Models page writes it)`, INVALID_CREDENTIAL_CODE); +} +/** + * Provider-wire adapter for the harness message and stream vocabulary. Register implementations + * with `ctx.llm.registerAdapter(providers, adapter)`. Every provider HTTP request must include + * `attributionHeaders()`; prove the headers are added in the wire request or library header hook. The direct-fetch + * DeepSeek and library-backed pi-ai adapters meet this contract through different internals. + */ +export class LlmAdapter { + /** + * Describe one provider route owned by this adapter. + * @param provider - a route passed to `registerAdapter()` for this instance. + * @returns detached display metadata whose id must equal `provider`. + */ + providerInfo(provider) { + return { id: provider, name: provider }; + } + /** + * Return the provider-owned retry policy captured with this route. + * @param _provider - a route passed to `registerAdapter()` for this instance. + * @returns a resolved policy, or `undefined` to use the normal defaults. + */ + providerRetryPolicy(_provider) { + return undefined; + } + /** + * List models this adapter can currently advertise for one owned provider. + * The result is advisory: an adapter may accept unlisted model ids, and + * consumers must not turn absence into request rejection. + * @param _provider - one provider route owned by this adapter. + * @returns discoverable models in adapter-preferred order. + */ + listModels(_provider) { + return Promise.resolve([]); + } + /** + * Resolve all metadata available for one exact model. This query is + * independent of the advisory catalog and does not validate request routing. + * @param provider - one provider route owned by this adapter. + * @param model - exact model id passed to {@link GenerateOptions.model}. + * @param _signal - cancellation for this exact-model lookup; asynchronous + * implementations must settle promptly after it aborts. + * @returns provider/model identity plus any context, call-default, and reasoning metadata. + */ + resolveModel(provider, model, _signal) { + return Promise.resolve({ provider, id: model, name: model }); + } +} +/** + * The abstract `llm` service: an adapter registry plus a streaming model-call + * API, interceptable via the `llm/stream` waterfall. + */ +export class LlmRuntime extends Service { + adapters = new Map(); + directory = new Map(); + discoveries = new Map(); + constructor(ctx) { + super(ctx, 'llm'); + } + /** Notify topology observers without letting one broken listener veto the commit. */ + emitAdaptersUpdated() { + // Cordis emit uses Array.map: one synchronous throw starves later + // listeners. Registry notifications are non-vetoing, so contain each + // callback independently; INVARIANT-coded failures still surface. + let invariantFailure; + for (const listener of this.ctx.events.dispatch('emit', ['llm/adapters-updated'])) { + try { + const returned = listener(); + if (returned != null && typeof returned.then === 'function') { + // An emit listener may still be an async function; its rejection + // cannot reach the synchronous INVARIANT rethrow below, so it is + // contained here instead of becoming an unhandled rejection. + void Promise.resolve(returned).then(undefined, (error) => { + this.warnAdaptersListenerFailure(error); + }); + } + } + catch (error) { + if (error?.code === 'INVARIANT') { + invariantFailure ??= error; + continue; + } + this.warnAdaptersListenerFailure(error); + } + } + if (invariantFailure !== undefined) + throw invariantFailure; + } + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnAdaptersListenerFailure(error) { + this.ctx.logger.warn('llm: an llm/adapters-updated listener failed'); + this.ctx.logger.warn(error); + } + /** + * Register an adapter for the given provider routes. Throws `LlmError` with code + * `DUPLICATE_ADAPTER` if any provider already has an adapter (all-or-nothing). + * Disposed with the fiber. + * @param providers - every provider route this adapter should serve. + * @param adapter - the adapter that streams calls for those providers. + * @returns the disposer, carrying {@link AdapterRegistrationHandle.replace}. + */ + registerAdapter(providers, adapter) { + // The routes this registration currently holds; `replace` rewrites it, and + // the disposer releases whatever it holds at disposal time. + const owned = new Set(); + // The disposer has run: `owned` being empty cannot say so on its own, + // because `replace([])` legally leaves a live registration holding none. + let released = false; + const dispose = this.ctx.effect(function* () { + if (providers.length === 0) + throw new LlmError('an adapter must register at least one provider', 'INVALID_ADAPTER'); + this.commitRoutes(owned, this.prepareRoutes(providers, adapter, owned)); + yield () => { + released = true; + for (const provider of owned) + this.adapters.delete(provider); + owned.clear(); + this.emitAdaptersUpdated(); + }; + }.bind(this), 'llm.registerAdapter()'); + // ctx.effect's disposer returns Promise; our disposer API is + // synchronous fire-and-forget — discard the (always-resolved) promise. + const handle = (() => void dispose()); + handle.replace = (next) => { + // Registering here would leak: the effect's disposer already ran, so + // nothing remains to release whatever this call would put in the map. + if (released) { + throw new LlmError('a disposed adapter registration cannot replace its routes', 'REGISTRATION_DISPOSED'); + } + this.commitRoutes(owned, this.prepareRoutes(next, adapter, owned)); + }; + return handle; + } + /** + * Validate one candidate route set for `adapter`, treating routes this + * registration already holds as available. Nothing is mutated: a rejected + * candidate leaves the registry exactly as it was. + */ + prepareRoutes(providers, adapter, owned) { + const unique = new Set(); + const registrations = []; + for (const provider of providers) { + if (provider.length === 0) + throw new LlmError('adapter provider names must be non-empty', 'INVALID_ADAPTER'); + if (unique.has(provider) || (this.adapters.has(provider) && !owned.has(provider))) { + throw new LlmError(`an adapter for provider "${provider}" is already registered`, 'DUPLICATE_ADAPTER'); + } + const info = adapter.providerInfo(provider); + if (typeof info.id !== 'string' || info.id !== provider || typeof info.name !== 'string' || info.name.length === 0) { + throw new LlmError(`adapter metadata for provider "${provider}" must preserve its id and have a non-empty name`, 'INVALID_ADAPTER'); + } + unique.add(provider); + const retryPolicy = adapter.providerRetryPolicy(provider) + ?? resolveRetryPolicy(undefined, `llm: provider "${provider}" retryPolicy`); + registrations.push({ + adapter, + provider: { id: info.id, name: info.name }, + retryPolicy, + }); + } + return registrations; + } + /** + * Swap this registration's routes for the prepared ones in one synchronous + * section, so no observer can see the registry between the release and the + * re-registration. The route set's one mutation point is also where + * `llm/adapters-updated` is published, so a `replace` announces itself + * exactly like a first registration. + */ + commitRoutes(owned, registrations) { + for (const provider of owned) + this.adapters.delete(provider); + owned.clear(); + for (const registration of registrations) { + this.adapters.set(registration.provider.id, registration); + owned.add(registration.provider.id); + } + this.emitAdaptersUpdated(); + } + /** + * Describe provider routes with a registered adapter. + * @returns detached provider metadata in registration order. + */ + listProviders() { + return [...this.adapters.values()].map(({ provider }) => ({ ...provider })); + } + /** + * Declare provider routes an adapter plugin can activate through + * configuration. Registration is all-or-nothing: an empty list, invalid + * entry, or a provider already declared by any registration throws + * `LlmError` without registering the rest. Disposed with the fiber. + * @param entries - every configurable provider this plugin owns. + * @returns a handle that withdraws all of them, and can atomically replace them. + */ + registerConfigurableProviders(entries) { + let held = []; + let disposed = false; + /** + * Validate a candidate set in full against everything this registration + * does not already hold, then publish it. Nothing is written until the + * whole set passes, so a refused candidate leaves the current entries in + * place — the property that makes `replace` a swap rather than a + * delete-then-add that can strand the directory empty. + */ + const commit = (candidates) => { + const detached = []; + const own = new Set(held.map(entry => entry.provider)); + for (const entry of candidates) { + if (entry.provider.length === 0 || entry.displayName.length === 0 || entry.settingsNs.length === 0) { + throw new LlmError('configurable providers need a non-empty provider, displayName, and settingsNs', 'INVALID_DIRECTORY'); + } + if (entry.settingsPath.some(segment => segment.length === 0)) { + throw new LlmError(`configurable provider "${entry.provider}" has an empty settingsPath segment`, 'INVALID_DIRECTORY'); + } + if ((this.directory.has(entry.provider) && !own.has(entry.provider)) + || detached.some(seen => seen.provider === entry.provider)) { + throw new LlmError(`configurable provider "${entry.provider}" is already declared`, 'DUPLICATE_DIRECTORY'); + } + detached.push({ ...entry, settingsPath: [...entry.settingsPath] }); + } + for (const entry of held) + this.directory.delete(entry.provider); + for (const entry of detached) + this.directory.set(entry.provider, entry); + held = detached; + this.emitAdaptersUpdated(); + }; + const dispose = this.ctx.effect(function* () { + if (entries.length === 0) { + throw new LlmError('a configurable-provider registration must declare at least one provider', 'INVALID_DIRECTORY'); + } + commit(entries); + yield () => { + disposed = true; + for (const entry of held) + this.directory.delete(entry.provider); + held = []; + this.emitAdaptersUpdated(); + }; + }.bind(this), 'llm.registerConfigurableProviders()'); + const handle = (() => void dispose()); + handle.replace = (next) => { + if (disposed) { + throw new LlmError('this configurable-provider registration was disposed', 'REGISTRATION_DISPOSED'); + } + commit(next); + }; + return handle; + } + /** + * List every declared configurable provider, registered or dormant. + * @returns detached directory entries in declaration order. + */ + listConfigurableProviders() { + return [...this.directory.values()].map(entry => ({ ...entry, settingsPath: [...entry.settingsPath] })); + } + /** + * Offer to interrogate provider endpoints on behalf of the settings + * namespace this plugin owns. The namespace is the key because that is what + * a configuration surface already holds from the configurable-provider + * directory, and because a provider being *added* has no route to name yet. + * Disposed with the fiber. + * @param settingsNs - the namespace whose profiles this discovery serves. + * @param discover - interrogates one endpoint; must honor `request.signal`. + * @returns the disposer that withdraws the offer. + */ + registerModelDiscovery(settingsNs, discover) { + const dispose = this.ctx.effect(function* () { + if (settingsNs.length === 0) { + throw new LlmError('model discovery needs a non-empty settings namespace', 'INVALID_DISCOVERY'); + } + if (this.discoveries.has(settingsNs)) { + throw new LlmError(`model discovery for "${settingsNs}" is already registered`, 'DUPLICATE_DISCOVERY'); + } + this.discoveries.set(settingsNs, discover); + yield () => { + this.discoveries.delete(settingsNs); + }; + }.bind(this), 'llm.registerModelDiscovery()'); + return () => void dispose(); + } + /** + * Interrogate one provider endpoint for the models it advertises. The + * request describes a draft, not a stored route, so nothing here reads or + * writes settings or credentials — the caller owns both, and the reply is + * candidate metadata a surface may offer for adoption. + * @param settingsNs - namespace whose registered discovery serves this draft. + * @param request - the endpoint, protocol, and one-shot credential to use. + * @returns the advertised models, deduplicated in endpoint order. + */ + async discoverModels(settingsNs, request) { + const discover = this.discoveries.get(settingsNs); + if (discover === undefined) { + throw new LlmError(`no model discovery is registered for "${settingsNs}"`, 'NO_DISCOVERY'); + } + // One of the two identifies what to describe: a route the adapter knows, or + // an endpoint to ask. Neither leaves nothing to answer about. + if ((request.provider ?? '').length === 0 && (request.baseURL ?? '').length === 0) { + throw new LlmError('model discovery needs a provider route or a baseURL', 'INVALID_DISCOVERY'); + } + const discovered = await discover(request); + const seen = new Set(); + const models = []; + for (const model of discovered) { + if (typeof model.id !== 'string' || model.id.length === 0 || seen.has(model.id)) + continue; + seen.add(model.id); + models.push({ + id: model.id, + ...model.name === undefined ? {} : { name: model.name }, + ...model.contextWindow === undefined ? {} : { contextWindow: model.contextWindow }, + ...model.maxTokens === undefined ? {} : { maxTokens: model.maxTokens }, + }); + } + return models; + } + /** + * Resolve the retry policy captured when one provider route was registered. + * @param provider - registered provider route to inspect. + * @returns the provider-owned policy, with normal defaults already resolved. + */ + providerRetryPolicy(provider) { + return this.registration(provider).retryPolicy; + } + /** Detach typed adapter-owned modality metadata. */ + detachedModalities(modalities) { + return modalities === undefined ? undefined : [...modalities]; + } + /** + * Discover models advertised by one registered provider. Catalog membership + * is advisory and never changes routing or request validation. + * @param provider - registered provider route to inspect. + * @returns detached model metadata in adapter-preferred order. + */ + async listModels(provider) { + const adapter = this.registration(provider).adapter; + const models = await adapter.listModels(provider); + const seen = new Set(); + return models.map((model) => { + if (typeof model.provider !== 'string' + || model.provider !== provider + || typeof model.id !== 'string' + || model.id.length === 0 + || typeof model.name !== 'string' + || model.name.length === 0 + || (model.description !== undefined && typeof model.description !== 'string') + || seen.has(model.id)) { + throw new LlmError(`adapter returned invalid or duplicate model metadata for provider "${provider}"`, 'INVALID_CATALOG'); + } + seen.add(model.id); + const inputModalities = this.detachedModalities(model.inputModalities); + return { + provider: model.provider, + id: model.id, + name: model.name, + ...model.description === undefined ? {} : { description: model.description }, + ...inputModalities === undefined ? {} : { inputModalities }, + }; + }); + } + /** + * Resolve and validate all metadata from the adapter that owns one exact + * route. The result is detached from adapter-owned objects; catalog + * membership remains advisory and does not control request routing. + * @param provider - registered provider route to inspect. + * @param model - exact model id passed to the adapter. + * @param signal - optional cancellation for adapter-owned asynchronous lookup. + * @returns exact model identity plus available context and reasoning metadata. + */ + async resolveModelInfo(provider, model, signal) { + return this.resolveModelInfoFor(this.registration(provider), model, signal); + } + async resolveModelInfoFor(registration, model, signal) { + const provider = registration.provider.id; + const resolved = await registration.adapter.resolveModel(provider, model, signal); + if (typeof resolved.provider !== 'string' + || resolved.provider !== provider + || typeof resolved.id !== 'string' + || resolved.id !== model + || typeof resolved.name !== 'string' + || resolved.name.length === 0 + || (resolved.description !== undefined && typeof resolved.description !== 'string')) { + throw new LlmError(`adapter returned invalid exact model metadata for provider "${provider}" model "${model}"`, 'INVALID_MODEL_INFO'); + } + const context = resolved.context; + if (context !== undefined && (!Number.isInteger(context.contextWindow) || context.contextWindow <= 0)) { + throw new LlmError(`adapter returned invalid context metadata for provider "${provider}" model "${model}"`, 'INVALID_MODEL_CONTEXT'); + } + // Capability metadata rides through: an explicit modality omission is + // negative capability downstream preflights act on (image admission). + const inputModalities = this.detachedModalities(resolved.inputModalities); + const defaultMaxTokens = resolved.defaultMaxTokens; + if (defaultMaxTokens !== undefined + && (!Number.isSafeInteger(defaultMaxTokens) || defaultMaxTokens <= 0)) { + throw new LlmError(`adapter returned invalid default maxTokens for provider "${provider}" model "${model}"`, 'INVALID_MODEL_MAX_TOKENS'); + } + const info = { + provider, + id: model, + name: resolved.name, + ...resolved.description === undefined ? {} : { description: resolved.description }, + ...inputModalities === undefined ? {} : { inputModalities }, + ...context === undefined ? {} : { context: { contextWindow: context.contextWindow } }, + ...defaultMaxTokens === undefined ? {} : { defaultMaxTokens }, + }; + const reasoning = resolved.reasoning; + if (reasoning === undefined) + return info; + if (reasoning.efforts.length === 0) { + throw new LlmError(`adapter returned invalid reasoning metadata for provider "${provider}" model "${model}"`, 'INVALID_MODEL_REASONING'); + } + const seen = new Set(); + const efforts = reasoning.efforts.map((effort) => { + if (typeof effort.id !== 'string' + || effort.id.length === 0 + || typeof effort.name !== 'string' + || effort.name.length === 0 + || (effort.description !== undefined && typeof effort.description !== 'string') + || seen.has(effort.id)) { + throw new LlmError(`adapter returned invalid or duplicate reasoning effort metadata for provider "${provider}" model "${model}"`, 'INVALID_MODEL_REASONING'); + } + seen.add(effort.id); + return { + id: effort.id, + name: effort.name, + ...effort.description === undefined ? {} : { description: effort.description }, + }; + }); + if (reasoning.defaultEffort !== undefined && !seen.has(reasoning.defaultEffort)) { + throw new LlmError(`adapter returned an unknown default reasoning effort for provider "${provider}" model "${model}"`, 'INVALID_MODEL_REASONING'); + } + return { + ...info, + reasoning: { + efforts, + ...reasoning.defaultEffort === undefined ? {} : { defaultEffort: reasoning.defaultEffort }, + }, + }; + } + /** + * Validate a conversation call config against its exact model capability and + * materialize adapter-configured defaults. Unsupported explicit efforts + * reject before provider I/O; no clamping or aliasing is performed. This + * standalone query does not bind a later dispatch; use {@link prepareCall} + * when logging and streaming must share one adapter registration. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a detached config only when a default must be materialized. + */ + async resolveCallConfig(config, signal) { + return (await this.resolveCallFor(this.registration(config.provider), config, signal)).config; + } + async resolveCallFor(registration, config, signal) { + const info = await this.resolveModelInfoFor(registration, config.model, signal); + const defaulted = config.maxTokens === undefined && info.defaultMaxTokens !== undefined + ? { ...config, maxTokens: info.defaultMaxTokens } + : config; + const reasoning = info.reasoning; + const requested = defaulted.reasoningEffort; + let resolvedConfig = defaulted; + if (reasoning === undefined) { + if (requested !== undefined) { + throw new LlmError(`provider "${config.provider}" model "${config.model}" does not support reasoning effort "${requested}"`, 'UNSUPPORTED_REASONING_EFFORT'); + } + } + else { + const effective = requested ?? reasoning.defaultEffort; + if (effective !== undefined) { + if (!reasoning.efforts.some(effort => effort.id === effective)) { + throw new LlmError(`provider "${config.provider}" model "${config.model}" does not support reasoning effort "${effective}"`, 'UNSUPPORTED_REASONING_EFFORT'); + } + if (requested !== effective) + resolvedConfig = { ...defaulted, reasoningEffort: effective }; + } + } + return { + config: resolvedConfig, + ...info.context === undefined ? {} : { context: info.context }, + }; + } + /** + * Resolve one call under its current adapter registration. The returned + * one-shot handle keeps that registration across header logging and dispatch, + * so HMR cannot combine one adapter's capability result with another adapter. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a prepared config and its registration-bound stream entry point. + */ + async prepareCall(config, signal) { + const registration = this.registration(config.provider); + const resolved = await this.resolveCallFor(registration, config, signal); + const resolvedConfig = deepFreeze(structuredClone(resolved.config)); + const context = resolved.context === undefined + ? undefined + : deepFreeze(structuredClone(resolved.context)); + const adapterDefaults = deepFreeze({ + ...config.reasoningEffort === undefined && resolvedConfig.reasoningEffort !== undefined + ? { reasoningEffort: true } + : {}, + ...config.maxTokens === undefined && resolvedConfig.maxTokens !== undefined + ? { maxTokens: true } + : {}, + }); + let dispatched = false; + return Object.freeze({ + config: resolvedConfig, + retryPolicy: registration.retryPolicy, + adapterDefaults, + ...context === undefined ? {} : { context }, + stream: (options) => { + if (dispatched) { + throw new LlmError('a prepared LLM call can only be dispatched once', 'INVALID_PREPARED_CALL'); + } + if (!callConfigEquals(options, resolvedConfig)) { + throw new LlmError('prepared LLM call config changed before adapter dispatch', 'INVALID_PREPARED_CALL'); + } + dispatched = true; + return this.streamWithRegistration(options, { registration, config: resolvedConfig }); + }, + }); + } + registration(provider) { + const registration = this.adapters.get(provider); + if (!registration) + throw new LlmError(`no adapter registered for provider "${provider}"`, 'NO_ADAPTER'); + return registration; + } + /** Remove replay state whose historical route is owned by another adapter. */ + forAdapter(options, adapter) { + const messages = options.messages.map((message) => { + const source = message.source; + if (message.role !== 'assistant' || source.kind !== 'model' || source.replayState === undefined) + return message; + if (this.adapters.get(source.provider)?.adapter === adapter) + return message; + return freezeMessage({ + ...message, + source: { kind: 'model', provider: source.provider, model: source.model }, + }); + }); + if (messages.every((message, index) => message === options.messages[index])) + return options; + const filtered = { ...options, messages }; + return Object.isFrozen(options) ? deepFreeze(filtered) : filtered; + } + /** + * Final adapter boundary. Adapter selection, dispatch, iterator construction, + * and iteration failures become one terminal failure chunk. Middleware and + * downstream consumer failures remain thrown plugin or consumer errors. + */ + async *adapterStream(options, prepared) { + let iterator; + try { + const registration = prepared?.registration ?? this.registration(options.provider); + const resolvedConfig = prepared === undefined + ? (await this.resolveCallFor(registration, options, options.signal)).config + : prepared.config; + if (prepared !== undefined && !callConfigEquals(options, resolvedConfig)) { + throw new LlmError('prepared LLM call config changed before adapter dispatch', 'INVALID_PREPARED_CALL'); + } + const resolvedOptions = callConfigEquals(options, resolvedConfig) + ? options + : Object.isFrozen(options) + ? deepFreeze({ ...options, ...resolvedConfig }) + : { ...options, ...resolvedConfig }; + const adapter = registration.adapter; + const stream = adapter.stream(this.forAdapter(resolvedOptions, adapter)); + iterator = stream[Symbol.asyncIterator](); + } + catch (error) { + yield adapterFailureChunk(error, options.signal); + return; + } + let completed = false; + try { + while (true) { + let item; + try { + const next = await iterator.next(); + item = next.done + ? { done: true } + : { done: false, value: next.value }; + } + catch (error) { + completed = true; + yield adapterFailureChunk(error, options.signal); + return; + } + if (item.done) { + completed = true; + return; + } + // End the adapter-owned try before yielding: consumer/middleware + // failures resumed into this generator must remain thrown. + yield item.value; + } + } + finally { + if (!completed) { + const close = iterator.return?.bind(iterator); + if (close) + await close(); + } + } + } + /** + * Stream one model call as raw chunks (token-level deltas). Replay state is + * retained only when the same adapter instance owns its historical provider + * and the target provider. Final adapter selection remains fixed through + * asynchronous exact-model resolution and dispatch. Adapter selection, + * dispatch, and iteration failures become terminal `error` or `aborted` + * finish chunks; middleware, nested-call, cleanup, and consumer failures + * remain thrown. + * @param options - the full request; `options.provider` selects the adapter. + * @returns the chunk stream, possibly wrapped by `llm/stream` listeners. + */ + stream(options) { + return this.streamWithRegistration(options); + } + streamWithRegistration(options, prepared) { + return this.ctx.waterfall(this, 'llm/stream', options, () => this.adapterStream(options, prepared)); + } +} +/** Convert one adapter throw into the stream protocol's terminal outcome. */ +function adapterFailureChunk(error, signal) { + const failure = normalizeLlmFailure(error); + return { + type: 'finish', + reason: signal?.aborted || failure.code === 'ABORTED' + ? { kind: 'aborted', failure } + : { kind: 'error', failure }, + }; +} +export default LlmRuntime; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.d.ts new file mode 100644 index 0000000..a463bc7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned LLM stream-protocol invariants. @module @deepseek-ai/dsh-llm/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "llm-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the LLM invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.js new file mode 100644 index 0000000..54896c8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.js @@ -0,0 +1,100 @@ +/** Package-owned LLM stream-protocol invariants. @module @deepseek-ai/dsh-llm/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-llm'; +/** Cordis companion plugin name. */ +export const name = 'llm-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Require one chunk index to be a non-negative safe integer. */ +function validateIndex(index, fail) { + if (!Number.isSafeInteger(index) || index < 0) { + fail(`LLM stream block index must be a non-negative safe integer, got ${index}`); + } +} +/** Require a delta to address an open block of its matching type. */ +function validateDelta(open, index, expected, fail) { + validateIndex(index, fail); + const actual = open.get(index); + if (actual !== expected) { + fail(`${expected} delta at index ${index} requires an open ${expected} block, got ${String(actual)}`); + } +} +/** Wrap one provider stream and enforce its grammar as chunks are consumed. */ +async function* validateStream(source, fail) { + const open = new Map(); + let usageSeen = false; + let finished = false; + for await (const chunk of source) { + if (finished) + fail(`LLM stream emitted ${chunk.type} after terminal finish`); + switch (chunk.type) { + case 'block-start': + validateIndex(chunk.index, fail); + if (open.has(chunk.index)) + fail(`LLM stream repeated block-start index ${chunk.index}`); + open.set(chunk.index, chunk.blockType); + break; + case 'text-delta': + validateDelta(open, chunk.index, 'text', fail); + break; + case 'reasoning-delta': + validateDelta(open, chunk.index, 'reasoning', fail); + break; + case 'tool-call-delta': + validateDelta(open, chunk.index, 'tool-call', fail); + break; + case 'block-end': { + validateIndex(chunk.index, fail); + const blockType = open.get(chunk.index); + if (blockType === undefined) + fail(`LLM stream block-end index ${chunk.index} has no open block`); + if (chunk.block.type !== blockType) { + fail(`LLM stream block-end index ${chunk.index} closes ${chunk.block.type}, expected ${blockType}`); + } + open.delete(chunk.index); + break; + } + case 'usage': + if (usageSeen) + fail('LLM stream emitted usage more than once'); + usageSeen = true; + break; + case 'finish': + if (open.size > 0 && chunk.reason.kind !== 'error' && chunk.reason.kind !== 'aborted') { + fail(`LLM stream finished with ${open.size} open block(s)`); + } + finished = true; + break; + } + yield chunk; + } + if (!finished) + fail('LLM stream ended without a terminal finish chunk'); +} +/** Install validation around every provider stream. */ +const install = (ctx, fail) => { + ctx.on('llm/stream', (_options, next) => validateStream(next(), fail), { global: true, prepend: true }); + ctx.on('llm/adapters-updated', () => { + // A disposer-time emit can outlive the service-store entry during whole- + // context teardown; only a live service promises a readable registry. + const llm = ctx.get('llm'); + if (llm === undefined) + return; + for (const provider of llm.listProviders()) { + try { + llm.providerRetryPolicy(provider.id); + } + catch { + // Reaching here IS the violation: the notification promised a readable + // registry, and only that broken promise can make the lookup throw. + fail(`llm/adapters-updated fired while provider "${provider.id}" has no readable registration`); + } + } + }, { global: true }); +}; +/** + * Register the LLM invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/message.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/message.d.ts new file mode 100644 index 0000000..67b4554 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/message.d.ts @@ -0,0 +1,206 @@ +/** Message value types, identity, and immutable construction helpers. */ +import { MessageId, type CallId } from './brand.ts'; +import type { ContentBlock, StreamChunk, ToolResultBlock } from './types.ts'; +/** Provider/model identity and adapter-private replay data for an assistant message. */ +export interface AssistantProvenance { + /** Provider route that produced the message. */ + provider: string; + /** Provider model id that produced the message. */ + model: string; + /** + * Lossless-JSON adapter state needed to replay the provider response. + * `LlmRuntime` exposes it to a target adapter only when that adapter instance + * currently owns both this historical provider and the target provider. + */ + replayState?: unknown; +} +/** Required source of an assistant message produced by a routed model. */ +export interface ModelMessageSource extends AssistantProvenance { + kind: 'model'; +} +/** Required source of a user-role message carrying one tool result. */ +export interface ToolMessageSource { + kind: 'tool'; + callId: CallId; +} +/** + * The kind of information in producer-supplied context, declared by the + * producer beside its provenance. + * + * `MessageSource.kind` answers *who produced this*; `form` answers *what kind + * of thing it is*, and the two axes are deliberately independent — several + * producers share one form, and one producer may emit more than one form over + * a session. + * + * The vocabulary is SEMANTIC, never visual: a value states that the content is + * a file's instructions or a catalog of available items, and a consumer decides + * what that looks like. Colors, icons, ordering, and collapse defaults are the + * consumer's business and must not enter this union. It grows one value at a + * time as producers gain the structured fields their form needs; an absent or + * unknown value is the documented default, presented as opaque content. + */ +export type ContextForm = +/** Instructions read out of workspace files the model is expected to follow. */ +'instructions' +/** A catalog of items available in this session, republished as it changes. */ + | 'catalog' +/** Current state, where a later snapshot from the same producer supersedes an earlier one. */ + | 'snapshot' +/** A one-off account of something that just happened; it supersedes nothing. */ + | 'notice' +/** A message another agent addressed to this one. */ + | 'relay' +/** Material lifted out of another session's log, possibly reduced on the way in. */ + | 'recall'; +/** One named contribution to a `snapshot`-form context, in assembly order. */ +export interface ContextSnapshotSection { + /** The contributing subsystem's name. */ + readonly name: string; + /** That contribution's model-facing text, exactly as assembled. */ + readonly text: string; +} +/** + * Producer-declared {@link ContextForm} and the fields that form requires, + * mixed into the source types that carry one. + * + * Discriminated by `form` so a producer cannot select a form without the + * fields needed to present it: a `notice` must record its one-line + * account, a `snapshot` its sections. Omitting `form` stays valid — an + * undeclared context is the documented default. + */ +export type ContextFormed = { + readonly form?: never; +} | { + readonly form: 'instructions'; +} | { + readonly form: 'catalog'; +} | { + readonly form: 'snapshot'; + /** The named contributions this snapshot assembled, in order. */ + readonly sections: readonly ContextSnapshotSection[]; +} | { + readonly form: 'notice'; + /** One-line account of what happened, shown without expanding the row. */ + readonly summary: string; +} | { + readonly form: 'relay'; +} | { + readonly form: 'recall'; +}; +/** + * Where a message (or injected content) came from. + * Merge-extensible sum type — plugins add their own `kind`s. + */ +export interface MessageSourceMap { + user: { + kind: 'user'; + }; + plugin: { + kind: 'plugin'; + plugin: string; + } & ContextFormed; + model: ModelMessageSource; + tool: ToolMessageSource; +} +/** + * Bound for a `notice` summary. The account rides a collapsed transcript row + * and is committed to the durable log, while its inputs — task labels, goal + * objectives, tool arguments — are caller text with no length of their own. + */ +export declare const CONTEXT_SUMMARY_MAX_CHARS = 120; +/** + * Bound one `notice` summary to {@link CONTEXT_SUMMARY_MAX_CHARS}. + * @param summary - the producer's one-line account, of any length. + * @returns the account, ellipsized when it exceeds the bound. + */ +export declare function boundContextSummary(summary: string): string; +/** Any known message source, derived from {@link MessageSourceMap}; switch on `kind` and fall through unknowns (merge-extensible). */ +export type MessageSource = MessageSourceMap[keyof MessageSourceMap]; +/** One immutable message representation shared by delivery, durable history, and model requests. */ +export interface Message { + /** Stable identity preserved across every representation boundary. */ + readonly id: MessageId; + /** Provider-neutral conversation role. */ + readonly role: 'system' | 'user' | 'assistant'; + /** Exact model-facing blocks. */ + readonly content: ContentBlock[]; + /** Required source fields supplied by the producer. */ + readonly source: MessageSource; +} +/** A user-role specialization of the one shared message representation. */ +export interface UserMessage extends Message { + readonly role: 'user'; +} +/** A model-produced assistant specialization of the shared message representation. */ +export interface AssistantMessage extends Message { + readonly role: 'assistant'; + readonly source: ModelMessageSource; +} +/** A tool-result specialization whose model-facing block retains call correlation. */ +export interface ToolResultMessage extends Message { + readonly role: 'user'; + readonly content: [ToolResultBlock]; + readonly source: ToolMessageSource; +} +type NewMessage = Omit; +type NewUserMessage = Omit; +type NewAssistantMessage = Omit & { + readonly source: Omit & { + readonly kind?: never; + }; +}; +/** + * Detach and deep-freeze a message whose identity already exists. + * @param message - complete message, including its stable identity. + * @returns an immutable snapshot that preserves the identity. + */ +export declare function freezeMessage(message: T): T; +/** + * Create one identified message and freeze it before publication. + * @param input - complete role, content, and source for a new message. + * @returns an immutable message with a fresh stable identity. + */ +export declare function createMessage(input: T & { + readonly id?: never; +}): T & Pick; +/** + * Create one identified user-role message and freeze it before publication. + * @param input - complete content and source for a new user message. + * @returns an immutable user message with a fresh stable identity. + */ +export declare function createUserMessage(input: T & { + readonly id?: never; + readonly role?: never; +}): T & Pick; +/** + * Create one identified model-produced assistant message and freeze it before publication. + * @param input - complete content plus the provider, model, and optional replay state for a new assistant message. + * @returns an immutable assistant message with fixed role/source tags and a fresh stable identity. + */ +export declare function createAssistantMessage(input: NewAssistantMessage & { + readonly id?: never; + readonly role?: never; +}): AssistantMessage; +/** Input whose acceptance creates one tool-result message. */ +export interface ToolResultMessageInput { + readonly callId: CallId; + readonly content: ContentBlock[]; + readonly isError: boolean; +} +/** + * Create and freeze one identified tool-result message. + * @param input - call identity, raw result blocks, and outcome. + * @returns an immutable user-role tool-result message. + */ +export declare function createToolResultMessage(input: ToolResultMessageInput): ToolResultMessage; +/** + * Whether a stream chunk carries visible model output (the first-token + * boundary shared by client step timing and the whole-log sessionStats + * projection). Empty deltas (heartbeats, empty tool-call frames) do not count + * as a first token. + * @param chunk - the stream chunk to test. + * @returns true when the chunk contains a non-empty text/reasoning/tool delta. + */ +export declare function isTokenDelta(chunk: StreamChunk): boolean; +export {}; +//# sourceMappingURL=message.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/message.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/message.js new file mode 100644 index 0000000..45b34a1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/message.js @@ -0,0 +1,100 @@ +/** Message value types, identity, and immutable construction helpers. */ +import { MessageId } from "./brand.js"; +import { deepFreeze } from "./call-config.js"; +/** + * Bound for a `notice` summary. The account rides a collapsed transcript row + * and is committed to the durable log, while its inputs — task labels, goal + * objectives, tool arguments — are caller text with no length of their own. + */ +export const CONTEXT_SUMMARY_MAX_CHARS = 120; +/** + * Bound one `notice` summary to {@link CONTEXT_SUMMARY_MAX_CHARS}. + * @param summary - the producer's one-line account, of any length. + * @returns the account, ellipsized when it exceeds the bound. + */ +export function boundContextSummary(summary) { + return summary.length <= CONTEXT_SUMMARY_MAX_CHARS + ? summary + : `${summary.slice(0, CONTEXT_SUMMARY_MAX_CHARS - 1)}…`; +} +/** + * Detach and deep-freeze a message whose identity already exists. + * @param message - complete message, including its stable identity. + * @returns an immutable snapshot that preserves the identity. + */ +export function freezeMessage(message) { + return deepFreeze(structuredClone(message)); +} +/** + * Create one identified message and freeze it before publication. + * @param input - complete role, content, and source for a new message. + * @returns an immutable message with a fresh stable identity. + */ +export function createMessage(input) { + return freezeMessage({ + ...input, + id: MessageId(crypto.randomUUID()), + }); +} +/** + * Create one identified user-role message and freeze it before publication. + * @param input - complete content and source for a new user message. + * @returns an immutable user message with a fresh stable identity. + */ +export function createUserMessage(input) { + return createMessage({ + ...input, + role: 'user', + }); +} +/** + * Create one identified model-produced assistant message and freeze it before publication. + * @param input - complete content plus the provider, model, and optional replay state for a new assistant message. + * @returns an immutable assistant message with fixed role/source tags and a fresh stable identity. + */ +export function createAssistantMessage(input) { + return createMessage({ + role: 'assistant', + content: input.content, + source: { + kind: 'model', + ...input.source, + }, + }); +} +/** + * Create and freeze one identified tool-result message. + * @param input - call identity, raw result blocks, and outcome. + * @returns an immutable user-role tool-result message. + */ +export function createToolResultMessage(input) { + return createUserMessage({ + source: { kind: 'tool', callId: input.callId }, + content: [{ + type: 'tool-result', + toolCallId: input.callId, + content: input.content, + isError: input.isError, + }], + }); +} +/** + * Whether a stream chunk carries visible model output (the first-token + * boundary shared by client step timing and the whole-log sessionStats + * projection). Empty deltas (heartbeats, empty tool-call frames) do not count + * as a first token. + * @param chunk - the stream chunk to test. + * @returns true when the chunk contains a non-empty text/reasoning/tool delta. + */ +export function isTokenDelta(chunk) { + switch (chunk.type) { + case 'text-delta': + case 'reasoning-delta': + return chunk.text !== ''; + case 'tool-call-delta': + return chunk.argumentsDelta !== '' || chunk.name !== undefined; + default: + return false; + } +} +//# sourceMappingURL=message.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/never.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/never.d.ts new file mode 100644 index 0000000..6efa7a4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/never.d.ts @@ -0,0 +1,16 @@ +/** + * Exhaustiveness helper for closed core unions. Use {@link assertNever} at the default branch so a + * new variant fails compilation at every required handler. Do not use it for declaration-merged + * unions such as session events or content blocks: handle known variants and explicitly fall + * through because plugins may add valid unknown cases. + * @module @deepseek-ai/dsh-llm/never + */ +/** + * Mark an unreachable closed-union branch. A newly unhandled typed variant fails at the call site; + * a value that escaped its type throws with diagnostics at runtime. + * @param value - the impossible value; typed `never` so an unhandled variant fails compilation at the call site. + * @param context - optional label (e.g. the switch site) prefixed into the throw message. + * @returns never — it always throws, with the offending value JSON-rendered in the message. + */ +export declare function assertNever(value: never, context?: string): never; +//# sourceMappingURL=never.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/never.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/never.js new file mode 100644 index 0000000..2381b13 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/never.js @@ -0,0 +1,21 @@ +/** + * Exhaustiveness helper for closed core unions. Use {@link assertNever} at the default branch so a + * new variant fails compilation at every required handler. Do not use it for declaration-merged + * unions such as session events or content blocks: handle known variants and explicitly fall + * through because plugins may add valid unknown cases. + * @module @deepseek-ai/dsh-llm/never + */ +/** + * Mark an unreachable closed-union branch. A newly unhandled typed variant fails at the call site; + * a value that escaped its type throws with diagnostics at runtime. + * @param value - the impossible value; typed `never` so an unhandled variant fails compilation at the call site. + * @param context - optional label (e.g. the switch site) prefixed into the throw message. + * @returns never — it always throws, with the offending value JSON-rendered in the message. + */ +export function assertNever(value, context) { + // JSON.stringify is typed string but returns undefined for undefined input; + // String() covers that and other non-serializable escapes. + const rendered = JSON.stringify(value) ?? String(value); + throw new Error(`unreachable variant${context ? ` in ${context}` : ''}: ${rendered}`); +} +//# sourceMappingURL=never.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.d.ts new file mode 100644 index 0000000..a8f9447 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.d.ts @@ -0,0 +1,66 @@ +/** + * Provider-owned request-retry policy configuration and resolution. + * + * Adapters expose one resolved policy per registered provider route; the + * optional dsh-llm-retry plugin executes it on the agent's failed-step extension point. + * + * @module @deepseek-ai/dsh-llm/retry-policy + */ +import z from '@deepseek-ai/schemastery'; +/** Bounded exponential backoff with symmetric jitter around each local delay. */ +export interface BackoffConfig { + /** Initial local exponential-backoff delay in milliseconds (default 500). */ + initialDelayMs?: number; + /** Maximum locally scheduled or accepted provider delay in milliseconds (default 10000). */ + maxDelayMs?: number; + /** Symmetric random multiplier range around one (default 0.1). */ + jitterRatio?: number; +} +/** Current bounded transient retry behavior for one provider route. */ +export interface NormalRetryPolicyConfig { + /** Retry only configured transient failure codes. */ + mode: 'normal'; + /** Maximum eligible retries after the first request (default 2). */ + maxRetries?: number; + /** Stable failure codes eligible for this policy. */ + retryableCodes?: string[]; + /** Local exponential-backoff and jitter configuration. */ + backoff?: BackoffConfig; +} +/** Unbounded retry behavior for every model-request failure on one provider route. */ +export interface AlwaysRetryPolicyConfig { + /** Retry every model-request failure until success, cancellation, or disposal. */ + mode: 'always'; + /** Local exponential-backoff and jitter configuration. */ + backoff?: BackoffConfig; +} +/** Provider-owned model-request retry policy configuration. */ +export type RetryPolicyConfig = NormalRetryPolicyConfig | AlwaysRetryPolicyConfig; +/** Fully resolved backoff shared by both retry modes. */ +export interface ResolvedRetryBackoff { + readonly initialDelayMs: number; + readonly maxDelayMs: number; + readonly jitterRatio: number; +} +/** Fully resolved bounded transient retry policy. */ +export interface ResolvedNormalRetryPolicy extends ResolvedRetryBackoff { + readonly mode: 'normal'; + readonly maxRetries: number; + readonly retryableCodes: readonly string[]; +} +/** Fully resolved unbounded retry policy. */ +export interface ResolvedAlwaysRetryPolicy extends ResolvedRetryBackoff { + readonly mode: 'always'; +} +/** Immutable provider policy captured when its adapter route is registered. */ +export type ResolvedRetryPolicy = ResolvedNormalRetryPolicy | ResolvedAlwaysRetryPolicy; +/** Cordis schema embedded by each concrete provider configuration. */ +export declare const RetryPolicySchema: z; +/** + * Validate, default, and detach one provider-owned retry policy. + * @param config - optional provider configuration; omission selects normal defaults. + * @param path - diagnostic path naming the provider config that owns the value. + * @returns an immutable policy safe to capture in provider registration state. + */ +export declare function resolveRetryPolicy(config: RetryPolicyConfig | undefined, path: string): ResolvedRetryPolicy; +//# sourceMappingURL=retry-policy.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.js new file mode 100644 index 0000000..d3285cb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.js @@ -0,0 +1,123 @@ +/** + * Provider-owned request-retry policy configuration and resolution. + * + * Adapters expose one resolved policy per registered provider route; the + * optional dsh-llm-retry plugin executes it on the agent's failed-step extension point. + * + * @module @deepseek-ai/dsh-llm/retry-policy + */ +import z from '@deepseek-ai/schemastery'; +import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'; +import { EMPTY_RESPONSE_CODE } from "./error.js"; +const DEFAULT_MAX_RETRIES = 2; +const DEFAULT_INITIAL_DELAY_MS = 500; +const DEFAULT_MAX_DELAY_MS = 10_000; +const DEFAULT_JITTER_RATIO = 0.1; +const DEFAULT_RETRYABLE_CODES = Object.freeze([ + EMPTY_RESPONSE_CODE, + 'RATE_LIMIT', + 'SERVER', + 'TIMEOUT', + 'TRANSPORT', +]); +const backoffSchema = z.object({ + initialDelayMs: z.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_INITIAL_DELAY_MS), + maxDelayMs: z.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_MAX_DELAY_MS), + jitterRatio: z.number().min(0).max(1).default(DEFAULT_JITTER_RATIO), +}); +const normalPolicySchema = z.object({ + mode: z.const('normal').required(), + maxRetries: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_MAX_RETRIES), + retryableCodes: z.array(z.string()).default([...DEFAULT_RETRYABLE_CODES]), + backoff: backoffSchema, +}); +const alwaysPolicySchema = z.object({ + mode: z.const('always').required(), + backoff: backoffSchema, +}); +/** Cordis schema embedded by each concrete provider configuration. */ +export const RetryPolicySchema = z.union([ + normalPolicySchema, + alwaysPolicySchema, +]); +const NORMAL_POLICY_KEYS = new Set([ + 'mode', 'maxRetries', 'retryableCodes', 'backoff', +]); +const ALWAYS_POLICY_KEYS = new Set(['mode', 'backoff']); +const BACKOFF_KEYS = new Set(['initialDelayMs', 'maxDelayMs', 'jitterRatio']); +function validateKeys(value, allowed, path) { + for (const key of Object.keys(value)) { + if (!allowed.has(key)) + throw new Error(`${path}: unknown key "${key}"`); + } +} +function resolveBackoff(config, path) { + if (config !== undefined) + validateKeys(config, BACKOFF_KEYS, path); + const initialDelayMs = config?.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS; + const maxDelayMs = config?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS; + const jitterRatio = config?.jitterRatio ?? DEFAULT_JITTER_RATIO; + if (!Number.isFinite(initialDelayMs) || initialDelayMs <= 0 || initialDelayMs > MAX_TIMER_DELAY_MS) { + throw new Error(`${path}.initialDelayMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`); + } + if (!Number.isFinite(maxDelayMs) || maxDelayMs <= 0 || maxDelayMs > MAX_TIMER_DELAY_MS) { + throw new Error(`${path}.maxDelayMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`); + } + if (initialDelayMs > maxDelayMs) { + throw new Error(`${path}.initialDelayMs must be less than or equal to maxDelayMs`); + } + if (!Number.isFinite(jitterRatio) || jitterRatio < 0 || jitterRatio > 1) { + throw new Error(`${path}.jitterRatio must be between 0 and 1`); + } + return Object.freeze({ initialDelayMs, maxDelayMs, jitterRatio }); +} +/** + * Validate, default, and detach one provider-owned retry policy. + * @param config - optional provider configuration; omission selects normal defaults. + * @param path - diagnostic path naming the provider config that owns the value. + * @returns an immutable policy safe to capture in provider registration state. + */ +export function resolveRetryPolicy(config, path) { + if (config === undefined) { + return Object.freeze({ + mode: 'normal', + maxRetries: DEFAULT_MAX_RETRIES, + retryableCodes: DEFAULT_RETRYABLE_CODES, + ...resolveBackoff(undefined, `${path}.backoff`), + }); + } + switch (config.mode) { + case 'normal': { + validateKeys(config, NORMAL_POLICY_KEYS, path); + const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES; + const retryableCodes = config.retryableCodes ?? [...DEFAULT_RETRYABLE_CODES]; + if (!Number.isSafeInteger(maxRetries) || maxRetries < 0) { + throw new Error(`${path}.maxRetries must be a non-negative safe integer`); + } + if (retryableCodes.length === 0) { + throw new Error(`${path}.retryableCodes must not be empty`); + } + if (retryableCodes.some(code => typeof code !== 'string' || code.length === 0)) { + throw new Error(`${path}.retryableCodes must contain only non-empty strings`); + } + if (new Set(retryableCodes).size !== retryableCodes.length) { + throw new Error(`${path}.retryableCodes must not contain duplicates`); + } + return Object.freeze({ + mode: 'normal', + maxRetries, + retryableCodes: Object.freeze([...retryableCodes]), + ...resolveBackoff(config.backoff, `${path}.backoff`), + }); + } + case 'always': + validateKeys(config, ALWAYS_POLICY_KEYS, path); + return Object.freeze({ + mode: 'always', + ...resolveBackoff(config.backoff, `${path}.backoff`), + }); + default: + throw new Error(`${path}.mode must be "normal" or "always"`); + } +} +//# sourceMappingURL=retry-policy.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/types.d.ts new file mode 100644 index 0000000..c8829a3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/types.d.ts @@ -0,0 +1,349 @@ +/** + * Canonical provider-neutral message and streaming vocabulary for the loop, + * session log, and plugins. Adapters alone translate provider wire messages; + * mapped interfaces make the content, source, and finish unions extensible. + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'; +import type { CallId, ProviderRequestId, ReasoningEffortId } from './brand.ts'; +import type { Message } from './message.ts'; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * The provider topology changed: an adapter registered or unregistered + * routes, or the configurable-provider directory gained or lost entries. + * This payload-free registry notification fires at each commit point + * (including registration disposal); consumers re-read `listProviders()`, + * `listModels()`, or `listConfigurableProviders()` for the new state. + * Observer failures are contained and cannot veto the registry mutation. + * @mode emit + */ + 'llm/adapters-updated'(): void; + } +} +export type { AssistantMessage, AssistantProvenance, Message, MessageSource, MessageSourceMap, ModelMessageSource, ToolMessageSource, ToolResultMessage, UserMessage, } from './message.ts'; +/** Serializable provider or transport failure facts; policy decides whether they are retryable. */ +export interface LlmFailure { + /** Human-readable provider or transport failure. */ + readonly message: string; + /** Stable provider-neutral machine-routing code. */ + readonly code: string; + /** HTTP status returned by the provider, when available. */ + readonly status?: number; + /** Provider-requested delay in milliseconds, when valid and available. */ + readonly providerRetryAfterMs?: number; + /** Opaque provider-issued request identifier for diagnostics. */ + readonly requestId?: ProviderRequestId; +} +/** Plain text visible to the end user. */ +export interface TextBlock { + type: 'text'; + text: string; +} +/** Reasoning / thinking content, distinct from visible text. */ +export interface ReasoningBlock { + type: 'reasoning'; + text: string; +} +/** + * A durable raster image reference, valid in user or assistant content. The + * block is deliberately role-neutral; assistant-side rendering is forward + * compatibility — the current production adapters declare text-only output, + * so only user content carries images today. + */ +export interface ImageBlock { + type: 'image'; + /** Immutable bytes and intrinsic display metadata owned by the attachment service. */ + attachment: ImageAttachmentRef; +} +/** A tool invocation requested by the model. */ +export interface ToolCallBlock { + type: 'tool-call'; + /** Provider-issued call id; correlates with the matching tool result. */ + id: CallId; + name: string; + /** Raw JSON string as produced by the model. */ + arguments: string; +} +/** The result of a tool invocation, sent back to the model. */ +export interface ToolResultBlock { + type: 'tool-result'; + toolCallId: CallId; + content: ContentBlock[]; + isError?: boolean; +} +/** + * Merge-extensible content blocks keyed by `type`. New core blocks must land + * with adapter, UI, and compaction support. + */ +export interface ContentBlockMap { + 'text': TextBlock; + 'reasoning': ReasoningBlock; + 'image': ImageBlock; + 'tool-call': ToolCallBlock; + 'tool-result': ToolResultBlock; +} +/** The block `type` tag vocabulary; widens as plugins add entries to {@link ContentBlockMap}. */ +export type ContentBlockType = keyof ContentBlockMap; +/** Any known content block, derived from {@link ContentBlockMap}; switch on `type` and fall through unknowns (merge-extensible). */ +export type ContentBlock = ContentBlockMap[ContentBlockType]; +/** + * Why a model response stopped. + * Merge-extensible so adapters can surface provider-specific reasons. + */ +export interface FinishReasonMap { + 'stop': { + kind: 'stop'; + }; + 'tool-calls': { + kind: 'tool-calls'; + }; + 'max-tokens': { + kind: 'max-tokens'; + }; + 'aborted': { + kind: 'aborted'; + failure: LlmFailure; + }; + 'error': { + kind: 'error'; + failure: LlmFailure; + }; +} +/** Any known finish reason, derived from {@link FinishReasonMap}; switch on `kind` and fall through unknowns (merge-extensible). */ +export type FinishReason = FinishReasonMap[keyof FinishReasonMap]; +/** + * Token accounting for one model call (cache fields are optional). + * + * Counts are DISJOINT: `inputTokens` is uncached input only; cached input is + * reported separately as `cacheReadTokens`/`cacheWriteTokens` (billed input = + * sum of the three). Adapters whose providers fold cache hits into a total + * prompt count (DeepSeek's `prompt_tokens`) subtract them out. + */ +export interface TokenUsage { + inputTokens: number; + outputTokens: number; + cacheReadTokens?: number; + cacheWriteTokens?: number; + reasoningTokens?: number; +} +/** Display metadata for one registered provider route. */ +export interface LlmProviderInfo { + /** Provider route key used by {@link GenerateOptions.provider}. */ + id: string; + /** Human-readable provider name for selectors and diagnostics. */ + name: string; +} +/** Merge-extensible provider model modality vocabulary. */ +export interface ModelModalityMap { + text: 'text'; + image: 'image'; +} +/** Any declared provider model modality. */ +export type ModelModality = ModelModalityMap[keyof ModelModalityMap]; +/** + * One provider route an adapter plugin can activate through configuration, + * whether or not the route is currently registered. Configuration surfaces + * merge this directory with `listProviders()` to offer every configurable + * provider alongside its live/dormant state. + */ +export interface LlmConfigurableProvider { + /** Provider route key this entry activates when configured. */ + provider: string; + /** Human-readable provider name for configuration surfaces. */ + displayName: string; + /** User-settings namespace whose section configures this provider. */ + settingsNs: string; + /** + * Path from that namespace's section root to this provider's profile + * object; empty when the whole section is the profile. + */ + settingsPath: readonly string[]; + /** + * Whether the owning adapter knows this route only because configuration + * declared it — a gateway or self-hosted server it ships nothing about. + * Absent means the adapter draws no such distinction; false means it does + * and this route is one of its own. Only the adapter can answer: a stored + * profile is how a user-added route AND a corrected shipped one both look + * from outside. + */ + declared?: boolean; +} +/** + * One interrogation of a provider endpoint that configuration has not stored + * yet. Configuration surfaces send the draft a user is still editing, so the + * request carries the endpoint and credential directly instead of naming a + * route: a provider being added has no route to name. + */ +export interface LlmModelDiscoveryRequest { + /** + * Route the draft is editing, when it edits an existing one. A route whose + * adapter already knows its models answers from that knowledge instead of + * asking the endpoint — the adapter's own registry is the better answer, and + * it costs no network call. + */ + provider?: string; + /** + * Endpoint to interrogate. Optional because a route the adapter already + * describes needs none; a route it does not must supply one. + */ + baseURL?: string; + /** Wire protocol the endpoint speaks, when the draft names one. */ + api?: string; + /** Credential for this interrogation alone; the harness never stores it. */ + apiKey?: string; + /** Caller cancellation; implementations must settle promptly after it aborts. */ + signal?: AbortSignal; +} +/** + * One model an endpoint reports about itself. Every field but the id is + * optional because most provider listings disclose an id and nothing else; + * a surface adopting one of these still owes the capacities its adapter needs. + */ +export interface LlmDiscoveredModel { + /** Model id the endpoint accepts. */ + id: string; + /** Human-readable name when the endpoint supplies one. */ + name?: string; + /** Maximum combined request and response context, when disclosed. */ + contextWindow?: number; + /** Maximum output tokens, when disclosed. */ + maxTokens?: number; +} +/** One adapter-discovered model; catalog membership is advisory, not request validation. */ +export interface LlmModelInfo { + /** Provider route that owns this model entry. */ + provider: string; + /** Model id passed to {@link GenerateOptions.model}. */ + id: string; + /** Human-readable model name for selectors. */ + name: string; + /** Optional user-facing distinction from otherwise similar models. */ + description?: string; + /** Accepted request modalities; absent means unknown, while an explicit omission is negative capability. */ + inputModalities?: readonly ModelModality[]; +} +/** Provider-owned context capacity for one exact provider/model route. */ +export interface LlmModelContext { + /** Maximum combined request and response context in tokens. */ + contextWindow: number; +} +/** Display metadata for one adapter-owned reasoning effort. */ +export interface LlmReasoningEffortInfo { + /** Opaque stable value accepted by {@link GenerateOptions.reasoningEffort}. */ + id: ReasoningEffortId; + /** Human-readable effort name for selectors and diagnostics. */ + name: string; + /** Optional user-facing distinction from otherwise similar efforts. */ + description?: string; +} +/** Selectable reasoning efforts for one exact provider/model route. */ +export interface LlmModelReasoningInfo { + /** Supported efforts in adapter-preferred display order. */ + efforts: readonly LlmReasoningEffortInfo[]; + /** + * Adapter-configured default materialized into requests when callers omit + * an effort. Absence preserves the provider's own default. + */ + defaultEffort?: ReasoningEffortId; +} +/** Exact-route model metadata resolved by its owning adapter. */ +export interface LlmResolvedModelInfo extends LlmModelInfo { + /** Provider-owned context capacity when known. */ + context?: LlmModelContext; + /** Adapter-configured per-request output cap materialized when callers omit one. */ + defaultMaxTokens?: number; + /** Adapter-owned selectable reasoning levels when exposed. */ + reasoning?: LlmModelReasoningInfo; +} +/** + * Raw streaming protocol emitted by adapters. + * Block indexes correlate interleaved deltas, and `block-end` carries the + * assembled block. Adapters emit usage before the terminal finish and nothing + * afterward; tool arguments remain raw JSON strings. An adapter implementation + * may throw, but `LlmRuntime.stream()` normalizes that failure to a terminal + * `error` or `aborted` finish before exposing it to consumers. + */ +export type StreamChunk = { + type: 'block-start'; + index: number; + blockType: ContentBlockType; +} | { + type: 'text-delta'; + index: number; + text: string; +} | { + type: 'reasoning-delta'; + index: number; + text: string; +} | { + type: 'tool-call-delta'; + index: number; + id: CallId; + name?: string; + argumentsDelta: string; +} | { + type: 'block-end'; + index: number; + block: ContentBlock; +} | { + type: 'usage'; + usage: TokenUsage; +} | { + type: 'finish'; + reason: FinishReason; + /** Adapter-private lossless-JSON state for replaying a successful response. */ + replayState?: unknown; +}; +/** + * JSON-schema description of a tool, as sent to the model. + * + * Declared here (not in dsh-tools) because it is part of {@link GenerateOptions}; + * dsh-tools' ToolDefinition and dsh-system-prompt's PromptAssembly both import + * it from this package. + */ +export interface ToolSchema { + name: string; + description: string; + /** JSON Schema object for the arguments. */ + parameters: Record; +} +/** A single model request, fully assembled. */ +export interface GenerateOptions { + /** Registered provider route selecting the adapter instance. */ + provider: string; + model: string; + /** Adapter-owned reasoning effort selected for this exact model. */ + reasoningEffort?: ReasoningEffortId; + /** + * Ordered conversation messages, exactly as the provider sees them (after + * the `system` slot). A loop-built request assembles them as + * the derived history (dsh-agent-loop); a hand-built one-shot passes any list. + */ + messages: Message[]; + /** System prompt text (adapters map to the provider's system slot). */ + system?: string; + /** Tool schemas (adapters map to the provider's `tools` field). */ + tools?: ToolSchema[]; + temperature?: number; + maxTokens?: number; + /** + * Stop sequences: generation halts as soon as the model produces any one of + * these strings (adapters map to the provider's stop field, e.g. OpenAI + * `stop`). The stop string itself is not included in the output. + */ + stop?: string[]; + signal?: AbortSignal; + /** + * Session identity stamped by the loop for request routing. Replay uses it + * to separate cursors; adapters may map it to model-hidden transport metadata. + */ + sessionId?: Branded<'SessionId'>; + /** + * Provider-neutral classification for an auxiliary model call. Adapters may + * map the purpose to model-hidden transport metadata or purpose-specific + * generation policy. Ordinary conversation requests leave it unset. + */ + purpose?: 'compaction' | 'session-title'; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/types.js new file mode 100644 index 0000000..73a21c9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Canonical provider-neutral message and streaming vocabulary for the loop, + * session log, and plugins. Adapters alone translate provider wire messages; + * mapped interfaces make the content, source, and finish unions extensible. + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/package.json new file mode 100644 index 0000000..251597d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm/package.json @@ -0,0 +1,64 @@ +{ + "name": "@deepseek-ai/dsh-llm", + "description": "Provider-neutral LLM service interface for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/llm/llm" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./brand": { + "types": "./lib/types/brand.d.ts", + "default": "./lib/types/brand.js" + }, + "./message": { + "types": "./lib/types/message.d.ts", + "default": "./lib/types/message.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-timeout b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-timeout new file mode 120000 index 0000000..6141c18 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-timeout @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-attachment b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-attachment new file mode 120000 index 0000000..dc64562 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-attachment @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.i18n.yaml new file mode 100644 index 0000000..fce8fa0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/llm/llm/README.md +README.md: fb6bd84240b41dd730d45b3eb34c35827dc4c991 +README.zh.md: 5c22767a7c654972cbf614505382fa4755d7d318 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.md new file mode 100644 index 0000000..fb6bd84 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.md @@ -0,0 +1,101 @@ +# dsh-llm + +English | [中文](README.zh.md) + +Provider-neutral LLM vocabulary and abstract service. This package defines the canonical language spoken by the agent loop, session logs, and every plugin. + +## Service: `LlmRuntime` (ctx key: `llm`) + +An adapter registry plus a single streaming call API, interceptable via a waterfall event. + +### Public API + +- `ctx.llm.registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHandle` Register one adapter instance for the given provider routes. Registration is all-or-nothing, and is disposed with the calling fiber. The returned disposer also carries `replace(providers)`: the candidate route set is validated in full before anything moves, so a conflict with another adapter leaves the current routes registered and serving, and the swap itself is one synchronous section with no observable gap. `replace([])` is legal — a registration holding zero routes — unlike an empty initial registration. +- `ctx.llm.listProviders(): LlmProviderInfo[]` Describe registered provider routes in registration order. +- `ctx.llm.registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): DirectoryRegistrationHandle` Declare provider routes an adapter plugin can activate through configuration — registered or dormant — each naming its owning settings namespace and the path to its profile inside that section. All-or-nothing (`INVALID_DIRECTORY`/`DUPLICATE_DIRECTORY`), disposed with the calling fiber. The handle also carries `replace(entries)`: the candidate set is validated in full before anything moves, so an entry another registration already declares leaves the current set intact, and an empty array is legal there. A plugin whose declared set follows its configuration must use `replace` rather than disposing and re-registering — the latter strands the directory empty whenever the new set is refused. +- `ctx.llm.listConfigurableProviders(): LlmConfigurableProvider[]` List the declared directory in declaration order; configuration surfaces merge it with `listProviders()` to mark each entry live or dormant. An entry may carry `declared` — whether the owning adapter knows that route only because configuration named it. Only the adapter can answer, so absence means "this adapter draws no such distinction", never "shipped". +- `ctx.llm.registerModelDiscovery(settingsNs: string, discover): () => void` Offer to interrogate provider endpoints for the settings namespace this plugin owns. One offer per namespace (`INVALID_DISCOVERY`/`DUPLICATE_DISCOVERY`), disposed with the calling fiber. +- `ctx.llm.listModelDiscoveryNamespaces(): string[]` List the namespaces that can interrogate an endpoint, so a surface offers the action only where it works. +- `ctx.llm.discoverModels(settingsNs: string, request: LlmModelDiscoveryRequest): Promise` Ask one endpoint which models it advertises. +- `ctx.llm.providerRetryPolicy(provider: string): ResolvedRetryPolicy` Return the provider-owned retry policy captured during registration, with normal defaults resolved. +- `ctx.llm.listModels(provider: string): Promise` Discover the models one registered provider currently advertises. +- `ctx.llm.resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise` Resolve validated exact-model identity plus available context, output-default, and reasoning metadata from the owning adapter, with optional cancellation for asynchronous adapters. +- `ctx.llm.resolveCallConfig(config: LlmCallConfig, signal?: AbortSignal): Promise` Validate an explicit effort and materialize adapter-configured call defaults without clamping. +- `ctx.llm.prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise` Resolve a config plus detached context metadata and markers for fields supplied by adapter defaults in one exact-model lookup, then capture its current adapter registration and immutable retry policy as one cancellable, one-shot call. +- `ctx.llm.stream(options: GenerateOptions): AsyncIterable` Stream one model call as raw chunks (token-level deltas). Consumers assemble the chunks into blocks/messages with `BlockAssembler`. + +`LlmRuntime` normalizes failures from final adapter selection, synchronous dispatch, iterator construction, and iteration into the stream protocol's single terminal form: `finish { kind: 'error' | 'aborted', failure }`. A failure after partial deltas may leave content blocks open; consumers discard that incomplete output. Errors from `llm/stream` middleware, nested calls, adapter cleanup, and downstream consumers remain thrown because they are plugin or consumer failures rather than model-request outcomes. A prepared call exposes the immutable retry policy captured with its exact adapter registration; a route handled entirely by middleware has no serving policy. + +Interrogating an endpoint is configuration-time work over a *draft*, keyed by settings namespace rather than by provider route — the provider a surface is adding does not exist yet, so there is no route to name. The request may still *name* a route it is editing, and an adapter that already describes that route answers from its own knowledge without a network call; `baseURL` is optional and one of the two is required. The request otherwise carries the endpoint, the protocol, and a credential the harness uses for that one interrogation and never stores — nothing here reads or writes settings or credentials, and the reply is candidate metadata a surface may offer for adoption, never a registered catalog. `LlmDiscoveredModel` makes every field but `id` optional because most provider listings disclose an id and nothing else; a surface adopting one still owes the capacities its adapter requires. Duplicate and unusable ids are dropped, an unserved namespace fails with `NO_DISCOVERY`, and a request naming neither a route nor an endpoint fails with `INVALID_DISCOVERY`. + +Provider and model metadata is a discovery surface, not a routing whitelist. `registerAdapter()` still owns provider exclusivity and captures the adapter's retry policy for each route, while an adapter may accept model ids absent from `listModels()`; consumers must not reject a request because its model is unlisted. Returned selector metadata is detached and invalid or duplicate adapter entries fail with `INVALID_ADAPTER` or `INVALID_CATALOG`. + +Every topology commit point — adapter routes registering or disposing, directory entries appearing or withdrawing — emits the payload-free `llm/adapters-updated` event after the mutation, so consumers re-read `listProviders()`/`listModels()`/`listConfigurableProviders()` instead of polling. Observer failures are contained (logged, non-vetoing); only `INVARIANT`-coded failures rethrow after the fan-out. + +Exact-model metadata is a separate correctness query, not a catalog decoration or global LLM setting. `resolveModelInfo()` asks the adapter that owns the exact provider/model route once; an adapter can describe an unlisted dynamic model, and absent `context`, `defaultMaxTokens`, or `reasoning` fields preserve unknown capacity, provider-owned output defaults, or unavailable reasoning capability. Invalid identity, context, output default, or reasoning metadata fails with `INVALID_MODEL_INFO`, `INVALID_MODEL_CONTEXT`, `INVALID_MODEL_MAX_TOKENS`, or `INVALID_MODEL_REASONING`. + +`defaultMaxTokens` is an adapter-configured per-request output cap, not a model hard limit. `resolveCallConfig()` materializes it only when the request omits `maxTokens`; an explicit cap wins. Reasoning identifiers are opaque adapter-owned strings rather than a core enum: the same resolution accepts only an exact advertised identifier, materializes `defaultEffort` when present, and otherwise preserves the provider default. Asynchronous model resolvers receive the caller's signal and must settle promptly after cancellation. `prepareCall()` additionally exposes detached context metadata from the same lookup, reports which `maxTokens` and `reasoningEffort` fields it materialized in `adapterDefaults`, and retains the exact adapter registration through header logging and terminal dispatch, so HMR cannot combine one adapter's capability result with another adapter's request; reusing its one-shot handle or changing its call-config fields fails with `INVALID_PREPARED_CALL`. An unsupported explicit or configured effort fails with `UNSUPPORTED_REASONING_EFFORT` before provider I/O. + +### Events + +| Event | Mode | Purpose | +|---|---|---| +| `llm/stream` | waterfall | Intercept/wrap every streaming model call for caching, logging, or routing | + +### Extension points + +- Subclass `LlmAdapter` and call `ctx.llm.registerAdapter(providers, adapter)` to add one or more provider routes. `GenerateOptions.provider` selects the adapter; `GenerateOptions.model` is adapter-owned and may be resolved dynamically. Override `providerRetryPolicy()` to supply provider-owned recovery configuration, `providerInfo()` and asynchronous `listModels()` to expose selector metadata, then implement `resolveModel()` when exact identity, capacity, an output default, or selectable reasoning efforts are available; an asynchronous resolver must honor its optional cancellation signal. The defaults use bounded normal retry policy, use the route and model ids as names, advertise no models, and return no capacity, output default, or reasoning metadata. +- Wrap `llm/stream` via `ctx.on()` waterfall listeners for caching, logging, or routing. A wrapper that retries after emitting a chunk has no durable attempt boundary; shipped agent retry policy therefore uses `agent/request-error` instead. + +### Messages (`message.ts`) and content blocks (`types.ts`) + +`Message` is the shared immutable value used by delivery, durable history, and model requests. Every message has a required `MessageId`, role, content, and typed source from creation onward. `createMessage(input)` mints the identity and returns a detached deep-frozen value; `createUserMessage({ content, source })` fixes the user role; `createAssistantMessage({ content, source })` fixes the assistant role and model source kind; `createToolResultMessage({ callId, content, isError })` fixes the user role and couples the tool source to its result block; `freezeMessage(message)` imports an identity that already exists and never replaces it. Message rewrites preserve the identity and produce another frozen value. Browser code imports these value constructors from the dependency-minimal `@deepseek-ai/dsh-llm/message` entry instead of the service-bearing package root. + +Message content is an array of typed blocks: `text`, `reasoning`, `tool-call`, `tool-result`. The union is derived from the merge-extensible `ContentBlockMap`, so plugins can add block types via declaration merging. Assistant messages use a model source carrying the provider and model that produced them plus optional adapter-private replay state. Before dispatch, `LlmRuntime` retains that state only when the historical provider route and target provider route are currently owned by the exact same adapter instance; the adapter then decides whether it can restore or convert the state across models/providers. The core block set is limited to blocks every shipping path honors — multimodal content (images, audio, …) has no core block type; a feature that needs one adds it via the map together with the adapter/UI/compaction support that honors it. + +Streaming is a raw chunk protocol (`block-start`, `text-delta`, `reasoning-delta`, `tool-call-delta`, `block-end`, `usage`, `finish`). Every adapter outcome reaches consumers as one terminal `finish`; operational failure uses its `error` or `aborted` reason rather than throwing across the stream API. `BlockAssembler` is the single shared implementation that assembles chunks into blocks/messages. A successful `finish` may carry a `ReplayEnvelope` — opaque response-level replay metadata plus optional per-block entries aligned with the emitted block sequence. Assembly makes one keep/drop decision for content and metadata together: a `max-tokens` finish drops tool calls that may have been truncated, and the envelope loses the entry at each dropped position, so stored metadata always describes stored content. + +### Call configuration (`call-config.ts`) + +`LlmCallConfig` is the provider, model, optional adapter-owned reasoning effort, and sampling scalars of one conversation's requests (`provider`, `model`, `reasoningEffort`, `temperature`, `maxTokens`, `stop` — each mapping 1:1 onto the same-named `GenerateOptions` field). It is per-conversation state recorded in the session log as part of the request header (see the dsh-session `request/header` events), never a silently-adjustable per-call knob: the `agent/request` waterfall proposes a replacement, `prepareCall()` validates it and materializes adapter defaults under the turn signal, and the loop logs the effective value plus markers for fields supplied by adapter defaults before using the prepared call's registration-bound stream. The next proposal omits marked defaults so a changed route resolves its own values; unmarked explicit fields persist. `callConfigEquals(a, b)` is the field-wise real-change detector; `deepFreeze(value)` is the ownership helper the loop applies to every built request before dispatch (`llm/stream` listeners and adapters read, never rewrite). `markAgentLoopRequest()` marks that exact object as created by the process-local agent loop, and `isAgentLoopRequest()` lets observers distinguish it from independently logged auxiliary calls that may also be frozen and session-associated. `GenerateOptions.purpose` classifies logged auxiliary compaction and session-title calls so adapters can apply purpose-specific transport policy without changing ordinary conversation requests. + +### App attribution (`attribution.ts`) + +Every product adapter sends application identity on provider HTTP requests. `attributionHeaders(identity?)` builds the standard `User-Agent`, defaulting to public `APP_IDENTITY`; white-label deployments may replace but not suppress it. Adapters verify the wire header directly or through their library hook. See [the attribution Agent Note](../../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md). + +### API key validation (`api-key.ts`) + +Every adapter that puts a credential in an HTTP header judges it the same way before use. `normalizeApiKey(raw)` trims surrounding whitespace, then accepts any non-empty printable-ASCII value (`/^[\x21-\x7E]+$/`, space excluded) or reports why not as an `ApiKeyRejection` (`'empty'` | `'illegalCharacters'`), both carried in the `ApiKeyCheck` result. Absence is never judged: a caller decides whether a value was supplied before asking, since a profile naming no credential authenticates through the provider's own ambient discovery or OAuth. + +### Classes + +- `LlmAdapter` — abstract base class for provider adapters. The only required method is `stream()`. +- `BlockAssembler` — incrementally assembles raw chunks into complete content blocks and can create an identified, frozen assistant message from them. The agent loop feeds it raw chunks (logging them for replay) while reading the assembled blocks for history. +- `HarnessError` — base class for the harness error taxonomy: a stable `code` string (distinct from the human `message`) plus `cause` chaining. Lives here, in the leaf package every other imports, so a single base is shared without a new dependency edge. Per-package errors (`LlmError`, `ToolArgsError`, `InvariantError`, …) extend it. `isHarnessError(value)` narrows at process boundaries. +- `LlmError` — extends `HarnessError`; its stable `code` string (`NO_ADAPTER`, `DUPLICATE_ADAPTER`, and adapter codes like `AUTH`/`RATE_LIMIT`) matches its frozen serializable `failure.code`. The payload may also retain validated status, `Retry-After`, and branded provider request id facts; policy remains outside the error. +- `errorChain(value)` — renders a thrown value with its full `cause` chain and AggregateError members for diagnostic outputs (UI notices, logger lines, durable `turn/end` messages), so transport wrappers like undici's `TypeError: fetch failed` surface the underlying `ECONNREFUSED`/DNS/TLS detail instead of masking it. Rendering only — route on `code`, never by parsing the result. +- `CONTEXT_WINDOW_EXCEEDED_CODE` — the provider-neutral code both DeepSeek adapters use when a request exceeds the model context window, regardless of thrown-HTTP versus in-band finish delivery. `isContextWindowExceededError(detail)` is their shared conservative classifier for OpenAI-compatible provider detail. +- `QUOTA_EXCEEDED_CODE` — the non-transient provider-neutral code for exhausted account quota, balance, credits, budget, or usage limits. `isQuotaExceededError(detail)` keeps those failures distinct from request-rate limits. +- `EMPTY_RESPONSE_CODE` — the provider-neutral code both adapters use for a degenerate provider completion: a terminal `stop` that carried no content blocks at all. Classified as an error finish (not a successful empty message) because the attempt produced nothing durable; `dsh-llm-retry` retries it by default. +- `INVALID_CREDENTIAL_CODE` — the provider-neutral code for a credential that was supplied but cannot be used: malformed rather than absent, so the fix is to correct the stored value rather than supply one — the distinction from `MISSING_CREDENTIAL`. Deliberately excluded from the default retryable set, since a malformed credential fails identically on every attempt. `assertUsableApiKey(raw, pkg, ref)` throws `LlmError` with this code, the one shared diagnosis every adapter uses for an unusable stored credential. + +### Real adapters + +Two adapters implement `LlmAdapter` on different internals: [`@deepseek-ai/dsh-llm-deepseek`](../llm-deepseek) uses direct fetch with `eventsource-parser` SSE framing for the `deepseek-official` route, while [`@deepseek-ai/dsh-llm-pi-ai`](../llm-pi-ai) dynamically resolves configured provider/model pairs through `@earendil-works/pi-ai`. Both follow the `StreamChunk` conventions in `types.ts`: usage precedes finish and tool arguments remain raw strings. Adapter implementations may throw or emit a failure finish internally; `LlmRuntime` exposes both as a terminal failure finish. See [the twin LLM adapters](../../../.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.md) for the adapter rationale and [the terminal-failure decision](../../../.agents/notes/implemented/architecture/2026-07-29-terminal-llm-stream-failures.md) for the service boundary. + +## Model Experience + +None, as the service adds no model-bound text, schema, or message; it only materializes and logs an adapter-configured reasoning effort. + +#### KV Cache effect + +Pass-through; the registry preserves the assembled request prefix, while the selected adapter and provider own cache reuse and routing boundaries. + +## Known Limitations and Deferred Work + +- **No retry execution, caching, or rate limiting ships in this service** — provider registration stores retry policy, but `llm/stream` remains a single-attempt call wrapper. The agent loop separately offers proven model-request failures to `agent/request-error`, whose default preserves the original failure; `@deepseek-ai/dsh-llm-retry` is the optional executor loaded by the shared example spine. +- **`GenerateOptions` sampling is `temperature`/`maxTokens`/`stop` only** — no `tool_choice`, `top_p`, or penalty fields; the vocabulary grows when a producer lands ([dropped inert knobs](../../../.agents/notes/archived/simplification/2026-07-04-drop-inert-request-knobs.md)). +- **Producer-gated variants stay out until produced** — `prefill`, per-tool `strict`, block `cache` hints, and the `agent` message-source variant were pruned as producerless ([Agent Note](../../../.agents/notes/archived/simplification/2026-07-04-prune-producerless-vocabulary-variants.md)). +- **`BlockAssembler` handles core block kinds only** — a plugin-added block type whose stream is never closed by `block-end` makes `blocks()` throw. +- **`APP_IDENTITY.url` names a repository that does not exist yet** — the public home must be reachable before release. +- **`GenerateOptions.sessionId` is a locally-declared brand** — importing dsh-session's `SessionId` would cycle; a future ids-owning package would dissolve the workaround. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.zh.md new file mode 100644 index 0000000..5c22767 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/README.zh.md @@ -0,0 +1,101 @@ +# dsh-llm + +[English](README.md) | 中文 + +提供方无关的 LLM(大语言模型)词汇与抽象服务。本包定义 agent loop(智能体循环)、会话日志和所有插件共同使用的规范词汇。 + +## 服务:`LlmRuntime`(ctx key:`llm`) + +一个适配器注册表加单一流式调用接口,可通过 waterfall(瀑布式事件)拦截。 + +### 公开 API + +- `ctx.llm.registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHandle` 为给定提供方路由注册一个适配器实例。注册要么全部成功,要么全部不生效,并且会随调用 fiber 一起 dispose(资源释放)。返回的句柄还提供 `replace(providers)`:候选路由集合会在注册状态发生任何变化前完成整体验证,因此与另一适配器发生冲突时,当前路由仍保持注册并继续提供服务。替换会在一次同步操作中完成,不会出现可观察的空档。`replace([])` 合法,表示保留注册但不持有任何路由;初始注册则不得为空。 +- `ctx.llm.listProviders(): LlmProviderInfo[]` 按注册顺序描述已注册提供方路由。 +- `ctx.llm.registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): DirectoryRegistrationHandle` 声明适配器插件可通过配置激活的提供方路由——无论已注册还是休眠——每个条目指明其所属 settings namespace,以及 profile 在该分节内的路径。要么全部成功,要么全部不生效(`INVALID_DIRECTORY`/`DUPLICATE_DIRECTORY`),并随调用 fiber dispose。该句柄还带 `replace(entries)`:候选集合会先被整体校验,因此其中若有条目已被另一个注册声明,当前集合原封不动;此处允许传空数组。声明集合随配置变化的插件必须使用 `replace`,而不是先 dispose 再重新注册——后者会在新集合被拒时让目录整个落空。 +- `ctx.llm.listConfigurableProviders(): LlmConfigurableProvider[]` 按声明顺序列出可配置提供方目录;配置界面将其与 `listProviders()` 合并,为每个条目标注存活或休眠。条目可携带 `declared`,表示拥有该路由的适配器是否只因配置点名才知道它。只有适配器能回答这一点:该字段缺失时,只表示该适配器不区分这两种来源,不能据此判断路由是否随产品交付。 +- `ctx.llm.registerModelDiscovery(settingsNs: string, discover): () => void` 为本插件拥有的 settings namespace 提供查询提供方端点的能力。每个 namespace 只能有一个(`INVALID_DISCOVERY`/`DUPLICATE_DISCOVERY`),并随调用 fiber dispose。 +- `ctx.llm.listModelDiscoveryNamespaces(): string[]` 列出可以询问端点的 namespace,让界面只在可用之处提供该动作。 +- `ctx.llm.discoverModels(settingsNs: string, request: LlmModelDiscoveryRequest): Promise` 询问某个端点它公布了哪些模型。 +- `ctx.llm.providerRetryPolicy(provider: string): ResolvedRetryPolicy` 返回注册时捕获的提供方自身的重试策略,并解析 normal 默认值。 +- `ctx.llm.listModels(provider: string): Promise` 发现某个已注册提供方当前公布的模型。 +- `ctx.llm.resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise` 从拥有该精确路由的适配器中,解析并校验确切模型身份,以及可用上下文、输出默认值和推理(reasoning)元数据;异步适配器可选地支持取消。 +- `ctx.llm.resolveCallConfig(config: LlmCallConfig, signal?: AbortSignal): Promise` 校验显式推理强度,并填入适配器配置的调用默认值,但不自动调整。 +- `ctx.llm.prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise` 在一次精确模型查询中解析配置、脱耦的上下文元数据以及标明哪些字段由适配器默认值填入的标记,再将当前适配器注册和不可变重试策略捕获为一次可取消、一次性调用。 +- `ctx.llm.stream(options: GenerateOptions): AsyncIterable` 将一次模型调用流式输出为原始分片(token 级增量)。消费方使用 `BlockAssembler` 将分片组装为块/消息。 + +`LlmRuntime` 将最终适配器选择、同步分发、迭代器构造和迭代期间的失败,统一转换为流协议唯一的终止形式:`finish { kind: 'error' | 'aborted', failure }`。部分增量输出后发生失败时,内容块可能仍未闭合;消费方会丢弃这些不完整输出。`llm/stream` middleware、嵌套调用、适配器清理和下游消费方的错误仍会抛出,因为它们属于插件或消费方失败,而非模型请求结果。已准备调用会暴露随其确切适配器注册一同捕获的不可变重试策略;完全由 middleware 处理的路由没有服务策略。 + +询问端点属于配置期针对**草稿**的操作,以 settings namespace 而非提供方路由为键——界面正在新增的提供方还不存在,也就没有路由可点名。但请求仍可**点名**它正在编辑的路由,而已经描述该路由的适配器会用自己的知识作答,无需联网;路由名称和 `baseURL` 至少需要提供一项。除此之外,请求携带端点、协议,以及一条 harness 只用于这一次询问、绝不存储的凭据。这里既不读取也不写入 settings 或 credentials;返回内容是界面可以提供给用户采纳的候选元数据,而不是已注册的 catalog。`LlmDiscoveredModel` 除 `id` 外每个字段都是可选的,因为大多数提供方列表只公布 id;采纳其中一条的界面仍要补上其适配器所需的容量。重复与不可用的 id 会被丢弃,无人服务的 namespace 以 `NO_DISCOVERY` 失败,既不点名路由也不给端点的请求以 `INVALID_DISCOVERY` 失败。 + +提供方和模型元数据用于发现,不构成路由白名单。`registerAdapter()` 仍拥有提供方路由的排他性,并为每条路由捕获适配器的重试策略;适配器可以接受未出现在 `listModels()` 中的模型 id,消费方不得仅因模型未列出而拒绝请求。返回的 selector 元数据已分离;无效或重复的适配器条目会以 `INVALID_ADAPTER` 或 `INVALID_CATALOG` 失败。 + +每个拓扑提交点——适配器路由注册或 dispose、目录条目出现或撤回——都会在变更之后发出无载荷的 `llm/adapters-updated` 事件,消费方因此会重新读取 `listProviders()`/`listModels()`/`listConfigurableProviders()`,而不是轮询。观察者故障会被记录并隔离,不能否决变更;只有带 `INVARIANT` 码的故障会在通知完所有观察者后重新抛出。 + +确切模型元数据是独立的正确性查询,不是 catalog 装饰或全局 LLM 设置。`resolveModelInfo()` 会向拥有精确提供方/模型路由的适配器查询一次;适配器可以描述未列出的动态模型。缺少 `context` 表示模型容量未知;缺少 `defaultMaxTokens` 表示继续沿用提供方自身的输出默认值;缺少 `reasoning` 则表示推理能力不可用。无效的身份、上下文、输出默认值或推理元数据会以 `INVALID_MODEL_INFO`、`INVALID_MODEL_CONTEXT`、`INVALID_MODEL_MAX_TOKENS` 或 `INVALID_MODEL_REASONING` 失败。 + +`defaultMaxTokens` 是适配器配置的单次请求输出上限,不是模型硬上限。仅当请求省略 `maxTokens` 时,`resolveCallConfig()` 才会填入该值;显式上限优先。推理标识符是由适配器定义的不透明字符串,而非核心枚举:同一次解析只接受与已公布标识符完全一致的值,在存在 `defaultEffort` 时填入它,否则保留提供方默认值。异步模型解析器会接收调用方信号,并且必须在取消后尽快结算。`prepareCall()` 还会返回同一次查询得到的、与适配器内部状态分离的上下文元数据,通过 `adapterDefaults` 标明填入了哪些 `maxTokens` 和 `reasoningEffort` 字段,并在请求头记录和最终分发期间始终保留同一项精确的适配器注册。因此,HMR(热模块替换)不会把一个适配器的能力结果与另一个适配器的请求混用;复用其一次性句柄或更改调用配置字段会以 `INVALID_PREPARED_CALL` 失败。不支持的显式或配置推理强度会在提供方 I/O 前以 `UNSUPPORTED_REASONING_EFFORT` 失败。 + +### 事件 + +| 事件 | 模式 | 用途 | +|---|---|---| +| `llm/stream` | waterfall | 拦截/包装每次流式模型调用,用于缓存、日志或路由 | + +### 扩展点 + +- 继承 `LlmAdapter` 并调用 `ctx.llm.registerAdapter(providers, adapter)`,添加一条或多条提供方路由。`GenerateOptions.provider` 选择适配器;`GenerateOptions.model` 属于适配器,可以动态解析。覆盖 `providerRetryPolicy()` 以提供由提供方定义的恢复配置,覆盖 `providerInfo()` 和异步 `listModels()` 以公开 selector 元数据;精确身份、容量、输出默认值或可选推理强度可用时,实现 `resolveModel()`;异步解析器必须响应其可选的取消 signal。默认实现使用有界的 normal 重试策略,将路由和模型 id 用作名称,不公布模型,也不返回容量、输出默认值或推理元数据。 +- 包装 `llm/stream` 时,通过 `ctx.on()` waterfall listener 实现缓存、日志或路由。包装层如果在已经发出分片后重试,就没有可持久记录的尝试边界;因此,随产品交付的 agent 重试策略改用 `agent/request-error`。 + +### 消息(`message.ts`)与内容块(`types.ts`) + +`Message` 是投递、持久历史和模型请求共享的不可变值。每条消息从创建起都必须具有 `MessageId`、角色、内容和带类型的来源。`createMessage(input)` 生成标识,并返回与输入分离且深度冻结的值;`createUserMessage({ content, source })` 固定 user 角色;`createAssistantMessage({ content, source })` 固定 assistant 角色与模型来源类别;`createToolResultMessage({ callId, content, isError })` 固定 user 角色,并将工具来源与其结果块耦合;`freezeMessage(message)` 导入已有标识,绝不将其替换。改写消息时会保留标识,并产生另一个冻结值。浏览器端代码会从依赖最少的 `@deepseek-ai/dsh-llm/message` 入口导入这些值构造函数,而不是从包含服务的包根入口导入。 + +消息内容是类型化内容块数组:`text`、`reasoning`、`tool-call`、`tool-result`。联合从可合并扩展的 `ContentBlockMap` 派生,因此插件可以通过 declaration merging 添加块类型。assistant 消息使用模型来源,其中携带生成该消息的提供方和模型,以及可选的适配器私有回放状态。dispatch 前,`LlmRuntime` 只在历史提供方路由与目标提供方路由当前由完全相同的适配器实例拥有时才保留该状态;随后由适配器判定能否在模型/提供方间恢复或转换该状态。核心块集只包含每条已发布路径都支持的块。多模态内容(图像、音频等)没有核心块类型;需要它的功能会通过 map 添加,并一并添加相应的适配器/UI/压缩(compaction)支持。 + +流式输出是原始分片协议(`block-start`、`text-delta`、`reasoning-delta`、`tool-call-delta`、`block-end`、`usage`、`finish`)。每个适配器结果都以一个终止 `finish` 到达消费方;运行故障使用 `error` 或 `aborted` 作为结束原因,而不会跨流 API 抛出。`BlockAssembler` 是将分片组装为块/消息的唯一共享实现。成功的 `finish` 可以携带 `ReplayEnvelope`——不透明的响应级回放元数据,加上与发射块序列对齐的可选逐块条目。组装对内容与元数据只做一次保留/丢弃决定:`max-tokens` 结束会丢弃可能被截断的工具调用,数据在每个被丢弃的位置同步失去对应条目,因此存储的元数据始终描述存储的内容。 + +### 调用配置(`call-config.ts`) + +`LlmCallConfig` 记录一个会话的模型请求所使用的提供方、模型、由适配器定义的可选推理强度,以及采样参数(`provider`、`model`、`reasoningEffort`、`temperature`、`maxTokens`、`stop`,分别与同名 `GenerateOptions` 字段一一对应)。它是作为请求标头一部分记录在会话日志中的每会话状态(见 dsh-session `request/header` 事件),绝不是可静默调整的每次调用旋钮:`agent/request` waterfall 会提议替换,`prepareCall()` 在轮次 signal 控制下校验它并填入适配器默认值,loop 随后记录生效值以及标明哪些字段由适配器默认值填入的标记,再使用已准备调用中与注册绑定的流。下一次提议会省略带标记的默认值,使变更后的路由解析自身的值;未带标记的显式字段会保留。`callConfigEquals(a, b)` 是逐字段真实变更检测器;`deepFreeze(value)` 是 loop 使用的请求所有权辅助函数:每个构造完成的请求都会在分发前深度冻结;`llm/stream` 监听器和适配器只能读取,绝不能改写。`markAgentLoopRequest()` 将该精确对象标记为由进程本地 agent loop 创建,`isAgentLoopRequest()` 让观测方可以将其与同样可能冻结并关联会话、但独立记录的辅助调用区分。`GenerateOptions.purpose` 会对已记录的辅助压缩和会话标题调用进行分类,使适配器可以按调用目的应用不同的传输策略,而不改变普通会话请求。 + +### 应用归因(`attribution.ts`) + +每个产品适配器都会在提供方 HTTP 请求上发送应用身份。`attributionHeaders(identity?)` 构建标准 `User-Agent`,默认为公开 `APP_IDENTITY`;白标部署可以替换它,但不能抑制它。适配器会直接验证 wire 标头,或通过自身库 hook 验证。详见 [归因 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 + +### API 密钥校验(`api-key.ts`) + +每个要把凭据放进 HTTP 标头的适配器,使用前都以同一套规则校验它。`normalizeApiKey(raw)` 会先去除首尾空白,然后接受任意非空的可打印 ASCII 值(`/^[\x21-\x7E]+$/`,不含空格),或通过 `ApiKeyRejection`(`'empty'` | `'illegalCharacters'`)说明拒绝原因。这些结果一并包含在 `ApiKeyCheck` 中。缺失从不参与校验:调用方会在询问之前自行判断是否提供了值——未点名凭据的 profile 会转由提供方自身的环境发现或 OAuth 完成认证。 + +### 类 + +- `LlmAdapter`:提供方适配器的抽象基类。唯一必需方法是 `stream()`。 +- `BlockAssembler`:将原始分片逐步组装为完整内容块,并能据此创建带标识且冻结的 assistant 消息。agent loop 向它提供原始分片(同时记录以供回放),并读取已组装块以构建历史。 +- `HarnessError`:harness 错误分类体系的基类,包含稳定 `code` 字符串(与面向人的 `message` 不同)以及 `cause` 链。它位于所有其他包都从中导入的叶子包中,因此可以共享单一基类,无需新的依赖边。各包的错误(`LlmError`、`ToolArgsError`、`InvariantError` 等)都继承自它。`isHarnessError(value)` 在进程边界处收窄类型。 +- `LlmError`:继承自 `HarnessError`;其稳定 `code` 字符串(`NO_ADAPTER`、`DUPLICATE_ADAPTER` 与 `AUTH`/`RATE_LIMIT` 等适配器 code)与冻结可序列化 `failure.code` 匹配。Payload 还可以保留已验证状态、`Retry-After` 和品牌化提供方请求 id 事实;策略位于错误之外。 +- `errorChain(value)`:渲染抛出值的完整 `cause` 链与 AggregateError 成员,供诊断输出使用,包括 UI 通知、logger 行和持久 `turn/end` 消息。因此 undici 的 `TypeError: fetch failed` 等传输包装层会显示底层 `ECONNREFUSED`/DNS/TLS 详细信息,而不是将其遮蔽。该函数只负责生成诊断文本。调用方必须依据稳定的 `code` 选择错误处理路径,绝不能通过解析渲染后的文本作出判断。 +- `CONTEXT_WINDOW_EXCEEDED_CODE`:当请求超过模型上下文窗口时,无论通过 HTTP 异常抛出还是带内 finish 交付,两个 DeepSeek 适配器都使用的提供方无关 code。`isContextWindowExceededError(detail)` 是它们针对 OpenAI 兼容提供方详细信息的共享保守分类器。 +- `QUOTA_EXCEEDED_CODE`:帐户配额、余额、点数、预算或用量限制耗尽时使用的非暂时性提供方无关 code。`isQuotaExceededError(detail)` 使这些失败与请求速率限制保持区分。 +- `EMPTY_RESPONSE_CODE`:两个适配器都使用的提供方无关 code,用于表示退化的提供方生成结果:一个未携带任何内容块的终止 `stop`。它会被分类为错误 finish(而非成功空消息),因为尝试未产生持久内容;`dsh-llm-retry` 默认重试它。 +- `INVALID_CREDENTIAL_CODE`:已提供但无法使用的凭据所用的提供方无关 code——格式错误而非缺失,修复方式是改正已存储的值,而不是补充一个凭据,这正是它与 `MISSING_CREDENTIAL` 的区别。它被刻意排除在默认可重试集合之外:格式错误的凭据每次尝试都会以同样方式失败。`assertUsableApiKey(raw, pkg, ref)` 会以该 code 抛出 `LlmError`,是每个适配器判定已存储凭据不可用时共用的诊断。 + +### 真实适配器 + +两个适配器使用不同内部机制实现 `LlmAdapter`:[`@deepseek-ai/dsh-llm-deepseek`](../llm-deepseek) 针对 `deepseek-official` 路由使用直接 fetch 加 `eventsource-parser` SSE(Server-Sent Events)分帧,[`@deepseek-ai/dsh-llm-pi-ai`](../llm-pi-ai) 则通过 `@earendil-works/pi-ai` 动态解析已配置提供方/模型对。两者都遵循 `types.ts` 中的 `StreamChunk` 约定:usage 先于 finish,工具参数保持原始字符串。适配器实现在内部可以抛出异常或发出失败 finish;`LlmRuntime` 会将两者都暴露为终止失败 finish。适配器理由见[双 LLM 适配器](../../../.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.md),服务边界见[终止失败决策](../../../.agents/notes/implemented/architecture/2026-07-29-terminal-llm-stream-failures.md)。 + +## 模型体验 + +无。服务不添加任何与模型绑定的文本、schema 或消息;它只会填入并记录适配器配置的推理强度。 + +#### KV Cache 影响 + +透传;注册表保留已组装请求前缀,cache 复用与路由边界属于所选适配器和提供方。 + +## 已知限制与暂缓事项 + +- **本服务不执行重试、缓存或速率限制**:提供方注册会存储重试策略,但 `llm/stream` 仍是单次尝试调用包装层。agent loop 会将已验证模型请求失败单独提供给 `agent/request-error`,其默认行为是保留原始失败;`@deepseek-ai/dsh-llm-retry` 是共享示例主干加载的可选执行器。 +- **`GenerateOptions` 采样只包含 `temperature`/`maxTokens`/`stop`**:没有 `tool_choice`、`top_p` 或 penalty 字段;有产生方落地时词汇才会增长(见 [已删除惰性旋钮](../../../.agents/notes/archived/simplification/2026-07-04-drop-inert-request-knobs.md))。 +- **只有出现实际产生方后,相应变体才会加入**:`prefill`、逐工具 `strict`、内容块 `cache` 提示和 `agent` 消息来源变体,都因当前没有产生方而被移除(见 [Agent Note](../../../.agents/notes/archived/simplification/2026-07-04-prune-producerless-vocabulary-variants.md))。 +- **`BlockAssembler` 只处理核心块类型**:如果插件添加块类型的流从未由 `block-end` 关闭,`blocks()` 会抛出异常。 +- **`APP_IDENTITY.url` 指向一个尚不存在的仓库**:该公开主页必须在发布前可访问。 +- **`GenerateOptions.sessionId` 是本地声明的品牌类型**:导入 dsh-session 的 `SessionId` 会产生循环;未来拥有 id 的包可以消除该权宜之计。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/index.js new file mode 100644 index 0000000..6c3a740 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/index.js @@ -0,0 +1,1436 @@ +import { createRequire } from "node:module"; +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { MAX_TIMER_DELAY_MS } from "@deepseek-ai/dsh-timeout"; +//#region lib/types/brand.js +/** +* dsh-llm's owned branded ids: tool-call correlation and provider request +* diagnostics. +* +* The `Branded` primitive itself lives in `@deepseek-ai/dsh-brand` (a +* zero-dependency type-only package) so every owner of a cross-boundary id can +* brand it without depending on dsh-llm; see that package's README for the +* nominal-typing policy. +* +* @module @deepseek-ai/dsh-llm/brand +*/ +/** +* Brand a message identifier. +* @param id - the opaque message identifier. +* @returns the same string, branded; no validation is performed. +*/ +function MessageId(id) { + return id; +} +/** +* Brand a string as a {@link CallId}. +* @param id - the provider-issued (or synthesized) call id. +* @returns the same string, branded; no validation is performed. +*/ +function CallId(id) { + return id; +} +/** +* Brand a provider-issued request identifier. +* @param id - the opaque provider-issued string. +* @returns the same string, branded; no validation is performed. +*/ +function ProviderRequestId(id) { + return id; +} +/** +* Brand an adapter-owned reasoning-effort identifier. +* @param id - the opaque identifier exposed by one model capability. +* @returns the same string, branded; no validation is performed. +*/ +function ReasoningEffortId(id) { + return id; +} +//#endregion +//#region lib/types/call-config.js +/** +* Conversation call configuration and freeze utilities. Provider routing, +* model, reasoning effort, and sampling values are request-header state that +* can affect cache reuse; request waterfalls replace them and the loop logs +* changed snapshots instead of allowing silent per-call drift. +* @module dsh-llm/call-config +*/ +/** Process-local identities of request objects assembled by dsh-agent-loop. */ +const AGENT_LOOP_REQUESTS = /* @__PURE__ */ new WeakSet(); +/** +* Field-wise equality over {@link LlmCallConfig} — the comparison a caller +* runs to decide whether a proposed configuration is a real change (worth a +* logged header snapshot) or the held one restated. +* @param a - one configuration. +* @param b - the other. +* @returns whether every field (including the `stop` list, element-wise) matches. +*/ +function callConfigEquals(a, b) { + if (a.provider !== b.provider || a.model !== b.model || a.reasoningEffort !== b.reasoningEffort || a.temperature !== b.temperature || a.maxTokens !== b.maxTokens) return false; + if (a.stop === void 0 || b.stop === void 0) return a.stop === b.stop; + return a.stop.length === b.stop.length && a.stop.every((s, i) => s === b.stop?.[i]); +} +/** +* Mark one exact request object as assembled by dsh-agent-loop. +* @param request - loop-owned request envelope before LLM dispatch. +* @returns the same request object marked as created by the process-local agent loop. +*/ +function markAgentLoopRequest(request) { + AGENT_LOOP_REQUESTS.add(request); + return request; +} +/** +* Test whether the exact request object was assembled by dsh-agent-loop. +* @param request - request envelope observed at the LLM waterfall. +* @returns whether {@link markAgentLoopRequest} recorded this object. +*/ +function isAgentLoopRequest(request) { + return AGENT_LOOP_REQUESTS.has(request); +} +/** +* Deep-freeze a value in place with an iterative traversal, guarding cycles, +* so later mutation throws without imposing a JavaScript call-stack depth cap. +* {@link AbortSignal} objects are deliberately skipped because they are the +* request's live cancellation channel and freezing them breaks abort. +* @param value - the value to freeze in place. +* @returns the same value, frozen. +*/ +function deepFreeze(value) { + const seen = /* @__PURE__ */ new WeakSet(); + const pending = [{ + kind: "visit", + node: value + }]; + while (pending.length > 0) { + const task = pending.pop(); + /* v8 ignore next -- the loop condition guarantees one pending task. */ + if (task === void 0) continue; + if (task.kind === "property") { + pending.push({ + kind: "visit", + node: task.source[task.key] + }); + continue; + } + const node = task.node; + if (node === null || typeof node !== "object") continue; + if (node instanceof AbortSignal) continue; + if (seen.has(node)) continue; + seen.add(node); + Object.freeze(node); + const keys = Object.keys(node); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === void 0) continue; + pending.push({ + kind: "property", + source: node, + key + }); + } + } + return value; +} +//#endregion +//#region lib/types/message.js +/** Message value types, identity, and immutable construction helpers. */ +/** +* Bound for a `notice` summary. The account rides a collapsed transcript row +* and is committed to the durable log, while its inputs — task labels, goal +* objectives, tool arguments — are caller text with no length of their own. +*/ +const CONTEXT_SUMMARY_MAX_CHARS = 120; +/** +* Bound one `notice` summary to {@link CONTEXT_SUMMARY_MAX_CHARS}. +* @param summary - the producer's one-line account, of any length. +* @returns the account, ellipsized when it exceeds the bound. +*/ +function boundContextSummary(summary) { + return summary.length <= 120 ? summary : `${summary.slice(0, 119)}…`; +} +/** +* Detach and deep-freeze a message whose identity already exists. +* @param message - complete message, including its stable identity. +* @returns an immutable snapshot that preserves the identity. +*/ +function freezeMessage(message) { + return deepFreeze(structuredClone(message)); +} +/** +* Create one identified message and freeze it before publication. +* @param input - complete role, content, and source for a new message. +* @returns an immutable message with a fresh stable identity. +*/ +function createMessage(input) { + return freezeMessage({ + ...input, + id: MessageId(crypto.randomUUID()) + }); +} +/** +* Create one identified user-role message and freeze it before publication. +* @param input - complete content and source for a new user message. +* @returns an immutable user message with a fresh stable identity. +*/ +function createUserMessage(input) { + return createMessage({ + ...input, + role: "user" + }); +} +/** +* Create one identified model-produced assistant message and freeze it before publication. +* @param input - complete content plus the provider, model, and optional replay state for a new assistant message. +* @returns an immutable assistant message with fixed role/source tags and a fresh stable identity. +*/ +function createAssistantMessage(input) { + return createMessage({ + role: "assistant", + content: input.content, + source: { + kind: "model", + ...input.source + } + }); +} +/** +* Create and freeze one identified tool-result message. +* @param input - call identity, raw result blocks, and outcome. +* @returns an immutable user-role tool-result message. +*/ +function createToolResultMessage(input) { + return createUserMessage({ + source: { + kind: "tool", + callId: input.callId + }, + content: [{ + type: "tool-result", + toolCallId: input.callId, + content: input.content, + isError: input.isError + }] + }); +} +/** +* Whether a stream chunk carries visible model output (the first-token +* boundary shared by client step timing and the whole-log sessionStats +* projection). Empty deltas (heartbeats, empty tool-call frames) do not count +* as a first token. +* @param chunk - the stream chunk to test. +* @returns true when the chunk contains a non-empty text/reasoning/tool delta. +*/ +function isTokenDelta(chunk) { + switch (chunk.type) { + case "text-delta": + case "reasoning-delta": return chunk.text !== ""; + case "tool-call-delta": return chunk.argumentsDelta !== "" || chunk.name !== void 0; + default: return false; + } +} +//#endregion +//#region lib/types/error.js +/** +* Harness error base with a stable machine-routable code and chained cause. +* Package errors extend it so tool results and replay can retain failure class. +* @module @deepseek-ai/dsh-llm/error +*/ +/** +* Base class for all harness errors. Carries a `code` (stable, programmatic — +* e.g. `NO_ADAPTER`, `INVALID_ARGS`, `INVARIANT`) distinct from the +* human-readable `message`, and supports `cause` chaining via the standard +* `ErrorOptions`. `name` defaults to the subclass constructor name. +*/ +var HarnessError = class extends Error { + /** Stable machine-routable failure class (e.g. `RATE_LIMIT`); route on this, never by parsing `message`. */ + code; + constructor(message, code, options) { + super(message, options); + this.code = code; + this.name = new.target.name; + } +}; +/** Canonical provider-neutral code for a model request rejected because its context window was exceeded. */ +const CONTEXT_WINDOW_EXCEEDED_CODE = "CONTEXT_WINDOW_EXCEEDED"; +/** Canonical provider-neutral code for an exhausted account quota or balance. */ +const QUOTA_EXCEEDED_CODE = "QUOTA"; +/** +* Canonical provider-neutral code for a response that completed normally but +* carried no content blocks at all. Providers occasionally emit a degenerate +* completion (a terminal stop with zero output); adapters classify it as this +* failure instead of yielding an empty assistant message, because an empty +* message silently ends the turn with nothing for the user or the loop to act +* on. The attempt produced nothing durable, so retry policy treats it as safe +* to repeat. +*/ +const EMPTY_RESPONSE_CODE = "EMPTY_RESPONSE"; +/** +* Canonical provider-neutral code for a credential that was supplied but +* cannot be used — malformed rather than absent. Distinct from +* `MISSING_CREDENTIAL` because the fix differs: correct the stored value +* rather than supply one. Deliberately outside the default retryable set — +* a malformed credential fails identically on every attempt. +*/ +const INVALID_CREDENTIAL_CODE = "INVALID_CREDENTIAL"; +/** Structured codes and plain phrases that explicitly name a context bound being exceeded. */ +const STRUCTURED_CONTEXT_OVERFLOW = new RegExp(String.raw`(?:^|[^a-z0-9])context[\s_-](?:length|window)[\s_-]` + String.raw`(?:exceed(?:ed|s)?|overflow(?:ed)?|limit[\s_-]exceeded)(?:$|[^a-z0-9])`, "i"); +/** Request-size wording that ties "too large" directly to model context capacity. */ +const TOO_LARGE_FOR_CONTEXT = new RegExp(String.raw`\b(?:request|prompt|input|messages?)\s+(?:is\s+|are\s+)?` + String.raw`too\s+(?:large|long)\s+for\s+(?:(?:this|the)\s+)?` + String.raw`(?:model(?:'s)?\s+)?context(?:\s+window)?\b`, "i"); +/** "Exceeds" wording is safe only when its object is explicitly the model context. */ +const EXCEEDS_MODEL_CONTEXT = new RegExp(String.raw`\b(?:input|prompt|request|messages?)\b.{0,40}` + String.raw`\b(?:exceed(?:s|ed)?|overflows?|is\s+larger\s+than)\b.{0,40}` + String.raw`\b(?:the\s+)?(?:model(?:'s)?\s+)?context(?:\s+(?:length|window))?\b`, "i"); +/** +* Recognize the context-overflow wording used by OpenAI-compatible providers +* and library adapters. Adapters pass all available provider code, type, and +* message text so both thrown and in-band delivery styles share one classifier. +* @param detail - provider error code/type/message text joined into one string. +* @returns true when the detail identifies a request exceeding the model context window. +*/ +function isContextWindowExceededError(detail) { + return STRUCTURED_CONTEXT_OVERFLOW.test(detail) || /\b(?:maximum|max)(?:\s+(?:allowed|supported))?\s+context\s+(?:length|window)\b/i.test(detail) || TOO_LARGE_FOR_CONTEXT.test(detail) || /\b(?:input|prompt|request)\s+(?:is\s+)?too\s+(?:long|large)\s+for\s+(?:this|the)\s+model\b/i.test(detail) || EXCEEDS_MODEL_CONTEXT.test(detail); +} +/** +* Recognize provider wording that identifies an exhausted account quota rather +* than a transient request-rate limit. +* @param detail - provider error code/type/message text joined into one string. +* @returns true only for terminal quota, balance, credit, budget, or usage-limit wording. +*/ +function isQuotaExceededError(detail) { + return /\binsufficient[\s_-]+(?:quota|balance|credits?)\b/i.test(detail) || /\b(?:quota|usage[\s_-]+limit)[\s_-]+(?:exceeded|exhausted|reached)\b/i.test(detail) || /\bexceed(?:ed|s)?[\s_-]+(?:(?:your|the)[\s_-]+)?(?:current[\s_-]+)?quota\b/i.test(detail) || /\b(?:balance|credits?)[\s_-]+(?:exhausted|depleted)\b/i.test(detail) || /\bout[\s_-]+of[\s_-]+(?:credits?|budget)\b/i.test(detail); +} +/** +* Render a thrown value with its full `cause` chain and AggregateError +* members, so transport wrappers like undici's `TypeError: fetch failed` +* surface the underlying failure instead of masking it. Plain structured +* failures render their own data-backed `message`. Diagnostic-surface +* rendering only (messages, notices, logs) — never parse the result; route on +* {@link HarnessError.code}. +* @param value - the caught value (`unknown` in catch clauses). +* @returns the outermost message first, each cause appended with `: ` (skipped +* when it repeats the wrapper message verbatim), and AggregateError members +* bracketed and `; `-joined. +*/ +function errorChain(value) { + const path = /* @__PURE__ */ new Set(); + const render = (current) => { + if (path.has(current)) return ""; + path.add(current); + try { + if (!(current instanceof Error)) { + if (typeof current === "object" && current !== null) { + const descriptor = Object.getOwnPropertyDescriptor(current, "message"); + if (descriptor !== void 0 && "value" in descriptor && typeof descriptor.value === "string") return descriptor.value; + } + return String(current); + } + const message = current.message === "" ? current.name : current.message; + const members = current instanceof AggregateError && current.errors.length > 0 ? ` [${current.errors.map(render).join("; ")}]` : ""; + const causeText = current.cause === void 0 || current.cause === null ? "" : render(current.cause); + return `${message}${members}${causeText === "" || causeText === message ? "" : `: ${causeText}`}`; + } catch { + return ""; + } finally { + path.delete(current); + } + }; + return render(value); +} +/** +* Narrow an arbitrary thrown value to a HarnessError (for `instanceof` at runtime boundaries). +* @param value - the caught value (`unknown` in catch clauses). +* @returns true only for real instances; duck-typed or cross-realm errors do not narrow. +*/ +function isHarnessError(value) { + return value instanceof HarnessError; +} +//#endregion +//#region lib/types/retry-policy.js +/** +* Provider-owned request-retry policy configuration and resolution. +* +* Adapters expose one resolved policy per registered provider route; the +* optional dsh-llm-retry plugin executes it on the agent's failed-step extension point. +* +* @module @deepseek-ai/dsh-llm/retry-policy +*/ +const DEFAULT_MAX_RETRIES = 2; +const DEFAULT_INITIAL_DELAY_MS = 500; +const DEFAULT_MAX_DELAY_MS = 1e4; +const DEFAULT_JITTER_RATIO = .1; +const DEFAULT_RETRYABLE_CODES = Object.freeze([ + EMPTY_RESPONSE_CODE, + "RATE_LIMIT", + "SERVER", + "TIMEOUT", + "TRANSPORT" +]); +const backoffSchema = z.object({ + initialDelayMs: z.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_INITIAL_DELAY_MS), + maxDelayMs: z.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_MAX_DELAY_MS), + jitterRatio: z.number().min(0).max(1).default(DEFAULT_JITTER_RATIO) +}); +const normalPolicySchema = z.object({ + mode: z.const("normal").required(), + maxRetries: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_MAX_RETRIES), + retryableCodes: z.array(z.string()).default([...DEFAULT_RETRYABLE_CODES]), + backoff: backoffSchema +}); +const alwaysPolicySchema = z.object({ + mode: z.const("always").required(), + backoff: backoffSchema +}); +/** Cordis schema embedded by each concrete provider configuration. */ +const RetryPolicySchema = z.union([normalPolicySchema, alwaysPolicySchema]); +const NORMAL_POLICY_KEYS = new Set([ + "mode", + "maxRetries", + "retryableCodes", + "backoff" +]); +const ALWAYS_POLICY_KEYS = new Set(["mode", "backoff"]); +const BACKOFF_KEYS = new Set([ + "initialDelayMs", + "maxDelayMs", + "jitterRatio" +]); +function validateKeys(value, allowed, path) { + for (const key of Object.keys(value)) if (!allowed.has(key)) throw new Error(`${path}: unknown key "${key}"`); +} +function resolveBackoff(config, path) { + if (config !== void 0) validateKeys(config, BACKOFF_KEYS, path); + const initialDelayMs = config?.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS; + const maxDelayMs = config?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS; + const jitterRatio = config?.jitterRatio ?? DEFAULT_JITTER_RATIO; + if (!Number.isFinite(initialDelayMs) || initialDelayMs <= 0 || initialDelayMs > MAX_TIMER_DELAY_MS) throw new Error(`${path}.initialDelayMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`); + if (!Number.isFinite(maxDelayMs) || maxDelayMs <= 0 || maxDelayMs > MAX_TIMER_DELAY_MS) throw new Error(`${path}.maxDelayMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`); + if (initialDelayMs > maxDelayMs) throw new Error(`${path}.initialDelayMs must be less than or equal to maxDelayMs`); + if (!Number.isFinite(jitterRatio) || jitterRatio < 0 || jitterRatio > 1) throw new Error(`${path}.jitterRatio must be between 0 and 1`); + return Object.freeze({ + initialDelayMs, + maxDelayMs, + jitterRatio + }); +} +/** +* Validate, default, and detach one provider-owned retry policy. +* @param config - optional provider configuration; omission selects normal defaults. +* @param path - diagnostic path naming the provider config that owns the value. +* @returns an immutable policy safe to capture in provider registration state. +*/ +function resolveRetryPolicy(config, path) { + if (config === void 0) return Object.freeze({ + mode: "normal", + maxRetries: DEFAULT_MAX_RETRIES, + retryableCodes: DEFAULT_RETRYABLE_CODES, + ...resolveBackoff(void 0, `${path}.backoff`) + }); + switch (config.mode) { + case "normal": { + validateKeys(config, NORMAL_POLICY_KEYS, path); + const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES; + const retryableCodes = config.retryableCodes ?? [...DEFAULT_RETRYABLE_CODES]; + if (!Number.isSafeInteger(maxRetries) || maxRetries < 0) throw new Error(`${path}.maxRetries must be a non-negative safe integer`); + if (retryableCodes.length === 0) throw new Error(`${path}.retryableCodes must not be empty`); + if (retryableCodes.some((code) => typeof code !== "string" || code.length === 0)) throw new Error(`${path}.retryableCodes must contain only non-empty strings`); + if (new Set(retryableCodes).size !== retryableCodes.length) throw new Error(`${path}.retryableCodes must not contain duplicates`); + return Object.freeze({ + mode: "normal", + maxRetries, + retryableCodes: Object.freeze([...retryableCodes]), + ...resolveBackoff(config.backoff, `${path}.backoff`) + }); + } + case "always": + validateKeys(config, ALWAYS_POLICY_KEYS, path); + return Object.freeze({ + mode: "always", + ...resolveBackoff(config.backoff, `${path}.backoff`) + }); + default: throw new Error(`${path}.mode must be "normal" or "always"`); + } +} +//#endregion +//#region lib/types/adapter-failure.js +/** +* Normalization for values thrown by a final LLM adapter boundary. +* +* @module @deepseek-ai/dsh-llm/adapter-failure +*/ +/** +* Detach serializable provider facts from a value thrown by an adapter. +* @param value - arbitrary value thrown during adapter dispatch or iteration. +* @returns immutable provider-neutral facts suitable for a terminal finish chunk. +* @internal +*/ +function normalizeLlmFailure(value) { + const error = value instanceof Error ? value : new HarnessError(thrownMessage(value), "UNKNOWN", { cause: value }); + const carried = ownFailureSnapshot(error); + if (carried !== void 0 && carried.code === ownErrorCode(error)) return carried; + return Object.freeze({ + message: errorMessage(error), + code: harnessErrorCode(error) + }); +} +/** Render a non-Error throw without letting hostile coercion escape normalization. */ +function thrownMessage(value) { + try { + const message = String(value); + return message.length > 0 ? message : "LLM adapter failed"; + } catch (_hostileThrownValue) { + return "LLM adapter failed"; + } +} +/** Read a foreign error's own data-backed `code` without invoking accessors. */ +function ownErrorCode(error) { + try { + const descriptor = Object.getOwnPropertyDescriptor(error, "code"); + return descriptor !== void 0 && "value" in descriptor ? descriptor.value : void 0; + } catch (_sdkPropertyTrap) { + return; + } +} +/** Snapshot an own data property without invoking an SDK-defined accessor. */ +function ownFailureSnapshot(error) { + try { + const descriptor = Object.getOwnPropertyDescriptor(error, "failure"); + return descriptor !== void 0 && "value" in descriptor ? failureSnapshot(descriptor.value) : void 0; + } catch (_sdkPropertyTrap) { + return; + } +} +/** Validate and detach an arbitrary serializable failure payload. */ +function failureSnapshot(value) { + if (typeof value !== "object" || value === null) return void 0; + try { + const candidate = value; + const message = candidate.message; + const code = candidate.code; + const status = candidate.status; + const providerRetryAfterMs = candidate.providerRetryAfterMs; + const requestId = candidate.requestId; + if (typeof message !== "string" || message.length === 0 || typeof code !== "string" || code.length === 0 || status !== void 0 && (!Number.isInteger(status) || status < 100 || status > 599) || providerRetryAfterMs !== void 0 && (!Number.isFinite(providerRetryAfterMs) || providerRetryAfterMs <= 0) || requestId !== void 0 && (typeof requestId !== "string" || requestId.length === 0)) return void 0; + return Object.freeze({ + message, + code, + ...status === void 0 ? {} : { status }, + ...providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs }, + ...requestId === void 0 ? {} : { requestId } + }); + } catch (_sdkFailureGetter) { + return; + } +} +/** Read an SDK error message without letting an accessor replace the primary failure. */ +function errorMessage(error) { + try { + const message = error.message; + if (typeof message === "string" && message.length > 0) return message; + } catch (_sdkMessageGetter) {} + return "LLM adapter failed"; +} +/** Trust only Harness-owned codes; third-party SDK codes are not our taxonomy. */ +function harnessErrorCode(error) { + return error instanceof HarnessError ? error.code : "UNKNOWN"; +} +//#endregion +//#region lib/types/api-key.js +/** +* The one definition of a well-formed provider API key, shared by every +* adapter that puts one in an HTTP header. +* @module @deepseek-ai/dsh-llm/api-key +*/ +/** +* Characters an HTTP header value carries verbatim and every known provider +* key uses: printable ASCII, space excluded. A key outside this set cannot +* reach any provider — `fetch` refuses to build the header — so this is a +* transport invariant rather than one provider's policy. Latin-1 is excluded +* deliberately: a header could carry it, but no provider issues it, and +* admitting it trades a local explained refusal for an opaque 401. +*/ +const LEGAL_API_KEY = /^[\x21-\x7E]+$/; +/** +* Judge one *supplied* API key, trimming surrounding whitespace first. +* +* Trimming is silent because a padded key has one unambiguous reading; every +* other defect is reported. Absence is a configuration state this function +* never sees — a profile naming no credential authenticates through the +* provider's own ambient discovery or OAuth — so callers decide whether a +* value was supplied before asking. +* @param raw - the key exactly as configured, stored, or typed. +* @returns the trimmed key, or why it cannot be used. +*/ +function normalizeApiKey(raw) { + const value = raw.trim(); + if (value.length === 0) return { + ok: false, + reason: "empty" + }; + if (!LEGAL_API_KEY.test(value)) return { + ok: false, + reason: "illegalCharacters" + }; + return { + ok: true, + value + }; +} +//#endregion +//#region lib/types/attribution.js +/** +* Centralize the non-secret product identity every provider request sends as `User-Agent`, keeping +* adapters from drifting. See +* `.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md`. +* +* App-attribution vocabulary for provider requests. +* @module @deepseek-ai/dsh-llm/attribution +*/ +const { version } = createRequire(import.meta.url)("../package.json"); +/** +* The harness's own identity: the default every adapter sends. Deployments +* that need a white-label identity pass their own {@link AppIdentity} to +* {@link attributionHeaders} — omission falls back to this default; nothing +* can suppress attribution entirely. +*/ +const APP_IDENTITY = { + product: "deepseek-harness", + version, + url: "https://github.com/deepseek-ai/deepseek-harness" +}; +/** +* The standard `User-Agent` value: `product/version (+url)`. The +* parenthesized `+url` comment is the conventional self-identification form +* (RFC 9110 §10.1.5 product + comment syntax). +* @param identity - the identity to render; defaults to {@link APP_IDENTITY}. +* @returns the ready-to-send header value. +*/ +function userAgent(identity = APP_IDENTITY) { + return `${identity.product}/${identity.version} (+${identity.url})`; +} +/** +* Build the attribution headers an adapter must send on every provider +* request. Header names are lowercase (HTTP field names are case-insensitive +* on the wire). +* @param identity - the identity to send; defaults to {@link APP_IDENTITY} — omission cannot suppress attribution. +* @returns headers to merge into the provider request (currently just `user-agent`). +*/ +function attributionHeaders(identity = APP_IDENTITY) { + return { "user-agent": userAgent(identity) }; +} +//#endregion +//#region lib/types/never.js +/** +* Exhaustiveness helper for closed core unions. Use {@link assertNever} at the default branch so a +* new variant fails compilation at every required handler. Do not use it for declaration-merged +* unions such as session events or content blocks: handle known variants and explicitly fall +* through because plugins may add valid unknown cases. +* @module @deepseek-ai/dsh-llm/never +*/ +/** +* Mark an unreachable closed-union branch. A newly unhandled typed variant fails at the call site; +* a value that escaped its type throws with diagnostics at runtime. +* @param value - the impossible value; typed `never` so an unhandled variant fails compilation at the call site. +* @param context - optional label (e.g. the switch site) prefixed into the throw message. +* @returns never — it always throws, with the offending value JSON-rendered in the message. +*/ +function assertNever(value, context) { + const rendered = JSON.stringify(value) ?? String(value); + throw new Error(`unreachable variant${context ? ` in ${context}` : ""}: ${rendered}`); +} +//#endregion +//#region lib/types/content.js +/** Content-block structure helpers. @module @deepseek-ai/dsh-llm/content */ +/** +* True when typed model content contains an image block, walking nested +* tool-result content. This is the one recursive image walk shared by every +* image policy (capability gating, text-only serialization, compaction +* survey), so a consumer cannot silently diverge on nesting depth. +* @param content - typed model content blocks. +* @returns whether any nested block is an image. +*/ +function contentHasImage(content) { + return content.some((block) => block.type === "image" || block.type === "tool-result" && contentHasImage(block.content)); +} +//#endregion +//#region lib/types/assembler.js +/** +* Incremental chunk-to-message assembler. This is the single canonical assembly +* algorithm used by the agent loop to build an assistant message from a chunk +* stream while logging the raw chunks for replay fidelity. +* +* @module @deepseek-ai/dsh-llm/assembler +*/ +/** +* Incrementally assembles raw {@link StreamChunk}s into complete +* {@link ContentBlock}s and a final assistant {@link Message}. +* +* The agent loop feeds it while logging raw chunks for replay fidelity, then +* reads `blocks()` / `message()` / `usage` / `finish` once the stream ends. +* +* Tolerant of delta-only protocols (no block-start/end); deltas arriving for +* an index already closed by `block-end` are ignored (malformed stream) so a +* misbehaving adapter cannot grow memory or corrupt a completed block. +*/ +var BlockAssembler = class { + partials = /* @__PURE__ */ new Map(); + order = []; + _usage; + _finish; + _replayState; + /** + * Feed one chunk into the assembly state. + * @param chunk - the next raw chunk, in stream order. + */ + push(chunk) { + switch (chunk.type) { + case "block-start": + if (!this.partials.has(chunk.index)) { + this.order.push(chunk.index); + this.partials.set(chunk.index, { + blockType: chunk.blockType, + text: "", + toolCallArguments: "" + }); + } + return; + case "text-delta": + case "reasoning-delta": { + const partial = this.ensure(chunk.index, chunk.type === "text-delta" ? "text" : "reasoning"); + if (partial.block) return; + partial.text += chunk.text; + return; + } + case "tool-call-delta": { + const partial = this.ensure(chunk.index, "tool-call"); + if (partial.block) return; + partial.toolCallId = chunk.id; + if (chunk.name) partial.toolCallName = chunk.name; + partial.toolCallArguments += chunk.argumentsDelta; + return; + } + case "block-end": { + const partial = this.ensure(chunk.index, chunk.block.type); + if (partial.block) return; + partial.block = chunk.block; + return; + } + case "usage": + this._usage = chunk.usage; + return; + case "finish": + this._finish = chunk.reason; + this._replayState = chunk.replayState; + return; + default: return assertNever(chunk, "BlockAssembler.push"); + } + } + ensure(index, blockType) { + let partial = this.partials.get(index); + if (!partial) { + partial = { + blockType, + text: "", + toolCallArguments: "" + }; + this.partials.set(index, partial); + this.order.push(index); + } + return partial; + } + assemble(partial, index) { + if (partial.block) return partial.block; + switch (partial.blockType) { + case "text": return { + type: "text", + text: partial.text + }; + case "reasoning": return { + type: "reasoning", + text: partial.text + }; + case "tool-call": return { + type: "tool-call", + id: partial.toolCallId ?? CallId(`call-${index}`), + name: partial.toolCallName ?? "", + arguments: partial.toolCallArguments + }; + default: throw new Error(`cannot assemble incomplete block of type "${partial.blockType}"`); + } + } + /** Invariant accessor: every index in `order` has a partial. */ + mustGet(index) { + const partial = this.partials.get(index); + if (!partial) throw new Error(`BlockAssembler invariant violated: no partial for index ${index}`); + return partial; + } + /** + * The one shared keep/drop decision over all seen blocks: max-token + * truncation drops tool calls that cannot be executed safely. Emitted blocks + * and replay metadata both derive from this result, so they cannot disagree. + */ + assembled() { + const all = this.order.map((index) => this.assemble(this.mustGet(index), index)); + const kept = this.finish.kind === "max-tokens" ? all.map((block) => block.type !== "tool-call") : void 0; + const blocks = kept === void 0 ? all : all.filter((_, position) => kept[position]); + const envelope = this._replayState; + if (envelope?.blocks === void 0) return { + blocks, + replay: envelope + }; + if (envelope.blocks.length !== all.length) return { + blocks, + replay: void 0 + }; + return { + blocks, + replay: kept === void 0 || blocks.length === all.length ? envelope : { + response: envelope.response, + blocks: envelope.blocks.filter((_, position) => kept[position]) + } + }; + } + /** + * Assemble all blocks seen so far, in stream order. + * @returns one block per seen index, except that max-token truncation drops + * tool calls that cannot be executed safely; an open block assembles from + * its accumulated deltas (an unknown block type never closed by `block-end` throws). + */ + blocks() { + return this.assembled().blocks; + } + /** Usage from the `usage` chunk; undefined until one arrives. */ + get usage() { + return this._usage; + } + /** Finish reason from the `finish` chunk; `{kind: 'stop'}` when the stream ended without one. */ + get finish() { + return this._finish ?? { kind: "stop" }; + } + /** + * Replay metadata from the terminal finish chunk, if any, with per-block + * entries pruned in step with {@link blocks}. Undefined when the envelope's + * entries do not align with the emitted blocks. + */ + get replayState() { + return this.assembled().replay; + } + /** + * The assembled assistant message. + * @param source - producer attribution for the assembled message. + * @returns a frozen assistant-role message over `blocks()` (same open-block assembly rules). + */ + message(source = { + kind: "plugin", + plugin: "dsh-llm/assembler" + }) { + return createMessage({ + role: "assistant", + content: this.blocks(), + source + }); + } +}; +//#endregion +//#region lib/types/index.js +/** +* LLM service: adapter registry with a waterfall-interceptable streaming call +* API. Exports the `LlmRuntime` default, the abstract `LlmAdapter` for +* provider backends, and `BlockAssembler` for chunk assembly. +* +* @module @deepseek-ai/dsh-llm +*/ +/** +* Typed error for LLM-related failures. Extends {@link HarnessError}, so the +* `code` string (e.g. `AUTH`, `RATE_LIMIT`, `NO_ADAPTER`) is shared taxonomy. +*/ +var LlmError = class extends HarnessError { + /** Serializable facts retained beside this live Error. */ + failure; + /** + * @param message - non-empty human-readable failure summary. + * @param code - non-empty stable provider-neutral machine code. + * @param options - optional cause and validated serializable provider facts. + */ + constructor(message, code, options) { + if (typeof message !== "string" || message.length === 0) throw new Error("LlmError message must be a non-empty string"); + if (typeof code !== "string" || code.length === 0) throw new Error("LlmError code must be a non-empty string"); + if (options?.status !== void 0 && (!Number.isInteger(options.status) || options.status < 100 || options.status > 599)) throw new Error("LlmError status must be an integer from 100 through 599"); + if (options?.providerRetryAfterMs !== void 0 && (!Number.isFinite(options.providerRetryAfterMs) || options.providerRetryAfterMs <= 0)) throw new Error("LlmError providerRetryAfterMs must be a positive finite number"); + if (options?.requestId !== void 0 && (typeof options.requestId !== "string" || options.requestId.length === 0)) throw new Error("LlmError requestId must be a non-empty string"); + super(message, code, options); + this.name = "LlmError"; + this.failure = Object.freeze({ + message, + code, + ...options?.status === void 0 ? {} : { status: options.status }, + ...options?.providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs: options.providerRetryAfterMs }, + ...options?.requestId === void 0 ? {} : { requestId: options.requestId } + }); + } +}; +/** +* Accept one supplied credential, or refuse it as unusable. +* +* A stored key arrives from the credentials seam, a `.env` line, or a shell +* export, all of which pick up surrounding whitespace, so trimming is silent. +* Anything else fails here rather than inside `fetch`, whose ByteString +* refusal names a UTF-16 code point instead of the setting to change. The key +* never enters the message: `ref` names where to fix it, and echoing any part +* of a secret into a log or a UI is the failure this diagnosis avoids. +* +* Lives beside {@link LlmError} rather than in `./api-key.ts` so the predicate +* module stays dependency-free; both adapters share this one diagnosis instead +* of keeping near-identical local copies. +* @param raw - the credential exactly as supplied. +* @param pkg - the refusing package name, prefixed to the diagnostic. +* @param ref - the credential reference the value resolved through. +* @returns the trimmed, usable key. +*/ +function assertUsableApiKey(raw, pkg, ref) { + const checked = normalizeApiKey(raw); + if (checked.ok) return checked.value; + throw new LlmError(checked.reason === "empty" ? `${pkg}: the API key resolved from ${ref} is blank; set ${ref} to the raw key (the web Models page writes it) or export it in the launching environment` : `${pkg}: the API key resolved from ${ref} contains characters no HTTP header can carry; set ${ref} to the raw key alone (the web Models page writes it)`, INVALID_CREDENTIAL_CODE); +} +/** +* Provider-wire adapter for the harness message and stream vocabulary. Register implementations +* with `ctx.llm.registerAdapter(providers, adapter)`. Every provider HTTP request must include +* `attributionHeaders()`; prove the headers are added in the wire request or library header hook. The direct-fetch +* DeepSeek and library-backed pi-ai adapters meet this contract through different internals. +*/ +var LlmAdapter = class { + /** + * Describe one provider route owned by this adapter. + * @param provider - a route passed to `registerAdapter()` for this instance. + * @returns detached display metadata whose id must equal `provider`. + */ + providerInfo(provider) { + return { + id: provider, + name: provider + }; + } + /** + * Return the provider-owned retry policy captured with this route. + * @param _provider - a route passed to `registerAdapter()` for this instance. + * @returns a resolved policy, or `undefined` to use the normal defaults. + */ + providerRetryPolicy(_provider) {} + /** + * List models this adapter can currently advertise for one owned provider. + * The result is advisory: an adapter may accept unlisted model ids, and + * consumers must not turn absence into request rejection. + * @param _provider - one provider route owned by this adapter. + * @returns discoverable models in adapter-preferred order. + */ + listModels(_provider) { + return Promise.resolve([]); + } + /** + * Resolve all metadata available for one exact model. This query is + * independent of the advisory catalog and does not validate request routing. + * @param provider - one provider route owned by this adapter. + * @param model - exact model id passed to {@link GenerateOptions.model}. + * @param _signal - cancellation for this exact-model lookup; asynchronous + * implementations must settle promptly after it aborts. + * @returns provider/model identity plus any context, call-default, and reasoning metadata. + */ + resolveModel(provider, model, _signal) { + return Promise.resolve({ + provider, + id: model, + name: model + }); + } +}; +/** +* The abstract `llm` service: an adapter registry plus a streaming model-call +* API, interceptable via the `llm/stream` waterfall. +*/ +var LlmRuntime = class extends Service { + adapters = /* @__PURE__ */ new Map(); + directory = /* @__PURE__ */ new Map(); + discoveries = /* @__PURE__ */ new Map(); + constructor(ctx) { + super(ctx, "llm"); + } + /** Notify topology observers without letting one broken listener veto the commit. */ + emitAdaptersUpdated() { + let invariantFailure; + for (const listener of this.ctx.events.dispatch("emit", ["llm/adapters-updated"])) try { + const returned = listener(); + if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => { + this.warnAdaptersListenerFailure(error); + }); + } catch (error) { + if (error?.code === "INVARIANT") { + invariantFailure ??= error; + continue; + } + this.warnAdaptersListenerFailure(error); + } + if (invariantFailure !== void 0) throw invariantFailure; + } + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnAdaptersListenerFailure(error) { + this.ctx.logger.warn("llm: an llm/adapters-updated listener failed"); + this.ctx.logger.warn(error); + } + /** + * Register an adapter for the given provider routes. Throws `LlmError` with code + * `DUPLICATE_ADAPTER` if any provider already has an adapter (all-or-nothing). + * Disposed with the fiber. + * @param providers - every provider route this adapter should serve. + * @param adapter - the adapter that streams calls for those providers. + * @returns the disposer, carrying {@link AdapterRegistrationHandle.replace}. + */ + registerAdapter(providers, adapter) { + const owned = /* @__PURE__ */ new Set(); + let released = false; + const dispose = this.ctx.effect(function* () { + if (providers.length === 0) throw new LlmError("an adapter must register at least one provider", "INVALID_ADAPTER"); + this.commitRoutes(owned, this.prepareRoutes(providers, adapter, owned)); + yield () => { + released = true; + for (const provider of owned) this.adapters.delete(provider); + owned.clear(); + this.emitAdaptersUpdated(); + }; + }.bind(this), "llm.registerAdapter()"); + const handle = (() => void dispose()); + handle.replace = (next) => { + if (released) throw new LlmError("a disposed adapter registration cannot replace its routes", "REGISTRATION_DISPOSED"); + this.commitRoutes(owned, this.prepareRoutes(next, adapter, owned)); + }; + return handle; + } + /** + * Validate one candidate route set for `adapter`, treating routes this + * registration already holds as available. Nothing is mutated: a rejected + * candidate leaves the registry exactly as it was. + */ + prepareRoutes(providers, adapter, owned) { + const unique = /* @__PURE__ */ new Set(); + const registrations = []; + for (const provider of providers) { + if (provider.length === 0) throw new LlmError("adapter provider names must be non-empty", "INVALID_ADAPTER"); + if (unique.has(provider) || this.adapters.has(provider) && !owned.has(provider)) throw new LlmError(`an adapter for provider "${provider}" is already registered`, "DUPLICATE_ADAPTER"); + const info = adapter.providerInfo(provider); + if (typeof info.id !== "string" || info.id !== provider || typeof info.name !== "string" || info.name.length === 0) throw new LlmError(`adapter metadata for provider "${provider}" must preserve its id and have a non-empty name`, "INVALID_ADAPTER"); + unique.add(provider); + const retryPolicy = adapter.providerRetryPolicy(provider) ?? resolveRetryPolicy(void 0, `llm: provider "${provider}" retryPolicy`); + registrations.push({ + adapter, + provider: { + id: info.id, + name: info.name + }, + retryPolicy + }); + } + return registrations; + } + /** + * Swap this registration's routes for the prepared ones in one synchronous + * section, so no observer can see the registry between the release and the + * re-registration. The route set's one mutation point is also where + * `llm/adapters-updated` is published, so a `replace` announces itself + * exactly like a first registration. + */ + commitRoutes(owned, registrations) { + for (const provider of owned) this.adapters.delete(provider); + owned.clear(); + for (const registration of registrations) { + this.adapters.set(registration.provider.id, registration); + owned.add(registration.provider.id); + } + this.emitAdaptersUpdated(); + } + /** + * Describe provider routes with a registered adapter. + * @returns detached provider metadata in registration order. + */ + listProviders() { + return [...this.adapters.values()].map(({ provider }) => ({ ...provider })); + } + /** + * Declare provider routes an adapter plugin can activate through + * configuration. Registration is all-or-nothing: an empty list, invalid + * entry, or a provider already declared by any registration throws + * `LlmError` without registering the rest. Disposed with the fiber. + * @param entries - every configurable provider this plugin owns. + * @returns a handle that withdraws all of them, and can atomically replace them. + */ + registerConfigurableProviders(entries) { + let held = []; + let disposed = false; + /** + * Validate a candidate set in full against everything this registration + * does not already hold, then publish it. Nothing is written until the + * whole set passes, so a refused candidate leaves the current entries in + * place — the property that makes `replace` a swap rather than a + * delete-then-add that can strand the directory empty. + */ + const commit = (candidates) => { + const detached = []; + const own = new Set(held.map((entry) => entry.provider)); + for (const entry of candidates) { + if (entry.provider.length === 0 || entry.displayName.length === 0 || entry.settingsNs.length === 0) throw new LlmError("configurable providers need a non-empty provider, displayName, and settingsNs", "INVALID_DIRECTORY"); + if (entry.settingsPath.some((segment) => segment.length === 0)) throw new LlmError(`configurable provider "${entry.provider}" has an empty settingsPath segment`, "INVALID_DIRECTORY"); + if (this.directory.has(entry.provider) && !own.has(entry.provider) || detached.some((seen) => seen.provider === entry.provider)) throw new LlmError(`configurable provider "${entry.provider}" is already declared`, "DUPLICATE_DIRECTORY"); + detached.push({ + ...entry, + settingsPath: [...entry.settingsPath] + }); + } + for (const entry of held) this.directory.delete(entry.provider); + for (const entry of detached) this.directory.set(entry.provider, entry); + held = detached; + this.emitAdaptersUpdated(); + }; + const dispose = this.ctx.effect(function* () { + if (entries.length === 0) throw new LlmError("a configurable-provider registration must declare at least one provider", "INVALID_DIRECTORY"); + commit(entries); + yield () => { + disposed = true; + for (const entry of held) this.directory.delete(entry.provider); + held = []; + this.emitAdaptersUpdated(); + }; + }.bind(this), "llm.registerConfigurableProviders()"); + const handle = (() => void dispose()); + handle.replace = (next) => { + if (disposed) throw new LlmError("this configurable-provider registration was disposed", "REGISTRATION_DISPOSED"); + commit(next); + }; + return handle; + } + /** + * List every declared configurable provider, registered or dormant. + * @returns detached directory entries in declaration order. + */ + listConfigurableProviders() { + return [...this.directory.values()].map((entry) => ({ + ...entry, + settingsPath: [...entry.settingsPath] + })); + } + /** + * Offer to interrogate provider endpoints on behalf of the settings + * namespace this plugin owns. The namespace is the key because that is what + * a configuration surface already holds from the configurable-provider + * directory, and because a provider being *added* has no route to name yet. + * Disposed with the fiber. + * @param settingsNs - the namespace whose profiles this discovery serves. + * @param discover - interrogates one endpoint; must honor `request.signal`. + * @returns the disposer that withdraws the offer. + */ + registerModelDiscovery(settingsNs, discover) { + const dispose = this.ctx.effect(function* () { + if (settingsNs.length === 0) throw new LlmError("model discovery needs a non-empty settings namespace", "INVALID_DISCOVERY"); + if (this.discoveries.has(settingsNs)) throw new LlmError(`model discovery for "${settingsNs}" is already registered`, "DUPLICATE_DISCOVERY"); + this.discoveries.set(settingsNs, discover); + yield () => { + this.discoveries.delete(settingsNs); + }; + }.bind(this), "llm.registerModelDiscovery()"); + return () => void dispose(); + } + /** + * Interrogate one provider endpoint for the models it advertises. The + * request describes a draft, not a stored route, so nothing here reads or + * writes settings or credentials — the caller owns both, and the reply is + * candidate metadata a surface may offer for adoption. + * @param settingsNs - namespace whose registered discovery serves this draft. + * @param request - the endpoint, protocol, and one-shot credential to use. + * @returns the advertised models, deduplicated in endpoint order. + */ + async discoverModels(settingsNs, request) { + const discover = this.discoveries.get(settingsNs); + if (discover === void 0) throw new LlmError(`no model discovery is registered for "${settingsNs}"`, "NO_DISCOVERY"); + if ((request.provider ?? "").length === 0 && (request.baseURL ?? "").length === 0) throw new LlmError("model discovery needs a provider route or a baseURL", "INVALID_DISCOVERY"); + const discovered = await discover(request); + const seen = /* @__PURE__ */ new Set(); + const models = []; + for (const model of discovered) { + if (typeof model.id !== "string" || model.id.length === 0 || seen.has(model.id)) continue; + seen.add(model.id); + models.push({ + id: model.id, + ...model.name === void 0 ? {} : { name: model.name }, + ...model.contextWindow === void 0 ? {} : { contextWindow: model.contextWindow }, + ...model.maxTokens === void 0 ? {} : { maxTokens: model.maxTokens } + }); + } + return models; + } + /** + * Resolve the retry policy captured when one provider route was registered. + * @param provider - registered provider route to inspect. + * @returns the provider-owned policy, with normal defaults already resolved. + */ + providerRetryPolicy(provider) { + return this.registration(provider).retryPolicy; + } + /** Detach typed adapter-owned modality metadata. */ + detachedModalities(modalities) { + return modalities === void 0 ? void 0 : [...modalities]; + } + /** + * Discover models advertised by one registered provider. Catalog membership + * is advisory and never changes routing or request validation. + * @param provider - registered provider route to inspect. + * @returns detached model metadata in adapter-preferred order. + */ + async listModels(provider) { + const models = await this.registration(provider).adapter.listModels(provider); + const seen = /* @__PURE__ */ new Set(); + return models.map((model) => { + if (typeof model.provider !== "string" || model.provider !== provider || typeof model.id !== "string" || model.id.length === 0 || typeof model.name !== "string" || model.name.length === 0 || model.description !== void 0 && typeof model.description !== "string" || seen.has(model.id)) throw new LlmError(`adapter returned invalid or duplicate model metadata for provider "${provider}"`, "INVALID_CATALOG"); + seen.add(model.id); + const inputModalities = this.detachedModalities(model.inputModalities); + return { + provider: model.provider, + id: model.id, + name: model.name, + ...model.description === void 0 ? {} : { description: model.description }, + ...inputModalities === void 0 ? {} : { inputModalities } + }; + }); + } + /** + * Resolve and validate all metadata from the adapter that owns one exact + * route. The result is detached from adapter-owned objects; catalog + * membership remains advisory and does not control request routing. + * @param provider - registered provider route to inspect. + * @param model - exact model id passed to the adapter. + * @param signal - optional cancellation for adapter-owned asynchronous lookup. + * @returns exact model identity plus available context and reasoning metadata. + */ + async resolveModelInfo(provider, model, signal) { + return this.resolveModelInfoFor(this.registration(provider), model, signal); + } + async resolveModelInfoFor(registration, model, signal) { + const provider = registration.provider.id; + const resolved = await registration.adapter.resolveModel(provider, model, signal); + if (typeof resolved.provider !== "string" || resolved.provider !== provider || typeof resolved.id !== "string" || resolved.id !== model || typeof resolved.name !== "string" || resolved.name.length === 0 || resolved.description !== void 0 && typeof resolved.description !== "string") throw new LlmError(`adapter returned invalid exact model metadata for provider "${provider}" model "${model}"`, "INVALID_MODEL_INFO"); + const context = resolved.context; + if (context !== void 0 && (!Number.isInteger(context.contextWindow) || context.contextWindow <= 0)) throw new LlmError(`adapter returned invalid context metadata for provider "${provider}" model "${model}"`, "INVALID_MODEL_CONTEXT"); + const inputModalities = this.detachedModalities(resolved.inputModalities); + const defaultMaxTokens = resolved.defaultMaxTokens; + if (defaultMaxTokens !== void 0 && (!Number.isSafeInteger(defaultMaxTokens) || defaultMaxTokens <= 0)) throw new LlmError(`adapter returned invalid default maxTokens for provider "${provider}" model "${model}"`, "INVALID_MODEL_MAX_TOKENS"); + const info = { + provider, + id: model, + name: resolved.name, + ...resolved.description === void 0 ? {} : { description: resolved.description }, + ...inputModalities === void 0 ? {} : { inputModalities }, + ...context === void 0 ? {} : { context: { contextWindow: context.contextWindow } }, + ...defaultMaxTokens === void 0 ? {} : { defaultMaxTokens } + }; + const reasoning = resolved.reasoning; + if (reasoning === void 0) return info; + if (reasoning.efforts.length === 0) throw new LlmError(`adapter returned invalid reasoning metadata for provider "${provider}" model "${model}"`, "INVALID_MODEL_REASONING"); + const seen = /* @__PURE__ */ new Set(); + const efforts = reasoning.efforts.map((effort) => { + if (typeof effort.id !== "string" || effort.id.length === 0 || typeof effort.name !== "string" || effort.name.length === 0 || effort.description !== void 0 && typeof effort.description !== "string" || seen.has(effort.id)) throw new LlmError(`adapter returned invalid or duplicate reasoning effort metadata for provider "${provider}" model "${model}"`, "INVALID_MODEL_REASONING"); + seen.add(effort.id); + return { + id: effort.id, + name: effort.name, + ...effort.description === void 0 ? {} : { description: effort.description } + }; + }); + if (reasoning.defaultEffort !== void 0 && !seen.has(reasoning.defaultEffort)) throw new LlmError(`adapter returned an unknown default reasoning effort for provider "${provider}" model "${model}"`, "INVALID_MODEL_REASONING"); + return { + ...info, + reasoning: { + efforts, + ...reasoning.defaultEffort === void 0 ? {} : { defaultEffort: reasoning.defaultEffort } + } + }; + } + /** + * Validate a conversation call config against its exact model capability and + * materialize adapter-configured defaults. Unsupported explicit efforts + * reject before provider I/O; no clamping or aliasing is performed. This + * standalone query does not bind a later dispatch; use {@link prepareCall} + * when logging and streaming must share one adapter registration. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a detached config only when a default must be materialized. + */ + async resolveCallConfig(config, signal) { + return (await this.resolveCallFor(this.registration(config.provider), config, signal)).config; + } + async resolveCallFor(registration, config, signal) { + const info = await this.resolveModelInfoFor(registration, config.model, signal); + const defaulted = config.maxTokens === void 0 && info.defaultMaxTokens !== void 0 ? { + ...config, + maxTokens: info.defaultMaxTokens + } : config; + const reasoning = info.reasoning; + const requested = defaulted.reasoningEffort; + let resolvedConfig = defaulted; + if (reasoning === void 0) { + if (requested !== void 0) throw new LlmError(`provider "${config.provider}" model "${config.model}" does not support reasoning effort "${requested}"`, "UNSUPPORTED_REASONING_EFFORT"); + } else { + const effective = requested ?? reasoning.defaultEffort; + if (effective !== void 0) { + if (!reasoning.efforts.some((effort) => effort.id === effective)) throw new LlmError(`provider "${config.provider}" model "${config.model}" does not support reasoning effort "${effective}"`, "UNSUPPORTED_REASONING_EFFORT"); + if (requested !== effective) resolvedConfig = { + ...defaulted, + reasoningEffort: effective + }; + } + } + return { + config: resolvedConfig, + ...info.context === void 0 ? {} : { context: info.context } + }; + } + /** + * Resolve one call under its current adapter registration. The returned + * one-shot handle keeps that registration across header logging and dispatch, + * so HMR cannot combine one adapter's capability result with another adapter. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a prepared config and its registration-bound stream entry point. + */ + async prepareCall(config, signal) { + const registration = this.registration(config.provider); + const resolved = await this.resolveCallFor(registration, config, signal); + const resolvedConfig = deepFreeze(structuredClone(resolved.config)); + const context = resolved.context === void 0 ? void 0 : deepFreeze(structuredClone(resolved.context)); + const adapterDefaults = deepFreeze({ + ...config.reasoningEffort === void 0 && resolvedConfig.reasoningEffort !== void 0 ? { reasoningEffort: true } : {}, + ...config.maxTokens === void 0 && resolvedConfig.maxTokens !== void 0 ? { maxTokens: true } : {} + }); + let dispatched = false; + return Object.freeze({ + config: resolvedConfig, + retryPolicy: registration.retryPolicy, + adapterDefaults, + ...context === void 0 ? {} : { context }, + stream: (options) => { + if (dispatched) throw new LlmError("a prepared LLM call can only be dispatched once", "INVALID_PREPARED_CALL"); + if (!callConfigEquals(options, resolvedConfig)) throw new LlmError("prepared LLM call config changed before adapter dispatch", "INVALID_PREPARED_CALL"); + dispatched = true; + return this.streamWithRegistration(options, { + registration, + config: resolvedConfig + }); + } + }); + } + registration(provider) { + const registration = this.adapters.get(provider); + if (!registration) throw new LlmError(`no adapter registered for provider "${provider}"`, "NO_ADAPTER"); + return registration; + } + /** Remove replay state whose historical route is owned by another adapter. */ + forAdapter(options, adapter) { + const messages = options.messages.map((message) => { + const source = message.source; + if (message.role !== "assistant" || source.kind !== "model" || source.replayState === void 0) return message; + if (this.adapters.get(source.provider)?.adapter === adapter) return message; + return freezeMessage({ + ...message, + source: { + kind: "model", + provider: source.provider, + model: source.model + } + }); + }); + if (messages.every((message, index) => message === options.messages[index])) return options; + const filtered = { + ...options, + messages + }; + return Object.isFrozen(options) ? deepFreeze(filtered) : filtered; + } + /** + * Final adapter boundary. Adapter selection, dispatch, iterator construction, + * and iteration failures become one terminal failure chunk. Middleware and + * downstream consumer failures remain thrown plugin or consumer errors. + */ + async *adapterStream(options, prepared) { + let iterator; + try { + const registration = prepared?.registration ?? this.registration(options.provider); + const resolvedConfig = prepared === void 0 ? (await this.resolveCallFor(registration, options, options.signal)).config : prepared.config; + if (prepared !== void 0 && !callConfigEquals(options, resolvedConfig)) throw new LlmError("prepared LLM call config changed before adapter dispatch", "INVALID_PREPARED_CALL"); + const resolvedOptions = callConfigEquals(options, resolvedConfig) ? options : Object.isFrozen(options) ? deepFreeze({ + ...options, + ...resolvedConfig + }) : { + ...options, + ...resolvedConfig + }; + const adapter = registration.adapter; + iterator = adapter.stream(this.forAdapter(resolvedOptions, adapter))[Symbol.asyncIterator](); + } catch (error) { + yield adapterFailureChunk(error, options.signal); + return; + } + let completed = false; + try { + while (true) { + let item; + try { + const next = await iterator.next(); + item = next.done ? { done: true } : { + done: false, + value: next.value + }; + } catch (error) { + completed = true; + yield adapterFailureChunk(error, options.signal); + return; + } + if (item.done) { + completed = true; + return; + } + yield item.value; + } + } finally { + if (!completed) { + const close = iterator.return?.bind(iterator); + if (close) await close(); + } + } + } + /** + * Stream one model call as raw chunks (token-level deltas). Replay state is + * retained only when the same adapter instance owns its historical provider + * and the target provider. Final adapter selection remains fixed through + * asynchronous exact-model resolution and dispatch. Adapter selection, + * dispatch, and iteration failures become terminal `error` or `aborted` + * finish chunks; middleware, nested-call, cleanup, and consumer failures + * remain thrown. + * @param options - the full request; `options.provider` selects the adapter. + * @returns the chunk stream, possibly wrapped by `llm/stream` listeners. + */ + stream(options) { + return this.streamWithRegistration(options); + } + streamWithRegistration(options, prepared) { + return this.ctx.waterfall(this, "llm/stream", options, () => this.adapterStream(options, prepared)); + } +}; +/** Convert one adapter throw into the stream protocol's terminal outcome. */ +function adapterFailureChunk(error, signal) { + const failure = normalizeLlmFailure(error); + return { + type: "finish", + reason: signal?.aborted || failure.code === "ABORTED" ? { + kind: "aborted", + failure + } : { + kind: "error", + failure + } + }; +} +//#endregion +export { APP_IDENTITY, BlockAssembler, CONTEXT_SUMMARY_MAX_CHARS, CONTEXT_WINDOW_EXCEEDED_CODE, CallId, EMPTY_RESPONSE_CODE, HarnessError, INVALID_CREDENTIAL_CODE, LlmAdapter, LlmError, LlmRuntime, LlmRuntime as default, MessageId, ProviderRequestId, QUOTA_EXCEEDED_CODE, ReasoningEffortId, RetryPolicySchema, assertNever, assertUsableApiKey, attributionHeaders, boundContextSummary, callConfigEquals, contentHasImage, createAssistantMessage, createMessage, createToolResultMessage, createUserMessage, deepFreeze, errorChain, freezeMessage, isAgentLoopRequest, isContextWindowExceededError, isHarnessError, isQuotaExceededError, isTokenDelta, markAgentLoopRequest, normalizeApiKey, resolveRetryPolicy, userAgent }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/invariant.js new file mode 100644 index 0000000..8b97724 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/invariant.js @@ -0,0 +1,84 @@ +//#region lib/types/invariant.js +/** Package-owned LLM stream-protocol invariants. @module @deepseek-ai/dsh-llm/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-llm"; +/** Cordis companion plugin name. */ +const name = "llm-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Require one chunk index to be a non-negative safe integer. */ +function validateIndex(index, fail) { + if (!Number.isSafeInteger(index) || index < 0) fail(`LLM stream block index must be a non-negative safe integer, got ${index}`); +} +/** Require a delta to address an open block of its matching type. */ +function validateDelta(open, index, expected, fail) { + validateIndex(index, fail); + const actual = open.get(index); + if (actual !== expected) fail(`${expected} delta at index ${index} requires an open ${expected} block, got ${String(actual)}`); +} +/** Wrap one provider stream and enforce its grammar as chunks are consumed. */ +async function* validateStream(source, fail) { + const open = /* @__PURE__ */ new Map(); + let usageSeen = false; + let finished = false; + for await (const chunk of source) { + if (finished) fail(`LLM stream emitted ${chunk.type} after terminal finish`); + switch (chunk.type) { + case "block-start": + validateIndex(chunk.index, fail); + if (open.has(chunk.index)) fail(`LLM stream repeated block-start index ${chunk.index}`); + open.set(chunk.index, chunk.blockType); + break; + case "text-delta": + validateDelta(open, chunk.index, "text", fail); + break; + case "reasoning-delta": + validateDelta(open, chunk.index, "reasoning", fail); + break; + case "tool-call-delta": + validateDelta(open, chunk.index, "tool-call", fail); + break; + case "block-end": { + validateIndex(chunk.index, fail); + const blockType = open.get(chunk.index); + if (blockType === void 0) fail(`LLM stream block-end index ${chunk.index} has no open block`); + if (chunk.block.type !== blockType) fail(`LLM stream block-end index ${chunk.index} closes ${chunk.block.type}, expected ${blockType}`); + open.delete(chunk.index); + break; + } + case "usage": + if (usageSeen) fail("LLM stream emitted usage more than once"); + usageSeen = true; + break; + case "finish": + if (open.size > 0 && chunk.reason.kind !== "error" && chunk.reason.kind !== "aborted") fail(`LLM stream finished with ${open.size} open block(s)`); + finished = true; + break; + } + yield chunk; + } + if (!finished) fail("LLM stream ended without a terminal finish chunk"); +} +/** Install validation around every provider stream. */ +const install = (ctx, fail) => { + ctx.on("llm/stream", (_options, next) => validateStream(next(), fail), { + global: true, + prepend: true + }); + ctx.on("llm/adapters-updated", () => { + const llm = ctx.get("llm"); + if (llm === void 0) return; + for (const provider of llm.listProviders()) try { + llm.providerRetryPolicy(provider.id); + } catch { + fail(`llm/adapters-updated fired while provider "${provider.id}" has no readable registration`); + } + }, { global: true }); +}; +/** +* Register the LLM invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.d.ts new file mode 100644 index 0000000..2bde887 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.d.ts @@ -0,0 +1,14 @@ +/** + * Normalization for values thrown by a final LLM adapter boundary. + * + * @module @deepseek-ai/dsh-llm/adapter-failure + */ +import type { LlmFailure } from './types.ts'; +/** + * Detach serializable provider facts from a value thrown by an adapter. + * @param value - arbitrary value thrown during adapter dispatch or iteration. + * @returns immutable provider-neutral facts suitable for a terminal finish chunk. + * @internal + */ +export declare function normalizeLlmFailure(value: unknown): LlmFailure; +//# sourceMappingURL=adapter-failure.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.js new file mode 100644 index 0000000..86ad05d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/adapter-failure.js @@ -0,0 +1,105 @@ +/** + * Normalization for values thrown by a final LLM adapter boundary. + * + * @module @deepseek-ai/dsh-llm/adapter-failure + */ +import { HarnessError } from "./error.js"; +/** + * Detach serializable provider facts from a value thrown by an adapter. + * @param value - arbitrary value thrown during adapter dispatch or iteration. + * @returns immutable provider-neutral facts suitable for a terminal finish chunk. + * @internal + */ +export function normalizeLlmFailure(value) { + const error = value instanceof Error + ? value + : new HarnessError(thrownMessage(value), 'UNKNOWN', { cause: value }); + // Cross-package copies preserve own data but not class identity. Trust the + // carried facts only when both own properties agree after validation. + const carried = ownFailureSnapshot(error); + if (carried !== undefined && carried.code === ownErrorCode(error)) + return carried; + return Object.freeze({ + message: errorMessage(error), + code: harnessErrorCode(error), + }); +} +/** Render a non-Error throw without letting hostile coercion escape normalization. */ +function thrownMessage(value) { + try { + const message = String(value); + return message.length > 0 ? message : 'LLM adapter failed'; + } + catch (_hostileThrownValue) { + return 'LLM adapter failed'; + } +} +/** Read a foreign error's own data-backed `code` without invoking accessors. */ +function ownErrorCode(error) { + try { + const descriptor = Object.getOwnPropertyDescriptor(error, 'code'); + return descriptor !== undefined && 'value' in descriptor ? descriptor.value : undefined; + } + catch (_sdkPropertyTrap) { + return undefined; + } +} +/** Snapshot an own data property without invoking an SDK-defined accessor. */ +function ownFailureSnapshot(error) { + try { + const descriptor = Object.getOwnPropertyDescriptor(error, 'failure'); + return descriptor !== undefined && 'value' in descriptor + ? failureSnapshot(descriptor.value) + : undefined; + } + catch (_sdkPropertyTrap) { + return undefined; + } +} +/** Validate and detach an arbitrary serializable failure payload. */ +function failureSnapshot(value) { + if (typeof value !== 'object' || value === null) + return undefined; + try { + const candidate = value; + const message = candidate.message; + const code = candidate.code; + const status = candidate.status; + const providerRetryAfterMs = candidate.providerRetryAfterMs; + const requestId = candidate.requestId; + if (typeof message !== 'string' || message.length === 0 + || typeof code !== 'string' || code.length === 0 + || (status !== undefined && (!Number.isInteger(status) || status < 100 || status > 599)) + || (providerRetryAfterMs !== undefined + && (!Number.isFinite(providerRetryAfterMs) || providerRetryAfterMs <= 0)) + || (requestId !== undefined && (typeof requestId !== 'string' || requestId.length === 0))) + return undefined; + return Object.freeze({ + message, + code, + ...status === undefined ? {} : { status }, + ...providerRetryAfterMs === undefined ? {} : { providerRetryAfterMs }, + ...requestId === undefined ? {} : { requestId }, + }); + } + catch (_sdkFailureGetter) { + return undefined; + } +} +/** Read an SDK error message without letting an accessor replace the primary failure. */ +function errorMessage(error) { + try { + const message = error.message; + if (typeof message === 'string' && message.length > 0) + return message; + } + catch (_sdkMessageGetter) { + // The fallback below preserves a serializable failure beside the original Error. + } + return 'LLM adapter failed'; +} +/** Trust only Harness-owned codes; third-party SDK codes are not our taxonomy. */ +function harnessErrorCode(error) { + return error instanceof HarnessError ? error.code : 'UNKNOWN'; +} +//# sourceMappingURL=adapter-failure.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.d.ts new file mode 100644 index 0000000..dfad49c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.d.ts @@ -0,0 +1,28 @@ +/** + * The one definition of a well-formed provider API key, shared by every + * adapter that puts one in an HTTP header. + * @module @deepseek-ai/dsh-llm/api-key + */ +/** Why a supplied API key cannot be used. */ +export type ApiKeyRejection = 'empty' | 'illegalCharacters'; +/** The verdict on one supplied API key. */ +export type ApiKeyCheck = { + readonly ok: true; + readonly value: string; +} | { + readonly ok: false; + readonly reason: ApiKeyRejection; +}; +/** + * Judge one *supplied* API key, trimming surrounding whitespace first. + * + * Trimming is silent because a padded key has one unambiguous reading; every + * other defect is reported. Absence is a configuration state this function + * never sees — a profile naming no credential authenticates through the + * provider's own ambient discovery or OAuth — so callers decide whether a + * value was supplied before asking. + * @param raw - the key exactly as configured, stored, or typed. + * @returns the trimmed key, or why it cannot be used. + */ +export declare function normalizeApiKey(raw: string): ApiKeyCheck; +//# sourceMappingURL=api-key.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.js new file mode 100644 index 0000000..37e78db --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/api-key.js @@ -0,0 +1,34 @@ +/** + * The one definition of a well-formed provider API key, shared by every + * adapter that puts one in an HTTP header. + * @module @deepseek-ai/dsh-llm/api-key + */ +/** + * Characters an HTTP header value carries verbatim and every known provider + * key uses: printable ASCII, space excluded. A key outside this set cannot + * reach any provider — `fetch` refuses to build the header — so this is a + * transport invariant rather than one provider's policy. Latin-1 is excluded + * deliberately: a header could carry it, but no provider issues it, and + * admitting it trades a local explained refusal for an opaque 401. + */ +const LEGAL_API_KEY = /^[\x21-\x7E]+$/; +/** + * Judge one *supplied* API key, trimming surrounding whitespace first. + * + * Trimming is silent because a padded key has one unambiguous reading; every + * other defect is reported. Absence is a configuration state this function + * never sees — a profile naming no credential authenticates through the + * provider's own ambient discovery or OAuth — so callers decide whether a + * value was supplied before asking. + * @param raw - the key exactly as configured, stored, or typed. + * @returns the trimmed key, or why it cannot be used. + */ +export function normalizeApiKey(raw) { + const value = raw.trim(); + if (value.length === 0) + return { ok: false, reason: 'empty' }; + if (!LEGAL_API_KEY.test(value)) + return { ok: false, reason: 'illegalCharacters' }; + return { ok: true, value }; +} +//# sourceMappingURL=api-key.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.d.ts new file mode 100644 index 0000000..f91c490 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.d.ts @@ -0,0 +1,66 @@ +/** + * Incremental chunk-to-message assembler. This is the single canonical assembly + * algorithm used by the agent loop to build an assistant message from a chunk + * stream while logging the raw chunks for replay fidelity. + * + * @module @deepseek-ai/dsh-llm/assembler + */ +import type { Message, MessageSource } from './message.ts'; +import type { ContentBlock, FinishReason, ReplayEnvelope, StreamChunk, TokenUsage } from './types.ts'; +/** + * Incrementally assembles raw {@link StreamChunk}s into complete + * {@link ContentBlock}s and a final assistant {@link Message}. + * + * The agent loop feeds it while logging raw chunks for replay fidelity, then + * reads `blocks()` / `message()` / `usage` / `finish` once the stream ends. + * + * Tolerant of delta-only protocols (no block-start/end); deltas arriving for + * an index already closed by `block-end` are ignored (malformed stream) so a + * misbehaving adapter cannot grow memory or corrupt a completed block. + */ +export declare class BlockAssembler { + private partials; + private order; + private _usage; + private _finish; + private _replayState; + /** + * Feed one chunk into the assembly state. + * @param chunk - the next raw chunk, in stream order. + */ + push(chunk: StreamChunk): void; + private ensure; + private assemble; + /** Invariant accessor: every index in `order` has a partial. */ + private mustGet; + /** + * The one shared keep/drop decision over all seen blocks: max-token + * truncation drops tool calls that cannot be executed safely. Emitted blocks + * and replay metadata both derive from this result, so they cannot disagree. + */ + private assembled; + /** + * Assemble all blocks seen so far, in stream order. + * @returns one block per seen index, except that max-token truncation drops + * tool calls that cannot be executed safely; an open block assembles from + * its accumulated deltas (an unknown block type never closed by `block-end` throws). + */ + blocks(): ContentBlock[]; + /** Usage from the `usage` chunk; undefined until one arrives. */ + get usage(): TokenUsage | undefined; + /** Finish reason from the `finish` chunk; `{kind: 'stop'}` when the stream ended without one. */ + get finish(): FinishReason; + /** + * Replay metadata from the terminal finish chunk, if any, with per-block + * entries pruned in step with {@link blocks}. Undefined when the envelope's + * entries do not align with the emitted blocks. + */ + get replayState(): ReplayEnvelope | undefined; + /** + * The assembled assistant message. + * @param source - producer attribution for the assembled message. + * @returns a frozen assistant-role message over `blocks()` (same open-block assembly rules). + */ + message(source?: MessageSource): Message; +} +//# sourceMappingURL=assembler.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.js new file mode 100644 index 0000000..3de3488 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/assembler.js @@ -0,0 +1,172 @@ +/** + * Incremental chunk-to-message assembler. This is the single canonical assembly + * algorithm used by the agent loop to build an assistant message from a chunk + * stream while logging the raw chunks for replay fidelity. + * + * @module @deepseek-ai/dsh-llm/assembler + */ +import { CallId } from "./brand.js"; +import { assertNever } from "./never.js"; +import { createMessage } from "./message.js"; +/** + * Incrementally assembles raw {@link StreamChunk}s into complete + * {@link ContentBlock}s and a final assistant {@link Message}. + * + * The agent loop feeds it while logging raw chunks for replay fidelity, then + * reads `blocks()` / `message()` / `usage` / `finish` once the stream ends. + * + * Tolerant of delta-only protocols (no block-start/end); deltas arriving for + * an index already closed by `block-end` are ignored (malformed stream) so a + * misbehaving adapter cannot grow memory or corrupt a completed block. + */ +export class BlockAssembler { + partials = new Map(); + order = []; + _usage; + _finish; + _replayState; + /** + * Feed one chunk into the assembly state. + * @param chunk - the next raw chunk, in stream order. + */ + push(chunk) { + switch (chunk.type) { + case 'block-start': { + if (!this.partials.has(chunk.index)) { + this.order.push(chunk.index); + this.partials.set(chunk.index, { + blockType: chunk.blockType, + text: '', + toolCallArguments: '', + }); + } + return; + } + case 'text-delta': + case 'reasoning-delta': { + const partial = this.ensure(chunk.index, chunk.type === 'text-delta' ? 'text' : 'reasoning'); + if (partial.block) + return; // closed by block-end; ignore stragglers + partial.text += chunk.text; + return; + } + case 'tool-call-delta': { + const partial = this.ensure(chunk.index, 'tool-call'); + if (partial.block) + return; // closed by block-end; ignore stragglers + partial.toolCallId = chunk.id; + if (chunk.name) + partial.toolCallName = chunk.name; + partial.toolCallArguments += chunk.argumentsDelta; + return; + } + case 'block-end': { + const partial = this.ensure(chunk.index, chunk.block.type); + // First close wins; ignoring re-close stragglers keeps streamed output + // and the final assembled block in agreement. + if (partial.block) + return; + partial.block = chunk.block; + return; + } + case 'usage': { + this._usage = chunk.usage; + return; + } + case 'finish': { + this._finish = chunk.reason; + this._replayState = chunk.replayState; + return; + } + default: return assertNever(chunk, 'BlockAssembler.push'); + } + } + ensure(index, blockType) { + let partial = this.partials.get(index); + if (!partial) { + partial = { blockType, text: '', toolCallArguments: '' }; + this.partials.set(index, partial); + this.order.push(index); + } + return partial; + } + assemble(partial, index) { + if (partial.block) + return partial.block; + switch (partial.blockType) { + case 'text': return { type: 'text', text: partial.text }; + case 'reasoning': return { type: 'reasoning', text: partial.text }; + case 'tool-call': return { + type: 'tool-call', + id: partial.toolCallId ?? CallId(`call-${index}`), + name: partial.toolCallName ?? '', + arguments: partial.toolCallArguments, + }; + default: throw new Error(`cannot assemble incomplete block of type "${partial.blockType}"`); + } + } + /** Invariant accessor: every index in `order` has a partial. */ + mustGet(index) { + const partial = this.partials.get(index); + if (!partial) + throw new Error(`BlockAssembler invariant violated: no partial for index ${index}`); + return partial; + } + /** + * The one shared keep/drop decision over all seen blocks: max-token + * truncation drops tool calls that cannot be executed safely. Emitted blocks + * and replay metadata both derive from this result, so they cannot disagree. + */ + assembled() { + const all = this.order.map(index => this.assemble(this.mustGet(index), index)); + const kept = this.finish.kind === 'max-tokens' + ? all.map(block => block.type !== 'tool-call') + : undefined; + const blocks = kept === undefined ? all : all.filter((_, position) => kept[position]); + const envelope = this._replayState; + if (envelope?.blocks === undefined) + return { blocks, replay: envelope }; + if (envelope.blocks.length !== all.length) + return { blocks, replay: undefined }; + return { + blocks, + replay: kept === undefined || blocks.length === all.length + ? envelope + : { response: envelope.response, blocks: envelope.blocks.filter((_, position) => kept[position]) }, + }; + } + /** + * Assemble all blocks seen so far, in stream order. + * @returns one block per seen index, except that max-token truncation drops + * tool calls that cannot be executed safely; an open block assembles from + * its accumulated deltas (an unknown block type never closed by `block-end` throws). + */ + blocks() { + return this.assembled().blocks; + } + /** Usage from the `usage` chunk; undefined until one arrives. */ + get usage() { + return this._usage; + } + /** Finish reason from the `finish` chunk; `{kind: 'stop'}` when the stream ended without one. */ + get finish() { + return this._finish ?? { kind: 'stop' }; + } + /** + * Replay metadata from the terminal finish chunk, if any, with per-block + * entries pruned in step with {@link blocks}. Undefined when the envelope's + * entries do not align with the emitted blocks. + */ + get replayState() { + return this.assembled().replay; + } + /** + * The assembled assistant message. + * @param source - producer attribution for the assembled message. + * @returns a frozen assistant-role message over `blocks()` (same open-block assembly rules). + */ + message(source = { kind: 'plugin', plugin: 'dsh-llm/assembler' }) { + return createMessage({ role: 'assistant', content: this.blocks(), source }); + } +} +//# sourceMappingURL=assembler.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.d.ts new file mode 100644 index 0000000..e4aa2a3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.d.ts @@ -0,0 +1,47 @@ +/** + * Centralize the non-secret product identity every provider request sends as `User-Agent`, keeping + * adapters from drifting. See + * `.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md`. + * + * App-attribution vocabulary for provider requests. + * @module @deepseek-ai/dsh-llm/attribution + */ +/** + * Static public application identity sent to LLM providers. + * + * Every field is a public product fact, safe on every request: no secrets, + * local paths, session ids, prompt text, or per-user identifiers belong here, + * and nothing per-request may influence the values. + */ +export interface AppIdentity { + /** `User-Agent` product token (lowercase, hyphenated). */ + product: string; + /** Product version; sourced from package metadata, never hand-copied. */ + version: string; + /** Repository home URL of the app, used as the `User-Agent` comment. */ + url: string; +} +/** + * The harness's own identity: the default every adapter sends. Deployments + * that need a white-label identity pass their own {@link AppIdentity} to + * {@link attributionHeaders} — omission falls back to this default; nothing + * can suppress attribution entirely. + */ +export declare const APP_IDENTITY: AppIdentity; +/** + * The standard `User-Agent` value: `product/version (+url)`. The + * parenthesized `+url` comment is the conventional self-identification form + * (RFC 9110 §10.1.5 product + comment syntax). + * @param identity - the identity to render; defaults to {@link APP_IDENTITY}. + * @returns the ready-to-send header value. + */ +export declare function userAgent(identity?: AppIdentity): string; +/** + * Build the attribution headers an adapter must send on every provider + * request. Header names are lowercase (HTTP field names are case-insensitive + * on the wire). + * @param identity - the identity to send; defaults to {@link APP_IDENTITY} — omission cannot suppress attribution. + * @returns headers to merge into the provider request (currently just `user-agent`). + */ +export declare function attributionHeaders(identity?: AppIdentity): Record; +//# sourceMappingURL=attribution.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.js new file mode 100644 index 0000000..a09678f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/attribution.js @@ -0,0 +1,46 @@ +/** + * Centralize the non-secret product identity every provider request sends as `User-Agent`, keeping + * adapters from drifting. See + * `.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md`. + * + * App-attribution vocabulary for provider requests. + * @module @deepseek-ai/dsh-llm/attribution + */ +import { createRequire } from 'node:module'; +// The package's own manifest is the single source of the version so the +// User-Agent cannot drift from what is published (`./package.json` is an +// export of this package; the relative path resolves from both `src/` and +// the bundled `lib/`). +const { version } = createRequire(import.meta.url)('../package.json'); +/** + * The harness's own identity: the default every adapter sends. Deployments + * that need a white-label identity pass their own {@link AppIdentity} to + * {@link attributionHeaders} — omission falls back to this default; nothing + * can suppress attribution entirely. + */ +export const APP_IDENTITY = { + product: 'deepseek-harness', + version, + url: 'https://github.com/deepseek-ai/deepseek-harness', +}; +/** + * The standard `User-Agent` value: `product/version (+url)`. The + * parenthesized `+url` comment is the conventional self-identification form + * (RFC 9110 §10.1.5 product + comment syntax). + * @param identity - the identity to render; defaults to {@link APP_IDENTITY}. + * @returns the ready-to-send header value. + */ +export function userAgent(identity = APP_IDENTITY) { + return `${identity.product}/${identity.version} (+${identity.url})`; +} +/** + * Build the attribution headers an adapter must send on every provider + * request. Header names are lowercase (HTTP field names are case-insensitive + * on the wire). + * @param identity - the identity to send; defaults to {@link APP_IDENTITY} — omission cannot suppress attribution. + * @returns headers to merge into the provider request (currently just `user-agent`). + */ +export function attributionHeaders(identity = APP_IDENTITY) { + return { 'user-agent': userAgent(identity) }; +} +//# sourceMappingURL=attribution.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.d.ts new file mode 100644 index 0000000..50599a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.d.ts @@ -0,0 +1,48 @@ +/** + * dsh-llm's owned branded ids: tool-call correlation and provider request + * diagnostics. + * + * The `Branded` primitive itself lives in `@deepseek-ai/dsh-brand` (a + * zero-dependency type-only package) so every owner of a cross-boundary id can + * brand it without depending on dsh-llm; see that package's README for the + * nominal-typing policy. + * + * @module @deepseek-ai/dsh-llm/brand + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Stable identity carried by one message across inbox, log, and model-request boundaries. */ +export type MessageId = Branded<'MessageId'>; +/** + * Brand a message identifier. + * @param id - the opaque message identifier. + * @returns the same string, branded; no validation is performed. + */ +export declare function MessageId(id: string): MessageId; +/** + * Correlates a model-issued tool call with its result. Provider-issued for + * real adapters; synthesized by mocks/assembler fallbacks. + */ +export type CallId = Branded<'CallId'>; +/** + * Brand a string as a {@link CallId}. + * @param id - the provider-issued (or synthesized) call id. + * @returns the same string, branded; no validation is performed. + */ +export declare function CallId(id: string): CallId; +/** Provider-issued request identifier retained for diagnostics across package boundaries. */ +export type ProviderRequestId = Branded<'ProviderRequestId'>; +/** + * Brand a provider-issued request identifier. + * @param id - the opaque provider-issued string. + * @returns the same string, branded; no validation is performed. + */ +export declare function ProviderRequestId(id: string): ProviderRequestId; +/** Adapter-owned identifier for one model's selectable reasoning effort. */ +export type ReasoningEffortId = Branded<'ReasoningEffortId'>; +/** + * Brand an adapter-owned reasoning-effort identifier. + * @param id - the opaque identifier exposed by one model capability. + * @returns the same string, branded; no validation is performed. + */ +export declare function ReasoningEffortId(id: string): ReasoningEffortId; +//# sourceMappingURL=brand.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.js new file mode 100644 index 0000000..a6eee43 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/brand.js @@ -0,0 +1,44 @@ +/** + * dsh-llm's owned branded ids: tool-call correlation and provider request + * diagnostics. + * + * The `Branded` primitive itself lives in `@deepseek-ai/dsh-brand` (a + * zero-dependency type-only package) so every owner of a cross-boundary id can + * brand it without depending on dsh-llm; see that package's README for the + * nominal-typing policy. + * + * @module @deepseek-ai/dsh-llm/brand + */ +/** + * Brand a message identifier. + * @param id - the opaque message identifier. + * @returns the same string, branded; no validation is performed. + */ +export function MessageId(id) { + return id; +} +/** + * Brand a string as a {@link CallId}. + * @param id - the provider-issued (or synthesized) call id. + * @returns the same string, branded; no validation is performed. + */ +export function CallId(id) { + return id; +} +/** + * Brand a provider-issued request identifier. + * @param id - the opaque provider-issued string. + * @returns the same string, branded; no validation is performed. + */ +export function ProviderRequestId(id) { + return id; +} +/** + * Brand an adapter-owned reasoning-effort identifier. + * @param id - the opaque identifier exposed by one model capability. + * @returns the same string, branded; no validation is performed. + */ +export function ReasoningEffortId(id) { + return id; +} +//# sourceMappingURL=brand.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.d.ts new file mode 100644 index 0000000..b157e27 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.d.ts @@ -0,0 +1,62 @@ +/** + * Conversation call configuration and freeze utilities. Provider routing, + * model, reasoning effort, and sampling values are request-header state that + * can affect cache reuse; request waterfalls replace them and the loop logs + * changed snapshots instead of allowing silent per-call drift. + * @module dsh-llm/call-config + */ +import type { GenerateOptions } from './types.ts'; +import type { ReasoningEffortId } from './brand.ts'; +/** + * Provider, model, reasoning effort, and sampling scalars of one conversation's + * requests. Every field maps 1:1 onto the same-named `GenerateOptions` field; + * the loop builds requests from the logged header rather than accepting these + * per call. + */ +export interface LlmCallConfig { + provider: string; + model: string; + reasoningEffort?: ReasoningEffortId; + temperature?: number; + maxTokens?: number; + stop?: string[]; +} +/** + * Effective config fields supplied by exact-model adapter resolution rather + * than by the caller's request proposal. + */ +export interface LlmCallConfigAdapterDefaults { + reasoningEffort?: true; + maxTokens?: true; +} +/** + * Field-wise equality over {@link LlmCallConfig} — the comparison a caller + * runs to decide whether a proposed configuration is a real change (worth a + * logged header snapshot) or the held one restated. + * @param a - one configuration. + * @param b - the other. + * @returns whether every field (including the `stop` list, element-wise) matches. + */ +export declare function callConfigEquals(a: LlmCallConfig, b: LlmCallConfig): boolean; +/** + * Mark one exact request object as assembled by dsh-agent-loop. + * @param request - loop-owned request envelope before LLM dispatch. + * @returns the same request object marked as created by the process-local agent loop. + */ +export declare function markAgentLoopRequest(request: T): T; +/** + * Test whether the exact request object was assembled by dsh-agent-loop. + * @param request - request envelope observed at the LLM waterfall. + * @returns whether {@link markAgentLoopRequest} recorded this object. + */ +export declare function isAgentLoopRequest(request: GenerateOptions): boolean; +/** + * Deep-freeze a value in place with an iterative traversal, guarding cycles, + * so later mutation throws without imposing a JavaScript call-stack depth cap. + * {@link AbortSignal} objects are deliberately skipped because they are the + * request's live cancellation channel and freezing them breaks abort. + * @param value - the value to freeze in place. + * @returns the same value, frozen. + */ +export declare function deepFreeze(value: T): T; +//# sourceMappingURL=call-config.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.js new file mode 100644 index 0000000..75b0874 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.js @@ -0,0 +1,86 @@ +/** + * Conversation call configuration and freeze utilities. Provider routing, + * model, reasoning effort, and sampling values are request-header state that + * can affect cache reuse; request waterfalls replace them and the loop logs + * changed snapshots instead of allowing silent per-call drift. + * @module dsh-llm/call-config + */ +/** Process-local identities of request objects assembled by dsh-agent-loop. */ +const AGENT_LOOP_REQUESTS = new WeakSet(); +/** + * Field-wise equality over {@link LlmCallConfig} — the comparison a caller + * runs to decide whether a proposed configuration is a real change (worth a + * logged header snapshot) or the held one restated. + * @param a - one configuration. + * @param b - the other. + * @returns whether every field (including the `stop` list, element-wise) matches. + */ +export function callConfigEquals(a, b) { + if (a.provider !== b.provider + || a.model !== b.model + || a.reasoningEffort !== b.reasoningEffort + || a.temperature !== b.temperature + || a.maxTokens !== b.maxTokens) + return false; + if (a.stop === undefined || b.stop === undefined) + return a.stop === b.stop; + return a.stop.length === b.stop.length && a.stop.every((s, i) => s === b.stop?.[i]); +} +/** + * Mark one exact request object as assembled by dsh-agent-loop. + * @param request - loop-owned request envelope before LLM dispatch. + * @returns the same request object marked as created by the process-local agent loop. + */ +export function markAgentLoopRequest(request) { + AGENT_LOOP_REQUESTS.add(request); + return request; +} +/** + * Test whether the exact request object was assembled by dsh-agent-loop. + * @param request - request envelope observed at the LLM waterfall. + * @returns whether {@link markAgentLoopRequest} recorded this object. + */ +export function isAgentLoopRequest(request) { + return AGENT_LOOP_REQUESTS.has(request); +} +/** + * Deep-freeze a value in place with an iterative traversal, guarding cycles, + * so later mutation throws without imposing a JavaScript call-stack depth cap. + * {@link AbortSignal} objects are deliberately skipped because they are the + * request's live cancellation channel and freezing them breaks abort. + * @param value - the value to freeze in place. + * @returns the same value, frozen. + */ +export function deepFreeze(value) { + const seen = new WeakSet(); + const pending = [{ kind: 'visit', node: value }]; + while (pending.length > 0) { + const task = pending.pop(); + /* v8 ignore next -- the loop condition guarantees one pending task. */ + if (task === undefined) + continue; + if (task.kind === 'property') { + pending.push({ kind: 'visit', node: task.source[task.key] }); + continue; + } + const node = task.node; + if (node === null || typeof node !== 'object') + continue; + if (node instanceof AbortSignal) + continue; + if (seen.has(node)) + continue; + seen.add(node); + Object.freeze(node); + const keys = Object.keys(node); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) + continue; + pending.push({ kind: 'property', source: node, key }); + } + } + return value; +} +//# sourceMappingURL=call-config.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/content.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/content.d.ts new file mode 100644 index 0000000..b9f5187 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/content.d.ts @@ -0,0 +1,12 @@ +/** Content-block structure helpers. @module @deepseek-ai/dsh-llm/content */ +import type { ContentBlock } from './types.ts'; +/** + * True when typed model content contains an image block, walking nested + * tool-result content. This is the one recursive image walk shared by every + * image policy (capability gating, text-only serialization, compaction + * survey), so a consumer cannot silently diverge on nesting depth. + * @param content - typed model content blocks. + * @returns whether any nested block is an image. + */ +export declare function contentHasImage(content: readonly ContentBlock[]): boolean; +//# sourceMappingURL=content.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/content.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/content.js new file mode 100644 index 0000000..1c057ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/content.js @@ -0,0 +1,14 @@ +/** Content-block structure helpers. @module @deepseek-ai/dsh-llm/content */ +/** + * True when typed model content contains an image block, walking nested + * tool-result content. This is the one recursive image walk shared by every + * image policy (capability gating, text-only serialization, compaction + * survey), so a consumer cannot silently diverge on nesting depth. + * @param content - typed model content blocks. + * @returns whether any nested block is an image. + */ +export function contentHasImage(content) { + return content.some(block => block.type === 'image' + || (block.type === 'tool-result' && contentHasImage(block.content))); +} +//# sourceMappingURL=content.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/error.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/error.d.ts new file mode 100644 index 0000000..7f522bd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/error.d.ts @@ -0,0 +1,73 @@ +/** + * Harness error base with a stable machine-routable code and chained cause. + * Package errors extend it so tool results and replay can retain failure class. + * @module @deepseek-ai/dsh-llm/error + */ +/** + * Base class for all harness errors. Carries a `code` (stable, programmatic — + * e.g. `NO_ADAPTER`, `INVALID_ARGS`, `INVARIANT`) distinct from the + * human-readable `message`, and supports `cause` chaining via the standard + * `ErrorOptions`. `name` defaults to the subclass constructor name. + */ +export declare class HarnessError extends Error { + /** Stable machine-routable failure class (e.g. `RATE_LIMIT`); route on this, never by parsing `message`. */ + readonly code: string; + constructor(message: string, code: string, options?: ErrorOptions); +} +/** Canonical provider-neutral code for a model request rejected because its context window was exceeded. */ +export declare const CONTEXT_WINDOW_EXCEEDED_CODE = "CONTEXT_WINDOW_EXCEEDED"; +/** Canonical provider-neutral code for an exhausted account quota or balance. */ +export declare const QUOTA_EXCEEDED_CODE = "QUOTA"; +/** + * Canonical provider-neutral code for a response that completed normally but + * carried no content blocks at all. Providers occasionally emit a degenerate + * completion (a terminal stop with zero output); adapters classify it as this + * failure instead of yielding an empty assistant message, because an empty + * message silently ends the turn with nothing for the user or the loop to act + * on. The attempt produced nothing durable, so retry policy treats it as safe + * to repeat. + */ +export declare const EMPTY_RESPONSE_CODE = "EMPTY_RESPONSE"; +/** + * Canonical provider-neutral code for a credential that was supplied but + * cannot be used — malformed rather than absent. Distinct from + * `MISSING_CREDENTIAL` because the fix differs: correct the stored value + * rather than supply one. Deliberately outside the default retryable set — + * a malformed credential fails identically on every attempt. + */ +export declare const INVALID_CREDENTIAL_CODE = "INVALID_CREDENTIAL"; +/** + * Recognize the context-overflow wording used by OpenAI-compatible providers + * and library adapters. Adapters pass all available provider code, type, and + * message text so both thrown and in-band delivery styles share one classifier. + * @param detail - provider error code/type/message text joined into one string. + * @returns true when the detail identifies a request exceeding the model context window. + */ +export declare function isContextWindowExceededError(detail: string): boolean; +/** + * Recognize provider wording that identifies an exhausted account quota rather + * than a transient request-rate limit. + * @param detail - provider error code/type/message text joined into one string. + * @returns true only for terminal quota, balance, credit, budget, or usage-limit wording. + */ +export declare function isQuotaExceededError(detail: string): boolean; +/** + * Render a thrown value with its full `cause` chain and AggregateError + * members, so transport wrappers like undici's `TypeError: fetch failed` + * surface the underlying failure instead of masking it. Plain structured + * failures render their own data-backed `message`. Diagnostic-surface + * rendering only (messages, notices, logs) — never parse the result; route on + * {@link HarnessError.code}. + * @param value - the caught value (`unknown` in catch clauses). + * @returns the outermost message first, each cause appended with `: ` (skipped + * when it repeats the wrapper message verbatim), and AggregateError members + * bracketed and `; `-joined. + */ +export declare function errorChain(value: unknown): string; +/** + * Narrow an arbitrary thrown value to a HarnessError (for `instanceof` at runtime boundaries). + * @param value - the caught value (`unknown` in catch clauses). + * @returns true only for real instances; duck-typed or cross-realm errors do not narrow. + */ +export declare function isHarnessError(value: unknown): value is HarnessError; +//# sourceMappingURL=error.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/error.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/error.js new file mode 100644 index 0000000..5a78c0f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/error.js @@ -0,0 +1,145 @@ +/** + * Harness error base with a stable machine-routable code and chained cause. + * Package errors extend it so tool results and replay can retain failure class. + * @module @deepseek-ai/dsh-llm/error + */ +/** + * Base class for all harness errors. Carries a `code` (stable, programmatic — + * e.g. `NO_ADAPTER`, `INVALID_ARGS`, `INVARIANT`) distinct from the + * human-readable `message`, and supports `cause` chaining via the standard + * `ErrorOptions`. `name` defaults to the subclass constructor name. + */ +export class HarnessError extends Error { + /** Stable machine-routable failure class (e.g. `RATE_LIMIT`); route on this, never by parsing `message`. */ + code; + constructor(message, code, options) { + super(message, options); + this.code = code; + this.name = new.target.name; + } +} +/** Canonical provider-neutral code for a model request rejected because its context window was exceeded. */ +export const CONTEXT_WINDOW_EXCEEDED_CODE = 'CONTEXT_WINDOW_EXCEEDED'; +/** Canonical provider-neutral code for an exhausted account quota or balance. */ +export const QUOTA_EXCEEDED_CODE = 'QUOTA'; +/** + * Canonical provider-neutral code for a response that completed normally but + * carried no content blocks at all. Providers occasionally emit a degenerate + * completion (a terminal stop with zero output); adapters classify it as this + * failure instead of yielding an empty assistant message, because an empty + * message silently ends the turn with nothing for the user or the loop to act + * on. The attempt produced nothing durable, so retry policy treats it as safe + * to repeat. + */ +export const EMPTY_RESPONSE_CODE = 'EMPTY_RESPONSE'; +/** + * Canonical provider-neutral code for a credential that was supplied but + * cannot be used — malformed rather than absent. Distinct from + * `MISSING_CREDENTIAL` because the fix differs: correct the stored value + * rather than supply one. Deliberately outside the default retryable set — + * a malformed credential fails identically on every attempt. + */ +export const INVALID_CREDENTIAL_CODE = 'INVALID_CREDENTIAL'; +/** Structured codes and plain phrases that explicitly name a context bound being exceeded. */ +const STRUCTURED_CONTEXT_OVERFLOW = new RegExp(String.raw `(?:^|[^a-z0-9])context[\s_-](?:length|window)[\s_-]` + + String.raw `(?:exceed(?:ed|s)?|overflow(?:ed)?|limit[\s_-]exceeded)(?:$|[^a-z0-9])`, 'i'); +/** Request-size wording that ties "too large" directly to model context capacity. */ +const TOO_LARGE_FOR_CONTEXT = new RegExp(String.raw `\b(?:request|prompt|input|messages?)\s+(?:is\s+|are\s+)?` + + String.raw `too\s+(?:large|long)\s+for\s+(?:(?:this|the)\s+)?` + + String.raw `(?:model(?:'s)?\s+)?context(?:\s+window)?\b`, 'i'); +/** "Exceeds" wording is safe only when its object is explicitly the model context. */ +const EXCEEDS_MODEL_CONTEXT = new RegExp(String.raw `\b(?:input|prompt|request|messages?)\b.{0,40}` + + String.raw `\b(?:exceed(?:s|ed)?|overflows?|is\s+larger\s+than)\b.{0,40}` + + String.raw `\b(?:the\s+)?(?:model(?:'s)?\s+)?context(?:\s+(?:length|window))?\b`, 'i'); +/** + * Recognize the context-overflow wording used by OpenAI-compatible providers + * and library adapters. Adapters pass all available provider code, type, and + * message text so both thrown and in-band delivery styles share one classifier. + * @param detail - provider error code/type/message text joined into one string. + * @returns true when the detail identifies a request exceeding the model context window. + */ +export function isContextWindowExceededError(detail) { + return STRUCTURED_CONTEXT_OVERFLOW.test(detail) + || /\b(?:maximum|max)(?:\s+(?:allowed|supported))?\s+context\s+(?:length|window)\b/i.test(detail) + || TOO_LARGE_FOR_CONTEXT.test(detail) + || /\b(?:input|prompt|request)\s+(?:is\s+)?too\s+(?:long|large)\s+for\s+(?:this|the)\s+model\b/i.test(detail) + || EXCEEDS_MODEL_CONTEXT.test(detail); +} +/** + * Recognize provider wording that identifies an exhausted account quota rather + * than a transient request-rate limit. + * @param detail - provider error code/type/message text joined into one string. + * @returns true only for terminal quota, balance, credit, budget, or usage-limit wording. + */ +export function isQuotaExceededError(detail) { + return /\binsufficient[\s_-]+(?:quota|balance|credits?)\b/i.test(detail) + || /\b(?:quota|usage[\s_-]+limit)[\s_-]+(?:exceeded|exhausted|reached)\b/i.test(detail) + || /\bexceed(?:ed|s)?[\s_-]+(?:(?:your|the)[\s_-]+)?(?:current[\s_-]+)?quota\b/i.test(detail) + || /\b(?:balance|credits?)[\s_-]+(?:exhausted|depleted)\b/i.test(detail) + || /\bout[\s_-]+of[\s_-]+(?:credits?|budget)\b/i.test(detail); +} +/** + * Render a thrown value with its full `cause` chain and AggregateError + * members, so transport wrappers like undici's `TypeError: fetch failed` + * surface the underlying failure instead of masking it. Plain structured + * failures render their own data-backed `message`. Diagnostic-surface + * rendering only (messages, notices, logs) — never parse the result; route on + * {@link HarnessError.code}. + * @param value - the caught value (`unknown` in catch clauses). + * @returns the outermost message first, each cause appended with `: ` (skipped + * when it repeats the wrapper message verbatim), and AggregateError members + * bracketed and `; `-joined. + */ +export function errorChain(value) { + // Tracks the active recursion path (entries removed on exit), so only true + // cycles are flagged and a diamond-shared cause still renders in full. + const path = new Set(); + const render = (current) => { + if (path.has(current)) + return ''; + path.add(current); + try { + if (!(current instanceof Error)) { + if (typeof current === 'object' && current !== null) { + const descriptor = Object.getOwnPropertyDescriptor(current, 'message'); + if (descriptor !== undefined && 'value' in descriptor && typeof descriptor.value === 'string') { + return descriptor.value; + } + } + return String(current); + } + const message = current.message === '' ? current.name : current.message; + const members = current instanceof AggregateError && current.errors.length > 0 + ? ` [${current.errors.map(render).join('; ')}]` + : ''; + const causeText = current.cause === undefined || current.cause === null + ? '' + : render(current.cause); + // Wrappers like `new HarnessError(String(value), code, { cause: value })` + // repeat their cause verbatim; rendering it again would only add noise. + const cause = causeText === '' || causeText === message ? '' : `: ${causeText}`; + return `${message}${members}${cause}`; + } + catch { + // Only hostile coercion or hostile accessors (a throwing toString / + // Symbol.toPrimitive on a non-Error, or a throwing message/name/cause/ + // errors getter on an Error subclass): this renderer feeds UI notices + // and logs, so nothing may escape. Inner frames catch their own throws, + // so only the hostile node collapses, not the whole chain. + return ''; + } + finally { + path.delete(current); + } + }; + return render(value); +} +/** + * Narrow an arbitrary thrown value to a HarnessError (for `instanceof` at runtime boundaries). + * @param value - the caught value (`unknown` in catch clauses). + * @returns true only for real instances; duck-typed or cross-realm errors do not narrow. + */ +export function isHarnessError(value) { + return value instanceof HarnessError; +} +//# sourceMappingURL=error.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/index.d.ts new file mode 100644 index 0000000..9692be1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/index.d.ts @@ -0,0 +1,341 @@ +/** + * LLM service: adapter registry with a waterfall-interceptable streaming call + * API. Exports the `LlmRuntime` default, the abstract `LlmAdapter` for + * provider backends, and `BlockAssembler` for chunk assembly. + * + * @module @deepseek-ai/dsh-llm + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { GenerateOptions, LlmConfigurableProvider, LlmDiscoveredModel, LlmFailure, LlmModelContext, LlmModelDiscoveryRequest, LlmModelInfo, LlmResolvedModelInfo, LlmProviderInfo, StreamChunk } from './types.ts'; +import type { ResolvedRetryPolicy } from './retry-policy.ts'; +import type { ProviderRequestId } from './brand.ts'; +import type { LlmCallConfig, LlmCallConfigAdapterDefaults } from './call-config.ts'; +import { HarnessError } from './error.ts'; +export * from './attribution.ts'; +export * from './brand.ts'; +export * from './never.ts'; +export * from './error.ts'; +export * from './api-key.ts'; +export * from './types.ts'; +export * from './content.ts'; +export * from './message.ts'; +export * from './retry-policy.ts'; +export { BlockAssembler } from './assembler.ts'; +export { callConfigEquals, deepFreeze, isAgentLoopRequest, markAgentLoopRequest } from './call-config.ts'; +export type { LlmCallConfig, LlmCallConfigAdapterDefaults } from './call-config.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + llm: LlmRuntime; + } + interface Events { + /** + * Waterfall around every streaming model call (retry, replay, routing). + * Bound to the {@link LlmRuntime}; call `next()` to reach the resolved + * adapter's stream, or yield your own chunks to short-circuit. + * @param options - the full request. A LOOP-built request carries the + * process-local {@link markAgentLoopRequest} identity and arrives deep-frozen + * (mutation throws): its content is a pure function of the session log (the + * reconstructability Agent Note), so listeners read it, never rewrite it. + * Hand-built calls do not carry that marker; their messages already obey + * the immutable creation contract. + * @mode waterfall + */ + 'llm/stream'(this: LlmRuntime, options: GenerateOptions, next: () => AsyncIterable): AsyncIterable; + } +} +/** Structured provider facts and cause accepted by {@link LlmError}. */ +export interface LlmErrorOptions extends ErrorOptions { + /** Valid HTTP status observed at the provider boundary. */ + status?: number; + /** Positive finite provider-requested delay in milliseconds. */ + providerRetryAfterMs?: number; + /** Non-empty opaque provider request id. */ + requestId?: ProviderRequestId; +} +/** + * Typed error for LLM-related failures. Extends {@link HarnessError}, so the + * `code` string (e.g. `AUTH`, `RATE_LIMIT`, `NO_ADAPTER`) is shared taxonomy. + */ +export declare class LlmError extends HarnessError { + /** Serializable facts retained beside this live Error. */ + readonly failure: LlmFailure; + /** + * @param message - non-empty human-readable failure summary. + * @param code - non-empty stable provider-neutral machine code. + * @param options - optional cause and validated serializable provider facts. + */ + constructor(message: string, code: string, options?: LlmErrorOptions); +} +/** + * Accept one supplied credential, or refuse it as unusable. + * + * A stored key arrives from the credentials seam, a `.env` line, or a shell + * export, all of which pick up surrounding whitespace, so trimming is silent. + * Anything else fails here rather than inside `fetch`, whose ByteString + * refusal names a UTF-16 code point instead of the setting to change. The key + * never enters the message: `ref` names where to fix it, and echoing any part + * of a secret into a log or a UI is the failure this diagnosis avoids. + * + * Lives beside {@link LlmError} rather than in `./api-key.ts` so the predicate + * module stays dependency-free; both adapters share this one diagnosis instead + * of keeping near-identical local copies. + * @param raw - the credential exactly as supplied. + * @param pkg - the refusing package name, prefixed to the diagnostic. + * @param ref - the credential reference the value resolved through. + * @returns the trimmed, usable key. + */ +export declare function assertUsableApiKey(raw: string, pkg: string, ref: string): string; +/** One model call whose config and adapter registration were resolved together. */ +export interface PreparedLlmCall { + /** Detached, deep-frozen config with any adapter-owned default materialized. */ + readonly config: LlmCallConfig; + /** Immutable retry policy captured with the adapter registration. */ + readonly retryPolicy: ResolvedRetryPolicy; + /** Detached context metadata resolved with the registration-bound call. */ + readonly context?: LlmModelContext; + /** Config fields materialized by the captured adapter rather than proposed by the caller. */ + readonly adapterDefaults: LlmCallConfigAdapterDefaults; + /** + * Dispatch this call once through the registration captured during + * preparation. The request's call-config fields must match {@link config}; + * reuse or mismatch fails with `INVALID_PREPARED_CALL`. + * @param options - fully assembled request carrying the prepared config. + * @returns the chunk stream, including the `llm/stream` waterfall. + */ + stream(options: GenerateOptions): AsyncIterable; +} +/** + * Provider-wire adapter for the harness message and stream vocabulary. Register implementations + * with `ctx.llm.registerAdapter(providers, adapter)`. Every provider HTTP request must include + * `attributionHeaders()`; prove the headers are added in the wire request or library header hook. The direct-fetch + * DeepSeek and library-backed pi-ai adapters meet this contract through different internals. + */ +export declare abstract class LlmAdapter { + /** + * Describe one provider route owned by this adapter. + * @param provider - a route passed to `registerAdapter()` for this instance. + * @returns detached display metadata whose id must equal `provider`. + */ + providerInfo(provider: string): LlmProviderInfo; + /** + * Return the provider-owned retry policy captured with this route. + * @param _provider - a route passed to `registerAdapter()` for this instance. + * @returns a resolved policy, or `undefined` to use the normal defaults. + */ + providerRetryPolicy(_provider: string): ResolvedRetryPolicy | undefined; + /** + * List models this adapter can currently advertise for one owned provider. + * The result is advisory: an adapter may accept unlisted model ids, and + * consumers must not turn absence into request rejection. + * @param _provider - one provider route owned by this adapter. + * @returns discoverable models in adapter-preferred order. + */ + listModels(_provider: string): Promise; + /** + * Resolve all metadata available for one exact model. This query is + * independent of the advisory catalog and does not validate request routing. + * @param provider - one provider route owned by this adapter. + * @param model - exact model id passed to {@link GenerateOptions.model}. + * @param _signal - cancellation for this exact-model lookup; asynchronous + * implementations must settle promptly after it aborts. + * @returns provider/model identity plus any context, call-default, and reasoning metadata. + */ + resolveModel(provider: string, model: string, _signal?: AbortSignal): Promise; + /** + * Stream one model call as raw chunks. The only required method. + * @param options - the fully-assembled request; implementations must honor `options.signal`. + * @returns the chunk stream, obeying the adapter contract documented on `StreamChunk`. + */ + abstract stream(options: GenerateOptions): AsyncIterable; +} +/** + * What {@link LlmRuntime.registerAdapter} returns: the disposer, plus an + * atomic route replacement for the same adapter instance. + */ +export interface AdapterRegistrationHandle { + /** Release every route this registration currently holds. */ + (): void; + /** + * Replace this registration's routes with `providers`, keeping the same + * adapter instance. The candidate set is validated in full first — a + * conflict with another adapter, an invalid name, or bad provider metadata + * throws and leaves the current routes untouched — and the swap itself is + * one synchronous section, so no request can observe a gap. An empty array + * is legal here (a settings section that emptied holds zero routes while + * staying registered), unlike an empty initial registration. + * + * Throws `LlmError` with code `REGISTRATION_DISPOSED` once the registration + * has been released: its routes are gone and its disposer has already run, + * so anything registered afterwards would have no owner left to release it. + * @param providers - the complete next route set for this registration. + */ + replace(providers: string[]): void; +} +/** + * A live configurable-provider registration, disposable and atomically + * replaceable — the directory counterpart of {@link AdapterRegistrationHandle}. + */ +export interface DirectoryRegistrationHandle { + /** Withdraw every entry this registration currently holds. */ + (): void; + /** + * Replace this registration's entries with `entries`. The candidate set is + * validated in full first — an entry another registration already declares, + * a duplicate within the set, or invalid metadata throws and leaves the + * current entries untouched — and the swap is one synchronous section, so no + * reader observes a gap. An empty array is legal here, unlike an empty + * initial registration. + * + * Throws `LlmError` with code `REGISTRATION_DISPOSED` once the registration + * has been disposed. + */ + replace(entries: readonly LlmConfigurableProvider[]): void; +} +/** + * The abstract `llm` service: an adapter registry plus a streaming model-call + * API, interceptable via the `llm/stream` waterfall. + */ +export declare class LlmRuntime extends Service { + private adapters; + private directory; + private discoveries; + constructor(ctx: Context); + /** Notify topology observers without letting one broken listener veto the commit. */ + private emitAdaptersUpdated; + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + private warnAdaptersListenerFailure; + /** + * Register an adapter for the given provider routes. Throws `LlmError` with code + * `DUPLICATE_ADAPTER` if any provider already has an adapter (all-or-nothing). + * Disposed with the fiber. + * @param providers - every provider route this adapter should serve. + * @param adapter - the adapter that streams calls for those providers. + * @returns the disposer, carrying {@link AdapterRegistrationHandle.replace}. + */ + registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHandle; + /** + * Validate one candidate route set for `adapter`, treating routes this + * registration already holds as available. Nothing is mutated: a rejected + * candidate leaves the registry exactly as it was. + */ + private prepareRoutes; + /** + * Swap this registration's routes for the prepared ones in one synchronous + * section, so no observer can see the registry between the release and the + * re-registration. The route set's one mutation point is also where + * `llm/adapters-updated` is published, so a `replace` announces itself + * exactly like a first registration. + */ + private commitRoutes; + /** + * Describe provider routes with a registered adapter. + * @returns detached provider metadata in registration order. + */ + listProviders(): LlmProviderInfo[]; + /** + * Declare provider routes an adapter plugin can activate through + * configuration. Registration is all-or-nothing: an empty list, invalid + * entry, or a provider already declared by any registration throws + * `LlmError` without registering the rest. Disposed with the fiber. + * @param entries - every configurable provider this plugin owns. + * @returns a handle that withdraws all of them, and can atomically replace them. + */ + registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): DirectoryRegistrationHandle; + /** + * List every declared configurable provider, registered or dormant. + * @returns detached directory entries in declaration order. + */ + listConfigurableProviders(): LlmConfigurableProvider[]; + /** + * Offer to interrogate provider endpoints on behalf of the settings + * namespace this plugin owns. The namespace is the key because that is what + * a configuration surface already holds from the configurable-provider + * directory, and because a provider being *added* has no route to name yet. + * Disposed with the fiber. + * @param settingsNs - the namespace whose profiles this discovery serves. + * @param discover - interrogates one endpoint; must honor `request.signal`. + * @returns the disposer that withdraws the offer. + */ + registerModelDiscovery(settingsNs: string, discover: (request: LlmModelDiscoveryRequest) => Promise): () => void; + /** + * Interrogate one provider endpoint for the models it advertises. The + * request describes a draft, not a stored route, so nothing here reads or + * writes settings or credentials — the caller owns both, and the reply is + * candidate metadata a surface may offer for adoption. + * @param settingsNs - namespace whose registered discovery serves this draft. + * @param request - the endpoint, protocol, and one-shot credential to use. + * @returns the advertised models, deduplicated in endpoint order. + */ + discoverModels(settingsNs: string, request: LlmModelDiscoveryRequest): Promise; + /** + * Resolve the retry policy captured when one provider route was registered. + * @param provider - registered provider route to inspect. + * @returns the provider-owned policy, with normal defaults already resolved. + */ + providerRetryPolicy(provider: string): ResolvedRetryPolicy; + /** Detach typed adapter-owned modality metadata. */ + private detachedModalities; + /** + * Discover models advertised by one registered provider. Catalog membership + * is advisory and never changes routing or request validation. + * @param provider - registered provider route to inspect. + * @returns detached model metadata in adapter-preferred order. + */ + listModels(provider: string): Promise; + /** + * Resolve and validate all metadata from the adapter that owns one exact + * route. The result is detached from adapter-owned objects; catalog + * membership remains advisory and does not control request routing. + * @param provider - registered provider route to inspect. + * @param model - exact model id passed to the adapter. + * @param signal - optional cancellation for adapter-owned asynchronous lookup. + * @returns exact model identity plus available context and reasoning metadata. + */ + resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise; + private resolveModelInfoFor; + /** + * Validate a conversation call config against its exact model capability and + * materialize adapter-configured defaults. Unsupported explicit efforts + * reject before provider I/O; no clamping or aliasing is performed. This + * standalone query does not bind a later dispatch; use {@link prepareCall} + * when logging and streaming must share one adapter registration. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a detached config only when a default must be materialized. + */ + resolveCallConfig(config: LlmCallConfig, signal?: AbortSignal): Promise; + private resolveCallFor; + /** + * Resolve one call under its current adapter registration. The returned + * one-shot handle keeps that registration across header logging and dispatch, + * so HMR cannot combine one adapter's capability result with another adapter. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a prepared config and its registration-bound stream entry point. + */ + prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise; + private registration; + /** Remove replay state whose historical route is owned by another adapter. */ + private forAdapter; + /** + * Final adapter boundary. Adapter selection, dispatch, iterator construction, + * and iteration failures become one terminal failure chunk. Middleware and + * downstream consumer failures remain thrown plugin or consumer errors. + */ + private adapterStream; + /** + * Stream one model call as raw chunks (token-level deltas). Replay state is + * retained only when the same adapter instance owns its historical provider + * and the target provider. Final adapter selection remains fixed through + * asynchronous exact-model resolution and dispatch. Adapter selection, + * dispatch, and iteration failures become terminal `error` or `aborted` + * finish chunks; middleware, nested-call, cleanup, and consumer failures + * remain thrown. + * @param options - the full request; `options.provider` selects the adapter. + * @returns the chunk stream, possibly wrapped by `llm/stream` listeners. + */ + stream(options: GenerateOptions): AsyncIterable; + private streamWithRegistration; +} +export default LlmRuntime; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/index.js new file mode 100644 index 0000000..584c7eb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/index.js @@ -0,0 +1,730 @@ +/** + * LLM service: adapter registry with a waterfall-interceptable streaming call + * API. Exports the `LlmRuntime` default, the abstract `LlmAdapter` for + * provider backends, and `BlockAssembler` for chunk assembly. + * + * @module @deepseek-ai/dsh-llm + */ +import { Service } from '@deepseek-ai/cordis'; +import { freezeMessage } from "./message.js"; +import { resolveRetryPolicy } from "./retry-policy.js"; +import { callConfigEquals, deepFreeze } from "./call-config.js"; +import { HarnessError, INVALID_CREDENTIAL_CODE } from "./error.js"; +import { normalizeLlmFailure } from "./adapter-failure.js"; +import { normalizeApiKey } from "./api-key.js"; +export * from "./attribution.js"; +export * from "./brand.js"; +export * from "./never.js"; +export * from "./error.js"; +export * from "./api-key.js"; +export * from "./types.js"; +export * from "./content.js"; +export * from "./message.js"; +export * from "./retry-policy.js"; +export { BlockAssembler } from "./assembler.js"; +export { callConfigEquals, deepFreeze, isAgentLoopRequest, markAgentLoopRequest } from "./call-config.js"; +/** + * Typed error for LLM-related failures. Extends {@link HarnessError}, so the + * `code` string (e.g. `AUTH`, `RATE_LIMIT`, `NO_ADAPTER`) is shared taxonomy. + */ +export class LlmError extends HarnessError { + /** Serializable facts retained beside this live Error. */ + failure; + /** + * @param message - non-empty human-readable failure summary. + * @param code - non-empty stable provider-neutral machine code. + * @param options - optional cause and validated serializable provider facts. + */ + constructor(message, code, options) { + if (typeof message !== 'string' || message.length === 0) + throw new Error('LlmError message must be a non-empty string'); + if (typeof code !== 'string' || code.length === 0) + throw new Error('LlmError code must be a non-empty string'); + if (options?.status !== undefined + && (!Number.isInteger(options.status) || options.status < 100 || options.status > 599)) { + throw new Error('LlmError status must be an integer from 100 through 599'); + } + if (options?.providerRetryAfterMs !== undefined + && (!Number.isFinite(options.providerRetryAfterMs) || options.providerRetryAfterMs <= 0)) { + throw new Error('LlmError providerRetryAfterMs must be a positive finite number'); + } + if (options?.requestId !== undefined + && (typeof options.requestId !== 'string' || options.requestId.length === 0)) { + throw new Error('LlmError requestId must be a non-empty string'); + } + super(message, code, options); + this.name = 'LlmError'; + this.failure = Object.freeze({ + message, + code, + ...options?.status === undefined ? {} : { status: options.status }, + ...options?.providerRetryAfterMs === undefined ? {} : { providerRetryAfterMs: options.providerRetryAfterMs }, + ...options?.requestId === undefined ? {} : { requestId: options.requestId }, + }); + } +} +/** + * Accept one supplied credential, or refuse it as unusable. + * + * A stored key arrives from the credentials seam, a `.env` line, or a shell + * export, all of which pick up surrounding whitespace, so trimming is silent. + * Anything else fails here rather than inside `fetch`, whose ByteString + * refusal names a UTF-16 code point instead of the setting to change. The key + * never enters the message: `ref` names where to fix it, and echoing any part + * of a secret into a log or a UI is the failure this diagnosis avoids. + * + * Lives beside {@link LlmError} rather than in `./api-key.ts` so the predicate + * module stays dependency-free; both adapters share this one diagnosis instead + * of keeping near-identical local copies. + * @param raw - the credential exactly as supplied. + * @param pkg - the refusing package name, prefixed to the diagnostic. + * @param ref - the credential reference the value resolved through. + * @returns the trimmed, usable key. + */ +export function assertUsableApiKey(raw, pkg, ref) { + const checked = normalizeApiKey(raw); + if (checked.ok) + return checked.value; + // The Models page is named as the writer it usually is, not as the only one: + // the same value can arrive from a hand-edited .env or a shell export in a + // composition that mounts no credentials seam at all, where directing the + // user to a page that deployment does not serve would be a dead end. + throw new LlmError(checked.reason === 'empty' + ? `${pkg}: the API key resolved from ${ref} is blank; set ${ref} to the raw key` + + ' (the web Models page writes it) or export it in the launching environment' + : `${pkg}: the API key resolved from ${ref} contains characters no HTTP header can carry;` + + ` set ${ref} to the raw key alone (the web Models page writes it)`, INVALID_CREDENTIAL_CODE); +} +/** + * Provider-wire adapter for the harness message and stream vocabulary. Register implementations + * with `ctx.llm.registerAdapter(providers, adapter)`. Every provider HTTP request must include + * `attributionHeaders()`; prove the headers are added in the wire request or library header hook. The direct-fetch + * DeepSeek and library-backed pi-ai adapters meet this contract through different internals. + */ +export class LlmAdapter { + /** + * Describe one provider route owned by this adapter. + * @param provider - a route passed to `registerAdapter()` for this instance. + * @returns detached display metadata whose id must equal `provider`. + */ + providerInfo(provider) { + return { id: provider, name: provider }; + } + /** + * Return the provider-owned retry policy captured with this route. + * @param _provider - a route passed to `registerAdapter()` for this instance. + * @returns a resolved policy, or `undefined` to use the normal defaults. + */ + providerRetryPolicy(_provider) { + return undefined; + } + /** + * List models this adapter can currently advertise for one owned provider. + * The result is advisory: an adapter may accept unlisted model ids, and + * consumers must not turn absence into request rejection. + * @param _provider - one provider route owned by this adapter. + * @returns discoverable models in adapter-preferred order. + */ + listModels(_provider) { + return Promise.resolve([]); + } + /** + * Resolve all metadata available for one exact model. This query is + * independent of the advisory catalog and does not validate request routing. + * @param provider - one provider route owned by this adapter. + * @param model - exact model id passed to {@link GenerateOptions.model}. + * @param _signal - cancellation for this exact-model lookup; asynchronous + * implementations must settle promptly after it aborts. + * @returns provider/model identity plus any context, call-default, and reasoning metadata. + */ + resolveModel(provider, model, _signal) { + return Promise.resolve({ provider, id: model, name: model }); + } +} +/** + * The abstract `llm` service: an adapter registry plus a streaming model-call + * API, interceptable via the `llm/stream` waterfall. + */ +export class LlmRuntime extends Service { + adapters = new Map(); + directory = new Map(); + discoveries = new Map(); + constructor(ctx) { + super(ctx, 'llm'); + } + /** Notify topology observers without letting one broken listener veto the commit. */ + emitAdaptersUpdated() { + // Cordis emit uses Array.map: one synchronous throw starves later + // listeners. Registry notifications are non-vetoing, so contain each + // callback independently; INVARIANT-coded failures still surface. + let invariantFailure; + for (const listener of this.ctx.events.dispatch('emit', ['llm/adapters-updated'])) { + try { + const returned = listener(); + if (returned != null && typeof returned.then === 'function') { + // An emit listener may still be an async function; its rejection + // cannot reach the synchronous INVARIANT rethrow below, so it is + // contained here instead of becoming an unhandled rejection. + void Promise.resolve(returned).then(undefined, (error) => { + this.warnAdaptersListenerFailure(error); + }); + } + } + catch (error) { + if (error?.code === 'INVARIANT') { + invariantFailure ??= error; + continue; + } + this.warnAdaptersListenerFailure(error); + } + } + if (invariantFailure !== undefined) + throw invariantFailure; + } + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnAdaptersListenerFailure(error) { + this.ctx.logger.warn('llm: an llm/adapters-updated listener failed'); + this.ctx.logger.warn(error); + } + /** + * Register an adapter for the given provider routes. Throws `LlmError` with code + * `DUPLICATE_ADAPTER` if any provider already has an adapter (all-or-nothing). + * Disposed with the fiber. + * @param providers - every provider route this adapter should serve. + * @param adapter - the adapter that streams calls for those providers. + * @returns the disposer, carrying {@link AdapterRegistrationHandle.replace}. + */ + registerAdapter(providers, adapter) { + // The routes this registration currently holds; `replace` rewrites it, and + // the disposer releases whatever it holds at disposal time. + const owned = new Set(); + // The disposer has run: `owned` being empty cannot say so on its own, + // because `replace([])` legally leaves a live registration holding none. + let released = false; + const dispose = this.ctx.effect(function* () { + if (providers.length === 0) + throw new LlmError('an adapter must register at least one provider', 'INVALID_ADAPTER'); + this.commitRoutes(owned, this.prepareRoutes(providers, adapter, owned)); + yield () => { + released = true; + for (const provider of owned) + this.adapters.delete(provider); + owned.clear(); + this.emitAdaptersUpdated(); + }; + }.bind(this), 'llm.registerAdapter()'); + // ctx.effect's disposer returns Promise; our disposer API is + // synchronous fire-and-forget — discard the (always-resolved) promise. + const handle = (() => void dispose()); + handle.replace = (next) => { + // Registering here would leak: the effect's disposer already ran, so + // nothing remains to release whatever this call would put in the map. + if (released) { + throw new LlmError('a disposed adapter registration cannot replace its routes', 'REGISTRATION_DISPOSED'); + } + this.commitRoutes(owned, this.prepareRoutes(next, adapter, owned)); + }; + return handle; + } + /** + * Validate one candidate route set for `adapter`, treating routes this + * registration already holds as available. Nothing is mutated: a rejected + * candidate leaves the registry exactly as it was. + */ + prepareRoutes(providers, adapter, owned) { + const unique = new Set(); + const registrations = []; + for (const provider of providers) { + if (provider.length === 0) + throw new LlmError('adapter provider names must be non-empty', 'INVALID_ADAPTER'); + if (unique.has(provider) || (this.adapters.has(provider) && !owned.has(provider))) { + throw new LlmError(`an adapter for provider "${provider}" is already registered`, 'DUPLICATE_ADAPTER'); + } + const info = adapter.providerInfo(provider); + if (typeof info.id !== 'string' || info.id !== provider || typeof info.name !== 'string' || info.name.length === 0) { + throw new LlmError(`adapter metadata for provider "${provider}" must preserve its id and have a non-empty name`, 'INVALID_ADAPTER'); + } + unique.add(provider); + const retryPolicy = adapter.providerRetryPolicy(provider) + ?? resolveRetryPolicy(undefined, `llm: provider "${provider}" retryPolicy`); + registrations.push({ + adapter, + provider: { id: info.id, name: info.name }, + retryPolicy, + }); + } + return registrations; + } + /** + * Swap this registration's routes for the prepared ones in one synchronous + * section, so no observer can see the registry between the release and the + * re-registration. The route set's one mutation point is also where + * `llm/adapters-updated` is published, so a `replace` announces itself + * exactly like a first registration. + */ + commitRoutes(owned, registrations) { + for (const provider of owned) + this.adapters.delete(provider); + owned.clear(); + for (const registration of registrations) { + this.adapters.set(registration.provider.id, registration); + owned.add(registration.provider.id); + } + this.emitAdaptersUpdated(); + } + /** + * Describe provider routes with a registered adapter. + * @returns detached provider metadata in registration order. + */ + listProviders() { + return [...this.adapters.values()].map(({ provider }) => ({ ...provider })); + } + /** + * Declare provider routes an adapter plugin can activate through + * configuration. Registration is all-or-nothing: an empty list, invalid + * entry, or a provider already declared by any registration throws + * `LlmError` without registering the rest. Disposed with the fiber. + * @param entries - every configurable provider this plugin owns. + * @returns a handle that withdraws all of them, and can atomically replace them. + */ + registerConfigurableProviders(entries) { + let held = []; + let disposed = false; + /** + * Validate a candidate set in full against everything this registration + * does not already hold, then publish it. Nothing is written until the + * whole set passes, so a refused candidate leaves the current entries in + * place — the property that makes `replace` a swap rather than a + * delete-then-add that can strand the directory empty. + */ + const commit = (candidates) => { + const detached = []; + const own = new Set(held.map(entry => entry.provider)); + for (const entry of candidates) { + if (entry.provider.length === 0 || entry.displayName.length === 0 || entry.settingsNs.length === 0) { + throw new LlmError('configurable providers need a non-empty provider, displayName, and settingsNs', 'INVALID_DIRECTORY'); + } + if (entry.settingsPath.some(segment => segment.length === 0)) { + throw new LlmError(`configurable provider "${entry.provider}" has an empty settingsPath segment`, 'INVALID_DIRECTORY'); + } + if ((this.directory.has(entry.provider) && !own.has(entry.provider)) + || detached.some(seen => seen.provider === entry.provider)) { + throw new LlmError(`configurable provider "${entry.provider}" is already declared`, 'DUPLICATE_DIRECTORY'); + } + detached.push({ ...entry, settingsPath: [...entry.settingsPath] }); + } + for (const entry of held) + this.directory.delete(entry.provider); + for (const entry of detached) + this.directory.set(entry.provider, entry); + held = detached; + this.emitAdaptersUpdated(); + }; + const dispose = this.ctx.effect(function* () { + if (entries.length === 0) { + throw new LlmError('a configurable-provider registration must declare at least one provider', 'INVALID_DIRECTORY'); + } + commit(entries); + yield () => { + disposed = true; + for (const entry of held) + this.directory.delete(entry.provider); + held = []; + this.emitAdaptersUpdated(); + }; + }.bind(this), 'llm.registerConfigurableProviders()'); + const handle = (() => void dispose()); + handle.replace = (next) => { + if (disposed) { + throw new LlmError('this configurable-provider registration was disposed', 'REGISTRATION_DISPOSED'); + } + commit(next); + }; + return handle; + } + /** + * List every declared configurable provider, registered or dormant. + * @returns detached directory entries in declaration order. + */ + listConfigurableProviders() { + return [...this.directory.values()].map(entry => ({ ...entry, settingsPath: [...entry.settingsPath] })); + } + /** + * Offer to interrogate provider endpoints on behalf of the settings + * namespace this plugin owns. The namespace is the key because that is what + * a configuration surface already holds from the configurable-provider + * directory, and because a provider being *added* has no route to name yet. + * Disposed with the fiber. + * @param settingsNs - the namespace whose profiles this discovery serves. + * @param discover - interrogates one endpoint; must honor `request.signal`. + * @returns the disposer that withdraws the offer. + */ + registerModelDiscovery(settingsNs, discover) { + const dispose = this.ctx.effect(function* () { + if (settingsNs.length === 0) { + throw new LlmError('model discovery needs a non-empty settings namespace', 'INVALID_DISCOVERY'); + } + if (this.discoveries.has(settingsNs)) { + throw new LlmError(`model discovery for "${settingsNs}" is already registered`, 'DUPLICATE_DISCOVERY'); + } + this.discoveries.set(settingsNs, discover); + yield () => { + this.discoveries.delete(settingsNs); + }; + }.bind(this), 'llm.registerModelDiscovery()'); + return () => void dispose(); + } + /** + * Interrogate one provider endpoint for the models it advertises. The + * request describes a draft, not a stored route, so nothing here reads or + * writes settings or credentials — the caller owns both, and the reply is + * candidate metadata a surface may offer for adoption. + * @param settingsNs - namespace whose registered discovery serves this draft. + * @param request - the endpoint, protocol, and one-shot credential to use. + * @returns the advertised models, deduplicated in endpoint order. + */ + async discoverModels(settingsNs, request) { + const discover = this.discoveries.get(settingsNs); + if (discover === undefined) { + throw new LlmError(`no model discovery is registered for "${settingsNs}"`, 'NO_DISCOVERY'); + } + // One of the two identifies what to describe: a route the adapter knows, or + // an endpoint to ask. Neither leaves nothing to answer about. + if ((request.provider ?? '').length === 0 && (request.baseURL ?? '').length === 0) { + throw new LlmError('model discovery needs a provider route or a baseURL', 'INVALID_DISCOVERY'); + } + const discovered = await discover(request); + const seen = new Set(); + const models = []; + for (const model of discovered) { + if (typeof model.id !== 'string' || model.id.length === 0 || seen.has(model.id)) + continue; + seen.add(model.id); + models.push({ + id: model.id, + ...model.name === undefined ? {} : { name: model.name }, + ...model.contextWindow === undefined ? {} : { contextWindow: model.contextWindow }, + ...model.maxTokens === undefined ? {} : { maxTokens: model.maxTokens }, + }); + } + return models; + } + /** + * Resolve the retry policy captured when one provider route was registered. + * @param provider - registered provider route to inspect. + * @returns the provider-owned policy, with normal defaults already resolved. + */ + providerRetryPolicy(provider) { + return this.registration(provider).retryPolicy; + } + /** Detach typed adapter-owned modality metadata. */ + detachedModalities(modalities) { + return modalities === undefined ? undefined : [...modalities]; + } + /** + * Discover models advertised by one registered provider. Catalog membership + * is advisory and never changes routing or request validation. + * @param provider - registered provider route to inspect. + * @returns detached model metadata in adapter-preferred order. + */ + async listModels(provider) { + const adapter = this.registration(provider).adapter; + const models = await adapter.listModels(provider); + const seen = new Set(); + return models.map((model) => { + if (typeof model.provider !== 'string' + || model.provider !== provider + || typeof model.id !== 'string' + || model.id.length === 0 + || typeof model.name !== 'string' + || model.name.length === 0 + || (model.description !== undefined && typeof model.description !== 'string') + || seen.has(model.id)) { + throw new LlmError(`adapter returned invalid or duplicate model metadata for provider "${provider}"`, 'INVALID_CATALOG'); + } + seen.add(model.id); + const inputModalities = this.detachedModalities(model.inputModalities); + return { + provider: model.provider, + id: model.id, + name: model.name, + ...model.description === undefined ? {} : { description: model.description }, + ...inputModalities === undefined ? {} : { inputModalities }, + }; + }); + } + /** + * Resolve and validate all metadata from the adapter that owns one exact + * route. The result is detached from adapter-owned objects; catalog + * membership remains advisory and does not control request routing. + * @param provider - registered provider route to inspect. + * @param model - exact model id passed to the adapter. + * @param signal - optional cancellation for adapter-owned asynchronous lookup. + * @returns exact model identity plus available context and reasoning metadata. + */ + async resolveModelInfo(provider, model, signal) { + return this.resolveModelInfoFor(this.registration(provider), model, signal); + } + async resolveModelInfoFor(registration, model, signal) { + const provider = registration.provider.id; + const resolved = await registration.adapter.resolveModel(provider, model, signal); + if (typeof resolved.provider !== 'string' + || resolved.provider !== provider + || typeof resolved.id !== 'string' + || resolved.id !== model + || typeof resolved.name !== 'string' + || resolved.name.length === 0 + || (resolved.description !== undefined && typeof resolved.description !== 'string')) { + throw new LlmError(`adapter returned invalid exact model metadata for provider "${provider}" model "${model}"`, 'INVALID_MODEL_INFO'); + } + const context = resolved.context; + if (context !== undefined && (!Number.isInteger(context.contextWindow) || context.contextWindow <= 0)) { + throw new LlmError(`adapter returned invalid context metadata for provider "${provider}" model "${model}"`, 'INVALID_MODEL_CONTEXT'); + } + // Capability metadata rides through: an explicit modality omission is + // negative capability downstream preflights act on (image admission). + const inputModalities = this.detachedModalities(resolved.inputModalities); + const defaultMaxTokens = resolved.defaultMaxTokens; + if (defaultMaxTokens !== undefined + && (!Number.isSafeInteger(defaultMaxTokens) || defaultMaxTokens <= 0)) { + throw new LlmError(`adapter returned invalid default maxTokens for provider "${provider}" model "${model}"`, 'INVALID_MODEL_MAX_TOKENS'); + } + const info = { + provider, + id: model, + name: resolved.name, + ...resolved.description === undefined ? {} : { description: resolved.description }, + ...inputModalities === undefined ? {} : { inputModalities }, + ...context === undefined ? {} : { context: { contextWindow: context.contextWindow } }, + ...defaultMaxTokens === undefined ? {} : { defaultMaxTokens }, + }; + const reasoning = resolved.reasoning; + if (reasoning === undefined) + return info; + if (reasoning.efforts.length === 0) { + throw new LlmError(`adapter returned invalid reasoning metadata for provider "${provider}" model "${model}"`, 'INVALID_MODEL_REASONING'); + } + const seen = new Set(); + const efforts = reasoning.efforts.map((effort) => { + if (typeof effort.id !== 'string' + || effort.id.length === 0 + || typeof effort.name !== 'string' + || effort.name.length === 0 + || (effort.description !== undefined && typeof effort.description !== 'string') + || seen.has(effort.id)) { + throw new LlmError(`adapter returned invalid or duplicate reasoning effort metadata for provider "${provider}" model "${model}"`, 'INVALID_MODEL_REASONING'); + } + seen.add(effort.id); + return { + id: effort.id, + name: effort.name, + ...effort.description === undefined ? {} : { description: effort.description }, + }; + }); + if (reasoning.defaultEffort !== undefined && !seen.has(reasoning.defaultEffort)) { + throw new LlmError(`adapter returned an unknown default reasoning effort for provider "${provider}" model "${model}"`, 'INVALID_MODEL_REASONING'); + } + return { + ...info, + reasoning: { + efforts, + ...reasoning.defaultEffort === undefined ? {} : { defaultEffort: reasoning.defaultEffort }, + }, + }; + } + /** + * Validate a conversation call config against its exact model capability and + * materialize adapter-configured defaults. Unsupported explicit efforts + * reject before provider I/O; no clamping or aliasing is performed. This + * standalone query does not bind a later dispatch; use {@link prepareCall} + * when logging and streaming must share one adapter registration. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a detached config only when a default must be materialized. + */ + async resolveCallConfig(config, signal) { + return (await this.resolveCallFor(this.registration(config.provider), config, signal)).config; + } + async resolveCallFor(registration, config, signal) { + const info = await this.resolveModelInfoFor(registration, config.model, signal); + const defaulted = config.maxTokens === undefined && info.defaultMaxTokens !== undefined + ? { ...config, maxTokens: info.defaultMaxTokens } + : config; + const reasoning = info.reasoning; + const requested = defaulted.reasoningEffort; + let resolvedConfig = defaulted; + if (reasoning === undefined) { + if (requested !== undefined) { + throw new LlmError(`provider "${config.provider}" model "${config.model}" does not support reasoning effort "${requested}"`, 'UNSUPPORTED_REASONING_EFFORT'); + } + } + else { + const effective = requested ?? reasoning.defaultEffort; + if (effective !== undefined) { + if (!reasoning.efforts.some(effort => effort.id === effective)) { + throw new LlmError(`provider "${config.provider}" model "${config.model}" does not support reasoning effort "${effective}"`, 'UNSUPPORTED_REASONING_EFFORT'); + } + if (requested !== effective) + resolvedConfig = { ...defaulted, reasoningEffort: effective }; + } + } + return { + config: resolvedConfig, + ...info.context === undefined ? {} : { context: info.context }, + }; + } + /** + * Resolve one call under its current adapter registration. The returned + * one-shot handle keeps that registration across header logging and dispatch, + * so HMR cannot combine one adapter's capability result with another adapter. + * @param config - provider/model route and optional request controls. + * @param signal - optional cancellation for adapter-owned capability lookup. + * @returns a prepared config and its registration-bound stream entry point. + */ + async prepareCall(config, signal) { + const registration = this.registration(config.provider); + const resolved = await this.resolveCallFor(registration, config, signal); + const resolvedConfig = deepFreeze(structuredClone(resolved.config)); + const context = resolved.context === undefined + ? undefined + : deepFreeze(structuredClone(resolved.context)); + const adapterDefaults = deepFreeze({ + ...config.reasoningEffort === undefined && resolvedConfig.reasoningEffort !== undefined + ? { reasoningEffort: true } + : {}, + ...config.maxTokens === undefined && resolvedConfig.maxTokens !== undefined + ? { maxTokens: true } + : {}, + }); + let dispatched = false; + return Object.freeze({ + config: resolvedConfig, + retryPolicy: registration.retryPolicy, + adapterDefaults, + ...context === undefined ? {} : { context }, + stream: (options) => { + if (dispatched) { + throw new LlmError('a prepared LLM call can only be dispatched once', 'INVALID_PREPARED_CALL'); + } + if (!callConfigEquals(options, resolvedConfig)) { + throw new LlmError('prepared LLM call config changed before adapter dispatch', 'INVALID_PREPARED_CALL'); + } + dispatched = true; + return this.streamWithRegistration(options, { registration, config: resolvedConfig }); + }, + }); + } + registration(provider) { + const registration = this.adapters.get(provider); + if (!registration) + throw new LlmError(`no adapter registered for provider "${provider}"`, 'NO_ADAPTER'); + return registration; + } + /** Remove replay state whose historical route is owned by another adapter. */ + forAdapter(options, adapter) { + const messages = options.messages.map((message) => { + const source = message.source; + if (message.role !== 'assistant' || source.kind !== 'model' || source.replayState === undefined) + return message; + if (this.adapters.get(source.provider)?.adapter === adapter) + return message; + return freezeMessage({ + ...message, + source: { kind: 'model', provider: source.provider, model: source.model }, + }); + }); + if (messages.every((message, index) => message === options.messages[index])) + return options; + const filtered = { ...options, messages }; + return Object.isFrozen(options) ? deepFreeze(filtered) : filtered; + } + /** + * Final adapter boundary. Adapter selection, dispatch, iterator construction, + * and iteration failures become one terminal failure chunk. Middleware and + * downstream consumer failures remain thrown plugin or consumer errors. + */ + async *adapterStream(options, prepared) { + let iterator; + try { + const registration = prepared?.registration ?? this.registration(options.provider); + const resolvedConfig = prepared === undefined + ? (await this.resolveCallFor(registration, options, options.signal)).config + : prepared.config; + if (prepared !== undefined && !callConfigEquals(options, resolvedConfig)) { + throw new LlmError('prepared LLM call config changed before adapter dispatch', 'INVALID_PREPARED_CALL'); + } + const resolvedOptions = callConfigEquals(options, resolvedConfig) + ? options + : Object.isFrozen(options) + ? deepFreeze({ ...options, ...resolvedConfig }) + : { ...options, ...resolvedConfig }; + const adapter = registration.adapter; + const stream = adapter.stream(this.forAdapter(resolvedOptions, adapter)); + iterator = stream[Symbol.asyncIterator](); + } + catch (error) { + yield adapterFailureChunk(error, options.signal); + return; + } + let completed = false; + try { + while (true) { + let item; + try { + const next = await iterator.next(); + item = next.done + ? { done: true } + : { done: false, value: next.value }; + } + catch (error) { + completed = true; + yield adapterFailureChunk(error, options.signal); + return; + } + if (item.done) { + completed = true; + return; + } + // End the adapter-owned try before yielding: consumer/middleware + // failures resumed into this generator must remain thrown. + yield item.value; + } + } + finally { + if (!completed) { + const close = iterator.return?.bind(iterator); + if (close) + await close(); + } + } + } + /** + * Stream one model call as raw chunks (token-level deltas). Replay state is + * retained only when the same adapter instance owns its historical provider + * and the target provider. Final adapter selection remains fixed through + * asynchronous exact-model resolution and dispatch. Adapter selection, + * dispatch, and iteration failures become terminal `error` or `aborted` + * finish chunks; middleware, nested-call, cleanup, and consumer failures + * remain thrown. + * @param options - the full request; `options.provider` selects the adapter. + * @returns the chunk stream, possibly wrapped by `llm/stream` listeners. + */ + stream(options) { + return this.streamWithRegistration(options); + } + streamWithRegistration(options, prepared) { + return this.ctx.waterfall(this, 'llm/stream', options, () => this.adapterStream(options, prepared)); + } +} +/** Convert one adapter throw into the stream protocol's terminal outcome. */ +function adapterFailureChunk(error, signal) { + const failure = normalizeLlmFailure(error); + return { + type: 'finish', + reason: signal?.aborted || failure.code === 'ABORTED' + ? { kind: 'aborted', failure } + : { kind: 'error', failure }, + }; +} +export default LlmRuntime; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.d.ts new file mode 100644 index 0000000..a463bc7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned LLM stream-protocol invariants. @module @deepseek-ai/dsh-llm/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "llm-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the LLM invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.js new file mode 100644 index 0000000..54896c8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/invariant.js @@ -0,0 +1,100 @@ +/** Package-owned LLM stream-protocol invariants. @module @deepseek-ai/dsh-llm/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-llm'; +/** Cordis companion plugin name. */ +export const name = 'llm-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Require one chunk index to be a non-negative safe integer. */ +function validateIndex(index, fail) { + if (!Number.isSafeInteger(index) || index < 0) { + fail(`LLM stream block index must be a non-negative safe integer, got ${index}`); + } +} +/** Require a delta to address an open block of its matching type. */ +function validateDelta(open, index, expected, fail) { + validateIndex(index, fail); + const actual = open.get(index); + if (actual !== expected) { + fail(`${expected} delta at index ${index} requires an open ${expected} block, got ${String(actual)}`); + } +} +/** Wrap one provider stream and enforce its grammar as chunks are consumed. */ +async function* validateStream(source, fail) { + const open = new Map(); + let usageSeen = false; + let finished = false; + for await (const chunk of source) { + if (finished) + fail(`LLM stream emitted ${chunk.type} after terminal finish`); + switch (chunk.type) { + case 'block-start': + validateIndex(chunk.index, fail); + if (open.has(chunk.index)) + fail(`LLM stream repeated block-start index ${chunk.index}`); + open.set(chunk.index, chunk.blockType); + break; + case 'text-delta': + validateDelta(open, chunk.index, 'text', fail); + break; + case 'reasoning-delta': + validateDelta(open, chunk.index, 'reasoning', fail); + break; + case 'tool-call-delta': + validateDelta(open, chunk.index, 'tool-call', fail); + break; + case 'block-end': { + validateIndex(chunk.index, fail); + const blockType = open.get(chunk.index); + if (blockType === undefined) + fail(`LLM stream block-end index ${chunk.index} has no open block`); + if (chunk.block.type !== blockType) { + fail(`LLM stream block-end index ${chunk.index} closes ${chunk.block.type}, expected ${blockType}`); + } + open.delete(chunk.index); + break; + } + case 'usage': + if (usageSeen) + fail('LLM stream emitted usage more than once'); + usageSeen = true; + break; + case 'finish': + if (open.size > 0 && chunk.reason.kind !== 'error' && chunk.reason.kind !== 'aborted') { + fail(`LLM stream finished with ${open.size} open block(s)`); + } + finished = true; + break; + } + yield chunk; + } + if (!finished) + fail('LLM stream ended without a terminal finish chunk'); +} +/** Install validation around every provider stream. */ +const install = (ctx, fail) => { + ctx.on('llm/stream', (_options, next) => validateStream(next(), fail), { global: true, prepend: true }); + ctx.on('llm/adapters-updated', () => { + // A disposer-time emit can outlive the service-store entry during whole- + // context teardown; only a live service promises a readable registry. + const llm = ctx.get('llm'); + if (llm === undefined) + return; + for (const provider of llm.listProviders()) { + try { + llm.providerRetryPolicy(provider.id); + } + catch { + // Reaching here IS the violation: the notification promised a readable + // registry, and only that broken promise can make the lookup throw. + fail(`llm/adapters-updated fired while provider "${provider.id}" has no readable registration`); + } + } + }, { global: true }); +}; +/** + * Register the LLM invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/message.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/message.d.ts new file mode 100644 index 0000000..67b4554 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/message.d.ts @@ -0,0 +1,206 @@ +/** Message value types, identity, and immutable construction helpers. */ +import { MessageId, type CallId } from './brand.ts'; +import type { ContentBlock, StreamChunk, ToolResultBlock } from './types.ts'; +/** Provider/model identity and adapter-private replay data for an assistant message. */ +export interface AssistantProvenance { + /** Provider route that produced the message. */ + provider: string; + /** Provider model id that produced the message. */ + model: string; + /** + * Lossless-JSON adapter state needed to replay the provider response. + * `LlmRuntime` exposes it to a target adapter only when that adapter instance + * currently owns both this historical provider and the target provider. + */ + replayState?: unknown; +} +/** Required source of an assistant message produced by a routed model. */ +export interface ModelMessageSource extends AssistantProvenance { + kind: 'model'; +} +/** Required source of a user-role message carrying one tool result. */ +export interface ToolMessageSource { + kind: 'tool'; + callId: CallId; +} +/** + * The kind of information in producer-supplied context, declared by the + * producer beside its provenance. + * + * `MessageSource.kind` answers *who produced this*; `form` answers *what kind + * of thing it is*, and the two axes are deliberately independent — several + * producers share one form, and one producer may emit more than one form over + * a session. + * + * The vocabulary is SEMANTIC, never visual: a value states that the content is + * a file's instructions or a catalog of available items, and a consumer decides + * what that looks like. Colors, icons, ordering, and collapse defaults are the + * consumer's business and must not enter this union. It grows one value at a + * time as producers gain the structured fields their form needs; an absent or + * unknown value is the documented default, presented as opaque content. + */ +export type ContextForm = +/** Instructions read out of workspace files the model is expected to follow. */ +'instructions' +/** A catalog of items available in this session, republished as it changes. */ + | 'catalog' +/** Current state, where a later snapshot from the same producer supersedes an earlier one. */ + | 'snapshot' +/** A one-off account of something that just happened; it supersedes nothing. */ + | 'notice' +/** A message another agent addressed to this one. */ + | 'relay' +/** Material lifted out of another session's log, possibly reduced on the way in. */ + | 'recall'; +/** One named contribution to a `snapshot`-form context, in assembly order. */ +export interface ContextSnapshotSection { + /** The contributing subsystem's name. */ + readonly name: string; + /** That contribution's model-facing text, exactly as assembled. */ + readonly text: string; +} +/** + * Producer-declared {@link ContextForm} and the fields that form requires, + * mixed into the source types that carry one. + * + * Discriminated by `form` so a producer cannot select a form without the + * fields needed to present it: a `notice` must record its one-line + * account, a `snapshot` its sections. Omitting `form` stays valid — an + * undeclared context is the documented default. + */ +export type ContextFormed = { + readonly form?: never; +} | { + readonly form: 'instructions'; +} | { + readonly form: 'catalog'; +} | { + readonly form: 'snapshot'; + /** The named contributions this snapshot assembled, in order. */ + readonly sections: readonly ContextSnapshotSection[]; +} | { + readonly form: 'notice'; + /** One-line account of what happened, shown without expanding the row. */ + readonly summary: string; +} | { + readonly form: 'relay'; +} | { + readonly form: 'recall'; +}; +/** + * Where a message (or injected content) came from. + * Merge-extensible sum type — plugins add their own `kind`s. + */ +export interface MessageSourceMap { + user: { + kind: 'user'; + }; + plugin: { + kind: 'plugin'; + plugin: string; + } & ContextFormed; + model: ModelMessageSource; + tool: ToolMessageSource; +} +/** + * Bound for a `notice` summary. The account rides a collapsed transcript row + * and is committed to the durable log, while its inputs — task labels, goal + * objectives, tool arguments — are caller text with no length of their own. + */ +export declare const CONTEXT_SUMMARY_MAX_CHARS = 120; +/** + * Bound one `notice` summary to {@link CONTEXT_SUMMARY_MAX_CHARS}. + * @param summary - the producer's one-line account, of any length. + * @returns the account, ellipsized when it exceeds the bound. + */ +export declare function boundContextSummary(summary: string): string; +/** Any known message source, derived from {@link MessageSourceMap}; switch on `kind` and fall through unknowns (merge-extensible). */ +export type MessageSource = MessageSourceMap[keyof MessageSourceMap]; +/** One immutable message representation shared by delivery, durable history, and model requests. */ +export interface Message { + /** Stable identity preserved across every representation boundary. */ + readonly id: MessageId; + /** Provider-neutral conversation role. */ + readonly role: 'system' | 'user' | 'assistant'; + /** Exact model-facing blocks. */ + readonly content: ContentBlock[]; + /** Required source fields supplied by the producer. */ + readonly source: MessageSource; +} +/** A user-role specialization of the one shared message representation. */ +export interface UserMessage extends Message { + readonly role: 'user'; +} +/** A model-produced assistant specialization of the shared message representation. */ +export interface AssistantMessage extends Message { + readonly role: 'assistant'; + readonly source: ModelMessageSource; +} +/** A tool-result specialization whose model-facing block retains call correlation. */ +export interface ToolResultMessage extends Message { + readonly role: 'user'; + readonly content: [ToolResultBlock]; + readonly source: ToolMessageSource; +} +type NewMessage = Omit; +type NewUserMessage = Omit; +type NewAssistantMessage = Omit & { + readonly source: Omit & { + readonly kind?: never; + }; +}; +/** + * Detach and deep-freeze a message whose identity already exists. + * @param message - complete message, including its stable identity. + * @returns an immutable snapshot that preserves the identity. + */ +export declare function freezeMessage(message: T): T; +/** + * Create one identified message and freeze it before publication. + * @param input - complete role, content, and source for a new message. + * @returns an immutable message with a fresh stable identity. + */ +export declare function createMessage(input: T & { + readonly id?: never; +}): T & Pick; +/** + * Create one identified user-role message and freeze it before publication. + * @param input - complete content and source for a new user message. + * @returns an immutable user message with a fresh stable identity. + */ +export declare function createUserMessage(input: T & { + readonly id?: never; + readonly role?: never; +}): T & Pick; +/** + * Create one identified model-produced assistant message and freeze it before publication. + * @param input - complete content plus the provider, model, and optional replay state for a new assistant message. + * @returns an immutable assistant message with fixed role/source tags and a fresh stable identity. + */ +export declare function createAssistantMessage(input: NewAssistantMessage & { + readonly id?: never; + readonly role?: never; +}): AssistantMessage; +/** Input whose acceptance creates one tool-result message. */ +export interface ToolResultMessageInput { + readonly callId: CallId; + readonly content: ContentBlock[]; + readonly isError: boolean; +} +/** + * Create and freeze one identified tool-result message. + * @param input - call identity, raw result blocks, and outcome. + * @returns an immutable user-role tool-result message. + */ +export declare function createToolResultMessage(input: ToolResultMessageInput): ToolResultMessage; +/** + * Whether a stream chunk carries visible model output (the first-token + * boundary shared by client step timing and the whole-log sessionStats + * projection). Empty deltas (heartbeats, empty tool-call frames) do not count + * as a first token. + * @param chunk - the stream chunk to test. + * @returns true when the chunk contains a non-empty text/reasoning/tool delta. + */ +export declare function isTokenDelta(chunk: StreamChunk): boolean; +export {}; +//# sourceMappingURL=message.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/message.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/message.js new file mode 100644 index 0000000..45b34a1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/message.js @@ -0,0 +1,100 @@ +/** Message value types, identity, and immutable construction helpers. */ +import { MessageId } from "./brand.js"; +import { deepFreeze } from "./call-config.js"; +/** + * Bound for a `notice` summary. The account rides a collapsed transcript row + * and is committed to the durable log, while its inputs — task labels, goal + * objectives, tool arguments — are caller text with no length of their own. + */ +export const CONTEXT_SUMMARY_MAX_CHARS = 120; +/** + * Bound one `notice` summary to {@link CONTEXT_SUMMARY_MAX_CHARS}. + * @param summary - the producer's one-line account, of any length. + * @returns the account, ellipsized when it exceeds the bound. + */ +export function boundContextSummary(summary) { + return summary.length <= CONTEXT_SUMMARY_MAX_CHARS + ? summary + : `${summary.slice(0, CONTEXT_SUMMARY_MAX_CHARS - 1)}…`; +} +/** + * Detach and deep-freeze a message whose identity already exists. + * @param message - complete message, including its stable identity. + * @returns an immutable snapshot that preserves the identity. + */ +export function freezeMessage(message) { + return deepFreeze(structuredClone(message)); +} +/** + * Create one identified message and freeze it before publication. + * @param input - complete role, content, and source for a new message. + * @returns an immutable message with a fresh stable identity. + */ +export function createMessage(input) { + return freezeMessage({ + ...input, + id: MessageId(crypto.randomUUID()), + }); +} +/** + * Create one identified user-role message and freeze it before publication. + * @param input - complete content and source for a new user message. + * @returns an immutable user message with a fresh stable identity. + */ +export function createUserMessage(input) { + return createMessage({ + ...input, + role: 'user', + }); +} +/** + * Create one identified model-produced assistant message and freeze it before publication. + * @param input - complete content plus the provider, model, and optional replay state for a new assistant message. + * @returns an immutable assistant message with fixed role/source tags and a fresh stable identity. + */ +export function createAssistantMessage(input) { + return createMessage({ + role: 'assistant', + content: input.content, + source: { + kind: 'model', + ...input.source, + }, + }); +} +/** + * Create and freeze one identified tool-result message. + * @param input - call identity, raw result blocks, and outcome. + * @returns an immutable user-role tool-result message. + */ +export function createToolResultMessage(input) { + return createUserMessage({ + source: { kind: 'tool', callId: input.callId }, + content: [{ + type: 'tool-result', + toolCallId: input.callId, + content: input.content, + isError: input.isError, + }], + }); +} +/** + * Whether a stream chunk carries visible model output (the first-token + * boundary shared by client step timing and the whole-log sessionStats + * projection). Empty deltas (heartbeats, empty tool-call frames) do not count + * as a first token. + * @param chunk - the stream chunk to test. + * @returns true when the chunk contains a non-empty text/reasoning/tool delta. + */ +export function isTokenDelta(chunk) { + switch (chunk.type) { + case 'text-delta': + case 'reasoning-delta': + return chunk.text !== ''; + case 'tool-call-delta': + return chunk.argumentsDelta !== '' || chunk.name !== undefined; + default: + return false; + } +} +//# sourceMappingURL=message.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/never.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/never.d.ts new file mode 100644 index 0000000..6efa7a4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/never.d.ts @@ -0,0 +1,16 @@ +/** + * Exhaustiveness helper for closed core unions. Use {@link assertNever} at the default branch so a + * new variant fails compilation at every required handler. Do not use it for declaration-merged + * unions such as session events or content blocks: handle known variants and explicitly fall + * through because plugins may add valid unknown cases. + * @module @deepseek-ai/dsh-llm/never + */ +/** + * Mark an unreachable closed-union branch. A newly unhandled typed variant fails at the call site; + * a value that escaped its type throws with diagnostics at runtime. + * @param value - the impossible value; typed `never` so an unhandled variant fails compilation at the call site. + * @param context - optional label (e.g. the switch site) prefixed into the throw message. + * @returns never — it always throws, with the offending value JSON-rendered in the message. + */ +export declare function assertNever(value: never, context?: string): never; +//# sourceMappingURL=never.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/never.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/never.js new file mode 100644 index 0000000..2381b13 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/never.js @@ -0,0 +1,21 @@ +/** + * Exhaustiveness helper for closed core unions. Use {@link assertNever} at the default branch so a + * new variant fails compilation at every required handler. Do not use it for declaration-merged + * unions such as session events or content blocks: handle known variants and explicitly fall + * through because plugins may add valid unknown cases. + * @module @deepseek-ai/dsh-llm/never + */ +/** + * Mark an unreachable closed-union branch. A newly unhandled typed variant fails at the call site; + * a value that escaped its type throws with diagnostics at runtime. + * @param value - the impossible value; typed `never` so an unhandled variant fails compilation at the call site. + * @param context - optional label (e.g. the switch site) prefixed into the throw message. + * @returns never — it always throws, with the offending value JSON-rendered in the message. + */ +export function assertNever(value, context) { + // JSON.stringify is typed string but returns undefined for undefined input; + // String() covers that and other non-serializable escapes. + const rendered = JSON.stringify(value) ?? String(value); + throw new Error(`unreachable variant${context ? ` in ${context}` : ''}: ${rendered}`); +} +//# sourceMappingURL=never.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.d.ts new file mode 100644 index 0000000..a8f9447 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.d.ts @@ -0,0 +1,66 @@ +/** + * Provider-owned request-retry policy configuration and resolution. + * + * Adapters expose one resolved policy per registered provider route; the + * optional dsh-llm-retry plugin executes it on the agent's failed-step extension point. + * + * @module @deepseek-ai/dsh-llm/retry-policy + */ +import z from '@deepseek-ai/schemastery'; +/** Bounded exponential backoff with symmetric jitter around each local delay. */ +export interface BackoffConfig { + /** Initial local exponential-backoff delay in milliseconds (default 500). */ + initialDelayMs?: number; + /** Maximum locally scheduled or accepted provider delay in milliseconds (default 10000). */ + maxDelayMs?: number; + /** Symmetric random multiplier range around one (default 0.1). */ + jitterRatio?: number; +} +/** Current bounded transient retry behavior for one provider route. */ +export interface NormalRetryPolicyConfig { + /** Retry only configured transient failure codes. */ + mode: 'normal'; + /** Maximum eligible retries after the first request (default 2). */ + maxRetries?: number; + /** Stable failure codes eligible for this policy. */ + retryableCodes?: string[]; + /** Local exponential-backoff and jitter configuration. */ + backoff?: BackoffConfig; +} +/** Unbounded retry behavior for every model-request failure on one provider route. */ +export interface AlwaysRetryPolicyConfig { + /** Retry every model-request failure until success, cancellation, or disposal. */ + mode: 'always'; + /** Local exponential-backoff and jitter configuration. */ + backoff?: BackoffConfig; +} +/** Provider-owned model-request retry policy configuration. */ +export type RetryPolicyConfig = NormalRetryPolicyConfig | AlwaysRetryPolicyConfig; +/** Fully resolved backoff shared by both retry modes. */ +export interface ResolvedRetryBackoff { + readonly initialDelayMs: number; + readonly maxDelayMs: number; + readonly jitterRatio: number; +} +/** Fully resolved bounded transient retry policy. */ +export interface ResolvedNormalRetryPolicy extends ResolvedRetryBackoff { + readonly mode: 'normal'; + readonly maxRetries: number; + readonly retryableCodes: readonly string[]; +} +/** Fully resolved unbounded retry policy. */ +export interface ResolvedAlwaysRetryPolicy extends ResolvedRetryBackoff { + readonly mode: 'always'; +} +/** Immutable provider policy captured when its adapter route is registered. */ +export type ResolvedRetryPolicy = ResolvedNormalRetryPolicy | ResolvedAlwaysRetryPolicy; +/** Cordis schema embedded by each concrete provider configuration. */ +export declare const RetryPolicySchema: z; +/** + * Validate, default, and detach one provider-owned retry policy. + * @param config - optional provider configuration; omission selects normal defaults. + * @param path - diagnostic path naming the provider config that owns the value. + * @returns an immutable policy safe to capture in provider registration state. + */ +export declare function resolveRetryPolicy(config: RetryPolicyConfig | undefined, path: string): ResolvedRetryPolicy; +//# sourceMappingURL=retry-policy.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.js new file mode 100644 index 0000000..d3285cb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.js @@ -0,0 +1,123 @@ +/** + * Provider-owned request-retry policy configuration and resolution. + * + * Adapters expose one resolved policy per registered provider route; the + * optional dsh-llm-retry plugin executes it on the agent's failed-step extension point. + * + * @module @deepseek-ai/dsh-llm/retry-policy + */ +import z from '@deepseek-ai/schemastery'; +import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'; +import { EMPTY_RESPONSE_CODE } from "./error.js"; +const DEFAULT_MAX_RETRIES = 2; +const DEFAULT_INITIAL_DELAY_MS = 500; +const DEFAULT_MAX_DELAY_MS = 10_000; +const DEFAULT_JITTER_RATIO = 0.1; +const DEFAULT_RETRYABLE_CODES = Object.freeze([ + EMPTY_RESPONSE_CODE, + 'RATE_LIMIT', + 'SERVER', + 'TIMEOUT', + 'TRANSPORT', +]); +const backoffSchema = z.object({ + initialDelayMs: z.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_INITIAL_DELAY_MS), + maxDelayMs: z.number().max(MAX_TIMER_DELAY_MS).default(DEFAULT_MAX_DELAY_MS), + jitterRatio: z.number().min(0).max(1).default(DEFAULT_JITTER_RATIO), +}); +const normalPolicySchema = z.object({ + mode: z.const('normal').required(), + maxRetries: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_MAX_RETRIES), + retryableCodes: z.array(z.string()).default([...DEFAULT_RETRYABLE_CODES]), + backoff: backoffSchema, +}); +const alwaysPolicySchema = z.object({ + mode: z.const('always').required(), + backoff: backoffSchema, +}); +/** Cordis schema embedded by each concrete provider configuration. */ +export const RetryPolicySchema = z.union([ + normalPolicySchema, + alwaysPolicySchema, +]); +const NORMAL_POLICY_KEYS = new Set([ + 'mode', 'maxRetries', 'retryableCodes', 'backoff', +]); +const ALWAYS_POLICY_KEYS = new Set(['mode', 'backoff']); +const BACKOFF_KEYS = new Set(['initialDelayMs', 'maxDelayMs', 'jitterRatio']); +function validateKeys(value, allowed, path) { + for (const key of Object.keys(value)) { + if (!allowed.has(key)) + throw new Error(`${path}: unknown key "${key}"`); + } +} +function resolveBackoff(config, path) { + if (config !== undefined) + validateKeys(config, BACKOFF_KEYS, path); + const initialDelayMs = config?.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS; + const maxDelayMs = config?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS; + const jitterRatio = config?.jitterRatio ?? DEFAULT_JITTER_RATIO; + if (!Number.isFinite(initialDelayMs) || initialDelayMs <= 0 || initialDelayMs > MAX_TIMER_DELAY_MS) { + throw new Error(`${path}.initialDelayMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`); + } + if (!Number.isFinite(maxDelayMs) || maxDelayMs <= 0 || maxDelayMs > MAX_TIMER_DELAY_MS) { + throw new Error(`${path}.maxDelayMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`); + } + if (initialDelayMs > maxDelayMs) { + throw new Error(`${path}.initialDelayMs must be less than or equal to maxDelayMs`); + } + if (!Number.isFinite(jitterRatio) || jitterRatio < 0 || jitterRatio > 1) { + throw new Error(`${path}.jitterRatio must be between 0 and 1`); + } + return Object.freeze({ initialDelayMs, maxDelayMs, jitterRatio }); +} +/** + * Validate, default, and detach one provider-owned retry policy. + * @param config - optional provider configuration; omission selects normal defaults. + * @param path - diagnostic path naming the provider config that owns the value. + * @returns an immutable policy safe to capture in provider registration state. + */ +export function resolveRetryPolicy(config, path) { + if (config === undefined) { + return Object.freeze({ + mode: 'normal', + maxRetries: DEFAULT_MAX_RETRIES, + retryableCodes: DEFAULT_RETRYABLE_CODES, + ...resolveBackoff(undefined, `${path}.backoff`), + }); + } + switch (config.mode) { + case 'normal': { + validateKeys(config, NORMAL_POLICY_KEYS, path); + const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES; + const retryableCodes = config.retryableCodes ?? [...DEFAULT_RETRYABLE_CODES]; + if (!Number.isSafeInteger(maxRetries) || maxRetries < 0) { + throw new Error(`${path}.maxRetries must be a non-negative safe integer`); + } + if (retryableCodes.length === 0) { + throw new Error(`${path}.retryableCodes must not be empty`); + } + if (retryableCodes.some(code => typeof code !== 'string' || code.length === 0)) { + throw new Error(`${path}.retryableCodes must contain only non-empty strings`); + } + if (new Set(retryableCodes).size !== retryableCodes.length) { + throw new Error(`${path}.retryableCodes must not contain duplicates`); + } + return Object.freeze({ + mode: 'normal', + maxRetries, + retryableCodes: Object.freeze([...retryableCodes]), + ...resolveBackoff(config.backoff, `${path}.backoff`), + }); + } + case 'always': + validateKeys(config, ALWAYS_POLICY_KEYS, path); + return Object.freeze({ + mode: 'always', + ...resolveBackoff(config.backoff, `${path}.backoff`), + }); + default: + throw new Error(`${path}.mode must be "normal" or "always"`); + } +} +//# sourceMappingURL=retry-policy.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/types.d.ts new file mode 100644 index 0000000..66c5068 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/types.d.ts @@ -0,0 +1,369 @@ +/** + * Canonical provider-neutral message and streaming vocabulary for the loop, + * session log, and plugins. Adapters alone translate provider wire messages; + * mapped interfaces make the content, source, and finish unions extensible. + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'; +import type { CallId, ProviderRequestId, ReasoningEffortId } from './brand.ts'; +import type { Message } from './message.ts'; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * The provider topology changed: an adapter registered or unregistered + * routes, or the configurable-provider directory gained or lost entries. + * This payload-free registry notification fires at each commit point + * (including registration disposal); consumers re-read `listProviders()`, + * `listModels()`, or `listConfigurableProviders()` for the new state. + * Observer failures are contained and cannot veto the registry mutation. + * @mode emit + */ + 'llm/adapters-updated'(): void; + } +} +export type { AssistantMessage, AssistantProvenance, Message, MessageSource, MessageSourceMap, ModelMessageSource, ToolMessageSource, ToolResultMessage, UserMessage, } from './message.ts'; +/** Serializable provider or transport failure facts; policy decides whether they are retryable. */ +export interface LlmFailure { + /** Human-readable provider or transport failure. */ + readonly message: string; + /** Stable provider-neutral machine-routing code. */ + readonly code: string; + /** HTTP status returned by the provider, when available. */ + readonly status?: number; + /** Provider-requested delay in milliseconds, when valid and available. */ + readonly providerRetryAfterMs?: number; + /** Opaque provider-issued request identifier for diagnostics. */ + readonly requestId?: ProviderRequestId; +} +/** Plain text visible to the end user. */ +export interface TextBlock { + type: 'text'; + text: string; +} +/** Reasoning / thinking content, distinct from visible text. */ +export interface ReasoningBlock { + type: 'reasoning'; + text: string; +} +/** + * A durable raster image reference, valid in user or assistant content. The + * block is deliberately role-neutral; assistant-side rendering is forward + * compatibility — the current production adapters declare text-only output, + * so only user content carries images today. + */ +export interface ImageBlock { + type: 'image'; + /** Immutable bytes and intrinsic display metadata owned by the attachment service. */ + attachment: ImageAttachmentRef; +} +/** A tool invocation requested by the model. */ +export interface ToolCallBlock { + type: 'tool-call'; + /** Provider-issued call id; correlates with the matching tool result. */ + id: CallId; + name: string; + /** Raw JSON string as produced by the model. */ + arguments: string; +} +/** The result of a tool invocation, sent back to the model. */ +export interface ToolResultBlock { + type: 'tool-result'; + toolCallId: CallId; + content: ContentBlock[]; + isError?: boolean; +} +/** + * Merge-extensible content blocks keyed by `type`. New core blocks must land + * with adapter, UI, and compaction support. + */ +export interface ContentBlockMap { + 'text': TextBlock; + 'reasoning': ReasoningBlock; + 'image': ImageBlock; + 'tool-call': ToolCallBlock; + 'tool-result': ToolResultBlock; +} +/** The block `type` tag vocabulary; widens as plugins add entries to {@link ContentBlockMap}. */ +export type ContentBlockType = keyof ContentBlockMap; +/** Any known content block, derived from {@link ContentBlockMap}; switch on `type` and fall through unknowns (merge-extensible). */ +export type ContentBlock = ContentBlockMap[ContentBlockType]; +/** + * Why a model response stopped. + * Merge-extensible so adapters can surface provider-specific reasons. + */ +export interface FinishReasonMap { + 'stop': { + kind: 'stop'; + }; + 'tool-calls': { + kind: 'tool-calls'; + }; + 'max-tokens': { + kind: 'max-tokens'; + }; + 'aborted': { + kind: 'aborted'; + failure: LlmFailure; + }; + 'error': { + kind: 'error'; + failure: LlmFailure; + }; +} +/** Any known finish reason, derived from {@link FinishReasonMap}; switch on `kind` and fall through unknowns (merge-extensible). */ +export type FinishReason = FinishReasonMap[keyof FinishReasonMap]; +/** + * Token accounting for one model call (cache fields are optional). + * + * Counts are DISJOINT: `inputTokens` is uncached input only; cached input is + * reported separately as `cacheReadTokens`/`cacheWriteTokens` (billed input = + * sum of the three). Adapters whose providers fold cache hits into a total + * prompt count (DeepSeek's `prompt_tokens`) subtract them out. + */ +export interface TokenUsage { + inputTokens: number; + outputTokens: number; + cacheReadTokens?: number; + cacheWriteTokens?: number; + reasoningTokens?: number; +} +/** Display metadata for one registered provider route. */ +export interface LlmProviderInfo { + /** Provider route key used by {@link GenerateOptions.provider}. */ + id: string; + /** Human-readable provider name for selectors and diagnostics. */ + name: string; +} +/** Merge-extensible provider model modality vocabulary. */ +export interface ModelModalityMap { + text: 'text'; + image: 'image'; +} +/** Any declared provider model modality. */ +export type ModelModality = ModelModalityMap[keyof ModelModalityMap]; +/** + * One provider route an adapter plugin can activate through configuration, + * whether or not the route is currently registered. Configuration surfaces + * merge this directory with `listProviders()` to offer every configurable + * provider alongside its live/dormant state. + */ +export interface LlmConfigurableProvider { + /** Provider route key this entry activates when configured. */ + provider: string; + /** Human-readable provider name for configuration surfaces. */ + displayName: string; + /** User-settings namespace whose section configures this provider. */ + settingsNs: string; + /** + * Path from that namespace's section root to this provider's profile + * object; empty when the whole section is the profile. + */ + settingsPath: readonly string[]; + /** + * Whether the owning adapter knows this route only because configuration + * declared it — a gateway or self-hosted server it ships nothing about. + * Absent means the adapter draws no such distinction; false means it does + * and this route is one of its own. Only the adapter can answer: a stored + * profile is how a user-added route AND a corrected shipped one both look + * from outside. + */ + declared?: boolean; +} +/** + * One interrogation of a provider endpoint that configuration has not stored + * yet. Configuration surfaces send the draft a user is still editing, so the + * request carries the endpoint and credential directly instead of naming a + * route: a provider being added has no route to name. + */ +export interface LlmModelDiscoveryRequest { + /** + * Route the draft is editing, when it edits an existing one. A route whose + * adapter already knows its models answers from that knowledge instead of + * asking the endpoint — the adapter's own registry is the better answer, and + * it costs no network call. + */ + provider?: string; + /** + * Endpoint to interrogate. Optional because a route the adapter already + * describes needs none; a route it does not must supply one. + */ + baseURL?: string; + /** Wire protocol the endpoint speaks, when the draft names one. */ + api?: string; + /** Credential for this interrogation alone; the harness never stores it. */ + apiKey?: string; + /** Caller cancellation; implementations must settle promptly after it aborts. */ + signal?: AbortSignal; +} +/** + * One model an endpoint reports about itself. Every field but the id is + * optional because most provider listings disclose an id and nothing else; + * a surface adopting one of these still owes the capacities its adapter needs. + */ +export interface LlmDiscoveredModel { + /** Model id the endpoint accepts. */ + id: string; + /** Human-readable name when the endpoint supplies one. */ + name?: string; + /** Maximum combined request and response context, when disclosed. */ + contextWindow?: number; + /** Maximum output tokens, when disclosed. */ + maxTokens?: number; +} +/** One adapter-discovered model; catalog membership is advisory, not request validation. */ +export interface LlmModelInfo { + /** Provider route that owns this model entry. */ + provider: string; + /** Model id passed to {@link GenerateOptions.model}. */ + id: string; + /** Human-readable model name for selectors. */ + name: string; + /** Optional user-facing distinction from otherwise similar models. */ + description?: string; + /** Accepted request modalities; absent means unknown, while an explicit omission is negative capability. */ + inputModalities?: readonly ModelModality[]; +} +/** Provider-owned context capacity for one exact provider/model route. */ +export interface LlmModelContext { + /** Maximum combined request and response context in tokens. */ + contextWindow: number; +} +/** Display metadata for one adapter-owned reasoning effort. */ +export interface LlmReasoningEffortInfo { + /** Opaque stable value accepted by {@link GenerateOptions.reasoningEffort}. */ + id: ReasoningEffortId; + /** Human-readable effort name for selectors and diagnostics. */ + name: string; + /** Optional user-facing distinction from otherwise similar efforts. */ + description?: string; +} +/** Selectable reasoning efforts for one exact provider/model route. */ +export interface LlmModelReasoningInfo { + /** Supported efforts in adapter-preferred display order. */ + efforts: readonly LlmReasoningEffortInfo[]; + /** + * Adapter-configured default materialized into requests when callers omit + * an effort. Absence preserves the provider's own default. + */ + defaultEffort?: ReasoningEffortId; +} +/** Exact-route model metadata resolved by its owning adapter. */ +export interface LlmResolvedModelInfo extends LlmModelInfo { + /** Provider-owned context capacity when known. */ + context?: LlmModelContext; + /** Adapter-configured per-request output cap materialized when callers omit one. */ + defaultMaxTokens?: number; + /** Adapter-owned selectable reasoning levels when exposed. */ + reasoning?: LlmModelReasoningInfo; +} +/** + * Adapter-private lossless-JSON state for replaying a successful response, + * carried by a terminal `finish` chunk and stored on the assembled assistant + * message's model source. Both halves stay opaque to the harness; only the + * split is shared vocabulary, so assembly can keep stored metadata aligned + * with stored content without reading either half. + */ +export interface ReplayEnvelope { + /** Response-level adapter-private metadata (ids, native stop reason). */ + response: unknown; + /** + * Per-block adapter-private metadata, one entry per emitted block in + * first-seen stream order. When assembly drops a block it drops the entry at + * the same position; entries whose length does not match the emitted block + * count discard the whole envelope. An adapter whose metadata is independent + * of block structure omits this field and the envelope passes through + * assembly unchanged. + */ + blocks?: readonly unknown[]; +} +/** + * Raw streaming protocol emitted by adapters. + * Block indexes correlate interleaved deltas, and `block-end` carries the + * assembled block. Adapters emit usage before the terminal finish and nothing + * afterward; tool arguments remain raw JSON strings. An adapter implementation + * may throw, but `LlmRuntime.stream()` normalizes that failure to a terminal + * `error` or `aborted` finish before exposing it to consumers. + */ +export type StreamChunk = { + type: 'block-start'; + index: number; + blockType: ContentBlockType; +} | { + type: 'text-delta'; + index: number; + text: string; +} | { + type: 'reasoning-delta'; + index: number; + text: string; +} | { + type: 'tool-call-delta'; + index: number; + id: CallId; + name?: string; + argumentsDelta: string; +} | { + type: 'block-end'; + index: number; + block: ContentBlock; +} | { + type: 'usage'; + usage: TokenUsage; +} | { + type: 'finish'; + reason: FinishReason; + /** Replay metadata for a successful response; see {@link ReplayEnvelope}. */ + replayState?: ReplayEnvelope; +}; +/** + * JSON-schema description of a tool, as sent to the model. + * + * Declared here (not in dsh-tools) because it is part of {@link GenerateOptions}; + * dsh-tools' ToolDefinition and dsh-system-prompt's PromptAssembly both import + * it from this package. + */ +export interface ToolSchema { + name: string; + description: string; + /** JSON Schema object for the arguments. */ + parameters: Record; +} +/** A single model request, fully assembled. */ +export interface GenerateOptions { + /** Registered provider route selecting the adapter instance. */ + provider: string; + model: string; + /** Adapter-owned reasoning effort selected for this exact model. */ + reasoningEffort?: ReasoningEffortId; + /** + * Ordered conversation messages, exactly as the provider sees them (after + * the `system` slot). A loop-built request assembles them as + * the derived history (dsh-agent-loop); a hand-built one-shot passes any list. + */ + messages: Message[]; + /** System prompt text (adapters map to the provider's system slot). */ + system?: string; + /** Tool schemas (adapters map to the provider's `tools` field). */ + tools?: ToolSchema[]; + temperature?: number; + maxTokens?: number; + /** + * Stop sequences: generation halts as soon as the model produces any one of + * these strings (adapters map to the provider's stop field, e.g. OpenAI + * `stop`). The stop string itself is not included in the output. + */ + stop?: string[]; + signal?: AbortSignal; + /** + * Session identity stamped by the loop for request routing. Replay uses it + * to separate cursors; adapters may map it to model-hidden transport metadata. + */ + sessionId?: Branded<'SessionId'>; + /** + * Provider-neutral classification for an auxiliary model call. Adapters may + * map the purpose to model-hidden transport metadata or purpose-specific + * generation policy. Ordinary conversation requests leave it unset. + */ + purpose?: 'compaction' | 'session-title'; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/types.js new file mode 100644 index 0000000..73a21c9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Canonical provider-neutral message and streaming vocabulary for the loop, + * session log, and plugins. Adapters alone translate provider wire messages; + * mapped interfaces make the content, source, and finish unions extensible. + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/package.json new file mode 100644 index 0000000..72c7d63 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm/package.json @@ -0,0 +1,64 @@ +{ + "name": "@deepseek-ai/dsh-llm", + "description": "Provider-neutral LLM service interface for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/llm/llm" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./brand": { + "types": "./lib/types/brand.d.ts", + "default": "./lib/types/brand.js" + }, + "./message": { + "types": "./lib/types/message.d.ts", + "default": "./lib/types/message.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-timeout b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-timeout new file mode 120000 index 0000000..995aaf1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-timeout @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.i18n.yaml new file mode 100644 index 0000000..c884f75 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/feedback/message-feedback/README.md +README.md: b85104abb983eb3b33ab6ddad9328e6f5f3b1fc9 +README.zh.md: 52efef5119854f4a5c3c776a227032b59b680fc5 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.md new file mode 100644 index 0000000..b85104a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.md @@ -0,0 +1,84 @@ +# @deepseek-ai/dsh-message-feedback + +English | [中文](README.zh.md) + +Host-owned editable feedback for one finalized assistant message. The package registers `ctx.messageFeedback`, persists one lifecycle-bound sidecar row per Session in storage-domain, and publishes the Host `messageFeedback.list`, `messageFeedback.put`, and `messageFeedback.delete` unary Remote contract. It is separate from the immutable Session-level `feedback/record` event and performs no telemetry handoff. The [message-feedback sidecar Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-message-feedback-sidecar.md) owns the design boundary. + +Public request, value, version, and failure types are exported from the package root and `@deepseek-ai/dsh-message-feedback/types`; [`src/types.ts`](src/types.ts) is their source. + +## Configuration + +| key | meaning | +|---|---| +| `maxNoteBytes` | Required positive safe integer: maximum UTF-8 byte length of one optional note. | + +Notes must contain at least one non-whitespace character, but accepted text is stored verbatim rather than trimmed. Omitting `note` means the desired value has no note, so a version-matched material `put` clears an existing note. Note validation precedes Session lookup and can therefore return `note-blank` or `note-too-large` for a missing Session without touching persistence. + +```yaml +- id: message-feedback + name: '@deepseek-ai/dsh-message-feedback' + config: + maxNoteBytes: 8192 +``` + +The service injects `storageDomain`, `sessionPersistence`, and `sessions`. Its durable domain is `message_feedback`, with one `sessions` table row per `SessionId`. + +## Data, lifecycle, and durability + +`MessageFeedbackItem` contains `messageId`, `rating: 'positive' | 'negative'`, optional `note`, an opaque equality-only `version`, and Host-assigned `createdAt`/`updatedAt` Unix-millisecond timestamps. A material update preserves `createdAt`, replaces `version`, and keeps `updatedAt` from moving backward. `list` returns fresh immutable snapshots in first-creation order; updating an item retains its place, while deleting and later recreating it appends a new item. + +Each stored row carries the inspected Session header identity `{createdAt, cwd}`. A mismatch is treated as absence: `list` returns an empty `items` array, `delete` returns the absent postcondition, and `put` may replace the stale row with one bound to the current identity. This fences a reused `SessionId` when its header identity differs. Forks use a distinct Session identity and receive no feedback-row copy. + +`SessionPersistence.inspect()` supplies a cold-safe observation without publishing or resuming an Agent and without committing cold repair. For a Session without a live owner, `listSnapshots()` first decides definite absence; an `inspect()` failure for a catalogued Session remains an infrastructure failure rather than being guessed into `session-not-found`. `put` accepts only a non-empty, append-origin `assistant/message` with the requested `MessageId`; replacement-origin messages, empty usage-only assistant records, and non-assistant records return `target-not-found`. + +After initial validation, `put` establishes a durability barrier before writing the sidecar. A matching live Session commits through the canonical `ctx.sessions.flush` checkpoint, then both live and cold paths are physically read from sequence zero through `SessionPersistence.readFrom`. The resulting observation's header identity and target are validated again. A missing flush participant, changed identity, vanished target, or physical-read failure prevents the sidecar commit, so durable feedback never precedes the durable target message. + +Message feedback is not Session-log content or a Session projection. It emits no `feedback/record` event, does not enter model history, and does not trigger `FEEDBACK_ONLY` telemetry release. + +## Service and Host Remote contract + +The same three `MessageFeedbackService` methods are published by `TypertRemoteService` and `@Remote`; the Host endpoint names are `messageFeedback.list`, `messageFeedback.put`, and `messageFeedback.delete`. Every method returns a discriminated business union: `{ ok: true, value }` or `{ ok: false, error }`. Operational storage, corruption, or missing-durability-listener failures reject instead of being mislabeled as business errors. + +| Method | Request | Success `value` | Rejected `error.code` | +|---|---|---|---| +| `list` | `MessageFeedbackListRequest { sessionId }` | `MessageFeedbackListValue { items }` | `session-not-found` | +| `put` | `MessageFeedbackPutRequest { sessionId, messageId, rating, note?, ifVersion }` | committed `MessageFeedbackItem` | `session-not-found`, `target-not-found`, `version-conflict`, `note-blank`, `note-too-large` | +| `delete` | `MessageFeedbackDeleteRequest { sessionId, messageId, ifVersion }` | `MessageFeedbackDeleteValue { absent: true }` | `session-not-found`, `version-conflict` | + +`MessageFeedbackVersionConflict` returns the authoritative `current` item, or `null` when no item exists. This lets a caller reconcile the current rating, note, and version without a second `list` request. `MessageFeedbackNoteTooLarge` returns both `maxBytes` and `actualBytes`. The Client Remote aggregate does not mount the generated client contribution yet; Host callers can use the service/Remote contract without that client assembly. + +## Compare-and-set and idempotency + +`ifVersion: null` requests creation only; every request for an existing item requires its exact current version, including a no-op whose desired value already matches. The check is per message rather than per Session, so changing one item does not conflict with another. Every material create or update assigns a fresh opaque UUID token, preventing stale writes from crossing an ABA value cycle. + +A matching-version no-op returns the already stored item with unchanged version and timestamps. After a lost success response, a retry with the old token receives `version-conflict.current`; the caller can compare that authoritative item with its desired value without an extra read. `delete` ignores `ifVersion` when the item is already absent and always returns the stable `{ absent: true }` postcondition after success. + +A per-Session promise queue encloses inspection, durability validation, sidecar read, comparison, and whole-row write. These semantics serialize concurrent mutations through one service instance; storage-domain itself has no cross-process conditional write. + +Plugin disposal closes mutation admission, drains every operation already accepted into the per-Session queues, and only then closes the storage domain. A mutation submitted after disposal begins rejects as a lifecycle failure instead of entering a closing domain. + +## Model Experience + +### Local message-feedback state + +#### What the model sees + +Nothing. `ctx.messageFeedback` registers no tool, prompt section, model-facing context, or Session event; feedback stays in a Host-owned sidecar unless a separately documented Consumer explicitly exposes it. + +#### Token effect + +Zero. No request, result, rating, note, timestamp, or failure from this package enters a model request. + +#### KV Cache effect + +Independent. Listing or mutating message feedback does not touch a model request prefix and cannot invalidate an otherwise reusable provider cache entry. + +## Known Limitations and Deferred Work + +- **Client aggregate and UI are absent** — the Host Remote contract ships, but the Client Remote aggregate contribution and any UI consumer are separately owned and deferred. +- **Compare-and-set is single-process** — the per-Session queue serializes one service instance only; multiple Host processes writing one storage root can still lose updates because storage-domain exposes no cross-process conditional write. +- **No durable Session deletion cascade** — Session persistence has no deletion API, and `session/disposed`/`host/session-removed` mean detach rather than durable deletion. The service therefore retains empty rows and may leave orphan rows after out-of-band log removal instead of deleting valid feedback on detach. +- **Detach/catalog retirement window** — a request in the narrow interval after live detach but before the persistence catalog materializes the header can receive `session-not-found`; callers retry after retirement materialization. +- **Header identity is not a content fingerprint** — `{createdAt, cwd}` detects reuse only when those fields differ; a cloned log retaining the same header identity is indistinguishable. +- **Trusted caller boundary** — `list`/`put`/`delete` carry no authenticated actor or audit identity. A deployment must expose the Host gateway only through its trusted or separately authenticated boundary until authorization and attribution are added. +- **Catalog and row bounds** — a cold request scans the complete Session snapshot catalog because persistence has no lookup-by-id metadata operation. `maxNoteBytes` bounds one note, but the item count and aggregate retained bytes of one Session row are not capped; an indexed metadata read and deployment-owned row bound remain deferred until a concrete consumer defines their policy. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.zh.md new file mode 100644 index 0000000..52efef5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/README.zh.md @@ -0,0 +1,84 @@ +# @deepseek-ai/dsh-message-feedback + +[English](README.md) | 中文 + +本包提供由 Host 拥有、针对单条已完成 assistant 消息的可编辑反馈。它注册 `ctx.messageFeedback`,在 storage-domain 中为每个 Session 持久化一条绑定生命周期的伴随记录(sidecar),并发布 Host `messageFeedback.list`、`messageFeedback.put` 与 `messageFeedback.delete` 一元 Remote 契约。它与不可变的 Session 级 `feedback/record` 事件相互独立,不执行遥测交接。[消息反馈伴随记录 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-message-feedback-sidecar.md)拥有其设计边界。 + +公开的请求、值、版本与失败类型从包根入口及 `@deepseek-ai/dsh-message-feedback/types` 导出;其源码为 [`src/types.ts`](src/types.ts)。 + +## 配置 + +| 键 | 含义 | +|---|---| +| `maxNoteBytes` | 必填正 safe integer:一条可选备注的最大 UTF-8 字节长度。 | + +备注必须包含至少一个非空白字符,但通过校验的文本按原样存储,不会 trim。省略 `note` 表示目标值不含备注,因此 version 匹配的实质 `put` 会清除已有备注。备注校验早于 Session 查找,因此即使 Session 不存在,也可能在不访问持久化的情况下返回 `note-blank` 或 `note-too-large`。 + +```yaml +- id: message-feedback + name: '@deepseek-ai/dsh-message-feedback' + config: + maxNoteBytes: 8192 +``` + +服务注入 `storageDomain`、`sessionPersistence` 与 `sessions`。其持久存储域为 `message_feedback`,其中 `sessions` 表按 `SessionId` 每个一行。 + +## 数据、生命周期与持久性 + +`MessageFeedbackItem` 包含 `messageId`、`rating: 'positive' | 'negative'`、可选 `note`、只能做相等比较的 opaque `version`,以及由 Host 分配、以 Unix 毫秒表示的 `createdAt`/`updatedAt` 时间戳。实质更新保留 `createdAt`、替换 `version`,并保证 `updatedAt` 不倒退。`list` 按首次创建顺序返回新的不可变快照;更新条目时保留其位置,删除后再创建则追加为新条目。 + +每条存储行都携带检查所得 Session header 身份 `{createdAt, cwd}`。不匹配按不存在处理:`list` 返回空 `items` 数组,`delete` 返回已不存在的后置条件,`put` 可以用绑定当前身份的新行替换陈旧行。这会在复用的 `SessionId` 具有不同 header 身份时形成隔离。fork 使用独立的 Session 身份,不复制反馈伴随记录。 + +`SessionPersistence.inspect()` 提供 cold-safe 观测,不发布或恢复 Agent,也不提交 cold repair。对于没有 live owner 的 Session,系统先用 `listSnapshots()` 判定明确不存在;已进入目录的 Session 若 `inspect()` 失败,仍属于基础设施故障,不会被猜测成 `session-not-found`。`put` 只接受具有指定 `MessageId` 的非空、append-origin `assistant/message`;replacement-origin 消息、仅承载 usage 的空 assistant 记录与非 assistant 记录都返回 `target-not-found`。 + +初步校验后,`put` 在写入伴随记录前建立 durability barrier。身份匹配的 live Session 先通过权威 `ctx.sessions.flush` checkpoint 提交,随后 live 与 cold 路径都会通过 `SessionPersistence.readFrom` 从序列零做物理复读。之后再次校验所得观测的 header 身份与目标。缺少 flush 参与方、身份变化、目标消失或物理读取失败都会阻止伴随记录提交,因此持久反馈绝不会先于其持久目标消息。 + +message feedback 不是 Session 日志内容或 Session 投影。它不发出 `feedback/record` 事件,不进入模型历史,也不触发 `FEEDBACK_ONLY` 遥测释放。 + +## 服务与 Host Remote 契约 + +`TypertRemoteService` 与 `@Remote` 将 `MessageFeedbackService` 的同三个方法发布出去;Host endpoint 名称为 `messageFeedback.list`、`messageFeedback.put` 与 `messageFeedback.delete`。每个方法都返回判别式业务 union:`{ ok: true, value }` 或 `{ ok: false, error }`。存储、损坏或缺少 durability listener 等操作故障会产生 reject,不会被误标为业务错误。 + +| 方法 | 请求 | 成功 `value` | 拒绝的 `error.code` | +|---|---|---|---| +| `list` | `MessageFeedbackListRequest { sessionId }` | `MessageFeedbackListValue { items }` | `session-not-found` | +| `put` | `MessageFeedbackPutRequest { sessionId, messageId, rating, note?, ifVersion }` | 已提交的 `MessageFeedbackItem` | `session-not-found`、`target-not-found`、`version-conflict`、`note-blank`、`note-too-large` | +| `delete` | `MessageFeedbackDeleteRequest { sessionId, messageId, ifVersion }` | `MessageFeedbackDeleteValue { absent: true }` | `session-not-found`、`version-conflict` | + +`MessageFeedbackVersionConflict` 返回权威 `current` 条目;条目不存在时为 `null`。调用方无需额外执行 `list`,即可协调当前 rating、note 与 version。`MessageFeedbackNoteTooLarge` 同时返回 `maxBytes` 与 `actualBytes`。客户端 Remote 聚合尚未挂载生成的客户端 contribution;Host 调用方无需该客户端组装即可使用 service/Remote 契约。 + +## Compare-and-set 与幂等性 + +`ifVersion: null` 表示仅当条目不存在时才创建;已有条目的每次请求都必须与其当前 version 完全一致,即使目标值已经相同、不会产生实质更新。检查按消息而非按 Session 进行,因此修改一个条目不会与另一个条目冲突。每次实质创建或更新都会分配新的 opaque UUID token,防止陈旧写入穿过 ABA 值循环。 + +携带匹配 version 的无变化请求会返回已存条目,version 与时间戳均不变。成功响应丢失后,使用旧 token 重试会得到 `version-conflict.current`;调用方无需额外读取,即可把权威当前值与目标值比较。条目已不存在时,`delete` 忽略 `ifVersion`;成功后始终返回稳定的 `{ absent: true }` 后置条件。 + +按 Session 划分的 promise 队列覆盖检查、持久性校验、伴随记录读取、比较与整行写入。这些语义会串行化经由同一服务实例的并发变更;storage-domain 自身没有跨进程条件写。 + +Plugin disposal 会先关闭变更接纳,排空已进入各个 Session 队列的所有操作,然后才关闭 storage domain。disposal 开始后提交的变更会以生命周期故障拒绝,不会进入正在关闭的 domain。 + +## 模型体验 + +### 本地消息反馈状态 + +#### 模型看到的内容 + +无。`ctx.messageFeedback` 不注册工具、提示词段落、模型可见上下文或 Session 事件;除非另一个具有独立文档的 Consumer 显式公开反馈,否则它只留在 Host 拥有的伴随记录中。 + +#### Token 影响 + +为零。本包的请求、结果、评分、备注、时间戳或失败都不会进入模型请求。 + +#### KV Cache 影响 + +相互独立。读取或变更消息反馈不会触碰模型请求前缀,也不会使本可复用的提供方缓存条目失效。 + +## 已知局限与延后工作 + +- **缺少客户端聚合与 UI**——Host Remote 契约已经发布,但客户端 Remote 聚合 contribution 与任何 UI 消费方由各自边界负责并保持延后。 +- **Compare-and-set 仅限单进程**——按 Session 划分的队列只串行化一个服务实例;storage-domain 不提供跨进程条件写,因此多个 Host 进程写入同一存储根目录时仍可能丢失更新。 +- **没有持久 Session 删除级联**——Session persistence 没有删除接口,且 `session/disposed`/`host/session-removed` 表示 detach 而非持久删除。因此服务会保留空行,并可能在带外移除日志后留下遗留行,而不会在 detach 时删除仍有效的反馈。 +- **Detach/catalog retirement 窗口**——请求若恰好落在 live detach 之后、persistence catalog 物化 header 之前的极短窗口,可能收到 `session-not-found`;调用方应在 retirement materialization 后重试。 +- **Header 身份不是内容指纹**——只有 `{createdAt, cwd}` 不同时才能识别复用;本契约无法区分保留相同 header 身份的克隆日志。 +- **调用方边界受信任**——`list`/`put`/`delete` 不携带已认证的 actor 或审计身份。在加入授权与归属信息前,部署方必须只通过受信任或另行认证的边界暴露 Host gateway。 +- **目录与行边界**——由于 persistence 没有按 id 读取元数据的操作,cold 请求会扫描完整的 Session snapshot 目录。`maxNoteBytes` 只限制单条备注,单个 Session 行的条目数和聚合保留字节尚无上限;按索引读取元数据和由部署决定的行边界,延后到具体消费方明确策略时处理。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/index.js new file mode 100644 index 0000000..2a2f0d5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/index.js @@ -0,0 +1,420 @@ +import { Buffer } from "node:buffer"; +import { randomUUID } from "node:crypto"; +import { Service } from "@deepseek-ai/cordis"; +import s from "@deepseek-ai/schemastery"; +import { deriveEventMessage, isAppendSurfaceEvent } from "@deepseek-ai/dsh-session/surface"; +import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol"; +import { z } from "zod"; +import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain"; +//#region lib/types/spec.js +/** +* Durable storage-domain declaration for lifecycle-bound message feedback. +* @module @deepseek-ai/dsh-message-feedback/src/spec +*/ +const nonNegativeSafeInteger = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER); +/** Runtime schema for the closed rating vocabulary. */ +const messageFeedbackRatingSchema = z.union([z.literal("positive"), z.literal("negative")]); +/** Runtime schema for one opaque item version stored on disk. */ +const messageFeedbackVersionSchema = z.uuid().transform((value) => value); +/** Runtime schema for one current feedback item. */ +const messageFeedbackItemSchema = z.object({ + messageId: z.string().min(1).transform((value) => value), + rating: messageFeedbackRatingSchema, + note: z.string().refine((note) => note.trim().length > 0, { message: "message feedback note must contain a non-whitespace character" }).optional(), + version: messageFeedbackVersionSchema, + createdAt: nonNegativeSafeInteger, + updatedAt: nonNegativeSafeInteger +}).refine((item) => item.updatedAt >= item.createdAt, { + path: ["updatedAt"], + message: "message feedback updatedAt must not precede createdAt" +}); +/** Persisted Session fields that fence a sidecar row to one log lifecycle. */ +const messageFeedbackSessionIdentitySchema = z.object({ + createdAt: nonNegativeSafeInteger, + cwd: z.string().optional() +}); +/** +* One whole-Session sidecar. Duplicate message ids would make item lookup +* ambiguous; duplicate versions would break their independent identity. +*/ +const messageFeedbackRowSchema = z.object({ + session: messageFeedbackSessionIdentitySchema, + items: z.array(messageFeedbackItemSchema) +}).superRefine((row, ctx) => { + const messageIds = /* @__PURE__ */ new Set(); + const versions = /* @__PURE__ */ new Set(); + row.items.forEach((item, index) => { + if (messageIds.has(item.messageId)) ctx.addIssue({ + code: "custom", + path: [ + "items", + index, + "messageId" + ], + message: `duplicate message feedback id '${item.messageId}'` + }); + messageIds.add(item.messageId); + if (versions.has(item.version)) ctx.addIssue({ + code: "custom", + path: [ + "items", + index, + "version" + ], + message: `duplicate message feedback version '${item.version}'` + }); + versions.add(item.version); + }); +}); +/** One lifecycle-bound sidecar record per Session id. */ +const messageFeedbackDomainSpec = defineDomain({ + name: "message_feedback", + version: 0, + tables: { sessions: domainTable(messageFeedbackRowSchema) } +}); +//#endregion +//#region lib/types/index.js +/** +* Durable, lifecycle-bound feedback for finalized assistant messages. +* @module @deepseek-ai/dsh-message-feedback +*/ +var __runInitializers = function(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + return useValue ? value : void 0; +}; +var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function(f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +/** Immutable empty list reused only as an input to caller-owned copying. */ +const EMPTY_ITEMS = Object.freeze([]); +/** Validate the one deployment-varying limit at the configuration boundary. */ +function resolveMaxNoteBytes(value) { + if (!Number.isSafeInteger(value) || value < 1) throw new TypeError(`message-feedback: maxNoteBytes must be a positive safe integer, got ${String(value)}`); + return value; +} +/** Copy and freeze one item before it crosses the service boundary. */ +function snapshotItem(item) { + return Object.freeze({ + messageId: item.messageId, + rating: item.rating, + ...item.note === void 0 ? {} : { note: item.note }, + version: item.version, + createdAt: item.createdAt, + updatedAt: item.updatedAt + }); +} +/** Copy and freeze a list response. */ +function snapshotList(items) { + return Object.freeze({ items: Object.freeze(items.map(snapshotItem)) }); +} +/** Build a frozen success branch. */ +function success(value) { + return Object.freeze({ + ok: true, + value + }); +} +/** Build a frozen business-failure branch. */ +function rejected(error) { + return Object.freeze({ + ok: false, + error: Object.freeze(error) + }); +} +/** Project the Session fields that distinguish one persisted log lifecycle. */ +function identityOf(header) { + return Object.freeze({ + createdAt: header.createdAt, + ...header.cwd === void 0 ? {} : { cwd: header.cwd } + }); +} +/** Whether a stored row belongs to the inspected Session lifecycle. */ +function sameIdentity(row, header) { + return row.session.createdAt === header.createdAt && row.session.cwd === header.cwd; +} +/** Whether two observations name the same persisted Session lifecycle. */ +function sameHeaderIdentity(left, right) { + return left.id === right.id && left.createdAt === right.createdAt && left.cwd === right.cwd; +} +/** Freeze the replacement row so storage-domain never exposes mutable aliases. */ +function rowSnapshot(session, items) { + const copiedItems = items.map(snapshotItem); + Object.freeze(copiedItems); + return Object.freeze({ + session, + items: copiedItems + }); +} +/** Generate an opaque equality token for one material mutation. */ +function nextVersion() { + return randomUUID(); +} +/** +* Storage-domain sidecar service. It inspects persisted Session history and +* never creates or resumes an Agent or Session. +*/ +let MessageFeedbackService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + let _put_decorators; + let _delete_decorators; + return class MessageFeedbackService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote("list")]; + _put_decorators = [Remote("put")]; + _delete_decorators = [Remote("delete")]; + __esDecorate(this, null, _list_decorators, { + kind: "method", + name: "list", + static: false, + private: false, + access: { + has: (obj) => "list" in obj, + get: (obj) => obj.list + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _put_decorators, { + kind: "method", + name: "put", + static: false, + private: false, + access: { + has: (obj) => "put" in obj, + get: (obj) => obj.put + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _delete_decorators, { + kind: "method", + name: "delete", + static: false, + private: false, + access: { + has: (obj) => "delete" in obj, + get: (obj) => obj.delete + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { + enumerable: true, + configurable: true, + writable: true, + value: _metadata + }); + } + static inject = [ + "storageDomain", + "sessionPersistence", + "sessions" + ]; + /** Loader validation for the required note-size policy. */ + static Config = s.object({ maxNoteBytes: s.number().step(1).min(1).required() }); + maxNoteBytes = __runInitializers(this, _instanceExtraInitializers); + table; + operationTails = /* @__PURE__ */ new Map(); + mutationAdmissionOpen = true; + /** + * @param ctx - Host context carrying persistence and the storage-domain form. + * @param config - Required note-size policy. + */ + constructor(ctx, config) { + super(ctx, "messageFeedback"); + this.maxNoteBytes = resolveMaxNoteBytes(config.maxNoteBytes); + } + /** Open and own the one message-feedback sidecar domain. */ + async [Service.init]() { + const domain = await this.ctx.storageDomain.open(messageFeedbackDomainSpec); + this.ctx.effect(() => async () => { + this.mutationAdmissionOpen = false; + await Promise.all(this.operationTails.values()); + await domain.close(); + }, "message-feedback.domainClose"); + this.table = domain.table("sessions"); + } + /** + * Read feedback belonging to the current persisted Session lifecycle. + * A stale row from a reused Session id is invisible. + * @param request - Session identity to inspect and list. + * @returns current immutable items or `session-not-found`. + */ + async list(request) { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) return known; + const row = this.requireTable().get(request.sessionId); + return success(snapshotList(row !== void 0 && sameIdentity(row, known.value.meta) ? row.items : EMPTY_ITEMS)); + } + /** + * Create or replace feedback for one derived append-origin assistant + * message. Every request must match the addressed item's current version; + * a matching no-op returns the stored item without changing its revision. + * @param request - target, desired value, and observed item version. + * @returns the committed item or an explicit business failure. + */ + put(request) { + const note = this.resolveNote(request.note); + if (!note.ok) return Promise.resolve(note); + return this.enqueue(request.sessionId, async () => { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) return known; + if (!this.hasFeedbackTarget(known.value, request.messageId)) return rejected({ + code: "target-not-found", + sessionId: request.sessionId, + messageId: request.messageId + }); + const durable = await this.ensureTargetDurable(known.value); + if (!sameHeaderIdentity(durable.meta, known.value.meta) || !this.hasFeedbackTarget(durable, request.messageId)) return rejected({ + code: "target-not-found", + sessionId: request.sessionId, + messageId: request.messageId + }); + const table = this.requireTable(); + const stored = table.get(request.sessionId); + const items = (stored !== void 0 && sameIdentity(stored, durable.meta) ? stored : void 0)?.items ?? EMPTY_ITEMS; + const index = items.findIndex((item) => item.messageId === request.messageId); + const existing = items[index]; + if (request.ifVersion !== (existing?.version ?? null)) return rejected(this.versionConflict(existing ?? null)); + if (existing !== void 0 && existing.rating === request.rating && existing.note === note.value) return success(snapshotItem(existing)); + const now = Date.now(); + const item = snapshotItem({ + messageId: request.messageId, + rating: request.rating, + ...note.value === void 0 ? {} : { note: note.value }, + version: nextVersion(), + createdAt: existing?.createdAt ?? now, + updatedAt: existing === void 0 ? now : Math.max(now, existing.updatedAt) + }); + const nextItems = [...items]; + if (index === -1) nextItems.push(item); + else nextItems[index] = item; + await table.put(request.sessionId, rowSnapshot(identityOf(durable.meta), nextItems)); + return success(snapshotItem(item)); + }); + } + /** + * Delete one feedback item. Absence is successful regardless of the + * supplied version; an existing item requires an exact version match. + * @param request - Session, message, and observed item version. + * @returns the stable absent postcondition, or an explicit failure. + */ + delete(request) { + return this.enqueue(request.sessionId, async () => { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) return known; + const table = this.requireTable(); + const stored = table.get(request.sessionId); + const items = (stored !== void 0 && sameIdentity(stored, known.value.meta) ? stored : void 0)?.items ?? EMPTY_ITEMS; + const existing = items.find((item) => item.messageId === request.messageId); + if (existing === void 0) return success(Object.freeze({ absent: true })); + if (request.ifVersion !== existing.version) return rejected(this.versionConflict(existing)); + await table.put(request.sessionId, rowSnapshot(identityOf(known.value.meta), items.filter((item) => item !== existing))); + return success(Object.freeze({ absent: true })); + }); + } + /** + * Resolve a live owner directly; otherwise use the storage catalog as the + * existence authority before inspecting the log. Inspection failures for a + * catalogued Session remain infrastructure failures rather than being + * guessed into the business `session-not-found` branch. + */ + async inspectSession(sessionId) { + if (this.ctx.sessions.get(sessionId) === void 0) { + if (!(await this.ctx.sessionPersistence.listSnapshots()).some((snapshot) => snapshot.header.id === sessionId) && this.ctx.sessions.get(sessionId) === void 0) return rejected({ + code: "session-not-found", + sessionId + }); + } + return success(await this.ctx.sessionPersistence.inspect(sessionId)); + } + /** Require the exact finalized append-origin assistant message projection. */ + hasFeedbackTarget(inspection, messageId) { + return inspection.events.some((event) => { + if (event.type !== "assistant/message" || !isAppendSurfaceEvent(event)) return false; + const message = deriveEventMessage(event); + return message?.role === "assistant" && message.id === messageId; + }); + } + /** + * Put the target log prefix behind a durability barrier before its sidecar. + * A live owner flushes through the SessionStore's canonical checkpoint; a + * cold owner is re-read from the physical durable prefix. + */ + async ensureTargetDurable(inspection) { + const live = this.ctx.sessions.get(inspection.meta.id); + if (live !== void 0 && sameHeaderIdentity(live.header, inspection.meta)) { + if (!await this.ctx.sessions.flush(live)) throw new Error(`message-feedback: no durability listener participated for live session '${inspection.meta.id}'`); + return await this.ctx.sessionPersistence.readFrom(inspection.meta.id, 0); + } + return await this.ctx.sessionPersistence.readFrom(inspection.meta.id, 0); + } + /** Validate optional-note semantics and the configured complete UTF-8 byte bound. */ + resolveNote(note) { + if (note === void 0) return success(void 0); + if (note.trim().length === 0) return rejected({ code: "note-blank" }); + const actualBytes = Buffer.byteLength(note, "utf8"); + if (actualBytes > this.maxNoteBytes) return rejected({ + code: "note-too-large", + maxBytes: this.maxNoteBytes, + actualBytes + }); + return success(note); + } + /** Return the authoritative item needed to reconcile one failed comparison. */ + versionConflict(current) { + return { + code: "version-conflict", + current: current === null ? null : snapshotItem(current) + }; + } + /** Queue a complete read/compare/write mutation behind this Session's prior mutation. */ + enqueue(sessionId, operation) { + if (!this.mutationAdmissionOpen) return Promise.reject(/* @__PURE__ */ new Error("message-feedback: service is disposing")); + const result = (this.operationTails.get(sessionId) ?? Promise.resolve()).then(operation); + const tail = result.then(() => void 0, () => void 0); + this.operationTails.set(sessionId, tail); + return result.finally(() => { + if (this.operationTails.get(sessionId) === tail) this.operationTails.delete(sessionId); + }); + } + /** Resolve the initialized durable table or fail a broken service lifecycle. */ + requireTable() { + if (this.table === void 0) throw new Error("message-feedback: durable domain is not initialized"); + return this.table; + } + }; +})(); +//#endregion +export { MessageFeedbackService, MessageFeedbackService as default, messageFeedbackDomainSpec, messageFeedbackItemSchema, messageFeedbackRatingSchema, messageFeedbackRowSchema, messageFeedbackSessionIdentitySchema, messageFeedbackVersionSchema }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/invariant.js new file mode 100644 index 0000000..5bc9b7b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/invariant.js @@ -0,0 +1,20 @@ +//#region lib/types/invariant.js +/** Package-owned invariant companion. @module @deepseek-ai/dsh-message-feedback/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-message-feedback"; +/** Cordis companion plugin name. */ +const name = "message-feedback-invariant"; +/** Services required before the companion can reserve and check package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the private typed writer owns current row mutations, +* the domain schema validates rows on reopen, and no second authority exists. +*/ +const install = Object.assign(() => {}, { inject: ["messageFeedback"] }); +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.d.ts new file mode 100644 index 0000000..dcf4919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.d.ts @@ -0,0 +1,3 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ + +export declare const TYPERT: unknown diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.js new file mode 100644 index 0000000..6f68965 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.js @@ -0,0 +1,307 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'ifVersion': z.intersection(z.string(), z.unknown()).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'absent': z.literal(true).readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.union([z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("version-conflict").readonly(), + 'current': z.union([z.literal(null), z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})]).readonly(), +})]).readonly(), +})]) +const _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'items': z.array(z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})).readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}).readonly(), +})]) +const _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'ifVersion': z.union([z.literal(null), z.intersection(z.string(), z.unknown())]).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.union([z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("target-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("version-conflict").readonly(), + 'current': z.union([z.literal(null), z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})]).readonly(), +}), z.object({ + 'code': z.literal("note-blank").readonly(), +}), z.object({ + 'code': z.literal("note-too-large").readonly(), + 'maxBytes': z.number().readonly(), + 'actualBytes': z.number().readonly(), +})]).readonly(), +})]) + +export const TYPERT = { + package: '@deepseek-ai/dsh-message-feedback', + face: 'host', + schemas: [ + ], + invocations: [ + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/delete', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'delete', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":272,"column":3}, + }, + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/list', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'list', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":190,"column":9}, + }, + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/put', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'put', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":206,"column":3}, + }, + ], + model: { + "services": [ + { + "description": "Storage-domain sidecar service. It inspects persisted Session history and never creates or resumes an Agent or Session.", + "summary": "Storage-domain sidecar service.", + "tags": [], + "jsDoc": "/**\n * Storage-domain sidecar service. It inspects persisted Session history and\n * never creates or resumes an Agent or Session.\n */", + "key": "messageFeedback", + "exportName": "MessageFeedbackService", + "members": [ + { + "kind": "method", + "name": "list", + "signature": "@Remote('list') async list(request: MessageFeedbackListRequest): Promise", + "summary": "Read feedback belonging to the current persisted Session lifecycle.", + "jsDoc": "/**\n * Read feedback belonging to the current persisted Session lifecycle.\n * A stale row from a reused Session id is invisible.\n * @param request - Session identity to inspect and list.\n * @returns current immutable items or `session-not-found`.\n */" + }, + { + "kind": "method", + "name": "put", + "signature": "@Remote('put') put(request: MessageFeedbackPutRequest): Promise", + "summary": "Create or replace feedback for one derived append-origin assistant message.", + "jsDoc": "/**\n * Create or replace feedback for one derived append-origin assistant\n * message. Every request must match the addressed item's current version;\n * a matching no-op returns the stored item without changing its revision.\n * @param request - target, desired value, and observed item version.\n * @returns the committed item or an explicit business failure.\n */" + }, + { + "kind": "method", + "name": "delete", + "signature": "@Remote('delete') delete(request: MessageFeedbackDeleteRequest): Promise", + "summary": "Delete one feedback item.", + "jsDoc": "/**\n * Delete one feedback item. Absence is successful regardless of the\n * supplied version; an existing item requires an exact version match.\n * @param request - Session, message, and observed item version.\n * @returns the stable absent postcondition, or an explicit failure.\n */" + } + ], + "types": [ + { + "name": "Branded", + "declaration": "export type Branded = string & { readonly [BRAND]: B; };" + }, + { + "name": "MessageFeedbackDeleteRequest", + "declaration": "export interface MessageFeedbackDeleteRequest {\n readonly sessionId: SessionId;\n readonly messageId: MessageId;\n readonly ifVersion: MessageFeedbackVersion;\n}" + }, + { + "name": "MessageFeedbackDeleteResult", + "declaration": "export type MessageFeedbackDeleteResult = MessageFeedbackSuccess | MessageFeedbackRejected;" + }, + { + "name": "MessageFeedbackDeleteValue", + "declaration": "export interface MessageFeedbackDeleteValue {\n readonly absent: true;\n}" + }, + { + "name": "MessageFeedbackFailure", + "declaration": "export type MessageFeedbackFailure = MessageFeedbackSessionNotFound | MessageFeedbackTargetNotFound | MessageFeedbackVersionConflict | MessageFeedbackNoteBlank | MessageFeedbackNoteTooLarge;" + }, + { + "name": "MessageFeedbackItem", + "declaration": "export interface MessageFeedbackItem {\n readonly messageId: MessageId;\n readonly rating: MessageFeedbackRating;\n readonly note?: string;\n readonly version: MessageFeedbackVersion;\n readonly createdAt: number;\n readonly updatedAt: number;\n}" + }, + { + "name": "MessageFeedbackListRequest", + "declaration": "export interface MessageFeedbackListRequest {\n readonly sessionId: SessionId;\n}" + }, + { + "name": "MessageFeedbackListResult", + "declaration": "export type MessageFeedbackListResult = MessageFeedbackSuccess | MessageFeedbackRejected;" + }, + { + "name": "MessageFeedbackListValue", + "declaration": "export interface MessageFeedbackListValue {\n readonly items: readonly MessageFeedbackItem[];\n}" + }, + { + "name": "MessageFeedbackNoteBlank", + "declaration": "export interface MessageFeedbackNoteBlank {\n readonly code: 'note-blank';\n}" + }, + { + "name": "MessageFeedbackNoteTooLarge", + "declaration": "export interface MessageFeedbackNoteTooLarge {\n readonly code: 'note-too-large';\n readonly maxBytes: number;\n readonly actualBytes: number;\n}" + }, + { + "name": "MessageFeedbackPutRequest", + "declaration": "export interface MessageFeedbackPutRequest {\n readonly sessionId: SessionId;\n readonly messageId: MessageId;\n readonly rating: MessageFeedbackRating;\n readonly note?: string;\n readonly ifVersion: MessageFeedbackVersion | null;\n}" + }, + { + "name": "MessageFeedbackPutResult", + "declaration": "export type MessageFeedbackPutResult = MessageFeedbackSuccess | MessageFeedbackRejected;" + }, + { + "name": "MessageFeedbackRating", + "declaration": "export type MessageFeedbackRating = 'positive' | 'negative';" + }, + { + "name": "MessageFeedbackRejected", + "declaration": "export interface MessageFeedbackRejected {\n readonly ok: false;\n readonly error: E;\n}" + }, + { + "name": "MessageFeedbackSessionNotFound", + "declaration": "export interface MessageFeedbackSessionNotFound {\n readonly code: 'session-not-found';\n readonly sessionId: SessionId;\n}" + }, + { + "name": "MessageFeedbackSuccess", + "declaration": "export interface MessageFeedbackSuccess {\n readonly ok: true;\n readonly value: T;\n}" + }, + { + "name": "MessageFeedbackTargetNotFound", + "declaration": "export interface MessageFeedbackTargetNotFound {\n readonly code: 'target-not-found';\n readonly sessionId: SessionId;\n readonly messageId: MessageId;\n}" + }, + { + "name": "MessageFeedbackVersion", + "declaration": "export type MessageFeedbackVersion = Branded<'MessageFeedbackVersion'>;" + }, + { + "name": "MessageFeedbackVersionConflict", + "declaration": "export interface MessageFeedbackVersionConflict {\n readonly code: 'version-conflict';\n readonly current: MessageFeedbackItem | null;\n}" + }, + { + "name": "MessageId", + "declaration": "export type MessageId = Branded<'MessageId'>;" + }, + { + "name": "SessionId", + "declaration": "export type SessionId = Branded<'SessionId'>;" + } + ] + } + ], + "events": [], + "objects": [] + }, +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.d.ts new file mode 100644 index 0000000..c4616a2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.d.ts @@ -0,0 +1,26 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import type { + RemoteResult, + TypertRemoteContribution, +} from '@deepseek-ai/dsh-typert-protocol' +import type { MessageFeedbackDeleteRequest, MessageFeedbackDeleteResult, MessageFeedbackListRequest, MessageFeedbackListResult, MessageFeedbackPutRequest, MessageFeedbackPutResult } from '@deepseek-ai/dsh-message-feedback/types' + +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteNamespace$6d657373616765466565646261636b { + delete: (request: MessageFeedbackDeleteRequest) => Promise> + list: (request: MessageFeedbackListRequest) => Promise> + put: (request: MessageFeedbackPutRequest) => Promise> + } + interface TypertRemoteMap { + 'messageFeedback/delete': (request: MessageFeedbackDeleteRequest) => Promise> + 'messageFeedback/list': (request: MessageFeedbackListRequest) => Promise> + 'messageFeedback/put': (request: MessageFeedbackPutRequest) => Promise> + } + interface TypertRemoteNamespaceMap { + 'messageFeedback': TypertRemoteNamespace$6d657373616765466565646261636b + } +} + +export declare const TYPERT_REMOTE: TypertRemoteContribution +export default TYPERT_REMOTE +//# sourceMappingURL=typert.remote-client.d.ts.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.js new file mode 100644 index 0000000..2efd155 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.js @@ -0,0 +1,179 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'ifVersion': z.intersection(z.string(), z.unknown()).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'absent': z.literal(true).readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.union([z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("version-conflict").readonly(), + 'current': z.union([z.literal(null), z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})]).readonly(), +})]).readonly(), +})]) +const _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'items': z.array(z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})).readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}).readonly(), +})]) +const _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'ifVersion': z.union([z.literal(null), z.intersection(z.string(), z.unknown())]).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.union([z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("target-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("version-conflict").readonly(), + 'current': z.union([z.literal(null), z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})]).readonly(), +}), z.object({ + 'code': z.literal("note-blank").readonly(), +}), z.object({ + 'code': z.literal("note-too-large").readonly(), + 'maxBytes': z.number().readonly(), + 'actualBytes': z.number().readonly(), +})]).readonly(), +})]) + +export const TYPERT_REMOTE = { + package: '@deepseek-ai/dsh-message-feedback', + descriptors: [ + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/delete', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'delete', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":272,"column":3}, + }, + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/list', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'list', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":190,"column":9}, + }, + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/put', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'put', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":206,"column":3}, + }, + ], +} + +export default TYPERT_REMOTE diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.d.ts new file mode 100644 index 0000000..d5dd7ae --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.d.ts @@ -0,0 +1,88 @@ +/** + * Durable, lifecycle-bound feedback for finalized assistant messages. + * @module @deepseek-ai/dsh-message-feedback + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import s from '@deepseek-ai/schemastery'; +import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'; +import type { MessageFeedbackDeleteRequest, MessageFeedbackDeleteResult, MessageFeedbackListRequest, MessageFeedbackListResult, MessageFeedbackPutRequest, MessageFeedbackPutResult } from './types.ts'; +export type * from './types.ts'; +export { messageFeedbackDomainSpec, messageFeedbackItemSchema, messageFeedbackRatingSchema, messageFeedbackRowSchema, messageFeedbackSessionIdentitySchema, messageFeedbackVersionSchema, } from './spec.ts'; +export type { MessageFeedbackRow, MessageFeedbackSessionIdentity } from './spec.ts'; +/** Required deployment policy for optional notes. */ +export interface Config { + /** Maximum UTF-8 byte length accepted for one note. */ + readonly maxNoteBytes: number; +} +declare module '@deepseek-ai/cordis' { + interface Context { + messageFeedback: MessageFeedbackService; + } +} +/** + * Storage-domain sidecar service. It inspects persisted Session history and + * never creates or resumes an Agent or Session. + */ +export declare class MessageFeedbackService extends TypertRemoteService { + static inject: string[]; + /** Loader validation for the required note-size policy. */ + static Config: s; + private readonly maxNoteBytes; + private table?; + private readonly operationTails; + private mutationAdmissionOpen; + /** + * @param ctx - Host context carrying persistence and the storage-domain form. + * @param config - Required note-size policy. + */ + constructor(ctx: Context, config: Config); + /** Open and own the one message-feedback sidecar domain. */ + protected [Service.init](): Promise; + /** + * Read feedback belonging to the current persisted Session lifecycle. + * A stale row from a reused Session id is invisible. + * @param request - Session identity to inspect and list. + * @returns current immutable items or `session-not-found`. + */ + list(request: MessageFeedbackListRequest): Promise; + /** + * Create or replace feedback for one derived append-origin assistant + * message. Every request must match the addressed item's current version; + * a matching no-op returns the stored item without changing its revision. + * @param request - target, desired value, and observed item version. + * @returns the committed item or an explicit business failure. + */ + put(request: MessageFeedbackPutRequest): Promise; + /** + * Delete one feedback item. Absence is successful regardless of the + * supplied version; an existing item requires an exact version match. + * @param request - Session, message, and observed item version. + * @returns the stable absent postcondition, or an explicit failure. + */ + delete(request: MessageFeedbackDeleteRequest): Promise; + /** + * Resolve a live owner directly; otherwise use the storage catalog as the + * existence authority before inspecting the log. Inspection failures for a + * catalogued Session remain infrastructure failures rather than being + * guessed into the business `session-not-found` branch. + */ + private inspectSession; + /** Require the exact finalized append-origin assistant message projection. */ + private hasFeedbackTarget; + /** + * Put the target log prefix behind a durability barrier before its sidecar. + * A live owner flushes through the SessionStore's canonical checkpoint; a + * cold owner is re-read from the physical durable prefix. + */ + private ensureTargetDurable; + /** Validate optional-note semantics and the configured complete UTF-8 byte bound. */ + private resolveNote; + /** Return the authoritative item needed to reconcile one failed comparison. */ + private versionConflict; + /** Queue a complete read/compare/write mutation behind this Session's prior mutation. */ + private enqueue; + /** Resolve the initialized durable table or fail a broken service lifecycle. */ + private requireTable; +} +export default MessageFeedbackService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.js new file mode 100644 index 0000000..918b29d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.js @@ -0,0 +1,342 @@ +/** + * Durable, lifecycle-bound feedback for finalized assistant messages. + * @module @deepseek-ai/dsh-message-feedback + */ +var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; +var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +import { Buffer } from 'node:buffer'; +import { randomUUID } from 'node:crypto'; +import { Service } from '@deepseek-ai/cordis'; +import s from '@deepseek-ai/schemastery'; +import { deriveEventMessage, isAppendSurfaceEvent } from '@deepseek-ai/dsh-session/surface'; +import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'; +import { messageFeedbackDomainSpec } from "./spec.js"; +export { messageFeedbackDomainSpec, messageFeedbackItemSchema, messageFeedbackRatingSchema, messageFeedbackRowSchema, messageFeedbackSessionIdentitySchema, messageFeedbackVersionSchema, } from "./spec.js"; +/** Immutable empty list reused only as an input to caller-owned copying. */ +const EMPTY_ITEMS = Object.freeze([]); +/** Validate the one deployment-varying limit at the configuration boundary. */ +function resolveMaxNoteBytes(value) { + if (!Number.isSafeInteger(value) || value < 1) { + throw new TypeError(`message-feedback: maxNoteBytes must be a positive safe integer, got ${String(value)}`); + } + return value; +} +/** Copy and freeze one item before it crosses the service boundary. */ +function snapshotItem(item) { + return Object.freeze({ + messageId: item.messageId, + rating: item.rating, + ...(item.note === undefined ? {} : { note: item.note }), + version: item.version, + createdAt: item.createdAt, + updatedAt: item.updatedAt, + }); +} +/** Copy and freeze a list response. */ +function snapshotList(items) { + return Object.freeze({ items: Object.freeze(items.map(snapshotItem)) }); +} +/** Build a frozen success branch. */ +function success(value) { + return Object.freeze({ ok: true, value }); +} +/** Build a frozen business-failure branch. */ +function rejected(error) { + return Object.freeze({ ok: false, error: Object.freeze(error) }); +} +/** Project the Session fields that distinguish one persisted log lifecycle. */ +function identityOf(header) { + return Object.freeze({ + createdAt: header.createdAt, + ...(header.cwd === undefined ? {} : { cwd: header.cwd }), + }); +} +/** Whether a stored row belongs to the inspected Session lifecycle. */ +function sameIdentity(row, header) { + return row.session.createdAt === header.createdAt && row.session.cwd === header.cwd; +} +/** Whether two observations name the same persisted Session lifecycle. */ +function sameHeaderIdentity(left, right) { + return left.id === right.id && left.createdAt === right.createdAt && left.cwd === right.cwd; +} +/** Freeze the replacement row so storage-domain never exposes mutable aliases. */ +function rowSnapshot(session, items) { + const copiedItems = items.map(snapshotItem); + Object.freeze(copiedItems); + return Object.freeze({ + session, + items: copiedItems, + }); +} +/** Generate an opaque equality token for one material mutation. */ +function nextVersion() { + return randomUUID(); +} +/** + * Storage-domain sidecar service. It inspects persisted Session history and + * never creates or resumes an Agent or Session. + */ +let MessageFeedbackService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + let _put_decorators; + let _delete_decorators; + return class MessageFeedbackService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote('list')]; + _put_decorators = [Remote('put')]; + _delete_decorators = [Remote('delete')]; + __esDecorate(this, null, _list_decorators, { kind: "method", name: "list", static: false, private: false, access: { has: obj => "list" in obj, get: obj => obj.list }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _put_decorators, { kind: "method", name: "put", static: false, private: false, access: { has: obj => "put" in obj, get: obj => obj.put }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _delete_decorators, { kind: "method", name: "delete", static: false, private: false, access: { has: obj => "delete" in obj, get: obj => obj.delete }, metadata: _metadata }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + static inject = ['storageDomain', 'sessionPersistence', 'sessions']; + /** Loader validation for the required note-size policy. */ + static Config = s.object({ + maxNoteBytes: s.number().step(1).min(1).required(), + }); + maxNoteBytes = __runInitializers(this, _instanceExtraInitializers); + table; + operationTails = new Map(); + mutationAdmissionOpen = true; + /** + * @param ctx - Host context carrying persistence and the storage-domain form. + * @param config - Required note-size policy. + */ + constructor(ctx, config) { + super(ctx, 'messageFeedback'); + this.maxNoteBytes = resolveMaxNoteBytes(config.maxNoteBytes); + } + /** Open and own the one message-feedback sidecar domain. */ + async [Service.init]() { + const domain = await this.ctx.storageDomain.open(messageFeedbackDomainSpec); + this.ctx.effect(() => async () => { + this.mutationAdmissionOpen = false; + await Promise.all(this.operationTails.values()); + await domain.close(); + }, 'message-feedback.domainClose'); + this.table = domain.table('sessions'); + } + /** + * Read feedback belonging to the current persisted Session lifecycle. + * A stale row from a reused Session id is invisible. + * @param request - Session identity to inspect and list. + * @returns current immutable items or `session-not-found`. + */ + async list(request) { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) + return known; + const row = this.requireTable().get(request.sessionId); + const items = row !== undefined && sameIdentity(row, known.value.meta) ? row.items : EMPTY_ITEMS; + return success(snapshotList(items)); + } + /** + * Create or replace feedback for one derived append-origin assistant + * message. Every request must match the addressed item's current version; + * a matching no-op returns the stored item without changing its revision. + * @param request - target, desired value, and observed item version. + * @returns the committed item or an explicit business failure. + */ + put(request) { + const note = this.resolveNote(request.note); + if (!note.ok) + return Promise.resolve(note); + return this.enqueue(request.sessionId, async () => { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) + return known; + if (!this.hasFeedbackTarget(known.value, request.messageId)) { + return rejected({ + code: 'target-not-found', + sessionId: request.sessionId, + messageId: request.messageId, + }); + } + const durable = await this.ensureTargetDurable(known.value); + if (!sameHeaderIdentity(durable.meta, known.value.meta) + || !this.hasFeedbackTarget(durable, request.messageId)) { + return rejected({ + code: 'target-not-found', + sessionId: request.sessionId, + messageId: request.messageId, + }); + } + const table = this.requireTable(); + const stored = table.get(request.sessionId); + const current = stored !== undefined && sameIdentity(stored, durable.meta) ? stored : undefined; + const items = current?.items ?? EMPTY_ITEMS; + const index = items.findIndex(item => item.messageId === request.messageId); + const existing = items[index]; + if (request.ifVersion !== (existing?.version ?? null)) { + return rejected(this.versionConflict(existing ?? null)); + } + if (existing !== undefined + && existing.rating === request.rating + && existing.note === note.value) { + return success(snapshotItem(existing)); + } + const now = Date.now(); + const item = snapshotItem({ + messageId: request.messageId, + rating: request.rating, + ...(note.value === undefined ? {} : { note: note.value }), + version: nextVersion(), + createdAt: existing?.createdAt ?? now, + updatedAt: existing === undefined ? now : Math.max(now, existing.updatedAt), + }); + const nextItems = [...items]; + if (index === -1) + nextItems.push(item); + else + nextItems[index] = item; + await table.put(request.sessionId, rowSnapshot(identityOf(durable.meta), nextItems)); + return success(snapshotItem(item)); + }); + } + /** + * Delete one feedback item. Absence is successful regardless of the + * supplied version; an existing item requires an exact version match. + * @param request - Session, message, and observed item version. + * @returns the stable absent postcondition, or an explicit failure. + */ + delete(request) { + return this.enqueue(request.sessionId, async () => { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) + return known; + const table = this.requireTable(); + const stored = table.get(request.sessionId); + const current = stored !== undefined && sameIdentity(stored, known.value.meta) ? stored : undefined; + const items = current?.items ?? EMPTY_ITEMS; + const existing = items.find(item => item.messageId === request.messageId); + if (existing === undefined) { + return success(Object.freeze({ absent: true })); + } + if (request.ifVersion !== existing.version) { + return rejected(this.versionConflict(existing)); + } + await table.put(request.sessionId, rowSnapshot(identityOf(known.value.meta), items.filter(item => item !== existing))); + return success(Object.freeze({ absent: true })); + }); + } + /** + * Resolve a live owner directly; otherwise use the storage catalog as the + * existence authority before inspecting the log. Inspection failures for a + * catalogued Session remain infrastructure failures rather than being + * guessed into the business `session-not-found` branch. + */ + async inspectSession(sessionId) { + if (this.ctx.sessions.get(sessionId) === undefined) { + const snapshots = await this.ctx.sessionPersistence.listSnapshots(); + if (!snapshots.some(snapshot => snapshot.header.id === sessionId) + && this.ctx.sessions.get(sessionId) === undefined) { + return rejected({ code: 'session-not-found', sessionId }); + } + } + return success(await this.ctx.sessionPersistence.inspect(sessionId)); + } + /** Require the exact finalized append-origin assistant message projection. */ + hasFeedbackTarget(inspection, messageId) { + return inspection.events.some((event) => { + if (event.type !== 'assistant/message' || !isAppendSurfaceEvent(event)) + return false; + const message = deriveEventMessage(event); + return message?.role === 'assistant' && message.id === messageId; + }); + } + /** + * Put the target log prefix behind a durability barrier before its sidecar. + * A live owner flushes through the SessionStore's canonical checkpoint; a + * cold owner is re-read from the physical durable prefix. + */ + async ensureTargetDurable(inspection) { + const live = this.ctx.sessions.get(inspection.meta.id); + if (live !== undefined && sameHeaderIdentity(live.header, inspection.meta)) { + if (!(await this.ctx.sessions.flush(live))) { + throw new Error(`message-feedback: no durability listener participated for live session '${inspection.meta.id}'`); + } + return await this.ctx.sessionPersistence.readFrom(inspection.meta.id, 0); + } + return await this.ctx.sessionPersistence.readFrom(inspection.meta.id, 0); + } + /** Validate optional-note semantics and the configured complete UTF-8 byte bound. */ + resolveNote(note) { + if (note === undefined) + return success(undefined); + if (note.trim().length === 0) + return rejected({ code: 'note-blank' }); + const actualBytes = Buffer.byteLength(note, 'utf8'); + if (actualBytes > this.maxNoteBytes) { + return rejected({ code: 'note-too-large', maxBytes: this.maxNoteBytes, actualBytes }); + } + return success(note); + } + /** Return the authoritative item needed to reconcile one failed comparison. */ + versionConflict(current) { + return { + code: 'version-conflict', + current: current === null ? null : snapshotItem(current), + }; + } + /** Queue a complete read/compare/write mutation behind this Session's prior mutation. */ + enqueue(sessionId, operation) { + if (!this.mutationAdmissionOpen) { + return Promise.reject(new Error('message-feedback: service is disposing')); + } + const previous = this.operationTails.get(sessionId) ?? Promise.resolve(); + const result = previous.then(operation); + const tail = result.then(() => undefined, () => undefined); + this.operationTails.set(sessionId, tail); + return result.finally(() => { + if (this.operationTails.get(sessionId) === tail) + this.operationTails.delete(sessionId); + }); + } + /** Resolve the initialized durable table or fail a broken service lifecycle. */ + requireTable() { + if (this.table === undefined) { + throw new Error('message-feedback: durable domain is not initialized'); + } + return this.table; + } + }; +})(); +export { MessageFeedbackService }; +export default MessageFeedbackService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.d.ts new file mode 100644 index 0000000..0fe4839 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned invariant companion. @module @deepseek-ai/dsh-message-feedback/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "message-feedback-invariant"; +/** Services required before the companion can reserve and check package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.js new file mode 100644 index 0000000..e335eea --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.js @@ -0,0 +1,19 @@ +/** Package-owned invariant companion. @module @deepseek-ai/dsh-message-feedback/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-message-feedback'; +/** Cordis companion plugin name. */ +export const name = 'message-feedback-invariant'; +/** Services required before the companion can reserve and check package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: the private typed writer owns current row mutations, + * the domain schema validates rows on reopen, and no second authority exists. + */ +const install = Object.assign(() => { }, { inject: ['messageFeedback'] }); +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.d.ts new file mode 100644 index 0000000..07f1eb1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.d.ts @@ -0,0 +1,48 @@ +/** + * Durable storage-domain declaration for lifecycle-bound message feedback. + * @module @deepseek-ai/dsh-message-feedback/src/spec + */ +import { z } from 'zod'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { MessageFeedbackItem, MessageFeedbackVersion } from './types.ts'; +/** Runtime schema for the closed rating vocabulary. */ +export declare const messageFeedbackRatingSchema: z.ZodUnion, z.ZodLiteral<"negative">]>; +/** Runtime schema for one opaque item version stored on disk. */ +export declare const messageFeedbackVersionSchema: z.ZodPipe>; +/** Runtime schema for one current feedback item. */ +export declare const messageFeedbackItemSchema: z.ZodType; +/** Persisted Session fields that fence a sidecar row to one log lifecycle. */ +export declare const messageFeedbackSessionIdentitySchema: z.ZodObject<{ + createdAt: z.ZodNumber; + cwd: z.ZodOptional; +}, z.core.$strip>; +/** Persisted lifecycle identity inferred from its durable schema. */ +export type MessageFeedbackSessionIdentity = z.infer; +/** + * One whole-Session sidecar. Duplicate message ids would make item lookup + * ambiguous; duplicate versions would break their independent identity. + */ +export declare const messageFeedbackRowSchema: z.ZodObject<{ + session: z.ZodObject<{ + createdAt: z.ZodNumber; + cwd: z.ZodOptional; + }, z.core.$strip>; + items: z.ZodArray>>; +}, z.core.$strip>; +/** Durable sidecar row inferred from {@link messageFeedbackRowSchema}. */ +export type MessageFeedbackRow = z.infer; +/** One lifecycle-bound sidecar record per Session id. */ +export declare const messageFeedbackDomainSpec: { + name: string; + version: number; + tables: { + sessions: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec; + }; +}; +//# sourceMappingURL=spec.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.js new file mode 100644 index 0000000..7c67536 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.js @@ -0,0 +1,74 @@ +/** + * Durable storage-domain declaration for lifecycle-bound message feedback. + * @module @deepseek-ai/dsh-message-feedback/src/spec + */ +import { z } from 'zod'; +import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'; +const nonNegativeSafeInteger = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER); +/** Runtime schema for the closed rating vocabulary. */ +export const messageFeedbackRatingSchema = z.union([ + z.literal('positive'), + z.literal('negative'), +]); +/** Runtime schema for one opaque item version stored on disk. */ +export const messageFeedbackVersionSchema = z.uuid() + .transform(value => value); +/** Runtime schema for one current feedback item. */ +// Zod infers transformed branded fields structurally, so it cannot name the +// public interface even though every branded output is created below. +export const messageFeedbackItemSchema = z.object({ + messageId: z.string().min(1).transform(value => value), + rating: messageFeedbackRatingSchema, + note: z.string().refine(note => note.trim().length > 0, { + message: 'message feedback note must contain a non-whitespace character', + }).optional(), + version: messageFeedbackVersionSchema, + createdAt: nonNegativeSafeInteger, + updatedAt: nonNegativeSafeInteger, +}).refine(item => item.updatedAt >= item.createdAt, { + path: ['updatedAt'], + message: 'message feedback updatedAt must not precede createdAt', +}); +/** Persisted Session fields that fence a sidecar row to one log lifecycle. */ +export const messageFeedbackSessionIdentitySchema = z.object({ + createdAt: nonNegativeSafeInteger, + cwd: z.string().optional(), +}); +/** + * One whole-Session sidecar. Duplicate message ids would make item lookup + * ambiguous; duplicate versions would break their independent identity. + */ +export const messageFeedbackRowSchema = z.object({ + session: messageFeedbackSessionIdentitySchema, + items: z.array(messageFeedbackItemSchema), +}).superRefine((row, ctx) => { + const messageIds = new Set(); + const versions = new Set(); + row.items.forEach((item, index) => { + if (messageIds.has(item.messageId)) { + ctx.addIssue({ + code: 'custom', + path: ['items', index, 'messageId'], + message: `duplicate message feedback id '${item.messageId}'`, + }); + } + messageIds.add(item.messageId); + if (versions.has(item.version)) { + ctx.addIssue({ + code: 'custom', + path: ['items', index, 'version'], + message: `duplicate message feedback version '${item.version}'`, + }); + } + versions.add(item.version); + }); +}); +/** One lifecycle-bound sidecar record per Session id. */ +export const messageFeedbackDomainSpec = defineDomain({ + name: 'message_feedback', + version: 0, + tables: { + sessions: domainTable(messageFeedbackRowSchema), + }, +}); +//# sourceMappingURL=spec.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.d.ts new file mode 100644 index 0000000..83eca1b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.d.ts @@ -0,0 +1,111 @@ +/** + * Public request, value, and failure vocabulary for per-message feedback. + * This module contains types only so generated Remote clients can consume it + * without importing Host runtime code. + * @module @deepseek-ai/dsh-message-feedback/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +/** Opaque compare-and-set token for one exact feedback item revision. */ +export type MessageFeedbackVersion = Branded<'MessageFeedbackVersion'>; +/** The human's overall judgment of one assistant message. */ +export type MessageFeedbackRating = 'positive' | 'negative'; +/** One current feedback value and its opaque mutation token. */ +export interface MessageFeedbackItem { + /** Stable identity of the assistant message inside the owning Session. */ + readonly messageId: MessageId; + /** Overall positive or negative judgment. */ + readonly rating: MessageFeedbackRating; + /** Optional explanation, preserved verbatim after validation. */ + readonly note?: string; + /** Equality-only token replaced by every material create or update. */ + readonly version: MessageFeedbackVersion; + /** Host-assigned creation time in Unix epoch milliseconds. */ + readonly createdAt: number; + /** Host-assigned time of the most recent material update. */ + readonly updatedAt: number; +} +/** Read all message feedback belonging to one persisted Session lifecycle. */ +export interface MessageFeedbackListRequest { + /** Persisted Session whose sidecar should be read. */ + readonly sessionId: SessionId; +} +/** Current feedback values for one Session, in first-creation order. */ +export interface MessageFeedbackListValue { + /** Fresh immutable item snapshots. */ + readonly items: readonly MessageFeedbackItem[]; +} +/** Create or replace feedback for one assistant message. */ +export interface MessageFeedbackPutRequest { + /** Persisted Session that owns the target message. */ + readonly sessionId: SessionId; + /** Target assistant-message identity. */ + readonly messageId: MessageId; + /** Desired overall judgment. */ + readonly rating: MessageFeedbackRating; + /** Optional non-blank explanation. */ + readonly note?: string; + /** Observed item version, or `null` to require that no item exists. */ + readonly ifVersion: MessageFeedbackVersion | null; +} +/** Delete feedback for one message after observing its current version. */ +export interface MessageFeedbackDeleteRequest { + /** Persisted Session that owns the sidecar. */ + readonly sessionId: SessionId; + /** Message whose feedback should be absent after this operation. */ + readonly messageId: MessageId; + /** Observed item version; ignored when the item is already absent. */ + readonly ifVersion: MessageFeedbackVersion; +} +/** Idempotent deletion acknowledgement. */ +export interface MessageFeedbackDeleteValue { + /** Stable postcondition shared by the first deletion and every retry. */ + readonly absent: true; +} +/** No persisted Session header exists for the requested id. */ +export interface MessageFeedbackSessionNotFound { + readonly code: 'session-not-found'; + readonly sessionId: SessionId; +} +/** The id does not name a derived, append-origin assistant message. */ +export interface MessageFeedbackTargetNotFound { + readonly code: 'target-not-found'; + readonly sessionId: SessionId; + readonly messageId: MessageId; +} +/** A material mutation did not match the addressed item's current version. */ +export interface MessageFeedbackVersionConflict { + readonly code: 'version-conflict'; + /** Authoritative current item, or `null` when it does not exist. */ + readonly current: MessageFeedbackItem | null; +} +/** A supplied note contains no non-whitespace character. */ +export interface MessageFeedbackNoteBlank { + readonly code: 'note-blank'; +} +/** A supplied note exceeds the configured UTF-8 byte limit. */ +export interface MessageFeedbackNoteTooLarge { + readonly code: 'note-too-large'; + readonly maxBytes: number; + readonly actualBytes: number; +} +/** Failures shared by the public message-feedback operations. */ +export type MessageFeedbackFailure = MessageFeedbackSessionNotFound | MessageFeedbackTargetNotFound | MessageFeedbackVersionConflict | MessageFeedbackNoteBlank | MessageFeedbackNoteTooLarge; +/** Successful public operation result. */ +export interface MessageFeedbackSuccess { + readonly ok: true; + readonly value: T; +} +/** Rejected public operation result with a stable business failure. */ +export interface MessageFeedbackRejected { + readonly ok: false; + readonly error: E; +} +/** Result returned by the message-feedback `list` operation. */ +export type MessageFeedbackListResult = MessageFeedbackSuccess | MessageFeedbackRejected; +/** Result returned by the message-feedback `put` operation. */ +export type MessageFeedbackPutResult = MessageFeedbackSuccess | MessageFeedbackRejected; +/** Result returned by the message-feedback `delete` operation. */ +export type MessageFeedbackDeleteResult = MessageFeedbackSuccess | MessageFeedbackRejected; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.js new file mode 100644 index 0000000..57ea1f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.js @@ -0,0 +1,8 @@ +/** + * Public request, value, and failure vocabulary for per-message feedback. + * This module contains types only so generated Remote clients can consume it + * without importing Host runtime code. + * @module @deepseek-ai/dsh-message-feedback/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/package.json new file mode 100644 index 0000000..9c10843 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-message-feedback/package.json @@ -0,0 +1,80 @@ +{ + "name": "@deepseek-ai/dsh-message-feedback", + "description": "Lifecycle-bound per-message rating and note sidecar for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/feedback/message-feedback" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./typert": { + "types": "./lib/typert.host.d.ts", + "default": "./lib/typert.host.js" + }, + "./remote": { + "types": "./lib/typert.remote-client.d.ts", + "default": "./lib/typert.remote-client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts", + "lib/typert.host.js", + "lib/typert.host.d.ts", + "lib/typert.remote-client.js", + "lib/typert.remote-client.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage-json": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..a0535b0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-storage-domain b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-storage-domain new file mode 120000 index 0000000..0ab7747 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-storage-domain @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..aa2ae83 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.6_cdd0c3e96f86c96ecb6bb448ac2abd9a/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.i18n.yaml new file mode 100644 index 0000000..c884f75 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/feedback/message-feedback/README.md +README.md: b85104abb983eb3b33ab6ddad9328e6f5f3b1fc9 +README.zh.md: 52efef5119854f4a5c3c776a227032b59b680fc5 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.md new file mode 100644 index 0000000..b85104a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.md @@ -0,0 +1,84 @@ +# @deepseek-ai/dsh-message-feedback + +English | [中文](README.zh.md) + +Host-owned editable feedback for one finalized assistant message. The package registers `ctx.messageFeedback`, persists one lifecycle-bound sidecar row per Session in storage-domain, and publishes the Host `messageFeedback.list`, `messageFeedback.put`, and `messageFeedback.delete` unary Remote contract. It is separate from the immutable Session-level `feedback/record` event and performs no telemetry handoff. The [message-feedback sidecar Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-message-feedback-sidecar.md) owns the design boundary. + +Public request, value, version, and failure types are exported from the package root and `@deepseek-ai/dsh-message-feedback/types`; [`src/types.ts`](src/types.ts) is their source. + +## Configuration + +| key | meaning | +|---|---| +| `maxNoteBytes` | Required positive safe integer: maximum UTF-8 byte length of one optional note. | + +Notes must contain at least one non-whitespace character, but accepted text is stored verbatim rather than trimmed. Omitting `note` means the desired value has no note, so a version-matched material `put` clears an existing note. Note validation precedes Session lookup and can therefore return `note-blank` or `note-too-large` for a missing Session without touching persistence. + +```yaml +- id: message-feedback + name: '@deepseek-ai/dsh-message-feedback' + config: + maxNoteBytes: 8192 +``` + +The service injects `storageDomain`, `sessionPersistence`, and `sessions`. Its durable domain is `message_feedback`, with one `sessions` table row per `SessionId`. + +## Data, lifecycle, and durability + +`MessageFeedbackItem` contains `messageId`, `rating: 'positive' | 'negative'`, optional `note`, an opaque equality-only `version`, and Host-assigned `createdAt`/`updatedAt` Unix-millisecond timestamps. A material update preserves `createdAt`, replaces `version`, and keeps `updatedAt` from moving backward. `list` returns fresh immutable snapshots in first-creation order; updating an item retains its place, while deleting and later recreating it appends a new item. + +Each stored row carries the inspected Session header identity `{createdAt, cwd}`. A mismatch is treated as absence: `list` returns an empty `items` array, `delete` returns the absent postcondition, and `put` may replace the stale row with one bound to the current identity. This fences a reused `SessionId` when its header identity differs. Forks use a distinct Session identity and receive no feedback-row copy. + +`SessionPersistence.inspect()` supplies a cold-safe observation without publishing or resuming an Agent and without committing cold repair. For a Session without a live owner, `listSnapshots()` first decides definite absence; an `inspect()` failure for a catalogued Session remains an infrastructure failure rather than being guessed into `session-not-found`. `put` accepts only a non-empty, append-origin `assistant/message` with the requested `MessageId`; replacement-origin messages, empty usage-only assistant records, and non-assistant records return `target-not-found`. + +After initial validation, `put` establishes a durability barrier before writing the sidecar. A matching live Session commits through the canonical `ctx.sessions.flush` checkpoint, then both live and cold paths are physically read from sequence zero through `SessionPersistence.readFrom`. The resulting observation's header identity and target are validated again. A missing flush participant, changed identity, vanished target, or physical-read failure prevents the sidecar commit, so durable feedback never precedes the durable target message. + +Message feedback is not Session-log content or a Session projection. It emits no `feedback/record` event, does not enter model history, and does not trigger `FEEDBACK_ONLY` telemetry release. + +## Service and Host Remote contract + +The same three `MessageFeedbackService` methods are published by `TypertRemoteService` and `@Remote`; the Host endpoint names are `messageFeedback.list`, `messageFeedback.put`, and `messageFeedback.delete`. Every method returns a discriminated business union: `{ ok: true, value }` or `{ ok: false, error }`. Operational storage, corruption, or missing-durability-listener failures reject instead of being mislabeled as business errors. + +| Method | Request | Success `value` | Rejected `error.code` | +|---|---|---|---| +| `list` | `MessageFeedbackListRequest { sessionId }` | `MessageFeedbackListValue { items }` | `session-not-found` | +| `put` | `MessageFeedbackPutRequest { sessionId, messageId, rating, note?, ifVersion }` | committed `MessageFeedbackItem` | `session-not-found`, `target-not-found`, `version-conflict`, `note-blank`, `note-too-large` | +| `delete` | `MessageFeedbackDeleteRequest { sessionId, messageId, ifVersion }` | `MessageFeedbackDeleteValue { absent: true }` | `session-not-found`, `version-conflict` | + +`MessageFeedbackVersionConflict` returns the authoritative `current` item, or `null` when no item exists. This lets a caller reconcile the current rating, note, and version without a second `list` request. `MessageFeedbackNoteTooLarge` returns both `maxBytes` and `actualBytes`. The Client Remote aggregate does not mount the generated client contribution yet; Host callers can use the service/Remote contract without that client assembly. + +## Compare-and-set and idempotency + +`ifVersion: null` requests creation only; every request for an existing item requires its exact current version, including a no-op whose desired value already matches. The check is per message rather than per Session, so changing one item does not conflict with another. Every material create or update assigns a fresh opaque UUID token, preventing stale writes from crossing an ABA value cycle. + +A matching-version no-op returns the already stored item with unchanged version and timestamps. After a lost success response, a retry with the old token receives `version-conflict.current`; the caller can compare that authoritative item with its desired value without an extra read. `delete` ignores `ifVersion` when the item is already absent and always returns the stable `{ absent: true }` postcondition after success. + +A per-Session promise queue encloses inspection, durability validation, sidecar read, comparison, and whole-row write. These semantics serialize concurrent mutations through one service instance; storage-domain itself has no cross-process conditional write. + +Plugin disposal closes mutation admission, drains every operation already accepted into the per-Session queues, and only then closes the storage domain. A mutation submitted after disposal begins rejects as a lifecycle failure instead of entering a closing domain. + +## Model Experience + +### Local message-feedback state + +#### What the model sees + +Nothing. `ctx.messageFeedback` registers no tool, prompt section, model-facing context, or Session event; feedback stays in a Host-owned sidecar unless a separately documented Consumer explicitly exposes it. + +#### Token effect + +Zero. No request, result, rating, note, timestamp, or failure from this package enters a model request. + +#### KV Cache effect + +Independent. Listing or mutating message feedback does not touch a model request prefix and cannot invalidate an otherwise reusable provider cache entry. + +## Known Limitations and Deferred Work + +- **Client aggregate and UI are absent** — the Host Remote contract ships, but the Client Remote aggregate contribution and any UI consumer are separately owned and deferred. +- **Compare-and-set is single-process** — the per-Session queue serializes one service instance only; multiple Host processes writing one storage root can still lose updates because storage-domain exposes no cross-process conditional write. +- **No durable Session deletion cascade** — Session persistence has no deletion API, and `session/disposed`/`host/session-removed` mean detach rather than durable deletion. The service therefore retains empty rows and may leave orphan rows after out-of-band log removal instead of deleting valid feedback on detach. +- **Detach/catalog retirement window** — a request in the narrow interval after live detach but before the persistence catalog materializes the header can receive `session-not-found`; callers retry after retirement materialization. +- **Header identity is not a content fingerprint** — `{createdAt, cwd}` detects reuse only when those fields differ; a cloned log retaining the same header identity is indistinguishable. +- **Trusted caller boundary** — `list`/`put`/`delete` carry no authenticated actor or audit identity. A deployment must expose the Host gateway only through its trusted or separately authenticated boundary until authorization and attribution are added. +- **Catalog and row bounds** — a cold request scans the complete Session snapshot catalog because persistence has no lookup-by-id metadata operation. `maxNoteBytes` bounds one note, but the item count and aggregate retained bytes of one Session row are not capped; an indexed metadata read and deployment-owned row bound remain deferred until a concrete consumer defines their policy. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.zh.md new file mode 100644 index 0000000..52efef5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/README.zh.md @@ -0,0 +1,84 @@ +# @deepseek-ai/dsh-message-feedback + +[English](README.md) | 中文 + +本包提供由 Host 拥有、针对单条已完成 assistant 消息的可编辑反馈。它注册 `ctx.messageFeedback`,在 storage-domain 中为每个 Session 持久化一条绑定生命周期的伴随记录(sidecar),并发布 Host `messageFeedback.list`、`messageFeedback.put` 与 `messageFeedback.delete` 一元 Remote 契约。它与不可变的 Session 级 `feedback/record` 事件相互独立,不执行遥测交接。[消息反馈伴随记录 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-message-feedback-sidecar.md)拥有其设计边界。 + +公开的请求、值、版本与失败类型从包根入口及 `@deepseek-ai/dsh-message-feedback/types` 导出;其源码为 [`src/types.ts`](src/types.ts)。 + +## 配置 + +| 键 | 含义 | +|---|---| +| `maxNoteBytes` | 必填正 safe integer:一条可选备注的最大 UTF-8 字节长度。 | + +备注必须包含至少一个非空白字符,但通过校验的文本按原样存储,不会 trim。省略 `note` 表示目标值不含备注,因此 version 匹配的实质 `put` 会清除已有备注。备注校验早于 Session 查找,因此即使 Session 不存在,也可能在不访问持久化的情况下返回 `note-blank` 或 `note-too-large`。 + +```yaml +- id: message-feedback + name: '@deepseek-ai/dsh-message-feedback' + config: + maxNoteBytes: 8192 +``` + +服务注入 `storageDomain`、`sessionPersistence` 与 `sessions`。其持久存储域为 `message_feedback`,其中 `sessions` 表按 `SessionId` 每个一行。 + +## 数据、生命周期与持久性 + +`MessageFeedbackItem` 包含 `messageId`、`rating: 'positive' | 'negative'`、可选 `note`、只能做相等比较的 opaque `version`,以及由 Host 分配、以 Unix 毫秒表示的 `createdAt`/`updatedAt` 时间戳。实质更新保留 `createdAt`、替换 `version`,并保证 `updatedAt` 不倒退。`list` 按首次创建顺序返回新的不可变快照;更新条目时保留其位置,删除后再创建则追加为新条目。 + +每条存储行都携带检查所得 Session header 身份 `{createdAt, cwd}`。不匹配按不存在处理:`list` 返回空 `items` 数组,`delete` 返回已不存在的后置条件,`put` 可以用绑定当前身份的新行替换陈旧行。这会在复用的 `SessionId` 具有不同 header 身份时形成隔离。fork 使用独立的 Session 身份,不复制反馈伴随记录。 + +`SessionPersistence.inspect()` 提供 cold-safe 观测,不发布或恢复 Agent,也不提交 cold repair。对于没有 live owner 的 Session,系统先用 `listSnapshots()` 判定明确不存在;已进入目录的 Session 若 `inspect()` 失败,仍属于基础设施故障,不会被猜测成 `session-not-found`。`put` 只接受具有指定 `MessageId` 的非空、append-origin `assistant/message`;replacement-origin 消息、仅承载 usage 的空 assistant 记录与非 assistant 记录都返回 `target-not-found`。 + +初步校验后,`put` 在写入伴随记录前建立 durability barrier。身份匹配的 live Session 先通过权威 `ctx.sessions.flush` checkpoint 提交,随后 live 与 cold 路径都会通过 `SessionPersistence.readFrom` 从序列零做物理复读。之后再次校验所得观测的 header 身份与目标。缺少 flush 参与方、身份变化、目标消失或物理读取失败都会阻止伴随记录提交,因此持久反馈绝不会先于其持久目标消息。 + +message feedback 不是 Session 日志内容或 Session 投影。它不发出 `feedback/record` 事件,不进入模型历史,也不触发 `FEEDBACK_ONLY` 遥测释放。 + +## 服务与 Host Remote 契约 + +`TypertRemoteService` 与 `@Remote` 将 `MessageFeedbackService` 的同三个方法发布出去;Host endpoint 名称为 `messageFeedback.list`、`messageFeedback.put` 与 `messageFeedback.delete`。每个方法都返回判别式业务 union:`{ ok: true, value }` 或 `{ ok: false, error }`。存储、损坏或缺少 durability listener 等操作故障会产生 reject,不会被误标为业务错误。 + +| 方法 | 请求 | 成功 `value` | 拒绝的 `error.code` | +|---|---|---|---| +| `list` | `MessageFeedbackListRequest { sessionId }` | `MessageFeedbackListValue { items }` | `session-not-found` | +| `put` | `MessageFeedbackPutRequest { sessionId, messageId, rating, note?, ifVersion }` | 已提交的 `MessageFeedbackItem` | `session-not-found`、`target-not-found`、`version-conflict`、`note-blank`、`note-too-large` | +| `delete` | `MessageFeedbackDeleteRequest { sessionId, messageId, ifVersion }` | `MessageFeedbackDeleteValue { absent: true }` | `session-not-found`、`version-conflict` | + +`MessageFeedbackVersionConflict` 返回权威 `current` 条目;条目不存在时为 `null`。调用方无需额外执行 `list`,即可协调当前 rating、note 与 version。`MessageFeedbackNoteTooLarge` 同时返回 `maxBytes` 与 `actualBytes`。客户端 Remote 聚合尚未挂载生成的客户端 contribution;Host 调用方无需该客户端组装即可使用 service/Remote 契约。 + +## Compare-and-set 与幂等性 + +`ifVersion: null` 表示仅当条目不存在时才创建;已有条目的每次请求都必须与其当前 version 完全一致,即使目标值已经相同、不会产生实质更新。检查按消息而非按 Session 进行,因此修改一个条目不会与另一个条目冲突。每次实质创建或更新都会分配新的 opaque UUID token,防止陈旧写入穿过 ABA 值循环。 + +携带匹配 version 的无变化请求会返回已存条目,version 与时间戳均不变。成功响应丢失后,使用旧 token 重试会得到 `version-conflict.current`;调用方无需额外读取,即可把权威当前值与目标值比较。条目已不存在时,`delete` 忽略 `ifVersion`;成功后始终返回稳定的 `{ absent: true }` 后置条件。 + +按 Session 划分的 promise 队列覆盖检查、持久性校验、伴随记录读取、比较与整行写入。这些语义会串行化经由同一服务实例的并发变更;storage-domain 自身没有跨进程条件写。 + +Plugin disposal 会先关闭变更接纳,排空已进入各个 Session 队列的所有操作,然后才关闭 storage domain。disposal 开始后提交的变更会以生命周期故障拒绝,不会进入正在关闭的 domain。 + +## 模型体验 + +### 本地消息反馈状态 + +#### 模型看到的内容 + +无。`ctx.messageFeedback` 不注册工具、提示词段落、模型可见上下文或 Session 事件;除非另一个具有独立文档的 Consumer 显式公开反馈,否则它只留在 Host 拥有的伴随记录中。 + +#### Token 影响 + +为零。本包的请求、结果、评分、备注、时间戳或失败都不会进入模型请求。 + +#### KV Cache 影响 + +相互独立。读取或变更消息反馈不会触碰模型请求前缀,也不会使本可复用的提供方缓存条目失效。 + +## 已知局限与延后工作 + +- **缺少客户端聚合与 UI**——Host Remote 契约已经发布,但客户端 Remote 聚合 contribution 与任何 UI 消费方由各自边界负责并保持延后。 +- **Compare-and-set 仅限单进程**——按 Session 划分的队列只串行化一个服务实例;storage-domain 不提供跨进程条件写,因此多个 Host 进程写入同一存储根目录时仍可能丢失更新。 +- **没有持久 Session 删除级联**——Session persistence 没有删除接口,且 `session/disposed`/`host/session-removed` 表示 detach 而非持久删除。因此服务会保留空行,并可能在带外移除日志后留下遗留行,而不会在 detach 时删除仍有效的反馈。 +- **Detach/catalog retirement 窗口**——请求若恰好落在 live detach 之后、persistence catalog 物化 header 之前的极短窗口,可能收到 `session-not-found`;调用方应在 retirement materialization 后重试。 +- **Header 身份不是内容指纹**——只有 `{createdAt, cwd}` 不同时才能识别复用;本契约无法区分保留相同 header 身份的克隆日志。 +- **调用方边界受信任**——`list`/`put`/`delete` 不携带已认证的 actor 或审计身份。在加入授权与归属信息前,部署方必须只通过受信任或另行认证的边界暴露 Host gateway。 +- **目录与行边界**——由于 persistence 没有按 id 读取元数据的操作,cold 请求会扫描完整的 Session snapshot 目录。`maxNoteBytes` 只限制单条备注,单个 Session 行的条目数和聚合保留字节尚无上限;按索引读取元数据和由部署决定的行边界,延后到具体消费方明确策略时处理。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/index.js new file mode 100644 index 0000000..2a2f0d5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/index.js @@ -0,0 +1,420 @@ +import { Buffer } from "node:buffer"; +import { randomUUID } from "node:crypto"; +import { Service } from "@deepseek-ai/cordis"; +import s from "@deepseek-ai/schemastery"; +import { deriveEventMessage, isAppendSurfaceEvent } from "@deepseek-ai/dsh-session/surface"; +import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol"; +import { z } from "zod"; +import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain"; +//#region lib/types/spec.js +/** +* Durable storage-domain declaration for lifecycle-bound message feedback. +* @module @deepseek-ai/dsh-message-feedback/src/spec +*/ +const nonNegativeSafeInteger = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER); +/** Runtime schema for the closed rating vocabulary. */ +const messageFeedbackRatingSchema = z.union([z.literal("positive"), z.literal("negative")]); +/** Runtime schema for one opaque item version stored on disk. */ +const messageFeedbackVersionSchema = z.uuid().transform((value) => value); +/** Runtime schema for one current feedback item. */ +const messageFeedbackItemSchema = z.object({ + messageId: z.string().min(1).transform((value) => value), + rating: messageFeedbackRatingSchema, + note: z.string().refine((note) => note.trim().length > 0, { message: "message feedback note must contain a non-whitespace character" }).optional(), + version: messageFeedbackVersionSchema, + createdAt: nonNegativeSafeInteger, + updatedAt: nonNegativeSafeInteger +}).refine((item) => item.updatedAt >= item.createdAt, { + path: ["updatedAt"], + message: "message feedback updatedAt must not precede createdAt" +}); +/** Persisted Session fields that fence a sidecar row to one log lifecycle. */ +const messageFeedbackSessionIdentitySchema = z.object({ + createdAt: nonNegativeSafeInteger, + cwd: z.string().optional() +}); +/** +* One whole-Session sidecar. Duplicate message ids would make item lookup +* ambiguous; duplicate versions would break their independent identity. +*/ +const messageFeedbackRowSchema = z.object({ + session: messageFeedbackSessionIdentitySchema, + items: z.array(messageFeedbackItemSchema) +}).superRefine((row, ctx) => { + const messageIds = /* @__PURE__ */ new Set(); + const versions = /* @__PURE__ */ new Set(); + row.items.forEach((item, index) => { + if (messageIds.has(item.messageId)) ctx.addIssue({ + code: "custom", + path: [ + "items", + index, + "messageId" + ], + message: `duplicate message feedback id '${item.messageId}'` + }); + messageIds.add(item.messageId); + if (versions.has(item.version)) ctx.addIssue({ + code: "custom", + path: [ + "items", + index, + "version" + ], + message: `duplicate message feedback version '${item.version}'` + }); + versions.add(item.version); + }); +}); +/** One lifecycle-bound sidecar record per Session id. */ +const messageFeedbackDomainSpec = defineDomain({ + name: "message_feedback", + version: 0, + tables: { sessions: domainTable(messageFeedbackRowSchema) } +}); +//#endregion +//#region lib/types/index.js +/** +* Durable, lifecycle-bound feedback for finalized assistant messages. +* @module @deepseek-ai/dsh-message-feedback +*/ +var __runInitializers = function(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + return useValue ? value : void 0; +}; +var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function(f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +/** Immutable empty list reused only as an input to caller-owned copying. */ +const EMPTY_ITEMS = Object.freeze([]); +/** Validate the one deployment-varying limit at the configuration boundary. */ +function resolveMaxNoteBytes(value) { + if (!Number.isSafeInteger(value) || value < 1) throw new TypeError(`message-feedback: maxNoteBytes must be a positive safe integer, got ${String(value)}`); + return value; +} +/** Copy and freeze one item before it crosses the service boundary. */ +function snapshotItem(item) { + return Object.freeze({ + messageId: item.messageId, + rating: item.rating, + ...item.note === void 0 ? {} : { note: item.note }, + version: item.version, + createdAt: item.createdAt, + updatedAt: item.updatedAt + }); +} +/** Copy and freeze a list response. */ +function snapshotList(items) { + return Object.freeze({ items: Object.freeze(items.map(snapshotItem)) }); +} +/** Build a frozen success branch. */ +function success(value) { + return Object.freeze({ + ok: true, + value + }); +} +/** Build a frozen business-failure branch. */ +function rejected(error) { + return Object.freeze({ + ok: false, + error: Object.freeze(error) + }); +} +/** Project the Session fields that distinguish one persisted log lifecycle. */ +function identityOf(header) { + return Object.freeze({ + createdAt: header.createdAt, + ...header.cwd === void 0 ? {} : { cwd: header.cwd } + }); +} +/** Whether a stored row belongs to the inspected Session lifecycle. */ +function sameIdentity(row, header) { + return row.session.createdAt === header.createdAt && row.session.cwd === header.cwd; +} +/** Whether two observations name the same persisted Session lifecycle. */ +function sameHeaderIdentity(left, right) { + return left.id === right.id && left.createdAt === right.createdAt && left.cwd === right.cwd; +} +/** Freeze the replacement row so storage-domain never exposes mutable aliases. */ +function rowSnapshot(session, items) { + const copiedItems = items.map(snapshotItem); + Object.freeze(copiedItems); + return Object.freeze({ + session, + items: copiedItems + }); +} +/** Generate an opaque equality token for one material mutation. */ +function nextVersion() { + return randomUUID(); +} +/** +* Storage-domain sidecar service. It inspects persisted Session history and +* never creates or resumes an Agent or Session. +*/ +let MessageFeedbackService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + let _put_decorators; + let _delete_decorators; + return class MessageFeedbackService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote("list")]; + _put_decorators = [Remote("put")]; + _delete_decorators = [Remote("delete")]; + __esDecorate(this, null, _list_decorators, { + kind: "method", + name: "list", + static: false, + private: false, + access: { + has: (obj) => "list" in obj, + get: (obj) => obj.list + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _put_decorators, { + kind: "method", + name: "put", + static: false, + private: false, + access: { + has: (obj) => "put" in obj, + get: (obj) => obj.put + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + __esDecorate(this, null, _delete_decorators, { + kind: "method", + name: "delete", + static: false, + private: false, + access: { + has: (obj) => "delete" in obj, + get: (obj) => obj.delete + }, + metadata: _metadata + }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { + enumerable: true, + configurable: true, + writable: true, + value: _metadata + }); + } + static inject = [ + "storageDomain", + "sessionPersistence", + "sessions" + ]; + /** Loader validation for the required note-size policy. */ + static Config = s.object({ maxNoteBytes: s.number().step(1).min(1).required() }); + maxNoteBytes = __runInitializers(this, _instanceExtraInitializers); + table; + operationTails = /* @__PURE__ */ new Map(); + mutationAdmissionOpen = true; + /** + * @param ctx - Host context carrying persistence and the storage-domain form. + * @param config - Required note-size policy. + */ + constructor(ctx, config) { + super(ctx, "messageFeedback"); + this.maxNoteBytes = resolveMaxNoteBytes(config.maxNoteBytes); + } + /** Open and own the one message-feedback sidecar domain. */ + async [Service.init]() { + const domain = await this.ctx.storageDomain.open(messageFeedbackDomainSpec); + this.ctx.effect(() => async () => { + this.mutationAdmissionOpen = false; + await Promise.all(this.operationTails.values()); + await domain.close(); + }, "message-feedback.domainClose"); + this.table = domain.table("sessions"); + } + /** + * Read feedback belonging to the current persisted Session lifecycle. + * A stale row from a reused Session id is invisible. + * @param request - Session identity to inspect and list. + * @returns current immutable items or `session-not-found`. + */ + async list(request) { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) return known; + const row = this.requireTable().get(request.sessionId); + return success(snapshotList(row !== void 0 && sameIdentity(row, known.value.meta) ? row.items : EMPTY_ITEMS)); + } + /** + * Create or replace feedback for one derived append-origin assistant + * message. Every request must match the addressed item's current version; + * a matching no-op returns the stored item without changing its revision. + * @param request - target, desired value, and observed item version. + * @returns the committed item or an explicit business failure. + */ + put(request) { + const note = this.resolveNote(request.note); + if (!note.ok) return Promise.resolve(note); + return this.enqueue(request.sessionId, async () => { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) return known; + if (!this.hasFeedbackTarget(known.value, request.messageId)) return rejected({ + code: "target-not-found", + sessionId: request.sessionId, + messageId: request.messageId + }); + const durable = await this.ensureTargetDurable(known.value); + if (!sameHeaderIdentity(durable.meta, known.value.meta) || !this.hasFeedbackTarget(durable, request.messageId)) return rejected({ + code: "target-not-found", + sessionId: request.sessionId, + messageId: request.messageId + }); + const table = this.requireTable(); + const stored = table.get(request.sessionId); + const items = (stored !== void 0 && sameIdentity(stored, durable.meta) ? stored : void 0)?.items ?? EMPTY_ITEMS; + const index = items.findIndex((item) => item.messageId === request.messageId); + const existing = items[index]; + if (request.ifVersion !== (existing?.version ?? null)) return rejected(this.versionConflict(existing ?? null)); + if (existing !== void 0 && existing.rating === request.rating && existing.note === note.value) return success(snapshotItem(existing)); + const now = Date.now(); + const item = snapshotItem({ + messageId: request.messageId, + rating: request.rating, + ...note.value === void 0 ? {} : { note: note.value }, + version: nextVersion(), + createdAt: existing?.createdAt ?? now, + updatedAt: existing === void 0 ? now : Math.max(now, existing.updatedAt) + }); + const nextItems = [...items]; + if (index === -1) nextItems.push(item); + else nextItems[index] = item; + await table.put(request.sessionId, rowSnapshot(identityOf(durable.meta), nextItems)); + return success(snapshotItem(item)); + }); + } + /** + * Delete one feedback item. Absence is successful regardless of the + * supplied version; an existing item requires an exact version match. + * @param request - Session, message, and observed item version. + * @returns the stable absent postcondition, or an explicit failure. + */ + delete(request) { + return this.enqueue(request.sessionId, async () => { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) return known; + const table = this.requireTable(); + const stored = table.get(request.sessionId); + const items = (stored !== void 0 && sameIdentity(stored, known.value.meta) ? stored : void 0)?.items ?? EMPTY_ITEMS; + const existing = items.find((item) => item.messageId === request.messageId); + if (existing === void 0) return success(Object.freeze({ absent: true })); + if (request.ifVersion !== existing.version) return rejected(this.versionConflict(existing)); + await table.put(request.sessionId, rowSnapshot(identityOf(known.value.meta), items.filter((item) => item !== existing))); + return success(Object.freeze({ absent: true })); + }); + } + /** + * Resolve a live owner directly; otherwise use the storage catalog as the + * existence authority before inspecting the log. Inspection failures for a + * catalogued Session remain infrastructure failures rather than being + * guessed into the business `session-not-found` branch. + */ + async inspectSession(sessionId) { + if (this.ctx.sessions.get(sessionId) === void 0) { + if (!(await this.ctx.sessionPersistence.listSnapshots()).some((snapshot) => snapshot.header.id === sessionId) && this.ctx.sessions.get(sessionId) === void 0) return rejected({ + code: "session-not-found", + sessionId + }); + } + return success(await this.ctx.sessionPersistence.inspect(sessionId)); + } + /** Require the exact finalized append-origin assistant message projection. */ + hasFeedbackTarget(inspection, messageId) { + return inspection.events.some((event) => { + if (event.type !== "assistant/message" || !isAppendSurfaceEvent(event)) return false; + const message = deriveEventMessage(event); + return message?.role === "assistant" && message.id === messageId; + }); + } + /** + * Put the target log prefix behind a durability barrier before its sidecar. + * A live owner flushes through the SessionStore's canonical checkpoint; a + * cold owner is re-read from the physical durable prefix. + */ + async ensureTargetDurable(inspection) { + const live = this.ctx.sessions.get(inspection.meta.id); + if (live !== void 0 && sameHeaderIdentity(live.header, inspection.meta)) { + if (!await this.ctx.sessions.flush(live)) throw new Error(`message-feedback: no durability listener participated for live session '${inspection.meta.id}'`); + return await this.ctx.sessionPersistence.readFrom(inspection.meta.id, 0); + } + return await this.ctx.sessionPersistence.readFrom(inspection.meta.id, 0); + } + /** Validate optional-note semantics and the configured complete UTF-8 byte bound. */ + resolveNote(note) { + if (note === void 0) return success(void 0); + if (note.trim().length === 0) return rejected({ code: "note-blank" }); + const actualBytes = Buffer.byteLength(note, "utf8"); + if (actualBytes > this.maxNoteBytes) return rejected({ + code: "note-too-large", + maxBytes: this.maxNoteBytes, + actualBytes + }); + return success(note); + } + /** Return the authoritative item needed to reconcile one failed comparison. */ + versionConflict(current) { + return { + code: "version-conflict", + current: current === null ? null : snapshotItem(current) + }; + } + /** Queue a complete read/compare/write mutation behind this Session's prior mutation. */ + enqueue(sessionId, operation) { + if (!this.mutationAdmissionOpen) return Promise.reject(/* @__PURE__ */ new Error("message-feedback: service is disposing")); + const result = (this.operationTails.get(sessionId) ?? Promise.resolve()).then(operation); + const tail = result.then(() => void 0, () => void 0); + this.operationTails.set(sessionId, tail); + return result.finally(() => { + if (this.operationTails.get(sessionId) === tail) this.operationTails.delete(sessionId); + }); + } + /** Resolve the initialized durable table or fail a broken service lifecycle. */ + requireTable() { + if (this.table === void 0) throw new Error("message-feedback: durable domain is not initialized"); + return this.table; + } + }; +})(); +//#endregion +export { MessageFeedbackService, MessageFeedbackService as default, messageFeedbackDomainSpec, messageFeedbackItemSchema, messageFeedbackRatingSchema, messageFeedbackRowSchema, messageFeedbackSessionIdentitySchema, messageFeedbackVersionSchema }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/invariant.js new file mode 100644 index 0000000..5bc9b7b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/invariant.js @@ -0,0 +1,20 @@ +//#region lib/types/invariant.js +/** Package-owned invariant companion. @module @deepseek-ai/dsh-message-feedback/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-message-feedback"; +/** Cordis companion plugin name. */ +const name = "message-feedback-invariant"; +/** Services required before the companion can reserve and check package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the private typed writer owns current row mutations, +* the domain schema validates rows on reopen, and no second authority exists. +*/ +const install = Object.assign(() => {}, { inject: ["messageFeedback"] }); +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.d.ts new file mode 100644 index 0000000..dcf4919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.d.ts @@ -0,0 +1,3 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ + +export declare const TYPERT: unknown diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.js new file mode 100644 index 0000000..6f68965 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.host.js @@ -0,0 +1,307 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'ifVersion': z.intersection(z.string(), z.unknown()).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'absent': z.literal(true).readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.union([z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("version-conflict").readonly(), + 'current': z.union([z.literal(null), z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})]).readonly(), +})]).readonly(), +})]) +const _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'items': z.array(z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})).readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}).readonly(), +})]) +const _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'ifVersion': z.union([z.literal(null), z.intersection(z.string(), z.unknown())]).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.union([z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("target-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("version-conflict").readonly(), + 'current': z.union([z.literal(null), z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})]).readonly(), +}), z.object({ + 'code': z.literal("note-blank").readonly(), +}), z.object({ + 'code': z.literal("note-too-large").readonly(), + 'maxBytes': z.number().readonly(), + 'actualBytes': z.number().readonly(), +})]).readonly(), +})]) + +export const TYPERT = { + package: '@deepseek-ai/dsh-message-feedback', + face: 'host', + schemas: [ + ], + invocations: [ + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/delete', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'delete', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":272,"column":3}, + }, + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/list', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'list', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":190,"column":9}, + }, + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/put', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'put', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":206,"column":3}, + }, + ], + model: { + "services": [ + { + "description": "Storage-domain sidecar service. It inspects persisted Session history and never creates or resumes an Agent or Session.", + "summary": "Storage-domain sidecar service.", + "tags": [], + "jsDoc": "/**\n * Storage-domain sidecar service. It inspects persisted Session history and\n * never creates or resumes an Agent or Session.\n */", + "key": "messageFeedback", + "exportName": "MessageFeedbackService", + "members": [ + { + "kind": "method", + "name": "list", + "signature": "@Remote('list') async list(request: MessageFeedbackListRequest): Promise", + "summary": "Read feedback belonging to the current persisted Session lifecycle.", + "jsDoc": "/**\n * Read feedback belonging to the current persisted Session lifecycle.\n * A stale row from a reused Session id is invisible.\n * @param request - Session identity to inspect and list.\n * @returns current immutable items or `session-not-found`.\n */" + }, + { + "kind": "method", + "name": "put", + "signature": "@Remote('put') put(request: MessageFeedbackPutRequest): Promise", + "summary": "Create or replace feedback for one derived append-origin assistant message.", + "jsDoc": "/**\n * Create or replace feedback for one derived append-origin assistant\n * message. Every request must match the addressed item's current version;\n * a matching no-op returns the stored item without changing its revision.\n * @param request - target, desired value, and observed item version.\n * @returns the committed item or an explicit business failure.\n */" + }, + { + "kind": "method", + "name": "delete", + "signature": "@Remote('delete') delete(request: MessageFeedbackDeleteRequest): Promise", + "summary": "Delete one feedback item.", + "jsDoc": "/**\n * Delete one feedback item. Absence is successful regardless of the\n * supplied version; an existing item requires an exact version match.\n * @param request - Session, message, and observed item version.\n * @returns the stable absent postcondition, or an explicit failure.\n */" + } + ], + "types": [ + { + "name": "Branded", + "declaration": "export type Branded = string & { readonly [BRAND]: B; };" + }, + { + "name": "MessageFeedbackDeleteRequest", + "declaration": "export interface MessageFeedbackDeleteRequest {\n readonly sessionId: SessionId;\n readonly messageId: MessageId;\n readonly ifVersion: MessageFeedbackVersion;\n}" + }, + { + "name": "MessageFeedbackDeleteResult", + "declaration": "export type MessageFeedbackDeleteResult = MessageFeedbackSuccess | MessageFeedbackRejected;" + }, + { + "name": "MessageFeedbackDeleteValue", + "declaration": "export interface MessageFeedbackDeleteValue {\n readonly absent: true;\n}" + }, + { + "name": "MessageFeedbackFailure", + "declaration": "export type MessageFeedbackFailure = MessageFeedbackSessionNotFound | MessageFeedbackTargetNotFound | MessageFeedbackVersionConflict | MessageFeedbackNoteBlank | MessageFeedbackNoteTooLarge;" + }, + { + "name": "MessageFeedbackItem", + "declaration": "export interface MessageFeedbackItem {\n readonly messageId: MessageId;\n readonly rating: MessageFeedbackRating;\n readonly note?: string;\n readonly version: MessageFeedbackVersion;\n readonly createdAt: number;\n readonly updatedAt: number;\n}" + }, + { + "name": "MessageFeedbackListRequest", + "declaration": "export interface MessageFeedbackListRequest {\n readonly sessionId: SessionId;\n}" + }, + { + "name": "MessageFeedbackListResult", + "declaration": "export type MessageFeedbackListResult = MessageFeedbackSuccess | MessageFeedbackRejected;" + }, + { + "name": "MessageFeedbackListValue", + "declaration": "export interface MessageFeedbackListValue {\n readonly items: readonly MessageFeedbackItem[];\n}" + }, + { + "name": "MessageFeedbackNoteBlank", + "declaration": "export interface MessageFeedbackNoteBlank {\n readonly code: 'note-blank';\n}" + }, + { + "name": "MessageFeedbackNoteTooLarge", + "declaration": "export interface MessageFeedbackNoteTooLarge {\n readonly code: 'note-too-large';\n readonly maxBytes: number;\n readonly actualBytes: number;\n}" + }, + { + "name": "MessageFeedbackPutRequest", + "declaration": "export interface MessageFeedbackPutRequest {\n readonly sessionId: SessionId;\n readonly messageId: MessageId;\n readonly rating: MessageFeedbackRating;\n readonly note?: string;\n readonly ifVersion: MessageFeedbackVersion | null;\n}" + }, + { + "name": "MessageFeedbackPutResult", + "declaration": "export type MessageFeedbackPutResult = MessageFeedbackSuccess | MessageFeedbackRejected;" + }, + { + "name": "MessageFeedbackRating", + "declaration": "export type MessageFeedbackRating = 'positive' | 'negative';" + }, + { + "name": "MessageFeedbackRejected", + "declaration": "export interface MessageFeedbackRejected {\n readonly ok: false;\n readonly error: E;\n}" + }, + { + "name": "MessageFeedbackSessionNotFound", + "declaration": "export interface MessageFeedbackSessionNotFound {\n readonly code: 'session-not-found';\n readonly sessionId: SessionId;\n}" + }, + { + "name": "MessageFeedbackSuccess", + "declaration": "export interface MessageFeedbackSuccess {\n readonly ok: true;\n readonly value: T;\n}" + }, + { + "name": "MessageFeedbackTargetNotFound", + "declaration": "export interface MessageFeedbackTargetNotFound {\n readonly code: 'target-not-found';\n readonly sessionId: SessionId;\n readonly messageId: MessageId;\n}" + }, + { + "name": "MessageFeedbackVersion", + "declaration": "export type MessageFeedbackVersion = Branded<'MessageFeedbackVersion'>;" + }, + { + "name": "MessageFeedbackVersionConflict", + "declaration": "export interface MessageFeedbackVersionConflict {\n readonly code: 'version-conflict';\n readonly current: MessageFeedbackItem | null;\n}" + }, + { + "name": "MessageId", + "declaration": "export type MessageId = Branded<'MessageId'>;" + }, + { + "name": "SessionId", + "declaration": "export type SessionId = Branded<'SessionId'>;" + } + ] + } + ], + "events": [], + "objects": [] + }, +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.d.ts new file mode 100644 index 0000000..c4616a2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.d.ts @@ -0,0 +1,26 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import type { + RemoteResult, + TypertRemoteContribution, +} from '@deepseek-ai/dsh-typert-protocol' +import type { MessageFeedbackDeleteRequest, MessageFeedbackDeleteResult, MessageFeedbackListRequest, MessageFeedbackListResult, MessageFeedbackPutRequest, MessageFeedbackPutResult } from '@deepseek-ai/dsh-message-feedback/types' + +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRemoteNamespace$6d657373616765466565646261636b { + delete: (request: MessageFeedbackDeleteRequest) => Promise> + list: (request: MessageFeedbackListRequest) => Promise> + put: (request: MessageFeedbackPutRequest) => Promise> + } + interface TypertRemoteMap { + 'messageFeedback/delete': (request: MessageFeedbackDeleteRequest) => Promise> + 'messageFeedback/list': (request: MessageFeedbackListRequest) => Promise> + 'messageFeedback/put': (request: MessageFeedbackPutRequest) => Promise> + } + interface TypertRemoteNamespaceMap { + 'messageFeedback': TypertRemoteNamespace$6d657373616765466565646261636b + } +} + +export declare const TYPERT_REMOTE: TypertRemoteContribution +export default TYPERT_REMOTE +//# sourceMappingURL=typert.remote-client.d.ts.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.js new file mode 100644 index 0000000..2efd155 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/typert.remote-client.js @@ -0,0 +1,179 @@ +/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */ +import { z } from 'zod' + +const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'ifVersion': z.intersection(z.string(), z.unknown()).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'absent': z.literal(true).readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.union([z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("version-conflict").readonly(), + 'current': z.union([z.literal(null), z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})]).readonly(), +})]).readonly(), +})]) +const _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'items': z.array(z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})).readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}).readonly(), +})]) +const _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema = z.object({ + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'ifVersion': z.union([z.literal(null), z.intersection(z.string(), z.unknown())]).readonly(), +}) +const _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema = z.union([z.object({ + 'ok': z.literal(true).readonly(), + 'value': z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +}).readonly(), +}), z.object({ + 'ok': z.literal(false).readonly(), + 'error': z.union([z.object({ + 'code': z.literal("session-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("target-not-found").readonly(), + 'sessionId': z.intersection(z.string(), z.unknown()).readonly(), + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), +}), z.object({ + 'code': z.literal("version-conflict").readonly(), + 'current': z.union([z.literal(null), z.object({ + 'messageId': z.intersection(z.string(), z.unknown()).readonly(), + 'rating': z.union([z.literal("positive"), z.literal("negative")]).readonly(), + 'note': z.string().readonly().optional(), + 'version': z.intersection(z.string(), z.unknown()).readonly(), + 'createdAt': z.number().readonly(), + 'updatedAt': z.number().readonly(), +})]).readonly(), +}), z.object({ + 'code': z.literal("note-blank").readonly(), +}), z.object({ + 'code': z.literal("note-too-large").readonly(), + 'maxBytes': z.number().readonly(), + 'actualBytes': z.number().readonly(), +})]).readonly(), +})]) + +export const TYPERT_REMOTE = { + package: '@deepseek-ai/dsh-message-feedback', + descriptors: [ + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/delete', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'delete', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":272,"column":3}, + }, + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/list', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'list', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":190,"column":9}, + }, + { + id: '@deepseek-ai/dsh-message-feedback#messageFeedback/put', + service: 'messageFeedback', + namespace: 'messageFeedback', + method: 'put', + invocation: { kind: 'direct' }, + parameters: [ + { + name: 'request', + wire: 'request', + source: 'json', + codec: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutRequest', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_parameter_0$schema, + }, + }, + ], + result: { + mode: 'strict', + typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutResult', + schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema, + }, + sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":206,"column":3}, + }, + ], +} + +export default TYPERT_REMOTE diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.d.ts new file mode 100644 index 0000000..d5dd7ae --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.d.ts @@ -0,0 +1,88 @@ +/** + * Durable, lifecycle-bound feedback for finalized assistant messages. + * @module @deepseek-ai/dsh-message-feedback + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import s from '@deepseek-ai/schemastery'; +import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'; +import type { MessageFeedbackDeleteRequest, MessageFeedbackDeleteResult, MessageFeedbackListRequest, MessageFeedbackListResult, MessageFeedbackPutRequest, MessageFeedbackPutResult } from './types.ts'; +export type * from './types.ts'; +export { messageFeedbackDomainSpec, messageFeedbackItemSchema, messageFeedbackRatingSchema, messageFeedbackRowSchema, messageFeedbackSessionIdentitySchema, messageFeedbackVersionSchema, } from './spec.ts'; +export type { MessageFeedbackRow, MessageFeedbackSessionIdentity } from './spec.ts'; +/** Required deployment policy for optional notes. */ +export interface Config { + /** Maximum UTF-8 byte length accepted for one note. */ + readonly maxNoteBytes: number; +} +declare module '@deepseek-ai/cordis' { + interface Context { + messageFeedback: MessageFeedbackService; + } +} +/** + * Storage-domain sidecar service. It inspects persisted Session history and + * never creates or resumes an Agent or Session. + */ +export declare class MessageFeedbackService extends TypertRemoteService { + static inject: string[]; + /** Loader validation for the required note-size policy. */ + static Config: s; + private readonly maxNoteBytes; + private table?; + private readonly operationTails; + private mutationAdmissionOpen; + /** + * @param ctx - Host context carrying persistence and the storage-domain form. + * @param config - Required note-size policy. + */ + constructor(ctx: Context, config: Config); + /** Open and own the one message-feedback sidecar domain. */ + protected [Service.init](): Promise; + /** + * Read feedback belonging to the current persisted Session lifecycle. + * A stale row from a reused Session id is invisible. + * @param request - Session identity to inspect and list. + * @returns current immutable items or `session-not-found`. + */ + list(request: MessageFeedbackListRequest): Promise; + /** + * Create or replace feedback for one derived append-origin assistant + * message. Every request must match the addressed item's current version; + * a matching no-op returns the stored item without changing its revision. + * @param request - target, desired value, and observed item version. + * @returns the committed item or an explicit business failure. + */ + put(request: MessageFeedbackPutRequest): Promise; + /** + * Delete one feedback item. Absence is successful regardless of the + * supplied version; an existing item requires an exact version match. + * @param request - Session, message, and observed item version. + * @returns the stable absent postcondition, or an explicit failure. + */ + delete(request: MessageFeedbackDeleteRequest): Promise; + /** + * Resolve a live owner directly; otherwise use the storage catalog as the + * existence authority before inspecting the log. Inspection failures for a + * catalogued Session remain infrastructure failures rather than being + * guessed into the business `session-not-found` branch. + */ + private inspectSession; + /** Require the exact finalized append-origin assistant message projection. */ + private hasFeedbackTarget; + /** + * Put the target log prefix behind a durability barrier before its sidecar. + * A live owner flushes through the SessionStore's canonical checkpoint; a + * cold owner is re-read from the physical durable prefix. + */ + private ensureTargetDurable; + /** Validate optional-note semantics and the configured complete UTF-8 byte bound. */ + private resolveNote; + /** Return the authoritative item needed to reconcile one failed comparison. */ + private versionConflict; + /** Queue a complete read/compare/write mutation behind this Session's prior mutation. */ + private enqueue; + /** Resolve the initialized durable table or fail a broken service lifecycle. */ + private requireTable; +} +export default MessageFeedbackService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.js new file mode 100644 index 0000000..918b29d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/index.js @@ -0,0 +1,342 @@ +/** + * Durable, lifecycle-bound feedback for finalized assistant messages. + * @module @deepseek-ai/dsh-message-feedback + */ +var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; +var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; +import { Buffer } from 'node:buffer'; +import { randomUUID } from 'node:crypto'; +import { Service } from '@deepseek-ai/cordis'; +import s from '@deepseek-ai/schemastery'; +import { deriveEventMessage, isAppendSurfaceEvent } from '@deepseek-ai/dsh-session/surface'; +import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol'; +import { messageFeedbackDomainSpec } from "./spec.js"; +export { messageFeedbackDomainSpec, messageFeedbackItemSchema, messageFeedbackRatingSchema, messageFeedbackRowSchema, messageFeedbackSessionIdentitySchema, messageFeedbackVersionSchema, } from "./spec.js"; +/** Immutable empty list reused only as an input to caller-owned copying. */ +const EMPTY_ITEMS = Object.freeze([]); +/** Validate the one deployment-varying limit at the configuration boundary. */ +function resolveMaxNoteBytes(value) { + if (!Number.isSafeInteger(value) || value < 1) { + throw new TypeError(`message-feedback: maxNoteBytes must be a positive safe integer, got ${String(value)}`); + } + return value; +} +/** Copy and freeze one item before it crosses the service boundary. */ +function snapshotItem(item) { + return Object.freeze({ + messageId: item.messageId, + rating: item.rating, + ...(item.note === undefined ? {} : { note: item.note }), + version: item.version, + createdAt: item.createdAt, + updatedAt: item.updatedAt, + }); +} +/** Copy and freeze a list response. */ +function snapshotList(items) { + return Object.freeze({ items: Object.freeze(items.map(snapshotItem)) }); +} +/** Build a frozen success branch. */ +function success(value) { + return Object.freeze({ ok: true, value }); +} +/** Build a frozen business-failure branch. */ +function rejected(error) { + return Object.freeze({ ok: false, error: Object.freeze(error) }); +} +/** Project the Session fields that distinguish one persisted log lifecycle. */ +function identityOf(header) { + return Object.freeze({ + createdAt: header.createdAt, + ...(header.cwd === undefined ? {} : { cwd: header.cwd }), + }); +} +/** Whether a stored row belongs to the inspected Session lifecycle. */ +function sameIdentity(row, header) { + return row.session.createdAt === header.createdAt && row.session.cwd === header.cwd; +} +/** Whether two observations name the same persisted Session lifecycle. */ +function sameHeaderIdentity(left, right) { + return left.id === right.id && left.createdAt === right.createdAt && left.cwd === right.cwd; +} +/** Freeze the replacement row so storage-domain never exposes mutable aliases. */ +function rowSnapshot(session, items) { + const copiedItems = items.map(snapshotItem); + Object.freeze(copiedItems); + return Object.freeze({ + session, + items: copiedItems, + }); +} +/** Generate an opaque equality token for one material mutation. */ +function nextVersion() { + return randomUUID(); +} +/** + * Storage-domain sidecar service. It inspects persisted Session history and + * never creates or resumes an Agent or Session. + */ +let MessageFeedbackService = (() => { + let _classSuper = TypertRemoteService; + let _instanceExtraInitializers = []; + let _list_decorators; + let _put_decorators; + let _delete_decorators; + return class MessageFeedbackService extends _classSuper { + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; + _list_decorators = [Remote('list')]; + _put_decorators = [Remote('put')]; + _delete_decorators = [Remote('delete')]; + __esDecorate(this, null, _list_decorators, { kind: "method", name: "list", static: false, private: false, access: { has: obj => "list" in obj, get: obj => obj.list }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _put_decorators, { kind: "method", name: "put", static: false, private: false, access: { has: obj => "put" in obj, get: obj => obj.put }, metadata: _metadata }, null, _instanceExtraInitializers); + __esDecorate(this, null, _delete_decorators, { kind: "method", name: "delete", static: false, private: false, access: { has: obj => "delete" in obj, get: obj => obj.delete }, metadata: _metadata }, null, _instanceExtraInitializers); + if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + static inject = ['storageDomain', 'sessionPersistence', 'sessions']; + /** Loader validation for the required note-size policy. */ + static Config = s.object({ + maxNoteBytes: s.number().step(1).min(1).required(), + }); + maxNoteBytes = __runInitializers(this, _instanceExtraInitializers); + table; + operationTails = new Map(); + mutationAdmissionOpen = true; + /** + * @param ctx - Host context carrying persistence and the storage-domain form. + * @param config - Required note-size policy. + */ + constructor(ctx, config) { + super(ctx, 'messageFeedback'); + this.maxNoteBytes = resolveMaxNoteBytes(config.maxNoteBytes); + } + /** Open and own the one message-feedback sidecar domain. */ + async [Service.init]() { + const domain = await this.ctx.storageDomain.open(messageFeedbackDomainSpec); + this.ctx.effect(() => async () => { + this.mutationAdmissionOpen = false; + await Promise.all(this.operationTails.values()); + await domain.close(); + }, 'message-feedback.domainClose'); + this.table = domain.table('sessions'); + } + /** + * Read feedback belonging to the current persisted Session lifecycle. + * A stale row from a reused Session id is invisible. + * @param request - Session identity to inspect and list. + * @returns current immutable items or `session-not-found`. + */ + async list(request) { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) + return known; + const row = this.requireTable().get(request.sessionId); + const items = row !== undefined && sameIdentity(row, known.value.meta) ? row.items : EMPTY_ITEMS; + return success(snapshotList(items)); + } + /** + * Create or replace feedback for one derived append-origin assistant + * message. Every request must match the addressed item's current version; + * a matching no-op returns the stored item without changing its revision. + * @param request - target, desired value, and observed item version. + * @returns the committed item or an explicit business failure. + */ + put(request) { + const note = this.resolveNote(request.note); + if (!note.ok) + return Promise.resolve(note); + return this.enqueue(request.sessionId, async () => { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) + return known; + if (!this.hasFeedbackTarget(known.value, request.messageId)) { + return rejected({ + code: 'target-not-found', + sessionId: request.sessionId, + messageId: request.messageId, + }); + } + const durable = await this.ensureTargetDurable(known.value); + if (!sameHeaderIdentity(durable.meta, known.value.meta) + || !this.hasFeedbackTarget(durable, request.messageId)) { + return rejected({ + code: 'target-not-found', + sessionId: request.sessionId, + messageId: request.messageId, + }); + } + const table = this.requireTable(); + const stored = table.get(request.sessionId); + const current = stored !== undefined && sameIdentity(stored, durable.meta) ? stored : undefined; + const items = current?.items ?? EMPTY_ITEMS; + const index = items.findIndex(item => item.messageId === request.messageId); + const existing = items[index]; + if (request.ifVersion !== (existing?.version ?? null)) { + return rejected(this.versionConflict(existing ?? null)); + } + if (existing !== undefined + && existing.rating === request.rating + && existing.note === note.value) { + return success(snapshotItem(existing)); + } + const now = Date.now(); + const item = snapshotItem({ + messageId: request.messageId, + rating: request.rating, + ...(note.value === undefined ? {} : { note: note.value }), + version: nextVersion(), + createdAt: existing?.createdAt ?? now, + updatedAt: existing === undefined ? now : Math.max(now, existing.updatedAt), + }); + const nextItems = [...items]; + if (index === -1) + nextItems.push(item); + else + nextItems[index] = item; + await table.put(request.sessionId, rowSnapshot(identityOf(durable.meta), nextItems)); + return success(snapshotItem(item)); + }); + } + /** + * Delete one feedback item. Absence is successful regardless of the + * supplied version; an existing item requires an exact version match. + * @param request - Session, message, and observed item version. + * @returns the stable absent postcondition, or an explicit failure. + */ + delete(request) { + return this.enqueue(request.sessionId, async () => { + const known = await this.inspectSession(request.sessionId); + if (!known.ok) + return known; + const table = this.requireTable(); + const stored = table.get(request.sessionId); + const current = stored !== undefined && sameIdentity(stored, known.value.meta) ? stored : undefined; + const items = current?.items ?? EMPTY_ITEMS; + const existing = items.find(item => item.messageId === request.messageId); + if (existing === undefined) { + return success(Object.freeze({ absent: true })); + } + if (request.ifVersion !== existing.version) { + return rejected(this.versionConflict(existing)); + } + await table.put(request.sessionId, rowSnapshot(identityOf(known.value.meta), items.filter(item => item !== existing))); + return success(Object.freeze({ absent: true })); + }); + } + /** + * Resolve a live owner directly; otherwise use the storage catalog as the + * existence authority before inspecting the log. Inspection failures for a + * catalogued Session remain infrastructure failures rather than being + * guessed into the business `session-not-found` branch. + */ + async inspectSession(sessionId) { + if (this.ctx.sessions.get(sessionId) === undefined) { + const snapshots = await this.ctx.sessionPersistence.listSnapshots(); + if (!snapshots.some(snapshot => snapshot.header.id === sessionId) + && this.ctx.sessions.get(sessionId) === undefined) { + return rejected({ code: 'session-not-found', sessionId }); + } + } + return success(await this.ctx.sessionPersistence.inspect(sessionId)); + } + /** Require the exact finalized append-origin assistant message projection. */ + hasFeedbackTarget(inspection, messageId) { + return inspection.events.some((event) => { + if (event.type !== 'assistant/message' || !isAppendSurfaceEvent(event)) + return false; + const message = deriveEventMessage(event); + return message?.role === 'assistant' && message.id === messageId; + }); + } + /** + * Put the target log prefix behind a durability barrier before its sidecar. + * A live owner flushes through the SessionStore's canonical checkpoint; a + * cold owner is re-read from the physical durable prefix. + */ + async ensureTargetDurable(inspection) { + const live = this.ctx.sessions.get(inspection.meta.id); + if (live !== undefined && sameHeaderIdentity(live.header, inspection.meta)) { + if (!(await this.ctx.sessions.flush(live))) { + throw new Error(`message-feedback: no durability listener participated for live session '${inspection.meta.id}'`); + } + return await this.ctx.sessionPersistence.readFrom(inspection.meta.id, 0); + } + return await this.ctx.sessionPersistence.readFrom(inspection.meta.id, 0); + } + /** Validate optional-note semantics and the configured complete UTF-8 byte bound. */ + resolveNote(note) { + if (note === undefined) + return success(undefined); + if (note.trim().length === 0) + return rejected({ code: 'note-blank' }); + const actualBytes = Buffer.byteLength(note, 'utf8'); + if (actualBytes > this.maxNoteBytes) { + return rejected({ code: 'note-too-large', maxBytes: this.maxNoteBytes, actualBytes }); + } + return success(note); + } + /** Return the authoritative item needed to reconcile one failed comparison. */ + versionConflict(current) { + return { + code: 'version-conflict', + current: current === null ? null : snapshotItem(current), + }; + } + /** Queue a complete read/compare/write mutation behind this Session's prior mutation. */ + enqueue(sessionId, operation) { + if (!this.mutationAdmissionOpen) { + return Promise.reject(new Error('message-feedback: service is disposing')); + } + const previous = this.operationTails.get(sessionId) ?? Promise.resolve(); + const result = previous.then(operation); + const tail = result.then(() => undefined, () => undefined); + this.operationTails.set(sessionId, tail); + return result.finally(() => { + if (this.operationTails.get(sessionId) === tail) + this.operationTails.delete(sessionId); + }); + } + /** Resolve the initialized durable table or fail a broken service lifecycle. */ + requireTable() { + if (this.table === undefined) { + throw new Error('message-feedback: durable domain is not initialized'); + } + return this.table; + } + }; +})(); +export { MessageFeedbackService }; +export default MessageFeedbackService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.d.ts new file mode 100644 index 0000000..0fe4839 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned invariant companion. @module @deepseek-ai/dsh-message-feedback/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "message-feedback-invariant"; +/** Services required before the companion can reserve and check package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.js new file mode 100644 index 0000000..e335eea --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/invariant.js @@ -0,0 +1,19 @@ +/** Package-owned invariant companion. @module @deepseek-ai/dsh-message-feedback/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-message-feedback'; +/** Cordis companion plugin name. */ +export const name = 'message-feedback-invariant'; +/** Services required before the companion can reserve and check package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: the private typed writer owns current row mutations, + * the domain schema validates rows on reopen, and no second authority exists. + */ +const install = Object.assign(() => { }, { inject: ['messageFeedback'] }); +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.d.ts new file mode 100644 index 0000000..07f1eb1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.d.ts @@ -0,0 +1,48 @@ +/** + * Durable storage-domain declaration for lifecycle-bound message feedback. + * @module @deepseek-ai/dsh-message-feedback/src/spec + */ +import { z } from 'zod'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +import type { MessageFeedbackItem, MessageFeedbackVersion } from './types.ts'; +/** Runtime schema for the closed rating vocabulary. */ +export declare const messageFeedbackRatingSchema: z.ZodUnion, z.ZodLiteral<"negative">]>; +/** Runtime schema for one opaque item version stored on disk. */ +export declare const messageFeedbackVersionSchema: z.ZodPipe>; +/** Runtime schema for one current feedback item. */ +export declare const messageFeedbackItemSchema: z.ZodType; +/** Persisted Session fields that fence a sidecar row to one log lifecycle. */ +export declare const messageFeedbackSessionIdentitySchema: z.ZodObject<{ + createdAt: z.ZodNumber; + cwd: z.ZodOptional; +}, z.core.$strip>; +/** Persisted lifecycle identity inferred from its durable schema. */ +export type MessageFeedbackSessionIdentity = z.infer; +/** + * One whole-Session sidecar. Duplicate message ids would make item lookup + * ambiguous; duplicate versions would break their independent identity. + */ +export declare const messageFeedbackRowSchema: z.ZodObject<{ + session: z.ZodObject<{ + createdAt: z.ZodNumber; + cwd: z.ZodOptional; + }, z.core.$strip>; + items: z.ZodArray>>; +}, z.core.$strip>; +/** Durable sidecar row inferred from {@link messageFeedbackRowSchema}. */ +export type MessageFeedbackRow = z.infer; +/** One lifecycle-bound sidecar record per Session id. */ +export declare const messageFeedbackDomainSpec: { + name: string; + version: number; + tables: { + sessions: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec; + }; +}; +//# sourceMappingURL=spec.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.js new file mode 100644 index 0000000..7c67536 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/spec.js @@ -0,0 +1,74 @@ +/** + * Durable storage-domain declaration for lifecycle-bound message feedback. + * @module @deepseek-ai/dsh-message-feedback/src/spec + */ +import { z } from 'zod'; +import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'; +const nonNegativeSafeInteger = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER); +/** Runtime schema for the closed rating vocabulary. */ +export const messageFeedbackRatingSchema = z.union([ + z.literal('positive'), + z.literal('negative'), +]); +/** Runtime schema for one opaque item version stored on disk. */ +export const messageFeedbackVersionSchema = z.uuid() + .transform(value => value); +/** Runtime schema for one current feedback item. */ +// Zod infers transformed branded fields structurally, so it cannot name the +// public interface even though every branded output is created below. +export const messageFeedbackItemSchema = z.object({ + messageId: z.string().min(1).transform(value => value), + rating: messageFeedbackRatingSchema, + note: z.string().refine(note => note.trim().length > 0, { + message: 'message feedback note must contain a non-whitespace character', + }).optional(), + version: messageFeedbackVersionSchema, + createdAt: nonNegativeSafeInteger, + updatedAt: nonNegativeSafeInteger, +}).refine(item => item.updatedAt >= item.createdAt, { + path: ['updatedAt'], + message: 'message feedback updatedAt must not precede createdAt', +}); +/** Persisted Session fields that fence a sidecar row to one log lifecycle. */ +export const messageFeedbackSessionIdentitySchema = z.object({ + createdAt: nonNegativeSafeInteger, + cwd: z.string().optional(), +}); +/** + * One whole-Session sidecar. Duplicate message ids would make item lookup + * ambiguous; duplicate versions would break their independent identity. + */ +export const messageFeedbackRowSchema = z.object({ + session: messageFeedbackSessionIdentitySchema, + items: z.array(messageFeedbackItemSchema), +}).superRefine((row, ctx) => { + const messageIds = new Set(); + const versions = new Set(); + row.items.forEach((item, index) => { + if (messageIds.has(item.messageId)) { + ctx.addIssue({ + code: 'custom', + path: ['items', index, 'messageId'], + message: `duplicate message feedback id '${item.messageId}'`, + }); + } + messageIds.add(item.messageId); + if (versions.has(item.version)) { + ctx.addIssue({ + code: 'custom', + path: ['items', index, 'version'], + message: `duplicate message feedback version '${item.version}'`, + }); + } + versions.add(item.version); + }); +}); +/** One lifecycle-bound sidecar record per Session id. */ +export const messageFeedbackDomainSpec = defineDomain({ + name: 'message_feedback', + version: 0, + tables: { + sessions: domainTable(messageFeedbackRowSchema), + }, +}); +//# sourceMappingURL=spec.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.d.ts new file mode 100644 index 0000000..83eca1b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.d.ts @@ -0,0 +1,111 @@ +/** + * Public request, value, and failure vocabulary for per-message feedback. + * This module contains types only so generated Remote clients can consume it + * without importing Host runtime code. + * @module @deepseek-ai/dsh-message-feedback/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { MessageId } from '@deepseek-ai/dsh-llm/brand'; +import type { SessionId } from '@deepseek-ai/dsh-session/types'; +/** Opaque compare-and-set token for one exact feedback item revision. */ +export type MessageFeedbackVersion = Branded<'MessageFeedbackVersion'>; +/** The human's overall judgment of one assistant message. */ +export type MessageFeedbackRating = 'positive' | 'negative'; +/** One current feedback value and its opaque mutation token. */ +export interface MessageFeedbackItem { + /** Stable identity of the assistant message inside the owning Session. */ + readonly messageId: MessageId; + /** Overall positive or negative judgment. */ + readonly rating: MessageFeedbackRating; + /** Optional explanation, preserved verbatim after validation. */ + readonly note?: string; + /** Equality-only token replaced by every material create or update. */ + readonly version: MessageFeedbackVersion; + /** Host-assigned creation time in Unix epoch milliseconds. */ + readonly createdAt: number; + /** Host-assigned time of the most recent material update. */ + readonly updatedAt: number; +} +/** Read all message feedback belonging to one persisted Session lifecycle. */ +export interface MessageFeedbackListRequest { + /** Persisted Session whose sidecar should be read. */ + readonly sessionId: SessionId; +} +/** Current feedback values for one Session, in first-creation order. */ +export interface MessageFeedbackListValue { + /** Fresh immutable item snapshots. */ + readonly items: readonly MessageFeedbackItem[]; +} +/** Create or replace feedback for one assistant message. */ +export interface MessageFeedbackPutRequest { + /** Persisted Session that owns the target message. */ + readonly sessionId: SessionId; + /** Target assistant-message identity. */ + readonly messageId: MessageId; + /** Desired overall judgment. */ + readonly rating: MessageFeedbackRating; + /** Optional non-blank explanation. */ + readonly note?: string; + /** Observed item version, or `null` to require that no item exists. */ + readonly ifVersion: MessageFeedbackVersion | null; +} +/** Delete feedback for one message after observing its current version. */ +export interface MessageFeedbackDeleteRequest { + /** Persisted Session that owns the sidecar. */ + readonly sessionId: SessionId; + /** Message whose feedback should be absent after this operation. */ + readonly messageId: MessageId; + /** Observed item version; ignored when the item is already absent. */ + readonly ifVersion: MessageFeedbackVersion; +} +/** Idempotent deletion acknowledgement. */ +export interface MessageFeedbackDeleteValue { + /** Stable postcondition shared by the first deletion and every retry. */ + readonly absent: true; +} +/** No persisted Session header exists for the requested id. */ +export interface MessageFeedbackSessionNotFound { + readonly code: 'session-not-found'; + readonly sessionId: SessionId; +} +/** The id does not name a derived, append-origin assistant message. */ +export interface MessageFeedbackTargetNotFound { + readonly code: 'target-not-found'; + readonly sessionId: SessionId; + readonly messageId: MessageId; +} +/** A material mutation did not match the addressed item's current version. */ +export interface MessageFeedbackVersionConflict { + readonly code: 'version-conflict'; + /** Authoritative current item, or `null` when it does not exist. */ + readonly current: MessageFeedbackItem | null; +} +/** A supplied note contains no non-whitespace character. */ +export interface MessageFeedbackNoteBlank { + readonly code: 'note-blank'; +} +/** A supplied note exceeds the configured UTF-8 byte limit. */ +export interface MessageFeedbackNoteTooLarge { + readonly code: 'note-too-large'; + readonly maxBytes: number; + readonly actualBytes: number; +} +/** Failures shared by the public message-feedback operations. */ +export type MessageFeedbackFailure = MessageFeedbackSessionNotFound | MessageFeedbackTargetNotFound | MessageFeedbackVersionConflict | MessageFeedbackNoteBlank | MessageFeedbackNoteTooLarge; +/** Successful public operation result. */ +export interface MessageFeedbackSuccess { + readonly ok: true; + readonly value: T; +} +/** Rejected public operation result with a stable business failure. */ +export interface MessageFeedbackRejected { + readonly ok: false; + readonly error: E; +} +/** Result returned by the message-feedback `list` operation. */ +export type MessageFeedbackListResult = MessageFeedbackSuccess | MessageFeedbackRejected; +/** Result returned by the message-feedback `put` operation. */ +export type MessageFeedbackPutResult = MessageFeedbackSuccess | MessageFeedbackRejected; +/** Result returned by the message-feedback `delete` operation. */ +export type MessageFeedbackDeleteResult = MessageFeedbackSuccess | MessageFeedbackRejected; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.js new file mode 100644 index 0000000..57ea1f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/lib/types/types.js @@ -0,0 +1,8 @@ +/** + * Public request, value, and failure vocabulary for per-message feedback. + * This module contains types only so generated Remote clients can consume it + * without importing Host runtime code. + * @module @deepseek-ai/dsh-message-feedback/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/package.json new file mode 100644 index 0000000..537ccfe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback/package.json @@ -0,0 +1,80 @@ +{ + "name": "@deepseek-ai/dsh-message-feedback", + "description": "Lifecycle-bound per-message rating and note sidecar for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/feedback/message-feedback" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./typert": { + "types": "./lib/typert.host.d.ts", + "default": "./lib/typert.host.js" + }, + "./remote": { + "types": "./lib/typert.remote-client.d.ts", + "default": "./lib/typert.remote-client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts", + "lib/typert.host.js", + "lib/typert.host.d.ts", + "lib/typert.remote-client.js", + "lib/typert.remote-client.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7" + }, + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage-json": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..5362978 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-storage-domain b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-storage-domain new file mode 120000 index 0000000..f157433 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-storage-domain @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..a2fcff1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.i18n.yaml new file mode 100644 index 0000000..e890eca --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/native-command/README.md +README.md: 8a552ac36fac150ae18b2a8adaab1dd489ecb476 +README.zh.md: 618e50afe7cd157b2dfc4763adfbf1d5d88d213e diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.md new file mode 100644 index 0000000..8a552ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.md @@ -0,0 +1,27 @@ +# dsh-native-command + +English | [中文](README.zh.md) + +A **zero-dependency no-shell `execFile` runner** shared by host-native OS integrations: one `runNativeCommand(command, args, signal)` call spawns the executable directly (never a shell string), captures utf8 stdout/stderr, propagates the caller's abort into child termination, and hides the transient console window on Windows. Failures reject with the exit `code` and both captured streams attached, so callers classify (missing tool, cancelled, real failure) without re-running anything. + +Its two consumers are the host-side native integrations: the [`directory-picker-native`](../../host/directory-picker-native/README.md) backend's OS chooser commands and the gateway's open-with-default-application hand-off ([`dsh-host-apiproxy`](../../host/apiproxy/README.md) `host.openPath`). The `NativeCommandRunner` type is their injectable command boundary. + +It is a **library, not a service or plugin**: no `ctx`, registers nothing, holds no state, emits no events. + +## Surface + +```ts +import { runNativeCommand, type NativeCommandRunner } from '@deepseek-ai/dsh-native-command' +``` + +## Model Experience + +None, as this is host-side subprocess plumbing; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **No output bounding** — both streams buffer unbounded in memory; every current caller invokes small native tools whose output is a path or an error line. Adopt `dsh-output-retention` bounding before pointing this at commands with meaningful output volume. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.zh.md new file mode 100644 index 0000000..618e50a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/README.zh.md @@ -0,0 +1,27 @@ +# dsh-native-command + +[English](README.md) | 中文 + +宿主原生 OS 集成共享的**零依赖免 shell `execFile` 运行器**:一次 `runNativeCommand(command, args, signal)` 调用直接 spawn 可执行文件(绝不拼 shell 字符串),以 utf8 捕获 stdout/stderr,把调用方的 abort 传播为子进程终止,并在 Windows 上隐藏瞬时控制台窗口。失败时,调用会以错误拒绝;该错误附带退出 `code` 与两路已捕获输出,调用方无需重跑即可分类(工具缺失、已取消、真实失败)。 + +它的两个消费方都是宿主侧原生集成:[`directory-picker-native`](../../host/directory-picker-native/README.md) 后端的 OS 选择器命令,以及网关将路径交由默认应用打开的操作([`dsh-host-apiproxy`](../../host/apiproxy/README.md) 的 `host.openPath`)。`NativeCommandRunner` 类型是这些调用方的可注入命令边界。 + +它是**库,不是服务或插件**:没有 `ctx`、不注册任何东西、不持有状态、不发事件。 + +## 接口面 + +```ts +import { runNativeCommand, type NativeCommandRunner } from '@deepseek-ai/dsh-native-command' +``` + +## 模型体验 + +无;这是宿主侧子进程管道,这里没有任何东西进入模型请求。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **不做输出限量**——两路流在内存中无界缓冲;当前每个调用方只运行输出为一个路径或一行错误的小型原生工具。把它指向输出量可观的命令之前,先接入 `dsh-output-retention` 限量。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/index.js new file mode 100644 index 0000000..7cbe606 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/index.js @@ -0,0 +1,38 @@ +import { execFile } from "node:child_process"; +//#region lib/types/index.js +/** +* Shared no-shell `execFile` runner for host-native OS integrations (the +* native directory chooser, the open-with-default-application hand-off): +* utf8 stdio capture, abort propagation, Windows console hide. A library, +* not a plugin — no ctx, no state, no events. +* @module @deepseek-ai/dsh-native-command +*/ +/** +* Run a host command with utf8 stdio, abort propagation, and Windows hide. +* @param command - executable path or PATH name. +* @param args - argv (never a shell string). +* @param signal - caller/connection lifetime; abort terminates the child. +* @returns captured stdout/stderr on exit 0. +*/ +const runNativeCommand = (command, args, signal) => new Promise((resolve, reject) => { + execFile(command, [...args], { + encoding: "utf8", + signal, + windowsHide: true + }, (error, stdout, stderr) => { + if (error !== null) { + reject(Object.assign(new Error(error.message, { cause: error }), { + code: error.code, + stdout, + stderr + })); + return; + } + resolve({ + stdout, + stderr + }); + }); +}); +//#endregion +export { runNativeCommand }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/invariant.js new file mode 100644 index 0000000..f94f502 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/invariant.js @@ -0,0 +1,24 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-native-command`. +* @module @deepseek-ai/dsh-native-command/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-native-command"; +/** Cordis companion plugin name. */ +const name = "native-command-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: each run is one stateless child-process round trip +* with no owned event stream or mutable runtime data; behavior is enforced by +* unit tests. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/types/index.d.ts new file mode 100644 index 0000000..16674c7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/types/index.d.ts @@ -0,0 +1,21 @@ +/** + * Shared no-shell `execFile` runner for host-native OS integrations (the + * native directory chooser, the open-with-default-application hand-off): + * utf8 stdio capture, abort propagation, Windows console hide. A library, + * not a plugin — no ctx, no state, no events. + * @module @deepseek-ai/dsh-native-command + */ +/** Testable command boundary; native implementations never invoke a shell. */ +export type NativeCommandRunner = (command: string, args: readonly string[], signal: AbortSignal) => Promise<{ + stdout: string; + stderr: string; +}>; +/** + * Run a host command with utf8 stdio, abort propagation, and Windows hide. + * @param command - executable path or PATH name. + * @param args - argv (never a shell string). + * @param signal - caller/connection lifetime; abort terminates the child. + * @returns captured stdout/stderr on exit 0. + */ +export declare const runNativeCommand: NativeCommandRunner; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/types/invariant.d.ts new file mode 100644 index 0000000..06318d4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-native-command`. + * @module @deepseek-ai/dsh-native-command/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "native-command-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/package.json new file mode 100644 index 0000000..113490c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_7f4ae8813dddb178bbb32bf5e8dc8c45/node_modules/@deepseek-ai/dsh-native-command/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-native-command", + "description": "Zero-dependency no-shell execFile runner for host-native OS integrations: utf8 stdio capture, abort propagation, Windows hide", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/util/native-command" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.i18n.yaml new file mode 100644 index 0000000..e890eca --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/native-command/README.md +README.md: 8a552ac36fac150ae18b2a8adaab1dd489ecb476 +README.zh.md: 618e50afe7cd157b2dfc4763adfbf1d5d88d213e diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.md new file mode 100644 index 0000000..8a552ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.md @@ -0,0 +1,27 @@ +# dsh-native-command + +English | [中文](README.zh.md) + +A **zero-dependency no-shell `execFile` runner** shared by host-native OS integrations: one `runNativeCommand(command, args, signal)` call spawns the executable directly (never a shell string), captures utf8 stdout/stderr, propagates the caller's abort into child termination, and hides the transient console window on Windows. Failures reject with the exit `code` and both captured streams attached, so callers classify (missing tool, cancelled, real failure) without re-running anything. + +Its two consumers are the host-side native integrations: the [`directory-picker-native`](../../host/directory-picker-native/README.md) backend's OS chooser commands and the gateway's open-with-default-application hand-off ([`dsh-host-apiproxy`](../../host/apiproxy/README.md) `host.openPath`). The `NativeCommandRunner` type is their injectable command boundary. + +It is a **library, not a service or plugin**: no `ctx`, registers nothing, holds no state, emits no events. + +## Surface + +```ts +import { runNativeCommand, type NativeCommandRunner } from '@deepseek-ai/dsh-native-command' +``` + +## Model Experience + +None, as this is host-side subprocess plumbing; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **No output bounding** — both streams buffer unbounded in memory; every current caller invokes small native tools whose output is a path or an error line. Adopt `dsh-output-retention` bounding before pointing this at commands with meaningful output volume. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.zh.md new file mode 100644 index 0000000..618e50a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/README.zh.md @@ -0,0 +1,27 @@ +# dsh-native-command + +[English](README.md) | 中文 + +宿主原生 OS 集成共享的**零依赖免 shell `execFile` 运行器**:一次 `runNativeCommand(command, args, signal)` 调用直接 spawn 可执行文件(绝不拼 shell 字符串),以 utf8 捕获 stdout/stderr,把调用方的 abort 传播为子进程终止,并在 Windows 上隐藏瞬时控制台窗口。失败时,调用会以错误拒绝;该错误附带退出 `code` 与两路已捕获输出,调用方无需重跑即可分类(工具缺失、已取消、真实失败)。 + +它的两个消费方都是宿主侧原生集成:[`directory-picker-native`](../../host/directory-picker-native/README.md) 后端的 OS 选择器命令,以及网关将路径交由默认应用打开的操作([`dsh-host-apiproxy`](../../host/apiproxy/README.md) 的 `host.openPath`)。`NativeCommandRunner` 类型是这些调用方的可注入命令边界。 + +它是**库,不是服务或插件**:没有 `ctx`、不注册任何东西、不持有状态、不发事件。 + +## 接口面 + +```ts +import { runNativeCommand, type NativeCommandRunner } from '@deepseek-ai/dsh-native-command' +``` + +## 模型体验 + +无;这是宿主侧子进程管道,这里没有任何东西进入模型请求。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **不做输出限量**——两路流在内存中无界缓冲;当前每个调用方只运行输出为一个路径或一行错误的小型原生工具。把它指向输出量可观的命令之前,先接入 `dsh-output-retention` 限量。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/index.js new file mode 100644 index 0000000..7cbe606 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/index.js @@ -0,0 +1,38 @@ +import { execFile } from "node:child_process"; +//#region lib/types/index.js +/** +* Shared no-shell `execFile` runner for host-native OS integrations (the +* native directory chooser, the open-with-default-application hand-off): +* utf8 stdio capture, abort propagation, Windows console hide. A library, +* not a plugin — no ctx, no state, no events. +* @module @deepseek-ai/dsh-native-command +*/ +/** +* Run a host command with utf8 stdio, abort propagation, and Windows hide. +* @param command - executable path or PATH name. +* @param args - argv (never a shell string). +* @param signal - caller/connection lifetime; abort terminates the child. +* @returns captured stdout/stderr on exit 0. +*/ +const runNativeCommand = (command, args, signal) => new Promise((resolve, reject) => { + execFile(command, [...args], { + encoding: "utf8", + signal, + windowsHide: true + }, (error, stdout, stderr) => { + if (error !== null) { + reject(Object.assign(new Error(error.message, { cause: error }), { + code: error.code, + stdout, + stderr + })); + return; + } + resolve({ + stdout, + stderr + }); + }); +}); +//#endregion +export { runNativeCommand }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/invariant.js new file mode 100644 index 0000000..f94f502 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/invariant.js @@ -0,0 +1,24 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-native-command`. +* @module @deepseek-ai/dsh-native-command/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-native-command"; +/** Cordis companion plugin name. */ +const name = "native-command-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: each run is one stateless child-process round trip +* with no owned event stream or mutable runtime data; behavior is enforced by +* unit tests. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/types/index.d.ts new file mode 100644 index 0000000..16674c7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/types/index.d.ts @@ -0,0 +1,21 @@ +/** + * Shared no-shell `execFile` runner for host-native OS integrations (the + * native directory chooser, the open-with-default-application hand-off): + * utf8 stdio capture, abort propagation, Windows console hide. A library, + * not a plugin — no ctx, no state, no events. + * @module @deepseek-ai/dsh-native-command + */ +/** Testable command boundary; native implementations never invoke a shell. */ +export type NativeCommandRunner = (command: string, args: readonly string[], signal: AbortSignal) => Promise<{ + stdout: string; + stderr: string; +}>; +/** + * Run a host command with utf8 stdio, abort propagation, and Windows hide. + * @param command - executable path or PATH name. + * @param args - argv (never a shell string). + * @param signal - caller/connection lifetime; abort terminates the child. + * @returns captured stdout/stderr on exit 0. + */ +export declare const runNativeCommand: NativeCommandRunner; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/types/invariant.d.ts new file mode 100644 index 0000000..06318d4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-native-command`. + * @module @deepseek-ai/dsh-native-command/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "native-command-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/package.json new file mode 100644 index 0000000..223ff2d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-native-command", + "description": "Zero-dependency no-shell execFile runner for host-native OS integrations: utf8 stdio capture, abort propagation, Windows hide", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/util/native-command" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.i18n.yaml new file mode 100644 index 0000000..52b812a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/scope/README.md +README.md: 1ed09acd7ccb864b16fb5d2ac4390264085d1c9e +README.zh.md: ef483412307833937a1b2558125c1955b0b96c3b diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.md new file mode 100644 index 0000000..1ed09ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.md @@ -0,0 +1,37 @@ +# dsh-scope + +English | [中文](README.zh.md) + +Scoped registration primitive. `createScope(ctx, key)` creates a tagged Cordis context whose backing fiber owns every registration made through it. `scopeOf(ctx)` reads the tag, and `scopeTarget(base, key)` routes scoped events to listeners with the same key while leaving unscoped listeners global. Keys form an optional parent chain (`bindScopeParent`): registration views inherit DOWN it — a child scope sees its ancestors' layers, nearest shadowing farthest — and event admission extends UP it — a listener tagged with an ancestor receives a descendant key's events, never the reverse. The agent loop creates one scope per live agent and an agent preset's standing mount is a parent scope over its agents, but the mechanism is key-agnostic so lower-level packages can use it without depending on either. + +## Public API + +- `createScope(ctx: Context, key: ScopeKey, options?): Scope` Mint a scope under `ctx`'s fiber. Usable synchronously (effect collection is uid-gated; service resolution falls through to the minting plugin's dependency surface). The typed, same-process key is trusted; an inactive minting context still fails through Cordis (`INACTIVE_EFFECT`). `options.parent` binds the enclosing scope via `bindScopeParent` before the scope is usable; the binding stays internal. +- `bindScopeParent(key, parent): ScopeParentBinding` / `scopeParentOf(key)` / `scopeChainOf(key)` The parent relation behind both chain directions. Binding is once: a key that already has a parent throws, and only the returned binding's `rebind(parent)` may re-link it — the blank-session recompose operation, valid only while nothing produced under the old parent is retained (the holder's contract — this relation cannot see what a session logged). Both the bind and every rebind reject a link closing a cycle. `scopeChainOf` returns `[key, parent, …]` nearest-first. +- `Scope.ctx` The tagged context: registrations through it are scope-visible AND scope-lifetime. Derived contexts (an `extend`, a fiber mounted under it) inherit the tag; nested scopes shadow (nearest tag wins). +- `Scope.rawDispose` The EXACT Cordis disposer for the backing fiber — a composite (generator) effect yields THIS function to nest the scope's teardown at that yield position (Cordis dedupes nested effects by function identity; yielding a wrapper leaves the scope disposing as a concurrent sibling). +- `Scope.dispose(): Promise` Idempotent, shared quiescence boundary for every registration made through the scope. Racing/repeat calls await the same teardown, including when `rawDispose` invoked the underlying single-shot Cordis disposer first. +- `scopeOf(ctx: Context): ScopeKey | undefined` The tag a context (or any context derived from it) carries; `undefined` = context-global. +- `scopeTarget(base: T, key: ScopeKey | undefined): Scoped` Build the opaque dispatch `thisArg` for a scope-filtered event. It composes `base`'s existing `Context.filter` with the scope predicate (untagged listener ⇒ admitted; tagged ⇒ admitted iff its tag is the key or an ancestor of it; `key === undefined` ⇒ untagged only). The carrier contains routing state only; the real subject is carried by the event arguments. `{ global: true }` listeners bypass filtering (Cordis semantics). +- `Scoped` The compile-time opaque carrier brand: scope-filtered events demand it as their `this` type, so dispatching with a bare subject is a compile error. The type parameter records the subject type but does not expose its properties. +- `isScopeCarrier(value)` / `carrierKeyOf(value)` Runtime carrier marks, used by the dev invariants to assert every scope-filtered dispatch carries a carrier keyed to the subject its arguments name. +- `ScopeLayer` Aggregate contract for one registry's complete global or exact-scope contribution; `isEmpty()` controls scoped-layer reclamation. +- `ScopedLayers` Own one eager global layer and lazy exact-scope layers. `peek()` never creates and stays chain-blind (a scope's OWN contributions — restrictions, guards — must not silently pick up an ancestor's), `chainLayers()` returns existing overlays farthest-ancestor-first, `merge()` materializes insertion-ordered named shadows along the chain, and `effect()` derives visibility and ownership from the same context while returning the exact Cordis disposer. +- `NamedEntries` Insertion-ordered named storage with caller-owned duplicate diagnostics, lookup, and live iteration within one nonempty table generation; draining the table detaches existing iterators from later insertions, and `insert()` returns an idempotent exact-entry undo. +- `AnonymousEntries` Insertion-ordered anonymous storage whose unique internal keys keep equal values as independent registrations; it uses the same drained-generation iterator boundary, and `append()` returns an idempotent exact-entry undo. + +The optional `@deepseek-ai/dsh-scope/invariant` companion owns that runtime assertion. It uses the generated `scoped-events.generated.ts` resolver map to require a carrier for every declared scoped event and, when the payload exposes its routing subject, require identity with the carrier key. The Program-backed generator derives the map from event declarations and real `scopeTarget(base, key)` calls. + +## Design contract + +The registration context determines both visibility and ownership, preventing a registration from being visible in one scope but disposed with another. Scopes route trusted same-process plugins; they are not sandboxes or authority boundaries. See the [agent-scope Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals) for rationale and security non-goals. + +Scope-aware services define a concrete `ScopeLayer` that aggregates their heterogeneous tables and domain helpers. `ScopedLayers.effect()` accepts one synchronous action returning one synchronous undo, installs that undo before optional notification, and reclaims an exact-scope layer only when the complete aggregate is empty. `notify` defaults to `true`; the supplied callback owns whether observer failures throw or are contained. `EntryValues` remains internal, the storage classes are imported from the package root rather than a `/store` subpath, and the shared storage does not define registry-specific filtering or iteration policy. See the [shared scoped-layer storage Agent Note](../../../.agents/notes/implemented/architecture/2026-07-12-scoped-layers-store.md). + +Handing out a scoped context hands out the minting plugin's service-resolution API (resolution walks the minting fiber's dependency chain, not the holder's) — mint it from the plugin whose dependencies the scoped registrations need to resolve. + +## Known Limitations and Deferred Work + +- **Only scope-aware APIs isolate state** — registries must file by `scopeOf()` and events must dispatch through `scopeTarget()`; an arbitrary Cordis service remains context-global merely because it is called through a scoped context. +- **A context carries one nearest scope key** — the hierarchy lives in the key-level parent relation, not in context tags; nested scope CONTEXTS still shadow to a single tag, and multi-membership policy sets remain unsupported. +- **Service reachability comes from the scope minter** — handing out `Scope.ctx` also hands out the minting plugin's injected services, so a broader minter cannot later be narrowed by the holder. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.zh.md new file mode 100644 index 0000000..ef48341 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/README.zh.md @@ -0,0 +1,37 @@ +# dsh-scope + +[English](README.md) | 中文 + +带作用域的注册原语。`createScope(ctx, key)` 创建一个带标签的 Cordis 上下文,其底层 fiber 拥有通过该上下文进行的每项注册。`scopeOf(ctx)` 读取标签;`scopeTarget(base, key)` 将带作用域的事件路由到键相同的监听器,同时让无作用域监听器保持全局可见。键可以构成可选的父链(`bindScopeParent`):注册视图沿链**向下**继承——子作用域看得见祖先各层,近者遮蔽远者——事件放行沿链**向上**扩展——标签为祖先的监听器能收到子孙键的事件,反向永不成立。agent loop(智能体循环)为每个存活的 agent 创建一个作用域,agent preset 的常驻挂载则是其 agent 们的父作用域,但该机制与键的具体含义无关,底层包无需依赖两者即可使用。 + +## 公开 API + +- `createScope(ctx: Context, key: ScopeKey, options?): Scope`:在 `ctx` 的 fiber 下创建作用域。可以同步使用(effect 收集受 uid 门禁约束;服务解析会沿创建该作用域的插件依赖范围继续查找)。同进程、带类型的键受信任;处于非活动状态的创建上下文仍会通过 Cordis 失败(`INACTIVE_EFFECT`)。`options.parent` 在作用域可用之前经 `bindScopeParent` 绑定其外围作用域;绑定句柄不外泄。 +- `bindScopeParent(key, parent): ScopeParentBinding` / `scopeParentOf(key)` / `scopeChainOf(key)`:支撑两条链方向的父关系。绑定仅此一次:已有父级的键直接抛错,只有返回的绑定句柄的 `rebind(parent)` 才能重新绑定父级——即空白会话 recompose 的操作,仅当旧父之下产出的东西一概不被保留时才合法(这是持有方的约定——该关系看不见会话记录了什么)。绑定与每次 rebind 都拒绝会闭环的链接。`scopeChainOf` 返回 `[key, parent, …]`,最近者在前。 +- `Scope.ctx`:带标签的上下文。通过它进行的注册既具备作用域可见性,也服从作用域生命周期。派生上下文(一次 `extend`、挂载于其下的 fiber)继承标签;嵌套作用域会遮蔽外层标签(最近的标签生效)。 +- `Scope.rawDispose`:底层 fiber 的确切 Cordis disposer。组合式(generator)effect 会 yield 此函数,从而把作用域 teardown 嵌套在该 yield 位置(Cordis 按函数标识去重嵌套 effect;yield 一个包装函数会使作用域 teardown 成为并行的同级操作)。 +- `Scope.dispose(): Promise`:通过作用域进行的每项注册所共用的幂等完全停稳边界。竞态调用或重复调用会等待同一次 teardown;即使 `rawDispose` 先调用了底层单次 Cordis disposer 也是如此。 +- `scopeOf(ctx: Context): ScopeKey | undefined`:上下文或其任意派生上下文携带的标签;`undefined` 表示上下文全局。 +- `scopeTarget(base: T, key: ScopeKey | undefined): Scoped`:为按作用域筛选的事件构造不透明分发 `thisArg`。它把 `base` 现有的 `Context.filter` 与作用域谓词组合起来(无标签监听器 ⇒ 放行;有标签监听器 ⇒ 仅当标签 === key,或标签为 key 的祖先时放行;`key === undefined` ⇒ 仅放行无标签监听器)。载体只包含路由状态;真实主体由事件参数携带。带 `{ global: true }` 的监听器绕过筛选(Cordis 语义)。 +- `Scoped`:编译期不透明载体 brand。按作用域筛选的事件要求它作为 `this` 类型,因此使用裸主体分发会产生编译错误。类型参数记录主体类型,但不公开其属性。 +- `isScopeCarrier(value)`/`carrierKeyOf(value)`:运行时载体标记,开发不变式使用它们断言每次按作用域筛选的分发都携带载体,而且载体键与参数所指名的主体一致。 +- `ScopeLayer`:一个注册表的完整全局贡献或精确作用域贡献的聚合约定;`isEmpty()` 控制带作用域层的回收。 +- `ScopedLayers`:持有一个立即构造的全局层与惰性的精确作用域层。`peek()` 从不创建且刻意不看链(某作用域**自己**的贡献——限制、守卫——不得悄悄继承祖先的),`chainLayers()` 按最远祖先在前返回已存在的各层,`merge()` 沿链物化按插入序的具名遮蔽,`effect()` 从同一上下文推导可见性与所有权,并返回精确的 Cordis disposer。 +- `NamedEntries`:按插入顺序排列的具名存储,调用方拥有重复项诊断、查找,以及一个非空表世代内的实时迭代。表清空后,现有迭代器与后续插入项脱离;`insert()` 返回幂等的精确条目撤销函数。 +- `AnonymousEntries`:按插入顺序排列的匿名存储;唯一内部键使相同值仍作为独立注册存在。它使用相同的清空世代迭代器边界;`append()` 返回幂等的精确条目撤销函数。 + +可选配套包 `@deepseek-ai/dsh-scope/invariant` 拥有该运行时断言。它使用生成的 `scoped-events.generated.ts` 解析器映射,要求每个已声明的带作用域事件都携带载体;当 payload 公开路由主体时,还要求路由主体与载体键严格相等。基于 Program 的生成器根据事件声明和真实的 `scopeTarget(base, key)` 调用生成该映射。 + +## 设计约定 + +注册上下文同时决定可见性和所有权,防止注册在一个作用域中可见、却随另一个作用域 dispose(资源释放)。作用域用于路由受信任的同进程插件;它们不是沙箱或权限边界。原理与明确排除的安全目标见 [agent 作用域 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals)。 + +感知作用域的服务会定义具体 `ScopeLayer`,聚合各自不同的表与领域辅助函数。`ScopedLayers.effect()` 接受一个返回同步撤销函数的同步动作,在可选通知前安装该撤销函数,并且只有在完整聚合为空时才回收精确作用域层。`notify` 默认为 `true`;由所提供的回调决定观测方失败是向外抛出还是在内部处理。`EntryValues` 保持内部可见;存储类从包根而非 `/store` 子路径导入;共享存储不定义注册表专属的筛选或迭代策略。详见[共享作用域层存储 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-12-scoped-layers-store.md)。 + +交出带作用域的上下文,也会交出创建该上下文的插件的服务解析范围(解析会沿创建者 fiber 的依赖链,而非持有者的依赖链行进),因此应由具备这些带作用域注册所需依赖的插件来创建它。 + +## 已知限制与暂缓事项 + +- **只有感知作用域的表层才会隔离状态**:注册表必须按 `scopeOf()` 归档,事件必须通过 `scopeTarget()` 分发;仅仅通过带作用域的上下文调用任意 Cordis 服务,并不会改变该服务仍为上下文全局这一事实。 +- **一个上下文只携带一个最近的作用域键**:层级关系存在于键级父关系中而非上下文标签里;嵌套作用域**上下文**仍遮蔽为单一标签,多成员策略集仍不受支持。 +- **服务可达性来自作用域创建者**:交出 `Scope.ctx` 也会交出创建插件注入的服务范围,因此,若作用域创建者提供的服务范围较宽,持有者之后也无法将其收窄。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/index.js new file mode 100644 index 0000000..8359860 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/index.js @@ -0,0 +1,357 @@ +import { Context } from "@deepseek-ai/cordis"; +//#region lib/types/store.js +/** +* Shared insertion-ordered storage and effect ownership for scope-aware registries. +* +* @module @deepseek-ai/dsh-scope +*/ +/** +* Insertion-ordered named entries with caller-owned duplicate diagnostics. +* +* Values are borrowed. Iterators are live within one nonempty table +* generation; draining the table detaches them from later insertions. Each +* successful insertion returns an idempotent undo for that exact entry. +*/ +var NamedEntries = class { + duplicateError; + data = /* @__PURE__ */ new Map(); + constructor(duplicateError) { + this.duplicateError = duplicateError; + } + /** + * Insert one unique name. + * @param name - name unique within this table. + * @param value - borrowed value to retain. + * @returns an idempotent undo that removes only this insertion. + */ + insert(name, value) { + const data = this.data; + if (data.has(name)) throw this.duplicateError(name); + data.set(name, value); + let active = true; + return () => { + if (!active) return; + active = false; + data.delete(name); + if (data.size === 0 && this.data === data) this.data = /* @__PURE__ */ new Map(); + }; + } + /** + * Read one named value. + * @param name - name to resolve. + * @returns the retained value, or `undefined` when absent. + */ + get(name) { + return this.data.get(name); + } + /** + * Test one name for membership. + * @param name - name to test. + * @returns whether the table contains that name. + */ + has(name) { + return this.data.has(name); + } + /** + * Iterate live names in insertion order. + * @returns the native live key iterator. + */ + keys() { + return this.data.keys(); + } + /** + * Iterate live entries in insertion order. + * @returns the native live entry iterator. + */ + entries() { + return this.data.entries(); + } + /** + * Iterate live values in insertion order. + * @returns the native live value iterator. + */ + values() { + return this.data.values(); + } + /** + * Test whether this table has no entries. + * @returns whether the table is empty. + */ + isEmpty() { + return this.data.size === 0; + } +}; +/** +* Insertion-ordered anonymous entries with independent registration identity. +* +* Equal values remain separate registrations. Values are borrowed, and +* iterators are live within one nonempty table generation; draining the table +* detaches them from later appends. +*/ +var AnonymousEntries = class { + data = /* @__PURE__ */ new Map(); + /** + * Append one independently owned value. + * @param value - borrowed value to retain. + * @returns an idempotent undo for this exact append. + */ + append(value) { + const data = this.data; + const key = Symbol(); + data.set(key, value); + let active = true; + return () => { + if (!active) return; + active = false; + data.delete(key); + if (data.size === 0 && this.data === data) this.data = /* @__PURE__ */ new Map(); + }; + } + /** + * Iterate live values in insertion order. + * @returns the native live value iterator. + */ + values() { + return this.data.values(); + } + /** + * Test whether this table has no entries. + * @returns whether the table is empty. + */ + isEmpty() { + return this.data.size === 0; + } +}; +/** +* Own the global and exact-scope layers for one registry. +* +* Reads never create scoped layers. Registrations derive both visibility and +* effect ownership from the supplied Cordis context, collect undo before +* notification, and reclaim only a completely empty aggregate layer. +*/ +var ScopedLayers = class { + createLayer; + onChange; + /** The eagerly constructed context-global layer. */ + global; + scoped = /* @__PURE__ */ new Map(); + constructor(createLayer, onChange) { + this.createLayer = createLayer; + this.onChange = onChange; + this.global = createLayer(void 0); + } + /** + * Read an existing exact-scope overlay. Deliberately chain-blind: callers + * addressing one scope's OWN contributions (its restrictions, its guards) + * must not silently pick up an ancestor's — use {@link chainLayers} where + * inheritance is the point. + * @param scope - exact scope key; `undefined` denotes no overlay. + * @returns the existing scoped layer, or `undefined` without creating one. + */ + peek(scope) { + if (scope === void 0) return void 0; + return this.scoped.get(scope); + } + /** + * Existing overlays along the scope's parent chain ({@link scopeChainOf}), + * farthest ancestor first and the exact scope last, so a caller layering + * them in order gives the nearest scope the final word. + * @param scope - viewing scope, or `undefined` for no overlays. + * @returns the existing layers, nearest last; absent overlays are skipped. + */ + chainLayers(scope) { + const layers = []; + for (const key of scopeChainOf(scope).reverse()) { + const layer = this.scoped.get(key); + if (layer !== void 0) layers.push(layer); + } + return layers; + } + /** + * Materialize global named entries followed by scope-chain shadows, + * farthest ancestor first, so the nearest scope's entry wins a name. + * @param scope - viewing scope, or `undefined` for the global view. + * @param pick - select the named table from a layer. + * @returns an insertion-ordered effective map. + */ + merge(scope, pick) { + const merged = new Map(pick(this.global).entries()); + for (const layer of this.chainLayers(scope)) for (const [name, value] of pick(layer).entries()) merged.set(name, value); + return merged; + } + /** + * Attach one synchronous layer mutation to its registration context. + * @param ctx - context that determines both scope visibility and effect ownership. + * @param action - atomic mutation returning its synchronous undo. + * @param options - Cordis effect label and optional change notification. + * @returns the exact disposer returned by `ctx.effect()`. + */ + effect(ctx, action, options) { + const scope = scopeOf(ctx); + const notify = options.notify ?? true; + return ctx.effect(function* () { + let layer; + let created = false; + if (scope === void 0) layer = this.global; + else { + const existing = this.scoped.get(scope); + if (existing === void 0) { + layer = this.createLayer(scope); + this.scoped.set(scope, layer); + created = true; + } else layer = existing; + } + let undo; + try { + undo = action(layer); + } catch (error) { + if (scope !== void 0 && created && layer.isEmpty()) this.scoped.delete(scope); + throw error; + } + yield () => { + undo(); + if (scope !== void 0 && layer.isEmpty()) this.scoped.delete(scope); + if (notify) this.onChange(); + }; + if (notify) this.onChange(); + }.bind(this), options.label); + } +}; +//#endregion +//#region lib/types/index.js +/** +* Scoped-context primitive: mint a Cordis context that tags registrations with +* an opaque identity and build routing-only event carriers for that identity. +* +* @module @deepseek-ai/dsh-scope +*/ +/** Context tag written by {@link createScope}. */ +const kScope = Symbol("dsh.scope"); +/** The key associated with each carrier. Presence distinguishes an unkeyed carrier from a non-carrier. */ +const carrierKeys = /* @__PURE__ */ new WeakMap(); +/** +* The enclosing scope of each key. One relation powers both directions of +* scope nesting: registration views inherit DOWN the chain (a child scope +* sees its ancestors' layers — {@link ScopedLayers}), and event admission +* extends UP it (a listener tagged with an ancestor receives events dispatched +* to a descendant key — {@link scopeTarget}). +*/ +const scopeParents = /* @__PURE__ */ new WeakMap(); +/** Cycle-checked write shared by the bind and every rebind. */ +function linkScopeParent(key, parent) { + for (let cursor = parent; cursor !== void 0; cursor = scopeParents.get(cursor)) if (cursor === key) throw new Error("dsh-scope: scope parent link would form a cycle"); + scopeParents.set(key, parent); +} +/** +* Bind `parent` as `key`'s enclosing scope, once. +* +* A key that already has a parent throws: there is no open re-link path, so a +* scope's ancestry cannot be moved by anyone but the original binder, who +* alone receives the {@link ScopeParentBinding}. A link that would close a +* cycle is rejected, because every chain consumer walks parents to the root. +* @param key - the child scope key. +* @param parent - its enclosing scope key. +* @returns the binding that alone may re-link this key. +*/ +function bindScopeParent(key, parent) { + if (scopeParents.has(key)) throw new Error("dsh-scope: scope key is already bound to a parent; re-linking requires the binding returned by the original bind"); + linkScopeParent(key, parent); + return { rebind(next) { + linkScopeParent(key, next); + } }; +} +/** +* Read one key's enclosing scope. +* @param key - the scope key to inspect. +* @returns its parent key, or `undefined` for a root scope. +*/ +function scopeParentOf(key) { + return scopeParents.get(key); +} +/** +* The chain from a key to its root ancestor. +* @param key - the starting key, or `undefined` for the empty chain. +* @returns keys nearest-first: `[key, parent, grandparent, …]`. +*/ +function scopeChainOf(key) { + const chain = []; + for (let cursor = key; cursor !== void 0; cursor = scopeParents.get(cursor)) chain.push(cursor); + return chain; +} +/** Follow a Cordis fiber through asynchronous teardown even if its raw disposer was already claimed. */ +async function quiesceFiber(fiber) { + await Promise.resolve(fiber.dispose()); + while (fiber.inertia !== void 0) await fiber.inertia; +} +/** Shared no-op plugin used as the backing scope fiber. */ +function scope() {} +/** +* Mint a scope under `ctx`. The scoped context inherits the minting plugin's +* dependency API and owns every registration made through it. +* @param ctx - active context whose dependency API the scope inherits. +* @param key - opaque identity used for listener routing. +* @param options - optional scope-chain placement. +* @returns the scoped context and exact/shared disposal boundaries. +*/ +function createScope(ctx, key, options) { + if (options?.parent !== void 0) bindScopeParent(key, options.parent); + const fiber = ctx.plugin(scope); + const scoped = fiber.ctx.extend({ [kScope]: key }); + let disposing; + return { + ctx: scoped, + rawDispose: fiber.dispose, + dispose: () => disposing ??= quiesceFiber(fiber) + }; +} +/** +* Read the nearest scope tag inherited by a context. +* @param ctx - context to inspect. +* @returns its scope key, or `undefined` for an unscoped context. +*/ +function scopeOf(ctx) { + return ctx[kScope]; +} +/** +* Build an opaque receiver that preserves the base filter, admits untagged +* listeners globally, and admits tagged listeners for a matching key or any +* of its ancestors ({@link bindScopeParent}): a listener owned by an enclosing +* scope receives every descendant scope's events, which is what lets one +* standing composition observe each of the agents composed under it. A tag +* BELOW the dispatch key stays excluded — events flow up the chain, never +* down. +* @param base - subject or service whose existing Cordis filter is preserved. +* @param key - routed scope identity, or `undefined` for an unscoped subject. +* @returns a carrier whose subject remains available only through event arguments. +*/ +function scopeTarget(base, key) { + const baseFilter = base[Context.filter]; + const carrier = { [Context.filter](ctx) { + if (baseFilter !== void 0 && !baseFilter.call(base, ctx)) return false; + const tag = scopeOf(ctx); + if (tag === void 0) return true; + for (let cursor = key; cursor !== void 0; cursor = scopeParents.get(cursor)) if (cursor === tag) return true; + return false; + } }; + carrierKeys.set(carrier, key); + return carrier; +} +/** +* Test whether a value is a scope carrier. +* @param value - dispatch receiver to inspect. +* @returns whether {@link scopeTarget} created it. +*/ +function isScopeCarrier(value) { + return typeof value === "object" && value !== null && carrierKeys.has(value); +} +/** +* Read a carrier's routing key. +* @param value - dispatch receiver to inspect. +* @returns the carrier key, or `undefined` for an unkeyed/non-carrier value. +*/ +function carrierKeyOf(value) { + if (!isScopeCarrier(value)) return void 0; + return carrierKeys.get(value); +} +//#endregion +export { AnonymousEntries, NamedEntries, ScopedLayers, bindScopeParent, carrierKeyOf, createScope, isScopeCarrier, scopeChainOf, scopeOf, scopeParentOf, scopeTarget }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/invariant.js new file mode 100644 index 0000000..65f9514 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/invariant.js @@ -0,0 +1,72 @@ +import { carrierKeyOf, isScopeCarrier } from "@deepseek-ai/dsh-scope"; +//#region lib/types/scoped-events.generated.js +/** +* Generated scoped-event routing-subject resolvers for dsh-scope invariants. +* Do not edit by hand; run `pnpm run gen-scoped-events`. +* +* @module @deepseek-ai/dsh-scope/scoped-events.generated +*/ +const scopedSubjectResolvers = Object.freeze({ + "agent/created": (args) => args[0]["agent"], + "agent/disposed": (args) => args[0]["agent"], + "agent/error": (args) => args[0]["agent"], + "agent/inbox/claimed": (args) => args[0]["agent"], + "agent/inbox/discarded": (args) => args[0]["agent"], + "agent/inbox/inserted": (args) => args[0]["agent"], + "agent/pre-step": (args) => args[0]["agent"], + "agent/request": (args) => args[0]["agent"], + "agent/request-error": (args) => args[0]["agent"], + "agent/session-start": (args) => args[0]["agent"], + "agent/status": (args) => args[0]["agent"], + "agent/turn-stopping": (args) => args[0]["agent"], + "approval/request": (args) => args[0]["agent"], + "goal/changed": (args) => args[0]["agent"], + "session/created": null, + "session/disposed": null, + "session/event": null, + "session/flush": null, + "subagent/end": null, + "subagent/start": null, + "system-prompt/assemble": (args) => args[1]["scope"], + "tools/code-dispatch-log": (args) => args[0]["agent"], + "tools/execute": (args) => args[0]["agent"], + "tools/post-execute": (args) => args[0]["agent"], + "tools/pre-execute": (args) => args[0]["agent"], + "tools/result": (args) => args[0]["agent"] +}); +/** +* Resolve the routing key named by one scoped event payload. A null +* resolver means the payload cannot expose its external routing key, so the +* invariant checks carrier presence only. +* @param event - runtime Cordis event name. +* @returns the generated subject resolver, null for presence-only, +* or undefined when the event is not scope-filtered. +*/ +function scopedSubjectResolverFor(event) { + return scopedSubjectResolvers[event]; +} +//#endregion +//#region lib/types/invariant.js +/** Package-owned scoped-dispatch invariants. @module @deepseek-ai/dsh-scope/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-scope"; +/** Cordis companion plugin name. */ +const name = "scope-invariant"; +/** Services required before the companion can register. */ +const inject = ["invariants"]; +/** Install the scoped-dispatch contribution into its child registration fiber. */ +const install = (ctx, fail) => { + ctx.on("internal/dispatch", (_mode, eventName, args, thisArg) => { + const subjectOf = scopedSubjectResolverFor(eventName); + if (subjectOf === void 0) return; + if (!isScopeCarrier(thisArg)) fail(`"${eventName}" is a scope-filtered event but was dispatched without a scope carrier — pass scopeTarget(base, subject) as the dispatch thisArg (agent events: use agentEvents(ctx, agent))`); + if (subjectOf !== null && carrierKeyOf(thisArg) !== subjectOf(args)) fail(`"${eventName}" was dispatched with a scope carrier keyed to a DIFFERENT subject than its arguments name — the carrier key and the event's subject must be the same object (use agentEvents(ctx, agent))`); + }, { global: true }); +}; +/** +* Register the scope invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/index.d.ts new file mode 100644 index 0000000..c790218 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/index.d.ts @@ -0,0 +1,110 @@ +/** + * Scoped-context primitive: mint a Cordis context that tags registrations with + * an opaque identity and build routing-only event carriers for that identity. + * + * @module @deepseek-ai/dsh-scope + */ +import type { Context } from '@deepseek-ai/cordis'; +export { AnonymousEntries, NamedEntries, ScopedLayers } from './store.ts'; +export type { ScopeLayer } from './store.ts'; +/** An opaque, identity-compared scope key. */ +export type ScopeKey = object; +declare const ScopedBrand: unique symbol; +/** + * A routing-only event receiver built by {@link scopeTarget}. The type + * parameter records the subject type for dispatch checking; the carrier does + * not expose the subject's properties. Event payloads carry the real subject. + */ +export type Scoped = object & { + readonly [ScopedBrand]: T; +}; +/** The privileged handle to move one scope key's parent link. */ +export interface ScopeParentBinding { + /** + * Re-link the bound key to a different parent, with the same cycle check as + * the bind. Valid only while nothing produced under the old parent is + * retained — the blank-session recompose contract, which the holder upholds + * because this relation cannot see what a session logged. + * @param parent - the new enclosing scope key. + */ + rebind(parent: ScopeKey): void; +} +/** + * Bind `parent` as `key`'s enclosing scope, once. + * + * A key that already has a parent throws: there is no open re-link path, so a + * scope's ancestry cannot be moved by anyone but the original binder, who + * alone receives the {@link ScopeParentBinding}. A link that would close a + * cycle is rejected, because every chain consumer walks parents to the root. + * @param key - the child scope key. + * @param parent - its enclosing scope key. + * @returns the binding that alone may re-link this key. + */ +export declare function bindScopeParent(key: ScopeKey, parent: ScopeKey): ScopeParentBinding; +/** + * Read one key's enclosing scope. + * @param key - the scope key to inspect. + * @returns its parent key, or `undefined` for a root scope. + */ +export declare function scopeParentOf(key: ScopeKey): ScopeKey | undefined; +/** + * The chain from a key to its root ancestor. + * @param key - the starting key, or `undefined` for the empty chain. + * @returns keys nearest-first: `[key, parent, grandparent, …]`. + */ +export declare function scopeChainOf(key: ScopeKey | undefined): ScopeKey[]; +/** A minted registration scope and its quiescent disposal boundaries. */ +export interface Scope { + /** Context through which scope-owned registrations are made. */ + ctx: Context; + /** Exact Cordis disposer, used when nesting this scope in an ordered composite effect. */ + rawDispose: () => Promise | void; + /** Dispose every scope-owned registration; racing calls await the same completion. */ + dispose(): Promise; +} +/** Options accepted by {@link createScope}. */ +export interface CreateScopeOptions { + /** Enclosing scope bound via {@link bindScopeParent} before the scope is usable; the binding stays internal. */ + parent?: ScopeKey; +} +/** + * Mint a scope under `ctx`. The scoped context inherits the minting plugin's + * dependency API and owns every registration made through it. + * @param ctx - active context whose dependency API the scope inherits. + * @param key - opaque identity used for listener routing. + * @param options - optional scope-chain placement. + * @returns the scoped context and exact/shared disposal boundaries. + */ +export declare function createScope(ctx: Context, key: ScopeKey, options?: CreateScopeOptions): Scope; +/** + * Read the nearest scope tag inherited by a context. + * @param ctx - context to inspect. + * @returns its scope key, or `undefined` for an unscoped context. + */ +export declare function scopeOf(ctx: Context): ScopeKey | undefined; +/** + * Build an opaque receiver that preserves the base filter, admits untagged + * listeners globally, and admits tagged listeners for a matching key or any + * of its ancestors ({@link bindScopeParent}): a listener owned by an enclosing + * scope receives every descendant scope's events, which is what lets one + * standing composition observe each of the agents composed under it. A tag + * BELOW the dispatch key stays excluded — events flow up the chain, never + * down. + * @param base - subject or service whose existing Cordis filter is preserved. + * @param key - routed scope identity, or `undefined` for an unscoped subject. + * @returns a carrier whose subject remains available only through event arguments. + */ +export declare function scopeTarget(base: T, key: ScopeKey | undefined): Scoped; +/** + * Test whether a value is a scope carrier. + * @param value - dispatch receiver to inspect. + * @returns whether {@link scopeTarget} created it. + */ +export declare function isScopeCarrier(value: unknown): value is Scoped; +/** + * Read a carrier's routing key. + * @param value - dispatch receiver to inspect. + * @returns the carrier key, or `undefined` for an unkeyed/non-carrier value. + */ +export declare function carrierKeyOf(value: unknown): ScopeKey | undefined; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/invariant.d.ts new file mode 100644 index 0000000..8ba88ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned scoped-dispatch invariants. @module @deepseek-ai/dsh-scope/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "scope-invariant"; +/** Services required before the companion can register. */ +export declare const inject: string[]; +/** + * Register the scope invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/scoped-events.generated.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/scoped-events.generated.d.ts new file mode 100644 index 0000000..4ecb2c3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/scoped-events.generated.d.ts @@ -0,0 +1,18 @@ +/** + * Generated scoped-event routing-subject resolvers for dsh-scope invariants. + * Do not edit by hand; run `pnpm run gen-scoped-events`. + * + * @module @deepseek-ai/dsh-scope/scoped-events.generated + */ +type ScopedSubjectResolver = (args: readonly unknown[]) => unknown; +/** + * Resolve the routing key named by one scoped event payload. A null + * resolver means the payload cannot expose its external routing key, so the + * invariant checks carrier presence only. + * @param event - runtime Cordis event name. + * @returns the generated subject resolver, null for presence-only, + * or undefined when the event is not scope-filtered. + */ +export declare function scopedSubjectResolverFor(event: string): ScopedSubjectResolver | null | undefined; +export {}; +//# sourceMappingURL=scoped-events.generated.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/store.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/store.d.ts new file mode 100644 index 0000000..dd69faa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/lib/types/store.d.ts @@ -0,0 +1,147 @@ +/** + * Shared insertion-ordered storage and effect ownership for scope-aware registries. + * + * @module @deepseek-ai/dsh-scope + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { ScopeKey } from './index.ts'; +/** One scope's aggregate contribution to a registry. */ +export interface ScopeLayer { + /** Whether every table in this layer is empty. */ + isEmpty(): boolean; +} +/** Internal common read contract for the two entry-table implementations. */ +interface EntryValues { + values(): IterableIterator; + isEmpty(): boolean; +} +/** + * Insertion-ordered named entries with caller-owned duplicate diagnostics. + * + * Values are borrowed. Iterators are live within one nonempty table + * generation; draining the table detaches them from later insertions. Each + * successful insertion returns an idempotent undo for that exact entry. + */ +export declare class NamedEntries implements EntryValues { + private readonly duplicateError; + private data; + constructor(duplicateError: (name: string) => Error); + /** + * Insert one unique name. + * @param name - name unique within this table. + * @param value - borrowed value to retain. + * @returns an idempotent undo that removes only this insertion. + */ + insert(name: string, value: V): () => void; + /** + * Read one named value. + * @param name - name to resolve. + * @returns the retained value, or `undefined` when absent. + */ + get(name: string): V | undefined; + /** + * Test one name for membership. + * @param name - name to test. + * @returns whether the table contains that name. + */ + has(name: string): boolean; + /** + * Iterate live names in insertion order. + * @returns the native live key iterator. + */ + keys(): IterableIterator; + /** + * Iterate live entries in insertion order. + * @returns the native live entry iterator. + */ + entries(): IterableIterator<[string, V]>; + /** + * Iterate live values in insertion order. + * @returns the native live value iterator. + */ + values(): IterableIterator; + /** + * Test whether this table has no entries. + * @returns whether the table is empty. + */ + isEmpty(): boolean; +} +/** + * Insertion-ordered anonymous entries with independent registration identity. + * + * Equal values remain separate registrations. Values are borrowed, and + * iterators are live within one nonempty table generation; draining the table + * detaches them from later appends. + */ +export declare class AnonymousEntries implements EntryValues { + private data; + /** + * Append one independently owned value. + * @param value - borrowed value to retain. + * @returns an idempotent undo for this exact append. + */ + append(value: V): () => void; + /** + * Iterate live values in insertion order. + * @returns the native live value iterator. + */ + values(): IterableIterator; + /** + * Test whether this table has no entries. + * @returns whether the table is empty. + */ + isEmpty(): boolean; +} +/** + * Own the global and exact-scope layers for one registry. + * + * Reads never create scoped layers. Registrations derive both visibility and + * effect ownership from the supplied Cordis context, collect undo before + * notification, and reclaim only a completely empty aggregate layer. + */ +export declare class ScopedLayers { + private readonly createLayer; + private readonly onChange; + /** The eagerly constructed context-global layer. */ + readonly global: L; + private readonly scoped; + constructor(createLayer: (scope: ScopeKey | undefined) => L, onChange: () => void); + /** + * Read an existing exact-scope overlay. Deliberately chain-blind: callers + * addressing one scope's OWN contributions (its restrictions, its guards) + * must not silently pick up an ancestor's — use {@link chainLayers} where + * inheritance is the point. + * @param scope - exact scope key; `undefined` denotes no overlay. + * @returns the existing scoped layer, or `undefined` without creating one. + */ + peek(scope: ScopeKey | undefined): L | undefined; + /** + * Existing overlays along the scope's parent chain ({@link scopeChainOf}), + * farthest ancestor first and the exact scope last, so a caller layering + * them in order gives the nearest scope the final word. + * @param scope - viewing scope, or `undefined` for no overlays. + * @returns the existing layers, nearest last; absent overlays are skipped. + */ + chainLayers(scope: ScopeKey | undefined): L[]; + /** + * Materialize global named entries followed by scope-chain shadows, + * farthest ancestor first, so the nearest scope's entry wins a name. + * @param scope - viewing scope, or `undefined` for the global view. + * @param pick - select the named table from a layer. + * @returns an insertion-ordered effective map. + */ + merge(scope: ScopeKey | undefined, pick: (layer: L) => NamedEntries): Map; + /** + * Attach one synchronous layer mutation to its registration context. + * @param ctx - context that determines both scope visibility and effect ownership. + * @param action - atomic mutation returning its synchronous undo. + * @param options - Cordis effect label and optional change notification. + * @returns the exact disposer returned by `ctx.effect()`. + */ + effect(ctx: Context, action: (layer: L) => () => void, options: { + label: string; + notify?: boolean; + }): () => void; +} +export {}; +//# sourceMappingURL=store.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/package.json new file mode 100644 index 0000000..ee13e6e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-scope", + "description": "Scoped-context registration primitive (scope tags, scope-filtered event dispatch) for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/scope" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.i18n.yaml new file mode 100644 index 0000000..52b812a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/scope/README.md +README.md: 1ed09acd7ccb864b16fb5d2ac4390264085d1c9e +README.zh.md: ef483412307833937a1b2558125c1955b0b96c3b diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.md new file mode 100644 index 0000000..1ed09ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.md @@ -0,0 +1,37 @@ +# dsh-scope + +English | [中文](README.zh.md) + +Scoped registration primitive. `createScope(ctx, key)` creates a tagged Cordis context whose backing fiber owns every registration made through it. `scopeOf(ctx)` reads the tag, and `scopeTarget(base, key)` routes scoped events to listeners with the same key while leaving unscoped listeners global. Keys form an optional parent chain (`bindScopeParent`): registration views inherit DOWN it — a child scope sees its ancestors' layers, nearest shadowing farthest — and event admission extends UP it — a listener tagged with an ancestor receives a descendant key's events, never the reverse. The agent loop creates one scope per live agent and an agent preset's standing mount is a parent scope over its agents, but the mechanism is key-agnostic so lower-level packages can use it without depending on either. + +## Public API + +- `createScope(ctx: Context, key: ScopeKey, options?): Scope` Mint a scope under `ctx`'s fiber. Usable synchronously (effect collection is uid-gated; service resolution falls through to the minting plugin's dependency surface). The typed, same-process key is trusted; an inactive minting context still fails through Cordis (`INACTIVE_EFFECT`). `options.parent` binds the enclosing scope via `bindScopeParent` before the scope is usable; the binding stays internal. +- `bindScopeParent(key, parent): ScopeParentBinding` / `scopeParentOf(key)` / `scopeChainOf(key)` The parent relation behind both chain directions. Binding is once: a key that already has a parent throws, and only the returned binding's `rebind(parent)` may re-link it — the blank-session recompose operation, valid only while nothing produced under the old parent is retained (the holder's contract — this relation cannot see what a session logged). Both the bind and every rebind reject a link closing a cycle. `scopeChainOf` returns `[key, parent, …]` nearest-first. +- `Scope.ctx` The tagged context: registrations through it are scope-visible AND scope-lifetime. Derived contexts (an `extend`, a fiber mounted under it) inherit the tag; nested scopes shadow (nearest tag wins). +- `Scope.rawDispose` The EXACT Cordis disposer for the backing fiber — a composite (generator) effect yields THIS function to nest the scope's teardown at that yield position (Cordis dedupes nested effects by function identity; yielding a wrapper leaves the scope disposing as a concurrent sibling). +- `Scope.dispose(): Promise` Idempotent, shared quiescence boundary for every registration made through the scope. Racing/repeat calls await the same teardown, including when `rawDispose` invoked the underlying single-shot Cordis disposer first. +- `scopeOf(ctx: Context): ScopeKey | undefined` The tag a context (or any context derived from it) carries; `undefined` = context-global. +- `scopeTarget(base: T, key: ScopeKey | undefined): Scoped` Build the opaque dispatch `thisArg` for a scope-filtered event. It composes `base`'s existing `Context.filter` with the scope predicate (untagged listener ⇒ admitted; tagged ⇒ admitted iff its tag is the key or an ancestor of it; `key === undefined` ⇒ untagged only). The carrier contains routing state only; the real subject is carried by the event arguments. `{ global: true }` listeners bypass filtering (Cordis semantics). +- `Scoped` The compile-time opaque carrier brand: scope-filtered events demand it as their `this` type, so dispatching with a bare subject is a compile error. The type parameter records the subject type but does not expose its properties. +- `isScopeCarrier(value)` / `carrierKeyOf(value)` Runtime carrier marks, used by the dev invariants to assert every scope-filtered dispatch carries a carrier keyed to the subject its arguments name. +- `ScopeLayer` Aggregate contract for one registry's complete global or exact-scope contribution; `isEmpty()` controls scoped-layer reclamation. +- `ScopedLayers` Own one eager global layer and lazy exact-scope layers. `peek()` never creates and stays chain-blind (a scope's OWN contributions — restrictions, guards — must not silently pick up an ancestor's), `chainLayers()` returns existing overlays farthest-ancestor-first, `merge()` materializes insertion-ordered named shadows along the chain, and `effect()` derives visibility and ownership from the same context while returning the exact Cordis disposer. +- `NamedEntries` Insertion-ordered named storage with caller-owned duplicate diagnostics, lookup, and live iteration within one nonempty table generation; draining the table detaches existing iterators from later insertions, and `insert()` returns an idempotent exact-entry undo. +- `AnonymousEntries` Insertion-ordered anonymous storage whose unique internal keys keep equal values as independent registrations; it uses the same drained-generation iterator boundary, and `append()` returns an idempotent exact-entry undo. + +The optional `@deepseek-ai/dsh-scope/invariant` companion owns that runtime assertion. It uses the generated `scoped-events.generated.ts` resolver map to require a carrier for every declared scoped event and, when the payload exposes its routing subject, require identity with the carrier key. The Program-backed generator derives the map from event declarations and real `scopeTarget(base, key)` calls. + +## Design contract + +The registration context determines both visibility and ownership, preventing a registration from being visible in one scope but disposed with another. Scopes route trusted same-process plugins; they are not sandboxes or authority boundaries. See the [agent-scope Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals) for rationale and security non-goals. + +Scope-aware services define a concrete `ScopeLayer` that aggregates their heterogeneous tables and domain helpers. `ScopedLayers.effect()` accepts one synchronous action returning one synchronous undo, installs that undo before optional notification, and reclaims an exact-scope layer only when the complete aggregate is empty. `notify` defaults to `true`; the supplied callback owns whether observer failures throw or are contained. `EntryValues` remains internal, the storage classes are imported from the package root rather than a `/store` subpath, and the shared storage does not define registry-specific filtering or iteration policy. See the [shared scoped-layer storage Agent Note](../../../.agents/notes/implemented/architecture/2026-07-12-scoped-layers-store.md). + +Handing out a scoped context hands out the minting plugin's service-resolution API (resolution walks the minting fiber's dependency chain, not the holder's) — mint it from the plugin whose dependencies the scoped registrations need to resolve. + +## Known Limitations and Deferred Work + +- **Only scope-aware APIs isolate state** — registries must file by `scopeOf()` and events must dispatch through `scopeTarget()`; an arbitrary Cordis service remains context-global merely because it is called through a scoped context. +- **A context carries one nearest scope key** — the hierarchy lives in the key-level parent relation, not in context tags; nested scope CONTEXTS still shadow to a single tag, and multi-membership policy sets remain unsupported. +- **Service reachability comes from the scope minter** — handing out `Scope.ctx` also hands out the minting plugin's injected services, so a broader minter cannot later be narrowed by the holder. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.zh.md new file mode 100644 index 0000000..ef48341 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/README.zh.md @@ -0,0 +1,37 @@ +# dsh-scope + +[English](README.md) | 中文 + +带作用域的注册原语。`createScope(ctx, key)` 创建一个带标签的 Cordis 上下文,其底层 fiber 拥有通过该上下文进行的每项注册。`scopeOf(ctx)` 读取标签;`scopeTarget(base, key)` 将带作用域的事件路由到键相同的监听器,同时让无作用域监听器保持全局可见。键可以构成可选的父链(`bindScopeParent`):注册视图沿链**向下**继承——子作用域看得见祖先各层,近者遮蔽远者——事件放行沿链**向上**扩展——标签为祖先的监听器能收到子孙键的事件,反向永不成立。agent loop(智能体循环)为每个存活的 agent 创建一个作用域,agent preset 的常驻挂载则是其 agent 们的父作用域,但该机制与键的具体含义无关,底层包无需依赖两者即可使用。 + +## 公开 API + +- `createScope(ctx: Context, key: ScopeKey, options?): Scope`:在 `ctx` 的 fiber 下创建作用域。可以同步使用(effect 收集受 uid 门禁约束;服务解析会沿创建该作用域的插件依赖范围继续查找)。同进程、带类型的键受信任;处于非活动状态的创建上下文仍会通过 Cordis 失败(`INACTIVE_EFFECT`)。`options.parent` 在作用域可用之前经 `bindScopeParent` 绑定其外围作用域;绑定句柄不外泄。 +- `bindScopeParent(key, parent): ScopeParentBinding` / `scopeParentOf(key)` / `scopeChainOf(key)`:支撑两条链方向的父关系。绑定仅此一次:已有父级的键直接抛错,只有返回的绑定句柄的 `rebind(parent)` 才能重新绑定父级——即空白会话 recompose 的操作,仅当旧父之下产出的东西一概不被保留时才合法(这是持有方的约定——该关系看不见会话记录了什么)。绑定与每次 rebind 都拒绝会闭环的链接。`scopeChainOf` 返回 `[key, parent, …]`,最近者在前。 +- `Scope.ctx`:带标签的上下文。通过它进行的注册既具备作用域可见性,也服从作用域生命周期。派生上下文(一次 `extend`、挂载于其下的 fiber)继承标签;嵌套作用域会遮蔽外层标签(最近的标签生效)。 +- `Scope.rawDispose`:底层 fiber 的确切 Cordis disposer。组合式(generator)effect 会 yield 此函数,从而把作用域 teardown 嵌套在该 yield 位置(Cordis 按函数标识去重嵌套 effect;yield 一个包装函数会使作用域 teardown 成为并行的同级操作)。 +- `Scope.dispose(): Promise`:通过作用域进行的每项注册所共用的幂等完全停稳边界。竞态调用或重复调用会等待同一次 teardown;即使 `rawDispose` 先调用了底层单次 Cordis disposer 也是如此。 +- `scopeOf(ctx: Context): ScopeKey | undefined`:上下文或其任意派生上下文携带的标签;`undefined` 表示上下文全局。 +- `scopeTarget(base: T, key: ScopeKey | undefined): Scoped`:为按作用域筛选的事件构造不透明分发 `thisArg`。它把 `base` 现有的 `Context.filter` 与作用域谓词组合起来(无标签监听器 ⇒ 放行;有标签监听器 ⇒ 仅当标签 === key,或标签为 key 的祖先时放行;`key === undefined` ⇒ 仅放行无标签监听器)。载体只包含路由状态;真实主体由事件参数携带。带 `{ global: true }` 的监听器绕过筛选(Cordis 语义)。 +- `Scoped`:编译期不透明载体 brand。按作用域筛选的事件要求它作为 `this` 类型,因此使用裸主体分发会产生编译错误。类型参数记录主体类型,但不公开其属性。 +- `isScopeCarrier(value)`/`carrierKeyOf(value)`:运行时载体标记,开发不变式使用它们断言每次按作用域筛选的分发都携带载体,而且载体键与参数所指名的主体一致。 +- `ScopeLayer`:一个注册表的完整全局贡献或精确作用域贡献的聚合约定;`isEmpty()` 控制带作用域层的回收。 +- `ScopedLayers`:持有一个立即构造的全局层与惰性的精确作用域层。`peek()` 从不创建且刻意不看链(某作用域**自己**的贡献——限制、守卫——不得悄悄继承祖先的),`chainLayers()` 按最远祖先在前返回已存在的各层,`merge()` 沿链物化按插入序的具名遮蔽,`effect()` 从同一上下文推导可见性与所有权,并返回精确的 Cordis disposer。 +- `NamedEntries`:按插入顺序排列的具名存储,调用方拥有重复项诊断、查找,以及一个非空表世代内的实时迭代。表清空后,现有迭代器与后续插入项脱离;`insert()` 返回幂等的精确条目撤销函数。 +- `AnonymousEntries`:按插入顺序排列的匿名存储;唯一内部键使相同值仍作为独立注册存在。它使用相同的清空世代迭代器边界;`append()` 返回幂等的精确条目撤销函数。 + +可选配套包 `@deepseek-ai/dsh-scope/invariant` 拥有该运行时断言。它使用生成的 `scoped-events.generated.ts` 解析器映射,要求每个已声明的带作用域事件都携带载体;当 payload 公开路由主体时,还要求路由主体与载体键严格相等。基于 Program 的生成器根据事件声明和真实的 `scopeTarget(base, key)` 调用生成该映射。 + +## 设计约定 + +注册上下文同时决定可见性和所有权,防止注册在一个作用域中可见、却随另一个作用域 dispose(资源释放)。作用域用于路由受信任的同进程插件;它们不是沙箱或权限边界。原理与明确排除的安全目标见 [agent 作用域 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals)。 + +感知作用域的服务会定义具体 `ScopeLayer`,聚合各自不同的表与领域辅助函数。`ScopedLayers.effect()` 接受一个返回同步撤销函数的同步动作,在可选通知前安装该撤销函数,并且只有在完整聚合为空时才回收精确作用域层。`notify` 默认为 `true`;由所提供的回调决定观测方失败是向外抛出还是在内部处理。`EntryValues` 保持内部可见;存储类从包根而非 `/store` 子路径导入;共享存储不定义注册表专属的筛选或迭代策略。详见[共享作用域层存储 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-12-scoped-layers-store.md)。 + +交出带作用域的上下文,也会交出创建该上下文的插件的服务解析范围(解析会沿创建者 fiber 的依赖链,而非持有者的依赖链行进),因此应由具备这些带作用域注册所需依赖的插件来创建它。 + +## 已知限制与暂缓事项 + +- **只有感知作用域的表层才会隔离状态**:注册表必须按 `scopeOf()` 归档,事件必须通过 `scopeTarget()` 分发;仅仅通过带作用域的上下文调用任意 Cordis 服务,并不会改变该服务仍为上下文全局这一事实。 +- **一个上下文只携带一个最近的作用域键**:层级关系存在于键级父关系中而非上下文标签里;嵌套作用域**上下文**仍遮蔽为单一标签,多成员策略集仍不受支持。 +- **服务可达性来自作用域创建者**:交出 `Scope.ctx` 也会交出创建插件注入的服务范围,因此,若作用域创建者提供的服务范围较宽,持有者之后也无法将其收窄。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/index.js new file mode 100644 index 0000000..8359860 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/index.js @@ -0,0 +1,357 @@ +import { Context } from "@deepseek-ai/cordis"; +//#region lib/types/store.js +/** +* Shared insertion-ordered storage and effect ownership for scope-aware registries. +* +* @module @deepseek-ai/dsh-scope +*/ +/** +* Insertion-ordered named entries with caller-owned duplicate diagnostics. +* +* Values are borrowed. Iterators are live within one nonempty table +* generation; draining the table detaches them from later insertions. Each +* successful insertion returns an idempotent undo for that exact entry. +*/ +var NamedEntries = class { + duplicateError; + data = /* @__PURE__ */ new Map(); + constructor(duplicateError) { + this.duplicateError = duplicateError; + } + /** + * Insert one unique name. + * @param name - name unique within this table. + * @param value - borrowed value to retain. + * @returns an idempotent undo that removes only this insertion. + */ + insert(name, value) { + const data = this.data; + if (data.has(name)) throw this.duplicateError(name); + data.set(name, value); + let active = true; + return () => { + if (!active) return; + active = false; + data.delete(name); + if (data.size === 0 && this.data === data) this.data = /* @__PURE__ */ new Map(); + }; + } + /** + * Read one named value. + * @param name - name to resolve. + * @returns the retained value, or `undefined` when absent. + */ + get(name) { + return this.data.get(name); + } + /** + * Test one name for membership. + * @param name - name to test. + * @returns whether the table contains that name. + */ + has(name) { + return this.data.has(name); + } + /** + * Iterate live names in insertion order. + * @returns the native live key iterator. + */ + keys() { + return this.data.keys(); + } + /** + * Iterate live entries in insertion order. + * @returns the native live entry iterator. + */ + entries() { + return this.data.entries(); + } + /** + * Iterate live values in insertion order. + * @returns the native live value iterator. + */ + values() { + return this.data.values(); + } + /** + * Test whether this table has no entries. + * @returns whether the table is empty. + */ + isEmpty() { + return this.data.size === 0; + } +}; +/** +* Insertion-ordered anonymous entries with independent registration identity. +* +* Equal values remain separate registrations. Values are borrowed, and +* iterators are live within one nonempty table generation; draining the table +* detaches them from later appends. +*/ +var AnonymousEntries = class { + data = /* @__PURE__ */ new Map(); + /** + * Append one independently owned value. + * @param value - borrowed value to retain. + * @returns an idempotent undo for this exact append. + */ + append(value) { + const data = this.data; + const key = Symbol(); + data.set(key, value); + let active = true; + return () => { + if (!active) return; + active = false; + data.delete(key); + if (data.size === 0 && this.data === data) this.data = /* @__PURE__ */ new Map(); + }; + } + /** + * Iterate live values in insertion order. + * @returns the native live value iterator. + */ + values() { + return this.data.values(); + } + /** + * Test whether this table has no entries. + * @returns whether the table is empty. + */ + isEmpty() { + return this.data.size === 0; + } +}; +/** +* Own the global and exact-scope layers for one registry. +* +* Reads never create scoped layers. Registrations derive both visibility and +* effect ownership from the supplied Cordis context, collect undo before +* notification, and reclaim only a completely empty aggregate layer. +*/ +var ScopedLayers = class { + createLayer; + onChange; + /** The eagerly constructed context-global layer. */ + global; + scoped = /* @__PURE__ */ new Map(); + constructor(createLayer, onChange) { + this.createLayer = createLayer; + this.onChange = onChange; + this.global = createLayer(void 0); + } + /** + * Read an existing exact-scope overlay. Deliberately chain-blind: callers + * addressing one scope's OWN contributions (its restrictions, its guards) + * must not silently pick up an ancestor's — use {@link chainLayers} where + * inheritance is the point. + * @param scope - exact scope key; `undefined` denotes no overlay. + * @returns the existing scoped layer, or `undefined` without creating one. + */ + peek(scope) { + if (scope === void 0) return void 0; + return this.scoped.get(scope); + } + /** + * Existing overlays along the scope's parent chain ({@link scopeChainOf}), + * farthest ancestor first and the exact scope last, so a caller layering + * them in order gives the nearest scope the final word. + * @param scope - viewing scope, or `undefined` for no overlays. + * @returns the existing layers, nearest last; absent overlays are skipped. + */ + chainLayers(scope) { + const layers = []; + for (const key of scopeChainOf(scope).reverse()) { + const layer = this.scoped.get(key); + if (layer !== void 0) layers.push(layer); + } + return layers; + } + /** + * Materialize global named entries followed by scope-chain shadows, + * farthest ancestor first, so the nearest scope's entry wins a name. + * @param scope - viewing scope, or `undefined` for the global view. + * @param pick - select the named table from a layer. + * @returns an insertion-ordered effective map. + */ + merge(scope, pick) { + const merged = new Map(pick(this.global).entries()); + for (const layer of this.chainLayers(scope)) for (const [name, value] of pick(layer).entries()) merged.set(name, value); + return merged; + } + /** + * Attach one synchronous layer mutation to its registration context. + * @param ctx - context that determines both scope visibility and effect ownership. + * @param action - atomic mutation returning its synchronous undo. + * @param options - Cordis effect label and optional change notification. + * @returns the exact disposer returned by `ctx.effect()`. + */ + effect(ctx, action, options) { + const scope = scopeOf(ctx); + const notify = options.notify ?? true; + return ctx.effect(function* () { + let layer; + let created = false; + if (scope === void 0) layer = this.global; + else { + const existing = this.scoped.get(scope); + if (existing === void 0) { + layer = this.createLayer(scope); + this.scoped.set(scope, layer); + created = true; + } else layer = existing; + } + let undo; + try { + undo = action(layer); + } catch (error) { + if (scope !== void 0 && created && layer.isEmpty()) this.scoped.delete(scope); + throw error; + } + yield () => { + undo(); + if (scope !== void 0 && layer.isEmpty()) this.scoped.delete(scope); + if (notify) this.onChange(); + }; + if (notify) this.onChange(); + }.bind(this), options.label); + } +}; +//#endregion +//#region lib/types/index.js +/** +* Scoped-context primitive: mint a Cordis context that tags registrations with +* an opaque identity and build routing-only event carriers for that identity. +* +* @module @deepseek-ai/dsh-scope +*/ +/** Context tag written by {@link createScope}. */ +const kScope = Symbol("dsh.scope"); +/** The key associated with each carrier. Presence distinguishes an unkeyed carrier from a non-carrier. */ +const carrierKeys = /* @__PURE__ */ new WeakMap(); +/** +* The enclosing scope of each key. One relation powers both directions of +* scope nesting: registration views inherit DOWN the chain (a child scope +* sees its ancestors' layers — {@link ScopedLayers}), and event admission +* extends UP it (a listener tagged with an ancestor receives events dispatched +* to a descendant key — {@link scopeTarget}). +*/ +const scopeParents = /* @__PURE__ */ new WeakMap(); +/** Cycle-checked write shared by the bind and every rebind. */ +function linkScopeParent(key, parent) { + for (let cursor = parent; cursor !== void 0; cursor = scopeParents.get(cursor)) if (cursor === key) throw new Error("dsh-scope: scope parent link would form a cycle"); + scopeParents.set(key, parent); +} +/** +* Bind `parent` as `key`'s enclosing scope, once. +* +* A key that already has a parent throws: there is no open re-link path, so a +* scope's ancestry cannot be moved by anyone but the original binder, who +* alone receives the {@link ScopeParentBinding}. A link that would close a +* cycle is rejected, because every chain consumer walks parents to the root. +* @param key - the child scope key. +* @param parent - its enclosing scope key. +* @returns the binding that alone may re-link this key. +*/ +function bindScopeParent(key, parent) { + if (scopeParents.has(key)) throw new Error("dsh-scope: scope key is already bound to a parent; re-linking requires the binding returned by the original bind"); + linkScopeParent(key, parent); + return { rebind(next) { + linkScopeParent(key, next); + } }; +} +/** +* Read one key's enclosing scope. +* @param key - the scope key to inspect. +* @returns its parent key, or `undefined` for a root scope. +*/ +function scopeParentOf(key) { + return scopeParents.get(key); +} +/** +* The chain from a key to its root ancestor. +* @param key - the starting key, or `undefined` for the empty chain. +* @returns keys nearest-first: `[key, parent, grandparent, …]`. +*/ +function scopeChainOf(key) { + const chain = []; + for (let cursor = key; cursor !== void 0; cursor = scopeParents.get(cursor)) chain.push(cursor); + return chain; +} +/** Follow a Cordis fiber through asynchronous teardown even if its raw disposer was already claimed. */ +async function quiesceFiber(fiber) { + await Promise.resolve(fiber.dispose()); + while (fiber.inertia !== void 0) await fiber.inertia; +} +/** Shared no-op plugin used as the backing scope fiber. */ +function scope() {} +/** +* Mint a scope under `ctx`. The scoped context inherits the minting plugin's +* dependency API and owns every registration made through it. +* @param ctx - active context whose dependency API the scope inherits. +* @param key - opaque identity used for listener routing. +* @param options - optional scope-chain placement. +* @returns the scoped context and exact/shared disposal boundaries. +*/ +function createScope(ctx, key, options) { + if (options?.parent !== void 0) bindScopeParent(key, options.parent); + const fiber = ctx.plugin(scope); + const scoped = fiber.ctx.extend({ [kScope]: key }); + let disposing; + return { + ctx: scoped, + rawDispose: fiber.dispose, + dispose: () => disposing ??= quiesceFiber(fiber) + }; +} +/** +* Read the nearest scope tag inherited by a context. +* @param ctx - context to inspect. +* @returns its scope key, or `undefined` for an unscoped context. +*/ +function scopeOf(ctx) { + return ctx[kScope]; +} +/** +* Build an opaque receiver that preserves the base filter, admits untagged +* listeners globally, and admits tagged listeners for a matching key or any +* of its ancestors ({@link bindScopeParent}): a listener owned by an enclosing +* scope receives every descendant scope's events, which is what lets one +* standing composition observe each of the agents composed under it. A tag +* BELOW the dispatch key stays excluded — events flow up the chain, never +* down. +* @param base - subject or service whose existing Cordis filter is preserved. +* @param key - routed scope identity, or `undefined` for an unscoped subject. +* @returns a carrier whose subject remains available only through event arguments. +*/ +function scopeTarget(base, key) { + const baseFilter = base[Context.filter]; + const carrier = { [Context.filter](ctx) { + if (baseFilter !== void 0 && !baseFilter.call(base, ctx)) return false; + const tag = scopeOf(ctx); + if (tag === void 0) return true; + for (let cursor = key; cursor !== void 0; cursor = scopeParents.get(cursor)) if (cursor === tag) return true; + return false; + } }; + carrierKeys.set(carrier, key); + return carrier; +} +/** +* Test whether a value is a scope carrier. +* @param value - dispatch receiver to inspect. +* @returns whether {@link scopeTarget} created it. +*/ +function isScopeCarrier(value) { + return typeof value === "object" && value !== null && carrierKeys.has(value); +} +/** +* Read a carrier's routing key. +* @param value - dispatch receiver to inspect. +* @returns the carrier key, or `undefined` for an unkeyed/non-carrier value. +*/ +function carrierKeyOf(value) { + if (!isScopeCarrier(value)) return void 0; + return carrierKeys.get(value); +} +//#endregion +export { AnonymousEntries, NamedEntries, ScopedLayers, bindScopeParent, carrierKeyOf, createScope, isScopeCarrier, scopeChainOf, scopeOf, scopeParentOf, scopeTarget }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/invariant.js new file mode 100644 index 0000000..65f9514 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/invariant.js @@ -0,0 +1,72 @@ +import { carrierKeyOf, isScopeCarrier } from "@deepseek-ai/dsh-scope"; +//#region lib/types/scoped-events.generated.js +/** +* Generated scoped-event routing-subject resolvers for dsh-scope invariants. +* Do not edit by hand; run `pnpm run gen-scoped-events`. +* +* @module @deepseek-ai/dsh-scope/scoped-events.generated +*/ +const scopedSubjectResolvers = Object.freeze({ + "agent/created": (args) => args[0]["agent"], + "agent/disposed": (args) => args[0]["agent"], + "agent/error": (args) => args[0]["agent"], + "agent/inbox/claimed": (args) => args[0]["agent"], + "agent/inbox/discarded": (args) => args[0]["agent"], + "agent/inbox/inserted": (args) => args[0]["agent"], + "agent/pre-step": (args) => args[0]["agent"], + "agent/request": (args) => args[0]["agent"], + "agent/request-error": (args) => args[0]["agent"], + "agent/session-start": (args) => args[0]["agent"], + "agent/status": (args) => args[0]["agent"], + "agent/turn-stopping": (args) => args[0]["agent"], + "approval/request": (args) => args[0]["agent"], + "goal/changed": (args) => args[0]["agent"], + "session/created": null, + "session/disposed": null, + "session/event": null, + "session/flush": null, + "subagent/end": null, + "subagent/start": null, + "system-prompt/assemble": (args) => args[1]["scope"], + "tools/code-dispatch-log": (args) => args[0]["agent"], + "tools/execute": (args) => args[0]["agent"], + "tools/post-execute": (args) => args[0]["agent"], + "tools/pre-execute": (args) => args[0]["agent"], + "tools/result": (args) => args[0]["agent"] +}); +/** +* Resolve the routing key named by one scoped event payload. A null +* resolver means the payload cannot expose its external routing key, so the +* invariant checks carrier presence only. +* @param event - runtime Cordis event name. +* @returns the generated subject resolver, null for presence-only, +* or undefined when the event is not scope-filtered. +*/ +function scopedSubjectResolverFor(event) { + return scopedSubjectResolvers[event]; +} +//#endregion +//#region lib/types/invariant.js +/** Package-owned scoped-dispatch invariants. @module @deepseek-ai/dsh-scope/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-scope"; +/** Cordis companion plugin name. */ +const name = "scope-invariant"; +/** Services required before the companion can register. */ +const inject = ["invariants"]; +/** Install the scoped-dispatch contribution into its child registration fiber. */ +const install = (ctx, fail) => { + ctx.on("internal/dispatch", (_mode, eventName, args, thisArg) => { + const subjectOf = scopedSubjectResolverFor(eventName); + if (subjectOf === void 0) return; + if (!isScopeCarrier(thisArg)) fail(`"${eventName}" is a scope-filtered event but was dispatched without a scope carrier — pass scopeTarget(base, subject) as the dispatch thisArg (agent events: use agentEvents(ctx, agent))`); + if (subjectOf !== null && carrierKeyOf(thisArg) !== subjectOf(args)) fail(`"${eventName}" was dispatched with a scope carrier keyed to a DIFFERENT subject than its arguments name — the carrier key and the event's subject must be the same object (use agentEvents(ctx, agent))`); + }, { global: true }); +}; +/** +* Register the scope invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/index.d.ts new file mode 100644 index 0000000..c790218 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/index.d.ts @@ -0,0 +1,110 @@ +/** + * Scoped-context primitive: mint a Cordis context that tags registrations with + * an opaque identity and build routing-only event carriers for that identity. + * + * @module @deepseek-ai/dsh-scope + */ +import type { Context } from '@deepseek-ai/cordis'; +export { AnonymousEntries, NamedEntries, ScopedLayers } from './store.ts'; +export type { ScopeLayer } from './store.ts'; +/** An opaque, identity-compared scope key. */ +export type ScopeKey = object; +declare const ScopedBrand: unique symbol; +/** + * A routing-only event receiver built by {@link scopeTarget}. The type + * parameter records the subject type for dispatch checking; the carrier does + * not expose the subject's properties. Event payloads carry the real subject. + */ +export type Scoped = object & { + readonly [ScopedBrand]: T; +}; +/** The privileged handle to move one scope key's parent link. */ +export interface ScopeParentBinding { + /** + * Re-link the bound key to a different parent, with the same cycle check as + * the bind. Valid only while nothing produced under the old parent is + * retained — the blank-session recompose contract, which the holder upholds + * because this relation cannot see what a session logged. + * @param parent - the new enclosing scope key. + */ + rebind(parent: ScopeKey): void; +} +/** + * Bind `parent` as `key`'s enclosing scope, once. + * + * A key that already has a parent throws: there is no open re-link path, so a + * scope's ancestry cannot be moved by anyone but the original binder, who + * alone receives the {@link ScopeParentBinding}. A link that would close a + * cycle is rejected, because every chain consumer walks parents to the root. + * @param key - the child scope key. + * @param parent - its enclosing scope key. + * @returns the binding that alone may re-link this key. + */ +export declare function bindScopeParent(key: ScopeKey, parent: ScopeKey): ScopeParentBinding; +/** + * Read one key's enclosing scope. + * @param key - the scope key to inspect. + * @returns its parent key, or `undefined` for a root scope. + */ +export declare function scopeParentOf(key: ScopeKey): ScopeKey | undefined; +/** + * The chain from a key to its root ancestor. + * @param key - the starting key, or `undefined` for the empty chain. + * @returns keys nearest-first: `[key, parent, grandparent, …]`. + */ +export declare function scopeChainOf(key: ScopeKey | undefined): ScopeKey[]; +/** A minted registration scope and its quiescent disposal boundaries. */ +export interface Scope { + /** Context through which scope-owned registrations are made. */ + ctx: Context; + /** Exact Cordis disposer, used when nesting this scope in an ordered composite effect. */ + rawDispose: () => Promise | void; + /** Dispose every scope-owned registration; racing calls await the same completion. */ + dispose(): Promise; +} +/** Options accepted by {@link createScope}. */ +export interface CreateScopeOptions { + /** Enclosing scope bound via {@link bindScopeParent} before the scope is usable; the binding stays internal. */ + parent?: ScopeKey; +} +/** + * Mint a scope under `ctx`. The scoped context inherits the minting plugin's + * dependency API and owns every registration made through it. + * @param ctx - active context whose dependency API the scope inherits. + * @param key - opaque identity used for listener routing. + * @param options - optional scope-chain placement. + * @returns the scoped context and exact/shared disposal boundaries. + */ +export declare function createScope(ctx: Context, key: ScopeKey, options?: CreateScopeOptions): Scope; +/** + * Read the nearest scope tag inherited by a context. + * @param ctx - context to inspect. + * @returns its scope key, or `undefined` for an unscoped context. + */ +export declare function scopeOf(ctx: Context): ScopeKey | undefined; +/** + * Build an opaque receiver that preserves the base filter, admits untagged + * listeners globally, and admits tagged listeners for a matching key or any + * of its ancestors ({@link bindScopeParent}): a listener owned by an enclosing + * scope receives every descendant scope's events, which is what lets one + * standing composition observe each of the agents composed under it. A tag + * BELOW the dispatch key stays excluded — events flow up the chain, never + * down. + * @param base - subject or service whose existing Cordis filter is preserved. + * @param key - routed scope identity, or `undefined` for an unscoped subject. + * @returns a carrier whose subject remains available only through event arguments. + */ +export declare function scopeTarget(base: T, key: ScopeKey | undefined): Scoped; +/** + * Test whether a value is a scope carrier. + * @param value - dispatch receiver to inspect. + * @returns whether {@link scopeTarget} created it. + */ +export declare function isScopeCarrier(value: unknown): value is Scoped; +/** + * Read a carrier's routing key. + * @param value - dispatch receiver to inspect. + * @returns the carrier key, or `undefined` for an unkeyed/non-carrier value. + */ +export declare function carrierKeyOf(value: unknown): ScopeKey | undefined; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/invariant.d.ts new file mode 100644 index 0000000..8ba88ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned scoped-dispatch invariants. @module @deepseek-ai/dsh-scope/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "scope-invariant"; +/** Services required before the companion can register. */ +export declare const inject: string[]; +/** + * Register the scope invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/scoped-events.generated.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/scoped-events.generated.d.ts new file mode 100644 index 0000000..4ecb2c3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/scoped-events.generated.d.ts @@ -0,0 +1,18 @@ +/** + * Generated scoped-event routing-subject resolvers for dsh-scope invariants. + * Do not edit by hand; run `pnpm run gen-scoped-events`. + * + * @module @deepseek-ai/dsh-scope/scoped-events.generated + */ +type ScopedSubjectResolver = (args: readonly unknown[]) => unknown; +/** + * Resolve the routing key named by one scoped event payload. A null + * resolver means the payload cannot expose its external routing key, so the + * invariant checks carrier presence only. + * @param event - runtime Cordis event name. + * @returns the generated subject resolver, null for presence-only, + * or undefined when the event is not scope-filtered. + */ +export declare function scopedSubjectResolverFor(event: string): ScopedSubjectResolver | null | undefined; +export {}; +//# sourceMappingURL=scoped-events.generated.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/store.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/store.d.ts new file mode 100644 index 0000000..dd69faa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/lib/types/store.d.ts @@ -0,0 +1,147 @@ +/** + * Shared insertion-ordered storage and effect ownership for scope-aware registries. + * + * @module @deepseek-ai/dsh-scope + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { ScopeKey } from './index.ts'; +/** One scope's aggregate contribution to a registry. */ +export interface ScopeLayer { + /** Whether every table in this layer is empty. */ + isEmpty(): boolean; +} +/** Internal common read contract for the two entry-table implementations. */ +interface EntryValues { + values(): IterableIterator; + isEmpty(): boolean; +} +/** + * Insertion-ordered named entries with caller-owned duplicate diagnostics. + * + * Values are borrowed. Iterators are live within one nonempty table + * generation; draining the table detaches them from later insertions. Each + * successful insertion returns an idempotent undo for that exact entry. + */ +export declare class NamedEntries implements EntryValues { + private readonly duplicateError; + private data; + constructor(duplicateError: (name: string) => Error); + /** + * Insert one unique name. + * @param name - name unique within this table. + * @param value - borrowed value to retain. + * @returns an idempotent undo that removes only this insertion. + */ + insert(name: string, value: V): () => void; + /** + * Read one named value. + * @param name - name to resolve. + * @returns the retained value, or `undefined` when absent. + */ + get(name: string): V | undefined; + /** + * Test one name for membership. + * @param name - name to test. + * @returns whether the table contains that name. + */ + has(name: string): boolean; + /** + * Iterate live names in insertion order. + * @returns the native live key iterator. + */ + keys(): IterableIterator; + /** + * Iterate live entries in insertion order. + * @returns the native live entry iterator. + */ + entries(): IterableIterator<[string, V]>; + /** + * Iterate live values in insertion order. + * @returns the native live value iterator. + */ + values(): IterableIterator; + /** + * Test whether this table has no entries. + * @returns whether the table is empty. + */ + isEmpty(): boolean; +} +/** + * Insertion-ordered anonymous entries with independent registration identity. + * + * Equal values remain separate registrations. Values are borrowed, and + * iterators are live within one nonempty table generation; draining the table + * detaches them from later appends. + */ +export declare class AnonymousEntries implements EntryValues { + private data; + /** + * Append one independently owned value. + * @param value - borrowed value to retain. + * @returns an idempotent undo for this exact append. + */ + append(value: V): () => void; + /** + * Iterate live values in insertion order. + * @returns the native live value iterator. + */ + values(): IterableIterator; + /** + * Test whether this table has no entries. + * @returns whether the table is empty. + */ + isEmpty(): boolean; +} +/** + * Own the global and exact-scope layers for one registry. + * + * Reads never create scoped layers. Registrations derive both visibility and + * effect ownership from the supplied Cordis context, collect undo before + * notification, and reclaim only a completely empty aggregate layer. + */ +export declare class ScopedLayers { + private readonly createLayer; + private readonly onChange; + /** The eagerly constructed context-global layer. */ + readonly global: L; + private readonly scoped; + constructor(createLayer: (scope: ScopeKey | undefined) => L, onChange: () => void); + /** + * Read an existing exact-scope overlay. Deliberately chain-blind: callers + * addressing one scope's OWN contributions (its restrictions, its guards) + * must not silently pick up an ancestor's — use {@link chainLayers} where + * inheritance is the point. + * @param scope - exact scope key; `undefined` denotes no overlay. + * @returns the existing scoped layer, or `undefined` without creating one. + */ + peek(scope: ScopeKey | undefined): L | undefined; + /** + * Existing overlays along the scope's parent chain ({@link scopeChainOf}), + * farthest ancestor first and the exact scope last, so a caller layering + * them in order gives the nearest scope the final word. + * @param scope - viewing scope, or `undefined` for no overlays. + * @returns the existing layers, nearest last; absent overlays are skipped. + */ + chainLayers(scope: ScopeKey | undefined): L[]; + /** + * Materialize global named entries followed by scope-chain shadows, + * farthest ancestor first, so the nearest scope's entry wins a name. + * @param scope - viewing scope, or `undefined` for the global view. + * @param pick - select the named table from a layer. + * @returns an insertion-ordered effective map. + */ + merge(scope: ScopeKey | undefined, pick: (layer: L) => NamedEntries): Map; + /** + * Attach one synchronous layer mutation to its registration context. + * @param ctx - context that determines both scope visibility and effect ownership. + * @param action - atomic mutation returning its synchronous undo. + * @param options - Cordis effect label and optional change notification. + * @returns the exact disposer returned by `ctx.effect()`. + */ + effect(ctx: Context, action: (layer: L) => () => void, options: { + label: string; + notify?: boolean; + }): () => void; +} +export {}; +//# sourceMappingURL=store.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/package.json new file mode 100644 index 0000000..6657bcc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-scope", + "description": "Scoped-context registration primitive (scope tags, scope-filtered event dispatch) for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/scope" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.i18n.yaml new file mode 100644 index 0000000..74b808b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/session/session-persistence/README.md +README.md: 335f40e7439fc4a49fa49bb4541f101250468d1b +README.zh.md: 5a50f051a2c53a5f27b009df11ad46f5952a32ac diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.md new file mode 100644 index 0000000..335f40e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.md @@ -0,0 +1,85 @@ +# @deepseek-ai/dsh-session-persistence + +English | [中文](README.zh.md) + +Session persistence is a capability seam. The abstract `SessionPersistence` service (`ctx.sessionPersistence`) is its Service Definition. It requires a persistence backend to store, reload, and list sessions durably without defining the storage implementation. The seam follows the `dsh-shell` roles ([capability seams](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)): this package owns the Service Definition, a sibling package owns the Service Provider, and Consumers inject the service. + +The persisted unit IS the existing `SessionEvent` (event-sourced model — the log is the single source of truth), so there is no parallel "persisted message" type. Metadata that is NOT replayable conversation state (format version, cwd, lineage, seed boundary, origin, delegation depth) travels separately as `SessionHeader`, owned by `dsh-session` and re-exported here. + +## Service API (`ctx.sessionPersistence`) + +| Method | Contract | +|---|---| +| `locate(meta): SessionLocation \| undefined` | Resolve an absolute per-session artifact target without I/O or materialization. Backends without an independent local artifact return `undefined`. | +| `supportsRawArtifacts: boolean` | State explicitly whether this backend exposes one verbatim artifact per session. Consumers check this capability before calling `readRaw`; `false` is not session absence. | +| `readRaw(id, signal?): Promise` | Read a supported backend's own artifact text verbatim, decoded from its physical encoding but never reconstructed from events. `undefined` means only that the requested artifact is absent; an unsupported backend rejects. | +| `create(meta): Promise` | Register a new session's metadata. MAY defer the physical write until the first `append` (lazy materialization). | +| `append(id, events): Promise` | Durably persist a batch. Append-only; first event `seq` == stored next-seq after any repair; rejects non-JSON-serializable data naming the offending type. | +| `prepare(id, signal?): Promise` | Reserve the exact unpublished Session used by resume. A coordinator reuses an earlier inspection when available, commits pending recovery, and releases an unpublished reservation back to its bounded cache on disposal. | +| `load(id): Promise<{ meta; events }>` | Return an immutable balanced logical log after converting supported older records from the same format version and committing cold recovery. A live load first flushes its snapshot and rejects while its turn is open; a cold load preserves an interrupted final turn and durably closes it with synthetic `tool/result`/`step/end?`/`turn/end {interrupted}` events. Only a torn tail fragment is dropped; committed corruption and malformed records reject as `SessionPersistenceCorruptionError`, while an unsupported format `version` or an event type unknown to this build (without the envelope's `ignorable` marker) refuses as `SessionFormatUnsupportedError`, naming the refusal direction and the raw log path when the backend keeps one artifact per session. | +| `inspect(id, signal?): Promise<{ meta; events }>` | Return an upgraded, validated, deeply frozen logical view without committing recovery or publishing a Session. A cold view receives in-memory synthetic recovery closers while its physical torn tail remains untouched; an already-live view is its current immutable snapshot and may contain an open turn. Coordinator-backed implementations retain the exact cold unpublished Session in a bounded LRU for later `prepare`, but discard and reload it when the stored revision changes. Same-id inspections share an in-flight read. | +| `readFrom(id, fromSeq, signal?): Promise<{ meta; events }>` | Return valid stored events with `seq >= fromSeq` without preparation caching, truncation, closers, or coordinator state. A `fromSeq` at or past the stored end returns an empty event list; a negative or non-safe-integer `fromSeq` rejects. Seek-capable backends (SQLite) read only the suffix unless converting a supported older record requires earlier records; sequential backends (JSONL) parse the whole artifact and skip forward. Unknown-type refusal follows that access pattern: a seek read checks only the returned suffix, while the sequential fallback also refuses on an unknown required event below the window. Intended for checkpoint consumers that apply only events after a stored sequence number. | +| `list(signal?): Promise` | Lightweight listing from metadata, no full-log parse. The optional signal cancels backend listing work. A zero-event lazily-materialized session is absent from `list`. | +| `listSnapshots(signal?): Promise` | Lightweight metadata plus an opaque branded per-log revision, without loading event logs. A revision stays equal while that log and its backing store are unchanged, changes after append or mutating load repair, and cannot collide solely because two stores use the same local counter. The optional signal requests cancellation of backend discovery work; first-party backends settle any started listing work before rejecting so an awaited call is quiescent. | + +## Invariants every backend must honor + +- **Append-only; a crashed turn is closed, not truncated.** Flushed events are never rewritten. A crash can leave an unclosed final turn whose events are real and possibly large; `load` preserves them and durably appends synthetic closers (a risk-classified error `tool/result` per unanswered assistant call, then `step/end?`+`turn/end {interrupted}`) to balance the log and keep the rehydrated history a valid provider transcript. Only a never-fully-written torn tail fragment is discarded. +- **Contiguous seq.** `load` rejects a `seq` gap/parse error in the MIDDLE of the log; `append`'s first `seq` must equal the stored next-seq. +- **JSON-serializable data.** `append` materializes each direct/replay batch through the shared one-pass lossless-JSON boundary. Live `Session` events are already deep-frozen, but the write coordinator still copies each event into a persistence-owned buffer. +- **Durability.** `append` returns only once the batch is durable. + +## The write coordinator + +`PersistenceCoordinator` owns per-id state and serialization, one bounded write controller per live session, lazy materialization, crash-tail repair, session adoption, and quiescent disposal. A first-party backend composes one, implements the small `PersistenceBackend` storage hook interface, and delegates its stateful methods. JSONL and SQLite therefore share lifecycle correctness while retaining different storage primitives; see the [coordinator Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md), [flush-controller simplification](../../../.agents/notes/implemented/simplification/2026-07-23-collapse-persistence-flush-state.md), and [bounded batching decision](../../../.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.md). + +Each `session/event` copies its event into the session controller. The first pending event starts a fixed batching window; later events join without resetting its deadline. The configured `writeBatchMaxDelayMs` bounds this intentional wait, not event-loop, initialization, serialized-operation, or backend latency. Events admitted during a write form a new bounded batch. `session/flush` cancels the wait and is a shared quiescence barrier that drains events admitted while it runs. A background failure is logged once, retains the ordered batch, and pauses automatic retry; a new event starts a fresh window, while explicit flush or backend teardown retries immediately and surfaces a repeated failure. + +Crash repair is cold-only. For a live id, `load(id)` snapshots the authoritative in-memory log, waits for that snapshot to become durable, and returns it only when balanced; an open live turn rejects instead of receiving synthetic interruption closers. For a cold id, inspection reads, validates, freezes, and constructs one unpublished Session; repeated inspection reuses that object graph only while its source revision remains current. `prepare(id)` performs the same check before repair, reserves the exact Session, commits any pending torn-tail/interrupted-turn repair, and returns it for publication. HMR adoption reads through `loadStored`, applies the coordinator's cwd check, and never closes the active turn. + +Backend reads convert the exact supported older records from the same format version before validating current records. Pre-identity messages receive the deterministic id `legacy-message::`; a tool-result content replacement inherits its target's imported id. A pre-react-loop `turn/start` loses its obsolete trigger, a removed `steering/message` becomes the same identified `user/message`, and an older `turn/end` maps its terminal reason without inventing a caller that the old record did not name. The coordinator uses the same converted view for `load`, `inspect`, `readFrom`, ownerless-state claims, and HMR prefix adoption. Storage remains append-only: reads do not rewrite old records, and later appends use the current format. These are narrow import exceptions from the [pre-identity message](../../../.agents/notes/implemented/bug-fix/2026-07-28-load-pre-identity-session-messages.md) and [pre-react-loop session](../../../.agents/notes/implemented/bug-fix/2026-08-04-load-pre-react-loop-sessions.md) decisions, not a general v0 migration promise. + +When a live session emits `session/disposed`, the coordinator waits for its controller, serializes a final drain, then releases state owned by that exact `Session` object. Failed retirement leaves the controller in the live-session map, so backend teardown can retry it. Backend teardown stops event admission first, flushes every remaining controller, awaits per-id operations, and only then closes the storage handle. + +The side-effect-free `locate`, lightweight `listSnapshots`, and per-id `readStoredRevision` queries remain backend-owned because they describe storage topology and revision identity rather than write orchestration. `listSnapshots(signal?)` passes the caller's exact signal into backend discovery so observers can cancel that work without detaching it. + +The `PersistenceBackend` hooks (the only contract between the coordinator and storage): + +| Hook | Role | +|---|---| +| `name` | Backend label for the dispose-failure `AggregateError`. | +| `loadStored(id, signal?)` | Read a stored prefix by id across every storage scope. Used by resume/load, non-mutating inspect, live adoption, and the create-collision probe. The optional signal belongs to observation-only reads. Returned metadata identifies `id`; `revision` identifies exactly the returned header and events; an opaque `tornMarker` is present iff a torn tail must be truncated. | +| `readStoredRevision(id, signal?)` | Read the current source-qualified revision for one id without loading its event log. It uses the same revision representation as `loadStored` and returns `undefined` when the id is absent. | +| `loadStoredFrom?(id, fromSeq, signal?)` | Optional seek-capable suffix read behind the service's `readFrom`: the header plus stored events with `seq >= fromSeq`, non-mutating, no torn marker. SQLite implements it (`WHERE seq >= ?`); a backend that omits it gets the coordinator's fallback — `loadStored` plus a forward skip. | +| `appendBatch(meta, events, isMaterialized)` | Durably append a contiguous batch, lazily materializing ATOMICALLY when not yet materialized. | +| `commitRepair(meta, tornMarker, closers)` | Make a crash repair durable: truncate the torn tail (iff `tornMarker !== undefined` — a marker may be falsy, e.g. seq/offset `0`) and append `closers`. NOT required to be atomic. Used by load (truncate + closers) and live-adoption (truncate only). | +| `list(signal?)` | List all stored metadata, observing optional cancellation. | +| `close?()` | Optional lifecycle teardown (e.g. close a db handle), awaited after the dispose drain. | + +The coordinator asserts the stored id and compares stored/live cwd before repair or live adoption. Its `inspect()` path takes ownership of fresh backend values, validates and freezes them once, and retains at most the configured number of unpublished Sessions without calling `commitRepair`. A retained source is reused or repaired only when its revision still equals `readStoredRevision`; otherwise the coordinator reloads it. This freshness check does not add cross-process writer exclusion. Revision retries converge when the durable log remains unchanged for one read/check round trip; continuous external writers can delay `load`, `inspect`, or `prepare`. The `tornMarker` is fully OPAQUE: the coordinator only tests `!== undefined` and round-trips it to `commitRepair`, never inspecting its value (the JSONL backend uses the byte offset to truncate to, the SQLite backend the seq to delete from). A third-party backend MAY implement the abstract service directly without the coordinator, but it must provide the same non-mutating inspection and trustworthy lightweight snapshot revisions. See [the write-coordinator Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md). + +## Metadata and location types + +Re-exported from `dsh-session`: `SessionHeader` (immutable session metadata: `version`, `id`, `createdAt`, `cwd?`, `parentSession?`, `seedLength?`, `origin?`, `delegationDepth?`). `SessionLocation` is `{ readonly kind: string; readonly path: string }`; its path is an absolute backend target, not proof that the artifact exists or contains an unflushed turn. + +## Model Experience + +### Resumed conversation history + +#### What the model sees + +This seam adds no prompt or schema. Resume restores stored surface events as message history; stored request headers reconstruct earlier calls, while the new loop composes the current system prompt, tools, and session prefix for its next request. Crash repair marks an assistant request without a durable call as `TOOL_NOT_STARTED`; a durable call without a result becomes `TOOL_OUTCOME_UNKNOWN`, whose text lets the model retry read-only or idempotent work but directs it to verify side effects or ask the user instead of retrying blindly. + +#### Token effect + +Zero tokens during ordinary persistence. Resume restores retained history cost and pays the current request envelope normally; each repaired call adds the quoted retained error text. + +#### KV Cache effect + +Persistence does not mutate live request prefixes. A resumed loop can reuse provider cache only when its reconstructed history, current envelope, and model route match; crash-repair results append without rewriting earlier history. + +## Known Limitations and Deferred Work + +- **No deletion or retention API** — pruning stored sessions is out-of-band backend maintenance. +- **`list()` is unpaginated and unfiltered** — it returns every stored session's header; fine for local stores, unindexed at scale. +- **Repair-time synthetic closers are the only crash story** — a backend must synthesize `tool/result`/`step/end`/`turn/end` closers on load; there is no partial-turn resume that continues an interrupted turn instead of closing it. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.zh.md new file mode 100644 index 0000000..5a50f05 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/README.zh.md @@ -0,0 +1,85 @@ +# @deepseek-ai/dsh-session-persistence + +[English](README.md) | 中文 + +会话持久化是一项能力 seam。抽象的 `SessionPersistence` 服务(`ctx.sessionPersistence`)是其 Service Definition。它要求持久化后端持久存储、重新加载和列出会话,但不规定具体存储实现。该 seam 采用与 `dsh-shell` 相同的角色划分(见[能力 seam](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):本包负责 Service Definition,同级包负责 Service Provider,Consumer 注入该服务。 + +持久化单元就是现有 `SessionEvent`(事件溯源模型:日志是唯一真源),因此不存在另一套并行的「持久消息」类型。不属于可回放对话状态的元数据(格式版本、cwd、血缘、种子边界、origin、委托深度)作为 `SessionHeader` 单独传输,该类型归 `dsh-session` 所有,并在此重新导出。 + +## 服务 API(`ctx.sessionPersistence`) + +| 方法 | 约定 | +|---|---| +| `locate(meta): SessionLocation \| undefined` | 在不执行 I/O 或实体化的情况下解析每个会话的绝对产物目标。没有独立本地产物的后端返回 `undefined`。 | +| `supportsRawArtifacts: boolean` | 明确说明该后端是否为每个会话暴露一份逐字工件。Consumer 在调用 `readRaw` 前检查此能力;`false` 并不表示会话缺失。 | +| `readRaw(id, signal?): Promise` | 读取受支持后端自身的逐字工件文本;只解码物理编码,绝不从事件重建。`undefined` 仅表示所请求工件缺失;不支持的后端会拒绝。 | +| `create(meta): Promise` | 注册新会话元数据。可以将物理写入延迟到第一次 `append`(延迟实体化)。 | +| `append(id, events): Promise` | 持久保存一个批次。仅追加;任何修复后,第一个事件 `seq` == 已存储 next-seq;非 JSON 可序列化数据会被拒绝,并命名违规类型。 | +| `prepare(id, signal?): Promise` | 预留恢复所使用的那个未发布 Session。协调器会尽可能复用之前的检查结果、提交待处理恢复,并在 dispose(资源释放)时将未发布 reservation 释放回有界缓存。 | +| `load(id): Promise<{ meta; events }>` | 转换同一格式版本中受支持的旧记录后,返回不可变、平衡的逻辑日志,并提交冷恢复。实时 load 先 flush 其快照,并在轮次开放时拒绝;冷 load 保留中断的最终轮次,并用合成 `tool/result`/`step/end?`/`turn/end {interrupted}` 事件持久关闭它。只丢弃撕裂尾部碎片;已提交损坏和格式错误的记录以 `SessionPersistenceCorruptionError` 拒绝,不支持的格式 `version` 或本构建不认识且信封未带 `ignorable` 标记的事件类型以 `SessionFormatUnsupportedError` 拒绝,消息说明拒绝方向,并在后端为每个会话保留独立文件时给出原始日志路径。 | +| `inspect(id, signal?): Promise<{ meta; events }>` | 返回已经升级、验证和深度冻结的逻辑视图,但不提交恢复或发布 Session。冷视图会获得仅存在于内存的合成恢复 closer,物理撕裂尾部保持不变;实时状态下的视图则是当前不可变快照,可能包含开放的轮次。基于协调器的实现会在有界 LRU 中保留该冷状态下未发布的 Session 本身,供后续 `prepare` 使用,但已存储修订值变化后会丢弃并重新读取。同 id 检查共享进行中的读取。 | +| `readFrom(id, fromSeq, signal?): Promise<{ meta; events }>` | 返回 `seq >= fromSeq` 的有效已存储事件,不进入 preparation 缓存、不截断、不合成 closer,也不发布协调器状态。`fromSeq` 达到或超过已存储末尾时返回空事件列表;负数或非安全整数 `fromSeq` 会被拒绝。可寻址后端(SQLite)只读后缀,除非转换受支持的旧记录需要读取更早的记录;顺序后端(JSONL)解析整个产物并向前跳过。未知类型拒绝遵循同一读取方式:寻址读取只检查返回的后缀,顺序回退路径还会拒绝窗口以下的未知必需事件。供 checkpoint 消费方只应用已存序号之后的事件。 | +| `list(signal?): Promise` | 从元数据轻量列出,不解析完整日志。可选信号取消后端列表工作。零事件延迟实体化会话不在 `list` 中。 | +| `listSnapshots(signal?): Promise` | 返回轻量元数据和每份日志一个不透明、带品牌类型的修订值,不加载事件日志。日志及其后端存储不变时,修订保持相等;append 或变更性 load 修复后会改变;不会仅因两个存储使用相同本地计数器而冲突。可选信号请求取消后端发现工作;第一方后端会先等待所有已启动的列出工作结束,再予以拒绝,因此调用返回拒绝时,相关工作已完全停稳。 | + +## 每个后端必须遵守的不变量 + +- **仅追加;崩溃轮次会被关闭,而非截断。** 已 flush 事件绝不重写。崩溃可留下未关闭最终轮次,其事件真实且可能很大;`load` 保留它们,并持久追加合成 closer(为每个未获回答的 assistant 调用添加一个带风险分类错误的 `tool/result`,再添加 `step/end?`+`turn/end {interrupted}`),以平衡日志,并确保重新载入的历史仍是有效的提供方 transcript(文本记录)。只丢弃从未完整写入的撕裂尾部碎片。 +- **连续 seq。**`load` 拒绝日志中间的 `seq` 缺口/解析错误;`append` 的第一个 `seq` 必须等于已存储 next-seq。 +- **JSON 可序列化数据。**`append` 通过共享单遍无损 JSON 边界实体化每个直接/回放批次。活动 `Session` 事件已深度冻结,但写入协调器仍将每个事件复制到持久化自有缓冲区。 +- **持久性。**`append` 只在批次持久后返回。 + +## 写入协调器 + +`PersistenceCoordinator` 负责每 id 状态和串行化、每个活动会话各自的有界写入 controller、延迟实体化、崩溃尾部修复、会话接管和完全停稳的 dispose。第一方后端组合一个协调器,实现小型 `PersistenceBackend` 存储钩子接口,并委托其有状态方法。因此 JSONL 和 SQLite 共享生命周期正确性,同时保留不同存储原语;见[协调器 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)、[flush controller 简化](../../../.agents/notes/implemented/simplification/2026-07-23-collapse-persistence-flush-state.md)和[有界批处理决策](../../../.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.md)。 + +每个 `session/event` 将事件复制到会话 controller。第一个待处理事件会开启固定批处理窗口;后续事件会加入该批次,但不会重置截止时间。配置的 `writeBatchMaxDelayMs` 只限制这段有意等待,而不限制事件循环、初始化、串行化操作或后端延迟。写入期间接纳的事件会形成一个新的有界批次。`session/flush` 会取消等待,并作为共享的完全停稳屏障,排空屏障运行期间接纳的事件。后台写入失败只记录一次日志,保留顺序不变的批次,并暂停自动重试;新事件会开启新的固定窗口,而显式 flush 或后端拆卸会立即重试,并在失败再次发生时向调用方暴露失败。 + +崩溃修复只适用于冷状态。对于已有活动会话的 id,`load(id)` 为权威内存日志制作快照,等待该快照持久,并只在平衡时返回;活动会话中开放的轮次会被拒绝,而不会收到合成中断 closer。对于冷 id,检查只读取、验证、冻结并构造一次未发布 Session;只有来源修订值仍然是当前值时,重复检查才会复用该对象图。`prepare(id)` 在修复前执行相同校验,预留该 Session 本身,提交任何待处理的撕裂尾部或中断轮次修复,并将其返回用于发布。HMR(热模块替换)接管通过 `loadStored` 读取,应用协调器 cwd 检查,并绝不关闭活动轮次。 + +后端读取会在验证当前记录前,转换同一格式版本中明确受支持的旧记录。消息标识机制引入前的消息会获得确定性的 id `legacy-message::`;工具结果的内容替换会继承其目标导入后的 id。react-loop 引入前的 `turn/start` 会移除过时的 trigger,已移除的 steering(中途引导)事件 `steering/message` 会转换为同一条带标识的 `user/message`;旧版 `turn/end` 会映射终止原因,但不会虚构旧记录中没有记载的调用方。协调器对 `load`、`inspect`、`readFrom`、无所有者状态的认领和 HMR 前缀接管使用同一份转换后视图。存储仍然仅追加:读取不会重写旧记录,此后追加的事件使用当前格式。这些是[消息标识机制引入前的消息](../../../.agents/notes/implemented/bug-fix/2026-07-28-load-pre-identity-session-messages.md)与 [react-loop 引入前会话](../../../.agents/notes/implemented/bug-fix/2026-08-04-load-pre-react-loop-sessions.md)决策所规定的范围受限的导入例外,并不构成通用的 v0 迁移承诺。 + +活动会话发出 `session/disposed` 时,协调器等待其 controller,以串行方式执行最终 drain,然后释放该精确 `Session` 对象拥有的状态。失败退役会将 controller 保留在活动会话 map 中,使后端拆卸可重试。后端拆卸先停止事件接纳,flush 每个剩余 controller,等待每 id 操作,最后才关闭存储句柄。 + +无副作用 `locate`、轻量 `listSnapshots` 和按 id 查询的 `readStoredRevision` 仍由后端负责,因为它们描述存储拓扑和修订身份,而非写入编排。`listSnapshots(signal?)` 将调用方传入的同一个信号传给后端发现流程,使观察者可在不脱离该工作的情况下取消。 + +`PersistenceBackend` 钩子(协调器与存储之间的唯一约定): + +| 钩子 | 职责 | +|---|---| +| `name` | dispose 失败 `AggregateError` 的后端标签。 | +| `loadStored(id, signal?)` | 在全部存储范围中按 id 读取已存储前缀。用于恢复/加载、非修改式 inspect、活动会话接管和 create 冲突探测。可选信号属于仅观察读取。返回元数据标识 `id`;`revision` 精确标识返回的 header 和事件;当且仅当必须截断撕裂尾部时才存在不透明 `tornMarker`。 | +| `readStoredRevision(id, signal?)` | 在不加载事件日志的情况下读取一个 id 当前的来源限定修订值。它使用与 `loadStored` 相同的修订值表示;id 不存在时返回 `undefined`。 | +| `loadStoredFrom?(id, fromSeq, signal?)` | 服务 `readFrom` 背后的可选可寻址后缀读取:返回 header 和 `seq >= fromSeq` 的已存储事件,非修改式、无撕裂标记。SQLite 实现它(`WHERE seq >= ?`);不实现的后端使用协调器回退——`loadStored` 加向前跳过。 | +| `appendBatch(meta, events, isMaterialized)` | 持久追加连续批次;尚未实体化时以原子方式延迟实体化。 | +| `commitRepair(meta, tornMarker, closers)` | 使崩溃修复持久:截断撕裂尾部(当且仅当 `tornMarker !== undefined`;标记可为 falsy,例如 seq/offset `0`),并追加 `closers`。不要求原子性。由 load(截断 + closer)和活动会话接管(仅截断)使用。 | +| `list(signal?)` | 列出全部已存储元数据,并遵循可选的取消信号。 | +| `close?()` | 可选生命周期拆卸(例如关闭 db 句柄),在 dispose drain 后等待其完成。 | + +协调器断言已存储 id,并在修复或活动会话接管前比较已存储/活动会话 cwd。其 `inspect()` 路径取得新鲜后端值的所有权,只验证和冻结一次,并在不调用 `commitRepair` 的情况下最多保留配置数量的未发布 Session。只有保留源的修订值仍等于 `readStoredRevision` 时,系统才会复用或修复它;否则协调器会重新读取。该新鲜性校验不会增加跨进程写入排他。持久日志在一次读取与复核往返内保持不变时,修订值重试才能收敛;持续的外部写入可能延迟 `load`、`inspect` 或 `prepare`。`tornMarker` 完全不透明:协调器只测试 `!== undefined`,并将其原样往返给 `commitRepair`,绝不检查值(JSONL 后端使用待截断字节偏移,SQLite 后端使用待删除 seq)。第三方后端可以不用协调器直接实现抽象服务,但必须提供相同的非修改式检查和可信轻量快照修订。详见[写入协调器 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)。 + +## 元数据与位置类型 + +从 `dsh-session` 重新导出:`SessionHeader`(不可变会话元数据:`version`、`id`、`createdAt`、`cwd?`、`parentSession?`、`seedLength?`、`origin?`、`delegationDepth?`)。`SessionLocation` 是 `{ readonly kind: string; readonly path: string }`;其 path 是绝对后端目标,不证明产物已存在或包含未 flush 轮次。 + +## 模型体验 + +### 恢复的对话历史 + +#### 模型所见 + +该 seam 不添加提示词或 schema。恢复会将已存储的表层事件还原为消息历史;已存储请求 header 重建较早调用,新 loop 则为下一次请求组合当前系统提示词、工具和会话前缀。崩溃修复将没有持久调用的 assistant 请求标记为 `TOOL_NOT_STARTED`;有持久调用但无结果时变为 `TOOL_OUTCOME_UNKNOWN`,其文本允许模型重试只读或幂等工作,但要求验证副作用或询问用户,而不是盲目重试。 + +#### Token 影响 + +普通持久化期间为零 token。恢复后会重新计入保留历史的 token 用量,并照常计入当前请求 envelope 的 token 用量;每个已修复调用都会增加一段以引用形式保留的错误文本。 + +#### KV Cache 影响 + +持久化不修改当前请求前缀。只有当重建历史、当前 envelope 和模型路由匹配时,恢复 loop 才能重用提供方缓存;崩溃修复结果仅追加,不重写较早历史。 + +## 已知限制与暂缓事项 + +- **无删除或保留接口**:剪枝已存储会话是带外后端维护。 +- **`list()` 无分页且无过滤**:它返回每个已存储会话的 header;适合本地存储,大规模时无索引。 +- **修复时合成 closer 是唯一崩溃方案**:后端必须在 load 时合成 `tool/result`/`step/end`/`turn/end` closer;没有继续中断轮次而不先关闭它的部分轮次恢复。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/index.js new file mode 100644 index 0000000..178ec2d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/index.js @@ -0,0 +1,1396 @@ +import { Service } from "@deepseek-ai/cordis"; +import { KNOWN_SESSION_EVENT_TYPES, SESSION_FORMAT_VERSION, SessionPreparation, adoptSessionEvent, interruptedTurnClosers, snapshotJsonValue, snapshotSessionEvent } from "@deepseek-ai/dsh-session"; +import { MAX_TIMER_DELAY_MS } from "@deepseek-ai/dsh-timeout"; +//#region lib/types/revision.js +/** Opaque revision identity for lightweight persistence observations. */ +/** +* Brand a backend revision for the provider-neutral persistence contract. +* @param value - backend-owned opaque revision representation. +* @returns the same runtime string with persistence-revision identity. +*/ +function SessionPersistenceRevision(value) { + return value; +} +//#endregion +//#region lib/types/preparations.js +/** +* Bounded sharing and exclusive reservation of unpublished Sessions. +* @module @deepseek-ai/dsh-session-persistence/preparations +*/ +/** Per-coordinator cold-read sharing, exclusive reservation, and ready-entry LRU. */ +var SessionPreparations = class { + capacity; + entries = /* @__PURE__ */ new Map(); + constructor(capacity) { + this.capacity = capacity; + } + /** + * Whether this pool currently knows about an unpublished identity. + * @param id - session identity. + * @returns whether an entry exists for the identity. + */ + has(id) { + return this.entries.has(id); + } + /** + * Observe one prepared source, sharing an in-flight read for the same id. + * @param id - session identity. + * @param load - cold loader used when no entry exists. + * @param signal - optional cancellation signal while waiting. + * @returns the shared prepared source. + */ + async inspect(id, load, signal) { + const entry = this.entryFor(id, load); + const loaded = signal === void 0 ? await entry.result : await observeQueuedAbort(entry.result, signal); + const source = entry.source ?? loaded; + if (this.entries.get(id) === entry && entry.phase === "ready") this.touch(entry); + return source; + } + /** + * Reserve one ready source after committing its pending durable repair. + * @param id - session identity. + * @param load - cold loader used when no entry exists. + * @param commit - durable repair and cursor-state commit. + * @param signal - optional cancellation signal while waiting. + * @returns the exclusive reservation, or undefined if its entry was invalidated. + */ + async reserve(id, load, commit, signal) { + const entry = this.entryFor(id, load); + await (signal === void 0 ? entry.result : observeQueuedAbort(entry.result, signal)); + while (this.entries.get(id) === entry && entry.phase !== "ready") { + const settled = entry.reservationSettled; + /* v8 ignore next -- committing/reserved transitions install this waiter synchronously. */ + if (settled === void 0) throw new Error(`session "${id}" preparation lost its reservation waiter`); + if (signal === void 0) await settled; + else await observeQueuedAbort(settled, signal); + } + if (this.entries.get(id) !== entry) return void 0; + const source = entry.source; + const reservationSettled = Promise.withResolvers(); + entry.phase = "committing"; + entry.reservationSettled = reservationSettled.promise; + entry.settleReservation = reservationSettled.resolve; + let committed; + try { + committed = await commit(source); + } catch (error) { + this.remove(entry); + throw error; + } + if (committed === void 0) { + this.remove(entry); + return; + } + entry.source = committed.source; + try { + signal?.throwIfAborted(); + } catch (error) { + this.makeReady(entry); + throw error; + } + if (this.entries.get(id) !== entry) return void 0; + const reservation = { + entry, + source: committed.source, + state: committed.state + }; + entry.phase = "reserved"; + entry.reservation = reservation; + return reservation; + } + /** + * Return the exact reservation for Session publication, rejecting aliases. + * @param session - exact Session candidate for publication. + * @returns its reservation, or undefined when no preparation exists. + */ + reservationFor(session) { + const entry = this.entries.get(session.id); + if (entry === void 0) return void 0; + if (entry.phase === "reserved" && entry.source?.session === session && entry.reservation !== void 0) return entry.reservation; + throw new Error(`cannot publish session "${session.id}": persisted state already owns this identity`); + } + /** + * Consume a reservation after its exact Session has attached. + * @param reservation - reservation to consume. + */ + attach(reservation) { + const { entry } = reservation; + if (this.entries.get(entry.id) !== entry || entry.reservation !== reservation) throw new Error(`session "${entry.id}" preparation is no longer reserved`); + this.remove(entry); + } + /** + * Consume a reservation whose caller only needs the committed inspection. + * @param reservation - reservation to consume. + */ + discard(reservation) { + const { entry } = reservation; + if (this.entries.get(entry.id) !== entry || entry.reservation !== reservation) return; + this.remove(entry); + } + /** + * Return a reusable unpublished reservation to the ready LRU. + * @param reservation - reservation to release. + * @param reusable - whether the source remains valid for reuse. + */ + release(reservation, reusable) { + const { entry } = reservation; + if (this.entries.get(entry.id) !== entry || entry.reservation !== reservation || entry.phase !== "reserved") return; + if (!reusable) { + this.remove(entry); + return; + } + delete entry.reservation; + this.makeReady(entry); + } + /** + * Discard a prepared view after the durable log changes. + * @param id - changed session identity. + */ + invalidate(id) { + const entry = this.entries.get(id); + if (entry !== void 0) this.remove(entry); + } + /** + * Discard an exact stale ready source without disturbing an exclusive owner. + * @param id - changed session identity. + * @param expected - exact source observed before its revision check. + * @returns whether the source was discarded, retained by a reservation, or is absent. + */ + discardReady(id, expected) { + const entry = this.entries.get(id); + if (entry === void 0 || entry.source !== expected) return "missing"; + if (entry.phase !== "ready") return "retained"; + this.remove(entry); + return "discarded"; + } + /** + * Reject writes while an unpublished Session exclusively reserves the id. + * @param id - session identity to check. + */ + assertWritable(id) { + const phase = this.entries.get(id)?.phase; + if (phase === "committing" || phase === "reserved") throw new Error(`cannot append session "${id}" while its persisted preparation is reserved`); + } + /** + * Remove a completed entry for an already-serialized append adoption. + * @param id - adopted session identity. + * @returns the prepared source, or undefined when no ready entry exists. + */ + takeReady(id) { + const entry = this.entries.get(id); + if (entry === void 0 || entry.phase !== "ready" || entry.source === void 0) return void 0; + this.remove(entry); + return entry.source; + } + entryFor(id, load) { + const existing = this.entries.get(id); + if (existing !== void 0) return existing; + const deferred = Promise.withResolvers(); + const entry = { + id, + result: deferred.promise, + phase: "loading" + }; + this.entries.set(id, entry); + let loading; + try { + loading = load(); + } catch (error) { + this.remove(entry); + deferred.reject(error); + return entry; + } + loading.then((source) => { + if (this.entries.get(id) === entry) { + entry.source = source; + this.makeReady(entry); + } + deferred.resolve(source); + }, (error) => { + this.remove(entry); + deferred.reject(error); + }); + return entry; + } + makeReady(entry) { + if (this.entries.get(entry.id) !== entry) return; + entry.phase = "ready"; + const settle = entry.settleReservation; + delete entry.reservationSettled; + delete entry.settleReservation; + settle?.(); + this.touch(entry); + } + remove(entry) { + if (this.entries.get(entry.id) !== entry) return; + this.entries.delete(entry.id); + const settle = entry.settleReservation; + delete entry.reservationSettled; + delete entry.settleReservation; + settle?.(); + } + touch(entry) { + this.entries.delete(entry.id); + this.entries.set(entry.id, entry); + let readyCount = 0; + for (const candidate of this.entries.values()) if (candidate.phase === "ready") readyCount += 1; + if (readyCount <= this.capacity) return; + for (const [id, candidate] of this.entries) { + if (candidate.phase !== "ready") continue; + this.entries.delete(id); + return; + } + } +}; +/** +* Give a queued observer a prompt cancellation view without cancelling shared work. +* @param operation - shared operation whose settlement remains authoritative. +* @param signal - observer-local cancellation signal. +* @param started - whether the operation has crossed its cancellation cutoff. +* @returns the operation result or the observer's prompt cancellation. +*/ +function observeQueuedAbort(operation, signal, started = () => false) { + return new Promise((resolve, reject) => { + let settled = false; + const finish = (callback) => { + if (settled) return; + settled = true; + signal.removeEventListener("abort", onAbort); + callback(); + }; + const onAbort = () => { + if (started()) return; + finish(() => { + try { + signal.throwIfAborted(); + } catch (reason) { + rejectObservation(reject, reason); + return; + } + /* v8 ignore next -- a native AbortSignal emits abort only after becoming aborted. */ + reject(/* @__PURE__ */ new Error("queued observation abort event lacked an aborted signal")); + }); + }; + signal.addEventListener("abort", onAbort, { once: true }); + operation.then((value) => { + finish(() => { + resolve(value); + }); + }, (reason) => { + finish(() => { + rejectObservation(reject, reason); + }); + }); + if (signal.aborted) onAbort(); + }); +} +/** Preserve an exact loader or AbortSignal reason, including legacy non-Error values. */ +function rejectObservation(reject, reason) { + reject(reason); +} +//#endregion +//#region lib/types/write-behind.js +/** +* Bounded per-session write batching for the shared persistence coordinator. +* @module @deepseek-ai/dsh-session-persistence/write-behind +*/ +/** +* Owns one live session's pending events, fixed batching deadline, active write, +* failure retention, and explicit quiescence barrier. +*/ +var SessionWriteBehind = class { + options; + pending = []; + timer; + active; + barrier; + deadlineExpired = false; + automaticPaused = false; + /** + * @param options - fixed scheduling policy and durable batch sink. + */ + constructor(options) { + this.options = options; + } + /** Whether this controller owns queued events or an active durable write. */ + get hasWork() { + return this.pending.length > 0 || this.active !== void 0; + } + /** + * Copy one event into the persistence-owned queue and start a fixed deadline + * when the automatic path is idle. + * @param event - frozen live event to retain independently of its producer. + */ + enqueue(event) { + const wasEmpty = this.pending.length === 0; + this.pending.push(structuredClone(event)); + if (this.barrier !== void 0) return; + if (this.automaticPaused) { + this.automaticPaused = false; + this.deadlineExpired = false; + this.armTimer(); + } else if (wasEmpty) this.armTimer(); + } + /** + * Cancel the batching wait and durably drain through a quiescent point. + * Concurrent callers join the same barrier. + * @returns a promise that rejects if the barrier's durable retry fails. + */ + flush() { + if (this.barrier !== void 0) return this.barrier; + this.cancelTimer(); + this.deadlineExpired = false; + this.automaticPaused = false; + const barrier = Promise.withResolvers(); + this.barrier = barrier.promise; + this.drainBarrier(barrier.resolve, barrier.reject); + return barrier.promise; + } + /** Cancel the current automatic deadline without draining retained work. */ + cancelAutomaticWait() { + this.cancelTimer(); + this.deadlineExpired = false; + } + /** Start the one fixed window for the current pending prefix. */ + armTimer() { + this.timer = setTimeout(() => { + this.onDeadline(); + }, this.options.maxDelayMs); + } + /** Cancel any pending automatic deadline. */ + cancelTimer() { + if (this.timer === void 0) return; + clearTimeout(this.timer); + this.timer = void 0; + } + /** Start a background write now, or remember that an active write used the budget. */ + onDeadline() { + this.timer = void 0; + if (this.active !== void 0) { + this.deadlineExpired = true; + return; + } + this.startBackground(); + } + /** Start one detached write whose failure is reported and retained. */ + startBackground() { + this.startWrite(true).then(() => { + this.continueAutomatic(); + }, () => {}); + } + /** Continue immediately after an over-budget active write, otherwise keep its timer. */ + continueAutomatic() { + if (this.barrier !== void 0 || this.pending.length === 0) return; + if (this.deadlineExpired) { + this.deadlineExpired = false; + this.startBackground(); + } + } + /** Await overlapping work, drain to quiescence, and settle the shared barrier. */ + async drainBarrier(resolve, reject) { + try { + const overlapping = this.active; + if (overlapping !== void 0) { + await Promise.allSettled([overlapping]); + this.automaticPaused = false; + } + while (this.pending.length > 0) await this.startWrite(false); + } catch (error) { + this.barrier = void 0; + reject(error); + return; + } + this.barrier = void 0; + resolve(); + } + /** Start one stable pending prefix, retaining it in order if durability fails. */ + startWrite(background) { + const batch = this.pending.splice(0); + this.cancelTimer(); + this.deadlineExpired = false; + const active = Promise.resolve().then(() => this.options.write(batch)).catch((error) => { + this.pending = batch.concat(this.pending); + this.cancelTimer(); + this.deadlineExpired = false; + this.automaticPaused = true; + if (background) this.options.reportBackgroundFailure(error); + throw error; + }).finally(() => { + this.active = void 0; + }); + this.active = active; + return active; + } +}; +//#endregion +//#region lib/types/coordinator.js +/** +* Shared buffering, serialization, adoption, repair, and disposal orchestration +* for first-party backends. Third-party backends may implement the public +* persistence seam directly. +* @module @deepseek-ai/dsh-session-persistence/coordinator +*/ +/** Default number of detached session preparations retained by a coordinator. */ +const DEFAULT_PREPARED_SESSION_CACHE_SIZE = 5; +/** Default maximum intentional wait before a live session batch starts writing. */ +const DEFAULT_WRITE_BATCH_MAX_DELAY_MS = 200; +/** Largest write batching delay accepted by Node's timer implementation. */ +const MAX_WRITE_BATCH_DELAY_MS = MAX_TIMER_DELAY_MS; +/** Durable session contents failed validation after a successful backend read. */ +var SessionPersistenceCorruptionError = class extends Error { + /** + * @param message - stable corruption context. + * @param options - original validation failure. + */ + constructor(message, options) { + super(message, options); + this.name = "SessionPersistenceCorruptionError"; + } +}; +/** +* The stored log is intact but this runtime cannot faithfully interpret it: +* the header carries an unsupported format version, or an event's type is +* unknown to this build and the event is not marked ignorable. Distinct from +* {@link SessionPersistenceCorruptionError} — nothing is damaged; the raw log +* remains readable at {@link location} when the backend keeps one artifact +* per session. +*/ +var SessionFormatUnsupportedError = class extends Error { + location; + /** + * @param message - stable reason the log cannot be interpreted, already + * including the raw-log path when one exists. + * @param location - the backend's artifact location, when one exists. + */ + constructor(message, location) { + super(message); + this.location = location; + this.name = "SessionFormatUnsupportedError"; + } +}; +/** +* Direction-aware refusal text for a stored session whose format version this +* build does not read. Shared by the coordinator's load-time check and by +* backends that must refuse BEFORE decoding version-dependent structure (a +* future format may not satisfy today's structural checks at all, and the +* user must see "upgrade the harness", never "corrupt"). +* @param id - the stored session id, for message context. +* @param version - the stored format version. +* @returns the stable refusal text, without a raw-log path suffix. +*/ +function sessionFormatVersionRefusal(id, version) { + return version > SESSION_FORMAT_VERSION ? `session "${id}" uses log format v${version}, but this harness reads only v${SESSION_FORMAT_VERSION}: the log was written by a newer harness — upgrade the harness to open it` : `session "${id}" uses log format v${version}, older than the supported v${SESSION_FORMAT_VERSION}, and this build ships no upgrade path for it`; +} +/** Collect the rejection reasons from a set of promises (none-throwing). */ +async function settledErrors(promises) { + const settled = await Promise.allSettled([...promises]); + const errors = []; + for (const result of settled) if (result.status === "rejected") errors.push(result.reason); + return errors; +} +/** Whether a live session seed reproduces a persisted prefix exactly. */ +function seedCoversPrefix(seed, prefix) { + return prefix.length <= seed.length && prefix.every((event, index) => { + const seedEvent = seed[index]; + return seedEvent !== void 0 && JSON.stringify(seedEvent) === JSON.stringify(event); + }); +} +/** Reject events from an obsolete v0 vocabulary that this build cannot replay. */ +function assertSupportedEvents(events, id) { + const legacyType = "request/header-delta"; + const legacy = events.find((event) => event.type === legacyType); + if (legacy !== void 0) throw new Error(`session "${id}" contains unsupported legacy request/header-delta event at seq ${legacy.seq}`); + const legacyModeType = "mode/set"; + const legacyMode = events.find((event) => event.type === legacyModeType); + if (legacyMode !== void 0) throw new Error(`session "${id}" contains unsupported legacy mode/set event at seq ${legacyMode.seq}`); + const fallback = events.find((event) => event.type === "request/header" && event.data.reason === "fallback"); + if (fallback !== void 0) throw new Error(`session "${id}" contains unsupported legacy request/header reason "fallback" at seq ${fallback.seq}`); +} +/** Return an object record without widening arrays into message payloads. */ +function asRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0; +} +/** Whether a record contains every required key and no key outside the optional extension set. */ +function hasOnlyKeys(record, required, optional = []) { + const allowed = [...required, ...optional]; + return Object.keys(record).every((key) => allowed.includes(key)) && required.every((key) => Object.hasOwn(record, key)); +} +/** Mint the stable import identity for a message persisted before identities existed. */ +function legacyMessageId(id, seq) { + return `legacy-message:${id}:${seq}`; +} +/** Read a replacement target while leaving malformed surface metadata to the session validator. */ +function replacementStart(event) { + const op = asRecord(event.surfaceOp); + return op?.["op"] === "replace" && typeof op["start"] === "number" ? op["start"] : void 0; +} +/** Whether one suffix event needs facts available only from the preceding stored prefix. */ +function needsLegacyPrefix(event) { + const data = asRecord(event.data); + if (event.type === "steering/message") return true; + if (data === void 0) return false; + switch (event.type) { + case "user/message": return !Object.hasOwn(data, "id") && Object.hasOwn(data, "content"); + case "assistant/message": return !Object.hasOwn(data, "message") && Object.hasOwn(data, "content"); + case "tool/result": return !Object.hasOwn(data, "message") && Object.hasOwn(data, "callId"); + default: return false; + } +} +/** Upgrade the removed steering surface event into its current user-message equivalent. */ +function migrateLegacySteeringEvent(event, id) { + if (event.type !== "steering/message") return event; + const data = asRecord(event.data); + if (data === void 0) throw new Error(`session "${id}" contains malformed pre-react-loop steering/message at seq ${event.seq}`); + const wrapped = asRecord(data["message"]); + if (wrapped !== void 0 && Number.isSafeInteger(data["turn"]) && hasOnlyKeys(data, ["turn", "message"])) return { + ...event, + type: "user/message", + data: wrapped + }; + if (!Number.isSafeInteger(data["turn"]) || !hasOnlyKeys(data, [ + "turn", + "content", + "source" + ])) throw new Error(`session "${id}" contains malformed pre-react-loop steering/message at seq ${event.seq}`); + const { turn: _turn, ...message } = data; + return { + ...event, + type: "user/message", + data: { + ...message, + id: legacyMessageId(id, event.seq), + role: "user" + } + }; +} +/** Remove the obsolete trigger after verifying the complete old turn-start envelope. */ +function migrateLegacyTurnStartEvent(event, id) { + if (event.type !== "turn/start") return event; + const data = asRecord(event.data); + if (data === void 0 || !Object.hasOwn(data, "trigger")) return event; + const trigger = asRecord(data["trigger"]); + if (!Number.isSafeInteger(data["turn"]) || data["turn"] < 1 || !hasOnlyKeys(data, ["turn", "trigger"]) || trigger === void 0 || typeof trigger["kind"] !== "string" || trigger["kind"].length === 0) throw new Error(`session "${id}" contains malformed pre-react-loop turn/start at seq ${event.seq}`); + return { + ...event, + data: { turn: data["turn"] } + }; +} +/** Upgrade an obsolete turn ending while preserving the latest-master envelope. */ +function migrateLegacyTurnEndEvent(event, id) { + if (event.type !== "turn/end") return event; + const data = asRecord(event.data); + /* v8 ignore next -- a non-record current envelope cannot match a legacy shape. */ + if (data === void 0) return event; + const malformed = () => { + throw new Error(`session "${id}" contains malformed pre-react-loop turn/end at seq ${event.seq}`); + }; + const reason = asRecord(data["reason"]); + if (!Number.isSafeInteger(data["turn"]) || data["turn"] < 1 || !hasOnlyKeys(data, ["turn", "reason"]) || reason === void 0 || typeof reason["kind"] !== "string") return malformed(); + let currentReason; + switch (reason["kind"]) { + case "completed": + case "blocked": + case "max-tokens": + case "interrupted": + if (!hasOnlyKeys(reason, ["kind"])) return malformed(); + return event; + case "aborted": + if (Object.hasOwn(reason, "reason")) return event; + if (!hasOnlyKeys(reason, ["kind"])) return malformed(); + currentReason = { + kind: "aborted", + reason: { kind: "legacy" } + }; + break; + case "disposed": + if (!hasOnlyKeys(reason, ["kind"])) return malformed(); + currentReason = { + kind: "aborted", + reason: { kind: "disposed" } + }; + break; + case "error": { + if (Object.hasOwn(reason, "error")) return event; + if (!Number.isSafeInteger(reason["step"]) || reason["step"] < 0) return malformed(); + const failure = asRecord(reason["failure"]); + if (failure !== void 0 && hasOnlyKeys(reason, [ + "kind", + "step", + "failure" + ]) && hasOnlyKeys(failure, ["message", "code"], [ + "status", + "providerRetryAfterMs", + "requestId" + ]) && typeof failure["message"] === "string" && typeof failure["code"] === "string" && (failure["status"] === void 0 || typeof failure["status"] === "number") && (failure["providerRetryAfterMs"] === void 0 || typeof failure["providerRetryAfterMs"] === "number") && (failure["requestId"] === void 0 || typeof failure["requestId"] === "string")) { + currentReason = { + kind: "error", + error: failure + }; + break; + } + if (!hasOnlyKeys(reason, reason["code"] === void 0 ? [ + "kind", + "step", + "message" + ] : [ + "kind", + "step", + "message", + "code" + ]) || typeof reason["message"] !== "string" || reason["code"] !== void 0 && typeof reason["code"] !== "string") return malformed(); + currentReason = { + kind: "error", + error: { + message: reason["message"], + code: typeof reason["code"] === "string" ? reason["code"] : "UNKNOWN" + } + }; + break; + } + default: return event; + } + return { + ...event, + data: { + ...data, + reason: currentReason + } + }; +} +/** +* Upgrade one pre-identity message event into the current wrapper shape. +* Current-looking malformed events remain untouched so validation rejects them +* instead of disguising corruption as legacy data. +*/ +function migrateLegacyMessageEvent(event, id, messageIds) { + const data = asRecord(event.data); + if (data === void 0) return event; + switch (event.type) { + case "user/message": + if (Object.hasOwn(data, "id") || Object.hasOwn(data, "role") || Object.hasOwn(data, "message") || !Object.hasOwn(data, "content") || !Object.hasOwn(data, "source")) return event; + return { + ...event, + data: { + ...data, + id: legacyMessageId(id, event.seq), + role: "user" + } + }; + case "assistant/message": { + if (Object.hasOwn(data, "message") || !Object.hasOwn(data, "content") || !Object.hasOwn(data, "provenance")) return event; + const { content, provenance, ...eventData } = data; + return { + ...event, + data: { + ...eventData, + message: { + id: legacyMessageId(id, event.seq), + role: "assistant", + content, + source: { + ...asRecord(provenance), + kind: "model" + } + } + } + }; + } + case "tool/result": { + if (Object.hasOwn(data, "message") || !Object.hasOwn(data, "callId") || !Object.hasOwn(data, "content") || !Object.hasOwn(data, "isError")) return event; + const { callId, content, isError, ...eventData } = data; + const inheritedId = replacementStart(event); + return { + ...event, + data: { + ...eventData, + message: { + id: inheritedId === void 0 ? legacyMessageId(id, event.seq) : messageIds.get(inheritedId), + role: "user", + content: [{ + type: "tool-result", + toolCallId: callId, + content, + isError + }], + source: { + kind: "tool", + callId + } + } + } + }; + } + default: return event; + } +} +/** Read the identified message carried by one validated current event. */ +function eventMessageId(event) { + const data = asRecord(event.data); + const message = event.type === "user/message" ? data : asRecord(data?.["message"]); + return typeof message?.["id"] === "string" ? message["id"] : void 0; +} +/** Materialize stored events as upgraded, validated snapshots with immutable messages. */ +function snapshotStoredEvents(events, id) { + assertSupportedEvents(events, id); + const messageIds = /* @__PURE__ */ new Map(); + return events.map((event) => { + const snapshot = snapshotSessionEvent(migrateLegacyMessageEvent(migrateLegacySteeringEvent(migrateLegacyTurnEndEvent(migrateLegacyTurnStartEvent(event, id), id), id), id, messageIds)); + const messageId = eventMessageId(snapshot); + if (messageId !== void 0) messageIds.set(snapshot.seq, messageId); + return snapshot; + }); +} +/** Upgrade and validate an exclusively owned backend result without copying it. */ +function adoptStoredEvents(events, id) { + assertSupportedEvents(events, id); + const messageIds = /* @__PURE__ */ new Map(); + for (const [index, event] of events.entries()) { + const adopted = adoptSessionEvent(migrateLegacyMessageEvent(migrateLegacySteeringEvent(migrateLegacyTurnEndEvent(migrateLegacyTurnStartEvent(event, id), id), id), id, messageIds)); + events[index] = adopted; + const messageId = eventMessageId(adopted); + if (messageId !== void 0) messageIds.set(adopted.seq, messageId); + } + return events; +} +/** +* Owns the backend-agnostic session write-path orchestration. A backend +* constructs one (`new PersistenceCoordinator(ctx, this)`), implements +* {@link PersistenceBackend}, and delegates its write/read service methods to +* the matching coordinator methods. +* +* All per-id operations are serialized (a per-id promise chain) so concurrent +* flushes / a flush racing a load never interleave storage writes. The +* constructor installs the write-path listeners, per-session retirement, and +* the backend dispose effect. +* +* @typeParam TornMarker - the backend's opaque torn-tail repair token. +*/ +var PersistenceCoordinator = class { + ctx; + backend; + /** Backend bookkeeping keyed by session id (NOT the live Session object). */ + states = /* @__PURE__ */ new Map(); + /** Lifecycle and write-behind state keyed by the exact live Session. */ + live = /* @__PURE__ */ new Map(); + /** Exact disposed lifecycles whose buffered tail is still draining. */ + retirements = /* @__PURE__ */ new Map(); + /** Shared cold reads, unpublished reservations, and completed LRU entries. */ + preparations; + /** + * Per-session serialization: every operation chains onto the prior one for the + * same id, so writes for one session never interleave. Keyed by session id. + */ + chains = /* @__PURE__ */ new Map(); + /** Resolved fixed write-batching window shared by per-session controllers. */ + writeBatchMaxDelayMs; + constructor(ctx, backend, options = { + preparedSessionCacheSize: 5, + writeBatchMaxDelayMs: 200 + }) { + this.ctx = ctx; + this.backend = backend; + if (!Number.isSafeInteger(options.preparedSessionCacheSize) || options.preparedSessionCacheSize < 1) throw new TypeError("preparedSessionCacheSize must be a positive safe integer"); + if (!Number.isSafeInteger(options.writeBatchMaxDelayMs) || options.writeBatchMaxDelayMs < 1 || options.writeBatchMaxDelayMs > MAX_WRITE_BATCH_DELAY_MS) throw new TypeError(`writeBatchMaxDelayMs must be an integer between 1 and ${MAX_WRITE_BATCH_DELAY_MS}`); + this.writeBatchMaxDelayMs = options.writeBatchMaxDelayMs; + this.preparations = new SessionPreparations(options.preparedSessionCacheSize); + this.installWritePath(); + } + /** + * Register detached session metadata for lazy creation on the first append. + * @param meta - header to snapshot; duplicate tracked or persisted ids reject. + */ + create(meta) { + const snapshot = snapshotJsonValue(meta); + if (snapshot === void 0) return Promise.reject(/* @__PURE__ */ new TypeError("session metadata must be losslessly JSON-serializable")); + if (!Number.isSafeInteger(snapshot.createdAt) || snapshot.createdAt < 0) return Promise.reject(/* @__PURE__ */ new TypeError("session metadata createdAt must be a non-negative safe integer")); + return this.serialize(snapshot.id, () => this.createCore(snapshot)); + } + async createCore(meta) { + if (this.states.has(meta.id) || this.preparations.has(meta.id)) throw new Error(`session "${meta.id}" already exists in this backend`); + if (await this.backend.loadStored(meta.id) !== void 0) throw new Error(`session "${meta.id}" already has a persisted log on disk; load/resume it instead of creating`); + this.states.set(meta.id, { + meta, + cursor: 0, + materialized: false + }); + } + /** + * Durably persist a batch of events. Honors the append-only and contiguous-seq + * contracts; rejects non-JSON-serializable `event.data`. + * @param id - the session the batch belongs to. + * @param events - the contiguous batch to persist, in seq order; materialized + * as a detached lossless-JSON snapshot at call time. + */ + async append(id, events) { + const batch = snapshotJsonValue(events); + if (batch === void 0) throw new TypeError("session event batch is not losslessly JSON-serializable because it contains non-JSON-serializable data"); + return this.serialize(id, () => this.appendCore(id, batch)); + } + async appendCore(id, events) { + assertSupportedEvents(events, id); + if (events.length === 0) return; + this.preparations.assertWritable(id); + let state = this.states.get(id); + if (state === void 0) state = await this.adopt(id); + for (const [i, event] of events.entries()) if (event.seq !== state.cursor + i) throw new Error(`append seq mismatch for "${id}": expected ${state.cursor + i} at index ${i}, got ${event.seq}`); + await this.backend.appendBatch(state.meta, events, state.materialized); + state.materialized = true; + state.cursor += events.length; + this.preparations.invalidate(id); + } + /** + * Prepare and reserve the exact unpublished Session used by resume. + * Revision retries converge once the durable log remains unchanged for one + * read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to prepare. + * @param signal - optional cancellation for reading and repair. + * @returns an owned preparation released after publication or rollback. + */ + async prepare(id, signal) { + for (;;) { + await this.waitForRetirement(id, signal); + if (this.ctx.sessions.get(id) !== void 0) throw new Error(`cannot prepare session "${id}" while it is live`); + const reservation = await this.preparations.reserve(id, () => this.serialize(id, () => this.prepareCore(id)), (source) => this.serialize(id, () => this.commitPrepared(source), signal), signal); + if (reservation === void 0) continue; + if (this.ctx.sessions.get(id) !== void 0) { + this.preparations.release(reservation, false); + throw new Error(`cannot prepare session "${id}" while it is live`); + } + return SessionPreparation.create(reservation.source.session, { release: () => { + this.preparations.release(reservation, reservation.state.owner === void 0 && reservation.source.session.events.length === reservation.source.sessionLength); + } }); + } + } + /** + * Commit recovery and return its immutable logical view without publication. + * Revision retries converge once the durable log remains unchanged for one + * read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to load. + * @returns prepared header and balanced events. + */ + async load(id) { + for (;;) { + await this.waitForRetirement(id); + const live = this.ctx.sessions.get(id); + if (live !== void 0) return this.loadLiveSnapshot(live); + const reservation = await this.preparations.reserve(id, () => this.serialize(id, () => this.prepareCore(id)), (source) => this.serialize(id, () => this.commitPrepared(source))); + if (reservation === void 0) continue; + const attached = this.ctx.sessions.get(id); + if (attached !== void 0) { + this.preparations.discard(reservation); + return this.loadLiveSnapshot(attached); + } + this.preparations.discard(reservation); + return reservation.source.inspection; + } + } + /** + * Inspect a logical session without publishing it or committing recovery. + * A stale ready source is reloaded. A source already committing or reserved + * for resume remains exclusive, and inspection may borrow its immutable view. + * Revision retries converge once the log is stable for one read/check round + * trip; continuous external writers may delay completion. + * @param id - persisted session to inspect. + * @param signal - optional cancellation for preparation work. + * @returns immutable prepared metadata and events; a live view may have an open turn. + */ + async inspect(id, signal) { + for (;;) { + signal?.throwIfAborted(); + if (this.retirements.has(id)) await this.waitForRetirement(id, signal); + const live = this.ctx.sessions.get(id); + if (live !== void 0) return this.inspectLive(live); + try { + const source = await this.preparations.inspect(id, () => this.serialize(id, () => this.prepareCore(id)), signal); + const attached = this.ctx.sessions.get(id); + if (attached !== void 0) return this.inspectLive(attached); + const current = await this.serialize(id, () => this.isPreparedSourceCurrent(source, signal), signal); + const published = this.ctx.sessions.get(id); + if (published !== void 0) return this.inspectLive(published); + if (current) return source.inspection; + if (this.preparations.discardReady(id, source) === "retained") return source.inspection; + } catch (error) { + signal?.throwIfAborted(); + const attached = this.ctx.sessions.get(id); + if (attached !== void 0) return this.inspectLive(attached); + throw error; + } + } + } + /** + * Read the stored events from `fromSeq` onward, detached and non-mutating + * (the read-from-seq primitive behind the service's `readFrom`). Runs on + * the same per-id chain as writes; a backend with the seek-capable + * {@link PersistenceBackend.loadStoredFrom} hook reads only the suffix, + * every other backend reads its stored prefix and skips forward here. + * @param id - persisted session to read. + * @param fromSeq - first event seq to include; a non-negative safe integer. + * @param signal - optional cancellation for queued and backend read work. + * @returns stored header and the valid stored events with `seq >= fromSeq`. + */ + readFrom(id, fromSeq, signal) { + if (!Number.isSafeInteger(fromSeq) || fromSeq < 0) return Promise.reject(/* @__PURE__ */ new TypeError(`readFrom fromSeq must be a non-negative safe integer, got ${String(fromSeq)}`)); + const retired = Promise.resolve(this.retirements.get(id)); + return (signal === void 0 ? retired : observeQueuedAbort(retired, signal, () => false)).then(() => this.serialize(id, () => this.readFromCore(id, fromSeq, signal), signal)); + } + async readFromCore(id, fromSeq, signal) { + signal?.throwIfAborted(); + if (this.backend.loadStoredFrom !== void 0) { + let suffix; + try { + suffix = await this.backend.loadStoredFrom(id, fromSeq, signal); + } catch (error) { + if (signal?.aborted) signal.throwIfAborted(); + throw error; + } + signal?.throwIfAborted(); + if (suffix === void 0) throw new Error(`session "${id}" not found`); + this.assertStoredId(id, suffix.meta); + this.assertVersion(suffix.meta); + if (suffix.events.some(needsLegacyPrefix)) { + const whole = await this.readStoredPrefix(id, signal); + return { + meta: whole.meta, + events: whole.events.filter((event) => event.seq >= fromSeq) + }; + } + const events = snapshotStoredEvents(suffix.events, id); + this.assertEventsSupported(suffix.meta, events); + return { + meta: structuredClone(suffix.meta), + events + }; + } + const whole = await this.readStoredPrefix(id, signal); + return { + meta: whole.meta, + events: whole.events.slice(fromSeq) + }; + } + /** Read one detached physical prefix without logical recovery or caching. */ + async readStoredPrefix(id, signal) { + signal?.throwIfAborted(); + const stored = await this.backend.loadStored(id, signal); + signal?.throwIfAborted(); + if (stored === void 0) throw new Error(`session "${id}" not found`); + this.assertStoredId(id, stored.meta); + this.assertVersion(stored.meta); + const events = snapshotStoredEvents(stored.events, id); + this.assertEventsSupported(stored.meta, events); + return { + meta: structuredClone(stored.meta), + events + }; + } + /** Read, repair in memory, validate, and freeze one cold source once. */ + async prepareCore(id) { + const stored = await this.backend.loadStored(id); + if (stored === void 0) throw new Error(`session "${id}" not found`); + try { + const { meta, events, revision, tornMarker } = stored; + this.assertStoredId(id, meta); + this.assertVersion(meta); + const storedEvents = adoptStoredEvents(events, id); + this.assertEventsSupported(meta, storedEvents); + const closers = interruptedTurnClosers(storedEvents).map(adoptSessionEvent); + const balanced = [...storedEvents, ...closers]; + const session = this.ctx.sessions.prepare(id, { + seed: balanced, + meta, + seedSource: "persistence" + }); + return { + inspection: Object.freeze({ + meta: session.header, + events: Object.freeze(balanced) + }), + session, + revision, + sessionLength: session.events.length, + tornMarker, + closers + }; + } catch (error) { + if (error instanceof SessionFormatUnsupportedError) throw error; + throw new SessionPersistenceCorruptionError(`stored session "${id}" failed validation: ${String(error)}`, { cause: error }); + } + } + /** Commit one prepared repair and establish its ownerless durable cursor. */ + async commitPrepared(source) { + const id = source.inspection.meta.id; + const cursor = source.inspection.events.length; + const existing = this.states.get(id); + if (existing?.owner !== void 0) throw new Error(`session "${id}" already has a live persistence owner`); + if (!await this.isPreparedSourceCurrent(source)) return void 0; + if (source.tornMarker !== void 0 || source.closers.length > 0) { + await this.backend.commitRepair(source.inspection.meta, source.tornMarker, source.closers); + return; + } + const state = existing ?? { + meta: source.inspection.meta, + cursor, + materialized: true + }; + state.meta = source.inspection.meta; + state.cursor = cursor; + state.materialized = true; + this.states.set(id, state); + return { + source, + state + }; + } + /** Whether one cached source still names the current durable log revision. */ + async isPreparedSourceCurrent(source, signal) { + return await this.backend.readStoredRevision(source.inspection.meta.id, signal) === source.revision; + } + /** Return one durable immutable view of an already-live Session. */ + async loadLiveSnapshot(session) { + const events = session.events; + await this.flush(session); + const state = this.states.get(session.id); + /* v8 ignore next -- successful flush always publishes this live session's durable state */ + if (state === void 0) throw new Error(`session "${session.id}" lost persistence state during load`); + if (events.length === 0) throw new Error(`session "${session.id}" not found`); + if (interruptedTurnClosers(events).length > 0) throw new Error(`cannot load session "${session.id}" while its live turn is open; use the live Session or wait for the turn to close`); + return Object.freeze({ + meta: state.meta, + events + }); + } + /** Borrow one immutable view from an already-live Session. */ + inspectLive(session) { + return Object.freeze({ + meta: session.header, + events: session.events + }); + } + /** Await one retiring lifecycle with caller cancellation. */ + waitForRetirement(id, signal) { + const retired = Promise.resolve(this.retirements.get(id)); + return signal === void 0 ? retired : observeQueuedAbort(retired, signal, () => false); + } + /** + * Run `op` after any in-flight operation for the same session id, so writes for + * one session never interleave. Errors do not poison the chain. NOTE: serialized + * public methods must NOT call each other (deadlock); they call the unserialized + * `*Core` helpers instead. + */ + serialize(id, op, signal) { + const prior = this.chains.get(id) ?? Promise.resolve(); + let started = false; + const run = () => { + signal?.throwIfAborted(); + started = true; + return op(); + }; + const next = prior.then(run, run); + const tail = next.then(() => void 0, () => void 0); + this.chains.set(id, tail); + tail.then(() => { + if (this.chains.get(id) === tail) this.chains.delete(id); + }); + return signal === void 0 ? next : observeQueuedAbort(next, signal, () => started); + } + /** Build a state for a session discovered in storage but not yet in memory. */ + async adopt(id) { + for (;;) { + const source = this.preparations.takeReady(id) ?? await this.prepareCore(id); + const committed = await this.commitPrepared(source); + if (committed !== void 0) return committed.state; + } + } + assertVersion(meta) { + if (meta.version === SESSION_FORMAT_VERSION) return; + throw this.unsupported(meta, sessionFormatVersionRefusal(meta.id, meta.version)); + } + /** + * Refuse a log containing an event type this build does not know, unless the + * writer marked the event ignorable: an unrecognized required event may + * change how the rest of the log must be interpreted, so silently skipping + * it would reconstruct a wrong session (the envelope contract on + * `SessionEvent.ignorable`). Runs on NORMALIZED events — after + * `snapshotStoredEvents`/`adoptStoredEvents` has upgraded the legacy shapes + * this build still reads and rejected the ones it does not, so those keep + * their specific diagnostics. + */ + assertEventsSupported(meta, events) { + for (const event of events) { + if (KNOWN_SESSION_EVENT_TYPES.has(event.type) || event.ignorable === true) continue; + throw this.unsupported(meta, `session "${meta.id}" contains event type "${event.type}" (seq ${event.seq}) unknown to this harness and not marked ignorable; refusing to interpret the log — it was likely written by a newer harness`); + } + } + /** Build a format refusal that points at the raw artifact when the backend has one. */ + unsupported(meta, reason) { + const location = this.backend.locate?.(meta); + return new SessionFormatUnsupportedError(location === void 0 ? reason : `${reason} (raw log: ${location.path})`, location); + } + /** Reject backend metadata that is not bound to the requested session id. */ + assertStoredId(id, meta) { + if (meta.id !== id) throw new Error(`stored session identity mismatch: requested "${id}", header contains "${meta.id}"`); + } + installWritePath() { + const ctx = this.ctx; + ctx.effect(() => async () => { + let disposeError; + try { + const errors = await settledErrors([...this.live.keys()].map((session) => this.flush(session))); + while (this.chains.size > 0) await Promise.allSettled([...this.chains.values()]); + if (errors.length > 0) throw new AggregateError(errors, `${this.backend.name} dispose failed`); + } catch (error) { + disposeError = error; + throw error; + } finally { + try { + await this.backend.close?.(); + } catch (closeError) { + /* v8 ignore start -- close failure racing disposal is a defensive teardown edge */ + if (disposeError === void 0) throw closeError; + } + } + }, `${this.backend.name} write path`); + ctx.on("session/created", (session) => { + this.initFor(session); + }); + ctx.on("session/event", (session, event) => { + this.initFor(session).writes.enqueue(event); + }); + ctx.on("session/flush", (session) => this.flush(session)); + ctx.on("session/disposed", (session) => { + this.retire(session); + }); + for (const session of ctx.sessions.list()) this.initFor(session); + } + /** Start and observe one disposed session's final drain. */ + retire(session) { + if (!this.live.has(session)) return; + const retirement = this.retireCore(session); + this.retirements.set(session.id, retirement); + const forget = () => { + if (this.retirements.get(session.id) === retirement) this.retirements.delete(session.id); + }; + retirement.then(forget, forget); + retirement.catch((error) => { + this.ctx.logger.warn(`${this.backend.name}: session "${session.id}" retirement failed: ${String(error)}`); + }); + } + /** Drain and release state owned by one exact disposed Session lifecycle. */ + async retireCore(session) { + await this.flush(session); + const id = session.header.id; + await this.serialize(id, () => { + this.live.delete(session); + if (this.states.get(id)?.owner === session) this.states.delete(id); + }); + } + /** Return the one lifecycle controller for a live session, creating it if needed. */ + initFor(session) { + const existing = this.live.get(session); + if (existing) return existing; + const reservation = this.preparations.reservationFor(session); + if (reservation !== void 0) { + const restored = this.attachPrepared(session, reservation); + this.live.set(session, restored); + return restored; + } + const seed = session.events.map((e) => structuredClone(e)); + const live = { + init: Promise.resolve(), + writes: this.createWriteBehind(session, () => live.init) + }; + this.live.set(session, live); + live.init = this.serialize(session.header.id, () => this.onCreated(session, seed)); + live.init.catch(() => {}); + return live; + } + /** Bind one exact prepared Session and persist only its unpublished suffix. */ + attachPrepared(session, reservation) { + const { source, state } = reservation; + if (source.session !== session || state.owner !== void 0 || state.cursor !== source.inspection.events.length || session.firstLiveSeq !== state.cursor) throw new Error(`session "${session.id}" preparation no longer matches its persistence state`); + const suffix = session.events.slice(state.cursor).map((event) => structuredClone(event)); + this.preparations.attach(reservation); + state.owner = session; + const live = { + init: Promise.resolve(), + writes: this.createWriteBehind(session, () => live.init) + }; + if (suffix.length > 0) { + live.init = this.serialize(session.id, () => this.appendCore(session.id, suffix)); + live.init.catch(() => {}); + } + return live; + } + /** + * Whether a live session's `seed` reproduces the first `cursor` persisted + * events. A `cursor` of 0 (nothing persisted yet) trivially matches. Used when + * a live session claims ownerless state left by a prior `load()`/`create()`. + */ + async seedMatchesPersisted(id, seed, cursor) { + if (cursor === 0) return true; + const stored = await this.backend.loadStored(id); + /* v8 ignore next -- a cursor > 0 means the session was materialized, so it exists */ + if (stored === void 0) return false; + this.assertStoredId(id, stored.meta); + return seedCoversPrefix(seed, snapshotStoredEvents(stored.events, id).slice(0, cursor)); + } + /** + * On session/created: sync the backend's in-memory state to a live Session. + * + * Cases, by whether this backend tracks the id and whether an artifact exists: + * 1. Already tracked → no-op (or claim ownerless state if the seed matches, + * or reclaim a truly-abandoned id, else reject as a collision). + * 2. Not tracked, an artifact EXISTS at the same cwd and is a seq-aligned + * PREFIX of the live events → ADOPT it, persisting any live suffix. + * 3. Not tracked, an artifact EXISTS at another cwd or is NOT a prefix → + * REJECT (collision). + * 4. Not tracked and NO artifact → a genuinely new session: register meta + * (lazy) and persist its seed once. + */ + async onCreated(session, seed) { + const id = session.header.id; + const tracked = this.states.get(id); + if (tracked !== void 0) { + /* v8 ignore next -- initFor dedupes per session object; same-object re-entry can't occur */ + if (tracked.owner === session) return; + if (tracked.owner === void 0) { + if (tracked.meta.cwd !== session.header.cwd) throw new Error(`session "${id}" is already persisted at a different cwd (persisted: ${String(tracked.meta.cwd)}, live: ${String(session.header.cwd)}) (id collision)`); + if (!await this.seedMatchesPersisted(id, seed, tracked.cursor)) throw new Error(`session "${id}" is already persisted with ${tracked.cursor} event(s) that do not match this live session (id collision)`); + tracked.owner = session; + const suffix = seed.slice(tracked.cursor); + if (suffix.length > 0) await this.appendCore(id, suffix); + return; + } + const owner = this.live.get(tracked.owner); + if (!tracked.materialized && !owner?.writes.hasWork) this.states.delete(id); + else throw new Error(`session "${id}" is already bound to a different live session in this backend (id collision)`); + } + const live = await this.backend.loadStored(id); + if (live !== void 0) { + await this.adoptLivePrefix(session, seed, live); + return; + } + const meta = { ...session.header }; + await this.createCore(meta); + const created = this.states.get(id); + /* v8 ignore next -- create() always sets the state for the id */ + if (created !== void 0) created.owner = session; + if (seed.length > 0) await this.appendCore(id, seed); + } + /** + * Adopt a stored prefix as a live session's history (HMR/reload): verify the + * seed covers the stored prefix, truncate any torn tail (NOT the open turn — + * the live Session is still the authority), bind ownership, and persist the + * live suffix that was ahead of the stored prefix. + */ + async adoptLivePrefix(session, seed, stored) { + const { meta, events, tornMarker } = stored; + this.assertStoredId(session.header.id, meta); + if (meta.cwd !== session.header.cwd) throw new Error(`session "${session.header.id}" is already persisted at a different cwd (persisted: ${String(meta.cwd)}, live: ${String(session.header.cwd)}) (id collision)`); + this.assertVersion(meta); + const storedEvents = snapshotStoredEvents(events, session.header.id); + this.assertEventsSupported(meta, storedEvents); + if (!seedCoversPrefix(seed, storedEvents)) throw new Error(`session "${session.header.id}" already has a persisted log on disk that does not match this live session (id collision)`); + if (tornMarker !== void 0) await this.backend.commitRepair(meta, tornMarker, []); + this.states.set(session.header.id, { + meta: { ...meta }, + cursor: storedEvents.length, + materialized: true, + owner: session + }); + const suffix = seed.slice(storedEvents.length); + if (suffix.length > 0) await this.appendCore(session.header.id, suffix); + } + async flush(session) { + const live = this.initFor(session); + live.writes.cancelAutomaticWait(); + try { + await live.init; + } catch (error) { + live.writes.cancelAutomaticWait(); + throw error; + } + await live.writes.flush(); + } + /** Build one package-private write controller around initialization and id serialization. */ + createWriteBehind(session, ready) { + return new SessionWriteBehind({ + maxDelayMs: this.writeBatchMaxDelayMs, + write: async (batch) => { + await ready(); + await this.serialize(session.header.id, () => this.appendLiveBatch(session.header.id, batch)); + }, + reportBackgroundFailure: (error) => { + this.ctx.logger.warn(`${this.backend.name}: background write for session "${session.id}" failed (buffered events retained): ${String(error)}`); + } + }); + } + /** Append one controller-owned prefix after filtering events initialization already stored. */ + async appendLiveBatch(id, batch) { + /* v8 ignore next -- state is always set by the awaited initialization */ + const cursor = this.states.get(id)?.cursor ?? 0; + const fresh = batch.filter((e) => e.seq >= cursor); + await this.appendCore(id, fresh); + } +}; +//#endregion +//#region lib/types/index.js +/** +* Durable session-persistence Service Definition (`ctx.sessionPersistence`). Backends store +* {@link SessionEvent}s as the event-sourced log and carry non-replayable +* {@link SessionHeader} metadata separately. +* @module @deepseek-ai/dsh-session-persistence +*/ +/** +* Durable append-only session storage. Implementations preserve contiguous, +* losslessly JSON-serializable events; {@link append} resolves only after +* durability, and {@link load} balances a complete interrupted tail without +* rewriting committed events. +*/ +var SessionPersistence = class extends Service { + constructor(ctx) { + super(ctx, "sessionPersistence"); + } + /** + * Read a session's backend-owned artifact text verbatim — the exact durable + * bytes the backend wrote (decoded from its physical encoding, e.g. a + * decompressed JSONL). The returned `content` is the raw text, not a + * reconstruction from parsed events, so it preserves backend-specific + * serialization (chunk packing, key order, line breaks). Callers first test + * {@link supportsRawArtifacts}; `undefined` then means only that the requested + * session has no materialized artifact. + * @param _id - the persisted session to read (unused by the default: no + * per-session artifact). + * @param signal - optional cancellation for backend read work. + * @returns the raw artifact plus its parsed header, or `undefined` when the + * session is absent. + * @throws when this backend does not expose per-session raw artifacts. + */ + readRaw(_id, signal) { + if (signal?.aborted === true) return Promise.reject(signal.reason instanceof Error ? signal.reason : /* @__PURE__ */ new Error("aborted")); + return Promise.reject(/* @__PURE__ */ new Error("this session persistence backend does not expose raw artifacts")); + } + /** + * Prepare the exact unpublished Session used by resume. Implementations may + * reuse object graphs retained by an earlier {@link inspect} after confirming + * their durable revision is still current; disposal releases an unpublished + * reservation. Revision retries require the durable log to remain unchanged + * for one read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to prepare. + * @param signal - optional cancellation for preparation work. + * @returns one owned unpublished Session preparation. + */ + async prepare(id, signal) { + signal?.throwIfAborted(); + const loaded = await this.load(id); + signal?.throwIfAborted(); + const sessions = this.ctx.get("sessions"); + if (sessions === void 0) throw new Error("cannot prepare a session: SessionStore is not configured"); + return SessionPreparation.create(sessions.prepare(id, { + seed: loaded.events.map((event) => structuredClone(event)), + meta: structuredClone(loaded.meta), + seedSource: "persistence" + })); + } +}; +//#endregion +export { DEFAULT_PREPARED_SESSION_CACHE_SIZE, DEFAULT_WRITE_BATCH_MAX_DELAY_MS, MAX_WRITE_BATCH_DELAY_MS, PersistenceCoordinator, SessionFormatUnsupportedError, SessionPersistence, SessionPersistence as default, SessionPersistenceCorruptionError, SessionPersistenceRevision, sessionFormatVersionRefusal }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/invariant.js new file mode 100644 index 0000000..6503792 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-session-persistence`. +* @module @deepseek-ai/dsh-session-persistence/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session-persistence"; +/** Cordis companion plugin name. */ +const name = "session-persistence-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: persistence correctness requires backend round-trip and crash-tail tests; +* this package exposes no continuously observable in-process relation. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/coordinator.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/coordinator.d.ts new file mode 100644 index 0000000..04301ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/coordinator.d.ts @@ -0,0 +1,348 @@ +/** + * Shared buffering, serialization, adoption, repair, and disposal orchestration + * for first-party backends. Third-party backends may implement the public + * persistence seam directly. + * @module @deepseek-ai/dsh-session-persistence/coordinator + */ +import { Context } from '@deepseek-ai/cordis'; +import { SessionPreparation } from '@deepseek-ai/dsh-session'; +import type { SessionEvent, SessionId, SessionHeader } from '@deepseek-ai/dsh-session'; +import type { SessionInspection, SessionLocation } from './index.ts'; +import type { SessionPersistenceRevision } from './revision.ts'; +/** Default number of detached session preparations retained by a coordinator. */ +export declare const DEFAULT_PREPARED_SESSION_CACHE_SIZE = 5; +/** Default maximum intentional wait before a live session batch starts writing. */ +export declare const DEFAULT_WRITE_BATCH_MAX_DELAY_MS = 200; +/** Largest write batching delay accepted by Node's timer implementation. */ +export declare const MAX_WRITE_BATCH_DELAY_MS = 2147483647; +/** Durable session contents failed validation after a successful backend read. */ +export declare class SessionPersistenceCorruptionError extends Error { + /** + * @param message - stable corruption context. + * @param options - original validation failure. + */ + constructor(message: string, options: ErrorOptions); +} +/** + * The stored log is intact but this runtime cannot faithfully interpret it: + * the header carries an unsupported format version, or an event's type is + * unknown to this build and the event is not marked ignorable. Distinct from + * {@link SessionPersistenceCorruptionError} — nothing is damaged; the raw log + * remains readable at {@link location} when the backend keeps one artifact + * per session. + */ +export declare class SessionFormatUnsupportedError extends Error { + readonly location?: SessionLocation | undefined; + /** + * @param message - stable reason the log cannot be interpreted, already + * including the raw-log path when one exists. + * @param location - the backend's artifact location, when one exists. + */ + constructor(message: string, location?: SessionLocation | undefined); +} +/** + * Direction-aware refusal text for a stored session whose format version this + * build does not read. Shared by the coordinator's load-time check and by + * backends that must refuse BEFORE decoding version-dependent structure (a + * future format may not satisfy today's structural checks at all, and the + * user must see "upgrade the harness", never "corrupt"). + * @param id - the stored session id, for message context. + * @param version - the stored format version. + * @returns the stable refusal text, without a raw-log path suffix. + */ +export declare function sessionFormatVersionRefusal(id: string, version: number): string; +/** Coordinator policy supplied by a concrete persistence backend. */ +export interface PersistenceCoordinatorOptions { + /** Maximum completed unpublished preparations retained for reuse. */ + readonly preparedSessionCacheSize: number; + /** Maximum intentional batching wait after an idle live queue receives work. */ + readonly writeBatchMaxDelayMs: number; +} +/** + * A stored session's header, valid contiguous event prefix, source-qualified + * revision, and optional opaque torn-tail marker. The revision identifies the + * exact detached prefix. The coordinator only checks marker presence and + * returns its value to {@link PersistenceBackend.commitRepair}; each backend + * owns the marker type. + */ +export interface StoredPrefix { + meta: SessionHeader; + events: SessionEvent[]; + /** Revision observed for exactly this detached prefix. */ + revision: SessionPersistenceRevision; + tornMarker?: TornMarker; +} +/** + * A stored session's header plus the events at or past a requested seq — the + * return shape of the optional seek-capable + * {@link PersistenceBackend.loadStoredFrom} hook. Non-mutating reads carry no + * torn marker: there is nothing to repair. + */ +export interface StoredSuffix { + meta: SessionHeader; + events: SessionEvent[]; +} +/** + * The storage contract between {@link PersistenceCoordinator} and a concrete + * backend: the minimal set of durable primitives the orchestration calls. A + * backend implements these (over files, rows, an object store, …); the + * coordinator supplies everything else (buffering, serialization, cursors, + * adoption, crash repair sequencing, dispose quiescence). + * + * @typeParam TornMarker - the backend's opaque torn-tail repair token (see + * {@link StoredPrefix}). The coordinator treats it as fully opaque. + */ +export interface PersistenceBackend { + /** Human-readable backend name, used in the dispose-failure AggregateError. */ + readonly name: string; + /** + * Read a stored prefix by id, scanning every backend storage scope. Returns + * `undefined` if no stored artifact exists. Returned metadata must identify + * `id` before repair or state publication. Used by resume/load, live adoption, + * and — via `!== undefined` — the create-collision probe. The returned + * `tornMarker` is present iff there is a torn tail to truncate. Every header + * and event graph must be fresh, mutually unaliased, and unretained by the + * backend because preparation freezes and publishes them in place. The + * returned revision must identify exactly those values and use the same + * representation as {@link readStoredRevision}. + * @param id - persisted session id to resolve. + * @param signal - optional cancellation for backend read work. + */ + loadStored(id: SessionId, signal?: AbortSignal): Promise | undefined>; + /** + * Read the current source-qualified revision for one stored session without + * loading its event log. Returns `undefined` when the identity is absent. + * @param id - persisted session id to observe. + * @param signal - optional cancellation for backend read work. + */ + readStoredRevision(id: SessionId, signal?: AbortSignal): Promise; + /** + * Optional seek-capable suffix read behind the service's `readFrom`: return + * the header plus the stored events with `seq >= fromSeq` without reading + * the whole log. A backend whose medium can address events by seq (SQLite) + * implements this so `readFrom` scales with the suffix; sequential backends + * omit it and the coordinator falls back to {@link loadStored} plus a + * forward skip. Non-mutating (no truncation, no closers). Validation of the + * region strictly below `fromSeq` is limited to seq contiguity — the + * service contract scopes this read to the suffix — unless that suffix + * contains a supported legacy shape whose normalization needs earlier + * message-identity facts, in which case the coordinator falls back + * to the complete stored prefix. + * Unknown-type refusal follows the same suffix scope: a seek-capable + * backend's `readFrom` checks only the returned suffix, while the + * sequential fallback parses the whole artifact and refuses on an unknown + * required event anywhere in it — over-refusal on the sequential side is + * accepted rather than widening the seek read. + * @param id - persisted session id to resolve. + * @param fromSeq - first event seq to include (non-negative safe integer, + * validated by the coordinator before this hook runs). + * @param signal - optional cancellation for backend read work. + */ + loadStoredFrom?(id: SessionId, fromSeq: number, signal?: AbortSignal): Promise; + /** + * Durably append a CONTIGUOUS batch, lazily materializing the session first + * when `!isMaterialized`. The materialize-write and the first event batch MUST + * commit ATOMICALLY (a crash between them must not leave a materialized-but- + * empty session). Returns once the batch is durable. + */ + appendBatch(meta: SessionHeader, events: readonly SessionEvent[], isMaterialized: boolean): Promise; + /** + * Make a crash repair durable: truncate the torn tail (iff + * `tornMarker !== undefined`) and append `closers` (iff any). NOT required to + * be atomic — a file backend may truncate-then-append in two fsync'd steps. + * Used by load (truncate + synthetic closers) and by live-adoption (truncate + * only, `closers = []`). + */ + commitRepair(meta: SessionHeader, tornMarker: TornMarker | undefined, closers: readonly SessionEvent[]): Promise; + /** + * List all stored (materialized) sessions' metadata. + * @param signal - optional cancellation for backend listing work. + */ + list(signal?: AbortSignal): Promise; + /** + * Optional side-effect-free artifact locator, used to point refusal + * diagnostics ({@link SessionFormatUnsupportedError}) at the raw log. + * Backends without one artifact per session omit it or return `undefined`. + * @param meta - the header whose artifact is requested. + */ + locate?(meta: SessionHeader): SessionLocation | undefined; + /** + * Optional lifecycle teardown (e.g. close a database handle). Awaited by the + * coordinator's dispose effect AFTER the quiescence drain. A stateless file + * backend omits it. + */ + close?(): Promise; +} +/** + * Owns the backend-agnostic session write-path orchestration. A backend + * constructs one (`new PersistenceCoordinator(ctx, this)`), implements + * {@link PersistenceBackend}, and delegates its write/read service methods to + * the matching coordinator methods. + * + * All per-id operations are serialized (a per-id promise chain) so concurrent + * flushes / a flush racing a load never interleave storage writes. The + * constructor installs the write-path listeners, per-session retirement, and + * the backend dispose effect. + * + * @typeParam TornMarker - the backend's opaque torn-tail repair token. + */ +export declare class PersistenceCoordinator { + private ctx; + private backend; + /** Backend bookkeeping keyed by session id (NOT the live Session object). */ + private states; + /** Lifecycle and write-behind state keyed by the exact live Session. */ + private live; + /** Exact disposed lifecycles whose buffered tail is still draining. */ + private retirements; + /** Shared cold reads, unpublished reservations, and completed LRU entries. */ + private readonly preparations; + /** + * Per-session serialization: every operation chains onto the prior one for the + * same id, so writes for one session never interleave. Keyed by session id. + */ + private chains; + /** Resolved fixed write-batching window shared by per-session controllers. */ + private readonly writeBatchMaxDelayMs; + constructor(ctx: Context, backend: PersistenceBackend, options?: PersistenceCoordinatorOptions); + /** + * Register detached session metadata for lazy creation on the first append. + * @param meta - header to snapshot; duplicate tracked or persisted ids reject. + */ + create(meta: SessionHeader): Promise; + private createCore; + /** + * Durably persist a batch of events. Honors the append-only and contiguous-seq + * contracts; rejects non-JSON-serializable `event.data`. + * @param id - the session the batch belongs to. + * @param events - the contiguous batch to persist, in seq order; materialized + * as a detached lossless-JSON snapshot at call time. + */ + append(id: SessionId, events: readonly SessionEvent[]): Promise; + private appendCore; + /** + * Prepare and reserve the exact unpublished Session used by resume. + * Revision retries converge once the durable log remains unchanged for one + * read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to prepare. + * @param signal - optional cancellation for reading and repair. + * @returns an owned preparation released after publication or rollback. + */ + prepare(id: SessionId, signal?: AbortSignal): Promise; + /** + * Commit recovery and return its immutable logical view without publication. + * Revision retries converge once the durable log remains unchanged for one + * read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to load. + * @returns prepared header and balanced events. + */ + load(id: SessionId): Promise; + /** + * Inspect a logical session without publishing it or committing recovery. + * A stale ready source is reloaded. A source already committing or reserved + * for resume remains exclusive, and inspection may borrow its immutable view. + * Revision retries converge once the log is stable for one read/check round + * trip; continuous external writers may delay completion. + * @param id - persisted session to inspect. + * @param signal - optional cancellation for preparation work. + * @returns immutable prepared metadata and events; a live view may have an open turn. + */ + inspect(id: SessionId, signal?: AbortSignal): Promise; + /** + * Read the stored events from `fromSeq` onward, detached and non-mutating + * (the read-from-seq primitive behind the service's `readFrom`). Runs on + * the same per-id chain as writes; a backend with the seek-capable + * {@link PersistenceBackend.loadStoredFrom} hook reads only the suffix, + * every other backend reads its stored prefix and skips forward here. + * @param id - persisted session to read. + * @param fromSeq - first event seq to include; a non-negative safe integer. + * @param signal - optional cancellation for queued and backend read work. + * @returns stored header and the valid stored events with `seq >= fromSeq`. + */ + readFrom(id: SessionId, fromSeq: number, signal?: AbortSignal): Promise<{ + meta: SessionHeader; + events: SessionEvent[]; + }>; + private readFromCore; + /** Read one detached physical prefix without logical recovery or caching. */ + private readStoredPrefix; + /** Read, repair in memory, validate, and freeze one cold source once. */ + private prepareCore; + /** Commit one prepared repair and establish its ownerless durable cursor. */ + private commitPrepared; + /** Whether one cached source still names the current durable log revision. */ + private isPreparedSourceCurrent; + /** Return one durable immutable view of an already-live Session. */ + private loadLiveSnapshot; + /** Borrow one immutable view from an already-live Session. */ + private inspectLive; + /** Await one retiring lifecycle with caller cancellation. */ + private waitForRetirement; + /** + * Run `op` after any in-flight operation for the same session id, so writes for + * one session never interleave. Errors do not poison the chain. NOTE: serialized + * public methods must NOT call each other (deadlock); they call the unserialized + * `*Core` helpers instead. + */ + private serialize; + /** Build a state for a session discovered in storage but not yet in memory. */ + private adopt; + private assertVersion; + /** + * Refuse a log containing an event type this build does not know, unless the + * writer marked the event ignorable: an unrecognized required event may + * change how the rest of the log must be interpreted, so silently skipping + * it would reconstruct a wrong session (the envelope contract on + * `SessionEvent.ignorable`). Runs on NORMALIZED events — after + * `snapshotStoredEvents`/`adoptStoredEvents` has upgraded the legacy shapes + * this build still reads and rejected the ones it does not, so those keep + * their specific diagnostics. + */ + private assertEventsSupported; + /** Build a format refusal that points at the raw artifact when the backend has one. */ + private unsupported; + /** Reject backend metadata that is not bound to the requested session id. */ + private assertStoredId; + private installWritePath; + /** Start and observe one disposed session's final drain. */ + private retire; + /** Drain and release state owned by one exact disposed Session lifecycle. */ + private retireCore; + /** Return the one lifecycle controller for a live session, creating it if needed. */ + private initFor; + /** Bind one exact prepared Session and persist only its unpublished suffix. */ + private attachPrepared; + /** + * Whether a live session's `seed` reproduces the first `cursor` persisted + * events. A `cursor` of 0 (nothing persisted yet) trivially matches. Used when + * a live session claims ownerless state left by a prior `load()`/`create()`. + */ + private seedMatchesPersisted; + /** + * On session/created: sync the backend's in-memory state to a live Session. + * + * Cases, by whether this backend tracks the id and whether an artifact exists: + * 1. Already tracked → no-op (or claim ownerless state if the seed matches, + * or reclaim a truly-abandoned id, else reject as a collision). + * 2. Not tracked, an artifact EXISTS at the same cwd and is a seq-aligned + * PREFIX of the live events → ADOPT it, persisting any live suffix. + * 3. Not tracked, an artifact EXISTS at another cwd or is NOT a prefix → + * REJECT (collision). + * 4. Not tracked and NO artifact → a genuinely new session: register meta + * (lazy) and persist its seed once. + */ + private onCreated; + /** + * Adopt a stored prefix as a live session's history (HMR/reload): verify the + * seed covers the stored prefix, truncate any torn tail (NOT the open turn — + * the live Session is still the authority), bind ownership, and persist the + * live suffix that was ahead of the stored prefix. + */ + private adoptLivePrefix; + private flush; + /** Build one package-private write controller around initialization and id serialization. */ + private createWriteBehind; + /** Append one controller-owned prefix after filtering events initialization already stored. */ + private appendLiveBatch; +} +//# sourceMappingURL=coordinator.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts new file mode 100644 index 0000000..1ef1a8f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts @@ -0,0 +1,190 @@ +/** + * Durable session-persistence Service Definition (`ctx.sessionPersistence`). Backends store + * {@link SessionEvent}s as the event-sourced log and carry non-replayable + * {@link SessionHeader} metadata separately. + * @module @deepseek-ai/dsh-session-persistence + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import { SessionPreparation } from '@deepseek-ai/dsh-session'; +import type { SessionEvent, SessionId, SessionHeader } from '@deepseek-ai/dsh-session'; +import type { SessionPersistenceRevision } from './revision.ts'; +export type { SessionHeader } from '@deepseek-ai/dsh-session'; +export { SessionPersistenceRevision } from './revision.ts'; +/** Lightweight immutable source identity returned without loading a full log. */ +export interface SessionPersistenceSnapshot { + /** Detached metadata for one materialized session. */ + header: SessionHeader; + /** Opaque source-qualified token that changes whenever this stored log changes. */ + revision: SessionPersistenceRevision; +} +/** Immutable logical session prepared from persistence or a live owner. */ +export interface SessionInspection { + /** Validated immutable session metadata. */ + readonly meta: SessionHeader; + /** Validated contiguous logical event log. */ + readonly events: readonly SessionEvent[]; +} +/** A backend's own raw artifact text for one session, verbatim. */ +export interface SessionRawArtifact { + /** The session header parsed from the artifact's own first line. */ + readonly meta: SessionHeader; + /** The artifact's base filename on disk, without any physical encoding suffix. */ + readonly filename: string; + /** The artifact's full text content, decoded from the backend's physical encoding. */ + readonly content: string; +} +export { DEFAULT_PREPARED_SESSION_CACHE_SIZE, DEFAULT_WRITE_BATCH_MAX_DELAY_MS, MAX_WRITE_BATCH_DELAY_MS, PersistenceCoordinator, SessionFormatUnsupportedError, SessionPersistenceCorruptionError, sessionFormatVersionRefusal, } from './coordinator.ts'; +export type { PersistenceBackend, PersistenceCoordinatorOptions, StoredPrefix, StoredSuffix, } from './coordinator.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + sessionPersistence: SessionPersistence; + } +} +/** + * A backend-resolved, per-session local artifact location. The path is an + * absolute target path and can name an artifact that has not materialized yet. + * Consumers must treat it as a location hint, never as an authorization token. + */ +export interface SessionLocation { + /** Backend-specific artifact kind, for example `jsonl`. */ + readonly kind: string; + /** Absolute path to this session's backend-owned artifact. */ + readonly path: string; +} +/** + * Durable append-only session storage. Implementations preserve contiguous, + * losslessly JSON-serializable events; {@link append} resolves only after + * durability, and {@link load} balances a complete interrupted tail without + * rewriting committed events. + */ +export declare abstract class SessionPersistence extends Service { + constructor(ctx: Context); + /** + * Resolve this backend's independent local artifact for a session without + * reading, creating, flushing, or otherwise materializing it. Backends such + * as SQLite that do not own one artifact per session return `undefined`. + * @param meta - the immutable session header whose artifact is requested. + * @returns the backend-specific absolute location, when one exists. + */ + abstract locate(meta: SessionHeader): SessionLocation | undefined; + /** + * Whether this backend exposes one verbatim raw artifact per session. + * A backend that declares `true` must override {@link readRaw}. + */ + abstract readonly supportsRawArtifacts: boolean; + /** + * Read a session's backend-owned artifact text verbatim — the exact durable + * bytes the backend wrote (decoded from its physical encoding, e.g. a + * decompressed JSONL). The returned `content` is the raw text, not a + * reconstruction from parsed events, so it preserves backend-specific + * serialization (chunk packing, key order, line breaks). Callers first test + * {@link supportsRawArtifacts}; `undefined` then means only that the requested + * session has no materialized artifact. + * @param _id - the persisted session to read (unused by the default: no + * per-session artifact). + * @param signal - optional cancellation for backend read work. + * @returns the raw artifact plus its parsed header, or `undefined` when the + * session is absent. + * @throws when this backend does not expose per-session raw artifacts. + */ + readRaw(_id: SessionId, signal?: AbortSignal): Promise; + /** + * Register a new session's metadata. A backend MAY defer the physical write + * until the first {@link append} (lazy materialization), in which case a + * created-but-never-appended session is absent from {@link list} + * — abandoned sessions leave nothing behind. + * @param meta - the immutable header (id, version, cwd, lineage) to record. + */ + abstract create(meta: SessionHeader): Promise; + /** + * Durably persist a batch of events. Honors the append-only and contiguous- + * seq contracts: the first event's `seq` MUST equal the stored next-seq + * (after `load` has durably closed any interrupted turn). Rejects non-JSON- + * serializable `event.data` with an error naming the offending event type. + * @param id - the session the batch belongs to. + * @param events - the contiguous batch to persist, in seq order. + */ + abstract append(id: SessionId, events: readonly SessionEvent[]): Promise; + /** + * Prepare the exact unpublished Session used by resume. Implementations may + * reuse object graphs retained by an earlier {@link inspect} after confirming + * their durable revision is still current; disposal releases an unpublished + * reservation. Revision retries require the durable log to remain unchanged + * for one read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to prepare. + * @param signal - optional cancellation for preparation work. + * @returns one owned unpublished Session preparation. + */ + prepare(id: SessionId, signal?: AbortSignal): Promise; + /** + * Load an immutable balanced logical view and commit any required cold + * recovery. A complete interrupted final turn is preserved and durably + * closed with missing tool errors plus any open step and turn boundaries; + * only a torn final record is discarded. Unknown versions and corruption in + * the committed prefix reject. Implementations MUST NOT crash-repair an + * identity still bound to a live Session: a balanced live log may return as a + * durable snapshot, while an open live turn rejects. Returned values may be + * shared with immutable live or prepared state and must not be mutated. + * Revision-based implementations may wait for one stable read/check round trip. + * @param id - the persisted session to reload. + * @returns the header and a log ending on a balanced `turn/end`. + */ + abstract load(id: SessionId): Promise; + /** + * Inspect an immutable logical session without committing recovery or + * publishing it. A cold complete interrupted turn receives synthetic closers + * in memory and a torn physical tail remains untouched. An already-live + * Session instead yields its current immutable snapshot, which may contain an + * open turn and its `session/end-seed` boundary. Coordinator-backed + * implementations retain the exact cold unpublished Session for bounded + * reuse by a later {@link prepare}. A stale ready source is reloaded; a source + * already committing or reserved for resume remains exclusive, and inspection + * may borrow its immutable view. Callers borrow only the immutable header and + * log. Continuous external writers may delay revision convergence. + * @param id - the persisted session to inspect. + * @param signal - optional cancellation for queued and backend read work. + * @returns the validated header and current logical event log. + */ + abstract inspect(id: SessionId, signal?: AbortSignal): Promise; + /** + * Read the stored events from `fromSeq` onward — the read-from-seq + * primitive for read models that resume from a watermark (e.g. a persisted + * projection cache folding only the tail past its checkpoint). Unlike + * {@link inspect}, it is a detached physical suffix read: no preparation + * cache, torn-tail truncation, synthetic closers, or coordinator-state + * publication. Only events from the valid contiguous stored prefix are + * returned, so a torn fragment never reaches the caller. `fromSeq` at or + * beyond the stored prefix returns an empty event list (never an error). + * Backends whose medium can seek by seq + * (SQLite) read only the suffix; sequential media (JSONL, both encodings) + * still parse the whole artifact and skip forward — the primitive bounds + * what is RETURNED and refolded, not every backend's physical read. + * @param id - the persisted session to read. + * @param fromSeq - first event seq to include; a non-negative safe integer. + * @param signal - optional cancellation for queued and backend read work. + * @returns the header and the stored events with `seq >= fromSeq`. + */ + abstract readFrom(id: SessionId, fromSeq: number, signal?: AbortSignal): Promise<{ + meta: SessionHeader; + events: SessionEvent[]; + }>; + /** + * Lightweight listing from metadata, without a full-log parse. + * @param signal - optional cancellation for backend listing work. + * @returns one header per materialized session. + */ + abstract list(signal?: AbortSignal): Promise; + /** + * List materialized sessions with cheap per-log change tokens. + * + * Repeated observations of an unchanged log return the same revision. A + * successful mutating {@link load} repair changes the next listed revision. + * Revisions also distinguish independently backed stores so backend-local + * counters cannot compare equal across different persistence sources. + * @param signal - optional cancellation for backend snapshot-listing work. + * @returns one header and opaque revision per materialized session without loading full logs. + */ + abstract listSnapshots(signal?: AbortSignal): Promise; +} +export default SessionPersistence; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/invariant.d.ts new file mode 100644 index 0000000..fa12796 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-persistence`. + * @module @deepseek-ai/dsh-session-persistence/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-persistence-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/preparations.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/preparations.d.ts new file mode 100644 index 0000000..6b93819 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/preparations.d.ts @@ -0,0 +1,115 @@ +/** + * Bounded sharing and exclusive reservation of unpublished Sessions. + * @module @deepseek-ai/dsh-session-persistence/preparations + */ +import type { Session, SessionId } from '@deepseek-ai/dsh-session'; +interface PreparedSource { + readonly session: Session; +} +type PreparationPhase = 'loading' | 'ready' | 'committing' | 'reserved'; +interface PreparationEntry { + readonly id: SessionId; + readonly result: Promise; + phase: PreparationPhase; + source?: Source; + reservation?: SessionPreparationReservation; + reservationSettled?: Promise; + settleReservation?: () => void; +} +/** One exclusively held prepared source and its committed persistence state. */ +export interface SessionPreparationReservation { + readonly entry: PreparationEntry; + readonly source: Source; + readonly state: CommitState; +} +/** Per-coordinator cold-read sharing, exclusive reservation, and ready-entry LRU. */ +export declare class SessionPreparations { + private readonly capacity; + private readonly entries; + constructor(capacity: number); + /** + * Whether this pool currently knows about an unpublished identity. + * @param id - session identity. + * @returns whether an entry exists for the identity. + */ + has(id: SessionId): boolean; + /** + * Observe one prepared source, sharing an in-flight read for the same id. + * @param id - session identity. + * @param load - cold loader used when no entry exists. + * @param signal - optional cancellation signal while waiting. + * @returns the shared prepared source. + */ + inspect(id: SessionId, load: () => Promise, signal?: AbortSignal): Promise; + /** + * Reserve one ready source after committing its pending durable repair. + * @param id - session identity. + * @param load - cold loader used when no entry exists. + * @param commit - durable repair and cursor-state commit. + * @param signal - optional cancellation signal while waiting. + * @returns the exclusive reservation, or undefined if its entry was invalidated. + */ + reserve(id: SessionId, load: () => Promise, commit: (source: Source) => Promise<{ + source: Source; + state: CommitState; + } | undefined>, signal?: AbortSignal): Promise | undefined>; + /** + * Return the exact reservation for Session publication, rejecting aliases. + * @param session - exact Session candidate for publication. + * @returns its reservation, or undefined when no preparation exists. + */ + reservationFor(session: Session): SessionPreparationReservation | undefined; + /** + * Consume a reservation after its exact Session has attached. + * @param reservation - reservation to consume. + */ + attach(reservation: SessionPreparationReservation): void; + /** + * Consume a reservation whose caller only needs the committed inspection. + * @param reservation - reservation to consume. + */ + discard(reservation: SessionPreparationReservation): void; + /** + * Return a reusable unpublished reservation to the ready LRU. + * @param reservation - reservation to release. + * @param reusable - whether the source remains valid for reuse. + */ + release(reservation: SessionPreparationReservation, reusable: boolean): void; + /** + * Discard a prepared view after the durable log changes. + * @param id - changed session identity. + */ + invalidate(id: SessionId): void; + /** + * Discard an exact stale ready source without disturbing an exclusive owner. + * @param id - changed session identity. + * @param expected - exact source observed before its revision check. + * @returns whether the source was discarded, retained by a reservation, or is absent. + */ + discardReady(id: SessionId, expected: Source): 'discarded' | 'retained' | 'missing'; + /** + * Reject writes while an unpublished Session exclusively reserves the id. + * @param id - session identity to check. + */ + assertWritable(id: SessionId): void; + /** + * Remove a completed entry for an already-serialized append adoption. + * @param id - adopted session identity. + * @returns the prepared source, or undefined when no ready entry exists. + */ + takeReady(id: SessionId): Source | undefined; + private entryFor; + private makeReady; + private remove; + private touch; +} +/** + * Give a queued observer a prompt cancellation view without cancelling shared work. + * @param operation - shared operation whose settlement remains authoritative. + * @param signal - observer-local cancellation signal. + * @param started - whether the operation has crossed its cancellation cutoff. + * @returns the operation result or the observer's prompt cancellation. + */ +export declare function observeQueuedAbort(operation: Promise, signal: AbortSignal, started?: () => boolean): Promise; +export {}; +//# sourceMappingURL=preparations.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/revision.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/revision.d.ts new file mode 100644 index 0000000..96da397 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/revision.d.ts @@ -0,0 +1,14 @@ +/** Opaque revision identity for lightweight persistence observations. */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** + * Backend-owned token that identifies both one storage source and one revision + * of a persisted session log. + */ +export type SessionPersistenceRevision = Branded<'SessionPersistenceRevision'>; +/** + * Brand a backend revision for the provider-neutral persistence contract. + * @param value - backend-owned opaque revision representation. + * @returns the same runtime string with persistence-revision identity. + */ +export declare function SessionPersistenceRevision(value: string): SessionPersistenceRevision; +//# sourceMappingURL=revision.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/write-behind.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/write-behind.d.ts new file mode 100644 index 0000000..7775329 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/write-behind.d.ts @@ -0,0 +1,62 @@ +/** + * Bounded per-session write batching for the shared persistence coordinator. + * @module @deepseek-ai/dsh-session-persistence/write-behind + */ +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +/** Dependencies and scheduling policy for one live session's write controller. */ +export interface SessionWriteBehindOptions { + /** Maximum intentional batching wait after an idle queue receives work. */ + readonly maxDelayMs: number; + /** Persist one stable ordered prefix; resolves only after backend durability. */ + readonly write: (events: readonly SessionEvent[]) => Promise; + /** Observe a detached background write failure without rejecting the producer. */ + readonly reportBackgroundFailure: (error: unknown) => void; +} +/** + * Owns one live session's pending events, fixed batching deadline, active write, + * failure retention, and explicit quiescence barrier. + */ +export declare class SessionWriteBehind { + private readonly options; + private pending; + private timer; + private active; + private barrier; + private deadlineExpired; + private automaticPaused; + /** + * @param options - fixed scheduling policy and durable batch sink. + */ + constructor(options: SessionWriteBehindOptions); + /** Whether this controller owns queued events or an active durable write. */ + get hasWork(): boolean; + /** + * Copy one event into the persistence-owned queue and start a fixed deadline + * when the automatic path is idle. + * @param event - frozen live event to retain independently of its producer. + */ + enqueue(event: SessionEvent): void; + /** + * Cancel the batching wait and durably drain through a quiescent point. + * Concurrent callers join the same barrier. + * @returns a promise that rejects if the barrier's durable retry fails. + */ + flush(): Promise; + /** Cancel the current automatic deadline without draining retained work. */ + cancelAutomaticWait(): void; + /** Start the one fixed window for the current pending prefix. */ + private armTimer; + /** Cancel any pending automatic deadline. */ + private cancelTimer; + /** Start a background write now, or remember that an active write used the budget. */ + private onDeadline; + /** Start one detached write whose failure is reported and retained. */ + private startBackground; + /** Continue immediately after an over-budget active write, otherwise keep its timer. */ + private continueAutomatic; + /** Await overlapping work, drain to quiescence, and settle the shared barrier. */ + private drainBarrier; + /** Start one stable pending prefix, retaining it in order if durability fails. */ + private startWrite; +} +//# sourceMappingURL=write-behind.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/package.json new file mode 100644 index 0000000..9eca23f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence/package.json @@ -0,0 +1,49 @@ +{ + "name": "@deepseek-ai/dsh-session-persistence", + "description": "Abstract durable session persistence seam (ctx.sessionPersistence) for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session/session-persistence" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-timeout b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-timeout new file mode 120000 index 0000000..6141c18 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-timeout @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.i18n.yaml new file mode 100644 index 0000000..74b808b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/session/session-persistence/README.md +README.md: 335f40e7439fc4a49fa49bb4541f101250468d1b +README.zh.md: 5a50f051a2c53a5f27b009df11ad46f5952a32ac diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.md new file mode 100644 index 0000000..335f40e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.md @@ -0,0 +1,85 @@ +# @deepseek-ai/dsh-session-persistence + +English | [中文](README.zh.md) + +Session persistence is a capability seam. The abstract `SessionPersistence` service (`ctx.sessionPersistence`) is its Service Definition. It requires a persistence backend to store, reload, and list sessions durably without defining the storage implementation. The seam follows the `dsh-shell` roles ([capability seams](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)): this package owns the Service Definition, a sibling package owns the Service Provider, and Consumers inject the service. + +The persisted unit IS the existing `SessionEvent` (event-sourced model — the log is the single source of truth), so there is no parallel "persisted message" type. Metadata that is NOT replayable conversation state (format version, cwd, lineage, seed boundary, origin, delegation depth) travels separately as `SessionHeader`, owned by `dsh-session` and re-exported here. + +## Service API (`ctx.sessionPersistence`) + +| Method | Contract | +|---|---| +| `locate(meta): SessionLocation \| undefined` | Resolve an absolute per-session artifact target without I/O or materialization. Backends without an independent local artifact return `undefined`. | +| `supportsRawArtifacts: boolean` | State explicitly whether this backend exposes one verbatim artifact per session. Consumers check this capability before calling `readRaw`; `false` is not session absence. | +| `readRaw(id, signal?): Promise` | Read a supported backend's own artifact text verbatim, decoded from its physical encoding but never reconstructed from events. `undefined` means only that the requested artifact is absent; an unsupported backend rejects. | +| `create(meta): Promise` | Register a new session's metadata. MAY defer the physical write until the first `append` (lazy materialization). | +| `append(id, events): Promise` | Durably persist a batch. Append-only; first event `seq` == stored next-seq after any repair; rejects non-JSON-serializable data naming the offending type. | +| `prepare(id, signal?): Promise` | Reserve the exact unpublished Session used by resume. A coordinator reuses an earlier inspection when available, commits pending recovery, and releases an unpublished reservation back to its bounded cache on disposal. | +| `load(id): Promise<{ meta; events }>` | Return an immutable balanced logical log after converting supported older records from the same format version and committing cold recovery. A live load first flushes its snapshot and rejects while its turn is open; a cold load preserves an interrupted final turn and durably closes it with synthetic `tool/result`/`step/end?`/`turn/end {interrupted}` events. Only a torn tail fragment is dropped; committed corruption and malformed records reject as `SessionPersistenceCorruptionError`, while an unsupported format `version` or an event type unknown to this build (without the envelope's `ignorable` marker) refuses as `SessionFormatUnsupportedError`, naming the refusal direction and the raw log path when the backend keeps one artifact per session. | +| `inspect(id, signal?): Promise<{ meta; events }>` | Return an upgraded, validated, deeply frozen logical view without committing recovery or publishing a Session. A cold view receives in-memory synthetic recovery closers while its physical torn tail remains untouched; an already-live view is its current immutable snapshot and may contain an open turn. Coordinator-backed implementations retain the exact cold unpublished Session in a bounded LRU for later `prepare`, but discard and reload it when the stored revision changes. Same-id inspections share an in-flight read. | +| `readFrom(id, fromSeq, signal?): Promise<{ meta; events }>` | Return valid stored events with `seq >= fromSeq` without preparation caching, truncation, closers, or coordinator state. A `fromSeq` at or past the stored end returns an empty event list; a negative or non-safe-integer `fromSeq` rejects. Seek-capable backends (SQLite) read only the suffix unless converting a supported older record requires earlier records; sequential backends (JSONL) parse the whole artifact and skip forward. Unknown-type refusal follows that access pattern: a seek read checks only the returned suffix, while the sequential fallback also refuses on an unknown required event below the window. Intended for checkpoint consumers that apply only events after a stored sequence number. | +| `list(signal?): Promise` | Lightweight listing from metadata, no full-log parse. The optional signal cancels backend listing work. A zero-event lazily-materialized session is absent from `list`. | +| `listSnapshots(signal?): Promise` | Lightweight metadata plus an opaque branded per-log revision, without loading event logs. A revision stays equal while that log and its backing store are unchanged, changes after append or mutating load repair, and cannot collide solely because two stores use the same local counter. The optional signal requests cancellation of backend discovery work; first-party backends settle any started listing work before rejecting so an awaited call is quiescent. | + +## Invariants every backend must honor + +- **Append-only; a crashed turn is closed, not truncated.** Flushed events are never rewritten. A crash can leave an unclosed final turn whose events are real and possibly large; `load` preserves them and durably appends synthetic closers (a risk-classified error `tool/result` per unanswered assistant call, then `step/end?`+`turn/end {interrupted}`) to balance the log and keep the rehydrated history a valid provider transcript. Only a never-fully-written torn tail fragment is discarded. +- **Contiguous seq.** `load` rejects a `seq` gap/parse error in the MIDDLE of the log; `append`'s first `seq` must equal the stored next-seq. +- **JSON-serializable data.** `append` materializes each direct/replay batch through the shared one-pass lossless-JSON boundary. Live `Session` events are already deep-frozen, but the write coordinator still copies each event into a persistence-owned buffer. +- **Durability.** `append` returns only once the batch is durable. + +## The write coordinator + +`PersistenceCoordinator` owns per-id state and serialization, one bounded write controller per live session, lazy materialization, crash-tail repair, session adoption, and quiescent disposal. A first-party backend composes one, implements the small `PersistenceBackend` storage hook interface, and delegates its stateful methods. JSONL and SQLite therefore share lifecycle correctness while retaining different storage primitives; see the [coordinator Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md), [flush-controller simplification](../../../.agents/notes/implemented/simplification/2026-07-23-collapse-persistence-flush-state.md), and [bounded batching decision](../../../.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.md). + +Each `session/event` copies its event into the session controller. The first pending event starts a fixed batching window; later events join without resetting its deadline. The configured `writeBatchMaxDelayMs` bounds this intentional wait, not event-loop, initialization, serialized-operation, or backend latency. Events admitted during a write form a new bounded batch. `session/flush` cancels the wait and is a shared quiescence barrier that drains events admitted while it runs. A background failure is logged once, retains the ordered batch, and pauses automatic retry; a new event starts a fresh window, while explicit flush or backend teardown retries immediately and surfaces a repeated failure. + +Crash repair is cold-only. For a live id, `load(id)` snapshots the authoritative in-memory log, waits for that snapshot to become durable, and returns it only when balanced; an open live turn rejects instead of receiving synthetic interruption closers. For a cold id, inspection reads, validates, freezes, and constructs one unpublished Session; repeated inspection reuses that object graph only while its source revision remains current. `prepare(id)` performs the same check before repair, reserves the exact Session, commits any pending torn-tail/interrupted-turn repair, and returns it for publication. HMR adoption reads through `loadStored`, applies the coordinator's cwd check, and never closes the active turn. + +Backend reads convert the exact supported older records from the same format version before validating current records. Pre-identity messages receive the deterministic id `legacy-message::`; a tool-result content replacement inherits its target's imported id. A pre-react-loop `turn/start` loses its obsolete trigger, a removed `steering/message` becomes the same identified `user/message`, and an older `turn/end` maps its terminal reason without inventing a caller that the old record did not name. The coordinator uses the same converted view for `load`, `inspect`, `readFrom`, ownerless-state claims, and HMR prefix adoption. Storage remains append-only: reads do not rewrite old records, and later appends use the current format. These are narrow import exceptions from the [pre-identity message](../../../.agents/notes/implemented/bug-fix/2026-07-28-load-pre-identity-session-messages.md) and [pre-react-loop session](../../../.agents/notes/implemented/bug-fix/2026-08-04-load-pre-react-loop-sessions.md) decisions, not a general v0 migration promise. + +When a live session emits `session/disposed`, the coordinator waits for its controller, serializes a final drain, then releases state owned by that exact `Session` object. Failed retirement leaves the controller in the live-session map, so backend teardown can retry it. Backend teardown stops event admission first, flushes every remaining controller, awaits per-id operations, and only then closes the storage handle. + +The side-effect-free `locate`, lightweight `listSnapshots`, and per-id `readStoredRevision` queries remain backend-owned because they describe storage topology and revision identity rather than write orchestration. `listSnapshots(signal?)` passes the caller's exact signal into backend discovery so observers can cancel that work without detaching it. + +The `PersistenceBackend` hooks (the only contract between the coordinator and storage): + +| Hook | Role | +|---|---| +| `name` | Backend label for the dispose-failure `AggregateError`. | +| `loadStored(id, signal?)` | Read a stored prefix by id across every storage scope. Used by resume/load, non-mutating inspect, live adoption, and the create-collision probe. The optional signal belongs to observation-only reads. Returned metadata identifies `id`; `revision` identifies exactly the returned header and events; an opaque `tornMarker` is present iff a torn tail must be truncated. | +| `readStoredRevision(id, signal?)` | Read the current source-qualified revision for one id without loading its event log. It uses the same revision representation as `loadStored` and returns `undefined` when the id is absent. | +| `loadStoredFrom?(id, fromSeq, signal?)` | Optional seek-capable suffix read behind the service's `readFrom`: the header plus stored events with `seq >= fromSeq`, non-mutating, no torn marker. SQLite implements it (`WHERE seq >= ?`); a backend that omits it gets the coordinator's fallback — `loadStored` plus a forward skip. | +| `appendBatch(meta, events, isMaterialized)` | Durably append a contiguous batch, lazily materializing ATOMICALLY when not yet materialized. | +| `commitRepair(meta, tornMarker, closers)` | Make a crash repair durable: truncate the torn tail (iff `tornMarker !== undefined` — a marker may be falsy, e.g. seq/offset `0`) and append `closers`. NOT required to be atomic. Used by load (truncate + closers) and live-adoption (truncate only). | +| `list(signal?)` | List all stored metadata, observing optional cancellation. | +| `close?()` | Optional lifecycle teardown (e.g. close a db handle), awaited after the dispose drain. | + +The coordinator asserts the stored id and compares stored/live cwd before repair or live adoption. Its `inspect()` path takes ownership of fresh backend values, validates and freezes them once, and retains at most the configured number of unpublished Sessions without calling `commitRepair`. A retained source is reused or repaired only when its revision still equals `readStoredRevision`; otherwise the coordinator reloads it. This freshness check does not add cross-process writer exclusion. Revision retries converge when the durable log remains unchanged for one read/check round trip; continuous external writers can delay `load`, `inspect`, or `prepare`. The `tornMarker` is fully OPAQUE: the coordinator only tests `!== undefined` and round-trips it to `commitRepair`, never inspecting its value (the JSONL backend uses the byte offset to truncate to, the SQLite backend the seq to delete from). A third-party backend MAY implement the abstract service directly without the coordinator, but it must provide the same non-mutating inspection and trustworthy lightweight snapshot revisions. See [the write-coordinator Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md). + +## Metadata and location types + +Re-exported from `dsh-session`: `SessionHeader` (immutable session metadata: `version`, `id`, `createdAt`, `cwd?`, `parentSession?`, `seedLength?`, `origin?`, `delegationDepth?`). `SessionLocation` is `{ readonly kind: string; readonly path: string }`; its path is an absolute backend target, not proof that the artifact exists or contains an unflushed turn. + +## Model Experience + +### Resumed conversation history + +#### What the model sees + +This seam adds no prompt or schema. Resume restores stored surface events as message history; stored request headers reconstruct earlier calls, while the new loop composes the current system prompt, tools, and session prefix for its next request. Crash repair marks an assistant request without a durable call as `TOOL_NOT_STARTED`; a durable call without a result becomes `TOOL_OUTCOME_UNKNOWN`, whose text lets the model retry read-only or idempotent work but directs it to verify side effects or ask the user instead of retrying blindly. + +#### Token effect + +Zero tokens during ordinary persistence. Resume restores retained history cost and pays the current request envelope normally; each repaired call adds the quoted retained error text. + +#### KV Cache effect + +Persistence does not mutate live request prefixes. A resumed loop can reuse provider cache only when its reconstructed history, current envelope, and model route match; crash-repair results append without rewriting earlier history. + +## Known Limitations and Deferred Work + +- **No deletion or retention API** — pruning stored sessions is out-of-band backend maintenance. +- **`list()` is unpaginated and unfiltered** — it returns every stored session's header; fine for local stores, unindexed at scale. +- **Repair-time synthetic closers are the only crash story** — a backend must synthesize `tool/result`/`step/end`/`turn/end` closers on load; there is no partial-turn resume that continues an interrupted turn instead of closing it. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.zh.md new file mode 100644 index 0000000..5a50f05 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/README.zh.md @@ -0,0 +1,85 @@ +# @deepseek-ai/dsh-session-persistence + +[English](README.md) | 中文 + +会话持久化是一项能力 seam。抽象的 `SessionPersistence` 服务(`ctx.sessionPersistence`)是其 Service Definition。它要求持久化后端持久存储、重新加载和列出会话,但不规定具体存储实现。该 seam 采用与 `dsh-shell` 相同的角色划分(见[能力 seam](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):本包负责 Service Definition,同级包负责 Service Provider,Consumer 注入该服务。 + +持久化单元就是现有 `SessionEvent`(事件溯源模型:日志是唯一真源),因此不存在另一套并行的「持久消息」类型。不属于可回放对话状态的元数据(格式版本、cwd、血缘、种子边界、origin、委托深度)作为 `SessionHeader` 单独传输,该类型归 `dsh-session` 所有,并在此重新导出。 + +## 服务 API(`ctx.sessionPersistence`) + +| 方法 | 约定 | +|---|---| +| `locate(meta): SessionLocation \| undefined` | 在不执行 I/O 或实体化的情况下解析每个会话的绝对产物目标。没有独立本地产物的后端返回 `undefined`。 | +| `supportsRawArtifacts: boolean` | 明确说明该后端是否为每个会话暴露一份逐字工件。Consumer 在调用 `readRaw` 前检查此能力;`false` 并不表示会话缺失。 | +| `readRaw(id, signal?): Promise` | 读取受支持后端自身的逐字工件文本;只解码物理编码,绝不从事件重建。`undefined` 仅表示所请求工件缺失;不支持的后端会拒绝。 | +| `create(meta): Promise` | 注册新会话元数据。可以将物理写入延迟到第一次 `append`(延迟实体化)。 | +| `append(id, events): Promise` | 持久保存一个批次。仅追加;任何修复后,第一个事件 `seq` == 已存储 next-seq;非 JSON 可序列化数据会被拒绝,并命名违规类型。 | +| `prepare(id, signal?): Promise` | 预留恢复所使用的那个未发布 Session。协调器会尽可能复用之前的检查结果、提交待处理恢复,并在 dispose(资源释放)时将未发布 reservation 释放回有界缓存。 | +| `load(id): Promise<{ meta; events }>` | 转换同一格式版本中受支持的旧记录后,返回不可变、平衡的逻辑日志,并提交冷恢复。实时 load 先 flush 其快照,并在轮次开放时拒绝;冷 load 保留中断的最终轮次,并用合成 `tool/result`/`step/end?`/`turn/end {interrupted}` 事件持久关闭它。只丢弃撕裂尾部碎片;已提交损坏和格式错误的记录以 `SessionPersistenceCorruptionError` 拒绝,不支持的格式 `version` 或本构建不认识且信封未带 `ignorable` 标记的事件类型以 `SessionFormatUnsupportedError` 拒绝,消息说明拒绝方向,并在后端为每个会话保留独立文件时给出原始日志路径。 | +| `inspect(id, signal?): Promise<{ meta; events }>` | 返回已经升级、验证和深度冻结的逻辑视图,但不提交恢复或发布 Session。冷视图会获得仅存在于内存的合成恢复 closer,物理撕裂尾部保持不变;实时状态下的视图则是当前不可变快照,可能包含开放的轮次。基于协调器的实现会在有界 LRU 中保留该冷状态下未发布的 Session 本身,供后续 `prepare` 使用,但已存储修订值变化后会丢弃并重新读取。同 id 检查共享进行中的读取。 | +| `readFrom(id, fromSeq, signal?): Promise<{ meta; events }>` | 返回 `seq >= fromSeq` 的有效已存储事件,不进入 preparation 缓存、不截断、不合成 closer,也不发布协调器状态。`fromSeq` 达到或超过已存储末尾时返回空事件列表;负数或非安全整数 `fromSeq` 会被拒绝。可寻址后端(SQLite)只读后缀,除非转换受支持的旧记录需要读取更早的记录;顺序后端(JSONL)解析整个产物并向前跳过。未知类型拒绝遵循同一读取方式:寻址读取只检查返回的后缀,顺序回退路径还会拒绝窗口以下的未知必需事件。供 checkpoint 消费方只应用已存序号之后的事件。 | +| `list(signal?): Promise` | 从元数据轻量列出,不解析完整日志。可选信号取消后端列表工作。零事件延迟实体化会话不在 `list` 中。 | +| `listSnapshots(signal?): Promise` | 返回轻量元数据和每份日志一个不透明、带品牌类型的修订值,不加载事件日志。日志及其后端存储不变时,修订保持相等;append 或变更性 load 修复后会改变;不会仅因两个存储使用相同本地计数器而冲突。可选信号请求取消后端发现工作;第一方后端会先等待所有已启动的列出工作结束,再予以拒绝,因此调用返回拒绝时,相关工作已完全停稳。 | + +## 每个后端必须遵守的不变量 + +- **仅追加;崩溃轮次会被关闭,而非截断。** 已 flush 事件绝不重写。崩溃可留下未关闭最终轮次,其事件真实且可能很大;`load` 保留它们,并持久追加合成 closer(为每个未获回答的 assistant 调用添加一个带风险分类错误的 `tool/result`,再添加 `step/end?`+`turn/end {interrupted}`),以平衡日志,并确保重新载入的历史仍是有效的提供方 transcript(文本记录)。只丢弃从未完整写入的撕裂尾部碎片。 +- **连续 seq。**`load` 拒绝日志中间的 `seq` 缺口/解析错误;`append` 的第一个 `seq` 必须等于已存储 next-seq。 +- **JSON 可序列化数据。**`append` 通过共享单遍无损 JSON 边界实体化每个直接/回放批次。活动 `Session` 事件已深度冻结,但写入协调器仍将每个事件复制到持久化自有缓冲区。 +- **持久性。**`append` 只在批次持久后返回。 + +## 写入协调器 + +`PersistenceCoordinator` 负责每 id 状态和串行化、每个活动会话各自的有界写入 controller、延迟实体化、崩溃尾部修复、会话接管和完全停稳的 dispose。第一方后端组合一个协调器,实现小型 `PersistenceBackend` 存储钩子接口,并委托其有状态方法。因此 JSONL 和 SQLite 共享生命周期正确性,同时保留不同存储原语;见[协调器 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)、[flush controller 简化](../../../.agents/notes/implemented/simplification/2026-07-23-collapse-persistence-flush-state.md)和[有界批处理决策](../../../.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.md)。 + +每个 `session/event` 将事件复制到会话 controller。第一个待处理事件会开启固定批处理窗口;后续事件会加入该批次,但不会重置截止时间。配置的 `writeBatchMaxDelayMs` 只限制这段有意等待,而不限制事件循环、初始化、串行化操作或后端延迟。写入期间接纳的事件会形成一个新的有界批次。`session/flush` 会取消等待,并作为共享的完全停稳屏障,排空屏障运行期间接纳的事件。后台写入失败只记录一次日志,保留顺序不变的批次,并暂停自动重试;新事件会开启新的固定窗口,而显式 flush 或后端拆卸会立即重试,并在失败再次发生时向调用方暴露失败。 + +崩溃修复只适用于冷状态。对于已有活动会话的 id,`load(id)` 为权威内存日志制作快照,等待该快照持久,并只在平衡时返回;活动会话中开放的轮次会被拒绝,而不会收到合成中断 closer。对于冷 id,检查只读取、验证、冻结并构造一次未发布 Session;只有来源修订值仍然是当前值时,重复检查才会复用该对象图。`prepare(id)` 在修复前执行相同校验,预留该 Session 本身,提交任何待处理的撕裂尾部或中断轮次修复,并将其返回用于发布。HMR(热模块替换)接管通过 `loadStored` 读取,应用协调器 cwd 检查,并绝不关闭活动轮次。 + +后端读取会在验证当前记录前,转换同一格式版本中明确受支持的旧记录。消息标识机制引入前的消息会获得确定性的 id `legacy-message::`;工具结果的内容替换会继承其目标导入后的 id。react-loop 引入前的 `turn/start` 会移除过时的 trigger,已移除的 steering(中途引导)事件 `steering/message` 会转换为同一条带标识的 `user/message`;旧版 `turn/end` 会映射终止原因,但不会虚构旧记录中没有记载的调用方。协调器对 `load`、`inspect`、`readFrom`、无所有者状态的认领和 HMR 前缀接管使用同一份转换后视图。存储仍然仅追加:读取不会重写旧记录,此后追加的事件使用当前格式。这些是[消息标识机制引入前的消息](../../../.agents/notes/implemented/bug-fix/2026-07-28-load-pre-identity-session-messages.md)与 [react-loop 引入前会话](../../../.agents/notes/implemented/bug-fix/2026-08-04-load-pre-react-loop-sessions.md)决策所规定的范围受限的导入例外,并不构成通用的 v0 迁移承诺。 + +活动会话发出 `session/disposed` 时,协调器等待其 controller,以串行方式执行最终 drain,然后释放该精确 `Session` 对象拥有的状态。失败退役会将 controller 保留在活动会话 map 中,使后端拆卸可重试。后端拆卸先停止事件接纳,flush 每个剩余 controller,等待每 id 操作,最后才关闭存储句柄。 + +无副作用 `locate`、轻量 `listSnapshots` 和按 id 查询的 `readStoredRevision` 仍由后端负责,因为它们描述存储拓扑和修订身份,而非写入编排。`listSnapshots(signal?)` 将调用方传入的同一个信号传给后端发现流程,使观察者可在不脱离该工作的情况下取消。 + +`PersistenceBackend` 钩子(协调器与存储之间的唯一约定): + +| 钩子 | 职责 | +|---|---| +| `name` | dispose 失败 `AggregateError` 的后端标签。 | +| `loadStored(id, signal?)` | 在全部存储范围中按 id 读取已存储前缀。用于恢复/加载、非修改式 inspect、活动会话接管和 create 冲突探测。可选信号属于仅观察读取。返回元数据标识 `id`;`revision` 精确标识返回的 header 和事件;当且仅当必须截断撕裂尾部时才存在不透明 `tornMarker`。 | +| `readStoredRevision(id, signal?)` | 在不加载事件日志的情况下读取一个 id 当前的来源限定修订值。它使用与 `loadStored` 相同的修订值表示;id 不存在时返回 `undefined`。 | +| `loadStoredFrom?(id, fromSeq, signal?)` | 服务 `readFrom` 背后的可选可寻址后缀读取:返回 header 和 `seq >= fromSeq` 的已存储事件,非修改式、无撕裂标记。SQLite 实现它(`WHERE seq >= ?`);不实现的后端使用协调器回退——`loadStored` 加向前跳过。 | +| `appendBatch(meta, events, isMaterialized)` | 持久追加连续批次;尚未实体化时以原子方式延迟实体化。 | +| `commitRepair(meta, tornMarker, closers)` | 使崩溃修复持久:截断撕裂尾部(当且仅当 `tornMarker !== undefined`;标记可为 falsy,例如 seq/offset `0`),并追加 `closers`。不要求原子性。由 load(截断 + closer)和活动会话接管(仅截断)使用。 | +| `list(signal?)` | 列出全部已存储元数据,并遵循可选的取消信号。 | +| `close?()` | 可选生命周期拆卸(例如关闭 db 句柄),在 dispose drain 后等待其完成。 | + +协调器断言已存储 id,并在修复或活动会话接管前比较已存储/活动会话 cwd。其 `inspect()` 路径取得新鲜后端值的所有权,只验证和冻结一次,并在不调用 `commitRepair` 的情况下最多保留配置数量的未发布 Session。只有保留源的修订值仍等于 `readStoredRevision` 时,系统才会复用或修复它;否则协调器会重新读取。该新鲜性校验不会增加跨进程写入排他。持久日志在一次读取与复核往返内保持不变时,修订值重试才能收敛;持续的外部写入可能延迟 `load`、`inspect` 或 `prepare`。`tornMarker` 完全不透明:协调器只测试 `!== undefined`,并将其原样往返给 `commitRepair`,绝不检查值(JSONL 后端使用待截断字节偏移,SQLite 后端使用待删除 seq)。第三方后端可以不用协调器直接实现抽象服务,但必须提供相同的非修改式检查和可信轻量快照修订。详见[写入协调器 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)。 + +## 元数据与位置类型 + +从 `dsh-session` 重新导出:`SessionHeader`(不可变会话元数据:`version`、`id`、`createdAt`、`cwd?`、`parentSession?`、`seedLength?`、`origin?`、`delegationDepth?`)。`SessionLocation` 是 `{ readonly kind: string; readonly path: string }`;其 path 是绝对后端目标,不证明产物已存在或包含未 flush 轮次。 + +## 模型体验 + +### 恢复的对话历史 + +#### 模型所见 + +该 seam 不添加提示词或 schema。恢复会将已存储的表层事件还原为消息历史;已存储请求 header 重建较早调用,新 loop 则为下一次请求组合当前系统提示词、工具和会话前缀。崩溃修复将没有持久调用的 assistant 请求标记为 `TOOL_NOT_STARTED`;有持久调用但无结果时变为 `TOOL_OUTCOME_UNKNOWN`,其文本允许模型重试只读或幂等工作,但要求验证副作用或询问用户,而不是盲目重试。 + +#### Token 影响 + +普通持久化期间为零 token。恢复后会重新计入保留历史的 token 用量,并照常计入当前请求 envelope 的 token 用量;每个已修复调用都会增加一段以引用形式保留的错误文本。 + +#### KV Cache 影响 + +持久化不修改当前请求前缀。只有当重建历史、当前 envelope 和模型路由匹配时,恢复 loop 才能重用提供方缓存;崩溃修复结果仅追加,不重写较早历史。 + +## 已知限制与暂缓事项 + +- **无删除或保留接口**:剪枝已存储会话是带外后端维护。 +- **`list()` 无分页且无过滤**:它返回每个已存储会话的 header;适合本地存储,大规模时无索引。 +- **修复时合成 closer 是唯一崩溃方案**:后端必须在 load 时合成 `tool/result`/`step/end`/`turn/end` closer;没有继续中断轮次而不先关闭它的部分轮次恢复。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/index.js new file mode 100644 index 0000000..178ec2d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/index.js @@ -0,0 +1,1396 @@ +import { Service } from "@deepseek-ai/cordis"; +import { KNOWN_SESSION_EVENT_TYPES, SESSION_FORMAT_VERSION, SessionPreparation, adoptSessionEvent, interruptedTurnClosers, snapshotJsonValue, snapshotSessionEvent } from "@deepseek-ai/dsh-session"; +import { MAX_TIMER_DELAY_MS } from "@deepseek-ai/dsh-timeout"; +//#region lib/types/revision.js +/** Opaque revision identity for lightweight persistence observations. */ +/** +* Brand a backend revision for the provider-neutral persistence contract. +* @param value - backend-owned opaque revision representation. +* @returns the same runtime string with persistence-revision identity. +*/ +function SessionPersistenceRevision(value) { + return value; +} +//#endregion +//#region lib/types/preparations.js +/** +* Bounded sharing and exclusive reservation of unpublished Sessions. +* @module @deepseek-ai/dsh-session-persistence/preparations +*/ +/** Per-coordinator cold-read sharing, exclusive reservation, and ready-entry LRU. */ +var SessionPreparations = class { + capacity; + entries = /* @__PURE__ */ new Map(); + constructor(capacity) { + this.capacity = capacity; + } + /** + * Whether this pool currently knows about an unpublished identity. + * @param id - session identity. + * @returns whether an entry exists for the identity. + */ + has(id) { + return this.entries.has(id); + } + /** + * Observe one prepared source, sharing an in-flight read for the same id. + * @param id - session identity. + * @param load - cold loader used when no entry exists. + * @param signal - optional cancellation signal while waiting. + * @returns the shared prepared source. + */ + async inspect(id, load, signal) { + const entry = this.entryFor(id, load); + const loaded = signal === void 0 ? await entry.result : await observeQueuedAbort(entry.result, signal); + const source = entry.source ?? loaded; + if (this.entries.get(id) === entry && entry.phase === "ready") this.touch(entry); + return source; + } + /** + * Reserve one ready source after committing its pending durable repair. + * @param id - session identity. + * @param load - cold loader used when no entry exists. + * @param commit - durable repair and cursor-state commit. + * @param signal - optional cancellation signal while waiting. + * @returns the exclusive reservation, or undefined if its entry was invalidated. + */ + async reserve(id, load, commit, signal) { + const entry = this.entryFor(id, load); + await (signal === void 0 ? entry.result : observeQueuedAbort(entry.result, signal)); + while (this.entries.get(id) === entry && entry.phase !== "ready") { + const settled = entry.reservationSettled; + /* v8 ignore next -- committing/reserved transitions install this waiter synchronously. */ + if (settled === void 0) throw new Error(`session "${id}" preparation lost its reservation waiter`); + if (signal === void 0) await settled; + else await observeQueuedAbort(settled, signal); + } + if (this.entries.get(id) !== entry) return void 0; + const source = entry.source; + const reservationSettled = Promise.withResolvers(); + entry.phase = "committing"; + entry.reservationSettled = reservationSettled.promise; + entry.settleReservation = reservationSettled.resolve; + let committed; + try { + committed = await commit(source); + } catch (error) { + this.remove(entry); + throw error; + } + if (committed === void 0) { + this.remove(entry); + return; + } + entry.source = committed.source; + try { + signal?.throwIfAborted(); + } catch (error) { + this.makeReady(entry); + throw error; + } + if (this.entries.get(id) !== entry) return void 0; + const reservation = { + entry, + source: committed.source, + state: committed.state + }; + entry.phase = "reserved"; + entry.reservation = reservation; + return reservation; + } + /** + * Return the exact reservation for Session publication, rejecting aliases. + * @param session - exact Session candidate for publication. + * @returns its reservation, or undefined when no preparation exists. + */ + reservationFor(session) { + const entry = this.entries.get(session.id); + if (entry === void 0) return void 0; + if (entry.phase === "reserved" && entry.source?.session === session && entry.reservation !== void 0) return entry.reservation; + throw new Error(`cannot publish session "${session.id}": persisted state already owns this identity`); + } + /** + * Consume a reservation after its exact Session has attached. + * @param reservation - reservation to consume. + */ + attach(reservation) { + const { entry } = reservation; + if (this.entries.get(entry.id) !== entry || entry.reservation !== reservation) throw new Error(`session "${entry.id}" preparation is no longer reserved`); + this.remove(entry); + } + /** + * Consume a reservation whose caller only needs the committed inspection. + * @param reservation - reservation to consume. + */ + discard(reservation) { + const { entry } = reservation; + if (this.entries.get(entry.id) !== entry || entry.reservation !== reservation) return; + this.remove(entry); + } + /** + * Return a reusable unpublished reservation to the ready LRU. + * @param reservation - reservation to release. + * @param reusable - whether the source remains valid for reuse. + */ + release(reservation, reusable) { + const { entry } = reservation; + if (this.entries.get(entry.id) !== entry || entry.reservation !== reservation || entry.phase !== "reserved") return; + if (!reusable) { + this.remove(entry); + return; + } + delete entry.reservation; + this.makeReady(entry); + } + /** + * Discard a prepared view after the durable log changes. + * @param id - changed session identity. + */ + invalidate(id) { + const entry = this.entries.get(id); + if (entry !== void 0) this.remove(entry); + } + /** + * Discard an exact stale ready source without disturbing an exclusive owner. + * @param id - changed session identity. + * @param expected - exact source observed before its revision check. + * @returns whether the source was discarded, retained by a reservation, or is absent. + */ + discardReady(id, expected) { + const entry = this.entries.get(id); + if (entry === void 0 || entry.source !== expected) return "missing"; + if (entry.phase !== "ready") return "retained"; + this.remove(entry); + return "discarded"; + } + /** + * Reject writes while an unpublished Session exclusively reserves the id. + * @param id - session identity to check. + */ + assertWritable(id) { + const phase = this.entries.get(id)?.phase; + if (phase === "committing" || phase === "reserved") throw new Error(`cannot append session "${id}" while its persisted preparation is reserved`); + } + /** + * Remove a completed entry for an already-serialized append adoption. + * @param id - adopted session identity. + * @returns the prepared source, or undefined when no ready entry exists. + */ + takeReady(id) { + const entry = this.entries.get(id); + if (entry === void 0 || entry.phase !== "ready" || entry.source === void 0) return void 0; + this.remove(entry); + return entry.source; + } + entryFor(id, load) { + const existing = this.entries.get(id); + if (existing !== void 0) return existing; + const deferred = Promise.withResolvers(); + const entry = { + id, + result: deferred.promise, + phase: "loading" + }; + this.entries.set(id, entry); + let loading; + try { + loading = load(); + } catch (error) { + this.remove(entry); + deferred.reject(error); + return entry; + } + loading.then((source) => { + if (this.entries.get(id) === entry) { + entry.source = source; + this.makeReady(entry); + } + deferred.resolve(source); + }, (error) => { + this.remove(entry); + deferred.reject(error); + }); + return entry; + } + makeReady(entry) { + if (this.entries.get(entry.id) !== entry) return; + entry.phase = "ready"; + const settle = entry.settleReservation; + delete entry.reservationSettled; + delete entry.settleReservation; + settle?.(); + this.touch(entry); + } + remove(entry) { + if (this.entries.get(entry.id) !== entry) return; + this.entries.delete(entry.id); + const settle = entry.settleReservation; + delete entry.reservationSettled; + delete entry.settleReservation; + settle?.(); + } + touch(entry) { + this.entries.delete(entry.id); + this.entries.set(entry.id, entry); + let readyCount = 0; + for (const candidate of this.entries.values()) if (candidate.phase === "ready") readyCount += 1; + if (readyCount <= this.capacity) return; + for (const [id, candidate] of this.entries) { + if (candidate.phase !== "ready") continue; + this.entries.delete(id); + return; + } + } +}; +/** +* Give a queued observer a prompt cancellation view without cancelling shared work. +* @param operation - shared operation whose settlement remains authoritative. +* @param signal - observer-local cancellation signal. +* @param started - whether the operation has crossed its cancellation cutoff. +* @returns the operation result or the observer's prompt cancellation. +*/ +function observeQueuedAbort(operation, signal, started = () => false) { + return new Promise((resolve, reject) => { + let settled = false; + const finish = (callback) => { + if (settled) return; + settled = true; + signal.removeEventListener("abort", onAbort); + callback(); + }; + const onAbort = () => { + if (started()) return; + finish(() => { + try { + signal.throwIfAborted(); + } catch (reason) { + rejectObservation(reject, reason); + return; + } + /* v8 ignore next -- a native AbortSignal emits abort only after becoming aborted. */ + reject(/* @__PURE__ */ new Error("queued observation abort event lacked an aborted signal")); + }); + }; + signal.addEventListener("abort", onAbort, { once: true }); + operation.then((value) => { + finish(() => { + resolve(value); + }); + }, (reason) => { + finish(() => { + rejectObservation(reject, reason); + }); + }); + if (signal.aborted) onAbort(); + }); +} +/** Preserve an exact loader or AbortSignal reason, including legacy non-Error values. */ +function rejectObservation(reject, reason) { + reject(reason); +} +//#endregion +//#region lib/types/write-behind.js +/** +* Bounded per-session write batching for the shared persistence coordinator. +* @module @deepseek-ai/dsh-session-persistence/write-behind +*/ +/** +* Owns one live session's pending events, fixed batching deadline, active write, +* failure retention, and explicit quiescence barrier. +*/ +var SessionWriteBehind = class { + options; + pending = []; + timer; + active; + barrier; + deadlineExpired = false; + automaticPaused = false; + /** + * @param options - fixed scheduling policy and durable batch sink. + */ + constructor(options) { + this.options = options; + } + /** Whether this controller owns queued events or an active durable write. */ + get hasWork() { + return this.pending.length > 0 || this.active !== void 0; + } + /** + * Copy one event into the persistence-owned queue and start a fixed deadline + * when the automatic path is idle. + * @param event - frozen live event to retain independently of its producer. + */ + enqueue(event) { + const wasEmpty = this.pending.length === 0; + this.pending.push(structuredClone(event)); + if (this.barrier !== void 0) return; + if (this.automaticPaused) { + this.automaticPaused = false; + this.deadlineExpired = false; + this.armTimer(); + } else if (wasEmpty) this.armTimer(); + } + /** + * Cancel the batching wait and durably drain through a quiescent point. + * Concurrent callers join the same barrier. + * @returns a promise that rejects if the barrier's durable retry fails. + */ + flush() { + if (this.barrier !== void 0) return this.barrier; + this.cancelTimer(); + this.deadlineExpired = false; + this.automaticPaused = false; + const barrier = Promise.withResolvers(); + this.barrier = barrier.promise; + this.drainBarrier(barrier.resolve, barrier.reject); + return barrier.promise; + } + /** Cancel the current automatic deadline without draining retained work. */ + cancelAutomaticWait() { + this.cancelTimer(); + this.deadlineExpired = false; + } + /** Start the one fixed window for the current pending prefix. */ + armTimer() { + this.timer = setTimeout(() => { + this.onDeadline(); + }, this.options.maxDelayMs); + } + /** Cancel any pending automatic deadline. */ + cancelTimer() { + if (this.timer === void 0) return; + clearTimeout(this.timer); + this.timer = void 0; + } + /** Start a background write now, or remember that an active write used the budget. */ + onDeadline() { + this.timer = void 0; + if (this.active !== void 0) { + this.deadlineExpired = true; + return; + } + this.startBackground(); + } + /** Start one detached write whose failure is reported and retained. */ + startBackground() { + this.startWrite(true).then(() => { + this.continueAutomatic(); + }, () => {}); + } + /** Continue immediately after an over-budget active write, otherwise keep its timer. */ + continueAutomatic() { + if (this.barrier !== void 0 || this.pending.length === 0) return; + if (this.deadlineExpired) { + this.deadlineExpired = false; + this.startBackground(); + } + } + /** Await overlapping work, drain to quiescence, and settle the shared barrier. */ + async drainBarrier(resolve, reject) { + try { + const overlapping = this.active; + if (overlapping !== void 0) { + await Promise.allSettled([overlapping]); + this.automaticPaused = false; + } + while (this.pending.length > 0) await this.startWrite(false); + } catch (error) { + this.barrier = void 0; + reject(error); + return; + } + this.barrier = void 0; + resolve(); + } + /** Start one stable pending prefix, retaining it in order if durability fails. */ + startWrite(background) { + const batch = this.pending.splice(0); + this.cancelTimer(); + this.deadlineExpired = false; + const active = Promise.resolve().then(() => this.options.write(batch)).catch((error) => { + this.pending = batch.concat(this.pending); + this.cancelTimer(); + this.deadlineExpired = false; + this.automaticPaused = true; + if (background) this.options.reportBackgroundFailure(error); + throw error; + }).finally(() => { + this.active = void 0; + }); + this.active = active; + return active; + } +}; +//#endregion +//#region lib/types/coordinator.js +/** +* Shared buffering, serialization, adoption, repair, and disposal orchestration +* for first-party backends. Third-party backends may implement the public +* persistence seam directly. +* @module @deepseek-ai/dsh-session-persistence/coordinator +*/ +/** Default number of detached session preparations retained by a coordinator. */ +const DEFAULT_PREPARED_SESSION_CACHE_SIZE = 5; +/** Default maximum intentional wait before a live session batch starts writing. */ +const DEFAULT_WRITE_BATCH_MAX_DELAY_MS = 200; +/** Largest write batching delay accepted by Node's timer implementation. */ +const MAX_WRITE_BATCH_DELAY_MS = MAX_TIMER_DELAY_MS; +/** Durable session contents failed validation after a successful backend read. */ +var SessionPersistenceCorruptionError = class extends Error { + /** + * @param message - stable corruption context. + * @param options - original validation failure. + */ + constructor(message, options) { + super(message, options); + this.name = "SessionPersistenceCorruptionError"; + } +}; +/** +* The stored log is intact but this runtime cannot faithfully interpret it: +* the header carries an unsupported format version, or an event's type is +* unknown to this build and the event is not marked ignorable. Distinct from +* {@link SessionPersistenceCorruptionError} — nothing is damaged; the raw log +* remains readable at {@link location} when the backend keeps one artifact +* per session. +*/ +var SessionFormatUnsupportedError = class extends Error { + location; + /** + * @param message - stable reason the log cannot be interpreted, already + * including the raw-log path when one exists. + * @param location - the backend's artifact location, when one exists. + */ + constructor(message, location) { + super(message); + this.location = location; + this.name = "SessionFormatUnsupportedError"; + } +}; +/** +* Direction-aware refusal text for a stored session whose format version this +* build does not read. Shared by the coordinator's load-time check and by +* backends that must refuse BEFORE decoding version-dependent structure (a +* future format may not satisfy today's structural checks at all, and the +* user must see "upgrade the harness", never "corrupt"). +* @param id - the stored session id, for message context. +* @param version - the stored format version. +* @returns the stable refusal text, without a raw-log path suffix. +*/ +function sessionFormatVersionRefusal(id, version) { + return version > SESSION_FORMAT_VERSION ? `session "${id}" uses log format v${version}, but this harness reads only v${SESSION_FORMAT_VERSION}: the log was written by a newer harness — upgrade the harness to open it` : `session "${id}" uses log format v${version}, older than the supported v${SESSION_FORMAT_VERSION}, and this build ships no upgrade path for it`; +} +/** Collect the rejection reasons from a set of promises (none-throwing). */ +async function settledErrors(promises) { + const settled = await Promise.allSettled([...promises]); + const errors = []; + for (const result of settled) if (result.status === "rejected") errors.push(result.reason); + return errors; +} +/** Whether a live session seed reproduces a persisted prefix exactly. */ +function seedCoversPrefix(seed, prefix) { + return prefix.length <= seed.length && prefix.every((event, index) => { + const seedEvent = seed[index]; + return seedEvent !== void 0 && JSON.stringify(seedEvent) === JSON.stringify(event); + }); +} +/** Reject events from an obsolete v0 vocabulary that this build cannot replay. */ +function assertSupportedEvents(events, id) { + const legacyType = "request/header-delta"; + const legacy = events.find((event) => event.type === legacyType); + if (legacy !== void 0) throw new Error(`session "${id}" contains unsupported legacy request/header-delta event at seq ${legacy.seq}`); + const legacyModeType = "mode/set"; + const legacyMode = events.find((event) => event.type === legacyModeType); + if (legacyMode !== void 0) throw new Error(`session "${id}" contains unsupported legacy mode/set event at seq ${legacyMode.seq}`); + const fallback = events.find((event) => event.type === "request/header" && event.data.reason === "fallback"); + if (fallback !== void 0) throw new Error(`session "${id}" contains unsupported legacy request/header reason "fallback" at seq ${fallback.seq}`); +} +/** Return an object record without widening arrays into message payloads. */ +function asRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0; +} +/** Whether a record contains every required key and no key outside the optional extension set. */ +function hasOnlyKeys(record, required, optional = []) { + const allowed = [...required, ...optional]; + return Object.keys(record).every((key) => allowed.includes(key)) && required.every((key) => Object.hasOwn(record, key)); +} +/** Mint the stable import identity for a message persisted before identities existed. */ +function legacyMessageId(id, seq) { + return `legacy-message:${id}:${seq}`; +} +/** Read a replacement target while leaving malformed surface metadata to the session validator. */ +function replacementStart(event) { + const op = asRecord(event.surfaceOp); + return op?.["op"] === "replace" && typeof op["start"] === "number" ? op["start"] : void 0; +} +/** Whether one suffix event needs facts available only from the preceding stored prefix. */ +function needsLegacyPrefix(event) { + const data = asRecord(event.data); + if (event.type === "steering/message") return true; + if (data === void 0) return false; + switch (event.type) { + case "user/message": return !Object.hasOwn(data, "id") && Object.hasOwn(data, "content"); + case "assistant/message": return !Object.hasOwn(data, "message") && Object.hasOwn(data, "content"); + case "tool/result": return !Object.hasOwn(data, "message") && Object.hasOwn(data, "callId"); + default: return false; + } +} +/** Upgrade the removed steering surface event into its current user-message equivalent. */ +function migrateLegacySteeringEvent(event, id) { + if (event.type !== "steering/message") return event; + const data = asRecord(event.data); + if (data === void 0) throw new Error(`session "${id}" contains malformed pre-react-loop steering/message at seq ${event.seq}`); + const wrapped = asRecord(data["message"]); + if (wrapped !== void 0 && Number.isSafeInteger(data["turn"]) && hasOnlyKeys(data, ["turn", "message"])) return { + ...event, + type: "user/message", + data: wrapped + }; + if (!Number.isSafeInteger(data["turn"]) || !hasOnlyKeys(data, [ + "turn", + "content", + "source" + ])) throw new Error(`session "${id}" contains malformed pre-react-loop steering/message at seq ${event.seq}`); + const { turn: _turn, ...message } = data; + return { + ...event, + type: "user/message", + data: { + ...message, + id: legacyMessageId(id, event.seq), + role: "user" + } + }; +} +/** Remove the obsolete trigger after verifying the complete old turn-start envelope. */ +function migrateLegacyTurnStartEvent(event, id) { + if (event.type !== "turn/start") return event; + const data = asRecord(event.data); + if (data === void 0 || !Object.hasOwn(data, "trigger")) return event; + const trigger = asRecord(data["trigger"]); + if (!Number.isSafeInteger(data["turn"]) || data["turn"] < 1 || !hasOnlyKeys(data, ["turn", "trigger"]) || trigger === void 0 || typeof trigger["kind"] !== "string" || trigger["kind"].length === 0) throw new Error(`session "${id}" contains malformed pre-react-loop turn/start at seq ${event.seq}`); + return { + ...event, + data: { turn: data["turn"] } + }; +} +/** Upgrade an obsolete turn ending while preserving the latest-master envelope. */ +function migrateLegacyTurnEndEvent(event, id) { + if (event.type !== "turn/end") return event; + const data = asRecord(event.data); + /* v8 ignore next -- a non-record current envelope cannot match a legacy shape. */ + if (data === void 0) return event; + const malformed = () => { + throw new Error(`session "${id}" contains malformed pre-react-loop turn/end at seq ${event.seq}`); + }; + const reason = asRecord(data["reason"]); + if (!Number.isSafeInteger(data["turn"]) || data["turn"] < 1 || !hasOnlyKeys(data, ["turn", "reason"]) || reason === void 0 || typeof reason["kind"] !== "string") return malformed(); + let currentReason; + switch (reason["kind"]) { + case "completed": + case "blocked": + case "max-tokens": + case "interrupted": + if (!hasOnlyKeys(reason, ["kind"])) return malformed(); + return event; + case "aborted": + if (Object.hasOwn(reason, "reason")) return event; + if (!hasOnlyKeys(reason, ["kind"])) return malformed(); + currentReason = { + kind: "aborted", + reason: { kind: "legacy" } + }; + break; + case "disposed": + if (!hasOnlyKeys(reason, ["kind"])) return malformed(); + currentReason = { + kind: "aborted", + reason: { kind: "disposed" } + }; + break; + case "error": { + if (Object.hasOwn(reason, "error")) return event; + if (!Number.isSafeInteger(reason["step"]) || reason["step"] < 0) return malformed(); + const failure = asRecord(reason["failure"]); + if (failure !== void 0 && hasOnlyKeys(reason, [ + "kind", + "step", + "failure" + ]) && hasOnlyKeys(failure, ["message", "code"], [ + "status", + "providerRetryAfterMs", + "requestId" + ]) && typeof failure["message"] === "string" && typeof failure["code"] === "string" && (failure["status"] === void 0 || typeof failure["status"] === "number") && (failure["providerRetryAfterMs"] === void 0 || typeof failure["providerRetryAfterMs"] === "number") && (failure["requestId"] === void 0 || typeof failure["requestId"] === "string")) { + currentReason = { + kind: "error", + error: failure + }; + break; + } + if (!hasOnlyKeys(reason, reason["code"] === void 0 ? [ + "kind", + "step", + "message" + ] : [ + "kind", + "step", + "message", + "code" + ]) || typeof reason["message"] !== "string" || reason["code"] !== void 0 && typeof reason["code"] !== "string") return malformed(); + currentReason = { + kind: "error", + error: { + message: reason["message"], + code: typeof reason["code"] === "string" ? reason["code"] : "UNKNOWN" + } + }; + break; + } + default: return event; + } + return { + ...event, + data: { + ...data, + reason: currentReason + } + }; +} +/** +* Upgrade one pre-identity message event into the current wrapper shape. +* Current-looking malformed events remain untouched so validation rejects them +* instead of disguising corruption as legacy data. +*/ +function migrateLegacyMessageEvent(event, id, messageIds) { + const data = asRecord(event.data); + if (data === void 0) return event; + switch (event.type) { + case "user/message": + if (Object.hasOwn(data, "id") || Object.hasOwn(data, "role") || Object.hasOwn(data, "message") || !Object.hasOwn(data, "content") || !Object.hasOwn(data, "source")) return event; + return { + ...event, + data: { + ...data, + id: legacyMessageId(id, event.seq), + role: "user" + } + }; + case "assistant/message": { + if (Object.hasOwn(data, "message") || !Object.hasOwn(data, "content") || !Object.hasOwn(data, "provenance")) return event; + const { content, provenance, ...eventData } = data; + return { + ...event, + data: { + ...eventData, + message: { + id: legacyMessageId(id, event.seq), + role: "assistant", + content, + source: { + ...asRecord(provenance), + kind: "model" + } + } + } + }; + } + case "tool/result": { + if (Object.hasOwn(data, "message") || !Object.hasOwn(data, "callId") || !Object.hasOwn(data, "content") || !Object.hasOwn(data, "isError")) return event; + const { callId, content, isError, ...eventData } = data; + const inheritedId = replacementStart(event); + return { + ...event, + data: { + ...eventData, + message: { + id: inheritedId === void 0 ? legacyMessageId(id, event.seq) : messageIds.get(inheritedId), + role: "user", + content: [{ + type: "tool-result", + toolCallId: callId, + content, + isError + }], + source: { + kind: "tool", + callId + } + } + } + }; + } + default: return event; + } +} +/** Read the identified message carried by one validated current event. */ +function eventMessageId(event) { + const data = asRecord(event.data); + const message = event.type === "user/message" ? data : asRecord(data?.["message"]); + return typeof message?.["id"] === "string" ? message["id"] : void 0; +} +/** Materialize stored events as upgraded, validated snapshots with immutable messages. */ +function snapshotStoredEvents(events, id) { + assertSupportedEvents(events, id); + const messageIds = /* @__PURE__ */ new Map(); + return events.map((event) => { + const snapshot = snapshotSessionEvent(migrateLegacyMessageEvent(migrateLegacySteeringEvent(migrateLegacyTurnEndEvent(migrateLegacyTurnStartEvent(event, id), id), id), id, messageIds)); + const messageId = eventMessageId(snapshot); + if (messageId !== void 0) messageIds.set(snapshot.seq, messageId); + return snapshot; + }); +} +/** Upgrade and validate an exclusively owned backend result without copying it. */ +function adoptStoredEvents(events, id) { + assertSupportedEvents(events, id); + const messageIds = /* @__PURE__ */ new Map(); + for (const [index, event] of events.entries()) { + const adopted = adoptSessionEvent(migrateLegacyMessageEvent(migrateLegacySteeringEvent(migrateLegacyTurnEndEvent(migrateLegacyTurnStartEvent(event, id), id), id), id, messageIds)); + events[index] = adopted; + const messageId = eventMessageId(adopted); + if (messageId !== void 0) messageIds.set(adopted.seq, messageId); + } + return events; +} +/** +* Owns the backend-agnostic session write-path orchestration. A backend +* constructs one (`new PersistenceCoordinator(ctx, this)`), implements +* {@link PersistenceBackend}, and delegates its write/read service methods to +* the matching coordinator methods. +* +* All per-id operations are serialized (a per-id promise chain) so concurrent +* flushes / a flush racing a load never interleave storage writes. The +* constructor installs the write-path listeners, per-session retirement, and +* the backend dispose effect. +* +* @typeParam TornMarker - the backend's opaque torn-tail repair token. +*/ +var PersistenceCoordinator = class { + ctx; + backend; + /** Backend bookkeeping keyed by session id (NOT the live Session object). */ + states = /* @__PURE__ */ new Map(); + /** Lifecycle and write-behind state keyed by the exact live Session. */ + live = /* @__PURE__ */ new Map(); + /** Exact disposed lifecycles whose buffered tail is still draining. */ + retirements = /* @__PURE__ */ new Map(); + /** Shared cold reads, unpublished reservations, and completed LRU entries. */ + preparations; + /** + * Per-session serialization: every operation chains onto the prior one for the + * same id, so writes for one session never interleave. Keyed by session id. + */ + chains = /* @__PURE__ */ new Map(); + /** Resolved fixed write-batching window shared by per-session controllers. */ + writeBatchMaxDelayMs; + constructor(ctx, backend, options = { + preparedSessionCacheSize: 5, + writeBatchMaxDelayMs: 200 + }) { + this.ctx = ctx; + this.backend = backend; + if (!Number.isSafeInteger(options.preparedSessionCacheSize) || options.preparedSessionCacheSize < 1) throw new TypeError("preparedSessionCacheSize must be a positive safe integer"); + if (!Number.isSafeInteger(options.writeBatchMaxDelayMs) || options.writeBatchMaxDelayMs < 1 || options.writeBatchMaxDelayMs > MAX_WRITE_BATCH_DELAY_MS) throw new TypeError(`writeBatchMaxDelayMs must be an integer between 1 and ${MAX_WRITE_BATCH_DELAY_MS}`); + this.writeBatchMaxDelayMs = options.writeBatchMaxDelayMs; + this.preparations = new SessionPreparations(options.preparedSessionCacheSize); + this.installWritePath(); + } + /** + * Register detached session metadata for lazy creation on the first append. + * @param meta - header to snapshot; duplicate tracked or persisted ids reject. + */ + create(meta) { + const snapshot = snapshotJsonValue(meta); + if (snapshot === void 0) return Promise.reject(/* @__PURE__ */ new TypeError("session metadata must be losslessly JSON-serializable")); + if (!Number.isSafeInteger(snapshot.createdAt) || snapshot.createdAt < 0) return Promise.reject(/* @__PURE__ */ new TypeError("session metadata createdAt must be a non-negative safe integer")); + return this.serialize(snapshot.id, () => this.createCore(snapshot)); + } + async createCore(meta) { + if (this.states.has(meta.id) || this.preparations.has(meta.id)) throw new Error(`session "${meta.id}" already exists in this backend`); + if (await this.backend.loadStored(meta.id) !== void 0) throw new Error(`session "${meta.id}" already has a persisted log on disk; load/resume it instead of creating`); + this.states.set(meta.id, { + meta, + cursor: 0, + materialized: false + }); + } + /** + * Durably persist a batch of events. Honors the append-only and contiguous-seq + * contracts; rejects non-JSON-serializable `event.data`. + * @param id - the session the batch belongs to. + * @param events - the contiguous batch to persist, in seq order; materialized + * as a detached lossless-JSON snapshot at call time. + */ + async append(id, events) { + const batch = snapshotJsonValue(events); + if (batch === void 0) throw new TypeError("session event batch is not losslessly JSON-serializable because it contains non-JSON-serializable data"); + return this.serialize(id, () => this.appendCore(id, batch)); + } + async appendCore(id, events) { + assertSupportedEvents(events, id); + if (events.length === 0) return; + this.preparations.assertWritable(id); + let state = this.states.get(id); + if (state === void 0) state = await this.adopt(id); + for (const [i, event] of events.entries()) if (event.seq !== state.cursor + i) throw new Error(`append seq mismatch for "${id}": expected ${state.cursor + i} at index ${i}, got ${event.seq}`); + await this.backend.appendBatch(state.meta, events, state.materialized); + state.materialized = true; + state.cursor += events.length; + this.preparations.invalidate(id); + } + /** + * Prepare and reserve the exact unpublished Session used by resume. + * Revision retries converge once the durable log remains unchanged for one + * read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to prepare. + * @param signal - optional cancellation for reading and repair. + * @returns an owned preparation released after publication or rollback. + */ + async prepare(id, signal) { + for (;;) { + await this.waitForRetirement(id, signal); + if (this.ctx.sessions.get(id) !== void 0) throw new Error(`cannot prepare session "${id}" while it is live`); + const reservation = await this.preparations.reserve(id, () => this.serialize(id, () => this.prepareCore(id)), (source) => this.serialize(id, () => this.commitPrepared(source), signal), signal); + if (reservation === void 0) continue; + if (this.ctx.sessions.get(id) !== void 0) { + this.preparations.release(reservation, false); + throw new Error(`cannot prepare session "${id}" while it is live`); + } + return SessionPreparation.create(reservation.source.session, { release: () => { + this.preparations.release(reservation, reservation.state.owner === void 0 && reservation.source.session.events.length === reservation.source.sessionLength); + } }); + } + } + /** + * Commit recovery and return its immutable logical view without publication. + * Revision retries converge once the durable log remains unchanged for one + * read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to load. + * @returns prepared header and balanced events. + */ + async load(id) { + for (;;) { + await this.waitForRetirement(id); + const live = this.ctx.sessions.get(id); + if (live !== void 0) return this.loadLiveSnapshot(live); + const reservation = await this.preparations.reserve(id, () => this.serialize(id, () => this.prepareCore(id)), (source) => this.serialize(id, () => this.commitPrepared(source))); + if (reservation === void 0) continue; + const attached = this.ctx.sessions.get(id); + if (attached !== void 0) { + this.preparations.discard(reservation); + return this.loadLiveSnapshot(attached); + } + this.preparations.discard(reservation); + return reservation.source.inspection; + } + } + /** + * Inspect a logical session without publishing it or committing recovery. + * A stale ready source is reloaded. A source already committing or reserved + * for resume remains exclusive, and inspection may borrow its immutable view. + * Revision retries converge once the log is stable for one read/check round + * trip; continuous external writers may delay completion. + * @param id - persisted session to inspect. + * @param signal - optional cancellation for preparation work. + * @returns immutable prepared metadata and events; a live view may have an open turn. + */ + async inspect(id, signal) { + for (;;) { + signal?.throwIfAborted(); + if (this.retirements.has(id)) await this.waitForRetirement(id, signal); + const live = this.ctx.sessions.get(id); + if (live !== void 0) return this.inspectLive(live); + try { + const source = await this.preparations.inspect(id, () => this.serialize(id, () => this.prepareCore(id)), signal); + const attached = this.ctx.sessions.get(id); + if (attached !== void 0) return this.inspectLive(attached); + const current = await this.serialize(id, () => this.isPreparedSourceCurrent(source, signal), signal); + const published = this.ctx.sessions.get(id); + if (published !== void 0) return this.inspectLive(published); + if (current) return source.inspection; + if (this.preparations.discardReady(id, source) === "retained") return source.inspection; + } catch (error) { + signal?.throwIfAborted(); + const attached = this.ctx.sessions.get(id); + if (attached !== void 0) return this.inspectLive(attached); + throw error; + } + } + } + /** + * Read the stored events from `fromSeq` onward, detached and non-mutating + * (the read-from-seq primitive behind the service's `readFrom`). Runs on + * the same per-id chain as writes; a backend with the seek-capable + * {@link PersistenceBackend.loadStoredFrom} hook reads only the suffix, + * every other backend reads its stored prefix and skips forward here. + * @param id - persisted session to read. + * @param fromSeq - first event seq to include; a non-negative safe integer. + * @param signal - optional cancellation for queued and backend read work. + * @returns stored header and the valid stored events with `seq >= fromSeq`. + */ + readFrom(id, fromSeq, signal) { + if (!Number.isSafeInteger(fromSeq) || fromSeq < 0) return Promise.reject(/* @__PURE__ */ new TypeError(`readFrom fromSeq must be a non-negative safe integer, got ${String(fromSeq)}`)); + const retired = Promise.resolve(this.retirements.get(id)); + return (signal === void 0 ? retired : observeQueuedAbort(retired, signal, () => false)).then(() => this.serialize(id, () => this.readFromCore(id, fromSeq, signal), signal)); + } + async readFromCore(id, fromSeq, signal) { + signal?.throwIfAborted(); + if (this.backend.loadStoredFrom !== void 0) { + let suffix; + try { + suffix = await this.backend.loadStoredFrom(id, fromSeq, signal); + } catch (error) { + if (signal?.aborted) signal.throwIfAborted(); + throw error; + } + signal?.throwIfAborted(); + if (suffix === void 0) throw new Error(`session "${id}" not found`); + this.assertStoredId(id, suffix.meta); + this.assertVersion(suffix.meta); + if (suffix.events.some(needsLegacyPrefix)) { + const whole = await this.readStoredPrefix(id, signal); + return { + meta: whole.meta, + events: whole.events.filter((event) => event.seq >= fromSeq) + }; + } + const events = snapshotStoredEvents(suffix.events, id); + this.assertEventsSupported(suffix.meta, events); + return { + meta: structuredClone(suffix.meta), + events + }; + } + const whole = await this.readStoredPrefix(id, signal); + return { + meta: whole.meta, + events: whole.events.slice(fromSeq) + }; + } + /** Read one detached physical prefix without logical recovery or caching. */ + async readStoredPrefix(id, signal) { + signal?.throwIfAborted(); + const stored = await this.backend.loadStored(id, signal); + signal?.throwIfAborted(); + if (stored === void 0) throw new Error(`session "${id}" not found`); + this.assertStoredId(id, stored.meta); + this.assertVersion(stored.meta); + const events = snapshotStoredEvents(stored.events, id); + this.assertEventsSupported(stored.meta, events); + return { + meta: structuredClone(stored.meta), + events + }; + } + /** Read, repair in memory, validate, and freeze one cold source once. */ + async prepareCore(id) { + const stored = await this.backend.loadStored(id); + if (stored === void 0) throw new Error(`session "${id}" not found`); + try { + const { meta, events, revision, tornMarker } = stored; + this.assertStoredId(id, meta); + this.assertVersion(meta); + const storedEvents = adoptStoredEvents(events, id); + this.assertEventsSupported(meta, storedEvents); + const closers = interruptedTurnClosers(storedEvents).map(adoptSessionEvent); + const balanced = [...storedEvents, ...closers]; + const session = this.ctx.sessions.prepare(id, { + seed: balanced, + meta, + seedSource: "persistence" + }); + return { + inspection: Object.freeze({ + meta: session.header, + events: Object.freeze(balanced) + }), + session, + revision, + sessionLength: session.events.length, + tornMarker, + closers + }; + } catch (error) { + if (error instanceof SessionFormatUnsupportedError) throw error; + throw new SessionPersistenceCorruptionError(`stored session "${id}" failed validation: ${String(error)}`, { cause: error }); + } + } + /** Commit one prepared repair and establish its ownerless durable cursor. */ + async commitPrepared(source) { + const id = source.inspection.meta.id; + const cursor = source.inspection.events.length; + const existing = this.states.get(id); + if (existing?.owner !== void 0) throw new Error(`session "${id}" already has a live persistence owner`); + if (!await this.isPreparedSourceCurrent(source)) return void 0; + if (source.tornMarker !== void 0 || source.closers.length > 0) { + await this.backend.commitRepair(source.inspection.meta, source.tornMarker, source.closers); + return; + } + const state = existing ?? { + meta: source.inspection.meta, + cursor, + materialized: true + }; + state.meta = source.inspection.meta; + state.cursor = cursor; + state.materialized = true; + this.states.set(id, state); + return { + source, + state + }; + } + /** Whether one cached source still names the current durable log revision. */ + async isPreparedSourceCurrent(source, signal) { + return await this.backend.readStoredRevision(source.inspection.meta.id, signal) === source.revision; + } + /** Return one durable immutable view of an already-live Session. */ + async loadLiveSnapshot(session) { + const events = session.events; + await this.flush(session); + const state = this.states.get(session.id); + /* v8 ignore next -- successful flush always publishes this live session's durable state */ + if (state === void 0) throw new Error(`session "${session.id}" lost persistence state during load`); + if (events.length === 0) throw new Error(`session "${session.id}" not found`); + if (interruptedTurnClosers(events).length > 0) throw new Error(`cannot load session "${session.id}" while its live turn is open; use the live Session or wait for the turn to close`); + return Object.freeze({ + meta: state.meta, + events + }); + } + /** Borrow one immutable view from an already-live Session. */ + inspectLive(session) { + return Object.freeze({ + meta: session.header, + events: session.events + }); + } + /** Await one retiring lifecycle with caller cancellation. */ + waitForRetirement(id, signal) { + const retired = Promise.resolve(this.retirements.get(id)); + return signal === void 0 ? retired : observeQueuedAbort(retired, signal, () => false); + } + /** + * Run `op` after any in-flight operation for the same session id, so writes for + * one session never interleave. Errors do not poison the chain. NOTE: serialized + * public methods must NOT call each other (deadlock); they call the unserialized + * `*Core` helpers instead. + */ + serialize(id, op, signal) { + const prior = this.chains.get(id) ?? Promise.resolve(); + let started = false; + const run = () => { + signal?.throwIfAborted(); + started = true; + return op(); + }; + const next = prior.then(run, run); + const tail = next.then(() => void 0, () => void 0); + this.chains.set(id, tail); + tail.then(() => { + if (this.chains.get(id) === tail) this.chains.delete(id); + }); + return signal === void 0 ? next : observeQueuedAbort(next, signal, () => started); + } + /** Build a state for a session discovered in storage but not yet in memory. */ + async adopt(id) { + for (;;) { + const source = this.preparations.takeReady(id) ?? await this.prepareCore(id); + const committed = await this.commitPrepared(source); + if (committed !== void 0) return committed.state; + } + } + assertVersion(meta) { + if (meta.version === SESSION_FORMAT_VERSION) return; + throw this.unsupported(meta, sessionFormatVersionRefusal(meta.id, meta.version)); + } + /** + * Refuse a log containing an event type this build does not know, unless the + * writer marked the event ignorable: an unrecognized required event may + * change how the rest of the log must be interpreted, so silently skipping + * it would reconstruct a wrong session (the envelope contract on + * `SessionEvent.ignorable`). Runs on NORMALIZED events — after + * `snapshotStoredEvents`/`adoptStoredEvents` has upgraded the legacy shapes + * this build still reads and rejected the ones it does not, so those keep + * their specific diagnostics. + */ + assertEventsSupported(meta, events) { + for (const event of events) { + if (KNOWN_SESSION_EVENT_TYPES.has(event.type) || event.ignorable === true) continue; + throw this.unsupported(meta, `session "${meta.id}" contains event type "${event.type}" (seq ${event.seq}) unknown to this harness and not marked ignorable; refusing to interpret the log — it was likely written by a newer harness`); + } + } + /** Build a format refusal that points at the raw artifact when the backend has one. */ + unsupported(meta, reason) { + const location = this.backend.locate?.(meta); + return new SessionFormatUnsupportedError(location === void 0 ? reason : `${reason} (raw log: ${location.path})`, location); + } + /** Reject backend metadata that is not bound to the requested session id. */ + assertStoredId(id, meta) { + if (meta.id !== id) throw new Error(`stored session identity mismatch: requested "${id}", header contains "${meta.id}"`); + } + installWritePath() { + const ctx = this.ctx; + ctx.effect(() => async () => { + let disposeError; + try { + const errors = await settledErrors([...this.live.keys()].map((session) => this.flush(session))); + while (this.chains.size > 0) await Promise.allSettled([...this.chains.values()]); + if (errors.length > 0) throw new AggregateError(errors, `${this.backend.name} dispose failed`); + } catch (error) { + disposeError = error; + throw error; + } finally { + try { + await this.backend.close?.(); + } catch (closeError) { + /* v8 ignore start -- close failure racing disposal is a defensive teardown edge */ + if (disposeError === void 0) throw closeError; + } + } + }, `${this.backend.name} write path`); + ctx.on("session/created", (session) => { + this.initFor(session); + }); + ctx.on("session/event", (session, event) => { + this.initFor(session).writes.enqueue(event); + }); + ctx.on("session/flush", (session) => this.flush(session)); + ctx.on("session/disposed", (session) => { + this.retire(session); + }); + for (const session of ctx.sessions.list()) this.initFor(session); + } + /** Start and observe one disposed session's final drain. */ + retire(session) { + if (!this.live.has(session)) return; + const retirement = this.retireCore(session); + this.retirements.set(session.id, retirement); + const forget = () => { + if (this.retirements.get(session.id) === retirement) this.retirements.delete(session.id); + }; + retirement.then(forget, forget); + retirement.catch((error) => { + this.ctx.logger.warn(`${this.backend.name}: session "${session.id}" retirement failed: ${String(error)}`); + }); + } + /** Drain and release state owned by one exact disposed Session lifecycle. */ + async retireCore(session) { + await this.flush(session); + const id = session.header.id; + await this.serialize(id, () => { + this.live.delete(session); + if (this.states.get(id)?.owner === session) this.states.delete(id); + }); + } + /** Return the one lifecycle controller for a live session, creating it if needed. */ + initFor(session) { + const existing = this.live.get(session); + if (existing) return existing; + const reservation = this.preparations.reservationFor(session); + if (reservation !== void 0) { + const restored = this.attachPrepared(session, reservation); + this.live.set(session, restored); + return restored; + } + const seed = session.events.map((e) => structuredClone(e)); + const live = { + init: Promise.resolve(), + writes: this.createWriteBehind(session, () => live.init) + }; + this.live.set(session, live); + live.init = this.serialize(session.header.id, () => this.onCreated(session, seed)); + live.init.catch(() => {}); + return live; + } + /** Bind one exact prepared Session and persist only its unpublished suffix. */ + attachPrepared(session, reservation) { + const { source, state } = reservation; + if (source.session !== session || state.owner !== void 0 || state.cursor !== source.inspection.events.length || session.firstLiveSeq !== state.cursor) throw new Error(`session "${session.id}" preparation no longer matches its persistence state`); + const suffix = session.events.slice(state.cursor).map((event) => structuredClone(event)); + this.preparations.attach(reservation); + state.owner = session; + const live = { + init: Promise.resolve(), + writes: this.createWriteBehind(session, () => live.init) + }; + if (suffix.length > 0) { + live.init = this.serialize(session.id, () => this.appendCore(session.id, suffix)); + live.init.catch(() => {}); + } + return live; + } + /** + * Whether a live session's `seed` reproduces the first `cursor` persisted + * events. A `cursor` of 0 (nothing persisted yet) trivially matches. Used when + * a live session claims ownerless state left by a prior `load()`/`create()`. + */ + async seedMatchesPersisted(id, seed, cursor) { + if (cursor === 0) return true; + const stored = await this.backend.loadStored(id); + /* v8 ignore next -- a cursor > 0 means the session was materialized, so it exists */ + if (stored === void 0) return false; + this.assertStoredId(id, stored.meta); + return seedCoversPrefix(seed, snapshotStoredEvents(stored.events, id).slice(0, cursor)); + } + /** + * On session/created: sync the backend's in-memory state to a live Session. + * + * Cases, by whether this backend tracks the id and whether an artifact exists: + * 1. Already tracked → no-op (or claim ownerless state if the seed matches, + * or reclaim a truly-abandoned id, else reject as a collision). + * 2. Not tracked, an artifact EXISTS at the same cwd and is a seq-aligned + * PREFIX of the live events → ADOPT it, persisting any live suffix. + * 3. Not tracked, an artifact EXISTS at another cwd or is NOT a prefix → + * REJECT (collision). + * 4. Not tracked and NO artifact → a genuinely new session: register meta + * (lazy) and persist its seed once. + */ + async onCreated(session, seed) { + const id = session.header.id; + const tracked = this.states.get(id); + if (tracked !== void 0) { + /* v8 ignore next -- initFor dedupes per session object; same-object re-entry can't occur */ + if (tracked.owner === session) return; + if (tracked.owner === void 0) { + if (tracked.meta.cwd !== session.header.cwd) throw new Error(`session "${id}" is already persisted at a different cwd (persisted: ${String(tracked.meta.cwd)}, live: ${String(session.header.cwd)}) (id collision)`); + if (!await this.seedMatchesPersisted(id, seed, tracked.cursor)) throw new Error(`session "${id}" is already persisted with ${tracked.cursor} event(s) that do not match this live session (id collision)`); + tracked.owner = session; + const suffix = seed.slice(tracked.cursor); + if (suffix.length > 0) await this.appendCore(id, suffix); + return; + } + const owner = this.live.get(tracked.owner); + if (!tracked.materialized && !owner?.writes.hasWork) this.states.delete(id); + else throw new Error(`session "${id}" is already bound to a different live session in this backend (id collision)`); + } + const live = await this.backend.loadStored(id); + if (live !== void 0) { + await this.adoptLivePrefix(session, seed, live); + return; + } + const meta = { ...session.header }; + await this.createCore(meta); + const created = this.states.get(id); + /* v8 ignore next -- create() always sets the state for the id */ + if (created !== void 0) created.owner = session; + if (seed.length > 0) await this.appendCore(id, seed); + } + /** + * Adopt a stored prefix as a live session's history (HMR/reload): verify the + * seed covers the stored prefix, truncate any torn tail (NOT the open turn — + * the live Session is still the authority), bind ownership, and persist the + * live suffix that was ahead of the stored prefix. + */ + async adoptLivePrefix(session, seed, stored) { + const { meta, events, tornMarker } = stored; + this.assertStoredId(session.header.id, meta); + if (meta.cwd !== session.header.cwd) throw new Error(`session "${session.header.id}" is already persisted at a different cwd (persisted: ${String(meta.cwd)}, live: ${String(session.header.cwd)}) (id collision)`); + this.assertVersion(meta); + const storedEvents = snapshotStoredEvents(events, session.header.id); + this.assertEventsSupported(meta, storedEvents); + if (!seedCoversPrefix(seed, storedEvents)) throw new Error(`session "${session.header.id}" already has a persisted log on disk that does not match this live session (id collision)`); + if (tornMarker !== void 0) await this.backend.commitRepair(meta, tornMarker, []); + this.states.set(session.header.id, { + meta: { ...meta }, + cursor: storedEvents.length, + materialized: true, + owner: session + }); + const suffix = seed.slice(storedEvents.length); + if (suffix.length > 0) await this.appendCore(session.header.id, suffix); + } + async flush(session) { + const live = this.initFor(session); + live.writes.cancelAutomaticWait(); + try { + await live.init; + } catch (error) { + live.writes.cancelAutomaticWait(); + throw error; + } + await live.writes.flush(); + } + /** Build one package-private write controller around initialization and id serialization. */ + createWriteBehind(session, ready) { + return new SessionWriteBehind({ + maxDelayMs: this.writeBatchMaxDelayMs, + write: async (batch) => { + await ready(); + await this.serialize(session.header.id, () => this.appendLiveBatch(session.header.id, batch)); + }, + reportBackgroundFailure: (error) => { + this.ctx.logger.warn(`${this.backend.name}: background write for session "${session.id}" failed (buffered events retained): ${String(error)}`); + } + }); + } + /** Append one controller-owned prefix after filtering events initialization already stored. */ + async appendLiveBatch(id, batch) { + /* v8 ignore next -- state is always set by the awaited initialization */ + const cursor = this.states.get(id)?.cursor ?? 0; + const fresh = batch.filter((e) => e.seq >= cursor); + await this.appendCore(id, fresh); + } +}; +//#endregion +//#region lib/types/index.js +/** +* Durable session-persistence Service Definition (`ctx.sessionPersistence`). Backends store +* {@link SessionEvent}s as the event-sourced log and carry non-replayable +* {@link SessionHeader} metadata separately. +* @module @deepseek-ai/dsh-session-persistence +*/ +/** +* Durable append-only session storage. Implementations preserve contiguous, +* losslessly JSON-serializable events; {@link append} resolves only after +* durability, and {@link load} balances a complete interrupted tail without +* rewriting committed events. +*/ +var SessionPersistence = class extends Service { + constructor(ctx) { + super(ctx, "sessionPersistence"); + } + /** + * Read a session's backend-owned artifact text verbatim — the exact durable + * bytes the backend wrote (decoded from its physical encoding, e.g. a + * decompressed JSONL). The returned `content` is the raw text, not a + * reconstruction from parsed events, so it preserves backend-specific + * serialization (chunk packing, key order, line breaks). Callers first test + * {@link supportsRawArtifacts}; `undefined` then means only that the requested + * session has no materialized artifact. + * @param _id - the persisted session to read (unused by the default: no + * per-session artifact). + * @param signal - optional cancellation for backend read work. + * @returns the raw artifact plus its parsed header, or `undefined` when the + * session is absent. + * @throws when this backend does not expose per-session raw artifacts. + */ + readRaw(_id, signal) { + if (signal?.aborted === true) return Promise.reject(signal.reason instanceof Error ? signal.reason : /* @__PURE__ */ new Error("aborted")); + return Promise.reject(/* @__PURE__ */ new Error("this session persistence backend does not expose raw artifacts")); + } + /** + * Prepare the exact unpublished Session used by resume. Implementations may + * reuse object graphs retained by an earlier {@link inspect} after confirming + * their durable revision is still current; disposal releases an unpublished + * reservation. Revision retries require the durable log to remain unchanged + * for one read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to prepare. + * @param signal - optional cancellation for preparation work. + * @returns one owned unpublished Session preparation. + */ + async prepare(id, signal) { + signal?.throwIfAborted(); + const loaded = await this.load(id); + signal?.throwIfAborted(); + const sessions = this.ctx.get("sessions"); + if (sessions === void 0) throw new Error("cannot prepare a session: SessionStore is not configured"); + return SessionPreparation.create(sessions.prepare(id, { + seed: loaded.events.map((event) => structuredClone(event)), + meta: structuredClone(loaded.meta), + seedSource: "persistence" + })); + } +}; +//#endregion +export { DEFAULT_PREPARED_SESSION_CACHE_SIZE, DEFAULT_WRITE_BATCH_MAX_DELAY_MS, MAX_WRITE_BATCH_DELAY_MS, PersistenceCoordinator, SessionFormatUnsupportedError, SessionPersistence, SessionPersistence as default, SessionPersistenceCorruptionError, SessionPersistenceRevision, sessionFormatVersionRefusal }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/invariant.js new file mode 100644 index 0000000..6503792 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-session-persistence`. +* @module @deepseek-ai/dsh-session-persistence/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session-persistence"; +/** Cordis companion plugin name. */ +const name = "session-persistence-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: persistence correctness requires backend round-trip and crash-tail tests; +* this package exposes no continuously observable in-process relation. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/coordinator.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/coordinator.d.ts new file mode 100644 index 0000000..04301ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/coordinator.d.ts @@ -0,0 +1,348 @@ +/** + * Shared buffering, serialization, adoption, repair, and disposal orchestration + * for first-party backends. Third-party backends may implement the public + * persistence seam directly. + * @module @deepseek-ai/dsh-session-persistence/coordinator + */ +import { Context } from '@deepseek-ai/cordis'; +import { SessionPreparation } from '@deepseek-ai/dsh-session'; +import type { SessionEvent, SessionId, SessionHeader } from '@deepseek-ai/dsh-session'; +import type { SessionInspection, SessionLocation } from './index.ts'; +import type { SessionPersistenceRevision } from './revision.ts'; +/** Default number of detached session preparations retained by a coordinator. */ +export declare const DEFAULT_PREPARED_SESSION_CACHE_SIZE = 5; +/** Default maximum intentional wait before a live session batch starts writing. */ +export declare const DEFAULT_WRITE_BATCH_MAX_DELAY_MS = 200; +/** Largest write batching delay accepted by Node's timer implementation. */ +export declare const MAX_WRITE_BATCH_DELAY_MS = 2147483647; +/** Durable session contents failed validation after a successful backend read. */ +export declare class SessionPersistenceCorruptionError extends Error { + /** + * @param message - stable corruption context. + * @param options - original validation failure. + */ + constructor(message: string, options: ErrorOptions); +} +/** + * The stored log is intact but this runtime cannot faithfully interpret it: + * the header carries an unsupported format version, or an event's type is + * unknown to this build and the event is not marked ignorable. Distinct from + * {@link SessionPersistenceCorruptionError} — nothing is damaged; the raw log + * remains readable at {@link location} when the backend keeps one artifact + * per session. + */ +export declare class SessionFormatUnsupportedError extends Error { + readonly location?: SessionLocation | undefined; + /** + * @param message - stable reason the log cannot be interpreted, already + * including the raw-log path when one exists. + * @param location - the backend's artifact location, when one exists. + */ + constructor(message: string, location?: SessionLocation | undefined); +} +/** + * Direction-aware refusal text for a stored session whose format version this + * build does not read. Shared by the coordinator's load-time check and by + * backends that must refuse BEFORE decoding version-dependent structure (a + * future format may not satisfy today's structural checks at all, and the + * user must see "upgrade the harness", never "corrupt"). + * @param id - the stored session id, for message context. + * @param version - the stored format version. + * @returns the stable refusal text, without a raw-log path suffix. + */ +export declare function sessionFormatVersionRefusal(id: string, version: number): string; +/** Coordinator policy supplied by a concrete persistence backend. */ +export interface PersistenceCoordinatorOptions { + /** Maximum completed unpublished preparations retained for reuse. */ + readonly preparedSessionCacheSize: number; + /** Maximum intentional batching wait after an idle live queue receives work. */ + readonly writeBatchMaxDelayMs: number; +} +/** + * A stored session's header, valid contiguous event prefix, source-qualified + * revision, and optional opaque torn-tail marker. The revision identifies the + * exact detached prefix. The coordinator only checks marker presence and + * returns its value to {@link PersistenceBackend.commitRepair}; each backend + * owns the marker type. + */ +export interface StoredPrefix { + meta: SessionHeader; + events: SessionEvent[]; + /** Revision observed for exactly this detached prefix. */ + revision: SessionPersistenceRevision; + tornMarker?: TornMarker; +} +/** + * A stored session's header plus the events at or past a requested seq — the + * return shape of the optional seek-capable + * {@link PersistenceBackend.loadStoredFrom} hook. Non-mutating reads carry no + * torn marker: there is nothing to repair. + */ +export interface StoredSuffix { + meta: SessionHeader; + events: SessionEvent[]; +} +/** + * The storage contract between {@link PersistenceCoordinator} and a concrete + * backend: the minimal set of durable primitives the orchestration calls. A + * backend implements these (over files, rows, an object store, …); the + * coordinator supplies everything else (buffering, serialization, cursors, + * adoption, crash repair sequencing, dispose quiescence). + * + * @typeParam TornMarker - the backend's opaque torn-tail repair token (see + * {@link StoredPrefix}). The coordinator treats it as fully opaque. + */ +export interface PersistenceBackend { + /** Human-readable backend name, used in the dispose-failure AggregateError. */ + readonly name: string; + /** + * Read a stored prefix by id, scanning every backend storage scope. Returns + * `undefined` if no stored artifact exists. Returned metadata must identify + * `id` before repair or state publication. Used by resume/load, live adoption, + * and — via `!== undefined` — the create-collision probe. The returned + * `tornMarker` is present iff there is a torn tail to truncate. Every header + * and event graph must be fresh, mutually unaliased, and unretained by the + * backend because preparation freezes and publishes them in place. The + * returned revision must identify exactly those values and use the same + * representation as {@link readStoredRevision}. + * @param id - persisted session id to resolve. + * @param signal - optional cancellation for backend read work. + */ + loadStored(id: SessionId, signal?: AbortSignal): Promise | undefined>; + /** + * Read the current source-qualified revision for one stored session without + * loading its event log. Returns `undefined` when the identity is absent. + * @param id - persisted session id to observe. + * @param signal - optional cancellation for backend read work. + */ + readStoredRevision(id: SessionId, signal?: AbortSignal): Promise; + /** + * Optional seek-capable suffix read behind the service's `readFrom`: return + * the header plus the stored events with `seq >= fromSeq` without reading + * the whole log. A backend whose medium can address events by seq (SQLite) + * implements this so `readFrom` scales with the suffix; sequential backends + * omit it and the coordinator falls back to {@link loadStored} plus a + * forward skip. Non-mutating (no truncation, no closers). Validation of the + * region strictly below `fromSeq` is limited to seq contiguity — the + * service contract scopes this read to the suffix — unless that suffix + * contains a supported legacy shape whose normalization needs earlier + * message-identity facts, in which case the coordinator falls back + * to the complete stored prefix. + * Unknown-type refusal follows the same suffix scope: a seek-capable + * backend's `readFrom` checks only the returned suffix, while the + * sequential fallback parses the whole artifact and refuses on an unknown + * required event anywhere in it — over-refusal on the sequential side is + * accepted rather than widening the seek read. + * @param id - persisted session id to resolve. + * @param fromSeq - first event seq to include (non-negative safe integer, + * validated by the coordinator before this hook runs). + * @param signal - optional cancellation for backend read work. + */ + loadStoredFrom?(id: SessionId, fromSeq: number, signal?: AbortSignal): Promise; + /** + * Durably append a CONTIGUOUS batch, lazily materializing the session first + * when `!isMaterialized`. The materialize-write and the first event batch MUST + * commit ATOMICALLY (a crash between them must not leave a materialized-but- + * empty session). Returns once the batch is durable. + */ + appendBatch(meta: SessionHeader, events: readonly SessionEvent[], isMaterialized: boolean): Promise; + /** + * Make a crash repair durable: truncate the torn tail (iff + * `tornMarker !== undefined`) and append `closers` (iff any). NOT required to + * be atomic — a file backend may truncate-then-append in two fsync'd steps. + * Used by load (truncate + synthetic closers) and by live-adoption (truncate + * only, `closers = []`). + */ + commitRepair(meta: SessionHeader, tornMarker: TornMarker | undefined, closers: readonly SessionEvent[]): Promise; + /** + * List all stored (materialized) sessions' metadata. + * @param signal - optional cancellation for backend listing work. + */ + list(signal?: AbortSignal): Promise; + /** + * Optional side-effect-free artifact locator, used to point refusal + * diagnostics ({@link SessionFormatUnsupportedError}) at the raw log. + * Backends without one artifact per session omit it or return `undefined`. + * @param meta - the header whose artifact is requested. + */ + locate?(meta: SessionHeader): SessionLocation | undefined; + /** + * Optional lifecycle teardown (e.g. close a database handle). Awaited by the + * coordinator's dispose effect AFTER the quiescence drain. A stateless file + * backend omits it. + */ + close?(): Promise; +} +/** + * Owns the backend-agnostic session write-path orchestration. A backend + * constructs one (`new PersistenceCoordinator(ctx, this)`), implements + * {@link PersistenceBackend}, and delegates its write/read service methods to + * the matching coordinator methods. + * + * All per-id operations are serialized (a per-id promise chain) so concurrent + * flushes / a flush racing a load never interleave storage writes. The + * constructor installs the write-path listeners, per-session retirement, and + * the backend dispose effect. + * + * @typeParam TornMarker - the backend's opaque torn-tail repair token. + */ +export declare class PersistenceCoordinator { + private ctx; + private backend; + /** Backend bookkeeping keyed by session id (NOT the live Session object). */ + private states; + /** Lifecycle and write-behind state keyed by the exact live Session. */ + private live; + /** Exact disposed lifecycles whose buffered tail is still draining. */ + private retirements; + /** Shared cold reads, unpublished reservations, and completed LRU entries. */ + private readonly preparations; + /** + * Per-session serialization: every operation chains onto the prior one for the + * same id, so writes for one session never interleave. Keyed by session id. + */ + private chains; + /** Resolved fixed write-batching window shared by per-session controllers. */ + private readonly writeBatchMaxDelayMs; + constructor(ctx: Context, backend: PersistenceBackend, options?: PersistenceCoordinatorOptions); + /** + * Register detached session metadata for lazy creation on the first append. + * @param meta - header to snapshot; duplicate tracked or persisted ids reject. + */ + create(meta: SessionHeader): Promise; + private createCore; + /** + * Durably persist a batch of events. Honors the append-only and contiguous-seq + * contracts; rejects non-JSON-serializable `event.data`. + * @param id - the session the batch belongs to. + * @param events - the contiguous batch to persist, in seq order; materialized + * as a detached lossless-JSON snapshot at call time. + */ + append(id: SessionId, events: readonly SessionEvent[]): Promise; + private appendCore; + /** + * Prepare and reserve the exact unpublished Session used by resume. + * Revision retries converge once the durable log remains unchanged for one + * read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to prepare. + * @param signal - optional cancellation for reading and repair. + * @returns an owned preparation released after publication or rollback. + */ + prepare(id: SessionId, signal?: AbortSignal): Promise; + /** + * Commit recovery and return its immutable logical view without publication. + * Revision retries converge once the durable log remains unchanged for one + * read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to load. + * @returns prepared header and balanced events. + */ + load(id: SessionId): Promise; + /** + * Inspect a logical session without publishing it or committing recovery. + * A stale ready source is reloaded. A source already committing or reserved + * for resume remains exclusive, and inspection may borrow its immutable view. + * Revision retries converge once the log is stable for one read/check round + * trip; continuous external writers may delay completion. + * @param id - persisted session to inspect. + * @param signal - optional cancellation for preparation work. + * @returns immutable prepared metadata and events; a live view may have an open turn. + */ + inspect(id: SessionId, signal?: AbortSignal): Promise; + /** + * Read the stored events from `fromSeq` onward, detached and non-mutating + * (the read-from-seq primitive behind the service's `readFrom`). Runs on + * the same per-id chain as writes; a backend with the seek-capable + * {@link PersistenceBackend.loadStoredFrom} hook reads only the suffix, + * every other backend reads its stored prefix and skips forward here. + * @param id - persisted session to read. + * @param fromSeq - first event seq to include; a non-negative safe integer. + * @param signal - optional cancellation for queued and backend read work. + * @returns stored header and the valid stored events with `seq >= fromSeq`. + */ + readFrom(id: SessionId, fromSeq: number, signal?: AbortSignal): Promise<{ + meta: SessionHeader; + events: SessionEvent[]; + }>; + private readFromCore; + /** Read one detached physical prefix without logical recovery or caching. */ + private readStoredPrefix; + /** Read, repair in memory, validate, and freeze one cold source once. */ + private prepareCore; + /** Commit one prepared repair and establish its ownerless durable cursor. */ + private commitPrepared; + /** Whether one cached source still names the current durable log revision. */ + private isPreparedSourceCurrent; + /** Return one durable immutable view of an already-live Session. */ + private loadLiveSnapshot; + /** Borrow one immutable view from an already-live Session. */ + private inspectLive; + /** Await one retiring lifecycle with caller cancellation. */ + private waitForRetirement; + /** + * Run `op` after any in-flight operation for the same session id, so writes for + * one session never interleave. Errors do not poison the chain. NOTE: serialized + * public methods must NOT call each other (deadlock); they call the unserialized + * `*Core` helpers instead. + */ + private serialize; + /** Build a state for a session discovered in storage but not yet in memory. */ + private adopt; + private assertVersion; + /** + * Refuse a log containing an event type this build does not know, unless the + * writer marked the event ignorable: an unrecognized required event may + * change how the rest of the log must be interpreted, so silently skipping + * it would reconstruct a wrong session (the envelope contract on + * `SessionEvent.ignorable`). Runs on NORMALIZED events — after + * `snapshotStoredEvents`/`adoptStoredEvents` has upgraded the legacy shapes + * this build still reads and rejected the ones it does not, so those keep + * their specific diagnostics. + */ + private assertEventsSupported; + /** Build a format refusal that points at the raw artifact when the backend has one. */ + private unsupported; + /** Reject backend metadata that is not bound to the requested session id. */ + private assertStoredId; + private installWritePath; + /** Start and observe one disposed session's final drain. */ + private retire; + /** Drain and release state owned by one exact disposed Session lifecycle. */ + private retireCore; + /** Return the one lifecycle controller for a live session, creating it if needed. */ + private initFor; + /** Bind one exact prepared Session and persist only its unpublished suffix. */ + private attachPrepared; + /** + * Whether a live session's `seed` reproduces the first `cursor` persisted + * events. A `cursor` of 0 (nothing persisted yet) trivially matches. Used when + * a live session claims ownerless state left by a prior `load()`/`create()`. + */ + private seedMatchesPersisted; + /** + * On session/created: sync the backend's in-memory state to a live Session. + * + * Cases, by whether this backend tracks the id and whether an artifact exists: + * 1. Already tracked → no-op (or claim ownerless state if the seed matches, + * or reclaim a truly-abandoned id, else reject as a collision). + * 2. Not tracked, an artifact EXISTS at the same cwd and is a seq-aligned + * PREFIX of the live events → ADOPT it, persisting any live suffix. + * 3. Not tracked, an artifact EXISTS at another cwd or is NOT a prefix → + * REJECT (collision). + * 4. Not tracked and NO artifact → a genuinely new session: register meta + * (lazy) and persist its seed once. + */ + private onCreated; + /** + * Adopt a stored prefix as a live session's history (HMR/reload): verify the + * seed covers the stored prefix, truncate any torn tail (NOT the open turn — + * the live Session is still the authority), bind ownership, and persist the + * live suffix that was ahead of the stored prefix. + */ + private adoptLivePrefix; + private flush; + /** Build one package-private write controller around initialization and id serialization. */ + private createWriteBehind; + /** Append one controller-owned prefix after filtering events initialization already stored. */ + private appendLiveBatch; +} +//# sourceMappingURL=coordinator.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts new file mode 100644 index 0000000..1ef1a8f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts @@ -0,0 +1,190 @@ +/** + * Durable session-persistence Service Definition (`ctx.sessionPersistence`). Backends store + * {@link SessionEvent}s as the event-sourced log and carry non-replayable + * {@link SessionHeader} metadata separately. + * @module @deepseek-ai/dsh-session-persistence + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import { SessionPreparation } from '@deepseek-ai/dsh-session'; +import type { SessionEvent, SessionId, SessionHeader } from '@deepseek-ai/dsh-session'; +import type { SessionPersistenceRevision } from './revision.ts'; +export type { SessionHeader } from '@deepseek-ai/dsh-session'; +export { SessionPersistenceRevision } from './revision.ts'; +/** Lightweight immutable source identity returned without loading a full log. */ +export interface SessionPersistenceSnapshot { + /** Detached metadata for one materialized session. */ + header: SessionHeader; + /** Opaque source-qualified token that changes whenever this stored log changes. */ + revision: SessionPersistenceRevision; +} +/** Immutable logical session prepared from persistence or a live owner. */ +export interface SessionInspection { + /** Validated immutable session metadata. */ + readonly meta: SessionHeader; + /** Validated contiguous logical event log. */ + readonly events: readonly SessionEvent[]; +} +/** A backend's own raw artifact text for one session, verbatim. */ +export interface SessionRawArtifact { + /** The session header parsed from the artifact's own first line. */ + readonly meta: SessionHeader; + /** The artifact's base filename on disk, without any physical encoding suffix. */ + readonly filename: string; + /** The artifact's full text content, decoded from the backend's physical encoding. */ + readonly content: string; +} +export { DEFAULT_PREPARED_SESSION_CACHE_SIZE, DEFAULT_WRITE_BATCH_MAX_DELAY_MS, MAX_WRITE_BATCH_DELAY_MS, PersistenceCoordinator, SessionFormatUnsupportedError, SessionPersistenceCorruptionError, sessionFormatVersionRefusal, } from './coordinator.ts'; +export type { PersistenceBackend, PersistenceCoordinatorOptions, StoredPrefix, StoredSuffix, } from './coordinator.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + sessionPersistence: SessionPersistence; + } +} +/** + * A backend-resolved, per-session local artifact location. The path is an + * absolute target path and can name an artifact that has not materialized yet. + * Consumers must treat it as a location hint, never as an authorization token. + */ +export interface SessionLocation { + /** Backend-specific artifact kind, for example `jsonl`. */ + readonly kind: string; + /** Absolute path to this session's backend-owned artifact. */ + readonly path: string; +} +/** + * Durable append-only session storage. Implementations preserve contiguous, + * losslessly JSON-serializable events; {@link append} resolves only after + * durability, and {@link load} balances a complete interrupted tail without + * rewriting committed events. + */ +export declare abstract class SessionPersistence extends Service { + constructor(ctx: Context); + /** + * Resolve this backend's independent local artifact for a session without + * reading, creating, flushing, or otherwise materializing it. Backends such + * as SQLite that do not own one artifact per session return `undefined`. + * @param meta - the immutable session header whose artifact is requested. + * @returns the backend-specific absolute location, when one exists. + */ + abstract locate(meta: SessionHeader): SessionLocation | undefined; + /** + * Whether this backend exposes one verbatim raw artifact per session. + * A backend that declares `true` must override {@link readRaw}. + */ + abstract readonly supportsRawArtifacts: boolean; + /** + * Read a session's backend-owned artifact text verbatim — the exact durable + * bytes the backend wrote (decoded from its physical encoding, e.g. a + * decompressed JSONL). The returned `content` is the raw text, not a + * reconstruction from parsed events, so it preserves backend-specific + * serialization (chunk packing, key order, line breaks). Callers first test + * {@link supportsRawArtifacts}; `undefined` then means only that the requested + * session has no materialized artifact. + * @param _id - the persisted session to read (unused by the default: no + * per-session artifact). + * @param signal - optional cancellation for backend read work. + * @returns the raw artifact plus its parsed header, or `undefined` when the + * session is absent. + * @throws when this backend does not expose per-session raw artifacts. + */ + readRaw(_id: SessionId, signal?: AbortSignal): Promise; + /** + * Register a new session's metadata. A backend MAY defer the physical write + * until the first {@link append} (lazy materialization), in which case a + * created-but-never-appended session is absent from {@link list} + * — abandoned sessions leave nothing behind. + * @param meta - the immutable header (id, version, cwd, lineage) to record. + */ + abstract create(meta: SessionHeader): Promise; + /** + * Durably persist a batch of events. Honors the append-only and contiguous- + * seq contracts: the first event's `seq` MUST equal the stored next-seq + * (after `load` has durably closed any interrupted turn). Rejects non-JSON- + * serializable `event.data` with an error naming the offending event type. + * @param id - the session the batch belongs to. + * @param events - the contiguous batch to persist, in seq order. + */ + abstract append(id: SessionId, events: readonly SessionEvent[]): Promise; + /** + * Prepare the exact unpublished Session used by resume. Implementations may + * reuse object graphs retained by an earlier {@link inspect} after confirming + * their durable revision is still current; disposal releases an unpublished + * reservation. Revision retries require the durable log to remain unchanged + * for one read/check round trip; continuous external writers may delay completion. + * @param id - persisted session to prepare. + * @param signal - optional cancellation for preparation work. + * @returns one owned unpublished Session preparation. + */ + prepare(id: SessionId, signal?: AbortSignal): Promise; + /** + * Load an immutable balanced logical view and commit any required cold + * recovery. A complete interrupted final turn is preserved and durably + * closed with missing tool errors plus any open step and turn boundaries; + * only a torn final record is discarded. Unknown versions and corruption in + * the committed prefix reject. Implementations MUST NOT crash-repair an + * identity still bound to a live Session: a balanced live log may return as a + * durable snapshot, while an open live turn rejects. Returned values may be + * shared with immutable live or prepared state and must not be mutated. + * Revision-based implementations may wait for one stable read/check round trip. + * @param id - the persisted session to reload. + * @returns the header and a log ending on a balanced `turn/end`. + */ + abstract load(id: SessionId): Promise; + /** + * Inspect an immutable logical session without committing recovery or + * publishing it. A cold complete interrupted turn receives synthetic closers + * in memory and a torn physical tail remains untouched. An already-live + * Session instead yields its current immutable snapshot, which may contain an + * open turn and its `session/end-seed` boundary. Coordinator-backed + * implementations retain the exact cold unpublished Session for bounded + * reuse by a later {@link prepare}. A stale ready source is reloaded; a source + * already committing or reserved for resume remains exclusive, and inspection + * may borrow its immutable view. Callers borrow only the immutable header and + * log. Continuous external writers may delay revision convergence. + * @param id - the persisted session to inspect. + * @param signal - optional cancellation for queued and backend read work. + * @returns the validated header and current logical event log. + */ + abstract inspect(id: SessionId, signal?: AbortSignal): Promise; + /** + * Read the stored events from `fromSeq` onward — the read-from-seq + * primitive for read models that resume from a watermark (e.g. a persisted + * projection cache folding only the tail past its checkpoint). Unlike + * {@link inspect}, it is a detached physical suffix read: no preparation + * cache, torn-tail truncation, synthetic closers, or coordinator-state + * publication. Only events from the valid contiguous stored prefix are + * returned, so a torn fragment never reaches the caller. `fromSeq` at or + * beyond the stored prefix returns an empty event list (never an error). + * Backends whose medium can seek by seq + * (SQLite) read only the suffix; sequential media (JSONL, both encodings) + * still parse the whole artifact and skip forward — the primitive bounds + * what is RETURNED and refolded, not every backend's physical read. + * @param id - the persisted session to read. + * @param fromSeq - first event seq to include; a non-negative safe integer. + * @param signal - optional cancellation for queued and backend read work. + * @returns the header and the stored events with `seq >= fromSeq`. + */ + abstract readFrom(id: SessionId, fromSeq: number, signal?: AbortSignal): Promise<{ + meta: SessionHeader; + events: SessionEvent[]; + }>; + /** + * Lightweight listing from metadata, without a full-log parse. + * @param signal - optional cancellation for backend listing work. + * @returns one header per materialized session. + */ + abstract list(signal?: AbortSignal): Promise; + /** + * List materialized sessions with cheap per-log change tokens. + * + * Repeated observations of an unchanged log return the same revision. A + * successful mutating {@link load} repair changes the next listed revision. + * Revisions also distinguish independently backed stores so backend-local + * counters cannot compare equal across different persistence sources. + * @param signal - optional cancellation for backend snapshot-listing work. + * @returns one header and opaque revision per materialized session without loading full logs. + */ + abstract listSnapshots(signal?: AbortSignal): Promise; +} +export default SessionPersistence; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/invariant.d.ts new file mode 100644 index 0000000..fa12796 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-persistence`. + * @module @deepseek-ai/dsh-session-persistence/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-persistence-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/preparations.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/preparations.d.ts new file mode 100644 index 0000000..6b93819 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/preparations.d.ts @@ -0,0 +1,115 @@ +/** + * Bounded sharing and exclusive reservation of unpublished Sessions. + * @module @deepseek-ai/dsh-session-persistence/preparations + */ +import type { Session, SessionId } from '@deepseek-ai/dsh-session'; +interface PreparedSource { + readonly session: Session; +} +type PreparationPhase = 'loading' | 'ready' | 'committing' | 'reserved'; +interface PreparationEntry { + readonly id: SessionId; + readonly result: Promise; + phase: PreparationPhase; + source?: Source; + reservation?: SessionPreparationReservation; + reservationSettled?: Promise; + settleReservation?: () => void; +} +/** One exclusively held prepared source and its committed persistence state. */ +export interface SessionPreparationReservation { + readonly entry: PreparationEntry; + readonly source: Source; + readonly state: CommitState; +} +/** Per-coordinator cold-read sharing, exclusive reservation, and ready-entry LRU. */ +export declare class SessionPreparations { + private readonly capacity; + private readonly entries; + constructor(capacity: number); + /** + * Whether this pool currently knows about an unpublished identity. + * @param id - session identity. + * @returns whether an entry exists for the identity. + */ + has(id: SessionId): boolean; + /** + * Observe one prepared source, sharing an in-flight read for the same id. + * @param id - session identity. + * @param load - cold loader used when no entry exists. + * @param signal - optional cancellation signal while waiting. + * @returns the shared prepared source. + */ + inspect(id: SessionId, load: () => Promise, signal?: AbortSignal): Promise; + /** + * Reserve one ready source after committing its pending durable repair. + * @param id - session identity. + * @param load - cold loader used when no entry exists. + * @param commit - durable repair and cursor-state commit. + * @param signal - optional cancellation signal while waiting. + * @returns the exclusive reservation, or undefined if its entry was invalidated. + */ + reserve(id: SessionId, load: () => Promise, commit: (source: Source) => Promise<{ + source: Source; + state: CommitState; + } | undefined>, signal?: AbortSignal): Promise | undefined>; + /** + * Return the exact reservation for Session publication, rejecting aliases. + * @param session - exact Session candidate for publication. + * @returns its reservation, or undefined when no preparation exists. + */ + reservationFor(session: Session): SessionPreparationReservation | undefined; + /** + * Consume a reservation after its exact Session has attached. + * @param reservation - reservation to consume. + */ + attach(reservation: SessionPreparationReservation): void; + /** + * Consume a reservation whose caller only needs the committed inspection. + * @param reservation - reservation to consume. + */ + discard(reservation: SessionPreparationReservation): void; + /** + * Return a reusable unpublished reservation to the ready LRU. + * @param reservation - reservation to release. + * @param reusable - whether the source remains valid for reuse. + */ + release(reservation: SessionPreparationReservation, reusable: boolean): void; + /** + * Discard a prepared view after the durable log changes. + * @param id - changed session identity. + */ + invalidate(id: SessionId): void; + /** + * Discard an exact stale ready source without disturbing an exclusive owner. + * @param id - changed session identity. + * @param expected - exact source observed before its revision check. + * @returns whether the source was discarded, retained by a reservation, or is absent. + */ + discardReady(id: SessionId, expected: Source): 'discarded' | 'retained' | 'missing'; + /** + * Reject writes while an unpublished Session exclusively reserves the id. + * @param id - session identity to check. + */ + assertWritable(id: SessionId): void; + /** + * Remove a completed entry for an already-serialized append adoption. + * @param id - adopted session identity. + * @returns the prepared source, or undefined when no ready entry exists. + */ + takeReady(id: SessionId): Source | undefined; + private entryFor; + private makeReady; + private remove; + private touch; +} +/** + * Give a queued observer a prompt cancellation view without cancelling shared work. + * @param operation - shared operation whose settlement remains authoritative. + * @param signal - observer-local cancellation signal. + * @param started - whether the operation has crossed its cancellation cutoff. + * @returns the operation result or the observer's prompt cancellation. + */ +export declare function observeQueuedAbort(operation: Promise, signal: AbortSignal, started?: () => boolean): Promise; +export {}; +//# sourceMappingURL=preparations.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/revision.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/revision.d.ts new file mode 100644 index 0000000..96da397 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/revision.d.ts @@ -0,0 +1,14 @@ +/** Opaque revision identity for lightweight persistence observations. */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** + * Backend-owned token that identifies both one storage source and one revision + * of a persisted session log. + */ +export type SessionPersistenceRevision = Branded<'SessionPersistenceRevision'>; +/** + * Brand a backend revision for the provider-neutral persistence contract. + * @param value - backend-owned opaque revision representation. + * @returns the same runtime string with persistence-revision identity. + */ +export declare function SessionPersistenceRevision(value: string): SessionPersistenceRevision; +//# sourceMappingURL=revision.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/write-behind.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/write-behind.d.ts new file mode 100644 index 0000000..7775329 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/write-behind.d.ts @@ -0,0 +1,62 @@ +/** + * Bounded per-session write batching for the shared persistence coordinator. + * @module @deepseek-ai/dsh-session-persistence/write-behind + */ +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +/** Dependencies and scheduling policy for one live session's write controller. */ +export interface SessionWriteBehindOptions { + /** Maximum intentional batching wait after an idle queue receives work. */ + readonly maxDelayMs: number; + /** Persist one stable ordered prefix; resolves only after backend durability. */ + readonly write: (events: readonly SessionEvent[]) => Promise; + /** Observe a detached background write failure without rejecting the producer. */ + readonly reportBackgroundFailure: (error: unknown) => void; +} +/** + * Owns one live session's pending events, fixed batching deadline, active write, + * failure retention, and explicit quiescence barrier. + */ +export declare class SessionWriteBehind { + private readonly options; + private pending; + private timer; + private active; + private barrier; + private deadlineExpired; + private automaticPaused; + /** + * @param options - fixed scheduling policy and durable batch sink. + */ + constructor(options: SessionWriteBehindOptions); + /** Whether this controller owns queued events or an active durable write. */ + get hasWork(): boolean; + /** + * Copy one event into the persistence-owned queue and start a fixed deadline + * when the automatic path is idle. + * @param event - frozen live event to retain independently of its producer. + */ + enqueue(event: SessionEvent): void; + /** + * Cancel the batching wait and durably drain through a quiescent point. + * Concurrent callers join the same barrier. + * @returns a promise that rejects if the barrier's durable retry fails. + */ + flush(): Promise; + /** Cancel the current automatic deadline without draining retained work. */ + cancelAutomaticWait(): void; + /** Start the one fixed window for the current pending prefix. */ + private armTimer; + /** Cancel any pending automatic deadline. */ + private cancelTimer; + /** Start a background write now, or remember that an active write used the budget. */ + private onDeadline; + /** Start one detached write whose failure is reported and retained. */ + private startBackground; + /** Continue immediately after an over-budget active write, otherwise keep its timer. */ + private continueAutomatic; + /** Await overlapping work, drain to quiescence, and settle the shared barrier. */ + private drainBarrier; + /** Start one stable pending prefix, retaining it in order if durability fails. */ + private startWrite; +} +//# sourceMappingURL=write-behind.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/package.json new file mode 100644 index 0000000..238add6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence/package.json @@ -0,0 +1,49 @@ +{ + "name": "@deepseek-ai/dsh-session-persistence", + "description": "Abstract durable session persistence seam (ctx.sessionPersistence) for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session/session-persistence" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-timeout b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-timeout new file mode 120000 index 0000000..995aaf1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-timeout @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..a0535b0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..fb5edd1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.i18n.yaml new file mode 100644 index 0000000..618533d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/session/session-projection-cache/README.md +README.md: 5d4ad07fab6648acdb40c6aa86d32cc78b4c016e +README.zh.md: 5e38ee98b04bc8f856538112d2922b64cadce4d5 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.md new file mode 100644 index 0000000..5d4ad07 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.md @@ -0,0 +1,62 @@ +# @deepseek-ai/dsh-session-projection-cache + +English | [中文](README.zh.md) + +The persisted projection cache (`ctx.sessionProjectionCache`): durable checkpoints of every registered projection unit's state, one record per session on the domain data form (`session_projcache` domain — the shipped json backend lands it beside `workspace.json` under the configured storage root). Design authority: the [session-projection RFC](../../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md) (persisted projection cache section). + +A stored row `(key → {ver, seq, val})` is a fold shortcut, never an authority: possibly stale (`seq` says exactly how stale) but never wrong. Consequences the implementation commits to: + +- **Every background write is fail-soft.** A failed durable write logs a warning and keeps the cache stale; the next write or cold read self-heals. A crash between writes costs a longer tail replay, never a wrong value. +- **A `ver` mismatch against the live unit's `stateVersion` discards, never migrates.** A unit bump invalidates its rows at read time; the key refolds from the log. +- **Whole-record writes.** Each write replaces the session's full checkpoint (the registry cut is always complete), snapshotted through the lossless-JSON boundary — a unit state violating the plain-JSON contract fails loud. +- **Records are bound to a log lifecycle, not just an id.** Each record stores the header identity (`createdAt`, `cwd`) it was folded from; every read validates it (the live or stored header is the witness) before accepting a row, so a deleted-then-recreated id or a persistence store swapped under a surviving cache discards the unrelated record instead of seeding phantom values. +- **The log leads, the cache follows.** A live checkpoint flushes the session's buffered events durably BEFORE the cache row lands, so a crash can leave the cache behind the log (a longer tail replay) but never ahead of it. + +## Write policy + +Two mandatory points, throttled in between: + +| Trigger | Nature | +|---|---| +| `turn/end` | Mandatory — the turn-final value is what cold reads want. | +| Session disposal (detach) | Mandatory — the live-to-cold moment; after it the cold ladder serves this session. | +| `writeEveryEvents` committed events | Config throttle (count). | +| `writeIntervalMs` since the first dirty event | Config throttle (interval). | + +Both `Config` fields are required (no defaults): flush cadence is a deployment choice with no universally correct value, stated in cordis.yml. + +## Listing read (`cachedSnapshot(meta)`) + +The zero-I/O rung: whole values viewed straight from the identity-matching stored record (version-matching keys only), returned as a `{asOfSeq, values}` cut — `asOfSeq` is the lowest served-row watermark, so a client seeding its per-session value store under higher-seq-wins can never let a stale list block overwrite a newer push frame. `undefined` when no usable record exists (unknown id, unrelated lifecycle, or no version-matching rows); the api-proxy list carrier turns that into an absent column. + +## Cold read (`coldSnapshot(id, signal?)`) + +The read ladder, zero full-log load on the happy path: cached rows → `sessionProjections.restoreFloor` (anchored one event below the lowest usable watermark) → persistence `readFrom(id, floor)` → `sessionProjections.restore` → fail-soft write-back of the refreshed rows. The anchor makes a shrunk log (crash-repair truncation) provable: an overreaching row triggers exactly one full re-read from seq 0 instead of serving a ghost value. No registered units serve `{asOfSeq: -1, values: {}}` without touching persistence; a session with no persisted log rejects with the seam's `not found`. + +`write(session)` is the synchronous-cut checkpoint both mandatory points use; carriers may call it directly (not fail-soft — the fail-soft wrappers own containment). + +## Composition + +```yaml +- id: session-projection-cache + name: '@deepseek-ai/dsh-session-projection-cache' + config: + writeEveryEvents: 200 + writeIntervalMs: 5000 +``` + +Injects `storageDomain`, `sessionProjections`, `sessionPersistence`, `sessions`. Without this row the projection system runs live-only (watermark cache; cold reads fall back to full log loads wherever a carrier implements them). + +## Model Experience + +None, as the cache only persists and restores host-side read models of already-logged session state and touches no prompt, message, schema, stream, or tool result. + +#### KV Cache effect + +None; the cache never assembles or sends provider requests. + +## Known Limitations and Deferred Work + +- **No eviction or retention surface** — records accumulate per session; pruning stored checkpoints is out-of-band maintenance, same stance as session persistence itself. +- **Interval throttle is per-session coarse** — the timer arms at the first dirty event after a clean write; a steady sub-threshold trickle writes once per interval, not a sliding window. +- **`coldSnapshot` reads are not deduplicated** — two concurrent cold reads of one session each run the ladder; last write-back wins (rows are equivalent), acceptable for listing-scale call rates. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.zh.md new file mode 100644 index 0000000..5e38ee9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/README.zh.md @@ -0,0 +1,62 @@ +# @deepseek-ai/dsh-session-projection-cache + +[English](README.md) | 中文 + +持久投影缓存(`ctx.sessionProjectionCache`):把每个已注册投影单元的状态持久化为检查点,基于域数据形态(domain data form)每会话一条记录(`session_projcache` 域——出厂 JSON 后端将其落在配置的存储根目录下、`workspace.json` 旁边)。设计权威:[session-projection RFC](../../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md)(persisted projection cache 一节)。 + +一条存储行 `(key → {ver, seq, val})` 是折叠捷径,绝不是权威:可能陈旧(`seq` 精确说明陈旧到哪),但绝不会错。实现据此承诺: + +- **每次后台写入都 fail-soft。** 持久写失败只记一条警告并保持缓存陈旧;下一次写入或冷读自愈。两次写之间崩溃的代价是更长的尾部回放,绝不是错误的值。 +- **`ver` 与当前运行单元的 `stateVersion` 不匹配即丢弃,绝不迁移。** 单元递增版本会在读取时使其行失效;该 key 从日志重新折叠。 +- **整记录写入。** 每次写入替换该会话的完整检查点(注册表切面始终是完整的),并经无损 JSON 边界快照——违反纯 JSON 约定的单元状态会显式失败并报错。 +- **记录绑定到日志生命周期,而不只是 id。** 每条记录存储其折叠来源的 header 身份(`createdAt`、`cwd`);每次读取先以活 header 或存储 header 为证验证它,再接受任何行——被删后重建的 id、或缓存幸存而持久化存储被换掉时,无关记录被整体丢弃,绝不播种幻影值。 +- **日志领先,缓存跟随。** 活会话检查点先把缓冲事件持久 flush,缓存行才落地,因此崩溃只会让缓存落后于日志(更长的尾部回放),绝不领先于它。 + +## 写策略 + +两个必写点,其间节流: + +| 触发 | 性质 | +|---|---| +| `turn/end` | 必写——冷读要的正是轮次终值。 | +| 会话释放(detach) | 必写——live 转 cold 的时刻;此后冷读阶梯接管该会话。 | +| 累计 `writeEveryEvents` 个已提交事件 | 配置节流(条数)。 | +| 距首个脏事件 `writeIntervalMs` 毫秒 | 配置节流(间隔)。 | + +两个 `Config` 字段均必填(无默认值):写入节奏是部署选择,没有普适正确值,由 cordis.yml 明示。 + +## 列表读(`cachedSnapshot(meta)`) + +零 I/O 一档:从身份匹配的存储记录直接 view 全量值(仅版本匹配的 key),以 `{asOfSeq, values}` 切面返回——`asOfSeq` 取所服务行的最低水位,客户端在 higher-seq-wins 规则下播种值存储时,陈旧列表块永远压不过更新的推送帧。无可用记录(未知 id、无关生命周期、无版本匹配行)时返回 `undefined`;api-proxy 列表载体将其转为列缺席。 + +## 冷读(`coldSnapshot(id, signal?)`) + +读取阶梯,正常路径无需加载全量日志:缓存行 → `sessionProjections.restoreFloor`(锚定在最低可用水位之前一个事件的位置)→ 持久化 `readFrom(id, floor)` → `sessionProjections.restore` → 刷新行的 fail-soft 写回。这个锚使缩短的日志(崩溃修复截断)可被证明:越界的行恰好触发一次从 seq 0 的全量重读,而不是把幽灵值当现值服务。无已注册单元时直接服务 `{asOfSeq: -1, values: {}}`,不触碰持久化;无持久日志的会话以 seam 的 `not found` 拒绝。 + +`write(session)` 是两个必写点共用的同步切面检查点;载体可以直接调用(非 fail-soft——由 fail-soft 包装层负责遏制)。 + +## 组合 + +```yaml +- id: session-projection-cache + name: '@deepseek-ai/dsh-session-projection-cache' + config: + writeEveryEvents: 200 + writeIntervalMs: 5000 +``` + +注入 `storageDomain`、`sessionProjections`、`sessionPersistence`、`sessions`。没有这一行时,投影系统只跑 live(水位缓存;冷读在实现了它的载体处退回全量日志加载)。 + +## 模型体验 + +无,因为缓存只持久化并恢复 host 侧的、由已写入日志的会话状态派生的读模型,不触碰任何提示词、消息、schema、流或工具结果。 + +#### KV Cache 影响 + +无;缓存从不组装或发送提供方请求。 + +## 已知局限与延后工作 + +- **不提供淘汰或保留接口**:记录会按会话持续累积;清理已存储的检查点属于带外维护,与会话持久化采用相同策略。 +- **间隔节流采用按会话的粗粒度控制**:一次无脏数据的写入完成后,计时器会在首个脏事件到达时启动;对于持续但未达到条数阈值的事件流,系统每个间隔写入一次,而不采用滑动窗口。 +- **`coldSnapshot` 读取不去重**——同一会话的两个并发冷读各跑一遍阶梯;写回最后者胜(行等价),对列表级调用频率可接受。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js new file mode 100644 index 0000000..9fe86d4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js @@ -0,0 +1,286 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { snapshotJsonValue } from "@deepseek-ai/dsh-session"; +import { z as z$1 } from "zod"; +import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain"; +//#region lib/types/spec.js +/** +* The session-projcache domain declaration: one `sessions` table keyed by +* {@link SessionId}, each record the full projection checkpoint for one +* session (`key → {ver, seq, val}` rows). The spec object +* is the single source of the domain's identity, version, and record schema; +* the storage-domain routing decides the medium (the shipped composition's +* json backend lands it at `/session_projcache.json`, beside +* `workspace.json`). +* @module @deepseek-ai/dsh-session-projection-cache/src/spec +*/ +/** +* One persisted checkpoint row (the RFC's `(sessionId, key, ver, seq, val)` +* minus the two record keys). `val` is the unit's internal state — plain +* JSON by the unit contract; `z.json()` enforces that at the durable +* boundary. A row is never wrong, only possibly stale: `seq` says exactly +* how stale, and a `ver` mismatch against the live unit's `stateVersion` +* discards it at read time (never a migration). +*/ +const checkpointRow = z$1.object({ + ver: z$1.number().int().nonnegative(), + seq: z$1.number().int().gte(-1), + val: z$1.json() +}); +/** +* The stored-log identity a record is bound to: the immutable header fields +* that distinguish one session lifecycle from another under the same id. A +* session id names a slot, not a lifecycle — a deleted-then-recreated id, or +* a persistence root swapped under a surviving cache, would otherwise let an +* old row pass every watermark check and seed state folded from an unrelated +* log. Reads validate this against the live header (listing) or the stored +* header (cold read) before accepting any row. +*/ +const checkpointIdentity = z$1.object({ + createdAt: z$1.number().int().nonnegative(), + cwd: z$1.string().optional() +}); +/** +* One session's stored record: the log identity it was folded from plus its +* checkpoint rows keyed by projection key. The whole record is replaced on +* every write (whole-value discipline — the registry checkpoint is always +* the complete per-session cut). +*/ +const checkpointRecord = z$1.object({ + identity: checkpointIdentity, + rows: z$1.record(z$1.string(), checkpointRow) +}); +/** +* The session-projcache domain spec. Version bumps discard the whole medium +* (cache semantics: a stale or unreadable cache costs a longer tail replay, +* never a wrong value). +*/ +const projectionCacheDomainSpec = defineDomain({ + name: "session_projcache", + version: 3, + tables: { sessions: domainTable(checkpointRecord) } +}); +//#endregion +//#region lib/types/index.js +/** +* Persisted projection cache (`ctx.sessionProjectionCache`): durable +* checkpoints of every registered projection unit's state, one record per +* session on the domain data form (`session_projcache` domain — the shipped +* json backend lands it beside `workspace.json`). The cache is a fold +* shortcut, never an authority: a row is possibly stale (its `seq` +* says how stale) but never wrong, so every write path is fail-soft (a lost +* write costs a longer tail replay on the next cold read) and a +* `ver` mismatch discards the row instead of migrating it. Design +* authority: the session-projection RFC +* (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md). +* @module @deepseek-ai/dsh-session-projection-cache +*/ +const Config = z.object({ + writeEveryEvents: z.natural().min(1).required(), + writeIntervalMs: z.natural().min(1).required() +}); +/** +* The persisted projection cache service. Opens the `session_projcache` +* domain at init, checkpoints live sessions on a throttled write-behind +* (count/interval triggers from {@link Config}) plus two mandatory points — +* `turn/end` and session disposal (the live-to-cold moment) — and serves the +* cold-read ladder: cached row, persistence `readFrom` tail, registry +* `restore`, durable write-back. Every durable write is fail-soft: failures +* log a warning and the cache self-heals on the next write or cold read. +*/ +var SessionProjectionCache = class extends Service { + config; + static inject = [ + "storageDomain", + "sessionProjections", + "sessionPersistence", + "sessions" + ]; + static Config = Config; + table; + dirty = /* @__PURE__ */ new Map(); + constructor(ctx, config) { + super(ctx, "sessionProjectionCache"); + this.config = config; + } + /** Open the domain and install the write-behind listeners. */ + async [Service.init]() { + const domain = await this.ctx.storageDomain.open(projectionCacheDomainSpec); + this.ctx.effect(() => () => domain.close(), "sessionProjectionCache.domainClose"); + this.table = domain.table("sessions"); + this.installWritePath(); + } + /** + * The stored record for one session, accepted only when its bound log + * identity matches `expected`. A session id names a slot, not a lifecycle: + * a recreated id or a persistence store swapped under a surviving cache + * must not let an old record seed state folded from an unrelated log. + * Synchronous from the domain's in-memory state. + * @param id - the session whose record is read. + * @param expected - the log identity the caller holds (live or stored header). + * @returns the identity-matching record, or `undefined` (absent or unrelated). + */ + recordFor(id, expected) { + const record = this.requireTable().get(id); + if (record === void 0) return void 0; + return identityMatches(record.identity, expected) ? record : void 0; + } + /** + * The zero-I/O listing read: whole values viewed straight from the stored + * rows (version-matching keys only), each cut carried with its watermark + * so a client value store can seed under its higher-seq-wins rule — as + * stale as the last durable checkpoint but never wrong, and never from an + * unrelated log (the caller's header is the identity witness). Fresher + * paths (the history tail baseline, {@link coldSnapshot}) supersede these + * values whenever a session is actually opened. + * @param meta - the listed session's header (identity witness; no log read). + * @returns the cut (`asOfSeq` = lowest served-row watermark), or + * `undefined` when no usable row exists for this lifecycle. + */ + cachedSnapshot(meta) { + const record = this.recordFor(meta.id, identityOf(meta)); + if (record === void 0) return void 0; + const values = this.ctx.sessionProjections.viewCheckpoint(record.rows); + const keys = Object.keys(values); + if (keys.length === 0) return void 0; + return { + asOfSeq: Math.min(...keys.map((key) => record.rows[key].seq)), + values + }; + } + /** + * Durably checkpoint one live session NOW (both mandatory points call + * this; tests and carriers may too). The registry cut is snapshotted at + * this boundary (states are live references), then the whole record is + * replaced. NOT fail-soft — callers on the fail-soft paths contain it. + * @param session - the live session to checkpoint. + * @returns resolution after durability and event emission. + */ + async write(session) { + const rows = this.ctx.sessionProjections.checkpoint(session); + this.markClean(session); + if (this.ctx.sessions.get(session.id) === session) await this.ctx.sessions.flush(session); + await this.put(session.id, identityOf(session.header), rows); + } + /** + * Cold-read one persisted session's projections with zero full-log load: + * cached rows + a persistence `readFrom` tail from the registry's restore + * floor, refolded by the registry and written back (fail-soft) so the next + * cold read starts closer. A cache row invalidated by a shrunk log + * (crash-repair truncation) triggers one full re-read from seq 0 — the + * ladder's slow rung, still no crash. Rejects when the session has no + * persisted log (`not found` from the persistence seam). + * @param id - the persisted session to read. + * @param signal - optional cancellation for the persistence reads. + * @returns the snapshot cut at the stored log end. + */ + async coldSnapshot(id, signal) { + const record = this.requireTable().get(id); + const cached = record?.rows ?? {}; + const floor = this.ctx.sessionProjections.restoreFloor(cached); + const persistence = this.ctx.sessionPersistence; + if (floor === void 0) return { + asOfSeq: (await persistence.readFrom(id, 0, signal)).events.at(-1)?.seq ?? -1, + values: {} + }; + let restored; + const tail = await persistence.readFrom(id, floor, signal); + const related = record === void 0 || identityMatches(record.identity, identityOf(tail.meta)); + try { + if (!related) throw new Error("unrelated log identity"); + restored = this.ctx.sessionProjections.restore(cached, tail.events, floor); + } catch { + const whole = await persistence.readFrom(id, 0, signal); + restored = this.ctx.sessionProjections.restore({}, whole.events, 0); + } + await this.putSoft(id, identityOf(tail.meta), restored.checkpoint, "cold-read write-back"); + return restored.snapshot; + } + installWritePath() { + this.ctx.on("session/event", (session, event) => { + if (event.type === "turn/end") { + this.flushSoft(session, "turn/end"); + return; + } + const state = this.dirty.get(session) ?? { + pending: 0, + timer: void 0 + }; + this.dirty.set(session, state); + state.pending += 1; + if (state.pending >= this.config.writeEveryEvents) { + this.flushSoft(session, "count threshold"); + return; + } + state.timer ??= setTimeout(() => { + this.flushSoft(session, "interval"); + }, this.config.writeIntervalMs); + }); + this.ctx.on("session/disposed", (session) => { + this.flushSoft(session, "detach"); + this.markClean(session); + this.dirty.delete(session); + }); + this.ctx.effect(() => () => { + for (const state of this.dirty.values()) if (state.timer !== void 0) clearTimeout(state.timer); + this.dirty.clear(); + }, "sessionProjectionCache.timers"); + } + /** + * One fail-soft durable checkpoint. Every caller has work by construction: + * the throttle triggers only fire dirty (markClean clears the timer with + * the counter) and the two mandatory points write unconditionally. + */ + async flushSoft(session, trigger) { + try { + await this.write(session); + } catch (error) { + this.ctx.logger.warn(`session projection cache: ${trigger} write for "${session.id}" failed (cache stays stale): ${String(error)}`); + } + } + /** Reset one session's dirty bookkeeping (its checkpoint is being written). */ + markClean(session) { + const state = this.dirty.get(session); + if (state === void 0) return; + state.pending = 0; + if (state.timer !== void 0) { + clearTimeout(state.timer); + state.timer = void 0; + } + } + /** Replace one session's stored record with its log identity and a detached snapshot of `rows`. */ + async put(id, identity, rows) { + const detached = snapshotJsonValue(rows); + if (detached === void 0) throw new TypeError("projection checkpoint is not losslessly JSON-serializable (a unit state violates the plain-JSON contract)"); + await this.requireTable().put(id, { + identity, + rows: detached + }); + } + /** Fail-soft {@link put}: cache writes must never fail their caller's read or event path. */ + async putSoft(id, identity, rows, what) { + try { + await this.put(id, identity, rows); + } catch (error) { + this.ctx.logger.warn(`session projection cache: ${what} for "${id}" failed (cache stays stale): ${String(error)}`); + } + } + requireTable() { + /* v8 ignore next -- Service.init assigns the table before the service becomes injectable */ + if (this.table === void 0) throw new Error("session projection cache is not initialized"); + return this.table; + } +}; +/** Project a header onto the identity fields a record is bound to. */ +function identityOf(header) { + return { + createdAt: header.createdAt, + ...header.cwd === void 0 ? {} : { cwd: header.cwd } + }; +} +/** Whether a stored record's bound identity names the caller's lifecycle. */ +function identityMatches(stored, expected) { + return stored.createdAt === expected.createdAt && stored.cwd === expected.cwd; +} +//#endregion +export { Config, SessionProjectionCache, SessionProjectionCache as default, checkpointIdentity, checkpointRecord, checkpointRow, projectionCacheDomainSpec }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/invariant.js new file mode 100644 index 0000000..8cb72da --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/invariant.js @@ -0,0 +1,28 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-session-projection-cache`. +* @module @deepseek-ai/dsh-session-projection-cache/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session-projection-cache"; +/** Cordis companion plugin name. */ +const name = "session-projection-cache-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the cache's correctness relation (a stored row equals +* the registry fold at its `seq` watermark) is only checkable by re-running the +* fold over the persisted log — duplicating the implementation rather than +* detecting drift — and its staleness is by design (fail-soft writes). The +* durable boundary is already schema-validated by the storage-domain layer +* on every reopen, and the read ladder's version/watermark guards are proven +* by the package spec. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts new file mode 100644 index 0000000..823177c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts @@ -0,0 +1,118 @@ +/** + * Persisted projection cache (`ctx.sessionProjectionCache`): durable + * checkpoints of every registered projection unit's state, one record per + * session on the domain data form (`session_projcache` domain — the shipped + * json backend lands it beside `workspace.json`). The cache is a fold + * shortcut, never an authority: a row is possibly stale (its `seq` + * says how stale) but never wrong, so every write path is fail-soft (a lost + * write costs a longer tail replay on the next cold read) and a + * `ver` mismatch discards the row instead of migrating it. Design + * authority: the session-projection RFC + * (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md). + * @module @deepseek-ai/dsh-session-projection-cache + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { Session, SessionHeader, SessionId } from '@deepseek-ai/dsh-session'; +import type { ProjectionSnapshot } from '@deepseek-ai/dsh-session-projection'; +export { checkpointIdentity, checkpointRecord, checkpointRow, projectionCacheDomainSpec } from './spec.ts'; +export type { CheckpointIdentity, CheckpointRecord } from './spec.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + sessionProjectionCache: SessionProjectionCache; + } +} +/** + * Plugin config. Both throttle triggers are deployment choices with no + * universally correct value, so the composition states them explicitly + * (cordis.yml); the two mandatory write points (`turn/end` and session + * disposal) are policy, not tunables, and always fire. + */ +export interface Config { + /** Committed events per session that force a durable checkpoint write between mandatory points. */ + writeEveryEvents: number; + /** Longest time (milliseconds) a dirty checkpoint may stay unwritten between mandatory points. */ + writeIntervalMs: number; +} +export declare const Config: z; +/** + * The persisted projection cache service. Opens the `session_projcache` + * domain at init, checkpoints live sessions on a throttled write-behind + * (count/interval triggers from {@link Config}) plus two mandatory points — + * `turn/end` and session disposal (the live-to-cold moment) — and serves the + * cold-read ladder: cached row, persistence `readFrom` tail, registry + * `restore`, durable write-back. Every durable write is fail-soft: failures + * log a warning and the cache self-heals on the next write or cold read. + */ +export declare class SessionProjectionCache extends Service { + config: Config; + static inject: string[]; + static Config: z; + private table?; + private readonly dirty; + constructor(ctx: Context, config: Config); + /** Open the domain and install the write-behind listeners. */ + protected [Service.init](): Promise; + /** + * The stored record for one session, accepted only when its bound log + * identity matches `expected`. A session id names a slot, not a lifecycle: + * a recreated id or a persistence store swapped under a surviving cache + * must not let an old record seed state folded from an unrelated log. + * Synchronous from the domain's in-memory state. + * @param id - the session whose record is read. + * @param expected - the log identity the caller holds (live or stored header). + * @returns the identity-matching record, or `undefined` (absent or unrelated). + */ + private recordFor; + /** + * The zero-I/O listing read: whole values viewed straight from the stored + * rows (version-matching keys only), each cut carried with its watermark + * so a client value store can seed under its higher-seq-wins rule — as + * stale as the last durable checkpoint but never wrong, and never from an + * unrelated log (the caller's header is the identity witness). Fresher + * paths (the history tail baseline, {@link coldSnapshot}) supersede these + * values whenever a session is actually opened. + * @param meta - the listed session's header (identity witness; no log read). + * @returns the cut (`asOfSeq` = lowest served-row watermark), or + * `undefined` when no usable row exists for this lifecycle. + */ + cachedSnapshot(meta: SessionHeader): ProjectionSnapshot | undefined; + /** + * Durably checkpoint one live session NOW (both mandatory points call + * this; tests and carriers may too). The registry cut is snapshotted at + * this boundary (states are live references), then the whole record is + * replaced. NOT fail-soft — callers on the fail-soft paths contain it. + * @param session - the live session to checkpoint. + * @returns resolution after durability and event emission. + */ + write(session: Session): Promise; + /** + * Cold-read one persisted session's projections with zero full-log load: + * cached rows + a persistence `readFrom` tail from the registry's restore + * floor, refolded by the registry and written back (fail-soft) so the next + * cold read starts closer. A cache row invalidated by a shrunk log + * (crash-repair truncation) triggers one full re-read from seq 0 — the + * ladder's slow rung, still no crash. Rejects when the session has no + * persisted log (`not found` from the persistence seam). + * @param id - the persisted session to read. + * @param signal - optional cancellation for the persistence reads. + * @returns the snapshot cut at the stored log end. + */ + coldSnapshot(id: SessionId, signal?: AbortSignal): Promise; + private installWritePath; + /** + * One fail-soft durable checkpoint. Every caller has work by construction: + * the throttle triggers only fire dirty (markClean clears the timer with + * the counter) and the two mandatory points write unconditionally. + */ + private flushSoft; + /** Reset one session's dirty bookkeeping (its checkpoint is being written). */ + private markClean; + /** Replace one session's stored record with its log identity and a detached snapshot of `rows`. */ + private put; + /** Fail-soft {@link put}: cache writes must never fail their caller's read or event path. */ + private putSoft; + private requireTable; +} +export default SessionProjectionCache; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/invariant.d.ts new file mode 100644 index 0000000..5e6839f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-projection-cache`. + * @module @deepseek-ai/dsh-session-projection-cache/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-projection-cache-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/spec.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/spec.d.ts new file mode 100644 index 0000000..35a2c82 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/spec.d.ts @@ -0,0 +1,82 @@ +/** + * The session-projcache domain declaration: one `sessions` table keyed by + * {@link SessionId}, each record the full projection checkpoint for one + * session (`key → {ver, seq, val}` rows). The spec object + * is the single source of the domain's identity, version, and record schema; + * the storage-domain routing decides the medium (the shipped composition's + * json backend lands it at `/session_projcache.json`, beside + * `workspace.json`). + * @module @deepseek-ai/dsh-session-projection-cache/src/spec + */ +import { z } from 'zod'; +import { SessionId } from '@deepseek-ai/dsh-session'; +/** + * One persisted checkpoint row (the RFC's `(sessionId, key, ver, seq, val)` + * minus the two record keys). `val` is the unit's internal state — plain + * JSON by the unit contract; `z.json()` enforces that at the durable + * boundary. A row is never wrong, only possibly stale: `seq` says exactly + * how stale, and a `ver` mismatch against the live unit's `stateVersion` + * discards it at read time (never a migration). + */ +export declare const checkpointRow: z.ZodObject<{ + ver: z.ZodNumber; + seq: z.ZodNumber; + val: z.ZodJSONSchema; +}, z.core.$strip>; +/** + * The stored-log identity a record is bound to: the immutable header fields + * that distinguish one session lifecycle from another under the same id. A + * session id names a slot, not a lifecycle — a deleted-then-recreated id, or + * a persistence root swapped under a surviving cache, would otherwise let an + * old row pass every watermark check and seed state folded from an unrelated + * log. Reads validate this against the live header (listing) or the stored + * header (cold read) before accepting any row. + */ +export declare const checkpointIdentity: z.ZodObject<{ + createdAt: z.ZodNumber; + cwd: z.ZodOptional; +}, z.core.$strip>; +/** The identity fields a record is bound to, inferred from {@link checkpointIdentity}. */ +export type CheckpointIdentity = z.infer; +/** + * One session's stored record: the log identity it was folded from plus its + * checkpoint rows keyed by projection key. The whole record is replaced on + * every write (whole-value discipline — the registry checkpoint is always + * the complete per-session cut). + */ +export declare const checkpointRecord: z.ZodObject<{ + identity: z.ZodObject<{ + createdAt: z.ZodNumber; + cwd: z.ZodOptional; + }, z.core.$strip>; + rows: z.ZodRecord>; +}, z.core.$strip>; +/** One stored per-session checkpoint record, inferred from {@link checkpointRecord}. */ +export type CheckpointRecord = z.infer; +/** + * The session-projcache domain spec. Version bumps discard the whole medium + * (cache semantics: a stale or unreadable cache costs a longer tail replay, + * never a wrong value). + */ +export declare const projectionCacheDomainSpec: { + name: string; + version: number; + tables: { + sessions: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec; + }>; + }; +}; +//# sourceMappingURL=spec.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/package.json new file mode 100644 index 0000000..e24c79a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache/package.json @@ -0,0 +1,55 @@ +{ + "name": "@deepseek-ai/dsh-session-projection-cache", + "description": "Persisted projection cache (ctx.sessionProjectionCache): durable per-session projection checkpoints over the domain data form, throttled write-behind, and the cold-read ladder (cache row + persistence tail replay)", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session/session-projection-cache" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-storage-domain b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-storage-domain new file mode 120000 index 0000000..0ab7747 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-storage-domain @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..5362978 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..ed04634 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.i18n.yaml new file mode 100644 index 0000000..618533d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/session/session-projection-cache/README.md +README.md: 5d4ad07fab6648acdb40c6aa86d32cc78b4c016e +README.zh.md: 5e38ee98b04bc8f856538112d2922b64cadce4d5 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.md new file mode 100644 index 0000000..5d4ad07 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.md @@ -0,0 +1,62 @@ +# @deepseek-ai/dsh-session-projection-cache + +English | [中文](README.zh.md) + +The persisted projection cache (`ctx.sessionProjectionCache`): durable checkpoints of every registered projection unit's state, one record per session on the domain data form (`session_projcache` domain — the shipped json backend lands it beside `workspace.json` under the configured storage root). Design authority: the [session-projection RFC](../../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md) (persisted projection cache section). + +A stored row `(key → {ver, seq, val})` is a fold shortcut, never an authority: possibly stale (`seq` says exactly how stale) but never wrong. Consequences the implementation commits to: + +- **Every background write is fail-soft.** A failed durable write logs a warning and keeps the cache stale; the next write or cold read self-heals. A crash between writes costs a longer tail replay, never a wrong value. +- **A `ver` mismatch against the live unit's `stateVersion` discards, never migrates.** A unit bump invalidates its rows at read time; the key refolds from the log. +- **Whole-record writes.** Each write replaces the session's full checkpoint (the registry cut is always complete), snapshotted through the lossless-JSON boundary — a unit state violating the plain-JSON contract fails loud. +- **Records are bound to a log lifecycle, not just an id.** Each record stores the header identity (`createdAt`, `cwd`) it was folded from; every read validates it (the live or stored header is the witness) before accepting a row, so a deleted-then-recreated id or a persistence store swapped under a surviving cache discards the unrelated record instead of seeding phantom values. +- **The log leads, the cache follows.** A live checkpoint flushes the session's buffered events durably BEFORE the cache row lands, so a crash can leave the cache behind the log (a longer tail replay) but never ahead of it. + +## Write policy + +Two mandatory points, throttled in between: + +| Trigger | Nature | +|---|---| +| `turn/end` | Mandatory — the turn-final value is what cold reads want. | +| Session disposal (detach) | Mandatory — the live-to-cold moment; after it the cold ladder serves this session. | +| `writeEveryEvents` committed events | Config throttle (count). | +| `writeIntervalMs` since the first dirty event | Config throttle (interval). | + +Both `Config` fields are required (no defaults): flush cadence is a deployment choice with no universally correct value, stated in cordis.yml. + +## Listing read (`cachedSnapshot(meta)`) + +The zero-I/O rung: whole values viewed straight from the identity-matching stored record (version-matching keys only), returned as a `{asOfSeq, values}` cut — `asOfSeq` is the lowest served-row watermark, so a client seeding its per-session value store under higher-seq-wins can never let a stale list block overwrite a newer push frame. `undefined` when no usable record exists (unknown id, unrelated lifecycle, or no version-matching rows); the api-proxy list carrier turns that into an absent column. + +## Cold read (`coldSnapshot(id, signal?)`) + +The read ladder, zero full-log load on the happy path: cached rows → `sessionProjections.restoreFloor` (anchored one event below the lowest usable watermark) → persistence `readFrom(id, floor)` → `sessionProjections.restore` → fail-soft write-back of the refreshed rows. The anchor makes a shrunk log (crash-repair truncation) provable: an overreaching row triggers exactly one full re-read from seq 0 instead of serving a ghost value. No registered units serve `{asOfSeq: -1, values: {}}` without touching persistence; a session with no persisted log rejects with the seam's `not found`. + +`write(session)` is the synchronous-cut checkpoint both mandatory points use; carriers may call it directly (not fail-soft — the fail-soft wrappers own containment). + +## Composition + +```yaml +- id: session-projection-cache + name: '@deepseek-ai/dsh-session-projection-cache' + config: + writeEveryEvents: 200 + writeIntervalMs: 5000 +``` + +Injects `storageDomain`, `sessionProjections`, `sessionPersistence`, `sessions`. Without this row the projection system runs live-only (watermark cache; cold reads fall back to full log loads wherever a carrier implements them). + +## Model Experience + +None, as the cache only persists and restores host-side read models of already-logged session state and touches no prompt, message, schema, stream, or tool result. + +#### KV Cache effect + +None; the cache never assembles or sends provider requests. + +## Known Limitations and Deferred Work + +- **No eviction or retention surface** — records accumulate per session; pruning stored checkpoints is out-of-band maintenance, same stance as session persistence itself. +- **Interval throttle is per-session coarse** — the timer arms at the first dirty event after a clean write; a steady sub-threshold trickle writes once per interval, not a sliding window. +- **`coldSnapshot` reads are not deduplicated** — two concurrent cold reads of one session each run the ladder; last write-back wins (rows are equivalent), acceptable for listing-scale call rates. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.zh.md new file mode 100644 index 0000000..5e38ee9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/README.zh.md @@ -0,0 +1,62 @@ +# @deepseek-ai/dsh-session-projection-cache + +[English](README.md) | 中文 + +持久投影缓存(`ctx.sessionProjectionCache`):把每个已注册投影单元的状态持久化为检查点,基于域数据形态(domain data form)每会话一条记录(`session_projcache` 域——出厂 JSON 后端将其落在配置的存储根目录下、`workspace.json` 旁边)。设计权威:[session-projection RFC](../../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md)(persisted projection cache 一节)。 + +一条存储行 `(key → {ver, seq, val})` 是折叠捷径,绝不是权威:可能陈旧(`seq` 精确说明陈旧到哪),但绝不会错。实现据此承诺: + +- **每次后台写入都 fail-soft。** 持久写失败只记一条警告并保持缓存陈旧;下一次写入或冷读自愈。两次写之间崩溃的代价是更长的尾部回放,绝不是错误的值。 +- **`ver` 与当前运行单元的 `stateVersion` 不匹配即丢弃,绝不迁移。** 单元递增版本会在读取时使其行失效;该 key 从日志重新折叠。 +- **整记录写入。** 每次写入替换该会话的完整检查点(注册表切面始终是完整的),并经无损 JSON 边界快照——违反纯 JSON 约定的单元状态会显式失败并报错。 +- **记录绑定到日志生命周期,而不只是 id。** 每条记录存储其折叠来源的 header 身份(`createdAt`、`cwd`);每次读取先以活 header 或存储 header 为证验证它,再接受任何行——被删后重建的 id、或缓存幸存而持久化存储被换掉时,无关记录被整体丢弃,绝不播种幻影值。 +- **日志领先,缓存跟随。** 活会话检查点先把缓冲事件持久 flush,缓存行才落地,因此崩溃只会让缓存落后于日志(更长的尾部回放),绝不领先于它。 + +## 写策略 + +两个必写点,其间节流: + +| 触发 | 性质 | +|---|---| +| `turn/end` | 必写——冷读要的正是轮次终值。 | +| 会话释放(detach) | 必写——live 转 cold 的时刻;此后冷读阶梯接管该会话。 | +| 累计 `writeEveryEvents` 个已提交事件 | 配置节流(条数)。 | +| 距首个脏事件 `writeIntervalMs` 毫秒 | 配置节流(间隔)。 | + +两个 `Config` 字段均必填(无默认值):写入节奏是部署选择,没有普适正确值,由 cordis.yml 明示。 + +## 列表读(`cachedSnapshot(meta)`) + +零 I/O 一档:从身份匹配的存储记录直接 view 全量值(仅版本匹配的 key),以 `{asOfSeq, values}` 切面返回——`asOfSeq` 取所服务行的最低水位,客户端在 higher-seq-wins 规则下播种值存储时,陈旧列表块永远压不过更新的推送帧。无可用记录(未知 id、无关生命周期、无版本匹配行)时返回 `undefined`;api-proxy 列表载体将其转为列缺席。 + +## 冷读(`coldSnapshot(id, signal?)`) + +读取阶梯,正常路径无需加载全量日志:缓存行 → `sessionProjections.restoreFloor`(锚定在最低可用水位之前一个事件的位置)→ 持久化 `readFrom(id, floor)` → `sessionProjections.restore` → 刷新行的 fail-soft 写回。这个锚使缩短的日志(崩溃修复截断)可被证明:越界的行恰好触发一次从 seq 0 的全量重读,而不是把幽灵值当现值服务。无已注册单元时直接服务 `{asOfSeq: -1, values: {}}`,不触碰持久化;无持久日志的会话以 seam 的 `not found` 拒绝。 + +`write(session)` 是两个必写点共用的同步切面检查点;载体可以直接调用(非 fail-soft——由 fail-soft 包装层负责遏制)。 + +## 组合 + +```yaml +- id: session-projection-cache + name: '@deepseek-ai/dsh-session-projection-cache' + config: + writeEveryEvents: 200 + writeIntervalMs: 5000 +``` + +注入 `storageDomain`、`sessionProjections`、`sessionPersistence`、`sessions`。没有这一行时,投影系统只跑 live(水位缓存;冷读在实现了它的载体处退回全量日志加载)。 + +## 模型体验 + +无,因为缓存只持久化并恢复 host 侧的、由已写入日志的会话状态派生的读模型,不触碰任何提示词、消息、schema、流或工具结果。 + +#### KV Cache 影响 + +无;缓存从不组装或发送提供方请求。 + +## 已知局限与延后工作 + +- **不提供淘汰或保留接口**:记录会按会话持续累积;清理已存储的检查点属于带外维护,与会话持久化采用相同策略。 +- **间隔节流采用按会话的粗粒度控制**:一次无脏数据的写入完成后,计时器会在首个脏事件到达时启动;对于持续但未达到条数阈值的事件流,系统每个间隔写入一次,而不采用滑动窗口。 +- **`coldSnapshot` 读取不去重**——同一会话的两个并发冷读各跑一遍阶梯;写回最后者胜(行等价),对列表级调用频率可接受。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js new file mode 100644 index 0000000..9fe86d4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js @@ -0,0 +1,286 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { snapshotJsonValue } from "@deepseek-ai/dsh-session"; +import { z as z$1 } from "zod"; +import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain"; +//#region lib/types/spec.js +/** +* The session-projcache domain declaration: one `sessions` table keyed by +* {@link SessionId}, each record the full projection checkpoint for one +* session (`key → {ver, seq, val}` rows). The spec object +* is the single source of the domain's identity, version, and record schema; +* the storage-domain routing decides the medium (the shipped composition's +* json backend lands it at `/session_projcache.json`, beside +* `workspace.json`). +* @module @deepseek-ai/dsh-session-projection-cache/src/spec +*/ +/** +* One persisted checkpoint row (the RFC's `(sessionId, key, ver, seq, val)` +* minus the two record keys). `val` is the unit's internal state — plain +* JSON by the unit contract; `z.json()` enforces that at the durable +* boundary. A row is never wrong, only possibly stale: `seq` says exactly +* how stale, and a `ver` mismatch against the live unit's `stateVersion` +* discards it at read time (never a migration). +*/ +const checkpointRow = z$1.object({ + ver: z$1.number().int().nonnegative(), + seq: z$1.number().int().gte(-1), + val: z$1.json() +}); +/** +* The stored-log identity a record is bound to: the immutable header fields +* that distinguish one session lifecycle from another under the same id. A +* session id names a slot, not a lifecycle — a deleted-then-recreated id, or +* a persistence root swapped under a surviving cache, would otherwise let an +* old row pass every watermark check and seed state folded from an unrelated +* log. Reads validate this against the live header (listing) or the stored +* header (cold read) before accepting any row. +*/ +const checkpointIdentity = z$1.object({ + createdAt: z$1.number().int().nonnegative(), + cwd: z$1.string().optional() +}); +/** +* One session's stored record: the log identity it was folded from plus its +* checkpoint rows keyed by projection key. The whole record is replaced on +* every write (whole-value discipline — the registry checkpoint is always +* the complete per-session cut). +*/ +const checkpointRecord = z$1.object({ + identity: checkpointIdentity, + rows: z$1.record(z$1.string(), checkpointRow) +}); +/** +* The session-projcache domain spec. Version bumps discard the whole medium +* (cache semantics: a stale or unreadable cache costs a longer tail replay, +* never a wrong value). +*/ +const projectionCacheDomainSpec = defineDomain({ + name: "session_projcache", + version: 3, + tables: { sessions: domainTable(checkpointRecord) } +}); +//#endregion +//#region lib/types/index.js +/** +* Persisted projection cache (`ctx.sessionProjectionCache`): durable +* checkpoints of every registered projection unit's state, one record per +* session on the domain data form (`session_projcache` domain — the shipped +* json backend lands it beside `workspace.json`). The cache is a fold +* shortcut, never an authority: a row is possibly stale (its `seq` +* says how stale) but never wrong, so every write path is fail-soft (a lost +* write costs a longer tail replay on the next cold read) and a +* `ver` mismatch discards the row instead of migrating it. Design +* authority: the session-projection RFC +* (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md). +* @module @deepseek-ai/dsh-session-projection-cache +*/ +const Config = z.object({ + writeEveryEvents: z.natural().min(1).required(), + writeIntervalMs: z.natural().min(1).required() +}); +/** +* The persisted projection cache service. Opens the `session_projcache` +* domain at init, checkpoints live sessions on a throttled write-behind +* (count/interval triggers from {@link Config}) plus two mandatory points — +* `turn/end` and session disposal (the live-to-cold moment) — and serves the +* cold-read ladder: cached row, persistence `readFrom` tail, registry +* `restore`, durable write-back. Every durable write is fail-soft: failures +* log a warning and the cache self-heals on the next write or cold read. +*/ +var SessionProjectionCache = class extends Service { + config; + static inject = [ + "storageDomain", + "sessionProjections", + "sessionPersistence", + "sessions" + ]; + static Config = Config; + table; + dirty = /* @__PURE__ */ new Map(); + constructor(ctx, config) { + super(ctx, "sessionProjectionCache"); + this.config = config; + } + /** Open the domain and install the write-behind listeners. */ + async [Service.init]() { + const domain = await this.ctx.storageDomain.open(projectionCacheDomainSpec); + this.ctx.effect(() => () => domain.close(), "sessionProjectionCache.domainClose"); + this.table = domain.table("sessions"); + this.installWritePath(); + } + /** + * The stored record for one session, accepted only when its bound log + * identity matches `expected`. A session id names a slot, not a lifecycle: + * a recreated id or a persistence store swapped under a surviving cache + * must not let an old record seed state folded from an unrelated log. + * Synchronous from the domain's in-memory state. + * @param id - the session whose record is read. + * @param expected - the log identity the caller holds (live or stored header). + * @returns the identity-matching record, or `undefined` (absent or unrelated). + */ + recordFor(id, expected) { + const record = this.requireTable().get(id); + if (record === void 0) return void 0; + return identityMatches(record.identity, expected) ? record : void 0; + } + /** + * The zero-I/O listing read: whole values viewed straight from the stored + * rows (version-matching keys only), each cut carried with its watermark + * so a client value store can seed under its higher-seq-wins rule — as + * stale as the last durable checkpoint but never wrong, and never from an + * unrelated log (the caller's header is the identity witness). Fresher + * paths (the history tail baseline, {@link coldSnapshot}) supersede these + * values whenever a session is actually opened. + * @param meta - the listed session's header (identity witness; no log read). + * @returns the cut (`asOfSeq` = lowest served-row watermark), or + * `undefined` when no usable row exists for this lifecycle. + */ + cachedSnapshot(meta) { + const record = this.recordFor(meta.id, identityOf(meta)); + if (record === void 0) return void 0; + const values = this.ctx.sessionProjections.viewCheckpoint(record.rows); + const keys = Object.keys(values); + if (keys.length === 0) return void 0; + return { + asOfSeq: Math.min(...keys.map((key) => record.rows[key].seq)), + values + }; + } + /** + * Durably checkpoint one live session NOW (both mandatory points call + * this; tests and carriers may too). The registry cut is snapshotted at + * this boundary (states are live references), then the whole record is + * replaced. NOT fail-soft — callers on the fail-soft paths contain it. + * @param session - the live session to checkpoint. + * @returns resolution after durability and event emission. + */ + async write(session) { + const rows = this.ctx.sessionProjections.checkpoint(session); + this.markClean(session); + if (this.ctx.sessions.get(session.id) === session) await this.ctx.sessions.flush(session); + await this.put(session.id, identityOf(session.header), rows); + } + /** + * Cold-read one persisted session's projections with zero full-log load: + * cached rows + a persistence `readFrom` tail from the registry's restore + * floor, refolded by the registry and written back (fail-soft) so the next + * cold read starts closer. A cache row invalidated by a shrunk log + * (crash-repair truncation) triggers one full re-read from seq 0 — the + * ladder's slow rung, still no crash. Rejects when the session has no + * persisted log (`not found` from the persistence seam). + * @param id - the persisted session to read. + * @param signal - optional cancellation for the persistence reads. + * @returns the snapshot cut at the stored log end. + */ + async coldSnapshot(id, signal) { + const record = this.requireTable().get(id); + const cached = record?.rows ?? {}; + const floor = this.ctx.sessionProjections.restoreFloor(cached); + const persistence = this.ctx.sessionPersistence; + if (floor === void 0) return { + asOfSeq: (await persistence.readFrom(id, 0, signal)).events.at(-1)?.seq ?? -1, + values: {} + }; + let restored; + const tail = await persistence.readFrom(id, floor, signal); + const related = record === void 0 || identityMatches(record.identity, identityOf(tail.meta)); + try { + if (!related) throw new Error("unrelated log identity"); + restored = this.ctx.sessionProjections.restore(cached, tail.events, floor); + } catch { + const whole = await persistence.readFrom(id, 0, signal); + restored = this.ctx.sessionProjections.restore({}, whole.events, 0); + } + await this.putSoft(id, identityOf(tail.meta), restored.checkpoint, "cold-read write-back"); + return restored.snapshot; + } + installWritePath() { + this.ctx.on("session/event", (session, event) => { + if (event.type === "turn/end") { + this.flushSoft(session, "turn/end"); + return; + } + const state = this.dirty.get(session) ?? { + pending: 0, + timer: void 0 + }; + this.dirty.set(session, state); + state.pending += 1; + if (state.pending >= this.config.writeEveryEvents) { + this.flushSoft(session, "count threshold"); + return; + } + state.timer ??= setTimeout(() => { + this.flushSoft(session, "interval"); + }, this.config.writeIntervalMs); + }); + this.ctx.on("session/disposed", (session) => { + this.flushSoft(session, "detach"); + this.markClean(session); + this.dirty.delete(session); + }); + this.ctx.effect(() => () => { + for (const state of this.dirty.values()) if (state.timer !== void 0) clearTimeout(state.timer); + this.dirty.clear(); + }, "sessionProjectionCache.timers"); + } + /** + * One fail-soft durable checkpoint. Every caller has work by construction: + * the throttle triggers only fire dirty (markClean clears the timer with + * the counter) and the two mandatory points write unconditionally. + */ + async flushSoft(session, trigger) { + try { + await this.write(session); + } catch (error) { + this.ctx.logger.warn(`session projection cache: ${trigger} write for "${session.id}" failed (cache stays stale): ${String(error)}`); + } + } + /** Reset one session's dirty bookkeeping (its checkpoint is being written). */ + markClean(session) { + const state = this.dirty.get(session); + if (state === void 0) return; + state.pending = 0; + if (state.timer !== void 0) { + clearTimeout(state.timer); + state.timer = void 0; + } + } + /** Replace one session's stored record with its log identity and a detached snapshot of `rows`. */ + async put(id, identity, rows) { + const detached = snapshotJsonValue(rows); + if (detached === void 0) throw new TypeError("projection checkpoint is not losslessly JSON-serializable (a unit state violates the plain-JSON contract)"); + await this.requireTable().put(id, { + identity, + rows: detached + }); + } + /** Fail-soft {@link put}: cache writes must never fail their caller's read or event path. */ + async putSoft(id, identity, rows, what) { + try { + await this.put(id, identity, rows); + } catch (error) { + this.ctx.logger.warn(`session projection cache: ${what} for "${id}" failed (cache stays stale): ${String(error)}`); + } + } + requireTable() { + /* v8 ignore next -- Service.init assigns the table before the service becomes injectable */ + if (this.table === void 0) throw new Error("session projection cache is not initialized"); + return this.table; + } +}; +/** Project a header onto the identity fields a record is bound to. */ +function identityOf(header) { + return { + createdAt: header.createdAt, + ...header.cwd === void 0 ? {} : { cwd: header.cwd } + }; +} +/** Whether a stored record's bound identity names the caller's lifecycle. */ +function identityMatches(stored, expected) { + return stored.createdAt === expected.createdAt && stored.cwd === expected.cwd; +} +//#endregion +export { Config, SessionProjectionCache, SessionProjectionCache as default, checkpointIdentity, checkpointRecord, checkpointRow, projectionCacheDomainSpec }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/invariant.js new file mode 100644 index 0000000..8cb72da --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/invariant.js @@ -0,0 +1,28 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-session-projection-cache`. +* @module @deepseek-ai/dsh-session-projection-cache/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session-projection-cache"; +/** Cordis companion plugin name. */ +const name = "session-projection-cache-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the cache's correctness relation (a stored row equals +* the registry fold at its `seq` watermark) is only checkable by re-running the +* fold over the persisted log — duplicating the implementation rather than +* detecting drift — and its staleness is by design (fail-soft writes). The +* durable boundary is already schema-validated by the storage-domain layer +* on every reopen, and the read ladder's version/watermark guards are proven +* by the package spec. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts new file mode 100644 index 0000000..823177c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts @@ -0,0 +1,118 @@ +/** + * Persisted projection cache (`ctx.sessionProjectionCache`): durable + * checkpoints of every registered projection unit's state, one record per + * session on the domain data form (`session_projcache` domain — the shipped + * json backend lands it beside `workspace.json`). The cache is a fold + * shortcut, never an authority: a row is possibly stale (its `seq` + * says how stale) but never wrong, so every write path is fail-soft (a lost + * write costs a longer tail replay on the next cold read) and a + * `ver` mismatch discards the row instead of migrating it. Design + * authority: the session-projection RFC + * (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md). + * @module @deepseek-ai/dsh-session-projection-cache + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { Session, SessionHeader, SessionId } from '@deepseek-ai/dsh-session'; +import type { ProjectionSnapshot } from '@deepseek-ai/dsh-session-projection'; +export { checkpointIdentity, checkpointRecord, checkpointRow, projectionCacheDomainSpec } from './spec.ts'; +export type { CheckpointIdentity, CheckpointRecord } from './spec.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + sessionProjectionCache: SessionProjectionCache; + } +} +/** + * Plugin config. Both throttle triggers are deployment choices with no + * universally correct value, so the composition states them explicitly + * (cordis.yml); the two mandatory write points (`turn/end` and session + * disposal) are policy, not tunables, and always fire. + */ +export interface Config { + /** Committed events per session that force a durable checkpoint write between mandatory points. */ + writeEveryEvents: number; + /** Longest time (milliseconds) a dirty checkpoint may stay unwritten between mandatory points. */ + writeIntervalMs: number; +} +export declare const Config: z; +/** + * The persisted projection cache service. Opens the `session_projcache` + * domain at init, checkpoints live sessions on a throttled write-behind + * (count/interval triggers from {@link Config}) plus two mandatory points — + * `turn/end` and session disposal (the live-to-cold moment) — and serves the + * cold-read ladder: cached row, persistence `readFrom` tail, registry + * `restore`, durable write-back. Every durable write is fail-soft: failures + * log a warning and the cache self-heals on the next write or cold read. + */ +export declare class SessionProjectionCache extends Service { + config: Config; + static inject: string[]; + static Config: z; + private table?; + private readonly dirty; + constructor(ctx: Context, config: Config); + /** Open the domain and install the write-behind listeners. */ + protected [Service.init](): Promise; + /** + * The stored record for one session, accepted only when its bound log + * identity matches `expected`. A session id names a slot, not a lifecycle: + * a recreated id or a persistence store swapped under a surviving cache + * must not let an old record seed state folded from an unrelated log. + * Synchronous from the domain's in-memory state. + * @param id - the session whose record is read. + * @param expected - the log identity the caller holds (live or stored header). + * @returns the identity-matching record, or `undefined` (absent or unrelated). + */ + private recordFor; + /** + * The zero-I/O listing read: whole values viewed straight from the stored + * rows (version-matching keys only), each cut carried with its watermark + * so a client value store can seed under its higher-seq-wins rule — as + * stale as the last durable checkpoint but never wrong, and never from an + * unrelated log (the caller's header is the identity witness). Fresher + * paths (the history tail baseline, {@link coldSnapshot}) supersede these + * values whenever a session is actually opened. + * @param meta - the listed session's header (identity witness; no log read). + * @returns the cut (`asOfSeq` = lowest served-row watermark), or + * `undefined` when no usable row exists for this lifecycle. + */ + cachedSnapshot(meta: SessionHeader): ProjectionSnapshot | undefined; + /** + * Durably checkpoint one live session NOW (both mandatory points call + * this; tests and carriers may too). The registry cut is snapshotted at + * this boundary (states are live references), then the whole record is + * replaced. NOT fail-soft — callers on the fail-soft paths contain it. + * @param session - the live session to checkpoint. + * @returns resolution after durability and event emission. + */ + write(session: Session): Promise; + /** + * Cold-read one persisted session's projections with zero full-log load: + * cached rows + a persistence `readFrom` tail from the registry's restore + * floor, refolded by the registry and written back (fail-soft) so the next + * cold read starts closer. A cache row invalidated by a shrunk log + * (crash-repair truncation) triggers one full re-read from seq 0 — the + * ladder's slow rung, still no crash. Rejects when the session has no + * persisted log (`not found` from the persistence seam). + * @param id - the persisted session to read. + * @param signal - optional cancellation for the persistence reads. + * @returns the snapshot cut at the stored log end. + */ + coldSnapshot(id: SessionId, signal?: AbortSignal): Promise; + private installWritePath; + /** + * One fail-soft durable checkpoint. Every caller has work by construction: + * the throttle triggers only fire dirty (markClean clears the timer with + * the counter) and the two mandatory points write unconditionally. + */ + private flushSoft; + /** Reset one session's dirty bookkeeping (its checkpoint is being written). */ + private markClean; + /** Replace one session's stored record with its log identity and a detached snapshot of `rows`. */ + private put; + /** Fail-soft {@link put}: cache writes must never fail their caller's read or event path. */ + private putSoft; + private requireTable; +} +export default SessionProjectionCache; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/invariant.d.ts new file mode 100644 index 0000000..5e6839f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-projection-cache`. + * @module @deepseek-ai/dsh-session-projection-cache/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-projection-cache-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/spec.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/spec.d.ts new file mode 100644 index 0000000..35a2c82 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/spec.d.ts @@ -0,0 +1,82 @@ +/** + * The session-projcache domain declaration: one `sessions` table keyed by + * {@link SessionId}, each record the full projection checkpoint for one + * session (`key → {ver, seq, val}` rows). The spec object + * is the single source of the domain's identity, version, and record schema; + * the storage-domain routing decides the medium (the shipped composition's + * json backend lands it at `/session_projcache.json`, beside + * `workspace.json`). + * @module @deepseek-ai/dsh-session-projection-cache/src/spec + */ +import { z } from 'zod'; +import { SessionId } from '@deepseek-ai/dsh-session'; +/** + * One persisted checkpoint row (the RFC's `(sessionId, key, ver, seq, val)` + * minus the two record keys). `val` is the unit's internal state — plain + * JSON by the unit contract; `z.json()` enforces that at the durable + * boundary. A row is never wrong, only possibly stale: `seq` says exactly + * how stale, and a `ver` mismatch against the live unit's `stateVersion` + * discards it at read time (never a migration). + */ +export declare const checkpointRow: z.ZodObject<{ + ver: z.ZodNumber; + seq: z.ZodNumber; + val: z.ZodJSONSchema; +}, z.core.$strip>; +/** + * The stored-log identity a record is bound to: the immutable header fields + * that distinguish one session lifecycle from another under the same id. A + * session id names a slot, not a lifecycle — a deleted-then-recreated id, or + * a persistence root swapped under a surviving cache, would otherwise let an + * old row pass every watermark check and seed state folded from an unrelated + * log. Reads validate this against the live header (listing) or the stored + * header (cold read) before accepting any row. + */ +export declare const checkpointIdentity: z.ZodObject<{ + createdAt: z.ZodNumber; + cwd: z.ZodOptional; +}, z.core.$strip>; +/** The identity fields a record is bound to, inferred from {@link checkpointIdentity}. */ +export type CheckpointIdentity = z.infer; +/** + * One session's stored record: the log identity it was folded from plus its + * checkpoint rows keyed by projection key. The whole record is replaced on + * every write (whole-value discipline — the registry checkpoint is always + * the complete per-session cut). + */ +export declare const checkpointRecord: z.ZodObject<{ + identity: z.ZodObject<{ + createdAt: z.ZodNumber; + cwd: z.ZodOptional; + }, z.core.$strip>; + rows: z.ZodRecord>; +}, z.core.$strip>; +/** One stored per-session checkpoint record, inferred from {@link checkpointRecord}. */ +export type CheckpointRecord = z.infer; +/** + * The session-projcache domain spec. Version bumps discard the whole medium + * (cache semantics: a stale or unreadable cache costs a longer tail replay, + * never a wrong value). + */ +export declare const projectionCacheDomainSpec: { + name: string; + version: number; + tables: { + sessions: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec; + }>; + }; +}; +//# sourceMappingURL=spec.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/package.json new file mode 100644 index 0000000..2de52ca --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache/package.json @@ -0,0 +1,55 @@ +{ + "name": "@deepseek-ai/dsh-session-projection-cache", + "description": "Persisted projection cache (ctx.sessionProjectionCache): durable per-session projection checkpoints over the domain data form, throttled write-behind, and the cold-read ladder (cache row + persistence tail replay)", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session/session-projection-cache" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-storage-domain b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-storage-domain new file mode 120000 index 0000000..f157433 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-storage-domain @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.i18n.yaml new file mode 100644 index 0000000..fb26401 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/session/session-projection/README.md +README.md: 9018b133bb69ed4717fede14c9a2070a07c3fa62 +README.zh.md: 2a3af5620f84ff9697268101a6cfb894232b68b7 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.md new file mode 100644 index 0000000..9018b13 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.md @@ -0,0 +1,48 @@ +# @deepseek-ai/dsh-session-projection + +English | [中文](README.zh.md) + +Session-projection Service Definition and drive registry. It owns `ctx.sessionProjections`, the registry that drives every registered projection unit over committed session events and serves finished whole values to carriers, currently the api-proxy history tail page and `session/projection` push frame. A domain registers pure mathematics; the framework owns the drive. The [session-projection RFC](../../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md) records the design rationale. + +## Service: `SessionProjectionRegistry` (ctx key: `sessionProjections`) + +### Public API + +- `ctx.sessionProjections.register(definition): () => void` Register one domain's unit. Duplicate keys and invalid `stateVersion` throw; the registration is an effect on the calling fiber, so an unloaded domain plugin's key (with its cached cells) disappears from subsequent drives and snapshots — clients read that as capability absence. +- `ctx.sessionProjections.onChanged(listener): () => void` Subscribe to the change feed: one call per unit whose state reference changed, per committed event, carrying the schema-validated view and the causing seq. Effect-tied like `register`. +- `ctx.sessionProjections.snapshot(session): ProjectionSnapshot` One consistent synchronous cut over every registered unit — `{ asOfSeq, values }` with `asOfSeq` = the seq of the last event every value reflects (`-1` for an empty log). + +### Key Types + +- `SessionProjectionMap` — the single merge-extensible type table for the whole chain (host unit, wire block, React hook). Values are wire-JSON whole values; rendering belongs to the slot system, never this layer. +- `ProjectionDefinition` — `{ key, schema, init(), apply(state, event), view(state), stateVersion }`: a state-driven computation unit of three pure synchronous functions plus declarations, never an opaque getter. + +## Contract + +- **The framework drives, the domain computes.** The registry subscribes to `session/event` once; every committed event passes every unit's `apply` eagerly. Domains hold no subscriptions. Cells (`{state, observedSeq}` per unit per session, WeakMap-keyed) build lazily — a unit registered after events flowed, or a read of a session predating the registration, folds `init` over the in-memory log on first touch. +- **Same-reference means no work.** `apply` MUST return the same state reference for events that do not concern the unit; the drive gates the change feed on `Object.is`, so non-matching events cost one call and nothing downstream. +- **Whole-value event rule (load-bearing).** A state-carrying log event MUST carry the complete post-change state, never a bare delta — it keeps every transition trivially cheap and every served value self-describing (last-wins for consumers). +- **Synchronous unit discipline.** `init`/`apply`/`view` MUST be synchronous; carriers read `snapshot()` in the same tick as their page slice, which is what makes `asOfSeq` one consistent cut. An accidentally-async `view` returns a Promise, which fails the boundary `schema.parse` loudly. +- **State is plain JSON, `stateVersion` is its invalidation anchor.** The persisted projection cache stores `(sessionId, key, ver, seq, val)` rows; bump `stateVersion` whenever the state shape or the fold semantics change so stale rows are discarded instead of forward-applied into garbage. +- **No wire vocabulary here.** The registry exposes only the change feed and the snapshot read face; carriers (api-proxy) mint their own frames (`session/projection`) and blocks from them. +- **Optional capability.** Domain plugins register under `ctx.inject(['sessionProjections'], …)` so headless assemblies without the registry stay unaffected; carriers use `ctx.get('sessionProjections')` and omit their block/frames entirely when the registry is absent. + +## Role + +This package owns the Service Definition and drive roles of the capability seam: domain host plugins (e.g. `dsh-tool-todo`) contribute units, carriers (`dsh-host-apiproxy`) consume the snapshot and change feed, and neither knows the other. + +## Model Experience + +None, as the registry only computes client-facing read models of already-logged session state and touches no prompt, message, schema, stream, or tool result. + +#### KV Cache effect + +None; projections never assemble or send provider requests. + +## Known Limitations and Deferred Work + +- **Every tail page carries every registered key** — there is no per-key opt-out or lazy-key request shape yet; acceptable while values are UI-scale whole states (a todo list, a goal snapshot), revisit if a domain's value grows large. +- **The unit table is process-wide, so key presence is not a per-session capability signal** — a key registered by ANY agent preset appears in every session's snapshot, including sessions whose own composition mounts nothing that produces it. A client must read the VALUE (`plan.active`, an empty todo list) rather than treat an absent key as absence of the feature; a unit whose empty value is indistinguishable from a real one belongs on the host plane instead, which is why `dsh-token-meter` sits there. +- **Eager drive touches every unit per event** — cheap by construction (whole-value rule, same-reference gate), but a hot path would justify per-unit event-type prefilters, addable without contract change. +- **Registry cells live in memory only** — a restart rebuilds by folding the log on first touch; compositions that mount `dsh-session-projection-cache` seed that fold from persisted rows instead. +- **Synchronous unit discipline is only partially mechanical** — the boundary `schema.parse` rejects a Promise-returning `view`, but an `apply` that blocks or reads torn non-session state is a review concern; the invariant companion documents why no runtime check exists. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.zh.md new file mode 100644 index 0000000..2a3af56 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/README.zh.md @@ -0,0 +1,48 @@ +# @deepseek-ai/dsh-session-projection + +[English](README.md) | 中文 + +会话投影 Service Definition 与驱动注册表。它拥有 `ctx.sessionProjections`:该注册表在已提交的会话事件上驱动每个已注册的投影单元,并向载体提供完整的最终值,目前包括 api-proxy 历史尾页和 `session/projection` 推送帧。领域注册的只是纯数学;驱动权归框架。[session-projection RFC](../../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md) 记录了设计理由。 + +## 服务:`SessionProjectionRegistry`(ctx 键:`sessionProjections`) + +### 公开 API + +- `ctx.sessionProjections.register(definition): () => void` 注册一个领域的单元。key 重复或 `stateVersion` 非法都会 throw;注册是挂在调用方 fiber 上的 effect,领域插件卸载后其 key(连同缓存的 cell)从后续驱动与快照中消失——客户端将其读作能力缺失。 +- `ctx.sessionProjections.onChanged(listener): () => void` 订阅变更流:每个已提交事件、每个状态引用发生变化的单元各回调一次,携带经 schema 校验的 view 与致因 seq。与 `register` 一样绑定 effect。 +- `ctx.sessionProjections.snapshot(session): ProjectionSnapshot` 对全部已注册单元做一次一致的同步切面——`{ asOfSeq, values }`,其中 `asOfSeq` = 所有值共同反映到的最后一个事件的 seq(空日志为 `-1`)。 + +### 关键类型 + +- `SessionProjectionMap`——整条链路唯一的 merge-extensible 类型表(host 侧单元、协议块、React 钩子)。值是协议层 JSON 全量值;渲染归 slot 体系管,永远不归本层。 +- `ProjectionDefinition`——`{ key, schema, init(), apply(state, event), view(state), stateVersion }`:由三个纯同步函数外加若干声明构成的状态驱动计算单元(state-driven computation unit),绝不是一个不透明的 getter。 + +## 约定 + +- **框架负责驱动,领域负责计算。** 注册表只订阅一次 `session/event`;每个已提交事件都会主动经过每个单元的 `apply`。领域不持有任何订阅。cell(每会话每单元一份 `{state, observedSeq}`,以 WeakMap 为键)惰性构建——在事件流过之后才注册的单元,或读取一个早于该注册的会话,都在首次触达时从 `init` 出发在内存日志上折叠。 +- **同引用即无工作。** 对与单元无关的事件,`apply` 必须返回同一个状态引用;驱动以 `Object.is` 把守变更流,因此不匹配的事件只花一次调用,不产生任何下游工作。 +- **全量值事件规则(承重)。** 携带状态的日志事件必须携带变更后的完整状态,绝不携带裸增量——这让每次状态转移始终足够廉价,也让每个被供给的值自描述(对消费方即 last-wins)。 +- **单元的同步纪律。**`init`/`apply`/`view` 必须是同步的;载体在切出页面切片的同一 tick 内读取 `snapshot()`,`asOfSeq` 之所以是一个一致切面正系于此。误写成异步的 `view` 会返回 Promise,让边界的 `schema.parse` 当场大声失败。 +- **状态是纯 JSON,`stateVersion` 是其失效锚点。** 持久投影缓存(persisted projection cache)存储 `(sessionId, key, ver, seq, val)` 行;状态形状或折叠语义一旦变化就递增 `stateVersion`,使陈旧行被丢弃,而不是被正向 apply 成垃圾。 +- **本层没有协议词汇。** 注册表只暴露变更流与快照读取面;载体(api-proxy)据此自铸各自的帧(`session/projection`)与块。 +- **可选能力。** 领域插件在 `ctx.inject(['sessionProjections'], …)` 下注册,因此不带注册表的 headless 组装完全不受影响;载体使用 `ctx.get('sessionProjections')`,注册表缺席时完全省略自己的块与帧。 + +## 职责 + +本包承担能力 seam 的 Service Definition 与驱动角色:领域 host 插件(如 `dsh-tool-todo`)贡献单元,载体(`dsh-host-apiproxy`)消费快照与变更流,两侧互不相识。 + +## 模型体验 + +无——注册表只对已入日志的会话状态计算面向客户端的读模型,不触碰任何提示词、消息、schema、流或工具结果。 + +#### KV Cache 影响 + +无;投影从不组装或发送提供方请求。 + +## 已知限制与暂缓事项 + +- **每个尾页携带每个已注册的 key**——尚无逐 key 的 opt-out 或惰性 key 请求形状;在值都是 UI 量级的全量状态(一张 todo 清单、一份 goal 快照)时可以接受,若某领域的值变大再重议。 +- **单元表是进程级的,因此 key 是否存在不能当作逐会话的能力信号**——只要**任何**一个 agent preset 注册了某个 key,它就出现在每个会话的快照里,包括自身组装完全不产出该值的会话。客户端必须读**值**(`plan.active`、空的 todo 列表),不能把 key 缺席当作功能缺席;如果某个单元的空值与真实值无法区分,它就该待在宿主平面——`dsh-token-meter` 正因如此留在那里。 +- **主动驱动(eager drive)逐事件触达每个单元**——按构造开销很低(全量值规则、同引用闸门),但若出现热点路径,可加按单元的事件类型预过滤,约定不变。 +- **注册表 cell 只活在内存里**——重启后首次触达时靠折叠日志重建;挂载了 `dsh-session-projection-cache` 的组合改由持久行播种该折叠。 +- **单元同步纪律只有部分可机械把关**——边界 `schema.parse` 能拒绝返回 Promise 的 `view`,但阻塞的 `apply`、或读取撕裂的非会话状态的 `apply`,只能靠评审把关;invariant 配套项记载了为何不存在运行时检查。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/index.js new file mode 100644 index 0000000..88c5137 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/index.js @@ -0,0 +1,274 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/index.js +/** +* Service Definition and drive registry for the session-projection capability seam: the merge-extensible `SessionProjectionMap` type +* table, the `ProjectionDefinition` state-driven computation unit contract, +* and the `ctx.sessionProjections` registry that DRIVES every registered unit +* forward eagerly over committed session events. Domain host plugins +* contribute pure mathematics (init/apply/view); the framework owns the +* subscription, the per-session watermark cache, and change notification; +* carriers consume the snapshot read face and the change feed. Neither side +* knows the other +* (capability-seam three-way split). Design authority: the session-projection +* RFC (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md). +* +* Whole-value event rule (load-bearing): a state-carrying log event MUST +* carry the complete post-change state, never a bare delta — it keeps every +* unit's transition trivially cheap and every served value self-describing. +* +* @module @deepseek-ai/dsh-session-projection +*/ +/** +* `ctx.sessionProjections`: the projection unit table and its drive. The +* service subscribes to `session/event` once; every committed event passes +* every registered unit's `apply` (eager drive), and a changed state +* reference notifies the change feed with the schema-validated view. +* Cells build lazily — a unit registered after events flowed, or a session +* older than the registry, folds `init` over the in-memory log on first +* touch (event or read). Registration is an effect (disposer rides the +* calling fiber): an unloaded domain plugin's key disappears from snapshots +* and clients read it as capability absence. Domain +* plugins register under `ctx.inject(['sessionProjections'], …)` so headless +* assemblies without the registry stay unaffected. Registrants sharing a key +* share one unit and are counted: the same tool package mounted in N agent +* presets registers N times, and the key survives until the last one +* unloads. +*/ +var SessionProjectionRegistry = class extends Service { + registrations = /* @__PURE__ */ new Map(); + listeners = /* @__PURE__ */ new Set(); + /** + * Create and install the registry as `ctx.sessionProjections`. + * @param ctx - Cordis context that owns the service. + */ + constructor(ctx) { + super(ctx, "sessionProjections"); + ctx.on("session/event", (session, event) => { + this.drive(session, event); + }); + } + /** + * Register one domain's unit. The registration is an effect on the calling + * context's fiber: disposing the fiber (or calling the returned disposer) + * removes the key — and the unit's cached cells — from subsequent drives + * and snapshots. + * @param definition - key, state schema, pure unit functions, and stateVersion. + * @returns the exact disposer that unregisters this unit. + */ + register(definition) { + if (!Number.isSafeInteger(definition.stateVersion) || definition.stateVersion < 0) throw new Error(`session projection ${JSON.stringify(definition.key)} stateVersion must be a non-negative integer, got ${String(definition.stateVersion)}`); + const dispose = this.ctx.effect(function* () { + const key = definition.key; + const existing = this.registrations.get(key); + if (existing === void 0) this.registrations.set(key, { + def: definition, + cells: /* @__PURE__ */ new WeakMap(), + refs: 1 + }); + else { + if (existing.def.stateVersion !== definition.stateVersion) throw new Error(`session projection key ${JSON.stringify(key)} is already registered at stateVersion ${String(existing.def.stateVersion)}; refusing to share it with stateVersion ${String(definition.stateVersion)}`); + existing.refs += 1; + } + yield () => { + const live = this.registrations.get(key); + /* v8 ignore next -- the disposer runs once per successful registration, so the entry it counted is still here */ + if (live === void 0) return; + live.refs -= 1; + if (live.refs === 0) this.registrations.delete(key); + }; + }.bind(this), "sessionProjections.register()"); + return () => void dispose(); + } + /** + * Subscribe to the change feed. The registration is an effect on the + * calling context's fiber. + * @param listener - called once per unit whose state reference changed, per committed event. + * @returns the exact disposer that unsubscribes. + */ + onChanged(listener) { + const dispose = this.ctx.effect(() => { + this.listeners.add(listener); + return () => { + this.listeners.delete(listener); + }; + }, "sessionProjections.onChanged()"); + return () => void dispose(); + } + /** + * One consistent cut over every registered unit for one session, read from + * the watermark cache (missing cells fold lazily over the in-memory log). + * Fully synchronous — every value and `asOfSeq` reflect the same log + * position. Each value passes its unit's schema before leaving. + * @param session - the session whose projection values are read. + * @returns the snapshot; `values` is empty when no unit is registered. + */ + snapshot(session) { + const values = {}; + for (const registration of this.registrations.values()) { + const cell = this.cellFor(registration, session); + values[registration.def.key] = registration.def.schema.parse(registration.def.view(cell.state)); + } + return { + asOfSeq: session.seq - 1, + values + }; + } + /** + * State-level checkpoint of every registered unit for one session, read + * from the watermark cache (missing cells fold lazily over the in-memory + * log). This is the write side of the persisted projection cache: the + * returned rows are the `(key → {ver, seq, val})` part of the durable + * `(sessionId, key, ver, seq, val)` + * rows. Every `val` is a DETACHED structured clone — never the live + * cell reference: the watermark cache is this registry's authoritative + * mutable state, and a caller reaching the live reference could corrupt + * every subsequent snapshot and frame through it (plain JSON by the unit + * contract, so the clone is total). + * @param session - the session whose unit states are checkpointed. + * @returns one row per registered key; empty when no unit is registered. + */ + checkpoint(session) { + const rows = {}; + for (const registration of this.registrations.values()) { + const cell = this.cellFor(registration, session); + rows[registration.def.key] = { + ver: registration.def.stateVersion, + seq: cell.observedSeq, + val: structuredClone(cell.state) + }; + } + return rows; + } + /** + * The stored seq a {@link restore} tail read over `checkpoint` must start + * at: one event BELOW the lowest usable watermark (a row is usable when + * its `ver` matches the live unit's `stateVersion`; an absent or mismatched row + * pulls the floor to `0` — that key must refold the full log). The + * one-below anchor is load-bearing: the tail then proves how far the + * stored log still extends, so {@link restore} can detect a log that + * shrank below a row's watermark (crash-repair truncation) instead of + * serving the stale row as current — an empty tail read from the anchor + * yields an end below every watermark and the restore rejects for a full + * re-read. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns the seq to hand the persistence `readFrom`, or `undefined` + * when no unit is registered (no read needed — {@link restore} would + * serve empty values regardless). + */ + restoreFloor(checkpoint) { + let floor; + for (const registration of this.registrations.values()) { + const row = checkpoint[registration.def.key]; + const need = row !== void 0 && row.ver === registration.def.stateVersion ? Math.max(row.seq + 1, 0) : 0; + floor = floor === void 0 ? need : Math.min(floor, need); + } + return floor === void 0 ? void 0 : Math.max(floor - 1, 0); + } + /** + * View a checkpoint's rows without any log read: for every registered + * unit whose row's `ver` matches, serve the schema-validated + * `view` of the stored state; mismatched or absent rows leave their key + * absent (a cold or listing consumer treats it as not-yet-available and a + * fuller read path refolds it). The zero-I/O rung of the read ladder — + * values are as stale as their rows, never wrong. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns whole values per key with a usable row; empty when none. + */ + viewCheckpoint(checkpoint) { + const values = {}; + for (const registration of this.registrations.values()) { + const def = registration.def; + const row = checkpoint[def.key]; + if (row === void 0 || row.ver !== def.stateVersion) continue; + values[def.key] = def.schema.parse(def.view(row.val)); + } + return values; + } + /** + * Cold read: fold every registered unit over a stored log suffix, seeding + * each from its checkpoint row when usable — the one read recipe (cached + * state + forward tail replay + `view`) applied without a live `Session`. + * Call with the events returned by a persistence + * `readFrom(id, restoreFloor(checkpoint))` and that same floor as + * `baseSeq`; the floor's one-below anchor makes the supplied end honest, + * so a shrunk log is detected here. A row is usable iff its + * `ver` matches the live unit's `stateVersion`, it does not predate `baseSeq` + * (`seq >= baseSeq - 1`), and it does not claim events past the + * supplied end (`seq <= endSeq`); an unusable row is discarded + * and its key refolds from `init` — which is only sound over the full + * log, so a discarded row with `baseSeq > 0` throws (the caller re-reads + * from seq 0, e.g. after a crash-repair truncation shrank the log below + * a row's watermark). + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @param events - the stored events with `seq >= baseSeq`, in seq order. + * @param baseSeq - the seq `events` starts at (its first event's seq when non-empty). + * @returns the snapshot cut at the supplied log end (`asOfSeq` is the last + * supplied event's seq, `baseSeq - 1` for an empty tail) plus the + * refreshed checkpoint rows at that cut, ready for a durable write-back. + */ + restore(checkpoint, events, baseSeq) { + const endSeq = events.at(-1)?.seq ?? baseSeq - 1; + const values = {}; + const refreshed = {}; + for (const registration of this.registrations.values()) { + const def = registration.def; + const row = checkpoint[def.key]; + const usable = row !== void 0 && row.ver === def.stateVersion && row.seq >= baseSeq - 1 && row.seq <= endSeq; + if (!usable && baseSeq > 0) throw new Error(`session projection ${JSON.stringify(def.key)} cannot restore from seq ${baseSeq}: its checkpoint row is missing, version-mismatched, or beyond the supplied log end; re-read from seq 0`); + let state = usable ? row.val : def.init(); + const from = usable ? row.seq : baseSeq - 1; + for (const event of events) if (event.seq > from) state = def.apply(state, event); + values[def.key] = def.schema.parse(def.view(state)); + refreshed[def.key] = { + ver: def.stateVersion, + seq: endSeq, + val: state + }; + } + return { + snapshot: { + asOfSeq: endSeq, + values + }, + checkpoint: refreshed + }; + } + /** Fold one unit from init over `events`, producing a cell watermarked at the last folded event. */ + buildCell(def, events) { + let state = def.init(); + for (const event of events) state = def.apply(state, event); + return { + state, + observedSeq: events.at(-1)?.seq ?? -1 + }; + } + /** Read (or lazily build, folding the full in-memory log) one unit's cell. */ + cellFor(registration, session) { + let cell = registration.cells.get(session); + if (cell === void 0) { + cell = this.buildCell(registration.def, session.events); + registration.cells.set(session, cell); + } + return cell; + } + /** Eager drive: pass one committed event through every registered unit; notify on changed references. */ + drive(session, event) { + for (const registration of this.registrations.values()) { + let cell = registration.cells.get(session); + if (cell === void 0) { + cell = this.buildCell(registration.def, session.events.slice(0, event.seq)); + registration.cells.set(session, cell); + } + const next = registration.def.apply(cell.state, event); + const changed = !Object.is(next, cell.state); + cell.state = next; + cell.observedSeq = event.seq; + if (changed && this.listeners.size > 0) { + const value = registration.def.schema.parse(registration.def.view(next)); + for (const listener of this.listeners) listener(session, registration.def.key, value, event.seq); + } + } + } +}; +//#endregion +export { SessionProjectionRegistry, SessionProjectionRegistry as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/invariant.js new file mode 100644 index 0000000..9a90716 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/invariant.js @@ -0,0 +1,31 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-session-projection`. +* @module @deepseek-ai/dsh-session-projection/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session-projection"; +/** Cordis companion plugin name. */ +const name = "session-projection-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the registry's own contracts (duplicate-key and +* stateVersion rejection, effect-tied removal, the Object.is change gate) are +* enforced synchronously inside the service and proven by its spec, the +* drive relation (every committed `session/event` passes every unit) would +* require re-running the drive to check — duplicating the implementation +* rather than detecting drift — and the served-value relation (every served +* key has a live registration) lives on each carrier's wire path, which +* emits no cordis event this companion could observe; carrier specs assert +* it. Synchronous-unit discipline is enforced as far as practical by the +* boundary `schema.parse` (a Promise-returning view fails loudly). +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.d.ts new file mode 100644 index 0000000..2614d9b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.d.ts @@ -0,0 +1,231 @@ +/** + * Service Definition and drive registry for the session-projection capability seam: the merge-extensible `SessionProjectionMap` type + * table, the `ProjectionDefinition` state-driven computation unit contract, + * and the `ctx.sessionProjections` registry that DRIVES every registered unit + * forward eagerly over committed session events. Domain host plugins + * contribute pure mathematics (init/apply/view); the framework owns the + * subscription, the per-session watermark cache, and change notification; + * carriers consume the snapshot read face and the change feed. Neither side + * knows the other + * (capability-seam three-way split). Design authority: the session-projection + * RFC (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md). + * + * Whole-value event rule (load-bearing): a state-carrying log event MUST + * carry the complete post-change state, never a bare delta — it keeps every + * unit's transition trivially cheap and every served value self-describing. + * + * @module @deepseek-ai/dsh-session-projection + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { ZodType } from 'zod'; +import type { Session, SessionEvent } from '@deepseek-ai/dsh-session'; +declare module '@deepseek-ai/cordis' { + interface Context { + sessionProjections: SessionProjectionRegistry; + } +} +import type { SessionProjectionMap } from './types.ts'; +export type { SessionProjectionMap } from './types.ts'; +/** + * One domain's state-driven computation unit: three pure synchronous + * functions plus declarations — never an opaque getter. The framework drives + * `apply` on every committed session event; the domain holds no + * subscriptions and owns only the mathematics. All three functions MUST be + * synchronous (an async unit would tear the carriers' consistency cut) and + * `state` MUST be plain JSON (the persisted-cache precondition). + */ +export interface ProjectionDefinition { + /** The projection key this unit owns (its `SessionProjectionMap` entry). */ + key: K; + /** Validates the wire payload (`view` output) before it leaves the host. */ + schema: ZodType; + /** + * State for the empty log. + * @returns the initial state. + */ + init(): S; + /** + * Pure transition: previous state + one committed event → next state. A + * unit uninterested in an event MUST return the same state reference — an + * unchanged reference (`Object.is`) produces zero downstream work. + * @param state - the state covering all prior events. + * @param event - the next committed session event. + * @returns the next state (same reference when the event is not the unit's). + */ + apply(state: S, event: SessionEvent): S; + /** + * State → wire payload (the read-side projection). + * @param state - the current state. + * @returns the whole current value for this unit's key. + */ + view(state: S): SessionProjectionMap[K]; + /** + * Persisted-cache invalidation version: bump whenever the serialized state fields or the + * fold semantics change, so persisted `(sessionId, key, ver, seq, val)` + * rows from an older unit are discarded instead of being forward-applied + * into garbage. Non-negative integer. + */ + stateVersion: number; +} +/** + * Change-feed listener: one unit's value changed for one session. `value` is + * the schema-validated `view` output; `seq` is the unit's watermark at + * emission (the seq of the event that caused the change). + */ +export type ProjectionChangeListener = (session: Session, key: Extract, value: unknown, seq: number) => void; +/** + * One consistent read cut over every registered unit for one session. + * `asOfSeq` is the shared watermark — the seq of the last event every value + * reflects (`-1` for an empty log, mirroring `session/subscribed.lastSeq`). + */ +export interface ProjectionSnapshot { + /** Seq of the last event the values reflect; -1 for an empty log. */ + asOfSeq: number; + /** Whole current value per registered key. */ + values: Partial; +} +/** + * One unit's checkpoint: its internal state (plain JSON by the unit + * contract), the seq of the last event folded into it, and the unit + * `stateVersion` that produced it — the persisted projection-cache row + * `(sessionId, key, ver, seq, val)` minus the two outer keys. A row is + * never authoritative, only a fold shortcut: `restore` discards it on a + * version mismatch or when it claims events past the stored log end. + */ +export interface ProjectionCheckpointRow { + /** The registering unit's `stateVersion` at fold time. */ + ver: number; + /** Seq of the last event folded into `val`; -1 for the empty log. */ + seq: number; + /** The unit's internal state — plain JSON per the unit contract. */ + val: unknown; +} +/** Checkpoint rows keyed by projection key (one session's persisted cache value). */ +export type ProjectionCheckpoint = Record; +/** + * `ctx.sessionProjections`: the projection unit table and its drive. The + * service subscribes to `session/event` once; every committed event passes + * every registered unit's `apply` (eager drive), and a changed state + * reference notifies the change feed with the schema-validated view. + * Cells build lazily — a unit registered after events flowed, or a session + * older than the registry, folds `init` over the in-memory log on first + * touch (event or read). Registration is an effect (disposer rides the + * calling fiber): an unloaded domain plugin's key disappears from snapshots + * and clients read it as capability absence. Domain + * plugins register under `ctx.inject(['sessionProjections'], …)` so headless + * assemblies without the registry stay unaffected. Registrants sharing a key + * share one unit and are counted: the same tool package mounted in N agent + * presets registers N times, and the key survives until the last one + * unloads. + */ +export declare class SessionProjectionRegistry extends Service { + private readonly registrations; + private readonly listeners; + /** + * Create and install the registry as `ctx.sessionProjections`. + * @param ctx - Cordis context that owns the service. + */ + constructor(ctx: Context); + /** + * Register one domain's unit. The registration is an effect on the calling + * context's fiber: disposing the fiber (or calling the returned disposer) + * removes the key — and the unit's cached cells — from subsequent drives + * and snapshots. + * @param definition - key, state schema, pure unit functions, and stateVersion. + * @returns the exact disposer that unregisters this unit. + */ + register(definition: ProjectionDefinition): () => void; + /** + * Subscribe to the change feed. The registration is an effect on the + * calling context's fiber. + * @param listener - called once per unit whose state reference changed, per committed event. + * @returns the exact disposer that unsubscribes. + */ + onChanged(listener: ProjectionChangeListener): () => void; + /** + * One consistent cut over every registered unit for one session, read from + * the watermark cache (missing cells fold lazily over the in-memory log). + * Fully synchronous — every value and `asOfSeq` reflect the same log + * position. Each value passes its unit's schema before leaving. + * @param session - the session whose projection values are read. + * @returns the snapshot; `values` is empty when no unit is registered. + */ + snapshot(session: Session): ProjectionSnapshot; + /** + * State-level checkpoint of every registered unit for one session, read + * from the watermark cache (missing cells fold lazily over the in-memory + * log). This is the write side of the persisted projection cache: the + * returned rows are the `(key → {ver, seq, val})` part of the durable + * `(sessionId, key, ver, seq, val)` + * rows. Every `val` is a DETACHED structured clone — never the live + * cell reference: the watermark cache is this registry's authoritative + * mutable state, and a caller reaching the live reference could corrupt + * every subsequent snapshot and frame through it (plain JSON by the unit + * contract, so the clone is total). + * @param session - the session whose unit states are checkpointed. + * @returns one row per registered key; empty when no unit is registered. + */ + checkpoint(session: Session): ProjectionCheckpoint; + /** + * The stored seq a {@link restore} tail read over `checkpoint` must start + * at: one event BELOW the lowest usable watermark (a row is usable when + * its `ver` matches the live unit's `stateVersion`; an absent or mismatched row + * pulls the floor to `0` — that key must refold the full log). The + * one-below anchor is load-bearing: the tail then proves how far the + * stored log still extends, so {@link restore} can detect a log that + * shrank below a row's watermark (crash-repair truncation) instead of + * serving the stale row as current — an empty tail read from the anchor + * yields an end below every watermark and the restore rejects for a full + * re-read. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns the seq to hand the persistence `readFrom`, or `undefined` + * when no unit is registered (no read needed — {@link restore} would + * serve empty values regardless). + */ + restoreFloor(checkpoint: ProjectionCheckpoint): number | undefined; + /** + * View a checkpoint's rows without any log read: for every registered + * unit whose row's `ver` matches, serve the schema-validated + * `view` of the stored state; mismatched or absent rows leave their key + * absent (a cold or listing consumer treats it as not-yet-available and a + * fuller read path refolds it). The zero-I/O rung of the read ladder — + * values are as stale as their rows, never wrong. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns whole values per key with a usable row; empty when none. + */ + viewCheckpoint(checkpoint: ProjectionCheckpoint): Partial; + /** + * Cold read: fold every registered unit over a stored log suffix, seeding + * each from its checkpoint row when usable — the one read recipe (cached + * state + forward tail replay + `view`) applied without a live `Session`. + * Call with the events returned by a persistence + * `readFrom(id, restoreFloor(checkpoint))` and that same floor as + * `baseSeq`; the floor's one-below anchor makes the supplied end honest, + * so a shrunk log is detected here. A row is usable iff its + * `ver` matches the live unit's `stateVersion`, it does not predate `baseSeq` + * (`seq >= baseSeq - 1`), and it does not claim events past the + * supplied end (`seq <= endSeq`); an unusable row is discarded + * and its key refolds from `init` — which is only sound over the full + * log, so a discarded row with `baseSeq > 0` throws (the caller re-reads + * from seq 0, e.g. after a crash-repair truncation shrank the log below + * a row's watermark). + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @param events - the stored events with `seq >= baseSeq`, in seq order. + * @param baseSeq - the seq `events` starts at (its first event's seq when non-empty). + * @returns the snapshot cut at the supplied log end (`asOfSeq` is the last + * supplied event's seq, `baseSeq - 1` for an empty tail) plus the + * refreshed checkpoint rows at that cut, ready for a durable write-back. + */ + restore(checkpoint: ProjectionCheckpoint, events: readonly SessionEvent[], baseSeq: number): { + snapshot: ProjectionSnapshot; + checkpoint: ProjectionCheckpoint; + }; + /** Fold one unit from init over `events`, producing a cell watermarked at the last folded event. */ + private buildCell; + /** Read (or lazily build, folding the full in-memory log) one unit's cell. */ + private cellFor; + /** Eager drive: pass one committed event through every registered unit; notify on changed references. */ + private drive; +} +export default SessionProjectionRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.js new file mode 100644 index 0000000..9c6738f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.js @@ -0,0 +1,285 @@ +/** + * Service Definition and drive registry for the session-projection capability seam: the merge-extensible `SessionProjectionMap` type + * table, the `ProjectionDefinition` state-driven computation unit contract, + * and the `ctx.sessionProjections` registry that DRIVES every registered unit + * forward eagerly over committed session events. Domain host plugins + * contribute pure mathematics (init/apply/view); the framework owns the + * subscription, the per-session watermark cache, and change notification; + * carriers consume the snapshot read face and the change feed. Neither side + * knows the other + * (capability-seam three-way split). Design authority: the session-projection + * RFC (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md). + * + * Whole-value event rule (load-bearing): a state-carrying log event MUST + * carry the complete post-change state, never a bare delta — it keeps every + * unit's transition trivially cheap and every served value self-describing. + * + * @module @deepseek-ai/dsh-session-projection + */ +import { Service } from '@deepseek-ai/cordis'; +/** + * `ctx.sessionProjections`: the projection unit table and its drive. The + * service subscribes to `session/event` once; every committed event passes + * every registered unit's `apply` (eager drive), and a changed state + * reference notifies the change feed with the schema-validated view. + * Cells build lazily — a unit registered after events flowed, or a session + * older than the registry, folds `init` over the in-memory log on first + * touch (event or read). Registration is an effect (disposer rides the + * calling fiber): an unloaded domain plugin's key disappears from snapshots + * and clients read it as capability absence. Domain + * plugins register under `ctx.inject(['sessionProjections'], …)` so headless + * assemblies without the registry stay unaffected. Registrants sharing a key + * share one unit and are counted: the same tool package mounted in N agent + * presets registers N times, and the key survives until the last one + * unloads. + */ +export class SessionProjectionRegistry extends Service { + registrations = new Map(); + listeners = new Set(); + /** + * Create and install the registry as `ctx.sessionProjections`. + * @param ctx - Cordis context that owns the service. + */ + constructor(ctx) { + super(ctx, 'sessionProjections'); + ctx.on('session/event', (session, event) => { + this.drive(session, event); + }); + } + /** + * Register one domain's unit. The registration is an effect on the calling + * context's fiber: disposing the fiber (or calling the returned disposer) + * removes the key — and the unit's cached cells — from subsequent drives + * and snapshots. + * @param definition - key, state schema, pure unit functions, and stateVersion. + * @returns the exact disposer that unregisters this unit. + */ + register(definition) { + if (!Number.isSafeInteger(definition.stateVersion) || definition.stateVersion < 0) { + throw new Error(`session projection ${JSON.stringify(definition.key)} stateVersion must be a non-negative integer, got ${String(definition.stateVersion)}`); + } + const dispose = this.ctx.effect(function* () { + const key = definition.key; + const existing = this.registrations.get(key); + if (existing === undefined) { + this.registrations.set(key, { def: definition, cells: new WeakMap(), refs: 1 }); + } + else { + // A differing `stateVersion` is the one incompatibility this can name: + // the versioned contract says the cached state shape differs, so the + // two registrants cannot share cells. Anything else about a definition + // is functions, which no runtime comparison can tell apart. + if (existing.def.stateVersion !== definition.stateVersion) { + throw new Error(`session projection key ${JSON.stringify(key)} is already registered at stateVersion ${String(existing.def.stateVersion)}; refusing to share it with stateVersion ${String(definition.stateVersion)}`); + } + existing.refs += 1; + } + yield () => { + const live = this.registrations.get(key); + /* v8 ignore next -- the disposer runs once per successful registration, so the entry it counted is still here */ + if (live === undefined) + return; + live.refs -= 1; + if (live.refs === 0) + this.registrations.delete(key); + }; + }.bind(this), 'sessionProjections.register()'); + return () => void dispose(); + } + /** + * Subscribe to the change feed. The registration is an effect on the + * calling context's fiber. + * @param listener - called once per unit whose state reference changed, per committed event. + * @returns the exact disposer that unsubscribes. + */ + onChanged(listener) { + const dispose = this.ctx.effect(() => { + this.listeners.add(listener); + return () => { + this.listeners.delete(listener); + }; + }, 'sessionProjections.onChanged()'); + return () => void dispose(); + } + /** + * One consistent cut over every registered unit for one session, read from + * the watermark cache (missing cells fold lazily over the in-memory log). + * Fully synchronous — every value and `asOfSeq` reflect the same log + * position. Each value passes its unit's schema before leaving. + * @param session - the session whose projection values are read. + * @returns the snapshot; `values` is empty when no unit is registered. + */ + snapshot(session) { + const values = {}; + for (const registration of this.registrations.values()) { + const cell = this.cellFor(registration, session); + values[registration.def.key] = registration.def.schema.parse(registration.def.view(cell.state)); + } + return { asOfSeq: session.seq - 1, values: values }; + } + /** + * State-level checkpoint of every registered unit for one session, read + * from the watermark cache (missing cells fold lazily over the in-memory + * log). This is the write side of the persisted projection cache: the + * returned rows are the `(key → {ver, seq, val})` part of the durable + * `(sessionId, key, ver, seq, val)` + * rows. Every `val` is a DETACHED structured clone — never the live + * cell reference: the watermark cache is this registry's authoritative + * mutable state, and a caller reaching the live reference could corrupt + * every subsequent snapshot and frame through it (plain JSON by the unit + * contract, so the clone is total). + * @param session - the session whose unit states are checkpointed. + * @returns one row per registered key; empty when no unit is registered. + */ + checkpoint(session) { + const rows = {}; + for (const registration of this.registrations.values()) { + const cell = this.cellFor(registration, session); + rows[registration.def.key] = { + ver: registration.def.stateVersion, + seq: cell.observedSeq, + val: structuredClone(cell.state), + }; + } + return rows; + } + /** + * The stored seq a {@link restore} tail read over `checkpoint` must start + * at: one event BELOW the lowest usable watermark (a row is usable when + * its `ver` matches the live unit's `stateVersion`; an absent or mismatched row + * pulls the floor to `0` — that key must refold the full log). The + * one-below anchor is load-bearing: the tail then proves how far the + * stored log still extends, so {@link restore} can detect a log that + * shrank below a row's watermark (crash-repair truncation) instead of + * serving the stale row as current — an empty tail read from the anchor + * yields an end below every watermark and the restore rejects for a full + * re-read. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns the seq to hand the persistence `readFrom`, or `undefined` + * when no unit is registered (no read needed — {@link restore} would + * serve empty values regardless). + */ + restoreFloor(checkpoint) { + let floor; + for (const registration of this.registrations.values()) { + const row = checkpoint[registration.def.key]; + const need = row !== undefined && row.ver === registration.def.stateVersion + ? Math.max(row.seq + 1, 0) + : 0; + floor = floor === undefined ? need : Math.min(floor, need); + } + return floor === undefined ? undefined : Math.max(floor - 1, 0); + } + /** + * View a checkpoint's rows without any log read: for every registered + * unit whose row's `ver` matches, serve the schema-validated + * `view` of the stored state; mismatched or absent rows leave their key + * absent (a cold or listing consumer treats it as not-yet-available and a + * fuller read path refolds it). The zero-I/O rung of the read ladder — + * values are as stale as their rows, never wrong. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns whole values per key with a usable row; empty when none. + */ + viewCheckpoint(checkpoint) { + const values = {}; + for (const registration of this.registrations.values()) { + const def = registration.def; + const row = checkpoint[def.key]; + if (row === undefined || row.ver !== def.stateVersion) + continue; + values[def.key] = def.schema.parse(def.view(row.val)); + } + return values; + } + /** + * Cold read: fold every registered unit over a stored log suffix, seeding + * each from its checkpoint row when usable — the one read recipe (cached + * state + forward tail replay + `view`) applied without a live `Session`. + * Call with the events returned by a persistence + * `readFrom(id, restoreFloor(checkpoint))` and that same floor as + * `baseSeq`; the floor's one-below anchor makes the supplied end honest, + * so a shrunk log is detected here. A row is usable iff its + * `ver` matches the live unit's `stateVersion`, it does not predate `baseSeq` + * (`seq >= baseSeq - 1`), and it does not claim events past the + * supplied end (`seq <= endSeq`); an unusable row is discarded + * and its key refolds from `init` — which is only sound over the full + * log, so a discarded row with `baseSeq > 0` throws (the caller re-reads + * from seq 0, e.g. after a crash-repair truncation shrank the log below + * a row's watermark). + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @param events - the stored events with `seq >= baseSeq`, in seq order. + * @param baseSeq - the seq `events` starts at (its first event's seq when non-empty). + * @returns the snapshot cut at the supplied log end (`asOfSeq` is the last + * supplied event's seq, `baseSeq - 1` for an empty tail) plus the + * refreshed checkpoint rows at that cut, ready for a durable write-back. + */ + restore(checkpoint, events, baseSeq) { + const endSeq = events.at(-1)?.seq ?? baseSeq - 1; + const values = {}; + const refreshed = {}; + for (const registration of this.registrations.values()) { + const def = registration.def; + const row = checkpoint[def.key]; + const usable = row !== undefined + && row.ver === def.stateVersion + && row.seq >= baseSeq - 1 + && row.seq <= endSeq; + if (!usable && baseSeq > 0) { + throw new Error(`session projection ${JSON.stringify(def.key)} cannot restore from seq ${baseSeq}: ` + + 'its checkpoint row is missing, version-mismatched, or beyond the supplied log end; re-read from seq 0'); + } + let state = usable ? row.val : def.init(); + const from = usable ? row.seq : baseSeq - 1; + for (const event of events) { + if (event.seq > from) + state = def.apply(state, event); + } + values[def.key] = def.schema.parse(def.view(state)); + refreshed[def.key] = { ver: def.stateVersion, seq: endSeq, val: state }; + } + return { + snapshot: { asOfSeq: endSeq, values: values }, + checkpoint: refreshed, + }; + } + /** Fold one unit from init over `events`, producing a cell watermarked at the last folded event. */ + buildCell(def, events) { + let state = def.init(); + for (const event of events) + state = def.apply(state, event); + return { state, observedSeq: (events.at(-1)?.seq ?? -1) }; + } + /** Read (or lazily build, folding the full in-memory log) one unit's cell. */ + cellFor(registration, session) { + let cell = registration.cells.get(session); + if (cell === undefined) { + cell = this.buildCell(registration.def, session.events); + registration.cells.set(session, cell); + } + return cell; + } + /** Eager drive: pass one committed event through every registered unit; notify on changed references. */ + drive(session, event) { + for (const registration of this.registrations.values()) { + let cell = registration.cells.get(session); + if (cell === undefined) { + // Late build mid-stream: fold history before this event (seq = log + // index, so the prefix slice is exact), then take the normal gate. + cell = this.buildCell(registration.def, session.events.slice(0, event.seq)); + registration.cells.set(session, cell); + } + const next = registration.def.apply(cell.state, event); + const changed = !Object.is(next, cell.state); + cell.state = next; + cell.observedSeq = event.seq; + if (changed && this.listeners.size > 0) { + const value = registration.def.schema.parse(registration.def.view(next)); + for (const listener of this.listeners) { + listener(session, registration.def.key, value, event.seq); + } + } + } + } +} +export default SessionProjectionRegistry; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.d.ts new file mode 100644 index 0000000..f3aaaf8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-projection`. + * @module @deepseek-ai/dsh-session-projection/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-projection-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.js new file mode 100644 index 0000000..d2ff429 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.js @@ -0,0 +1,30 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-projection`. + * @module @deepseek-ai/dsh-session-projection/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-session-projection'; +/** Cordis companion plugin name. */ +export const name = 'session-projection-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: the registry's own contracts (duplicate-key and + * stateVersion rejection, effect-tied removal, the Object.is change gate) are + * enforced synchronously inside the service and proven by its spec, the + * drive relation (every committed `session/event` passes every unit) would + * require re-running the drive to check — duplicating the implementation + * rather than detecting drift — and the served-value relation (every served + * key has a live registration) lives on each carrier's wire path, which + * emits no cordis event this companion could observe; carrier specs assert + * it. Synchronous-unit discipline is enforced as far as practical by the + * boundary `schema.parse` (a Promise-returning view fails loudly). + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts new file mode 100644 index 0000000..2be9f7a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts @@ -0,0 +1,18 @@ +/** + * Pure-type outlet of the session-projection Service Definition: the one projection type + * table, importable from client aggregates without dragging the host-side + * cordis Context merges of the package root (dsh-agent → dsh-session). Domain + * packages may declare-merge through either the package root or this outlet — + * re-export preserves symbol identity, so both land on the same table. + * + * @module @deepseek-ai/dsh-session-projection/types + */ +/** + * The single projection type table for the whole chain (host provider, wire + * block, client cell, React hook). Domain packages merge their key here via + * declaration merging; values are wire-JSON whole values. How a value is + * rendered is the slot system's business, never this layer's. + */ +export interface SessionProjectionMap { +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.js new file mode 100644 index 0000000..4b169bd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.js @@ -0,0 +1,11 @@ +/** + * Pure-type outlet of the session-projection Service Definition: the one projection type + * table, importable from client aggregates without dragging the host-side + * cordis Context merges of the package root (dsh-agent → dsh-session). Domain + * packages may declare-merge through either the package root or this outlet — + * re-export preserves symbol identity, so both land on the same table. + * + * @module @deepseek-ai/dsh-session-projection/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/package.json new file mode 100644 index 0000000..1a762ff --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection/package.json @@ -0,0 +1,52 @@ +{ + "name": "@deepseek-ai/dsh-session-projection", + "description": "Session-projection seam: the merge-extensible projection type table, the provider contract, and the ctx.sessionProjections registry serving whole current values of log-derived per-session state", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session/session-projection" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.i18n.yaml new file mode 100644 index 0000000..fb26401 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/session/session-projection/README.md +README.md: 9018b133bb69ed4717fede14c9a2070a07c3fa62 +README.zh.md: 2a3af5620f84ff9697268101a6cfb894232b68b7 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.md new file mode 100644 index 0000000..9018b13 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.md @@ -0,0 +1,48 @@ +# @deepseek-ai/dsh-session-projection + +English | [中文](README.zh.md) + +Session-projection Service Definition and drive registry. It owns `ctx.sessionProjections`, the registry that drives every registered projection unit over committed session events and serves finished whole values to carriers, currently the api-proxy history tail page and `session/projection` push frame. A domain registers pure mathematics; the framework owns the drive. The [session-projection RFC](../../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md) records the design rationale. + +## Service: `SessionProjectionRegistry` (ctx key: `sessionProjections`) + +### Public API + +- `ctx.sessionProjections.register(definition): () => void` Register one domain's unit. Duplicate keys and invalid `stateVersion` throw; the registration is an effect on the calling fiber, so an unloaded domain plugin's key (with its cached cells) disappears from subsequent drives and snapshots — clients read that as capability absence. +- `ctx.sessionProjections.onChanged(listener): () => void` Subscribe to the change feed: one call per unit whose state reference changed, per committed event, carrying the schema-validated view and the causing seq. Effect-tied like `register`. +- `ctx.sessionProjections.snapshot(session): ProjectionSnapshot` One consistent synchronous cut over every registered unit — `{ asOfSeq, values }` with `asOfSeq` = the seq of the last event every value reflects (`-1` for an empty log). + +### Key Types + +- `SessionProjectionMap` — the single merge-extensible type table for the whole chain (host unit, wire block, React hook). Values are wire-JSON whole values; rendering belongs to the slot system, never this layer. +- `ProjectionDefinition` — `{ key, schema, init(), apply(state, event), view(state), stateVersion }`: a state-driven computation unit of three pure synchronous functions plus declarations, never an opaque getter. + +## Contract + +- **The framework drives, the domain computes.** The registry subscribes to `session/event` once; every committed event passes every unit's `apply` eagerly. Domains hold no subscriptions. Cells (`{state, observedSeq}` per unit per session, WeakMap-keyed) build lazily — a unit registered after events flowed, or a read of a session predating the registration, folds `init` over the in-memory log on first touch. +- **Same-reference means no work.** `apply` MUST return the same state reference for events that do not concern the unit; the drive gates the change feed on `Object.is`, so non-matching events cost one call and nothing downstream. +- **Whole-value event rule (load-bearing).** A state-carrying log event MUST carry the complete post-change state, never a bare delta — it keeps every transition trivially cheap and every served value self-describing (last-wins for consumers). +- **Synchronous unit discipline.** `init`/`apply`/`view` MUST be synchronous; carriers read `snapshot()` in the same tick as their page slice, which is what makes `asOfSeq` one consistent cut. An accidentally-async `view` returns a Promise, which fails the boundary `schema.parse` loudly. +- **State is plain JSON, `stateVersion` is its invalidation anchor.** The persisted projection cache stores `(sessionId, key, ver, seq, val)` rows; bump `stateVersion` whenever the state shape or the fold semantics change so stale rows are discarded instead of forward-applied into garbage. +- **No wire vocabulary here.** The registry exposes only the change feed and the snapshot read face; carriers (api-proxy) mint their own frames (`session/projection`) and blocks from them. +- **Optional capability.** Domain plugins register under `ctx.inject(['sessionProjections'], …)` so headless assemblies without the registry stay unaffected; carriers use `ctx.get('sessionProjections')` and omit their block/frames entirely when the registry is absent. + +## Role + +This package owns the Service Definition and drive roles of the capability seam: domain host plugins (e.g. `dsh-tool-todo`) contribute units, carriers (`dsh-host-apiproxy`) consume the snapshot and change feed, and neither knows the other. + +## Model Experience + +None, as the registry only computes client-facing read models of already-logged session state and touches no prompt, message, schema, stream, or tool result. + +#### KV Cache effect + +None; projections never assemble or send provider requests. + +## Known Limitations and Deferred Work + +- **Every tail page carries every registered key** — there is no per-key opt-out or lazy-key request shape yet; acceptable while values are UI-scale whole states (a todo list, a goal snapshot), revisit if a domain's value grows large. +- **The unit table is process-wide, so key presence is not a per-session capability signal** — a key registered by ANY agent preset appears in every session's snapshot, including sessions whose own composition mounts nothing that produces it. A client must read the VALUE (`plan.active`, an empty todo list) rather than treat an absent key as absence of the feature; a unit whose empty value is indistinguishable from a real one belongs on the host plane instead, which is why `dsh-token-meter` sits there. +- **Eager drive touches every unit per event** — cheap by construction (whole-value rule, same-reference gate), but a hot path would justify per-unit event-type prefilters, addable without contract change. +- **Registry cells live in memory only** — a restart rebuilds by folding the log on first touch; compositions that mount `dsh-session-projection-cache` seed that fold from persisted rows instead. +- **Synchronous unit discipline is only partially mechanical** — the boundary `schema.parse` rejects a Promise-returning `view`, but an `apply` that blocks or reads torn non-session state is a review concern; the invariant companion documents why no runtime check exists. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.zh.md new file mode 100644 index 0000000..2a3af56 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/README.zh.md @@ -0,0 +1,48 @@ +# @deepseek-ai/dsh-session-projection + +[English](README.md) | 中文 + +会话投影 Service Definition 与驱动注册表。它拥有 `ctx.sessionProjections`:该注册表在已提交的会话事件上驱动每个已注册的投影单元,并向载体提供完整的最终值,目前包括 api-proxy 历史尾页和 `session/projection` 推送帧。领域注册的只是纯数学;驱动权归框架。[session-projection RFC](../../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md) 记录了设计理由。 + +## 服务:`SessionProjectionRegistry`(ctx 键:`sessionProjections`) + +### 公开 API + +- `ctx.sessionProjections.register(definition): () => void` 注册一个领域的单元。key 重复或 `stateVersion` 非法都会 throw;注册是挂在调用方 fiber 上的 effect,领域插件卸载后其 key(连同缓存的 cell)从后续驱动与快照中消失——客户端将其读作能力缺失。 +- `ctx.sessionProjections.onChanged(listener): () => void` 订阅变更流:每个已提交事件、每个状态引用发生变化的单元各回调一次,携带经 schema 校验的 view 与致因 seq。与 `register` 一样绑定 effect。 +- `ctx.sessionProjections.snapshot(session): ProjectionSnapshot` 对全部已注册单元做一次一致的同步切面——`{ asOfSeq, values }`,其中 `asOfSeq` = 所有值共同反映到的最后一个事件的 seq(空日志为 `-1`)。 + +### 关键类型 + +- `SessionProjectionMap`——整条链路唯一的 merge-extensible 类型表(host 侧单元、协议块、React 钩子)。值是协议层 JSON 全量值;渲染归 slot 体系管,永远不归本层。 +- `ProjectionDefinition`——`{ key, schema, init(), apply(state, event), view(state), stateVersion }`:由三个纯同步函数外加若干声明构成的状态驱动计算单元(state-driven computation unit),绝不是一个不透明的 getter。 + +## 约定 + +- **框架负责驱动,领域负责计算。** 注册表只订阅一次 `session/event`;每个已提交事件都会主动经过每个单元的 `apply`。领域不持有任何订阅。cell(每会话每单元一份 `{state, observedSeq}`,以 WeakMap 为键)惰性构建——在事件流过之后才注册的单元,或读取一个早于该注册的会话,都在首次触达时从 `init` 出发在内存日志上折叠。 +- **同引用即无工作。** 对与单元无关的事件,`apply` 必须返回同一个状态引用;驱动以 `Object.is` 把守变更流,因此不匹配的事件只花一次调用,不产生任何下游工作。 +- **全量值事件规则(承重)。** 携带状态的日志事件必须携带变更后的完整状态,绝不携带裸增量——这让每次状态转移始终足够廉价,也让每个被供给的值自描述(对消费方即 last-wins)。 +- **单元的同步纪律。**`init`/`apply`/`view` 必须是同步的;载体在切出页面切片的同一 tick 内读取 `snapshot()`,`asOfSeq` 之所以是一个一致切面正系于此。误写成异步的 `view` 会返回 Promise,让边界的 `schema.parse` 当场大声失败。 +- **状态是纯 JSON,`stateVersion` 是其失效锚点。** 持久投影缓存(persisted projection cache)存储 `(sessionId, key, ver, seq, val)` 行;状态形状或折叠语义一旦变化就递增 `stateVersion`,使陈旧行被丢弃,而不是被正向 apply 成垃圾。 +- **本层没有协议词汇。** 注册表只暴露变更流与快照读取面;载体(api-proxy)据此自铸各自的帧(`session/projection`)与块。 +- **可选能力。** 领域插件在 `ctx.inject(['sessionProjections'], …)` 下注册,因此不带注册表的 headless 组装完全不受影响;载体使用 `ctx.get('sessionProjections')`,注册表缺席时完全省略自己的块与帧。 + +## 职责 + +本包承担能力 seam 的 Service Definition 与驱动角色:领域 host 插件(如 `dsh-tool-todo`)贡献单元,载体(`dsh-host-apiproxy`)消费快照与变更流,两侧互不相识。 + +## 模型体验 + +无——注册表只对已入日志的会话状态计算面向客户端的读模型,不触碰任何提示词、消息、schema、流或工具结果。 + +#### KV Cache 影响 + +无;投影从不组装或发送提供方请求。 + +## 已知限制与暂缓事项 + +- **每个尾页携带每个已注册的 key**——尚无逐 key 的 opt-out 或惰性 key 请求形状;在值都是 UI 量级的全量状态(一张 todo 清单、一份 goal 快照)时可以接受,若某领域的值变大再重议。 +- **单元表是进程级的,因此 key 是否存在不能当作逐会话的能力信号**——只要**任何**一个 agent preset 注册了某个 key,它就出现在每个会话的快照里,包括自身组装完全不产出该值的会话。客户端必须读**值**(`plan.active`、空的 todo 列表),不能把 key 缺席当作功能缺席;如果某个单元的空值与真实值无法区分,它就该待在宿主平面——`dsh-token-meter` 正因如此留在那里。 +- **主动驱动(eager drive)逐事件触达每个单元**——按构造开销很低(全量值规则、同引用闸门),但若出现热点路径,可加按单元的事件类型预过滤,约定不变。 +- **注册表 cell 只活在内存里**——重启后首次触达时靠折叠日志重建;挂载了 `dsh-session-projection-cache` 的组合改由持久行播种该折叠。 +- **单元同步纪律只有部分可机械把关**——边界 `schema.parse` 能拒绝返回 Promise 的 `view`,但阻塞的 `apply`、或读取撕裂的非会话状态的 `apply`,只能靠评审把关;invariant 配套项记载了为何不存在运行时检查。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/index.js new file mode 100644 index 0000000..88c5137 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/index.js @@ -0,0 +1,274 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/index.js +/** +* Service Definition and drive registry for the session-projection capability seam: the merge-extensible `SessionProjectionMap` type +* table, the `ProjectionDefinition` state-driven computation unit contract, +* and the `ctx.sessionProjections` registry that DRIVES every registered unit +* forward eagerly over committed session events. Domain host plugins +* contribute pure mathematics (init/apply/view); the framework owns the +* subscription, the per-session watermark cache, and change notification; +* carriers consume the snapshot read face and the change feed. Neither side +* knows the other +* (capability-seam three-way split). Design authority: the session-projection +* RFC (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md). +* +* Whole-value event rule (load-bearing): a state-carrying log event MUST +* carry the complete post-change state, never a bare delta — it keeps every +* unit's transition trivially cheap and every served value self-describing. +* +* @module @deepseek-ai/dsh-session-projection +*/ +/** +* `ctx.sessionProjections`: the projection unit table and its drive. The +* service subscribes to `session/event` once; every committed event passes +* every registered unit's `apply` (eager drive), and a changed state +* reference notifies the change feed with the schema-validated view. +* Cells build lazily — a unit registered after events flowed, or a session +* older than the registry, folds `init` over the in-memory log on first +* touch (event or read). Registration is an effect (disposer rides the +* calling fiber): an unloaded domain plugin's key disappears from snapshots +* and clients read it as capability absence. Domain +* plugins register under `ctx.inject(['sessionProjections'], …)` so headless +* assemblies without the registry stay unaffected. Registrants sharing a key +* share one unit and are counted: the same tool package mounted in N agent +* presets registers N times, and the key survives until the last one +* unloads. +*/ +var SessionProjectionRegistry = class extends Service { + registrations = /* @__PURE__ */ new Map(); + listeners = /* @__PURE__ */ new Set(); + /** + * Create and install the registry as `ctx.sessionProjections`. + * @param ctx - Cordis context that owns the service. + */ + constructor(ctx) { + super(ctx, "sessionProjections"); + ctx.on("session/event", (session, event) => { + this.drive(session, event); + }); + } + /** + * Register one domain's unit. The registration is an effect on the calling + * context's fiber: disposing the fiber (or calling the returned disposer) + * removes the key — and the unit's cached cells — from subsequent drives + * and snapshots. + * @param definition - key, state schema, pure unit functions, and stateVersion. + * @returns the exact disposer that unregisters this unit. + */ + register(definition) { + if (!Number.isSafeInteger(definition.stateVersion) || definition.stateVersion < 0) throw new Error(`session projection ${JSON.stringify(definition.key)} stateVersion must be a non-negative integer, got ${String(definition.stateVersion)}`); + const dispose = this.ctx.effect(function* () { + const key = definition.key; + const existing = this.registrations.get(key); + if (existing === void 0) this.registrations.set(key, { + def: definition, + cells: /* @__PURE__ */ new WeakMap(), + refs: 1 + }); + else { + if (existing.def.stateVersion !== definition.stateVersion) throw new Error(`session projection key ${JSON.stringify(key)} is already registered at stateVersion ${String(existing.def.stateVersion)}; refusing to share it with stateVersion ${String(definition.stateVersion)}`); + existing.refs += 1; + } + yield () => { + const live = this.registrations.get(key); + /* v8 ignore next -- the disposer runs once per successful registration, so the entry it counted is still here */ + if (live === void 0) return; + live.refs -= 1; + if (live.refs === 0) this.registrations.delete(key); + }; + }.bind(this), "sessionProjections.register()"); + return () => void dispose(); + } + /** + * Subscribe to the change feed. The registration is an effect on the + * calling context's fiber. + * @param listener - called once per unit whose state reference changed, per committed event. + * @returns the exact disposer that unsubscribes. + */ + onChanged(listener) { + const dispose = this.ctx.effect(() => { + this.listeners.add(listener); + return () => { + this.listeners.delete(listener); + }; + }, "sessionProjections.onChanged()"); + return () => void dispose(); + } + /** + * One consistent cut over every registered unit for one session, read from + * the watermark cache (missing cells fold lazily over the in-memory log). + * Fully synchronous — every value and `asOfSeq` reflect the same log + * position. Each value passes its unit's schema before leaving. + * @param session - the session whose projection values are read. + * @returns the snapshot; `values` is empty when no unit is registered. + */ + snapshot(session) { + const values = {}; + for (const registration of this.registrations.values()) { + const cell = this.cellFor(registration, session); + values[registration.def.key] = registration.def.schema.parse(registration.def.view(cell.state)); + } + return { + asOfSeq: session.seq - 1, + values + }; + } + /** + * State-level checkpoint of every registered unit for one session, read + * from the watermark cache (missing cells fold lazily over the in-memory + * log). This is the write side of the persisted projection cache: the + * returned rows are the `(key → {ver, seq, val})` part of the durable + * `(sessionId, key, ver, seq, val)` + * rows. Every `val` is a DETACHED structured clone — never the live + * cell reference: the watermark cache is this registry's authoritative + * mutable state, and a caller reaching the live reference could corrupt + * every subsequent snapshot and frame through it (plain JSON by the unit + * contract, so the clone is total). + * @param session - the session whose unit states are checkpointed. + * @returns one row per registered key; empty when no unit is registered. + */ + checkpoint(session) { + const rows = {}; + for (const registration of this.registrations.values()) { + const cell = this.cellFor(registration, session); + rows[registration.def.key] = { + ver: registration.def.stateVersion, + seq: cell.observedSeq, + val: structuredClone(cell.state) + }; + } + return rows; + } + /** + * The stored seq a {@link restore} tail read over `checkpoint` must start + * at: one event BELOW the lowest usable watermark (a row is usable when + * its `ver` matches the live unit's `stateVersion`; an absent or mismatched row + * pulls the floor to `0` — that key must refold the full log). The + * one-below anchor is load-bearing: the tail then proves how far the + * stored log still extends, so {@link restore} can detect a log that + * shrank below a row's watermark (crash-repair truncation) instead of + * serving the stale row as current — an empty tail read from the anchor + * yields an end below every watermark and the restore rejects for a full + * re-read. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns the seq to hand the persistence `readFrom`, or `undefined` + * when no unit is registered (no read needed — {@link restore} would + * serve empty values regardless). + */ + restoreFloor(checkpoint) { + let floor; + for (const registration of this.registrations.values()) { + const row = checkpoint[registration.def.key]; + const need = row !== void 0 && row.ver === registration.def.stateVersion ? Math.max(row.seq + 1, 0) : 0; + floor = floor === void 0 ? need : Math.min(floor, need); + } + return floor === void 0 ? void 0 : Math.max(floor - 1, 0); + } + /** + * View a checkpoint's rows without any log read: for every registered + * unit whose row's `ver` matches, serve the schema-validated + * `view` of the stored state; mismatched or absent rows leave their key + * absent (a cold or listing consumer treats it as not-yet-available and a + * fuller read path refolds it). The zero-I/O rung of the read ladder — + * values are as stale as their rows, never wrong. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns whole values per key with a usable row; empty when none. + */ + viewCheckpoint(checkpoint) { + const values = {}; + for (const registration of this.registrations.values()) { + const def = registration.def; + const row = checkpoint[def.key]; + if (row === void 0 || row.ver !== def.stateVersion) continue; + values[def.key] = def.schema.parse(def.view(row.val)); + } + return values; + } + /** + * Cold read: fold every registered unit over a stored log suffix, seeding + * each from its checkpoint row when usable — the one read recipe (cached + * state + forward tail replay + `view`) applied without a live `Session`. + * Call with the events returned by a persistence + * `readFrom(id, restoreFloor(checkpoint))` and that same floor as + * `baseSeq`; the floor's one-below anchor makes the supplied end honest, + * so a shrunk log is detected here. A row is usable iff its + * `ver` matches the live unit's `stateVersion`, it does not predate `baseSeq` + * (`seq >= baseSeq - 1`), and it does not claim events past the + * supplied end (`seq <= endSeq`); an unusable row is discarded + * and its key refolds from `init` — which is only sound over the full + * log, so a discarded row with `baseSeq > 0` throws (the caller re-reads + * from seq 0, e.g. after a crash-repair truncation shrank the log below + * a row's watermark). + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @param events - the stored events with `seq >= baseSeq`, in seq order. + * @param baseSeq - the seq `events` starts at (its first event's seq when non-empty). + * @returns the snapshot cut at the supplied log end (`asOfSeq` is the last + * supplied event's seq, `baseSeq - 1` for an empty tail) plus the + * refreshed checkpoint rows at that cut, ready for a durable write-back. + */ + restore(checkpoint, events, baseSeq) { + const endSeq = events.at(-1)?.seq ?? baseSeq - 1; + const values = {}; + const refreshed = {}; + for (const registration of this.registrations.values()) { + const def = registration.def; + const row = checkpoint[def.key]; + const usable = row !== void 0 && row.ver === def.stateVersion && row.seq >= baseSeq - 1 && row.seq <= endSeq; + if (!usable && baseSeq > 0) throw new Error(`session projection ${JSON.stringify(def.key)} cannot restore from seq ${baseSeq}: its checkpoint row is missing, version-mismatched, or beyond the supplied log end; re-read from seq 0`); + let state = usable ? row.val : def.init(); + const from = usable ? row.seq : baseSeq - 1; + for (const event of events) if (event.seq > from) state = def.apply(state, event); + values[def.key] = def.schema.parse(def.view(state)); + refreshed[def.key] = { + ver: def.stateVersion, + seq: endSeq, + val: state + }; + } + return { + snapshot: { + asOfSeq: endSeq, + values + }, + checkpoint: refreshed + }; + } + /** Fold one unit from init over `events`, producing a cell watermarked at the last folded event. */ + buildCell(def, events) { + let state = def.init(); + for (const event of events) state = def.apply(state, event); + return { + state, + observedSeq: events.at(-1)?.seq ?? -1 + }; + } + /** Read (or lazily build, folding the full in-memory log) one unit's cell. */ + cellFor(registration, session) { + let cell = registration.cells.get(session); + if (cell === void 0) { + cell = this.buildCell(registration.def, session.events); + registration.cells.set(session, cell); + } + return cell; + } + /** Eager drive: pass one committed event through every registered unit; notify on changed references. */ + drive(session, event) { + for (const registration of this.registrations.values()) { + let cell = registration.cells.get(session); + if (cell === void 0) { + cell = this.buildCell(registration.def, session.events.slice(0, event.seq)); + registration.cells.set(session, cell); + } + const next = registration.def.apply(cell.state, event); + const changed = !Object.is(next, cell.state); + cell.state = next; + cell.observedSeq = event.seq; + if (changed && this.listeners.size > 0) { + const value = registration.def.schema.parse(registration.def.view(next)); + for (const listener of this.listeners) listener(session, registration.def.key, value, event.seq); + } + } + } +}; +//#endregion +export { SessionProjectionRegistry, SessionProjectionRegistry as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/invariant.js new file mode 100644 index 0000000..9a90716 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/invariant.js @@ -0,0 +1,31 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-session-projection`. +* @module @deepseek-ai/dsh-session-projection/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session-projection"; +/** Cordis companion plugin name. */ +const name = "session-projection-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the registry's own contracts (duplicate-key and +* stateVersion rejection, effect-tied removal, the Object.is change gate) are +* enforced synchronously inside the service and proven by its spec, the +* drive relation (every committed `session/event` passes every unit) would +* require re-running the drive to check — duplicating the implementation +* rather than detecting drift — and the served-value relation (every served +* key has a live registration) lives on each carrier's wire path, which +* emits no cordis event this companion could observe; carrier specs assert +* it. Synchronous-unit discipline is enforced as far as practical by the +* boundary `schema.parse` (a Promise-returning view fails loudly). +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.d.ts new file mode 100644 index 0000000..2614d9b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.d.ts @@ -0,0 +1,231 @@ +/** + * Service Definition and drive registry for the session-projection capability seam: the merge-extensible `SessionProjectionMap` type + * table, the `ProjectionDefinition` state-driven computation unit contract, + * and the `ctx.sessionProjections` registry that DRIVES every registered unit + * forward eagerly over committed session events. Domain host plugins + * contribute pure mathematics (init/apply/view); the framework owns the + * subscription, the per-session watermark cache, and change notification; + * carriers consume the snapshot read face and the change feed. Neither side + * knows the other + * (capability-seam three-way split). Design authority: the session-projection + * RFC (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md). + * + * Whole-value event rule (load-bearing): a state-carrying log event MUST + * carry the complete post-change state, never a bare delta — it keeps every + * unit's transition trivially cheap and every served value self-describing. + * + * @module @deepseek-ai/dsh-session-projection + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { ZodType } from 'zod'; +import type { Session, SessionEvent } from '@deepseek-ai/dsh-session'; +declare module '@deepseek-ai/cordis' { + interface Context { + sessionProjections: SessionProjectionRegistry; + } +} +import type { SessionProjectionMap } from './types.ts'; +export type { SessionProjectionMap } from './types.ts'; +/** + * One domain's state-driven computation unit: three pure synchronous + * functions plus declarations — never an opaque getter. The framework drives + * `apply` on every committed session event; the domain holds no + * subscriptions and owns only the mathematics. All three functions MUST be + * synchronous (an async unit would tear the carriers' consistency cut) and + * `state` MUST be plain JSON (the persisted-cache precondition). + */ +export interface ProjectionDefinition { + /** The projection key this unit owns (its `SessionProjectionMap` entry). */ + key: K; + /** Validates the wire payload (`view` output) before it leaves the host. */ + schema: ZodType; + /** + * State for the empty log. + * @returns the initial state. + */ + init(): S; + /** + * Pure transition: previous state + one committed event → next state. A + * unit uninterested in an event MUST return the same state reference — an + * unchanged reference (`Object.is`) produces zero downstream work. + * @param state - the state covering all prior events. + * @param event - the next committed session event. + * @returns the next state (same reference when the event is not the unit's). + */ + apply(state: S, event: SessionEvent): S; + /** + * State → wire payload (the read-side projection). + * @param state - the current state. + * @returns the whole current value for this unit's key. + */ + view(state: S): SessionProjectionMap[K]; + /** + * Persisted-cache invalidation version: bump whenever the serialized state fields or the + * fold semantics change, so persisted `(sessionId, key, ver, seq, val)` + * rows from an older unit are discarded instead of being forward-applied + * into garbage. Non-negative integer. + */ + stateVersion: number; +} +/** + * Change-feed listener: one unit's value changed for one session. `value` is + * the schema-validated `view` output; `seq` is the unit's watermark at + * emission (the seq of the event that caused the change). + */ +export type ProjectionChangeListener = (session: Session, key: Extract, value: unknown, seq: number) => void; +/** + * One consistent read cut over every registered unit for one session. + * `asOfSeq` is the shared watermark — the seq of the last event every value + * reflects (`-1` for an empty log, mirroring `session/subscribed.lastSeq`). + */ +export interface ProjectionSnapshot { + /** Seq of the last event the values reflect; -1 for an empty log. */ + asOfSeq: number; + /** Whole current value per registered key. */ + values: Partial; +} +/** + * One unit's checkpoint: its internal state (plain JSON by the unit + * contract), the seq of the last event folded into it, and the unit + * `stateVersion` that produced it — the persisted projection-cache row + * `(sessionId, key, ver, seq, val)` minus the two outer keys. A row is + * never authoritative, only a fold shortcut: `restore` discards it on a + * version mismatch or when it claims events past the stored log end. + */ +export interface ProjectionCheckpointRow { + /** The registering unit's `stateVersion` at fold time. */ + ver: number; + /** Seq of the last event folded into `val`; -1 for the empty log. */ + seq: number; + /** The unit's internal state — plain JSON per the unit contract. */ + val: unknown; +} +/** Checkpoint rows keyed by projection key (one session's persisted cache value). */ +export type ProjectionCheckpoint = Record; +/** + * `ctx.sessionProjections`: the projection unit table and its drive. The + * service subscribes to `session/event` once; every committed event passes + * every registered unit's `apply` (eager drive), and a changed state + * reference notifies the change feed with the schema-validated view. + * Cells build lazily — a unit registered after events flowed, or a session + * older than the registry, folds `init` over the in-memory log on first + * touch (event or read). Registration is an effect (disposer rides the + * calling fiber): an unloaded domain plugin's key disappears from snapshots + * and clients read it as capability absence. Domain + * plugins register under `ctx.inject(['sessionProjections'], …)` so headless + * assemblies without the registry stay unaffected. Registrants sharing a key + * share one unit and are counted: the same tool package mounted in N agent + * presets registers N times, and the key survives until the last one + * unloads. + */ +export declare class SessionProjectionRegistry extends Service { + private readonly registrations; + private readonly listeners; + /** + * Create and install the registry as `ctx.sessionProjections`. + * @param ctx - Cordis context that owns the service. + */ + constructor(ctx: Context); + /** + * Register one domain's unit. The registration is an effect on the calling + * context's fiber: disposing the fiber (or calling the returned disposer) + * removes the key — and the unit's cached cells — from subsequent drives + * and snapshots. + * @param definition - key, state schema, pure unit functions, and stateVersion. + * @returns the exact disposer that unregisters this unit. + */ + register(definition: ProjectionDefinition): () => void; + /** + * Subscribe to the change feed. The registration is an effect on the + * calling context's fiber. + * @param listener - called once per unit whose state reference changed, per committed event. + * @returns the exact disposer that unsubscribes. + */ + onChanged(listener: ProjectionChangeListener): () => void; + /** + * One consistent cut over every registered unit for one session, read from + * the watermark cache (missing cells fold lazily over the in-memory log). + * Fully synchronous — every value and `asOfSeq` reflect the same log + * position. Each value passes its unit's schema before leaving. + * @param session - the session whose projection values are read. + * @returns the snapshot; `values` is empty when no unit is registered. + */ + snapshot(session: Session): ProjectionSnapshot; + /** + * State-level checkpoint of every registered unit for one session, read + * from the watermark cache (missing cells fold lazily over the in-memory + * log). This is the write side of the persisted projection cache: the + * returned rows are the `(key → {ver, seq, val})` part of the durable + * `(sessionId, key, ver, seq, val)` + * rows. Every `val` is a DETACHED structured clone — never the live + * cell reference: the watermark cache is this registry's authoritative + * mutable state, and a caller reaching the live reference could corrupt + * every subsequent snapshot and frame through it (plain JSON by the unit + * contract, so the clone is total). + * @param session - the session whose unit states are checkpointed. + * @returns one row per registered key; empty when no unit is registered. + */ + checkpoint(session: Session): ProjectionCheckpoint; + /** + * The stored seq a {@link restore} tail read over `checkpoint` must start + * at: one event BELOW the lowest usable watermark (a row is usable when + * its `ver` matches the live unit's `stateVersion`; an absent or mismatched row + * pulls the floor to `0` — that key must refold the full log). The + * one-below anchor is load-bearing: the tail then proves how far the + * stored log still extends, so {@link restore} can detect a log that + * shrank below a row's watermark (crash-repair truncation) instead of + * serving the stale row as current — an empty tail read from the anchor + * yields an end below every watermark and the restore rejects for a full + * re-read. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns the seq to hand the persistence `readFrom`, or `undefined` + * when no unit is registered (no read needed — {@link restore} would + * serve empty values regardless). + */ + restoreFloor(checkpoint: ProjectionCheckpoint): number | undefined; + /** + * View a checkpoint's rows without any log read: for every registered + * unit whose row's `ver` matches, serve the schema-validated + * `view` of the stored state; mismatched or absent rows leave their key + * absent (a cold or listing consumer treats it as not-yet-available and a + * fuller read path refolds it). The zero-I/O rung of the read ladder — + * values are as stale as their rows, never wrong. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns whole values per key with a usable row; empty when none. + */ + viewCheckpoint(checkpoint: ProjectionCheckpoint): Partial; + /** + * Cold read: fold every registered unit over a stored log suffix, seeding + * each from its checkpoint row when usable — the one read recipe (cached + * state + forward tail replay + `view`) applied without a live `Session`. + * Call with the events returned by a persistence + * `readFrom(id, restoreFloor(checkpoint))` and that same floor as + * `baseSeq`; the floor's one-below anchor makes the supplied end honest, + * so a shrunk log is detected here. A row is usable iff its + * `ver` matches the live unit's `stateVersion`, it does not predate `baseSeq` + * (`seq >= baseSeq - 1`), and it does not claim events past the + * supplied end (`seq <= endSeq`); an unusable row is discarded + * and its key refolds from `init` — which is only sound over the full + * log, so a discarded row with `baseSeq > 0` throws (the caller re-reads + * from seq 0, e.g. after a crash-repair truncation shrank the log below + * a row's watermark). + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @param events - the stored events with `seq >= baseSeq`, in seq order. + * @param baseSeq - the seq `events` starts at (its first event's seq when non-empty). + * @returns the snapshot cut at the supplied log end (`asOfSeq` is the last + * supplied event's seq, `baseSeq - 1` for an empty tail) plus the + * refreshed checkpoint rows at that cut, ready for a durable write-back. + */ + restore(checkpoint: ProjectionCheckpoint, events: readonly SessionEvent[], baseSeq: number): { + snapshot: ProjectionSnapshot; + checkpoint: ProjectionCheckpoint; + }; + /** Fold one unit from init over `events`, producing a cell watermarked at the last folded event. */ + private buildCell; + /** Read (or lazily build, folding the full in-memory log) one unit's cell. */ + private cellFor; + /** Eager drive: pass one committed event through every registered unit; notify on changed references. */ + private drive; +} +export default SessionProjectionRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.js new file mode 100644 index 0000000..9c6738f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.js @@ -0,0 +1,285 @@ +/** + * Service Definition and drive registry for the session-projection capability seam: the merge-extensible `SessionProjectionMap` type + * table, the `ProjectionDefinition` state-driven computation unit contract, + * and the `ctx.sessionProjections` registry that DRIVES every registered unit + * forward eagerly over committed session events. Domain host plugins + * contribute pure mathematics (init/apply/view); the framework owns the + * subscription, the per-session watermark cache, and change notification; + * carriers consume the snapshot read face and the change feed. Neither side + * knows the other + * (capability-seam three-way split). Design authority: the session-projection + * RFC (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md). + * + * Whole-value event rule (load-bearing): a state-carrying log event MUST + * carry the complete post-change state, never a bare delta — it keeps every + * unit's transition trivially cheap and every served value self-describing. + * + * @module @deepseek-ai/dsh-session-projection + */ +import { Service } from '@deepseek-ai/cordis'; +/** + * `ctx.sessionProjections`: the projection unit table and its drive. The + * service subscribes to `session/event` once; every committed event passes + * every registered unit's `apply` (eager drive), and a changed state + * reference notifies the change feed with the schema-validated view. + * Cells build lazily — a unit registered after events flowed, or a session + * older than the registry, folds `init` over the in-memory log on first + * touch (event or read). Registration is an effect (disposer rides the + * calling fiber): an unloaded domain plugin's key disappears from snapshots + * and clients read it as capability absence. Domain + * plugins register under `ctx.inject(['sessionProjections'], …)` so headless + * assemblies without the registry stay unaffected. Registrants sharing a key + * share one unit and are counted: the same tool package mounted in N agent + * presets registers N times, and the key survives until the last one + * unloads. + */ +export class SessionProjectionRegistry extends Service { + registrations = new Map(); + listeners = new Set(); + /** + * Create and install the registry as `ctx.sessionProjections`. + * @param ctx - Cordis context that owns the service. + */ + constructor(ctx) { + super(ctx, 'sessionProjections'); + ctx.on('session/event', (session, event) => { + this.drive(session, event); + }); + } + /** + * Register one domain's unit. The registration is an effect on the calling + * context's fiber: disposing the fiber (or calling the returned disposer) + * removes the key — and the unit's cached cells — from subsequent drives + * and snapshots. + * @param definition - key, state schema, pure unit functions, and stateVersion. + * @returns the exact disposer that unregisters this unit. + */ + register(definition) { + if (!Number.isSafeInteger(definition.stateVersion) || definition.stateVersion < 0) { + throw new Error(`session projection ${JSON.stringify(definition.key)} stateVersion must be a non-negative integer, got ${String(definition.stateVersion)}`); + } + const dispose = this.ctx.effect(function* () { + const key = definition.key; + const existing = this.registrations.get(key); + if (existing === undefined) { + this.registrations.set(key, { def: definition, cells: new WeakMap(), refs: 1 }); + } + else { + // A differing `stateVersion` is the one incompatibility this can name: + // the versioned contract says the cached state shape differs, so the + // two registrants cannot share cells. Anything else about a definition + // is functions, which no runtime comparison can tell apart. + if (existing.def.stateVersion !== definition.stateVersion) { + throw new Error(`session projection key ${JSON.stringify(key)} is already registered at stateVersion ${String(existing.def.stateVersion)}; refusing to share it with stateVersion ${String(definition.stateVersion)}`); + } + existing.refs += 1; + } + yield () => { + const live = this.registrations.get(key); + /* v8 ignore next -- the disposer runs once per successful registration, so the entry it counted is still here */ + if (live === undefined) + return; + live.refs -= 1; + if (live.refs === 0) + this.registrations.delete(key); + }; + }.bind(this), 'sessionProjections.register()'); + return () => void dispose(); + } + /** + * Subscribe to the change feed. The registration is an effect on the + * calling context's fiber. + * @param listener - called once per unit whose state reference changed, per committed event. + * @returns the exact disposer that unsubscribes. + */ + onChanged(listener) { + const dispose = this.ctx.effect(() => { + this.listeners.add(listener); + return () => { + this.listeners.delete(listener); + }; + }, 'sessionProjections.onChanged()'); + return () => void dispose(); + } + /** + * One consistent cut over every registered unit for one session, read from + * the watermark cache (missing cells fold lazily over the in-memory log). + * Fully synchronous — every value and `asOfSeq` reflect the same log + * position. Each value passes its unit's schema before leaving. + * @param session - the session whose projection values are read. + * @returns the snapshot; `values` is empty when no unit is registered. + */ + snapshot(session) { + const values = {}; + for (const registration of this.registrations.values()) { + const cell = this.cellFor(registration, session); + values[registration.def.key] = registration.def.schema.parse(registration.def.view(cell.state)); + } + return { asOfSeq: session.seq - 1, values: values }; + } + /** + * State-level checkpoint of every registered unit for one session, read + * from the watermark cache (missing cells fold lazily over the in-memory + * log). This is the write side of the persisted projection cache: the + * returned rows are the `(key → {ver, seq, val})` part of the durable + * `(sessionId, key, ver, seq, val)` + * rows. Every `val` is a DETACHED structured clone — never the live + * cell reference: the watermark cache is this registry's authoritative + * mutable state, and a caller reaching the live reference could corrupt + * every subsequent snapshot and frame through it (plain JSON by the unit + * contract, so the clone is total). + * @param session - the session whose unit states are checkpointed. + * @returns one row per registered key; empty when no unit is registered. + */ + checkpoint(session) { + const rows = {}; + for (const registration of this.registrations.values()) { + const cell = this.cellFor(registration, session); + rows[registration.def.key] = { + ver: registration.def.stateVersion, + seq: cell.observedSeq, + val: structuredClone(cell.state), + }; + } + return rows; + } + /** + * The stored seq a {@link restore} tail read over `checkpoint` must start + * at: one event BELOW the lowest usable watermark (a row is usable when + * its `ver` matches the live unit's `stateVersion`; an absent or mismatched row + * pulls the floor to `0` — that key must refold the full log). The + * one-below anchor is load-bearing: the tail then proves how far the + * stored log still extends, so {@link restore} can detect a log that + * shrank below a row's watermark (crash-repair truncation) instead of + * serving the stale row as current — an empty tail read from the anchor + * yields an end below every watermark and the restore rejects for a full + * re-read. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns the seq to hand the persistence `readFrom`, or `undefined` + * when no unit is registered (no read needed — {@link restore} would + * serve empty values regardless). + */ + restoreFloor(checkpoint) { + let floor; + for (const registration of this.registrations.values()) { + const row = checkpoint[registration.def.key]; + const need = row !== undefined && row.ver === registration.def.stateVersion + ? Math.max(row.seq + 1, 0) + : 0; + floor = floor === undefined ? need : Math.min(floor, need); + } + return floor === undefined ? undefined : Math.max(floor - 1, 0); + } + /** + * View a checkpoint's rows without any log read: for every registered + * unit whose row's `ver` matches, serve the schema-validated + * `view` of the stored state; mismatched or absent rows leave their key + * absent (a cold or listing consumer treats it as not-yet-available and a + * fuller read path refolds it). The zero-I/O rung of the read ladder — + * values are as stale as their rows, never wrong. + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @returns whole values per key with a usable row; empty when none. + */ + viewCheckpoint(checkpoint) { + const values = {}; + for (const registration of this.registrations.values()) { + const def = registration.def; + const row = checkpoint[def.key]; + if (row === undefined || row.ver !== def.stateVersion) + continue; + values[def.key] = def.schema.parse(def.view(row.val)); + } + return values; + } + /** + * Cold read: fold every registered unit over a stored log suffix, seeding + * each from its checkpoint row when usable — the one read recipe (cached + * state + forward tail replay + `view`) applied without a live `Session`. + * Call with the events returned by a persistence + * `readFrom(id, restoreFloor(checkpoint))` and that same floor as + * `baseSeq`; the floor's one-below anchor makes the supplied end honest, + * so a shrunk log is detected here. A row is usable iff its + * `ver` matches the live unit's `stateVersion`, it does not predate `baseSeq` + * (`seq >= baseSeq - 1`), and it does not claim events past the + * supplied end (`seq <= endSeq`); an unusable row is discarded + * and its key refolds from `init` — which is only sound over the full + * log, so a discarded row with `baseSeq > 0` throws (the caller re-reads + * from seq 0, e.g. after a crash-repair truncation shrank the log below + * a row's watermark). + * @param checkpoint - persisted rows for one session (possibly stale or empty). + * @param events - the stored events with `seq >= baseSeq`, in seq order. + * @param baseSeq - the seq `events` starts at (its first event's seq when non-empty). + * @returns the snapshot cut at the supplied log end (`asOfSeq` is the last + * supplied event's seq, `baseSeq - 1` for an empty tail) plus the + * refreshed checkpoint rows at that cut, ready for a durable write-back. + */ + restore(checkpoint, events, baseSeq) { + const endSeq = events.at(-1)?.seq ?? baseSeq - 1; + const values = {}; + const refreshed = {}; + for (const registration of this.registrations.values()) { + const def = registration.def; + const row = checkpoint[def.key]; + const usable = row !== undefined + && row.ver === def.stateVersion + && row.seq >= baseSeq - 1 + && row.seq <= endSeq; + if (!usable && baseSeq > 0) { + throw new Error(`session projection ${JSON.stringify(def.key)} cannot restore from seq ${baseSeq}: ` + + 'its checkpoint row is missing, version-mismatched, or beyond the supplied log end; re-read from seq 0'); + } + let state = usable ? row.val : def.init(); + const from = usable ? row.seq : baseSeq - 1; + for (const event of events) { + if (event.seq > from) + state = def.apply(state, event); + } + values[def.key] = def.schema.parse(def.view(state)); + refreshed[def.key] = { ver: def.stateVersion, seq: endSeq, val: state }; + } + return { + snapshot: { asOfSeq: endSeq, values: values }, + checkpoint: refreshed, + }; + } + /** Fold one unit from init over `events`, producing a cell watermarked at the last folded event. */ + buildCell(def, events) { + let state = def.init(); + for (const event of events) + state = def.apply(state, event); + return { state, observedSeq: (events.at(-1)?.seq ?? -1) }; + } + /** Read (or lazily build, folding the full in-memory log) one unit's cell. */ + cellFor(registration, session) { + let cell = registration.cells.get(session); + if (cell === undefined) { + cell = this.buildCell(registration.def, session.events); + registration.cells.set(session, cell); + } + return cell; + } + /** Eager drive: pass one committed event through every registered unit; notify on changed references. */ + drive(session, event) { + for (const registration of this.registrations.values()) { + let cell = registration.cells.get(session); + if (cell === undefined) { + // Late build mid-stream: fold history before this event (seq = log + // index, so the prefix slice is exact), then take the normal gate. + cell = this.buildCell(registration.def, session.events.slice(0, event.seq)); + registration.cells.set(session, cell); + } + const next = registration.def.apply(cell.state, event); + const changed = !Object.is(next, cell.state); + cell.state = next; + cell.observedSeq = event.seq; + if (changed && this.listeners.size > 0) { + const value = registration.def.schema.parse(registration.def.view(next)); + for (const listener of this.listeners) { + listener(session, registration.def.key, value, event.seq); + } + } + } + } +} +export default SessionProjectionRegistry; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.d.ts new file mode 100644 index 0000000..f3aaaf8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-projection`. + * @module @deepseek-ai/dsh-session-projection/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-projection-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.js new file mode 100644 index 0000000..d2ff429 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/invariant.js @@ -0,0 +1,30 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-projection`. + * @module @deepseek-ai/dsh-session-projection/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-session-projection'; +/** Cordis companion plugin name. */ +export const name = 'session-projection-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: the registry's own contracts (duplicate-key and + * stateVersion rejection, effect-tied removal, the Object.is change gate) are + * enforced synchronously inside the service and proven by its spec, the + * drive relation (every committed `session/event` passes every unit) would + * require re-running the drive to check — duplicating the implementation + * rather than detecting drift — and the served-value relation (every served + * key has a live registration) lives on each carrier's wire path, which + * emits no cordis event this companion could observe; carrier specs assert + * it. Synchronous-unit discipline is enforced as far as practical by the + * boundary `schema.parse` (a Promise-returning view fails loudly). + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts new file mode 100644 index 0000000..2be9f7a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts @@ -0,0 +1,18 @@ +/** + * Pure-type outlet of the session-projection Service Definition: the one projection type + * table, importable from client aggregates without dragging the host-side + * cordis Context merges of the package root (dsh-agent → dsh-session). Domain + * packages may declare-merge through either the package root or this outlet — + * re-export preserves symbol identity, so both land on the same table. + * + * @module @deepseek-ai/dsh-session-projection/types + */ +/** + * The single projection type table for the whole chain (host provider, wire + * block, client cell, React hook). Domain packages merge their key here via + * declaration merging; values are wire-JSON whole values. How a value is + * rendered is the slot system's business, never this layer's. + */ +export interface SessionProjectionMap { +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.js new file mode 100644 index 0000000..4b169bd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.js @@ -0,0 +1,11 @@ +/** + * Pure-type outlet of the session-projection Service Definition: the one projection type + * table, importable from client aggregates without dragging the host-side + * cordis Context merges of the package root (dsh-agent → dsh-session). Domain + * packages may declare-merge through either the package root or this outlet — + * re-export preserves symbol identity, so both land on the same table. + * + * @module @deepseek-ai/dsh-session-projection/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/package.json new file mode 100644 index 0000000..7051e81 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection/package.json @@ -0,0 +1,52 @@ +{ + "name": "@deepseek-ai/dsh-session-projection", + "description": "Session-projection seam: the merge-extensible projection type table, the provider contract, and the ctx.sessionProjections registry serving whole current values of log-derived per-session state", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session/session-projection" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..a0535b0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.i18n.yaml new file mode 100644 index 0000000..783b6d9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/session-query/session-query/README.md +README.md: 02640bee4b3eb7f6877756a2ce84b26f698c9f58 +README.zh.md: 794c0e6e86606d92ed82ec286844647487df3295 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.md new file mode 100644 index 0000000..02640be --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.md @@ -0,0 +1,56 @@ +# @deepseek-ai/dsh-session-query + +English | [中文](README.zh.md) + +`SessionQueryEngine` is the combined abstract `ctx.sessionQuery` contract. It implements exact session-history retrieval, relationship tracing, and provider-independent filtering over live `ctx.sessions` plus optional dynamically mounted `ctx.sessionPersistence`; concrete backends implement its two full-text methods. Matching ids produce one record: live events win, while `live` and `persisted` report both source availabilities. Conflicting immutable headers fail with `SESSION_QUERY_SOURCE_CONFLICT`. + +## Reads + +- `listSessions(signal?)` reads current persistence metadata, merges live records with live precedence, and returns cloned records in deterministic newest-first order. +- `readSession(sessionId)` returns one complete detached raw log after the same core replay validation used by resume; it never enters the session into the live store. +- `filterSessions(filters, signal?)` applies provider-independent session metadata and availability predicates to that same cloned logical corpus. +- `filterEvents(sessionId, filters)` extracts first-party semantic documents and applies provider-independent metadata and literal-text predicates in ascending seq order. +- `readTitleSnapshots(sessionIds, signal?)` resolves unique ids from one live-preferred corpus observation, passes cancellation through persisted listing and inspection, and returns ordered per-session settlements so one missing or malformed title source does not discard its peers. Each live source is folded directly, and each persisted worker folds to a detached header/title result and releases the full log before dequeuing another id. Cancellation rejects the whole batch. `readTitleSnapshot(sessionId, signal?)` is the one-observation view; `readTitle(sessionId, signal?)` returns only its optional folded `session/title`. +- `listEvents(sessionId)` loads the live-preferred raw log and classifies each event as `current`, `shadowed`, or `log-only` with the shared `dsh-session` surface fold. +- `readSurface(sessionId)` returns one cloned header, raw-log capture boundary, and the complete folded current surface in model-history order. A live session wins over persistence; compaction is observed before or after its replacement append, never as a synthetic mixture. +- `readEvent(request, signal?)` returns a cloned header, the full target event, and a bounded raw-seq window. `before` and `after` default to zero and may not exceed `readWindowMax`. +- `traceSession(sessionId, signal?)` reads the corpus once and returns immediate-to-outward ancestors plus deterministic recursive descendant trees. `complete: false` identifies the first missing parent; a target-connected cycle fails with `SESSION_QUERY_INVALID_LINEAGE`. +- `traceEvent(request, signal?)` loads the logical log once and returns its cloned source header with direct positional replacements and direct cited source-event links. `replacementChain` follows positional replacers to the final replacement; source-event links remain non-transitive. + +Persistence is optional and may mount or unmount dynamically. Cross-corpus listing and lineage tracing fail with `SESSION_QUERY_PERSISTENCE_FAILED` while mounted persistence is unreadable; a successfully read durable record that fails Session validation reports `SESSION_QUERY_CORRUPT_SESSION` instead. A title read, event trace, or event read targeting a known live session does not consult persistence, so durable backend health cannot make current in-memory state unreadable. Persisted title and event operations list before loading and reject a metadata mismatch rather than combining inconsistent observations. Lineage-trace cancellation is passed to persisted listing; event-trace and event-read cancellation is passed to persisted listing and inspection. Each waits for the started backend call to settle, then rejects with the signal's exact reason even when the backend ignored that signal. A pre-aborted known-live title read, event trace, or event read rejects before folding or snapshotting without consulting persistence. A batch title observation performs one metadata listing, inspects its unique persisted ids with at most `persistedInspectConcurrency` workers, and preserves each title's own observed header for downstream authorization. Cancellation starts no queued inspections and rejects only after already-started workers settle. `listSessions()` remains lightweight and does not load logs or index titles. + +## Filtering and extraction + +`SessionResultFilter` covers id, nullable cwd, created-at range, nullable parent, and source availability. `SessionEventResultFilter` covers seq/time ranges, event type, surface, and semantic text. Filter arrays are ANDed; values within one list clause are ORed. Empty list values match nothing, ranges are inclusive, and malformed ranges or closed-union values fail with `SESSION_QUERY_INVALID_FILTER`. + +The text clause is deliberately independent of FTS providers: caller text is escaped into a Unicode, case-insensitive regular expression, and each whitespace run matches one or more whitespace characters. It is a literal semantic-text scan, not a full-text query. `extractSessionEventText()` and `buildSessionEventSearchDocuments()` define the shared first-party document projection; reasoning blocks, structural boundaries, stream chunks, request headers, and unknown declaration-merged variants produce no document. + +## Full-text methods + +`SessionQueryEngine.searchSessions(request, exec?)` groups the logical corpus by strongest matching event; `searchEvents(request, exec?)` searches one logical session. These are the service's only abstract methods. Both return pages whose continuation is an owned branded `SessionSearchCursor`, accept optional cancellation, and expose snippets without provider-specific numeric scores. An event-search page also carries the cloned target header from the same indexed generation as its hits, allowing authorization consumers to bind policy to the payload observation. Search requests accept only metadata event filters, because literal-text filtering is the scan path described above. + +The package has no provider coordinator, fallback implementation, or standalone concrete plugin. A concrete service backend inherits the implemented reads, filters, and traces while owning full-text observation, reconciliation, ranking, cursor generations, and query execution; the first implementation is [`@deepseek-ai/dsh-session-query-sqlite`](../session-query-sqlite/README.md). + +`SessionQueryError.code` is a closed union covering request validation, missing targets, malformed surfaces, source conflicts, persistence/index failures, cancellation, and invalid or stale cursors; the exact literals are defined in [`src/config.ts`](src/config.ts). + +`listEvents()`, `readSurface()`, and `traceEvent()` run the same one-pass `dsh-session` surface fold. A loaded log is valid only when event seqs are zero-based and contiguous, surface markers obey event-type eligibility, source-event arrays are nonempty and duplicate-free, references name earlier events, and each positional replacement names and cites every surface node it removes; every violation fails with `SESSION_QUERY_INVALID_SURFACE`. + +## Configuration + +| Key | Default | Contract | +|---|---:|---| +| `readWindowMax` | `50` | Maximum `before` or `after` raw-event count. | +| `persistedInspectConcurrency` | `4` | Maximum concurrent persisted-log inspections in one batch read; must be a positive safe integer. | + +## Model Experience + +None, as this trusted query service returns cloned session records only to its callers and registers no model-facing prompt, schema, tool, or message. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **No caller authorization** — this is trusted context-wide infrastructure; a future model tool or UI must constrain which sessions its caller may inspect. +- **No registries or model-facing tool** — extractor and search-provider registries, recursive traversal through cited source events, and a model-facing tool are absent. The [tracing decision](../../../.agents/notes/implemented/feature/2026-07-13-session-query-tracing.md) owns relationship semantics; SQLite ownership and tokenizer decisions live in the [implemented search note](../../../.agents/notes/implemented/feature/2026-07-10-sqlite-session-query-provider.md). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.zh.md new file mode 100644 index 0000000..794c0e6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/README.zh.md @@ -0,0 +1,56 @@ +# @deepseek-ai/dsh-session-query + +[English](README.md) | 中文 + +`SessionQueryEngine` 是组合式抽象 `ctx.sessionQuery` 约定。它对实时 `ctx.sessions` 和可选的动态挂载 `ctx.sessionPersistence` 实现精确会话历史取回、关系跟踪和与提供方无关的过滤;具体后端实现它的两个全文方法。匹配 id 只产生一条记录:实时事件优先,而 `live` 和 `persisted` 会报告两种来源的可用性。如果不可变 header 存在冲突,则以 `SESSION_QUERY_SOURCE_CONFLICT` 失败。 + +## 读取 + +- `listSessions(signal?)` 读取当前持久化元数据,以实时记录优先的方式合并它们,并按确定性的最新优先顺序返回克隆记录。 +- `readSession(sessionId)` 在执行与恢复相同的核心回放验证后,返回一份完整、脱离存储的原始日志;它绝不会将该会话放入实时存储。 +- `filterSessions(filters, signal?)` 对同一份克隆逻辑语料库应用与提供方无关的会话元数据和可用性谓词。 +- `filterEvents(sessionId, filters)` 提取第一方语义文档,并按 seq 升序应用与提供方无关的元数据和字面文本谓词。 +- `readTitleSnapshots(sessionIds, signal?)` 从一次实时优先的语料库观察中解析唯一 id,将取消信号传递给持久化列表查询和检查,并按顺序返回每个会话的结算结果,使某个缺失或格式错误的标题来源不会导致其他会话的结果被丢弃。每个实时来源直接 fold,每个持久化 worker fold 为脱离存储的 header/标题结果,并在出队下一个 id 前释放完整日志。取消会拒绝整个批次。`readTitleSnapshot(sessionId, signal?)` 是单次观察视图;`readTitle(sessionId, signal?)` 只返回其可选的 folded `session/title`。 +- `listEvents(sessionId)` 加载实时优先的原始日志,将每个事件分类为 `current`、`shadowed` 或 `log-only`;该分类使用共享 `dsh-session` 表层 fold。 +- `readSurface(sessionId)` 返回一个克隆 header、原始日志捕获边界,以及按模型历史顺序排列的完整折叠后当前表层。实时会话优先于持久化;压缩(compaction)只会在其替换追加之前或之后被观察,绝不会出现合成混合。 +- `readEvent(request, signal?)` 返回一个克隆 header、完整目标事件和有界的原始 seq 窗口。`before` 和 `after` 默认为 0,且不得超过 `readWindowMax`。 +- `traceSession(sessionId, signal?)` 只读取一次语料库,返回从直接父级向外的祖先,以及确定性的递归后代树。`complete: false` 标识第一个缺失父级;与目标相连的循环会以 `SESSION_QUERY_INVALID_LINEAGE` 失败。 +- `traceEvent(request, signal?)` 只加载一次逻辑日志,返回其克隆源 header、直接位置替换和直接引用的源事件链接。`replacementChain` 沿位置替换者跟踪到最终替换;源事件链接仍不传递。 + +持久化是可选的,可动态挂载或卸载。已挂载持久化无法读取时,跨语料库列表和血缘跟踪以 `SESSION_QUERY_PERSISTENCE_FAILED` 失败;已经成功读取、但无法通过 Session 校验的持久化记录则以 `SESSION_QUERY_CORRUPT_SESSION` 失败。针对已知实时会话的标题读取、事件跟踪或事件读取不会查询持久化,因此持久化后端的健康状态无法使当前内存状态变得不可读。持久化标题和事件操作在加载前先执行列表查询,并在元数据不匹配时拒绝,而不会组合不一致的观察。血缘跟踪的取消信号会传递给持久化列表查询;事件跟踪和事件读取的取消信号会传递给持久化列表查询和检查。每项操作都会等待已启动的后端调用结算,然后使用信号的精确原因拒绝,即使后端忽略了该信号。针对已知实时会话且预先中止的标题读取、事件跟踪或事件读取会在 fold 或快照之前拒绝,且不查询持久化。批量标题观察执行一次元数据列表查询,使用最多 `persistedInspectConcurrency` 个 worker 检查唯一持久化 id,并保留每个标题自己观察到的 header,供下游授权使用。取消不会启动已排队检查,且只在已启动 worker 结算后拒绝。`listSessions()` 仍保持轻量,不加载日志或索引标题。 + +## 过滤与提取 + +`SessionResultFilter` 覆盖 id、可空 cwd、创建时间范围、可空父级和来源可用性。`SessionEventResultFilter` 覆盖 seq/时间范围、事件类型、表层和语义文本。过滤器数组使用 AND;同一列表子句内的值使用 OR。空列表值不匹配任何内容,范围包含端点,而格式错误的范围或封闭联合值以 `SESSION_QUERY_INVALID_FILTER` 失败。 + +文本子句刻意与 FTS 提供方无关:调用方文本会被转义为不区分大小写的 Unicode 正则表达式,每段连续空白匹配一个或多个空白字符。它是字面语义文本扫描,而非全文查询。`extractSessionEventText()` 和 `buildSessionEventSearchDocuments()` 定义共享的第一方文档投影;推理(reasoning)块、结构边界、流分片、请求 header 和未知声明合并变体不产生文档。 + +## 全文方法 + +`SessionQueryEngine.searchSessions(request, exec?)` 按匹配最强的事件对逻辑语料库分组;`searchEvents(request, exec?)` 搜索一个逻辑会话。这两个是服务仅有的抽象方法。两者都返回分页结果,其延续信息是由服务持有的带品牌 `SessionSearchCursor`;接受可选取消,并在不使用提供方专用数值分数的情况下提供摘录。事件搜索分页结果还携带来自与命中相同索引世代的克隆目标 header,使授权消费方可将策略绑定到此次载荷观察。搜索请求只接受事件元数据过滤器,因为字面文本过滤使用上文所述扫描路径。 + +该包没有提供方协调器、回退实现或独立具体插件。具体服务后端继承已实现的读取、过滤和跟踪,同时负责全文观察、对账、排名、游标世代和查询执行;第一个实现是 [`@deepseek-ai/dsh-session-query-sqlite`](../session-query-sqlite/README.md)。 + +`SessionQueryError.code` 是一个封闭联合,覆盖请求验证、缺失目标、格式错误的表层、来源冲突、持久化/索引失败、取消,以及无效或陈旧游标;精确字面值在 [`src/config.ts`](src/config.ts) 中定义。 + +`listEvents()`、`readSurface()` 和 `traceEvent()` 执行同一个单遍 `dsh-session` 表层 fold。只有当事件 seq 从零开始且连续、表层标记符合事件类型的适用性要求、源事件数组非空且无重复、引用指向较早事件,且每个位置替换都命名并引用它移除的每个表层节点时,加载的日志才有效;任何违规都以 `SESSION_QUERY_INVALID_SURFACE` 失败。 + +## 配置 + +| 键 | 默认值 | 约定 | +|---|---:|---| +| `readWindowMax` | `50` | `before` 或 `after` 的最大原始事件数。 | +| `persistedInspectConcurrency` | `4` | 一次批量读取中的最大并发持久化日志检查数;必须是正的安全整数。 | + +## 模型体验 + +无。该可信查询服务只向调用方返回克隆会话记录,不注册面向模型的提示词、schema、工具或消息。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **无调用方授权**:这是上下文范围内的可信基础设施;未来的模型工具或 UI 必须限制调用方可检查的会话。 +- **无注册表或面向模型工具**:尚未提供提取器和搜索提供方注册表、递归遍历所引用的源事件的能力,以及面向模型的工具。[跟踪决策](../../../.agents/notes/implemented/feature/2026-07-13-session-query-tracing.md) 负责关系语义;SQLite 归属和 tokenizer 决策位于[已实现搜索记录](../../../.agents/notes/implemented/feature/2026-07-10-sqlite-session-query-provider.md)。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/index.js new file mode 100644 index 0000000..20e9c88 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/index.js @@ -0,0 +1,969 @@ +import { Service } from "@deepseek-ai/cordis"; +import { Session, foldSurface, isSurfaceEvent, snapshotSessionEvent } from "@deepseek-ai/dsh-session"; +import { foldSessionTitle } from "@deepseek-ai/dsh-session-title"; +import { HarnessError } from "@deepseek-ai/dsh-llm"; +//#region lib/types/config.js +/** Public configuration and typed failures for the combined session-query service. */ +/** Default maximum `before`/`after` raw-event window. */ +const SESSION_QUERY_READ_WINDOW_MAX = 50; +/** Default maximum number of concurrent persisted-log inspections in one batch read. */ +const SESSION_QUERY_DEFAULT_PERSISTED_INSPECT_CONCURRENCY = 4; +/** Typed session-query failure whose `code` is one closed taxonomy member. */ +var SessionQueryError = class extends HarnessError { + constructor(message, code, options) { + super(message, code, options); + } +}; +//#endregion +//#region lib/types/sources.js +/** Shared immutable-header checks for logical session source observers. */ +/** +* Reject incompatible observations of one logical session source. +* @param a - first live, listed, or loaded header observation. +* @param b - second header observation expected to identify the same source. +*/ +function assertSessionHeadersCompatible(a, b) { + if (a.version !== b.version || a.id !== b.id || a.createdAt !== b.createdAt || a.cwd !== b.cwd || a.parentSession !== b.parentSession || a.seedLength !== b.seedLength || (a.delegationDepth ?? 0) !== (b.delegationDepth ?? 0)) throw new SessionQueryError(`session source headers conflict for session "${a.id}"`, "SESSION_QUERY_SOURCE_CONFLICT"); +} +//#endregion +//#region lib/types/corpus.js +/** Live/persisted logical-corpus resolution for session-query. */ +/** Resolves a live-preferred corpus against the persistence service mounted now. */ +var SessionCorpus = class { + _ctx; + _persistedInspectConcurrency; + _persistence; + _optionalPersistenceFiber; + constructor(_ctx, _persistedInspectConcurrency) { + this._ctx = _ctx; + this._persistedInspectConcurrency = _persistedInspectConcurrency; + this._optionalPersistenceFiber = _ctx.inject(["sessionPersistence"], (childCtx) => { + const service = childCtx.sessionPersistence; + this._persistence = service; + childCtx.effect(() => () => { + /* v8 ignore next -- a stale optional-service disposer cannot clear a replacement */ + if (this._persistence === service) this._persistence = void 0; + }, "sessionQuery.persistenceBinding"); + }); + _ctx.effect(() => { + return () => this._optionalPersistenceFiber.dispose(); + }, "sessionQuery.optionalPersistence"); + } + /** + * List the complete logical corpus with live precedence and cloned headers. + * @param signal - optional cancellation for persistence listing. + * @returns records in deterministic newest-first order. + */ + async listSessions(signal) { + signal?.throwIfAborted(); + const persistence = this._persistence; + const persisted = persistence === void 0 ? [] : await listPersisted(persistence, signal); + signal?.throwIfAborted(); + const records = /* @__PURE__ */ new Map(); + for (const header of persisted) records.set(header.id, { + header: structuredClone(header), + live: false, + persisted: true + }); + for (const session of this._ctx.sessions.list()) { + const durable = records.get(session.id); + if (durable !== void 0) assertSessionHeadersCompatible(session.header, durable.header); + records.set(session.id, { + header: structuredClone(session.header), + live: true, + persisted: durable !== void 0 + }); + } + return [...records.values()].sort(compareSessions); + } + /** + * Load one logical source, preferring a detached live snapshot. + * + * A known live target never consults persistence, so an optional backend's + * failure cannot make current in-memory history unreadable. + * @param sessionId - session to resolve. + * @param signal - optional cancellation for persisted source resolution. + * @returns detached live-preferred header and events. + */ + async load(sessionId, signal) { + signal?.throwIfAborted(); + const live = this._ctx.sessions.get(sessionId); + if (live !== void 0) { + const snapshot = snapshotLive(live); + signal?.throwIfAborted(); + return snapshot; + } + const persistence = this._persistence; + if (persistence === void 0) throw notFound(sessionId); + const listed = (await listPersisted(persistence, signal)).find((header) => header.id === sessionId); + signal?.throwIfAborted(); + if (listed === void 0) throw notFound(sessionId); + const loaded = await inspectPersisted(persistence, sessionId, signal); + signal?.throwIfAborted(); + const attached = this._ctx.sessions.get(sessionId); + if (attached !== void 0) { + const snapshot = snapshotLive(attached); + signal?.throwIfAborted(); + return snapshot; + } + assertSessionHeadersCompatible(loaded.meta, listed); + const snapshot = { + header: structuredClone(loaded.meta), + events: loaded.events.map((event) => structuredClone(event)) + }; + signal?.throwIfAborted(); + return snapshot; + } + /** + * Project unique logical sources immediately from one persistence listing. + * + * The synchronous projector runs before a persisted worker claims its next id. + * Full logs are borrowed only for that call and never retained by the batch. + * @param sessionIds - sessions to resolve in first-occurrence order. + * @param project - synchronous fold that owns/clones every retained value. + * @param signal - cancellation shared by listing and every persisted inspection. + * @returns one fulfilled or rejected projected result per unique requested id. + */ + async projectMany(sessionIds, project, signal) { + const ids = [...new Set(sessionIds)]; + signal?.throwIfAborted(); + const resolved = /* @__PURE__ */ new Map(); + const unresolved = []; + for (const id of ids) { + const session = this._ctx.sessions.get(id); + if (session === void 0) unresolved.push(id); + else resolved.set(id, projectSource(id, sourceLive(session), project, signal)); + } + if (unresolved.length === 0) return orderedResults(ids, resolved); + const persistence = this._persistence; + if (persistence === void 0) { + for (const sessionId of unresolved) resolved.set(sessionId, { + sessionId, + status: "rejected", + reason: notFound(sessionId) + }); + return orderedResults(ids, resolved); + } + let persisted; + try { + persisted = await listPersisted(persistence, signal); + signal?.throwIfAborted(); + } catch (error) { + if (signal?.aborted) signal.throwIfAborted(); + for (const sessionId of unresolved) resolved.set(sessionId, { + sessionId, + status: "rejected", + reason: error + }); + return orderedResults(ids, resolved); + } + const persistedById = new Map(persisted.map((header) => [header.id, header])); + const resolvePersisted = async (sessionId) => { + const listed = persistedById.get(sessionId); + if (listed === void 0) { + const attached = this._ctx.sessions.get(sessionId); + resolved.set(sessionId, attached === void 0 ? { + sessionId, + status: "rejected", + reason: notFound(sessionId) + } : projectSource(sessionId, sourceLive(attached), project, signal)); + return; + } + try { + signal?.throwIfAborted(); + const loaded = await inspectPersisted(persistence, sessionId, signal); + signal?.throwIfAborted(); + const attached = this._ctx.sessions.get(sessionId); + if (attached !== void 0) { + resolved.set(sessionId, projectSource(sessionId, sourceLive(attached), project, signal)); + return; + } + assertSessionHeadersCompatible(loaded.meta, listed); + resolved.set(sessionId, projectSource(sessionId, { + header: loaded.meta, + events: loaded.events + }, project, signal)); + } catch (error) { + if (signal?.aborted) signal.throwIfAborted(); + resolved.set(sessionId, { + sessionId, + status: "rejected", + reason: error + }); + } + }; + let cursor = 0; + const worker = async () => { + for (;;) { + signal?.throwIfAborted(); + const index = cursor; + if (index >= unresolved.length) return; + cursor += 1; + await resolvePersisted(unresolved[index]); + } + }; + const workerCount = Math.min(this._persistedInspectConcurrency, unresolved.length); + const settlements = await Promise.allSettled(Array.from({ length: workerCount }, () => worker())); + if (signal?.aborted) signal.throwIfAborted(); + /* v8 ignore start -- per-id failures settle inside resolvePersisted; workers reject only on abort above */ + for (const settlement of settlements) if (settlement.status === "rejected") throw settlement.reason; + /* v8 ignore stop */ + signal?.throwIfAborted(); + return orderedResults(ids, resolved); + } +}; +function projectSource(sessionId, source, project, signal) { + try { + signal?.throwIfAborted(); + const value = project(source); + signal?.throwIfAborted(); + return { + sessionId, + status: "fulfilled", + value + }; + } catch (reason) { + /* v8 ignore next -- the synchronous projector has no external cancellation yield */ + if (signal?.aborted) signal.throwIfAborted(); + return { + sessionId, + status: "rejected", + reason + }; + } +} +function sourceLive(session) { + return { + header: session.header, + events: session.events + }; +} +function orderedResults(ids, resolved) { + return ids.map((sessionId) => resolved.get(sessionId)); +} +async function listPersisted(persistence, signal) { + try { + return await persistence.list(signal); + } catch (error) { + if (signal?.aborted) signal.throwIfAborted(); + throw new SessionQueryError(`session persistence listing failed: ${errorMessage(error)}`, "SESSION_QUERY_PERSISTENCE_FAILED", { cause: error }); + } +} +async function inspectPersisted(persistence, sessionId, signal) { + try { + return await persistence.inspect(sessionId, signal); + } catch (error) { + if (signal?.aborted) signal.throwIfAborted(); + if (error instanceof Error && error.name === "SessionPersistenceCorruptionError") throw new SessionQueryError(`stored session "${sessionId}" is corrupt: ${errorMessage(error)}`, "SESSION_QUERY_CORRUPT_SESSION", { cause: error }); + throw new SessionQueryError(`failed to inspect session "${sessionId}": ${errorMessage(error)}`, "SESSION_QUERY_PERSISTENCE_FAILED", { cause: error }); + } +} +function snapshotLive(session) { + return { + header: structuredClone(session.header), + events: session.events.map((event) => structuredClone(event)) + }; +} +function compareSessions(a, b) { + return b.header.createdAt - a.header.createdAt || a.header.id.localeCompare(b.header.id); +} +function notFound(sessionId) { + return new SessionQueryError(`session "${sessionId}" not found`, "SESSION_QUERY_SESSION_NOT_FOUND"); +} +function errorMessage(error) { + return error instanceof Error ? error.message : "unknown error"; +} +//#endregion +//#region lib/types/extraction.js +/** First-party semantic text extraction for session-query consumers. */ +/** +* Extract searchable semantic text from one first-party session event. +* +* Structural boundaries, raw stream chunks, request envelopes, and unknown +* declaration-merged events contribute no text. +* @param event - event to inspect. +* @returns newline-joined semantic text, or an empty string when non-searchable. +*/ +function extractSessionEventText(event) { + switch (event.type) { + case "user/message": return contentText(event.data.content); + case "assistant/message": return contentText(event.data.message.content); + case "tool/call": return joinText([event.data.name, event.data.arguments]); + case "tool/result": return joinText([ + contentText(event.data.message.content), + event.data.error?.name ?? "", + event.data.error?.code ?? "" + ]); + case "todo/write": return joinText(event.data.todos.flatMap((todo) => [todo.status, todo.content])); + case "turn/end": return turnEndText(event.data.reason); + case "turn/start": + case "step/start": + case "step/end": + case "assistant/chunk": + case "request/header": return ""; + default: return ""; + } +} +function turnEndText(reason) { + switch (reason.kind) { + case "error": return joinText(["error", reason.error.message]); + case "aborted": return "aborted"; + case "max-tokens": + case "interrupted": return reason.kind; + case "completed": return ""; + default: return ""; + } +} +function contentText(content) { + return joinText(content.flatMap(blockText)); +} +function blockText(block) { + switch (block.type) { + case "text": return [block.text]; + case "reasoning": return []; + case "tool-call": return [block.name, block.arguments]; + case "tool-result": return block.content.flatMap(blockText); + default: return []; + } +} +function joinText(parts) { + return parts.map((part) => part.trim()).filter(Boolean).join("\n"); +} +//#endregion +//#region lib/types/documents.js +/** Shared event metadata and semantic-document projection. */ +/** +* Project a raw log into lightweight surface-aware event records. +* @param sessionId - session that owns the log. +* @param events - complete contiguous raw event log. +* @returns one record per event in ascending seq order. +*/ +function buildSessionEventRecords(sessionId, events) { + const surfaceBySeq = classifySurface(events); + return events.map((event) => ({ + sessionId, + seq: event.seq, + type: event.type, + time: event.time, + surface: surfaceBySeq.get(event.seq) ?? "log-only" + })); +} +/** +* Build first-party semantic documents for one complete raw event log. +* @param sessionId - session that owns the log. +* @param events - complete contiguous raw event log. +* @returns searchable documents in ascending seq order; structural events are omitted. +*/ +function buildSessionEventSearchDocuments(sessionId, events) { + const surfaceBySeq = classifySurface(events); + const documents = []; + for (const event of events) { + const text = extractSessionEventText(event); + if (text.length === 0) continue; + documents.push({ + sessionId, + seq: event.seq, + type: event.type, + time: event.time, + surface: surfaceBySeq.get(event.seq) ?? "log-only", + text + }); + } + return documents; +} +function classifySurface(events) { + let folded; + try { + folded = foldSurface(events); + } catch (error) { + throw new SessionQueryError( + /* v8 ignore next -- foldSurface throws Error instances */ + `invalid session surface: ${error instanceof Error ? error.message : "unknown error"}`, + "SESSION_QUERY_INVALID_SURFACE", + { cause: error } + ); + } + const result = /* @__PURE__ */ new Map(); + for (const seq of folded.nodes) result.set(seq, "current"); + for (const replacement of folded.replacements) for (const seq of replacement.shadowedSeqs) result.set(seq, "shadowed"); + return result; +} +//#endregion +//#region lib/types/filters.js +/** Pure provider-independent predicates for logical sessions and event text. */ +/** +* Apply ANDed logical-session filters while preserving input order. +* @param records - detached logical-session records to inspect. +* @param filters - clauses whose list values are ORed within each clause. +* @returns records accepted by every clause. +*/ +function filterSessionResults(records, filters = []) { + const predicates = filters.map(sessionPredicate); + return records.filter((record) => predicates.every((predicate) => predicate(record))); +} +/** +* Apply ANDed event filters to extracted semantic documents. +* @param documents - semantic documents produced by {@link buildSessionEventSearchDocuments}. +* @param filters - metadata and literal-text predicates. +* @returns documents accepted by every clause, in input order. +*/ +function filterSessionEventDocuments(documents, filters = []) { + const predicates = filters.map(eventPredicate); + return documents.filter((document) => predicates.every((predicate) => predicate(document))); +} +/** +* Copy and validate logical-session filters before an asynchronous boundary. +* @param filters - caller-owned clauses to materialize. +* @returns detached validated clauses. +*/ +function materializeSessionResultFilters(filters) { + assertArray(filters); + return filters.map((filter) => { + switch (filter.kind) { + case "id": return { + kind: filter.kind, + values: copyStrings(filter.kind, filter.values) + }; + case "cwd": return { + kind: filter.kind, + values: copyNullableStrings(filter.kind, filter.values) + }; + case "created-at": return copyRange(filter.kind, filter); + case "parent": return { + kind: filter.kind, + values: copyNullableStrings(filter.kind, filter.values) + }; + case "availability": { + const values = copyStrings(filter.kind, filter.values); + assertAllowedValues(filter.kind, values, ["live", "persisted"]); + return { + kind: filter.kind, + values + }; + } + default: return unknownFilter(filter); + } + }); +} +/** +* Copy and validate event filters before an asynchronous boundary. +* @param filters - caller-owned clauses to materialize. +* @returns detached validated clauses. +*/ +function materializeSessionEventResultFilters(filters) { + assertArray(filters); + return filters.map((filter) => { + switch (filter.kind) { + case "seq": + case "time": return copyRange(filter.kind, filter); + case "type": return { + kind: filter.kind, + values: copyStrings(filter.kind, filter.values) + }; + case "surface": { + const values = copyStrings(filter.kind, filter.values); + assertAllowedValues(filter.kind, values, [ + "current", + "shadowed", + "log-only" + ]); + return { + kind: filter.kind, + values + }; + } + case "text": + if (typeof filter.text !== "string") throw invalidFilter("text filter text must be a string"); + return { + kind: filter.kind, + text: filter.text + }; + default: return unknownFilter(filter); + } + }); +} +/** +* Compile a literal case-insensitive, whitespace-flexible semantic-text match. +* @param text - caller-provided literal text. +* @returns Unicode-aware regular expression safe from regex injection. +*/ +function compileSessionTextFilter(text) { + const trimmed = text.trim(); + if (trimmed.length === 0) throw new SessionQueryError("session text filter must contain non-whitespace text", "SESSION_QUERY_INVALID_FILTER"); + const pattern = trimmed.split(/\s+/u).map((part) => part.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")).join("\\s+"); + return new RegExp(pattern, "iu"); +} +function sessionPredicate(filter) { + switch (filter.kind) { + case "id": return (record) => filter.values.includes(record.header.id); + case "cwd": return (record) => filter.values.includes(record.header.cwd ?? null); + case "created-at": { + const range = validateRange(filter.kind, filter); + return (record) => matchesRange(record.header.createdAt, range); + } + case "parent": return (record) => filter.values.includes(record.header.parentSession ?? null); + case "availability": + assertAllowedValues(filter.kind, filter.values, ["live", "persisted"]); + return (record) => filter.values.some((value) => value === "live" ? record.live : record.persisted); + default: return unknownFilter(filter); + } +} +function eventPredicate(filter) { + switch (filter.kind) { + case "seq": { + const range = validateRange(filter.kind, filter); + return (document) => matchesRange(document.seq, range); + } + case "time": { + const range = validateRange(filter.kind, filter); + return (document) => matchesRange(document.time, range); + } + case "type": return (document) => filter.values.includes(document.type); + case "surface": + assertAllowedValues(filter.kind, filter.values, [ + "current", + "shadowed", + "log-only" + ]); + return (document) => filter.values.includes(document.surface); + case "text": { + const pattern = compileSessionTextFilter(filter.text); + return (document) => pattern.test(document.text); + } + default: return unknownFilter(filter); + } +} +function copyStrings(name, values) { + if (!isRuntimeArray(values) || values.some((value) => typeof value !== "string")) throw invalidFilter(`${name} filter values must be an array of strings`); + return [...values]; +} +function assertArray(value) { + if (!Array.isArray(value)) throw invalidFilter("filters must be an array"); +} +function copyNullableStrings(name, values) { + if (!isRuntimeArray(values) || values.some((value) => value !== null && typeof value !== "string")) throw invalidFilter(`${name} filter values must be an array of strings or null`); + return [...values]; +} +function copyRange(kind, range) { + const copy = { + kind, + ...range.from === void 0 ? {} : { from: range.from }, + ...range.to === void 0 ? {} : { to: range.to } + }; + validateRange(kind, copy); + return copy; +} +function unknownFilter(filter) { + const kind = filter.kind; + throw invalidFilter(`unknown filter kind ${typeof kind === "string" ? `"${kind}"` : "(missing)"}`); +} +function assertAllowedValues(name, values, allowed) { + for (const value of values) if (!allowed.includes(value)) throw new SessionQueryError(`session ${name} filter contains unknown value "${value}"`, "SESSION_QUERY_INVALID_FILTER"); +} +function validateRange(name, range) { + if (range.from !== void 0 && !Number.isFinite(range.from)) throw invalidRange(name, "from must be finite"); + if (range.to !== void 0 && !Number.isFinite(range.to)) throw invalidRange(name, "to must be finite"); + if (range.from !== void 0 && range.to !== void 0 && range.from > range.to) throw invalidRange(name, "from must be less than or equal to to"); + return range; +} +function matchesRange(value, range) { + return (range.from === void 0 || value >= range.from) && (range.to === void 0 || value <= range.to); +} +function invalidRange(name, detail) { + return invalidFilter(`${name} filter ${detail}`); +} +function invalidFilter(detail) { + return new SessionQueryError(`session ${detail}`, "SESSION_QUERY_INVALID_FILTER"); +} +function isRuntimeArray(value) { + return Array.isArray(value); +} +//#endregion +//#region lib/types/tracing.js +/** One-shot session-lineage and event-relationship tracing helpers. */ +/** +* Classify a raw event log with one canonical surface fold. +* @param sessionId - owner of the event log. +* @param events - detached raw event log. +* @returns lightweight records in ascending log order. +*/ +function eventRecords(sessionId, events) { + return analyzeEventLog(sessionId, events).records; +} +/** +* Fold and return the current model surface after validating the whole log. +* @param sessionId - owner used in query diagnostics. +* @param events - detached raw event log from one corpus observation. +* @returns detached current surface events in folded order. +*/ +function currentSurfaceEvents(sessionId, events) { + return analyzeEventLog(sessionId, events).currentSeqs.map((seq) => { + const event = events[seq]; + /* v8 ignore next 6 -- analyzeEventLog validated contiguous seqs and foldSurface returned only surface-event seqs. */ + if (event === void 0 || event.seq !== seq || !isSurfaceEvent(event)) throw new SessionQueryError(`invalid session surface: current node ${seq} is not a surface event`, "SESSION_QUERY_INVALID_SURFACE"); + return snapshotSessionEvent(event); + }); +} +/** +* Trace one target after one canonical surface fold and whole-log validation. +* @param sessionId - owner of the event log. +* @param events - detached raw event log. +* @param seq - target event seq. +* @returns direct surface replacements and relationships to cited source events. +*/ +function traceEvent(sessionId, events, seq) { + const target = events[seq]; + if (target === void 0 || target.seq !== seq) throw new SessionQueryError(`session "${sessionId}" has no event at seq ${seq}`, "SESSION_QUERY_EVENT_NOT_FOUND"); + const analysis = analyzeEventLog(sessionId, events); + const replacementChain = []; + let replacement = analysis.replacedBy.get(seq); + while (replacement !== void 0) { + replacementChain.push(replacement); + replacement = analysis.replacedBy.get(replacement); + } + const derivedEventSeqs = []; + for (const event of events) { + if (event.seq <= seq) continue; + if (eventSources(event).includes(seq)) derivedEventSeqs.push(event.seq); + } + const targetRecord = analysis.records[seq]; + const replacedBy = analysis.replacedBy.get(seq); + return { + target: targetRecord, + ...replacedBy === void 0 ? {} : { replacedBy }, + replacementChain, + replacedEventSeqs: analysis.replacedEventSeqs.get(seq) ?? [], + sourceEventSeqs: [...eventSources(target)], + derivedEventSeqs + }; +} +/** +* Trace one target's known ancestry and recursively known descendants. +* @param records - complete logical corpus from one observation. +* @param sessionId - target session id. +* @returns complete or explicitly partial lineage. +*/ +function traceSession(records, sessionId) { + const byId = new Map(records.map((record) => [record.header.id, record])); + const target = byId.get(sessionId); + if (target === void 0) throw new SessionQueryError(`session "${sessionId}" not found`, "SESSION_QUERY_SESSION_NOT_FOUND"); + const ancestors = []; + const ancestrySeen = new Set([sessionId]); + let unresolvedParentId; + let parentId = target.header.parentSession; + while (parentId !== void 0) { + if (ancestrySeen.has(parentId)) throw new SessionQueryError(`session lineage contains a cycle at "${parentId}"`, "SESSION_QUERY_INVALID_LINEAGE"); + ancestrySeen.add(parentId); + const parent = byId.get(parentId); + if (parent === void 0) { + unresolvedParentId = parentId; + break; + } + ancestors.push(parent); + parentId = parent.header.parentSession; + } + const childrenByParent = /* @__PURE__ */ new Map(); + for (const record of records) { + const parent = record.header.parentSession; + if (parent === void 0) continue; + const children = childrenByParent.get(parent) ?? []; + children.push(record); + childrenByParent.set(parent, children); + } + for (const children of childrenByParent.values()) children.sort((a, b) => a.header.createdAt - b.header.createdAt || a.header.id.localeCompare(b.header.id)); + const descendants = buildDescendants(childrenByParent, sessionId); + const common = { + target: cloneRecord(target), + ancestors: ancestors.map(cloneRecord), + descendants + }; + if (unresolvedParentId !== void 0) return { + ...common, + complete: false, + unresolvedParentId + }; + return { + ...common, + complete: true, + root: cloneRecord(ancestors.at(-1) ?? target) + }; +} +function analyzeEventLog(sessionId, events) { + let folded; + try { + folded = foldSurface(events); + } catch (error) { + throw new SessionQueryError( + /* v8 ignore next -- foldSurface throws Error instances */ + `invalid session surface: ${error instanceof Error ? error.message : "unknown error"}`, + "SESSION_QUERY_INVALID_SURFACE", + { cause: error } + ); + } + const current = new Set(folded.nodes); + const replacedBy = /* @__PURE__ */ new Map(); + const replacedEventSeqs = /* @__PURE__ */ new Map(); + for (const replacement of folded.replacements) { + const removed = replacement.shadowedSeqs; + replacedEventSeqs.set(replacement.seq, removed); + for (const removedSeq of removed) replacedBy.set(removedSeq, replacement.seq); + } + return { + records: events.map((event) => ({ + sessionId, + seq: event.seq, + type: event.type, + time: event.time, + surface: current.has(event.seq) ? "current" : replacedBy.has(event.seq) ? "shadowed" : "log-only" + })), + replacedBy, + replacedEventSeqs, + currentSeqs: [...folded.nodes] + }; +} +function eventSources(event) { + return event.sourceEventSeqs ?? []; +} +function buildDescendants(childrenByParent, sessionId) { + const descendants = []; + const stack = [{ + sessionId, + descendants + }]; + while (stack.length > 0) { + const frame = stack.pop(); + const nodes = []; + for (const child of childrenByParent.get(frame.sessionId) ?? []) { + const node = { + session: cloneRecord(child), + descendants: [] + }; + nodes.push(node); + frame.descendants.push(node); + } + for (let index = nodes.length - 1; index >= 0; index -= 1) { + const node = nodes[index]; + stack.push({ + sessionId: node.session.header.id, + descendants: node.descendants + }); + } + } + return descendants; +} +function cloneRecord(record) { + return { + ...record, + header: structuredClone(record.header) + }; +} +//#endregion +//#region lib/types/cursor.js +/** Opaque cursor identity for session-search pagination. */ +/** +* Brand an encoded provider cursor for the public search contract. +* @param value - opaque encoded cursor value. +* @returns the same runtime string with session-search cursor identity. +*/ +function SessionSearchCursor(value) { + return value; +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for combined session-history reads, traces, filters, and full-text search. +* +* @module @deepseek-ai/dsh-session-query +*/ +/** +* Unified live-preferred session query service. +* +* Exact reads, filters, and traces are backend-independent concrete behavior. +* A backend implements full-text observation, reconciliation, ranking, cursor +* generations, and query execution on the same `ctx.sessionQuery` service. +*/ +var SessionQueryEngine = class extends Service { + static inject = ["sessions"]; + _readWindowMax; + _corpus; + constructor(ctx, config = {}) { + super(ctx, "sessionQuery"); + this._readWindowMax = config.readWindowMax ?? 50; + if (!Number.isInteger(this._readWindowMax) || this._readWindowMax < 0) throw new SessionQueryError("session-query: readWindowMax must be a non-negative integer", "SESSION_QUERY_INVALID_CONFIG"); + const persistedInspectConcurrency = config.persistedInspectConcurrency ?? 4; + if (!Number.isSafeInteger(persistedInspectConcurrency) || persistedInspectConcurrency < 1) throw new SessionQueryError("session-query: persistedInspectConcurrency must be a positive safe integer", "SESSION_QUERY_INVALID_CONFIG"); + this._corpus = new SessionCorpus(ctx, persistedInspectConcurrency); + } + /** + * List the complete logical corpus using live-preferred records. + * @param signal - optional cancellation for persistence listing. + * @returns deterministic newest-first cloned session records. + */ + listSessions(signal) { + return this._corpus.listSessions(signal); + } + /** + * Read and replay-validate one complete logical session log without making it live. + * @param sessionId - live or persisted session id to read. + * @returns cloned header and complete raw event log from one observation. + * @throws when persistence, header compatibility, or replay validation fails. + */ + async readSession(sessionId) { + const loaded = await this._corpus.load(sessionId); + Session.create(sessionId, loaded.events, loaded.header); + return { + session: structuredClone(loaded.header), + events: loaded.events.map(snapshotSessionEvent) + }; + } + /** + * Filter the complete logical corpus with provider-independent predicates. + * @param filters - ANDed session metadata and availability clauses. + * @param signal - optional cancellation for persistence listing. + * @returns matching cloned records in deterministic newest-first order. + */ + async filterSessions(filters, signal) { + const ownedFilters = materializeSessionResultFilters(filters); + return this._filterSessions(ownedFilters, signal); + } + /** + * Fold the latest log-backed title from one live-preferred logical session. + * @param sessionId - live or persisted session id to read. + * @param signal - optional cancellation for source resolution and title folding. + * @returns latest title snapshot, or `undefined` when the log has no title event. + */ + async readTitle(sessionId, signal) { + return (await this.readTitleSnapshot(sessionId, signal)).title; + } + /** + * Fold the latest title and return its source header from one corpus observation. + * @param sessionId - live or persisted session id to read. + * @param signal - optional cancellation for source resolution and title folding. + * @returns cloned source header and optional latest title snapshot. + */ + async readTitleSnapshot(sessionId, signal) { + const result = (await this.readTitleSnapshots([sessionId], signal))[0]; + if (result.status === "rejected") throw result.reason; + return result.value; + } + /** + * Fold titles for unique sessions from one cancellable corpus observation. + * + * Results preserve first-occurrence input order. Operational failures stay + * isolated per session, while cancellation rejects the complete operation. + * @param sessionIds - live or persisted session ids to observe. + * @param signal - optional cancellation shared by all source reads. + * @returns one fulfilled or rejected result per unique requested id. + */ + async readTitleSnapshots(sessionIds, signal) { + return this._corpus.projectMany(sessionIds, (source) => { + const title = foldSessionTitle(source.events); + return { + session: structuredClone(source.header), + ...title === void 0 ? {} : { title } + }; + }, signal); + } + /** + * List lightweight raw-log event records for one logical session. + * @param sessionId - live-preferred session id to read. + * @returns event records in ascending seq order. + */ + async listEvents(sessionId) { + return eventRecords(sessionId, (await this._corpus.load(sessionId)).events); + } + /** + * Scan first-party semantic event documents with provider-independent filters. + * @param sessionId - live-preferred session id to scan. + * @param filters - ANDed metadata and literal-text predicates. + * @returns matching semantic documents in ascending seq order. + */ + async filterEvents(sessionId, filters) { + const ownedFilters = materializeSessionEventResultFilters(filters); + return this._filterEvents(sessionId, ownedFilters); + } + async _filterSessions(filters, signal) { + return filterSessionResults(await this._corpus.listSessions(signal), filters); + } + async _filterEvents(sessionId, filters) { + return filterSessionEventDocuments(buildSessionEventSearchDocuments(sessionId, (await this._corpus.load(sessionId)).events), filters); + } + /** + * Read one session's complete current model surface from one corpus observation. + * @param sessionId - live-preferred session id to read. + * @returns cloned header, current surface, and the last sequence number included in the raw-log capture. + * @throws when source resolution fails or the session surface is invalid. + */ + async readSurface(sessionId) { + const loaded = await this._corpus.load(sessionId); + return { + session: structuredClone(loaded.header), + capturedThroughSeq: loaded.events.at(-1)?.seq ?? null, + events: currentSurfaceEvents(sessionId, loaded.events) + }; + } + /** + * Trace known ancestry and descendants from one corpus observation. + * @param sessionId - logical session id to trace. + * @param signal - optional cancellation for persistence listing. + * @returns a complete lineage or the first parent that could not be resolved. + * @throws when corpus resolution fails, the target is absent, or its known ancestry cycles. + */ + async traceSession(sessionId, signal) { + const records = await this._corpus.listSessions(signal); + signal?.throwIfAborted(); + return traceSession(records, sessionId); + } + /** + * Trace one event's direct positional replacements and cited source events. + * @param request - target session id and event seq. + * @param signal - optional cancellation for persisted source resolution. + * @returns source header, direct links, and the target's positional replacement chain. + * @throws when source resolution fails, the target is absent, or surface/source-event validation fails. + */ + async traceEvent(request, signal) { + const loaded = await this._corpus.load(request.sessionId, signal); + signal?.throwIfAborted(); + return { + session: loaded.header, + ...traceEvent(request.sessionId, loaded.events, request.seq) + }; + } + /** + * Read one full event plus a bounded raw-log context window. + * @param request - target session/seq and context sizes. + * @param signal - optional cancellation for persisted source resolution. + * @returns cloned target and neighboring events. + */ + async readEvent(request, signal) { + const before = this._readWindow("before", request.before); + const after = this._readWindow("after", request.after); + const sessionId = request.sessionId; + const seq = request.seq; + return this._readEvent(sessionId, seq, before, after, signal); + } + async _readEvent(sessionId, seq, before, after, signal) { + const loaded = await this._corpus.load(sessionId, signal); + signal?.throwIfAborted(); + const target = loaded.events[seq]; + if (target === void 0 || target.seq !== seq) throw new SessionQueryError(`session "${sessionId}" has no event at seq ${seq}`, "SESSION_QUERY_EVENT_NOT_FOUND"); + const startSeq = Math.max(0, seq - before); + const endSeq = Math.min(loaded.events.length - 1, seq + after); + const targetSnapshot = snapshotSessionEvent(target); + const events = loaded.events.slice(startSeq, endSeq + 1).map((event) => event === target ? targetSnapshot : snapshotSessionEvent(event)); + return { + session: structuredClone(loaded.header), + target: targetSnapshot, + events, + startSeq, + endSeq + }; + } + _readWindow(name, value) { + if (value === void 0) return 0; + if (!Number.isInteger(value) || value < 0 || value > this._readWindowMax) throw new SessionQueryError(`${name} must be an integer between 0 and ${this._readWindowMax}`, "SESSION_QUERY_INVALID_WINDOW"); + return value; + } +}; +//#endregion +export { SESSION_QUERY_DEFAULT_PERSISTED_INSPECT_CONCURRENCY, SESSION_QUERY_READ_WINDOW_MAX, SessionQueryEngine, SessionQueryEngine as default, SessionQueryError, SessionSearchCursor, assertSessionHeadersCompatible, buildSessionEventRecords, buildSessionEventSearchDocuments, compileSessionTextFilter, extractSessionEventText, filterSessionEventDocuments, filterSessionResults, materializeSessionEventResultFilters, materializeSessionResultFilters }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/invariant.js new file mode 100644 index 0000000..fbd0558 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-session-query`. +* @module @deepseek-ai/dsh-session-query/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session-query"; +/** Cordis companion plugin name. */ +const name = "session-query-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: query results are immutable per-call projections whose lineage and event +* relations are validated while they are built; the service retains no observable result state. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/config.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/config.d.ts new file mode 100644 index 0000000..2869d58 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/config.d.ts @@ -0,0 +1,21 @@ +/** Public configuration and typed failures for the combined session-query service. */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +/** Default maximum `before`/`after` raw-event window. */ +export declare const SESSION_QUERY_READ_WINDOW_MAX = 50; +/** Default maximum number of concurrent persisted-log inspections in one batch read. */ +export declare const SESSION_QUERY_DEFAULT_PERSISTED_INSPECT_CONCURRENCY = 4; +/** Backend-independent configuration inherited by every session-query implementation. */ +export interface Config { + /** Maximum accepted raw read context on either side. Defaults to 50. */ + readWindowMax?: number; + /** Maximum concurrent persisted-log inspections in one batch read. Defaults to 4. */ + persistedInspectConcurrency?: number; +} +/** Stable machine-routable failure taxonomy for session reads, traces, and search. */ +export type SessionQueryErrorCode = 'SESSION_QUERY_ABORTED' | 'SESSION_QUERY_CORRUPT_SESSION' | 'SESSION_QUERY_EVENT_NOT_FOUND' | 'SESSION_QUERY_INDEX_FAILED' | 'SESSION_QUERY_INVALID_CONFIG' | 'SESSION_QUERY_INVALID_CURSOR' | 'SESSION_QUERY_INVALID_FILTER' | 'SESSION_QUERY_INVALID_LIMIT' | 'SESSION_QUERY_INVALID_QUERY' | 'SESSION_QUERY_INVALID_LINEAGE' | 'SESSION_QUERY_INVALID_SURFACE' | 'SESSION_QUERY_INVALID_WINDOW' | 'SESSION_QUERY_PERSISTENCE_FAILED' | 'SESSION_QUERY_SEARCH_DISABLED' | 'SESSION_QUERY_SESSION_NOT_FOUND' | 'SESSION_QUERY_STALE_CURSOR' | 'SESSION_QUERY_SOURCE_CONFLICT'; +/** Typed session-query failure whose `code` is one closed taxonomy member. */ +export declare class SessionQueryError extends HarnessError { + readonly code: SessionQueryErrorCode; + constructor(message: string, code: SessionQueryErrorCode, options?: ErrorOptions); +} +//# sourceMappingURL=config.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/corpus.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/corpus.d.ts new file mode 100644 index 0000000..f10b6ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/corpus.d.ts @@ -0,0 +1,64 @@ +/** Live/persisted logical-corpus resolution for session-query. */ +import type { Context } from '@deepseek-ai/cordis'; +import type { SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session'; +import type { SessionRecord } from './types.ts'; +/** Detached source selected for one exact read. */ +export interface LogicalSession { + /** Cloned source header. */ + header: SessionHeader; + /** Cloned raw event log. */ + events: SessionEvent[]; +} +/** Borrowed source visible only during one synchronous batch projection. */ +export interface LogicalSessionSource { + /** Header selected with `events`; callers must clone retained output. */ + readonly header: SessionHeader; + /** Raw events selected with `header`; valid only for the projection call. */ + readonly events: readonly SessionEvent[]; +} +/** One source-projection result in a batch logical-corpus observation. */ +export type LogicalProjectionResult = { + sessionId: SessionId; + status: 'fulfilled'; + value: Value; +} | { + sessionId: SessionId; + status: 'rejected'; + reason: unknown; +}; +/** Resolves a live-preferred corpus against the persistence service mounted now. */ +export declare class SessionCorpus { + private readonly _ctx; + private readonly _persistedInspectConcurrency; + private _persistence; + private readonly _optionalPersistenceFiber; + constructor(_ctx: Context, _persistedInspectConcurrency: number); + /** + * List the complete logical corpus with live precedence and cloned headers. + * @param signal - optional cancellation for persistence listing. + * @returns records in deterministic newest-first order. + */ + listSessions(signal?: AbortSignal): Promise; + /** + * Load one logical source, preferring a detached live snapshot. + * + * A known live target never consults persistence, so an optional backend's + * failure cannot make current in-memory history unreadable. + * @param sessionId - session to resolve. + * @param signal - optional cancellation for persisted source resolution. + * @returns detached live-preferred header and events. + */ + load(sessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Project unique logical sources immediately from one persistence listing. + * + * The synchronous projector runs before a persisted worker claims its next id. + * Full logs are borrowed only for that call and never retained by the batch. + * @param sessionIds - sessions to resolve in first-occurrence order. + * @param project - synchronous fold that owns/clones every retained value. + * @param signal - cancellation shared by listing and every persisted inspection. + * @returns one fulfilled or rejected projected result per unique requested id. + */ + projectMany(sessionIds: readonly SessionId[], project: (source: LogicalSessionSource) => Value, signal?: AbortSignal): Promise[]>; +} +//# sourceMappingURL=corpus.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/cursor.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/cursor.d.ts new file mode 100644 index 0000000..969ed10 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/cursor.d.ts @@ -0,0 +1,11 @@ +/** Opaque cursor identity for session-search pagination. */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Provider-owned opaque continuation token returned by session search. */ +export type SessionSearchCursor = Branded<'SessionSearchCursor'>; +/** + * Brand an encoded provider cursor for the public search contract. + * @param value - opaque encoded cursor value. + * @returns the same runtime string with session-search cursor identity. + */ +export declare function SessionSearchCursor(value: string): SessionSearchCursor; +//# sourceMappingURL=cursor.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/documents.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/documents.d.ts new file mode 100644 index 0000000..1208f8d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/documents.d.ts @@ -0,0 +1,18 @@ +/** Shared event metadata and semantic-document projection. */ +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'; +import type { SessionEventRecord, SessionEventSearchDocument } from './types.ts'; +/** + * Project a raw log into lightweight surface-aware event records. + * @param sessionId - session that owns the log. + * @param events - complete contiguous raw event log. + * @returns one record per event in ascending seq order. + */ +export declare function buildSessionEventRecords(sessionId: SessionId, events: readonly SessionEvent[]): SessionEventRecord[]; +/** + * Build first-party semantic documents for one complete raw event log. + * @param sessionId - session that owns the log. + * @param events - complete contiguous raw event log. + * @returns searchable documents in ascending seq order; structural events are omitted. + */ +export declare function buildSessionEventSearchDocuments(sessionId: SessionId, events: readonly SessionEvent[]): SessionEventSearchDocument[]; +//# sourceMappingURL=documents.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/extraction.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/extraction.d.ts new file mode 100644 index 0000000..713e425 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/extraction.d.ts @@ -0,0 +1,12 @@ +/** First-party semantic text extraction for session-query consumers. */ +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +/** + * Extract searchable semantic text from one first-party session event. + * + * Structural boundaries, raw stream chunks, request envelopes, and unknown + * declaration-merged events contribute no text. + * @param event - event to inspect. + * @returns newline-joined semantic text, or an empty string when non-searchable. + */ +export declare function extractSessionEventText(event: SessionEvent): string; +//# sourceMappingURL=extraction.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/filters.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/filters.d.ts new file mode 100644 index 0000000..a6f010b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/filters.d.ts @@ -0,0 +1,35 @@ +/** Pure provider-independent predicates for logical sessions and event text. */ +import type { SessionEventResultFilter, SessionEventSearchDocument, SessionRecord, SessionResultFilter } from './types.ts'; +/** + * Apply ANDed logical-session filters while preserving input order. + * @param records - detached logical-session records to inspect. + * @param filters - clauses whose list values are ORed within each clause. + * @returns records accepted by every clause. + */ +export declare function filterSessionResults(records: readonly T[], filters?: readonly SessionResultFilter[]): T[]; +/** + * Apply ANDed event filters to extracted semantic documents. + * @param documents - semantic documents produced by {@link buildSessionEventSearchDocuments}. + * @param filters - metadata and literal-text predicates. + * @returns documents accepted by every clause, in input order. + */ +export declare function filterSessionEventDocuments(documents: readonly T[], filters?: readonly SessionEventResultFilter[]): T[]; +/** + * Copy and validate logical-session filters before an asynchronous boundary. + * @param filters - caller-owned clauses to materialize. + * @returns detached validated clauses. + */ +export declare function materializeSessionResultFilters(filters: readonly SessionResultFilter[]): SessionResultFilter[]; +/** + * Copy and validate event filters before an asynchronous boundary. + * @param filters - caller-owned clauses to materialize. + * @returns detached validated clauses. + */ +export declare function materializeSessionEventResultFilters(filters: readonly SessionEventResultFilter[]): SessionEventResultFilter[]; +/** + * Compile a literal case-insensitive, whitespace-flexible semantic-text match. + * @param text - caller-provided literal text. + * @returns Unicode-aware regular expression safe from regex injection. + */ +export declare function compileSessionTextFilter(text: string): RegExp; +//# sourceMappingURL=filters.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/index.d.ts new file mode 100644 index 0000000..4b29880 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/index.d.ts @@ -0,0 +1,143 @@ +/** + * Service Definition for combined session-history reads, traces, filters, and full-text search. + * + * @module @deepseek-ai/dsh-session-query + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import { type SessionId } from '@deepseek-ai/dsh-session'; +import type { SessionTitleSnapshot } from '@deepseek-ai/dsh-session-title'; +import type { SessionEventResultFilter, SessionEventSearchPage, SessionEventReadRequest, SessionEventRecord, SessionEventSearchDocument, SessionEventSearchRequest, SessionEventTraceObservation, SessionEventTraceRequest, SessionEventWindow, SessionLineageTrace, SessionLogSnapshot, SessionRecord, SessionResultFilter, SessionSearchExecContext, SessionSearchHit, SessionSearchPage, SessionSearchRequest, SessionSurfaceSnapshot, SessionTitleObservation, SessionTitleObservationResult } from './types.ts'; +import { type Config } from './config.ts'; +export type * from './types.ts'; +export { SessionSearchCursor } from './cursor.ts'; +export type { Config, SessionQueryErrorCode } from './config.ts'; +export { SESSION_QUERY_DEFAULT_PERSISTED_INSPECT_CONCURRENCY, SESSION_QUERY_READ_WINDOW_MAX, SessionQueryError, } from './config.ts'; +export { extractSessionEventText } from './extraction.ts'; +export { buildSessionEventRecords, buildSessionEventSearchDocuments } from './documents.ts'; +export { compileSessionTextFilter, filterSessionEventDocuments, filterSessionResults, materializeSessionEventResultFilters, materializeSessionResultFilters, } from './filters.ts'; +export { assertSessionHeadersCompatible } from './sources.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + sessionQuery: SessionQueryEngine; + } +} +/** + * Unified live-preferred session query service. + * + * Exact reads, filters, and traces are backend-independent concrete behavior. + * A backend implements full-text observation, reconciliation, ranking, cursor + * generations, and query execution on the same `ctx.sessionQuery` service. + */ +export declare abstract class SessionQueryEngine extends Service { + static inject: string[]; + private readonly _readWindowMax; + private readonly _corpus; + constructor(ctx: Context, config?: Config); + /** + * Search the live-preferred logical corpus and group by session. + * @param request - query text, metadata filters, page size, and cursor. + * @param exec - optional cancellation control. + * @returns session hits ranked by their strongest matching event. + */ + abstract searchSessions(request: SessionSearchRequest, exec?: SessionSearchExecContext): Promise>; + /** + * Search events within one live-preferred logical session. + * @param request - target session, query text, filters, page size, and cursor. + * @param exec - optional cancellation control. + * @returns matching event hits and their target header from one indexed generation. + */ + abstract searchEvents(request: SessionEventSearchRequest, exec?: SessionSearchExecContext): Promise; + /** + * List the complete logical corpus using live-preferred records. + * @param signal - optional cancellation for persistence listing. + * @returns deterministic newest-first cloned session records. + */ + listSessions(signal?: AbortSignal): Promise; + /** + * Read and replay-validate one complete logical session log without making it live. + * @param sessionId - live or persisted session id to read. + * @returns cloned header and complete raw event log from one observation. + * @throws when persistence, header compatibility, or replay validation fails. + */ + readSession(sessionId: SessionId): Promise; + /** + * Filter the complete logical corpus with provider-independent predicates. + * @param filters - ANDed session metadata and availability clauses. + * @param signal - optional cancellation for persistence listing. + * @returns matching cloned records in deterministic newest-first order. + */ + filterSessions(filters: readonly SessionResultFilter[], signal?: AbortSignal): Promise; + /** + * Fold the latest log-backed title from one live-preferred logical session. + * @param sessionId - live or persisted session id to read. + * @param signal - optional cancellation for source resolution and title folding. + * @returns latest title snapshot, or `undefined` when the log has no title event. + */ + readTitle(sessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Fold the latest title and return its source header from one corpus observation. + * @param sessionId - live or persisted session id to read. + * @param signal - optional cancellation for source resolution and title folding. + * @returns cloned source header and optional latest title snapshot. + */ + readTitleSnapshot(sessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Fold titles for unique sessions from one cancellable corpus observation. + * + * Results preserve first-occurrence input order. Operational failures stay + * isolated per session, while cancellation rejects the complete operation. + * @param sessionIds - live or persisted session ids to observe. + * @param signal - optional cancellation shared by all source reads. + * @returns one fulfilled or rejected result per unique requested id. + */ + readTitleSnapshots(sessionIds: readonly SessionId[], signal?: AbortSignal): Promise; + /** + * List lightweight raw-log event records for one logical session. + * @param sessionId - live-preferred session id to read. + * @returns event records in ascending seq order. + */ + listEvents(sessionId: SessionId): Promise; + /** + * Scan first-party semantic event documents with provider-independent filters. + * @param sessionId - live-preferred session id to scan. + * @param filters - ANDed metadata and literal-text predicates. + * @returns matching semantic documents in ascending seq order. + */ + filterEvents(sessionId: SessionId, filters: readonly SessionEventResultFilter[]): Promise; + private _filterSessions; + private _filterEvents; + /** + * Read one session's complete current model surface from one corpus observation. + * @param sessionId - live-preferred session id to read. + * @returns cloned header, current surface, and the last sequence number included in the raw-log capture. + * @throws when source resolution fails or the session surface is invalid. + */ + readSurface(sessionId: SessionId): Promise; + /** + * Trace known ancestry and descendants from one corpus observation. + * @param sessionId - logical session id to trace. + * @param signal - optional cancellation for persistence listing. + * @returns a complete lineage or the first parent that could not be resolved. + * @throws when corpus resolution fails, the target is absent, or its known ancestry cycles. + */ + traceSession(sessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Trace one event's direct positional replacements and cited source events. + * @param request - target session id and event seq. + * @param signal - optional cancellation for persisted source resolution. + * @returns source header, direct links, and the target's positional replacement chain. + * @throws when source resolution fails, the target is absent, or surface/source-event validation fails. + */ + traceEvent(request: SessionEventTraceRequest, signal?: AbortSignal): Promise; + /** + * Read one full event plus a bounded raw-log context window. + * @param request - target session/seq and context sizes. + * @param signal - optional cancellation for persisted source resolution. + * @returns cloned target and neighboring events. + */ + readEvent(request: SessionEventReadRequest, signal?: AbortSignal): Promise; + private _readEvent; + private _readWindow; +} +export default SessionQueryEngine; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/invariant.d.ts new file mode 100644 index 0000000..fc2cb87 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-query`. + * @module @deepseek-ai/dsh-session-query/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-query-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/sources.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/sources.d.ts new file mode 100644 index 0000000..2390501 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/sources.d.ts @@ -0,0 +1,9 @@ +/** Shared immutable-header checks for logical session source observers. */ +import type { SessionHeader } from '@deepseek-ai/dsh-session'; +/** + * Reject incompatible observations of one logical session source. + * @param a - first live, listed, or loaded header observation. + * @param b - second header observation expected to identify the same source. + */ +export declare function assertSessionHeadersCompatible(a: SessionHeader, b: SessionHeader): void; +//# sourceMappingURL=sources.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/tracing.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/tracing.d.ts new file mode 100644 index 0000000..6e9ddfb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/tracing.d.ts @@ -0,0 +1,33 @@ +/** One-shot session-lineage and event-relationship tracing helpers. */ +import type { SessionEvent, SessionId, SurfaceEvent } from '@deepseek-ai/dsh-session'; +import type { SessionEventRecord, SessionEventTrace, SessionLineageTrace, SessionRecord } from './types.ts'; +/** + * Classify a raw event log with one canonical surface fold. + * @param sessionId - owner of the event log. + * @param events - detached raw event log. + * @returns lightweight records in ascending log order. + */ +export declare function eventRecords(sessionId: SessionId, events: readonly SessionEvent[]): SessionEventRecord[]; +/** + * Fold and return the current model surface after validating the whole log. + * @param sessionId - owner used in query diagnostics. + * @param events - detached raw event log from one corpus observation. + * @returns detached current surface events in folded order. + */ +export declare function currentSurfaceEvents(sessionId: SessionId, events: readonly SessionEvent[]): SurfaceEvent[]; +/** + * Trace one target after one canonical surface fold and whole-log validation. + * @param sessionId - owner of the event log. + * @param events - detached raw event log. + * @param seq - target event seq. + * @returns direct surface replacements and relationships to cited source events. + */ +export declare function traceEvent(sessionId: SessionId, events: readonly SessionEvent[], seq: number): SessionEventTrace; +/** + * Trace one target's known ancestry and recursively known descendants. + * @param records - complete logical corpus from one observation. + * @param sessionId - target session id. + * @returns complete or explicitly partial lineage. + */ +export declare function traceSession(records: readonly SessionRecord[], sessionId: SessionId): SessionLineageTrace; +//# sourceMappingURL=tracing.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/types.d.ts new file mode 100644 index 0000000..5f875ef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/lib/types/types.d.ts @@ -0,0 +1,259 @@ +/** + * Public records for exact reads and relationship traces over the + * live-preferred logical session corpus. + * + * @module @deepseek-ai/dsh-session-query/types + */ +import type { SessionEvent, SessionEventType, SessionHeader, SessionId, SurfaceEvent } from '@deepseek-ai/dsh-session'; +import type { SessionTitleSnapshot } from '@deepseek-ai/dsh-session-title'; +import type { SessionSearchCursor } from './cursor.ts'; +export type { SessionSearchCursor } from './cursor.ts'; +/** Whether an event is current model context, replaced context, or raw-log-only. */ +export type SessionEventSurface = 'current' | 'shadowed' | 'log-only'; +/** Lightweight identity and source availability for one logical session. */ +export interface SessionRecord { + /** Cloned session header selected from the live-preferred corpus. */ + header: SessionHeader; + /** Whether the id currently exists in `ctx.sessions`. */ + live: boolean; + /** Whether the active persistence backend currently materializes the id. */ + persisted: boolean; +} +/** One atomic live-preferred observation of a session's current model surface. */ +export interface SessionSurfaceSnapshot { + /** Cloned session header selected from the same corpus observation as `events`. */ + session: SessionHeader; + /** Highest raw-log seq included in the observation, or `null` for an empty log. */ + capturedThroughSeq: number | null; + /** Cloned current surface events in model-history order. */ + events: SurfaceEvent[]; +} +/** One validated detached observation of a logical session's complete raw log. */ +export interface SessionLogSnapshot { + /** Cloned session header selected from the same observation as `events`. */ + session: SessionHeader; + /** Cloned contiguous raw events after persistence repair and replay validation. */ + events: SessionEvent[]; +} +/** Lightweight metadata for one event within a logical session. */ +export interface SessionEventRecord { + /** Session that owns the event. */ + sessionId: SessionId; + /** Monotonic event seq within the session. */ + seq: number; + /** Discriminant of the session event. */ + type: SessionEventType; + /** Event timestamp in Unix epoch milliseconds. */ + time: number; + /** Event placement in the folded session surface. */ + surface: SessionEventSurface; +} +/** Recursive descendant node in a session-lineage trace. */ +export interface SessionLineageNode { + /** Detached logical-corpus record for this descendant. */ + session: SessionRecord; + /** Direct children, each carrying its own recursive descendants. */ + descendants: SessionLineageNode[]; +} +/** Known ancestry and descendants for one logical session. */ +export type SessionLineageTrace = { + /** Detached record for the session that was traced. */ + target: SessionRecord; + /** Known parents from the immediate parent outward. */ + ancestors: SessionRecord[]; + /** Complete known descendant trees rooted at the target's direct children. */ + descendants: SessionLineageNode[]; +} & ({ + /** The complete parent chain is present in the logical corpus. */ + complete: true; + /** Detached record at the top of the complete lineage. */ + root: SessionRecord; +} | { + /** The parent chain leaves the visible logical corpus. */ + complete: false; + /** First parent id that is not present in the logical corpus. */ + unresolvedParentId: SessionId; +}); +/** Request for direct surface replacements and relationships to cited source events around one event. */ +export interface SessionEventTraceRequest { + /** Session that owns the target event. */ + sessionId: SessionId; + /** Target event seq. */ + seq: number; +} +/** Direct surface replacements and relationships to cited source events for one event. */ +export interface SessionEventTrace { + /** Lightweight target record. */ + target: SessionEventRecord; + /** Immediate positional replacement event, when the target was shadowed. */ + replacedBy?: number; + /** Positional replacers from the immediate replacement to the final replacement. */ + replacementChain: number[]; + /** Surface nodes directly removed when the target itself performed a replacement. */ + replacedEventSeqs: number[]; + /** Earlier events cited directly as sources, in their recorded order. */ + sourceEventSeqs: number[]; + /** Later events that directly cite the target as a source, in log order. */ + derivedEventSeqs: number[]; +} +/** Event relationships bound to the same session-header observation. */ +export interface SessionEventTraceObservation extends SessionEventTrace { + /** Cloned header selected with the event log used for the trace. */ + session: SessionHeader; +} +/** Request for one event plus raw neighboring log context. */ +export interface SessionEventReadRequest { + /** Session that owns the target event. */ + sessionId: SessionId; + /** Target event seq. */ + seq: number; + /** Number of preceding raw events to include. */ + before?: number; + /** Number of following raw events to include. */ + after?: number; +} +/** Full target event and a bounded raw-log window. */ +export interface SessionEventWindow { + /** Cloned header for the live-preferred source read. */ + session: SessionHeader; + /** Full cloned target event. */ + target: SessionEvent; + /** Full cloned events from `startSeq` through `endSeq`. */ + events: SessionEvent[]; + /** First seq included in `events`. */ + startSeq: number; + /** Last seq included in `events`. */ + endSeq: number; +} +/** Latest folded title bound to the same session-header observation. */ +export interface SessionTitleObservation { + /** Cloned header selected with the event log used for the title fold. */ + session: SessionHeader; + /** Latest title snapshot, absent when the observed log has no title. */ + title?: SessionTitleSnapshot; +} +/** One ordered result from a batch title observation. */ +export type SessionTitleObservationResult = { + /** Requested session id. */ + sessionId: SessionId; + /** Successful atomic header/title observation. */ + status: 'fulfilled'; + /** Header and optional latest title from one logical source. */ + value: SessionTitleObservation; +} | { + /** Requested session id. */ + sessionId: SessionId; + /** Operational failure isolated to this session. */ + status: 'rejected'; + /** Original failure from logical-source resolution or title folding. */ + reason: unknown; +}; +/** Inclusive numeric interval used by time and sequence filters. */ +export interface SessionResultRange { + /** Inclusive lower bound. */ + from?: number; + /** Inclusive upper bound. */ + to?: number; +} +/** Source availability predicates understood by logical-session filters. */ +export type SessionAvailability = 'live' | 'persisted'; +/** + * One logical-session predicate. A filter array is ANDed; `values` within a + * clause are ORed. + */ +export type SessionResultFilter = { + kind: 'id'; + values: readonly SessionId[]; +} | { + kind: 'cwd'; + values: readonly (string | null)[]; +} | ({ + kind: 'created-at'; +} & SessionResultRange) | { + kind: 'parent'; + values: readonly (SessionId | null)[]; +} | { + kind: 'availability'; + values: readonly SessionAvailability[]; +}; +/** + * One event predicate. A filter array is ANDed; list-valued clauses are ORed. + * Text is a literal, case-insensitive, whitespace-flexible semantic-text scan. + */ +export type SessionEventResultFilter = ({ + kind: 'seq'; +} & SessionResultRange) | ({ + kind: 'time'; +} & SessionResultRange) | { + kind: 'type'; + values: readonly SessionEventType[]; +} | { + kind: 'surface'; + values: readonly SessionEventSurface[]; +} | { + kind: 'text'; + text: string; +}; +/** Event predicates a full-text provider can apply before relevance ranking. */ +export type SessionEventMetadataFilter = Exclude; +/** Searchable semantic document derived from one session event. */ +export interface SessionEventSearchDocument extends SessionEventRecord { + /** First-party semantic text used by scan filters and full-text indexes. */ + text: string; +} +/** One cursor-paginated result page. */ +export interface SessionSearchPage { + /** Results for this page in contract-defined order. */ + items: readonly T[]; + /** Opaque continuation cursor, absent on the final page. */ + nextCursor?: SessionSearchCursor; +} +/** Event-search results bound to the indexed target-session observation. */ +export interface SessionEventSearchPage extends SessionSearchPage { + /** Cloned target header from the same indexed generation as `items`. */ + session: SessionHeader; +} +/** Controls shared by cross-session and within-session search calls. */ +export interface SessionSearchExecContext { + /** Abort caller waiting and interrupt provider work where supported. */ + signal?: AbortSignal; +} +/** Cross-session full-text search request. */ +export interface SessionSearchRequest { + /** Full-text query interpreted as data, never executable FTS syntax. */ + query: string; + /** Logical-session predicates applied before event ranking. */ + sessionFilters?: readonly SessionResultFilter[]; + /** Event predicates applied before event ranking. */ + eventFilters?: readonly SessionEventMetadataFilter[]; + /** Maximum sessions in this page. */ + limit?: number; + /** Opaque cursor returned for the identical normalized request. */ + cursor?: SessionSearchCursor; +} +/** Within-session full-text search request. */ +export interface SessionEventSearchRequest { + /** Session whose live-preferred logical log is searched. */ + sessionId: SessionId; + /** Full-text query interpreted as data, never executable FTS syntax. */ + query: string; + /** Event predicates applied before ranking. */ + filters?: readonly SessionEventMetadataFilter[]; + /** Maximum events in this page. */ + limit?: number; + /** Opaque cursor returned for the identical normalized request. */ + cursor?: SessionSearchCursor; +} +/** One event full-text search hit with a bounded plain-text excerpt. */ +export interface SessionEventSearchHit extends SessionEventRecord { + /** Plain text excerpt selected around the match. */ + snippet: string; +} +/** One grouped cross-session hit, ranked by its strongest matching event. */ +export interface SessionSearchHit extends SessionRecord { + /** Strongest matching event for this session. */ + bestMatch: SessionEventSearchHit; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/package.json new file mode 100644 index 0000000..d2051ef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-query/package.json @@ -0,0 +1,57 @@ +{ + "name": "@deepseek-ai/dsh-session-query", + "description": "Combined session query service contract with concrete reads, traces, and filters", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session-query/session-query" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + } + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-title b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-title new file mode 120000 index 0000000..f2e65bb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.6_544b8438a28525db12c0e9ef99074d42/node_modules/@deepseek-ai/dsh-session-title @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..5362978 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.i18n.yaml new file mode 100644 index 0000000..783b6d9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/session-query/session-query/README.md +README.md: 02640bee4b3eb7f6877756a2ce84b26f698c9f58 +README.zh.md: 794c0e6e86606d92ed82ec286844647487df3295 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.md new file mode 100644 index 0000000..02640be --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.md @@ -0,0 +1,56 @@ +# @deepseek-ai/dsh-session-query + +English | [中文](README.zh.md) + +`SessionQueryEngine` is the combined abstract `ctx.sessionQuery` contract. It implements exact session-history retrieval, relationship tracing, and provider-independent filtering over live `ctx.sessions` plus optional dynamically mounted `ctx.sessionPersistence`; concrete backends implement its two full-text methods. Matching ids produce one record: live events win, while `live` and `persisted` report both source availabilities. Conflicting immutable headers fail with `SESSION_QUERY_SOURCE_CONFLICT`. + +## Reads + +- `listSessions(signal?)` reads current persistence metadata, merges live records with live precedence, and returns cloned records in deterministic newest-first order. +- `readSession(sessionId)` returns one complete detached raw log after the same core replay validation used by resume; it never enters the session into the live store. +- `filterSessions(filters, signal?)` applies provider-independent session metadata and availability predicates to that same cloned logical corpus. +- `filterEvents(sessionId, filters)` extracts first-party semantic documents and applies provider-independent metadata and literal-text predicates in ascending seq order. +- `readTitleSnapshots(sessionIds, signal?)` resolves unique ids from one live-preferred corpus observation, passes cancellation through persisted listing and inspection, and returns ordered per-session settlements so one missing or malformed title source does not discard its peers. Each live source is folded directly, and each persisted worker folds to a detached header/title result and releases the full log before dequeuing another id. Cancellation rejects the whole batch. `readTitleSnapshot(sessionId, signal?)` is the one-observation view; `readTitle(sessionId, signal?)` returns only its optional folded `session/title`. +- `listEvents(sessionId)` loads the live-preferred raw log and classifies each event as `current`, `shadowed`, or `log-only` with the shared `dsh-session` surface fold. +- `readSurface(sessionId)` returns one cloned header, raw-log capture boundary, and the complete folded current surface in model-history order. A live session wins over persistence; compaction is observed before or after its replacement append, never as a synthetic mixture. +- `readEvent(request, signal?)` returns a cloned header, the full target event, and a bounded raw-seq window. `before` and `after` default to zero and may not exceed `readWindowMax`. +- `traceSession(sessionId, signal?)` reads the corpus once and returns immediate-to-outward ancestors plus deterministic recursive descendant trees. `complete: false` identifies the first missing parent; a target-connected cycle fails with `SESSION_QUERY_INVALID_LINEAGE`. +- `traceEvent(request, signal?)` loads the logical log once and returns its cloned source header with direct positional replacements and direct cited source-event links. `replacementChain` follows positional replacers to the final replacement; source-event links remain non-transitive. + +Persistence is optional and may mount or unmount dynamically. Cross-corpus listing and lineage tracing fail with `SESSION_QUERY_PERSISTENCE_FAILED` while mounted persistence is unreadable; a successfully read durable record that fails Session validation reports `SESSION_QUERY_CORRUPT_SESSION` instead. A title read, event trace, or event read targeting a known live session does not consult persistence, so durable backend health cannot make current in-memory state unreadable. Persisted title and event operations list before loading and reject a metadata mismatch rather than combining inconsistent observations. Lineage-trace cancellation is passed to persisted listing; event-trace and event-read cancellation is passed to persisted listing and inspection. Each waits for the started backend call to settle, then rejects with the signal's exact reason even when the backend ignored that signal. A pre-aborted known-live title read, event trace, or event read rejects before folding or snapshotting without consulting persistence. A batch title observation performs one metadata listing, inspects its unique persisted ids with at most `persistedInspectConcurrency` workers, and preserves each title's own observed header for downstream authorization. Cancellation starts no queued inspections and rejects only after already-started workers settle. `listSessions()` remains lightweight and does not load logs or index titles. + +## Filtering and extraction + +`SessionResultFilter` covers id, nullable cwd, created-at range, nullable parent, and source availability. `SessionEventResultFilter` covers seq/time ranges, event type, surface, and semantic text. Filter arrays are ANDed; values within one list clause are ORed. Empty list values match nothing, ranges are inclusive, and malformed ranges or closed-union values fail with `SESSION_QUERY_INVALID_FILTER`. + +The text clause is deliberately independent of FTS providers: caller text is escaped into a Unicode, case-insensitive regular expression, and each whitespace run matches one or more whitespace characters. It is a literal semantic-text scan, not a full-text query. `extractSessionEventText()` and `buildSessionEventSearchDocuments()` define the shared first-party document projection; reasoning blocks, structural boundaries, stream chunks, request headers, and unknown declaration-merged variants produce no document. + +## Full-text methods + +`SessionQueryEngine.searchSessions(request, exec?)` groups the logical corpus by strongest matching event; `searchEvents(request, exec?)` searches one logical session. These are the service's only abstract methods. Both return pages whose continuation is an owned branded `SessionSearchCursor`, accept optional cancellation, and expose snippets without provider-specific numeric scores. An event-search page also carries the cloned target header from the same indexed generation as its hits, allowing authorization consumers to bind policy to the payload observation. Search requests accept only metadata event filters, because literal-text filtering is the scan path described above. + +The package has no provider coordinator, fallback implementation, or standalone concrete plugin. A concrete service backend inherits the implemented reads, filters, and traces while owning full-text observation, reconciliation, ranking, cursor generations, and query execution; the first implementation is [`@deepseek-ai/dsh-session-query-sqlite`](../session-query-sqlite/README.md). + +`SessionQueryError.code` is a closed union covering request validation, missing targets, malformed surfaces, source conflicts, persistence/index failures, cancellation, and invalid or stale cursors; the exact literals are defined in [`src/config.ts`](src/config.ts). + +`listEvents()`, `readSurface()`, and `traceEvent()` run the same one-pass `dsh-session` surface fold. A loaded log is valid only when event seqs are zero-based and contiguous, surface markers obey event-type eligibility, source-event arrays are nonempty and duplicate-free, references name earlier events, and each positional replacement names and cites every surface node it removes; every violation fails with `SESSION_QUERY_INVALID_SURFACE`. + +## Configuration + +| Key | Default | Contract | +|---|---:|---| +| `readWindowMax` | `50` | Maximum `before` or `after` raw-event count. | +| `persistedInspectConcurrency` | `4` | Maximum concurrent persisted-log inspections in one batch read; must be a positive safe integer. | + +## Model Experience + +None, as this trusted query service returns cloned session records only to its callers and registers no model-facing prompt, schema, tool, or message. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **No caller authorization** — this is trusted context-wide infrastructure; a future model tool or UI must constrain which sessions its caller may inspect. +- **No registries or model-facing tool** — extractor and search-provider registries, recursive traversal through cited source events, and a model-facing tool are absent. The [tracing decision](../../../.agents/notes/implemented/feature/2026-07-13-session-query-tracing.md) owns relationship semantics; SQLite ownership and tokenizer decisions live in the [implemented search note](../../../.agents/notes/implemented/feature/2026-07-10-sqlite-session-query-provider.md). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.zh.md new file mode 100644 index 0000000..794c0e6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/README.zh.md @@ -0,0 +1,56 @@ +# @deepseek-ai/dsh-session-query + +[English](README.md) | 中文 + +`SessionQueryEngine` 是组合式抽象 `ctx.sessionQuery` 约定。它对实时 `ctx.sessions` 和可选的动态挂载 `ctx.sessionPersistence` 实现精确会话历史取回、关系跟踪和与提供方无关的过滤;具体后端实现它的两个全文方法。匹配 id 只产生一条记录:实时事件优先,而 `live` 和 `persisted` 会报告两种来源的可用性。如果不可变 header 存在冲突,则以 `SESSION_QUERY_SOURCE_CONFLICT` 失败。 + +## 读取 + +- `listSessions(signal?)` 读取当前持久化元数据,以实时记录优先的方式合并它们,并按确定性的最新优先顺序返回克隆记录。 +- `readSession(sessionId)` 在执行与恢复相同的核心回放验证后,返回一份完整、脱离存储的原始日志;它绝不会将该会话放入实时存储。 +- `filterSessions(filters, signal?)` 对同一份克隆逻辑语料库应用与提供方无关的会话元数据和可用性谓词。 +- `filterEvents(sessionId, filters)` 提取第一方语义文档,并按 seq 升序应用与提供方无关的元数据和字面文本谓词。 +- `readTitleSnapshots(sessionIds, signal?)` 从一次实时优先的语料库观察中解析唯一 id,将取消信号传递给持久化列表查询和检查,并按顺序返回每个会话的结算结果,使某个缺失或格式错误的标题来源不会导致其他会话的结果被丢弃。每个实时来源直接 fold,每个持久化 worker fold 为脱离存储的 header/标题结果,并在出队下一个 id 前释放完整日志。取消会拒绝整个批次。`readTitleSnapshot(sessionId, signal?)` 是单次观察视图;`readTitle(sessionId, signal?)` 只返回其可选的 folded `session/title`。 +- `listEvents(sessionId)` 加载实时优先的原始日志,将每个事件分类为 `current`、`shadowed` 或 `log-only`;该分类使用共享 `dsh-session` 表层 fold。 +- `readSurface(sessionId)` 返回一个克隆 header、原始日志捕获边界,以及按模型历史顺序排列的完整折叠后当前表层。实时会话优先于持久化;压缩(compaction)只会在其替换追加之前或之后被观察,绝不会出现合成混合。 +- `readEvent(request, signal?)` 返回一个克隆 header、完整目标事件和有界的原始 seq 窗口。`before` 和 `after` 默认为 0,且不得超过 `readWindowMax`。 +- `traceSession(sessionId, signal?)` 只读取一次语料库,返回从直接父级向外的祖先,以及确定性的递归后代树。`complete: false` 标识第一个缺失父级;与目标相连的循环会以 `SESSION_QUERY_INVALID_LINEAGE` 失败。 +- `traceEvent(request, signal?)` 只加载一次逻辑日志,返回其克隆源 header、直接位置替换和直接引用的源事件链接。`replacementChain` 沿位置替换者跟踪到最终替换;源事件链接仍不传递。 + +持久化是可选的,可动态挂载或卸载。已挂载持久化无法读取时,跨语料库列表和血缘跟踪以 `SESSION_QUERY_PERSISTENCE_FAILED` 失败;已经成功读取、但无法通过 Session 校验的持久化记录则以 `SESSION_QUERY_CORRUPT_SESSION` 失败。针对已知实时会话的标题读取、事件跟踪或事件读取不会查询持久化,因此持久化后端的健康状态无法使当前内存状态变得不可读。持久化标题和事件操作在加载前先执行列表查询,并在元数据不匹配时拒绝,而不会组合不一致的观察。血缘跟踪的取消信号会传递给持久化列表查询;事件跟踪和事件读取的取消信号会传递给持久化列表查询和检查。每项操作都会等待已启动的后端调用结算,然后使用信号的精确原因拒绝,即使后端忽略了该信号。针对已知实时会话且预先中止的标题读取、事件跟踪或事件读取会在 fold 或快照之前拒绝,且不查询持久化。批量标题观察执行一次元数据列表查询,使用最多 `persistedInspectConcurrency` 个 worker 检查唯一持久化 id,并保留每个标题自己观察到的 header,供下游授权使用。取消不会启动已排队检查,且只在已启动 worker 结算后拒绝。`listSessions()` 仍保持轻量,不加载日志或索引标题。 + +## 过滤与提取 + +`SessionResultFilter` 覆盖 id、可空 cwd、创建时间范围、可空父级和来源可用性。`SessionEventResultFilter` 覆盖 seq/时间范围、事件类型、表层和语义文本。过滤器数组使用 AND;同一列表子句内的值使用 OR。空列表值不匹配任何内容,范围包含端点,而格式错误的范围或封闭联合值以 `SESSION_QUERY_INVALID_FILTER` 失败。 + +文本子句刻意与 FTS 提供方无关:调用方文本会被转义为不区分大小写的 Unicode 正则表达式,每段连续空白匹配一个或多个空白字符。它是字面语义文本扫描,而非全文查询。`extractSessionEventText()` 和 `buildSessionEventSearchDocuments()` 定义共享的第一方文档投影;推理(reasoning)块、结构边界、流分片、请求 header 和未知声明合并变体不产生文档。 + +## 全文方法 + +`SessionQueryEngine.searchSessions(request, exec?)` 按匹配最强的事件对逻辑语料库分组;`searchEvents(request, exec?)` 搜索一个逻辑会话。这两个是服务仅有的抽象方法。两者都返回分页结果,其延续信息是由服务持有的带品牌 `SessionSearchCursor`;接受可选取消,并在不使用提供方专用数值分数的情况下提供摘录。事件搜索分页结果还携带来自与命中相同索引世代的克隆目标 header,使授权消费方可将策略绑定到此次载荷观察。搜索请求只接受事件元数据过滤器,因为字面文本过滤使用上文所述扫描路径。 + +该包没有提供方协调器、回退实现或独立具体插件。具体服务后端继承已实现的读取、过滤和跟踪,同时负责全文观察、对账、排名、游标世代和查询执行;第一个实现是 [`@deepseek-ai/dsh-session-query-sqlite`](../session-query-sqlite/README.md)。 + +`SessionQueryError.code` 是一个封闭联合,覆盖请求验证、缺失目标、格式错误的表层、来源冲突、持久化/索引失败、取消,以及无效或陈旧游标;精确字面值在 [`src/config.ts`](src/config.ts) 中定义。 + +`listEvents()`、`readSurface()` 和 `traceEvent()` 执行同一个单遍 `dsh-session` 表层 fold。只有当事件 seq 从零开始且连续、表层标记符合事件类型的适用性要求、源事件数组非空且无重复、引用指向较早事件,且每个位置替换都命名并引用它移除的每个表层节点时,加载的日志才有效;任何违规都以 `SESSION_QUERY_INVALID_SURFACE` 失败。 + +## 配置 + +| 键 | 默认值 | 约定 | +|---|---:|---| +| `readWindowMax` | `50` | `before` 或 `after` 的最大原始事件数。 | +| `persistedInspectConcurrency` | `4` | 一次批量读取中的最大并发持久化日志检查数;必须是正的安全整数。 | + +## 模型体验 + +无。该可信查询服务只向调用方返回克隆会话记录,不注册面向模型的提示词、schema、工具或消息。 + +#### KV Cache 影响 + +无;该包既不组装也不发送提供方请求。 + +## 已知限制与暂缓事项 + +- **无调用方授权**:这是上下文范围内的可信基础设施;未来的模型工具或 UI 必须限制调用方可检查的会话。 +- **无注册表或面向模型工具**:尚未提供提取器和搜索提供方注册表、递归遍历所引用的源事件的能力,以及面向模型的工具。[跟踪决策](../../../.agents/notes/implemented/feature/2026-07-13-session-query-tracing.md) 负责关系语义;SQLite 归属和 tokenizer 决策位于[已实现搜索记录](../../../.agents/notes/implemented/feature/2026-07-10-sqlite-session-query-provider.md)。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/index.js new file mode 100644 index 0000000..20e9c88 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/index.js @@ -0,0 +1,969 @@ +import { Service } from "@deepseek-ai/cordis"; +import { Session, foldSurface, isSurfaceEvent, snapshotSessionEvent } from "@deepseek-ai/dsh-session"; +import { foldSessionTitle } from "@deepseek-ai/dsh-session-title"; +import { HarnessError } from "@deepseek-ai/dsh-llm"; +//#region lib/types/config.js +/** Public configuration and typed failures for the combined session-query service. */ +/** Default maximum `before`/`after` raw-event window. */ +const SESSION_QUERY_READ_WINDOW_MAX = 50; +/** Default maximum number of concurrent persisted-log inspections in one batch read. */ +const SESSION_QUERY_DEFAULT_PERSISTED_INSPECT_CONCURRENCY = 4; +/** Typed session-query failure whose `code` is one closed taxonomy member. */ +var SessionQueryError = class extends HarnessError { + constructor(message, code, options) { + super(message, code, options); + } +}; +//#endregion +//#region lib/types/sources.js +/** Shared immutable-header checks for logical session source observers. */ +/** +* Reject incompatible observations of one logical session source. +* @param a - first live, listed, or loaded header observation. +* @param b - second header observation expected to identify the same source. +*/ +function assertSessionHeadersCompatible(a, b) { + if (a.version !== b.version || a.id !== b.id || a.createdAt !== b.createdAt || a.cwd !== b.cwd || a.parentSession !== b.parentSession || a.seedLength !== b.seedLength || (a.delegationDepth ?? 0) !== (b.delegationDepth ?? 0)) throw new SessionQueryError(`session source headers conflict for session "${a.id}"`, "SESSION_QUERY_SOURCE_CONFLICT"); +} +//#endregion +//#region lib/types/corpus.js +/** Live/persisted logical-corpus resolution for session-query. */ +/** Resolves a live-preferred corpus against the persistence service mounted now. */ +var SessionCorpus = class { + _ctx; + _persistedInspectConcurrency; + _persistence; + _optionalPersistenceFiber; + constructor(_ctx, _persistedInspectConcurrency) { + this._ctx = _ctx; + this._persistedInspectConcurrency = _persistedInspectConcurrency; + this._optionalPersistenceFiber = _ctx.inject(["sessionPersistence"], (childCtx) => { + const service = childCtx.sessionPersistence; + this._persistence = service; + childCtx.effect(() => () => { + /* v8 ignore next -- a stale optional-service disposer cannot clear a replacement */ + if (this._persistence === service) this._persistence = void 0; + }, "sessionQuery.persistenceBinding"); + }); + _ctx.effect(() => { + return () => this._optionalPersistenceFiber.dispose(); + }, "sessionQuery.optionalPersistence"); + } + /** + * List the complete logical corpus with live precedence and cloned headers. + * @param signal - optional cancellation for persistence listing. + * @returns records in deterministic newest-first order. + */ + async listSessions(signal) { + signal?.throwIfAborted(); + const persistence = this._persistence; + const persisted = persistence === void 0 ? [] : await listPersisted(persistence, signal); + signal?.throwIfAborted(); + const records = /* @__PURE__ */ new Map(); + for (const header of persisted) records.set(header.id, { + header: structuredClone(header), + live: false, + persisted: true + }); + for (const session of this._ctx.sessions.list()) { + const durable = records.get(session.id); + if (durable !== void 0) assertSessionHeadersCompatible(session.header, durable.header); + records.set(session.id, { + header: structuredClone(session.header), + live: true, + persisted: durable !== void 0 + }); + } + return [...records.values()].sort(compareSessions); + } + /** + * Load one logical source, preferring a detached live snapshot. + * + * A known live target never consults persistence, so an optional backend's + * failure cannot make current in-memory history unreadable. + * @param sessionId - session to resolve. + * @param signal - optional cancellation for persisted source resolution. + * @returns detached live-preferred header and events. + */ + async load(sessionId, signal) { + signal?.throwIfAborted(); + const live = this._ctx.sessions.get(sessionId); + if (live !== void 0) { + const snapshot = snapshotLive(live); + signal?.throwIfAborted(); + return snapshot; + } + const persistence = this._persistence; + if (persistence === void 0) throw notFound(sessionId); + const listed = (await listPersisted(persistence, signal)).find((header) => header.id === sessionId); + signal?.throwIfAborted(); + if (listed === void 0) throw notFound(sessionId); + const loaded = await inspectPersisted(persistence, sessionId, signal); + signal?.throwIfAborted(); + const attached = this._ctx.sessions.get(sessionId); + if (attached !== void 0) { + const snapshot = snapshotLive(attached); + signal?.throwIfAborted(); + return snapshot; + } + assertSessionHeadersCompatible(loaded.meta, listed); + const snapshot = { + header: structuredClone(loaded.meta), + events: loaded.events.map((event) => structuredClone(event)) + }; + signal?.throwIfAborted(); + return snapshot; + } + /** + * Project unique logical sources immediately from one persistence listing. + * + * The synchronous projector runs before a persisted worker claims its next id. + * Full logs are borrowed only for that call and never retained by the batch. + * @param sessionIds - sessions to resolve in first-occurrence order. + * @param project - synchronous fold that owns/clones every retained value. + * @param signal - cancellation shared by listing and every persisted inspection. + * @returns one fulfilled or rejected projected result per unique requested id. + */ + async projectMany(sessionIds, project, signal) { + const ids = [...new Set(sessionIds)]; + signal?.throwIfAborted(); + const resolved = /* @__PURE__ */ new Map(); + const unresolved = []; + for (const id of ids) { + const session = this._ctx.sessions.get(id); + if (session === void 0) unresolved.push(id); + else resolved.set(id, projectSource(id, sourceLive(session), project, signal)); + } + if (unresolved.length === 0) return orderedResults(ids, resolved); + const persistence = this._persistence; + if (persistence === void 0) { + for (const sessionId of unresolved) resolved.set(sessionId, { + sessionId, + status: "rejected", + reason: notFound(sessionId) + }); + return orderedResults(ids, resolved); + } + let persisted; + try { + persisted = await listPersisted(persistence, signal); + signal?.throwIfAborted(); + } catch (error) { + if (signal?.aborted) signal.throwIfAborted(); + for (const sessionId of unresolved) resolved.set(sessionId, { + sessionId, + status: "rejected", + reason: error + }); + return orderedResults(ids, resolved); + } + const persistedById = new Map(persisted.map((header) => [header.id, header])); + const resolvePersisted = async (sessionId) => { + const listed = persistedById.get(sessionId); + if (listed === void 0) { + const attached = this._ctx.sessions.get(sessionId); + resolved.set(sessionId, attached === void 0 ? { + sessionId, + status: "rejected", + reason: notFound(sessionId) + } : projectSource(sessionId, sourceLive(attached), project, signal)); + return; + } + try { + signal?.throwIfAborted(); + const loaded = await inspectPersisted(persistence, sessionId, signal); + signal?.throwIfAborted(); + const attached = this._ctx.sessions.get(sessionId); + if (attached !== void 0) { + resolved.set(sessionId, projectSource(sessionId, sourceLive(attached), project, signal)); + return; + } + assertSessionHeadersCompatible(loaded.meta, listed); + resolved.set(sessionId, projectSource(sessionId, { + header: loaded.meta, + events: loaded.events + }, project, signal)); + } catch (error) { + if (signal?.aborted) signal.throwIfAborted(); + resolved.set(sessionId, { + sessionId, + status: "rejected", + reason: error + }); + } + }; + let cursor = 0; + const worker = async () => { + for (;;) { + signal?.throwIfAborted(); + const index = cursor; + if (index >= unresolved.length) return; + cursor += 1; + await resolvePersisted(unresolved[index]); + } + }; + const workerCount = Math.min(this._persistedInspectConcurrency, unresolved.length); + const settlements = await Promise.allSettled(Array.from({ length: workerCount }, () => worker())); + if (signal?.aborted) signal.throwIfAborted(); + /* v8 ignore start -- per-id failures settle inside resolvePersisted; workers reject only on abort above */ + for (const settlement of settlements) if (settlement.status === "rejected") throw settlement.reason; + /* v8 ignore stop */ + signal?.throwIfAborted(); + return orderedResults(ids, resolved); + } +}; +function projectSource(sessionId, source, project, signal) { + try { + signal?.throwIfAborted(); + const value = project(source); + signal?.throwIfAborted(); + return { + sessionId, + status: "fulfilled", + value + }; + } catch (reason) { + /* v8 ignore next -- the synchronous projector has no external cancellation yield */ + if (signal?.aborted) signal.throwIfAborted(); + return { + sessionId, + status: "rejected", + reason + }; + } +} +function sourceLive(session) { + return { + header: session.header, + events: session.events + }; +} +function orderedResults(ids, resolved) { + return ids.map((sessionId) => resolved.get(sessionId)); +} +async function listPersisted(persistence, signal) { + try { + return await persistence.list(signal); + } catch (error) { + if (signal?.aborted) signal.throwIfAborted(); + throw new SessionQueryError(`session persistence listing failed: ${errorMessage(error)}`, "SESSION_QUERY_PERSISTENCE_FAILED", { cause: error }); + } +} +async function inspectPersisted(persistence, sessionId, signal) { + try { + return await persistence.inspect(sessionId, signal); + } catch (error) { + if (signal?.aborted) signal.throwIfAborted(); + if (error instanceof Error && error.name === "SessionPersistenceCorruptionError") throw new SessionQueryError(`stored session "${sessionId}" is corrupt: ${errorMessage(error)}`, "SESSION_QUERY_CORRUPT_SESSION", { cause: error }); + throw new SessionQueryError(`failed to inspect session "${sessionId}": ${errorMessage(error)}`, "SESSION_QUERY_PERSISTENCE_FAILED", { cause: error }); + } +} +function snapshotLive(session) { + return { + header: structuredClone(session.header), + events: session.events.map((event) => structuredClone(event)) + }; +} +function compareSessions(a, b) { + return b.header.createdAt - a.header.createdAt || a.header.id.localeCompare(b.header.id); +} +function notFound(sessionId) { + return new SessionQueryError(`session "${sessionId}" not found`, "SESSION_QUERY_SESSION_NOT_FOUND"); +} +function errorMessage(error) { + return error instanceof Error ? error.message : "unknown error"; +} +//#endregion +//#region lib/types/extraction.js +/** First-party semantic text extraction for session-query consumers. */ +/** +* Extract searchable semantic text from one first-party session event. +* +* Structural boundaries, raw stream chunks, request envelopes, and unknown +* declaration-merged events contribute no text. +* @param event - event to inspect. +* @returns newline-joined semantic text, or an empty string when non-searchable. +*/ +function extractSessionEventText(event) { + switch (event.type) { + case "user/message": return contentText(event.data.content); + case "assistant/message": return contentText(event.data.message.content); + case "tool/call": return joinText([event.data.name, event.data.arguments]); + case "tool/result": return joinText([ + contentText(event.data.message.content), + event.data.error?.name ?? "", + event.data.error?.code ?? "" + ]); + case "todo/write": return joinText(event.data.todos.flatMap((todo) => [todo.status, todo.content])); + case "turn/end": return turnEndText(event.data.reason); + case "turn/start": + case "step/start": + case "step/end": + case "assistant/chunk": + case "request/header": return ""; + default: return ""; + } +} +function turnEndText(reason) { + switch (reason.kind) { + case "error": return joinText(["error", reason.error.message]); + case "aborted": return "aborted"; + case "max-tokens": + case "interrupted": return reason.kind; + case "completed": return ""; + default: return ""; + } +} +function contentText(content) { + return joinText(content.flatMap(blockText)); +} +function blockText(block) { + switch (block.type) { + case "text": return [block.text]; + case "reasoning": return []; + case "tool-call": return [block.name, block.arguments]; + case "tool-result": return block.content.flatMap(blockText); + default: return []; + } +} +function joinText(parts) { + return parts.map((part) => part.trim()).filter(Boolean).join("\n"); +} +//#endregion +//#region lib/types/documents.js +/** Shared event metadata and semantic-document projection. */ +/** +* Project a raw log into lightweight surface-aware event records. +* @param sessionId - session that owns the log. +* @param events - complete contiguous raw event log. +* @returns one record per event in ascending seq order. +*/ +function buildSessionEventRecords(sessionId, events) { + const surfaceBySeq = classifySurface(events); + return events.map((event) => ({ + sessionId, + seq: event.seq, + type: event.type, + time: event.time, + surface: surfaceBySeq.get(event.seq) ?? "log-only" + })); +} +/** +* Build first-party semantic documents for one complete raw event log. +* @param sessionId - session that owns the log. +* @param events - complete contiguous raw event log. +* @returns searchable documents in ascending seq order; structural events are omitted. +*/ +function buildSessionEventSearchDocuments(sessionId, events) { + const surfaceBySeq = classifySurface(events); + const documents = []; + for (const event of events) { + const text = extractSessionEventText(event); + if (text.length === 0) continue; + documents.push({ + sessionId, + seq: event.seq, + type: event.type, + time: event.time, + surface: surfaceBySeq.get(event.seq) ?? "log-only", + text + }); + } + return documents; +} +function classifySurface(events) { + let folded; + try { + folded = foldSurface(events); + } catch (error) { + throw new SessionQueryError( + /* v8 ignore next -- foldSurface throws Error instances */ + `invalid session surface: ${error instanceof Error ? error.message : "unknown error"}`, + "SESSION_QUERY_INVALID_SURFACE", + { cause: error } + ); + } + const result = /* @__PURE__ */ new Map(); + for (const seq of folded.nodes) result.set(seq, "current"); + for (const replacement of folded.replacements) for (const seq of replacement.shadowedSeqs) result.set(seq, "shadowed"); + return result; +} +//#endregion +//#region lib/types/filters.js +/** Pure provider-independent predicates for logical sessions and event text. */ +/** +* Apply ANDed logical-session filters while preserving input order. +* @param records - detached logical-session records to inspect. +* @param filters - clauses whose list values are ORed within each clause. +* @returns records accepted by every clause. +*/ +function filterSessionResults(records, filters = []) { + const predicates = filters.map(sessionPredicate); + return records.filter((record) => predicates.every((predicate) => predicate(record))); +} +/** +* Apply ANDed event filters to extracted semantic documents. +* @param documents - semantic documents produced by {@link buildSessionEventSearchDocuments}. +* @param filters - metadata and literal-text predicates. +* @returns documents accepted by every clause, in input order. +*/ +function filterSessionEventDocuments(documents, filters = []) { + const predicates = filters.map(eventPredicate); + return documents.filter((document) => predicates.every((predicate) => predicate(document))); +} +/** +* Copy and validate logical-session filters before an asynchronous boundary. +* @param filters - caller-owned clauses to materialize. +* @returns detached validated clauses. +*/ +function materializeSessionResultFilters(filters) { + assertArray(filters); + return filters.map((filter) => { + switch (filter.kind) { + case "id": return { + kind: filter.kind, + values: copyStrings(filter.kind, filter.values) + }; + case "cwd": return { + kind: filter.kind, + values: copyNullableStrings(filter.kind, filter.values) + }; + case "created-at": return copyRange(filter.kind, filter); + case "parent": return { + kind: filter.kind, + values: copyNullableStrings(filter.kind, filter.values) + }; + case "availability": { + const values = copyStrings(filter.kind, filter.values); + assertAllowedValues(filter.kind, values, ["live", "persisted"]); + return { + kind: filter.kind, + values + }; + } + default: return unknownFilter(filter); + } + }); +} +/** +* Copy and validate event filters before an asynchronous boundary. +* @param filters - caller-owned clauses to materialize. +* @returns detached validated clauses. +*/ +function materializeSessionEventResultFilters(filters) { + assertArray(filters); + return filters.map((filter) => { + switch (filter.kind) { + case "seq": + case "time": return copyRange(filter.kind, filter); + case "type": return { + kind: filter.kind, + values: copyStrings(filter.kind, filter.values) + }; + case "surface": { + const values = copyStrings(filter.kind, filter.values); + assertAllowedValues(filter.kind, values, [ + "current", + "shadowed", + "log-only" + ]); + return { + kind: filter.kind, + values + }; + } + case "text": + if (typeof filter.text !== "string") throw invalidFilter("text filter text must be a string"); + return { + kind: filter.kind, + text: filter.text + }; + default: return unknownFilter(filter); + } + }); +} +/** +* Compile a literal case-insensitive, whitespace-flexible semantic-text match. +* @param text - caller-provided literal text. +* @returns Unicode-aware regular expression safe from regex injection. +*/ +function compileSessionTextFilter(text) { + const trimmed = text.trim(); + if (trimmed.length === 0) throw new SessionQueryError("session text filter must contain non-whitespace text", "SESSION_QUERY_INVALID_FILTER"); + const pattern = trimmed.split(/\s+/u).map((part) => part.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")).join("\\s+"); + return new RegExp(pattern, "iu"); +} +function sessionPredicate(filter) { + switch (filter.kind) { + case "id": return (record) => filter.values.includes(record.header.id); + case "cwd": return (record) => filter.values.includes(record.header.cwd ?? null); + case "created-at": { + const range = validateRange(filter.kind, filter); + return (record) => matchesRange(record.header.createdAt, range); + } + case "parent": return (record) => filter.values.includes(record.header.parentSession ?? null); + case "availability": + assertAllowedValues(filter.kind, filter.values, ["live", "persisted"]); + return (record) => filter.values.some((value) => value === "live" ? record.live : record.persisted); + default: return unknownFilter(filter); + } +} +function eventPredicate(filter) { + switch (filter.kind) { + case "seq": { + const range = validateRange(filter.kind, filter); + return (document) => matchesRange(document.seq, range); + } + case "time": { + const range = validateRange(filter.kind, filter); + return (document) => matchesRange(document.time, range); + } + case "type": return (document) => filter.values.includes(document.type); + case "surface": + assertAllowedValues(filter.kind, filter.values, [ + "current", + "shadowed", + "log-only" + ]); + return (document) => filter.values.includes(document.surface); + case "text": { + const pattern = compileSessionTextFilter(filter.text); + return (document) => pattern.test(document.text); + } + default: return unknownFilter(filter); + } +} +function copyStrings(name, values) { + if (!isRuntimeArray(values) || values.some((value) => typeof value !== "string")) throw invalidFilter(`${name} filter values must be an array of strings`); + return [...values]; +} +function assertArray(value) { + if (!Array.isArray(value)) throw invalidFilter("filters must be an array"); +} +function copyNullableStrings(name, values) { + if (!isRuntimeArray(values) || values.some((value) => value !== null && typeof value !== "string")) throw invalidFilter(`${name} filter values must be an array of strings or null`); + return [...values]; +} +function copyRange(kind, range) { + const copy = { + kind, + ...range.from === void 0 ? {} : { from: range.from }, + ...range.to === void 0 ? {} : { to: range.to } + }; + validateRange(kind, copy); + return copy; +} +function unknownFilter(filter) { + const kind = filter.kind; + throw invalidFilter(`unknown filter kind ${typeof kind === "string" ? `"${kind}"` : "(missing)"}`); +} +function assertAllowedValues(name, values, allowed) { + for (const value of values) if (!allowed.includes(value)) throw new SessionQueryError(`session ${name} filter contains unknown value "${value}"`, "SESSION_QUERY_INVALID_FILTER"); +} +function validateRange(name, range) { + if (range.from !== void 0 && !Number.isFinite(range.from)) throw invalidRange(name, "from must be finite"); + if (range.to !== void 0 && !Number.isFinite(range.to)) throw invalidRange(name, "to must be finite"); + if (range.from !== void 0 && range.to !== void 0 && range.from > range.to) throw invalidRange(name, "from must be less than or equal to to"); + return range; +} +function matchesRange(value, range) { + return (range.from === void 0 || value >= range.from) && (range.to === void 0 || value <= range.to); +} +function invalidRange(name, detail) { + return invalidFilter(`${name} filter ${detail}`); +} +function invalidFilter(detail) { + return new SessionQueryError(`session ${detail}`, "SESSION_QUERY_INVALID_FILTER"); +} +function isRuntimeArray(value) { + return Array.isArray(value); +} +//#endregion +//#region lib/types/tracing.js +/** One-shot session-lineage and event-relationship tracing helpers. */ +/** +* Classify a raw event log with one canonical surface fold. +* @param sessionId - owner of the event log. +* @param events - detached raw event log. +* @returns lightweight records in ascending log order. +*/ +function eventRecords(sessionId, events) { + return analyzeEventLog(sessionId, events).records; +} +/** +* Fold and return the current model surface after validating the whole log. +* @param sessionId - owner used in query diagnostics. +* @param events - detached raw event log from one corpus observation. +* @returns detached current surface events in folded order. +*/ +function currentSurfaceEvents(sessionId, events) { + return analyzeEventLog(sessionId, events).currentSeqs.map((seq) => { + const event = events[seq]; + /* v8 ignore next 6 -- analyzeEventLog validated contiguous seqs and foldSurface returned only surface-event seqs. */ + if (event === void 0 || event.seq !== seq || !isSurfaceEvent(event)) throw new SessionQueryError(`invalid session surface: current node ${seq} is not a surface event`, "SESSION_QUERY_INVALID_SURFACE"); + return snapshotSessionEvent(event); + }); +} +/** +* Trace one target after one canonical surface fold and whole-log validation. +* @param sessionId - owner of the event log. +* @param events - detached raw event log. +* @param seq - target event seq. +* @returns direct surface replacements and relationships to cited source events. +*/ +function traceEvent(sessionId, events, seq) { + const target = events[seq]; + if (target === void 0 || target.seq !== seq) throw new SessionQueryError(`session "${sessionId}" has no event at seq ${seq}`, "SESSION_QUERY_EVENT_NOT_FOUND"); + const analysis = analyzeEventLog(sessionId, events); + const replacementChain = []; + let replacement = analysis.replacedBy.get(seq); + while (replacement !== void 0) { + replacementChain.push(replacement); + replacement = analysis.replacedBy.get(replacement); + } + const derivedEventSeqs = []; + for (const event of events) { + if (event.seq <= seq) continue; + if (eventSources(event).includes(seq)) derivedEventSeqs.push(event.seq); + } + const targetRecord = analysis.records[seq]; + const replacedBy = analysis.replacedBy.get(seq); + return { + target: targetRecord, + ...replacedBy === void 0 ? {} : { replacedBy }, + replacementChain, + replacedEventSeqs: analysis.replacedEventSeqs.get(seq) ?? [], + sourceEventSeqs: [...eventSources(target)], + derivedEventSeqs + }; +} +/** +* Trace one target's known ancestry and recursively known descendants. +* @param records - complete logical corpus from one observation. +* @param sessionId - target session id. +* @returns complete or explicitly partial lineage. +*/ +function traceSession(records, sessionId) { + const byId = new Map(records.map((record) => [record.header.id, record])); + const target = byId.get(sessionId); + if (target === void 0) throw new SessionQueryError(`session "${sessionId}" not found`, "SESSION_QUERY_SESSION_NOT_FOUND"); + const ancestors = []; + const ancestrySeen = new Set([sessionId]); + let unresolvedParentId; + let parentId = target.header.parentSession; + while (parentId !== void 0) { + if (ancestrySeen.has(parentId)) throw new SessionQueryError(`session lineage contains a cycle at "${parentId}"`, "SESSION_QUERY_INVALID_LINEAGE"); + ancestrySeen.add(parentId); + const parent = byId.get(parentId); + if (parent === void 0) { + unresolvedParentId = parentId; + break; + } + ancestors.push(parent); + parentId = parent.header.parentSession; + } + const childrenByParent = /* @__PURE__ */ new Map(); + for (const record of records) { + const parent = record.header.parentSession; + if (parent === void 0) continue; + const children = childrenByParent.get(parent) ?? []; + children.push(record); + childrenByParent.set(parent, children); + } + for (const children of childrenByParent.values()) children.sort((a, b) => a.header.createdAt - b.header.createdAt || a.header.id.localeCompare(b.header.id)); + const descendants = buildDescendants(childrenByParent, sessionId); + const common = { + target: cloneRecord(target), + ancestors: ancestors.map(cloneRecord), + descendants + }; + if (unresolvedParentId !== void 0) return { + ...common, + complete: false, + unresolvedParentId + }; + return { + ...common, + complete: true, + root: cloneRecord(ancestors.at(-1) ?? target) + }; +} +function analyzeEventLog(sessionId, events) { + let folded; + try { + folded = foldSurface(events); + } catch (error) { + throw new SessionQueryError( + /* v8 ignore next -- foldSurface throws Error instances */ + `invalid session surface: ${error instanceof Error ? error.message : "unknown error"}`, + "SESSION_QUERY_INVALID_SURFACE", + { cause: error } + ); + } + const current = new Set(folded.nodes); + const replacedBy = /* @__PURE__ */ new Map(); + const replacedEventSeqs = /* @__PURE__ */ new Map(); + for (const replacement of folded.replacements) { + const removed = replacement.shadowedSeqs; + replacedEventSeqs.set(replacement.seq, removed); + for (const removedSeq of removed) replacedBy.set(removedSeq, replacement.seq); + } + return { + records: events.map((event) => ({ + sessionId, + seq: event.seq, + type: event.type, + time: event.time, + surface: current.has(event.seq) ? "current" : replacedBy.has(event.seq) ? "shadowed" : "log-only" + })), + replacedBy, + replacedEventSeqs, + currentSeqs: [...folded.nodes] + }; +} +function eventSources(event) { + return event.sourceEventSeqs ?? []; +} +function buildDescendants(childrenByParent, sessionId) { + const descendants = []; + const stack = [{ + sessionId, + descendants + }]; + while (stack.length > 0) { + const frame = stack.pop(); + const nodes = []; + for (const child of childrenByParent.get(frame.sessionId) ?? []) { + const node = { + session: cloneRecord(child), + descendants: [] + }; + nodes.push(node); + frame.descendants.push(node); + } + for (let index = nodes.length - 1; index >= 0; index -= 1) { + const node = nodes[index]; + stack.push({ + sessionId: node.session.header.id, + descendants: node.descendants + }); + } + } + return descendants; +} +function cloneRecord(record) { + return { + ...record, + header: structuredClone(record.header) + }; +} +//#endregion +//#region lib/types/cursor.js +/** Opaque cursor identity for session-search pagination. */ +/** +* Brand an encoded provider cursor for the public search contract. +* @param value - opaque encoded cursor value. +* @returns the same runtime string with session-search cursor identity. +*/ +function SessionSearchCursor(value) { + return value; +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for combined session-history reads, traces, filters, and full-text search. +* +* @module @deepseek-ai/dsh-session-query +*/ +/** +* Unified live-preferred session query service. +* +* Exact reads, filters, and traces are backend-independent concrete behavior. +* A backend implements full-text observation, reconciliation, ranking, cursor +* generations, and query execution on the same `ctx.sessionQuery` service. +*/ +var SessionQueryEngine = class extends Service { + static inject = ["sessions"]; + _readWindowMax; + _corpus; + constructor(ctx, config = {}) { + super(ctx, "sessionQuery"); + this._readWindowMax = config.readWindowMax ?? 50; + if (!Number.isInteger(this._readWindowMax) || this._readWindowMax < 0) throw new SessionQueryError("session-query: readWindowMax must be a non-negative integer", "SESSION_QUERY_INVALID_CONFIG"); + const persistedInspectConcurrency = config.persistedInspectConcurrency ?? 4; + if (!Number.isSafeInteger(persistedInspectConcurrency) || persistedInspectConcurrency < 1) throw new SessionQueryError("session-query: persistedInspectConcurrency must be a positive safe integer", "SESSION_QUERY_INVALID_CONFIG"); + this._corpus = new SessionCorpus(ctx, persistedInspectConcurrency); + } + /** + * List the complete logical corpus using live-preferred records. + * @param signal - optional cancellation for persistence listing. + * @returns deterministic newest-first cloned session records. + */ + listSessions(signal) { + return this._corpus.listSessions(signal); + } + /** + * Read and replay-validate one complete logical session log without making it live. + * @param sessionId - live or persisted session id to read. + * @returns cloned header and complete raw event log from one observation. + * @throws when persistence, header compatibility, or replay validation fails. + */ + async readSession(sessionId) { + const loaded = await this._corpus.load(sessionId); + Session.create(sessionId, loaded.events, loaded.header); + return { + session: structuredClone(loaded.header), + events: loaded.events.map(snapshotSessionEvent) + }; + } + /** + * Filter the complete logical corpus with provider-independent predicates. + * @param filters - ANDed session metadata and availability clauses. + * @param signal - optional cancellation for persistence listing. + * @returns matching cloned records in deterministic newest-first order. + */ + async filterSessions(filters, signal) { + const ownedFilters = materializeSessionResultFilters(filters); + return this._filterSessions(ownedFilters, signal); + } + /** + * Fold the latest log-backed title from one live-preferred logical session. + * @param sessionId - live or persisted session id to read. + * @param signal - optional cancellation for source resolution and title folding. + * @returns latest title snapshot, or `undefined` when the log has no title event. + */ + async readTitle(sessionId, signal) { + return (await this.readTitleSnapshot(sessionId, signal)).title; + } + /** + * Fold the latest title and return its source header from one corpus observation. + * @param sessionId - live or persisted session id to read. + * @param signal - optional cancellation for source resolution and title folding. + * @returns cloned source header and optional latest title snapshot. + */ + async readTitleSnapshot(sessionId, signal) { + const result = (await this.readTitleSnapshots([sessionId], signal))[0]; + if (result.status === "rejected") throw result.reason; + return result.value; + } + /** + * Fold titles for unique sessions from one cancellable corpus observation. + * + * Results preserve first-occurrence input order. Operational failures stay + * isolated per session, while cancellation rejects the complete operation. + * @param sessionIds - live or persisted session ids to observe. + * @param signal - optional cancellation shared by all source reads. + * @returns one fulfilled or rejected result per unique requested id. + */ + async readTitleSnapshots(sessionIds, signal) { + return this._corpus.projectMany(sessionIds, (source) => { + const title = foldSessionTitle(source.events); + return { + session: structuredClone(source.header), + ...title === void 0 ? {} : { title } + }; + }, signal); + } + /** + * List lightweight raw-log event records for one logical session. + * @param sessionId - live-preferred session id to read. + * @returns event records in ascending seq order. + */ + async listEvents(sessionId) { + return eventRecords(sessionId, (await this._corpus.load(sessionId)).events); + } + /** + * Scan first-party semantic event documents with provider-independent filters. + * @param sessionId - live-preferred session id to scan. + * @param filters - ANDed metadata and literal-text predicates. + * @returns matching semantic documents in ascending seq order. + */ + async filterEvents(sessionId, filters) { + const ownedFilters = materializeSessionEventResultFilters(filters); + return this._filterEvents(sessionId, ownedFilters); + } + async _filterSessions(filters, signal) { + return filterSessionResults(await this._corpus.listSessions(signal), filters); + } + async _filterEvents(sessionId, filters) { + return filterSessionEventDocuments(buildSessionEventSearchDocuments(sessionId, (await this._corpus.load(sessionId)).events), filters); + } + /** + * Read one session's complete current model surface from one corpus observation. + * @param sessionId - live-preferred session id to read. + * @returns cloned header, current surface, and the last sequence number included in the raw-log capture. + * @throws when source resolution fails or the session surface is invalid. + */ + async readSurface(sessionId) { + const loaded = await this._corpus.load(sessionId); + return { + session: structuredClone(loaded.header), + capturedThroughSeq: loaded.events.at(-1)?.seq ?? null, + events: currentSurfaceEvents(sessionId, loaded.events) + }; + } + /** + * Trace known ancestry and descendants from one corpus observation. + * @param sessionId - logical session id to trace. + * @param signal - optional cancellation for persistence listing. + * @returns a complete lineage or the first parent that could not be resolved. + * @throws when corpus resolution fails, the target is absent, or its known ancestry cycles. + */ + async traceSession(sessionId, signal) { + const records = await this._corpus.listSessions(signal); + signal?.throwIfAborted(); + return traceSession(records, sessionId); + } + /** + * Trace one event's direct positional replacements and cited source events. + * @param request - target session id and event seq. + * @param signal - optional cancellation for persisted source resolution. + * @returns source header, direct links, and the target's positional replacement chain. + * @throws when source resolution fails, the target is absent, or surface/source-event validation fails. + */ + async traceEvent(request, signal) { + const loaded = await this._corpus.load(request.sessionId, signal); + signal?.throwIfAborted(); + return { + session: loaded.header, + ...traceEvent(request.sessionId, loaded.events, request.seq) + }; + } + /** + * Read one full event plus a bounded raw-log context window. + * @param request - target session/seq and context sizes. + * @param signal - optional cancellation for persisted source resolution. + * @returns cloned target and neighboring events. + */ + async readEvent(request, signal) { + const before = this._readWindow("before", request.before); + const after = this._readWindow("after", request.after); + const sessionId = request.sessionId; + const seq = request.seq; + return this._readEvent(sessionId, seq, before, after, signal); + } + async _readEvent(sessionId, seq, before, after, signal) { + const loaded = await this._corpus.load(sessionId, signal); + signal?.throwIfAborted(); + const target = loaded.events[seq]; + if (target === void 0 || target.seq !== seq) throw new SessionQueryError(`session "${sessionId}" has no event at seq ${seq}`, "SESSION_QUERY_EVENT_NOT_FOUND"); + const startSeq = Math.max(0, seq - before); + const endSeq = Math.min(loaded.events.length - 1, seq + after); + const targetSnapshot = snapshotSessionEvent(target); + const events = loaded.events.slice(startSeq, endSeq + 1).map((event) => event === target ? targetSnapshot : snapshotSessionEvent(event)); + return { + session: structuredClone(loaded.header), + target: targetSnapshot, + events, + startSeq, + endSeq + }; + } + _readWindow(name, value) { + if (value === void 0) return 0; + if (!Number.isInteger(value) || value < 0 || value > this._readWindowMax) throw new SessionQueryError(`${name} must be an integer between 0 and ${this._readWindowMax}`, "SESSION_QUERY_INVALID_WINDOW"); + return value; + } +}; +//#endregion +export { SESSION_QUERY_DEFAULT_PERSISTED_INSPECT_CONCURRENCY, SESSION_QUERY_READ_WINDOW_MAX, SessionQueryEngine, SessionQueryEngine as default, SessionQueryError, SessionSearchCursor, assertSessionHeadersCompatible, buildSessionEventRecords, buildSessionEventSearchDocuments, compileSessionTextFilter, extractSessionEventText, filterSessionEventDocuments, filterSessionResults, materializeSessionEventResultFilters, materializeSessionResultFilters }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/invariant.js new file mode 100644 index 0000000..fbd0558 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-session-query`. +* @module @deepseek-ai/dsh-session-query/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session-query"; +/** Cordis companion plugin name. */ +const name = "session-query-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: query results are immutable per-call projections whose lineage and event +* relations are validated while they are built; the service retains no observable result state. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/config.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/config.d.ts new file mode 100644 index 0000000..2869d58 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/config.d.ts @@ -0,0 +1,21 @@ +/** Public configuration and typed failures for the combined session-query service. */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +/** Default maximum `before`/`after` raw-event window. */ +export declare const SESSION_QUERY_READ_WINDOW_MAX = 50; +/** Default maximum number of concurrent persisted-log inspections in one batch read. */ +export declare const SESSION_QUERY_DEFAULT_PERSISTED_INSPECT_CONCURRENCY = 4; +/** Backend-independent configuration inherited by every session-query implementation. */ +export interface Config { + /** Maximum accepted raw read context on either side. Defaults to 50. */ + readWindowMax?: number; + /** Maximum concurrent persisted-log inspections in one batch read. Defaults to 4. */ + persistedInspectConcurrency?: number; +} +/** Stable machine-routable failure taxonomy for session reads, traces, and search. */ +export type SessionQueryErrorCode = 'SESSION_QUERY_ABORTED' | 'SESSION_QUERY_CORRUPT_SESSION' | 'SESSION_QUERY_EVENT_NOT_FOUND' | 'SESSION_QUERY_INDEX_FAILED' | 'SESSION_QUERY_INVALID_CONFIG' | 'SESSION_QUERY_INVALID_CURSOR' | 'SESSION_QUERY_INVALID_FILTER' | 'SESSION_QUERY_INVALID_LIMIT' | 'SESSION_QUERY_INVALID_QUERY' | 'SESSION_QUERY_INVALID_LINEAGE' | 'SESSION_QUERY_INVALID_SURFACE' | 'SESSION_QUERY_INVALID_WINDOW' | 'SESSION_QUERY_PERSISTENCE_FAILED' | 'SESSION_QUERY_SEARCH_DISABLED' | 'SESSION_QUERY_SESSION_NOT_FOUND' | 'SESSION_QUERY_STALE_CURSOR' | 'SESSION_QUERY_SOURCE_CONFLICT'; +/** Typed session-query failure whose `code` is one closed taxonomy member. */ +export declare class SessionQueryError extends HarnessError { + readonly code: SessionQueryErrorCode; + constructor(message: string, code: SessionQueryErrorCode, options?: ErrorOptions); +} +//# sourceMappingURL=config.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/corpus.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/corpus.d.ts new file mode 100644 index 0000000..f10b6ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/corpus.d.ts @@ -0,0 +1,64 @@ +/** Live/persisted logical-corpus resolution for session-query. */ +import type { Context } from '@deepseek-ai/cordis'; +import type { SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session'; +import type { SessionRecord } from './types.ts'; +/** Detached source selected for one exact read. */ +export interface LogicalSession { + /** Cloned source header. */ + header: SessionHeader; + /** Cloned raw event log. */ + events: SessionEvent[]; +} +/** Borrowed source visible only during one synchronous batch projection. */ +export interface LogicalSessionSource { + /** Header selected with `events`; callers must clone retained output. */ + readonly header: SessionHeader; + /** Raw events selected with `header`; valid only for the projection call. */ + readonly events: readonly SessionEvent[]; +} +/** One source-projection result in a batch logical-corpus observation. */ +export type LogicalProjectionResult = { + sessionId: SessionId; + status: 'fulfilled'; + value: Value; +} | { + sessionId: SessionId; + status: 'rejected'; + reason: unknown; +}; +/** Resolves a live-preferred corpus against the persistence service mounted now. */ +export declare class SessionCorpus { + private readonly _ctx; + private readonly _persistedInspectConcurrency; + private _persistence; + private readonly _optionalPersistenceFiber; + constructor(_ctx: Context, _persistedInspectConcurrency: number); + /** + * List the complete logical corpus with live precedence and cloned headers. + * @param signal - optional cancellation for persistence listing. + * @returns records in deterministic newest-first order. + */ + listSessions(signal?: AbortSignal): Promise; + /** + * Load one logical source, preferring a detached live snapshot. + * + * A known live target never consults persistence, so an optional backend's + * failure cannot make current in-memory history unreadable. + * @param sessionId - session to resolve. + * @param signal - optional cancellation for persisted source resolution. + * @returns detached live-preferred header and events. + */ + load(sessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Project unique logical sources immediately from one persistence listing. + * + * The synchronous projector runs before a persisted worker claims its next id. + * Full logs are borrowed only for that call and never retained by the batch. + * @param sessionIds - sessions to resolve in first-occurrence order. + * @param project - synchronous fold that owns/clones every retained value. + * @param signal - cancellation shared by listing and every persisted inspection. + * @returns one fulfilled or rejected projected result per unique requested id. + */ + projectMany(sessionIds: readonly SessionId[], project: (source: LogicalSessionSource) => Value, signal?: AbortSignal): Promise[]>; +} +//# sourceMappingURL=corpus.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/cursor.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/cursor.d.ts new file mode 100644 index 0000000..969ed10 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/cursor.d.ts @@ -0,0 +1,11 @@ +/** Opaque cursor identity for session-search pagination. */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Provider-owned opaque continuation token returned by session search. */ +export type SessionSearchCursor = Branded<'SessionSearchCursor'>; +/** + * Brand an encoded provider cursor for the public search contract. + * @param value - opaque encoded cursor value. + * @returns the same runtime string with session-search cursor identity. + */ +export declare function SessionSearchCursor(value: string): SessionSearchCursor; +//# sourceMappingURL=cursor.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/documents.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/documents.d.ts new file mode 100644 index 0000000..1208f8d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/documents.d.ts @@ -0,0 +1,18 @@ +/** Shared event metadata and semantic-document projection. */ +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'; +import type { SessionEventRecord, SessionEventSearchDocument } from './types.ts'; +/** + * Project a raw log into lightweight surface-aware event records. + * @param sessionId - session that owns the log. + * @param events - complete contiguous raw event log. + * @returns one record per event in ascending seq order. + */ +export declare function buildSessionEventRecords(sessionId: SessionId, events: readonly SessionEvent[]): SessionEventRecord[]; +/** + * Build first-party semantic documents for one complete raw event log. + * @param sessionId - session that owns the log. + * @param events - complete contiguous raw event log. + * @returns searchable documents in ascending seq order; structural events are omitted. + */ +export declare function buildSessionEventSearchDocuments(sessionId: SessionId, events: readonly SessionEvent[]): SessionEventSearchDocument[]; +//# sourceMappingURL=documents.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/extraction.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/extraction.d.ts new file mode 100644 index 0000000..713e425 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/extraction.d.ts @@ -0,0 +1,12 @@ +/** First-party semantic text extraction for session-query consumers. */ +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +/** + * Extract searchable semantic text from one first-party session event. + * + * Structural boundaries, raw stream chunks, request envelopes, and unknown + * declaration-merged events contribute no text. + * @param event - event to inspect. + * @returns newline-joined semantic text, or an empty string when non-searchable. + */ +export declare function extractSessionEventText(event: SessionEvent): string; +//# sourceMappingURL=extraction.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/filters.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/filters.d.ts new file mode 100644 index 0000000..a6f010b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/filters.d.ts @@ -0,0 +1,35 @@ +/** Pure provider-independent predicates for logical sessions and event text. */ +import type { SessionEventResultFilter, SessionEventSearchDocument, SessionRecord, SessionResultFilter } from './types.ts'; +/** + * Apply ANDed logical-session filters while preserving input order. + * @param records - detached logical-session records to inspect. + * @param filters - clauses whose list values are ORed within each clause. + * @returns records accepted by every clause. + */ +export declare function filterSessionResults(records: readonly T[], filters?: readonly SessionResultFilter[]): T[]; +/** + * Apply ANDed event filters to extracted semantic documents. + * @param documents - semantic documents produced by {@link buildSessionEventSearchDocuments}. + * @param filters - metadata and literal-text predicates. + * @returns documents accepted by every clause, in input order. + */ +export declare function filterSessionEventDocuments(documents: readonly T[], filters?: readonly SessionEventResultFilter[]): T[]; +/** + * Copy and validate logical-session filters before an asynchronous boundary. + * @param filters - caller-owned clauses to materialize. + * @returns detached validated clauses. + */ +export declare function materializeSessionResultFilters(filters: readonly SessionResultFilter[]): SessionResultFilter[]; +/** + * Copy and validate event filters before an asynchronous boundary. + * @param filters - caller-owned clauses to materialize. + * @returns detached validated clauses. + */ +export declare function materializeSessionEventResultFilters(filters: readonly SessionEventResultFilter[]): SessionEventResultFilter[]; +/** + * Compile a literal case-insensitive, whitespace-flexible semantic-text match. + * @param text - caller-provided literal text. + * @returns Unicode-aware regular expression safe from regex injection. + */ +export declare function compileSessionTextFilter(text: string): RegExp; +//# sourceMappingURL=filters.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/index.d.ts new file mode 100644 index 0000000..4b29880 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/index.d.ts @@ -0,0 +1,143 @@ +/** + * Service Definition for combined session-history reads, traces, filters, and full-text search. + * + * @module @deepseek-ai/dsh-session-query + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import { type SessionId } from '@deepseek-ai/dsh-session'; +import type { SessionTitleSnapshot } from '@deepseek-ai/dsh-session-title'; +import type { SessionEventResultFilter, SessionEventSearchPage, SessionEventReadRequest, SessionEventRecord, SessionEventSearchDocument, SessionEventSearchRequest, SessionEventTraceObservation, SessionEventTraceRequest, SessionEventWindow, SessionLineageTrace, SessionLogSnapshot, SessionRecord, SessionResultFilter, SessionSearchExecContext, SessionSearchHit, SessionSearchPage, SessionSearchRequest, SessionSurfaceSnapshot, SessionTitleObservation, SessionTitleObservationResult } from './types.ts'; +import { type Config } from './config.ts'; +export type * from './types.ts'; +export { SessionSearchCursor } from './cursor.ts'; +export type { Config, SessionQueryErrorCode } from './config.ts'; +export { SESSION_QUERY_DEFAULT_PERSISTED_INSPECT_CONCURRENCY, SESSION_QUERY_READ_WINDOW_MAX, SessionQueryError, } from './config.ts'; +export { extractSessionEventText } from './extraction.ts'; +export { buildSessionEventRecords, buildSessionEventSearchDocuments } from './documents.ts'; +export { compileSessionTextFilter, filterSessionEventDocuments, filterSessionResults, materializeSessionEventResultFilters, materializeSessionResultFilters, } from './filters.ts'; +export { assertSessionHeadersCompatible } from './sources.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + sessionQuery: SessionQueryEngine; + } +} +/** + * Unified live-preferred session query service. + * + * Exact reads, filters, and traces are backend-independent concrete behavior. + * A backend implements full-text observation, reconciliation, ranking, cursor + * generations, and query execution on the same `ctx.sessionQuery` service. + */ +export declare abstract class SessionQueryEngine extends Service { + static inject: string[]; + private readonly _readWindowMax; + private readonly _corpus; + constructor(ctx: Context, config?: Config); + /** + * Search the live-preferred logical corpus and group by session. + * @param request - query text, metadata filters, page size, and cursor. + * @param exec - optional cancellation control. + * @returns session hits ranked by their strongest matching event. + */ + abstract searchSessions(request: SessionSearchRequest, exec?: SessionSearchExecContext): Promise>; + /** + * Search events within one live-preferred logical session. + * @param request - target session, query text, filters, page size, and cursor. + * @param exec - optional cancellation control. + * @returns matching event hits and their target header from one indexed generation. + */ + abstract searchEvents(request: SessionEventSearchRequest, exec?: SessionSearchExecContext): Promise; + /** + * List the complete logical corpus using live-preferred records. + * @param signal - optional cancellation for persistence listing. + * @returns deterministic newest-first cloned session records. + */ + listSessions(signal?: AbortSignal): Promise; + /** + * Read and replay-validate one complete logical session log without making it live. + * @param sessionId - live or persisted session id to read. + * @returns cloned header and complete raw event log from one observation. + * @throws when persistence, header compatibility, or replay validation fails. + */ + readSession(sessionId: SessionId): Promise; + /** + * Filter the complete logical corpus with provider-independent predicates. + * @param filters - ANDed session metadata and availability clauses. + * @param signal - optional cancellation for persistence listing. + * @returns matching cloned records in deterministic newest-first order. + */ + filterSessions(filters: readonly SessionResultFilter[], signal?: AbortSignal): Promise; + /** + * Fold the latest log-backed title from one live-preferred logical session. + * @param sessionId - live or persisted session id to read. + * @param signal - optional cancellation for source resolution and title folding. + * @returns latest title snapshot, or `undefined` when the log has no title event. + */ + readTitle(sessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Fold the latest title and return its source header from one corpus observation. + * @param sessionId - live or persisted session id to read. + * @param signal - optional cancellation for source resolution and title folding. + * @returns cloned source header and optional latest title snapshot. + */ + readTitleSnapshot(sessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Fold titles for unique sessions from one cancellable corpus observation. + * + * Results preserve first-occurrence input order. Operational failures stay + * isolated per session, while cancellation rejects the complete operation. + * @param sessionIds - live or persisted session ids to observe. + * @param signal - optional cancellation shared by all source reads. + * @returns one fulfilled or rejected result per unique requested id. + */ + readTitleSnapshots(sessionIds: readonly SessionId[], signal?: AbortSignal): Promise; + /** + * List lightweight raw-log event records for one logical session. + * @param sessionId - live-preferred session id to read. + * @returns event records in ascending seq order. + */ + listEvents(sessionId: SessionId): Promise; + /** + * Scan first-party semantic event documents with provider-independent filters. + * @param sessionId - live-preferred session id to scan. + * @param filters - ANDed metadata and literal-text predicates. + * @returns matching semantic documents in ascending seq order. + */ + filterEvents(sessionId: SessionId, filters: readonly SessionEventResultFilter[]): Promise; + private _filterSessions; + private _filterEvents; + /** + * Read one session's complete current model surface from one corpus observation. + * @param sessionId - live-preferred session id to read. + * @returns cloned header, current surface, and the last sequence number included in the raw-log capture. + * @throws when source resolution fails or the session surface is invalid. + */ + readSurface(sessionId: SessionId): Promise; + /** + * Trace known ancestry and descendants from one corpus observation. + * @param sessionId - logical session id to trace. + * @param signal - optional cancellation for persistence listing. + * @returns a complete lineage or the first parent that could not be resolved. + * @throws when corpus resolution fails, the target is absent, or its known ancestry cycles. + */ + traceSession(sessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Trace one event's direct positional replacements and cited source events. + * @param request - target session id and event seq. + * @param signal - optional cancellation for persisted source resolution. + * @returns source header, direct links, and the target's positional replacement chain. + * @throws when source resolution fails, the target is absent, or surface/source-event validation fails. + */ + traceEvent(request: SessionEventTraceRequest, signal?: AbortSignal): Promise; + /** + * Read one full event plus a bounded raw-log context window. + * @param request - target session/seq and context sizes. + * @param signal - optional cancellation for persisted source resolution. + * @returns cloned target and neighboring events. + */ + readEvent(request: SessionEventReadRequest, signal?: AbortSignal): Promise; + private _readEvent; + private _readWindow; +} +export default SessionQueryEngine; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/invariant.d.ts new file mode 100644 index 0000000..fc2cb87 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-query`. + * @module @deepseek-ai/dsh-session-query/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-query-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/sources.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/sources.d.ts new file mode 100644 index 0000000..2390501 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/sources.d.ts @@ -0,0 +1,9 @@ +/** Shared immutable-header checks for logical session source observers. */ +import type { SessionHeader } from '@deepseek-ai/dsh-session'; +/** + * Reject incompatible observations of one logical session source. + * @param a - first live, listed, or loaded header observation. + * @param b - second header observation expected to identify the same source. + */ +export declare function assertSessionHeadersCompatible(a: SessionHeader, b: SessionHeader): void; +//# sourceMappingURL=sources.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/tracing.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/tracing.d.ts new file mode 100644 index 0000000..6e9ddfb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/tracing.d.ts @@ -0,0 +1,33 @@ +/** One-shot session-lineage and event-relationship tracing helpers. */ +import type { SessionEvent, SessionId, SurfaceEvent } from '@deepseek-ai/dsh-session'; +import type { SessionEventRecord, SessionEventTrace, SessionLineageTrace, SessionRecord } from './types.ts'; +/** + * Classify a raw event log with one canonical surface fold. + * @param sessionId - owner of the event log. + * @param events - detached raw event log. + * @returns lightweight records in ascending log order. + */ +export declare function eventRecords(sessionId: SessionId, events: readonly SessionEvent[]): SessionEventRecord[]; +/** + * Fold and return the current model surface after validating the whole log. + * @param sessionId - owner used in query diagnostics. + * @param events - detached raw event log from one corpus observation. + * @returns detached current surface events in folded order. + */ +export declare function currentSurfaceEvents(sessionId: SessionId, events: readonly SessionEvent[]): SurfaceEvent[]; +/** + * Trace one target after one canonical surface fold and whole-log validation. + * @param sessionId - owner of the event log. + * @param events - detached raw event log. + * @param seq - target event seq. + * @returns direct surface replacements and relationships to cited source events. + */ +export declare function traceEvent(sessionId: SessionId, events: readonly SessionEvent[], seq: number): SessionEventTrace; +/** + * Trace one target's known ancestry and recursively known descendants. + * @param records - complete logical corpus from one observation. + * @param sessionId - target session id. + * @returns complete or explicitly partial lineage. + */ +export declare function traceSession(records: readonly SessionRecord[], sessionId: SessionId): SessionLineageTrace; +//# sourceMappingURL=tracing.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/types.d.ts new file mode 100644 index 0000000..5f875ef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/lib/types/types.d.ts @@ -0,0 +1,259 @@ +/** + * Public records for exact reads and relationship traces over the + * live-preferred logical session corpus. + * + * @module @deepseek-ai/dsh-session-query/types + */ +import type { SessionEvent, SessionEventType, SessionHeader, SessionId, SurfaceEvent } from '@deepseek-ai/dsh-session'; +import type { SessionTitleSnapshot } from '@deepseek-ai/dsh-session-title'; +import type { SessionSearchCursor } from './cursor.ts'; +export type { SessionSearchCursor } from './cursor.ts'; +/** Whether an event is current model context, replaced context, or raw-log-only. */ +export type SessionEventSurface = 'current' | 'shadowed' | 'log-only'; +/** Lightweight identity and source availability for one logical session. */ +export interface SessionRecord { + /** Cloned session header selected from the live-preferred corpus. */ + header: SessionHeader; + /** Whether the id currently exists in `ctx.sessions`. */ + live: boolean; + /** Whether the active persistence backend currently materializes the id. */ + persisted: boolean; +} +/** One atomic live-preferred observation of a session's current model surface. */ +export interface SessionSurfaceSnapshot { + /** Cloned session header selected from the same corpus observation as `events`. */ + session: SessionHeader; + /** Highest raw-log seq included in the observation, or `null` for an empty log. */ + capturedThroughSeq: number | null; + /** Cloned current surface events in model-history order. */ + events: SurfaceEvent[]; +} +/** One validated detached observation of a logical session's complete raw log. */ +export interface SessionLogSnapshot { + /** Cloned session header selected from the same observation as `events`. */ + session: SessionHeader; + /** Cloned contiguous raw events after persistence repair and replay validation. */ + events: SessionEvent[]; +} +/** Lightweight metadata for one event within a logical session. */ +export interface SessionEventRecord { + /** Session that owns the event. */ + sessionId: SessionId; + /** Monotonic event seq within the session. */ + seq: number; + /** Discriminant of the session event. */ + type: SessionEventType; + /** Event timestamp in Unix epoch milliseconds. */ + time: number; + /** Event placement in the folded session surface. */ + surface: SessionEventSurface; +} +/** Recursive descendant node in a session-lineage trace. */ +export interface SessionLineageNode { + /** Detached logical-corpus record for this descendant. */ + session: SessionRecord; + /** Direct children, each carrying its own recursive descendants. */ + descendants: SessionLineageNode[]; +} +/** Known ancestry and descendants for one logical session. */ +export type SessionLineageTrace = { + /** Detached record for the session that was traced. */ + target: SessionRecord; + /** Known parents from the immediate parent outward. */ + ancestors: SessionRecord[]; + /** Complete known descendant trees rooted at the target's direct children. */ + descendants: SessionLineageNode[]; +} & ({ + /** The complete parent chain is present in the logical corpus. */ + complete: true; + /** Detached record at the top of the complete lineage. */ + root: SessionRecord; +} | { + /** The parent chain leaves the visible logical corpus. */ + complete: false; + /** First parent id that is not present in the logical corpus. */ + unresolvedParentId: SessionId; +}); +/** Request for direct surface replacements and relationships to cited source events around one event. */ +export interface SessionEventTraceRequest { + /** Session that owns the target event. */ + sessionId: SessionId; + /** Target event seq. */ + seq: number; +} +/** Direct surface replacements and relationships to cited source events for one event. */ +export interface SessionEventTrace { + /** Lightweight target record. */ + target: SessionEventRecord; + /** Immediate positional replacement event, when the target was shadowed. */ + replacedBy?: number; + /** Positional replacers from the immediate replacement to the final replacement. */ + replacementChain: number[]; + /** Surface nodes directly removed when the target itself performed a replacement. */ + replacedEventSeqs: number[]; + /** Earlier events cited directly as sources, in their recorded order. */ + sourceEventSeqs: number[]; + /** Later events that directly cite the target as a source, in log order. */ + derivedEventSeqs: number[]; +} +/** Event relationships bound to the same session-header observation. */ +export interface SessionEventTraceObservation extends SessionEventTrace { + /** Cloned header selected with the event log used for the trace. */ + session: SessionHeader; +} +/** Request for one event plus raw neighboring log context. */ +export interface SessionEventReadRequest { + /** Session that owns the target event. */ + sessionId: SessionId; + /** Target event seq. */ + seq: number; + /** Number of preceding raw events to include. */ + before?: number; + /** Number of following raw events to include. */ + after?: number; +} +/** Full target event and a bounded raw-log window. */ +export interface SessionEventWindow { + /** Cloned header for the live-preferred source read. */ + session: SessionHeader; + /** Full cloned target event. */ + target: SessionEvent; + /** Full cloned events from `startSeq` through `endSeq`. */ + events: SessionEvent[]; + /** First seq included in `events`. */ + startSeq: number; + /** Last seq included in `events`. */ + endSeq: number; +} +/** Latest folded title bound to the same session-header observation. */ +export interface SessionTitleObservation { + /** Cloned header selected with the event log used for the title fold. */ + session: SessionHeader; + /** Latest title snapshot, absent when the observed log has no title. */ + title?: SessionTitleSnapshot; +} +/** One ordered result from a batch title observation. */ +export type SessionTitleObservationResult = { + /** Requested session id. */ + sessionId: SessionId; + /** Successful atomic header/title observation. */ + status: 'fulfilled'; + /** Header and optional latest title from one logical source. */ + value: SessionTitleObservation; +} | { + /** Requested session id. */ + sessionId: SessionId; + /** Operational failure isolated to this session. */ + status: 'rejected'; + /** Original failure from logical-source resolution or title folding. */ + reason: unknown; +}; +/** Inclusive numeric interval used by time and sequence filters. */ +export interface SessionResultRange { + /** Inclusive lower bound. */ + from?: number; + /** Inclusive upper bound. */ + to?: number; +} +/** Source availability predicates understood by logical-session filters. */ +export type SessionAvailability = 'live' | 'persisted'; +/** + * One logical-session predicate. A filter array is ANDed; `values` within a + * clause are ORed. + */ +export type SessionResultFilter = { + kind: 'id'; + values: readonly SessionId[]; +} | { + kind: 'cwd'; + values: readonly (string | null)[]; +} | ({ + kind: 'created-at'; +} & SessionResultRange) | { + kind: 'parent'; + values: readonly (SessionId | null)[]; +} | { + kind: 'availability'; + values: readonly SessionAvailability[]; +}; +/** + * One event predicate. A filter array is ANDed; list-valued clauses are ORed. + * Text is a literal, case-insensitive, whitespace-flexible semantic-text scan. + */ +export type SessionEventResultFilter = ({ + kind: 'seq'; +} & SessionResultRange) | ({ + kind: 'time'; +} & SessionResultRange) | { + kind: 'type'; + values: readonly SessionEventType[]; +} | { + kind: 'surface'; + values: readonly SessionEventSurface[]; +} | { + kind: 'text'; + text: string; +}; +/** Event predicates a full-text provider can apply before relevance ranking. */ +export type SessionEventMetadataFilter = Exclude; +/** Searchable semantic document derived from one session event. */ +export interface SessionEventSearchDocument extends SessionEventRecord { + /** First-party semantic text used by scan filters and full-text indexes. */ + text: string; +} +/** One cursor-paginated result page. */ +export interface SessionSearchPage { + /** Results for this page in contract-defined order. */ + items: readonly T[]; + /** Opaque continuation cursor, absent on the final page. */ + nextCursor?: SessionSearchCursor; +} +/** Event-search results bound to the indexed target-session observation. */ +export interface SessionEventSearchPage extends SessionSearchPage { + /** Cloned target header from the same indexed generation as `items`. */ + session: SessionHeader; +} +/** Controls shared by cross-session and within-session search calls. */ +export interface SessionSearchExecContext { + /** Abort caller waiting and interrupt provider work where supported. */ + signal?: AbortSignal; +} +/** Cross-session full-text search request. */ +export interface SessionSearchRequest { + /** Full-text query interpreted as data, never executable FTS syntax. */ + query: string; + /** Logical-session predicates applied before event ranking. */ + sessionFilters?: readonly SessionResultFilter[]; + /** Event predicates applied before event ranking. */ + eventFilters?: readonly SessionEventMetadataFilter[]; + /** Maximum sessions in this page. */ + limit?: number; + /** Opaque cursor returned for the identical normalized request. */ + cursor?: SessionSearchCursor; +} +/** Within-session full-text search request. */ +export interface SessionEventSearchRequest { + /** Session whose live-preferred logical log is searched. */ + sessionId: SessionId; + /** Full-text query interpreted as data, never executable FTS syntax. */ + query: string; + /** Event predicates applied before ranking. */ + filters?: readonly SessionEventMetadataFilter[]; + /** Maximum events in this page. */ + limit?: number; + /** Opaque cursor returned for the identical normalized request. */ + cursor?: SessionSearchCursor; +} +/** One event full-text search hit with a bounded plain-text excerpt. */ +export interface SessionEventSearchHit extends SessionEventRecord { + /** Plain text excerpt selected around the match. */ + snippet: string; +} +/** One grouped cross-session hit, ranked by its strongest matching event. */ +export interface SessionSearchHit extends SessionRecord { + /** Strongest matching event for this session. */ + bestMatch: SessionEventSearchHit; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/package.json new file mode 100644 index 0000000..d13b4b9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query/package.json @@ -0,0 +1,57 @@ +{ + "name": "@deepseek-ai/dsh-session-query", + "description": "Combined session query service contract with concrete reads, traces, and filters", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session-query/session-query" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + } + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-title b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-title new file mode 120000 index 0000000..dbf95ad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-title @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..fb5edd1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.i18n.yaml new file mode 100644 index 0000000..bbe1cfc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/session/session-title/README.md +README.md: e923bd9700180214f235c4971d4b020565bfee43 +README.zh.md: 8e84ac27d9f1509c8530b838eeb5eb2216d87199 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.md new file mode 100644 index 0000000..e923bd9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.md @@ -0,0 +1,55 @@ +# @deepseek-ai/dsh-session-title + +English | [中文](README.zh.md) + +Log-backed session titles with an immediate deterministic fallback and one optional asynchronous provider. Every accepted revision is a log-only `session/title` event; `foldSessionTitle()` and `ctx.sessionTitle.get()` select the latest event and return its event seq and timestamp. + +Only text blocks from human `user/message` events are eligible. The first eligible prompt schedules a fallback from its first words within the configured UTF-8 byte limit. Whitespace is normalized, terminal control sequences are removed, and truncation never splits a code point. Empty and non-text prompts wait for later eligible input. + +## Service: `SessionTitleService` (ctx key: `sessionTitle`) + +- `get(session)` folds the latest accepted title from a live or replayed log. +- `refresh(session, signal?)` materializes the fallback when needed, then explicitly runs the registered provider over the current eligible messages. Provider errors and caller cancellation reject; cancellation does not roll back an already accepted fallback event. +- `rename(session, title)` accepts an explicit user title synchronously: it normalizes the text, supersedes in-flight automatic work, and appends a `session/title` event with the `user` source. A user-sourced latest title pins the session — later user messages schedule no automatic revision; an explicit `refresh` remains the deliberate unpin. +- `register(provider)` installs the sole optional provider and returns its awaitable Cordis effect disposer. A second registration throws immediately; disposal aborts pending and active calls, waits for their settlement, and only then permits another provider to register. + +Automatic work never delays the main agent response. A provider starts only after a marked loop-built request's exact route matches the current logged `request/header`, including when the unchanged header needs no new snapshot. Its late completion appends a standalone log-only event directly through `Session` without opening a turn. Persistence observes that event eagerly and drains on ordinary lifecycle checkpoints; title publication itself does not force a flush. Automatic failures warn and retain the latest title. New all-message revisions, provider disposal, session disposal, and explicit refresh abort older work, and a stale completion cannot append. Concurrent explicit refreshes reserve their revision before provider work, while overlapping automatic and explicit fallback requests share one session-local in-flight append. The service and bundled model provider each append their own literal event type, so no generic title-write marker, cast, or settlement queue is needed. Service teardown cancels queued work and drains calls that ignore cancellation before unloading completes. + +Forks inherit title events in their seed unchanged. The first-prompt cadence does not automatically retitle a child; the all-messages cadence may append a new revision after the child receives a later human prompt. + +## Configuration + +All limits are required; the library supplies no defaults. + +| Key | Contract | +|---|---| +| `fallbackMaxWords` | Positive maximum whitespace-delimited words in the deterministic fallback. | +| `fallbackMaxBytes` | Positive maximum UTF-8 bytes in the fallback; must not exceed `maxTitleBytes`. | +| `maxTitleBytes` | Positive maximum UTF-8 bytes accepted from any source. | + +## Provider contract + +A provider supplies a branded stable id, automatic mode (`first-prompt` or `all-prompts`), and `generate(request)`. The request carries the live session, all eligible messages through one fixed revision, the current logged main-request route when available, and cancellation. The result identifies a non-empty title, unique ordered source-message seqs from that request, and the optional provider/model route used to generate it. The service normalizes and validates the result before it becomes durable. + +See the [session-title data structures](../../../docs/subsystems/session-title.md) and [implemented decision](../../../.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md). + +## Model Experience + +### Session title state + +#### What the model sees + +Nothing. `session/title` is log-only and never enters the session surface, `deriveMessages()`, system prompt, tool schemas, or request prefix. + +#### Token effect + +The fallback and accepted provider revisions add zero tokens to the main agent request. An optional provider's separate auxiliary request is documented by that provider package. + +#### KV Cache effect + +None for the main request; title events do not change its reconstructed content or cache key. + +## Known Limitations and Deferred Work + +- Title deletion (unpinning back to automatic titles without an explicit `refresh`), search, and list indexing are outside this service. +- The provider registry deliberately accepts at most one implementation, so a deployment cannot compose competing title strategies without writing one provider that owns their precedence. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.zh.md new file mode 100644 index 0000000..8e84ac2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/README.zh.md @@ -0,0 +1,55 @@ +# @deepseek-ai/dsh-session-title + +[English](README.md) | 中文 + +由日志支持的会话标题,提供即时确定性回退与一个可选异步提供方。每次已接受的修订都是仅写入日志的 `session/title` 事件;`foldSessionTitle()` 与 `ctx.sessionTitle.get()` 会选择最新事件,并返回其事件 seq 和时间戳。 + +只有用户 `user/message` 事件中的文本块符合条件。第一条符合条件的提示词会安排回退,从其开头若干词生成标题,并受所配置 UTF-8 字节上限约束。系统会规范化空白、移除终端控制序列,且截断绝不会切断码点。空提示词和非文本提示词会等待后续符合条件的输入。 + +## 服务:`SessionTitleService`(ctx 键:`sessionTitle`) + +- `get(session)` 从活跃或回放日志折叠最新已接受标题。 +- `refresh(session, signal?)` 在需要时物化回退,然后显式运行已注册提供方,处理当前符合条件的消息。提供方错误或调用方取消都会导致返回的 Promise 被拒绝;取消不会回滚已接受的回退事件。 +- `rename(session, title)` 同步接受用户显式标题:规范化文本、取代在途自动工作,并追加一条 `user` 来源的 `session/title` 事件。用户来源的最新标题会钉住该会话——后续用户消息不再安排自动修订;显式 `refresh` 仍是有意的解钉手段。 +- `register(provider)` 安装唯一可选提供方,并返回可等待的 Cordis effect disposer。第二次注册会立即抛出;对提供方执行 dispose(资源释放)会中止待处理和活跃调用,等待其结算,之后才允许注册另一个提供方。 + +自动工作绝不会延迟主 agent(智能体)响应。只有当带标记、由循环构建的请求,其确切路由与当前已记录的 `request/header` 匹配时,提供方才会启动;即使请求头未变而无需新快照,也适用此规则。延迟完成会直接通过 `Session` 追加一个独立的纯日志事件,而不打开轮次。持久化会立即观察到该事件,并在常规生命周期检查点完成刷写;标题发布本身不会强制刷写。自动失败会发出警告并保留最新标题。新的全消息修订、提供方 dispose、会话 dispose 和显式刷新都会中止旧工作,陈旧的完成结果无法追加。并发显式刷新会在提供方工作之前预留修订号;重叠的自动/显式回退请求共享一个会话本地正在进行的追加操作。服务与内置模型提供方各自追加自己的字面事件类型,因此不需要通用标题写入标记、类型断言或结算队列。服务拆卸会取消排队工作,并在卸载完成前等待不响应取消的调用结算完成。 + +fork 出的会话会原样继承种子中的标题事件。首消息节奏不会自动为子会话重新生成标题;全消息节奏可以在子会话收到后续用户提示词后追加新修订。 + +## 配置 + +所有上限都是必填项;该库不提供默认值。 + +| 键 | 约定 | +|---|---| +| `fallbackMaxWords` | 确定性回退中以空白分隔的最大正整数词数。 | +| `fallbackMaxBytes` | 回退允许的最大正整数 UTF-8 字节数;不得超过 `maxTitleBytes`。 | +| `maxTitleBytes` | 接受任何来源标题的最大正整数 UTF-8 字节数。 | + +## 提供方约定 + +提供方会提供带品牌类型的稳定 id、自动模式(`first-prompt` 或 `all-prompts`)和 `generate(request)`。请求携带活跃会话、截至一次固定修订的所有符合条件消息、可用时当前已记录的主请求路由,以及取消信号。结果包含非空标题、该请求中互不重复且有序的来源消息 seq,以及生成该标题时使用的可选提供方/模型路由。服务会在结果持久保存前进行规范化和验证。 + +参见[会话标题数据结构](../../../docs/subsystems/session-title.md)与[已实现决策](../../../.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md)。 + +## 模型体验 + +### 会话标题状态 + +#### 模型看到的内容 + +无。`session/title` 只写入日志,绝不会进入会话接口、`deriveMessages()`、系统提示词、工具 schema 或请求前缀。 + +#### Token 影响 + +回退与已接受的提供方修订不会向主 agent 请求增加 token。可选提供方的独立辅助请求由对应提供方包的文档说明。 + +#### KV Cache 影响 + +不影响主请求;标题事件不会改变重建内容或缓存键。 + +## 已知限制与暂缓事项 + +- 删除标题(不经显式 `refresh` 就解钉回自动标题)、搜索和列表索引不属于此服务。 +- 提供方注册表有意最多接受一个实现,因此部署若要组合相互竞争的标题策略,必须编写一个自行负责优先级的提供方。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/index.js new file mode 100644 index 0000000..00039f8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/index.js @@ -0,0 +1,580 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { z as z$1 } from "zod"; +import { assertNever, deepFreeze, isAgentLoopRequest } from "@deepseek-ai/dsh-llm"; +//#region lib/types/normalize.js +/** Title text normalization and UTF-8-safe truncation. */ +/** Operating-system-command escape sequences, including unterminated tails. */ +const OSC_SEQUENCE = /(?:\u001B\]|\u009D)(?:(?!\u0007|\u001B\\)[\s\S])*(?:\u0007|\u001B\\|$)/gu; +/** Control-sequence-introducer escapes such as SGR color codes. */ +const CSI_SEQUENCE = /(?:\u001B\[|\u009B)[0-?]*[ -/]*[@-~]/gu; +/** Remaining two-byte ESC control sequences. */ +const ESC_SEQUENCE = /\u001B[@-_]/gu; +/** Non-whitespace C0/C1 control characters. */ +const CONTROL_CHARACTER = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/gu; +/** Directional and invisible controls that can make a displayed title deceptive. */ +const DIRECTIONAL_CONTROL = /[\u200B\u200E\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF]/gu; +/** Reject an invalid public text limit. */ +function assertPositiveInteger$1(name, value) { + if (!Number.isInteger(value) || value <= 0) throw new Error(`${name} must be a positive integer`); +} +/** Remove controls and produce one trimmed, whitespace-normalized line. */ +function cleanTitleText(input) { + return input.replace(OSC_SEQUENCE, "").replace(CSI_SEQUENCE, "").replace(ESC_SEQUENCE, "").replace(CONTROL_CHARACTER, "").replace(DIRECTIONAL_CONTROL, "").replace(/\s+/gu, " ").trim(); +} +/** +* Truncate a string to a UTF-8 byte budget without splitting a Unicode code point. +* @param input - normalized title text. +* @param maxBytes - positive UTF-8 byte budget. +* @returns the longest leading code-point prefix within the budget. +*/ +function truncateTitleUtf8(input, maxBytes) { + assertPositiveInteger$1("maxBytes", maxBytes); + if (Buffer.byteLength(input, "utf8") <= maxBytes) return input; + let used = 0; + let output = ""; + for (const character of input) { + const bytes = Buffer.byteLength(character, "utf8"); + if (used + bytes > maxBytes) break; + output += character; + used += bytes; + } + return output; +} +/** +* Normalize one accepted session title and enforce its UTF-8 byte budget. +* @param input - untrusted title text. +* @param maxBytes - positive maximum encoded size. +* @returns a terminal-safe one-line title, possibly empty after sanitization. +*/ +function normalizeSessionTitle(input, maxBytes) { + return truncateTitleUtf8(cleanTitleText(input), maxBytes).trimEnd(); +} +/** +* Derive the deterministic first-prompt fallback. +* @param input - text from the first eligible human message. +* @param maxWords - positive whitespace-delimited word cap. +* @param maxBytes - positive UTF-8 byte cap. +* @returns the normalized leading words within both limits. +*/ +function fallbackSessionTitle(input, maxWords, maxBytes) { + assertPositiveInteger$1("maxWords", maxWords); + return truncateTitleUtf8(cleanTitleText(input).split(" ").filter(Boolean).slice(0, maxWords).join(" "), maxBytes).trimEnd(); +} +//#endregion +//#region lib/types/index.js +/** +* Log-backed session title service, deterministic fallback, and provider contract. +* @module @deepseek-ai/dsh-session-title +*/ +/** +* Brand a raw provider id. +* @param id - stable non-empty provider identifier supplied by a plugin. +* @returns the same string with the session-title provider brand. +*/ +function SessionTitleProviderId(id) { + return id; +} +/** +* Rejection of an explicit user title whose text normalizes to empty — the +* one {@link SessionTitleService.rename} failure that blames the input. +* Callers translating rename failures onto a wire (`title-invalid`) narrow on +* this class; liveness and disposal failures stay plain `Error`s. +*/ +var SessionTitleInvalidError = class extends Error { + name = "SessionTitleInvalidError"; +}; +/** +* Collect human text-bearing user messages in log order. +* @param events - session log or persisted replay. +* @param throughSeq - optional inclusive event boundary. +* @returns eligible messages with exact source seqs. +*/ +function collectSessionTitleMessages(events, throughSeq) { + const messages = []; + for (const event of events) { + if (throughSeq !== void 0 && event.seq > throughSeq) break; + if (event.type !== "user/message" || event.data.source.kind !== "user") continue; + const text = event.data.content.filter((block) => block.type === "text").map((block) => block.text).join("\n"); + if (normalizeSessionTitle(text, Number.MAX_SAFE_INTEGER).length === 0) continue; + messages.push({ + seq: event.seq, + text + }); + } + return messages; +} +/** +* Fold the latest logged title without consulting mutable metadata. +* @param events - live or persisted session log. +* @returns the latest immutable title snapshot, or `undefined`. +*/ +function foldSessionTitle(events) { + const event = events.findLast((item) => item.type === "session/title"); + if (event === void 0) return void 0; + return deepFreeze({ + title: event.data.title, + messageSeqs: [...event.data.messageSeqs], + source: copySessionTitleSource(event.data.source), + eventSeq: event.seq, + updatedAt: event.time + }); +} +/** Defensive copy of a logged title source (the snapshot must not alias log-owned objects). */ +function copySessionTitleSource(source) { + switch (source.kind) { + case "fallback": return { kind: "fallback" }; + case "provider": return { + kind: "provider", + provider: source.provider, + ...source.model === void 0 ? {} : { model: { ...source.model } } + }; + case "user": return { kind: "user" }; + /* v8 ignore next -- closed-union exhaustiveness guard */ + default: return assertNever(source, "SessionTitleSource"); + } +} +/** Validate one positive integer configuration field. */ +function assertPositiveInteger(name, value) { + if (!Number.isInteger(value) || value <= 0) throw new Error(`session-title: ${name} must be a positive integer`); +} +/** Log-backed title fold plus asynchronous fallback generation. */ +var SessionTitleService = class extends Service { + static inject = ["sessions"]; + static Config = z.object({ + fallbackMaxWords: z.number().step(1).min(1).required(), + fallbackMaxBytes: z.number().step(1).min(1).required(), + maxTitleBytes: z.number().step(1).min(1).required() + }); + config; + ownerFiber; + registration; + work = /* @__PURE__ */ new Map(); + lifetime = new AbortController(); + inFlight = /* @__PURE__ */ new Set(); + constructor(ctx, config) { + super(ctx, "sessionTitle"); + this.ownerFiber = ctx.fiber; + const candidate = config; + if (candidate === null || typeof candidate !== "object") throw new Error("session-title: configuration is required"); + const value = candidate; + assertPositiveInteger("fallbackMaxWords", value.fallbackMaxWords); + assertPositiveInteger("fallbackMaxBytes", value.fallbackMaxBytes); + assertPositiveInteger("maxTitleBytes", value.maxTitleBytes); + if (value.fallbackMaxBytes > value.maxTitleBytes) throw new Error("session-title: fallbackMaxBytes must not exceed maxTitleBytes"); + this.config = deepFreeze({ ...value }); + ctx.effect(() => async () => { + this.lifetime.abort(/* @__PURE__ */ new Error("session-title service disposed")); + if (this.registration !== void 0) this.registration.closing = true; + this.registration = void 0; + for (const state of this.work.values()) { + delete state.pending; + state.active?.controller.abort(/* @__PURE__ */ new Error("session-title service disposed")); + } + await this.drain(this.inFlight); + this.work.clear(); + }, "sessionTitle lifecycle"); + ctx.inject(["sessionProjections"], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: "title", + schema: z$1.union([z$1.string().min(1), z$1.null()]), + init: () => null, + apply: (state, event) => event.type === "session/title" ? event.data.title : state, + view: (state) => state, + stateVersion: 1 + }); + }); + ctx.on("session/event", (session, event) => { + switch (event.type) { + case "user/message": + this.onUserMessage(session, event); + break; + case "request/header": + this.onRequestHeader(session, event); + break; + default: break; + } + }); + ctx.on("llm/stream", (options, next) => { + this.onMainRequest(options); + return next(); + }, { + global: true, + prepend: true + }); + ctx.on("session/disposed", (session) => { + const state = this.work.get(session); + if (state === void 0) return; + state.active?.controller.abort(/* @__PURE__ */ new Error("session disposed during title generation")); + this.work.delete(session); + }); + } + /** + * Read the latest folded title from one live or replayed session. + * @param session - session whose log is the title source of truth. + * @returns latest title snapshot, or `undefined` before eligible input. + */ + get(session) { + return foldSessionTitle(session.events); + } + /** + * Accept an explicit user title. Appends a `session/title` event with the + * `user` source, which pins the title: in-flight automatic generation is + * superseded and later user messages schedule none (an explicit + * {@link SessionTitleService.refresh} remains the deliberate unpin). + * @param session - exact live session to rename. + * @param title - raw user input; normalized before acceptance. + * @returns the accepted title snapshot. + * @throws {SessionTitleInvalidError} when the title normalizes to empty. + * @throws {Error} when the session is not live or the service is disposed. + */ + rename(session, title) { + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) throw new Error(`session "${session.id}" is not live in this store`); + const normalized = normalizeSessionTitle(title, this.config.maxTitleBytes); + if (normalized.length === 0) throw new SessionTitleInvalidError("session title must contain visible characters"); + const state = this.stateFor(session); + this.supersede(state, "user rename superseded automatic title generation"); + session.append("session/title", { + title: normalized, + messageSeqs: [], + source: { kind: "user" } + }); + const snapshot = this.get(session); + /* v8 ignore next -- unreachable: the append above just committed a session/title event. */ + if (snapshot === void 0) throw new Error("renamed title failed to fold"); + return snapshot; + } + /** + * Explicitly retry the registered provider, or materialize the built-in + * fallback when no provider is registered. + * @param session - exact live session to refresh. + * @param signal - optional caller cancellation. + * @returns latest accepted title, or `undefined` when no eligible text exists. + */ + async refresh(session, signal) { + signal?.throwIfAborted(); + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) throw new Error(`session "${session.id}" is not live in this store`); + const registration = this.registration; + const messages = collectSessionTitleMessages(session.events); + const latest = messages.at(-1); + if (registration === void 0 || registration.closing || latest === void 0) { + const current = this.get(session); + const [first] = messages; + if (current?.source.kind === "user" && first !== void 0) { + this.appendFallback(session, first); + signal?.throwIfAborted(); + return this.get(session); + } + const fallback = await this.ensureFallback(session); + signal?.throwIfAborted(); + return fallback; + } + const state = this.stateFor(session); + const revision = this.supersede(state, "explicit title refresh superseded older generation"); + const work = this.activate({ + registration, + revision, + throughSeq: latest.seq + }, state, signal); + const config = session.requestHeader()?.config; + const route = config === void 0 ? void 0 : { + provider: config.provider, + model: config.model + }; + return this.startProvider(session, work, route); + } + /** + * Register the sole optional title provider. Disposal aborts its pending and + * active work before another provider may register. + * @param provider - provider identity, cadence, and generation function. + * @returns exact Cordis effect disposer, which settles after active calls quiesce. + */ + register(provider) { + this.validateProvider(provider); + if (this.registration !== void 0) throw new Error(`session-title provider "${this.registration.provider.id}" is already registered`); + const registration = { + provider, + active: /* @__PURE__ */ new Set(), + closing: false + }; + return this.ctx.effect(function* () { + this.registration = registration; + yield async () => { + registration.closing = true; + for (const state of this.work.values()) { + if (state.pending?.registration === registration) delete state.pending; + if (state.active?.registration === registration) state.active.controller.abort(/* @__PURE__ */ new Error(`session-title provider "${provider.id}" was disposed`)); + } + await this.drain(registration.active); + if (this.registration === registration) this.registration = void 0; + }; + }.bind(this), "sessionTitle.register()"); + } + /** Schedule fallback creation and any provider cadence for one eligible event. */ + onUserMessage(session, event) { + if (!this.serviceActive()) return; + if (event.data.source.kind !== "user" || collectSessionTitleMessages([event]).length === 0) return; + if (this.get(session)?.source.kind === "user") return; + const registration = this.registration; + if (registration !== void 0 && !registration.closing) { + const messages = collectSessionTitleMessages(session.events, event.seq); + if (registration.provider.automatic === "all-prompts" || session.header.parentSession === void 0 && messages.length === 1 && this.get(session) === void 0) { + const state = this.stateFor(session); + state.pending = { + registration, + revision: this.supersede(state, "newer user message superseded title generation"), + throughSeq: event.seq + }; + } + } + this.defer(async () => { + try { + await this.ensureFallback(session); + } catch (error) { + if (!this.serviceActive()) return; + this.ctx.logger.warn(`session "${session.id}": fallback title update failed: ${String(error)}`); + } + }); + } + /** Start pending automatic work only after its exact main-request route is logged. */ + onRequestHeader(session, event) { + if (!this.serviceActive()) return; + const state = this.work.get(session); + const pending = state?.pending; + if (state === void 0 || pending === void 0 || pending.throughSeq >= event.seq) return; + const route = { + provider: event.data.header.config.provider, + model: event.data.header.config.model + }; + this.startPending(session, state, pending, route); + } + /** Start unchanged-route work from the marked loop request after its header fold is current. */ + onMainRequest(options) { + if (!this.serviceActive() || options.sessionId === void 0 || !isAgentLoopRequest(options)) return; + const session = this.ctx.sessions.get(options.sessionId); + const state = session === void 0 ? void 0 : this.work.get(session); + const pending = state?.pending; + if (session === void 0 || state === void 0 || pending === void 0) return; + const boundary = session.events.findLast((event) => event.type === "step/start" || event.type === "step/end"); + const route = session.requestHeader()?.config; + if (boundary?.type !== "step/start" || boundary.seq <= pending.throughSeq || route?.provider !== options.provider || route.model !== options.model) return; + this.startPending(session, state, pending, { + provider: options.provider, + model: options.model + }); + } + /** Consume one pending revision and schedule its non-blocking provider call. */ + startPending(session, state, pending, route) { + delete state.pending; + this.defer(async () => { + if (this.registration !== pending.registration || pending.registration.closing || this.work.get(session) !== state || state.revision !== pending.revision) return; + const work = this.activate(pending, state); + try { + await this.startProvider(session, work, route); + } catch (error) { + if (work.signal.aborted || !this.serviceActive()) return; + this.ctx.logger.warn(`session "${session.id}": automatic title generation failed: ${String(error)}`); + } + }); + } + /** Start one tracked provider call after publishing its active revision. */ + startProvider(session, work, route) { + const run = Promise.resolve().then(() => this.runProvider(session, work, route)); + return this.track(run, work.registration); + } + /** Execute and accept one current provider revision. */ + async runProvider(session, work, route) { + try { + this.assertCurrent(session, work); + await this.ensureFallback(session); + this.assertCurrent(session, work); + const messages = collectSessionTitleMessages(session.events, work.throughSeq); + const result = await work.registration.provider.generate({ + session, + messages, + ...route === void 0 ? {} : { route }, + signal: work.signal + }); + this.assertCurrent(session, work); + const accepted = this.validateResult(result, messages); + session.append("session/title", { + title: accepted.title, + messageSeqs: [...accepted.messageSeqs], + source: { + kind: "provider", + provider: work.registration.provider.id, + ...accepted.model === void 0 ? {} : { model: accepted.model } + } + }); + return this.get(session); + } finally { + const state = this.work.get(session); + if (state?.active === work) delete state.active; + } + } + /** Validate and normalize provider output against the supplied message snapshot. */ + validateResult(result, messages) { + if (result === null || typeof result !== "object") throw new Error("session-title provider returned an invalid result"); + const candidate = result; + if (typeof candidate.title !== "string") throw new Error("session-title provider title must be a string"); + const title = normalizeSessionTitle(candidate.title, this.config.maxTitleBytes); + if (title.length === 0) throw new Error("session-title provider returned an empty title"); + if (!Array.isArray(candidate.messageSeqs) || candidate.messageSeqs.length === 0) throw new Error("session-title provider must identify at least one source message seq"); + const messageSeqs = []; + const order = new Map(messages.map((message, index) => [message.seq, index])); + let previous = -1; + for (const seq of candidate.messageSeqs) { + if (typeof seq !== "number") throw new Error("session-title provider messageSeqs must be unique, ordered seqs from the request"); + const index = order.get(seq); + if (!Number.isSafeInteger(seq) || seq < 0 || index === void 0 || index <= previous) throw new Error("session-title provider messageSeqs must be unique, ordered seqs from the request"); + messageSeqs.push(seq); + previous = index; + } + const modelCandidate = candidate.model; + let model; + if (modelCandidate !== void 0) { + if (modelCandidate === null || typeof modelCandidate !== "object") throw new Error("session-title provider result model must contain non-empty provider and model strings"); + const record = modelCandidate; + if (typeof record.provider !== "string" || record.provider.length === 0 || typeof record.model !== "string" || record.model.length === 0) throw new Error("session-title provider result model must contain non-empty provider and model strings"); + model = { + provider: record.provider, + model: record.model + }; + } + return { + title, + messageSeqs, + ...model === void 0 ? {} : { model } + }; + } + /** Fail a completion whose provider, revision, session, or signal is stale. */ + assertCurrent(session, work) { + this.assertServiceActive(); + work.signal.throwIfAborted(); + const state = this.work.get(session); + /* v8 ignore next -- every supported supersession, provider disposal, and session disposal aborts + * the work signal before changing this state. */ + if (this.registration !== work.registration || state?.active !== work || state.revision !== work.revision || this.ctx.sessions.get(session.id) !== session) throw new Error("session title generation state changed without cancellation"); + } + /** Create and publish an active provider call from one fixed revision. */ + activate(pending, state, upstream) { + const controller = new AbortController(); + const signal = upstream === void 0 ? AbortSignal.any([controller.signal, this.lifetime.signal]) : AbortSignal.any([ + controller.signal, + this.lifetime.signal, + upstream + ]); + const work = { + ...pending, + controller, + signal + }; + state.active = work; + return work; + } + /** Abort older active work and reserve the next session-local revision. */ + supersede(state, reason) { + state.active?.controller.abort(new Error(reason)); + delete state.pending; + state.revision += 1; + return state.revision; + } + /** Return mutable work state for one session. */ + stateFor(session) { + let state = this.work.get(session); + if (state === void 0) { + state = { revision: 0 }; + this.work.set(session, state); + } + return state; + } + /** Queue detached service work and retain it through service disposal. */ + defer(task) { + const run = Promise.resolve().then(async () => { + if (!this.serviceActive()) return; + await task(); + }); + this.track(run); + } + /** Retain one promise until settlement for service and optional provider teardown. */ + track(run, registration) { + this.inFlight.add(run); + registration?.active.add(run); + const settled = () => { + this.inFlight.delete(run); + registration?.active.delete(run); + }; + run.then(settled, settled); + return run; + } + /** Await every current and settling promise in one lifecycle registry. */ + async drain(active) { + while (active.size > 0) await Promise.allSettled([...active]); + } + /** Whether the owning plugin fiber can still start or commit title work. */ + serviceActive() { + return !this.lifetime.signal.aborted && this.ownerFiber.uid !== null && this.ownerFiber.state === 2; + } + /** Reject work once the owning plugin fiber has begun unloading. */ + assertServiceActive() { + if (!this.serviceActive()) throw new Error("session-title service disposed"); + } + /** Reject malformed provider registrations before publishing an effect. */ + validateProvider(provider) { + if (provider === null || typeof provider !== "object") throw new Error("session-title provider must be an object"); + const candidate = provider; + if (typeof candidate.id !== "string" || candidate.id.length === 0) throw new Error("session-title provider id must be a non-empty string"); + if (candidate.automatic !== "first-prompt" && candidate.automatic !== "all-prompts") throw new Error("session-title provider automatic mode is invalid"); + if (typeof candidate.generate !== "function") throw new Error(`session-title provider "${candidate.id}" requires generate()`); + } + /** + * Derive and append the deterministic fallback title over whatever stands + * (the refresh unpin path: overwriting a pinned user title is the point). + * Synchronous on purpose — no await may separate derivation from append, so + * it needs neither ensureFallback's in-flight dedup nor its liveness + * re-check. An underivable fallback (empty after the caps) appends nothing. + */ + appendFallback(session, first) { + const title = fallbackSessionTitle(first.text, this.config.fallbackMaxWords, this.config.fallbackMaxBytes); + if (title.length === 0) return; + session.append("session/title", { + title, + messageSeqs: [first.seq], + source: { kind: "fallback" } + }); + } + /** Create the first deterministic fallback if the session still lacks a title. */ + async ensureFallback(session) { + this.assertServiceActive(); + const current = this.get(session); + if (current !== void 0) return current; + const [first] = collectSessionTitleMessages(session.events); + if (first === void 0) return void 0; + const title = fallbackSessionTitle(first.text, this.config.fallbackMaxWords, this.config.fallbackMaxBytes); + if (title.length === 0) return void 0; + const state = this.stateFor(session); + if (state.fallback !== void 0) return state.fallback; + const fallback = Promise.resolve().then(() => { + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) throw new Error(`session "${session.id}" is not live in this store`); + const accepted = this.get(session); + if (accepted !== void 0) return accepted; + session.append("session/title", { + title, + messageSeqs: [first.seq], + source: { kind: "fallback" } + }); + return this.get(session); + }); + state.fallback = fallback; + try { + return await fallback; + } finally { + delete state.fallback; + } + } +}; +//#endregion +export { SessionTitleInvalidError, SessionTitleProviderId, SessionTitleService, SessionTitleService as default, collectSessionTitleMessages, fallbackSessionTitle, foldSessionTitle, normalizeSessionTitle, truncateTitleUtf8 }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/invariant.js new file mode 100644 index 0000000..d2b72b4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/invariant.js @@ -0,0 +1,38 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-session-title`. +* @module @deepseek-ai/dsh-session-title/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session-title"; +/** Cordis companion plugin name. */ +const name = "session-title-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* Durable title-source invariant: an automatic title always cites at +* least one human `user/message` seq, and an explicit user rename cites none +* — `messageSeqs` is empty iff `source.kind` is `user`. Provider revisions +* are validated by the service before their append; this checks the durable +* relationship every appended `session/title` event must keep, whichever +* writer produced it. +*/ +const install = Object.assign((ctx, fail) => { + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName !== "session/event") return; + const [, event] = args; + if (event.type !== "session/title") return; + const { source, messageSeqs } = event.data; + if (messageSeqs.length === 0 !== (source.kind === "user")) { + const requirement = source.kind === "user" ? "cite no message seqs" : "cite at least one message seq"; + fail(`session/title event ${String(event.seq)} with source "${source.kind}" must ${requirement}; got ${String(messageSeqs.length)}`); + } + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.d.ts new file mode 100644 index 0000000..9f1c7d1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.d.ts @@ -0,0 +1,10 @@ +/** + * Client-namespace projection of the title domain: a pure re-export of the package's + * types outlet. Client code imports ONLY the client namespace (repo + * discipline), so `./client` projects the same single-source content + * `./types` serves to host consumers — zero duplication. + * + * @module @deepseek-ai/dsh-session-title/client + */ +export type * from './types.ts'; +//# sourceMappingURL=client.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.js new file mode 100644 index 0000000..b6c0882 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.js @@ -0,0 +1,10 @@ +/** + * Client-namespace projection of the title domain: a pure re-export of the package's + * types outlet. Client code imports ONLY the client namespace (repo + * discipline), so `./client` projects the same single-source content + * `./types` serves to host consumers — zero duplication. + * + * @module @deepseek-ai/dsh-session-title/client + */ +export {}; +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.d.ts new file mode 100644 index 0000000..4cb8714 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.d.ts @@ -0,0 +1,230 @@ +/** + * Log-backed session title service, deterministic fallback, and provider contract. + * @module @deepseek-ai/dsh-session-title + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { Session, SessionEvent } from '@deepseek-ai/dsh-session'; +export type * from './types.ts'; +export { fallbackSessionTitle, normalizeSessionTitle, truncateTitleUtf8 } from './normalize.ts'; +/** Identifies one session-title provider registration. */ +export type SessionTitleProviderId = Branded<'SessionTitleProviderId'>; +/** + * Brand a raw provider id. + * @param id - stable non-empty provider identifier supplied by a plugin. + * @returns the same string with the session-title provider brand. + */ +export declare function SessionTitleProviderId(id: string): SessionTitleProviderId; +/** Exact auxiliary model route that produced a title. */ +export interface SessionTitleModelProvenance { + /** Registered LLM provider route. */ + readonly provider: string; + /** Provider model id. */ + readonly model: string; +} +/** Durable ownership record for an accepted session title. */ +export type SessionTitleSource = { + readonly kind: 'fallback'; +} | { + readonly kind: 'provider'; + readonly provider: SessionTitleProviderId; + readonly model?: SessionTitleModelProvenance; +} | { + /** Explicit user rename: pins the title — automatic generation stops scheduling. */ + readonly kind: 'user'; +}; +/** Payload of the log-only `session/title` event. */ +export interface SessionTitleEventData { + /** Normalized non-empty title text. */ + readonly title: string; + /** Exact human `user/message` seqs used to derive this title; empty for an explicit user rename. */ + readonly messageSeqs: number[]; + /** Whether the built-in fallback, a registered provider, or the user supplied the title. */ + readonly source: SessionTitleSource; +} +/** Latest folded title plus the title event's durable envelope facts. */ +export interface SessionTitleSnapshot extends SessionTitleEventData { + /** Seq of the latest `session/title` event. */ + readonly eventSeq: number; + /** Timestamp of the latest `session/title` event. */ + readonly updatedAt: number; +} +/** Required deterministic fallback and accepted-title limits. */ +export interface Config { + /** Maximum whitespace-delimited words in the built-in fallback. */ + readonly fallbackMaxWords: number; + /** Maximum UTF-8 bytes in the built-in fallback. */ + readonly fallbackMaxBytes: number; + /** Maximum UTF-8 bytes in any accepted title. */ + readonly maxTitleBytes: number; +} +declare module '@deepseek-ai/cordis' { + interface Context { + sessionTitle: SessionTitleService; + } +} +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * Latest-wins session title snapshot. Log-only: it never enters the model + * surface or derived history. + */ + 'session/title': SessionTitleEventData; + } +} +/** + * Rejection of an explicit user title whose text normalizes to empty — the + * one {@link SessionTitleService.rename} failure that blames the input. + * Callers translating rename failures onto a wire (`title-invalid`) narrow on + * this class; liveness and disposal failures stay plain `Error`s. + */ +export declare class SessionTitleInvalidError extends Error { + readonly name = "SessionTitleInvalidError"; +} +/** One eligible human text message exposed to title providers. */ +export interface SessionTitleUserMessage { + /** Source `user/message` event seq. */ + readonly seq: number; + /** Exact concatenated text-block content. */ + readonly text: string; +} +/** Automatic generation cadence owned by a registered provider. */ +export type SessionTitleAutomaticMode = 'first-prompt' | 'all-prompts'; +/** Immutable input supplied to one title-provider call. */ +export interface SessionTitleProviderRequest { + /** Live session being titled. */ + readonly session: Session; + /** All eligible human messages through this generation revision. */ + readonly messages: readonly SessionTitleUserMessage[]; + /** Exact current logged main-request route, when one has been recorded. */ + readonly route?: SessionTitleModelProvenance; + /** Cancellation for supersession, disposal, timeout composition, or the explicit caller. */ + readonly signal: AbortSignal; +} +/** Provider output before service-owned normalization and log acceptance. */ +export interface SessionTitleProviderResult { + /** Proposed title text. */ + readonly title: string; + /** Exact seqs from `request.messages` used by this result. */ + readonly messageSeqs: readonly number[]; + /** Auxiliary LLM route, when generation used a model. */ + readonly model?: SessionTitleModelProvenance; +} +/** One optional asynchronous title implementation registered with the service. */ +export interface SessionTitleProvider { + /** Stable id of the provider recorded with the title. */ + readonly id: SessionTitleProviderId; + /** When new human prompts start automatic generation. */ + readonly automatic: SessionTitleAutomaticMode; + /** + * Produce one title revision. + * @param request - message snapshot, current route, session, and cancellation. + * @returns proposed title plus exact input seqs and the optional provider/model route used to generate it. + */ + generate(request: SessionTitleProviderRequest): Promise; +} +/** + * Collect human text-bearing user messages in log order. + * @param events - session log or persisted replay. + * @param throughSeq - optional inclusive event boundary. + * @returns eligible messages with exact source seqs. + */ +export declare function collectSessionTitleMessages(events: readonly SessionEvent[], throughSeq?: number): SessionTitleUserMessage[]; +/** + * Fold the latest logged title without consulting mutable metadata. + * @param events - live or persisted session log. + * @returns the latest immutable title snapshot, or `undefined`. + */ +export declare function foldSessionTitle(events: readonly SessionEvent[]): SessionTitleSnapshot | undefined; +/** Log-backed title fold plus asynchronous fallback generation. */ +export declare class SessionTitleService extends Service { + static inject: string[]; + static Config: z; + private readonly config; + private readonly ownerFiber; + private registration; + private readonly work; + private readonly lifetime; + private readonly inFlight; + constructor(ctx: Context, config: Config); + /** + * Read the latest folded title from one live or replayed session. + * @param session - session whose log is the title source of truth. + * @returns latest title snapshot, or `undefined` before eligible input. + */ + get(session: Session): SessionTitleSnapshot | undefined; + /** + * Accept an explicit user title. Appends a `session/title` event with the + * `user` source, which pins the title: in-flight automatic generation is + * superseded and later user messages schedule none (an explicit + * {@link SessionTitleService.refresh} remains the deliberate unpin). + * @param session - exact live session to rename. + * @param title - raw user input; normalized before acceptance. + * @returns the accepted title snapshot. + * @throws {SessionTitleInvalidError} when the title normalizes to empty. + * @throws {Error} when the session is not live or the service is disposed. + */ + rename(session: Session, title: string): SessionTitleSnapshot; + /** + * Explicitly retry the registered provider, or materialize the built-in + * fallback when no provider is registered. + * @param session - exact live session to refresh. + * @param signal - optional caller cancellation. + * @returns latest accepted title, or `undefined` when no eligible text exists. + */ + refresh(session: Session, signal?: AbortSignal): Promise; + /** + * Register the sole optional title provider. Disposal aborts its pending and + * active work before another provider may register. + * @param provider - provider identity, cadence, and generation function. + * @returns exact Cordis effect disposer, which settles after active calls quiesce. + */ + register(provider: SessionTitleProvider): () => Promise; + /** Schedule fallback creation and any provider cadence for one eligible event. */ + private onUserMessage; + /** Start pending automatic work only after its exact main-request route is logged. */ + private onRequestHeader; + /** Start unchanged-route work from the marked loop request after its header fold is current. */ + private onMainRequest; + /** Consume one pending revision and schedule its non-blocking provider call. */ + private startPending; + /** Start one tracked provider call after publishing its active revision. */ + private startProvider; + /** Execute and accept one current provider revision. */ + private runProvider; + /** Validate and normalize provider output against the supplied message snapshot. */ + private validateResult; + /** Fail a completion whose provider, revision, session, or signal is stale. */ + private assertCurrent; + /** Create and publish an active provider call from one fixed revision. */ + private activate; + /** Abort older active work and reserve the next session-local revision. */ + private supersede; + /** Return mutable work state for one session. */ + private stateFor; + /** Queue detached service work and retain it through service disposal. */ + private defer; + /** Retain one promise until settlement for service and optional provider teardown. */ + private track; + /** Await every current and settling promise in one lifecycle registry. */ + private drain; + /** Whether the owning plugin fiber can still start or commit title work. */ + private serviceActive; + /** Reject work once the owning plugin fiber has begun unloading. */ + private assertServiceActive; + /** Reject malformed provider registrations before publishing an effect. */ + private validateProvider; + /** + * Derive and append the deterministic fallback title over whatever stands + * (the refresh unpin path: overwriting a pinned user title is the point). + * Synchronous on purpose — no await may separate derivation from append, so + * it needs neither ensureFallback's in-flight dedup nor its liveness + * re-check. An underivable fallback (empty after the caps) appends nothing. + */ + private appendFallback; + /** Create the first deterministic fallback if the session still lacks a title. */ + private ensureFallback; +} +export default SessionTitleService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.js new file mode 100644 index 0000000..f34245e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.js @@ -0,0 +1,601 @@ +/** + * Log-backed session title service, deterministic fallback, and provider contract. + * @module @deepseek-ai/dsh-session-title + */ +import { Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { z as zod } from 'zod'; +import { assertNever, deepFreeze, isAgentLoopRequest } from '@deepseek-ai/dsh-llm'; +import { fallbackSessionTitle, normalizeSessionTitle } from "./normalize.js"; +export { fallbackSessionTitle, normalizeSessionTitle, truncateTitleUtf8 } from "./normalize.js"; +/** + * Brand a raw provider id. + * @param id - stable non-empty provider identifier supplied by a plugin. + * @returns the same string with the session-title provider brand. + */ +export function SessionTitleProviderId(id) { + return id; +} +/** + * Rejection of an explicit user title whose text normalizes to empty — the + * one {@link SessionTitleService.rename} failure that blames the input. + * Callers translating rename failures onto a wire (`title-invalid`) narrow on + * this class; liveness and disposal failures stay plain `Error`s. + */ +export class SessionTitleInvalidError extends Error { + name = 'SessionTitleInvalidError'; +} +/** + * Collect human text-bearing user messages in log order. + * @param events - session log or persisted replay. + * @param throughSeq - optional inclusive event boundary. + * @returns eligible messages with exact source seqs. + */ +export function collectSessionTitleMessages(events, throughSeq) { + const messages = []; + for (const event of events) { + if (throughSeq !== undefined && event.seq > throughSeq) + break; + if (event.type !== 'user/message' || event.data.source.kind !== 'user') + continue; + const content = event.data.content; + const text = content + .filter((block) => block.type === 'text') + .map(block => block.text) + .join('\n'); + if (normalizeSessionTitle(text, Number.MAX_SAFE_INTEGER).length === 0) + continue; + messages.push({ seq: event.seq, text }); + } + return messages; +} +/** + * Fold the latest logged title without consulting mutable metadata. + * @param events - live or persisted session log. + * @returns the latest immutable title snapshot, or `undefined`. + */ +export function foldSessionTitle(events) { + const event = events.findLast(item => item.type === 'session/title'); + if (event === undefined) + return undefined; + return deepFreeze({ + title: event.data.title, + messageSeqs: [...event.data.messageSeqs], + source: copySessionTitleSource(event.data.source), + eventSeq: event.seq, + updatedAt: event.time, + }); +} +/** Defensive copy of a logged title source (the snapshot must not alias log-owned objects). */ +function copySessionTitleSource(source) { + switch (source.kind) { + case 'fallback': return { kind: 'fallback' }; + case 'provider': return { + kind: 'provider', + provider: source.provider, + ...(source.model === undefined ? {} : { model: { ...source.model } }), + }; + case 'user': return { kind: 'user' }; + /* v8 ignore next -- closed-union exhaustiveness guard */ + default: return assertNever(source, 'SessionTitleSource'); + } +} +/** Validate one positive integer configuration field. */ +function assertPositiveInteger(name, value) { + if (!Number.isInteger(value) || value <= 0) { + throw new Error(`session-title: ${name} must be a positive integer`); + } +} +/** Log-backed title fold plus asynchronous fallback generation. */ +export class SessionTitleService extends Service { + static inject = ['sessions']; + static Config = z.object({ + fallbackMaxWords: z.number().step(1).min(1).required(), + fallbackMaxBytes: z.number().step(1).min(1).required(), + maxTitleBytes: z.number().step(1).min(1).required(), + }); + config; + ownerFiber; + registration; + work = new Map(); + lifetime = new AbortController(); + inFlight = new Set(); + constructor(ctx, config) { + super(ctx, 'sessionTitle'); + this.ownerFiber = ctx.fiber; + const candidate = config; + if (candidate === null || typeof candidate !== 'object') { + throw new Error('session-title: configuration is required'); + } + const value = candidate; + assertPositiveInteger('fallbackMaxWords', value.fallbackMaxWords); + assertPositiveInteger('fallbackMaxBytes', value.fallbackMaxBytes); + assertPositiveInteger('maxTitleBytes', value.maxTitleBytes); + if (value.fallbackMaxBytes > value.maxTitleBytes) { + throw new Error('session-title: fallbackMaxBytes must not exceed maxTitleBytes'); + } + this.config = deepFreeze({ ...value }); + ctx.effect(() => async () => { + this.lifetime.abort(new Error('session-title service disposed')); + if (this.registration !== undefined) + this.registration.closing = true; + this.registration = undefined; + for (const state of this.work.values()) { + delete state.pending; + state.active?.controller.abort(new Error('session-title service disposed')); + } + await this.drain(this.inFlight); + this.work.clear(); + }, 'sessionTitle lifecycle'); + // The title projection unit: pure last-wins fold of session/title events + // (the same events foldSessionTitle consumes), serving the plain title + // string clients list rows read. The unit child activates only when a + // projection registry is composed (headless assemblies stay unaffected). + ctx.inject(['sessionProjections'], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: 'title', + schema: zod.union([zod.string().min(1), zod.null()]), + init: () => null, + apply: (state, event) => (event.type === 'session/title' ? event.data.title : state), + view: state => state, + stateVersion: 1, + }); + }); + ctx.on('session/event', (session, event) => { + switch (event.type) { + case 'user/message': + this.onUserMessage(session, event); + break; + case 'request/header': + this.onRequestHeader(session, event); + break; + default: + break; + } + }); + ctx.on('llm/stream', (options, next) => { + this.onMainRequest(options); + return next(); + }, { global: true, prepend: true }); + ctx.on('session/disposed', (session) => { + const state = this.work.get(session); + if (state === undefined) + return; + state.active?.controller.abort(new Error('session disposed during title generation')); + this.work.delete(session); + }); + } + /** + * Read the latest folded title from one live or replayed session. + * @param session - session whose log is the title source of truth. + * @returns latest title snapshot, or `undefined` before eligible input. + */ + get(session) { + return foldSessionTitle(session.events); + } + /** + * Accept an explicit user title. Appends a `session/title` event with the + * `user` source, which pins the title: in-flight automatic generation is + * superseded and later user messages schedule none (an explicit + * {@link SessionTitleService.refresh} remains the deliberate unpin). + * @param session - exact live session to rename. + * @param title - raw user input; normalized before acceptance. + * @returns the accepted title snapshot. + * @throws {SessionTitleInvalidError} when the title normalizes to empty. + * @throws {Error} when the session is not live or the service is disposed. + */ + rename(session, title) { + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) { + throw new Error(`session "${session.id}" is not live in this store`); + } + const normalized = normalizeSessionTitle(title, this.config.maxTitleBytes); + if (normalized.length === 0) { + throw new SessionTitleInvalidError('session title must contain visible characters'); + } + const state = this.stateFor(session); + this.supersede(state, 'user rename superseded automatic title generation'); + session.append('session/title', { + title: normalized, + messageSeqs: [], + source: { kind: 'user' }, + }); + const snapshot = this.get(session); + /* v8 ignore next -- unreachable: the append above just committed a session/title event. */ + if (snapshot === undefined) + throw new Error('renamed title failed to fold'); + return snapshot; + } + /** + * Explicitly retry the registered provider, or materialize the built-in + * fallback when no provider is registered. + * @param session - exact live session to refresh. + * @param signal - optional caller cancellation. + * @returns latest accepted title, or `undefined` when no eligible text exists. + */ + async refresh(session, signal) { + signal?.throwIfAborted(); + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) { + throw new Error(`session "${session.id}" is not live in this store`); + } + const registration = this.registration; + const messages = collectSessionTitleMessages(session.events); + const latest = messages.at(-1); + if (registration === undefined || registration.closing || latest === undefined) { + // Explicit refresh is the unpin even without a provider: a standing + // user title must not short-circuit ensureFallback into a no-op, so + // re-derive and append the fallback over it when one is derivable. + const current = this.get(session); + const [first] = messages; + if (current?.source.kind === 'user' && first !== undefined) { + this.appendFallback(session, first); + signal?.throwIfAborted(); + return this.get(session); + } + const fallback = await this.ensureFallback(session); + signal?.throwIfAborted(); + return fallback; + } + const state = this.stateFor(session); + const revision = this.supersede(state, 'explicit title refresh superseded older generation'); + const work = this.activate({ + registration, + revision, + throughSeq: latest.seq, + }, state, signal); + const config = session.requestHeader()?.config; + const route = config === undefined ? undefined : { provider: config.provider, model: config.model }; + return this.startProvider(session, work, route); + } + /** + * Register the sole optional title provider. Disposal aborts its pending and + * active work before another provider may register. + * @param provider - provider identity, cadence, and generation function. + * @returns exact Cordis effect disposer, which settles after active calls quiesce. + */ + register(provider) { + this.validateProvider(provider); + if (this.registration !== undefined) { + throw new Error(`session-title provider "${this.registration.provider.id}" is already registered`); + } + const registration = { + provider, + active: new Set(), + closing: false, + }; + const dispose = this.ctx.effect(function* () { + this.registration = registration; + yield async () => { + registration.closing = true; + for (const state of this.work.values()) { + if (state.pending?.registration === registration) + delete state.pending; + if (state.active?.registration === registration) { + state.active.controller.abort(new Error(`session-title provider "${provider.id}" was disposed`)); + } + } + await this.drain(registration.active); + if (this.registration === registration) + this.registration = undefined; + }; + }.bind(this), 'sessionTitle.register()'); + return dispose; + } + /** Schedule fallback creation and any provider cadence for one eligible event. */ + onUserMessage(session, event) { + if (!this.serviceActive()) + return; + if (event.data.source.kind !== 'user' || collectSessionTitleMessages([event]).length === 0) + return; + // A user rename pins the title: no automatic revision may override it. + if (this.get(session)?.source.kind === 'user') + return; + const registration = this.registration; + if (registration !== undefined && !registration.closing) { + const messages = collectSessionTitleMessages(session.events, event.seq); + const shouldSchedule = registration.provider.automatic === 'all-prompts' + || (session.header.parentSession === undefined && messages.length === 1 && this.get(session) === undefined); + if (shouldSchedule) { + const state = this.stateFor(session); + const revision = this.supersede(state, 'newer user message superseded title generation'); + state.pending = { registration, revision, throughSeq: event.seq }; + } + } + this.defer(async () => { + try { + await this.ensureFallback(session); + } + catch (error) { + if (!this.serviceActive()) + return; + this.ctx.logger.warn(`session "${session.id}": fallback title update failed: ${String(error)}`); + } + }); + } + /** Start pending automatic work only after its exact main-request route is logged. */ + onRequestHeader(session, event) { + if (!this.serviceActive()) + return; + const state = this.work.get(session); + const pending = state?.pending; + if (state === undefined || pending === undefined || pending.throughSeq >= event.seq) + return; + const route = { + provider: event.data.header.config.provider, + model: event.data.header.config.model, + }; + this.startPending(session, state, pending, route); + } + /** Start unchanged-route work from the marked loop request after its header fold is current. */ + onMainRequest(options) { + if (!this.serviceActive() || options.sessionId === undefined || !isAgentLoopRequest(options)) + return; + const session = this.ctx.sessions.get(options.sessionId); + const state = session === undefined ? undefined : this.work.get(session); + const pending = state?.pending; + if (session === undefined || state === undefined || pending === undefined) + return; + const boundary = session.events.findLast(event => event.type === 'step/start' || event.type === 'step/end'); + const route = session.requestHeader()?.config; + if (boundary?.type !== 'step/start' + || boundary.seq <= pending.throughSeq + || route?.provider !== options.provider + || route.model !== options.model) + return; + this.startPending(session, state, pending, { provider: options.provider, model: options.model }); + } + /** Consume one pending revision and schedule its non-blocking provider call. */ + startPending(session, state, pending, route) { + delete state.pending; + this.defer(async () => { + if (this.registration !== pending.registration + || pending.registration.closing + || this.work.get(session) !== state + || state.revision !== pending.revision) + return; + const work = this.activate(pending, state); + try { + await this.startProvider(session, work, route); + } + catch (error) { + if (work.signal.aborted || !this.serviceActive()) + return; + this.ctx.logger.warn(`session "${session.id}": automatic title generation failed: ${String(error)}`); + } + }); + } + /** Start one tracked provider call after publishing its active revision. */ + startProvider(session, work, route) { + const run = Promise.resolve().then(() => this.runProvider(session, work, route)); + return this.track(run, work.registration); + } + /** Execute and accept one current provider revision. */ + async runProvider(session, work, route) { + try { + this.assertCurrent(session, work); + await this.ensureFallback(session); + this.assertCurrent(session, work); + const messages = collectSessionTitleMessages(session.events, work.throughSeq); + const result = await work.registration.provider.generate({ + session, + messages, + ...route === undefined ? {} : { route }, + signal: work.signal, + }); + this.assertCurrent(session, work); + const accepted = this.validateResult(result, messages); + session.append('session/title', { + title: accepted.title, + messageSeqs: [...accepted.messageSeqs], + source: { + kind: 'provider', + provider: work.registration.provider.id, + ...accepted.model === undefined ? {} : { model: accepted.model }, + }, + }); + return this.get(session); + } + finally { + const state = this.work.get(session); + if (state?.active === work) + delete state.active; + } + } + /** Validate and normalize provider output against the supplied message snapshot. */ + validateResult(result, messages) { + if (result === null || typeof result !== 'object') { + throw new Error('session-title provider returned an invalid result'); + } + const candidate = result; + if (typeof candidate.title !== 'string') + throw new Error('session-title provider title must be a string'); + const title = normalizeSessionTitle(candidate.title, this.config.maxTitleBytes); + if (title.length === 0) + throw new Error('session-title provider returned an empty title'); + if (!Array.isArray(candidate.messageSeqs) || candidate.messageSeqs.length === 0) { + throw new Error('session-title provider must identify at least one source message seq'); + } + const messageSeqs = []; + const order = new Map(messages.map((message, index) => [message.seq, index])); + let previous = -1; + for (const seq of candidate.messageSeqs) { + if (typeof seq !== 'number') { + throw new Error('session-title provider messageSeqs must be unique, ordered seqs from the request'); + } + const index = order.get(seq); + if (!Number.isSafeInteger(seq) || seq < 0 || index === undefined || index <= previous) { + throw new Error('session-title provider messageSeqs must be unique, ordered seqs from the request'); + } + messageSeqs.push(seq); + previous = index; + } + const modelCandidate = candidate.model; + let model; + if (modelCandidate !== undefined) { + if (modelCandidate === null || typeof modelCandidate !== 'object') { + throw new Error('session-title provider result model must contain non-empty provider and model strings'); + } + const record = modelCandidate; + if (typeof record.provider !== 'string' || record.provider.length === 0 + || typeof record.model !== 'string' || record.model.length === 0) { + throw new Error('session-title provider result model must contain non-empty provider and model strings'); + } + model = { provider: record.provider, model: record.model }; + } + return { + title, + messageSeqs, + ...(model === undefined ? {} : { model }), + }; + } + /** Fail a completion whose provider, revision, session, or signal is stale. */ + assertCurrent(session, work) { + this.assertServiceActive(); + work.signal.throwIfAborted(); + const state = this.work.get(session); + /* v8 ignore next -- every supported supersession, provider disposal, and session disposal aborts + * the work signal before changing this state. */ + if (this.registration !== work.registration + || state?.active !== work + || state.revision !== work.revision + || this.ctx.sessions.get(session.id) !== session) { + throw new Error('session title generation state changed without cancellation'); + } + } + /** Create and publish an active provider call from one fixed revision. */ + activate(pending, state, upstream) { + const controller = new AbortController(); + const signal = upstream === undefined + ? AbortSignal.any([controller.signal, this.lifetime.signal]) + : AbortSignal.any([controller.signal, this.lifetime.signal, upstream]); + const work = { ...pending, controller, signal }; + state.active = work; + return work; + } + /** Abort older active work and reserve the next session-local revision. */ + supersede(state, reason) { + state.active?.controller.abort(new Error(reason)); + delete state.pending; + state.revision += 1; + return state.revision; + } + /** Return mutable work state for one session. */ + stateFor(session) { + let state = this.work.get(session); + if (state === undefined) { + state = { revision: 0 }; + this.work.set(session, state); + } + return state; + } + /** Queue detached service work and retain it through service disposal. */ + defer(task) { + const run = Promise.resolve().then(async () => { + if (!this.serviceActive()) + return; + await task(); + }); + void this.track(run); + } + /** Retain one promise until settlement for service and optional provider teardown. */ + track(run, registration) { + this.inFlight.add(run); + registration?.active.add(run); + const settled = () => { + this.inFlight.delete(run); + registration?.active.delete(run); + }; + void run.then(settled, settled); + return run; + } + /** Await every current and settling promise in one lifecycle registry. */ + async drain(active) { + while (active.size > 0) + await Promise.allSettled([...active]); + } + /** Whether the owning plugin fiber can still start or commit title work. */ + serviceActive() { + return !this.lifetime.signal.aborted + && this.ownerFiber.uid !== null + && this.ownerFiber.state === 2 /* FiberState.ACTIVE */; + } + /** Reject work once the owning plugin fiber has begun unloading. */ + assertServiceActive() { + if (!this.serviceActive()) + throw new Error('session-title service disposed'); + } + /** Reject malformed provider registrations before publishing an effect. */ + validateProvider(provider) { + if (provider === null || typeof provider !== 'object') { + throw new Error('session-title provider must be an object'); + } + const candidate = provider; + if (typeof candidate.id !== 'string' || candidate.id.length === 0) { + throw new Error('session-title provider id must be a non-empty string'); + } + if (candidate.automatic !== 'first-prompt' && candidate.automatic !== 'all-prompts') { + throw new Error('session-title provider automatic mode is invalid'); + } + if (typeof candidate.generate !== 'function') { + throw new Error(`session-title provider "${candidate.id}" requires generate()`); + } + } + /** + * Derive and append the deterministic fallback title over whatever stands + * (the refresh unpin path: overwriting a pinned user title is the point). + * Synchronous on purpose — no await may separate derivation from append, so + * it needs neither ensureFallback's in-flight dedup nor its liveness + * re-check. An underivable fallback (empty after the caps) appends nothing. + */ + appendFallback(session, first) { + const title = fallbackSessionTitle(first.text, this.config.fallbackMaxWords, this.config.fallbackMaxBytes); + if (title.length === 0) + return; + session.append('session/title', { + title, + messageSeqs: [first.seq], + source: { kind: 'fallback' }, + }); + } + /** Create the first deterministic fallback if the session still lacks a title. */ + async ensureFallback(session) { + this.assertServiceActive(); + const current = this.get(session); + if (current !== undefined) + return current; + const [first] = collectSessionTitleMessages(session.events); + if (first === undefined) + return undefined; + const title = fallbackSessionTitle(first.text, this.config.fallbackMaxWords, this.config.fallbackMaxBytes); + if (title.length === 0) + return undefined; + const state = this.stateFor(session); + if (state.fallback !== undefined) + return state.fallback; + const fallback = Promise.resolve().then(() => { + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) { + throw new Error(`session "${session.id}" is not live in this store`); + } + const accepted = this.get(session); + if (accepted !== undefined) + return accepted; + session.append('session/title', { + title, + messageSeqs: [first.seq], + source: { kind: 'fallback' }, + }); + return this.get(session); + }); + state.fallback = fallback; + try { + return await fallback; + } + finally { + delete state.fallback; + } + } +} +export default SessionTitleService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.d.ts new file mode 100644 index 0000000..bfebd4b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-title`. + * @module @deepseek-ai/dsh-session-title/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-title-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.js new file mode 100644 index 0000000..12980c1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.js @@ -0,0 +1,41 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-title`. + * @module @deepseek-ai/dsh-session-title/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-session-title'; +/** Cordis companion plugin name. */ +export const name = 'session-title-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * Durable title-source invariant: an automatic title always cites at + * least one human `user/message` seq, and an explicit user rename cites none + * — `messageSeqs` is empty iff `source.kind` is `user`. Provider revisions + * are validated by the service before their append; this checks the durable + * relationship every appended `session/title` event must keep, whichever + * writer produced it. + */ +const install = Object.assign((ctx, fail) => { + // internal/dispatch interception rejects the append before publication + // (the session/event listener would only observe the already-committed log). + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') + return; + const [, event] = args; + if (event.type !== 'session/title') + return; + const { source, messageSeqs } = event.data; + if ((messageSeqs.length === 0) !== (source.kind === 'user')) { + const requirement = source.kind === 'user' ? 'cite no message seqs' : 'cite at least one message seq'; + fail(`session/title event ${String(event.seq)} with source "${source.kind}" must ${requirement}; got ${String(messageSeqs.length)}`); + } + }, { global: true }); +}, { inject: ['sessions'] }); +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.d.ts new file mode 100644 index 0000000..ea2631e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.d.ts @@ -0,0 +1,24 @@ +/** Title text normalization and UTF-8-safe truncation. */ +/** + * Truncate a string to a UTF-8 byte budget without splitting a Unicode code point. + * @param input - normalized title text. + * @param maxBytes - positive UTF-8 byte budget. + * @returns the longest leading code-point prefix within the budget. + */ +export declare function truncateTitleUtf8(input: string, maxBytes: number): string; +/** + * Normalize one accepted session title and enforce its UTF-8 byte budget. + * @param input - untrusted title text. + * @param maxBytes - positive maximum encoded size. + * @returns a terminal-safe one-line title, possibly empty after sanitization. + */ +export declare function normalizeSessionTitle(input: string, maxBytes: number): string; +/** + * Derive the deterministic first-prompt fallback. + * @param input - text from the first eligible human message. + * @param maxWords - positive whitespace-delimited word cap. + * @param maxBytes - positive UTF-8 byte cap. + * @returns the normalized leading words within both limits. + */ +export declare function fallbackSessionTitle(input: string, maxWords: number, maxBytes: number): string; +//# sourceMappingURL=normalize.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.js new file mode 100644 index 0000000..8c7f9f5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.js @@ -0,0 +1,71 @@ +/** Title text normalization and UTF-8-safe truncation. */ +/** Operating-system-command escape sequences, including unterminated tails. */ +const OSC_SEQUENCE = /(?:\u001B\]|\u009D)(?:(?!\u0007|\u001B\\)[\s\S])*(?:\u0007|\u001B\\|$)/gu; +/** Control-sequence-introducer escapes such as SGR color codes. */ +const CSI_SEQUENCE = /(?:\u001B\[|\u009B)[0-?]*[ -/]*[@-~]/gu; +/** Remaining two-byte ESC control sequences. */ +const ESC_SEQUENCE = /\u001B[@-_]/gu; +/** Non-whitespace C0/C1 control characters. */ +const CONTROL_CHARACTER = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/gu; +/** Directional and invisible controls that can make a displayed title deceptive. */ +const DIRECTIONAL_CONTROL = /[\u200B\u200E\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF]/gu; +/** Reject an invalid public text limit. */ +function assertPositiveInteger(name, value) { + if (!Number.isInteger(value) || value <= 0) { + throw new Error(`${name} must be a positive integer`); + } +} +/** Remove controls and produce one trimmed, whitespace-normalized line. */ +function cleanTitleText(input) { + return input + .replace(OSC_SEQUENCE, '') + .replace(CSI_SEQUENCE, '') + .replace(ESC_SEQUENCE, '') + .replace(CONTROL_CHARACTER, '') + .replace(DIRECTIONAL_CONTROL, '') + .replace(/\s+/gu, ' ') + .trim(); +} +/** + * Truncate a string to a UTF-8 byte budget without splitting a Unicode code point. + * @param input - normalized title text. + * @param maxBytes - positive UTF-8 byte budget. + * @returns the longest leading code-point prefix within the budget. + */ +export function truncateTitleUtf8(input, maxBytes) { + assertPositiveInteger('maxBytes', maxBytes); + if (Buffer.byteLength(input, 'utf8') <= maxBytes) + return input; + let used = 0; + let output = ''; + for (const character of input) { + const bytes = Buffer.byteLength(character, 'utf8'); + if (used + bytes > maxBytes) + break; + output += character; + used += bytes; + } + return output; +} +/** + * Normalize one accepted session title and enforce its UTF-8 byte budget. + * @param input - untrusted title text. + * @param maxBytes - positive maximum encoded size. + * @returns a terminal-safe one-line title, possibly empty after sanitization. + */ +export function normalizeSessionTitle(input, maxBytes) { + return truncateTitleUtf8(cleanTitleText(input), maxBytes).trimEnd(); +} +/** + * Derive the deterministic first-prompt fallback. + * @param input - text from the first eligible human message. + * @param maxWords - positive whitespace-delimited word cap. + * @param maxBytes - positive UTF-8 byte cap. + * @returns the normalized leading words within both limits. + */ +export function fallbackSessionTitle(input, maxWords, maxBytes) { + assertPositiveInteger('maxWords', maxWords); + const words = cleanTitleText(input).split(' ').filter(Boolean).slice(0, maxWords); + return truncateTitleUtf8(words.join(' '), maxBytes).trimEnd(); +} +//# sourceMappingURL=normalize.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.d.ts new file mode 100644 index 0000000..6d0f49d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.d.ts @@ -0,0 +1,21 @@ +/** + * Pure types of the title domain: the ONE home of the `title` projection-key + * declaration, free of this package's host-side value imports (cordis + * service, schemastery, the llm seam). Two namespace projections serve it — + * `./types` for host consumers, `./client/types` (the browser half-entry's + * re-export) for client aggregates — with zero content duplication. + * + * @module @deepseek-ai/dsh-session-title/types + */ +export {}; +declare module '@deepseek-ai/dsh-session-projection/types' { + interface SessionProjectionMap { + /** + * The session's current normalized title — the latest `session/title` + * event's text (last-wins), or `null` before the first title lands. A + * plain string: the shape the client list rows consume. + */ + title: string | null; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.js new file mode 100644 index 0000000..c0a79a3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.js @@ -0,0 +1,11 @@ +/** + * Pure types of the title domain: the ONE home of the `title` projection-key + * declaration, free of this package's host-side value imports (cordis + * service, schemastery, the llm seam). Two namespace projections serve it — + * `./types` for host consumers, `./client/types` (the browser half-entry's + * re-export) for client aggregates — with zero content duplication. + * + * @module @deepseek-ai/dsh-session-title/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/package.json new file mode 100644 index 0000000..abbfef1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/dsh-session-title/package.json @@ -0,0 +1,65 @@ +{ + "name": "@deepseek-ai/dsh-session-title", + "description": "Log-backed session title service and provider registry for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session/session-title" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./client": { + "types": "./lib/types/client.d.ts", + "default": "./lib/types/client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence-sqlite": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.6_d1255cd1c1cc892be642dda517b65e3c/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..ed04634 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.i18n.yaml new file mode 100644 index 0000000..bbe1cfc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/session/session-title/README.md +README.md: e923bd9700180214f235c4971d4b020565bfee43 +README.zh.md: 8e84ac27d9f1509c8530b838eeb5eb2216d87199 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.md new file mode 100644 index 0000000..e923bd9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.md @@ -0,0 +1,55 @@ +# @deepseek-ai/dsh-session-title + +English | [中文](README.zh.md) + +Log-backed session titles with an immediate deterministic fallback and one optional asynchronous provider. Every accepted revision is a log-only `session/title` event; `foldSessionTitle()` and `ctx.sessionTitle.get()` select the latest event and return its event seq and timestamp. + +Only text blocks from human `user/message` events are eligible. The first eligible prompt schedules a fallback from its first words within the configured UTF-8 byte limit. Whitespace is normalized, terminal control sequences are removed, and truncation never splits a code point. Empty and non-text prompts wait for later eligible input. + +## Service: `SessionTitleService` (ctx key: `sessionTitle`) + +- `get(session)` folds the latest accepted title from a live or replayed log. +- `refresh(session, signal?)` materializes the fallback when needed, then explicitly runs the registered provider over the current eligible messages. Provider errors and caller cancellation reject; cancellation does not roll back an already accepted fallback event. +- `rename(session, title)` accepts an explicit user title synchronously: it normalizes the text, supersedes in-flight automatic work, and appends a `session/title` event with the `user` source. A user-sourced latest title pins the session — later user messages schedule no automatic revision; an explicit `refresh` remains the deliberate unpin. +- `register(provider)` installs the sole optional provider and returns its awaitable Cordis effect disposer. A second registration throws immediately; disposal aborts pending and active calls, waits for their settlement, and only then permits another provider to register. + +Automatic work never delays the main agent response. A provider starts only after a marked loop-built request's exact route matches the current logged `request/header`, including when the unchanged header needs no new snapshot. Its late completion appends a standalone log-only event directly through `Session` without opening a turn. Persistence observes that event eagerly and drains on ordinary lifecycle checkpoints; title publication itself does not force a flush. Automatic failures warn and retain the latest title. New all-message revisions, provider disposal, session disposal, and explicit refresh abort older work, and a stale completion cannot append. Concurrent explicit refreshes reserve their revision before provider work, while overlapping automatic and explicit fallback requests share one session-local in-flight append. The service and bundled model provider each append their own literal event type, so no generic title-write marker, cast, or settlement queue is needed. Service teardown cancels queued work and drains calls that ignore cancellation before unloading completes. + +Forks inherit title events in their seed unchanged. The first-prompt cadence does not automatically retitle a child; the all-messages cadence may append a new revision after the child receives a later human prompt. + +## Configuration + +All limits are required; the library supplies no defaults. + +| Key | Contract | +|---|---| +| `fallbackMaxWords` | Positive maximum whitespace-delimited words in the deterministic fallback. | +| `fallbackMaxBytes` | Positive maximum UTF-8 bytes in the fallback; must not exceed `maxTitleBytes`. | +| `maxTitleBytes` | Positive maximum UTF-8 bytes accepted from any source. | + +## Provider contract + +A provider supplies a branded stable id, automatic mode (`first-prompt` or `all-prompts`), and `generate(request)`. The request carries the live session, all eligible messages through one fixed revision, the current logged main-request route when available, and cancellation. The result identifies a non-empty title, unique ordered source-message seqs from that request, and the optional provider/model route used to generate it. The service normalizes and validates the result before it becomes durable. + +See the [session-title data structures](../../../docs/subsystems/session-title.md) and [implemented decision](../../../.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md). + +## Model Experience + +### Session title state + +#### What the model sees + +Nothing. `session/title` is log-only and never enters the session surface, `deriveMessages()`, system prompt, tool schemas, or request prefix. + +#### Token effect + +The fallback and accepted provider revisions add zero tokens to the main agent request. An optional provider's separate auxiliary request is documented by that provider package. + +#### KV Cache effect + +None for the main request; title events do not change its reconstructed content or cache key. + +## Known Limitations and Deferred Work + +- Title deletion (unpinning back to automatic titles without an explicit `refresh`), search, and list indexing are outside this service. +- The provider registry deliberately accepts at most one implementation, so a deployment cannot compose competing title strategies without writing one provider that owns their precedence. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.zh.md new file mode 100644 index 0000000..8e84ac2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/README.zh.md @@ -0,0 +1,55 @@ +# @deepseek-ai/dsh-session-title + +[English](README.md) | 中文 + +由日志支持的会话标题,提供即时确定性回退与一个可选异步提供方。每次已接受的修订都是仅写入日志的 `session/title` 事件;`foldSessionTitle()` 与 `ctx.sessionTitle.get()` 会选择最新事件,并返回其事件 seq 和时间戳。 + +只有用户 `user/message` 事件中的文本块符合条件。第一条符合条件的提示词会安排回退,从其开头若干词生成标题,并受所配置 UTF-8 字节上限约束。系统会规范化空白、移除终端控制序列,且截断绝不会切断码点。空提示词和非文本提示词会等待后续符合条件的输入。 + +## 服务:`SessionTitleService`(ctx 键:`sessionTitle`) + +- `get(session)` 从活跃或回放日志折叠最新已接受标题。 +- `refresh(session, signal?)` 在需要时物化回退,然后显式运行已注册提供方,处理当前符合条件的消息。提供方错误或调用方取消都会导致返回的 Promise 被拒绝;取消不会回滚已接受的回退事件。 +- `rename(session, title)` 同步接受用户显式标题:规范化文本、取代在途自动工作,并追加一条 `user` 来源的 `session/title` 事件。用户来源的最新标题会钉住该会话——后续用户消息不再安排自动修订;显式 `refresh` 仍是有意的解钉手段。 +- `register(provider)` 安装唯一可选提供方,并返回可等待的 Cordis effect disposer。第二次注册会立即抛出;对提供方执行 dispose(资源释放)会中止待处理和活跃调用,等待其结算,之后才允许注册另一个提供方。 + +自动工作绝不会延迟主 agent(智能体)响应。只有当带标记、由循环构建的请求,其确切路由与当前已记录的 `request/header` 匹配时,提供方才会启动;即使请求头未变而无需新快照,也适用此规则。延迟完成会直接通过 `Session` 追加一个独立的纯日志事件,而不打开轮次。持久化会立即观察到该事件,并在常规生命周期检查点完成刷写;标题发布本身不会强制刷写。自动失败会发出警告并保留最新标题。新的全消息修订、提供方 dispose、会话 dispose 和显式刷新都会中止旧工作,陈旧的完成结果无法追加。并发显式刷新会在提供方工作之前预留修订号;重叠的自动/显式回退请求共享一个会话本地正在进行的追加操作。服务与内置模型提供方各自追加自己的字面事件类型,因此不需要通用标题写入标记、类型断言或结算队列。服务拆卸会取消排队工作,并在卸载完成前等待不响应取消的调用结算完成。 + +fork 出的会话会原样继承种子中的标题事件。首消息节奏不会自动为子会话重新生成标题;全消息节奏可以在子会话收到后续用户提示词后追加新修订。 + +## 配置 + +所有上限都是必填项;该库不提供默认值。 + +| 键 | 约定 | +|---|---| +| `fallbackMaxWords` | 确定性回退中以空白分隔的最大正整数词数。 | +| `fallbackMaxBytes` | 回退允许的最大正整数 UTF-8 字节数;不得超过 `maxTitleBytes`。 | +| `maxTitleBytes` | 接受任何来源标题的最大正整数 UTF-8 字节数。 | + +## 提供方约定 + +提供方会提供带品牌类型的稳定 id、自动模式(`first-prompt` 或 `all-prompts`)和 `generate(request)`。请求携带活跃会话、截至一次固定修订的所有符合条件消息、可用时当前已记录的主请求路由,以及取消信号。结果包含非空标题、该请求中互不重复且有序的来源消息 seq,以及生成该标题时使用的可选提供方/模型路由。服务会在结果持久保存前进行规范化和验证。 + +参见[会话标题数据结构](../../../docs/subsystems/session-title.md)与[已实现决策](../../../.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md)。 + +## 模型体验 + +### 会话标题状态 + +#### 模型看到的内容 + +无。`session/title` 只写入日志,绝不会进入会话接口、`deriveMessages()`、系统提示词、工具 schema 或请求前缀。 + +#### Token 影响 + +回退与已接受的提供方修订不会向主 agent 请求增加 token。可选提供方的独立辅助请求由对应提供方包的文档说明。 + +#### KV Cache 影响 + +不影响主请求;标题事件不会改变重建内容或缓存键。 + +## 已知限制与暂缓事项 + +- 删除标题(不经显式 `refresh` 就解钉回自动标题)、搜索和列表索引不属于此服务。 +- 提供方注册表有意最多接受一个实现,因此部署若要组合相互竞争的标题策略,必须编写一个自行负责优先级的提供方。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/index.js new file mode 100644 index 0000000..00039f8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/index.js @@ -0,0 +1,580 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { z as z$1 } from "zod"; +import { assertNever, deepFreeze, isAgentLoopRequest } from "@deepseek-ai/dsh-llm"; +//#region lib/types/normalize.js +/** Title text normalization and UTF-8-safe truncation. */ +/** Operating-system-command escape sequences, including unterminated tails. */ +const OSC_SEQUENCE = /(?:\u001B\]|\u009D)(?:(?!\u0007|\u001B\\)[\s\S])*(?:\u0007|\u001B\\|$)/gu; +/** Control-sequence-introducer escapes such as SGR color codes. */ +const CSI_SEQUENCE = /(?:\u001B\[|\u009B)[0-?]*[ -/]*[@-~]/gu; +/** Remaining two-byte ESC control sequences. */ +const ESC_SEQUENCE = /\u001B[@-_]/gu; +/** Non-whitespace C0/C1 control characters. */ +const CONTROL_CHARACTER = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/gu; +/** Directional and invisible controls that can make a displayed title deceptive. */ +const DIRECTIONAL_CONTROL = /[\u200B\u200E\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF]/gu; +/** Reject an invalid public text limit. */ +function assertPositiveInteger$1(name, value) { + if (!Number.isInteger(value) || value <= 0) throw new Error(`${name} must be a positive integer`); +} +/** Remove controls and produce one trimmed, whitespace-normalized line. */ +function cleanTitleText(input) { + return input.replace(OSC_SEQUENCE, "").replace(CSI_SEQUENCE, "").replace(ESC_SEQUENCE, "").replace(CONTROL_CHARACTER, "").replace(DIRECTIONAL_CONTROL, "").replace(/\s+/gu, " ").trim(); +} +/** +* Truncate a string to a UTF-8 byte budget without splitting a Unicode code point. +* @param input - normalized title text. +* @param maxBytes - positive UTF-8 byte budget. +* @returns the longest leading code-point prefix within the budget. +*/ +function truncateTitleUtf8(input, maxBytes) { + assertPositiveInteger$1("maxBytes", maxBytes); + if (Buffer.byteLength(input, "utf8") <= maxBytes) return input; + let used = 0; + let output = ""; + for (const character of input) { + const bytes = Buffer.byteLength(character, "utf8"); + if (used + bytes > maxBytes) break; + output += character; + used += bytes; + } + return output; +} +/** +* Normalize one accepted session title and enforce its UTF-8 byte budget. +* @param input - untrusted title text. +* @param maxBytes - positive maximum encoded size. +* @returns a terminal-safe one-line title, possibly empty after sanitization. +*/ +function normalizeSessionTitle(input, maxBytes) { + return truncateTitleUtf8(cleanTitleText(input), maxBytes).trimEnd(); +} +/** +* Derive the deterministic first-prompt fallback. +* @param input - text from the first eligible human message. +* @param maxWords - positive whitespace-delimited word cap. +* @param maxBytes - positive UTF-8 byte cap. +* @returns the normalized leading words within both limits. +*/ +function fallbackSessionTitle(input, maxWords, maxBytes) { + assertPositiveInteger$1("maxWords", maxWords); + return truncateTitleUtf8(cleanTitleText(input).split(" ").filter(Boolean).slice(0, maxWords).join(" "), maxBytes).trimEnd(); +} +//#endregion +//#region lib/types/index.js +/** +* Log-backed session title service, deterministic fallback, and provider contract. +* @module @deepseek-ai/dsh-session-title +*/ +/** +* Brand a raw provider id. +* @param id - stable non-empty provider identifier supplied by a plugin. +* @returns the same string with the session-title provider brand. +*/ +function SessionTitleProviderId(id) { + return id; +} +/** +* Rejection of an explicit user title whose text normalizes to empty — the +* one {@link SessionTitleService.rename} failure that blames the input. +* Callers translating rename failures onto a wire (`title-invalid`) narrow on +* this class; liveness and disposal failures stay plain `Error`s. +*/ +var SessionTitleInvalidError = class extends Error { + name = "SessionTitleInvalidError"; +}; +/** +* Collect human text-bearing user messages in log order. +* @param events - session log or persisted replay. +* @param throughSeq - optional inclusive event boundary. +* @returns eligible messages with exact source seqs. +*/ +function collectSessionTitleMessages(events, throughSeq) { + const messages = []; + for (const event of events) { + if (throughSeq !== void 0 && event.seq > throughSeq) break; + if (event.type !== "user/message" || event.data.source.kind !== "user") continue; + const text = event.data.content.filter((block) => block.type === "text").map((block) => block.text).join("\n"); + if (normalizeSessionTitle(text, Number.MAX_SAFE_INTEGER).length === 0) continue; + messages.push({ + seq: event.seq, + text + }); + } + return messages; +} +/** +* Fold the latest logged title without consulting mutable metadata. +* @param events - live or persisted session log. +* @returns the latest immutable title snapshot, or `undefined`. +*/ +function foldSessionTitle(events) { + const event = events.findLast((item) => item.type === "session/title"); + if (event === void 0) return void 0; + return deepFreeze({ + title: event.data.title, + messageSeqs: [...event.data.messageSeqs], + source: copySessionTitleSource(event.data.source), + eventSeq: event.seq, + updatedAt: event.time + }); +} +/** Defensive copy of a logged title source (the snapshot must not alias log-owned objects). */ +function copySessionTitleSource(source) { + switch (source.kind) { + case "fallback": return { kind: "fallback" }; + case "provider": return { + kind: "provider", + provider: source.provider, + ...source.model === void 0 ? {} : { model: { ...source.model } } + }; + case "user": return { kind: "user" }; + /* v8 ignore next -- closed-union exhaustiveness guard */ + default: return assertNever(source, "SessionTitleSource"); + } +} +/** Validate one positive integer configuration field. */ +function assertPositiveInteger(name, value) { + if (!Number.isInteger(value) || value <= 0) throw new Error(`session-title: ${name} must be a positive integer`); +} +/** Log-backed title fold plus asynchronous fallback generation. */ +var SessionTitleService = class extends Service { + static inject = ["sessions"]; + static Config = z.object({ + fallbackMaxWords: z.number().step(1).min(1).required(), + fallbackMaxBytes: z.number().step(1).min(1).required(), + maxTitleBytes: z.number().step(1).min(1).required() + }); + config; + ownerFiber; + registration; + work = /* @__PURE__ */ new Map(); + lifetime = new AbortController(); + inFlight = /* @__PURE__ */ new Set(); + constructor(ctx, config) { + super(ctx, "sessionTitle"); + this.ownerFiber = ctx.fiber; + const candidate = config; + if (candidate === null || typeof candidate !== "object") throw new Error("session-title: configuration is required"); + const value = candidate; + assertPositiveInteger("fallbackMaxWords", value.fallbackMaxWords); + assertPositiveInteger("fallbackMaxBytes", value.fallbackMaxBytes); + assertPositiveInteger("maxTitleBytes", value.maxTitleBytes); + if (value.fallbackMaxBytes > value.maxTitleBytes) throw new Error("session-title: fallbackMaxBytes must not exceed maxTitleBytes"); + this.config = deepFreeze({ ...value }); + ctx.effect(() => async () => { + this.lifetime.abort(/* @__PURE__ */ new Error("session-title service disposed")); + if (this.registration !== void 0) this.registration.closing = true; + this.registration = void 0; + for (const state of this.work.values()) { + delete state.pending; + state.active?.controller.abort(/* @__PURE__ */ new Error("session-title service disposed")); + } + await this.drain(this.inFlight); + this.work.clear(); + }, "sessionTitle lifecycle"); + ctx.inject(["sessionProjections"], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: "title", + schema: z$1.union([z$1.string().min(1), z$1.null()]), + init: () => null, + apply: (state, event) => event.type === "session/title" ? event.data.title : state, + view: (state) => state, + stateVersion: 1 + }); + }); + ctx.on("session/event", (session, event) => { + switch (event.type) { + case "user/message": + this.onUserMessage(session, event); + break; + case "request/header": + this.onRequestHeader(session, event); + break; + default: break; + } + }); + ctx.on("llm/stream", (options, next) => { + this.onMainRequest(options); + return next(); + }, { + global: true, + prepend: true + }); + ctx.on("session/disposed", (session) => { + const state = this.work.get(session); + if (state === void 0) return; + state.active?.controller.abort(/* @__PURE__ */ new Error("session disposed during title generation")); + this.work.delete(session); + }); + } + /** + * Read the latest folded title from one live or replayed session. + * @param session - session whose log is the title source of truth. + * @returns latest title snapshot, or `undefined` before eligible input. + */ + get(session) { + return foldSessionTitle(session.events); + } + /** + * Accept an explicit user title. Appends a `session/title` event with the + * `user` source, which pins the title: in-flight automatic generation is + * superseded and later user messages schedule none (an explicit + * {@link SessionTitleService.refresh} remains the deliberate unpin). + * @param session - exact live session to rename. + * @param title - raw user input; normalized before acceptance. + * @returns the accepted title snapshot. + * @throws {SessionTitleInvalidError} when the title normalizes to empty. + * @throws {Error} when the session is not live or the service is disposed. + */ + rename(session, title) { + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) throw new Error(`session "${session.id}" is not live in this store`); + const normalized = normalizeSessionTitle(title, this.config.maxTitleBytes); + if (normalized.length === 0) throw new SessionTitleInvalidError("session title must contain visible characters"); + const state = this.stateFor(session); + this.supersede(state, "user rename superseded automatic title generation"); + session.append("session/title", { + title: normalized, + messageSeqs: [], + source: { kind: "user" } + }); + const snapshot = this.get(session); + /* v8 ignore next -- unreachable: the append above just committed a session/title event. */ + if (snapshot === void 0) throw new Error("renamed title failed to fold"); + return snapshot; + } + /** + * Explicitly retry the registered provider, or materialize the built-in + * fallback when no provider is registered. + * @param session - exact live session to refresh. + * @param signal - optional caller cancellation. + * @returns latest accepted title, or `undefined` when no eligible text exists. + */ + async refresh(session, signal) { + signal?.throwIfAborted(); + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) throw new Error(`session "${session.id}" is not live in this store`); + const registration = this.registration; + const messages = collectSessionTitleMessages(session.events); + const latest = messages.at(-1); + if (registration === void 0 || registration.closing || latest === void 0) { + const current = this.get(session); + const [first] = messages; + if (current?.source.kind === "user" && first !== void 0) { + this.appendFallback(session, first); + signal?.throwIfAborted(); + return this.get(session); + } + const fallback = await this.ensureFallback(session); + signal?.throwIfAborted(); + return fallback; + } + const state = this.stateFor(session); + const revision = this.supersede(state, "explicit title refresh superseded older generation"); + const work = this.activate({ + registration, + revision, + throughSeq: latest.seq + }, state, signal); + const config = session.requestHeader()?.config; + const route = config === void 0 ? void 0 : { + provider: config.provider, + model: config.model + }; + return this.startProvider(session, work, route); + } + /** + * Register the sole optional title provider. Disposal aborts its pending and + * active work before another provider may register. + * @param provider - provider identity, cadence, and generation function. + * @returns exact Cordis effect disposer, which settles after active calls quiesce. + */ + register(provider) { + this.validateProvider(provider); + if (this.registration !== void 0) throw new Error(`session-title provider "${this.registration.provider.id}" is already registered`); + const registration = { + provider, + active: /* @__PURE__ */ new Set(), + closing: false + }; + return this.ctx.effect(function* () { + this.registration = registration; + yield async () => { + registration.closing = true; + for (const state of this.work.values()) { + if (state.pending?.registration === registration) delete state.pending; + if (state.active?.registration === registration) state.active.controller.abort(/* @__PURE__ */ new Error(`session-title provider "${provider.id}" was disposed`)); + } + await this.drain(registration.active); + if (this.registration === registration) this.registration = void 0; + }; + }.bind(this), "sessionTitle.register()"); + } + /** Schedule fallback creation and any provider cadence for one eligible event. */ + onUserMessage(session, event) { + if (!this.serviceActive()) return; + if (event.data.source.kind !== "user" || collectSessionTitleMessages([event]).length === 0) return; + if (this.get(session)?.source.kind === "user") return; + const registration = this.registration; + if (registration !== void 0 && !registration.closing) { + const messages = collectSessionTitleMessages(session.events, event.seq); + if (registration.provider.automatic === "all-prompts" || session.header.parentSession === void 0 && messages.length === 1 && this.get(session) === void 0) { + const state = this.stateFor(session); + state.pending = { + registration, + revision: this.supersede(state, "newer user message superseded title generation"), + throughSeq: event.seq + }; + } + } + this.defer(async () => { + try { + await this.ensureFallback(session); + } catch (error) { + if (!this.serviceActive()) return; + this.ctx.logger.warn(`session "${session.id}": fallback title update failed: ${String(error)}`); + } + }); + } + /** Start pending automatic work only after its exact main-request route is logged. */ + onRequestHeader(session, event) { + if (!this.serviceActive()) return; + const state = this.work.get(session); + const pending = state?.pending; + if (state === void 0 || pending === void 0 || pending.throughSeq >= event.seq) return; + const route = { + provider: event.data.header.config.provider, + model: event.data.header.config.model + }; + this.startPending(session, state, pending, route); + } + /** Start unchanged-route work from the marked loop request after its header fold is current. */ + onMainRequest(options) { + if (!this.serviceActive() || options.sessionId === void 0 || !isAgentLoopRequest(options)) return; + const session = this.ctx.sessions.get(options.sessionId); + const state = session === void 0 ? void 0 : this.work.get(session); + const pending = state?.pending; + if (session === void 0 || state === void 0 || pending === void 0) return; + const boundary = session.events.findLast((event) => event.type === "step/start" || event.type === "step/end"); + const route = session.requestHeader()?.config; + if (boundary?.type !== "step/start" || boundary.seq <= pending.throughSeq || route?.provider !== options.provider || route.model !== options.model) return; + this.startPending(session, state, pending, { + provider: options.provider, + model: options.model + }); + } + /** Consume one pending revision and schedule its non-blocking provider call. */ + startPending(session, state, pending, route) { + delete state.pending; + this.defer(async () => { + if (this.registration !== pending.registration || pending.registration.closing || this.work.get(session) !== state || state.revision !== pending.revision) return; + const work = this.activate(pending, state); + try { + await this.startProvider(session, work, route); + } catch (error) { + if (work.signal.aborted || !this.serviceActive()) return; + this.ctx.logger.warn(`session "${session.id}": automatic title generation failed: ${String(error)}`); + } + }); + } + /** Start one tracked provider call after publishing its active revision. */ + startProvider(session, work, route) { + const run = Promise.resolve().then(() => this.runProvider(session, work, route)); + return this.track(run, work.registration); + } + /** Execute and accept one current provider revision. */ + async runProvider(session, work, route) { + try { + this.assertCurrent(session, work); + await this.ensureFallback(session); + this.assertCurrent(session, work); + const messages = collectSessionTitleMessages(session.events, work.throughSeq); + const result = await work.registration.provider.generate({ + session, + messages, + ...route === void 0 ? {} : { route }, + signal: work.signal + }); + this.assertCurrent(session, work); + const accepted = this.validateResult(result, messages); + session.append("session/title", { + title: accepted.title, + messageSeqs: [...accepted.messageSeqs], + source: { + kind: "provider", + provider: work.registration.provider.id, + ...accepted.model === void 0 ? {} : { model: accepted.model } + } + }); + return this.get(session); + } finally { + const state = this.work.get(session); + if (state?.active === work) delete state.active; + } + } + /** Validate and normalize provider output against the supplied message snapshot. */ + validateResult(result, messages) { + if (result === null || typeof result !== "object") throw new Error("session-title provider returned an invalid result"); + const candidate = result; + if (typeof candidate.title !== "string") throw new Error("session-title provider title must be a string"); + const title = normalizeSessionTitle(candidate.title, this.config.maxTitleBytes); + if (title.length === 0) throw new Error("session-title provider returned an empty title"); + if (!Array.isArray(candidate.messageSeqs) || candidate.messageSeqs.length === 0) throw new Error("session-title provider must identify at least one source message seq"); + const messageSeqs = []; + const order = new Map(messages.map((message, index) => [message.seq, index])); + let previous = -1; + for (const seq of candidate.messageSeqs) { + if (typeof seq !== "number") throw new Error("session-title provider messageSeqs must be unique, ordered seqs from the request"); + const index = order.get(seq); + if (!Number.isSafeInteger(seq) || seq < 0 || index === void 0 || index <= previous) throw new Error("session-title provider messageSeqs must be unique, ordered seqs from the request"); + messageSeqs.push(seq); + previous = index; + } + const modelCandidate = candidate.model; + let model; + if (modelCandidate !== void 0) { + if (modelCandidate === null || typeof modelCandidate !== "object") throw new Error("session-title provider result model must contain non-empty provider and model strings"); + const record = modelCandidate; + if (typeof record.provider !== "string" || record.provider.length === 0 || typeof record.model !== "string" || record.model.length === 0) throw new Error("session-title provider result model must contain non-empty provider and model strings"); + model = { + provider: record.provider, + model: record.model + }; + } + return { + title, + messageSeqs, + ...model === void 0 ? {} : { model } + }; + } + /** Fail a completion whose provider, revision, session, or signal is stale. */ + assertCurrent(session, work) { + this.assertServiceActive(); + work.signal.throwIfAborted(); + const state = this.work.get(session); + /* v8 ignore next -- every supported supersession, provider disposal, and session disposal aborts + * the work signal before changing this state. */ + if (this.registration !== work.registration || state?.active !== work || state.revision !== work.revision || this.ctx.sessions.get(session.id) !== session) throw new Error("session title generation state changed without cancellation"); + } + /** Create and publish an active provider call from one fixed revision. */ + activate(pending, state, upstream) { + const controller = new AbortController(); + const signal = upstream === void 0 ? AbortSignal.any([controller.signal, this.lifetime.signal]) : AbortSignal.any([ + controller.signal, + this.lifetime.signal, + upstream + ]); + const work = { + ...pending, + controller, + signal + }; + state.active = work; + return work; + } + /** Abort older active work and reserve the next session-local revision. */ + supersede(state, reason) { + state.active?.controller.abort(new Error(reason)); + delete state.pending; + state.revision += 1; + return state.revision; + } + /** Return mutable work state for one session. */ + stateFor(session) { + let state = this.work.get(session); + if (state === void 0) { + state = { revision: 0 }; + this.work.set(session, state); + } + return state; + } + /** Queue detached service work and retain it through service disposal. */ + defer(task) { + const run = Promise.resolve().then(async () => { + if (!this.serviceActive()) return; + await task(); + }); + this.track(run); + } + /** Retain one promise until settlement for service and optional provider teardown. */ + track(run, registration) { + this.inFlight.add(run); + registration?.active.add(run); + const settled = () => { + this.inFlight.delete(run); + registration?.active.delete(run); + }; + run.then(settled, settled); + return run; + } + /** Await every current and settling promise in one lifecycle registry. */ + async drain(active) { + while (active.size > 0) await Promise.allSettled([...active]); + } + /** Whether the owning plugin fiber can still start or commit title work. */ + serviceActive() { + return !this.lifetime.signal.aborted && this.ownerFiber.uid !== null && this.ownerFiber.state === 2; + } + /** Reject work once the owning plugin fiber has begun unloading. */ + assertServiceActive() { + if (!this.serviceActive()) throw new Error("session-title service disposed"); + } + /** Reject malformed provider registrations before publishing an effect. */ + validateProvider(provider) { + if (provider === null || typeof provider !== "object") throw new Error("session-title provider must be an object"); + const candidate = provider; + if (typeof candidate.id !== "string" || candidate.id.length === 0) throw new Error("session-title provider id must be a non-empty string"); + if (candidate.automatic !== "first-prompt" && candidate.automatic !== "all-prompts") throw new Error("session-title provider automatic mode is invalid"); + if (typeof candidate.generate !== "function") throw new Error(`session-title provider "${candidate.id}" requires generate()`); + } + /** + * Derive and append the deterministic fallback title over whatever stands + * (the refresh unpin path: overwriting a pinned user title is the point). + * Synchronous on purpose — no await may separate derivation from append, so + * it needs neither ensureFallback's in-flight dedup nor its liveness + * re-check. An underivable fallback (empty after the caps) appends nothing. + */ + appendFallback(session, first) { + const title = fallbackSessionTitle(first.text, this.config.fallbackMaxWords, this.config.fallbackMaxBytes); + if (title.length === 0) return; + session.append("session/title", { + title, + messageSeqs: [first.seq], + source: { kind: "fallback" } + }); + } + /** Create the first deterministic fallback if the session still lacks a title. */ + async ensureFallback(session) { + this.assertServiceActive(); + const current = this.get(session); + if (current !== void 0) return current; + const [first] = collectSessionTitleMessages(session.events); + if (first === void 0) return void 0; + const title = fallbackSessionTitle(first.text, this.config.fallbackMaxWords, this.config.fallbackMaxBytes); + if (title.length === 0) return void 0; + const state = this.stateFor(session); + if (state.fallback !== void 0) return state.fallback; + const fallback = Promise.resolve().then(() => { + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) throw new Error(`session "${session.id}" is not live in this store`); + const accepted = this.get(session); + if (accepted !== void 0) return accepted; + session.append("session/title", { + title, + messageSeqs: [first.seq], + source: { kind: "fallback" } + }); + return this.get(session); + }); + state.fallback = fallback; + try { + return await fallback; + } finally { + delete state.fallback; + } + } +}; +//#endregion +export { SessionTitleInvalidError, SessionTitleProviderId, SessionTitleService, SessionTitleService as default, collectSessionTitleMessages, fallbackSessionTitle, foldSessionTitle, normalizeSessionTitle, truncateTitleUtf8 }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/invariant.js new file mode 100644 index 0000000..d2b72b4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/invariant.js @@ -0,0 +1,38 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-session-title`. +* @module @deepseek-ai/dsh-session-title/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session-title"; +/** Cordis companion plugin name. */ +const name = "session-title-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* Durable title-source invariant: an automatic title always cites at +* least one human `user/message` seq, and an explicit user rename cites none +* — `messageSeqs` is empty iff `source.kind` is `user`. Provider revisions +* are validated by the service before their append; this checks the durable +* relationship every appended `session/title` event must keep, whichever +* writer produced it. +*/ +const install = Object.assign((ctx, fail) => { + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName !== "session/event") return; + const [, event] = args; + if (event.type !== "session/title") return; + const { source, messageSeqs } = event.data; + if (messageSeqs.length === 0 !== (source.kind === "user")) { + const requirement = source.kind === "user" ? "cite no message seqs" : "cite at least one message seq"; + fail(`session/title event ${String(event.seq)} with source "${source.kind}" must ${requirement}; got ${String(messageSeqs.length)}`); + } + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.d.ts new file mode 100644 index 0000000..9f1c7d1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.d.ts @@ -0,0 +1,10 @@ +/** + * Client-namespace projection of the title domain: a pure re-export of the package's + * types outlet. Client code imports ONLY the client namespace (repo + * discipline), so `./client` projects the same single-source content + * `./types` serves to host consumers — zero duplication. + * + * @module @deepseek-ai/dsh-session-title/client + */ +export type * from './types.ts'; +//# sourceMappingURL=client.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.js new file mode 100644 index 0000000..b6c0882 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/client.js @@ -0,0 +1,10 @@ +/** + * Client-namespace projection of the title domain: a pure re-export of the package's + * types outlet. Client code imports ONLY the client namespace (repo + * discipline), so `./client` projects the same single-source content + * `./types` serves to host consumers — zero duplication. + * + * @module @deepseek-ai/dsh-session-title/client + */ +export {}; +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.d.ts new file mode 100644 index 0000000..4cb8714 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.d.ts @@ -0,0 +1,230 @@ +/** + * Log-backed session title service, deterministic fallback, and provider contract. + * @module @deepseek-ai/dsh-session-title + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { Session, SessionEvent } from '@deepseek-ai/dsh-session'; +export type * from './types.ts'; +export { fallbackSessionTitle, normalizeSessionTitle, truncateTitleUtf8 } from './normalize.ts'; +/** Identifies one session-title provider registration. */ +export type SessionTitleProviderId = Branded<'SessionTitleProviderId'>; +/** + * Brand a raw provider id. + * @param id - stable non-empty provider identifier supplied by a plugin. + * @returns the same string with the session-title provider brand. + */ +export declare function SessionTitleProviderId(id: string): SessionTitleProviderId; +/** Exact auxiliary model route that produced a title. */ +export interface SessionTitleModelProvenance { + /** Registered LLM provider route. */ + readonly provider: string; + /** Provider model id. */ + readonly model: string; +} +/** Durable ownership record for an accepted session title. */ +export type SessionTitleSource = { + readonly kind: 'fallback'; +} | { + readonly kind: 'provider'; + readonly provider: SessionTitleProviderId; + readonly model?: SessionTitleModelProvenance; +} | { + /** Explicit user rename: pins the title — automatic generation stops scheduling. */ + readonly kind: 'user'; +}; +/** Payload of the log-only `session/title` event. */ +export interface SessionTitleEventData { + /** Normalized non-empty title text. */ + readonly title: string; + /** Exact human `user/message` seqs used to derive this title; empty for an explicit user rename. */ + readonly messageSeqs: number[]; + /** Whether the built-in fallback, a registered provider, or the user supplied the title. */ + readonly source: SessionTitleSource; +} +/** Latest folded title plus the title event's durable envelope facts. */ +export interface SessionTitleSnapshot extends SessionTitleEventData { + /** Seq of the latest `session/title` event. */ + readonly eventSeq: number; + /** Timestamp of the latest `session/title` event. */ + readonly updatedAt: number; +} +/** Required deterministic fallback and accepted-title limits. */ +export interface Config { + /** Maximum whitespace-delimited words in the built-in fallback. */ + readonly fallbackMaxWords: number; + /** Maximum UTF-8 bytes in the built-in fallback. */ + readonly fallbackMaxBytes: number; + /** Maximum UTF-8 bytes in any accepted title. */ + readonly maxTitleBytes: number; +} +declare module '@deepseek-ai/cordis' { + interface Context { + sessionTitle: SessionTitleService; + } +} +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * Latest-wins session title snapshot. Log-only: it never enters the model + * surface or derived history. + */ + 'session/title': SessionTitleEventData; + } +} +/** + * Rejection of an explicit user title whose text normalizes to empty — the + * one {@link SessionTitleService.rename} failure that blames the input. + * Callers translating rename failures onto a wire (`title-invalid`) narrow on + * this class; liveness and disposal failures stay plain `Error`s. + */ +export declare class SessionTitleInvalidError extends Error { + readonly name = "SessionTitleInvalidError"; +} +/** One eligible human text message exposed to title providers. */ +export interface SessionTitleUserMessage { + /** Source `user/message` event seq. */ + readonly seq: number; + /** Exact concatenated text-block content. */ + readonly text: string; +} +/** Automatic generation cadence owned by a registered provider. */ +export type SessionTitleAutomaticMode = 'first-prompt' | 'all-prompts'; +/** Immutable input supplied to one title-provider call. */ +export interface SessionTitleProviderRequest { + /** Live session being titled. */ + readonly session: Session; + /** All eligible human messages through this generation revision. */ + readonly messages: readonly SessionTitleUserMessage[]; + /** Exact current logged main-request route, when one has been recorded. */ + readonly route?: SessionTitleModelProvenance; + /** Cancellation for supersession, disposal, timeout composition, or the explicit caller. */ + readonly signal: AbortSignal; +} +/** Provider output before service-owned normalization and log acceptance. */ +export interface SessionTitleProviderResult { + /** Proposed title text. */ + readonly title: string; + /** Exact seqs from `request.messages` used by this result. */ + readonly messageSeqs: readonly number[]; + /** Auxiliary LLM route, when generation used a model. */ + readonly model?: SessionTitleModelProvenance; +} +/** One optional asynchronous title implementation registered with the service. */ +export interface SessionTitleProvider { + /** Stable id of the provider recorded with the title. */ + readonly id: SessionTitleProviderId; + /** When new human prompts start automatic generation. */ + readonly automatic: SessionTitleAutomaticMode; + /** + * Produce one title revision. + * @param request - message snapshot, current route, session, and cancellation. + * @returns proposed title plus exact input seqs and the optional provider/model route used to generate it. + */ + generate(request: SessionTitleProviderRequest): Promise; +} +/** + * Collect human text-bearing user messages in log order. + * @param events - session log or persisted replay. + * @param throughSeq - optional inclusive event boundary. + * @returns eligible messages with exact source seqs. + */ +export declare function collectSessionTitleMessages(events: readonly SessionEvent[], throughSeq?: number): SessionTitleUserMessage[]; +/** + * Fold the latest logged title without consulting mutable metadata. + * @param events - live or persisted session log. + * @returns the latest immutable title snapshot, or `undefined`. + */ +export declare function foldSessionTitle(events: readonly SessionEvent[]): SessionTitleSnapshot | undefined; +/** Log-backed title fold plus asynchronous fallback generation. */ +export declare class SessionTitleService extends Service { + static inject: string[]; + static Config: z; + private readonly config; + private readonly ownerFiber; + private registration; + private readonly work; + private readonly lifetime; + private readonly inFlight; + constructor(ctx: Context, config: Config); + /** + * Read the latest folded title from one live or replayed session. + * @param session - session whose log is the title source of truth. + * @returns latest title snapshot, or `undefined` before eligible input. + */ + get(session: Session): SessionTitleSnapshot | undefined; + /** + * Accept an explicit user title. Appends a `session/title` event with the + * `user` source, which pins the title: in-flight automatic generation is + * superseded and later user messages schedule none (an explicit + * {@link SessionTitleService.refresh} remains the deliberate unpin). + * @param session - exact live session to rename. + * @param title - raw user input; normalized before acceptance. + * @returns the accepted title snapshot. + * @throws {SessionTitleInvalidError} when the title normalizes to empty. + * @throws {Error} when the session is not live or the service is disposed. + */ + rename(session: Session, title: string): SessionTitleSnapshot; + /** + * Explicitly retry the registered provider, or materialize the built-in + * fallback when no provider is registered. + * @param session - exact live session to refresh. + * @param signal - optional caller cancellation. + * @returns latest accepted title, or `undefined` when no eligible text exists. + */ + refresh(session: Session, signal?: AbortSignal): Promise; + /** + * Register the sole optional title provider. Disposal aborts its pending and + * active work before another provider may register. + * @param provider - provider identity, cadence, and generation function. + * @returns exact Cordis effect disposer, which settles after active calls quiesce. + */ + register(provider: SessionTitleProvider): () => Promise; + /** Schedule fallback creation and any provider cadence for one eligible event. */ + private onUserMessage; + /** Start pending automatic work only after its exact main-request route is logged. */ + private onRequestHeader; + /** Start unchanged-route work from the marked loop request after its header fold is current. */ + private onMainRequest; + /** Consume one pending revision and schedule its non-blocking provider call. */ + private startPending; + /** Start one tracked provider call after publishing its active revision. */ + private startProvider; + /** Execute and accept one current provider revision. */ + private runProvider; + /** Validate and normalize provider output against the supplied message snapshot. */ + private validateResult; + /** Fail a completion whose provider, revision, session, or signal is stale. */ + private assertCurrent; + /** Create and publish an active provider call from one fixed revision. */ + private activate; + /** Abort older active work and reserve the next session-local revision. */ + private supersede; + /** Return mutable work state for one session. */ + private stateFor; + /** Queue detached service work and retain it through service disposal. */ + private defer; + /** Retain one promise until settlement for service and optional provider teardown. */ + private track; + /** Await every current and settling promise in one lifecycle registry. */ + private drain; + /** Whether the owning plugin fiber can still start or commit title work. */ + private serviceActive; + /** Reject work once the owning plugin fiber has begun unloading. */ + private assertServiceActive; + /** Reject malformed provider registrations before publishing an effect. */ + private validateProvider; + /** + * Derive and append the deterministic fallback title over whatever stands + * (the refresh unpin path: overwriting a pinned user title is the point). + * Synchronous on purpose — no await may separate derivation from append, so + * it needs neither ensureFallback's in-flight dedup nor its liveness + * re-check. An underivable fallback (empty after the caps) appends nothing. + */ + private appendFallback; + /** Create the first deterministic fallback if the session still lacks a title. */ + private ensureFallback; +} +export default SessionTitleService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.js new file mode 100644 index 0000000..f34245e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/index.js @@ -0,0 +1,601 @@ +/** + * Log-backed session title service, deterministic fallback, and provider contract. + * @module @deepseek-ai/dsh-session-title + */ +import { Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { z as zod } from 'zod'; +import { assertNever, deepFreeze, isAgentLoopRequest } from '@deepseek-ai/dsh-llm'; +import { fallbackSessionTitle, normalizeSessionTitle } from "./normalize.js"; +export { fallbackSessionTitle, normalizeSessionTitle, truncateTitleUtf8 } from "./normalize.js"; +/** + * Brand a raw provider id. + * @param id - stable non-empty provider identifier supplied by a plugin. + * @returns the same string with the session-title provider brand. + */ +export function SessionTitleProviderId(id) { + return id; +} +/** + * Rejection of an explicit user title whose text normalizes to empty — the + * one {@link SessionTitleService.rename} failure that blames the input. + * Callers translating rename failures onto a wire (`title-invalid`) narrow on + * this class; liveness and disposal failures stay plain `Error`s. + */ +export class SessionTitleInvalidError extends Error { + name = 'SessionTitleInvalidError'; +} +/** + * Collect human text-bearing user messages in log order. + * @param events - session log or persisted replay. + * @param throughSeq - optional inclusive event boundary. + * @returns eligible messages with exact source seqs. + */ +export function collectSessionTitleMessages(events, throughSeq) { + const messages = []; + for (const event of events) { + if (throughSeq !== undefined && event.seq > throughSeq) + break; + if (event.type !== 'user/message' || event.data.source.kind !== 'user') + continue; + const content = event.data.content; + const text = content + .filter((block) => block.type === 'text') + .map(block => block.text) + .join('\n'); + if (normalizeSessionTitle(text, Number.MAX_SAFE_INTEGER).length === 0) + continue; + messages.push({ seq: event.seq, text }); + } + return messages; +} +/** + * Fold the latest logged title without consulting mutable metadata. + * @param events - live or persisted session log. + * @returns the latest immutable title snapshot, or `undefined`. + */ +export function foldSessionTitle(events) { + const event = events.findLast(item => item.type === 'session/title'); + if (event === undefined) + return undefined; + return deepFreeze({ + title: event.data.title, + messageSeqs: [...event.data.messageSeqs], + source: copySessionTitleSource(event.data.source), + eventSeq: event.seq, + updatedAt: event.time, + }); +} +/** Defensive copy of a logged title source (the snapshot must not alias log-owned objects). */ +function copySessionTitleSource(source) { + switch (source.kind) { + case 'fallback': return { kind: 'fallback' }; + case 'provider': return { + kind: 'provider', + provider: source.provider, + ...(source.model === undefined ? {} : { model: { ...source.model } }), + }; + case 'user': return { kind: 'user' }; + /* v8 ignore next -- closed-union exhaustiveness guard */ + default: return assertNever(source, 'SessionTitleSource'); + } +} +/** Validate one positive integer configuration field. */ +function assertPositiveInteger(name, value) { + if (!Number.isInteger(value) || value <= 0) { + throw new Error(`session-title: ${name} must be a positive integer`); + } +} +/** Log-backed title fold plus asynchronous fallback generation. */ +export class SessionTitleService extends Service { + static inject = ['sessions']; + static Config = z.object({ + fallbackMaxWords: z.number().step(1).min(1).required(), + fallbackMaxBytes: z.number().step(1).min(1).required(), + maxTitleBytes: z.number().step(1).min(1).required(), + }); + config; + ownerFiber; + registration; + work = new Map(); + lifetime = new AbortController(); + inFlight = new Set(); + constructor(ctx, config) { + super(ctx, 'sessionTitle'); + this.ownerFiber = ctx.fiber; + const candidate = config; + if (candidate === null || typeof candidate !== 'object') { + throw new Error('session-title: configuration is required'); + } + const value = candidate; + assertPositiveInteger('fallbackMaxWords', value.fallbackMaxWords); + assertPositiveInteger('fallbackMaxBytes', value.fallbackMaxBytes); + assertPositiveInteger('maxTitleBytes', value.maxTitleBytes); + if (value.fallbackMaxBytes > value.maxTitleBytes) { + throw new Error('session-title: fallbackMaxBytes must not exceed maxTitleBytes'); + } + this.config = deepFreeze({ ...value }); + ctx.effect(() => async () => { + this.lifetime.abort(new Error('session-title service disposed')); + if (this.registration !== undefined) + this.registration.closing = true; + this.registration = undefined; + for (const state of this.work.values()) { + delete state.pending; + state.active?.controller.abort(new Error('session-title service disposed')); + } + await this.drain(this.inFlight); + this.work.clear(); + }, 'sessionTitle lifecycle'); + // The title projection unit: pure last-wins fold of session/title events + // (the same events foldSessionTitle consumes), serving the plain title + // string clients list rows read. The unit child activates only when a + // projection registry is composed (headless assemblies stay unaffected). + ctx.inject(['sessionProjections'], (projectionCtx) => { + projectionCtx.sessionProjections.register({ + key: 'title', + schema: zod.union([zod.string().min(1), zod.null()]), + init: () => null, + apply: (state, event) => (event.type === 'session/title' ? event.data.title : state), + view: state => state, + stateVersion: 1, + }); + }); + ctx.on('session/event', (session, event) => { + switch (event.type) { + case 'user/message': + this.onUserMessage(session, event); + break; + case 'request/header': + this.onRequestHeader(session, event); + break; + default: + break; + } + }); + ctx.on('llm/stream', (options, next) => { + this.onMainRequest(options); + return next(); + }, { global: true, prepend: true }); + ctx.on('session/disposed', (session) => { + const state = this.work.get(session); + if (state === undefined) + return; + state.active?.controller.abort(new Error('session disposed during title generation')); + this.work.delete(session); + }); + } + /** + * Read the latest folded title from one live or replayed session. + * @param session - session whose log is the title source of truth. + * @returns latest title snapshot, or `undefined` before eligible input. + */ + get(session) { + return foldSessionTitle(session.events); + } + /** + * Accept an explicit user title. Appends a `session/title` event with the + * `user` source, which pins the title: in-flight automatic generation is + * superseded and later user messages schedule none (an explicit + * {@link SessionTitleService.refresh} remains the deliberate unpin). + * @param session - exact live session to rename. + * @param title - raw user input; normalized before acceptance. + * @returns the accepted title snapshot. + * @throws {SessionTitleInvalidError} when the title normalizes to empty. + * @throws {Error} when the session is not live or the service is disposed. + */ + rename(session, title) { + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) { + throw new Error(`session "${session.id}" is not live in this store`); + } + const normalized = normalizeSessionTitle(title, this.config.maxTitleBytes); + if (normalized.length === 0) { + throw new SessionTitleInvalidError('session title must contain visible characters'); + } + const state = this.stateFor(session); + this.supersede(state, 'user rename superseded automatic title generation'); + session.append('session/title', { + title: normalized, + messageSeqs: [], + source: { kind: 'user' }, + }); + const snapshot = this.get(session); + /* v8 ignore next -- unreachable: the append above just committed a session/title event. */ + if (snapshot === undefined) + throw new Error('renamed title failed to fold'); + return snapshot; + } + /** + * Explicitly retry the registered provider, or materialize the built-in + * fallback when no provider is registered. + * @param session - exact live session to refresh. + * @param signal - optional caller cancellation. + * @returns latest accepted title, or `undefined` when no eligible text exists. + */ + async refresh(session, signal) { + signal?.throwIfAborted(); + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) { + throw new Error(`session "${session.id}" is not live in this store`); + } + const registration = this.registration; + const messages = collectSessionTitleMessages(session.events); + const latest = messages.at(-1); + if (registration === undefined || registration.closing || latest === undefined) { + // Explicit refresh is the unpin even without a provider: a standing + // user title must not short-circuit ensureFallback into a no-op, so + // re-derive and append the fallback over it when one is derivable. + const current = this.get(session); + const [first] = messages; + if (current?.source.kind === 'user' && first !== undefined) { + this.appendFallback(session, first); + signal?.throwIfAborted(); + return this.get(session); + } + const fallback = await this.ensureFallback(session); + signal?.throwIfAborted(); + return fallback; + } + const state = this.stateFor(session); + const revision = this.supersede(state, 'explicit title refresh superseded older generation'); + const work = this.activate({ + registration, + revision, + throughSeq: latest.seq, + }, state, signal); + const config = session.requestHeader()?.config; + const route = config === undefined ? undefined : { provider: config.provider, model: config.model }; + return this.startProvider(session, work, route); + } + /** + * Register the sole optional title provider. Disposal aborts its pending and + * active work before another provider may register. + * @param provider - provider identity, cadence, and generation function. + * @returns exact Cordis effect disposer, which settles after active calls quiesce. + */ + register(provider) { + this.validateProvider(provider); + if (this.registration !== undefined) { + throw new Error(`session-title provider "${this.registration.provider.id}" is already registered`); + } + const registration = { + provider, + active: new Set(), + closing: false, + }; + const dispose = this.ctx.effect(function* () { + this.registration = registration; + yield async () => { + registration.closing = true; + for (const state of this.work.values()) { + if (state.pending?.registration === registration) + delete state.pending; + if (state.active?.registration === registration) { + state.active.controller.abort(new Error(`session-title provider "${provider.id}" was disposed`)); + } + } + await this.drain(registration.active); + if (this.registration === registration) + this.registration = undefined; + }; + }.bind(this), 'sessionTitle.register()'); + return dispose; + } + /** Schedule fallback creation and any provider cadence for one eligible event. */ + onUserMessage(session, event) { + if (!this.serviceActive()) + return; + if (event.data.source.kind !== 'user' || collectSessionTitleMessages([event]).length === 0) + return; + // A user rename pins the title: no automatic revision may override it. + if (this.get(session)?.source.kind === 'user') + return; + const registration = this.registration; + if (registration !== undefined && !registration.closing) { + const messages = collectSessionTitleMessages(session.events, event.seq); + const shouldSchedule = registration.provider.automatic === 'all-prompts' + || (session.header.parentSession === undefined && messages.length === 1 && this.get(session) === undefined); + if (shouldSchedule) { + const state = this.stateFor(session); + const revision = this.supersede(state, 'newer user message superseded title generation'); + state.pending = { registration, revision, throughSeq: event.seq }; + } + } + this.defer(async () => { + try { + await this.ensureFallback(session); + } + catch (error) { + if (!this.serviceActive()) + return; + this.ctx.logger.warn(`session "${session.id}": fallback title update failed: ${String(error)}`); + } + }); + } + /** Start pending automatic work only after its exact main-request route is logged. */ + onRequestHeader(session, event) { + if (!this.serviceActive()) + return; + const state = this.work.get(session); + const pending = state?.pending; + if (state === undefined || pending === undefined || pending.throughSeq >= event.seq) + return; + const route = { + provider: event.data.header.config.provider, + model: event.data.header.config.model, + }; + this.startPending(session, state, pending, route); + } + /** Start unchanged-route work from the marked loop request after its header fold is current. */ + onMainRequest(options) { + if (!this.serviceActive() || options.sessionId === undefined || !isAgentLoopRequest(options)) + return; + const session = this.ctx.sessions.get(options.sessionId); + const state = session === undefined ? undefined : this.work.get(session); + const pending = state?.pending; + if (session === undefined || state === undefined || pending === undefined) + return; + const boundary = session.events.findLast(event => event.type === 'step/start' || event.type === 'step/end'); + const route = session.requestHeader()?.config; + if (boundary?.type !== 'step/start' + || boundary.seq <= pending.throughSeq + || route?.provider !== options.provider + || route.model !== options.model) + return; + this.startPending(session, state, pending, { provider: options.provider, model: options.model }); + } + /** Consume one pending revision and schedule its non-blocking provider call. */ + startPending(session, state, pending, route) { + delete state.pending; + this.defer(async () => { + if (this.registration !== pending.registration + || pending.registration.closing + || this.work.get(session) !== state + || state.revision !== pending.revision) + return; + const work = this.activate(pending, state); + try { + await this.startProvider(session, work, route); + } + catch (error) { + if (work.signal.aborted || !this.serviceActive()) + return; + this.ctx.logger.warn(`session "${session.id}": automatic title generation failed: ${String(error)}`); + } + }); + } + /** Start one tracked provider call after publishing its active revision. */ + startProvider(session, work, route) { + const run = Promise.resolve().then(() => this.runProvider(session, work, route)); + return this.track(run, work.registration); + } + /** Execute and accept one current provider revision. */ + async runProvider(session, work, route) { + try { + this.assertCurrent(session, work); + await this.ensureFallback(session); + this.assertCurrent(session, work); + const messages = collectSessionTitleMessages(session.events, work.throughSeq); + const result = await work.registration.provider.generate({ + session, + messages, + ...route === undefined ? {} : { route }, + signal: work.signal, + }); + this.assertCurrent(session, work); + const accepted = this.validateResult(result, messages); + session.append('session/title', { + title: accepted.title, + messageSeqs: [...accepted.messageSeqs], + source: { + kind: 'provider', + provider: work.registration.provider.id, + ...accepted.model === undefined ? {} : { model: accepted.model }, + }, + }); + return this.get(session); + } + finally { + const state = this.work.get(session); + if (state?.active === work) + delete state.active; + } + } + /** Validate and normalize provider output against the supplied message snapshot. */ + validateResult(result, messages) { + if (result === null || typeof result !== 'object') { + throw new Error('session-title provider returned an invalid result'); + } + const candidate = result; + if (typeof candidate.title !== 'string') + throw new Error('session-title provider title must be a string'); + const title = normalizeSessionTitle(candidate.title, this.config.maxTitleBytes); + if (title.length === 0) + throw new Error('session-title provider returned an empty title'); + if (!Array.isArray(candidate.messageSeqs) || candidate.messageSeqs.length === 0) { + throw new Error('session-title provider must identify at least one source message seq'); + } + const messageSeqs = []; + const order = new Map(messages.map((message, index) => [message.seq, index])); + let previous = -1; + for (const seq of candidate.messageSeqs) { + if (typeof seq !== 'number') { + throw new Error('session-title provider messageSeqs must be unique, ordered seqs from the request'); + } + const index = order.get(seq); + if (!Number.isSafeInteger(seq) || seq < 0 || index === undefined || index <= previous) { + throw new Error('session-title provider messageSeqs must be unique, ordered seqs from the request'); + } + messageSeqs.push(seq); + previous = index; + } + const modelCandidate = candidate.model; + let model; + if (modelCandidate !== undefined) { + if (modelCandidate === null || typeof modelCandidate !== 'object') { + throw new Error('session-title provider result model must contain non-empty provider and model strings'); + } + const record = modelCandidate; + if (typeof record.provider !== 'string' || record.provider.length === 0 + || typeof record.model !== 'string' || record.model.length === 0) { + throw new Error('session-title provider result model must contain non-empty provider and model strings'); + } + model = { provider: record.provider, model: record.model }; + } + return { + title, + messageSeqs, + ...(model === undefined ? {} : { model }), + }; + } + /** Fail a completion whose provider, revision, session, or signal is stale. */ + assertCurrent(session, work) { + this.assertServiceActive(); + work.signal.throwIfAborted(); + const state = this.work.get(session); + /* v8 ignore next -- every supported supersession, provider disposal, and session disposal aborts + * the work signal before changing this state. */ + if (this.registration !== work.registration + || state?.active !== work + || state.revision !== work.revision + || this.ctx.sessions.get(session.id) !== session) { + throw new Error('session title generation state changed without cancellation'); + } + } + /** Create and publish an active provider call from one fixed revision. */ + activate(pending, state, upstream) { + const controller = new AbortController(); + const signal = upstream === undefined + ? AbortSignal.any([controller.signal, this.lifetime.signal]) + : AbortSignal.any([controller.signal, this.lifetime.signal, upstream]); + const work = { ...pending, controller, signal }; + state.active = work; + return work; + } + /** Abort older active work and reserve the next session-local revision. */ + supersede(state, reason) { + state.active?.controller.abort(new Error(reason)); + delete state.pending; + state.revision += 1; + return state.revision; + } + /** Return mutable work state for one session. */ + stateFor(session) { + let state = this.work.get(session); + if (state === undefined) { + state = { revision: 0 }; + this.work.set(session, state); + } + return state; + } + /** Queue detached service work and retain it through service disposal. */ + defer(task) { + const run = Promise.resolve().then(async () => { + if (!this.serviceActive()) + return; + await task(); + }); + void this.track(run); + } + /** Retain one promise until settlement for service and optional provider teardown. */ + track(run, registration) { + this.inFlight.add(run); + registration?.active.add(run); + const settled = () => { + this.inFlight.delete(run); + registration?.active.delete(run); + }; + void run.then(settled, settled); + return run; + } + /** Await every current and settling promise in one lifecycle registry. */ + async drain(active) { + while (active.size > 0) + await Promise.allSettled([...active]); + } + /** Whether the owning plugin fiber can still start or commit title work. */ + serviceActive() { + return !this.lifetime.signal.aborted + && this.ownerFiber.uid !== null + && this.ownerFiber.state === 2 /* FiberState.ACTIVE */; + } + /** Reject work once the owning plugin fiber has begun unloading. */ + assertServiceActive() { + if (!this.serviceActive()) + throw new Error('session-title service disposed'); + } + /** Reject malformed provider registrations before publishing an effect. */ + validateProvider(provider) { + if (provider === null || typeof provider !== 'object') { + throw new Error('session-title provider must be an object'); + } + const candidate = provider; + if (typeof candidate.id !== 'string' || candidate.id.length === 0) { + throw new Error('session-title provider id must be a non-empty string'); + } + if (candidate.automatic !== 'first-prompt' && candidate.automatic !== 'all-prompts') { + throw new Error('session-title provider automatic mode is invalid'); + } + if (typeof candidate.generate !== 'function') { + throw new Error(`session-title provider "${candidate.id}" requires generate()`); + } + } + /** + * Derive and append the deterministic fallback title over whatever stands + * (the refresh unpin path: overwriting a pinned user title is the point). + * Synchronous on purpose — no await may separate derivation from append, so + * it needs neither ensureFallback's in-flight dedup nor its liveness + * re-check. An underivable fallback (empty after the caps) appends nothing. + */ + appendFallback(session, first) { + const title = fallbackSessionTitle(first.text, this.config.fallbackMaxWords, this.config.fallbackMaxBytes); + if (title.length === 0) + return; + session.append('session/title', { + title, + messageSeqs: [first.seq], + source: { kind: 'fallback' }, + }); + } + /** Create the first deterministic fallback if the session still lacks a title. */ + async ensureFallback(session) { + this.assertServiceActive(); + const current = this.get(session); + if (current !== undefined) + return current; + const [first] = collectSessionTitleMessages(session.events); + if (first === undefined) + return undefined; + const title = fallbackSessionTitle(first.text, this.config.fallbackMaxWords, this.config.fallbackMaxBytes); + if (title.length === 0) + return undefined; + const state = this.stateFor(session); + if (state.fallback !== undefined) + return state.fallback; + const fallback = Promise.resolve().then(() => { + this.assertServiceActive(); + if (this.ctx.sessions.get(session.id) !== session) { + throw new Error(`session "${session.id}" is not live in this store`); + } + const accepted = this.get(session); + if (accepted !== undefined) + return accepted; + session.append('session/title', { + title, + messageSeqs: [first.seq], + source: { kind: 'fallback' }, + }); + return this.get(session); + }); + state.fallback = fallback; + try { + return await fallback; + } + finally { + delete state.fallback; + } + } +} +export default SessionTitleService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.d.ts new file mode 100644 index 0000000..bfebd4b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-title`. + * @module @deepseek-ai/dsh-session-title/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-title-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.js new file mode 100644 index 0000000..12980c1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/invariant.js @@ -0,0 +1,41 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-session-title`. + * @module @deepseek-ai/dsh-session-title/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-session-title'; +/** Cordis companion plugin name. */ +export const name = 'session-title-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * Durable title-source invariant: an automatic title always cites at + * least one human `user/message` seq, and an explicit user rename cites none + * — `messageSeqs` is empty iff `source.kind` is `user`. Provider revisions + * are validated by the service before their append; this checks the durable + * relationship every appended `session/title` event must keep, whichever + * writer produced it. + */ +const install = Object.assign((ctx, fail) => { + // internal/dispatch interception rejects the append before publication + // (the session/event listener would only observe the already-committed log). + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') + return; + const [, event] = args; + if (event.type !== 'session/title') + return; + const { source, messageSeqs } = event.data; + if ((messageSeqs.length === 0) !== (source.kind === 'user')) { + const requirement = source.kind === 'user' ? 'cite no message seqs' : 'cite at least one message seq'; + fail(`session/title event ${String(event.seq)} with source "${source.kind}" must ${requirement}; got ${String(messageSeqs.length)}`); + } + }, { global: true }); +}, { inject: ['sessions'] }); +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.d.ts new file mode 100644 index 0000000..ea2631e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.d.ts @@ -0,0 +1,24 @@ +/** Title text normalization and UTF-8-safe truncation. */ +/** + * Truncate a string to a UTF-8 byte budget without splitting a Unicode code point. + * @param input - normalized title text. + * @param maxBytes - positive UTF-8 byte budget. + * @returns the longest leading code-point prefix within the budget. + */ +export declare function truncateTitleUtf8(input: string, maxBytes: number): string; +/** + * Normalize one accepted session title and enforce its UTF-8 byte budget. + * @param input - untrusted title text. + * @param maxBytes - positive maximum encoded size. + * @returns a terminal-safe one-line title, possibly empty after sanitization. + */ +export declare function normalizeSessionTitle(input: string, maxBytes: number): string; +/** + * Derive the deterministic first-prompt fallback. + * @param input - text from the first eligible human message. + * @param maxWords - positive whitespace-delimited word cap. + * @param maxBytes - positive UTF-8 byte cap. + * @returns the normalized leading words within both limits. + */ +export declare function fallbackSessionTitle(input: string, maxWords: number, maxBytes: number): string; +//# sourceMappingURL=normalize.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.js new file mode 100644 index 0000000..8c7f9f5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/normalize.js @@ -0,0 +1,71 @@ +/** Title text normalization and UTF-8-safe truncation. */ +/** Operating-system-command escape sequences, including unterminated tails. */ +const OSC_SEQUENCE = /(?:\u001B\]|\u009D)(?:(?!\u0007|\u001B\\)[\s\S])*(?:\u0007|\u001B\\|$)/gu; +/** Control-sequence-introducer escapes such as SGR color codes. */ +const CSI_SEQUENCE = /(?:\u001B\[|\u009B)[0-?]*[ -/]*[@-~]/gu; +/** Remaining two-byte ESC control sequences. */ +const ESC_SEQUENCE = /\u001B[@-_]/gu; +/** Non-whitespace C0/C1 control characters. */ +const CONTROL_CHARACTER = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/gu; +/** Directional and invisible controls that can make a displayed title deceptive. */ +const DIRECTIONAL_CONTROL = /[\u200B\u200E\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF]/gu; +/** Reject an invalid public text limit. */ +function assertPositiveInteger(name, value) { + if (!Number.isInteger(value) || value <= 0) { + throw new Error(`${name} must be a positive integer`); + } +} +/** Remove controls and produce one trimmed, whitespace-normalized line. */ +function cleanTitleText(input) { + return input + .replace(OSC_SEQUENCE, '') + .replace(CSI_SEQUENCE, '') + .replace(ESC_SEQUENCE, '') + .replace(CONTROL_CHARACTER, '') + .replace(DIRECTIONAL_CONTROL, '') + .replace(/\s+/gu, ' ') + .trim(); +} +/** + * Truncate a string to a UTF-8 byte budget without splitting a Unicode code point. + * @param input - normalized title text. + * @param maxBytes - positive UTF-8 byte budget. + * @returns the longest leading code-point prefix within the budget. + */ +export function truncateTitleUtf8(input, maxBytes) { + assertPositiveInteger('maxBytes', maxBytes); + if (Buffer.byteLength(input, 'utf8') <= maxBytes) + return input; + let used = 0; + let output = ''; + for (const character of input) { + const bytes = Buffer.byteLength(character, 'utf8'); + if (used + bytes > maxBytes) + break; + output += character; + used += bytes; + } + return output; +} +/** + * Normalize one accepted session title and enforce its UTF-8 byte budget. + * @param input - untrusted title text. + * @param maxBytes - positive maximum encoded size. + * @returns a terminal-safe one-line title, possibly empty after sanitization. + */ +export function normalizeSessionTitle(input, maxBytes) { + return truncateTitleUtf8(cleanTitleText(input), maxBytes).trimEnd(); +} +/** + * Derive the deterministic first-prompt fallback. + * @param input - text from the first eligible human message. + * @param maxWords - positive whitespace-delimited word cap. + * @param maxBytes - positive UTF-8 byte cap. + * @returns the normalized leading words within both limits. + */ +export function fallbackSessionTitle(input, maxWords, maxBytes) { + assertPositiveInteger('maxWords', maxWords); + const words = cleanTitleText(input).split(' ').filter(Boolean).slice(0, maxWords); + return truncateTitleUtf8(words.join(' '), maxBytes).trimEnd(); +} +//# sourceMappingURL=normalize.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.d.ts new file mode 100644 index 0000000..6d0f49d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.d.ts @@ -0,0 +1,21 @@ +/** + * Pure types of the title domain: the ONE home of the `title` projection-key + * declaration, free of this package's host-side value imports (cordis + * service, schemastery, the llm seam). Two namespace projections serve it — + * `./types` for host consumers, `./client/types` (the browser half-entry's + * re-export) for client aggregates — with zero content duplication. + * + * @module @deepseek-ai/dsh-session-title/types + */ +export {}; +declare module '@deepseek-ai/dsh-session-projection/types' { + interface SessionProjectionMap { + /** + * The session's current normalized title — the latest `session/title` + * event's text (last-wins), or `null` before the first title lands. A + * plain string: the shape the client list rows consume. + */ + title: string | null; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.js new file mode 100644 index 0000000..c0a79a3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/lib/types/types.js @@ -0,0 +1,11 @@ +/** + * Pure types of the title domain: the ONE home of the `title` projection-key + * declaration, free of this package's host-side value imports (cordis + * service, schemastery, the llm seam). Two namespace projections serve it — + * `./types` for host consumers, `./client/types` (the browser half-entry's + * re-export) for client aggregates — with zero content duplication. + * + * @module @deepseek-ai/dsh-session-title/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/package.json new file mode 100644 index 0000000..48b8001 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title/package.json @@ -0,0 +1,65 @@ +{ + "name": "@deepseek-ai/dsh-session-title", + "description": "Log-backed session title service and provider registry for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session/session-title" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./client": { + "types": "./lib/types/client.d.ts", + "default": "./lib/types/client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + }, + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-session-persistence-sqlite": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.i18n.yaml new file mode 100644 index 0000000..b84b2b2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/session/README.md +README.md: 02aae21d71101e626bf2d2ead0bfd5d155723165 +README.zh.md: 2da8c5db8fe25d55faafdd6d44ea9090dd232576 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.md new file mode 100644 index 0000000..02aae21 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.md @@ -0,0 +1,144 @@ +# dsh-session + +English | [中文](README.zh.md) + +Event-sourced session log and in-memory store. A `Session` is the append-only source of truth for an agent's whole interaction history — the LLM message history is *derived* from it. A **surface** layer (an ordered projection of message-producing events) is maintained on top of the raw log for efficient derivation and compaction. + +The optional `@deepseek-ai/dsh-session/invariant` companion registers this package's relational trace checks with `ctx.invariants`: monotonic sequence numbers, turn/step enclosure, and same-step tool call/result pairing. It replays existing sessions when loaded or reloaded; storage validation, snapshotting, freezing, cited source-event validation, and surface acceptance remain always-on responsibilities of the root session package. + +## Service: `SessionStore` (ctx key: `sessions`) + +Creates and holds event-sourced `Session` instances. Persistence is intentionally not implemented here — plugins subscribe to `session/event`, flush on `session/flush`, and may mirror the paired `session/created`/`session/disposed` lifecycle. + +### Public API + +- `ctx.sessions.create(id?, { seed?, meta? }?)` validates and detaches durable seed/header data, fills the version and id, defaults `createdAt` to now, publishes the session, and binds it to the calling fiber. Persisted reconstruction supplies its original `createdAt`, `seedLength`, and `delegationDepth`. +- `ctx.sessions.flush(session)` dispatches the awaited parallel durability checkpoint through the session's captured scope. Every listener starts and the call waits for all to settle before reporting failure; unpublished, detached, and stale objects reject. +- `ctx.sessions.fork(source, boundary?, childSessionId?): Session` — Resolve a live session object or id, select a seed through the inclusive `boundary` event seq (default: current last event), require that prefix to end outside an open turn, and create a live child session with lineage metadata. +- `ctx.sessions.get(id: SessionId): Session | undefined` +- `ctx.sessions.list(): Session[]` + +#### Advanced: ordered-teardown lifecycle primitives + +Use the split lifecycle only when teardown must be ordered with another resource: + +- `prepare(id?, options?)` validates and constructs without publication. +- `enter(session)` performs the collision check, publishes without announcing, and returns an entry-bound idempotent detach. Concurrent same-id preparations are allowed, but only one entry succeeds; a stale detach cannot remove its replacement. +- `announce(session)` emits the single creation edge and rejects repeat or reentrant announcements. Detach during that dispatch is deferred and later emits the paired disposal edge; an unannounced entry emits neither lifecycle edge. + +`dsh-agent-loop` uses this split so final loop flush precedes session detach; see the [ownership Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.md). + +### Live service events + +The store pairs announced creation with disposal, publishes post-commit append notifications with per-listener containment, and provides an awaited durability checkpoint. Exact signatures and scope behavior live in the generated region of [session.md](../../../docs/subsystems/session.md#cordis-surface); payloads live in the [persistence catalog](../../../docs/persistence-catalog.md). + +### Class: `Session` + +Plain class (not a Cordis Service). Create live sessions through `ctx.sessions.create()` and detached replay or inspection sessions through `Session.create()`; the detached factory does not publish lifecycle events or bind the session to a fiber. + +- `session.append(type, data, opts?)` snapshots and freezes durable data and surface metadata, validates marker shape, cited source-event seqs, complete replacement coverage, and content-only single-result `tool/result` rewrites, commits synchronously, then notifies observers with independent failure containment. Reentrant attached-session appends reject, and runtime checks cover widened unions and loaded logs. +- `session.deriveMessages()` incrementally projects each new surface entry once and returns a fresh array over the complete identified, frozen messages stored by those entries. Assistant messages preserve the provider and model that produced them plus adapter-private replay state in their model source. A surface rewrite rebuilds the projection; there is no raw-log fallback. +- `session.deriveEventMessage(event)` is the canonical per-event projection used by reconstruction and request checks. +- `session.surface` exposes the readonly `SessionSurface` view owned by the session's single incremental surface manager; `replaceGeneration` changes on every committed rewrite. +- `session.events` is a cached frozen snapshot invalidated by append; accepted events remain deeply frozen. +- `session.seq`, `session.id` — current sequence and readonly typed identity. +- `session.header: SessionHeader` — detached, deep-frozen creation metadata (`version`, `id`, `createdAt`, optional `cwd`/`parentSession`/`seedLength`/`delegationDepth`). Construction validates the durable record and requires its id to match `session.id`. + +### Lossless JSON utilities + +Durable values need one accepted representation, not a check followed by a second read. `isJsonValue(value)` is the boolean predicate; `snapshotJsonValue(value)` iteratively validates and copies a plain value in one pass, returning `undefined` for invalid input and propagating a throwing getter. The snapshot helper accepts finite JSON numbers except `-0` (JSON rewrites it to `0`), dense ordinary arrays, and plain or null-prototype objects; it rejects cycles, unsupported scalars, and exotic prototypes before normalization without imposing a call-stack depth limit. + +Session-event import separates ownership from message validation. `snapshotSessionEvent(event)` clones a borrowed event before validating and freezing its identified message. `adoptSessionEvent(event)` performs the same message work in place and returns the original event; callers may use it only when they transfer an exclusively owned object graph with no mutable child shared with another event. + +### Chunk-row storage codec (`chunk-rows.ts`) + +The shared [storage codec](src/chunk-rows.ts) losslessly converts event sequences to compact rows and back. It preserves unrecognized events verbatim and rejects malformed encoded rows; persistence backends decide whether to enable packed writes. + +### Surface types + +This package owns ordered surface projection, replacement validation, replay, and the type guards that distinguish append-origin from replacement events. The [surface type catalog](../../../docs/subsystems/session.md#surface-types) owns the exact shapes and field semantics. A human transcript must project append-origin events rather than `session.surface`, because landed replacements shadow history the reader already saw; model-facing consumers continue to read `session.surface`. + +### Request-header reconstruction (`request-header.ts`) + +`request/header` records a full canonical snapshot of the non-history request envelope with reason `initial`, `resume`, or `change`. Its optional `adapterDefaults` map marks effective `reasoningEffort` or `maxTokens` values materialized by exact-model resolution, allowing the next request proposal to distinguish them from explicit conversation settings. `foldRequestHeader()` selects the latest snapshot; legacy delta events and the removed `fallback` reason are rejected. See the [reconstructable-requests Agent Note](../../../.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.md). + +A `user/message` stores the complete `UserMessage` directly, including the identity created before inbox routing or step entry. It renders its `content` verbatim whether it is a direct human prompt, a synthetic injection, or an entered goal round; its typed `source` is the only channel that tells them apart and carries any domain-specific durable facts. `assistant/message` and `tool/result` likewise store complete message values. Turn execution remains enclosed by `turn/start` and `turn/end`; `agent.inject()` queues input until a later pre-step claims it and returns it in an enter decision. + +`tool/result` persists one identified user-role tool-result message, optional internal failure identity, and optional presentation metadata. A tool's successful canonical `value` and human-readable canonical failure message remain execution-local; rendered error content is the replay-authoritative message. + +### Session event vocabulary (`types.ts`) + +The generated [persistence log event catalog](../../../docs/persistence-catalog.md) enumerates each append-only event type with its payload, surface badge, and declaration site. Token accounting reads per-step `assistant/chunk { type: 'usage' }` records and treats `assistant/message.usage` as the committed-step fallback when no usage chunk exists; failed model-request attempts have no assistant message. Each `assistant/message` records the provider, model, and optional replay state. + +Merge-extensible via `SessionEventMap` — a plugin declaration-merges its own types (the compaction seam's `compaction/*`, bounded recovery's non-surface `llm/retry`, the hook bridges' `hook/*`); merged members appear in the same catalog. A plugin owns the relational invariant for its merged events, including whether a log-only event may appear between turns. A producer that requires durability appends through `Session` and then awaits `ctx.sessions.flush(session)` without fabricating an execution turn. + +Also defines `TurnEndReasonMap`, the merge-extensible `kind`-tagged sum type for turn endings. `turn/start` carries only the turn number; the following entered `user/message` batch records its input, while `llm/retry` records request recovery. + +An interrupted live turn ends with `{ kind: 'aborted', reason: AgentCancelCause }`, preserving the typed cancellation cause in the durable transcript. Persistence imports the coarse aborted outcome from the supported older format as `{ kind: 'aborted', reason: { kind: 'legacy' } }`, because that record did not retain its caller. A turn failure carries `{ kind: 'error', error }`; crash recovery alone synthesizes `{ kind: 'interrupted' }`. + +Every `SessionEvent` carries three optional top-level fields (structural metadata): + +- `sourceEventSeqs?: number[]` — seq numbers of earlier events cited as sources (e.g., the `assistant/chunk` seqs behind an `assistant/message`, or the shadowed entries behind a compaction replacement entry). On `assistant/message`, a present `[]` records a known empty provider stream, while omission means a legacy or foreign event did not record the source stream; other surface events require a non-empty list when this field is present. +- `surfaceOp?: SurfaceOp` — how this event entered the surface. Absent for non-surface events (boundaries, chunks, usage, errors). +- `ignorable?: true` — marks an event a reader may safely skip when it does not recognize the type; absent means required, so an unknown-type event refuses session reconstruction ([mechanism](../../../.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md)). + +### Metadata types (`types.ts`) + +- `SessionHeader` — session metadata written once when published as `Session.header`, where detachment and deep-freezing enforce immutability at runtime: `{ version, id, createdAt, cwd?, parentSession?, seedLength?, delegationDepth? }`. Persistence loaders may return mutable detached copies of the same data type. Owned here (beside `SessionId`) because `Session.header` is typed by it; persistence backends re-export it rather than own it (which would force a package cycle). + +### Extension points + +- Persistence plugins: subscribe to `session/event` (write-behind) and drain on `session/flush` (awaited) and fiber dispose. A durable backend reads the log and reloads it into a live session; the metadata contract (`SessionHeader`, `session.header`) is what such a backend stores beside the log. +- Replay/fork: `create(id, { seed })` validates and freezes a contiguous current-format log and rebuilds its surface; request headers require provider/model, and assistant messages require provider/model provenance. Persistence owns read compatibility before constructing this current-format seed. `fork(source, boundary?, childSessionId?)` selects a completed-turn prefix and records lineage. +- Compaction: `dsh-compaction-basic` appends a `user/message` replacement for summary checkpoints, while `dsh-compaction-tool-result-pruner` appends a content-only `tool/result` replacement. Tool-pairing boundary policy and its cache belong to the [`dsh-compaction` seam](../../compaction/compaction/README.md), while this package owns ordered surface membership, replacement validation, and `replaceGeneration`. + +## Model Experience + +### Derived message history + +#### What the model sees + +The model receives the complete messages from `user/message`, `assistant/message`, and `tool/result` surface entries verbatim. Their identities, roles, sources, and content blocks are the same values established at creation; projections do not mint identities. A prompt envelope changes only human presentation; its prefix context and request delimiter are already present in the event content. Tool calls live inside assistant messages. Chunks, boundaries, usage, hook records, todo records, and other log-only events add no message. + +#### Token effect + +Appended surface entries are resent on later steps. A `replace` surface operation removes the shadowed entries from future inputs without deleting their raw log records. + +#### KV Cache effect + +Appended surface entries preserve reusable prefixes. A `replace` operation invalidates reuse from the first shadowed message even though the underlying event log stays append-only. + +### Crash-repair result + +#### What the model sees + +If recovery finds an assistant tool request with no durable `tool/call`, its synthetic `TOOL_NOT_STARTED` result says `The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed.` If a durable `tool/call` has no result, its `TOOL_OUTCOME_UNKNOWN` result says `The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly.` + +#### Token effect + +Zero tokens in an intact session. Each repaired call adds its retained risk-specific error text on resume. + +#### KV Cache effect + +Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries. + +### Logged request header + +#### What the model sees + +The session reconstructs the system prompt, tool schemas, call config, and session prefix that the loop actually sent. Header events do not add a second copy to message history; the prefix is prepended outside `deriveMessages()`. + +#### Token effect + +Zero duplicate tokens from logging. The reconstructed prefix, system text, and schemas still incur their normal per-request cost. + +#### KV Cache effect + +Logging causes no invalidation, and exact reconstruction preserves request-prefix identity. A later header with changed prefix, prompt, or schemas may invalidate reuse from its first difference. + +## Known Limitations and Deferred Work + +- **Session branching/tree** (pi-style entry tree) — deferred unless needed beyond boundary-based `fork()`. +- **`fork()` cuts only at stable boundaries of live sessions** — the selected prefix must end outside an open turn and the source must be in the store; forking a persisted-but-unloaded session is excluded from the [fork API](../../../.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.md). +- **`SESSION_FORMAT_VERSION` stays pinned at `0`** — pre-release, no broad compatibility implied: `Session` accepts only current seed shapes, and a backend refuses any other version naming the direction (newer: "written by a newer harness — upgrade"; older: no upgrade path ships yet). Unknown event types refuse the same way unless marked `ignorable` in the envelope; the versioning mechanism is the [session-log-version-mechanism note](../../../.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md). Narrow storage import upgrades belong to the persistence boundary ([policy](../../../AGENTS.md), [pre-identity message recovery](../../../.agents/notes/implemented/bug-fix/2026-07-28-load-pre-identity-session-messages.md)). +- **`TurnEndReasonMap` omits the ACP-named `refusal` / `max_turn_requests` variants** — producer-gated: they land when an adapter or the loop first emits them. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.zh.md new file mode 100644 index 0000000..2da8c5d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/README.zh.md @@ -0,0 +1,144 @@ +# dsh-session + +[English](README.md) | 中文 + +事件溯源的会话日志和内存存储。`Session` 是 agent(智能体)全部交互历史的仅追加真源,LLM(大语言模型)消息历史由它*派生*。原始日志之上维护一个 **surface** 层(产生消息事件的有序投影),以便高效派生和压缩(compaction)。 + +可选配套入口 `@deepseek-ai/dsh-session/invariant` 将此包的关系轨迹检查注册到 `ctx.invariants`:序号单调递增、轮次/步骤闭合,以及同一步骤内的工具调用/结果配对。加载或重新加载时,它会回放现有会话;存储校验、快照、冻结、被引用的源事件校验和 surface 准入仍始终由根会话包负责。 + +## 服务:`SessionStore`(ctx 键:`sessions`) + +创建并持有事件溯源的 `Session` 实例。这里有意不实现持久化:插件订阅 `session/event`,在 `session/flush` 时刷新,并可镜像成对的 `session/created`/`session/disposed` 生命周期。 + +### 公共 API + +- `ctx.sessions.create(id?, { seed?, meta? }?)` 校验持久种子/头部数据并生成脱离副本,补齐版本和 id,在未提供 `createdAt` 时使用当前时间,发布会话并将其绑定到调用方 fiber。持久化重建会提供原始的 `createdAt`、`seedLength` 和 `delegationDepth`。 +- `ctx.sessions.flush(session)` 通过会话捕获的作用域分发一个需等待完成的并行持久性检查点。每个监听器都会启动;调用会等待全部结算后才报告失败。未发布、已脱离和陈旧的对象会被拒绝。 +- `ctx.sessions.fork(source, boundary?, childSessionId?): Session`:解析实时会话对象或 id,选取截至 `boundary` 事件序号(含该事件)的种子(默认为当前最后一个事件),要求所选前缀结束时没有开放轮次,再创建带谱系元数据的实时子会话。 +- `ctx.sessions.get(id: SessionId): Session | undefined` +- `ctx.sessions.list(): Session[]` + +#### 高级:有序清理生命周期原语 + +仅在清理必须与另一项资源排序时使用拆分生命周期: + +- `prepare(id?, options?)` 校验并构造,但不发布。 +- `enter(session)` 执行冲突检查,在不通知的情况下发布,并返回一个绑定到该条目的幂等脱离函数。允许并发准备相同 id,但只有一个条目能够成功进入;陈旧的脱离函数无法移除其替代项。 +- `announce(session)` 发出唯一一次创建边,并拒绝重复或重入通知。该次分发期间请求的脱离操作会延后,之后再发出成对的释放边;未通知的条目不会发出任何生命周期边。 + +`dsh-agent-loop` 使用这一拆分,以保证循环的最终刷新先于会话脱离;详见[所有权 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.md)。 + +### 实时服务事件 + +会话存储会将已通知的创建与释放配对,在提交后发布追加通知并逐个监听器收容失败,同时提供受等待的持久性检查点。确切签名和作用域行为见 [session.md](../../../docs/subsystems/session.md#cordis-surface) 的生成区块;载荷见[持久化目录](../../../docs/persistence-catalog.md)。 + +### 类:`Session` + +普通类(不是 Cordis 服务)。活跃会话通过 `ctx.sessions.create()` 创建,脱离态的回放或检查会话通过 `Session.create()` 创建;脱离态工厂不会发布生命周期事件,也不会将会话绑定到 fiber。 + +- `session.append(type, data, opts?)` 会为持久数据和 surface 元数据制作快照并冻结它们,校验标记形态、被引用的源事件 seq、替换覆盖完整性,以及仅修改内容的单个 `tool/result` 重写,随后同步提交,再在彼此独立的失败收容下通知观察者。对已挂接会话的重入追加会被拒绝,运行时检查也覆盖扩宽后的联合类型和已加载日志。 +- `session.deriveMessages()` 对每个新的 surface 条目只做一次增量投影,并返回一个新数组,其中包含这些条目存储的完整、带标识且冻结的消息。assistant 消息的模型来源会保留生成该消息的提供方和模型,以及适配器私有回放状态。surface 重写会重建投影;不存在原始日志回退。 +- `session.deriveEventMessage(event)` 是重建和请求检查使用的规范逐事件投影。 +- `session.surface` 暴露只读 `SessionSurface` 视图,由会话唯一的增量 surface 管理器所有;每次提交重写,`replaceGeneration` 都会变化。 +- `session.events` 是按追加失效的缓存冻结快照;已接受事件保持深度冻结。 +- `session.seq`、`session.id`:当前序号和只读类型化身份。 +- `session.header: SessionHeader`:脱离、深冻结的创建元数据(`version`、`id`、`createdAt`,以及可选的 `cwd`/`parentSession`/`seedLength`/`delegationDepth`)。构造时会校验持久记录,并要求其中的 id 与 `session.id` 一致。 + +### 无损 JSON 工具 + +持久值需要一种已接受的表示,不能先检查再二次读取。`isJsonValue(value)` 是布尔判断函数;`snapshotJsonValue(value)` 在一趟迭代中校验并复制普通值,无效输入返回 `undefined`,getter 抛出的异常则向外传播。快照辅助函数接受除 `-0` 外的有限 JSON 数值(JSON 会将其改写为 `0`)、稠密普通数组、普通对象或 null 原型对象;它会在规范化前拒绝循环引用、不支持的标量和特殊原型,同时不施加调用栈深度限制。 + +会话事件导入将所有权与消息校验分开处理。`snapshotSessionEvent(event)` 会先克隆借用的事件,再校验并冻结其中带标识的消息。`adoptSessionEvent(event)` 原地执行相同的消息处理并返回原事件;调用方只有在移交独占的对象图,且该对象图没有与其他事件共享可变子对象时,才可以使用此函数。 + +### 分片行存储编解码器(`chunk-rows.ts`) + +共享的[存储编解码器](src/chunk-rows.ts)在事件序列与紧凑行之间无损转换。它会逐字保留无法识别的事件,并拒绝形态错误的编码行;是否启用打包写入由持久化后端决定。 + +### Surface 类型 + +此包拥有有序 surface 投影、替换校验、回放,以及区分追加来源事件与替换事件的类型守卫。[surface 类型目录](../../../docs/subsystems/session.md#surface-types)拥有精确形状与字段语义。面向人的 transcript(文本记录)必须投影追加来源事件,而不是 `session.surface`,因为已落地的替换会遮蔽读者已经看到的历史;面向模型的消费方继续读取 `session.surface`。 + +### 请求头重建(`request-header.ts`) + +`request/header` 记录非历史请求封装的完整规范快照,其原因为 `initial`、`resume` 或 `change`。其可选 `adapterDefaults` 映射会标记由精确模型解析填入的生效 `reasoningEffort` 或 `maxTokens` 值,使下一次请求提议能够将它们与显式对话设置区分开。`foldRequestHeader()` 选择最新快照;旧版增量事件和已移除的 `fallback` 原因会被拒绝。详见[可重建请求 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.md)。 + +`user/message` 会直接存储完整的 `UserMessage`,其中包括收件箱路由或进入步骤前创建的标识。无论它是直接人类提示词、合成注入,还是已进入的 Goal Round,都会原样呈现其 `content`;带类型的 `source` 是区分三者的唯一通道,并携带各领域专有的持久事实。`assistant/message` 和 `tool/result` 也会存储完整的消息值。轮次执行仍由 `turn/start` 与 `turn/end` 包围;`agent.inject()` 会把输入排队,直到后续某次 pre-step 领取它,并在 enter 决策中返回它。 + +`tool/result` 持久保存一条带标识、user-role 的工具结果消息,以及可选内部失败标识和可选呈现元数据。工具成功时的规范 `value` 和便于人类阅读的规范失败消息只存在于执行本地;渲染后的错误内容是回放权威消息。 + +### 会话事件词汇(`types.ts`) + +生成的[持久化日志事件目录](../../../docs/persistence-catalog.md)逐成员列举仅追加日志的事件类型、载荷、surface 标记与声明位置。Token 记账读取每个步骤的 `assistant/chunk { type: 'usage' }` 记录;如果没有用量分片,则将 `assistant/message.usage` 作为已提交步骤的后备。失败的模型请求尝试没有 assistant 消息。每条 `assistant/message` 都会记录提供方、模型和可选回放状态。 + +`SessionEventMap` 可通过合并扩展:插件使用声明合并添加自身类型(压缩 seam 的 `compaction/*`、有界恢复的非 surface `llm/retry`、钩子桥接层的 `hook/*`);合并成员会出现在同一目录中。插件拥有其合并事件的关系不变量,包括是否允许纯日志事件出现在轮次之间。需要持久性的生产方通过 `Session` 追加,再等待 `ctx.sessions.flush(session)`,无需虚构一个执行轮次。 + +此包还定义 `TurnEndReasonMap`,即用于轮次结束、可合并扩展且以 `kind` 为标签的和类型。`turn/start` 只携带轮次编号;随后已进入的 `user/message` 批次记录其输入,`llm/retry` 则记录请求恢复。 + +被中断的实时轮次以 `{ kind: 'aborted', reason: AgentCancelCause }` 结束,在持久 transcript 中保留类型化取消原因。持久化会将受支持旧格式中的粗粒度中止结果导入为 `{ kind: 'aborted', reason: { kind: 'legacy' } }`,因为该记录没有保留调用方。轮次失败携带 `{ kind: 'error', error }`;只有崩溃恢复会合成 `{ kind: 'interrupted' }`。 + +每个 `SessionEvent` 都有三个可选顶层字段(结构元数据): + +- `sourceEventSeqs?: number[]`:被引用为来源的较早事件 seq(例如 `assistant/message` 引用的 `assistant/chunk` seq,或压缩替换条目引用的已遮蔽条目)。对于 `assistant/message`,存在的 `[]` 表示已知提供方流为空;省略则表示旧版或外部事件没有记录源流。其他 surface 事件若有此字段,则要求非空列表。 +- `surfaceOp?: SurfaceOp`:事件进入 surface 的方式。非 surface 事件(边界、分片、用量、错误)不含该字段。 +- `ignorable?: true`:标记读取器在不认识事件类型时可以安全跳过该事件;缺失表示必需,不认识的事件类型会使会话重建被拒绝([机制](../../../.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md))。 + +### 元数据类型(`types.ts`) + +- `SessionHeader`:会话元数据,在发布为 `Session.header` 时写入一次;脱离和深冻结保证运行时不可变:`{ version, id, createdAt, cwd?, parentSession?, seedLength?, delegationDepth? }`。持久化 loader 可返回相同数据类型的可变脱离副本。该类型与 `SessionId` 一同归此包所有,因为 `Session.header` 以它为类型;持久化后端只是重新导出而不拥有它,否则会形成包循环依赖。 + +### 扩展点 + +- 持久化插件:订阅 `session/event`(延后写入),并在 `session/flush`(受等待)及 fiber dispose(资源释放)时排空。持久后端读取日志并重新加载到实时会话;这类后端会把元数据约定(`SessionHeader`、`session.header`)与日志一同存储。 +- 回放/fork:`create(id, { seed })` 校验并冻结连续的当前格式日志,再重建 surface;请求头必须包含提供方/模型,assistant 消息必须包含提供方/模型溯源信息。持久化层在构造该当前格式 seed 前负责读取兼容性处理。`fork(source, boundary?, childSessionId?)` 选择已完成轮次前缀并记录谱系。 +- 压缩:`dsh-compaction-basic` 为摘要检查点追加一个替换用 `user/message`,而 `dsh-compaction-tool-result-pruner` 追加仅修改内容的 `tool/result` 替换。工具配对边界策略及其缓存归 [`dsh-compaction` seam](../../compaction/compaction/README.md) 所有;此包拥有有序 surface 成员关系、替换校验与 `replaceGeneration`。 + +## 模型体验 + +### 派生消息历史 + +#### 模型看到的内容 + +模型会原样接收 `user/message`、`assistant/message` 和 `tool/result` surface 条目中的完整消息。其标识、角色、来源和内容块都与创建时确定的值相同;投影不会生成标识。提示词封装只改变面向人的呈现;其前缀上下文和请求分隔符已经位于事件内容中。工具调用包含在 assistant 消息内。分片、边界、用量、钩子记录、todo 记录以及其他仅日志事件不会添加消息。 + +#### Token 影响 + +追加的 surface 条目会在后续步骤中重新发送。`replace` surface 操作会从未来输入中移除被遮蔽条目,但不删除其原始日志记录。 + +#### KV Cache 影响 + +追加的 surface 条目会保留可复用前缀。即使底层事件日志保持仅追加,`replace` 操作也会从首条被遮蔽消息起使缓存复用失效。 + +### 崩溃修复结果 + +#### 模型看到的内容 + +如果恢复发现 assistant 工具请求没有持久 `tool/call`,其合成 `TOOL_NOT_STARTED` 结果内容为 `The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed.`。如果持久 `tool/call` 没有结果,其 `TOOL_OUTCOME_UNKNOWN` 结果内容为 `The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly.`。 + +#### Token 影响 + +未受损会话的 token 增量为零。恢复时,每个修复后的调用都会添加保留的、针对具体风险的错误文本。 + +#### KV Cache 影响 + +保持仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。 + +### 已记录的请求头 + +#### 模型看到的内容 + +会话会重建循环实际发送的系统提示词、工具 schema、调用配置和会话前缀。请求头事件不会向消息历史加入第二份副本;前缀在 `deriveMessages()` 外部前置。 + +#### Token 影响 + +日志记录不产生重复 token。重建的前缀、系统文本和 schema 仍会产生正常的逐请求开销。 + +#### KV Cache 影响 + +记录日志不会导致失效,精确重建会保持请求前缀一致。后续请求头若更改前缀、提示词或 schema,可能从第一处差异开始使复用失效。 + +## 已知限制与暂缓事项 + +- **会话分支/树结构**(pi 风格条目树):除非需要超越基于边界的 `fork()` 能力,否则暂缓。 +- **`fork()` 仅在实时会话的稳定边界处切分**:所选前缀结束时不得有开放轮次,且源会话必须位于存储中;[fork API](../../../.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.md) 不支持对已持久化但未加载的会话进行 fork。 +- **`SESSION_FORMAT_VERSION` 固定为 `0`**:预发布阶段不承诺广泛兼容性;`Session` 只接受当前 seed 形状,后端拒绝其他任何版本并说明方向(更新的版本提示"由更新的 harness 写入,请升级";更旧的版本说明尚无升级路径)。不认识的事件类型同样被拒绝,除非信封带 `ignorable` 标记;版本机制见 [session-log 版本机制 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md)。范围受限的存储导入升级应由持久化边界负责([政策](../../../AGENTS.md)、[消息标识机制引入前的消息恢复](../../../.agents/notes/implemented/bug-fix/2026-07-28-load-pre-identity-session-messages.md))。 +- **`TurnEndReasonMap` 不含 ACP(Agent Client Protocol)命名的 `refusal`/`max_turn_requests` 变体**:受生产方约束;只有当适配器或循环首次产生这些变体时才加入。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/index.js new file mode 100644 index 0000000..1102035 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/index.js @@ -0,0 +1,1886 @@ +import { Service } from "@deepseek-ai/cordis"; +import { isAbsolute } from "node:path"; +import { CallId, MessageId, assertNever, callConfigEquals, deepFreeze, freezeMessage } from "@deepseek-ai/dsh-llm"; +import { scopeOf, scopeTarget } from "@deepseek-ai/dsh-scope"; +//#region lib/types/types.js +/** +* Brand a string as a {@link SessionId}. +* @param id - the raw session id string. +* @returns the same string, branded (a compile-time cast — no runtime cost). +*/ +function SessionId(id) { + return id; +} +/** +* The on-disk session format version, stamped into every newly-written {@link SessionHeader} +* and enforced by every persistence backend on load. The single source of truth for the +* version — write sites and the load-time check all read it. +* While the harness is unreleased it is pinned at `0`: no compatibility is +* implied, incompatible logs are rejected, and no migration is provided. +* +* The version is a single monotonic integer with no major/minor split. Whether +* a bump is needed is decided by what the WRITER emits, never by what a newer +* reader can accept: bump exactly when an older runtime could no longer handle +* a new log with full semantic correctness ("parses without error" is not +* correctness — silently skipping content that shapes reconstruction is a +* wrong read). Only structural changes reach that bar: the header shape, the +* {@link SessionEvent} envelope, core event semantics, or the surface +* mechanism (the {@link SurfaceEventType} set and {@link SurfaceOp} variants). +* Adding an ordinary event type does not bump — the per-event +* {@link SessionEvent.ignorable} guard covers vocabulary growth instead. When +* in doubt, bump: a near-identity upgrade step is almost free, a missed bump +* makes older runtimes read new logs wrong silently. The full mechanism +* (upgrade-step chain, in-memory view conversion, migrate-on-continue) is +* recorded in the session-log-version-mechanism Agent Note +* (`.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md`). +*/ +const SESSION_FORMAT_VERSION = 0; +//#endregion +//#region lib/types/json.js +/** Lossless-JSON validation and detached snapshots for durable session data. @module @deepseek-ai/dsh-session/json */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const constructor = Object.getOwnPropertyDescriptor(prototype, "constructor")?.value; + if (typeof constructor !== "function") return false; + try { + return constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } catch { + return false; + } +} +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value) { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, "Object"); +} +/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, "Array")) return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === "object" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype); +} +/** Whether an object is a plain or null-prototype record from any JavaScript realm. */ +function hasPlainObjectPrototype(value) { + const prototype = Object.getPrototypeOf(value); + return prototype === null || typeof prototype === "object" && isIntrinsicObjectPrototype(prototype); +} +/** Return every JSON-visible object key, or reject own data JSON would discard. */ +function enumerableStringKeys(value) { + const keys = Reflect.ownKeys(value); + if (keys.some((key) => typeof key !== "string" || !Object.prototype.propertyIsEnumerable.call(value, key))) return void 0; + return keys; +} +/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */ +function walkJsonValue(value, detach) { + const ancestors = /* @__PURE__ */ new Set(); + let root; + const assign = (destination, item) => { + if (destination === void 0) return; + if (destination.kind === "root") root = item; + else if (destination.kind === "array") destination.target[destination.index] = item; + else Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true + }); + }; + const tasks = [{ + kind: "visit", + value, + ...detach ? { destination: { kind: "root" } } : {} + }]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "leave") { + ancestors.delete(task.source); + continue; + } + if (task.kind === "array-item") { + if (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return void 0; + tasks.push({ + kind: "visit", + value: task.source[task.index], + ...task.target === void 0 ? {} : { destination: { + kind: "array", + target: task.target, + index: task.index + } } + }); + continue; + } + if (task.kind === "object-property") { + tasks.push({ + kind: "visit", + value: task.source[task.key], + ...task.target === void 0 ? {} : { destination: { + kind: "object", + target: task.target, + key: task.key + } } + }); + continue; + } + const current = task.value; + if (current === null) { + assign(task.destination, null); + continue; + } + if (typeof current === "boolean" || typeof current === "string") { + assign(task.destination, current); + continue; + } + if (typeof current === "number") { + if (!Number.isFinite(current) || Object.is(current, -0)) return void 0; + assign(task.destination, current); + continue; + } + if (typeof current !== "object") return void 0; + if (ancestors.has(current)) return void 0; + if (Array.isArray(current)) { + if (!hasPlainArrayPrototype(current)) return void 0; + const length = current.length; + if (Reflect.ownKeys(current).length !== length + 1) return void 0; + const target = detach ? [] : void 0; + if (target !== void 0) assign(task.destination, target); + ancestors.add(current); + tasks.push({ + kind: "leave", + source: current + }); + for (let index = length - 1; index >= 0; index--) tasks.push({ + kind: "array-item", + source: current, + index, + ...target === void 0 ? {} : { target } + }); + continue; + } + if (!hasPlainObjectPrototype(current)) return void 0; + const keys = enumerableStringKeys(current); + if (keys === void 0) return void 0; + const target = detach ? {} : void 0; + if (target !== void 0) assign(task.destination, target); + ancestors.add(current); + tasks.push({ + kind: "leave", + source: current + }); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === void 0) return void 0; + tasks.push({ + kind: "object-property", + source: current, + key, + ...target === void 0 ? {} : { target } + }); + } + } + return detach ? root : true; +} +/** +* Validate and detach lossless JSON in one read per property, so a stateful +* getter cannot change between validation and copying. Traversal is iterative, +* so valid nesting is bounded by available memory rather than the JavaScript +* call stack. Accepts ordinary arrays, plain or null-prototype objects, and JSON +* scalars; rejects sparse, cyclic, exotic, negative-zero, and non-finite values. +* Getter throws propagate. +* +* @param value - the candidate value to validate and detach. +* @returns the detached snapshot, or `undefined` when the value is not +* losslessly JSON-serializable. +*/ +function snapshotJsonValue(value) { + return walkJsonValue(value, true); +} +/** +* Test the same lossless JSON boundary as {@link snapshotJsonValue} without +* detaching it. Only own enumerable string properties participate; `toJSON` +* is ignored and getters run, so persistence boundaries use the snapshotter. +* @param value - the candidate event data to test. +* @returns whether `value` survives JSON round-trip losslessly. +*/ +function isJsonValue(value) { + return walkJsonValue(value, false) === true; +} +//#endregion +//#region lib/types/surface.js +/** +* Surface layer on top of the session event log: an ordered view of events +* that produce LLM messages. The append-only log remains the source of truth. +* +* Browser-safe: web clients consume this subpath export, so it must stay free +* of `node:` imports (they break the vite bundle). +* +* @module @deepseek-ai/dsh-session/surface +*/ +/** Runtime counterpart of the message-producing event union. */ +const SURFACE_EVENT_TYPES = new Set([ + "user/message", + "assistant/message", + "tool/result" +]); +/** +* Whether an event type can join the model-visible surface. +* @param type - event type to test. +* @returns true for one of the three message-producing event types. +*/ +function isSurfaceEligibleType(type) { + return SURFACE_EVENT_TYPES.has(type); +} +/** +* Narrow an event to a surface-eligible event carrying its required marker. +* @param event - event to test. +* @returns true when both the type and marker identify a surface event. +*/ +function isSurfaceEvent(event) { + if (!SURFACE_EVENT_TYPES.has(event.type)) return false; + return event.surfaceOp !== void 0; +} +/** +* Narrow an event to an append-origin surface event: one that entered the +* surface at its own log position and was never itself a replacement copy. +* +* The model-visible surface deliberately shadows replaced ranges, so it is the +* wrong source for a human transcript — a landed replacement would erase +* conversation the user already saw. Append-origin events are that transcript's +* durable source material; replacement copies stay model-only. +* @param event - event to test. +* @returns true when the event appended to the surface tail. +*/ +function isAppendSurfaceEvent(event) { + return isSurfaceEvent(event) && event.surfaceOp === "append"; +} +/** +* Narrow an event to a surface replacement: a node that shadowed an existing +* surface range instead of appending to the tail. The counterpart of +* {@link isAppendSurfaceEvent} over the two {@link SurfaceOp} variants. +* @param event - event to test. +* @returns true when the event replaced a surface range. +*/ +function isReplacementSurfaceEvent(event) { + return isSurfaceEvent(event) && event.surfaceOp !== "append"; +} +/** +* Project a single event into the LLM message it derives to, or null when it +* produces none — a non-surface event (chunk, boundary, log-only record) or an +* empty-content assistant/message (which exists only to host usage). This is +* THE per-node projection rule: `Session.deriveMessages` folds it over the +* live surface, external reconstructors and pure projections fold the same +* function over a log prefix's surface to rebuild the exact messages any +* request was built from. The returned message is the already frozen message +* nested in the event wrapper and shared by delivery, durable history, and +* model requests. +* @param event - the event to project. +* @returns the derived message, or null when the event produces none. +*/ +function deriveEventMessage(event) { + switch (event.type) { + case "user/message": return event.data; + case "assistant/message": + if (event.data.message.content.length === 0) return null; + return event.data.message; + case "tool/result": return event.data.message; + default: return null; + } +} +/** Create an empty surface fold state. */ +function createFoldState() { + return { + nodes: [], + replaceGeneration: 0 + }; +} +/** Whether a runtime value is a non-negative safe event sequence. */ +function isEventSeq(value) { + return typeof value === "number" && Number.isSafeInteger(value) && value >= 0; +} +/** Whether a runtime value is the exact positional-replacement shape. */ +function isReplaceOp(value) { + const op = value; + return Object.keys(op).length === 3 && Object.hasOwn(op, "op") && Object.hasOwn(op, "start") && Object.hasOwn(op, "end") && op["op"] === "replace" && isEventSeq(op["start"]) && isEventSeq(op["end"]); +} +/** Validate event-local surface eligibility and return its operation. */ +function surfaceOpOf(event) { + const raw = event; + if (!isSurfaceEligibleType(event.type)) { + if (raw.surfaceOp !== void 0) throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry surfaceOp`); + if (raw.sourceEventSeqs !== void 0) throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry sourceEventSeqs`); + return; + } + const op = raw.surfaceOp; + if (op === void 0) throw new Error(`session event "${event.type}" is surface-eligible and requires a surfaceOp marker`); + if (op === "append") return op; + if (op === null || typeof op !== "object" || Array.isArray(op)) throw new Error(`session event "${event.type}" carries an invalid surfaceOp`); + if (!isReplaceOp(op)) throw new Error(`session event "${event.type}" carries an invalid replace surfaceOp`); + return op; +} +/** Validate cited source-event seqs against prior log entries and the replacement range. */ +function assertProvenance(event, shadowedSeqs) { + const raw = event.sourceEventSeqs; + const sources = /* @__PURE__ */ new Set(); + if (raw !== void 0) { + if (!Array.isArray(raw)) throw new Error(`sourceEventSeqs on event at seq ${event.seq} must be an array when present`); + if (raw.length === 0 && event.type !== "assistant/message") throw new Error("sourceEventSeqs must not be empty except on assistant/message"); + let nonEarlierSource; + for (const source of raw) { + if (!isEventSeq(source)) throw new Error(`session event "${event.type}" sourceEventSeqs must densely contain non-negative safe integers`); + sources.add(source); + if (nonEarlierSource === void 0 && source >= event.seq) nonEarlierSource = source; + } + if (sources.size !== raw.length) throw new Error("sourceEventSeqs must not contain duplicates"); + if (nonEarlierSource !== void 0) throw new Error(`sourceEventSeqs must reference earlier events: ${nonEarlierSource} >= current seq ${event.seq}`); + } + const missing = shadowedSeqs.filter((seq) => !sources.has(seq)); + if (missing.length > 0) throw new Error(`surface replace: sourceEventSeqs must include every shadowed surface node; missing ${missing.join(", ")}`); +} +/** Locate one replacement range without mutating the current fold state. */ +function replacementRange(state, op) { + const startIdx = state.nodes.indexOf(op.start); + if (startIdx === -1) throw new Error(`surface replace: start seq ${op.start} not found in surface`); + const endIdx = state.nodes.indexOf(op.end); + if (endIdx === -1) throw new Error(`surface replace: end seq ${op.end} not found in surface`); + if (startIdx > endIdx) throw new Error(`surface replace: start seq ${op.start} (index ${startIdx}) is after end seq ${op.end} (index ${endIdx})`); + return { + startIdx, + endIdx, + shadowedSeqs: state.nodes.slice(startIdx, endIdx + 1) + }; +} +/** +* Deep structural equality over the session-event JSON value domain +* (null/boolean/number/string, arrays, plain objects). Replaces +* `node:util`'s isDeepStrictEqual to keep this module browser-safe. +*/ +function isDeepEqualJson(a, b) { + if (a === b) return true; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false; + return a.every((item, i) => isDeepEqualJson(item, b[i])); + } + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false; + const aKeys = Object.keys(a); + const bRecord = b; + if (aKeys.length !== Object.keys(b).length) return false; + return aKeys.every((key) => Object.hasOwn(b, key) && isDeepEqualJson(a[key], bRecord[key])); +} +/** Restrict a tool-result replacement to one current result's content. */ +function assertToolResultRewrite(event, shadowedSeqs, events, baseSeq) { + if (event.type !== "tool/result") return; + if (shadowedSeqs.length !== 1) throw new Error("tool/result surface replacement must rewrite exactly one current node"); + for (const originalSeq of shadowedSeqs) { + const original = events[originalSeq - baseSeq]; + if (original?.type !== "tool/result") throw new Error("tool/result surface replacement must target a current tool/result"); + const originalRest = { ...original.data }; + const replacementRest = { ...event.data }; + const originalResult = original.data.message.content[0]; + const replacementResult = event.data.message.content[0]; + originalRest["message"] = { + ...original.data.message, + content: [{ + ...originalResult, + content: null + }] + }; + replacementRest["message"] = { + ...event.data.message, + content: [{ + ...replacementResult, + content: null + }] + }; + if (!isDeepEqualJson(originalRest, replacementRest)) throw new Error("tool/result surface replacement may change only content"); + } +} +/** Validate one event at its replay boundary and prepare its atomic fold transition. */ +function planSurfaceEvent(state, event, expectedSeq, events, baseSeq) { + if (event.seq !== expectedSeq) throw new Error(`session event seq ${event.seq} is not contiguous; expected ${expectedSeq}`); + const surfaceOp = surfaceOpOf(event); + if (surfaceOp === void 0) return; + if (surfaceOp === "append") { + assertProvenance(event, []); + return { + kind: "append", + seq: event.seq + }; + } + const range = replacementRange(state, surfaceOp); + assertProvenance(event, range.shadowedSeqs); + assertToolResultRewrite(event, range.shadowedSeqs, events, baseSeq); + return { + kind: "replace", + seq: event.seq, + start: surfaceOp.start, + end: surfaceOp.end, + ...range + }; +} +/** Apply one event and return replacement metadata only when one occurred. */ +function applySurfaceEvent(state, event, expectedSeq, events, baseSeq) { + return applySurfacePlan(state, planSurfaceEvent(state, event, expectedSeq, events, baseSeq)); +} +/** Commit one previously validated surface transition. */ +function applySurfacePlan(state, plan) { + if (plan?.kind === "append") state.nodes.push(plan.seq); + else if (plan?.kind === "replace") { + state.nodes.splice(plan.startIdx, plan.endIdx - plan.startIdx + 1, plan.seq); + state.replaceGeneration += 1; + } + if (plan?.kind !== "replace") return; + return { + seq: plan.seq, + start: plan.start, + end: plan.end, + shadowedSeqs: plan.shadowedSeqs + }; +} +/** +* Replay a complete session log through the canonical surface fold. +* @param events - session events in contiguous seq order. +* @returns detached current sequences and replacement history. +* @throws when an event violates surface metadata, source-event references, range, or tool-result rewrite rules. +*/ +function foldSurface(events) { + const state = createFoldState(); + const replacements = []; + for (const [index, event] of events.entries()) { + const replacement = applySurfaceEvent(state, event, index, events, 0); + if (replacement !== void 0) replacements.push(replacement); + } + return { + nodes: [...state.nodes], + replacements + }; +} +/** Incremental ordered surface view and append-boundary validator. */ +var SurfaceManager = class { + log; + baseSeq; + /** Shared transition state; replacement history is not retained. */ + _state = createFoldState(); + /** Last processed absolute seq. */ + _lastProcessedSeq; + /** Candidate already validated by `validateNext`, pending exact log admission. */ + _pendingPlan; + /** + * @param log - Contiguous complete log or loaded event window. + * @param baseSeq - Absolute sequence of the window's first event. + */ + constructor(log, baseSeq = 0) { + this.log = log; + this.baseSeq = baseSeq; + this._lastProcessedSeq = baseSeq - 1; + } + /** + * Validate the next candidate without mutating the committed surface. + * @param event - candidate event that has not entered the log yet. + */ + validateNext(event) { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta(); + const expectedSeq = this.baseSeq + this.log.length; + this._pendingPlan = { + event, + expectedSeq, + plan: planSurfaceEvent(this._state, event, expectedSeq, this.log, this.baseSeq) + }; + } + /** Monotonic count of folded positional replacements. */ + get replaceGeneration() { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta(); + return this._state.replaceGeneration; + } + /** Surface event sequences in model-visible order. */ + get nodes() { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta(); + return this._state.nodes; + } + /** Fold events appended since the previous access. */ + _processDelta() { + const tailSeq = this.baseSeq + this.log.length - 1; + for (let seq = this._lastProcessedSeq + 1; seq <= tailSeq; seq++) { + const index = seq - this.baseSeq; + const event = this.log[index]; + const pending = this._pendingPlan; + if (pending?.event === event && pending.expectedSeq === seq) applySurfacePlan(this._state, pending.plan); + else applySurfaceEvent(this._state, event, seq, this.log, this.baseSeq); + if (pending !== void 0 && pending.expectedSeq <= seq) this._pendingPlan = void 0; + this._lastProcessedSeq = seq; + } + } +}; +//#endregion +//#region lib/types/request-header.js +/** +* Request-header reconstruction utilities over full `request/header` session +* events. Anyone holding a session log reconstructs the {@link EpochHeader} +* any request was built under by taking the latest canonical snapshot; the +* loop uses the same equality helper to avoid logging unchanged headers. +* +* @module dsh-session/request-header +*/ +/** +* Normalize a header to canonical form: an empty system prompt and empty tool +* list become absent fields, matching how requests are built. Logging, folding, +* and comparison use this one representation. +* @param header - the header to normalize (not mutated). +* @returns the canonical header. +*/ +function canonicalHeader(header) { + const adapterDefaults = header.adapterDefaults; + return { + config: header.config, + ...adapterDefaults?.reasoningEffort === true || adapterDefaults?.maxTokens === true ? { adapterDefaults } : {}, + ...header.system !== void 0 && header.system.length > 0 ? { system: header.system } : {}, + ...header.tools !== void 0 && header.tools.length > 0 ? { tools: header.tools } : {} + }; +} +/** Canonical JSON equality for tool schemas assembled through the same path. */ +function sameSchema(a, b) { + return JSON.stringify(a) === JSON.stringify(b); +} +/** +* Field-wise equality over canonical headers. Tool schemas compare in order. +* @param a - one canonical header. +* @param b - the other. +* @returns whether config, system, and tools all match. +*/ +function headerEquals(a, b) { + if (!callConfigEquals(a.config, b.config) || a.adapterDefaults?.reasoningEffort !== b.adapterDefaults?.reasoningEffort || a.adapterDefaults?.maxTokens !== b.adapterDefaults?.maxTokens || a.system !== b.system) return false; + const at = a.tools ?? []; + const bt = b.tools ?? []; + return at.length === bt.length && at.every((tool, i) => sameSchema(tool, bt[i])); +} +/** +* Fold the header events of a log (or any prefix) into the +* {@link EpochHeader} in force after the last snapshot. Non-header events are +* skipped. This is the pure offline reconstruction path; the live session +* tracks the same fold incrementally. +* @param events - session events in log order. +* @param from - a previously folded state to continue from. +* @returns the latest canonical header, or undefined when none exists yet. +*/ +function foldRequestHeader(events, from) { + let state = from; + for (const event of events) if (event.type === "request/header") state = canonicalHeader(event.data.header); + return state; +} +//#endregion +//#region lib/types/preparation.js +/** +* Ownership of one unpublished Session before registry publication. +* @module @deepseek-ai/dsh-session/preparation +*/ +/** +* One exact unpublished Session and the provider state that keeps it usable. +* Disposal is synchronous and idempotent. Providers decide whether release +* returns the Session to a cache or discards it; publication may consume that +* state before disposal, making the callback a no-op. +*/ +var SessionPreparation = class SessionPreparation { + options; + released = false; + /** The exact Session to use for setup and publication. */ + session; + constructor(session, options) { + this.options = options; + this.session = session; + } + /** + * Wrap an unpublished Session in one preparation lifetime. + * @param session - exact unpublished Session. + * @param options - optional provider release behavior. + * @returns a preparation disposed after publication or rollback. + */ + static create(session, options) { + return new SessionPreparation(session, options ?? {}); + } + /** Release provider state once when this preparation leaves its caller. */ + [Symbol.dispose]() { + if (this.released) return; + this.released = true; + this.options.release?.(); + } +}; +//#endregion +//#region lib/types/repair.js +/** +* Crash-recovery repair for an interrupted session log. It preserves a fully +* written final turn and supplies the missing tool, step, and turn boundaries +* needed to resume with a provider-valid transcript. +* @module @deepseek-ai/dsh-session/repair +*/ +/** Recovery code for an assistant tool request that never reached a recorded call start. */ +const TOOL_NOT_STARTED = "TOOL_NOT_STARTED"; +/** Recovery code for a recorded tool call whose completed outcome was not durably recorded. */ +const TOOL_OUTCOME_UNKNOWN = "TOOL_OUTCOME_UNKNOWN"; +/** +* Return deterministic synthetic events that close an open tail turn. Unmatched +* calls receive error results first, followed by an open `step/end` and an +* interrupted `turn/end`; sequences continue the log and timestamps reuse the +* last real event. A balanced or empty log returns no events. +* +* @param events - the loaded durable log to scan (a valid committed prefix, possibly with a crash tail). +* @returns the synthetic closer events to append after `events`, in order; empty when the log is already balanced. +*/ +function interruptedTurnClosers(events) { + let openTurn = null; + let openStep = null; + const pendingCalls = /* @__PURE__ */ new Map(); + for (const event of events) switch (event.type) { + case "turn/start": + openTurn = event.data.turn; + openStep = null; + pendingCalls.clear(); + break; + case "turn/end": + openTurn = null; + openStep = null; + pendingCalls.clear(); + break; + case "step/start": + openStep = event.data.step; + break; + case "step/end": + pendingCalls.clear(); + openStep = null; + break; + case "assistant/message": + for (const block of event.data.message.content) if (block.type === "tool-call") pendingCalls.set(block.id, { step: event.data.step }); + break; + case "tool/call": + { + const entry = pendingCalls.get(event.data.callId); + if (entry) entry.callSeq = event.seq; + } + break; + case "tool/result": + pendingCalls.delete(event.data.message.source.callId); + break; + default: break; + } + const last = events.at(-1); + if (openTurn === null || last === void 0) return []; + let seq = last.seq + 1; + const time = last.time; + const closers = []; + for (const [callId, { step, callSeq }] of pendingCalls) { + const started = callSeq !== void 0; + const message = freezeMessage({ + id: MessageId(`interrupted-tool-result-${callId}-${seq}`), + role: "user", + source: { + kind: "tool", + callId + }, + content: [{ + type: "tool-result", + toolCallId: callId, + isError: true, + content: [{ + type: "text", + text: started ? "The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly." : "The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed." + }] + }] + }); + closers.push({ + type: "tool/result", + seq: seq++, + time, + data: { + turn: openTurn, + step, + message, + error: started ? { + name: "ToolOutcomeUnknownError", + code: TOOL_OUTCOME_UNKNOWN + } : { + name: "ToolNotStartedError", + code: TOOL_NOT_STARTED + } + }, + surfaceOp: "append", + ...started ? { sourceEventSeqs: [callSeq] } : {} + }); + } + if (openStep !== null) closers.push({ + type: "step/end", + seq: seq++, + time, + data: { + turn: openTurn, + step: openStep + } + }); + closers.push({ + type: "turn/end", + seq: seq++, + time, + data: { + turn: openTurn, + reason: { kind: "interrupted" } + } + }); + return closers; +} +//#endregion +//#region lib/types/chunk-rows.js +/** +* Lossless storage packing for `assistant/chunk` delta runs. Providers stream +* token-sized deltas, so a log stores hundreds of near-identical event lines +* whose JSON envelopes dwarf their payloads (~56× measured on a real DeepSeek +* session). This module packs each run of consecutive same-block delta chunks +* into ONE storage row — `text-chunks`, `reasoning-chunks`, or +* `tool-call-chunks` — and expands rows back to the exact original events. +* +* Storage rows are a durable-encoding vocabulary, NOT session events: they +* never enter `Session.events`, have no `SessionEventMap` entry, and use bare +* (slash-less) type tags so a reader cannot confuse them with the event +* taxonomy (precedent: the JSONL header line's `session` tag). The encoder +* whitelists exact shapes — anything it does not fully recognize is stored +* verbatim, so unknown fields or future chunk variants lose compression, never +* data. The decoder validates before expanding and fails loud on a malformed +* row-tagged value instead of silently dropping a whole run. +* +* @module @deepseek-ai/dsh-session/chunk-rows +*/ +/** +* Minimum members before a run packs. Below it a row's envelope rivals the +* event lines it replaces. A format constant, not a tunable: both layouts +* decode identically, so changing it never invalidates stored logs. +*/ +const MIN_RUN = 3; +function isRecord(value) { + return typeof value === "object" && value !== null; +} +/** Exact-key check: `value` has every key in `keys` and nothing else. */ +function hasExactKeys(value, keys) { + return Object.keys(value).length === keys.length && keys.every((k) => Object.hasOwn(value, k)); +} +/** +* Classify an event for packing: its delta kind when the ENTIRE shape +* (envelope, data, chunk — exact keys, primitive types, integer seq/time) is +* whitelisted, else `undefined` (store verbatim). Inputs come from live typed +* appends AND parsed fixture files, so the checks are structural, not +* type-trusted. Integer times keep gap encoding exact: a fractional time would +* reconstruct through float subtraction/addition, which need not round-trip. +*/ +function classify(event) { + if (event.type !== "assistant/chunk") return void 0; + if (!hasExactKeys(event, [ + "type", + "seq", + "time", + "data" + ])) return void 0; + if (!Number.isSafeInteger(event.seq) || event.seq < 0 || !Number.isSafeInteger(event.time)) return void 0; + const data = event.data; + if (!isRecord(data) || !hasExactKeys(data, [ + "turn", + "step", + "chunk" + ])) return void 0; + if (typeof data.turn !== "number" || typeof data.step !== "number") return void 0; + const chunk = data.chunk; + if (!isRecord(chunk) || typeof chunk.index !== "number") return void 0; + switch (chunk.type) { + case "text-delta": + case "reasoning-delta": return hasExactKeys(chunk, [ + "type", + "index", + "text" + ]) && typeof chunk.text === "string" ? chunk.type : void 0; + case "tool-call-delta": return (hasExactKeys(chunk, [ + "type", + "index", + "id", + "argumentsDelta" + ]) || hasExactKeys(chunk, [ + "type", + "index", + "id", + "name", + "argumentsDelta" + ]) && typeof chunk.name === "string") && typeof chunk.id === "string" && typeof chunk.argumentsDelta === "string" ? chunk.type : void 0; + default: return; + } +} +/** The tool-call fields of a whitelisted delta chunk (only after {@link classify} returned `'tool-call-delta'`). */ +function toolCallOf(event) { + return event.data.chunk; +} +/** The block index of a whitelisted delta chunk (not every {@link StreamChunk} variant carries one). */ +function indexOf(event) { + return event.data.chunk.index; +} +/** Whether `next` extends a run ending in `prev` (same kind already checked by the caller). */ +function continues(prev, next, kind) { + if (next.seq !== prev.seq + 1) return false; + if (!Number.isSafeInteger(next.time - prev.time)) return false; + if (next.data.turn !== prev.data.turn || next.data.step !== prev.data.step) return false; + if (indexOf(next) !== indexOf(prev)) return false; + if (kind !== "tool-call-delta") return true; + const a = toolCallOf(prev); + const b = toolCallOf(next); + return a.id === b.id && Object.hasOwn(a, "name") === Object.hasOwn(b, "name") && a.name === b.name; +} +/** Build the row for a completed run (`run.length >= MIN_RUN`, uniform per {@link continues}). */ +function buildRow(kind, run) { + const first = run[0]; + const base = { + turn: first.data.turn, + step: first.data.step, + index: indexOf(first), + dt: run.slice(1).map((event, i) => event.time - run[i].time) + }; + const envelope = { + seq0: first.seq, + time0: first.time + }; + if (kind === "tool-call-delta") { + const call = toolCallOf(first); + return { + type: "tool-call-chunks", + ...envelope, + data: { + ...base, + id: CallId(call.id), + ...Object.hasOwn(call, "name") ? { name: call.name } : {}, + args: run.map((event) => event.data.chunk.argumentsDelta) + } + }; + } + const data = { + ...base, + texts: run.map((event) => event.data.chunk.text) + }; + return kind === "text-delta" ? { + type: "text-chunks", + ...envelope, + data + } : { + type: "reasoning-chunks", + ...envelope, + data + }; +} +/** +* Pack an event batch for storage: each run of at least {@link MIN_RUN} +* consecutive whitelisted same-kind, same-block delta chunk events becomes one +* {@link ChunkRow}; every other event passes through verbatim, in order. +* Pure and stateless — safe over any array, including a batch whose runs were +* split by flush boundaries (the split runs simply pack per batch). +* +* @param events - the batch to encode, in log order. +* @returns the storage records to write, one JSONL line each. +*/ +function packChunkRuns(events) { + const out = []; + let kind; + let run = []; + const flush = () => { + if (kind !== void 0 && run.length >= MIN_RUN) out.push(buildRow(kind, run)); + else out.push(...run); + kind = void 0; + run = []; + }; + for (const event of events) { + const k = classify(event); + if (k === void 0) { + flush(); + out.push(event); + continue; + } + const delta = event; + const last = run[run.length - 1]; + if (k === kind && last !== void 0 && continues(last, delta, k)) { + run.push(delta); + continue; + } + flush(); + kind = k; + run = [delta]; + } + flush(); + return out; +} +/** Throw the uniform malformed-row diagnostic. */ +function malformed(tag, why) { + throw new Error(`malformed ${tag} storage row: ${why}`); +} +/** Validate the shared run-data fields and the payload/dt arity; returns the member payload. */ +function validateRunData(tag, data, payloadKey) { + if (typeof data.turn !== "number" || typeof data.step !== "number" || typeof data.index !== "number") malformed(tag, "turn/step/index must be numbers"); + const payload = data[payloadKey]; + if (!Array.isArray(payload) || payload.length === 0 || payload.some((entry) => typeof entry !== "string")) malformed(tag, `${payloadKey} must be a non-empty string array`); + const dt = data.dt; + if (!Array.isArray(dt) || dt.some((gap) => !Number.isSafeInteger(gap))) malformed(tag, "dt must be an array of safe integers"); + if (dt.length !== payload.length - 1) malformed(tag, `dt length ${dt.length} does not match ${payload.length} members`); + return payload; +} +/** Validate a row-tagged parsed value's envelope and data, throwing on any malformation. */ +function validateRow(value, tag) { + if (!hasExactKeys(value, [ + "type", + "seq0", + "time0", + "data" + ])) malformed(tag, "envelope must be exactly {type, seq0, time0, data}"); + if (!Number.isSafeInteger(value.seq0) || value.seq0 < 0) malformed(tag, "seq0 must be a non-negative safe integer"); + if (!Number.isSafeInteger(value.time0)) malformed(tag, "time0 must be a safe integer"); + const data = value.data; + if (!isRecord(data)) malformed(tag, "data must be an object"); + let payload; + if (tag === "tool-call-chunks") { + const withName = hasExactKeys(data, [ + "turn", + "step", + "index", + "id", + "name", + "dt", + "args" + ]); + if (!withName && !hasExactKeys(data, [ + "turn", + "step", + "index", + "id", + "dt", + "args" + ])) malformed(tag, "data must be exactly {turn, step, index, id, name?, dt, args}"); + if (typeof data.id !== "string" || withName && typeof data.name !== "string") malformed(tag, "id (and name when present) must be strings"); + payload = validateRunData(tag, data, "args"); + } else { + if (!hasExactKeys(data, [ + "turn", + "step", + "index", + "dt", + "texts" + ])) malformed(tag, "data must be exactly {turn, step, index, dt, texts}"); + payload = validateRunData(tag, data, "texts"); + } + if (!Number.isSafeInteger(value.seq0 + payload.length - 1)) malformed(tag, "member seqs must stay safe integers"); + let time = value.time0; + for (const gap of data.dt) { + time += gap; + if (!Number.isSafeInteger(time)) malformed(tag, "member times must stay safe integers"); + } + return value; +} +/** Expand a validated row back into its exact original events, in order. */ +function expandRow(row) { + const members = row.type === "tool-call-chunks" ? row.data.args : row.data.texts; + const events = []; + let time = row.time0; + for (let k = 0; k < members.length; k++) { + if (k > 0) time += row.data.dt[k - 1]; + let chunk; + switch (row.type) { + case "text-chunks": + chunk = { + type: "text-delta", + index: row.data.index, + text: members[k] + }; + break; + case "reasoning-chunks": + chunk = { + type: "reasoning-delta", + index: row.data.index, + text: members[k] + }; + break; + case "tool-call-chunks": + chunk = { + type: "tool-call-delta", + index: row.data.index, + id: row.data.id, + ...Object.hasOwn(row.data, "name") ? { name: row.data.name } : {}, + argumentsDelta: members[k] + }; + break; + /* v8 ignore next 2 -- validateRow only returns the three row tags */ + default: return assertNever(row, "chunk-rows expandRow"); + } + events.push({ + type: "assistant/chunk", + seq: row.seq0 + k, + time, + data: { + turn: row.data.turn, + step: row.data.step, + chunk + } + }); + } + return events; +} +/** +* Decode one parsed JSONL line value into the session event(s) it stores. +* Chunk-row-tagged values validate and expand (a malformed row throws — it is +* corrupt storage, and treating it as an event would silently drop a whole +* run); every other value passes through as a single event, unvalidated. +* +* @param value - one line's `JSON.parse` result. +* @returns the stored events, in log order. +*/ +function decodeStorageRecord(value) { + if (!isRecord(value)) return [value]; + const tag = value.type; + if (tag !== "text-chunks" && tag !== "reasoning-chunks" && tag !== "tool-call-chunks") return [value]; + return expandRow(validateRow(value, tag)); +} +//#endregion +//#region lib/types/known-event-types.js +/** +* GENERATED by `scripts/gen-persistence-catalog.ts` — do not edit by hand; run +* `pnpm run gen-persistence-catalog` to regenerate (verified fresh by +* `pnpm run verify-persistence-catalog`, part of `doc-sync`). +* @module @deepseek-ai/dsh-session/known-event-types +*/ +/** +* Every `SessionEventMap` member declared in this repository — the event +* vocabulary this build understands. The persistence read path refuses to +* interpret a log containing a type outside this set unless the event +* carries the envelope's `ignorable` marker (see `SessionEvent.ignorable` +* in `./types.ts`): such a log was likely written by a newer harness, and +* silently skipping a required event would reconstruct a wrong session. +* Downstream (out-of-repo) plugin events are outside this list by +* construction; a registration surface for them is deferred until such a +* consumer exists. +*/ +const KNOWN_SESSION_EVENT_TYPES = new Set([ + "agent-preset/selected", + "agent/inbox/spliced", + "approval/asked", + "approval/decided", + "approval/policy", + "assistant/chunk", + "assistant/message", + "command/done", + "command/run", + "compaction/end", + "compaction/prune", + "compaction/start", + "compaction/summary", + "feedback/record", + "goal/change", + "hook/invoked", + "hook/result", + "llm/retry", + "llm/retry-started", + "permission/preset", + "plan/mode", + "request/context", + "request/header", + "sandbox/mode", + "schedule/change", + "session/end-seed", + "session/title", + "session/title-llm-request", + "step/end", + "step/start", + "subagent/descriptor", + "todo/write", + "tool-workflow/agent-end", + "tool-workflow/agent-start", + "tool-workflow/run-end", + "tool-workflow/run-start", + "tool/call", + "tool/code-dispatch", + "tool/code-dispatch-start", + "tool/result", + "turn/end", + "turn/start", + "user/message", + "web/deepseek-search-llm-request" +]); +//#endregion +//#region lib/types/index.js +/** +* Event-sourced session service: append-only session log, in-memory store, and +* the derived LLM message history. Persistence is a plugin concern (subscribe +* to `session/event`, drain on `session/flush`). +* +* @module @deepseek-ai/dsh-session +*/ +/** Validate and freeze one detached creation header in place. */ +function validateSessionHeader(id, input) { + if (input === null || typeof input !== "object" || Array.isArray(input)) throw new Error("session header is not a plain JSON record"); + const record = input; + if (record.version !== 0) throw new Error(`session header version must be 0, got ${String(record.version)}`); + if (record.id !== id) throw new Error(`session header id "${String(record.id)}" does not match session id "${id}"`); + if (typeof record.createdAt !== "number" || !Number.isSafeInteger(record.createdAt) || record.createdAt < 0) throw new Error("session header createdAt must be a non-negative safe integer"); + if (record.cwd !== void 0) { + if (typeof record.cwd !== "string") throw new Error("session header cwd must be a string"); + if (!isAbsolute(record.cwd)) throw new Error(`session header cwd must be an absolute path, got "${record.cwd}"`); + } + if (record.parentSession !== void 0 && typeof record.parentSession !== "string") throw new Error("session header parentSession must be a string"); + if (record.seedLength !== void 0 && (typeof record.seedLength !== "number" || !Number.isSafeInteger(record.seedLength) || record.seedLength < 0)) throw new Error("session header seedLength must be a non-negative safe integer"); + if (record.origin !== void 0 && record.origin !== "subagent") throw new Error("session header origin must be \"subagent\""); + if (record.delegationDepth !== void 0 && (typeof record.delegationDepth !== "number" || !Number.isSafeInteger(record.delegationDepth) || record.delegationDepth < 0)) throw new Error("session header delegationDepth must be a non-negative safe integer"); + if (record.agentPreset !== void 0 && typeof record.agentPreset !== "string") throw new Error("session header agentPreset must be a string"); + return deepFreeze(record); +} +/** Validate and freeze one exclusively owned persistence header in place. */ +function validateRestoredSessionHeader(id, input) { + if (input !== null && typeof input === "object" && !Array.isArray(input)) { + const prototype = Reflect.getPrototypeOf(input); + if (prototype !== Object.prototype && prototype !== null) throw new Error("session header is not a plain JSON record"); + } + return validateSessionHeader(id, input); +} +/** Detach, validate, and freeze the creation metadata published by a session. */ +function snapshotSessionHeader(id, source) { + const snapshot = snapshotJsonValue(source === void 0 ? { + version: 0, + id, + createdAt: Date.now() + } : source); + if (snapshot === void 0) throw new Error("session header is not losslessly JSON-serializable"); + return validateSessionHeader(id, snapshot); +} +/** +* Validate an exclusively owned event and deeply freeze its identified message +* without copying the event. The caller transfers an object graph that no +* producer retains and that shares no mutable children with another event. +* Use {@link snapshotSessionEvent} when exclusive ownership is not guaranteed. +* @param event - exclusively owned event imported across a trusted boundary. +* @returns the same event object with a validated, deeply frozen message. +*/ +function adoptSessionEvent(event) { + assertMessageEventShape(event, `session event at seq ${event.seq}`); + switch (event.type) { + case "user/message": + deepFreeze(event.data); + break; + case "assistant/message": + case "tool/result": + deepFreeze(event.data.message); + break; + default: break; + } + return event; +} +/** +* Detach one event while preserving deep immutability for its identified message. +* @param event - event imported across a query or persistence boundary. +* @returns a detached event snapshot with a validated, deeply frozen message. +*/ +function snapshotSessionEvent(event) { + return adoptSessionEvent(structuredClone(event)); +} +/** Deep-freeze one acyclic JSON tree without consuming the JavaScript call stack. */ +function freezeRestoredObject(value) { + const pending = [value]; + while (pending.length > 0) { + const current = pending.pop(); + Object.freeze(current); + for (const key in current) { + const child = current[key]; + if (child !== null && typeof child === "object") pending.push(child); + } + } + return value; +} +/** Validate the fixed event envelope after one-pass JSON materialization. */ +function assertSessionEventEnvelope(value, index) { + const event = value; + if (event["type"] === "request/header-delta") throw new Error(`seed event at index ${index} uses unsupported legacy request/header-delta format`); + for (const key in event) switch (key) { + case "type": + case "seq": + case "time": + case "data": + case "surfaceOp": + case "sourceEventSeqs": + case "ignorable": break; + default: throw new Error(`seed event at index ${index} has an invalid event envelope`); + } + const type = event["type"]; + const seq = event["seq"]; + const time = event["time"]; + if (typeof type !== "string" || typeof seq !== "number" || !Number.isSafeInteger(seq) || seq < 0 || typeof time !== "number" || !Number.isSafeInteger(time) || event["data"] === void 0 || event["ignorable"] !== void 0 && event["ignorable"] !== true) throw new Error(`seed event at index ${index} has an invalid event envelope`); + switch (type) { + case "request/header": + case "user/message": + case "assistant/message": + case "tool/result": + assertCurrentLlmShape(event, index); + break; + } +} +/** Reject obsolete request headers and malformed messages at the seed/load boundary. */ +function assertCurrentLlmShape(event, index) { + const data = event["data"]; + const record = typeof data === "object" && data !== null ? data : void 0; + if (event["type"] === "request/header") { + const header = record?.["header"]; + const headerRecord = typeof header === "object" && header !== null && !Array.isArray(header) ? header : void 0; + const config = headerRecord?.["config"]; + if (!hasProviderModel(config)) throw new Error(`seed request/header at index ${index} lacks provider/model`); + const configRecord = config; + const reasoningEffort = configRecord["reasoningEffort"]; + if (reasoningEffort !== void 0 && (typeof reasoningEffort !== "string" || reasoningEffort.length === 0)) throw new Error(`seed request/header at index ${index} has an invalid reasoningEffort`); + assertAdapterDefaults(headerRecord?.["adapterDefaults"], configRecord, index); + } + const type = event["type"]; + if (type !== "user/message" && type !== "assistant/message" && type !== "tool/result") return; + assertMessageEventShape(event, `seed ${type} at index ${index}`); +} +const allowedAdapterKeys = new Set(["reasoningEffort", "maxTokens"]); +/** Validate adapter-default markers imported from a durable request header. */ +function assertAdapterDefaults(value, config, index) { + if (value === void 0) return; + if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`seed request/header at index ${index} has invalid adapterDefaults`); + const defaults = value; + if (Object.keys(defaults).some((key) => !allowedAdapterKeys.has(key)) || Object.values(defaults).some((marker) => marker !== true) || defaults["reasoningEffort"] === true && config["reasoningEffort"] === void 0 || defaults["maxTokens"] === true && config["maxTokens"] === void 0) throw new Error(`seed request/header at index ${index} has invalid adapterDefaults`); +} +/** Validate only the event-specific invariants needed to safely replay a message. */ +function assertMessageEventShape(event, subject) { + const type = event["type"]; + if (type !== "user/message" && type !== "assistant/message" && type !== "tool/result") return; + const data = event["data"]; + const record = typeof data === "object" && data !== null ? data : void 0; + const message = type === "user/message" ? record : record?.["message"]; + if (typeof message !== "object" || message === null || typeof message["id"] !== "string" || message["id"] === "") throw new Error(`${subject} lacks an identified message`); + const messageRecord = message; + const expectedRole = type === "assistant/message" ? "assistant" : "user"; + if (messageRecord["role"] !== expectedRole) throw new Error(`${subject} message must have role "${expectedRole}"`); + const source = messageRecord["source"]; + if (typeof source !== "object" || source === null || typeof source["kind"] !== "string" || source["kind"] === "") throw new Error(`${subject} message has invalid source`); + if (!Array.isArray(messageRecord["content"])) throw new Error(`${subject} message has invalid content`); + const sourceRecord = source; + if (type === "assistant/message") { + if (sourceRecord["kind"] !== "model" || !hasProviderModel(sourceRecord)) throw new Error(`${subject} message must have model source`); + return; + } + if (type !== "tool/result") return; + if (sourceRecord["kind"] !== "tool" || typeof sourceRecord["callId"] !== "string" || sourceRecord["callId"] === "") throw new Error(`${subject} message must have tool source`); + const content = messageRecord["content"]; + const block = content[0]; + if (content.length !== 1 || typeof block !== "object" || block === null || block["type"] !== "tool-result" || !Array.isArray(block["content"])) throw new Error(`${subject} message must contain one tool-result block`); + if (block["toolCallId"] !== sourceRecord["callId"]) throw new Error(`${subject} message has mismatched tool call ids`); +} +/** Whether an unknown value carries the current provider/model pair. */ +function hasProviderModel(value) { + if (typeof value !== "object" || value === null) return false; + const pair = value; + return typeof pair["provider"] === "string" && pair["provider"].length > 0 && typeof pair["model"] === "string" && pair["model"].length > 0; +} +/** Reject request-header vocabulary removed with the legacy delta codec. */ +function assertSupportedRequestHeader(type, data, location) { + if (type === "request/header-delta") throw new Error(`${location} uses unsupported legacy request/header-delta format`); + if (type === "request/header" && data !== null && typeof data === "object" && !Array.isArray(data) && data["reason"] === "fallback") throw new Error(`${location} uses unsupported legacy request/header reason "fallback"`); +} +/** Resolve one listener snapshot, including Cordis's internal dispatch checks. */ +function collectSessionCallbacks(ctx, args) { + return [...ctx.events.dispatch("emit", args)]; +} +/** Invoke one resolved observe-only listener snapshot with per-listener containment. */ +function invokeContainedSessionObservers(ctx, name, id, args, callbacks) { + for (const callback of callbacks) try { + const returned = callback(...args); + Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`session "${id}": ${name} listener rejected: ${String(error)}`); + }); + } catch (error) { + ctx.logger.warn(`session "${id}": ${name} listener threw: ${String(error)}`); + } +} +/** Store attachment for the append path; module-private to keep Session store-agnostic publicly. */ +const attachments = /* @__PURE__ */ new WeakMap(); +/** +* An event-sourced session: an append-only log of {@link SessionEvent}s. +* +* Plain class (not a Service) — create live instances via +* `ctx.sessions.create()` and detached instances via {@link create}. +* Seeding with an existing event log replays/forks a session. +* @typert object +*/ +var Session = class Session { + log = []; + /** Single incremental owner of surface acceptance and projection state. */ + surfaceManager = new SurfaceManager(this.log); + /** The ordered surface over this session's event log. */ + get surface() { + return this.surfaceManager; + } + /** + * Detached, deep-frozen creation metadata (format version, cwd, lineage, + * seed boundary). Supplied by the store via `ctx.sessions.create()`. When a + * `Session` is created without a store-owned header, a minimal header is + * synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so + * `session.header` is always present. Kept out of the event log — it is a + * storage concern, not replayable conversation state. + */ + header; + /** The session identity, derived from its durable header's single copy. */ + get id() { + return this.header.id; + } + /** + * The first seq appended IN THIS PROCESS: the length of the constructor + * seed (0 without one). Events with smaller seq values entered through + * construction — replay, fork, or resume — and were never published on the + * `session/event` firehose (constructor seeds do not emit), so consumers + * that replay the log as a publication substitute (telemetry adoption) + * start here. Distinct from `header.seedLength`, the DURABLE fork-lineage + * boundary: a resumed session's constructor seed is its full stored log, + * while its header keeps the original fork value — this field is the + * in-process construction fact. + * + * Not persisted itself: a seeded session projects it into the log as the + * `session/end-seed` event, which is what a consumer reading STORED history + * reads. Locate the LAST such event, not necessarily one at this seq — a + * seed already ending in one is not re-marked, so reopening an untouched + * session leaves that event at a smaller seq than `firstLiveSeq`. Prefer + * this field in-process: it is exact before the marker reaches storage. + * + * When this lifecycle appends the marker, it occupies this seq before the + * store attaches and therefore does not publish either. Otherwise this seq + * holds an ordinary published write. + */ + firstLiveSeq; + /** + * Create a detached session by validating and snapshotting borrowed seed + * events and storage metadata. + * @param id - session identity. + * @param seed - optional borrowed replay or fork events. + * @param header - optional borrowed storage metadata. + * @returns a detached session. + */ + static create(id, seed, header) { + return new Session(id, seed, header); + } + /** + * Restore a detached session by taking ownership of fresh persistence values. + * The storage format, event envelopes, sequence continuity, surface transitions, + * and header fields are validated before the restored objects are frozen. + * @param id - restored session identity. + * @param seed - fresh detached events whose ownership is transferred. + * @param header - fresh detached metadata whose ownership is transferred. + * @returns a restored detached session. + */ + static fromRestore(id, seed, header) { + return new Session(id, seed, header, "restore"); + } + constructor(id, seed, header, mode = "snapshot") { + const restoredHeader = mode === "restore" ? validateRestoredSessionHeader(id, header) : void 0; + if (seed !== void 0) for (const [index, source] of seed.entries()) { + const snapshot = mode === "restore" ? source : snapshotJsonValue(source); + if (snapshot === void 0) throw new Error(`seed event at index ${index} is not losslessly JSON-serializable`); + assertSessionEventEnvelope(snapshot, index); + assertSupportedRequestHeader(snapshot.type, snapshot.data, `seed event at index ${index}`); + if (snapshot.seq !== index) throw new Error(`seed event at index ${index} has seq ${snapshot.seq} (expected ${index}); seed must be contiguous from 0`); + try { + this.surfaceManager.validateNext(snapshot); + } catch (error) { + throw new Error(`invalid seed event at index ${index}: ${error instanceof Error ? error.message : "invalid surface metadata"}`); + } + this.log.push(mode === "restore" ? freezeRestoredObject(snapshot) : deepFreeze(snapshot)); + } + this.firstLiveSeq = this.log.length; + this.header = restoredHeader ?? snapshotSessionHeader(id, header); + if (seed !== void 0 && this.log.at(-1)?.type !== "session/end-seed") this.append("session/end-seed", {}); + } + /** Cached immutable public snapshot of the private append-only log. */ + eventsSnapshot; + /** + * An immutable snapshot of the append-only event log. The snapshot is reused + * until the next append; a previously returned array does not grow later. + * Events and their nested data are deep-frozen at acceptance, so neither a + * cast nor ordinary JavaScript can rewrite durable history. + */ + get events() { + this.eventsSnapshot ??= Object.freeze([...this.log]); + return this.eventsSnapshot; + } + /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */ + get seq() { + return this.log.length; + } + /** + * Append one typed event to the log and synchronously notify observers via + * the store-owned, module-private publication hooks. The hot path never blocks + * on I/O — persistence plugins buffer asynchronously. Once the event enters + * the log, the append is committed: observer failures are logged and + * contained per listener, so they do not change the return value or prevent + * later listeners from observing the same accepted event. + * + * @param type - The event type (key of {@link SessionEventMap}). + * @param data - The event payload; must be JSON-serializable. + * @param opts - Surface metadata: `surfaceOp` controls how the event enters + * the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier + * events this one derives from. REQUIRED for + * {@link SurfaceEventType} events (every message-producing event must + * declare how it joins the surface, the sole source of derived model + * history) and + * rejected by the compiler for non-surface types like `turn/start` or + * `assistant/chunk`. + * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of + * `data` that entered the log, so reading `event.data` back sees the logged + * value, never the caller's still-mutable input. + * @throws if `data` or surface metadata is not losslessly JSON-serializable + * (BigInt, function, symbol, undefined, negative zero, non-finite number, + * circular reference, sparse array, or an exotic object such as + * Map/Set/Date/class instance), or when the candidate violates the + * canonical surface contract (marker shape and eligibility, unique + * earlier source-event references, positional replacement validity, and complete + * shadowed-node coverage). One recursive pass reads, validates, and + * copies each nested value once, so a stateful getter cannot supply one value + * to validation and another to storage. The event log is the durable source + * of truth, so a bad event fails at the append site rather than later during + * a backend flush. A synchronous internal dispatch validation failure or an + * append reentered while this acceptance/publication boundary is open also + * rejects before the log changes. + */ + append(type, data, ...opts) { + const surfaceOpts = opts[0]; + const surfaceMetadata = { + ...surfaceOpts?.sourceEventSeqs === void 0 ? {} : { sourceEventSeqs: surfaceOpts.sourceEventSeqs }, + ...surfaceOpts?.surfaceOp === void 0 ? {} : { surfaceOp: surfaceOpts.surfaceOp } + }; + const dataSnapshot = snapshotJsonValue(data); + if (dataSnapshot === void 0) throw new Error(`session event "${type}" carries non-JSON-serializable data`); + assertSupportedRequestHeader(type, dataSnapshot, `session event "${type}"`); + const surfaceMetadataSnapshot = snapshotJsonValue(surfaceMetadata); + if (surfaceMetadataSnapshot === void 0) throw new Error(`session event "${type}" carries non-JSON-serializable surface metadata`); + const entry = attachments.get(this); + if (entry?.appending) throw new Error("session append cannot reenter while another append is being published"); + const event = deepFreeze({ + type, + seq: this.log.length, + time: Date.now(), + data: dataSnapshot, + ...surfaceMetadataSnapshot + }); + this.surfaceManager.validateNext(event); + if (entry !== void 0) entry.appending = true; + try { + let callbacks; + const callbackArgs = [this, event]; + if (entry !== void 0) callbacks = collectSessionCallbacks(entry.emitCtx, [ + entry.carrier, + "session/event", + ...callbackArgs + ]); + this.log.push(event); + this.eventsSnapshot = void 0; + if (callbacks !== void 0 && entry !== void 0) invokeContainedSessionObservers(entry.emitCtx, "session/event", entry.id, callbackArgs, callbacks); + return event; + } finally { + if (entry !== void 0) { + entry.appending = false; + if (entry.detachRequested && !entry.announcing) entry.detach(); + } + } + } + /** Cached fold of the request-header events — see {@link requestHeader}. */ + headerFold; + /** Log position (events consumed) the header fold has reached. */ + headerFoldSeq = 0; + /** + * The {@link EpochHeader} in force after the log's last header event — the + * header the NEXT request will be compared against — or undefined before + * the first `request/header` snapshot. The live, incrementally-maintained + * form of `foldRequestHeader(session.events)`: each header event is folded + * once, when first seen, so a per-step read costs O(new events). + * @returns the folded header, or undefined when no header event exists yet. + */ + requestHeader() { + if (this.headerFoldSeq < this.log.length) { + this.headerFold = deepFreeze(foldRequestHeader(this.log.slice(this.headerFoldSeq), this.headerFold)); + this.headerFoldSeq = this.log.length; + } + return this.headerFold; + } + /** Cached fold of `request/context` events. */ + contextFold; + contextFoldSeq = 0; + /** + * Return the latest resolved route metadata, or `undefined` before the first + * `request/context` event. Each event is folded once. + * @returns the latest immutable route metadata. + */ + requestContext() { + if (this.contextFoldSeq < this.log.length) { + for (const event of this.log.slice(this.contextFoldSeq)) if (event.type === "request/context") this.contextFold = deepFreeze({ ...event.data }); + this.contextFoldSeq = this.log.length; + } + return this.contextFold; + } + /** The derived-message cache: frozen projections, extended per unseen node. */ + derived = []; + /** Surface position (nodes projected) the cache has reached. */ + derivedNodes = 0; + /** {@link SurfaceManager.replaceGeneration} the cache was built under. */ + derivedGeneration = 0; + /** + * Derive the LLM message history by walking the ordered sequences of + * message-producing events maintained by `surfaceOp` markers. The + * surface is the single source of derived history: every message-producing + * append records its `surfaceOp`, so a raw event with no marker (a chunk, a + * turn boundary) is correctly absent, and a compaction `replace` deletes the + * shadowed nodes from the derivation. The projection rules are + * {@link deriveEventMessage}, folded per node. + * + * CACHED: each surface node is projected exactly once, when first seen — a + * call costs O(new nodes), and a surface rewrite (a `replace`; + * {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is + * a fresh snapshot per call (later appends never grow an array a caller + * already holds); the `Message` objects in it are SHARED and **deep-frozen**. + * Their content reuses the already frozen durable event data, so the cache + * needs no second deep clone and consumers still cannot mutate the log. + * @returns a fresh array of the shared, frozen derived history. + */ + deriveMessages() { + const surface = this.surface; + const nodes = surface.nodes; + const generation = surface.replaceGeneration; + if (generation !== this.derivedGeneration) { + this.derived = []; + this.derivedNodes = 0; + this.derivedGeneration = generation; + } + for (const seq of nodes.slice(this.derivedNodes)) { + const msg = this.deriveEventMessage(this.log[seq]); + if (msg) this.derived.push(msg); + } + this.derivedNodes = nodes.length; + return [...this.derived]; + } + /** + * Instance face of the pure per-node `deriveEventMessage` export from + * `surface.ts`. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ + deriveEventMessage(event) { + return deriveEventMessage(event); + } +}; +/** Typed error for session fork rejections. */ +var SessionForkError = class extends Error { + code; + constructor(message, code) { + super(message); + this.code = code; + this.name = "SessionForkError"; + } +}; +/** +* In-memory session store (`ctx.sessions`). +* +* Persistence is intentionally not implemented here — persistence plugins +* subscribe to `session/event` and flush on `session/flush` / dispose. +*/ +var SessionStore = class extends Service { + store = /* @__PURE__ */ new Map(); + counter = 0; + constructor(ctx) { + super(ctx, "sessions"); + ctx.inject(["typert"], (typeCtx) => { + typeCtx.typert.lookups.register("session", { + parameter: "session", + wire: "sessionId", + hostTypeSymbol: "@deepseek-ai/dsh-session#Session", + wireTypeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + resolve: (sessionId) => this.get(sessionId) + }); + }); + } + /** + * Create a session owned by the calling fiber: disposing that fiber stops + * event notification and removes the session from the store. `options.seed` + * populates the session with a copy of those events (replay/fork); + * `options.meta` attaches creation metadata (validated absolute `cwd`, seed + * and parent lineage, and delegation depth) as the immutable + * {@link SessionHeader} (the store fills `version`/`id`/`createdAt`). + * + * For an agent whose session must be torn down IN ORDER with its loop (so the + * loop's final events are published before the store attachment ends), do NOT use this + * — fold the session lifecycle into the agent's own effect via + * {@link prepare} + {@link enter} + {@link announce} (see + * `dsh-agent-loop`'s creation transaction). + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. + * @returns the live session, already entered and announced. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path (storage backends key directories off it). + */ + create(id, options) { + const session = this.prepare(id, options); + this.ctx.effect(function* () { + yield this.enter(session); + this.announce(session); + }.bind(this), "sessions.create()"); + return session; + } + /** + * Build a session WITHOUT entering it into the store — validate the id/cwd and + * construct the {@link Session} (with its immutable {@link SessionHeader}). + * Pairs with {@link enter} + {@link announce}: a caller that owns a composite + * `ctx.effect` (the agent factory) folds the session lifecycle into that ONE + * effect so a fiber unload tears the session + agent down as a single ORDERED + * chain rather than as racing sibling effects — which would remove the publication hooks + * before the driver's closing events commit, dropping them. + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. With + * `seedSource: 'persistence'`, metadata and events must be fresh detached + * graphs whose ownership transfers to this call: they are validated and + * frozen in place through {@link Session.fromRestore}, so the caller must + * retain no mutable aliases. + * @returns the constructed session, NOT yet in the store. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path. + */ + prepare(id, options) { + let sessionId; + if (id === void 0) do + sessionId = SessionId(`session-${++this.counter}`); + while (this.store.has(sessionId)); + else sessionId = SessionId(id); + if (this.store.has(sessionId)) throw new Error(`session "${sessionId}" already exists`); + if (options?.seedSource === "persistence") return Session.fromRestore(sessionId, options.seed, options.meta); + const seed = options?.seed; + const meta = options?.meta; + const header = { + version: 0, + id: sessionId, + createdAt: meta?.createdAt ?? Date.now(), + ...meta?.cwd === void 0 ? {} : { cwd: meta.cwd }, + ...meta?.parentSession === void 0 ? {} : { parentSession: meta.parentSession }, + ...meta?.seedLength === void 0 ? {} : { seedLength: meta.seedLength }, + ...meta?.origin === void 0 ? {} : { origin: meta.origin }, + ...meta?.delegationDepth === void 0 ? {} : { delegationDepth: meta.delegationDepth }, + ...meta?.agentPreset === void 0 ? {} : { agentPreset: meta.agentPreset } + }; + return Session.create(sessionId, seed, header); + } + /** + * Enter a {@link prepare}d session into the store: install the module-private + * append publication hooks and add it to the store. Returns the DETACH + * disposer (hooks + store removal). Does NOT emit `session/created` — + * the caller yields this disposer inside its effect and THEN calls + * {@link announce}, so a throwing `session/created` listener rolls the attach + * back instead of leaking it. + * + * Re-checks the id for a duplicate: `prepare` and `enter` are public + * cross-package primitives and a caller may interleave arbitrary work (or + * another create) between them, so a stale prepared session must NOT overwrite + * a live store entry of the same id — its detach disposer would later delete + * the REAL session. The {@link create} convenience and the agent factory call + * the two back-to-back so they never trip this, but the public API cannot + * assume that. + * + * @param session - a {@link prepare}d session not yet in the store. + * @returns the detach disposer (publication hooks + store removal). When called from + * a synchronous `session/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + * @throws if a session with this id is already in the store. + */ + enter(session) { + const id = session.id; + const carrier = scopeTarget(session, scopeOf(this.ctx)); + if (this.store.has(id)) throw new Error(`session "${id}" already exists`); + if (attachments.has(session)) throw new Error(`session "${id}" is already attached to a store`); + const entry = { + id, + session, + carrier, + emitCtx: this.ctx, + announced: false, + announcing: false, + appending: false, + detachRequested: false, + detach: () => { + this.detachEntered(entry); + } + }; + this.store.set(id, entry); + attachments.set(session, entry); + let entered = true; + const detach = () => { + if (!entered) return; + entered = false; + if (entry.announcing || entry.appending) { + entry.detachRequested = true; + return; + } + entry.detach(); + }; + return detach; + } + /** Remove one exact entered session and emit its paired disposal when announced. */ + detachEntered(entry) { + entry.detachRequested = false; + /* v8 ignore next -- enter() rejects replacement while this single-shot detach capability is live. */ + if (this.store.get(entry.id) !== entry) return; + this.store.delete(entry.id); + attachments.delete(entry.session); + if (entry.announced) this.emitDisposed(entry); + } + /** Emit `session/created` exactly once for an {@link enter}ed session (with + * the carrier {@link enter} captured). Separate from {@link enter} so the + * caller can yield the detach disposer first (rollback safety — see + * {@link enter}). + * @param session - the entered session to announce to listeners. + * @throws if the session is not live or its announcement already began, + * including a reentrant call from a creation listener. */ + announce(session) { + const entry = this.liveEntryFor(session); + if (entry.announced || entry.announcing) throw new Error(`session "${entry.id}" was already announced`); + entry.announced = true; + const callbackArgs = [session]; + entry.announcing = true; + try { + const callbacks = collectSessionCallbacks(this.ctx, [ + entry.carrier, + "session/created", + session + ]); + for (const callback of callbacks) { + const returned = callback(...callbackArgs); + Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`session "${entry.id}": session/created listener rejected: ${String(error)}`); + }); + } + } finally { + entry.announcing = false; + if (entry.detachRequested && !entry.appending) entry.detach(); + } + } + /** Emit the paired teardown notification with per-listener containment. */ + emitDisposed(entry) { + const callbackArgs = [entry.session]; + try { + const callbacks = collectSessionCallbacks(this.ctx, [ + entry.carrier, + "session/disposed", + entry.session + ]); + invokeContainedSessionObservers(this.ctx, "session/disposed", entry.id, callbackArgs, callbacks); + } catch (error) { + this.ctx.logger.warn(`session "${entry.id}": session/disposed dispatch threw: ${String(error)}`); + } + } + /** + * Dispatch the awaited `session/flush` durability checkpoint for `session`, + * with the carrier captured at {@link enter}. THE flush entry point: the + * store owns the carrier, so callers (the checkpoint policy's per-request + * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers + * that flush themselves before reading storage) must come through here + * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner, + * one spelling, and the scoped-dispatch invariant can pin it. + * @param session - the session whose buffered events must reach durable storage. + * @returns whether at least one durability listener participated, after every + * listener has settled successfully. + * @throws the first registered listener failure after every listener settles. + */ + async flush(session) { + const { carrier } = this.liveEntryFor(session); + const callbackArgs = [session]; + const callbacks = collectSessionCallbacks(this.ctx, [ + carrier, + "session/flush", + session + ]); + const failure = (await Promise.allSettled(callbacks.map((callback) => { + try { + return callback(...callbackArgs); + } catch (error) { + return Promise.reject(error); + } + }))).find((result) => result.status === "rejected"); + if (failure !== void 0) throw failure.reason; + return callbacks.length > 0; + } + /** Return the exact live entry; detached/prepared objects reject. */ + liveEntryFor(session) { + const entry = attachments.get(session); + if (entry === void 0 || this.store.get(entry.id) !== entry) throw new Error(`session "${session.id}" is not live in this store`); + return entry; + } + /** + * Look up a live session. + * @param id - the session id to look up. + * @returns the session, or undefined when no live session has that id. + */ + get(id) { + return this.store.get(id)?.session; + } + /** + * All live sessions, in creation order. + * @returns a fresh array; mutating it does not affect the store. + */ + list() { + return [...this.store.values()].map((entry) => entry.session); + } + /** + * Create a live child session from a stable prefix of a live source. + * `boundary` is an inclusive source event seq; omitted means the source's + * current last event. The selected slice may end with a between-turn event + * but must not end inside an open turn. + * + * @param source - Live source session object or id. + * @param boundary - Inclusive source event seq to fork through; omitted means + * the source's current last event, and omitted on an empty source forks an + * empty child. + * @param childSessionId - Optional child session id; omitted delegates to + * `SessionStore`'s id policy. + * @returns The created live child session. + */ + fork(source, boundary, childSessionId) { + if (childSessionId !== void 0 && this.get(childSessionId) !== void 0) throw new SessionForkError(`session "${childSessionId}" already exists`, "SESSION_ALREADY_EXISTS"); + const liveSource = this._resolveForkSource(source); + const seed = this._forkSeed(liveSource, boundary); + return this.create(childSessionId, { + seed, + meta: { + ...liveSource.header.cwd !== void 0 ? { cwd: liveSource.header.cwd } : {}, + parentSession: liveSource.id, + seedLength: seed.length + } + }); + } + _forkSeed(session, requestedBoundary) { + const events = session.events; + const lastEvent = events.at(-1); + let boundary; + if (requestedBoundary !== void 0) boundary = requestedBoundary; + else { + if (lastEvent === void 0) return []; + boundary = lastEvent.seq; + } + if (!Number.isSafeInteger(boundary) || boundary < 0) throw new SessionForkError(`fork boundary for session "${session.id}" must be a non-negative safe integer, got ${String(boundary)}`, "INVALID_BOUNDARY"); + if (boundary >= events.length) { + const lastSeq = events.at(-1)?.seq; + throw new SessionForkError(`fork boundary ${boundary} does not exist in session "${session.id}" (last seq: ${lastSeq ?? "none"})`, "INVALID_BOUNDARY"); + } + const boundaryEvent = events[boundary]; + if (boundaryEvent === void 0 || boundaryEvent.seq !== boundary) throw new SessionForkError(`fork boundary ${boundary} does not match a contiguous event seq in session "${session.id}"`, "INVALID_BOUNDARY"); + const lastTurnBoundary = events.slice(0, boundary + 1).findLast((event) => event.type === "turn/start" || event.type === "turn/end"); + if (lastTurnBoundary?.type === "turn/start") throw new SessionForkError(`fork boundary ${boundary} in session "${session.id}" ends inside open turn ${lastTurnBoundary.data.turn}`, "OPEN_TURN"); + return events.slice(0, boundary + 1); + } + _resolveForkSource(source) { + if (typeof source === "string") { + const session = this.get(source); + if (session === void 0) throw new SessionForkError(`session "${source}" not found`, "SESSION_NOT_FOUND"); + return session; + } + const live = this.get(source.id); + if (live === void 0) throw new SessionForkError(`session "${source.id}" not found`, "SESSION_NOT_FOUND"); + if (live !== source) throw new SessionForkError(`session "${source.id}" is not the live store instance`, "SESSION_NOT_LIVE"); + return source; + } +}; +//#endregion +export { KNOWN_SESSION_EVENT_TYPES, SESSION_FORMAT_VERSION, Session, SessionForkError, SessionId, SessionPreparation, SessionStore, SessionStore as default, TOOL_NOT_STARTED, TOOL_OUTCOME_UNKNOWN, adoptSessionEvent, canonicalHeader, decodeStorageRecord, deriveEventMessage, foldRequestHeader, foldSurface, headerEquals, interruptedTurnClosers, isAppendSurfaceEvent, isJsonValue, isReplacementSurfaceEvent, isSurfaceEligibleType, isSurfaceEvent, packChunkRuns, snapshotJsonValue, snapshotSessionEvent }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/invariant.js new file mode 100644 index 0000000..b96f03d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/invariant.js @@ -0,0 +1,168 @@ +import { assertNever } from "@deepseek-ai/dsh-llm"; +//#endregion +//#region lib/types/invariant.js +/** +* Package-owned relational invariants for the session event log. Load this +* companion beside `@deepseek-ai/dsh-invariants` to enable the checks. +* +* @module @deepseek-ai/dsh-session/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session"; +/** Cordis companion plugin name. */ +const name = "session-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Assert that a step-scoped event names the currently open turn and step. */ +function requireOpenStep(trace, kind, turn, step, fail) { + if (trace.openTurn !== turn || trace.openStep !== step) fail(`${kind} names turn ${turn}/step ${step} but open is turn ${trace.openTurn}/step ${trace.openStep}`); +} +/** Validate one candidate event without mutating the committed trace. */ +function validateEvent(trace, event, fail) { + if (event.seq <= trace.lastSeq) fail(`seq must strictly increase: saw ${event.seq} after ${trace.lastSeq}`); + let openTurn = trace.openTurn; + let openStep = trace.openStep; + let nextTurn = trace.nextTurn; + let nextStep = trace.nextStep; + let pendingCalls = { kind: "none" }; + switch (event.type) { + case "turn/start": + if (trace.openTurn !== null) fail(`turn/start ${event.data.turn} while turn ${trace.openTurn} is still open`); + if (event.data.turn !== trace.nextTurn) fail(`turn/start expected turn ${trace.nextTurn}, got ${event.data.turn}`); + openTurn = event.data.turn; + nextStep = 1; + break; + case "turn/end": + if (trace.openTurn !== event.data.turn) fail(`turn/end ${event.data.turn} does not match open turn ${trace.openTurn}`); + if (trace.openStep !== null) fail(`turn/end ${event.data.turn} while step ${trace.openStep} is still open`); + openTurn = null; + nextTurn += 1; + break; + case "step/start": + if (trace.openTurn !== event.data.turn) fail(`step/start in turn ${event.data.turn} but open turn is ${trace.openTurn}`); + if (trace.openStep !== null) fail(`step/start ${event.data.step} while step ${trace.openStep} is still open`); + if (event.data.step !== trace.nextStep) fail(`step/start expected step ${trace.nextStep} in turn ${event.data.turn}, got ${event.data.step}`); + openStep = event.data.step; + break; + case "step/end": + requireOpenStep(trace, "step/end", event.data.turn, event.data.step, fail); + pendingCalls = { kind: "clear" }; + openStep = null; + nextStep += 1; + break; + case "assistant/chunk": + requireOpenStep(trace, "assistant/chunk", event.data.turn, event.data.step, fail); + break; + case "assistant/message": + requireOpenStep(trace, "assistant/message", event.data.turn, event.data.step, fail); + break; + case "tool/call": + requireOpenStep(trace, "tool/call", event.data.turn, event.data.step, fail); + pendingCalls = { + kind: "add", + callId: event.data.callId + }; + break; + case "tool/result": { + if (event.surfaceOp !== "append") { + if (trace.openTurn === null) fail("tool/result surface replacement appended outside any open turn"); + break; + } + requireOpenStep(trace, "tool/result", event.data.turn, event.data.step, fail); + const callId = event.data.message.source.callId; + const syntheticNotStarted = event.data.message.content[0].isError === true && event.data.error?.code === "TOOL_NOT_STARTED"; + if (!trace.pendingCalls.has(callId) && !syntheticNotStarted) fail(`tool/result for ${callId} with no prior tool/call in this step`); + pendingCalls = { + kind: "delete", + callId + }; + break; + } + case "user/message": break; + case "session/end-seed": break; + case "todo/write": + case "request/header": + case "request/context": + if (trace.openTurn === null) fail(`${event.type} appended outside any open turn (core execution events must be turn-enclosed)`); + break; + default: break; + } + return { + scalars: { + lastSeq: event.seq, + openTurn, + openStep, + nextTurn, + nextStep + }, + pendingCalls + }; +} +/** Apply one already-validated transition after its event commits. */ +function applyTransition(trace, transition) { + Object.assign(trace, transition.scalars); + switch (transition.pendingCalls.kind) { + case "none": break; + case "add": + trace.pendingCalls.add(transition.pendingCalls.callId); + break; + case "delete": + trace.pendingCalls.delete(transition.pendingCalls.callId); + break; + case "clear": + trace.pendingCalls.clear(); + break; + /* v8 ignore next -- validateEvent produces this closed transition union */ + default: assertNever(transition.pendingCalls, "session trace pending-call transition"); + } +} +/** Install the session contribution into its child registration fiber. */ +const install = Object.assign((ctx, fail) => { + const traces = /* @__PURE__ */ new WeakMap(); + const stagedTransitions = /* @__PURE__ */ new WeakMap(); + const freshTrace = () => ({ + lastSeq: -1, + openTurn: null, + openStep: null, + nextTurn: 1, + nextStep: 1, + pendingCalls: /* @__PURE__ */ new Set() + }); + const seedSession = (session) => { + const trace = freshTrace(); + traces.set(session, trace); + for (const event of session.events) applyTransition(trace, validateEvent(trace, event, fail)); + return trace; + }; + /* v8 ignore next -- session/event always follows list() or session/created seeding */ + const traceFor = (session) => traces.get(session) ?? seedSession(session); + for (const session of ctx.sessions.list()) seedSession(session); + ctx.on("session/created", (session) => { + seedSession(session); + }, { global: true }); + ctx.on("session/event", (session, event) => { + const staged = stagedTransitions.get(event); + /* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */ + if (staged === void 0 || staged.session !== session) return fail("session/event reached publication without matching pre-commit validation"); + stagedTransitions.delete(event); + applyTransition(staged.trace, staged.transition); + }, { global: true }); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName !== "session/event") return; + const [session, event] = args; + const trace = traceFor(session); + const transition = validateEvent(trace, event, fail); + stagedTransitions.set(event, { + session, + trace, + transition + }); + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register the session invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.d.ts new file mode 100644 index 0000000..0e00895 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.d.ts @@ -0,0 +1,92 @@ +/** + * Lossless storage packing for `assistant/chunk` delta runs. Providers stream + * token-sized deltas, so a log stores hundreds of near-identical event lines + * whose JSON envelopes dwarf their payloads (~56× measured on a real DeepSeek + * session). This module packs each run of consecutive same-block delta chunks + * into ONE storage row — `text-chunks`, `reasoning-chunks`, or + * `tool-call-chunks` — and expands rows back to the exact original events. + * + * Storage rows are a durable-encoding vocabulary, NOT session events: they + * never enter `Session.events`, have no `SessionEventMap` entry, and use bare + * (slash-less) type tags so a reader cannot confuse them with the event + * taxonomy (precedent: the JSONL header line's `session` tag). The encoder + * whitelists exact shapes — anything it does not fully recognize is stored + * verbatim, so unknown fields or future chunk variants lose compression, never + * data. The decoder validates before expanding and fails loud on a malformed + * row-tagged value instead of silently dropping a whole run. + * + * @module @deepseek-ai/dsh-session/chunk-rows + */ +import { CallId } from '@deepseek-ai/dsh-llm'; +import type { SessionEvent } from './types.ts'; +/** + * Fields shared by every packed run: placement, block correlation, and member + * timestamps as gaps. Member `k` reconstructs as seq `seq0 + k` and time + * `time0` plus the first `k` gaps; a gap may be negative when the wall clock + * stepped backwards between events. + */ +interface RunDataBase { + turn: number; + step: number; + /** The stream block index every member shares. */ + index: number; + /** Epoch-ms gaps between consecutive members; length is one less than the member count. */ + dt: number[]; +} +/** Payload of a `text-chunks`/`reasoning-chunks` row: one entry per member, never joined — token boundaries are data. */ +interface TextRunData extends RunDataBase { + texts: string[]; +} +/** Payload of a `tool-call-chunks` row: the run-constant call identity plus each member's raw arguments fragment. */ +interface ToolCallRunData extends RunDataBase { + id: CallId; + /** Present iff every member carried it, with one uniform value (a mixed run never packs). */ + name?: string; + args: string[]; +} +/** + * A packed run of consecutive delta chunk events, discriminated on `type`. + * `seq0`/`time0` anchor the first member; text and reasoning rows share the + * {@link TextRunData} payload, tool-call rows carry {@link ToolCallRunData}. + */ +export type ChunkRow = { + type: 'text-chunks'; + seq0: number; + time0: number; + data: TextRunData; +} | { + type: 'reasoning-chunks'; + seq0: number; + time0: number; + data: TextRunData; +} | { + type: 'tool-call-chunks'; + seq0: number; + time0: number; + data: ToolCallRunData; +}; +/** One durable log line's JSON value: a session event verbatim, or a packed chunk row. */ +export type StorageRecord = SessionEvent | ChunkRow; +/** + * Pack an event batch for storage: each run of at least {@link MIN_RUN} + * consecutive whitelisted same-kind, same-block delta chunk events becomes one + * {@link ChunkRow}; every other event passes through verbatim, in order. + * Pure and stateless — safe over any array, including a batch whose runs were + * split by flush boundaries (the split runs simply pack per batch). + * + * @param events - the batch to encode, in log order. + * @returns the storage records to write, one JSONL line each. + */ +export declare function packChunkRuns(events: readonly SessionEvent[]): StorageRecord[]; +/** + * Decode one parsed JSONL line value into the session event(s) it stores. + * Chunk-row-tagged values validate and expand (a malformed row throws — it is + * corrupt storage, and treating it as an event would silently drop a whole + * run); every other value passes through as a single event, unvalidated. + * + * @param value - one line's `JSON.parse` result. + * @returns the stored events, in log order. + */ +export declare function decodeStorageRecord(value: unknown): SessionEvent[]; +export {}; +//# sourceMappingURL=chunk-rows.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.js new file mode 100644 index 0000000..a5c4933 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.js @@ -0,0 +1,301 @@ +/** + * Lossless storage packing for `assistant/chunk` delta runs. Providers stream + * token-sized deltas, so a log stores hundreds of near-identical event lines + * whose JSON envelopes dwarf their payloads (~56× measured on a real DeepSeek + * session). This module packs each run of consecutive same-block delta chunks + * into ONE storage row — `text-chunks`, `reasoning-chunks`, or + * `tool-call-chunks` — and expands rows back to the exact original events. + * + * Storage rows are a durable-encoding vocabulary, NOT session events: they + * never enter `Session.events`, have no `SessionEventMap` entry, and use bare + * (slash-less) type tags so a reader cannot confuse them with the event + * taxonomy (precedent: the JSONL header line's `session` tag). The encoder + * whitelists exact shapes — anything it does not fully recognize is stored + * verbatim, so unknown fields or future chunk variants lose compression, never + * data. The decoder validates before expanding and fails loud on a malformed + * row-tagged value instead of silently dropping a whole run. + * + * @module @deepseek-ai/dsh-session/chunk-rows + */ +import { CallId, assertNever } from '@deepseek-ai/dsh-llm'; +/** + * Minimum members before a run packs. Below it a row's envelope rivals the + * event lines it replaces. A format constant, not a tunable: both layouts + * decode identically, so changing it never invalidates stored logs. + */ +const MIN_RUN = 3; +function isRecord(value) { + return typeof value === 'object' && value !== null; +} +/** Exact-key check: `value` has every key in `keys` and nothing else. */ +function hasExactKeys(value, keys) { + return Object.keys(value).length === keys.length && keys.every(k => Object.hasOwn(value, k)); +} +/** + * Classify an event for packing: its delta kind when the ENTIRE shape + * (envelope, data, chunk — exact keys, primitive types, integer seq/time) is + * whitelisted, else `undefined` (store verbatim). Inputs come from live typed + * appends AND parsed fixture files, so the checks are structural, not + * type-trusted. Integer times keep gap encoding exact: a fractional time would + * reconstruct through float subtraction/addition, which need not round-trip. + */ +function classify(event) { + if (event.type !== 'assistant/chunk') + return undefined; + if (!hasExactKeys(event, ['type', 'seq', 'time', 'data'])) + return undefined; + if (!Number.isSafeInteger(event.seq) || event.seq < 0 || !Number.isSafeInteger(event.time)) + return undefined; + const data = event.data; + if (!isRecord(data) || !hasExactKeys(data, ['turn', 'step', 'chunk'])) + return undefined; + if (typeof data.turn !== 'number' || typeof data.step !== 'number') + return undefined; + const chunk = data.chunk; + if (!isRecord(chunk) || typeof chunk.index !== 'number') + return undefined; + switch (chunk.type) { + case 'text-delta': + case 'reasoning-delta': + return hasExactKeys(chunk, ['type', 'index', 'text']) && typeof chunk.text === 'string' + ? chunk.type + : undefined; + case 'tool-call-delta': { + const shapeOk = hasExactKeys(chunk, ['type', 'index', 'id', 'argumentsDelta']) + || (hasExactKeys(chunk, ['type', 'index', 'id', 'name', 'argumentsDelta']) && typeof chunk.name === 'string'); + return shapeOk && typeof chunk.id === 'string' && typeof chunk.argumentsDelta === 'string' + ? chunk.type + : undefined; + } + // Whitelist fall-through over parsed data: block-start/end, usage, finish, + // and any future chunk variant stay one event per line. + default: + return undefined; + } +} +/** The tool-call fields of a whitelisted delta chunk (only after {@link classify} returned `'tool-call-delta'`). */ +function toolCallOf(event) { + return event.data.chunk; +} +/** The block index of a whitelisted delta chunk (not every {@link StreamChunk} variant carries one). */ +function indexOf(event) { + return event.data.chunk.index; +} +/** Whether `next` extends a run ending in `prev` (same kind already checked by the caller). */ +function continues(prev, next, kind) { + if (next.seq !== prev.seq + 1) + return false; + // Two safe-integer times can sit further apart than a double subtracts + // exactly (2^53-1 and its negation differ by ~2^54); a rounded gap would + // decode to a different timestamp. The check is exact in both directions: a + // true gap within safe range subtracts without rounding and passes, while a + // true gap beyond it rounds to a value that is itself beyond and fails. + if (!Number.isSafeInteger(next.time - prev.time)) + return false; + if (next.data.turn !== prev.data.turn || next.data.step !== prev.data.step) + return false; + if (indexOf(next) !== indexOf(prev)) + return false; + if (kind !== 'tool-call-delta') + return true; + const a = toolCallOf(prev); + const b = toolCallOf(next); + // `name` must match in presence AND value — a mixed run is not representable. + return a.id === b.id && Object.hasOwn(a, 'name') === Object.hasOwn(b, 'name') && a.name === b.name; +} +/** Build the row for a completed run (`run.length >= MIN_RUN`, uniform per {@link continues}). */ +function buildRow(kind, run) { + const first = run[0]; + const base = { + turn: first.data.turn, + step: first.data.step, + index: indexOf(first), + dt: run.slice(1).map((event, i) => event.time - run[i].time), + }; + const envelope = { seq0: first.seq, time0: first.time }; + if (kind === 'tool-call-delta') { + const call = toolCallOf(first); + return { + type: 'tool-call-chunks', + ...envelope, + data: { + ...base, + id: CallId(call.id), + ...Object.hasOwn(call, 'name') ? { name: call.name } : {}, + args: run.map(event => event.data.chunk.argumentsDelta), + }, + }; + } + const data = { ...base, texts: run.map(event => event.data.chunk.text) }; + return kind === 'text-delta' + ? { type: 'text-chunks', ...envelope, data } + : { type: 'reasoning-chunks', ...envelope, data }; +} +/** + * Pack an event batch for storage: each run of at least {@link MIN_RUN} + * consecutive whitelisted same-kind, same-block delta chunk events becomes one + * {@link ChunkRow}; every other event passes through verbatim, in order. + * Pure and stateless — safe over any array, including a batch whose runs were + * split by flush boundaries (the split runs simply pack per batch). + * + * @param events - the batch to encode, in log order. + * @returns the storage records to write, one JSONL line each. + */ +export function packChunkRuns(events) { + const out = []; + let kind; + let run = []; + const flush = () => { + if (kind !== undefined && run.length >= MIN_RUN) + out.push(buildRow(kind, run)); + else + out.push(...run); + kind = undefined; + run = []; + }; + for (const event of events) { + const k = classify(event); + if (k === undefined) { + flush(); + out.push(event); + continue; + } + const delta = event; + const last = run[run.length - 1]; + if (k === kind && last !== undefined && continues(last, delta, k)) { + run.push(delta); + continue; + } + flush(); + kind = k; + run = [delta]; + } + flush(); + return out; +} +/** Throw the uniform malformed-row diagnostic. */ +function malformed(tag, why) { + throw new Error(`malformed ${tag} storage row: ${why}`); +} +/** Validate the shared run-data fields and the payload/dt arity; returns the member payload. */ +function validateRunData(tag, data, payloadKey) { + if (typeof data.turn !== 'number' || typeof data.step !== 'number' || typeof data.index !== 'number') { + malformed(tag, 'turn/step/index must be numbers'); + } + const payload = data[payloadKey]; + if (!Array.isArray(payload) || payload.length === 0 || payload.some(entry => typeof entry !== 'string')) { + malformed(tag, `${payloadKey} must be a non-empty string array`); + } + const dt = data.dt; + if (!Array.isArray(dt) || dt.some(gap => !Number.isSafeInteger(gap))) { + malformed(tag, 'dt must be an array of safe integers'); + } + if (dt.length !== payload.length - 1) { + malformed(tag, `dt length ${dt.length} does not match ${payload.length} members`); + } + return payload; +} +/** Validate a row-tagged parsed value's envelope and data, throwing on any malformation. */ +function validateRow(value, tag) { + if (!hasExactKeys(value, ['type', 'seq0', 'time0', 'data'])) { + malformed(tag, 'envelope must be exactly {type, seq0, time0, data}'); + } + if (!Number.isSafeInteger(value.seq0) || value.seq0 < 0) { + malformed(tag, 'seq0 must be a non-negative safe integer'); + } + if (!Number.isSafeInteger(value.time0)) { + malformed(tag, 'time0 must be a safe integer'); + } + const data = value.data; + if (!isRecord(data)) + malformed(tag, 'data must be an object'); + let payload; + if (tag === 'tool-call-chunks') { + const withName = hasExactKeys(data, ['turn', 'step', 'index', 'id', 'name', 'dt', 'args']); + if (!withName && !hasExactKeys(data, ['turn', 'step', 'index', 'id', 'dt', 'args'])) { + malformed(tag, 'data must be exactly {turn, step, index, id, name?, dt, args}'); + } + if (typeof data.id !== 'string' || (withName && typeof data.name !== 'string')) { + malformed(tag, 'id (and name when present) must be strings'); + } + payload = validateRunData(tag, data, 'args'); + } + else { + if (!hasExactKeys(data, ['turn', 'step', 'index', 'dt', 'texts'])) { + malformed(tag, 'data must be exactly {turn, step, index, dt, texts}'); + } + payload = validateRunData(tag, data, 'texts'); + } + // Reconstruction bounds. The encoder only packs runs whose member seqs and + // times are all safe integers, so a running value that leaves safe range is + // outside any encoder's image: float arithmetic would round it to a + // different number than exact arithmetic, a silent corruption. Within safe + // range every step is exact, so the first departure is always caught. + if (!Number.isSafeInteger(value.seq0 + payload.length - 1)) { + malformed(tag, 'member seqs must stay safe integers'); + } + let time = value.time0; + for (const gap of data.dt) { + time += gap; + if (!Number.isSafeInteger(time)) + malformed(tag, 'member times must stay safe integers'); + } + return value; +} +/** Expand a validated row back into its exact original events, in order. */ +function expandRow(row) { + const members = row.type === 'tool-call-chunks' ? row.data.args : row.data.texts; + const events = []; + let time = row.time0; + for (let k = 0; k < members.length; k++) { + if (k > 0) + time += row.data.dt[k - 1]; + let chunk; + switch (row.type) { + case 'text-chunks': + chunk = { type: 'text-delta', index: row.data.index, text: members[k] }; + break; + case 'reasoning-chunks': + chunk = { type: 'reasoning-delta', index: row.data.index, text: members[k] }; + break; + case 'tool-call-chunks': + chunk = { + type: 'tool-call-delta', + index: row.data.index, + id: row.data.id, + ...Object.hasOwn(row.data, 'name') ? { name: row.data.name } : {}, + argumentsDelta: members[k], + }; + break; + /* v8 ignore next 2 -- validateRow only returns the three row tags */ + default: + return assertNever(row, 'chunk-rows expandRow'); + } + events.push({ + type: 'assistant/chunk', + seq: row.seq0 + k, + time, + data: { turn: row.data.turn, step: row.data.step, chunk }, + }); + } + return events; +} +/** + * Decode one parsed JSONL line value into the session event(s) it stores. + * Chunk-row-tagged values validate and expand (a malformed row throws — it is + * corrupt storage, and treating it as an event would silently drop a whole + * run); every other value passes through as a single event, unvalidated. + * + * @param value - one line's `JSON.parse` result. + * @returns the stored events, in log order. + */ +export function decodeStorageRecord(value) { + if (!isRecord(value)) + return [value]; + const tag = value.type; + if (tag !== 'text-chunks' && tag !== 'reasoning-chunks' && tag !== 'tool-call-chunks') { + return [value]; + } + return expandRow(validateRow(value, tag)); +} +//# sourceMappingURL=chunk-rows.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts new file mode 100644 index 0000000..1e2f5ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts @@ -0,0 +1,418 @@ +/** + * Event-sourced session service: append-only session log, in-memory store, and + * the derived LLM message history. Persistence is a plugin concern (subscribe + * to `session/event`, drain on `session/flush`). + * + * @module @deepseek-ai/dsh-session + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { Scoped } from '@deepseek-ai/dsh-scope'; +import type { Message } from '@deepseek-ai/dsh-llm'; +import { SessionId } from './types.ts'; +import type { TypertLookup } from '@deepseek-ai/dsh-typert-protocol'; +import type { CreateSessionOptions, EpochHeader, PrepareSessionOptions, RequestContext, SessionEvent, SessionEventMap, SessionEventType, SessionHeader, SurfaceIntent, SurfaceEventType } from './types.ts'; +import type { SessionSurface } from './surface.ts'; +export * from './types.ts'; +export { SessionPreparation } from './preparation.ts'; +export type { SessionPreparationOptions } from './preparation.ts'; +export type { AssistantMessage, ToolResultMessage, UserMessage } from '@deepseek-ai/dsh-llm'; +export { isJsonValue, snapshotJsonValue } from './json.ts'; +export type { JsonValue } from './json.ts'; +export { interruptedTurnClosers, TOOL_NOT_STARTED, TOOL_OUTCOME_UNKNOWN } from './repair.ts'; +export { decodeStorageRecord, packChunkRuns } from './chunk-rows.ts'; +export type { ChunkRow, StorageRecord } from './chunk-rows.ts'; +export type { SessionSurface, SurfaceFoldReplacement, SurfaceFoldResult } from './surface.ts'; +export { deriveEventMessage, foldSurface, isAppendSurfaceEvent, isReplacementSurfaceEvent, isSurfaceEvent, isSurfaceEligibleType } from './surface.ts'; +export { canonicalHeader, foldRequestHeader, headerEquals } from './request-header.ts'; +export { KNOWN_SESSION_EVENT_TYPES } from './known-event-types.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + sessions: SessionStore; + } + interface Events { + /** + * Creation announcement during session publication. A synchronous throw vetoes and rolls + * back with a paired disposal; detach requested during dispatch is deferred. + * A returned-promise rejection is logged but cannot retroactively veto this + * synchronous boundary. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners + * receive only sessions entered through that agent's context. + * @param session - the session just entered and announced. + * @dshScopeScan unsupported + * @mode emit + */ + 'session/created'(this: Scoped, session: Session): void; + /** + * Emitted once when an announced session leaves the store, including + * publication rollback, but never for an entry whose creation announcement + * did not begin. Listener failures are logged and contained. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`) reuses the owner scope. + * @param session - the session that is no longer live in the store. + * @dshScopeScan unsupported + * @mode emit + */ + 'session/disposed'(this: Scoped, session: Session): void; + /** + * Post-commit, fire-and-forget append feed. The listener snapshot resolves + * before the log push, but callbacks run after it; observer failures are + * logged and contained without making the committed append fail. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners + * receive only events from sessions entered through that agent's context. + * @param session - the session whose log grew. + * @param event - the appended event, exactly as recorded. + * @dshScopeScan unsupported + * @mode emit + */ + 'session/event'(this: Scoped, session: Session, event: SessionEvent): void; + /** + * Awaited parallel durability checkpoint: every listener runs and the + * caller awaits all of them, with no waterfall veto. Scope-filtered dispatch + * (`@deepseek-ai/dsh-scope`) reuses the session's owner scope. + * @param session - the session whose buffered events must reach durable storage. + * @dshScopeScan unsupported + * @mode parallel + */ + 'session/flush'(this: Scoped, session: Session): Promise | void; + } +} +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertLookupMap { + session: TypertLookup; + } +} +/** + * Validate an exclusively owned event and deeply freeze its identified message + * without copying the event. The caller transfers an object graph that no + * producer retains and that shares no mutable children with another event. + * Use {@link snapshotSessionEvent} when exclusive ownership is not guaranteed. + * @param event - exclusively owned event imported across a trusted boundary. + * @returns the same event object with a validated, deeply frozen message. + */ +export declare function adoptSessionEvent(event: T): T; +/** + * Detach one event while preserving deep immutability for its identified message. + * @param event - event imported across a query or persistence boundary. + * @returns a detached event snapshot with a validated, deeply frozen message. + */ +export declare function snapshotSessionEvent(event: T): T; +/** + * An event-sourced session: an append-only log of {@link SessionEvent}s. + * + * Plain class (not a Service) — create live instances via + * `ctx.sessions.create()` and detached instances via {@link create}. + * Seeding with an existing event log replays/forks a session. + * @typert object + */ +export declare class Session { + private log; + /** Single incremental owner of surface acceptance and projection state. */ + private readonly surfaceManager; + /** The ordered surface over this session's event log. */ + get surface(): SessionSurface; + /** + * Detached, deep-frozen creation metadata (format version, cwd, lineage, + * seed boundary). Supplied by the store via `ctx.sessions.create()`. When a + * `Session` is created without a store-owned header, a minimal header is + * synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so + * `session.header` is always present. Kept out of the event log — it is a + * storage concern, not replayable conversation state. + */ + readonly header: SessionHeader; + /** The session identity, derived from its durable header's single copy. */ + get id(): SessionId; + /** + * The first seq appended IN THIS PROCESS: the length of the constructor + * seed (0 without one). Events with smaller seq values entered through + * construction — replay, fork, or resume — and were never published on the + * `session/event` firehose (constructor seeds do not emit), so consumers + * that replay the log as a publication substitute (telemetry adoption) + * start here. Distinct from `header.seedLength`, the DURABLE fork-lineage + * boundary: a resumed session's constructor seed is its full stored log, + * while its header keeps the original fork value — this field is the + * in-process construction fact. + * + * Not persisted itself: a seeded session projects it into the log as the + * `session/end-seed` event, which is what a consumer reading STORED history + * reads. Locate the LAST such event, not necessarily one at this seq — a + * seed already ending in one is not re-marked, so reopening an untouched + * session leaves that event at a smaller seq than `firstLiveSeq`. Prefer + * this field in-process: it is exact before the marker reaches storage. + * + * When this lifecycle appends the marker, it occupies this seq before the + * store attaches and therefore does not publish either. Otherwise this seq + * holds an ordinary published write. + */ + readonly firstLiveSeq: number; + /** + * Create a detached session by validating and snapshotting borrowed seed + * events and storage metadata. + * @param id - session identity. + * @param seed - optional borrowed replay or fork events. + * @param header - optional borrowed storage metadata. + * @returns a detached session. + */ + static create(id: SessionId, seed?: readonly SessionEvent[], header?: SessionHeader): Session; + /** + * Restore a detached session by taking ownership of fresh persistence values. + * The storage format, event envelopes, sequence continuity, surface transitions, + * and header fields are validated before the restored objects are frozen. + * @param id - restored session identity. + * @param seed - fresh detached events whose ownership is transferred. + * @param header - fresh detached metadata whose ownership is transferred. + * @returns a restored detached session. + */ + static fromRestore(id: SessionId, seed: readonly SessionEvent[], header: SessionHeader): Session; + private constructor(); + /** Cached immutable public snapshot of the private append-only log. */ + private eventsSnapshot; + /** + * An immutable snapshot of the append-only event log. The snapshot is reused + * until the next append; a previously returned array does not grow later. + * Events and their nested data are deep-frozen at acceptance, so neither a + * cast nor ordinary JavaScript can rewrite durable history. + */ + get events(): readonly SessionEvent[]; + /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */ + get seq(): number; + /** + * Append one typed event to the log and synchronously notify observers via + * the store-owned, module-private publication hooks. The hot path never blocks + * on I/O — persistence plugins buffer asynchronously. Once the event enters + * the log, the append is committed: observer failures are logged and + * contained per listener, so they do not change the return value or prevent + * later listeners from observing the same accepted event. + * + * @param type - The event type (key of {@link SessionEventMap}). + * @param data - The event payload; must be JSON-serializable. + * @param opts - Surface metadata: `surfaceOp` controls how the event enters + * the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier + * events this one derives from. REQUIRED for + * {@link SurfaceEventType} events (every message-producing event must + * declare how it joins the surface, the sole source of derived model + * history) and + * rejected by the compiler for non-surface types like `turn/start` or + * `assistant/chunk`. + * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of + * `data` that entered the log, so reading `event.data` back sees the logged + * value, never the caller's still-mutable input. + * @throws if `data` or surface metadata is not losslessly JSON-serializable + * (BigInt, function, symbol, undefined, negative zero, non-finite number, + * circular reference, sparse array, or an exotic object such as + * Map/Set/Date/class instance), or when the candidate violates the + * canonical surface contract (marker shape and eligibility, unique + * earlier source-event references, positional replacement validity, and complete + * shadowed-node coverage). One recursive pass reads, validates, and + * copies each nested value once, so a stateful getter cannot supply one value + * to validation and another to storage. The event log is the durable source + * of truth, so a bad event fails at the append site rather than later during + * a backend flush. A synchronous internal dispatch validation failure or an + * append reentered while this acceptance/publication boundary is open also + * rejects before the log changes. + */ + append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent; + /** Cached fold of the request-header events — see {@link requestHeader}. */ + private headerFold; + /** Log position (events consumed) the header fold has reached. */ + private headerFoldSeq; + /** + * The {@link EpochHeader} in force after the log's last header event — the + * header the NEXT request will be compared against — or undefined before + * the first `request/header` snapshot. The live, incrementally-maintained + * form of `foldRequestHeader(session.events)`: each header event is folded + * once, when first seen, so a per-step read costs O(new events). + * @returns the folded header, or undefined when no header event exists yet. + */ + requestHeader(): EpochHeader | undefined; + /** Cached fold of `request/context` events. */ + private contextFold; + private contextFoldSeq; + /** + * Return the latest resolved route metadata, or `undefined` before the first + * `request/context` event. Each event is folded once. + * @returns the latest immutable route metadata. + */ + requestContext(): RequestContext | undefined; + /** The derived-message cache: frozen projections, extended per unseen node. */ + private derived; + /** Surface position (nodes projected) the cache has reached. */ + private derivedNodes; + /** {@link SurfaceManager.replaceGeneration} the cache was built under. */ + private derivedGeneration; + /** + * Derive the LLM message history by walking the ordered sequences of + * message-producing events maintained by `surfaceOp` markers. The + * surface is the single source of derived history: every message-producing + * append records its `surfaceOp`, so a raw event with no marker (a chunk, a + * turn boundary) is correctly absent, and a compaction `replace` deletes the + * shadowed nodes from the derivation. The projection rules are + * {@link deriveEventMessage}, folded per node. + * + * CACHED: each surface node is projected exactly once, when first seen — a + * call costs O(new nodes), and a surface rewrite (a `replace`; + * {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is + * a fresh snapshot per call (later appends never grow an array a caller + * already holds); the `Message` objects in it are SHARED and **deep-frozen**. + * Their content reuses the already frozen durable event data, so the cache + * needs no second deep clone and consumers still cannot mutate the log. + * @returns a fresh array of the shared, frozen derived history. + */ + deriveMessages(): Message[]; + /** + * Instance face of the pure per-node `deriveEventMessage` export from + * `surface.ts`. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ + deriveEventMessage(event: SessionEvent): Message | null; +} +/** A fork source: either the live session object or its live store id. */ +export type SessionForkSource = Session | SessionId; +/** + * Rejection codes for session forking: the fork source id is unknown to the + * live store (`SESSION_NOT_FOUND`) or names a session object that is not the + * store's live instance (`SESSION_NOT_LIVE`); the requested child id is + * already taken (`SESSION_ALREADY_EXISTS`); the boundary is not a contiguous + * existing seq (`INVALID_BOUNDARY`); or the selected prefix ends inside an + * open turn (`OPEN_TURN`). + */ +export type SessionForkErrorCode = 'SESSION_NOT_FOUND' | 'SESSION_NOT_LIVE' | 'SESSION_ALREADY_EXISTS' | 'INVALID_BOUNDARY' | 'OPEN_TURN'; +/** Typed error for session fork rejections. */ +export declare class SessionForkError extends Error { + readonly code: SessionForkErrorCode; + constructor(message: string, code: SessionForkErrorCode); +} +/** + * In-memory session store (`ctx.sessions`). + * + * Persistence is intentionally not implemented here — persistence plugins + * subscribe to `session/event` and flush on `session/flush` / dispose. + */ +export declare class SessionStore extends Service { + private store; + private counter; + constructor(ctx: Context); + /** + * Create a session owned by the calling fiber: disposing that fiber stops + * event notification and removes the session from the store. `options.seed` + * populates the session with a copy of those events (replay/fork); + * `options.meta` attaches creation metadata (validated absolute `cwd`, seed + * and parent lineage, and delegation depth) as the immutable + * {@link SessionHeader} (the store fills `version`/`id`/`createdAt`). + * + * For an agent whose session must be torn down IN ORDER with its loop (so the + * loop's final events are published before the store attachment ends), do NOT use this + * — fold the session lifecycle into the agent's own effect via + * {@link prepare} + {@link enter} + {@link announce} (see + * `dsh-agent-loop`'s creation transaction). + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. + * @returns the live session, already entered and announced. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path (storage backends key directories off it). + */ + create(id?: SessionId, options?: CreateSessionOptions): Session; + /** + * Build a session WITHOUT entering it into the store — validate the id/cwd and + * construct the {@link Session} (with its immutable {@link SessionHeader}). + * Pairs with {@link enter} + {@link announce}: a caller that owns a composite + * `ctx.effect` (the agent factory) folds the session lifecycle into that ONE + * effect so a fiber unload tears the session + agent down as a single ORDERED + * chain rather than as racing sibling effects — which would remove the publication hooks + * before the driver's closing events commit, dropping them. + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. With + * `seedSource: 'persistence'`, metadata and events must be fresh detached + * graphs whose ownership transfers to this call: they are validated and + * frozen in place through {@link Session.fromRestore}, so the caller must + * retain no mutable aliases. + * @returns the constructed session, NOT yet in the store. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path. + */ + prepare(id?: SessionId, options?: PrepareSessionOptions): Session; + /** + * Enter a {@link prepare}d session into the store: install the module-private + * append publication hooks and add it to the store. Returns the DETACH + * disposer (hooks + store removal). Does NOT emit `session/created` — + * the caller yields this disposer inside its effect and THEN calls + * {@link announce}, so a throwing `session/created` listener rolls the attach + * back instead of leaking it. + * + * Re-checks the id for a duplicate: `prepare` and `enter` are public + * cross-package primitives and a caller may interleave arbitrary work (or + * another create) between them, so a stale prepared session must NOT overwrite + * a live store entry of the same id — its detach disposer would later delete + * the REAL session. The {@link create} convenience and the agent factory call + * the two back-to-back so they never trip this, but the public API cannot + * assume that. + * + * @param session - a {@link prepare}d session not yet in the store. + * @returns the detach disposer (publication hooks + store removal). When called from + * a synchronous `session/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + * @throws if a session with this id is already in the store. + */ + enter(session: Session): () => void; + /** Remove one exact entered session and emit its paired disposal when announced. */ + private detachEntered; + /** Emit `session/created` exactly once for an {@link enter}ed session (with + * the carrier {@link enter} captured). Separate from {@link enter} so the + * caller can yield the detach disposer first (rollback safety — see + * {@link enter}). + * @param session - the entered session to announce to listeners. + * @throws if the session is not live or its announcement already began, + * including a reentrant call from a creation listener. */ + announce(session: Session): void; + /** Emit the paired teardown notification with per-listener containment. */ + private emitDisposed; + /** + * Dispatch the awaited `session/flush` durability checkpoint for `session`, + * with the carrier captured at {@link enter}. THE flush entry point: the + * store owns the carrier, so callers (the checkpoint policy's per-request + * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers + * that flush themselves before reading storage) must come through here + * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner, + * one spelling, and the scoped-dispatch invariant can pin it. + * @param session - the session whose buffered events must reach durable storage. + * @returns whether at least one durability listener participated, after every + * listener has settled successfully. + * @throws the first registered listener failure after every listener settles. + */ + flush(session: Session): Promise; + /** Return the exact live entry; detached/prepared objects reject. */ + private liveEntryFor; + /** + * Look up a live session. + * @param id - the session id to look up. + * @returns the session, or undefined when no live session has that id. + */ + get(id: SessionId): Session | undefined; + /** + * All live sessions, in creation order. + * @returns a fresh array; mutating it does not affect the store. + */ + list(): Session[]; + /** + * Create a live child session from a stable prefix of a live source. + * `boundary` is an inclusive source event seq; omitted means the source's + * current last event. The selected slice may end with a between-turn event + * but must not end inside an open turn. + * + * @param source - Live source session object or id. + * @param boundary - Inclusive source event seq to fork through; omitted means + * the source's current last event, and omitted on an empty source forks an + * empty child. + * @param childSessionId - Optional child session id; omitted delegates to + * `SessionStore`'s id policy. + * @returns The created live child session. + */ + fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Session; + private _forkSeed; + private _resolveForkSource; +} +export default SessionStore; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/index.js new file mode 100644 index 0000000..673a13b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/index.js @@ -0,0 +1,999 @@ +/** + * Event-sourced session service: append-only session log, in-memory store, and + * the derived LLM message history. Persistence is a plugin concern (subscribe + * to `session/event`, drain on `session/flush`). + * + * @module @deepseek-ai/dsh-session + */ +import { Service } from '@deepseek-ai/cordis'; +import { isAbsolute } from 'node:path'; +import { deepFreeze } from '@deepseek-ai/dsh-llm'; +import { scopeOf, scopeTarget } from '@deepseek-ai/dsh-scope'; +import { SESSION_FORMAT_VERSION, SessionId } from "./types.js"; +import { snapshotJsonValue } from "./json.js"; +import { deriveEventMessage, SurfaceManager } from "./surface.js"; +import { foldRequestHeader } from "./request-header.js"; +export * from "./types.js"; +export { SessionPreparation } from "./preparation.js"; +export { isJsonValue, snapshotJsonValue } from "./json.js"; +export { interruptedTurnClosers, TOOL_NOT_STARTED, TOOL_OUTCOME_UNKNOWN } from "./repair.js"; +export { decodeStorageRecord, packChunkRuns } from "./chunk-rows.js"; +export { deriveEventMessage, foldSurface, isAppendSurfaceEvent, isReplacementSurfaceEvent, isSurfaceEvent, isSurfaceEligibleType } from "./surface.js"; +export { canonicalHeader, foldRequestHeader, headerEquals } from "./request-header.js"; +export { KNOWN_SESSION_EVENT_TYPES } from "./known-event-types.js"; +/** Validate and freeze one detached creation header in place. */ +function validateSessionHeader(id, input) { + if (input === null || typeof input !== 'object' || Array.isArray(input)) { + throw new Error('session header is not a plain JSON record'); + } + const record = input; + if (record.version !== SESSION_FORMAT_VERSION) { + throw new Error(`session header version must be ${SESSION_FORMAT_VERSION}, got ${String(record.version)}`); + } + if (record.id !== id) { + throw new Error(`session header id "${String(record.id)}" does not match session id "${id}"`); + } + if (typeof record.createdAt !== 'number' + || !Number.isSafeInteger(record.createdAt) + || record.createdAt < 0) { + throw new Error('session header createdAt must be a non-negative safe integer'); + } + if (record.cwd !== undefined) { + if (typeof record.cwd !== 'string') + throw new Error('session header cwd must be a string'); + if (!isAbsolute(record.cwd)) { + throw new Error(`session header cwd must be an absolute path, got "${record.cwd}"`); + } + } + if (record.parentSession !== undefined && typeof record.parentSession !== 'string') { + throw new Error('session header parentSession must be a string'); + } + if (record.seedLength !== undefined + && (typeof record.seedLength !== 'number' || !Number.isSafeInteger(record.seedLength) || record.seedLength < 0)) { + throw new Error('session header seedLength must be a non-negative safe integer'); + } + if (record.origin !== undefined && record.origin !== 'subagent') { + throw new Error('session header origin must be "subagent"'); + } + if (record.delegationDepth !== undefined + && (typeof record.delegationDepth !== 'number' || !Number.isSafeInteger(record.delegationDepth) || record.delegationDepth < 0)) { + throw new Error('session header delegationDepth must be a non-negative safe integer'); + } + if (record.agentPreset !== undefined && typeof record.agentPreset !== 'string') { + throw new Error('session header agentPreset must be a string'); + } + return deepFreeze(record); +} +/** Validate and freeze one exclusively owned persistence header in place. */ +function validateRestoredSessionHeader(id, input) { + if (input !== null && typeof input === 'object' && !Array.isArray(input)) { + const prototype = Reflect.getPrototypeOf(input); + if (prototype !== Object.prototype && prototype !== null) { + throw new Error('session header is not a plain JSON record'); + } + } + return validateSessionHeader(id, input); +} +/** Detach, validate, and freeze the creation metadata published by a session. */ +function snapshotSessionHeader(id, source) { + const input = source === undefined + ? { version: SESSION_FORMAT_VERSION, id, createdAt: Date.now() } + : source; + const snapshot = snapshotJsonValue(input); + if (snapshot === undefined) + throw new Error('session header is not losslessly JSON-serializable'); + return validateSessionHeader(id, snapshot); +} +/** + * Validate an exclusively owned event and deeply freeze its identified message + * without copying the event. The caller transfers an object graph that no + * producer retains and that shares no mutable children with another event. + * Use {@link snapshotSessionEvent} when exclusive ownership is not guaranteed. + * @param event - exclusively owned event imported across a trusted boundary. + * @returns the same event object with a validated, deeply frozen message. + */ +export function adoptSessionEvent(event) { + assertMessageEventShape(event, `session event at seq ${event.seq}`); + switch (event.type) { + case 'user/message': + deepFreeze(event.data); + break; + case 'assistant/message': + case 'tool/result': + deepFreeze(event.data.message); + break; + default: + // SessionEventMap is merge-extensible; plugin-owned events carry no core message. + break; + } + return event; +} +/** + * Detach one event while preserving deep immutability for its identified message. + * @param event - event imported across a query or persistence boundary. + * @returns a detached event snapshot with a validated, deeply frozen message. + */ +export function snapshotSessionEvent(event) { + return adoptSessionEvent(structuredClone(event)); +} +/** Deep-freeze one acyclic JSON tree without consuming the JavaScript call stack. */ +function freezeRestoredObject(value) { + const pending = [value]; + while (pending.length > 0) { + // The non-empty check proves an object remains to visit. + // oxlint-disable-next-line typescript/no-non-null-assertion + const current = pending.pop(); + Object.freeze(current); + for (const key in current) { + const child = current[key]; + if (child !== null && typeof child === 'object') + pending.push(child); + } + } + return value; +} +/** Validate the fixed event envelope after one-pass JSON materialization. */ +function assertSessionEventEnvelope(value, index) { + const event = value; + if (event['type'] === 'request/header-delta') { + throw new Error(`seed event at index ${index} uses unsupported legacy request/header-delta format`); + } + for (const key in event) { + switch (key) { + case 'type': + case 'seq': + case 'time': + case 'data': + case 'surfaceOp': + case 'sourceEventSeqs': + case 'ignorable': + break; + default: + throw new Error(`seed event at index ${index} has an invalid event envelope`); + } + } + const type = event['type']; + const seq = event['seq']; + const time = event['time']; + if (typeof type !== 'string' + || typeof seq !== 'number' || !Number.isSafeInteger(seq) || seq < 0 + || typeof time !== 'number' || !Number.isSafeInteger(time) + || event['data'] === undefined + || (event['ignorable'] !== undefined && event['ignorable'] !== true)) { + throw new Error(`seed event at index ${index} has an invalid event envelope`); + } + switch (type) { + case 'request/header': + case 'user/message': + case 'assistant/message': + case 'tool/result': + assertCurrentLlmShape(event, index); + break; + } +} +/** Reject obsolete request headers and malformed messages at the seed/load boundary. */ +function assertCurrentLlmShape(event, index) { + const data = event['data']; + const record = typeof data === 'object' && data !== null + ? data + : undefined; + if (event['type'] === 'request/header') { + const header = record?.['header']; + const headerRecord = typeof header === 'object' && header !== null && !Array.isArray(header) + ? header + : undefined; + const config = headerRecord?.['config']; + if (!hasProviderModel(config)) + throw new Error(`seed request/header at index ${index} lacks provider/model`); + const configRecord = config; + const reasoningEffort = configRecord['reasoningEffort']; + if (reasoningEffort !== undefined + && (typeof reasoningEffort !== 'string' || reasoningEffort.length === 0)) { + throw new Error(`seed request/header at index ${index} has an invalid reasoningEffort`); + } + assertAdapterDefaults(headerRecord?.['adapterDefaults'], configRecord, index); + } + const type = event['type']; + if (type !== 'user/message' && type !== 'assistant/message' + && type !== 'tool/result') + return; + assertMessageEventShape(event, `seed ${type} at index ${index}`); +} +const allowedAdapterKeys = new Set(['reasoningEffort', 'maxTokens']); +/** Validate adapter-default markers imported from a durable request header. */ +function assertAdapterDefaults(value, config, index) { + if (value === undefined) + return; + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + throw new Error(`seed request/header at index ${index} has invalid adapterDefaults`); + } + const defaults = value; + if (Object.keys(defaults).some(key => !allowedAdapterKeys.has(key)) + || Object.values(defaults).some(marker => marker !== true) + || defaults['reasoningEffort'] === true && config['reasoningEffort'] === undefined + || defaults['maxTokens'] === true && config['maxTokens'] === undefined) { + throw new Error(`seed request/header at index ${index} has invalid adapterDefaults`); + } +} +/** Validate only the event-specific invariants needed to safely replay a message. */ +function assertMessageEventShape(event, subject) { + const type = event['type']; + if (type !== 'user/message' && type !== 'assistant/message' + && type !== 'tool/result') + return; + const data = event['data']; + const record = typeof data === 'object' && data !== null + ? data + : undefined; + const message = type === 'user/message' ? record : record?.['message']; + if (typeof message !== 'object' || message === null + || typeof message['id'] !== 'string' + || message['id'] === '') { + throw new Error(`${subject} lacks an identified message`); + } + const messageRecord = message; + const expectedRole = type === 'assistant/message' ? 'assistant' : 'user'; + if (messageRecord['role'] !== expectedRole) { + throw new Error(`${subject} message must have role "${expectedRole}"`); + } + const source = messageRecord['source']; + if (typeof source !== 'object' || source === null + || typeof source['kind'] !== 'string' + || source['kind'] === '') { + throw new Error(`${subject} message has invalid source`); + } + if (!Array.isArray(messageRecord['content'])) { + throw new Error(`${subject} message has invalid content`); + } + const sourceRecord = source; + if (type === 'assistant/message') { + if (sourceRecord['kind'] !== 'model' || !hasProviderModel(sourceRecord)) { + throw new Error(`${subject} message must have model source`); + } + return; + } + if (type !== 'tool/result') + return; + if (sourceRecord['kind'] !== 'tool' + || typeof sourceRecord['callId'] !== 'string' + || sourceRecord['callId'] === '') { + throw new Error(`${subject} message must have tool source`); + } + const content = messageRecord['content']; + const block = content[0]; + if (content.length !== 1 || typeof block !== 'object' || block === null + || block['type'] !== 'tool-result' + || !Array.isArray(block['content'])) { + throw new Error(`${subject} message must contain one tool-result block`); + } + if (block['toolCallId'] !== sourceRecord['callId']) { + throw new Error(`${subject} message has mismatched tool call ids`); + } +} +/** Whether an unknown value carries the current provider/model pair. */ +function hasProviderModel(value) { + if (typeof value !== 'object' || value === null) + return false; + const pair = value; + return typeof pair['provider'] === 'string' && pair['provider'].length > 0 + && typeof pair['model'] === 'string' && pair['model'].length > 0; +} +/** Reject request-header vocabulary removed with the legacy delta codec. */ +function assertSupportedRequestHeader(type, data, location) { + if (type === 'request/header-delta') { + throw new Error(`${location} uses unsupported legacy request/header-delta format`); + } + if (type === 'request/header' + && data !== null && typeof data === 'object' && !Array.isArray(data) + && data['reason'] === 'fallback') { + throw new Error(`${location} uses unsupported legacy request/header reason "fallback"`); + } +} +/** Resolve one listener snapshot, including Cordis's internal dispatch checks. */ +function collectSessionCallbacks(ctx, args) { + return [...ctx.events.dispatch('emit', args)]; +} +/** Invoke one resolved observe-only listener snapshot with per-listener containment. */ +function invokeContainedSessionObservers(ctx, name, id, args, callbacks) { + for (const callback of callbacks) { + try { + const returned = callback(...args); + void Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`session "${id}": ${name} listener rejected: ${String(error)}`); + }); + } + catch (error) { + ctx.logger.warn(`session "${id}": ${name} listener threw: ${String(error)}`); + } + } +} +/** Store attachment for the append path; module-private to keep Session store-agnostic publicly. */ +const attachments = new WeakMap(); +/** + * An event-sourced session: an append-only log of {@link SessionEvent}s. + * + * Plain class (not a Service) — create live instances via + * `ctx.sessions.create()` and detached instances via {@link create}. + * Seeding with an existing event log replays/forks a session. + * @typert object + */ +export class Session { + log = []; + /** Single incremental owner of surface acceptance and projection state. */ + surfaceManager = new SurfaceManager(this.log); + /** The ordered surface over this session's event log. */ + get surface() { + return this.surfaceManager; + } + /** + * Detached, deep-frozen creation metadata (format version, cwd, lineage, + * seed boundary). Supplied by the store via `ctx.sessions.create()`. When a + * `Session` is created without a store-owned header, a minimal header is + * synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so + * `session.header` is always present. Kept out of the event log — it is a + * storage concern, not replayable conversation state. + */ + header; + /** The session identity, derived from its durable header's single copy. */ + get id() { + return this.header.id; + } + /** + * The first seq appended IN THIS PROCESS: the length of the constructor + * seed (0 without one). Events with smaller seq values entered through + * construction — replay, fork, or resume — and were never published on the + * `session/event` firehose (constructor seeds do not emit), so consumers + * that replay the log as a publication substitute (telemetry adoption) + * start here. Distinct from `header.seedLength`, the DURABLE fork-lineage + * boundary: a resumed session's constructor seed is its full stored log, + * while its header keeps the original fork value — this field is the + * in-process construction fact. + * + * Not persisted itself: a seeded session projects it into the log as the + * `session/end-seed` event, which is what a consumer reading STORED history + * reads. Locate the LAST such event, not necessarily one at this seq — a + * seed already ending in one is not re-marked, so reopening an untouched + * session leaves that event at a smaller seq than `firstLiveSeq`. Prefer + * this field in-process: it is exact before the marker reaches storage. + * + * When this lifecycle appends the marker, it occupies this seq before the + * store attaches and therefore does not publish either. Otherwise this seq + * holds an ordinary published write. + */ + firstLiveSeq; + /** + * Create a detached session by validating and snapshotting borrowed seed + * events and storage metadata. + * @param id - session identity. + * @param seed - optional borrowed replay or fork events. + * @param header - optional borrowed storage metadata. + * @returns a detached session. + */ + static create(id, seed, header) { + return new Session(id, seed, header); + } + /** + * Restore a detached session by taking ownership of fresh persistence values. + * The storage format, event envelopes, sequence continuity, surface transitions, + * and header fields are validated before the restored objects are frozen. + * @param id - restored session identity. + * @param seed - fresh detached events whose ownership is transferred. + * @param header - fresh detached metadata whose ownership is transferred. + * @returns a restored detached session. + */ + static fromRestore(id, seed, header) { + return new Session(id, seed, header, 'restore'); + } + constructor(id, seed, header, mode = 'snapshot') { + const restoredHeader = mode === 'restore' + ? validateRestoredSessionHeader(id, header) + : undefined; + if (seed !== undefined) { + // Validate the seed to the SAME invariants `append` enforces, so a + // replay/fork (`ctx.sessions.create(id, { seed })`) cannot construct a + // live log that no persistence backend could store: each event's `data` + // must be JSON-serializable, and `seq` must be contiguous from 0 (the + // `seq = log.length` contract the whole system relies on). Without this, + // a bad seed would surface only later as a backend rejection or a silent + // divergence between the live log and disk. + for (const [index, source] of seed.entries()) { + // The seed is a persistence/replay boundary: validate and detach the + // complete event in one lossless-JSON pass. + const snapshot = mode === 'restore' ? source : snapshotJsonValue(source); + if (snapshot === undefined) { + throw new Error(`seed event at index ${index} is not losslessly JSON-serializable`); + } + assertSessionEventEnvelope(snapshot, index); + assertSupportedRequestHeader(snapshot.type, snapshot.data, `seed event at index ${index}`); + if (snapshot.seq !== index) { + throw new Error(`seed event at index ${index} has seq ${snapshot.seq} (expected ${index}); seed must be contiguous from 0`); + } + // A seed is accepted incrementally through the same transition as a + // live append and a full-log fold. The candidate is planned before it + // enters `log`, so a failure cannot partially mutate the surface. + try { + this.surfaceManager.validateNext(snapshot); + } + catch (error) { + throw new Error(`invalid seed event at index ${index}: ${error instanceof Error ? error.message : 'invalid surface metadata'}`); + } + this.log.push(mode === 'restore' ? freezeRestoredObject(snapshot) : deepFreeze(snapshot)); + } + } + this.firstLiveSeq = this.log.length; + this.header = restoredHeader ?? snapshotSessionHeader(id, header); + // Appended here so the marker is already in `events` when a backend + // captures the creation seed: no load-time write. Re-marking is skipped + // because a cold session is resumed on first touch, so repeatedly opening + // one must not grow its log per open. + if (seed !== undefined && this.log.at(-1)?.type !== 'session/end-seed') { + this.append('session/end-seed', {}); + } + } + /** Cached immutable public snapshot of the private append-only log. */ + eventsSnapshot; + /** + * An immutable snapshot of the append-only event log. The snapshot is reused + * until the next append; a previously returned array does not grow later. + * Events and their nested data are deep-frozen at acceptance, so neither a + * cast nor ordinary JavaScript can rewrite durable history. + */ + get events() { + this.eventsSnapshot ??= Object.freeze([...this.log]); + return this.eventsSnapshot; + } + /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */ + get seq() { + return this.log.length; + } + /** + * Append one typed event to the log and synchronously notify observers via + * the store-owned, module-private publication hooks. The hot path never blocks + * on I/O — persistence plugins buffer asynchronously. Once the event enters + * the log, the append is committed: observer failures are logged and + * contained per listener, so they do not change the return value or prevent + * later listeners from observing the same accepted event. + * + * @param type - The event type (key of {@link SessionEventMap}). + * @param data - The event payload; must be JSON-serializable. + * @param opts - Surface metadata: `surfaceOp` controls how the event enters + * the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier + * events this one derives from. REQUIRED for + * {@link SurfaceEventType} events (every message-producing event must + * declare how it joins the surface, the sole source of derived model + * history) and + * rejected by the compiler for non-surface types like `turn/start` or + * `assistant/chunk`. + * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of + * `data` that entered the log, so reading `event.data` back sees the logged + * value, never the caller's still-mutable input. + * @throws if `data` or surface metadata is not losslessly JSON-serializable + * (BigInt, function, symbol, undefined, negative zero, non-finite number, + * circular reference, sparse array, or an exotic object such as + * Map/Set/Date/class instance), or when the candidate violates the + * canonical surface contract (marker shape and eligibility, unique + * earlier source-event references, positional replacement validity, and complete + * shadowed-node coverage). One recursive pass reads, validates, and + * copies each nested value once, so a stateful getter cannot supply one value + * to validation and another to storage. The event log is the durable source + * of truth, so a bad event fails at the append site rather than later during + * a backend flush. A synchronous internal dispatch validation failure or an + * append reentered while this acceptance/publication boundary is open also + * rejects before the log changes. + */ + append(type, data, ...opts) { + const surfaceOpts = opts[0]; + const surfaceMetadata = { + ...surfaceOpts?.sourceEventSeqs === undefined ? {} : { sourceEventSeqs: surfaceOpts.sourceEventSeqs }, + ...surfaceOpts?.surfaceOp === undefined ? {} : { surfaceOp: surfaceOpts.surfaceOp }, + }; + const dataSnapshot = snapshotJsonValue(data); + if (dataSnapshot === undefined) { + throw new Error(`session event "${type}" carries non-JSON-serializable data`); + } + assertSupportedRequestHeader(type, dataSnapshot, `session event "${type}"`); + const surfaceMetadataSnapshot = snapshotJsonValue(surfaceMetadata); + if (surfaceMetadataSnapshot === undefined) { + throw new Error(`session event "${type}" carries non-JSON-serializable surface metadata`); + } + const entry = attachments.get(this); + if (entry?.appending) { + throw new Error('session append cannot reenter while another append is being published'); + } + const event = deepFreeze({ + type, + seq: this.log.length, + time: Date.now(), + data: dataSnapshot, + ...surfaceMetadataSnapshot, + }); + this.surfaceManager.validateNext(event); + if (entry !== undefined) + entry.appending = true; + try { + let callbacks; + const callbackArgs = [this, event]; + if (entry !== undefined) { + callbacks = collectSessionCallbacks(entry.emitCtx, [entry.carrier, 'session/event', ...callbackArgs]); + } + this.log.push(event); + this.eventsSnapshot = undefined; + if (callbacks !== undefined && entry !== undefined) { + invokeContainedSessionObservers(entry.emitCtx, 'session/event', entry.id, callbackArgs, callbacks); + } + return event; + } + finally { + if (entry !== undefined) { + entry.appending = false; + if (entry.detachRequested && !entry.announcing) + entry.detach(); + } + } + } + /** Cached fold of the request-header events — see {@link requestHeader}. */ + headerFold; + /** Log position (events consumed) the header fold has reached. */ + headerFoldSeq = 0; + /** + * The {@link EpochHeader} in force after the log's last header event — the + * header the NEXT request will be compared against — or undefined before + * the first `request/header` snapshot. The live, incrementally-maintained + * form of `foldRequestHeader(session.events)`: each header event is folded + * once, when first seen, so a per-step read costs O(new events). + * @returns the folded header, or undefined when no header event exists yet. + */ + requestHeader() { + if (this.headerFoldSeq < this.log.length) { + // Frozen on update: the fold is session state exposed by reference — a + // consumer mutating it in place (instead of building a replacement) + // would desync every later comparison against the log, so mutation + // throws instead. + this.headerFold = deepFreeze(foldRequestHeader(this.log.slice(this.headerFoldSeq), this.headerFold)); + this.headerFoldSeq = this.log.length; + } + return this.headerFold; + } + /** Cached fold of `request/context` events. */ + contextFold; + contextFoldSeq = 0; + /** + * Return the latest resolved route metadata, or `undefined` before the first + * `request/context` event. Each event is folded once. + * @returns the latest immutable route metadata. + */ + requestContext() { + if (this.contextFoldSeq < this.log.length) { + for (const event of this.log.slice(this.contextFoldSeq)) { + if (event.type === 'request/context') + this.contextFold = deepFreeze({ ...event.data }); + } + this.contextFoldSeq = this.log.length; + } + return this.contextFold; + } + /** The derived-message cache: frozen projections, extended per unseen node. */ + derived = []; + /** Surface position (nodes projected) the cache has reached. */ + derivedNodes = 0; + /** {@link SurfaceManager.replaceGeneration} the cache was built under. */ + derivedGeneration = 0; + /** + * Derive the LLM message history by walking the ordered sequences of + * message-producing events maintained by `surfaceOp` markers. The + * surface is the single source of derived history: every message-producing + * append records its `surfaceOp`, so a raw event with no marker (a chunk, a + * turn boundary) is correctly absent, and a compaction `replace` deletes the + * shadowed nodes from the derivation. The projection rules are + * {@link deriveEventMessage}, folded per node. + * + * CACHED: each surface node is projected exactly once, when first seen — a + * call costs O(new nodes), and a surface rewrite (a `replace`; + * {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is + * a fresh snapshot per call (later appends never grow an array a caller + * already holds); the `Message` objects in it are SHARED and **deep-frozen**. + * Their content reuses the already frozen durable event data, so the cache + * needs no second deep clone and consumers still cannot mutate the log. + * @returns a fresh array of the shared, frozen derived history. + */ + deriveMessages() { + const surface = this.surface; + const nodes = surface.nodes; + const generation = surface.replaceGeneration; + if (generation !== this.derivedGeneration) { + this.derived = []; + this.derivedNodes = 0; + this.derivedGeneration = generation; + } + for (const seq of nodes.slice(this.derivedNodes)) { + // Surface sequences are built from this.log — seq is always a valid + // index by construction. The non-null assertion expresses that invariant. + // oxlint-disable-next-line typescript/no-non-null-assertion + const msg = this.deriveEventMessage(this.log[seq]); + // A surface node is one of the five message-producing types, but an + // empty-content assistant/message (a max-tokens step that hosts only + // usage) derives to null and must not enter the transcript. + if (msg) + this.derived.push(msg); + } + this.derivedNodes = nodes.length; + return [...this.derived]; + } + /** + * Instance face of the pure per-node `deriveEventMessage` export from + * `surface.ts`. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ + deriveEventMessage(event) { + return deriveEventMessage(event); + } +} +/** Typed error for session fork rejections. */ +export class SessionForkError extends Error { + code; + constructor(message, code) { + super(message); + this.code = code; + this.name = 'SessionForkError'; + } +} +/** + * In-memory session store (`ctx.sessions`). + * + * Persistence is intentionally not implemented here — persistence plugins + * subscribe to `session/event` and flush on `session/flush` / dispose. + */ +export class SessionStore extends Service { + store = new Map(); + counter = 0; + constructor(ctx) { + super(ctx, 'sessions'); + ctx.inject(['typert'], (typeCtx) => { + typeCtx.typert.lookups.register('session', { + parameter: 'session', + wire: 'sessionId', + hostTypeSymbol: '@deepseek-ai/dsh-session#Session', + wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + resolve: sessionId => this.get(sessionId), + }); + }); + } + /** + * Create a session owned by the calling fiber: disposing that fiber stops + * event notification and removes the session from the store. `options.seed` + * populates the session with a copy of those events (replay/fork); + * `options.meta` attaches creation metadata (validated absolute `cwd`, seed + * and parent lineage, and delegation depth) as the immutable + * {@link SessionHeader} (the store fills `version`/`id`/`createdAt`). + * + * For an agent whose session must be torn down IN ORDER with its loop (so the + * loop's final events are published before the store attachment ends), do NOT use this + * — fold the session lifecycle into the agent's own effect via + * {@link prepare} + {@link enter} + {@link announce} (see + * `dsh-agent-loop`'s creation transaction). + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. + * @returns the live session, already entered and announced. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path (storage backends key directories off it). + */ + create(id, options) { + const session = this.prepare(id, options); + // Single effect owned by the calling fiber. Yield the detach BEFORE + // announcing so a throwing `session/created` listener rolls the attach back + // (the generator effect disposes already-yielded disposers on a throw) + // instead of leaking the store entry and its publication hooks. + this.ctx.effect(function* () { + yield this.enter(session); + this.announce(session); + }.bind(this), 'sessions.create()'); + return session; + } + /** + * Build a session WITHOUT entering it into the store — validate the id/cwd and + * construct the {@link Session} (with its immutable {@link SessionHeader}). + * Pairs with {@link enter} + {@link announce}: a caller that owns a composite + * `ctx.effect` (the agent factory) folds the session lifecycle into that ONE + * effect so a fiber unload tears the session + agent down as a single ORDERED + * chain rather than as racing sibling effects — which would remove the publication hooks + * before the driver's closing events commit, dropping them. + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. With + * `seedSource: 'persistence'`, metadata and events must be fresh detached + * graphs whose ownership transfers to this call: they are validated and + * frozen in place through {@link Session.fromRestore}, so the caller must + * retain no mutable aliases. + * @returns the constructed session, NOT yet in the store. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path. + */ + prepare(id, options) { + let sessionId; + if (id === undefined) { + do + sessionId = SessionId(`session-${++this.counter}`); + while (this.store.has(sessionId)); + } + else { + sessionId = SessionId(id); + } + if (this.store.has(sessionId)) + throw new Error(`session "${sessionId}" already exists`); + if (options?.seedSource === 'persistence') { + return Session.fromRestore(sessionId, options.seed, options.meta); + } + const seed = options?.seed; + const meta = options?.meta; + const header = { + version: SESSION_FORMAT_VERSION, + id: sessionId, + createdAt: meta?.createdAt ?? Date.now(), + ...meta?.cwd === undefined ? {} : { cwd: meta.cwd }, + ...meta?.parentSession === undefined ? {} : { parentSession: meta.parentSession }, + ...meta?.seedLength === undefined ? {} : { seedLength: meta.seedLength }, + ...meta?.origin === undefined ? {} : { origin: meta.origin }, + ...meta?.delegationDepth === undefined ? {} : { delegationDepth: meta.delegationDepth }, + ...meta?.agentPreset === undefined ? {} : { agentPreset: meta.agentPreset }, + }; + return Session.create(sessionId, seed, header); + } + /** + * Enter a {@link prepare}d session into the store: install the module-private + * append publication hooks and add it to the store. Returns the DETACH + * disposer (hooks + store removal). Does NOT emit `session/created` — + * the caller yields this disposer inside its effect and THEN calls + * {@link announce}, so a throwing `session/created` listener rolls the attach + * back instead of leaking it. + * + * Re-checks the id for a duplicate: `prepare` and `enter` are public + * cross-package primitives and a caller may interleave arbitrary work (or + * another create) between them, so a stale prepared session must NOT overwrite + * a live store entry of the same id — its detach disposer would later delete + * the REAL session. The {@link create} convenience and the agent factory call + * the two back-to-back so they never trip this, but the public API cannot + * assume that. + * + * @param session - a {@link prepare}d session not yet in the store. + * @returns the detach disposer (publication hooks + store removal). When called from + * a synchronous `session/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + * @throws if a session with this id is already in the store. + */ + enter(session) { + const id = session.id; + const carrier = scopeTarget(session, scopeOf(this.ctx)); + // This is the authoritative collision boundary after arbitrary unpublished + // preparation. Only one exact same-id transaction can publish. + if (this.store.has(id)) + throw new Error(`session "${id}" already exists`); + if (attachments.has(session)) + throw new Error(`session "${id}" is already attached to a store`); + const entry = { + id, + session, + carrier, + emitCtx: this.ctx, + announced: false, + announcing: false, + appending: false, + detachRequested: false, + detach: () => { this.detachEntered(entry); }, + }; + this.store.set(id, entry); + attachments.set(session, entry); + let entered = true; + const detach = () => { + if (!entered) + return; + entered = false; + // A lifecycle listener may own the advanced detach capability. Keep the + // entry and its publication hooks live until synchronous creation or append + // publication unwinds, then publish the paired disposal edge. + if (entry.announcing || entry.appending) { + entry.detachRequested = true; + return; + } + entry.detach(); + }; + return detach; + } + /** Remove one exact entered session and emit its paired disposal when announced. */ + detachEntered(entry) { + entry.detachRequested = false; + // A stale capability cannot remove observers or storage belonging to a + // later same-id lifecycle. + /* v8 ignore next -- enter() rejects replacement while this single-shot detach capability is live. */ + if (this.store.get(entry.id) !== entry) + return; + this.store.delete(entry.id); + attachments.delete(entry.session); + if (entry.announced) + this.emitDisposed(entry); + } + /** Emit `session/created` exactly once for an {@link enter}ed session (with + * the carrier {@link enter} captured). Separate from {@link enter} so the + * caller can yield the detach disposer first (rollback safety — see + * {@link enter}). + * @param session - the entered session to announce to listeners. + * @throws if the session is not live or its announcement already began, + * including a reentrant call from a creation listener. */ + announce(session) { + const entry = this.liveEntryFor(session); + if (entry.announced || entry.announcing) { + throw new Error(`session "${entry.id}" was already announced`); + } + // Mark before emit: Cordis emit may deliver to earlier listeners and then + // throw. Rollback must still pair that partial creation with disposal, and + // a listener cannot recursively create a second lifecycle edge. + entry.announced = true; + const callbackArgs = [session]; + entry.announcing = true; + try { + const callbacks = collectSessionCallbacks(this.ctx, [entry.carrier, 'session/created', session]); + for (const callback of callbacks) { + // Synchronous throws intentionally propagate and veto publication; the + // yielded detach then emits the paired disposal edge. An async function + // is nevertheless assignable to a void listener, so observe its returned + // promise: rejection is too late to roll back and must be logged instead + // of becoming unhandled. + const returned = callback(...callbackArgs); + void Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`session "${entry.id}": session/created listener rejected: ${String(error)}`); + }); + } + } + finally { + entry.announcing = false; + if (entry.detachRequested && !entry.appending) + entry.detach(); + } + } + /** Emit the paired teardown notification with per-listener containment. */ + emitDisposed(entry) { + const callbackArgs = [entry.session]; + try { + const callbacks = collectSessionCallbacks(this.ctx, [entry.carrier, 'session/disposed', entry.session]); + invokeContainedSessionObservers(this.ctx, 'session/disposed', entry.id, callbackArgs, callbacks); + } + catch (error) { + this.ctx.logger.warn(`session "${entry.id}": session/disposed dispatch threw: ${String(error)}`); + } + } + /** + * Dispatch the awaited `session/flush` durability checkpoint for `session`, + * with the carrier captured at {@link enter}. THE flush entry point: the + * store owns the carrier, so callers (the checkpoint policy's per-request + * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers + * that flush themselves before reading storage) must come through here + * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner, + * one spelling, and the scoped-dispatch invariant can pin it. + * @param session - the session whose buffered events must reach durable storage. + * @returns whether at least one durability listener participated, after every + * listener has settled successfully. + * @throws the first registered listener failure after every listener settles. + */ + async flush(session) { + const { carrier } = this.liveEntryFor(session); + const callbackArgs = [session]; + const callbacks = collectSessionCallbacks(this.ctx, [carrier, 'session/flush', session]); + const results = await Promise.allSettled(callbacks.map((callback) => { + try { + return callback(...callbackArgs); + } + catch (error) { + // Preserve the listener's exact rejection value; flush is a caller-owned + // failure boundary, and Cordis listeners may throw arbitrary values. + // oxlint-disable-next-line typescript/prefer-promise-reject-errors + return Promise.reject(error); + } + })); + const failure = results.find((result) => result.status === 'rejected'); + if (failure !== undefined) + throw failure.reason; + return callbacks.length > 0; + } + /** Return the exact live entry; detached/prepared objects reject. */ + liveEntryFor(session) { + const entry = attachments.get(session); + if (entry === undefined || this.store.get(entry.id) !== entry) { + throw new Error(`session "${session.id}" is not live in this store`); + } + return entry; + } + /** + * Look up a live session. + * @param id - the session id to look up. + * @returns the session, or undefined when no live session has that id. + */ + get(id) { + return this.store.get(id)?.session; + } + /** + * All live sessions, in creation order. + * @returns a fresh array; mutating it does not affect the store. + */ + list() { + return [...this.store.values()].map(entry => entry.session); + } + /** + * Create a live child session from a stable prefix of a live source. + * `boundary` is an inclusive source event seq; omitted means the source's + * current last event. The selected slice may end with a between-turn event + * but must not end inside an open turn. + * + * @param source - Live source session object or id. + * @param boundary - Inclusive source event seq to fork through; omitted means + * the source's current last event, and omitted on an empty source forks an + * empty child. + * @param childSessionId - Optional child session id; omitted delegates to + * `SessionStore`'s id policy. + * @returns The created live child session. + */ + fork(source, boundary, childSessionId) { + if (childSessionId !== undefined && this.get(childSessionId) !== undefined) { + throw new SessionForkError(`session "${childSessionId}" already exists`, 'SESSION_ALREADY_EXISTS'); + } + const liveSource = this._resolveForkSource(source); + const seed = this._forkSeed(liveSource, boundary); + return this.create(childSessionId, { + seed, + meta: { + ...liveSource.header.cwd !== undefined ? { cwd: liveSource.header.cwd } : {}, + parentSession: liveSource.id, + seedLength: seed.length, + }, + }); + } + _forkSeed(session, requestedBoundary) { + const events = session.events; + const lastEvent = events.at(-1); + let boundary; + if (requestedBoundary !== undefined) { + boundary = requestedBoundary; + } + else { + if (lastEvent === undefined) + return []; + boundary = lastEvent.seq; + } + if (!Number.isSafeInteger(boundary) || boundary < 0) { + throw new SessionForkError(`fork boundary for session "${session.id}" must be a non-negative safe integer, got ${String(boundary)}`, 'INVALID_BOUNDARY'); + } + if (boundary >= events.length) { + const lastSeq = events.at(-1)?.seq; + throw new SessionForkError(`fork boundary ${boundary} does not exist in session "${session.id}" (last seq: ${lastSeq ?? 'none'})`, 'INVALID_BOUNDARY'); + } + const boundaryEvent = events[boundary]; + if (boundaryEvent === undefined || boundaryEvent.seq !== boundary) { + throw new SessionForkError(`fork boundary ${boundary} does not match a contiguous event seq in session "${session.id}"`, 'INVALID_BOUNDARY'); + } + const lastTurnBoundary = events.slice(0, boundary + 1) + .findLast(event => event.type === 'turn/start' || event.type === 'turn/end'); + if (lastTurnBoundary?.type === 'turn/start') { + throw new SessionForkError(`fork boundary ${boundary} in session "${session.id}" ends inside open turn ${lastTurnBoundary.data.turn}`, 'OPEN_TURN'); + } + return events.slice(0, boundary + 1); + } + _resolveForkSource(source) { + if (typeof source === 'string') { + const session = this.get(source); + if (session === undefined) + throw new SessionForkError(`session "${source}" not found`, 'SESSION_NOT_FOUND'); + return session; + } + const live = this.get(source.id); + if (live === undefined) { + throw new SessionForkError(`session "${source.id}" not found`, 'SESSION_NOT_FOUND'); + } + if (live !== source) + throw new SessionForkError(`session "${source.id}" is not the live store instance`, 'SESSION_NOT_LIVE'); + return source; + } +} +export default SessionStore; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.d.ts new file mode 100644 index 0000000..6652847 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.d.ts @@ -0,0 +1,18 @@ +/** + * Package-owned relational invariants for the session event log. Load this + * companion beside `@deepseek-ai/dsh-invariants` to enable the checks. + * + * @module @deepseek-ai/dsh-session/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the session invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.js new file mode 100644 index 0000000..c685d9f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.js @@ -0,0 +1,199 @@ +/** + * Package-owned relational invariants for the session event log. Load this + * companion beside `@deepseek-ai/dsh-invariants` to enable the checks. + * + * @module @deepseek-ai/dsh-session/invariant + */ +import { assertNever } from '@deepseek-ai/dsh-llm'; +import { TOOL_NOT_STARTED } from "./repair.js"; +const PACKAGE_NAME = '@deepseek-ai/dsh-session'; +/** Cordis companion plugin name. */ +export const name = 'session-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Assert that a step-scoped event names the currently open turn and step. */ +function requireOpenStep(trace, kind, turn, step, fail) { + if (trace.openTurn !== turn || trace.openStep !== step) { + fail(`${kind} names turn ${turn}/step ${step} but open is turn ${trace.openTurn}/step ${trace.openStep}`); + } +} +/** Validate one candidate event without mutating the committed trace. */ +function validateEvent(trace, event, fail) { + if (event.seq <= trace.lastSeq) { + fail(`seq must strictly increase: saw ${event.seq} after ${trace.lastSeq}`); + } + let openTurn = trace.openTurn; + let openStep = trace.openStep; + let nextTurn = trace.nextTurn; + let nextStep = trace.nextStep; + let pendingCalls = { kind: 'none' }; + // Context and plugin-owned log-only events may be appended between model + // executions. Core execution events retain their explicit turn relations. + switch (event.type) { + case 'turn/start': { + if (trace.openTurn !== null) { + fail(`turn/start ${event.data.turn} while turn ${trace.openTurn} is still open`); + } + if (event.data.turn !== trace.nextTurn) { + fail(`turn/start expected turn ${trace.nextTurn}, got ${event.data.turn}`); + } + openTurn = event.data.turn; + nextStep = 1; + break; + } + case 'turn/end': { + if (trace.openTurn !== event.data.turn) { + fail(`turn/end ${event.data.turn} does not match open turn ${trace.openTurn}`); + } + if (trace.openStep !== null) { + fail(`turn/end ${event.data.turn} while step ${trace.openStep} is still open`); + } + openTurn = null; + nextTurn += 1; + break; + } + case 'step/start': { + if (trace.openTurn !== event.data.turn) { + fail(`step/start in turn ${event.data.turn} but open turn is ${trace.openTurn}`); + } + if (trace.openStep !== null) { + fail(`step/start ${event.data.step} while step ${trace.openStep} is still open`); + } + if (event.data.step !== trace.nextStep) { + fail(`step/start expected step ${trace.nextStep} in turn ${event.data.turn}, got ${event.data.step}`); + } + openStep = event.data.step; + break; + } + case 'step/end': { + requireOpenStep(trace, 'step/end', event.data.turn, event.data.step, fail); + pendingCalls = { kind: 'clear' }; + openStep = null; + nextStep += 1; + break; + } + case 'assistant/chunk': { + requireOpenStep(trace, 'assistant/chunk', event.data.turn, event.data.step, fail); + break; + } + case 'assistant/message': { + requireOpenStep(trace, 'assistant/message', event.data.turn, event.data.step, fail); + break; + } + case 'tool/call': { + requireOpenStep(trace, 'tool/call', event.data.turn, event.data.step, fail); + pendingCalls = { kind: 'add', callId: event.data.callId }; + break; + } + case 'tool/result': { + // Session has already validated a content rewrite that cites its replaced event. + // It is durable turn work, not a second execution of the original call. + if (event.surfaceOp !== 'append') { + if (trace.openTurn === null) { + fail('tool/result surface replacement appended outside any open turn'); + } + break; + } + requireOpenStep(trace, 'tool/result', event.data.turn, event.data.step, fail); + const callId = event.data.message.source.callId; + const syntheticNotStarted = event.data.message.content[0].isError === true && event.data.error?.code === TOOL_NOT_STARTED; + if (!trace.pendingCalls.has(callId) && !syntheticNotStarted) { + fail(`tool/result for ${callId} with no prior tool/call in this step`); + } + pendingCalls = { kind: 'delete', callId }; + break; + } + case 'user/message': + break; + case 'session/end-seed': + // Unconstrained: an unbalanced seed legally puts it inside an open turn. + break; + case 'todo/write': + case 'request/header': + case 'request/context': { + if (trace.openTurn === null) { + fail(`${event.type} appended outside any open turn (core execution events must be turn-enclosed)`); + } + break; + } + default: + // Merge-extensible event relations belong to their owning plugin. + break; + } + return { + scalars: { lastSeq: event.seq, openTurn, openStep, nextTurn, nextStep }, + pendingCalls, + }; +} +/** Apply one already-validated transition after its event commits. */ +function applyTransition(trace, transition) { + Object.assign(trace, transition.scalars); + switch (transition.pendingCalls.kind) { + case 'none': + break; + case 'add': + trace.pendingCalls.add(transition.pendingCalls.callId); + break; + case 'delete': + trace.pendingCalls.delete(transition.pendingCalls.callId); + break; + case 'clear': + trace.pendingCalls.clear(); + break; + /* v8 ignore next -- validateEvent produces this closed transition union */ + default: + assertNever(transition.pendingCalls, 'session trace pending-call transition'); + } +} +/** Install the session contribution into its child registration fiber. */ +const install = Object.assign((ctx, fail) => { + const traces = new WeakMap(); + const stagedTransitions = new WeakMap(); + const freshTrace = () => ({ + lastSeq: -1, + openTurn: null, + openStep: null, + nextTurn: 1, + nextStep: 1, + pendingCalls: new Set(), + }); + const seedSession = (session) => { + const trace = freshTrace(); + traces.set(session, trace); + for (const event of session.events) { + applyTransition(trace, validateEvent(trace, event, fail)); + } + return trace; + }; + /* v8 ignore next -- session/event always follows list() or session/created seeding */ + const traceFor = (session) => traces.get(session) ?? seedSession(session); + for (const session of ctx.sessions.list()) + seedSession(session); + ctx.on('session/created', (session) => { seedSession(session); }, { global: true }); + ctx.on('session/event', (session, event) => { + const staged = stagedTransitions.get(event); + /* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */ + if (staged === undefined || staged.session !== session) { + return fail('session/event reached publication without matching pre-commit validation'); + } + stagedTransitions.delete(event); + applyTransition(staged.trace, staged.transition); + }, { global: true }); + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') + return; + const [session, event] = args; + const trace = traceFor(session); + const transition = validateEvent(trace, event, fail); + // A later dispatch listener may veto. Validation is pure, so abandoning + // this weakly keyed transition does not advance or retain the session. + stagedTransitions.set(event, { session, trace, transition }); + }, { global: true }); +}, { inject: ['sessions'] }); +/** + * Register the session invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/json.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/json.d.ts new file mode 100644 index 0000000..baf05c6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/json.d.ts @@ -0,0 +1,36 @@ +/** Lossless-JSON validation and detached snapshots for durable session data. @module @deepseek-ai/dsh-session/json */ +/** + * A value that round-trips losslessly through JSON: `null`, a boolean, a finite + * number other than negative zero, a string, an array of such values, or a + * plain object whose values are such values. Arrays may carry only their dense + * indexed elements; extra own properties would be discarded by JSON. TypeScript + * cannot distinguish `-0` from `number`, so {@link isJsonValue} and + * {@link snapshotJsonValue} enforce these details at runtime. Use this type for + * a payload that must survive session-log persistence and replay byte-identically + * — e.g. a tool's private presentation `meta`. + */ +export type JsonValue = null | boolean | number | string | JsonValue[] | { + [key: string]: JsonValue; +}; +/** + * Validate and detach lossless JSON in one read per property, so a stateful + * getter cannot change between validation and copying. Traversal is iterative, + * so valid nesting is bounded by available memory rather than the JavaScript + * call stack. Accepts ordinary arrays, plain or null-prototype objects, and JSON + * scalars; rejects sparse, cyclic, exotic, negative-zero, and non-finite values. + * Getter throws propagate. + * + * @param value - the candidate value to validate and detach. + * @returns the detached snapshot, or `undefined` when the value is not + * losslessly JSON-serializable. + */ +export declare function snapshotJsonValue(value: T): T | undefined; +/** + * Test the same lossless JSON boundary as {@link snapshotJsonValue} without + * detaching it. Only own enumerable string properties participate; `toJSON` + * is ignored and getters run, so persistence boundaries use the snapshotter. + * @param value - the candidate event data to test. + * @returns whether `value` survives JSON round-trip losslessly. + */ +export declare function isJsonValue(value: unknown): boolean; +//# sourceMappingURL=json.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/json.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/json.js new file mode 100644 index 0000000..de672ae --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/json.js @@ -0,0 +1,174 @@ +/** Lossless-JSON validation and detached snapshots for durable session data. @module @deepseek-ai/dsh-session/json */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor'); + const constructor = descriptor?.value; + if (typeof constructor !== 'function') + return false; + try { + return constructor.name === name + && constructor.prototype === prototype + && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } + catch { + return false; + } +} +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value) { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, 'Object'); +} +/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) + return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === 'object' + && objectPrototype !== null + && isIntrinsicObjectPrototype(objectPrototype); +} +/** Whether an object is a plain or null-prototype record from any JavaScript realm. */ +function hasPlainObjectPrototype(value) { + const prototype = Object.getPrototypeOf(value); + return prototype === null + || typeof prototype === 'object' && isIntrinsicObjectPrototype(prototype); +} +/** Return every JSON-visible object key, or reject own data JSON would discard. */ +function enumerableStringKeys(value) { + const keys = Reflect.ownKeys(value); + if (keys.some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) + return undefined; + return keys; +} +/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */ +function walkJsonValue(value, detach) { + const ancestors = new Set(); + let root; + const assign = (destination, item) => { + if (destination === undefined) + return; + if (destination.kind === 'root') { + root = item; + } + else if (destination.kind === 'array') { + destination.target[destination.index] = item; + } + else { + Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true, + }); + } + }; + const tasks = [{ + kind: 'visit', + value, + ...(detach ? { destination: { kind: 'root' } } : {}), + }]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + ancestors.delete(task.source); + continue; + } + if (task.kind === 'array-item') { + if (!Object.prototype.hasOwnProperty.call(task.source, task.index)) + return undefined; + tasks.push({ + kind: 'visit', + value: task.source[task.index], + ...(task.target === undefined ? {} : { destination: { kind: 'array', target: task.target, index: task.index } }), + }); + continue; + } + if (task.kind === 'object-property') { + tasks.push({ + kind: 'visit', + value: task.source[task.key], + ...(task.target === undefined ? {} : { destination: { kind: 'object', target: task.target, key: task.key } }), + }); + continue; + } + const current = task.value; + if (current === null) { + assign(task.destination, null); + continue; + } + if (typeof current === 'boolean' || typeof current === 'string') { + assign(task.destination, current); + continue; + } + if (typeof current === 'number') { + if (!Number.isFinite(current) || Object.is(current, -0)) + return undefined; + assign(task.destination, current); + continue; + } + if (typeof current !== 'object') + return undefined; + if (ancestors.has(current)) + return undefined; + if (Array.isArray(current)) { + if (!hasPlainArrayPrototype(current)) + return undefined; + const length = current.length; + if (Reflect.ownKeys(current).length !== length + 1) + return undefined; + const target = detach ? [] : undefined; + if (target !== undefined) + assign(task.destination, target); + ancestors.add(current); + tasks.push({ kind: 'leave', source: current }); + for (let index = length - 1; index >= 0; index--) { + tasks.push({ kind: 'array-item', source: current, index, ...(target === undefined ? {} : { target }) }); + } + continue; + } + if (!hasPlainObjectPrototype(current)) + return undefined; + const keys = enumerableStringKeys(current); + if (keys === undefined) + return undefined; + const target = detach ? {} : undefined; + if (target !== undefined) + assign(task.destination, target); + ancestors.add(current); + tasks.push({ kind: 'leave', source: current }); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) + return undefined; + tasks.push({ kind: 'object-property', source: current, key, ...(target === undefined ? {} : { target }) }); + } + } + return detach ? root : true; +} +/** + * Validate and detach lossless JSON in one read per property, so a stateful + * getter cannot change between validation and copying. Traversal is iterative, + * so valid nesting is bounded by available memory rather than the JavaScript + * call stack. Accepts ordinary arrays, plain or null-prototype objects, and JSON + * scalars; rejects sparse, cyclic, exotic, negative-zero, and non-finite values. + * Getter throws propagate. + * + * @param value - the candidate value to validate and detach. + * @returns the detached snapshot, or `undefined` when the value is not + * losslessly JSON-serializable. + */ +export function snapshotJsonValue(value) { + return walkJsonValue(value, true); +} +/** + * Test the same lossless JSON boundary as {@link snapshotJsonValue} without + * detaching it. Only own enumerable string properties participate; `toJSON` + * is ignored and getters run, so persistence boundaries use the snapshotter. + * @param value - the candidate event data to test. + * @returns whether `value` survives JSON round-trip losslessly. + */ +export function isJsonValue(value) { + return walkJsonValue(value, false) === true; +} +//# sourceMappingURL=json.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.d.ts new file mode 100644 index 0000000..a060061 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.d.ts @@ -0,0 +1,19 @@ +/** + * GENERATED by `scripts/gen-persistence-catalog.ts` — do not edit by hand; run + * `pnpm run gen-persistence-catalog` to regenerate (verified fresh by + * `pnpm run verify-persistence-catalog`, part of `doc-sync`). + * @module @deepseek-ai/dsh-session/known-event-types + */ +/** + * Every `SessionEventMap` member declared in this repository — the event + * vocabulary this build understands. The persistence read path refuses to + * interpret a log containing a type outside this set unless the event + * carries the envelope's `ignorable` marker (see `SessionEvent.ignorable` + * in `./types.ts`): such a log was likely written by a newer harness, and + * silently skipping a required event would reconstruct a wrong session. + * Downstream (out-of-repo) plugin events are outside this list by + * construction; a registration surface for them is deferred until such a + * consumer exists. + */ +export declare const KNOWN_SESSION_EVENT_TYPES: ReadonlySet; +//# sourceMappingURL=known-event-types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.js new file mode 100644 index 0000000..7541caa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.js @@ -0,0 +1,64 @@ +/** + * GENERATED by `scripts/gen-persistence-catalog.ts` — do not edit by hand; run + * `pnpm run gen-persistence-catalog` to regenerate (verified fresh by + * `pnpm run verify-persistence-catalog`, part of `doc-sync`). + * @module @deepseek-ai/dsh-session/known-event-types + */ +/** + * Every `SessionEventMap` member declared in this repository — the event + * vocabulary this build understands. The persistence read path refuses to + * interpret a log containing a type outside this set unless the event + * carries the envelope's `ignorable` marker (see `SessionEvent.ignorable` + * in `./types.ts`): such a log was likely written by a newer harness, and + * silently skipping a required event would reconstruct a wrong session. + * Downstream (out-of-repo) plugin events are outside this list by + * construction; a registration surface for them is deferred until such a + * consumer exists. + */ +export const KNOWN_SESSION_EVENT_TYPES = new Set([ + 'agent-preset/selected', + 'agent/inbox/spliced', + 'approval/asked', + 'approval/decided', + 'approval/policy', + 'assistant/chunk', + 'assistant/message', + 'command/done', + 'command/run', + 'compaction/end', + 'compaction/prune', + 'compaction/start', + 'compaction/summary', + 'feedback/record', + 'goal/change', + 'hook/invoked', + 'hook/result', + 'llm/retry', + 'llm/retry-started', + 'permission/preset', + 'plan/mode', + 'request/context', + 'request/header', + 'sandbox/mode', + 'schedule/change', + 'session/end-seed', + 'session/title', + 'session/title-llm-request', + 'step/end', + 'step/start', + 'subagent/descriptor', + 'todo/write', + 'tool-workflow/agent-end', + 'tool-workflow/agent-start', + 'tool-workflow/run-end', + 'tool-workflow/run-start', + 'tool/call', + 'tool/code-dispatch', + 'tool/code-dispatch-start', + 'tool/result', + 'turn/end', + 'turn/start', + 'user/message', + 'web/deepseek-search-llm-request', +]); +//# sourceMappingURL=known-event-types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.d.ts new file mode 100644 index 0000000..52c0f55 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.d.ts @@ -0,0 +1,33 @@ +/** + * Ownership of one unpublished Session before registry publication. + * @module @deepseek-ai/dsh-session/preparation + */ +import type { Session } from './index.ts'; +/** Options for a preparation whose provider retains unpublished state. */ +export interface SessionPreparationOptions { + /** Release provider-owned state when the Session was not published. */ + readonly release?: () => void; +} +/** + * One exact unpublished Session and the provider state that keeps it usable. + * Disposal is synchronous and idempotent. Providers decide whether release + * returns the Session to a cache or discards it; publication may consume that + * state before disposal, making the callback a no-op. + */ +export declare class SessionPreparation implements Disposable { + private readonly options; + private released; + /** The exact Session to use for setup and publication. */ + readonly session: Session; + private constructor(); + /** + * Wrap an unpublished Session in one preparation lifetime. + * @param session - exact unpublished Session. + * @param options - optional provider release behavior. + * @returns a preparation disposed after publication or rollback. + */ + static create(session: Session, options?: SessionPreparationOptions): SessionPreparation; + /** Release provider state once when this preparation leaves its caller. */ + [Symbol.dispose](): void; +} +//# sourceMappingURL=preparation.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.js new file mode 100644 index 0000000..baecac6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.js @@ -0,0 +1,37 @@ +/** + * Ownership of one unpublished Session before registry publication. + * @module @deepseek-ai/dsh-session/preparation + */ +/** + * One exact unpublished Session and the provider state that keeps it usable. + * Disposal is synchronous and idempotent. Providers decide whether release + * returns the Session to a cache or discards it; publication may consume that + * state before disposal, making the callback a no-op. + */ +export class SessionPreparation { + options; + released = false; + /** The exact Session to use for setup and publication. */ + session; + constructor(session, options) { + this.options = options; + this.session = session; + } + /** + * Wrap an unpublished Session in one preparation lifetime. + * @param session - exact unpublished Session. + * @param options - optional provider release behavior. + * @returns a preparation disposed after publication or rollback. + */ + static create(session, options) { + return new SessionPreparation(session, options ?? {}); + } + /** Release provider state once when this preparation leaves its caller. */ + [Symbol.dispose]() { + if (this.released) + return; + this.released = true; + this.options.release?.(); + } +} +//# sourceMappingURL=preparation.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/repair.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/repair.d.ts new file mode 100644 index 0000000..0cf7879 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/repair.d.ts @@ -0,0 +1,22 @@ +/** + * Crash-recovery repair for an interrupted session log. It preserves a fully + * written final turn and supplies the missing tool, step, and turn boundaries + * needed to resume with a provider-valid transcript. + * @module @deepseek-ai/dsh-session/repair + */ +import type { SessionEvent } from './types.ts'; +/** Recovery code for an assistant tool request that never reached a recorded call start. */ +export declare const TOOL_NOT_STARTED = "TOOL_NOT_STARTED"; +/** Recovery code for a recorded tool call whose completed outcome was not durably recorded. */ +export declare const TOOL_OUTCOME_UNKNOWN = "TOOL_OUTCOME_UNKNOWN"; +/** + * Return deterministic synthetic events that close an open tail turn. Unmatched + * calls receive error results first, followed by an open `step/end` and an + * interrupted `turn/end`; sequences continue the log and timestamps reuse the + * last real event. A balanced or empty log returns no events. + * + * @param events - the loaded durable log to scan (a valid committed prefix, possibly with a crash tail). + * @returns the synthetic closer events to append after `events`, in order; empty when the log is already balanced. + */ +export declare function interruptedTurnClosers(events: readonly SessionEvent[]): SessionEvent[]; +//# sourceMappingURL=repair.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/repair.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/repair.js new file mode 100644 index 0000000..39544bb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/repair.js @@ -0,0 +1,126 @@ +/** + * Crash-recovery repair for an interrupted session log. It preserves a fully + * written final turn and supplies the missing tool, step, and turn boundaries + * needed to resume with a provider-valid transcript. + * @module @deepseek-ai/dsh-session/repair + */ +import { MessageId, freezeMessage } from '@deepseek-ai/dsh-llm'; +/** Recovery code for an assistant tool request that never reached a recorded call start. */ +export const TOOL_NOT_STARTED = 'TOOL_NOT_STARTED'; +/** Recovery code for a recorded tool call whose completed outcome was not durably recorded. */ +export const TOOL_OUTCOME_UNKNOWN = 'TOOL_OUTCOME_UNKNOWN'; +/** + * Return deterministic synthetic events that close an open tail turn. Unmatched + * calls receive error results first, followed by an open `step/end` and an + * interrupted `turn/end`; sequences continue the log and timestamps reuse the + * last real event. A balanced or empty log returns no events. + * + * @param events - the loaded durable log to scan (a valid committed prefix, possibly with a crash tail). + * @returns the synthetic closer events to append after `events`, in order; empty when the log is already balanced. + */ +export function interruptedTurnClosers(events) { + let openTurn = null; + let openStep = null; + // Reset at each turn boundary so earlier calls cannot leak into tail repair. + // Assistant blocks register calls; later `tool/call` events add their seqs to `sourceEventSeqs`. + const pendingCalls = new Map(); + for (const event of events) { + switch (event.type) { + case 'turn/start': + openTurn = event.data.turn; + openStep = null; + pendingCalls.clear(); + break; + case 'turn/end': + openTurn = null; + openStep = null; + pendingCalls.clear(); + break; + case 'step/start': + openStep = event.data.step; + break; + case 'step/end': + pendingCalls.clear(); + openStep = null; + break; + case 'assistant/message': + // The assistant message carries the tool-call blocks; each is pending + // until a tool/result event with the same callId is logged. + for (const block of event.data.message.content) { + if (block.type === 'tool-call') + pendingCalls.set(block.id, { step: event.data.step }); + } + break; + case 'tool/call': + // Cite the `tool/call` seq from the synthetic result. + { + const entry = pendingCalls.get(event.data.callId); + if (entry) { + entry.callSeq = event.seq; + } + } + break; + case 'tool/result': + pendingCalls.delete(event.data.message.source.callId); + break; + // Other event types do not move the turn/step boundary cursor. + default: + break; + } + } + // Balanced log (no crash mid-turn): nothing to close. An open turn implies + // `events` is non-empty (its turn/start was logged), so `last` exists. + const last = events.at(-1); + if (openTurn === null || last === undefined) + return []; + // The last real event supplies the seq base and the timestamp for the + // synthetic closers (reusing the last timestamp keeps them deterministic and + // never invents a "future" time). + let seq = last.seq + 1; + const time = last.time; + const closers = []; + // Close calls before their step: providers reject dangling assistant calls, + // and Map insertion order preserves their transcript order. + for (const [callId, { step, callSeq }] of pendingCalls) { + const started = callSeq !== undefined; + const message = freezeMessage({ + id: MessageId(`interrupted-tool-result-${callId}-${seq}`), + role: 'user', + source: { kind: 'tool', callId }, + content: [{ + type: 'tool-result', + toolCallId: callId, + isError: true, + content: [{ + type: 'text', + text: started + ? 'The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly.' + : 'The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed.', + }], + }], + }); + closers.push({ + type: 'tool/result', + seq: seq++, + time, + data: { + turn: openTurn, + step, + message, + error: started + ? { name: 'ToolOutcomeUnknownError', code: TOOL_OUTCOME_UNKNOWN } + : { name: 'ToolNotStartedError', code: TOOL_NOT_STARTED }, + }, + surfaceOp: 'append', + ...started ? { sourceEventSeqs: [callSeq] } : {}, + }); + } + // Close an open step next — a turn/end while a step is open is an invariant + // violation, so the step's boundary must be synthesized before the turn's. + if (openStep !== null) { + closers.push({ type: 'step/end', seq: seq++, time, data: { turn: openTurn, step: openStep } }); + } + closers.push({ type: 'turn/end', seq: seq++, time, data: { turn: openTurn, reason: { kind: 'interrupted' } } }); + return closers; +} +//# sourceMappingURL=repair.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.d.ts new file mode 100644 index 0000000..2513521 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.d.ts @@ -0,0 +1,35 @@ +/** + * Request-header reconstruction utilities over full `request/header` session + * events. Anyone holding a session log reconstructs the {@link EpochHeader} + * any request was built under by taking the latest canonical snapshot; the + * loop uses the same equality helper to avoid logging unchanged headers. + * + * @module dsh-session/request-header + */ +import type { EpochHeader, SessionEvent } from './types.ts'; +/** + * Normalize a header to canonical form: an empty system prompt and empty tool + * list become absent fields, matching how requests are built. Logging, folding, + * and comparison use this one representation. + * @param header - the header to normalize (not mutated). + * @returns the canonical header. + */ +export declare function canonicalHeader(header: EpochHeader): EpochHeader; +/** + * Field-wise equality over canonical headers. Tool schemas compare in order. + * @param a - one canonical header. + * @param b - the other. + * @returns whether config, system, and tools all match. + */ +export declare function headerEquals(a: EpochHeader, b: EpochHeader): boolean; +/** + * Fold the header events of a log (or any prefix) into the + * {@link EpochHeader} in force after the last snapshot. Non-header events are + * skipped. This is the pure offline reconstruction path; the live session + * tracks the same fold incrementally. + * @param events - session events in log order. + * @param from - a previously folded state to continue from. + * @returns the latest canonical header, or undefined when none exists yet. + */ +export declare function foldRequestHeader(events: readonly SessionEvent[], from?: EpochHeader): EpochHeader | undefined; +//# sourceMappingURL=request-header.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.js new file mode 100644 index 0000000..0d9d564 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.js @@ -0,0 +1,65 @@ +/** + * Request-header reconstruction utilities over full `request/header` session + * events. Anyone holding a session log reconstructs the {@link EpochHeader} + * any request was built under by taking the latest canonical snapshot; the + * loop uses the same equality helper to avoid logging unchanged headers. + * + * @module dsh-session/request-header + */ +import { callConfigEquals } from '@deepseek-ai/dsh-llm'; +/** + * Normalize a header to canonical form: an empty system prompt and empty tool + * list become absent fields, matching how requests are built. Logging, folding, + * and comparison use this one representation. + * @param header - the header to normalize (not mutated). + * @returns the canonical header. + */ +export function canonicalHeader(header) { + const adapterDefaults = header.adapterDefaults; + return { + config: header.config, + ...adapterDefaults?.reasoningEffort === true || adapterDefaults?.maxTokens === true + ? { adapterDefaults } + : {}, + ...header.system !== undefined && header.system.length > 0 ? { system: header.system } : {}, + ...header.tools !== undefined && header.tools.length > 0 ? { tools: header.tools } : {}, + }; +} +/** Canonical JSON equality for tool schemas assembled through the same path. */ +function sameSchema(a, b) { + return JSON.stringify(a) === JSON.stringify(b); +} +/** + * Field-wise equality over canonical headers. Tool schemas compare in order. + * @param a - one canonical header. + * @param b - the other. + * @returns whether config, system, and tools all match. + */ +export function headerEquals(a, b) { + if (!callConfigEquals(a.config, b.config) + || a.adapterDefaults?.reasoningEffort !== b.adapterDefaults?.reasoningEffort + || a.adapterDefaults?.maxTokens !== b.adapterDefaults?.maxTokens + || a.system !== b.system) + return false; + const at = a.tools ?? []; + const bt = b.tools ?? []; + return at.length === bt.length && at.every((tool, i) => sameSchema(tool, bt[i])); +} +/** + * Fold the header events of a log (or any prefix) into the + * {@link EpochHeader} in force after the last snapshot. Non-header events are + * skipped. This is the pure offline reconstruction path; the live session + * tracks the same fold incrementally. + * @param events - session events in log order. + * @param from - a previously folded state to continue from. + * @returns the latest canonical header, or undefined when none exists yet. + */ +export function foldRequestHeader(events, from) { + let state = from; + for (const event of events) { + if (event.type === 'request/header') + state = canonicalHeader(event.data.header); + } + return state; +} +//# sourceMappingURL=request-header.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/surface.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/surface.d.ts new file mode 100644 index 0000000..d0db42f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/surface.d.ts @@ -0,0 +1,123 @@ +/** + * Surface layer on top of the session event log: an ordered view of events + * that produce LLM messages. The append-only log remains the source of truth. + * + * Browser-safe: web clients consume this subpath export, so it must stay free + * of `node:` imports (they break the vite bundle). + * + * @module @deepseek-ai/dsh-session/surface + */ +import type { Message } from '@deepseek-ai/dsh-llm'; +import type { SessionEvent, SurfaceEvent, SurfaceOp } from './types.ts'; +/** + * Whether an event type can join the model-visible surface. + * @param type - event type to test. + * @returns true for one of the three message-producing event types. + */ +export declare function isSurfaceEligibleType(type: string): boolean; +/** + * Narrow an event to a surface-eligible event carrying its required marker. + * @param event - event to test. + * @returns true when both the type and marker identify a surface event. + */ +export declare function isSurfaceEvent(event: SessionEvent): event is SurfaceEvent; +/** + * Narrow an event to an append-origin surface event: one that entered the + * surface at its own log position and was never itself a replacement copy. + * + * The model-visible surface deliberately shadows replaced ranges, so it is the + * wrong source for a human transcript — a landed replacement would erase + * conversation the user already saw. Append-origin events are that transcript's + * durable source material; replacement copies stay model-only. + * @param event - event to test. + * @returns true when the event appended to the surface tail. + */ +export declare function isAppendSurfaceEvent(event: SessionEvent): event is SurfaceEvent & { + surfaceOp: 'append'; +}; +/** + * Narrow an event to a surface replacement: a node that shadowed an existing + * surface range instead of appending to the tail. The counterpart of + * {@link isAppendSurfaceEvent} over the two {@link SurfaceOp} variants. + * @param event - event to test. + * @returns true when the event replaced a surface range. + */ +export declare function isReplacementSurfaceEvent(event: SessionEvent): event is SurfaceEvent & { + surfaceOp: Extract; +}; +/** + * Project a single event into the LLM message it derives to, or null when it + * produces none — a non-surface event (chunk, boundary, log-only record) or an + * empty-content assistant/message (which exists only to host usage). This is + * THE per-node projection rule: `Session.deriveMessages` folds it over the + * live surface, external reconstructors and pure projections fold the same + * function over a log prefix's surface to rebuild the exact messages any + * request was built from. The returned message is the already frozen message + * nested in the event wrapper and shared by delivery, durable history, and + * model requests. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ +export declare function deriveEventMessage(event: SessionEvent): Message | null; +/** One replacement operation observed while folding a session surface. */ +export interface SurfaceFoldReplacement { + /** Seq of the event that replaced the prior surface range. */ + seq: number; + /** Declared inclusive start seq of the replaced surface range. */ + start: number; + /** Declared inclusive end seq of the replaced surface range. */ + end: number; + /** Actual surface entries removed by the operation, in surface order. */ + shadowedSeqs: number[]; +} +/** Complete result of replaying the surface operations in a session log. */ +export interface SurfaceFoldResult { + /** Current surface event sequences in model-visible order. */ + nodes: number[]; + /** Replacement operations in event order. */ + replacements: SurfaceFoldReplacement[]; +} +/** Readonly live projection of the message-producing session events. */ +export interface SessionSurface { + /** Current surface event sequences in model-visible order. */ + readonly nodes: readonly number[]; + /** Monotonic count of committed positional replacements. */ + readonly replaceGeneration: number; +} +/** + * Replay a complete session log through the canonical surface fold. + * @param events - session events in contiguous seq order. + * @returns detached current sequences and replacement history. + * @throws when an event violates surface metadata, source-event references, range, or tool-result rewrite rules. + */ +export declare function foldSurface(events: readonly SessionEvent[]): SurfaceFoldResult; +/** Incremental ordered surface view and append-boundary validator. */ +export declare class SurfaceManager implements SessionSurface { + private log; + private readonly baseSeq; + /** Shared transition state; replacement history is not retained. */ + private _state; + /** Last processed absolute seq. */ + private _lastProcessedSeq; + /** Candidate already validated by `validateNext`, pending exact log admission. */ + private _pendingPlan; + /** + * @param log - Contiguous complete log or loaded event window. + * @param baseSeq - Absolute sequence of the window's first event. + */ + constructor(log: readonly SessionEvent[], baseSeq?: number); + /** + * Validate the next candidate without mutating the committed surface. + * @param event - candidate event that has not entered the log yet. + */ + validateNext(event: SessionEvent): void; + /** Monotonic count of folded positional replacements. */ + get replaceGeneration(): number; + /** Surface event sequences in model-visible order. */ + get nodes(): readonly number[]; + /** Fold events appended since the previous access. */ + private _processDelta; +} +//# sourceMappingURL=surface.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/surface.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/surface.js new file mode 100644 index 0000000..c4b05f4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/surface.js @@ -0,0 +1,377 @@ +/** + * Surface layer on top of the session event log: an ordered view of events + * that produce LLM messages. The append-only log remains the source of truth. + * + * Browser-safe: web clients consume this subpath export, so it must stay free + * of `node:` imports (they break the vite bundle). + * + * @module @deepseek-ai/dsh-session/surface + */ +/** Runtime counterpart of the message-producing event union. */ +const SURFACE_EVENT_TYPES = new Set([ + 'user/message', + 'assistant/message', + 'tool/result', +]); +/** + * Whether an event type can join the model-visible surface. + * @param type - event type to test. + * @returns true for one of the three message-producing event types. + */ +export function isSurfaceEligibleType(type) { + return SURFACE_EVENT_TYPES.has(type); +} +/** + * Narrow an event to a surface-eligible event carrying its required marker. + * @param event - event to test. + * @returns true when both the type and marker identify a surface event. + */ +export function isSurfaceEvent(event) { + if (!SURFACE_EVENT_TYPES.has(event.type)) + return false; + return event.surfaceOp !== undefined; +} +/** + * Narrow an event to an append-origin surface event: one that entered the + * surface at its own log position and was never itself a replacement copy. + * + * The model-visible surface deliberately shadows replaced ranges, so it is the + * wrong source for a human transcript — a landed replacement would erase + * conversation the user already saw. Append-origin events are that transcript's + * durable source material; replacement copies stay model-only. + * @param event - event to test. + * @returns true when the event appended to the surface tail. + */ +export function isAppendSurfaceEvent(event) { + return isSurfaceEvent(event) && event.surfaceOp === 'append'; +} +/** + * Narrow an event to a surface replacement: a node that shadowed an existing + * surface range instead of appending to the tail. The counterpart of + * {@link isAppendSurfaceEvent} over the two {@link SurfaceOp} variants. + * @param event - event to test. + * @returns true when the event replaced a surface range. + */ +export function isReplacementSurfaceEvent(event) { + return isSurfaceEvent(event) && event.surfaceOp !== 'append'; +} +/** + * Project a single event into the LLM message it derives to, or null when it + * produces none — a non-surface event (chunk, boundary, log-only record) or an + * empty-content assistant/message (which exists only to host usage). This is + * THE per-node projection rule: `Session.deriveMessages` folds it over the + * live surface, external reconstructors and pure projections fold the same + * function over a log prefix's surface to rebuild the exact messages any + * request was built from. The returned message is the already frozen message + * nested in the event wrapper and shared by delivery, durable history, and + * model requests. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ +export function deriveEventMessage(event) { + // Intentionally non-exhaustive: only message-producing events derive + // history; turn/step boundaries, chunks, usage, and errors are trace/replay + // data. + switch (event.type) { + // Ordinary prompts and injected context project in user role: the event's + // model-facing content stays verbatim. Do NOT re-add per-type framing + // (e.g. ``) here: framing is caller-owned — a producer bakes it + // into `content`, as agent-instructions does with `` — or, + // if reintroduced, must be driven by the event `meta` map and a dedicated + // renderer, keeping this projection a verbatim pass-through. See the + // deferred design note in + // ../../../../.agents/notes/implemented/simplification/2026-07-20-unwrap-injected-content-envelopes.md + case 'user/message': { + return event.data; + } + case 'assistant/message': { + // Skip an empty-content assistant/message: it exists only to host a + // max-tokens step's usage and must not inject a content-less assistant + // turn into the provider transcript. + if (event.data.message.content.length === 0) + return null; + return event.data.message; + } + case 'tool/result': { + return event.data.message; + } + default: + // A non-surface event (boundary, chunk, log-only record) projects to + // no message. Merge-extensible union: no assertNever here. + return null; + } +} +/** Create an empty surface fold state. */ +function createFoldState() { + return { nodes: [], replaceGeneration: 0 }; +} +/** Whether a runtime value is a non-negative safe event sequence. */ +function isEventSeq(value) { + return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0; +} +/** Whether a runtime value is the exact positional-replacement shape. */ +function isReplaceOp(value) { + const op = value; + return Object.keys(op).length === 3 + && Object.hasOwn(op, 'op') + && Object.hasOwn(op, 'start') + && Object.hasOwn(op, 'end') + && op['op'] === 'replace' + && isEventSeq(op['start']) + && isEventSeq(op['end']); +} +/** Validate event-local surface eligibility and return its operation. */ +function surfaceOpOf(event) { + const raw = event; + if (!isSurfaceEligibleType(event.type)) { + if (raw.surfaceOp !== undefined) { + throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry surfaceOp`); + } + if (raw.sourceEventSeqs !== undefined) { + throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry sourceEventSeqs`); + } + return; + } + const op = raw.surfaceOp; + if (op === undefined) { + throw new Error(`session event "${event.type}" is surface-eligible and requires a surfaceOp marker`); + } + if (op === 'append') + return op; + if (op === null || typeof op !== 'object' || Array.isArray(op)) { + throw new Error(`session event "${event.type}" carries an invalid surfaceOp`); + } + if (!isReplaceOp(op)) { + throw new Error(`session event "${event.type}" carries an invalid replace surfaceOp`); + } + return op; +} +/** Validate cited source-event seqs against prior log entries and the replacement range. */ +function assertProvenance(event, shadowedSeqs) { + const raw = event.sourceEventSeqs; + const sources = new Set(); + if (raw !== undefined) { + if (!Array.isArray(raw)) { + throw new Error(`sourceEventSeqs on event at seq ${event.seq} must be an array when present`); + } + if (raw.length === 0 && event.type !== 'assistant/message') { + throw new Error('sourceEventSeqs must not be empty except on assistant/message'); + } + let nonEarlierSource; + for (const source of raw) { + if (!isEventSeq(source)) { + throw new Error(`session event "${event.type}" sourceEventSeqs must densely contain non-negative safe integers`); + } + sources.add(source); + if (nonEarlierSource === undefined && source >= event.seq) + nonEarlierSource = source; + } + if (sources.size !== raw.length) { + throw new Error('sourceEventSeqs must not contain duplicates'); + } + if (nonEarlierSource !== undefined) { + throw new Error(`sourceEventSeqs must reference earlier events: ${nonEarlierSource} >= current seq ${event.seq}`); + } + } + const missing = shadowedSeqs.filter(seq => !sources.has(seq)); + if (missing.length > 0) { + throw new Error(`surface replace: sourceEventSeqs must include every shadowed surface node; missing ${missing.join(', ')}`); + } +} +/** Locate one replacement range without mutating the current fold state. */ +function replacementRange(state, op) { + const startIdx = state.nodes.indexOf(op.start); + if (startIdx === -1) { + throw new Error(`surface replace: start seq ${op.start} not found in surface`); + } + const endIdx = state.nodes.indexOf(op.end); + if (endIdx === -1) { + throw new Error(`surface replace: end seq ${op.end} not found in surface`); + } + if (startIdx > endIdx) { + throw new Error(`surface replace: start seq ${op.start} (index ${startIdx}) is after end seq ${op.end} (index ${endIdx})`); + } + return { + startIdx, + endIdx, + shadowedSeqs: state.nodes.slice(startIdx, endIdx + 1), + }; +} +/** + * Deep structural equality over the session-event JSON value domain + * (null/boolean/number/string, arrays, plain objects). Replaces + * `node:util`'s isDeepStrictEqual to keep this module browser-safe. + */ +function isDeepEqualJson(a, b) { + if (a === b) + return true; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) + return false; + return a.every((item, i) => isDeepEqualJson(item, b[i])); + } + if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) + return false; + const aKeys = Object.keys(a); + const bRecord = b; + if (aKeys.length !== Object.keys(b).length) + return false; + return aKeys.every(key => Object.hasOwn(b, key) && isDeepEqualJson(a[key], bRecord[key])); +} +/** Restrict a tool-result replacement to one current result's content. */ +function assertToolResultRewrite(event, shadowedSeqs, events, baseSeq) { + if (event.type !== 'tool/result') + return; + if (shadowedSeqs.length !== 1) { + throw new Error('tool/result surface replacement must rewrite exactly one current node'); + } + for (const originalSeq of shadowedSeqs) { + const original = events[originalSeq - baseSeq]; + if (original?.type !== 'tool/result') { + throw new Error('tool/result surface replacement must target a current tool/result'); + } + const originalRest = { ...original.data }; + const replacementRest = { ...event.data }; + const originalResult = original.data.message.content[0]; + const replacementResult = event.data.message.content[0]; + originalRest['message'] = { + ...original.data.message, + content: [{ ...originalResult, content: null }], + }; + replacementRest['message'] = { + ...event.data.message, + content: [{ ...replacementResult, content: null }], + }; + if (!isDeepEqualJson(originalRest, replacementRest)) { + throw new Error('tool/result surface replacement may change only content'); + } + } +} +/** Validate one event at its replay boundary and prepare its atomic fold transition. */ +function planSurfaceEvent(state, event, expectedSeq, events, baseSeq) { + if (event.seq !== expectedSeq) { + throw new Error(`session event seq ${event.seq} is not contiguous; expected ${expectedSeq}`); + } + const surfaceOp = surfaceOpOf(event); + if (surfaceOp === undefined) + return; + if (surfaceOp === 'append') { + assertProvenance(event, []); + return { kind: 'append', seq: event.seq }; + } + const range = replacementRange(state, surfaceOp); + assertProvenance(event, range.shadowedSeqs); + assertToolResultRewrite(event, range.shadowedSeqs, events, baseSeq); + return { + kind: 'replace', + seq: event.seq, + start: surfaceOp.start, + end: surfaceOp.end, + ...range, + }; +} +/** Apply one event and return replacement metadata only when one occurred. */ +function applySurfaceEvent(state, event, expectedSeq, events, baseSeq) { + const plan = planSurfaceEvent(state, event, expectedSeq, events, baseSeq); + return applySurfacePlan(state, plan); +} +/** Commit one previously validated surface transition. */ +function applySurfacePlan(state, plan) { + if (plan?.kind === 'append') { + state.nodes.push(plan.seq); + } + else if (plan?.kind === 'replace') { + state.nodes.splice(plan.startIdx, plan.endIdx - plan.startIdx + 1, plan.seq); + state.replaceGeneration += 1; + } + if (plan?.kind !== 'replace') + return; + return { + seq: plan.seq, + start: plan.start, + end: plan.end, + shadowedSeqs: plan.shadowedSeqs, + }; +} +/** + * Replay a complete session log through the canonical surface fold. + * @param events - session events in contiguous seq order. + * @returns detached current sequences and replacement history. + * @throws when an event violates surface metadata, source-event references, range, or tool-result rewrite rules. + */ +export function foldSurface(events) { + const state = createFoldState(); + const replacements = []; + for (const [index, event] of events.entries()) { + const replacement = applySurfaceEvent(state, event, index, events, 0); + if (replacement !== undefined) + replacements.push(replacement); + } + return { nodes: [...state.nodes], replacements }; +} +/** Incremental ordered surface view and append-boundary validator. */ +export class SurfaceManager { + log; + baseSeq; + /** Shared transition state; replacement history is not retained. */ + _state = createFoldState(); + /** Last processed absolute seq. */ + _lastProcessedSeq; + /** Candidate already validated by `validateNext`, pending exact log admission. */ + _pendingPlan; + /** + * @param log - Contiguous complete log or loaded event window. + * @param baseSeq - Absolute sequence of the window's first event. + */ + constructor(log, baseSeq = 0) { + this.log = log; + this.baseSeq = baseSeq; + this._lastProcessedSeq = baseSeq - 1; + } + /** + * Validate the next candidate without mutating the committed surface. + * @param event - candidate event that has not entered the log yet. + */ + validateNext(event) { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) + this._processDelta(); + const expectedSeq = this.baseSeq + this.log.length; + this._pendingPlan = { + event, + expectedSeq, + plan: planSurfaceEvent(this._state, event, expectedSeq, this.log, this.baseSeq), + }; + } + /** Monotonic count of folded positional replacements. */ + get replaceGeneration() { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) + this._processDelta(); + return this._state.replaceGeneration; + } + /** Surface event sequences in model-visible order. */ + get nodes() { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) + this._processDelta(); + return this._state.nodes; + } + /** Fold events appended since the previous access. */ + _processDelta() { + const tailSeq = this.baseSeq + this.log.length - 1; + for (let seq = this._lastProcessedSeq + 1; seq <= tailSeq; seq++) { + const index = seq - this.baseSeq; + // oxlint-disable-next-line typescript/no-non-null-assertion -- bounded by the loop condition + const event = this.log[index]; + const pending = this._pendingPlan; + if (pending?.event === event && pending.expectedSeq === seq) { + applySurfacePlan(this._state, pending.plan); + } + else { + applySurfaceEvent(this._state, event, seq, this.log, this.baseSeq); + } + if (pending !== undefined && pending.expectedSeq <= seq) + this._pendingPlan = undefined; + this._lastProcessedSeq = seq; + } + } +} +//# sourceMappingURL=surface.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts new file mode 100644 index 0000000..b1e6a94 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts @@ -0,0 +1,453 @@ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { AssistantMessage, CallId, LlmCallConfig, LlmCallConfigAdapterDefaults, LlmFailure, StreamChunk, TokenUsage, ToolResultMessage, ToolSchema, UserMessage } from '@deepseek-ai/dsh-llm'; +import type { JsonValue } from './json.ts'; +export type { JsonValue } from './json.ts'; +/** Identifies one session in the store (and its persistence artifacts). */ +export type SessionId = Branded<'SessionId'>; +/** + * Brand a string as a {@link SessionId}. + * @param id - the raw session id string. + * @returns the same string, branded (a compile-time cast — no runtime cost). + */ +export declare function SessionId(id: string): SessionId; +/** + * The on-disk session format version, stamped into every newly-written {@link SessionHeader} + * and enforced by every persistence backend on load. The single source of truth for the + * version — write sites and the load-time check all read it. + * While the harness is unreleased it is pinned at `0`: no compatibility is + * implied, incompatible logs are rejected, and no migration is provided. + * + * The version is a single monotonic integer with no major/minor split. Whether + * a bump is needed is decided by what the WRITER emits, never by what a newer + * reader can accept: bump exactly when an older runtime could no longer handle + * a new log with full semantic correctness ("parses without error" is not + * correctness — silently skipping content that shapes reconstruction is a + * wrong read). Only structural changes reach that bar: the header shape, the + * {@link SessionEvent} envelope, core event semantics, or the surface + * mechanism (the {@link SurfaceEventType} set and {@link SurfaceOp} variants). + * Adding an ordinary event type does not bump — the per-event + * {@link SessionEvent.ignorable} guard covers vocabulary growth instead. When + * in doubt, bump: a near-identity upgrade step is almost free, a missed bump + * makes older runtimes read new logs wrong silently. The full mechanism + * (upgrade-step chain, in-memory view conversion, migrate-on-continue) is + * recorded in the session-log-version-mechanism Agent Note + * (`.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md`). + */ +export declare const SESSION_FORMAT_VERSION = 0; +/** + * Immutable validated storage metadata, kept outside the conversation event log. + */ +export interface SessionHeader { + /** + * On-disk format version, stamped from {@link SESSION_FORMAT_VERSION} when the + * session is created. A persistence backend rejects any other version on load + * (no migration — see the constant). + */ + readonly version: number; + /** The session's id (mirrors the {@link Session}'s id). */ + readonly id: SessionId; + /** Non-negative safe-integer Unix epoch milliseconds when the session was created. */ + readonly createdAt: number; + /** Absolute working directory the session was created in (if any). */ + readonly cwd?: string; + /** The session this one was forked from (seed lineage), if any. */ + readonly parentSession?: SessionId; + /** + * How many leading events were inherited through a seed. Persisting this + * boundary lets resume and replay distinguish parent history from child work. + */ + readonly seedLength?: number; + /** + * Coarse product classification for a session created as a subagent child. + * This is presentation metadata, not proof that the child is continuable. + */ + readonly origin?: 'subagent'; + /** + * Delegation depth: absent (zero) for a top-level session, parent depth + 1 + * for a subagent child. Persisted so a recursion budget survives restart and + * resume — a runtime-only depth would reset a resumed child to top-level. + */ + readonly delegationDepth?: number; + /** + * Id of the agent preset this session's agent was composed from, when the + * deployment composes per session. Durable because the preset decides the + * session's tools and prompt: a resume that restored a different composition + * would replay history the model can no longer act on. + */ + readonly agentPreset?: string; +} +/** + * Options for creating a {@link Session} via the store. `seed` replays/forks + * an existing event log; `meta` carries the caller-supplied storage fields the + * store folds into a {@link SessionHeader}. + */ +export interface CreateSessionOptions { + /** Initial replay or fork history supplied at construction. */ + readonly seed?: readonly SessionEvent[]; + /** + * Storage metadata read once before publication. `seedLength` is explicit + * because a resumed seed contains the full stored log, not only its inherited prefix. + */ + readonly meta?: { + readonly cwd?: string; + readonly parentSession?: SessionId; + readonly createdAt?: number; + readonly seedLength?: number; + readonly origin?: 'subagent'; + readonly delegationDepth?: number; + readonly agentPreset?: string; + }; +} +/** + * Fresh storage values transferred to {@link SessionStore.prepare} without a + * second serialization copy. Callers retain no mutable aliases. + */ +export interface RestoredSessionOptions { + /** Fresh detached storage events to validate and freeze in place. */ + readonly seed: SessionEvent[]; + /** Fresh detached storage metadata to validate and freeze in place. */ + readonly meta: SessionHeader; + /** Select the persistence ownership-transfer path. */ + readonly seedSource: 'persistence'; +} +/** Inputs accepted while constructing an unpublished Session. */ +export type PrepareSessionOptions = (CreateSessionOptions & { + readonly seedSource?: undefined; +}) | RestoredSessionOptions; +/** Why an active agent driver was cancelled. */ +export type AgentCancelCause = { + readonly kind: 'user'; +} | { + readonly kind: 'parent'; +} | { + readonly kind: 'hook'; + readonly reason: string; +} | { + readonly kind: 'disposed'; +}; +/** Durable cancellation cause, including imports whose original coarse record carried no cause. */ +export type TurnEndCancelCause = AgentCancelCause | { + readonly kind: 'legacy'; +}; +/** + * Why a turn ended. Merge-extensible sum type. + */ +export interface TurnEndReasonMap { + completed: { + kind: 'completed'; + }; + /** A cancellation request interrupted the live turn. */ + aborted: { + kind: 'aborted'; + reason: TurnEndCancelCause; + }; + blocked: { + kind: 'blocked'; + }; + /** + * The turn failed. `error` is always a structured failure: the `LlmError` + * facts verbatim, or `{ message: errorChain(error), code: 'UNKNOWN' }` + * flattened from any other error. + */ + error: { + kind: 'error'; + error: LlmFailure; + }; + /** At least one step reached its output-token ceiling, even if a plugin continued the turn. */ + 'max-tokens': { + kind: 'max-tokens'; + }; + /** + * A persistence backend closed a crash-orphaned turn on reload. The loop never + * emits this marker, and the events recorded before the crash remain intact. + */ + interrupted: { + kind: 'interrupted'; + }; +} +/** The union over {@link TurnEndReasonMap} — why a turn ended; plugins extend it by merging variants into the map. */ +export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap]; +/** + * One entry in an agent's todo list — the unit of the `todo/write` + * {@link SessionEventMap} event's whole-list snapshot. + * + * Deliberately minimal: a human-readable `content` line and a three-state + * `status`. No id, priority, or `activeForm` — the list is replaced wholesale + * on every write (last-write-wins), so entries need no stable identity. The + * three statuses describe the complete portable lifecycle needed by model and + * UI consumers. + */ +export interface TodoItem { + /** What this task is — a short imperative line shown in the UI. */ + content: string; + /** Lifecycle state. `in_progress` marks a task being worked now; parallel work may mark several. */ + status: 'pending' | 'in_progress' | 'completed'; +} +/** + * Logged request state outside derived history: call config, system prompt, and + * tools. The latest full `request/header` snapshot reconstructs it; canonical + * empty optional fields are absent. + */ +export interface EpochHeader { + /** The conversation's call configuration (provider, model, reasoning effort, and sampling scalars). */ + config: LlmCallConfig; + /** Effective config fields materialized from the exact adapter rather than proposed by a caller. */ + adapterDefaults?: LlmCallConfigAdapterDefaults; + /** Rendered system prompt text; absent for a system-less request. */ + system?: string; + /** Assembled tool schemas; absent for a tool-less request. */ + tools?: ToolSchema[]; +} +/** Registration-bound metadata for one resolved model route. */ +export interface RequestContext { + /** Registered provider route the metadata belongs to. */ + provider: string; + /** Provider-owned model id the metadata belongs to. */ + model: string; + /** Maximum combined request and response context in tokens, when advertised. */ + contextWindow?: number; +} +/** + * Why a `request/header` snapshot was appended: `'initial'` — the log's first + * header (a new conversation); `'resume'` — a loop instance's first request + * over a log that already has header events (process restart, fork seed); + * `'change'` — a later request used a different header. + */ +export type RequestHeaderReason = 'initial' | 'resume' | 'change'; +/** + * The merge-extensible, append-only source of truth for an agent interaction. + * Message history is derived from this log. Every event is lossless JSON and + * sequence numbers stay contiguous, including raw chunks, so persistence can + * store the canonical log verbatim. + */ +export interface SessionEventMap { + /** + * Opens turn `turn` before the loop claims queued input or runs pre-step. + * Rejection, empty input, cancellation, or failure may close it with no + * step; otherwise the following identified `user/message` event or batch + * records the messages entering the step. + */ + 'turn/start': { + turn: number; + }; + /** + * Closes turn `turn` with the {@link TurnEndReason} that ended it. A turn + * with no entered step has no `step/start` or `step/end`. The loop does not await a + * flush at turn boundaries: `dsh-session-checkpoint-policy` owns the + * per-request durability checkpoint, and consumers that read storage after + * `whenIdle()` flush themselves. Success commits the turn; rejection is + * reported live and does not prevent later work. + */ + 'turn/end': { + turn: number; + reason: TurnEndReason; + }; + /** Opens step `step` of turn `turn` — one model call plus the tool executions it requested. */ + 'step/start': { + turn: number; + step: number; + }; + /** Closes step `step` of turn `turn`. */ + 'step/end': { + turn: number; + step: number; + }; + /** + * A user-role message on the model-visible surface: a direct human prompt + * (the queued message claimed for this turn), a synthetic `agent.inject()` + * context (file-change notices, subdir AGENTS.md, skill content, cron + * notifications, …), or an entered goal continuation round. All three + * project their `content` verbatim; `source` tells them apart. + */ + 'user/message': UserMessage; + /** Raw stream chunk — token-level replay fidelity. */ + 'assistant/chunk': { + turn: number; + step: number; + chunk: StreamChunk; + }; + /** + * Assembled assistant message for one step (derived history uses this). + * Carries the step's `usage` when the adapter reported token accounting, so + * the model output and its accounting travel together (there is no separate + * usage record). `usage` is absent when the adapter reported none. + */ + 'assistant/message': { + turn: number; + step: number; + message: AssistantMessage; + usage?: TokenUsage; + }; + /** + * The model requested one tool invocation: `name` with the raw `arguments` + * JSON string exactly as the model produced it (unparsed). `callId` pairs the + * call with its `tool/result`. + */ + 'tool/call': { + turn: number; + step: number; + callId: CallId; + name: string; + arguments: string; + }; + /** + * A completed tool call's model-facing result, optional internal failure + * identity, and optional tool-private `meta` presentation payload. `meta` is + * opaque to the core (the producing tool owns its shape and reads it back in + * `presentResult`) but MUST be JSON-serializable: `Session.append` + * runtime-validates all event data with `isJsonValue`, so a non-serializable + * `meta` is rejected at the source, and the durable log reproduces the + * identical card on replay. Absent + * unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time + * contextual diff here). + */ + 'tool/result': { + turn: number; + step: number; + message: ToolResultMessage; + error?: { + name: string; + code: string; + }; + meta?: JsonValue; + }; + /** Whole-list snapshot; latest write wins on replay. Log-only UI state; never derived history. */ + 'todo/write': { + todos: TodoItem[]; + }; + /** + * Full header for the next request, appended inside its step before dispatch. + * It is log-only; the latest snapshot reconstructs the request header. + */ + 'request/header': { + header: EpochHeader; + reason: RequestHeaderReason; + }; + /** + * Route metadata for the next request, logged only when the route or capacity + * changes. It does not participate in request reconstruction or header equality. + */ + 'request/context': RequestContext; + /** + * Marks the end of a constructor seed. Events before it have smaller seq + * values and came from the seed (resume, fork, or replay); this lifecycle + * produced none of them. This log-only event is the durable projection of + * {@link Session.firstLiveSeq}. Its payload is empty — position and `time` + * carry the meaning. + * + * Locate the LAST one in stored history. A seed already ending in one is not + * re-marked, so reopening an untouched session does not grow its log per + * pickup and the event need not be at the current `firstLiveSeq`. + * + * `Session`'s constructor is the only legitimate writer. The invariant + * companion deliberately constrains nothing here, so a plugin appending one + * would silently classify every live bracket before it as seed history. + * + * An owner of a standalone open/close bracket (`compaction/start` … + * `compaction/end`) reads it because seed history and live work are otherwise + * byte-identical: an unmatched opening marker before this event belongs to + * an ended lifecycle, whatever ended it. NOT a liveness signal about other + * writers — a concurrently live session holds its own boundary elsewhere, + * so tolerating concurrent writers needs a signal beyond the log. + */ + 'session/end-seed': Record; +} +/** The appendable event-type keys of {@link SessionEventMap}, plugin-merged extensions included. */ +export type SessionEventType = keyof SessionEventMap; +/** + * The subset of {@link SessionEventType} values whose events produce LLM + * messages and are eligible to appear on the ordered surface. Only these + * event types may carry {@link SurfaceOp} and {@link SessionEvent.sourceEventSeqs}. + */ +export type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result'; +/** + * A {@link SessionEvent} that is **on** the ordered surface — its + * `surfaceOp` is guaranteed present (mandatory), narrowed from a + * surface-eligible {@link SessionEvent} by checking both `type` and + * `surfaceOp` at runtime. + * + * Use the `isSurfaceEvent` type guard (in `surface.ts`) to narrow a + * `SessionEvent` to this type. + */ +export type SurfaceEvent = SessionEvent & { + surfaceOp: SurfaceOp; +}; +/** + * How a session event entered the ordered surface. Only valid on + * {@link SurfaceEventType} events. + * + * - `'append'`: added to the tail — normal path for user/assistant/tool + * messages. + * - `{ op: 'replace', start, end }`: replaces surface nodes from `start` + * (inclusive) through `end` (inclusive) with this node. Both must exist as + * surface nodes in the current surface. `start === end` replaces a single + * node. The node's {@link SessionEvent.sourceEventSeqs} must include every + * shadowed surface node. Used by compaction; any surface-replacing producer + * may use it. + */ +export type SurfaceOp = 'append' | { + op: 'replace'; + start: number; + end: number; +}; +/** + * Surface placement and cited source-event seqs for {@link Session.append}. Required on + * message-producing events and forbidden on log-only events. + */ +export interface SurfaceIntent { + surfaceOp: SurfaceOp; + /** + * Complete set of known source-event seqs. `assistant/message` may use a + * present empty array for a known empty provider stream; when the field is + * absent, the event does not record which earlier events produced the message. + * Other surface events require a non-empty set when this field is present. + */ + sourceEventSeqs?: number[]; +} +/** + * One immutable entry in the session log. + * + * A proper discriminated union over `type` (not independent `type`/`data` + * unions), so `switch (event.type)` narrows `event.data` without casts. + * + * The {@link sourceEventSeqs} and {@link surfaceOp} fields are conditional: + * they only exist on {@link SurfaceEventType} variants (`user/message`, + * `assistant/message`, `tool/result`). + * Non-surface events (boundary markers, chunks, usage, errors) never carry + * surface metadata — the compiler enforces this at `Session.append()` + * call sites. + */ +export type SessionEvent = { + [K in SessionEventType]: { + type: K; + /** Monotonic sequence number within the session. */ + seq: number; + /** Unix epoch milliseconds. */ + time: number; + data: SessionEventMap[K]; + /** + * Marks an event a reader may safely skip when it does not recognize + * `type`. Absent means required: a reader meeting an unrecognized type + * without this marker MUST refuse to reconstruct the session instead of + * silently dropping the event, because an unrecognized required event may + * change how the rest of the log is interpreted. A writer sets `true` only + * on purely informational records whose loss cannot affect reconstruction; + * defaulting to required means a forgotten marker over-refuses (an + * inconvenience) rather than silently resuming a gutted session. + */ + ignorable?: true; + } & (K extends SurfaceEventType ? { + /** + * Seq numbers of earlier events that this event cites as sources + * (e.g. the `assistant/chunk` seqs that built an `assistant/message`, + * or the surface nodes shadowed by a compaction replace node). An + * `assistant/message` may carry a present empty array for a known empty + * provider stream; when the field is absent, the event does not record which + * earlier events produced the message. + */ + sourceEventSeqs?: number[]; + /** How this event entered the surface; absent for non-surface events. */ + surfaceOp?: SurfaceOp; + } : object); +}[T]; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/types.js new file mode 100644 index 0000000..83ce659 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/lib/types/types.js @@ -0,0 +1,33 @@ +/** + * Brand a string as a {@link SessionId}. + * @param id - the raw session id string. + * @returns the same string, branded (a compile-time cast — no runtime cost). + */ +export function SessionId(id) { + return id; +} +/** + * The on-disk session format version, stamped into every newly-written {@link SessionHeader} + * and enforced by every persistence backend on load. The single source of truth for the + * version — write sites and the load-time check all read it. + * While the harness is unreleased it is pinned at `0`: no compatibility is + * implied, incompatible logs are rejected, and no migration is provided. + * + * The version is a single monotonic integer with no major/minor split. Whether + * a bump is needed is decided by what the WRITER emits, never by what a newer + * reader can accept: bump exactly when an older runtime could no longer handle + * a new log with full semantic correctness ("parses without error" is not + * correctness — silently skipping content that shapes reconstruction is a + * wrong read). Only structural changes reach that bar: the header shape, the + * {@link SessionEvent} envelope, core event semantics, or the surface + * mechanism (the {@link SurfaceEventType} set and {@link SurfaceOp} variants). + * Adding an ordinary event type does not bump — the per-event + * {@link SessionEvent.ignorable} guard covers vocabulary growth instead. When + * in doubt, bump: a near-identity upgrade step is almost free, a missed bump + * makes older runtimes read new logs wrong silently. The full mechanism + * (upgrade-step chain, in-memory view conversion, migrate-on-continue) is + * recorded in the session-log-version-mechanism Agent Note + * (`.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md`). + */ +export const SESSION_FORMAT_VERSION = 0; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/package.json new file mode 100644 index 0000000..aa14159 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session/package.json @@ -0,0 +1,60 @@ +{ + "name": "@deepseek-ai/dsh-session", + "description": "Event-sourced session store for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/session" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json", + "./surface": { + "types": "./lib/types/surface.d.ts", + "default": "./lib/types/surface.js" + } + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..aa2ae83 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.i18n.yaml new file mode 100644 index 0000000..b84b2b2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/session/README.md +README.md: 02aae21d71101e626bf2d2ead0bfd5d155723165 +README.zh.md: 2da8c5db8fe25d55faafdd6d44ea9090dd232576 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.md new file mode 100644 index 0000000..02aae21 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.md @@ -0,0 +1,144 @@ +# dsh-session + +English | [中文](README.zh.md) + +Event-sourced session log and in-memory store. A `Session` is the append-only source of truth for an agent's whole interaction history — the LLM message history is *derived* from it. A **surface** layer (an ordered projection of message-producing events) is maintained on top of the raw log for efficient derivation and compaction. + +The optional `@deepseek-ai/dsh-session/invariant` companion registers this package's relational trace checks with `ctx.invariants`: monotonic sequence numbers, turn/step enclosure, and same-step tool call/result pairing. It replays existing sessions when loaded or reloaded; storage validation, snapshotting, freezing, cited source-event validation, and surface acceptance remain always-on responsibilities of the root session package. + +## Service: `SessionStore` (ctx key: `sessions`) + +Creates and holds event-sourced `Session` instances. Persistence is intentionally not implemented here — plugins subscribe to `session/event`, flush on `session/flush`, and may mirror the paired `session/created`/`session/disposed` lifecycle. + +### Public API + +- `ctx.sessions.create(id?, { seed?, meta? }?)` validates and detaches durable seed/header data, fills the version and id, defaults `createdAt` to now, publishes the session, and binds it to the calling fiber. Persisted reconstruction supplies its original `createdAt`, `seedLength`, and `delegationDepth`. +- `ctx.sessions.flush(session)` dispatches the awaited parallel durability checkpoint through the session's captured scope. Every listener starts and the call waits for all to settle before reporting failure; unpublished, detached, and stale objects reject. +- `ctx.sessions.fork(source, boundary?, childSessionId?): Session` — Resolve a live session object or id, select a seed through the inclusive `boundary` event seq (default: current last event), require that prefix to end outside an open turn, and create a live child session with lineage metadata. +- `ctx.sessions.get(id: SessionId): Session | undefined` +- `ctx.sessions.list(): Session[]` + +#### Advanced: ordered-teardown lifecycle primitives + +Use the split lifecycle only when teardown must be ordered with another resource: + +- `prepare(id?, options?)` validates and constructs without publication. +- `enter(session)` performs the collision check, publishes without announcing, and returns an entry-bound idempotent detach. Concurrent same-id preparations are allowed, but only one entry succeeds; a stale detach cannot remove its replacement. +- `announce(session)` emits the single creation edge and rejects repeat or reentrant announcements. Detach during that dispatch is deferred and later emits the paired disposal edge; an unannounced entry emits neither lifecycle edge. + +`dsh-agent-loop` uses this split so final loop flush precedes session detach; see the [ownership Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.md). + +### Live service events + +The store pairs announced creation with disposal, publishes post-commit append notifications with per-listener containment, and provides an awaited durability checkpoint. Exact signatures and scope behavior live in the generated region of [session.md](../../../docs/subsystems/session.md#cordis-surface); payloads live in the [persistence catalog](../../../docs/persistence-catalog.md). + +### Class: `Session` + +Plain class (not a Cordis Service). Create live sessions through `ctx.sessions.create()` and detached replay or inspection sessions through `Session.create()`; the detached factory does not publish lifecycle events or bind the session to a fiber. + +- `session.append(type, data, opts?)` snapshots and freezes durable data and surface metadata, validates marker shape, cited source-event seqs, complete replacement coverage, and content-only single-result `tool/result` rewrites, commits synchronously, then notifies observers with independent failure containment. Reentrant attached-session appends reject, and runtime checks cover widened unions and loaded logs. +- `session.deriveMessages()` incrementally projects each new surface entry once and returns a fresh array over the complete identified, frozen messages stored by those entries. Assistant messages preserve the provider and model that produced them plus adapter-private replay state in their model source. A surface rewrite rebuilds the projection; there is no raw-log fallback. +- `session.deriveEventMessage(event)` is the canonical per-event projection used by reconstruction and request checks. +- `session.surface` exposes the readonly `SessionSurface` view owned by the session's single incremental surface manager; `replaceGeneration` changes on every committed rewrite. +- `session.events` is a cached frozen snapshot invalidated by append; accepted events remain deeply frozen. +- `session.seq`, `session.id` — current sequence and readonly typed identity. +- `session.header: SessionHeader` — detached, deep-frozen creation metadata (`version`, `id`, `createdAt`, optional `cwd`/`parentSession`/`seedLength`/`delegationDepth`). Construction validates the durable record and requires its id to match `session.id`. + +### Lossless JSON utilities + +Durable values need one accepted representation, not a check followed by a second read. `isJsonValue(value)` is the boolean predicate; `snapshotJsonValue(value)` iteratively validates and copies a plain value in one pass, returning `undefined` for invalid input and propagating a throwing getter. The snapshot helper accepts finite JSON numbers except `-0` (JSON rewrites it to `0`), dense ordinary arrays, and plain or null-prototype objects; it rejects cycles, unsupported scalars, and exotic prototypes before normalization without imposing a call-stack depth limit. + +Session-event import separates ownership from message validation. `snapshotSessionEvent(event)` clones a borrowed event before validating and freezing its identified message. `adoptSessionEvent(event)` performs the same message work in place and returns the original event; callers may use it only when they transfer an exclusively owned object graph with no mutable child shared with another event. + +### Chunk-row storage codec (`chunk-rows.ts`) + +The shared [storage codec](src/chunk-rows.ts) losslessly converts event sequences to compact rows and back. It preserves unrecognized events verbatim and rejects malformed encoded rows; persistence backends decide whether to enable packed writes. + +### Surface types + +This package owns ordered surface projection, replacement validation, replay, and the type guards that distinguish append-origin from replacement events. The [surface type catalog](../../../docs/subsystems/session.md#surface-types) owns the exact shapes and field semantics. A human transcript must project append-origin events rather than `session.surface`, because landed replacements shadow history the reader already saw; model-facing consumers continue to read `session.surface`. + +### Request-header reconstruction (`request-header.ts`) + +`request/header` records a full canonical snapshot of the non-history request envelope with reason `initial`, `resume`, or `change`. Its optional `adapterDefaults` map marks effective `reasoningEffort` or `maxTokens` values materialized by exact-model resolution, allowing the next request proposal to distinguish them from explicit conversation settings. `foldRequestHeader()` selects the latest snapshot; legacy delta events and the removed `fallback` reason are rejected. See the [reconstructable-requests Agent Note](../../../.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.md). + +A `user/message` stores the complete `UserMessage` directly, including the identity created before inbox routing or step entry. It renders its `content` verbatim whether it is a direct human prompt, a synthetic injection, or an entered goal round; its typed `source` is the only channel that tells them apart and carries any domain-specific durable facts. `assistant/message` and `tool/result` likewise store complete message values. Turn execution remains enclosed by `turn/start` and `turn/end`; `agent.inject()` queues input until a later pre-step claims it and returns it in an enter decision. + +`tool/result` persists one identified user-role tool-result message, optional internal failure identity, and optional presentation metadata. A tool's successful canonical `value` and human-readable canonical failure message remain execution-local; rendered error content is the replay-authoritative message. + +### Session event vocabulary (`types.ts`) + +The generated [persistence log event catalog](../../../docs/persistence-catalog.md) enumerates each append-only event type with its payload, surface badge, and declaration site. Token accounting reads per-step `assistant/chunk { type: 'usage' }` records and treats `assistant/message.usage` as the committed-step fallback when no usage chunk exists; failed model-request attempts have no assistant message. Each `assistant/message` records the provider, model, and optional replay state. + +Merge-extensible via `SessionEventMap` — a plugin declaration-merges its own types (the compaction seam's `compaction/*`, bounded recovery's non-surface `llm/retry`, the hook bridges' `hook/*`); merged members appear in the same catalog. A plugin owns the relational invariant for its merged events, including whether a log-only event may appear between turns. A producer that requires durability appends through `Session` and then awaits `ctx.sessions.flush(session)` without fabricating an execution turn. + +Also defines `TurnEndReasonMap`, the merge-extensible `kind`-tagged sum type for turn endings. `turn/start` carries only the turn number; the following entered `user/message` batch records its input, while `llm/retry` records request recovery. + +An interrupted live turn ends with `{ kind: 'aborted', reason: AgentCancelCause }`, preserving the typed cancellation cause in the durable transcript. Persistence imports the coarse aborted outcome from the supported older format as `{ kind: 'aborted', reason: { kind: 'legacy' } }`, because that record did not retain its caller. A turn failure carries `{ kind: 'error', error }`; crash recovery alone synthesizes `{ kind: 'interrupted' }`. + +Every `SessionEvent` carries three optional top-level fields (structural metadata): + +- `sourceEventSeqs?: number[]` — seq numbers of earlier events cited as sources (e.g., the `assistant/chunk` seqs behind an `assistant/message`, or the shadowed entries behind a compaction replacement entry). On `assistant/message`, a present `[]` records a known empty provider stream, while omission means a legacy or foreign event did not record the source stream; other surface events require a non-empty list when this field is present. +- `surfaceOp?: SurfaceOp` — how this event entered the surface. Absent for non-surface events (boundaries, chunks, usage, errors). +- `ignorable?: true` — marks an event a reader may safely skip when it does not recognize the type; absent means required, so an unknown-type event refuses session reconstruction ([mechanism](../../../.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md)). + +### Metadata types (`types.ts`) + +- `SessionHeader` — session metadata written once when published as `Session.header`, where detachment and deep-freezing enforce immutability at runtime: `{ version, id, createdAt, cwd?, parentSession?, seedLength?, delegationDepth? }`. Persistence loaders may return mutable detached copies of the same data type. Owned here (beside `SessionId`) because `Session.header` is typed by it; persistence backends re-export it rather than own it (which would force a package cycle). + +### Extension points + +- Persistence plugins: subscribe to `session/event` (write-behind) and drain on `session/flush` (awaited) and fiber dispose. A durable backend reads the log and reloads it into a live session; the metadata contract (`SessionHeader`, `session.header`) is what such a backend stores beside the log. +- Replay/fork: `create(id, { seed })` validates and freezes a contiguous current-format log and rebuilds its surface; request headers require provider/model, and assistant messages require provider/model provenance. Persistence owns read compatibility before constructing this current-format seed. `fork(source, boundary?, childSessionId?)` selects a completed-turn prefix and records lineage. +- Compaction: `dsh-compaction-basic` appends a `user/message` replacement for summary checkpoints, while `dsh-compaction-tool-result-pruner` appends a content-only `tool/result` replacement. Tool-pairing boundary policy and its cache belong to the [`dsh-compaction` seam](../../compaction/compaction/README.md), while this package owns ordered surface membership, replacement validation, and `replaceGeneration`. + +## Model Experience + +### Derived message history + +#### What the model sees + +The model receives the complete messages from `user/message`, `assistant/message`, and `tool/result` surface entries verbatim. Their identities, roles, sources, and content blocks are the same values established at creation; projections do not mint identities. A prompt envelope changes only human presentation; its prefix context and request delimiter are already present in the event content. Tool calls live inside assistant messages. Chunks, boundaries, usage, hook records, todo records, and other log-only events add no message. + +#### Token effect + +Appended surface entries are resent on later steps. A `replace` surface operation removes the shadowed entries from future inputs without deleting their raw log records. + +#### KV Cache effect + +Appended surface entries preserve reusable prefixes. A `replace` operation invalidates reuse from the first shadowed message even though the underlying event log stays append-only. + +### Crash-repair result + +#### What the model sees + +If recovery finds an assistant tool request with no durable `tool/call`, its synthetic `TOOL_NOT_STARTED` result says `The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed.` If a durable `tool/call` has no result, its `TOOL_OUTCOME_UNKNOWN` result says `The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly.` + +#### Token effect + +Zero tokens in an intact session. Each repaired call adds its retained risk-specific error text on resume. + +#### KV Cache effect + +Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries. + +### Logged request header + +#### What the model sees + +The session reconstructs the system prompt, tool schemas, call config, and session prefix that the loop actually sent. Header events do not add a second copy to message history; the prefix is prepended outside `deriveMessages()`. + +#### Token effect + +Zero duplicate tokens from logging. The reconstructed prefix, system text, and schemas still incur their normal per-request cost. + +#### KV Cache effect + +Logging causes no invalidation, and exact reconstruction preserves request-prefix identity. A later header with changed prefix, prompt, or schemas may invalidate reuse from its first difference. + +## Known Limitations and Deferred Work + +- **Session branching/tree** (pi-style entry tree) — deferred unless needed beyond boundary-based `fork()`. +- **`fork()` cuts only at stable boundaries of live sessions** — the selected prefix must end outside an open turn and the source must be in the store; forking a persisted-but-unloaded session is excluded from the [fork API](../../../.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.md). +- **`SESSION_FORMAT_VERSION` stays pinned at `0`** — pre-release, no broad compatibility implied: `Session` accepts only current seed shapes, and a backend refuses any other version naming the direction (newer: "written by a newer harness — upgrade"; older: no upgrade path ships yet). Unknown event types refuse the same way unless marked `ignorable` in the envelope; the versioning mechanism is the [session-log-version-mechanism note](../../../.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md). Narrow storage import upgrades belong to the persistence boundary ([policy](../../../AGENTS.md), [pre-identity message recovery](../../../.agents/notes/implemented/bug-fix/2026-07-28-load-pre-identity-session-messages.md)). +- **`TurnEndReasonMap` omits the ACP-named `refusal` / `max_turn_requests` variants** — producer-gated: they land when an adapter or the loop first emits them. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.zh.md new file mode 100644 index 0000000..2da8c5d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/README.zh.md @@ -0,0 +1,144 @@ +# dsh-session + +[English](README.md) | 中文 + +事件溯源的会话日志和内存存储。`Session` 是 agent(智能体)全部交互历史的仅追加真源,LLM(大语言模型)消息历史由它*派生*。原始日志之上维护一个 **surface** 层(产生消息事件的有序投影),以便高效派生和压缩(compaction)。 + +可选配套入口 `@deepseek-ai/dsh-session/invariant` 将此包的关系轨迹检查注册到 `ctx.invariants`:序号单调递增、轮次/步骤闭合,以及同一步骤内的工具调用/结果配对。加载或重新加载时,它会回放现有会话;存储校验、快照、冻结、被引用的源事件校验和 surface 准入仍始终由根会话包负责。 + +## 服务:`SessionStore`(ctx 键:`sessions`) + +创建并持有事件溯源的 `Session` 实例。这里有意不实现持久化:插件订阅 `session/event`,在 `session/flush` 时刷新,并可镜像成对的 `session/created`/`session/disposed` 生命周期。 + +### 公共 API + +- `ctx.sessions.create(id?, { seed?, meta? }?)` 校验持久种子/头部数据并生成脱离副本,补齐版本和 id,在未提供 `createdAt` 时使用当前时间,发布会话并将其绑定到调用方 fiber。持久化重建会提供原始的 `createdAt`、`seedLength` 和 `delegationDepth`。 +- `ctx.sessions.flush(session)` 通过会话捕获的作用域分发一个需等待完成的并行持久性检查点。每个监听器都会启动;调用会等待全部结算后才报告失败。未发布、已脱离和陈旧的对象会被拒绝。 +- `ctx.sessions.fork(source, boundary?, childSessionId?): Session`:解析实时会话对象或 id,选取截至 `boundary` 事件序号(含该事件)的种子(默认为当前最后一个事件),要求所选前缀结束时没有开放轮次,再创建带谱系元数据的实时子会话。 +- `ctx.sessions.get(id: SessionId): Session | undefined` +- `ctx.sessions.list(): Session[]` + +#### 高级:有序清理生命周期原语 + +仅在清理必须与另一项资源排序时使用拆分生命周期: + +- `prepare(id?, options?)` 校验并构造,但不发布。 +- `enter(session)` 执行冲突检查,在不通知的情况下发布,并返回一个绑定到该条目的幂等脱离函数。允许并发准备相同 id,但只有一个条目能够成功进入;陈旧的脱离函数无法移除其替代项。 +- `announce(session)` 发出唯一一次创建边,并拒绝重复或重入通知。该次分发期间请求的脱离操作会延后,之后再发出成对的释放边;未通知的条目不会发出任何生命周期边。 + +`dsh-agent-loop` 使用这一拆分,以保证循环的最终刷新先于会话脱离;详见[所有权 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-contracts.md)。 + +### 实时服务事件 + +会话存储会将已通知的创建与释放配对,在提交后发布追加通知并逐个监听器收容失败,同时提供受等待的持久性检查点。确切签名和作用域行为见 [session.md](../../../docs/subsystems/session.md#cordis-surface) 的生成区块;载荷见[持久化目录](../../../docs/persistence-catalog.md)。 + +### 类:`Session` + +普通类(不是 Cordis 服务)。活跃会话通过 `ctx.sessions.create()` 创建,脱离态的回放或检查会话通过 `Session.create()` 创建;脱离态工厂不会发布生命周期事件,也不会将会话绑定到 fiber。 + +- `session.append(type, data, opts?)` 会为持久数据和 surface 元数据制作快照并冻结它们,校验标记形态、被引用的源事件 seq、替换覆盖完整性,以及仅修改内容的单个 `tool/result` 重写,随后同步提交,再在彼此独立的失败收容下通知观察者。对已挂接会话的重入追加会被拒绝,运行时检查也覆盖扩宽后的联合类型和已加载日志。 +- `session.deriveMessages()` 对每个新的 surface 条目只做一次增量投影,并返回一个新数组,其中包含这些条目存储的完整、带标识且冻结的消息。assistant 消息的模型来源会保留生成该消息的提供方和模型,以及适配器私有回放状态。surface 重写会重建投影;不存在原始日志回退。 +- `session.deriveEventMessage(event)` 是重建和请求检查使用的规范逐事件投影。 +- `session.surface` 暴露只读 `SessionSurface` 视图,由会话唯一的增量 surface 管理器所有;每次提交重写,`replaceGeneration` 都会变化。 +- `session.events` 是按追加失效的缓存冻结快照;已接受事件保持深度冻结。 +- `session.seq`、`session.id`:当前序号和只读类型化身份。 +- `session.header: SessionHeader`:脱离、深冻结的创建元数据(`version`、`id`、`createdAt`,以及可选的 `cwd`/`parentSession`/`seedLength`/`delegationDepth`)。构造时会校验持久记录,并要求其中的 id 与 `session.id` 一致。 + +### 无损 JSON 工具 + +持久值需要一种已接受的表示,不能先检查再二次读取。`isJsonValue(value)` 是布尔判断函数;`snapshotJsonValue(value)` 在一趟迭代中校验并复制普通值,无效输入返回 `undefined`,getter 抛出的异常则向外传播。快照辅助函数接受除 `-0` 外的有限 JSON 数值(JSON 会将其改写为 `0`)、稠密普通数组、普通对象或 null 原型对象;它会在规范化前拒绝循环引用、不支持的标量和特殊原型,同时不施加调用栈深度限制。 + +会话事件导入将所有权与消息校验分开处理。`snapshotSessionEvent(event)` 会先克隆借用的事件,再校验并冻结其中带标识的消息。`adoptSessionEvent(event)` 原地执行相同的消息处理并返回原事件;调用方只有在移交独占的对象图,且该对象图没有与其他事件共享可变子对象时,才可以使用此函数。 + +### 分片行存储编解码器(`chunk-rows.ts`) + +共享的[存储编解码器](src/chunk-rows.ts)在事件序列与紧凑行之间无损转换。它会逐字保留无法识别的事件,并拒绝形态错误的编码行;是否启用打包写入由持久化后端决定。 + +### Surface 类型 + +此包拥有有序 surface 投影、替换校验、回放,以及区分追加来源事件与替换事件的类型守卫。[surface 类型目录](../../../docs/subsystems/session.md#surface-types)拥有精确形状与字段语义。面向人的 transcript(文本记录)必须投影追加来源事件,而不是 `session.surface`,因为已落地的替换会遮蔽读者已经看到的历史;面向模型的消费方继续读取 `session.surface`。 + +### 请求头重建(`request-header.ts`) + +`request/header` 记录非历史请求封装的完整规范快照,其原因为 `initial`、`resume` 或 `change`。其可选 `adapterDefaults` 映射会标记由精确模型解析填入的生效 `reasoningEffort` 或 `maxTokens` 值,使下一次请求提议能够将它们与显式对话设置区分开。`foldRequestHeader()` 选择最新快照;旧版增量事件和已移除的 `fallback` 原因会被拒绝。详见[可重建请求 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.md)。 + +`user/message` 会直接存储完整的 `UserMessage`,其中包括收件箱路由或进入步骤前创建的标识。无论它是直接人类提示词、合成注入,还是已进入的 Goal Round,都会原样呈现其 `content`;带类型的 `source` 是区分三者的唯一通道,并携带各领域专有的持久事实。`assistant/message` 和 `tool/result` 也会存储完整的消息值。轮次执行仍由 `turn/start` 与 `turn/end` 包围;`agent.inject()` 会把输入排队,直到后续某次 pre-step 领取它,并在 enter 决策中返回它。 + +`tool/result` 持久保存一条带标识、user-role 的工具结果消息,以及可选内部失败标识和可选呈现元数据。工具成功时的规范 `value` 和便于人类阅读的规范失败消息只存在于执行本地;渲染后的错误内容是回放权威消息。 + +### 会话事件词汇(`types.ts`) + +生成的[持久化日志事件目录](../../../docs/persistence-catalog.md)逐成员列举仅追加日志的事件类型、载荷、surface 标记与声明位置。Token 记账读取每个步骤的 `assistant/chunk { type: 'usage' }` 记录;如果没有用量分片,则将 `assistant/message.usage` 作为已提交步骤的后备。失败的模型请求尝试没有 assistant 消息。每条 `assistant/message` 都会记录提供方、模型和可选回放状态。 + +`SessionEventMap` 可通过合并扩展:插件使用声明合并添加自身类型(压缩 seam 的 `compaction/*`、有界恢复的非 surface `llm/retry`、钩子桥接层的 `hook/*`);合并成员会出现在同一目录中。插件拥有其合并事件的关系不变量,包括是否允许纯日志事件出现在轮次之间。需要持久性的生产方通过 `Session` 追加,再等待 `ctx.sessions.flush(session)`,无需虚构一个执行轮次。 + +此包还定义 `TurnEndReasonMap`,即用于轮次结束、可合并扩展且以 `kind` 为标签的和类型。`turn/start` 只携带轮次编号;随后已进入的 `user/message` 批次记录其输入,`llm/retry` 则记录请求恢复。 + +被中断的实时轮次以 `{ kind: 'aborted', reason: AgentCancelCause }` 结束,在持久 transcript 中保留类型化取消原因。持久化会将受支持旧格式中的粗粒度中止结果导入为 `{ kind: 'aborted', reason: { kind: 'legacy' } }`,因为该记录没有保留调用方。轮次失败携带 `{ kind: 'error', error }`;只有崩溃恢复会合成 `{ kind: 'interrupted' }`。 + +每个 `SessionEvent` 都有三个可选顶层字段(结构元数据): + +- `sourceEventSeqs?: number[]`:被引用为来源的较早事件 seq(例如 `assistant/message` 引用的 `assistant/chunk` seq,或压缩替换条目引用的已遮蔽条目)。对于 `assistant/message`,存在的 `[]` 表示已知提供方流为空;省略则表示旧版或外部事件没有记录源流。其他 surface 事件若有此字段,则要求非空列表。 +- `surfaceOp?: SurfaceOp`:事件进入 surface 的方式。非 surface 事件(边界、分片、用量、错误)不含该字段。 +- `ignorable?: true`:标记读取器在不认识事件类型时可以安全跳过该事件;缺失表示必需,不认识的事件类型会使会话重建被拒绝([机制](../../../.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md))。 + +### 元数据类型(`types.ts`) + +- `SessionHeader`:会话元数据,在发布为 `Session.header` 时写入一次;脱离和深冻结保证运行时不可变:`{ version, id, createdAt, cwd?, parentSession?, seedLength?, delegationDepth? }`。持久化 loader 可返回相同数据类型的可变脱离副本。该类型与 `SessionId` 一同归此包所有,因为 `Session.header` 以它为类型;持久化后端只是重新导出而不拥有它,否则会形成包循环依赖。 + +### 扩展点 + +- 持久化插件:订阅 `session/event`(延后写入),并在 `session/flush`(受等待)及 fiber dispose(资源释放)时排空。持久后端读取日志并重新加载到实时会话;这类后端会把元数据约定(`SessionHeader`、`session.header`)与日志一同存储。 +- 回放/fork:`create(id, { seed })` 校验并冻结连续的当前格式日志,再重建 surface;请求头必须包含提供方/模型,assistant 消息必须包含提供方/模型溯源信息。持久化层在构造该当前格式 seed 前负责读取兼容性处理。`fork(source, boundary?, childSessionId?)` 选择已完成轮次前缀并记录谱系。 +- 压缩:`dsh-compaction-basic` 为摘要检查点追加一个替换用 `user/message`,而 `dsh-compaction-tool-result-pruner` 追加仅修改内容的 `tool/result` 替换。工具配对边界策略及其缓存归 [`dsh-compaction` seam](../../compaction/compaction/README.md) 所有;此包拥有有序 surface 成员关系、替换校验与 `replaceGeneration`。 + +## 模型体验 + +### 派生消息历史 + +#### 模型看到的内容 + +模型会原样接收 `user/message`、`assistant/message` 和 `tool/result` surface 条目中的完整消息。其标识、角色、来源和内容块都与创建时确定的值相同;投影不会生成标识。提示词封装只改变面向人的呈现;其前缀上下文和请求分隔符已经位于事件内容中。工具调用包含在 assistant 消息内。分片、边界、用量、钩子记录、todo 记录以及其他仅日志事件不会添加消息。 + +#### Token 影响 + +追加的 surface 条目会在后续步骤中重新发送。`replace` surface 操作会从未来输入中移除被遮蔽条目,但不删除其原始日志记录。 + +#### KV Cache 影响 + +追加的 surface 条目会保留可复用前缀。即使底层事件日志保持仅追加,`replace` 操作也会从首条被遮蔽消息起使缓存复用失效。 + +### 崩溃修复结果 + +#### 模型看到的内容 + +如果恢复发现 assistant 工具请求没有持久 `tool/call`,其合成 `TOOL_NOT_STARTED` 结果内容为 `The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed.`。如果持久 `tool/call` 没有结果,其 `TOOL_OUTCOME_UNKNOWN` 结果内容为 `The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly.`。 + +#### Token 影响 + +未受损会话的 token 增量为零。恢复时,每个修复后的调用都会添加保留的、针对具体风险的错误文本。 + +#### KV Cache 影响 + +保持仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。 + +### 已记录的请求头 + +#### 模型看到的内容 + +会话会重建循环实际发送的系统提示词、工具 schema、调用配置和会话前缀。请求头事件不会向消息历史加入第二份副本;前缀在 `deriveMessages()` 外部前置。 + +#### Token 影响 + +日志记录不产生重复 token。重建的前缀、系统文本和 schema 仍会产生正常的逐请求开销。 + +#### KV Cache 影响 + +记录日志不会导致失效,精确重建会保持请求前缀一致。后续请求头若更改前缀、提示词或 schema,可能从第一处差异开始使复用失效。 + +## 已知限制与暂缓事项 + +- **会话分支/树结构**(pi 风格条目树):除非需要超越基于边界的 `fork()` 能力,否则暂缓。 +- **`fork()` 仅在实时会话的稳定边界处切分**:所选前缀结束时不得有开放轮次,且源会话必须位于存储中;[fork API](../../../.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.md) 不支持对已持久化但未加载的会话进行 fork。 +- **`SESSION_FORMAT_VERSION` 固定为 `0`**:预发布阶段不承诺广泛兼容性;`Session` 只接受当前 seed 形状,后端拒绝其他任何版本并说明方向(更新的版本提示"由更新的 harness 写入,请升级";更旧的版本说明尚无升级路径)。不认识的事件类型同样被拒绝,除非信封带 `ignorable` 标记;版本机制见 [session-log 版本机制 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md)。范围受限的存储导入升级应由持久化边界负责([政策](../../../AGENTS.md)、[消息标识机制引入前的消息恢复](../../../.agents/notes/implemented/bug-fix/2026-07-28-load-pre-identity-session-messages.md))。 +- **`TurnEndReasonMap` 不含 ACP(Agent Client Protocol)命名的 `refusal`/`max_turn_requests` 变体**:受生产方约束;只有当适配器或循环首次产生这些变体时才加入。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/index.js new file mode 100644 index 0000000..1102035 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/index.js @@ -0,0 +1,1886 @@ +import { Service } from "@deepseek-ai/cordis"; +import { isAbsolute } from "node:path"; +import { CallId, MessageId, assertNever, callConfigEquals, deepFreeze, freezeMessage } from "@deepseek-ai/dsh-llm"; +import { scopeOf, scopeTarget } from "@deepseek-ai/dsh-scope"; +//#region lib/types/types.js +/** +* Brand a string as a {@link SessionId}. +* @param id - the raw session id string. +* @returns the same string, branded (a compile-time cast — no runtime cost). +*/ +function SessionId(id) { + return id; +} +/** +* The on-disk session format version, stamped into every newly-written {@link SessionHeader} +* and enforced by every persistence backend on load. The single source of truth for the +* version — write sites and the load-time check all read it. +* While the harness is unreleased it is pinned at `0`: no compatibility is +* implied, incompatible logs are rejected, and no migration is provided. +* +* The version is a single monotonic integer with no major/minor split. Whether +* a bump is needed is decided by what the WRITER emits, never by what a newer +* reader can accept: bump exactly when an older runtime could no longer handle +* a new log with full semantic correctness ("parses without error" is not +* correctness — silently skipping content that shapes reconstruction is a +* wrong read). Only structural changes reach that bar: the header shape, the +* {@link SessionEvent} envelope, core event semantics, or the surface +* mechanism (the {@link SurfaceEventType} set and {@link SurfaceOp} variants). +* Adding an ordinary event type does not bump — the per-event +* {@link SessionEvent.ignorable} guard covers vocabulary growth instead. When +* in doubt, bump: a near-identity upgrade step is almost free, a missed bump +* makes older runtimes read new logs wrong silently. The full mechanism +* (upgrade-step chain, in-memory view conversion, migrate-on-continue) is +* recorded in the session-log-version-mechanism Agent Note +* (`.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md`). +*/ +const SESSION_FORMAT_VERSION = 0; +//#endregion +//#region lib/types/json.js +/** Lossless-JSON validation and detached snapshots for durable session data. @module @deepseek-ai/dsh-session/json */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const constructor = Object.getOwnPropertyDescriptor(prototype, "constructor")?.value; + if (typeof constructor !== "function") return false; + try { + return constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } catch { + return false; + } +} +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value) { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, "Object"); +} +/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, "Array")) return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === "object" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype); +} +/** Whether an object is a plain or null-prototype record from any JavaScript realm. */ +function hasPlainObjectPrototype(value) { + const prototype = Object.getPrototypeOf(value); + return prototype === null || typeof prototype === "object" && isIntrinsicObjectPrototype(prototype); +} +/** Return every JSON-visible object key, or reject own data JSON would discard. */ +function enumerableStringKeys(value) { + const keys = Reflect.ownKeys(value); + if (keys.some((key) => typeof key !== "string" || !Object.prototype.propertyIsEnumerable.call(value, key))) return void 0; + return keys; +} +/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */ +function walkJsonValue(value, detach) { + const ancestors = /* @__PURE__ */ new Set(); + let root; + const assign = (destination, item) => { + if (destination === void 0) return; + if (destination.kind === "root") root = item; + else if (destination.kind === "array") destination.target[destination.index] = item; + else Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true + }); + }; + const tasks = [{ + kind: "visit", + value, + ...detach ? { destination: { kind: "root" } } : {} + }]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "leave") { + ancestors.delete(task.source); + continue; + } + if (task.kind === "array-item") { + if (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return void 0; + tasks.push({ + kind: "visit", + value: task.source[task.index], + ...task.target === void 0 ? {} : { destination: { + kind: "array", + target: task.target, + index: task.index + } } + }); + continue; + } + if (task.kind === "object-property") { + tasks.push({ + kind: "visit", + value: task.source[task.key], + ...task.target === void 0 ? {} : { destination: { + kind: "object", + target: task.target, + key: task.key + } } + }); + continue; + } + const current = task.value; + if (current === null) { + assign(task.destination, null); + continue; + } + if (typeof current === "boolean" || typeof current === "string") { + assign(task.destination, current); + continue; + } + if (typeof current === "number") { + if (!Number.isFinite(current) || Object.is(current, -0)) return void 0; + assign(task.destination, current); + continue; + } + if (typeof current !== "object") return void 0; + if (ancestors.has(current)) return void 0; + if (Array.isArray(current)) { + if (!hasPlainArrayPrototype(current)) return void 0; + const length = current.length; + if (Reflect.ownKeys(current).length !== length + 1) return void 0; + const target = detach ? [] : void 0; + if (target !== void 0) assign(task.destination, target); + ancestors.add(current); + tasks.push({ + kind: "leave", + source: current + }); + for (let index = length - 1; index >= 0; index--) tasks.push({ + kind: "array-item", + source: current, + index, + ...target === void 0 ? {} : { target } + }); + continue; + } + if (!hasPlainObjectPrototype(current)) return void 0; + const keys = enumerableStringKeys(current); + if (keys === void 0) return void 0; + const target = detach ? {} : void 0; + if (target !== void 0) assign(task.destination, target); + ancestors.add(current); + tasks.push({ + kind: "leave", + source: current + }); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === void 0) return void 0; + tasks.push({ + kind: "object-property", + source: current, + key, + ...target === void 0 ? {} : { target } + }); + } + } + return detach ? root : true; +} +/** +* Validate and detach lossless JSON in one read per property, so a stateful +* getter cannot change between validation and copying. Traversal is iterative, +* so valid nesting is bounded by available memory rather than the JavaScript +* call stack. Accepts ordinary arrays, plain or null-prototype objects, and JSON +* scalars; rejects sparse, cyclic, exotic, negative-zero, and non-finite values. +* Getter throws propagate. +* +* @param value - the candidate value to validate and detach. +* @returns the detached snapshot, or `undefined` when the value is not +* losslessly JSON-serializable. +*/ +function snapshotJsonValue(value) { + return walkJsonValue(value, true); +} +/** +* Test the same lossless JSON boundary as {@link snapshotJsonValue} without +* detaching it. Only own enumerable string properties participate; `toJSON` +* is ignored and getters run, so persistence boundaries use the snapshotter. +* @param value - the candidate event data to test. +* @returns whether `value` survives JSON round-trip losslessly. +*/ +function isJsonValue(value) { + return walkJsonValue(value, false) === true; +} +//#endregion +//#region lib/types/surface.js +/** +* Surface layer on top of the session event log: an ordered view of events +* that produce LLM messages. The append-only log remains the source of truth. +* +* Browser-safe: web clients consume this subpath export, so it must stay free +* of `node:` imports (they break the vite bundle). +* +* @module @deepseek-ai/dsh-session/surface +*/ +/** Runtime counterpart of the message-producing event union. */ +const SURFACE_EVENT_TYPES = new Set([ + "user/message", + "assistant/message", + "tool/result" +]); +/** +* Whether an event type can join the model-visible surface. +* @param type - event type to test. +* @returns true for one of the three message-producing event types. +*/ +function isSurfaceEligibleType(type) { + return SURFACE_EVENT_TYPES.has(type); +} +/** +* Narrow an event to a surface-eligible event carrying its required marker. +* @param event - event to test. +* @returns true when both the type and marker identify a surface event. +*/ +function isSurfaceEvent(event) { + if (!SURFACE_EVENT_TYPES.has(event.type)) return false; + return event.surfaceOp !== void 0; +} +/** +* Narrow an event to an append-origin surface event: one that entered the +* surface at its own log position and was never itself a replacement copy. +* +* The model-visible surface deliberately shadows replaced ranges, so it is the +* wrong source for a human transcript — a landed replacement would erase +* conversation the user already saw. Append-origin events are that transcript's +* durable source material; replacement copies stay model-only. +* @param event - event to test. +* @returns true when the event appended to the surface tail. +*/ +function isAppendSurfaceEvent(event) { + return isSurfaceEvent(event) && event.surfaceOp === "append"; +} +/** +* Narrow an event to a surface replacement: a node that shadowed an existing +* surface range instead of appending to the tail. The counterpart of +* {@link isAppendSurfaceEvent} over the two {@link SurfaceOp} variants. +* @param event - event to test. +* @returns true when the event replaced a surface range. +*/ +function isReplacementSurfaceEvent(event) { + return isSurfaceEvent(event) && event.surfaceOp !== "append"; +} +/** +* Project a single event into the LLM message it derives to, or null when it +* produces none — a non-surface event (chunk, boundary, log-only record) or an +* empty-content assistant/message (which exists only to host usage). This is +* THE per-node projection rule: `Session.deriveMessages` folds it over the +* live surface, external reconstructors and pure projections fold the same +* function over a log prefix's surface to rebuild the exact messages any +* request was built from. The returned message is the already frozen message +* nested in the event wrapper and shared by delivery, durable history, and +* model requests. +* @param event - the event to project. +* @returns the derived message, or null when the event produces none. +*/ +function deriveEventMessage(event) { + switch (event.type) { + case "user/message": return event.data; + case "assistant/message": + if (event.data.message.content.length === 0) return null; + return event.data.message; + case "tool/result": return event.data.message; + default: return null; + } +} +/** Create an empty surface fold state. */ +function createFoldState() { + return { + nodes: [], + replaceGeneration: 0 + }; +} +/** Whether a runtime value is a non-negative safe event sequence. */ +function isEventSeq(value) { + return typeof value === "number" && Number.isSafeInteger(value) && value >= 0; +} +/** Whether a runtime value is the exact positional-replacement shape. */ +function isReplaceOp(value) { + const op = value; + return Object.keys(op).length === 3 && Object.hasOwn(op, "op") && Object.hasOwn(op, "start") && Object.hasOwn(op, "end") && op["op"] === "replace" && isEventSeq(op["start"]) && isEventSeq(op["end"]); +} +/** Validate event-local surface eligibility and return its operation. */ +function surfaceOpOf(event) { + const raw = event; + if (!isSurfaceEligibleType(event.type)) { + if (raw.surfaceOp !== void 0) throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry surfaceOp`); + if (raw.sourceEventSeqs !== void 0) throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry sourceEventSeqs`); + return; + } + const op = raw.surfaceOp; + if (op === void 0) throw new Error(`session event "${event.type}" is surface-eligible and requires a surfaceOp marker`); + if (op === "append") return op; + if (op === null || typeof op !== "object" || Array.isArray(op)) throw new Error(`session event "${event.type}" carries an invalid surfaceOp`); + if (!isReplaceOp(op)) throw new Error(`session event "${event.type}" carries an invalid replace surfaceOp`); + return op; +} +/** Validate cited source-event seqs against prior log entries and the replacement range. */ +function assertProvenance(event, shadowedSeqs) { + const raw = event.sourceEventSeqs; + const sources = /* @__PURE__ */ new Set(); + if (raw !== void 0) { + if (!Array.isArray(raw)) throw new Error(`sourceEventSeqs on event at seq ${event.seq} must be an array when present`); + if (raw.length === 0 && event.type !== "assistant/message") throw new Error("sourceEventSeqs must not be empty except on assistant/message"); + let nonEarlierSource; + for (const source of raw) { + if (!isEventSeq(source)) throw new Error(`session event "${event.type}" sourceEventSeqs must densely contain non-negative safe integers`); + sources.add(source); + if (nonEarlierSource === void 0 && source >= event.seq) nonEarlierSource = source; + } + if (sources.size !== raw.length) throw new Error("sourceEventSeqs must not contain duplicates"); + if (nonEarlierSource !== void 0) throw new Error(`sourceEventSeqs must reference earlier events: ${nonEarlierSource} >= current seq ${event.seq}`); + } + const missing = shadowedSeqs.filter((seq) => !sources.has(seq)); + if (missing.length > 0) throw new Error(`surface replace: sourceEventSeqs must include every shadowed surface node; missing ${missing.join(", ")}`); +} +/** Locate one replacement range without mutating the current fold state. */ +function replacementRange(state, op) { + const startIdx = state.nodes.indexOf(op.start); + if (startIdx === -1) throw new Error(`surface replace: start seq ${op.start} not found in surface`); + const endIdx = state.nodes.indexOf(op.end); + if (endIdx === -1) throw new Error(`surface replace: end seq ${op.end} not found in surface`); + if (startIdx > endIdx) throw new Error(`surface replace: start seq ${op.start} (index ${startIdx}) is after end seq ${op.end} (index ${endIdx})`); + return { + startIdx, + endIdx, + shadowedSeqs: state.nodes.slice(startIdx, endIdx + 1) + }; +} +/** +* Deep structural equality over the session-event JSON value domain +* (null/boolean/number/string, arrays, plain objects). Replaces +* `node:util`'s isDeepStrictEqual to keep this module browser-safe. +*/ +function isDeepEqualJson(a, b) { + if (a === b) return true; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false; + return a.every((item, i) => isDeepEqualJson(item, b[i])); + } + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false; + const aKeys = Object.keys(a); + const bRecord = b; + if (aKeys.length !== Object.keys(b).length) return false; + return aKeys.every((key) => Object.hasOwn(b, key) && isDeepEqualJson(a[key], bRecord[key])); +} +/** Restrict a tool-result replacement to one current result's content. */ +function assertToolResultRewrite(event, shadowedSeqs, events, baseSeq) { + if (event.type !== "tool/result") return; + if (shadowedSeqs.length !== 1) throw new Error("tool/result surface replacement must rewrite exactly one current node"); + for (const originalSeq of shadowedSeqs) { + const original = events[originalSeq - baseSeq]; + if (original?.type !== "tool/result") throw new Error("tool/result surface replacement must target a current tool/result"); + const originalRest = { ...original.data }; + const replacementRest = { ...event.data }; + const originalResult = original.data.message.content[0]; + const replacementResult = event.data.message.content[0]; + originalRest["message"] = { + ...original.data.message, + content: [{ + ...originalResult, + content: null + }] + }; + replacementRest["message"] = { + ...event.data.message, + content: [{ + ...replacementResult, + content: null + }] + }; + if (!isDeepEqualJson(originalRest, replacementRest)) throw new Error("tool/result surface replacement may change only content"); + } +} +/** Validate one event at its replay boundary and prepare its atomic fold transition. */ +function planSurfaceEvent(state, event, expectedSeq, events, baseSeq) { + if (event.seq !== expectedSeq) throw new Error(`session event seq ${event.seq} is not contiguous; expected ${expectedSeq}`); + const surfaceOp = surfaceOpOf(event); + if (surfaceOp === void 0) return; + if (surfaceOp === "append") { + assertProvenance(event, []); + return { + kind: "append", + seq: event.seq + }; + } + const range = replacementRange(state, surfaceOp); + assertProvenance(event, range.shadowedSeqs); + assertToolResultRewrite(event, range.shadowedSeqs, events, baseSeq); + return { + kind: "replace", + seq: event.seq, + start: surfaceOp.start, + end: surfaceOp.end, + ...range + }; +} +/** Apply one event and return replacement metadata only when one occurred. */ +function applySurfaceEvent(state, event, expectedSeq, events, baseSeq) { + return applySurfacePlan(state, planSurfaceEvent(state, event, expectedSeq, events, baseSeq)); +} +/** Commit one previously validated surface transition. */ +function applySurfacePlan(state, plan) { + if (plan?.kind === "append") state.nodes.push(plan.seq); + else if (plan?.kind === "replace") { + state.nodes.splice(plan.startIdx, plan.endIdx - plan.startIdx + 1, plan.seq); + state.replaceGeneration += 1; + } + if (plan?.kind !== "replace") return; + return { + seq: plan.seq, + start: plan.start, + end: plan.end, + shadowedSeqs: plan.shadowedSeqs + }; +} +/** +* Replay a complete session log through the canonical surface fold. +* @param events - session events in contiguous seq order. +* @returns detached current sequences and replacement history. +* @throws when an event violates surface metadata, source-event references, range, or tool-result rewrite rules. +*/ +function foldSurface(events) { + const state = createFoldState(); + const replacements = []; + for (const [index, event] of events.entries()) { + const replacement = applySurfaceEvent(state, event, index, events, 0); + if (replacement !== void 0) replacements.push(replacement); + } + return { + nodes: [...state.nodes], + replacements + }; +} +/** Incremental ordered surface view and append-boundary validator. */ +var SurfaceManager = class { + log; + baseSeq; + /** Shared transition state; replacement history is not retained. */ + _state = createFoldState(); + /** Last processed absolute seq. */ + _lastProcessedSeq; + /** Candidate already validated by `validateNext`, pending exact log admission. */ + _pendingPlan; + /** + * @param log - Contiguous complete log or loaded event window. + * @param baseSeq - Absolute sequence of the window's first event. + */ + constructor(log, baseSeq = 0) { + this.log = log; + this.baseSeq = baseSeq; + this._lastProcessedSeq = baseSeq - 1; + } + /** + * Validate the next candidate without mutating the committed surface. + * @param event - candidate event that has not entered the log yet. + */ + validateNext(event) { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta(); + const expectedSeq = this.baseSeq + this.log.length; + this._pendingPlan = { + event, + expectedSeq, + plan: planSurfaceEvent(this._state, event, expectedSeq, this.log, this.baseSeq) + }; + } + /** Monotonic count of folded positional replacements. */ + get replaceGeneration() { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta(); + return this._state.replaceGeneration; + } + /** Surface event sequences in model-visible order. */ + get nodes() { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta(); + return this._state.nodes; + } + /** Fold events appended since the previous access. */ + _processDelta() { + const tailSeq = this.baseSeq + this.log.length - 1; + for (let seq = this._lastProcessedSeq + 1; seq <= tailSeq; seq++) { + const index = seq - this.baseSeq; + const event = this.log[index]; + const pending = this._pendingPlan; + if (pending?.event === event && pending.expectedSeq === seq) applySurfacePlan(this._state, pending.plan); + else applySurfaceEvent(this._state, event, seq, this.log, this.baseSeq); + if (pending !== void 0 && pending.expectedSeq <= seq) this._pendingPlan = void 0; + this._lastProcessedSeq = seq; + } + } +}; +//#endregion +//#region lib/types/request-header.js +/** +* Request-header reconstruction utilities over full `request/header` session +* events. Anyone holding a session log reconstructs the {@link EpochHeader} +* any request was built under by taking the latest canonical snapshot; the +* loop uses the same equality helper to avoid logging unchanged headers. +* +* @module dsh-session/request-header +*/ +/** +* Normalize a header to canonical form: an empty system prompt and empty tool +* list become absent fields, matching how requests are built. Logging, folding, +* and comparison use this one representation. +* @param header - the header to normalize (not mutated). +* @returns the canonical header. +*/ +function canonicalHeader(header) { + const adapterDefaults = header.adapterDefaults; + return { + config: header.config, + ...adapterDefaults?.reasoningEffort === true || adapterDefaults?.maxTokens === true ? { adapterDefaults } : {}, + ...header.system !== void 0 && header.system.length > 0 ? { system: header.system } : {}, + ...header.tools !== void 0 && header.tools.length > 0 ? { tools: header.tools } : {} + }; +} +/** Canonical JSON equality for tool schemas assembled through the same path. */ +function sameSchema(a, b) { + return JSON.stringify(a) === JSON.stringify(b); +} +/** +* Field-wise equality over canonical headers. Tool schemas compare in order. +* @param a - one canonical header. +* @param b - the other. +* @returns whether config, system, and tools all match. +*/ +function headerEquals(a, b) { + if (!callConfigEquals(a.config, b.config) || a.adapterDefaults?.reasoningEffort !== b.adapterDefaults?.reasoningEffort || a.adapterDefaults?.maxTokens !== b.adapterDefaults?.maxTokens || a.system !== b.system) return false; + const at = a.tools ?? []; + const bt = b.tools ?? []; + return at.length === bt.length && at.every((tool, i) => sameSchema(tool, bt[i])); +} +/** +* Fold the header events of a log (or any prefix) into the +* {@link EpochHeader} in force after the last snapshot. Non-header events are +* skipped. This is the pure offline reconstruction path; the live session +* tracks the same fold incrementally. +* @param events - session events in log order. +* @param from - a previously folded state to continue from. +* @returns the latest canonical header, or undefined when none exists yet. +*/ +function foldRequestHeader(events, from) { + let state = from; + for (const event of events) if (event.type === "request/header") state = canonicalHeader(event.data.header); + return state; +} +//#endregion +//#region lib/types/preparation.js +/** +* Ownership of one unpublished Session before registry publication. +* @module @deepseek-ai/dsh-session/preparation +*/ +/** +* One exact unpublished Session and the provider state that keeps it usable. +* Disposal is synchronous and idempotent. Providers decide whether release +* returns the Session to a cache or discards it; publication may consume that +* state before disposal, making the callback a no-op. +*/ +var SessionPreparation = class SessionPreparation { + options; + released = false; + /** The exact Session to use for setup and publication. */ + session; + constructor(session, options) { + this.options = options; + this.session = session; + } + /** + * Wrap an unpublished Session in one preparation lifetime. + * @param session - exact unpublished Session. + * @param options - optional provider release behavior. + * @returns a preparation disposed after publication or rollback. + */ + static create(session, options) { + return new SessionPreparation(session, options ?? {}); + } + /** Release provider state once when this preparation leaves its caller. */ + [Symbol.dispose]() { + if (this.released) return; + this.released = true; + this.options.release?.(); + } +}; +//#endregion +//#region lib/types/repair.js +/** +* Crash-recovery repair for an interrupted session log. It preserves a fully +* written final turn and supplies the missing tool, step, and turn boundaries +* needed to resume with a provider-valid transcript. +* @module @deepseek-ai/dsh-session/repair +*/ +/** Recovery code for an assistant tool request that never reached a recorded call start. */ +const TOOL_NOT_STARTED = "TOOL_NOT_STARTED"; +/** Recovery code for a recorded tool call whose completed outcome was not durably recorded. */ +const TOOL_OUTCOME_UNKNOWN = "TOOL_OUTCOME_UNKNOWN"; +/** +* Return deterministic synthetic events that close an open tail turn. Unmatched +* calls receive error results first, followed by an open `step/end` and an +* interrupted `turn/end`; sequences continue the log and timestamps reuse the +* last real event. A balanced or empty log returns no events. +* +* @param events - the loaded durable log to scan (a valid committed prefix, possibly with a crash tail). +* @returns the synthetic closer events to append after `events`, in order; empty when the log is already balanced. +*/ +function interruptedTurnClosers(events) { + let openTurn = null; + let openStep = null; + const pendingCalls = /* @__PURE__ */ new Map(); + for (const event of events) switch (event.type) { + case "turn/start": + openTurn = event.data.turn; + openStep = null; + pendingCalls.clear(); + break; + case "turn/end": + openTurn = null; + openStep = null; + pendingCalls.clear(); + break; + case "step/start": + openStep = event.data.step; + break; + case "step/end": + pendingCalls.clear(); + openStep = null; + break; + case "assistant/message": + for (const block of event.data.message.content) if (block.type === "tool-call") pendingCalls.set(block.id, { step: event.data.step }); + break; + case "tool/call": + { + const entry = pendingCalls.get(event.data.callId); + if (entry) entry.callSeq = event.seq; + } + break; + case "tool/result": + pendingCalls.delete(event.data.message.source.callId); + break; + default: break; + } + const last = events.at(-1); + if (openTurn === null || last === void 0) return []; + let seq = last.seq + 1; + const time = last.time; + const closers = []; + for (const [callId, { step, callSeq }] of pendingCalls) { + const started = callSeq !== void 0; + const message = freezeMessage({ + id: MessageId(`interrupted-tool-result-${callId}-${seq}`), + role: "user", + source: { + kind: "tool", + callId + }, + content: [{ + type: "tool-result", + toolCallId: callId, + isError: true, + content: [{ + type: "text", + text: started ? "The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly." : "The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed." + }] + }] + }); + closers.push({ + type: "tool/result", + seq: seq++, + time, + data: { + turn: openTurn, + step, + message, + error: started ? { + name: "ToolOutcomeUnknownError", + code: TOOL_OUTCOME_UNKNOWN + } : { + name: "ToolNotStartedError", + code: TOOL_NOT_STARTED + } + }, + surfaceOp: "append", + ...started ? { sourceEventSeqs: [callSeq] } : {} + }); + } + if (openStep !== null) closers.push({ + type: "step/end", + seq: seq++, + time, + data: { + turn: openTurn, + step: openStep + } + }); + closers.push({ + type: "turn/end", + seq: seq++, + time, + data: { + turn: openTurn, + reason: { kind: "interrupted" } + } + }); + return closers; +} +//#endregion +//#region lib/types/chunk-rows.js +/** +* Lossless storage packing for `assistant/chunk` delta runs. Providers stream +* token-sized deltas, so a log stores hundreds of near-identical event lines +* whose JSON envelopes dwarf their payloads (~56× measured on a real DeepSeek +* session). This module packs each run of consecutive same-block delta chunks +* into ONE storage row — `text-chunks`, `reasoning-chunks`, or +* `tool-call-chunks` — and expands rows back to the exact original events. +* +* Storage rows are a durable-encoding vocabulary, NOT session events: they +* never enter `Session.events`, have no `SessionEventMap` entry, and use bare +* (slash-less) type tags so a reader cannot confuse them with the event +* taxonomy (precedent: the JSONL header line's `session` tag). The encoder +* whitelists exact shapes — anything it does not fully recognize is stored +* verbatim, so unknown fields or future chunk variants lose compression, never +* data. The decoder validates before expanding and fails loud on a malformed +* row-tagged value instead of silently dropping a whole run. +* +* @module @deepseek-ai/dsh-session/chunk-rows +*/ +/** +* Minimum members before a run packs. Below it a row's envelope rivals the +* event lines it replaces. A format constant, not a tunable: both layouts +* decode identically, so changing it never invalidates stored logs. +*/ +const MIN_RUN = 3; +function isRecord(value) { + return typeof value === "object" && value !== null; +} +/** Exact-key check: `value` has every key in `keys` and nothing else. */ +function hasExactKeys(value, keys) { + return Object.keys(value).length === keys.length && keys.every((k) => Object.hasOwn(value, k)); +} +/** +* Classify an event for packing: its delta kind when the ENTIRE shape +* (envelope, data, chunk — exact keys, primitive types, integer seq/time) is +* whitelisted, else `undefined` (store verbatim). Inputs come from live typed +* appends AND parsed fixture files, so the checks are structural, not +* type-trusted. Integer times keep gap encoding exact: a fractional time would +* reconstruct through float subtraction/addition, which need not round-trip. +*/ +function classify(event) { + if (event.type !== "assistant/chunk") return void 0; + if (!hasExactKeys(event, [ + "type", + "seq", + "time", + "data" + ])) return void 0; + if (!Number.isSafeInteger(event.seq) || event.seq < 0 || !Number.isSafeInteger(event.time)) return void 0; + const data = event.data; + if (!isRecord(data) || !hasExactKeys(data, [ + "turn", + "step", + "chunk" + ])) return void 0; + if (typeof data.turn !== "number" || typeof data.step !== "number") return void 0; + const chunk = data.chunk; + if (!isRecord(chunk) || typeof chunk.index !== "number") return void 0; + switch (chunk.type) { + case "text-delta": + case "reasoning-delta": return hasExactKeys(chunk, [ + "type", + "index", + "text" + ]) && typeof chunk.text === "string" ? chunk.type : void 0; + case "tool-call-delta": return (hasExactKeys(chunk, [ + "type", + "index", + "id", + "argumentsDelta" + ]) || hasExactKeys(chunk, [ + "type", + "index", + "id", + "name", + "argumentsDelta" + ]) && typeof chunk.name === "string") && typeof chunk.id === "string" && typeof chunk.argumentsDelta === "string" ? chunk.type : void 0; + default: return; + } +} +/** The tool-call fields of a whitelisted delta chunk (only after {@link classify} returned `'tool-call-delta'`). */ +function toolCallOf(event) { + return event.data.chunk; +} +/** The block index of a whitelisted delta chunk (not every {@link StreamChunk} variant carries one). */ +function indexOf(event) { + return event.data.chunk.index; +} +/** Whether `next` extends a run ending in `prev` (same kind already checked by the caller). */ +function continues(prev, next, kind) { + if (next.seq !== prev.seq + 1) return false; + if (!Number.isSafeInteger(next.time - prev.time)) return false; + if (next.data.turn !== prev.data.turn || next.data.step !== prev.data.step) return false; + if (indexOf(next) !== indexOf(prev)) return false; + if (kind !== "tool-call-delta") return true; + const a = toolCallOf(prev); + const b = toolCallOf(next); + return a.id === b.id && Object.hasOwn(a, "name") === Object.hasOwn(b, "name") && a.name === b.name; +} +/** Build the row for a completed run (`run.length >= MIN_RUN`, uniform per {@link continues}). */ +function buildRow(kind, run) { + const first = run[0]; + const base = { + turn: first.data.turn, + step: first.data.step, + index: indexOf(first), + dt: run.slice(1).map((event, i) => event.time - run[i].time) + }; + const envelope = { + seq0: first.seq, + time0: first.time + }; + if (kind === "tool-call-delta") { + const call = toolCallOf(first); + return { + type: "tool-call-chunks", + ...envelope, + data: { + ...base, + id: CallId(call.id), + ...Object.hasOwn(call, "name") ? { name: call.name } : {}, + args: run.map((event) => event.data.chunk.argumentsDelta) + } + }; + } + const data = { + ...base, + texts: run.map((event) => event.data.chunk.text) + }; + return kind === "text-delta" ? { + type: "text-chunks", + ...envelope, + data + } : { + type: "reasoning-chunks", + ...envelope, + data + }; +} +/** +* Pack an event batch for storage: each run of at least {@link MIN_RUN} +* consecutive whitelisted same-kind, same-block delta chunk events becomes one +* {@link ChunkRow}; every other event passes through verbatim, in order. +* Pure and stateless — safe over any array, including a batch whose runs were +* split by flush boundaries (the split runs simply pack per batch). +* +* @param events - the batch to encode, in log order. +* @returns the storage records to write, one JSONL line each. +*/ +function packChunkRuns(events) { + const out = []; + let kind; + let run = []; + const flush = () => { + if (kind !== void 0 && run.length >= MIN_RUN) out.push(buildRow(kind, run)); + else out.push(...run); + kind = void 0; + run = []; + }; + for (const event of events) { + const k = classify(event); + if (k === void 0) { + flush(); + out.push(event); + continue; + } + const delta = event; + const last = run[run.length - 1]; + if (k === kind && last !== void 0 && continues(last, delta, k)) { + run.push(delta); + continue; + } + flush(); + kind = k; + run = [delta]; + } + flush(); + return out; +} +/** Throw the uniform malformed-row diagnostic. */ +function malformed(tag, why) { + throw new Error(`malformed ${tag} storage row: ${why}`); +} +/** Validate the shared run-data fields and the payload/dt arity; returns the member payload. */ +function validateRunData(tag, data, payloadKey) { + if (typeof data.turn !== "number" || typeof data.step !== "number" || typeof data.index !== "number") malformed(tag, "turn/step/index must be numbers"); + const payload = data[payloadKey]; + if (!Array.isArray(payload) || payload.length === 0 || payload.some((entry) => typeof entry !== "string")) malformed(tag, `${payloadKey} must be a non-empty string array`); + const dt = data.dt; + if (!Array.isArray(dt) || dt.some((gap) => !Number.isSafeInteger(gap))) malformed(tag, "dt must be an array of safe integers"); + if (dt.length !== payload.length - 1) malformed(tag, `dt length ${dt.length} does not match ${payload.length} members`); + return payload; +} +/** Validate a row-tagged parsed value's envelope and data, throwing on any malformation. */ +function validateRow(value, tag) { + if (!hasExactKeys(value, [ + "type", + "seq0", + "time0", + "data" + ])) malformed(tag, "envelope must be exactly {type, seq0, time0, data}"); + if (!Number.isSafeInteger(value.seq0) || value.seq0 < 0) malformed(tag, "seq0 must be a non-negative safe integer"); + if (!Number.isSafeInteger(value.time0)) malformed(tag, "time0 must be a safe integer"); + const data = value.data; + if (!isRecord(data)) malformed(tag, "data must be an object"); + let payload; + if (tag === "tool-call-chunks") { + const withName = hasExactKeys(data, [ + "turn", + "step", + "index", + "id", + "name", + "dt", + "args" + ]); + if (!withName && !hasExactKeys(data, [ + "turn", + "step", + "index", + "id", + "dt", + "args" + ])) malformed(tag, "data must be exactly {turn, step, index, id, name?, dt, args}"); + if (typeof data.id !== "string" || withName && typeof data.name !== "string") malformed(tag, "id (and name when present) must be strings"); + payload = validateRunData(tag, data, "args"); + } else { + if (!hasExactKeys(data, [ + "turn", + "step", + "index", + "dt", + "texts" + ])) malformed(tag, "data must be exactly {turn, step, index, dt, texts}"); + payload = validateRunData(tag, data, "texts"); + } + if (!Number.isSafeInteger(value.seq0 + payload.length - 1)) malformed(tag, "member seqs must stay safe integers"); + let time = value.time0; + for (const gap of data.dt) { + time += gap; + if (!Number.isSafeInteger(time)) malformed(tag, "member times must stay safe integers"); + } + return value; +} +/** Expand a validated row back into its exact original events, in order. */ +function expandRow(row) { + const members = row.type === "tool-call-chunks" ? row.data.args : row.data.texts; + const events = []; + let time = row.time0; + for (let k = 0; k < members.length; k++) { + if (k > 0) time += row.data.dt[k - 1]; + let chunk; + switch (row.type) { + case "text-chunks": + chunk = { + type: "text-delta", + index: row.data.index, + text: members[k] + }; + break; + case "reasoning-chunks": + chunk = { + type: "reasoning-delta", + index: row.data.index, + text: members[k] + }; + break; + case "tool-call-chunks": + chunk = { + type: "tool-call-delta", + index: row.data.index, + id: row.data.id, + ...Object.hasOwn(row.data, "name") ? { name: row.data.name } : {}, + argumentsDelta: members[k] + }; + break; + /* v8 ignore next 2 -- validateRow only returns the three row tags */ + default: return assertNever(row, "chunk-rows expandRow"); + } + events.push({ + type: "assistant/chunk", + seq: row.seq0 + k, + time, + data: { + turn: row.data.turn, + step: row.data.step, + chunk + } + }); + } + return events; +} +/** +* Decode one parsed JSONL line value into the session event(s) it stores. +* Chunk-row-tagged values validate and expand (a malformed row throws — it is +* corrupt storage, and treating it as an event would silently drop a whole +* run); every other value passes through as a single event, unvalidated. +* +* @param value - one line's `JSON.parse` result. +* @returns the stored events, in log order. +*/ +function decodeStorageRecord(value) { + if (!isRecord(value)) return [value]; + const tag = value.type; + if (tag !== "text-chunks" && tag !== "reasoning-chunks" && tag !== "tool-call-chunks") return [value]; + return expandRow(validateRow(value, tag)); +} +//#endregion +//#region lib/types/known-event-types.js +/** +* GENERATED by `scripts/gen-persistence-catalog.ts` — do not edit by hand; run +* `pnpm run gen-persistence-catalog` to regenerate (verified fresh by +* `pnpm run verify-persistence-catalog`, part of `doc-sync`). +* @module @deepseek-ai/dsh-session/known-event-types +*/ +/** +* Every `SessionEventMap` member declared in this repository — the event +* vocabulary this build understands. The persistence read path refuses to +* interpret a log containing a type outside this set unless the event +* carries the envelope's `ignorable` marker (see `SessionEvent.ignorable` +* in `./types.ts`): such a log was likely written by a newer harness, and +* silently skipping a required event would reconstruct a wrong session. +* Downstream (out-of-repo) plugin events are outside this list by +* construction; a registration surface for them is deferred until such a +* consumer exists. +*/ +const KNOWN_SESSION_EVENT_TYPES = new Set([ + "agent-preset/selected", + "agent/inbox/spliced", + "approval/asked", + "approval/decided", + "approval/policy", + "assistant/chunk", + "assistant/message", + "command/done", + "command/run", + "compaction/end", + "compaction/prune", + "compaction/start", + "compaction/summary", + "feedback/record", + "goal/change", + "hook/invoked", + "hook/result", + "llm/retry", + "llm/retry-started", + "permission/preset", + "plan/mode", + "request/context", + "request/header", + "sandbox/mode", + "schedule/change", + "session/end-seed", + "session/title", + "session/title-llm-request", + "step/end", + "step/start", + "subagent/descriptor", + "todo/write", + "tool-workflow/agent-end", + "tool-workflow/agent-start", + "tool-workflow/run-end", + "tool-workflow/run-start", + "tool/call", + "tool/code-dispatch", + "tool/code-dispatch-start", + "tool/result", + "turn/end", + "turn/start", + "user/message", + "web/deepseek-search-llm-request" +]); +//#endregion +//#region lib/types/index.js +/** +* Event-sourced session service: append-only session log, in-memory store, and +* the derived LLM message history. Persistence is a plugin concern (subscribe +* to `session/event`, drain on `session/flush`). +* +* @module @deepseek-ai/dsh-session +*/ +/** Validate and freeze one detached creation header in place. */ +function validateSessionHeader(id, input) { + if (input === null || typeof input !== "object" || Array.isArray(input)) throw new Error("session header is not a plain JSON record"); + const record = input; + if (record.version !== 0) throw new Error(`session header version must be 0, got ${String(record.version)}`); + if (record.id !== id) throw new Error(`session header id "${String(record.id)}" does not match session id "${id}"`); + if (typeof record.createdAt !== "number" || !Number.isSafeInteger(record.createdAt) || record.createdAt < 0) throw new Error("session header createdAt must be a non-negative safe integer"); + if (record.cwd !== void 0) { + if (typeof record.cwd !== "string") throw new Error("session header cwd must be a string"); + if (!isAbsolute(record.cwd)) throw new Error(`session header cwd must be an absolute path, got "${record.cwd}"`); + } + if (record.parentSession !== void 0 && typeof record.parentSession !== "string") throw new Error("session header parentSession must be a string"); + if (record.seedLength !== void 0 && (typeof record.seedLength !== "number" || !Number.isSafeInteger(record.seedLength) || record.seedLength < 0)) throw new Error("session header seedLength must be a non-negative safe integer"); + if (record.origin !== void 0 && record.origin !== "subagent") throw new Error("session header origin must be \"subagent\""); + if (record.delegationDepth !== void 0 && (typeof record.delegationDepth !== "number" || !Number.isSafeInteger(record.delegationDepth) || record.delegationDepth < 0)) throw new Error("session header delegationDepth must be a non-negative safe integer"); + if (record.agentPreset !== void 0 && typeof record.agentPreset !== "string") throw new Error("session header agentPreset must be a string"); + return deepFreeze(record); +} +/** Validate and freeze one exclusively owned persistence header in place. */ +function validateRestoredSessionHeader(id, input) { + if (input !== null && typeof input === "object" && !Array.isArray(input)) { + const prototype = Reflect.getPrototypeOf(input); + if (prototype !== Object.prototype && prototype !== null) throw new Error("session header is not a plain JSON record"); + } + return validateSessionHeader(id, input); +} +/** Detach, validate, and freeze the creation metadata published by a session. */ +function snapshotSessionHeader(id, source) { + const snapshot = snapshotJsonValue(source === void 0 ? { + version: 0, + id, + createdAt: Date.now() + } : source); + if (snapshot === void 0) throw new Error("session header is not losslessly JSON-serializable"); + return validateSessionHeader(id, snapshot); +} +/** +* Validate an exclusively owned event and deeply freeze its identified message +* without copying the event. The caller transfers an object graph that no +* producer retains and that shares no mutable children with another event. +* Use {@link snapshotSessionEvent} when exclusive ownership is not guaranteed. +* @param event - exclusively owned event imported across a trusted boundary. +* @returns the same event object with a validated, deeply frozen message. +*/ +function adoptSessionEvent(event) { + assertMessageEventShape(event, `session event at seq ${event.seq}`); + switch (event.type) { + case "user/message": + deepFreeze(event.data); + break; + case "assistant/message": + case "tool/result": + deepFreeze(event.data.message); + break; + default: break; + } + return event; +} +/** +* Detach one event while preserving deep immutability for its identified message. +* @param event - event imported across a query or persistence boundary. +* @returns a detached event snapshot with a validated, deeply frozen message. +*/ +function snapshotSessionEvent(event) { + return adoptSessionEvent(structuredClone(event)); +} +/** Deep-freeze one acyclic JSON tree without consuming the JavaScript call stack. */ +function freezeRestoredObject(value) { + const pending = [value]; + while (pending.length > 0) { + const current = pending.pop(); + Object.freeze(current); + for (const key in current) { + const child = current[key]; + if (child !== null && typeof child === "object") pending.push(child); + } + } + return value; +} +/** Validate the fixed event envelope after one-pass JSON materialization. */ +function assertSessionEventEnvelope(value, index) { + const event = value; + if (event["type"] === "request/header-delta") throw new Error(`seed event at index ${index} uses unsupported legacy request/header-delta format`); + for (const key in event) switch (key) { + case "type": + case "seq": + case "time": + case "data": + case "surfaceOp": + case "sourceEventSeqs": + case "ignorable": break; + default: throw new Error(`seed event at index ${index} has an invalid event envelope`); + } + const type = event["type"]; + const seq = event["seq"]; + const time = event["time"]; + if (typeof type !== "string" || typeof seq !== "number" || !Number.isSafeInteger(seq) || seq < 0 || typeof time !== "number" || !Number.isSafeInteger(time) || event["data"] === void 0 || event["ignorable"] !== void 0 && event["ignorable"] !== true) throw new Error(`seed event at index ${index} has an invalid event envelope`); + switch (type) { + case "request/header": + case "user/message": + case "assistant/message": + case "tool/result": + assertCurrentLlmShape(event, index); + break; + } +} +/** Reject obsolete request headers and malformed messages at the seed/load boundary. */ +function assertCurrentLlmShape(event, index) { + const data = event["data"]; + const record = typeof data === "object" && data !== null ? data : void 0; + if (event["type"] === "request/header") { + const header = record?.["header"]; + const headerRecord = typeof header === "object" && header !== null && !Array.isArray(header) ? header : void 0; + const config = headerRecord?.["config"]; + if (!hasProviderModel(config)) throw new Error(`seed request/header at index ${index} lacks provider/model`); + const configRecord = config; + const reasoningEffort = configRecord["reasoningEffort"]; + if (reasoningEffort !== void 0 && (typeof reasoningEffort !== "string" || reasoningEffort.length === 0)) throw new Error(`seed request/header at index ${index} has an invalid reasoningEffort`); + assertAdapterDefaults(headerRecord?.["adapterDefaults"], configRecord, index); + } + const type = event["type"]; + if (type !== "user/message" && type !== "assistant/message" && type !== "tool/result") return; + assertMessageEventShape(event, `seed ${type} at index ${index}`); +} +const allowedAdapterKeys = new Set(["reasoningEffort", "maxTokens"]); +/** Validate adapter-default markers imported from a durable request header. */ +function assertAdapterDefaults(value, config, index) { + if (value === void 0) return; + if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`seed request/header at index ${index} has invalid adapterDefaults`); + const defaults = value; + if (Object.keys(defaults).some((key) => !allowedAdapterKeys.has(key)) || Object.values(defaults).some((marker) => marker !== true) || defaults["reasoningEffort"] === true && config["reasoningEffort"] === void 0 || defaults["maxTokens"] === true && config["maxTokens"] === void 0) throw new Error(`seed request/header at index ${index} has invalid adapterDefaults`); +} +/** Validate only the event-specific invariants needed to safely replay a message. */ +function assertMessageEventShape(event, subject) { + const type = event["type"]; + if (type !== "user/message" && type !== "assistant/message" && type !== "tool/result") return; + const data = event["data"]; + const record = typeof data === "object" && data !== null ? data : void 0; + const message = type === "user/message" ? record : record?.["message"]; + if (typeof message !== "object" || message === null || typeof message["id"] !== "string" || message["id"] === "") throw new Error(`${subject} lacks an identified message`); + const messageRecord = message; + const expectedRole = type === "assistant/message" ? "assistant" : "user"; + if (messageRecord["role"] !== expectedRole) throw new Error(`${subject} message must have role "${expectedRole}"`); + const source = messageRecord["source"]; + if (typeof source !== "object" || source === null || typeof source["kind"] !== "string" || source["kind"] === "") throw new Error(`${subject} message has invalid source`); + if (!Array.isArray(messageRecord["content"])) throw new Error(`${subject} message has invalid content`); + const sourceRecord = source; + if (type === "assistant/message") { + if (sourceRecord["kind"] !== "model" || !hasProviderModel(sourceRecord)) throw new Error(`${subject} message must have model source`); + return; + } + if (type !== "tool/result") return; + if (sourceRecord["kind"] !== "tool" || typeof sourceRecord["callId"] !== "string" || sourceRecord["callId"] === "") throw new Error(`${subject} message must have tool source`); + const content = messageRecord["content"]; + const block = content[0]; + if (content.length !== 1 || typeof block !== "object" || block === null || block["type"] !== "tool-result" || !Array.isArray(block["content"])) throw new Error(`${subject} message must contain one tool-result block`); + if (block["toolCallId"] !== sourceRecord["callId"]) throw new Error(`${subject} message has mismatched tool call ids`); +} +/** Whether an unknown value carries the current provider/model pair. */ +function hasProviderModel(value) { + if (typeof value !== "object" || value === null) return false; + const pair = value; + return typeof pair["provider"] === "string" && pair["provider"].length > 0 && typeof pair["model"] === "string" && pair["model"].length > 0; +} +/** Reject request-header vocabulary removed with the legacy delta codec. */ +function assertSupportedRequestHeader(type, data, location) { + if (type === "request/header-delta") throw new Error(`${location} uses unsupported legacy request/header-delta format`); + if (type === "request/header" && data !== null && typeof data === "object" && !Array.isArray(data) && data["reason"] === "fallback") throw new Error(`${location} uses unsupported legacy request/header reason "fallback"`); +} +/** Resolve one listener snapshot, including Cordis's internal dispatch checks. */ +function collectSessionCallbacks(ctx, args) { + return [...ctx.events.dispatch("emit", args)]; +} +/** Invoke one resolved observe-only listener snapshot with per-listener containment. */ +function invokeContainedSessionObservers(ctx, name, id, args, callbacks) { + for (const callback of callbacks) try { + const returned = callback(...args); + Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`session "${id}": ${name} listener rejected: ${String(error)}`); + }); + } catch (error) { + ctx.logger.warn(`session "${id}": ${name} listener threw: ${String(error)}`); + } +} +/** Store attachment for the append path; module-private to keep Session store-agnostic publicly. */ +const attachments = /* @__PURE__ */ new WeakMap(); +/** +* An event-sourced session: an append-only log of {@link SessionEvent}s. +* +* Plain class (not a Service) — create live instances via +* `ctx.sessions.create()` and detached instances via {@link create}. +* Seeding with an existing event log replays/forks a session. +* @typert object +*/ +var Session = class Session { + log = []; + /** Single incremental owner of surface acceptance and projection state. */ + surfaceManager = new SurfaceManager(this.log); + /** The ordered surface over this session's event log. */ + get surface() { + return this.surfaceManager; + } + /** + * Detached, deep-frozen creation metadata (format version, cwd, lineage, + * seed boundary). Supplied by the store via `ctx.sessions.create()`. When a + * `Session` is created without a store-owned header, a minimal header is + * synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so + * `session.header` is always present. Kept out of the event log — it is a + * storage concern, not replayable conversation state. + */ + header; + /** The session identity, derived from its durable header's single copy. */ + get id() { + return this.header.id; + } + /** + * The first seq appended IN THIS PROCESS: the length of the constructor + * seed (0 without one). Events with smaller seq values entered through + * construction — replay, fork, or resume — and were never published on the + * `session/event` firehose (constructor seeds do not emit), so consumers + * that replay the log as a publication substitute (telemetry adoption) + * start here. Distinct from `header.seedLength`, the DURABLE fork-lineage + * boundary: a resumed session's constructor seed is its full stored log, + * while its header keeps the original fork value — this field is the + * in-process construction fact. + * + * Not persisted itself: a seeded session projects it into the log as the + * `session/end-seed` event, which is what a consumer reading STORED history + * reads. Locate the LAST such event, not necessarily one at this seq — a + * seed already ending in one is not re-marked, so reopening an untouched + * session leaves that event at a smaller seq than `firstLiveSeq`. Prefer + * this field in-process: it is exact before the marker reaches storage. + * + * When this lifecycle appends the marker, it occupies this seq before the + * store attaches and therefore does not publish either. Otherwise this seq + * holds an ordinary published write. + */ + firstLiveSeq; + /** + * Create a detached session by validating and snapshotting borrowed seed + * events and storage metadata. + * @param id - session identity. + * @param seed - optional borrowed replay or fork events. + * @param header - optional borrowed storage metadata. + * @returns a detached session. + */ + static create(id, seed, header) { + return new Session(id, seed, header); + } + /** + * Restore a detached session by taking ownership of fresh persistence values. + * The storage format, event envelopes, sequence continuity, surface transitions, + * and header fields are validated before the restored objects are frozen. + * @param id - restored session identity. + * @param seed - fresh detached events whose ownership is transferred. + * @param header - fresh detached metadata whose ownership is transferred. + * @returns a restored detached session. + */ + static fromRestore(id, seed, header) { + return new Session(id, seed, header, "restore"); + } + constructor(id, seed, header, mode = "snapshot") { + const restoredHeader = mode === "restore" ? validateRestoredSessionHeader(id, header) : void 0; + if (seed !== void 0) for (const [index, source] of seed.entries()) { + const snapshot = mode === "restore" ? source : snapshotJsonValue(source); + if (snapshot === void 0) throw new Error(`seed event at index ${index} is not losslessly JSON-serializable`); + assertSessionEventEnvelope(snapshot, index); + assertSupportedRequestHeader(snapshot.type, snapshot.data, `seed event at index ${index}`); + if (snapshot.seq !== index) throw new Error(`seed event at index ${index} has seq ${snapshot.seq} (expected ${index}); seed must be contiguous from 0`); + try { + this.surfaceManager.validateNext(snapshot); + } catch (error) { + throw new Error(`invalid seed event at index ${index}: ${error instanceof Error ? error.message : "invalid surface metadata"}`); + } + this.log.push(mode === "restore" ? freezeRestoredObject(snapshot) : deepFreeze(snapshot)); + } + this.firstLiveSeq = this.log.length; + this.header = restoredHeader ?? snapshotSessionHeader(id, header); + if (seed !== void 0 && this.log.at(-1)?.type !== "session/end-seed") this.append("session/end-seed", {}); + } + /** Cached immutable public snapshot of the private append-only log. */ + eventsSnapshot; + /** + * An immutable snapshot of the append-only event log. The snapshot is reused + * until the next append; a previously returned array does not grow later. + * Events and their nested data are deep-frozen at acceptance, so neither a + * cast nor ordinary JavaScript can rewrite durable history. + */ + get events() { + this.eventsSnapshot ??= Object.freeze([...this.log]); + return this.eventsSnapshot; + } + /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */ + get seq() { + return this.log.length; + } + /** + * Append one typed event to the log and synchronously notify observers via + * the store-owned, module-private publication hooks. The hot path never blocks + * on I/O — persistence plugins buffer asynchronously. Once the event enters + * the log, the append is committed: observer failures are logged and + * contained per listener, so they do not change the return value or prevent + * later listeners from observing the same accepted event. + * + * @param type - The event type (key of {@link SessionEventMap}). + * @param data - The event payload; must be JSON-serializable. + * @param opts - Surface metadata: `surfaceOp` controls how the event enters + * the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier + * events this one derives from. REQUIRED for + * {@link SurfaceEventType} events (every message-producing event must + * declare how it joins the surface, the sole source of derived model + * history) and + * rejected by the compiler for non-surface types like `turn/start` or + * `assistant/chunk`. + * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of + * `data` that entered the log, so reading `event.data` back sees the logged + * value, never the caller's still-mutable input. + * @throws if `data` or surface metadata is not losslessly JSON-serializable + * (BigInt, function, symbol, undefined, negative zero, non-finite number, + * circular reference, sparse array, or an exotic object such as + * Map/Set/Date/class instance), or when the candidate violates the + * canonical surface contract (marker shape and eligibility, unique + * earlier source-event references, positional replacement validity, and complete + * shadowed-node coverage). One recursive pass reads, validates, and + * copies each nested value once, so a stateful getter cannot supply one value + * to validation and another to storage. The event log is the durable source + * of truth, so a bad event fails at the append site rather than later during + * a backend flush. A synchronous internal dispatch validation failure or an + * append reentered while this acceptance/publication boundary is open also + * rejects before the log changes. + */ + append(type, data, ...opts) { + const surfaceOpts = opts[0]; + const surfaceMetadata = { + ...surfaceOpts?.sourceEventSeqs === void 0 ? {} : { sourceEventSeqs: surfaceOpts.sourceEventSeqs }, + ...surfaceOpts?.surfaceOp === void 0 ? {} : { surfaceOp: surfaceOpts.surfaceOp } + }; + const dataSnapshot = snapshotJsonValue(data); + if (dataSnapshot === void 0) throw new Error(`session event "${type}" carries non-JSON-serializable data`); + assertSupportedRequestHeader(type, dataSnapshot, `session event "${type}"`); + const surfaceMetadataSnapshot = snapshotJsonValue(surfaceMetadata); + if (surfaceMetadataSnapshot === void 0) throw new Error(`session event "${type}" carries non-JSON-serializable surface metadata`); + const entry = attachments.get(this); + if (entry?.appending) throw new Error("session append cannot reenter while another append is being published"); + const event = deepFreeze({ + type, + seq: this.log.length, + time: Date.now(), + data: dataSnapshot, + ...surfaceMetadataSnapshot + }); + this.surfaceManager.validateNext(event); + if (entry !== void 0) entry.appending = true; + try { + let callbacks; + const callbackArgs = [this, event]; + if (entry !== void 0) callbacks = collectSessionCallbacks(entry.emitCtx, [ + entry.carrier, + "session/event", + ...callbackArgs + ]); + this.log.push(event); + this.eventsSnapshot = void 0; + if (callbacks !== void 0 && entry !== void 0) invokeContainedSessionObservers(entry.emitCtx, "session/event", entry.id, callbackArgs, callbacks); + return event; + } finally { + if (entry !== void 0) { + entry.appending = false; + if (entry.detachRequested && !entry.announcing) entry.detach(); + } + } + } + /** Cached fold of the request-header events — see {@link requestHeader}. */ + headerFold; + /** Log position (events consumed) the header fold has reached. */ + headerFoldSeq = 0; + /** + * The {@link EpochHeader} in force after the log's last header event — the + * header the NEXT request will be compared against — or undefined before + * the first `request/header` snapshot. The live, incrementally-maintained + * form of `foldRequestHeader(session.events)`: each header event is folded + * once, when first seen, so a per-step read costs O(new events). + * @returns the folded header, or undefined when no header event exists yet. + */ + requestHeader() { + if (this.headerFoldSeq < this.log.length) { + this.headerFold = deepFreeze(foldRequestHeader(this.log.slice(this.headerFoldSeq), this.headerFold)); + this.headerFoldSeq = this.log.length; + } + return this.headerFold; + } + /** Cached fold of `request/context` events. */ + contextFold; + contextFoldSeq = 0; + /** + * Return the latest resolved route metadata, or `undefined` before the first + * `request/context` event. Each event is folded once. + * @returns the latest immutable route metadata. + */ + requestContext() { + if (this.contextFoldSeq < this.log.length) { + for (const event of this.log.slice(this.contextFoldSeq)) if (event.type === "request/context") this.contextFold = deepFreeze({ ...event.data }); + this.contextFoldSeq = this.log.length; + } + return this.contextFold; + } + /** The derived-message cache: frozen projections, extended per unseen node. */ + derived = []; + /** Surface position (nodes projected) the cache has reached. */ + derivedNodes = 0; + /** {@link SurfaceManager.replaceGeneration} the cache was built under. */ + derivedGeneration = 0; + /** + * Derive the LLM message history by walking the ordered sequences of + * message-producing events maintained by `surfaceOp` markers. The + * surface is the single source of derived history: every message-producing + * append records its `surfaceOp`, so a raw event with no marker (a chunk, a + * turn boundary) is correctly absent, and a compaction `replace` deletes the + * shadowed nodes from the derivation. The projection rules are + * {@link deriveEventMessage}, folded per node. + * + * CACHED: each surface node is projected exactly once, when first seen — a + * call costs O(new nodes), and a surface rewrite (a `replace`; + * {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is + * a fresh snapshot per call (later appends never grow an array a caller + * already holds); the `Message` objects in it are SHARED and **deep-frozen**. + * Their content reuses the already frozen durable event data, so the cache + * needs no second deep clone and consumers still cannot mutate the log. + * @returns a fresh array of the shared, frozen derived history. + */ + deriveMessages() { + const surface = this.surface; + const nodes = surface.nodes; + const generation = surface.replaceGeneration; + if (generation !== this.derivedGeneration) { + this.derived = []; + this.derivedNodes = 0; + this.derivedGeneration = generation; + } + for (const seq of nodes.slice(this.derivedNodes)) { + const msg = this.deriveEventMessage(this.log[seq]); + if (msg) this.derived.push(msg); + } + this.derivedNodes = nodes.length; + return [...this.derived]; + } + /** + * Instance face of the pure per-node `deriveEventMessage` export from + * `surface.ts`. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ + deriveEventMessage(event) { + return deriveEventMessage(event); + } +}; +/** Typed error for session fork rejections. */ +var SessionForkError = class extends Error { + code; + constructor(message, code) { + super(message); + this.code = code; + this.name = "SessionForkError"; + } +}; +/** +* In-memory session store (`ctx.sessions`). +* +* Persistence is intentionally not implemented here — persistence plugins +* subscribe to `session/event` and flush on `session/flush` / dispose. +*/ +var SessionStore = class extends Service { + store = /* @__PURE__ */ new Map(); + counter = 0; + constructor(ctx) { + super(ctx, "sessions"); + ctx.inject(["typert"], (typeCtx) => { + typeCtx.typert.lookups.register("session", { + parameter: "session", + wire: "sessionId", + hostTypeSymbol: "@deepseek-ai/dsh-session#Session", + wireTypeSymbol: "@deepseek-ai/dsh-session/types#SessionId", + resolve: (sessionId) => this.get(sessionId) + }); + }); + } + /** + * Create a session owned by the calling fiber: disposing that fiber stops + * event notification and removes the session from the store. `options.seed` + * populates the session with a copy of those events (replay/fork); + * `options.meta` attaches creation metadata (validated absolute `cwd`, seed + * and parent lineage, and delegation depth) as the immutable + * {@link SessionHeader} (the store fills `version`/`id`/`createdAt`). + * + * For an agent whose session must be torn down IN ORDER with its loop (so the + * loop's final events are published before the store attachment ends), do NOT use this + * — fold the session lifecycle into the agent's own effect via + * {@link prepare} + {@link enter} + {@link announce} (see + * `dsh-agent-loop`'s creation transaction). + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. + * @returns the live session, already entered and announced. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path (storage backends key directories off it). + */ + create(id, options) { + const session = this.prepare(id, options); + this.ctx.effect(function* () { + yield this.enter(session); + this.announce(session); + }.bind(this), "sessions.create()"); + return session; + } + /** + * Build a session WITHOUT entering it into the store — validate the id/cwd and + * construct the {@link Session} (with its immutable {@link SessionHeader}). + * Pairs with {@link enter} + {@link announce}: a caller that owns a composite + * `ctx.effect` (the agent factory) folds the session lifecycle into that ONE + * effect so a fiber unload tears the session + agent down as a single ORDERED + * chain rather than as racing sibling effects — which would remove the publication hooks + * before the driver's closing events commit, dropping them. + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. With + * `seedSource: 'persistence'`, metadata and events must be fresh detached + * graphs whose ownership transfers to this call: they are validated and + * frozen in place through {@link Session.fromRestore}, so the caller must + * retain no mutable aliases. + * @returns the constructed session, NOT yet in the store. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path. + */ + prepare(id, options) { + let sessionId; + if (id === void 0) do + sessionId = SessionId(`session-${++this.counter}`); + while (this.store.has(sessionId)); + else sessionId = SessionId(id); + if (this.store.has(sessionId)) throw new Error(`session "${sessionId}" already exists`); + if (options?.seedSource === "persistence") return Session.fromRestore(sessionId, options.seed, options.meta); + const seed = options?.seed; + const meta = options?.meta; + const header = { + version: 0, + id: sessionId, + createdAt: meta?.createdAt ?? Date.now(), + ...meta?.cwd === void 0 ? {} : { cwd: meta.cwd }, + ...meta?.parentSession === void 0 ? {} : { parentSession: meta.parentSession }, + ...meta?.seedLength === void 0 ? {} : { seedLength: meta.seedLength }, + ...meta?.origin === void 0 ? {} : { origin: meta.origin }, + ...meta?.delegationDepth === void 0 ? {} : { delegationDepth: meta.delegationDepth }, + ...meta?.agentPreset === void 0 ? {} : { agentPreset: meta.agentPreset } + }; + return Session.create(sessionId, seed, header); + } + /** + * Enter a {@link prepare}d session into the store: install the module-private + * append publication hooks and add it to the store. Returns the DETACH + * disposer (hooks + store removal). Does NOT emit `session/created` — + * the caller yields this disposer inside its effect and THEN calls + * {@link announce}, so a throwing `session/created` listener rolls the attach + * back instead of leaking it. + * + * Re-checks the id for a duplicate: `prepare` and `enter` are public + * cross-package primitives and a caller may interleave arbitrary work (or + * another create) between them, so a stale prepared session must NOT overwrite + * a live store entry of the same id — its detach disposer would later delete + * the REAL session. The {@link create} convenience and the agent factory call + * the two back-to-back so they never trip this, but the public API cannot + * assume that. + * + * @param session - a {@link prepare}d session not yet in the store. + * @returns the detach disposer (publication hooks + store removal). When called from + * a synchronous `session/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + * @throws if a session with this id is already in the store. + */ + enter(session) { + const id = session.id; + const carrier = scopeTarget(session, scopeOf(this.ctx)); + if (this.store.has(id)) throw new Error(`session "${id}" already exists`); + if (attachments.has(session)) throw new Error(`session "${id}" is already attached to a store`); + const entry = { + id, + session, + carrier, + emitCtx: this.ctx, + announced: false, + announcing: false, + appending: false, + detachRequested: false, + detach: () => { + this.detachEntered(entry); + } + }; + this.store.set(id, entry); + attachments.set(session, entry); + let entered = true; + const detach = () => { + if (!entered) return; + entered = false; + if (entry.announcing || entry.appending) { + entry.detachRequested = true; + return; + } + entry.detach(); + }; + return detach; + } + /** Remove one exact entered session and emit its paired disposal when announced. */ + detachEntered(entry) { + entry.detachRequested = false; + /* v8 ignore next -- enter() rejects replacement while this single-shot detach capability is live. */ + if (this.store.get(entry.id) !== entry) return; + this.store.delete(entry.id); + attachments.delete(entry.session); + if (entry.announced) this.emitDisposed(entry); + } + /** Emit `session/created` exactly once for an {@link enter}ed session (with + * the carrier {@link enter} captured). Separate from {@link enter} so the + * caller can yield the detach disposer first (rollback safety — see + * {@link enter}). + * @param session - the entered session to announce to listeners. + * @throws if the session is not live or its announcement already began, + * including a reentrant call from a creation listener. */ + announce(session) { + const entry = this.liveEntryFor(session); + if (entry.announced || entry.announcing) throw new Error(`session "${entry.id}" was already announced`); + entry.announced = true; + const callbackArgs = [session]; + entry.announcing = true; + try { + const callbacks = collectSessionCallbacks(this.ctx, [ + entry.carrier, + "session/created", + session + ]); + for (const callback of callbacks) { + const returned = callback(...callbackArgs); + Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`session "${entry.id}": session/created listener rejected: ${String(error)}`); + }); + } + } finally { + entry.announcing = false; + if (entry.detachRequested && !entry.appending) entry.detach(); + } + } + /** Emit the paired teardown notification with per-listener containment. */ + emitDisposed(entry) { + const callbackArgs = [entry.session]; + try { + const callbacks = collectSessionCallbacks(this.ctx, [ + entry.carrier, + "session/disposed", + entry.session + ]); + invokeContainedSessionObservers(this.ctx, "session/disposed", entry.id, callbackArgs, callbacks); + } catch (error) { + this.ctx.logger.warn(`session "${entry.id}": session/disposed dispatch threw: ${String(error)}`); + } + } + /** + * Dispatch the awaited `session/flush` durability checkpoint for `session`, + * with the carrier captured at {@link enter}. THE flush entry point: the + * store owns the carrier, so callers (the checkpoint policy's per-request + * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers + * that flush themselves before reading storage) must come through here + * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner, + * one spelling, and the scoped-dispatch invariant can pin it. + * @param session - the session whose buffered events must reach durable storage. + * @returns whether at least one durability listener participated, after every + * listener has settled successfully. + * @throws the first registered listener failure after every listener settles. + */ + async flush(session) { + const { carrier } = this.liveEntryFor(session); + const callbackArgs = [session]; + const callbacks = collectSessionCallbacks(this.ctx, [ + carrier, + "session/flush", + session + ]); + const failure = (await Promise.allSettled(callbacks.map((callback) => { + try { + return callback(...callbackArgs); + } catch (error) { + return Promise.reject(error); + } + }))).find((result) => result.status === "rejected"); + if (failure !== void 0) throw failure.reason; + return callbacks.length > 0; + } + /** Return the exact live entry; detached/prepared objects reject. */ + liveEntryFor(session) { + const entry = attachments.get(session); + if (entry === void 0 || this.store.get(entry.id) !== entry) throw new Error(`session "${session.id}" is not live in this store`); + return entry; + } + /** + * Look up a live session. + * @param id - the session id to look up. + * @returns the session, or undefined when no live session has that id. + */ + get(id) { + return this.store.get(id)?.session; + } + /** + * All live sessions, in creation order. + * @returns a fresh array; mutating it does not affect the store. + */ + list() { + return [...this.store.values()].map((entry) => entry.session); + } + /** + * Create a live child session from a stable prefix of a live source. + * `boundary` is an inclusive source event seq; omitted means the source's + * current last event. The selected slice may end with a between-turn event + * but must not end inside an open turn. + * + * @param source - Live source session object or id. + * @param boundary - Inclusive source event seq to fork through; omitted means + * the source's current last event, and omitted on an empty source forks an + * empty child. + * @param childSessionId - Optional child session id; omitted delegates to + * `SessionStore`'s id policy. + * @returns The created live child session. + */ + fork(source, boundary, childSessionId) { + if (childSessionId !== void 0 && this.get(childSessionId) !== void 0) throw new SessionForkError(`session "${childSessionId}" already exists`, "SESSION_ALREADY_EXISTS"); + const liveSource = this._resolveForkSource(source); + const seed = this._forkSeed(liveSource, boundary); + return this.create(childSessionId, { + seed, + meta: { + ...liveSource.header.cwd !== void 0 ? { cwd: liveSource.header.cwd } : {}, + parentSession: liveSource.id, + seedLength: seed.length + } + }); + } + _forkSeed(session, requestedBoundary) { + const events = session.events; + const lastEvent = events.at(-1); + let boundary; + if (requestedBoundary !== void 0) boundary = requestedBoundary; + else { + if (lastEvent === void 0) return []; + boundary = lastEvent.seq; + } + if (!Number.isSafeInteger(boundary) || boundary < 0) throw new SessionForkError(`fork boundary for session "${session.id}" must be a non-negative safe integer, got ${String(boundary)}`, "INVALID_BOUNDARY"); + if (boundary >= events.length) { + const lastSeq = events.at(-1)?.seq; + throw new SessionForkError(`fork boundary ${boundary} does not exist in session "${session.id}" (last seq: ${lastSeq ?? "none"})`, "INVALID_BOUNDARY"); + } + const boundaryEvent = events[boundary]; + if (boundaryEvent === void 0 || boundaryEvent.seq !== boundary) throw new SessionForkError(`fork boundary ${boundary} does not match a contiguous event seq in session "${session.id}"`, "INVALID_BOUNDARY"); + const lastTurnBoundary = events.slice(0, boundary + 1).findLast((event) => event.type === "turn/start" || event.type === "turn/end"); + if (lastTurnBoundary?.type === "turn/start") throw new SessionForkError(`fork boundary ${boundary} in session "${session.id}" ends inside open turn ${lastTurnBoundary.data.turn}`, "OPEN_TURN"); + return events.slice(0, boundary + 1); + } + _resolveForkSource(source) { + if (typeof source === "string") { + const session = this.get(source); + if (session === void 0) throw new SessionForkError(`session "${source}" not found`, "SESSION_NOT_FOUND"); + return session; + } + const live = this.get(source.id); + if (live === void 0) throw new SessionForkError(`session "${source.id}" not found`, "SESSION_NOT_FOUND"); + if (live !== source) throw new SessionForkError(`session "${source.id}" is not the live store instance`, "SESSION_NOT_LIVE"); + return source; + } +}; +//#endregion +export { KNOWN_SESSION_EVENT_TYPES, SESSION_FORMAT_VERSION, Session, SessionForkError, SessionId, SessionPreparation, SessionStore, SessionStore as default, TOOL_NOT_STARTED, TOOL_OUTCOME_UNKNOWN, adoptSessionEvent, canonicalHeader, decodeStorageRecord, deriveEventMessage, foldRequestHeader, foldSurface, headerEquals, interruptedTurnClosers, isAppendSurfaceEvent, isJsonValue, isReplacementSurfaceEvent, isSurfaceEligibleType, isSurfaceEvent, packChunkRuns, snapshotJsonValue, snapshotSessionEvent }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/invariant.js new file mode 100644 index 0000000..b96f03d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/invariant.js @@ -0,0 +1,168 @@ +import { assertNever } from "@deepseek-ai/dsh-llm"; +//#endregion +//#region lib/types/invariant.js +/** +* Package-owned relational invariants for the session event log. Load this +* companion beside `@deepseek-ai/dsh-invariants` to enable the checks. +* +* @module @deepseek-ai/dsh-session/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-session"; +/** Cordis companion plugin name. */ +const name = "session-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Assert that a step-scoped event names the currently open turn and step. */ +function requireOpenStep(trace, kind, turn, step, fail) { + if (trace.openTurn !== turn || trace.openStep !== step) fail(`${kind} names turn ${turn}/step ${step} but open is turn ${trace.openTurn}/step ${trace.openStep}`); +} +/** Validate one candidate event without mutating the committed trace. */ +function validateEvent(trace, event, fail) { + if (event.seq <= trace.lastSeq) fail(`seq must strictly increase: saw ${event.seq} after ${trace.lastSeq}`); + let openTurn = trace.openTurn; + let openStep = trace.openStep; + let nextTurn = trace.nextTurn; + let nextStep = trace.nextStep; + let pendingCalls = { kind: "none" }; + switch (event.type) { + case "turn/start": + if (trace.openTurn !== null) fail(`turn/start ${event.data.turn} while turn ${trace.openTurn} is still open`); + if (event.data.turn !== trace.nextTurn) fail(`turn/start expected turn ${trace.nextTurn}, got ${event.data.turn}`); + openTurn = event.data.turn; + nextStep = 1; + break; + case "turn/end": + if (trace.openTurn !== event.data.turn) fail(`turn/end ${event.data.turn} does not match open turn ${trace.openTurn}`); + if (trace.openStep !== null) fail(`turn/end ${event.data.turn} while step ${trace.openStep} is still open`); + openTurn = null; + nextTurn += 1; + break; + case "step/start": + if (trace.openTurn !== event.data.turn) fail(`step/start in turn ${event.data.turn} but open turn is ${trace.openTurn}`); + if (trace.openStep !== null) fail(`step/start ${event.data.step} while step ${trace.openStep} is still open`); + if (event.data.step !== trace.nextStep) fail(`step/start expected step ${trace.nextStep} in turn ${event.data.turn}, got ${event.data.step}`); + openStep = event.data.step; + break; + case "step/end": + requireOpenStep(trace, "step/end", event.data.turn, event.data.step, fail); + pendingCalls = { kind: "clear" }; + openStep = null; + nextStep += 1; + break; + case "assistant/chunk": + requireOpenStep(trace, "assistant/chunk", event.data.turn, event.data.step, fail); + break; + case "assistant/message": + requireOpenStep(trace, "assistant/message", event.data.turn, event.data.step, fail); + break; + case "tool/call": + requireOpenStep(trace, "tool/call", event.data.turn, event.data.step, fail); + pendingCalls = { + kind: "add", + callId: event.data.callId + }; + break; + case "tool/result": { + if (event.surfaceOp !== "append") { + if (trace.openTurn === null) fail("tool/result surface replacement appended outside any open turn"); + break; + } + requireOpenStep(trace, "tool/result", event.data.turn, event.data.step, fail); + const callId = event.data.message.source.callId; + const syntheticNotStarted = event.data.message.content[0].isError === true && event.data.error?.code === "TOOL_NOT_STARTED"; + if (!trace.pendingCalls.has(callId) && !syntheticNotStarted) fail(`tool/result for ${callId} with no prior tool/call in this step`); + pendingCalls = { + kind: "delete", + callId + }; + break; + } + case "user/message": break; + case "session/end-seed": break; + case "todo/write": + case "request/header": + case "request/context": + if (trace.openTurn === null) fail(`${event.type} appended outside any open turn (core execution events must be turn-enclosed)`); + break; + default: break; + } + return { + scalars: { + lastSeq: event.seq, + openTurn, + openStep, + nextTurn, + nextStep + }, + pendingCalls + }; +} +/** Apply one already-validated transition after its event commits. */ +function applyTransition(trace, transition) { + Object.assign(trace, transition.scalars); + switch (transition.pendingCalls.kind) { + case "none": break; + case "add": + trace.pendingCalls.add(transition.pendingCalls.callId); + break; + case "delete": + trace.pendingCalls.delete(transition.pendingCalls.callId); + break; + case "clear": + trace.pendingCalls.clear(); + break; + /* v8 ignore next -- validateEvent produces this closed transition union */ + default: assertNever(transition.pendingCalls, "session trace pending-call transition"); + } +} +/** Install the session contribution into its child registration fiber. */ +const install = Object.assign((ctx, fail) => { + const traces = /* @__PURE__ */ new WeakMap(); + const stagedTransitions = /* @__PURE__ */ new WeakMap(); + const freshTrace = () => ({ + lastSeq: -1, + openTurn: null, + openStep: null, + nextTurn: 1, + nextStep: 1, + pendingCalls: /* @__PURE__ */ new Set() + }); + const seedSession = (session) => { + const trace = freshTrace(); + traces.set(session, trace); + for (const event of session.events) applyTransition(trace, validateEvent(trace, event, fail)); + return trace; + }; + /* v8 ignore next -- session/event always follows list() or session/created seeding */ + const traceFor = (session) => traces.get(session) ?? seedSession(session); + for (const session of ctx.sessions.list()) seedSession(session); + ctx.on("session/created", (session) => { + seedSession(session); + }, { global: true }); + ctx.on("session/event", (session, event) => { + const staged = stagedTransitions.get(event); + /* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */ + if (staged === void 0 || staged.session !== session) return fail("session/event reached publication without matching pre-commit validation"); + stagedTransitions.delete(event); + applyTransition(staged.trace, staged.transition); + }, { global: true }); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName !== "session/event") return; + const [session, event] = args; + const trace = traceFor(session); + const transition = validateEvent(trace, event, fail); + stagedTransitions.set(event, { + session, + trace, + transition + }); + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register the session invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.d.ts new file mode 100644 index 0000000..0e00895 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.d.ts @@ -0,0 +1,92 @@ +/** + * Lossless storage packing for `assistant/chunk` delta runs. Providers stream + * token-sized deltas, so a log stores hundreds of near-identical event lines + * whose JSON envelopes dwarf their payloads (~56× measured on a real DeepSeek + * session). This module packs each run of consecutive same-block delta chunks + * into ONE storage row — `text-chunks`, `reasoning-chunks`, or + * `tool-call-chunks` — and expands rows back to the exact original events. + * + * Storage rows are a durable-encoding vocabulary, NOT session events: they + * never enter `Session.events`, have no `SessionEventMap` entry, and use bare + * (slash-less) type tags so a reader cannot confuse them with the event + * taxonomy (precedent: the JSONL header line's `session` tag). The encoder + * whitelists exact shapes — anything it does not fully recognize is stored + * verbatim, so unknown fields or future chunk variants lose compression, never + * data. The decoder validates before expanding and fails loud on a malformed + * row-tagged value instead of silently dropping a whole run. + * + * @module @deepseek-ai/dsh-session/chunk-rows + */ +import { CallId } from '@deepseek-ai/dsh-llm'; +import type { SessionEvent } from './types.ts'; +/** + * Fields shared by every packed run: placement, block correlation, and member + * timestamps as gaps. Member `k` reconstructs as seq `seq0 + k` and time + * `time0` plus the first `k` gaps; a gap may be negative when the wall clock + * stepped backwards between events. + */ +interface RunDataBase { + turn: number; + step: number; + /** The stream block index every member shares. */ + index: number; + /** Epoch-ms gaps between consecutive members; length is one less than the member count. */ + dt: number[]; +} +/** Payload of a `text-chunks`/`reasoning-chunks` row: one entry per member, never joined — token boundaries are data. */ +interface TextRunData extends RunDataBase { + texts: string[]; +} +/** Payload of a `tool-call-chunks` row: the run-constant call identity plus each member's raw arguments fragment. */ +interface ToolCallRunData extends RunDataBase { + id: CallId; + /** Present iff every member carried it, with one uniform value (a mixed run never packs). */ + name?: string; + args: string[]; +} +/** + * A packed run of consecutive delta chunk events, discriminated on `type`. + * `seq0`/`time0` anchor the first member; text and reasoning rows share the + * {@link TextRunData} payload, tool-call rows carry {@link ToolCallRunData}. + */ +export type ChunkRow = { + type: 'text-chunks'; + seq0: number; + time0: number; + data: TextRunData; +} | { + type: 'reasoning-chunks'; + seq0: number; + time0: number; + data: TextRunData; +} | { + type: 'tool-call-chunks'; + seq0: number; + time0: number; + data: ToolCallRunData; +}; +/** One durable log line's JSON value: a session event verbatim, or a packed chunk row. */ +export type StorageRecord = SessionEvent | ChunkRow; +/** + * Pack an event batch for storage: each run of at least {@link MIN_RUN} + * consecutive whitelisted same-kind, same-block delta chunk events becomes one + * {@link ChunkRow}; every other event passes through verbatim, in order. + * Pure and stateless — safe over any array, including a batch whose runs were + * split by flush boundaries (the split runs simply pack per batch). + * + * @param events - the batch to encode, in log order. + * @returns the storage records to write, one JSONL line each. + */ +export declare function packChunkRuns(events: readonly SessionEvent[]): StorageRecord[]; +/** + * Decode one parsed JSONL line value into the session event(s) it stores. + * Chunk-row-tagged values validate and expand (a malformed row throws — it is + * corrupt storage, and treating it as an event would silently drop a whole + * run); every other value passes through as a single event, unvalidated. + * + * @param value - one line's `JSON.parse` result. + * @returns the stored events, in log order. + */ +export declare function decodeStorageRecord(value: unknown): SessionEvent[]; +export {}; +//# sourceMappingURL=chunk-rows.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.js new file mode 100644 index 0000000..a5c4933 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/chunk-rows.js @@ -0,0 +1,301 @@ +/** + * Lossless storage packing for `assistant/chunk` delta runs. Providers stream + * token-sized deltas, so a log stores hundreds of near-identical event lines + * whose JSON envelopes dwarf their payloads (~56× measured on a real DeepSeek + * session). This module packs each run of consecutive same-block delta chunks + * into ONE storage row — `text-chunks`, `reasoning-chunks`, or + * `tool-call-chunks` — and expands rows back to the exact original events. + * + * Storage rows are a durable-encoding vocabulary, NOT session events: they + * never enter `Session.events`, have no `SessionEventMap` entry, and use bare + * (slash-less) type tags so a reader cannot confuse them with the event + * taxonomy (precedent: the JSONL header line's `session` tag). The encoder + * whitelists exact shapes — anything it does not fully recognize is stored + * verbatim, so unknown fields or future chunk variants lose compression, never + * data. The decoder validates before expanding and fails loud on a malformed + * row-tagged value instead of silently dropping a whole run. + * + * @module @deepseek-ai/dsh-session/chunk-rows + */ +import { CallId, assertNever } from '@deepseek-ai/dsh-llm'; +/** + * Minimum members before a run packs. Below it a row's envelope rivals the + * event lines it replaces. A format constant, not a tunable: both layouts + * decode identically, so changing it never invalidates stored logs. + */ +const MIN_RUN = 3; +function isRecord(value) { + return typeof value === 'object' && value !== null; +} +/** Exact-key check: `value` has every key in `keys` and nothing else. */ +function hasExactKeys(value, keys) { + return Object.keys(value).length === keys.length && keys.every(k => Object.hasOwn(value, k)); +} +/** + * Classify an event for packing: its delta kind when the ENTIRE shape + * (envelope, data, chunk — exact keys, primitive types, integer seq/time) is + * whitelisted, else `undefined` (store verbatim). Inputs come from live typed + * appends AND parsed fixture files, so the checks are structural, not + * type-trusted. Integer times keep gap encoding exact: a fractional time would + * reconstruct through float subtraction/addition, which need not round-trip. + */ +function classify(event) { + if (event.type !== 'assistant/chunk') + return undefined; + if (!hasExactKeys(event, ['type', 'seq', 'time', 'data'])) + return undefined; + if (!Number.isSafeInteger(event.seq) || event.seq < 0 || !Number.isSafeInteger(event.time)) + return undefined; + const data = event.data; + if (!isRecord(data) || !hasExactKeys(data, ['turn', 'step', 'chunk'])) + return undefined; + if (typeof data.turn !== 'number' || typeof data.step !== 'number') + return undefined; + const chunk = data.chunk; + if (!isRecord(chunk) || typeof chunk.index !== 'number') + return undefined; + switch (chunk.type) { + case 'text-delta': + case 'reasoning-delta': + return hasExactKeys(chunk, ['type', 'index', 'text']) && typeof chunk.text === 'string' + ? chunk.type + : undefined; + case 'tool-call-delta': { + const shapeOk = hasExactKeys(chunk, ['type', 'index', 'id', 'argumentsDelta']) + || (hasExactKeys(chunk, ['type', 'index', 'id', 'name', 'argumentsDelta']) && typeof chunk.name === 'string'); + return shapeOk && typeof chunk.id === 'string' && typeof chunk.argumentsDelta === 'string' + ? chunk.type + : undefined; + } + // Whitelist fall-through over parsed data: block-start/end, usage, finish, + // and any future chunk variant stay one event per line. + default: + return undefined; + } +} +/** The tool-call fields of a whitelisted delta chunk (only after {@link classify} returned `'tool-call-delta'`). */ +function toolCallOf(event) { + return event.data.chunk; +} +/** The block index of a whitelisted delta chunk (not every {@link StreamChunk} variant carries one). */ +function indexOf(event) { + return event.data.chunk.index; +} +/** Whether `next` extends a run ending in `prev` (same kind already checked by the caller). */ +function continues(prev, next, kind) { + if (next.seq !== prev.seq + 1) + return false; + // Two safe-integer times can sit further apart than a double subtracts + // exactly (2^53-1 and its negation differ by ~2^54); a rounded gap would + // decode to a different timestamp. The check is exact in both directions: a + // true gap within safe range subtracts without rounding and passes, while a + // true gap beyond it rounds to a value that is itself beyond and fails. + if (!Number.isSafeInteger(next.time - prev.time)) + return false; + if (next.data.turn !== prev.data.turn || next.data.step !== prev.data.step) + return false; + if (indexOf(next) !== indexOf(prev)) + return false; + if (kind !== 'tool-call-delta') + return true; + const a = toolCallOf(prev); + const b = toolCallOf(next); + // `name` must match in presence AND value — a mixed run is not representable. + return a.id === b.id && Object.hasOwn(a, 'name') === Object.hasOwn(b, 'name') && a.name === b.name; +} +/** Build the row for a completed run (`run.length >= MIN_RUN`, uniform per {@link continues}). */ +function buildRow(kind, run) { + const first = run[0]; + const base = { + turn: first.data.turn, + step: first.data.step, + index: indexOf(first), + dt: run.slice(1).map((event, i) => event.time - run[i].time), + }; + const envelope = { seq0: first.seq, time0: first.time }; + if (kind === 'tool-call-delta') { + const call = toolCallOf(first); + return { + type: 'tool-call-chunks', + ...envelope, + data: { + ...base, + id: CallId(call.id), + ...Object.hasOwn(call, 'name') ? { name: call.name } : {}, + args: run.map(event => event.data.chunk.argumentsDelta), + }, + }; + } + const data = { ...base, texts: run.map(event => event.data.chunk.text) }; + return kind === 'text-delta' + ? { type: 'text-chunks', ...envelope, data } + : { type: 'reasoning-chunks', ...envelope, data }; +} +/** + * Pack an event batch for storage: each run of at least {@link MIN_RUN} + * consecutive whitelisted same-kind, same-block delta chunk events becomes one + * {@link ChunkRow}; every other event passes through verbatim, in order. + * Pure and stateless — safe over any array, including a batch whose runs were + * split by flush boundaries (the split runs simply pack per batch). + * + * @param events - the batch to encode, in log order. + * @returns the storage records to write, one JSONL line each. + */ +export function packChunkRuns(events) { + const out = []; + let kind; + let run = []; + const flush = () => { + if (kind !== undefined && run.length >= MIN_RUN) + out.push(buildRow(kind, run)); + else + out.push(...run); + kind = undefined; + run = []; + }; + for (const event of events) { + const k = classify(event); + if (k === undefined) { + flush(); + out.push(event); + continue; + } + const delta = event; + const last = run[run.length - 1]; + if (k === kind && last !== undefined && continues(last, delta, k)) { + run.push(delta); + continue; + } + flush(); + kind = k; + run = [delta]; + } + flush(); + return out; +} +/** Throw the uniform malformed-row diagnostic. */ +function malformed(tag, why) { + throw new Error(`malformed ${tag} storage row: ${why}`); +} +/** Validate the shared run-data fields and the payload/dt arity; returns the member payload. */ +function validateRunData(tag, data, payloadKey) { + if (typeof data.turn !== 'number' || typeof data.step !== 'number' || typeof data.index !== 'number') { + malformed(tag, 'turn/step/index must be numbers'); + } + const payload = data[payloadKey]; + if (!Array.isArray(payload) || payload.length === 0 || payload.some(entry => typeof entry !== 'string')) { + malformed(tag, `${payloadKey} must be a non-empty string array`); + } + const dt = data.dt; + if (!Array.isArray(dt) || dt.some(gap => !Number.isSafeInteger(gap))) { + malformed(tag, 'dt must be an array of safe integers'); + } + if (dt.length !== payload.length - 1) { + malformed(tag, `dt length ${dt.length} does not match ${payload.length} members`); + } + return payload; +} +/** Validate a row-tagged parsed value's envelope and data, throwing on any malformation. */ +function validateRow(value, tag) { + if (!hasExactKeys(value, ['type', 'seq0', 'time0', 'data'])) { + malformed(tag, 'envelope must be exactly {type, seq0, time0, data}'); + } + if (!Number.isSafeInteger(value.seq0) || value.seq0 < 0) { + malformed(tag, 'seq0 must be a non-negative safe integer'); + } + if (!Number.isSafeInteger(value.time0)) { + malformed(tag, 'time0 must be a safe integer'); + } + const data = value.data; + if (!isRecord(data)) + malformed(tag, 'data must be an object'); + let payload; + if (tag === 'tool-call-chunks') { + const withName = hasExactKeys(data, ['turn', 'step', 'index', 'id', 'name', 'dt', 'args']); + if (!withName && !hasExactKeys(data, ['turn', 'step', 'index', 'id', 'dt', 'args'])) { + malformed(tag, 'data must be exactly {turn, step, index, id, name?, dt, args}'); + } + if (typeof data.id !== 'string' || (withName && typeof data.name !== 'string')) { + malformed(tag, 'id (and name when present) must be strings'); + } + payload = validateRunData(tag, data, 'args'); + } + else { + if (!hasExactKeys(data, ['turn', 'step', 'index', 'dt', 'texts'])) { + malformed(tag, 'data must be exactly {turn, step, index, dt, texts}'); + } + payload = validateRunData(tag, data, 'texts'); + } + // Reconstruction bounds. The encoder only packs runs whose member seqs and + // times are all safe integers, so a running value that leaves safe range is + // outside any encoder's image: float arithmetic would round it to a + // different number than exact arithmetic, a silent corruption. Within safe + // range every step is exact, so the first departure is always caught. + if (!Number.isSafeInteger(value.seq0 + payload.length - 1)) { + malformed(tag, 'member seqs must stay safe integers'); + } + let time = value.time0; + for (const gap of data.dt) { + time += gap; + if (!Number.isSafeInteger(time)) + malformed(tag, 'member times must stay safe integers'); + } + return value; +} +/** Expand a validated row back into its exact original events, in order. */ +function expandRow(row) { + const members = row.type === 'tool-call-chunks' ? row.data.args : row.data.texts; + const events = []; + let time = row.time0; + for (let k = 0; k < members.length; k++) { + if (k > 0) + time += row.data.dt[k - 1]; + let chunk; + switch (row.type) { + case 'text-chunks': + chunk = { type: 'text-delta', index: row.data.index, text: members[k] }; + break; + case 'reasoning-chunks': + chunk = { type: 'reasoning-delta', index: row.data.index, text: members[k] }; + break; + case 'tool-call-chunks': + chunk = { + type: 'tool-call-delta', + index: row.data.index, + id: row.data.id, + ...Object.hasOwn(row.data, 'name') ? { name: row.data.name } : {}, + argumentsDelta: members[k], + }; + break; + /* v8 ignore next 2 -- validateRow only returns the three row tags */ + default: + return assertNever(row, 'chunk-rows expandRow'); + } + events.push({ + type: 'assistant/chunk', + seq: row.seq0 + k, + time, + data: { turn: row.data.turn, step: row.data.step, chunk }, + }); + } + return events; +} +/** + * Decode one parsed JSONL line value into the session event(s) it stores. + * Chunk-row-tagged values validate and expand (a malformed row throws — it is + * corrupt storage, and treating it as an event would silently drop a whole + * run); every other value passes through as a single event, unvalidated. + * + * @param value - one line's `JSON.parse` result. + * @returns the stored events, in log order. + */ +export function decodeStorageRecord(value) { + if (!isRecord(value)) + return [value]; + const tag = value.type; + if (tag !== 'text-chunks' && tag !== 'reasoning-chunks' && tag !== 'tool-call-chunks') { + return [value]; + } + return expandRow(validateRow(value, tag)); +} +//# sourceMappingURL=chunk-rows.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts new file mode 100644 index 0000000..1e2f5ba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts @@ -0,0 +1,418 @@ +/** + * Event-sourced session service: append-only session log, in-memory store, and + * the derived LLM message history. Persistence is a plugin concern (subscribe + * to `session/event`, drain on `session/flush`). + * + * @module @deepseek-ai/dsh-session + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { Scoped } from '@deepseek-ai/dsh-scope'; +import type { Message } from '@deepseek-ai/dsh-llm'; +import { SessionId } from './types.ts'; +import type { TypertLookup } from '@deepseek-ai/dsh-typert-protocol'; +import type { CreateSessionOptions, EpochHeader, PrepareSessionOptions, RequestContext, SessionEvent, SessionEventMap, SessionEventType, SessionHeader, SurfaceIntent, SurfaceEventType } from './types.ts'; +import type { SessionSurface } from './surface.ts'; +export * from './types.ts'; +export { SessionPreparation } from './preparation.ts'; +export type { SessionPreparationOptions } from './preparation.ts'; +export type { AssistantMessage, ToolResultMessage, UserMessage } from '@deepseek-ai/dsh-llm'; +export { isJsonValue, snapshotJsonValue } from './json.ts'; +export type { JsonValue } from './json.ts'; +export { interruptedTurnClosers, TOOL_NOT_STARTED, TOOL_OUTCOME_UNKNOWN } from './repair.ts'; +export { decodeStorageRecord, packChunkRuns } from './chunk-rows.ts'; +export type { ChunkRow, StorageRecord } from './chunk-rows.ts'; +export type { SessionSurface, SurfaceFoldReplacement, SurfaceFoldResult } from './surface.ts'; +export { deriveEventMessage, foldSurface, isAppendSurfaceEvent, isReplacementSurfaceEvent, isSurfaceEvent, isSurfaceEligibleType } from './surface.ts'; +export { canonicalHeader, foldRequestHeader, headerEquals } from './request-header.ts'; +export { KNOWN_SESSION_EVENT_TYPES } from './known-event-types.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + sessions: SessionStore; + } + interface Events { + /** + * Creation announcement during session publication. A synchronous throw vetoes and rolls + * back with a paired disposal; detach requested during dispatch is deferred. + * A returned-promise rejection is logged but cannot retroactively veto this + * synchronous boundary. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners + * receive only sessions entered through that agent's context. + * @param session - the session just entered and announced. + * @dshScopeScan unsupported + * @mode emit + */ + 'session/created'(this: Scoped, session: Session): void; + /** + * Emitted once when an announced session leaves the store, including + * publication rollback, but never for an entry whose creation announcement + * did not begin. Listener failures are logged and contained. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`) reuses the owner scope. + * @param session - the session that is no longer live in the store. + * @dshScopeScan unsupported + * @mode emit + */ + 'session/disposed'(this: Scoped, session: Session): void; + /** + * Post-commit, fire-and-forget append feed. The listener snapshot resolves + * before the log push, but callbacks run after it; observer failures are + * logged and contained without making the committed append fail. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners + * receive only events from sessions entered through that agent's context. + * @param session - the session whose log grew. + * @param event - the appended event, exactly as recorded. + * @dshScopeScan unsupported + * @mode emit + */ + 'session/event'(this: Scoped, session: Session, event: SessionEvent): void; + /** + * Awaited parallel durability checkpoint: every listener runs and the + * caller awaits all of them, with no waterfall veto. Scope-filtered dispatch + * (`@deepseek-ai/dsh-scope`) reuses the session's owner scope. + * @param session - the session whose buffered events must reach durable storage. + * @dshScopeScan unsupported + * @mode parallel + */ + 'session/flush'(this: Scoped, session: Session): Promise | void; + } +} +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertLookupMap { + session: TypertLookup; + } +} +/** + * Validate an exclusively owned event and deeply freeze its identified message + * without copying the event. The caller transfers an object graph that no + * producer retains and that shares no mutable children with another event. + * Use {@link snapshotSessionEvent} when exclusive ownership is not guaranteed. + * @param event - exclusively owned event imported across a trusted boundary. + * @returns the same event object with a validated, deeply frozen message. + */ +export declare function adoptSessionEvent(event: T): T; +/** + * Detach one event while preserving deep immutability for its identified message. + * @param event - event imported across a query or persistence boundary. + * @returns a detached event snapshot with a validated, deeply frozen message. + */ +export declare function snapshotSessionEvent(event: T): T; +/** + * An event-sourced session: an append-only log of {@link SessionEvent}s. + * + * Plain class (not a Service) — create live instances via + * `ctx.sessions.create()` and detached instances via {@link create}. + * Seeding with an existing event log replays/forks a session. + * @typert object + */ +export declare class Session { + private log; + /** Single incremental owner of surface acceptance and projection state. */ + private readonly surfaceManager; + /** The ordered surface over this session's event log. */ + get surface(): SessionSurface; + /** + * Detached, deep-frozen creation metadata (format version, cwd, lineage, + * seed boundary). Supplied by the store via `ctx.sessions.create()`. When a + * `Session` is created without a store-owned header, a minimal header is + * synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so + * `session.header` is always present. Kept out of the event log — it is a + * storage concern, not replayable conversation state. + */ + readonly header: SessionHeader; + /** The session identity, derived from its durable header's single copy. */ + get id(): SessionId; + /** + * The first seq appended IN THIS PROCESS: the length of the constructor + * seed (0 without one). Events with smaller seq values entered through + * construction — replay, fork, or resume — and were never published on the + * `session/event` firehose (constructor seeds do not emit), so consumers + * that replay the log as a publication substitute (telemetry adoption) + * start here. Distinct from `header.seedLength`, the DURABLE fork-lineage + * boundary: a resumed session's constructor seed is its full stored log, + * while its header keeps the original fork value — this field is the + * in-process construction fact. + * + * Not persisted itself: a seeded session projects it into the log as the + * `session/end-seed` event, which is what a consumer reading STORED history + * reads. Locate the LAST such event, not necessarily one at this seq — a + * seed already ending in one is not re-marked, so reopening an untouched + * session leaves that event at a smaller seq than `firstLiveSeq`. Prefer + * this field in-process: it is exact before the marker reaches storage. + * + * When this lifecycle appends the marker, it occupies this seq before the + * store attaches and therefore does not publish either. Otherwise this seq + * holds an ordinary published write. + */ + readonly firstLiveSeq: number; + /** + * Create a detached session by validating and snapshotting borrowed seed + * events and storage metadata. + * @param id - session identity. + * @param seed - optional borrowed replay or fork events. + * @param header - optional borrowed storage metadata. + * @returns a detached session. + */ + static create(id: SessionId, seed?: readonly SessionEvent[], header?: SessionHeader): Session; + /** + * Restore a detached session by taking ownership of fresh persistence values. + * The storage format, event envelopes, sequence continuity, surface transitions, + * and header fields are validated before the restored objects are frozen. + * @param id - restored session identity. + * @param seed - fresh detached events whose ownership is transferred. + * @param header - fresh detached metadata whose ownership is transferred. + * @returns a restored detached session. + */ + static fromRestore(id: SessionId, seed: readonly SessionEvent[], header: SessionHeader): Session; + private constructor(); + /** Cached immutable public snapshot of the private append-only log. */ + private eventsSnapshot; + /** + * An immutable snapshot of the append-only event log. The snapshot is reused + * until the next append; a previously returned array does not grow later. + * Events and their nested data are deep-frozen at acceptance, so neither a + * cast nor ordinary JavaScript can rewrite durable history. + */ + get events(): readonly SessionEvent[]; + /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */ + get seq(): number; + /** + * Append one typed event to the log and synchronously notify observers via + * the store-owned, module-private publication hooks. The hot path never blocks + * on I/O — persistence plugins buffer asynchronously. Once the event enters + * the log, the append is committed: observer failures are logged and + * contained per listener, so they do not change the return value or prevent + * later listeners from observing the same accepted event. + * + * @param type - The event type (key of {@link SessionEventMap}). + * @param data - The event payload; must be JSON-serializable. + * @param opts - Surface metadata: `surfaceOp` controls how the event enters + * the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier + * events this one derives from. REQUIRED for + * {@link SurfaceEventType} events (every message-producing event must + * declare how it joins the surface, the sole source of derived model + * history) and + * rejected by the compiler for non-surface types like `turn/start` or + * `assistant/chunk`. + * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of + * `data` that entered the log, so reading `event.data` back sees the logged + * value, never the caller's still-mutable input. + * @throws if `data` or surface metadata is not losslessly JSON-serializable + * (BigInt, function, symbol, undefined, negative zero, non-finite number, + * circular reference, sparse array, or an exotic object such as + * Map/Set/Date/class instance), or when the candidate violates the + * canonical surface contract (marker shape and eligibility, unique + * earlier source-event references, positional replacement validity, and complete + * shadowed-node coverage). One recursive pass reads, validates, and + * copies each nested value once, so a stateful getter cannot supply one value + * to validation and another to storage. The event log is the durable source + * of truth, so a bad event fails at the append site rather than later during + * a backend flush. A synchronous internal dispatch validation failure or an + * append reentered while this acceptance/publication boundary is open also + * rejects before the log changes. + */ + append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent; + /** Cached fold of the request-header events — see {@link requestHeader}. */ + private headerFold; + /** Log position (events consumed) the header fold has reached. */ + private headerFoldSeq; + /** + * The {@link EpochHeader} in force after the log's last header event — the + * header the NEXT request will be compared against — or undefined before + * the first `request/header` snapshot. The live, incrementally-maintained + * form of `foldRequestHeader(session.events)`: each header event is folded + * once, when first seen, so a per-step read costs O(new events). + * @returns the folded header, or undefined when no header event exists yet. + */ + requestHeader(): EpochHeader | undefined; + /** Cached fold of `request/context` events. */ + private contextFold; + private contextFoldSeq; + /** + * Return the latest resolved route metadata, or `undefined` before the first + * `request/context` event. Each event is folded once. + * @returns the latest immutable route metadata. + */ + requestContext(): RequestContext | undefined; + /** The derived-message cache: frozen projections, extended per unseen node. */ + private derived; + /** Surface position (nodes projected) the cache has reached. */ + private derivedNodes; + /** {@link SurfaceManager.replaceGeneration} the cache was built under. */ + private derivedGeneration; + /** + * Derive the LLM message history by walking the ordered sequences of + * message-producing events maintained by `surfaceOp` markers. The + * surface is the single source of derived history: every message-producing + * append records its `surfaceOp`, so a raw event with no marker (a chunk, a + * turn boundary) is correctly absent, and a compaction `replace` deletes the + * shadowed nodes from the derivation. The projection rules are + * {@link deriveEventMessage}, folded per node. + * + * CACHED: each surface node is projected exactly once, when first seen — a + * call costs O(new nodes), and a surface rewrite (a `replace`; + * {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is + * a fresh snapshot per call (later appends never grow an array a caller + * already holds); the `Message` objects in it are SHARED and **deep-frozen**. + * Their content reuses the already frozen durable event data, so the cache + * needs no second deep clone and consumers still cannot mutate the log. + * @returns a fresh array of the shared, frozen derived history. + */ + deriveMessages(): Message[]; + /** + * Instance face of the pure per-node `deriveEventMessage` export from + * `surface.ts`. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ + deriveEventMessage(event: SessionEvent): Message | null; +} +/** A fork source: either the live session object or its live store id. */ +export type SessionForkSource = Session | SessionId; +/** + * Rejection codes for session forking: the fork source id is unknown to the + * live store (`SESSION_NOT_FOUND`) or names a session object that is not the + * store's live instance (`SESSION_NOT_LIVE`); the requested child id is + * already taken (`SESSION_ALREADY_EXISTS`); the boundary is not a contiguous + * existing seq (`INVALID_BOUNDARY`); or the selected prefix ends inside an + * open turn (`OPEN_TURN`). + */ +export type SessionForkErrorCode = 'SESSION_NOT_FOUND' | 'SESSION_NOT_LIVE' | 'SESSION_ALREADY_EXISTS' | 'INVALID_BOUNDARY' | 'OPEN_TURN'; +/** Typed error for session fork rejections. */ +export declare class SessionForkError extends Error { + readonly code: SessionForkErrorCode; + constructor(message: string, code: SessionForkErrorCode); +} +/** + * In-memory session store (`ctx.sessions`). + * + * Persistence is intentionally not implemented here — persistence plugins + * subscribe to `session/event` and flush on `session/flush` / dispose. + */ +export declare class SessionStore extends Service { + private store; + private counter; + constructor(ctx: Context); + /** + * Create a session owned by the calling fiber: disposing that fiber stops + * event notification and removes the session from the store. `options.seed` + * populates the session with a copy of those events (replay/fork); + * `options.meta` attaches creation metadata (validated absolute `cwd`, seed + * and parent lineage, and delegation depth) as the immutable + * {@link SessionHeader} (the store fills `version`/`id`/`createdAt`). + * + * For an agent whose session must be torn down IN ORDER with its loop (so the + * loop's final events are published before the store attachment ends), do NOT use this + * — fold the session lifecycle into the agent's own effect via + * {@link prepare} + {@link enter} + {@link announce} (see + * `dsh-agent-loop`'s creation transaction). + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. + * @returns the live session, already entered and announced. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path (storage backends key directories off it). + */ + create(id?: SessionId, options?: CreateSessionOptions): Session; + /** + * Build a session WITHOUT entering it into the store — validate the id/cwd and + * construct the {@link Session} (with its immutable {@link SessionHeader}). + * Pairs with {@link enter} + {@link announce}: a caller that owns a composite + * `ctx.effect` (the agent factory) folds the session lifecycle into that ONE + * effect so a fiber unload tears the session + agent down as a single ORDERED + * chain rather than as racing sibling effects — which would remove the publication hooks + * before the driver's closing events commit, dropping them. + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. With + * `seedSource: 'persistence'`, metadata and events must be fresh detached + * graphs whose ownership transfers to this call: they are validated and + * frozen in place through {@link Session.fromRestore}, so the caller must + * retain no mutable aliases. + * @returns the constructed session, NOT yet in the store. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path. + */ + prepare(id?: SessionId, options?: PrepareSessionOptions): Session; + /** + * Enter a {@link prepare}d session into the store: install the module-private + * append publication hooks and add it to the store. Returns the DETACH + * disposer (hooks + store removal). Does NOT emit `session/created` — + * the caller yields this disposer inside its effect and THEN calls + * {@link announce}, so a throwing `session/created` listener rolls the attach + * back instead of leaking it. + * + * Re-checks the id for a duplicate: `prepare` and `enter` are public + * cross-package primitives and a caller may interleave arbitrary work (or + * another create) between them, so a stale prepared session must NOT overwrite + * a live store entry of the same id — its detach disposer would later delete + * the REAL session. The {@link create} convenience and the agent factory call + * the two back-to-back so they never trip this, but the public API cannot + * assume that. + * + * @param session - a {@link prepare}d session not yet in the store. + * @returns the detach disposer (publication hooks + store removal). When called from + * a synchronous `session/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + * @throws if a session with this id is already in the store. + */ + enter(session: Session): () => void; + /** Remove one exact entered session and emit its paired disposal when announced. */ + private detachEntered; + /** Emit `session/created` exactly once for an {@link enter}ed session (with + * the carrier {@link enter} captured). Separate from {@link enter} so the + * caller can yield the detach disposer first (rollback safety — see + * {@link enter}). + * @param session - the entered session to announce to listeners. + * @throws if the session is not live or its announcement already began, + * including a reentrant call from a creation listener. */ + announce(session: Session): void; + /** Emit the paired teardown notification with per-listener containment. */ + private emitDisposed; + /** + * Dispatch the awaited `session/flush` durability checkpoint for `session`, + * with the carrier captured at {@link enter}. THE flush entry point: the + * store owns the carrier, so callers (the checkpoint policy's per-request + * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers + * that flush themselves before reading storage) must come through here + * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner, + * one spelling, and the scoped-dispatch invariant can pin it. + * @param session - the session whose buffered events must reach durable storage. + * @returns whether at least one durability listener participated, after every + * listener has settled successfully. + * @throws the first registered listener failure after every listener settles. + */ + flush(session: Session): Promise; + /** Return the exact live entry; detached/prepared objects reject. */ + private liveEntryFor; + /** + * Look up a live session. + * @param id - the session id to look up. + * @returns the session, or undefined when no live session has that id. + */ + get(id: SessionId): Session | undefined; + /** + * All live sessions, in creation order. + * @returns a fresh array; mutating it does not affect the store. + */ + list(): Session[]; + /** + * Create a live child session from a stable prefix of a live source. + * `boundary` is an inclusive source event seq; omitted means the source's + * current last event. The selected slice may end with a between-turn event + * but must not end inside an open turn. + * + * @param source - Live source session object or id. + * @param boundary - Inclusive source event seq to fork through; omitted means + * the source's current last event, and omitted on an empty source forks an + * empty child. + * @param childSessionId - Optional child session id; omitted delegates to + * `SessionStore`'s id policy. + * @returns The created live child session. + */ + fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Session; + private _forkSeed; + private _resolveForkSource; +} +export default SessionStore; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/index.js new file mode 100644 index 0000000..673a13b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/index.js @@ -0,0 +1,999 @@ +/** + * Event-sourced session service: append-only session log, in-memory store, and + * the derived LLM message history. Persistence is a plugin concern (subscribe + * to `session/event`, drain on `session/flush`). + * + * @module @deepseek-ai/dsh-session + */ +import { Service } from '@deepseek-ai/cordis'; +import { isAbsolute } from 'node:path'; +import { deepFreeze } from '@deepseek-ai/dsh-llm'; +import { scopeOf, scopeTarget } from '@deepseek-ai/dsh-scope'; +import { SESSION_FORMAT_VERSION, SessionId } from "./types.js"; +import { snapshotJsonValue } from "./json.js"; +import { deriveEventMessage, SurfaceManager } from "./surface.js"; +import { foldRequestHeader } from "./request-header.js"; +export * from "./types.js"; +export { SessionPreparation } from "./preparation.js"; +export { isJsonValue, snapshotJsonValue } from "./json.js"; +export { interruptedTurnClosers, TOOL_NOT_STARTED, TOOL_OUTCOME_UNKNOWN } from "./repair.js"; +export { decodeStorageRecord, packChunkRuns } from "./chunk-rows.js"; +export { deriveEventMessage, foldSurface, isAppendSurfaceEvent, isReplacementSurfaceEvent, isSurfaceEvent, isSurfaceEligibleType } from "./surface.js"; +export { canonicalHeader, foldRequestHeader, headerEquals } from "./request-header.js"; +export { KNOWN_SESSION_EVENT_TYPES } from "./known-event-types.js"; +/** Validate and freeze one detached creation header in place. */ +function validateSessionHeader(id, input) { + if (input === null || typeof input !== 'object' || Array.isArray(input)) { + throw new Error('session header is not a plain JSON record'); + } + const record = input; + if (record.version !== SESSION_FORMAT_VERSION) { + throw new Error(`session header version must be ${SESSION_FORMAT_VERSION}, got ${String(record.version)}`); + } + if (record.id !== id) { + throw new Error(`session header id "${String(record.id)}" does not match session id "${id}"`); + } + if (typeof record.createdAt !== 'number' + || !Number.isSafeInteger(record.createdAt) + || record.createdAt < 0) { + throw new Error('session header createdAt must be a non-negative safe integer'); + } + if (record.cwd !== undefined) { + if (typeof record.cwd !== 'string') + throw new Error('session header cwd must be a string'); + if (!isAbsolute(record.cwd)) { + throw new Error(`session header cwd must be an absolute path, got "${record.cwd}"`); + } + } + if (record.parentSession !== undefined && typeof record.parentSession !== 'string') { + throw new Error('session header parentSession must be a string'); + } + if (record.seedLength !== undefined + && (typeof record.seedLength !== 'number' || !Number.isSafeInteger(record.seedLength) || record.seedLength < 0)) { + throw new Error('session header seedLength must be a non-negative safe integer'); + } + if (record.origin !== undefined && record.origin !== 'subagent') { + throw new Error('session header origin must be "subagent"'); + } + if (record.delegationDepth !== undefined + && (typeof record.delegationDepth !== 'number' || !Number.isSafeInteger(record.delegationDepth) || record.delegationDepth < 0)) { + throw new Error('session header delegationDepth must be a non-negative safe integer'); + } + if (record.agentPreset !== undefined && typeof record.agentPreset !== 'string') { + throw new Error('session header agentPreset must be a string'); + } + return deepFreeze(record); +} +/** Validate and freeze one exclusively owned persistence header in place. */ +function validateRestoredSessionHeader(id, input) { + if (input !== null && typeof input === 'object' && !Array.isArray(input)) { + const prototype = Reflect.getPrototypeOf(input); + if (prototype !== Object.prototype && prototype !== null) { + throw new Error('session header is not a plain JSON record'); + } + } + return validateSessionHeader(id, input); +} +/** Detach, validate, and freeze the creation metadata published by a session. */ +function snapshotSessionHeader(id, source) { + const input = source === undefined + ? { version: SESSION_FORMAT_VERSION, id, createdAt: Date.now() } + : source; + const snapshot = snapshotJsonValue(input); + if (snapshot === undefined) + throw new Error('session header is not losslessly JSON-serializable'); + return validateSessionHeader(id, snapshot); +} +/** + * Validate an exclusively owned event and deeply freeze its identified message + * without copying the event. The caller transfers an object graph that no + * producer retains and that shares no mutable children with another event. + * Use {@link snapshotSessionEvent} when exclusive ownership is not guaranteed. + * @param event - exclusively owned event imported across a trusted boundary. + * @returns the same event object with a validated, deeply frozen message. + */ +export function adoptSessionEvent(event) { + assertMessageEventShape(event, `session event at seq ${event.seq}`); + switch (event.type) { + case 'user/message': + deepFreeze(event.data); + break; + case 'assistant/message': + case 'tool/result': + deepFreeze(event.data.message); + break; + default: + // SessionEventMap is merge-extensible; plugin-owned events carry no core message. + break; + } + return event; +} +/** + * Detach one event while preserving deep immutability for its identified message. + * @param event - event imported across a query or persistence boundary. + * @returns a detached event snapshot with a validated, deeply frozen message. + */ +export function snapshotSessionEvent(event) { + return adoptSessionEvent(structuredClone(event)); +} +/** Deep-freeze one acyclic JSON tree without consuming the JavaScript call stack. */ +function freezeRestoredObject(value) { + const pending = [value]; + while (pending.length > 0) { + // The non-empty check proves an object remains to visit. + // oxlint-disable-next-line typescript/no-non-null-assertion + const current = pending.pop(); + Object.freeze(current); + for (const key in current) { + const child = current[key]; + if (child !== null && typeof child === 'object') + pending.push(child); + } + } + return value; +} +/** Validate the fixed event envelope after one-pass JSON materialization. */ +function assertSessionEventEnvelope(value, index) { + const event = value; + if (event['type'] === 'request/header-delta') { + throw new Error(`seed event at index ${index} uses unsupported legacy request/header-delta format`); + } + for (const key in event) { + switch (key) { + case 'type': + case 'seq': + case 'time': + case 'data': + case 'surfaceOp': + case 'sourceEventSeqs': + case 'ignorable': + break; + default: + throw new Error(`seed event at index ${index} has an invalid event envelope`); + } + } + const type = event['type']; + const seq = event['seq']; + const time = event['time']; + if (typeof type !== 'string' + || typeof seq !== 'number' || !Number.isSafeInteger(seq) || seq < 0 + || typeof time !== 'number' || !Number.isSafeInteger(time) + || event['data'] === undefined + || (event['ignorable'] !== undefined && event['ignorable'] !== true)) { + throw new Error(`seed event at index ${index} has an invalid event envelope`); + } + switch (type) { + case 'request/header': + case 'user/message': + case 'assistant/message': + case 'tool/result': + assertCurrentLlmShape(event, index); + break; + } +} +/** Reject obsolete request headers and malformed messages at the seed/load boundary. */ +function assertCurrentLlmShape(event, index) { + const data = event['data']; + const record = typeof data === 'object' && data !== null + ? data + : undefined; + if (event['type'] === 'request/header') { + const header = record?.['header']; + const headerRecord = typeof header === 'object' && header !== null && !Array.isArray(header) + ? header + : undefined; + const config = headerRecord?.['config']; + if (!hasProviderModel(config)) + throw new Error(`seed request/header at index ${index} lacks provider/model`); + const configRecord = config; + const reasoningEffort = configRecord['reasoningEffort']; + if (reasoningEffort !== undefined + && (typeof reasoningEffort !== 'string' || reasoningEffort.length === 0)) { + throw new Error(`seed request/header at index ${index} has an invalid reasoningEffort`); + } + assertAdapterDefaults(headerRecord?.['adapterDefaults'], configRecord, index); + } + const type = event['type']; + if (type !== 'user/message' && type !== 'assistant/message' + && type !== 'tool/result') + return; + assertMessageEventShape(event, `seed ${type} at index ${index}`); +} +const allowedAdapterKeys = new Set(['reasoningEffort', 'maxTokens']); +/** Validate adapter-default markers imported from a durable request header. */ +function assertAdapterDefaults(value, config, index) { + if (value === undefined) + return; + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + throw new Error(`seed request/header at index ${index} has invalid adapterDefaults`); + } + const defaults = value; + if (Object.keys(defaults).some(key => !allowedAdapterKeys.has(key)) + || Object.values(defaults).some(marker => marker !== true) + || defaults['reasoningEffort'] === true && config['reasoningEffort'] === undefined + || defaults['maxTokens'] === true && config['maxTokens'] === undefined) { + throw new Error(`seed request/header at index ${index} has invalid adapterDefaults`); + } +} +/** Validate only the event-specific invariants needed to safely replay a message. */ +function assertMessageEventShape(event, subject) { + const type = event['type']; + if (type !== 'user/message' && type !== 'assistant/message' + && type !== 'tool/result') + return; + const data = event['data']; + const record = typeof data === 'object' && data !== null + ? data + : undefined; + const message = type === 'user/message' ? record : record?.['message']; + if (typeof message !== 'object' || message === null + || typeof message['id'] !== 'string' + || message['id'] === '') { + throw new Error(`${subject} lacks an identified message`); + } + const messageRecord = message; + const expectedRole = type === 'assistant/message' ? 'assistant' : 'user'; + if (messageRecord['role'] !== expectedRole) { + throw new Error(`${subject} message must have role "${expectedRole}"`); + } + const source = messageRecord['source']; + if (typeof source !== 'object' || source === null + || typeof source['kind'] !== 'string' + || source['kind'] === '') { + throw new Error(`${subject} message has invalid source`); + } + if (!Array.isArray(messageRecord['content'])) { + throw new Error(`${subject} message has invalid content`); + } + const sourceRecord = source; + if (type === 'assistant/message') { + if (sourceRecord['kind'] !== 'model' || !hasProviderModel(sourceRecord)) { + throw new Error(`${subject} message must have model source`); + } + return; + } + if (type !== 'tool/result') + return; + if (sourceRecord['kind'] !== 'tool' + || typeof sourceRecord['callId'] !== 'string' + || sourceRecord['callId'] === '') { + throw new Error(`${subject} message must have tool source`); + } + const content = messageRecord['content']; + const block = content[0]; + if (content.length !== 1 || typeof block !== 'object' || block === null + || block['type'] !== 'tool-result' + || !Array.isArray(block['content'])) { + throw new Error(`${subject} message must contain one tool-result block`); + } + if (block['toolCallId'] !== sourceRecord['callId']) { + throw new Error(`${subject} message has mismatched tool call ids`); + } +} +/** Whether an unknown value carries the current provider/model pair. */ +function hasProviderModel(value) { + if (typeof value !== 'object' || value === null) + return false; + const pair = value; + return typeof pair['provider'] === 'string' && pair['provider'].length > 0 + && typeof pair['model'] === 'string' && pair['model'].length > 0; +} +/** Reject request-header vocabulary removed with the legacy delta codec. */ +function assertSupportedRequestHeader(type, data, location) { + if (type === 'request/header-delta') { + throw new Error(`${location} uses unsupported legacy request/header-delta format`); + } + if (type === 'request/header' + && data !== null && typeof data === 'object' && !Array.isArray(data) + && data['reason'] === 'fallback') { + throw new Error(`${location} uses unsupported legacy request/header reason "fallback"`); + } +} +/** Resolve one listener snapshot, including Cordis's internal dispatch checks. */ +function collectSessionCallbacks(ctx, args) { + return [...ctx.events.dispatch('emit', args)]; +} +/** Invoke one resolved observe-only listener snapshot with per-listener containment. */ +function invokeContainedSessionObservers(ctx, name, id, args, callbacks) { + for (const callback of callbacks) { + try { + const returned = callback(...args); + void Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`session "${id}": ${name} listener rejected: ${String(error)}`); + }); + } + catch (error) { + ctx.logger.warn(`session "${id}": ${name} listener threw: ${String(error)}`); + } + } +} +/** Store attachment for the append path; module-private to keep Session store-agnostic publicly. */ +const attachments = new WeakMap(); +/** + * An event-sourced session: an append-only log of {@link SessionEvent}s. + * + * Plain class (not a Service) — create live instances via + * `ctx.sessions.create()` and detached instances via {@link create}. + * Seeding with an existing event log replays/forks a session. + * @typert object + */ +export class Session { + log = []; + /** Single incremental owner of surface acceptance and projection state. */ + surfaceManager = new SurfaceManager(this.log); + /** The ordered surface over this session's event log. */ + get surface() { + return this.surfaceManager; + } + /** + * Detached, deep-frozen creation metadata (format version, cwd, lineage, + * seed boundary). Supplied by the store via `ctx.sessions.create()`. When a + * `Session` is created without a store-owned header, a minimal header is + * synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so + * `session.header` is always present. Kept out of the event log — it is a + * storage concern, not replayable conversation state. + */ + header; + /** The session identity, derived from its durable header's single copy. */ + get id() { + return this.header.id; + } + /** + * The first seq appended IN THIS PROCESS: the length of the constructor + * seed (0 without one). Events with smaller seq values entered through + * construction — replay, fork, or resume — and were never published on the + * `session/event` firehose (constructor seeds do not emit), so consumers + * that replay the log as a publication substitute (telemetry adoption) + * start here. Distinct from `header.seedLength`, the DURABLE fork-lineage + * boundary: a resumed session's constructor seed is its full stored log, + * while its header keeps the original fork value — this field is the + * in-process construction fact. + * + * Not persisted itself: a seeded session projects it into the log as the + * `session/end-seed` event, which is what a consumer reading STORED history + * reads. Locate the LAST such event, not necessarily one at this seq — a + * seed already ending in one is not re-marked, so reopening an untouched + * session leaves that event at a smaller seq than `firstLiveSeq`. Prefer + * this field in-process: it is exact before the marker reaches storage. + * + * When this lifecycle appends the marker, it occupies this seq before the + * store attaches and therefore does not publish either. Otherwise this seq + * holds an ordinary published write. + */ + firstLiveSeq; + /** + * Create a detached session by validating and snapshotting borrowed seed + * events and storage metadata. + * @param id - session identity. + * @param seed - optional borrowed replay or fork events. + * @param header - optional borrowed storage metadata. + * @returns a detached session. + */ + static create(id, seed, header) { + return new Session(id, seed, header); + } + /** + * Restore a detached session by taking ownership of fresh persistence values. + * The storage format, event envelopes, sequence continuity, surface transitions, + * and header fields are validated before the restored objects are frozen. + * @param id - restored session identity. + * @param seed - fresh detached events whose ownership is transferred. + * @param header - fresh detached metadata whose ownership is transferred. + * @returns a restored detached session. + */ + static fromRestore(id, seed, header) { + return new Session(id, seed, header, 'restore'); + } + constructor(id, seed, header, mode = 'snapshot') { + const restoredHeader = mode === 'restore' + ? validateRestoredSessionHeader(id, header) + : undefined; + if (seed !== undefined) { + // Validate the seed to the SAME invariants `append` enforces, so a + // replay/fork (`ctx.sessions.create(id, { seed })`) cannot construct a + // live log that no persistence backend could store: each event's `data` + // must be JSON-serializable, and `seq` must be contiguous from 0 (the + // `seq = log.length` contract the whole system relies on). Without this, + // a bad seed would surface only later as a backend rejection or a silent + // divergence between the live log and disk. + for (const [index, source] of seed.entries()) { + // The seed is a persistence/replay boundary: validate and detach the + // complete event in one lossless-JSON pass. + const snapshot = mode === 'restore' ? source : snapshotJsonValue(source); + if (snapshot === undefined) { + throw new Error(`seed event at index ${index} is not losslessly JSON-serializable`); + } + assertSessionEventEnvelope(snapshot, index); + assertSupportedRequestHeader(snapshot.type, snapshot.data, `seed event at index ${index}`); + if (snapshot.seq !== index) { + throw new Error(`seed event at index ${index} has seq ${snapshot.seq} (expected ${index}); seed must be contiguous from 0`); + } + // A seed is accepted incrementally through the same transition as a + // live append and a full-log fold. The candidate is planned before it + // enters `log`, so a failure cannot partially mutate the surface. + try { + this.surfaceManager.validateNext(snapshot); + } + catch (error) { + throw new Error(`invalid seed event at index ${index}: ${error instanceof Error ? error.message : 'invalid surface metadata'}`); + } + this.log.push(mode === 'restore' ? freezeRestoredObject(snapshot) : deepFreeze(snapshot)); + } + } + this.firstLiveSeq = this.log.length; + this.header = restoredHeader ?? snapshotSessionHeader(id, header); + // Appended here so the marker is already in `events` when a backend + // captures the creation seed: no load-time write. Re-marking is skipped + // because a cold session is resumed on first touch, so repeatedly opening + // one must not grow its log per open. + if (seed !== undefined && this.log.at(-1)?.type !== 'session/end-seed') { + this.append('session/end-seed', {}); + } + } + /** Cached immutable public snapshot of the private append-only log. */ + eventsSnapshot; + /** + * An immutable snapshot of the append-only event log. The snapshot is reused + * until the next append; a previously returned array does not grow later. + * Events and their nested data are deep-frozen at acceptance, so neither a + * cast nor ordinary JavaScript can rewrite durable history. + */ + get events() { + this.eventsSnapshot ??= Object.freeze([...this.log]); + return this.eventsSnapshot; + } + /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */ + get seq() { + return this.log.length; + } + /** + * Append one typed event to the log and synchronously notify observers via + * the store-owned, module-private publication hooks. The hot path never blocks + * on I/O — persistence plugins buffer asynchronously. Once the event enters + * the log, the append is committed: observer failures are logged and + * contained per listener, so they do not change the return value or prevent + * later listeners from observing the same accepted event. + * + * @param type - The event type (key of {@link SessionEventMap}). + * @param data - The event payload; must be JSON-serializable. + * @param opts - Surface metadata: `surfaceOp` controls how the event enters + * the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier + * events this one derives from. REQUIRED for + * {@link SurfaceEventType} events (every message-producing event must + * declare how it joins the surface, the sole source of derived model + * history) and + * rejected by the compiler for non-surface types like `turn/start` or + * `assistant/chunk`. + * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of + * `data` that entered the log, so reading `event.data` back sees the logged + * value, never the caller's still-mutable input. + * @throws if `data` or surface metadata is not losslessly JSON-serializable + * (BigInt, function, symbol, undefined, negative zero, non-finite number, + * circular reference, sparse array, or an exotic object such as + * Map/Set/Date/class instance), or when the candidate violates the + * canonical surface contract (marker shape and eligibility, unique + * earlier source-event references, positional replacement validity, and complete + * shadowed-node coverage). One recursive pass reads, validates, and + * copies each nested value once, so a stateful getter cannot supply one value + * to validation and another to storage. The event log is the durable source + * of truth, so a bad event fails at the append site rather than later during + * a backend flush. A synchronous internal dispatch validation failure or an + * append reentered while this acceptance/publication boundary is open also + * rejects before the log changes. + */ + append(type, data, ...opts) { + const surfaceOpts = opts[0]; + const surfaceMetadata = { + ...surfaceOpts?.sourceEventSeqs === undefined ? {} : { sourceEventSeqs: surfaceOpts.sourceEventSeqs }, + ...surfaceOpts?.surfaceOp === undefined ? {} : { surfaceOp: surfaceOpts.surfaceOp }, + }; + const dataSnapshot = snapshotJsonValue(data); + if (dataSnapshot === undefined) { + throw new Error(`session event "${type}" carries non-JSON-serializable data`); + } + assertSupportedRequestHeader(type, dataSnapshot, `session event "${type}"`); + const surfaceMetadataSnapshot = snapshotJsonValue(surfaceMetadata); + if (surfaceMetadataSnapshot === undefined) { + throw new Error(`session event "${type}" carries non-JSON-serializable surface metadata`); + } + const entry = attachments.get(this); + if (entry?.appending) { + throw new Error('session append cannot reenter while another append is being published'); + } + const event = deepFreeze({ + type, + seq: this.log.length, + time: Date.now(), + data: dataSnapshot, + ...surfaceMetadataSnapshot, + }); + this.surfaceManager.validateNext(event); + if (entry !== undefined) + entry.appending = true; + try { + let callbacks; + const callbackArgs = [this, event]; + if (entry !== undefined) { + callbacks = collectSessionCallbacks(entry.emitCtx, [entry.carrier, 'session/event', ...callbackArgs]); + } + this.log.push(event); + this.eventsSnapshot = undefined; + if (callbacks !== undefined && entry !== undefined) { + invokeContainedSessionObservers(entry.emitCtx, 'session/event', entry.id, callbackArgs, callbacks); + } + return event; + } + finally { + if (entry !== undefined) { + entry.appending = false; + if (entry.detachRequested && !entry.announcing) + entry.detach(); + } + } + } + /** Cached fold of the request-header events — see {@link requestHeader}. */ + headerFold; + /** Log position (events consumed) the header fold has reached. */ + headerFoldSeq = 0; + /** + * The {@link EpochHeader} in force after the log's last header event — the + * header the NEXT request will be compared against — or undefined before + * the first `request/header` snapshot. The live, incrementally-maintained + * form of `foldRequestHeader(session.events)`: each header event is folded + * once, when first seen, so a per-step read costs O(new events). + * @returns the folded header, or undefined when no header event exists yet. + */ + requestHeader() { + if (this.headerFoldSeq < this.log.length) { + // Frozen on update: the fold is session state exposed by reference — a + // consumer mutating it in place (instead of building a replacement) + // would desync every later comparison against the log, so mutation + // throws instead. + this.headerFold = deepFreeze(foldRequestHeader(this.log.slice(this.headerFoldSeq), this.headerFold)); + this.headerFoldSeq = this.log.length; + } + return this.headerFold; + } + /** Cached fold of `request/context` events. */ + contextFold; + contextFoldSeq = 0; + /** + * Return the latest resolved route metadata, or `undefined` before the first + * `request/context` event. Each event is folded once. + * @returns the latest immutable route metadata. + */ + requestContext() { + if (this.contextFoldSeq < this.log.length) { + for (const event of this.log.slice(this.contextFoldSeq)) { + if (event.type === 'request/context') + this.contextFold = deepFreeze({ ...event.data }); + } + this.contextFoldSeq = this.log.length; + } + return this.contextFold; + } + /** The derived-message cache: frozen projections, extended per unseen node. */ + derived = []; + /** Surface position (nodes projected) the cache has reached. */ + derivedNodes = 0; + /** {@link SurfaceManager.replaceGeneration} the cache was built under. */ + derivedGeneration = 0; + /** + * Derive the LLM message history by walking the ordered sequences of + * message-producing events maintained by `surfaceOp` markers. The + * surface is the single source of derived history: every message-producing + * append records its `surfaceOp`, so a raw event with no marker (a chunk, a + * turn boundary) is correctly absent, and a compaction `replace` deletes the + * shadowed nodes from the derivation. The projection rules are + * {@link deriveEventMessage}, folded per node. + * + * CACHED: each surface node is projected exactly once, when first seen — a + * call costs O(new nodes), and a surface rewrite (a `replace`; + * {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is + * a fresh snapshot per call (later appends never grow an array a caller + * already holds); the `Message` objects in it are SHARED and **deep-frozen**. + * Their content reuses the already frozen durable event data, so the cache + * needs no second deep clone and consumers still cannot mutate the log. + * @returns a fresh array of the shared, frozen derived history. + */ + deriveMessages() { + const surface = this.surface; + const nodes = surface.nodes; + const generation = surface.replaceGeneration; + if (generation !== this.derivedGeneration) { + this.derived = []; + this.derivedNodes = 0; + this.derivedGeneration = generation; + } + for (const seq of nodes.slice(this.derivedNodes)) { + // Surface sequences are built from this.log — seq is always a valid + // index by construction. The non-null assertion expresses that invariant. + // oxlint-disable-next-line typescript/no-non-null-assertion + const msg = this.deriveEventMessage(this.log[seq]); + // A surface node is one of the five message-producing types, but an + // empty-content assistant/message (a max-tokens step that hosts only + // usage) derives to null and must not enter the transcript. + if (msg) + this.derived.push(msg); + } + this.derivedNodes = nodes.length; + return [...this.derived]; + } + /** + * Instance face of the pure per-node `deriveEventMessage` export from + * `surface.ts`. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ + deriveEventMessage(event) { + return deriveEventMessage(event); + } +} +/** Typed error for session fork rejections. */ +export class SessionForkError extends Error { + code; + constructor(message, code) { + super(message); + this.code = code; + this.name = 'SessionForkError'; + } +} +/** + * In-memory session store (`ctx.sessions`). + * + * Persistence is intentionally not implemented here — persistence plugins + * subscribe to `session/event` and flush on `session/flush` / dispose. + */ +export class SessionStore extends Service { + store = new Map(); + counter = 0; + constructor(ctx) { + super(ctx, 'sessions'); + ctx.inject(['typert'], (typeCtx) => { + typeCtx.typert.lookups.register('session', { + parameter: 'session', + wire: 'sessionId', + hostTypeSymbol: '@deepseek-ai/dsh-session#Session', + wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId', + resolve: sessionId => this.get(sessionId), + }); + }); + } + /** + * Create a session owned by the calling fiber: disposing that fiber stops + * event notification and removes the session from the store. `options.seed` + * populates the session with a copy of those events (replay/fork); + * `options.meta` attaches creation metadata (validated absolute `cwd`, seed + * and parent lineage, and delegation depth) as the immutable + * {@link SessionHeader} (the store fills `version`/`id`/`createdAt`). + * + * For an agent whose session must be torn down IN ORDER with its loop (so the + * loop's final events are published before the store attachment ends), do NOT use this + * — fold the session lifecycle into the agent's own effect via + * {@link prepare} + {@link enter} + {@link announce} (see + * `dsh-agent-loop`'s creation transaction). + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. + * @returns the live session, already entered and announced. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path (storage backends key directories off it). + */ + create(id, options) { + const session = this.prepare(id, options); + // Single effect owned by the calling fiber. Yield the detach BEFORE + // announcing so a throwing `session/created` listener rolls the attach back + // (the generator effect disposes already-yielded disposers on a throw) + // instead of leaking the store entry and its publication hooks. + this.ctx.effect(function* () { + yield this.enter(session); + this.announce(session); + }.bind(this), 'sessions.create()'); + return session; + } + /** + * Build a session WITHOUT entering it into the store — validate the id/cwd and + * construct the {@link Session} (with its immutable {@link SessionHeader}). + * Pairs with {@link enter} + {@link announce}: a caller that owns a composite + * `ctx.effect` (the agent factory) folds the session lifecycle into that ONE + * effect so a fiber unload tears the session + agent down as a single ORDERED + * chain rather than as racing sibling effects — which would remove the publication hooks + * before the driver's closing events commit, dropping them. + * + * @param id - the session id; omitted, the store mints `session-`. + * @param options - seed events and/or creation metadata for the header. With + * `seedSource: 'persistence'`, metadata and events must be fresh detached + * graphs whose ownership transfers to this call: they are validated and + * frozen in place through {@link Session.fromRestore}, so the caller must + * retain no mutable aliases. + * @returns the constructed session, NOT yet in the store. + * @throws if a session with `id` already exists, metadata is not a plain + * lossless-JSON record with valid scalar fields, or `meta.cwd` is a + * non-absolute path. + */ + prepare(id, options) { + let sessionId; + if (id === undefined) { + do + sessionId = SessionId(`session-${++this.counter}`); + while (this.store.has(sessionId)); + } + else { + sessionId = SessionId(id); + } + if (this.store.has(sessionId)) + throw new Error(`session "${sessionId}" already exists`); + if (options?.seedSource === 'persistence') { + return Session.fromRestore(sessionId, options.seed, options.meta); + } + const seed = options?.seed; + const meta = options?.meta; + const header = { + version: SESSION_FORMAT_VERSION, + id: sessionId, + createdAt: meta?.createdAt ?? Date.now(), + ...meta?.cwd === undefined ? {} : { cwd: meta.cwd }, + ...meta?.parentSession === undefined ? {} : { parentSession: meta.parentSession }, + ...meta?.seedLength === undefined ? {} : { seedLength: meta.seedLength }, + ...meta?.origin === undefined ? {} : { origin: meta.origin }, + ...meta?.delegationDepth === undefined ? {} : { delegationDepth: meta.delegationDepth }, + ...meta?.agentPreset === undefined ? {} : { agentPreset: meta.agentPreset }, + }; + return Session.create(sessionId, seed, header); + } + /** + * Enter a {@link prepare}d session into the store: install the module-private + * append publication hooks and add it to the store. Returns the DETACH + * disposer (hooks + store removal). Does NOT emit `session/created` — + * the caller yields this disposer inside its effect and THEN calls + * {@link announce}, so a throwing `session/created` listener rolls the attach + * back instead of leaking it. + * + * Re-checks the id for a duplicate: `prepare` and `enter` are public + * cross-package primitives and a caller may interleave arbitrary work (or + * another create) between them, so a stale prepared session must NOT overwrite + * a live store entry of the same id — its detach disposer would later delete + * the REAL session. The {@link create} convenience and the agent factory call + * the two back-to-back so they never trip this, but the public API cannot + * assume that. + * + * @param session - a {@link prepare}d session not yet in the store. + * @returns the detach disposer (publication hooks + store removal). When called from + * a synchronous `session/created` listener, removal and disposal wait until + * that creation dispatch unwinds. + * @throws if a session with this id is already in the store. + */ + enter(session) { + const id = session.id; + const carrier = scopeTarget(session, scopeOf(this.ctx)); + // This is the authoritative collision boundary after arbitrary unpublished + // preparation. Only one exact same-id transaction can publish. + if (this.store.has(id)) + throw new Error(`session "${id}" already exists`); + if (attachments.has(session)) + throw new Error(`session "${id}" is already attached to a store`); + const entry = { + id, + session, + carrier, + emitCtx: this.ctx, + announced: false, + announcing: false, + appending: false, + detachRequested: false, + detach: () => { this.detachEntered(entry); }, + }; + this.store.set(id, entry); + attachments.set(session, entry); + let entered = true; + const detach = () => { + if (!entered) + return; + entered = false; + // A lifecycle listener may own the advanced detach capability. Keep the + // entry and its publication hooks live until synchronous creation or append + // publication unwinds, then publish the paired disposal edge. + if (entry.announcing || entry.appending) { + entry.detachRequested = true; + return; + } + entry.detach(); + }; + return detach; + } + /** Remove one exact entered session and emit its paired disposal when announced. */ + detachEntered(entry) { + entry.detachRequested = false; + // A stale capability cannot remove observers or storage belonging to a + // later same-id lifecycle. + /* v8 ignore next -- enter() rejects replacement while this single-shot detach capability is live. */ + if (this.store.get(entry.id) !== entry) + return; + this.store.delete(entry.id); + attachments.delete(entry.session); + if (entry.announced) + this.emitDisposed(entry); + } + /** Emit `session/created` exactly once for an {@link enter}ed session (with + * the carrier {@link enter} captured). Separate from {@link enter} so the + * caller can yield the detach disposer first (rollback safety — see + * {@link enter}). + * @param session - the entered session to announce to listeners. + * @throws if the session is not live or its announcement already began, + * including a reentrant call from a creation listener. */ + announce(session) { + const entry = this.liveEntryFor(session); + if (entry.announced || entry.announcing) { + throw new Error(`session "${entry.id}" was already announced`); + } + // Mark before emit: Cordis emit may deliver to earlier listeners and then + // throw. Rollback must still pair that partial creation with disposal, and + // a listener cannot recursively create a second lifecycle edge. + entry.announced = true; + const callbackArgs = [session]; + entry.announcing = true; + try { + const callbacks = collectSessionCallbacks(this.ctx, [entry.carrier, 'session/created', session]); + for (const callback of callbacks) { + // Synchronous throws intentionally propagate and veto publication; the + // yielded detach then emits the paired disposal edge. An async function + // is nevertheless assignable to a void listener, so observe its returned + // promise: rejection is too late to roll back and must be logged instead + // of becoming unhandled. + const returned = callback(...callbackArgs); + void Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`session "${entry.id}": session/created listener rejected: ${String(error)}`); + }); + } + } + finally { + entry.announcing = false; + if (entry.detachRequested && !entry.appending) + entry.detach(); + } + } + /** Emit the paired teardown notification with per-listener containment. */ + emitDisposed(entry) { + const callbackArgs = [entry.session]; + try { + const callbacks = collectSessionCallbacks(this.ctx, [entry.carrier, 'session/disposed', entry.session]); + invokeContainedSessionObservers(this.ctx, 'session/disposed', entry.id, callbackArgs, callbacks); + } + catch (error) { + this.ctx.logger.warn(`session "${entry.id}": session/disposed dispatch threw: ${String(error)}`); + } + } + /** + * Dispatch the awaited `session/flush` durability checkpoint for `session`, + * with the carrier captured at {@link enter}. THE flush entry point: the + * store owns the carrier, so callers (the checkpoint policy's per-request + * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers + * that flush themselves before reading storage) must come through here + * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner, + * one spelling, and the scoped-dispatch invariant can pin it. + * @param session - the session whose buffered events must reach durable storage. + * @returns whether at least one durability listener participated, after every + * listener has settled successfully. + * @throws the first registered listener failure after every listener settles. + */ + async flush(session) { + const { carrier } = this.liveEntryFor(session); + const callbackArgs = [session]; + const callbacks = collectSessionCallbacks(this.ctx, [carrier, 'session/flush', session]); + const results = await Promise.allSettled(callbacks.map((callback) => { + try { + return callback(...callbackArgs); + } + catch (error) { + // Preserve the listener's exact rejection value; flush is a caller-owned + // failure boundary, and Cordis listeners may throw arbitrary values. + // oxlint-disable-next-line typescript/prefer-promise-reject-errors + return Promise.reject(error); + } + })); + const failure = results.find((result) => result.status === 'rejected'); + if (failure !== undefined) + throw failure.reason; + return callbacks.length > 0; + } + /** Return the exact live entry; detached/prepared objects reject. */ + liveEntryFor(session) { + const entry = attachments.get(session); + if (entry === undefined || this.store.get(entry.id) !== entry) { + throw new Error(`session "${session.id}" is not live in this store`); + } + return entry; + } + /** + * Look up a live session. + * @param id - the session id to look up. + * @returns the session, or undefined when no live session has that id. + */ + get(id) { + return this.store.get(id)?.session; + } + /** + * All live sessions, in creation order. + * @returns a fresh array; mutating it does not affect the store. + */ + list() { + return [...this.store.values()].map(entry => entry.session); + } + /** + * Create a live child session from a stable prefix of a live source. + * `boundary` is an inclusive source event seq; omitted means the source's + * current last event. The selected slice may end with a between-turn event + * but must not end inside an open turn. + * + * @param source - Live source session object or id. + * @param boundary - Inclusive source event seq to fork through; omitted means + * the source's current last event, and omitted on an empty source forks an + * empty child. + * @param childSessionId - Optional child session id; omitted delegates to + * `SessionStore`'s id policy. + * @returns The created live child session. + */ + fork(source, boundary, childSessionId) { + if (childSessionId !== undefined && this.get(childSessionId) !== undefined) { + throw new SessionForkError(`session "${childSessionId}" already exists`, 'SESSION_ALREADY_EXISTS'); + } + const liveSource = this._resolveForkSource(source); + const seed = this._forkSeed(liveSource, boundary); + return this.create(childSessionId, { + seed, + meta: { + ...liveSource.header.cwd !== undefined ? { cwd: liveSource.header.cwd } : {}, + parentSession: liveSource.id, + seedLength: seed.length, + }, + }); + } + _forkSeed(session, requestedBoundary) { + const events = session.events; + const lastEvent = events.at(-1); + let boundary; + if (requestedBoundary !== undefined) { + boundary = requestedBoundary; + } + else { + if (lastEvent === undefined) + return []; + boundary = lastEvent.seq; + } + if (!Number.isSafeInteger(boundary) || boundary < 0) { + throw new SessionForkError(`fork boundary for session "${session.id}" must be a non-negative safe integer, got ${String(boundary)}`, 'INVALID_BOUNDARY'); + } + if (boundary >= events.length) { + const lastSeq = events.at(-1)?.seq; + throw new SessionForkError(`fork boundary ${boundary} does not exist in session "${session.id}" (last seq: ${lastSeq ?? 'none'})`, 'INVALID_BOUNDARY'); + } + const boundaryEvent = events[boundary]; + if (boundaryEvent === undefined || boundaryEvent.seq !== boundary) { + throw new SessionForkError(`fork boundary ${boundary} does not match a contiguous event seq in session "${session.id}"`, 'INVALID_BOUNDARY'); + } + const lastTurnBoundary = events.slice(0, boundary + 1) + .findLast(event => event.type === 'turn/start' || event.type === 'turn/end'); + if (lastTurnBoundary?.type === 'turn/start') { + throw new SessionForkError(`fork boundary ${boundary} in session "${session.id}" ends inside open turn ${lastTurnBoundary.data.turn}`, 'OPEN_TURN'); + } + return events.slice(0, boundary + 1); + } + _resolveForkSource(source) { + if (typeof source === 'string') { + const session = this.get(source); + if (session === undefined) + throw new SessionForkError(`session "${source}" not found`, 'SESSION_NOT_FOUND'); + return session; + } + const live = this.get(source.id); + if (live === undefined) { + throw new SessionForkError(`session "${source.id}" not found`, 'SESSION_NOT_FOUND'); + } + if (live !== source) + throw new SessionForkError(`session "${source.id}" is not the live store instance`, 'SESSION_NOT_LIVE'); + return source; + } +} +export default SessionStore; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.d.ts new file mode 100644 index 0000000..6652847 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.d.ts @@ -0,0 +1,18 @@ +/** + * Package-owned relational invariants for the session event log. Load this + * companion beside `@deepseek-ai/dsh-invariants` to enable the checks. + * + * @module @deepseek-ai/dsh-session/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "session-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the session invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.js new file mode 100644 index 0000000..c685d9f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/invariant.js @@ -0,0 +1,199 @@ +/** + * Package-owned relational invariants for the session event log. Load this + * companion beside `@deepseek-ai/dsh-invariants` to enable the checks. + * + * @module @deepseek-ai/dsh-session/invariant + */ +import { assertNever } from '@deepseek-ai/dsh-llm'; +import { TOOL_NOT_STARTED } from "./repair.js"; +const PACKAGE_NAME = '@deepseek-ai/dsh-session'; +/** Cordis companion plugin name. */ +export const name = 'session-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Assert that a step-scoped event names the currently open turn and step. */ +function requireOpenStep(trace, kind, turn, step, fail) { + if (trace.openTurn !== turn || trace.openStep !== step) { + fail(`${kind} names turn ${turn}/step ${step} but open is turn ${trace.openTurn}/step ${trace.openStep}`); + } +} +/** Validate one candidate event without mutating the committed trace. */ +function validateEvent(trace, event, fail) { + if (event.seq <= trace.lastSeq) { + fail(`seq must strictly increase: saw ${event.seq} after ${trace.lastSeq}`); + } + let openTurn = trace.openTurn; + let openStep = trace.openStep; + let nextTurn = trace.nextTurn; + let nextStep = trace.nextStep; + let pendingCalls = { kind: 'none' }; + // Context and plugin-owned log-only events may be appended between model + // executions. Core execution events retain their explicit turn relations. + switch (event.type) { + case 'turn/start': { + if (trace.openTurn !== null) { + fail(`turn/start ${event.data.turn} while turn ${trace.openTurn} is still open`); + } + if (event.data.turn !== trace.nextTurn) { + fail(`turn/start expected turn ${trace.nextTurn}, got ${event.data.turn}`); + } + openTurn = event.data.turn; + nextStep = 1; + break; + } + case 'turn/end': { + if (trace.openTurn !== event.data.turn) { + fail(`turn/end ${event.data.turn} does not match open turn ${trace.openTurn}`); + } + if (trace.openStep !== null) { + fail(`turn/end ${event.data.turn} while step ${trace.openStep} is still open`); + } + openTurn = null; + nextTurn += 1; + break; + } + case 'step/start': { + if (trace.openTurn !== event.data.turn) { + fail(`step/start in turn ${event.data.turn} but open turn is ${trace.openTurn}`); + } + if (trace.openStep !== null) { + fail(`step/start ${event.data.step} while step ${trace.openStep} is still open`); + } + if (event.data.step !== trace.nextStep) { + fail(`step/start expected step ${trace.nextStep} in turn ${event.data.turn}, got ${event.data.step}`); + } + openStep = event.data.step; + break; + } + case 'step/end': { + requireOpenStep(trace, 'step/end', event.data.turn, event.data.step, fail); + pendingCalls = { kind: 'clear' }; + openStep = null; + nextStep += 1; + break; + } + case 'assistant/chunk': { + requireOpenStep(trace, 'assistant/chunk', event.data.turn, event.data.step, fail); + break; + } + case 'assistant/message': { + requireOpenStep(trace, 'assistant/message', event.data.turn, event.data.step, fail); + break; + } + case 'tool/call': { + requireOpenStep(trace, 'tool/call', event.data.turn, event.data.step, fail); + pendingCalls = { kind: 'add', callId: event.data.callId }; + break; + } + case 'tool/result': { + // Session has already validated a content rewrite that cites its replaced event. + // It is durable turn work, not a second execution of the original call. + if (event.surfaceOp !== 'append') { + if (trace.openTurn === null) { + fail('tool/result surface replacement appended outside any open turn'); + } + break; + } + requireOpenStep(trace, 'tool/result', event.data.turn, event.data.step, fail); + const callId = event.data.message.source.callId; + const syntheticNotStarted = event.data.message.content[0].isError === true && event.data.error?.code === TOOL_NOT_STARTED; + if (!trace.pendingCalls.has(callId) && !syntheticNotStarted) { + fail(`tool/result for ${callId} with no prior tool/call in this step`); + } + pendingCalls = { kind: 'delete', callId }; + break; + } + case 'user/message': + break; + case 'session/end-seed': + // Unconstrained: an unbalanced seed legally puts it inside an open turn. + break; + case 'todo/write': + case 'request/header': + case 'request/context': { + if (trace.openTurn === null) { + fail(`${event.type} appended outside any open turn (core execution events must be turn-enclosed)`); + } + break; + } + default: + // Merge-extensible event relations belong to their owning plugin. + break; + } + return { + scalars: { lastSeq: event.seq, openTurn, openStep, nextTurn, nextStep }, + pendingCalls, + }; +} +/** Apply one already-validated transition after its event commits. */ +function applyTransition(trace, transition) { + Object.assign(trace, transition.scalars); + switch (transition.pendingCalls.kind) { + case 'none': + break; + case 'add': + trace.pendingCalls.add(transition.pendingCalls.callId); + break; + case 'delete': + trace.pendingCalls.delete(transition.pendingCalls.callId); + break; + case 'clear': + trace.pendingCalls.clear(); + break; + /* v8 ignore next -- validateEvent produces this closed transition union */ + default: + assertNever(transition.pendingCalls, 'session trace pending-call transition'); + } +} +/** Install the session contribution into its child registration fiber. */ +const install = Object.assign((ctx, fail) => { + const traces = new WeakMap(); + const stagedTransitions = new WeakMap(); + const freshTrace = () => ({ + lastSeq: -1, + openTurn: null, + openStep: null, + nextTurn: 1, + nextStep: 1, + pendingCalls: new Set(), + }); + const seedSession = (session) => { + const trace = freshTrace(); + traces.set(session, trace); + for (const event of session.events) { + applyTransition(trace, validateEvent(trace, event, fail)); + } + return trace; + }; + /* v8 ignore next -- session/event always follows list() or session/created seeding */ + const traceFor = (session) => traces.get(session) ?? seedSession(session); + for (const session of ctx.sessions.list()) + seedSession(session); + ctx.on('session/created', (session) => { seedSession(session); }, { global: true }); + ctx.on('session/event', (session, event) => { + const staged = stagedTransitions.get(event); + /* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */ + if (staged === undefined || staged.session !== session) { + return fail('session/event reached publication without matching pre-commit validation'); + } + stagedTransitions.delete(event); + applyTransition(staged.trace, staged.transition); + }, { global: true }); + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') + return; + const [session, event] = args; + const trace = traceFor(session); + const transition = validateEvent(trace, event, fail); + // A later dispatch listener may veto. Validation is pure, so abandoning + // this weakly keyed transition does not advance or retain the session. + stagedTransitions.set(event, { session, trace, transition }); + }, { global: true }); +}, { inject: ['sessions'] }); +/** + * Register the session invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/json.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/json.d.ts new file mode 100644 index 0000000..baf05c6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/json.d.ts @@ -0,0 +1,36 @@ +/** Lossless-JSON validation and detached snapshots for durable session data. @module @deepseek-ai/dsh-session/json */ +/** + * A value that round-trips losslessly through JSON: `null`, a boolean, a finite + * number other than negative zero, a string, an array of such values, or a + * plain object whose values are such values. Arrays may carry only their dense + * indexed elements; extra own properties would be discarded by JSON. TypeScript + * cannot distinguish `-0` from `number`, so {@link isJsonValue} and + * {@link snapshotJsonValue} enforce these details at runtime. Use this type for + * a payload that must survive session-log persistence and replay byte-identically + * — e.g. a tool's private presentation `meta`. + */ +export type JsonValue = null | boolean | number | string | JsonValue[] | { + [key: string]: JsonValue; +}; +/** + * Validate and detach lossless JSON in one read per property, so a stateful + * getter cannot change between validation and copying. Traversal is iterative, + * so valid nesting is bounded by available memory rather than the JavaScript + * call stack. Accepts ordinary arrays, plain or null-prototype objects, and JSON + * scalars; rejects sparse, cyclic, exotic, negative-zero, and non-finite values. + * Getter throws propagate. + * + * @param value - the candidate value to validate and detach. + * @returns the detached snapshot, or `undefined` when the value is not + * losslessly JSON-serializable. + */ +export declare function snapshotJsonValue(value: T): T | undefined; +/** + * Test the same lossless JSON boundary as {@link snapshotJsonValue} without + * detaching it. Only own enumerable string properties participate; `toJSON` + * is ignored and getters run, so persistence boundaries use the snapshotter. + * @param value - the candidate event data to test. + * @returns whether `value` survives JSON round-trip losslessly. + */ +export declare function isJsonValue(value: unknown): boolean; +//# sourceMappingURL=json.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/json.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/json.js new file mode 100644 index 0000000..de672ae --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/json.js @@ -0,0 +1,174 @@ +/** Lossless-JSON validation and detached snapshots for durable session data. @module @deepseek-ai/dsh-session/json */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor'); + const constructor = descriptor?.value; + if (typeof constructor !== 'function') + return false; + try { + return constructor.name === name + && constructor.prototype === prototype + && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } + catch { + return false; + } +} +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value) { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, 'Object'); +} +/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) + return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === 'object' + && objectPrototype !== null + && isIntrinsicObjectPrototype(objectPrototype); +} +/** Whether an object is a plain or null-prototype record from any JavaScript realm. */ +function hasPlainObjectPrototype(value) { + const prototype = Object.getPrototypeOf(value); + return prototype === null + || typeof prototype === 'object' && isIntrinsicObjectPrototype(prototype); +} +/** Return every JSON-visible object key, or reject own data JSON would discard. */ +function enumerableStringKeys(value) { + const keys = Reflect.ownKeys(value); + if (keys.some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) + return undefined; + return keys; +} +/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */ +function walkJsonValue(value, detach) { + const ancestors = new Set(); + let root; + const assign = (destination, item) => { + if (destination === undefined) + return; + if (destination.kind === 'root') { + root = item; + } + else if (destination.kind === 'array') { + destination.target[destination.index] = item; + } + else { + Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true, + }); + } + }; + const tasks = [{ + kind: 'visit', + value, + ...(detach ? { destination: { kind: 'root' } } : {}), + }]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + ancestors.delete(task.source); + continue; + } + if (task.kind === 'array-item') { + if (!Object.prototype.hasOwnProperty.call(task.source, task.index)) + return undefined; + tasks.push({ + kind: 'visit', + value: task.source[task.index], + ...(task.target === undefined ? {} : { destination: { kind: 'array', target: task.target, index: task.index } }), + }); + continue; + } + if (task.kind === 'object-property') { + tasks.push({ + kind: 'visit', + value: task.source[task.key], + ...(task.target === undefined ? {} : { destination: { kind: 'object', target: task.target, key: task.key } }), + }); + continue; + } + const current = task.value; + if (current === null) { + assign(task.destination, null); + continue; + } + if (typeof current === 'boolean' || typeof current === 'string') { + assign(task.destination, current); + continue; + } + if (typeof current === 'number') { + if (!Number.isFinite(current) || Object.is(current, -0)) + return undefined; + assign(task.destination, current); + continue; + } + if (typeof current !== 'object') + return undefined; + if (ancestors.has(current)) + return undefined; + if (Array.isArray(current)) { + if (!hasPlainArrayPrototype(current)) + return undefined; + const length = current.length; + if (Reflect.ownKeys(current).length !== length + 1) + return undefined; + const target = detach ? [] : undefined; + if (target !== undefined) + assign(task.destination, target); + ancestors.add(current); + tasks.push({ kind: 'leave', source: current }); + for (let index = length - 1; index >= 0; index--) { + tasks.push({ kind: 'array-item', source: current, index, ...(target === undefined ? {} : { target }) }); + } + continue; + } + if (!hasPlainObjectPrototype(current)) + return undefined; + const keys = enumerableStringKeys(current); + if (keys === undefined) + return undefined; + const target = detach ? {} : undefined; + if (target !== undefined) + assign(task.destination, target); + ancestors.add(current); + tasks.push({ kind: 'leave', source: current }); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) + return undefined; + tasks.push({ kind: 'object-property', source: current, key, ...(target === undefined ? {} : { target }) }); + } + } + return detach ? root : true; +} +/** + * Validate and detach lossless JSON in one read per property, so a stateful + * getter cannot change between validation and copying. Traversal is iterative, + * so valid nesting is bounded by available memory rather than the JavaScript + * call stack. Accepts ordinary arrays, plain or null-prototype objects, and JSON + * scalars; rejects sparse, cyclic, exotic, negative-zero, and non-finite values. + * Getter throws propagate. + * + * @param value - the candidate value to validate and detach. + * @returns the detached snapshot, or `undefined` when the value is not + * losslessly JSON-serializable. + */ +export function snapshotJsonValue(value) { + return walkJsonValue(value, true); +} +/** + * Test the same lossless JSON boundary as {@link snapshotJsonValue} without + * detaching it. Only own enumerable string properties participate; `toJSON` + * is ignored and getters run, so persistence boundaries use the snapshotter. + * @param value - the candidate event data to test. + * @returns whether `value` survives JSON round-trip losslessly. + */ +export function isJsonValue(value) { + return walkJsonValue(value, false) === true; +} +//# sourceMappingURL=json.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.d.ts new file mode 100644 index 0000000..a060061 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.d.ts @@ -0,0 +1,19 @@ +/** + * GENERATED by `scripts/gen-persistence-catalog.ts` — do not edit by hand; run + * `pnpm run gen-persistence-catalog` to regenerate (verified fresh by + * `pnpm run verify-persistence-catalog`, part of `doc-sync`). + * @module @deepseek-ai/dsh-session/known-event-types + */ +/** + * Every `SessionEventMap` member declared in this repository — the event + * vocabulary this build understands. The persistence read path refuses to + * interpret a log containing a type outside this set unless the event + * carries the envelope's `ignorable` marker (see `SessionEvent.ignorable` + * in `./types.ts`): such a log was likely written by a newer harness, and + * silently skipping a required event would reconstruct a wrong session. + * Downstream (out-of-repo) plugin events are outside this list by + * construction; a registration surface for them is deferred until such a + * consumer exists. + */ +export declare const KNOWN_SESSION_EVENT_TYPES: ReadonlySet; +//# sourceMappingURL=known-event-types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.js new file mode 100644 index 0000000..7541caa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/known-event-types.js @@ -0,0 +1,64 @@ +/** + * GENERATED by `scripts/gen-persistence-catalog.ts` — do not edit by hand; run + * `pnpm run gen-persistence-catalog` to regenerate (verified fresh by + * `pnpm run verify-persistence-catalog`, part of `doc-sync`). + * @module @deepseek-ai/dsh-session/known-event-types + */ +/** + * Every `SessionEventMap` member declared in this repository — the event + * vocabulary this build understands. The persistence read path refuses to + * interpret a log containing a type outside this set unless the event + * carries the envelope's `ignorable` marker (see `SessionEvent.ignorable` + * in `./types.ts`): such a log was likely written by a newer harness, and + * silently skipping a required event would reconstruct a wrong session. + * Downstream (out-of-repo) plugin events are outside this list by + * construction; a registration surface for them is deferred until such a + * consumer exists. + */ +export const KNOWN_SESSION_EVENT_TYPES = new Set([ + 'agent-preset/selected', + 'agent/inbox/spliced', + 'approval/asked', + 'approval/decided', + 'approval/policy', + 'assistant/chunk', + 'assistant/message', + 'command/done', + 'command/run', + 'compaction/end', + 'compaction/prune', + 'compaction/start', + 'compaction/summary', + 'feedback/record', + 'goal/change', + 'hook/invoked', + 'hook/result', + 'llm/retry', + 'llm/retry-started', + 'permission/preset', + 'plan/mode', + 'request/context', + 'request/header', + 'sandbox/mode', + 'schedule/change', + 'session/end-seed', + 'session/title', + 'session/title-llm-request', + 'step/end', + 'step/start', + 'subagent/descriptor', + 'todo/write', + 'tool-workflow/agent-end', + 'tool-workflow/agent-start', + 'tool-workflow/run-end', + 'tool-workflow/run-start', + 'tool/call', + 'tool/code-dispatch', + 'tool/code-dispatch-start', + 'tool/result', + 'turn/end', + 'turn/start', + 'user/message', + 'web/deepseek-search-llm-request', +]); +//# sourceMappingURL=known-event-types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.d.ts new file mode 100644 index 0000000..52c0f55 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.d.ts @@ -0,0 +1,33 @@ +/** + * Ownership of one unpublished Session before registry publication. + * @module @deepseek-ai/dsh-session/preparation + */ +import type { Session } from './index.ts'; +/** Options for a preparation whose provider retains unpublished state. */ +export interface SessionPreparationOptions { + /** Release provider-owned state when the Session was not published. */ + readonly release?: () => void; +} +/** + * One exact unpublished Session and the provider state that keeps it usable. + * Disposal is synchronous and idempotent. Providers decide whether release + * returns the Session to a cache or discards it; publication may consume that + * state before disposal, making the callback a no-op. + */ +export declare class SessionPreparation implements Disposable { + private readonly options; + private released; + /** The exact Session to use for setup and publication. */ + readonly session: Session; + private constructor(); + /** + * Wrap an unpublished Session in one preparation lifetime. + * @param session - exact unpublished Session. + * @param options - optional provider release behavior. + * @returns a preparation disposed after publication or rollback. + */ + static create(session: Session, options?: SessionPreparationOptions): SessionPreparation; + /** Release provider state once when this preparation leaves its caller. */ + [Symbol.dispose](): void; +} +//# sourceMappingURL=preparation.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.js new file mode 100644 index 0000000..baecac6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/preparation.js @@ -0,0 +1,37 @@ +/** + * Ownership of one unpublished Session before registry publication. + * @module @deepseek-ai/dsh-session/preparation + */ +/** + * One exact unpublished Session and the provider state that keeps it usable. + * Disposal is synchronous and idempotent. Providers decide whether release + * returns the Session to a cache or discards it; publication may consume that + * state before disposal, making the callback a no-op. + */ +export class SessionPreparation { + options; + released = false; + /** The exact Session to use for setup and publication. */ + session; + constructor(session, options) { + this.options = options; + this.session = session; + } + /** + * Wrap an unpublished Session in one preparation lifetime. + * @param session - exact unpublished Session. + * @param options - optional provider release behavior. + * @returns a preparation disposed after publication or rollback. + */ + static create(session, options) { + return new SessionPreparation(session, options ?? {}); + } + /** Release provider state once when this preparation leaves its caller. */ + [Symbol.dispose]() { + if (this.released) + return; + this.released = true; + this.options.release?.(); + } +} +//# sourceMappingURL=preparation.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/repair.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/repair.d.ts new file mode 100644 index 0000000..0cf7879 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/repair.d.ts @@ -0,0 +1,22 @@ +/** + * Crash-recovery repair for an interrupted session log. It preserves a fully + * written final turn and supplies the missing tool, step, and turn boundaries + * needed to resume with a provider-valid transcript. + * @module @deepseek-ai/dsh-session/repair + */ +import type { SessionEvent } from './types.ts'; +/** Recovery code for an assistant tool request that never reached a recorded call start. */ +export declare const TOOL_NOT_STARTED = "TOOL_NOT_STARTED"; +/** Recovery code for a recorded tool call whose completed outcome was not durably recorded. */ +export declare const TOOL_OUTCOME_UNKNOWN = "TOOL_OUTCOME_UNKNOWN"; +/** + * Return deterministic synthetic events that close an open tail turn. Unmatched + * calls receive error results first, followed by an open `step/end` and an + * interrupted `turn/end`; sequences continue the log and timestamps reuse the + * last real event. A balanced or empty log returns no events. + * + * @param events - the loaded durable log to scan (a valid committed prefix, possibly with a crash tail). + * @returns the synthetic closer events to append after `events`, in order; empty when the log is already balanced. + */ +export declare function interruptedTurnClosers(events: readonly SessionEvent[]): SessionEvent[]; +//# sourceMappingURL=repair.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/repair.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/repair.js new file mode 100644 index 0000000..39544bb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/repair.js @@ -0,0 +1,126 @@ +/** + * Crash-recovery repair for an interrupted session log. It preserves a fully + * written final turn and supplies the missing tool, step, and turn boundaries + * needed to resume with a provider-valid transcript. + * @module @deepseek-ai/dsh-session/repair + */ +import { MessageId, freezeMessage } from '@deepseek-ai/dsh-llm'; +/** Recovery code for an assistant tool request that never reached a recorded call start. */ +export const TOOL_NOT_STARTED = 'TOOL_NOT_STARTED'; +/** Recovery code for a recorded tool call whose completed outcome was not durably recorded. */ +export const TOOL_OUTCOME_UNKNOWN = 'TOOL_OUTCOME_UNKNOWN'; +/** + * Return deterministic synthetic events that close an open tail turn. Unmatched + * calls receive error results first, followed by an open `step/end` and an + * interrupted `turn/end`; sequences continue the log and timestamps reuse the + * last real event. A balanced or empty log returns no events. + * + * @param events - the loaded durable log to scan (a valid committed prefix, possibly with a crash tail). + * @returns the synthetic closer events to append after `events`, in order; empty when the log is already balanced. + */ +export function interruptedTurnClosers(events) { + let openTurn = null; + let openStep = null; + // Reset at each turn boundary so earlier calls cannot leak into tail repair. + // Assistant blocks register calls; later `tool/call` events add their seqs to `sourceEventSeqs`. + const pendingCalls = new Map(); + for (const event of events) { + switch (event.type) { + case 'turn/start': + openTurn = event.data.turn; + openStep = null; + pendingCalls.clear(); + break; + case 'turn/end': + openTurn = null; + openStep = null; + pendingCalls.clear(); + break; + case 'step/start': + openStep = event.data.step; + break; + case 'step/end': + pendingCalls.clear(); + openStep = null; + break; + case 'assistant/message': + // The assistant message carries the tool-call blocks; each is pending + // until a tool/result event with the same callId is logged. + for (const block of event.data.message.content) { + if (block.type === 'tool-call') + pendingCalls.set(block.id, { step: event.data.step }); + } + break; + case 'tool/call': + // Cite the `tool/call` seq from the synthetic result. + { + const entry = pendingCalls.get(event.data.callId); + if (entry) { + entry.callSeq = event.seq; + } + } + break; + case 'tool/result': + pendingCalls.delete(event.data.message.source.callId); + break; + // Other event types do not move the turn/step boundary cursor. + default: + break; + } + } + // Balanced log (no crash mid-turn): nothing to close. An open turn implies + // `events` is non-empty (its turn/start was logged), so `last` exists. + const last = events.at(-1); + if (openTurn === null || last === undefined) + return []; + // The last real event supplies the seq base and the timestamp for the + // synthetic closers (reusing the last timestamp keeps them deterministic and + // never invents a "future" time). + let seq = last.seq + 1; + const time = last.time; + const closers = []; + // Close calls before their step: providers reject dangling assistant calls, + // and Map insertion order preserves their transcript order. + for (const [callId, { step, callSeq }] of pendingCalls) { + const started = callSeq !== undefined; + const message = freezeMessage({ + id: MessageId(`interrupted-tool-result-${callId}-${seq}`), + role: 'user', + source: { kind: 'tool', callId }, + content: [{ + type: 'tool-result', + toolCallId: callId, + isError: true, + content: [{ + type: 'text', + text: started + ? 'The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly.' + : 'The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed.', + }], + }], + }); + closers.push({ + type: 'tool/result', + seq: seq++, + time, + data: { + turn: openTurn, + step, + message, + error: started + ? { name: 'ToolOutcomeUnknownError', code: TOOL_OUTCOME_UNKNOWN } + : { name: 'ToolNotStartedError', code: TOOL_NOT_STARTED }, + }, + surfaceOp: 'append', + ...started ? { sourceEventSeqs: [callSeq] } : {}, + }); + } + // Close an open step next — a turn/end while a step is open is an invariant + // violation, so the step's boundary must be synthesized before the turn's. + if (openStep !== null) { + closers.push({ type: 'step/end', seq: seq++, time, data: { turn: openTurn, step: openStep } }); + } + closers.push({ type: 'turn/end', seq: seq++, time, data: { turn: openTurn, reason: { kind: 'interrupted' } } }); + return closers; +} +//# sourceMappingURL=repair.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.d.ts new file mode 100644 index 0000000..2513521 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.d.ts @@ -0,0 +1,35 @@ +/** + * Request-header reconstruction utilities over full `request/header` session + * events. Anyone holding a session log reconstructs the {@link EpochHeader} + * any request was built under by taking the latest canonical snapshot; the + * loop uses the same equality helper to avoid logging unchanged headers. + * + * @module dsh-session/request-header + */ +import type { EpochHeader, SessionEvent } from './types.ts'; +/** + * Normalize a header to canonical form: an empty system prompt and empty tool + * list become absent fields, matching how requests are built. Logging, folding, + * and comparison use this one representation. + * @param header - the header to normalize (not mutated). + * @returns the canonical header. + */ +export declare function canonicalHeader(header: EpochHeader): EpochHeader; +/** + * Field-wise equality over canonical headers. Tool schemas compare in order. + * @param a - one canonical header. + * @param b - the other. + * @returns whether config, system, and tools all match. + */ +export declare function headerEquals(a: EpochHeader, b: EpochHeader): boolean; +/** + * Fold the header events of a log (or any prefix) into the + * {@link EpochHeader} in force after the last snapshot. Non-header events are + * skipped. This is the pure offline reconstruction path; the live session + * tracks the same fold incrementally. + * @param events - session events in log order. + * @param from - a previously folded state to continue from. + * @returns the latest canonical header, or undefined when none exists yet. + */ +export declare function foldRequestHeader(events: readonly SessionEvent[], from?: EpochHeader): EpochHeader | undefined; +//# sourceMappingURL=request-header.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.js new file mode 100644 index 0000000..0d9d564 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/request-header.js @@ -0,0 +1,65 @@ +/** + * Request-header reconstruction utilities over full `request/header` session + * events. Anyone holding a session log reconstructs the {@link EpochHeader} + * any request was built under by taking the latest canonical snapshot; the + * loop uses the same equality helper to avoid logging unchanged headers. + * + * @module dsh-session/request-header + */ +import { callConfigEquals } from '@deepseek-ai/dsh-llm'; +/** + * Normalize a header to canonical form: an empty system prompt and empty tool + * list become absent fields, matching how requests are built. Logging, folding, + * and comparison use this one representation. + * @param header - the header to normalize (not mutated). + * @returns the canonical header. + */ +export function canonicalHeader(header) { + const adapterDefaults = header.adapterDefaults; + return { + config: header.config, + ...adapterDefaults?.reasoningEffort === true || adapterDefaults?.maxTokens === true + ? { adapterDefaults } + : {}, + ...header.system !== undefined && header.system.length > 0 ? { system: header.system } : {}, + ...header.tools !== undefined && header.tools.length > 0 ? { tools: header.tools } : {}, + }; +} +/** Canonical JSON equality for tool schemas assembled through the same path. */ +function sameSchema(a, b) { + return JSON.stringify(a) === JSON.stringify(b); +} +/** + * Field-wise equality over canonical headers. Tool schemas compare in order. + * @param a - one canonical header. + * @param b - the other. + * @returns whether config, system, and tools all match. + */ +export function headerEquals(a, b) { + if (!callConfigEquals(a.config, b.config) + || a.adapterDefaults?.reasoningEffort !== b.adapterDefaults?.reasoningEffort + || a.adapterDefaults?.maxTokens !== b.adapterDefaults?.maxTokens + || a.system !== b.system) + return false; + const at = a.tools ?? []; + const bt = b.tools ?? []; + return at.length === bt.length && at.every((tool, i) => sameSchema(tool, bt[i])); +} +/** + * Fold the header events of a log (or any prefix) into the + * {@link EpochHeader} in force after the last snapshot. Non-header events are + * skipped. This is the pure offline reconstruction path; the live session + * tracks the same fold incrementally. + * @param events - session events in log order. + * @param from - a previously folded state to continue from. + * @returns the latest canonical header, or undefined when none exists yet. + */ +export function foldRequestHeader(events, from) { + let state = from; + for (const event of events) { + if (event.type === 'request/header') + state = canonicalHeader(event.data.header); + } + return state; +} +//# sourceMappingURL=request-header.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/surface.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/surface.d.ts new file mode 100644 index 0000000..d0db42f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/surface.d.ts @@ -0,0 +1,123 @@ +/** + * Surface layer on top of the session event log: an ordered view of events + * that produce LLM messages. The append-only log remains the source of truth. + * + * Browser-safe: web clients consume this subpath export, so it must stay free + * of `node:` imports (they break the vite bundle). + * + * @module @deepseek-ai/dsh-session/surface + */ +import type { Message } from '@deepseek-ai/dsh-llm'; +import type { SessionEvent, SurfaceEvent, SurfaceOp } from './types.ts'; +/** + * Whether an event type can join the model-visible surface. + * @param type - event type to test. + * @returns true for one of the three message-producing event types. + */ +export declare function isSurfaceEligibleType(type: string): boolean; +/** + * Narrow an event to a surface-eligible event carrying its required marker. + * @param event - event to test. + * @returns true when both the type and marker identify a surface event. + */ +export declare function isSurfaceEvent(event: SessionEvent): event is SurfaceEvent; +/** + * Narrow an event to an append-origin surface event: one that entered the + * surface at its own log position and was never itself a replacement copy. + * + * The model-visible surface deliberately shadows replaced ranges, so it is the + * wrong source for a human transcript — a landed replacement would erase + * conversation the user already saw. Append-origin events are that transcript's + * durable source material; replacement copies stay model-only. + * @param event - event to test. + * @returns true when the event appended to the surface tail. + */ +export declare function isAppendSurfaceEvent(event: SessionEvent): event is SurfaceEvent & { + surfaceOp: 'append'; +}; +/** + * Narrow an event to a surface replacement: a node that shadowed an existing + * surface range instead of appending to the tail. The counterpart of + * {@link isAppendSurfaceEvent} over the two {@link SurfaceOp} variants. + * @param event - event to test. + * @returns true when the event replaced a surface range. + */ +export declare function isReplacementSurfaceEvent(event: SessionEvent): event is SurfaceEvent & { + surfaceOp: Extract; +}; +/** + * Project a single event into the LLM message it derives to, or null when it + * produces none — a non-surface event (chunk, boundary, log-only record) or an + * empty-content assistant/message (which exists only to host usage). This is + * THE per-node projection rule: `Session.deriveMessages` folds it over the + * live surface, external reconstructors and pure projections fold the same + * function over a log prefix's surface to rebuild the exact messages any + * request was built from. The returned message is the already frozen message + * nested in the event wrapper and shared by delivery, durable history, and + * model requests. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ +export declare function deriveEventMessage(event: SessionEvent): Message | null; +/** One replacement operation observed while folding a session surface. */ +export interface SurfaceFoldReplacement { + /** Seq of the event that replaced the prior surface range. */ + seq: number; + /** Declared inclusive start seq of the replaced surface range. */ + start: number; + /** Declared inclusive end seq of the replaced surface range. */ + end: number; + /** Actual surface entries removed by the operation, in surface order. */ + shadowedSeqs: number[]; +} +/** Complete result of replaying the surface operations in a session log. */ +export interface SurfaceFoldResult { + /** Current surface event sequences in model-visible order. */ + nodes: number[]; + /** Replacement operations in event order. */ + replacements: SurfaceFoldReplacement[]; +} +/** Readonly live projection of the message-producing session events. */ +export interface SessionSurface { + /** Current surface event sequences in model-visible order. */ + readonly nodes: readonly number[]; + /** Monotonic count of committed positional replacements. */ + readonly replaceGeneration: number; +} +/** + * Replay a complete session log through the canonical surface fold. + * @param events - session events in contiguous seq order. + * @returns detached current sequences and replacement history. + * @throws when an event violates surface metadata, source-event references, range, or tool-result rewrite rules. + */ +export declare function foldSurface(events: readonly SessionEvent[]): SurfaceFoldResult; +/** Incremental ordered surface view and append-boundary validator. */ +export declare class SurfaceManager implements SessionSurface { + private log; + private readonly baseSeq; + /** Shared transition state; replacement history is not retained. */ + private _state; + /** Last processed absolute seq. */ + private _lastProcessedSeq; + /** Candidate already validated by `validateNext`, pending exact log admission. */ + private _pendingPlan; + /** + * @param log - Contiguous complete log or loaded event window. + * @param baseSeq - Absolute sequence of the window's first event. + */ + constructor(log: readonly SessionEvent[], baseSeq?: number); + /** + * Validate the next candidate without mutating the committed surface. + * @param event - candidate event that has not entered the log yet. + */ + validateNext(event: SessionEvent): void; + /** Monotonic count of folded positional replacements. */ + get replaceGeneration(): number; + /** Surface event sequences in model-visible order. */ + get nodes(): readonly number[]; + /** Fold events appended since the previous access. */ + private _processDelta; +} +//# sourceMappingURL=surface.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/surface.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/surface.js new file mode 100644 index 0000000..c4b05f4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/surface.js @@ -0,0 +1,377 @@ +/** + * Surface layer on top of the session event log: an ordered view of events + * that produce LLM messages. The append-only log remains the source of truth. + * + * Browser-safe: web clients consume this subpath export, so it must stay free + * of `node:` imports (they break the vite bundle). + * + * @module @deepseek-ai/dsh-session/surface + */ +/** Runtime counterpart of the message-producing event union. */ +const SURFACE_EVENT_TYPES = new Set([ + 'user/message', + 'assistant/message', + 'tool/result', +]); +/** + * Whether an event type can join the model-visible surface. + * @param type - event type to test. + * @returns true for one of the three message-producing event types. + */ +export function isSurfaceEligibleType(type) { + return SURFACE_EVENT_TYPES.has(type); +} +/** + * Narrow an event to a surface-eligible event carrying its required marker. + * @param event - event to test. + * @returns true when both the type and marker identify a surface event. + */ +export function isSurfaceEvent(event) { + if (!SURFACE_EVENT_TYPES.has(event.type)) + return false; + return event.surfaceOp !== undefined; +} +/** + * Narrow an event to an append-origin surface event: one that entered the + * surface at its own log position and was never itself a replacement copy. + * + * The model-visible surface deliberately shadows replaced ranges, so it is the + * wrong source for a human transcript — a landed replacement would erase + * conversation the user already saw. Append-origin events are that transcript's + * durable source material; replacement copies stay model-only. + * @param event - event to test. + * @returns true when the event appended to the surface tail. + */ +export function isAppendSurfaceEvent(event) { + return isSurfaceEvent(event) && event.surfaceOp === 'append'; +} +/** + * Narrow an event to a surface replacement: a node that shadowed an existing + * surface range instead of appending to the tail. The counterpart of + * {@link isAppendSurfaceEvent} over the two {@link SurfaceOp} variants. + * @param event - event to test. + * @returns true when the event replaced a surface range. + */ +export function isReplacementSurfaceEvent(event) { + return isSurfaceEvent(event) && event.surfaceOp !== 'append'; +} +/** + * Project a single event into the LLM message it derives to, or null when it + * produces none — a non-surface event (chunk, boundary, log-only record) or an + * empty-content assistant/message (which exists only to host usage). This is + * THE per-node projection rule: `Session.deriveMessages` folds it over the + * live surface, external reconstructors and pure projections fold the same + * function over a log prefix's surface to rebuild the exact messages any + * request was built from. The returned message is the already frozen message + * nested in the event wrapper and shared by delivery, durable history, and + * model requests. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ +export function deriveEventMessage(event) { + // Intentionally non-exhaustive: only message-producing events derive + // history; turn/step boundaries, chunks, usage, and errors are trace/replay + // data. + switch (event.type) { + // Ordinary prompts and injected context project in user role: the event's + // model-facing content stays verbatim. Do NOT re-add per-type framing + // (e.g. ``) here: framing is caller-owned — a producer bakes it + // into `content`, as agent-instructions does with `` — or, + // if reintroduced, must be driven by the event `meta` map and a dedicated + // renderer, keeping this projection a verbatim pass-through. See the + // deferred design note in + // ../../../../.agents/notes/implemented/simplification/2026-07-20-unwrap-injected-content-envelopes.md + case 'user/message': { + return event.data; + } + case 'assistant/message': { + // Skip an empty-content assistant/message: it exists only to host a + // max-tokens step's usage and must not inject a content-less assistant + // turn into the provider transcript. + if (event.data.message.content.length === 0) + return null; + return event.data.message; + } + case 'tool/result': { + return event.data.message; + } + default: + // A non-surface event (boundary, chunk, log-only record) projects to + // no message. Merge-extensible union: no assertNever here. + return null; + } +} +/** Create an empty surface fold state. */ +function createFoldState() { + return { nodes: [], replaceGeneration: 0 }; +} +/** Whether a runtime value is a non-negative safe event sequence. */ +function isEventSeq(value) { + return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0; +} +/** Whether a runtime value is the exact positional-replacement shape. */ +function isReplaceOp(value) { + const op = value; + return Object.keys(op).length === 3 + && Object.hasOwn(op, 'op') + && Object.hasOwn(op, 'start') + && Object.hasOwn(op, 'end') + && op['op'] === 'replace' + && isEventSeq(op['start']) + && isEventSeq(op['end']); +} +/** Validate event-local surface eligibility and return its operation. */ +function surfaceOpOf(event) { + const raw = event; + if (!isSurfaceEligibleType(event.type)) { + if (raw.surfaceOp !== undefined) { + throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry surfaceOp`); + } + if (raw.sourceEventSeqs !== undefined) { + throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry sourceEventSeqs`); + } + return; + } + const op = raw.surfaceOp; + if (op === undefined) { + throw new Error(`session event "${event.type}" is surface-eligible and requires a surfaceOp marker`); + } + if (op === 'append') + return op; + if (op === null || typeof op !== 'object' || Array.isArray(op)) { + throw new Error(`session event "${event.type}" carries an invalid surfaceOp`); + } + if (!isReplaceOp(op)) { + throw new Error(`session event "${event.type}" carries an invalid replace surfaceOp`); + } + return op; +} +/** Validate cited source-event seqs against prior log entries and the replacement range. */ +function assertProvenance(event, shadowedSeqs) { + const raw = event.sourceEventSeqs; + const sources = new Set(); + if (raw !== undefined) { + if (!Array.isArray(raw)) { + throw new Error(`sourceEventSeqs on event at seq ${event.seq} must be an array when present`); + } + if (raw.length === 0 && event.type !== 'assistant/message') { + throw new Error('sourceEventSeqs must not be empty except on assistant/message'); + } + let nonEarlierSource; + for (const source of raw) { + if (!isEventSeq(source)) { + throw new Error(`session event "${event.type}" sourceEventSeqs must densely contain non-negative safe integers`); + } + sources.add(source); + if (nonEarlierSource === undefined && source >= event.seq) + nonEarlierSource = source; + } + if (sources.size !== raw.length) { + throw new Error('sourceEventSeqs must not contain duplicates'); + } + if (nonEarlierSource !== undefined) { + throw new Error(`sourceEventSeqs must reference earlier events: ${nonEarlierSource} >= current seq ${event.seq}`); + } + } + const missing = shadowedSeqs.filter(seq => !sources.has(seq)); + if (missing.length > 0) { + throw new Error(`surface replace: sourceEventSeqs must include every shadowed surface node; missing ${missing.join(', ')}`); + } +} +/** Locate one replacement range without mutating the current fold state. */ +function replacementRange(state, op) { + const startIdx = state.nodes.indexOf(op.start); + if (startIdx === -1) { + throw new Error(`surface replace: start seq ${op.start} not found in surface`); + } + const endIdx = state.nodes.indexOf(op.end); + if (endIdx === -1) { + throw new Error(`surface replace: end seq ${op.end} not found in surface`); + } + if (startIdx > endIdx) { + throw new Error(`surface replace: start seq ${op.start} (index ${startIdx}) is after end seq ${op.end} (index ${endIdx})`); + } + return { + startIdx, + endIdx, + shadowedSeqs: state.nodes.slice(startIdx, endIdx + 1), + }; +} +/** + * Deep structural equality over the session-event JSON value domain + * (null/boolean/number/string, arrays, plain objects). Replaces + * `node:util`'s isDeepStrictEqual to keep this module browser-safe. + */ +function isDeepEqualJson(a, b) { + if (a === b) + return true; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) + return false; + return a.every((item, i) => isDeepEqualJson(item, b[i])); + } + if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) + return false; + const aKeys = Object.keys(a); + const bRecord = b; + if (aKeys.length !== Object.keys(b).length) + return false; + return aKeys.every(key => Object.hasOwn(b, key) && isDeepEqualJson(a[key], bRecord[key])); +} +/** Restrict a tool-result replacement to one current result's content. */ +function assertToolResultRewrite(event, shadowedSeqs, events, baseSeq) { + if (event.type !== 'tool/result') + return; + if (shadowedSeqs.length !== 1) { + throw new Error('tool/result surface replacement must rewrite exactly one current node'); + } + for (const originalSeq of shadowedSeqs) { + const original = events[originalSeq - baseSeq]; + if (original?.type !== 'tool/result') { + throw new Error('tool/result surface replacement must target a current tool/result'); + } + const originalRest = { ...original.data }; + const replacementRest = { ...event.data }; + const originalResult = original.data.message.content[0]; + const replacementResult = event.data.message.content[0]; + originalRest['message'] = { + ...original.data.message, + content: [{ ...originalResult, content: null }], + }; + replacementRest['message'] = { + ...event.data.message, + content: [{ ...replacementResult, content: null }], + }; + if (!isDeepEqualJson(originalRest, replacementRest)) { + throw new Error('tool/result surface replacement may change only content'); + } + } +} +/** Validate one event at its replay boundary and prepare its atomic fold transition. */ +function planSurfaceEvent(state, event, expectedSeq, events, baseSeq) { + if (event.seq !== expectedSeq) { + throw new Error(`session event seq ${event.seq} is not contiguous; expected ${expectedSeq}`); + } + const surfaceOp = surfaceOpOf(event); + if (surfaceOp === undefined) + return; + if (surfaceOp === 'append') { + assertProvenance(event, []); + return { kind: 'append', seq: event.seq }; + } + const range = replacementRange(state, surfaceOp); + assertProvenance(event, range.shadowedSeqs); + assertToolResultRewrite(event, range.shadowedSeqs, events, baseSeq); + return { + kind: 'replace', + seq: event.seq, + start: surfaceOp.start, + end: surfaceOp.end, + ...range, + }; +} +/** Apply one event and return replacement metadata only when one occurred. */ +function applySurfaceEvent(state, event, expectedSeq, events, baseSeq) { + const plan = planSurfaceEvent(state, event, expectedSeq, events, baseSeq); + return applySurfacePlan(state, plan); +} +/** Commit one previously validated surface transition. */ +function applySurfacePlan(state, plan) { + if (plan?.kind === 'append') { + state.nodes.push(plan.seq); + } + else if (plan?.kind === 'replace') { + state.nodes.splice(plan.startIdx, plan.endIdx - plan.startIdx + 1, plan.seq); + state.replaceGeneration += 1; + } + if (plan?.kind !== 'replace') + return; + return { + seq: plan.seq, + start: plan.start, + end: plan.end, + shadowedSeqs: plan.shadowedSeqs, + }; +} +/** + * Replay a complete session log through the canonical surface fold. + * @param events - session events in contiguous seq order. + * @returns detached current sequences and replacement history. + * @throws when an event violates surface metadata, source-event references, range, or tool-result rewrite rules. + */ +export function foldSurface(events) { + const state = createFoldState(); + const replacements = []; + for (const [index, event] of events.entries()) { + const replacement = applySurfaceEvent(state, event, index, events, 0); + if (replacement !== undefined) + replacements.push(replacement); + } + return { nodes: [...state.nodes], replacements }; +} +/** Incremental ordered surface view and append-boundary validator. */ +export class SurfaceManager { + log; + baseSeq; + /** Shared transition state; replacement history is not retained. */ + _state = createFoldState(); + /** Last processed absolute seq. */ + _lastProcessedSeq; + /** Candidate already validated by `validateNext`, pending exact log admission. */ + _pendingPlan; + /** + * @param log - Contiguous complete log or loaded event window. + * @param baseSeq - Absolute sequence of the window's first event. + */ + constructor(log, baseSeq = 0) { + this.log = log; + this.baseSeq = baseSeq; + this._lastProcessedSeq = baseSeq - 1; + } + /** + * Validate the next candidate without mutating the committed surface. + * @param event - candidate event that has not entered the log yet. + */ + validateNext(event) { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) + this._processDelta(); + const expectedSeq = this.baseSeq + this.log.length; + this._pendingPlan = { + event, + expectedSeq, + plan: planSurfaceEvent(this._state, event, expectedSeq, this.log, this.baseSeq), + }; + } + /** Monotonic count of folded positional replacements. */ + get replaceGeneration() { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) + this._processDelta(); + return this._state.replaceGeneration; + } + /** Surface event sequences in model-visible order. */ + get nodes() { + if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) + this._processDelta(); + return this._state.nodes; + } + /** Fold events appended since the previous access. */ + _processDelta() { + const tailSeq = this.baseSeq + this.log.length - 1; + for (let seq = this._lastProcessedSeq + 1; seq <= tailSeq; seq++) { + const index = seq - this.baseSeq; + // oxlint-disable-next-line typescript/no-non-null-assertion -- bounded by the loop condition + const event = this.log[index]; + const pending = this._pendingPlan; + if (pending?.event === event && pending.expectedSeq === seq) { + applySurfacePlan(this._state, pending.plan); + } + else { + applySurfaceEvent(this._state, event, seq, this.log, this.baseSeq); + } + if (pending !== undefined && pending.expectedSeq <= seq) + this._pendingPlan = undefined; + this._lastProcessedSeq = seq; + } + } +} +//# sourceMappingURL=surface.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts new file mode 100644 index 0000000..b1e6a94 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts @@ -0,0 +1,453 @@ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { AssistantMessage, CallId, LlmCallConfig, LlmCallConfigAdapterDefaults, LlmFailure, StreamChunk, TokenUsage, ToolResultMessage, ToolSchema, UserMessage } from '@deepseek-ai/dsh-llm'; +import type { JsonValue } from './json.ts'; +export type { JsonValue } from './json.ts'; +/** Identifies one session in the store (and its persistence artifacts). */ +export type SessionId = Branded<'SessionId'>; +/** + * Brand a string as a {@link SessionId}. + * @param id - the raw session id string. + * @returns the same string, branded (a compile-time cast — no runtime cost). + */ +export declare function SessionId(id: string): SessionId; +/** + * The on-disk session format version, stamped into every newly-written {@link SessionHeader} + * and enforced by every persistence backend on load. The single source of truth for the + * version — write sites and the load-time check all read it. + * While the harness is unreleased it is pinned at `0`: no compatibility is + * implied, incompatible logs are rejected, and no migration is provided. + * + * The version is a single monotonic integer with no major/minor split. Whether + * a bump is needed is decided by what the WRITER emits, never by what a newer + * reader can accept: bump exactly when an older runtime could no longer handle + * a new log with full semantic correctness ("parses without error" is not + * correctness — silently skipping content that shapes reconstruction is a + * wrong read). Only structural changes reach that bar: the header shape, the + * {@link SessionEvent} envelope, core event semantics, or the surface + * mechanism (the {@link SurfaceEventType} set and {@link SurfaceOp} variants). + * Adding an ordinary event type does not bump — the per-event + * {@link SessionEvent.ignorable} guard covers vocabulary growth instead. When + * in doubt, bump: a near-identity upgrade step is almost free, a missed bump + * makes older runtimes read new logs wrong silently. The full mechanism + * (upgrade-step chain, in-memory view conversion, migrate-on-continue) is + * recorded in the session-log-version-mechanism Agent Note + * (`.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md`). + */ +export declare const SESSION_FORMAT_VERSION = 0; +/** + * Immutable validated storage metadata, kept outside the conversation event log. + */ +export interface SessionHeader { + /** + * On-disk format version, stamped from {@link SESSION_FORMAT_VERSION} when the + * session is created. A persistence backend rejects any other version on load + * (no migration — see the constant). + */ + readonly version: number; + /** The session's id (mirrors the {@link Session}'s id). */ + readonly id: SessionId; + /** Non-negative safe-integer Unix epoch milliseconds when the session was created. */ + readonly createdAt: number; + /** Absolute working directory the session was created in (if any). */ + readonly cwd?: string; + /** The session this one was forked from (seed lineage), if any. */ + readonly parentSession?: SessionId; + /** + * How many leading events were inherited through a seed. Persisting this + * boundary lets resume and replay distinguish parent history from child work. + */ + readonly seedLength?: number; + /** + * Coarse product classification for a session created as a subagent child. + * This is presentation metadata, not proof that the child is continuable. + */ + readonly origin?: 'subagent'; + /** + * Delegation depth: absent (zero) for a top-level session, parent depth + 1 + * for a subagent child. Persisted so a recursion budget survives restart and + * resume — a runtime-only depth would reset a resumed child to top-level. + */ + readonly delegationDepth?: number; + /** + * Id of the agent preset this session's agent was composed from, when the + * deployment composes per session. Durable because the preset decides the + * session's tools and prompt: a resume that restored a different composition + * would replay history the model can no longer act on. + */ + readonly agentPreset?: string; +} +/** + * Options for creating a {@link Session} via the store. `seed` replays/forks + * an existing event log; `meta` carries the caller-supplied storage fields the + * store folds into a {@link SessionHeader}. + */ +export interface CreateSessionOptions { + /** Initial replay or fork history supplied at construction. */ + readonly seed?: readonly SessionEvent[]; + /** + * Storage metadata read once before publication. `seedLength` is explicit + * because a resumed seed contains the full stored log, not only its inherited prefix. + */ + readonly meta?: { + readonly cwd?: string; + readonly parentSession?: SessionId; + readonly createdAt?: number; + readonly seedLength?: number; + readonly origin?: 'subagent'; + readonly delegationDepth?: number; + readonly agentPreset?: string; + }; +} +/** + * Fresh storage values transferred to {@link SessionStore.prepare} without a + * second serialization copy. Callers retain no mutable aliases. + */ +export interface RestoredSessionOptions { + /** Fresh detached storage events to validate and freeze in place. */ + readonly seed: SessionEvent[]; + /** Fresh detached storage metadata to validate and freeze in place. */ + readonly meta: SessionHeader; + /** Select the persistence ownership-transfer path. */ + readonly seedSource: 'persistence'; +} +/** Inputs accepted while constructing an unpublished Session. */ +export type PrepareSessionOptions = (CreateSessionOptions & { + readonly seedSource?: undefined; +}) | RestoredSessionOptions; +/** Why an active agent driver was cancelled. */ +export type AgentCancelCause = { + readonly kind: 'user'; +} | { + readonly kind: 'parent'; +} | { + readonly kind: 'hook'; + readonly reason: string; +} | { + readonly kind: 'disposed'; +}; +/** Durable cancellation cause, including imports whose original coarse record carried no cause. */ +export type TurnEndCancelCause = AgentCancelCause | { + readonly kind: 'legacy'; +}; +/** + * Why a turn ended. Merge-extensible sum type. + */ +export interface TurnEndReasonMap { + completed: { + kind: 'completed'; + }; + /** A cancellation request interrupted the live turn. */ + aborted: { + kind: 'aborted'; + reason: TurnEndCancelCause; + }; + blocked: { + kind: 'blocked'; + }; + /** + * The turn failed. `error` is always a structured failure: the `LlmError` + * facts verbatim, or `{ message: errorChain(error), code: 'UNKNOWN' }` + * flattened from any other error. + */ + error: { + kind: 'error'; + error: LlmFailure; + }; + /** At least one step reached its output-token ceiling, even if a plugin continued the turn. */ + 'max-tokens': { + kind: 'max-tokens'; + }; + /** + * A persistence backend closed a crash-orphaned turn on reload. The loop never + * emits this marker, and the events recorded before the crash remain intact. + */ + interrupted: { + kind: 'interrupted'; + }; +} +/** The union over {@link TurnEndReasonMap} — why a turn ended; plugins extend it by merging variants into the map. */ +export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap]; +/** + * One entry in an agent's todo list — the unit of the `todo/write` + * {@link SessionEventMap} event's whole-list snapshot. + * + * Deliberately minimal: a human-readable `content` line and a three-state + * `status`. No id, priority, or `activeForm` — the list is replaced wholesale + * on every write (last-write-wins), so entries need no stable identity. The + * three statuses describe the complete portable lifecycle needed by model and + * UI consumers. + */ +export interface TodoItem { + /** What this task is — a short imperative line shown in the UI. */ + content: string; + /** Lifecycle state. `in_progress` marks a task being worked now; parallel work may mark several. */ + status: 'pending' | 'in_progress' | 'completed'; +} +/** + * Logged request state outside derived history: call config, system prompt, and + * tools. The latest full `request/header` snapshot reconstructs it; canonical + * empty optional fields are absent. + */ +export interface EpochHeader { + /** The conversation's call configuration (provider, model, reasoning effort, and sampling scalars). */ + config: LlmCallConfig; + /** Effective config fields materialized from the exact adapter rather than proposed by a caller. */ + adapterDefaults?: LlmCallConfigAdapterDefaults; + /** Rendered system prompt text; absent for a system-less request. */ + system?: string; + /** Assembled tool schemas; absent for a tool-less request. */ + tools?: ToolSchema[]; +} +/** Registration-bound metadata for one resolved model route. */ +export interface RequestContext { + /** Registered provider route the metadata belongs to. */ + provider: string; + /** Provider-owned model id the metadata belongs to. */ + model: string; + /** Maximum combined request and response context in tokens, when advertised. */ + contextWindow?: number; +} +/** + * Why a `request/header` snapshot was appended: `'initial'` — the log's first + * header (a new conversation); `'resume'` — a loop instance's first request + * over a log that already has header events (process restart, fork seed); + * `'change'` — a later request used a different header. + */ +export type RequestHeaderReason = 'initial' | 'resume' | 'change'; +/** + * The merge-extensible, append-only source of truth for an agent interaction. + * Message history is derived from this log. Every event is lossless JSON and + * sequence numbers stay contiguous, including raw chunks, so persistence can + * store the canonical log verbatim. + */ +export interface SessionEventMap { + /** + * Opens turn `turn` before the loop claims queued input or runs pre-step. + * Rejection, empty input, cancellation, or failure may close it with no + * step; otherwise the following identified `user/message` event or batch + * records the messages entering the step. + */ + 'turn/start': { + turn: number; + }; + /** + * Closes turn `turn` with the {@link TurnEndReason} that ended it. A turn + * with no entered step has no `step/start` or `step/end`. The loop does not await a + * flush at turn boundaries: `dsh-session-checkpoint-policy` owns the + * per-request durability checkpoint, and consumers that read storage after + * `whenIdle()` flush themselves. Success commits the turn; rejection is + * reported live and does not prevent later work. + */ + 'turn/end': { + turn: number; + reason: TurnEndReason; + }; + /** Opens step `step` of turn `turn` — one model call plus the tool executions it requested. */ + 'step/start': { + turn: number; + step: number; + }; + /** Closes step `step` of turn `turn`. */ + 'step/end': { + turn: number; + step: number; + }; + /** + * A user-role message on the model-visible surface: a direct human prompt + * (the queued message claimed for this turn), a synthetic `agent.inject()` + * context (file-change notices, subdir AGENTS.md, skill content, cron + * notifications, …), or an entered goal continuation round. All three + * project their `content` verbatim; `source` tells them apart. + */ + 'user/message': UserMessage; + /** Raw stream chunk — token-level replay fidelity. */ + 'assistant/chunk': { + turn: number; + step: number; + chunk: StreamChunk; + }; + /** + * Assembled assistant message for one step (derived history uses this). + * Carries the step's `usage` when the adapter reported token accounting, so + * the model output and its accounting travel together (there is no separate + * usage record). `usage` is absent when the adapter reported none. + */ + 'assistant/message': { + turn: number; + step: number; + message: AssistantMessage; + usage?: TokenUsage; + }; + /** + * The model requested one tool invocation: `name` with the raw `arguments` + * JSON string exactly as the model produced it (unparsed). `callId` pairs the + * call with its `tool/result`. + */ + 'tool/call': { + turn: number; + step: number; + callId: CallId; + name: string; + arguments: string; + }; + /** + * A completed tool call's model-facing result, optional internal failure + * identity, and optional tool-private `meta` presentation payload. `meta` is + * opaque to the core (the producing tool owns its shape and reads it back in + * `presentResult`) but MUST be JSON-serializable: `Session.append` + * runtime-validates all event data with `isJsonValue`, so a non-serializable + * `meta` is rejected at the source, and the durable log reproduces the + * identical card on replay. Absent + * unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time + * contextual diff here). + */ + 'tool/result': { + turn: number; + step: number; + message: ToolResultMessage; + error?: { + name: string; + code: string; + }; + meta?: JsonValue; + }; + /** Whole-list snapshot; latest write wins on replay. Log-only UI state; never derived history. */ + 'todo/write': { + todos: TodoItem[]; + }; + /** + * Full header for the next request, appended inside its step before dispatch. + * It is log-only; the latest snapshot reconstructs the request header. + */ + 'request/header': { + header: EpochHeader; + reason: RequestHeaderReason; + }; + /** + * Route metadata for the next request, logged only when the route or capacity + * changes. It does not participate in request reconstruction or header equality. + */ + 'request/context': RequestContext; + /** + * Marks the end of a constructor seed. Events before it have smaller seq + * values and came from the seed (resume, fork, or replay); this lifecycle + * produced none of them. This log-only event is the durable projection of + * {@link Session.firstLiveSeq}. Its payload is empty — position and `time` + * carry the meaning. + * + * Locate the LAST one in stored history. A seed already ending in one is not + * re-marked, so reopening an untouched session does not grow its log per + * pickup and the event need not be at the current `firstLiveSeq`. + * + * `Session`'s constructor is the only legitimate writer. The invariant + * companion deliberately constrains nothing here, so a plugin appending one + * would silently classify every live bracket before it as seed history. + * + * An owner of a standalone open/close bracket (`compaction/start` … + * `compaction/end`) reads it because seed history and live work are otherwise + * byte-identical: an unmatched opening marker before this event belongs to + * an ended lifecycle, whatever ended it. NOT a liveness signal about other + * writers — a concurrently live session holds its own boundary elsewhere, + * so tolerating concurrent writers needs a signal beyond the log. + */ + 'session/end-seed': Record; +} +/** The appendable event-type keys of {@link SessionEventMap}, plugin-merged extensions included. */ +export type SessionEventType = keyof SessionEventMap; +/** + * The subset of {@link SessionEventType} values whose events produce LLM + * messages and are eligible to appear on the ordered surface. Only these + * event types may carry {@link SurfaceOp} and {@link SessionEvent.sourceEventSeqs}. + */ +export type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result'; +/** + * A {@link SessionEvent} that is **on** the ordered surface — its + * `surfaceOp` is guaranteed present (mandatory), narrowed from a + * surface-eligible {@link SessionEvent} by checking both `type` and + * `surfaceOp` at runtime. + * + * Use the `isSurfaceEvent` type guard (in `surface.ts`) to narrow a + * `SessionEvent` to this type. + */ +export type SurfaceEvent = SessionEvent & { + surfaceOp: SurfaceOp; +}; +/** + * How a session event entered the ordered surface. Only valid on + * {@link SurfaceEventType} events. + * + * - `'append'`: added to the tail — normal path for user/assistant/tool + * messages. + * - `{ op: 'replace', start, end }`: replaces surface nodes from `start` + * (inclusive) through `end` (inclusive) with this node. Both must exist as + * surface nodes in the current surface. `start === end` replaces a single + * node. The node's {@link SessionEvent.sourceEventSeqs} must include every + * shadowed surface node. Used by compaction; any surface-replacing producer + * may use it. + */ +export type SurfaceOp = 'append' | { + op: 'replace'; + start: number; + end: number; +}; +/** + * Surface placement and cited source-event seqs for {@link Session.append}. Required on + * message-producing events and forbidden on log-only events. + */ +export interface SurfaceIntent { + surfaceOp: SurfaceOp; + /** + * Complete set of known source-event seqs. `assistant/message` may use a + * present empty array for a known empty provider stream; when the field is + * absent, the event does not record which earlier events produced the message. + * Other surface events require a non-empty set when this field is present. + */ + sourceEventSeqs?: number[]; +} +/** + * One immutable entry in the session log. + * + * A proper discriminated union over `type` (not independent `type`/`data` + * unions), so `switch (event.type)` narrows `event.data` without casts. + * + * The {@link sourceEventSeqs} and {@link surfaceOp} fields are conditional: + * they only exist on {@link SurfaceEventType} variants (`user/message`, + * `assistant/message`, `tool/result`). + * Non-surface events (boundary markers, chunks, usage, errors) never carry + * surface metadata — the compiler enforces this at `Session.append()` + * call sites. + */ +export type SessionEvent = { + [K in SessionEventType]: { + type: K; + /** Monotonic sequence number within the session. */ + seq: number; + /** Unix epoch milliseconds. */ + time: number; + data: SessionEventMap[K]; + /** + * Marks an event a reader may safely skip when it does not recognize + * `type`. Absent means required: a reader meeting an unrecognized type + * without this marker MUST refuse to reconstruct the session instead of + * silently dropping the event, because an unrecognized required event may + * change how the rest of the log is interpreted. A writer sets `true` only + * on purely informational records whose loss cannot affect reconstruction; + * defaulting to required means a forgotten marker over-refuses (an + * inconvenience) rather than silently resuming a gutted session. + */ + ignorable?: true; + } & (K extends SurfaceEventType ? { + /** + * Seq numbers of earlier events that this event cites as sources + * (e.g. the `assistant/chunk` seqs that built an `assistant/message`, + * or the surface nodes shadowed by a compaction replace node). An + * `assistant/message` may carry a present empty array for a known empty + * provider stream; when the field is absent, the event does not record which + * earlier events produced the message. + */ + sourceEventSeqs?: number[]; + /** How this event entered the surface; absent for non-surface events. */ + surfaceOp?: SurfaceOp; + } : object); +}[T]; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/types.js new file mode 100644 index 0000000..83ce659 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/lib/types/types.js @@ -0,0 +1,33 @@ +/** + * Brand a string as a {@link SessionId}. + * @param id - the raw session id string. + * @returns the same string, branded (a compile-time cast — no runtime cost). + */ +export function SessionId(id) { + return id; +} +/** + * The on-disk session format version, stamped into every newly-written {@link SessionHeader} + * and enforced by every persistence backend on load. The single source of truth for the + * version — write sites and the load-time check all read it. + * While the harness is unreleased it is pinned at `0`: no compatibility is + * implied, incompatible logs are rejected, and no migration is provided. + * + * The version is a single monotonic integer with no major/minor split. Whether + * a bump is needed is decided by what the WRITER emits, never by what a newer + * reader can accept: bump exactly when an older runtime could no longer handle + * a new log with full semantic correctness ("parses without error" is not + * correctness — silently skipping content that shapes reconstruction is a + * wrong read). Only structural changes reach that bar: the header shape, the + * {@link SessionEvent} envelope, core event semantics, or the surface + * mechanism (the {@link SurfaceEventType} set and {@link SurfaceOp} variants). + * Adding an ordinary event type does not bump — the per-event + * {@link SessionEvent.ignorable} guard covers vocabulary growth instead. When + * in doubt, bump: a near-identity upgrade step is almost free, a missed bump + * makes older runtimes read new logs wrong silently. The full mechanism + * (upgrade-step chain, in-memory view conversion, migrate-on-continue) is + * recorded in the session-log-version-mechanism Agent Note + * (`.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md`). + */ +export const SESSION_FORMAT_VERSION = 0; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/package.json new file mode 100644 index 0000000..00bbf84 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session/package.json @@ -0,0 +1,60 @@ +{ + "name": "@deepseek-ai/dsh-session", + "description": "Event-sourced session store for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/session" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json", + "./surface": { + "types": "./lib/types/surface.d.ts", + "default": "./lib/types/surface.js" + } + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..a2fcff1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.i18n.yaml new file mode 100644 index 0000000..6d9760a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/settings/settings/README.md +README.md: b1c32c7f4cd05b05802400b33dfdd40f7ed20e61 +README.zh.md: ebb5d2cebb347301c32ea3f2c3448dd33b57872e diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.md new file mode 100644 index 0000000..b1c32c7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.md @@ -0,0 +1,45 @@ +# @deepseek-ai/dsh-settings + +English | [中文](README.zh.md) + +User-settings Service Definition (`ctx.settings`). One provider holds a raw document of per-namespace sections; plugins register a namespace schema and read a resolved value layered as schema defaults, then the registrant's composition `base` (its cordis.yml entry-config subset), then the user document section. Without a mounted provider nothing changes for consumers: they keep resolving entry config alone, so every composition works with or without settings. + +## Service API + +- `documentPath` — absolute path of the provider's user-editable file when it has one; non-file providers leave it `undefined`. Host configuration adapters derive availability from it, while browser protocols expose only a boolean capability and never a filesystem target. +- `prepareDocument()` — return that path after making the document ready for a native editor. The base implementation returns `documentPath`; a file provider may materialize an absent document first. +- `register(ns, schema, { base?, applies? })` — returns the owner `SettingsScope` (`get`/`watch`/`update`). The registration is an effect on the calling plugin's fiber: disposing that fiber removes the namespace and its observers. A stored section the schema rejects fails the registration itself; a duplicate namespace fails loud. +- `describe(options?)` — one descriptor per namespace (`schema.toJSON()` envelope, resolved value, detached `base`/`user` layers, `applies`) for configuration surfaces; a field's presence in `user` is what marks it user-overridden. `describe({ redactSecrets: true })` strips `role('secret')` fields from every layer and adds the `secrets` slot list (`{ path, set }`); every wire surface MUST pass it, and the pure `redactSecrets(schema, value)` walker is exported for other wires. +- `get(ns)` — resolved value, `undefined` while unregistered. +- `update(ns, patch)` — deep-merges the plain-object patch into the user section only (never the `base`), validates the resolved candidate, persists through the provider, then commits. Patches may contain only JSON-compatible data: a Date, Map, BigInt, non-finite number, or circular reference rejects with its `$`-rooted path before anything persists (YAML/JSON storage would silently change such values on reload). Validation failure rejects before anything is persisted; a read-only provider (`writable: false`) rejects every write. Writes to one namespace are serialized in call order. +- `replace(ns, section)` — sets the user section wholesale: the deliberate reset (`replace({})` re-inherits `base` and schema defaults). +- `mutate(ns, ops)` — applies ordered `{ op: 'set' | 'unset', path }` edits to the section as it stands when the write reaches the front of the queue. This is the removal path for any caller holding an INCOMPLETE view: a configuration UI reads the redacted descriptor, so rebuilding a section from it and replacing wholesale deletes every secret the wire never returned, while an op names the one field it means. +- Every write takes an optional `expectedRevision`. Each descriptor carries the namespace's `revision`, a monotonic counter over its RAW section; a write whose expectation no longer matches rejects with `SettingsConflictError` (`code: 'SETTINGS_CONFLICT'`, both revisions attached) instead of overwriting the writer that landed first. The write queue orders writes but cannot by itself tell a fresh writer from one holding a stale snapshot. +- Resolved values are deep-frozen snapshots. Watchers receive `(next, prev)` after each commit: invocations of one callback run asynchronously, one at a time, in commit order (a slow stale invocation can never apply after a newer one), and failures — sync throws and async rejections alike — are contained. After a watch disposer returns, no further invocation starts (one already queued is skipped); an invocation already started still settles. The `settings/updated` event fans out one listener at a time, so one throwing listener cannot starve the rest; an async listener's rejection is contained and logged, which is why `INVARIANT`-coded failures rethrow only from synchronous listeners. +- Service teardown refuses new writes and watcher starts, then drains every queued write and every started watcher invocation before disposal completes; a write whose registrant fiber was disposed mid-flight still reaches storage but commits and notifies nobody. + +## Provider contract + +Subclasses implement `writable`, `load()`, and `persist(ns, section)`, optionally override `documentPath` and `prepareDocument()` for one local user-editable file, and push externally observed documents through the protected `publish(doc)`. The base service init loads and publishes the document once before the service becomes injectable; a provider with its own init (watcher, connection) delegates first via `yield* super[Service.init]()`. At publish, each registered namespace re-resolves independently: an invalid section keeps that namespace's last good value and warns — a live reload never takes the process down — while boot-time and registration-time validation fail loud. + +## Events + +`settings/updated (ns, next, prev, source)` fires after each commit; `source` is `update` (in-process write) or `provider` (external change). It never fires for a deep-equal resolved value — it is the consumer-facing event, and a consumer only cares that its value moved. + +`settings/document-updated (ns, revision)` fires whenever the RAW user section changes, whether or not the resolved value did. Configuration surfaces need this one: storing an override equal to the composition base leaves the resolved value alone but changes what the document says (the field is now overridden, not inherited) and moves the revision every open editor is holding. Listener containment matches `settings/updated`. + +Both declarations live in the client-safe `./types` subpath export, together with the `SettingsNamespace` and `SettingsUpdateSource` types their signatures name; the package root re-exports those types. A consumer outside the Host compilation face therefore reads the very signature the Host emits instead of restating it. + +## Model Experience + +Indirectly, through consumer plugins that resolve model-affecting values (for example a default model route) from their namespaces; each consumer's own surface documents the effect. + +#### KV Cache effect + +No direct invalidation; a consumer that folds a settings value into the request prefix owns that change. + +## Known Limitations and Deferred Work + +- **Single user layer** — resolution knows schema defaults, one composition `base`, and one user document; it does not yet record which layer supplied each resolved value. +- **`redactSecrets` is not a proven wire boundary** — the walker follows `object`/`dict`/`array`, so a `role('secret')` reached only through a union, intersection, or transform is returned VERBATIM with an empty `secrets` list, and `schema.toJSON()` carries a secret field's `.default(...)` to every client. Neither case is rejected; a schema whose secrets are not reachable through the walked containers must not be registered on a wire-exposed namespace. A fail-closed `describeForWire()` — one that refuses a schema it cannot prove safe, and sanitizes the serialized envelope and error text — is the real answer and is deferred. +- **Cross-process concurrency is provider-defined** — the seam serializes writes per namespace in-process only; concurrent processes converge by provider behavior (the local file provider read-modify-writes under a writer lock, so namespaces survive concurrent writers and same-namespace conflicts resolve last-write-wins). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.zh.md new file mode 100644 index 0000000..ebb5d2c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/README.zh.md @@ -0,0 +1,45 @@ +# @deepseek-ai/dsh-settings + +[English](README.md) | 中文 + +用户设置 Service Definition(`ctx.settings`)。一个提供方持有按 namespace 分节的原始文档;插件注册 namespace schema 并读取分层解析值:schema 默认值,然后注册方的组合 `base`(其 cordis.yml entry 配置子集),最后用户文档分节。不挂载提供方时消费方行为不变:仍只按 entry 配置解析,因此任何组合有无 settings 都能工作。 + +## 服务 API + +- `documentPath` — 提供方拥有用户可编辑文件时,该字段是文件的绝对路径;非文件提供方保留 `undefined`。Host 配置适配器据此派生可用性,而浏览器协议只暴露一个布尔能力,绝不暴露文件系统目标。 +- `prepareDocument()` — 让文档做好供原生编辑器打开的准备后返回该路径。基类实现返回 `documentPath`;文件提供方可先创建缺失的文档。 +- `register(ns, schema, { base?, applies? })` — 返回 owner 的 `SettingsScope`(`get`/`watch`/`update`)。注册是调用方插件 fiber 上的 effect:dispose(资源释放)该 fiber 即移除 namespace 及其观察者。schema 拒绝的存量分节会使注册本身失败;重复 namespace 立即报错。 +- `describe(options?)` — 每个 namespace 一条描述(`schema.toJSON()` 封装、解析值、分离出的 `base`/`user` 层、`applies`),供配置界面使用;字段出现在 `user` 中即标记其被用户覆盖。`describe({ redactSecrets: true })` 从每一层剥离 `role('secret')` 字段,并附加 `secrets` slot 列表(`{ path, set }`);每个协议接口都必须传入它,纯遍历器 `redactSecrets(schema, value)` 已导出,供其他 wire 使用。 +- `get(ns)` — 解析值;未注册时为 `undefined`。 +- `update(ns, patch)` — 把普通对象 patch 深合并进用户分节(绝不合并进 `base`),校验解析候选值,经提供方持久化后提交。patch 只能包含与 JSON 兼容的数据:Date、Map、BigInt、非有限数或循环引用会在任何内容持久化前被拒绝,并给出以 `$` 为根的路径(YAML/JSON 存储在重载时会静默改变这类值)。校验失败在持久化前拒绝;只读提供方(`writable: false`)拒绝一切写入。同一 namespace 的写入按调用顺序串行。 +- `replace(ns, section)` — 整体替换用户分节:这是刻意的重置(`replace({})` 重新继承 `base` 与 schema 默认值)。 +- `mutate(ns, ops)` — 在写入排到队首那一刻的分节上,按序施加 `{ op: 'set' | 'unset', path }` 编辑。这是任何持有**不完整**视图的调用方的删除路径:配置 UI 读到的是脱敏后的 descriptor,据此重建分节再整体替换,会把 wire 从未回传的每个机密都删掉,而一条 op 只点名它真正要改的那个字段。 +- 每次写入都可携带可选的 `expectedRevision`。每个 descriptor 都带有该 namespace 的 `revision`——一个针对其**原始**分节的单调计数器;期望值不再匹配的写入会以 `SettingsConflictError`(`code: 'SETTINGS_CONFLICT'`,并附上两个 revision)被拒绝,而不是覆盖先完成写入的写入方。写队列只保证写入的先后次序,它本身分辨不出持有新鲜快照的写入方与持有陈旧快照的写入方。 +- 解析值是深冻结快照。每次提交后观察者收到 `(next, prev)`:同一回调的调用异步、逐次、按提交顺序执行(慢的旧调用绝不会晚于较新的调用生效),异常——同步抛出与异步拒绝——均被隔离。watch 的 disposer 返回后不再启动新的调用(已排队的那一次会被跳过);已启动的调用仍会结算。`settings/updated` 事件逐监听器扇出,一个抛错的 listener 不会饿死其余 listener;异步 listener 的拒绝会被隔离并记入日志,这正是 `INVARIANT` 编码的失败只从同步 listener 重新抛出的原因。 +- 服务卸载先拒绝新写入与观察者调用的启动,再排干全部排队写入与已启动的观察者调用后才完成;registrant fiber 在写入途中被 dispose 时,该写入仍到达存储,但不会提交,也不会通知任何人。 + +## 提供方约定 + +子类实现 `writable`、`load()`、`persist(ns, section)`,可选择为一个本地用户可编辑文件重写 `documentPath` 与 `prepareDocument()`,并通过受保护的 `publish(doc)` 推入外部观察到的文档。基类服务 init 在服务可注入前加载并发布一次文档;拥有自有 init(watcher、连接)的提供方会先通过 `yield* super[Service.init]()` 委托给基类。publish 时每个已注册 namespace 独立重解析:非法分节保留该 namespace 的最后可用值并告警——热重载绝不拖垮进程;启动期与注册期校验则立即报错。 + +## 事件 + +`settings/updated (ns, next, prev, source)` 在每次提交后触发;`source` 为 `update`(进程内写入)或 `provider`(外部变更)。解析值深相等时绝不触发——它面向消费方,而消费方只关心自己的值有没有变。 + +`settings/document-updated (ns, revision)` 在**原始**用户分节发生变化时触发,无论解析值是否随之改变。配置界面需要的是这一个:存入一个与组合 `base` 相同的覆盖值不会改变解析值,却改变了文档的说法(该字段从继承变成了覆盖),也推进了每个已打开编辑器所持有的 revision。监听器的异常隔离方式与 `settings/updated` 相同。 + +两条声明都住在 client-safe 的 `./types` 子路径出口,与其签名点名的 `SettingsNamespace`、`SettingsUpdateSource` 类型同处一处;包根继续 re-export 这些类型。于是 Host 编译面之外的消费方读到的正是 Host 发射的那一份签名,而不必再写一遍。 + +## 模型体验 + +间接生效:消费方插件从各自 namespace 解析影响模型的值(例如默认模型路由);效果由各消费方自己的接口文档说明。 + +#### KV Cache 影响 + +无直接失效;把设置值纳入请求前缀的消费方负责该变更。 + +## 已知限制与暂缓事项 + +- **单一用户层** — 解析只认识 schema 默认值、一个组合 `base` 与一个用户文档;它尚未记录每个解析值由哪一层提供。 +- **`redactSecrets` 并非一条可被证明的协议边界**:walker 只跟随 `object`/`dict`/`array`,因此只能经由 union、intersection 或 transform 抵达的 `role('secret')` 会被**原样**返回,且 `secrets` 列表为空;而 `schema.toJSON()` 会把 secret 字段的 `.default(...)` 一并带给每个客户端。这两种情况都不会被拒绝;机密无法经由被遍历的容器抵达的 schema,绝不可注册到暴露于协议的 namespace 上。真正的答案是一个 fail-closed 的 `describeForWire()`——它拒绝自己无法证明安全的 schema,并对序列化封装与错误文本做净化——此项暂缓。 +- **跨进程并发由提供方定义** — seam 仅在进程内按 namespace 串行化写入;跨进程并发按提供方行为收敛(本地文件提供方在写锁下读-改-写,因此 namespace 在并发写入者下不会丢失,同 namespace 冲突按后写胜出解决)。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/index.js new file mode 100644 index 0000000..5ab6707 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/index.js @@ -0,0 +1,638 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/redact.js +/** +* Structural secret redaction for settings values. `role('secret')` fields are +* removed from a value before it crosses a wire boundary; a sidecar records +* each schema-declared secret position and whether it currently holds a value, +* so a configuration surface can render a write-only input without ever +* receiving the secret itself. +* @module @deepseek-ai/dsh-settings/redact +*/ +/** Whether a value is a plain data object the walker may recurse into. */ +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +function walk(node, value, path, secrets) { + if (node === void 0) return value; + if (node.meta?.role === "secret") { + secrets.push({ + path, + set: value !== void 0 + }); + return; + } + switch (node.type) { + case "object": { + const properties = node.dict ?? {}; + const source = isRecord(value) ? value : void 0; + const rebuilt = {}; + if (source !== void 0) for (const [key, entry] of Object.entries(source)) { + if (key in properties) continue; + rebuilt[key] = entry; + } + for (const [key, child] of Object.entries(properties)) { + const stripped = walk(child, source?.[key], [...path, key], secrets); + if (stripped !== void 0) rebuilt[key] = stripped; + } + return source === void 0 && Object.keys(rebuilt).length === 0 ? value : rebuilt; + } + case "dict": { + if (!isRecord(value)) return value; + const rebuilt = {}; + for (const [key, entry] of Object.entries(value)) { + const stripped = walk(node.inner, entry, [...path, key], secrets); + if (stripped !== void 0) rebuilt[key] = stripped; + } + return rebuilt; + } + case "array": + if (!Array.isArray(value)) return value; + return value.map((entry, index) => walk(node.inner, entry, [...path, String(index)], secrets)); + default: return value; + } +} +/** +* Remove every `role('secret')` field a schema declares from a value. The +* walker follows `object`, `dict`, and `array` containers; a secret must be +* declared directly on a field reachable through those containers (a secret +* buried inside a union branch or transform is not reachable and must not be +* modeled that way). The input is never mutated. +* @param schema - live schemastery schema describing the value. +* @param value - the value to strip; `undefined` yields an empty record with +* object-property secret slots still enumerated. +* @returns the stripped detached value and the ordered secret positions. +*/ +function redactSecrets(schema, value) { + const secrets = []; + return { + value: walk(schema, value, [], secrets), + secrets + }; +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for the user-settings capability seam (`ctx.settings`). Providers store one raw document of +* per-namespace sections; plugins register a namespace schema and read the +* resolved value, which layers schema defaults, the registrant's composition +* `base`, and the user document section, in that order. +* @module @deepseek-ai/dsh-settings +*/ +const NAMESPACE_PATTERN = /^[a-z][a-z0-9-]*$/; +/** +* Brand a raw string as a {@link SettingsNamespace}. +* @param value - candidate namespace; lowercase kebab-case, as in plugin short names. +* @returns the branded namespace. +*/ +function settingsNamespace(value) { + if (!NAMESPACE_PATTERN.test(value)) throw new TypeError(`settings namespace "${value}" must match ${String(NAMESPACE_PATTERN)}`); + return value; +} +/** +* Deep equality over JSON-compatible data (objects, arrays, primitives) — the +* Service Definition's single change-detection predicate, exported so the invariant +* companion checks exactly the implementation's relation. +* @param a - one JSON-compatible value. +* @param b - the other JSON-compatible value. +* @returns whether the two values are structurally equal. +*/ +function deepEqualJson(a, b) { + if (a === b) return true; + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false; + return a.every((entry, index) => deepEqualJson(entry, b[index])); + } + const left = a; + const right = b; + const keys = Object.keys(left); + if (keys.length !== Object.keys(right).length) return false; + return keys.every((key) => key in right && deepEqualJson(left[key], right[key])); +} +/** +* A write refused because the namespace moved since the caller read it. The +* Service Definition's serialized write queue orders writes; it cannot tell a fresh writer +* from one holding a stale snapshot, which is what this reports. +*/ +var SettingsConflictError = class extends Error { + /** Stable machine code for wire layers mapping this to their own taxonomy. */ + code = "SETTINGS_CONFLICT"; + /** The revision the write expected. */ + expected; + /** The revision the namespace actually stands at. */ + actual; + /** + * @param ns - the namespace whose write was refused. + * @param expected - the revision the caller sent. + * @param actual - the revision now stored. + */ + constructor(ns, expected, actual) { + super(`settings namespace "${ns}" changed since it was read (expected revision ${String(expected)}, now ${String(actual)})`); + this.name = "SettingsConflictError"; + this.expected = expected; + this.actual = actual; + } +}; +/** Whether a value is a plain data object (not an array, null, or class instance). */ +function isPlainObject(value) { + if (typeof value !== "object" || value === null || Array.isArray(value)) return false; + const proto = Object.getPrototypeOf(value); + return proto === Object.prototype || proto === null; +} +/** Apply one path op to a detached section, returning the next section. */ +function applyPathOp(section, op) { + const [head, ...rest] = op.path; + if (head === void 0) { + if (op.op === "unset") return {}; + if (!isPlainObject(op.value)) throw new TypeError("settings mutate: setting the section root requires a plain object"); + return { ...op.value }; + } + if (rest.length === 0) { + if (op.op === "set") return { + ...section, + [head]: op.value + }; + const { [head]: _removed, ...kept } = section; + return kept; + } + const child = section[head]; + if (!isPlainObject(child)) { + if (op.op === "unset") return section; + return { + ...section, + [head]: applyPathOp({}, { + ...op, + path: rest + }) + }; + } + return { + ...section, + [head]: applyPathOp(child, { + ...op, + path: rest + }) + }; +} +/** Human label for a value that lossless JSON cannot represent (numbers reject inline). */ +function describeRejected(value) { + if (value === void 0) return "undefined"; + if (typeof value === "object" && value !== null) { + const name = Object.getPrototypeOf(value)?.constructor?.name; + return name === void 0 || name === "Object" ? "a non-plain object" : `a ${name}`; + } + return `a ${typeof value}`; +} +/** +* Detach and validate one write input in a single walk before persistence: +* only JSON data (plain objects, arrays, strings, finite numbers, +* booleans, `null`) may reach a provider document. `structuredClone` alone +* would admit Dates, Maps, BigInts, and cycles that YAML/JSON storage then +* silently distorts on the reload round-trip. `undefined` entries in objects +* are skipped — the same sparse-patch semantics as {@link mergeLayers} — while +* an `undefined` array entry is rejected rather than coerced. +* @param root - plain-object write input (caller-checked). +* @param reject - builds the validation error from a value label and its `$`-rooted path. +* @returns the detached JSON-compatible clone. +*/ +function cloneJsonShaped(root, reject) { + const visiting = /* @__PURE__ */ new WeakSet(); + const clone = (value, path) => { + if (value === null || typeof value === "string" || typeof value === "boolean") return value; + if (typeof value === "number") { + if (!Number.isFinite(value)) throw reject("a non-finite number", path); + return value; + } + if (Array.isArray(value)) { + if (visiting.has(value)) throw reject("a circular reference", path); + visiting.add(value); + const entries = value.map((entry, index) => clone(entry, `${path}[${index}]`)); + visiting.delete(value); + return entries; + } + if (isPlainObject(value)) { + if (visiting.has(value)) throw reject("a circular reference", path); + visiting.add(value); + const out = {}; + for (const [key, entry] of Object.entries(value)) { + if (entry === void 0) continue; + out[key] = clone(entry, `${path}.${key}`); + } + visiting.delete(value); + return out; + } + throw reject(describeRejected(value), path); + }; + return clone(root, "$"); +} +/** +* Layer `over` onto `under`: plain objects merge recursively, every other +* value (arrays included) replaces the lower layer wholesale. `over` never +* carries `undefined` entries — sections come from parsed documents and write +* snapshots pass {@link cloneJsonShaped}, which strips them so a sparse patch +* cannot erase lower keys. +*/ +function mergeLayers(under, over) { + if (over === void 0) return under; + if (!isPlainObject(under) || !isPlainObject(over)) return over; + const merged = { ...under }; + for (const [key, value] of Object.entries(over)) merged[key] = key in merged ? mergeLayers(merged[key], value) : value; + return merged; +} +/** Recursively freeze one resolved value so handed-out snapshots stay immutable. */ +function deepFreeze(value) { + if (typeof value !== "object" || value === null || Object.isFrozen(value)) return value; + for (const entry of Object.values(value)) deepFreeze(entry); + return Object.freeze(value); +} +/** +* Abstract settings service. Providers implement raw-document storage +* (`load`/`persist`) and push external changes through {@link Settings.publish}; +* the base class owns namespace registration, resolution, validation, change +* detection, and the `settings/updated` commit event. +*/ +var SettingsProvider = class extends Service { + registrations = /* @__PURE__ */ new Map(); + /** Latest published raw document; empty until the provider's first publish. */ + document = {}; + /** Per-namespace write chains; settled tails, so a failure never poisons the queue. */ + writeQueues = /* @__PURE__ */ new Map(); + /** In-flight watcher invocation segments, drained by the dispose teardown. */ + pendingTails = /* @__PURE__ */ new Set(); + /** Set at service dispose: refuse new writes while queued ones drain. */ + stopped = false; + /** Opaque read of {@link stopped}: control flow cannot narrow it across awaits. */ + isStopped() { + return this.stopped; + } + constructor(ctx) { + super(ctx, "settings"); + } + /** + * Load the provider's document once and publish it before the service + * becomes injectable, and register the write-drain teardown. Providers with + * their own init (watchers, connections) delegate here first via + * `yield* super[Service.init]()`; their disposers then run before the drain. + */ + async *[Service.init]() { + yield async () => { + this.stopped = true; + await Promise.allSettled([...this.writeQueues.values(), ...this.pendingTails]); + }; + this.publish(await this.load()); + } + /** + * Absolute path of the provider's user-editable document, when its storage + * is one local file. Configuration surfaces use this only as availability + * metadata; the guarded open operation resolves the path again Host-side. + * Non-file providers leave it undefined and expose no open-document affordance. + * @returns the absolute local document path, or undefined for non-file storage. + */ + get documentPath() {} + /** + * Prepare the provider's user-editable document for a native editor. File + * providers may materialize an absent document before returning its path; + * non-file providers return undefined. + * @returns the absolute local document path, or undefined for non-file storage. + */ + prepareDocument() { + return Promise.resolve(this.documentPath); + } + /** + * Register a namespace schema and receive its owner scope. The registration + * is an effect on the calling plugin's fiber: disposing that fiber removes + * the namespace and its observers. An invalid stored section fails the + * registration itself — the earliest point where the schema can judge it. + * @param ns - unique namespace; duplicate registration fails loud. + * @param schema - schemastery schema resolving this namespace's value. + * @param options - composition `base` layer and effect timing. + * @returns the owner scope for reads, observation, and updates. + */ + register(ns, schema, options) { + if (this.registrations.has(ns)) throw new Error(`settings namespace "${ns}" is already registered`); + const registration = { + ns, + schema, + base: options?.base, + applies: options?.applies ?? "live", + ...options?.validate === void 0 ? {} : { validate: options.validate }, + resolved: deepFreeze(this.resolve(schema, options?.base, this.section(ns), options?.validate)), + revision: 0, + watchers: /* @__PURE__ */ new Set() + }; + this.ctx.effect(() => { + this.registrations.set(ns, registration); + return () => this.registrations.delete(ns); + }, `settings.register(${JSON.stringify(String(ns))})`); + return { + get: () => registration.resolved, + watch: (callback) => { + const watcher = { + callback, + tail: Promise.resolve(), + active: true + }; + registration.watchers.add(watcher); + return () => { + watcher.active = false; + registration.watchers.delete(watcher); + }; + }, + update: (patch) => this.update(ns, patch), + replace: (section) => this.replace(ns, section) + }; + } + /** + * Describe every registered namespace for configuration surfaces, including + * the composition `base` and raw user layers so a form can mark which fields + * the user overrode (presence in `user`) and what a reset returns to. + * @param options - redaction switch; wire surfaces must redact. + * @returns one descriptor per registered namespace, in registration order. + */ + describe(options) { + return [...this.registrations.values()].map((registration) => { + let user; + try { + user = this.section(registration.ns); + } catch { + user = void 0; + } + const base = registration.base === void 0 ? void 0 : structuredClone(registration.base); + const detachedUser = user === void 0 ? void 0 : structuredClone(user); + const descriptor = { + ns: registration.ns, + schema: registration.schema.toJSON(), + value: registration.resolved, + revision: registration.revision, + ...base === void 0 ? {} : { base }, + ...detachedUser === void 0 ? {} : { user: detachedUser }, + applies: registration.applies + }; + if (options?.redactSecrets !== true) return descriptor; + const schema = registration.schema; + const redacted = redactSecrets(schema, registration.resolved); + return { + ...descriptor, + value: redacted.value, + ...base === void 0 ? {} : { base: redactSecrets(schema, base).value }, + ...detachedUser === void 0 ? {} : { user: redactSecrets(schema, detachedUser).value }, + secrets: redacted.secrets + }; + }); + } + /** + * Read one registered namespace's resolved value. + * @param ns - the namespace to read. + * @returns the resolved value, or `undefined` while unregistered. + */ + get(ns) { + return this.registrations.get(ns)?.resolved; + } + /** + * Merge a patch into one registered namespace's user layer, validate the + * resolved candidate, persist through the provider, then commit and emit. + * A validation failure rejects before anything is persisted. Writes to one + * namespace are serialized: concurrent updates apply in call order, each + * merging over the previous write's committed section. + * @param ns - the registered namespace to update. + * @param patch - plain-object patch over the user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async update(ns, patch, expectedRevision) { + return this.write(ns, patch, "merge", expectedRevision); + } + /** + * Replace one registered namespace's user section wholesale, validate, + * persist, then commit and emit. Keys absent from `section` fall back to the + * composition `base` and schema defaults — this is the removal/reset path a + * merge-only patch cannot express (`replace({})` re-inherits everything). + * @param ns - the registered namespace to replace. + * @param section - the complete next user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async replace(ns, section, expectedRevision) { + return this.write(ns, section, "replace", expectedRevision); + } + /** + * Apply path-addressed edits to one registered namespace's user section, + * validate, persist, then commit and emit. The ops are applied to the + * section as it stands when the write reaches the front of the queue, so a + * caller never has to restate fields it did not touch — and, crucially, + * cannot delete fields it never saw. This is the write path for any caller + * holding a redacted view; `replace` remains the wholesale reset. + * @param ns - the registered namespace to edit. + * @param ops - ordered path edits; later ops observe earlier ones. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async mutate(ns, ops, expectedRevision) { + if (!Array.isArray(ops)) throw new TypeError(`settings mutate for "${ns}" must be an array of path ops`); + for (const op of ops) { + if (!isPlainObject(op) || op["op"] !== "set" && op["op"] !== "unset") throw new TypeError(`settings mutate for "${ns}" ops must be {op:'set'|'unset', path}`); + if (!Array.isArray(op["path"]) || op["path"].some((part) => typeof part !== "string")) throw new TypeError(`settings mutate for "${ns}" op paths must be arrays of strings`); + } + return this.write(ns, ops, "mutate", expectedRevision); + } + /** Validate a write, then queue it on the namespace's serialized write chain. */ + write(ns, input, mode, expectedRevision) { + const verb = mode === "merge" ? "update" : mode === "replace" ? "replace" : "mutate"; + const registration = this.registrations.get(ns); + if (registration === void 0) throw new Error(`settings namespace "${ns}" is not registered`); + if (this.isStopped()) throw new Error(`settings service is disposed: "${ns}" cannot be written`); + if (!this.writable) throw new Error(`settings provider is read-only: "${ns}" cannot be updated in-process`); + let payload; + if (mode === "mutate") payload = { ops: input }; + else { + if (!isPlainObject(input)) throw new TypeError(`settings ${verb} for "${ns}" must be a plain object`); + payload = input; + } + const snapshot = cloneJsonShaped(payload, (label, path) => /* @__PURE__ */ new TypeError(`settings ${verb} for "${ns}" must contain only JSON-compatible data (found ${label} at ${path})`)); + const run = (this.writeQueues.get(ns) ?? Promise.resolve()).catch(() => void 0).then(async () => { + if (this.isStopped()) throw new Error(`settings service was disposed before the queued "${ns}" ${verb} ran`); + if (this.registrations.get(ns) !== registration) throw new Error(`settings namespace "${ns}" registration was disposed before the queued ${verb} ran`); + const current = this.section(ns) ?? {}; + if (expectedRevision !== void 0 && expectedRevision !== registration.revision) throw new SettingsConflictError(ns, expectedRevision, registration.revision); + const section = mode === "merge" ? mergeLayers(current, snapshot) : mode === "replace" ? snapshot : snapshot["ops"].reduce(applyPathOp, current); + const next = deepFreeze(this.resolve(registration.schema, registration.base, section, registration.validate)); + await this.persist(ns, section); + this.document[ns] = section; + if (this.registrations.get(ns) === registration && !this.isStopped()) { + this.bumpRevision(registration, current, section); + this.commit(registration, next, "update"); + } + }); + this.writeQueues.set(ns, run); + return run; + } + /** + * Provider hook: commit a complete raw document observed in storage. Each + * registered namespace re-resolves; an invalid section keeps that + * namespace's last good value and warns, other namespaces still commit. + * @param doc - the detached raw document (unregistered sections preserved). + * @param source - change origin; defaults to `provider`. + */ + publish(doc, source = "provider") { + const before = /* @__PURE__ */ new Map(); + for (const registration of this.registrations.values()) try { + before.set(registration.ns, this.section(registration.ns)); + } catch { + before.set(registration.ns, void 0); + } + this.document = doc; + for (const registration of this.registrations.values()) { + let next; + try { + next = deepFreeze(this.resolve(registration.schema, registration.base, this.section(registration.ns), registration.validate)); + } catch (error) { + this.ctx.logger.warn("settings: keeping last good \"%s\" after invalid stored section", registration.ns); + this.ctx.logger.warn(error); + continue; + } + this.bumpRevision(registration, before.get(registration.ns), this.section(registration.ns)); + this.commit(registration, next, source); + } + } + /** Read one namespace's raw user section, rejecting non-object sections. */ + section(ns) { + const section = this.document[ns]; + if (section === void 0) return void 0; + if (!isPlainObject(section)) throw new TypeError(`settings section "${ns}" must be an object of keys`); + return section; + } + /** Resolve one namespace value: schema defaults, then `base`, then the user layer. */ + resolve(schema, base, section, validate) { + const value = schema(mergeLayers(base, section)); + validate?.(value); + return value; + } + /** + * Advance a namespace's revision when its RAW section changed, and announce + * it. Deliberately independent of {@link commit}'s resolved-value equality: + * storing an override equal to the composition base leaves the resolved + * value alone but changes what the document says, which is exactly what a + * configuration surface must re-read. + */ + bumpRevision(registration, before, after) { + if (deepEqualJson(before, after)) return; + registration.revision += 1; + this.emitDocumentUpdated(registration.ns, registration.revision); + } + /** Contained fan-out of `settings/document-updated`, mirroring {@link commit}'s. */ + emitDocumentUpdated(ns, revision) { + let invariantFailure; + const args = [ + "settings/document-updated", + ns, + revision + ]; + for (const listener of this.ctx.events.dispatch("emit", args)) try { + const returned = listener(ns, revision); + if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => { + this.warnListenerFailure(ns, error); + }); + } catch (error) { + if (error?.code === "INVARIANT") { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(ns, error); + } + if (invariantFailure !== void 0) throw invariantFailure; + } + /** Commit a resolved value when changed: swap, notify watchers, emit the event. */ + commit(registration, next, source) { + const prev = registration.resolved; + if (deepEqualJson(next, prev)) return; + registration.resolved = next; + for (const watcher of [...registration.watchers]) { + const segment = watcher.tail.then(() => { + if (!watcher.active || this.isStopped()) return; + return watcher.callback(next, prev); + }).then(() => void 0, (error) => { + this.warnWatcherFailure(registration.ns, error); + }); + watcher.tail = segment; + this.pendingTails.add(segment); + segment.then(() => this.pendingTails.delete(segment)); + } + let invariantFailure; + const args = [ + "settings/updated", + registration.ns, + next, + prev, + source + ]; + for (const listener of this.ctx.events.dispatch("emit", args)) try { + const returned = listener(registration.ns, next, prev, source); + if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => { + this.warnListenerFailure(registration.ns, error); + }); + } catch (error) { + if (error?.code === "INVARIANT") { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(registration.ns, error); + } + if (invariantFailure !== void 0) throw invariantFailure; + } + /** Contained-watcher diagnostic shared by the sync and async failure paths. */ + warnWatcherFailure(ns, error) { + this.ctx.logger.warn("settings: watcher for \"%s\" failed", ns); + this.ctx.logger.warn(error); + } + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnListenerFailure(ns, error) { + this.ctx.logger.warn("settings: a settings/updated listener for \"%s\" failed", ns); + this.ctx.logger.warn(error); + } +}; +/** +* Value mirror of the `FiberState` members {@link isUnloading} compares +* against: a const enum has no runtime object to import, and the value is +* needed at runtime (same rationale as the CLI boot driver's mirror). +*/ +const FIBER_DISPOSED = 4; +const FIBER_UNLOADING = 5; +/** Whether the consumer's own fiber is tearing down (not just losing the settings service). */ +function isUnloading(ctx) { + const state = ctx.fiber.state; + return state === FIBER_UNLOADING || state === FIBER_DISPOSED; +} +/** +* Install the canonical optional-settings consumer wiring: while a settings +* service exists, register `ns` with the consumer's composition entry as the +* `base` layer and point the source thunk at the resolved scope; when the +* service goes away (disposal, provider reload), fall back to the entry so +* the consumer keeps working exactly as composed. The registration rides the +* scoped fiber, so no settings service ever mounted means none of this runs. +* @param ctx - consumer plugin context owning the wiring. +* @param ns - the consumer-owned settings namespace. +* @param schema - schema resolving the namespace (typically the plugin Config). +* @param entry - the consumer's composition entry config, used as `base`. +* @param hooks - source sink and change notification. +*/ +function installSettingsSection(ctx, ns, schema, entry, hooks) { + ctx.inject(["settings"], (sctx) => { + const scope = sctx.settings.register(ns, schema, { + base: entry, + ...hooks.validate === void 0 ? {} : { validate: hooks.validate } + }); + hooks.setSource(() => scope.get()); + sctx.effect(() => () => { + if (isUnloading(ctx)) return; + hooks.setSource(() => entry); + hooks.onChange(); + }); + hooks.onChange(); + scope.watch(() => { + if (isUnloading(ctx)) return; + hooks.onChange(); + }); + }); +} +//#endregion +export { SettingsConflictError, SettingsProvider, SettingsProvider as default, deepEqualJson, installSettingsSection, redactSecrets, settingsNamespace }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/invariant.js new file mode 100644 index 0000000..7dacb78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/invariant.js @@ -0,0 +1,180 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/redact.js +/** +* Structural secret redaction for settings values. `role('secret')` fields are +* removed from a value before it crosses a wire boundary; a sidecar records +* each schema-declared secret position and whether it currently holds a value, +* so a configuration surface can render a write-only input without ever +* receiving the secret itself. +* @module @deepseek-ai/dsh-settings/redact +*/ +/** Whether a value is a plain data object the walker may recurse into. */ +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +function walk(node, value, path, secrets) { + if (node === void 0) return value; + if (node.meta?.role === "secret") { + secrets.push({ + path, + set: value !== void 0 + }); + return; + } + switch (node.type) { + case "object": { + const properties = node.dict ?? {}; + const source = isRecord(value) ? value : void 0; + const rebuilt = {}; + if (source !== void 0) for (const [key, entry] of Object.entries(source)) { + if (key in properties) continue; + rebuilt[key] = entry; + } + for (const [key, child] of Object.entries(properties)) { + const stripped = walk(child, source?.[key], [...path, key], secrets); + if (stripped !== void 0) rebuilt[key] = stripped; + } + return source === void 0 && Object.keys(rebuilt).length === 0 ? value : rebuilt; + } + case "dict": { + if (!isRecord(value)) return value; + const rebuilt = {}; + for (const [key, entry] of Object.entries(value)) { + const stripped = walk(node.inner, entry, [...path, key], secrets); + if (stripped !== void 0) rebuilt[key] = stripped; + } + return rebuilt; + } + case "array": + if (!Array.isArray(value)) return value; + return value.map((entry, index) => walk(node.inner, entry, [...path, String(index)], secrets)); + default: return value; + } +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for the user-settings capability seam (`ctx.settings`). Providers store one raw document of +* per-namespace sections; plugins register a namespace schema and read the +* resolved value, which layers schema defaults, the registrant's composition +* `base`, and the user document section, in that order. +* @module @deepseek-ai/dsh-settings +*/ +/** +* Deep equality over JSON-compatible data (objects, arrays, primitives) — the +* Service Definition's single change-detection predicate, exported so the invariant +* companion checks exactly the implementation's relation. +* @param a - one JSON-compatible value. +* @param b - the other JSON-compatible value. +* @returns whether the two values are structurally equal. +*/ +function deepEqualJson(a, b) { + if (a === b) return true; + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false; + return a.every((entry, index) => deepEqualJson(entry, b[index])); + } + const left = a; + const right = b; + const keys = Object.keys(left); + if (keys.length !== Object.keys(right).length) return false; + return keys.every((key) => key in right && deepEqualJson(left[key], right[key])); +} +/** Whether a value is a plain data object (not an array, null, or class instance). */ +function isPlainObject(value) { + if (typeof value !== "object" || value === null || Array.isArray(value)) return false; + const proto = Object.getPrototypeOf(value); + return proto === Object.prototype || proto === null; +} +/** Apply one path op to a detached section, returning the next section. */ +function applyPathOp(section, op) { + const [head, ...rest] = op.path; + if (head === void 0) { + if (op.op === "unset") return {}; + if (!isPlainObject(op.value)) throw new TypeError("settings mutate: setting the section root requires a plain object"); + return { ...op.value }; + } + if (rest.length === 0) { + if (op.op === "set") return { + ...section, + [head]: op.value + }; + const { [head]: _removed, ...kept } = section; + return kept; + } + const child = section[head]; + if (!isPlainObject(child)) { + if (op.op === "unset") return section; + return { + ...section, + [head]: applyPathOp({}, { + ...op, + path: rest + }) + }; + } + return { + ...section, + [head]: applyPathOp(child, { + ...op, + path: rest + }) + }; +} +/** +* Layer `over` onto `under`: plain objects merge recursively, every other +* value (arrays included) replaces the lower layer wholesale. `over` never +* carries `undefined` entries — sections come from parsed documents and write +* snapshots pass {@link cloneJsonShaped}, which strips them so a sparse patch +* cannot erase lower keys. +*/ +function mergeLayers(under, over) { + if (over === void 0) return under; + if (!isPlainObject(under) || !isPlainObject(over)) return over; + const merged = { ...under }; + for (const [key, value] of Object.entries(over)) merged[key] = key in merged ? mergeLayers(merged[key], value) : value; + return merged; +} +/** Recursively freeze one resolved value so handed-out snapshots stay immutable. */ +function deepFreeze(value) { + if (typeof value !== "object" || value === null || Object.isFrozen(value)) return value; + for (const entry of Object.values(value)) deepFreeze(entry); + return Object.freeze(value); +} +Service.init; +//#endregion +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-settings`. +* @module @deepseek-ai/dsh-settings/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-settings"; +/** Cordis companion plugin name. */ +const name = "settings-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* Install the commit-event contract: `settings/updated` fires only for a +* currently registered namespace, only when the resolved value changed, and +* only with the service's authoritative resolved value — all judged with the +* seam's own equality predicate. +*/ +const install = (ctx, fail) => { + ctx.on("settings/updated", (ns, next, prev) => { + const settings = ctx.get("settings"); + if (settings === void 0) fail(`settings/updated for "${ns}" emitted without a live settings service`); + const current = settings.get(ns); + if (current === void 0) fail(`settings/updated for "${ns}" emitted while the namespace is unregistered`); + if (!deepEqualJson(current, next)) fail(`settings/updated for "${ns}" does not match the authoritative resolved value`); + if (deepEqualJson(next, prev)) fail(`settings/updated for "${ns}" emitted without a resolved-value change`); + }); +}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/index.d.ts new file mode 100644 index 0000000..7768c1b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/index.d.ts @@ -0,0 +1,343 @@ +/** + * Service Definition for the user-settings capability seam (`ctx.settings`). Providers store one raw document of + * per-namespace sections; plugins register a namespace schema and read the + * resolved value, which layers schema defaults, the registrant's composition + * `base`, and the user document section, in that order. + * @module @deepseek-ai/dsh-settings + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type z from '@deepseek-ai/schemastery'; +import type { RedactedSecret } from './redact.ts'; +import type { SettingsNamespace, SettingsUpdateSource } from './types.ts'; +export { redactSecrets } from './redact.ts'; +export type { RedactedSecret, RedactedValue } from './redact.ts'; +export type { SettingsNamespace, SettingsUpdateSource } from './types.ts'; +/** + * Brand a raw string as a {@link SettingsNamespace}. + * @param value - candidate namespace; lowercase kebab-case, as in plugin short names. + * @returns the branded namespace. + */ +export declare function settingsNamespace(value: string): SettingsNamespace; +/** When a namespace's changes take effect for its owner. */ +export type SettingsApplies = 'live' | 'restart'; +/** Registration options beyond the namespace schema. */ +export interface SettingsRegisterOptions { + /** Composition-layer values resolved below the user layer (entry-config subset). */ + base?: Partial; + /** Owner's effect timing, surfaced to configuration UIs; defaults to `live`. */ + applies?: SettingsApplies; + /** + * Reject a resolved section the owner could not act on, for constraints its + * schema cannot express — a cross-field requirement, or one field's validity + * depending on another's. Throwing here refuses the *write* that produced the + * value, so a caller learns at `update`/`replace`/`mutate` instead of storing + * something that would silently disable the owner. + * + * Kept separate from the schema because the schema is also what a + * configuration surface renders and what an absent section resolves through; + * folding a cross-field check into it would change both. + * + * Once the owner is registered, a stored section that fails this keeps the + * namespace's last good value and warns, exactly as a schema failure does, + * so an externally edited document cannot strand a running owner. At + * registration there is no last good value yet, so a stored section that + * already fails rejects the registration itself — again exactly as a schema + * failure does. + * @param value - the resolved section, schema-valid by construction. + */ + validate?: (value: T) => void; +} +/** One registered namespace as surfaced to configuration UIs. */ +export interface SettingsDescriptor { + /** The registered namespace. */ + ns: SettingsNamespace; + /** Serialized schemastery schema (`schema.toJSON()`). */ + schema: unknown; + /** Current resolved value. */ + value: unknown; + /** + * Monotonic revision of the raw user section this descriptor was read at. + * Send it back as `expectedRevision` on a write to refuse a stale one. + */ + revision: number; + /** Registrant's composition `base` layer (detached), when one was declared. */ + base?: unknown; + /** + * Raw user section from the stored document (detached), when one exists and + * is well-formed; a field's presence here is what marks it user-overridden. + */ + user?: unknown; + /** Owner's declared effect timing. */ + applies: SettingsApplies; + /** Schema-declared secret positions; present only under `redactSecrets`. */ + secrets?: RedactedSecret[]; +} +/** Options for {@link SettingsProvider.describe}. */ +export interface SettingsDescribeOptions { + /** + * Strip `role('secret')` fields from `value`/`base`/`user` and enumerate + * them in each descriptor's `secrets`. Every wire surface MUST pass this; + * the verbatim default exists for same-process configuration UIs only. + */ + redactSecrets?: boolean; +} +/** Owner-facing handle for one registered namespace. */ +export interface SettingsScope { + /** Current resolved value: schema defaults, then `base`, then the user layer. */ + get(): T; + /** + * Observe committed changes to this namespace's resolved value. Invocations + * of one callback run asynchronously, one at a time, in commit order; a + * rejection is contained and logged like a sync throw. After the disposer + * returns, no further invocation starts — one already queued is skipped; + * one already started still settles, and service disposal waits for it. + * @param callback - invoked after each commit with the next and previous values. + * @returns the disposer removing this observer. + */ + watch(callback: (next: T, prev: T) => void | Promise): () => void; + /** + * Merge a partial patch into this namespace's user layer and persist it. + * @param patch - plain-object patch over the user section; JSON-compatible data + * only (non-JSON values reject with their path before anything persists). + */ + update(patch: object): Promise; + /** + * Replace this namespace's user section wholesale; absent keys re-inherit + * the composition `base` and schema defaults (`replace({})` resets all). + * @param section - the complete next user section; JSON-compatible data only, + * as for {@link update}. + */ + replace(section: object): Promise; +} +declare module '@deepseek-ai/cordis' { + interface Context { + settings: SettingsProvider; + } +} +/** + * Deep equality over JSON-compatible data (objects, arrays, primitives) — the + * Service Definition's single change-detection predicate, exported so the invariant + * companion checks exactly the implementation's relation. + * @param a - one JSON-compatible value. + * @param b - the other JSON-compatible value. + * @returns whether the two values are structurally equal. + */ +export declare function deepEqualJson(a: unknown, b: unknown): boolean; +/** + * A write refused because the namespace moved since the caller read it. The + * Service Definition's serialized write queue orders writes; it cannot tell a fresh writer + * from one holding a stale snapshot, which is what this reports. + */ +export declare class SettingsConflictError extends Error { + /** Stable machine code for wire layers mapping this to their own taxonomy. */ + readonly code = "SETTINGS_CONFLICT"; + /** The revision the write expected. */ + readonly expected: number; + /** The revision the namespace actually stands at. */ + readonly actual: number; + /** + * @param ns - the namespace whose write was refused. + * @param expected - the revision the caller sent. + * @param actual - the revision now stored. + */ + constructor(ns: SettingsNamespace, expected: number, actual: number); +} +/** + * One path-addressed edit to a namespace's user section. Path mutation exists + * for a caller holding an INCOMPLETE view of the section — a configuration UI + * reads the redacted descriptor, which by construction never received the + * `role('secret')` fields. Such a caller can name the field it means without + * restating the section: a wholesale `replace` rebuilt from a redacted + * document silently deletes every secret the wire never returned. + */ +export type SettingsPathOp = { + op: 'set'; + path: readonly string[]; + value: unknown; +} | { + op: 'unset'; + path: readonly string[]; +}; +/** + * Abstract settings service. Providers implement raw-document storage + * (`load`/`persist`) and push external changes through {@link Settings.publish}; + * the base class owns namespace registration, resolution, validation, change + * detection, and the `settings/updated` commit event. + */ +export declare abstract class SettingsProvider extends Service { + private readonly registrations; + /** Latest published raw document; empty until the provider's first publish. */ + private document; + /** Per-namespace write chains; settled tails, so a failure never poisons the queue. */ + private readonly writeQueues; + /** In-flight watcher invocation segments, drained by the dispose teardown. */ + private readonly pendingTails; + /** Set at service dispose: refuse new writes while queued ones drain. */ + private stopped; + /** Opaque read of {@link stopped}: control flow cannot narrow it across awaits. */ + private isStopped; + constructor(ctx: Context); + /** + * Load the provider's document once and publish it before the service + * becomes injectable, and register the write-drain teardown. Providers with + * their own init (watchers, connections) delegate here first via + * `yield* super[Service.init]()`; their disposers then run before the drain. + */ + [Service.init](): AsyncGenerator<() => Promise | void, void, void>; + /** Whether {@link update} may persist through this provider. */ + abstract readonly writable: boolean; + /** + * Absolute path of the provider's user-editable document, when its storage + * is one local file. Configuration surfaces use this only as availability + * metadata; the guarded open operation resolves the path again Host-side. + * Non-file providers leave it undefined and expose no open-document affordance. + * @returns the absolute local document path, or undefined for non-file storage. + */ + get documentPath(): string | undefined; + /** + * Prepare the provider's user-editable document for a native editor. File + * providers may materialize an absent document before returning its path; + * non-file providers return undefined. + * @returns the absolute local document path, or undefined for non-file storage. + */ + prepareDocument(): Promise; + /** + * Read the provider's current raw document (namespace to raw section). + * @returns the detached raw document. + */ + protected abstract load(): Promise>; + /** + * Durably store one namespace's merged user section. + * @param ns - the namespace being written. + * @param section - the complete merged user section to store. + */ + protected abstract persist(ns: SettingsNamespace, section: Record): Promise; + /** + * Register a namespace schema and receive its owner scope. The registration + * is an effect on the calling plugin's fiber: disposing that fiber removes + * the namespace and its observers. An invalid stored section fails the + * registration itself — the earliest point where the schema can judge it. + * @param ns - unique namespace; duplicate registration fails loud. + * @param schema - schemastery schema resolving this namespace's value. + * @param options - composition `base` layer and effect timing. + * @returns the owner scope for reads, observation, and updates. + */ + register(ns: SettingsNamespace, schema: z, options?: SettingsRegisterOptions): SettingsScope; + /** + * Describe every registered namespace for configuration surfaces, including + * the composition `base` and raw user layers so a form can mark which fields + * the user overrode (presence in `user`) and what a reset returns to. + * @param options - redaction switch; wire surfaces must redact. + * @returns one descriptor per registered namespace, in registration order. + */ + describe(options?: SettingsDescribeOptions): SettingsDescriptor[]; + /** + * Read one registered namespace's resolved value. + * @param ns - the namespace to read. + * @returns the resolved value, or `undefined` while unregistered. + */ + get(ns: SettingsNamespace): unknown; + /** + * Merge a patch into one registered namespace's user layer, validate the + * resolved candidate, persist through the provider, then commit and emit. + * A validation failure rejects before anything is persisted. Writes to one + * namespace are serialized: concurrent updates apply in call order, each + * merging over the previous write's committed section. + * @param ns - the registered namespace to update. + * @param patch - plain-object patch over the user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + update(ns: SettingsNamespace, patch: object, expectedRevision?: number): Promise; + /** + * Replace one registered namespace's user section wholesale, validate, + * persist, then commit and emit. Keys absent from `section` fall back to the + * composition `base` and schema defaults — this is the removal/reset path a + * merge-only patch cannot express (`replace({})` re-inherits everything). + * @param ns - the registered namespace to replace. + * @param section - the complete next user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + replace(ns: SettingsNamespace, section: object, expectedRevision?: number): Promise; + /** + * Apply path-addressed edits to one registered namespace's user section, + * validate, persist, then commit and emit. The ops are applied to the + * section as it stands when the write reaches the front of the queue, so a + * caller never has to restate fields it did not touch — and, crucially, + * cannot delete fields it never saw. This is the write path for any caller + * holding a redacted view; `replace` remains the wholesale reset. + * @param ns - the registered namespace to edit. + * @param ops - ordered path edits; later ops observe earlier ones. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + mutate(ns: SettingsNamespace, ops: readonly SettingsPathOp[], expectedRevision?: number): Promise; + /** Validate a write, then queue it on the namespace's serialized write chain. */ + private write; + /** + * Provider hook: commit a complete raw document observed in storage. Each + * registered namespace re-resolves; an invalid section keeps that + * namespace's last good value and warns, other namespaces still commit. + * @param doc - the detached raw document (unregistered sections preserved). + * @param source - change origin; defaults to `provider`. + */ + protected publish(doc: Record, source?: SettingsUpdateSource): void; + /** Read one namespace's raw user section, rejecting non-object sections. */ + private section; + /** Resolve one namespace value: schema defaults, then `base`, then the user layer. */ + private resolve; + /** + * Advance a namespace's revision when its RAW section changed, and announce + * it. Deliberately independent of {@link commit}'s resolved-value equality: + * storing an override equal to the composition base leaves the resolved + * value alone but changes what the document says, which is exactly what a + * configuration surface must re-read. + */ + private bumpRevision; + /** Contained fan-out of `settings/document-updated`, mirroring {@link commit}'s. */ + private emitDocumentUpdated; + /** Commit a resolved value when changed: swap, notify watchers, emit the event. */ + private commit; + /** Contained-watcher diagnostic shared by the sync and async failure paths. */ + private warnWatcherFailure; + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + private warnListenerFailure; +} +/** Hooks a consumer hands to {@link installSettingsSection}. */ +export interface SettingsSectionHooks { + /** + * Receive the active configuration source: the resolved settings scope + * while one is attached, the composition entry otherwise. Called before + * the matching `onChange` at attach and at detach. + * @param current - thunk returning the currently authoritative value. + */ + setSource(current: () => T): void; + /** + * Re-judge anything derived from the source — registration-level facts, + * memoized resolutions — after an attach, a detach, or a committed change. + */ + onChange(): void; + /** + * Reject a resolved section this consumer could not act on, for constraints + * its schema cannot express. See {@link SettingsRegisterOptions.validate}. + * @param value - the resolved section, schema-valid by construction. + */ + validate?: (value: T) => void; +} +/** + * Install the canonical optional-settings consumer wiring: while a settings + * service exists, register `ns` with the consumer's composition entry as the + * `base` layer and point the source thunk at the resolved scope; when the + * service goes away (disposal, provider reload), fall back to the entry so + * the consumer keeps working exactly as composed. The registration rides the + * scoped fiber, so no settings service ever mounted means none of this runs. + * @param ctx - consumer plugin context owning the wiring. + * @param ns - the consumer-owned settings namespace. + * @param schema - schema resolving the namespace (typically the plugin Config). + * @param entry - the consumer's composition entry config, used as `base`. + * @param hooks - source sink and change notification. + */ +export declare function installSettingsSection(ctx: Context, ns: SettingsNamespace, schema: z, entry: T, hooks: SettingsSectionHooks): void; +export default SettingsProvider; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/index.js new file mode 100644 index 0000000..2a1c5a6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/index.js @@ -0,0 +1,688 @@ +/** + * Service Definition for the user-settings capability seam (`ctx.settings`). Providers store one raw document of + * per-namespace sections; plugins register a namespace schema and read the + * resolved value, which layers schema defaults, the registrant's composition + * `base`, and the user document section, in that order. + * @module @deepseek-ai/dsh-settings + */ +import { Service } from '@deepseek-ai/cordis'; +import { redactSecrets } from "./redact.js"; +export { redactSecrets } from "./redact.js"; +const NAMESPACE_PATTERN = /^[a-z][a-z0-9-]*$/; +/** + * Brand a raw string as a {@link SettingsNamespace}. + * @param value - candidate namespace; lowercase kebab-case, as in plugin short names. + * @returns the branded namespace. + */ +export function settingsNamespace(value) { + if (!NAMESPACE_PATTERN.test(value)) { + throw new TypeError(`settings namespace "${value}" must match ${String(NAMESPACE_PATTERN)}`); + } + return value; +} +/** + * Deep equality over JSON-compatible data (objects, arrays, primitives) — the + * Service Definition's single change-detection predicate, exported so the invariant + * companion checks exactly the implementation's relation. + * @param a - one JSON-compatible value. + * @param b - the other JSON-compatible value. + * @returns whether the two values are structurally equal. + */ +export function deepEqualJson(a, b) { + if (a === b) + return true; + if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) + return false; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) + return false; + return a.every((entry, index) => deepEqualJson(entry, b[index])); + } + const left = a; + const right = b; + const keys = Object.keys(left); + if (keys.length !== Object.keys(right).length) + return false; + return keys.every(key => key in right && deepEqualJson(left[key], right[key])); +} +/** + * A write refused because the namespace moved since the caller read it. The + * Service Definition's serialized write queue orders writes; it cannot tell a fresh writer + * from one holding a stale snapshot, which is what this reports. + */ +export class SettingsConflictError extends Error { + /** Stable machine code for wire layers mapping this to their own taxonomy. */ + code = 'SETTINGS_CONFLICT'; + /** The revision the write expected. */ + expected; + /** The revision the namespace actually stands at. */ + actual; + /** + * @param ns - the namespace whose write was refused. + * @param expected - the revision the caller sent. + * @param actual - the revision now stored. + */ + constructor(ns, expected, actual) { + super(`settings namespace "${ns}" changed since it was read (expected revision ${String(expected)}, now ${String(actual)})`); + this.name = 'SettingsConflictError'; + this.expected = expected; + this.actual = actual; + } +} +/** Whether a value is a plain data object (not an array, null, or class instance). */ +function isPlainObject(value) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) + return false; + const proto = Object.getPrototypeOf(value); + return proto === Object.prototype || proto === null; +} +/** Apply one path op to a detached section, returning the next section. */ +function applyPathOp(section, op) { + const [head, ...rest] = op.path; + // The empty path addresses the section itself. + if (head === undefined) { + if (op.op === 'unset') + return {}; + if (!isPlainObject(op.value)) { + throw new TypeError('settings mutate: setting the section root requires a plain object'); + } + return { ...op.value }; + } + if (rest.length === 0) { + if (op.op === 'set') + return { ...section, [head]: op.value }; + const { [head]: _removed, ...kept } = section; + return kept; + } + const child = section[head]; + if (!isPlainObject(child)) { + // Unsetting through an absent path is already satisfied; setting through + // one creates the intermediate objects it needs. + if (op.op === 'unset') + return section; + return { ...section, [head]: applyPathOp({}, { ...op, path: rest }) }; + } + return { ...section, [head]: applyPathOp(child, { ...op, path: rest }) }; +} +/** Human label for a value that lossless JSON cannot represent (numbers reject inline). */ +function describeRejected(value) { + if (value === undefined) + return 'undefined'; + if (typeof value === 'object' && value !== null) { + const proto = Object.getPrototypeOf(value); + const name = proto?.constructor?.name; + return name === undefined || name === 'Object' ? 'a non-plain object' : `a ${name}`; + } + return `a ${typeof value}`; +} +/** + * Detach and validate one write input in a single walk before persistence: + * only JSON data (plain objects, arrays, strings, finite numbers, + * booleans, `null`) may reach a provider document. `structuredClone` alone + * would admit Dates, Maps, BigInts, and cycles that YAML/JSON storage then + * silently distorts on the reload round-trip. `undefined` entries in objects + * are skipped — the same sparse-patch semantics as {@link mergeLayers} — while + * an `undefined` array entry is rejected rather than coerced. + * @param root - plain-object write input (caller-checked). + * @param reject - builds the validation error from a value label and its `$`-rooted path. + * @returns the detached JSON-compatible clone. + */ +function cloneJsonShaped(root, reject) { + const visiting = new WeakSet(); + const clone = (value, path) => { + if (value === null || typeof value === 'string' || typeof value === 'boolean') + return value; + if (typeof value === 'number') { + if (!Number.isFinite(value)) + throw reject('a non-finite number', path); + return value; + } + if (Array.isArray(value)) { + if (visiting.has(value)) + throw reject('a circular reference', path); + visiting.add(value); + const entries = value.map((entry, index) => clone(entry, `${path}[${index}]`)); + // Un-mark on exit so one object referenced twice without a cycle passes. + visiting.delete(value); + return entries; + } + if (isPlainObject(value)) { + if (visiting.has(value)) + throw reject('a circular reference', path); + visiting.add(value); + // TODO(settings-json-properties): Use property-safe construction here and + // in mergeLayers so valid JSON keys such as "__proto__" remain own data. + const out = {}; + for (const [key, entry] of Object.entries(value)) { + if (entry === undefined) + continue; + out[key] = clone(entry, `${path}.${key}`); + } + visiting.delete(value); + return out; + } + throw reject(describeRejected(value), path); + }; + return clone(root, '$'); +} +/** + * Layer `over` onto `under`: plain objects merge recursively, every other + * value (arrays included) replaces the lower layer wholesale. `over` never + * carries `undefined` entries — sections come from parsed documents and write + * snapshots pass {@link cloneJsonShaped}, which strips them so a sparse patch + * cannot erase lower keys. + */ +function mergeLayers(under, over) { + if (over === undefined) + return under; + if (!isPlainObject(under) || !isPlainObject(over)) + return over; + const merged = { ...under }; + for (const [key, value] of Object.entries(over)) { + merged[key] = key in merged ? mergeLayers(merged[key], value) : value; + } + return merged; +} +/** Recursively freeze one resolved value so handed-out snapshots stay immutable. */ +function deepFreeze(value) { + if (typeof value !== 'object' || value === null || Object.isFrozen(value)) + return value; + for (const entry of Object.values(value)) + deepFreeze(entry); + return Object.freeze(value); +} +/** + * Abstract settings service. Providers implement raw-document storage + * (`load`/`persist`) and push external changes through {@link Settings.publish}; + * the base class owns namespace registration, resolution, validation, change + * detection, and the `settings/updated` commit event. + */ +export class SettingsProvider extends Service { + registrations = new Map(); + /** Latest published raw document; empty until the provider's first publish. */ + document = {}; + /** Per-namespace write chains; settled tails, so a failure never poisons the queue. */ + writeQueues = new Map(); + /** In-flight watcher invocation segments, drained by the dispose teardown. */ + pendingTails = new Set(); + /** Set at service dispose: refuse new writes while queued ones drain. */ + stopped = false; + /** Opaque read of {@link stopped}: control flow cannot narrow it across awaits. */ + isStopped() { + return this.stopped; + } + constructor(ctx) { + super(ctx, 'settings'); + } + /** + * Load the provider's document once and publish it before the service + * becomes injectable, and register the write-drain teardown. Providers with + * their own init (watchers, connections) delegate here first via + * `yield* super[Service.init]()`; their disposers then run before the drain. + */ + async *[Service.init]() { + yield async () => { + // Teardown: refuse new writes and new watcher starts, then wait until + // every queued write chain and every started watcher invocation settles + // so disposal completes only once storage and observers are quiescent. + // Invocations queued but not yet started skip via the stopped check. + this.stopped = true; + await Promise.allSettled([...this.writeQueues.values(), ...this.pendingTails]); + }; + this.publish(await this.load()); + } + /** + * Absolute path of the provider's user-editable document, when its storage + * is one local file. Configuration surfaces use this only as availability + * metadata; the guarded open operation resolves the path again Host-side. + * Non-file providers leave it undefined and expose no open-document affordance. + * @returns the absolute local document path, or undefined for non-file storage. + */ + get documentPath() { + return undefined; + } + /** + * Prepare the provider's user-editable document for a native editor. File + * providers may materialize an absent document before returning its path; + * non-file providers return undefined. + * @returns the absolute local document path, or undefined for non-file storage. + */ + prepareDocument() { + return Promise.resolve(this.documentPath); + } + /** + * Register a namespace schema and receive its owner scope. The registration + * is an effect on the calling plugin's fiber: disposing that fiber removes + * the namespace and its observers. An invalid stored section fails the + * registration itself — the earliest point where the schema can judge it. + * @param ns - unique namespace; duplicate registration fails loud. + * @param schema - schemastery schema resolving this namespace's value. + * @param options - composition `base` layer and effect timing. + * @returns the owner scope for reads, observation, and updates. + */ + register(ns, schema, options) { + if (this.registrations.has(ns)) { + throw new Error(`settings namespace "${ns}" is already registered`); + } + const registration = { + ns, + schema: schema, + base: options?.base, + applies: options?.applies ?? 'live', + ...options?.validate === undefined + ? {} + : { validate: options.validate }, + resolved: deepFreeze(this.resolve(schema, options?.base, this.section(ns), options?.validate)), + revision: 0, + watchers: new Set(), + }; + this.ctx.effect(() => { + this.registrations.set(ns, registration); + // TODO(settings-registration-quiescence): Deactivate every watcher and await + // its tail on disposal so callbacks cannot outlive the registrant fiber. + return () => this.registrations.delete(ns); + }, `settings.register(${JSON.stringify(String(ns))})`); + return { + get: () => registration.resolved, + watch: (callback) => { + const watcher = { callback: callback, tail: Promise.resolve(), active: true }; + registration.watchers.add(watcher); + return () => { + watcher.active = false; + registration.watchers.delete(watcher); + }; + }, + update: patch => this.update(ns, patch), + replace: section => this.replace(ns, section), + }; + } + /** + * Describe every registered namespace for configuration surfaces, including + * the composition `base` and raw user layers so a form can mark which fields + * the user overrode (presence in `user`) and what a reset returns to. + * @param options - redaction switch; wire surfaces must redact. + * @returns one descriptor per registered namespace, in registration order. + */ + describe(options) { + return [...this.registrations.values()].map((registration) => { + let user; + try { + user = this.section(registration.ns); + } + catch { + // A malformed stored section already warned at publish and kept the + // last good resolved value; only that malformed shape can throw here, + // and describing it as "no user layer" keeps this read total. + user = undefined; + } + const base = registration.base === undefined ? undefined : structuredClone(registration.base); + const detachedUser = user === undefined ? undefined : structuredClone(user); + const descriptor = { + ns: registration.ns, + schema: registration.schema.toJSON(), + value: registration.resolved, + revision: registration.revision, + ...base === undefined ? {} : { base }, + ...detachedUser === undefined ? {} : { user: detachedUser }, + applies: registration.applies, + }; + if (options?.redactSecrets !== true) + return descriptor; + const schema = registration.schema; + const redacted = redactSecrets(schema, registration.resolved); + return { + ...descriptor, + value: redacted.value, + ...base === undefined ? {} : { base: redactSecrets(schema, base).value }, + ...detachedUser === undefined ? {} : { user: redactSecrets(schema, detachedUser).value }, + secrets: redacted.secrets, + }; + }); + } + /** + * Read one registered namespace's resolved value. + * @param ns - the namespace to read. + * @returns the resolved value, or `undefined` while unregistered. + */ + get(ns) { + return this.registrations.get(ns)?.resolved; + } + /** + * Merge a patch into one registered namespace's user layer, validate the + * resolved candidate, persist through the provider, then commit and emit. + * A validation failure rejects before anything is persisted. Writes to one + * namespace are serialized: concurrent updates apply in call order, each + * merging over the previous write's committed section. + * @param ns - the registered namespace to update. + * @param patch - plain-object patch over the user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async update(ns, patch, expectedRevision) { + return this.write(ns, patch, 'merge', expectedRevision); + } + /** + * Replace one registered namespace's user section wholesale, validate, + * persist, then commit and emit. Keys absent from `section` fall back to the + * composition `base` and schema defaults — this is the removal/reset path a + * merge-only patch cannot express (`replace({})` re-inherits everything). + * @param ns - the registered namespace to replace. + * @param section - the complete next user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async replace(ns, section, expectedRevision) { + return this.write(ns, section, 'replace', expectedRevision); + } + /** + * Apply path-addressed edits to one registered namespace's user section, + * validate, persist, then commit and emit. The ops are applied to the + * section as it stands when the write reaches the front of the queue, so a + * caller never has to restate fields it did not touch — and, crucially, + * cannot delete fields it never saw. This is the write path for any caller + * holding a redacted view; `replace` remains the wholesale reset. + * @param ns - the registered namespace to edit. + * @param ops - ordered path edits; later ops observe earlier ones. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async mutate(ns, ops, expectedRevision) { + if (!Array.isArray(ops)) + throw new TypeError(`settings mutate for "${ns}" must be an array of path ops`); + for (const op of ops) { + if (!isPlainObject(op) || (op['op'] !== 'set' && op['op'] !== 'unset')) { + throw new TypeError(`settings mutate for "${ns}" ops must be {op:'set'|'unset', path}`); + } + if (!Array.isArray(op['path']) || op['path'].some(part => typeof part !== 'string')) { + throw new TypeError(`settings mutate for "${ns}" op paths must be arrays of strings`); + } + } + return this.write(ns, ops, 'mutate', expectedRevision); + } + /** Validate a write, then queue it on the namespace's serialized write chain. */ + write(ns, input, mode, expectedRevision) { + const verb = mode === 'merge' ? 'update' : mode === 'replace' ? 'replace' : 'mutate'; + const registration = this.registrations.get(ns); + if (registration === undefined) { + throw new Error(`settings namespace "${ns}" is not registered`); + } + if (this.isStopped()) { + throw new Error(`settings service is disposed: "${ns}" cannot be written`); + } + if (!this.writable) { + throw new Error(`settings provider is read-only: "${ns}" cannot be updated in-process`); + } + // A mutate's ops array is wrapped so one JSON-shape walk covers both + // shapes; merge/replace carry the section itself. + let payload; + if (mode === 'mutate') { + payload = { ops: input }; + } + else { + if (!isPlainObject(input)) + throw new TypeError(`settings ${verb} for "${ns}" must be a plain object`); + payload = input; + } + // Snapshot at call time: the queue must never read a caller-owned object + // the caller may keep mutating while the write waits its turn. The same + // walk rejects values that JSON cannot preserve (see cloneJsonShaped). + const snapshot = cloneJsonShaped(payload, (label, path) => new TypeError(`settings ${verb} for "${ns}" must contain only JSON-compatible data (found ${label} at ${path})`)); + const previous = this.writeQueues.get(ns) ?? Promise.resolve(); + // Chain past a failed predecessor: one rejected write must not poison the + // namespace queue for every later caller. + const run = previous.catch(() => undefined).then(async () => { + if (this.isStopped()) { + throw new Error(`settings service was disposed before the queued "${ns}" ${verb} ran`); + } + if (this.registrations.get(ns) !== registration) { + throw new Error(`settings namespace "${ns}" registration was disposed before the queued ${verb} ran`); + } + // Every mode derives from the section as it stands NOW, at the front of + // the queue — never from whatever the caller last saw. + const current = this.section(ns) ?? {}; + // The revision check belongs HERE, not at call time: the queue orders + // writes but cannot tell a fresh writer from one holding a snapshot + // that a predecessor already superseded. + if (expectedRevision !== undefined && expectedRevision !== registration.revision) { + throw new SettingsConflictError(ns, expectedRevision, registration.revision); + } + const section = mode === 'merge' + ? mergeLayers(current, snapshot) + : mode === 'replace' + ? snapshot + : snapshot['ops'].reduce(applyPathOp, current); + const next = deepFreeze(this.resolve(registration.schema, registration.base, section, registration.validate)); + await this.persist(ns, section); + // The write reached storage either way; the cache must say so. Commit + // only when this registration is still the namespace owner — a fiber + // disposed (or replaced) mid-persist must not receive the notification. + this.document[ns] = section; + // TODO(settings-replacement-resync): Re-resolve any replacement registration + // from this persisted section so an old in-flight write cannot leave it stale. + if (this.registrations.get(ns) === registration && !this.isStopped()) { + this.bumpRevision(registration, current, section); + this.commit(registration, next, 'update'); + } + }); + this.writeQueues.set(ns, run); + return run; + } + /** + * Provider hook: commit a complete raw document observed in storage. Each + * registered namespace re-resolves; an invalid section keeps that + * namespace's last good value and warns, other namespaces still commit. + * @param doc - the detached raw document (unregistered sections preserved). + * @param source - change origin; defaults to `provider`. + */ + publish(doc, source = 'provider') { + // Read every raw section BEFORE swapping the document, so the revision + // bump below compares what was stored with what now is — an external edit + // moves the revision exactly like an in-process write. + const before = new Map(); + for (const registration of this.registrations.values()) { + try { + before.set(registration.ns, this.section(registration.ns)); + } + catch { + // A malformed stored section is not a readable "before"; treating it + // as absent still bumps against any well-formed replacement. + before.set(registration.ns, undefined); + } + } + this.document = doc; + for (const registration of this.registrations.values()) { + let next; + try { + next = deepFreeze(this.resolve(registration.schema, registration.base, this.section(registration.ns), registration.validate)); + } + catch (error) { + this.ctx.logger.warn('settings: keeping last good "%s" after invalid stored section', registration.ns); + this.ctx.logger.warn(error); + continue; + } + this.bumpRevision(registration, before.get(registration.ns), this.section(registration.ns)); + this.commit(registration, next, source); + } + } + /** Read one namespace's raw user section, rejecting non-object sections. */ + section(ns) { + const section = this.document[ns]; + if (section === undefined) + return undefined; + if (!isPlainObject(section)) { + throw new TypeError(`settings section "${ns}" must be an object of keys`); + } + return section; + } + /** Resolve one namespace value: schema defaults, then `base`, then the user layer. */ + resolve(schema, base, section, validate) { + // The merged candidate is untyped by construction; the schema call is the + // runtime validation that admits it into T. + const value = schema(mergeLayers(base, section)); + // The owner's own check runs on the admitted value, so it sees defaults + // and the composition base exactly as the owner will. + validate?.(value); + return value; + } + /** + * Advance a namespace's revision when its RAW section changed, and announce + * it. Deliberately independent of {@link commit}'s resolved-value equality: + * storing an override equal to the composition base leaves the resolved + * value alone but changes what the document says, which is exactly what a + * configuration surface must re-read. + */ + bumpRevision(registration, before, after) { + if (deepEqualJson(before, after)) + return; + registration.revision += 1; + this.emitDocumentUpdated(registration.ns, registration.revision); + } + /** Contained fan-out of `settings/document-updated`, mirroring {@link commit}'s. */ + emitDocumentUpdated(ns, revision) { + let invariantFailure; + const args = ['settings/document-updated', ns, revision]; + for (const listener of this.ctx.events.dispatch('emit', args)) { + try { + const returned = listener(ns, revision); + if (returned != null && typeof returned.then === 'function') { + void Promise.resolve(returned).then(undefined, (error) => { + this.warnListenerFailure(ns, error); + }); + } + } + catch (error) { + if (error?.code === 'INVARIANT') { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(ns, error); + } + } + if (invariantFailure !== undefined) + throw invariantFailure; + } + /** Commit a resolved value when changed: swap, notify watchers, emit the event. */ + commit(registration, next, source) { + const prev = registration.resolved; + if (deepEqualJson(next, prev)) + return; + registration.resolved = next; + for (const watcher of [...registration.watchers]) { + // Serialize per watcher: invocations of one callback run one at a time + // in commit order, so a slow stale invocation can never apply after a + // newer one. Sync throws and async rejections land in the same handler. + // The activity check runs when the queued invocation would start, so a + // disposer (or service stop) that ran while it waited prevents the + // start entirely; started invocations drain at service dispose. + const segment = watcher.tail + .then(() => { + if (!watcher.active || this.isStopped()) + return; + return watcher.callback(next, prev); + }) + .then(() => undefined, (error) => { + this.warnWatcherFailure(registration.ns, error); + }); + watcher.tail = segment; + this.pendingTails.add(segment); + void segment.then(() => this.pendingTails.delete(segment)); + } + // Fan the event out one listener at a time (the plain emit stops at the + // first throwing listener, starving the rest). Invariant violations are + // harness-fatal by design and rethrow after every listener ran; any other + // failure is contained so one broken observer cannot wedge the commit + // path (and, through it, a provider's reload loop). + let invariantFailure; + const args = ['settings/updated', registration.ns, next, prev, source]; + for (const listener of this.ctx.events.dispatch('emit', args)) { + try { + const returned = listener(registration.ns, next, prev, source); + if (returned != null && typeof returned.then === 'function') { + // An emit listener may still be an async function; its rejection + // cannot reach the synchronous INVARIANT rethrow below, so it is + // contained here instead of becoming an unhandled rejection. + void Promise.resolve(returned).then(undefined, (error) => { + this.warnListenerFailure(registration.ns, error); + }); + } + } + catch (error) { + if (error?.code === 'INVARIANT') { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(registration.ns, error); + } + } + if (invariantFailure !== undefined) + throw invariantFailure; + } + /** Contained-watcher diagnostic shared by the sync and async failure paths. */ + warnWatcherFailure(ns, error) { + this.ctx.logger.warn('settings: watcher for "%s" failed', ns); + this.ctx.logger.warn(error); + } + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnListenerFailure(ns, error) { + this.ctx.logger.warn('settings: a settings/updated listener for "%s" failed', ns); + this.ctx.logger.warn(error); + } +} +/** + * Value mirror of the `FiberState` members {@link isUnloading} compares + * against: a const enum has no runtime object to import, and the value is + * needed at runtime (same rationale as the CLI boot driver's mirror). + */ +const FIBER_DISPOSED = 4; +const FIBER_UNLOADING = 5; +/** Whether the consumer's own fiber is tearing down (not just losing the settings service). */ +function isUnloading(ctx) { + const state = ctx.fiber.state; + return state === FIBER_UNLOADING || state === FIBER_DISPOSED; +} +/** + * Install the canonical optional-settings consumer wiring: while a settings + * service exists, register `ns` with the consumer's composition entry as the + * `base` layer and point the source thunk at the resolved scope; when the + * service goes away (disposal, provider reload), fall back to the entry so + * the consumer keeps working exactly as composed. The registration rides the + * scoped fiber, so no settings service ever mounted means none of this runs. + * @param ctx - consumer plugin context owning the wiring. + * @param ns - the consumer-owned settings namespace. + * @param schema - schema resolving the namespace (typically the plugin Config). + * @param entry - the consumer's composition entry config, used as `base`. + * @param hooks - source sink and change notification. + */ +export function installSettingsSection(ctx, ns, schema, entry, hooks) { + ctx.inject(['settings'], (sctx) => { + const scope = sctx.settings.register(ns, schema, { + base: entry, + ...hooks.validate === undefined ? {} : { validate: hooks.validate }, + }); + hooks.setSource(() => scope.get()); + sctx.effect(() => () => { + // This disposer runs for two different reasons. A settings provider + // detaching leaves the consumer running, so it must fall back to its + // composition entry and re-judge what it derived. The consumer's own + // unload runs it too — and there `onChange` would re-register routes + // and touch resources the teardown is releasing, so the fallback is + // pointless and the notification actively harmful. + if (isUnloading(ctx)) + return; + hooks.setSource(() => entry); + hooks.onChange(); + }); + hooks.onChange(); + scope.watch(() => { + // A stored change landing while the consumer unloads reaches the watcher + // before the registration is released, and `onChange` is exactly as + // harmful here as in the disposer above: it re-registers routes against + // a fiber whose resources are being let go. + if (isUnloading(ctx)) + return; + hooks.onChange(); + }); + }); +} +export default SettingsProvider; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.d.ts new file mode 100644 index 0000000..560f361 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-settings`. + * @module @deepseek-ai/dsh-settings/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "settings-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.js new file mode 100644 index 0000000..82ccd30 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.js @@ -0,0 +1,41 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-settings`. + * @module @deepseek-ai/dsh-settings/invariant + */ +import { deepEqualJson } from "./index.js"; +const PACKAGE_NAME = '@deepseek-ai/dsh-settings'; +/** Cordis companion plugin name. */ +export const name = 'settings-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * Install the commit-event contract: `settings/updated` fires only for a + * currently registered namespace, only when the resolved value changed, and + * only with the service's authoritative resolved value — all judged with the + * seam's own equality predicate. + */ +const install = (ctx, fail) => { + ctx.on('settings/updated', (ns, next, prev) => { + const settings = ctx.get('settings'); + if (settings === undefined) { + fail(`settings/updated for "${ns}" emitted without a live settings service`); + } + const current = settings.get(ns); + if (current === undefined) { + fail(`settings/updated for "${ns}" emitted while the namespace is unregistered`); + } + if (!deepEqualJson(current, next)) { + fail(`settings/updated for "${ns}" does not match the authoritative resolved value`); + } + if (deepEqualJson(next, prev)) { + fail(`settings/updated for "${ns}" emitted without a resolved-value change`); + } + }); +}; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.d.ts new file mode 100644 index 0000000..d582774 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.d.ts @@ -0,0 +1,40 @@ +/** + * Structural secret redaction for settings values. `role('secret')` fields are + * removed from a value before it crosses a wire boundary; a sidecar records + * each schema-declared secret position and whether it currently holds a value, + * so a configuration surface can render a write-only input without ever + * receiving the secret itself. + * @module @deepseek-ai/dsh-settings/redact + */ +import type z from '@deepseek-ai/schemastery'; +/** One schema-declared secret position inside a redacted value. */ +export interface RedactedSecret { + /** Path from the section root to the removed field (concrete dict keys and array indexes included). */ + path: string[]; + /** Whether the field held a value before redaction. */ + set: boolean; +} +/** A value with every `role('secret')` field removed, plus the removal record. */ +export interface RedactedValue { + /** Detached copy of the input with secret fields absent. */ + value: unknown; + /** + * Every reachable secret position: object properties always (even unset, so + * a form knows the slot exists), dict entries and array items only where the + * value has them. + */ + secrets: RedactedSecret[]; +} +/** + * Remove every `role('secret')` field a schema declares from a value. The + * walker follows `object`, `dict`, and `array` containers; a secret must be + * declared directly on a field reachable through those containers (a secret + * buried inside a union branch or transform is not reachable and must not be + * modeled that way). The input is never mutated. + * @param schema - live schemastery schema describing the value. + * @param value - the value to strip; `undefined` yields an empty record with + * object-property secret slots still enumerated. + * @returns the stripped detached value and the ordered secret positions. + */ +export declare function redactSecrets(schema: z, value: unknown): RedactedValue; +//# sourceMappingURL=redact.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.js new file mode 100644 index 0000000..6361590 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.js @@ -0,0 +1,78 @@ +/** + * Structural secret redaction for settings values. `role('secret')` fields are + * removed from a value before it crosses a wire boundary; a sidecar records + * each schema-declared secret position and whether it currently holds a value, + * so a configuration surface can render a write-only input without ever + * receiving the secret itself. + * @module @deepseek-ai/dsh-settings/redact + */ +/** Whether a value is a plain data object the walker may recurse into. */ +function isRecord(value) { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} +function walk(node, value, path, secrets) { + if (node === undefined) + return value; + if (node.meta?.role === 'secret') { + secrets.push({ path, set: value !== undefined }); + return undefined; + } + switch (node.type) { + case 'object': { + const properties = node.dict ?? {}; + const source = isRecord(value) ? value : undefined; + const rebuilt = {}; + if (source !== undefined) { + for (const [key, entry] of Object.entries(source)) { + if (key in properties) + continue; + rebuilt[key] = entry; + } + } + for (const [key, child] of Object.entries(properties)) { + const stripped = walk(child, source?.[key], [...path, key], secrets); + if (stripped !== undefined) + rebuilt[key] = stripped; + } + return source === undefined && Object.keys(rebuilt).length === 0 ? value : rebuilt; + } + case 'dict': { + if (!isRecord(value)) + return value; + const rebuilt = {}; + for (const [key, entry] of Object.entries(value)) { + const stripped = walk(node.inner, entry, [...path, key], secrets); + if (stripped !== undefined) + rebuilt[key] = stripped; + } + return rebuilt; + } + case 'array': { + if (!Array.isArray(value)) + return value; + return value.map((entry, index) => walk(node.inner, entry, [...path, String(index)], secrets)); + } + default: + // TODO(settings-wire-redaction): Fail closed instead — a secret reachable + // only through a union, intersection, or transform is returned verbatim + // here, with nothing recording that it was missed. + return value; + } +} +/** + * Remove every `role('secret')` field a schema declares from a value. The + * walker follows `object`, `dict`, and `array` containers; a secret must be + * declared directly on a field reachable through those containers (a secret + * buried inside a union branch or transform is not reachable and must not be + * modeled that way). The input is never mutated. + * @param schema - live schemastery schema describing the value. + * @param value - the value to strip; `undefined` yields an empty record with + * object-property secret slots still enumerated. + * @returns the stripped detached value and the ordered secret positions. + */ +export function redactSecrets(schema, value) { + const secrets = []; + const stripped = walk(schema, value, [], secrets); + return { value: stripped, secrets }; +} +//# sourceMappingURL=redact.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/types.d.ts new file mode 100644 index 0000000..c113168 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/types.d.ts @@ -0,0 +1,46 @@ +/** + * Client-safe type surface of the user-settings seam: the namespace brand, the + * commit-origin union, and the seam's Cordis event declarations. Types only — + * no runtime code, and nothing here reaches a Host-only symbol, so a Client + * compilation face reads exactly the signatures the Host emits. + * + * @module @deepseek-ai/dsh-settings/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Nominal id of one registered settings namespace. */ +export type SettingsNamespace = Branded<'SettingsNamespace'>; +/** Origin of one committed settings change. */ +export type SettingsUpdateSource = 'update' | 'provider'; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * Committed change to one registered namespace's resolved value. Emitted + * after the provider persisted (for `update`) or published (`provider`) + * the change; never emitted when the resolved value is deep-equal. + * Listener failures are contained and logged — a sync throw and an async + * rejection alike — except `INVARIANT`-coded failures, which rethrow + * after every listener ran; that rethrow reaches the emitter only from + * synchronous listeners, so invariant checks on this event must not be + * async functions. + * @param ns - the namespace whose resolved value changed. + * @param next - the new resolved value. + * @param prev - the previous resolved value. + * @param source - whether the change entered through `update()` or the provider. + * @mode emit + */ + 'settings/updated'(ns: SettingsNamespace, next: unknown, prev: unknown, source: SettingsUpdateSource): void; + /** + * One registered namespace's RAW user section changed, whether or not the + * resolved value did. `settings/updated` is the consumer-facing event and + * stays deep-equal-gated; this one exists for configuration surfaces, + * which must learn that a field went from inherited to overridden (same + * resolved value, different meaning) and that their held revision is + * stale. Listener containment matches `settings/updated`. + * @param ns - the namespace whose stored section changed. + * @param revision - the namespace's new revision. + * @mode emit + */ + 'settings/document-updated'(ns: SettingsNamespace, revision: number): void; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/types.js new file mode 100644 index 0000000..3438445 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/lib/types/types.js @@ -0,0 +1,10 @@ +/** + * Client-safe type surface of the user-settings seam: the namespace brand, the + * commit-origin union, and the seam's Cordis event declarations. Types only — + * no runtime code, and nothing here reaches a Host-only symbol, so a Client + * compilation face reads exactly the signatures the Host emits. + * + * @module @deepseek-ai/dsh-settings/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/package.json new file mode 100644 index 0000000..d60857f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/dsh-settings/package.json @@ -0,0 +1,51 @@ +{ + "name": "@deepseek-ai/dsh-settings", + "description": "Abstract user-settings seam (ctx.settings) for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/settings/settings" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/schemastery": "^3.18.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_52495af71738a1095726249ceff4fd7b/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.i18n.yaml new file mode 100644 index 0000000..6d9760a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/settings/settings/README.md +README.md: b1c32c7f4cd05b05802400b33dfdd40f7ed20e61 +README.zh.md: ebb5d2cebb347301c32ea3f2c3448dd33b57872e diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.md new file mode 100644 index 0000000..b1c32c7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.md @@ -0,0 +1,45 @@ +# @deepseek-ai/dsh-settings + +English | [中文](README.zh.md) + +User-settings Service Definition (`ctx.settings`). One provider holds a raw document of per-namespace sections; plugins register a namespace schema and read a resolved value layered as schema defaults, then the registrant's composition `base` (its cordis.yml entry-config subset), then the user document section. Without a mounted provider nothing changes for consumers: they keep resolving entry config alone, so every composition works with or without settings. + +## Service API + +- `documentPath` — absolute path of the provider's user-editable file when it has one; non-file providers leave it `undefined`. Host configuration adapters derive availability from it, while browser protocols expose only a boolean capability and never a filesystem target. +- `prepareDocument()` — return that path after making the document ready for a native editor. The base implementation returns `documentPath`; a file provider may materialize an absent document first. +- `register(ns, schema, { base?, applies? })` — returns the owner `SettingsScope` (`get`/`watch`/`update`). The registration is an effect on the calling plugin's fiber: disposing that fiber removes the namespace and its observers. A stored section the schema rejects fails the registration itself; a duplicate namespace fails loud. +- `describe(options?)` — one descriptor per namespace (`schema.toJSON()` envelope, resolved value, detached `base`/`user` layers, `applies`) for configuration surfaces; a field's presence in `user` is what marks it user-overridden. `describe({ redactSecrets: true })` strips `role('secret')` fields from every layer and adds the `secrets` slot list (`{ path, set }`); every wire surface MUST pass it, and the pure `redactSecrets(schema, value)` walker is exported for other wires. +- `get(ns)` — resolved value, `undefined` while unregistered. +- `update(ns, patch)` — deep-merges the plain-object patch into the user section only (never the `base`), validates the resolved candidate, persists through the provider, then commits. Patches may contain only JSON-compatible data: a Date, Map, BigInt, non-finite number, or circular reference rejects with its `$`-rooted path before anything persists (YAML/JSON storage would silently change such values on reload). Validation failure rejects before anything is persisted; a read-only provider (`writable: false`) rejects every write. Writes to one namespace are serialized in call order. +- `replace(ns, section)` — sets the user section wholesale: the deliberate reset (`replace({})` re-inherits `base` and schema defaults). +- `mutate(ns, ops)` — applies ordered `{ op: 'set' | 'unset', path }` edits to the section as it stands when the write reaches the front of the queue. This is the removal path for any caller holding an INCOMPLETE view: a configuration UI reads the redacted descriptor, so rebuilding a section from it and replacing wholesale deletes every secret the wire never returned, while an op names the one field it means. +- Every write takes an optional `expectedRevision`. Each descriptor carries the namespace's `revision`, a monotonic counter over its RAW section; a write whose expectation no longer matches rejects with `SettingsConflictError` (`code: 'SETTINGS_CONFLICT'`, both revisions attached) instead of overwriting the writer that landed first. The write queue orders writes but cannot by itself tell a fresh writer from one holding a stale snapshot. +- Resolved values are deep-frozen snapshots. Watchers receive `(next, prev)` after each commit: invocations of one callback run asynchronously, one at a time, in commit order (a slow stale invocation can never apply after a newer one), and failures — sync throws and async rejections alike — are contained. After a watch disposer returns, no further invocation starts (one already queued is skipped); an invocation already started still settles. The `settings/updated` event fans out one listener at a time, so one throwing listener cannot starve the rest; an async listener's rejection is contained and logged, which is why `INVARIANT`-coded failures rethrow only from synchronous listeners. +- Service teardown refuses new writes and watcher starts, then drains every queued write and every started watcher invocation before disposal completes; a write whose registrant fiber was disposed mid-flight still reaches storage but commits and notifies nobody. + +## Provider contract + +Subclasses implement `writable`, `load()`, and `persist(ns, section)`, optionally override `documentPath` and `prepareDocument()` for one local user-editable file, and push externally observed documents through the protected `publish(doc)`. The base service init loads and publishes the document once before the service becomes injectable; a provider with its own init (watcher, connection) delegates first via `yield* super[Service.init]()`. At publish, each registered namespace re-resolves independently: an invalid section keeps that namespace's last good value and warns — a live reload never takes the process down — while boot-time and registration-time validation fail loud. + +## Events + +`settings/updated (ns, next, prev, source)` fires after each commit; `source` is `update` (in-process write) or `provider` (external change). It never fires for a deep-equal resolved value — it is the consumer-facing event, and a consumer only cares that its value moved. + +`settings/document-updated (ns, revision)` fires whenever the RAW user section changes, whether or not the resolved value did. Configuration surfaces need this one: storing an override equal to the composition base leaves the resolved value alone but changes what the document says (the field is now overridden, not inherited) and moves the revision every open editor is holding. Listener containment matches `settings/updated`. + +Both declarations live in the client-safe `./types` subpath export, together with the `SettingsNamespace` and `SettingsUpdateSource` types their signatures name; the package root re-exports those types. A consumer outside the Host compilation face therefore reads the very signature the Host emits instead of restating it. + +## Model Experience + +Indirectly, through consumer plugins that resolve model-affecting values (for example a default model route) from their namespaces; each consumer's own surface documents the effect. + +#### KV Cache effect + +No direct invalidation; a consumer that folds a settings value into the request prefix owns that change. + +## Known Limitations and Deferred Work + +- **Single user layer** — resolution knows schema defaults, one composition `base`, and one user document; it does not yet record which layer supplied each resolved value. +- **`redactSecrets` is not a proven wire boundary** — the walker follows `object`/`dict`/`array`, so a `role('secret')` reached only through a union, intersection, or transform is returned VERBATIM with an empty `secrets` list, and `schema.toJSON()` carries a secret field's `.default(...)` to every client. Neither case is rejected; a schema whose secrets are not reachable through the walked containers must not be registered on a wire-exposed namespace. A fail-closed `describeForWire()` — one that refuses a schema it cannot prove safe, and sanitizes the serialized envelope and error text — is the real answer and is deferred. +- **Cross-process concurrency is provider-defined** — the seam serializes writes per namespace in-process only; concurrent processes converge by provider behavior (the local file provider read-modify-writes under a writer lock, so namespaces survive concurrent writers and same-namespace conflicts resolve last-write-wins). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.zh.md new file mode 100644 index 0000000..ebb5d2c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/README.zh.md @@ -0,0 +1,45 @@ +# @deepseek-ai/dsh-settings + +[English](README.md) | 中文 + +用户设置 Service Definition(`ctx.settings`)。一个提供方持有按 namespace 分节的原始文档;插件注册 namespace schema 并读取分层解析值:schema 默认值,然后注册方的组合 `base`(其 cordis.yml entry 配置子集),最后用户文档分节。不挂载提供方时消费方行为不变:仍只按 entry 配置解析,因此任何组合有无 settings 都能工作。 + +## 服务 API + +- `documentPath` — 提供方拥有用户可编辑文件时,该字段是文件的绝对路径;非文件提供方保留 `undefined`。Host 配置适配器据此派生可用性,而浏览器协议只暴露一个布尔能力,绝不暴露文件系统目标。 +- `prepareDocument()` — 让文档做好供原生编辑器打开的准备后返回该路径。基类实现返回 `documentPath`;文件提供方可先创建缺失的文档。 +- `register(ns, schema, { base?, applies? })` — 返回 owner 的 `SettingsScope`(`get`/`watch`/`update`)。注册是调用方插件 fiber 上的 effect:dispose(资源释放)该 fiber 即移除 namespace 及其观察者。schema 拒绝的存量分节会使注册本身失败;重复 namespace 立即报错。 +- `describe(options?)` — 每个 namespace 一条描述(`schema.toJSON()` 封装、解析值、分离出的 `base`/`user` 层、`applies`),供配置界面使用;字段出现在 `user` 中即标记其被用户覆盖。`describe({ redactSecrets: true })` 从每一层剥离 `role('secret')` 字段,并附加 `secrets` slot 列表(`{ path, set }`);每个协议接口都必须传入它,纯遍历器 `redactSecrets(schema, value)` 已导出,供其他 wire 使用。 +- `get(ns)` — 解析值;未注册时为 `undefined`。 +- `update(ns, patch)` — 把普通对象 patch 深合并进用户分节(绝不合并进 `base`),校验解析候选值,经提供方持久化后提交。patch 只能包含与 JSON 兼容的数据:Date、Map、BigInt、非有限数或循环引用会在任何内容持久化前被拒绝,并给出以 `$` 为根的路径(YAML/JSON 存储在重载时会静默改变这类值)。校验失败在持久化前拒绝;只读提供方(`writable: false`)拒绝一切写入。同一 namespace 的写入按调用顺序串行。 +- `replace(ns, section)` — 整体替换用户分节:这是刻意的重置(`replace({})` 重新继承 `base` 与 schema 默认值)。 +- `mutate(ns, ops)` — 在写入排到队首那一刻的分节上,按序施加 `{ op: 'set' | 'unset', path }` 编辑。这是任何持有**不完整**视图的调用方的删除路径:配置 UI 读到的是脱敏后的 descriptor,据此重建分节再整体替换,会把 wire 从未回传的每个机密都删掉,而一条 op 只点名它真正要改的那个字段。 +- 每次写入都可携带可选的 `expectedRevision`。每个 descriptor 都带有该 namespace 的 `revision`——一个针对其**原始**分节的单调计数器;期望值不再匹配的写入会以 `SettingsConflictError`(`code: 'SETTINGS_CONFLICT'`,并附上两个 revision)被拒绝,而不是覆盖先完成写入的写入方。写队列只保证写入的先后次序,它本身分辨不出持有新鲜快照的写入方与持有陈旧快照的写入方。 +- 解析值是深冻结快照。每次提交后观察者收到 `(next, prev)`:同一回调的调用异步、逐次、按提交顺序执行(慢的旧调用绝不会晚于较新的调用生效),异常——同步抛出与异步拒绝——均被隔离。watch 的 disposer 返回后不再启动新的调用(已排队的那一次会被跳过);已启动的调用仍会结算。`settings/updated` 事件逐监听器扇出,一个抛错的 listener 不会饿死其余 listener;异步 listener 的拒绝会被隔离并记入日志,这正是 `INVARIANT` 编码的失败只从同步 listener 重新抛出的原因。 +- 服务卸载先拒绝新写入与观察者调用的启动,再排干全部排队写入与已启动的观察者调用后才完成;registrant fiber 在写入途中被 dispose 时,该写入仍到达存储,但不会提交,也不会通知任何人。 + +## 提供方约定 + +子类实现 `writable`、`load()`、`persist(ns, section)`,可选择为一个本地用户可编辑文件重写 `documentPath` 与 `prepareDocument()`,并通过受保护的 `publish(doc)` 推入外部观察到的文档。基类服务 init 在服务可注入前加载并发布一次文档;拥有自有 init(watcher、连接)的提供方会先通过 `yield* super[Service.init]()` 委托给基类。publish 时每个已注册 namespace 独立重解析:非法分节保留该 namespace 的最后可用值并告警——热重载绝不拖垮进程;启动期与注册期校验则立即报错。 + +## 事件 + +`settings/updated (ns, next, prev, source)` 在每次提交后触发;`source` 为 `update`(进程内写入)或 `provider`(外部变更)。解析值深相等时绝不触发——它面向消费方,而消费方只关心自己的值有没有变。 + +`settings/document-updated (ns, revision)` 在**原始**用户分节发生变化时触发,无论解析值是否随之改变。配置界面需要的是这一个:存入一个与组合 `base` 相同的覆盖值不会改变解析值,却改变了文档的说法(该字段从继承变成了覆盖),也推进了每个已打开编辑器所持有的 revision。监听器的异常隔离方式与 `settings/updated` 相同。 + +两条声明都住在 client-safe 的 `./types` 子路径出口,与其签名点名的 `SettingsNamespace`、`SettingsUpdateSource` 类型同处一处;包根继续 re-export 这些类型。于是 Host 编译面之外的消费方读到的正是 Host 发射的那一份签名,而不必再写一遍。 + +## 模型体验 + +间接生效:消费方插件从各自 namespace 解析影响模型的值(例如默认模型路由);效果由各消费方自己的接口文档说明。 + +#### KV Cache 影响 + +无直接失效;把设置值纳入请求前缀的消费方负责该变更。 + +## 已知限制与暂缓事项 + +- **单一用户层** — 解析只认识 schema 默认值、一个组合 `base` 与一个用户文档;它尚未记录每个解析值由哪一层提供。 +- **`redactSecrets` 并非一条可被证明的协议边界**:walker 只跟随 `object`/`dict`/`array`,因此只能经由 union、intersection 或 transform 抵达的 `role('secret')` 会被**原样**返回,且 `secrets` 列表为空;而 `schema.toJSON()` 会把 secret 字段的 `.default(...)` 一并带给每个客户端。这两种情况都不会被拒绝;机密无法经由被遍历的容器抵达的 schema,绝不可注册到暴露于协议的 namespace 上。真正的答案是一个 fail-closed 的 `describeForWire()`——它拒绝自己无法证明安全的 schema,并对序列化封装与错误文本做净化——此项暂缓。 +- **跨进程并发由提供方定义** — seam 仅在进程内按 namespace 串行化写入;跨进程并发按提供方行为收敛(本地文件提供方在写锁下读-改-写,因此 namespace 在并发写入者下不会丢失,同 namespace 冲突按后写胜出解决)。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/index.js new file mode 100644 index 0000000..5ab6707 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/index.js @@ -0,0 +1,638 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/redact.js +/** +* Structural secret redaction for settings values. `role('secret')` fields are +* removed from a value before it crosses a wire boundary; a sidecar records +* each schema-declared secret position and whether it currently holds a value, +* so a configuration surface can render a write-only input without ever +* receiving the secret itself. +* @module @deepseek-ai/dsh-settings/redact +*/ +/** Whether a value is a plain data object the walker may recurse into. */ +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +function walk(node, value, path, secrets) { + if (node === void 0) return value; + if (node.meta?.role === "secret") { + secrets.push({ + path, + set: value !== void 0 + }); + return; + } + switch (node.type) { + case "object": { + const properties = node.dict ?? {}; + const source = isRecord(value) ? value : void 0; + const rebuilt = {}; + if (source !== void 0) for (const [key, entry] of Object.entries(source)) { + if (key in properties) continue; + rebuilt[key] = entry; + } + for (const [key, child] of Object.entries(properties)) { + const stripped = walk(child, source?.[key], [...path, key], secrets); + if (stripped !== void 0) rebuilt[key] = stripped; + } + return source === void 0 && Object.keys(rebuilt).length === 0 ? value : rebuilt; + } + case "dict": { + if (!isRecord(value)) return value; + const rebuilt = {}; + for (const [key, entry] of Object.entries(value)) { + const stripped = walk(node.inner, entry, [...path, key], secrets); + if (stripped !== void 0) rebuilt[key] = stripped; + } + return rebuilt; + } + case "array": + if (!Array.isArray(value)) return value; + return value.map((entry, index) => walk(node.inner, entry, [...path, String(index)], secrets)); + default: return value; + } +} +/** +* Remove every `role('secret')` field a schema declares from a value. The +* walker follows `object`, `dict`, and `array` containers; a secret must be +* declared directly on a field reachable through those containers (a secret +* buried inside a union branch or transform is not reachable and must not be +* modeled that way). The input is never mutated. +* @param schema - live schemastery schema describing the value. +* @param value - the value to strip; `undefined` yields an empty record with +* object-property secret slots still enumerated. +* @returns the stripped detached value and the ordered secret positions. +*/ +function redactSecrets(schema, value) { + const secrets = []; + return { + value: walk(schema, value, [], secrets), + secrets + }; +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for the user-settings capability seam (`ctx.settings`). Providers store one raw document of +* per-namespace sections; plugins register a namespace schema and read the +* resolved value, which layers schema defaults, the registrant's composition +* `base`, and the user document section, in that order. +* @module @deepseek-ai/dsh-settings +*/ +const NAMESPACE_PATTERN = /^[a-z][a-z0-9-]*$/; +/** +* Brand a raw string as a {@link SettingsNamespace}. +* @param value - candidate namespace; lowercase kebab-case, as in plugin short names. +* @returns the branded namespace. +*/ +function settingsNamespace(value) { + if (!NAMESPACE_PATTERN.test(value)) throw new TypeError(`settings namespace "${value}" must match ${String(NAMESPACE_PATTERN)}`); + return value; +} +/** +* Deep equality over JSON-compatible data (objects, arrays, primitives) — the +* Service Definition's single change-detection predicate, exported so the invariant +* companion checks exactly the implementation's relation. +* @param a - one JSON-compatible value. +* @param b - the other JSON-compatible value. +* @returns whether the two values are structurally equal. +*/ +function deepEqualJson(a, b) { + if (a === b) return true; + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false; + return a.every((entry, index) => deepEqualJson(entry, b[index])); + } + const left = a; + const right = b; + const keys = Object.keys(left); + if (keys.length !== Object.keys(right).length) return false; + return keys.every((key) => key in right && deepEqualJson(left[key], right[key])); +} +/** +* A write refused because the namespace moved since the caller read it. The +* Service Definition's serialized write queue orders writes; it cannot tell a fresh writer +* from one holding a stale snapshot, which is what this reports. +*/ +var SettingsConflictError = class extends Error { + /** Stable machine code for wire layers mapping this to their own taxonomy. */ + code = "SETTINGS_CONFLICT"; + /** The revision the write expected. */ + expected; + /** The revision the namespace actually stands at. */ + actual; + /** + * @param ns - the namespace whose write was refused. + * @param expected - the revision the caller sent. + * @param actual - the revision now stored. + */ + constructor(ns, expected, actual) { + super(`settings namespace "${ns}" changed since it was read (expected revision ${String(expected)}, now ${String(actual)})`); + this.name = "SettingsConflictError"; + this.expected = expected; + this.actual = actual; + } +}; +/** Whether a value is a plain data object (not an array, null, or class instance). */ +function isPlainObject(value) { + if (typeof value !== "object" || value === null || Array.isArray(value)) return false; + const proto = Object.getPrototypeOf(value); + return proto === Object.prototype || proto === null; +} +/** Apply one path op to a detached section, returning the next section. */ +function applyPathOp(section, op) { + const [head, ...rest] = op.path; + if (head === void 0) { + if (op.op === "unset") return {}; + if (!isPlainObject(op.value)) throw new TypeError("settings mutate: setting the section root requires a plain object"); + return { ...op.value }; + } + if (rest.length === 0) { + if (op.op === "set") return { + ...section, + [head]: op.value + }; + const { [head]: _removed, ...kept } = section; + return kept; + } + const child = section[head]; + if (!isPlainObject(child)) { + if (op.op === "unset") return section; + return { + ...section, + [head]: applyPathOp({}, { + ...op, + path: rest + }) + }; + } + return { + ...section, + [head]: applyPathOp(child, { + ...op, + path: rest + }) + }; +} +/** Human label for a value that lossless JSON cannot represent (numbers reject inline). */ +function describeRejected(value) { + if (value === void 0) return "undefined"; + if (typeof value === "object" && value !== null) { + const name = Object.getPrototypeOf(value)?.constructor?.name; + return name === void 0 || name === "Object" ? "a non-plain object" : `a ${name}`; + } + return `a ${typeof value}`; +} +/** +* Detach and validate one write input in a single walk before persistence: +* only JSON data (plain objects, arrays, strings, finite numbers, +* booleans, `null`) may reach a provider document. `structuredClone` alone +* would admit Dates, Maps, BigInts, and cycles that YAML/JSON storage then +* silently distorts on the reload round-trip. `undefined` entries in objects +* are skipped — the same sparse-patch semantics as {@link mergeLayers} — while +* an `undefined` array entry is rejected rather than coerced. +* @param root - plain-object write input (caller-checked). +* @param reject - builds the validation error from a value label and its `$`-rooted path. +* @returns the detached JSON-compatible clone. +*/ +function cloneJsonShaped(root, reject) { + const visiting = /* @__PURE__ */ new WeakSet(); + const clone = (value, path) => { + if (value === null || typeof value === "string" || typeof value === "boolean") return value; + if (typeof value === "number") { + if (!Number.isFinite(value)) throw reject("a non-finite number", path); + return value; + } + if (Array.isArray(value)) { + if (visiting.has(value)) throw reject("a circular reference", path); + visiting.add(value); + const entries = value.map((entry, index) => clone(entry, `${path}[${index}]`)); + visiting.delete(value); + return entries; + } + if (isPlainObject(value)) { + if (visiting.has(value)) throw reject("a circular reference", path); + visiting.add(value); + const out = {}; + for (const [key, entry] of Object.entries(value)) { + if (entry === void 0) continue; + out[key] = clone(entry, `${path}.${key}`); + } + visiting.delete(value); + return out; + } + throw reject(describeRejected(value), path); + }; + return clone(root, "$"); +} +/** +* Layer `over` onto `under`: plain objects merge recursively, every other +* value (arrays included) replaces the lower layer wholesale. `over` never +* carries `undefined` entries — sections come from parsed documents and write +* snapshots pass {@link cloneJsonShaped}, which strips them so a sparse patch +* cannot erase lower keys. +*/ +function mergeLayers(under, over) { + if (over === void 0) return under; + if (!isPlainObject(under) || !isPlainObject(over)) return over; + const merged = { ...under }; + for (const [key, value] of Object.entries(over)) merged[key] = key in merged ? mergeLayers(merged[key], value) : value; + return merged; +} +/** Recursively freeze one resolved value so handed-out snapshots stay immutable. */ +function deepFreeze(value) { + if (typeof value !== "object" || value === null || Object.isFrozen(value)) return value; + for (const entry of Object.values(value)) deepFreeze(entry); + return Object.freeze(value); +} +/** +* Abstract settings service. Providers implement raw-document storage +* (`load`/`persist`) and push external changes through {@link Settings.publish}; +* the base class owns namespace registration, resolution, validation, change +* detection, and the `settings/updated` commit event. +*/ +var SettingsProvider = class extends Service { + registrations = /* @__PURE__ */ new Map(); + /** Latest published raw document; empty until the provider's first publish. */ + document = {}; + /** Per-namespace write chains; settled tails, so a failure never poisons the queue. */ + writeQueues = /* @__PURE__ */ new Map(); + /** In-flight watcher invocation segments, drained by the dispose teardown. */ + pendingTails = /* @__PURE__ */ new Set(); + /** Set at service dispose: refuse new writes while queued ones drain. */ + stopped = false; + /** Opaque read of {@link stopped}: control flow cannot narrow it across awaits. */ + isStopped() { + return this.stopped; + } + constructor(ctx) { + super(ctx, "settings"); + } + /** + * Load the provider's document once and publish it before the service + * becomes injectable, and register the write-drain teardown. Providers with + * their own init (watchers, connections) delegate here first via + * `yield* super[Service.init]()`; their disposers then run before the drain. + */ + async *[Service.init]() { + yield async () => { + this.stopped = true; + await Promise.allSettled([...this.writeQueues.values(), ...this.pendingTails]); + }; + this.publish(await this.load()); + } + /** + * Absolute path of the provider's user-editable document, when its storage + * is one local file. Configuration surfaces use this only as availability + * metadata; the guarded open operation resolves the path again Host-side. + * Non-file providers leave it undefined and expose no open-document affordance. + * @returns the absolute local document path, or undefined for non-file storage. + */ + get documentPath() {} + /** + * Prepare the provider's user-editable document for a native editor. File + * providers may materialize an absent document before returning its path; + * non-file providers return undefined. + * @returns the absolute local document path, or undefined for non-file storage. + */ + prepareDocument() { + return Promise.resolve(this.documentPath); + } + /** + * Register a namespace schema and receive its owner scope. The registration + * is an effect on the calling plugin's fiber: disposing that fiber removes + * the namespace and its observers. An invalid stored section fails the + * registration itself — the earliest point where the schema can judge it. + * @param ns - unique namespace; duplicate registration fails loud. + * @param schema - schemastery schema resolving this namespace's value. + * @param options - composition `base` layer and effect timing. + * @returns the owner scope for reads, observation, and updates. + */ + register(ns, schema, options) { + if (this.registrations.has(ns)) throw new Error(`settings namespace "${ns}" is already registered`); + const registration = { + ns, + schema, + base: options?.base, + applies: options?.applies ?? "live", + ...options?.validate === void 0 ? {} : { validate: options.validate }, + resolved: deepFreeze(this.resolve(schema, options?.base, this.section(ns), options?.validate)), + revision: 0, + watchers: /* @__PURE__ */ new Set() + }; + this.ctx.effect(() => { + this.registrations.set(ns, registration); + return () => this.registrations.delete(ns); + }, `settings.register(${JSON.stringify(String(ns))})`); + return { + get: () => registration.resolved, + watch: (callback) => { + const watcher = { + callback, + tail: Promise.resolve(), + active: true + }; + registration.watchers.add(watcher); + return () => { + watcher.active = false; + registration.watchers.delete(watcher); + }; + }, + update: (patch) => this.update(ns, patch), + replace: (section) => this.replace(ns, section) + }; + } + /** + * Describe every registered namespace for configuration surfaces, including + * the composition `base` and raw user layers so a form can mark which fields + * the user overrode (presence in `user`) and what a reset returns to. + * @param options - redaction switch; wire surfaces must redact. + * @returns one descriptor per registered namespace, in registration order. + */ + describe(options) { + return [...this.registrations.values()].map((registration) => { + let user; + try { + user = this.section(registration.ns); + } catch { + user = void 0; + } + const base = registration.base === void 0 ? void 0 : structuredClone(registration.base); + const detachedUser = user === void 0 ? void 0 : structuredClone(user); + const descriptor = { + ns: registration.ns, + schema: registration.schema.toJSON(), + value: registration.resolved, + revision: registration.revision, + ...base === void 0 ? {} : { base }, + ...detachedUser === void 0 ? {} : { user: detachedUser }, + applies: registration.applies + }; + if (options?.redactSecrets !== true) return descriptor; + const schema = registration.schema; + const redacted = redactSecrets(schema, registration.resolved); + return { + ...descriptor, + value: redacted.value, + ...base === void 0 ? {} : { base: redactSecrets(schema, base).value }, + ...detachedUser === void 0 ? {} : { user: redactSecrets(schema, detachedUser).value }, + secrets: redacted.secrets + }; + }); + } + /** + * Read one registered namespace's resolved value. + * @param ns - the namespace to read. + * @returns the resolved value, or `undefined` while unregistered. + */ + get(ns) { + return this.registrations.get(ns)?.resolved; + } + /** + * Merge a patch into one registered namespace's user layer, validate the + * resolved candidate, persist through the provider, then commit and emit. + * A validation failure rejects before anything is persisted. Writes to one + * namespace are serialized: concurrent updates apply in call order, each + * merging over the previous write's committed section. + * @param ns - the registered namespace to update. + * @param patch - plain-object patch over the user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async update(ns, patch, expectedRevision) { + return this.write(ns, patch, "merge", expectedRevision); + } + /** + * Replace one registered namespace's user section wholesale, validate, + * persist, then commit and emit. Keys absent from `section` fall back to the + * composition `base` and schema defaults — this is the removal/reset path a + * merge-only patch cannot express (`replace({})` re-inherits everything). + * @param ns - the registered namespace to replace. + * @param section - the complete next user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async replace(ns, section, expectedRevision) { + return this.write(ns, section, "replace", expectedRevision); + } + /** + * Apply path-addressed edits to one registered namespace's user section, + * validate, persist, then commit and emit. The ops are applied to the + * section as it stands when the write reaches the front of the queue, so a + * caller never has to restate fields it did not touch — and, crucially, + * cannot delete fields it never saw. This is the write path for any caller + * holding a redacted view; `replace` remains the wholesale reset. + * @param ns - the registered namespace to edit. + * @param ops - ordered path edits; later ops observe earlier ones. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async mutate(ns, ops, expectedRevision) { + if (!Array.isArray(ops)) throw new TypeError(`settings mutate for "${ns}" must be an array of path ops`); + for (const op of ops) { + if (!isPlainObject(op) || op["op"] !== "set" && op["op"] !== "unset") throw new TypeError(`settings mutate for "${ns}" ops must be {op:'set'|'unset', path}`); + if (!Array.isArray(op["path"]) || op["path"].some((part) => typeof part !== "string")) throw new TypeError(`settings mutate for "${ns}" op paths must be arrays of strings`); + } + return this.write(ns, ops, "mutate", expectedRevision); + } + /** Validate a write, then queue it on the namespace's serialized write chain. */ + write(ns, input, mode, expectedRevision) { + const verb = mode === "merge" ? "update" : mode === "replace" ? "replace" : "mutate"; + const registration = this.registrations.get(ns); + if (registration === void 0) throw new Error(`settings namespace "${ns}" is not registered`); + if (this.isStopped()) throw new Error(`settings service is disposed: "${ns}" cannot be written`); + if (!this.writable) throw new Error(`settings provider is read-only: "${ns}" cannot be updated in-process`); + let payload; + if (mode === "mutate") payload = { ops: input }; + else { + if (!isPlainObject(input)) throw new TypeError(`settings ${verb} for "${ns}" must be a plain object`); + payload = input; + } + const snapshot = cloneJsonShaped(payload, (label, path) => /* @__PURE__ */ new TypeError(`settings ${verb} for "${ns}" must contain only JSON-compatible data (found ${label} at ${path})`)); + const run = (this.writeQueues.get(ns) ?? Promise.resolve()).catch(() => void 0).then(async () => { + if (this.isStopped()) throw new Error(`settings service was disposed before the queued "${ns}" ${verb} ran`); + if (this.registrations.get(ns) !== registration) throw new Error(`settings namespace "${ns}" registration was disposed before the queued ${verb} ran`); + const current = this.section(ns) ?? {}; + if (expectedRevision !== void 0 && expectedRevision !== registration.revision) throw new SettingsConflictError(ns, expectedRevision, registration.revision); + const section = mode === "merge" ? mergeLayers(current, snapshot) : mode === "replace" ? snapshot : snapshot["ops"].reduce(applyPathOp, current); + const next = deepFreeze(this.resolve(registration.schema, registration.base, section, registration.validate)); + await this.persist(ns, section); + this.document[ns] = section; + if (this.registrations.get(ns) === registration && !this.isStopped()) { + this.bumpRevision(registration, current, section); + this.commit(registration, next, "update"); + } + }); + this.writeQueues.set(ns, run); + return run; + } + /** + * Provider hook: commit a complete raw document observed in storage. Each + * registered namespace re-resolves; an invalid section keeps that + * namespace's last good value and warns, other namespaces still commit. + * @param doc - the detached raw document (unregistered sections preserved). + * @param source - change origin; defaults to `provider`. + */ + publish(doc, source = "provider") { + const before = /* @__PURE__ */ new Map(); + for (const registration of this.registrations.values()) try { + before.set(registration.ns, this.section(registration.ns)); + } catch { + before.set(registration.ns, void 0); + } + this.document = doc; + for (const registration of this.registrations.values()) { + let next; + try { + next = deepFreeze(this.resolve(registration.schema, registration.base, this.section(registration.ns), registration.validate)); + } catch (error) { + this.ctx.logger.warn("settings: keeping last good \"%s\" after invalid stored section", registration.ns); + this.ctx.logger.warn(error); + continue; + } + this.bumpRevision(registration, before.get(registration.ns), this.section(registration.ns)); + this.commit(registration, next, source); + } + } + /** Read one namespace's raw user section, rejecting non-object sections. */ + section(ns) { + const section = this.document[ns]; + if (section === void 0) return void 0; + if (!isPlainObject(section)) throw new TypeError(`settings section "${ns}" must be an object of keys`); + return section; + } + /** Resolve one namespace value: schema defaults, then `base`, then the user layer. */ + resolve(schema, base, section, validate) { + const value = schema(mergeLayers(base, section)); + validate?.(value); + return value; + } + /** + * Advance a namespace's revision when its RAW section changed, and announce + * it. Deliberately independent of {@link commit}'s resolved-value equality: + * storing an override equal to the composition base leaves the resolved + * value alone but changes what the document says, which is exactly what a + * configuration surface must re-read. + */ + bumpRevision(registration, before, after) { + if (deepEqualJson(before, after)) return; + registration.revision += 1; + this.emitDocumentUpdated(registration.ns, registration.revision); + } + /** Contained fan-out of `settings/document-updated`, mirroring {@link commit}'s. */ + emitDocumentUpdated(ns, revision) { + let invariantFailure; + const args = [ + "settings/document-updated", + ns, + revision + ]; + for (const listener of this.ctx.events.dispatch("emit", args)) try { + const returned = listener(ns, revision); + if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => { + this.warnListenerFailure(ns, error); + }); + } catch (error) { + if (error?.code === "INVARIANT") { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(ns, error); + } + if (invariantFailure !== void 0) throw invariantFailure; + } + /** Commit a resolved value when changed: swap, notify watchers, emit the event. */ + commit(registration, next, source) { + const prev = registration.resolved; + if (deepEqualJson(next, prev)) return; + registration.resolved = next; + for (const watcher of [...registration.watchers]) { + const segment = watcher.tail.then(() => { + if (!watcher.active || this.isStopped()) return; + return watcher.callback(next, prev); + }).then(() => void 0, (error) => { + this.warnWatcherFailure(registration.ns, error); + }); + watcher.tail = segment; + this.pendingTails.add(segment); + segment.then(() => this.pendingTails.delete(segment)); + } + let invariantFailure; + const args = [ + "settings/updated", + registration.ns, + next, + prev, + source + ]; + for (const listener of this.ctx.events.dispatch("emit", args)) try { + const returned = listener(registration.ns, next, prev, source); + if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => { + this.warnListenerFailure(registration.ns, error); + }); + } catch (error) { + if (error?.code === "INVARIANT") { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(registration.ns, error); + } + if (invariantFailure !== void 0) throw invariantFailure; + } + /** Contained-watcher diagnostic shared by the sync and async failure paths. */ + warnWatcherFailure(ns, error) { + this.ctx.logger.warn("settings: watcher for \"%s\" failed", ns); + this.ctx.logger.warn(error); + } + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnListenerFailure(ns, error) { + this.ctx.logger.warn("settings: a settings/updated listener for \"%s\" failed", ns); + this.ctx.logger.warn(error); + } +}; +/** +* Value mirror of the `FiberState` members {@link isUnloading} compares +* against: a const enum has no runtime object to import, and the value is +* needed at runtime (same rationale as the CLI boot driver's mirror). +*/ +const FIBER_DISPOSED = 4; +const FIBER_UNLOADING = 5; +/** Whether the consumer's own fiber is tearing down (not just losing the settings service). */ +function isUnloading(ctx) { + const state = ctx.fiber.state; + return state === FIBER_UNLOADING || state === FIBER_DISPOSED; +} +/** +* Install the canonical optional-settings consumer wiring: while a settings +* service exists, register `ns` with the consumer's composition entry as the +* `base` layer and point the source thunk at the resolved scope; when the +* service goes away (disposal, provider reload), fall back to the entry so +* the consumer keeps working exactly as composed. The registration rides the +* scoped fiber, so no settings service ever mounted means none of this runs. +* @param ctx - consumer plugin context owning the wiring. +* @param ns - the consumer-owned settings namespace. +* @param schema - schema resolving the namespace (typically the plugin Config). +* @param entry - the consumer's composition entry config, used as `base`. +* @param hooks - source sink and change notification. +*/ +function installSettingsSection(ctx, ns, schema, entry, hooks) { + ctx.inject(["settings"], (sctx) => { + const scope = sctx.settings.register(ns, schema, { + base: entry, + ...hooks.validate === void 0 ? {} : { validate: hooks.validate } + }); + hooks.setSource(() => scope.get()); + sctx.effect(() => () => { + if (isUnloading(ctx)) return; + hooks.setSource(() => entry); + hooks.onChange(); + }); + hooks.onChange(); + scope.watch(() => { + if (isUnloading(ctx)) return; + hooks.onChange(); + }); + }); +} +//#endregion +export { SettingsConflictError, SettingsProvider, SettingsProvider as default, deepEqualJson, installSettingsSection, redactSecrets, settingsNamespace }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/invariant.js new file mode 100644 index 0000000..7dacb78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/invariant.js @@ -0,0 +1,180 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/redact.js +/** +* Structural secret redaction for settings values. `role('secret')` fields are +* removed from a value before it crosses a wire boundary; a sidecar records +* each schema-declared secret position and whether it currently holds a value, +* so a configuration surface can render a write-only input without ever +* receiving the secret itself. +* @module @deepseek-ai/dsh-settings/redact +*/ +/** Whether a value is a plain data object the walker may recurse into. */ +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +function walk(node, value, path, secrets) { + if (node === void 0) return value; + if (node.meta?.role === "secret") { + secrets.push({ + path, + set: value !== void 0 + }); + return; + } + switch (node.type) { + case "object": { + const properties = node.dict ?? {}; + const source = isRecord(value) ? value : void 0; + const rebuilt = {}; + if (source !== void 0) for (const [key, entry] of Object.entries(source)) { + if (key in properties) continue; + rebuilt[key] = entry; + } + for (const [key, child] of Object.entries(properties)) { + const stripped = walk(child, source?.[key], [...path, key], secrets); + if (stripped !== void 0) rebuilt[key] = stripped; + } + return source === void 0 && Object.keys(rebuilt).length === 0 ? value : rebuilt; + } + case "dict": { + if (!isRecord(value)) return value; + const rebuilt = {}; + for (const [key, entry] of Object.entries(value)) { + const stripped = walk(node.inner, entry, [...path, key], secrets); + if (stripped !== void 0) rebuilt[key] = stripped; + } + return rebuilt; + } + case "array": + if (!Array.isArray(value)) return value; + return value.map((entry, index) => walk(node.inner, entry, [...path, String(index)], secrets)); + default: return value; + } +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for the user-settings capability seam (`ctx.settings`). Providers store one raw document of +* per-namespace sections; plugins register a namespace schema and read the +* resolved value, which layers schema defaults, the registrant's composition +* `base`, and the user document section, in that order. +* @module @deepseek-ai/dsh-settings +*/ +/** +* Deep equality over JSON-compatible data (objects, arrays, primitives) — the +* Service Definition's single change-detection predicate, exported so the invariant +* companion checks exactly the implementation's relation. +* @param a - one JSON-compatible value. +* @param b - the other JSON-compatible value. +* @returns whether the two values are structurally equal. +*/ +function deepEqualJson(a, b) { + if (a === b) return true; + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false; + return a.every((entry, index) => deepEqualJson(entry, b[index])); + } + const left = a; + const right = b; + const keys = Object.keys(left); + if (keys.length !== Object.keys(right).length) return false; + return keys.every((key) => key in right && deepEqualJson(left[key], right[key])); +} +/** Whether a value is a plain data object (not an array, null, or class instance). */ +function isPlainObject(value) { + if (typeof value !== "object" || value === null || Array.isArray(value)) return false; + const proto = Object.getPrototypeOf(value); + return proto === Object.prototype || proto === null; +} +/** Apply one path op to a detached section, returning the next section. */ +function applyPathOp(section, op) { + const [head, ...rest] = op.path; + if (head === void 0) { + if (op.op === "unset") return {}; + if (!isPlainObject(op.value)) throw new TypeError("settings mutate: setting the section root requires a plain object"); + return { ...op.value }; + } + if (rest.length === 0) { + if (op.op === "set") return { + ...section, + [head]: op.value + }; + const { [head]: _removed, ...kept } = section; + return kept; + } + const child = section[head]; + if (!isPlainObject(child)) { + if (op.op === "unset") return section; + return { + ...section, + [head]: applyPathOp({}, { + ...op, + path: rest + }) + }; + } + return { + ...section, + [head]: applyPathOp(child, { + ...op, + path: rest + }) + }; +} +/** +* Layer `over` onto `under`: plain objects merge recursively, every other +* value (arrays included) replaces the lower layer wholesale. `over` never +* carries `undefined` entries — sections come from parsed documents and write +* snapshots pass {@link cloneJsonShaped}, which strips them so a sparse patch +* cannot erase lower keys. +*/ +function mergeLayers(under, over) { + if (over === void 0) return under; + if (!isPlainObject(under) || !isPlainObject(over)) return over; + const merged = { ...under }; + for (const [key, value] of Object.entries(over)) merged[key] = key in merged ? mergeLayers(merged[key], value) : value; + return merged; +} +/** Recursively freeze one resolved value so handed-out snapshots stay immutable. */ +function deepFreeze(value) { + if (typeof value !== "object" || value === null || Object.isFrozen(value)) return value; + for (const entry of Object.values(value)) deepFreeze(entry); + return Object.freeze(value); +} +Service.init; +//#endregion +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-settings`. +* @module @deepseek-ai/dsh-settings/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-settings"; +/** Cordis companion plugin name. */ +const name = "settings-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* Install the commit-event contract: `settings/updated` fires only for a +* currently registered namespace, only when the resolved value changed, and +* only with the service's authoritative resolved value — all judged with the +* seam's own equality predicate. +*/ +const install = (ctx, fail) => { + ctx.on("settings/updated", (ns, next, prev) => { + const settings = ctx.get("settings"); + if (settings === void 0) fail(`settings/updated for "${ns}" emitted without a live settings service`); + const current = settings.get(ns); + if (current === void 0) fail(`settings/updated for "${ns}" emitted while the namespace is unregistered`); + if (!deepEqualJson(current, next)) fail(`settings/updated for "${ns}" does not match the authoritative resolved value`); + if (deepEqualJson(next, prev)) fail(`settings/updated for "${ns}" emitted without a resolved-value change`); + }); +}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/index.d.ts new file mode 100644 index 0000000..7768c1b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/index.d.ts @@ -0,0 +1,343 @@ +/** + * Service Definition for the user-settings capability seam (`ctx.settings`). Providers store one raw document of + * per-namespace sections; plugins register a namespace schema and read the + * resolved value, which layers schema defaults, the registrant's composition + * `base`, and the user document section, in that order. + * @module @deepseek-ai/dsh-settings + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type z from '@deepseek-ai/schemastery'; +import type { RedactedSecret } from './redact.ts'; +import type { SettingsNamespace, SettingsUpdateSource } from './types.ts'; +export { redactSecrets } from './redact.ts'; +export type { RedactedSecret, RedactedValue } from './redact.ts'; +export type { SettingsNamespace, SettingsUpdateSource } from './types.ts'; +/** + * Brand a raw string as a {@link SettingsNamespace}. + * @param value - candidate namespace; lowercase kebab-case, as in plugin short names. + * @returns the branded namespace. + */ +export declare function settingsNamespace(value: string): SettingsNamespace; +/** When a namespace's changes take effect for its owner. */ +export type SettingsApplies = 'live' | 'restart'; +/** Registration options beyond the namespace schema. */ +export interface SettingsRegisterOptions { + /** Composition-layer values resolved below the user layer (entry-config subset). */ + base?: Partial; + /** Owner's effect timing, surfaced to configuration UIs; defaults to `live`. */ + applies?: SettingsApplies; + /** + * Reject a resolved section the owner could not act on, for constraints its + * schema cannot express — a cross-field requirement, or one field's validity + * depending on another's. Throwing here refuses the *write* that produced the + * value, so a caller learns at `update`/`replace`/`mutate` instead of storing + * something that would silently disable the owner. + * + * Kept separate from the schema because the schema is also what a + * configuration surface renders and what an absent section resolves through; + * folding a cross-field check into it would change both. + * + * Once the owner is registered, a stored section that fails this keeps the + * namespace's last good value and warns, exactly as a schema failure does, + * so an externally edited document cannot strand a running owner. At + * registration there is no last good value yet, so a stored section that + * already fails rejects the registration itself — again exactly as a schema + * failure does. + * @param value - the resolved section, schema-valid by construction. + */ + validate?: (value: T) => void; +} +/** One registered namespace as surfaced to configuration UIs. */ +export interface SettingsDescriptor { + /** The registered namespace. */ + ns: SettingsNamespace; + /** Serialized schemastery schema (`schema.toJSON()`). */ + schema: unknown; + /** Current resolved value. */ + value: unknown; + /** + * Monotonic revision of the raw user section this descriptor was read at. + * Send it back as `expectedRevision` on a write to refuse a stale one. + */ + revision: number; + /** Registrant's composition `base` layer (detached), when one was declared. */ + base?: unknown; + /** + * Raw user section from the stored document (detached), when one exists and + * is well-formed; a field's presence here is what marks it user-overridden. + */ + user?: unknown; + /** Owner's declared effect timing. */ + applies: SettingsApplies; + /** Schema-declared secret positions; present only under `redactSecrets`. */ + secrets?: RedactedSecret[]; +} +/** Options for {@link SettingsProvider.describe}. */ +export interface SettingsDescribeOptions { + /** + * Strip `role('secret')` fields from `value`/`base`/`user` and enumerate + * them in each descriptor's `secrets`. Every wire surface MUST pass this; + * the verbatim default exists for same-process configuration UIs only. + */ + redactSecrets?: boolean; +} +/** Owner-facing handle for one registered namespace. */ +export interface SettingsScope { + /** Current resolved value: schema defaults, then `base`, then the user layer. */ + get(): T; + /** + * Observe committed changes to this namespace's resolved value. Invocations + * of one callback run asynchronously, one at a time, in commit order; a + * rejection is contained and logged like a sync throw. After the disposer + * returns, no further invocation starts — one already queued is skipped; + * one already started still settles, and service disposal waits for it. + * @param callback - invoked after each commit with the next and previous values. + * @returns the disposer removing this observer. + */ + watch(callback: (next: T, prev: T) => void | Promise): () => void; + /** + * Merge a partial patch into this namespace's user layer and persist it. + * @param patch - plain-object patch over the user section; JSON-compatible data + * only (non-JSON values reject with their path before anything persists). + */ + update(patch: object): Promise; + /** + * Replace this namespace's user section wholesale; absent keys re-inherit + * the composition `base` and schema defaults (`replace({})` resets all). + * @param section - the complete next user section; JSON-compatible data only, + * as for {@link update}. + */ + replace(section: object): Promise; +} +declare module '@deepseek-ai/cordis' { + interface Context { + settings: SettingsProvider; + } +} +/** + * Deep equality over JSON-compatible data (objects, arrays, primitives) — the + * Service Definition's single change-detection predicate, exported so the invariant + * companion checks exactly the implementation's relation. + * @param a - one JSON-compatible value. + * @param b - the other JSON-compatible value. + * @returns whether the two values are structurally equal. + */ +export declare function deepEqualJson(a: unknown, b: unknown): boolean; +/** + * A write refused because the namespace moved since the caller read it. The + * Service Definition's serialized write queue orders writes; it cannot tell a fresh writer + * from one holding a stale snapshot, which is what this reports. + */ +export declare class SettingsConflictError extends Error { + /** Stable machine code for wire layers mapping this to their own taxonomy. */ + readonly code = "SETTINGS_CONFLICT"; + /** The revision the write expected. */ + readonly expected: number; + /** The revision the namespace actually stands at. */ + readonly actual: number; + /** + * @param ns - the namespace whose write was refused. + * @param expected - the revision the caller sent. + * @param actual - the revision now stored. + */ + constructor(ns: SettingsNamespace, expected: number, actual: number); +} +/** + * One path-addressed edit to a namespace's user section. Path mutation exists + * for a caller holding an INCOMPLETE view of the section — a configuration UI + * reads the redacted descriptor, which by construction never received the + * `role('secret')` fields. Such a caller can name the field it means without + * restating the section: a wholesale `replace` rebuilt from a redacted + * document silently deletes every secret the wire never returned. + */ +export type SettingsPathOp = { + op: 'set'; + path: readonly string[]; + value: unknown; +} | { + op: 'unset'; + path: readonly string[]; +}; +/** + * Abstract settings service. Providers implement raw-document storage + * (`load`/`persist`) and push external changes through {@link Settings.publish}; + * the base class owns namespace registration, resolution, validation, change + * detection, and the `settings/updated` commit event. + */ +export declare abstract class SettingsProvider extends Service { + private readonly registrations; + /** Latest published raw document; empty until the provider's first publish. */ + private document; + /** Per-namespace write chains; settled tails, so a failure never poisons the queue. */ + private readonly writeQueues; + /** In-flight watcher invocation segments, drained by the dispose teardown. */ + private readonly pendingTails; + /** Set at service dispose: refuse new writes while queued ones drain. */ + private stopped; + /** Opaque read of {@link stopped}: control flow cannot narrow it across awaits. */ + private isStopped; + constructor(ctx: Context); + /** + * Load the provider's document once and publish it before the service + * becomes injectable, and register the write-drain teardown. Providers with + * their own init (watchers, connections) delegate here first via + * `yield* super[Service.init]()`; their disposers then run before the drain. + */ + [Service.init](): AsyncGenerator<() => Promise | void, void, void>; + /** Whether {@link update} may persist through this provider. */ + abstract readonly writable: boolean; + /** + * Absolute path of the provider's user-editable document, when its storage + * is one local file. Configuration surfaces use this only as availability + * metadata; the guarded open operation resolves the path again Host-side. + * Non-file providers leave it undefined and expose no open-document affordance. + * @returns the absolute local document path, or undefined for non-file storage. + */ + get documentPath(): string | undefined; + /** + * Prepare the provider's user-editable document for a native editor. File + * providers may materialize an absent document before returning its path; + * non-file providers return undefined. + * @returns the absolute local document path, or undefined for non-file storage. + */ + prepareDocument(): Promise; + /** + * Read the provider's current raw document (namespace to raw section). + * @returns the detached raw document. + */ + protected abstract load(): Promise>; + /** + * Durably store one namespace's merged user section. + * @param ns - the namespace being written. + * @param section - the complete merged user section to store. + */ + protected abstract persist(ns: SettingsNamespace, section: Record): Promise; + /** + * Register a namespace schema and receive its owner scope. The registration + * is an effect on the calling plugin's fiber: disposing that fiber removes + * the namespace and its observers. An invalid stored section fails the + * registration itself — the earliest point where the schema can judge it. + * @param ns - unique namespace; duplicate registration fails loud. + * @param schema - schemastery schema resolving this namespace's value. + * @param options - composition `base` layer and effect timing. + * @returns the owner scope for reads, observation, and updates. + */ + register(ns: SettingsNamespace, schema: z, options?: SettingsRegisterOptions): SettingsScope; + /** + * Describe every registered namespace for configuration surfaces, including + * the composition `base` and raw user layers so a form can mark which fields + * the user overrode (presence in `user`) and what a reset returns to. + * @param options - redaction switch; wire surfaces must redact. + * @returns one descriptor per registered namespace, in registration order. + */ + describe(options?: SettingsDescribeOptions): SettingsDescriptor[]; + /** + * Read one registered namespace's resolved value. + * @param ns - the namespace to read. + * @returns the resolved value, or `undefined` while unregistered. + */ + get(ns: SettingsNamespace): unknown; + /** + * Merge a patch into one registered namespace's user layer, validate the + * resolved candidate, persist through the provider, then commit and emit. + * A validation failure rejects before anything is persisted. Writes to one + * namespace are serialized: concurrent updates apply in call order, each + * merging over the previous write's committed section. + * @param ns - the registered namespace to update. + * @param patch - plain-object patch over the user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + update(ns: SettingsNamespace, patch: object, expectedRevision?: number): Promise; + /** + * Replace one registered namespace's user section wholesale, validate, + * persist, then commit and emit. Keys absent from `section` fall back to the + * composition `base` and schema defaults — this is the removal/reset path a + * merge-only patch cannot express (`replace({})` re-inherits everything). + * @param ns - the registered namespace to replace. + * @param section - the complete next user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + replace(ns: SettingsNamespace, section: object, expectedRevision?: number): Promise; + /** + * Apply path-addressed edits to one registered namespace's user section, + * validate, persist, then commit and emit. The ops are applied to the + * section as it stands when the write reaches the front of the queue, so a + * caller never has to restate fields it did not touch — and, crucially, + * cannot delete fields it never saw. This is the write path for any caller + * holding a redacted view; `replace` remains the wholesale reset. + * @param ns - the registered namespace to edit. + * @param ops - ordered path edits; later ops observe earlier ones. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + mutate(ns: SettingsNamespace, ops: readonly SettingsPathOp[], expectedRevision?: number): Promise; + /** Validate a write, then queue it on the namespace's serialized write chain. */ + private write; + /** + * Provider hook: commit a complete raw document observed in storage. Each + * registered namespace re-resolves; an invalid section keeps that + * namespace's last good value and warns, other namespaces still commit. + * @param doc - the detached raw document (unregistered sections preserved). + * @param source - change origin; defaults to `provider`. + */ + protected publish(doc: Record, source?: SettingsUpdateSource): void; + /** Read one namespace's raw user section, rejecting non-object sections. */ + private section; + /** Resolve one namespace value: schema defaults, then `base`, then the user layer. */ + private resolve; + /** + * Advance a namespace's revision when its RAW section changed, and announce + * it. Deliberately independent of {@link commit}'s resolved-value equality: + * storing an override equal to the composition base leaves the resolved + * value alone but changes what the document says, which is exactly what a + * configuration surface must re-read. + */ + private bumpRevision; + /** Contained fan-out of `settings/document-updated`, mirroring {@link commit}'s. */ + private emitDocumentUpdated; + /** Commit a resolved value when changed: swap, notify watchers, emit the event. */ + private commit; + /** Contained-watcher diagnostic shared by the sync and async failure paths. */ + private warnWatcherFailure; + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + private warnListenerFailure; +} +/** Hooks a consumer hands to {@link installSettingsSection}. */ +export interface SettingsSectionHooks { + /** + * Receive the active configuration source: the resolved settings scope + * while one is attached, the composition entry otherwise. Called before + * the matching `onChange` at attach and at detach. + * @param current - thunk returning the currently authoritative value. + */ + setSource(current: () => T): void; + /** + * Re-judge anything derived from the source — registration-level facts, + * memoized resolutions — after an attach, a detach, or a committed change. + */ + onChange(): void; + /** + * Reject a resolved section this consumer could not act on, for constraints + * its schema cannot express. See {@link SettingsRegisterOptions.validate}. + * @param value - the resolved section, schema-valid by construction. + */ + validate?: (value: T) => void; +} +/** + * Install the canonical optional-settings consumer wiring: while a settings + * service exists, register `ns` with the consumer's composition entry as the + * `base` layer and point the source thunk at the resolved scope; when the + * service goes away (disposal, provider reload), fall back to the entry so + * the consumer keeps working exactly as composed. The registration rides the + * scoped fiber, so no settings service ever mounted means none of this runs. + * @param ctx - consumer plugin context owning the wiring. + * @param ns - the consumer-owned settings namespace. + * @param schema - schema resolving the namespace (typically the plugin Config). + * @param entry - the consumer's composition entry config, used as `base`. + * @param hooks - source sink and change notification. + */ +export declare function installSettingsSection(ctx: Context, ns: SettingsNamespace, schema: z, entry: T, hooks: SettingsSectionHooks): void; +export default SettingsProvider; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/index.js new file mode 100644 index 0000000..2a1c5a6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/index.js @@ -0,0 +1,688 @@ +/** + * Service Definition for the user-settings capability seam (`ctx.settings`). Providers store one raw document of + * per-namespace sections; plugins register a namespace schema and read the + * resolved value, which layers schema defaults, the registrant's composition + * `base`, and the user document section, in that order. + * @module @deepseek-ai/dsh-settings + */ +import { Service } from '@deepseek-ai/cordis'; +import { redactSecrets } from "./redact.js"; +export { redactSecrets } from "./redact.js"; +const NAMESPACE_PATTERN = /^[a-z][a-z0-9-]*$/; +/** + * Brand a raw string as a {@link SettingsNamespace}. + * @param value - candidate namespace; lowercase kebab-case, as in plugin short names. + * @returns the branded namespace. + */ +export function settingsNamespace(value) { + if (!NAMESPACE_PATTERN.test(value)) { + throw new TypeError(`settings namespace "${value}" must match ${String(NAMESPACE_PATTERN)}`); + } + return value; +} +/** + * Deep equality over JSON-compatible data (objects, arrays, primitives) — the + * Service Definition's single change-detection predicate, exported so the invariant + * companion checks exactly the implementation's relation. + * @param a - one JSON-compatible value. + * @param b - the other JSON-compatible value. + * @returns whether the two values are structurally equal. + */ +export function deepEqualJson(a, b) { + if (a === b) + return true; + if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) + return false; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) + return false; + return a.every((entry, index) => deepEqualJson(entry, b[index])); + } + const left = a; + const right = b; + const keys = Object.keys(left); + if (keys.length !== Object.keys(right).length) + return false; + return keys.every(key => key in right && deepEqualJson(left[key], right[key])); +} +/** + * A write refused because the namespace moved since the caller read it. The + * Service Definition's serialized write queue orders writes; it cannot tell a fresh writer + * from one holding a stale snapshot, which is what this reports. + */ +export class SettingsConflictError extends Error { + /** Stable machine code for wire layers mapping this to their own taxonomy. */ + code = 'SETTINGS_CONFLICT'; + /** The revision the write expected. */ + expected; + /** The revision the namespace actually stands at. */ + actual; + /** + * @param ns - the namespace whose write was refused. + * @param expected - the revision the caller sent. + * @param actual - the revision now stored. + */ + constructor(ns, expected, actual) { + super(`settings namespace "${ns}" changed since it was read (expected revision ${String(expected)}, now ${String(actual)})`); + this.name = 'SettingsConflictError'; + this.expected = expected; + this.actual = actual; + } +} +/** Whether a value is a plain data object (not an array, null, or class instance). */ +function isPlainObject(value) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) + return false; + const proto = Object.getPrototypeOf(value); + return proto === Object.prototype || proto === null; +} +/** Apply one path op to a detached section, returning the next section. */ +function applyPathOp(section, op) { + const [head, ...rest] = op.path; + // The empty path addresses the section itself. + if (head === undefined) { + if (op.op === 'unset') + return {}; + if (!isPlainObject(op.value)) { + throw new TypeError('settings mutate: setting the section root requires a plain object'); + } + return { ...op.value }; + } + if (rest.length === 0) { + if (op.op === 'set') + return { ...section, [head]: op.value }; + const { [head]: _removed, ...kept } = section; + return kept; + } + const child = section[head]; + if (!isPlainObject(child)) { + // Unsetting through an absent path is already satisfied; setting through + // one creates the intermediate objects it needs. + if (op.op === 'unset') + return section; + return { ...section, [head]: applyPathOp({}, { ...op, path: rest }) }; + } + return { ...section, [head]: applyPathOp(child, { ...op, path: rest }) }; +} +/** Human label for a value that lossless JSON cannot represent (numbers reject inline). */ +function describeRejected(value) { + if (value === undefined) + return 'undefined'; + if (typeof value === 'object' && value !== null) { + const proto = Object.getPrototypeOf(value); + const name = proto?.constructor?.name; + return name === undefined || name === 'Object' ? 'a non-plain object' : `a ${name}`; + } + return `a ${typeof value}`; +} +/** + * Detach and validate one write input in a single walk before persistence: + * only JSON data (plain objects, arrays, strings, finite numbers, + * booleans, `null`) may reach a provider document. `structuredClone` alone + * would admit Dates, Maps, BigInts, and cycles that YAML/JSON storage then + * silently distorts on the reload round-trip. `undefined` entries in objects + * are skipped — the same sparse-patch semantics as {@link mergeLayers} — while + * an `undefined` array entry is rejected rather than coerced. + * @param root - plain-object write input (caller-checked). + * @param reject - builds the validation error from a value label and its `$`-rooted path. + * @returns the detached JSON-compatible clone. + */ +function cloneJsonShaped(root, reject) { + const visiting = new WeakSet(); + const clone = (value, path) => { + if (value === null || typeof value === 'string' || typeof value === 'boolean') + return value; + if (typeof value === 'number') { + if (!Number.isFinite(value)) + throw reject('a non-finite number', path); + return value; + } + if (Array.isArray(value)) { + if (visiting.has(value)) + throw reject('a circular reference', path); + visiting.add(value); + const entries = value.map((entry, index) => clone(entry, `${path}[${index}]`)); + // Un-mark on exit so one object referenced twice without a cycle passes. + visiting.delete(value); + return entries; + } + if (isPlainObject(value)) { + if (visiting.has(value)) + throw reject('a circular reference', path); + visiting.add(value); + // TODO(settings-json-properties): Use property-safe construction here and + // in mergeLayers so valid JSON keys such as "__proto__" remain own data. + const out = {}; + for (const [key, entry] of Object.entries(value)) { + if (entry === undefined) + continue; + out[key] = clone(entry, `${path}.${key}`); + } + visiting.delete(value); + return out; + } + throw reject(describeRejected(value), path); + }; + return clone(root, '$'); +} +/** + * Layer `over` onto `under`: plain objects merge recursively, every other + * value (arrays included) replaces the lower layer wholesale. `over` never + * carries `undefined` entries — sections come from parsed documents and write + * snapshots pass {@link cloneJsonShaped}, which strips them so a sparse patch + * cannot erase lower keys. + */ +function mergeLayers(under, over) { + if (over === undefined) + return under; + if (!isPlainObject(under) || !isPlainObject(over)) + return over; + const merged = { ...under }; + for (const [key, value] of Object.entries(over)) { + merged[key] = key in merged ? mergeLayers(merged[key], value) : value; + } + return merged; +} +/** Recursively freeze one resolved value so handed-out snapshots stay immutable. */ +function deepFreeze(value) { + if (typeof value !== 'object' || value === null || Object.isFrozen(value)) + return value; + for (const entry of Object.values(value)) + deepFreeze(entry); + return Object.freeze(value); +} +/** + * Abstract settings service. Providers implement raw-document storage + * (`load`/`persist`) and push external changes through {@link Settings.publish}; + * the base class owns namespace registration, resolution, validation, change + * detection, and the `settings/updated` commit event. + */ +export class SettingsProvider extends Service { + registrations = new Map(); + /** Latest published raw document; empty until the provider's first publish. */ + document = {}; + /** Per-namespace write chains; settled tails, so a failure never poisons the queue. */ + writeQueues = new Map(); + /** In-flight watcher invocation segments, drained by the dispose teardown. */ + pendingTails = new Set(); + /** Set at service dispose: refuse new writes while queued ones drain. */ + stopped = false; + /** Opaque read of {@link stopped}: control flow cannot narrow it across awaits. */ + isStopped() { + return this.stopped; + } + constructor(ctx) { + super(ctx, 'settings'); + } + /** + * Load the provider's document once and publish it before the service + * becomes injectable, and register the write-drain teardown. Providers with + * their own init (watchers, connections) delegate here first via + * `yield* super[Service.init]()`; their disposers then run before the drain. + */ + async *[Service.init]() { + yield async () => { + // Teardown: refuse new writes and new watcher starts, then wait until + // every queued write chain and every started watcher invocation settles + // so disposal completes only once storage and observers are quiescent. + // Invocations queued but not yet started skip via the stopped check. + this.stopped = true; + await Promise.allSettled([...this.writeQueues.values(), ...this.pendingTails]); + }; + this.publish(await this.load()); + } + /** + * Absolute path of the provider's user-editable document, when its storage + * is one local file. Configuration surfaces use this only as availability + * metadata; the guarded open operation resolves the path again Host-side. + * Non-file providers leave it undefined and expose no open-document affordance. + * @returns the absolute local document path, or undefined for non-file storage. + */ + get documentPath() { + return undefined; + } + /** + * Prepare the provider's user-editable document for a native editor. File + * providers may materialize an absent document before returning its path; + * non-file providers return undefined. + * @returns the absolute local document path, or undefined for non-file storage. + */ + prepareDocument() { + return Promise.resolve(this.documentPath); + } + /** + * Register a namespace schema and receive its owner scope. The registration + * is an effect on the calling plugin's fiber: disposing that fiber removes + * the namespace and its observers. An invalid stored section fails the + * registration itself — the earliest point where the schema can judge it. + * @param ns - unique namespace; duplicate registration fails loud. + * @param schema - schemastery schema resolving this namespace's value. + * @param options - composition `base` layer and effect timing. + * @returns the owner scope for reads, observation, and updates. + */ + register(ns, schema, options) { + if (this.registrations.has(ns)) { + throw new Error(`settings namespace "${ns}" is already registered`); + } + const registration = { + ns, + schema: schema, + base: options?.base, + applies: options?.applies ?? 'live', + ...options?.validate === undefined + ? {} + : { validate: options.validate }, + resolved: deepFreeze(this.resolve(schema, options?.base, this.section(ns), options?.validate)), + revision: 0, + watchers: new Set(), + }; + this.ctx.effect(() => { + this.registrations.set(ns, registration); + // TODO(settings-registration-quiescence): Deactivate every watcher and await + // its tail on disposal so callbacks cannot outlive the registrant fiber. + return () => this.registrations.delete(ns); + }, `settings.register(${JSON.stringify(String(ns))})`); + return { + get: () => registration.resolved, + watch: (callback) => { + const watcher = { callback: callback, tail: Promise.resolve(), active: true }; + registration.watchers.add(watcher); + return () => { + watcher.active = false; + registration.watchers.delete(watcher); + }; + }, + update: patch => this.update(ns, patch), + replace: section => this.replace(ns, section), + }; + } + /** + * Describe every registered namespace for configuration surfaces, including + * the composition `base` and raw user layers so a form can mark which fields + * the user overrode (presence in `user`) and what a reset returns to. + * @param options - redaction switch; wire surfaces must redact. + * @returns one descriptor per registered namespace, in registration order. + */ + describe(options) { + return [...this.registrations.values()].map((registration) => { + let user; + try { + user = this.section(registration.ns); + } + catch { + // A malformed stored section already warned at publish and kept the + // last good resolved value; only that malformed shape can throw here, + // and describing it as "no user layer" keeps this read total. + user = undefined; + } + const base = registration.base === undefined ? undefined : structuredClone(registration.base); + const detachedUser = user === undefined ? undefined : structuredClone(user); + const descriptor = { + ns: registration.ns, + schema: registration.schema.toJSON(), + value: registration.resolved, + revision: registration.revision, + ...base === undefined ? {} : { base }, + ...detachedUser === undefined ? {} : { user: detachedUser }, + applies: registration.applies, + }; + if (options?.redactSecrets !== true) + return descriptor; + const schema = registration.schema; + const redacted = redactSecrets(schema, registration.resolved); + return { + ...descriptor, + value: redacted.value, + ...base === undefined ? {} : { base: redactSecrets(schema, base).value }, + ...detachedUser === undefined ? {} : { user: redactSecrets(schema, detachedUser).value }, + secrets: redacted.secrets, + }; + }); + } + /** + * Read one registered namespace's resolved value. + * @param ns - the namespace to read. + * @returns the resolved value, or `undefined` while unregistered. + */ + get(ns) { + return this.registrations.get(ns)?.resolved; + } + /** + * Merge a patch into one registered namespace's user layer, validate the + * resolved candidate, persist through the provider, then commit and emit. + * A validation failure rejects before anything is persisted. Writes to one + * namespace are serialized: concurrent updates apply in call order, each + * merging over the previous write's committed section. + * @param ns - the registered namespace to update. + * @param patch - plain-object patch over the user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async update(ns, patch, expectedRevision) { + return this.write(ns, patch, 'merge', expectedRevision); + } + /** + * Replace one registered namespace's user section wholesale, validate, + * persist, then commit and emit. Keys absent from `section` fall back to the + * composition `base` and schema defaults — this is the removal/reset path a + * merge-only patch cannot express (`replace({})` re-inherits everything). + * @param ns - the registered namespace to replace. + * @param section - the complete next user section. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async replace(ns, section, expectedRevision) { + return this.write(ns, section, 'replace', expectedRevision); + } + /** + * Apply path-addressed edits to one registered namespace's user section, + * validate, persist, then commit and emit. The ops are applied to the + * section as it stands when the write reaches the front of the queue, so a + * caller never has to restate fields it did not touch — and, crucially, + * cannot delete fields it never saw. This is the write path for any caller + * holding a redacted view; `replace` remains the wholesale reset. + * @param ns - the registered namespace to edit. + * @param ops - ordered path edits; later ops observe earlier ones. + * @param expectedRevision - the descriptor `revision` the caller read; a + * namespace that moved past it rejects with {@link SettingsConflictError}. + */ + async mutate(ns, ops, expectedRevision) { + if (!Array.isArray(ops)) + throw new TypeError(`settings mutate for "${ns}" must be an array of path ops`); + for (const op of ops) { + if (!isPlainObject(op) || (op['op'] !== 'set' && op['op'] !== 'unset')) { + throw new TypeError(`settings mutate for "${ns}" ops must be {op:'set'|'unset', path}`); + } + if (!Array.isArray(op['path']) || op['path'].some(part => typeof part !== 'string')) { + throw new TypeError(`settings mutate for "${ns}" op paths must be arrays of strings`); + } + } + return this.write(ns, ops, 'mutate', expectedRevision); + } + /** Validate a write, then queue it on the namespace's serialized write chain. */ + write(ns, input, mode, expectedRevision) { + const verb = mode === 'merge' ? 'update' : mode === 'replace' ? 'replace' : 'mutate'; + const registration = this.registrations.get(ns); + if (registration === undefined) { + throw new Error(`settings namespace "${ns}" is not registered`); + } + if (this.isStopped()) { + throw new Error(`settings service is disposed: "${ns}" cannot be written`); + } + if (!this.writable) { + throw new Error(`settings provider is read-only: "${ns}" cannot be updated in-process`); + } + // A mutate's ops array is wrapped so one JSON-shape walk covers both + // shapes; merge/replace carry the section itself. + let payload; + if (mode === 'mutate') { + payload = { ops: input }; + } + else { + if (!isPlainObject(input)) + throw new TypeError(`settings ${verb} for "${ns}" must be a plain object`); + payload = input; + } + // Snapshot at call time: the queue must never read a caller-owned object + // the caller may keep mutating while the write waits its turn. The same + // walk rejects values that JSON cannot preserve (see cloneJsonShaped). + const snapshot = cloneJsonShaped(payload, (label, path) => new TypeError(`settings ${verb} for "${ns}" must contain only JSON-compatible data (found ${label} at ${path})`)); + const previous = this.writeQueues.get(ns) ?? Promise.resolve(); + // Chain past a failed predecessor: one rejected write must not poison the + // namespace queue for every later caller. + const run = previous.catch(() => undefined).then(async () => { + if (this.isStopped()) { + throw new Error(`settings service was disposed before the queued "${ns}" ${verb} ran`); + } + if (this.registrations.get(ns) !== registration) { + throw new Error(`settings namespace "${ns}" registration was disposed before the queued ${verb} ran`); + } + // Every mode derives from the section as it stands NOW, at the front of + // the queue — never from whatever the caller last saw. + const current = this.section(ns) ?? {}; + // The revision check belongs HERE, not at call time: the queue orders + // writes but cannot tell a fresh writer from one holding a snapshot + // that a predecessor already superseded. + if (expectedRevision !== undefined && expectedRevision !== registration.revision) { + throw new SettingsConflictError(ns, expectedRevision, registration.revision); + } + const section = mode === 'merge' + ? mergeLayers(current, snapshot) + : mode === 'replace' + ? snapshot + : snapshot['ops'].reduce(applyPathOp, current); + const next = deepFreeze(this.resolve(registration.schema, registration.base, section, registration.validate)); + await this.persist(ns, section); + // The write reached storage either way; the cache must say so. Commit + // only when this registration is still the namespace owner — a fiber + // disposed (or replaced) mid-persist must not receive the notification. + this.document[ns] = section; + // TODO(settings-replacement-resync): Re-resolve any replacement registration + // from this persisted section so an old in-flight write cannot leave it stale. + if (this.registrations.get(ns) === registration && !this.isStopped()) { + this.bumpRevision(registration, current, section); + this.commit(registration, next, 'update'); + } + }); + this.writeQueues.set(ns, run); + return run; + } + /** + * Provider hook: commit a complete raw document observed in storage. Each + * registered namespace re-resolves; an invalid section keeps that + * namespace's last good value and warns, other namespaces still commit. + * @param doc - the detached raw document (unregistered sections preserved). + * @param source - change origin; defaults to `provider`. + */ + publish(doc, source = 'provider') { + // Read every raw section BEFORE swapping the document, so the revision + // bump below compares what was stored with what now is — an external edit + // moves the revision exactly like an in-process write. + const before = new Map(); + for (const registration of this.registrations.values()) { + try { + before.set(registration.ns, this.section(registration.ns)); + } + catch { + // A malformed stored section is not a readable "before"; treating it + // as absent still bumps against any well-formed replacement. + before.set(registration.ns, undefined); + } + } + this.document = doc; + for (const registration of this.registrations.values()) { + let next; + try { + next = deepFreeze(this.resolve(registration.schema, registration.base, this.section(registration.ns), registration.validate)); + } + catch (error) { + this.ctx.logger.warn('settings: keeping last good "%s" after invalid stored section', registration.ns); + this.ctx.logger.warn(error); + continue; + } + this.bumpRevision(registration, before.get(registration.ns), this.section(registration.ns)); + this.commit(registration, next, source); + } + } + /** Read one namespace's raw user section, rejecting non-object sections. */ + section(ns) { + const section = this.document[ns]; + if (section === undefined) + return undefined; + if (!isPlainObject(section)) { + throw new TypeError(`settings section "${ns}" must be an object of keys`); + } + return section; + } + /** Resolve one namespace value: schema defaults, then `base`, then the user layer. */ + resolve(schema, base, section, validate) { + // The merged candidate is untyped by construction; the schema call is the + // runtime validation that admits it into T. + const value = schema(mergeLayers(base, section)); + // The owner's own check runs on the admitted value, so it sees defaults + // and the composition base exactly as the owner will. + validate?.(value); + return value; + } + /** + * Advance a namespace's revision when its RAW section changed, and announce + * it. Deliberately independent of {@link commit}'s resolved-value equality: + * storing an override equal to the composition base leaves the resolved + * value alone but changes what the document says, which is exactly what a + * configuration surface must re-read. + */ + bumpRevision(registration, before, after) { + if (deepEqualJson(before, after)) + return; + registration.revision += 1; + this.emitDocumentUpdated(registration.ns, registration.revision); + } + /** Contained fan-out of `settings/document-updated`, mirroring {@link commit}'s. */ + emitDocumentUpdated(ns, revision) { + let invariantFailure; + const args = ['settings/document-updated', ns, revision]; + for (const listener of this.ctx.events.dispatch('emit', args)) { + try { + const returned = listener(ns, revision); + if (returned != null && typeof returned.then === 'function') { + void Promise.resolve(returned).then(undefined, (error) => { + this.warnListenerFailure(ns, error); + }); + } + } + catch (error) { + if (error?.code === 'INVARIANT') { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(ns, error); + } + } + if (invariantFailure !== undefined) + throw invariantFailure; + } + /** Commit a resolved value when changed: swap, notify watchers, emit the event. */ + commit(registration, next, source) { + const prev = registration.resolved; + if (deepEqualJson(next, prev)) + return; + registration.resolved = next; + for (const watcher of [...registration.watchers]) { + // Serialize per watcher: invocations of one callback run one at a time + // in commit order, so a slow stale invocation can never apply after a + // newer one. Sync throws and async rejections land in the same handler. + // The activity check runs when the queued invocation would start, so a + // disposer (or service stop) that ran while it waited prevents the + // start entirely; started invocations drain at service dispose. + const segment = watcher.tail + .then(() => { + if (!watcher.active || this.isStopped()) + return; + return watcher.callback(next, prev); + }) + .then(() => undefined, (error) => { + this.warnWatcherFailure(registration.ns, error); + }); + watcher.tail = segment; + this.pendingTails.add(segment); + void segment.then(() => this.pendingTails.delete(segment)); + } + // Fan the event out one listener at a time (the plain emit stops at the + // first throwing listener, starving the rest). Invariant violations are + // harness-fatal by design and rethrow after every listener ran; any other + // failure is contained so one broken observer cannot wedge the commit + // path (and, through it, a provider's reload loop). + let invariantFailure; + const args = ['settings/updated', registration.ns, next, prev, source]; + for (const listener of this.ctx.events.dispatch('emit', args)) { + try { + const returned = listener(registration.ns, next, prev, source); + if (returned != null && typeof returned.then === 'function') { + // An emit listener may still be an async function; its rejection + // cannot reach the synchronous INVARIANT rethrow below, so it is + // contained here instead of becoming an unhandled rejection. + void Promise.resolve(returned).then(undefined, (error) => { + this.warnListenerFailure(registration.ns, error); + }); + } + } + catch (error) { + if (error?.code === 'INVARIANT') { + invariantFailure ??= error; + continue; + } + this.warnListenerFailure(registration.ns, error); + } + } + if (invariantFailure !== undefined) + throw invariantFailure; + } + /** Contained-watcher diagnostic shared by the sync and async failure paths. */ + warnWatcherFailure(ns, error) { + this.ctx.logger.warn('settings: watcher for "%s" failed', ns); + this.ctx.logger.warn(error); + } + /** Contained-listener diagnostic shared by the sync and async failure paths. */ + warnListenerFailure(ns, error) { + this.ctx.logger.warn('settings: a settings/updated listener for "%s" failed', ns); + this.ctx.logger.warn(error); + } +} +/** + * Value mirror of the `FiberState` members {@link isUnloading} compares + * against: a const enum has no runtime object to import, and the value is + * needed at runtime (same rationale as the CLI boot driver's mirror). + */ +const FIBER_DISPOSED = 4; +const FIBER_UNLOADING = 5; +/** Whether the consumer's own fiber is tearing down (not just losing the settings service). */ +function isUnloading(ctx) { + const state = ctx.fiber.state; + return state === FIBER_UNLOADING || state === FIBER_DISPOSED; +} +/** + * Install the canonical optional-settings consumer wiring: while a settings + * service exists, register `ns` with the consumer's composition entry as the + * `base` layer and point the source thunk at the resolved scope; when the + * service goes away (disposal, provider reload), fall back to the entry so + * the consumer keeps working exactly as composed. The registration rides the + * scoped fiber, so no settings service ever mounted means none of this runs. + * @param ctx - consumer plugin context owning the wiring. + * @param ns - the consumer-owned settings namespace. + * @param schema - schema resolving the namespace (typically the plugin Config). + * @param entry - the consumer's composition entry config, used as `base`. + * @param hooks - source sink and change notification. + */ +export function installSettingsSection(ctx, ns, schema, entry, hooks) { + ctx.inject(['settings'], (sctx) => { + const scope = sctx.settings.register(ns, schema, { + base: entry, + ...hooks.validate === undefined ? {} : { validate: hooks.validate }, + }); + hooks.setSource(() => scope.get()); + sctx.effect(() => () => { + // This disposer runs for two different reasons. A settings provider + // detaching leaves the consumer running, so it must fall back to its + // composition entry and re-judge what it derived. The consumer's own + // unload runs it too — and there `onChange` would re-register routes + // and touch resources the teardown is releasing, so the fallback is + // pointless and the notification actively harmful. + if (isUnloading(ctx)) + return; + hooks.setSource(() => entry); + hooks.onChange(); + }); + hooks.onChange(); + scope.watch(() => { + // A stored change landing while the consumer unloads reaches the watcher + // before the registration is released, and `onChange` is exactly as + // harmful here as in the disposer above: it re-registers routes against + // a fiber whose resources are being let go. + if (isUnloading(ctx)) + return; + hooks.onChange(); + }); + }); +} +export default SettingsProvider; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.d.ts new file mode 100644 index 0000000..560f361 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-settings`. + * @module @deepseek-ai/dsh-settings/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "settings-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.js new file mode 100644 index 0000000..82ccd30 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/invariant.js @@ -0,0 +1,41 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-settings`. + * @module @deepseek-ai/dsh-settings/invariant + */ +import { deepEqualJson } from "./index.js"; +const PACKAGE_NAME = '@deepseek-ai/dsh-settings'; +/** Cordis companion plugin name. */ +export const name = 'settings-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * Install the commit-event contract: `settings/updated` fires only for a + * currently registered namespace, only when the resolved value changed, and + * only with the service's authoritative resolved value — all judged with the + * seam's own equality predicate. + */ +const install = (ctx, fail) => { + ctx.on('settings/updated', (ns, next, prev) => { + const settings = ctx.get('settings'); + if (settings === undefined) { + fail(`settings/updated for "${ns}" emitted without a live settings service`); + } + const current = settings.get(ns); + if (current === undefined) { + fail(`settings/updated for "${ns}" emitted while the namespace is unregistered`); + } + if (!deepEqualJson(current, next)) { + fail(`settings/updated for "${ns}" does not match the authoritative resolved value`); + } + if (deepEqualJson(next, prev)) { + fail(`settings/updated for "${ns}" emitted without a resolved-value change`); + } + }); +}; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.d.ts new file mode 100644 index 0000000..d582774 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.d.ts @@ -0,0 +1,40 @@ +/** + * Structural secret redaction for settings values. `role('secret')` fields are + * removed from a value before it crosses a wire boundary; a sidecar records + * each schema-declared secret position and whether it currently holds a value, + * so a configuration surface can render a write-only input without ever + * receiving the secret itself. + * @module @deepseek-ai/dsh-settings/redact + */ +import type z from '@deepseek-ai/schemastery'; +/** One schema-declared secret position inside a redacted value. */ +export interface RedactedSecret { + /** Path from the section root to the removed field (concrete dict keys and array indexes included). */ + path: string[]; + /** Whether the field held a value before redaction. */ + set: boolean; +} +/** A value with every `role('secret')` field removed, plus the removal record. */ +export interface RedactedValue { + /** Detached copy of the input with secret fields absent. */ + value: unknown; + /** + * Every reachable secret position: object properties always (even unset, so + * a form knows the slot exists), dict entries and array items only where the + * value has them. + */ + secrets: RedactedSecret[]; +} +/** + * Remove every `role('secret')` field a schema declares from a value. The + * walker follows `object`, `dict`, and `array` containers; a secret must be + * declared directly on a field reachable through those containers (a secret + * buried inside a union branch or transform is not reachable and must not be + * modeled that way). The input is never mutated. + * @param schema - live schemastery schema describing the value. + * @param value - the value to strip; `undefined` yields an empty record with + * object-property secret slots still enumerated. + * @returns the stripped detached value and the ordered secret positions. + */ +export declare function redactSecrets(schema: z, value: unknown): RedactedValue; +//# sourceMappingURL=redact.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.js new file mode 100644 index 0000000..6361590 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/redact.js @@ -0,0 +1,78 @@ +/** + * Structural secret redaction for settings values. `role('secret')` fields are + * removed from a value before it crosses a wire boundary; a sidecar records + * each schema-declared secret position and whether it currently holds a value, + * so a configuration surface can render a write-only input without ever + * receiving the secret itself. + * @module @deepseek-ai/dsh-settings/redact + */ +/** Whether a value is a plain data object the walker may recurse into. */ +function isRecord(value) { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} +function walk(node, value, path, secrets) { + if (node === undefined) + return value; + if (node.meta?.role === 'secret') { + secrets.push({ path, set: value !== undefined }); + return undefined; + } + switch (node.type) { + case 'object': { + const properties = node.dict ?? {}; + const source = isRecord(value) ? value : undefined; + const rebuilt = {}; + if (source !== undefined) { + for (const [key, entry] of Object.entries(source)) { + if (key in properties) + continue; + rebuilt[key] = entry; + } + } + for (const [key, child] of Object.entries(properties)) { + const stripped = walk(child, source?.[key], [...path, key], secrets); + if (stripped !== undefined) + rebuilt[key] = stripped; + } + return source === undefined && Object.keys(rebuilt).length === 0 ? value : rebuilt; + } + case 'dict': { + if (!isRecord(value)) + return value; + const rebuilt = {}; + for (const [key, entry] of Object.entries(value)) { + const stripped = walk(node.inner, entry, [...path, key], secrets); + if (stripped !== undefined) + rebuilt[key] = stripped; + } + return rebuilt; + } + case 'array': { + if (!Array.isArray(value)) + return value; + return value.map((entry, index) => walk(node.inner, entry, [...path, String(index)], secrets)); + } + default: + // TODO(settings-wire-redaction): Fail closed instead — a secret reachable + // only through a union, intersection, or transform is returned verbatim + // here, with nothing recording that it was missed. + return value; + } +} +/** + * Remove every `role('secret')` field a schema declares from a value. The + * walker follows `object`, `dict`, and `array` containers; a secret must be + * declared directly on a field reachable through those containers (a secret + * buried inside a union branch or transform is not reachable and must not be + * modeled that way). The input is never mutated. + * @param schema - live schemastery schema describing the value. + * @param value - the value to strip; `undefined` yields an empty record with + * object-property secret slots still enumerated. + * @returns the stripped detached value and the ordered secret positions. + */ +export function redactSecrets(schema, value) { + const secrets = []; + const stripped = walk(schema, value, [], secrets); + return { value: stripped, secrets }; +} +//# sourceMappingURL=redact.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/types.d.ts new file mode 100644 index 0000000..c113168 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/types.d.ts @@ -0,0 +1,46 @@ +/** + * Client-safe type surface of the user-settings seam: the namespace brand, the + * commit-origin union, and the seam's Cordis event declarations. Types only — + * no runtime code, and nothing here reaches a Host-only symbol, so a Client + * compilation face reads exactly the signatures the Host emits. + * + * @module @deepseek-ai/dsh-settings/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** Nominal id of one registered settings namespace. */ +export type SettingsNamespace = Branded<'SettingsNamespace'>; +/** Origin of one committed settings change. */ +export type SettingsUpdateSource = 'update' | 'provider'; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * Committed change to one registered namespace's resolved value. Emitted + * after the provider persisted (for `update`) or published (`provider`) + * the change; never emitted when the resolved value is deep-equal. + * Listener failures are contained and logged — a sync throw and an async + * rejection alike — except `INVARIANT`-coded failures, which rethrow + * after every listener ran; that rethrow reaches the emitter only from + * synchronous listeners, so invariant checks on this event must not be + * async functions. + * @param ns - the namespace whose resolved value changed. + * @param next - the new resolved value. + * @param prev - the previous resolved value. + * @param source - whether the change entered through `update()` or the provider. + * @mode emit + */ + 'settings/updated'(ns: SettingsNamespace, next: unknown, prev: unknown, source: SettingsUpdateSource): void; + /** + * One registered namespace's RAW user section changed, whether or not the + * resolved value did. `settings/updated` is the consumer-facing event and + * stays deep-equal-gated; this one exists for configuration surfaces, + * which must learn that a field went from inherited to overridden (same + * resolved value, different meaning) and that their held revision is + * stale. Listener containment matches `settings/updated`. + * @param ns - the namespace whose stored section changed. + * @param revision - the namespace's new revision. + * @mode emit + */ + 'settings/document-updated'(ns: SettingsNamespace, revision: number): void; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/types.js new file mode 100644 index 0000000..3438445 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/lib/types/types.js @@ -0,0 +1,10 @@ +/** + * Client-safe type surface of the user-settings seam: the namespace brand, the + * commit-origin union, and the seam's Cordis event declarations. Types only — + * no runtime code, and nothing here reaches a Host-only symbol, so a Client + * compilation face reads exactly the signatures the Host emits. + * + * @module @deepseek-ai/dsh-settings/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/package.json new file mode 100644 index 0000000..d7180cb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings/package.json @@ -0,0 +1,51 @@ +{ + "name": "@deepseek-ai/dsh-settings", + "description": "Abstract user-settings seam (ctx.settings) for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/settings/settings" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/schemastery": "^3.18.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.i18n.yaml new file mode 100644 index 0000000..d4b2895 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/skill/skill/README.md +README.md: ae8812aeb3cc6583677d22bd5c35639318d15237 +README.zh.md: 5eae1d5aeb9eb87072d4b33c26f6c9a6e20cffdf diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.md new file mode 100644 index 0000000..ae8812a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.md @@ -0,0 +1,79 @@ +# @deepseek-ai/dsh-skill + +English | [中文](README.zh.md) + +Pure agent skill provider registry. + +This package owns the `ctx.skills` interface. It does not know whether skills come from local files, embedded plugin data, HTTP, or another backend; providers register those sources with `ctx.skills.registerProvider(...)`. The shipped local implementation is [`@deepseek-ai/dsh-skill-filesystem`](../skill-filesystem). + +The registry is host+per-scope layered over [`@deepseek-ai/dsh-scope`](../../core/scope), the shape the tools registry established: a registration files into the layer of its calling context's scope — host rows and repository plugins land in the global layer, a plugin mounted by an agent preset's standing composition lands in that preset's layer — and a read merges the global layer with the viewing scope's chain, the nearest layer winning a duplicate name outright while rank decides duplicates only within one layer. + +## Service: `SkillRegistry` (ctx key: `skills`) + +### Public API + +- `ctx.skills.registerProvider(create): () => void` Calls a synchronous provider factory with `{ signal, invalidate }`, then registers its readonly result by `provider.name`, unique within the calling context's layer. Duplicate names in one layer throw, `runtime` is reserved, and failed registration aborts the signal. The exact Cordis disposer unregisters the provider, aborts the signal, and preserves ordered composite teardown. +- `ctx.skills.snapshot({ cwd?, signal?, scope? })` Returns the invocation-neutral `{ skills, complete }` observation for the viewing scope's merged layers. `complete` is false when any provider rejects or explicitly reports incomplete discovery, or when a second catalog revision races the bounded retry; candidates supplied by that observation remain in this result, which is never cached. +- `ctx.skills.list({ cwd?, signal?, scope? })` Borrows the readonly view options, then returns every winning summary for the current workspace, merged across the global layer and the viewing scope's chain and sorted by name. Consumers apply `isModelInvocable(skill)` or `isUserInvocable(skill)` at their own boundary. +- `ctx.skills.get(name, { cwd?, signal?, scope? })` Uses the same readonly options and winning candidate for discovery and loading, rechecks cancellation after discovery or a cache hit, races provider loading against the signal, validates the loaded definition, then returns it regardless of invocation policy. +- `ctx.skills.register(skill): () => void` Registers a readonly runtime embedded skill into the calling context's layer, adding the all-invocable policy and `provider: "runtime"` when omitted. Same-name runtime registrations in one layer are first-wins: a duplicate logs a warning and gets a no-op disposer. Successful registrations return the exact Cordis disposer for ordered composite teardown. + +### Events + +- `skills/change` is an unfiltered invalidation notification emitted after a provider or runtime contribution is registered or disposed and after an active provider's registration control invalidates. It carries no catalog or diff: each consumer refetches `snapshot()` with its own lookup options. Listener throws and rejected promises are logged and cannot veto the registry mutation or starve later listeners. + +### Config + +| Field | Default | Meaning | +|---|---|---| +| `collectCacheMaxEntries` | `128` | Maximum completed cwd/provider catalogs kept in memory. | + +### Invocation policy + +`SkillSummary.invocation` is a required typed policy object whose positive booleans `modelInvocable` and `userInvocable` describe the two surfaces independently. Providers return this resolved shape on every candidate and definition; only the `SkillRegistration` input may omit it, in which case `register()` supplies `{ modelInvocable: true, userInvocable: true }`. The registry keeps all four combinations so one discovery result can serve model-facing tools, human-facing commands, and trusted internal callers without conflating their catalogs. + +| Policy | Model | User | +|---|---|---| +| `{ modelInvocable: true, userInvocable: true }` | included | included | +| `{ modelInvocable: true, userInvocable: false }` | included | excluded | +| `{ modelInvocable: false, userInvocable: true }` | excluded | included | +| `{ modelInvocable: false, userInvocable: false }` | excluded | excluded | + +### Shared model-facing rendering + +`renderSkillContent(skill)` renders one loaded skill as the canonical `` block (escaped `name` attribute, resource hints, verbatim body). It is the single truth for both loading paths: `dsh-tool-skill` returns it as the `skill` tool result and injects it at the user-explicit gesture boundary, so the model sees one shape regardless of who initiated the load. `escapeText` is exported beside it for consumers embedding prose in the same markup frame. The package also declares the `skill-invocation` `MessageSource` kind ({ name, form: 'instructions' }) that user-explicit injection stamps on its messages — transcript consumers present the invocation from this metadata instead of re-parsing the body. + +`isModelInvocable(skill)` and `isUserInvocable(skill)` read the matching positive field directly. `ctx.skills.get()` remains the trusted, policy-neutral loading primitive, so every user- or model-facing consumer must enforce the predicate that matches its surface before exposing or loading a skill. + +## Provider Contract + +A provider factory runs synchronously and receives one registration-scoped control. `control.signal` aborts when registration fails or is disposed; `control.invalidate()` clears completed catalogs only while that exact registration remains active, so late callbacks cannot affect a replacement with the same name. Immutable providers may ignore the control. Remote setup, authentication, and discovery belong in the provider's awaited `list(options)` call. An array return is shorthand for complete discovery; a provider that collected usable candidates but could not establish an authoritative observation returns `{ candidates, complete: false }`. Provider objects, lookup options, candidates, and definitions are borrowed readonly rather than cloned or rebound. Providers should honor `options.signal`; the registry also stops awaiting uncooperative discovery or loading after cancellation. + +The registry validates candidates before caching and definitions before returning them. The winning provider receives the same candidate and opaque `locator` it returned from `list()`, allowing backend-specific file, URL, id, or version handles. Callers and providers must preserve the readonly contract. + +Contract violations fail fast. A rejected provider `list()` is treated as a transient source failure and omitted. An explicit incomplete observation still contributes its candidates for `list()` and `get()`, but makes the aggregate snapshot incomplete and uncacheable. A provider or runtime revision change discards an in-flight result and retries once. If the retry is also superseded, its candidates are returned incomplete and uncached so a continuously invalidating provider cannot monopolize the caller. Within one layer, duplicate names resolve by rank, provider registration order, then provider-local order; across layers the nearest scope's entry wins the name. Summaries are sorted by skill name. + +Definitions remain progressively loaded. `get()` asks the winning provider for the body on every call rather than caching it in this registry. If the returned definition has a different name from the selected candidate, the stale selection is rejected and the registry internally invalidates that exact provider so the next snapshot rediscovers its catalog. + +## Runtime Skills + +`ctx.skills.register(...)` is a convenience for embedded runtime skills. Runtime skills use rank `250`: project providers can override them, while they override the shipped local provider's custom and user roots. Runtime definitions and nested resource metadata are borrowed readonly; the service materializes one top-level definition to supply omitted invocation and provider defaults. Registration is first-wins within runtime contributions, so a duplicate contribution cannot remove the active one through its disposer. + +## Consumer boundary + +The registry does not render model guidance or register model-facing tools. [`@deepseek-ai/dsh-tool-skill`](../tool-skill) consumes `ctx.skills` to provide durable session catalogs and the `skill` tool, so providers remain independent of model-facing behavior. + +## Model Experience + +Indirectly, through `dsh-tool-skill`, which renders provider summaries into durable initial or replacement catalog messages and loaded instructions into retained tool results. + +#### KV Cache effect + +No direct prompt effect. The named consumer owns the durable initial catalog and append-only replacements after invalidation. + +## Known Limitations and Deferred Work + +- **Invalidation is provider-driven** — the registry has no TTL and cannot infer that an arbitrary remote source changed; each mutable provider must retain and call its registration-scoped `invalidate()` capability from its own observation mechanism. +- **Providers are queried sequentially** — one slow cooperative provider delays every provider registered after it; cancellation stops the caller's wait but cannot terminate work an uncooperative provider keeps running. +- **Incomplete observations are not retained** — rejected providers are omitted and explicitly supplied candidates remain available only to the current lookup; the registry owns neither a last-good catalog nor per-provider diagnostics. +- **Duplicate resolution is first-wins** — later lower-priority candidates within a layer are logged and hidden, and a nearer layer shadows a farther one silently; there is no API to inspect all shadowed definitions. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.zh.md new file mode 100644 index 0000000..5eae1d5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/README.zh.md @@ -0,0 +1,79 @@ +# @deepseek-ai/dsh-skill + +[English](README.md) | 中文 + +纯 agent skill(智能体技能)提供方注册表。 + +该包负责 `ctx.skills` 接口。它不知道 skill 来自本地文件、嵌入式插件数据、HTTP 还是其他后端;提供方通过 `ctx.skills.registerProvider(...)` 注册这些来源。已发布的本地实现是 [`@deepseek-ai/dsh-skill-filesystem`](../skill-filesystem)。 + +注册表基于 [`@deepseek-ai/dsh-scope`](../../core/scope) 采用宿主 + 按 scope 的分层结构,即工具注册表确立的形态:注册落入调用方上下文 scope 对应的层——宿主行与 repository 插件落入全局层,由 agent preset 常驻组合挂载的插件落入该 preset 的层——读取时将全局层与观察 scope 的链合并,最近层直接赢得重名,rank 只在单层内裁决重名。 + +## 服务:`SkillRegistry`(ctx 键:`skills`) + +### 公开 API + +- `ctx.skills.registerProvider(create): () => void` 调用同步提供方工厂并向其传入 `{ signal, invalidate }`,随后以在调用方上下文所在层内唯一的 `provider.name` 注册其只读结果。同层重复提供方名称会抛错,`runtime` 为保留名称;注册失败会中止信号。精确的 Cordis disposer 会注销提供方、中止信号,并保持有序组合拆卸。 +- `ctx.skills.snapshot({ cwd?, signal?, scope? })` 返回观察 scope 各层合并后、与调用策略无关的 `{ skills, complete }` 观测。任一提供方调用被拒绝或显式报告发现不完整,或有界重试期间又发生目录修订时,`complete` 为 false;该次观测提供的候选项仍保留在此结果中,但该结果绝不缓存。 +- `ctx.skills.list({ cwd?, signal?, scope? })` 借用只读视图选项,然后返回当前工作区中的全部胜出摘要;这些摘要在全局层与观察 scope 链之间合并,并按名称排序。消费方在自身边界调用 `isModelInvocable(skill)` 或 `isUserInvocable(skill)`。 +- `ctx.skills.get(name, { cwd?, signal?, scope? })` 在发现和加载中使用同一组只读选项和胜出候选项;在发现或缓存命中后重新检查取消,让提供方加载与信号竞速,验证已加载定义,然后无论调用策略如何都将其返回。 +- `ctx.skills.register(skill): () => void` 将只读运行时嵌入式 skill 注册进调用方上下文所在层,省略时添加允许模型和用户调用的策略以及 `provider: "runtime"`。同层同名运行时注册使用先到先得:重复项会记录警告,并获得无操作 disposer。成功注册会返回精确的 Cordis disposer,以供有序组合拆卸。 + +### 事件 + +- `skills/change` 是一条不带过滤条件的失效通知,在提供方或运行时贡献注册或释放后,以及活动提供方的注册控制触发失效后发出。它不携带目录或 diff;每个消费方都使用自身的查找选项重新获取 `snapshot()`。监听器抛错或 Promise 拒绝会被记录,既不能否决注册表变更,也不能阻止后续监听器执行。 + +### 配置 + +| 字段 | 默认值 | 含义 | +|---|---|---| +| `collectCacheMaxEntries` | `128` | 内存中保留的最大已完成 cwd/提供方目录数。 | + +### 调用策略 + +`SkillSummary.invocation` 是一个必填的类型化策略对象,其正向布尔字段 `modelInvocable` 和 `userInvocable` 分别描述两个接口。提供方会在每个候选项和定义中返回这一已解析形状;只有 `SkillRegistration` 输入可以省略它,此时 `register()` 会补入 `{ modelInvocable: true, userInvocable: true }`。注册表保留全部四种组合,使一次发现结果可以同时服务面向模型的工具、面向用户的命令和受信内部调用方,而不会混淆各自的目录。 + +| 策略 | 模型 | 用户 | +|---|---|---| +| `{ modelInvocable: true, userInvocable: true }` | 包含 | 包含 | +| `{ modelInvocable: true, userInvocable: false }` | 包含 | 排除 | +| `{ modelInvocable: false, userInvocable: true }` | 排除 | 包含 | +| `{ modelInvocable: false, userInvocable: false }` | 排除 | 排除 | + +### 共享的面向模型渲染 + +`renderSkillContent(skill)` 把一个已加载 skill 渲染为规范的 `` 块(转义后的 `name` 属性、资源提示、原样正文)。它是两条加载路径的唯一真源:`dsh-tool-skill` 将其作为 `skill` 工具结果返回,并在用户显式的手势边界将其注入,因此无论加载由谁发起,模型看到的都是同一种形态。`escapeText` 随之一并导出,供要在同一标记框架中嵌入文案的消费方使用。该包还声明 `skill-invocation` 这个 `MessageSource` kind({ name, form: 'instructions' }),用户显式注入会把它打在自己的消息上——transcript(文本记录)消费方依据这份元数据呈现该次调用,而不是重新解析正文。 + +`isModelInvocable(skill)` 和 `isUserInvocable(skill)` 分别直接读取对应的正向字段。`ctx.skills.get()` 仍是受信且与策略无关的加载原语,因此每个面向用户或模型的消费方都必须先执行与自身接口匹配的判定,再暴露或加载 skill。 + +## 提供方约定 + +提供方工厂同步运行,并接收一项注册作用域内的控制能力。注册失败或释放时,`control.signal` 会中止;仅当该精确注册仍处于活动状态时,`control.invalidate()` 才会清除已完成目录,因此延迟回调无法影响同名替代项。不可变提供方可以忽略该控制能力。远程设置、身份验证和发现应在提供方的 `list(options)` 调用中完成,该调用会被等待。返回数组是完整发现的简写形式;若提供方已收集到可用候选项,却无法建立权威观测,则返回 `{ candidates, complete: false }`。提供方对象、查找选项、候选项和定义都以只读方式借用,而不是克隆或重新绑定。提供方应遵守 `options.signal`;取消后,注册表也会停止等待不协作的发现或加载。 + +注册表在缓存前验证候选项,在返回前验证定义。胜出提供方会收到同一候选项和不透明 `locator`,两者都是它从 `list()` 返回的内容,从而支持后端专用文件、URL、id 或版本句柄。调用方和提供方必须保持只读约定。 + +违反约定时会快速失败。`list()` 返回的 Promise 被拒绝会被视为瞬时来源失败,并省略其结果。显式的不完整观测仍会为 `list()` 和 `get()` 提供其候选项,但会使聚合快照不完整且不可缓存。提供方或运行时修订发生变化时,会丢弃正在进行的结果并重试一次。如果这次重试也被后续修订取代,则返回其候选项,并将结果标为不完整且不予缓存,以免持续触发失效的提供方一直占用调用方。单层内重复名称依次按 rank、提供方注册顺序和提供方本地顺序解决冲突;跨层则由最近 scope 的条目赢得名称。摘要按 skill 名称排序。 + +定义仍采用渐进式加载。`get()` 每次调用都会向胜出提供方请求正文,而不是在此注册表中缓存正文。若返回定义的名称不同于所选候选项,系统会拒绝该陈旧选择,并由注册表在内部使该精确提供方失效,以便下一次快照重新发现其目录。 + +## 运行时 skill + +`ctx.skills.register(...)` 是嵌入式运行时 skill 的便利接口。运行时 skill 使用 rank `250`:项目提供方可覆盖它们,它们则覆盖已发布本地提供方的自定义根目录和用户根目录。运行时定义和嵌套资源元数据均以只读方式借用;服务只物化一个顶层定义,以补入省略的调用策略和 `provider` 默认值。运行时贡献内的注册使用先到先得,因此重复贡献无法通过其 disposer 移除当前生效的贡献。 + +## 消费方边界 + +注册表不渲染模型指引,也不注册面向模型的工具。[`@deepseek-ai/dsh-tool-skill`](../tool-skill) 消费 `ctx.skills` 以提供持久会话目录和 `skill` 工具,因此提供方仍与模型接口独立。 + +## 模型体验 + +通过 `dsh-tool-skill` 间接影响模型;该包将提供方摘要渲染到持久的初始目录或替换目录消息中,并将已加载指令渲染到已保留工具结果中。 + +#### KV Cache 影响 + +不直接影响提示词。指定的消费方负责持久初始目录,以及失效后的仅追加式目录替换。 + +## 已知限制与暂缓事项 + +- **失效由提供方驱动**:注册表没有 TTL,无法推断任意远程来源是否已发生变化;每个可变提供方都必须保留其注册作用域内的 `invalidate()` 能力,并由自身的观测机制调用它。 +- **提供方依次查询**:一个响应取消但速度缓慢的提供方会延迟之后注册的所有提供方;取消会停止调用方等待,但无法终止不响应取消的提供方持续运行的工作。 +- **不保留不完整观测**:被拒绝的提供方会被省略,显式提供的候选项也仅在当前查找中可用;注册表既不负责上一份可用目录,也不负责逐提供方诊断。 +- **重名项的裁决采用先到先得**:系统会记录并隐藏层内较晚出现的低优先级候选项,较近的层会静默遮蔽较远的层;不提供检查全部被遮蔽定义的 API。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/index.js new file mode 100644 index 0000000..8bc9885 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/index.js @@ -0,0 +1,565 @@ +import { Service } from "@deepseek-ai/cordis"; +import { assertNever } from "@deepseek-ai/dsh-llm"; +import { NamedEntries, ScopedLayers, scopeChainOf, scopeOf } from "@deepseek-ai/dsh-scope"; +import z from "@deepseek-ai/schemastery"; +//#region lib/types/index.js +/** +* Agent skill provider registry. +* +* This package owns the Service Definition role of the skill capability seam. +* Concrete +* providers such as `@deepseek-ai/dsh-skill-filesystem` decide where skills come +* from; this service only merges provider catalogs, resolves the winning skill +* for a name, and exposes the winning summaries and definitions to consumers. +* +* @module @deepseek-ai/dsh-skill +*/ +const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/; +const DEFAULT_COLLECT_CACHE_ENTRIES = 128; +const MAX_COLLECT_ATTEMPTS = 2; +const RUNTIME_PROVIDER = "runtime"; +const RUNTIME_RANK = 250; +/** Standard precedence rank for packaged skill providers and local bundled roots. */ +const BUNDLED_SKILL_RANK = 600; +/** +* Return whether a string is a valid kebab-case skill name. +* @param name - candidate skill name to validate. +* @returns whether the name matches the public skill-name grammar. +*/ +function isSkillName(name) { + return SKILL_NAME.test(name); +} +/** +* Return whether a skill may be advertised to and loaded by a model. +* @param skill - skill metadata carrying resolved invocation controls. +* @returns whether the policy permits model invocation. +*/ +function isModelInvocable(skill) { + return skill.invocation.modelInvocable; +} +/** +* Return whether a skill may be advertised to and loaded by a human-facing command. +* @param skill - skill metadata carrying resolved invocation controls. +* @returns whether the policy permits user invocation. +*/ +function isUserInvocable(skill) { + return skill.invocation.userInvocable; +} +/** +* Render one loaded skill for the model. The output is shared verbatim by the +* `skill` tool result and the user-explicit invocation injection, so the model +* sees one canonical `` shape on both paths. The name rides an +* escaped attribute; the body is embedded verbatim (skills are trusted local +* content, and user-supplied invocation text stays outside this wrapper). +* @param skill - name, provider, optional resource base, and body to render. +* @returns the complete model-facing `` block. +*/ +function renderSkillContent(skill) { + const resourceHint = renderResourceHint(skill); + return [ + ``, + "", + ...resourceHint, + "", + "", + "", + skill.content, + "", + "" + ].join("\n"); +} +function renderResourceHint(skill) { + const base = skill.resourceBase; + if (base === void 0) return [`Resources for this skill are managed by provider "${escapeText(skill.provider)}".`, "Load referenced resources only as needed."]; + switch (base.kind) { + case "directory": return [`Base directory for this skill: ${escapeText(base.path)}`, "Resolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed."]; + case "url": return [`Base URL for this skill: ${escapeText(base.url)}`, "Resolve relative URLs mentioned by this skill against the base URL before using them. Load referenced resources only as needed."]; + case "opaque": return [`Resources for this skill: ${escapeText(base.description)}`, "Load referenced resources only as needed."]; + /* v8 ignore start -- SkillResourceBase is a closed union; a future kind must fail compilation here. */ + default: return assertNever(base, "SkillResourceBase.kind"); + } +} +function escapeAttr(value) { + return value.replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<"); +} +/** +* Escape model-facing prose embedded inside skill markup so provider-supplied +* text cannot open or close framing tags. +* @param value - raw prose to embed. +* @returns the escaped text. +*/ +function escapeText(value) { + return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); +} +/** One scope's complete skill-registry contribution. */ +var SkillLayer = class { + /** Providers registered through contexts carrying this scope, insertion-ordered. */ + providers; + /** Runtime skills registered through contexts carrying this scope. */ + runtime = /* @__PURE__ */ new Map(); + constructor(scope) { + this.providers = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `a skill provider named "${name}" is already registered` : `a skill provider named "${name}" is already registered in this scope`)); + } + /** Whether every contribution table in this aggregate layer is empty. */ + isEmpty() { + return this.providers.isEmpty() && this.runtime.size === 0; + } +}; +/** +* Layered registry of skill providers, the host+per-scope shape the tools +* registry established. A registration files into the layer of its calling +* context's scope ({@link scopeOf}): host rows and repository plugins land in +* the global layer, while a plugin mounted by an agent preset's standing +* composition lands in that preset's layer. A read merges the global layer +* with the viewing scope's chain — the nearest layer's entry wins a duplicate +* name outright, and the rank order decides duplicates only within one layer. +* It exposes sorted invocation-neutral summaries and loads full skill bodies +* on demand. +*/ +var SkillRegistry = class extends Service { + static Config = z.object({ collectCacheMaxEntries: z.number().default(DEFAULT_COLLECT_CACHE_ENTRIES) }); + collectCacheMaxEntries; + layers = new ScopedLayers((scope) => new SkillLayer(scope), () => { + this.invalidateCache(); + }); + collectCache = /* @__PURE__ */ new Map(); + revision = 0; + nextProviderOrder = 0; + /** Stable identities for cache keys; scope keys are opaque identity-compared objects. */ + scopeIds = /* @__PURE__ */ new WeakMap(); + nextScopeId = 1; + constructor(ctx, config = {}) { + super(ctx, "skills"); + this.collectCacheMaxEntries = config.collectCacheMaxEntries ?? DEFAULT_COLLECT_CACHE_ENTRIES; + assertPositiveInteger("collectCacheMaxEntries", this.collectCacheMaxEntries); + } + /** + * Register a borrowed same-process provider synchronously during plugin + * apply, into the calling context's layer: a scoped context (an agent + * preset's standing mount) registers for that scope alone, an unscoped + * context registers globally. Duplicate names within one layer and reserved + * names throw; remote initialization belongs in `list()`. Fiber disposal + * unregisters the provider and invalidates catalog caches. + * @param create - synchronous factory receiving this registration's lifecycle and invalidation control. + * @returns the exact Cordis effect disposer that unregisters this provider; + * composite effects may yield it directly to preserve teardown ordering. + */ + registerProvider(create) { + const lifecycle = new AbortController(); + let registration; + let provider; + const control = { + signal: lifecycle.signal, + invalidate: () => { + const active = registration; + if (active !== void 0 && active.layer.providers.get(active.name)?.provider === provider) this.invalidateCache(); + } + }; + try { + provider = create(control); + const name = provider.name; + if (name === RUNTIME_PROVIDER) throw new Error(`"${RUNTIME_PROVIDER}" is reserved for runtime skill registrations`); + const order = this.nextProviderOrder; + this.nextProviderOrder += 1; + return this.layers.effect(this.ctx, (layer) => { + const undo = layer.providers.insert(name, { + provider, + order + }); + registration = { + layer, + name + }; + return () => { + registration = void 0; + undo(); + lifecycle.abort(/* @__PURE__ */ new Error(`skill provider "${name}" disposed`)); + }; + }, { label: "skills.registerProvider()" }); + } catch (error) { + lifecycle.abort(error); + throw error; + } + } + /** + * Register a borrowed readonly runtime skill into the calling context's + * layer. Project entries outrank runtime entries, which outrank user + * entries, within one layer. Same-name runtime entries in one layer are + * first-wins; a duplicate logs a warning and receives a no-op disposer so + * it cannot remove the winner. + * @param skill - the skill definition input; omitted invocation and provider fields receive defaults. + * @returns the exact Cordis effect disposer, preserving composite teardown order and invalidating caches. + */ + register(skill) { + validateRuntimeSkill(skill); + const scope = scopeOf(this.ctx); + const existingLayer = scope === void 0 ? this.layers.global : this.layers.peek(scope); + if (existingLayer !== void 0 && existingLayer.runtime.has(skill.name)) { + this.ctx.logger.warn(`runtime skill "${skill.name}" ignored because it is already registered`); + return () => {}; + } + const definition = { + ...skill, + invocation: skill.invocation ?? { + modelInvocable: true, + userInvocable: true + }, + provider: skill.provider ?? RUNTIME_PROVIDER + }; + return this.layers.effect(this.ctx, (layer) => { + layer.runtime.set(definition.name, definition); + return () => { + layer.runtime.delete(definition.name); + }; + }, { label: "skills.register()" }); + } + /** + * List invocation-neutral skill summaries for a workspace. Consumers apply + * model or user invocation policy at their operational boundary. Lookup + * options and provider candidates are readonly same-process values borrowed + * throughout discovery. + * @param options - view options; `scope` selects the viewing agent's layers, `cwd` selects project roots, and `signal` cancels discovery. + * @returns all sorted winning summaries. + */ + async list(options = {}) { + return (await this.snapshot(options)).skills; + } + /** + * Observe the current invocation-neutral catalog and whether discovery completed within a stable revision. + * Incomplete observations are never cached, allowing consumers to retain last-good state and + * retry on their next request boundary. + * @param options - view options; `scope` selects the viewing agent's layers, `cwd` selects project roots, and `signal` cancels discovery. + * @returns sorted summaries plus discovery-completeness state. + */ + async snapshot(options = {}) { + const collected = await this.collect(options); + return { + skills: [...collected.entries.values()].map((entry) => toSummary(entry.candidate)).sort(compareSkillSummary), + complete: collected.cacheable + }; + } + /** + * Load and validate the winning candidate, passing its opaque discovery locator back to the + * provider. Cancellation is rechecked after selection, including cache hits, and raced against + * loading so an uncooperative provider cannot hang the caller. + * @param name - kebab-case skill name. + * @param options - view options; `scope` selects the viewing agent's layers, + * `cwd` selects workspace-sensitive skills, and `signal` cancels work. + * @returns the full skill, including body content, or `undefined`. + */ + async get(name, options = {}) { + if (!isSkillName(name)) return void 0; + const collected = await this.collect(options); + throwIfAborted(options.signal); + const match = collected.entries.get(name); + if (match === void 0) return void 0; + const definition = await waitWithAbort(match.provider.get(match.candidate, options), options.signal); + if (definition === void 0) return void 0; + validateDefinition(definition); + if (definition.name !== match.candidate.name) { + this.invalidateEntry(match); + return; + } + return definition; + } + async collect(options) { + throwIfAborted(options.signal); + let attempt = 1; + while (true) { + const revision = this.revision; + const key = this.collectCacheKey(options.cwd, scopeChainOf(options.scope), revision); + const cached = this.collectCache.get(key); + if (cached !== void 0) return { + entries: cached, + cacheable: true + }; + const result = await this.collectFresh(options); + throwIfAborted(options.signal); + if (revision !== this.revision) { + if (attempt < MAX_COLLECT_ATTEMPTS) { + attempt += 1; + continue; + } + return { + entries: result.entries, + cacheable: false + }; + } + if (result.cacheable) { + this.collectCache.set(key, result.entries); + if (this.collectCache.size > this.collectCacheMaxEntries) { + const oldest = this.collectCache.keys().next(); + this.collectCache.delete(oldest.value); + } + } + return result; + } + } + async collectFresh(options) { + const layers = [this.layers.global, ...this.layers.chainLayers(options.scope)]; + const merged = /* @__PURE__ */ new Map(); + let cacheable = true; + for (const layer of layers) { + const collected = await this.collectLayer(layer, options); + if (!collected.cacheable) cacheable = false; + for (const entry of collected.entries) merged.set(entry.candidate.name, entry); + } + return { + entries: merged, + cacheable + }; + } + async collectLayer(layer, options) { + const collected = await this.listLayerCandidates(layer, options); + collected.entries.sort(compareIndexedCandidates); + const seen = /* @__PURE__ */ new Set(); + const result = []; + for (const entry of collected.entries) { + const skill = entry.candidate; + if (seen.has(skill.name)) { + this.ctx.logger.warn(`skill "${skill.name}" from ${skill.source} ignored because a higher-priority skill already exists`); + continue; + } + seen.add(skill.name); + result.push(entry); + } + return { + entries: result, + cacheable: collected.cacheable + }; + } + async listLayerCandidates(layer, options) { + throwIfAborted(options.signal); + const candidates = []; + let cacheable = true; + let runtimeOrder = 0; + for (const skill of [...layer.runtime.values()].sort((a, b) => compareCodePoints(a.name, b.name))) { + candidates.push({ + candidate: runtimeCandidate(skill), + provider: RUNTIME_SKILL_PROVIDER, + providerOrder: -1, + localOrder: runtimeOrder, + layer + }); + runtimeOrder += 1; + } + for (const { provider, order } of [...layer.providers.values()]) { + let localOrder = 0; + let output; + try { + output = await waitWithAbort(provider.list(options), options.signal); + } catch (error) { + if (options.signal?.aborted === true) throw toError(options.signal.reason); + cacheable = false; + this.ctx.logger.warn(`skill provider "${provider.name}" skipped: ${errorMessage(error)}`); + } + if (output === void 0) continue; + const observation = normalizeProviderObservation(output, provider.name); + if (!observation.complete) cacheable = false; + for (const candidate of observation.candidates) { + validateCandidate(candidate, provider.name); + candidates.push({ + candidate, + provider, + providerOrder: order, + localOrder, + layer + }); + localOrder += 1; + } + } + return { + entries: candidates, + cacheable + }; + } + invalidateCache() { + this.revision += 1; + this.collectCache.clear(); + this.notifyChange(); + } + /** Invalidate after a stale definition load, only while the exact registration that produced the entry is still live. */ + invalidateEntry(entry) { + /* v8 ignore else -- A definition load can outlive the exact provider registration it selected. */ + if (entry.layer.providers.get(entry.provider.name)?.provider === entry.provider) this.invalidateCache(); + } + scopeId(key) { + let id = this.scopeIds.get(key); + if (id === void 0) { + id = this.nextScopeId; + this.nextScopeId += 1; + this.scopeIds.set(key, id); + } + return id; + } + collectCacheKey(cwd, chain, revision) { + return JSON.stringify({ + cwd, + scopes: chain.map((key) => this.scopeId(key)), + revision + }); + } + /** Notify catalog observers without making their refresh work load-bearing. */ + notifyChange() { + for (const callback of this.ctx.events.dispatch("emit", ["skills/change"])) try { + const returned = callback(); + Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`skills/change listener rejected: ${errorMessage(error)}`); + }); + } catch (error) { + this.ctx.logger.warn(`skills/change listener threw: ${errorMessage(error)}`); + } + } +}; +function normalizeProviderObservation(output, providerName) { + if (Array.isArray(output)) return { + candidates: output, + complete: true + }; + if (output === null || typeof output !== "object") throw invalidProviderObservation(providerName); + const observation = output; + if (!Array.isArray(observation.candidates) || typeof observation.complete !== "boolean") throw invalidProviderObservation(providerName); + return observation; +} +function invalidProviderObservation(providerName) { + return /* @__PURE__ */ new TypeError(`skill provider "${providerName}" list() must return an array or { candidates, complete } observation`); +} +const RUNTIME_SKILL_PROVIDER = { + name: RUNTIME_PROVIDER, + /* v8 ignore next -- Runtime skills are injected directly by the registry; this provider only owns `get()`. */ + list() { + return Promise.resolve([]); + }, + get(candidate) { + return Promise.resolve(candidate.locator); + } +}; +function runtimeCandidate(skill) { + return { + name: skill.name, + description: skill.description, + ...skill.whenToUse !== void 0 ? { whenToUse: skill.whenToUse } : {}, + invocation: skill.invocation, + source: skill.source, + provider: skill.provider, + ...skill.resourceBase !== void 0 ? { resourceBase: skill.resourceBase } : {}, + rank: RUNTIME_RANK, + locator: skill, + ...skill.path !== void 0 ? { path: skill.path } : {}, + ...skill.metadata !== void 0 ? { metadata: skill.metadata } : {} + }; +} +function validateCandidate(candidate, providerName) { + if (typeof candidate.name !== "string") throw new TypeError(`skill provider "${providerName}" returned a non-string skill name`); + if (!SKILL_NAME.test(candidate.name)) throw new Error(`skill provider "${providerName}" returned invalid skill name "${candidate.name}"`); + if (typeof candidate.description !== "string") throw new TypeError(`skill provider "${providerName}" returned skill "${candidate.name}" with a non-string description`); + if (candidate.description.length === 0) throw new Error(`skill provider "${providerName}" returned skill "${candidate.name}" without a description`); + validateInvocation(candidate.invocation, `skill provider "${providerName}" returned skill "${candidate.name}"`); + if (candidate.whenToUse !== void 0 && typeof candidate.whenToUse !== "string") throw new TypeError(`skill provider "${providerName}" returned skill "${candidate.name}" with a non-string whenToUse`); + if (typeof candidate.source !== "string") throw new TypeError(`skill provider "${providerName}" returned skill "${candidate.name}" with a non-string source`); + if (typeof candidate.rank !== "number" || !Number.isFinite(candidate.rank)) throw new Error(`skill provider "${providerName}" returned skill "${candidate.name}" with an invalid rank`); + if (typeof candidate.provider !== "string") throw new TypeError(`skill provider "${providerName}" returned skill "${candidate.name}" with a non-string provider`); + if (candidate.provider !== providerName) throw new Error(`skill provider "${providerName}" returned skill "${candidate.name}" for provider "${candidate.provider}"`); + if (candidate.path !== void 0 && typeof candidate.path !== "string") throw new TypeError(`skill provider "${providerName}" returned skill "${candidate.name}" with a non-string path`); +} +function validateRuntimeSkill(skill) { + if (!SKILL_NAME.test(skill.name)) throw new Error(`invalid skill name "${skill.name}"`); + if (skill.description.length === 0) throw new Error(`skill "${skill.name}" requires a description`); + validateInvocation(skill.invocation, `runtime skill "${skill.name}"`); +} +/** Validate a definition loaded from a provider-controlled parser or remote source. */ +function validateDefinition(skill) { + const name = skill.name; + const description = skill.description; + const whenToUse = skill.whenToUse; + const invocation = skill.invocation; + const source = skill.source; + const provider = skill.provider; + const content = skill.content; + const path = skill.path; + if (typeof name !== "string") throw new TypeError("loaded skill name must be a string"); + if (!SKILL_NAME.test(name)) throw new Error(`loaded skill has invalid name "${name}"`); + if (typeof description !== "string") throw new TypeError(`loaded skill "${name}" description must be a string`); + if (description.length === 0) throw new Error(`loaded skill "${name}" requires a description`); + validateInvocation(invocation, `loaded skill "${name}"`); + if (whenToUse !== void 0 && typeof whenToUse !== "string") throw new TypeError(`loaded skill "${name}" whenToUse must be a string`); + if (typeof source !== "string") throw new TypeError(`loaded skill "${name}" source must be a string`); + if (typeof provider !== "string") throw new TypeError(`loaded skill "${name}" provider must be a string`); + if (typeof content !== "string") throw new TypeError(`loaded skill "${name}" content must be a string`); + if (path !== void 0 && typeof path !== "string") throw new TypeError(`loaded skill "${name}" path must be a string`); +} +function toSummary(skill) { + const { name, description, whenToUse, invocation, source, provider, resourceBase } = skill; + return { + name, + description, + ...whenToUse !== void 0 ? { whenToUse } : {}, + invocation, + source, + provider, + ...resourceBase !== void 0 ? { resourceBase } : {} + }; +} +function validateInvocation(invocation, subject) { + if (invocation === void 0) return; + if (typeof invocation !== "object" || invocation === null || Array.isArray(invocation)) throw new TypeError(`${subject} with a non-object invocation policy`); + const policy = invocation; + if (typeof policy.modelInvocable !== "boolean") throw new TypeError(`${subject} with a non-boolean invocation.modelInvocable`); + if (typeof policy.userInvocable !== "boolean") throw new TypeError(`${subject} with a non-boolean invocation.userInvocable`); +} +function compareSkillSummary(left, right) { + return compareCodePoints(left.name, right.name); +} +function compareCodePoints(left, right) { + if (left < right) return -1; + if (left > right) return 1; + return 0; +} +function compareIndexedCandidates(left, right) { + return left.candidate.rank - right.candidate.rank || left.providerOrder - right.providerOrder || left.localOrder - right.localOrder; +} +function assertPositiveInteger(name, value, minimum = 1) { + if (!Number.isInteger(value) || value < minimum) throw new Error(`skill: ${name} must be an integer greater than or equal to ${minimum}`); +} +function waitWithAbort(promise, signal) { + if (signal === void 0) return promise; + throwIfAborted(signal); + return new Promise((resolve, reject) => { + const cleanup = () => { + signal.removeEventListener("abort", onAbort); + }; + const onAbort = () => { + cleanup(); + reject(toError(signal.reason)); + }; + signal.addEventListener("abort", onAbort, { once: true }); + promise.then((value) => { + cleanup(); + resolve(value); + }, (error) => { + cleanup(); + reject(toError(error)); + }); + }); +} +/** Throw a total Error for an already-aborted lookup. */ +function throwIfAborted(signal) { + if (signal?.aborted === true) throw toError(signal.reason); +} +/** Normalize an arbitrary abort or provider failure without trusting coercion. */ +function toError(error) { + try { + if (error instanceof Error) return error; + } catch {} + return new Error(errorMessage(error)); +} +/** Render an arbitrary provider failure without letting coercion escape containment. */ +function errorMessage(error) { + try { + return String(error); + } catch { + return "[unrenderable thrown value]"; + } +} +//#endregion +export { BUNDLED_SKILL_RANK, SkillRegistry, SkillRegistry as default, escapeText, isModelInvocable, isSkillName, isUserInvocable, renderSkillContent }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/invariant.js new file mode 100644 index 0000000..7ac6e52 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-skill`. +* @module @deepseek-ai/dsh-skill/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-skill"; +/** Cordis companion plugin name. */ +const name = "skill-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: provider/runtime maps and revisioned caches mutate atomically inside the +* registry, which exposes no independent change event or snapshot for cross-checking them. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/types/index.d.ts new file mode 100644 index 0000000..46e1970 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/types/index.d.ts @@ -0,0 +1,300 @@ +/** + * Agent skill provider registry. + * + * This package owns the Service Definition role of the skill capability seam. + * Concrete + * providers such as `@deepseek-ai/dsh-skill-filesystem` decide where skills come + * from; this service only merges provider catalogs, resolves the winning skill + * for a name, and exposes the winning summaries and definitions to consumers. + * + * @module @deepseek-ai/dsh-skill + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { ScopeKey } from '@deepseek-ai/dsh-scope'; +import type Schema from '@deepseek-ai/schemastery'; +/** Standard precedence rank for packaged skill providers and local bundled roots. */ +export declare const BUNDLED_SKILL_RANK = 600; +/** + * Return whether a string is a valid kebab-case skill name. + * @param name - candidate skill name to validate. + * @returns whether the name matches the public skill-name grammar. + */ +export declare function isSkillName(name: string): boolean; +/** Origin bucket for a skill contribution. The value is prompt-visible metadata, not precedence by itself. */ +export type SkillSource = 'project-dsh' | 'project-agents' | 'runtime' | 'user-dsh' | 'user-agents' | 'custom' | 'bundled' | (string & {}); +/** Optional provider-specific base used by loaded skill bodies to resolve relative resources. */ +export type SkillResourceBase = { + readonly kind: 'directory'; + readonly path: string; +} | { + readonly kind: 'url'; + readonly url: string; +} | { + readonly kind: 'opaque'; + readonly description: string; +}; +/** Invocation controls shared by skill discovery consumers. */ +export interface SkillInvocationPolicy { + /** Whether model-facing catalogs and loaders include this skill. */ + readonly modelInvocable: boolean; + /** Whether human-facing command catalogs and loaders include this skill. */ + readonly userInvocable: boolean; +} +/** Invocation-neutral skill metadata returned by `ctx.skills.list()`. */ +export interface SkillSummary { + /** Kebab-case identifier used to address the skill. */ + readonly name: string; + /** Short routing description shown by discovery consumers. */ + readonly description: string; + /** Optional extra routing guidance. */ + readonly whenToUse?: string; + /** Resolved model and user invocation controls. */ + readonly invocation: SkillInvocationPolicy; + /** Discovery source that produced this winning skill. */ + readonly source: SkillSource; + /** Provider that owns this skill body. */ + readonly provider: string; + /** Provider-specific base for relative resources. */ + readonly resourceBase?: SkillResourceBase; +} +/** Provider catalog entry used by the registry to merge and later load skills. */ +export interface SkillCandidate extends SkillSummary { + /** Lower ranks win duplicate skill names before provider registration order is considered. */ + readonly rank: number; + /** Opaque provider-owned handle passed back to `provider.get()`. */ + readonly locator: unknown; + /** Absolute file path when the provider has one. */ + readonly path?: string; + /** Parsed optional metadata object from provider-specific skill frontmatter. */ + readonly metadata?: Readonly>; +} +/** Complete parsed skill definition, including the body loaded by `ctx.skills.get()`. */ +export interface SkillDefinition extends SkillSummary { + /** Markdown instruction body after any provider-specific metadata removal. */ + readonly content: string; + /** Absolute file path when the skill came from disk. */ + readonly path?: string; + /** Parsed optional metadata object from frontmatter. */ + readonly metadata?: Readonly>; +} +/** Runtime skill contribution accepted by `ctx.skills.register()`. */ +export type SkillRegistration = Omit & { + /** Invocation controls; omission permits both model and user surfaces. */ + readonly invocation?: SkillInvocationPolicy; + /** Provider label; omission uses the registry-owned runtime provider. */ + readonly provider?: string; +}; +/** Caller context used for cwd-sensitive and abortable provider work. */ +export interface SkillLookupOptions { + /** Workspace selector for the current lookup. */ + readonly cwd?: string | undefined; + /** Abort discovery or loading work for the current caller. */ + readonly signal?: AbortSignal | undefined; +} +/** + * Registry read options: provider lookup context plus the viewing scope. + * The registry consumes `scope` to select layers; providers receive the same + * borrowed options object and read only their {@link SkillLookupOptions} + * contract from it. + */ +export interface SkillViewOptions extends SkillLookupOptions { + /** Viewing scope (the calling agent); omitted reads the global layer alone. */ + readonly scope?: ScopeKey | undefined; +} +/** + * Return whether a skill may be advertised to and loaded by a model. + * @param skill - skill metadata carrying resolved invocation controls. + * @returns whether the policy permits model invocation. + */ +export declare function isModelInvocable(skill: Pick): boolean; +/** + * Return whether a skill may be advertised to and loaded by a human-facing command. + * @param skill - skill metadata carrying resolved invocation controls. + * @returns whether the policy permits user invocation. + */ +export declare function isUserInvocable(skill: Pick): boolean; +/** + * Durable source for the context message a user-explicit skill invocation + * injects: the user's own words ride a plain user message, and the rendered + * skill body follows as injected `instructions`-form context carrying this + * source, so transcript consumers present the injection from metadata + * instead of re-parsing the model-facing text. + */ +export interface SkillInvocationSource { + readonly kind: 'skill-invocation'; + /** Invoked skill name, validated user-invocable at the injecting boundary. */ + readonly name: string; + /** Injected skill bodies are instructions for the model to follow. */ + readonly form: 'instructions'; +} +declare module '@deepseek-ai/dsh-llm' { + interface MessageSourceMap { + /** A user-explicit skill invocation injected by the host. */ + 'skill-invocation': SkillInvocationSource; + } +} +/** + * Render one loaded skill for the model. The output is shared verbatim by the + * `skill` tool result and the user-explicit invocation injection, so the model + * sees one canonical `` shape on both paths. The name rides an + * escaped attribute; the body is embedded verbatim (skills are trusted local + * content, and user-supplied invocation text stays outside this wrapper). + * @param skill - name, provider, optional resource base, and body to render. + * @returns the complete model-facing `` block. + */ +export declare function renderSkillContent(skill: Pick): string; +/** + * Escape model-facing prose embedded inside skill markup so provider-supplied + * text cannot open or close framing tags. + * @param value - raw prose to embed. + * @returns the escaped text. + */ +export declare function escapeText(value: string): string; +/** One catalog observation plus whether discovery completed within a stable catalog revision. */ +export interface SkillCatalogSnapshot { + /** Sorted invocation-neutral summaries collected in this observation. */ + readonly skills: SkillSummary[]; + /** Whether every registered provider completed without a concurrent catalog revision. */ + readonly complete: boolean; +} +/** Provider candidates plus whether the current discovery is authoritative. */ +export interface SkillProviderObservation { + /** Candidates available from the current provider discovery. */ + readonly candidates: readonly SkillCandidate[]; + /** Whether discovery completed and these candidates may be cached. */ + readonly complete: boolean; +} +/** Provider interface for one source of skills, such as local directories or a remote registry. */ +export interface SkillProvider { + /** Unique provider name in the `ctx.skills` registry. */ + readonly name: string; + /** + * List available skill candidates for the current lookup context. Provider + * plugins register synchronously during `apply()`; remote initialization, + * authentication, and discovery are awaited inside this method. Implementations + * should settle promptly when `options.signal` aborts. + * @param options - lookup options; `cwd` selects workspace-sensitive skills and `signal` cancels work. + * @returns provider candidates as a complete-array shorthand, or an explicit + * observation when usable candidates came from incomplete discovery. + */ + readonly list: (options: SkillLookupOptions) => Promise; + /** + * Load a complete skill body for a previously listed candidate. + * @param candidate - the winning candidate originally returned by this provider. + * @param options - lookup options; `cwd` selects workspace-sensitive skills and `signal` cancels work. + * @returns the full skill body, or `undefined` if it is no longer loadable. + */ + readonly get: (candidate: SkillCandidate, options: SkillLookupOptions) => Promise; +} +/** Registration-scoped lifecycle and invalidation capability borrowed by one provider. */ +export interface SkillProviderControl { + /** Aborts if registration fails or when the exact provider registration is disposed. */ + readonly signal: AbortSignal; + /** Invalidate completed catalogs and notify consumers only while the exact registration remains active. */ + readonly invalidate: () => void; +} +/** Skill registry configuration. */ +export interface Config { + /** Maximum number of completed cwd/provider catalogs kept in memory. */ + readonly collectCacheMaxEntries?: number; +} +declare module '@deepseek-ai/cordis' { + interface Context { + skills: SkillRegistry; + } + interface Events { + /** + * A skill provider, runtime contribution, or provider-backed catalog may + * have changed. This is an unfiltered invalidation notification; consumers + * refetch the catalog for their own lookup options. Listener failures are + * contained and cannot veto the registry mutation. + * @mode emit + */ + 'skills/change'(): void; + } +} +/** + * Layered registry of skill providers, the host+per-scope shape the tools + * registry established. A registration files into the layer of its calling + * context's scope ({@link scopeOf}): host rows and repository plugins land in + * the global layer, while a plugin mounted by an agent preset's standing + * composition lands in that preset's layer. A read merges the global layer + * with the viewing scope's chain — the nearest layer's entry wins a duplicate + * name outright, and the rank order decides duplicates only within one layer. + * It exposes sorted invocation-neutral summaries and loads full skill bodies + * on demand. + */ +export declare class SkillRegistry extends Service { + static Config: Schema; + private readonly collectCacheMaxEntries; + private readonly layers; + private readonly collectCache; + private revision; + private nextProviderOrder; + /** Stable identities for cache keys; scope keys are opaque identity-compared objects. */ + private readonly scopeIds; + private nextScopeId; + constructor(ctx: Context, config?: Config); + /** + * Register a borrowed same-process provider synchronously during plugin + * apply, into the calling context's layer: a scoped context (an agent + * preset's standing mount) registers for that scope alone, an unscoped + * context registers globally. Duplicate names within one layer and reserved + * names throw; remote initialization belongs in `list()`. Fiber disposal + * unregisters the provider and invalidates catalog caches. + * @param create - synchronous factory receiving this registration's lifecycle and invalidation control. + * @returns the exact Cordis effect disposer that unregisters this provider; + * composite effects may yield it directly to preserve teardown ordering. + */ + registerProvider(create: (control: SkillProviderControl) => SkillProvider): () => void; + /** + * Register a borrowed readonly runtime skill into the calling context's + * layer. Project entries outrank runtime entries, which outrank user + * entries, within one layer. Same-name runtime entries in one layer are + * first-wins; a duplicate logs a warning and receives a no-op disposer so + * it cannot remove the winner. + * @param skill - the skill definition input; omitted invocation and provider fields receive defaults. + * @returns the exact Cordis effect disposer, preserving composite teardown order and invalidating caches. + */ + register(skill: SkillRegistration): () => void; + /** + * List invocation-neutral skill summaries for a workspace. Consumers apply + * model or user invocation policy at their operational boundary. Lookup + * options and provider candidates are readonly same-process values borrowed + * throughout discovery. + * @param options - view options; `scope` selects the viewing agent's layers, `cwd` selects project roots, and `signal` cancels discovery. + * @returns all sorted winning summaries. + */ + list(options?: SkillViewOptions): Promise; + /** + * Observe the current invocation-neutral catalog and whether discovery completed within a stable revision. + * Incomplete observations are never cached, allowing consumers to retain last-good state and + * retry on their next request boundary. + * @param options - view options; `scope` selects the viewing agent's layers, `cwd` selects project roots, and `signal` cancels discovery. + * @returns sorted summaries plus discovery-completeness state. + */ + snapshot(options?: SkillViewOptions): Promise; + /** + * Load and validate the winning candidate, passing its opaque discovery locator back to the + * provider. Cancellation is rechecked after selection, including cache hits, and raced against + * loading so an uncooperative provider cannot hang the caller. + * @param name - kebab-case skill name. + * @param options - view options; `scope` selects the viewing agent's layers, + * `cwd` selects workspace-sensitive skills, and `signal` cancels work. + * @returns the full skill, including body content, or `undefined`. + */ + get(name: string, options?: SkillViewOptions): Promise; + private collect; + private collectFresh; + private collectLayer; + private listLayerCandidates; + private invalidateCache; + /** Invalidate after a stale definition load, only while the exact registration that produced the entry is still live. */ + private invalidateEntry; + private scopeId; + private collectCacheKey; + /** Notify catalog observers without making their refresh work load-bearing. */ + private notifyChange; +} +export default SkillRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/types/invariant.d.ts new file mode 100644 index 0000000..4289011 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-skill`. + * @module @deepseek-ai/dsh-skill/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "skill-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/package.json new file mode 100644 index 0000000..ca761c5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/dsh-skill/package.json @@ -0,0 +1,49 @@ +{ + "name": "@deepseek-ai/dsh-skill", + "description": "Agent skill provider registry for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/skill/skill" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_4052638b0b26c5a8ff62b742c3e8a235/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.i18n.yaml new file mode 100644 index 0000000..d4b2895 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/skill/skill/README.md +README.md: ae8812aeb3cc6583677d22bd5c35639318d15237 +README.zh.md: 5eae1d5aeb9eb87072d4b33c26f6c9a6e20cffdf diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.md new file mode 100644 index 0000000..ae8812a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.md @@ -0,0 +1,79 @@ +# @deepseek-ai/dsh-skill + +English | [中文](README.zh.md) + +Pure agent skill provider registry. + +This package owns the `ctx.skills` interface. It does not know whether skills come from local files, embedded plugin data, HTTP, or another backend; providers register those sources with `ctx.skills.registerProvider(...)`. The shipped local implementation is [`@deepseek-ai/dsh-skill-filesystem`](../skill-filesystem). + +The registry is host+per-scope layered over [`@deepseek-ai/dsh-scope`](../../core/scope), the shape the tools registry established: a registration files into the layer of its calling context's scope — host rows and repository plugins land in the global layer, a plugin mounted by an agent preset's standing composition lands in that preset's layer — and a read merges the global layer with the viewing scope's chain, the nearest layer winning a duplicate name outright while rank decides duplicates only within one layer. + +## Service: `SkillRegistry` (ctx key: `skills`) + +### Public API + +- `ctx.skills.registerProvider(create): () => void` Calls a synchronous provider factory with `{ signal, invalidate }`, then registers its readonly result by `provider.name`, unique within the calling context's layer. Duplicate names in one layer throw, `runtime` is reserved, and failed registration aborts the signal. The exact Cordis disposer unregisters the provider, aborts the signal, and preserves ordered composite teardown. +- `ctx.skills.snapshot({ cwd?, signal?, scope? })` Returns the invocation-neutral `{ skills, complete }` observation for the viewing scope's merged layers. `complete` is false when any provider rejects or explicitly reports incomplete discovery, or when a second catalog revision races the bounded retry; candidates supplied by that observation remain in this result, which is never cached. +- `ctx.skills.list({ cwd?, signal?, scope? })` Borrows the readonly view options, then returns every winning summary for the current workspace, merged across the global layer and the viewing scope's chain and sorted by name. Consumers apply `isModelInvocable(skill)` or `isUserInvocable(skill)` at their own boundary. +- `ctx.skills.get(name, { cwd?, signal?, scope? })` Uses the same readonly options and winning candidate for discovery and loading, rechecks cancellation after discovery or a cache hit, races provider loading against the signal, validates the loaded definition, then returns it regardless of invocation policy. +- `ctx.skills.register(skill): () => void` Registers a readonly runtime embedded skill into the calling context's layer, adding the all-invocable policy and `provider: "runtime"` when omitted. Same-name runtime registrations in one layer are first-wins: a duplicate logs a warning and gets a no-op disposer. Successful registrations return the exact Cordis disposer for ordered composite teardown. + +### Events + +- `skills/change` is an unfiltered invalidation notification emitted after a provider or runtime contribution is registered or disposed and after an active provider's registration control invalidates. It carries no catalog or diff: each consumer refetches `snapshot()` with its own lookup options. Listener throws and rejected promises are logged and cannot veto the registry mutation or starve later listeners. + +### Config + +| Field | Default | Meaning | +|---|---|---| +| `collectCacheMaxEntries` | `128` | Maximum completed cwd/provider catalogs kept in memory. | + +### Invocation policy + +`SkillSummary.invocation` is a required typed policy object whose positive booleans `modelInvocable` and `userInvocable` describe the two surfaces independently. Providers return this resolved shape on every candidate and definition; only the `SkillRegistration` input may omit it, in which case `register()` supplies `{ modelInvocable: true, userInvocable: true }`. The registry keeps all four combinations so one discovery result can serve model-facing tools, human-facing commands, and trusted internal callers without conflating their catalogs. + +| Policy | Model | User | +|---|---|---| +| `{ modelInvocable: true, userInvocable: true }` | included | included | +| `{ modelInvocable: true, userInvocable: false }` | included | excluded | +| `{ modelInvocable: false, userInvocable: true }` | excluded | included | +| `{ modelInvocable: false, userInvocable: false }` | excluded | excluded | + +### Shared model-facing rendering + +`renderSkillContent(skill)` renders one loaded skill as the canonical `` block (escaped `name` attribute, resource hints, verbatim body). It is the single truth for both loading paths: `dsh-tool-skill` returns it as the `skill` tool result and injects it at the user-explicit gesture boundary, so the model sees one shape regardless of who initiated the load. `escapeText` is exported beside it for consumers embedding prose in the same markup frame. The package also declares the `skill-invocation` `MessageSource` kind ({ name, form: 'instructions' }) that user-explicit injection stamps on its messages — transcript consumers present the invocation from this metadata instead of re-parsing the body. + +`isModelInvocable(skill)` and `isUserInvocable(skill)` read the matching positive field directly. `ctx.skills.get()` remains the trusted, policy-neutral loading primitive, so every user- or model-facing consumer must enforce the predicate that matches its surface before exposing or loading a skill. + +## Provider Contract + +A provider factory runs synchronously and receives one registration-scoped control. `control.signal` aborts when registration fails or is disposed; `control.invalidate()` clears completed catalogs only while that exact registration remains active, so late callbacks cannot affect a replacement with the same name. Immutable providers may ignore the control. Remote setup, authentication, and discovery belong in the provider's awaited `list(options)` call. An array return is shorthand for complete discovery; a provider that collected usable candidates but could not establish an authoritative observation returns `{ candidates, complete: false }`. Provider objects, lookup options, candidates, and definitions are borrowed readonly rather than cloned or rebound. Providers should honor `options.signal`; the registry also stops awaiting uncooperative discovery or loading after cancellation. + +The registry validates candidates before caching and definitions before returning them. The winning provider receives the same candidate and opaque `locator` it returned from `list()`, allowing backend-specific file, URL, id, or version handles. Callers and providers must preserve the readonly contract. + +Contract violations fail fast. A rejected provider `list()` is treated as a transient source failure and omitted. An explicit incomplete observation still contributes its candidates for `list()` and `get()`, but makes the aggregate snapshot incomplete and uncacheable. A provider or runtime revision change discards an in-flight result and retries once. If the retry is also superseded, its candidates are returned incomplete and uncached so a continuously invalidating provider cannot monopolize the caller. Within one layer, duplicate names resolve by rank, provider registration order, then provider-local order; across layers the nearest scope's entry wins the name. Summaries are sorted by skill name. + +Definitions remain progressively loaded. `get()` asks the winning provider for the body on every call rather than caching it in this registry. If the returned definition has a different name from the selected candidate, the stale selection is rejected and the registry internally invalidates that exact provider so the next snapshot rediscovers its catalog. + +## Runtime Skills + +`ctx.skills.register(...)` is a convenience for embedded runtime skills. Runtime skills use rank `250`: project providers can override them, while they override the shipped local provider's custom and user roots. Runtime definitions and nested resource metadata are borrowed readonly; the service materializes one top-level definition to supply omitted invocation and provider defaults. Registration is first-wins within runtime contributions, so a duplicate contribution cannot remove the active one through its disposer. + +## Consumer boundary + +The registry does not render model guidance or register model-facing tools. [`@deepseek-ai/dsh-tool-skill`](../tool-skill) consumes `ctx.skills` to provide durable session catalogs and the `skill` tool, so providers remain independent of model-facing behavior. + +## Model Experience + +Indirectly, through `dsh-tool-skill`, which renders provider summaries into durable initial or replacement catalog messages and loaded instructions into retained tool results. + +#### KV Cache effect + +No direct prompt effect. The named consumer owns the durable initial catalog and append-only replacements after invalidation. + +## Known Limitations and Deferred Work + +- **Invalidation is provider-driven** — the registry has no TTL and cannot infer that an arbitrary remote source changed; each mutable provider must retain and call its registration-scoped `invalidate()` capability from its own observation mechanism. +- **Providers are queried sequentially** — one slow cooperative provider delays every provider registered after it; cancellation stops the caller's wait but cannot terminate work an uncooperative provider keeps running. +- **Incomplete observations are not retained** — rejected providers are omitted and explicitly supplied candidates remain available only to the current lookup; the registry owns neither a last-good catalog nor per-provider diagnostics. +- **Duplicate resolution is first-wins** — later lower-priority candidates within a layer are logged and hidden, and a nearer layer shadows a farther one silently; there is no API to inspect all shadowed definitions. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.zh.md new file mode 100644 index 0000000..5eae1d5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/README.zh.md @@ -0,0 +1,79 @@ +# @deepseek-ai/dsh-skill + +[English](README.md) | 中文 + +纯 agent skill(智能体技能)提供方注册表。 + +该包负责 `ctx.skills` 接口。它不知道 skill 来自本地文件、嵌入式插件数据、HTTP 还是其他后端;提供方通过 `ctx.skills.registerProvider(...)` 注册这些来源。已发布的本地实现是 [`@deepseek-ai/dsh-skill-filesystem`](../skill-filesystem)。 + +注册表基于 [`@deepseek-ai/dsh-scope`](../../core/scope) 采用宿主 + 按 scope 的分层结构,即工具注册表确立的形态:注册落入调用方上下文 scope 对应的层——宿主行与 repository 插件落入全局层,由 agent preset 常驻组合挂载的插件落入该 preset 的层——读取时将全局层与观察 scope 的链合并,最近层直接赢得重名,rank 只在单层内裁决重名。 + +## 服务:`SkillRegistry`(ctx 键:`skills`) + +### 公开 API + +- `ctx.skills.registerProvider(create): () => void` 调用同步提供方工厂并向其传入 `{ signal, invalidate }`,随后以在调用方上下文所在层内唯一的 `provider.name` 注册其只读结果。同层重复提供方名称会抛错,`runtime` 为保留名称;注册失败会中止信号。精确的 Cordis disposer 会注销提供方、中止信号,并保持有序组合拆卸。 +- `ctx.skills.snapshot({ cwd?, signal?, scope? })` 返回观察 scope 各层合并后、与调用策略无关的 `{ skills, complete }` 观测。任一提供方调用被拒绝或显式报告发现不完整,或有界重试期间又发生目录修订时,`complete` 为 false;该次观测提供的候选项仍保留在此结果中,但该结果绝不缓存。 +- `ctx.skills.list({ cwd?, signal?, scope? })` 借用只读视图选项,然后返回当前工作区中的全部胜出摘要;这些摘要在全局层与观察 scope 链之间合并,并按名称排序。消费方在自身边界调用 `isModelInvocable(skill)` 或 `isUserInvocable(skill)`。 +- `ctx.skills.get(name, { cwd?, signal?, scope? })` 在发现和加载中使用同一组只读选项和胜出候选项;在发现或缓存命中后重新检查取消,让提供方加载与信号竞速,验证已加载定义,然后无论调用策略如何都将其返回。 +- `ctx.skills.register(skill): () => void` 将只读运行时嵌入式 skill 注册进调用方上下文所在层,省略时添加允许模型和用户调用的策略以及 `provider: "runtime"`。同层同名运行时注册使用先到先得:重复项会记录警告,并获得无操作 disposer。成功注册会返回精确的 Cordis disposer,以供有序组合拆卸。 + +### 事件 + +- `skills/change` 是一条不带过滤条件的失效通知,在提供方或运行时贡献注册或释放后,以及活动提供方的注册控制触发失效后发出。它不携带目录或 diff;每个消费方都使用自身的查找选项重新获取 `snapshot()`。监听器抛错或 Promise 拒绝会被记录,既不能否决注册表变更,也不能阻止后续监听器执行。 + +### 配置 + +| 字段 | 默认值 | 含义 | +|---|---|---| +| `collectCacheMaxEntries` | `128` | 内存中保留的最大已完成 cwd/提供方目录数。 | + +### 调用策略 + +`SkillSummary.invocation` 是一个必填的类型化策略对象,其正向布尔字段 `modelInvocable` 和 `userInvocable` 分别描述两个接口。提供方会在每个候选项和定义中返回这一已解析形状;只有 `SkillRegistration` 输入可以省略它,此时 `register()` 会补入 `{ modelInvocable: true, userInvocable: true }`。注册表保留全部四种组合,使一次发现结果可以同时服务面向模型的工具、面向用户的命令和受信内部调用方,而不会混淆各自的目录。 + +| 策略 | 模型 | 用户 | +|---|---|---| +| `{ modelInvocable: true, userInvocable: true }` | 包含 | 包含 | +| `{ modelInvocable: true, userInvocable: false }` | 包含 | 排除 | +| `{ modelInvocable: false, userInvocable: true }` | 排除 | 包含 | +| `{ modelInvocable: false, userInvocable: false }` | 排除 | 排除 | + +### 共享的面向模型渲染 + +`renderSkillContent(skill)` 把一个已加载 skill 渲染为规范的 `` 块(转义后的 `name` 属性、资源提示、原样正文)。它是两条加载路径的唯一真源:`dsh-tool-skill` 将其作为 `skill` 工具结果返回,并在用户显式的手势边界将其注入,因此无论加载由谁发起,模型看到的都是同一种形态。`escapeText` 随之一并导出,供要在同一标记框架中嵌入文案的消费方使用。该包还声明 `skill-invocation` 这个 `MessageSource` kind({ name, form: 'instructions' }),用户显式注入会把它打在自己的消息上——transcript(文本记录)消费方依据这份元数据呈现该次调用,而不是重新解析正文。 + +`isModelInvocable(skill)` 和 `isUserInvocable(skill)` 分别直接读取对应的正向字段。`ctx.skills.get()` 仍是受信且与策略无关的加载原语,因此每个面向用户或模型的消费方都必须先执行与自身接口匹配的判定,再暴露或加载 skill。 + +## 提供方约定 + +提供方工厂同步运行,并接收一项注册作用域内的控制能力。注册失败或释放时,`control.signal` 会中止;仅当该精确注册仍处于活动状态时,`control.invalidate()` 才会清除已完成目录,因此延迟回调无法影响同名替代项。不可变提供方可以忽略该控制能力。远程设置、身份验证和发现应在提供方的 `list(options)` 调用中完成,该调用会被等待。返回数组是完整发现的简写形式;若提供方已收集到可用候选项,却无法建立权威观测,则返回 `{ candidates, complete: false }`。提供方对象、查找选项、候选项和定义都以只读方式借用,而不是克隆或重新绑定。提供方应遵守 `options.signal`;取消后,注册表也会停止等待不协作的发现或加载。 + +注册表在缓存前验证候选项,在返回前验证定义。胜出提供方会收到同一候选项和不透明 `locator`,两者都是它从 `list()` 返回的内容,从而支持后端专用文件、URL、id 或版本句柄。调用方和提供方必须保持只读约定。 + +违反约定时会快速失败。`list()` 返回的 Promise 被拒绝会被视为瞬时来源失败,并省略其结果。显式的不完整观测仍会为 `list()` 和 `get()` 提供其候选项,但会使聚合快照不完整且不可缓存。提供方或运行时修订发生变化时,会丢弃正在进行的结果并重试一次。如果这次重试也被后续修订取代,则返回其候选项,并将结果标为不完整且不予缓存,以免持续触发失效的提供方一直占用调用方。单层内重复名称依次按 rank、提供方注册顺序和提供方本地顺序解决冲突;跨层则由最近 scope 的条目赢得名称。摘要按 skill 名称排序。 + +定义仍采用渐进式加载。`get()` 每次调用都会向胜出提供方请求正文,而不是在此注册表中缓存正文。若返回定义的名称不同于所选候选项,系统会拒绝该陈旧选择,并由注册表在内部使该精确提供方失效,以便下一次快照重新发现其目录。 + +## 运行时 skill + +`ctx.skills.register(...)` 是嵌入式运行时 skill 的便利接口。运行时 skill 使用 rank `250`:项目提供方可覆盖它们,它们则覆盖已发布本地提供方的自定义根目录和用户根目录。运行时定义和嵌套资源元数据均以只读方式借用;服务只物化一个顶层定义,以补入省略的调用策略和 `provider` 默认值。运行时贡献内的注册使用先到先得,因此重复贡献无法通过其 disposer 移除当前生效的贡献。 + +## 消费方边界 + +注册表不渲染模型指引,也不注册面向模型的工具。[`@deepseek-ai/dsh-tool-skill`](../tool-skill) 消费 `ctx.skills` 以提供持久会话目录和 `skill` 工具,因此提供方仍与模型接口独立。 + +## 模型体验 + +通过 `dsh-tool-skill` 间接影响模型;该包将提供方摘要渲染到持久的初始目录或替换目录消息中,并将已加载指令渲染到已保留工具结果中。 + +#### KV Cache 影响 + +不直接影响提示词。指定的消费方负责持久初始目录,以及失效后的仅追加式目录替换。 + +## 已知限制与暂缓事项 + +- **失效由提供方驱动**:注册表没有 TTL,无法推断任意远程来源是否已发生变化;每个可变提供方都必须保留其注册作用域内的 `invalidate()` 能力,并由自身的观测机制调用它。 +- **提供方依次查询**:一个响应取消但速度缓慢的提供方会延迟之后注册的所有提供方;取消会停止调用方等待,但无法终止不响应取消的提供方持续运行的工作。 +- **不保留不完整观测**:被拒绝的提供方会被省略,显式提供的候选项也仅在当前查找中可用;注册表既不负责上一份可用目录,也不负责逐提供方诊断。 +- **重名项的裁决采用先到先得**:系统会记录并隐藏层内较晚出现的低优先级候选项,较近的层会静默遮蔽较远的层;不提供检查全部被遮蔽定义的 API。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/index.js new file mode 100644 index 0000000..8bc9885 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/index.js @@ -0,0 +1,565 @@ +import { Service } from "@deepseek-ai/cordis"; +import { assertNever } from "@deepseek-ai/dsh-llm"; +import { NamedEntries, ScopedLayers, scopeChainOf, scopeOf } from "@deepseek-ai/dsh-scope"; +import z from "@deepseek-ai/schemastery"; +//#region lib/types/index.js +/** +* Agent skill provider registry. +* +* This package owns the Service Definition role of the skill capability seam. +* Concrete +* providers such as `@deepseek-ai/dsh-skill-filesystem` decide where skills come +* from; this service only merges provider catalogs, resolves the winning skill +* for a name, and exposes the winning summaries and definitions to consumers. +* +* @module @deepseek-ai/dsh-skill +*/ +const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/; +const DEFAULT_COLLECT_CACHE_ENTRIES = 128; +const MAX_COLLECT_ATTEMPTS = 2; +const RUNTIME_PROVIDER = "runtime"; +const RUNTIME_RANK = 250; +/** Standard precedence rank for packaged skill providers and local bundled roots. */ +const BUNDLED_SKILL_RANK = 600; +/** +* Return whether a string is a valid kebab-case skill name. +* @param name - candidate skill name to validate. +* @returns whether the name matches the public skill-name grammar. +*/ +function isSkillName(name) { + return SKILL_NAME.test(name); +} +/** +* Return whether a skill may be advertised to and loaded by a model. +* @param skill - skill metadata carrying resolved invocation controls. +* @returns whether the policy permits model invocation. +*/ +function isModelInvocable(skill) { + return skill.invocation.modelInvocable; +} +/** +* Return whether a skill may be advertised to and loaded by a human-facing command. +* @param skill - skill metadata carrying resolved invocation controls. +* @returns whether the policy permits user invocation. +*/ +function isUserInvocable(skill) { + return skill.invocation.userInvocable; +} +/** +* Render one loaded skill for the model. The output is shared verbatim by the +* `skill` tool result and the user-explicit invocation injection, so the model +* sees one canonical `` shape on both paths. The name rides an +* escaped attribute; the body is embedded verbatim (skills are trusted local +* content, and user-supplied invocation text stays outside this wrapper). +* @param skill - name, provider, optional resource base, and body to render. +* @returns the complete model-facing `` block. +*/ +function renderSkillContent(skill) { + const resourceHint = renderResourceHint(skill); + return [ + ``, + "", + ...resourceHint, + "", + "", + "", + skill.content, + "", + "" + ].join("\n"); +} +function renderResourceHint(skill) { + const base = skill.resourceBase; + if (base === void 0) return [`Resources for this skill are managed by provider "${escapeText(skill.provider)}".`, "Load referenced resources only as needed."]; + switch (base.kind) { + case "directory": return [`Base directory for this skill: ${escapeText(base.path)}`, "Resolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed."]; + case "url": return [`Base URL for this skill: ${escapeText(base.url)}`, "Resolve relative URLs mentioned by this skill against the base URL before using them. Load referenced resources only as needed."]; + case "opaque": return [`Resources for this skill: ${escapeText(base.description)}`, "Load referenced resources only as needed."]; + /* v8 ignore start -- SkillResourceBase is a closed union; a future kind must fail compilation here. */ + default: return assertNever(base, "SkillResourceBase.kind"); + } +} +function escapeAttr(value) { + return value.replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<"); +} +/** +* Escape model-facing prose embedded inside skill markup so provider-supplied +* text cannot open or close framing tags. +* @param value - raw prose to embed. +* @returns the escaped text. +*/ +function escapeText(value) { + return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); +} +/** One scope's complete skill-registry contribution. */ +var SkillLayer = class { + /** Providers registered through contexts carrying this scope, insertion-ordered. */ + providers; + /** Runtime skills registered through contexts carrying this scope. */ + runtime = /* @__PURE__ */ new Map(); + constructor(scope) { + this.providers = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `a skill provider named "${name}" is already registered` : `a skill provider named "${name}" is already registered in this scope`)); + } + /** Whether every contribution table in this aggregate layer is empty. */ + isEmpty() { + return this.providers.isEmpty() && this.runtime.size === 0; + } +}; +/** +* Layered registry of skill providers, the host+per-scope shape the tools +* registry established. A registration files into the layer of its calling +* context's scope ({@link scopeOf}): host rows and repository plugins land in +* the global layer, while a plugin mounted by an agent preset's standing +* composition lands in that preset's layer. A read merges the global layer +* with the viewing scope's chain — the nearest layer's entry wins a duplicate +* name outright, and the rank order decides duplicates only within one layer. +* It exposes sorted invocation-neutral summaries and loads full skill bodies +* on demand. +*/ +var SkillRegistry = class extends Service { + static Config = z.object({ collectCacheMaxEntries: z.number().default(DEFAULT_COLLECT_CACHE_ENTRIES) }); + collectCacheMaxEntries; + layers = new ScopedLayers((scope) => new SkillLayer(scope), () => { + this.invalidateCache(); + }); + collectCache = /* @__PURE__ */ new Map(); + revision = 0; + nextProviderOrder = 0; + /** Stable identities for cache keys; scope keys are opaque identity-compared objects. */ + scopeIds = /* @__PURE__ */ new WeakMap(); + nextScopeId = 1; + constructor(ctx, config = {}) { + super(ctx, "skills"); + this.collectCacheMaxEntries = config.collectCacheMaxEntries ?? DEFAULT_COLLECT_CACHE_ENTRIES; + assertPositiveInteger("collectCacheMaxEntries", this.collectCacheMaxEntries); + } + /** + * Register a borrowed same-process provider synchronously during plugin + * apply, into the calling context's layer: a scoped context (an agent + * preset's standing mount) registers for that scope alone, an unscoped + * context registers globally. Duplicate names within one layer and reserved + * names throw; remote initialization belongs in `list()`. Fiber disposal + * unregisters the provider and invalidates catalog caches. + * @param create - synchronous factory receiving this registration's lifecycle and invalidation control. + * @returns the exact Cordis effect disposer that unregisters this provider; + * composite effects may yield it directly to preserve teardown ordering. + */ + registerProvider(create) { + const lifecycle = new AbortController(); + let registration; + let provider; + const control = { + signal: lifecycle.signal, + invalidate: () => { + const active = registration; + if (active !== void 0 && active.layer.providers.get(active.name)?.provider === provider) this.invalidateCache(); + } + }; + try { + provider = create(control); + const name = provider.name; + if (name === RUNTIME_PROVIDER) throw new Error(`"${RUNTIME_PROVIDER}" is reserved for runtime skill registrations`); + const order = this.nextProviderOrder; + this.nextProviderOrder += 1; + return this.layers.effect(this.ctx, (layer) => { + const undo = layer.providers.insert(name, { + provider, + order + }); + registration = { + layer, + name + }; + return () => { + registration = void 0; + undo(); + lifecycle.abort(/* @__PURE__ */ new Error(`skill provider "${name}" disposed`)); + }; + }, { label: "skills.registerProvider()" }); + } catch (error) { + lifecycle.abort(error); + throw error; + } + } + /** + * Register a borrowed readonly runtime skill into the calling context's + * layer. Project entries outrank runtime entries, which outrank user + * entries, within one layer. Same-name runtime entries in one layer are + * first-wins; a duplicate logs a warning and receives a no-op disposer so + * it cannot remove the winner. + * @param skill - the skill definition input; omitted invocation and provider fields receive defaults. + * @returns the exact Cordis effect disposer, preserving composite teardown order and invalidating caches. + */ + register(skill) { + validateRuntimeSkill(skill); + const scope = scopeOf(this.ctx); + const existingLayer = scope === void 0 ? this.layers.global : this.layers.peek(scope); + if (existingLayer !== void 0 && existingLayer.runtime.has(skill.name)) { + this.ctx.logger.warn(`runtime skill "${skill.name}" ignored because it is already registered`); + return () => {}; + } + const definition = { + ...skill, + invocation: skill.invocation ?? { + modelInvocable: true, + userInvocable: true + }, + provider: skill.provider ?? RUNTIME_PROVIDER + }; + return this.layers.effect(this.ctx, (layer) => { + layer.runtime.set(definition.name, definition); + return () => { + layer.runtime.delete(definition.name); + }; + }, { label: "skills.register()" }); + } + /** + * List invocation-neutral skill summaries for a workspace. Consumers apply + * model or user invocation policy at their operational boundary. Lookup + * options and provider candidates are readonly same-process values borrowed + * throughout discovery. + * @param options - view options; `scope` selects the viewing agent's layers, `cwd` selects project roots, and `signal` cancels discovery. + * @returns all sorted winning summaries. + */ + async list(options = {}) { + return (await this.snapshot(options)).skills; + } + /** + * Observe the current invocation-neutral catalog and whether discovery completed within a stable revision. + * Incomplete observations are never cached, allowing consumers to retain last-good state and + * retry on their next request boundary. + * @param options - view options; `scope` selects the viewing agent's layers, `cwd` selects project roots, and `signal` cancels discovery. + * @returns sorted summaries plus discovery-completeness state. + */ + async snapshot(options = {}) { + const collected = await this.collect(options); + return { + skills: [...collected.entries.values()].map((entry) => toSummary(entry.candidate)).sort(compareSkillSummary), + complete: collected.cacheable + }; + } + /** + * Load and validate the winning candidate, passing its opaque discovery locator back to the + * provider. Cancellation is rechecked after selection, including cache hits, and raced against + * loading so an uncooperative provider cannot hang the caller. + * @param name - kebab-case skill name. + * @param options - view options; `scope` selects the viewing agent's layers, + * `cwd` selects workspace-sensitive skills, and `signal` cancels work. + * @returns the full skill, including body content, or `undefined`. + */ + async get(name, options = {}) { + if (!isSkillName(name)) return void 0; + const collected = await this.collect(options); + throwIfAborted(options.signal); + const match = collected.entries.get(name); + if (match === void 0) return void 0; + const definition = await waitWithAbort(match.provider.get(match.candidate, options), options.signal); + if (definition === void 0) return void 0; + validateDefinition(definition); + if (definition.name !== match.candidate.name) { + this.invalidateEntry(match); + return; + } + return definition; + } + async collect(options) { + throwIfAborted(options.signal); + let attempt = 1; + while (true) { + const revision = this.revision; + const key = this.collectCacheKey(options.cwd, scopeChainOf(options.scope), revision); + const cached = this.collectCache.get(key); + if (cached !== void 0) return { + entries: cached, + cacheable: true + }; + const result = await this.collectFresh(options); + throwIfAborted(options.signal); + if (revision !== this.revision) { + if (attempt < MAX_COLLECT_ATTEMPTS) { + attempt += 1; + continue; + } + return { + entries: result.entries, + cacheable: false + }; + } + if (result.cacheable) { + this.collectCache.set(key, result.entries); + if (this.collectCache.size > this.collectCacheMaxEntries) { + const oldest = this.collectCache.keys().next(); + this.collectCache.delete(oldest.value); + } + } + return result; + } + } + async collectFresh(options) { + const layers = [this.layers.global, ...this.layers.chainLayers(options.scope)]; + const merged = /* @__PURE__ */ new Map(); + let cacheable = true; + for (const layer of layers) { + const collected = await this.collectLayer(layer, options); + if (!collected.cacheable) cacheable = false; + for (const entry of collected.entries) merged.set(entry.candidate.name, entry); + } + return { + entries: merged, + cacheable + }; + } + async collectLayer(layer, options) { + const collected = await this.listLayerCandidates(layer, options); + collected.entries.sort(compareIndexedCandidates); + const seen = /* @__PURE__ */ new Set(); + const result = []; + for (const entry of collected.entries) { + const skill = entry.candidate; + if (seen.has(skill.name)) { + this.ctx.logger.warn(`skill "${skill.name}" from ${skill.source} ignored because a higher-priority skill already exists`); + continue; + } + seen.add(skill.name); + result.push(entry); + } + return { + entries: result, + cacheable: collected.cacheable + }; + } + async listLayerCandidates(layer, options) { + throwIfAborted(options.signal); + const candidates = []; + let cacheable = true; + let runtimeOrder = 0; + for (const skill of [...layer.runtime.values()].sort((a, b) => compareCodePoints(a.name, b.name))) { + candidates.push({ + candidate: runtimeCandidate(skill), + provider: RUNTIME_SKILL_PROVIDER, + providerOrder: -1, + localOrder: runtimeOrder, + layer + }); + runtimeOrder += 1; + } + for (const { provider, order } of [...layer.providers.values()]) { + let localOrder = 0; + let output; + try { + output = await waitWithAbort(provider.list(options), options.signal); + } catch (error) { + if (options.signal?.aborted === true) throw toError(options.signal.reason); + cacheable = false; + this.ctx.logger.warn(`skill provider "${provider.name}" skipped: ${errorMessage(error)}`); + } + if (output === void 0) continue; + const observation = normalizeProviderObservation(output, provider.name); + if (!observation.complete) cacheable = false; + for (const candidate of observation.candidates) { + validateCandidate(candidate, provider.name); + candidates.push({ + candidate, + provider, + providerOrder: order, + localOrder, + layer + }); + localOrder += 1; + } + } + return { + entries: candidates, + cacheable + }; + } + invalidateCache() { + this.revision += 1; + this.collectCache.clear(); + this.notifyChange(); + } + /** Invalidate after a stale definition load, only while the exact registration that produced the entry is still live. */ + invalidateEntry(entry) { + /* v8 ignore else -- A definition load can outlive the exact provider registration it selected. */ + if (entry.layer.providers.get(entry.provider.name)?.provider === entry.provider) this.invalidateCache(); + } + scopeId(key) { + let id = this.scopeIds.get(key); + if (id === void 0) { + id = this.nextScopeId; + this.nextScopeId += 1; + this.scopeIds.set(key, id); + } + return id; + } + collectCacheKey(cwd, chain, revision) { + return JSON.stringify({ + cwd, + scopes: chain.map((key) => this.scopeId(key)), + revision + }); + } + /** Notify catalog observers without making their refresh work load-bearing. */ + notifyChange() { + for (const callback of this.ctx.events.dispatch("emit", ["skills/change"])) try { + const returned = callback(); + Promise.resolve(returned).catch((error) => { + this.ctx.logger.warn(`skills/change listener rejected: ${errorMessage(error)}`); + }); + } catch (error) { + this.ctx.logger.warn(`skills/change listener threw: ${errorMessage(error)}`); + } + } +}; +function normalizeProviderObservation(output, providerName) { + if (Array.isArray(output)) return { + candidates: output, + complete: true + }; + if (output === null || typeof output !== "object") throw invalidProviderObservation(providerName); + const observation = output; + if (!Array.isArray(observation.candidates) || typeof observation.complete !== "boolean") throw invalidProviderObservation(providerName); + return observation; +} +function invalidProviderObservation(providerName) { + return /* @__PURE__ */ new TypeError(`skill provider "${providerName}" list() must return an array or { candidates, complete } observation`); +} +const RUNTIME_SKILL_PROVIDER = { + name: RUNTIME_PROVIDER, + /* v8 ignore next -- Runtime skills are injected directly by the registry; this provider only owns `get()`. */ + list() { + return Promise.resolve([]); + }, + get(candidate) { + return Promise.resolve(candidate.locator); + } +}; +function runtimeCandidate(skill) { + return { + name: skill.name, + description: skill.description, + ...skill.whenToUse !== void 0 ? { whenToUse: skill.whenToUse } : {}, + invocation: skill.invocation, + source: skill.source, + provider: skill.provider, + ...skill.resourceBase !== void 0 ? { resourceBase: skill.resourceBase } : {}, + rank: RUNTIME_RANK, + locator: skill, + ...skill.path !== void 0 ? { path: skill.path } : {}, + ...skill.metadata !== void 0 ? { metadata: skill.metadata } : {} + }; +} +function validateCandidate(candidate, providerName) { + if (typeof candidate.name !== "string") throw new TypeError(`skill provider "${providerName}" returned a non-string skill name`); + if (!SKILL_NAME.test(candidate.name)) throw new Error(`skill provider "${providerName}" returned invalid skill name "${candidate.name}"`); + if (typeof candidate.description !== "string") throw new TypeError(`skill provider "${providerName}" returned skill "${candidate.name}" with a non-string description`); + if (candidate.description.length === 0) throw new Error(`skill provider "${providerName}" returned skill "${candidate.name}" without a description`); + validateInvocation(candidate.invocation, `skill provider "${providerName}" returned skill "${candidate.name}"`); + if (candidate.whenToUse !== void 0 && typeof candidate.whenToUse !== "string") throw new TypeError(`skill provider "${providerName}" returned skill "${candidate.name}" with a non-string whenToUse`); + if (typeof candidate.source !== "string") throw new TypeError(`skill provider "${providerName}" returned skill "${candidate.name}" with a non-string source`); + if (typeof candidate.rank !== "number" || !Number.isFinite(candidate.rank)) throw new Error(`skill provider "${providerName}" returned skill "${candidate.name}" with an invalid rank`); + if (typeof candidate.provider !== "string") throw new TypeError(`skill provider "${providerName}" returned skill "${candidate.name}" with a non-string provider`); + if (candidate.provider !== providerName) throw new Error(`skill provider "${providerName}" returned skill "${candidate.name}" for provider "${candidate.provider}"`); + if (candidate.path !== void 0 && typeof candidate.path !== "string") throw new TypeError(`skill provider "${providerName}" returned skill "${candidate.name}" with a non-string path`); +} +function validateRuntimeSkill(skill) { + if (!SKILL_NAME.test(skill.name)) throw new Error(`invalid skill name "${skill.name}"`); + if (skill.description.length === 0) throw new Error(`skill "${skill.name}" requires a description`); + validateInvocation(skill.invocation, `runtime skill "${skill.name}"`); +} +/** Validate a definition loaded from a provider-controlled parser or remote source. */ +function validateDefinition(skill) { + const name = skill.name; + const description = skill.description; + const whenToUse = skill.whenToUse; + const invocation = skill.invocation; + const source = skill.source; + const provider = skill.provider; + const content = skill.content; + const path = skill.path; + if (typeof name !== "string") throw new TypeError("loaded skill name must be a string"); + if (!SKILL_NAME.test(name)) throw new Error(`loaded skill has invalid name "${name}"`); + if (typeof description !== "string") throw new TypeError(`loaded skill "${name}" description must be a string`); + if (description.length === 0) throw new Error(`loaded skill "${name}" requires a description`); + validateInvocation(invocation, `loaded skill "${name}"`); + if (whenToUse !== void 0 && typeof whenToUse !== "string") throw new TypeError(`loaded skill "${name}" whenToUse must be a string`); + if (typeof source !== "string") throw new TypeError(`loaded skill "${name}" source must be a string`); + if (typeof provider !== "string") throw new TypeError(`loaded skill "${name}" provider must be a string`); + if (typeof content !== "string") throw new TypeError(`loaded skill "${name}" content must be a string`); + if (path !== void 0 && typeof path !== "string") throw new TypeError(`loaded skill "${name}" path must be a string`); +} +function toSummary(skill) { + const { name, description, whenToUse, invocation, source, provider, resourceBase } = skill; + return { + name, + description, + ...whenToUse !== void 0 ? { whenToUse } : {}, + invocation, + source, + provider, + ...resourceBase !== void 0 ? { resourceBase } : {} + }; +} +function validateInvocation(invocation, subject) { + if (invocation === void 0) return; + if (typeof invocation !== "object" || invocation === null || Array.isArray(invocation)) throw new TypeError(`${subject} with a non-object invocation policy`); + const policy = invocation; + if (typeof policy.modelInvocable !== "boolean") throw new TypeError(`${subject} with a non-boolean invocation.modelInvocable`); + if (typeof policy.userInvocable !== "boolean") throw new TypeError(`${subject} with a non-boolean invocation.userInvocable`); +} +function compareSkillSummary(left, right) { + return compareCodePoints(left.name, right.name); +} +function compareCodePoints(left, right) { + if (left < right) return -1; + if (left > right) return 1; + return 0; +} +function compareIndexedCandidates(left, right) { + return left.candidate.rank - right.candidate.rank || left.providerOrder - right.providerOrder || left.localOrder - right.localOrder; +} +function assertPositiveInteger(name, value, minimum = 1) { + if (!Number.isInteger(value) || value < minimum) throw new Error(`skill: ${name} must be an integer greater than or equal to ${minimum}`); +} +function waitWithAbort(promise, signal) { + if (signal === void 0) return promise; + throwIfAborted(signal); + return new Promise((resolve, reject) => { + const cleanup = () => { + signal.removeEventListener("abort", onAbort); + }; + const onAbort = () => { + cleanup(); + reject(toError(signal.reason)); + }; + signal.addEventListener("abort", onAbort, { once: true }); + promise.then((value) => { + cleanup(); + resolve(value); + }, (error) => { + cleanup(); + reject(toError(error)); + }); + }); +} +/** Throw a total Error for an already-aborted lookup. */ +function throwIfAborted(signal) { + if (signal?.aborted === true) throw toError(signal.reason); +} +/** Normalize an arbitrary abort or provider failure without trusting coercion. */ +function toError(error) { + try { + if (error instanceof Error) return error; + } catch {} + return new Error(errorMessage(error)); +} +/** Render an arbitrary provider failure without letting coercion escape containment. */ +function errorMessage(error) { + try { + return String(error); + } catch { + return "[unrenderable thrown value]"; + } +} +//#endregion +export { BUNDLED_SKILL_RANK, SkillRegistry, SkillRegistry as default, escapeText, isModelInvocable, isSkillName, isUserInvocable, renderSkillContent }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/invariant.js new file mode 100644 index 0000000..7ac6e52 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-skill`. +* @module @deepseek-ai/dsh-skill/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-skill"; +/** Cordis companion plugin name. */ +const name = "skill-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: provider/runtime maps and revisioned caches mutate atomically inside the +* registry, which exposes no independent change event or snapshot for cross-checking them. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/types/index.d.ts new file mode 100644 index 0000000..46e1970 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/types/index.d.ts @@ -0,0 +1,300 @@ +/** + * Agent skill provider registry. + * + * This package owns the Service Definition role of the skill capability seam. + * Concrete + * providers such as `@deepseek-ai/dsh-skill-filesystem` decide where skills come + * from; this service only merges provider catalogs, resolves the winning skill + * for a name, and exposes the winning summaries and definitions to consumers. + * + * @module @deepseek-ai/dsh-skill + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { ScopeKey } from '@deepseek-ai/dsh-scope'; +import type Schema from '@deepseek-ai/schemastery'; +/** Standard precedence rank for packaged skill providers and local bundled roots. */ +export declare const BUNDLED_SKILL_RANK = 600; +/** + * Return whether a string is a valid kebab-case skill name. + * @param name - candidate skill name to validate. + * @returns whether the name matches the public skill-name grammar. + */ +export declare function isSkillName(name: string): boolean; +/** Origin bucket for a skill contribution. The value is prompt-visible metadata, not precedence by itself. */ +export type SkillSource = 'project-dsh' | 'project-agents' | 'runtime' | 'user-dsh' | 'user-agents' | 'custom' | 'bundled' | (string & {}); +/** Optional provider-specific base used by loaded skill bodies to resolve relative resources. */ +export type SkillResourceBase = { + readonly kind: 'directory'; + readonly path: string; +} | { + readonly kind: 'url'; + readonly url: string; +} | { + readonly kind: 'opaque'; + readonly description: string; +}; +/** Invocation controls shared by skill discovery consumers. */ +export interface SkillInvocationPolicy { + /** Whether model-facing catalogs and loaders include this skill. */ + readonly modelInvocable: boolean; + /** Whether human-facing command catalogs and loaders include this skill. */ + readonly userInvocable: boolean; +} +/** Invocation-neutral skill metadata returned by `ctx.skills.list()`. */ +export interface SkillSummary { + /** Kebab-case identifier used to address the skill. */ + readonly name: string; + /** Short routing description shown by discovery consumers. */ + readonly description: string; + /** Optional extra routing guidance. */ + readonly whenToUse?: string; + /** Resolved model and user invocation controls. */ + readonly invocation: SkillInvocationPolicy; + /** Discovery source that produced this winning skill. */ + readonly source: SkillSource; + /** Provider that owns this skill body. */ + readonly provider: string; + /** Provider-specific base for relative resources. */ + readonly resourceBase?: SkillResourceBase; +} +/** Provider catalog entry used by the registry to merge and later load skills. */ +export interface SkillCandidate extends SkillSummary { + /** Lower ranks win duplicate skill names before provider registration order is considered. */ + readonly rank: number; + /** Opaque provider-owned handle passed back to `provider.get()`. */ + readonly locator: unknown; + /** Absolute file path when the provider has one. */ + readonly path?: string; + /** Parsed optional metadata object from provider-specific skill frontmatter. */ + readonly metadata?: Readonly>; +} +/** Complete parsed skill definition, including the body loaded by `ctx.skills.get()`. */ +export interface SkillDefinition extends SkillSummary { + /** Markdown instruction body after any provider-specific metadata removal. */ + readonly content: string; + /** Absolute file path when the skill came from disk. */ + readonly path?: string; + /** Parsed optional metadata object from frontmatter. */ + readonly metadata?: Readonly>; +} +/** Runtime skill contribution accepted by `ctx.skills.register()`. */ +export type SkillRegistration = Omit & { + /** Invocation controls; omission permits both model and user surfaces. */ + readonly invocation?: SkillInvocationPolicy; + /** Provider label; omission uses the registry-owned runtime provider. */ + readonly provider?: string; +}; +/** Caller context used for cwd-sensitive and abortable provider work. */ +export interface SkillLookupOptions { + /** Workspace selector for the current lookup. */ + readonly cwd?: string | undefined; + /** Abort discovery or loading work for the current caller. */ + readonly signal?: AbortSignal | undefined; +} +/** + * Registry read options: provider lookup context plus the viewing scope. + * The registry consumes `scope` to select layers; providers receive the same + * borrowed options object and read only their {@link SkillLookupOptions} + * contract from it. + */ +export interface SkillViewOptions extends SkillLookupOptions { + /** Viewing scope (the calling agent); omitted reads the global layer alone. */ + readonly scope?: ScopeKey | undefined; +} +/** + * Return whether a skill may be advertised to and loaded by a model. + * @param skill - skill metadata carrying resolved invocation controls. + * @returns whether the policy permits model invocation. + */ +export declare function isModelInvocable(skill: Pick): boolean; +/** + * Return whether a skill may be advertised to and loaded by a human-facing command. + * @param skill - skill metadata carrying resolved invocation controls. + * @returns whether the policy permits user invocation. + */ +export declare function isUserInvocable(skill: Pick): boolean; +/** + * Durable source for the context message a user-explicit skill invocation + * injects: the user's own words ride a plain user message, and the rendered + * skill body follows as injected `instructions`-form context carrying this + * source, so transcript consumers present the injection from metadata + * instead of re-parsing the model-facing text. + */ +export interface SkillInvocationSource { + readonly kind: 'skill-invocation'; + /** Invoked skill name, validated user-invocable at the injecting boundary. */ + readonly name: string; + /** Injected skill bodies are instructions for the model to follow. */ + readonly form: 'instructions'; +} +declare module '@deepseek-ai/dsh-llm' { + interface MessageSourceMap { + /** A user-explicit skill invocation injected by the host. */ + 'skill-invocation': SkillInvocationSource; + } +} +/** + * Render one loaded skill for the model. The output is shared verbatim by the + * `skill` tool result and the user-explicit invocation injection, so the model + * sees one canonical `` shape on both paths. The name rides an + * escaped attribute; the body is embedded verbatim (skills are trusted local + * content, and user-supplied invocation text stays outside this wrapper). + * @param skill - name, provider, optional resource base, and body to render. + * @returns the complete model-facing `` block. + */ +export declare function renderSkillContent(skill: Pick): string; +/** + * Escape model-facing prose embedded inside skill markup so provider-supplied + * text cannot open or close framing tags. + * @param value - raw prose to embed. + * @returns the escaped text. + */ +export declare function escapeText(value: string): string; +/** One catalog observation plus whether discovery completed within a stable catalog revision. */ +export interface SkillCatalogSnapshot { + /** Sorted invocation-neutral summaries collected in this observation. */ + readonly skills: SkillSummary[]; + /** Whether every registered provider completed without a concurrent catalog revision. */ + readonly complete: boolean; +} +/** Provider candidates plus whether the current discovery is authoritative. */ +export interface SkillProviderObservation { + /** Candidates available from the current provider discovery. */ + readonly candidates: readonly SkillCandidate[]; + /** Whether discovery completed and these candidates may be cached. */ + readonly complete: boolean; +} +/** Provider interface for one source of skills, such as local directories or a remote registry. */ +export interface SkillProvider { + /** Unique provider name in the `ctx.skills` registry. */ + readonly name: string; + /** + * List available skill candidates for the current lookup context. Provider + * plugins register synchronously during `apply()`; remote initialization, + * authentication, and discovery are awaited inside this method. Implementations + * should settle promptly when `options.signal` aborts. + * @param options - lookup options; `cwd` selects workspace-sensitive skills and `signal` cancels work. + * @returns provider candidates as a complete-array shorthand, or an explicit + * observation when usable candidates came from incomplete discovery. + */ + readonly list: (options: SkillLookupOptions) => Promise; + /** + * Load a complete skill body for a previously listed candidate. + * @param candidate - the winning candidate originally returned by this provider. + * @param options - lookup options; `cwd` selects workspace-sensitive skills and `signal` cancels work. + * @returns the full skill body, or `undefined` if it is no longer loadable. + */ + readonly get: (candidate: SkillCandidate, options: SkillLookupOptions) => Promise; +} +/** Registration-scoped lifecycle and invalidation capability borrowed by one provider. */ +export interface SkillProviderControl { + /** Aborts if registration fails or when the exact provider registration is disposed. */ + readonly signal: AbortSignal; + /** Invalidate completed catalogs and notify consumers only while the exact registration remains active. */ + readonly invalidate: () => void; +} +/** Skill registry configuration. */ +export interface Config { + /** Maximum number of completed cwd/provider catalogs kept in memory. */ + readonly collectCacheMaxEntries?: number; +} +declare module '@deepseek-ai/cordis' { + interface Context { + skills: SkillRegistry; + } + interface Events { + /** + * A skill provider, runtime contribution, or provider-backed catalog may + * have changed. This is an unfiltered invalidation notification; consumers + * refetch the catalog for their own lookup options. Listener failures are + * contained and cannot veto the registry mutation. + * @mode emit + */ + 'skills/change'(): void; + } +} +/** + * Layered registry of skill providers, the host+per-scope shape the tools + * registry established. A registration files into the layer of its calling + * context's scope ({@link scopeOf}): host rows and repository plugins land in + * the global layer, while a plugin mounted by an agent preset's standing + * composition lands in that preset's layer. A read merges the global layer + * with the viewing scope's chain — the nearest layer's entry wins a duplicate + * name outright, and the rank order decides duplicates only within one layer. + * It exposes sorted invocation-neutral summaries and loads full skill bodies + * on demand. + */ +export declare class SkillRegistry extends Service { + static Config: Schema; + private readonly collectCacheMaxEntries; + private readonly layers; + private readonly collectCache; + private revision; + private nextProviderOrder; + /** Stable identities for cache keys; scope keys are opaque identity-compared objects. */ + private readonly scopeIds; + private nextScopeId; + constructor(ctx: Context, config?: Config); + /** + * Register a borrowed same-process provider synchronously during plugin + * apply, into the calling context's layer: a scoped context (an agent + * preset's standing mount) registers for that scope alone, an unscoped + * context registers globally. Duplicate names within one layer and reserved + * names throw; remote initialization belongs in `list()`. Fiber disposal + * unregisters the provider and invalidates catalog caches. + * @param create - synchronous factory receiving this registration's lifecycle and invalidation control. + * @returns the exact Cordis effect disposer that unregisters this provider; + * composite effects may yield it directly to preserve teardown ordering. + */ + registerProvider(create: (control: SkillProviderControl) => SkillProvider): () => void; + /** + * Register a borrowed readonly runtime skill into the calling context's + * layer. Project entries outrank runtime entries, which outrank user + * entries, within one layer. Same-name runtime entries in one layer are + * first-wins; a duplicate logs a warning and receives a no-op disposer so + * it cannot remove the winner. + * @param skill - the skill definition input; omitted invocation and provider fields receive defaults. + * @returns the exact Cordis effect disposer, preserving composite teardown order and invalidating caches. + */ + register(skill: SkillRegistration): () => void; + /** + * List invocation-neutral skill summaries for a workspace. Consumers apply + * model or user invocation policy at their operational boundary. Lookup + * options and provider candidates are readonly same-process values borrowed + * throughout discovery. + * @param options - view options; `scope` selects the viewing agent's layers, `cwd` selects project roots, and `signal` cancels discovery. + * @returns all sorted winning summaries. + */ + list(options?: SkillViewOptions): Promise; + /** + * Observe the current invocation-neutral catalog and whether discovery completed within a stable revision. + * Incomplete observations are never cached, allowing consumers to retain last-good state and + * retry on their next request boundary. + * @param options - view options; `scope` selects the viewing agent's layers, `cwd` selects project roots, and `signal` cancels discovery. + * @returns sorted summaries plus discovery-completeness state. + */ + snapshot(options?: SkillViewOptions): Promise; + /** + * Load and validate the winning candidate, passing its opaque discovery locator back to the + * provider. Cancellation is rechecked after selection, including cache hits, and raced against + * loading so an uncooperative provider cannot hang the caller. + * @param name - kebab-case skill name. + * @param options - view options; `scope` selects the viewing agent's layers, + * `cwd` selects workspace-sensitive skills, and `signal` cancels work. + * @returns the full skill, including body content, or `undefined`. + */ + get(name: string, options?: SkillViewOptions): Promise; + private collect; + private collectFresh; + private collectLayer; + private listLayerCandidates; + private invalidateCache; + /** Invalidate after a stale definition load, only while the exact registration that produced the entry is still live. */ + private invalidateEntry; + private scopeId; + private collectCacheKey; + /** Notify catalog observers without making their refresh work load-bearing. */ + private notifyChange; +} +export default SkillRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/types/invariant.d.ts new file mode 100644 index 0000000..4289011 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-skill`. + * @module @deepseek-ai/dsh-skill/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "skill-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/package.json new file mode 100644 index 0000000..2e03e28 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill/package.json @@ -0,0 +1,49 @@ +{ + "name": "@deepseek-ai/dsh-skill", + "description": "Agent skill provider registry for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/skill/skill" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage new file mode 120000 index 0000000..e659a28 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.i18n.yaml new file mode 100644 index 0000000..80ccac9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/storage/storage-domain/README.md +README.md: 7c058ab557cfb128f54c15e715685d59f6720696 +README.zh.md: 10eb33711e147bc5ac6b7770a196bfea4fe66306 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.md new file mode 100644 index 0000000..7c058ab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.md @@ -0,0 +1,35 @@ +# @deepseek-ai/dsh-storage-domain + +English | [中文](README.zh.md) + +Domain data form for the DeepSeek Harness storage hub: exposes the injectable `ctx.storageDomain` service and the matching `ctx.storage.domain` projection after every configured backend is registered. A domain is declared once with `defineDomain` (zod record schemas, `z.infer`-derived types), opened through `DomainFacility.open`, and served from authoritative in-memory state — reads are synchronous, writes serialize on one per-domain chain, reach durability on the routed backend first, then update memory and emit `domain/changed`. The opening consumer owns the handle's lifecycle and releases it with `Domain.close()` (idempotent; typically its own `ctx.effect` disposer); domains still open when the plugin unmounts are closed by the facility. + +Design rationale, open semantics, and the storage/domain layer split live in the [Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md). + +## Configuration + +| key | meaning | +| --- | --- | +| `backend` | Default backend name for every domain (required; no universally correct medium exists). | +| `routes` | Per-domain overrides: domain name → backend name. | + +## Model Experience + +### Durable domain state + +#### What the model sees + +Nothing. The package registers no tools, injects no prompts, and appends no session events; it stores non-session data (workspace records, future session sidecars) behind `ctx.storageDomain` and emits only the in-process `domain/changed` event, which reaches a model only if a Consumer package renders it through its own documented surface. + +#### Token effect + +Zero. No text from this package enters any model request. + +#### KV Cache effect + +Independent: domain reads and writes never touch request prefixes, so nothing here can invalidate provider cache reuse. + +## Known Limitations and Deferred Work + +- **Single-process change visibility** — `domain/changed` is an in-process event; a second host process or a reconnecting GUI observes no changes until the cross-process revision pattern deferred in the Agent Note lands. +- **No cross-table transactions, secondary indexes, or multi-segment keys** — each write touches one record; triggers and rework points for these extensions are tabled in the Agent Note's deferred-work list. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.zh.md new file mode 100644 index 0000000..10eb337 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/README.zh.md @@ -0,0 +1,35 @@ +# @deepseek-ai/dsh-storage-domain + +[English](README.md) | 中文 + +DeepSeek Harness 存储中心的领域数据形式:在所有已配置的后端注册后,公开可注入的 `ctx.storageDomain` 服务及对应的 `ctx.storage.domain` 投影。一个领域通过 `defineDomain`(zod 记录 schema、从 `z.infer` 派生的类型)声明一次,通过 `DomainFacility.open` 打开,并由具有最终决定权的内存状态提供服务:读取同步执行;写入在每个领域各自的一条链上串行化,先在已路由后端达到持久状态,再更新内存并发出 `domain/changed`。打开领域的消费方负责管理句柄的生命周期,并通过 `Domain.close()` 释放它(幂等;通常作为其自身的 `ctx.effect` 资源释放函数);插件卸载时,该设施会关闭仍处于打开状态的领域。 + +设计原理、打开语义和存储/领域分层见 [Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。 + +## 配置 + +| key | 含义 | +| --- | --- | +| `backend` | 每个领域的默认后端名称(必填;不存在普遍适用的存储介质)。 | +| `routes` | 逐领域覆盖:领域名称 → 后端名称。 | + +## 模型体验 + +### 持久领域状态 + +#### 模型看到的内容 + +无。该包不注册工具、不注入提示词,也不追加会话事件;它在 `ctx.storageDomain` 后面存储非会话数据(工作区记录、未来的会话伴随数据),只发出进程内 `domain/changed` 事件。只有 Consumer 包通过自身有文档说明的接口呈现该事件时,它才会到达模型。 + +#### Token 影响 + +为零。该包的文本不会进入任何模型请求。 + +#### KV Cache 影响 + +相互独立:领域读写绝不触碰请求前缀,因此这里没有任何内容能使提供方缓存复用失效。 + +## 已知限制与暂缓事项 + +- **变更只在单进程内可见**:`domain/changed` 是进程内事件;在 Agent Note 暂缓的跨进程修订模式落地前,第二个主机进程或重新连接的 GUI 无法观察变更。 +- **没有跨表事务、二级索引或多段键**:每次写入只触碰一条记录;这些扩展的触发点和返工点列在 Agent Note 的暂缓工作清单中。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js new file mode 100644 index 0000000..cb2f21a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js @@ -0,0 +1,430 @@ +import z from "@deepseek-ai/schemastery"; +import { UNIT_NAME_RE, storageBackendServiceKey } from "@deepseek-ai/dsh-storage"; +//#region lib/types/error.js +/** +* Error vocabulary of the domain data form. +* @module @deepseek-ai/dsh-storage-domain/src/error +*/ +/** +* Error thrown by the domain layer. The `code` is the stable contract +* consumers may switch on; `message` is diagnostic prose. Backend failures +* (`backend-not-found`, `version-mismatch`, …) pass through as +* `StorageError` — the domain layer does not rewrap them. +*/ +var DomainError = class extends Error { + code; + name = "DomainError"; + /** Present exactly when `code` is `invalid-record`. */ + detail; + /** + * @param code - Stable discriminant for the failure class. + * @param message - Human-readable diagnostic detail. + * @param options - Standard error options plus the `invalid-record` location. + */ + constructor(code, message, options) { + super(message, options); + this.code = code; + if (options?.detail) this.detail = options.detail; + } +}; +//#endregion +//#region lib/types/spec.js +/** +* Domain declaration vocabulary. A spec object is the single source of a +* domain's identity, layout, and record schemas: the owning package defines +* it once with {@link defineDomain} and both the type surface and the runtime +* (validation, descriptor projection) derive from it. Record schemas are zod +* (`z.infer` keeps types un-duplicated and the same schemas later project to +* RPC wire schemas); plugin `Config` stays schemastery. +* @module @deepseek-ai/dsh-storage-domain/src/spec +*/ +/** +* Declare one table. +* @param schema - zod schema validating every stored record of this table. +* @returns the table declaration, key-typed by `K`. +*/ +function domainTable(schema) { + return { valueSchema: schema }; +} +/** +* Identity helper that pins a spec's literal types and validates its fields. +* Misconfiguration fails loud at the owning package's module load, before any +* medium is touched: a domain or table name outside `UNIT_NAME_RE`, a version +* that is not a non-negative integer, or a global schema that accepts `null` +* all throw. The `null` rejection guards round-tripping: backends store the +* global as opaque JSON with `null` as the "never written" sentinel, so a +* nullable global would be indistinguishable from an absent one on reopen +* (a stored `null` silently reverts to `initial`). +* @param spec - The domain declaration. +* @returns the same spec, narrowed to its literal type. +*/ +function defineDomain(spec) { + if (!UNIT_NAME_RE.test(spec.name)) throw new Error(`domain name '${spec.name}' must match ${UNIT_NAME_RE}`); + if (!Number.isInteger(spec.version) || spec.version < 0) throw new Error(`domain '${spec.name}' version must be a non-negative integer, got ${spec.version}`); + for (const table of Object.keys(spec.tables)) if (!UNIT_NAME_RE.test(table)) throw new Error(`domain '${spec.name}' table name '${table}' must match ${UNIT_NAME_RE}`); + if (spec.global !== void 0 && spec.global.schema.safeParse(null).success) throw new Error(`domain '${spec.name}' global schema must not accept null: null is the medium's "never written" sentinel, so a stored null could not round-trip`); + return spec; +} +/** +* Project a spec onto the backend-facing unit descriptor. +* @param spec - The domain declaration. +* @returns the descriptor handed to `KvFacet.open`. +*/ +function descriptorOf(spec) { + return { + name: spec.name, + version: spec.version, + tables: Object.keys(spec.tables), + hasGlobal: spec.global !== void 0 + }; +} +//#endregion +//#region lib/types/domain.js +/** +* Runtime of one open domain: authoritative in-memory state, the single +* per-domain write chain, and change-event emission. Reads are synchronous +* from memory; every write queues on the chain, awaits backend durability +* FIRST, then mutates memory, then emits `domain/changed` — a rejected +* backend write leaves memory untouched (no divergence between reads and the +* medium), and events carry values that equal the in-memory state at +* emission, in write order. +* @module @deepseek-ai/dsh-storage-domain/src/domain +*/ +const noop = () => {}; +/** +* The single domain implementation behind the {@link Domain} interface. The +* facility constructs it from a validated `loadAll` snapshot and erases it to +* `Domain`; nothing outside this package constructs one. +*/ +var DomainImpl = class { + ctx; + unit; + onClosed; + /** Domain name from the spec. */ + name; + tables = /* @__PURE__ */ new Map(); + globalValue; + globalHandle; + /** Tail of the write chain; every link settles (rejections are observed by the caller's slice). */ + chain = Promise.resolve(); + /** Set when close begins: new writes reject while already-queued writes drain. */ + disposing = false; + /** Set when close finishes (chain drained, unit closed): reads reject from here on. */ + closed = false; + disposal; + /** + * @param ctx - Context that carries `domain/changed` emissions. + * @param spec - The domain declaration. + * @param unit - The opened backend unit; this instance owns its lifecycle. + * @param records - Validated records from the unit's `loadAll`, one entry + * per declared table (empty maps included) — the facility builds it from + * the spec, so the entry set IS the table set. + * @param globalValue - Validated stored global, or the spec's `initial` + * when the medium held none; `undefined` when the spec declares no global. + * @param onClosed - Facility hook run once after teardown completes; frees + * the domain name for a later open. + */ + constructor(ctx, spec, unit, records, globalValue, onClosed) { + this.ctx = ctx; + this.unit = unit; + this.onClosed = onClosed; + this.name = spec.name; + const host = { + domainName: spec.name, + unit, + enqueue: (job) => this.enqueue(job), + assertReadable: () => { + this.assertReadable(); + }, + emitChanged: (change) => { + this.emitChanged(change); + } + }; + for (const [table, tableRecords] of records) this.tables.set(table, new KvTableImpl(host, table, tableRecords)); + if (spec.global !== void 0) { + this.globalValue = globalValue; + this.globalHandle = { + get: () => { + this.assertReadable(); + return this.globalValue; + }, + set: (value) => this.enqueue(async () => { + await this.unit.setGlobal(value); + this.globalValue = value; + this.emitChanged({ + domain: this.name, + table: "", + key: "", + operation: "put", + value + }); + }) + }; + } + } + /** Global singleton handle; accessing it on a spec that declares no global is a caller bug and throws. */ + get global() { + if (this.globalHandle === void 0) throw new Error(`domain '${this.name}' declares no global`); + return this.globalHandle; + } + /** + * Resolve one declared table handle; an undeclared name is a caller bug + * and throws. + * @param name - Declared table name. + * @returns the stable table handle. + */ + table(name) { + const table = this.tables.get(name); + if (table === void 0) throw new Error(`domain '${this.name}' declares no table '${name}'`); + return table; + } + /** + * Close this domain: reject new writes immediately, drain already-queued + * writes (their events still emit), close the unit, then free the name via + * the facility hook. Idempotent — repeated calls share one teardown. + * @returns resolution after the unit is released. + */ + close() { + this.disposal ??= this.runClose(); + return this.disposal; + } + async runClose() { + this.disposing = true; + await this.chain; + await this.unit.close(); + this.closed = true; + this.onClosed(); + } + /** + * Dispatch one post-durability change notification, containing observer + * failures: the write is already committed (medium and memory both hold + * the new state), so a throwing listener must not retroactively reject it. + */ + emitChanged(change) { + try { + this.ctx.emit("domain/changed", change); + } catch (error) { + this.ctx.logger.warn(`domain '${this.name}': domain/changed listener failed: ${String(error)}`); + } + } + enqueue(job) { + if (this.disposing) return Promise.reject(new DomainError("closed", `domain '${this.name}' is closed`)); + const result = this.chain.then(job); + this.chain = result.then(noop, noop); + return result; + } + assertReadable() { + if (this.closed) throw new DomainError("closed", `domain '${this.name}' is closed`); + } +}; +/** Table handle bound to one in-memory record map and its domain's write chain. */ +var KvTableImpl = class { + host; + tableName; + records; + constructor(host, tableName, records) { + this.host = host; + this.tableName = tableName; + this.records = records; + } + get(key) { + this.host.assertReadable(); + return this.records.get(key); + } + entries() { + this.host.assertReadable(); + return [...this.records.entries()][Symbol.iterator](); + } + keys() { + this.host.assertReadable(); + return [...this.records.keys()][Symbol.iterator](); + } + get size() { + this.host.assertReadable(); + return this.records.size; + } + put(key, value) { + return this.host.enqueue(async () => { + await this.host.unit.putRecord(this.tableName, key, value); + this.records.set(key, value); + this.emitPut(key, value); + }); + } + delete(key) { + return this.host.enqueue(async () => { + if (!this.records.has(key)) return false; + await this.host.unit.deleteRecord(this.tableName, key); + this.records.delete(key); + this.host.emitChanged({ + domain: this.host.domainName, + table: this.tableName, + key, + operation: "deleted" + }); + return true; + }); + } + update(key, fn) { + return this.host.enqueue(async () => { + if (!this.records.has(key)) throw new DomainError("missing-key", `domain '${this.host.domainName}' table '${this.tableName}' has no record '${key}' to update`); + const next = fn(this.records.get(key)); + await this.host.unit.putRecord(this.tableName, key, next); + this.records.set(key, next); + this.emitPut(key, next); + return next; + }); + } + emitPut(key, value) { + this.host.emitChanged({ + domain: this.host.domainName, + table: this.tableName, + key, + operation: "put", + value + }); + } +}; +//#endregion +//#region lib/types/index.js +/** +* Domain data form (`ctx.storage.domain`): schema-validated, change-emitting +* KV domains over storage backends. The single implementation of the domain +* layer — consumers depend on this package and never touch backends directly. +* Plugin `Config` is schemastery; record schemas inside domain specs are zod +* (see `src/spec.ts` for the split rationale). +* @module @deepseek-ai/dsh-storage-domain +*/ +/** Cordis plugin name. */ +const name = "storage-domain"; +/** The storage hub must be present before the form can mount. */ +const inject = ["storage"]; +const Config = z.object({ + backend: z.string().required(), + routes: z.dict(z.string()).default({}) +}); +/** +* The mounted domain facility. Opens declared domains over routed backends; +* one facility instance owns the open-domain table and enforces single-open +* per domain name. +*/ +var DomainFacility = class { + ctx; + config; + domains = /* @__PURE__ */ new Map(); + /** Names reserved by an in-flight or completed open, so concurrent opens of one name fail loud. */ + reserved = /* @__PURE__ */ new Set(); + /** + * @param ctx - Context of the domain plugin; open-domain effects and change + * events attach here. + * @param config - Validated plugin config. + */ + constructor(ctx, config) { + this.ctx = ctx; + this.config = config; + } + /** + * Open one declared domain. Steps, each failing the whole call: reject a + * name that is already open (`already-open`); resolve the backend route + * (`backend-not-found` passes through from the hub); require its `kv` facet + * (`facet-unsupported`); open the unit projected from the spec (backend + * `version-mismatch`/`malformed-medium` pass through); load and validate + * every stored record against the spec's zod schemas (`invalid-record` + * with the offending table and key); construct the domain. + * + * Lifecycle: the CALLER owns the returned handle and closes it via + * `Domain.close()` (typically as its own `ctx.effect` disposer) — the + * facility does not tie the domain to any consumer fiber. Domains still + * open when the facility unmounts are closed by the plugin disposer. + * @param spec - The domain declaration, typically from `defineDomain`. + * @returns the opened domain handle, typed by the spec. + */ + async open(spec) { + if (this.reserved.has(spec.name)) throw new DomainError("already-open", `domain '${spec.name}' is already open`); + this.reserved.add(spec.name); + try { + const backendName = this.config.routes?.[spec.name] ?? this.config.backend; + const backend = this.ctx.storage.backend.get(backendName); + if (!backend.kv) throw new DomainError("facet-unsupported", `backend '${backendName}' routed for domain '${spec.name}' has no kv facet`); + const unit = await backend.kv.open(descriptorOf(spec)); + try { + const snapshot = await unit.loadAll(); + const tables = /* @__PURE__ */ new Map(); + for (const [table, tableSpec] of Object.entries(spec.tables)) { + const records = /* @__PURE__ */ new Map(); + for (const [key, raw] of Object.entries(snapshot.tables[table] ?? {})) records.set(key, parseRecord(spec.name, table, key, () => tableSpec.valueSchema.parse(raw))); + tables.set(table, records); + } + const globalSpec = spec.global; + const globalValue = globalSpec === void 0 ? void 0 : snapshot.global === null ? globalSpec.initial : parseRecord(spec.name, "", "", () => globalSpec.schema.parse(snapshot.global)); + const domain = new DomainImpl(this.ctx, spec, unit, tables, globalValue, () => { + this.domains.delete(spec.name); + this.reserved.delete(spec.name); + }); + this.domains.set(spec.name, domain); + return domain; + } catch (error) { + await unit.close(); + throw error; + } + } catch (error) { + this.reserved.delete(spec.name); + throw error; + } + } + /** + * Look up an open domain by name, untyped. Diagnostic surface (the package + * invariant cross-checks change events against live domain state); typed + * consumers hold the handle returned by {@link open}. + * @param name - Domain name. + * @returns the open domain runtime, or `undefined` when not open. + */ + get(name) { + return this.domains.get(name); + } + /** + * Close every domain still open on this facility. The unmount path for + * consumers that never called `Domain.close()` themselves; closing is + * idempotent, so double-closing an already-closed domain is harmless. + * @returns resolution after every unit is released. + */ + async closeAll() { + await Promise.all([...this.domains.values()].map((domain) => domain.close())); + } +}; +/** Run one zod parse, translating failure to `invalid-record` with its location. */ +function parseRecord(domain, table, key, parse) { + try { + return parse(); + } catch (error) { + throw new DomainError("invalid-record", `domain '${domain}': stored ${table === "" ? "global" : `record '${key}' in table '${table}'`} does not match its schema`, { + detail: { + table, + key + }, + cause: error + }); + } +} +/** +* Mount the domain data form on the storage hub. +* @param ctx - Plugin context. +* @param config - Validated plugin config. +* @returns resolution after an already-available backend set activates the form. +*/ +function apply(ctx, config) { + const backendServices = [...new Set([config.backend, ...Object.values(config.routes ?? {})])].map(storageBackendServiceKey); + const fiber = ctx.inject(backendServices, (domainCtx) => { + const facility = new DomainFacility(domainCtx, config); + domainCtx.effect(() => { + const unmount = domainCtx.storage.mount("domain", facility); + return async () => { + await facility.closeAll(); + unmount(); + }; + }); + domainCtx.provide("storageDomain", facility); + }); + return Promise.resolve(fiber).then(() => {}); +} +//#endregion +export { Config, DomainError, DomainFacility, apply, defineDomain, descriptorOf, domainTable, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/invariant.js new file mode 100644 index 0000000..b9e30ad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/invariant.js @@ -0,0 +1,45 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-storage-domain`: every +* `domain/changed` event must agree with the emitting domain's authoritative +* in-memory state (the owned event-stream ↔ mutable-data relationship of this +* package). Writes emit strictly after mutating memory and the write chain +* serializes them, so at emission time the event's snapshot equals the +* current read — any divergence means a write path skipped the chain or +* emitted a stale value. +* @module @deepseek-ai/dsh-storage-domain/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-storage-domain"; +/** Cordis companion plugin name. */ +const name = "storage-domain-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Install the change-event ↔ memory-state agreement check. */ +const install = Object.assign((ctx, fail) => { + ctx.on("domain/changed", (change) => { + const domain = ctx.storage.form("domain").get(change.domain); + if (domain === void 0) return fail(`domain/changed for '${change.domain}' emitted while that domain is not open`); + if (change.table === "") { + if (domain.global.get() !== change.value) return fail(`domain/changed global value for '${change.domain}' differs from the in-memory global`); + return; + } + const current = domain.table(change.table).get(change.key); + switch (change.operation) { + case "deleted": + if (current !== void 0) return fail(`domain/changed deletion of '${change.domain}'.'${change.table}'['${change.key}'] emitted while the record is still in memory`); + return; + case "put": + if (current !== change.value) return fail(`domain/changed value for '${change.domain}'.'${change.table}'['${change.key}'] differs from the in-memory record`); + return; + default: + } + }, { global: true }); +}, { inject: ["storage"] }); +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/domain.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/domain.d.ts new file mode 100644 index 0000000..e43ab81 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/domain.d.ts @@ -0,0 +1,166 @@ +/** + * Runtime of one open domain: authoritative in-memory state, the single + * per-domain write chain, and change-event emission. Reads are synchronous + * from memory; every write queues on the chain, awaits backend durability + * FIRST, then mutates memory, then emits `domain/changed` — a rejected + * backend write leaves memory untouched (no divergence between reads and the + * medium), and events carry values that equal the in-memory state at + * emission, in write order. + * @module @deepseek-ai/dsh-storage-domain/src/domain + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { KvUnit } from '@deepseek-ai/dsh-storage'; +import type { DomainSpec, DomainGlobalSpec, TableKeyOf, TableValueOf } from './spec.ts'; +/** Handle on a domain's global singleton. */ +export interface DomainGlobal { + /** + * Current value, synchronously from the authoritative in-memory state. + * Before the first `set` this is the spec's `initial`. + * @returns the current global value. + */ + get(): G; + /** + * Replace the value durably. Queued on the domain's write chain; the first + * `set` is what materializes the global on the medium. + * @param value - New value; must satisfy the spec's schema (not re-checked + * here — validation happens at the durable read boundary). + * @returns resolution after durability and event emission. + */ + set(value: G): Promise; +} +/** + * Handle on one declared table. Records are plain immutable data: returned + * values are the stored objects themselves (no defensive copies) and must not + * be mutated in place — replace via `put`/`update`. + */ +export interface KvTable { + /** + * Read one record, synchronously from memory. + * @param key - Record key. + * @returns the record, or `undefined` when absent. + */ + get(key: K): V | undefined; + /** + * Snapshot iterator over `[key, record]` pairs. A snapshot, not a live + * view: iteration stays stable while queued writes land. + * @returns the pair iterator. + */ + entries(): IterableIterator<[K, V]>; + /** + * Snapshot iterator over keys. + * @returns the key iterator. + */ + keys(): IterableIterator; + /** Current record count. */ + readonly size: number; + /** + * Insert or overwrite one record durably. + * @param key - Record key. + * @param value - The full new record (no partial merge). + * @returns resolution after durability and event emission. + */ + put(key: K, value: V): Promise; + /** + * Delete one record durably. + * @param key - Record key. + * @returns `true` when the record existed, `false` when it was already + * absent (no write and no event in that case). + */ + delete(key: K): Promise; + /** + * Atomic read-modify-write on the domain's write chain: `fn` sees the + * value current at its queue slot, so concurrent updates never interleave. + * @param key - Record key; a missing key rejects with `missing-key`. + * @param fn - Synchronous pure transform from current to next record. + * @returns the stored next record. + */ + update(key: K, fn: (current: V) => V): Promise; +} +/** Global handle of a spec: typed when declared, `never` (inaccessible) when not. */ +export type DomainGlobalHandleOf = S extends { + readonly global: DomainGlobalSpec; +} ? DomainGlobal : never; +/** One open domain, typed by its spec. */ +export interface Domain { + /** Domain name from the spec. */ + readonly name: string; + /** Global singleton handle; a spec without `global` has no usable handle (`never`). */ + readonly global: DomainGlobalHandleOf; + /** + * Resolve one declared table handle. Handles are stable — repeated calls + * return the same instance. + * @param name - Declared table name. + * @returns the typed table handle. + */ + table(name: N): KvTable, TableValueOf>; + /** + * Close this domain: reject new writes immediately, drain already-queued + * writes (their events still emit), release the backend unit, then free + * the domain name for a later open. Idempotent — repeated calls share one + * teardown. The consumer owns this call (typically as its own `ctx.effect` + * disposer); the facility closes any domain left open when it unmounts. + * @returns resolution after the unit is released. + */ + close(): Promise; +} +/** + * The single domain implementation behind the {@link Domain} interface. The + * facility constructs it from a validated `loadAll` snapshot and erases it to + * `Domain`; nothing outside this package constructs one. + */ +export declare class DomainImpl { + private readonly ctx; + private readonly unit; + private readonly onClosed; + /** Domain name from the spec. */ + readonly name: string; + private readonly tables; + private globalValue; + private readonly globalHandle?; + /** Tail of the write chain; every link settles (rejections are observed by the caller's slice). */ + private chain; + /** Set when close begins: new writes reject while already-queued writes drain. */ + private disposing; + /** Set when close finishes (chain drained, unit closed): reads reject from here on. */ + private closed; + private disposal?; + /** + * @param ctx - Context that carries `domain/changed` emissions. + * @param spec - The domain declaration. + * @param unit - The opened backend unit; this instance owns its lifecycle. + * @param records - Validated records from the unit's `loadAll`, one entry + * per declared table (empty maps included) — the facility builds it from + * the spec, so the entry set IS the table set. + * @param globalValue - Validated stored global, or the spec's `initial` + * when the medium held none; `undefined` when the spec declares no global. + * @param onClosed - Facility hook run once after teardown completes; frees + * the domain name for a later open. + */ + constructor(ctx: Context, spec: DomainSpec, unit: KvUnit, records: Map>, globalValue: unknown, onClosed: () => void); + /** Global singleton handle; accessing it on a spec that declares no global is a caller bug and throws. */ + get global(): DomainGlobal; + /** + * Resolve one declared table handle; an undeclared name is a caller bug + * and throws. + * @param name - Declared table name. + * @returns the stable table handle. + */ + table(name: string): KvTable; + /** + * Close this domain: reject new writes immediately, drain already-queued + * writes (their events still emit), close the unit, then free the name via + * the facility hook. Idempotent — repeated calls share one teardown. + * @returns resolution after the unit is released. + */ + close(): Promise; + private runClose; + /** + * Dispatch one post-durability change notification, containing observer + * failures: the write is already committed (medium and memory both hold + * the new state), so a throwing listener must not retroactively reject it. + */ + private emitChanged; + private enqueue; + private assertReadable; +} +//# sourceMappingURL=domain.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/error.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/error.d.ts new file mode 100644 index 0000000..546d3a3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/error.d.ts @@ -0,0 +1,37 @@ +/** + * Error vocabulary of the domain data form. + * @module @deepseek-ai/dsh-storage-domain/src/error + */ +/** Discriminant codes carried by every {@link DomainError}. */ +export type DomainErrorCode = 'already-open' | 'facet-unsupported' | 'invalid-record' | 'missing-key' | 'closed'; +/** Location of the record that failed schema validation at the durable boundary. */ +export interface InvalidRecordDetail { + /** Table holding the rejected record; `''` for the global singleton. */ + readonly table: string; + /** Key of the rejected record; `''` for the global singleton. */ + readonly key: string; +} +/** Construction options: standard `cause` plus the `invalid-record` location. */ +export interface DomainErrorOptions extends ErrorOptions { + /** Present exactly when `code` is `invalid-record`. */ + readonly detail?: InvalidRecordDetail; +} +/** + * Error thrown by the domain layer. The `code` is the stable contract + * consumers may switch on; `message` is diagnostic prose. Backend failures + * (`backend-not-found`, `version-mismatch`, …) pass through as + * `StorageError` — the domain layer does not rewrap them. + */ +export declare class DomainError extends Error { + readonly code: DomainErrorCode; + readonly name = "DomainError"; + /** Present exactly when `code` is `invalid-record`. */ + readonly detail?: InvalidRecordDetail; + /** + * @param code - Stable discriminant for the failure class. + * @param message - Human-readable diagnostic detail. + * @param options - Standard error options plus the `invalid-record` location. + */ + constructor(code: DomainErrorCode, message: string, options?: DomainErrorOptions); +} +//# sourceMappingURL=error.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/events.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/events.d.ts new file mode 100644 index 0000000..c4ff849 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/events.d.ts @@ -0,0 +1,44 @@ +/** + * Change-event vocabulary of the domain data form. Every durable write emits + * one event after the backend resolves durability, carrying the new snapshot + * and an operation discriminant — never the old value (a diffing consumer + * keeps its own previous snapshot). This is the event source for cross-process + * change push (RPC frames) in a later phase. + * @module @deepseek-ai/dsh-storage-domain/src/events + */ +/** Shared location fields of one durable domain change. */ +export interface DomainChangedBase { + /** Owning domain name. */ + readonly domain: string; + /** Table name; `''` for a global-singleton write. */ + readonly table: string; + /** Record key; `''` for a global-singleton write. */ + readonly key: string; +} +/** A record (or the global singleton) was inserted or overwritten. */ +export interface DomainChangedPut extends DomainChangedBase { + readonly operation: 'put'; + /** The new snapshot. */ + readonly value: unknown; +} +/** A record was deleted; tombstones carry no value. */ +export interface DomainChangedDeleted extends DomainChangedBase { + readonly operation: 'deleted'; + readonly value?: never; +} +/** One durable domain change; a closed union — switch on `operation`. */ +export type DomainChanged = DomainChangedPut | DomainChangedDeleted; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * A domain record or the global singleton changed, emitted once per write + * strictly after the backend acknowledged durability. Events of one + * domain arrive in its write-chain order. + * @param change - domain, table (`''` for global), key (`''` for global), + * operation discriminant, and on `put` the new snapshot. + * @mode emit + */ + 'domain/changed'(change: DomainChanged): void; + } +} +//# sourceMappingURL=events.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/index.d.ts new file mode 100644 index 0000000..24eeac5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/index.d.ts @@ -0,0 +1,104 @@ +/** + * Domain data form (`ctx.storage.domain`): schema-validated, change-emitting + * KV domains over storage backends. The single implementation of the domain + * layer — consumers depend on this package and never touch backends directly. + * Plugin `Config` is schemastery; record schemas inside domain specs are zod + * (see `src/spec.ts` for the split rationale). + * @module @deepseek-ai/dsh-storage-domain + */ +import type { Context } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { DomainSpec } from './spec.ts'; +import { DomainImpl } from './domain.ts'; +import type { Domain } from './domain.ts'; +export { DomainError } from './error.ts'; +export type { DomainErrorCode, DomainErrorOptions, InvalidRecordDetail } from './error.ts'; +export { defineDomain, domainTable, descriptorOf } from './spec.ts'; +export type { DomainSpec, DomainGlobalSpec, DomainTableSpec, TableKeyOf, TableValueOf, GlobalValueOf, } from './spec.ts'; +export type { DomainChanged } from './events.ts'; +export type { Domain, DomainGlobal, DomainGlobalHandleOf, KvTable } from './domain.ts'; +declare module '@deepseek-ai/dsh-storage' { + interface StorageForms { + domain: DomainFacility; + } +} +declare module '@deepseek-ai/cordis' { + interface Context { + storageDomain: DomainFacility; + } +} +/** Cordis plugin name. */ +export declare const name = "storage-domain"; +/** The storage hub must be present before the form can mount. */ +export declare const inject: string[]; +/** + * Plugin config. Which backend serves which domain is decided here, not + * globally on the hub: `backend` is the default route and `routes` overrides + * it per domain name. A route naming an unregistered backend fails loud at + * `open` with `backend-not-found`. + */ +export interface Config { + /** Default backend name for every domain without an explicit route. Required: there is no universally correct medium. */ + backend: string; + /** Per-domain overrides: domain name → backend name. */ + routes?: Record; +} +export declare const Config: z; +/** + * The mounted domain facility. Opens declared domains over routed backends; + * one facility instance owns the open-domain table and enforces single-open + * per domain name. + */ +export declare class DomainFacility { + private readonly ctx; + private readonly config; + private readonly domains; + /** Names reserved by an in-flight or completed open, so concurrent opens of one name fail loud. */ + private readonly reserved; + /** + * @param ctx - Context of the domain plugin; open-domain effects and change + * events attach here. + * @param config - Validated plugin config. + */ + constructor(ctx: Context, config: Config); + /** + * Open one declared domain. Steps, each failing the whole call: reject a + * name that is already open (`already-open`); resolve the backend route + * (`backend-not-found` passes through from the hub); require its `kv` facet + * (`facet-unsupported`); open the unit projected from the spec (backend + * `version-mismatch`/`malformed-medium` pass through); load and validate + * every stored record against the spec's zod schemas (`invalid-record` + * with the offending table and key); construct the domain. + * + * Lifecycle: the CALLER owns the returned handle and closes it via + * `Domain.close()` (typically as its own `ctx.effect` disposer) — the + * facility does not tie the domain to any consumer fiber. Domains still + * open when the facility unmounts are closed by the plugin disposer. + * @param spec - The domain declaration, typically from `defineDomain`. + * @returns the opened domain handle, typed by the spec. + */ + open(spec: S): Promise>; + /** + * Look up an open domain by name, untyped. Diagnostic surface (the package + * invariant cross-checks change events against live domain state); typed + * consumers hold the handle returned by {@link open}. + * @param name - Domain name. + * @returns the open domain runtime, or `undefined` when not open. + */ + get(name: string): DomainImpl | undefined; + /** + * Close every domain still open on this facility. The unmount path for + * consumers that never called `Domain.close()` themselves; closing is + * idempotent, so double-closing an already-closed domain is harmless. + * @returns resolution after every unit is released. + */ + closeAll(): Promise; +} +/** + * Mount the domain data form on the storage hub. + * @param ctx - Plugin context. + * @param config - Validated plugin config. + * @returns resolution after an already-available backend set activates the form. + */ +export declare function apply(ctx: Context, config: Config): Promise; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/invariant.d.ts new file mode 100644 index 0000000..d0d3b37 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/invariant.d.ts @@ -0,0 +1,22 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-storage-domain`: every + * `domain/changed` event must agree with the emitting domain's authoritative + * in-memory state (the owned event-stream ↔ mutable-data relationship of this + * package). Writes emit strictly after mutating memory and the write chain + * serializes them, so at emission time the event's snapshot equals the + * current read — any divergence means a write path skipped the chain or + * emitted a stale value. + * @module @deepseek-ai/dsh-storage-domain/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "storage-domain-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/spec.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/spec.d.ts new file mode 100644 index 0000000..bd1bdbc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/spec.d.ts @@ -0,0 +1,72 @@ +/** + * Domain declaration vocabulary. A spec object is the single source of a + * domain's identity, layout, and record schemas: the owning package defines + * it once with {@link defineDomain} and both the type surface and the runtime + * (validation, descriptor projection) derive from it. Record schemas are zod + * (`z.infer` keeps types un-duplicated and the same schemas later project to + * RPC wire schemas); plugin `Config` stays schemastery. + * @module @deepseek-ai/dsh-storage-domain/src/spec + */ +import type { ZodType } from 'zod'; +import { type KvUnitDescriptor } from '@deepseek-ai/dsh-storage'; +/** Global singleton declaration: schema plus the value used before the first write. */ +export interface DomainGlobalSpec { + /** Validates the stored global at the durable boundary. */ + readonly schema: ZodType; + /** Value served when the medium holds no global yet; not written until the first `set`. */ + readonly initial: G; +} +/** + * One table declaration. `K` is a phantom key type (typically a branded + * string) carried for compile-time projection only; keys are plain strings on + * the medium. + */ +export interface DomainTableSpec { + /** Validates every stored record at the durable boundary. */ + readonly valueSchema: ZodType; + /** Phantom carrier for the key type; never present at runtime. */ + readonly __key?: K; +} +/** Static declaration of one domain: identity, version, and record layout. */ +export interface DomainSpec { + /** Domain name; must match `UNIT_NAME_RE` (doubles as the backend unit name). */ + readonly name: string; + /** Domain format version; a medium stamped with a different version rejects at open. */ + readonly version: number; + /** Optional global singleton slot. */ + readonly global?: DomainGlobalSpec; + /** Table declarations keyed by table name; each name must match `UNIT_NAME_RE`. */ + readonly tables: Record; +} +/** Key type of one declared table, recovered from its phantom carrier. */ +export type TableKeyOf = S['tables'][N] extends DomainTableSpec ? K : never; +/** Value type of one declared table. */ +export type TableValueOf = S['tables'][N] extends DomainTableSpec ? V : never; +/** Global value type of a spec; `never` when the spec declares no global. */ +export type GlobalValueOf = S['global'] extends DomainGlobalSpec ? G : never; +/** + * Declare one table. + * @param schema - zod schema validating every stored record of this table. + * @returns the table declaration, key-typed by `K`. + */ +export declare function domainTable(schema: ZodType): DomainTableSpec; +/** + * Identity helper that pins a spec's literal types and validates its fields. + * Misconfiguration fails loud at the owning package's module load, before any + * medium is touched: a domain or table name outside `UNIT_NAME_RE`, a version + * that is not a non-negative integer, or a global schema that accepts `null` + * all throw. The `null` rejection guards round-tripping: backends store the + * global as opaque JSON with `null` as the "never written" sentinel, so a + * nullable global would be indistinguishable from an absent one on reopen + * (a stored `null` silently reverts to `initial`). + * @param spec - The domain declaration. + * @returns the same spec, narrowed to its literal type. + */ +export declare function defineDomain(spec: S): S; +/** + * Project a spec onto the backend-facing unit descriptor. + * @param spec - The domain declaration. + * @returns the descriptor handed to `KvFacet.open`. + */ +export declare function descriptorOf(spec: DomainSpec): KvUnitDescriptor; +//# sourceMappingURL=spec.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/package.json new file mode 100644 index 0000000..475fbb8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain/package.json @@ -0,0 +1,48 @@ +{ + "name": "@deepseek-ai/dsh-storage-domain", + "description": "Domain data form (ctx.storage.domain): schema-validated, event-emitting KV domains over storage backends for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/storage/storage-domain" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage new file mode 120000 index 0000000..c3ed99b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.i18n.yaml new file mode 100644 index 0000000..80ccac9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/storage/storage-domain/README.md +README.md: 7c058ab557cfb128f54c15e715685d59f6720696 +README.zh.md: 10eb33711e147bc5ac6b7770a196bfea4fe66306 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.md new file mode 100644 index 0000000..7c058ab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.md @@ -0,0 +1,35 @@ +# @deepseek-ai/dsh-storage-domain + +English | [中文](README.zh.md) + +Domain data form for the DeepSeek Harness storage hub: exposes the injectable `ctx.storageDomain` service and the matching `ctx.storage.domain` projection after every configured backend is registered. A domain is declared once with `defineDomain` (zod record schemas, `z.infer`-derived types), opened through `DomainFacility.open`, and served from authoritative in-memory state — reads are synchronous, writes serialize on one per-domain chain, reach durability on the routed backend first, then update memory and emit `domain/changed`. The opening consumer owns the handle's lifecycle and releases it with `Domain.close()` (idempotent; typically its own `ctx.effect` disposer); domains still open when the plugin unmounts are closed by the facility. + +Design rationale, open semantics, and the storage/domain layer split live in the [Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md). + +## Configuration + +| key | meaning | +| --- | --- | +| `backend` | Default backend name for every domain (required; no universally correct medium exists). | +| `routes` | Per-domain overrides: domain name → backend name. | + +## Model Experience + +### Durable domain state + +#### What the model sees + +Nothing. The package registers no tools, injects no prompts, and appends no session events; it stores non-session data (workspace records, future session sidecars) behind `ctx.storageDomain` and emits only the in-process `domain/changed` event, which reaches a model only if a Consumer package renders it through its own documented surface. + +#### Token effect + +Zero. No text from this package enters any model request. + +#### KV Cache effect + +Independent: domain reads and writes never touch request prefixes, so nothing here can invalidate provider cache reuse. + +## Known Limitations and Deferred Work + +- **Single-process change visibility** — `domain/changed` is an in-process event; a second host process or a reconnecting GUI observes no changes until the cross-process revision pattern deferred in the Agent Note lands. +- **No cross-table transactions, secondary indexes, or multi-segment keys** — each write touches one record; triggers and rework points for these extensions are tabled in the Agent Note's deferred-work list. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.zh.md new file mode 100644 index 0000000..10eb337 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/README.zh.md @@ -0,0 +1,35 @@ +# @deepseek-ai/dsh-storage-domain + +[English](README.md) | 中文 + +DeepSeek Harness 存储中心的领域数据形式:在所有已配置的后端注册后,公开可注入的 `ctx.storageDomain` 服务及对应的 `ctx.storage.domain` 投影。一个领域通过 `defineDomain`(zod 记录 schema、从 `z.infer` 派生的类型)声明一次,通过 `DomainFacility.open` 打开,并由具有最终决定权的内存状态提供服务:读取同步执行;写入在每个领域各自的一条链上串行化,先在已路由后端达到持久状态,再更新内存并发出 `domain/changed`。打开领域的消费方负责管理句柄的生命周期,并通过 `Domain.close()` 释放它(幂等;通常作为其自身的 `ctx.effect` 资源释放函数);插件卸载时,该设施会关闭仍处于打开状态的领域。 + +设计原理、打开语义和存储/领域分层见 [Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。 + +## 配置 + +| key | 含义 | +| --- | --- | +| `backend` | 每个领域的默认后端名称(必填;不存在普遍适用的存储介质)。 | +| `routes` | 逐领域覆盖:领域名称 → 后端名称。 | + +## 模型体验 + +### 持久领域状态 + +#### 模型看到的内容 + +无。该包不注册工具、不注入提示词,也不追加会话事件;它在 `ctx.storageDomain` 后面存储非会话数据(工作区记录、未来的会话伴随数据),只发出进程内 `domain/changed` 事件。只有 Consumer 包通过自身有文档说明的接口呈现该事件时,它才会到达模型。 + +#### Token 影响 + +为零。该包的文本不会进入任何模型请求。 + +#### KV Cache 影响 + +相互独立:领域读写绝不触碰请求前缀,因此这里没有任何内容能使提供方缓存复用失效。 + +## 已知限制与暂缓事项 + +- **变更只在单进程内可见**:`domain/changed` 是进程内事件;在 Agent Note 暂缓的跨进程修订模式落地前,第二个主机进程或重新连接的 GUI 无法观察变更。 +- **没有跨表事务、二级索引或多段键**:每次写入只触碰一条记录;这些扩展的触发点和返工点列在 Agent Note 的暂缓工作清单中。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js new file mode 100644 index 0000000..cb2f21a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js @@ -0,0 +1,430 @@ +import z from "@deepseek-ai/schemastery"; +import { UNIT_NAME_RE, storageBackendServiceKey } from "@deepseek-ai/dsh-storage"; +//#region lib/types/error.js +/** +* Error vocabulary of the domain data form. +* @module @deepseek-ai/dsh-storage-domain/src/error +*/ +/** +* Error thrown by the domain layer. The `code` is the stable contract +* consumers may switch on; `message` is diagnostic prose. Backend failures +* (`backend-not-found`, `version-mismatch`, …) pass through as +* `StorageError` — the domain layer does not rewrap them. +*/ +var DomainError = class extends Error { + code; + name = "DomainError"; + /** Present exactly when `code` is `invalid-record`. */ + detail; + /** + * @param code - Stable discriminant for the failure class. + * @param message - Human-readable diagnostic detail. + * @param options - Standard error options plus the `invalid-record` location. + */ + constructor(code, message, options) { + super(message, options); + this.code = code; + if (options?.detail) this.detail = options.detail; + } +}; +//#endregion +//#region lib/types/spec.js +/** +* Domain declaration vocabulary. A spec object is the single source of a +* domain's identity, layout, and record schemas: the owning package defines +* it once with {@link defineDomain} and both the type surface and the runtime +* (validation, descriptor projection) derive from it. Record schemas are zod +* (`z.infer` keeps types un-duplicated and the same schemas later project to +* RPC wire schemas); plugin `Config` stays schemastery. +* @module @deepseek-ai/dsh-storage-domain/src/spec +*/ +/** +* Declare one table. +* @param schema - zod schema validating every stored record of this table. +* @returns the table declaration, key-typed by `K`. +*/ +function domainTable(schema) { + return { valueSchema: schema }; +} +/** +* Identity helper that pins a spec's literal types and validates its fields. +* Misconfiguration fails loud at the owning package's module load, before any +* medium is touched: a domain or table name outside `UNIT_NAME_RE`, a version +* that is not a non-negative integer, or a global schema that accepts `null` +* all throw. The `null` rejection guards round-tripping: backends store the +* global as opaque JSON with `null` as the "never written" sentinel, so a +* nullable global would be indistinguishable from an absent one on reopen +* (a stored `null` silently reverts to `initial`). +* @param spec - The domain declaration. +* @returns the same spec, narrowed to its literal type. +*/ +function defineDomain(spec) { + if (!UNIT_NAME_RE.test(spec.name)) throw new Error(`domain name '${spec.name}' must match ${UNIT_NAME_RE}`); + if (!Number.isInteger(spec.version) || spec.version < 0) throw new Error(`domain '${spec.name}' version must be a non-negative integer, got ${spec.version}`); + for (const table of Object.keys(spec.tables)) if (!UNIT_NAME_RE.test(table)) throw new Error(`domain '${spec.name}' table name '${table}' must match ${UNIT_NAME_RE}`); + if (spec.global !== void 0 && spec.global.schema.safeParse(null).success) throw new Error(`domain '${spec.name}' global schema must not accept null: null is the medium's "never written" sentinel, so a stored null could not round-trip`); + return spec; +} +/** +* Project a spec onto the backend-facing unit descriptor. +* @param spec - The domain declaration. +* @returns the descriptor handed to `KvFacet.open`. +*/ +function descriptorOf(spec) { + return { + name: spec.name, + version: spec.version, + tables: Object.keys(spec.tables), + hasGlobal: spec.global !== void 0 + }; +} +//#endregion +//#region lib/types/domain.js +/** +* Runtime of one open domain: authoritative in-memory state, the single +* per-domain write chain, and change-event emission. Reads are synchronous +* from memory; every write queues on the chain, awaits backend durability +* FIRST, then mutates memory, then emits `domain/changed` — a rejected +* backend write leaves memory untouched (no divergence between reads and the +* medium), and events carry values that equal the in-memory state at +* emission, in write order. +* @module @deepseek-ai/dsh-storage-domain/src/domain +*/ +const noop = () => {}; +/** +* The single domain implementation behind the {@link Domain} interface. The +* facility constructs it from a validated `loadAll` snapshot and erases it to +* `Domain`; nothing outside this package constructs one. +*/ +var DomainImpl = class { + ctx; + unit; + onClosed; + /** Domain name from the spec. */ + name; + tables = /* @__PURE__ */ new Map(); + globalValue; + globalHandle; + /** Tail of the write chain; every link settles (rejections are observed by the caller's slice). */ + chain = Promise.resolve(); + /** Set when close begins: new writes reject while already-queued writes drain. */ + disposing = false; + /** Set when close finishes (chain drained, unit closed): reads reject from here on. */ + closed = false; + disposal; + /** + * @param ctx - Context that carries `domain/changed` emissions. + * @param spec - The domain declaration. + * @param unit - The opened backend unit; this instance owns its lifecycle. + * @param records - Validated records from the unit's `loadAll`, one entry + * per declared table (empty maps included) — the facility builds it from + * the spec, so the entry set IS the table set. + * @param globalValue - Validated stored global, or the spec's `initial` + * when the medium held none; `undefined` when the spec declares no global. + * @param onClosed - Facility hook run once after teardown completes; frees + * the domain name for a later open. + */ + constructor(ctx, spec, unit, records, globalValue, onClosed) { + this.ctx = ctx; + this.unit = unit; + this.onClosed = onClosed; + this.name = spec.name; + const host = { + domainName: spec.name, + unit, + enqueue: (job) => this.enqueue(job), + assertReadable: () => { + this.assertReadable(); + }, + emitChanged: (change) => { + this.emitChanged(change); + } + }; + for (const [table, tableRecords] of records) this.tables.set(table, new KvTableImpl(host, table, tableRecords)); + if (spec.global !== void 0) { + this.globalValue = globalValue; + this.globalHandle = { + get: () => { + this.assertReadable(); + return this.globalValue; + }, + set: (value) => this.enqueue(async () => { + await this.unit.setGlobal(value); + this.globalValue = value; + this.emitChanged({ + domain: this.name, + table: "", + key: "", + operation: "put", + value + }); + }) + }; + } + } + /** Global singleton handle; accessing it on a spec that declares no global is a caller bug and throws. */ + get global() { + if (this.globalHandle === void 0) throw new Error(`domain '${this.name}' declares no global`); + return this.globalHandle; + } + /** + * Resolve one declared table handle; an undeclared name is a caller bug + * and throws. + * @param name - Declared table name. + * @returns the stable table handle. + */ + table(name) { + const table = this.tables.get(name); + if (table === void 0) throw new Error(`domain '${this.name}' declares no table '${name}'`); + return table; + } + /** + * Close this domain: reject new writes immediately, drain already-queued + * writes (their events still emit), close the unit, then free the name via + * the facility hook. Idempotent — repeated calls share one teardown. + * @returns resolution after the unit is released. + */ + close() { + this.disposal ??= this.runClose(); + return this.disposal; + } + async runClose() { + this.disposing = true; + await this.chain; + await this.unit.close(); + this.closed = true; + this.onClosed(); + } + /** + * Dispatch one post-durability change notification, containing observer + * failures: the write is already committed (medium and memory both hold + * the new state), so a throwing listener must not retroactively reject it. + */ + emitChanged(change) { + try { + this.ctx.emit("domain/changed", change); + } catch (error) { + this.ctx.logger.warn(`domain '${this.name}': domain/changed listener failed: ${String(error)}`); + } + } + enqueue(job) { + if (this.disposing) return Promise.reject(new DomainError("closed", `domain '${this.name}' is closed`)); + const result = this.chain.then(job); + this.chain = result.then(noop, noop); + return result; + } + assertReadable() { + if (this.closed) throw new DomainError("closed", `domain '${this.name}' is closed`); + } +}; +/** Table handle bound to one in-memory record map and its domain's write chain. */ +var KvTableImpl = class { + host; + tableName; + records; + constructor(host, tableName, records) { + this.host = host; + this.tableName = tableName; + this.records = records; + } + get(key) { + this.host.assertReadable(); + return this.records.get(key); + } + entries() { + this.host.assertReadable(); + return [...this.records.entries()][Symbol.iterator](); + } + keys() { + this.host.assertReadable(); + return [...this.records.keys()][Symbol.iterator](); + } + get size() { + this.host.assertReadable(); + return this.records.size; + } + put(key, value) { + return this.host.enqueue(async () => { + await this.host.unit.putRecord(this.tableName, key, value); + this.records.set(key, value); + this.emitPut(key, value); + }); + } + delete(key) { + return this.host.enqueue(async () => { + if (!this.records.has(key)) return false; + await this.host.unit.deleteRecord(this.tableName, key); + this.records.delete(key); + this.host.emitChanged({ + domain: this.host.domainName, + table: this.tableName, + key, + operation: "deleted" + }); + return true; + }); + } + update(key, fn) { + return this.host.enqueue(async () => { + if (!this.records.has(key)) throw new DomainError("missing-key", `domain '${this.host.domainName}' table '${this.tableName}' has no record '${key}' to update`); + const next = fn(this.records.get(key)); + await this.host.unit.putRecord(this.tableName, key, next); + this.records.set(key, next); + this.emitPut(key, next); + return next; + }); + } + emitPut(key, value) { + this.host.emitChanged({ + domain: this.host.domainName, + table: this.tableName, + key, + operation: "put", + value + }); + } +}; +//#endregion +//#region lib/types/index.js +/** +* Domain data form (`ctx.storage.domain`): schema-validated, change-emitting +* KV domains over storage backends. The single implementation of the domain +* layer — consumers depend on this package and never touch backends directly. +* Plugin `Config` is schemastery; record schemas inside domain specs are zod +* (see `src/spec.ts` for the split rationale). +* @module @deepseek-ai/dsh-storage-domain +*/ +/** Cordis plugin name. */ +const name = "storage-domain"; +/** The storage hub must be present before the form can mount. */ +const inject = ["storage"]; +const Config = z.object({ + backend: z.string().required(), + routes: z.dict(z.string()).default({}) +}); +/** +* The mounted domain facility. Opens declared domains over routed backends; +* one facility instance owns the open-domain table and enforces single-open +* per domain name. +*/ +var DomainFacility = class { + ctx; + config; + domains = /* @__PURE__ */ new Map(); + /** Names reserved by an in-flight or completed open, so concurrent opens of one name fail loud. */ + reserved = /* @__PURE__ */ new Set(); + /** + * @param ctx - Context of the domain plugin; open-domain effects and change + * events attach here. + * @param config - Validated plugin config. + */ + constructor(ctx, config) { + this.ctx = ctx; + this.config = config; + } + /** + * Open one declared domain. Steps, each failing the whole call: reject a + * name that is already open (`already-open`); resolve the backend route + * (`backend-not-found` passes through from the hub); require its `kv` facet + * (`facet-unsupported`); open the unit projected from the spec (backend + * `version-mismatch`/`malformed-medium` pass through); load and validate + * every stored record against the spec's zod schemas (`invalid-record` + * with the offending table and key); construct the domain. + * + * Lifecycle: the CALLER owns the returned handle and closes it via + * `Domain.close()` (typically as its own `ctx.effect` disposer) — the + * facility does not tie the domain to any consumer fiber. Domains still + * open when the facility unmounts are closed by the plugin disposer. + * @param spec - The domain declaration, typically from `defineDomain`. + * @returns the opened domain handle, typed by the spec. + */ + async open(spec) { + if (this.reserved.has(spec.name)) throw new DomainError("already-open", `domain '${spec.name}' is already open`); + this.reserved.add(spec.name); + try { + const backendName = this.config.routes?.[spec.name] ?? this.config.backend; + const backend = this.ctx.storage.backend.get(backendName); + if (!backend.kv) throw new DomainError("facet-unsupported", `backend '${backendName}' routed for domain '${spec.name}' has no kv facet`); + const unit = await backend.kv.open(descriptorOf(spec)); + try { + const snapshot = await unit.loadAll(); + const tables = /* @__PURE__ */ new Map(); + for (const [table, tableSpec] of Object.entries(spec.tables)) { + const records = /* @__PURE__ */ new Map(); + for (const [key, raw] of Object.entries(snapshot.tables[table] ?? {})) records.set(key, parseRecord(spec.name, table, key, () => tableSpec.valueSchema.parse(raw))); + tables.set(table, records); + } + const globalSpec = spec.global; + const globalValue = globalSpec === void 0 ? void 0 : snapshot.global === null ? globalSpec.initial : parseRecord(spec.name, "", "", () => globalSpec.schema.parse(snapshot.global)); + const domain = new DomainImpl(this.ctx, spec, unit, tables, globalValue, () => { + this.domains.delete(spec.name); + this.reserved.delete(spec.name); + }); + this.domains.set(spec.name, domain); + return domain; + } catch (error) { + await unit.close(); + throw error; + } + } catch (error) { + this.reserved.delete(spec.name); + throw error; + } + } + /** + * Look up an open domain by name, untyped. Diagnostic surface (the package + * invariant cross-checks change events against live domain state); typed + * consumers hold the handle returned by {@link open}. + * @param name - Domain name. + * @returns the open domain runtime, or `undefined` when not open. + */ + get(name) { + return this.domains.get(name); + } + /** + * Close every domain still open on this facility. The unmount path for + * consumers that never called `Domain.close()` themselves; closing is + * idempotent, so double-closing an already-closed domain is harmless. + * @returns resolution after every unit is released. + */ + async closeAll() { + await Promise.all([...this.domains.values()].map((domain) => domain.close())); + } +}; +/** Run one zod parse, translating failure to `invalid-record` with its location. */ +function parseRecord(domain, table, key, parse) { + try { + return parse(); + } catch (error) { + throw new DomainError("invalid-record", `domain '${domain}': stored ${table === "" ? "global" : `record '${key}' in table '${table}'`} does not match its schema`, { + detail: { + table, + key + }, + cause: error + }); + } +} +/** +* Mount the domain data form on the storage hub. +* @param ctx - Plugin context. +* @param config - Validated plugin config. +* @returns resolution after an already-available backend set activates the form. +*/ +function apply(ctx, config) { + const backendServices = [...new Set([config.backend, ...Object.values(config.routes ?? {})])].map(storageBackendServiceKey); + const fiber = ctx.inject(backendServices, (domainCtx) => { + const facility = new DomainFacility(domainCtx, config); + domainCtx.effect(() => { + const unmount = domainCtx.storage.mount("domain", facility); + return async () => { + await facility.closeAll(); + unmount(); + }; + }); + domainCtx.provide("storageDomain", facility); + }); + return Promise.resolve(fiber).then(() => {}); +} +//#endregion +export { Config, DomainError, DomainFacility, apply, defineDomain, descriptorOf, domainTable, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/invariant.js new file mode 100644 index 0000000..b9e30ad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/invariant.js @@ -0,0 +1,45 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-storage-domain`: every +* `domain/changed` event must agree with the emitting domain's authoritative +* in-memory state (the owned event-stream ↔ mutable-data relationship of this +* package). Writes emit strictly after mutating memory and the write chain +* serializes them, so at emission time the event's snapshot equals the +* current read — any divergence means a write path skipped the chain or +* emitted a stale value. +* @module @deepseek-ai/dsh-storage-domain/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-storage-domain"; +/** Cordis companion plugin name. */ +const name = "storage-domain-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Install the change-event ↔ memory-state agreement check. */ +const install = Object.assign((ctx, fail) => { + ctx.on("domain/changed", (change) => { + const domain = ctx.storage.form("domain").get(change.domain); + if (domain === void 0) return fail(`domain/changed for '${change.domain}' emitted while that domain is not open`); + if (change.table === "") { + if (domain.global.get() !== change.value) return fail(`domain/changed global value for '${change.domain}' differs from the in-memory global`); + return; + } + const current = domain.table(change.table).get(change.key); + switch (change.operation) { + case "deleted": + if (current !== void 0) return fail(`domain/changed deletion of '${change.domain}'.'${change.table}'['${change.key}'] emitted while the record is still in memory`); + return; + case "put": + if (current !== change.value) return fail(`domain/changed value for '${change.domain}'.'${change.table}'['${change.key}'] differs from the in-memory record`); + return; + default: + } + }, { global: true }); +}, { inject: ["storage"] }); +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/domain.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/domain.d.ts new file mode 100644 index 0000000..e43ab81 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/domain.d.ts @@ -0,0 +1,166 @@ +/** + * Runtime of one open domain: authoritative in-memory state, the single + * per-domain write chain, and change-event emission. Reads are synchronous + * from memory; every write queues on the chain, awaits backend durability + * FIRST, then mutates memory, then emits `domain/changed` — a rejected + * backend write leaves memory untouched (no divergence between reads and the + * medium), and events carry values that equal the in-memory state at + * emission, in write order. + * @module @deepseek-ai/dsh-storage-domain/src/domain + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { KvUnit } from '@deepseek-ai/dsh-storage'; +import type { DomainSpec, DomainGlobalSpec, TableKeyOf, TableValueOf } from './spec.ts'; +/** Handle on a domain's global singleton. */ +export interface DomainGlobal { + /** + * Current value, synchronously from the authoritative in-memory state. + * Before the first `set` this is the spec's `initial`. + * @returns the current global value. + */ + get(): G; + /** + * Replace the value durably. Queued on the domain's write chain; the first + * `set` is what materializes the global on the medium. + * @param value - New value; must satisfy the spec's schema (not re-checked + * here — validation happens at the durable read boundary). + * @returns resolution after durability and event emission. + */ + set(value: G): Promise; +} +/** + * Handle on one declared table. Records are plain immutable data: returned + * values are the stored objects themselves (no defensive copies) and must not + * be mutated in place — replace via `put`/`update`. + */ +export interface KvTable { + /** + * Read one record, synchronously from memory. + * @param key - Record key. + * @returns the record, or `undefined` when absent. + */ + get(key: K): V | undefined; + /** + * Snapshot iterator over `[key, record]` pairs. A snapshot, not a live + * view: iteration stays stable while queued writes land. + * @returns the pair iterator. + */ + entries(): IterableIterator<[K, V]>; + /** + * Snapshot iterator over keys. + * @returns the key iterator. + */ + keys(): IterableIterator; + /** Current record count. */ + readonly size: number; + /** + * Insert or overwrite one record durably. + * @param key - Record key. + * @param value - The full new record (no partial merge). + * @returns resolution after durability and event emission. + */ + put(key: K, value: V): Promise; + /** + * Delete one record durably. + * @param key - Record key. + * @returns `true` when the record existed, `false` when it was already + * absent (no write and no event in that case). + */ + delete(key: K): Promise; + /** + * Atomic read-modify-write on the domain's write chain: `fn` sees the + * value current at its queue slot, so concurrent updates never interleave. + * @param key - Record key; a missing key rejects with `missing-key`. + * @param fn - Synchronous pure transform from current to next record. + * @returns the stored next record. + */ + update(key: K, fn: (current: V) => V): Promise; +} +/** Global handle of a spec: typed when declared, `never` (inaccessible) when not. */ +export type DomainGlobalHandleOf = S extends { + readonly global: DomainGlobalSpec; +} ? DomainGlobal : never; +/** One open domain, typed by its spec. */ +export interface Domain { + /** Domain name from the spec. */ + readonly name: string; + /** Global singleton handle; a spec without `global` has no usable handle (`never`). */ + readonly global: DomainGlobalHandleOf; + /** + * Resolve one declared table handle. Handles are stable — repeated calls + * return the same instance. + * @param name - Declared table name. + * @returns the typed table handle. + */ + table(name: N): KvTable, TableValueOf>; + /** + * Close this domain: reject new writes immediately, drain already-queued + * writes (their events still emit), release the backend unit, then free + * the domain name for a later open. Idempotent — repeated calls share one + * teardown. The consumer owns this call (typically as its own `ctx.effect` + * disposer); the facility closes any domain left open when it unmounts. + * @returns resolution after the unit is released. + */ + close(): Promise; +} +/** + * The single domain implementation behind the {@link Domain} interface. The + * facility constructs it from a validated `loadAll` snapshot and erases it to + * `Domain`; nothing outside this package constructs one. + */ +export declare class DomainImpl { + private readonly ctx; + private readonly unit; + private readonly onClosed; + /** Domain name from the spec. */ + readonly name: string; + private readonly tables; + private globalValue; + private readonly globalHandle?; + /** Tail of the write chain; every link settles (rejections are observed by the caller's slice). */ + private chain; + /** Set when close begins: new writes reject while already-queued writes drain. */ + private disposing; + /** Set when close finishes (chain drained, unit closed): reads reject from here on. */ + private closed; + private disposal?; + /** + * @param ctx - Context that carries `domain/changed` emissions. + * @param spec - The domain declaration. + * @param unit - The opened backend unit; this instance owns its lifecycle. + * @param records - Validated records from the unit's `loadAll`, one entry + * per declared table (empty maps included) — the facility builds it from + * the spec, so the entry set IS the table set. + * @param globalValue - Validated stored global, or the spec's `initial` + * when the medium held none; `undefined` when the spec declares no global. + * @param onClosed - Facility hook run once after teardown completes; frees + * the domain name for a later open. + */ + constructor(ctx: Context, spec: DomainSpec, unit: KvUnit, records: Map>, globalValue: unknown, onClosed: () => void); + /** Global singleton handle; accessing it on a spec that declares no global is a caller bug and throws. */ + get global(): DomainGlobal; + /** + * Resolve one declared table handle; an undeclared name is a caller bug + * and throws. + * @param name - Declared table name. + * @returns the stable table handle. + */ + table(name: string): KvTable; + /** + * Close this domain: reject new writes immediately, drain already-queued + * writes (their events still emit), close the unit, then free the name via + * the facility hook. Idempotent — repeated calls share one teardown. + * @returns resolution after the unit is released. + */ + close(): Promise; + private runClose; + /** + * Dispatch one post-durability change notification, containing observer + * failures: the write is already committed (medium and memory both hold + * the new state), so a throwing listener must not retroactively reject it. + */ + private emitChanged; + private enqueue; + private assertReadable; +} +//# sourceMappingURL=domain.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/error.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/error.d.ts new file mode 100644 index 0000000..546d3a3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/error.d.ts @@ -0,0 +1,37 @@ +/** + * Error vocabulary of the domain data form. + * @module @deepseek-ai/dsh-storage-domain/src/error + */ +/** Discriminant codes carried by every {@link DomainError}. */ +export type DomainErrorCode = 'already-open' | 'facet-unsupported' | 'invalid-record' | 'missing-key' | 'closed'; +/** Location of the record that failed schema validation at the durable boundary. */ +export interface InvalidRecordDetail { + /** Table holding the rejected record; `''` for the global singleton. */ + readonly table: string; + /** Key of the rejected record; `''` for the global singleton. */ + readonly key: string; +} +/** Construction options: standard `cause` plus the `invalid-record` location. */ +export interface DomainErrorOptions extends ErrorOptions { + /** Present exactly when `code` is `invalid-record`. */ + readonly detail?: InvalidRecordDetail; +} +/** + * Error thrown by the domain layer. The `code` is the stable contract + * consumers may switch on; `message` is diagnostic prose. Backend failures + * (`backend-not-found`, `version-mismatch`, …) pass through as + * `StorageError` — the domain layer does not rewrap them. + */ +export declare class DomainError extends Error { + readonly code: DomainErrorCode; + readonly name = "DomainError"; + /** Present exactly when `code` is `invalid-record`. */ + readonly detail?: InvalidRecordDetail; + /** + * @param code - Stable discriminant for the failure class. + * @param message - Human-readable diagnostic detail. + * @param options - Standard error options plus the `invalid-record` location. + */ + constructor(code: DomainErrorCode, message: string, options?: DomainErrorOptions); +} +//# sourceMappingURL=error.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/events.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/events.d.ts new file mode 100644 index 0000000..c4ff849 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/events.d.ts @@ -0,0 +1,44 @@ +/** + * Change-event vocabulary of the domain data form. Every durable write emits + * one event after the backend resolves durability, carrying the new snapshot + * and an operation discriminant — never the old value (a diffing consumer + * keeps its own previous snapshot). This is the event source for cross-process + * change push (RPC frames) in a later phase. + * @module @deepseek-ai/dsh-storage-domain/src/events + */ +/** Shared location fields of one durable domain change. */ +export interface DomainChangedBase { + /** Owning domain name. */ + readonly domain: string; + /** Table name; `''` for a global-singleton write. */ + readonly table: string; + /** Record key; `''` for a global-singleton write. */ + readonly key: string; +} +/** A record (or the global singleton) was inserted or overwritten. */ +export interface DomainChangedPut extends DomainChangedBase { + readonly operation: 'put'; + /** The new snapshot. */ + readonly value: unknown; +} +/** A record was deleted; tombstones carry no value. */ +export interface DomainChangedDeleted extends DomainChangedBase { + readonly operation: 'deleted'; + readonly value?: never; +} +/** One durable domain change; a closed union — switch on `operation`. */ +export type DomainChanged = DomainChangedPut | DomainChangedDeleted; +declare module '@deepseek-ai/cordis' { + interface Events { + /** + * A domain record or the global singleton changed, emitted once per write + * strictly after the backend acknowledged durability. Events of one + * domain arrive in its write-chain order. + * @param change - domain, table (`''` for global), key (`''` for global), + * operation discriminant, and on `put` the new snapshot. + * @mode emit + */ + 'domain/changed'(change: DomainChanged): void; + } +} +//# sourceMappingURL=events.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/index.d.ts new file mode 100644 index 0000000..24eeac5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/index.d.ts @@ -0,0 +1,104 @@ +/** + * Domain data form (`ctx.storage.domain`): schema-validated, change-emitting + * KV domains over storage backends. The single implementation of the domain + * layer — consumers depend on this package and never touch backends directly. + * Plugin `Config` is schemastery; record schemas inside domain specs are zod + * (see `src/spec.ts` for the split rationale). + * @module @deepseek-ai/dsh-storage-domain + */ +import type { Context } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { DomainSpec } from './spec.ts'; +import { DomainImpl } from './domain.ts'; +import type { Domain } from './domain.ts'; +export { DomainError } from './error.ts'; +export type { DomainErrorCode, DomainErrorOptions, InvalidRecordDetail } from './error.ts'; +export { defineDomain, domainTable, descriptorOf } from './spec.ts'; +export type { DomainSpec, DomainGlobalSpec, DomainTableSpec, TableKeyOf, TableValueOf, GlobalValueOf, } from './spec.ts'; +export type { DomainChanged } from './events.ts'; +export type { Domain, DomainGlobal, DomainGlobalHandleOf, KvTable } from './domain.ts'; +declare module '@deepseek-ai/dsh-storage' { + interface StorageForms { + domain: DomainFacility; + } +} +declare module '@deepseek-ai/cordis' { + interface Context { + storageDomain: DomainFacility; + } +} +/** Cordis plugin name. */ +export declare const name = "storage-domain"; +/** The storage hub must be present before the form can mount. */ +export declare const inject: string[]; +/** + * Plugin config. Which backend serves which domain is decided here, not + * globally on the hub: `backend` is the default route and `routes` overrides + * it per domain name. A route naming an unregistered backend fails loud at + * `open` with `backend-not-found`. + */ +export interface Config { + /** Default backend name for every domain without an explicit route. Required: there is no universally correct medium. */ + backend: string; + /** Per-domain overrides: domain name → backend name. */ + routes?: Record; +} +export declare const Config: z; +/** + * The mounted domain facility. Opens declared domains over routed backends; + * one facility instance owns the open-domain table and enforces single-open + * per domain name. + */ +export declare class DomainFacility { + private readonly ctx; + private readonly config; + private readonly domains; + /** Names reserved by an in-flight or completed open, so concurrent opens of one name fail loud. */ + private readonly reserved; + /** + * @param ctx - Context of the domain plugin; open-domain effects and change + * events attach here. + * @param config - Validated plugin config. + */ + constructor(ctx: Context, config: Config); + /** + * Open one declared domain. Steps, each failing the whole call: reject a + * name that is already open (`already-open`); resolve the backend route + * (`backend-not-found` passes through from the hub); require its `kv` facet + * (`facet-unsupported`); open the unit projected from the spec (backend + * `version-mismatch`/`malformed-medium` pass through); load and validate + * every stored record against the spec's zod schemas (`invalid-record` + * with the offending table and key); construct the domain. + * + * Lifecycle: the CALLER owns the returned handle and closes it via + * `Domain.close()` (typically as its own `ctx.effect` disposer) — the + * facility does not tie the domain to any consumer fiber. Domains still + * open when the facility unmounts are closed by the plugin disposer. + * @param spec - The domain declaration, typically from `defineDomain`. + * @returns the opened domain handle, typed by the spec. + */ + open(spec: S): Promise>; + /** + * Look up an open domain by name, untyped. Diagnostic surface (the package + * invariant cross-checks change events against live domain state); typed + * consumers hold the handle returned by {@link open}. + * @param name - Domain name. + * @returns the open domain runtime, or `undefined` when not open. + */ + get(name: string): DomainImpl | undefined; + /** + * Close every domain still open on this facility. The unmount path for + * consumers that never called `Domain.close()` themselves; closing is + * idempotent, so double-closing an already-closed domain is harmless. + * @returns resolution after every unit is released. + */ + closeAll(): Promise; +} +/** + * Mount the domain data form on the storage hub. + * @param ctx - Plugin context. + * @param config - Validated plugin config. + * @returns resolution after an already-available backend set activates the form. + */ +export declare function apply(ctx: Context, config: Config): Promise; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/invariant.d.ts new file mode 100644 index 0000000..d0d3b37 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/invariant.d.ts @@ -0,0 +1,22 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-storage-domain`: every + * `domain/changed` event must agree with the emitting domain's authoritative + * in-memory state (the owned event-stream ↔ mutable-data relationship of this + * package). Writes emit strictly after mutating memory and the write chain + * serializes them, so at emission time the event's snapshot equals the + * current read — any divergence means a write path skipped the chain or + * emitted a stale value. + * @module @deepseek-ai/dsh-storage-domain/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "storage-domain-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/spec.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/spec.d.ts new file mode 100644 index 0000000..bd1bdbc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/spec.d.ts @@ -0,0 +1,72 @@ +/** + * Domain declaration vocabulary. A spec object is the single source of a + * domain's identity, layout, and record schemas: the owning package defines + * it once with {@link defineDomain} and both the type surface and the runtime + * (validation, descriptor projection) derive from it. Record schemas are zod + * (`z.infer` keeps types un-duplicated and the same schemas later project to + * RPC wire schemas); plugin `Config` stays schemastery. + * @module @deepseek-ai/dsh-storage-domain/src/spec + */ +import type { ZodType } from 'zod'; +import { type KvUnitDescriptor } from '@deepseek-ai/dsh-storage'; +/** Global singleton declaration: schema plus the value used before the first write. */ +export interface DomainGlobalSpec { + /** Validates the stored global at the durable boundary. */ + readonly schema: ZodType; + /** Value served when the medium holds no global yet; not written until the first `set`. */ + readonly initial: G; +} +/** + * One table declaration. `K` is a phantom key type (typically a branded + * string) carried for compile-time projection only; keys are plain strings on + * the medium. + */ +export interface DomainTableSpec { + /** Validates every stored record at the durable boundary. */ + readonly valueSchema: ZodType; + /** Phantom carrier for the key type; never present at runtime. */ + readonly __key?: K; +} +/** Static declaration of one domain: identity, version, and record layout. */ +export interface DomainSpec { + /** Domain name; must match `UNIT_NAME_RE` (doubles as the backend unit name). */ + readonly name: string; + /** Domain format version; a medium stamped with a different version rejects at open. */ + readonly version: number; + /** Optional global singleton slot. */ + readonly global?: DomainGlobalSpec; + /** Table declarations keyed by table name; each name must match `UNIT_NAME_RE`. */ + readonly tables: Record; +} +/** Key type of one declared table, recovered from its phantom carrier. */ +export type TableKeyOf = S['tables'][N] extends DomainTableSpec ? K : never; +/** Value type of one declared table. */ +export type TableValueOf = S['tables'][N] extends DomainTableSpec ? V : never; +/** Global value type of a spec; `never` when the spec declares no global. */ +export type GlobalValueOf = S['global'] extends DomainGlobalSpec ? G : never; +/** + * Declare one table. + * @param schema - zod schema validating every stored record of this table. + * @returns the table declaration, key-typed by `K`. + */ +export declare function domainTable(schema: ZodType): DomainTableSpec; +/** + * Identity helper that pins a spec's literal types and validates its fields. + * Misconfiguration fails loud at the owning package's module load, before any + * medium is touched: a domain or table name outside `UNIT_NAME_RE`, a version + * that is not a non-negative integer, or a global schema that accepts `null` + * all throw. The `null` rejection guards round-tripping: backends store the + * global as opaque JSON with `null` as the "never written" sentinel, so a + * nullable global would be indistinguishable from an absent one on reopen + * (a stored `null` silently reverts to `initial`). + * @param spec - The domain declaration. + * @returns the same spec, narrowed to its literal type. + */ +export declare function defineDomain(spec: S): S; +/** + * Project a spec onto the backend-facing unit descriptor. + * @param spec - The domain declaration. + * @returns the descriptor handed to `KvFacet.open`. + */ +export declare function descriptorOf(spec: DomainSpec): KvUnitDescriptor; +//# sourceMappingURL=spec.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/package.json new file mode 100644 index 0000000..b2feb31 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain/package.json @@ -0,0 +1,48 @@ +{ + "name": "@deepseek-ai/dsh-storage-domain", + "description": "Domain data form (ctx.storage.domain): schema-validated, event-emitting KV domains over storage backends for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/storage/storage-domain" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-storage": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + }, + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.i18n.yaml new file mode 100644 index 0000000..09fa051 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/storage/storage/README.md +README.md: bf827220afe0d8b1cbc53b3a12e6d0034004e1d2 +README.zh.md: 86b6994d74a727275e0bcaea2a83bd51f93b6ca1 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.md new file mode 100644 index 0000000..bf82722 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.md @@ -0,0 +1,32 @@ +# @deepseek-ai/dsh-storage + +English | [中文](README.zh.md) + +Storage hub (`ctx.storage`) for non-session data: a named backend registry plus mounted data-form facilities. The hub performs no IO itself — backends own media, and data forms own semantics. The [storage family overview](../README.md) maps those packages; the [domain KV storage Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md) records the design rationale. + +## Shape + +- `ctx.storage.backend` — name → backend table. Multiple backends stay mounted side by side (`json`, `sqlite`); which backend serves a consumer is that consumer's configuration (the domain layer's route table), never a hub-global choice. `register()` returns the disposer; duplicate names and unknown lookups fail loud. +- `ctx.storage.mount(form, facility)` / `ctx.storage.form(form)` — data-form mounting. `StorageForms` is merge-extensible; the domain layer merges `domain` and is reached as `ctx.storage.domain`. +- A backend owns one medium and exposes the data-shape facets it supports. `kv` is the current facet; `src/backend.ts` owns its exact contract. + +## Model Experience + +### Backend and form registrations + +#### What the model sees + +Nothing. `ctx.storage` is a host-side registration table; the hub registers no tools, injects no prompts, and writes no session events. + +#### Token effect + +Zero direct tokens on every request. + +#### KV Cache effect + +Independent of live requests: the hub never touches a request prefix, so it cannot invalidate provider cache reuse. + +## Known Limitations and Deferred Work + +- **`kv` is the only data shape** — backends currently have one facet to implement. +- **Forms resolve lazily** — reading `ctx.storage.domain` before the domain plugin mounts throws `form-not-mounted`; assemblies order plugins accordingly (misconfiguration fails loud rather than silently deferring). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.zh.md new file mode 100644 index 0000000..86b6994 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/README.zh.md @@ -0,0 +1,32 @@ +# @deepseek-ai/dsh-storage + +[English](README.md) | 中文 + +非会话数据的存储中心(`ctx.storage`):具名后端注册表加已挂载的数据形式设施。中心自身不执行 IO:后端拥有介质,数据形式拥有语义。[存储家族概述](../README.md)列出了这些包;[领域 KV 存储 Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md)记录了设计理由。 + +## 结构 + +- `ctx.storage.backend`:名称 → 后端表。多个后端并排保持挂载(`json`、`sqlite`);为消费方提供服务的后端由该消费方自身的配置决定(领域层的路由表),绝非中心的全局选择。`register()` 返回资源释放函数;注册重复名称或查找未知名称时都会明确报错。 +- `ctx.storage.mount(form, facility)`/`ctx.storage.form(form)`:数据形式挂载。`StorageForms` 可通过合并扩展;领域层合并 `domain`,并通过 `ctx.storage.domain` 访问。 +- 后端拥有一种介质,并公开其支持的数据形状**分面**。当前分面为 `kv`;`src/backend.ts` 负责定义其确切约定。 + +## 模型体验 + +### 后端与形式注册 + +#### 模型看到的内容 + +无。`ctx.storage` 是主机侧注册表;中心不注册工具、不注入提示词,也不写入会话事件。 + +#### Token 影响 + +每次请求都不会直接增加 token。 + +#### KV Cache 影响 + +与实时请求相互独立:中心绝不触碰请求前缀,因此无法使提供方缓存复用失效。 + +## 已知限制与暂缓事项 + +- **`kv` 是唯一的数据形状**:后端目前只有一个分面需要实现。 +- **数据形式按需解析**:在领域插件挂载前读取 `ctx.storage.domain` 会抛出 `form-not-mounted`;组装会按相应顺序排列插件(错误配置会明确报错,而不是静默推迟处理)。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/index.js new file mode 100644 index 0000000..33229d6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/index.js @@ -0,0 +1,140 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/error.js +/** +* Error vocabulary for the storage hub and its backends. +* @module @deepseek-ai/dsh-storage/src/error +*/ +/** +* Error thrown by the hub and by backend implementations. The `code` is the +* stable contract consumers may switch on; `message` is diagnostic prose. +*/ +var StorageError = class extends Error { + code; + name = "StorageError"; + /** + * @param code - Stable discriminant for the failure class. + * @param message - Human-readable diagnostic detail. + * @param options - Standard error options (`cause`). + */ + constructor(code, message, options) { + super(message, options); + this.code = code; + } +}; +//#endregion +//#region lib/types/registry.js +/** +* Named backend registry of the storage hub. +* @module @deepseek-ai/dsh-storage/src/registry +*/ +/** +* Mutable name → backend table. Multiple backends stay mounted side by side; +* which backend serves which consumer is the consumer's configuration +* (e.g. the domain layer's route table), never a hub-global choice. +*/ +var BackendRegistry = class { + backends = /* @__PURE__ */ new Map(); + /** + * Register a named backend. Registration is an effect: the returned + * disposer removes the name. Disposal does NOT close the backend — the + * owning plugin closes it after unregistering. + * @param name - Backend name, e.g. `json` or `sqlite`. + * @param backend - The backend instance. + * @returns the disposer that unregisters the name. + */ + register(name, backend) { + if (this.backends.has(name)) throw new StorageError("duplicate-backend", `storage backend '${name}' is already registered`); + this.backends.set(name, backend); + return () => { + if (this.backends.get(name) === backend) this.backends.delete(name); + }; + } + /** + * Resolve a backend by name. + * @param name - Registered backend name. + * @returns the backend. + */ + get(name) { + const backend = this.backends.get(name); + if (!backend) throw new StorageError("backend-not-found", `storage backend '${name}' is not registered (registered: ${[...this.backends.keys()].join(", ") || "none"})`); + return backend; + } + /** + * Registered backend names, for diagnostics. + * @returns a snapshot array of names. + */ + names() { + return [...this.backends.keys()]; + } +}; +//#endregion +//#region lib/types/backend.js +/** +* Backend-facing vocabulary of the storage hub: a backend owns one medium +* (a file-tree root, a database file) and exposes operation groups over it. +* This module defines the normative contract text for backend implementers; the shared +* conformance suite in `tests/contract.ts` checks every rule. +* @module @deepseek-ai/dsh-storage/src/backend +*/ +/** Allowed format for unit and table names: safe as a file name and as a SQL identifier segment without escaping. */ +const UNIT_NAME_RE = /^[a-z][a-z0-9_]*$/; +//#endregion +//#region lib/types/index.js +/** +* Storage hub (`ctx.storage`): a named backend registry plus mounted +* data-form facilities. The hub itself performs no IO — backends own media, +* data forms (the domain layer first) own semantics. +* @module @deepseek-ai/dsh-storage +*/ +/** +* Derive the Cordis lifecycle service that one named backend plugin provides. +* Domain-form providers inject these keys so activation cannot race backend +* registration even though callers continue resolving backends through the +* storage registry. +* @param name - Backend registry name. +* @returns the corresponding lifecycle-only service key. +*/ +function storageBackendServiceKey(name) { + return `storage.backend.${name}`; +} +/** +* The storage hub service. Backends register under `backend`; data forms +* mount under their `StorageForms` key and are reached as `ctx.storage.
`. +*/ +var Storage = class extends Service { + /** Named backend table; multiple backends stay mounted side by side. */ + backend = new BackendRegistry(); + forms = /* @__PURE__ */ new Map(); + constructor(ctx) { + super(ctx, "storage"); + } + /** + * Mount a data-form facility on the hub. Mounting is an effect: the + * returned disposer unmounts the form. + * @param form - Form key declared in {@link StorageForms}. + * @param facility - The facility instance to expose. + * @returns the disposer that unmounts the form. + */ + mount(form, facility) { + if (this.forms.has(form)) throw new StorageError("duplicate-mount", `storage form '${String(form)}' is already mounted`); + this.forms.set(form, facility); + return () => { + if (this.forms.get(form) === facility) this.forms.delete(form); + }; + } + /** + * Resolve a mounted data form. + * @param form - Form key declared in {@link StorageForms}. + * @returns the mounted facility. + */ + form(form) { + if (!this.forms.has(form)) throw new StorageError("form-not-mounted", `storage form '${String(form)}' is not mounted`); + return this.forms.get(form); + } + /** Domain data form; present once the domain layer plugin is loaded. */ + get domain() { + return this.form("domain"); + } +}; +//#endregion +export { BackendRegistry, Storage, Storage as default, StorageError, UNIT_NAME_RE, storageBackendServiceKey }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/invariant.js new file mode 100644 index 0000000..07064f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/invariant.js @@ -0,0 +1,25 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-storage`. +* @module @deepseek-ai/dsh-storage/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-storage"; +/** Cordis companion plugin name. */ +const name = "storage-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the hub is a pure registration table (names → +* backends, forms → facilities) whose consistency is fully enforced at the +* call sites (duplicate/missing entries fail loud synchronously); it owns no +* event stream or mutable medium to cross-check. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/backend.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/backend.d.ts new file mode 100644 index 0000000..6f14bfd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/backend.d.ts @@ -0,0 +1,98 @@ +/** + * Backend-facing vocabulary of the storage hub: a backend owns one medium + * (a file-tree root, a database file) and exposes operation groups over it. + * This module defines the normative contract text for backend implementers; the shared + * conformance suite in `tests/contract.ts` checks every rule. + * @module @deepseek-ai/dsh-storage/src/backend + */ +/** Allowed format for unit and table names: safe as a file name and as a SQL identifier segment without escaping. */ +export declare const UNIT_NAME_RE: RegExp; +/** + * One registered backend. A backend owns exactly one medium and shares its + * lifecycle across all facets; facets are optional members — a backend that + * cannot serve a data kind simply omits it, and resolution fails loud instead. + */ +export interface StorageBackend { + /** Key-value operations; absent when this backend cannot serve them. */ + readonly kv?: KvFacet; + /** + * Drain in-flight writes across all open units and release the medium. + * Idempotent; concurrent and repeated calls resolve once teardown finishes. + * @returns resolution after the medium is released. + */ + close(): Promise; +} +/** The key-value data shape: whole-unit snapshots plus per-record durable writes. */ +export interface KvFacet { + /** + * Open one unit, creating it when the medium holds no trace of it yet + * (materialization may defer to the first write, but {@link KvUnit.loadAll} + * must immediately serve the empty shape). A version already stamped on the + * medium that differs from `descriptor.version` rejects with + * `version-mismatch`; a medium that cannot be parsed as this unit rejects + * with `malformed-medium`. Opening the same unit name twice without closing + * is a caller bug and rejects. + * @param descriptor - Static identity and shape of the unit to open. + * @returns the opened unit. + */ + open(descriptor: KvUnitDescriptor): Promise; +} +/** Static identity and shape of one KV unit, projected from its owner's spec. */ +export interface KvUnitDescriptor { + /** Unit name; must match {@link UNIT_NAME_RE}. Also the file-name / SQL-identifier segment. */ + readonly name: string; + /** Unit format version; a non-negative integer stamped on the medium at first materialization. */ + readonly version: number; + /** Table names; each must match {@link UNIT_NAME_RE}. */ + readonly tables: readonly string[]; + /** Whether this unit carries the global singleton slot. */ + readonly hasGlobal: boolean; +} +/** + * One opened unit. Values are opaque JSON to this layer: no schema, no + * events, no domain meaning. The unit does NOT serialize concurrent writes — + * write ordering is the caller's responsibility (the domain layer runs one + * write chain per unit); the unit only guarantees that each single call is + * atomic on the medium and durable once resolved (a crash after resolution + * followed by a re-open observes the write). Any call after {@link close} + * rejects with `closed`. + */ +export interface KvUnit { + /** + * Read the full current snapshot. + * @returns every table's records keyed by table name, plus the global + * singleton (`null` when never written or not declared). + */ + loadAll(): Promise<{ + tables: Record>; + global: unknown; + }>; + /** + * Upsert one record durably. Overwrite semantics: an existing key is replaced. + * @param table - Declared table name. + * @param key - Record key; any string is safe (keys never reach file paths). + * @param value - Opaque JSON-serializable record. + * @returns resolution after durability. + */ + putRecord(table: string, key: string, value: unknown): Promise; + /** + * Delete one record durably. Idempotent: a missing key is a no-op. + * @param table - Declared table name. + * @param key - Record key. + * @returns resolution after durability. + */ + deleteRecord(table: string, key: string): Promise; + /** + * Write the global singleton durably. Only valid when the descriptor + * declared `hasGlobal`. + * @param value - Opaque JSON-serializable value. + * @returns resolution after durability. + */ + setGlobal(value: unknown): Promise; + /** + * Drain this unit's in-flight writes and release it. Idempotent. + * @returns resolution after the unit is released. + */ + close(): Promise; +} +//# sourceMappingURL=backend.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/error.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/error.d.ts new file mode 100644 index 0000000..5bc6914 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/error.d.ts @@ -0,0 +1,21 @@ +/** + * Error vocabulary for the storage hub and its backends. + * @module @deepseek-ai/dsh-storage/src/error + */ +/** Discriminant codes carried by every {@link StorageError}. */ +export type StorageErrorCode = 'backend-not-found' | 'form-not-mounted' | 'duplicate-backend' | 'duplicate-mount' | 'version-mismatch' | 'malformed-medium' | 'closed'; +/** + * Error thrown by the hub and by backend implementations. The `code` is the + * stable contract consumers may switch on; `message` is diagnostic prose. + */ +export declare class StorageError extends Error { + readonly code: StorageErrorCode; + readonly name = "StorageError"; + /** + * @param code - Stable discriminant for the failure class. + * @param message - Human-readable diagnostic detail. + * @param options - Standard error options (`cause`). + */ + constructor(code: StorageErrorCode, message: string, options?: ErrorOptions); +} +//# sourceMappingURL=error.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/index.d.ts new file mode 100644 index 0000000..6dfaaa8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/index.d.ts @@ -0,0 +1,64 @@ +/** + * Storage hub (`ctx.storage`): a named backend registry plus mounted + * data-form facilities. The hub itself performs no IO — backends own media, + * data forms (the domain layer first) own semantics. + * @module @deepseek-ai/dsh-storage + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import { BackendRegistry } from './registry.ts'; +export { BackendRegistry } from './registry.ts'; +export { StorageError } from './error.ts'; +export type { StorageErrorCode } from './error.ts'; +export { UNIT_NAME_RE } from './backend.ts'; +export type { StorageBackend, KvFacet, KvUnit, KvUnitDescriptor } from './backend.ts'; +/** + * Derive the Cordis lifecycle service that one named backend plugin provides. + * Domain-form providers inject these keys so activation cannot race backend + * registration even though callers continue resolving backends through the + * storage registry. + * @param name - Backend registry name. + * @returns the corresponding lifecycle-only service key. + */ +export declare function storageBackendServiceKey(name: string): string; +declare module '@deepseek-ai/cordis' { + interface Context { + storage: Storage; + } +} +/** + * Data forms mountable on the hub, keyed by form name. Form owners extend + * this map via declaration merging (the domain layer merges + * `domain: DomainFacility`) and mount the facility in their `apply`. + */ +export interface StorageForms { +} +/** + * The storage hub service. Backends register under `backend`; data forms + * mount under their `StorageForms` key and are reached as `ctx.storage.`. + */ +export declare class Storage extends Service { + /** Named backend table; multiple backends stay mounted side by side. */ + readonly backend: BackendRegistry; + private readonly forms; + constructor(ctx: Context); + /** + * Mount a data-form facility on the hub. Mounting is an effect: the + * returned disposer unmounts the form. + * @param form - Form key declared in {@link StorageForms}. + * @param facility - The facility instance to expose. + * @returns the disposer that unmounts the form. + */ + mount(form: K, facility: StorageForms[K]): () => void; + /** + * Resolve a mounted data form. + * @param form - Form key declared in {@link StorageForms}. + * @returns the mounted facility. + */ + form(form: K): StorageForms[K]; + /** Domain data form; present once the domain layer plugin is loaded. */ + get domain(): StorageForms extends { + domain: infer D; + } ? D : never; +} +export default Storage; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/invariant.d.ts new file mode 100644 index 0000000..d91d221 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-storage`. + * @module @deepseek-ai/dsh-storage/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "storage-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/registry.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/registry.d.ts new file mode 100644 index 0000000..814c2be --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/lib/types/registry.d.ts @@ -0,0 +1,34 @@ +/** + * Named backend registry of the storage hub. + * @module @deepseek-ai/dsh-storage/src/registry + */ +import type { StorageBackend } from './backend.ts'; +/** + * Mutable name → backend table. Multiple backends stay mounted side by side; + * which backend serves which consumer is the consumer's configuration + * (e.g. the domain layer's route table), never a hub-global choice. + */ +export declare class BackendRegistry { + private readonly backends; + /** + * Register a named backend. Registration is an effect: the returned + * disposer removes the name. Disposal does NOT close the backend — the + * owning plugin closes it after unregistering. + * @param name - Backend name, e.g. `json` or `sqlite`. + * @param backend - The backend instance. + * @returns the disposer that unregisters the name. + */ + register(name: string, backend: StorageBackend): () => void; + /** + * Resolve a backend by name. + * @param name - Registered backend name. + * @returns the backend. + */ + get(name: string): StorageBackend; + /** + * Registered backend names, for diagnostics. + * @returns a snapshot array of names. + */ + names(): string[]; +} +//# sourceMappingURL=registry.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/package.json new file mode 100644 index 0000000..7046635 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-storage", + "description": "Storage hub (ctx.storage): named backend registry plus mounted data-form facilities for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/storage/storage" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.i18n.yaml new file mode 100644 index 0000000..09fa051 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/storage/storage/README.md +README.md: bf827220afe0d8b1cbc53b3a12e6d0034004e1d2 +README.zh.md: 86b6994d74a727275e0bcaea2a83bd51f93b6ca1 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.md new file mode 100644 index 0000000..bf82722 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.md @@ -0,0 +1,32 @@ +# @deepseek-ai/dsh-storage + +English | [中文](README.zh.md) + +Storage hub (`ctx.storage`) for non-session data: a named backend registry plus mounted data-form facilities. The hub performs no IO itself — backends own media, and data forms own semantics. The [storage family overview](../README.md) maps those packages; the [domain KV storage Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md) records the design rationale. + +## Shape + +- `ctx.storage.backend` — name → backend table. Multiple backends stay mounted side by side (`json`, `sqlite`); which backend serves a consumer is that consumer's configuration (the domain layer's route table), never a hub-global choice. `register()` returns the disposer; duplicate names and unknown lookups fail loud. +- `ctx.storage.mount(form, facility)` / `ctx.storage.form(form)` — data-form mounting. `StorageForms` is merge-extensible; the domain layer merges `domain` and is reached as `ctx.storage.domain`. +- A backend owns one medium and exposes the data-shape facets it supports. `kv` is the current facet; `src/backend.ts` owns its exact contract. + +## Model Experience + +### Backend and form registrations + +#### What the model sees + +Nothing. `ctx.storage` is a host-side registration table; the hub registers no tools, injects no prompts, and writes no session events. + +#### Token effect + +Zero direct tokens on every request. + +#### KV Cache effect + +Independent of live requests: the hub never touches a request prefix, so it cannot invalidate provider cache reuse. + +## Known Limitations and Deferred Work + +- **`kv` is the only data shape** — backends currently have one facet to implement. +- **Forms resolve lazily** — reading `ctx.storage.domain` before the domain plugin mounts throws `form-not-mounted`; assemblies order plugins accordingly (misconfiguration fails loud rather than silently deferring). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.zh.md new file mode 100644 index 0000000..86b6994 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/README.zh.md @@ -0,0 +1,32 @@ +# @deepseek-ai/dsh-storage + +[English](README.md) | 中文 + +非会话数据的存储中心(`ctx.storage`):具名后端注册表加已挂载的数据形式设施。中心自身不执行 IO:后端拥有介质,数据形式拥有语义。[存储家族概述](../README.md)列出了这些包;[领域 KV 存储 Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md)记录了设计理由。 + +## 结构 + +- `ctx.storage.backend`:名称 → 后端表。多个后端并排保持挂载(`json`、`sqlite`);为消费方提供服务的后端由该消费方自身的配置决定(领域层的路由表),绝非中心的全局选择。`register()` 返回资源释放函数;注册重复名称或查找未知名称时都会明确报错。 +- `ctx.storage.mount(form, facility)`/`ctx.storage.form(form)`:数据形式挂载。`StorageForms` 可通过合并扩展;领域层合并 `domain`,并通过 `ctx.storage.domain` 访问。 +- 后端拥有一种介质,并公开其支持的数据形状**分面**。当前分面为 `kv`;`src/backend.ts` 负责定义其确切约定。 + +## 模型体验 + +### 后端与形式注册 + +#### 模型看到的内容 + +无。`ctx.storage` 是主机侧注册表;中心不注册工具、不注入提示词,也不写入会话事件。 + +#### Token 影响 + +每次请求都不会直接增加 token。 + +#### KV Cache 影响 + +与实时请求相互独立:中心绝不触碰请求前缀,因此无法使提供方缓存复用失效。 + +## 已知限制与暂缓事项 + +- **`kv` 是唯一的数据形状**:后端目前只有一个分面需要实现。 +- **数据形式按需解析**:在领域插件挂载前读取 `ctx.storage.domain` 会抛出 `form-not-mounted`;组装会按相应顺序排列插件(错误配置会明确报错,而不是静默推迟处理)。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/index.js new file mode 100644 index 0000000..33229d6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/index.js @@ -0,0 +1,140 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/error.js +/** +* Error vocabulary for the storage hub and its backends. +* @module @deepseek-ai/dsh-storage/src/error +*/ +/** +* Error thrown by the hub and by backend implementations. The `code` is the +* stable contract consumers may switch on; `message` is diagnostic prose. +*/ +var StorageError = class extends Error { + code; + name = "StorageError"; + /** + * @param code - Stable discriminant for the failure class. + * @param message - Human-readable diagnostic detail. + * @param options - Standard error options (`cause`). + */ + constructor(code, message, options) { + super(message, options); + this.code = code; + } +}; +//#endregion +//#region lib/types/registry.js +/** +* Named backend registry of the storage hub. +* @module @deepseek-ai/dsh-storage/src/registry +*/ +/** +* Mutable name → backend table. Multiple backends stay mounted side by side; +* which backend serves which consumer is the consumer's configuration +* (e.g. the domain layer's route table), never a hub-global choice. +*/ +var BackendRegistry = class { + backends = /* @__PURE__ */ new Map(); + /** + * Register a named backend. Registration is an effect: the returned + * disposer removes the name. Disposal does NOT close the backend — the + * owning plugin closes it after unregistering. + * @param name - Backend name, e.g. `json` or `sqlite`. + * @param backend - The backend instance. + * @returns the disposer that unregisters the name. + */ + register(name, backend) { + if (this.backends.has(name)) throw new StorageError("duplicate-backend", `storage backend '${name}' is already registered`); + this.backends.set(name, backend); + return () => { + if (this.backends.get(name) === backend) this.backends.delete(name); + }; + } + /** + * Resolve a backend by name. + * @param name - Registered backend name. + * @returns the backend. + */ + get(name) { + const backend = this.backends.get(name); + if (!backend) throw new StorageError("backend-not-found", `storage backend '${name}' is not registered (registered: ${[...this.backends.keys()].join(", ") || "none"})`); + return backend; + } + /** + * Registered backend names, for diagnostics. + * @returns a snapshot array of names. + */ + names() { + return [...this.backends.keys()]; + } +}; +//#endregion +//#region lib/types/backend.js +/** +* Backend-facing vocabulary of the storage hub: a backend owns one medium +* (a file-tree root, a database file) and exposes operation groups over it. +* This module defines the normative contract text for backend implementers; the shared +* conformance suite in `tests/contract.ts` checks every rule. +* @module @deepseek-ai/dsh-storage/src/backend +*/ +/** Allowed format for unit and table names: safe as a file name and as a SQL identifier segment without escaping. */ +const UNIT_NAME_RE = /^[a-z][a-z0-9_]*$/; +//#endregion +//#region lib/types/index.js +/** +* Storage hub (`ctx.storage`): a named backend registry plus mounted +* data-form facilities. The hub itself performs no IO — backends own media, +* data forms (the domain layer first) own semantics. +* @module @deepseek-ai/dsh-storage +*/ +/** +* Derive the Cordis lifecycle service that one named backend plugin provides. +* Domain-form providers inject these keys so activation cannot race backend +* registration even though callers continue resolving backends through the +* storage registry. +* @param name - Backend registry name. +* @returns the corresponding lifecycle-only service key. +*/ +function storageBackendServiceKey(name) { + return `storage.backend.${name}`; +} +/** +* The storage hub service. Backends register under `backend`; data forms +* mount under their `StorageForms` key and are reached as `ctx.storage.`. +*/ +var Storage = class extends Service { + /** Named backend table; multiple backends stay mounted side by side. */ + backend = new BackendRegistry(); + forms = /* @__PURE__ */ new Map(); + constructor(ctx) { + super(ctx, "storage"); + } + /** + * Mount a data-form facility on the hub. Mounting is an effect: the + * returned disposer unmounts the form. + * @param form - Form key declared in {@link StorageForms}. + * @param facility - The facility instance to expose. + * @returns the disposer that unmounts the form. + */ + mount(form, facility) { + if (this.forms.has(form)) throw new StorageError("duplicate-mount", `storage form '${String(form)}' is already mounted`); + this.forms.set(form, facility); + return () => { + if (this.forms.get(form) === facility) this.forms.delete(form); + }; + } + /** + * Resolve a mounted data form. + * @param form - Form key declared in {@link StorageForms}. + * @returns the mounted facility. + */ + form(form) { + if (!this.forms.has(form)) throw new StorageError("form-not-mounted", `storage form '${String(form)}' is not mounted`); + return this.forms.get(form); + } + /** Domain data form; present once the domain layer plugin is loaded. */ + get domain() { + return this.form("domain"); + } +}; +//#endregion +export { BackendRegistry, Storage, Storage as default, StorageError, UNIT_NAME_RE, storageBackendServiceKey }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/invariant.js new file mode 100644 index 0000000..07064f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/invariant.js @@ -0,0 +1,25 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-storage`. +* @module @deepseek-ai/dsh-storage/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-storage"; +/** Cordis companion plugin name. */ +const name = "storage-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the hub is a pure registration table (names → +* backends, forms → facilities) whose consistency is fully enforced at the +* call sites (duplicate/missing entries fail loud synchronously); it owns no +* event stream or mutable medium to cross-check. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/backend.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/backend.d.ts new file mode 100644 index 0000000..6f14bfd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/backend.d.ts @@ -0,0 +1,98 @@ +/** + * Backend-facing vocabulary of the storage hub: a backend owns one medium + * (a file-tree root, a database file) and exposes operation groups over it. + * This module defines the normative contract text for backend implementers; the shared + * conformance suite in `tests/contract.ts` checks every rule. + * @module @deepseek-ai/dsh-storage/src/backend + */ +/** Allowed format for unit and table names: safe as a file name and as a SQL identifier segment without escaping. */ +export declare const UNIT_NAME_RE: RegExp; +/** + * One registered backend. A backend owns exactly one medium and shares its + * lifecycle across all facets; facets are optional members — a backend that + * cannot serve a data kind simply omits it, and resolution fails loud instead. + */ +export interface StorageBackend { + /** Key-value operations; absent when this backend cannot serve them. */ + readonly kv?: KvFacet; + /** + * Drain in-flight writes across all open units and release the medium. + * Idempotent; concurrent and repeated calls resolve once teardown finishes. + * @returns resolution after the medium is released. + */ + close(): Promise; +} +/** The key-value data shape: whole-unit snapshots plus per-record durable writes. */ +export interface KvFacet { + /** + * Open one unit, creating it when the medium holds no trace of it yet + * (materialization may defer to the first write, but {@link KvUnit.loadAll} + * must immediately serve the empty shape). A version already stamped on the + * medium that differs from `descriptor.version` rejects with + * `version-mismatch`; a medium that cannot be parsed as this unit rejects + * with `malformed-medium`. Opening the same unit name twice without closing + * is a caller bug and rejects. + * @param descriptor - Static identity and shape of the unit to open. + * @returns the opened unit. + */ + open(descriptor: KvUnitDescriptor): Promise; +} +/** Static identity and shape of one KV unit, projected from its owner's spec. */ +export interface KvUnitDescriptor { + /** Unit name; must match {@link UNIT_NAME_RE}. Also the file-name / SQL-identifier segment. */ + readonly name: string; + /** Unit format version; a non-negative integer stamped on the medium at first materialization. */ + readonly version: number; + /** Table names; each must match {@link UNIT_NAME_RE}. */ + readonly tables: readonly string[]; + /** Whether this unit carries the global singleton slot. */ + readonly hasGlobal: boolean; +} +/** + * One opened unit. Values are opaque JSON to this layer: no schema, no + * events, no domain meaning. The unit does NOT serialize concurrent writes — + * write ordering is the caller's responsibility (the domain layer runs one + * write chain per unit); the unit only guarantees that each single call is + * atomic on the medium and durable once resolved (a crash after resolution + * followed by a re-open observes the write). Any call after {@link close} + * rejects with `closed`. + */ +export interface KvUnit { + /** + * Read the full current snapshot. + * @returns every table's records keyed by table name, plus the global + * singleton (`null` when never written or not declared). + */ + loadAll(): Promise<{ + tables: Record>; + global: unknown; + }>; + /** + * Upsert one record durably. Overwrite semantics: an existing key is replaced. + * @param table - Declared table name. + * @param key - Record key; any string is safe (keys never reach file paths). + * @param value - Opaque JSON-serializable record. + * @returns resolution after durability. + */ + putRecord(table: string, key: string, value: unknown): Promise; + /** + * Delete one record durably. Idempotent: a missing key is a no-op. + * @param table - Declared table name. + * @param key - Record key. + * @returns resolution after durability. + */ + deleteRecord(table: string, key: string): Promise; + /** + * Write the global singleton durably. Only valid when the descriptor + * declared `hasGlobal`. + * @param value - Opaque JSON-serializable value. + * @returns resolution after durability. + */ + setGlobal(value: unknown): Promise; + /** + * Drain this unit's in-flight writes and release it. Idempotent. + * @returns resolution after the unit is released. + */ + close(): Promise; +} +//# sourceMappingURL=backend.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/error.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/error.d.ts new file mode 100644 index 0000000..5bc6914 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/error.d.ts @@ -0,0 +1,21 @@ +/** + * Error vocabulary for the storage hub and its backends. + * @module @deepseek-ai/dsh-storage/src/error + */ +/** Discriminant codes carried by every {@link StorageError}. */ +export type StorageErrorCode = 'backend-not-found' | 'form-not-mounted' | 'duplicate-backend' | 'duplicate-mount' | 'version-mismatch' | 'malformed-medium' | 'closed'; +/** + * Error thrown by the hub and by backend implementations. The `code` is the + * stable contract consumers may switch on; `message` is diagnostic prose. + */ +export declare class StorageError extends Error { + readonly code: StorageErrorCode; + readonly name = "StorageError"; + /** + * @param code - Stable discriminant for the failure class. + * @param message - Human-readable diagnostic detail. + * @param options - Standard error options (`cause`). + */ + constructor(code: StorageErrorCode, message: string, options?: ErrorOptions); +} +//# sourceMappingURL=error.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/index.d.ts new file mode 100644 index 0000000..6dfaaa8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/index.d.ts @@ -0,0 +1,64 @@ +/** + * Storage hub (`ctx.storage`): a named backend registry plus mounted + * data-form facilities. The hub itself performs no IO — backends own media, + * data forms (the domain layer first) own semantics. + * @module @deepseek-ai/dsh-storage + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import { BackendRegistry } from './registry.ts'; +export { BackendRegistry } from './registry.ts'; +export { StorageError } from './error.ts'; +export type { StorageErrorCode } from './error.ts'; +export { UNIT_NAME_RE } from './backend.ts'; +export type { StorageBackend, KvFacet, KvUnit, KvUnitDescriptor } from './backend.ts'; +/** + * Derive the Cordis lifecycle service that one named backend plugin provides. + * Domain-form providers inject these keys so activation cannot race backend + * registration even though callers continue resolving backends through the + * storage registry. + * @param name - Backend registry name. + * @returns the corresponding lifecycle-only service key. + */ +export declare function storageBackendServiceKey(name: string): string; +declare module '@deepseek-ai/cordis' { + interface Context { + storage: Storage; + } +} +/** + * Data forms mountable on the hub, keyed by form name. Form owners extend + * this map via declaration merging (the domain layer merges + * `domain: DomainFacility`) and mount the facility in their `apply`. + */ +export interface StorageForms { +} +/** + * The storage hub service. Backends register under `backend`; data forms + * mount under their `StorageForms` key and are reached as `ctx.storage.`. + */ +export declare class Storage extends Service { + /** Named backend table; multiple backends stay mounted side by side. */ + readonly backend: BackendRegistry; + private readonly forms; + constructor(ctx: Context); + /** + * Mount a data-form facility on the hub. Mounting is an effect: the + * returned disposer unmounts the form. + * @param form - Form key declared in {@link StorageForms}. + * @param facility - The facility instance to expose. + * @returns the disposer that unmounts the form. + */ + mount(form: K, facility: StorageForms[K]): () => void; + /** + * Resolve a mounted data form. + * @param form - Form key declared in {@link StorageForms}. + * @returns the mounted facility. + */ + form(form: K): StorageForms[K]; + /** Domain data form; present once the domain layer plugin is loaded. */ + get domain(): StorageForms extends { + domain: infer D; + } ? D : never; +} +export default Storage; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/invariant.d.ts new file mode 100644 index 0000000..d91d221 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-storage`. + * @module @deepseek-ai/dsh-storage/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "storage-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/registry.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/registry.d.ts new file mode 100644 index 0000000..814c2be --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/lib/types/registry.d.ts @@ -0,0 +1,34 @@ +/** + * Named backend registry of the storage hub. + * @module @deepseek-ai/dsh-storage/src/registry + */ +import type { StorageBackend } from './backend.ts'; +/** + * Mutable name → backend table. Multiple backends stay mounted side by side; + * which backend serves which consumer is the consumer's configuration + * (e.g. the domain layer's route table), never a hub-global choice. + */ +export declare class BackendRegistry { + private readonly backends; + /** + * Register a named backend. Registration is an effect: the returned + * disposer removes the name. Disposal does NOT close the backend — the + * owning plugin closes it after unregistering. + * @param name - Backend name, e.g. `json` or `sqlite`. + * @param backend - The backend instance. + * @returns the disposer that unregisters the name. + */ + register(name: string, backend: StorageBackend): () => void; + /** + * Resolve a backend by name. + * @param name - Registered backend name. + * @returns the backend. + */ + get(name: string): StorageBackend; + /** + * Registered backend names, for diagnostics. + * @returns a snapshot array of names. + */ + names(): string[]; +} +//# sourceMappingURL=registry.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/package.json new file mode 100644 index 0000000..1f43fa7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-storage", + "description": "Storage hub (ctx.storage): named backend registry plus mounted data-form facilities for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/storage/storage" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-agent-presets b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-agent-presets new file mode 120000 index 0000000..485bbde --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-agent-presets @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent-presets@0.1.0-rc.6_4c20af7d23bdb1bbe92fd5e1e7ddef5d/node_modules/@deepseek-ai/dsh-agent-presets \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-jobs b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-jobs new file mode 120000 index 0000000..e453c9c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-jobs @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-jobs@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_12c564ff6efdb2c2a5dc8f402d25078d/node_modules/@deepseek-ai/dsh-jobs \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..a0535b0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..fb5edd1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_64a6b0602a631355cd8e96ecf58f6c70/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-projection-cache b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-projection-cache new file mode 120000 index 0000000..4edc1ab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-session-projection-cache @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.6_dd975d4b23df368efdec0af129bff74d/node_modules/@deepseek-ai/dsh-session-projection-cache \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.i18n.yaml new file mode 100644 index 0000000..6d443fc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/subagent/subagent/README.md +README.md: ed4a9123a2dfa5b2fa5abc67f4513547feb3d140 +README.zh.md: 3ad2ee5738a210a776d1f0b2746dcbd21d46144c diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.md new file mode 100644 index 0000000..ed4a912 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.md @@ -0,0 +1,154 @@ +# @deepseek-ai/dsh-subagent + +English | [中文](README.zh.md) + +The subagent seam lets one agent delegate work to a child through a named provider. Callers use one service API (`ctx.subagents`); providers decide whether the child runs in this process, in another process, or through a future transport. + +The [subagent family overview](../README.md) maps implementations and model-facing consumers. This package owns the provider registry, shared request and result contracts, durable descriptors, and continuable-child orchestration. Multiple named providers may coexist behind that contract. + +## Service API + +`SubagentRuntime` has these operations: + +| Member | Meaning | +|---|---| +| `registerProvider(provider)` | Register one trusted same-process implementation by name. Registration is effect-scoped; removing it prevents new starts but does not revoke runs already returned to callers. Duplicate names fail loud. | +| `getProvider(name)` | Return the provider, or `undefined` when absent. | +| `list()` | Return provider names in insertion order. | +| `start(name, request)` | Validate an ordinary caller request, resolve its detached `one-shot` descriptor, then await the provider until a real one-shot child is published. Fulfillment returns a holder-owned `SubagentRun`; rejection means the provider has already cleaned every unpublished startup resource, while post-publication turn or infrastructure faults settle through the run. Continuable children never enter through this operation. | +| `startContinuable(spec)` | Establish one durable continuable child and deliver its initial prompt. Resolves with `{ childId, messageId }` when the child's inbox accepts that prompt, without waiting for the turn to start or for the message to reach the Session log; any earlier failure rejects with no ids and rolls the child back entirely. Requires `ctx.agents`, session persistence, and a provider with the `prepareContinuable` capability. | +| `followup(parent, childId, content, { source, signal })` | Deliver one later message from the exact live direct parent as the child's next FIFO turn, matching `Agent.followup()` terminology, and return the accepted `MessageId`. A resident child's inbox accepts it directly (waking a waiting Activation); an absent one cold-resumes from its persisted Session. Requires `ctx.agents`; cold resume also requires session persistence. | +| `interrupt(targetSessionId, authority)` | Interrupt one live continuable child's current turn under a human durable parent address (`{ kind: 'user', parentSessionId }`) or an exact live ancestor Agent (`{ kind: 'ancestor', agent }`). Admission is synchronous and the effect asynchronous: it issues `Agent.cancel(cause, { keepInbox: true })` and returns without waiting for the target to observe the signal. Unclaimed pending inbox work, the Activation, and published descendants are preserved; work already claimed into the interrupted turn is not requeued. An absent target is an accepted no-op; a wrong parent address or a stale, self-targeting, or non-ancestor caller rejects with `UNAUTHORIZED`. | +| `reportFrom(child, content, { delivery, signal })` | Deliver one selected message from the exact live continuable child to its exact live direct parent and return the accepted stable `MessageId`. Quiet delivery injects context; waking delivery submits one later parent turn. | +| `registerContinuableSetup(contribution)` | Compose an optional deployment capability into each continuable child's unpublished scope, with immediate revocation from resident children. | +| `drainContinuableDescendants(parents)` | Close admission below exact live host-owned parent Agents, stop only their visible continuable descendants, await materializations admitted below those roots through publication or rollback, then release the selected forests child-first. The cutoff lasts until each exact parent leaves the registry; unrelated parent forests and manager-wide admission remain live. | +| `listChildren(parentSessionId, signal?)` | List direct session-backed subagents with their `one-shot`/`continuable` mode, `running`/`inactive` activity, origin-classified one-level `hasChildren` hint, and per-child diagnostics, ordered by `createdAt` then id, without loading or resuming them. Reads the live session store and optional session persistence directly (live-only enumeration when persistence is absent) and requires the mounted `sessionProjections` registry; it does not require `ctx.agents`, the continuation manager, or any query service. | +| `listDescendants(rootSessionId, signal?)` | Flatten the root's complete session tree in stable pre-order from the same live-preferred corpus, adding each subagent entry's durable `parentId` and root-relative `depth`. Ordinary sessions and one-shot children remain traversal nodes so continuable descendants below them are discovered. Identity, diagnostics, dependencies, and cancellation follow `listChildren()`. | + +`SubagentStartRequest.label` is an optional short durable display label for a session-backed one-shot child. Model-facing delegation supplies its existing `description`; lower-level callers need not invent presentation metadata. Continuable starts always carry their own required label. `signal` is required and is the canonical cancellation channel for a one-shot `start`. An abort before publication makes `start()` reject after rollback; an abort after publication cancels the returned run's remaining turn work without hiding its id. The request may also select a model, require structured output, cap delegation depth, restrict child tools, or set a child persona. For a continuable start or follow-up, the caller signal owns lookup, materialization, and admission only until inbox acceptance; afterward the manager owns the Activation independently, so later caller cancellation neither cancels the accepted turn nor disposes the child. + +Follow-up authority comes from the exact live direct parent recorded in the child's durable header. Cold resume checks that authority before reconstruction and again in the final no-await inbox-admission span, so a parent unregistered or replaced during materialization cannot authorize delivery. The `source` on a follow-up records who supplied the delivered message and grants no authority. + +Same-process requests, descriptors, results, and event payloads are trusted typed values borrowed as immutable. The service does not clone or freeze them; serialization and hostile-input validation belong at actual process, worker, persistence, and model boundaries. + +## Capabilities + +Start-time features are advertised in `provider.capabilities` because the service must reject an unsupported one-shot request before child creation: + +- `outputSchema` — enforce a structured final result. +- `depthLimit` — enforce `maxDepth`. +- `toolFilter` — apply the requested child tool restriction. +- `persona` — apply a per-child persona. + +Every in-process child is composed by one call, `applyChildComposition(childCtx, parent, composition)`, which joins the parent's agent-preset composition before applying the child's own persona and tool filter. The join is what gives the child its capabilities: with every model-facing row on the agent plane, a child that joined nothing would reach the model with an empty tool registry ([`dsh-agent-presets`](../../preset/agent-presets/README.md)). Taking the parent as a parameter is deliberate — it makes composing a child WITHOUT that join unrepresentable at the call sites, which is the defect the one call exists to prevent. A deployment composing no preset roster joins nothing and needs nothing: its model-facing rows sit in the host composition, where the child already resolves them through the tool registry's global layer. + +`childSessionMeta()` records the joined preset id on the child's durable header for the same reason a top-level session records its own: the preset decides the tool schemas and prompt sections the model saw, so a cold read of the child's history has to rebuild that composition rather than the deployment default. It is read from the parent's live scope chain, not from the parent header, because a parent that switched preset while blank runs on the newer composition while its header still names the older one. + +Continuable creation is the optional `SubagentProvider.prepareContinuable?()` method: its presence is the capability check, so the service rejects a configured continuable start on a provider without it, while a provider that has it may still serve ordinary one-shot delegations. The method returns only a detached `ContinuableCreateSpec` (`{ seed? }`) — data, never a capability: it carries no Agent, `AgentHandle`, prompt delivery, result, disposal, or resume operation, because the continuation manager owns identity reservation, composition, Agent creation, prompt delivery, cold resume, ownership, and disposal after preparation. A one-shot `SubagentRun` represents one disposable foreground delegation with one result and no cold-resume operation. The service may invoke one provider concurrently for distinct siblings: each start or preparation owns its mutable state and cancellation path, and one operation's failure, result, or cleanup must not settle or release another. A provider may queue its own capacity internally without changing that independence contract. + +## The durable descriptor + +The Service Definition owns the versioned `subagent/descriptor` session event vocabulary (`src/descriptor.ts`): `snapshotSubagentDescriptor()` validates and detaches the record before provider work, and `foldSubagentDescriptor()` validates the complete current-version payload before recovering it from a loaded child log. Every local session-backed start appends one descriptor with the provider name and lifecycle `mode`. A `one-shot` descriptor optionally carries the caller-owned durable display `label`; a `continuable` descriptor requires its durable creation label and additionally records resolved child `agentOptions.provider`/`model` and optional `persona`/`toolFilter` for cold resume. These are explicit fields, never the merge-extensible `AgentOptions` object, so an unrelated extension value cannot break continuation. The descriptor omits `subagentDepth` (the persisted header's `delegationDepth` is the monotone floor) and `outputSchema` (an Activation's result contract). The event is log-only: no `surfaceOp`, absent from model history, and retained by the append-only log across compaction. Malformed current-version payloads are corrupt; unsupported versions cannot be classified by this runtime. + +## Delegation depth + +The seam owns the depth vocabulary shared by Service Providers and Consumers: the `AgentOptions.subagentDepth` declaration, `assertSubagentMaxDepth`, and `delegationDepthOf(agent)`. The persisted `SessionHeader.delegationDepth` is authoritative and monotone — runtime options may deepen the count but never lower it, so a resumed child cannot be re-counted as top-level. + +`inheritsParentContext` is descriptive rather than enforceable. It says only whether the child sees completed parent conversation history (`fork` does; `spawn` and the out-of-process one-shot providers do not), not whether it inherits tools, services, or authority. + +## Delegated policy + +Both in-process delegation paths fix the child's permission scope at the delegation boundary through the shared child-agent helpers. `captureDelegatedPolicyOverrides(parent)` snapshots the parent session's explicit sandbox override (`sandboxPolicy.overrideOf()`) and pins the child's approval policy to `'never'` whenever the approval capability is composed — regardless of the parent's own policy — so a delegated child acts only within its inherited sandbox scope and every ask (for example a `sandbox_permissions` escalation) is rejected deterministically instead of waiting on a prompt no one is watching (both services are optional `ctx.get` consumers). `appendDelegatedPolicyOverrides()` writes each value onto the child's own log as a `source: 'delegation'` `sandbox/mode` or `approval/policy` event during unpublished setup, after any fork seed — so fresh policy wins stale seed state and the child's effective policy stays reconstructable from its log alone. The sandbox deployment default is never copied: an unswitched parent stamps no `sandbox/mode` and its child follows the deployment default dynamically. A continuable start captures before its first await and seeds only fresh materialization; a cold resume replays the persisted delegation events instead of re-capturing the parent, so a parent switch after creation never retroactively changes a durable child. Every in-process child also receives a scoped runtime-context statement (`subagent:delegation`) telling it the scope is fixed and that a task needing wider access ends with a reported limitation, not retries. See the [one-shot](../../../.agents/notes/implemented/feature/2026-07-25-subagent-policy-inheritance.md) and [continuable](../../../.agents/notes/implemented/feature/2026-08-10-continuable-subagent-policy-inheritance.md) delegation-policy Agent Notes. + +## One-shot ownership and lifecycle + +`provider.start(request): Promise` is the ownership-transfer boundary; the delegation tool also uses it inside its one-shot Task-backed background path. Before fulfillment, the provider owns setup and must cancel, roll back, and quiesce unpublished resources on every failure. After fulfillment, the caller owns the run and must call `dispose()` on every path; remaining prompt and turn work belongs to `SubagentRun.result`. + +`SubagentRun.result` resolves to `{ output, structured?, stopReason }`. Child-level failures resolve with a non-`completed` reason; only an infrastructure fault that the seam cannot represent may reject. `dispose()` is idempotent, cancels remaining work, and waits for both result settlement and child-resource quiescence. A result rejection remains on `result`; `dispose()` rejects only for an independent resource-release failure. `output` and the `subagent/end` event's `lastAssistantMessage` use the exported `AssistantOutputFold`/`finalAssistantOutput` helpers to select the child's last non-empty assistant message, or its accumulated assistant text when no such message exists. `output` is `[]` and the event field is absent when the child produced neither ([`SubagentResult.output`](../../../docs/subsystems/subagent.md#the-terminal-result-subagentresult) owns the result contract). + +A local run publishes an ordinary child agent/session before `start()` fulfills, returns that shared session id as `SubagentRun.id`, exposes the exact child as `SubagentRun.localAgent`, records `request.parent.session.id` in the child's `parentSession` header, and appends the resolved descriptor inside its initial turn. Remote providers instead mint a parent-scoped lifecycle id and return `localAgent: undefined`; without a local child session, their one-shot runs are not part of trace-backed enumeration. + +## Continuable children and Activations + +A continuable child has one durable Session and at most one process-local **Activation** — one residency epoch for a reconstructed child Agent, not a request, result, cancellation, or Task boundary. The Agent inbox is the only turn queue, so the continuation manager owns residency while the Agent loop owns all turn ordering and execution. No continuable path creates a Task or an intermediate result-bearing wrapper. + +The manager derives three internal residency conditions from Agent quiescence and the owned-child set rather than maintaining a second state machine: running (an active admission, open turn, or waking inbox work), waiting (quiescent but still owning at least one undisposed child), and settled (quiescent with every owned child disposed, so the manager disposes the `AgentHandle` and removes the Activation). Every continuation message uses `Agent.followup()` and becomes one FIFO turn with no steering of the current turn. Routing depends only on residency: running enqueues, waiting wakes the same Agent, and an absent Activation cold-resumes a new one. + +The manager reserves the child identity, resolves the durable descriptor, calls `ctx.agents.create()` (or `ctx.agents.resume()` for cold resume) through a private activation-owner scope, installs the returned `AgentHandle` in the Activation, establishes any continuable-parent ownership, and then submits the prompt. Cold resume never dispatches through a provider because the persisted Session already holds the initial prefix and the folded descriptor is the whole reconstruction input. + +### Settlement delivery + +When a resident Activation settles, the manager tells the child's durable direct parent, in the parent's own turn stream, that the child produced everything it is going to. Delivery is unconditional for every child whose id a caller actually received: it does not consider whether the child called `report`, because the endings that most need an account — a token ceiling, a model failure, cancellation, teardown — are exactly the ones where the child never got to choose. A materialization rolled back before its first accepted message stays silent, since that caller was told the child was not established. The message carries the epoch's stop reason, its final assistant content when it produced any, and durable provenance `{ kind: 'subagent-settled', form: 'notice', senderSessionId: }` — a different source kind from a child-authored `subagent-report`, so a transcript never credits the child with words the runtime wrote. + +Two ordering rules make the delivery reliable rather than lucky, and both are why this belongs to the manager instead of an external `subagent/end` listener. First, the send happens **before** the child's ownership release, while the parent still counts the child and is therefore structurally unable to be judged settled. Second, a parent that is itself a resident Activation receives the message through the same waking-admission accounting as a report, so the window between the synchronous send and the microtask that admits it is not mistaken for quiescence — `Agent.status` folds context maintenance into `idle`, and a waking send behind maintenance only arms a deferred wake. Without either rule the parent can be disposed with the notice still in an inbox that `cancel()` clears, which loses it silently. + +An idle parent receives the notice as one ordinary later turn. A busy parent is steered into its nearest step boundary instead, so several children settling together cost one step rather than one turn each; steering rather than injecting also means a driver that retires between the status read and the send still claims the message. A parent whose own lineage is already draining receives the notice by injection, with no wake at all: `Agent.followup()` on a quiescent parent starts a turn and `cancel()` does not arm against a later one, so waking during teardown would spend a model request on an Agent its host is about to dispose — once per tree layer, since each layer's notice then wakes the layer above it. The injected message reaches a parent that is still reading its inbox, and the log records the account either way, but it does not outlive that parent's own disposal: `AgentHandle.dispose()` is a `keepInbox: false` cancel, which durably cancels an unclaimed notice. A resumed parent therefore has no pending notice to read: `list_agents` tells it which children exist and whether each is live or stored, while the outcome itself stays in the child's own Session, which a `send_message` reaches by resuming that child. A parent that has left the registry is not an error: the notice is dropped and the child's own Session remains the durable record. Delivery never blocks or fails teardown — a rejected send is logged, because retaining a child to retry a notice would pin its whole ancestry in `waiting` forever. + +A continuation-managed parent Activation records each child Session id in an `ownedChildren` set before the child can run and disposes only after every owned child Activation completes `AgentHandle` disposal (child-first). Teardown propagates Agent cancellation top-down before awaiting slow descendants, while handle release remains child-first. Top-level and other non-continuation Agents have no Activation and stay outside this waiting graph. Final settlement awaits a best-effort `ctx.sessions.flush(child.session)` before handle disposal. A listener rejection is logged without failing the Activation because listener participation does not identify a persistence backend; the persisted state may therefore be missing or stale on resume. + +## Lifecycle events + +The service emits a `subagent/start`/`subagent/end` pair for each one-shot run and each resident continuable Activation epoch, so continuable children are observable with the same vocabulary as one-shot runs without exposing whether the manager materialized, woke, or cold-resumed them. For a one-shot start it attaches the result observer before the synchronous `subagent/start`, so even an already-settled child still produces `subagent/start` before `subagent/end`; a continuable epoch that fails before residency emits neither edge. The pair shares a service-minted `runId`; the `local` flag is snapshotted from the provider's exact `localAgent` (always true for a continuable child), so observers never infer run identity or locality from reusable provider/session names. The `provider` field contains the provider name recorded when the child was first created rather than claiming current registration: an accepted one-shot run may settle after provider removal, and a cold-resumed epoch reads the initial provider name from its descriptor without calling or registering that provider. + +Run events are scoped to the delegating parent. Every listener is independently contained: a synchronous throw or rejected returned promise is logged without starving peer listeners or changing the run. + +Provider additions and removals also emit `subagent/provider-added` and `subagent/provider-removed`. Consumers such as the model-facing tool use those events because Cordis may load sibling plugins concurrently; configuration order does not prove registration order. + +Continuable children do not create `SubagentRun` or Jobs. The continuation manager directly owns one process-local Activation and retained `AgentHandle` per resident child Session, uses the Agent inbox as the only FIFO, and cold-resumes from the durable descriptor. Exact live direct-parent identity authorizes parent-to-child delivery. Exact live child identity authorizes reports; the manager derives the recipient from durable `parentSession`, and `MessageSource` records the sender without granting authority. Interrupt authority is deliberately wider than delivery authority: a human presents the durable direct-parent address so a live child stays stoppable while its parent Agent is offline, and any exact live ancestor recorded in the Activation's materialization lineage may stop its descendant, because stopping a turn is idempotent and delivers no content. + +When `ctx.sessionProjections` is available, the service registers two projection units. `subagentTiming` resets at each descriptor so a fork seed's ancestor work cannot enter the child's total, then accumulates `turn/start` → `turn/end` active time and retains same-cut `active.since` and `active.through` bounds for an open turn; while that turn remains open, `active.through` follows the latest folded event, giving an inactive consumer a conservative crash bound without mixing in newer session metadata. `subagent` folds the durable identity — mode plus creation label — from `subagent/descriptor` events with the same last-wins reset discipline, so a fork seed's ancestor descriptor stands only until the child's own overrides it; a malformed or unrecognized-version payload folds to the serializable `null` sentinel — indistinguishable from a log with no descriptor, and surviving every JSON push frame so a consumer replaces a stale identity instead of keeping it — and never throws. + +`registerContinuableSetup()` lets optional packages add child-scoped capabilities without teaching the continuation manager their names. Contributions install synchronously before Activation publication, roll back with failed setup, and are released with the child scope. New grants wait for the next Activation, while contribution removal revokes every resident installation immediately. + +## Collection model + +The model-facing tool collects synchronously by default: it awaits the child result and disposes the run before returning. One-shot background delegation registers a plain Task in the tool, whose generic status, collection, and cancellation tools own later interaction, and persists its model-supplied `description` as the optional display label. Continuable background delegation calls `ctx.subagents.startContinuable()` and returns only the durable child id; the child owns its own turns from inbox acceptance, so there is no Task and no result promise — a caller sends later work with the `send_message` follow-up tool, and `interrupt()` stops only the current turn without disposing the child, and the durable child Session remains the source of the child's detailed output. The continuation manager exists only while `ctx.agents` is available, and session persistence is resolved per continuation operation. Independently, `listChildren()` enumerates the live-preferred merge of the live session store and optional session persistence — live-only when persistence is absent, since a cold child cannot be resumed then either — and serves each child's durable mode/label from the registered `subagent` projection unit: the registry's watermark snapshot for a live child; for a cold one, a durable projection-cache row when it serves an own-suffix identity — its `seq` gate proves the value postdates the fork seed, where a child's own descriptor is immutable once appended — else one bounded-concurrency persistence inspection folded through the registry, whose result must still name the enumerated lifecycle (a re-published id degrades to a `corrupt` diagnostic). A throwing cache read renders no verdict — the cache is derived data — and silently falls through to that authoritative re-fold. The projection fold is the single classification authority; listing parses no descriptor itself. A served identity produces a child row; a settled candidate whose fold served no identity is a `corrupt` diagnostic, a failed inspection is a transient `unavailable` retried on the next listing, and a running candidate without an identity yet is omitted (the creation window before its descriptor is appended). It never consults the continuation manager, Agent registrations, Activations, or providers. Each child row derives its read-time `hasChildren` hint from merged headers carrying durable `origin: 'subagent'`; it does not read descendant event logs, and the descriptor-backed child catalog remains authoritative when expanded. Service consumers such as a UI can retain both modes and choose a fallback for an unlabeled one-shot child; the model-facing `list_agents` tool projects only `continuable` entries and refines status through the live Agent registry and maps storage-only to its resumable-not-terminal `ready` (`running`/`idle`/`ready`) and walks `listDescendants()` for its `descendants` scope. The listing forwards the caller's signal to every persistence read, checks cancellation around each of those awaits, and reports every observed abort as `SubagentError` code `CANCELLED`; an unmounted projection registry fails loud with `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE`, and a missing session store with `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE`. See the [background subagent tasks Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-background-subagent-tasks.md), the [continuable background subagents Agent Note](../../../.agents/notes/implemented/feature/2026-07-21-continuable-background-subagents.md), the [durable catalog Agent Note](../../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md), the [merged-service Agent Note](../../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md), the [capability-seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md), and `src/types.ts` for the complete contracts. + +Continuable Activations await a best-effort final session flush without treating listener participation as durability confirmation. One-shot runs retain best-effort session checkpointing, so a completed one-shot child is discoverable after disposal only when its session actually reached persistence; the service does not invent a catalog entry from Task history when that checkpoint is absent. + +## Model Experience + +### Settlement notice + +#### What the model sees + +One user-role parent message opening with the outcome — `Background subagent finished and will do no further work unless you send it more.`, or the matching line for a child that was stopped, ran out of room, declined, or failed — followed by `Its closing message:` and the child's final assistant content, or `It left no closing message.` when it produced none. This is the service's only direct parent-side contribution; delegation schemas, parent continuation and discovery, and the child-scoped `report` belong to `dsh-tool-subagent`, `dsh-tool-subagent-control`, and `dsh-tool-subagent-report`. + +#### Token effect + +One notice per settled Activation in the parent's request, sized by the child's final message. A child that both reports and settles costs the parent both. + +#### KV Cache effect + +Append-only in the parent: the notice follows its reusable request prefix. Reaching an idle parent starts one independent model request; reaching a busy one does not. + +### Child delegation-scope statement + +#### What the model sees + +Every in-process child's runtime-context snapshot carries the `subagent:delegation` statement below, after the sandbox-policy and approval-policy sentences. + +##### The delegation-scope statement + +```markdown +You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the job needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it. +``` + +#### Token effect + +One fixed statement in each child's runtime-context snapshot; none in the parent's requests. + +#### KV Cache effect + +Prefix-stable within a child: the statement never changes during the child's lifetime, so it is written once into the first runtime-context snapshot. Parent-side, no direct invalidation; the named tool consumers own any request-prefix changes. + +## Known Limitations and Deferred Work + +- **ACP children remain one-shot and are not trace-enumerable** — an ACP run has no local child session in the parent's session corpus. An ACP `prepareContinuable` requires persisting the remote session id in provider-specific descriptor data and a per-child continuation advertisement, since ACP `loadSession` support is negotiated per child rather than established by the method's presence. Remote providers also require a separate Activation ownership contract with equivalent authenticated control and child-first quiescence before they support continuable children. +- **No host-user continuation** — `followup()` requires the exact live direct parent. Only `interrupt()` accepts a durable parent-address user authority, because stopping a turn is idempotent and delivers no content; a future host adapter needs a concrete authenticated interaction before the seam gains a user delivery capability. +- **No current-turn steering** — continuable messages and waking reports enqueue later turns; neither redirects an open turn. +- **Wake gap during cancellation convergence** — a waking follow-up accepted after the interrupt signal is issued but before the active driver becomes idle remains queued until another waking send. Issue #1838 owns the agent-loop wake latch, which also affects ordinary session cancellation. +- **Process-local residency** — the Activation inbox and ownership graph do not coordinate two harness processes; concurrent access to one persistence store still requires a durable mailbox and cross-process lease protocol. +- **No replay of accepted-but-unlogged messages** — only messages written to the child Session log are reconstructable with the source that supplied them. A crash may lose an accepted initial prompt or follow-up that never reached the log; a later authorized message can cold-resume the child, but the lost message is not replayed automatically. +- **No durable report mailbox** — reports require a live direct parent and provide acceptance identity rather than exactly-once delivery or a read receipt. +- **Lifecycle events are observe-only** — a run-affecting `subagent/end` continuation or decision API waits for a concrete consumer. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.zh.md new file mode 100644 index 0000000..3ad2ee5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/README.zh.md @@ -0,0 +1,154 @@ +# @deepseek-ai/dsh-subagent + +[English](README.md) | 中文 + +subagent seam 允许一个 agent(智能体)通过具名提供方把工作委派给子 agent。调用方统一使用 `ctx.subagents` 服务 API;提供方决定子 agent 在当前进程、其他进程,还是通过未来的传输方式运行。 + +[subagent 家族概述](../README.md)列出了实现和面向模型的消费方。本包负责提供方注册表、共享请求和结果约定、持久描述符以及可继续子级编排。多个具名提供方可以在该约定背后共存。 + +## 服务 API + +`SubagentRuntime` 具有以下操作: + +| 成员 | 含义 | +|---|---| +| `registerProvider(provider)` | 按名称注册一个可信的同进程实现。注册受 effect 作用域约束;移除注册会阻止新的启动,但不会撤销已返回给调用方的运行。重复名称会明确报错。 | +| `getProvider(name)` | 返回提供方;不存在时返回 `undefined`。 | +| `list()` | 按插入顺序返回提供方名称。 | +| `start(name, request)` | 校验普通调用方请求,解析其已分离的 `one-shot` 描述符,然后等待提供方发布真正的一次性子 agent。兑现时返回由持有方拥有的 `SubagentRun`;如果调用被拒绝,提供方已经清理所有尚未发布的启动资源。发布后的轮次故障或基础设施故障则通过该 run 结算。可继续子 agent 绝不通过此操作进入。 | +| `startContinuable(spec)` | 建立一个持久化的可继续子 agent,并投递其初始提示词。子 agent 的 inbox 一接受该提示词,调用就会兑现为 `{ childId, messageId }`,无需等待轮次开始,也无需等待消息写入会话日志。在此之前发生的任何失败都会使调用被拒绝,不返回任何 id,并完全回滚该子 agent。要求 `ctx.agents`、会话持久化以及具备 `prepareContinuable` 能力的提供方。 | +| `followup(parent, childId, content, { source, signal })` | 将来自确切在线直接父级的一条后续消息作为子 agent 的下一个 FIFO 轮次投递,术语与 `Agent.followup()` 一致,并返回被接受的 `MessageId`。驻留中的子 agent 由其 inbox 直接接受(唤醒处于 waiting 的 Activation);不驻留的则从其持久化会话冷恢复。要求 `ctx.agents`;冷恢复还要求会话持久化。 | +| `interrupt(targetSessionId, authority)` | 凭人类出示的持久化父级地址 `{ kind: 'user', parentSessionId }`,或确切在线的祖先 Agent `{ kind: 'ancestor', agent }` 进行授权,中断一个在线可继续子级的当前轮次。准入判定同步完成,但取消异步生效:该操作发出 `Agent.cancel(cause, { keepInbox: true })` 后立即返回,不等待目标观察到信号。尚未领取的待处理 inbox 工作、Activation 和已发布的后代均会保留;已经领取到被中断轮次中的工作不会重新入队。目标不存在时视为已接受的空操作;错误的父级地址,或陈旧、指向自身、并非祖先的调用方,会以 `UNAUTHORIZED` 被拒绝。 | +| `reportFrom(child, content, { delivery, signal })` | 从确切在线可继续 child 向其确切在线直接 parent 投递一条选中消息,并返回已接受的稳定 `MessageId`。静默投递会注入上下文;唤醒投递会提交一个后续 parent 轮次。 | +| `registerContinuableSetup(contribution)` | 把一项可选部署能力组合到每个可继续 child 尚未发布的作用域中,并支持从驻留 child 立即撤销。 | +| `drainContinuableDescendants(parents)` | 在由 host 拥有的确切在线父级 Agent 之下关闭准入,只停止这些父级可见的可继续后代;等待已在这些根节点下获准的物化过程完成发布或回滚后,再按子级优先顺序释放所选的各棵树。该截止状态会持续到每个确切父级离开注册表;无关的父级树仍在线,管理器全局准入仍保持开放。 | +| `listChildren(parentSessionId, signal?)` | 按 `createdAt`、再按 id 的顺序列出由会话支撑的直接 subagent,包括其 `one-shot`/`continuable` 模式、`running`/`inactive` 活动状态、根据 origin 分类得出的一层 `hasChildren` 提示,以及每个子级的诊断信息,且不会加载或恢复它们。该操作直接读取在线会话存储和可选的会话持久化(没有持久化时只枚举在线子级),并要求已挂载 `sessionProjections` 注册表;不要求 `ctx.agents`、继续执行管理器或任何查询服务。 | +| `listDescendants(rootSessionId, signal?)` | 从同一份在线优先语料按稳定 pre-order 展平根的完整会话树,并为每个 subagent 条目附加持久 `parentId` 与相对根的 `depth`。普通会话与一次性 child 仍作为遍历节点,因此其下的可继续后代仍可发现。身份、diagnostic、依赖与取消约定均沿用 `listChildren()`。 | + +`SubagentStartRequest.label` 是由会话支撑的一次性 child 所使用的可选简短持久化显示标签。面向模型的委派会提供其已有的 `description`;底层调用方无需凭空构造展示元数据。可继续启动始终携带自身的必填标签。`signal` 是必填项,也是一次性 `start` 的规范取消通道。发布前中止会使 `start()` 在回滚后拒绝;发布后中止会取消已返回 run 的剩余轮次工作,但不会隐藏其 id。请求还可以选择模型、要求结构化输出、限制委派深度、约束子 agent 工具或设置子 agent persona。对于可继续启动或后续操作,调用方信号只负责 inbox 接受前的查找、物化和准入;此后,Activation 由管理器独立拥有,因此调用方取消既不会取消已接受的轮次,也不会 dispose(资源释放)子 agent。 + +后续操作的权限来自子 agent 持久化 header 中记录的确切在线直接父级。冷恢复会在重建前检查该权限,并在最终无 await 的 inbox 准入区间再次检查,因此在物化期间被注销或替换的 parent 无法授权投递。后续操作上的 `source` 记录谁提供了所投递的消息,不授予任何权限。 + +同进程请求、描述符、结果和事件 payload 都是可信的类型值,并按不可变约定借用。服务不会克隆或冻结它们;序列化和不可信输入校验属于真实的进程、worker、持久化和模型边界。 + +## 能力 + +启动时功能通过 `provider.capabilities` 声明,因为服务必须在创建子 agent 前拒绝不受支持的一次性请求: + +- `outputSchema`:强制执行结构化最终结果; +- `depthLimit`:强制执行 `maxDepth`; +- `toolFilter`:应用请求的子 agent 工具限制; +- `persona`:应用每个子 agent 独立的 persona。 + +每个进程内子 agent 都通过一次 `applyChildComposition(childCtx, parent, composition)` 调用完成组装:先加入父级的 agent-preset 组合,再应用子 agent 自己的 persona 和工具限制。加入父级组合正是子 agent 获得能力的途径:所有面向模型的行都位于 agent 平面,完全没有加入任何组合的子 agent 抵达模型时会看到空的工具注册表(见 [`dsh-agent-presets`](../../preset/agent-presets/README.md))。将父级作为参数是刻意设计:这让“组装子 agent 却不做该加入”在各调用点无法表达,而这正是这一次调用所要杜绝的缺陷。未组装 preset roster 的部署不加入任何组合、也不需要加入;其面向模型的行位于宿主组合中,子 agent 已能通过工具注册表的全局层解析到它们。 + +`childSessionMeta()` 把所加入的 preset id 记在子 agent 的持久化 header 上,理由与顶层会话记录自己的那一个相同:preset 决定了模型所见的工具 schema 与提示段,因此冷读子 agent 的历史时必须重建那份组装,而不是部署默认值。该值从父方**活着的** scope 链读取,而不是从父方 header 读取,因为在空白期切换过 preset 的父方运行在更新的那份组装上,而它的 header 仍写着旧的那个。 + +可继续创建对应可选的 `SubagentProvider.prepareContinuable?()` 方法:方法是否存在就是能力检查,因此服务会在没有该方法的提供方上拒绝已配置的可继续启动,而具备该方法的提供方仍可服务普通一次性委派。该方法只返回已分离的 `ContinuableCreateSpec`(`{ seed? }`)。它只是数据,不携带任何能力:不包含 Agent、`AgentHandle`、提示词投递、结果、dispose 或恢复操作。准备完成后,身份预留、组合、Agent 创建、提示词投递、冷恢复、所有权和 dispose 均由继续执行管理器负责。一次性 `SubagentRun` 表示一次可 dispose 的前台委派,只有一个结果,且没有冷恢复操作。服务可以针对不同的同级子 agent 并发调用同一提供方:每次启动或准备都拥有各自的可变状态和取消路径,一项操作的失败、结果或清理不得使另一项操作结算或释放。提供方可以在内部按自身容量排队,但不得改变这项独立性约定。 + +## 持久化描述符 + +该 Service Definition 拥有版本化的 `subagent/descriptor` 会话事件词汇(`src/descriptor.ts`):`snapshotSubagentDescriptor()` 会在提供方工作之前校验并分离记录,`foldSubagentDescriptor()` 则会在从已加载子 agent 日志中恢复描述符之前,校验当前版本的完整 payload。每次由本地会话支撑的启动都会追加一个带有提供方名称与生命周期 `mode` 的描述符。`one-shot` 描述符可以携带调用方拥有的可选持久化显示 `label`;`continuable` 描述符要求其持久化创建标签,并另外记录已解析的子 agent `agentOptions.provider`/`model`,以及用于从持久化存储恢复的可选 `persona`/`toolFilter`。这些是显式字段,绝不是可通过合并扩展的 `AgentOptions` 对象,因此无关的扩展值不会破坏继续执行。描述符省略 `subagentDepth`(持久化 header 的 `delegationDepth` 是单调下界)和 `outputSchema`(单次 Activation 的结果约定)。该事件只进入日志:不含 `surfaceOp`,不进入模型历史,并由仅追加日志跨压缩(compaction)保留。格式错误的当前版本 payload 属于损坏;本运行时无法对不受支持的版本进行分类。 + +## 委派深度 + +该 seam 拥有 Service Provider 和 Consumer 共享的深度词汇:`AgentOptions.subagentDepth` 声明、`assertSubagentMaxDepth` 和 `delegationDepthOf(agent)`。持久化的 `SessionHeader.delegationDepth` 具有权威性且单调:运行时选项可以增大委派深度,但绝不能将其降到这个下界以下,因此恢复后的子 agent 不会被重新计为顶层。 + +`inheritsParentContext` 只用于描述,不能强制执行。它仅说明子 agent 是否能看到父级已完成的对话历史(`fork` 可以;`spawn` 和各进程外一次性提供方不可以),不表示是否继承工具、服务或权限。 + +## 委派策略 + +两条进程内委派路径都会通过共享的子 agent 辅助函数,在委派边界固定子 agent 的权限范围。`captureDelegatedPolicyOverrides(parent)` 会为父会话的显式沙箱覆盖项(`sandboxPolicy.overrideOf()`)创建快照,并在审批能力已组合时将子 agent 的审批策略固定为 `'never'`,无论父级自身采用何种策略。这样,被委派的子 agent 只能在继承的沙箱范围内行动,每次审批请求(例如 `sandbox_permissions` 升权)都会被确定性拒绝,而不会等待无人处理的提示(这两个服务都是可选的 `ctx.get` 消费方)。`appendDelegatedPolicyOverrides()` 则在未发布的设置阶段、在任何 fork 种子之后,把每个值作为一条 `source: 'delegation'` 的 `sandbox/mode` 或 `approval/policy` 事件写入子 agent 自己的日志。因此,新捕获的策略会覆盖种子中的陈旧状态,而子 agent 的生效策略始终可以仅凭其日志重建。沙箱的部署默认值绝不复制:未切换的父级不会记录 `sandbox/mode`,其子 agent 会动态跟随部署默认值。可继续启动会在第一次 await 前捕获策略,并且只为全新物化写入这些委派事件;冷恢复只会重放已持久化的委派事件,不会重新捕获父级策略,因此创建之后的父级切换绝不会追溯性地改变持久化子 agent。每个进程内子 agent 还会收到一条作用域内的运行时上下文声明(`subagent:delegation`),告知其权限范围已固定,需要更宽访问的任务应以上报限制收尾,而不是重试。参见[一次性](../../../.agents/notes/implemented/feature/2026-07-25-subagent-policy-inheritance.md)与[可继续](../../../.agents/notes/implemented/feature/2026-08-10-continuable-subagent-policy-inheritance.md)两篇委派策略 Agent Note。 + +## 一次性所有权与生命周期 + +`provider.start(request): Promise` 是所有权转移边界;委派工具也会在其由 Task 支撑的一次性后台路径中使用它。兑现前,提供方拥有设置过程,并且在任何失败路径上都必须取消、回滚并使尚未发布的资源完全停稳。兑现后,run 的所有权转移给调用方;调用方必须在每条路径上调用 `dispose()`。剩余提示词和轮次工作属于 `SubagentRun.result`。 + +`SubagentRun.result` 兑现为 `{ output, structured?, stopReason }`。子 agent 级失败会以非 `completed` 原因兑现;只有 seam 无法表示的基础设施故障才可以拒绝。`dispose()` 是幂等的,会取消剩余工作,并等待结果结算以及子 agent 资源完全停稳。result 的拒绝只通过 `result` 本身报告;只有独立的资源释放失败,才会使 `dispose()` 被拒绝。`output` 与 `subagent/end` 事件的 `lastAssistantMessage` 使用导出的 `AssistantOutputFold`/`finalAssistantOutput` 辅助函数选取子 agent 最后一条非空 assistant 消息;若没有这类消息,则选取其累积的 assistant 文本。子 agent 两种输出均未产生时,`output` 为 `[]`,该事件字段缺省(结果约定归 [`SubagentResult.output`](../../../docs/subsystems/subagent.md#the-terminal-result-subagentresult) 所有)。 + +本地运行会在 `start()` 兑现前发布普通的子 agent/会话,把该共享会话 id 作为 `SubagentRun.id` 返回,以 `SubagentRun.localAgent` 公开准确的子 agent,把 `request.parent.session.id` 记录到子 agent 的 `parentSession` header,并在其初始轮次内追加已解析的描述符。远程提供方则生成 parent 作用域的生命周期 id,并返回 `localAgent: undefined`;由于没有本地 child 会话,其一次性运行不会进入基于追踪的枚举结果。 + +## 可继续子 agent 与 Activation + +每个可继续子 agent 都有一个持久化 Session,并且同一时刻至多有一个进程内 **Activation**。Activation 表示重建后的子 agent 的一次驻留时段,不是请求、结果、取消或 Task 的边界。Agent inbox 是唯一的轮次队列,因此驻留归继续执行管理器,所有轮次排序与执行归 agent loop(智能体循环)。任何可继续路径都不会创建 Task 或中间的承载结果的包装层。 + +管理器根据 Agent 的完全停稳状态和所拥有的子级集合推导三种内部驻留状态,而不维护第二套状态机:running 表示存在正在进行的准入、尚未结束的轮次,或会唤醒 Agent 的 inbox 工作;waiting 表示 Agent 已完全停稳,但仍拥有至少一个尚未 dispose 的子级;settled 表示 Agent 已完全停稳且所有拥有的子级均已 dispose,此时管理器会 dispose `AgentHandle` 并移除 Activation。每条后续消息都使用 `Agent.followup()` 并成为一个 FIFO 轮次,且不会对当前轮次进行 steering(中途引导)。路由只取决于驻留状态:running 入队、waiting 唤醒同一 Agent,无 Activation 时则冷恢复一个新的。 + +管理器预留子 agent 身份、解析持久化描述符,通过私有的 activation-owner 作用域调用 `ctx.agents.create()`(冷恢复时为 `ctx.agents.resume()`),把返回的 `AgentHandle` 安装到 Activation 中,建立任何可继续父级所有权,然后提交提示词。冷恢复绝不通过提供方分发,因为持久化会话已持有初始前缀,折叠后的描述符即是全部重建输入。 + +### 结算投递 + +当一个驻留 Activation 结算时,管理器会在父级自身的轮次流中告知该子级持久化的直接父级:这个子级已经产出它将产出的全部内容。对于每个已经向调用方返回过 id 的子级,管理器都会无条件投递结算通知,不考虑该子级是否调用过 `report`。最需要说明结局的终止情形,包括达到 token 上限、模型失败、取消或拆卸,恰恰是子级根本没有机会选择的那些情形。在第一条消息被接受之前就回滚的物化保持静默,因为那位调用方已被告知该子级未建立。消息会携带该 epoch 的终止原因、它产出过的最终 assistant 内容,以及持久化来源 `{ kind: 'subagent-settled', form: 'notice', senderSessionId: }`——与子级自撰的 `subagent-report` 是不同的来源 kind,因此 transcript(文本记录)绝不会把运行时写下的话算到子级头上。 + +有两条顺序规则让这条投递可靠而非侥幸,它们也正是这件事属于管理器而非外部 `subagent/end` listener 的原因。第一,发送发生在子级所有权释放**之前**,此时父级仍然计入该子级,因此在结构上不可能被判定为已结算。第二,如果父级本身也是驻留 Activation,该消息会采用与 report 相同的唤醒准入记账。这样,从同步发送消息到负责准入该消息的 microtask 运行之间的窗口,不会被误判为完全停稳——`Agent.status` 会把上下文维护折叠成 `idle`,而维护期间的唤醒发送只会预置一次延后唤醒。缺少其中任一条规则,父级都可能在通知仍留在 inbox 时被 dispose,而 `cancel()` 会清空该 inbox,于是通知被静默丢失。 + +空闲父级会以一个普通的后续轮次收到该通知。繁忙父级则被 steer 到其最近的 step 边界,因此同时结算的多个子级只消耗一个 step,而不是各自一个轮次;采用 steer 而非 inject 还意味着:即便驱动在状态读取与发送之间退出,该消息仍会被认领。如果父级所在的谱系已经开始排空,该通知会通过 inject 投递,且完全不会唤醒父级。对已经完全停稳的父级调用 `Agent.followup()` 会开启新轮次,而 `cancel()` 不会预先阻止之后开启的轮次;因此在拆卸期间唤醒父级,会让宿主即将 dispose 的 Agent 多执行一次模型请求,而且树的每一层各一次,因为每层自己的通知又会唤醒上一层。被 inject 的消息会送达仍在读取自身 inbox 的父级,而无论如何日志都会记录这份记账;但它不会比该父级自身的 dispose 活得更久:`AgentHandle.dispose()` 是一次 `keepInbox: false` 的 cancel,会持久地取消尚未被认领的通知。因此 resume 后的父级没有待处理通知可读:`list_agents` 只告诉它有哪些子级、各自是在线还是仅存于存储;结局本身留在子级自己的 Session 里,一次 `send_message` 会通过 resume 该子级把它取回。已离开注册表的父级不算错误:通知被丢弃,子级自身的 Session 仍是持久记录。投递绝不会阻塞或使拆卸失败——发送被拒只会记录日志,因为为了重试一条通知而保留子级,会把它的整条祖先链永久钉在 `waiting` 上。 + +受继续执行管理的父级 Activation 会在子 agent 能够运行之前,把每个子 agent 的会话 id 记录到 `ownedChildren` 集合中,并且只有在每个所拥有的子 agent Activation 完成 `AgentHandle` dispose 之后才会 dispose(子先于父)。拆卸会先自顶向下传播 Agent 取消,再等待缓慢的后代,而 handle 释放仍保持 child-first。顶层及其他非继续执行的 Agent 没有 Activation,处于该等待图之外。最终结算会在 dispose handle 前等待 best-effort 的 `ctx.sessions.flush(child.session)`。监听器拒绝会被记录,但不会使 Activation 失败,因为监听器参与本身不能标识持久化后端;因此恢复时的持久化状态仍可能缺失或陈旧。 + +## 生命周期事件 + +服务会为每次一次性运行以及每个已驻留的可继续 Activation 时段发出一对 `subagent/start`/`subagent/end`,因此可继续子 agent 可用与一次性运行相同的词汇观察,且不会暴露管理器是物化、唤醒还是冷恢复了它们。对于一次性启动,它会在同步的 `subagent/start` 之前附加结果观察器,因此即使子 agent 已经结算,也仍会先产生 `subagent/start`,再产生 `subagent/end`;在驻留前失败的可继续时段不会发出这对生命周期事件中的任何一个。这对事件共享由服务生成的 `runId`;`local` 标志根据提供方返回的确切 `localAgent` 是否存在取得快照(可继续子级恒为 true),因此观察器不会根据可复用的提供方名称或会话名称推断运行身份或本地性。`provider` 字段包含子 agent 初次创建时记录的提供方名称,不表示该提供方当前仍在注册:已接受的一次性 run 可在提供方移除后才结算;冷恢复时段会从描述符读取初始提供方名称,不会调用或注册该提供方。 + +运行事件受执行委派的父级作用域约束。每个监听器都独立隔离:同步抛出或返回的 promise 被拒绝时,只会记录日志,不会阻塞同级监听器或改变运行。 + +提供方新增和移除还会发出 `subagent/provider-added` 与 `subagent/provider-removed`。面向模型的工具等消费方使用这些事件,因为 Cordis 可能并发加载同级插件;配置顺序不能证明注册顺序。 + +可继续子级不会创建 `SubagentRun` 或 Task。继续执行管理器为每个驻留子会话直接拥有一个仅存在于当前进程的 Activation 和一个留存的 `AgentHandle`,使用 Agent inbox 作为唯一 FIFO,并从持久化描述符冷恢复。父到子投递由确切在线的直接父级身份授权。上报则由确切在线的子级身份授权;管理器根据持久化的 `parentSession` 推导接收方,`MessageSource` 记录发送方,但不授予权限。中断权限被刻意设计得比投递权限更宽:人类出示持久化直接 parent 地址,因此即使 parent Agent 离线,在线 child 仍可被停止;Activation 物化时记录的任何确切在线 ancestor 也可以停止其后代,因为停止一个轮次是幂等的,且不投递任何内容。 + +当 `ctx.sessionProjections` 可用时,服务会注册两个投影单元。`subagentTiming` 会在每个描述符处重置,使 fork 种子中的祖先工作不会计入 child 总量,随后累加 `turn/start` → `turn/end` 活跃时间,并为未结束的轮次保留同一切面的 `active.since` 和 `active.through` 边界;在该轮次保持未结束期间,`active.through` 会跟随最近折叠的事件,从而为 inactive 消费方提供保守的崩溃上界,又不会混入更新的会话元数据。`subagent` 以同样的 last-wins 重置纪律从 `subagent/descriptor` 事件折叠持久化身份——模式与创建标签——因此 fork 种子中的祖先描述符只在 child 自身的描述符覆盖之前有效;畸形或版本无法识别的载荷折叠为可序列化的 `null` 哨兵——与没有描述符的日志不可区分,且能完好通过每个 JSON 推送帧,让消费方以之替换掉手中的陈旧身份而非继续保留该身份——绝不抛错。 + +`registerContinuableSetup()` 允许可选包添加子级作用域能力,而无需让继续执行管理器知道这些能力的名称。贡献会在 Activation 发布前同步安装,在设置失败时一并回滚,并随子级作用域释放。新授权须等到下一个 Activation,移除贡献则会立即撤销每个驻留安装项。 + +## 收集模型 + +面向模型的工具默认同步收集:先等待子 agent 结果,再 dispose 运行,然后才返回。一次性后台委派会在工具中注册普通 Task,其通用状态、收集和取消工具负责后续交互,并将模型提供的 `description` 持久化为可选显示标签。可继续后台委派会调用 `ctx.subagents.startContinuable()`,只返回持久化子 agent id;子 agent 自 inbox 接受起就拥有自己的轮次,因此没有 Task、也没有结果 promise——调用方通过 `send_message` 后续操作工具发送后续工作,`interrupt()` 只停止当前轮次而不 dispose 子 agent,而持久化子 agent 会话仍是子 agent 详细输出的来源。只有 `ctx.agents` 可用时,继续执行管理器才会存在,而会话持久化按每项继续执行操作解析。与此独立,`listChildren()` 枚举在线会话存储与可选会话持久化的在线优先合并——持久化缺席时仅枚举在线 child,因为那时冷 child 本就无法恢复——并由已注册的 `subagent` 投影单元供给每个 child 的持久化模式与标签:在线 child 取注册表的水位快照;冷 child 先取可选投影缓存的持久化行,且仅当其 `seq` 门证明该值折叠自 child 自身后缀(fork 种子之后——自有描述符一经追加即不可变)才直接采用,否则经一次有界并发的持久化 inspect 再经注册表折叠,且 inspect 结果必须仍指向枚举时的生命周期(同 id 被重新发布的会话降级为 `corrupt` diagnostic)。缓存读取抛出异常时,不会据此作出分类判断,因为缓存只是派生数据;静默落到该权威重折。分类结果完全以投影折叠为准;列表操作本身不解析描述符。取得身份值即产出 child 行;已定局而折叠未产出身份的候选是 `corrupt` diagnostic,inspect 失败是瞬时的 `unavailable`(下次列表重试),运行中而暂无身份值的候选整行省略(描述符尚未追加的创建窗口)。它不查询继续执行管理器、Agent 注册信息、Activation 或提供方。每个 child 行都会根据合并结果中携带持久化 `origin: 'subagent'` 的 header 派生读取时的 `hasChildren` 提示;它不会读取后代事件日志,展开后仍以描述符支撑的 child 目录为权威依据。UI 等服务消费方可以保留两种模式,并为无标签的一次性 child 选择回退展示;面向模型的 `list_agents` 工具只投影 `continuable` 条目,通过在线 Agent 注册表细化状态,并把仅存于存储的状态映射为可恢复而非终态的 `ready`(`running`/`idle`/`ready`),并在 `descendants` scope 下遍历 `listDescendants()`。列表操作会把调用方的取消信号转发到每次持久化读取,在这些 await 前后检查取消,并将每次检测到的中止报告为 `SubagentError` 错误码 `CANCELLED`;投影注册表未挂载则以 `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE` 响亮失败,会话存储缺失则以 `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE` 响亮失败。完整约定见[后台 subagent 任务 Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-background-subagent-tasks.md)、[可继续后台 subagent Agent Note](../../../.agents/notes/implemented/feature/2026-07-21-continuable-background-subagents.md)、[持久化目录 Agent Note](../../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md)、[服务合并 Agent Note](../../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md)、[能力 seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md)和 `src/types.ts`。 + +可继续 Activation 会等待 best-effort 的最终会话 flush,但不会把 listener 参与视为持久性确认。一次性运行保留尽力执行的会话检查点,因此已完成的一次性 child 只有在其会话确实进入持久化存储时,才可在 dispose 后继续被发现;如果该检查点缺失,服务不会根据 Task 历史虚构目录条目。 + +## 模型体验 + +### 结算通知 + +#### 模型看到的内容 + +一条用户角色的父级消息,开头是结果本身——`Background subagent finished and will do no further work unless you send it more.`,或子级被停止、耗尽额度、拒绝任务或失败时的对应句子——随后是 `Its closing message:` 与子级的最终 assistant 内容;若子级没有产出内容,则是 `It left no closing message.`。这是本服务面向父级的唯一直接贡献;委派 schema、父级延续与发现以及子级作用域的 `report` 分别归 `dsh-tool-subagent`、`dsh-tool-subagent-control` 和 `dsh-tool-subagent-report` 所有。 + +#### Token 影响 + +父级请求中,每个已结算的 Activation 一条通知,长度取决于子级的最终消息。如果子级既上报又结算,父级请求会同时承担上报消息和结算通知两部分 token 开销。 + +#### KV Cache 影响 + +在父级中仅追加:通知位于其可复用请求前缀之后。到达空闲父级会启动一次独立的模型请求,到达繁忙父级则不会。 + +### 子级委派范围声明 + +#### 模型看到的内容 + +每个进程内子 agent 的运行时上下文快照都携带下方的 `subagent:delegation` 声明,位于沙箱策略与审批策略语句之后。 + +##### 委派范围声明 + +```markdown +You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the job needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it. +``` + +#### Token 影响 + +每个子 agent 的运行时上下文快照中一条固定声明;父级请求中没有任何新增。 + +#### KV Cache 影响 + +子级内部前缀稳定:该声明在子 agent 生命周期内绝不变化,因此只写入第一份运行时上下文快照一次。父级侧不会直接使缓存失效;具名工具消费方共同负责请求前缀的任何变化。 + +## 已知限制与暂缓事项 + +- **ACP 子 agent 仍为一次性,且无法通过追踪枚举**:ACP 运行在 parent 会话语料中没有本地 child 会话。ACP 的 `prepareContinuable` 需要在提供方专用描述符数据中持久化远端会话 id,以及逐子 agent 的继续执行能力声明,因为 ACP 的 `loadSession` 支持按子 agent 协商,而不是通过方法是否存在来确定。远程提供方还需要一份独立的 Activation 所有权约定,具备等效的经认证控制和子先于父的完全停稳保证,才能支持可继续子 agent。 +- **无 host-user 继续执行**:`followup()` 要求确切在线直接父级。只有 `interrupt()` 接受持久化 parent 地址形式的用户授权,因为停止一个轮次是幂等的且不投递任何内容;未来 host 适配器需要具体的经认证交互,才能让该 seam 获得用户投递能力。 +- **不对当前轮次进行 steering**:可继续消息和唤醒式 report 会排入后续轮次,均不会重定向正在进行的轮次。 +- **取消收敛期间存在唤醒缺口**:中断信号发出后、活动 driver 进入 idle 前被接受的唤醒型 follow-up 会保持排队,直到另一条唤醒发送到达。Issue #1838 负责 agent-loop 的唤醒锁存;普通会话取消也受此影响。 +- **驻留仅限进程内**:Activation inbox 与所有权图不会在两个 harness 进程之间协调;对单个持久化存储的并发访问仍然需要持久化邮箱和跨进程租约协议。 +- **不回放已接受但未记录的消息**:只有写入子 agent 会话日志的消息才能连同提供该消息的来源一起重建。崩溃可能丢失从未写入日志、已被接受的初始提示词或后续消息;此后一条经授权的消息可以冷恢复该子 agent,但丢失的消息不会自动回放。 +- **没有持久化的上报 mailbox**:上报需要在线直接父级,提供的是接受标识,不保证恰好一次投递,也不提供已读回执。 +- **生命周期事件只供观察**:影响运行的 `subagent/end` 延续或决策接口仍需等待具体消费方。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/index.js new file mode 100644 index 0000000..9719208 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/index.js @@ -0,0 +1,2572 @@ +import { Service } from "@deepseek-ai/cordis"; +import { scopeTarget } from "@deepseek-ai/dsh-scope"; +import { assertObjectJsonSchema } from "@deepseek-ai/dsh-tools"; +import { HarnessError, boundContextSummary, createUserMessage, errorChain } from "@deepseek-ai/dsh-llm"; +import { randomUUID } from "node:crypto"; +import { foldConsumedWork } from "@deepseek-ai/dsh-agent"; +import { Session, SessionId, snapshotJsonValue } from "@deepseek-ai/dsh-session"; +import { z } from "zod"; +import { accessSync, constants, statSync } from "node:fs"; +import { isAbsolute, resolve } from "node:path"; +//#region lib/types/error.js +/** +* Typed failures shared by subagent service and provider operations. +* +* @module @deepseek-ai/dsh-subagent +*/ +/** Typed failure for the subagent seam. */ +var SubagentError = class extends HarnessError { + constructor(message, code, options) { + super(message, code, options); + this.name = "SubagentError"; + } +}; +//#endregion +//#region lib/types/depth.js +/** +* Delegation-depth accounting: the recursion budget a parent passes to its +* children. Kept apart from the service so composition helpers can read it +* without importing the registry. +* +* @module @deepseek-ai/dsh-subagent/depth +*/ +/** +* Read an agent's delegation depth, treating absence as top-level depth zero. +* The persisted session header is authoritative and monotone: runtime +* `AgentOptions.subagentDepth` may DEEPEN the count but can never lower it — +* a resumed child arrives with fresh options, and counting it from zero would +* let it delegate as if it were top-level. +* @param agent - the agent whose header and options carry the depth. +* @returns its non-negative safe-integer depth. +* @throws if the runtime `AgentOptions.subagentDepth` is not a non-negative safe integer. +*/ +function delegationDepthOf(agent) { + const runtime = agent.options.subagentDepth; + if (runtime !== void 0 && (!Number.isSafeInteger(runtime) || runtime < 0 || Object.is(runtime, -0))) throw new TypeError("agent subagentDepth must be a non-negative safe integer"); + return Math.max(agent.session.header.delegationDepth ?? 0, runtime ?? 0); +} +/** +* Reject a recursion cap that cannot represent an exact delegation depth. +* @param maxDepth - the optional runtime value to validate. +*/ +function assertSubagentMaxDepth(maxDepth) { + if (maxDepth !== void 0 && (typeof maxDepth !== "number" || !Number.isSafeInteger(maxDepth) || maxDepth < 0 || Object.is(maxDepth, -0))) throw new TypeError("subagent maxDepth must be a non-negative safe integer"); +} +//#endregion +//#region lib/types/assistant-output.js +/** +* Canonical selection of a child's final assistant output. Backend run results +* and `subagent/end.lastAssistantMessage` apply the same rule: select the last +* non-empty assistant message. An empty-content message records usage only +* when the loop appends it after a max-tokens step with no executable blocks, +* so it does not replace earlier output. If no non-empty message exists, +* select the accumulated assistant text. Selection is independent of the +* run's stop reason. +* +* @module @deepseek-ai/dsh-subagent/assistant-output +*/ +/** +* Incremental fold of the selection rule, for backends that observe a child's +* output as it streams: session-event backends {@link push} each event, and +* transports without session events (ACP content chunks) {@link pushText} raw +* text into the same streamed fallback. +*/ +var AssistantOutputFold = class { + message; + partial = []; + /** + * Fold one session event: a non-empty assistant message becomes the + * candidate final answer, and a `text-delta` chunk extends the streamed + * fallback; every other event contributes nothing. + * @param event - the next observed session event. + */ + push(event) { + if (event.type === "assistant/message") { + const content = event.data.message.content; + if (content.length > 0) this.message = content; + } else if (event.type === "assistant/chunk" && event.data.chunk.type === "text-delta") this.pushText(event.data.chunk.text); + } + /** + * Extend the streamed fallback with text observed outside session events. + * @param text - the next streamed text piece (an empty piece is a no-op). + */ + pushText(text) { + if (text.length > 0) this.partial.push(text); + } + /** + * Select the final output folded so far. + * @returns the last non-empty assistant message, else the accumulated + * streamed text, or `undefined` when the child produced neither. + */ + collect() { + if (this.message !== void 0) return this.message; + const text = this.partial.join(""); + return text.length > 0 ? [{ + type: "text", + text + }] : void 0; + } +}; +/** +* Apply the selection rule to one complete child-owned event suffix. +* @param events - the child-owned events (after any seed or epoch boundary). +* @returns the selected output, or `undefined` when the child produced none. +*/ +function finalAssistantOutput(events) { + const fold = new AssistantOutputFold(); + for (const event of events) fold.push(event); + return fold.collect(); +} +//#endregion +//#region lib/types/types.js +/** +* The seam's consumer-facing contracts: request, result, and capability types +* for {@link SubagentProvider}, plus the `subagent/start` and `subagent/end` +* payloads that plugins and hosts observe. Internal control interfaces belong +* with their implementation — the lifecycle observer in `./lifecycle.ts`, the +* continuation host in `./continuation.ts` — so this module stays the published +* surface rather than a bag of everything type-shaped. +* +* @module @deepseek-ai/dsh-subagent/types +*/ +/** +* Brand a string as a {@link SubagentRunId}. +* @param id - the raw run id. +* @returns the same string, branded. +*/ +function SubagentRunId(id) { + return id; +} +//#endregion +//#region lib/types/lifecycle.js +/** +* Lifecycle-edge publication for both subagent shapes: the contained emitter, +* the one-shot run observer, and the continuable Activation observer. +* +* The public payload contracts ({@link SubagentRunInfo}, +* {@link SubagentRunEndInfo}) live in `./types.ts` with the rest of the seam's +* consumer-facing types; this module owns only the implementation and the +* package-private {@link ActivationObserver} the continuation manager consumes. +* Keeping the internal control interface out of the published surface is +* deliberate: the observer's `start`/`capture`/`settle` ordering is a contract +* between this module and one in-package caller, not something a plugin may +* depend on. +* +* @module @deepseek-ai/dsh-subagent/lifecycle +*/ +/** +* Build the contained lifecycle emitter this seam publishes every edge through. +* Every listener is independently contained: a synchronous throw or a rejected +* returned promise is logged without starving peer listeners, changing the run, +* or — for provider removal, which fires from a disposer — breaking teardown. +* @param ctx - the service's own context, owning dispatch and the logger. +* @param carrier - resolve the scoped dispatch carrier for one delegating parent. +* @returns the emitter both observers and the provider registry publish through. +*/ +function createLifecycleEmitter(ctx, carrier) { + return (name, info, parent) => { + const dispatchArgs = parent === void 0 ? [name, info] : [ + carrier(parent), + name, + info + ]; + for (const callback of ctx.events.dispatch("emit", dispatchArgs)) try { + const returned = callback(info); + Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`subagent: ${name} listener rejected: ${renderThrown(error)}`); + }); + } catch (error) { + ctx.logger.warn(`subagent: ${name} listener threw: ${renderThrown(error)}`); + } + }; +} +/** +* Emit the start/end lifecycle pair for one accepted one-shot run. +* @param emit - the contained lifecycle emitter. +* @param provider - the provider that established the run. +* @param parent - the delegating parent keying scoped dispatch. +* @param run - the published run whose settlement closes the pair. +* @returns the same run, unchanged. +*/ +function observeRun(emit, provider, parent, run) { + const identity = { + runId: SubagentRunId(randomUUID()), + provider, + id: run.id, + local: run.localAgent !== void 0 + }; + run.result.then((result) => { + emit("subagent/end", { + ...identity, + stopReason: result.stopReason, + ...result.output.length === 0 ? {} : { lastAssistantMessage: result.output } + }, parent); + }, () => { + emit("subagent/end", { + ...identity, + stopReason: "error" + }, parent); + }); + emit("subagent/start", identity, parent); + return run; +} +/** +* Build the observer for one continuable Activation's residency epoch. Observers +* see the same vocabulary as a one-shot run, so a child's start and settlement +* remain observable without exposing whether the manager materialized, woke, or +* cold-resumed it. Creation failure before residency emits no lifecycle edge. +* @param emit - the contained lifecycle emitter. +* @param provider - the provider name recorded in the durable descriptor. +* @param childId - the durable child session id. +* @param parent - the exact live direct parent keying scoped dispatch. +* @returns the observer whose edges this epoch publishes. +*/ +function createActivationObserver(emit, provider, childId, parent) { + const identity = { + runId: SubagentRunId(randomUUID()), + provider, + id: childId, + local: true + }; + let boundary = 0; + let captured = { stopReason: "completed" }; + const terminal = (failure) => failure === void 0 ? captured : { stopReason: "error" }; + return { + start: (child) => { + boundary = child.session.events.length; + emit("subagent/start", identity, parent); + }, + capture: (child) => { + const own = child.session.events.slice(boundary); + const output = finalAssistantOutput(own); + captured = { + stopReason: epochStopReason(own), + ...output === void 0 ? {} : { output } + }; + }, + terminal, + settle: (failure) => { + const { stopReason, output } = terminal(failure); + emit("subagent/end", { + ...identity, + stopReason, + ...output === void 0 ? {} : { lastAssistantMessage: output } + }, parent); + } + }; +} +/** +* Why this child's epoch ended, for the terminal lifecycle edge and the +* manager's own parent delivery. The child's own log is authoritative: +* teardown succeeding says nothing about whether the model errored, hit its +* token ceiling, or was cancelled, so deriving the reason from disposal would +* report failed work as completed. +* +* {@link foldConsumedWork} supplies both halves the raw turn sequence cannot: +* which turn accounts for the work this epoch consumed, and whether accepted +* work was cancelled after it without any turn opening over it. A recorded +* failure still wins over a cancellation — stopping a child that had already +* failed does not turn its failure into a cancellation. +* @param events - this epoch's own event suffix. +* @returns its terminal stop reason; `completed` only for an epoch that both +* closed cleanly and had nothing left to run. +*/ +function epochStopReason(events) { + const { end, droppedUnrun } = foldConsumedWork(events); + switch (end?.data.reason.kind) { + case "max-tokens": return "max-tokens"; + case "aborted": + case "interrupted": return "aborted"; + case "error": return "error"; + case "blocked": return "refusal"; + case void 0: + case "completed": return droppedUnrun ? "aborted" : "completed"; + /* v8 ignore next 3 -- `TurnEndReason` is merge-extensible, so this arm needs a + * backend that adds a variant; treating an unnameable reason as success would + * report failed work as completed. */ + default: return "error"; + } +} +/** Render any listener-thrown value without letting coercion escape containment. */ +function renderThrown(value) { + try { + return value instanceof Error ? `${value.name}: ${value.message}` : String(value); + } catch { + return ""; + } +} +//#endregion +//#region lib/types/descriptor.js +/** +* The durable subagent-child descriptor: the versioned, model-hidden +* `subagent/descriptor` session event that identifies every session-backed +* subagent and records whether it is one-shot or continuable. Continuable +* descriptors additionally preserve the declared composition required for +* cold resume. Providers append it turn-enclosed in the child's initial turn. +* +* The descriptor deliberately snapshots explicit fields rather than the +* merge-extensible `AgentOptions` object: an unrelated extension value cannot +* make continuation fail merely because it is not JSON, and later composition +* inputs require a deliberate {@link SUBAGENT_DESCRIPTOR_VERSION} change. It +* omits `subagentDepth` — cold resume trusts the persisted header's +* `delegationDepth` as the monotone floor — and `outputSchema`, which belongs +* to one activation's result contract rather than durable child composition. +* Per-activation knobs such as `maxTokens` are omitted for the same reason as +* `outputSchema`: they budget one activation. Cold resume requires the exact +* live parent for authorization but reconstructs child options only from the +* durable descriptor, so it neither restores the prior budget nor inherits +* the parent's current one; the resumed route's defaults apply instead. +* +* @module @deepseek-ai/dsh-subagent/descriptor +*/ +/** +* The current descriptor format version, stamped into every appended +* `subagent/descriptor` event and required verbatim by {@link foldSubagentDescriptor}. +* Supporting another composition input is a deliberate version change, never +* an implicit extra field. +*/ +const SUBAGENT_DESCRIPTOR_VERSION = 2; +const DESCRIPTOR_BASE_KEYS = [ + "version", + "mode", + "provider", + "label" +]; +const ONE_SHOT_DESCRIPTOR_KEYS = new Set(DESCRIPTOR_BASE_KEYS); +const CONTINUABLE_DESCRIPTOR_KEYS = new Set([ + ...DESCRIPTOR_BASE_KEYS, + "agentProvider", + "agentModel", + "persona", + "toolFilter" +]); +const TOOL_FILTER_KEYS = new Set(["allow", "deny"]); +/** Whether a persisted JSON value is an object record. */ +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +/** Reject fields outside one versioned record's declared schema. */ +function assertKnownKeys(value, keys, path) { + const unknown = Object.keys(value).find((key) => !keys.has(key)); + if (unknown !== void 0) throw new Error(`persisted subagent descriptor ${path} has unknown field "${unknown}"`); +} +/** Read one optional string field from a persisted descriptor record. */ +function optionalString(value, key) { + if (!Object.hasOwn(value, key)) return void 0; + const field = value[key]; + if (typeof field !== "string") throw new Error(`persisted subagent descriptor ${key} must be a string`); + return field; +} +/** Read one optional string-array field from a persisted tool restriction. */ +function optionalStringArray(value, key) { + if (!Object.hasOwn(value, key)) return void 0; + const field = value[key]; + if (!Array.isArray(field)) throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`); + const items = field; + if (items.some((item) => typeof item !== "string")) throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`); + return items; +} +/** Validate and reconstruct a persisted tool restriction. */ +function parseToolFilter(value) { + if (!isRecord(value)) throw new Error("persisted subagent descriptor toolFilter must be an object"); + assertKnownKeys(value, TOOL_FILTER_KEYS, "toolFilter"); + const allow = optionalStringArray(value, "allow"); + const deny = optionalStringArray(value, "deny"); + if (allow === void 0 && deny === void 0) throw new Error("persisted subagent descriptor toolFilter must declare allow and/or deny"); + return { + ...allow !== void 0 ? { allow } : {}, + ...deny !== void 0 ? { deny } : {} + }; +} +/** Validate one persisted descriptor payload for the current runtime. */ +function parseSubagentDescriptor(value) { + if (!isRecord(value)) throw new Error("persisted subagent descriptor payload must be an object"); + const version = value["version"]; + if (typeof version !== "number") throw new Error("persisted subagent descriptor version must be a number"); + if (version !== 2) return void 0; + const mode = value["mode"]; + if (mode !== "one-shot" && mode !== "continuable") throw new Error("persisted subagent descriptor mode must be \"one-shot\" or \"continuable\""); + assertKnownKeys(value, mode === "one-shot" ? ONE_SHOT_DESCRIPTOR_KEYS : CONTINUABLE_DESCRIPTOR_KEYS, "payload"); + const provider = value["provider"]; + if (typeof provider !== "string") throw new Error("persisted subagent descriptor provider must be a string"); + if (mode === "one-shot") { + const label = optionalString(value, "label"); + return { + version: 2, + mode, + provider, + ...label !== void 0 ? { label } : {} + }; + } + const label = value["label"]; + if (typeof label !== "string") throw new Error("persisted subagent descriptor label must be a string"); + const agentProvider = optionalString(value, "agentProvider"); + const agentModel = optionalString(value, "agentModel"); + const persona = optionalString(value, "persona"); + const toolFilter = Object.hasOwn(value, "toolFilter") ? parseToolFilter(value["toolFilter"]) : void 0; + return { + version: 2, + mode, + provider, + label, + ...agentProvider !== void 0 ? { agentProvider } : {}, + ...agentModel !== void 0 ? { agentModel } : {}, + ...persona !== void 0 ? { persona } : {}, + ...toolFilter !== void 0 ? { toolFilter } : {} + }; +} +function snapshotSubagentDescriptor(input) { + const snapshot = snapshotJsonValue(input.mode === "one-shot" ? { + version: 2, + mode: input.mode, + provider: input.provider, + ...input.label !== void 0 ? { label: input.label } : {} + } : { + version: 2, + mode: input.mode, + provider: input.provider, + label: input.label, + ...input.agentProvider !== void 0 ? { agentProvider: input.agentProvider } : {}, + ...input.agentModel !== void 0 ? { agentModel: input.agentModel } : {}, + ...input.persona !== void 0 ? { persona: input.persona } : {}, + ...input.toolFilter !== void 0 ? { toolFilter: input.toolFilter } : {} + }); + if (snapshot === void 0) throw new Error("subagent descriptor is not losslessly JSON-serializable"); + return snapshot; +} +/** +* Fold a persisted child log to its supported descriptor. The first +* `subagent/descriptor` event is authoritative — the establishing provider +* appends exactly one, so a later same-type event cannot rewrite the declared +* composition. +* @param events - the loaded child session events. +* @returns the descriptor, or `undefined` when the log has none or its +* version is not {@link SUBAGENT_DESCRIPTOR_VERSION} (the child cannot be +* classified by this runtime). +* @throws when a current-version persisted payload does not match its complete +* declared schema. +*/ +function foldSubagentDescriptor(events) { + const event = events.find((candidate) => candidate.type === "subagent/descriptor"); + if (event === void 0) return void 0; + return parseSubagentDescriptor(event.data); +} +//#endregion +//#region lib/types/child-agent.js +/** +* Shared in-process child composition: the delegation-depth budget, the +* durable session metadata, the resolved child `AgentOptions`, the delegated +* policy seed, and the scoped setup a child agent needs. Both the one-shot +* provider driver and the continuation manager compose children this way, so +* depth accounting, lineage stamping, and delegation policy have one home. +* +* @module @deepseek-ai/dsh-subagent/child-agent +*/ +/** Thrown when starting a child would exceed the requested depth cap. */ +var SubagentDepthError = class extends Error { + attemptedDepth; + maxDepth; + constructor(attemptedDepth, maxDepth) { + super(`subagent depth ${attemptedDepth} exceeds maxDepth ${maxDepth}`); + this.attemptedDepth = attemptedDepth; + this.maxDepth = maxDepth; + this.name = "SubagentDepthError"; + } +}; +/** +* Resolve the child's delegation depth from its parent and enforce an optional +* cap. The persisted parent header is the monotone floor, so a resumed parent +* cannot delegate as if it were top-level. +* @param parent - the delegating parent agent. +* @param maxDepth - optional absolute cap the resolved depth must not exceed. +* @returns the child's non-negative safe-integer depth. +* @throws {SubagentDepthError} when the resolved depth exceeds `maxDepth`. +* @throws {RangeError} when the resolved depth leaves the safe-integer range. +*/ +function resolveChildDepth(parent, maxDepth) { + const childDepth = delegationDepthOf(parent) + 1; + if (!Number.isSafeInteger(childDepth)) throw new RangeError("subagent child depth exceeds the safe-integer range"); + if (maxDepth !== void 0 && childDepth > maxDepth) throw new SubagentDepthError(childDepth, maxDepth); + return childDepth; +} +/** +* Resolve the child's `AgentOptions`: the parent's provider/model/maxTokens +* route unless the request overrides it, stamped with the child's own +* delegation depth. +* @param parent - the delegating parent whose route the child inherits. +* @param requested - per-child overrides, if any. +* @param childDepth - the resolved delegation depth to stamp. +* @returns the resolved options for `ctx.agents.create()`. +*/ +function resolveChildAgentOptions(parent, requested, childDepth) { + const parentProvider = parent.options.provider; + const parentModel = parent.options.model; + const parentMaxTokens = parent.options.maxTokens; + return { + ...parentProvider !== void 0 ? { provider: parentProvider } : {}, + ...parentModel !== void 0 ? { model: parentModel } : {}, + ...parentMaxTokens !== void 0 ? { maxTokens: parentMaxTokens } : {}, + ...requested, + subagentDepth: childDepth + }; +} +/** +* Build the child session's durable creation metadata: the parent's workspace, +* its direct lineage, coarse product origin, the recursion budget that must +* survive persistence, the seed boundary that separates inherited parent +* history from child work, and the composition the child runs under. +* +* The preset is read from the parent's LIVE scope chain rather than from its +* header, because a parent that switched preset while blank runs on the newer +* composition and its header still names the older one. Recording it is what +* makes a child's history reconstructable: without it a cold read of the child +* resolves the deployment default and rebuilds turns under a tool set the +* child never had. +* @param parent - the delegating parent agent. +* @param childDepth - the resolved delegation depth to persist. +* @param lineageSeedLength - how many leading events came from the parent's log. +* @returns the `meta` for `ctx.agents.create()`. +*/ +function childSessionMeta(parent, childDepth, lineageSeedLength) { + const parentHeader = parent.session.header; + const agentPreset = parent.ctx.get("agentPresets")?.composedPreset(parent.ctx); + return { + ...parentHeader.cwd !== void 0 ? { cwd: parentHeader.cwd } : {}, + ...agentPreset === void 0 ? {} : { agentPreset }, + parentSession: parentHeader.id, + origin: "subagent", + delegationDepth: childDepth, + ...lineageSeedLength > 0 ? { seedLength: lineageSeedLength } : {} + }; +} +/** +* Model-facing delegation-scope statement for every in-process child. A +* runtime-context contribution rather than a system-prompt section, so the +* deployment's system prompt stays uniform across parents and children. +*/ +const SUBAGENT_DELEGATION_CONTEXT = "You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."; +/** +* Compose one child inside its creation window: join its parent's preset, +* register the fixed delegation-scope statement, then apply the child's own +* shadowing persona section and tool restriction, all owned by the child's +* scope and therefore invisible to its parent and siblings. Creation and cold +* resume both pass through here. +* +* The join comes first and the child's own registrations second, which is the +* order the layering already implies — the nearest scope wins a name, and a +* per-child restriction intersects with everything its chain admits — but +* stating it here keeps the two steps from being read as independent. +* +* The join and the per-child registrations live in ONE call because a child +* composed without the join is exactly the defect this function exists to +* prevent: with every model-facing row on the agent plane, a child that joins +* no preset sees an empty tool registry and none of its parent's prompt +* sections. Taking the parent as a parameter is what makes that omission +* unrepresentable at the call sites. +* @param childCtx - the child agent's scoped creation context. +* @param parent - the delegating parent whose composition the child joins. +* @param composition - the per-child persona and tool filter to install. +*/ +function applyChildComposition(childCtx, parent, composition) { + childCtx.get("agentPresets")?.composeFrom(childCtx, parent.ctx); + childCtx.systemPrompt.context({ + name: "subagent:delegation", + order: 120, + text: SUBAGENT_DELEGATION_CONTEXT + }); + if (composition.persona !== void 0) childCtx.systemPrompt.section({ + name: "deployment:persona", + order: 0, + text: composition.persona + }); + if (composition.toolFilter !== void 0) childCtx.tools.restrict(composition.toolFilter); +} +/** +* Capture the policy to seed into one delegation. Call synchronously before +* the child start's first await: a later parent switch belongs to the +* parent's future, not to this child. Only the parent session's explicit +* sandbox override is captured — never deployment defaults or one-shot +* grants — and the approval policy is pinned to `'never'` regardless of the +* parent's own policy. +* @param parent - the delegating parent agent. +* @returns the sandbox override (or `undefined` without one) and the approval pin. +*/ +function captureDelegatedPolicyOverrides(parent) { + return { + sandboxMode: parent.ctx.get("sandboxPolicy")?.overrideOf(parent.session), + approvalPolicy: parent.ctx.get("approval") === void 0 ? void 0 : "never" + }; +} +/** +* Append the captured delegation policy onto the child's own log as +* `source: 'delegation'` events inside the unpublished creation window, so the +* child's effective policy is reconstructable from its log alone. Appends land +* after any fork seed, so fresh policy wins stale seed state; later child +* switches still win over these events. +* @param childSession - the unpublished child's session. +* @param overrides - the policy captured at delegation. +*/ +function appendDelegatedPolicyOverrides(childSession, overrides) { + if (overrides.sandboxMode !== void 0) childSession.append("sandbox/mode", { + mode: overrides.sandboxMode, + source: "delegation" + }); + if (overrides.approvalPolicy !== void 0) childSession.append("approval/policy", { + policy: overrides.approvalPolicy, + source: "delegation" + }); +} +//#endregion +//#region lib/types/descriptor-seed.js +/** +* Seeding of a continuable child's durable descriptor event: the model-hidden +* record of the child's declared composition before its first request, so a +* later cold resume can reconstruct it from its own log. +* +* @module @deepseek-ai/dsh-subagent/descriptor-seed +*/ +/** +* Build the child's creation seed: any inherited parent-history prefix followed +* by one model-hidden, between-turn `descriptor` event. Staging through a +* `Session` assigns the sequence number and enforces the same lossless-JSON +* rules the durable log does. +* @param childId - the reserved child session id the staged log belongs to. +* @param seed - the inherited completed-turn prefix, or `undefined` for a fresh child. +* @param descriptor - the snapshotted composition record to persist. +* @returns the complete seed events, contiguous from sequence zero. +*/ +function seedDescriptorTurn(childId, seed, descriptor) { + const staged = Session.create(childId, seed); + staged.append("subagent/descriptor", descriptor); + return [...staged.events]; +} +//#endregion +//#region lib/types/continuation.js +/** +* Internal continuable-subagent manager: stable child ids, descriptor +* persistence, activation admission, the live ownership graph, cold resume, +* child-first disposal, and settlement delivery to the parent, behind +* `ctx.subagents`. +* +* A continuable child has one durable Session and at most one process-local +* {@link Activation} — one residency epoch for a reconstructed child Agent. An +* Activation is not a request, result, cancellation, or Task boundary: it may +* execute many FIFO turns and stays resident while descendants it created are +* still running. The Agent inbox is the only turn queue, so this manager owns +* residency while the Agent loop owns all turn ordering and execution. No +* continuable path creates a Task or an intermediate result-bearing wrapper. +* +* Because residency is this manager's alone to end, telling the parent that a +* child settled is its job too. An external `subagent/end` listener cannot do +* it correctly: that payload names no parent, the child handle is already +* disposed by then, and the release that wakes the parent's own settlement +* watcher has already run. See {@link SubagentContinuationManager.notifySettlement}. +* +* @module @deepseek-ai/dsh-subagent +*/ +/** +* Read one Activation's current disposal transaction. This indirection exists +* because TypeScript would otherwise narrow repeated reads of the mutable field +* inside a long-lived closure to constants instead of re-reading runtime state. +* @param activation - the Activation to inspect. +* @returns the in-flight or settled disposal, or `undefined` while resident. +*/ +function disposalOf(activation) { + return activation.disposal; +} +/** +* One line telling a parent that a background child is finished and why, in +* the parent's own task vocabulary. +* @param childId - the durable child the parent knows by id. +* @param stopReason - how the child's last ordinary turn ended. +* @returns the model-facing opening line of the settlement notice. +*/ +function settlementSummary(childId, stopReason) { + const subject = `Background subagent ${childId}`; + switch (stopReason) { + case "completed": return `${subject} finished and will do no further work unless you send it more.`; + case "aborted": return `${subject} was stopped before it finished.`; + case "max-tokens": return `${subject} ran out of room before it finished.`; + case "refusal": return `${subject} declined the task.`; + case "error": return `${subject} failed before it finished.`; + /* v8 ignore next 4 -- `SubagentResult['stopReason']` is merge-extensible, so this arm + * needs a backend that adds a variant; an unnameable ending is reported as unfinished + * rather than silently as success. */ + default: return `${subject} ended abnormally (${String(stopReason)}) before it finished.`; + } +} +/** Serialize each durable child's delivery, release, and disposal. */ +var ChildLock = class { + tails = /* @__PURE__ */ new Map(); + /** + * Run `operation` after every previously queued operation for `childId`. + * @param childId - the durable child whose operations are linearized. + * @param operation - the critical section to run in order. + * @returns the operation's own settlement. + */ + run(childId, operation) { + const result = (this.tails.get(childId) ?? Promise.resolve()).then(operation, operation); + const tail = result.then(() => void 0, () => void 0); + this.tails.set(childId, tail); + tail.then(() => { + if (this.tails.get(childId) === tail) this.tails.delete(childId); + }); + return result; + } +}; +/** +* The continuable-subagent orchestration service behind `ctx.subagents`. Tool +* schema and host adapters are consumers of this one contract; foreground +* one-shot delegation keeps calling `ctx.subagents.start()` and never enters +* this lifecycle. +*/ +var SubagentContinuationManager = class { + ctx; + host; + setupRegistry; + /** Child session id → its live Activation. Process-local, never durable. */ + activations = /* @__PURE__ */ new Map(); + /** Materializations admitted before drain, tracked through publication or rollback. */ + materializations = /* @__PURE__ */ new Set(); + locks = new ChildLock(); + /** Structural Cordis owner of every Activation handle. */ + ownerCtx; + /** + * Exact roots whose host teardown has begun, with the live lineage members + * observed under each root. Entries remain until that exact root leaves the + * Agent registry, closing admission throughout its host's teardown without + * poisoning a later same-id replacement. + */ + closingScopes = /* @__PURE__ */ new Map(); + draining = false; + constructor(ctx, host, setupRegistry) { + this.ctx = ctx; + this.host = host; + this.setupRegistry = setupRegistry; + const scope = ctx.plugin(function activationOwner() {}); + this.ownerCtx = scope.ctx; + ctx.on("agent/disposed", ({ agent }) => { + this.closingScopes.delete(agent); + }); + ctx.effect(function* () { + yield scope.dispose; + yield () => this.drain(); + }.bind(this), "subagents.continuations()"); + } + /** + * Start one continuable background child: reserve its durable identity, + * resolve the provider's detached creation spec, create the child Agent + * through the private activation-owner scope, establish any continuable-parent + * ownership, and submit the initial prompt. Resolves when inbox acceptance + * yields the message id — without waiting for the turn to start or for the + * message to reach the Session log. + * + * Every failure before that acceptance rejects without either id, disposing + * any created handle and rolling back the Activation and parent ownership. + * The caller signal owns lookup, materialization, and admission only until + * acceptance; afterwards the manager owns the Activation independently. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted initial prompt's message id. + */ + async startContinuable(spec) { + const request = spec.request; + const parent = request.parent; + this.assertAdmitting(parent); + this.requirePersistence(); + assertSubagentMaxDepth(request.maxDepth); + const childId = SessionId(randomUUID()); + const childDepth = resolveChildDepth(parent, request.maxDepth); + const agentProvider = request.agentOptions?.provider ?? parent.options.provider; + const agentModel = request.agentOptions?.model ?? parent.options.model; + const descriptor = snapshotSubagentDescriptor({ + mode: "continuable", + provider: spec.provider, + label: spec.label, + ...agentProvider !== void 0 ? { agentProvider } : {}, + ...agentModel !== void 0 ? { agentModel } : {}, + ...request.persona !== void 0 ? { persona: request.persona } : {}, + ...request.toolFilter !== void 0 ? { toolFilter: request.toolFilter } : {} + }); + const delegatedPolicies = captureDelegatedPolicyOverrides(parent); + const prepared = await this.host.prepareContinuable(spec.provider, { + sessionId: childId, + parent, + signal: spec.signal + }); + spec.signal.throwIfAborted(); + this.assertAdmitting(parent); + const lineageSeedLength = prepared.seed?.length ?? 0; + const seed = seedDescriptorTurn(childId, prepared.seed, descriptor); + return { + childId, + messageId: await this.locks.run(childId, async () => { + const activation = await this.materialize({ + childId, + provider: spec.provider, + parent, + create: { + seed, + meta: childSessionMeta(parent, childDepth, lineageSeedLength), + delegatedPolicies + }, + agentOptions: resolveChildAgentOptions(parent, request.agentOptions, childDepth), + composition: { + persona: request.persona, + toolFilter: request.toolFilter + }, + signal: spec.signal + }); + return this.submitMaterialized(activation, request.prompt, { kind: "user" }, parent, spec.signal); + }) + }; + } + /** + * Deliver one later message to a known continuable child as its next FIFO + * turn. Routing depends only on Activation residency: a `running` Activation + * enqueues, a `waiting` one wakes the same Agent, and an absent one + * cold-resumes a new Activation from the persisted Session. The Agent inbox + * is the only queue, so every accepted message has one observable order. + * + * The caller signal owns lookup, materialization, and admission only until + * inbox acceptance; afterwards the accepted turn cannot be cancelled through + * this service. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - the durable child session id. + * @param content - the user-role content to deliver. + * @param options - the message source fields and caller cancellation. + * @returns the accepted message's inbox id. + * @throws when parent authority, availability, or admission rejects the delivery. + */ + async followup(parent, childId, content, options) { + this.assertAdmitting(parent); + while (true) { + const live = await this.locks.run(childId, async () => { + const activation = this.activations.get(childId); + if (activation === void 0) return this.coldResume(parent, childId, content, options); + /* v8 ignore next 3 -- the send-versus-dispose cutoff: reaching this arm needs a + * delivery to observe the transaction inside the same critical section that opened it, + * which no test can schedule deterministically. The behavior is covered end-to-end by + * "cold-resumes a delivery that lost the race with final disposal". */ + if (activation.disposal !== void 0) return activation.disposal.then(() => void 0, () => void 0); + return this.submitAdmitted(activation, content, options.source, parent, options.signal); + }); + /* v8 ignore start -- only the lost-cutoff arm above returns undefined, so only that + * race reaches the retry below, which then cold-resumes a new Activation. */ + if (live !== void 0) return live; + this.assertAdmitting(parent); + options.signal.throwIfAborted(); + } + } + /** + * Interrupt one live continuable child's current turn. Admission is + * synchronous and the effect is asynchronous: this authorizes the caller, + * requests `Agent.cancel(cause, { keepInbox: true })` on the target, and + * returns without waiting for the target to observe the signal or reach + * quiescence. The Activation, its handle, accepted unclaimed inbox work, and + * already-published descendants are untouched; work already claimed into the + * interrupted turn is not requeued. Once the interrupted driver is idle, a + * waking send resumes the parked queue. + * + * An absent target is an accepted no-op, which uniformly covers natural + * completion races, repeated requests, one-shot ids, and unknown ids without + * consulting the durable catalog. A target whose disposal transaction is + * already open is likewise an accepted no-op after authorization. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the presented authority does + * not own the live target: a stale or self-targeting ancestor caller, a + * parent address that is not the live target's durable direct parent, or + * an ancestor outside the target's recorded live lineage. + */ + interrupt(targetSessionId, authority) { + if (authority.kind === "ancestor") { + const caller = authority.agent; + if (this.ctx.agents.get(caller.id) !== caller) throw new SubagentError(`interrupting "${targetSessionId}" requires the exact live ancestor agent`, "UNAUTHORIZED"); + if (caller.id === targetSessionId) throw new SubagentError(`agent "${caller.id}" cannot interrupt itself`, "UNAUTHORIZED"); + } + const activation = this.activations.get(targetSessionId); + if (activation === void 0) return; + if (authority.kind === "user") { + if (activation.handle.agent.session.header.parentSession !== authority.parentSessionId) throw new SubagentError(`subagent "${targetSessionId}" belongs to another parent session`, "UNAUTHORIZED"); + } else if (!activation.ancestry.has(authority.agent)) throw new SubagentError(`subagent "${targetSessionId}" is not a live descendant of agent "${authority.agent.id}"`, "UNAUTHORIZED"); + if (activation.disposal !== void 0) return; + activation.handle.agent.cancel(authority.kind === "user" ? { kind: "user" } : { kind: "parent" }, { keepInbox: true }); + } + /** + * Deliver explicitly selected content from one resident continuable child to + * its durable direct parent. Sender authorization, parent resolution, and + * send acceptance share one no-await span. Reporting neither concludes the + * child's turn nor changes its Activation lifetime. + * @param child - exact live reporting child; this is the authority credential. + * @param content - selected model-facing content. + * @param options - scheduling policy and pre-acceptance cancellation. + * @returns the stable identity of the message accepted by the parent. + * @throws {SubagentError} when the sender is unauthorized, the parent is not + * live, or continuation admission is closing. + */ + async reportFrom(child, content, options) { + options.signal.throwIfAborted(); + this.assertAdmitting(child); + const activation = this.authorizeReporter(child); + const parent = this.resolveReportParent(child); + return this.deliverReport(activation, parent, content, options.delivery); + } + /** Authorize only the exact Agent of one resident Activation. */ + authorizeReporter(child) { + const activation = this.activations.get(child.id); + if (activation === void 0 || activation.handle.agent !== child) throw new SubagentError(`agent "${child.id}" is not a live continuable subagent and cannot report`, "UNAUTHORIZED"); + /* v8 ignore next 6 -- only a synchronous re-entrant disposer can open this + * transaction between exact-agent authorization and this no-await cutoff. */ + if (activation.disposal !== void 0) throw new SubagentError(`subagent "${child.id}" activation is being disposed; the report was not delivered`, "ACTIVATION_CLOSING"); + return activation; + } + /** Resolve the reporting child's live direct parent from durable lineage. */ + resolveReportParent(child) { + const parentId = child.session.header.parentSession; + /* v8 ignore next -- every continuation-managed child has direct-parent metadata. */ + const parent = parentId === void 0 ? void 0 : this.ctx.agents.get(parentId); + if (parent === void 0) throw new SubagentError("direct parent is not live; report was not delivered", "PARENT_UNAVAILABLE"); + return parent; + } + /** Deliver one framed report through the selected parent scheduling preset. */ + deliverReport(activation, parent, content, delivery) { + const message = createUserMessage({ + content: [{ + type: "text", + text: `Background subagent ${activation.childId} reported:` + }, ...content], + source: { + kind: "subagent-report", + form: "relay", + senderSessionId: activation.childId + } + }); + if (delivery === "wakeup") this.sendWaking(parent, message, () => { + this.sendReport(parent, message, delivery); + }); + else this.sendReport(parent, message, delivery); + return message.id; + } + /** + * Perform one waking send to a parent, accounted against that parent's own + * Activation when it has one. Registering the id before the send is what + * keeps a continuation-managed parent from being judged quiescent in the + * window between `followup()` and the microtask that admits it. + * @param parent - the exact live parent receiving the waking message. + * @param message - the message whose id is accounted. + * @param send - the synchronous waking send to perform. + */ + sendWaking(parent, message, send) { + const parentActivation = this.activations.get(parent.id); + if (parentActivation !== void 0 && parentActivation.handle.agent === parent) this.admitWaking(parentActivation, message.id, send); + else send(); + } + /** Send one report while translating only the parent's own rejection. */ + sendReport(parent, message, delivery) { + try { + if (delivery === "wakeup") parent.followup(message); + else parent.inject(message); + } catch (error) { + throw new SubagentError("direct parent is not live; report was not delivered", "PARENT_UNAVAILABLE", { cause: error }); + } + } + /** + * Close admission, await every already-admitted materialization through + * publication or rollback, then dispose the stable live Activation forest + * child-first. Sibling branches drain independently: one failure is recorded + * but never prevents the remaining handles from being attempted, and the + * aggregate rejects only after every branch settles. + * @returns once materialization is quiescent and every live Activation released its handle. + * @throws an aggregate error when any branch failed to release. + */ + async drain() { + this.draining = true; + await Promise.all([...this.materializations].map((materialization) => materialization.settled)); + const owned = /* @__PURE__ */ new Set(); + for (const activation of this.activations.values()) for (const child of activation.ownedChildren) owned.add(child); + const roots = [...this.activations.values()].filter((activation) => !owned.has(activation.childId)); + await this.disposeRoots(roots, "activation(s)"); + } + /** + * Stop only the continuable descendants of exact live host-owned parents. + * Admission stays closed for those parent trees until each exact parent + * leaves the Agent registry; unrelated trees and manager-wide admission stay + * live. + * @param parents - exact live roots whose continuable descendants must stop. + * @returns once every retained descendant Activation released its handle. + * @throws an aggregate error after all scoped branches settle when any failed. + */ + async drainDescendants(parents) { + const roots = new Set(parents.filter((parent) => this.ctx.agents.get(parent.id) === parent)); + if (roots.size === 0) return; + for (const root of roots) this.closingMembers(root).add(root); + const targets = []; + for (const activation of this.activations.values()) { + const lineage = this.liveLineage(activation.handle.agent); + const owners = [...roots].filter((root) => activation.handle.agent !== root && activation.ancestry.has(root)); + if (owners.length === 0) continue; + targets.push(activation); + for (const owner of owners) { + const members = this.closingMembers(owner); + members.add(activation.handle.agent); + for (const agent of lineage) members.add(agent); + } + } + const materializations = [...this.materializations].filter((materialization) => { + const owners = [...roots].filter((root) => materialization.lineage.includes(root)); + for (const owner of owners) { + const members = this.closingMembers(owner); + for (const agent of materialization.lineage) members.add(agent); + } + return owners.length > 0; + }); + const ownedTargets = /* @__PURE__ */ new Set(); + for (const activation of targets) for (const child of activation.ownedChildren) ownedTargets.add(child); + const targetRoots = targets.filter((activation) => !ownedTargets.has(activation.childId)); + for (const activation of targets) this.dispose(activation).catch(() => void 0); + await Promise.all(materializations.map((materialization) => materialization.settled)); + await this.disposeRoots(targetRoots, "scoped activation(s)"); + } + /** Dispose independent roots and report every branch failure after all settle. */ + async disposeRoots(roots, failureSubject) { + const reasons = (await Promise.all(roots.map(async (activation) => { + try { + await this.dispose(activation); + return; + } catch (error) { + return error; + } + }))).filter((failure) => failure !== void 0); + if (reasons.length > 0) throw new SubagentError(`continuable subagent teardown failed for ${reasons.length} ${failureSubject}: ` + reasons.map((reason) => errorChain(reason)).join("; "), "ACTIVATION_TEARDOWN_FAILED"); + } + /** Return the retained member set for one exact scoped-teardown root. */ + closingMembers(root) { + const existing = this.closingScopes.get(root); + if (existing !== void 0) return existing; + const members = /* @__PURE__ */ new Set(); + this.closingScopes.set(root, members); + return members; + } + /** + * Return the exact currently resolvable ancestry from `agent` upward. The + * first element is always the supplied identity, even when it is already + * stale; each ancestor after it must be the registry's current exact entry. + */ + liveLineage(agent) { + const lineage = [agent]; + const seen = new Set([agent.id]); + let parentSession = agent.session.header.parentSession; + while (parentSession !== void 0) { + const parent = this.ctx.agents.get(parentSession); + if (parent === void 0 || seen.has(parent.id)) break; + lineage.push(parent); + seen.add(parent.id); + parentSession = parent.session.header.parentSession; + } + return lineage; + } + /** + * The teardown that closed continuable admission for this agent's lineage. + * `'manager'` is the whole manager draining; an Agent is the exact scoped root + * whose forest is closing. + * @param agent - the agent whose lineage is tested. + * @returns the closing teardown, or `undefined` while admission is open. + */ + closingTeardownFor(agent) { + if (this.draining) return "manager"; + const lineage = this.liveLineage(agent); + for (const [root, members] of this.closingScopes) if (members.has(agent) || lineage.includes(root)) return root; + } + /** Reject new admission once the manager or this exact parent tree began draining. */ + assertAdmitting(agent) { + const closing = this.closingTeardownFor(agent); + if (closing === void 0) return; + throw new SubagentError(closing === "manager" ? "continuable subagents are draining; the operation was not admitted" : `continuable subagents below parent "${closing.id}" are draining; the operation was not admitted`, "DRAINING"); + } + /** + * Derive residency from Agent quiescence and the owned-child set. `running` + * covers an active admission, an open turn, or accepted waking inbox work. + * + * `Agent.status` alone is insufficient: it stays `idle` between an accepted + * waking send and the microtask that admits it, so a synchronous inbox + * observer would see `settled` while a turn is already queued. `accepted` + * holds the ids this manager admitted but has not yet seen drained. + */ + stateOf(activation) { + if (activation.handle.agent.status === "running" || activation.accepted.size > 0) return "running"; + if (activation.ownedChildren.size > 0) return "waiting"; + return "settled"; + } + /** + * Cold-resume a persisted child: inspect and authorize its Session, fold the + * generic descriptor, create the Activation through `ctx.agents.resume()`, + * and submit the waiting turn. This never dispatches through a subagent + * provider — the persisted Session already holds the initial prefix and the + * descriptor is the whole reconstruction input. + */ + async coldResume(parent, childId, content, options) { + const persistence = this.requirePersistence(); + let loaded; + try { + loaded = await persistence.inspect(childId, options.signal); + } catch (error) { + options.signal.throwIfAborted(); + throw new SubagentError(`subagent "${childId}" is unavailable`, "NOT_RESUMABLE", { cause: error }); + } + options.signal.throwIfAborted(); + this.assertAdmitting(parent); + this.authorizeLineage(parent, childId, loaded.meta.parentSession); + const descriptor = foldSubagentDescriptor(loaded.events.slice(loaded.meta.seedLength ?? 0)); + if (descriptor === void 0 || descriptor.mode !== "continuable") throw new SubagentError(`subagent "${childId}" has no supported continuation state and cannot be resumed; do not retry send_message with this id`, "NOT_RESUMABLE"); + let activation; + try { + activation = await this.materialize({ + childId, + provider: descriptor.provider, + parent, + agentOptions: { + ...descriptor.agentProvider !== void 0 ? { provider: descriptor.agentProvider } : {}, + ...descriptor.agentModel !== void 0 ? { model: descriptor.agentModel } : {} + }, + composition: { + persona: descriptor.persona, + toolFilter: descriptor.toolFilter + }, + signal: options.signal + }); + } catch (error) { + options.signal.throwIfAborted(); + if (error instanceof SubagentError) throw error; + throw new SubagentError(`subagent "${childId}" is unavailable`, "NOT_RESUMABLE", { cause: error }); + } + return this.submitMaterialized(activation, content, options.source, parent, options.signal); + } + /** + * Submit to a freshly materialized Activation or roll it back completely. + * @param activation - the just-published Activation to admit or release. + * @param content - the initial or resumed message content. + * @param source - durable fields naming who supplied the accepted message. + * @param parent - the live direct parent authorizing admission. + * @param signal - caller cancellation owning admission until acceptance. + * @returns the accepted inbox message id. + */ + async submitMaterialized(activation, content, source, parent, signal) { + try { + return this.submitAdmitted(activation, content, source, parent, signal); + } catch (error) { + /* v8 ignore next -- rollback disposal failures must not mask the + * pre-acceptance signal, drain, or lifecycle failure. */ + await this.dispose(activation).catch(() => void 0); + throw error; + } + } + /** + * Create or resume the child Agent through the private activation-owner + * scope, install the handle in a fresh Activation, and register ownership on + * a continuation-managed parent. Rejection leaves no Activation, no handle, + * and no ownership membership. + */ + materialize(inputs) { + this.assertAdmitting(inputs.parent); + const settled = Promise.withResolvers(); + const lineage = this.liveLineage(inputs.parent); + const materialization = { + lineage, + settled: settled.promise + }; + this.materializations.add(materialization); + return this.materializeTracked(inputs, lineage).finally(() => { + this.materializations.delete(materialization); + settled.resolve(); + }); + } + /** + * Perform one tracked materialization. The caller keeps the drain barrier + * registered until this either returns a resident Activation or finishes + * rollback. + */ + async materializeTracked(inputs, parentLineage) { + const { childId, provider, parent, create } = inputs; + inputs.signal.throwIfAborted(); + const setup = (childCtx) => { + if (create !== void 0) appendDelegatedPolicyOverrides(childCtx.agent.session, create.delegatedPolicies); + applyChildComposition(childCtx, parent, inputs.composition); + return this.setupRegistry.apply(childCtx); + }; + const observer = this.host.observeActivation(provider, childId, parent); + const handle = create === void 0 ? await this.ownerCtx.agents.resume({ + resumeSessionId: childId, + agentOptions: inputs.agentOptions, + signal: inputs.signal, + setup + }) : await this.ownerCtx.agents.create({ + sessionId: childId, + meta: create.meta, + seed: create.seed, + agentOptions: inputs.agentOptions, + signal: inputs.signal, + setup + }); + const activation = { + childId, + parentSession: parent.id, + provider, + handle, + ancestry: new WeakSet([handle.agent, ...parentLineage]), + ownedChildren: /* @__PURE__ */ new Set(), + observer, + disposal: void 0, + accepted: /* @__PURE__ */ new Set(), + announced: false, + poke: Promise.withResolvers() + }; + this.activations.set(childId, activation); + try { + inputs.signal.throwIfAborted(); + this.assertAdmitting(parent); + this.acquireOwnership(parent, childId); + handle.agent.ctx.on("agent/inbox/claimed", ({ message }) => { + /* v8 ignore next -- a claim of an id this manager never admitted needs + * another sender on the same child, which no current path allows. */ + if (activation.accepted.delete(message.id)) this.wake(activation); + }); + handle.agent.ctx.on("agent/inbox/discarded", ({ message }) => { + if (activation.accepted.delete(message.id)) this.wake(activation); + }); + observer.start(handle.agent); + } catch (error) { + /* v8 ignore next -- rollback failure must not mask the admission failure + * that prevented this operation from returning an accepted message id. */ + await this.rollbackUnpublished(activation).catch(() => void 0); + throw error; + } + this.watchSettlement(activation); + return activation; + } + /** + * Release an Activation whose start edge was not published. The memoized + * transaction remains in the live map until handle disposal settles, so a + * concurrent drain or delivery observes the same closing boundary. + */ + rollbackUnpublished(activation) { + return activation.disposal ??= (async () => { + try { + await activation.handle.dispose(); + } finally { + this.activations.delete(activation.childId); + this.releaseOwnership(activation.childId); + } + })(); + } + /** + * Register the child in a continuation-managed parent's owned set before the + * child can run, so that parent cannot settle while the child is live. A + * top-level or other non-continuation Agent has no Activation and stays + * outside the waiting graph. + */ + acquireOwnership(parent, childId) { + const parentActivation = this.activations.get(parent.id); + if (parentActivation === void 0) return; + if (parentActivation.disposal !== void 0) throw new SubagentError(`subagent parent "${parent.id}" is being disposed; the child was not established`, "ACTIVATION_CLOSING"); + parentActivation.ownedChildren.add(childId); + } + /** Remove one child from its live owner's set and let that owner re-check settlement. */ + releaseOwnership(childId) { + for (const candidate of this.activations.values()) if (candidate.ownedChildren.delete(childId)) this.wake(candidate); + } + /** Let a settlement watcher re-observe quiescence after ownership or inbox changes. */ + wake(activation) { + activation.poke.resolve(); + activation.poke = Promise.withResolvers(); + } + /** + * Submit one message as the child's next FIFO turn and return its accepted + * inbox id. Acceptance is the operation's success boundary; the manager owns + * the Activation independently afterwards. + */ + submit(activation, content, source, parent) { + this.acquireOwnership(parent, activation.childId); + const message = createUserMessage({ + content, + source + }); + const accepted = this.admitWaking(activation, message.id, () => { + activation.handle.agent.followup(message); + }); + activation.announced = true; + return accepted; + } + /** + * Account one waking send across a resident Activation's settlement window. + * @param activation - Activation receiving waking inbox work. + * @param messageId - stable identity of the message about to be sent. + * @param send - synchronous send that publishes one enqueue occurrence. + * @returns the accepted message id. + */ + admitWaking(activation, messageId, send) { + activation.accepted.add(messageId); + try { + send(); + } catch (error) { + activation.accepted.delete(messageId); + throw error; + } + this.wake(activation); + return messageId; + } + /** + * Cross the final admission cutoff and submit without yielding. Signal abort, + * manager drain, or Activation disposal that wins before this synchronous + * span rejects without inbox acceptance. + */ + submitAdmitted(activation, content, source, parent, signal) { + signal.throwIfAborted(); + this.assertAdmitting(parent); + /* v8 ignore next 6 -- only a synchronous re-entrant disposer can change + * this field between the caller's live check and this no-await boundary. */ + if (disposalOf(activation) !== void 0) throw new SubagentError(`subagent "${activation.childId}" activation is being disposed; the message was not accepted`, "ACTIVATION_CLOSING"); + this.authorizeLineage(parent, activation.childId, activation.handle.agent.session.header.parentSession); + return this.submit(activation, content, source, parent); + } + /** + * Authorize one operation against the durable direct-parent lineage. Other + * agents, ancestors, teams, workflows, and hosts remain rejected until an + * explicit authority protocol has a production consumer. + */ + authorizeLineage(parent, childId, parentSession) { + if (this.ctx.agents.get(parent.id) !== parent) throw new SubagentError(`subagent "${childId}" delivery requires the exact live parent agent`, "UNAUTHORIZED"); + if (parentSession !== parent.id) throw new SubagentError(`subagent "${childId}" belongs to another parent session`, "UNAUTHORIZED"); + } + /** + * Follow one Activation to settlement: wait for Agent quiescence, then for + * every owned child to complete disposal, and dispose the handle once both + * hold. A `next-turn` delivered while `waiting` wakes the same Agent and + * returns it to `running`, so this re-observes rather than settling early. + */ + watchSettlement(activation) { + (async () => { + while (disposalOf(activation) === void 0) { + const poked = activation.poke.promise; + await Promise.race([activation.handle.agent.whenIdle(), poked]); + if (disposalOf(activation) !== void 0) return; + const settling = await this.locks.run(activation.childId, () => { + if (disposalOf(activation) !== void 0 || this.stateOf(activation) !== "settled") return Promise.resolve({ settling: false }); + return Promise.resolve({ + settling: true, + done: this.dispose(activation) + }); + }); + if (!settling.settling) { + if (activation.handle.agent.status !== "running") await poked; + continue; + } + try { + await settling.done; + } catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" activation teardown failed: ${errorChain(error)}`); + } + return; + } + })(); + } + /** + * Stop one Activation immediately, then release it child-first. The memoized + * transaction is installed before cancellation or recursive callbacks, so + * admission and reentrant teardown converge on the same owner. + * + * The final session flush is best effort and never prevents handle disposal + * or ownership release, because retaining a child would permanently pin its + * ancestors in `waiting`. + * @param activation - the residency epoch to stop and release. + * @returns the one disposal transaction owned by this Activation. + */ + dispose(activation) { + const existing = activation.disposal; + if (existing !== void 0) return existing; + const completion = Promise.withResolvers(); + activation.disposal = completion.promise; + this.finishDisposal(activation).then(completion.resolve, completion.reject); + return completion.promise; + } + /** + * Propagate stop synchronously, then finish the child-first release. + * @param activation - the Activation whose disposal transaction is installed. + * @returns once the handle and ownership edge are released. + */ + async finishDisposal(activation) { + this.wake(activation); + const { childId } = activation; + activation.handle.agent.cancel({ kind: "parent" }); + const idle = activation.handle.agent.whenIdle(); + const childDisposals = [...activation.ownedChildren].map((child) => this.activations.get(child)).filter((child) => child !== void 0).map((child) => this.dispose(child)); + const failures = []; + try { + const reasons = (await Promise.all(childDisposals.map(async (disposal) => { + try { + await disposal; + return; + } catch (error) { + return error; + } + }))).filter((reason) => reason !== void 0); + if (reasons.length > 0) failures.push(new SubagentError(`subagent "${childId}" child teardown failed: ${reasons.map((reason) => errorChain(reason)).join("; ")}`, "ACTIVATION_TEARDOWN_FAILED")); + await idle; + await this.flushFinalState(activation); + activation.observer.capture(activation.handle.agent); + } catch (error) { + failures.push(new SubagentError(`subagent "${childId}" activation teardown failed: ${errorChain(error)}`, "ACTIVATION_TEARDOWN_FAILED", { cause: error })); + } + try { + await activation.handle.dispose(); + } catch (error) { + failures.push(new SubagentError(`subagent "${childId}" activation handle disposal failed: ${errorChain(error)}`, "ACTIVATION_TEARDOWN_FAILED", { cause: error })); + } + let failure; + if (failures.length === 1) failure = failures[0]; + else if (failures.length > 1) failure = new SubagentError(`subagent "${childId}" activation teardown failed at ${failures.length} boundaries: ` + failures.map((item) => errorChain(item)).join("; "), "ACTIVATION_TEARDOWN_FAILED", { cause: new AggregateError(failures) }); + this.activations.delete(childId); + this.notifySettlement(activation, activation.observer.terminal(failure)); + this.releaseOwnership(childId); + activation.observer.settle(failure); + if (failure !== void 0) throw failure; + } + /** + * Tell the durable direct parent that this child produced everything it is + * going to. Unconditional for every child the caller received an id for: it + * does not consider whether the child reported, because the cases that most + * need it — a token ceiling, a model failure, cancellation, teardown — are + * exactly the ones where the child never got to choose. A materialization + * rolled back before its first acceptance stays silent, since the caller was + * told that child was not established. A parent that is no longer live is not + * an error; the child's own Session remains the durable record either way. + * A parent whose own lineage is already closing receives the notice without a + * wake, because teardown is not a reason to start a turn. + * + * Never blocks disposal. A delivery failure is logged and dropped, because + * retaining a child to retry a notice would pin its whole ancestry in + * `waiting` forever. + * @param activation - the settling Activation, still owned by its parent. + * @param terminal - how this epoch ended, as the terminal edge will report it. + */ + notifySettlement(activation, terminal) { + if (!activation.announced) return; + try { + const parent = this.ctx.agents.get(activation.parentSession); + if (parent === void 0) return; + const summary = settlementSummary(activation.childId, terminal.stopReason); + const message = createUserMessage({ + content: [{ + type: "text", + text: summary + }, ...terminal.output === void 0 ? [{ + type: "text", + text: "It left no closing message." + }] : [{ + type: "text", + text: "Its closing message:" + }, ...terminal.output]], + source: { + kind: "subagent-settled", + form: "notice", + summary: boundContextSummary(summary), + senderSessionId: activation.childId + } + }); + if (this.closingTeardownFor(parent) !== void 0) { + parent.inject(message); + return; + } + this.sendWaking(parent, message, () => { + if (parent.status === "idle") parent.followup(message); + else parent.steer(message); + }); + } catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" settlement notice was not delivered to its parent: ` + errorChain(error)); + } + } + /** + * Request a best-effort final session flush after the child is quiescent. + * Listener failure is logged because flush participation cannot identify a + * particular persistence backend, and teardown must still release ownership. + * @param activation - the Activation whose final events should be flushed. + */ + async flushFinalState(activation) { + const child = activation.handle.agent; + try { + await child.ctx.sessions.flush(child.session); + } catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" best-effort final session flush failed; the persisted state may be unavailable or stale on resume: ${errorChain(error)}`); + } + } + /** Resolve the persistence service continuable children require, or fail loud. */ + requirePersistence() { + const persistence = this.ctx.get("sessionPersistence"); + if (persistence === void 0) throw new SubagentError("continuable subagents require session persistence (load a dsh-session-persistence backend)", "PERSISTENCE_UNAVAILABLE"); + return persistence; + } +}; +//#endregion +//#region lib/types/activation-setup-registry.js +/** +* Internal registry of deployment capabilities composed into every continuable +* child's unpublished creation context. +* +* A contribution grants a child-scoped capability without teaching the +* continuation manager which capabilities exist. The manager owns residency; +* this registry owns the join between plugin lifetime, unpublished setup, and +* Activation disposal, so no installation outlives either owner and no removed +* contribution can be installed after revocation reports completion. +* +* @module @deepseek-ai/dsh-subagent/activation-setup-registry +*/ +/** Re-read mutable removal state after a contribution may have revoked itself. */ +function isRemoved(registration) { + return registration.removed; +} +/** +* Owns continuable-child setup registrations, installations, rollback, child +* cleanup, and immediate live revocation. +*/ +var SubagentActivationSetupRegistry = class { + /** Live contributions in installation order. */ + registrations = /* @__PURE__ */ new Set(); + /** Child context to its live installations. */ + byChild = /* @__PURE__ */ new Map(); + /** + * Register one contribution. + * @param contribution - synchronous child-scope installer. + * @returns an idempotent registration undo. + * @throws after attempting every installation when any disposer fails. + */ + register(contribution) { + const registration = { + contribution, + removed: false, + installations: /* @__PURE__ */ new Set() + }; + this.registrations.add(registration); + return () => { + if (registration.removed) return; + registration.removed = true; + this.registrations.delete(registration); + this.releaseAll([...registration.installations], "contribution removal"); + }; + } + /** + * Install every live contribution into one unpublished child context. + * @param childCtx - the child's unpublished scoped context. + * @returns the provisioning commit consumed at Agent publication. + */ + apply(childCtx) { + const state = { + installations: [], + invalidated: false + }; + try { + for (const registration of [...this.registrations]) { + /* v8 ignore next -- only a synchronous re-entrant revocation of an + * already-snapshotted registration reaches this guard. */ + if (registration.removed) continue; + const installation = { + registration, + childCtx, + dispose: registration.contribution(childCtx), + released: false, + transaction: state + }; + registration.installations.add(installation); + state.installations.push(installation); + let indexed = this.byChild.get(childCtx); + if (indexed === void 0) { + indexed = /* @__PURE__ */ new Set(); + this.byChild.set(childCtx, indexed); + } + indexed.add(installation); + if (isRemoved(registration)) this.release(installation); + } + } catch (error) { + try { + this.releaseAll([...state.installations], "setup rollback"); + } catch (releaseFailure) {} + throw error; + } + childCtx.effect(() => () => { + this.releaseChild(childCtx); + }, "subagents.activationSetup()"); + return { commit: () => { + if (state.invalidated) throw new SubagentError("a continuable-subagent setup contribution was revoked while this child was being built; the child was not established", "ACTIVATION_SETUP_REVOKED"); + for (const installation of state.installations) installation.transaction = void 0; + } }; + } + /** Release every remaining installation owned by one disposed child scope. */ + releaseChild(childCtx) { + const indexed = this.byChild.get(childCtx) ?? []; + this.releaseAll([...indexed], "child scope disposal"); + } + /** + * Release a batch completely before reporting disposer failures. + * @param installations - records to release. + * @param during - operation name for diagnostics. + */ + releaseAll(installations, during) { + const failures = []; + for (const installation of installations) try { + this.release(installation); + } catch (error) { + failures.push(error); + } + if (failures.length === 0) return; + throw new SubagentError(`continuable-subagent setup ${during} failed to release ${failures.length} installation(s): ` + failures.map((failure) => errorChain(failure)).join("; "), "ACTIVATION_SETUP_RELEASE_FAILED"); + } + /** Drop one installation from both indices and dispose it exactly once. */ + release(installation) { + if (installation.released) return; + installation.released = true; + installation.registration.installations.delete(installation); + const indexed = this.byChild.get(installation.childCtx); + /* v8 ignore next 4 -- every live installation is indexed until this method removes it. */ + if (indexed !== void 0) { + indexed.delete(installation); + if (indexed.size === 0) this.byChild.delete(installation.childCtx); + } + if (installation.transaction !== void 0) installation.transaction.invalidated = true; + installation.dispose(); + } +}; +//#endregion +//#region lib/types/list-children.js +/** +* Read-only enumeration of durable subagent children and descendant trees +* straight from the live session store and optional session persistence — no +* query service. Candidates come from one live-preferred corpus; each child's +* mode/label is the registered `subagent` projection unit's value, resolved +* down a three-rung ladder: the registry's watermark cache for a live child, +* a durable projection-cache row when it serves an own-suffix identity (the +* seq gate), and one persistence inspection folded through the registry +* otherwise, validated against the enumerated lifecycle. The projection fold +* is the single classification authority — this module parses no descriptor +* itself. Absent persistence, enumeration is live-only: a cold child is +* unreachable for resume anyway, so its absence is capability absence, not an +* error. The module owns no catalog state and does not consult Activation, +* Agent-registry, continuation-manager, or provider state. +* +* @module @deepseek-ai/dsh-subagent +*/ +/** +* Concurrent cold inspections per listing; a constant because it bounds one +* read-only scan of local media, not deployment behavior. Should a networked +* persistence backend appear, promote it to a validated `Config` field. +*/ +const COLD_READ_CONCURRENCY = 4; +/** +* Enumerate one parent's origin-classified direct children from the +* live-preferred merge of `ctx.sessions` and optional session persistence, +* serving each identity from the `subagent` projection unit: the registry's +* watermark snapshot for a live child; for a cold one, a durable +* projection-cache row when it serves an own-suffix identity (the seq gate), +* else one bounded-concurrency persistence inspection folded through the +* registry. +* @see SubagentRuntime.listChildren for the public cancellation and failure contract. +* @param ctx - context carrying the session store, the projection registry, +* optional persistence, and the optional projection cache. +* @param parentSessionId - parent session whose direct children are listed. +* @param signal - caller-owned cancellation observed around every persistence read. +* @returns children and per-child diagnostics ordered by `createdAt`, then id. +* @throws {@link SubagentError} when the projection registry or the session +* store is not mounted, or the caller cancels the listing. +*/ +async function listChildren(ctx, parentSessionId, signal) { + const listing = await prepareListing(ctx, signal); + return (await resolveCandidateRows([...listing.corpus.values()].filter((record) => record.header.parentSession === parentSessionId && record.header.origin === "subagent").sort(compareCorpusRecords), listing, signal)).filter((row) => row !== void 0); +} +/** +* Enumerate every session-backed subagent below one root in stable pre-order. +* Ordinary sessions and one-shot children remain traversal nodes, so a +* continuable child below either is still discovered. Classification uses the +* same projection-backed runtime as {@link listChildren}; no Agent is loaded or +* resumed. +* @see SubagentRuntime.listDescendants for the public cancellation and failure contract. +* @param ctx - context carrying the session store, projection registry, and optional persistence/cache. +* @param rootSessionId - session whose complete descendant tree is listed. +* @param signal - caller-owned cancellation observed around every persistence read. +* @returns interpreted subagents with durable direct-parent and root-relative depth. +* @throws {@link SubagentError} under the same conditions as {@link listChildren}. +*/ +async function listDescendants(ctx, rootSessionId, signal) { + const listing = await prepareListing(ctx, signal); + const positioned = descendantCandidates(listing.corpus, rootSessionId); + const rows = await resolveCandidateRows(positioned.map((candidate) => candidate.record), listing, signal); + const entries = []; + positioned.forEach((position, index) => { + const row = rows[index]; + if (row !== void 0) entries.push({ + ...row, + parentId: position.parentId, + depth: position.depth + }); + }); + return entries; +} +/** Resolve listing services once and build one live-preferred session corpus. */ +async function prepareListing(ctx, signal) { + const projections = ctx.get("sessionProjections"); + if (projections === void 0) throw new SubagentError("listing subagents requires the sessionProjections registry (load @deepseek-ai/dsh-session-projection)", "SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE"); + const sessions = ctx.get("sessions"); + if (sessions === void 0) throw new SubagentError("listing subagents requires the session store (load @deepseek-ai/dsh-session)", "SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE"); + assertListingNotCancelled(signal); + const persistence = ctx.get("sessionPersistence"); + const cache = ctx.get("sessionProjectionCache"); + let persistedHeaders = []; + if (persistence !== void 0) { + try { + persistedHeaders = await persistence.list(signal); + } catch (error) { + assertListingNotCancelled(signal); + throw error; + } + assertListingNotCancelled(signal); + } + const corpus = /* @__PURE__ */ new Map(); + for (const header of persistedHeaders) corpus.set(header.id, { + header, + live: void 0 + }); + for (const session of sessions.list()) corpus.set(session.header.id, { + header: session.header, + live: session + }); + const subagentParents = /* @__PURE__ */ new Set(); + for (const record of corpus.values()) if (record.header.origin === "subagent" && record.header.parentSession !== void 0) subagentParents.add(record.header.parentSession); + return { + projections, + persistence, + cache, + corpus, + subagentParents + }; +} +/** Resolve projection-backed rows for aligned candidates with bounded cold reads. */ +async function resolveCandidateRows(candidates, listing, signal) { + const { projections, persistence, cache, subagentParents } = listing; + const rows = Array.from({ length: candidates.length }); + const coldReads = []; + candidates.forEach((candidate, index) => { + const childId = candidate.header.id; + if (candidate.live === void 0) { + coldReads.push({ + index, + header: candidate.header + }); + return; + } + let identity; + try { + identity = projections.snapshot(candidate.live).values.subagent; + } catch { + rows[index] = { + kind: "diagnostic", + id: childId, + reason: "corrupt" + }; + return; + } + if (identity === void 0 || identity === null) return; + rows[index] = childRow(childId, identity, "running", subagentParents.has(childId)); + }); + if (persistence !== void 0 && coldReads.length > 0) { + const queue = [...coldReads]; + await Promise.all(Array.from({ length: Math.min(COLD_READ_CONCURRENCY, queue.length) }, async () => { + for (let job = queue.shift(); job !== void 0; job = queue.shift()) rows[job.index] = await resolveColdIdentity(persistence, projections, cache, job.header, subagentParents.has(job.header.id), signal); + })); + } + assertListingNotCancelled(signal); + return rows; +} +/** Build origin-classified candidates from the complete tree without recursion. */ +function descendantCandidates(corpus, rootSessionId) { + const children = /* @__PURE__ */ new Map(); + for (const record of corpus.values()) { + const parentId = record.header.parentSession; + if (parentId === void 0) continue; + const siblings = children.get(parentId); + if (siblings === void 0) children.set(parentId, [record]); + else siblings.push(record); + } + for (const siblings of children.values()) siblings.sort(compareCorpusRecords); + const positioned = []; + const stack = (children.get(rootSessionId) ?? []).map((record) => ({ + record, + parentId: rootSessionId, + depth: 1 + })).reverse(); + const visited = new Set([rootSessionId]); + while (stack.length > 0) { + const position = stack.pop(); + const id = position.record.header.id; + if (visited.has(id)) continue; + visited.add(id); + if (position.record.header.origin === "subagent") positioned.push(position); + const descendants = children.get(id) ?? []; + for (const record of [...descendants].reverse()) stack.push({ + record, + parentId: id, + depth: position.depth + 1 + }); + } + return positioned; +} +/** Compare siblings by durable creation time, then id. */ +function compareCorpusRecords(a, b) { + return a.header.createdAt - b.header.createdAt || a.header.id.localeCompare(b.header.id); +} +/** +* Resolve one cold candidate down the remaining ladder: a durable +* projection-cache row when it serves an own-suffix identity (the seq gate), +* otherwise one persistence inspection folded through the projection +* registry (the same detached recipe the API proxy uses for detached session +* projections). A failed inspection is one transient `unavailable` row +* retried on the next listing; an inspection naming another lifecycle, and a +* settled log the fold cannot identify — or that makes any registered unit +* throw — are final, so they report `corrupt`. +*/ +async function resolveColdIdentity(persistence, projections, cache, header, hasChildren, signal) { + const childId = header.id; + if (cache !== void 0) { + let cached; + try { + cached = cache.cachedSnapshot(header)?.values.subagent; + } catch { + cached = void 0; + } + if (cached !== void 0 && cached !== null && cached.seq >= (header.seedLength ?? 0)) return childRow(childId, cached, "inactive", hasChildren); + } + assertListingNotCancelled(signal); + let inspected; + try { + inspected = await persistence.inspect(childId, signal); + } catch { + assertListingNotCancelled(signal); + return { + kind: "diagnostic", + id: childId, + reason: "unavailable" + }; + } + assertListingNotCancelled(signal); + if (!sameLifecycle(inspected.meta, header)) return { + kind: "diagnostic", + id: childId, + reason: "corrupt" + }; + let identity; + try { + identity = projections.restore({}, inspected.events, 0).snapshot.values.subagent; + } catch { + return { + kind: "diagnostic", + id: childId, + reason: "corrupt" + }; + } + if (identity === void 0 || identity === null) return { + kind: "diagnostic", + id: childId, + reason: "corrupt" + }; + return childRow(childId, identity, "inactive", hasChildren); +} +/** Materialize one served identity as its child row. */ +function childRow(id, identity, activity, hasChildren) { + return identity.mode === "one-shot" ? { + kind: "child", + id, + mode: "one-shot", + ...identity.label !== void 0 ? { label: identity.label } : {}, + activity, + hasChildren + } : { + kind: "child", + id, + mode: "continuable", + label: identity.label, + activity, + hasChildren + }; +} +/** Immutable header fields that distinguish one session lifecycle from another under the same id. */ +const LIFECYCLE_WITNESS_KEYS = [ + "version", + "id", + "createdAt", + "cwd", + "parentSession", + "seedLength", + "delegationDepth" +]; +/** Whether an inspected log still belongs to the enumerated lifecycle. */ +function sameLifecycle(meta, expected) { + return LIFECYCLE_WITNESS_KEYS.every((key) => meta[key] === expected[key]); +} +/** Stop a listing at its next cancellation checkpoint. */ +function assertListingNotCancelled(signal) { + if (signal?.aborted) throw new SubagentError("subagent listing was cancelled", "CANCELLED"); +} +/** +* Fold turn boundaries around the child's own durable descriptor. +* +* A fork seed may contain an ancestor descriptor and completed turns. Every +* descriptor therefore resets the accumulated state; the healthy catalog +* admits only a child with exactly one descriptor in its own suffix, making +* the final reset the child's authoritative timing origin. +*/ +const subagentTimingProjectionDefinition = { + key: "subagentTiming", + schema: z.object({ + settledMs: z.number().int().nonnegative(), + active: z.object({ + since: z.number().int().nonnegative(), + through: z.number().int().nonnegative() + }).strict().optional() + }).strict(), + init: () => ({ + descriptorSeen: false, + settledMs: 0 + }), + apply: (state, event) => { + if (event.type === "turn/start") return state.descriptorSeen ? { + ...state, + active: { + since: event.time, + through: event.time + } + } : { + ...state, + pendingTurnStart: event.time + }; + if (event.type === "subagent/descriptor") { + const activeSince = state.active?.since ?? state.pendingTurnStart; + return { + descriptorSeen: true, + settledMs: 0, + ...activeSince === void 0 ? {} : { active: { + since: activeSince, + through: event.time + } } + }; + } + if (event.type === "turn/end") { + if (!state.descriptorSeen) { + if (state.pendingTurnStart === void 0) return state; + const { pendingTurnStart: _closed, ...next } = state; + return next; + } + if (state.active === void 0) return state; + const { active, ...rest } = state; + return { + ...rest, + settledMs: state.settledMs + Math.max(0, event.time - active.since) + }; + } + if (state.active === void 0) return state; + return { + ...state, + active: { + ...state.active, + through: event.time + } + }; + }, + view: (state) => ({ + settledMs: state.settledMs, + ...state.active === void 0 ? {} : { active: state.active } + }), + stateVersion: 2 +}; +const identitySchema = z.discriminatedUnion("mode", [z.object({ + mode: z.literal("one-shot"), + label: z.string().optional(), + seq: z.number().int().nonnegative() +}).strict(), z.object({ + mode: z.literal("continuable"), + label: z.string(), + seq: z.number().int().nonnegative() +}).strict()]).nullable(); +/** Interpret one `subagent/descriptor` event's identity; no value when the payload cannot be trusted. */ +function descriptorIdentity(event) { + let descriptor; + try { + descriptor = foldSubagentDescriptor([event]); + } catch { + descriptor = void 0; + } + if (descriptor === void 0) return void 0; + return descriptor.mode === "one-shot" ? { + mode: "one-shot", + ...descriptor.label !== void 0 ? { label: descriptor.label } : {}, + seq: event.seq + } : { + mode: "continuable", + label: descriptor.label, + seq: event.seq + }; +} +/** +* Fold the durable mode/label identity from `subagent/descriptor` events, +* last-wins: a fork seed may replay an ancestor's descriptor, and the child's +* own descriptor must override it — the same reset discipline as +* {@link subagentTimingProjectionDefinition}. A malformed or unknown-version +* payload resets to the `null` sentinel instead of throwing, so a fork of a +* healthy ancestor never inherits an identity its own descriptor failed to +* establish — and the reset survives every JSON push frame, so a consumer +* holding the earlier identity replaces it instead of keeping it stale; +* `null` ⟺ no valid descriptor, with the causes deliberately undistinguished. +*/ +const subagentIdentityProjectionDefinition = { + key: "subagent", + schema: identitySchema, + init: () => ({}), + apply: (state, event) => { + if (event.type !== "subagent/descriptor") return state; + const identity = descriptorIdentity(event); + return identity === void 0 ? {} : { identity }; + }, + view: (state) => state.identity ?? null, + stateVersion: 2 +}; +//#endregion +//#region lib/types/out-of-process.js +/** +* Provider-side vocabulary for OUT-OF-PROCESS subagent backends — the pieces +* that enforce this seam's own contracts around a child in another process: +* the no-capabilities advertisement, timing-bound validation, child +* working-directory resolution (config override, else the delegating parent +* session's workspace), the never-reject result settlement, and the standard +* run-handle publication. Backends compose these with their own wire drivers; +* the process machinery itself (spawn, env scrub, tree-scoped teardown) +* belongs to the `dsh-subprocess` seam. +* +* @module @deepseek-ai/dsh-subagent/out-of-process +*/ +/** +* The capability advertisement of an out-of-process backend: NONE. A child in +* another process cannot honor parent-enforced start features +* (`outputSchema`/`maxDepth`/`toolFilter`/`persona`), so the service rejects a +* request needing any of them before `start` runs — never accepted-then-ignored. +*/ +const NO_START_CAPABILITIES = Object.freeze({ + outputSchema: false, + depthLimit: false, + toolFilter: false, + persona: false +}); +/** +* Assert a configured timing bound is a positive finite number (it bounds a +* teardown or shutdown wait; zero, negative, or NaN would skip or wedge it). +* @param prefix - the consuming plugin's diagnostic prefix (e.g. `subagent-acp`). +* @param name - the config field name, for the diagnostic. +* @param value - the configured value. +*/ +function assertPositiveFinite(prefix, name, value) { + if (!Number.isFinite(value) || value <= 0) throw new Error(`${prefix}: ${name} must be a positive finite number`); +} +/** +* Whether `path` names an existing directory the harness can ENTER. The +* search-permission probe matters: `statSync().isDirectory()` is true for a +* mode-600 directory, but a subprocess cwd needs `X_OK` or spawn fails EACCES. +*/ +function isEnterableDirectory(path) { + try { + if (!statSync(path).isDirectory()) return false; + accessSync(path, constants.X_OK); + return true; + } catch { + return false; + } +} +/** +* Assert `cwd` can actually host the child: absolute (it doubles as the +* child's workspace identity, and a relative path would be re-anchored to the +* server process's launch directory) and an existing directory (fail here, +* before the process boundary, instead of as an ambiguous spawn ENOENT). +* @param prefix - the consuming plugin's diagnostic prefix. +* @param label - which source supplied the value, for the diagnostic. +* @param cwd - the candidate working directory. +* @returns `cwd`, validated. +*/ +function assertUsableCwd(prefix, label, cwd) { + if (!isAbsolute(cwd)) throw new Error(`${prefix}: ${label} must be an absolute path: ${cwd}`); + if (!isEnterableDirectory(cwd)) throw new Error(`${prefix}: ${label} is not an accessible directory: ${cwd}`); + return cwd; +} +/** +* Validate a configured `cwd` override ONCE, at plugin load: reject the empty +* string (`path.resolve('')` is the process cwd — it would silently +* reintroduce the launch-directory fallback this resolution removes), +* interpret a relative path against the harness launch directory, and require +* an enterable directory. +* @param prefix - the consuming plugin's diagnostic prefix. +* @param cwd - the configured override, or `undefined` when the config omits it. +* @returns the validated absolute override, or `undefined` when omitted. +*/ +function validateConfiguredCwd(prefix, cwd) { + if (cwd === void 0) return void 0; + if (cwd === "") throw new Error(`${prefix}: config cwd must not be empty — omit the key to inherit the parent session cwd`); + return assertUsableCwd(prefix, "config cwd", resolve(cwd)); +} +/** +* Resolve the child's working directory at start: the deployment override +* when configured (already validated at load), else the parent session's +* workspace cwd (validated here, its earliest resolvable point). Fails loud +* when neither exists — falling back to the harness process cwd would +* silently bind the child to the server's launch directory instead of the +* delegating session's workspace (one server process serves many sessions, +* each with its own cwd). +* @param prefix - the consuming plugin's diagnostic prefix. +* @param configured - the load-validated override, or `undefined`. +* @param parentCwd - the delegating parent session's workspace cwd, if any. +* @returns the absolute child working directory. +*/ +function resolveChildCwd(prefix, configured, parentCwd) { + if (configured !== void 0) return configured; + if (parentCwd === void 0) throw new Error(`${prefix}: no working directory for the child — configure \`cwd\` or delegate from a parent session that has one`); + return assertUsableCwd(prefix, "parent session cwd", parentCwd); +} +/** Normalize an unknown thrown value to an Error (the catch binding is `unknown`). */ +function toError(value) { + /* v8 ignore next */ + return value instanceof Error ? value : new Error(String(value)); +} +/** +* Settle an out-of-process run result under the seam contract: `result` never +* rejects after publication. A normally completed or rejected attempt resolves +* as `aborted` when cancellation already settled locally; another rejection is +* flattened to `stopReason: 'error'` through the contained diagnostic sink. +* The abort listener is removed on every path. +* @param parts - the attempt, output snapshot, cancellation state, sink, and signal wiring. +* @returns the terminal result (never a rejection). +*/ +async function settleRunResult(parts) { + try { + const result = await parts.attempt(); + return parts.cancelled() ? { + output: parts.collectOutput(), + stopReason: "aborted" + } : result; + } catch (error) { + if (parts.cancelled()) return { + output: parts.collectOutput(), + stopReason: "aborted" + }; + try { + parts.onError?.(toError(error), "error"); + } catch {} + return { + output: parts.collectOutput(), + stopReason: "error" + }; + } finally { + parts.signal.removeEventListener("abort", parts.onAbort); + } +} +/** +* Publish the seam run handle for an out-of-process child. `dispose()` is +* idempotent (one memoized teardown): it removes the abort listener, settles +* local cancellation — there is no assumption the child cooperates — and then +* awaits the backend's teardown to actual exit. +* @param parts - the run identity, result, cancellation wiring, and teardown. +* @returns the seam run handle (`localAgent` is `undefined` for remote runs). +*/ +function subprocessRunHandle(parts) { + let disposal; + return { + id: parts.id, + localAgent: void 0, + result: parts.result, + dispose() { + if (disposal !== void 0) return disposal; + parts.signal.removeEventListener("abort", parts.onAbort); + parts.requestCancel(); + disposal = parts.teardown(); + return disposal; + } + }; +} +//#endregion +//#region lib/types/run-settlement.js +/** +* Settlement of one ONE-SHOT subagent run into a background-Task outcome. Only +* the one-shot background path uses Jobs; continuable children have no Task, +* no per-message result, and no Task cancellation. +* +* @module @deepseek-ai/dsh-subagent/run-settlement +*/ +/** Flatten a child's final output blocks to the task's final text. */ +function finalText(blocks) { + return blocks.filter((block) => block.type === "text").map((block) => block.text).join(""); +} +/** +* Map a child result to the task outcome: completed carries final text, +* aborted is killed, and every other reason is failed without partial output. +* @param result - child terminal result. +* @returns outcome for the `ctx.jobs` registration. +*/ +function runOutcome(result) { + switch (result.stopReason) { + case "completed": return { + status: "completed", + output: finalText(result.output) + }; + case "aborted": return { status: "killed" }; + case "error": + case "max-tokens": + case "refusal": return { + status: "failed", + detail: result.stopReason + }; + default: return { + status: "failed", + detail: String(result.stopReason) + }; + } +} +/** +* Await the child result, dispose the run, then return its task outcome. Result +* and disposal failures become `failed`; when both fail, both details survive. +* @param run - live run to settle and release. +* @returns outcome after child resources are released. +*/ +async function settleRun(run) { + let outcome; + try { + outcome = runOutcome(await run.result); + } catch (error) { + outcome = { + status: "failed", + detail: String(error) + }; + } + try { + await run.dispose(); + } catch (error) { + return { + status: "failed", + detail: `${outcome.detail === void 0 ? "" : `${outcome.detail}; `}dispose failed: ${String(error)}` + }; + } + return outcome; +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for the subagent capability seam (`ctx.subagents`): a named-provider registry plus a +* capability-validating asynchronous start API. Providers establish a +* child before returning its run, so fulfillment is the single publication and +* ownership-transfer boundary. +* +* Unlike the bash seam (one executor per context, second load throws), MULTIPLE +* providers coexist here: each registers under a unique name and a caller picks +* one by name. The shape mirrors the LLM adapter registry +* (`LlmRuntime.registerAdapter`), not the single-service bash executor. +* +* This package owns the Service Definition role of the capability seam. Service Providers +* (`@deepseek-ai/dsh-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing +* consumer (`@deepseek-ai/dsh-tool-subagent`) are separate packages. +* +* Public operations express caller intent: `start` returns one published owned +* one-shot run, `startContinuable` establishes a durable continuable child, and +* `followup` delivers later content without exposing whether the child is +* resident. Continuable children never become a {@link SubagentRun}: the +* continuation manager holds their `AgentHandle` directly and orders every turn +* through the child's own inbox, so providers contribute only the detached +* creation spec and see no handle, turn, or teardown. Child and descendant +* discovery read the live session store and optional session persistence +* directly and do not require that continuation runtime. +* +* Same-process providers are trusted typed collaborators. Requests, provider +* descriptors, results, and lifecycle payloads are borrowed immutable values; +* serialization and hostile-input validation belong at real process, worker, +* persistence, and model boundaries. +* +* @module @deepseek-ai/dsh-subagent +*/ +/** Named provider registry with one-shot runs, durable discovery, and continuable-child operations. */ +var SubagentRuntime = class extends Service { + providers = /* @__PURE__ */ new Map(); + continuations; + /** Deployment contributions composed into unpublished continuable children. */ + setupRegistry = new SubagentActivationSetupRegistry(); + /** + * The contained lifecycle-edge publisher. Built here because scoped dispatch + * keys its carrier by this exact service instance, whose own context filter + * composes into the carrier. + */ + emitLifecycle; + constructor(ctx) { + super(ctx, "subagents"); + this.emitLifecycle = createLifecycleEmitter(this.ctx, (parent) => scopeTarget(this, parent)); + ctx.inject(["agents"], (childCtx) => { + const manager = new SubagentContinuationManager(childCtx, { + prepareContinuable: (name, request) => this.prepareContinuable(name, request), + observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent) + }, this.setupRegistry); + this.continuations = manager; + childCtx.effect(() => () => { + /* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */ + if (this.continuations === manager) this.continuations = void 0; + }, "subagents.continuationBinding()"); + }); + ctx.inject(["sessionProjections"], (projectionCtx) => { + projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition); + projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition); + }); + } + /** + * Establish one durable continuable child and deliver its initial prompt. + * Resolves when the child's inbox accepts that prompt, without waiting for the + * turn to start or for the message to reach the Session log; any earlier + * failure rejects with no ids and rolls back the child entirely. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted prompt's message id. + * @throws when continuation services are unavailable or materialization fails. + */ + async startContinuable(spec) { + return this.requireContinuations().startContinuable(spec); + } + /** + * Deliver one later message to a continuable child as its next FIFO turn. A + * resident child's Agent inbox accepts it directly (waking a `waiting` + * Activation), while an absent one is cold-resumed from its persisted + * Session. The Agent inbox is the only queue, so every accepted message has + * one observable order. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - durable child session id. + * @param content - user-role content to deliver. + * @param options - the message source fields and caller cancellation, which stops the + * operation only before inbox acceptance. + * @returns the accepted message's inbox id. + * @throws when continuation services are unavailable, parent authority is + * rejected, or the message was not admitted. + */ + async followup(parent, childId, content, options) { + return this.requireContinuations().followup(parent, childId, content, options); + } + /** + * Interrupt one live continuable child's current turn under a human parent + * address or an exact live ancestor Agent. Fire-and-return: the cancel + * signal is issued before this returns, but the target may keep running + * until it observes the signal. Unclaimed pending inbox work, the Activation, + * and published descendants are preserved; claimed work is not requeued. + * Once the interrupted driver is idle, a waking send resumes the parked FIFO + * queue. An absent target — including a one-shot or unknown id — + * is an accepted no-op, as is a manager-less composition, which cannot own a + * live Activation. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the authority does not own the + * live target. + */ + interrupt(targetSessionId, authority) { + this.continuations?.interrupt(targetSessionId, authority); + } + /** + * Deliver selected content from one live continuable child to its durable + * direct parent. The child is the authority credential; callers cannot name a + * recipient. Reporting does not conclude the child's turn or Activation. + * @param child - exact live reporting child. + * @param content - selected model-facing content. + * @param options - parent scheduling and pre-acceptance cancellation. + * @returns the stable identity of the parent-accepted message. + * @throws when continuation services are unavailable, sender authorization + * fails, or the direct parent is not live. + */ + async reportFrom(child, content, options) { + return this.requireContinuations().reportFrom(child, content, options); + } + /** + * Compose one deployment capability into every continuable child's + * unpublished creation context on fresh creation and cold resume. Grants wait + * for the next Activation; removing the contribution revokes every resident + * installation immediately. + * @param contribution - synchronous child-scope installer. + * @returns the exact Cordis effect disposer. + */ + registerContinuableSetup(contribution) { + return this.ctx.effect(() => this.setupRegistry.register(contribution), "subagents.registerContinuableSetup()"); + } + /** + * Close continuable admission below exact live parent Agents, stop only their + * visible descendant Activations synchronously, then await admitted scoped + * materializations and release those forests child-first. The scoped cutoff + * lasts until each exact parent leaves the registry; unrelated parent trees + * remain live. + * @param parents - exact host-owned parent Agents entering teardown. + * @returns once every retained descendant Activation released its `AgentHandle`. + * @throws an aggregate error after all branches settle when any failed. + */ + async drainContinuableDescendants(parents) { + const manager = this.continuations; + if (manager === void 0) return; + await manager.drainDescendants(parents); + } + /** + * Enumerate the parent's direct session-backed subagents without loading or + * resuming an Agent and without any query service: the listing merges the live + * session store with optional session persistence (live-preferred) and + * serves each child's durable mode/label from the registered `subagent` + * projection unit down a three-rung ladder — the registry's watermark + * snapshot for a live child; for a cold one, a durable projection-cache + * row when the optional cache serves an own-suffix identity (its `seq` + * gate proves the value postdates the fork seed, where a child's own + * descriptor is immutable once appended), else one persistence inspection + * folded through the registry. The + * projection fold is the single classification authority; per-child + * diagnostics relay a fold that served no identity or a failed inspection, + * never a list-time descriptor parse. Absent persistence, enumeration is + * live-only (a cold child cannot be resumed then either, so its absence is + * capability absence, not an error). This service consults no Agent + * registrations, Activations, or providers. + * + * Every persistence read receives `signal`, and the listing rechecks + * cancellation around each of those awaits. Read rejections that settle + * after an abort become a stable `SubagentError` with code `CANCELLED`. + * @param parentSessionId - parent session whose direct children are listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-child diagnostics ordered by `createdAt`, then id. + * @throws {@link SubagentError} when the projection registry or the session + * store is not mounted, or the caller cancels the listing. + */ + listChildren(parentSessionId, signal) { + return listChildren(this.ctx, parentSessionId, signal); + } + /** + * Enumerate the root's complete session-backed subagent tree in stable + * pre-order from one live-preferred corpus, without loading or resuming an + * Agent. Ordinary sessions and one-shot children remain traversal nodes so + * continuable descendants below them are discovered; each returned entry + * adds its durable `parentId` and root-relative `depth`. Identity resolution, + * diagnostics, optional persistence, and cancellation follow the same + * projection-backed contract as {@link listChildren}. + * @param rootSessionId - session whose complete descendant tree is listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-candidate diagnostics with tree position, in + * stable pre-order. + * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + */ + listDescendants(rootSessionId, signal) { + return listDescendants(this.ctx, rootSessionId, signal); + } + /** + * Register a provider under its name. Registration is effect-scoped and HMR + * safe; removing a provider blocks new starts but does not revoke runs that + * were already returned to their holders. + * @param provider - the trusted provider implementation. + * @returns the exact Cordis effect disposer. + */ + registerProvider(provider) { + const name = provider.name; + return this.ctx.effect(function* () { + if (this.providers.has(name)) throw new SubagentError(`a subagent provider named "${name}" is already registered`, "DUPLICATE_PROVIDER"); + this.providers.set(name, provider); + yield () => { + this.providers.delete(name); + this.emitLifecycle("subagent/provider-removed", name); + }; + this.ctx.emit("subagent/provider-added", provider); + }.bind(this), "subagents.registerProvider()"); + } + /** + * Look up a provider by name. + * @param name - the provider name. + * @returns the provider, or undefined when absent. + */ + getProvider(name) { + return this.providers.get(name); + } + /** + * List registered provider names in insertion order. + * @returns the registered names. + */ + list() { + return [...this.providers.keys()]; + } + /** + * Establish a published child on the named provider. Capability and semantic + * checks run before delegation. Provider ownership lasts until its promise + * fulfills; a rejection therefore has no run for the caller to dispose and + * emits no run lifecycle events. Post-publication turn and infrastructure + * failures settle through the returned run. + * @param name - the provider to use. + * @param request - child label, prompt, parent, signal, and optional capabilities. + * @returns the published holder-owned run. + */ + async start(name, request) { + const provider = this.expectProvider(name); + this.assertCapabilities(provider, request); + assertSubagentMaxDepth(request.maxDepth); + if (request.outputSchema !== void 0) assertObjectJsonSchema(request.outputSchema); + const descriptor = snapshotSubagentDescriptor({ + mode: "one-shot", + provider: name, + ...request.label !== void 0 ? { label: request.label } : {} + }); + const resolved = { + ...request, + descriptor + }; + return observeRun(this.emitLifecycle, name, request.parent, await provider.start(resolved)); + } + /** + * Resolve one provider's detached continuable-creation contribution. Method + * presence on the provider IS the capability, so a provider without it is + * rejected before the manager reserves any child resources. + */ + async prepareContinuable(name, request) { + const provider = this.expectProvider(name); + if (provider.prepareContinuable === void 0) throw new SubagentError(`subagent provider "${provider.name}" does not support continuable children (no prepareContinuable capability)`, "UNSUPPORTED_CAPABILITY"); + return provider.prepareContinuable(request); + } + /** Look up a provider for dispatch or fail loud. */ + expectProvider(name) { + const provider = this.providers.get(name); + if (provider === void 0) throw new SubagentError(`no subagent provider registered for "${name}"`, "NO_PROVIDER"); + return provider; + } + /** Resolve the optional continuable-subagent manager or fail loud. */ + requireContinuations() { + if (this.continuations === void 0) throw new SubagentError("continuable subagents require the agents service", "CONTINUATION_UNAVAILABLE"); + return this.continuations; + } + /** + * Build the lifecycle observer for one continuable Activation's residency + * epoch, so the manager publishes its edges without owning event dispatch. + */ + observeActivation(provider, childId, parent) { + return createActivationObserver(this.emitLifecycle, provider, childId, parent); + } + /** Reject the first requested capability that the provider lacks. */ + assertCapabilities(provider, request) { + const needs = [ + { + when: request.outputSchema !== void 0, + cap: "outputSchema" + }, + { + when: request.maxDepth !== void 0, + cap: "depthLimit" + }, + { + when: request.toolFilter !== void 0, + cap: "toolFilter" + }, + { + when: request.persona !== void 0, + cap: "persona" + } + ]; + for (const { when, cap } of needs) if (when && !provider.capabilities[cap]) throw new SubagentError(`subagent provider "${provider.name}" does not support the "${cap}" capability`, "UNSUPPORTED_CAPABILITY"); + } +}; +//#endregion +export { AssistantOutputFold, NO_START_CAPABILITIES, SUBAGENT_DESCRIPTOR_VERSION, SubagentDepthError, SubagentError, SubagentRunId, SubagentRuntime, SubagentRuntime as default, appendDelegatedPolicyOverrides, applyChildComposition, assertPositiveFinite, assertSubagentMaxDepth, assertUsableCwd, captureDelegatedPolicyOverrides, childSessionMeta, delegationDepthOf, finalAssistantOutput, foldSubagentDescriptor, resolveChildAgentOptions, resolveChildCwd, resolveChildDepth, seedDescriptorTurn, settleRun, settleRunResult, snapshotSubagentDescriptor, subprocessRunHandle, validateConfiguredCwd }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/invariant.js new file mode 100644 index 0000000..81138a2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/invariant.js @@ -0,0 +1,76 @@ +//#region lib/types/invariant.js +/** Package-owned subagent registry and lifecycle invariants. @module @deepseek-ai/dsh-subagent/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-subagent"; +/** Cordis companion plugin name. */ +const name = "subagent-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Assert that a terminal lifecycle payload matches its start identity. */ +function validateRunEnd(start, end, fail) { + if (start.provider !== end.provider || start.id !== end.id || start.local !== end.local) fail(`subagent/end identity diverges from subagent/start for run ${JSON.stringify(end.runId)}`); +} +/** Install provider-registry and start/end pairing checks. */ +const install = Object.assign((ctx, fail) => { + const providers = new Set(ctx.subagents.list()); + const runs = /* @__PURE__ */ new Map(); + const stagedProviders = /* @__PURE__ */ new WeakSet(); + const stagedRemovals = /* @__PURE__ */ new Set(); + const stagedStarts = /* @__PURE__ */ new WeakSet(); + const stagedEnds = /* @__PURE__ */ new WeakSet(); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName === "subagent/provider-added") { + const provider = args[0]; + if (provider.name.length === 0) fail("subagent provider names must be non-empty"); + if (providers.has(provider.name)) fail(`subagent/provider-added repeated ${JSON.stringify(provider.name)}`); + stagedProviders.add(provider); + return; + } + if (eventName === "subagent/provider-removed") { + const providerName = args[0]; + if (!providers.has(providerName)) fail(`subagent/provider-removed names unknown provider ${JSON.stringify(providerName)}`); + stagedRemovals.add(providerName); + return; + } + if (eventName === "subagent/start") { + const info = args[0]; + if (info.provider.length === 0 || String(info.runId).length === 0 || String(info.id).length === 0) fail("subagent/start provider, runId, and child id must be non-empty"); + if (runs.has(info.runId)) fail(`subagent/start repeated run id ${JSON.stringify(info.runId)}`); + stagedStarts.add(info); + return; + } + if (eventName !== "subagent/end") return; + const info = args[0]; + const start = runs.get(info.runId); + if (start === void 0) fail(`subagent/end has no matching subagent/start for run ${JSON.stringify(info.runId)}`); + validateRunEnd(start, info, fail); + stagedEnds.add(info); + }, { global: true }); + ctx.on("subagent/provider-added", (provider) => { + /* v8 ignore next -- internal/dispatch stages the same provider object */ + if (!stagedProviders.delete(provider)) return; + providers.add(provider.name); + }, { global: true }); + ctx.on("subagent/provider-removed", (providerName) => { + /* v8 ignore next -- internal/dispatch stages the same provider name */ + if (!stagedRemovals.delete(providerName)) return; + providers.delete(providerName); + }, { global: true }); + ctx.on("subagent/start", (info) => { + /* v8 ignore next -- internal/dispatch stages the same lifecycle object */ + if (!stagedStarts.delete(info)) return; + runs.set(info.runId, info); + }, { global: true }); + ctx.on("subagent/end", (info) => { + /* v8 ignore next -- internal/dispatch stages the same lifecycle object */ + if (!stagedEnds.delete(info)) return; + runs.delete(info.runId); + }, { global: true }); +}, { inject: ["subagents"] }); +/** +* Register the subagent invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.d.ts new file mode 100644 index 0000000..d7aba36 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.d.ts @@ -0,0 +1,57 @@ +/** + * Internal registry of deployment capabilities composed into every continuable + * child's unpublished creation context. + * + * A contribution grants a child-scoped capability without teaching the + * continuation manager which capabilities exist. The manager owns residency; + * this registry owns the join between plugin lifetime, unpublished setup, and + * Activation disposal, so no installation outlives either owner and no removed + * contribution can be installed after revocation reports completion. + * + * @module @deepseek-ai/dsh-subagent/activation-setup-registry + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { AgentSetupCommit } from '@deepseek-ai/dsh-agent'; +/** + * One deployment capability installed into a continuable child's unpublished + * creation context. It composes synchronously before publication and returns + * the disposer for exactly that installation. + * @param childCtx - the child's unpublished scoped context. + * @returns the disposer revoking this installation. + */ +export type ContinuableSetupContribution = (childCtx: Context) => () => void; +/** + * Owns continuable-child setup registrations, installations, rollback, child + * cleanup, and immediate live revocation. + */ +export declare class SubagentActivationSetupRegistry { + /** Live contributions in installation order. */ + private readonly registrations; + /** Child context to its live installations. */ + private readonly byChild; + /** + * Register one contribution. + * @param contribution - synchronous child-scope installer. + * @returns an idempotent registration undo. + * @throws after attempting every installation when any disposer fails. + */ + register(contribution: ContinuableSetupContribution): () => void; + /** + * Install every live contribution into one unpublished child context. + * @param childCtx - the child's unpublished scoped context. + * @returns the provisioning commit consumed at Agent publication. + */ + apply(childCtx: Context): AgentSetupCommit; + /** Release every remaining installation owned by one disposed child scope. */ + private releaseChild; + /** + * Release a batch completely before reporting disposer failures. + * @param installations - records to release. + * @param during - operation name for diagnostics. + */ + private releaseAll; + /** Drop one installation from both indices and dispose it exactly once. */ + private release; +} +export default SubagentActivationSetupRegistry; +//# sourceMappingURL=activation-setup-registry.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.js new file mode 100644 index 0000000..c113508 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.js @@ -0,0 +1,148 @@ +/** + * Internal registry of deployment capabilities composed into every continuable + * child's unpublished creation context. + * + * A contribution grants a child-scoped capability without teaching the + * continuation manager which capabilities exist. The manager owns residency; + * this registry owns the join between plugin lifetime, unpublished setup, and + * Activation disposal, so no installation outlives either owner and no removed + * contribution can be installed after revocation reports completion. + * + * @module @deepseek-ai/dsh-subagent/activation-setup-registry + */ +import { errorChain } from '@deepseek-ai/dsh-llm'; +import { SubagentError } from "./error.js"; +/** Re-read mutable removal state after a contribution may have revoked itself. */ +function isRemoved(registration) { + return registration.removed; +} +/** + * Owns continuable-child setup registrations, installations, rollback, child + * cleanup, and immediate live revocation. + */ +export class SubagentActivationSetupRegistry { + /** Live contributions in installation order. */ + registrations = new Set(); + /** Child context to its live installations. */ + byChild = new Map(); + /** + * Register one contribution. + * @param contribution - synchronous child-scope installer. + * @returns an idempotent registration undo. + * @throws after attempting every installation when any disposer fails. + */ + register(contribution) { + const registration = { contribution, removed: false, installations: new Set() }; + this.registrations.add(registration); + return () => { + if (registration.removed) + return; + // Close before disposal so a snapshotted apply() cannot install after + // revocation reports completion. + registration.removed = true; + this.registrations.delete(registration); + this.releaseAll([...registration.installations], 'contribution removal'); + }; + } + /** + * Install every live contribution into one unpublished child context. + * @param childCtx - the child's unpublished scoped context. + * @returns the provisioning commit consumed at Agent publication. + */ + apply(childCtx) { + const state = { installations: [], invalidated: false }; + try { + for (const registration of [...this.registrations]) { + /* v8 ignore next -- only a synchronous re-entrant revocation of an + * already-snapshotted registration reaches this guard. */ + if (registration.removed) + continue; + const installation = { + registration, + childCtx, + dispose: registration.contribution(childCtx), + released: false, + transaction: state, + }; + registration.installations.add(installation); + state.installations.push(installation); + let indexed = this.byChild.get(childCtx); + if (indexed === undefined) { + indexed = new Set(); + this.byChild.set(childCtx, indexed); + } + indexed.add(installation); + // An installer may revoke itself before its installation record exists. + // Dispose that escaped record and invalidate the provisioning batch. + if (isRemoved(registration)) + this.release(installation); + } + } + catch (error) { + // Keep the installer failure authoritative, but attempt every rollback. + try { + this.releaseAll([...state.installations], 'setup rollback'); + } + catch (releaseFailure) { + /* v8 ignore next -- requires independent installer and rollback faults. */ + void releaseFailure; + } + throw error; + } + childCtx.effect(() => () => { this.releaseChild(childCtx); }, 'subagents.activationSetup()'); + return { + commit: () => { + if (state.invalidated) { + throw new SubagentError('a continuable-subagent setup contribution was revoked while this child was being built; ' + + 'the child was not established', 'ACTIVATION_SETUP_REVOKED'); + } + for (const installation of state.installations) + installation.transaction = undefined; + }, + }; + } + /** Release every remaining installation owned by one disposed child scope. */ + releaseChild(childCtx) { + const indexed = this.byChild.get(childCtx) ?? []; + this.releaseAll([...indexed], 'child scope disposal'); + } + /** + * Release a batch completely before reporting disposer failures. + * @param installations - records to release. + * @param during - operation name for diagnostics. + */ + releaseAll(installations, during) { + const failures = []; + for (const installation of installations) { + try { + this.release(installation); + } + catch (error) { + failures.push(error); + } + } + if (failures.length === 0) + return; + throw new SubagentError(`continuable-subagent setup ${during} failed to release ${failures.length} installation(s): ` + + failures.map(failure => errorChain(failure)).join('; '), 'ACTIVATION_SETUP_RELEASE_FAILED'); + } + /** Drop one installation from both indices and dispose it exactly once. */ + release(installation) { + if (installation.released) + return; + installation.released = true; + installation.registration.installations.delete(installation); + const indexed = this.byChild.get(installation.childCtx); + /* v8 ignore next 4 -- every live installation is indexed until this method removes it. */ + if (indexed !== undefined) { + indexed.delete(installation); + if (indexed.size === 0) + this.byChild.delete(installation.childCtx); + } + if (installation.transaction !== undefined) + installation.transaction.invalidated = true; + installation.dispose(); + } +} +export default SubagentActivationSetupRegistry; +//# sourceMappingURL=activation-setup-registry.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.d.ts new file mode 100644 index 0000000..125a833 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.d.ts @@ -0,0 +1,48 @@ +/** + * Canonical selection of a child's final assistant output. Backend run results + * and `subagent/end.lastAssistantMessage` apply the same rule: select the last + * non-empty assistant message. An empty-content message records usage only + * when the loop appends it after a max-tokens step with no executable blocks, + * so it does not replace earlier output. If no non-empty message exists, + * select the accumulated assistant text. Selection is independent of the + * run's stop reason. + * + * @module @deepseek-ai/dsh-subagent/assistant-output + */ +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +/** + * Incremental fold of the selection rule, for backends that observe a child's + * output as it streams: session-event backends {@link push} each event, and + * transports without session events (ACP content chunks) {@link pushText} raw + * text into the same streamed fallback. + */ +export declare class AssistantOutputFold { + private message; + private partial; + /** + * Fold one session event: a non-empty assistant message becomes the + * candidate final answer, and a `text-delta` chunk extends the streamed + * fallback; every other event contributes nothing. + * @param event - the next observed session event. + */ + push(event: SessionEvent): void; + /** + * Extend the streamed fallback with text observed outside session events. + * @param text - the next streamed text piece (an empty piece is a no-op). + */ + pushText(text: string): void; + /** + * Select the final output folded so far. + * @returns the last non-empty assistant message, else the accumulated + * streamed text, or `undefined` when the child produced neither. + */ + collect(): ContentBlock[] | undefined; +} +/** + * Apply the selection rule to one complete child-owned event suffix. + * @param events - the child-owned events (after any seed or epoch boundary). + * @returns the selected output, or `undefined` when the child produced none. + */ +export declare function finalAssistantOutput(events: readonly SessionEvent[]): ContentBlock[] | undefined; +//# sourceMappingURL=assistant-output.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.js new file mode 100644 index 0000000..68f7a1d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.js @@ -0,0 +1,72 @@ +/** + * Canonical selection of a child's final assistant output. Backend run results + * and `subagent/end.lastAssistantMessage` apply the same rule: select the last + * non-empty assistant message. An empty-content message records usage only + * when the loop appends it after a max-tokens step with no executable blocks, + * so it does not replace earlier output. If no non-empty message exists, + * select the accumulated assistant text. Selection is independent of the + * run's stop reason. + * + * @module @deepseek-ai/dsh-subagent/assistant-output + */ +/** + * Incremental fold of the selection rule, for backends that observe a child's + * output as it streams: session-event backends {@link push} each event, and + * transports without session events (ACP content chunks) {@link pushText} raw + * text into the same streamed fallback. + */ +export class AssistantOutputFold { + message; + partial = []; + /** + * Fold one session event: a non-empty assistant message becomes the + * candidate final answer, and a `text-delta` chunk extends the streamed + * fallback; every other event contributes nothing. + * @param event - the next observed session event. + */ + push(event) { + if (event.type === 'assistant/message') { + const content = event.data.message.content; + if (content.length > 0) + this.message = content; + } + else if (event.type === 'assistant/chunk' && event.data.chunk.type === 'text-delta') { + this.pushText(event.data.chunk.text); + } + } + /** + * Extend the streamed fallback with text observed outside session events. + * @param text - the next streamed text piece (an empty piece is a no-op). + */ + pushText(text) { + if (text.length > 0) + this.partial.push(text); + } + /** + * Select the final output folded so far. + * @returns the last non-empty assistant message, else the accumulated + * streamed text, or `undefined` when the child produced neither. + */ + collect() { + if (this.message !== undefined) + return this.message; + const text = this.partial.join(''); + return text.length > 0 ? [{ type: 'text', text }] : undefined; + } +} +/** + * Apply the selection rule to one complete child-owned event suffix. + * @param events - the child-owned events (after any seed or epoch boundary). + * @returns the selected output, or `undefined` when the child produced none. + */ +export function finalAssistantOutput(events) { + // TODO: this folds the complete suffix once per run/epoch settlement. If a + // long continuable epoch ever profiles hot here, scan backward with early + // exit for the last non-empty message and fold text deltas only on the + // no-message fallback. + const fold = new AssistantOutputFold(); + for (const event of events) + fold.push(event); + return fold.collect(); +} +//# sourceMappingURL=assistant-output.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.d.ts new file mode 100644 index 0000000..a95ba0f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.d.ts @@ -0,0 +1,139 @@ +/** + * Shared in-process child composition: the delegation-depth budget, the + * durable session metadata, the resolved child `AgentOptions`, the delegated + * policy seed, and the scoped setup a child agent needs. Both the one-shot + * provider driver and the continuation manager compose children this way, so + * depth accounting, lineage stamping, and delegation policy have one home. + * + * @module @deepseek-ai/dsh-subagent/child-agent + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { Agent, AgentOptions, CreateAgentOptions } from '@deepseek-ai/dsh-agent'; +import type { SandboxMode } from '@deepseek-ai/dsh-sandbox'; +import type { Session, SessionId } from '@deepseek-ai/dsh-session'; +import type { ToolRestriction } from '@deepseek-ai/dsh-tools'; +/** Thrown when starting a child would exceed the requested depth cap. */ +export declare class SubagentDepthError extends Error { + readonly attemptedDepth: number; + readonly maxDepth: number; + constructor(attemptedDepth: number, maxDepth: number); +} +/** + * Resolve the child's delegation depth from its parent and enforce an optional + * cap. The persisted parent header is the monotone floor, so a resumed parent + * cannot delegate as if it were top-level. + * @param parent - the delegating parent agent. + * @param maxDepth - optional absolute cap the resolved depth must not exceed. + * @returns the child's non-negative safe-integer depth. + * @throws {SubagentDepthError} when the resolved depth exceeds `maxDepth`. + * @throws {RangeError} when the resolved depth leaves the safe-integer range. + */ +export declare function resolveChildDepth(parent: Agent, maxDepth: number | undefined): number; +/** + * Resolve the child's `AgentOptions`: the parent's provider/model/maxTokens + * route unless the request overrides it, stamped with the child's own + * delegation depth. + * @param parent - the delegating parent whose route the child inherits. + * @param requested - per-child overrides, if any. + * @param childDepth - the resolved delegation depth to stamp. + * @returns the resolved options for `ctx.agents.create()`. + */ +export declare function resolveChildAgentOptions(parent: Agent, requested: AgentOptions | undefined, childDepth: number): AgentOptions; +/** + * Build the child session's durable creation metadata: the parent's workspace, + * its direct lineage, coarse product origin, the recursion budget that must + * survive persistence, the seed boundary that separates inherited parent + * history from child work, and the composition the child runs under. + * + * The preset is read from the parent's LIVE scope chain rather than from its + * header, because a parent that switched preset while blank runs on the newer + * composition and its header still names the older one. Recording it is what + * makes a child's history reconstructable: without it a cold read of the child + * resolves the deployment default and rebuilds turns under a tool set the + * child never had. + * @param parent - the delegating parent agent. + * @param childDepth - the resolved delegation depth to persist. + * @param lineageSeedLength - how many leading events came from the parent's log. + * @returns the `meta` for `ctx.agents.create()`. + */ +export declare function childSessionMeta(parent: Agent, childDepth: number, lineageSeedLength: number): NonNullable; +/** The scoped composition a child agent's creation window applies. */ +export interface ChildComposition { + /** Per-child persona shadowing the deployment persona. */ + readonly persona?: string | undefined; + /** Per-child tool scoping. */ + readonly toolFilter?: ToolRestriction | undefined; +} +/** + * Model-facing delegation-scope statement for every in-process child. A + * runtime-context contribution rather than a system-prompt section, so the + * deployment's system prompt stays uniform across parents and children. + */ +export declare const SUBAGENT_DELEGATION_CONTEXT: string; +/** + * Compose one child inside its creation window: join its parent's preset, + * register the fixed delegation-scope statement, then apply the child's own + * shadowing persona section and tool restriction, all owned by the child's + * scope and therefore invisible to its parent and siblings. Creation and cold + * resume both pass through here. + * + * The join comes first and the child's own registrations second, which is the + * order the layering already implies — the nearest scope wins a name, and a + * per-child restriction intersects with everything its chain admits — but + * stating it here keeps the two steps from being read as independent. + * + * The join and the per-child registrations live in ONE call because a child + * composed without the join is exactly the defect this function exists to + * prevent: with every model-facing row on the agent plane, a child that joins + * no preset sees an empty tool registry and none of its parent's prompt + * sections. Taking the parent as a parameter is what makes that omission + * unrepresentable at the call sites. + * @param childCtx - the child agent's scoped creation context. + * @param parent - the delegating parent whose composition the child joins. + * @param composition - the per-child persona and tool filter to install. + */ +export declare function applyChildComposition(childCtx: Context, parent: Agent, composition: ChildComposition): void; +/** Policy seeded onto a child session's log at the delegation boundary. */ +export interface DelegatedPolicyOverrides { + /** The parent session's explicit sandbox-mode override, or `undefined` without one. */ + readonly sandboxMode: SandboxMode | undefined; + /** + * `'never'` whenever the approval capability is composed, `undefined` + * otherwise: a delegated child acts only within the sandbox scope fixed at + * delegation, so its asks are rejected deterministically. + */ + readonly approvalPolicy: 'never' | undefined; +} +/** + * Capture the policy to seed into one delegation. Call synchronously before + * the child start's first await: a later parent switch belongs to the + * parent's future, not to this child. Only the parent session's explicit + * sandbox override is captured — never deployment defaults or one-shot + * grants — and the approval policy is pinned to `'never'` regardless of the + * parent's own policy. + * @param parent - the delegating parent agent. + * @returns the sandbox override (or `undefined` without one) and the approval pin. + */ +export declare function captureDelegatedPolicyOverrides(parent: Agent): DelegatedPolicyOverrides; +/** + * Append the captured delegation policy onto the child's own log as + * `source: 'delegation'` events inside the unpublished creation window, so the + * child's effective policy is reconstructable from its log alone. Appends land + * after any fork seed, so fresh policy wins stale seed state; later child + * switches still win over these events. + * @param childSession - the unpublished child's session. + * @param overrides - the policy captured at delegation. + */ +export declare function appendDelegatedPolicyOverrides(childSession: Session, overrides: DelegatedPolicyOverrides): void; +/** Identity and lineage inputs shared by every in-process child creation. */ +export interface ChildCreateInputs { + /** The child's reserved session id. */ + readonly sessionId: SessionId; + /** The delegating parent agent. */ + readonly parent: Agent; + /** The resolved delegation depth. */ + readonly childDepth: number; + /** How many leading seed events came from the parent's log. */ + readonly lineageSeedLength: number; +} +//# sourceMappingURL=child-agent.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.js new file mode 100644 index 0000000..8e7a9e3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.js @@ -0,0 +1,169 @@ +/** + * Shared in-process child composition: the delegation-depth budget, the + * durable session metadata, the resolved child `AgentOptions`, the delegated + * policy seed, and the scoped setup a child agent needs. Both the one-shot + * provider driver and the continuation manager compose children this way, so + * depth accounting, lineage stamping, and delegation policy have one home. + * + * @module @deepseek-ai/dsh-subagent/child-agent + */ +import { delegationDepthOf } from "./depth.js"; +/** Thrown when starting a child would exceed the requested depth cap. */ +export class SubagentDepthError extends Error { + attemptedDepth; + maxDepth; + constructor(attemptedDepth, maxDepth) { + super(`subagent depth ${attemptedDepth} exceeds maxDepth ${maxDepth}`); + this.attemptedDepth = attemptedDepth; + this.maxDepth = maxDepth; + this.name = 'SubagentDepthError'; + } +} +/** + * Resolve the child's delegation depth from its parent and enforce an optional + * cap. The persisted parent header is the monotone floor, so a resumed parent + * cannot delegate as if it were top-level. + * @param parent - the delegating parent agent. + * @param maxDepth - optional absolute cap the resolved depth must not exceed. + * @returns the child's non-negative safe-integer depth. + * @throws {SubagentDepthError} when the resolved depth exceeds `maxDepth`. + * @throws {RangeError} when the resolved depth leaves the safe-integer range. + */ +export function resolveChildDepth(parent, maxDepth) { + const childDepth = delegationDepthOf(parent) + 1; + if (!Number.isSafeInteger(childDepth)) { + throw new RangeError('subagent child depth exceeds the safe-integer range'); + } + if (maxDepth !== undefined && childDepth > maxDepth) { + throw new SubagentDepthError(childDepth, maxDepth); + } + return childDepth; +} +/** + * Resolve the child's `AgentOptions`: the parent's provider/model/maxTokens + * route unless the request overrides it, stamped with the child's own + * delegation depth. + * @param parent - the delegating parent whose route the child inherits. + * @param requested - per-child overrides, if any. + * @param childDepth - the resolved delegation depth to stamp. + * @returns the resolved options for `ctx.agents.create()`. + */ +export function resolveChildAgentOptions(parent, requested, childDepth) { + const parentProvider = parent.options.provider; + const parentModel = parent.options.model; + const parentMaxTokens = parent.options.maxTokens; + return { + ...parentProvider !== undefined ? { provider: parentProvider } : {}, + ...parentModel !== undefined ? { model: parentModel } : {}, + ...parentMaxTokens !== undefined ? { maxTokens: parentMaxTokens } : {}, + ...requested, + subagentDepth: childDepth, + }; +} +/** + * Build the child session's durable creation metadata: the parent's workspace, + * its direct lineage, coarse product origin, the recursion budget that must + * survive persistence, the seed boundary that separates inherited parent + * history from child work, and the composition the child runs under. + * + * The preset is read from the parent's LIVE scope chain rather than from its + * header, because a parent that switched preset while blank runs on the newer + * composition and its header still names the older one. Recording it is what + * makes a child's history reconstructable: without it a cold read of the child + * resolves the deployment default and rebuilds turns under a tool set the + * child never had. + * @param parent - the delegating parent agent. + * @param childDepth - the resolved delegation depth to persist. + * @param lineageSeedLength - how many leading events came from the parent's log. + * @returns the `meta` for `ctx.agents.create()`. + */ +export function childSessionMeta(parent, childDepth, lineageSeedLength) { + const parentHeader = parent.session.header; + const agentPreset = parent.ctx.get('agentPresets')?.composedPreset(parent.ctx); + return { + ...parentHeader.cwd !== undefined ? { cwd: parentHeader.cwd } : {}, + ...agentPreset === undefined ? {} : { agentPreset }, + parentSession: parentHeader.id, + // Navigation classification only; the descriptor remains the authority + // for mode and continuation capability. + origin: 'subagent', + // Durable: the recursion budget must survive persistence and resume. + delegationDepth: childDepth, + ...lineageSeedLength > 0 ? { seedLength: lineageSeedLength } : {}, + }; +} +/** + * Model-facing delegation-scope statement for every in-process child. A + * runtime-context contribution rather than a system-prompt section, so the + * deployment's system prompt stays uniform across parents and children. + */ +export const SUBAGENT_DELEGATION_CONTEXT = 'You are a delegated subagent: your permission scope was fixed when you were started and cannot be ' + + 'widened from inside this session — operations that require approval are rejected automatically. ' + + 'When the task needs access beyond that scope, do not retry the denied operation; state the ' + + 'limitation in your reply so the delegating agent can handle it.'; +/** + * Compose one child inside its creation window: join its parent's preset, + * register the fixed delegation-scope statement, then apply the child's own + * shadowing persona section and tool restriction, all owned by the child's + * scope and therefore invisible to its parent and siblings. Creation and cold + * resume both pass through here. + * + * The join comes first and the child's own registrations second, which is the + * order the layering already implies — the nearest scope wins a name, and a + * per-child restriction intersects with everything its chain admits — but + * stating it here keeps the two steps from being read as independent. + * + * The join and the per-child registrations live in ONE call because a child + * composed without the join is exactly the defect this function exists to + * prevent: with every model-facing row on the agent plane, a child that joins + * no preset sees an empty tool registry and none of its parent's prompt + * sections. Taking the parent as a parameter is what makes that omission + * unrepresentable at the call sites. + * @param childCtx - the child agent's scoped creation context. + * @param parent - the delegating parent whose composition the child joins. + * @param composition - the per-child persona and tool filter to install. + */ +export function applyChildComposition(childCtx, parent, composition) { + childCtx.get('agentPresets')?.composeFrom(childCtx, parent.ctx); + // Order 120: after the sandbox:policy (110) and approval:policy (115) sentences. + childCtx.systemPrompt.context({ name: 'subagent:delegation', order: 120, text: SUBAGENT_DELEGATION_CONTEXT }); + if (composition.persona !== undefined) { + childCtx.systemPrompt.section({ name: 'deployment:persona', order: 0, text: composition.persona }); + } + if (composition.toolFilter !== undefined) + childCtx.tools.restrict(composition.toolFilter); +} +/** + * Capture the policy to seed into one delegation. Call synchronously before + * the child start's first await: a later parent switch belongs to the + * parent's future, not to this child. Only the parent session's explicit + * sandbox override is captured — never deployment defaults or one-shot + * grants — and the approval policy is pinned to `'never'` regardless of the + * parent's own policy. + * @param parent - the delegating parent agent. + * @returns the sandbox override (or `undefined` without one) and the approval pin. + */ +export function captureDelegatedPolicyOverrides(parent) { + return { + sandboxMode: parent.ctx.get('sandboxPolicy')?.overrideOf(parent.session), + approvalPolicy: parent.ctx.get('approval') === undefined ? undefined : 'never', + }; +} +/** + * Append the captured delegation policy onto the child's own log as + * `source: 'delegation'` events inside the unpublished creation window, so the + * child's effective policy is reconstructable from its log alone. Appends land + * after any fork seed, so fresh policy wins stale seed state; later child + * switches still win over these events. + * @param childSession - the unpublished child's session. + * @param overrides - the policy captured at delegation. + */ +export function appendDelegatedPolicyOverrides(childSession, overrides) { + if (overrides.sandboxMode !== undefined) { + childSession.append('sandbox/mode', { mode: overrides.sandboxMode, source: 'delegation' }); + } + if (overrides.approvalPolicy !== undefined) { + childSession.append('approval/policy', { policy: overrides.approvalPolicy, source: 'delegation' }); + } +} +//# sourceMappingURL=child-agent.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.d.ts new file mode 100644 index 0000000..7153d11 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.d.ts @@ -0,0 +1,7 @@ +/** + * Browser-safe subagent projection vocabulary. + * + * @module @deepseek-ai/dsh-subagent/client + */ +export type { SubagentIdentityProjection, SubagentTimingProjection } from './projection-types.ts'; +//# sourceMappingURL=client.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.js new file mode 100644 index 0000000..776ccb4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.js @@ -0,0 +1,7 @@ +/** + * Browser-safe subagent projection vocabulary. + * + * @module @deepseek-ai/dsh-subagent/client + */ +export {}; +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.d.ts new file mode 100644 index 0000000..8706df5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.d.ts @@ -0,0 +1,436 @@ +/** + * Internal continuable-subagent manager: stable child ids, descriptor + * persistence, activation admission, the live ownership graph, cold resume, + * child-first disposal, and settlement delivery to the parent, behind + * `ctx.subagents`. + * + * A continuable child has one durable Session and at most one process-local + * {@link Activation} — one residency epoch for a reconstructed child Agent. An + * Activation is not a request, result, cancellation, or Task boundary: it may + * execute many FIFO turns and stays resident while descendants it created are + * still running. The Agent inbox is the only turn queue, so this manager owns + * residency while the Agent loop owns all turn ordering and execution. No + * continuable path creates a Task or an intermediate result-bearing wrapper. + * + * Because residency is this manager's alone to end, telling the parent that a + * child settled is its job too. An external `subagent/end` listener cannot do + * it correctly: that payload names no parent, the child handle is already + * disposed by then, and the release that wakes the parent's own settlement + * watcher has already run. See {@link SubagentContinuationManager.notifySettlement}. + * + * @module @deepseek-ai/dsh-subagent + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { ContentBlock, MessageId, MessageSource } from '@deepseek-ai/dsh-llm'; +import { SessionId } from '@deepseek-ai/dsh-session'; +import type { SubagentDescriptorData } from './descriptor.ts'; +import type { ContinuableCreateRequest, ContinuableCreateSpec, SubagentStartRequest } from './types.ts'; +import type { ActivationObserver } from './lifecycle.ts'; +import type SubagentActivationSetupRegistry from './activation-setup-registry.ts'; +/** Attribution for a model coordinator's follow-up to one of its children. */ +export interface CoordinatorMessageSource { + readonly kind: 'coordinator'; + /** A message another agent addressed to this one (`relay` context form). */ + readonly form: 'relay'; + /** Session id of the agent whose tool call produced the follow-up. */ + readonly senderSessionId: SessionId; +} +/** Durable attribution for a continuable child's explicit parent report. */ +export interface SubagentReportMessageSource { + readonly kind: 'subagent-report'; + /** A message another agent addressed to this one (`relay` context form). */ + readonly form: 'relay'; + /** Session id of the reporting child. */ + readonly senderSessionId: SessionId; +} +/** + * Durable attribution for the runtime's own account of a continuable child + * settling. Deliberately a different kind from + * {@link SubagentReportMessageSource}: a report is content the child chose, + * while this message is the manager stating what became of the child, and a + * transcript that merged them would credit the child with words it never wrote. + */ +export interface SubagentSettledMessageSource { + readonly kind: 'subagent-settled'; + /** A runtime account shown without expanding the row (`notice` context form). */ + readonly form: 'notice'; + /** One-line account of how the child ended. */ + readonly summary: string; + /** Session id of the child that settled. */ + readonly senderSessionId: SessionId; +} +declare module '@deepseek-ai/dsh-llm' { + interface MessageSourceMap { + coordinator: CoordinatorMessageSource; + 'subagent-report': SubagentReportMessageSource; + 'subagent-settled': SubagentSettledMessageSource; + } +} +/** Deployment scheduling policy for accepted child reports. */ +export type SubagentReportDelivery = 'quiet' | 'wakeup'; +/** Options for one continuable child's report to its direct parent. */ +export interface SubagentReportOptions { + /** Already-resolved parent scheduling policy. */ + readonly delivery: SubagentReportDelivery; + /** Caller cancellation, owning authorization and admission until acceptance. */ + readonly signal: AbortSignal; +} +/** What a caller asks for when starting a continuable background child. */ +export interface ContinuableStartSpec { + /** The `ctx.subagents` provider whose continuable-creation capability establishes the child. */ + readonly provider: string; + /** The initial delegation's short `description`, persisted as the child's creation label. */ + readonly label: string; + /** + * The delegation request. The manager reserves the stable child id, resolves + * the durable descriptor, and composes the child itself. + */ + readonly request: Omit; + /** Caller cancellation, owning the operation only until inbox acceptance. */ + readonly signal: AbortSignal; +} +/** Identities returned once a continuable child accepted its initial prompt. */ +export interface ContinuableStart { + /** The durable child session id, stable across activations. */ + readonly childId: SessionId; + /** The accepted initial prompt's inbox message id. */ + readonly messageId: MessageId; +} +/** + * Authority under which one interrupt request is admitted. `user` carries the + * durable direct-parent address a human client presented; `ancestor` carries + * the exact live Agent object whose recorded lineage must contain the caller. + */ +export type SubagentInterruptAuthority = { + readonly kind: 'user'; + readonly parentSessionId: SessionId; +} | { + readonly kind: 'ancestor'; + readonly agent: Agent; +}; +/** Options for following up with one continuable child. */ +export interface SubagentFollowupOptions { + /** Durable attribution retained on the delivered message; it grants no authority. */ + readonly source: MessageSource; + /** Caller cancellation, owning the operation only until inbox acceptance. */ + readonly signal: AbortSignal; +} +/** + * Hooks the manager needs from the owning service. Declared here, by the + * dependent, so the manager states exactly what it requires instead of + * depending back on the whole {@link SubagentRuntime}. Package-private: no + * consumer outside this package supplies a host. + */ +interface ContinuationHost { + /** + * Resolve one provider's continuable-creation contribution, or reject when + * the provider is unknown or lacks the capability. + * @param name - the configured provider name. + * @param request - the reserved identity, delegating parent, and cancellation. + * @returns the provider's detached creation spec. + */ + prepareContinuable(name: string, request: ContinuableCreateRequest): Promise; + /** + * Build the lifecycle observer for one Activation's residency epoch. + * @param provider - the provider name recorded in the durable descriptor. + * @param childId - the durable child session id. + * @param parent - the exact live direct parent for scoped dispatch. + * @returns the observer whose edges this epoch publishes. + */ + observeActivation(provider: string, childId: SessionId, parent: Agent): ActivationObserver; +} +/** + * The continuable-subagent orchestration service behind `ctx.subagents`. Tool + * schema and host adapters are consumers of this one contract; foreground + * one-shot delegation keeps calling `ctx.subagents.start()` and never enters + * this lifecycle. + */ +export declare class SubagentContinuationManager { + private readonly ctx; + private readonly host; + private readonly setupRegistry; + /** Child session id → its live Activation. Process-local, never durable. */ + private activations; + /** Materializations admitted before drain, tracked through publication or rollback. */ + private readonly materializations; + private readonly locks; + /** Structural Cordis owner of every Activation handle. */ + private readonly ownerCtx; + /** + * Exact roots whose host teardown has begun, with the live lineage members + * observed under each root. Entries remain until that exact root leaves the + * Agent registry, closing admission throughout its host's teardown without + * poisoning a later same-id replacement. + */ + private readonly closingScopes; + private draining; + constructor(ctx: Context, host: ContinuationHost, setupRegistry: SubagentActivationSetupRegistry); + /** + * Start one continuable background child: reserve its durable identity, + * resolve the provider's detached creation spec, create the child Agent + * through the private activation-owner scope, establish any continuable-parent + * ownership, and submit the initial prompt. Resolves when inbox acceptance + * yields the message id — without waiting for the turn to start or for the + * message to reach the Session log. + * + * Every failure before that acceptance rejects without either id, disposing + * any created handle and rolling back the Activation and parent ownership. + * The caller signal owns lookup, materialization, and admission only until + * acceptance; afterwards the manager owns the Activation independently. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted initial prompt's message id. + */ + startContinuable(spec: ContinuableStartSpec): Promise; + /** + * Deliver one later message to a known continuable child as its next FIFO + * turn. Routing depends only on Activation residency: a `running` Activation + * enqueues, a `waiting` one wakes the same Agent, and an absent one + * cold-resumes a new Activation from the persisted Session. The Agent inbox + * is the only queue, so every accepted message has one observable order. + * + * The caller signal owns lookup, materialization, and admission only until + * inbox acceptance; afterwards the accepted turn cannot be cancelled through + * this service. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - the durable child session id. + * @param content - the user-role content to deliver. + * @param options - the message source fields and caller cancellation. + * @returns the accepted message's inbox id. + * @throws when parent authority, availability, or admission rejects the delivery. + */ + followup(parent: Agent, childId: SessionId, content: ContentBlock[], options: SubagentFollowupOptions): Promise; + /** + * Interrupt one live continuable child's current turn. Admission is + * synchronous and the effect is asynchronous: this authorizes the caller, + * requests `Agent.cancel(cause, { keepInbox: true })` on the target, and + * returns without waiting for the target to observe the signal or reach + * quiescence. The Activation, its handle, accepted unclaimed inbox work, and + * already-published descendants are untouched; work already claimed into the + * interrupted turn is not requeued. Once the interrupted driver is idle, a + * waking send resumes the parked queue. + * + * An absent target is an accepted no-op, which uniformly covers natural + * completion races, repeated requests, one-shot ids, and unknown ids without + * consulting the durable catalog. A target whose disposal transaction is + * already open is likewise an accepted no-op after authorization. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the presented authority does + * not own the live target: a stale or self-targeting ancestor caller, a + * parent address that is not the live target's durable direct parent, or + * an ancestor outside the target's recorded live lineage. + */ + interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void; + /** + * Deliver explicitly selected content from one resident continuable child to + * its durable direct parent. Sender authorization, parent resolution, and + * send acceptance share one no-await span. Reporting neither concludes the + * child's turn nor changes its Activation lifetime. + * @param child - exact live reporting child; this is the authority credential. + * @param content - selected model-facing content. + * @param options - scheduling policy and pre-acceptance cancellation. + * @returns the stable identity of the message accepted by the parent. + * @throws {SubagentError} when the sender is unauthorized, the parent is not + * live, or continuation admission is closing. + */ + reportFrom(child: Agent, content: ContentBlock[], options: SubagentReportOptions): Promise; + /** Authorize only the exact Agent of one resident Activation. */ + private authorizeReporter; + /** Resolve the reporting child's live direct parent from durable lineage. */ + private resolveReportParent; + /** Deliver one framed report through the selected parent scheduling preset. */ + private deliverReport; + /** + * Perform one waking send to a parent, accounted against that parent's own + * Activation when it has one. Registering the id before the send is what + * keeps a continuation-managed parent from being judged quiescent in the + * window between `followup()` and the microtask that admits it. + * @param parent - the exact live parent receiving the waking message. + * @param message - the message whose id is accounted. + * @param send - the synchronous waking send to perform. + */ + private sendWaking; + /** Send one report while translating only the parent's own rejection. */ + private sendReport; + /** + * Close admission, await every already-admitted materialization through + * publication or rollback, then dispose the stable live Activation forest + * child-first. Sibling branches drain independently: one failure is recorded + * but never prevents the remaining handles from being attempted, and the + * aggregate rejects only after every branch settles. + * @returns once materialization is quiescent and every live Activation released its handle. + * @throws an aggregate error when any branch failed to release. + */ + drain(): Promise; + /** + * Stop only the continuable descendants of exact live host-owned parents. + * Admission stays closed for those parent trees until each exact parent + * leaves the Agent registry; unrelated trees and manager-wide admission stay + * live. + * @param parents - exact live roots whose continuable descendants must stop. + * @returns once every retained descendant Activation released its handle. + * @throws an aggregate error after all scoped branches settle when any failed. + */ + drainDescendants(parents: readonly Agent[]): Promise; + /** Dispose independent roots and report every branch failure after all settle. */ + private disposeRoots; + /** Return the retained member set for one exact scoped-teardown root. */ + private closingMembers; + /** + * Return the exact currently resolvable ancestry from `agent` upward. The + * first element is always the supplied identity, even when it is already + * stale; each ancestor after it must be the registry's current exact entry. + */ + private liveLineage; + /** + * The teardown that closed continuable admission for this agent's lineage. + * `'manager'` is the whole manager draining; an Agent is the exact scoped root + * whose forest is closing. + * @param agent - the agent whose lineage is tested. + * @returns the closing teardown, or `undefined` while admission is open. + */ + private closingTeardownFor; + /** Reject new admission once the manager or this exact parent tree began draining. */ + private assertAdmitting; + /** + * Derive residency from Agent quiescence and the owned-child set. `running` + * covers an active admission, an open turn, or accepted waking inbox work. + * + * `Agent.status` alone is insufficient: it stays `idle` between an accepted + * waking send and the microtask that admits it, so a synchronous inbox + * observer would see `settled` while a turn is already queued. `accepted` + * holds the ids this manager admitted but has not yet seen drained. + */ + private stateOf; + /** + * Cold-resume a persisted child: inspect and authorize its Session, fold the + * generic descriptor, create the Activation through `ctx.agents.resume()`, + * and submit the waiting turn. This never dispatches through a subagent + * provider — the persisted Session already holds the initial prefix and the + * descriptor is the whole reconstruction input. + */ + private coldResume; + /** + * Submit to a freshly materialized Activation or roll it back completely. + * @param activation - the just-published Activation to admit or release. + * @param content - the initial or resumed message content. + * @param source - durable fields naming who supplied the accepted message. + * @param parent - the live direct parent authorizing admission. + * @param signal - caller cancellation owning admission until acceptance. + * @returns the accepted inbox message id. + */ + private submitMaterialized; + /** + * Create or resume the child Agent through the private activation-owner + * scope, install the handle in a fresh Activation, and register ownership on + * a continuation-managed parent. Rejection leaves no Activation, no handle, + * and no ownership membership. + */ + private materialize; + /** + * Perform one tracked materialization. The caller keeps the drain barrier + * registered until this either returns a resident Activation or finishes + * rollback. + */ + private materializeTracked; + /** + * Release an Activation whose start edge was not published. The memoized + * transaction remains in the live map until handle disposal settles, so a + * concurrent drain or delivery observes the same closing boundary. + */ + private rollbackUnpublished; + /** + * Register the child in a continuation-managed parent's owned set before the + * child can run, so that parent cannot settle while the child is live. A + * top-level or other non-continuation Agent has no Activation and stays + * outside the waiting graph. + */ + private acquireOwnership; + /** Remove one child from its live owner's set and let that owner re-check settlement. */ + private releaseOwnership; + /** Let a settlement watcher re-observe quiescence after ownership or inbox changes. */ + private wake; + /** + * Submit one message as the child's next FIFO turn and return its accepted + * inbox id. Acceptance is the operation's success boundary; the manager owns + * the Activation independently afterwards. + */ + private submit; + /** + * Account one waking send across a resident Activation's settlement window. + * @param activation - Activation receiving waking inbox work. + * @param messageId - stable identity of the message about to be sent. + * @param send - synchronous send that publishes one enqueue occurrence. + * @returns the accepted message id. + */ + private admitWaking; + /** + * Cross the final admission cutoff and submit without yielding. Signal abort, + * manager drain, or Activation disposal that wins before this synchronous + * span rejects without inbox acceptance. + */ + private submitAdmitted; + /** + * Authorize one operation against the durable direct-parent lineage. Other + * agents, ancestors, teams, workflows, and hosts remain rejected until an + * explicit authority protocol has a production consumer. + */ + private authorizeLineage; + /** + * Follow one Activation to settlement: wait for Agent quiescence, then for + * every owned child to complete disposal, and dispose the handle once both + * hold. A `next-turn` delivered while `waiting` wakes the same Agent and + * returns it to `running`, so this re-observes rather than settling early. + */ + private watchSettlement; + /** + * Stop one Activation immediately, then release it child-first. The memoized + * transaction is installed before cancellation or recursive callbacks, so + * admission and reentrant teardown converge on the same owner. + * + * The final session flush is best effort and never prevents handle disposal + * or ownership release, because retaining a child would permanently pin its + * ancestors in `waiting`. + * @param activation - the residency epoch to stop and release. + * @returns the one disposal transaction owned by this Activation. + */ + private dispose; + /** + * Propagate stop synchronously, then finish the child-first release. + * @param activation - the Activation whose disposal transaction is installed. + * @returns once the handle and ownership edge are released. + */ + private finishDisposal; + /** + * Tell the durable direct parent that this child produced everything it is + * going to. Unconditional for every child the caller received an id for: it + * does not consider whether the child reported, because the cases that most + * need it — a token ceiling, a model failure, cancellation, teardown — are + * exactly the ones where the child never got to choose. A materialization + * rolled back before its first acceptance stays silent, since the caller was + * told that child was not established. A parent that is no longer live is not + * an error; the child's own Session remains the durable record either way. + * A parent whose own lineage is already closing receives the notice without a + * wake, because teardown is not a reason to start a turn. + * + * Never blocks disposal. A delivery failure is logged and dropped, because + * retaining a child to retry a notice would pin its whole ancestry in + * `waiting` forever. + * @param activation - the settling Activation, still owned by its parent. + * @param terminal - how this epoch ended, as the terminal edge will report it. + */ + private notifySettlement; + /** + * Request a best-effort final session flush after the child is quiescent. + * Listener failure is logged because flush participation cannot identify a + * particular persistence backend, and teardown must still release ownership. + * @param activation - the Activation whose final events should be flushed. + */ + private flushFinalState; + /** Resolve the persistence service continuable children require, or fail loud. */ + private requirePersistence; +} +export type { SubagentDescriptorData }; +export default SubagentContinuationManager; +//# sourceMappingURL=continuation.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.js new file mode 100644 index 0000000..7fb519d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.js @@ -0,0 +1,1100 @@ +/** + * Internal continuable-subagent manager: stable child ids, descriptor + * persistence, activation admission, the live ownership graph, cold resume, + * child-first disposal, and settlement delivery to the parent, behind + * `ctx.subagents`. + * + * A continuable child has one durable Session and at most one process-local + * {@link Activation} — one residency epoch for a reconstructed child Agent. An + * Activation is not a request, result, cancellation, or Task boundary: it may + * execute many FIFO turns and stays resident while descendants it created are + * still running. The Agent inbox is the only turn queue, so this manager owns + * residency while the Agent loop owns all turn ordering and execution. No + * continuable path creates a Task or an intermediate result-bearing wrapper. + * + * Because residency is this manager's alone to end, telling the parent that a + * child settled is its job too. An external `subagent/end` listener cannot do + * it correctly: that payload names no parent, the child handle is already + * disposed by then, and the release that wakes the parent's own settlement + * watcher has already run. See {@link SubagentContinuationManager.notifySettlement}. + * + * @module @deepseek-ai/dsh-subagent + */ +import { randomUUID } from 'node:crypto'; +import { boundContextSummary, createUserMessage, errorChain } from '@deepseek-ai/dsh-llm'; +import { SessionId } from '@deepseek-ai/dsh-session'; +import { foldSubagentDescriptor, snapshotSubagentDescriptor } from "./descriptor.js"; +import { appendDelegatedPolicyOverrides, applyChildComposition, captureDelegatedPolicyOverrides, childSessionMeta, resolveChildAgentOptions, resolveChildDepth, } from "./child-agent.js"; +import { assertSubagentMaxDepth } from "./depth.js"; +import { seedDescriptorTurn } from "./descriptor-seed.js"; +import { SubagentError } from "./error.js"; +/** + * Read one Activation's current disposal transaction. This indirection exists + * because TypeScript would otherwise narrow repeated reads of the mutable field + * inside a long-lived closure to constants instead of re-reading runtime state. + * @param activation - the Activation to inspect. + * @returns the in-flight or settled disposal, or `undefined` while resident. + */ +function disposalOf(activation) { + return activation.disposal; +} +/** + * One line telling a parent that a background child is finished and why, in + * the parent's own task vocabulary. + * @param childId - the durable child the parent knows by id. + * @param stopReason - how the child's last ordinary turn ended. + * @returns the model-facing opening line of the settlement notice. + */ +function settlementSummary(childId, stopReason) { + const subject = `Background subagent ${childId}`; + switch (stopReason) { + case 'completed': + return `${subject} finished and will do no further work unless you send it more.`; + case 'aborted': + return `${subject} was stopped before it finished.`; + case 'max-tokens': + return `${subject} ran out of room before it finished.`; + // A pre-step rejection — a hook deny, a policy plugin — discarded input + // the child had claimed, so the parent must not treat the task as done. + case 'refusal': + return `${subject} declined the task.`; + case 'error': + return `${subject} failed before it finished.`; + /* v8 ignore next 4 -- `SubagentResult['stopReason']` is merge-extensible, so this arm + * needs a backend that adds a variant; an unnameable ending is reported as unfinished + * rather than silently as success. */ + default: + return `${subject} ended abnormally (${String(stopReason)}) before it finished.`; + } +} +/** Serialize each durable child's delivery, release, and disposal. */ +class ChildLock { + tails = new Map(); + /** + * Run `operation` after every previously queued operation for `childId`. + * @param childId - the durable child whose operations are linearized. + * @param operation - the critical section to run in order. + * @returns the operation's own settlement. + */ + run(childId, operation) { + const previous = this.tails.get(childId) ?? Promise.resolve(); + const result = previous.then(operation, operation); + // Absorb rejections in the chaining tail so one failed critical section + // cannot reject an unrelated later caller. + const tail = result.then(() => undefined, () => undefined); + this.tails.set(childId, tail); + void tail.then(() => { + if (this.tails.get(childId) === tail) + this.tails.delete(childId); + }); + return result; + } +} +/** + * The continuable-subagent orchestration service behind `ctx.subagents`. Tool + * schema and host adapters are consumers of this one contract; foreground + * one-shot delegation keeps calling `ctx.subagents.start()` and never enters + * this lifecycle. + */ +export class SubagentContinuationManager { + ctx; + host; + setupRegistry; + /** Child session id → its live Activation. Process-local, never durable. */ + activations = new Map(); + /** Materializations admitted before drain, tracked through publication or rollback. */ + materializations = new Set(); + locks = new ChildLock(); + /** Structural Cordis owner of every Activation handle. */ + ownerCtx; + /** + * Exact roots whose host teardown has begun, with the live lineage members + * observed under each root. Entries remain until that exact root leaves the + * Agent registry, closing admission throughout its host's teardown without + * poisoning a later same-id replacement. + */ + closingScopes = new Map(); + draining = false; + constructor(ctx, host, setupRegistry) { + this.ctx = ctx; + this.host = host; + this.setupRegistry = setupRegistry; + // Ordinary Cordis owner effects unwind in reverse registration order, which + // cannot express the dynamic child graph. Register the private scope's + // structural disposer FIRST and the drain SECOND, so reverse unwind invokes + // the drain before releasing the scope; a cleanup effect on the same scope + // as the Agent handles would let structural handle disposal bypass + // child-first ordering. + const scope = ctx.plugin(function activationOwner() { }); + this.ownerCtx = scope.ctx; + ctx.on('agent/disposed', ({ agent }) => { + this.closingScopes.delete(agent); + }); + ctx.effect(function* () { + yield scope.dispose; + yield () => this.drain(); + }.bind(this), 'subagents.continuations()'); + } + /** + * Start one continuable background child: reserve its durable identity, + * resolve the provider's detached creation spec, create the child Agent + * through the private activation-owner scope, establish any continuable-parent + * ownership, and submit the initial prompt. Resolves when inbox acceptance + * yields the message id — without waiting for the turn to start or for the + * message to reach the Session log. + * + * Every failure before that acceptance rejects without either id, disposing + * any created handle and rolling back the Activation and parent ownership. + * The caller signal owns lookup, materialization, and admission only until + * acceptance; afterwards the manager owns the Activation independently. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted initial prompt's message id. + */ + async startContinuable(spec) { + const request = spec.request; + const parent = request.parent; + this.assertAdmitting(parent); + this.requirePersistence(); + assertSubagentMaxDepth(request.maxDepth); + const childId = SessionId(randomUUID()); + const childDepth = resolveChildDepth(parent, request.maxDepth); + // Snapshot before any await: invalid descriptor JSON rejects the call + // before a child exists, and the detached value is what reaches the log. + const agentProvider = request.agentOptions?.provider ?? parent.options.provider; + const agentModel = request.agentOptions?.model ?? parent.options.model; + const descriptor = snapshotSubagentDescriptor({ + mode: 'continuable', + provider: spec.provider, + label: spec.label, + ...agentProvider !== undefined ? { agentProvider } : {}, + ...agentModel !== undefined ? { agentModel } : {}, + ...request.persona !== undefined ? { persona: request.persona } : {}, + ...request.toolFilter !== undefined ? { toolFilter: request.toolFilter } : {}, + }); + // Capture before the first await: a later parent switch belongs to the + // parent's future, not to this child. + const delegatedPolicies = captureDelegatedPolicyOverrides(parent); + const prepared = await this.host.prepareContinuable(spec.provider, { + sessionId: childId, + parent, + signal: spec.signal, + }); + spec.signal.throwIfAborted(); + this.assertAdmitting(parent); + const lineageSeedLength = prepared.seed?.length ?? 0; + const seed = seedDescriptorTurn(childId, prepared.seed, descriptor); + const messageId = await this.locks.run(childId, async () => { + const activation = await this.materialize({ + childId, + provider: spec.provider, + parent, + create: { seed, meta: childSessionMeta(parent, childDepth, lineageSeedLength), delegatedPolicies }, + agentOptions: resolveChildAgentOptions(parent, request.agentOptions, childDepth), + composition: { persona: request.persona, toolFilter: request.toolFilter }, + signal: spec.signal, + }); + return this.submitMaterialized(activation, request.prompt, { kind: 'user' }, parent, spec.signal); + }); + return { childId, messageId }; + } + /** + * Deliver one later message to a known continuable child as its next FIFO + * turn. Routing depends only on Activation residency: a `running` Activation + * enqueues, a `waiting` one wakes the same Agent, and an absent one + * cold-resumes a new Activation from the persisted Session. The Agent inbox + * is the only queue, so every accepted message has one observable order. + * + * The caller signal owns lookup, materialization, and admission only until + * inbox acceptance; afterwards the accepted turn cannot be cancelled through + * this service. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - the durable child session id. + * @param content - the user-role content to deliver. + * @param options - the message source fields and caller cancellation. + * @returns the accepted message's inbox id. + * @throws when parent authority, availability, or admission rejects the delivery. + */ + async followup(parent, childId, content, options) { + this.assertAdmitting(parent); + while (true) { + const live = await this.locks.run(childId, async () => { + const activation = this.activations.get(childId); + if (activation === undefined) + return this.coldResume(parent, childId, content, options); + // A delivery that arrives after the disposal transaction began must not + // reach a handle being torn down; wait for release, then cold-resume. + /* v8 ignore next 3 -- the send-versus-dispose cutoff: reaching this arm needs a + * delivery to observe the transaction inside the same critical section that opened it, + * which no test can schedule deterministically. The behavior is covered end-to-end by + * "cold-resumes a delivery that lost the race with final disposal". */ + if (activation.disposal !== undefined) { + return activation.disposal.then(() => undefined, () => undefined); + } + return this.submitAdmitted(activation, content, options.source, parent, options.signal); + }); + /* v8 ignore start -- only the lost-cutoff arm above returns undefined, so only that + * race reaches the retry below, which then cold-resumes a new Activation. */ + if (live !== undefined) + return live; + this.assertAdmitting(parent); + options.signal.throwIfAborted(); + /* v8 ignore stop */ + } + } + /** + * Interrupt one live continuable child's current turn. Admission is + * synchronous and the effect is asynchronous: this authorizes the caller, + * requests `Agent.cancel(cause, { keepInbox: true })` on the target, and + * returns without waiting for the target to observe the signal or reach + * quiescence. The Activation, its handle, accepted unclaimed inbox work, and + * already-published descendants are untouched; work already claimed into the + * interrupted turn is not requeued. Once the interrupted driver is idle, a + * waking send resumes the parked queue. + * + * An absent target is an accepted no-op, which uniformly covers natural + * completion races, repeated requests, one-shot ids, and unknown ids without + * consulting the durable catalog. A target whose disposal transaction is + * already open is likewise an accepted no-op after authorization. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the presented authority does + * not own the live target: a stale or self-targeting ancestor caller, a + * parent address that is not the live target's durable direct parent, or + * an ancestor outside the target's recorded live lineage. + */ + interrupt(targetSessionId, authority) { + if (authority.kind === 'ancestor') { + const caller = authority.agent; + // A stale caller is rejected even when the target is absent, so a + // replaced same-id Agent can never probe this manager's state. + if (this.ctx.agents.get(caller.id) !== caller) { + throw new SubagentError(`interrupting "${targetSessionId}" requires the exact live ancestor agent`, 'UNAUTHORIZED'); + } + if (caller.id === targetSessionId) { + throw new SubagentError(`agent "${caller.id}" cannot interrupt itself`, 'UNAUTHORIZED'); + } + } + const activation = this.activations.get(targetSessionId); + if (activation === undefined) + return; + if (authority.kind === 'user') { + if (activation.handle.agent.session.header.parentSession !== authority.parentSessionId) { + throw new SubagentError(`subagent "${targetSessionId}" belongs to another parent session`, 'UNAUTHORIZED'); + } + } + else if (!activation.ancestry.has(authority.agent)) { + throw new SubagentError(`subagent "${targetSessionId}" is not a live descendant of agent "${authority.agent.id}"`, 'UNAUTHORIZED'); + } + // Disposal already stopped the target with a whole-Activation teardown; + // a second cancel would be a redundant signal on a closing handle. + if (activation.disposal !== undefined) + return; + activation.handle.agent.cancel(authority.kind === 'user' ? { kind: 'user' } : { kind: 'parent' }, { keepInbox: true }); + } + /** + * Deliver explicitly selected content from one resident continuable child to + * its durable direct parent. Sender authorization, parent resolution, and + * send acceptance share one no-await span. Reporting neither concludes the + * child's turn nor changes its Activation lifetime. + * @param child - exact live reporting child; this is the authority credential. + * @param content - selected model-facing content. + * @param options - scheduling policy and pre-acceptance cancellation. + * @returns the stable identity of the message accepted by the parent. + * @throws {SubagentError} when the sender is unauthorized, the parent is not + * live, or continuation admission is closing. + */ + // oxlint-disable-next-line typescript/require-await -- keep rejection semantics without yielding during admission + async reportFrom(child, content, options) { + options.signal.throwIfAborted(); + this.assertAdmitting(child); + const activation = this.authorizeReporter(child); + const parent = this.resolveReportParent(child); + return this.deliverReport(activation, parent, content, options.delivery); + } + /** Authorize only the exact Agent of one resident Activation. */ + authorizeReporter(child) { + const activation = this.activations.get(child.id); + if (activation === undefined || activation.handle.agent !== child) { + throw new SubagentError(`agent "${child.id}" is not a live continuable subagent and cannot report`, 'UNAUTHORIZED'); + } + /* v8 ignore next 6 -- only a synchronous re-entrant disposer can open this + * transaction between exact-agent authorization and this no-await cutoff. */ + if (activation.disposal !== undefined) { + throw new SubagentError(`subagent "${child.id}" activation is being disposed; the report was not delivered`, 'ACTIVATION_CLOSING'); + } + return activation; + } + /** Resolve the reporting child's live direct parent from durable lineage. */ + resolveReportParent(child) { + const parentId = child.session.header.parentSession; + /* v8 ignore next -- every continuation-managed child has direct-parent metadata. */ + const parent = parentId === undefined ? undefined : this.ctx.agents.get(parentId); + if (parent === undefined) { + throw new SubagentError('direct parent is not live; report was not delivered', 'PARENT_UNAVAILABLE'); + } + return parent; + } + /** Deliver one framed report through the selected parent scheduling preset. */ + deliverReport(activation, parent, content, delivery) { + const message = createUserMessage({ + content: [ + { type: 'text', text: `Background subagent ${activation.childId} reported:` }, + ...content, + ], + source: { + kind: 'subagent-report', + form: 'relay', + senderSessionId: activation.childId, + }, + }); + if (delivery === 'wakeup') { + this.sendWaking(parent, message, () => { this.sendReport(parent, message, delivery); }); + } + else { + this.sendReport(parent, message, delivery); + } + return message.id; + } + /** + * Perform one waking send to a parent, accounted against that parent's own + * Activation when it has one. Registering the id before the send is what + * keeps a continuation-managed parent from being judged quiescent in the + * window between `followup()` and the microtask that admits it. + * @param parent - the exact live parent receiving the waking message. + * @param message - the message whose id is accounted. + * @param send - the synchronous waking send to perform. + */ + sendWaking(parent, message, send) { + const parentActivation = this.activations.get(parent.id); + if (parentActivation !== undefined && parentActivation.handle.agent === parent) { + this.admitWaking(parentActivation, message.id, send); + } + else { + send(); + } + } + /** Send one report while translating only the parent's own rejection. */ + sendReport(parent, message, delivery) { + try { + if (delivery === 'wakeup') + parent.followup(message); + else + parent.inject(message); + } + catch (error) { + throw new SubagentError('direct parent is not live; report was not delivered', 'PARENT_UNAVAILABLE', { cause: error }); + } + } + /** + * Close admission, await every already-admitted materialization through + * publication or rollback, then dispose the stable live Activation forest + * child-first. Sibling branches drain independently: one failure is recorded + * but never prevents the remaining handles from being attempted, and the + * aggregate rejects only after every branch settles. + * @returns once materialization is quiescent and every live Activation released its handle. + * @throws an aggregate error when any branch failed to release. + */ + async drain() { + // Close admission synchronously before the first await. Materializations + // already past that cutoff remain tracked until their handle is installed + // or rollback completes, producing a stable forest for the later snapshot. + this.draining = true; + await Promise.all([...this.materializations].map(materialization => materialization.settled)); + // Snapshot roots after closing admission: a root is an Activation no live + // Activation owns, so disposing roots recurses child-first into the forest. + const owned = new Set(); + for (const activation of this.activations.values()) { + for (const child of activation.ownedChildren) + owned.add(child); + } + const roots = [...this.activations.values()].filter(activation => !owned.has(activation.childId)); + await this.disposeRoots(roots, 'activation(s)'); + } + /** + * Stop only the continuable descendants of exact live host-owned parents. + * Admission stays closed for those parent trees until each exact parent + * leaves the Agent registry; unrelated trees and manager-wide admission stay + * live. + * @param parents - exact live roots whose continuable descendants must stop. + * @returns once every retained descendant Activation released its handle. + * @throws an aggregate error after all scoped branches settle when any failed. + */ + async drainDescendants(parents) { + const roots = new Set(parents.filter(parent => this.ctx.agents.get(parent.id) === parent)); + if (roots.size === 0) + return; + // Publish the scoped admission cutoff before the first await. Merge with an + // earlier call for the same exact root so a converging drain cannot forget + // descendants whose release is already in flight. + for (const root of roots) { + this.closingMembers(root).add(root); + } + const targets = []; + for (const activation of this.activations.values()) { + const lineage = this.liveLineage(activation.handle.agent); + // Strict descendants only: a continuable Agent may itself be a + // host-owned root, and its host remains responsible for that root handle. + const owners = [...roots].filter(root => activation.handle.agent !== root + && activation.ancestry.has(root)); + if (owners.length === 0) + continue; + targets.push(activation); + for (const owner of owners) { + const members = this.closingMembers(owner); + members.add(activation.handle.agent); + for (const agent of lineage) + members.add(agent); + } + } + const materializations = [...this.materializations].filter((materialization) => { + const owners = [...roots].filter(root => materialization.lineage.includes(root)); + for (const owner of owners) { + const members = this.closingMembers(owner); + for (const agent of materialization.lineage) + members.add(agent); + } + return owners.length > 0; + }); + const ownedTargets = new Set(); + for (const activation of targets) { + for (const child of activation.ownedChildren) + ownedTargets.add(child); + } + const targetRoots = targets.filter(activation => !ownedTargets.has(activation.childId)); + // Open every selected transaction before the materialization barrier. + // Disposal propagates cancellation top-down in the same synchronous span; + // handle release remains child-first. + for (const activation of targets) { + const disposal = this.dispose(activation); + void disposal.catch(() => undefined); + } + await Promise.all(materializations.map(materialization => materialization.settled)); + await this.disposeRoots(targetRoots, 'scoped activation(s)'); + } + /** Dispose independent roots and report every branch failure after all settle. */ + async disposeRoots(roots, failureSubject) { + const failures = await Promise.all(roots.map(async (activation) => { + try { + await this.dispose(activation); + return undefined; + } + catch (error) { + return error; + } + })); + const reasons = failures.filter(failure => failure !== undefined); + if (reasons.length > 0) { + throw new SubagentError(`continuable subagent teardown failed for ${reasons.length} ${failureSubject}: ` + + reasons.map(reason => errorChain(reason)).join('; '), 'ACTIVATION_TEARDOWN_FAILED'); + } + } + /** Return the retained member set for one exact scoped-teardown root. */ + closingMembers(root) { + const existing = this.closingScopes.get(root); + if (existing !== undefined) + return existing; + const members = new Set(); + this.closingScopes.set(root, members); + return members; + } + /** + * Return the exact currently resolvable ancestry from `agent` upward. The + * first element is always the supplied identity, even when it is already + * stale; each ancestor after it must be the registry's current exact entry. + */ + liveLineage(agent) { + const lineage = [agent]; + const seen = new Set([agent.id]); + let parentSession = agent.session.header.parentSession; + while (parentSession !== undefined) { + const parent = this.ctx.agents.get(parentSession); + if (parent === undefined || seen.has(parent.id)) + break; + lineage.push(parent); + seen.add(parent.id); + parentSession = parent.session.header.parentSession; + } + return lineage; + } + /** + * The teardown that closed continuable admission for this agent's lineage. + * `'manager'` is the whole manager draining; an Agent is the exact scoped root + * whose forest is closing. + * @param agent - the agent whose lineage is tested. + * @returns the closing teardown, or `undefined` while admission is open. + */ + closingTeardownFor(agent) { + if (this.draining) + return 'manager'; + const lineage = this.liveLineage(agent); + for (const [root, members] of this.closingScopes) { + if (members.has(agent) || lineage.includes(root)) + return root; + } + return undefined; + } + /** Reject new admission once the manager or this exact parent tree began draining. */ + assertAdmitting(agent) { + const closing = this.closingTeardownFor(agent); + if (closing === undefined) + return; + throw new SubagentError(closing === 'manager' + ? 'continuable subagents are draining; the operation was not admitted' + : `continuable subagents below parent "${closing.id}" are draining; the operation was not admitted`, 'DRAINING'); + } + /** + * Derive residency from Agent quiescence and the owned-child set. `running` + * covers an active admission, an open turn, or accepted waking inbox work. + * + * `Agent.status` alone is insufficient: it stays `idle` between an accepted + * waking send and the microtask that admits it, so a synchronous inbox + * observer would see `settled` while a turn is already queued. `accepted` + * holds the ids this manager admitted but has not yet seen drained. + */ + stateOf(activation) { + if (activation.handle.agent.status === 'running' || activation.accepted.size > 0) + return 'running'; + if (activation.ownedChildren.size > 0) + return 'waiting'; + return 'settled'; + } + /** + * Cold-resume a persisted child: inspect and authorize its Session, fold the + * generic descriptor, create the Activation through `ctx.agents.resume()`, + * and submit the waiting turn. This never dispatches through a subagent + * provider — the persisted Session already holds the initial prefix and the + * descriptor is the whole reconstruction input. + */ + async coldResume(parent, childId, content, options) { + const persistence = this.requirePersistence(); + let loaded; + try { + loaded = await persistence.inspect(childId, options.signal); + } + catch (error) { + options.signal.throwIfAborted(); + throw new SubagentError(`subagent "${childId}" is unavailable`, 'NOT_RESUMABLE', { cause: error }); + } + options.signal.throwIfAborted(); + this.assertAdmitting(parent); + // Authorize the persisted header before folding: only the durable child's + // exact live direct parent may continue it. + this.authorizeLineage(parent, childId, loaded.meta.parentSession); + // Fold only the child's own suffix: a fork seed replays the parent's log, + // which may carry an ANCESTOR's descriptor when the parent is itself a + // continuable child. + const descriptor = foldSubagentDescriptor(loaded.events.slice(loaded.meta.seedLength ?? 0)); + if (descriptor === undefined || descriptor.mode !== 'continuable') { + throw new SubagentError(`subagent "${childId}" has no supported continuation state and cannot be resumed; ` + + 'do not retry send_message with this id', 'NOT_RESUMABLE'); + } + let activation; + try { + activation = await this.materialize({ + childId, + provider: descriptor.provider, + parent, + agentOptions: { + ...descriptor.agentProvider !== undefined ? { provider: descriptor.agentProvider } : {}, + ...descriptor.agentModel !== undefined ? { model: descriptor.agentModel } : {}, + }, + composition: { persona: descriptor.persona, toolFilter: descriptor.toolFilter }, + signal: options.signal, + }); + } + catch (error) { + options.signal.throwIfAborted(); + if (error instanceof SubagentError) + throw error; + throw new SubagentError(`subagent "${childId}" is unavailable`, 'NOT_RESUMABLE', { cause: error }); + } + return this.submitMaterialized(activation, content, options.source, parent, options.signal); + } + /** + * Submit to a freshly materialized Activation or roll it back completely. + * @param activation - the just-published Activation to admit or release. + * @param content - the initial or resumed message content. + * @param source - durable fields naming who supplied the accepted message. + * @param parent - the live direct parent authorizing admission. + * @param signal - caller cancellation owning admission until acceptance. + * @returns the accepted inbox message id. + */ + async submitMaterialized(activation, content, source, parent, signal) { + try { + return this.submitAdmitted(activation, content, source, parent, signal); + } + catch (error) { + /* v8 ignore next -- rollback disposal failures must not mask the + * pre-acceptance signal, drain, or lifecycle failure. */ + await this.dispose(activation).catch(() => undefined); + throw error; + } + } + /** + * Create or resume the child Agent through the private activation-owner + * scope, install the handle in a fresh Activation, and register ownership on + * a continuation-managed parent. Rejection leaves no Activation, no handle, + * and no ownership membership. + */ + materialize(inputs) { + this.assertAdmitting(inputs.parent); + const settled = Promise.withResolvers(); + const lineage = this.liveLineage(inputs.parent); + const materialization = { + lineage, + settled: settled.promise, + }; + this.materializations.add(materialization); + return this.materializeTracked(inputs, lineage).finally(() => { + this.materializations.delete(materialization); + settled.resolve(); + }); + } + /** + * Perform one tracked materialization. The caller keeps the drain barrier + * registered until this either returns a resident Activation or finishes + * rollback. + */ + async materializeTracked(inputs, parentLineage) { + const { childId, provider, parent, create } = inputs; + // No id pre-check here: the child lock serializes each durable child, both + // callers reach this only after confirming no Activation exists, and + // `AgentRegistry.enter()` is the authoritative collision boundary for an id + // some other owner holds — a duplicate would reject there with rollback. + inputs.signal.throwIfAborted(); + const setup = (childCtx) => { + // Only fresh creation seeds the delegation policy onto the child's own + // log (after any fork seed, so fresh policy wins stale seed state); a + // cold resume replays those persisted events instead. + if (create !== undefined) { + appendDelegatedPolicyOverrides(childCtx.agent.session, create.delegatedPolicies); + } + applyChildComposition(childCtx, parent, inputs.composition); + return this.setupRegistry.apply(childCtx); + }; + const observer = this.host.observeActivation(provider, childId, parent); + // Agent creation owns rollback before handle transfer. A rejection leaves + // no resident Activation and therefore publishes no lifecycle edge. + const handle = create === undefined + ? await this.ownerCtx.agents.resume({ + resumeSessionId: childId, + agentOptions: inputs.agentOptions, + signal: inputs.signal, + setup, + }) + : await this.ownerCtx.agents.create({ + sessionId: childId, + meta: create.meta, + seed: create.seed, + agentOptions: inputs.agentOptions, + signal: inputs.signal, + setup, + }); + const activation = { + childId, + // The durable lineage, not merely the caller: creation stamps this same + // agent into the child's header, and cold resume authorized it against + // the persisted header before materializing. + parentSession: parent.id, + provider, + handle, + ancestry: new WeakSet([handle.agent, ...parentLineage]), + ownedChildren: new Set(), + observer, + disposal: undefined, + accepted: new Set(), + announced: false, + poke: Promise.withResolvers(), + }; + // After transfer, any failure must dispose the created handle, remove the + // Activation, and roll back parent ownership before rejecting. + this.activations.set(childId, activation); + try { + inputs.signal.throwIfAborted(); + this.assertAdmitting(parent); + this.acquireOwnership(parent, childId); + // Every accepted id leaves the inbox exactly once, through dequeue or + // discard. Clearing it there is what lets `stateOf()` distinguish a truly + // quiet Agent from one whose accepted turn has not been admitted yet. + // Registered through the child's own scoped context, so scope filtering + // already restricts both listeners to this exact agent. + handle.agent.ctx.on('agent/inbox/claimed', ({ message }) => { + /* v8 ignore next -- a claim of an id this manager never admitted needs + * another sender on the same child, which no current path allows. */ + if (activation.accepted.delete(message.id)) + this.wake(activation); + }); + handle.agent.ctx.on('agent/inbox/discarded', ({ message }) => { + if (activation.accepted.delete(message.id)) + this.wake(activation); + }); + // Agent creation committed setup at its publication boundary; + // revocations from here on are immediate live revocation. + // Publish the start edge before any turn can run, so observers see this + // epoch before its first request. + observer.start(handle.agent); + } + catch (error) { + // Listener exceptions are contained by the lifecycle emitter; a start + // publication throw therefore leaves no residency edge to pair. + /* v8 ignore next -- rollback failure must not mask the admission failure + * that prevented this operation from returning an accepted message id. */ + await this.rollbackUnpublished(activation).catch(() => undefined); + throw error; + } + this.watchSettlement(activation); + return activation; + } + /** + * Release an Activation whose start edge was not published. The memoized + * transaction remains in the live map until handle disposal settles, so a + * concurrent drain or delivery observes the same closing boundary. + */ + rollbackUnpublished(activation) { + return (activation.disposal ??= (async () => { + try { + await activation.handle.dispose(); + } + finally { + this.activations.delete(activation.childId); + this.releaseOwnership(activation.childId); + } + })()); + } + /** + * Register the child in a continuation-managed parent's owned set before the + * child can run, so that parent cannot settle while the child is live. A + * top-level or other non-continuation Agent has no Activation and stays + * outside the waiting graph. + */ + acquireOwnership(parent, childId) { + const parentActivation = this.activations.get(parent.id); + if (parentActivation === undefined) + return; + if (parentActivation.disposal !== undefined) { + throw new SubagentError(`subagent parent "${parent.id}" is being disposed; the child was not established`, 'ACTIVATION_CLOSING'); + } + parentActivation.ownedChildren.add(childId); + } + /** Remove one child from its live owner's set and let that owner re-check settlement. */ + releaseOwnership(childId) { + for (const candidate of this.activations.values()) { + if (candidate.ownedChildren.delete(childId)) + this.wake(candidate); + } + } + /** Let a settlement watcher re-observe quiescence after ownership or inbox changes. */ + wake(activation) { + activation.poke.resolve(); + activation.poke = Promise.withResolvers(); + } + /** + * Submit one message as the child's next FIFO turn and return its accepted + * inbox id. Acceptance is the operation's success boundary; the manager owns + * the Activation independently afterwards. + */ + submit(activation, content, source, parent) { + // Parent-originated delivery keeps the parent live through ownership, so + // establish it before the message can enter the child's inbox. + this.acquireOwnership(parent, activation.childId); + const message = createUserMessage({ content, source }); + const accepted = this.admitWaking(activation, message.id, () => { + activation.handle.agent.followup(message); + }); + // Past this point the caller has an id for this child, so its eventual + // settlement is something the parent is owed an account of. + activation.announced = true; + return accepted; + } + /** + * Account one waking send across a resident Activation's settlement window. + * @param activation - Activation receiving waking inbox work. + * @param messageId - stable identity of the message about to be sent. + * @param send - synchronous send that publishes one enqueue occurrence. + * @returns the accepted message id. + */ + admitWaking(activation, messageId, send) { + // `Agent.followup()` publishes inbox events synchronously, so observers must + // see this Activation as busy before the call begins. + activation.accepted.add(messageId); + try { + send(); + } + catch (error) { + activation.accepted.delete(messageId); + throw error; + } + // Accepted waking work keeps this Activation live until whenIdle() observes + // the complete waking suffix. + this.wake(activation); + return messageId; + } + /** + * Cross the final admission cutoff and submit without yielding. Signal abort, + * manager drain, or Activation disposal that wins before this synchronous + * span rejects without inbox acceptance. + */ + submitAdmitted(activation, content, source, parent, signal) { + signal.throwIfAborted(); + this.assertAdmitting(parent); + /* v8 ignore next 6 -- only a synchronous re-entrant disposer can change + * this field between the caller's live check and this no-await boundary. */ + if (disposalOf(activation) !== undefined) { + throw new SubagentError(`subagent "${activation.childId}" activation is being disposed; the message was not accepted`, 'ACTIVATION_CLOSING'); + } + this.authorizeLineage(parent, activation.childId, activation.handle.agent.session.header.parentSession); + return this.submit(activation, content, source, parent); + } + /** + * Authorize one operation against the durable direct-parent lineage. Other + * agents, ancestors, teams, workflows, and hosts remain rejected until an + * explicit authority protocol has a production consumer. + */ + authorizeLineage(parent, childId, parentSession) { + if (this.ctx.agents.get(parent.id) !== parent) { + throw new SubagentError(`subagent "${childId}" delivery requires the exact live parent agent`, 'UNAUTHORIZED'); + } + if (parentSession !== parent.id) { + throw new SubagentError(`subagent "${childId}" belongs to another parent session`, 'UNAUTHORIZED'); + } + } + /** + * Follow one Activation to settlement: wait for Agent quiescence, then for + * every owned child to complete disposal, and dispose the handle once both + * hold. A `next-turn` delivered while `waiting` wakes the same Agent and + * returns it to `running`, so this re-observes rather than settling early. + */ + watchSettlement(activation) { + void (async () => { + while (disposalOf(activation) === undefined) { + const poked = activation.poke.promise; + await Promise.race([activation.handle.agent.whenIdle(), poked]); + if (disposalOf(activation) !== undefined) + return; + // Re-check settlement INSIDE the child lock and begin disposal in the + // same critical section, so a concurrent delivery either wins admission + // before the transaction opens or waits for release and cold-resumes. + // Deciding outside the lock would let a delivery observe a not-yet + // resident handle that this watcher is already about to tear down. + const settling = await this.locks.run(activation.childId, () => { + if (disposalOf(activation) !== undefined || this.stateOf(activation) !== 'settled') { + return Promise.resolve({ settling: false }); + } + // `dispose()` assigns its memoized transaction synchronously, so + // admission is closed before this critical section releases. + return Promise.resolve({ settling: true, done: this.dispose(activation) }); + }); + if (!settling.settling) { + // Still running, or waiting on descendants: re-observe after the next + // accepted message or ownership release. + if (activation.handle.agent.status !== 'running') + await poked; + continue; + } + try { + await settling.done; + } + catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" activation teardown failed: ${errorChain(error)}`); + } + return; + } + })(); + } + /** + * Stop one Activation immediately, then release it child-first. The memoized + * transaction is installed before cancellation or recursive callbacks, so + * admission and reentrant teardown converge on the same owner. + * + * The final session flush is best effort and never prevents handle disposal + * or ownership release, because retaining a child would permanently pin its + * ancestors in `waiting`. + * @param activation - the residency epoch to stop and release. + * @returns the one disposal transaction owned by this Activation. + */ + dispose(activation) { + const existing = activation.disposal; + if (existing !== undefined) + return existing; + const completion = Promise.withResolvers(); + // Presence is the admission cutoff. Assign it before the async helper starts + // because that helper cancels Agents and may synchronously re-enter callers. + activation.disposal = completion.promise; + void this.finishDisposal(activation).then(completion.resolve, completion.reject); + return completion.promise; + } + /** + * Propagate stop synchronously, then finish the child-first release. + * @param activation - the Activation whose disposal transaction is installed. + * @returns once the handle and ownership edge are released. + */ + async finishDisposal(activation) { + this.wake(activation); + const { childId } = activation; + // Stop top-down before the first await. Slow descendant cleanup may delay + // release, but it cannot let this ancestor continue model or tool work. + activation.handle.agent.cancel({ kind: 'parent' }); + const idle = activation.handle.agent.whenIdle(); + const children = [...activation.ownedChildren] + .map(child => this.activations.get(child)) + .filter((child) => child !== undefined); + const childDisposals = children.map(child => this.dispose(child)); + const failures = []; + try { + // Release remains child-first even though cancellation propagated + // top-down: every owned child completes before this handle is removed. + const childFailures = await Promise.all(childDisposals.map(async (disposal) => { + try { + await disposal; + return undefined; + } + catch (error) { + return error; + } + })); + const reasons = childFailures.filter(reason => reason !== undefined); + if (reasons.length > 0) { + failures.push(new SubagentError(`subagent "${childId}" child teardown failed: ${reasons.map(reason => errorChain(reason)).join('; ')}`, 'ACTIVATION_TEARDOWN_FAILED')); + } + // Quiesce before the flush: a turn still running would keep + // appending events the flush cannot cover. + await idle; + await this.flushFinalState(activation); + // Capture the child-dependent edge data while the child is still live: + // handle disposal unregisters it, and consumers read its log and scope. + activation.observer.capture(activation.handle.agent); + } + catch (error) { + failures.push(new SubagentError(`subagent "${childId}" activation teardown failed: ${errorChain(error)}`, 'ACTIVATION_TEARDOWN_FAILED', { cause: error })); + } + try { + await activation.handle.dispose(); + } + catch (error) { + failures.push(new SubagentError(`subagent "${childId}" activation handle disposal failed: ${errorChain(error)}`, 'ACTIVATION_TEARDOWN_FAILED', { cause: error })); + } + let failure; + if (failures.length === 1) { + failure = failures[0]; + } + else if (failures.length > 1) { + failure = new SubagentError(`subagent "${childId}" activation teardown failed at ${failures.length} boundaries: ` + + failures.map(item => errorChain(item)).join('; '), 'ACTIVATION_TEARDOWN_FAILED', { cause: new AggregateError(failures) }); + } + // Only now is the Activation gone: keeping the entry until disposal settles + // makes a racing delivery wait for release rather than cold-resume into the + // still-registered agent. + this.activations.delete(childId); + // BEFORE releasing ownership, while the parent still counts this child and + // therefore cannot be judged settled. Delivering after the release would + // race a parent watcher that resumes one microtask later, finds itself + // childless and quiet, and disposes an Agent whose `cancel()` clears the + // inbox this notice is sitting in. + this.notifySettlement(activation, activation.observer.terminal(failure)); + // Release ownership even on failure: a retained failed child would pin its + // ancestors in `waiting` forever. + this.releaseOwnership(childId); + // Emit once the disposal outcome is known, so a rejecting scoped cleanup + // cannot be reported as a successful epoch. + activation.observer.settle(failure); + if (failure !== undefined) + throw failure; + } + /** + * Tell the durable direct parent that this child produced everything it is + * going to. Unconditional for every child the caller received an id for: it + * does not consider whether the child reported, because the cases that most + * need it — a token ceiling, a model failure, cancellation, teardown — are + * exactly the ones where the child never got to choose. A materialization + * rolled back before its first acceptance stays silent, since the caller was + * told that child was not established. A parent that is no longer live is not + * an error; the child's own Session remains the durable record either way. + * A parent whose own lineage is already closing receives the notice without a + * wake, because teardown is not a reason to start a turn. + * + * Never blocks disposal. A delivery failure is logged and dropped, because + * retaining a child to retry a notice would pin its whole ancestry in + * `waiting` forever. + * @param activation - the settling Activation, still owned by its parent. + * @param terminal - how this epoch ended, as the terminal edge will report it. + */ + notifySettlement(activation, terminal) { + if (!activation.announced) + return; + try { + const parent = this.ctx.agents.get(activation.parentSession); + if (parent === undefined) + return; + const summary = settlementSummary(activation.childId, terminal.stopReason); + const message = createUserMessage({ + content: [ + { type: 'text', text: summary }, + ...terminal.output === undefined + ? [{ type: 'text', text: 'It left no closing message.' }] + : [{ type: 'text', text: 'Its closing message:' }, ...terminal.output], + ], + source: { + kind: 'subagent-settled', + form: 'notice', + summary: boundContextSummary(summary), + senderSessionId: activation.childId, + }, + }); + // A parent whose own teardown already began must not be woken. Waking is + // not a queue operation: `followup()` on a quiescent Agent starts a turn, + // and `cancel()` does not arm against a later one, so a notice arriving + // during teardown would spend a model request on an Agent its host is + // about to dispose — once per tree layer, since each layer's own notice + // then wakes the layer above it. Injecting delivers to a parent still + // reading its inbox and records the account in the log either way; it + // does NOT survive that parent's own disposal, whose `keepInbox: false` + // cancel durably clears whatever it never claimed. + if (this.closingTeardownFor(parent) !== undefined) { + parent.inject(message); + return; + } + // An idle parent has nothing else to look at, so it gets one ordinary + // turn. A busy parent is steered instead of woken: `Inbox.claim()` takes + // the whole next-step batch at one boundary, so several children settling + // together cost one step rather than one turn each. Steering rather than + // injecting closes the window where a driver retires between this status + // read and the send, which would strand the notice unclaimed. + this.sendWaking(parent, message, () => { + if (parent.status === 'idle') + parent.followup(message); + else + parent.steer(message); + }); + } + catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" settlement notice was not delivered to its parent: ` + + errorChain(error)); + } + } + /** + * Request a best-effort final session flush after the child is quiescent. + * Listener failure is logged because flush participation cannot identify a + * particular persistence backend, and teardown must still release ownership. + * @param activation - the Activation whose final events should be flushed. + */ + async flushFinalState(activation) { + const child = activation.handle.agent; + try { + await child.ctx.sessions.flush(child.session); + } + catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" best-effort final session flush failed; ` + + `the persisted state may be unavailable or stale on resume: ${errorChain(error)}`); + } + } + /** Resolve the persistence service continuable children require, or fail loud. */ + requirePersistence() { + const persistence = this.ctx.get('sessionPersistence'); + if (persistence === undefined) { + throw new SubagentError('continuable subagents require session persistence (load a dsh-session-persistence backend)', 'PERSISTENCE_UNAVAILABLE'); + } + return persistence; + } +} +export default SubagentContinuationManager; +//# sourceMappingURL=continuation.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.d.ts new file mode 100644 index 0000000..6b9082e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.d.ts @@ -0,0 +1,31 @@ +/** + * Delegation-depth accounting: the recursion budget a parent passes to its + * children. Kept apart from the service so composition helpers can read it + * without importing the registry. + * + * @module @deepseek-ai/dsh-subagent/depth + */ +import type { Agent } from '@deepseek-ai/dsh-agent'; +declare module '@deepseek-ai/dsh-agent' { + interface AgentOptions { + /** Delegation depth: zero for a top-level agent and parent depth + 1 for a child. */ + subagentDepth?: number; + } +} +/** + * Read an agent's delegation depth, treating absence as top-level depth zero. + * The persisted session header is authoritative and monotone: runtime + * `AgentOptions.subagentDepth` may DEEPEN the count but can never lower it — + * a resumed child arrives with fresh options, and counting it from zero would + * let it delegate as if it were top-level. + * @param agent - the agent whose header and options carry the depth. + * @returns its non-negative safe-integer depth. + * @throws if the runtime `AgentOptions.subagentDepth` is not a non-negative safe integer. + */ +export declare function delegationDepthOf(agent: Agent): number; +/** + * Reject a recursion cap that cannot represent an exact delegation depth. + * @param maxDepth - the optional runtime value to validate. + */ +export declare function assertSubagentMaxDepth(maxDepth: unknown): void; +//# sourceMappingURL=depth.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.js new file mode 100644 index 0000000..9282c92 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.js @@ -0,0 +1,39 @@ +/** + * Delegation-depth accounting: the recursion budget a parent passes to its + * children. Kept apart from the service so composition helpers can read it + * without importing the registry. + * + * @module @deepseek-ai/dsh-subagent/depth + */ +/** + * Read an agent's delegation depth, treating absence as top-level depth zero. + * The persisted session header is authoritative and monotone: runtime + * `AgentOptions.subagentDepth` may DEEPEN the count but can never lower it — + * a resumed child arrives with fresh options, and counting it from zero would + * let it delegate as if it were top-level. + * @param agent - the agent whose header and options carry the depth. + * @returns its non-negative safe-integer depth. + * @throws if the runtime `AgentOptions.subagentDepth` is not a non-negative safe integer. + */ +export function delegationDepthOf(agent) { + const runtime = agent.options.subagentDepth; + if (runtime !== undefined && (!Number.isSafeInteger(runtime) || runtime < 0 || Object.is(runtime, -0))) { + throw new TypeError('agent subagentDepth must be a non-negative safe integer'); + } + // The header value was validated at the session boundary (creation and + // persistence load both construct through the store). + return Math.max(agent.session.header.delegationDepth ?? 0, runtime ?? 0); +} +/** + * Reject a recursion cap that cannot represent an exact delegation depth. + * @param maxDepth - the optional runtime value to validate. + */ +export function assertSubagentMaxDepth(maxDepth) { + if (maxDepth !== undefined && (typeof maxDepth !== 'number' + || !Number.isSafeInteger(maxDepth) + || maxDepth < 0 + || Object.is(maxDepth, -0))) { + throw new TypeError('subagent maxDepth must be a non-negative safe integer'); + } +} +//# sourceMappingURL=depth.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.d.ts new file mode 100644 index 0000000..b608916 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.d.ts @@ -0,0 +1,21 @@ +/** + * Seeding of a continuable child's durable descriptor event: the model-hidden + * record of the child's declared composition before its first request, so a + * later cold resume can reconstruct it from its own log. + * + * @module @deepseek-ai/dsh-subagent/descriptor-seed + */ +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'; +import type { SubagentDescriptorData } from './descriptor.ts'; +/** + * Build the child's creation seed: any inherited parent-history prefix followed + * by one model-hidden, between-turn `descriptor` event. Staging through a + * `Session` assigns the sequence number and enforces the same lossless-JSON + * rules the durable log does. + * @param childId - the reserved child session id the staged log belongs to. + * @param seed - the inherited completed-turn prefix, or `undefined` for a fresh child. + * @param descriptor - the snapshotted composition record to persist. + * @returns the complete seed events, contiguous from sequence zero. + */ +export declare function seedDescriptorTurn(childId: SessionId, seed: readonly SessionEvent[] | undefined, descriptor: SubagentDescriptorData): SessionEvent[]; +//# sourceMappingURL=descriptor-seed.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.js new file mode 100644 index 0000000..6a32f51 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.js @@ -0,0 +1,24 @@ +/** + * Seeding of a continuable child's durable descriptor event: the model-hidden + * record of the child's declared composition before its first request, so a + * later cold resume can reconstruct it from its own log. + * + * @module @deepseek-ai/dsh-subagent/descriptor-seed + */ +import { Session } from '@deepseek-ai/dsh-session'; +/** + * Build the child's creation seed: any inherited parent-history prefix followed + * by one model-hidden, between-turn `descriptor` event. Staging through a + * `Session` assigns the sequence number and enforces the same lossless-JSON + * rules the durable log does. + * @param childId - the reserved child session id the staged log belongs to. + * @param seed - the inherited completed-turn prefix, or `undefined` for a fresh child. + * @param descriptor - the snapshotted composition record to persist. + * @returns the complete seed events, contiguous from sequence zero. + */ +export function seedDescriptorTurn(childId, seed, descriptor) { + const staged = Session.create(childId, seed); + staged.append('subagent/descriptor', descriptor); + return [...staged.events]; +} +//# sourceMappingURL=descriptor-seed.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.d.ts new file mode 100644 index 0000000..9e34084 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.d.ts @@ -0,0 +1,139 @@ +/** + * The durable subagent-child descriptor: the versioned, model-hidden + * `subagent/descriptor` session event that identifies every session-backed + * subagent and records whether it is one-shot or continuable. Continuable + * descriptors additionally preserve the declared composition required for + * cold resume. Providers append it turn-enclosed in the child's initial turn. + * + * The descriptor deliberately snapshots explicit fields rather than the + * merge-extensible `AgentOptions` object: an unrelated extension value cannot + * make continuation fail merely because it is not JSON, and later composition + * inputs require a deliberate {@link SUBAGENT_DESCRIPTOR_VERSION} change. It + * omits `subagentDepth` — cold resume trusts the persisted header's + * `delegationDepth` as the monotone floor — and `outputSchema`, which belongs + * to one activation's result contract rather than durable child composition. + * Per-activation knobs such as `maxTokens` are omitted for the same reason as + * `outputSchema`: they budget one activation. Cold resume requires the exact + * live parent for authorization but reconstructs child options only from the + * durable descriptor, so it neither restores the prior budget nor inherits + * the parent's current one; the resumed route's defaults apply instead. + * + * @module @deepseek-ai/dsh-subagent/descriptor + */ +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +import type { ToolRestriction } from '@deepseek-ai/dsh-tools'; +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * Durable identity and lifecycle mode of a session-backed subagent child, + * appended once by the establishing provider inside the child's initial + * turn, before its first request. Continuable records also carry their + * resumable composition. Log-only: it carries no `surfaceOp`, never enters + * model history, and survives compaction. + */ + 'subagent/descriptor': SubagentDescriptorData; + } +} +/** + * The current descriptor format version, stamped into every appended + * `subagent/descriptor` event and required verbatim by {@link foldSubagentDescriptor}. + * Supporting another composition input is a deliberate version change, never + * an implicit extra field. + */ +export declare const SUBAGENT_DESCRIPTOR_VERSION = 2; +/** Fields shared by every supported `subagent/descriptor` payload. */ +interface SubagentDescriptorBase { + /** Descriptor format version ({@link SUBAGENT_DESCRIPTOR_VERSION}). */ + readonly version: number; + /** Whether the child is a terminal one-shot run or a resumable conversation. */ + readonly mode: 'one-shot' | 'continuable'; + /** The `ctx.subagents` provider name that established the child. */ + readonly provider: string; +} +/** A session-backed subagent that cannot be cold-resumed after its run. */ +export interface OneShotSubagentDescriptorData extends SubagentDescriptorBase { + readonly mode: 'one-shot'; + /** + * The initial delegation's short `description`, kept as the child's durable + * creation label so enumeration can identify the conversation without + * replaying parent tool results or exposing the child prompt. + */ + readonly label?: string; +} +/** A session-backed subagent whose declared composition supports cold resume. */ +export interface ContinuableSubagentDescriptorData extends SubagentDescriptorBase { + readonly mode: 'continuable'; + /** The initial delegation's short `description`, used for durable enumeration. */ + readonly label: string; + /** Resolved child `agentOptions.provider`, when one was declared. */ + readonly agentProvider?: string; + /** Resolved child `agentOptions.model`, when one was declared. */ + readonly agentModel?: string; + /** Per-child persona that shadows the deployment persona on resume. */ + readonly persona?: string; + /** Child tool scoping reapplied on resume. */ + readonly toolFilter?: ToolRestriction; +} +/** The supported durable subagent identity and optional continuation composition. */ +export type SubagentDescriptorData = OneShotSubagentDescriptorData | ContinuableSubagentDescriptorData; +/** Fields shared by descriptor snapshot inputs. */ +interface SubagentDescriptorInputBase { + /** Whether the child is a terminal one-shot run or a resumable conversation. */ + readonly mode: 'one-shot' | 'continuable'; + /** The `ctx.subagents` provider name that will establish the child. */ + readonly provider: string; +} +/** Input for a one-shot child's durable identity. */ +export interface OneShotSubagentDescriptorInput extends SubagentDescriptorInputBase { + readonly mode: 'one-shot'; + /** Optional initial delegation `description` used as the durable creation label. */ + readonly label?: string; +} +/** Input for a continuable child's durable identity and resumable composition. */ +export interface ContinuableSubagentDescriptorInput extends SubagentDescriptorInputBase { + readonly mode: 'continuable'; + /** Initial delegation `description` used for durable enumeration. */ + readonly label: string; + /** Requested child `agentOptions.provider`. */ + readonly agentProvider?: string; + /** Requested child `agentOptions.model`. */ + readonly agentModel?: string; + /** Requested per-child persona. */ + readonly persona?: string; + /** Requested child tool scoping. */ + readonly toolFilter?: ToolRestriction; +} +/** Inputs {@link snapshotSubagentDescriptor} validates and detaches. */ +export type SubagentDescriptorInput = OneShotSubagentDescriptorInput | ContinuableSubagentDescriptorInput; +/** + * Validate and detach descriptor inputs into the durable payload, before any + * Task or provider work begins — the same detached lossless-JSON boundary the + * session log itself enforces, applied early so a synchronous validation + * failure rejects the tool call without creating a Task. + * @param input - the caller-collected composition fields. + * @returns the versioned, detached descriptor payload. + * @throws when a field is not losslessly JSON-serializable. + */ +export declare function snapshotSubagentDescriptor(input: OneShotSubagentDescriptorInput): OneShotSubagentDescriptorData; +/** + * Validate and detach a continuable descriptor input. + * @param input - the caller-collected continuable composition fields. + * @returns the versioned, detached continuable descriptor payload. + * @throws when a field is not losslessly JSON-serializable. + */ +export declare function snapshotSubagentDescriptor(input: ContinuableSubagentDescriptorInput): ContinuableSubagentDescriptorData; +/** + * Fold a persisted child log to its supported descriptor. The first + * `subagent/descriptor` event is authoritative — the establishing provider + * appends exactly one, so a later same-type event cannot rewrite the declared + * composition. + * @param events - the loaded child session events. + * @returns the descriptor, or `undefined` when the log has none or its + * version is not {@link SUBAGENT_DESCRIPTOR_VERSION} (the child cannot be + * classified by this runtime). + * @throws when a current-version persisted payload does not match its complete + * declared schema. + */ +export declare function foldSubagentDescriptor(events: readonly SessionEvent[]): SubagentDescriptorData | undefined; +export {}; +//# sourceMappingURL=descriptor.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.js new file mode 100644 index 0000000..52e9081 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.js @@ -0,0 +1,189 @@ +/** + * The durable subagent-child descriptor: the versioned, model-hidden + * `subagent/descriptor` session event that identifies every session-backed + * subagent and records whether it is one-shot or continuable. Continuable + * descriptors additionally preserve the declared composition required for + * cold resume. Providers append it turn-enclosed in the child's initial turn. + * + * The descriptor deliberately snapshots explicit fields rather than the + * merge-extensible `AgentOptions` object: an unrelated extension value cannot + * make continuation fail merely because it is not JSON, and later composition + * inputs require a deliberate {@link SUBAGENT_DESCRIPTOR_VERSION} change. It + * omits `subagentDepth` — cold resume trusts the persisted header's + * `delegationDepth` as the monotone floor — and `outputSchema`, which belongs + * to one activation's result contract rather than durable child composition. + * Per-activation knobs such as `maxTokens` are omitted for the same reason as + * `outputSchema`: they budget one activation. Cold resume requires the exact + * live parent for authorization but reconstructs child options only from the + * durable descriptor, so it neither restores the prior budget nor inherits + * the parent's current one; the resumed route's defaults apply instead. + * + * @module @deepseek-ai/dsh-subagent/descriptor + */ +import { snapshotJsonValue } from '@deepseek-ai/dsh-session'; +/** + * The current descriptor format version, stamped into every appended + * `subagent/descriptor` event and required verbatim by {@link foldSubagentDescriptor}. + * Supporting another composition input is a deliberate version change, never + * an implicit extra field. + */ +export const SUBAGENT_DESCRIPTOR_VERSION = 2; +const DESCRIPTOR_BASE_KEYS = [ + 'version', + 'mode', + 'provider', + 'label', +]; +const ONE_SHOT_DESCRIPTOR_KEYS = new Set(DESCRIPTOR_BASE_KEYS); +const CONTINUABLE_DESCRIPTOR_KEYS = new Set([ + ...DESCRIPTOR_BASE_KEYS, + 'agentProvider', + 'agentModel', + 'persona', + 'toolFilter', +]); +const TOOL_FILTER_KEYS = new Set(['allow', 'deny']); +/** Whether a persisted JSON value is an object record. */ +function isRecord(value) { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} +/** Reject fields outside one versioned record's declared schema. */ +function assertKnownKeys(value, keys, path) { + const unknown = Object.keys(value).find(key => !keys.has(key)); + if (unknown !== undefined) { + throw new Error(`persisted subagent descriptor ${path} has unknown field "${unknown}"`); + } +} +/** Read one optional string field from a persisted descriptor record. */ +function optionalString(value, key) { + if (!Object.hasOwn(value, key)) + return undefined; + const field = value[key]; + if (typeof field !== 'string') { + throw new Error(`persisted subagent descriptor ${key} must be a string`); + } + return field; +} +/** Read one optional string-array field from a persisted tool restriction. */ +function optionalStringArray(value, key) { + if (!Object.hasOwn(value, key)) + return undefined; + const field = value[key]; + if (!Array.isArray(field)) { + throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`); + } + const items = field; + if (items.some(item => typeof item !== 'string')) { + throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`); + } + return items; +} +/** Validate and reconstruct a persisted tool restriction. */ +function parseToolFilter(value) { + if (!isRecord(value)) { + throw new Error('persisted subagent descriptor toolFilter must be an object'); + } + assertKnownKeys(value, TOOL_FILTER_KEYS, 'toolFilter'); + const allow = optionalStringArray(value, 'allow'); + const deny = optionalStringArray(value, 'deny'); + if (allow === undefined && deny === undefined) { + throw new Error('persisted subagent descriptor toolFilter must declare allow and/or deny'); + } + return { + ...allow !== undefined ? { allow } : {}, + ...deny !== undefined ? { deny } : {}, + }; +} +/** Validate one persisted descriptor payload for the current runtime. */ +function parseSubagentDescriptor(value) { + if (!isRecord(value)) { + throw new Error('persisted subagent descriptor payload must be an object'); + } + const version = value['version']; + if (typeof version !== 'number') { + throw new Error('persisted subagent descriptor version must be a number'); + } + if (version !== SUBAGENT_DESCRIPTOR_VERSION) + return undefined; + const mode = value['mode']; + if (mode !== 'one-shot' && mode !== 'continuable') { + throw new Error('persisted subagent descriptor mode must be "one-shot" or "continuable"'); + } + assertKnownKeys(value, mode === 'one-shot' ? ONE_SHOT_DESCRIPTOR_KEYS : CONTINUABLE_DESCRIPTOR_KEYS, 'payload'); + const provider = value['provider']; + if (typeof provider !== 'string') { + throw new Error('persisted subagent descriptor provider must be a string'); + } + if (mode === 'one-shot') { + const label = optionalString(value, 'label'); + return { + version: SUBAGENT_DESCRIPTOR_VERSION, + mode, + provider, + ...label !== undefined ? { label } : {}, + }; + } + const label = value['label']; + if (typeof label !== 'string') { + throw new Error('persisted subagent descriptor label must be a string'); + } + const agentProvider = optionalString(value, 'agentProvider'); + const agentModel = optionalString(value, 'agentModel'); + const persona = optionalString(value, 'persona'); + const toolFilter = Object.hasOwn(value, 'toolFilter') + ? parseToolFilter(value['toolFilter']) + : undefined; + return { + version: SUBAGENT_DESCRIPTOR_VERSION, + mode, + provider, + label, + ...agentProvider !== undefined ? { agentProvider } : {}, + ...agentModel !== undefined ? { agentModel } : {}, + ...persona !== undefined ? { persona } : {}, + ...toolFilter !== undefined ? { toolFilter } : {}, + }; +} +export function snapshotSubagentDescriptor(input) { + const candidate = input.mode === 'one-shot' + ? { + version: SUBAGENT_DESCRIPTOR_VERSION, + mode: input.mode, + provider: input.provider, + ...input.label !== undefined ? { label: input.label } : {}, + } + : { + version: SUBAGENT_DESCRIPTOR_VERSION, + mode: input.mode, + provider: input.provider, + label: input.label, + ...input.agentProvider !== undefined ? { agentProvider: input.agentProvider } : {}, + ...input.agentModel !== undefined ? { agentModel: input.agentModel } : {}, + ...input.persona !== undefined ? { persona: input.persona } : {}, + ...input.toolFilter !== undefined ? { toolFilter: input.toolFilter } : {}, + }; + const snapshot = snapshotJsonValue(candidate); + if (snapshot === undefined) { + throw new Error('subagent descriptor is not losslessly JSON-serializable'); + } + return snapshot; +} +/** + * Fold a persisted child log to its supported descriptor. The first + * `subagent/descriptor` event is authoritative — the establishing provider + * appends exactly one, so a later same-type event cannot rewrite the declared + * composition. + * @param events - the loaded child session events. + * @returns the descriptor, or `undefined` when the log has none or its + * version is not {@link SUBAGENT_DESCRIPTOR_VERSION} (the child cannot be + * classified by this runtime). + * @throws when a current-version persisted payload does not match its complete + * declared schema. + */ +export function foldSubagentDescriptor(events) { + const event = events.find((candidate) => candidate.type === 'subagent/descriptor'); + if (event === undefined) + return undefined; + return parseSubagentDescriptor(event.data); +} +//# sourceMappingURL=descriptor.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.d.ts new file mode 100644 index 0000000..0be7ce3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.d.ts @@ -0,0 +1,11 @@ +/** + * Typed failures shared by subagent service and provider operations. + * + * @module @deepseek-ai/dsh-subagent + */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +/** Typed failure for the subagent seam. */ +export declare class SubagentError extends HarnessError { + constructor(message: string, code: string, options?: ErrorOptions); +} +//# sourceMappingURL=error.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.js new file mode 100644 index 0000000..2ba567e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.js @@ -0,0 +1,14 @@ +/** + * Typed failures shared by subagent service and provider operations. + * + * @module @deepseek-ai/dsh-subagent + */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +/** Typed failure for the subagent seam. */ +export class SubagentError extends HarnessError { + constructor(message, code, options) { + super(message, code, options); + this.name = 'SubagentError'; + } +} +//# sourceMappingURL=error.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.d.ts new file mode 100644 index 0000000..62b5cad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.d.ts @@ -0,0 +1,279 @@ +/** + * Service Definition for the subagent capability seam (`ctx.subagents`): a named-provider registry plus a + * capability-validating asynchronous start API. Providers establish a + * child before returning its run, so fulfillment is the single publication and + * ownership-transfer boundary. + * + * Unlike the bash seam (one executor per context, second load throws), MULTIPLE + * providers coexist here: each registers under a unique name and a caller picks + * one by name. The shape mirrors the LLM adapter registry + * (`LlmRuntime.registerAdapter`), not the single-service bash executor. + * + * This package owns the Service Definition role of the capability seam. Service Providers + * (`@deepseek-ai/dsh-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing + * consumer (`@deepseek-ai/dsh-tool-subagent`) are separate packages. + * + * Public operations express caller intent: `start` returns one published owned + * one-shot run, `startContinuable` establishes a durable continuable child, and + * `followup` delivers later content without exposing whether the child is + * resident. Continuable children never become a {@link SubagentRun}: the + * continuation manager holds their `AgentHandle` directly and orders every turn + * through the child's own inbox, so providers contribute only the detached + * creation spec and see no handle, turn, or teardown. Child and descendant + * discovery read the live session store and optional session persistence + * directly and do not require that continuation runtime. + * + * Same-process providers are trusted typed collaborators. Requests, provider + * descriptors, results, and lifecycle payloads are borrowed immutable values; + * serialization and hostile-input validation belong at real process, worker, + * persistence, and model boundaries. + * + * @module @deepseek-ai/dsh-subagent + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { Scoped } from '@deepseek-ai/dsh-scope'; +import type { ContentBlock, MessageId } from '@deepseek-ai/dsh-llm'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +import type { SubagentProvider, SubagentRun, SubagentRunEndInfo, SubagentRunInfo, SubagentStartRequest } from './types.ts'; +import type { ContinuableStart, ContinuableStartSpec, SubagentFollowupOptions, SubagentInterruptAuthority, SubagentReportOptions } from './continuation.ts'; +import type { ContinuableSetupContribution } from './activation-setup-registry.ts'; +import type { SubagentDescendantListEntry, SubagentListEntry } from './list-children.ts'; +export * from './out-of-process.ts'; +export { AssistantOutputFold, finalAssistantOutput } from './assistant-output.ts'; +export { SubagentRunId } from './types.ts'; +export type { ContinuableCreateRequest, ContinuableCreateSpec, ResolvedSubagentStartRequest, SubagentCapabilities, SubagentProvider, SubagentResult, SubagentRun, SubagentStartRequest, SubagentStopReason, SubagentStopReasonMap, } from './types.ts'; +export { foldSubagentDescriptor, snapshotSubagentDescriptor, SUBAGENT_DESCRIPTOR_VERSION, } from './descriptor.ts'; +export type { ContinuableSubagentDescriptorData, ContinuableSubagentDescriptorInput, OneShotSubagentDescriptorData, OneShotSubagentDescriptorInput, SubagentDescriptorData, SubagentDescriptorInput, } from './descriptor.ts'; +export { seedDescriptorTurn } from './descriptor-seed.ts'; +export { SubagentError } from './error.ts'; +export { settleRun } from './run-settlement.ts'; +export { assertSubagentMaxDepth, delegationDepthOf } from './depth.ts'; +export { appendDelegatedPolicyOverrides, applyChildComposition, captureDelegatedPolicyOverrides, childSessionMeta, resolveChildAgentOptions, resolveChildDepth, SubagentDepthError, } from './child-agent.ts'; +export type { ChildComposition, DelegatedPolicyOverrides } from './child-agent.ts'; +export type { ContinuableStart, ContinuableStartSpec, CoordinatorMessageSource, SubagentFollowupOptions, SubagentInterruptAuthority, SubagentReportDelivery, SubagentReportMessageSource, SubagentReportOptions, SubagentSettledMessageSource, } from './continuation.ts'; +export type { ContinuableSetupContribution } from './activation-setup-registry.ts'; +export type { SubagentDescendantListEntry, SubagentListEntry } from './list-children.ts'; +export type { SubagentRunEndInfo, SubagentRunInfo } from './types.ts'; +export type { SubagentIdentityProjection, SubagentTimingProjection } from './projection-types.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + subagents: SubagentRuntime; + } + interface Events { + /** + * A provider became resolvable in the registry. + * @param provider - the registered provider. + * @mode emit + */ + 'subagent/provider-added'(provider: SubagentProvider): void; + /** + * A provider left the registry. Accepted runs remain holder-owned. + * @param name - the provider name that no longer resolves. + * @mode emit + */ + 'subagent/provider-removed'(name: string): void; + /** + * A provider established a published child. For in-process providers, + * `ctx.agents.get(info.id)` resolves during this notification. + * Scope-filtered dispatch keys the carrier by the delegating parent, so a + * parent-scoped listener observes only its own delegations. Paired with + * `subagent/end`. + * @param info - the provider and published child identity. + * @dshScopeScan unsupported + * @mode emit + */ + 'subagent/start'(this: Scoped, info: SubagentRunInfo): void; + /** + * A published child settled. Scope-filtered dispatch uses the same delegating + * parent carrier as `subagent/start`, so the lifecycle pair reaches the + * same scoped audience. + * @param info - the run identity and terminal outcome. + * @dshScopeScan unsupported + * @mode emit + */ + 'subagent/end'(this: Scoped, info: SubagentRunEndInfo): void; + } +} +/** Named provider registry with one-shot runs, durable discovery, and continuable-child operations. */ +export declare class SubagentRuntime extends Service { + private providers; + private continuations; + /** Deployment contributions composed into unpublished continuable children. */ + private readonly setupRegistry; + /** + * The contained lifecycle-edge publisher. Built here because scoped dispatch + * keys its carrier by this exact service instance, whose own context filter + * composes into the carrier. + */ + private readonly emitLifecycle; + constructor(ctx: Context); + /** + * Establish one durable continuable child and deliver its initial prompt. + * Resolves when the child's inbox accepts that prompt, without waiting for the + * turn to start or for the message to reach the Session log; any earlier + * failure rejects with no ids and rolls back the child entirely. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted prompt's message id. + * @throws when continuation services are unavailable or materialization fails. + */ + startContinuable(spec: ContinuableStartSpec): Promise; + /** + * Deliver one later message to a continuable child as its next FIFO turn. A + * resident child's Agent inbox accepts it directly (waking a `waiting` + * Activation), while an absent one is cold-resumed from its persisted + * Session. The Agent inbox is the only queue, so every accepted message has + * one observable order. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - durable child session id. + * @param content - user-role content to deliver. + * @param options - the message source fields and caller cancellation, which stops the + * operation only before inbox acceptance. + * @returns the accepted message's inbox id. + * @throws when continuation services are unavailable, parent authority is + * rejected, or the message was not admitted. + */ + followup(parent: Agent, childId: SessionId, content: ContentBlock[], options: SubagentFollowupOptions): Promise; + /** + * Interrupt one live continuable child's current turn under a human parent + * address or an exact live ancestor Agent. Fire-and-return: the cancel + * signal is issued before this returns, but the target may keep running + * until it observes the signal. Unclaimed pending inbox work, the Activation, + * and published descendants are preserved; claimed work is not requeued. + * Once the interrupted driver is idle, a waking send resumes the parked FIFO + * queue. An absent target — including a one-shot or unknown id — + * is an accepted no-op, as is a manager-less composition, which cannot own a + * live Activation. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the authority does not own the + * live target. + */ + interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void; + /** + * Deliver selected content from one live continuable child to its durable + * direct parent. The child is the authority credential; callers cannot name a + * recipient. Reporting does not conclude the child's turn or Activation. + * @param child - exact live reporting child. + * @param content - selected model-facing content. + * @param options - parent scheduling and pre-acceptance cancellation. + * @returns the stable identity of the parent-accepted message. + * @throws when continuation services are unavailable, sender authorization + * fails, or the direct parent is not live. + */ + reportFrom(child: Agent, content: ContentBlock[], options: SubagentReportOptions): Promise; + /** + * Compose one deployment capability into every continuable child's + * unpublished creation context on fresh creation and cold resume. Grants wait + * for the next Activation; removing the contribution revokes every resident + * installation immediately. + * @param contribution - synchronous child-scope installer. + * @returns the exact Cordis effect disposer. + */ + registerContinuableSetup(contribution: ContinuableSetupContribution): () => void; + /** + * Close continuable admission below exact live parent Agents, stop only their + * visible descendant Activations synchronously, then await admitted scoped + * materializations and release those forests child-first. The scoped cutoff + * lasts until each exact parent leaves the registry; unrelated parent trees + * remain live. + * @param parents - exact host-owned parent Agents entering teardown. + * @returns once every retained descendant Activation released its `AgentHandle`. + * @throws an aggregate error after all branches settle when any failed. + */ + drainContinuableDescendants(parents: readonly Agent[]): Promise; + /** + * Enumerate the parent's direct session-backed subagents without loading or + * resuming an Agent and without any query service: the listing merges the live + * session store with optional session persistence (live-preferred) and + * serves each child's durable mode/label from the registered `subagent` + * projection unit down a three-rung ladder — the registry's watermark + * snapshot for a live child; for a cold one, a durable projection-cache + * row when the optional cache serves an own-suffix identity (its `seq` + * gate proves the value postdates the fork seed, where a child's own + * descriptor is immutable once appended), else one persistence inspection + * folded through the registry. The + * projection fold is the single classification authority; per-child + * diagnostics relay a fold that served no identity or a failed inspection, + * never a list-time descriptor parse. Absent persistence, enumeration is + * live-only (a cold child cannot be resumed then either, so its absence is + * capability absence, not an error). This service consults no Agent + * registrations, Activations, or providers. + * + * Every persistence read receives `signal`, and the listing rechecks + * cancellation around each of those awaits. Read rejections that settle + * after an abort become a stable `SubagentError` with code `CANCELLED`. + * @param parentSessionId - parent session whose direct children are listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-child diagnostics ordered by `createdAt`, then id. + * @throws {@link SubagentError} when the projection registry or the session + * store is not mounted, or the caller cancels the listing. + */ + listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Enumerate the root's complete session-backed subagent tree in stable + * pre-order from one live-preferred corpus, without loading or resuming an + * Agent. Ordinary sessions and one-shot children remain traversal nodes so + * continuable descendants below them are discovered; each returned entry + * adds its durable `parentId` and root-relative `depth`. Identity resolution, + * diagnostics, optional persistence, and cancellation follow the same + * projection-backed contract as {@link listChildren}. + * @param rootSessionId - session whose complete descendant tree is listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-candidate diagnostics with tree position, in + * stable pre-order. + * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + */ + listDescendants(rootSessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Register a provider under its name. Registration is effect-scoped and HMR + * safe; removing a provider blocks new starts but does not revoke runs that + * were already returned to their holders. + * @param provider - the trusted provider implementation. + * @returns the exact Cordis effect disposer. + */ + registerProvider(provider: SubagentProvider): () => void; + /** + * Look up a provider by name. + * @param name - the provider name. + * @returns the provider, or undefined when absent. + */ + getProvider(name: string): SubagentProvider | undefined; + /** + * List registered provider names in insertion order. + * @returns the registered names. + */ + list(): string[]; + /** + * Establish a published child on the named provider. Capability and semantic + * checks run before delegation. Provider ownership lasts until its promise + * fulfills; a rejection therefore has no run for the caller to dispose and + * emits no run lifecycle events. Post-publication turn and infrastructure + * failures settle through the returned run. + * @param name - the provider to use. + * @param request - child label, prompt, parent, signal, and optional capabilities. + * @returns the published holder-owned run. + */ + start(name: string, request: SubagentStartRequest): Promise; + /** + * Resolve one provider's detached continuable-creation contribution. Method + * presence on the provider IS the capability, so a provider without it is + * rejected before the manager reserves any child resources. + */ + private prepareContinuable; + /** Look up a provider for dispatch or fail loud. */ + private expectProvider; + /** Resolve the optional continuable-subagent manager or fail loud. */ + private requireContinuations; + /** + * Build the lifecycle observer for one continuable Activation's residency + * epoch, so the manager publishes its edges without owning event dispatch. + */ + private observeActivation; + /** Reject the first requested capability that the provider lacks. */ + private assertCapabilities; +} +export default SubagentRuntime; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.js new file mode 100644 index 0000000..e61f852 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.js @@ -0,0 +1,339 @@ +/** + * Service Definition for the subagent capability seam (`ctx.subagents`): a named-provider registry plus a + * capability-validating asynchronous start API. Providers establish a + * child before returning its run, so fulfillment is the single publication and + * ownership-transfer boundary. + * + * Unlike the bash seam (one executor per context, second load throws), MULTIPLE + * providers coexist here: each registers under a unique name and a caller picks + * one by name. The shape mirrors the LLM adapter registry + * (`LlmRuntime.registerAdapter`), not the single-service bash executor. + * + * This package owns the Service Definition role of the capability seam. Service Providers + * (`@deepseek-ai/dsh-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing + * consumer (`@deepseek-ai/dsh-tool-subagent`) are separate packages. + * + * Public operations express caller intent: `start` returns one published owned + * one-shot run, `startContinuable` establishes a durable continuable child, and + * `followup` delivers later content without exposing whether the child is + * resident. Continuable children never become a {@link SubagentRun}: the + * continuation manager holds their `AgentHandle` directly and orders every turn + * through the child's own inbox, so providers contribute only the detached + * creation spec and see no handle, turn, or teardown. Child and descendant + * discovery read the live session store and optional session persistence + * directly and do not require that continuation runtime. + * + * Same-process providers are trusted typed collaborators. Requests, provider + * descriptors, results, and lifecycle payloads are borrowed immutable values; + * serialization and hostile-input validation belong at real process, worker, + * persistence, and model boundaries. + * + * @module @deepseek-ai/dsh-subagent + */ +import { Service } from '@deepseek-ai/cordis'; +import { scopeTarget } from '@deepseek-ai/dsh-scope'; +import { assertObjectJsonSchema } from '@deepseek-ai/dsh-tools'; +import { SubagentError } from "./error.js"; +import { assertSubagentMaxDepth } from "./depth.js"; +import { createActivationObserver, createLifecycleEmitter, observeRun } from "./lifecycle.js"; +import SubagentContinuationManager from "./continuation.js"; +import SubagentActivationSetupRegistry from "./activation-setup-registry.js"; +import { listChildren as listSubagentChildren, listDescendants as listSubagentDescendants } from "./list-children.js"; +import { snapshotSubagentDescriptor } from "./descriptor.js"; +import { subagentIdentityProjectionDefinition, subagentTimingProjectionDefinition } from "./projection.js"; +export * from "./out-of-process.js"; +export { AssistantOutputFold, finalAssistantOutput } from "./assistant-output.js"; +export { SubagentRunId } from "./types.js"; +export { foldSubagentDescriptor, snapshotSubagentDescriptor, SUBAGENT_DESCRIPTOR_VERSION, } from "./descriptor.js"; +export { seedDescriptorTurn } from "./descriptor-seed.js"; +export { SubagentError } from "./error.js"; +export { settleRun } from "./run-settlement.js"; +export { assertSubagentMaxDepth, delegationDepthOf } from "./depth.js"; +export { appendDelegatedPolicyOverrides, applyChildComposition, captureDelegatedPolicyOverrides, childSessionMeta, resolveChildAgentOptions, resolveChildDepth, SubagentDepthError, } from "./child-agent.js"; +/** Named provider registry with one-shot runs, durable discovery, and continuable-child operations. */ +export class SubagentRuntime extends Service { + providers = new Map(); + continuations; + /** Deployment contributions composed into unpublished continuable children. */ + setupRegistry = new SubagentActivationSetupRegistry(); + /** + * The contained lifecycle-edge publisher. Built here because scoped dispatch + * keys its carrier by this exact service instance, whose own context filter + * composes into the carrier. + */ + emitLifecycle; + constructor(ctx) { + super(ctx, 'subagents'); + this.emitLifecycle = createLifecycleEmitter(this.ctx, parent => scopeTarget(this, parent)); + ctx.inject(['agents'], (childCtx) => { + const manager = new SubagentContinuationManager(childCtx, { + prepareContinuable: (name, request) => this.prepareContinuable(name, request), + observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent), + }, this.setupRegistry); + this.continuations = manager; + childCtx.effect(() => () => { + /* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */ + if (this.continuations === manager) + this.continuations = undefined; + }, 'subagents.continuationBinding()'); + }); + ctx.inject(['sessionProjections'], (projectionCtx) => { + projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition); + projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition); + }); + } + /** + * Establish one durable continuable child and deliver its initial prompt. + * Resolves when the child's inbox accepts that prompt, without waiting for the + * turn to start or for the message to reach the Session log; any earlier + * failure rejects with no ids and rolls back the child entirely. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted prompt's message id. + * @throws when continuation services are unavailable or materialization fails. + */ + async startContinuable(spec) { + return this.requireContinuations().startContinuable(spec); + } + /** + * Deliver one later message to a continuable child as its next FIFO turn. A + * resident child's Agent inbox accepts it directly (waking a `waiting` + * Activation), while an absent one is cold-resumed from its persisted + * Session. The Agent inbox is the only queue, so every accepted message has + * one observable order. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - durable child session id. + * @param content - user-role content to deliver. + * @param options - the message source fields and caller cancellation, which stops the + * operation only before inbox acceptance. + * @returns the accepted message's inbox id. + * @throws when continuation services are unavailable, parent authority is + * rejected, or the message was not admitted. + */ + async followup(parent, childId, content, options) { + return this.requireContinuations().followup(parent, childId, content, options); + } + /** + * Interrupt one live continuable child's current turn under a human parent + * address or an exact live ancestor Agent. Fire-and-return: the cancel + * signal is issued before this returns, but the target may keep running + * until it observes the signal. Unclaimed pending inbox work, the Activation, + * and published descendants are preserved; claimed work is not requeued. + * Once the interrupted driver is idle, a waking send resumes the parked FIFO + * queue. An absent target — including a one-shot or unknown id — + * is an accepted no-op, as is a manager-less composition, which cannot own a + * live Activation. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the authority does not own the + * live target. + */ + interrupt(targetSessionId, authority) { + this.continuations?.interrupt(targetSessionId, authority); + } + /** + * Deliver selected content from one live continuable child to its durable + * direct parent. The child is the authority credential; callers cannot name a + * recipient. Reporting does not conclude the child's turn or Activation. + * @param child - exact live reporting child. + * @param content - selected model-facing content. + * @param options - parent scheduling and pre-acceptance cancellation. + * @returns the stable identity of the parent-accepted message. + * @throws when continuation services are unavailable, sender authorization + * fails, or the direct parent is not live. + */ + async reportFrom(child, content, options) { + return this.requireContinuations().reportFrom(child, content, options); + } + /** + * Compose one deployment capability into every continuable child's + * unpublished creation context on fresh creation and cold resume. Grants wait + * for the next Activation; removing the contribution revokes every resident + * installation immediately. + * @param contribution - synchronous child-scope installer. + * @returns the exact Cordis effect disposer. + */ + registerContinuableSetup(contribution) { + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity + return this.ctx.effect(() => this.setupRegistry.register(contribution), 'subagents.registerContinuableSetup()'); + } + /** + * Close continuable admission below exact live parent Agents, stop only their + * visible descendant Activations synchronously, then await admitted scoped + * materializations and release those forests child-first. The scoped cutoff + * lasts until each exact parent leaves the registry; unrelated parent trees + * remain live. + * @param parents - exact host-owned parent Agents entering teardown. + * @returns once every retained descendant Activation released its `AgentHandle`. + * @throws an aggregate error after all branches settle when any failed. + */ + async drainContinuableDescendants(parents) { + const manager = this.continuations; + // Absent continuation services means nothing was ever materialized. + if (manager === undefined) + return; + await manager.drainDescendants(parents); + } + /** + * Enumerate the parent's direct session-backed subagents without loading or + * resuming an Agent and without any query service: the listing merges the live + * session store with optional session persistence (live-preferred) and + * serves each child's durable mode/label from the registered `subagent` + * projection unit down a three-rung ladder — the registry's watermark + * snapshot for a live child; for a cold one, a durable projection-cache + * row when the optional cache serves an own-suffix identity (its `seq` + * gate proves the value postdates the fork seed, where a child's own + * descriptor is immutable once appended), else one persistence inspection + * folded through the registry. The + * projection fold is the single classification authority; per-child + * diagnostics relay a fold that served no identity or a failed inspection, + * never a list-time descriptor parse. Absent persistence, enumeration is + * live-only (a cold child cannot be resumed then either, so its absence is + * capability absence, not an error). This service consults no Agent + * registrations, Activations, or providers. + * + * Every persistence read receives `signal`, and the listing rechecks + * cancellation around each of those awaits. Read rejections that settle + * after an abort become a stable `SubagentError` with code `CANCELLED`. + * @param parentSessionId - parent session whose direct children are listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-child diagnostics ordered by `createdAt`, then id. + * @throws {@link SubagentError} when the projection registry or the session + * store is not mounted, or the caller cancels the listing. + */ + listChildren(parentSessionId, signal) { + return listSubagentChildren(this.ctx, parentSessionId, signal); + } + /** + * Enumerate the root's complete session-backed subagent tree in stable + * pre-order from one live-preferred corpus, without loading or resuming an + * Agent. Ordinary sessions and one-shot children remain traversal nodes so + * continuable descendants below them are discovered; each returned entry + * adds its durable `parentId` and root-relative `depth`. Identity resolution, + * diagnostics, optional persistence, and cancellation follow the same + * projection-backed contract as {@link listChildren}. + * @param rootSessionId - session whose complete descendant tree is listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-candidate diagnostics with tree position, in + * stable pre-order. + * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + */ + listDescendants(rootSessionId, signal) { + return listSubagentDescendants(this.ctx, rootSessionId, signal); + } + /** + * Register a provider under its name. Registration is effect-scoped and HMR + * safe; removing a provider blocks new starts but does not revoke runs that + * were already returned to their holders. + * @param provider - the trusted provider implementation. + * @returns the exact Cordis effect disposer. + */ + registerProvider(provider) { + const name = provider.name; + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity + return this.ctx.effect(function* () { + if (this.providers.has(name)) { + throw new SubagentError(`a subagent provider named "${name}" is already registered`, 'DUPLICATE_PROVIDER'); + } + this.providers.set(name, provider); + yield () => { + this.providers.delete(name); + this.emitLifecycle('subagent/provider-removed', name); + }; + // A throwing added-listener unwinds the yielded rollback, matching the + // repository's fail-loud registration semantics. + this.ctx.emit('subagent/provider-added', provider); + }.bind(this), 'subagents.registerProvider()'); + } + /** + * Look up a provider by name. + * @param name - the provider name. + * @returns the provider, or undefined when absent. + */ + getProvider(name) { + return this.providers.get(name); + } + /** + * List registered provider names in insertion order. + * @returns the registered names. + */ + list() { + return [...this.providers.keys()]; + } + /** + * Establish a published child on the named provider. Capability and semantic + * checks run before delegation. Provider ownership lasts until its promise + * fulfills; a rejection therefore has no run for the caller to dispose and + * emits no run lifecycle events. Post-publication turn and infrastructure + * failures settle through the returned run. + * @param name - the provider to use. + * @param request - child label, prompt, parent, signal, and optional capabilities. + * @returns the published holder-owned run. + */ + async start(name, request) { + const provider = this.expectProvider(name); + this.assertCapabilities(provider, request); + assertSubagentMaxDepth(request.maxDepth); + if (request.outputSchema !== undefined) + assertObjectJsonSchema(request.outputSchema); + const descriptor = snapshotSubagentDescriptor({ + mode: 'one-shot', + provider: name, + ...request.label !== undefined ? { label: request.label } : {}, + }); + const resolved = { ...request, descriptor }; + return observeRun(this.emitLifecycle, name, request.parent, await provider.start(resolved)); + } + /** + * Resolve one provider's detached continuable-creation contribution. Method + * presence on the provider IS the capability, so a provider without it is + * rejected before the manager reserves any child resources. + */ + async prepareContinuable(name, request) { + const provider = this.expectProvider(name); + if (provider.prepareContinuable === undefined) { + throw new SubagentError(`subagent provider "${provider.name}" does not support continuable children ` + + '(no prepareContinuable capability)', 'UNSUPPORTED_CAPABILITY'); + } + return provider.prepareContinuable(request); + } + /** Look up a provider for dispatch or fail loud. */ + expectProvider(name) { + const provider = this.providers.get(name); + if (provider === undefined) { + throw new SubagentError(`no subagent provider registered for "${name}"`, 'NO_PROVIDER'); + } + return provider; + } + /** Resolve the optional continuable-subagent manager or fail loud. */ + requireContinuations() { + if (this.continuations === undefined) { + throw new SubagentError('continuable subagents require the agents service', 'CONTINUATION_UNAVAILABLE'); + } + return this.continuations; + } + /** + * Build the lifecycle observer for one continuable Activation's residency + * epoch, so the manager publishes its edges without owning event dispatch. + */ + observeActivation(provider, childId, parent) { + return createActivationObserver(this.emitLifecycle, provider, childId, parent); + } + /** Reject the first requested capability that the provider lacks. */ + assertCapabilities(provider, request) { + const needs = [ + { when: request.outputSchema !== undefined, cap: 'outputSchema' }, + { when: request.maxDepth !== undefined, cap: 'depthLimit' }, + { when: request.toolFilter !== undefined, cap: 'toolFilter' }, + { when: request.persona !== undefined, cap: 'persona' }, + ]; + for (const { when, cap } of needs) { + if (when && !provider.capabilities[cap]) { + throw new SubagentError(`subagent provider "${provider.name}" does not support the "${cap}" capability`, 'UNSUPPORTED_CAPABILITY'); + } + } + } +} +export default SubagentRuntime; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.d.ts new file mode 100644 index 0000000..7dda58d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned subagent registry and lifecycle invariants. @module @deepseek-ai/dsh-subagent/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "subagent-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the subagent invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.js new file mode 100644 index 0000000..41c0014 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.js @@ -0,0 +1,91 @@ +/** Package-owned subagent registry and lifecycle invariants. @module @deepseek-ai/dsh-subagent/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-subagent'; +/** Cordis companion plugin name. */ +export const name = 'subagent-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Assert that a terminal lifecycle payload matches its start identity. */ +function validateRunEnd(start, end, fail) { + if (start.provider !== end.provider || start.id !== end.id || start.local !== end.local) { + fail(`subagent/end identity diverges from subagent/start for run ${JSON.stringify(end.runId)}`); + } +} +/** Install provider-registry and start/end pairing checks. */ +const install = Object.assign((ctx, fail) => { + const providers = new Set(ctx.subagents.list()); + const runs = new Map(); + const stagedProviders = new WeakSet(); + const stagedRemovals = new Set(); + const stagedStarts = new WeakSet(); + const stagedEnds = new WeakSet(); + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName === 'subagent/provider-added') { + const provider = args[0]; + if (provider.name.length === 0) + fail('subagent provider names must be non-empty'); + if (providers.has(provider.name)) + fail(`subagent/provider-added repeated ${JSON.stringify(provider.name)}`); + stagedProviders.add(provider); + return; + } + if (eventName === 'subagent/provider-removed') { + const providerName = args[0]; + if (!providers.has(providerName)) + fail(`subagent/provider-removed names unknown provider ${JSON.stringify(providerName)}`); + stagedRemovals.add(providerName); + return; + } + if (eventName === 'subagent/start') { + const info = args[0]; + // Provider availability is an admission-time relationship. A published + // one-shot run may outlive provider removal, and a cold-resumed Activation + // records the initial provider name without dispatching through it. + if (info.provider.length === 0 || String(info.runId).length === 0 || String(info.id).length === 0) { + fail('subagent/start provider, runId, and child id must be non-empty'); + } + if (runs.has(info.runId)) + fail(`subagent/start repeated run id ${JSON.stringify(info.runId)}`); + stagedStarts.add(info); + return; + } + if (eventName !== 'subagent/end') + return; + const info = args[0]; + const start = runs.get(info.runId); + if (start === undefined) + fail(`subagent/end has no matching subagent/start for run ${JSON.stringify(info.runId)}`); + validateRunEnd(start, info, fail); + stagedEnds.add(info); + }, { global: true }); + ctx.on('subagent/provider-added', (provider) => { + /* v8 ignore next -- internal/dispatch stages the same provider object */ + if (!stagedProviders.delete(provider)) + return; + providers.add(provider.name); + }, { global: true }); + ctx.on('subagent/provider-removed', (providerName) => { + /* v8 ignore next -- internal/dispatch stages the same provider name */ + if (!stagedRemovals.delete(providerName)) + return; + providers.delete(providerName); + }, { global: true }); + ctx.on('subagent/start', (info) => { + /* v8 ignore next -- internal/dispatch stages the same lifecycle object */ + if (!stagedStarts.delete(info)) + return; + runs.set(info.runId, info); + }, { global: true }); + ctx.on('subagent/end', (info) => { + /* v8 ignore next -- internal/dispatch stages the same lifecycle object */ + if (!stagedEnds.delete(info)) + return; + runs.delete(info.runId); + }, { global: true }); +}, { inject: ['subagents'] }); +/** + * Register the subagent invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.d.ts new file mode 100644 index 0000000..9d63a61 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.d.ts @@ -0,0 +1,113 @@ +/** + * Lifecycle-edge publication for both subagent shapes: the contained emitter, + * the one-shot run observer, and the continuable Activation observer. + * + * The public payload contracts ({@link SubagentRunInfo}, + * {@link SubagentRunEndInfo}) live in `./types.ts` with the rest of the seam's + * consumer-facing types; this module owns only the implementation and the + * package-private {@link ActivationObserver} the continuation manager consumes. + * Keeping the internal control interface out of the published surface is + * deliberate: the observer's `start`/`capture`/`settle` ordering is a contract + * between this module and one in-package caller, not something a plugin may + * depend on. + * + * @module @deepseek-ai/dsh-subagent/lifecycle + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +import type { SubagentResult, SubagentRun, SubagentRunEndInfo, SubagentRunInfo } from './types.ts'; +/** + * How one Activation's residency epoch ended, as both the terminal lifecycle + * edge and the manager's own parent delivery report it. + */ +export interface ActivationTerminal { + /** Why this epoch's last ordinary turn ended, or `error` when teardown failed. */ + readonly stopReason: SubagentResult['stopReason']; + /** The epoch's final assistant content, absent when it produced none or failed. */ + readonly output?: ContentBlock[]; +} +/** + * Lifecycle observer for one Activation's residency epoch, so continuable + * children emit the same start/end pair as one-shot runs. Package-private: the + * continuation manager is the only consumer, and its call ordering is an + * in-package contract rather than a published extension point. + */ +export interface ActivationObserver { + /** + * Publish the start edge once the epoch is resident. + * @param child - the resident child agent, whose log suffix bounds this epoch. + */ + start(child: Agent): void; + /** + * Snapshot the child-dependent terminal facts while the child is still + * registered, because handle disposal unregisters it and consumers resolve it + * to read the child's own log and scope. + * @param child - the quiescent child agent about to be released. + */ + capture(child: Agent): void; + /** + * Resolve the terminal facts {@link settle} will publish, without publishing + * them. The manager's parent delivery must run before the ownership release + * that lets the parent settle, which is earlier than the terminal edge; both + * therefore read one computation instead of restating the failure rule. + * @param failure - the teardown or durability failure, or `undefined` on success. + * @returns this epoch's stop reason and final assistant content. + */ + terminal(failure: unknown): ActivationTerminal; + /** + * Publish the terminal edge exactly once, pairing this epoch's {@link start}, + * after the disposal outcome is known. Called only for a resident epoch: a + * failure before residency publishes no edge, because inventing one would + * report a lifecycle the child never had. + * @param failure - the teardown or durability failure, or `undefined` on success. + */ + settle(failure: unknown): void; +} +/** + * Publish one lifecycle edge with per-listener exception containment. Run edges + * carry the delegating parent that keys scoped dispatch; provider removal has no + * parent carrier and reaches listeners unscoped. + * + * The service owns this closure because scoped dispatch keys its carrier by the + * exact service instance, whose own context filter composes into the carrier; + * a narrowed stand-in would silently change scope filtering. + */ +export type LifecycleEmitter = { + (name: 'subagent/start', info: SubagentRunInfo, parent: Agent): void; + (name: 'subagent/end', info: SubagentRunEndInfo, parent: Agent): void; + (name: 'subagent/provider-removed', info: string): void; +}; +/** + * Build the contained lifecycle emitter this seam publishes every edge through. + * Every listener is independently contained: a synchronous throw or a rejected + * returned promise is logged without starving peer listeners, changing the run, + * or — for provider removal, which fires from a disposer — breaking teardown. + * @param ctx - the service's own context, owning dispatch and the logger. + * @param carrier - resolve the scoped dispatch carrier for one delegating parent. + * @returns the emitter both observers and the provider registry publish through. + */ +export declare function createLifecycleEmitter(ctx: Context, carrier: (parent: Agent) => object): LifecycleEmitter; +/** + * Emit the start/end lifecycle pair for one accepted one-shot run. + * @param emit - the contained lifecycle emitter. + * @param provider - the provider that established the run. + * @param parent - the delegating parent keying scoped dispatch. + * @param run - the published run whose settlement closes the pair. + * @returns the same run, unchanged. + */ +export declare function observeRun(emit: LifecycleEmitter, provider: string, parent: Agent, run: SubagentRun): SubagentRun; +/** + * Build the observer for one continuable Activation's residency epoch. Observers + * see the same vocabulary as a one-shot run, so a child's start and settlement + * remain observable without exposing whether the manager materialized, woke, or + * cold-resumed it. Creation failure before residency emits no lifecycle edge. + * @param emit - the contained lifecycle emitter. + * @param provider - the provider name recorded in the durable descriptor. + * @param childId - the durable child session id. + * @param parent - the exact live direct parent keying scoped dispatch. + * @returns the observer whose edges this epoch publishes. + */ +export declare function createActivationObserver(emit: LifecycleEmitter, provider: string, childId: SessionId, parent: Agent): ActivationObserver; +//# sourceMappingURL=lifecycle.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.js new file mode 100644 index 0000000..cff7aed --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.js @@ -0,0 +1,177 @@ +/** + * Lifecycle-edge publication for both subagent shapes: the contained emitter, + * the one-shot run observer, and the continuable Activation observer. + * + * The public payload contracts ({@link SubagentRunInfo}, + * {@link SubagentRunEndInfo}) live in `./types.ts` with the rest of the seam's + * consumer-facing types; this module owns only the implementation and the + * package-private {@link ActivationObserver} the continuation manager consumes. + * Keeping the internal control interface out of the published surface is + * deliberate: the observer's `start`/`capture`/`settle` ordering is a contract + * between this module and one in-package caller, not something a plugin may + * depend on. + * + * @module @deepseek-ai/dsh-subagent/lifecycle + */ +import { randomUUID } from 'node:crypto'; +import { foldConsumedWork } from '@deepseek-ai/dsh-agent'; +import { finalAssistantOutput } from "./assistant-output.js"; +import { SubagentRunId } from "./types.js"; +/** + * Build the contained lifecycle emitter this seam publishes every edge through. + * Every listener is independently contained: a synchronous throw or a rejected + * returned promise is logged without starving peer listeners, changing the run, + * or — for provider removal, which fires from a disposer — breaking teardown. + * @param ctx - the service's own context, owning dispatch and the logger. + * @param carrier - resolve the scoped dispatch carrier for one delegating parent. + * @returns the emitter both observers and the provider registry publish through. + */ +export function createLifecycleEmitter(ctx, carrier) { + return (name, info, parent) => { + const dispatchArgs = parent === undefined + ? [name, info] + : [carrier(parent), name, info]; + for (const callback of ctx.events.dispatch('emit', dispatchArgs)) { + try { + const returned = callback(info); + void Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`subagent: ${name} listener rejected: ${renderThrown(error)}`); + }); + } + catch (error) { + ctx.logger.warn(`subagent: ${name} listener threw: ${renderThrown(error)}`); + } + } + }; +} +/** + * Emit the start/end lifecycle pair for one accepted one-shot run. + * @param emit - the contained lifecycle emitter. + * @param provider - the provider that established the run. + * @param parent - the delegating parent keying scoped dispatch. + * @param run - the published run whose settlement closes the pair. + * @returns the same run, unchanged. + */ +export function observeRun(emit, provider, parent, run) { + const identity = { + runId: SubagentRunId(randomUUID()), + provider, + id: run.id, + local: run.localAgent !== undefined, + }; + // Attach the terminal observer before dispatching start. Promise reactions + // still run after this synchronous start emission, preserving start → end. + void run.result.then((result) => { + emit('subagent/end', { + ...identity, + stopReason: result.stopReason, + // Omit the field when no output exists, matching continuable epochs. + ...result.output.length === 0 ? {} : { lastAssistantMessage: result.output }, + }, parent); + }, () => { + emit('subagent/end', { ...identity, stopReason: 'error' }, parent); + }); + emit('subagent/start', identity, parent); + return run; +} +/** + * Build the observer for one continuable Activation's residency epoch. Observers + * see the same vocabulary as a one-shot run, so a child's start and settlement + * remain observable without exposing whether the manager materialized, woke, or + * cold-resumed it. Creation failure before residency emits no lifecycle edge. + * @param emit - the contained lifecycle emitter. + * @param provider - the provider name recorded in the durable descriptor. + * @param childId - the durable child session id. + * @param parent - the exact live direct parent keying scoped dispatch. + * @returns the observer whose edges this epoch publishes. + */ +export function createActivationObserver(emit, provider, childId, parent) { + const identity = { runId: SubagentRunId(randomUUID()), provider, id: childId, local: true }; + // A cold resume replays earlier turns, so this epoch's telemetry must come + // from the suffix it actually produced — never the whole session, which + // would report a previous epoch's answer when this one opened no turn. + let boundary = 0; + // Assigned by `capture()`, which the disposal path always runs before + // `settle()`; a resident epoch therefore always has its facts by then. + let captured = { stopReason: 'completed' }; + // Teardown failure overrides the epoch's own outcome and withholds its + // output: an answer this harness could not durably release is not a result. + const terminal = (failure) => failure === undefined + ? captured + : { stopReason: 'error' }; + return { + start: (child) => { + boundary = child.session.events.length; + emit('subagent/start', identity, parent); + }, + capture: (child) => { + const own = child.session.events.slice(boundary); + const output = finalAssistantOutput(own); + captured = { + stopReason: epochStopReason(own), + ...output === undefined ? {} : { output }, + }; + }, + terminal, + settle: (failure) => { + const { stopReason, output } = terminal(failure); + emit('subagent/end', { + ...identity, + stopReason, + ...output === undefined ? {} : { lastAssistantMessage: output }, + }, parent); + }, + }; +} +/** + * Why this child's epoch ended, for the terminal lifecycle edge and the + * manager's own parent delivery. The child's own log is authoritative: + * teardown succeeding says nothing about whether the model errored, hit its + * token ceiling, or was cancelled, so deriving the reason from disposal would + * report failed work as completed. + * + * {@link foldConsumedWork} supplies both halves the raw turn sequence cannot: + * which turn accounts for the work this epoch consumed, and whether accepted + * work was cancelled after it without any turn opening over it. A recorded + * failure still wins over a cancellation — stopping a child that had already + * failed does not turn its failure into a cancellation. + * @param events - this epoch's own event suffix. + * @returns its terminal stop reason; `completed` only for an epoch that both + * closed cleanly and had nothing left to run. + */ +function epochStopReason(events) { + const { end, droppedUnrun } = foldConsumedWork(events); + switch (end?.data.reason.kind) { + case 'max-tokens': + return 'max-tokens'; + case 'aborted': + case 'interrupted': + return 'aborted'; + case 'error': + return 'error'; + // A pre-step rejection — a hook deny, a policy plugin — discarded input + // this epoch had claimed: the work was declined, not done. + case 'blocked': + return 'refusal'; + // A clean ending and no accounting turn at all share one rule: the epoch + // finished what it was given unless a cancelled queue says otherwise. + case undefined: + case 'completed': + return droppedUnrun ? 'aborted' : 'completed'; + /* v8 ignore next 3 -- `TurnEndReason` is merge-extensible, so this arm needs a + * backend that adds a variant; treating an unnameable reason as success would + * report failed work as completed. */ + default: + return 'error'; + } +} +/** Render any listener-thrown value without letting coercion escape containment. */ +function renderThrown(value) { + try { + return value instanceof Error ? `${value.name}: ${value.message}` : String(value); + } + catch { + return ''; + } +} +//# sourceMappingURL=lifecycle.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.d.ts new file mode 100644 index 0000000..c8cba52 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.d.ts @@ -0,0 +1,112 @@ +/** + * Read-only enumeration of durable subagent children and descendant trees + * straight from the live session store and optional session persistence — no + * query service. Candidates come from one live-preferred corpus; each child's + * mode/label is the registered `subagent` projection unit's value, resolved + * down a three-rung ladder: the registry's watermark cache for a live child, + * a durable projection-cache row when it serves an own-suffix identity (the + * seq gate), and one persistence inspection folded through the registry + * otherwise, validated against the enumerated lifecycle. The projection fold + * is the single classification authority — this module parses no descriptor + * itself. Absent persistence, enumeration is live-only: a cold child is + * unreachable for resume anyway, so its absence is capability absence, not an + * error. The module owns no catalog state and does not consult Activation, + * Agent-registry, continuation-manager, or provider state. + * + * @module @deepseek-ai/dsh-subagent + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +/** + * One entry of a {@link listChildren} result, ordered by header `createdAt` + * with ties broken on id. Only a candidate whose durable header has + * `origin: 'subagent'` is interpreted. A served `subagent` projection value + * produces a `child`; a settled candidate whose fold served no identity + * produces a `diagnostic`; a running candidate without one is omitted — its + * descriptor may not be appended yet (the creation window). Diagnostics + * relay the projection fold's outcome or a failed read, never a per-child + * event scan, and never expose model-hidden descriptor content. + */ +export type SubagentListEntry = { + readonly kind: 'child'; + /** The durable child session id, stable across Activations. */ + readonly id: SessionId; + /** + * Store snapshot activity: `running` means the logical record is live in + * `ctx.sessions`; `inactive` means it exists only in persistence. Neither + * encodes a durable outcome, and a continuable child may still reject + * delivery as an ownership conflict. + */ + readonly activity: 'running' | 'inactive'; + /** Whether a direct descendant has durable `origin: 'subagent'`. */ + readonly hasChildren: boolean; +} & ({ + /** A terminal one-shot child. */ + readonly mode: 'one-shot'; + /** Optional durable creation label from the child's descriptor. */ + readonly label?: string; +} | { + /** A resumable conversation. */ + readonly mode: 'continuable'; + /** Durable creation label from the child's descriptor. */ + readonly label: string; +}) | { + readonly kind: 'diagnostic'; + /** The candidate's session id. */ + readonly id: SessionId; + /** + * Why the candidate has no `child` row: `corrupt` for a settled candidate + * whose projection fold served no identity (a missing, malformed, or + * unrecognized-version descriptor — deliberately undistinguished), and + * for any candidate whose log makes a registered unit's fold or schema + * throw (deterministic data damage, contained per child); `unavailable` + * when the candidate's persistence inspection failed (retried on the + * next listing). `unsupported` is never produced; it remains in the + * union for consumers that route on it. + */ + readonly reason: 'corrupt' | 'unsupported' | 'unavailable'; +}; +/** + * One entry of a descendant listing: the interpreted subagent facts plus its + * position in the complete session tree. `parentId` is the durable direct + * parent from the enumerated header, and `depth` counts edges from the root. + */ +export type SubagentDescendantListEntry = SubagentListEntry & { + /** Durable direct parent of this candidate in the enumerated tree. */ + readonly parentId: SessionId; + /** Edge distance from the requested root; direct children are `1`. */ + readonly depth: number; +}; +/** + * Enumerate one parent's origin-classified direct children from the + * live-preferred merge of `ctx.sessions` and optional session persistence, + * serving each identity from the `subagent` projection unit: the registry's + * watermark snapshot for a live child; for a cold one, a durable + * projection-cache row when it serves an own-suffix identity (the seq gate), + * else one bounded-concurrency persistence inspection folded through the + * registry. + * @see SubagentRuntime.listChildren for the public cancellation and failure contract. + * @param ctx - context carrying the session store, the projection registry, + * optional persistence, and the optional projection cache. + * @param parentSessionId - parent session whose direct children are listed. + * @param signal - caller-owned cancellation observed around every persistence read. + * @returns children and per-child diagnostics ordered by `createdAt`, then id. + * @throws {@link SubagentError} when the projection registry or the session + * store is not mounted, or the caller cancels the listing. + */ +export declare function listChildren(ctx: Context, parentSessionId: SessionId, signal?: AbortSignal): Promise; +/** + * Enumerate every session-backed subagent below one root in stable pre-order. + * Ordinary sessions and one-shot children remain traversal nodes, so a + * continuable child below either is still discovered. Classification uses the + * same projection-backed runtime as {@link listChildren}; no Agent is loaded or + * resumed. + * @see SubagentRuntime.listDescendants for the public cancellation and failure contract. + * @param ctx - context carrying the session store, projection registry, and optional persistence/cache. + * @param rootSessionId - session whose complete descendant tree is listed. + * @param signal - caller-owned cancellation observed around every persistence read. + * @returns interpreted subagents with durable direct-parent and root-relative depth. + * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + */ +export declare function listDescendants(ctx: Context, rootSessionId: SessionId, signal?: AbortSignal): Promise; +//# sourceMappingURL=list-children.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.js new file mode 100644 index 0000000..d7d2170 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.js @@ -0,0 +1,316 @@ +/** + * Read-only enumeration of durable subagent children and descendant trees + * straight from the live session store and optional session persistence — no + * query service. Candidates come from one live-preferred corpus; each child's + * mode/label is the registered `subagent` projection unit's value, resolved + * down a three-rung ladder: the registry's watermark cache for a live child, + * a durable projection-cache row when it serves an own-suffix identity (the + * seq gate), and one persistence inspection folded through the registry + * otherwise, validated against the enumerated lifecycle. The projection fold + * is the single classification authority — this module parses no descriptor + * itself. Absent persistence, enumeration is live-only: a cold child is + * unreachable for resume anyway, so its absence is capability absence, not an + * error. The module owns no catalog state and does not consult Activation, + * Agent-registry, continuation-manager, or provider state. + * + * @module @deepseek-ai/dsh-subagent + */ +import { SubagentError } from "./error.js"; +/** + * Concurrent cold inspections per listing; a constant because it bounds one + * read-only scan of local media, not deployment behavior. Should a networked + * persistence backend appear, promote it to a validated `Config` field. + */ +const COLD_READ_CONCURRENCY = 4; +/** + * Enumerate one parent's origin-classified direct children from the + * live-preferred merge of `ctx.sessions` and optional session persistence, + * serving each identity from the `subagent` projection unit: the registry's + * watermark snapshot for a live child; for a cold one, a durable + * projection-cache row when it serves an own-suffix identity (the seq gate), + * else one bounded-concurrency persistence inspection folded through the + * registry. + * @see SubagentRuntime.listChildren for the public cancellation and failure contract. + * @param ctx - context carrying the session store, the projection registry, + * optional persistence, and the optional projection cache. + * @param parentSessionId - parent session whose direct children are listed. + * @param signal - caller-owned cancellation observed around every persistence read. + * @returns children and per-child diagnostics ordered by `createdAt`, then id. + * @throws {@link SubagentError} when the projection registry or the session + * store is not mounted, or the caller cancels the listing. + */ +export async function listChildren(ctx, parentSessionId, signal) { + const listing = await prepareListing(ctx, signal); + const candidates = [...listing.corpus.values()] + .filter(record => record.header.parentSession === parentSessionId + && record.header.origin === 'subagent') + .sort(compareCorpusRecords); + const rows = await resolveCandidateRows(candidates, listing, signal); + return rows.filter((row) => row !== undefined); +} +/** + * Enumerate every session-backed subagent below one root in stable pre-order. + * Ordinary sessions and one-shot children remain traversal nodes, so a + * continuable child below either is still discovered. Classification uses the + * same projection-backed runtime as {@link listChildren}; no Agent is loaded or + * resumed. + * @see SubagentRuntime.listDescendants for the public cancellation and failure contract. + * @param ctx - context carrying the session store, projection registry, and optional persistence/cache. + * @param rootSessionId - session whose complete descendant tree is listed. + * @param signal - caller-owned cancellation observed around every persistence read. + * @returns interpreted subagents with durable direct-parent and root-relative depth. + * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + */ +export async function listDescendants(ctx, rootSessionId, signal) { + const listing = await prepareListing(ctx, signal); + const positioned = descendantCandidates(listing.corpus, rootSessionId); + const rows = await resolveCandidateRows(positioned.map(candidate => candidate.record), listing, signal); + const entries = []; + positioned.forEach((position, index) => { + const row = rows[index]; + if (row !== undefined) { + entries.push({ ...row, parentId: position.parentId, depth: position.depth }); + } + }); + return entries; +} +/** Resolve listing services once and build one live-preferred session corpus. */ +async function prepareListing(ctx, signal) { + const projections = ctx.get('sessionProjections'); + // Checked before any read, even with zero candidates: mode/label are the + // row's strong contract, so a missing fold capability is a deterministic + // deployment configuration error, never an empty success. + if (projections === undefined) { + throw new SubagentError('listing subagents requires the sessionProjections registry (load @deepseek-ai/dsh-session-projection)', 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE'); + } + // Strict global read, never the `ctx.sessions` property proxy: the proxy is + // caller-scope bound, so a consumer plugin without its own `sessions` + // injection (the model-facing tool, the API proxy) would throw on access. + const sessions = ctx.get('sessions'); + if (sessions === undefined) { + throw new SubagentError('listing subagents requires the session store (load @deepseek-ai/dsh-session)', 'SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE'); + } + assertListingNotCancelled(signal); + const persistence = ctx.get('sessionPersistence'); + // Optional acceleration only: an absent cache service just means every + // cold candidate takes the authoritative preparation rung, so it carries + // no error code and no configuration check. + const cache = ctx.get('sessionProjectionCache'); + let persistedHeaders = []; + if (persistence !== undefined) { + try { + persistedHeaders = await persistence.list(signal); + } + catch (error) { + // The backend may reject with its own abort failure after observing the + // forwarded signal; cancellation stays a stable subagent failure. + assertListingNotCancelled(signal); + throw error; + } + assertListingNotCancelled(signal); + } + // Live-preferred merge without header reconciliation: a live record wins + // its id wholesale, exactly as a live-preferred corpus would serve it. + const corpus = new Map(); + for (const header of persistedHeaders) + corpus.set(header.id, { header, live: undefined }); + for (const session of sessions.list()) { + corpus.set(session.header.id, { header: session.header, live: session }); + } + const subagentParents = new Set(); + for (const record of corpus.values()) { + if (record.header.origin === 'subagent' && record.header.parentSession !== undefined) { + subagentParents.add(record.header.parentSession); + } + } + return { projections, persistence, cache, corpus, subagentParents }; +} +/** Resolve projection-backed rows for aligned candidates with bounded cold reads. */ +async function resolveCandidateRows(candidates, listing, signal) { + const { projections, persistence, cache, subagentParents } = listing; + const rows = Array.from({ length: candidates.length }); + const coldReads = []; + candidates.forEach((candidate, index) => { + const childId = candidate.header.id; + if (candidate.live === undefined) { + coldReads.push({ index, header: candidate.header }); + return; + } + // The registry's watermark cache serves the live value with zero log + // reads; a live child without an identity yet is the creation window + // before the establishing provider appends its descriptor. + let identity; + try { + identity = projections.snapshot(candidate.live).values.subagent; + } + catch { + // The snapshot folds EVERY registered unit over this child's log, so + // any unit's fold or schema can reject damaged payloads. That is + // deterministic data damage in this one child; it degrades to one + // corrupt diagnostic instead of failing the whole listing. + rows[index] = { kind: 'diagnostic', id: childId, reason: 'corrupt' }; + return; + } + // The unit's serializable no-value sentinel is `null`; `undefined` can + // only mean the key was dropped at a JSON boundary. Both are no value. + if (identity === undefined || identity === null) + return; + rows[index] = childRow(childId, identity, 'running', subagentParents.has(childId)); + }); + // Cold candidates exist only when persistence listed them, so the narrow + // re-check is about types, not reachability. + if (persistence !== undefined && coldReads.length > 0) { + const queue = [...coldReads]; + await Promise.all(Array.from({ length: Math.min(COLD_READ_CONCURRENCY, queue.length) }, async () => { + for (let job = queue.shift(); job !== undefined; job = queue.shift()) { + rows[job.index] = await resolveColdIdentity(persistence, projections, cache, job.header, subagentParents.has(job.header.id), signal); + } + })); + } + assertListingNotCancelled(signal); + return rows; +} +/** Build origin-classified candidates from the complete tree without recursion. */ +function descendantCandidates(corpus, rootSessionId) { + const children = new Map(); + for (const record of corpus.values()) { + const parentId = record.header.parentSession; + if (parentId === undefined) + continue; + const siblings = children.get(parentId); + if (siblings === undefined) + children.set(parentId, [record]); + else + siblings.push(record); + } + for (const siblings of children.values()) + siblings.sort(compareCorpusRecords); + const positioned = []; + const stack = (children.get(rootSessionId) ?? []) + .map(record => ({ record, parentId: rootSessionId, depth: 1 })) + .reverse(); + const visited = new Set([rootSessionId]); + while (stack.length > 0) { + // The length guard proves one frame exists. + // oxlint-disable-next-line typescript/no-non-null-assertion + const position = stack.pop(); + const id = position.record.header.id; + if (visited.has(id)) + continue; + visited.add(id); + if (position.record.header.origin === 'subagent') + positioned.push(position); + const descendants = children.get(id) ?? []; + for (const record of [...descendants].reverse()) { + stack.push({ record, parentId: id, depth: position.depth + 1 }); + } + } + return positioned; +} +/** Compare siblings by durable creation time, then id. */ +function compareCorpusRecords(a, b) { + return a.header.createdAt - b.header.createdAt || a.header.id.localeCompare(b.header.id); +} +/** + * Resolve one cold candidate down the remaining ladder: a durable + * projection-cache row when it serves an own-suffix identity (the seq gate), + * otherwise one persistence inspection folded through the projection + * registry (the same detached recipe the API proxy uses for detached session + * projections). A failed inspection is one transient `unavailable` row + * retried on the next listing; an inspection naming another lifecycle, and a + * settled log the fold cannot identify — or that makes any registered unit + * throw — are final, so they report `corrupt`. + */ +async function resolveColdIdentity(persistence, projections, cache, header, hasChildren, signal) { + const childId = header.id; + if (cache !== undefined) { + let cached; + try { + cached = cache.cachedSnapshot(header)?.values.subagent; + } + catch { + // Unlike the preparation fold below, a throwing cache read renders no + // verdict: the cache is derived data, so its damage (a poisoned stored + // row of ANY unit) silently falls through to the authoritative re-fold. + cached = undefined; + } + // A child's OWN descriptor is immutable once appended, so a cached + // identity is final only when the seq gate proves it was folded from the + // own suffix: a creation-window checkpoint may instead carry a fork + // seed's replayed ANCESTOR descriptor (seq below `seedLength`), which + // must not outrank the re-fold. Everything else also falls through to + // preparation: an absent key (a cut before any descriptor) and the + // `null` sentinel, whose verdict belongs to the authoritative re-fold, + // not to a derived row. + if (cached !== undefined && cached !== null && cached.seq >= (header.seedLength ?? 0)) { + return childRow(childId, cached, 'inactive', hasChildren); + } + } + assertListingNotCancelled(signal); + let inspected; + try { + inspected = await persistence.inspect(childId, signal); + } + catch { + // Per-child isolation: the child vanished or its backend read failed — + // one diagnostic row, and the listing itself still succeeds. + assertListingNotCancelled(signal); + return { kind: 'diagnostic', id: childId, reason: 'unavailable' }; + } + assertListingNotCancelled(signal); + // A session id names a slot, not a lifecycle: a child deleted and + // re-published under another owner between the enumeration and this read + // must not leak into the old parent's listing. + if (!sameLifecycle(inspected.meta, header)) { + return { kind: 'diagnostic', id: childId, reason: 'corrupt' }; + } + let identity; + try { + identity = projections.restore({}, inspected.events, 0).snapshot.values.subagent; + } + catch { + // The restore folds EVERY registered unit over this child's log, so any + // unit's fold or schema can reject damaged payloads — deterministic data + // damage in this one child, contained as its own corrupt diagnostic. + return { kind: 'diagnostic', id: childId, reason: 'corrupt' }; + } + if (identity === undefined || identity === null) { + return { kind: 'diagnostic', id: childId, reason: 'corrupt' }; + } + return childRow(childId, identity, 'inactive', hasChildren); +} +/** Materialize one served identity as its child row. */ +function childRow(id, identity, activity, hasChildren) { + return identity.mode === 'one-shot' + ? { + kind: 'child', + id, + mode: 'one-shot', + ...identity.label !== undefined ? { label: identity.label } : {}, + activity, + hasChildren, + } + : { + kind: 'child', + id, + mode: 'continuable', + label: identity.label, + activity, + hasChildren, + }; +} +/** Immutable header fields that distinguish one session lifecycle from another under the same id. */ +const LIFECYCLE_WITNESS_KEYS = [ + 'version', 'id', 'createdAt', 'cwd', 'parentSession', 'seedLength', 'delegationDepth', +]; +/** Whether an inspected log still belongs to the enumerated lifecycle. */ +function sameLifecycle(meta, expected) { + return LIFECYCLE_WITNESS_KEYS.every(key => meta[key] === expected[key]); +} +/** Stop a listing at its next cancellation checkpoint. */ +function assertListingNotCancelled(signal) { + if (signal?.aborted) { + throw new SubagentError('subagent listing was cancelled', 'CANCELLED'); + } +} +//# sourceMappingURL=list-children.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.d.ts new file mode 100644 index 0000000..476ade5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.d.ts @@ -0,0 +1,115 @@ +/** + * Provider-side vocabulary for OUT-OF-PROCESS subagent backends — the pieces + * that enforce this seam's own contracts around a child in another process: + * the no-capabilities advertisement, timing-bound validation, child + * working-directory resolution (config override, else the delegating parent + * session's workspace), the never-reject result settlement, and the standard + * run-handle publication. Backends compose these with their own wire drivers; + * the process machinery itself (spawn, env scrub, tree-scoped teardown) + * belongs to the `dsh-subprocess` seam. + * + * @module @deepseek-ai/dsh-subagent/out-of-process + */ +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { SubagentCapabilities, SubagentResult, SubagentRun, SubagentStopReason } from './types.ts'; +/** + * The capability advertisement of an out-of-process backend: NONE. A child in + * another process cannot honor parent-enforced start features + * (`outputSchema`/`maxDepth`/`toolFilter`/`persona`), so the service rejects a + * request needing any of them before `start` runs — never accepted-then-ignored. + */ +export declare const NO_START_CAPABILITIES: SubagentCapabilities; +/** + * Assert a configured timing bound is a positive finite number (it bounds a + * teardown or shutdown wait; zero, negative, or NaN would skip or wedge it). + * @param prefix - the consuming plugin's diagnostic prefix (e.g. `subagent-acp`). + * @param name - the config field name, for the diagnostic. + * @param value - the configured value. + */ +export declare function assertPositiveFinite(prefix: string, name: string, value: number): void; +/** + * Assert `cwd` can actually host the child: absolute (it doubles as the + * child's workspace identity, and a relative path would be re-anchored to the + * server process's launch directory) and an existing directory (fail here, + * before the process boundary, instead of as an ambiguous spawn ENOENT). + * @param prefix - the consuming plugin's diagnostic prefix. + * @param label - which source supplied the value, for the diagnostic. + * @param cwd - the candidate working directory. + * @returns `cwd`, validated. + */ +export declare function assertUsableCwd(prefix: string, label: string, cwd: string): string; +/** + * Validate a configured `cwd` override ONCE, at plugin load: reject the empty + * string (`path.resolve('')` is the process cwd — it would silently + * reintroduce the launch-directory fallback this resolution removes), + * interpret a relative path against the harness launch directory, and require + * an enterable directory. + * @param prefix - the consuming plugin's diagnostic prefix. + * @param cwd - the configured override, or `undefined` when the config omits it. + * @returns the validated absolute override, or `undefined` when omitted. + */ +export declare function validateConfiguredCwd(prefix: string, cwd: string | undefined): string | undefined; +/** + * Resolve the child's working directory at start: the deployment override + * when configured (already validated at load), else the parent session's + * workspace cwd (validated here, its earliest resolvable point). Fails loud + * when neither exists — falling back to the harness process cwd would + * silently bind the child to the server's launch directory instead of the + * delegating session's workspace (one server process serves many sessions, + * each with its own cwd). + * @param prefix - the consuming plugin's diagnostic prefix. + * @param configured - the load-validated override, or `undefined`. + * @param parentCwd - the delegating parent session's workspace cwd, if any. + * @returns the absolute child working directory. + */ +export declare function resolveChildCwd(prefix: string, configured: string | undefined, parentCwd: string | undefined): string; +/** Inputs to {@link settleRunResult}. */ +export interface RunResultSettlement { + /** The turn attempt (typically racing local cancellation); returns the terminal result. */ + attempt: () => Promise; + /** Snapshot the provider exposes when cancellation or failure wins settlement. */ + collectOutput: () => ContentBlock[]; + /** Whether local cancellation settled before the attempt's outcome is observed. */ + cancelled: () => boolean; + /** Diagnostic sink for a failure flattened to a stop reason; a throw from it is contained. */ + onError?: ((error: Error, stopReason: SubagentStopReason) => void) | undefined; + /** The request's cancellation signal (the listener is removed at settlement). */ + signal: AbortSignal; + /** The abort listener registered on {@link signal} at start. */ + onAbort: () => void; +} +/** + * Settle an out-of-process run result under the seam contract: `result` never + * rejects after publication. A normally completed or rejected attempt resolves + * as `aborted` when cancellation already settled locally; another rejection is + * flattened to `stopReason: 'error'` through the contained diagnostic sink. + * The abort listener is removed on every path. + * @param parts - the attempt, output snapshot, cancellation state, sink, and signal wiring. + * @returns the terminal result (never a rejection). + */ +export declare function settleRunResult(parts: RunResultSettlement): Promise; +/** Inputs to {@link subprocessRunHandle}. */ +export interface SubprocessRunHandleParts { + /** The parent-scoped run id. */ + id: SubagentRun['id']; + /** The flattened, never-rejecting result (the seam contract). */ + result: Promise; + /** The request's cancellation signal (the listener is removed on dispose). */ + signal: AbortSignal; + /** The abort listener registered on {@link signal} at start. */ + onAbort: () => void; + /** Settle local cancellation so {@link result} resolves without the child. */ + requestCancel: () => void; + /** Tear the child process down to quiescence (backend-owned ladder). */ + teardown: () => Promise; +} +/** + * Publish the seam run handle for an out-of-process child. `dispose()` is + * idempotent (one memoized teardown): it removes the abort listener, settles + * local cancellation — there is no assumption the child cooperates — and then + * awaits the backend's teardown to actual exit. + * @param parts - the run identity, result, cancellation wiring, and teardown. + * @returns the seam run handle (`localAgent` is `undefined` for remote runs). + */ +export declare function subprocessRunHandle(parts: SubprocessRunHandleParts): SubagentRun; +//# sourceMappingURL=out-of-process.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.js new file mode 100644 index 0000000..5460dfe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.js @@ -0,0 +1,181 @@ +/** + * Provider-side vocabulary for OUT-OF-PROCESS subagent backends — the pieces + * that enforce this seam's own contracts around a child in another process: + * the no-capabilities advertisement, timing-bound validation, child + * working-directory resolution (config override, else the delegating parent + * session's workspace), the never-reject result settlement, and the standard + * run-handle publication. Backends compose these with their own wire drivers; + * the process machinery itself (spawn, env scrub, tree-scoped teardown) + * belongs to the `dsh-subprocess` seam. + * + * @module @deepseek-ai/dsh-subagent/out-of-process + */ +import { accessSync, constants, statSync } from 'node:fs'; +import { isAbsolute, resolve } from 'node:path'; +/** + * The capability advertisement of an out-of-process backend: NONE. A child in + * another process cannot honor parent-enforced start features + * (`outputSchema`/`maxDepth`/`toolFilter`/`persona`), so the service rejects a + * request needing any of them before `start` runs — never accepted-then-ignored. + */ +export const NO_START_CAPABILITIES = Object.freeze({ + outputSchema: false, + depthLimit: false, + toolFilter: false, + persona: false, +}); +/** + * Assert a configured timing bound is a positive finite number (it bounds a + * teardown or shutdown wait; zero, negative, or NaN would skip or wedge it). + * @param prefix - the consuming plugin's diagnostic prefix (e.g. `subagent-acp`). + * @param name - the config field name, for the diagnostic. + * @param value - the configured value. + */ +export function assertPositiveFinite(prefix, name, value) { + if (!Number.isFinite(value) || value <= 0) { + throw new Error(`${prefix}: ${name} must be a positive finite number`); + } +} +/** + * Whether `path` names an existing directory the harness can ENTER. The + * search-permission probe matters: `statSync().isDirectory()` is true for a + * mode-600 directory, but a subprocess cwd needs `X_OK` or spawn fails EACCES. + */ +function isEnterableDirectory(path) { + try { + if (!statSync(path).isDirectory()) + return false; + accessSync(path, constants.X_OK); + return true; + } + catch { + // statSync/accessSync throw only filesystem access errors here + // (ENOENT/EACCES/ENOTDIR/…), and every one of them means the path cannot + // serve as the child's cwd. + return false; + } +} +/** + * Assert `cwd` can actually host the child: absolute (it doubles as the + * child's workspace identity, and a relative path would be re-anchored to the + * server process's launch directory) and an existing directory (fail here, + * before the process boundary, instead of as an ambiguous spawn ENOENT). + * @param prefix - the consuming plugin's diagnostic prefix. + * @param label - which source supplied the value, for the diagnostic. + * @param cwd - the candidate working directory. + * @returns `cwd`, validated. + */ +export function assertUsableCwd(prefix, label, cwd) { + if (!isAbsolute(cwd)) { + throw new Error(`${prefix}: ${label} must be an absolute path: ${cwd}`); + } + if (!isEnterableDirectory(cwd)) { + throw new Error(`${prefix}: ${label} is not an accessible directory: ${cwd}`); + } + return cwd; +} +/** + * Validate a configured `cwd` override ONCE, at plugin load: reject the empty + * string (`path.resolve('')` is the process cwd — it would silently + * reintroduce the launch-directory fallback this resolution removes), + * interpret a relative path against the harness launch directory, and require + * an enterable directory. + * @param prefix - the consuming plugin's diagnostic prefix. + * @param cwd - the configured override, or `undefined` when the config omits it. + * @returns the validated absolute override, or `undefined` when omitted. + */ +export function validateConfiguredCwd(prefix, cwd) { + if (cwd === undefined) + return undefined; + if (cwd === '') { + throw new Error(`${prefix}: config cwd must not be empty — omit the key to inherit the parent session cwd`); + } + return assertUsableCwd(prefix, 'config cwd', resolve(cwd)); +} +/** + * Resolve the child's working directory at start: the deployment override + * when configured (already validated at load), else the parent session's + * workspace cwd (validated here, its earliest resolvable point). Fails loud + * when neither exists — falling back to the harness process cwd would + * silently bind the child to the server's launch directory instead of the + * delegating session's workspace (one server process serves many sessions, + * each with its own cwd). + * @param prefix - the consuming plugin's diagnostic prefix. + * @param configured - the load-validated override, or `undefined`. + * @param parentCwd - the delegating parent session's workspace cwd, if any. + * @returns the absolute child working directory. + */ +export function resolveChildCwd(prefix, configured, parentCwd) { + if (configured !== undefined) + return configured; + if (parentCwd === undefined) { + throw new Error(`${prefix}: no working directory for the child — configure \`cwd\` or delegate from a parent session that has one`); + } + return assertUsableCwd(prefix, 'parent session cwd', parentCwd); +} +/** Normalize an unknown thrown value to an Error (the catch binding is `unknown`). */ +function toError(value) { + // The rejecting surfaces (wire clients, spawn failures) only throw + // `Error`s; the `String(value)` arm is a defensive fallback for a non-Error + // throw the typed surfaces cannot produce. + /* v8 ignore next */ + return value instanceof Error ? value : new Error(String(value)); +} +/** + * Settle an out-of-process run result under the seam contract: `result` never + * rejects after publication. A normally completed or rejected attempt resolves + * as `aborted` when cancellation already settled locally; another rejection is + * flattened to `stopReason: 'error'` through the contained diagnostic sink. + * The abort listener is removed on every path. + * @param parts - the attempt, output snapshot, cancellation state, sink, and signal wiring. + * @returns the terminal result (never a rejection). + */ +export async function settleRunResult(parts) { + try { + const result = await parts.attempt(); + return parts.cancelled() + ? { output: parts.collectOutput(), stopReason: 'aborted' } + : result; + } + catch (error) { + // Cover a rejection already queued when cancellation arrives. + if (parts.cancelled()) + return { output: parts.collectOutput(), stopReason: 'aborted' }; + // Flatten post-publication transport failures while preserving diagnostics. + try { + parts.onError?.(toError(error), 'error'); + } + catch { + // The diagnostic sink cannot reject the run result. + } + return { output: parts.collectOutput(), stopReason: 'error' }; + } + finally { + parts.signal.removeEventListener('abort', parts.onAbort); + } +} +/** + * Publish the seam run handle for an out-of-process child. `dispose()` is + * idempotent (one memoized teardown): it removes the abort listener, settles + * local cancellation — there is no assumption the child cooperates — and then + * awaits the backend's teardown to actual exit. + * @param parts - the run identity, result, cancellation wiring, and teardown. + * @returns the seam run handle (`localAgent` is `undefined` for remote runs). + */ +export function subprocessRunHandle(parts) { + let disposal; + return { + id: parts.id, + localAgent: undefined, + result: parts.result, + dispose() { + if (disposal !== undefined) + return disposal; + parts.signal.removeEventListener('abort', parts.onAbort); + parts.requestCancel(); + disposal = parts.teardown(); + return disposal; + }, + }; +} +//# sourceMappingURL=out-of-process.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.d.ts new file mode 100644 index 0000000..53cac6b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.d.ts @@ -0,0 +1,60 @@ +/** + * Pure client-safe subagent projection vocabulary. + * + * @module @deepseek-ai/dsh-subagent/projection-types + */ +/** Durable active-turn timing for one descriptor-backed child session. */ +export interface SubagentTimingProjection { + /** Milliseconds accumulated across completed turns after the child's own descriptor. */ + settledMs: number; + /** Same-cut bounds of the currently open turn, when one has not reached `turn/end`. */ + active?: { + /** Start of the open turn. */ + since: number; + /** Latest event time folded into this projection cut. */ + through: number; + }; +} +/** + * Durable identity of one descriptor-backed subagent session: lifecycle mode + * plus creation label, folded last-wins from `subagent/descriptor` events. + * Label strength follows the descriptor schema: a continuable child always + * carries one, a one-shot child may omit it. + */ +export type SubagentIdentityProjection = { + /** A terminal one-shot child. */ + mode: 'one-shot'; + /** Optional durable creation label from the child's descriptor. */ + label?: string; + /** + * Seq of the `subagent/descriptor` event this identity was folded from. + * `seq >= header.seedLength` proves the identity comes from the child's + * OWN log suffix — where a descriptor is immutable once appended — and + * not from a fork seed's replayed ancestor descriptor. + */ + seq: number; +} | { + /** A resumable conversation. */ + mode: 'continuable'; + /** Durable creation label from the child's descriptor. */ + label: string; + /** Seq of the folded descriptor event; see the one-shot arm for the own-suffix proof. */ + seq: number; +}; +declare module '@deepseek-ai/dsh-session-projection/types' { + interface SessionProjectionMap { + /** Active-turn duration for a descriptor-backed subagent session. */ + subagentTiming: SubagentTimingProjection; + /** + * Identity of a descriptor-backed subagent session. `null` ⟺ no valid + * descriptor (missing, malformed, or unrecognized-version — deliberately + * undistinguished). The sentinel is deliberately serializable: a + * value pushed over JSON transports must survive `JSON.stringify` + * losslessly, where an `undefined` field would be dropped and a stale + * identity would survive on the receiving side. The entry itself stays + * non-optional. + */ + subagent: SubagentIdentityProjection | null; + } +} +//# sourceMappingURL=projection-types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.js new file mode 100644 index 0000000..fd835de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.js @@ -0,0 +1,7 @@ +/** + * Pure client-safe subagent projection vocabulary. + * + * @module @deepseek-ai/dsh-subagent/projection-types + */ +export {}; +//# sourceMappingURL=projection-types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.d.ts new file mode 100644 index 0000000..d2c9675 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.d.ts @@ -0,0 +1,48 @@ +/** + * Pure session projections for subagent identity (mode/label) and active-turn + * duration. + * + * @module @deepseek-ai/dsh-subagent/projection + */ +import type { ProjectionDefinition } from '@deepseek-ai/dsh-session-projection'; +import type { SubagentIdentityProjection } from './projection-types.ts'; +interface TimingState { + /** Milliseconds accumulated across completed post-descriptor turns. */ + settledMs: number; + /** Current open interval kept paired inside the fold. */ + active?: { + since: number; + through: number; + }; + /** Latest pre-descriptor turn start, promoted when the child's own descriptor arrives. */ + pendingTurnStart?: number; + /** Whether the fold has crossed a descriptor in this logical log. */ + descriptorSeen: boolean; +} +/** + * Fold turn boundaries around the child's own durable descriptor. + * + * A fork seed may contain an ancestor descriptor and completed turns. Every + * descriptor therefore resets the accumulated state; the healthy catalog + * admits only a child with exactly one descriptor in its own suffix, making + * the final reset the child's authoritative timing origin. + */ +export declare const subagentTimingProjectionDefinition: ProjectionDefinition<'subagentTiming', TimingState>; +interface IdentityState { + /** Identity from the last valid descriptor; absent before one, and after an invalid one. */ + identity?: SubagentIdentityProjection; +} +/** + * Fold the durable mode/label identity from `subagent/descriptor` events, + * last-wins: a fork seed may replay an ancestor's descriptor, and the child's + * own descriptor must override it — the same reset discipline as + * {@link subagentTimingProjectionDefinition}. A malformed or unknown-version + * payload resets to the `null` sentinel instead of throwing, so a fork of a + * healthy ancestor never inherits an identity its own descriptor failed to + * establish — and the reset survives every JSON push frame, so a consumer + * holding the earlier identity replaces it instead of keeping it stale; + * `null` ⟺ no valid descriptor, with the causes deliberately undistinguished. + */ +export declare const subagentIdentityProjectionDefinition: ProjectionDefinition<'subagent', IdentityState>; +export {}; +//# sourceMappingURL=projection.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.js new file mode 100644 index 0000000..283b1df --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.js @@ -0,0 +1,135 @@ +/** + * Pure session projections for subagent identity (mode/label) and active-turn + * duration. + * + * @module @deepseek-ai/dsh-subagent/projection + */ +import { z } from 'zod'; +import { foldSubagentDescriptor } from "./descriptor.js"; +// Zod's optional output includes explicit `undefined`; with +// exactOptionalPropertyTypes the public interface permits omission only. +const projectionSchema = z.object({ + settledMs: z.number().int().nonnegative(), + active: z.object({ + since: z.number().int().nonnegative(), + through: z.number().int().nonnegative(), + }).strict().optional(), +}).strict(); +/** + * Fold turn boundaries around the child's own durable descriptor. + * + * A fork seed may contain an ancestor descriptor and completed turns. Every + * descriptor therefore resets the accumulated state; the healthy catalog + * admits only a child with exactly one descriptor in its own suffix, making + * the final reset the child's authoritative timing origin. + */ +export const subagentTimingProjectionDefinition = { + key: 'subagentTiming', + schema: projectionSchema, + init: () => ({ descriptorSeen: false, settledMs: 0 }), + apply: (state, event) => { + if (event.type === 'turn/start') { + return state.descriptorSeen + ? { ...state, active: { since: event.time, through: event.time } } + : { ...state, pendingTurnStart: event.time }; + } + if (event.type === 'subagent/descriptor') { + const activeSince = state.active?.since ?? state.pendingTurnStart; + return { + descriptorSeen: true, + settledMs: 0, + ...(activeSince === undefined + ? {} + : { active: { since: activeSince, through: event.time } }), + }; + } + if (event.type === 'turn/end') { + if (!state.descriptorSeen) { + if (state.pendingTurnStart === undefined) + return state; + const { pendingTurnStart: _closed, ...next } = state; + return next; + } + if (state.active === undefined) + return state; + const { active, ...rest } = state; + return { + ...rest, + settledMs: state.settledMs + Math.max(0, event.time - active.since), + }; + } + if (state.active === undefined) + return state; + return { ...state, active: { ...state.active, through: event.time } }; + }, + view: state => ({ + settledMs: state.settledMs, + ...(state.active === undefined ? {} : { active: state.active }), + }), + stateVersion: 2, +}; +// The cast bridges only the optional-label arm: Zod's optional output +// includes explicit `undefined`, which exactOptionalPropertyTypes excludes +// from the public interface. The no-value state itself is the serializable +// `null` arm — never `undefined` — so every registry read and push frame +// survives JSON.stringify losslessly. +const identitySchema = z.discriminatedUnion('mode', [ + z.object({ + mode: z.literal('one-shot'), + label: z.string().optional(), + seq: z.number().int().nonnegative(), + }).strict(), + z.object({ + mode: z.literal('continuable'), + label: z.string(), + seq: z.number().int().nonnegative(), + }).strict(), +]).nullable(); +/** Interpret one `subagent/descriptor` event's identity; no value when the payload cannot be trusted. */ +function descriptorIdentity(event) { + let descriptor; + try { + descriptor = foldSubagentDescriptor([event]); + } + catch { + // Only a malformed current-version payload throws in descriptor parsing; + // a projection fold must never throw, so damage folds to no value. + descriptor = undefined; + } + if (descriptor === undefined) + return undefined; + return descriptor.mode === 'one-shot' + ? { + mode: 'one-shot', + ...descriptor.label !== undefined ? { label: descriptor.label } : {}, + seq: event.seq, + } + : { mode: 'continuable', label: descriptor.label, seq: event.seq }; +} +/** + * Fold the durable mode/label identity from `subagent/descriptor` events, + * last-wins: a fork seed may replay an ancestor's descriptor, and the child's + * own descriptor must override it — the same reset discipline as + * {@link subagentTimingProjectionDefinition}. A malformed or unknown-version + * payload resets to the `null` sentinel instead of throwing, so a fork of a + * healthy ancestor never inherits an identity its own descriptor failed to + * establish — and the reset survives every JSON push frame, so a consumer + * holding the earlier identity replaces it instead of keeping it stale; + * `null` ⟺ no valid descriptor, with the causes deliberately undistinguished. + */ +export const subagentIdentityProjectionDefinition = { + key: 'subagent', + schema: identitySchema, + init: () => ({}), + apply: (state, event) => { + if (event.type !== 'subagent/descriptor') + return state; + const identity = descriptorIdentity(event); + return identity === undefined ? {} : { identity }; + }, + view: state => state.identity ?? null, + // Bumped when the identity gained its `seq` field: an older checkpoint row + // would replay into a value the schema rejects, so it must refold instead. + stateVersion: 2, +}; +//# sourceMappingURL=projection.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.d.ts new file mode 100644 index 0000000..f1f22ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.d.ts @@ -0,0 +1,17 @@ +/** + * Settlement of one ONE-SHOT subagent run into a background-Task outcome. Only + * the one-shot background path uses Jobs; continuable children have no Task, + * no per-message result, and no Task cancellation. + * + * @module @deepseek-ai/dsh-subagent/run-settlement + */ +import type { JobOutcome } from '@deepseek-ai/dsh-jobs'; +import type { SubagentRun } from './types.ts'; +/** + * Await the child result, dispose the run, then return its task outcome. Result + * and disposal failures become `failed`; when both fail, both details survive. + * @param run - live run to settle and release. + * @returns outcome after child resources are released. + */ +export declare function settleRun(run: SubagentRun): Promise; +//# sourceMappingURL=run-settlement.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.js new file mode 100644 index 0000000..220f06a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.js @@ -0,0 +1,59 @@ +/** + * Settlement of one ONE-SHOT subagent run into a background-Task outcome. Only + * the one-shot background path uses Jobs; continuable children have no Task, + * no per-message result, and no Task cancellation. + * + * @module @deepseek-ai/dsh-subagent/run-settlement + */ +/** Flatten a child's final output blocks to the task's final text. */ +function finalText(blocks) { + return blocks + .filter((block) => block.type === 'text') + .map(block => block.text) + .join(''); +} +/** + * Map a child result to the task outcome: completed carries final text, + * aborted is killed, and every other reason is failed without partial output. + * @param result - child terminal result. + * @returns outcome for the `ctx.jobs` registration. + */ +function runOutcome(result) { + switch (result.stopReason) { + case 'completed': + return { status: 'completed', output: finalText(result.output) }; + case 'aborted': + return { status: 'killed' }; + case 'error': + case 'max-tokens': + case 'refusal': + return { status: 'failed', detail: result.stopReason }; + // Merge-extensible reasons remain failures with their raw detail. + default: + return { status: 'failed', detail: String(result.stopReason) }; + } +} +/** + * Await the child result, dispose the run, then return its task outcome. Result + * and disposal failures become `failed`; when both fail, both details survive. + * @param run - live run to settle and release. + * @returns outcome after child resources are released. + */ +export async function settleRun(run) { + let outcome; + try { + outcome = runOutcome(await run.result); + } + catch (error) { + outcome = { status: 'failed', detail: String(error) }; + } + try { + await run.dispose(); + } + catch (error) { + const prefix = outcome.detail === undefined ? '' : `${outcome.detail}; `; + return { status: 'failed', detail: `${prefix}dispose failed: ${String(error)}` }; + } + return outcome; +} +//# sourceMappingURL=run-settlement.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.d.ts new file mode 100644 index 0000000..4f50d95 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.d.ts @@ -0,0 +1,308 @@ +/** + * The seam's consumer-facing contracts: request, result, and capability types + * for {@link SubagentProvider}, plus the `subagent/start` and `subagent/end` + * payloads that plugins and hosts observe. Internal control interfaces belong + * with their implementation — the lifecycle observer in `./lifecycle.ts`, the + * continuation host in `./continuation.ts` — so this module stays the published + * surface rather than a bag of everything type-shaped. + * + * @module @deepseek-ai/dsh-subagent/types + */ +import type { Agent, AgentOptions } from '@deepseek-ai/dsh-agent'; +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'; +import type { ObjectJsonSchema, ToolRestriction } from '@deepseek-ai/dsh-tools'; +import type { SubagentDescriptorData } from './descriptor.ts'; +/** Identifies one accepted subagent run across its lifecycle event pair. */ +export type SubagentRunId = Branded<'SubagentRunId'>; +/** + * Brand a string as a {@link SubagentRunId}. + * @param id - the raw run id. + * @returns the same string, branded. + */ +export declare function SubagentRunId(id: string): SubagentRunId; +/** + * Observe-only identifying detail for a published subagent run, carried by + * `subagent/start`. One-shot runs and continuable Activation epochs share this + * payload, so an observer sees the same vocabulary for both. + */ +export interface SubagentRunInfo { + /** Unique identity shared with the paired terminal event. */ + readonly runId: SubagentRunId; + /** + * Provider name recorded when the child was first created. The provider may + * be absent when an accepted one-shot run becomes ready or a persisted + * Activation cold-resumes, because neither lifecycle depends on continued + * registration. + */ + readonly provider: string; + /** The child agent's id. */ + readonly id: SessionId; + /** Snapshot of whether `SubagentRun.localAgent` was present when start fulfilled. */ + readonly local: boolean; +} +/** + * Observe-only outcome detail for a settled subagent run, carried by + * `subagent/end` and paired with one {@link SubagentRunInfo} by `runId`. + */ +export interface SubagentRunEndInfo { + /** Unique identity shared with the paired start event. */ + readonly runId: SubagentRunId; + /** The same provider name carried by the paired start event. */ + readonly provider: string; + /** The child agent's id. */ + readonly id: SessionId; + /** Snapshot of whether `SubagentRun.localAgent` was present when start fulfilled. */ + readonly local: boolean; + /** The terminal stop reason. */ + readonly stopReason: SubagentResult['stopReason']; + /** + * The child's final assistant output, selected by the same rule as + * {@link SubagentResult.output}; absent on infrastructure rejection or when + * the child produced none. + */ + readonly lastAssistantMessage?: ContentBlock[]; +} +/** + * Which START-TIME features a provider supports. Checked by the service before delegating to + * {@link SubagentProvider.start}: a request that needs a capability the chosen provider lacks + * is rejected with a typed error rather than accepted-then-ignored (the "fail loud, no silent + * degradation" rule). These flags describe the ONE-SHOT + * {@link SubagentProvider.start} path, where the provider composes the child; + * continuable children are composed by the continuation manager itself and are + * gated by {@link SubagentProvider.prepareContinuable} instead. Each flag + * corresponds one-to-one to a {@link SubagentStartRequest} option: `depthLimit` + * to `maxDepth`; the other names match. + */ +export interface SubagentCapabilities { + readonly outputSchema: boolean; + readonly depthLimit: boolean; + readonly toolFilter: boolean; + readonly persona: boolean; +} +/** + * What a caller asks for when starting a ONE-SHOT subagent. The tool layer + * builds this from the model's `{ description, prompt }` plus its own config; + * the service validates {@link SubagentCapabilities} against the named provider + * and resolves the durable descriptor before dispatching to + * {@link SubagentProvider.start}. + */ +export interface SubagentStartRequest { + /** Optional short display label persisted with a session-backed child. */ + readonly label?: string; + /** Content delivered as the child's user message. */ + readonly prompt: ContentBlock[]; + /** + * The spawning agent. In-process providers derive workspace, lineage, and + * delegation depth from its durable session state. ACP reads only its cwd, + * and only when no deployment `cwd` override is configured. + */ + readonly parent: Agent; + /** + * Cancellation signal from the spawning context (the tool's `exec.signal`). + * This is the canonical cancellation channel both before and after startup: + * a provider rejects `start()` after cleaning partial resources when it + * fires before the run is published, and cancels the published run's + * remaining turn work when it fires afterward. + */ + readonly signal: AbortSignal; + readonly agentOptions?: AgentOptions; + /** + * Object-rooted JSON Schema within `assertObjectJsonSchema`'s enforced subset. Start rejects + * unsupported schemas or providers without the capability. Data must be plain host-realm JSON; + * a successful child returns the matching value as {@link SubagentResult.structured}. + */ + readonly outputSchema?: ObjectJsonSchema; + /** + * Optional absolute delegation-depth cap for the child being started: its + * computed depth must be less than or equal to this non-negative safe + * integer. Requires {@link SubagentCapabilities.depthLimit}; rejected at + * start otherwise. + */ + readonly maxDepth?: number; + /** + * Optional child tool scoping. Requires {@link SubagentCapabilities.toolFilter}; + * rejected at start otherwise. In-process backends apply it as a scoped + * `tools.restrict()` in the child's creation window: the named tools vanish + * from the child's prompt AND refuse to execute (one visibility), with loud + * unknown-name validation. + */ + readonly toolFilter?: ToolRestriction; + /** + * Optional per-child persona. Requires {@link SubagentCapabilities.persona}; + * rejected at start otherwise. In-process backends register it as a scoped + * `deployment:persona` section on the child, SHADOWING the deployment's + * persona for this child alone — same template semantics as the deployment + * persona (strict `{{…}}` interpolation against the registered variables). + */ + readonly persona?: string; +} +/** + * Provider-facing one-shot request after {@link SubagentRuntime.start} resolves + * the durable child descriptor. + */ +export interface ResolvedSubagentStartRequest extends SubagentStartRequest { + /** Detached descriptor a session-backed provider persists in the child log. */ + readonly descriptor: SubagentDescriptorData; +} +/** + * What the continuation manager asks a provider for while materializing one + * continuable child's FIRST activation. The manager has already reserved the + * durable child identity and owns every later operation, so this request + * carries only what distinguishes a fresh child from one seeded with parent + * history. + */ +export interface ContinuableCreateRequest { + /** The reserved durable child session id, for provider diagnostics. */ + readonly sessionId: SessionId; + /** The delegating parent agent whose history a seeding provider reads. */ + readonly parent: Agent; + /** + * Caller cancellation, which owns preparation only until the manager accepts + * the initial prompt into the child's inbox. + */ + readonly signal: AbortSignal; +} +/** + * A provider's detached contribution to one continuable child's creation. This + * is DATA, never a capability: it carries no Agent, `AgentHandle`, prompt + * delivery, result, disposal, or resume operation, because the continuation + * manager owns the child's whole lifecycle after preparation. + */ +export interface ContinuableCreateSpec { + /** + * Completed-turn prefix of the parent's log to seed the child session with, + * or absent for a fresh child. Same durable contract as + * `CreateAgentOptions.seed`: contiguous from seq 0, lossless JSON, balanced. + */ + readonly seed?: readonly SessionEvent[]; +} +/** + * Why a subagent run ended. Merge-extensible (a backend may add variants); + * consumers branch on the known cases and fall through `default`. The known + * cases mirror the harness turn-end vocabulary so the tool layer can map a + * non-`completed` result to an `isError` tool result. + */ +export interface SubagentStopReasonMap { + /** The child finished its turn normally. */ + completed: 'completed'; + /** Cancelled through the request signal or disposal. */ + aborted: 'aborted'; + /** Model or transport failure. */ + error: 'error'; + /** The child hit its token ceiling before finishing. */ + 'max-tokens': 'max-tokens'; + /** The child declined the task. */ + refusal: 'refusal'; +} +/** The union over {@link SubagentStopReasonMap} — widens automatically as backends merge in variants. */ +export type SubagentStopReason = SubagentStopReasonMap[keyof SubagentStopReasonMap]; +/** + * The terminal outcome of a subagent run, resolved by {@link SubagentRun.result}. + */ +export interface SubagentResult { + /** + * The child's final assistant output is the content of its last non-empty + * assistant message. Empty-content messages, including usage-only messages, + * are skipped. Without a non-empty message, the output is its accumulated + * assistant text stream, or `[]` when the child produced neither. + */ + readonly output: ContentBlock[]; + /** + * The structured result after a requested `outputSchema` was successfully + * satisfied. Requesting a schema does not guarantee presence: a provider can + * end with `stopReason: 'error'` when the child fails or finishes without a + * valid capture. The structured value is validated against the requested + * output schema by the provider; `unknown` here because the seam is + * schema-agnostic. + */ + readonly structured?: unknown; + /** Why the run ended. A non-`completed` reason means `output` may be partial. */ + readonly stopReason: SubagentStopReason; +} +/** + * ONE-SHOT child handle returned after publication. Prompt submission, turn + * work, and infrastructure faults after that boundary belong to {@link result}. + * Consumers await that result and must always {@link dispose} to cancel + * remaining work and reach quiescence. A run is one disposable foreground + * delegation with one result; continuable conversations have no run — the + * continuation manager holds their `AgentHandle` directly and orders every + * turn through the child's own inbox. + */ +export interface SubagentRun { + /** + * Parent-scoped run id. For a local run, this MUST equal the published child + * session id, whose `parentSession` records `request.parent.session.id`; a + * remote provider mints an id unique in the parent namespace. + */ + readonly id: SessionId; + /** + * The exact published in-process child, or `undefined` for a remote run. + * When present, its id is {@link id}; the provider retains no ownership + * implication beyond the run's ordinary {@link dispose} contract. + */ + readonly localAgent: Agent | undefined; + /** + * Resolves with the child's terminal {@link SubagentResult} when the run + * settles. Does NOT reject on a child-level failure — a model/transport + * failure resolves with `stopReason: 'error'` so the consumer maps it to an + * `isError` tool result. Rejects on an infrastructure fault the seam cannot + * represent as a stop reason. + */ + readonly result: Promise; + /** + * Cancel remaining work, reach child quiescence, and release resources. + * Idempotent. + */ + dispose(): Promise; +} +/** + * One registered transport for running child agents. Providers are trusted + * same-process implementations; callers treat descriptors and returned values + * as borrowed immutable data. The service may call one provider concurrently + * for distinct children. Providers isolate operation-local mutable state; a + * shared capacity controller may delay an operation but must not couple its + * settlement or cleanup to a sibling. + */ +export interface SubagentProvider { + /** Unique registry name (e.g. `spawn`, `fork`, `acp`). */ + readonly name: string; + /** The start-time features this provider supports (see {@link SubagentCapabilities}). */ + readonly capabilities: SubagentCapabilities; + /** + * Whether the child sees the parent's completed-turn prefix. This is descriptive, not a + * service-validated start capability: the model-facing tool derives truthful wording from it. + * It says nothing about tool registration, injected services, or authority inheritance. + */ + readonly inheritsParentContext: boolean; + /** + * Establish a ONE-SHOT child and return its handle after publication. + * The service has already validated that every requested start-time + * capability is supported and resolved `request.descriptor`, so a + * session-backed implementation appends that descriptor inside the child's + * initial turn. Before fulfillment, the provider owns setup and cleans any + * unpublished partial resources before rejecting. Ownership transfers on + * fulfillment; subsequent turn or infrastructure failure settles through + * the returned run. Distinct starts may overlap; cancellation, failure, + * result settlement, and disposal remain independent for each run. + */ + start(request: ResolvedSubagentStartRequest): Promise; + /** + * OPTIONAL (continuable-creation capability): contribute the detached + * creation inputs that distinguish this provider's continuable children — + * only whether the child session is seeded with parent history. Method + * presence IS the capability: the service rejects continuable starts on + * providers without it, while a provider that has it may still serve + * ordinary one-shot delegations. + * + * This is the provider's ONLY participation in a continuable child. The + * continuation manager owns identity reservation, composition, Agent + * creation, prompt delivery, cold resume, ownership, and disposal, so a + * provider never sees the child's Agent, handle, turns, or teardown. + * Distinct preparations may overlap; each follows its own signal and returns + * data belonging only to `request.sessionId`. + */ + prepareContinuable?(request: ContinuableCreateRequest): Promise; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.js new file mode 100644 index 0000000..4b00332 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.js @@ -0,0 +1,19 @@ +/** + * The seam's consumer-facing contracts: request, result, and capability types + * for {@link SubagentProvider}, plus the `subagent/start` and `subagent/end` + * payloads that plugins and hosts observe. Internal control interfaces belong + * with their implementation — the lifecycle observer in `./lifecycle.ts`, the + * continuation host in `./continuation.ts` — so this module stays the published + * surface rather than a bag of everything type-shaped. + * + * @module @deepseek-ai/dsh-subagent/types + */ +/** + * Brand a string as a {@link SubagentRunId}. + * @param id - the raw run id. + * @returns the same string, branded. + */ +export function SubagentRunId(id) { + return id; +} +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/package.json new file mode 100644 index 0000000..2ec4b86 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-subagent/package.json @@ -0,0 +1,106 @@ +{ + "name": "@deepseek-ai/dsh-subagent", + "description": "Abstract subagent seam (ctx.subagents): named-provider registry for delegating to child agents", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/subagent/subagent" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client.d.ts", + "default": "./lib/types/client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.6", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.6", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.6", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent-presets": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox-policy": { + "optional": true + }, + "@deepseek-ai/dsh-session-persistence": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection-cache": { + "optional": true + }, + "@deepseek-ai/dsh-jobs": { + "optional": true + }, + "@deepseek-ai/dsh-user-approval": { + "optional": true + } + }, + "devDependencies": { + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.6", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.6", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.6", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.6", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-tools b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-tools new file mode 120000 index 0000000..49af432 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-tools @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-user-approval b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-user-approval new file mode 120000 index 0000000..fd6eee4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/@deepseek-ai/dsh-user-approval @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.6_8b00c1f8ce51e08c328cf93c42b529f7/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-agent-presets b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-agent-presets new file mode 120000 index 0000000..dff57a0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-agent-presets @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-jobs b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-jobs new file mode 120000 index 0000000..95f3330 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-jobs @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..5362978 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..ed04634 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-projection-cache b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-projection-cache new file mode 120000 index 0000000..f44faa3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-session-projection-cache @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.i18n.yaml new file mode 100644 index 0000000..6d443fc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/subagent/subagent/README.md +README.md: ed4a9123a2dfa5b2fa5abc67f4513547feb3d140 +README.zh.md: 3ad2ee5738a210a776d1f0b2746dcbd21d46144c diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.md new file mode 100644 index 0000000..ed4a912 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.md @@ -0,0 +1,154 @@ +# @deepseek-ai/dsh-subagent + +English | [中文](README.zh.md) + +The subagent seam lets one agent delegate work to a child through a named provider. Callers use one service API (`ctx.subagents`); providers decide whether the child runs in this process, in another process, or through a future transport. + +The [subagent family overview](../README.md) maps implementations and model-facing consumers. This package owns the provider registry, shared request and result contracts, durable descriptors, and continuable-child orchestration. Multiple named providers may coexist behind that contract. + +## Service API + +`SubagentRuntime` has these operations: + +| Member | Meaning | +|---|---| +| `registerProvider(provider)` | Register one trusted same-process implementation by name. Registration is effect-scoped; removing it prevents new starts but does not revoke runs already returned to callers. Duplicate names fail loud. | +| `getProvider(name)` | Return the provider, or `undefined` when absent. | +| `list()` | Return provider names in insertion order. | +| `start(name, request)` | Validate an ordinary caller request, resolve its detached `one-shot` descriptor, then await the provider until a real one-shot child is published. Fulfillment returns a holder-owned `SubagentRun`; rejection means the provider has already cleaned every unpublished startup resource, while post-publication turn or infrastructure faults settle through the run. Continuable children never enter through this operation. | +| `startContinuable(spec)` | Establish one durable continuable child and deliver its initial prompt. Resolves with `{ childId, messageId }` when the child's inbox accepts that prompt, without waiting for the turn to start or for the message to reach the Session log; any earlier failure rejects with no ids and rolls the child back entirely. Requires `ctx.agents`, session persistence, and a provider with the `prepareContinuable` capability. | +| `followup(parent, childId, content, { source, signal })` | Deliver one later message from the exact live direct parent as the child's next FIFO turn, matching `Agent.followup()` terminology, and return the accepted `MessageId`. A resident child's inbox accepts it directly (waking a waiting Activation); an absent one cold-resumes from its persisted Session. Requires `ctx.agents`; cold resume also requires session persistence. | +| `interrupt(targetSessionId, authority)` | Interrupt one live continuable child's current turn under a human durable parent address (`{ kind: 'user', parentSessionId }`) or an exact live ancestor Agent (`{ kind: 'ancestor', agent }`). Admission is synchronous and the effect asynchronous: it issues `Agent.cancel(cause, { keepInbox: true })` and returns without waiting for the target to observe the signal. Unclaimed pending inbox work, the Activation, and published descendants are preserved; work already claimed into the interrupted turn is not requeued. An absent target is an accepted no-op; a wrong parent address or a stale, self-targeting, or non-ancestor caller rejects with `UNAUTHORIZED`. | +| `reportFrom(child, content, { delivery, signal })` | Deliver one selected message from the exact live continuable child to its exact live direct parent and return the accepted stable `MessageId`. Quiet delivery injects context; waking delivery submits one later parent turn. | +| `registerContinuableSetup(contribution)` | Compose an optional deployment capability into each continuable child's unpublished scope, with immediate revocation from resident children. | +| `drainContinuableDescendants(parents)` | Close admission below exact live host-owned parent Agents, stop only their visible continuable descendants, await materializations admitted below those roots through publication or rollback, then release the selected forests child-first. The cutoff lasts until each exact parent leaves the registry; unrelated parent forests and manager-wide admission remain live. | +| `listChildren(parentSessionId, signal?)` | List direct session-backed subagents with their `one-shot`/`continuable` mode, `running`/`inactive` activity, origin-classified one-level `hasChildren` hint, and per-child diagnostics, ordered by `createdAt` then id, without loading or resuming them. Reads the live session store and optional session persistence directly (live-only enumeration when persistence is absent) and requires the mounted `sessionProjections` registry; it does not require `ctx.agents`, the continuation manager, or any query service. | +| `listDescendants(rootSessionId, signal?)` | Flatten the root's complete session tree in stable pre-order from the same live-preferred corpus, adding each subagent entry's durable `parentId` and root-relative `depth`. Ordinary sessions and one-shot children remain traversal nodes so continuable descendants below them are discovered. Identity, diagnostics, dependencies, and cancellation follow `listChildren()`. | + +`SubagentStartRequest.label` is an optional short durable display label for a session-backed one-shot child. Model-facing delegation supplies its existing `description`; lower-level callers need not invent presentation metadata. Continuable starts always carry their own required label. `signal` is required and is the canonical cancellation channel for a one-shot `start`. An abort before publication makes `start()` reject after rollback; an abort after publication cancels the returned run's remaining turn work without hiding its id. The request may also select a model, require structured output, cap delegation depth, restrict child tools, or set a child persona. For a continuable start or follow-up, the caller signal owns lookup, materialization, and admission only until inbox acceptance; afterward the manager owns the Activation independently, so later caller cancellation neither cancels the accepted turn nor disposes the child. + +Follow-up authority comes from the exact live direct parent recorded in the child's durable header. Cold resume checks that authority before reconstruction and again in the final no-await inbox-admission span, so a parent unregistered or replaced during materialization cannot authorize delivery. The `source` on a follow-up records who supplied the delivered message and grants no authority. + +Same-process requests, descriptors, results, and event payloads are trusted typed values borrowed as immutable. The service does not clone or freeze them; serialization and hostile-input validation belong at actual process, worker, persistence, and model boundaries. + +## Capabilities + +Start-time features are advertised in `provider.capabilities` because the service must reject an unsupported one-shot request before child creation: + +- `outputSchema` — enforce a structured final result. +- `depthLimit` — enforce `maxDepth`. +- `toolFilter` — apply the requested child tool restriction. +- `persona` — apply a per-child persona. + +Every in-process child is composed by one call, `applyChildComposition(childCtx, parent, composition)`, which joins the parent's agent-preset composition before applying the child's own persona and tool filter. The join is what gives the child its capabilities: with every model-facing row on the agent plane, a child that joined nothing would reach the model with an empty tool registry ([`dsh-agent-presets`](../../preset/agent-presets/README.md)). Taking the parent as a parameter is deliberate — it makes composing a child WITHOUT that join unrepresentable at the call sites, which is the defect the one call exists to prevent. A deployment composing no preset roster joins nothing and needs nothing: its model-facing rows sit in the host composition, where the child already resolves them through the tool registry's global layer. + +`childSessionMeta()` records the joined preset id on the child's durable header for the same reason a top-level session records its own: the preset decides the tool schemas and prompt sections the model saw, so a cold read of the child's history has to rebuild that composition rather than the deployment default. It is read from the parent's live scope chain, not from the parent header, because a parent that switched preset while blank runs on the newer composition while its header still names the older one. + +Continuable creation is the optional `SubagentProvider.prepareContinuable?()` method: its presence is the capability check, so the service rejects a configured continuable start on a provider without it, while a provider that has it may still serve ordinary one-shot delegations. The method returns only a detached `ContinuableCreateSpec` (`{ seed? }`) — data, never a capability: it carries no Agent, `AgentHandle`, prompt delivery, result, disposal, or resume operation, because the continuation manager owns identity reservation, composition, Agent creation, prompt delivery, cold resume, ownership, and disposal after preparation. A one-shot `SubagentRun` represents one disposable foreground delegation with one result and no cold-resume operation. The service may invoke one provider concurrently for distinct siblings: each start or preparation owns its mutable state and cancellation path, and one operation's failure, result, or cleanup must not settle or release another. A provider may queue its own capacity internally without changing that independence contract. + +## The durable descriptor + +The Service Definition owns the versioned `subagent/descriptor` session event vocabulary (`src/descriptor.ts`): `snapshotSubagentDescriptor()` validates and detaches the record before provider work, and `foldSubagentDescriptor()` validates the complete current-version payload before recovering it from a loaded child log. Every local session-backed start appends one descriptor with the provider name and lifecycle `mode`. A `one-shot` descriptor optionally carries the caller-owned durable display `label`; a `continuable` descriptor requires its durable creation label and additionally records resolved child `agentOptions.provider`/`model` and optional `persona`/`toolFilter` for cold resume. These are explicit fields, never the merge-extensible `AgentOptions` object, so an unrelated extension value cannot break continuation. The descriptor omits `subagentDepth` (the persisted header's `delegationDepth` is the monotone floor) and `outputSchema` (an Activation's result contract). The event is log-only: no `surfaceOp`, absent from model history, and retained by the append-only log across compaction. Malformed current-version payloads are corrupt; unsupported versions cannot be classified by this runtime. + +## Delegation depth + +The seam owns the depth vocabulary shared by Service Providers and Consumers: the `AgentOptions.subagentDepth` declaration, `assertSubagentMaxDepth`, and `delegationDepthOf(agent)`. The persisted `SessionHeader.delegationDepth` is authoritative and monotone — runtime options may deepen the count but never lower it, so a resumed child cannot be re-counted as top-level. + +`inheritsParentContext` is descriptive rather than enforceable. It says only whether the child sees completed parent conversation history (`fork` does; `spawn` and the out-of-process one-shot providers do not), not whether it inherits tools, services, or authority. + +## Delegated policy + +Both in-process delegation paths fix the child's permission scope at the delegation boundary through the shared child-agent helpers. `captureDelegatedPolicyOverrides(parent)` snapshots the parent session's explicit sandbox override (`sandboxPolicy.overrideOf()`) and pins the child's approval policy to `'never'` whenever the approval capability is composed — regardless of the parent's own policy — so a delegated child acts only within its inherited sandbox scope and every ask (for example a `sandbox_permissions` escalation) is rejected deterministically instead of waiting on a prompt no one is watching (both services are optional `ctx.get` consumers). `appendDelegatedPolicyOverrides()` writes each value onto the child's own log as a `source: 'delegation'` `sandbox/mode` or `approval/policy` event during unpublished setup, after any fork seed — so fresh policy wins stale seed state and the child's effective policy stays reconstructable from its log alone. The sandbox deployment default is never copied: an unswitched parent stamps no `sandbox/mode` and its child follows the deployment default dynamically. A continuable start captures before its first await and seeds only fresh materialization; a cold resume replays the persisted delegation events instead of re-capturing the parent, so a parent switch after creation never retroactively changes a durable child. Every in-process child also receives a scoped runtime-context statement (`subagent:delegation`) telling it the scope is fixed and that a task needing wider access ends with a reported limitation, not retries. See the [one-shot](../../../.agents/notes/implemented/feature/2026-07-25-subagent-policy-inheritance.md) and [continuable](../../../.agents/notes/implemented/feature/2026-08-10-continuable-subagent-policy-inheritance.md) delegation-policy Agent Notes. + +## One-shot ownership and lifecycle + +`provider.start(request): Promise` is the ownership-transfer boundary; the delegation tool also uses it inside its one-shot Task-backed background path. Before fulfillment, the provider owns setup and must cancel, roll back, and quiesce unpublished resources on every failure. After fulfillment, the caller owns the run and must call `dispose()` on every path; remaining prompt and turn work belongs to `SubagentRun.result`. + +`SubagentRun.result` resolves to `{ output, structured?, stopReason }`. Child-level failures resolve with a non-`completed` reason; only an infrastructure fault that the seam cannot represent may reject. `dispose()` is idempotent, cancels remaining work, and waits for both result settlement and child-resource quiescence. A result rejection remains on `result`; `dispose()` rejects only for an independent resource-release failure. `output` and the `subagent/end` event's `lastAssistantMessage` use the exported `AssistantOutputFold`/`finalAssistantOutput` helpers to select the child's last non-empty assistant message, or its accumulated assistant text when no such message exists. `output` is `[]` and the event field is absent when the child produced neither ([`SubagentResult.output`](../../../docs/subsystems/subagent.md#the-terminal-result-subagentresult) owns the result contract). + +A local run publishes an ordinary child agent/session before `start()` fulfills, returns that shared session id as `SubagentRun.id`, exposes the exact child as `SubagentRun.localAgent`, records `request.parent.session.id` in the child's `parentSession` header, and appends the resolved descriptor inside its initial turn. Remote providers instead mint a parent-scoped lifecycle id and return `localAgent: undefined`; without a local child session, their one-shot runs are not part of trace-backed enumeration. + +## Continuable children and Activations + +A continuable child has one durable Session and at most one process-local **Activation** — one residency epoch for a reconstructed child Agent, not a request, result, cancellation, or Task boundary. The Agent inbox is the only turn queue, so the continuation manager owns residency while the Agent loop owns all turn ordering and execution. No continuable path creates a Task or an intermediate result-bearing wrapper. + +The manager derives three internal residency conditions from Agent quiescence and the owned-child set rather than maintaining a second state machine: running (an active admission, open turn, or waking inbox work), waiting (quiescent but still owning at least one undisposed child), and settled (quiescent with every owned child disposed, so the manager disposes the `AgentHandle` and removes the Activation). Every continuation message uses `Agent.followup()` and becomes one FIFO turn with no steering of the current turn. Routing depends only on residency: running enqueues, waiting wakes the same Agent, and an absent Activation cold-resumes a new one. + +The manager reserves the child identity, resolves the durable descriptor, calls `ctx.agents.create()` (or `ctx.agents.resume()` for cold resume) through a private activation-owner scope, installs the returned `AgentHandle` in the Activation, establishes any continuable-parent ownership, and then submits the prompt. Cold resume never dispatches through a provider because the persisted Session already holds the initial prefix and the folded descriptor is the whole reconstruction input. + +### Settlement delivery + +When a resident Activation settles, the manager tells the child's durable direct parent, in the parent's own turn stream, that the child produced everything it is going to. Delivery is unconditional for every child whose id a caller actually received: it does not consider whether the child called `report`, because the endings that most need an account — a token ceiling, a model failure, cancellation, teardown — are exactly the ones where the child never got to choose. A materialization rolled back before its first accepted message stays silent, since that caller was told the child was not established. The message carries the epoch's stop reason, its final assistant content when it produced any, and durable provenance `{ kind: 'subagent-settled', form: 'notice', senderSessionId: }` — a different source kind from a child-authored `subagent-report`, so a transcript never credits the child with words the runtime wrote. + +Two ordering rules make the delivery reliable rather than lucky, and both are why this belongs to the manager instead of an external `subagent/end` listener. First, the send happens **before** the child's ownership release, while the parent still counts the child and is therefore structurally unable to be judged settled. Second, a parent that is itself a resident Activation receives the message through the same waking-admission accounting as a report, so the window between the synchronous send and the microtask that admits it is not mistaken for quiescence — `Agent.status` folds context maintenance into `idle`, and a waking send behind maintenance only arms a deferred wake. Without either rule the parent can be disposed with the notice still in an inbox that `cancel()` clears, which loses it silently. + +An idle parent receives the notice as one ordinary later turn. A busy parent is steered into its nearest step boundary instead, so several children settling together cost one step rather than one turn each; steering rather than injecting also means a driver that retires between the status read and the send still claims the message. A parent whose own lineage is already draining receives the notice by injection, with no wake at all: `Agent.followup()` on a quiescent parent starts a turn and `cancel()` does not arm against a later one, so waking during teardown would spend a model request on an Agent its host is about to dispose — once per tree layer, since each layer's notice then wakes the layer above it. The injected message reaches a parent that is still reading its inbox, and the log records the account either way, but it does not outlive that parent's own disposal: `AgentHandle.dispose()` is a `keepInbox: false` cancel, which durably cancels an unclaimed notice. A resumed parent therefore has no pending notice to read: `list_agents` tells it which children exist and whether each is live or stored, while the outcome itself stays in the child's own Session, which a `send_message` reaches by resuming that child. A parent that has left the registry is not an error: the notice is dropped and the child's own Session remains the durable record. Delivery never blocks or fails teardown — a rejected send is logged, because retaining a child to retry a notice would pin its whole ancestry in `waiting` forever. + +A continuation-managed parent Activation records each child Session id in an `ownedChildren` set before the child can run and disposes only after every owned child Activation completes `AgentHandle` disposal (child-first). Teardown propagates Agent cancellation top-down before awaiting slow descendants, while handle release remains child-first. Top-level and other non-continuation Agents have no Activation and stay outside this waiting graph. Final settlement awaits a best-effort `ctx.sessions.flush(child.session)` before handle disposal. A listener rejection is logged without failing the Activation because listener participation does not identify a persistence backend; the persisted state may therefore be missing or stale on resume. + +## Lifecycle events + +The service emits a `subagent/start`/`subagent/end` pair for each one-shot run and each resident continuable Activation epoch, so continuable children are observable with the same vocabulary as one-shot runs without exposing whether the manager materialized, woke, or cold-resumed them. For a one-shot start it attaches the result observer before the synchronous `subagent/start`, so even an already-settled child still produces `subagent/start` before `subagent/end`; a continuable epoch that fails before residency emits neither edge. The pair shares a service-minted `runId`; the `local` flag is snapshotted from the provider's exact `localAgent` (always true for a continuable child), so observers never infer run identity or locality from reusable provider/session names. The `provider` field contains the provider name recorded when the child was first created rather than claiming current registration: an accepted one-shot run may settle after provider removal, and a cold-resumed epoch reads the initial provider name from its descriptor without calling or registering that provider. + +Run events are scoped to the delegating parent. Every listener is independently contained: a synchronous throw or rejected returned promise is logged without starving peer listeners or changing the run. + +Provider additions and removals also emit `subagent/provider-added` and `subagent/provider-removed`. Consumers such as the model-facing tool use those events because Cordis may load sibling plugins concurrently; configuration order does not prove registration order. + +Continuable children do not create `SubagentRun` or Jobs. The continuation manager directly owns one process-local Activation and retained `AgentHandle` per resident child Session, uses the Agent inbox as the only FIFO, and cold-resumes from the durable descriptor. Exact live direct-parent identity authorizes parent-to-child delivery. Exact live child identity authorizes reports; the manager derives the recipient from durable `parentSession`, and `MessageSource` records the sender without granting authority. Interrupt authority is deliberately wider than delivery authority: a human presents the durable direct-parent address so a live child stays stoppable while its parent Agent is offline, and any exact live ancestor recorded in the Activation's materialization lineage may stop its descendant, because stopping a turn is idempotent and delivers no content. + +When `ctx.sessionProjections` is available, the service registers two projection units. `subagentTiming` resets at each descriptor so a fork seed's ancestor work cannot enter the child's total, then accumulates `turn/start` → `turn/end` active time and retains same-cut `active.since` and `active.through` bounds for an open turn; while that turn remains open, `active.through` follows the latest folded event, giving an inactive consumer a conservative crash bound without mixing in newer session metadata. `subagent` folds the durable identity — mode plus creation label — from `subagent/descriptor` events with the same last-wins reset discipline, so a fork seed's ancestor descriptor stands only until the child's own overrides it; a malformed or unrecognized-version payload folds to the serializable `null` sentinel — indistinguishable from a log with no descriptor, and surviving every JSON push frame so a consumer replaces a stale identity instead of keeping it — and never throws. + +`registerContinuableSetup()` lets optional packages add child-scoped capabilities without teaching the continuation manager their names. Contributions install synchronously before Activation publication, roll back with failed setup, and are released with the child scope. New grants wait for the next Activation, while contribution removal revokes every resident installation immediately. + +## Collection model + +The model-facing tool collects synchronously by default: it awaits the child result and disposes the run before returning. One-shot background delegation registers a plain Task in the tool, whose generic status, collection, and cancellation tools own later interaction, and persists its model-supplied `description` as the optional display label. Continuable background delegation calls `ctx.subagents.startContinuable()` and returns only the durable child id; the child owns its own turns from inbox acceptance, so there is no Task and no result promise — a caller sends later work with the `send_message` follow-up tool, and `interrupt()` stops only the current turn without disposing the child, and the durable child Session remains the source of the child's detailed output. The continuation manager exists only while `ctx.agents` is available, and session persistence is resolved per continuation operation. Independently, `listChildren()` enumerates the live-preferred merge of the live session store and optional session persistence — live-only when persistence is absent, since a cold child cannot be resumed then either — and serves each child's durable mode/label from the registered `subagent` projection unit: the registry's watermark snapshot for a live child; for a cold one, a durable projection-cache row when it serves an own-suffix identity — its `seq` gate proves the value postdates the fork seed, where a child's own descriptor is immutable once appended — else one bounded-concurrency persistence inspection folded through the registry, whose result must still name the enumerated lifecycle (a re-published id degrades to a `corrupt` diagnostic). A throwing cache read renders no verdict — the cache is derived data — and silently falls through to that authoritative re-fold. The projection fold is the single classification authority; listing parses no descriptor itself. A served identity produces a child row; a settled candidate whose fold served no identity is a `corrupt` diagnostic, a failed inspection is a transient `unavailable` retried on the next listing, and a running candidate without an identity yet is omitted (the creation window before its descriptor is appended). It never consults the continuation manager, Agent registrations, Activations, or providers. Each child row derives its read-time `hasChildren` hint from merged headers carrying durable `origin: 'subagent'`; it does not read descendant event logs, and the descriptor-backed child catalog remains authoritative when expanded. Service consumers such as a UI can retain both modes and choose a fallback for an unlabeled one-shot child; the model-facing `list_agents` tool projects only `continuable` entries and refines status through the live Agent registry and maps storage-only to its resumable-not-terminal `ready` (`running`/`idle`/`ready`) and walks `listDescendants()` for its `descendants` scope. The listing forwards the caller's signal to every persistence read, checks cancellation around each of those awaits, and reports every observed abort as `SubagentError` code `CANCELLED`; an unmounted projection registry fails loud with `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE`, and a missing session store with `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE`. See the [background subagent tasks Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-background-subagent-tasks.md), the [continuable background subagents Agent Note](../../../.agents/notes/implemented/feature/2026-07-21-continuable-background-subagents.md), the [durable catalog Agent Note](../../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md), the [merged-service Agent Note](../../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md), the [capability-seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md), and `src/types.ts` for the complete contracts. + +Continuable Activations await a best-effort final session flush without treating listener participation as durability confirmation. One-shot runs retain best-effort session checkpointing, so a completed one-shot child is discoverable after disposal only when its session actually reached persistence; the service does not invent a catalog entry from Task history when that checkpoint is absent. + +## Model Experience + +### Settlement notice + +#### What the model sees + +One user-role parent message opening with the outcome — `Background subagent finished and will do no further work unless you send it more.`, or the matching line for a child that was stopped, ran out of room, declined, or failed — followed by `Its closing message:` and the child's final assistant content, or `It left no closing message.` when it produced none. This is the service's only direct parent-side contribution; delegation schemas, parent continuation and discovery, and the child-scoped `report` belong to `dsh-tool-subagent`, `dsh-tool-subagent-control`, and `dsh-tool-subagent-report`. + +#### Token effect + +One notice per settled Activation in the parent's request, sized by the child's final message. A child that both reports and settles costs the parent both. + +#### KV Cache effect + +Append-only in the parent: the notice follows its reusable request prefix. Reaching an idle parent starts one independent model request; reaching a busy one does not. + +### Child delegation-scope statement + +#### What the model sees + +Every in-process child's runtime-context snapshot carries the `subagent:delegation` statement below, after the sandbox-policy and approval-policy sentences. + +##### The delegation-scope statement + +```markdown +You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the job needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it. +``` + +#### Token effect + +One fixed statement in each child's runtime-context snapshot; none in the parent's requests. + +#### KV Cache effect + +Prefix-stable within a child: the statement never changes during the child's lifetime, so it is written once into the first runtime-context snapshot. Parent-side, no direct invalidation; the named tool consumers own any request-prefix changes. + +## Known Limitations and Deferred Work + +- **ACP children remain one-shot and are not trace-enumerable** — an ACP run has no local child session in the parent's session corpus. An ACP `prepareContinuable` requires persisting the remote session id in provider-specific descriptor data and a per-child continuation advertisement, since ACP `loadSession` support is negotiated per child rather than established by the method's presence. Remote providers also require a separate Activation ownership contract with equivalent authenticated control and child-first quiescence before they support continuable children. +- **No host-user continuation** — `followup()` requires the exact live direct parent. Only `interrupt()` accepts a durable parent-address user authority, because stopping a turn is idempotent and delivers no content; a future host adapter needs a concrete authenticated interaction before the seam gains a user delivery capability. +- **No current-turn steering** — continuable messages and waking reports enqueue later turns; neither redirects an open turn. +- **Wake gap during cancellation convergence** — a waking follow-up accepted after the interrupt signal is issued but before the active driver becomes idle remains queued until another waking send. Issue #1838 owns the agent-loop wake latch, which also affects ordinary session cancellation. +- **Process-local residency** — the Activation inbox and ownership graph do not coordinate two harness processes; concurrent access to one persistence store still requires a durable mailbox and cross-process lease protocol. +- **No replay of accepted-but-unlogged messages** — only messages written to the child Session log are reconstructable with the source that supplied them. A crash may lose an accepted initial prompt or follow-up that never reached the log; a later authorized message can cold-resume the child, but the lost message is not replayed automatically. +- **No durable report mailbox** — reports require a live direct parent and provide acceptance identity rather than exactly-once delivery or a read receipt. +- **Lifecycle events are observe-only** — a run-affecting `subagent/end` continuation or decision API waits for a concrete consumer. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.zh.md new file mode 100644 index 0000000..3ad2ee5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/README.zh.md @@ -0,0 +1,154 @@ +# @deepseek-ai/dsh-subagent + +[English](README.md) | 中文 + +subagent seam 允许一个 agent(智能体)通过具名提供方把工作委派给子 agent。调用方统一使用 `ctx.subagents` 服务 API;提供方决定子 agent 在当前进程、其他进程,还是通过未来的传输方式运行。 + +[subagent 家族概述](../README.md)列出了实现和面向模型的消费方。本包负责提供方注册表、共享请求和结果约定、持久描述符以及可继续子级编排。多个具名提供方可以在该约定背后共存。 + +## 服务 API + +`SubagentRuntime` 具有以下操作: + +| 成员 | 含义 | +|---|---| +| `registerProvider(provider)` | 按名称注册一个可信的同进程实现。注册受 effect 作用域约束;移除注册会阻止新的启动,但不会撤销已返回给调用方的运行。重复名称会明确报错。 | +| `getProvider(name)` | 返回提供方;不存在时返回 `undefined`。 | +| `list()` | 按插入顺序返回提供方名称。 | +| `start(name, request)` | 校验普通调用方请求,解析其已分离的 `one-shot` 描述符,然后等待提供方发布真正的一次性子 agent。兑现时返回由持有方拥有的 `SubagentRun`;如果调用被拒绝,提供方已经清理所有尚未发布的启动资源。发布后的轮次故障或基础设施故障则通过该 run 结算。可继续子 agent 绝不通过此操作进入。 | +| `startContinuable(spec)` | 建立一个持久化的可继续子 agent,并投递其初始提示词。子 agent 的 inbox 一接受该提示词,调用就会兑现为 `{ childId, messageId }`,无需等待轮次开始,也无需等待消息写入会话日志。在此之前发生的任何失败都会使调用被拒绝,不返回任何 id,并完全回滚该子 agent。要求 `ctx.agents`、会话持久化以及具备 `prepareContinuable` 能力的提供方。 | +| `followup(parent, childId, content, { source, signal })` | 将来自确切在线直接父级的一条后续消息作为子 agent 的下一个 FIFO 轮次投递,术语与 `Agent.followup()` 一致,并返回被接受的 `MessageId`。驻留中的子 agent 由其 inbox 直接接受(唤醒处于 waiting 的 Activation);不驻留的则从其持久化会话冷恢复。要求 `ctx.agents`;冷恢复还要求会话持久化。 | +| `interrupt(targetSessionId, authority)` | 凭人类出示的持久化父级地址 `{ kind: 'user', parentSessionId }`,或确切在线的祖先 Agent `{ kind: 'ancestor', agent }` 进行授权,中断一个在线可继续子级的当前轮次。准入判定同步完成,但取消异步生效:该操作发出 `Agent.cancel(cause, { keepInbox: true })` 后立即返回,不等待目标观察到信号。尚未领取的待处理 inbox 工作、Activation 和已发布的后代均会保留;已经领取到被中断轮次中的工作不会重新入队。目标不存在时视为已接受的空操作;错误的父级地址,或陈旧、指向自身、并非祖先的调用方,会以 `UNAUTHORIZED` 被拒绝。 | +| `reportFrom(child, content, { delivery, signal })` | 从确切在线可继续 child 向其确切在线直接 parent 投递一条选中消息,并返回已接受的稳定 `MessageId`。静默投递会注入上下文;唤醒投递会提交一个后续 parent 轮次。 | +| `registerContinuableSetup(contribution)` | 把一项可选部署能力组合到每个可继续 child 尚未发布的作用域中,并支持从驻留 child 立即撤销。 | +| `drainContinuableDescendants(parents)` | 在由 host 拥有的确切在线父级 Agent 之下关闭准入,只停止这些父级可见的可继续后代;等待已在这些根节点下获准的物化过程完成发布或回滚后,再按子级优先顺序释放所选的各棵树。该截止状态会持续到每个确切父级离开注册表;无关的父级树仍在线,管理器全局准入仍保持开放。 | +| `listChildren(parentSessionId, signal?)` | 按 `createdAt`、再按 id 的顺序列出由会话支撑的直接 subagent,包括其 `one-shot`/`continuable` 模式、`running`/`inactive` 活动状态、根据 origin 分类得出的一层 `hasChildren` 提示,以及每个子级的诊断信息,且不会加载或恢复它们。该操作直接读取在线会话存储和可选的会话持久化(没有持久化时只枚举在线子级),并要求已挂载 `sessionProjections` 注册表;不要求 `ctx.agents`、继续执行管理器或任何查询服务。 | +| `listDescendants(rootSessionId, signal?)` | 从同一份在线优先语料按稳定 pre-order 展平根的完整会话树,并为每个 subagent 条目附加持久 `parentId` 与相对根的 `depth`。普通会话与一次性 child 仍作为遍历节点,因此其下的可继续后代仍可发现。身份、diagnostic、依赖与取消约定均沿用 `listChildren()`。 | + +`SubagentStartRequest.label` 是由会话支撑的一次性 child 所使用的可选简短持久化显示标签。面向模型的委派会提供其已有的 `description`;底层调用方无需凭空构造展示元数据。可继续启动始终携带自身的必填标签。`signal` 是必填项,也是一次性 `start` 的规范取消通道。发布前中止会使 `start()` 在回滚后拒绝;发布后中止会取消已返回 run 的剩余轮次工作,但不会隐藏其 id。请求还可以选择模型、要求结构化输出、限制委派深度、约束子 agent 工具或设置子 agent persona。对于可继续启动或后续操作,调用方信号只负责 inbox 接受前的查找、物化和准入;此后,Activation 由管理器独立拥有,因此调用方取消既不会取消已接受的轮次,也不会 dispose(资源释放)子 agent。 + +后续操作的权限来自子 agent 持久化 header 中记录的确切在线直接父级。冷恢复会在重建前检查该权限,并在最终无 await 的 inbox 准入区间再次检查,因此在物化期间被注销或替换的 parent 无法授权投递。后续操作上的 `source` 记录谁提供了所投递的消息,不授予任何权限。 + +同进程请求、描述符、结果和事件 payload 都是可信的类型值,并按不可变约定借用。服务不会克隆或冻结它们;序列化和不可信输入校验属于真实的进程、worker、持久化和模型边界。 + +## 能力 + +启动时功能通过 `provider.capabilities` 声明,因为服务必须在创建子 agent 前拒绝不受支持的一次性请求: + +- `outputSchema`:强制执行结构化最终结果; +- `depthLimit`:强制执行 `maxDepth`; +- `toolFilter`:应用请求的子 agent 工具限制; +- `persona`:应用每个子 agent 独立的 persona。 + +每个进程内子 agent 都通过一次 `applyChildComposition(childCtx, parent, composition)` 调用完成组装:先加入父级的 agent-preset 组合,再应用子 agent 自己的 persona 和工具限制。加入父级组合正是子 agent 获得能力的途径:所有面向模型的行都位于 agent 平面,完全没有加入任何组合的子 agent 抵达模型时会看到空的工具注册表(见 [`dsh-agent-presets`](../../preset/agent-presets/README.md))。将父级作为参数是刻意设计:这让“组装子 agent 却不做该加入”在各调用点无法表达,而这正是这一次调用所要杜绝的缺陷。未组装 preset roster 的部署不加入任何组合、也不需要加入;其面向模型的行位于宿主组合中,子 agent 已能通过工具注册表的全局层解析到它们。 + +`childSessionMeta()` 把所加入的 preset id 记在子 agent 的持久化 header 上,理由与顶层会话记录自己的那一个相同:preset 决定了模型所见的工具 schema 与提示段,因此冷读子 agent 的历史时必须重建那份组装,而不是部署默认值。该值从父方**活着的** scope 链读取,而不是从父方 header 读取,因为在空白期切换过 preset 的父方运行在更新的那份组装上,而它的 header 仍写着旧的那个。 + +可继续创建对应可选的 `SubagentProvider.prepareContinuable?()` 方法:方法是否存在就是能力检查,因此服务会在没有该方法的提供方上拒绝已配置的可继续启动,而具备该方法的提供方仍可服务普通一次性委派。该方法只返回已分离的 `ContinuableCreateSpec`(`{ seed? }`)。它只是数据,不携带任何能力:不包含 Agent、`AgentHandle`、提示词投递、结果、dispose 或恢复操作。准备完成后,身份预留、组合、Agent 创建、提示词投递、冷恢复、所有权和 dispose 均由继续执行管理器负责。一次性 `SubagentRun` 表示一次可 dispose 的前台委派,只有一个结果,且没有冷恢复操作。服务可以针对不同的同级子 agent 并发调用同一提供方:每次启动或准备都拥有各自的可变状态和取消路径,一项操作的失败、结果或清理不得使另一项操作结算或释放。提供方可以在内部按自身容量排队,但不得改变这项独立性约定。 + +## 持久化描述符 + +该 Service Definition 拥有版本化的 `subagent/descriptor` 会话事件词汇(`src/descriptor.ts`):`snapshotSubagentDescriptor()` 会在提供方工作之前校验并分离记录,`foldSubagentDescriptor()` 则会在从已加载子 agent 日志中恢复描述符之前,校验当前版本的完整 payload。每次由本地会话支撑的启动都会追加一个带有提供方名称与生命周期 `mode` 的描述符。`one-shot` 描述符可以携带调用方拥有的可选持久化显示 `label`;`continuable` 描述符要求其持久化创建标签,并另外记录已解析的子 agent `agentOptions.provider`/`model`,以及用于从持久化存储恢复的可选 `persona`/`toolFilter`。这些是显式字段,绝不是可通过合并扩展的 `AgentOptions` 对象,因此无关的扩展值不会破坏继续执行。描述符省略 `subagentDepth`(持久化 header 的 `delegationDepth` 是单调下界)和 `outputSchema`(单次 Activation 的结果约定)。该事件只进入日志:不含 `surfaceOp`,不进入模型历史,并由仅追加日志跨压缩(compaction)保留。格式错误的当前版本 payload 属于损坏;本运行时无法对不受支持的版本进行分类。 + +## 委派深度 + +该 seam 拥有 Service Provider 和 Consumer 共享的深度词汇:`AgentOptions.subagentDepth` 声明、`assertSubagentMaxDepth` 和 `delegationDepthOf(agent)`。持久化的 `SessionHeader.delegationDepth` 具有权威性且单调:运行时选项可以增大委派深度,但绝不能将其降到这个下界以下,因此恢复后的子 agent 不会被重新计为顶层。 + +`inheritsParentContext` 只用于描述,不能强制执行。它仅说明子 agent 是否能看到父级已完成的对话历史(`fork` 可以;`spawn` 和各进程外一次性提供方不可以),不表示是否继承工具、服务或权限。 + +## 委派策略 + +两条进程内委派路径都会通过共享的子 agent 辅助函数,在委派边界固定子 agent 的权限范围。`captureDelegatedPolicyOverrides(parent)` 会为父会话的显式沙箱覆盖项(`sandboxPolicy.overrideOf()`)创建快照,并在审批能力已组合时将子 agent 的审批策略固定为 `'never'`,无论父级自身采用何种策略。这样,被委派的子 agent 只能在继承的沙箱范围内行动,每次审批请求(例如 `sandbox_permissions` 升权)都会被确定性拒绝,而不会等待无人处理的提示(这两个服务都是可选的 `ctx.get` 消费方)。`appendDelegatedPolicyOverrides()` 则在未发布的设置阶段、在任何 fork 种子之后,把每个值作为一条 `source: 'delegation'` 的 `sandbox/mode` 或 `approval/policy` 事件写入子 agent 自己的日志。因此,新捕获的策略会覆盖种子中的陈旧状态,而子 agent 的生效策略始终可以仅凭其日志重建。沙箱的部署默认值绝不复制:未切换的父级不会记录 `sandbox/mode`,其子 agent 会动态跟随部署默认值。可继续启动会在第一次 await 前捕获策略,并且只为全新物化写入这些委派事件;冷恢复只会重放已持久化的委派事件,不会重新捕获父级策略,因此创建之后的父级切换绝不会追溯性地改变持久化子 agent。每个进程内子 agent 还会收到一条作用域内的运行时上下文声明(`subagent:delegation`),告知其权限范围已固定,需要更宽访问的任务应以上报限制收尾,而不是重试。参见[一次性](../../../.agents/notes/implemented/feature/2026-07-25-subagent-policy-inheritance.md)与[可继续](../../../.agents/notes/implemented/feature/2026-08-10-continuable-subagent-policy-inheritance.md)两篇委派策略 Agent Note。 + +## 一次性所有权与生命周期 + +`provider.start(request): Promise` 是所有权转移边界;委派工具也会在其由 Task 支撑的一次性后台路径中使用它。兑现前,提供方拥有设置过程,并且在任何失败路径上都必须取消、回滚并使尚未发布的资源完全停稳。兑现后,run 的所有权转移给调用方;调用方必须在每条路径上调用 `dispose()`。剩余提示词和轮次工作属于 `SubagentRun.result`。 + +`SubagentRun.result` 兑现为 `{ output, structured?, stopReason }`。子 agent 级失败会以非 `completed` 原因兑现;只有 seam 无法表示的基础设施故障才可以拒绝。`dispose()` 是幂等的,会取消剩余工作,并等待结果结算以及子 agent 资源完全停稳。result 的拒绝只通过 `result` 本身报告;只有独立的资源释放失败,才会使 `dispose()` 被拒绝。`output` 与 `subagent/end` 事件的 `lastAssistantMessage` 使用导出的 `AssistantOutputFold`/`finalAssistantOutput` 辅助函数选取子 agent 最后一条非空 assistant 消息;若没有这类消息,则选取其累积的 assistant 文本。子 agent 两种输出均未产生时,`output` 为 `[]`,该事件字段缺省(结果约定归 [`SubagentResult.output`](../../../docs/subsystems/subagent.md#the-terminal-result-subagentresult) 所有)。 + +本地运行会在 `start()` 兑现前发布普通的子 agent/会话,把该共享会话 id 作为 `SubagentRun.id` 返回,以 `SubagentRun.localAgent` 公开准确的子 agent,把 `request.parent.session.id` 记录到子 agent 的 `parentSession` header,并在其初始轮次内追加已解析的描述符。远程提供方则生成 parent 作用域的生命周期 id,并返回 `localAgent: undefined`;由于没有本地 child 会话,其一次性运行不会进入基于追踪的枚举结果。 + +## 可继续子 agent 与 Activation + +每个可继续子 agent 都有一个持久化 Session,并且同一时刻至多有一个进程内 **Activation**。Activation 表示重建后的子 agent 的一次驻留时段,不是请求、结果、取消或 Task 的边界。Agent inbox 是唯一的轮次队列,因此驻留归继续执行管理器,所有轮次排序与执行归 agent loop(智能体循环)。任何可继续路径都不会创建 Task 或中间的承载结果的包装层。 + +管理器根据 Agent 的完全停稳状态和所拥有的子级集合推导三种内部驻留状态,而不维护第二套状态机:running 表示存在正在进行的准入、尚未结束的轮次,或会唤醒 Agent 的 inbox 工作;waiting 表示 Agent 已完全停稳,但仍拥有至少一个尚未 dispose 的子级;settled 表示 Agent 已完全停稳且所有拥有的子级均已 dispose,此时管理器会 dispose `AgentHandle` 并移除 Activation。每条后续消息都使用 `Agent.followup()` 并成为一个 FIFO 轮次,且不会对当前轮次进行 steering(中途引导)。路由只取决于驻留状态:running 入队、waiting 唤醒同一 Agent,无 Activation 时则冷恢复一个新的。 + +管理器预留子 agent 身份、解析持久化描述符,通过私有的 activation-owner 作用域调用 `ctx.agents.create()`(冷恢复时为 `ctx.agents.resume()`),把返回的 `AgentHandle` 安装到 Activation 中,建立任何可继续父级所有权,然后提交提示词。冷恢复绝不通过提供方分发,因为持久化会话已持有初始前缀,折叠后的描述符即是全部重建输入。 + +### 结算投递 + +当一个驻留 Activation 结算时,管理器会在父级自身的轮次流中告知该子级持久化的直接父级:这个子级已经产出它将产出的全部内容。对于每个已经向调用方返回过 id 的子级,管理器都会无条件投递结算通知,不考虑该子级是否调用过 `report`。最需要说明结局的终止情形,包括达到 token 上限、模型失败、取消或拆卸,恰恰是子级根本没有机会选择的那些情形。在第一条消息被接受之前就回滚的物化保持静默,因为那位调用方已被告知该子级未建立。消息会携带该 epoch 的终止原因、它产出过的最终 assistant 内容,以及持久化来源 `{ kind: 'subagent-settled', form: 'notice', senderSessionId: }`——与子级自撰的 `subagent-report` 是不同的来源 kind,因此 transcript(文本记录)绝不会把运行时写下的话算到子级头上。 + +有两条顺序规则让这条投递可靠而非侥幸,它们也正是这件事属于管理器而非外部 `subagent/end` listener 的原因。第一,发送发生在子级所有权释放**之前**,此时父级仍然计入该子级,因此在结构上不可能被判定为已结算。第二,如果父级本身也是驻留 Activation,该消息会采用与 report 相同的唤醒准入记账。这样,从同步发送消息到负责准入该消息的 microtask 运行之间的窗口,不会被误判为完全停稳——`Agent.status` 会把上下文维护折叠成 `idle`,而维护期间的唤醒发送只会预置一次延后唤醒。缺少其中任一条规则,父级都可能在通知仍留在 inbox 时被 dispose,而 `cancel()` 会清空该 inbox,于是通知被静默丢失。 + +空闲父级会以一个普通的后续轮次收到该通知。繁忙父级则被 steer 到其最近的 step 边界,因此同时结算的多个子级只消耗一个 step,而不是各自一个轮次;采用 steer 而非 inject 还意味着:即便驱动在状态读取与发送之间退出,该消息仍会被认领。如果父级所在的谱系已经开始排空,该通知会通过 inject 投递,且完全不会唤醒父级。对已经完全停稳的父级调用 `Agent.followup()` 会开启新轮次,而 `cancel()` 不会预先阻止之后开启的轮次;因此在拆卸期间唤醒父级,会让宿主即将 dispose 的 Agent 多执行一次模型请求,而且树的每一层各一次,因为每层自己的通知又会唤醒上一层。被 inject 的消息会送达仍在读取自身 inbox 的父级,而无论如何日志都会记录这份记账;但它不会比该父级自身的 dispose 活得更久:`AgentHandle.dispose()` 是一次 `keepInbox: false` 的 cancel,会持久地取消尚未被认领的通知。因此 resume 后的父级没有待处理通知可读:`list_agents` 只告诉它有哪些子级、各自是在线还是仅存于存储;结局本身留在子级自己的 Session 里,一次 `send_message` 会通过 resume 该子级把它取回。已离开注册表的父级不算错误:通知被丢弃,子级自身的 Session 仍是持久记录。投递绝不会阻塞或使拆卸失败——发送被拒只会记录日志,因为为了重试一条通知而保留子级,会把它的整条祖先链永久钉在 `waiting` 上。 + +受继续执行管理的父级 Activation 会在子 agent 能够运行之前,把每个子 agent 的会话 id 记录到 `ownedChildren` 集合中,并且只有在每个所拥有的子 agent Activation 完成 `AgentHandle` dispose 之后才会 dispose(子先于父)。拆卸会先自顶向下传播 Agent 取消,再等待缓慢的后代,而 handle 释放仍保持 child-first。顶层及其他非继续执行的 Agent 没有 Activation,处于该等待图之外。最终结算会在 dispose handle 前等待 best-effort 的 `ctx.sessions.flush(child.session)`。监听器拒绝会被记录,但不会使 Activation 失败,因为监听器参与本身不能标识持久化后端;因此恢复时的持久化状态仍可能缺失或陈旧。 + +## 生命周期事件 + +服务会为每次一次性运行以及每个已驻留的可继续 Activation 时段发出一对 `subagent/start`/`subagent/end`,因此可继续子 agent 可用与一次性运行相同的词汇观察,且不会暴露管理器是物化、唤醒还是冷恢复了它们。对于一次性启动,它会在同步的 `subagent/start` 之前附加结果观察器,因此即使子 agent 已经结算,也仍会先产生 `subagent/start`,再产生 `subagent/end`;在驻留前失败的可继续时段不会发出这对生命周期事件中的任何一个。这对事件共享由服务生成的 `runId`;`local` 标志根据提供方返回的确切 `localAgent` 是否存在取得快照(可继续子级恒为 true),因此观察器不会根据可复用的提供方名称或会话名称推断运行身份或本地性。`provider` 字段包含子 agent 初次创建时记录的提供方名称,不表示该提供方当前仍在注册:已接受的一次性 run 可在提供方移除后才结算;冷恢复时段会从描述符读取初始提供方名称,不会调用或注册该提供方。 + +运行事件受执行委派的父级作用域约束。每个监听器都独立隔离:同步抛出或返回的 promise 被拒绝时,只会记录日志,不会阻塞同级监听器或改变运行。 + +提供方新增和移除还会发出 `subagent/provider-added` 与 `subagent/provider-removed`。面向模型的工具等消费方使用这些事件,因为 Cordis 可能并发加载同级插件;配置顺序不能证明注册顺序。 + +可继续子级不会创建 `SubagentRun` 或 Task。继续执行管理器为每个驻留子会话直接拥有一个仅存在于当前进程的 Activation 和一个留存的 `AgentHandle`,使用 Agent inbox 作为唯一 FIFO,并从持久化描述符冷恢复。父到子投递由确切在线的直接父级身份授权。上报则由确切在线的子级身份授权;管理器根据持久化的 `parentSession` 推导接收方,`MessageSource` 记录发送方,但不授予权限。中断权限被刻意设计得比投递权限更宽:人类出示持久化直接 parent 地址,因此即使 parent Agent 离线,在线 child 仍可被停止;Activation 物化时记录的任何确切在线 ancestor 也可以停止其后代,因为停止一个轮次是幂等的,且不投递任何内容。 + +当 `ctx.sessionProjections` 可用时,服务会注册两个投影单元。`subagentTiming` 会在每个描述符处重置,使 fork 种子中的祖先工作不会计入 child 总量,随后累加 `turn/start` → `turn/end` 活跃时间,并为未结束的轮次保留同一切面的 `active.since` 和 `active.through` 边界;在该轮次保持未结束期间,`active.through` 会跟随最近折叠的事件,从而为 inactive 消费方提供保守的崩溃上界,又不会混入更新的会话元数据。`subagent` 以同样的 last-wins 重置纪律从 `subagent/descriptor` 事件折叠持久化身份——模式与创建标签——因此 fork 种子中的祖先描述符只在 child 自身的描述符覆盖之前有效;畸形或版本无法识别的载荷折叠为可序列化的 `null` 哨兵——与没有描述符的日志不可区分,且能完好通过每个 JSON 推送帧,让消费方以之替换掉手中的陈旧身份而非继续保留该身份——绝不抛错。 + +`registerContinuableSetup()` 允许可选包添加子级作用域能力,而无需让继续执行管理器知道这些能力的名称。贡献会在 Activation 发布前同步安装,在设置失败时一并回滚,并随子级作用域释放。新授权须等到下一个 Activation,移除贡献则会立即撤销每个驻留安装项。 + +## 收集模型 + +面向模型的工具默认同步收集:先等待子 agent 结果,再 dispose 运行,然后才返回。一次性后台委派会在工具中注册普通 Task,其通用状态、收集和取消工具负责后续交互,并将模型提供的 `description` 持久化为可选显示标签。可继续后台委派会调用 `ctx.subagents.startContinuable()`,只返回持久化子 agent id;子 agent 自 inbox 接受起就拥有自己的轮次,因此没有 Task、也没有结果 promise——调用方通过 `send_message` 后续操作工具发送后续工作,`interrupt()` 只停止当前轮次而不 dispose 子 agent,而持久化子 agent 会话仍是子 agent 详细输出的来源。只有 `ctx.agents` 可用时,继续执行管理器才会存在,而会话持久化按每项继续执行操作解析。与此独立,`listChildren()` 枚举在线会话存储与可选会话持久化的在线优先合并——持久化缺席时仅枚举在线 child,因为那时冷 child 本就无法恢复——并由已注册的 `subagent` 投影单元供给每个 child 的持久化模式与标签:在线 child 取注册表的水位快照;冷 child 先取可选投影缓存的持久化行,且仅当其 `seq` 门证明该值折叠自 child 自身后缀(fork 种子之后——自有描述符一经追加即不可变)才直接采用,否则经一次有界并发的持久化 inspect 再经注册表折叠,且 inspect 结果必须仍指向枚举时的生命周期(同 id 被重新发布的会话降级为 `corrupt` diagnostic)。缓存读取抛出异常时,不会据此作出分类判断,因为缓存只是派生数据;静默落到该权威重折。分类结果完全以投影折叠为准;列表操作本身不解析描述符。取得身份值即产出 child 行;已定局而折叠未产出身份的候选是 `corrupt` diagnostic,inspect 失败是瞬时的 `unavailable`(下次列表重试),运行中而暂无身份值的候选整行省略(描述符尚未追加的创建窗口)。它不查询继续执行管理器、Agent 注册信息、Activation 或提供方。每个 child 行都会根据合并结果中携带持久化 `origin: 'subagent'` 的 header 派生读取时的 `hasChildren` 提示;它不会读取后代事件日志,展开后仍以描述符支撑的 child 目录为权威依据。UI 等服务消费方可以保留两种模式,并为无标签的一次性 child 选择回退展示;面向模型的 `list_agents` 工具只投影 `continuable` 条目,通过在线 Agent 注册表细化状态,并把仅存于存储的状态映射为可恢复而非终态的 `ready`(`running`/`idle`/`ready`),并在 `descendants` scope 下遍历 `listDescendants()`。列表操作会把调用方的取消信号转发到每次持久化读取,在这些 await 前后检查取消,并将每次检测到的中止报告为 `SubagentError` 错误码 `CANCELLED`;投影注册表未挂载则以 `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE` 响亮失败,会话存储缺失则以 `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE` 响亮失败。完整约定见[后台 subagent 任务 Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-background-subagent-tasks.md)、[可继续后台 subagent Agent Note](../../../.agents/notes/implemented/feature/2026-07-21-continuable-background-subagents.md)、[持久化目录 Agent Note](../../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md)、[服务合并 Agent Note](../../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md)、[能力 seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md)和 `src/types.ts`。 + +可继续 Activation 会等待 best-effort 的最终会话 flush,但不会把 listener 参与视为持久性确认。一次性运行保留尽力执行的会话检查点,因此已完成的一次性 child 只有在其会话确实进入持久化存储时,才可在 dispose 后继续被发现;如果该检查点缺失,服务不会根据 Task 历史虚构目录条目。 + +## 模型体验 + +### 结算通知 + +#### 模型看到的内容 + +一条用户角色的父级消息,开头是结果本身——`Background subagent finished and will do no further work unless you send it more.`,或子级被停止、耗尽额度、拒绝任务或失败时的对应句子——随后是 `Its closing message:` 与子级的最终 assistant 内容;若子级没有产出内容,则是 `It left no closing message.`。这是本服务面向父级的唯一直接贡献;委派 schema、父级延续与发现以及子级作用域的 `report` 分别归 `dsh-tool-subagent`、`dsh-tool-subagent-control` 和 `dsh-tool-subagent-report` 所有。 + +#### Token 影响 + +父级请求中,每个已结算的 Activation 一条通知,长度取决于子级的最终消息。如果子级既上报又结算,父级请求会同时承担上报消息和结算通知两部分 token 开销。 + +#### KV Cache 影响 + +在父级中仅追加:通知位于其可复用请求前缀之后。到达空闲父级会启动一次独立的模型请求,到达繁忙父级则不会。 + +### 子级委派范围声明 + +#### 模型看到的内容 + +每个进程内子 agent 的运行时上下文快照都携带下方的 `subagent:delegation` 声明,位于沙箱策略与审批策略语句之后。 + +##### 委派范围声明 + +```markdown +You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the job needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it. +``` + +#### Token 影响 + +每个子 agent 的运行时上下文快照中一条固定声明;父级请求中没有任何新增。 + +#### KV Cache 影响 + +子级内部前缀稳定:该声明在子 agent 生命周期内绝不变化,因此只写入第一份运行时上下文快照一次。父级侧不会直接使缓存失效;具名工具消费方共同负责请求前缀的任何变化。 + +## 已知限制与暂缓事项 + +- **ACP 子 agent 仍为一次性,且无法通过追踪枚举**:ACP 运行在 parent 会话语料中没有本地 child 会话。ACP 的 `prepareContinuable` 需要在提供方专用描述符数据中持久化远端会话 id,以及逐子 agent 的继续执行能力声明,因为 ACP 的 `loadSession` 支持按子 agent 协商,而不是通过方法是否存在来确定。远程提供方还需要一份独立的 Activation 所有权约定,具备等效的经认证控制和子先于父的完全停稳保证,才能支持可继续子 agent。 +- **无 host-user 继续执行**:`followup()` 要求确切在线直接父级。只有 `interrupt()` 接受持久化 parent 地址形式的用户授权,因为停止一个轮次是幂等的且不投递任何内容;未来 host 适配器需要具体的经认证交互,才能让该 seam 获得用户投递能力。 +- **不对当前轮次进行 steering**:可继续消息和唤醒式 report 会排入后续轮次,均不会重定向正在进行的轮次。 +- **取消收敛期间存在唤醒缺口**:中断信号发出后、活动 driver 进入 idle 前被接受的唤醒型 follow-up 会保持排队,直到另一条唤醒发送到达。Issue #1838 负责 agent-loop 的唤醒锁存;普通会话取消也受此影响。 +- **驻留仅限进程内**:Activation inbox 与所有权图不会在两个 harness 进程之间协调;对单个持久化存储的并发访问仍然需要持久化邮箱和跨进程租约协议。 +- **不回放已接受但未记录的消息**:只有写入子 agent 会话日志的消息才能连同提供该消息的来源一起重建。崩溃可能丢失从未写入日志、已被接受的初始提示词或后续消息;此后一条经授权的消息可以冷恢复该子 agent,但丢失的消息不会自动回放。 +- **没有持久化的上报 mailbox**:上报需要在线直接父级,提供的是接受标识,不保证恰好一次投递,也不提供已读回执。 +- **生命周期事件只供观察**:影响运行的 `subagent/end` 延续或决策接口仍需等待具体消费方。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/index.js new file mode 100644 index 0000000..9719208 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/index.js @@ -0,0 +1,2572 @@ +import { Service } from "@deepseek-ai/cordis"; +import { scopeTarget } from "@deepseek-ai/dsh-scope"; +import { assertObjectJsonSchema } from "@deepseek-ai/dsh-tools"; +import { HarnessError, boundContextSummary, createUserMessage, errorChain } from "@deepseek-ai/dsh-llm"; +import { randomUUID } from "node:crypto"; +import { foldConsumedWork } from "@deepseek-ai/dsh-agent"; +import { Session, SessionId, snapshotJsonValue } from "@deepseek-ai/dsh-session"; +import { z } from "zod"; +import { accessSync, constants, statSync } from "node:fs"; +import { isAbsolute, resolve } from "node:path"; +//#region lib/types/error.js +/** +* Typed failures shared by subagent service and provider operations. +* +* @module @deepseek-ai/dsh-subagent +*/ +/** Typed failure for the subagent seam. */ +var SubagentError = class extends HarnessError { + constructor(message, code, options) { + super(message, code, options); + this.name = "SubagentError"; + } +}; +//#endregion +//#region lib/types/depth.js +/** +* Delegation-depth accounting: the recursion budget a parent passes to its +* children. Kept apart from the service so composition helpers can read it +* without importing the registry. +* +* @module @deepseek-ai/dsh-subagent/depth +*/ +/** +* Read an agent's delegation depth, treating absence as top-level depth zero. +* The persisted session header is authoritative and monotone: runtime +* `AgentOptions.subagentDepth` may DEEPEN the count but can never lower it — +* a resumed child arrives with fresh options, and counting it from zero would +* let it delegate as if it were top-level. +* @param agent - the agent whose header and options carry the depth. +* @returns its non-negative safe-integer depth. +* @throws if the runtime `AgentOptions.subagentDepth` is not a non-negative safe integer. +*/ +function delegationDepthOf(agent) { + const runtime = agent.options.subagentDepth; + if (runtime !== void 0 && (!Number.isSafeInteger(runtime) || runtime < 0 || Object.is(runtime, -0))) throw new TypeError("agent subagentDepth must be a non-negative safe integer"); + return Math.max(agent.session.header.delegationDepth ?? 0, runtime ?? 0); +} +/** +* Reject a recursion cap that cannot represent an exact delegation depth. +* @param maxDepth - the optional runtime value to validate. +*/ +function assertSubagentMaxDepth(maxDepth) { + if (maxDepth !== void 0 && (typeof maxDepth !== "number" || !Number.isSafeInteger(maxDepth) || maxDepth < 0 || Object.is(maxDepth, -0))) throw new TypeError("subagent maxDepth must be a non-negative safe integer"); +} +//#endregion +//#region lib/types/assistant-output.js +/** +* Canonical selection of a child's final assistant output. Backend run results +* and `subagent/end.lastAssistantMessage` apply the same rule: select the last +* non-empty assistant message. An empty-content message records usage only +* when the loop appends it after a max-tokens step with no executable blocks, +* so it does not replace earlier output. If no non-empty message exists, +* select the accumulated assistant text. Selection is independent of the +* run's stop reason. +* +* @module @deepseek-ai/dsh-subagent/assistant-output +*/ +/** +* Incremental fold of the selection rule, for backends that observe a child's +* output as it streams: session-event backends {@link push} each event, and +* transports without session events (ACP content chunks) {@link pushText} raw +* text into the same streamed fallback. +*/ +var AssistantOutputFold = class { + message; + partial = []; + /** + * Fold one session event: a non-empty assistant message becomes the + * candidate final answer, and a `text-delta` chunk extends the streamed + * fallback; every other event contributes nothing. + * @param event - the next observed session event. + */ + push(event) { + if (event.type === "assistant/message") { + const content = event.data.message.content; + if (content.length > 0) this.message = content; + } else if (event.type === "assistant/chunk" && event.data.chunk.type === "text-delta") this.pushText(event.data.chunk.text); + } + /** + * Extend the streamed fallback with text observed outside session events. + * @param text - the next streamed text piece (an empty piece is a no-op). + */ + pushText(text) { + if (text.length > 0) this.partial.push(text); + } + /** + * Select the final output folded so far. + * @returns the last non-empty assistant message, else the accumulated + * streamed text, or `undefined` when the child produced neither. + */ + collect() { + if (this.message !== void 0) return this.message; + const text = this.partial.join(""); + return text.length > 0 ? [{ + type: "text", + text + }] : void 0; + } +}; +/** +* Apply the selection rule to one complete child-owned event suffix. +* @param events - the child-owned events (after any seed or epoch boundary). +* @returns the selected output, or `undefined` when the child produced none. +*/ +function finalAssistantOutput(events) { + const fold = new AssistantOutputFold(); + for (const event of events) fold.push(event); + return fold.collect(); +} +//#endregion +//#region lib/types/types.js +/** +* The seam's consumer-facing contracts: request, result, and capability types +* for {@link SubagentProvider}, plus the `subagent/start` and `subagent/end` +* payloads that plugins and hosts observe. Internal control interfaces belong +* with their implementation — the lifecycle observer in `./lifecycle.ts`, the +* continuation host in `./continuation.ts` — so this module stays the published +* surface rather than a bag of everything type-shaped. +* +* @module @deepseek-ai/dsh-subagent/types +*/ +/** +* Brand a string as a {@link SubagentRunId}. +* @param id - the raw run id. +* @returns the same string, branded. +*/ +function SubagentRunId(id) { + return id; +} +//#endregion +//#region lib/types/lifecycle.js +/** +* Lifecycle-edge publication for both subagent shapes: the contained emitter, +* the one-shot run observer, and the continuable Activation observer. +* +* The public payload contracts ({@link SubagentRunInfo}, +* {@link SubagentRunEndInfo}) live in `./types.ts` with the rest of the seam's +* consumer-facing types; this module owns only the implementation and the +* package-private {@link ActivationObserver} the continuation manager consumes. +* Keeping the internal control interface out of the published surface is +* deliberate: the observer's `start`/`capture`/`settle` ordering is a contract +* between this module and one in-package caller, not something a plugin may +* depend on. +* +* @module @deepseek-ai/dsh-subagent/lifecycle +*/ +/** +* Build the contained lifecycle emitter this seam publishes every edge through. +* Every listener is independently contained: a synchronous throw or a rejected +* returned promise is logged without starving peer listeners, changing the run, +* or — for provider removal, which fires from a disposer — breaking teardown. +* @param ctx - the service's own context, owning dispatch and the logger. +* @param carrier - resolve the scoped dispatch carrier for one delegating parent. +* @returns the emitter both observers and the provider registry publish through. +*/ +function createLifecycleEmitter(ctx, carrier) { + return (name, info, parent) => { + const dispatchArgs = parent === void 0 ? [name, info] : [ + carrier(parent), + name, + info + ]; + for (const callback of ctx.events.dispatch("emit", dispatchArgs)) try { + const returned = callback(info); + Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`subagent: ${name} listener rejected: ${renderThrown(error)}`); + }); + } catch (error) { + ctx.logger.warn(`subagent: ${name} listener threw: ${renderThrown(error)}`); + } + }; +} +/** +* Emit the start/end lifecycle pair for one accepted one-shot run. +* @param emit - the contained lifecycle emitter. +* @param provider - the provider that established the run. +* @param parent - the delegating parent keying scoped dispatch. +* @param run - the published run whose settlement closes the pair. +* @returns the same run, unchanged. +*/ +function observeRun(emit, provider, parent, run) { + const identity = { + runId: SubagentRunId(randomUUID()), + provider, + id: run.id, + local: run.localAgent !== void 0 + }; + run.result.then((result) => { + emit("subagent/end", { + ...identity, + stopReason: result.stopReason, + ...result.output.length === 0 ? {} : { lastAssistantMessage: result.output } + }, parent); + }, () => { + emit("subagent/end", { + ...identity, + stopReason: "error" + }, parent); + }); + emit("subagent/start", identity, parent); + return run; +} +/** +* Build the observer for one continuable Activation's residency epoch. Observers +* see the same vocabulary as a one-shot run, so a child's start and settlement +* remain observable without exposing whether the manager materialized, woke, or +* cold-resumed it. Creation failure before residency emits no lifecycle edge. +* @param emit - the contained lifecycle emitter. +* @param provider - the provider name recorded in the durable descriptor. +* @param childId - the durable child session id. +* @param parent - the exact live direct parent keying scoped dispatch. +* @returns the observer whose edges this epoch publishes. +*/ +function createActivationObserver(emit, provider, childId, parent) { + const identity = { + runId: SubagentRunId(randomUUID()), + provider, + id: childId, + local: true + }; + let boundary = 0; + let captured = { stopReason: "completed" }; + const terminal = (failure) => failure === void 0 ? captured : { stopReason: "error" }; + return { + start: (child) => { + boundary = child.session.events.length; + emit("subagent/start", identity, parent); + }, + capture: (child) => { + const own = child.session.events.slice(boundary); + const output = finalAssistantOutput(own); + captured = { + stopReason: epochStopReason(own), + ...output === void 0 ? {} : { output } + }; + }, + terminal, + settle: (failure) => { + const { stopReason, output } = terminal(failure); + emit("subagent/end", { + ...identity, + stopReason, + ...output === void 0 ? {} : { lastAssistantMessage: output } + }, parent); + } + }; +} +/** +* Why this child's epoch ended, for the terminal lifecycle edge and the +* manager's own parent delivery. The child's own log is authoritative: +* teardown succeeding says nothing about whether the model errored, hit its +* token ceiling, or was cancelled, so deriving the reason from disposal would +* report failed work as completed. +* +* {@link foldConsumedWork} supplies both halves the raw turn sequence cannot: +* which turn accounts for the work this epoch consumed, and whether accepted +* work was cancelled after it without any turn opening over it. A recorded +* failure still wins over a cancellation — stopping a child that had already +* failed does not turn its failure into a cancellation. +* @param events - this epoch's own event suffix. +* @returns its terminal stop reason; `completed` only for an epoch that both +* closed cleanly and had nothing left to run. +*/ +function epochStopReason(events) { + const { end, droppedUnrun } = foldConsumedWork(events); + switch (end?.data.reason.kind) { + case "max-tokens": return "max-tokens"; + case "aborted": + case "interrupted": return "aborted"; + case "error": return "error"; + case "blocked": return "refusal"; + case void 0: + case "completed": return droppedUnrun ? "aborted" : "completed"; + /* v8 ignore next 3 -- `TurnEndReason` is merge-extensible, so this arm needs a + * backend that adds a variant; treating an unnameable reason as success would + * report failed work as completed. */ + default: return "error"; + } +} +/** Render any listener-thrown value without letting coercion escape containment. */ +function renderThrown(value) { + try { + return value instanceof Error ? `${value.name}: ${value.message}` : String(value); + } catch { + return ""; + } +} +//#endregion +//#region lib/types/descriptor.js +/** +* The durable subagent-child descriptor: the versioned, model-hidden +* `subagent/descriptor` session event that identifies every session-backed +* subagent and records whether it is one-shot or continuable. Continuable +* descriptors additionally preserve the declared composition required for +* cold resume. Providers append it turn-enclosed in the child's initial turn. +* +* The descriptor deliberately snapshots explicit fields rather than the +* merge-extensible `AgentOptions` object: an unrelated extension value cannot +* make continuation fail merely because it is not JSON, and later composition +* inputs require a deliberate {@link SUBAGENT_DESCRIPTOR_VERSION} change. It +* omits `subagentDepth` — cold resume trusts the persisted header's +* `delegationDepth` as the monotone floor — and `outputSchema`, which belongs +* to one activation's result contract rather than durable child composition. +* Per-activation knobs such as `maxTokens` are omitted for the same reason as +* `outputSchema`: they budget one activation. Cold resume requires the exact +* live parent for authorization but reconstructs child options only from the +* durable descriptor, so it neither restores the prior budget nor inherits +* the parent's current one; the resumed route's defaults apply instead. +* +* @module @deepseek-ai/dsh-subagent/descriptor +*/ +/** +* The current descriptor format version, stamped into every appended +* `subagent/descriptor` event and required verbatim by {@link foldSubagentDescriptor}. +* Supporting another composition input is a deliberate version change, never +* an implicit extra field. +*/ +const SUBAGENT_DESCRIPTOR_VERSION = 2; +const DESCRIPTOR_BASE_KEYS = [ + "version", + "mode", + "provider", + "label" +]; +const ONE_SHOT_DESCRIPTOR_KEYS = new Set(DESCRIPTOR_BASE_KEYS); +const CONTINUABLE_DESCRIPTOR_KEYS = new Set([ + ...DESCRIPTOR_BASE_KEYS, + "agentProvider", + "agentModel", + "persona", + "toolFilter" +]); +const TOOL_FILTER_KEYS = new Set(["allow", "deny"]); +/** Whether a persisted JSON value is an object record. */ +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +/** Reject fields outside one versioned record's declared schema. */ +function assertKnownKeys(value, keys, path) { + const unknown = Object.keys(value).find((key) => !keys.has(key)); + if (unknown !== void 0) throw new Error(`persisted subagent descriptor ${path} has unknown field "${unknown}"`); +} +/** Read one optional string field from a persisted descriptor record. */ +function optionalString(value, key) { + if (!Object.hasOwn(value, key)) return void 0; + const field = value[key]; + if (typeof field !== "string") throw new Error(`persisted subagent descriptor ${key} must be a string`); + return field; +} +/** Read one optional string-array field from a persisted tool restriction. */ +function optionalStringArray(value, key) { + if (!Object.hasOwn(value, key)) return void 0; + const field = value[key]; + if (!Array.isArray(field)) throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`); + const items = field; + if (items.some((item) => typeof item !== "string")) throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`); + return items; +} +/** Validate and reconstruct a persisted tool restriction. */ +function parseToolFilter(value) { + if (!isRecord(value)) throw new Error("persisted subagent descriptor toolFilter must be an object"); + assertKnownKeys(value, TOOL_FILTER_KEYS, "toolFilter"); + const allow = optionalStringArray(value, "allow"); + const deny = optionalStringArray(value, "deny"); + if (allow === void 0 && deny === void 0) throw new Error("persisted subagent descriptor toolFilter must declare allow and/or deny"); + return { + ...allow !== void 0 ? { allow } : {}, + ...deny !== void 0 ? { deny } : {} + }; +} +/** Validate one persisted descriptor payload for the current runtime. */ +function parseSubagentDescriptor(value) { + if (!isRecord(value)) throw new Error("persisted subagent descriptor payload must be an object"); + const version = value["version"]; + if (typeof version !== "number") throw new Error("persisted subagent descriptor version must be a number"); + if (version !== 2) return void 0; + const mode = value["mode"]; + if (mode !== "one-shot" && mode !== "continuable") throw new Error("persisted subagent descriptor mode must be \"one-shot\" or \"continuable\""); + assertKnownKeys(value, mode === "one-shot" ? ONE_SHOT_DESCRIPTOR_KEYS : CONTINUABLE_DESCRIPTOR_KEYS, "payload"); + const provider = value["provider"]; + if (typeof provider !== "string") throw new Error("persisted subagent descriptor provider must be a string"); + if (mode === "one-shot") { + const label = optionalString(value, "label"); + return { + version: 2, + mode, + provider, + ...label !== void 0 ? { label } : {} + }; + } + const label = value["label"]; + if (typeof label !== "string") throw new Error("persisted subagent descriptor label must be a string"); + const agentProvider = optionalString(value, "agentProvider"); + const agentModel = optionalString(value, "agentModel"); + const persona = optionalString(value, "persona"); + const toolFilter = Object.hasOwn(value, "toolFilter") ? parseToolFilter(value["toolFilter"]) : void 0; + return { + version: 2, + mode, + provider, + label, + ...agentProvider !== void 0 ? { agentProvider } : {}, + ...agentModel !== void 0 ? { agentModel } : {}, + ...persona !== void 0 ? { persona } : {}, + ...toolFilter !== void 0 ? { toolFilter } : {} + }; +} +function snapshotSubagentDescriptor(input) { + const snapshot = snapshotJsonValue(input.mode === "one-shot" ? { + version: 2, + mode: input.mode, + provider: input.provider, + ...input.label !== void 0 ? { label: input.label } : {} + } : { + version: 2, + mode: input.mode, + provider: input.provider, + label: input.label, + ...input.agentProvider !== void 0 ? { agentProvider: input.agentProvider } : {}, + ...input.agentModel !== void 0 ? { agentModel: input.agentModel } : {}, + ...input.persona !== void 0 ? { persona: input.persona } : {}, + ...input.toolFilter !== void 0 ? { toolFilter: input.toolFilter } : {} + }); + if (snapshot === void 0) throw new Error("subagent descriptor is not losslessly JSON-serializable"); + return snapshot; +} +/** +* Fold a persisted child log to its supported descriptor. The first +* `subagent/descriptor` event is authoritative — the establishing provider +* appends exactly one, so a later same-type event cannot rewrite the declared +* composition. +* @param events - the loaded child session events. +* @returns the descriptor, or `undefined` when the log has none or its +* version is not {@link SUBAGENT_DESCRIPTOR_VERSION} (the child cannot be +* classified by this runtime). +* @throws when a current-version persisted payload does not match its complete +* declared schema. +*/ +function foldSubagentDescriptor(events) { + const event = events.find((candidate) => candidate.type === "subagent/descriptor"); + if (event === void 0) return void 0; + return parseSubagentDescriptor(event.data); +} +//#endregion +//#region lib/types/child-agent.js +/** +* Shared in-process child composition: the delegation-depth budget, the +* durable session metadata, the resolved child `AgentOptions`, the delegated +* policy seed, and the scoped setup a child agent needs. Both the one-shot +* provider driver and the continuation manager compose children this way, so +* depth accounting, lineage stamping, and delegation policy have one home. +* +* @module @deepseek-ai/dsh-subagent/child-agent +*/ +/** Thrown when starting a child would exceed the requested depth cap. */ +var SubagentDepthError = class extends Error { + attemptedDepth; + maxDepth; + constructor(attemptedDepth, maxDepth) { + super(`subagent depth ${attemptedDepth} exceeds maxDepth ${maxDepth}`); + this.attemptedDepth = attemptedDepth; + this.maxDepth = maxDepth; + this.name = "SubagentDepthError"; + } +}; +/** +* Resolve the child's delegation depth from its parent and enforce an optional +* cap. The persisted parent header is the monotone floor, so a resumed parent +* cannot delegate as if it were top-level. +* @param parent - the delegating parent agent. +* @param maxDepth - optional absolute cap the resolved depth must not exceed. +* @returns the child's non-negative safe-integer depth. +* @throws {SubagentDepthError} when the resolved depth exceeds `maxDepth`. +* @throws {RangeError} when the resolved depth leaves the safe-integer range. +*/ +function resolveChildDepth(parent, maxDepth) { + const childDepth = delegationDepthOf(parent) + 1; + if (!Number.isSafeInteger(childDepth)) throw new RangeError("subagent child depth exceeds the safe-integer range"); + if (maxDepth !== void 0 && childDepth > maxDepth) throw new SubagentDepthError(childDepth, maxDepth); + return childDepth; +} +/** +* Resolve the child's `AgentOptions`: the parent's provider/model/maxTokens +* route unless the request overrides it, stamped with the child's own +* delegation depth. +* @param parent - the delegating parent whose route the child inherits. +* @param requested - per-child overrides, if any. +* @param childDepth - the resolved delegation depth to stamp. +* @returns the resolved options for `ctx.agents.create()`. +*/ +function resolveChildAgentOptions(parent, requested, childDepth) { + const parentProvider = parent.options.provider; + const parentModel = parent.options.model; + const parentMaxTokens = parent.options.maxTokens; + return { + ...parentProvider !== void 0 ? { provider: parentProvider } : {}, + ...parentModel !== void 0 ? { model: parentModel } : {}, + ...parentMaxTokens !== void 0 ? { maxTokens: parentMaxTokens } : {}, + ...requested, + subagentDepth: childDepth + }; +} +/** +* Build the child session's durable creation metadata: the parent's workspace, +* its direct lineage, coarse product origin, the recursion budget that must +* survive persistence, the seed boundary that separates inherited parent +* history from child work, and the composition the child runs under. +* +* The preset is read from the parent's LIVE scope chain rather than from its +* header, because a parent that switched preset while blank runs on the newer +* composition and its header still names the older one. Recording it is what +* makes a child's history reconstructable: without it a cold read of the child +* resolves the deployment default and rebuilds turns under a tool set the +* child never had. +* @param parent - the delegating parent agent. +* @param childDepth - the resolved delegation depth to persist. +* @param lineageSeedLength - how many leading events came from the parent's log. +* @returns the `meta` for `ctx.agents.create()`. +*/ +function childSessionMeta(parent, childDepth, lineageSeedLength) { + const parentHeader = parent.session.header; + const agentPreset = parent.ctx.get("agentPresets")?.composedPreset(parent.ctx); + return { + ...parentHeader.cwd !== void 0 ? { cwd: parentHeader.cwd } : {}, + ...agentPreset === void 0 ? {} : { agentPreset }, + parentSession: parentHeader.id, + origin: "subagent", + delegationDepth: childDepth, + ...lineageSeedLength > 0 ? { seedLength: lineageSeedLength } : {} + }; +} +/** +* Model-facing delegation-scope statement for every in-process child. A +* runtime-context contribution rather than a system-prompt section, so the +* deployment's system prompt stays uniform across parents and children. +*/ +const SUBAGENT_DELEGATION_CONTEXT = "You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."; +/** +* Compose one child inside its creation window: join its parent's preset, +* register the fixed delegation-scope statement, then apply the child's own +* shadowing persona section and tool restriction, all owned by the child's +* scope and therefore invisible to its parent and siblings. Creation and cold +* resume both pass through here. +* +* The join comes first and the child's own registrations second, which is the +* order the layering already implies — the nearest scope wins a name, and a +* per-child restriction intersects with everything its chain admits — but +* stating it here keeps the two steps from being read as independent. +* +* The join and the per-child registrations live in ONE call because a child +* composed without the join is exactly the defect this function exists to +* prevent: with every model-facing row on the agent plane, a child that joins +* no preset sees an empty tool registry and none of its parent's prompt +* sections. Taking the parent as a parameter is what makes that omission +* unrepresentable at the call sites. +* @param childCtx - the child agent's scoped creation context. +* @param parent - the delegating parent whose composition the child joins. +* @param composition - the per-child persona and tool filter to install. +*/ +function applyChildComposition(childCtx, parent, composition) { + childCtx.get("agentPresets")?.composeFrom(childCtx, parent.ctx); + childCtx.systemPrompt.context({ + name: "subagent:delegation", + order: 120, + text: SUBAGENT_DELEGATION_CONTEXT + }); + if (composition.persona !== void 0) childCtx.systemPrompt.section({ + name: "deployment:persona", + order: 0, + text: composition.persona + }); + if (composition.toolFilter !== void 0) childCtx.tools.restrict(composition.toolFilter); +} +/** +* Capture the policy to seed into one delegation. Call synchronously before +* the child start's first await: a later parent switch belongs to the +* parent's future, not to this child. Only the parent session's explicit +* sandbox override is captured — never deployment defaults or one-shot +* grants — and the approval policy is pinned to `'never'` regardless of the +* parent's own policy. +* @param parent - the delegating parent agent. +* @returns the sandbox override (or `undefined` without one) and the approval pin. +*/ +function captureDelegatedPolicyOverrides(parent) { + return { + sandboxMode: parent.ctx.get("sandboxPolicy")?.overrideOf(parent.session), + approvalPolicy: parent.ctx.get("approval") === void 0 ? void 0 : "never" + }; +} +/** +* Append the captured delegation policy onto the child's own log as +* `source: 'delegation'` events inside the unpublished creation window, so the +* child's effective policy is reconstructable from its log alone. Appends land +* after any fork seed, so fresh policy wins stale seed state; later child +* switches still win over these events. +* @param childSession - the unpublished child's session. +* @param overrides - the policy captured at delegation. +*/ +function appendDelegatedPolicyOverrides(childSession, overrides) { + if (overrides.sandboxMode !== void 0) childSession.append("sandbox/mode", { + mode: overrides.sandboxMode, + source: "delegation" + }); + if (overrides.approvalPolicy !== void 0) childSession.append("approval/policy", { + policy: overrides.approvalPolicy, + source: "delegation" + }); +} +//#endregion +//#region lib/types/descriptor-seed.js +/** +* Seeding of a continuable child's durable descriptor event: the model-hidden +* record of the child's declared composition before its first request, so a +* later cold resume can reconstruct it from its own log. +* +* @module @deepseek-ai/dsh-subagent/descriptor-seed +*/ +/** +* Build the child's creation seed: any inherited parent-history prefix followed +* by one model-hidden, between-turn `descriptor` event. Staging through a +* `Session` assigns the sequence number and enforces the same lossless-JSON +* rules the durable log does. +* @param childId - the reserved child session id the staged log belongs to. +* @param seed - the inherited completed-turn prefix, or `undefined` for a fresh child. +* @param descriptor - the snapshotted composition record to persist. +* @returns the complete seed events, contiguous from sequence zero. +*/ +function seedDescriptorTurn(childId, seed, descriptor) { + const staged = Session.create(childId, seed); + staged.append("subagent/descriptor", descriptor); + return [...staged.events]; +} +//#endregion +//#region lib/types/continuation.js +/** +* Internal continuable-subagent manager: stable child ids, descriptor +* persistence, activation admission, the live ownership graph, cold resume, +* child-first disposal, and settlement delivery to the parent, behind +* `ctx.subagents`. +* +* A continuable child has one durable Session and at most one process-local +* {@link Activation} — one residency epoch for a reconstructed child Agent. An +* Activation is not a request, result, cancellation, or Task boundary: it may +* execute many FIFO turns and stays resident while descendants it created are +* still running. The Agent inbox is the only turn queue, so this manager owns +* residency while the Agent loop owns all turn ordering and execution. No +* continuable path creates a Task or an intermediate result-bearing wrapper. +* +* Because residency is this manager's alone to end, telling the parent that a +* child settled is its job too. An external `subagent/end` listener cannot do +* it correctly: that payload names no parent, the child handle is already +* disposed by then, and the release that wakes the parent's own settlement +* watcher has already run. See {@link SubagentContinuationManager.notifySettlement}. +* +* @module @deepseek-ai/dsh-subagent +*/ +/** +* Read one Activation's current disposal transaction. This indirection exists +* because TypeScript would otherwise narrow repeated reads of the mutable field +* inside a long-lived closure to constants instead of re-reading runtime state. +* @param activation - the Activation to inspect. +* @returns the in-flight or settled disposal, or `undefined` while resident. +*/ +function disposalOf(activation) { + return activation.disposal; +} +/** +* One line telling a parent that a background child is finished and why, in +* the parent's own task vocabulary. +* @param childId - the durable child the parent knows by id. +* @param stopReason - how the child's last ordinary turn ended. +* @returns the model-facing opening line of the settlement notice. +*/ +function settlementSummary(childId, stopReason) { + const subject = `Background subagent ${childId}`; + switch (stopReason) { + case "completed": return `${subject} finished and will do no further work unless you send it more.`; + case "aborted": return `${subject} was stopped before it finished.`; + case "max-tokens": return `${subject} ran out of room before it finished.`; + case "refusal": return `${subject} declined the task.`; + case "error": return `${subject} failed before it finished.`; + /* v8 ignore next 4 -- `SubagentResult['stopReason']` is merge-extensible, so this arm + * needs a backend that adds a variant; an unnameable ending is reported as unfinished + * rather than silently as success. */ + default: return `${subject} ended abnormally (${String(stopReason)}) before it finished.`; + } +} +/** Serialize each durable child's delivery, release, and disposal. */ +var ChildLock = class { + tails = /* @__PURE__ */ new Map(); + /** + * Run `operation` after every previously queued operation for `childId`. + * @param childId - the durable child whose operations are linearized. + * @param operation - the critical section to run in order. + * @returns the operation's own settlement. + */ + run(childId, operation) { + const result = (this.tails.get(childId) ?? Promise.resolve()).then(operation, operation); + const tail = result.then(() => void 0, () => void 0); + this.tails.set(childId, tail); + tail.then(() => { + if (this.tails.get(childId) === tail) this.tails.delete(childId); + }); + return result; + } +}; +/** +* The continuable-subagent orchestration service behind `ctx.subagents`. Tool +* schema and host adapters are consumers of this one contract; foreground +* one-shot delegation keeps calling `ctx.subagents.start()` and never enters +* this lifecycle. +*/ +var SubagentContinuationManager = class { + ctx; + host; + setupRegistry; + /** Child session id → its live Activation. Process-local, never durable. */ + activations = /* @__PURE__ */ new Map(); + /** Materializations admitted before drain, tracked through publication or rollback. */ + materializations = /* @__PURE__ */ new Set(); + locks = new ChildLock(); + /** Structural Cordis owner of every Activation handle. */ + ownerCtx; + /** + * Exact roots whose host teardown has begun, with the live lineage members + * observed under each root. Entries remain until that exact root leaves the + * Agent registry, closing admission throughout its host's teardown without + * poisoning a later same-id replacement. + */ + closingScopes = /* @__PURE__ */ new Map(); + draining = false; + constructor(ctx, host, setupRegistry) { + this.ctx = ctx; + this.host = host; + this.setupRegistry = setupRegistry; + const scope = ctx.plugin(function activationOwner() {}); + this.ownerCtx = scope.ctx; + ctx.on("agent/disposed", ({ agent }) => { + this.closingScopes.delete(agent); + }); + ctx.effect(function* () { + yield scope.dispose; + yield () => this.drain(); + }.bind(this), "subagents.continuations()"); + } + /** + * Start one continuable background child: reserve its durable identity, + * resolve the provider's detached creation spec, create the child Agent + * through the private activation-owner scope, establish any continuable-parent + * ownership, and submit the initial prompt. Resolves when inbox acceptance + * yields the message id — without waiting for the turn to start or for the + * message to reach the Session log. + * + * Every failure before that acceptance rejects without either id, disposing + * any created handle and rolling back the Activation and parent ownership. + * The caller signal owns lookup, materialization, and admission only until + * acceptance; afterwards the manager owns the Activation independently. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted initial prompt's message id. + */ + async startContinuable(spec) { + const request = spec.request; + const parent = request.parent; + this.assertAdmitting(parent); + this.requirePersistence(); + assertSubagentMaxDepth(request.maxDepth); + const childId = SessionId(randomUUID()); + const childDepth = resolveChildDepth(parent, request.maxDepth); + const agentProvider = request.agentOptions?.provider ?? parent.options.provider; + const agentModel = request.agentOptions?.model ?? parent.options.model; + const descriptor = snapshotSubagentDescriptor({ + mode: "continuable", + provider: spec.provider, + label: spec.label, + ...agentProvider !== void 0 ? { agentProvider } : {}, + ...agentModel !== void 0 ? { agentModel } : {}, + ...request.persona !== void 0 ? { persona: request.persona } : {}, + ...request.toolFilter !== void 0 ? { toolFilter: request.toolFilter } : {} + }); + const delegatedPolicies = captureDelegatedPolicyOverrides(parent); + const prepared = await this.host.prepareContinuable(spec.provider, { + sessionId: childId, + parent, + signal: spec.signal + }); + spec.signal.throwIfAborted(); + this.assertAdmitting(parent); + const lineageSeedLength = prepared.seed?.length ?? 0; + const seed = seedDescriptorTurn(childId, prepared.seed, descriptor); + return { + childId, + messageId: await this.locks.run(childId, async () => { + const activation = await this.materialize({ + childId, + provider: spec.provider, + parent, + create: { + seed, + meta: childSessionMeta(parent, childDepth, lineageSeedLength), + delegatedPolicies + }, + agentOptions: resolveChildAgentOptions(parent, request.agentOptions, childDepth), + composition: { + persona: request.persona, + toolFilter: request.toolFilter + }, + signal: spec.signal + }); + return this.submitMaterialized(activation, request.prompt, { kind: "user" }, parent, spec.signal); + }) + }; + } + /** + * Deliver one later message to a known continuable child as its next FIFO + * turn. Routing depends only on Activation residency: a `running` Activation + * enqueues, a `waiting` one wakes the same Agent, and an absent one + * cold-resumes a new Activation from the persisted Session. The Agent inbox + * is the only queue, so every accepted message has one observable order. + * + * The caller signal owns lookup, materialization, and admission only until + * inbox acceptance; afterwards the accepted turn cannot be cancelled through + * this service. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - the durable child session id. + * @param content - the user-role content to deliver. + * @param options - the message source fields and caller cancellation. + * @returns the accepted message's inbox id. + * @throws when parent authority, availability, or admission rejects the delivery. + */ + async followup(parent, childId, content, options) { + this.assertAdmitting(parent); + while (true) { + const live = await this.locks.run(childId, async () => { + const activation = this.activations.get(childId); + if (activation === void 0) return this.coldResume(parent, childId, content, options); + /* v8 ignore next 3 -- the send-versus-dispose cutoff: reaching this arm needs a + * delivery to observe the transaction inside the same critical section that opened it, + * which no test can schedule deterministically. The behavior is covered end-to-end by + * "cold-resumes a delivery that lost the race with final disposal". */ + if (activation.disposal !== void 0) return activation.disposal.then(() => void 0, () => void 0); + return this.submitAdmitted(activation, content, options.source, parent, options.signal); + }); + /* v8 ignore start -- only the lost-cutoff arm above returns undefined, so only that + * race reaches the retry below, which then cold-resumes a new Activation. */ + if (live !== void 0) return live; + this.assertAdmitting(parent); + options.signal.throwIfAborted(); + } + } + /** + * Interrupt one live continuable child's current turn. Admission is + * synchronous and the effect is asynchronous: this authorizes the caller, + * requests `Agent.cancel(cause, { keepInbox: true })` on the target, and + * returns without waiting for the target to observe the signal or reach + * quiescence. The Activation, its handle, accepted unclaimed inbox work, and + * already-published descendants are untouched; work already claimed into the + * interrupted turn is not requeued. Once the interrupted driver is idle, a + * waking send resumes the parked queue. + * + * An absent target is an accepted no-op, which uniformly covers natural + * completion races, repeated requests, one-shot ids, and unknown ids without + * consulting the durable catalog. A target whose disposal transaction is + * already open is likewise an accepted no-op after authorization. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the presented authority does + * not own the live target: a stale or self-targeting ancestor caller, a + * parent address that is not the live target's durable direct parent, or + * an ancestor outside the target's recorded live lineage. + */ + interrupt(targetSessionId, authority) { + if (authority.kind === "ancestor") { + const caller = authority.agent; + if (this.ctx.agents.get(caller.id) !== caller) throw new SubagentError(`interrupting "${targetSessionId}" requires the exact live ancestor agent`, "UNAUTHORIZED"); + if (caller.id === targetSessionId) throw new SubagentError(`agent "${caller.id}" cannot interrupt itself`, "UNAUTHORIZED"); + } + const activation = this.activations.get(targetSessionId); + if (activation === void 0) return; + if (authority.kind === "user") { + if (activation.handle.agent.session.header.parentSession !== authority.parentSessionId) throw new SubagentError(`subagent "${targetSessionId}" belongs to another parent session`, "UNAUTHORIZED"); + } else if (!activation.ancestry.has(authority.agent)) throw new SubagentError(`subagent "${targetSessionId}" is not a live descendant of agent "${authority.agent.id}"`, "UNAUTHORIZED"); + if (activation.disposal !== void 0) return; + activation.handle.agent.cancel(authority.kind === "user" ? { kind: "user" } : { kind: "parent" }, { keepInbox: true }); + } + /** + * Deliver explicitly selected content from one resident continuable child to + * its durable direct parent. Sender authorization, parent resolution, and + * send acceptance share one no-await span. Reporting neither concludes the + * child's turn nor changes its Activation lifetime. + * @param child - exact live reporting child; this is the authority credential. + * @param content - selected model-facing content. + * @param options - scheduling policy and pre-acceptance cancellation. + * @returns the stable identity of the message accepted by the parent. + * @throws {SubagentError} when the sender is unauthorized, the parent is not + * live, or continuation admission is closing. + */ + async reportFrom(child, content, options) { + options.signal.throwIfAborted(); + this.assertAdmitting(child); + const activation = this.authorizeReporter(child); + const parent = this.resolveReportParent(child); + return this.deliverReport(activation, parent, content, options.delivery); + } + /** Authorize only the exact Agent of one resident Activation. */ + authorizeReporter(child) { + const activation = this.activations.get(child.id); + if (activation === void 0 || activation.handle.agent !== child) throw new SubagentError(`agent "${child.id}" is not a live continuable subagent and cannot report`, "UNAUTHORIZED"); + /* v8 ignore next 6 -- only a synchronous re-entrant disposer can open this + * transaction between exact-agent authorization and this no-await cutoff. */ + if (activation.disposal !== void 0) throw new SubagentError(`subagent "${child.id}" activation is being disposed; the report was not delivered`, "ACTIVATION_CLOSING"); + return activation; + } + /** Resolve the reporting child's live direct parent from durable lineage. */ + resolveReportParent(child) { + const parentId = child.session.header.parentSession; + /* v8 ignore next -- every continuation-managed child has direct-parent metadata. */ + const parent = parentId === void 0 ? void 0 : this.ctx.agents.get(parentId); + if (parent === void 0) throw new SubagentError("direct parent is not live; report was not delivered", "PARENT_UNAVAILABLE"); + return parent; + } + /** Deliver one framed report through the selected parent scheduling preset. */ + deliverReport(activation, parent, content, delivery) { + const message = createUserMessage({ + content: [{ + type: "text", + text: `Background subagent ${activation.childId} reported:` + }, ...content], + source: { + kind: "subagent-report", + form: "relay", + senderSessionId: activation.childId + } + }); + if (delivery === "wakeup") this.sendWaking(parent, message, () => { + this.sendReport(parent, message, delivery); + }); + else this.sendReport(parent, message, delivery); + return message.id; + } + /** + * Perform one waking send to a parent, accounted against that parent's own + * Activation when it has one. Registering the id before the send is what + * keeps a continuation-managed parent from being judged quiescent in the + * window between `followup()` and the microtask that admits it. + * @param parent - the exact live parent receiving the waking message. + * @param message - the message whose id is accounted. + * @param send - the synchronous waking send to perform. + */ + sendWaking(parent, message, send) { + const parentActivation = this.activations.get(parent.id); + if (parentActivation !== void 0 && parentActivation.handle.agent === parent) this.admitWaking(parentActivation, message.id, send); + else send(); + } + /** Send one report while translating only the parent's own rejection. */ + sendReport(parent, message, delivery) { + try { + if (delivery === "wakeup") parent.followup(message); + else parent.inject(message); + } catch (error) { + throw new SubagentError("direct parent is not live; report was not delivered", "PARENT_UNAVAILABLE", { cause: error }); + } + } + /** + * Close admission, await every already-admitted materialization through + * publication or rollback, then dispose the stable live Activation forest + * child-first. Sibling branches drain independently: one failure is recorded + * but never prevents the remaining handles from being attempted, and the + * aggregate rejects only after every branch settles. + * @returns once materialization is quiescent and every live Activation released its handle. + * @throws an aggregate error when any branch failed to release. + */ + async drain() { + this.draining = true; + await Promise.all([...this.materializations].map((materialization) => materialization.settled)); + const owned = /* @__PURE__ */ new Set(); + for (const activation of this.activations.values()) for (const child of activation.ownedChildren) owned.add(child); + const roots = [...this.activations.values()].filter((activation) => !owned.has(activation.childId)); + await this.disposeRoots(roots, "activation(s)"); + } + /** + * Stop only the continuable descendants of exact live host-owned parents. + * Admission stays closed for those parent trees until each exact parent + * leaves the Agent registry; unrelated trees and manager-wide admission stay + * live. + * @param parents - exact live roots whose continuable descendants must stop. + * @returns once every retained descendant Activation released its handle. + * @throws an aggregate error after all scoped branches settle when any failed. + */ + async drainDescendants(parents) { + const roots = new Set(parents.filter((parent) => this.ctx.agents.get(parent.id) === parent)); + if (roots.size === 0) return; + for (const root of roots) this.closingMembers(root).add(root); + const targets = []; + for (const activation of this.activations.values()) { + const lineage = this.liveLineage(activation.handle.agent); + const owners = [...roots].filter((root) => activation.handle.agent !== root && activation.ancestry.has(root)); + if (owners.length === 0) continue; + targets.push(activation); + for (const owner of owners) { + const members = this.closingMembers(owner); + members.add(activation.handle.agent); + for (const agent of lineage) members.add(agent); + } + } + const materializations = [...this.materializations].filter((materialization) => { + const owners = [...roots].filter((root) => materialization.lineage.includes(root)); + for (const owner of owners) { + const members = this.closingMembers(owner); + for (const agent of materialization.lineage) members.add(agent); + } + return owners.length > 0; + }); + const ownedTargets = /* @__PURE__ */ new Set(); + for (const activation of targets) for (const child of activation.ownedChildren) ownedTargets.add(child); + const targetRoots = targets.filter((activation) => !ownedTargets.has(activation.childId)); + for (const activation of targets) this.dispose(activation).catch(() => void 0); + await Promise.all(materializations.map((materialization) => materialization.settled)); + await this.disposeRoots(targetRoots, "scoped activation(s)"); + } + /** Dispose independent roots and report every branch failure after all settle. */ + async disposeRoots(roots, failureSubject) { + const reasons = (await Promise.all(roots.map(async (activation) => { + try { + await this.dispose(activation); + return; + } catch (error) { + return error; + } + }))).filter((failure) => failure !== void 0); + if (reasons.length > 0) throw new SubagentError(`continuable subagent teardown failed for ${reasons.length} ${failureSubject}: ` + reasons.map((reason) => errorChain(reason)).join("; "), "ACTIVATION_TEARDOWN_FAILED"); + } + /** Return the retained member set for one exact scoped-teardown root. */ + closingMembers(root) { + const existing = this.closingScopes.get(root); + if (existing !== void 0) return existing; + const members = /* @__PURE__ */ new Set(); + this.closingScopes.set(root, members); + return members; + } + /** + * Return the exact currently resolvable ancestry from `agent` upward. The + * first element is always the supplied identity, even when it is already + * stale; each ancestor after it must be the registry's current exact entry. + */ + liveLineage(agent) { + const lineage = [agent]; + const seen = new Set([agent.id]); + let parentSession = agent.session.header.parentSession; + while (parentSession !== void 0) { + const parent = this.ctx.agents.get(parentSession); + if (parent === void 0 || seen.has(parent.id)) break; + lineage.push(parent); + seen.add(parent.id); + parentSession = parent.session.header.parentSession; + } + return lineage; + } + /** + * The teardown that closed continuable admission for this agent's lineage. + * `'manager'` is the whole manager draining; an Agent is the exact scoped root + * whose forest is closing. + * @param agent - the agent whose lineage is tested. + * @returns the closing teardown, or `undefined` while admission is open. + */ + closingTeardownFor(agent) { + if (this.draining) return "manager"; + const lineage = this.liveLineage(agent); + for (const [root, members] of this.closingScopes) if (members.has(agent) || lineage.includes(root)) return root; + } + /** Reject new admission once the manager or this exact parent tree began draining. */ + assertAdmitting(agent) { + const closing = this.closingTeardownFor(agent); + if (closing === void 0) return; + throw new SubagentError(closing === "manager" ? "continuable subagents are draining; the operation was not admitted" : `continuable subagents below parent "${closing.id}" are draining; the operation was not admitted`, "DRAINING"); + } + /** + * Derive residency from Agent quiescence and the owned-child set. `running` + * covers an active admission, an open turn, or accepted waking inbox work. + * + * `Agent.status` alone is insufficient: it stays `idle` between an accepted + * waking send and the microtask that admits it, so a synchronous inbox + * observer would see `settled` while a turn is already queued. `accepted` + * holds the ids this manager admitted but has not yet seen drained. + */ + stateOf(activation) { + if (activation.handle.agent.status === "running" || activation.accepted.size > 0) return "running"; + if (activation.ownedChildren.size > 0) return "waiting"; + return "settled"; + } + /** + * Cold-resume a persisted child: inspect and authorize its Session, fold the + * generic descriptor, create the Activation through `ctx.agents.resume()`, + * and submit the waiting turn. This never dispatches through a subagent + * provider — the persisted Session already holds the initial prefix and the + * descriptor is the whole reconstruction input. + */ + async coldResume(parent, childId, content, options) { + const persistence = this.requirePersistence(); + let loaded; + try { + loaded = await persistence.inspect(childId, options.signal); + } catch (error) { + options.signal.throwIfAborted(); + throw new SubagentError(`subagent "${childId}" is unavailable`, "NOT_RESUMABLE", { cause: error }); + } + options.signal.throwIfAborted(); + this.assertAdmitting(parent); + this.authorizeLineage(parent, childId, loaded.meta.parentSession); + const descriptor = foldSubagentDescriptor(loaded.events.slice(loaded.meta.seedLength ?? 0)); + if (descriptor === void 0 || descriptor.mode !== "continuable") throw new SubagentError(`subagent "${childId}" has no supported continuation state and cannot be resumed; do not retry send_message with this id`, "NOT_RESUMABLE"); + let activation; + try { + activation = await this.materialize({ + childId, + provider: descriptor.provider, + parent, + agentOptions: { + ...descriptor.agentProvider !== void 0 ? { provider: descriptor.agentProvider } : {}, + ...descriptor.agentModel !== void 0 ? { model: descriptor.agentModel } : {} + }, + composition: { + persona: descriptor.persona, + toolFilter: descriptor.toolFilter + }, + signal: options.signal + }); + } catch (error) { + options.signal.throwIfAborted(); + if (error instanceof SubagentError) throw error; + throw new SubagentError(`subagent "${childId}" is unavailable`, "NOT_RESUMABLE", { cause: error }); + } + return this.submitMaterialized(activation, content, options.source, parent, options.signal); + } + /** + * Submit to a freshly materialized Activation or roll it back completely. + * @param activation - the just-published Activation to admit or release. + * @param content - the initial or resumed message content. + * @param source - durable fields naming who supplied the accepted message. + * @param parent - the live direct parent authorizing admission. + * @param signal - caller cancellation owning admission until acceptance. + * @returns the accepted inbox message id. + */ + async submitMaterialized(activation, content, source, parent, signal) { + try { + return this.submitAdmitted(activation, content, source, parent, signal); + } catch (error) { + /* v8 ignore next -- rollback disposal failures must not mask the + * pre-acceptance signal, drain, or lifecycle failure. */ + await this.dispose(activation).catch(() => void 0); + throw error; + } + } + /** + * Create or resume the child Agent through the private activation-owner + * scope, install the handle in a fresh Activation, and register ownership on + * a continuation-managed parent. Rejection leaves no Activation, no handle, + * and no ownership membership. + */ + materialize(inputs) { + this.assertAdmitting(inputs.parent); + const settled = Promise.withResolvers(); + const lineage = this.liveLineage(inputs.parent); + const materialization = { + lineage, + settled: settled.promise + }; + this.materializations.add(materialization); + return this.materializeTracked(inputs, lineage).finally(() => { + this.materializations.delete(materialization); + settled.resolve(); + }); + } + /** + * Perform one tracked materialization. The caller keeps the drain barrier + * registered until this either returns a resident Activation or finishes + * rollback. + */ + async materializeTracked(inputs, parentLineage) { + const { childId, provider, parent, create } = inputs; + inputs.signal.throwIfAborted(); + const setup = (childCtx) => { + if (create !== void 0) appendDelegatedPolicyOverrides(childCtx.agent.session, create.delegatedPolicies); + applyChildComposition(childCtx, parent, inputs.composition); + return this.setupRegistry.apply(childCtx); + }; + const observer = this.host.observeActivation(provider, childId, parent); + const handle = create === void 0 ? await this.ownerCtx.agents.resume({ + resumeSessionId: childId, + agentOptions: inputs.agentOptions, + signal: inputs.signal, + setup + }) : await this.ownerCtx.agents.create({ + sessionId: childId, + meta: create.meta, + seed: create.seed, + agentOptions: inputs.agentOptions, + signal: inputs.signal, + setup + }); + const activation = { + childId, + parentSession: parent.id, + provider, + handle, + ancestry: new WeakSet([handle.agent, ...parentLineage]), + ownedChildren: /* @__PURE__ */ new Set(), + observer, + disposal: void 0, + accepted: /* @__PURE__ */ new Set(), + announced: false, + poke: Promise.withResolvers() + }; + this.activations.set(childId, activation); + try { + inputs.signal.throwIfAborted(); + this.assertAdmitting(parent); + this.acquireOwnership(parent, childId); + handle.agent.ctx.on("agent/inbox/claimed", ({ message }) => { + /* v8 ignore next -- a claim of an id this manager never admitted needs + * another sender on the same child, which no current path allows. */ + if (activation.accepted.delete(message.id)) this.wake(activation); + }); + handle.agent.ctx.on("agent/inbox/discarded", ({ message }) => { + if (activation.accepted.delete(message.id)) this.wake(activation); + }); + observer.start(handle.agent); + } catch (error) { + /* v8 ignore next -- rollback failure must not mask the admission failure + * that prevented this operation from returning an accepted message id. */ + await this.rollbackUnpublished(activation).catch(() => void 0); + throw error; + } + this.watchSettlement(activation); + return activation; + } + /** + * Release an Activation whose start edge was not published. The memoized + * transaction remains in the live map until handle disposal settles, so a + * concurrent drain or delivery observes the same closing boundary. + */ + rollbackUnpublished(activation) { + return activation.disposal ??= (async () => { + try { + await activation.handle.dispose(); + } finally { + this.activations.delete(activation.childId); + this.releaseOwnership(activation.childId); + } + })(); + } + /** + * Register the child in a continuation-managed parent's owned set before the + * child can run, so that parent cannot settle while the child is live. A + * top-level or other non-continuation Agent has no Activation and stays + * outside the waiting graph. + */ + acquireOwnership(parent, childId) { + const parentActivation = this.activations.get(parent.id); + if (parentActivation === void 0) return; + if (parentActivation.disposal !== void 0) throw new SubagentError(`subagent parent "${parent.id}" is being disposed; the child was not established`, "ACTIVATION_CLOSING"); + parentActivation.ownedChildren.add(childId); + } + /** Remove one child from its live owner's set and let that owner re-check settlement. */ + releaseOwnership(childId) { + for (const candidate of this.activations.values()) if (candidate.ownedChildren.delete(childId)) this.wake(candidate); + } + /** Let a settlement watcher re-observe quiescence after ownership or inbox changes. */ + wake(activation) { + activation.poke.resolve(); + activation.poke = Promise.withResolvers(); + } + /** + * Submit one message as the child's next FIFO turn and return its accepted + * inbox id. Acceptance is the operation's success boundary; the manager owns + * the Activation independently afterwards. + */ + submit(activation, content, source, parent) { + this.acquireOwnership(parent, activation.childId); + const message = createUserMessage({ + content, + source + }); + const accepted = this.admitWaking(activation, message.id, () => { + activation.handle.agent.followup(message); + }); + activation.announced = true; + return accepted; + } + /** + * Account one waking send across a resident Activation's settlement window. + * @param activation - Activation receiving waking inbox work. + * @param messageId - stable identity of the message about to be sent. + * @param send - synchronous send that publishes one enqueue occurrence. + * @returns the accepted message id. + */ + admitWaking(activation, messageId, send) { + activation.accepted.add(messageId); + try { + send(); + } catch (error) { + activation.accepted.delete(messageId); + throw error; + } + this.wake(activation); + return messageId; + } + /** + * Cross the final admission cutoff and submit without yielding. Signal abort, + * manager drain, or Activation disposal that wins before this synchronous + * span rejects without inbox acceptance. + */ + submitAdmitted(activation, content, source, parent, signal) { + signal.throwIfAborted(); + this.assertAdmitting(parent); + /* v8 ignore next 6 -- only a synchronous re-entrant disposer can change + * this field between the caller's live check and this no-await boundary. */ + if (disposalOf(activation) !== void 0) throw new SubagentError(`subagent "${activation.childId}" activation is being disposed; the message was not accepted`, "ACTIVATION_CLOSING"); + this.authorizeLineage(parent, activation.childId, activation.handle.agent.session.header.parentSession); + return this.submit(activation, content, source, parent); + } + /** + * Authorize one operation against the durable direct-parent lineage. Other + * agents, ancestors, teams, workflows, and hosts remain rejected until an + * explicit authority protocol has a production consumer. + */ + authorizeLineage(parent, childId, parentSession) { + if (this.ctx.agents.get(parent.id) !== parent) throw new SubagentError(`subagent "${childId}" delivery requires the exact live parent agent`, "UNAUTHORIZED"); + if (parentSession !== parent.id) throw new SubagentError(`subagent "${childId}" belongs to another parent session`, "UNAUTHORIZED"); + } + /** + * Follow one Activation to settlement: wait for Agent quiescence, then for + * every owned child to complete disposal, and dispose the handle once both + * hold. A `next-turn` delivered while `waiting` wakes the same Agent and + * returns it to `running`, so this re-observes rather than settling early. + */ + watchSettlement(activation) { + (async () => { + while (disposalOf(activation) === void 0) { + const poked = activation.poke.promise; + await Promise.race([activation.handle.agent.whenIdle(), poked]); + if (disposalOf(activation) !== void 0) return; + const settling = await this.locks.run(activation.childId, () => { + if (disposalOf(activation) !== void 0 || this.stateOf(activation) !== "settled") return Promise.resolve({ settling: false }); + return Promise.resolve({ + settling: true, + done: this.dispose(activation) + }); + }); + if (!settling.settling) { + if (activation.handle.agent.status !== "running") await poked; + continue; + } + try { + await settling.done; + } catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" activation teardown failed: ${errorChain(error)}`); + } + return; + } + })(); + } + /** + * Stop one Activation immediately, then release it child-first. The memoized + * transaction is installed before cancellation or recursive callbacks, so + * admission and reentrant teardown converge on the same owner. + * + * The final session flush is best effort and never prevents handle disposal + * or ownership release, because retaining a child would permanently pin its + * ancestors in `waiting`. + * @param activation - the residency epoch to stop and release. + * @returns the one disposal transaction owned by this Activation. + */ + dispose(activation) { + const existing = activation.disposal; + if (existing !== void 0) return existing; + const completion = Promise.withResolvers(); + activation.disposal = completion.promise; + this.finishDisposal(activation).then(completion.resolve, completion.reject); + return completion.promise; + } + /** + * Propagate stop synchronously, then finish the child-first release. + * @param activation - the Activation whose disposal transaction is installed. + * @returns once the handle and ownership edge are released. + */ + async finishDisposal(activation) { + this.wake(activation); + const { childId } = activation; + activation.handle.agent.cancel({ kind: "parent" }); + const idle = activation.handle.agent.whenIdle(); + const childDisposals = [...activation.ownedChildren].map((child) => this.activations.get(child)).filter((child) => child !== void 0).map((child) => this.dispose(child)); + const failures = []; + try { + const reasons = (await Promise.all(childDisposals.map(async (disposal) => { + try { + await disposal; + return; + } catch (error) { + return error; + } + }))).filter((reason) => reason !== void 0); + if (reasons.length > 0) failures.push(new SubagentError(`subagent "${childId}" child teardown failed: ${reasons.map((reason) => errorChain(reason)).join("; ")}`, "ACTIVATION_TEARDOWN_FAILED")); + await idle; + await this.flushFinalState(activation); + activation.observer.capture(activation.handle.agent); + } catch (error) { + failures.push(new SubagentError(`subagent "${childId}" activation teardown failed: ${errorChain(error)}`, "ACTIVATION_TEARDOWN_FAILED", { cause: error })); + } + try { + await activation.handle.dispose(); + } catch (error) { + failures.push(new SubagentError(`subagent "${childId}" activation handle disposal failed: ${errorChain(error)}`, "ACTIVATION_TEARDOWN_FAILED", { cause: error })); + } + let failure; + if (failures.length === 1) failure = failures[0]; + else if (failures.length > 1) failure = new SubagentError(`subagent "${childId}" activation teardown failed at ${failures.length} boundaries: ` + failures.map((item) => errorChain(item)).join("; "), "ACTIVATION_TEARDOWN_FAILED", { cause: new AggregateError(failures) }); + this.activations.delete(childId); + this.notifySettlement(activation, activation.observer.terminal(failure)); + this.releaseOwnership(childId); + activation.observer.settle(failure); + if (failure !== void 0) throw failure; + } + /** + * Tell the durable direct parent that this child produced everything it is + * going to. Unconditional for every child the caller received an id for: it + * does not consider whether the child reported, because the cases that most + * need it — a token ceiling, a model failure, cancellation, teardown — are + * exactly the ones where the child never got to choose. A materialization + * rolled back before its first acceptance stays silent, since the caller was + * told that child was not established. A parent that is no longer live is not + * an error; the child's own Session remains the durable record either way. + * A parent whose own lineage is already closing receives the notice without a + * wake, because teardown is not a reason to start a turn. + * + * Never blocks disposal. A delivery failure is logged and dropped, because + * retaining a child to retry a notice would pin its whole ancestry in + * `waiting` forever. + * @param activation - the settling Activation, still owned by its parent. + * @param terminal - how this epoch ended, as the terminal edge will report it. + */ + notifySettlement(activation, terminal) { + if (!activation.announced) return; + try { + const parent = this.ctx.agents.get(activation.parentSession); + if (parent === void 0) return; + const summary = settlementSummary(activation.childId, terminal.stopReason); + const message = createUserMessage({ + content: [{ + type: "text", + text: summary + }, ...terminal.output === void 0 ? [{ + type: "text", + text: "It left no closing message." + }] : [{ + type: "text", + text: "Its closing message:" + }, ...terminal.output]], + source: { + kind: "subagent-settled", + form: "notice", + summary: boundContextSummary(summary), + senderSessionId: activation.childId + } + }); + if (this.closingTeardownFor(parent) !== void 0) { + parent.inject(message); + return; + } + this.sendWaking(parent, message, () => { + if (parent.status === "idle") parent.followup(message); + else parent.steer(message); + }); + } catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" settlement notice was not delivered to its parent: ` + errorChain(error)); + } + } + /** + * Request a best-effort final session flush after the child is quiescent. + * Listener failure is logged because flush participation cannot identify a + * particular persistence backend, and teardown must still release ownership. + * @param activation - the Activation whose final events should be flushed. + */ + async flushFinalState(activation) { + const child = activation.handle.agent; + try { + await child.ctx.sessions.flush(child.session); + } catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" best-effort final session flush failed; the persisted state may be unavailable or stale on resume: ${errorChain(error)}`); + } + } + /** Resolve the persistence service continuable children require, or fail loud. */ + requirePersistence() { + const persistence = this.ctx.get("sessionPersistence"); + if (persistence === void 0) throw new SubagentError("continuable subagents require session persistence (load a dsh-session-persistence backend)", "PERSISTENCE_UNAVAILABLE"); + return persistence; + } +}; +//#endregion +//#region lib/types/activation-setup-registry.js +/** +* Internal registry of deployment capabilities composed into every continuable +* child's unpublished creation context. +* +* A contribution grants a child-scoped capability without teaching the +* continuation manager which capabilities exist. The manager owns residency; +* this registry owns the join between plugin lifetime, unpublished setup, and +* Activation disposal, so no installation outlives either owner and no removed +* contribution can be installed after revocation reports completion. +* +* @module @deepseek-ai/dsh-subagent/activation-setup-registry +*/ +/** Re-read mutable removal state after a contribution may have revoked itself. */ +function isRemoved(registration) { + return registration.removed; +} +/** +* Owns continuable-child setup registrations, installations, rollback, child +* cleanup, and immediate live revocation. +*/ +var SubagentActivationSetupRegistry = class { + /** Live contributions in installation order. */ + registrations = /* @__PURE__ */ new Set(); + /** Child context to its live installations. */ + byChild = /* @__PURE__ */ new Map(); + /** + * Register one contribution. + * @param contribution - synchronous child-scope installer. + * @returns an idempotent registration undo. + * @throws after attempting every installation when any disposer fails. + */ + register(contribution) { + const registration = { + contribution, + removed: false, + installations: /* @__PURE__ */ new Set() + }; + this.registrations.add(registration); + return () => { + if (registration.removed) return; + registration.removed = true; + this.registrations.delete(registration); + this.releaseAll([...registration.installations], "contribution removal"); + }; + } + /** + * Install every live contribution into one unpublished child context. + * @param childCtx - the child's unpublished scoped context. + * @returns the provisioning commit consumed at Agent publication. + */ + apply(childCtx) { + const state = { + installations: [], + invalidated: false + }; + try { + for (const registration of [...this.registrations]) { + /* v8 ignore next -- only a synchronous re-entrant revocation of an + * already-snapshotted registration reaches this guard. */ + if (registration.removed) continue; + const installation = { + registration, + childCtx, + dispose: registration.contribution(childCtx), + released: false, + transaction: state + }; + registration.installations.add(installation); + state.installations.push(installation); + let indexed = this.byChild.get(childCtx); + if (indexed === void 0) { + indexed = /* @__PURE__ */ new Set(); + this.byChild.set(childCtx, indexed); + } + indexed.add(installation); + if (isRemoved(registration)) this.release(installation); + } + } catch (error) { + try { + this.releaseAll([...state.installations], "setup rollback"); + } catch (releaseFailure) {} + throw error; + } + childCtx.effect(() => () => { + this.releaseChild(childCtx); + }, "subagents.activationSetup()"); + return { commit: () => { + if (state.invalidated) throw new SubagentError("a continuable-subagent setup contribution was revoked while this child was being built; the child was not established", "ACTIVATION_SETUP_REVOKED"); + for (const installation of state.installations) installation.transaction = void 0; + } }; + } + /** Release every remaining installation owned by one disposed child scope. */ + releaseChild(childCtx) { + const indexed = this.byChild.get(childCtx) ?? []; + this.releaseAll([...indexed], "child scope disposal"); + } + /** + * Release a batch completely before reporting disposer failures. + * @param installations - records to release. + * @param during - operation name for diagnostics. + */ + releaseAll(installations, during) { + const failures = []; + for (const installation of installations) try { + this.release(installation); + } catch (error) { + failures.push(error); + } + if (failures.length === 0) return; + throw new SubagentError(`continuable-subagent setup ${during} failed to release ${failures.length} installation(s): ` + failures.map((failure) => errorChain(failure)).join("; "), "ACTIVATION_SETUP_RELEASE_FAILED"); + } + /** Drop one installation from both indices and dispose it exactly once. */ + release(installation) { + if (installation.released) return; + installation.released = true; + installation.registration.installations.delete(installation); + const indexed = this.byChild.get(installation.childCtx); + /* v8 ignore next 4 -- every live installation is indexed until this method removes it. */ + if (indexed !== void 0) { + indexed.delete(installation); + if (indexed.size === 0) this.byChild.delete(installation.childCtx); + } + if (installation.transaction !== void 0) installation.transaction.invalidated = true; + installation.dispose(); + } +}; +//#endregion +//#region lib/types/list-children.js +/** +* Read-only enumeration of durable subagent children and descendant trees +* straight from the live session store and optional session persistence — no +* query service. Candidates come from one live-preferred corpus; each child's +* mode/label is the registered `subagent` projection unit's value, resolved +* down a three-rung ladder: the registry's watermark cache for a live child, +* a durable projection-cache row when it serves an own-suffix identity (the +* seq gate), and one persistence inspection folded through the registry +* otherwise, validated against the enumerated lifecycle. The projection fold +* is the single classification authority — this module parses no descriptor +* itself. Absent persistence, enumeration is live-only: a cold child is +* unreachable for resume anyway, so its absence is capability absence, not an +* error. The module owns no catalog state and does not consult Activation, +* Agent-registry, continuation-manager, or provider state. +* +* @module @deepseek-ai/dsh-subagent +*/ +/** +* Concurrent cold inspections per listing; a constant because it bounds one +* read-only scan of local media, not deployment behavior. Should a networked +* persistence backend appear, promote it to a validated `Config` field. +*/ +const COLD_READ_CONCURRENCY = 4; +/** +* Enumerate one parent's origin-classified direct children from the +* live-preferred merge of `ctx.sessions` and optional session persistence, +* serving each identity from the `subagent` projection unit: the registry's +* watermark snapshot for a live child; for a cold one, a durable +* projection-cache row when it serves an own-suffix identity (the seq gate), +* else one bounded-concurrency persistence inspection folded through the +* registry. +* @see SubagentRuntime.listChildren for the public cancellation and failure contract. +* @param ctx - context carrying the session store, the projection registry, +* optional persistence, and the optional projection cache. +* @param parentSessionId - parent session whose direct children are listed. +* @param signal - caller-owned cancellation observed around every persistence read. +* @returns children and per-child diagnostics ordered by `createdAt`, then id. +* @throws {@link SubagentError} when the projection registry or the session +* store is not mounted, or the caller cancels the listing. +*/ +async function listChildren(ctx, parentSessionId, signal) { + const listing = await prepareListing(ctx, signal); + return (await resolveCandidateRows([...listing.corpus.values()].filter((record) => record.header.parentSession === parentSessionId && record.header.origin === "subagent").sort(compareCorpusRecords), listing, signal)).filter((row) => row !== void 0); +} +/** +* Enumerate every session-backed subagent below one root in stable pre-order. +* Ordinary sessions and one-shot children remain traversal nodes, so a +* continuable child below either is still discovered. Classification uses the +* same projection-backed runtime as {@link listChildren}; no Agent is loaded or +* resumed. +* @see SubagentRuntime.listDescendants for the public cancellation and failure contract. +* @param ctx - context carrying the session store, projection registry, and optional persistence/cache. +* @param rootSessionId - session whose complete descendant tree is listed. +* @param signal - caller-owned cancellation observed around every persistence read. +* @returns interpreted subagents with durable direct-parent and root-relative depth. +* @throws {@link SubagentError} under the same conditions as {@link listChildren}. +*/ +async function listDescendants(ctx, rootSessionId, signal) { + const listing = await prepareListing(ctx, signal); + const positioned = descendantCandidates(listing.corpus, rootSessionId); + const rows = await resolveCandidateRows(positioned.map((candidate) => candidate.record), listing, signal); + const entries = []; + positioned.forEach((position, index) => { + const row = rows[index]; + if (row !== void 0) entries.push({ + ...row, + parentId: position.parentId, + depth: position.depth + }); + }); + return entries; +} +/** Resolve listing services once and build one live-preferred session corpus. */ +async function prepareListing(ctx, signal) { + const projections = ctx.get("sessionProjections"); + if (projections === void 0) throw new SubagentError("listing subagents requires the sessionProjections registry (load @deepseek-ai/dsh-session-projection)", "SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE"); + const sessions = ctx.get("sessions"); + if (sessions === void 0) throw new SubagentError("listing subagents requires the session store (load @deepseek-ai/dsh-session)", "SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE"); + assertListingNotCancelled(signal); + const persistence = ctx.get("sessionPersistence"); + const cache = ctx.get("sessionProjectionCache"); + let persistedHeaders = []; + if (persistence !== void 0) { + try { + persistedHeaders = await persistence.list(signal); + } catch (error) { + assertListingNotCancelled(signal); + throw error; + } + assertListingNotCancelled(signal); + } + const corpus = /* @__PURE__ */ new Map(); + for (const header of persistedHeaders) corpus.set(header.id, { + header, + live: void 0 + }); + for (const session of sessions.list()) corpus.set(session.header.id, { + header: session.header, + live: session + }); + const subagentParents = /* @__PURE__ */ new Set(); + for (const record of corpus.values()) if (record.header.origin === "subagent" && record.header.parentSession !== void 0) subagentParents.add(record.header.parentSession); + return { + projections, + persistence, + cache, + corpus, + subagentParents + }; +} +/** Resolve projection-backed rows for aligned candidates with bounded cold reads. */ +async function resolveCandidateRows(candidates, listing, signal) { + const { projections, persistence, cache, subagentParents } = listing; + const rows = Array.from({ length: candidates.length }); + const coldReads = []; + candidates.forEach((candidate, index) => { + const childId = candidate.header.id; + if (candidate.live === void 0) { + coldReads.push({ + index, + header: candidate.header + }); + return; + } + let identity; + try { + identity = projections.snapshot(candidate.live).values.subagent; + } catch { + rows[index] = { + kind: "diagnostic", + id: childId, + reason: "corrupt" + }; + return; + } + if (identity === void 0 || identity === null) return; + rows[index] = childRow(childId, identity, "running", subagentParents.has(childId)); + }); + if (persistence !== void 0 && coldReads.length > 0) { + const queue = [...coldReads]; + await Promise.all(Array.from({ length: Math.min(COLD_READ_CONCURRENCY, queue.length) }, async () => { + for (let job = queue.shift(); job !== void 0; job = queue.shift()) rows[job.index] = await resolveColdIdentity(persistence, projections, cache, job.header, subagentParents.has(job.header.id), signal); + })); + } + assertListingNotCancelled(signal); + return rows; +} +/** Build origin-classified candidates from the complete tree without recursion. */ +function descendantCandidates(corpus, rootSessionId) { + const children = /* @__PURE__ */ new Map(); + for (const record of corpus.values()) { + const parentId = record.header.parentSession; + if (parentId === void 0) continue; + const siblings = children.get(parentId); + if (siblings === void 0) children.set(parentId, [record]); + else siblings.push(record); + } + for (const siblings of children.values()) siblings.sort(compareCorpusRecords); + const positioned = []; + const stack = (children.get(rootSessionId) ?? []).map((record) => ({ + record, + parentId: rootSessionId, + depth: 1 + })).reverse(); + const visited = new Set([rootSessionId]); + while (stack.length > 0) { + const position = stack.pop(); + const id = position.record.header.id; + if (visited.has(id)) continue; + visited.add(id); + if (position.record.header.origin === "subagent") positioned.push(position); + const descendants = children.get(id) ?? []; + for (const record of [...descendants].reverse()) stack.push({ + record, + parentId: id, + depth: position.depth + 1 + }); + } + return positioned; +} +/** Compare siblings by durable creation time, then id. */ +function compareCorpusRecords(a, b) { + return a.header.createdAt - b.header.createdAt || a.header.id.localeCompare(b.header.id); +} +/** +* Resolve one cold candidate down the remaining ladder: a durable +* projection-cache row when it serves an own-suffix identity (the seq gate), +* otherwise one persistence inspection folded through the projection +* registry (the same detached recipe the API proxy uses for detached session +* projections). A failed inspection is one transient `unavailable` row +* retried on the next listing; an inspection naming another lifecycle, and a +* settled log the fold cannot identify — or that makes any registered unit +* throw — are final, so they report `corrupt`. +*/ +async function resolveColdIdentity(persistence, projections, cache, header, hasChildren, signal) { + const childId = header.id; + if (cache !== void 0) { + let cached; + try { + cached = cache.cachedSnapshot(header)?.values.subagent; + } catch { + cached = void 0; + } + if (cached !== void 0 && cached !== null && cached.seq >= (header.seedLength ?? 0)) return childRow(childId, cached, "inactive", hasChildren); + } + assertListingNotCancelled(signal); + let inspected; + try { + inspected = await persistence.inspect(childId, signal); + } catch { + assertListingNotCancelled(signal); + return { + kind: "diagnostic", + id: childId, + reason: "unavailable" + }; + } + assertListingNotCancelled(signal); + if (!sameLifecycle(inspected.meta, header)) return { + kind: "diagnostic", + id: childId, + reason: "corrupt" + }; + let identity; + try { + identity = projections.restore({}, inspected.events, 0).snapshot.values.subagent; + } catch { + return { + kind: "diagnostic", + id: childId, + reason: "corrupt" + }; + } + if (identity === void 0 || identity === null) return { + kind: "diagnostic", + id: childId, + reason: "corrupt" + }; + return childRow(childId, identity, "inactive", hasChildren); +} +/** Materialize one served identity as its child row. */ +function childRow(id, identity, activity, hasChildren) { + return identity.mode === "one-shot" ? { + kind: "child", + id, + mode: "one-shot", + ...identity.label !== void 0 ? { label: identity.label } : {}, + activity, + hasChildren + } : { + kind: "child", + id, + mode: "continuable", + label: identity.label, + activity, + hasChildren + }; +} +/** Immutable header fields that distinguish one session lifecycle from another under the same id. */ +const LIFECYCLE_WITNESS_KEYS = [ + "version", + "id", + "createdAt", + "cwd", + "parentSession", + "seedLength", + "delegationDepth" +]; +/** Whether an inspected log still belongs to the enumerated lifecycle. */ +function sameLifecycle(meta, expected) { + return LIFECYCLE_WITNESS_KEYS.every((key) => meta[key] === expected[key]); +} +/** Stop a listing at its next cancellation checkpoint. */ +function assertListingNotCancelled(signal) { + if (signal?.aborted) throw new SubagentError("subagent listing was cancelled", "CANCELLED"); +} +/** +* Fold turn boundaries around the child's own durable descriptor. +* +* A fork seed may contain an ancestor descriptor and completed turns. Every +* descriptor therefore resets the accumulated state; the healthy catalog +* admits only a child with exactly one descriptor in its own suffix, making +* the final reset the child's authoritative timing origin. +*/ +const subagentTimingProjectionDefinition = { + key: "subagentTiming", + schema: z.object({ + settledMs: z.number().int().nonnegative(), + active: z.object({ + since: z.number().int().nonnegative(), + through: z.number().int().nonnegative() + }).strict().optional() + }).strict(), + init: () => ({ + descriptorSeen: false, + settledMs: 0 + }), + apply: (state, event) => { + if (event.type === "turn/start") return state.descriptorSeen ? { + ...state, + active: { + since: event.time, + through: event.time + } + } : { + ...state, + pendingTurnStart: event.time + }; + if (event.type === "subagent/descriptor") { + const activeSince = state.active?.since ?? state.pendingTurnStart; + return { + descriptorSeen: true, + settledMs: 0, + ...activeSince === void 0 ? {} : { active: { + since: activeSince, + through: event.time + } } + }; + } + if (event.type === "turn/end") { + if (!state.descriptorSeen) { + if (state.pendingTurnStart === void 0) return state; + const { pendingTurnStart: _closed, ...next } = state; + return next; + } + if (state.active === void 0) return state; + const { active, ...rest } = state; + return { + ...rest, + settledMs: state.settledMs + Math.max(0, event.time - active.since) + }; + } + if (state.active === void 0) return state; + return { + ...state, + active: { + ...state.active, + through: event.time + } + }; + }, + view: (state) => ({ + settledMs: state.settledMs, + ...state.active === void 0 ? {} : { active: state.active } + }), + stateVersion: 2 +}; +const identitySchema = z.discriminatedUnion("mode", [z.object({ + mode: z.literal("one-shot"), + label: z.string().optional(), + seq: z.number().int().nonnegative() +}).strict(), z.object({ + mode: z.literal("continuable"), + label: z.string(), + seq: z.number().int().nonnegative() +}).strict()]).nullable(); +/** Interpret one `subagent/descriptor` event's identity; no value when the payload cannot be trusted. */ +function descriptorIdentity(event) { + let descriptor; + try { + descriptor = foldSubagentDescriptor([event]); + } catch { + descriptor = void 0; + } + if (descriptor === void 0) return void 0; + return descriptor.mode === "one-shot" ? { + mode: "one-shot", + ...descriptor.label !== void 0 ? { label: descriptor.label } : {}, + seq: event.seq + } : { + mode: "continuable", + label: descriptor.label, + seq: event.seq + }; +} +/** +* Fold the durable mode/label identity from `subagent/descriptor` events, +* last-wins: a fork seed may replay an ancestor's descriptor, and the child's +* own descriptor must override it — the same reset discipline as +* {@link subagentTimingProjectionDefinition}. A malformed or unknown-version +* payload resets to the `null` sentinel instead of throwing, so a fork of a +* healthy ancestor never inherits an identity its own descriptor failed to +* establish — and the reset survives every JSON push frame, so a consumer +* holding the earlier identity replaces it instead of keeping it stale; +* `null` ⟺ no valid descriptor, with the causes deliberately undistinguished. +*/ +const subagentIdentityProjectionDefinition = { + key: "subagent", + schema: identitySchema, + init: () => ({}), + apply: (state, event) => { + if (event.type !== "subagent/descriptor") return state; + const identity = descriptorIdentity(event); + return identity === void 0 ? {} : { identity }; + }, + view: (state) => state.identity ?? null, + stateVersion: 2 +}; +//#endregion +//#region lib/types/out-of-process.js +/** +* Provider-side vocabulary for OUT-OF-PROCESS subagent backends — the pieces +* that enforce this seam's own contracts around a child in another process: +* the no-capabilities advertisement, timing-bound validation, child +* working-directory resolution (config override, else the delegating parent +* session's workspace), the never-reject result settlement, and the standard +* run-handle publication. Backends compose these with their own wire drivers; +* the process machinery itself (spawn, env scrub, tree-scoped teardown) +* belongs to the `dsh-subprocess` seam. +* +* @module @deepseek-ai/dsh-subagent/out-of-process +*/ +/** +* The capability advertisement of an out-of-process backend: NONE. A child in +* another process cannot honor parent-enforced start features +* (`outputSchema`/`maxDepth`/`toolFilter`/`persona`), so the service rejects a +* request needing any of them before `start` runs — never accepted-then-ignored. +*/ +const NO_START_CAPABILITIES = Object.freeze({ + outputSchema: false, + depthLimit: false, + toolFilter: false, + persona: false +}); +/** +* Assert a configured timing bound is a positive finite number (it bounds a +* teardown or shutdown wait; zero, negative, or NaN would skip or wedge it). +* @param prefix - the consuming plugin's diagnostic prefix (e.g. `subagent-acp`). +* @param name - the config field name, for the diagnostic. +* @param value - the configured value. +*/ +function assertPositiveFinite(prefix, name, value) { + if (!Number.isFinite(value) || value <= 0) throw new Error(`${prefix}: ${name} must be a positive finite number`); +} +/** +* Whether `path` names an existing directory the harness can ENTER. The +* search-permission probe matters: `statSync().isDirectory()` is true for a +* mode-600 directory, but a subprocess cwd needs `X_OK` or spawn fails EACCES. +*/ +function isEnterableDirectory(path) { + try { + if (!statSync(path).isDirectory()) return false; + accessSync(path, constants.X_OK); + return true; + } catch { + return false; + } +} +/** +* Assert `cwd` can actually host the child: absolute (it doubles as the +* child's workspace identity, and a relative path would be re-anchored to the +* server process's launch directory) and an existing directory (fail here, +* before the process boundary, instead of as an ambiguous spawn ENOENT). +* @param prefix - the consuming plugin's diagnostic prefix. +* @param label - which source supplied the value, for the diagnostic. +* @param cwd - the candidate working directory. +* @returns `cwd`, validated. +*/ +function assertUsableCwd(prefix, label, cwd) { + if (!isAbsolute(cwd)) throw new Error(`${prefix}: ${label} must be an absolute path: ${cwd}`); + if (!isEnterableDirectory(cwd)) throw new Error(`${prefix}: ${label} is not an accessible directory: ${cwd}`); + return cwd; +} +/** +* Validate a configured `cwd` override ONCE, at plugin load: reject the empty +* string (`path.resolve('')` is the process cwd — it would silently +* reintroduce the launch-directory fallback this resolution removes), +* interpret a relative path against the harness launch directory, and require +* an enterable directory. +* @param prefix - the consuming plugin's diagnostic prefix. +* @param cwd - the configured override, or `undefined` when the config omits it. +* @returns the validated absolute override, or `undefined` when omitted. +*/ +function validateConfiguredCwd(prefix, cwd) { + if (cwd === void 0) return void 0; + if (cwd === "") throw new Error(`${prefix}: config cwd must not be empty — omit the key to inherit the parent session cwd`); + return assertUsableCwd(prefix, "config cwd", resolve(cwd)); +} +/** +* Resolve the child's working directory at start: the deployment override +* when configured (already validated at load), else the parent session's +* workspace cwd (validated here, its earliest resolvable point). Fails loud +* when neither exists — falling back to the harness process cwd would +* silently bind the child to the server's launch directory instead of the +* delegating session's workspace (one server process serves many sessions, +* each with its own cwd). +* @param prefix - the consuming plugin's diagnostic prefix. +* @param configured - the load-validated override, or `undefined`. +* @param parentCwd - the delegating parent session's workspace cwd, if any. +* @returns the absolute child working directory. +*/ +function resolveChildCwd(prefix, configured, parentCwd) { + if (configured !== void 0) return configured; + if (parentCwd === void 0) throw new Error(`${prefix}: no working directory for the child — configure \`cwd\` or delegate from a parent session that has one`); + return assertUsableCwd(prefix, "parent session cwd", parentCwd); +} +/** Normalize an unknown thrown value to an Error (the catch binding is `unknown`). */ +function toError(value) { + /* v8 ignore next */ + return value instanceof Error ? value : new Error(String(value)); +} +/** +* Settle an out-of-process run result under the seam contract: `result` never +* rejects after publication. A normally completed or rejected attempt resolves +* as `aborted` when cancellation already settled locally; another rejection is +* flattened to `stopReason: 'error'` through the contained diagnostic sink. +* The abort listener is removed on every path. +* @param parts - the attempt, output snapshot, cancellation state, sink, and signal wiring. +* @returns the terminal result (never a rejection). +*/ +async function settleRunResult(parts) { + try { + const result = await parts.attempt(); + return parts.cancelled() ? { + output: parts.collectOutput(), + stopReason: "aborted" + } : result; + } catch (error) { + if (parts.cancelled()) return { + output: parts.collectOutput(), + stopReason: "aborted" + }; + try { + parts.onError?.(toError(error), "error"); + } catch {} + return { + output: parts.collectOutput(), + stopReason: "error" + }; + } finally { + parts.signal.removeEventListener("abort", parts.onAbort); + } +} +/** +* Publish the seam run handle for an out-of-process child. `dispose()` is +* idempotent (one memoized teardown): it removes the abort listener, settles +* local cancellation — there is no assumption the child cooperates — and then +* awaits the backend's teardown to actual exit. +* @param parts - the run identity, result, cancellation wiring, and teardown. +* @returns the seam run handle (`localAgent` is `undefined` for remote runs). +*/ +function subprocessRunHandle(parts) { + let disposal; + return { + id: parts.id, + localAgent: void 0, + result: parts.result, + dispose() { + if (disposal !== void 0) return disposal; + parts.signal.removeEventListener("abort", parts.onAbort); + parts.requestCancel(); + disposal = parts.teardown(); + return disposal; + } + }; +} +//#endregion +//#region lib/types/run-settlement.js +/** +* Settlement of one ONE-SHOT subagent run into a background-Task outcome. Only +* the one-shot background path uses Jobs; continuable children have no Task, +* no per-message result, and no Task cancellation. +* +* @module @deepseek-ai/dsh-subagent/run-settlement +*/ +/** Flatten a child's final output blocks to the task's final text. */ +function finalText(blocks) { + return blocks.filter((block) => block.type === "text").map((block) => block.text).join(""); +} +/** +* Map a child result to the task outcome: completed carries final text, +* aborted is killed, and every other reason is failed without partial output. +* @param result - child terminal result. +* @returns outcome for the `ctx.jobs` registration. +*/ +function runOutcome(result) { + switch (result.stopReason) { + case "completed": return { + status: "completed", + output: finalText(result.output) + }; + case "aborted": return { status: "killed" }; + case "error": + case "max-tokens": + case "refusal": return { + status: "failed", + detail: result.stopReason + }; + default: return { + status: "failed", + detail: String(result.stopReason) + }; + } +} +/** +* Await the child result, dispose the run, then return its task outcome. Result +* and disposal failures become `failed`; when both fail, both details survive. +* @param run - live run to settle and release. +* @returns outcome after child resources are released. +*/ +async function settleRun(run) { + let outcome; + try { + outcome = runOutcome(await run.result); + } catch (error) { + outcome = { + status: "failed", + detail: String(error) + }; + } + try { + await run.dispose(); + } catch (error) { + return { + status: "failed", + detail: `${outcome.detail === void 0 ? "" : `${outcome.detail}; `}dispose failed: ${String(error)}` + }; + } + return outcome; +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for the subagent capability seam (`ctx.subagents`): a named-provider registry plus a +* capability-validating asynchronous start API. Providers establish a +* child before returning its run, so fulfillment is the single publication and +* ownership-transfer boundary. +* +* Unlike the bash seam (one executor per context, second load throws), MULTIPLE +* providers coexist here: each registers under a unique name and a caller picks +* one by name. The shape mirrors the LLM adapter registry +* (`LlmRuntime.registerAdapter`), not the single-service bash executor. +* +* This package owns the Service Definition role of the capability seam. Service Providers +* (`@deepseek-ai/dsh-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing +* consumer (`@deepseek-ai/dsh-tool-subagent`) are separate packages. +* +* Public operations express caller intent: `start` returns one published owned +* one-shot run, `startContinuable` establishes a durable continuable child, and +* `followup` delivers later content without exposing whether the child is +* resident. Continuable children never become a {@link SubagentRun}: the +* continuation manager holds their `AgentHandle` directly and orders every turn +* through the child's own inbox, so providers contribute only the detached +* creation spec and see no handle, turn, or teardown. Child and descendant +* discovery read the live session store and optional session persistence +* directly and do not require that continuation runtime. +* +* Same-process providers are trusted typed collaborators. Requests, provider +* descriptors, results, and lifecycle payloads are borrowed immutable values; +* serialization and hostile-input validation belong at real process, worker, +* persistence, and model boundaries. +* +* @module @deepseek-ai/dsh-subagent +*/ +/** Named provider registry with one-shot runs, durable discovery, and continuable-child operations. */ +var SubagentRuntime = class extends Service { + providers = /* @__PURE__ */ new Map(); + continuations; + /** Deployment contributions composed into unpublished continuable children. */ + setupRegistry = new SubagentActivationSetupRegistry(); + /** + * The contained lifecycle-edge publisher. Built here because scoped dispatch + * keys its carrier by this exact service instance, whose own context filter + * composes into the carrier. + */ + emitLifecycle; + constructor(ctx) { + super(ctx, "subagents"); + this.emitLifecycle = createLifecycleEmitter(this.ctx, (parent) => scopeTarget(this, parent)); + ctx.inject(["agents"], (childCtx) => { + const manager = new SubagentContinuationManager(childCtx, { + prepareContinuable: (name, request) => this.prepareContinuable(name, request), + observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent) + }, this.setupRegistry); + this.continuations = manager; + childCtx.effect(() => () => { + /* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */ + if (this.continuations === manager) this.continuations = void 0; + }, "subagents.continuationBinding()"); + }); + ctx.inject(["sessionProjections"], (projectionCtx) => { + projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition); + projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition); + }); + } + /** + * Establish one durable continuable child and deliver its initial prompt. + * Resolves when the child's inbox accepts that prompt, without waiting for the + * turn to start or for the message to reach the Session log; any earlier + * failure rejects with no ids and rolls back the child entirely. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted prompt's message id. + * @throws when continuation services are unavailable or materialization fails. + */ + async startContinuable(spec) { + return this.requireContinuations().startContinuable(spec); + } + /** + * Deliver one later message to a continuable child as its next FIFO turn. A + * resident child's Agent inbox accepts it directly (waking a `waiting` + * Activation), while an absent one is cold-resumed from its persisted + * Session. The Agent inbox is the only queue, so every accepted message has + * one observable order. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - durable child session id. + * @param content - user-role content to deliver. + * @param options - the message source fields and caller cancellation, which stops the + * operation only before inbox acceptance. + * @returns the accepted message's inbox id. + * @throws when continuation services are unavailable, parent authority is + * rejected, or the message was not admitted. + */ + async followup(parent, childId, content, options) { + return this.requireContinuations().followup(parent, childId, content, options); + } + /** + * Interrupt one live continuable child's current turn under a human parent + * address or an exact live ancestor Agent. Fire-and-return: the cancel + * signal is issued before this returns, but the target may keep running + * until it observes the signal. Unclaimed pending inbox work, the Activation, + * and published descendants are preserved; claimed work is not requeued. + * Once the interrupted driver is idle, a waking send resumes the parked FIFO + * queue. An absent target — including a one-shot or unknown id — + * is an accepted no-op, as is a manager-less composition, which cannot own a + * live Activation. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the authority does not own the + * live target. + */ + interrupt(targetSessionId, authority) { + this.continuations?.interrupt(targetSessionId, authority); + } + /** + * Deliver selected content from one live continuable child to its durable + * direct parent. The child is the authority credential; callers cannot name a + * recipient. Reporting does not conclude the child's turn or Activation. + * @param child - exact live reporting child. + * @param content - selected model-facing content. + * @param options - parent scheduling and pre-acceptance cancellation. + * @returns the stable identity of the parent-accepted message. + * @throws when continuation services are unavailable, sender authorization + * fails, or the direct parent is not live. + */ + async reportFrom(child, content, options) { + return this.requireContinuations().reportFrom(child, content, options); + } + /** + * Compose one deployment capability into every continuable child's + * unpublished creation context on fresh creation and cold resume. Grants wait + * for the next Activation; removing the contribution revokes every resident + * installation immediately. + * @param contribution - synchronous child-scope installer. + * @returns the exact Cordis effect disposer. + */ + registerContinuableSetup(contribution) { + return this.ctx.effect(() => this.setupRegistry.register(contribution), "subagents.registerContinuableSetup()"); + } + /** + * Close continuable admission below exact live parent Agents, stop only their + * visible descendant Activations synchronously, then await admitted scoped + * materializations and release those forests child-first. The scoped cutoff + * lasts until each exact parent leaves the registry; unrelated parent trees + * remain live. + * @param parents - exact host-owned parent Agents entering teardown. + * @returns once every retained descendant Activation released its `AgentHandle`. + * @throws an aggregate error after all branches settle when any failed. + */ + async drainContinuableDescendants(parents) { + const manager = this.continuations; + if (manager === void 0) return; + await manager.drainDescendants(parents); + } + /** + * Enumerate the parent's direct session-backed subagents without loading or + * resuming an Agent and without any query service: the listing merges the live + * session store with optional session persistence (live-preferred) and + * serves each child's durable mode/label from the registered `subagent` + * projection unit down a three-rung ladder — the registry's watermark + * snapshot for a live child; for a cold one, a durable projection-cache + * row when the optional cache serves an own-suffix identity (its `seq` + * gate proves the value postdates the fork seed, where a child's own + * descriptor is immutable once appended), else one persistence inspection + * folded through the registry. The + * projection fold is the single classification authority; per-child + * diagnostics relay a fold that served no identity or a failed inspection, + * never a list-time descriptor parse. Absent persistence, enumeration is + * live-only (a cold child cannot be resumed then either, so its absence is + * capability absence, not an error). This service consults no Agent + * registrations, Activations, or providers. + * + * Every persistence read receives `signal`, and the listing rechecks + * cancellation around each of those awaits. Read rejections that settle + * after an abort become a stable `SubagentError` with code `CANCELLED`. + * @param parentSessionId - parent session whose direct children are listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-child diagnostics ordered by `createdAt`, then id. + * @throws {@link SubagentError} when the projection registry or the session + * store is not mounted, or the caller cancels the listing. + */ + listChildren(parentSessionId, signal) { + return listChildren(this.ctx, parentSessionId, signal); + } + /** + * Enumerate the root's complete session-backed subagent tree in stable + * pre-order from one live-preferred corpus, without loading or resuming an + * Agent. Ordinary sessions and one-shot children remain traversal nodes so + * continuable descendants below them are discovered; each returned entry + * adds its durable `parentId` and root-relative `depth`. Identity resolution, + * diagnostics, optional persistence, and cancellation follow the same + * projection-backed contract as {@link listChildren}. + * @param rootSessionId - session whose complete descendant tree is listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-candidate diagnostics with tree position, in + * stable pre-order. + * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + */ + listDescendants(rootSessionId, signal) { + return listDescendants(this.ctx, rootSessionId, signal); + } + /** + * Register a provider under its name. Registration is effect-scoped and HMR + * safe; removing a provider blocks new starts but does not revoke runs that + * were already returned to their holders. + * @param provider - the trusted provider implementation. + * @returns the exact Cordis effect disposer. + */ + registerProvider(provider) { + const name = provider.name; + return this.ctx.effect(function* () { + if (this.providers.has(name)) throw new SubagentError(`a subagent provider named "${name}" is already registered`, "DUPLICATE_PROVIDER"); + this.providers.set(name, provider); + yield () => { + this.providers.delete(name); + this.emitLifecycle("subagent/provider-removed", name); + }; + this.ctx.emit("subagent/provider-added", provider); + }.bind(this), "subagents.registerProvider()"); + } + /** + * Look up a provider by name. + * @param name - the provider name. + * @returns the provider, or undefined when absent. + */ + getProvider(name) { + return this.providers.get(name); + } + /** + * List registered provider names in insertion order. + * @returns the registered names. + */ + list() { + return [...this.providers.keys()]; + } + /** + * Establish a published child on the named provider. Capability and semantic + * checks run before delegation. Provider ownership lasts until its promise + * fulfills; a rejection therefore has no run for the caller to dispose and + * emits no run lifecycle events. Post-publication turn and infrastructure + * failures settle through the returned run. + * @param name - the provider to use. + * @param request - child label, prompt, parent, signal, and optional capabilities. + * @returns the published holder-owned run. + */ + async start(name, request) { + const provider = this.expectProvider(name); + this.assertCapabilities(provider, request); + assertSubagentMaxDepth(request.maxDepth); + if (request.outputSchema !== void 0) assertObjectJsonSchema(request.outputSchema); + const descriptor = snapshotSubagentDescriptor({ + mode: "one-shot", + provider: name, + ...request.label !== void 0 ? { label: request.label } : {} + }); + const resolved = { + ...request, + descriptor + }; + return observeRun(this.emitLifecycle, name, request.parent, await provider.start(resolved)); + } + /** + * Resolve one provider's detached continuable-creation contribution. Method + * presence on the provider IS the capability, so a provider without it is + * rejected before the manager reserves any child resources. + */ + async prepareContinuable(name, request) { + const provider = this.expectProvider(name); + if (provider.prepareContinuable === void 0) throw new SubagentError(`subagent provider "${provider.name}" does not support continuable children (no prepareContinuable capability)`, "UNSUPPORTED_CAPABILITY"); + return provider.prepareContinuable(request); + } + /** Look up a provider for dispatch or fail loud. */ + expectProvider(name) { + const provider = this.providers.get(name); + if (provider === void 0) throw new SubagentError(`no subagent provider registered for "${name}"`, "NO_PROVIDER"); + return provider; + } + /** Resolve the optional continuable-subagent manager or fail loud. */ + requireContinuations() { + if (this.continuations === void 0) throw new SubagentError("continuable subagents require the agents service", "CONTINUATION_UNAVAILABLE"); + return this.continuations; + } + /** + * Build the lifecycle observer for one continuable Activation's residency + * epoch, so the manager publishes its edges without owning event dispatch. + */ + observeActivation(provider, childId, parent) { + return createActivationObserver(this.emitLifecycle, provider, childId, parent); + } + /** Reject the first requested capability that the provider lacks. */ + assertCapabilities(provider, request) { + const needs = [ + { + when: request.outputSchema !== void 0, + cap: "outputSchema" + }, + { + when: request.maxDepth !== void 0, + cap: "depthLimit" + }, + { + when: request.toolFilter !== void 0, + cap: "toolFilter" + }, + { + when: request.persona !== void 0, + cap: "persona" + } + ]; + for (const { when, cap } of needs) if (when && !provider.capabilities[cap]) throw new SubagentError(`subagent provider "${provider.name}" does not support the "${cap}" capability`, "UNSUPPORTED_CAPABILITY"); + } +}; +//#endregion +export { AssistantOutputFold, NO_START_CAPABILITIES, SUBAGENT_DESCRIPTOR_VERSION, SubagentDepthError, SubagentError, SubagentRunId, SubagentRuntime, SubagentRuntime as default, appendDelegatedPolicyOverrides, applyChildComposition, assertPositiveFinite, assertSubagentMaxDepth, assertUsableCwd, captureDelegatedPolicyOverrides, childSessionMeta, delegationDepthOf, finalAssistantOutput, foldSubagentDescriptor, resolveChildAgentOptions, resolveChildCwd, resolveChildDepth, seedDescriptorTurn, settleRun, settleRunResult, snapshotSubagentDescriptor, subprocessRunHandle, validateConfiguredCwd }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/invariant.js new file mode 100644 index 0000000..81138a2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/invariant.js @@ -0,0 +1,76 @@ +//#region lib/types/invariant.js +/** Package-owned subagent registry and lifecycle invariants. @module @deepseek-ai/dsh-subagent/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-subagent"; +/** Cordis companion plugin name. */ +const name = "subagent-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Assert that a terminal lifecycle payload matches its start identity. */ +function validateRunEnd(start, end, fail) { + if (start.provider !== end.provider || start.id !== end.id || start.local !== end.local) fail(`subagent/end identity diverges from subagent/start for run ${JSON.stringify(end.runId)}`); +} +/** Install provider-registry and start/end pairing checks. */ +const install = Object.assign((ctx, fail) => { + const providers = new Set(ctx.subagents.list()); + const runs = /* @__PURE__ */ new Map(); + const stagedProviders = /* @__PURE__ */ new WeakSet(); + const stagedRemovals = /* @__PURE__ */ new Set(); + const stagedStarts = /* @__PURE__ */ new WeakSet(); + const stagedEnds = /* @__PURE__ */ new WeakSet(); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName === "subagent/provider-added") { + const provider = args[0]; + if (provider.name.length === 0) fail("subagent provider names must be non-empty"); + if (providers.has(provider.name)) fail(`subagent/provider-added repeated ${JSON.stringify(provider.name)}`); + stagedProviders.add(provider); + return; + } + if (eventName === "subagent/provider-removed") { + const providerName = args[0]; + if (!providers.has(providerName)) fail(`subagent/provider-removed names unknown provider ${JSON.stringify(providerName)}`); + stagedRemovals.add(providerName); + return; + } + if (eventName === "subagent/start") { + const info = args[0]; + if (info.provider.length === 0 || String(info.runId).length === 0 || String(info.id).length === 0) fail("subagent/start provider, runId, and child id must be non-empty"); + if (runs.has(info.runId)) fail(`subagent/start repeated run id ${JSON.stringify(info.runId)}`); + stagedStarts.add(info); + return; + } + if (eventName !== "subagent/end") return; + const info = args[0]; + const start = runs.get(info.runId); + if (start === void 0) fail(`subagent/end has no matching subagent/start for run ${JSON.stringify(info.runId)}`); + validateRunEnd(start, info, fail); + stagedEnds.add(info); + }, { global: true }); + ctx.on("subagent/provider-added", (provider) => { + /* v8 ignore next -- internal/dispatch stages the same provider object */ + if (!stagedProviders.delete(provider)) return; + providers.add(provider.name); + }, { global: true }); + ctx.on("subagent/provider-removed", (providerName) => { + /* v8 ignore next -- internal/dispatch stages the same provider name */ + if (!stagedRemovals.delete(providerName)) return; + providers.delete(providerName); + }, { global: true }); + ctx.on("subagent/start", (info) => { + /* v8 ignore next -- internal/dispatch stages the same lifecycle object */ + if (!stagedStarts.delete(info)) return; + runs.set(info.runId, info); + }, { global: true }); + ctx.on("subagent/end", (info) => { + /* v8 ignore next -- internal/dispatch stages the same lifecycle object */ + if (!stagedEnds.delete(info)) return; + runs.delete(info.runId); + }, { global: true }); +}, { inject: ["subagents"] }); +/** +* Register the subagent invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.d.ts new file mode 100644 index 0000000..d7aba36 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.d.ts @@ -0,0 +1,57 @@ +/** + * Internal registry of deployment capabilities composed into every continuable + * child's unpublished creation context. + * + * A contribution grants a child-scoped capability without teaching the + * continuation manager which capabilities exist. The manager owns residency; + * this registry owns the join between plugin lifetime, unpublished setup, and + * Activation disposal, so no installation outlives either owner and no removed + * contribution can be installed after revocation reports completion. + * + * @module @deepseek-ai/dsh-subagent/activation-setup-registry + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { AgentSetupCommit } from '@deepseek-ai/dsh-agent'; +/** + * One deployment capability installed into a continuable child's unpublished + * creation context. It composes synchronously before publication and returns + * the disposer for exactly that installation. + * @param childCtx - the child's unpublished scoped context. + * @returns the disposer revoking this installation. + */ +export type ContinuableSetupContribution = (childCtx: Context) => () => void; +/** + * Owns continuable-child setup registrations, installations, rollback, child + * cleanup, and immediate live revocation. + */ +export declare class SubagentActivationSetupRegistry { + /** Live contributions in installation order. */ + private readonly registrations; + /** Child context to its live installations. */ + private readonly byChild; + /** + * Register one contribution. + * @param contribution - synchronous child-scope installer. + * @returns an idempotent registration undo. + * @throws after attempting every installation when any disposer fails. + */ + register(contribution: ContinuableSetupContribution): () => void; + /** + * Install every live contribution into one unpublished child context. + * @param childCtx - the child's unpublished scoped context. + * @returns the provisioning commit consumed at Agent publication. + */ + apply(childCtx: Context): AgentSetupCommit; + /** Release every remaining installation owned by one disposed child scope. */ + private releaseChild; + /** + * Release a batch completely before reporting disposer failures. + * @param installations - records to release. + * @param during - operation name for diagnostics. + */ + private releaseAll; + /** Drop one installation from both indices and dispose it exactly once. */ + private release; +} +export default SubagentActivationSetupRegistry; +//# sourceMappingURL=activation-setup-registry.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.js new file mode 100644 index 0000000..c113508 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/activation-setup-registry.js @@ -0,0 +1,148 @@ +/** + * Internal registry of deployment capabilities composed into every continuable + * child's unpublished creation context. + * + * A contribution grants a child-scoped capability without teaching the + * continuation manager which capabilities exist. The manager owns residency; + * this registry owns the join between plugin lifetime, unpublished setup, and + * Activation disposal, so no installation outlives either owner and no removed + * contribution can be installed after revocation reports completion. + * + * @module @deepseek-ai/dsh-subagent/activation-setup-registry + */ +import { errorChain } from '@deepseek-ai/dsh-llm'; +import { SubagentError } from "./error.js"; +/** Re-read mutable removal state after a contribution may have revoked itself. */ +function isRemoved(registration) { + return registration.removed; +} +/** + * Owns continuable-child setup registrations, installations, rollback, child + * cleanup, and immediate live revocation. + */ +export class SubagentActivationSetupRegistry { + /** Live contributions in installation order. */ + registrations = new Set(); + /** Child context to its live installations. */ + byChild = new Map(); + /** + * Register one contribution. + * @param contribution - synchronous child-scope installer. + * @returns an idempotent registration undo. + * @throws after attempting every installation when any disposer fails. + */ + register(contribution) { + const registration = { contribution, removed: false, installations: new Set() }; + this.registrations.add(registration); + return () => { + if (registration.removed) + return; + // Close before disposal so a snapshotted apply() cannot install after + // revocation reports completion. + registration.removed = true; + this.registrations.delete(registration); + this.releaseAll([...registration.installations], 'contribution removal'); + }; + } + /** + * Install every live contribution into one unpublished child context. + * @param childCtx - the child's unpublished scoped context. + * @returns the provisioning commit consumed at Agent publication. + */ + apply(childCtx) { + const state = { installations: [], invalidated: false }; + try { + for (const registration of [...this.registrations]) { + /* v8 ignore next -- only a synchronous re-entrant revocation of an + * already-snapshotted registration reaches this guard. */ + if (registration.removed) + continue; + const installation = { + registration, + childCtx, + dispose: registration.contribution(childCtx), + released: false, + transaction: state, + }; + registration.installations.add(installation); + state.installations.push(installation); + let indexed = this.byChild.get(childCtx); + if (indexed === undefined) { + indexed = new Set(); + this.byChild.set(childCtx, indexed); + } + indexed.add(installation); + // An installer may revoke itself before its installation record exists. + // Dispose that escaped record and invalidate the provisioning batch. + if (isRemoved(registration)) + this.release(installation); + } + } + catch (error) { + // Keep the installer failure authoritative, but attempt every rollback. + try { + this.releaseAll([...state.installations], 'setup rollback'); + } + catch (releaseFailure) { + /* v8 ignore next -- requires independent installer and rollback faults. */ + void releaseFailure; + } + throw error; + } + childCtx.effect(() => () => { this.releaseChild(childCtx); }, 'subagents.activationSetup()'); + return { + commit: () => { + if (state.invalidated) { + throw new SubagentError('a continuable-subagent setup contribution was revoked while this child was being built; ' + + 'the child was not established', 'ACTIVATION_SETUP_REVOKED'); + } + for (const installation of state.installations) + installation.transaction = undefined; + }, + }; + } + /** Release every remaining installation owned by one disposed child scope. */ + releaseChild(childCtx) { + const indexed = this.byChild.get(childCtx) ?? []; + this.releaseAll([...indexed], 'child scope disposal'); + } + /** + * Release a batch completely before reporting disposer failures. + * @param installations - records to release. + * @param during - operation name for diagnostics. + */ + releaseAll(installations, during) { + const failures = []; + for (const installation of installations) { + try { + this.release(installation); + } + catch (error) { + failures.push(error); + } + } + if (failures.length === 0) + return; + throw new SubagentError(`continuable-subagent setup ${during} failed to release ${failures.length} installation(s): ` + + failures.map(failure => errorChain(failure)).join('; '), 'ACTIVATION_SETUP_RELEASE_FAILED'); + } + /** Drop one installation from both indices and dispose it exactly once. */ + release(installation) { + if (installation.released) + return; + installation.released = true; + installation.registration.installations.delete(installation); + const indexed = this.byChild.get(installation.childCtx); + /* v8 ignore next 4 -- every live installation is indexed until this method removes it. */ + if (indexed !== undefined) { + indexed.delete(installation); + if (indexed.size === 0) + this.byChild.delete(installation.childCtx); + } + if (installation.transaction !== undefined) + installation.transaction.invalidated = true; + installation.dispose(); + } +} +export default SubagentActivationSetupRegistry; +//# sourceMappingURL=activation-setup-registry.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.d.ts new file mode 100644 index 0000000..125a833 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.d.ts @@ -0,0 +1,48 @@ +/** + * Canonical selection of a child's final assistant output. Backend run results + * and `subagent/end.lastAssistantMessage` apply the same rule: select the last + * non-empty assistant message. An empty-content message records usage only + * when the loop appends it after a max-tokens step with no executable blocks, + * so it does not replace earlier output. If no non-empty message exists, + * select the accumulated assistant text. Selection is independent of the + * run's stop reason. + * + * @module @deepseek-ai/dsh-subagent/assistant-output + */ +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +/** + * Incremental fold of the selection rule, for backends that observe a child's + * output as it streams: session-event backends {@link push} each event, and + * transports without session events (ACP content chunks) {@link pushText} raw + * text into the same streamed fallback. + */ +export declare class AssistantOutputFold { + private message; + private partial; + /** + * Fold one session event: a non-empty assistant message becomes the + * candidate final answer, and a `text-delta` chunk extends the streamed + * fallback; every other event contributes nothing. + * @param event - the next observed session event. + */ + push(event: SessionEvent): void; + /** + * Extend the streamed fallback with text observed outside session events. + * @param text - the next streamed text piece (an empty piece is a no-op). + */ + pushText(text: string): void; + /** + * Select the final output folded so far. + * @returns the last non-empty assistant message, else the accumulated + * streamed text, or `undefined` when the child produced neither. + */ + collect(): ContentBlock[] | undefined; +} +/** + * Apply the selection rule to one complete child-owned event suffix. + * @param events - the child-owned events (after any seed or epoch boundary). + * @returns the selected output, or `undefined` when the child produced none. + */ +export declare function finalAssistantOutput(events: readonly SessionEvent[]): ContentBlock[] | undefined; +//# sourceMappingURL=assistant-output.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.js new file mode 100644 index 0000000..68f7a1d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/assistant-output.js @@ -0,0 +1,72 @@ +/** + * Canonical selection of a child's final assistant output. Backend run results + * and `subagent/end.lastAssistantMessage` apply the same rule: select the last + * non-empty assistant message. An empty-content message records usage only + * when the loop appends it after a max-tokens step with no executable blocks, + * so it does not replace earlier output. If no non-empty message exists, + * select the accumulated assistant text. Selection is independent of the + * run's stop reason. + * + * @module @deepseek-ai/dsh-subagent/assistant-output + */ +/** + * Incremental fold of the selection rule, for backends that observe a child's + * output as it streams: session-event backends {@link push} each event, and + * transports without session events (ACP content chunks) {@link pushText} raw + * text into the same streamed fallback. + */ +export class AssistantOutputFold { + message; + partial = []; + /** + * Fold one session event: a non-empty assistant message becomes the + * candidate final answer, and a `text-delta` chunk extends the streamed + * fallback; every other event contributes nothing. + * @param event - the next observed session event. + */ + push(event) { + if (event.type === 'assistant/message') { + const content = event.data.message.content; + if (content.length > 0) + this.message = content; + } + else if (event.type === 'assistant/chunk' && event.data.chunk.type === 'text-delta') { + this.pushText(event.data.chunk.text); + } + } + /** + * Extend the streamed fallback with text observed outside session events. + * @param text - the next streamed text piece (an empty piece is a no-op). + */ + pushText(text) { + if (text.length > 0) + this.partial.push(text); + } + /** + * Select the final output folded so far. + * @returns the last non-empty assistant message, else the accumulated + * streamed text, or `undefined` when the child produced neither. + */ + collect() { + if (this.message !== undefined) + return this.message; + const text = this.partial.join(''); + return text.length > 0 ? [{ type: 'text', text }] : undefined; + } +} +/** + * Apply the selection rule to one complete child-owned event suffix. + * @param events - the child-owned events (after any seed or epoch boundary). + * @returns the selected output, or `undefined` when the child produced none. + */ +export function finalAssistantOutput(events) { + // TODO: this folds the complete suffix once per run/epoch settlement. If a + // long continuable epoch ever profiles hot here, scan backward with early + // exit for the last non-empty message and fold text deltas only on the + // no-message fallback. + const fold = new AssistantOutputFold(); + for (const event of events) + fold.push(event); + return fold.collect(); +} +//# sourceMappingURL=assistant-output.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.d.ts new file mode 100644 index 0000000..a95ba0f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.d.ts @@ -0,0 +1,139 @@ +/** + * Shared in-process child composition: the delegation-depth budget, the + * durable session metadata, the resolved child `AgentOptions`, the delegated + * policy seed, and the scoped setup a child agent needs. Both the one-shot + * provider driver and the continuation manager compose children this way, so + * depth accounting, lineage stamping, and delegation policy have one home. + * + * @module @deepseek-ai/dsh-subagent/child-agent + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { Agent, AgentOptions, CreateAgentOptions } from '@deepseek-ai/dsh-agent'; +import type { SandboxMode } from '@deepseek-ai/dsh-sandbox'; +import type { Session, SessionId } from '@deepseek-ai/dsh-session'; +import type { ToolRestriction } from '@deepseek-ai/dsh-tools'; +/** Thrown when starting a child would exceed the requested depth cap. */ +export declare class SubagentDepthError extends Error { + readonly attemptedDepth: number; + readonly maxDepth: number; + constructor(attemptedDepth: number, maxDepth: number); +} +/** + * Resolve the child's delegation depth from its parent and enforce an optional + * cap. The persisted parent header is the monotone floor, so a resumed parent + * cannot delegate as if it were top-level. + * @param parent - the delegating parent agent. + * @param maxDepth - optional absolute cap the resolved depth must not exceed. + * @returns the child's non-negative safe-integer depth. + * @throws {SubagentDepthError} when the resolved depth exceeds `maxDepth`. + * @throws {RangeError} when the resolved depth leaves the safe-integer range. + */ +export declare function resolveChildDepth(parent: Agent, maxDepth: number | undefined): number; +/** + * Resolve the child's `AgentOptions`: the parent's provider/model/maxTokens + * route unless the request overrides it, stamped with the child's own + * delegation depth. + * @param parent - the delegating parent whose route the child inherits. + * @param requested - per-child overrides, if any. + * @param childDepth - the resolved delegation depth to stamp. + * @returns the resolved options for `ctx.agents.create()`. + */ +export declare function resolveChildAgentOptions(parent: Agent, requested: AgentOptions | undefined, childDepth: number): AgentOptions; +/** + * Build the child session's durable creation metadata: the parent's workspace, + * its direct lineage, coarse product origin, the recursion budget that must + * survive persistence, the seed boundary that separates inherited parent + * history from child work, and the composition the child runs under. + * + * The preset is read from the parent's LIVE scope chain rather than from its + * header, because a parent that switched preset while blank runs on the newer + * composition and its header still names the older one. Recording it is what + * makes a child's history reconstructable: without it a cold read of the child + * resolves the deployment default and rebuilds turns under a tool set the + * child never had. + * @param parent - the delegating parent agent. + * @param childDepth - the resolved delegation depth to persist. + * @param lineageSeedLength - how many leading events came from the parent's log. + * @returns the `meta` for `ctx.agents.create()`. + */ +export declare function childSessionMeta(parent: Agent, childDepth: number, lineageSeedLength: number): NonNullable; +/** The scoped composition a child agent's creation window applies. */ +export interface ChildComposition { + /** Per-child persona shadowing the deployment persona. */ + readonly persona?: string | undefined; + /** Per-child tool scoping. */ + readonly toolFilter?: ToolRestriction | undefined; +} +/** + * Model-facing delegation-scope statement for every in-process child. A + * runtime-context contribution rather than a system-prompt section, so the + * deployment's system prompt stays uniform across parents and children. + */ +export declare const SUBAGENT_DELEGATION_CONTEXT: string; +/** + * Compose one child inside its creation window: join its parent's preset, + * register the fixed delegation-scope statement, then apply the child's own + * shadowing persona section and tool restriction, all owned by the child's + * scope and therefore invisible to its parent and siblings. Creation and cold + * resume both pass through here. + * + * The join comes first and the child's own registrations second, which is the + * order the layering already implies — the nearest scope wins a name, and a + * per-child restriction intersects with everything its chain admits — but + * stating it here keeps the two steps from being read as independent. + * + * The join and the per-child registrations live in ONE call because a child + * composed without the join is exactly the defect this function exists to + * prevent: with every model-facing row on the agent plane, a child that joins + * no preset sees an empty tool registry and none of its parent's prompt + * sections. Taking the parent as a parameter is what makes that omission + * unrepresentable at the call sites. + * @param childCtx - the child agent's scoped creation context. + * @param parent - the delegating parent whose composition the child joins. + * @param composition - the per-child persona and tool filter to install. + */ +export declare function applyChildComposition(childCtx: Context, parent: Agent, composition: ChildComposition): void; +/** Policy seeded onto a child session's log at the delegation boundary. */ +export interface DelegatedPolicyOverrides { + /** The parent session's explicit sandbox-mode override, or `undefined` without one. */ + readonly sandboxMode: SandboxMode | undefined; + /** + * `'never'` whenever the approval capability is composed, `undefined` + * otherwise: a delegated child acts only within the sandbox scope fixed at + * delegation, so its asks are rejected deterministically. + */ + readonly approvalPolicy: 'never' | undefined; +} +/** + * Capture the policy to seed into one delegation. Call synchronously before + * the child start's first await: a later parent switch belongs to the + * parent's future, not to this child. Only the parent session's explicit + * sandbox override is captured — never deployment defaults or one-shot + * grants — and the approval policy is pinned to `'never'` regardless of the + * parent's own policy. + * @param parent - the delegating parent agent. + * @returns the sandbox override (or `undefined` without one) and the approval pin. + */ +export declare function captureDelegatedPolicyOverrides(parent: Agent): DelegatedPolicyOverrides; +/** + * Append the captured delegation policy onto the child's own log as + * `source: 'delegation'` events inside the unpublished creation window, so the + * child's effective policy is reconstructable from its log alone. Appends land + * after any fork seed, so fresh policy wins stale seed state; later child + * switches still win over these events. + * @param childSession - the unpublished child's session. + * @param overrides - the policy captured at delegation. + */ +export declare function appendDelegatedPolicyOverrides(childSession: Session, overrides: DelegatedPolicyOverrides): void; +/** Identity and lineage inputs shared by every in-process child creation. */ +export interface ChildCreateInputs { + /** The child's reserved session id. */ + readonly sessionId: SessionId; + /** The delegating parent agent. */ + readonly parent: Agent; + /** The resolved delegation depth. */ + readonly childDepth: number; + /** How many leading seed events came from the parent's log. */ + readonly lineageSeedLength: number; +} +//# sourceMappingURL=child-agent.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.js new file mode 100644 index 0000000..8e7a9e3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/child-agent.js @@ -0,0 +1,169 @@ +/** + * Shared in-process child composition: the delegation-depth budget, the + * durable session metadata, the resolved child `AgentOptions`, the delegated + * policy seed, and the scoped setup a child agent needs. Both the one-shot + * provider driver and the continuation manager compose children this way, so + * depth accounting, lineage stamping, and delegation policy have one home. + * + * @module @deepseek-ai/dsh-subagent/child-agent + */ +import { delegationDepthOf } from "./depth.js"; +/** Thrown when starting a child would exceed the requested depth cap. */ +export class SubagentDepthError extends Error { + attemptedDepth; + maxDepth; + constructor(attemptedDepth, maxDepth) { + super(`subagent depth ${attemptedDepth} exceeds maxDepth ${maxDepth}`); + this.attemptedDepth = attemptedDepth; + this.maxDepth = maxDepth; + this.name = 'SubagentDepthError'; + } +} +/** + * Resolve the child's delegation depth from its parent and enforce an optional + * cap. The persisted parent header is the monotone floor, so a resumed parent + * cannot delegate as if it were top-level. + * @param parent - the delegating parent agent. + * @param maxDepth - optional absolute cap the resolved depth must not exceed. + * @returns the child's non-negative safe-integer depth. + * @throws {SubagentDepthError} when the resolved depth exceeds `maxDepth`. + * @throws {RangeError} when the resolved depth leaves the safe-integer range. + */ +export function resolveChildDepth(parent, maxDepth) { + const childDepth = delegationDepthOf(parent) + 1; + if (!Number.isSafeInteger(childDepth)) { + throw new RangeError('subagent child depth exceeds the safe-integer range'); + } + if (maxDepth !== undefined && childDepth > maxDepth) { + throw new SubagentDepthError(childDepth, maxDepth); + } + return childDepth; +} +/** + * Resolve the child's `AgentOptions`: the parent's provider/model/maxTokens + * route unless the request overrides it, stamped with the child's own + * delegation depth. + * @param parent - the delegating parent whose route the child inherits. + * @param requested - per-child overrides, if any. + * @param childDepth - the resolved delegation depth to stamp. + * @returns the resolved options for `ctx.agents.create()`. + */ +export function resolveChildAgentOptions(parent, requested, childDepth) { + const parentProvider = parent.options.provider; + const parentModel = parent.options.model; + const parentMaxTokens = parent.options.maxTokens; + return { + ...parentProvider !== undefined ? { provider: parentProvider } : {}, + ...parentModel !== undefined ? { model: parentModel } : {}, + ...parentMaxTokens !== undefined ? { maxTokens: parentMaxTokens } : {}, + ...requested, + subagentDepth: childDepth, + }; +} +/** + * Build the child session's durable creation metadata: the parent's workspace, + * its direct lineage, coarse product origin, the recursion budget that must + * survive persistence, the seed boundary that separates inherited parent + * history from child work, and the composition the child runs under. + * + * The preset is read from the parent's LIVE scope chain rather than from its + * header, because a parent that switched preset while blank runs on the newer + * composition and its header still names the older one. Recording it is what + * makes a child's history reconstructable: without it a cold read of the child + * resolves the deployment default and rebuilds turns under a tool set the + * child never had. + * @param parent - the delegating parent agent. + * @param childDepth - the resolved delegation depth to persist. + * @param lineageSeedLength - how many leading events came from the parent's log. + * @returns the `meta` for `ctx.agents.create()`. + */ +export function childSessionMeta(parent, childDepth, lineageSeedLength) { + const parentHeader = parent.session.header; + const agentPreset = parent.ctx.get('agentPresets')?.composedPreset(parent.ctx); + return { + ...parentHeader.cwd !== undefined ? { cwd: parentHeader.cwd } : {}, + ...agentPreset === undefined ? {} : { agentPreset }, + parentSession: parentHeader.id, + // Navigation classification only; the descriptor remains the authority + // for mode and continuation capability. + origin: 'subagent', + // Durable: the recursion budget must survive persistence and resume. + delegationDepth: childDepth, + ...lineageSeedLength > 0 ? { seedLength: lineageSeedLength } : {}, + }; +} +/** + * Model-facing delegation-scope statement for every in-process child. A + * runtime-context contribution rather than a system-prompt section, so the + * deployment's system prompt stays uniform across parents and children. + */ +export const SUBAGENT_DELEGATION_CONTEXT = 'You are a delegated subagent: your permission scope was fixed when you were started and cannot be ' + + 'widened from inside this session — operations that require approval are rejected automatically. ' + + 'When the task needs access beyond that scope, do not retry the denied operation; state the ' + + 'limitation in your reply so the delegating agent can handle it.'; +/** + * Compose one child inside its creation window: join its parent's preset, + * register the fixed delegation-scope statement, then apply the child's own + * shadowing persona section and tool restriction, all owned by the child's + * scope and therefore invisible to its parent and siblings. Creation and cold + * resume both pass through here. + * + * The join comes first and the child's own registrations second, which is the + * order the layering already implies — the nearest scope wins a name, and a + * per-child restriction intersects with everything its chain admits — but + * stating it here keeps the two steps from being read as independent. + * + * The join and the per-child registrations live in ONE call because a child + * composed without the join is exactly the defect this function exists to + * prevent: with every model-facing row on the agent plane, a child that joins + * no preset sees an empty tool registry and none of its parent's prompt + * sections. Taking the parent as a parameter is what makes that omission + * unrepresentable at the call sites. + * @param childCtx - the child agent's scoped creation context. + * @param parent - the delegating parent whose composition the child joins. + * @param composition - the per-child persona and tool filter to install. + */ +export function applyChildComposition(childCtx, parent, composition) { + childCtx.get('agentPresets')?.composeFrom(childCtx, parent.ctx); + // Order 120: after the sandbox:policy (110) and approval:policy (115) sentences. + childCtx.systemPrompt.context({ name: 'subagent:delegation', order: 120, text: SUBAGENT_DELEGATION_CONTEXT }); + if (composition.persona !== undefined) { + childCtx.systemPrompt.section({ name: 'deployment:persona', order: 0, text: composition.persona }); + } + if (composition.toolFilter !== undefined) + childCtx.tools.restrict(composition.toolFilter); +} +/** + * Capture the policy to seed into one delegation. Call synchronously before + * the child start's first await: a later parent switch belongs to the + * parent's future, not to this child. Only the parent session's explicit + * sandbox override is captured — never deployment defaults or one-shot + * grants — and the approval policy is pinned to `'never'` regardless of the + * parent's own policy. + * @param parent - the delegating parent agent. + * @returns the sandbox override (or `undefined` without one) and the approval pin. + */ +export function captureDelegatedPolicyOverrides(parent) { + return { + sandboxMode: parent.ctx.get('sandboxPolicy')?.overrideOf(parent.session), + approvalPolicy: parent.ctx.get('approval') === undefined ? undefined : 'never', + }; +} +/** + * Append the captured delegation policy onto the child's own log as + * `source: 'delegation'` events inside the unpublished creation window, so the + * child's effective policy is reconstructable from its log alone. Appends land + * after any fork seed, so fresh policy wins stale seed state; later child + * switches still win over these events. + * @param childSession - the unpublished child's session. + * @param overrides - the policy captured at delegation. + */ +export function appendDelegatedPolicyOverrides(childSession, overrides) { + if (overrides.sandboxMode !== undefined) { + childSession.append('sandbox/mode', { mode: overrides.sandboxMode, source: 'delegation' }); + } + if (overrides.approvalPolicy !== undefined) { + childSession.append('approval/policy', { policy: overrides.approvalPolicy, source: 'delegation' }); + } +} +//# sourceMappingURL=child-agent.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.d.ts new file mode 100644 index 0000000..7153d11 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.d.ts @@ -0,0 +1,7 @@ +/** + * Browser-safe subagent projection vocabulary. + * + * @module @deepseek-ai/dsh-subagent/client + */ +export type { SubagentIdentityProjection, SubagentTimingProjection } from './projection-types.ts'; +//# sourceMappingURL=client.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.js new file mode 100644 index 0000000..776ccb4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/client.js @@ -0,0 +1,7 @@ +/** + * Browser-safe subagent projection vocabulary. + * + * @module @deepseek-ai/dsh-subagent/client + */ +export {}; +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.d.ts new file mode 100644 index 0000000..8706df5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.d.ts @@ -0,0 +1,436 @@ +/** + * Internal continuable-subagent manager: stable child ids, descriptor + * persistence, activation admission, the live ownership graph, cold resume, + * child-first disposal, and settlement delivery to the parent, behind + * `ctx.subagents`. + * + * A continuable child has one durable Session and at most one process-local + * {@link Activation} — one residency epoch for a reconstructed child Agent. An + * Activation is not a request, result, cancellation, or Task boundary: it may + * execute many FIFO turns and stays resident while descendants it created are + * still running. The Agent inbox is the only turn queue, so this manager owns + * residency while the Agent loop owns all turn ordering and execution. No + * continuable path creates a Task or an intermediate result-bearing wrapper. + * + * Because residency is this manager's alone to end, telling the parent that a + * child settled is its job too. An external `subagent/end` listener cannot do + * it correctly: that payload names no parent, the child handle is already + * disposed by then, and the release that wakes the parent's own settlement + * watcher has already run. See {@link SubagentContinuationManager.notifySettlement}. + * + * @module @deepseek-ai/dsh-subagent + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { ContentBlock, MessageId, MessageSource } from '@deepseek-ai/dsh-llm'; +import { SessionId } from '@deepseek-ai/dsh-session'; +import type { SubagentDescriptorData } from './descriptor.ts'; +import type { ContinuableCreateRequest, ContinuableCreateSpec, SubagentStartRequest } from './types.ts'; +import type { ActivationObserver } from './lifecycle.ts'; +import type SubagentActivationSetupRegistry from './activation-setup-registry.ts'; +/** Attribution for a model coordinator's follow-up to one of its children. */ +export interface CoordinatorMessageSource { + readonly kind: 'coordinator'; + /** A message another agent addressed to this one (`relay` context form). */ + readonly form: 'relay'; + /** Session id of the agent whose tool call produced the follow-up. */ + readonly senderSessionId: SessionId; +} +/** Durable attribution for a continuable child's explicit parent report. */ +export interface SubagentReportMessageSource { + readonly kind: 'subagent-report'; + /** A message another agent addressed to this one (`relay` context form). */ + readonly form: 'relay'; + /** Session id of the reporting child. */ + readonly senderSessionId: SessionId; +} +/** + * Durable attribution for the runtime's own account of a continuable child + * settling. Deliberately a different kind from + * {@link SubagentReportMessageSource}: a report is content the child chose, + * while this message is the manager stating what became of the child, and a + * transcript that merged them would credit the child with words it never wrote. + */ +export interface SubagentSettledMessageSource { + readonly kind: 'subagent-settled'; + /** A runtime account shown without expanding the row (`notice` context form). */ + readonly form: 'notice'; + /** One-line account of how the child ended. */ + readonly summary: string; + /** Session id of the child that settled. */ + readonly senderSessionId: SessionId; +} +declare module '@deepseek-ai/dsh-llm' { + interface MessageSourceMap { + coordinator: CoordinatorMessageSource; + 'subagent-report': SubagentReportMessageSource; + 'subagent-settled': SubagentSettledMessageSource; + } +} +/** Deployment scheduling policy for accepted child reports. */ +export type SubagentReportDelivery = 'quiet' | 'wakeup'; +/** Options for one continuable child's report to its direct parent. */ +export interface SubagentReportOptions { + /** Already-resolved parent scheduling policy. */ + readonly delivery: SubagentReportDelivery; + /** Caller cancellation, owning authorization and admission until acceptance. */ + readonly signal: AbortSignal; +} +/** What a caller asks for when starting a continuable background child. */ +export interface ContinuableStartSpec { + /** The `ctx.subagents` provider whose continuable-creation capability establishes the child. */ + readonly provider: string; + /** The initial delegation's short `description`, persisted as the child's creation label. */ + readonly label: string; + /** + * The delegation request. The manager reserves the stable child id, resolves + * the durable descriptor, and composes the child itself. + */ + readonly request: Omit; + /** Caller cancellation, owning the operation only until inbox acceptance. */ + readonly signal: AbortSignal; +} +/** Identities returned once a continuable child accepted its initial prompt. */ +export interface ContinuableStart { + /** The durable child session id, stable across activations. */ + readonly childId: SessionId; + /** The accepted initial prompt's inbox message id. */ + readonly messageId: MessageId; +} +/** + * Authority under which one interrupt request is admitted. `user` carries the + * durable direct-parent address a human client presented; `ancestor` carries + * the exact live Agent object whose recorded lineage must contain the caller. + */ +export type SubagentInterruptAuthority = { + readonly kind: 'user'; + readonly parentSessionId: SessionId; +} | { + readonly kind: 'ancestor'; + readonly agent: Agent; +}; +/** Options for following up with one continuable child. */ +export interface SubagentFollowupOptions { + /** Durable attribution retained on the delivered message; it grants no authority. */ + readonly source: MessageSource; + /** Caller cancellation, owning the operation only until inbox acceptance. */ + readonly signal: AbortSignal; +} +/** + * Hooks the manager needs from the owning service. Declared here, by the + * dependent, so the manager states exactly what it requires instead of + * depending back on the whole {@link SubagentRuntime}. Package-private: no + * consumer outside this package supplies a host. + */ +interface ContinuationHost { + /** + * Resolve one provider's continuable-creation contribution, or reject when + * the provider is unknown or lacks the capability. + * @param name - the configured provider name. + * @param request - the reserved identity, delegating parent, and cancellation. + * @returns the provider's detached creation spec. + */ + prepareContinuable(name: string, request: ContinuableCreateRequest): Promise; + /** + * Build the lifecycle observer for one Activation's residency epoch. + * @param provider - the provider name recorded in the durable descriptor. + * @param childId - the durable child session id. + * @param parent - the exact live direct parent for scoped dispatch. + * @returns the observer whose edges this epoch publishes. + */ + observeActivation(provider: string, childId: SessionId, parent: Agent): ActivationObserver; +} +/** + * The continuable-subagent orchestration service behind `ctx.subagents`. Tool + * schema and host adapters are consumers of this one contract; foreground + * one-shot delegation keeps calling `ctx.subagents.start()` and never enters + * this lifecycle. + */ +export declare class SubagentContinuationManager { + private readonly ctx; + private readonly host; + private readonly setupRegistry; + /** Child session id → its live Activation. Process-local, never durable. */ + private activations; + /** Materializations admitted before drain, tracked through publication or rollback. */ + private readonly materializations; + private readonly locks; + /** Structural Cordis owner of every Activation handle. */ + private readonly ownerCtx; + /** + * Exact roots whose host teardown has begun, with the live lineage members + * observed under each root. Entries remain until that exact root leaves the + * Agent registry, closing admission throughout its host's teardown without + * poisoning a later same-id replacement. + */ + private readonly closingScopes; + private draining; + constructor(ctx: Context, host: ContinuationHost, setupRegistry: SubagentActivationSetupRegistry); + /** + * Start one continuable background child: reserve its durable identity, + * resolve the provider's detached creation spec, create the child Agent + * through the private activation-owner scope, establish any continuable-parent + * ownership, and submit the initial prompt. Resolves when inbox acceptance + * yields the message id — without waiting for the turn to start or for the + * message to reach the Session log. + * + * Every failure before that acceptance rejects without either id, disposing + * any created handle and rolling back the Activation and parent ownership. + * The caller signal owns lookup, materialization, and admission only until + * acceptance; afterwards the manager owns the Activation independently. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted initial prompt's message id. + */ + startContinuable(spec: ContinuableStartSpec): Promise; + /** + * Deliver one later message to a known continuable child as its next FIFO + * turn. Routing depends only on Activation residency: a `running` Activation + * enqueues, a `waiting` one wakes the same Agent, and an absent one + * cold-resumes a new Activation from the persisted Session. The Agent inbox + * is the only queue, so every accepted message has one observable order. + * + * The caller signal owns lookup, materialization, and admission only until + * inbox acceptance; afterwards the accepted turn cannot be cancelled through + * this service. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - the durable child session id. + * @param content - the user-role content to deliver. + * @param options - the message source fields and caller cancellation. + * @returns the accepted message's inbox id. + * @throws when parent authority, availability, or admission rejects the delivery. + */ + followup(parent: Agent, childId: SessionId, content: ContentBlock[], options: SubagentFollowupOptions): Promise; + /** + * Interrupt one live continuable child's current turn. Admission is + * synchronous and the effect is asynchronous: this authorizes the caller, + * requests `Agent.cancel(cause, { keepInbox: true })` on the target, and + * returns without waiting for the target to observe the signal or reach + * quiescence. The Activation, its handle, accepted unclaimed inbox work, and + * already-published descendants are untouched; work already claimed into the + * interrupted turn is not requeued. Once the interrupted driver is idle, a + * waking send resumes the parked queue. + * + * An absent target is an accepted no-op, which uniformly covers natural + * completion races, repeated requests, one-shot ids, and unknown ids without + * consulting the durable catalog. A target whose disposal transaction is + * already open is likewise an accepted no-op after authorization. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the presented authority does + * not own the live target: a stale or self-targeting ancestor caller, a + * parent address that is not the live target's durable direct parent, or + * an ancestor outside the target's recorded live lineage. + */ + interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void; + /** + * Deliver explicitly selected content from one resident continuable child to + * its durable direct parent. Sender authorization, parent resolution, and + * send acceptance share one no-await span. Reporting neither concludes the + * child's turn nor changes its Activation lifetime. + * @param child - exact live reporting child; this is the authority credential. + * @param content - selected model-facing content. + * @param options - scheduling policy and pre-acceptance cancellation. + * @returns the stable identity of the message accepted by the parent. + * @throws {SubagentError} when the sender is unauthorized, the parent is not + * live, or continuation admission is closing. + */ + reportFrom(child: Agent, content: ContentBlock[], options: SubagentReportOptions): Promise; + /** Authorize only the exact Agent of one resident Activation. */ + private authorizeReporter; + /** Resolve the reporting child's live direct parent from durable lineage. */ + private resolveReportParent; + /** Deliver one framed report through the selected parent scheduling preset. */ + private deliverReport; + /** + * Perform one waking send to a parent, accounted against that parent's own + * Activation when it has one. Registering the id before the send is what + * keeps a continuation-managed parent from being judged quiescent in the + * window between `followup()` and the microtask that admits it. + * @param parent - the exact live parent receiving the waking message. + * @param message - the message whose id is accounted. + * @param send - the synchronous waking send to perform. + */ + private sendWaking; + /** Send one report while translating only the parent's own rejection. */ + private sendReport; + /** + * Close admission, await every already-admitted materialization through + * publication or rollback, then dispose the stable live Activation forest + * child-first. Sibling branches drain independently: one failure is recorded + * but never prevents the remaining handles from being attempted, and the + * aggregate rejects only after every branch settles. + * @returns once materialization is quiescent and every live Activation released its handle. + * @throws an aggregate error when any branch failed to release. + */ + drain(): Promise; + /** + * Stop only the continuable descendants of exact live host-owned parents. + * Admission stays closed for those parent trees until each exact parent + * leaves the Agent registry; unrelated trees and manager-wide admission stay + * live. + * @param parents - exact live roots whose continuable descendants must stop. + * @returns once every retained descendant Activation released its handle. + * @throws an aggregate error after all scoped branches settle when any failed. + */ + drainDescendants(parents: readonly Agent[]): Promise; + /** Dispose independent roots and report every branch failure after all settle. */ + private disposeRoots; + /** Return the retained member set for one exact scoped-teardown root. */ + private closingMembers; + /** + * Return the exact currently resolvable ancestry from `agent` upward. The + * first element is always the supplied identity, even when it is already + * stale; each ancestor after it must be the registry's current exact entry. + */ + private liveLineage; + /** + * The teardown that closed continuable admission for this agent's lineage. + * `'manager'` is the whole manager draining; an Agent is the exact scoped root + * whose forest is closing. + * @param agent - the agent whose lineage is tested. + * @returns the closing teardown, or `undefined` while admission is open. + */ + private closingTeardownFor; + /** Reject new admission once the manager or this exact parent tree began draining. */ + private assertAdmitting; + /** + * Derive residency from Agent quiescence and the owned-child set. `running` + * covers an active admission, an open turn, or accepted waking inbox work. + * + * `Agent.status` alone is insufficient: it stays `idle` between an accepted + * waking send and the microtask that admits it, so a synchronous inbox + * observer would see `settled` while a turn is already queued. `accepted` + * holds the ids this manager admitted but has not yet seen drained. + */ + private stateOf; + /** + * Cold-resume a persisted child: inspect and authorize its Session, fold the + * generic descriptor, create the Activation through `ctx.agents.resume()`, + * and submit the waiting turn. This never dispatches through a subagent + * provider — the persisted Session already holds the initial prefix and the + * descriptor is the whole reconstruction input. + */ + private coldResume; + /** + * Submit to a freshly materialized Activation or roll it back completely. + * @param activation - the just-published Activation to admit or release. + * @param content - the initial or resumed message content. + * @param source - durable fields naming who supplied the accepted message. + * @param parent - the live direct parent authorizing admission. + * @param signal - caller cancellation owning admission until acceptance. + * @returns the accepted inbox message id. + */ + private submitMaterialized; + /** + * Create or resume the child Agent through the private activation-owner + * scope, install the handle in a fresh Activation, and register ownership on + * a continuation-managed parent. Rejection leaves no Activation, no handle, + * and no ownership membership. + */ + private materialize; + /** + * Perform one tracked materialization. The caller keeps the drain barrier + * registered until this either returns a resident Activation or finishes + * rollback. + */ + private materializeTracked; + /** + * Release an Activation whose start edge was not published. The memoized + * transaction remains in the live map until handle disposal settles, so a + * concurrent drain or delivery observes the same closing boundary. + */ + private rollbackUnpublished; + /** + * Register the child in a continuation-managed parent's owned set before the + * child can run, so that parent cannot settle while the child is live. A + * top-level or other non-continuation Agent has no Activation and stays + * outside the waiting graph. + */ + private acquireOwnership; + /** Remove one child from its live owner's set and let that owner re-check settlement. */ + private releaseOwnership; + /** Let a settlement watcher re-observe quiescence after ownership or inbox changes. */ + private wake; + /** + * Submit one message as the child's next FIFO turn and return its accepted + * inbox id. Acceptance is the operation's success boundary; the manager owns + * the Activation independently afterwards. + */ + private submit; + /** + * Account one waking send across a resident Activation's settlement window. + * @param activation - Activation receiving waking inbox work. + * @param messageId - stable identity of the message about to be sent. + * @param send - synchronous send that publishes one enqueue occurrence. + * @returns the accepted message id. + */ + private admitWaking; + /** + * Cross the final admission cutoff and submit without yielding. Signal abort, + * manager drain, or Activation disposal that wins before this synchronous + * span rejects without inbox acceptance. + */ + private submitAdmitted; + /** + * Authorize one operation against the durable direct-parent lineage. Other + * agents, ancestors, teams, workflows, and hosts remain rejected until an + * explicit authority protocol has a production consumer. + */ + private authorizeLineage; + /** + * Follow one Activation to settlement: wait for Agent quiescence, then for + * every owned child to complete disposal, and dispose the handle once both + * hold. A `next-turn` delivered while `waiting` wakes the same Agent and + * returns it to `running`, so this re-observes rather than settling early. + */ + private watchSettlement; + /** + * Stop one Activation immediately, then release it child-first. The memoized + * transaction is installed before cancellation or recursive callbacks, so + * admission and reentrant teardown converge on the same owner. + * + * The final session flush is best effort and never prevents handle disposal + * or ownership release, because retaining a child would permanently pin its + * ancestors in `waiting`. + * @param activation - the residency epoch to stop and release. + * @returns the one disposal transaction owned by this Activation. + */ + private dispose; + /** + * Propagate stop synchronously, then finish the child-first release. + * @param activation - the Activation whose disposal transaction is installed. + * @returns once the handle and ownership edge are released. + */ + private finishDisposal; + /** + * Tell the durable direct parent that this child produced everything it is + * going to. Unconditional for every child the caller received an id for: it + * does not consider whether the child reported, because the cases that most + * need it — a token ceiling, a model failure, cancellation, teardown — are + * exactly the ones where the child never got to choose. A materialization + * rolled back before its first acceptance stays silent, since the caller was + * told that child was not established. A parent that is no longer live is not + * an error; the child's own Session remains the durable record either way. + * A parent whose own lineage is already closing receives the notice without a + * wake, because teardown is not a reason to start a turn. + * + * Never blocks disposal. A delivery failure is logged and dropped, because + * retaining a child to retry a notice would pin its whole ancestry in + * `waiting` forever. + * @param activation - the settling Activation, still owned by its parent. + * @param terminal - how this epoch ended, as the terminal edge will report it. + */ + private notifySettlement; + /** + * Request a best-effort final session flush after the child is quiescent. + * Listener failure is logged because flush participation cannot identify a + * particular persistence backend, and teardown must still release ownership. + * @param activation - the Activation whose final events should be flushed. + */ + private flushFinalState; + /** Resolve the persistence service continuable children require, or fail loud. */ + private requirePersistence; +} +export type { SubagentDescriptorData }; +export default SubagentContinuationManager; +//# sourceMappingURL=continuation.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.js new file mode 100644 index 0000000..7fb519d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/continuation.js @@ -0,0 +1,1100 @@ +/** + * Internal continuable-subagent manager: stable child ids, descriptor + * persistence, activation admission, the live ownership graph, cold resume, + * child-first disposal, and settlement delivery to the parent, behind + * `ctx.subagents`. + * + * A continuable child has one durable Session and at most one process-local + * {@link Activation} — one residency epoch for a reconstructed child Agent. An + * Activation is not a request, result, cancellation, or Task boundary: it may + * execute many FIFO turns and stays resident while descendants it created are + * still running. The Agent inbox is the only turn queue, so this manager owns + * residency while the Agent loop owns all turn ordering and execution. No + * continuable path creates a Task or an intermediate result-bearing wrapper. + * + * Because residency is this manager's alone to end, telling the parent that a + * child settled is its job too. An external `subagent/end` listener cannot do + * it correctly: that payload names no parent, the child handle is already + * disposed by then, and the release that wakes the parent's own settlement + * watcher has already run. See {@link SubagentContinuationManager.notifySettlement}. + * + * @module @deepseek-ai/dsh-subagent + */ +import { randomUUID } from 'node:crypto'; +import { boundContextSummary, createUserMessage, errorChain } from '@deepseek-ai/dsh-llm'; +import { SessionId } from '@deepseek-ai/dsh-session'; +import { foldSubagentDescriptor, snapshotSubagentDescriptor } from "./descriptor.js"; +import { appendDelegatedPolicyOverrides, applyChildComposition, captureDelegatedPolicyOverrides, childSessionMeta, resolveChildAgentOptions, resolveChildDepth, } from "./child-agent.js"; +import { assertSubagentMaxDepth } from "./depth.js"; +import { seedDescriptorTurn } from "./descriptor-seed.js"; +import { SubagentError } from "./error.js"; +/** + * Read one Activation's current disposal transaction. This indirection exists + * because TypeScript would otherwise narrow repeated reads of the mutable field + * inside a long-lived closure to constants instead of re-reading runtime state. + * @param activation - the Activation to inspect. + * @returns the in-flight or settled disposal, or `undefined` while resident. + */ +function disposalOf(activation) { + return activation.disposal; +} +/** + * One line telling a parent that a background child is finished and why, in + * the parent's own task vocabulary. + * @param childId - the durable child the parent knows by id. + * @param stopReason - how the child's last ordinary turn ended. + * @returns the model-facing opening line of the settlement notice. + */ +function settlementSummary(childId, stopReason) { + const subject = `Background subagent ${childId}`; + switch (stopReason) { + case 'completed': + return `${subject} finished and will do no further work unless you send it more.`; + case 'aborted': + return `${subject} was stopped before it finished.`; + case 'max-tokens': + return `${subject} ran out of room before it finished.`; + // A pre-step rejection — a hook deny, a policy plugin — discarded input + // the child had claimed, so the parent must not treat the task as done. + case 'refusal': + return `${subject} declined the task.`; + case 'error': + return `${subject} failed before it finished.`; + /* v8 ignore next 4 -- `SubagentResult['stopReason']` is merge-extensible, so this arm + * needs a backend that adds a variant; an unnameable ending is reported as unfinished + * rather than silently as success. */ + default: + return `${subject} ended abnormally (${String(stopReason)}) before it finished.`; + } +} +/** Serialize each durable child's delivery, release, and disposal. */ +class ChildLock { + tails = new Map(); + /** + * Run `operation` after every previously queued operation for `childId`. + * @param childId - the durable child whose operations are linearized. + * @param operation - the critical section to run in order. + * @returns the operation's own settlement. + */ + run(childId, operation) { + const previous = this.tails.get(childId) ?? Promise.resolve(); + const result = previous.then(operation, operation); + // Absorb rejections in the chaining tail so one failed critical section + // cannot reject an unrelated later caller. + const tail = result.then(() => undefined, () => undefined); + this.tails.set(childId, tail); + void tail.then(() => { + if (this.tails.get(childId) === tail) + this.tails.delete(childId); + }); + return result; + } +} +/** + * The continuable-subagent orchestration service behind `ctx.subagents`. Tool + * schema and host adapters are consumers of this one contract; foreground + * one-shot delegation keeps calling `ctx.subagents.start()` and never enters + * this lifecycle. + */ +export class SubagentContinuationManager { + ctx; + host; + setupRegistry; + /** Child session id → its live Activation. Process-local, never durable. */ + activations = new Map(); + /** Materializations admitted before drain, tracked through publication or rollback. */ + materializations = new Set(); + locks = new ChildLock(); + /** Structural Cordis owner of every Activation handle. */ + ownerCtx; + /** + * Exact roots whose host teardown has begun, with the live lineage members + * observed under each root. Entries remain until that exact root leaves the + * Agent registry, closing admission throughout its host's teardown without + * poisoning a later same-id replacement. + */ + closingScopes = new Map(); + draining = false; + constructor(ctx, host, setupRegistry) { + this.ctx = ctx; + this.host = host; + this.setupRegistry = setupRegistry; + // Ordinary Cordis owner effects unwind in reverse registration order, which + // cannot express the dynamic child graph. Register the private scope's + // structural disposer FIRST and the drain SECOND, so reverse unwind invokes + // the drain before releasing the scope; a cleanup effect on the same scope + // as the Agent handles would let structural handle disposal bypass + // child-first ordering. + const scope = ctx.plugin(function activationOwner() { }); + this.ownerCtx = scope.ctx; + ctx.on('agent/disposed', ({ agent }) => { + this.closingScopes.delete(agent); + }); + ctx.effect(function* () { + yield scope.dispose; + yield () => this.drain(); + }.bind(this), 'subagents.continuations()'); + } + /** + * Start one continuable background child: reserve its durable identity, + * resolve the provider's detached creation spec, create the child Agent + * through the private activation-owner scope, establish any continuable-parent + * ownership, and submit the initial prompt. Resolves when inbox acceptance + * yields the message id — without waiting for the turn to start or for the + * message to reach the Session log. + * + * Every failure before that acceptance rejects without either id, disposing + * any created handle and rolling back the Activation and parent ownership. + * The caller signal owns lookup, materialization, and admission only until + * acceptance; afterwards the manager owns the Activation independently. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted initial prompt's message id. + */ + async startContinuable(spec) { + const request = spec.request; + const parent = request.parent; + this.assertAdmitting(parent); + this.requirePersistence(); + assertSubagentMaxDepth(request.maxDepth); + const childId = SessionId(randomUUID()); + const childDepth = resolveChildDepth(parent, request.maxDepth); + // Snapshot before any await: invalid descriptor JSON rejects the call + // before a child exists, and the detached value is what reaches the log. + const agentProvider = request.agentOptions?.provider ?? parent.options.provider; + const agentModel = request.agentOptions?.model ?? parent.options.model; + const descriptor = snapshotSubagentDescriptor({ + mode: 'continuable', + provider: spec.provider, + label: spec.label, + ...agentProvider !== undefined ? { agentProvider } : {}, + ...agentModel !== undefined ? { agentModel } : {}, + ...request.persona !== undefined ? { persona: request.persona } : {}, + ...request.toolFilter !== undefined ? { toolFilter: request.toolFilter } : {}, + }); + // Capture before the first await: a later parent switch belongs to the + // parent's future, not to this child. + const delegatedPolicies = captureDelegatedPolicyOverrides(parent); + const prepared = await this.host.prepareContinuable(spec.provider, { + sessionId: childId, + parent, + signal: spec.signal, + }); + spec.signal.throwIfAborted(); + this.assertAdmitting(parent); + const lineageSeedLength = prepared.seed?.length ?? 0; + const seed = seedDescriptorTurn(childId, prepared.seed, descriptor); + const messageId = await this.locks.run(childId, async () => { + const activation = await this.materialize({ + childId, + provider: spec.provider, + parent, + create: { seed, meta: childSessionMeta(parent, childDepth, lineageSeedLength), delegatedPolicies }, + agentOptions: resolveChildAgentOptions(parent, request.agentOptions, childDepth), + composition: { persona: request.persona, toolFilter: request.toolFilter }, + signal: spec.signal, + }); + return this.submitMaterialized(activation, request.prompt, { kind: 'user' }, parent, spec.signal); + }); + return { childId, messageId }; + } + /** + * Deliver one later message to a known continuable child as its next FIFO + * turn. Routing depends only on Activation residency: a `running` Activation + * enqueues, a `waiting` one wakes the same Agent, and an absent one + * cold-resumes a new Activation from the persisted Session. The Agent inbox + * is the only queue, so every accepted message has one observable order. + * + * The caller signal owns lookup, materialization, and admission only until + * inbox acceptance; afterwards the accepted turn cannot be cancelled through + * this service. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - the durable child session id. + * @param content - the user-role content to deliver. + * @param options - the message source fields and caller cancellation. + * @returns the accepted message's inbox id. + * @throws when parent authority, availability, or admission rejects the delivery. + */ + async followup(parent, childId, content, options) { + this.assertAdmitting(parent); + while (true) { + const live = await this.locks.run(childId, async () => { + const activation = this.activations.get(childId); + if (activation === undefined) + return this.coldResume(parent, childId, content, options); + // A delivery that arrives after the disposal transaction began must not + // reach a handle being torn down; wait for release, then cold-resume. + /* v8 ignore next 3 -- the send-versus-dispose cutoff: reaching this arm needs a + * delivery to observe the transaction inside the same critical section that opened it, + * which no test can schedule deterministically. The behavior is covered end-to-end by + * "cold-resumes a delivery that lost the race with final disposal". */ + if (activation.disposal !== undefined) { + return activation.disposal.then(() => undefined, () => undefined); + } + return this.submitAdmitted(activation, content, options.source, parent, options.signal); + }); + /* v8 ignore start -- only the lost-cutoff arm above returns undefined, so only that + * race reaches the retry below, which then cold-resumes a new Activation. */ + if (live !== undefined) + return live; + this.assertAdmitting(parent); + options.signal.throwIfAborted(); + /* v8 ignore stop */ + } + } + /** + * Interrupt one live continuable child's current turn. Admission is + * synchronous and the effect is asynchronous: this authorizes the caller, + * requests `Agent.cancel(cause, { keepInbox: true })` on the target, and + * returns without waiting for the target to observe the signal or reach + * quiescence. The Activation, its handle, accepted unclaimed inbox work, and + * already-published descendants are untouched; work already claimed into the + * interrupted turn is not requeued. Once the interrupted driver is idle, a + * waking send resumes the parked queue. + * + * An absent target is an accepted no-op, which uniformly covers natural + * completion races, repeated requests, one-shot ids, and unknown ids without + * consulting the durable catalog. A target whose disposal transaction is + * already open is likewise an accepted no-op after authorization. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the presented authority does + * not own the live target: a stale or self-targeting ancestor caller, a + * parent address that is not the live target's durable direct parent, or + * an ancestor outside the target's recorded live lineage. + */ + interrupt(targetSessionId, authority) { + if (authority.kind === 'ancestor') { + const caller = authority.agent; + // A stale caller is rejected even when the target is absent, so a + // replaced same-id Agent can never probe this manager's state. + if (this.ctx.agents.get(caller.id) !== caller) { + throw new SubagentError(`interrupting "${targetSessionId}" requires the exact live ancestor agent`, 'UNAUTHORIZED'); + } + if (caller.id === targetSessionId) { + throw new SubagentError(`agent "${caller.id}" cannot interrupt itself`, 'UNAUTHORIZED'); + } + } + const activation = this.activations.get(targetSessionId); + if (activation === undefined) + return; + if (authority.kind === 'user') { + if (activation.handle.agent.session.header.parentSession !== authority.parentSessionId) { + throw new SubagentError(`subagent "${targetSessionId}" belongs to another parent session`, 'UNAUTHORIZED'); + } + } + else if (!activation.ancestry.has(authority.agent)) { + throw new SubagentError(`subagent "${targetSessionId}" is not a live descendant of agent "${authority.agent.id}"`, 'UNAUTHORIZED'); + } + // Disposal already stopped the target with a whole-Activation teardown; + // a second cancel would be a redundant signal on a closing handle. + if (activation.disposal !== undefined) + return; + activation.handle.agent.cancel(authority.kind === 'user' ? { kind: 'user' } : { kind: 'parent' }, { keepInbox: true }); + } + /** + * Deliver explicitly selected content from one resident continuable child to + * its durable direct parent. Sender authorization, parent resolution, and + * send acceptance share one no-await span. Reporting neither concludes the + * child's turn nor changes its Activation lifetime. + * @param child - exact live reporting child; this is the authority credential. + * @param content - selected model-facing content. + * @param options - scheduling policy and pre-acceptance cancellation. + * @returns the stable identity of the message accepted by the parent. + * @throws {SubagentError} when the sender is unauthorized, the parent is not + * live, or continuation admission is closing. + */ + // oxlint-disable-next-line typescript/require-await -- keep rejection semantics without yielding during admission + async reportFrom(child, content, options) { + options.signal.throwIfAborted(); + this.assertAdmitting(child); + const activation = this.authorizeReporter(child); + const parent = this.resolveReportParent(child); + return this.deliverReport(activation, parent, content, options.delivery); + } + /** Authorize only the exact Agent of one resident Activation. */ + authorizeReporter(child) { + const activation = this.activations.get(child.id); + if (activation === undefined || activation.handle.agent !== child) { + throw new SubagentError(`agent "${child.id}" is not a live continuable subagent and cannot report`, 'UNAUTHORIZED'); + } + /* v8 ignore next 6 -- only a synchronous re-entrant disposer can open this + * transaction between exact-agent authorization and this no-await cutoff. */ + if (activation.disposal !== undefined) { + throw new SubagentError(`subagent "${child.id}" activation is being disposed; the report was not delivered`, 'ACTIVATION_CLOSING'); + } + return activation; + } + /** Resolve the reporting child's live direct parent from durable lineage. */ + resolveReportParent(child) { + const parentId = child.session.header.parentSession; + /* v8 ignore next -- every continuation-managed child has direct-parent metadata. */ + const parent = parentId === undefined ? undefined : this.ctx.agents.get(parentId); + if (parent === undefined) { + throw new SubagentError('direct parent is not live; report was not delivered', 'PARENT_UNAVAILABLE'); + } + return parent; + } + /** Deliver one framed report through the selected parent scheduling preset. */ + deliverReport(activation, parent, content, delivery) { + const message = createUserMessage({ + content: [ + { type: 'text', text: `Background subagent ${activation.childId} reported:` }, + ...content, + ], + source: { + kind: 'subagent-report', + form: 'relay', + senderSessionId: activation.childId, + }, + }); + if (delivery === 'wakeup') { + this.sendWaking(parent, message, () => { this.sendReport(parent, message, delivery); }); + } + else { + this.sendReport(parent, message, delivery); + } + return message.id; + } + /** + * Perform one waking send to a parent, accounted against that parent's own + * Activation when it has one. Registering the id before the send is what + * keeps a continuation-managed parent from being judged quiescent in the + * window between `followup()` and the microtask that admits it. + * @param parent - the exact live parent receiving the waking message. + * @param message - the message whose id is accounted. + * @param send - the synchronous waking send to perform. + */ + sendWaking(parent, message, send) { + const parentActivation = this.activations.get(parent.id); + if (parentActivation !== undefined && parentActivation.handle.agent === parent) { + this.admitWaking(parentActivation, message.id, send); + } + else { + send(); + } + } + /** Send one report while translating only the parent's own rejection. */ + sendReport(parent, message, delivery) { + try { + if (delivery === 'wakeup') + parent.followup(message); + else + parent.inject(message); + } + catch (error) { + throw new SubagentError('direct parent is not live; report was not delivered', 'PARENT_UNAVAILABLE', { cause: error }); + } + } + /** + * Close admission, await every already-admitted materialization through + * publication or rollback, then dispose the stable live Activation forest + * child-first. Sibling branches drain independently: one failure is recorded + * but never prevents the remaining handles from being attempted, and the + * aggregate rejects only after every branch settles. + * @returns once materialization is quiescent and every live Activation released its handle. + * @throws an aggregate error when any branch failed to release. + */ + async drain() { + // Close admission synchronously before the first await. Materializations + // already past that cutoff remain tracked until their handle is installed + // or rollback completes, producing a stable forest for the later snapshot. + this.draining = true; + await Promise.all([...this.materializations].map(materialization => materialization.settled)); + // Snapshot roots after closing admission: a root is an Activation no live + // Activation owns, so disposing roots recurses child-first into the forest. + const owned = new Set(); + for (const activation of this.activations.values()) { + for (const child of activation.ownedChildren) + owned.add(child); + } + const roots = [...this.activations.values()].filter(activation => !owned.has(activation.childId)); + await this.disposeRoots(roots, 'activation(s)'); + } + /** + * Stop only the continuable descendants of exact live host-owned parents. + * Admission stays closed for those parent trees until each exact parent + * leaves the Agent registry; unrelated trees and manager-wide admission stay + * live. + * @param parents - exact live roots whose continuable descendants must stop. + * @returns once every retained descendant Activation released its handle. + * @throws an aggregate error after all scoped branches settle when any failed. + */ + async drainDescendants(parents) { + const roots = new Set(parents.filter(parent => this.ctx.agents.get(parent.id) === parent)); + if (roots.size === 0) + return; + // Publish the scoped admission cutoff before the first await. Merge with an + // earlier call for the same exact root so a converging drain cannot forget + // descendants whose release is already in flight. + for (const root of roots) { + this.closingMembers(root).add(root); + } + const targets = []; + for (const activation of this.activations.values()) { + const lineage = this.liveLineage(activation.handle.agent); + // Strict descendants only: a continuable Agent may itself be a + // host-owned root, and its host remains responsible for that root handle. + const owners = [...roots].filter(root => activation.handle.agent !== root + && activation.ancestry.has(root)); + if (owners.length === 0) + continue; + targets.push(activation); + for (const owner of owners) { + const members = this.closingMembers(owner); + members.add(activation.handle.agent); + for (const agent of lineage) + members.add(agent); + } + } + const materializations = [...this.materializations].filter((materialization) => { + const owners = [...roots].filter(root => materialization.lineage.includes(root)); + for (const owner of owners) { + const members = this.closingMembers(owner); + for (const agent of materialization.lineage) + members.add(agent); + } + return owners.length > 0; + }); + const ownedTargets = new Set(); + for (const activation of targets) { + for (const child of activation.ownedChildren) + ownedTargets.add(child); + } + const targetRoots = targets.filter(activation => !ownedTargets.has(activation.childId)); + // Open every selected transaction before the materialization barrier. + // Disposal propagates cancellation top-down in the same synchronous span; + // handle release remains child-first. + for (const activation of targets) { + const disposal = this.dispose(activation); + void disposal.catch(() => undefined); + } + await Promise.all(materializations.map(materialization => materialization.settled)); + await this.disposeRoots(targetRoots, 'scoped activation(s)'); + } + /** Dispose independent roots and report every branch failure after all settle. */ + async disposeRoots(roots, failureSubject) { + const failures = await Promise.all(roots.map(async (activation) => { + try { + await this.dispose(activation); + return undefined; + } + catch (error) { + return error; + } + })); + const reasons = failures.filter(failure => failure !== undefined); + if (reasons.length > 0) { + throw new SubagentError(`continuable subagent teardown failed for ${reasons.length} ${failureSubject}: ` + + reasons.map(reason => errorChain(reason)).join('; '), 'ACTIVATION_TEARDOWN_FAILED'); + } + } + /** Return the retained member set for one exact scoped-teardown root. */ + closingMembers(root) { + const existing = this.closingScopes.get(root); + if (existing !== undefined) + return existing; + const members = new Set(); + this.closingScopes.set(root, members); + return members; + } + /** + * Return the exact currently resolvable ancestry from `agent` upward. The + * first element is always the supplied identity, even when it is already + * stale; each ancestor after it must be the registry's current exact entry. + */ + liveLineage(agent) { + const lineage = [agent]; + const seen = new Set([agent.id]); + let parentSession = agent.session.header.parentSession; + while (parentSession !== undefined) { + const parent = this.ctx.agents.get(parentSession); + if (parent === undefined || seen.has(parent.id)) + break; + lineage.push(parent); + seen.add(parent.id); + parentSession = parent.session.header.parentSession; + } + return lineage; + } + /** + * The teardown that closed continuable admission for this agent's lineage. + * `'manager'` is the whole manager draining; an Agent is the exact scoped root + * whose forest is closing. + * @param agent - the agent whose lineage is tested. + * @returns the closing teardown, or `undefined` while admission is open. + */ + closingTeardownFor(agent) { + if (this.draining) + return 'manager'; + const lineage = this.liveLineage(agent); + for (const [root, members] of this.closingScopes) { + if (members.has(agent) || lineage.includes(root)) + return root; + } + return undefined; + } + /** Reject new admission once the manager or this exact parent tree began draining. */ + assertAdmitting(agent) { + const closing = this.closingTeardownFor(agent); + if (closing === undefined) + return; + throw new SubagentError(closing === 'manager' + ? 'continuable subagents are draining; the operation was not admitted' + : `continuable subagents below parent "${closing.id}" are draining; the operation was not admitted`, 'DRAINING'); + } + /** + * Derive residency from Agent quiescence and the owned-child set. `running` + * covers an active admission, an open turn, or accepted waking inbox work. + * + * `Agent.status` alone is insufficient: it stays `idle` between an accepted + * waking send and the microtask that admits it, so a synchronous inbox + * observer would see `settled` while a turn is already queued. `accepted` + * holds the ids this manager admitted but has not yet seen drained. + */ + stateOf(activation) { + if (activation.handle.agent.status === 'running' || activation.accepted.size > 0) + return 'running'; + if (activation.ownedChildren.size > 0) + return 'waiting'; + return 'settled'; + } + /** + * Cold-resume a persisted child: inspect and authorize its Session, fold the + * generic descriptor, create the Activation through `ctx.agents.resume()`, + * and submit the waiting turn. This never dispatches through a subagent + * provider — the persisted Session already holds the initial prefix and the + * descriptor is the whole reconstruction input. + */ + async coldResume(parent, childId, content, options) { + const persistence = this.requirePersistence(); + let loaded; + try { + loaded = await persistence.inspect(childId, options.signal); + } + catch (error) { + options.signal.throwIfAborted(); + throw new SubagentError(`subagent "${childId}" is unavailable`, 'NOT_RESUMABLE', { cause: error }); + } + options.signal.throwIfAborted(); + this.assertAdmitting(parent); + // Authorize the persisted header before folding: only the durable child's + // exact live direct parent may continue it. + this.authorizeLineage(parent, childId, loaded.meta.parentSession); + // Fold only the child's own suffix: a fork seed replays the parent's log, + // which may carry an ANCESTOR's descriptor when the parent is itself a + // continuable child. + const descriptor = foldSubagentDescriptor(loaded.events.slice(loaded.meta.seedLength ?? 0)); + if (descriptor === undefined || descriptor.mode !== 'continuable') { + throw new SubagentError(`subagent "${childId}" has no supported continuation state and cannot be resumed; ` + + 'do not retry send_message with this id', 'NOT_RESUMABLE'); + } + let activation; + try { + activation = await this.materialize({ + childId, + provider: descriptor.provider, + parent, + agentOptions: { + ...descriptor.agentProvider !== undefined ? { provider: descriptor.agentProvider } : {}, + ...descriptor.agentModel !== undefined ? { model: descriptor.agentModel } : {}, + }, + composition: { persona: descriptor.persona, toolFilter: descriptor.toolFilter }, + signal: options.signal, + }); + } + catch (error) { + options.signal.throwIfAborted(); + if (error instanceof SubagentError) + throw error; + throw new SubagentError(`subagent "${childId}" is unavailable`, 'NOT_RESUMABLE', { cause: error }); + } + return this.submitMaterialized(activation, content, options.source, parent, options.signal); + } + /** + * Submit to a freshly materialized Activation or roll it back completely. + * @param activation - the just-published Activation to admit or release. + * @param content - the initial or resumed message content. + * @param source - durable fields naming who supplied the accepted message. + * @param parent - the live direct parent authorizing admission. + * @param signal - caller cancellation owning admission until acceptance. + * @returns the accepted inbox message id. + */ + async submitMaterialized(activation, content, source, parent, signal) { + try { + return this.submitAdmitted(activation, content, source, parent, signal); + } + catch (error) { + /* v8 ignore next -- rollback disposal failures must not mask the + * pre-acceptance signal, drain, or lifecycle failure. */ + await this.dispose(activation).catch(() => undefined); + throw error; + } + } + /** + * Create or resume the child Agent through the private activation-owner + * scope, install the handle in a fresh Activation, and register ownership on + * a continuation-managed parent. Rejection leaves no Activation, no handle, + * and no ownership membership. + */ + materialize(inputs) { + this.assertAdmitting(inputs.parent); + const settled = Promise.withResolvers(); + const lineage = this.liveLineage(inputs.parent); + const materialization = { + lineage, + settled: settled.promise, + }; + this.materializations.add(materialization); + return this.materializeTracked(inputs, lineage).finally(() => { + this.materializations.delete(materialization); + settled.resolve(); + }); + } + /** + * Perform one tracked materialization. The caller keeps the drain barrier + * registered until this either returns a resident Activation or finishes + * rollback. + */ + async materializeTracked(inputs, parentLineage) { + const { childId, provider, parent, create } = inputs; + // No id pre-check here: the child lock serializes each durable child, both + // callers reach this only after confirming no Activation exists, and + // `AgentRegistry.enter()` is the authoritative collision boundary for an id + // some other owner holds — a duplicate would reject there with rollback. + inputs.signal.throwIfAborted(); + const setup = (childCtx) => { + // Only fresh creation seeds the delegation policy onto the child's own + // log (after any fork seed, so fresh policy wins stale seed state); a + // cold resume replays those persisted events instead. + if (create !== undefined) { + appendDelegatedPolicyOverrides(childCtx.agent.session, create.delegatedPolicies); + } + applyChildComposition(childCtx, parent, inputs.composition); + return this.setupRegistry.apply(childCtx); + }; + const observer = this.host.observeActivation(provider, childId, parent); + // Agent creation owns rollback before handle transfer. A rejection leaves + // no resident Activation and therefore publishes no lifecycle edge. + const handle = create === undefined + ? await this.ownerCtx.agents.resume({ + resumeSessionId: childId, + agentOptions: inputs.agentOptions, + signal: inputs.signal, + setup, + }) + : await this.ownerCtx.agents.create({ + sessionId: childId, + meta: create.meta, + seed: create.seed, + agentOptions: inputs.agentOptions, + signal: inputs.signal, + setup, + }); + const activation = { + childId, + // The durable lineage, not merely the caller: creation stamps this same + // agent into the child's header, and cold resume authorized it against + // the persisted header before materializing. + parentSession: parent.id, + provider, + handle, + ancestry: new WeakSet([handle.agent, ...parentLineage]), + ownedChildren: new Set(), + observer, + disposal: undefined, + accepted: new Set(), + announced: false, + poke: Promise.withResolvers(), + }; + // After transfer, any failure must dispose the created handle, remove the + // Activation, and roll back parent ownership before rejecting. + this.activations.set(childId, activation); + try { + inputs.signal.throwIfAborted(); + this.assertAdmitting(parent); + this.acquireOwnership(parent, childId); + // Every accepted id leaves the inbox exactly once, through dequeue or + // discard. Clearing it there is what lets `stateOf()` distinguish a truly + // quiet Agent from one whose accepted turn has not been admitted yet. + // Registered through the child's own scoped context, so scope filtering + // already restricts both listeners to this exact agent. + handle.agent.ctx.on('agent/inbox/claimed', ({ message }) => { + /* v8 ignore next -- a claim of an id this manager never admitted needs + * another sender on the same child, which no current path allows. */ + if (activation.accepted.delete(message.id)) + this.wake(activation); + }); + handle.agent.ctx.on('agent/inbox/discarded', ({ message }) => { + if (activation.accepted.delete(message.id)) + this.wake(activation); + }); + // Agent creation committed setup at its publication boundary; + // revocations from here on are immediate live revocation. + // Publish the start edge before any turn can run, so observers see this + // epoch before its first request. + observer.start(handle.agent); + } + catch (error) { + // Listener exceptions are contained by the lifecycle emitter; a start + // publication throw therefore leaves no residency edge to pair. + /* v8 ignore next -- rollback failure must not mask the admission failure + * that prevented this operation from returning an accepted message id. */ + await this.rollbackUnpublished(activation).catch(() => undefined); + throw error; + } + this.watchSettlement(activation); + return activation; + } + /** + * Release an Activation whose start edge was not published. The memoized + * transaction remains in the live map until handle disposal settles, so a + * concurrent drain or delivery observes the same closing boundary. + */ + rollbackUnpublished(activation) { + return (activation.disposal ??= (async () => { + try { + await activation.handle.dispose(); + } + finally { + this.activations.delete(activation.childId); + this.releaseOwnership(activation.childId); + } + })()); + } + /** + * Register the child in a continuation-managed parent's owned set before the + * child can run, so that parent cannot settle while the child is live. A + * top-level or other non-continuation Agent has no Activation and stays + * outside the waiting graph. + */ + acquireOwnership(parent, childId) { + const parentActivation = this.activations.get(parent.id); + if (parentActivation === undefined) + return; + if (parentActivation.disposal !== undefined) { + throw new SubagentError(`subagent parent "${parent.id}" is being disposed; the child was not established`, 'ACTIVATION_CLOSING'); + } + parentActivation.ownedChildren.add(childId); + } + /** Remove one child from its live owner's set and let that owner re-check settlement. */ + releaseOwnership(childId) { + for (const candidate of this.activations.values()) { + if (candidate.ownedChildren.delete(childId)) + this.wake(candidate); + } + } + /** Let a settlement watcher re-observe quiescence after ownership or inbox changes. */ + wake(activation) { + activation.poke.resolve(); + activation.poke = Promise.withResolvers(); + } + /** + * Submit one message as the child's next FIFO turn and return its accepted + * inbox id. Acceptance is the operation's success boundary; the manager owns + * the Activation independently afterwards. + */ + submit(activation, content, source, parent) { + // Parent-originated delivery keeps the parent live through ownership, so + // establish it before the message can enter the child's inbox. + this.acquireOwnership(parent, activation.childId); + const message = createUserMessage({ content, source }); + const accepted = this.admitWaking(activation, message.id, () => { + activation.handle.agent.followup(message); + }); + // Past this point the caller has an id for this child, so its eventual + // settlement is something the parent is owed an account of. + activation.announced = true; + return accepted; + } + /** + * Account one waking send across a resident Activation's settlement window. + * @param activation - Activation receiving waking inbox work. + * @param messageId - stable identity of the message about to be sent. + * @param send - synchronous send that publishes one enqueue occurrence. + * @returns the accepted message id. + */ + admitWaking(activation, messageId, send) { + // `Agent.followup()` publishes inbox events synchronously, so observers must + // see this Activation as busy before the call begins. + activation.accepted.add(messageId); + try { + send(); + } + catch (error) { + activation.accepted.delete(messageId); + throw error; + } + // Accepted waking work keeps this Activation live until whenIdle() observes + // the complete waking suffix. + this.wake(activation); + return messageId; + } + /** + * Cross the final admission cutoff and submit without yielding. Signal abort, + * manager drain, or Activation disposal that wins before this synchronous + * span rejects without inbox acceptance. + */ + submitAdmitted(activation, content, source, parent, signal) { + signal.throwIfAborted(); + this.assertAdmitting(parent); + /* v8 ignore next 6 -- only a synchronous re-entrant disposer can change + * this field between the caller's live check and this no-await boundary. */ + if (disposalOf(activation) !== undefined) { + throw new SubagentError(`subagent "${activation.childId}" activation is being disposed; the message was not accepted`, 'ACTIVATION_CLOSING'); + } + this.authorizeLineage(parent, activation.childId, activation.handle.agent.session.header.parentSession); + return this.submit(activation, content, source, parent); + } + /** + * Authorize one operation against the durable direct-parent lineage. Other + * agents, ancestors, teams, workflows, and hosts remain rejected until an + * explicit authority protocol has a production consumer. + */ + authorizeLineage(parent, childId, parentSession) { + if (this.ctx.agents.get(parent.id) !== parent) { + throw new SubagentError(`subagent "${childId}" delivery requires the exact live parent agent`, 'UNAUTHORIZED'); + } + if (parentSession !== parent.id) { + throw new SubagentError(`subagent "${childId}" belongs to another parent session`, 'UNAUTHORIZED'); + } + } + /** + * Follow one Activation to settlement: wait for Agent quiescence, then for + * every owned child to complete disposal, and dispose the handle once both + * hold. A `next-turn` delivered while `waiting` wakes the same Agent and + * returns it to `running`, so this re-observes rather than settling early. + */ + watchSettlement(activation) { + void (async () => { + while (disposalOf(activation) === undefined) { + const poked = activation.poke.promise; + await Promise.race([activation.handle.agent.whenIdle(), poked]); + if (disposalOf(activation) !== undefined) + return; + // Re-check settlement INSIDE the child lock and begin disposal in the + // same critical section, so a concurrent delivery either wins admission + // before the transaction opens or waits for release and cold-resumes. + // Deciding outside the lock would let a delivery observe a not-yet + // resident handle that this watcher is already about to tear down. + const settling = await this.locks.run(activation.childId, () => { + if (disposalOf(activation) !== undefined || this.stateOf(activation) !== 'settled') { + return Promise.resolve({ settling: false }); + } + // `dispose()` assigns its memoized transaction synchronously, so + // admission is closed before this critical section releases. + return Promise.resolve({ settling: true, done: this.dispose(activation) }); + }); + if (!settling.settling) { + // Still running, or waiting on descendants: re-observe after the next + // accepted message or ownership release. + if (activation.handle.agent.status !== 'running') + await poked; + continue; + } + try { + await settling.done; + } + catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" activation teardown failed: ${errorChain(error)}`); + } + return; + } + })(); + } + /** + * Stop one Activation immediately, then release it child-first. The memoized + * transaction is installed before cancellation or recursive callbacks, so + * admission and reentrant teardown converge on the same owner. + * + * The final session flush is best effort and never prevents handle disposal + * or ownership release, because retaining a child would permanently pin its + * ancestors in `waiting`. + * @param activation - the residency epoch to stop and release. + * @returns the one disposal transaction owned by this Activation. + */ + dispose(activation) { + const existing = activation.disposal; + if (existing !== undefined) + return existing; + const completion = Promise.withResolvers(); + // Presence is the admission cutoff. Assign it before the async helper starts + // because that helper cancels Agents and may synchronously re-enter callers. + activation.disposal = completion.promise; + void this.finishDisposal(activation).then(completion.resolve, completion.reject); + return completion.promise; + } + /** + * Propagate stop synchronously, then finish the child-first release. + * @param activation - the Activation whose disposal transaction is installed. + * @returns once the handle and ownership edge are released. + */ + async finishDisposal(activation) { + this.wake(activation); + const { childId } = activation; + // Stop top-down before the first await. Slow descendant cleanup may delay + // release, but it cannot let this ancestor continue model or tool work. + activation.handle.agent.cancel({ kind: 'parent' }); + const idle = activation.handle.agent.whenIdle(); + const children = [...activation.ownedChildren] + .map(child => this.activations.get(child)) + .filter((child) => child !== undefined); + const childDisposals = children.map(child => this.dispose(child)); + const failures = []; + try { + // Release remains child-first even though cancellation propagated + // top-down: every owned child completes before this handle is removed. + const childFailures = await Promise.all(childDisposals.map(async (disposal) => { + try { + await disposal; + return undefined; + } + catch (error) { + return error; + } + })); + const reasons = childFailures.filter(reason => reason !== undefined); + if (reasons.length > 0) { + failures.push(new SubagentError(`subagent "${childId}" child teardown failed: ${reasons.map(reason => errorChain(reason)).join('; ')}`, 'ACTIVATION_TEARDOWN_FAILED')); + } + // Quiesce before the flush: a turn still running would keep + // appending events the flush cannot cover. + await idle; + await this.flushFinalState(activation); + // Capture the child-dependent edge data while the child is still live: + // handle disposal unregisters it, and consumers read its log and scope. + activation.observer.capture(activation.handle.agent); + } + catch (error) { + failures.push(new SubagentError(`subagent "${childId}" activation teardown failed: ${errorChain(error)}`, 'ACTIVATION_TEARDOWN_FAILED', { cause: error })); + } + try { + await activation.handle.dispose(); + } + catch (error) { + failures.push(new SubagentError(`subagent "${childId}" activation handle disposal failed: ${errorChain(error)}`, 'ACTIVATION_TEARDOWN_FAILED', { cause: error })); + } + let failure; + if (failures.length === 1) { + failure = failures[0]; + } + else if (failures.length > 1) { + failure = new SubagentError(`subagent "${childId}" activation teardown failed at ${failures.length} boundaries: ` + + failures.map(item => errorChain(item)).join('; '), 'ACTIVATION_TEARDOWN_FAILED', { cause: new AggregateError(failures) }); + } + // Only now is the Activation gone: keeping the entry until disposal settles + // makes a racing delivery wait for release rather than cold-resume into the + // still-registered agent. + this.activations.delete(childId); + // BEFORE releasing ownership, while the parent still counts this child and + // therefore cannot be judged settled. Delivering after the release would + // race a parent watcher that resumes one microtask later, finds itself + // childless and quiet, and disposes an Agent whose `cancel()` clears the + // inbox this notice is sitting in. + this.notifySettlement(activation, activation.observer.terminal(failure)); + // Release ownership even on failure: a retained failed child would pin its + // ancestors in `waiting` forever. + this.releaseOwnership(childId); + // Emit once the disposal outcome is known, so a rejecting scoped cleanup + // cannot be reported as a successful epoch. + activation.observer.settle(failure); + if (failure !== undefined) + throw failure; + } + /** + * Tell the durable direct parent that this child produced everything it is + * going to. Unconditional for every child the caller received an id for: it + * does not consider whether the child reported, because the cases that most + * need it — a token ceiling, a model failure, cancellation, teardown — are + * exactly the ones where the child never got to choose. A materialization + * rolled back before its first acceptance stays silent, since the caller was + * told that child was not established. A parent that is no longer live is not + * an error; the child's own Session remains the durable record either way. + * A parent whose own lineage is already closing receives the notice without a + * wake, because teardown is not a reason to start a turn. + * + * Never blocks disposal. A delivery failure is logged and dropped, because + * retaining a child to retry a notice would pin its whole ancestry in + * `waiting` forever. + * @param activation - the settling Activation, still owned by its parent. + * @param terminal - how this epoch ended, as the terminal edge will report it. + */ + notifySettlement(activation, terminal) { + if (!activation.announced) + return; + try { + const parent = this.ctx.agents.get(activation.parentSession); + if (parent === undefined) + return; + const summary = settlementSummary(activation.childId, terminal.stopReason); + const message = createUserMessage({ + content: [ + { type: 'text', text: summary }, + ...terminal.output === undefined + ? [{ type: 'text', text: 'It left no closing message.' }] + : [{ type: 'text', text: 'Its closing message:' }, ...terminal.output], + ], + source: { + kind: 'subagent-settled', + form: 'notice', + summary: boundContextSummary(summary), + senderSessionId: activation.childId, + }, + }); + // A parent whose own teardown already began must not be woken. Waking is + // not a queue operation: `followup()` on a quiescent Agent starts a turn, + // and `cancel()` does not arm against a later one, so a notice arriving + // during teardown would spend a model request on an Agent its host is + // about to dispose — once per tree layer, since each layer's own notice + // then wakes the layer above it. Injecting delivers to a parent still + // reading its inbox and records the account in the log either way; it + // does NOT survive that parent's own disposal, whose `keepInbox: false` + // cancel durably clears whatever it never claimed. + if (this.closingTeardownFor(parent) !== undefined) { + parent.inject(message); + return; + } + // An idle parent has nothing else to look at, so it gets one ordinary + // turn. A busy parent is steered instead of woken: `Inbox.claim()` takes + // the whole next-step batch at one boundary, so several children settling + // together cost one step rather than one turn each. Steering rather than + // injecting closes the window where a driver retires between this status + // read and the send, which would strand the notice unclaimed. + this.sendWaking(parent, message, () => { + if (parent.status === 'idle') + parent.followup(message); + else + parent.steer(message); + }); + } + catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" settlement notice was not delivered to its parent: ` + + errorChain(error)); + } + } + /** + * Request a best-effort final session flush after the child is quiescent. + * Listener failure is logged because flush participation cannot identify a + * particular persistence backend, and teardown must still release ownership. + * @param activation - the Activation whose final events should be flushed. + */ + async flushFinalState(activation) { + const child = activation.handle.agent; + try { + await child.ctx.sessions.flush(child.session); + } + catch (error) { + this.ctx.logger.warn(`subagent "${activation.childId}" best-effort final session flush failed; ` + + `the persisted state may be unavailable or stale on resume: ${errorChain(error)}`); + } + } + /** Resolve the persistence service continuable children require, or fail loud. */ + requirePersistence() { + const persistence = this.ctx.get('sessionPersistence'); + if (persistence === undefined) { + throw new SubagentError('continuable subagents require session persistence (load a dsh-session-persistence backend)', 'PERSISTENCE_UNAVAILABLE'); + } + return persistence; + } +} +export default SubagentContinuationManager; +//# sourceMappingURL=continuation.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.d.ts new file mode 100644 index 0000000..6b9082e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.d.ts @@ -0,0 +1,31 @@ +/** + * Delegation-depth accounting: the recursion budget a parent passes to its + * children. Kept apart from the service so composition helpers can read it + * without importing the registry. + * + * @module @deepseek-ai/dsh-subagent/depth + */ +import type { Agent } from '@deepseek-ai/dsh-agent'; +declare module '@deepseek-ai/dsh-agent' { + interface AgentOptions { + /** Delegation depth: zero for a top-level agent and parent depth + 1 for a child. */ + subagentDepth?: number; + } +} +/** + * Read an agent's delegation depth, treating absence as top-level depth zero. + * The persisted session header is authoritative and monotone: runtime + * `AgentOptions.subagentDepth` may DEEPEN the count but can never lower it — + * a resumed child arrives with fresh options, and counting it from zero would + * let it delegate as if it were top-level. + * @param agent - the agent whose header and options carry the depth. + * @returns its non-negative safe-integer depth. + * @throws if the runtime `AgentOptions.subagentDepth` is not a non-negative safe integer. + */ +export declare function delegationDepthOf(agent: Agent): number; +/** + * Reject a recursion cap that cannot represent an exact delegation depth. + * @param maxDepth - the optional runtime value to validate. + */ +export declare function assertSubagentMaxDepth(maxDepth: unknown): void; +//# sourceMappingURL=depth.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.js new file mode 100644 index 0000000..9282c92 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/depth.js @@ -0,0 +1,39 @@ +/** + * Delegation-depth accounting: the recursion budget a parent passes to its + * children. Kept apart from the service so composition helpers can read it + * without importing the registry. + * + * @module @deepseek-ai/dsh-subagent/depth + */ +/** + * Read an agent's delegation depth, treating absence as top-level depth zero. + * The persisted session header is authoritative and monotone: runtime + * `AgentOptions.subagentDepth` may DEEPEN the count but can never lower it — + * a resumed child arrives with fresh options, and counting it from zero would + * let it delegate as if it were top-level. + * @param agent - the agent whose header and options carry the depth. + * @returns its non-negative safe-integer depth. + * @throws if the runtime `AgentOptions.subagentDepth` is not a non-negative safe integer. + */ +export function delegationDepthOf(agent) { + const runtime = agent.options.subagentDepth; + if (runtime !== undefined && (!Number.isSafeInteger(runtime) || runtime < 0 || Object.is(runtime, -0))) { + throw new TypeError('agent subagentDepth must be a non-negative safe integer'); + } + // The header value was validated at the session boundary (creation and + // persistence load both construct through the store). + return Math.max(agent.session.header.delegationDepth ?? 0, runtime ?? 0); +} +/** + * Reject a recursion cap that cannot represent an exact delegation depth. + * @param maxDepth - the optional runtime value to validate. + */ +export function assertSubagentMaxDepth(maxDepth) { + if (maxDepth !== undefined && (typeof maxDepth !== 'number' + || !Number.isSafeInteger(maxDepth) + || maxDepth < 0 + || Object.is(maxDepth, -0))) { + throw new TypeError('subagent maxDepth must be a non-negative safe integer'); + } +} +//# sourceMappingURL=depth.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.d.ts new file mode 100644 index 0000000..b608916 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.d.ts @@ -0,0 +1,21 @@ +/** + * Seeding of a continuable child's durable descriptor event: the model-hidden + * record of the child's declared composition before its first request, so a + * later cold resume can reconstruct it from its own log. + * + * @module @deepseek-ai/dsh-subagent/descriptor-seed + */ +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'; +import type { SubagentDescriptorData } from './descriptor.ts'; +/** + * Build the child's creation seed: any inherited parent-history prefix followed + * by one model-hidden, between-turn `descriptor` event. Staging through a + * `Session` assigns the sequence number and enforces the same lossless-JSON + * rules the durable log does. + * @param childId - the reserved child session id the staged log belongs to. + * @param seed - the inherited completed-turn prefix, or `undefined` for a fresh child. + * @param descriptor - the snapshotted composition record to persist. + * @returns the complete seed events, contiguous from sequence zero. + */ +export declare function seedDescriptorTurn(childId: SessionId, seed: readonly SessionEvent[] | undefined, descriptor: SubagentDescriptorData): SessionEvent[]; +//# sourceMappingURL=descriptor-seed.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.js new file mode 100644 index 0000000..6a32f51 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor-seed.js @@ -0,0 +1,24 @@ +/** + * Seeding of a continuable child's durable descriptor event: the model-hidden + * record of the child's declared composition before its first request, so a + * later cold resume can reconstruct it from its own log. + * + * @module @deepseek-ai/dsh-subagent/descriptor-seed + */ +import { Session } from '@deepseek-ai/dsh-session'; +/** + * Build the child's creation seed: any inherited parent-history prefix followed + * by one model-hidden, between-turn `descriptor` event. Staging through a + * `Session` assigns the sequence number and enforces the same lossless-JSON + * rules the durable log does. + * @param childId - the reserved child session id the staged log belongs to. + * @param seed - the inherited completed-turn prefix, or `undefined` for a fresh child. + * @param descriptor - the snapshotted composition record to persist. + * @returns the complete seed events, contiguous from sequence zero. + */ +export function seedDescriptorTurn(childId, seed, descriptor) { + const staged = Session.create(childId, seed); + staged.append('subagent/descriptor', descriptor); + return [...staged.events]; +} +//# sourceMappingURL=descriptor-seed.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.d.ts new file mode 100644 index 0000000..9e34084 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.d.ts @@ -0,0 +1,139 @@ +/** + * The durable subagent-child descriptor: the versioned, model-hidden + * `subagent/descriptor` session event that identifies every session-backed + * subagent and records whether it is one-shot or continuable. Continuable + * descriptors additionally preserve the declared composition required for + * cold resume. Providers append it turn-enclosed in the child's initial turn. + * + * The descriptor deliberately snapshots explicit fields rather than the + * merge-extensible `AgentOptions` object: an unrelated extension value cannot + * make continuation fail merely because it is not JSON, and later composition + * inputs require a deliberate {@link SUBAGENT_DESCRIPTOR_VERSION} change. It + * omits `subagentDepth` — cold resume trusts the persisted header's + * `delegationDepth` as the monotone floor — and `outputSchema`, which belongs + * to one activation's result contract rather than durable child composition. + * Per-activation knobs such as `maxTokens` are omitted for the same reason as + * `outputSchema`: they budget one activation. Cold resume requires the exact + * live parent for authorization but reconstructs child options only from the + * durable descriptor, so it neither restores the prior budget nor inherits + * the parent's current one; the resumed route's defaults apply instead. + * + * @module @deepseek-ai/dsh-subagent/descriptor + */ +import type { SessionEvent } from '@deepseek-ai/dsh-session'; +import type { ToolRestriction } from '@deepseek-ai/dsh-tools'; +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * Durable identity and lifecycle mode of a session-backed subagent child, + * appended once by the establishing provider inside the child's initial + * turn, before its first request. Continuable records also carry their + * resumable composition. Log-only: it carries no `surfaceOp`, never enters + * model history, and survives compaction. + */ + 'subagent/descriptor': SubagentDescriptorData; + } +} +/** + * The current descriptor format version, stamped into every appended + * `subagent/descriptor` event and required verbatim by {@link foldSubagentDescriptor}. + * Supporting another composition input is a deliberate version change, never + * an implicit extra field. + */ +export declare const SUBAGENT_DESCRIPTOR_VERSION = 2; +/** Fields shared by every supported `subagent/descriptor` payload. */ +interface SubagentDescriptorBase { + /** Descriptor format version ({@link SUBAGENT_DESCRIPTOR_VERSION}). */ + readonly version: number; + /** Whether the child is a terminal one-shot run or a resumable conversation. */ + readonly mode: 'one-shot' | 'continuable'; + /** The `ctx.subagents` provider name that established the child. */ + readonly provider: string; +} +/** A session-backed subagent that cannot be cold-resumed after its run. */ +export interface OneShotSubagentDescriptorData extends SubagentDescriptorBase { + readonly mode: 'one-shot'; + /** + * The initial delegation's short `description`, kept as the child's durable + * creation label so enumeration can identify the conversation without + * replaying parent tool results or exposing the child prompt. + */ + readonly label?: string; +} +/** A session-backed subagent whose declared composition supports cold resume. */ +export interface ContinuableSubagentDescriptorData extends SubagentDescriptorBase { + readonly mode: 'continuable'; + /** The initial delegation's short `description`, used for durable enumeration. */ + readonly label: string; + /** Resolved child `agentOptions.provider`, when one was declared. */ + readonly agentProvider?: string; + /** Resolved child `agentOptions.model`, when one was declared. */ + readonly agentModel?: string; + /** Per-child persona that shadows the deployment persona on resume. */ + readonly persona?: string; + /** Child tool scoping reapplied on resume. */ + readonly toolFilter?: ToolRestriction; +} +/** The supported durable subagent identity and optional continuation composition. */ +export type SubagentDescriptorData = OneShotSubagentDescriptorData | ContinuableSubagentDescriptorData; +/** Fields shared by descriptor snapshot inputs. */ +interface SubagentDescriptorInputBase { + /** Whether the child is a terminal one-shot run or a resumable conversation. */ + readonly mode: 'one-shot' | 'continuable'; + /** The `ctx.subagents` provider name that will establish the child. */ + readonly provider: string; +} +/** Input for a one-shot child's durable identity. */ +export interface OneShotSubagentDescriptorInput extends SubagentDescriptorInputBase { + readonly mode: 'one-shot'; + /** Optional initial delegation `description` used as the durable creation label. */ + readonly label?: string; +} +/** Input for a continuable child's durable identity and resumable composition. */ +export interface ContinuableSubagentDescriptorInput extends SubagentDescriptorInputBase { + readonly mode: 'continuable'; + /** Initial delegation `description` used for durable enumeration. */ + readonly label: string; + /** Requested child `agentOptions.provider`. */ + readonly agentProvider?: string; + /** Requested child `agentOptions.model`. */ + readonly agentModel?: string; + /** Requested per-child persona. */ + readonly persona?: string; + /** Requested child tool scoping. */ + readonly toolFilter?: ToolRestriction; +} +/** Inputs {@link snapshotSubagentDescriptor} validates and detaches. */ +export type SubagentDescriptorInput = OneShotSubagentDescriptorInput | ContinuableSubagentDescriptorInput; +/** + * Validate and detach descriptor inputs into the durable payload, before any + * Task or provider work begins — the same detached lossless-JSON boundary the + * session log itself enforces, applied early so a synchronous validation + * failure rejects the tool call without creating a Task. + * @param input - the caller-collected composition fields. + * @returns the versioned, detached descriptor payload. + * @throws when a field is not losslessly JSON-serializable. + */ +export declare function snapshotSubagentDescriptor(input: OneShotSubagentDescriptorInput): OneShotSubagentDescriptorData; +/** + * Validate and detach a continuable descriptor input. + * @param input - the caller-collected continuable composition fields. + * @returns the versioned, detached continuable descriptor payload. + * @throws when a field is not losslessly JSON-serializable. + */ +export declare function snapshotSubagentDescriptor(input: ContinuableSubagentDescriptorInput): ContinuableSubagentDescriptorData; +/** + * Fold a persisted child log to its supported descriptor. The first + * `subagent/descriptor` event is authoritative — the establishing provider + * appends exactly one, so a later same-type event cannot rewrite the declared + * composition. + * @param events - the loaded child session events. + * @returns the descriptor, or `undefined` when the log has none or its + * version is not {@link SUBAGENT_DESCRIPTOR_VERSION} (the child cannot be + * classified by this runtime). + * @throws when a current-version persisted payload does not match its complete + * declared schema. + */ +export declare function foldSubagentDescriptor(events: readonly SessionEvent[]): SubagentDescriptorData | undefined; +export {}; +//# sourceMappingURL=descriptor.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.js new file mode 100644 index 0000000..52e9081 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/descriptor.js @@ -0,0 +1,189 @@ +/** + * The durable subagent-child descriptor: the versioned, model-hidden + * `subagent/descriptor` session event that identifies every session-backed + * subagent and records whether it is one-shot or continuable. Continuable + * descriptors additionally preserve the declared composition required for + * cold resume. Providers append it turn-enclosed in the child's initial turn. + * + * The descriptor deliberately snapshots explicit fields rather than the + * merge-extensible `AgentOptions` object: an unrelated extension value cannot + * make continuation fail merely because it is not JSON, and later composition + * inputs require a deliberate {@link SUBAGENT_DESCRIPTOR_VERSION} change. It + * omits `subagentDepth` — cold resume trusts the persisted header's + * `delegationDepth` as the monotone floor — and `outputSchema`, which belongs + * to one activation's result contract rather than durable child composition. + * Per-activation knobs such as `maxTokens` are omitted for the same reason as + * `outputSchema`: they budget one activation. Cold resume requires the exact + * live parent for authorization but reconstructs child options only from the + * durable descriptor, so it neither restores the prior budget nor inherits + * the parent's current one; the resumed route's defaults apply instead. + * + * @module @deepseek-ai/dsh-subagent/descriptor + */ +import { snapshotJsonValue } from '@deepseek-ai/dsh-session'; +/** + * The current descriptor format version, stamped into every appended + * `subagent/descriptor` event and required verbatim by {@link foldSubagentDescriptor}. + * Supporting another composition input is a deliberate version change, never + * an implicit extra field. + */ +export const SUBAGENT_DESCRIPTOR_VERSION = 2; +const DESCRIPTOR_BASE_KEYS = [ + 'version', + 'mode', + 'provider', + 'label', +]; +const ONE_SHOT_DESCRIPTOR_KEYS = new Set(DESCRIPTOR_BASE_KEYS); +const CONTINUABLE_DESCRIPTOR_KEYS = new Set([ + ...DESCRIPTOR_BASE_KEYS, + 'agentProvider', + 'agentModel', + 'persona', + 'toolFilter', +]); +const TOOL_FILTER_KEYS = new Set(['allow', 'deny']); +/** Whether a persisted JSON value is an object record. */ +function isRecord(value) { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} +/** Reject fields outside one versioned record's declared schema. */ +function assertKnownKeys(value, keys, path) { + const unknown = Object.keys(value).find(key => !keys.has(key)); + if (unknown !== undefined) { + throw new Error(`persisted subagent descriptor ${path} has unknown field "${unknown}"`); + } +} +/** Read one optional string field from a persisted descriptor record. */ +function optionalString(value, key) { + if (!Object.hasOwn(value, key)) + return undefined; + const field = value[key]; + if (typeof field !== 'string') { + throw new Error(`persisted subagent descriptor ${key} must be a string`); + } + return field; +} +/** Read one optional string-array field from a persisted tool restriction. */ +function optionalStringArray(value, key) { + if (!Object.hasOwn(value, key)) + return undefined; + const field = value[key]; + if (!Array.isArray(field)) { + throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`); + } + const items = field; + if (items.some(item => typeof item !== 'string')) { + throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`); + } + return items; +} +/** Validate and reconstruct a persisted tool restriction. */ +function parseToolFilter(value) { + if (!isRecord(value)) { + throw new Error('persisted subagent descriptor toolFilter must be an object'); + } + assertKnownKeys(value, TOOL_FILTER_KEYS, 'toolFilter'); + const allow = optionalStringArray(value, 'allow'); + const deny = optionalStringArray(value, 'deny'); + if (allow === undefined && deny === undefined) { + throw new Error('persisted subagent descriptor toolFilter must declare allow and/or deny'); + } + return { + ...allow !== undefined ? { allow } : {}, + ...deny !== undefined ? { deny } : {}, + }; +} +/** Validate one persisted descriptor payload for the current runtime. */ +function parseSubagentDescriptor(value) { + if (!isRecord(value)) { + throw new Error('persisted subagent descriptor payload must be an object'); + } + const version = value['version']; + if (typeof version !== 'number') { + throw new Error('persisted subagent descriptor version must be a number'); + } + if (version !== SUBAGENT_DESCRIPTOR_VERSION) + return undefined; + const mode = value['mode']; + if (mode !== 'one-shot' && mode !== 'continuable') { + throw new Error('persisted subagent descriptor mode must be "one-shot" or "continuable"'); + } + assertKnownKeys(value, mode === 'one-shot' ? ONE_SHOT_DESCRIPTOR_KEYS : CONTINUABLE_DESCRIPTOR_KEYS, 'payload'); + const provider = value['provider']; + if (typeof provider !== 'string') { + throw new Error('persisted subagent descriptor provider must be a string'); + } + if (mode === 'one-shot') { + const label = optionalString(value, 'label'); + return { + version: SUBAGENT_DESCRIPTOR_VERSION, + mode, + provider, + ...label !== undefined ? { label } : {}, + }; + } + const label = value['label']; + if (typeof label !== 'string') { + throw new Error('persisted subagent descriptor label must be a string'); + } + const agentProvider = optionalString(value, 'agentProvider'); + const agentModel = optionalString(value, 'agentModel'); + const persona = optionalString(value, 'persona'); + const toolFilter = Object.hasOwn(value, 'toolFilter') + ? parseToolFilter(value['toolFilter']) + : undefined; + return { + version: SUBAGENT_DESCRIPTOR_VERSION, + mode, + provider, + label, + ...agentProvider !== undefined ? { agentProvider } : {}, + ...agentModel !== undefined ? { agentModel } : {}, + ...persona !== undefined ? { persona } : {}, + ...toolFilter !== undefined ? { toolFilter } : {}, + }; +} +export function snapshotSubagentDescriptor(input) { + const candidate = input.mode === 'one-shot' + ? { + version: SUBAGENT_DESCRIPTOR_VERSION, + mode: input.mode, + provider: input.provider, + ...input.label !== undefined ? { label: input.label } : {}, + } + : { + version: SUBAGENT_DESCRIPTOR_VERSION, + mode: input.mode, + provider: input.provider, + label: input.label, + ...input.agentProvider !== undefined ? { agentProvider: input.agentProvider } : {}, + ...input.agentModel !== undefined ? { agentModel: input.agentModel } : {}, + ...input.persona !== undefined ? { persona: input.persona } : {}, + ...input.toolFilter !== undefined ? { toolFilter: input.toolFilter } : {}, + }; + const snapshot = snapshotJsonValue(candidate); + if (snapshot === undefined) { + throw new Error('subagent descriptor is not losslessly JSON-serializable'); + } + return snapshot; +} +/** + * Fold a persisted child log to its supported descriptor. The first + * `subagent/descriptor` event is authoritative — the establishing provider + * appends exactly one, so a later same-type event cannot rewrite the declared + * composition. + * @param events - the loaded child session events. + * @returns the descriptor, or `undefined` when the log has none or its + * version is not {@link SUBAGENT_DESCRIPTOR_VERSION} (the child cannot be + * classified by this runtime). + * @throws when a current-version persisted payload does not match its complete + * declared schema. + */ +export function foldSubagentDescriptor(events) { + const event = events.find((candidate) => candidate.type === 'subagent/descriptor'); + if (event === undefined) + return undefined; + return parseSubagentDescriptor(event.data); +} +//# sourceMappingURL=descriptor.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.d.ts new file mode 100644 index 0000000..0be7ce3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.d.ts @@ -0,0 +1,11 @@ +/** + * Typed failures shared by subagent service and provider operations. + * + * @module @deepseek-ai/dsh-subagent + */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +/** Typed failure for the subagent seam. */ +export declare class SubagentError extends HarnessError { + constructor(message: string, code: string, options?: ErrorOptions); +} +//# sourceMappingURL=error.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.js new file mode 100644 index 0000000..2ba567e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/error.js @@ -0,0 +1,14 @@ +/** + * Typed failures shared by subagent service and provider operations. + * + * @module @deepseek-ai/dsh-subagent + */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +/** Typed failure for the subagent seam. */ +export class SubagentError extends HarnessError { + constructor(message, code, options) { + super(message, code, options); + this.name = 'SubagentError'; + } +} +//# sourceMappingURL=error.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.d.ts new file mode 100644 index 0000000..62b5cad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.d.ts @@ -0,0 +1,279 @@ +/** + * Service Definition for the subagent capability seam (`ctx.subagents`): a named-provider registry plus a + * capability-validating asynchronous start API. Providers establish a + * child before returning its run, so fulfillment is the single publication and + * ownership-transfer boundary. + * + * Unlike the bash seam (one executor per context, second load throws), MULTIPLE + * providers coexist here: each registers under a unique name and a caller picks + * one by name. The shape mirrors the LLM adapter registry + * (`LlmRuntime.registerAdapter`), not the single-service bash executor. + * + * This package owns the Service Definition role of the capability seam. Service Providers + * (`@deepseek-ai/dsh-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing + * consumer (`@deepseek-ai/dsh-tool-subagent`) are separate packages. + * + * Public operations express caller intent: `start` returns one published owned + * one-shot run, `startContinuable` establishes a durable continuable child, and + * `followup` delivers later content without exposing whether the child is + * resident. Continuable children never become a {@link SubagentRun}: the + * continuation manager holds their `AgentHandle` directly and orders every turn + * through the child's own inbox, so providers contribute only the detached + * creation spec and see no handle, turn, or teardown. Child and descendant + * discovery read the live session store and optional session persistence + * directly and do not require that continuation runtime. + * + * Same-process providers are trusted typed collaborators. Requests, provider + * descriptors, results, and lifecycle payloads are borrowed immutable values; + * serialization and hostile-input validation belong at real process, worker, + * persistence, and model boundaries. + * + * @module @deepseek-ai/dsh-subagent + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { Scoped } from '@deepseek-ai/dsh-scope'; +import type { ContentBlock, MessageId } from '@deepseek-ai/dsh-llm'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +import type { SubagentProvider, SubagentRun, SubagentRunEndInfo, SubagentRunInfo, SubagentStartRequest } from './types.ts'; +import type { ContinuableStart, ContinuableStartSpec, SubagentFollowupOptions, SubagentInterruptAuthority, SubagentReportOptions } from './continuation.ts'; +import type { ContinuableSetupContribution } from './activation-setup-registry.ts'; +import type { SubagentDescendantListEntry, SubagentListEntry } from './list-children.ts'; +export * from './out-of-process.ts'; +export { AssistantOutputFold, finalAssistantOutput } from './assistant-output.ts'; +export { SubagentRunId } from './types.ts'; +export type { ContinuableCreateRequest, ContinuableCreateSpec, ResolvedSubagentStartRequest, SubagentCapabilities, SubagentProvider, SubagentResult, SubagentRun, SubagentStartRequest, SubagentStopReason, SubagentStopReasonMap, } from './types.ts'; +export { foldSubagentDescriptor, snapshotSubagentDescriptor, SUBAGENT_DESCRIPTOR_VERSION, } from './descriptor.ts'; +export type { ContinuableSubagentDescriptorData, ContinuableSubagentDescriptorInput, OneShotSubagentDescriptorData, OneShotSubagentDescriptorInput, SubagentDescriptorData, SubagentDescriptorInput, } from './descriptor.ts'; +export { seedDescriptorTurn } from './descriptor-seed.ts'; +export { SubagentError } from './error.ts'; +export { settleRun } from './run-settlement.ts'; +export { assertSubagentMaxDepth, delegationDepthOf } from './depth.ts'; +export { appendDelegatedPolicyOverrides, applyChildComposition, captureDelegatedPolicyOverrides, childSessionMeta, resolveChildAgentOptions, resolveChildDepth, SubagentDepthError, } from './child-agent.ts'; +export type { ChildComposition, DelegatedPolicyOverrides } from './child-agent.ts'; +export type { ContinuableStart, ContinuableStartSpec, CoordinatorMessageSource, SubagentFollowupOptions, SubagentInterruptAuthority, SubagentReportDelivery, SubagentReportMessageSource, SubagentReportOptions, SubagentSettledMessageSource, } from './continuation.ts'; +export type { ContinuableSetupContribution } from './activation-setup-registry.ts'; +export type { SubagentDescendantListEntry, SubagentListEntry } from './list-children.ts'; +export type { SubagentRunEndInfo, SubagentRunInfo } from './types.ts'; +export type { SubagentIdentityProjection, SubagentTimingProjection } from './projection-types.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + subagents: SubagentRuntime; + } + interface Events { + /** + * A provider became resolvable in the registry. + * @param provider - the registered provider. + * @mode emit + */ + 'subagent/provider-added'(provider: SubagentProvider): void; + /** + * A provider left the registry. Accepted runs remain holder-owned. + * @param name - the provider name that no longer resolves. + * @mode emit + */ + 'subagent/provider-removed'(name: string): void; + /** + * A provider established a published child. For in-process providers, + * `ctx.agents.get(info.id)` resolves during this notification. + * Scope-filtered dispatch keys the carrier by the delegating parent, so a + * parent-scoped listener observes only its own delegations. Paired with + * `subagent/end`. + * @param info - the provider and published child identity. + * @dshScopeScan unsupported + * @mode emit + */ + 'subagent/start'(this: Scoped, info: SubagentRunInfo): void; + /** + * A published child settled. Scope-filtered dispatch uses the same delegating + * parent carrier as `subagent/start`, so the lifecycle pair reaches the + * same scoped audience. + * @param info - the run identity and terminal outcome. + * @dshScopeScan unsupported + * @mode emit + */ + 'subagent/end'(this: Scoped, info: SubagentRunEndInfo): void; + } +} +/** Named provider registry with one-shot runs, durable discovery, and continuable-child operations. */ +export declare class SubagentRuntime extends Service { + private providers; + private continuations; + /** Deployment contributions composed into unpublished continuable children. */ + private readonly setupRegistry; + /** + * The contained lifecycle-edge publisher. Built here because scoped dispatch + * keys its carrier by this exact service instance, whose own context filter + * composes into the carrier. + */ + private readonly emitLifecycle; + constructor(ctx: Context); + /** + * Establish one durable continuable child and deliver its initial prompt. + * Resolves when the child's inbox accepts that prompt, without waiting for the + * turn to start or for the message to reach the Session log; any earlier + * failure rejects with no ids and rolls back the child entirely. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted prompt's message id. + * @throws when continuation services are unavailable or materialization fails. + */ + startContinuable(spec: ContinuableStartSpec): Promise; + /** + * Deliver one later message to a continuable child as its next FIFO turn. A + * resident child's Agent inbox accepts it directly (waking a `waiting` + * Activation), while an absent one is cold-resumed from its persisted + * Session. The Agent inbox is the only queue, so every accepted message has + * one observable order. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - durable child session id. + * @param content - user-role content to deliver. + * @param options - the message source fields and caller cancellation, which stops the + * operation only before inbox acceptance. + * @returns the accepted message's inbox id. + * @throws when continuation services are unavailable, parent authority is + * rejected, or the message was not admitted. + */ + followup(parent: Agent, childId: SessionId, content: ContentBlock[], options: SubagentFollowupOptions): Promise; + /** + * Interrupt one live continuable child's current turn under a human parent + * address or an exact live ancestor Agent. Fire-and-return: the cancel + * signal is issued before this returns, but the target may keep running + * until it observes the signal. Unclaimed pending inbox work, the Activation, + * and published descendants are preserved; claimed work is not requeued. + * Once the interrupted driver is idle, a waking send resumes the parked FIFO + * queue. An absent target — including a one-shot or unknown id — + * is an accepted no-op, as is a manager-less composition, which cannot own a + * live Activation. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the authority does not own the + * live target. + */ + interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void; + /** + * Deliver selected content from one live continuable child to its durable + * direct parent. The child is the authority credential; callers cannot name a + * recipient. Reporting does not conclude the child's turn or Activation. + * @param child - exact live reporting child. + * @param content - selected model-facing content. + * @param options - parent scheduling and pre-acceptance cancellation. + * @returns the stable identity of the parent-accepted message. + * @throws when continuation services are unavailable, sender authorization + * fails, or the direct parent is not live. + */ + reportFrom(child: Agent, content: ContentBlock[], options: SubagentReportOptions): Promise; + /** + * Compose one deployment capability into every continuable child's + * unpublished creation context on fresh creation and cold resume. Grants wait + * for the next Activation; removing the contribution revokes every resident + * installation immediately. + * @param contribution - synchronous child-scope installer. + * @returns the exact Cordis effect disposer. + */ + registerContinuableSetup(contribution: ContinuableSetupContribution): () => void; + /** + * Close continuable admission below exact live parent Agents, stop only their + * visible descendant Activations synchronously, then await admitted scoped + * materializations and release those forests child-first. The scoped cutoff + * lasts until each exact parent leaves the registry; unrelated parent trees + * remain live. + * @param parents - exact host-owned parent Agents entering teardown. + * @returns once every retained descendant Activation released its `AgentHandle`. + * @throws an aggregate error after all branches settle when any failed. + */ + drainContinuableDescendants(parents: readonly Agent[]): Promise; + /** + * Enumerate the parent's direct session-backed subagents without loading or + * resuming an Agent and without any query service: the listing merges the live + * session store with optional session persistence (live-preferred) and + * serves each child's durable mode/label from the registered `subagent` + * projection unit down a three-rung ladder — the registry's watermark + * snapshot for a live child; for a cold one, a durable projection-cache + * row when the optional cache serves an own-suffix identity (its `seq` + * gate proves the value postdates the fork seed, where a child's own + * descriptor is immutable once appended), else one persistence inspection + * folded through the registry. The + * projection fold is the single classification authority; per-child + * diagnostics relay a fold that served no identity or a failed inspection, + * never a list-time descriptor parse. Absent persistence, enumeration is + * live-only (a cold child cannot be resumed then either, so its absence is + * capability absence, not an error). This service consults no Agent + * registrations, Activations, or providers. + * + * Every persistence read receives `signal`, and the listing rechecks + * cancellation around each of those awaits. Read rejections that settle + * after an abort become a stable `SubagentError` with code `CANCELLED`. + * @param parentSessionId - parent session whose direct children are listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-child diagnostics ordered by `createdAt`, then id. + * @throws {@link SubagentError} when the projection registry or the session + * store is not mounted, or the caller cancels the listing. + */ + listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Enumerate the root's complete session-backed subagent tree in stable + * pre-order from one live-preferred corpus, without loading or resuming an + * Agent. Ordinary sessions and one-shot children remain traversal nodes so + * continuable descendants below them are discovered; each returned entry + * adds its durable `parentId` and root-relative `depth`. Identity resolution, + * diagnostics, optional persistence, and cancellation follow the same + * projection-backed contract as {@link listChildren}. + * @param rootSessionId - session whose complete descendant tree is listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-candidate diagnostics with tree position, in + * stable pre-order. + * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + */ + listDescendants(rootSessionId: SessionId, signal?: AbortSignal): Promise; + /** + * Register a provider under its name. Registration is effect-scoped and HMR + * safe; removing a provider blocks new starts but does not revoke runs that + * were already returned to their holders. + * @param provider - the trusted provider implementation. + * @returns the exact Cordis effect disposer. + */ + registerProvider(provider: SubagentProvider): () => void; + /** + * Look up a provider by name. + * @param name - the provider name. + * @returns the provider, or undefined when absent. + */ + getProvider(name: string): SubagentProvider | undefined; + /** + * List registered provider names in insertion order. + * @returns the registered names. + */ + list(): string[]; + /** + * Establish a published child on the named provider. Capability and semantic + * checks run before delegation. Provider ownership lasts until its promise + * fulfills; a rejection therefore has no run for the caller to dispose and + * emits no run lifecycle events. Post-publication turn and infrastructure + * failures settle through the returned run. + * @param name - the provider to use. + * @param request - child label, prompt, parent, signal, and optional capabilities. + * @returns the published holder-owned run. + */ + start(name: string, request: SubagentStartRequest): Promise; + /** + * Resolve one provider's detached continuable-creation contribution. Method + * presence on the provider IS the capability, so a provider without it is + * rejected before the manager reserves any child resources. + */ + private prepareContinuable; + /** Look up a provider for dispatch or fail loud. */ + private expectProvider; + /** Resolve the optional continuable-subagent manager or fail loud. */ + private requireContinuations; + /** + * Build the lifecycle observer for one continuable Activation's residency + * epoch, so the manager publishes its edges without owning event dispatch. + */ + private observeActivation; + /** Reject the first requested capability that the provider lacks. */ + private assertCapabilities; +} +export default SubagentRuntime; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.js new file mode 100644 index 0000000..e61f852 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/index.js @@ -0,0 +1,339 @@ +/** + * Service Definition for the subagent capability seam (`ctx.subagents`): a named-provider registry plus a + * capability-validating asynchronous start API. Providers establish a + * child before returning its run, so fulfillment is the single publication and + * ownership-transfer boundary. + * + * Unlike the bash seam (one executor per context, second load throws), MULTIPLE + * providers coexist here: each registers under a unique name and a caller picks + * one by name. The shape mirrors the LLM adapter registry + * (`LlmRuntime.registerAdapter`), not the single-service bash executor. + * + * This package owns the Service Definition role of the capability seam. Service Providers + * (`@deepseek-ai/dsh-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing + * consumer (`@deepseek-ai/dsh-tool-subagent`) are separate packages. + * + * Public operations express caller intent: `start` returns one published owned + * one-shot run, `startContinuable` establishes a durable continuable child, and + * `followup` delivers later content without exposing whether the child is + * resident. Continuable children never become a {@link SubagentRun}: the + * continuation manager holds their `AgentHandle` directly and orders every turn + * through the child's own inbox, so providers contribute only the detached + * creation spec and see no handle, turn, or teardown. Child and descendant + * discovery read the live session store and optional session persistence + * directly and do not require that continuation runtime. + * + * Same-process providers are trusted typed collaborators. Requests, provider + * descriptors, results, and lifecycle payloads are borrowed immutable values; + * serialization and hostile-input validation belong at real process, worker, + * persistence, and model boundaries. + * + * @module @deepseek-ai/dsh-subagent + */ +import { Service } from '@deepseek-ai/cordis'; +import { scopeTarget } from '@deepseek-ai/dsh-scope'; +import { assertObjectJsonSchema } from '@deepseek-ai/dsh-tools'; +import { SubagentError } from "./error.js"; +import { assertSubagentMaxDepth } from "./depth.js"; +import { createActivationObserver, createLifecycleEmitter, observeRun } from "./lifecycle.js"; +import SubagentContinuationManager from "./continuation.js"; +import SubagentActivationSetupRegistry from "./activation-setup-registry.js"; +import { listChildren as listSubagentChildren, listDescendants as listSubagentDescendants } from "./list-children.js"; +import { snapshotSubagentDescriptor } from "./descriptor.js"; +import { subagentIdentityProjectionDefinition, subagentTimingProjectionDefinition } from "./projection.js"; +export * from "./out-of-process.js"; +export { AssistantOutputFold, finalAssistantOutput } from "./assistant-output.js"; +export { SubagentRunId } from "./types.js"; +export { foldSubagentDescriptor, snapshotSubagentDescriptor, SUBAGENT_DESCRIPTOR_VERSION, } from "./descriptor.js"; +export { seedDescriptorTurn } from "./descriptor-seed.js"; +export { SubagentError } from "./error.js"; +export { settleRun } from "./run-settlement.js"; +export { assertSubagentMaxDepth, delegationDepthOf } from "./depth.js"; +export { appendDelegatedPolicyOverrides, applyChildComposition, captureDelegatedPolicyOverrides, childSessionMeta, resolveChildAgentOptions, resolveChildDepth, SubagentDepthError, } from "./child-agent.js"; +/** Named provider registry with one-shot runs, durable discovery, and continuable-child operations. */ +export class SubagentRuntime extends Service { + providers = new Map(); + continuations; + /** Deployment contributions composed into unpublished continuable children. */ + setupRegistry = new SubagentActivationSetupRegistry(); + /** + * The contained lifecycle-edge publisher. Built here because scoped dispatch + * keys its carrier by this exact service instance, whose own context filter + * composes into the carrier. + */ + emitLifecycle; + constructor(ctx) { + super(ctx, 'subagents'); + this.emitLifecycle = createLifecycleEmitter(this.ctx, parent => scopeTarget(this, parent)); + ctx.inject(['agents'], (childCtx) => { + const manager = new SubagentContinuationManager(childCtx, { + prepareContinuable: (name, request) => this.prepareContinuable(name, request), + observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent), + }, this.setupRegistry); + this.continuations = manager; + childCtx.effect(() => () => { + /* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */ + if (this.continuations === manager) + this.continuations = undefined; + }, 'subagents.continuationBinding()'); + }); + ctx.inject(['sessionProjections'], (projectionCtx) => { + projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition); + projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition); + }); + } + /** + * Establish one durable continuable child and deliver its initial prompt. + * Resolves when the child's inbox accepts that prompt, without waiting for the + * turn to start or for the message to reach the Session log; any earlier + * failure rejects with no ids and rolls back the child entirely. + * @param spec - provider, delegation request, and caller cancellation. + * @returns the durable child id and the accepted prompt's message id. + * @throws when continuation services are unavailable or materialization fails. + */ + async startContinuable(spec) { + return this.requireContinuations().startContinuable(spec); + } + /** + * Deliver one later message to a continuable child as its next FIFO turn. A + * resident child's Agent inbox accepts it directly (waking a `waiting` + * Activation), while an absent one is cold-resumed from its persisted + * Session. The Agent inbox is the only queue, so every accepted message has + * one observable order. + * @param parent - the exact live direct parent authorizing this delivery. + * @param childId - durable child session id. + * @param content - user-role content to deliver. + * @param options - the message source fields and caller cancellation, which stops the + * operation only before inbox acceptance. + * @returns the accepted message's inbox id. + * @throws when continuation services are unavailable, parent authority is + * rejected, or the message was not admitted. + */ + async followup(parent, childId, content, options) { + return this.requireContinuations().followup(parent, childId, content, options); + } + /** + * Interrupt one live continuable child's current turn under a human parent + * address or an exact live ancestor Agent. Fire-and-return: the cancel + * signal is issued before this returns, but the target may keep running + * until it observes the signal. Unclaimed pending inbox work, the Activation, + * and published descendants are preserved; claimed work is not requeued. + * Once the interrupted driver is idle, a waking send resumes the parked FIFO + * queue. An absent target — including a one-shot or unknown id — + * is an accepted no-op, as is a manager-less composition, which cannot own a + * live Activation. + * @param targetSessionId - the durable child session id to interrupt. + * @param authority - the human parent address or exact live ancestor Agent. + * @throws {SubagentError} `UNAUTHORIZED` when the authority does not own the + * live target. + */ + interrupt(targetSessionId, authority) { + this.continuations?.interrupt(targetSessionId, authority); + } + /** + * Deliver selected content from one live continuable child to its durable + * direct parent. The child is the authority credential; callers cannot name a + * recipient. Reporting does not conclude the child's turn or Activation. + * @param child - exact live reporting child. + * @param content - selected model-facing content. + * @param options - parent scheduling and pre-acceptance cancellation. + * @returns the stable identity of the parent-accepted message. + * @throws when continuation services are unavailable, sender authorization + * fails, or the direct parent is not live. + */ + async reportFrom(child, content, options) { + return this.requireContinuations().reportFrom(child, content, options); + } + /** + * Compose one deployment capability into every continuable child's + * unpublished creation context on fresh creation and cold resume. Grants wait + * for the next Activation; removing the contribution revokes every resident + * installation immediately. + * @param contribution - synchronous child-scope installer. + * @returns the exact Cordis effect disposer. + */ + registerContinuableSetup(contribution) { + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity + return this.ctx.effect(() => this.setupRegistry.register(contribution), 'subagents.registerContinuableSetup()'); + } + /** + * Close continuable admission below exact live parent Agents, stop only their + * visible descendant Activations synchronously, then await admitted scoped + * materializations and release those forests child-first. The scoped cutoff + * lasts until each exact parent leaves the registry; unrelated parent trees + * remain live. + * @param parents - exact host-owned parent Agents entering teardown. + * @returns once every retained descendant Activation released its `AgentHandle`. + * @throws an aggregate error after all branches settle when any failed. + */ + async drainContinuableDescendants(parents) { + const manager = this.continuations; + // Absent continuation services means nothing was ever materialized. + if (manager === undefined) + return; + await manager.drainDescendants(parents); + } + /** + * Enumerate the parent's direct session-backed subagents without loading or + * resuming an Agent and without any query service: the listing merges the live + * session store with optional session persistence (live-preferred) and + * serves each child's durable mode/label from the registered `subagent` + * projection unit down a three-rung ladder — the registry's watermark + * snapshot for a live child; for a cold one, a durable projection-cache + * row when the optional cache serves an own-suffix identity (its `seq` + * gate proves the value postdates the fork seed, where a child's own + * descriptor is immutable once appended), else one persistence inspection + * folded through the registry. The + * projection fold is the single classification authority; per-child + * diagnostics relay a fold that served no identity or a failed inspection, + * never a list-time descriptor parse. Absent persistence, enumeration is + * live-only (a cold child cannot be resumed then either, so its absence is + * capability absence, not an error). This service consults no Agent + * registrations, Activations, or providers. + * + * Every persistence read receives `signal`, and the listing rechecks + * cancellation around each of those awaits. Read rejections that settle + * after an abort become a stable `SubagentError` with code `CANCELLED`. + * @param parentSessionId - parent session whose direct children are listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-child diagnostics ordered by `createdAt`, then id. + * @throws {@link SubagentError} when the projection registry or the session + * store is not mounted, or the caller cancels the listing. + */ + listChildren(parentSessionId, signal) { + return listSubagentChildren(this.ctx, parentSessionId, signal); + } + /** + * Enumerate the root's complete session-backed subagent tree in stable + * pre-order from one live-preferred corpus, without loading or resuming an + * Agent. Ordinary sessions and one-shot children remain traversal nodes so + * continuable descendants below them are discovered; each returned entry + * adds its durable `parentId` and root-relative `depth`. Identity resolution, + * diagnostics, optional persistence, and cancellation follow the same + * projection-backed contract as {@link listChildren}. + * @param rootSessionId - session whose complete descendant tree is listed. + * @param signal - caller-owned cancellation forwarded to persistence reads + * and observed around every read await. + * @returns children and per-candidate diagnostics with tree position, in + * stable pre-order. + * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + */ + listDescendants(rootSessionId, signal) { + return listSubagentDescendants(this.ctx, rootSessionId, signal); + } + /** + * Register a provider under its name. Registration is effect-scoped and HMR + * safe; removing a provider blocks new starts but does not revoke runs that + * were already returned to their holders. + * @param provider - the trusted provider implementation. + * @returns the exact Cordis effect disposer. + */ + registerProvider(provider) { + const name = provider.name; + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity + return this.ctx.effect(function* () { + if (this.providers.has(name)) { + throw new SubagentError(`a subagent provider named "${name}" is already registered`, 'DUPLICATE_PROVIDER'); + } + this.providers.set(name, provider); + yield () => { + this.providers.delete(name); + this.emitLifecycle('subagent/provider-removed', name); + }; + // A throwing added-listener unwinds the yielded rollback, matching the + // repository's fail-loud registration semantics. + this.ctx.emit('subagent/provider-added', provider); + }.bind(this), 'subagents.registerProvider()'); + } + /** + * Look up a provider by name. + * @param name - the provider name. + * @returns the provider, or undefined when absent. + */ + getProvider(name) { + return this.providers.get(name); + } + /** + * List registered provider names in insertion order. + * @returns the registered names. + */ + list() { + return [...this.providers.keys()]; + } + /** + * Establish a published child on the named provider. Capability and semantic + * checks run before delegation. Provider ownership lasts until its promise + * fulfills; a rejection therefore has no run for the caller to dispose and + * emits no run lifecycle events. Post-publication turn and infrastructure + * failures settle through the returned run. + * @param name - the provider to use. + * @param request - child label, prompt, parent, signal, and optional capabilities. + * @returns the published holder-owned run. + */ + async start(name, request) { + const provider = this.expectProvider(name); + this.assertCapabilities(provider, request); + assertSubagentMaxDepth(request.maxDepth); + if (request.outputSchema !== undefined) + assertObjectJsonSchema(request.outputSchema); + const descriptor = snapshotSubagentDescriptor({ + mode: 'one-shot', + provider: name, + ...request.label !== undefined ? { label: request.label } : {}, + }); + const resolved = { ...request, descriptor }; + return observeRun(this.emitLifecycle, name, request.parent, await provider.start(resolved)); + } + /** + * Resolve one provider's detached continuable-creation contribution. Method + * presence on the provider IS the capability, so a provider without it is + * rejected before the manager reserves any child resources. + */ + async prepareContinuable(name, request) { + const provider = this.expectProvider(name); + if (provider.prepareContinuable === undefined) { + throw new SubagentError(`subagent provider "${provider.name}" does not support continuable children ` + + '(no prepareContinuable capability)', 'UNSUPPORTED_CAPABILITY'); + } + return provider.prepareContinuable(request); + } + /** Look up a provider for dispatch or fail loud. */ + expectProvider(name) { + const provider = this.providers.get(name); + if (provider === undefined) { + throw new SubagentError(`no subagent provider registered for "${name}"`, 'NO_PROVIDER'); + } + return provider; + } + /** Resolve the optional continuable-subagent manager or fail loud. */ + requireContinuations() { + if (this.continuations === undefined) { + throw new SubagentError('continuable subagents require the agents service', 'CONTINUATION_UNAVAILABLE'); + } + return this.continuations; + } + /** + * Build the lifecycle observer for one continuable Activation's residency + * epoch, so the manager publishes its edges without owning event dispatch. + */ + observeActivation(provider, childId, parent) { + return createActivationObserver(this.emitLifecycle, provider, childId, parent); + } + /** Reject the first requested capability that the provider lacks. */ + assertCapabilities(provider, request) { + const needs = [ + { when: request.outputSchema !== undefined, cap: 'outputSchema' }, + { when: request.maxDepth !== undefined, cap: 'depthLimit' }, + { when: request.toolFilter !== undefined, cap: 'toolFilter' }, + { when: request.persona !== undefined, cap: 'persona' }, + ]; + for (const { when, cap } of needs) { + if (when && !provider.capabilities[cap]) { + throw new SubagentError(`subagent provider "${provider.name}" does not support the "${cap}" capability`, 'UNSUPPORTED_CAPABILITY'); + } + } + } +} +export default SubagentRuntime; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.d.ts new file mode 100644 index 0000000..7dda58d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned subagent registry and lifecycle invariants. @module @deepseek-ai/dsh-subagent/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "subagent-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the subagent invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.js new file mode 100644 index 0000000..41c0014 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/invariant.js @@ -0,0 +1,91 @@ +/** Package-owned subagent registry and lifecycle invariants. @module @deepseek-ai/dsh-subagent/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-subagent'; +/** Cordis companion plugin name. */ +export const name = 'subagent-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Assert that a terminal lifecycle payload matches its start identity. */ +function validateRunEnd(start, end, fail) { + if (start.provider !== end.provider || start.id !== end.id || start.local !== end.local) { + fail(`subagent/end identity diverges from subagent/start for run ${JSON.stringify(end.runId)}`); + } +} +/** Install provider-registry and start/end pairing checks. */ +const install = Object.assign((ctx, fail) => { + const providers = new Set(ctx.subagents.list()); + const runs = new Map(); + const stagedProviders = new WeakSet(); + const stagedRemovals = new Set(); + const stagedStarts = new WeakSet(); + const stagedEnds = new WeakSet(); + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName === 'subagent/provider-added') { + const provider = args[0]; + if (provider.name.length === 0) + fail('subagent provider names must be non-empty'); + if (providers.has(provider.name)) + fail(`subagent/provider-added repeated ${JSON.stringify(provider.name)}`); + stagedProviders.add(provider); + return; + } + if (eventName === 'subagent/provider-removed') { + const providerName = args[0]; + if (!providers.has(providerName)) + fail(`subagent/provider-removed names unknown provider ${JSON.stringify(providerName)}`); + stagedRemovals.add(providerName); + return; + } + if (eventName === 'subagent/start') { + const info = args[0]; + // Provider availability is an admission-time relationship. A published + // one-shot run may outlive provider removal, and a cold-resumed Activation + // records the initial provider name without dispatching through it. + if (info.provider.length === 0 || String(info.runId).length === 0 || String(info.id).length === 0) { + fail('subagent/start provider, runId, and child id must be non-empty'); + } + if (runs.has(info.runId)) + fail(`subagent/start repeated run id ${JSON.stringify(info.runId)}`); + stagedStarts.add(info); + return; + } + if (eventName !== 'subagent/end') + return; + const info = args[0]; + const start = runs.get(info.runId); + if (start === undefined) + fail(`subagent/end has no matching subagent/start for run ${JSON.stringify(info.runId)}`); + validateRunEnd(start, info, fail); + stagedEnds.add(info); + }, { global: true }); + ctx.on('subagent/provider-added', (provider) => { + /* v8 ignore next -- internal/dispatch stages the same provider object */ + if (!stagedProviders.delete(provider)) + return; + providers.add(provider.name); + }, { global: true }); + ctx.on('subagent/provider-removed', (providerName) => { + /* v8 ignore next -- internal/dispatch stages the same provider name */ + if (!stagedRemovals.delete(providerName)) + return; + providers.delete(providerName); + }, { global: true }); + ctx.on('subagent/start', (info) => { + /* v8 ignore next -- internal/dispatch stages the same lifecycle object */ + if (!stagedStarts.delete(info)) + return; + runs.set(info.runId, info); + }, { global: true }); + ctx.on('subagent/end', (info) => { + /* v8 ignore next -- internal/dispatch stages the same lifecycle object */ + if (!stagedEnds.delete(info)) + return; + runs.delete(info.runId); + }, { global: true }); +}, { inject: ['subagents'] }); +/** + * Register the subagent invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.d.ts new file mode 100644 index 0000000..9d63a61 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.d.ts @@ -0,0 +1,113 @@ +/** + * Lifecycle-edge publication for both subagent shapes: the contained emitter, + * the one-shot run observer, and the continuable Activation observer. + * + * The public payload contracts ({@link SubagentRunInfo}, + * {@link SubagentRunEndInfo}) live in `./types.ts` with the rest of the seam's + * consumer-facing types; this module owns only the implementation and the + * package-private {@link ActivationObserver} the continuation manager consumes. + * Keeping the internal control interface out of the published surface is + * deliberate: the observer's `start`/`capture`/`settle` ordering is a contract + * between this module and one in-package caller, not something a plugin may + * depend on. + * + * @module @deepseek-ai/dsh-subagent/lifecycle + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +import type { SubagentResult, SubagentRun, SubagentRunEndInfo, SubagentRunInfo } from './types.ts'; +/** + * How one Activation's residency epoch ended, as both the terminal lifecycle + * edge and the manager's own parent delivery report it. + */ +export interface ActivationTerminal { + /** Why this epoch's last ordinary turn ended, or `error` when teardown failed. */ + readonly stopReason: SubagentResult['stopReason']; + /** The epoch's final assistant content, absent when it produced none or failed. */ + readonly output?: ContentBlock[]; +} +/** + * Lifecycle observer for one Activation's residency epoch, so continuable + * children emit the same start/end pair as one-shot runs. Package-private: the + * continuation manager is the only consumer, and its call ordering is an + * in-package contract rather than a published extension point. + */ +export interface ActivationObserver { + /** + * Publish the start edge once the epoch is resident. + * @param child - the resident child agent, whose log suffix bounds this epoch. + */ + start(child: Agent): void; + /** + * Snapshot the child-dependent terminal facts while the child is still + * registered, because handle disposal unregisters it and consumers resolve it + * to read the child's own log and scope. + * @param child - the quiescent child agent about to be released. + */ + capture(child: Agent): void; + /** + * Resolve the terminal facts {@link settle} will publish, without publishing + * them. The manager's parent delivery must run before the ownership release + * that lets the parent settle, which is earlier than the terminal edge; both + * therefore read one computation instead of restating the failure rule. + * @param failure - the teardown or durability failure, or `undefined` on success. + * @returns this epoch's stop reason and final assistant content. + */ + terminal(failure: unknown): ActivationTerminal; + /** + * Publish the terminal edge exactly once, pairing this epoch's {@link start}, + * after the disposal outcome is known. Called only for a resident epoch: a + * failure before residency publishes no edge, because inventing one would + * report a lifecycle the child never had. + * @param failure - the teardown or durability failure, or `undefined` on success. + */ + settle(failure: unknown): void; +} +/** + * Publish one lifecycle edge with per-listener exception containment. Run edges + * carry the delegating parent that keys scoped dispatch; provider removal has no + * parent carrier and reaches listeners unscoped. + * + * The service owns this closure because scoped dispatch keys its carrier by the + * exact service instance, whose own context filter composes into the carrier; + * a narrowed stand-in would silently change scope filtering. + */ +export type LifecycleEmitter = { + (name: 'subagent/start', info: SubagentRunInfo, parent: Agent): void; + (name: 'subagent/end', info: SubagentRunEndInfo, parent: Agent): void; + (name: 'subagent/provider-removed', info: string): void; +}; +/** + * Build the contained lifecycle emitter this seam publishes every edge through. + * Every listener is independently contained: a synchronous throw or a rejected + * returned promise is logged without starving peer listeners, changing the run, + * or — for provider removal, which fires from a disposer — breaking teardown. + * @param ctx - the service's own context, owning dispatch and the logger. + * @param carrier - resolve the scoped dispatch carrier for one delegating parent. + * @returns the emitter both observers and the provider registry publish through. + */ +export declare function createLifecycleEmitter(ctx: Context, carrier: (parent: Agent) => object): LifecycleEmitter; +/** + * Emit the start/end lifecycle pair for one accepted one-shot run. + * @param emit - the contained lifecycle emitter. + * @param provider - the provider that established the run. + * @param parent - the delegating parent keying scoped dispatch. + * @param run - the published run whose settlement closes the pair. + * @returns the same run, unchanged. + */ +export declare function observeRun(emit: LifecycleEmitter, provider: string, parent: Agent, run: SubagentRun): SubagentRun; +/** + * Build the observer for one continuable Activation's residency epoch. Observers + * see the same vocabulary as a one-shot run, so a child's start and settlement + * remain observable without exposing whether the manager materialized, woke, or + * cold-resumed it. Creation failure before residency emits no lifecycle edge. + * @param emit - the contained lifecycle emitter. + * @param provider - the provider name recorded in the durable descriptor. + * @param childId - the durable child session id. + * @param parent - the exact live direct parent keying scoped dispatch. + * @returns the observer whose edges this epoch publishes. + */ +export declare function createActivationObserver(emit: LifecycleEmitter, provider: string, childId: SessionId, parent: Agent): ActivationObserver; +//# sourceMappingURL=lifecycle.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.js new file mode 100644 index 0000000..cff7aed --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/lifecycle.js @@ -0,0 +1,177 @@ +/** + * Lifecycle-edge publication for both subagent shapes: the contained emitter, + * the one-shot run observer, and the continuable Activation observer. + * + * The public payload contracts ({@link SubagentRunInfo}, + * {@link SubagentRunEndInfo}) live in `./types.ts` with the rest of the seam's + * consumer-facing types; this module owns only the implementation and the + * package-private {@link ActivationObserver} the continuation manager consumes. + * Keeping the internal control interface out of the published surface is + * deliberate: the observer's `start`/`capture`/`settle` ordering is a contract + * between this module and one in-package caller, not something a plugin may + * depend on. + * + * @module @deepseek-ai/dsh-subagent/lifecycle + */ +import { randomUUID } from 'node:crypto'; +import { foldConsumedWork } from '@deepseek-ai/dsh-agent'; +import { finalAssistantOutput } from "./assistant-output.js"; +import { SubagentRunId } from "./types.js"; +/** + * Build the contained lifecycle emitter this seam publishes every edge through. + * Every listener is independently contained: a synchronous throw or a rejected + * returned promise is logged without starving peer listeners, changing the run, + * or — for provider removal, which fires from a disposer — breaking teardown. + * @param ctx - the service's own context, owning dispatch and the logger. + * @param carrier - resolve the scoped dispatch carrier for one delegating parent. + * @returns the emitter both observers and the provider registry publish through. + */ +export function createLifecycleEmitter(ctx, carrier) { + return (name, info, parent) => { + const dispatchArgs = parent === undefined + ? [name, info] + : [carrier(parent), name, info]; + for (const callback of ctx.events.dispatch('emit', dispatchArgs)) { + try { + const returned = callback(info); + void Promise.resolve(returned).catch((error) => { + ctx.logger.warn(`subagent: ${name} listener rejected: ${renderThrown(error)}`); + }); + } + catch (error) { + ctx.logger.warn(`subagent: ${name} listener threw: ${renderThrown(error)}`); + } + } + }; +} +/** + * Emit the start/end lifecycle pair for one accepted one-shot run. + * @param emit - the contained lifecycle emitter. + * @param provider - the provider that established the run. + * @param parent - the delegating parent keying scoped dispatch. + * @param run - the published run whose settlement closes the pair. + * @returns the same run, unchanged. + */ +export function observeRun(emit, provider, parent, run) { + const identity = { + runId: SubagentRunId(randomUUID()), + provider, + id: run.id, + local: run.localAgent !== undefined, + }; + // Attach the terminal observer before dispatching start. Promise reactions + // still run after this synchronous start emission, preserving start → end. + void run.result.then((result) => { + emit('subagent/end', { + ...identity, + stopReason: result.stopReason, + // Omit the field when no output exists, matching continuable epochs. + ...result.output.length === 0 ? {} : { lastAssistantMessage: result.output }, + }, parent); + }, () => { + emit('subagent/end', { ...identity, stopReason: 'error' }, parent); + }); + emit('subagent/start', identity, parent); + return run; +} +/** + * Build the observer for one continuable Activation's residency epoch. Observers + * see the same vocabulary as a one-shot run, so a child's start and settlement + * remain observable without exposing whether the manager materialized, woke, or + * cold-resumed it. Creation failure before residency emits no lifecycle edge. + * @param emit - the contained lifecycle emitter. + * @param provider - the provider name recorded in the durable descriptor. + * @param childId - the durable child session id. + * @param parent - the exact live direct parent keying scoped dispatch. + * @returns the observer whose edges this epoch publishes. + */ +export function createActivationObserver(emit, provider, childId, parent) { + const identity = { runId: SubagentRunId(randomUUID()), provider, id: childId, local: true }; + // A cold resume replays earlier turns, so this epoch's telemetry must come + // from the suffix it actually produced — never the whole session, which + // would report a previous epoch's answer when this one opened no turn. + let boundary = 0; + // Assigned by `capture()`, which the disposal path always runs before + // `settle()`; a resident epoch therefore always has its facts by then. + let captured = { stopReason: 'completed' }; + // Teardown failure overrides the epoch's own outcome and withholds its + // output: an answer this harness could not durably release is not a result. + const terminal = (failure) => failure === undefined + ? captured + : { stopReason: 'error' }; + return { + start: (child) => { + boundary = child.session.events.length; + emit('subagent/start', identity, parent); + }, + capture: (child) => { + const own = child.session.events.slice(boundary); + const output = finalAssistantOutput(own); + captured = { + stopReason: epochStopReason(own), + ...output === undefined ? {} : { output }, + }; + }, + terminal, + settle: (failure) => { + const { stopReason, output } = terminal(failure); + emit('subagent/end', { + ...identity, + stopReason, + ...output === undefined ? {} : { lastAssistantMessage: output }, + }, parent); + }, + }; +} +/** + * Why this child's epoch ended, for the terminal lifecycle edge and the + * manager's own parent delivery. The child's own log is authoritative: + * teardown succeeding says nothing about whether the model errored, hit its + * token ceiling, or was cancelled, so deriving the reason from disposal would + * report failed work as completed. + * + * {@link foldConsumedWork} supplies both halves the raw turn sequence cannot: + * which turn accounts for the work this epoch consumed, and whether accepted + * work was cancelled after it without any turn opening over it. A recorded + * failure still wins over a cancellation — stopping a child that had already + * failed does not turn its failure into a cancellation. + * @param events - this epoch's own event suffix. + * @returns its terminal stop reason; `completed` only for an epoch that both + * closed cleanly and had nothing left to run. + */ +function epochStopReason(events) { + const { end, droppedUnrun } = foldConsumedWork(events); + switch (end?.data.reason.kind) { + case 'max-tokens': + return 'max-tokens'; + case 'aborted': + case 'interrupted': + return 'aborted'; + case 'error': + return 'error'; + // A pre-step rejection — a hook deny, a policy plugin — discarded input + // this epoch had claimed: the work was declined, not done. + case 'blocked': + return 'refusal'; + // A clean ending and no accounting turn at all share one rule: the epoch + // finished what it was given unless a cancelled queue says otherwise. + case undefined: + case 'completed': + return droppedUnrun ? 'aborted' : 'completed'; + /* v8 ignore next 3 -- `TurnEndReason` is merge-extensible, so this arm needs a + * backend that adds a variant; treating an unnameable reason as success would + * report failed work as completed. */ + default: + return 'error'; + } +} +/** Render any listener-thrown value without letting coercion escape containment. */ +function renderThrown(value) { + try { + return value instanceof Error ? `${value.name}: ${value.message}` : String(value); + } + catch { + return ''; + } +} +//# sourceMappingURL=lifecycle.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.d.ts new file mode 100644 index 0000000..c8cba52 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.d.ts @@ -0,0 +1,112 @@ +/** + * Read-only enumeration of durable subagent children and descendant trees + * straight from the live session store and optional session persistence — no + * query service. Candidates come from one live-preferred corpus; each child's + * mode/label is the registered `subagent` projection unit's value, resolved + * down a three-rung ladder: the registry's watermark cache for a live child, + * a durable projection-cache row when it serves an own-suffix identity (the + * seq gate), and one persistence inspection folded through the registry + * otherwise, validated against the enumerated lifecycle. The projection fold + * is the single classification authority — this module parses no descriptor + * itself. Absent persistence, enumeration is live-only: a cold child is + * unreachable for resume anyway, so its absence is capability absence, not an + * error. The module owns no catalog state and does not consult Activation, + * Agent-registry, continuation-manager, or provider state. + * + * @module @deepseek-ai/dsh-subagent + */ +import type { Context } from '@deepseek-ai/cordis'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +/** + * One entry of a {@link listChildren} result, ordered by header `createdAt` + * with ties broken on id. Only a candidate whose durable header has + * `origin: 'subagent'` is interpreted. A served `subagent` projection value + * produces a `child`; a settled candidate whose fold served no identity + * produces a `diagnostic`; a running candidate without one is omitted — its + * descriptor may not be appended yet (the creation window). Diagnostics + * relay the projection fold's outcome or a failed read, never a per-child + * event scan, and never expose model-hidden descriptor content. + */ +export type SubagentListEntry = { + readonly kind: 'child'; + /** The durable child session id, stable across Activations. */ + readonly id: SessionId; + /** + * Store snapshot activity: `running` means the logical record is live in + * `ctx.sessions`; `inactive` means it exists only in persistence. Neither + * encodes a durable outcome, and a continuable child may still reject + * delivery as an ownership conflict. + */ + readonly activity: 'running' | 'inactive'; + /** Whether a direct descendant has durable `origin: 'subagent'`. */ + readonly hasChildren: boolean; +} & ({ + /** A terminal one-shot child. */ + readonly mode: 'one-shot'; + /** Optional durable creation label from the child's descriptor. */ + readonly label?: string; +} | { + /** A resumable conversation. */ + readonly mode: 'continuable'; + /** Durable creation label from the child's descriptor. */ + readonly label: string; +}) | { + readonly kind: 'diagnostic'; + /** The candidate's session id. */ + readonly id: SessionId; + /** + * Why the candidate has no `child` row: `corrupt` for a settled candidate + * whose projection fold served no identity (a missing, malformed, or + * unrecognized-version descriptor — deliberately undistinguished), and + * for any candidate whose log makes a registered unit's fold or schema + * throw (deterministic data damage, contained per child); `unavailable` + * when the candidate's persistence inspection failed (retried on the + * next listing). `unsupported` is never produced; it remains in the + * union for consumers that route on it. + */ + readonly reason: 'corrupt' | 'unsupported' | 'unavailable'; +}; +/** + * One entry of a descendant listing: the interpreted subagent facts plus its + * position in the complete session tree. `parentId` is the durable direct + * parent from the enumerated header, and `depth` counts edges from the root. + */ +export type SubagentDescendantListEntry = SubagentListEntry & { + /** Durable direct parent of this candidate in the enumerated tree. */ + readonly parentId: SessionId; + /** Edge distance from the requested root; direct children are `1`. */ + readonly depth: number; +}; +/** + * Enumerate one parent's origin-classified direct children from the + * live-preferred merge of `ctx.sessions` and optional session persistence, + * serving each identity from the `subagent` projection unit: the registry's + * watermark snapshot for a live child; for a cold one, a durable + * projection-cache row when it serves an own-suffix identity (the seq gate), + * else one bounded-concurrency persistence inspection folded through the + * registry. + * @see SubagentRuntime.listChildren for the public cancellation and failure contract. + * @param ctx - context carrying the session store, the projection registry, + * optional persistence, and the optional projection cache. + * @param parentSessionId - parent session whose direct children are listed. + * @param signal - caller-owned cancellation observed around every persistence read. + * @returns children and per-child diagnostics ordered by `createdAt`, then id. + * @throws {@link SubagentError} when the projection registry or the session + * store is not mounted, or the caller cancels the listing. + */ +export declare function listChildren(ctx: Context, parentSessionId: SessionId, signal?: AbortSignal): Promise; +/** + * Enumerate every session-backed subagent below one root in stable pre-order. + * Ordinary sessions and one-shot children remain traversal nodes, so a + * continuable child below either is still discovered. Classification uses the + * same projection-backed runtime as {@link listChildren}; no Agent is loaded or + * resumed. + * @see SubagentRuntime.listDescendants for the public cancellation and failure contract. + * @param ctx - context carrying the session store, projection registry, and optional persistence/cache. + * @param rootSessionId - session whose complete descendant tree is listed. + * @param signal - caller-owned cancellation observed around every persistence read. + * @returns interpreted subagents with durable direct-parent and root-relative depth. + * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + */ +export declare function listDescendants(ctx: Context, rootSessionId: SessionId, signal?: AbortSignal): Promise; +//# sourceMappingURL=list-children.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.js new file mode 100644 index 0000000..d7d2170 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/list-children.js @@ -0,0 +1,316 @@ +/** + * Read-only enumeration of durable subagent children and descendant trees + * straight from the live session store and optional session persistence — no + * query service. Candidates come from one live-preferred corpus; each child's + * mode/label is the registered `subagent` projection unit's value, resolved + * down a three-rung ladder: the registry's watermark cache for a live child, + * a durable projection-cache row when it serves an own-suffix identity (the + * seq gate), and one persistence inspection folded through the registry + * otherwise, validated against the enumerated lifecycle. The projection fold + * is the single classification authority — this module parses no descriptor + * itself. Absent persistence, enumeration is live-only: a cold child is + * unreachable for resume anyway, so its absence is capability absence, not an + * error. The module owns no catalog state and does not consult Activation, + * Agent-registry, continuation-manager, or provider state. + * + * @module @deepseek-ai/dsh-subagent + */ +import { SubagentError } from "./error.js"; +/** + * Concurrent cold inspections per listing; a constant because it bounds one + * read-only scan of local media, not deployment behavior. Should a networked + * persistence backend appear, promote it to a validated `Config` field. + */ +const COLD_READ_CONCURRENCY = 4; +/** + * Enumerate one parent's origin-classified direct children from the + * live-preferred merge of `ctx.sessions` and optional session persistence, + * serving each identity from the `subagent` projection unit: the registry's + * watermark snapshot for a live child; for a cold one, a durable + * projection-cache row when it serves an own-suffix identity (the seq gate), + * else one bounded-concurrency persistence inspection folded through the + * registry. + * @see SubagentRuntime.listChildren for the public cancellation and failure contract. + * @param ctx - context carrying the session store, the projection registry, + * optional persistence, and the optional projection cache. + * @param parentSessionId - parent session whose direct children are listed. + * @param signal - caller-owned cancellation observed around every persistence read. + * @returns children and per-child diagnostics ordered by `createdAt`, then id. + * @throws {@link SubagentError} when the projection registry or the session + * store is not mounted, or the caller cancels the listing. + */ +export async function listChildren(ctx, parentSessionId, signal) { + const listing = await prepareListing(ctx, signal); + const candidates = [...listing.corpus.values()] + .filter(record => record.header.parentSession === parentSessionId + && record.header.origin === 'subagent') + .sort(compareCorpusRecords); + const rows = await resolveCandidateRows(candidates, listing, signal); + return rows.filter((row) => row !== undefined); +} +/** + * Enumerate every session-backed subagent below one root in stable pre-order. + * Ordinary sessions and one-shot children remain traversal nodes, so a + * continuable child below either is still discovered. Classification uses the + * same projection-backed runtime as {@link listChildren}; no Agent is loaded or + * resumed. + * @see SubagentRuntime.listDescendants for the public cancellation and failure contract. + * @param ctx - context carrying the session store, projection registry, and optional persistence/cache. + * @param rootSessionId - session whose complete descendant tree is listed. + * @param signal - caller-owned cancellation observed around every persistence read. + * @returns interpreted subagents with durable direct-parent and root-relative depth. + * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + */ +export async function listDescendants(ctx, rootSessionId, signal) { + const listing = await prepareListing(ctx, signal); + const positioned = descendantCandidates(listing.corpus, rootSessionId); + const rows = await resolveCandidateRows(positioned.map(candidate => candidate.record), listing, signal); + const entries = []; + positioned.forEach((position, index) => { + const row = rows[index]; + if (row !== undefined) { + entries.push({ ...row, parentId: position.parentId, depth: position.depth }); + } + }); + return entries; +} +/** Resolve listing services once and build one live-preferred session corpus. */ +async function prepareListing(ctx, signal) { + const projections = ctx.get('sessionProjections'); + // Checked before any read, even with zero candidates: mode/label are the + // row's strong contract, so a missing fold capability is a deterministic + // deployment configuration error, never an empty success. + if (projections === undefined) { + throw new SubagentError('listing subagents requires the sessionProjections registry (load @deepseek-ai/dsh-session-projection)', 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE'); + } + // Strict global read, never the `ctx.sessions` property proxy: the proxy is + // caller-scope bound, so a consumer plugin without its own `sessions` + // injection (the model-facing tool, the API proxy) would throw on access. + const sessions = ctx.get('sessions'); + if (sessions === undefined) { + throw new SubagentError('listing subagents requires the session store (load @deepseek-ai/dsh-session)', 'SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE'); + } + assertListingNotCancelled(signal); + const persistence = ctx.get('sessionPersistence'); + // Optional acceleration only: an absent cache service just means every + // cold candidate takes the authoritative preparation rung, so it carries + // no error code and no configuration check. + const cache = ctx.get('sessionProjectionCache'); + let persistedHeaders = []; + if (persistence !== undefined) { + try { + persistedHeaders = await persistence.list(signal); + } + catch (error) { + // The backend may reject with its own abort failure after observing the + // forwarded signal; cancellation stays a stable subagent failure. + assertListingNotCancelled(signal); + throw error; + } + assertListingNotCancelled(signal); + } + // Live-preferred merge without header reconciliation: a live record wins + // its id wholesale, exactly as a live-preferred corpus would serve it. + const corpus = new Map(); + for (const header of persistedHeaders) + corpus.set(header.id, { header, live: undefined }); + for (const session of sessions.list()) { + corpus.set(session.header.id, { header: session.header, live: session }); + } + const subagentParents = new Set(); + for (const record of corpus.values()) { + if (record.header.origin === 'subagent' && record.header.parentSession !== undefined) { + subagentParents.add(record.header.parentSession); + } + } + return { projections, persistence, cache, corpus, subagentParents }; +} +/** Resolve projection-backed rows for aligned candidates with bounded cold reads. */ +async function resolveCandidateRows(candidates, listing, signal) { + const { projections, persistence, cache, subagentParents } = listing; + const rows = Array.from({ length: candidates.length }); + const coldReads = []; + candidates.forEach((candidate, index) => { + const childId = candidate.header.id; + if (candidate.live === undefined) { + coldReads.push({ index, header: candidate.header }); + return; + } + // The registry's watermark cache serves the live value with zero log + // reads; a live child without an identity yet is the creation window + // before the establishing provider appends its descriptor. + let identity; + try { + identity = projections.snapshot(candidate.live).values.subagent; + } + catch { + // The snapshot folds EVERY registered unit over this child's log, so + // any unit's fold or schema can reject damaged payloads. That is + // deterministic data damage in this one child; it degrades to one + // corrupt diagnostic instead of failing the whole listing. + rows[index] = { kind: 'diagnostic', id: childId, reason: 'corrupt' }; + return; + } + // The unit's serializable no-value sentinel is `null`; `undefined` can + // only mean the key was dropped at a JSON boundary. Both are no value. + if (identity === undefined || identity === null) + return; + rows[index] = childRow(childId, identity, 'running', subagentParents.has(childId)); + }); + // Cold candidates exist only when persistence listed them, so the narrow + // re-check is about types, not reachability. + if (persistence !== undefined && coldReads.length > 0) { + const queue = [...coldReads]; + await Promise.all(Array.from({ length: Math.min(COLD_READ_CONCURRENCY, queue.length) }, async () => { + for (let job = queue.shift(); job !== undefined; job = queue.shift()) { + rows[job.index] = await resolveColdIdentity(persistence, projections, cache, job.header, subagentParents.has(job.header.id), signal); + } + })); + } + assertListingNotCancelled(signal); + return rows; +} +/** Build origin-classified candidates from the complete tree without recursion. */ +function descendantCandidates(corpus, rootSessionId) { + const children = new Map(); + for (const record of corpus.values()) { + const parentId = record.header.parentSession; + if (parentId === undefined) + continue; + const siblings = children.get(parentId); + if (siblings === undefined) + children.set(parentId, [record]); + else + siblings.push(record); + } + for (const siblings of children.values()) + siblings.sort(compareCorpusRecords); + const positioned = []; + const stack = (children.get(rootSessionId) ?? []) + .map(record => ({ record, parentId: rootSessionId, depth: 1 })) + .reverse(); + const visited = new Set([rootSessionId]); + while (stack.length > 0) { + // The length guard proves one frame exists. + // oxlint-disable-next-line typescript/no-non-null-assertion + const position = stack.pop(); + const id = position.record.header.id; + if (visited.has(id)) + continue; + visited.add(id); + if (position.record.header.origin === 'subagent') + positioned.push(position); + const descendants = children.get(id) ?? []; + for (const record of [...descendants].reverse()) { + stack.push({ record, parentId: id, depth: position.depth + 1 }); + } + } + return positioned; +} +/** Compare siblings by durable creation time, then id. */ +function compareCorpusRecords(a, b) { + return a.header.createdAt - b.header.createdAt || a.header.id.localeCompare(b.header.id); +} +/** + * Resolve one cold candidate down the remaining ladder: a durable + * projection-cache row when it serves an own-suffix identity (the seq gate), + * otherwise one persistence inspection folded through the projection + * registry (the same detached recipe the API proxy uses for detached session + * projections). A failed inspection is one transient `unavailable` row + * retried on the next listing; an inspection naming another lifecycle, and a + * settled log the fold cannot identify — or that makes any registered unit + * throw — are final, so they report `corrupt`. + */ +async function resolveColdIdentity(persistence, projections, cache, header, hasChildren, signal) { + const childId = header.id; + if (cache !== undefined) { + let cached; + try { + cached = cache.cachedSnapshot(header)?.values.subagent; + } + catch { + // Unlike the preparation fold below, a throwing cache read renders no + // verdict: the cache is derived data, so its damage (a poisoned stored + // row of ANY unit) silently falls through to the authoritative re-fold. + cached = undefined; + } + // A child's OWN descriptor is immutable once appended, so a cached + // identity is final only when the seq gate proves it was folded from the + // own suffix: a creation-window checkpoint may instead carry a fork + // seed's replayed ANCESTOR descriptor (seq below `seedLength`), which + // must not outrank the re-fold. Everything else also falls through to + // preparation: an absent key (a cut before any descriptor) and the + // `null` sentinel, whose verdict belongs to the authoritative re-fold, + // not to a derived row. + if (cached !== undefined && cached !== null && cached.seq >= (header.seedLength ?? 0)) { + return childRow(childId, cached, 'inactive', hasChildren); + } + } + assertListingNotCancelled(signal); + let inspected; + try { + inspected = await persistence.inspect(childId, signal); + } + catch { + // Per-child isolation: the child vanished or its backend read failed — + // one diagnostic row, and the listing itself still succeeds. + assertListingNotCancelled(signal); + return { kind: 'diagnostic', id: childId, reason: 'unavailable' }; + } + assertListingNotCancelled(signal); + // A session id names a slot, not a lifecycle: a child deleted and + // re-published under another owner between the enumeration and this read + // must not leak into the old parent's listing. + if (!sameLifecycle(inspected.meta, header)) { + return { kind: 'diagnostic', id: childId, reason: 'corrupt' }; + } + let identity; + try { + identity = projections.restore({}, inspected.events, 0).snapshot.values.subagent; + } + catch { + // The restore folds EVERY registered unit over this child's log, so any + // unit's fold or schema can reject damaged payloads — deterministic data + // damage in this one child, contained as its own corrupt diagnostic. + return { kind: 'diagnostic', id: childId, reason: 'corrupt' }; + } + if (identity === undefined || identity === null) { + return { kind: 'diagnostic', id: childId, reason: 'corrupt' }; + } + return childRow(childId, identity, 'inactive', hasChildren); +} +/** Materialize one served identity as its child row. */ +function childRow(id, identity, activity, hasChildren) { + return identity.mode === 'one-shot' + ? { + kind: 'child', + id, + mode: 'one-shot', + ...identity.label !== undefined ? { label: identity.label } : {}, + activity, + hasChildren, + } + : { + kind: 'child', + id, + mode: 'continuable', + label: identity.label, + activity, + hasChildren, + }; +} +/** Immutable header fields that distinguish one session lifecycle from another under the same id. */ +const LIFECYCLE_WITNESS_KEYS = [ + 'version', 'id', 'createdAt', 'cwd', 'parentSession', 'seedLength', 'delegationDepth', +]; +/** Whether an inspected log still belongs to the enumerated lifecycle. */ +function sameLifecycle(meta, expected) { + return LIFECYCLE_WITNESS_KEYS.every(key => meta[key] === expected[key]); +} +/** Stop a listing at its next cancellation checkpoint. */ +function assertListingNotCancelled(signal) { + if (signal?.aborted) { + throw new SubagentError('subagent listing was cancelled', 'CANCELLED'); + } +} +//# sourceMappingURL=list-children.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.d.ts new file mode 100644 index 0000000..476ade5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.d.ts @@ -0,0 +1,115 @@ +/** + * Provider-side vocabulary for OUT-OF-PROCESS subagent backends — the pieces + * that enforce this seam's own contracts around a child in another process: + * the no-capabilities advertisement, timing-bound validation, child + * working-directory resolution (config override, else the delegating parent + * session's workspace), the never-reject result settlement, and the standard + * run-handle publication. Backends compose these with their own wire drivers; + * the process machinery itself (spawn, env scrub, tree-scoped teardown) + * belongs to the `dsh-subprocess` seam. + * + * @module @deepseek-ai/dsh-subagent/out-of-process + */ +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { SubagentCapabilities, SubagentResult, SubagentRun, SubagentStopReason } from './types.ts'; +/** + * The capability advertisement of an out-of-process backend: NONE. A child in + * another process cannot honor parent-enforced start features + * (`outputSchema`/`maxDepth`/`toolFilter`/`persona`), so the service rejects a + * request needing any of them before `start` runs — never accepted-then-ignored. + */ +export declare const NO_START_CAPABILITIES: SubagentCapabilities; +/** + * Assert a configured timing bound is a positive finite number (it bounds a + * teardown or shutdown wait; zero, negative, or NaN would skip or wedge it). + * @param prefix - the consuming plugin's diagnostic prefix (e.g. `subagent-acp`). + * @param name - the config field name, for the diagnostic. + * @param value - the configured value. + */ +export declare function assertPositiveFinite(prefix: string, name: string, value: number): void; +/** + * Assert `cwd` can actually host the child: absolute (it doubles as the + * child's workspace identity, and a relative path would be re-anchored to the + * server process's launch directory) and an existing directory (fail here, + * before the process boundary, instead of as an ambiguous spawn ENOENT). + * @param prefix - the consuming plugin's diagnostic prefix. + * @param label - which source supplied the value, for the diagnostic. + * @param cwd - the candidate working directory. + * @returns `cwd`, validated. + */ +export declare function assertUsableCwd(prefix: string, label: string, cwd: string): string; +/** + * Validate a configured `cwd` override ONCE, at plugin load: reject the empty + * string (`path.resolve('')` is the process cwd — it would silently + * reintroduce the launch-directory fallback this resolution removes), + * interpret a relative path against the harness launch directory, and require + * an enterable directory. + * @param prefix - the consuming plugin's diagnostic prefix. + * @param cwd - the configured override, or `undefined` when the config omits it. + * @returns the validated absolute override, or `undefined` when omitted. + */ +export declare function validateConfiguredCwd(prefix: string, cwd: string | undefined): string | undefined; +/** + * Resolve the child's working directory at start: the deployment override + * when configured (already validated at load), else the parent session's + * workspace cwd (validated here, its earliest resolvable point). Fails loud + * when neither exists — falling back to the harness process cwd would + * silently bind the child to the server's launch directory instead of the + * delegating session's workspace (one server process serves many sessions, + * each with its own cwd). + * @param prefix - the consuming plugin's diagnostic prefix. + * @param configured - the load-validated override, or `undefined`. + * @param parentCwd - the delegating parent session's workspace cwd, if any. + * @returns the absolute child working directory. + */ +export declare function resolveChildCwd(prefix: string, configured: string | undefined, parentCwd: string | undefined): string; +/** Inputs to {@link settleRunResult}. */ +export interface RunResultSettlement { + /** The turn attempt (typically racing local cancellation); returns the terminal result. */ + attempt: () => Promise; + /** Snapshot the provider exposes when cancellation or failure wins settlement. */ + collectOutput: () => ContentBlock[]; + /** Whether local cancellation settled before the attempt's outcome is observed. */ + cancelled: () => boolean; + /** Diagnostic sink for a failure flattened to a stop reason; a throw from it is contained. */ + onError?: ((error: Error, stopReason: SubagentStopReason) => void) | undefined; + /** The request's cancellation signal (the listener is removed at settlement). */ + signal: AbortSignal; + /** The abort listener registered on {@link signal} at start. */ + onAbort: () => void; +} +/** + * Settle an out-of-process run result under the seam contract: `result` never + * rejects after publication. A normally completed or rejected attempt resolves + * as `aborted` when cancellation already settled locally; another rejection is + * flattened to `stopReason: 'error'` through the contained diagnostic sink. + * The abort listener is removed on every path. + * @param parts - the attempt, output snapshot, cancellation state, sink, and signal wiring. + * @returns the terminal result (never a rejection). + */ +export declare function settleRunResult(parts: RunResultSettlement): Promise; +/** Inputs to {@link subprocessRunHandle}. */ +export interface SubprocessRunHandleParts { + /** The parent-scoped run id. */ + id: SubagentRun['id']; + /** The flattened, never-rejecting result (the seam contract). */ + result: Promise; + /** The request's cancellation signal (the listener is removed on dispose). */ + signal: AbortSignal; + /** The abort listener registered on {@link signal} at start. */ + onAbort: () => void; + /** Settle local cancellation so {@link result} resolves without the child. */ + requestCancel: () => void; + /** Tear the child process down to quiescence (backend-owned ladder). */ + teardown: () => Promise; +} +/** + * Publish the seam run handle for an out-of-process child. `dispose()` is + * idempotent (one memoized teardown): it removes the abort listener, settles + * local cancellation — there is no assumption the child cooperates — and then + * awaits the backend's teardown to actual exit. + * @param parts - the run identity, result, cancellation wiring, and teardown. + * @returns the seam run handle (`localAgent` is `undefined` for remote runs). + */ +export declare function subprocessRunHandle(parts: SubprocessRunHandleParts): SubagentRun; +//# sourceMappingURL=out-of-process.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.js new file mode 100644 index 0000000..5460dfe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/out-of-process.js @@ -0,0 +1,181 @@ +/** + * Provider-side vocabulary for OUT-OF-PROCESS subagent backends — the pieces + * that enforce this seam's own contracts around a child in another process: + * the no-capabilities advertisement, timing-bound validation, child + * working-directory resolution (config override, else the delegating parent + * session's workspace), the never-reject result settlement, and the standard + * run-handle publication. Backends compose these with their own wire drivers; + * the process machinery itself (spawn, env scrub, tree-scoped teardown) + * belongs to the `dsh-subprocess` seam. + * + * @module @deepseek-ai/dsh-subagent/out-of-process + */ +import { accessSync, constants, statSync } from 'node:fs'; +import { isAbsolute, resolve } from 'node:path'; +/** + * The capability advertisement of an out-of-process backend: NONE. A child in + * another process cannot honor parent-enforced start features + * (`outputSchema`/`maxDepth`/`toolFilter`/`persona`), so the service rejects a + * request needing any of them before `start` runs — never accepted-then-ignored. + */ +export const NO_START_CAPABILITIES = Object.freeze({ + outputSchema: false, + depthLimit: false, + toolFilter: false, + persona: false, +}); +/** + * Assert a configured timing bound is a positive finite number (it bounds a + * teardown or shutdown wait; zero, negative, or NaN would skip or wedge it). + * @param prefix - the consuming plugin's diagnostic prefix (e.g. `subagent-acp`). + * @param name - the config field name, for the diagnostic. + * @param value - the configured value. + */ +export function assertPositiveFinite(prefix, name, value) { + if (!Number.isFinite(value) || value <= 0) { + throw new Error(`${prefix}: ${name} must be a positive finite number`); + } +} +/** + * Whether `path` names an existing directory the harness can ENTER. The + * search-permission probe matters: `statSync().isDirectory()` is true for a + * mode-600 directory, but a subprocess cwd needs `X_OK` or spawn fails EACCES. + */ +function isEnterableDirectory(path) { + try { + if (!statSync(path).isDirectory()) + return false; + accessSync(path, constants.X_OK); + return true; + } + catch { + // statSync/accessSync throw only filesystem access errors here + // (ENOENT/EACCES/ENOTDIR/…), and every one of them means the path cannot + // serve as the child's cwd. + return false; + } +} +/** + * Assert `cwd` can actually host the child: absolute (it doubles as the + * child's workspace identity, and a relative path would be re-anchored to the + * server process's launch directory) and an existing directory (fail here, + * before the process boundary, instead of as an ambiguous spawn ENOENT). + * @param prefix - the consuming plugin's diagnostic prefix. + * @param label - which source supplied the value, for the diagnostic. + * @param cwd - the candidate working directory. + * @returns `cwd`, validated. + */ +export function assertUsableCwd(prefix, label, cwd) { + if (!isAbsolute(cwd)) { + throw new Error(`${prefix}: ${label} must be an absolute path: ${cwd}`); + } + if (!isEnterableDirectory(cwd)) { + throw new Error(`${prefix}: ${label} is not an accessible directory: ${cwd}`); + } + return cwd; +} +/** + * Validate a configured `cwd` override ONCE, at plugin load: reject the empty + * string (`path.resolve('')` is the process cwd — it would silently + * reintroduce the launch-directory fallback this resolution removes), + * interpret a relative path against the harness launch directory, and require + * an enterable directory. + * @param prefix - the consuming plugin's diagnostic prefix. + * @param cwd - the configured override, or `undefined` when the config omits it. + * @returns the validated absolute override, or `undefined` when omitted. + */ +export function validateConfiguredCwd(prefix, cwd) { + if (cwd === undefined) + return undefined; + if (cwd === '') { + throw new Error(`${prefix}: config cwd must not be empty — omit the key to inherit the parent session cwd`); + } + return assertUsableCwd(prefix, 'config cwd', resolve(cwd)); +} +/** + * Resolve the child's working directory at start: the deployment override + * when configured (already validated at load), else the parent session's + * workspace cwd (validated here, its earliest resolvable point). Fails loud + * when neither exists — falling back to the harness process cwd would + * silently bind the child to the server's launch directory instead of the + * delegating session's workspace (one server process serves many sessions, + * each with its own cwd). + * @param prefix - the consuming plugin's diagnostic prefix. + * @param configured - the load-validated override, or `undefined`. + * @param parentCwd - the delegating parent session's workspace cwd, if any. + * @returns the absolute child working directory. + */ +export function resolveChildCwd(prefix, configured, parentCwd) { + if (configured !== undefined) + return configured; + if (parentCwd === undefined) { + throw new Error(`${prefix}: no working directory for the child — configure \`cwd\` or delegate from a parent session that has one`); + } + return assertUsableCwd(prefix, 'parent session cwd', parentCwd); +} +/** Normalize an unknown thrown value to an Error (the catch binding is `unknown`). */ +function toError(value) { + // The rejecting surfaces (wire clients, spawn failures) only throw + // `Error`s; the `String(value)` arm is a defensive fallback for a non-Error + // throw the typed surfaces cannot produce. + /* v8 ignore next */ + return value instanceof Error ? value : new Error(String(value)); +} +/** + * Settle an out-of-process run result under the seam contract: `result` never + * rejects after publication. A normally completed or rejected attempt resolves + * as `aborted` when cancellation already settled locally; another rejection is + * flattened to `stopReason: 'error'` through the contained diagnostic sink. + * The abort listener is removed on every path. + * @param parts - the attempt, output snapshot, cancellation state, sink, and signal wiring. + * @returns the terminal result (never a rejection). + */ +export async function settleRunResult(parts) { + try { + const result = await parts.attempt(); + return parts.cancelled() + ? { output: parts.collectOutput(), stopReason: 'aborted' } + : result; + } + catch (error) { + // Cover a rejection already queued when cancellation arrives. + if (parts.cancelled()) + return { output: parts.collectOutput(), stopReason: 'aborted' }; + // Flatten post-publication transport failures while preserving diagnostics. + try { + parts.onError?.(toError(error), 'error'); + } + catch { + // The diagnostic sink cannot reject the run result. + } + return { output: parts.collectOutput(), stopReason: 'error' }; + } + finally { + parts.signal.removeEventListener('abort', parts.onAbort); + } +} +/** + * Publish the seam run handle for an out-of-process child. `dispose()` is + * idempotent (one memoized teardown): it removes the abort listener, settles + * local cancellation — there is no assumption the child cooperates — and then + * awaits the backend's teardown to actual exit. + * @param parts - the run identity, result, cancellation wiring, and teardown. + * @returns the seam run handle (`localAgent` is `undefined` for remote runs). + */ +export function subprocessRunHandle(parts) { + let disposal; + return { + id: parts.id, + localAgent: undefined, + result: parts.result, + dispose() { + if (disposal !== undefined) + return disposal; + parts.signal.removeEventListener('abort', parts.onAbort); + parts.requestCancel(); + disposal = parts.teardown(); + return disposal; + }, + }; +} +//# sourceMappingURL=out-of-process.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.d.ts new file mode 100644 index 0000000..53cac6b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.d.ts @@ -0,0 +1,60 @@ +/** + * Pure client-safe subagent projection vocabulary. + * + * @module @deepseek-ai/dsh-subagent/projection-types + */ +/** Durable active-turn timing for one descriptor-backed child session. */ +export interface SubagentTimingProjection { + /** Milliseconds accumulated across completed turns after the child's own descriptor. */ + settledMs: number; + /** Same-cut bounds of the currently open turn, when one has not reached `turn/end`. */ + active?: { + /** Start of the open turn. */ + since: number; + /** Latest event time folded into this projection cut. */ + through: number; + }; +} +/** + * Durable identity of one descriptor-backed subagent session: lifecycle mode + * plus creation label, folded last-wins from `subagent/descriptor` events. + * Label strength follows the descriptor schema: a continuable child always + * carries one, a one-shot child may omit it. + */ +export type SubagentIdentityProjection = { + /** A terminal one-shot child. */ + mode: 'one-shot'; + /** Optional durable creation label from the child's descriptor. */ + label?: string; + /** + * Seq of the `subagent/descriptor` event this identity was folded from. + * `seq >= header.seedLength` proves the identity comes from the child's + * OWN log suffix — where a descriptor is immutable once appended — and + * not from a fork seed's replayed ancestor descriptor. + */ + seq: number; +} | { + /** A resumable conversation. */ + mode: 'continuable'; + /** Durable creation label from the child's descriptor. */ + label: string; + /** Seq of the folded descriptor event; see the one-shot arm for the own-suffix proof. */ + seq: number; +}; +declare module '@deepseek-ai/dsh-session-projection/types' { + interface SessionProjectionMap { + /** Active-turn duration for a descriptor-backed subagent session. */ + subagentTiming: SubagentTimingProjection; + /** + * Identity of a descriptor-backed subagent session. `null` ⟺ no valid + * descriptor (missing, malformed, or unrecognized-version — deliberately + * undistinguished). The sentinel is deliberately serializable: a + * value pushed over JSON transports must survive `JSON.stringify` + * losslessly, where an `undefined` field would be dropped and a stale + * identity would survive on the receiving side. The entry itself stays + * non-optional. + */ + subagent: SubagentIdentityProjection | null; + } +} +//# sourceMappingURL=projection-types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.js new file mode 100644 index 0000000..fd835de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection-types.js @@ -0,0 +1,7 @@ +/** + * Pure client-safe subagent projection vocabulary. + * + * @module @deepseek-ai/dsh-subagent/projection-types + */ +export {}; +//# sourceMappingURL=projection-types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.d.ts new file mode 100644 index 0000000..d2c9675 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.d.ts @@ -0,0 +1,48 @@ +/** + * Pure session projections for subagent identity (mode/label) and active-turn + * duration. + * + * @module @deepseek-ai/dsh-subagent/projection + */ +import type { ProjectionDefinition } from '@deepseek-ai/dsh-session-projection'; +import type { SubagentIdentityProjection } from './projection-types.ts'; +interface TimingState { + /** Milliseconds accumulated across completed post-descriptor turns. */ + settledMs: number; + /** Current open interval kept paired inside the fold. */ + active?: { + since: number; + through: number; + }; + /** Latest pre-descriptor turn start, promoted when the child's own descriptor arrives. */ + pendingTurnStart?: number; + /** Whether the fold has crossed a descriptor in this logical log. */ + descriptorSeen: boolean; +} +/** + * Fold turn boundaries around the child's own durable descriptor. + * + * A fork seed may contain an ancestor descriptor and completed turns. Every + * descriptor therefore resets the accumulated state; the healthy catalog + * admits only a child with exactly one descriptor in its own suffix, making + * the final reset the child's authoritative timing origin. + */ +export declare const subagentTimingProjectionDefinition: ProjectionDefinition<'subagentTiming', TimingState>; +interface IdentityState { + /** Identity from the last valid descriptor; absent before one, and after an invalid one. */ + identity?: SubagentIdentityProjection; +} +/** + * Fold the durable mode/label identity from `subagent/descriptor` events, + * last-wins: a fork seed may replay an ancestor's descriptor, and the child's + * own descriptor must override it — the same reset discipline as + * {@link subagentTimingProjectionDefinition}. A malformed or unknown-version + * payload resets to the `null` sentinel instead of throwing, so a fork of a + * healthy ancestor never inherits an identity its own descriptor failed to + * establish — and the reset survives every JSON push frame, so a consumer + * holding the earlier identity replaces it instead of keeping it stale; + * `null` ⟺ no valid descriptor, with the causes deliberately undistinguished. + */ +export declare const subagentIdentityProjectionDefinition: ProjectionDefinition<'subagent', IdentityState>; +export {}; +//# sourceMappingURL=projection.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.js new file mode 100644 index 0000000..283b1df --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/projection.js @@ -0,0 +1,135 @@ +/** + * Pure session projections for subagent identity (mode/label) and active-turn + * duration. + * + * @module @deepseek-ai/dsh-subagent/projection + */ +import { z } from 'zod'; +import { foldSubagentDescriptor } from "./descriptor.js"; +// Zod's optional output includes explicit `undefined`; with +// exactOptionalPropertyTypes the public interface permits omission only. +const projectionSchema = z.object({ + settledMs: z.number().int().nonnegative(), + active: z.object({ + since: z.number().int().nonnegative(), + through: z.number().int().nonnegative(), + }).strict().optional(), +}).strict(); +/** + * Fold turn boundaries around the child's own durable descriptor. + * + * A fork seed may contain an ancestor descriptor and completed turns. Every + * descriptor therefore resets the accumulated state; the healthy catalog + * admits only a child with exactly one descriptor in its own suffix, making + * the final reset the child's authoritative timing origin. + */ +export const subagentTimingProjectionDefinition = { + key: 'subagentTiming', + schema: projectionSchema, + init: () => ({ descriptorSeen: false, settledMs: 0 }), + apply: (state, event) => { + if (event.type === 'turn/start') { + return state.descriptorSeen + ? { ...state, active: { since: event.time, through: event.time } } + : { ...state, pendingTurnStart: event.time }; + } + if (event.type === 'subagent/descriptor') { + const activeSince = state.active?.since ?? state.pendingTurnStart; + return { + descriptorSeen: true, + settledMs: 0, + ...(activeSince === undefined + ? {} + : { active: { since: activeSince, through: event.time } }), + }; + } + if (event.type === 'turn/end') { + if (!state.descriptorSeen) { + if (state.pendingTurnStart === undefined) + return state; + const { pendingTurnStart: _closed, ...next } = state; + return next; + } + if (state.active === undefined) + return state; + const { active, ...rest } = state; + return { + ...rest, + settledMs: state.settledMs + Math.max(0, event.time - active.since), + }; + } + if (state.active === undefined) + return state; + return { ...state, active: { ...state.active, through: event.time } }; + }, + view: state => ({ + settledMs: state.settledMs, + ...(state.active === undefined ? {} : { active: state.active }), + }), + stateVersion: 2, +}; +// The cast bridges only the optional-label arm: Zod's optional output +// includes explicit `undefined`, which exactOptionalPropertyTypes excludes +// from the public interface. The no-value state itself is the serializable +// `null` arm — never `undefined` — so every registry read and push frame +// survives JSON.stringify losslessly. +const identitySchema = z.discriminatedUnion('mode', [ + z.object({ + mode: z.literal('one-shot'), + label: z.string().optional(), + seq: z.number().int().nonnegative(), + }).strict(), + z.object({ + mode: z.literal('continuable'), + label: z.string(), + seq: z.number().int().nonnegative(), + }).strict(), +]).nullable(); +/** Interpret one `subagent/descriptor` event's identity; no value when the payload cannot be trusted. */ +function descriptorIdentity(event) { + let descriptor; + try { + descriptor = foldSubagentDescriptor([event]); + } + catch { + // Only a malformed current-version payload throws in descriptor parsing; + // a projection fold must never throw, so damage folds to no value. + descriptor = undefined; + } + if (descriptor === undefined) + return undefined; + return descriptor.mode === 'one-shot' + ? { + mode: 'one-shot', + ...descriptor.label !== undefined ? { label: descriptor.label } : {}, + seq: event.seq, + } + : { mode: 'continuable', label: descriptor.label, seq: event.seq }; +} +/** + * Fold the durable mode/label identity from `subagent/descriptor` events, + * last-wins: a fork seed may replay an ancestor's descriptor, and the child's + * own descriptor must override it — the same reset discipline as + * {@link subagentTimingProjectionDefinition}. A malformed or unknown-version + * payload resets to the `null` sentinel instead of throwing, so a fork of a + * healthy ancestor never inherits an identity its own descriptor failed to + * establish — and the reset survives every JSON push frame, so a consumer + * holding the earlier identity replaces it instead of keeping it stale; + * `null` ⟺ no valid descriptor, with the causes deliberately undistinguished. + */ +export const subagentIdentityProjectionDefinition = { + key: 'subagent', + schema: identitySchema, + init: () => ({}), + apply: (state, event) => { + if (event.type !== 'subagent/descriptor') + return state; + const identity = descriptorIdentity(event); + return identity === undefined ? {} : { identity }; + }, + view: state => state.identity ?? null, + // Bumped when the identity gained its `seq` field: an older checkpoint row + // would replay into a value the schema rejects, so it must refold instead. + stateVersion: 2, +}; +//# sourceMappingURL=projection.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.d.ts new file mode 100644 index 0000000..f1f22ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.d.ts @@ -0,0 +1,17 @@ +/** + * Settlement of one ONE-SHOT subagent run into a background-Task outcome. Only + * the one-shot background path uses Jobs; continuable children have no Task, + * no per-message result, and no Task cancellation. + * + * @module @deepseek-ai/dsh-subagent/run-settlement + */ +import type { JobOutcome } from '@deepseek-ai/dsh-jobs'; +import type { SubagentRun } from './types.ts'; +/** + * Await the child result, dispose the run, then return its task outcome. Result + * and disposal failures become `failed`; when both fail, both details survive. + * @param run - live run to settle and release. + * @returns outcome after child resources are released. + */ +export declare function settleRun(run: SubagentRun): Promise; +//# sourceMappingURL=run-settlement.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.js new file mode 100644 index 0000000..220f06a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/run-settlement.js @@ -0,0 +1,59 @@ +/** + * Settlement of one ONE-SHOT subagent run into a background-Task outcome. Only + * the one-shot background path uses Jobs; continuable children have no Task, + * no per-message result, and no Task cancellation. + * + * @module @deepseek-ai/dsh-subagent/run-settlement + */ +/** Flatten a child's final output blocks to the task's final text. */ +function finalText(blocks) { + return blocks + .filter((block) => block.type === 'text') + .map(block => block.text) + .join(''); +} +/** + * Map a child result to the task outcome: completed carries final text, + * aborted is killed, and every other reason is failed without partial output. + * @param result - child terminal result. + * @returns outcome for the `ctx.jobs` registration. + */ +function runOutcome(result) { + switch (result.stopReason) { + case 'completed': + return { status: 'completed', output: finalText(result.output) }; + case 'aborted': + return { status: 'killed' }; + case 'error': + case 'max-tokens': + case 'refusal': + return { status: 'failed', detail: result.stopReason }; + // Merge-extensible reasons remain failures with their raw detail. + default: + return { status: 'failed', detail: String(result.stopReason) }; + } +} +/** + * Await the child result, dispose the run, then return its task outcome. Result + * and disposal failures become `failed`; when both fail, both details survive. + * @param run - live run to settle and release. + * @returns outcome after child resources are released. + */ +export async function settleRun(run) { + let outcome; + try { + outcome = runOutcome(await run.result); + } + catch (error) { + outcome = { status: 'failed', detail: String(error) }; + } + try { + await run.dispose(); + } + catch (error) { + const prefix = outcome.detail === undefined ? '' : `${outcome.detail}; `; + return { status: 'failed', detail: `${prefix}dispose failed: ${String(error)}` }; + } + return outcome; +} +//# sourceMappingURL=run-settlement.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.d.ts new file mode 100644 index 0000000..4f50d95 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.d.ts @@ -0,0 +1,308 @@ +/** + * The seam's consumer-facing contracts: request, result, and capability types + * for {@link SubagentProvider}, plus the `subagent/start` and `subagent/end` + * payloads that plugins and hosts observe. Internal control interfaces belong + * with their implementation — the lifecycle observer in `./lifecycle.ts`, the + * continuation host in `./continuation.ts` — so this module stays the published + * surface rather than a bag of everything type-shaped. + * + * @module @deepseek-ai/dsh-subagent/types + */ +import type { Agent, AgentOptions } from '@deepseek-ai/dsh-agent'; +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'; +import type { ObjectJsonSchema, ToolRestriction } from '@deepseek-ai/dsh-tools'; +import type { SubagentDescriptorData } from './descriptor.ts'; +/** Identifies one accepted subagent run across its lifecycle event pair. */ +export type SubagentRunId = Branded<'SubagentRunId'>; +/** + * Brand a string as a {@link SubagentRunId}. + * @param id - the raw run id. + * @returns the same string, branded. + */ +export declare function SubagentRunId(id: string): SubagentRunId; +/** + * Observe-only identifying detail for a published subagent run, carried by + * `subagent/start`. One-shot runs and continuable Activation epochs share this + * payload, so an observer sees the same vocabulary for both. + */ +export interface SubagentRunInfo { + /** Unique identity shared with the paired terminal event. */ + readonly runId: SubagentRunId; + /** + * Provider name recorded when the child was first created. The provider may + * be absent when an accepted one-shot run becomes ready or a persisted + * Activation cold-resumes, because neither lifecycle depends on continued + * registration. + */ + readonly provider: string; + /** The child agent's id. */ + readonly id: SessionId; + /** Snapshot of whether `SubagentRun.localAgent` was present when start fulfilled. */ + readonly local: boolean; +} +/** + * Observe-only outcome detail for a settled subagent run, carried by + * `subagent/end` and paired with one {@link SubagentRunInfo} by `runId`. + */ +export interface SubagentRunEndInfo { + /** Unique identity shared with the paired start event. */ + readonly runId: SubagentRunId; + /** The same provider name carried by the paired start event. */ + readonly provider: string; + /** The child agent's id. */ + readonly id: SessionId; + /** Snapshot of whether `SubagentRun.localAgent` was present when start fulfilled. */ + readonly local: boolean; + /** The terminal stop reason. */ + readonly stopReason: SubagentResult['stopReason']; + /** + * The child's final assistant output, selected by the same rule as + * {@link SubagentResult.output}; absent on infrastructure rejection or when + * the child produced none. + */ + readonly lastAssistantMessage?: ContentBlock[]; +} +/** + * Which START-TIME features a provider supports. Checked by the service before delegating to + * {@link SubagentProvider.start}: a request that needs a capability the chosen provider lacks + * is rejected with a typed error rather than accepted-then-ignored (the "fail loud, no silent + * degradation" rule). These flags describe the ONE-SHOT + * {@link SubagentProvider.start} path, where the provider composes the child; + * continuable children are composed by the continuation manager itself and are + * gated by {@link SubagentProvider.prepareContinuable} instead. Each flag + * corresponds one-to-one to a {@link SubagentStartRequest} option: `depthLimit` + * to `maxDepth`; the other names match. + */ +export interface SubagentCapabilities { + readonly outputSchema: boolean; + readonly depthLimit: boolean; + readonly toolFilter: boolean; + readonly persona: boolean; +} +/** + * What a caller asks for when starting a ONE-SHOT subagent. The tool layer + * builds this from the model's `{ description, prompt }` plus its own config; + * the service validates {@link SubagentCapabilities} against the named provider + * and resolves the durable descriptor before dispatching to + * {@link SubagentProvider.start}. + */ +export interface SubagentStartRequest { + /** Optional short display label persisted with a session-backed child. */ + readonly label?: string; + /** Content delivered as the child's user message. */ + readonly prompt: ContentBlock[]; + /** + * The spawning agent. In-process providers derive workspace, lineage, and + * delegation depth from its durable session state. ACP reads only its cwd, + * and only when no deployment `cwd` override is configured. + */ + readonly parent: Agent; + /** + * Cancellation signal from the spawning context (the tool's `exec.signal`). + * This is the canonical cancellation channel both before and after startup: + * a provider rejects `start()` after cleaning partial resources when it + * fires before the run is published, and cancels the published run's + * remaining turn work when it fires afterward. + */ + readonly signal: AbortSignal; + readonly agentOptions?: AgentOptions; + /** + * Object-rooted JSON Schema within `assertObjectJsonSchema`'s enforced subset. Start rejects + * unsupported schemas or providers without the capability. Data must be plain host-realm JSON; + * a successful child returns the matching value as {@link SubagentResult.structured}. + */ + readonly outputSchema?: ObjectJsonSchema; + /** + * Optional absolute delegation-depth cap for the child being started: its + * computed depth must be less than or equal to this non-negative safe + * integer. Requires {@link SubagentCapabilities.depthLimit}; rejected at + * start otherwise. + */ + readonly maxDepth?: number; + /** + * Optional child tool scoping. Requires {@link SubagentCapabilities.toolFilter}; + * rejected at start otherwise. In-process backends apply it as a scoped + * `tools.restrict()` in the child's creation window: the named tools vanish + * from the child's prompt AND refuse to execute (one visibility), with loud + * unknown-name validation. + */ + readonly toolFilter?: ToolRestriction; + /** + * Optional per-child persona. Requires {@link SubagentCapabilities.persona}; + * rejected at start otherwise. In-process backends register it as a scoped + * `deployment:persona` section on the child, SHADOWING the deployment's + * persona for this child alone — same template semantics as the deployment + * persona (strict `{{…}}` interpolation against the registered variables). + */ + readonly persona?: string; +} +/** + * Provider-facing one-shot request after {@link SubagentRuntime.start} resolves + * the durable child descriptor. + */ +export interface ResolvedSubagentStartRequest extends SubagentStartRequest { + /** Detached descriptor a session-backed provider persists in the child log. */ + readonly descriptor: SubagentDescriptorData; +} +/** + * What the continuation manager asks a provider for while materializing one + * continuable child's FIRST activation. The manager has already reserved the + * durable child identity and owns every later operation, so this request + * carries only what distinguishes a fresh child from one seeded with parent + * history. + */ +export interface ContinuableCreateRequest { + /** The reserved durable child session id, for provider diagnostics. */ + readonly sessionId: SessionId; + /** The delegating parent agent whose history a seeding provider reads. */ + readonly parent: Agent; + /** + * Caller cancellation, which owns preparation only until the manager accepts + * the initial prompt into the child's inbox. + */ + readonly signal: AbortSignal; +} +/** + * A provider's detached contribution to one continuable child's creation. This + * is DATA, never a capability: it carries no Agent, `AgentHandle`, prompt + * delivery, result, disposal, or resume operation, because the continuation + * manager owns the child's whole lifecycle after preparation. + */ +export interface ContinuableCreateSpec { + /** + * Completed-turn prefix of the parent's log to seed the child session with, + * or absent for a fresh child. Same durable contract as + * `CreateAgentOptions.seed`: contiguous from seq 0, lossless JSON, balanced. + */ + readonly seed?: readonly SessionEvent[]; +} +/** + * Why a subagent run ended. Merge-extensible (a backend may add variants); + * consumers branch on the known cases and fall through `default`. The known + * cases mirror the harness turn-end vocabulary so the tool layer can map a + * non-`completed` result to an `isError` tool result. + */ +export interface SubagentStopReasonMap { + /** The child finished its turn normally. */ + completed: 'completed'; + /** Cancelled through the request signal or disposal. */ + aborted: 'aborted'; + /** Model or transport failure. */ + error: 'error'; + /** The child hit its token ceiling before finishing. */ + 'max-tokens': 'max-tokens'; + /** The child declined the task. */ + refusal: 'refusal'; +} +/** The union over {@link SubagentStopReasonMap} — widens automatically as backends merge in variants. */ +export type SubagentStopReason = SubagentStopReasonMap[keyof SubagentStopReasonMap]; +/** + * The terminal outcome of a subagent run, resolved by {@link SubagentRun.result}. + */ +export interface SubagentResult { + /** + * The child's final assistant output is the content of its last non-empty + * assistant message. Empty-content messages, including usage-only messages, + * are skipped. Without a non-empty message, the output is its accumulated + * assistant text stream, or `[]` when the child produced neither. + */ + readonly output: ContentBlock[]; + /** + * The structured result after a requested `outputSchema` was successfully + * satisfied. Requesting a schema does not guarantee presence: a provider can + * end with `stopReason: 'error'` when the child fails or finishes without a + * valid capture. The structured value is validated against the requested + * output schema by the provider; `unknown` here because the seam is + * schema-agnostic. + */ + readonly structured?: unknown; + /** Why the run ended. A non-`completed` reason means `output` may be partial. */ + readonly stopReason: SubagentStopReason; +} +/** + * ONE-SHOT child handle returned after publication. Prompt submission, turn + * work, and infrastructure faults after that boundary belong to {@link result}. + * Consumers await that result and must always {@link dispose} to cancel + * remaining work and reach quiescence. A run is one disposable foreground + * delegation with one result; continuable conversations have no run — the + * continuation manager holds their `AgentHandle` directly and orders every + * turn through the child's own inbox. + */ +export interface SubagentRun { + /** + * Parent-scoped run id. For a local run, this MUST equal the published child + * session id, whose `parentSession` records `request.parent.session.id`; a + * remote provider mints an id unique in the parent namespace. + */ + readonly id: SessionId; + /** + * The exact published in-process child, or `undefined` for a remote run. + * When present, its id is {@link id}; the provider retains no ownership + * implication beyond the run's ordinary {@link dispose} contract. + */ + readonly localAgent: Agent | undefined; + /** + * Resolves with the child's terminal {@link SubagentResult} when the run + * settles. Does NOT reject on a child-level failure — a model/transport + * failure resolves with `stopReason: 'error'` so the consumer maps it to an + * `isError` tool result. Rejects on an infrastructure fault the seam cannot + * represent as a stop reason. + */ + readonly result: Promise; + /** + * Cancel remaining work, reach child quiescence, and release resources. + * Idempotent. + */ + dispose(): Promise; +} +/** + * One registered transport for running child agents. Providers are trusted + * same-process implementations; callers treat descriptors and returned values + * as borrowed immutable data. The service may call one provider concurrently + * for distinct children. Providers isolate operation-local mutable state; a + * shared capacity controller may delay an operation but must not couple its + * settlement or cleanup to a sibling. + */ +export interface SubagentProvider { + /** Unique registry name (e.g. `spawn`, `fork`, `acp`). */ + readonly name: string; + /** The start-time features this provider supports (see {@link SubagentCapabilities}). */ + readonly capabilities: SubagentCapabilities; + /** + * Whether the child sees the parent's completed-turn prefix. This is descriptive, not a + * service-validated start capability: the model-facing tool derives truthful wording from it. + * It says nothing about tool registration, injected services, or authority inheritance. + */ + readonly inheritsParentContext: boolean; + /** + * Establish a ONE-SHOT child and return its handle after publication. + * The service has already validated that every requested start-time + * capability is supported and resolved `request.descriptor`, so a + * session-backed implementation appends that descriptor inside the child's + * initial turn. Before fulfillment, the provider owns setup and cleans any + * unpublished partial resources before rejecting. Ownership transfers on + * fulfillment; subsequent turn or infrastructure failure settles through + * the returned run. Distinct starts may overlap; cancellation, failure, + * result settlement, and disposal remain independent for each run. + */ + start(request: ResolvedSubagentStartRequest): Promise; + /** + * OPTIONAL (continuable-creation capability): contribute the detached + * creation inputs that distinguish this provider's continuable children — + * only whether the child session is seeded with parent history. Method + * presence IS the capability: the service rejects continuable starts on + * providers without it, while a provider that has it may still serve + * ordinary one-shot delegations. + * + * This is the provider's ONLY participation in a continuable child. The + * continuation manager owns identity reservation, composition, Agent + * creation, prompt delivery, cold resume, ownership, and disposal, so a + * provider never sees the child's Agent, handle, turns, or teardown. + * Distinct preparations may overlap; each follows its own signal and returns + * data belonging only to `request.sessionId`. + */ + prepareContinuable?(request: ContinuableCreateRequest): Promise; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.js new file mode 100644 index 0000000..4b00332 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/lib/types/types.js @@ -0,0 +1,19 @@ +/** + * The seam's consumer-facing contracts: request, result, and capability types + * for {@link SubagentProvider}, plus the `subagent/start` and `subagent/end` + * payloads that plugins and hosts observe. Internal control interfaces belong + * with their implementation — the lifecycle observer in `./lifecycle.ts`, the + * continuation host in `./continuation.ts` — so this module stays the published + * surface rather than a bag of everything type-shaped. + * + * @module @deepseek-ai/dsh-subagent/types + */ +/** + * Brand a string as a {@link SubagentRunId}. + * @param id - the raw run id. + * @returns the same string, branded. + */ +export function SubagentRunId(id) { + return id; +} +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/package.json new file mode 100644 index 0000000..73ba68b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent/package.json @@ -0,0 +1,106 @@ +{ + "name": "@deepseek-ai/dsh-subagent", + "description": "Abstract subagent seam (ctx.subagents): named-provider registry for delegating to child agents", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/subagent/subagent" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client.d.ts", + "default": "./lib/types/client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.7", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.7", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.7", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent-presets": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox-policy": { + "optional": true + }, + "@deepseek-ai/dsh-session-persistence": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection-cache": { + "optional": true + }, + "@deepseek-ai/dsh-jobs": { + "optional": true + }, + "@deepseek-ai/dsh-user-approval": { + "optional": true + } + }, + "devDependencies": { + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.7", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.7", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-tools b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-tools new file mode 120000 index 0000000..df45afe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-tools @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-user-approval b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-user-approval new file mode 120000 index 0000000..7a0ea6d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-user-approval @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.i18n.yaml new file mode 100644 index 0000000..28bc2cf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/system-prompt/README.md +README.md: d750a507e628e7609af542227e4528d4d4934ce8 +README.zh.md: fcf5ebfad1e467b060b2efaa6c6f2816d75945d1 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.md new file mode 100644 index 0000000..d750a50 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.md @@ -0,0 +1,90 @@ +# dsh-system-prompt + +English | [中文](README.zh.md) + +System prompt assembly registry. Plugins contribute ordered sections, tool schemas, and named variables. The loop assembles once per step and renders the result as the complete model prompt. This plugin owns the static harness identity and global deployment persona; an agent-scoped persona shadows the global default. + +## Config + +| Key | Default | Meaning | +|---|---|---| +| `includeHarnessIdentity` | `true` | Include the fixed `You are an AI agent powered by DeepSeek Harness.` order-−100 opener. Set false only when a compatibility deployment owns the complete system prompt. | +| `includeRuntimeContext` | `true` | Include ordered dynamic contexts in assembly. When false, context providers are not evaluated and contexts added by `system-prompt/assemble` listeners are discarded after the waterfall; other services and their enforcement remain active. | +| `persona` | `''` | The global deployment-persona default: the ONE config-authored prompt fragment, rendered as the order-0 `deployment:persona` section unless an agent-scoped contribution shadows it. A template — complete `{{…}}` groups are interpreted strictly against the registered variables (the shipped loop registers `{{model}}`/`{{cwd}}`), with no escape syntax for literal braces yet. Empty ⇒ the section is dropped at render. | +| `toolOrder` | — | Explicit model-facing tool order, as a list of `ToolSchema.name`s with one `''` rest entry (`TOOL_ORDER_REST`): listed tools take their listed position, unlisted tools land at the rest entry in lexicographic name order. Absent ⇒ plain lexicographic name order. Applied to the collected tools BEFORE the `system-prompt/assemble` waterfall — like the sections' `order` sort, it canonicalizes what the registry contributed (registration order is a plugin-load artifact), and a waterfall listener that mutates the list owns the determinism of what it emits. Misconfiguration fails loud: a list without exactly one rest entry, or with duplicates, throws at load; a listed name with no registered tool rejects every `assemble()`; a tool provider returning the reserved rest-entry name also rejects. Under the shipped loop the turn fails before any model request. Why a central list and not per-plugin weights: [Explicit model-facing tool order](../../../.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.md). | + +## Service: `SystemPrompt` (ctx key: `systemPrompt`) + +### Public API + +- `ctx.systemPrompt.section(section: PromptSection): () => void` Contribute a section. The layer is the calling context's scope: `agent.ctx` contributes to that agent alone, shadowing a same-named global section there. A `complete: true` section becomes the exact complete prompt after the assembly waterfall; more than one effective complete section rejects assembly. Duplicate names within one layer and non-finite orders throw. Disposed with the calling fiber. +- `ctx.systemPrompt.context(context: PromptContext): () => void` Contribute ordered dynamic context for the calling scope. Providers are evaluated for each eligible assembly and become a sourced runtime-context snapshot in model history under the shipped loop. +- `ctx.systemPrompt.suppressRuntimeContext(): () => void` Suppress every dynamic-context contribution for the calling scope. Multiple registrations compose independently; disposing the returned effect restores context when no suppressor remains. +- `ctx.systemPrompt.tools(provider: (context: AssembleContext) => ToolProviderResult): () => void` Contribute tool schemas, evaluated at each assembly with that assembly's context. `ToolProviderResult` = `{ schemas, knownNames? }`: `schemas` is the post-restriction visible set; `knownNames` is the pre-restriction universe used by `toolOrder`. A provider must not return a schema named `TOOL_ORDER_REST`. Scoped providers are consulted only for their scope's assemblies. Disposed with the calling fiber. +- `ctx.systemPrompt.variable(name: string, provider: (context) => string | undefined): () => void` Contribute a prompt variable, referenced from section text as `{{name}}`. Scoped variables shadow a same-named global for that agent. Duplicate-in-layer or unreferenceable names throw; `undefined` means "no value for this assembly". Disposed with the calling fiber. +- `ctx.systemPrompt.assemble(context?: AssembleContext): Promise` Assemble the prompt for one caller: the global layer merged with `context.scope`'s layer, with tool schemas detached before the transform waterfall. Runs through the scope-filtered `system-prompt/assemble` waterfall, then restores an effective complete section as the sole prompt section and enforces any active runtime-context suppressor. An optional `context.signal` explicitly controls this assembly request; providers and listeners may cooperate with it but must not retain it for another turn. Rejects for multiple complete sections, when a configured `toolOrder` names a tool outside the providers' `knownNames` universe, or when a provider returns the reserved rest-entry name. + +### Live events + +`system-prompt/assemble` is authoritative for ordinary sections; a complete section is the final prompt constraint applied after the waterfall. Listeners that replace entries must preserve any active Code Mode or structured-output protocol. Use [`ToolRuntime.restrict()`](../tools/README.md) when filtering must stay aligned across presentation, lookup, and execution. Registry-change notifications are unfiltered. The generated region of [system-prompt.md](../../../docs/subsystems/system-prompt.md#cordis-surface) owns signatures and dispatch contracts. + +### Key types + +- `AssembleContext` — what one `assemble()` call is FOR. Merge-extensible; declares `scope?: ScopeKey` (the layer selector) and `signal?: AbortSignal` (the explicit request control capability) here, while `dsh-agent` declares `agent?: Agent` (the typed DX field — never set without `scope`; use `assembleContextFor(agent, signal)`). Providers must tolerate absent fields because a bare `assemble()` carries an empty, scope-less, signal-less context. `signal` is a request value, not part of the ambient Agent execution frame. +- `PromptSection` — `{ name, order, text, complete? }`. Sections are concatenated in ascending `order`. Order bands: `-100` is the harness identity, `0` the deployment persona, tool guidance uses `100–199`. One effective `complete` section suppresses all other sections after cooperative assembly. +- `PromptAssembly` — `{ sections: AssembledSection[], tools: ToolSchema[], variables: Record }`. Section texts arrive resolved but not yet interpolated; `variables` holds every registered variable resolved against the context. Tool schemas are part of the assembly by design: "what the model is told it can do" is one coherent thing, even though adapters transmit schemas as a separate wire field. +- `renderPrompt(assembly)` — interpolates `{{variable}}` references in each section, drops empty sections, joins with blank lines. STRICT: an unknown reference (`Object.hasOwn` lookup — prototype names like `{{constructor}}` are unknown), a registered-but-valueless reference, a malformed complete `{{…}}` group, or a `{{` that opens no complete group while a `}}` still follows (`{{{model}}}`) throws — fail loud beats shipping a malformed prompt. A lone `{{` with no `}}` anywhere after it passes through verbatim; substituted values are never re-scanned. + +Merge-extensible: plugins can declare extra fields on `PromptAssembly` and `AssembleContext` via declaration merging. + +### Extension points + +- Section providers: tool packages own their cross-call guidance (`tool:bash`, `tool:read`, …); this plugin owns `harness:identity` and `deployment:persona`. +- Variable providers: the agent loop registers `model` and `cwd`; any plugin can register the facts it owns (a future `date`, git state, …). +- Tool schema providers: `ToolRuntime` registers itself as a tool provider automatically. +- The [`system-prompt/assemble` waterfall](#live-events): cooperatively mutate or replace the assembly per caller before any complete-section constraint is enforced. + +Design rationale: [the prompt-variables Agent Note](../../../.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md). + +## Model Experience + +### System prompt + +#### What the model sees + +By default every assembly starts with the harness identity below, then the configured persona and ordered plugin sections after strict variable interpolation. `includeHarnessIdentity: false` omits only that fixed opener. Empty sections disappear; scoped sections and variables can shadow globals for one agent. The `system-prompt/assemble` waterfall determines the delivered prompt and tool schemas unless one effective section declares itself complete; that exact section then becomes the whole system prompt while the waterfall's contexts, tools, and variables remain. Ordered dynamic contexts are separate from system-prompt sections and become sourced user-role snapshots only when present. `includeRuntimeContext: false` or a scoped suppressor removes all such contexts, including listener additions, without disabling the services that own the underlying policy or state. + +##### Harness identity + +```markdown +You are an AI agent powered by DeepSeek Harness. +``` + +#### Token effect + +Identity is a fixed per-request cost when enabled. Persona and plugin text are repeated per request and scale with their rendered content. + +#### KV Cache effect + +Prefix-stable while identity, persona, variables, section text, and order render identically. Any change may invalidate reuse from the first changed system-prompt token. + +### Tool schemas + +#### What the model sees + +For shipped tools, the model receives the per-agent-visible subset of the [generated tool schemas](../../../docs/tool-catalog.md#tool-package-map), ordered by configuration or lexicographically after restrictions and assembly interception. Extensions can contribute additional definitions through the same registry. Sections and schema providers are separate assembly inputs, so a tool restriction does not remove independently registered guidance. + +#### Token effect + +Schema tokens repeat on every request. Restricting a tool removes its entire schema cost for that agent but not a separate prompt section; reordering changes cache shape but not semantic content. + +#### KV Cache effect + +Prefix-stable while the visible schema set, rendering, and order are unchanged. Registration, restriction, or reordering may invalidate reuse from the first changed schema token. + +## Known Limitations and Deferred Work + +- **Deployment-authored prompt text is config/composition only** — this plugin owns the global persona default, creator plugins may register agent-scoped shadows, and other sections come from the plugin that owns the fact; there is no end-user prompt-editing API. +- **No escape syntax for literal `{{…}}` braces** — every complete group is interpolated against registered variables; an escape is deferred until a real prompt needs one. +- **`toolOrder` misconfiguration surfaces at prompt assembly (the first turn), not at boot** — only shape violations throw at config load. +- **Sections sharing an `order` value tie-break by registration order** — a plugin-load artifact; determinism relies on the distinct-order band convention, unlike the canonicalized tool order. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.zh.md new file mode 100644 index 0000000..fcf5ebf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/README.zh.md @@ -0,0 +1,92 @@ +# dsh-system-prompt + +[English](README.md) | 中文 + +系统提示词组装注册表。插件可以贡献有序段、工具 schema 和具名变量。循环在每个步骤组装一次,并将结果渲染为完整的模型提示词。此插件拥有静态 harness 身份和全局部署 persona;agent(智能体)作用域的 persona 会遮蔽全局默认值。 + +## 配置 + +| 键 | 默认值 | 含义 | +|---|---|---| +| `includeHarnessIdentity` | `true` | 是否包含顺序为 −100 的固定开场白 `You are an AI agent powered by DeepSeek Harness.`。仅当兼容性部署拥有完整系统提示词时设为 false。 | +| `includeRuntimeContext` | `true` | 是否在组装中包含有序动态上下文。设为 false 时不会求值上下文提供方,并会在 waterfall 后丢弃 `system-prompt/assemble` 监听器添加的上下文;其他服务及其强制机制仍然生效。 | +| `persona` | `''` | 全局部署 persona 默认值:唯一由配置提供的提示词片段,渲染为顺序为 0 的 `deployment:persona` 段,除非 agent 作用域的贡献将其遮蔽。它是模板,完整的 `{{…}}` 组会严格按已注册变量解释(随附循环注册 `{{model}}`/`{{cwd}}`),目前没有表达字面量花括号的转义语法。为空 ⇒ 渲染时删除该段。 | +| `toolOrder` | 无 | 显式指定面向模型的工具顺序。该列表由 `ToolSchema.name` 组成,并且必须恰好包含一个 `''` 其余项标记(`TOOL_ORDER_REST`):已列工具按列表位置排列,未列工具则按名称字典序插入该标记所在的位置。缺席 ⇒ 直接按名称字典序排列。该顺序会在 `system-prompt/assemble` waterfall(瀑布式事件)之前应用于已收集的工具。与段的 `order` 排序一样,它会规范化注册表贡献的内容;注册顺序只是插件加载时序的产物。修改列表的 waterfall 监听器对其输出的确定性负责。配置错误会明确失败:列表没有恰好一个其余项或存在重复项,会在加载时抛出;已列名称没有对应已注册工具,会使每次 `assemble()` 被拒绝;工具提供方返回保留的其余项名称也会被拒绝。在随附循环下,轮次会在任何模型请求前失败。为何采用中心列表而非每插件权重,见[显式面向模型工具顺序](../../../.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.md)。 | + +## 服务:`SystemPrompt`(ctx 键:`systemPrompt`) + +### 公开 API + +- `ctx.systemPrompt.section(section: PromptSection): () => void`:贡献一个段。层由调用上下文的作用域决定:`agent.ctx` 只为该 agent 贡献,并在该处遮蔽同名全局段。一个 `complete: true` 段会在组装 waterfall 之后成为精确的完整提示词;有效 complete 段超过一个时,组装会被拒绝。同一层中的重复名称和非有限顺序会抛出。随调用 fiber 一并 dispose(资源释放)。 +- `ctx.systemPrompt.context(context: PromptContext): () => void`:为调用作用域贡献有序动态上下文。每次符合条件的组装都会求值提供方,并在随附循环下成为模型历史中带来源的 runtime-context 快照。 +- `ctx.systemPrompt.suppressRuntimeContext(): () => void`:抑制调用作用域的所有动态上下文贡献。多个注册会独立组合;只有当不再存在抑制器时,dispose 返回的 effect 才会恢复上下文。 +- `ctx.systemPrompt.tools(provider: (context: AssembleContext) => ToolProviderResult): () => void`:贡献工具 schema;每次组装时使用该次组装的上下文求值。`ToolProviderResult` = `{ schemas, knownNames? }`:`schemas` 是限制后的可见集合;`knownNames` 是限制前由 `toolOrder` 使用的全集。提供方不得返回名为 `TOOL_ORDER_REST` 的 schema。带作用域提供方只在其作用域的组装中查询。随调用 fiber 一并 dispose。 +- `ctx.systemPrompt.variable(name: string, provider: (context) => string | undefined): () => void`:贡献提示词变量,在段文本中以 `{{name}}` 引用。带作用域变量会为该 agent 遮蔽同名全局变量。同层重复或无法引用的名称会抛出;`undefined` 表示「本次组装没有值」。随调用 fiber 一并 dispose。 +- `ctx.systemPrompt.assemble(context?: AssembleContext): Promise`:为一个调用方组装提示词:将全局层与 `context.scope` 的层合并,并在变换 waterfall 前分离工具 schema。它经过按作用域筛选的 `system-prompt/assemble` waterfall,之后将一个有效的 complete 段恢复为唯一的提示词段,并实施任何活动的 runtime-context 抑制器。可选的 `context.signal` 显式控制本次组装请求;提供方与监听器可以配合该信号,但不得将它保留给另一轮次。存在多个 complete 段、已配置的 `toolOrder` 指名提供方 `knownNames` 全集以外的工具,或提供方返回保留的其余项名称时,调用会被拒绝。 + + + +### 实时事件 + +普通段以 `system-prompt/assemble` 的返回结果为准;complete 段则会在 waterfall 之后作为最终提示词约束生效。替换条目的监听器必须保留任何已启用的 Code Mode 或结构化输出协议。筛选需要在呈现、查找与执行之间保持一致时,应使用 [`ToolRuntime.restrict()`](../tools/README.md)。注册表变更通知不经过筛选。[system-prompt.md](../../../docs/subsystems/system-prompt.md#cordis-surface) 的生成区块拥有事件签名和分发约定。 + +### 关键类型 + +- `AssembleContext`:说明一次 `assemble()` 调用的用途。它可通过合并扩展;此处声明 `scope?: ScopeKey`(层选择器)与 `signal?: AbortSignal`(显式请求控制能力),而 `dsh-agent` 声明 `agent?: Agent`(类型化 DX 字段;绝不能在没有 `scope` 时设置,应使用 `assembleContextFor(agent, signal)`)。提供方必须容忍字段缺席,因为裸 `assemble()` 携带的是无作用域、无信号的空上下文。`signal` 是请求值,不是环境 Agent 执行 frame 的一部分。 +- `PromptSection`:`{ name, order, text, complete? }`。各段按 `order` 升序拼接。顺序区间:`-100` 是 harness 身份,`0` 是部署 persona,工具引导使用 `100–199`。协作式组装完成后,一个有效的 `complete` 段会抑制其他所有段。 +- `PromptAssembly`:`{ sections: AssembledSection[], tools: ToolSchema[], variables: Record }`。各段文本到达时已求值,但尚未插值;`variables` 保存所有已注册变量在当前上下文中求得的值。工具 schema 按设计属于组装结果:「模型获知自己能做什么」是一个连贯整体,尽管适配器把 schema 作为独立 wire 字段传输。 +- `renderPrompt(assembly)`:插值每个段中的 `{{variable}}` 引用,删除空段,并用空行连接。严格规则:未知引用(使用 `Object.hasOwn` 查找,因此 `{{constructor}}` 等原型名称未知)、已注册但无值的引用、格式错误的完整 `{{…}}` 组,或出现 `{{` 却没有形成完整组、而后文仍有 `}}`(`{{{model}}}`),都会抛出异常;明确失败胜过交付格式错误的提示词。孤立的 `{{` 如果后面任何位置都没有 `}}`,会按字面量通过;替换值绝不再次扫描。 + +可通过合并扩展:插件可以借助声明合并,为 `PromptAssembly` 和 `AssembleContext` 声明额外字段。 + +### 扩展点 + +- 段提供方:工具包拥有自身的跨调用指导(`tool:bash`、`tool:read` 等);此插件拥有 `harness:identity` 与 `deployment:persona`。 +- 变量提供方:agent loop(智能体循环)注册 `model` 与 `cwd`;任何插件都可以注册自己拥有的事实(未来的 `date`、git 状态等)。 +- 工具 schema 提供方:`ToolRuntime` 自动将自身注册为工具提供方。 +- [`system-prompt/assemble` waterfall](#live-events):按调用方协作式修改或替换组装结果,之后再实施 complete 段约束。 + +设计原理:[提示词变量 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)。 + +## 模型体验 + +### 系统提示词 + +#### 模型看到的内容 + +默认情况下,每次组装都从下方 harness 身份开始,然后在严格变量插值后追加已配置 persona 与有序插件段。`includeHarnessIdentity: false` 仅省略这个固定开场白。空段会消失;带作用域的段和变量可以为一个 agent 遮蔽全局项。`system-prompt/assemble` waterfall 决定交付的提示词与工具 schema,除非一个有效段声明自身为 complete;此时,该确切段会成为完整的系统提示词,而 waterfall 得到的上下文、工具和变量保持不变。有序动态上下文与系统提示词段分离,只在存在时才会成为带来源的 user 角色快照。`includeRuntimeContext: false` 或带作用域的抑制器会移除所有这类上下文,包括监听器添加的内容,但不会禁用拥有底层策略或状态的服务。 + +##### harness 身份 + +```markdown +You are an AI agent powered by DeepSeek Harness. +``` + +#### Token 影响 + +启用时,身份是每次请求的固定成本。Persona 与插件文本在每次请求中重复,成本随渲染内容增长。 + +#### KV Cache 影响 + +只要身份、persona、变量、段文本与顺序的渲染完全相同,前缀就保持稳定。任何变更都可能从第一个变化的系统提示词 token 起使复用失效。 + +### 工具 schema + +#### 模型看到的内容 + +对于已交付工具,模型会收到[生成工具 schema](../../../docs/tool-catalog.md#tool-package-map) 中对每个 agent 可见的子集;限制与组装拦截完成后,按配置或字典序排列。扩展可以通过同一注册表贡献其他定义。段与 schema 提供方是独立的组装输入,因此工具限制不会移除独立注册的引导。 + +#### Token 影响 + +schema token 在每次请求中重复。限制工具会为该 agent 移除其全部 schema 成本,但不会移除独立提示词段;重排序会改变缓存形状,但不改变语义内容。 + +#### KV Cache 影响 + +只要可见 schema 集合、渲染与顺序不变,前缀就保持稳定。注册、限制或重排序可能从第一个变化的 schema token 起使复用失效。 + +## 已知限制与暂缓事项 + +- **部署方编写的提示词文本只来自配置/组合**:此插件拥有全局 persona 默认值;创建方插件可以注册 agent 作用域的遮蔽项;其他段来自拥有相应事实的插件。不存在终端用户提示词编辑 API。 +- **没有表示字面量 `{{…}}` 花括号的转义语法**:每个完整组都会按已注册变量插值;只有实际提示词需要转义时才会实现。 +- **`toolOrder` 配置错误在提示词组装(首轮)时出现,而不是启动时**:只有形状违规会在配置加载时抛出。 +- **共享同一 `order` 值的段按注册顺序打破平局**:这是插件加载产物;确定性依赖在顺序分段内使用不同值的约定,与已规范化的工具顺序不同。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/index.js new file mode 100644 index 0000000..7c166a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/index.js @@ -0,0 +1,293 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { AnonymousEntries, NamedEntries, ScopedLayers, scopeTarget } from "@deepseek-ai/dsh-scope"; +//#region lib/types/index.js +/** +* Registry for ordered system sections, dynamic context, tool schemas, and prompt variables. +* +* @module @deepseek-ai/dsh-system-prompt +*/ +/** +* The deployment persona's section name and order. Exported because a +* composition can replace this slot — an agent preset shadows the +* deployment's persona with its own — and both sides naming the same section +* is what makes the replacement work rather than duplicate. +*/ +const PERSONA_SECTION = "deployment:persona"; +/** Prompt order of the persona slot; the first section a model reads. */ +const PERSONA_ORDER = 0; +/** Valid variable names: how they are written between the braces. */ +const VARIABLE_NAME = /^[a-z][a-z0-9_]*$/; +/** A complete `{{...}}` reference group at the scan position (validated after). */ +const GROUP_AT = /^\{\{([^{}]*)\}\}/; +/** Reserved {@link Config.toolOrder} marker for unlisted tools. */ +const TOOL_ORDER_REST = ""; +/** +* Validate duplicate names and the required {@link TOOL_ORDER_REST} marker. +* Registered names are checked later because plugins have not loaded yet. +*/ +function validateToolOrder(toolOrder) { + if (toolOrder === void 0) return void 0; + const seen = /* @__PURE__ */ new Set(); + for (const name of toolOrder) { + if (seen.has(name)) throw new Error(`toolOrder lists "${name}" more than once`); + seen.add(name); + } + if (!seen.has("")) throw new Error(`toolOrder must contain the "${TOOL_ORDER_REST}" rest entry (where unlisted tools are inserted)`); + return toolOrder; +} +/** +* Apply configured tool order, inserting unlisted tools lexicographically at +* {@link TOOL_ORDER_REST}. Unknown configured names fail; known but restricted +* names may be absent. +*/ +function orderTools(tools, toolOrder, knownNames) { + if (tools.find((tool) => tool.name === "") !== void 0) throw new Error(`tool provider returned reserved tool name "${TOOL_ORDER_REST}" (reserved for toolOrder's rest entry)`); + if (toolOrder === void 0) return tools.sort(compareToolNames); + const unknown = toolOrder.filter((name) => name !== "" && !knownNames.has(name)); + if (unknown.length > 0) throw new Error(`toolOrder lists unregistered tool${unknown.length > 1 ? "s" : ""} ${unknown.map((name) => `"${name}"`).join(", ")}; known tools: ${[...knownNames].sort().join(", ") || "(none)"}`); + const listed = new Set(toolOrder); + const rest = tools.filter((tool) => !listed.has(tool.name)).sort(compareToolNames); + return toolOrder.flatMap((name) => name === "" ? rest : tools.filter((tool) => tool.name === name)); +} +/** Lexicographic (code-unit) name comparison — locale-independent, so the order is identical on every machine. */ +function compareToolNames(a, b) { + return a.name < b.name ? -1 : a.name > b.name ? 1 : 0; +} +/** +* Interpolate strict `{{variable}}` references, drop empty sections, and join +* the rest with blank lines. Malformed, unknown, or undefined references throw; +* a lone `{{` without any later `}}` is literal prose, and substituted values +* are not scanned again. +* @param assembly - the assembly whose sections and variables to render. +* @returns the rendered prompt, or `''` when all sections are empty. +*/ +function renderPrompt(assembly) { + return assembly.sections.map((section) => interpolate(section, assembly.variables, "section")).filter((text) => text.length > 0).join("\n\n"); +} +/** +* Render the complete dynamic context snapshot. +* @param assembly - the assembly whose contexts and variables to render. +* @returns the current full snapshot, or `''` when no context is active. +*/ +function renderContextSnapshot(assembly) { + return joinContextSections(renderContextSections(assembly)); +} +/** +* The model-facing snapshot text for an already-rendered section list. +* +* A caller that also needs the sections renders them once and joins here, so a +* request does not interpolate every context twice. +* @param sections - sections from {@link renderContextSections}. +* @returns the current full snapshot, or `''` when no context is active. +*/ +function joinContextSections(sections) { + const body = sections.map((section) => section.text).join("\n\n"); + if (body.length === 0) return ""; + return `Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\n${body}`; +} +/** +* The same snapshot, kept as the named contributions it was assembled from. +* +* {@link renderContextSnapshot} joins these for the model; a consumer that +* presents the snapshot uses them to attribute each part to the subsystem that +* contributed it, without re-splitting the joined prose. +* @param assembly - the assembly whose contexts and variables to render. +* @returns one entry per contributing context that rendered to non-empty text. +*/ +function renderContextSections(assembly) { + return assembly.contexts.map((context) => ({ + name: context.name, + text: interpolate(context, assembly.variables, "context") + })).filter((section) => section.text.length > 0); +} +/** Interpolate one section or context and attribute diagnostics to its owning input. */ +function interpolate(input, variables, kind) { + const text = input.text; + let result = ""; + let last = 0; + for (let open = text.indexOf("{{"); open >= 0; open = text.indexOf("{{", last)) { + const group = GROUP_AT.exec(text.slice(open)); + if (group === null) { + if (text.indexOf("}}", open + 2) >= 0) throw new Error(`malformed prompt variable reference at "${text.slice(open, open + 16)}…" in ${kind} "${input.name}" (references are complete simple {{name}} groups)`); + result += text.slice(last, open + 2); + last = open + 2; + continue; + } + const name = group[0].slice(2, -2); + if (!VARIABLE_NAME.test(name)) throw new Error(`malformed prompt variable reference "{{${name}}}" in ${kind} "${input.name}" (variable names match ${String(VARIABLE_NAME)})`); + if (!Object.hasOwn(variables, name)) { + const known = Object.keys(variables); + throw new Error(`unknown prompt variable "{{${name}}}" in ${kind} "${input.name}"; registered variables: ${known.length > 0 ? known.join(", ") : "(none)"}`); + } + const value = variables[name]; + if (value === void 0) throw new Error(`prompt variable "{{${name}}}" has no value for this assembly (${kind} "${input.name}")`); + result += text.slice(last, open) + value; + last = open + group[0].length; + } + return result + text.slice(last); +} +/** All prompt registrations owned by one global or scoped layer. */ +var PromptLayer = class { + sections; + contexts; + runtimeContextSuppressors = new AnonymousEntries(); + toolProviders = new AnonymousEntries(); + variables; + /** + * Create one prompt layer with diagnostics specific to its ownership scope. + * @param scope - the scoped owner, or `undefined` for global registrations. + */ + constructor(scope) { + this.sections = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `prompt section "${name}" is already registered (for a per-agent override, register through that agent's \`agent.ctx\` instead)` : `prompt section "${name}" is already registered in this scope`)); + this.contexts = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `prompt context "${name}" is already registered (for a per-agent override, register through that agent's \`agent.ctx\` instead)` : `prompt context "${name}" is already registered in this scope`)); + this.variables = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `prompt variable "${name}" is already registered (for a per-agent value, register through that agent's \`agent.ctx\` instead)` : `prompt variable "${name}" is already registered in this scope`)); + } + /** @returns whether this layer owns no prompt registrations. */ + isEmpty() { + return this.sections.isEmpty() && this.contexts.isEmpty() && this.runtimeContextSuppressors.isEmpty() && this.toolProviders.isEmpty() && this.variables.isEmpty(); + } +}; +/** Registry service for the prompt inputs assembled before each model step. */ +var SystemPrompt = class extends Service { + static Config = z.object({ + includeHarnessIdentity: z.boolean().default(true), + includeRuntimeContext: z.boolean().default(true), + persona: z.string().default(""), + toolOrder: z.array(z.string()).default(void 0) + }); + layers = new ScopedLayers((scope) => new PromptLayer(scope), () => { + this.ctx.emit("system-prompt/change"); + }); + toolOrder; + constructor(ctx, config) { + super(ctx, "systemPrompt"); + this.toolOrder = validateToolOrder(config.toolOrder); + if (config.includeHarnessIdentity ?? true) this.section({ + name: "harness:identity", + order: -100, + text: "You are an AI agent powered by DeepSeek Harness." + }); + this.section({ + name: PERSONA_SECTION, + order: 0, + text: config.persona ?? "" + }); + if (!(config.includeRuntimeContext ?? true)) this.suppressRuntimeContext(); + } + /** + * Register an ordered prompt section in the calling context's scope. A scoped + * section shadows a global section with the same name; duplicates within one + * layer and non-finite orders throw. Registration and disposal emit + * `system-prompt/change`. + * @param section - the section to register. + * @returns the exact Cordis effect disposer. + */ + section(section) { + if (!Number.isFinite(section.order)) throw new TypeError(`prompt section "${section.name}" order must be a finite number`); + return this.layers.effect(this.ctx, (layer) => layer.sections.insert(section.name, section), { label: "systemPrompt.section()" }); + } + /** + * Register ordered dynamic context in the calling context's scope. Scoped + * entries shadow global entries with the same name. + * @param context - the context contribution to register. + * @returns the exact Cordis effect disposer. + */ + context(context) { + if (!Number.isFinite(context.order)) throw new TypeError(`prompt context "${context.name}" order must be a finite number`); + return this.layers.effect(this.ctx, (layer) => layer.contexts.insert(context.name, context), { label: "systemPrompt.context()" }); + } + /** + * Suppress every dynamic runtime-context contribution in the calling + * context's scope without changing the services that own or enforce those + * facts. Multiple suppressors remain independently disposable. + * @returns the exact Cordis effect disposer. + */ + suppressRuntimeContext() { + return this.layers.effect(this.ctx, (layer) => layer.runtimeContextSuppressors.append(true), { label: "systemPrompt.suppressRuntimeContext()" }); + } + /** + * Register a tool-schema provider in the calling context's scope. Global and + * matching scoped providers both contribute; returning the reserved + * {@link TOOL_ORDER_REST} name makes assembly fail. + * @param provider - evaluated for each assembly with its context. + * @returns the exact Cordis effect disposer. + */ + tools(provider) { + return this.layers.effect(this.ctx, (layer) => layer.toolProviders.append(provider), { label: "systemPrompt.tools()" }); + } + /** + * Register a prompt variable in the calling context's scope. Scoped values + * shadow globals; invalid or duplicate names throw. A provider may return + * `undefined`, but rendering a section that references that value then fails. + * @param name - the `[a-z][a-z0-9_]*` reference name. + * @param provider - evaluated for each assembly. + * @returns the exact Cordis effect disposer. + */ + variable(name, provider) { + if (!VARIABLE_NAME.test(name)) throw new Error(`invalid prompt variable name "${name}" (must match ${String(VARIABLE_NAME)})`); + return this.layers.effect(this.ctx, (layer) => layer.variables.insert(name, provider), { label: "systemPrompt.variable()" }); + } + /** + * Assemble global and scoped providers, detach tool parameters, apply + * canonical ordering, then run the assembly waterfall. Scoped sections and + * variables shadow globals. The returned waterfall value is authoritative + * except that an effective complete section is restored afterwards as the + * sole prompt section. + * @param context - the optional scope and plugin-defined assembly fields. + * @returns the post-waterfall assembly with any complete prompt enforced. + */ + async assemble(context = {}) { + const scope = context.scope; + const scopeLayers = this.layers.chainLayers(scope); + const runtimeContextSuppressed = !this.layers.global.runtimeContextSuppressors.isEmpty() || scopeLayers.some((layer) => !layer.runtimeContextSuppressors.isEmpty()); + const variables = {}; + for (const [name, provider] of this.layers.global.variables.entries()) variables[name] = provider(context); + for (const layer of scopeLayers) for (const [name, provider] of layer.variables.entries()) variables[name] = provider(context); + const sectionByName = this.layers.merge(scope, (layer) => layer.sections); + const contextByName = this.layers.merge(scope, (layer) => layer.contexts); + const providers = [...this.layers.global.toolProviders.values(), ...scopeLayers.flatMap((layer) => [...layer.toolProviders.values()])]; + const collected = []; + const knownNames = /* @__PURE__ */ new Set(); + for (const provider of providers) { + const result = provider(context); + const schemas = result.schemas.map(({ name, description, parameters }) => ({ + name, + description, + parameters: structuredClone(parameters) + })); + const acceptedKnownNames = result.knownNames ?? schemas.map((tool) => tool.name); + collected.push(...schemas); + for (const name of acceptedKnownNames) knownNames.add(name); + } + const sectionDefinitions = [...sectionByName.values()].sort((a, b) => a.order - b.order); + const completeSections = sectionDefinitions.filter((section) => section.complete === true); + if (completeSections.length > 1) throw new Error(`multiple complete prompt sections are active: ${completeSections.map((section) => JSON.stringify(section.name)).join(", ")}`); + let completeSection; + const assembly = { + sections: sectionDefinitions.map((section) => { + const assembled = { + name: section.name, + text: typeof section.text === "function" ? section.text(context) : section.text + }; + if (section.complete === true) completeSection = { ...assembled }; + return assembled; + }), + contexts: runtimeContextSuppressed ? [] : [...contextByName.values()].sort((a, b) => a.order - b.order).map((entry) => ({ + name: entry.name, + text: typeof entry.text === "function" ? entry.text(context) : entry.text + })), + tools: orderTools(collected, this.toolOrder, knownNames), + variables + }; + const transformed = await this.ctx.waterfall(scopeTarget(this, scope), "system-prompt/assemble", assembly, context, () => Promise.resolve(assembly)); + if (completeSection === void 0 && !runtimeContextSuppressed) return transformed; + return { + ...transformed, + sections: completeSection === void 0 ? transformed.sections : [completeSection], + contexts: runtimeContextSuppressed ? [] : transformed.contexts + }; + } +}; +//#endregion +export { PERSONA_ORDER, PERSONA_SECTION, SystemPrompt, SystemPrompt as default, TOOL_ORDER_REST, joinContextSections, renderContextSections, renderContextSnapshot, renderPrompt }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/invariant.js new file mode 100644 index 0000000..79e580f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/invariant.js @@ -0,0 +1,49 @@ +//#region lib/types/invariant.js +/** Package-owned prompt-assembly invariants. @module @deepseek-ai/dsh-system-prompt/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-system-prompt"; +const VARIABLE_NAME = /^[a-z][a-z0-9_]*$/; +/** Cordis companion plugin name. */ +const name = "system-prompt-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Validate the authoritative assembly returned by the waterfall. */ +function validateAssembly(assembly, fail) { + const sectionNames = /* @__PURE__ */ new Set(); + for (const section of assembly.sections) { + if (section.name.length === 0) fail("assembled section names must be non-empty"); + if (sectionNames.has(section.name)) fail(`assembled section name ${JSON.stringify(section.name)} is duplicated`); + sectionNames.add(section.name); + if (typeof section.text !== "string") fail(`assembled section ${JSON.stringify(section.name)} text must be a string`); + } + const contextNames = /* @__PURE__ */ new Set(); + for (const context of assembly.contexts) { + if (context.name.length === 0) fail("assembled context names must be non-empty"); + if (contextNames.has(context.name)) fail(`assembled context name ${JSON.stringify(context.name)} is duplicated`); + contextNames.add(context.name); + if (typeof context.text !== "string") fail(`assembled context ${JSON.stringify(context.name)} text must be a string`); + } + for (const tool of assembly.tools) if (tool.name.length === 0) fail("assembled tool names must be non-empty"); + for (const [name, value] of Object.entries(assembly.variables)) { + if (!VARIABLE_NAME.test(name)) fail(`assembled variable name ${JSON.stringify(name)} is invalid`); + if (value !== void 0 && typeof value !== "string") fail(`assembled variable ${JSON.stringify(name)} must be a string or undefined`); + } +} +/** Install validation around the authoritative assembly waterfall result. */ +const install = (ctx, fail) => { + ctx.on("system-prompt/assemble", async (_assembly, _context, next) => { + const assembled = await next(); + validateAssembly(assembled, fail); + return assembled; + }, { + global: true, + prepend: true + }); +}; +/** +* Register the system-prompt invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/index.d.ts new file mode 100644 index 0000000..0fc6c78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/index.d.ts @@ -0,0 +1,231 @@ +/** + * Registry for ordered system sections, dynamic context, tool schemas, and prompt variables. + * + * @module @deepseek-ai/dsh-system-prompt + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { ScopeKey, Scoped } from '@deepseek-ai/dsh-scope'; +import type { ContextSnapshotSection, ToolSchema } from '@deepseek-ai/dsh-llm'; +declare module '@deepseek-ai/cordis' { + interface Context { + systemPrompt: SystemPrompt; + } + interface Events { + /** + * Expert waterfall over the assembled sections, contexts, tools, and variables. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners + * receive only that scope's assemblies. The returned value is authoritative. + * A supplied signal controls only this explicit assembly request and must not + * be retained to control later turns. A registered complete section is + * restored after this waterfall, so listeners cannot add to or replace + * that scope's system prompt. + * @param assembly - the mutable assembly built from registered providers. + * @param context - the caller's per-assembly context. + * @mode waterfall + */ + 'system-prompt/assemble'(this: Scoped, assembly: PromptAssembly, context: AssembleContext, next: () => Promise): Promise; + /** + * Emitted when any prompt provider changes. This registry notification is + * unfiltered because a global change affects every scope. + * @mode emit + */ + 'system-prompt/change'(): void; + } +} +/** Merge-extensible context for one prompt assembly. */ +export interface AssembleContext { + /** + * Scope whose providers and waterfall listeners participate. When absent, + * only global providers and subject-less listeners participate. + */ + scope?: ScopeKey; + /** Explicit control signal for the turn that requested this assembly, when any. */ + signal?: AbortSignal; +} +/** One contributed section of the system prompt (registry input). */ +export interface PromptSection { + /** Unique name — a duplicate registration throws (see {@link SystemPrompt.section}). */ + readonly name: string; + /** + * Sections are concatenated in ascending order. Convention: `-100` is the + * harness identity, `0` the deployment persona, tool guidance uses 100–199; + * other negative orders also render before the persona. + */ + readonly order: number; + /** + * Static text or a provider evaluated at each assembly with that assembly's + * {@link AssembleContext}. The text may reference `{{variable}}`s — they are + * interpolated later, by {@link renderPrompt}. + */ + readonly text: string | ((context: AssembleContext) => string); + /** + * Treat this contribution as the complete system prompt. Assembly still + * runs the cooperative waterfall so tools, contexts, and variables can be + * resolved, then restores this exact section as the sole prompt section. + * More than one effective complete section makes assembly fail. + */ + readonly complete?: boolean; +} +/** Dynamic model context materialized as a durable user-role snapshot. */ +export interface PromptContext { + /** Unique name — a duplicate registration throws (see {@link SystemPrompt.context}). */ + readonly name: string; + /** Contexts are joined in ascending order. */ + readonly order: number; + /** Static text or a provider evaluated for each assembly. Empty text contributes nothing. */ + readonly text: string | ((context: AssembleContext) => string); +} +/** One section of an assembly: {@link PromptSection} with its text resolved. */ +export interface AssembledSection { + /** The contributing section's unique name. */ + name: string; + /** The resolved (but not yet interpolated) section text. */ + text: string; +} +/** One resolved dynamic context contribution. */ +export interface AssembledContext { + /** The contributing context's unique name. */ + name: string; + /** The resolved text before variable interpolation. */ + text: string; +} +/** Tool schemas visible in one assembly and their pre-restriction name set. */ +export interface ToolProviderResult { + /** The schemas this provider contributes to THIS assembly. */ + readonly schemas: readonly ToolSchema[]; + /** The pre-restriction name universe for config validation (defaults to `schemas`' names). */ + readonly knownNames?: readonly string[]; +} +/** + * Merge-extensible assembled model input. Sections and contexts remain + * uninterpolated until rendered; tools are already in canonical order. + */ +export interface PromptAssembly { + sections: AssembledSection[]; + contexts: AssembledContext[]; + tools: ToolSchema[]; + variables: Record; +} +/** + * The deployment persona's section name and order. Exported because a + * composition can replace this slot — an agent preset shadows the + * deployment's persona with its own — and both sides naming the same section + * is what makes the replacement work rather than duplicate. + */ +export declare const PERSONA_SECTION = "deployment:persona"; +/** Prompt order of the persona slot; the first section a model reads. */ +export declare const PERSONA_ORDER = 0; +/** Reserved {@link Config.toolOrder} marker for unlisted tools. */ +export declare const TOOL_ORDER_REST = ""; +/** Plugin config: the deployment-authored fragment of the system prompt (see {@link Config.persona} for its contract). */ +export interface Config { + /** Include the fixed DeepSeek Harness identity before the deployment persona (default true). */ + includeHarnessIdentity?: boolean; + /** Include dynamic runtime-context snapshots in model history (default true). */ + includeRuntimeContext?: boolean; + /** + * Deployment-wide order-0 persona template. A scoped section named + * `deployment:persona` shadows it; `{{variable}}` references are strict. + */ + persona?: string; + /** + * Model-facing tool names in order, with {@link TOOL_ORDER_REST} exactly once. + * Invalid fields fail at load and unknown names fail at assembly; known names + * hidden in one scope may be absent there. Omitted means lexicographic order. + */ + toolOrder?: string[]; +} +/** + * Interpolate strict `{{variable}}` references, drop empty sections, and join + * the rest with blank lines. Malformed, unknown, or undefined references throw; + * a lone `{{` without any later `}}` is literal prose, and substituted values + * are not scanned again. + * @param assembly - the assembly whose sections and variables to render. + * @returns the rendered prompt, or `''` when all sections are empty. + */ +export declare function renderPrompt(assembly: PromptAssembly): string; +/** + * Render the complete dynamic context snapshot. + * @param assembly - the assembly whose contexts and variables to render. + * @returns the current full snapshot, or `''` when no context is active. + */ +export declare function renderContextSnapshot(assembly: PromptAssembly): string; +/** + * The model-facing snapshot text for an already-rendered section list. + * + * A caller that also needs the sections renders them once and joins here, so a + * request does not interpolate every context twice. + * @param sections - sections from {@link renderContextSections}. + * @returns the current full snapshot, or `''` when no context is active. + */ +export declare function joinContextSections(sections: readonly ContextSnapshotSection[]): string; +/** + * The same snapshot, kept as the named contributions it was assembled from. + * + * {@link renderContextSnapshot} joins these for the model; a consumer that + * presents the snapshot uses them to attribute each part to the subsystem that + * contributed it, without re-splitting the joined prose. + * @param assembly - the assembly whose contexts and variables to render. + * @returns one entry per contributing context that rendered to non-empty text. + */ +export declare function renderContextSections(assembly: PromptAssembly): ContextSnapshotSection[]; +/** Registry service for the prompt inputs assembled before each model step. */ +export declare class SystemPrompt extends Service { + static Config: z; + private readonly layers; + private readonly toolOrder; + constructor(ctx: Context, config: Config); + /** + * Register an ordered prompt section in the calling context's scope. A scoped + * section shadows a global section with the same name; duplicates within one + * layer and non-finite orders throw. Registration and disposal emit + * `system-prompt/change`. + * @param section - the section to register. + * @returns the exact Cordis effect disposer. + */ + section(section: PromptSection): () => void; + /** + * Register ordered dynamic context in the calling context's scope. Scoped + * entries shadow global entries with the same name. + * @param context - the context contribution to register. + * @returns the exact Cordis effect disposer. + */ + context(context: PromptContext): () => void; + /** + * Suppress every dynamic runtime-context contribution in the calling + * context's scope without changing the services that own or enforce those + * facts. Multiple suppressors remain independently disposable. + * @returns the exact Cordis effect disposer. + */ + suppressRuntimeContext(): () => void; + /** + * Register a tool-schema provider in the calling context's scope. Global and + * matching scoped providers both contribute; returning the reserved + * {@link TOOL_ORDER_REST} name makes assembly fail. + * @param provider - evaluated for each assembly with its context. + * @returns the exact Cordis effect disposer. + */ + tools(provider: (context: AssembleContext) => ToolProviderResult): () => void; + /** + * Register a prompt variable in the calling context's scope. Scoped values + * shadow globals; invalid or duplicate names throw. A provider may return + * `undefined`, but rendering a section that references that value then fails. + * @param name - the `[a-z][a-z0-9_]*` reference name. + * @param provider - evaluated for each assembly. + * @returns the exact Cordis effect disposer. + */ + variable(name: string, provider: (context: AssembleContext) => string | undefined): () => void; + /** + * Assemble global and scoped providers, detach tool parameters, apply + * canonical ordering, then run the assembly waterfall. Scoped sections and + * variables shadow globals. The returned waterfall value is authoritative + * except that an effective complete section is restored afterwards as the + * sole prompt section. + * @param context - the optional scope and plugin-defined assembly fields. + * @returns the post-waterfall assembly with any complete prompt enforced. + */ + assemble(context?: AssembleContext): Promise; +} +export default SystemPrompt; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/invariant.d.ts new file mode 100644 index 0000000..89c90d3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned prompt-assembly invariants. @module @deepseek-ai/dsh-system-prompt/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "system-prompt-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the system-prompt invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/package.json new file mode 100644 index 0000000..5bfbf49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt/package.json @@ -0,0 +1,49 @@ +{ + "name": "@deepseek-ai/dsh-system-prompt", + "description": "System prompt assembly registry for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/system-prompt" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.i18n.yaml new file mode 100644 index 0000000..28bc2cf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/system-prompt/README.md +README.md: d750a507e628e7609af542227e4528d4d4934ce8 +README.zh.md: fcf5ebfad1e467b060b2efaa6c6f2816d75945d1 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.md new file mode 100644 index 0000000..d750a50 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.md @@ -0,0 +1,90 @@ +# dsh-system-prompt + +English | [中文](README.zh.md) + +System prompt assembly registry. Plugins contribute ordered sections, tool schemas, and named variables. The loop assembles once per step and renders the result as the complete model prompt. This plugin owns the static harness identity and global deployment persona; an agent-scoped persona shadows the global default. + +## Config + +| Key | Default | Meaning | +|---|---|---| +| `includeHarnessIdentity` | `true` | Include the fixed `You are an AI agent powered by DeepSeek Harness.` order-−100 opener. Set false only when a compatibility deployment owns the complete system prompt. | +| `includeRuntimeContext` | `true` | Include ordered dynamic contexts in assembly. When false, context providers are not evaluated and contexts added by `system-prompt/assemble` listeners are discarded after the waterfall; other services and their enforcement remain active. | +| `persona` | `''` | The global deployment-persona default: the ONE config-authored prompt fragment, rendered as the order-0 `deployment:persona` section unless an agent-scoped contribution shadows it. A template — complete `{{…}}` groups are interpreted strictly against the registered variables (the shipped loop registers `{{model}}`/`{{cwd}}`), with no escape syntax for literal braces yet. Empty ⇒ the section is dropped at render. | +| `toolOrder` | — | Explicit model-facing tool order, as a list of `ToolSchema.name`s with one `''` rest entry (`TOOL_ORDER_REST`): listed tools take their listed position, unlisted tools land at the rest entry in lexicographic name order. Absent ⇒ plain lexicographic name order. Applied to the collected tools BEFORE the `system-prompt/assemble` waterfall — like the sections' `order` sort, it canonicalizes what the registry contributed (registration order is a plugin-load artifact), and a waterfall listener that mutates the list owns the determinism of what it emits. Misconfiguration fails loud: a list without exactly one rest entry, or with duplicates, throws at load; a listed name with no registered tool rejects every `assemble()`; a tool provider returning the reserved rest-entry name also rejects. Under the shipped loop the turn fails before any model request. Why a central list and not per-plugin weights: [Explicit model-facing tool order](../../../.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.md). | + +## Service: `SystemPrompt` (ctx key: `systemPrompt`) + +### Public API + +- `ctx.systemPrompt.section(section: PromptSection): () => void` Contribute a section. The layer is the calling context's scope: `agent.ctx` contributes to that agent alone, shadowing a same-named global section there. A `complete: true` section becomes the exact complete prompt after the assembly waterfall; more than one effective complete section rejects assembly. Duplicate names within one layer and non-finite orders throw. Disposed with the calling fiber. +- `ctx.systemPrompt.context(context: PromptContext): () => void` Contribute ordered dynamic context for the calling scope. Providers are evaluated for each eligible assembly and become a sourced runtime-context snapshot in model history under the shipped loop. +- `ctx.systemPrompt.suppressRuntimeContext(): () => void` Suppress every dynamic-context contribution for the calling scope. Multiple registrations compose independently; disposing the returned effect restores context when no suppressor remains. +- `ctx.systemPrompt.tools(provider: (context: AssembleContext) => ToolProviderResult): () => void` Contribute tool schemas, evaluated at each assembly with that assembly's context. `ToolProviderResult` = `{ schemas, knownNames? }`: `schemas` is the post-restriction visible set; `knownNames` is the pre-restriction universe used by `toolOrder`. A provider must not return a schema named `TOOL_ORDER_REST`. Scoped providers are consulted only for their scope's assemblies. Disposed with the calling fiber. +- `ctx.systemPrompt.variable(name: string, provider: (context) => string | undefined): () => void` Contribute a prompt variable, referenced from section text as `{{name}}`. Scoped variables shadow a same-named global for that agent. Duplicate-in-layer or unreferenceable names throw; `undefined` means "no value for this assembly". Disposed with the calling fiber. +- `ctx.systemPrompt.assemble(context?: AssembleContext): Promise` Assemble the prompt for one caller: the global layer merged with `context.scope`'s layer, with tool schemas detached before the transform waterfall. Runs through the scope-filtered `system-prompt/assemble` waterfall, then restores an effective complete section as the sole prompt section and enforces any active runtime-context suppressor. An optional `context.signal` explicitly controls this assembly request; providers and listeners may cooperate with it but must not retain it for another turn. Rejects for multiple complete sections, when a configured `toolOrder` names a tool outside the providers' `knownNames` universe, or when a provider returns the reserved rest-entry name. + +### Live events + +`system-prompt/assemble` is authoritative for ordinary sections; a complete section is the final prompt constraint applied after the waterfall. Listeners that replace entries must preserve any active Code Mode or structured-output protocol. Use [`ToolRuntime.restrict()`](../tools/README.md) when filtering must stay aligned across presentation, lookup, and execution. Registry-change notifications are unfiltered. The generated region of [system-prompt.md](../../../docs/subsystems/system-prompt.md#cordis-surface) owns signatures and dispatch contracts. + +### Key types + +- `AssembleContext` — what one `assemble()` call is FOR. Merge-extensible; declares `scope?: ScopeKey` (the layer selector) and `signal?: AbortSignal` (the explicit request control capability) here, while `dsh-agent` declares `agent?: Agent` (the typed DX field — never set without `scope`; use `assembleContextFor(agent, signal)`). Providers must tolerate absent fields because a bare `assemble()` carries an empty, scope-less, signal-less context. `signal` is a request value, not part of the ambient Agent execution frame. +- `PromptSection` — `{ name, order, text, complete? }`. Sections are concatenated in ascending `order`. Order bands: `-100` is the harness identity, `0` the deployment persona, tool guidance uses `100–199`. One effective `complete` section suppresses all other sections after cooperative assembly. +- `PromptAssembly` — `{ sections: AssembledSection[], tools: ToolSchema[], variables: Record }`. Section texts arrive resolved but not yet interpolated; `variables` holds every registered variable resolved against the context. Tool schemas are part of the assembly by design: "what the model is told it can do" is one coherent thing, even though adapters transmit schemas as a separate wire field. +- `renderPrompt(assembly)` — interpolates `{{variable}}` references in each section, drops empty sections, joins with blank lines. STRICT: an unknown reference (`Object.hasOwn` lookup — prototype names like `{{constructor}}` are unknown), a registered-but-valueless reference, a malformed complete `{{…}}` group, or a `{{` that opens no complete group while a `}}` still follows (`{{{model}}}`) throws — fail loud beats shipping a malformed prompt. A lone `{{` with no `}}` anywhere after it passes through verbatim; substituted values are never re-scanned. + +Merge-extensible: plugins can declare extra fields on `PromptAssembly` and `AssembleContext` via declaration merging. + +### Extension points + +- Section providers: tool packages own their cross-call guidance (`tool:bash`, `tool:read`, …); this plugin owns `harness:identity` and `deployment:persona`. +- Variable providers: the agent loop registers `model` and `cwd`; any plugin can register the facts it owns (a future `date`, git state, …). +- Tool schema providers: `ToolRuntime` registers itself as a tool provider automatically. +- The [`system-prompt/assemble` waterfall](#live-events): cooperatively mutate or replace the assembly per caller before any complete-section constraint is enforced. + +Design rationale: [the prompt-variables Agent Note](../../../.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md). + +## Model Experience + +### System prompt + +#### What the model sees + +By default every assembly starts with the harness identity below, then the configured persona and ordered plugin sections after strict variable interpolation. `includeHarnessIdentity: false` omits only that fixed opener. Empty sections disappear; scoped sections and variables can shadow globals for one agent. The `system-prompt/assemble` waterfall determines the delivered prompt and tool schemas unless one effective section declares itself complete; that exact section then becomes the whole system prompt while the waterfall's contexts, tools, and variables remain. Ordered dynamic contexts are separate from system-prompt sections and become sourced user-role snapshots only when present. `includeRuntimeContext: false` or a scoped suppressor removes all such contexts, including listener additions, without disabling the services that own the underlying policy or state. + +##### Harness identity + +```markdown +You are an AI agent powered by DeepSeek Harness. +``` + +#### Token effect + +Identity is a fixed per-request cost when enabled. Persona and plugin text are repeated per request and scale with their rendered content. + +#### KV Cache effect + +Prefix-stable while identity, persona, variables, section text, and order render identically. Any change may invalidate reuse from the first changed system-prompt token. + +### Tool schemas + +#### What the model sees + +For shipped tools, the model receives the per-agent-visible subset of the [generated tool schemas](../../../docs/tool-catalog.md#tool-package-map), ordered by configuration or lexicographically after restrictions and assembly interception. Extensions can contribute additional definitions through the same registry. Sections and schema providers are separate assembly inputs, so a tool restriction does not remove independently registered guidance. + +#### Token effect + +Schema tokens repeat on every request. Restricting a tool removes its entire schema cost for that agent but not a separate prompt section; reordering changes cache shape but not semantic content. + +#### KV Cache effect + +Prefix-stable while the visible schema set, rendering, and order are unchanged. Registration, restriction, or reordering may invalidate reuse from the first changed schema token. + +## Known Limitations and Deferred Work + +- **Deployment-authored prompt text is config/composition only** — this plugin owns the global persona default, creator plugins may register agent-scoped shadows, and other sections come from the plugin that owns the fact; there is no end-user prompt-editing API. +- **No escape syntax for literal `{{…}}` braces** — every complete group is interpolated against registered variables; an escape is deferred until a real prompt needs one. +- **`toolOrder` misconfiguration surfaces at prompt assembly (the first turn), not at boot** — only shape violations throw at config load. +- **Sections sharing an `order` value tie-break by registration order** — a plugin-load artifact; determinism relies on the distinct-order band convention, unlike the canonicalized tool order. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.zh.md new file mode 100644 index 0000000..fcf5ebf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/README.zh.md @@ -0,0 +1,92 @@ +# dsh-system-prompt + +[English](README.md) | 中文 + +系统提示词组装注册表。插件可以贡献有序段、工具 schema 和具名变量。循环在每个步骤组装一次,并将结果渲染为完整的模型提示词。此插件拥有静态 harness 身份和全局部署 persona;agent(智能体)作用域的 persona 会遮蔽全局默认值。 + +## 配置 + +| 键 | 默认值 | 含义 | +|---|---|---| +| `includeHarnessIdentity` | `true` | 是否包含顺序为 −100 的固定开场白 `You are an AI agent powered by DeepSeek Harness.`。仅当兼容性部署拥有完整系统提示词时设为 false。 | +| `includeRuntimeContext` | `true` | 是否在组装中包含有序动态上下文。设为 false 时不会求值上下文提供方,并会在 waterfall 后丢弃 `system-prompt/assemble` 监听器添加的上下文;其他服务及其强制机制仍然生效。 | +| `persona` | `''` | 全局部署 persona 默认值:唯一由配置提供的提示词片段,渲染为顺序为 0 的 `deployment:persona` 段,除非 agent 作用域的贡献将其遮蔽。它是模板,完整的 `{{…}}` 组会严格按已注册变量解释(随附循环注册 `{{model}}`/`{{cwd}}`),目前没有表达字面量花括号的转义语法。为空 ⇒ 渲染时删除该段。 | +| `toolOrder` | 无 | 显式指定面向模型的工具顺序。该列表由 `ToolSchema.name` 组成,并且必须恰好包含一个 `''` 其余项标记(`TOOL_ORDER_REST`):已列工具按列表位置排列,未列工具则按名称字典序插入该标记所在的位置。缺席 ⇒ 直接按名称字典序排列。该顺序会在 `system-prompt/assemble` waterfall(瀑布式事件)之前应用于已收集的工具。与段的 `order` 排序一样,它会规范化注册表贡献的内容;注册顺序只是插件加载时序的产物。修改列表的 waterfall 监听器对其输出的确定性负责。配置错误会明确失败:列表没有恰好一个其余项或存在重复项,会在加载时抛出;已列名称没有对应已注册工具,会使每次 `assemble()` 被拒绝;工具提供方返回保留的其余项名称也会被拒绝。在随附循环下,轮次会在任何模型请求前失败。为何采用中心列表而非每插件权重,见[显式面向模型工具顺序](../../../.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.md)。 | + +## 服务:`SystemPrompt`(ctx 键:`systemPrompt`) + +### 公开 API + +- `ctx.systemPrompt.section(section: PromptSection): () => void`:贡献一个段。层由调用上下文的作用域决定:`agent.ctx` 只为该 agent 贡献,并在该处遮蔽同名全局段。一个 `complete: true` 段会在组装 waterfall 之后成为精确的完整提示词;有效 complete 段超过一个时,组装会被拒绝。同一层中的重复名称和非有限顺序会抛出。随调用 fiber 一并 dispose(资源释放)。 +- `ctx.systemPrompt.context(context: PromptContext): () => void`:为调用作用域贡献有序动态上下文。每次符合条件的组装都会求值提供方,并在随附循环下成为模型历史中带来源的 runtime-context 快照。 +- `ctx.systemPrompt.suppressRuntimeContext(): () => void`:抑制调用作用域的所有动态上下文贡献。多个注册会独立组合;只有当不再存在抑制器时,dispose 返回的 effect 才会恢复上下文。 +- `ctx.systemPrompt.tools(provider: (context: AssembleContext) => ToolProviderResult): () => void`:贡献工具 schema;每次组装时使用该次组装的上下文求值。`ToolProviderResult` = `{ schemas, knownNames? }`:`schemas` 是限制后的可见集合;`knownNames` 是限制前由 `toolOrder` 使用的全集。提供方不得返回名为 `TOOL_ORDER_REST` 的 schema。带作用域提供方只在其作用域的组装中查询。随调用 fiber 一并 dispose。 +- `ctx.systemPrompt.variable(name: string, provider: (context) => string | undefined): () => void`:贡献提示词变量,在段文本中以 `{{name}}` 引用。带作用域变量会为该 agent 遮蔽同名全局变量。同层重复或无法引用的名称会抛出;`undefined` 表示「本次组装没有值」。随调用 fiber 一并 dispose。 +- `ctx.systemPrompt.assemble(context?: AssembleContext): Promise`:为一个调用方组装提示词:将全局层与 `context.scope` 的层合并,并在变换 waterfall 前分离工具 schema。它经过按作用域筛选的 `system-prompt/assemble` waterfall,之后将一个有效的 complete 段恢复为唯一的提示词段,并实施任何活动的 runtime-context 抑制器。可选的 `context.signal` 显式控制本次组装请求;提供方与监听器可以配合该信号,但不得将它保留给另一轮次。存在多个 complete 段、已配置的 `toolOrder` 指名提供方 `knownNames` 全集以外的工具,或提供方返回保留的其余项名称时,调用会被拒绝。 + + + +### 实时事件 + +普通段以 `system-prompt/assemble` 的返回结果为准;complete 段则会在 waterfall 之后作为最终提示词约束生效。替换条目的监听器必须保留任何已启用的 Code Mode 或结构化输出协议。筛选需要在呈现、查找与执行之间保持一致时,应使用 [`ToolRuntime.restrict()`](../tools/README.md)。注册表变更通知不经过筛选。[system-prompt.md](../../../docs/subsystems/system-prompt.md#cordis-surface) 的生成区块拥有事件签名和分发约定。 + +### 关键类型 + +- `AssembleContext`:说明一次 `assemble()` 调用的用途。它可通过合并扩展;此处声明 `scope?: ScopeKey`(层选择器)与 `signal?: AbortSignal`(显式请求控制能力),而 `dsh-agent` 声明 `agent?: Agent`(类型化 DX 字段;绝不能在没有 `scope` 时设置,应使用 `assembleContextFor(agent, signal)`)。提供方必须容忍字段缺席,因为裸 `assemble()` 携带的是无作用域、无信号的空上下文。`signal` 是请求值,不是环境 Agent 执行 frame 的一部分。 +- `PromptSection`:`{ name, order, text, complete? }`。各段按 `order` 升序拼接。顺序区间:`-100` 是 harness 身份,`0` 是部署 persona,工具引导使用 `100–199`。协作式组装完成后,一个有效的 `complete` 段会抑制其他所有段。 +- `PromptAssembly`:`{ sections: AssembledSection[], tools: ToolSchema[], variables: Record }`。各段文本到达时已求值,但尚未插值;`variables` 保存所有已注册变量在当前上下文中求得的值。工具 schema 按设计属于组装结果:「模型获知自己能做什么」是一个连贯整体,尽管适配器把 schema 作为独立 wire 字段传输。 +- `renderPrompt(assembly)`:插值每个段中的 `{{variable}}` 引用,删除空段,并用空行连接。严格规则:未知引用(使用 `Object.hasOwn` 查找,因此 `{{constructor}}` 等原型名称未知)、已注册但无值的引用、格式错误的完整 `{{…}}` 组,或出现 `{{` 却没有形成完整组、而后文仍有 `}}`(`{{{model}}}`),都会抛出异常;明确失败胜过交付格式错误的提示词。孤立的 `{{` 如果后面任何位置都没有 `}}`,会按字面量通过;替换值绝不再次扫描。 + +可通过合并扩展:插件可以借助声明合并,为 `PromptAssembly` 和 `AssembleContext` 声明额外字段。 + +### 扩展点 + +- 段提供方:工具包拥有自身的跨调用指导(`tool:bash`、`tool:read` 等);此插件拥有 `harness:identity` 与 `deployment:persona`。 +- 变量提供方:agent loop(智能体循环)注册 `model` 与 `cwd`;任何插件都可以注册自己拥有的事实(未来的 `date`、git 状态等)。 +- 工具 schema 提供方:`ToolRuntime` 自动将自身注册为工具提供方。 +- [`system-prompt/assemble` waterfall](#live-events):按调用方协作式修改或替换组装结果,之后再实施 complete 段约束。 + +设计原理:[提示词变量 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)。 + +## 模型体验 + +### 系统提示词 + +#### 模型看到的内容 + +默认情况下,每次组装都从下方 harness 身份开始,然后在严格变量插值后追加已配置 persona 与有序插件段。`includeHarnessIdentity: false` 仅省略这个固定开场白。空段会消失;带作用域的段和变量可以为一个 agent 遮蔽全局项。`system-prompt/assemble` waterfall 决定交付的提示词与工具 schema,除非一个有效段声明自身为 complete;此时,该确切段会成为完整的系统提示词,而 waterfall 得到的上下文、工具和变量保持不变。有序动态上下文与系统提示词段分离,只在存在时才会成为带来源的 user 角色快照。`includeRuntimeContext: false` 或带作用域的抑制器会移除所有这类上下文,包括监听器添加的内容,但不会禁用拥有底层策略或状态的服务。 + +##### harness 身份 + +```markdown +You are an AI agent powered by DeepSeek Harness. +``` + +#### Token 影响 + +启用时,身份是每次请求的固定成本。Persona 与插件文本在每次请求中重复,成本随渲染内容增长。 + +#### KV Cache 影响 + +只要身份、persona、变量、段文本与顺序的渲染完全相同,前缀就保持稳定。任何变更都可能从第一个变化的系统提示词 token 起使复用失效。 + +### 工具 schema + +#### 模型看到的内容 + +对于已交付工具,模型会收到[生成工具 schema](../../../docs/tool-catalog.md#tool-package-map) 中对每个 agent 可见的子集;限制与组装拦截完成后,按配置或字典序排列。扩展可以通过同一注册表贡献其他定义。段与 schema 提供方是独立的组装输入,因此工具限制不会移除独立注册的引导。 + +#### Token 影响 + +schema token 在每次请求中重复。限制工具会为该 agent 移除其全部 schema 成本,但不会移除独立提示词段;重排序会改变缓存形状,但不改变语义内容。 + +#### KV Cache 影响 + +只要可见 schema 集合、渲染与顺序不变,前缀就保持稳定。注册、限制或重排序可能从第一个变化的 schema token 起使复用失效。 + +## 已知限制与暂缓事项 + +- **部署方编写的提示词文本只来自配置/组合**:此插件拥有全局 persona 默认值;创建方插件可以注册 agent 作用域的遮蔽项;其他段来自拥有相应事实的插件。不存在终端用户提示词编辑 API。 +- **没有表示字面量 `{{…}}` 花括号的转义语法**:每个完整组都会按已注册变量插值;只有实际提示词需要转义时才会实现。 +- **`toolOrder` 配置错误在提示词组装(首轮)时出现,而不是启动时**:只有形状违规会在配置加载时抛出。 +- **共享同一 `order` 值的段按注册顺序打破平局**:这是插件加载产物;确定性依赖在顺序分段内使用不同值的约定,与已规范化的工具顺序不同。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/index.js new file mode 100644 index 0000000..7c166a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/index.js @@ -0,0 +1,293 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { AnonymousEntries, NamedEntries, ScopedLayers, scopeTarget } from "@deepseek-ai/dsh-scope"; +//#region lib/types/index.js +/** +* Registry for ordered system sections, dynamic context, tool schemas, and prompt variables. +* +* @module @deepseek-ai/dsh-system-prompt +*/ +/** +* The deployment persona's section name and order. Exported because a +* composition can replace this slot — an agent preset shadows the +* deployment's persona with its own — and both sides naming the same section +* is what makes the replacement work rather than duplicate. +*/ +const PERSONA_SECTION = "deployment:persona"; +/** Prompt order of the persona slot; the first section a model reads. */ +const PERSONA_ORDER = 0; +/** Valid variable names: how they are written between the braces. */ +const VARIABLE_NAME = /^[a-z][a-z0-9_]*$/; +/** A complete `{{...}}` reference group at the scan position (validated after). */ +const GROUP_AT = /^\{\{([^{}]*)\}\}/; +/** Reserved {@link Config.toolOrder} marker for unlisted tools. */ +const TOOL_ORDER_REST = ""; +/** +* Validate duplicate names and the required {@link TOOL_ORDER_REST} marker. +* Registered names are checked later because plugins have not loaded yet. +*/ +function validateToolOrder(toolOrder) { + if (toolOrder === void 0) return void 0; + const seen = /* @__PURE__ */ new Set(); + for (const name of toolOrder) { + if (seen.has(name)) throw new Error(`toolOrder lists "${name}" more than once`); + seen.add(name); + } + if (!seen.has("")) throw new Error(`toolOrder must contain the "${TOOL_ORDER_REST}" rest entry (where unlisted tools are inserted)`); + return toolOrder; +} +/** +* Apply configured tool order, inserting unlisted tools lexicographically at +* {@link TOOL_ORDER_REST}. Unknown configured names fail; known but restricted +* names may be absent. +*/ +function orderTools(tools, toolOrder, knownNames) { + if (tools.find((tool) => tool.name === "") !== void 0) throw new Error(`tool provider returned reserved tool name "${TOOL_ORDER_REST}" (reserved for toolOrder's rest entry)`); + if (toolOrder === void 0) return tools.sort(compareToolNames); + const unknown = toolOrder.filter((name) => name !== "" && !knownNames.has(name)); + if (unknown.length > 0) throw new Error(`toolOrder lists unregistered tool${unknown.length > 1 ? "s" : ""} ${unknown.map((name) => `"${name}"`).join(", ")}; known tools: ${[...knownNames].sort().join(", ") || "(none)"}`); + const listed = new Set(toolOrder); + const rest = tools.filter((tool) => !listed.has(tool.name)).sort(compareToolNames); + return toolOrder.flatMap((name) => name === "" ? rest : tools.filter((tool) => tool.name === name)); +} +/** Lexicographic (code-unit) name comparison — locale-independent, so the order is identical on every machine. */ +function compareToolNames(a, b) { + return a.name < b.name ? -1 : a.name > b.name ? 1 : 0; +} +/** +* Interpolate strict `{{variable}}` references, drop empty sections, and join +* the rest with blank lines. Malformed, unknown, or undefined references throw; +* a lone `{{` without any later `}}` is literal prose, and substituted values +* are not scanned again. +* @param assembly - the assembly whose sections and variables to render. +* @returns the rendered prompt, or `''` when all sections are empty. +*/ +function renderPrompt(assembly) { + return assembly.sections.map((section) => interpolate(section, assembly.variables, "section")).filter((text) => text.length > 0).join("\n\n"); +} +/** +* Render the complete dynamic context snapshot. +* @param assembly - the assembly whose contexts and variables to render. +* @returns the current full snapshot, or `''` when no context is active. +*/ +function renderContextSnapshot(assembly) { + return joinContextSections(renderContextSections(assembly)); +} +/** +* The model-facing snapshot text for an already-rendered section list. +* +* A caller that also needs the sections renders them once and joins here, so a +* request does not interpolate every context twice. +* @param sections - sections from {@link renderContextSections}. +* @returns the current full snapshot, or `''` when no context is active. +*/ +function joinContextSections(sections) { + const body = sections.map((section) => section.text).join("\n\n"); + if (body.length === 0) return ""; + return `Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\n${body}`; +} +/** +* The same snapshot, kept as the named contributions it was assembled from. +* +* {@link renderContextSnapshot} joins these for the model; a consumer that +* presents the snapshot uses them to attribute each part to the subsystem that +* contributed it, without re-splitting the joined prose. +* @param assembly - the assembly whose contexts and variables to render. +* @returns one entry per contributing context that rendered to non-empty text. +*/ +function renderContextSections(assembly) { + return assembly.contexts.map((context) => ({ + name: context.name, + text: interpolate(context, assembly.variables, "context") + })).filter((section) => section.text.length > 0); +} +/** Interpolate one section or context and attribute diagnostics to its owning input. */ +function interpolate(input, variables, kind) { + const text = input.text; + let result = ""; + let last = 0; + for (let open = text.indexOf("{{"); open >= 0; open = text.indexOf("{{", last)) { + const group = GROUP_AT.exec(text.slice(open)); + if (group === null) { + if (text.indexOf("}}", open + 2) >= 0) throw new Error(`malformed prompt variable reference at "${text.slice(open, open + 16)}…" in ${kind} "${input.name}" (references are complete simple {{name}} groups)`); + result += text.slice(last, open + 2); + last = open + 2; + continue; + } + const name = group[0].slice(2, -2); + if (!VARIABLE_NAME.test(name)) throw new Error(`malformed prompt variable reference "{{${name}}}" in ${kind} "${input.name}" (variable names match ${String(VARIABLE_NAME)})`); + if (!Object.hasOwn(variables, name)) { + const known = Object.keys(variables); + throw new Error(`unknown prompt variable "{{${name}}}" in ${kind} "${input.name}"; registered variables: ${known.length > 0 ? known.join(", ") : "(none)"}`); + } + const value = variables[name]; + if (value === void 0) throw new Error(`prompt variable "{{${name}}}" has no value for this assembly (${kind} "${input.name}")`); + result += text.slice(last, open) + value; + last = open + group[0].length; + } + return result + text.slice(last); +} +/** All prompt registrations owned by one global or scoped layer. */ +var PromptLayer = class { + sections; + contexts; + runtimeContextSuppressors = new AnonymousEntries(); + toolProviders = new AnonymousEntries(); + variables; + /** + * Create one prompt layer with diagnostics specific to its ownership scope. + * @param scope - the scoped owner, or `undefined` for global registrations. + */ + constructor(scope) { + this.sections = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `prompt section "${name}" is already registered (for a per-agent override, register through that agent's \`agent.ctx\` instead)` : `prompt section "${name}" is already registered in this scope`)); + this.contexts = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `prompt context "${name}" is already registered (for a per-agent override, register through that agent's \`agent.ctx\` instead)` : `prompt context "${name}" is already registered in this scope`)); + this.variables = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `prompt variable "${name}" is already registered (for a per-agent value, register through that agent's \`agent.ctx\` instead)` : `prompt variable "${name}" is already registered in this scope`)); + } + /** @returns whether this layer owns no prompt registrations. */ + isEmpty() { + return this.sections.isEmpty() && this.contexts.isEmpty() && this.runtimeContextSuppressors.isEmpty() && this.toolProviders.isEmpty() && this.variables.isEmpty(); + } +}; +/** Registry service for the prompt inputs assembled before each model step. */ +var SystemPrompt = class extends Service { + static Config = z.object({ + includeHarnessIdentity: z.boolean().default(true), + includeRuntimeContext: z.boolean().default(true), + persona: z.string().default(""), + toolOrder: z.array(z.string()).default(void 0) + }); + layers = new ScopedLayers((scope) => new PromptLayer(scope), () => { + this.ctx.emit("system-prompt/change"); + }); + toolOrder; + constructor(ctx, config) { + super(ctx, "systemPrompt"); + this.toolOrder = validateToolOrder(config.toolOrder); + if (config.includeHarnessIdentity ?? true) this.section({ + name: "harness:identity", + order: -100, + text: "You are an AI agent powered by DeepSeek Harness." + }); + this.section({ + name: PERSONA_SECTION, + order: 0, + text: config.persona ?? "" + }); + if (!(config.includeRuntimeContext ?? true)) this.suppressRuntimeContext(); + } + /** + * Register an ordered prompt section in the calling context's scope. A scoped + * section shadows a global section with the same name; duplicates within one + * layer and non-finite orders throw. Registration and disposal emit + * `system-prompt/change`. + * @param section - the section to register. + * @returns the exact Cordis effect disposer. + */ + section(section) { + if (!Number.isFinite(section.order)) throw new TypeError(`prompt section "${section.name}" order must be a finite number`); + return this.layers.effect(this.ctx, (layer) => layer.sections.insert(section.name, section), { label: "systemPrompt.section()" }); + } + /** + * Register ordered dynamic context in the calling context's scope. Scoped + * entries shadow global entries with the same name. + * @param context - the context contribution to register. + * @returns the exact Cordis effect disposer. + */ + context(context) { + if (!Number.isFinite(context.order)) throw new TypeError(`prompt context "${context.name}" order must be a finite number`); + return this.layers.effect(this.ctx, (layer) => layer.contexts.insert(context.name, context), { label: "systemPrompt.context()" }); + } + /** + * Suppress every dynamic runtime-context contribution in the calling + * context's scope without changing the services that own or enforce those + * facts. Multiple suppressors remain independently disposable. + * @returns the exact Cordis effect disposer. + */ + suppressRuntimeContext() { + return this.layers.effect(this.ctx, (layer) => layer.runtimeContextSuppressors.append(true), { label: "systemPrompt.suppressRuntimeContext()" }); + } + /** + * Register a tool-schema provider in the calling context's scope. Global and + * matching scoped providers both contribute; returning the reserved + * {@link TOOL_ORDER_REST} name makes assembly fail. + * @param provider - evaluated for each assembly with its context. + * @returns the exact Cordis effect disposer. + */ + tools(provider) { + return this.layers.effect(this.ctx, (layer) => layer.toolProviders.append(provider), { label: "systemPrompt.tools()" }); + } + /** + * Register a prompt variable in the calling context's scope. Scoped values + * shadow globals; invalid or duplicate names throw. A provider may return + * `undefined`, but rendering a section that references that value then fails. + * @param name - the `[a-z][a-z0-9_]*` reference name. + * @param provider - evaluated for each assembly. + * @returns the exact Cordis effect disposer. + */ + variable(name, provider) { + if (!VARIABLE_NAME.test(name)) throw new Error(`invalid prompt variable name "${name}" (must match ${String(VARIABLE_NAME)})`); + return this.layers.effect(this.ctx, (layer) => layer.variables.insert(name, provider), { label: "systemPrompt.variable()" }); + } + /** + * Assemble global and scoped providers, detach tool parameters, apply + * canonical ordering, then run the assembly waterfall. Scoped sections and + * variables shadow globals. The returned waterfall value is authoritative + * except that an effective complete section is restored afterwards as the + * sole prompt section. + * @param context - the optional scope and plugin-defined assembly fields. + * @returns the post-waterfall assembly with any complete prompt enforced. + */ + async assemble(context = {}) { + const scope = context.scope; + const scopeLayers = this.layers.chainLayers(scope); + const runtimeContextSuppressed = !this.layers.global.runtimeContextSuppressors.isEmpty() || scopeLayers.some((layer) => !layer.runtimeContextSuppressors.isEmpty()); + const variables = {}; + for (const [name, provider] of this.layers.global.variables.entries()) variables[name] = provider(context); + for (const layer of scopeLayers) for (const [name, provider] of layer.variables.entries()) variables[name] = provider(context); + const sectionByName = this.layers.merge(scope, (layer) => layer.sections); + const contextByName = this.layers.merge(scope, (layer) => layer.contexts); + const providers = [...this.layers.global.toolProviders.values(), ...scopeLayers.flatMap((layer) => [...layer.toolProviders.values()])]; + const collected = []; + const knownNames = /* @__PURE__ */ new Set(); + for (const provider of providers) { + const result = provider(context); + const schemas = result.schemas.map(({ name, description, parameters }) => ({ + name, + description, + parameters: structuredClone(parameters) + })); + const acceptedKnownNames = result.knownNames ?? schemas.map((tool) => tool.name); + collected.push(...schemas); + for (const name of acceptedKnownNames) knownNames.add(name); + } + const sectionDefinitions = [...sectionByName.values()].sort((a, b) => a.order - b.order); + const completeSections = sectionDefinitions.filter((section) => section.complete === true); + if (completeSections.length > 1) throw new Error(`multiple complete prompt sections are active: ${completeSections.map((section) => JSON.stringify(section.name)).join(", ")}`); + let completeSection; + const assembly = { + sections: sectionDefinitions.map((section) => { + const assembled = { + name: section.name, + text: typeof section.text === "function" ? section.text(context) : section.text + }; + if (section.complete === true) completeSection = { ...assembled }; + return assembled; + }), + contexts: runtimeContextSuppressed ? [] : [...contextByName.values()].sort((a, b) => a.order - b.order).map((entry) => ({ + name: entry.name, + text: typeof entry.text === "function" ? entry.text(context) : entry.text + })), + tools: orderTools(collected, this.toolOrder, knownNames), + variables + }; + const transformed = await this.ctx.waterfall(scopeTarget(this, scope), "system-prompt/assemble", assembly, context, () => Promise.resolve(assembly)); + if (completeSection === void 0 && !runtimeContextSuppressed) return transformed; + return { + ...transformed, + sections: completeSection === void 0 ? transformed.sections : [completeSection], + contexts: runtimeContextSuppressed ? [] : transformed.contexts + }; + } +}; +//#endregion +export { PERSONA_ORDER, PERSONA_SECTION, SystemPrompt, SystemPrompt as default, TOOL_ORDER_REST, joinContextSections, renderContextSections, renderContextSnapshot, renderPrompt }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/invariant.js new file mode 100644 index 0000000..79e580f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/invariant.js @@ -0,0 +1,49 @@ +//#region lib/types/invariant.js +/** Package-owned prompt-assembly invariants. @module @deepseek-ai/dsh-system-prompt/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-system-prompt"; +const VARIABLE_NAME = /^[a-z][a-z0-9_]*$/; +/** Cordis companion plugin name. */ +const name = "system-prompt-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Validate the authoritative assembly returned by the waterfall. */ +function validateAssembly(assembly, fail) { + const sectionNames = /* @__PURE__ */ new Set(); + for (const section of assembly.sections) { + if (section.name.length === 0) fail("assembled section names must be non-empty"); + if (sectionNames.has(section.name)) fail(`assembled section name ${JSON.stringify(section.name)} is duplicated`); + sectionNames.add(section.name); + if (typeof section.text !== "string") fail(`assembled section ${JSON.stringify(section.name)} text must be a string`); + } + const contextNames = /* @__PURE__ */ new Set(); + for (const context of assembly.contexts) { + if (context.name.length === 0) fail("assembled context names must be non-empty"); + if (contextNames.has(context.name)) fail(`assembled context name ${JSON.stringify(context.name)} is duplicated`); + contextNames.add(context.name); + if (typeof context.text !== "string") fail(`assembled context ${JSON.stringify(context.name)} text must be a string`); + } + for (const tool of assembly.tools) if (tool.name.length === 0) fail("assembled tool names must be non-empty"); + for (const [name, value] of Object.entries(assembly.variables)) { + if (!VARIABLE_NAME.test(name)) fail(`assembled variable name ${JSON.stringify(name)} is invalid`); + if (value !== void 0 && typeof value !== "string") fail(`assembled variable ${JSON.stringify(name)} must be a string or undefined`); + } +} +/** Install validation around the authoritative assembly waterfall result. */ +const install = (ctx, fail) => { + ctx.on("system-prompt/assemble", async (_assembly, _context, next) => { + const assembled = await next(); + validateAssembly(assembled, fail); + return assembled; + }, { + global: true, + prepend: true + }); +}; +/** +* Register the system-prompt invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/index.d.ts new file mode 100644 index 0000000..0fc6c78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/index.d.ts @@ -0,0 +1,231 @@ +/** + * Registry for ordered system sections, dynamic context, tool schemas, and prompt variables. + * + * @module @deepseek-ai/dsh-system-prompt + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { ScopeKey, Scoped } from '@deepseek-ai/dsh-scope'; +import type { ContextSnapshotSection, ToolSchema } from '@deepseek-ai/dsh-llm'; +declare module '@deepseek-ai/cordis' { + interface Context { + systemPrompt: SystemPrompt; + } + interface Events { + /** + * Expert waterfall over the assembled sections, contexts, tools, and variables. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners + * receive only that scope's assemblies. The returned value is authoritative. + * A supplied signal controls only this explicit assembly request and must not + * be retained to control later turns. A registered complete section is + * restored after this waterfall, so listeners cannot add to or replace + * that scope's system prompt. + * @param assembly - the mutable assembly built from registered providers. + * @param context - the caller's per-assembly context. + * @mode waterfall + */ + 'system-prompt/assemble'(this: Scoped, assembly: PromptAssembly, context: AssembleContext, next: () => Promise): Promise; + /** + * Emitted when any prompt provider changes. This registry notification is + * unfiltered because a global change affects every scope. + * @mode emit + */ + 'system-prompt/change'(): void; + } +} +/** Merge-extensible context for one prompt assembly. */ +export interface AssembleContext { + /** + * Scope whose providers and waterfall listeners participate. When absent, + * only global providers and subject-less listeners participate. + */ + scope?: ScopeKey; + /** Explicit control signal for the turn that requested this assembly, when any. */ + signal?: AbortSignal; +} +/** One contributed section of the system prompt (registry input). */ +export interface PromptSection { + /** Unique name — a duplicate registration throws (see {@link SystemPrompt.section}). */ + readonly name: string; + /** + * Sections are concatenated in ascending order. Convention: `-100` is the + * harness identity, `0` the deployment persona, tool guidance uses 100–199; + * other negative orders also render before the persona. + */ + readonly order: number; + /** + * Static text or a provider evaluated at each assembly with that assembly's + * {@link AssembleContext}. The text may reference `{{variable}}`s — they are + * interpolated later, by {@link renderPrompt}. + */ + readonly text: string | ((context: AssembleContext) => string); + /** + * Treat this contribution as the complete system prompt. Assembly still + * runs the cooperative waterfall so tools, contexts, and variables can be + * resolved, then restores this exact section as the sole prompt section. + * More than one effective complete section makes assembly fail. + */ + readonly complete?: boolean; +} +/** Dynamic model context materialized as a durable user-role snapshot. */ +export interface PromptContext { + /** Unique name — a duplicate registration throws (see {@link SystemPrompt.context}). */ + readonly name: string; + /** Contexts are joined in ascending order. */ + readonly order: number; + /** Static text or a provider evaluated for each assembly. Empty text contributes nothing. */ + readonly text: string | ((context: AssembleContext) => string); +} +/** One section of an assembly: {@link PromptSection} with its text resolved. */ +export interface AssembledSection { + /** The contributing section's unique name. */ + name: string; + /** The resolved (but not yet interpolated) section text. */ + text: string; +} +/** One resolved dynamic context contribution. */ +export interface AssembledContext { + /** The contributing context's unique name. */ + name: string; + /** The resolved text before variable interpolation. */ + text: string; +} +/** Tool schemas visible in one assembly and their pre-restriction name set. */ +export interface ToolProviderResult { + /** The schemas this provider contributes to THIS assembly. */ + readonly schemas: readonly ToolSchema[]; + /** The pre-restriction name universe for config validation (defaults to `schemas`' names). */ + readonly knownNames?: readonly string[]; +} +/** + * Merge-extensible assembled model input. Sections and contexts remain + * uninterpolated until rendered; tools are already in canonical order. + */ +export interface PromptAssembly { + sections: AssembledSection[]; + contexts: AssembledContext[]; + tools: ToolSchema[]; + variables: Record; +} +/** + * The deployment persona's section name and order. Exported because a + * composition can replace this slot — an agent preset shadows the + * deployment's persona with its own — and both sides naming the same section + * is what makes the replacement work rather than duplicate. + */ +export declare const PERSONA_SECTION = "deployment:persona"; +/** Prompt order of the persona slot; the first section a model reads. */ +export declare const PERSONA_ORDER = 0; +/** Reserved {@link Config.toolOrder} marker for unlisted tools. */ +export declare const TOOL_ORDER_REST = ""; +/** Plugin config: the deployment-authored fragment of the system prompt (see {@link Config.persona} for its contract). */ +export interface Config { + /** Include the fixed DeepSeek Harness identity before the deployment persona (default true). */ + includeHarnessIdentity?: boolean; + /** Include dynamic runtime-context snapshots in model history (default true). */ + includeRuntimeContext?: boolean; + /** + * Deployment-wide order-0 persona template. A scoped section named + * `deployment:persona` shadows it; `{{variable}}` references are strict. + */ + persona?: string; + /** + * Model-facing tool names in order, with {@link TOOL_ORDER_REST} exactly once. + * Invalid fields fail at load and unknown names fail at assembly; known names + * hidden in one scope may be absent there. Omitted means lexicographic order. + */ + toolOrder?: string[]; +} +/** + * Interpolate strict `{{variable}}` references, drop empty sections, and join + * the rest with blank lines. Malformed, unknown, or undefined references throw; + * a lone `{{` without any later `}}` is literal prose, and substituted values + * are not scanned again. + * @param assembly - the assembly whose sections and variables to render. + * @returns the rendered prompt, or `''` when all sections are empty. + */ +export declare function renderPrompt(assembly: PromptAssembly): string; +/** + * Render the complete dynamic context snapshot. + * @param assembly - the assembly whose contexts and variables to render. + * @returns the current full snapshot, or `''` when no context is active. + */ +export declare function renderContextSnapshot(assembly: PromptAssembly): string; +/** + * The model-facing snapshot text for an already-rendered section list. + * + * A caller that also needs the sections renders them once and joins here, so a + * request does not interpolate every context twice. + * @param sections - sections from {@link renderContextSections}. + * @returns the current full snapshot, or `''` when no context is active. + */ +export declare function joinContextSections(sections: readonly ContextSnapshotSection[]): string; +/** + * The same snapshot, kept as the named contributions it was assembled from. + * + * {@link renderContextSnapshot} joins these for the model; a consumer that + * presents the snapshot uses them to attribute each part to the subsystem that + * contributed it, without re-splitting the joined prose. + * @param assembly - the assembly whose contexts and variables to render. + * @returns one entry per contributing context that rendered to non-empty text. + */ +export declare function renderContextSections(assembly: PromptAssembly): ContextSnapshotSection[]; +/** Registry service for the prompt inputs assembled before each model step. */ +export declare class SystemPrompt extends Service { + static Config: z; + private readonly layers; + private readonly toolOrder; + constructor(ctx: Context, config: Config); + /** + * Register an ordered prompt section in the calling context's scope. A scoped + * section shadows a global section with the same name; duplicates within one + * layer and non-finite orders throw. Registration and disposal emit + * `system-prompt/change`. + * @param section - the section to register. + * @returns the exact Cordis effect disposer. + */ + section(section: PromptSection): () => void; + /** + * Register ordered dynamic context in the calling context's scope. Scoped + * entries shadow global entries with the same name. + * @param context - the context contribution to register. + * @returns the exact Cordis effect disposer. + */ + context(context: PromptContext): () => void; + /** + * Suppress every dynamic runtime-context contribution in the calling + * context's scope without changing the services that own or enforce those + * facts. Multiple suppressors remain independently disposable. + * @returns the exact Cordis effect disposer. + */ + suppressRuntimeContext(): () => void; + /** + * Register a tool-schema provider in the calling context's scope. Global and + * matching scoped providers both contribute; returning the reserved + * {@link TOOL_ORDER_REST} name makes assembly fail. + * @param provider - evaluated for each assembly with its context. + * @returns the exact Cordis effect disposer. + */ + tools(provider: (context: AssembleContext) => ToolProviderResult): () => void; + /** + * Register a prompt variable in the calling context's scope. Scoped values + * shadow globals; invalid or duplicate names throw. A provider may return + * `undefined`, but rendering a section that references that value then fails. + * @param name - the `[a-z][a-z0-9_]*` reference name. + * @param provider - evaluated for each assembly. + * @returns the exact Cordis effect disposer. + */ + variable(name: string, provider: (context: AssembleContext) => string | undefined): () => void; + /** + * Assemble global and scoped providers, detach tool parameters, apply + * canonical ordering, then run the assembly waterfall. Scoped sections and + * variables shadow globals. The returned waterfall value is authoritative + * except that an effective complete section is restored afterwards as the + * sole prompt section. + * @param context - the optional scope and plugin-defined assembly fields. + * @returns the post-waterfall assembly with any complete prompt enforced. + */ + assemble(context?: AssembleContext): Promise; +} +export default SystemPrompt; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/invariant.d.ts new file mode 100644 index 0000000..89c90d3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned prompt-assembly invariants. @module @deepseek-ai/dsh-system-prompt/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "system-prompt-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the system-prompt invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/package.json new file mode 100644 index 0000000..30a8c1d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt/package.json @@ -0,0 +1,49 @@ +{ + "name": "@deepseek-ai/dsh-system-prompt", + "description": "System prompt assembly registry for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/system-prompt" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.i18n.yaml new file mode 100644 index 0000000..c000fae --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/timeout/README.md +README.md: c29f6a7661abf40eadafc7637c1bbca509a62a24 +README.zh.md: ca05fcaf0ac7f3379d746e11a123294e3febf436 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.md new file mode 100644 index 0000000..c29f6a7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.md @@ -0,0 +1,70 @@ +# dsh-timeout + +English | [中文](README.zh.md) + +The **timing-and-classification** half of a timeout — a zero-dependency library of pure functions (no runtime harness deps) shared by every capability that clamps a caller's timeout hint, arms a deadline, and later has to tell "timed out" apart from "cancelled". + +It owns **no termination**. The signal it hands out only *notifies*; actually stopping the work stays in each capability, because that mechanism differs — bash SIGKILLs an OS process group, web tears down a `fetch` socket — and no shared layer can own all of them. This is the boundary the [Agent Note](../../../.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.md) draws: share the timing/classification, keep the hard kill local. + +It is a **library, not a service or plugin**: no `ctx`, registers nothing, holds no state, emits no events. A "timeout service" would have to understand how to stop every capability's work — exactly the knowledge a microkernel keeps out of shared layers. + +## API + +```ts +import { clampTimeout, deadline, idleWatchdog, MAX_TIMER_DELAY_MS, timeoutOf, TimeoutReason } from '@deepseek-ai/dsh-timeout' +``` + +| Export | Role | +|---|---| +| `clampTimeout(requested, def, max, name?)` | Validate the caller's optional positive-finite hint, fill from `def`, cap at `max`. Throws (with `name`) on a non-positive/non-finite hint. | +| `deadline(upstream, timeoutMs, code)` | Fuse `upstream` cancellation with a timeout into one `AbortSignal` (`AbortSignal.any`); the timeout carries a `TimeoutReason`. `[Symbol.dispose]` clears the timer. | +| `idleWatchdog(upstream, timeoutMs, code)` | Keep one stable fused signal and arm only while its guarded async-iterator `next()` is outstanding. Resolution disarms; later demand or `pulse()` activity rearms; disposal clears; concurrent demand rejects. | +| `MAX_TIMER_DELAY_MS` | Largest delay Node schedules without clamping it to one millisecond (`2_147_483_647`). Timer-owning config must not exceed it. | +| `timeoutOf(signal \| { reason }, code?)` | Recover the `TimeoutReason` from an aborted signal/error, else `undefined` — the timeout-vs-cancel classifier. Pass `code` to match only THIS deadline's timer (see nesting below). | +| `TimeoutReason` | The internal reason (`code` + `timeoutMs`) stamped on a timeout abort. Not a public error — providers translate it into their own error/field. | + +## The `timeoutMs <= 0` sentinel + +`0` is the **internal** "no timeout" value for backend-owned background work (bash `start()`): `deadline()` arms no timer and forwards only `upstream`; with no upstream either, it returns a never-aborting signal plus a no-op disposer, so every caller keeps one call shape. External request hints validate as **positive finite** via `clampTimeout` before they reach `deadline`, so `0` is never a model-/plugin-facing "disable timeout" value. + +## Usage shape + +```ts +import { deadline, timeoutOf } from '@deepseek-ai/dsh-timeout' + +declare function runWork(options: { signal: AbortSignal }): Promise + +// Scope-lifetime consumer (foreground bash, one fetch): `using` disposes the timer. +export async function runWithDeadline(upstream: AbortSignal | undefined, timeoutMs: number): Promise { + using d = deadline(upstream, timeoutMs, 'BASH_TIMEOUT') + const outcome = await runWork({ signal: d.signal }) // work listens on d.signal and terminates itself + const timedOut = timeoutOf(d.signal, 'BASH_TIMEOUT') !== undefined // classify the first abort, scoped to OUR code + const aborted = d.signal.aborted && !timedOut // mutually exclusive: timeout won, or cancel did + return { outcome, timedOut, aborted } +} +``` + +The signal only *notifies* — the caller MUST attach its own termination (`d.signal.addEventListener('abort', kill)`, or hand `d.signal` to `fetch`). Racing a promise against a timer would resolve the tool-call while the child process or socket leaks on; handing out a signal forces a real termination path to exist. + +Pass your own `code` to `timeoutOf` so classification composes under nesting. When `upstream` is itself a deadline signal, `AbortSignal.any` preserves its `TimeoutReason` if that timer fires first. Scoping to your code makes a foreign timeout read as an ordinary upstream cancel instead of claiming that the local timer expired. + +For a streamed transport, create one `idleWatchdog`, pass its stable `signal` into the transport, and call `watchdog.next(iterator)` for each provider read. Call `watchdog.pulse()` when transport activity does not yield an iterator value. The interval must be positive, finite, and no greater than `MAX_TIMER_DELAY_MS`; Node otherwise clamps it to one millisecond. It measures only outstanding demand, so no timer runs while downstream code renders or otherwise waits before asking for the next chunk. The primitive still only notifies, so the transport must observe the stable signal; the DeepSeek and pi-ai adapters prove that timeout closes their real response body or SDK request. + +## What does NOT get a timeout + +Local file `read`/`write`/`edit` take no `timeoutMs`: file IO runs untimed because a deadline would kill work the OS will still finish. See [the filesystem subsystem page](../../../docs/subsystems/filesystem.md). + +## Model Experience + +Indirectly, through consumers such as `dsh-tool-call-timeout-policy`, which may replace a provider result with a retained timeout error or suppress a late result. + +#### KV Cache effect + +No direct invalidation; the named consumer owns any request-prefix changes. + +## Known Limitations and Deferred Work + +- **Notification only** — a deadline cannot stop work that ignores its signal; every capability still needs its own socket/process/task termination path. +- **`timeoutMs <= 0` is internal vocabulary** — it disables the local timer only after an owning backend has resolved policy, never as a public model/plugin knob. +- **The first abort reason wins classification** — when an upstream cancellation beats the local timer, this layer cannot later report that its own timeout would also have elapsed. +- **An idle watchdog is not a total deadline** — it rearms per outstanding iterator demand and deliberately excludes consumer think time. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.zh.md new file mode 100644 index 0000000..ca05fca --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/README.zh.md @@ -0,0 +1,70 @@ +# dsh-timeout + +[English](README.md) | 中文 + +超时的**时序与分类**部分:一个零依赖纯函数库(无运行时 harness 依赖),由每个需要限制调用方超时提示、启动 deadline,并在之后区分「已超时」与「已取消」的能力共享。 + +它**不负责终止**。它发出的信号只会*通知*;真正停止工作仍由各能力负责,因为机制各不相同:bash 对操作系统进程组发送 SIGKILL,web 关闭 `fetch` 套接字,没有任何共享层能够承担全部终止机制。[Agent Note](../../../.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.md) 将边界划定为:共享时序/分类,将强制终止保留在本地。 + +它是**库,而非服务或插件**:没有 `ctx`,不注册任何内容,不持有状态,也不发出事件。「超时服务」必须了解如何停止每项能力的工作,这正是微内核要排除在共享层之外的知识。 + +## 对外接口 + +```ts +import { clampTimeout, deadline, idleWatchdog, MAX_TIMER_DELAY_MS, timeoutOf, TimeoutReason } from '@deepseek-ai/dsh-timeout' +``` + +| 导出项 | 职责 | +|---|---| +| `clampTimeout(requested, def, max, name?)` | 验证调用方可选的、值为正且有限的提示,从 `def` 填充,并限制在 `max` 以内。如果提示为非正数或非有限数,则抛出错误(包含 `name`)。 | +| `deadline(upstream, timeoutMs, code)` | 将 `upstream` 取消与超时融合为一个 `AbortSignal`(`AbortSignal.any`);超时携带 `TimeoutReason`。`[Symbol.dispose]` 清除 timer。 | +| `idleWatchdog(upstream, timeoutMs, code)` | 保持一个稳定的融合信号,并且只在受保护的异步迭代器 `next()` 尚未完成时启动 timer。完成后停止 timer;后续需求或 `pulse()` 活动会重新启动 timer;dispose(资源释放)时清除;并发需求被拒绝。 | +| `MAX_TIMER_DELAY_MS` | Node 在不将延迟限制为 1 毫秒时可调度的最大延迟(`2_147_483_647`)。负责 timer 的配置不得超过该值。 | +| `timeoutOf(signal \| { reason }, code?)` | 从已中止的信号/错误中恢复 `TimeoutReason`,否则返回 `undefined`,即超时与取消的分类器。传入 `code` 可仅匹配这个 deadline 的 timer(见下文的嵌套)。 | +| `TimeoutReason` | 标记在超时中止上的内部原因(`code` + `timeoutMs`)。它不是公开错误;提供方将其转换为自己的错误/字段。 | + +## `timeoutMs <= 0` 哨兵值 + +`0` 是后端自有后台工作(bash `start()`)使用的**内部**「无超时」值。`deadline()` 不启动 timer,只转发 `upstream`;如果也没有 upstream,它将返回永不中止的信号和无操作 disposer,因此每个调用方都能保持同一种调用形态。外部请求提示会通过 `clampTimeout` 验证为**正有限数**,之后才进入 `deadline`,因此 `0` 绝不是面向模型/插件的「禁用超时」值。 + +## 使用形态 + +```ts +import { deadline, timeoutOf } from '@deepseek-ai/dsh-timeout' + +declare function runWork(options: { signal: AbortSignal }): Promise + +// Scope-lifetime consumer (foreground bash, one fetch): `using` disposes the timer. +export async function runWithDeadline(upstream: AbortSignal | undefined, timeoutMs: number): Promise { + using d = deadline(upstream, timeoutMs, 'BASH_TIMEOUT') + const outcome = await runWork({ signal: d.signal }) // work listens on d.signal and terminates itself + const timedOut = timeoutOf(d.signal, 'BASH_TIMEOUT') !== undefined // classify the first abort, scoped to OUR code + const aborted = d.signal.aborted && !timedOut // mutually exclusive: timeout won, or cancel did + return { outcome, timedOut, aborted } +} +``` + +该信号只会*通知*;调用方必须接入自己的终止机制(`d.signal.addEventListener('abort', kill)`,或将 `d.signal` 传给 `fetch`)。让 promise 与 timer 竞速,会在子进程或套接字仍在泄漏时就让工具调用完成;发出信号则会强制要求存在真正的终止路径。 + +将你自己的 `code` 传给 `timeoutOf`,使分类可在嵌套场景中正确组合。当 `upstream` 本身是 deadline 信号时,如果该 timer 先触发,`AbortSignal.any` 会保留它的 `TimeoutReason`。将匹配范围限定为你的 code,会把外部超时视为普通的 upstream 取消,而不会声称本地 timer 已到期。 + +对于流式传输,创建一个 `idleWatchdog`,将其稳定的 `signal` 传给传输层,并为提供方的每次读取调用 `watchdog.next(iterator)`。当传输活动不产生迭代器值时,调用 `watchdog.pulse()`。间隔必须为正有限数,且不得超过 `MAX_TIMER_DELAY_MS`;否则 Node 会将其限制为 1 毫秒。它只对尚未完成的读取请求计时,因此当下游代码进行渲染或在请求下一个分片前以其他方式等待时,timer 不会运行。该原语仍然只会通知,因此传输层必须观察稳定信号;DeepSeek 和 pi-ai 适配器证明,超时会关闭它们的真实响应正文或 SDK 请求。 + +## 哪些操作不设置超时 + +本地文件 `read`/`write`/`edit` 不接受 `timeoutMs`:文件 IO 不设时限地运行,因为截止时间会中止操作系统仍会完成的工作。详见[文件系统子系统页面](../../../docs/subsystems/filesystem.md)。 + +## 模型体验 + +通过 `dsh-tool-call-timeout-policy` 等消费方间接影响模型;消费方可能会将提供方结果替换为已保留的超时错误,或抑制延迟结果。 + +#### KV Cache 影响 + +不会直接导致 KV Cache 失效;请求前缀变更由上述消费方负责。 + +## 已知限制与暂缓事项 + +- **只发出通知**:deadline 无法停止忽略其信号的工作;每项能力仍需要自己的 socket/进程/任务终止路径。 +- **`timeoutMs <= 0` 是内部词汇**:只有在所属后端已解析策略后,它才会禁用本地 timer;绝不会作为面向模型/插件的公开开关。 +- **第一个中止原因决定分类**:当 upstream 取消早于本地 timer 发生时,即使自己的超时之后也会到期,该层也无法再报告。 +- **空闲 watchdog 不是总 deadline**:它针对每个尚未完成的迭代器需求重新启动,并刻意排除消费方的处理时间。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/index.js new file mode 100644 index 0000000..0aaa8d1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/index.js @@ -0,0 +1,140 @@ +//#region lib/types/index.js +/** +* Shared timeout arithmetic, signal fusion, and classification. The library +* only notifies through abort signals; each capability still owns the mechanism +* that stops its work and translates timeout reasons into public outcomes. +* @module @deepseek-ai/dsh-timeout +*/ +/** +* Internal abort reason carrying a capability-owned code and elapsed deadline. +* Providers translate it through {@link timeoutOf} before returning to callers. +*/ +var TimeoutReason = class extends Error { + code; + timeoutMs; + name = "TimeoutReason"; + /** + * @param code Capability-owned timeout code (e.g. `BASH_TIMEOUT`). + * @param timeoutMs The deadline that elapsed, in milliseconds. + */ + constructor(code, timeoutMs) { + super(`${code} after ${timeoutMs}ms`); + this.code = code; + this.timeoutMs = timeoutMs; + } +}; +/** Largest delay Node schedules without clamping it to one millisecond. */ +const MAX_TIMER_DELAY_MS = 2147483647; +function assertTimerDelay(timeoutMs, name) { + if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647) throw new Error(`${name} must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`); +} +/** +* Validate a caller's optional timeout hint, use the backend default, then cap +* it. Supplied values must be positive and finite; zero is not a public +* disable-timeout sentinel. +* +* @param requested The caller's optional hint; validated when present. +* @param def The backend default applied when `requested` is absent. +* @param max The backend upper bound the result is capped to. +* @param name Field name used in the thrown message (so the caller sees which input was +* bad). +* @returns The effective timeout in milliseconds: `min(requested ?? def, max)`. +*/ +function clampTimeout(requested, def, max, name = "timeoutMs") { + if (requested !== void 0 && (!Number.isFinite(requested) || requested <= 0)) throw new Error(`${name} must be a positive finite number`); + return Math.min(requested ?? def, max); +} +/** +* Fuse upstream cancellation with an identifiable timeout. `timeoutMs <= 0` is +* the internal no-timer sentinel; the returned disposer clears an armed timer. +* The signal only notifies, so callers must stop their own work. +* +* @param upstream The caller's cancellation signal, if any, fused into the result. +* @param timeoutMs Deadline in milliseconds; `<= 0` means "no timeout" (arm no timer). +* @param code Capability-owned code stamped onto the timeout's {@link TimeoutReason}. +* @returns The fused {@link Deadline} (signal + timer cleanup). +*/ +function deadline(upstream, timeoutMs, code) { + if (timeoutMs <= 0) return { + signal: upstream ?? new AbortController().signal, + [Symbol.dispose]() {} + }; + assertTimerDelay(timeoutMs, "deadline timeoutMs"); + const timer = new AbortController(); + const id = setTimeout(() => { + timer.abort(new TimeoutReason(code, timeoutMs)); + }, timeoutMs); + return { + signal: upstream !== void 0 ? AbortSignal.any([upstream, timer.signal]) : timer.signal, + [Symbol.dispose]() { + clearTimeout(id); + } + }; +} +/** +* Create a rearmable idle watchdog for an async iterator. The timer exists only +* while {@link IdleWatchdog.next} is outstanding, so consumer think time does +* not count as provider idle time. The returned signal is stable for the whole +* call and only notifies; the iterator must observe it to terminate its work. +* +* @param upstream - caller cancellation fused into the stable signal. +* @param timeoutMs - positive finite idle interval in milliseconds. +* @param code - capability-owned code carried by the timeout reason. +* @returns a stable signal, guarded next operation, and timer disposer. +*/ +function idleWatchdog(upstream, timeoutMs, code) { + assertTimerDelay(timeoutMs, "idleWatchdog timeoutMs"); + const timeout = new AbortController(); + const signal = upstream === void 0 ? timeout.signal : AbortSignal.any([upstream, timeout.signal]); + let timer; + let outstanding = false; + let disposed = false; + const arm = () => { + if (timer !== void 0) clearTimeout(timer); + timer = setTimeout(() => { + timeout.abort(new TimeoutReason(code, timeoutMs)); + }, timeoutMs); + }; + return { + signal, + async next(iterator) { + if (disposed) throw new Error("idleWatchdog is disposed"); + if (outstanding) throw new Error("idleWatchdog next is already outstanding"); + outstanding = true; + arm(); + try { + return await iterator.next(); + } finally { + clearTimeout(timer); + timer = void 0; + outstanding = false; + } + }, + pulse() { + if (disposed || !outstanding) return; + arm(); + }, + [Symbol.dispose]() { + if (disposed) return; + disposed = true; + if (timer !== void 0) clearTimeout(timer); + timer = void 0; + } + }; +} +/** +* Recover a timeout reason from a reason-bearing object. Supplying `code` +* distinguishes this deadline from a nested upstream deadline; a foreign code +* follows the ordinary cancellation path. +* +* @param x An {@link AbortSignal} or any `{ reason }` carrier (e.g. a caught abort error). +* @param code When provided, only a {@link TimeoutReason} with this exact `code` matches. +* @returns The matching {@link TimeoutReason}, else `undefined`. +*/ +function timeoutOf(x, code) { + const reason = x.reason; + if (!(reason instanceof TimeoutReason)) return void 0; + return code === void 0 || reason.code === code ? reason : void 0; +} +//#endregion +export { MAX_TIMER_DELAY_MS, TimeoutReason, clampTimeout, deadline, idleWatchdog, timeoutOf }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/invariant.js new file mode 100644 index 0000000..8fa9558 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-timeout`. +* @module @deepseek-ai/dsh-timeout/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-timeout"; +/** Cordis companion plugin name. */ +const name = "timeout-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value +* algebra is enforced by unit tests. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/types/index.d.ts new file mode 100644 index 0000000..735dfbe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/types/index.d.ts @@ -0,0 +1,93 @@ +/** + * Shared timeout arithmetic, signal fusion, and classification. The library + * only notifies through abort signals; each capability still owns the mechanism + * that stops its work and translates timeout reasons into public outcomes. + * @module @deepseek-ai/dsh-timeout + */ +/** + * Internal abort reason carrying a capability-owned code and elapsed deadline. + * Providers translate it through {@link timeoutOf} before returning to callers. + */ +export declare class TimeoutReason extends Error { + readonly code: string; + readonly timeoutMs: number; + name: string; + /** + * @param code Capability-owned timeout code (e.g. `BASH_TIMEOUT`). + * @param timeoutMs The deadline that elapsed, in milliseconds. + */ + constructor(code: string, timeoutMs: number); +} +/** Largest delay Node schedules without clamping it to one millisecond. */ +export declare const MAX_TIMER_DELAY_MS = 2147483647; +/** + * Validate a caller's optional timeout hint, use the backend default, then cap + * it. Supplied values must be positive and finite; zero is not a public + * disable-timeout sentinel. + * + * @param requested The caller's optional hint; validated when present. + * @param def The backend default applied when `requested` is absent. + * @param max The backend upper bound the result is capped to. + * @param name Field name used in the thrown message (so the caller sees which input was + * bad). + * @returns The effective timeout in milliseconds: `min(requested ?? def, max)`. + */ +export declare function clampTimeout(requested: number | undefined, def: number, max: number, name?: string): number; +/** A deadline signal plus the cleanup that clears its timer (dispose-once). */ +export interface Deadline { + /** Aborts on upstream cancellation OR on timeout (the timeout carries a {@link TimeoutReason}). */ + readonly signal: AbortSignal; + /** Clear the timer. Safe to call once; `using` calls it at scope exit. */ + [Symbol.dispose](): void; +} +/** Rearmable timeout around one outstanding async-iterator demand. */ +export interface IdleWatchdog { + /** Stable signal aborted by upstream cancellation or this watchdog's timeout. */ + readonly signal: AbortSignal; + /** + * Await one iterator demand while the idle timer is armed. + * @param iterator - iterator whose next value represents provider progress. + * @returns the iterator's next result. + */ + next(iterator: AsyncIterator): Promise>; + /** Rearm an outstanding demand after transport activity that yields no iterator value; otherwise a no-op. */ + pulse(): void; + /** Clear an armed timer; safe to call once at the owning stream's exit. */ + [Symbol.dispose](): void; +} +/** + * Fuse upstream cancellation with an identifiable timeout. `timeoutMs <= 0` is + * the internal no-timer sentinel; the returned disposer clears an armed timer. + * The signal only notifies, so callers must stop their own work. + * + * @param upstream The caller's cancellation signal, if any, fused into the result. + * @param timeoutMs Deadline in milliseconds; `<= 0` means "no timeout" (arm no timer). + * @param code Capability-owned code stamped onto the timeout's {@link TimeoutReason}. + * @returns The fused {@link Deadline} (signal + timer cleanup). + */ +export declare function deadline(upstream: AbortSignal | undefined, timeoutMs: number, code: string): Deadline; +/** + * Create a rearmable idle watchdog for an async iterator. The timer exists only + * while {@link IdleWatchdog.next} is outstanding, so consumer think time does + * not count as provider idle time. The returned signal is stable for the whole + * call and only notifies; the iterator must observe it to terminate its work. + * + * @param upstream - caller cancellation fused into the stable signal. + * @param timeoutMs - positive finite idle interval in milliseconds. + * @param code - capability-owned code carried by the timeout reason. + * @returns a stable signal, guarded next operation, and timer disposer. + */ +export declare function idleWatchdog(upstream: AbortSignal | undefined, timeoutMs: number, code: string): IdleWatchdog; +/** + * Recover a timeout reason from a reason-bearing object. Supplying `code` + * distinguishes this deadline from a nested upstream deadline; a foreign code + * follows the ordinary cancellation path. + * + * @param x An {@link AbortSignal} or any `{ reason }` carrier (e.g. a caught abort error). + * @param code When provided, only a {@link TimeoutReason} with this exact `code` matches. + * @returns The matching {@link TimeoutReason}, else `undefined`. + */ +export declare function timeoutOf(x: AbortSignal | { + reason?: unknown; +}, code?: string): TimeoutReason | undefined; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/types/invariant.d.ts new file mode 100644 index 0000000..9c8294f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-timeout`. + * @module @deepseek-ai/dsh-timeout/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "timeout-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/package.json new file mode 100644 index 0000000..129954f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_8c173ab999b05cf1db05d479dd44e888/node_modules/@deepseek-ai/dsh-timeout/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-timeout", + "description": "Zero-dependency timeout/deadline primitive: clampTimeout, deadline, timeoutOf, TimeoutReason (timing + classification only, no termination)", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/util/timeout" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.i18n.yaml new file mode 100644 index 0000000..c000fae --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/timeout/README.md +README.md: c29f6a7661abf40eadafc7637c1bbca509a62a24 +README.zh.md: ca05fcaf0ac7f3379d746e11a123294e3febf436 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.md new file mode 100644 index 0000000..c29f6a7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.md @@ -0,0 +1,70 @@ +# dsh-timeout + +English | [中文](README.zh.md) + +The **timing-and-classification** half of a timeout — a zero-dependency library of pure functions (no runtime harness deps) shared by every capability that clamps a caller's timeout hint, arms a deadline, and later has to tell "timed out" apart from "cancelled". + +It owns **no termination**. The signal it hands out only *notifies*; actually stopping the work stays in each capability, because that mechanism differs — bash SIGKILLs an OS process group, web tears down a `fetch` socket — and no shared layer can own all of them. This is the boundary the [Agent Note](../../../.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.md) draws: share the timing/classification, keep the hard kill local. + +It is a **library, not a service or plugin**: no `ctx`, registers nothing, holds no state, emits no events. A "timeout service" would have to understand how to stop every capability's work — exactly the knowledge a microkernel keeps out of shared layers. + +## API + +```ts +import { clampTimeout, deadline, idleWatchdog, MAX_TIMER_DELAY_MS, timeoutOf, TimeoutReason } from '@deepseek-ai/dsh-timeout' +``` + +| Export | Role | +|---|---| +| `clampTimeout(requested, def, max, name?)` | Validate the caller's optional positive-finite hint, fill from `def`, cap at `max`. Throws (with `name`) on a non-positive/non-finite hint. | +| `deadline(upstream, timeoutMs, code)` | Fuse `upstream` cancellation with a timeout into one `AbortSignal` (`AbortSignal.any`); the timeout carries a `TimeoutReason`. `[Symbol.dispose]` clears the timer. | +| `idleWatchdog(upstream, timeoutMs, code)` | Keep one stable fused signal and arm only while its guarded async-iterator `next()` is outstanding. Resolution disarms; later demand or `pulse()` activity rearms; disposal clears; concurrent demand rejects. | +| `MAX_TIMER_DELAY_MS` | Largest delay Node schedules without clamping it to one millisecond (`2_147_483_647`). Timer-owning config must not exceed it. | +| `timeoutOf(signal \| { reason }, code?)` | Recover the `TimeoutReason` from an aborted signal/error, else `undefined` — the timeout-vs-cancel classifier. Pass `code` to match only THIS deadline's timer (see nesting below). | +| `TimeoutReason` | The internal reason (`code` + `timeoutMs`) stamped on a timeout abort. Not a public error — providers translate it into their own error/field. | + +## The `timeoutMs <= 0` sentinel + +`0` is the **internal** "no timeout" value for backend-owned background work (bash `start()`): `deadline()` arms no timer and forwards only `upstream`; with no upstream either, it returns a never-aborting signal plus a no-op disposer, so every caller keeps one call shape. External request hints validate as **positive finite** via `clampTimeout` before they reach `deadline`, so `0` is never a model-/plugin-facing "disable timeout" value. + +## Usage shape + +```ts +import { deadline, timeoutOf } from '@deepseek-ai/dsh-timeout' + +declare function runWork(options: { signal: AbortSignal }): Promise + +// Scope-lifetime consumer (foreground bash, one fetch): `using` disposes the timer. +export async function runWithDeadline(upstream: AbortSignal | undefined, timeoutMs: number): Promise { + using d = deadline(upstream, timeoutMs, 'BASH_TIMEOUT') + const outcome = await runWork({ signal: d.signal }) // work listens on d.signal and terminates itself + const timedOut = timeoutOf(d.signal, 'BASH_TIMEOUT') !== undefined // classify the first abort, scoped to OUR code + const aborted = d.signal.aborted && !timedOut // mutually exclusive: timeout won, or cancel did + return { outcome, timedOut, aborted } +} +``` + +The signal only *notifies* — the caller MUST attach its own termination (`d.signal.addEventListener('abort', kill)`, or hand `d.signal` to `fetch`). Racing a promise against a timer would resolve the tool-call while the child process or socket leaks on; handing out a signal forces a real termination path to exist. + +Pass your own `code` to `timeoutOf` so classification composes under nesting. When `upstream` is itself a deadline signal, `AbortSignal.any` preserves its `TimeoutReason` if that timer fires first. Scoping to your code makes a foreign timeout read as an ordinary upstream cancel instead of claiming that the local timer expired. + +For a streamed transport, create one `idleWatchdog`, pass its stable `signal` into the transport, and call `watchdog.next(iterator)` for each provider read. Call `watchdog.pulse()` when transport activity does not yield an iterator value. The interval must be positive, finite, and no greater than `MAX_TIMER_DELAY_MS`; Node otherwise clamps it to one millisecond. It measures only outstanding demand, so no timer runs while downstream code renders or otherwise waits before asking for the next chunk. The primitive still only notifies, so the transport must observe the stable signal; the DeepSeek and pi-ai adapters prove that timeout closes their real response body or SDK request. + +## What does NOT get a timeout + +Local file `read`/`write`/`edit` take no `timeoutMs`: file IO runs untimed because a deadline would kill work the OS will still finish. See [the filesystem subsystem page](../../../docs/subsystems/filesystem.md). + +## Model Experience + +Indirectly, through consumers such as `dsh-tool-call-timeout-policy`, which may replace a provider result with a retained timeout error or suppress a late result. + +#### KV Cache effect + +No direct invalidation; the named consumer owns any request-prefix changes. + +## Known Limitations and Deferred Work + +- **Notification only** — a deadline cannot stop work that ignores its signal; every capability still needs its own socket/process/task termination path. +- **`timeoutMs <= 0` is internal vocabulary** — it disables the local timer only after an owning backend has resolved policy, never as a public model/plugin knob. +- **The first abort reason wins classification** — when an upstream cancellation beats the local timer, this layer cannot later report that its own timeout would also have elapsed. +- **An idle watchdog is not a total deadline** — it rearms per outstanding iterator demand and deliberately excludes consumer think time. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.zh.md new file mode 100644 index 0000000..ca05fca --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/README.zh.md @@ -0,0 +1,70 @@ +# dsh-timeout + +[English](README.md) | 中文 + +超时的**时序与分类**部分:一个零依赖纯函数库(无运行时 harness 依赖),由每个需要限制调用方超时提示、启动 deadline,并在之后区分「已超时」与「已取消」的能力共享。 + +它**不负责终止**。它发出的信号只会*通知*;真正停止工作仍由各能力负责,因为机制各不相同:bash 对操作系统进程组发送 SIGKILL,web 关闭 `fetch` 套接字,没有任何共享层能够承担全部终止机制。[Agent Note](../../../.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.md) 将边界划定为:共享时序/分类,将强制终止保留在本地。 + +它是**库,而非服务或插件**:没有 `ctx`,不注册任何内容,不持有状态,也不发出事件。「超时服务」必须了解如何停止每项能力的工作,这正是微内核要排除在共享层之外的知识。 + +## 对外接口 + +```ts +import { clampTimeout, deadline, idleWatchdog, MAX_TIMER_DELAY_MS, timeoutOf, TimeoutReason } from '@deepseek-ai/dsh-timeout' +``` + +| 导出项 | 职责 | +|---|---| +| `clampTimeout(requested, def, max, name?)` | 验证调用方可选的、值为正且有限的提示,从 `def` 填充,并限制在 `max` 以内。如果提示为非正数或非有限数,则抛出错误(包含 `name`)。 | +| `deadline(upstream, timeoutMs, code)` | 将 `upstream` 取消与超时融合为一个 `AbortSignal`(`AbortSignal.any`);超时携带 `TimeoutReason`。`[Symbol.dispose]` 清除 timer。 | +| `idleWatchdog(upstream, timeoutMs, code)` | 保持一个稳定的融合信号,并且只在受保护的异步迭代器 `next()` 尚未完成时启动 timer。完成后停止 timer;后续需求或 `pulse()` 活动会重新启动 timer;dispose(资源释放)时清除;并发需求被拒绝。 | +| `MAX_TIMER_DELAY_MS` | Node 在不将延迟限制为 1 毫秒时可调度的最大延迟(`2_147_483_647`)。负责 timer 的配置不得超过该值。 | +| `timeoutOf(signal \| { reason }, code?)` | 从已中止的信号/错误中恢复 `TimeoutReason`,否则返回 `undefined`,即超时与取消的分类器。传入 `code` 可仅匹配这个 deadline 的 timer(见下文的嵌套)。 | +| `TimeoutReason` | 标记在超时中止上的内部原因(`code` + `timeoutMs`)。它不是公开错误;提供方将其转换为自己的错误/字段。 | + +## `timeoutMs <= 0` 哨兵值 + +`0` 是后端自有后台工作(bash `start()`)使用的**内部**「无超时」值。`deadline()` 不启动 timer,只转发 `upstream`;如果也没有 upstream,它将返回永不中止的信号和无操作 disposer,因此每个调用方都能保持同一种调用形态。外部请求提示会通过 `clampTimeout` 验证为**正有限数**,之后才进入 `deadline`,因此 `0` 绝不是面向模型/插件的「禁用超时」值。 + +## 使用形态 + +```ts +import { deadline, timeoutOf } from '@deepseek-ai/dsh-timeout' + +declare function runWork(options: { signal: AbortSignal }): Promise + +// Scope-lifetime consumer (foreground bash, one fetch): `using` disposes the timer. +export async function runWithDeadline(upstream: AbortSignal | undefined, timeoutMs: number): Promise { + using d = deadline(upstream, timeoutMs, 'BASH_TIMEOUT') + const outcome = await runWork({ signal: d.signal }) // work listens on d.signal and terminates itself + const timedOut = timeoutOf(d.signal, 'BASH_TIMEOUT') !== undefined // classify the first abort, scoped to OUR code + const aborted = d.signal.aborted && !timedOut // mutually exclusive: timeout won, or cancel did + return { outcome, timedOut, aborted } +} +``` + +该信号只会*通知*;调用方必须接入自己的终止机制(`d.signal.addEventListener('abort', kill)`,或将 `d.signal` 传给 `fetch`)。让 promise 与 timer 竞速,会在子进程或套接字仍在泄漏时就让工具调用完成;发出信号则会强制要求存在真正的终止路径。 + +将你自己的 `code` 传给 `timeoutOf`,使分类可在嵌套场景中正确组合。当 `upstream` 本身是 deadline 信号时,如果该 timer 先触发,`AbortSignal.any` 会保留它的 `TimeoutReason`。将匹配范围限定为你的 code,会把外部超时视为普通的 upstream 取消,而不会声称本地 timer 已到期。 + +对于流式传输,创建一个 `idleWatchdog`,将其稳定的 `signal` 传给传输层,并为提供方的每次读取调用 `watchdog.next(iterator)`。当传输活动不产生迭代器值时,调用 `watchdog.pulse()`。间隔必须为正有限数,且不得超过 `MAX_TIMER_DELAY_MS`;否则 Node 会将其限制为 1 毫秒。它只对尚未完成的读取请求计时,因此当下游代码进行渲染或在请求下一个分片前以其他方式等待时,timer 不会运行。该原语仍然只会通知,因此传输层必须观察稳定信号;DeepSeek 和 pi-ai 适配器证明,超时会关闭它们的真实响应正文或 SDK 请求。 + +## 哪些操作不设置超时 + +本地文件 `read`/`write`/`edit` 不接受 `timeoutMs`:文件 IO 不设时限地运行,因为截止时间会中止操作系统仍会完成的工作。详见[文件系统子系统页面](../../../docs/subsystems/filesystem.md)。 + +## 模型体验 + +通过 `dsh-tool-call-timeout-policy` 等消费方间接影响模型;消费方可能会将提供方结果替换为已保留的超时错误,或抑制延迟结果。 + +#### KV Cache 影响 + +不会直接导致 KV Cache 失效;请求前缀变更由上述消费方负责。 + +## 已知限制与暂缓事项 + +- **只发出通知**:deadline 无法停止忽略其信号的工作;每项能力仍需要自己的 socket/进程/任务终止路径。 +- **`timeoutMs <= 0` 是内部词汇**:只有在所属后端已解析策略后,它才会禁用本地 timer;绝不会作为面向模型/插件的公开开关。 +- **第一个中止原因决定分类**:当 upstream 取消早于本地 timer 发生时,即使自己的超时之后也会到期,该层也无法再报告。 +- **空闲 watchdog 不是总 deadline**:它针对每个尚未完成的迭代器需求重新启动,并刻意排除消费方的处理时间。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/index.js new file mode 100644 index 0000000..0aaa8d1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/index.js @@ -0,0 +1,140 @@ +//#region lib/types/index.js +/** +* Shared timeout arithmetic, signal fusion, and classification. The library +* only notifies through abort signals; each capability still owns the mechanism +* that stops its work and translates timeout reasons into public outcomes. +* @module @deepseek-ai/dsh-timeout +*/ +/** +* Internal abort reason carrying a capability-owned code and elapsed deadline. +* Providers translate it through {@link timeoutOf} before returning to callers. +*/ +var TimeoutReason = class extends Error { + code; + timeoutMs; + name = "TimeoutReason"; + /** + * @param code Capability-owned timeout code (e.g. `BASH_TIMEOUT`). + * @param timeoutMs The deadline that elapsed, in milliseconds. + */ + constructor(code, timeoutMs) { + super(`${code} after ${timeoutMs}ms`); + this.code = code; + this.timeoutMs = timeoutMs; + } +}; +/** Largest delay Node schedules without clamping it to one millisecond. */ +const MAX_TIMER_DELAY_MS = 2147483647; +function assertTimerDelay(timeoutMs, name) { + if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647) throw new Error(`${name} must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`); +} +/** +* Validate a caller's optional timeout hint, use the backend default, then cap +* it. Supplied values must be positive and finite; zero is not a public +* disable-timeout sentinel. +* +* @param requested The caller's optional hint; validated when present. +* @param def The backend default applied when `requested` is absent. +* @param max The backend upper bound the result is capped to. +* @param name Field name used in the thrown message (so the caller sees which input was +* bad). +* @returns The effective timeout in milliseconds: `min(requested ?? def, max)`. +*/ +function clampTimeout(requested, def, max, name = "timeoutMs") { + if (requested !== void 0 && (!Number.isFinite(requested) || requested <= 0)) throw new Error(`${name} must be a positive finite number`); + return Math.min(requested ?? def, max); +} +/** +* Fuse upstream cancellation with an identifiable timeout. `timeoutMs <= 0` is +* the internal no-timer sentinel; the returned disposer clears an armed timer. +* The signal only notifies, so callers must stop their own work. +* +* @param upstream The caller's cancellation signal, if any, fused into the result. +* @param timeoutMs Deadline in milliseconds; `<= 0` means "no timeout" (arm no timer). +* @param code Capability-owned code stamped onto the timeout's {@link TimeoutReason}. +* @returns The fused {@link Deadline} (signal + timer cleanup). +*/ +function deadline(upstream, timeoutMs, code) { + if (timeoutMs <= 0) return { + signal: upstream ?? new AbortController().signal, + [Symbol.dispose]() {} + }; + assertTimerDelay(timeoutMs, "deadline timeoutMs"); + const timer = new AbortController(); + const id = setTimeout(() => { + timer.abort(new TimeoutReason(code, timeoutMs)); + }, timeoutMs); + return { + signal: upstream !== void 0 ? AbortSignal.any([upstream, timer.signal]) : timer.signal, + [Symbol.dispose]() { + clearTimeout(id); + } + }; +} +/** +* Create a rearmable idle watchdog for an async iterator. The timer exists only +* while {@link IdleWatchdog.next} is outstanding, so consumer think time does +* not count as provider idle time. The returned signal is stable for the whole +* call and only notifies; the iterator must observe it to terminate its work. +* +* @param upstream - caller cancellation fused into the stable signal. +* @param timeoutMs - positive finite idle interval in milliseconds. +* @param code - capability-owned code carried by the timeout reason. +* @returns a stable signal, guarded next operation, and timer disposer. +*/ +function idleWatchdog(upstream, timeoutMs, code) { + assertTimerDelay(timeoutMs, "idleWatchdog timeoutMs"); + const timeout = new AbortController(); + const signal = upstream === void 0 ? timeout.signal : AbortSignal.any([upstream, timeout.signal]); + let timer; + let outstanding = false; + let disposed = false; + const arm = () => { + if (timer !== void 0) clearTimeout(timer); + timer = setTimeout(() => { + timeout.abort(new TimeoutReason(code, timeoutMs)); + }, timeoutMs); + }; + return { + signal, + async next(iterator) { + if (disposed) throw new Error("idleWatchdog is disposed"); + if (outstanding) throw new Error("idleWatchdog next is already outstanding"); + outstanding = true; + arm(); + try { + return await iterator.next(); + } finally { + clearTimeout(timer); + timer = void 0; + outstanding = false; + } + }, + pulse() { + if (disposed || !outstanding) return; + arm(); + }, + [Symbol.dispose]() { + if (disposed) return; + disposed = true; + if (timer !== void 0) clearTimeout(timer); + timer = void 0; + } + }; +} +/** +* Recover a timeout reason from a reason-bearing object. Supplying `code` +* distinguishes this deadline from a nested upstream deadline; a foreign code +* follows the ordinary cancellation path. +* +* @param x An {@link AbortSignal} or any `{ reason }` carrier (e.g. a caught abort error). +* @param code When provided, only a {@link TimeoutReason} with this exact `code` matches. +* @returns The matching {@link TimeoutReason}, else `undefined`. +*/ +function timeoutOf(x, code) { + const reason = x.reason; + if (!(reason instanceof TimeoutReason)) return void 0; + return code === void 0 || reason.code === code ? reason : void 0; +} +//#endregion +export { MAX_TIMER_DELAY_MS, TimeoutReason, clampTimeout, deadline, idleWatchdog, timeoutOf }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/invariant.js new file mode 100644 index 0000000..8fa9558 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-timeout`. +* @module @deepseek-ai/dsh-timeout/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-timeout"; +/** Cordis companion plugin name. */ +const name = "timeout-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value +* algebra is enforced by unit tests. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/types/index.d.ts new file mode 100644 index 0000000..735dfbe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/types/index.d.ts @@ -0,0 +1,93 @@ +/** + * Shared timeout arithmetic, signal fusion, and classification. The library + * only notifies through abort signals; each capability still owns the mechanism + * that stops its work and translates timeout reasons into public outcomes. + * @module @deepseek-ai/dsh-timeout + */ +/** + * Internal abort reason carrying a capability-owned code and elapsed deadline. + * Providers translate it through {@link timeoutOf} before returning to callers. + */ +export declare class TimeoutReason extends Error { + readonly code: string; + readonly timeoutMs: number; + name: string; + /** + * @param code Capability-owned timeout code (e.g. `BASH_TIMEOUT`). + * @param timeoutMs The deadline that elapsed, in milliseconds. + */ + constructor(code: string, timeoutMs: number); +} +/** Largest delay Node schedules without clamping it to one millisecond. */ +export declare const MAX_TIMER_DELAY_MS = 2147483647; +/** + * Validate a caller's optional timeout hint, use the backend default, then cap + * it. Supplied values must be positive and finite; zero is not a public + * disable-timeout sentinel. + * + * @param requested The caller's optional hint; validated when present. + * @param def The backend default applied when `requested` is absent. + * @param max The backend upper bound the result is capped to. + * @param name Field name used in the thrown message (so the caller sees which input was + * bad). + * @returns The effective timeout in milliseconds: `min(requested ?? def, max)`. + */ +export declare function clampTimeout(requested: number | undefined, def: number, max: number, name?: string): number; +/** A deadline signal plus the cleanup that clears its timer (dispose-once). */ +export interface Deadline { + /** Aborts on upstream cancellation OR on timeout (the timeout carries a {@link TimeoutReason}). */ + readonly signal: AbortSignal; + /** Clear the timer. Safe to call once; `using` calls it at scope exit. */ + [Symbol.dispose](): void; +} +/** Rearmable timeout around one outstanding async-iterator demand. */ +export interface IdleWatchdog { + /** Stable signal aborted by upstream cancellation or this watchdog's timeout. */ + readonly signal: AbortSignal; + /** + * Await one iterator demand while the idle timer is armed. + * @param iterator - iterator whose next value represents provider progress. + * @returns the iterator's next result. + */ + next(iterator: AsyncIterator): Promise>; + /** Rearm an outstanding demand after transport activity that yields no iterator value; otherwise a no-op. */ + pulse(): void; + /** Clear an armed timer; safe to call once at the owning stream's exit. */ + [Symbol.dispose](): void; +} +/** + * Fuse upstream cancellation with an identifiable timeout. `timeoutMs <= 0` is + * the internal no-timer sentinel; the returned disposer clears an armed timer. + * The signal only notifies, so callers must stop their own work. + * + * @param upstream The caller's cancellation signal, if any, fused into the result. + * @param timeoutMs Deadline in milliseconds; `<= 0` means "no timeout" (arm no timer). + * @param code Capability-owned code stamped onto the timeout's {@link TimeoutReason}. + * @returns The fused {@link Deadline} (signal + timer cleanup). + */ +export declare function deadline(upstream: AbortSignal | undefined, timeoutMs: number, code: string): Deadline; +/** + * Create a rearmable idle watchdog for an async iterator. The timer exists only + * while {@link IdleWatchdog.next} is outstanding, so consumer think time does + * not count as provider idle time. The returned signal is stable for the whole + * call and only notifies; the iterator must observe it to terminate its work. + * + * @param upstream - caller cancellation fused into the stable signal. + * @param timeoutMs - positive finite idle interval in milliseconds. + * @param code - capability-owned code carried by the timeout reason. + * @returns a stable signal, guarded next operation, and timer disposer. + */ +export declare function idleWatchdog(upstream: AbortSignal | undefined, timeoutMs: number, code: string): IdleWatchdog; +/** + * Recover a timeout reason from a reason-bearing object. Supplying `code` + * distinguishes this deadline from a nested upstream deadline; a foreign code + * follows the ordinary cancellation path. + * + * @param x An {@link AbortSignal} or any `{ reason }` carrier (e.g. a caught abort error). + * @param code When provided, only a {@link TimeoutReason} with this exact `code` matches. + * @returns The matching {@link TimeoutReason}, else `undefined`. + */ +export declare function timeoutOf(x: AbortSignal | { + reason?: unknown; +}, code?: string): TimeoutReason | undefined; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/types/invariant.d.ts new file mode 100644 index 0000000..9c8294f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-timeout`. + * @module @deepseek-ai/dsh-timeout/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "timeout-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/package.json new file mode 100644 index 0000000..9fb828d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout/package.json @@ -0,0 +1,42 @@ +{ + "name": "@deepseek-ai/dsh-timeout", + "description": "Zero-dependency timeout/deadline primitive: clampTimeout, deadline, timeoutOf, TimeoutReason (timing + classification only, no termination)", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/util/timeout" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-code-runtime b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-code-runtime new file mode 120000 index 0000000..48d5f98 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-code-runtime @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-code-runtime@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_32ca6603c85cd8533345d5c948089cd0/node_modules/@deepseek-ai/dsh-code-runtime \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-system-prompt b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-system-prompt new file mode 120000 index 0000000..7b9075d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-system-prompt @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.i18n.yaml new file mode 100644 index 0000000..ede5781 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/tools/README.md +README.md: 60841513ad5ad439ae8851dffc34e8d250acaa67 +README.zh.md: 6e26a802c2c16a9d48e29236d358b15eafddcc07 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.md new file mode 100644 index 0000000..6084151 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.md @@ -0,0 +1,198 @@ +# dsh-tools + +English | [中文](README.zh.md) + +Tool registry and execution pipeline. Tool plugins register their schemas and executors; the agent loop executes each call through `tools/pre-execute` (the extensible allow/deny gate) → monotonic registered guards → `tools/execute` (an around-dispatch wrapper for timeout/retry/metrics plugins) → `tools/post-execute` (inspect/replace the result, attach context) → the definition-owned `finalizeContent` boundary → the observe-only `tools/result` notification. The registry also owns HOW its tools are presented to the model — its `mode` config selects native function calling, [Code Mode](#code-mode), or both, and one agent shadows that default for itself with `presentAs`. + +## Service: `ToolRuntime` (ctx key: `tools`) + +### Config + +```yaml +tools: + mode: native # native (default) | code | both +``` + +`native` contributes visible tools as function definitions. `code` contributes the reserved `run_code` transport, the generated `tools:sdk` section, and the `tools:code-only` rule stating that only `run_code` may be called directly — which the executor then enforces, resolving a model-direct call naming any other tool to `UNKNOWN_TOOL` before policy runs; `both` contributes both forms and states no such rule, because its native calls do execute. This is the default for agents that declare none of their own — an agent preset selects its own with [`dsh-agent-tool-presentation`](../agent-tool-presentation/README.md). The reserved transport cannot be registered, shadowed, restricted, or removed, and its name is reserved whatever the configured mode, because any agent may select a code mode. Non-native modes require a `ctx.codeRuntime` whose `language` has a registered SDK renderer — TypeScript ships via [`dsh-code-runtime-worker-thread`](../../code-runtime/code-runtime-worker-thread/README.md); a Python renderer is built in and drives any runtime that reports `language: 'python'` (a first-party `dsh-code-runtime-python` backend is delivered separately). A runtime language with no renderer fails prompt assembly loudly, and a `systemPrompt.toolOrder` entry for a tool the mode does not contribute rejects prompt assembly. A `system-prompt/assemble` listener may replace the registry's contributions; its returned assembly is authoritative, so that listener owns preserving a usable Code Mode protocol. + +### Public API + +- `ctx.tools.register(definition: ToolDefinition): () => void` Register a trusted typed same-process definition with a mandatory canonical `output` declaration. The layer is the calling context's scope: a plain plugin context registers globally; an agent's `agent.ctx` registers for that agent alone, shadowing a same-named global tool there. Duplicate names within one layer throw; non-native modes also reject the reserved `run_code` transport name. Missing or unsupported output declarations and a non-positive or non-finite `timeoutMs` fail at registration. The optional synchronous `finalizeContent` callback is snapshotted when a call starts and may replace only final model-facing content after every pipeline outcome is normalized, including an error discovered while materializing another result field. Disposed with the calling fiber. +- `ctx.tools.presentAs(mode: ToolPresentationMode): () => void` selects this agent's model-facing presentation, shadowing the `mode` config for that agent alone; it throws from a plain context (a process-wide presentation is the config field) and from a second declaration in the same scope. A code mode also registers that agent's own `tools:sdk` section. The catalog is unchanged — `schemas(agent)` still reports the agent's capabilities; only the assembly's tools collapse. Disposed with the calling fiber. +- `ctx.tools.restrict(filter)` applies an agent-scoped allow/deny mask to global tools and throws from a plain context. The filter is snapshotted at registration; multiple masks intersect and scope-local tools merge afterwards. Deny masks admit later unnamed globals, while allow masks exclude later names. Unknown, local, or reserved names and empty filters reject. This is live visibility composition, not an authority boundary; see the [scope security non-goal](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals). +- `ctx.tools.get(name: string, scope?: ScopeKey): ToolDefinition | undefined` Resolution as one scope sees it (shadowing applied; a restricted-away global reads as absent) — presenters pass the calling agent so the card matches what executed. +- `ctx.tools.schemas(scope?: ScopeKey): ToolSchema[]` Schemas of everything the scope can see (without the `execute` functions). The shipped tools' schemas are catalogued in [docs/tool-catalog.md](../../../docs/tool-catalog.md), generated by booting each tool plugin and harvesting this method (see [the tool-schema-catalog Agent Note](../../../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md)). +- `ctx.tools.guard(guard: ToolGuard): () => void` Register a monotonic synchronous execution guard after `tools/pre-execute`: returning a reason denies the call, while `undefined` leaves it unchanged. A plain-context guard applies globally; an `agent.ctx` guard applies only to that agent. Later waterfall listeners cannot turn a guard denial back into permission. Disposed with the calling fiber. +- `ctx.tools.execute(exec)` losslessly snapshots and freezes arguments, assigns an opaque token, runs the complete policy/dispatch/result pipeline, then independently snapshots the authoritative outcome before final observation. Invalid arguments use the same result path without reaching policy or the body. Around wrappers may replace only `signal`; the registry re-fuses the original caller signal immediately before the body. +- `ctx.tools.executionMode(exec)` returns `parallel` only when the visible definition's `isConcurrencySafe(exec.arguments)` classifier returns exactly `true`; unknown, hidden, undeclared, invalid, or throwing classifications are exclusive. + +### Injected services + +`SystemPrompt` — the registry automatically feeds its tool schemas into the system-prompt assembly via `ctx.systemPrompt.tools()`. The approval seam is consumed opportunistically instead (`ctx.get('approval')`, no static inject): a deployment without it keeps the ask→deny degrade, and the registry stays active either way. + +### Cancellation + +Cancellation is cooperative and quiescent. Every typed invocation supplies a caller-owned `AbortSignal`; tool bodies receive it as required readonly `exec.signal`, while only `tools/execute` wrappers may temporarily replace the required signal. The registry preserves caller cancellation through replacement and never races away from a started same-process promise. Cancellation before body invocation is `ABORTED_BEFORE_DISPATCH`; cancellation after invocation can replace only a successful outcome with `ABORTED`. A denial, wrapper failure, tool failure, post-policy failure, or timeout-owned `TOOL_TIMEOUT` remains more specific. A pre-aborted entry materializes and freezes arguments, then skips every policy and dispatch phase and publishes one result. Every async tool must observe or forward the signal and settle only after owned work stops. The [tool-cancellation Agent Note](../../../.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md) owns the full contract and hard-termination limit. + +### Live events + +The live registry pipeline has three transformable waterfalls, then the definition-owned content finalizer, then the observe-only `tools/result` event; registry changes are deliberately unfiltered shared-state notifications. Exact signatures, dispatch modes, scope filtering, and failure containment contracts live in the generated region of [tools.md](../../../docs/subsystems/tools.md#cordis-surface), while the complete ordering is visualized in the generated [tool execution pipeline](../../../docs/tool-execution-pipeline.md). `tools/result` is live; the similarly named `tool/result` is the durable session event the agent loop appends afterwards. + +### Key types + +- `ToolDefinition` — `ToolSchema` + mandatory `output { schema, render, presentationMeta? }` + `execute(args, exec)`, optional final-content and presentation callbacks, cooperative `timeoutMs`, and optional per-call `isConcurrencySafe(args)` classification. A body returns only the canonical JSON value declared by the output schema and cooperatively stops through `exec.signal`. `finalizeContent(exec, result)` runs exactly once for every normalized result, including failures that bypass post-policy, and can replace only `content`; it must be synchronous and total. +- `ToolExecutionInput` — the caller-supplied call description: `{ callId, name, arguments, signal, agent?, parent? }`; `signal` is required and readonly, callers may pass an enclosing execution's opaque token as `parent`, and callers never choose the new execution's own token. +- `ToolExecutionToken` — a fresh branded `Symbol` assigned by the registry. It supports equality correlation only and never crosses a model, log, or worker boundary. +- `ToolExecution` — the readonly pipeline view: immutable `{ token, callId, name, arguments, signal, agent?, parent? }`; the registry separately retains and re-fuses the original caller signal. `ToolDispatchExecution` is the `tools/execute`-only view whose required signal is mutable, so a wrapper may replace and restore it but cannot delete it. A nested call's `parent` is a `ToolExecutionToken`, not an execution object. +- `ToolRunContext` — the execution passed to a tool body, extending `ToolExecution` with `deferContext(context)`. It defers one context until the tool's final result reaches the loop — typically a nested-dispatch context ferried by a composite tool, or a fresh plugin-sourced instruction minted by a leaf tool (`tool-goal`'s wrap-up) — even when the tool later throws or cancellation wins; it never injects immediately. +- `ToolExecutionResult` — discriminated execution-local outcome. Success is `{ isError:false, value:JsonValue, content, meta?, additionalContexts? }`; failure is `{ isError:true, error:{ message, info? }, content, meta?, additionalContexts? }` and has no value. Call identity stays on the immutable `ToolExecution`. The registry snapshots, validates, and freezes the canonical value before rendering, then materializes the durable presentation fields before final observation. `ToolFailure.info` carries an internal `{ name, code }` for a `HarnessError`; `additionalContexts` preserves every deferred or post-execute identified `UserMessage` for the loop's post-result FIFO. +- `PreToolDecision` — `{kind:'allow'}` | `{kind:'deny', reason}` | `{kind:'ask', reason?}`. Input rewrite is deliberately not offered; `ask` is serviced by [`ctx.approval`](../../interaction/user-approval/README.md) when mounted and otherwise degrades to deny. +- `PostToolDecision` — accept may replace `content` or `value`, never both, and may attach `additionalContexts`; block turns feedback into a valueless failure. Content replacement preserves the canonical value and metadata. Value replacement is revalidated and rerenders content/metadata. Accept preserves tool-deferred contexts before decision contexts; block discards tool-deferred contexts and exposes only contexts explicitly supplied by the blocking decision. +- `ToolGuard` — `(execution) => string | undefined`; the returned string is a final monotonic denial reason evaluated after the reorderable pre-execute waterfall and before dispatch. +- `ToolCallView` / `ToolResultView` — provider-neutral `card`-tagged render intents a tool returns from `presentCall` / `presentResult` to own how a UI renders ITS calls (see "Tool-owned UI presentation"). + +### Extension points + +- Tool plugins call `ctx.tools.register()` — schemas flow into the assembly automatically. +- `tools/pre-execute` is the reorderable allow/deny/ask gate; `ctx.tools.guard()` adds monotonic owner policy after it. +- `tools/execute` wraps normalized canonical dispatch for timeout, retry, or metrics. Wrappers may replace only the operational signal; a wrapper-authored success is normalized through the resolved tool's output declaration. Each canonical result belongs to one immutable dispatch token, so a cached result from another call or tool is revalidated under the active declaration. +- `tools/post-execute` may replace presentation content, replace the canonical value, block with feedback, or attach ordered contexts. A definition's optional `finalizeContent` then owns its last content-only invariant across normal results and outer pipeline failures; `tools/result` observes the immutable final outcome. Content replacement is not a confidentiality boundary: block or replace the value when programmatic consumers must not receive it. +- Exact signatures and ordering live in the generated region of [tools.md](../../../docs/subsystems/tools.md#cordis-surface) and [pipeline](../../../docs/tool-execution-pipeline.md). +- MCP servers: one plugin per server, discover tools, call `ctx.tools.register()` with the server's schemas. + +### Typed tool parameter schemas + +First-party plugin authors can use the `defineTool()` helper (exported from this package) for typed tool parameter schemas: + +```ts +import { readFile } from 'node:fs/promises' +import type { Context } from '@deepseek-ai/cordis' +import { defineTool } from '@deepseek-ai/dsh-tools' + +declare const ctx: Context + +ctx.tools.register(defineTool({ + name: 'read_file', + description: 'Read a file from disk.', + parameters: { + path: { type: 'string', required: true, description: 'Absolute file path' }, + offset: { type: 'number' }, + limit: { type: 'number' }, + }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, + async execute(args, exec) { + // args is typed: { path: string; offset?: number; limit?: number } + return readFile(args.path, { encoding: 'utf8', signal: exec.signal }) + }, +})) +``` + +The unified schema DSL uses `ParameterSchemaSpec` for the implicit open parameter object and `ValueSchemaSpec` for any JSON-value root. It supports `string`, `number`, `integer`, `boolean`, `null`, `array`, `object`, author-only `json`, and exact-one `oneOf`; scalar `enum`/`const` values are type-correct. Every explicit DSL object declares `additionalProperties: true | false`, while the implicit parameter root and raw JSON Schema keep the standard open default. Schema records accept only own enumerable string keys, and schema arrays must be dense ordinary arrays. Compilation, validation, registry detachment, and schema-to-TypeScript rendering use explicit work stacks, so runtime processing of valid deep schemas is memory-bounded rather than call-stack-bounded; `InferValue` preserves exact types through 16 container levels and then falls back to `JsonValue` so TypeScript itself remains stack-safe. + +A `defineTool` definition validates model arguments before execution and turns missing required values, wrong primitives, invalid enum members, and nested violations into `ToolArgsError` (`INVALID_ARGS`) for the normal error-result path. It also infers the body return and pure output projectors from `output.schema`; the registry snapshots and validates the returned lossless JSON before presentation. The implicit parameter root is open; an explicit object accepts extra keys only with `additionalProperties: true`, and a closed object with no declared properties accepts only `{}`. Raw JSON Schema objects remain open unless they explicitly set `additionalProperties: false`. Defaults are not applied; open objects without `properties` and arrays without `items` receive only a container type check. Raw-registered tools own input validation but still declare and receive registry-enforced output. + +See `defineTool`, `validateArgs`, `ToolArgsError`, `ValueSchemaSpec`, `ParameterSchemaSpec`, `InferValue`, `InferArgs`, `valueSchemaSpecToJsonSchema`, and `parameterSchemaSpecToJsonSchema` in the public API for details. + +Optional `timeoutMs` must be positive and finite; it is policy metadata, not model-visible schema. + +Optional `isConcurrencySafe(args)` receives typed, softly validated arguments. Exact `true` permits concurrent dispatch/body execution; invalid input and all other outcomes remain exclusive. Opted-in bodies do not mutate parent-owned state, and shared-state races must commute or fail closed. The [parallel tool-call Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) owns the full safety contract. + +### Enforced raw JSON Schema subset + +`JsonSchemaNode` is the raw counterpart shared by tool outputs, Code Mode generation, subagents, and workflows. It permits any JSON root, an annotation-only unconstrained JSON node, and exact-one `oneOf`; annotations must remain lossless JSON. `assertSupportedJsonSchema()` rejects unsupported constructs, while `validateJsonSchemaValue()` returns path-qualified violations. Subagents and workflows retain their caller-defined object-root requirement through `assertObjectJsonSchema()` and `ObjectJsonSchema`, not through a limitation in the shared vocabulary. + +### Tool-owned UI presentation + +Tools optionally own pure `presentCall()` and `presentResult()` render intents, so UIs do not special-case tool names: + +- Call views are `{ card: 'generic', title, kind?, rawInput?, content?, locations? }`, `{ card: 'terminal', title, description?, cwd? }`, or `{ card: 'diff', title, diffs, locations? }`. +- Result views are `{ card: 'generic', title?, content? }`, `{ card: 'terminal', title?, output?, exitCode?, signal? }`, `{ card: 'diff', title?, diffs }`, `{ card: 'search', shape, title?, truncated, total, … }` (a completed discovery search — grouped-by-file matches for `shape: 'matches'` (grep) or a flat path list for `shape: 'paths'` (glob), with `truncated`/`total` so a UI never presents a capped result as complete; the view carries no result text and a search has no `card: 'search'` call-time analogue), `{ card: 'read', title?, path, offset, lines, totalLines, lang?, content? }` (a completed file read → a line-numbered, optionally syntax-highlighted code view; `offset` is the 1-based first line the window requested, kept even when `lines` is empty; `lines` is `{ number, text }[]` keeping each file line number, and `content` is the envelope-stripped text a UI without read support falls back to), or `{ card: 'web', kind: 'search' | 'fetch', title?, … }` (a completed web retrieval; the `kind` arms carry the structured search sources or the fetch summary, and a UI without the `web` capability falls back to the raw result content). + +Returning `undefined` selects generic fallback. Presenters depend only on their arguments and the durable result because UIs call them during live streaming and log replay. `output.presentationMeta(args, value)` derives JSON metadata for direct top-level calls; that metadata persists with `tool/result` and returns to `presentResult`, while the canonical value itself remains execution-local and is never replayed. Nested Code dispatches do not compute metadata. `defineTool` soft-validates older logged arguments and falls back instead of crashing replay. `dsh-tool-bash` and `dsh-tool-fs` are the reference implementations; the [canonical-output Agent Note](../../../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md) owns the value/presentation split and the [render-intent Agent Note](../../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md) owns card vocabulary. + +### Code Mode + +Under `code` or `both`, the registry exposes the reserved `run_code` transport and a deterministic SDK for the current scope, generated in the loaded runtime's language — the registry selects the renderer by `ctx.codeRuntime.language` (`typescript` → the TypeScript SDK below, `python` → the Python SDK). Only the program's outer logs and return value re-enter model context. The SDK declares exact per-tool argument and canonical-output types for every visible tool (`ToolArgsMap`/`ToolOutputMap` in TypeScript, named `TypedDict`s in Python), and each binding resolves to the tool's canonical JSON value. Each lossless-JSON binding call re-enters the complete tool pipeline under the native scheduling contract (concurrency-safe calls may overlap up to `maxParallelSubCalls`; exclusive calls run alone as ordering barriers) with logged correlation to the outer call. Denials and other failed results reject with the real program-visible `ToolCallError` carrying only `toolName` and `message`; Native content and internal error codes stay outside the Code contract. Ordinary side effects are not rolled back, and sub-call `additionalContexts` are deferred through the parent result to preserve call/result adjacency. Run settlement aborts and drains outstanding bindings; runtime failures surface as `CodeRunFailedError`. + +Under `code` — not `both` — the transport is also the only entry the model may use: a model-direct call naming any other visible tool resolves to `UNKNOWN_TOOL` at execution creation, before `tools/pre-execute`, approval `ask`, and guards, so nothing observes or approves a call that can only fail. The denial names the route back (`only \`run_code\` is callable directly — call \`\` from inside a \`run_code\` program instead`), because the same prompt declares that tool and a bare `unknown tool` reads as a broken deployment. SDK sub-dispatches carry the outer execution's `parent` token and are exempt, so programs keep every binding the SDK declared. See the [executor-collapse note](../../../.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md), the [Code Mode foundation](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md), [typed-return contract](../../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md), and [code-runtime seam](../../code-runtime/README.md). Try `pnpm run demo:code-mode`. + +- **The SDK section** (`tools:sdk`, order 150): a lazy prompt section regenerating the language-appropriate SDK text at each assembly. In the TypeScript flavor it emits `JsonValue`, exact `ToolArgsMap` / `ToolOutputMap`, `ToolName`, the `ToolCallError` declaration, and a mapped `tools` namespace for the calling scope's visible end capabilities (exotic names via quoted keys), plus fixed usage instructions; the Python flavor (`ctx.codeRuntime.language === 'python'`) emits the equivalent named `TypedDict`s and a `tools` object with matching usage instructions. Deterministic — lexicographic tool order, byte-identical text for an unchanged tool set (prefix-cache-friendly). Both codegens are exported and never throw during prompt assembly: `jsonSchemaToTs` handles every unified schema construct and degrades unsupported raw constructs to `unknown`; `jsonSchemaToPy` does the same, degrading to `Any` (and a whole object to `dict[str, Any]` when a field name is not a legal `TypedDict` attribute, or whenever it is called outside the SDK render, which supplies the naming context a `TypedDict` declaration needs). +- **The dispatch bridge** (`run_code`'s execute): every binding call is snapshotted as lossless JSON before dispatch (`undefined`, `BigInt`, cycles, sparse arrays, `-0`, and exotic objects reject that one call), scheduled through a per-run pool that reuses the native concurrency contract — calls start strictly in submission order, consecutive `isConcurrencySafe` calls overlap up to the validated `maxParallelSubCalls` config (default 10; `1` restores serial dispatch), and an exclusive-classified call drains the pool, runs alone, and bars later calls — given the outer execution's opaque token as `parent`, and run through the complete pre-execute → guards → execute → post-execute → result pipeline. A success returns the final canonical value after policy; a failure reaches the worker as one message and becomes `ToolCallError(toolName, message)`. Each started sub-call logs a `tool/code-dispatch-start` event (deterministic id `:code:`, numbered by submission) at pipeline entry and settles with one `tool/code-dispatch` event carrying the complete model-facing `content`/`isError` outcome (the `tool/result` vocabulary, so UIs render sub-calls through the native path — the pair's `time` fields carry per-sub-call timing); a queued call abandoned by run settlement logs neither. `deriveMessages()` surfaces neither event nor persists the canonical value. Token correlation lets commit-style observers defer an inner success until the final `run_code` result without exposing the live outer execution; ordinary tool side effects are not rolled back. Every sub-call `additionalContexts` entry is deferred through the outer `ToolRunContext` in dispatch order; the loop appends those contexts only after the parent `run_code` result, preserving adjacency and retaining each source/meta even when the program later fails. +- **Settlement discipline**: the bridge owns a run-scoped abort that follows the outer signal in and fires when the run settles for any reason, so a budget expiry aborts an in-flight sub-tool instead of orphaning it; the bridge then drains its queue BEFORE returning, so every `tool/code-dispatch` lands inside the open turn. A failed run throws `CodeRunFailedError` (`code: 'CODE_RUN_FAILED'`, message = the failure kind + captured logs), which the pipeline converts to a structured `isError` the model self-corrects from. +- **Result size**: intermediate binding values cross the worker process whole and have no per-binding byte cap. `run_code` returns canonical `{ logs: string[], result?: JsonValue }`; strings render raw, every other present JSON root renders through a stack-safe pretty JSON traversal whose total indentation is capped at ten characters (deeper subtrees stay compact), `null` remains explicit, and absent `result` means the program returned `undefined`. The worker's configurable `maxOutputBytes` (default 64 MiB) applies only to the combined serialized outer log-array, completion-value, or failure-message payloads; fixed result-envelope syntax and presentation whitespace are outside that limit. Invalid and over-limit completions fail explicitly, and only this outer result is eligible for ordinary spill. + +### Parallel execution + +The agent loop groups consecutive `parallel` calls into a bounded rolling pool and treats each `exclusive` call as an ordering barrier. Only dispatch/body overlaps; policy, durable results, and context retain model order. Code Mode bindings reuse the same classification through the bridge's own pool. The [parallel tool-call Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) owns the shipped declarations and rationale. + +## Model Experience + +### Normal tool schemas + +#### What the model sees + +In normal mode the model sees each visible definition's exact name, description, and JSON schema; the shipped definitions are recorded in the generated [tool package map and schema sections](../../../docs/tool-catalog.md#tool-package-map). Agent-scoped restrictions, shadows, and extension registrations change that agent's end-tool set. + +#### Token effect + +Fixed per-request cost proportional to the visible definitions. Restrictions that hide tools remove their entire schema cost for that agent. + +#### KV Cache effect + +Prefix-stable while visible definitions and their order are unchanged. Registration, disposal, or scoped restriction may invalidate reuse from the first changed schema token. + +### Code Mode schema and system prompt + +#### What the model sees + +Code Mode exposes the generated [`run_code` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tools), the SDK instructions below, and the generated exact SDK block for the loaded runtime's language (the TypeScript `declare const tools` block, or the Python `tools` declaration). `both` exposes normal schemas and this Code Mode API. Under `code` the prompt also carries the `tools:code-only` rule, ordered ahead of the per-tool guidance band so the model reads which tools it may call before it reads what each one is for; `both` renders it empty. The instructions and SDK block match the loaded runtime's language; the TypeScript version (via [`dsh-code-runtime-worker-thread`](../../code-runtime/code-runtime-worker-thread/README.md)) is shown below, and the Python version (for any runtime reporting `language: 'python'`) has the same operations and types in Python syntax (`await tools.name(args)`, subscript access for exotic names, `print(...)` and top-level `return`). + +##### Code Mode SDK instructions + +```markdown +## Writing code for run_code + +`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program: + +- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue. +- Independent read-only calls MAY overlap under `Promise.all` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with `await`. +- Emit results with `return` and/or `console.log(...)`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. + +The available tools: +``` + +#### Token effect + +Fixed per-request cost proportional to the visible definitions. Code Mode trades end-tool schemas for generated SDK text plus one transport schema rather than promising a universal reduction. + +#### KV Cache effect + +Prefix-stable while the Code Mode selection, generated SDK, transport schema, and visible tool set are unchanged. Mode or filter changes may invalidate reuse from the first changed prompt or schema token. + +### Tool-call history and results + +#### What the model sees + +The loop retains model-emitted arguments and the registry's final content. Any thrown or denied call becomes exactly `Error: `. Code Mode returns only the outer program's printed lines and rendered return value, `(run_code completed with no output)` when both are empty, or `Error: code run failed (): ` followed conditionally by `Captured output:` and the captured lines. Inner dispatch events stay log-only; post-execute listeners may append source-attributed context after the result. + +#### Token effect + +Arguments, results, and additional context are data-dependent and resent until compaction. Restrictions that hide tools also remove their schemas before the model can call them. + +#### KV Cache effect + +Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries. + +## Known Limitations and Deferred Work + +- **Concurrency policy is not an event gate** — `executionMode()` reads the resolved tool definition directly; plugins can only declare a classifier on definitions they own. +- **`tools/pre-execute` deliberately cannot rewrite `exec.arguments`** — logged and rendered args would desync from what ran; the rewrite design is [a proposed Agent Note](../../../.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.md). +- **Caller-defined subagent and workflow structured outputs remain object-rooted** — this is a consumer-level guard; the shared schema vocabulary and tool outputs support every JSON root. +- **`timeoutMs` on a definition is declarative only** — the registry never enforces deadlines; enforcement requires the `@deepseek-ai/dsh-tool-call-timeout-policy` wrapper. +- **Code Mode's SDK language follows the one loaded runtime, and a presentation is per agent rather than per tool** — `mode: code`/`both` rejects prompt assembly unless `ctx.codeRuntime.language` has a registered SDK renderer (TypeScript or Python); scoped restrictions/shadows and `presentAs` choose each agent's visible bindings and their form, but within one agent no tool can be native-only while another is code-only. +- **Code Mode intermediate values are execution-local and unbounded by bytes** — the canonical typed values cannot be reconstructed from session replay and may exhaust process or worker memory; only the outer `run_code` output has the worker's configurable hard cap. The durable log copy of each sub-call IS bounded: the `tools/code-dispatch-log` waterfall lets the spill policy replace an oversized `tool/code-dispatch` content with a preview + locator ([rationale](../../../.agents/notes/implemented/feature/2026-07-26-code-dispatch-log-spill.md)). +- **`run_code` state is fresh per run** — a persistent REPL-style kernel is rejected for the MVP (cross-call state would be invisible to the log); see [the Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.zh.md new file mode 100644 index 0000000..6e26a80 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/README.zh.md @@ -0,0 +1,198 @@ +# dsh-tools + +[English](README.md) | 中文 + +工具注册表与执行流水线。工具插件注册各自的 schema 和执行器;agent loop(智能体循环)依次让每次调用经过 `tools/pre-execute`(可扩展的允许/拒绝门禁)→ 已注册的单调守卫 → `tools/execute`(供超时/重试/指标插件使用的环绕分发包装层)→ `tools/post-execute`(检查/替换结果、附加上下文)→ 由工具定义持有的 `finalizeContent` 边界 → 仅观测的 `tools/result` 通知。注册表还决定以何种方式向模型呈现工具:`mode` 配置可以选择原生 Function Calling(函数调用)、[Code Mode](#code-mode),或同时选择两者;单个 agent 可用 `presentAs` 为自己遮蔽该默认值。 + +## 服务:`ToolRuntime`(ctx 键:`tools`) + +### 配置 + +```yaml +tools: + mode: native # native (default) | code | both +``` + +`native` 以函数定义的形式贡献可见工具。`code` 会提供保留的 `run_code` 传输、生成的 `tools:sdk` 段,以及声明「只有 `run_code` 可被直接调用」的 `tools:code-only` 规则。执行器随后强制执行该规则:模型直接调用其他任何工具时,会在策略运行前将该调用解析为 `UNKNOWN_TOOL`;`both` 同时提供两种形式,且不声明该规则,因为其中的原生调用确实可以执行。没有单独声明呈现模式的 agent 默认采用此配置;agent preset 可通过 [`dsh-agent-tool-presentation`](../agent-tool-presentation/README.md) 自行选择呈现模式。不能注册、遮蔽、限制或移除该保留传输,且无论配置何种模式,该名称都是保留的,因为任何 agent 都可能选择 code 模式。非原生模式要求所加载 `ctx.codeRuntime` 的 `language` 有已注册的 SDK 渲染器——TypeScript 经 [`dsh-code-runtime-worker-thread`](../../code-runtime/code-runtime-worker-thread/README.md) 交付;Python 渲染器内置,驱动任何报告 `language: 'python'` 的运行时(第一方 `dsh-code-runtime-python` 后端另行交付)。没有渲染器的运行时语言会导致提示词组装明确失败;如果 `systemPrompt.toolOrder` 条目指向当前模式未贡献的工具,系统会拒绝组装提示词。`system-prompt/assemble` 监听器可以替换注册表贡献;它返回的组装结果具有权威性,因此该监听器负责保留可用的 Code Mode 协议。 + +### 公开 API + +- `ctx.tools.register(definition: ToolDefinition): () => void`:注册一个受信任、带类型的同进程定义,其中必须包含规范的 `output` 声明。所在层由调用上下文的作用域决定:普通插件上下文会全局注册;agent 的 `agent.ctx` 只为该 agent 注册,并在此处遮蔽同名全局工具。同一层内名称重复会抛出;非原生模式还会拒绝保留的 `run_code` 传输名称。缺失或不受支持的输出声明,以及非正数或非有限的 `timeoutMs`,都会使注册失败。可选的同步 `finalizeContent` 回调会在调用开始时纳入快照;在所有流水线结果(包括实体化其他结果字段时发现的错误)规范化之后,它只能替换最终面向模型的内容。该注册会随调用方 fiber 一同 dispose(资源释放)。 +- `ctx.tools.presentAs(mode: ToolPresentationMode): () => void`:为本 agent 选择面向模型的呈现方式,仅对该 agent 遮蔽 `mode` 配置;从普通上下文调用会抛出(进程级呈现方式是那个配置字段),同一 scope 内第二次声明也会抛出。code 类模式还会为该 agent 注册它自己的 `tools:sdk` 段。工具目录保持不变:`schemas(agent)` 仍会报告该 agent 的能力;只有组装结果中的工具列表会按所选呈现方式收束。随调用方 fiber dispose。 +- `ctx.tools.restrict(filter)`:对全局工具应用 agent 作用域的允许/拒绝掩码;从普通上下文调用会抛出。筛选器在注册时创建快照;多个掩码取交集,随后再合并作用域本地工具。拒绝掩码会接纳后来出现且未点名的全局工具,而允许掩码会排除后来出现的名称。未知、本地或保留名称以及空筛选器都会被拒绝。这是实时可见性组合,不是权限边界;参见[作用域安全非目标](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals)。 +- `ctx.tools.get(name: string, scope?: ScopeKey): ToolDefinition | undefined`:返回指定作用域可见的解析结果,其中已应用名称遮蔽;被作用域限制排除的全局工具会被视为不存在。呈现器会传入发起调用的 agent,使卡片与实际执行内容一致。 +- `ctx.tools.schemas(scope?: ScopeKey): ToolSchema[]`:返回该作用域可见的所有 schema(不含 `execute` 函数)。已交付工具的 schema 收录在 [docs/tool-catalog.md](../../../docs/tool-catalog.md) 中;该目录通过启动每个工具插件并采集此方法的结果生成(参见[工具 schema 目录 Agent Note](../../../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md))。 +- `ctx.tools.guard(guard: ToolGuard): () => void`:在 `tools/pre-execute` 之后注册单调同步执行守卫:返回理由会拒绝调用,返回 `undefined` 则保持原决定。普通上下文守卫全局生效;`agent.ctx` 守卫只对该 agent 生效。后续 waterfall(瀑布式事件)监听器无法将守卫的拒绝重新变为允许。随调用 fiber dispose。 +- `ctx.tools.execute(exec)`:以无损方式快照并冻结参数,分配不透明 token,运行完整的策略/分发/结果流水线,然后在最终观测前独立快照权威结果。无效参数会进入同一结果路径,但不会到达策略或工具主体。环绕包装层只能替换 `signal`;注册表会在进入工具主体之前,立即将调用方的原始信号重新合并到当前信号中。 +- `ctx.tools.executionMode(exec)`:返回 `parallel` 的唯一条件是可见定义的 `isConcurrencySafe(exec.arguments)` 分类器恰好返回 `true`;未知、隐藏、未声明、无效或抛出异常的分类结果均为独占。 + +### 注入的服务 + +`SystemPrompt`:注册表通过 `ctx.systemPrompt.tools()` 自动将工具 schema 送入系统提示词组装。审批 seam 则在可用时使用(`ctx.get('approval')`,无静态注入):未部署该 seam 时仍会将询问退化为拒绝,而无论是否存在该 seam,注册表都会保持活动。 + +### 取消 + +取消采用协作方式,并等待完全停稳。每次类型化调用都提供由调用方拥有的 `AbortSignal`;工具主体通过必填的只读 `exec.signal` 接收它,只有 `tools/execute` 包装层可以临时替换这个必填信号。注册表会在替换期间保留调用方取消,并且绝不会在已启动的同进程 Promise 尚未结算时提前返回。工具主体调用前发生的取消为 `ABORTED_BEFORE_DISPATCH`;工具主体被调用后发生的取消,只能将成功结果替换为 `ABORTED`。拒绝、包装层失败、工具失败、后置策略失败或由超时机制产生的 `TOOL_TIMEOUT` 仍保留更具体的结果。入口处已中止的调用会实体化并冻结参数,随后跳过所有策略和分发阶段,只发布一个结果。每个异步工具都必须观测或转发该信号,并且只能在其负责的工作停止后结算。[工具取消 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md) 规定完整约定和强制终止边界。 + +### 实时事件 + +实时注册表流水线先经过 3 道可转换的 waterfall,再经过由工具定义持有的内容终结器,最后发布仅供观测的 `tools/result` 事件;注册表变更通知有意不作过滤,并作为共享状态通知发布。确切签名、分发 mode、作用域筛选和失败隔离约定位于 [tools.md](../../../docs/subsystems/tools.md#cordis-surface) 的生成区块,完整顺序则在生成的[工具执行流水线](../../../docs/tool-execution-pipeline.md)中可视化。`tools/result` 是实时事件;名称相近的 `tool/result` 是 agent loop 随后追加的持久会话事件。 + +### 关键类型 + +- `ToolDefinition`:`ToolSchema` + 必填的 `output { schema, render, presentationMeta? }` + `execute(args, exec)`,以及可选的最终内容回调、呈现回调、协作式 `timeoutMs` 和逐调用的 `isConcurrencySafe(args)` 分类器。主体只能返回输出 schema 声明的规范 JSON 值,并通过 `exec.signal` 协作停止。`finalizeContent(exec, result)` 对每个规范化结果都恰好运行一次,包括绕过后置策略的失败,并且只能替换 `content`;它必须是同步且对所有输入都有定义的函数。 +- `ToolExecutionInput`:调用方提供的调用描述:`{ callId, name, arguments, signal, agent?, parent? }`;`signal` 必填且只读,调用方可以将外层执行的不透明 token 作为 `parent` 传入,但绝不能选择新执行自身的 token。 +- `ToolExecutionToken`:注册表分配的全新带品牌 `Symbol`。它只支持通过相等性进行关联,绝不会跨越模型、日志或 worker 边界。 +- `ToolExecution`:只读流水线视图:不可变的 `{ token, callId, name, arguments, signal, agent?, parent? }`;注册表会另行保留并重新融合调用方的原始信号。`ToolDispatchExecution` 是仅供 `tools/execute` 使用的视图,其必填信号可变,因此包装层可以替换并还原它,但不能删除它。嵌套调用的 `parent` 是 `ToolExecutionToken`,而不是执行对象。 +- `ToolRunContext`:传给工具主体的执行上下文,在 `ToolExecution` 基础上增加 `deferContext(context)`。它把一条上下文推迟到该工具的最终结果抵达循环时——通常是组合工具转运的嵌套分发上下文,也可以是叶子工具创建的全新插件来源指令(如 `tool-goal` 的收尾注入)——即使工具后来抛出或取消胜出也不例外;该方法绝不会立即注入上下文。 +- `ToolExecutionResult`:带判别标记的执行局部结果。成功形态为 `{ isError:false, value:JsonValue, content, meta?, additionalContexts? }`;失败形态为 `{ isError:true, error:{ message, info? }, content, meta?, additionalContexts? }`,且不含值。调用身份保留在不可变的 `ToolExecution` 上。注册表会在呈现前快照、验证并冻结规范值,随后在最终观测前实体化持久呈现字段。`ToolFailure.info` 携带内部的 `{ name, code }`,用于表示 `HarnessError`;`additionalContexts` 会保留每个通过延迟或 post-execute 加入且带标识的 `UserMessage`,供循环在结果后按 FIFO 顺序处理。 +- `PreToolDecision`:`{kind:'allow'}` | `{kind:'deny', reason}` | `{kind:'ask', reason?}`。该类型有意不提供输入改写;`ask` 在挂载 [`ctx.approval`](../../interaction/user-approval/README.md) 时由它处理,否则退化为拒绝。 +- `PostToolDecision`:接受决定可以替换 `content` 或 `value`(不能同时替换),并可附加 `additionalContexts`;阻止决定会把反馈变成无值失败。替换内容会保留规范值和元数据。替换值会重新验证,并重新呈现内容/元数据。接受决定会先保留工具延迟的上下文,再附加决定上下文;阻止决定会丢弃工具延迟的上下文,只公开阻止决定显式提供的上下文。 +- `ToolGuard`:`(execution) => string | undefined`;返回的字符串是最终单调拒绝理由,在可重排的前置执行 waterfall 之后、分发之前求值。 +- `ToolCallView` / `ToolResultView`:提供方无关、带 `card` 标签的呈现意图;工具通过 `presentCall` / `presentResult` 返回该意图,从而拥有 UI 呈现其自身调用的方式(参见「工具拥有的 UI 呈现」)。 + +### 扩展点 + +- 工具插件调用 `ctx.tools.register()`:schema 会自动流入组装结果。 +- `tools/pre-execute` 是可重排的允许/拒绝/询问门禁;`ctx.tools.guard()` 在其后添加单调的拥有方策略。 +- `tools/execute` 会环绕包装规范化后的规范分发,以支持超时、重试或指标采集。包装层只能替换操作信号;包装层生成的成功结果会根据已解析工具的输出声明进行规范化。每个规范结果属于一个不可变分发 token,因此来自其他调用或工具的缓存结果会根据当前声明重新验证。 +- `tools/post-execute` 可以替换呈现内容、替换规范值、通过反馈阻止,或附加有序上下文。随后,定义可选的 `finalizeContent` 会在普通结果和外层流水线失败中维护其最终、仅涉及内容的不变式;`tools/result` 观测不可变的最终结果。内容替换不是保密边界:当编程消费方不得接收某个值时,应阻止或替换该值。 +- 确切签名与顺序位于 [tools.md](../../../docs/subsystems/tools.md#cordis-surface) 的生成区块和[流水线](../../../docs/tool-execution-pipeline.md)中。 +- MCP 服务器:每个服务器使用一个插件;发现工具后,使用服务器的 schema 调用 `ctx.tools.register()`。 + +### 类型化工具参数 schema + +第一方插件作者可以使用本包导出的 `defineTool()` 辅助函数定义类型化工具参数 schema: + +```ts +import { readFile } from 'node:fs/promises' +import type { Context } from '@deepseek-ai/cordis' +import { defineTool } from '@deepseek-ai/dsh-tools' + +declare const ctx: Context + +ctx.tools.register(defineTool({ + name: 'read_file', + description: 'Read a file from disk.', + parameters: { + path: { type: 'string', required: true, description: 'Absolute file path' }, + offset: { type: 'number' }, + limit: { type: 'number' }, + }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, + async execute(args, exec) { + // args is typed: { path: string; offset?: number; limit?: number } + return readFile(args.path, { encoding: 'utf8', signal: exec.signal }) + }, +})) +``` + +统一 schema DSL 使用 `ParameterSchemaSpec` 表示隐式开放参数对象,使用 `ValueSchemaSpec` 表示任意 JSON 值根。它支持 `string`、`number`、`integer`、`boolean`、`null`、`array`、`object`、仅供作者使用的 `json`,以及恰好匹配一个分支的 `oneOf`;标量 `enum`/`const` 值必须符合其声明类型。每个显式 DSL 对象都声明 `additionalProperties: true | false`,而隐式参数根和原始 JSON Schema 保持标准的开放默认值。schema 记录只接受自身可枚举字符串键,schema 数组必须是稠密普通数组。编译、验证、从注册表分离以及 schema 到 TypeScript 的呈现均使用显式工作栈,因此,对有效深层 schema 的运行时处理受内存而非调用栈限制;`InferValue` 在 16 层容器内保留精确类型,之后回退到 `JsonValue`,使 TypeScript 自身也保持栈安全。 + +`defineTool` 定义会在执行前验证模型参数,并把缺失必填值、基本类型错误、无效枚举成员和嵌套违规转换为 `ToolArgsError`(`INVALID_ARGS`),进入普通错误结果路径。它还会根据 `output.schema` 推断主体返回类型和纯输出投影器;注册表在呈现前快照并验证返回的无损 JSON。隐式参数根是开放的;显式对象只有在设置 `additionalProperties: true` 时才接受额外键,而没有声明属性的封闭对象只接受 `{}`。原始 JSON Schema 对象保持开放,除非显式设置 `additionalProperties: false`。系统不会应用默认值;没有 `properties` 的开放对象和没有 `items` 的数组只接受容器类型检查。通过原始方式注册的工具负责输入验证,但仍需声明输出,并由注册表强制校验输出。 + +有关详细信息,请参阅公开 API 中的 `defineTool`、`validateArgs`、`ToolArgsError`、`ValueSchemaSpec`、`ParameterSchemaSpec`、`InferValue`、`InferArgs`、`valueSchemaSpecToJsonSchema` 和 `parameterSchemaSpecToJsonSchema`。 + +可选的 `timeoutMs` 必须为正数且为有限值;它是策略元数据,不是模型可见的 schema。 + +可选的 `isConcurrencySafe(args)` 接收经过软验证的类型化参数。只有确切的 `true` 才允许并发分发/主体执行;无效输入和所有其他结果仍为独占。选择并发的主体不得改变父级拥有的状态;共享状态竞态必须具有交换性,否则必须安全拒绝。[并行工具调用 Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) 规定完整安全约定。 + +### 强制执行的原始 JSON Schema 子集 + +`JsonSchemaNode` 是工具输出、Code Mode 生成、subagent 和工作流共享的原始 JSON Schema 对应类型。它允许任意 JSON 根、仅含注解且不施加约束的 JSON 节点,以及恰好匹配一个分支的 `oneOf`;注解必须保持为无损 JSON。`assertSupportedJsonSchema()` 拒绝不受支持的构造,而 `validateJsonSchemaValue()` 返回带路径的违规信息。subagent 和工作流通过 `assertObjectJsonSchema()` 与 `ObjectJsonSchema` 保留调用方定义的对象根要求,而不是依赖共享词汇的限制。 + +### 由工具定义的 UI 呈现 + +工具可以选择通过纯函数 `presentCall()` 和 `presentResult()` 定义呈现意图,使 UI 无需针对工具名称编写特殊逻辑: + +- 调用视图为 `{ card: 'generic', title, kind?, rawInput?, content?, locations? }`、`{ card: 'terminal', title, description?, cwd? }` 或 `{ card: 'diff', title, diffs, locations? }`。 +- 结果视图为 `{ card: 'generic', title?, content? }`、`{ card: 'terminal', title?, output?, exitCode?, signal? }`、`{ card: 'diff', title?, diffs }`、`{ card: 'search', shape, title?, truncated, total, … }`(已完成的发现型搜索——`shape: 'matches'`(grep)为按文件分组的匹配,`shape: 'paths'`(glob)为扁平路径列表,配 `truncated`/`total` 使 UI 永不把被截断的结果当作完整结果呈现;该视图不携带结果文本,且搜索没有 `card: 'search'` 的调用时对应视图)、`{ card: 'read', title?, path, offset, lines, totalLines, lang?, content? }`(已完成的文件读取→带行号、可选语法高亮的代码视图;`offset` 是窗口请求的 1-based 起始行,即使 `lines` 为空也保留;`lines` 是 `{ number, text }[]`,保留每一行的文件行号,`content` 是去除读取结果外层封装后的正文,供不支持读取视图的 UI 回退显示)或 `{ card: 'web', kind: 'search' | 'fetch', title?, … }`(已完成的 web 检索;`kind` 各分支携带结构化的搜索来源或抓取摘要,不具备 `web` 能力的 UI 回退到原始结果内容)。 + +返回 `undefined` 会选择通用回退。呈现器只依赖其参数和持久结果,因为 UI 会在实时流式输出和日志回放期间调用它们。`output.presentationMeta(args, value)` 为直接的顶层调用派生 JSON 元数据;该元数据随 `tool/result` 持久化并传回 `presentResult`,而规范值本身仍只存在于执行局部,绝不会回放。嵌套 Code 分发不会计算元数据。`defineTool` 会软验证较旧的日志参数并回退,而不会使回放崩溃。`dsh-tool-bash` 与 `dsh-tool-fs` 是参考实现;[规范输出 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md) 规定值/呈现拆分,[呈现意图 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md) 规定卡片词汇。 + +### Code Mode + +在 `code` 或 `both` 模式下,注册表为当前作用域公开保留的 `run_code` 传输和按所加载运行时语言生成的确定性 SDK——注册表按 `ctx.codeRuntime.language` 选择渲染器(`typescript` → 下方的 TypeScript SDK,`python` → Python SDK)。只有程序的外层日志与返回值会重新进入模型上下文。SDK 为每个可见工具声明精确的参数与规范输出类型(TypeScript 为 `ToolArgsMap`/`ToolOutputMap`,Python 为具名 `TypedDict`),每个绑定都会解析为该工具的规范 JSON 值。每个无损 JSON 绑定调用都会在原生调度约定下重新进入完整工具流水线(并发安全的调用最多可重叠 `maxParallelSubCalls` 个;独占调用单独运行并构成排序屏障),并在日志中与外层调用建立关联。拒绝及其他失败结果会以程序实际可见的 `ToolCallError` 形式拒绝,且只携带 `toolName` 和 `message`;Native 内容和内部错误码留在 Code 约定之外。普通副作用不会回滚,子调用的 `additionalContexts` 会通过父结果延迟,以保持调用/结果相邻。运行结算会中止并排空尚未完成的绑定;运行时失败以 `CodeRunFailedError` 形式出现。 + +在 `code`(而非 `both`)下,该传输同时也是模型唯一可用的入口:模型直呼其他任何可见工具名,都会在创建执行时、早于 `tools/pre-execute`、审批 `ask` 和 guards 解析为 `UNKNOWN_TOOL`,因此没有任何一方会观察或批准一个注定失败的调用。拒绝信息会给出正确路径(`only \`run_code\` is callable directly — call \`\` from inside a \`run_code\` program instead`),因为同一份提示词刚刚声明过那个工具,只说 `unknown tool` 会被读成部署损坏。SDK 子分发携带外层执行的 `parent` token,不受此限制,因此程序保留 SDK 声明的全部绑定。参见[执行器塌缩 note](../../../.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md)、[Code Mode 基础](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)、[类型化返回约定](../../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md)和[代码运行时 seam](../../code-runtime/README.md)。可以运行 `pnpm run demo:code-mode` 试用。 + +- **SDK 段**(`tools:sdk`,顺序 150):一个在组装时求值的提示词段,每次组装都会重新生成与所加载运行时语言相符的 SDK 文本。TypeScript 形态会生成 `JsonValue`、精确的 `ToolArgsMap` / `ToolOutputMap`、`ToolName`、`ToolCallError` 声明,以及映射调用作用域最终可见工具的 `tools` 命名空间(特殊名称使用带引号的键),并附带固定的使用说明;Python 形态(`ctx.codeRuntime.language === 'python'`)发出等价的具名 `TypedDict` 与一个带相同用法说明的 `tools` 对象。其输出具有确定性:工具按字典序排列;工具集合不变时,文本逐字节相同(有利于前缀 cache)。两个代码生成器都已导出,且绝不会在提示词组装期间抛出:`jsonSchemaToTs` 处理统一 schema 的每种构造并将不受支持的原始构造降级为 `unknown`;`jsonSchemaToPy` 同理,降级为 `Any`(当某字段名不是合法的 `TypedDict` 属性时,或在 SDK 渲染之外被调用时——`TypedDict` 声明所需的命名上下文由该渲染提供——整个对象降级为 `dict[str, Any]`)。 +- **分发桥接层**(`run_code` 的 execute):每个绑定调用都会在分发前快照为无损 JSON(`undefined`、`BigInt`、循环、稀疏数组、`-0` 和特殊对象会使该次调用被拒绝),经由每次运行独有、复用原生并发约定的池调度——调用严格按提交顺序启动,连续的 `isConcurrencySafe` 调用最多可重叠经校验的 `maxParallelSubCalls` 配置个(默认 10;设为 `1` 即恢复串行分发),被分类为独占的调用先排空池、单独运行并阻挡其后的调用——以外层执行的不透明 token 作为 `parent`,并经过完整的 pre-execute → guards → execute → post-execute → result 流水线。成功会返回策略处理后的最终规范值;失败以一条消息到达 worker,并成为 `ToolCallError(toolName, message)`。每个已启动的子调用在进入流水线时记录一条 `tool/code-dispatch-start` 事件(确定性 id `:code:`,按提交顺序编号),并以一条携带完整模型可见 `content`/`isError` 结果的 `tool/code-dispatch` 事件完结(采用 `tool/result` 词汇,因此 UI 会沿原生路径呈现子调用——这对事件的 `time` 字段承载每个子调用的计时);因 run 结算而被放弃的排队调用两者都不记录。`deriveMessages()` 既不公开这两个事件,也不持久化规范值。token 关联使按提交语义工作的观察器可以延后提交内部调用的成功结果,直到最终 `run_code` 结果确定,而无需暴露进行中的外层执行;普通工具副作用不会回滚。每个子调用的 `additionalContexts` 条目都会按分发顺序通过外层 `ToolRunContext` 延迟;循环只在父级 `run_code` 结果之后追加这些上下文,从而保持相邻关系,并且即使程序后来失败,也会保留各自的来源/元数据。 +- **结算纪律**:桥接层拥有一个运行作用域的中止机制;该中止会跟随传入的外层信号,并在运行因任何原因结算时触发,因此预算耗尽会中止正在运行的子工具,而不会将其遗留。桥接层随后会在返回之前排空队列,使每个 `tool/code-dispatch` 都落在仍打开的轮次内。失败的运行会抛出 `CodeRunFailedError`(`code: 'CODE_RUN_FAILED'`,message = 失败类型 + 已捕获日志),流水线会将其转换为模型可据以自我修正的结构化 `isError`。 +- **结果大小**:中间绑定值会完整传入 worker 进程,且没有逐绑定字节上限。`run_code` 返回规范的 `{ logs: string[], result?: JsonValue }`;字符串原样呈现,其他所有存在的 JSON 根都通过栈安全的美化 JSON 遍历呈现,总缩进最多为 10 个字符(更深的子树保持紧凑),`null` 保持显式,而缺少 `result` 表示程序返回 `undefined`。worker 可配置的 `maxOutputBytes`(默认 64 MiB)只应用于组合序列化后的外层日志数组、完成值或失败消息载荷;固定的结果封装语法和呈现空白不计入该上限。无效和超限的完成会明确失败,只有这个外层结果可以按常规 spill 机制处理。 + +### 并行执行 + +agent loop 将连续的 `parallel` 调用归入有界滚动池,并把每个 `exclusive` 调用视为顺序屏障。只有分发/主体会重叠;策略、持久结果和上下文仍保持模型顺序。Code Mode 绑定通过桥接层自己的池复用同一套分类。[并行工具调用 Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) 规定已交付声明及其原理。 + +## 模型体验 + +### 普通工具 schema + +#### 模型看到的内容 + +在普通模式下,模型会看到每个可见定义的确切名称、描述和 JSON Schema;已交付定义记录在生成的[工具包映射和 schema 章节](../../../docs/tool-catalog.md#tool-package-map)中。agent 作用域的限制、遮蔽和扩展注册会改变该 agent 的最终工具集合。 + +#### Token 影响 + +每次请求的固定成本与可见定义成正比。隐藏工具的限制会为该 agent 移除其全部 schema 成本。 + +#### KV Cache 影响 + +只要可见定义及其顺序不变,前缀就保持稳定。注册、dispose 或作用域限制可能从第一个改变的 schema token 起使复用失效。 + +### Code Mode schema 与系统提示词 + +#### 模型看到的内容 + +Code Mode 会公开生成的 [`run_code` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tools)、下方 SDK 说明,以及按所加载运行时语言生成的精确 SDK 块(TypeScript 的 `declare const tools` 块,或 Python 的 `tools` 声明)。`both` 会同时公开普通 schema 与此 Code Mode API。在 `code` 下,提示词还会带上 `tools:code-only` 规则,其顺序排在逐工具指导段之前,让模型先读到「可以调用哪些工具」再读「每个工具做什么」;`both` 下它渲染为空。说明与 SDK 块随所加载运行时的语言切换;下方展示 TypeScript 版本(经 [`dsh-code-runtime-worker-thread`](../../code-runtime/code-runtime-worker-thread/README.md)),Python 版本(用于任何报告 `language: 'python'` 的运行时)以 Python 语法提供相同操作和类型(`await tools.name(args)`、特殊名称用下标访问、`print(...)` 与顶层 `return`)。 + +##### Code Mode SDK 说明 + +```markdown +## Writing code for run_code + +`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program: + +- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue. +- Independent read-only calls MAY overlap under `Promise.all` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with `await`. +- Emit results with `return` and/or `console.log(...)`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. + +The available tools: +``` + +#### Token 影响 + +每次请求的固定成本与可见定义成正比。Code Mode 使用生成的 SDK 文本加一个传输 schema 取代最终工具 schema,但不承诺普遍减少成本。 + +#### KV Cache 影响 + +只要 Code Mode 选择、生成的 SDK、传输 schema 和可见工具集合不变,前缀就保持稳定。模式或筛选器变更可能从第一个改变的提示词或 schema token 起使复用失效。 + +### 工具调用历史与结果 + +#### 模型看到的内容 + +循环会保留模型发出的参数和注册表的最终内容。任何抛出异常或遭到拒绝的调用,都会转换为确切的 `Error: `。Code Mode 只返回外层程序打印的行和呈现后的返回值;两者都为空时返回 `(run_code completed with no output)`;失败时返回 `Error: code run failed (): `,并根据是否存在已捕获内容,在其后附加 `Captured output:` 与捕获的行。内部分发事件只保留在日志中;后置执行监听器可以在结果之后追加带来源归属的上下文。 + +#### Token 影响 + +参数、结果和附加上下文取决于数据,并会重复发送直至压缩(compaction)。隐藏工具的限制还会在模型可以调用这些工具之前移除其 schema。 + +#### KV Cache 影响 + +仅追加;新的可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。 + +## 已知限制与暂缓事项 + +- **并发策略不是事件门禁**:`executionMode()` 直接读取已解析的工具定义;插件只能在自身拥有的定义上声明分类器。 +- **`tools/pre-execute` 有意不允许改写 `exec.arguments`**:否则日志记录和呈现的参数会与实际运行内容失去同步;改写设计记录在[拟议的 Agent Note](../../../.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.md)中。 +- **调用方定义的 subagent 与工作流结构化输出仍要求对象根**:这是消费方层面的守卫;共享 schema 词汇和工具输出支持任意 JSON 根。 +- **定义中的 `timeoutMs` 仅作声明之用**:注册表绝不会强制执行截止时间;要强制执行,必须使用 `@deepseek-ai/dsh-tool-call-timeout-policy` 包装层。 +- **Code Mode 的 SDK 语言由当前加载的运行时决定,且呈现方式按 agent 而非按工具**:`mode: code`/`both` 会拒绝组装提示词,除非 `ctx.codeRuntime.language` 有已注册的 SDK 渲染器(TypeScript 或 Python);作用域限制/遮蔽与 `presentAs` 会选择每个 agent 的可见绑定及其形态,但在同一个 agent 内不能让一个工具仅使用 Native,而另一个仅使用 Code。 +- **Code Mode 中间值只存在于执行局部,且没有字节上限**:这些规范的类型化值无法从会话回放重建,并可能耗尽进程或 worker 内存;只有外层 `run_code` 输出受 worker 可配置的硬上限约束。每个子调用的持久日志副本则确实有上限:`tools/code-dispatch-log` waterfall 允许 spill 策略把过大的 `tool/code-dispatch` 内容替换为预览加定位符([原理](../../../.agents/notes/implemented/feature/2026-07-26-code-dispatch-log-spill.md))。 +- **每次运行都会获得全新的 `run_code` 状态**:MVP 不采用持久 REPL 风格内核(跨调用状态不会出现在日志中);参见 [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/index.js new file mode 100644 index 0000000..813391b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/index.js @@ -0,0 +1,3570 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { AnonymousEntries, NamedEntries, ScopedLayers, scopeOf, scopeTarget } from "@deepseek-ai/dsh-scope"; +import { CallId, HarnessError, assertNever, deepFreeze } from "@deepseek-ai/dsh-llm"; +import { isJsonValue, snapshotJsonValue } from "@deepseek-ai/dsh-session"; +//#region lib/types/json-schema.js +/** +* Enforced JSON Schema subset shared by tool outputs, generated Code Mode +* types, subagents, and workflows. The subset accepts any JSON root, an +* annotation-only schema for unconstrained JSON, one scalar `type`, object +* `properties`/`required`/boolean `additionalProperties`, array `items`, +* type-correct scalar `enum`/`const`, and exact-one `oneOf`. +* +* Unsupported or misplaced keywords reject rather than being accepted without +* enforcement. Consumers that require an object root apply +* {@link assertObjectJsonSchema} before accepting input. +* @module dsh-tools/json-schema +*/ +/** +* Thrown when a raw schema falls outside the enforced subset. `violations` +* lists every offending path instead of stopping at the first author error. +*/ +var JsonSchemaError = class extends HarnessError { + /** Individual schema violations in walk order. */ + violations; + constructor(violations) { + super(`unsupported JSON schema: ${violations.join("; ")}`, "UNSUPPORTED_SCHEMA"); + this.name = "JsonSchemaError"; + this.violations = violations; + } +}; +const CONSTRAINT_KEYWORDS = new Set([ + "type", + "oneOf", + "properties", + "required", + "additionalProperties", + "items", + "enum", + "const" +]); +const ANNOTATION_KEYWORDS = new Set([ + "description", + "title", + "default", + "examples" +]); +const SCHEMA_TYPES = [ + "object", + "array", + "string", + "number", + "integer", + "boolean", + "null" +]; +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const constructor = Object.getOwnPropertyDescriptor(prototype, "constructor")?.value; + if (typeof constructor !== "function") return false; + try { + return constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } catch { + return false; + } +} +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value) { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, "Object"); +} +/** +* Test for a realm-agnostic plain JSON record without accepting arrays or +* exotic objects. +* @param value - candidate record from any JavaScript realm. +* @returns Whether the value has a plain-object prototype chain. +*/ +function isPlainJsonRecord(value) { + if (typeof value !== "object" || value === null || Array.isArray(value)) return false; + try { + const prototype = Object.getPrototypeOf(value); + return prototype === null || typeof prototype === "object" && isIntrinsicObjectPrototype(prototype); + } catch { + return false; + } +} +/** Whether an array uses one realm's intrinsic `Array.prototype`. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, "Array")) return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === "object" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype); +} +/** Return whether a record contains only own enumerable string keys. */ +function hasOnlyEnumerableStringKeys(value) { + try { + return Reflect.ownKeys(value).every((key) => typeof key === "string" && Object.prototype.propertyIsEnumerable.call(value, key)); + } catch { + return false; + } +} +/** +* Test for an ordinary schema record whose keys survive JSON projection. +* @param value - candidate record from any JavaScript realm. +* @returns Whether the record has an intrinsic prototype and only own enumerable string keys. +*/ +function isJsonSchemaRecord(value) { + return isPlainJsonRecord(value) && hasOnlyEnumerableStringKeys(value); +} +/** +* Test for a dense ordinary array with no JSON-invisible decorations. +* @param value - candidate array from any JavaScript realm. +* @returns Whether the array is intrinsic, dense, and undecorated. +*/ +function isPlainJsonArray(value) { + if (!Array.isArray(value)) return false; + try { + if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false; + for (let index = 0; index < value.length; index++) if (!Object.hasOwn(value, index)) return false; + return true; + } catch { + return false; + } +} +/** Lossless finite JSON number, excluding negative zero. */ +function isJsonNumber(value) { + return typeof value === "number" && Number.isFinite(value) && !Object.is(value, -0); +} +/** Whether a scalar is valid for one declared schema type. */ +function scalarMatches(type, value) { + switch (type) { + case "string": return typeof value === "string"; + case "number": return isJsonNumber(value); + case "integer": return isJsonNumber(value) && Number.isInteger(value); + case "boolean": return typeof value === "boolean"; + case "null": return value === null; + /* v8 ignore next -- JsonSchemaScalarType is closed; this retains compile-time exhaustiveness. */ + default: return assertNever(type, "JsonSchemaType"); + } +} +/** Keywords that are invalid beside `oneOf`. */ +const ONE_OF_SIBLING_KEYWORDS = [ + "properties", + "required", + "additionalProperties", + "items", + "enum", + "const" +]; +/** Validate object-only fields after its property schemas have been visited. */ +function checkObjectSchemaTail(node, path, properties, violations) { + const hasRequired = Object.hasOwn(node, "required"); + const required = hasRequired ? node.required : void 0; + if (hasRequired) if (!isPlainJsonArray(required) || required.some((entry) => typeof entry !== "string")) violations.push(`${path}.required must be an array of strings`); + else { + const declared = isJsonSchemaRecord(properties) ? properties : {}; + for (const key of required) if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names "${key}" which is not in properties`); + } + if (Object.hasOwn(node, "additionalProperties") && typeof node.additionalProperties !== "boolean") violations.push(`${path}.additionalProperties must be a boolean`); +} +/** Collect every violation for one raw schema tree without using the JavaScript call stack. */ +function checkSchemaNode(root, rootPath, violations, seen) { + const tasks = [{ + kind: "enter", + node: root, + path: rootPath + }]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "leave") { + seen.delete(task.node); + continue; + } + if (task.kind === "one-of-tail") { + for (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(task.node, key)) violations.push(`${task.path}.${key} is not supported beside oneOf`); + continue; + } + if (task.kind === "object-tail") { + checkObjectSchemaTail(task.node, task.path, task.properties, violations); + continue; + } + const { node, path } = task; + if (!isJsonSchemaRecord(node)) { + violations.push(`${path} must be a schema object`); + continue; + } + if (seen.has(node)) { + violations.push(`${path} is circular`); + continue; + } + seen.add(node); + tasks.push({ + kind: "leave", + node + }); + for (const key of Object.keys(node)) { + if (CONSTRAINT_KEYWORDS.has(key)) continue; + if (ANNOTATION_KEYWORDS.has(key)) { + try { + if (!isJsonValue(node[key])) violations.push(`${path}.${key} annotation must be lossless JSON data`); + } catch { + violations.push(`${path}.${key} annotation must be lossless JSON data`); + } + continue; + } + violations.push(`${path}.${key} is not a supported keyword (subset: type/oneOf/properties/required/additionalProperties/items/enum/const + annotations)`); + } + if (Object.hasOwn(node, "description") && typeof node.description !== "string") violations.push(`${path}.description must be a string`); + if (Object.hasOwn(node, "title") && typeof node.title !== "string") violations.push(`${path}.title must be a string`); + const hasType = Object.hasOwn(node, "type"); + const hasOneOf = Object.hasOwn(node, "oneOf"); + if (hasType && hasOneOf) { + violations.push(`${path} cannot declare both type and oneOf`); + continue; + } + if (!hasType && !hasOneOf) { + for (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(node, key)) violations.push(`${path}.${key} requires type or oneOf`); + continue; + } + if (hasOneOf) { + const oneOf = node.oneOf; + tasks.push({ + kind: "one-of-tail", + node, + path + }); + if (!isPlainJsonArray(oneOf) || oneOf.length < 2) violations.push(`${path}.oneOf must be an array of at least two schemas`); + else for (let index = oneOf.length - 1; index >= 0; index--) tasks.push({ + kind: "enter", + node: oneOf[index], + path: `${path}.oneOf[${index}]` + }); + continue; + } + const type = node.type; + if (typeof type !== "string" || !SCHEMA_TYPES.includes(type)) { + violations.push(Array.isArray(type) ? `${path}.type must be a single type string (type arrays are not supported)` : `${path}.type must be one of ${SCHEMA_TYPES.join("/")}`); + continue; + } + const schemaType = type; + for (const [key, types] of Object.entries({ + properties: ["object"], + required: ["object"], + additionalProperties: ["object"], + items: ["array"], + enum: [ + "string", + "number", + "integer", + "boolean", + "null" + ], + const: [ + "string", + "number", + "integer", + "boolean", + "null" + ] + })) if (Object.hasOwn(node, key) && !types.includes(schemaType)) violations.push(`${path}.${key} is not supported on type "${schemaType}"`); + switch (schemaType) { + case "object": { + const properties = Object.hasOwn(node, "properties") ? node.properties : void 0; + tasks.push({ + kind: "object-tail", + node, + path, + properties + }); + if (Object.hasOwn(node, "properties")) if (!isJsonSchemaRecord(properties)) violations.push(`${path}.properties must be an object of schemas`); + else { + const entries = Object.entries(properties); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === void 0) continue; + tasks.push({ + kind: "enter", + node: entry[1], + path: `${path}.properties.${entry[0]}` + }); + } + } + break; + } + case "array": + if (Object.hasOwn(node, "items")) tasks.push({ + kind: "enter", + node: node.items, + path: `${path}.items` + }); + break; + case "string": + case "number": + case "integer": + case "boolean": + case "null": { + const hasEnum = Object.hasOwn(node, "enum"); + const allowed = hasEnum ? node.enum : void 0; + const enumValid = isPlainJsonArray(allowed) && allowed.length > 0 && allowed.every((entry) => scalarMatches(schemaType, entry)); + if (hasEnum && !enumValid) violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`); + const hasConst = Object.hasOwn(node, "const"); + const declaredConst = hasConst ? node.const : void 0; + const constValid = scalarMatches(schemaType, declaredConst); + if (hasConst) { + if (!constValid) violations.push(`${path}.const must be a ${schemaType} value`); + else if (enumValid && !allowed.includes(declaredConst)) violations.push(`${path}.const must be one of ${path}.enum when both are declared`); + } + break; + } + /* v8 ignore next -- schemaType was narrowed from the closed SCHEMA_TYPES table above. */ + default: assertNever(schemaType, "JsonSchemaType"); + } + } +} +/** +* Assert that an arbitrary raw schema uses only the enforced subset. +* Annotation-only schemas are accepted as the standard unconstrained-JSON +* form; callers that require an object root use {@link assertObjectJsonSchema}. +* @param schema - untrusted raw JSON Schema. +* @returns Assertion that the schema belongs to the supported subset. +*/ +function assertSupportedJsonSchema(schema) { + const violations = []; + checkSchemaNode(schema, "schema", violations, /* @__PURE__ */ new Set()); + if (violations.length > 0) throw new JsonSchemaError(violations); +} +/** +* Assert the enforced subset plus the object-root constraint retained by +* subagent and workflow structured outputs. +* @param schema - untrusted caller-supplied schema. +* @returns Assertion that the schema belongs to the supported subset and has an object root. +*/ +function assertObjectJsonSchema(schema) { + const violations = []; + checkSchemaNode(schema, "schema", violations, /* @__PURE__ */ new Set()); + if (violations.length === 0 && (!isJsonSchemaRecord(schema) || !Object.hasOwn(schema, "type") || schema.type !== "object")) violations.push("schema.type must be \"object\" (structured output is object-rooted)"); + if (violations.length > 0) throw new JsonSchemaError(violations); +} +/** Safely test the lossless JSON boundary when a getter may throw. */ +function safelyIsJsonValue(value) { + try { + return isJsonValue(value); + } catch { + return false; + } +} +/** Root-aware diagnostic path for the parameter validator's empty sentinel. */ +function diagnosticPath(path) { + return path === "" ? "arguments" : path; +} +/** Append one object property without a leading dot at an implicit root. */ +function propertyPath(path, key) { + return path === "" ? key : `${path}.${key}`; +} +/** The generic exception-containment diagnostic owned by one valid schema node. */ +function losslessValueViolation(path) { + return [`"${diagnosticPath(path)}" must be a lossless JSON value`]; +} +/** Append diagnostics without spreading a potentially wide child result as call arguments. */ +function appendViolations(target, source) { + for (const violation of source) target.push(violation); +} +/** Initialize one validation frame with empty aggregation state. */ +function valueFrame(node, value, path) { + return { + node, + value, + path, + catches: false, + phase: "start", + children: [], + childIndex: 0, + violations: [], + tailViolations: [], + matches: 0 + }; +} +/** Validate one scalar node after its primitive type check. */ +function checkScalarValue(node, value, path) { + const allowed = Object.hasOwn(node, "enum") ? node.enum : void 0; + if (allowed !== void 0 && !allowed.includes(value)) return [`"${diagnosticPath(path)}" must be one of ${JSON.stringify(allowed)}`]; + if (Object.hasOwn(node, "const") && value !== node.const) return [`"${diagnosticPath(path)}" must be ${JSON.stringify(node.const)}`]; + return []; +} +/** Validate one trusted schema/value pair with explicit frames rather than recursive calls. */ +function checkValue(schema, value, path) { + const frames = [valueFrame(schema, value, path)]; + let rootResult; + const receive = (result) => { + const parent = frames.at(-1); + if (parent === void 0) { + rootResult = result; + return; + } + if (parent.kind === "oneOf") { + if (result.length === 0) parent.matches++; + } else appendViolations(parent.violations, result); + }; + const finish = (result) => { + frames.pop(); + receive(result); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === void 0) break; + try { + if (frame.phase === "children") { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === void 0) throw new Error("missing schema-value child frame"); + frame.childIndex++; + frames.push(valueFrame(child.node, child.value, child.path)); + continue; + } + if (frame.kind === "oneOf") { + finish(frame.matches === 1 ? [] : [`"${diagnosticPath(frame.path)}" must match exactly one oneOf branch (matched ${frame.matches})`]); + continue; + } + appendViolations(frame.violations, frame.tailViolations); + if (frame.violations.length > 0) finish(frame.violations); + else if (frame.kind === "object") finish(safelyIsJsonValue(frame.value) ? [] : [`"${diagnosticPath(frame.path)}" must be a lossless JSON object`]); + else finish(safelyIsJsonValue(frame.value) ? [] : [`"${diagnosticPath(frame.path)}" must be a dense lossless JSON array`]); + continue; + } + const nodeType = Object.hasOwn(frame.node, "type") ? frame.node.type : void 0; + frame.catches = !(nodeType !== void 0 && !SCHEMA_TYPES.includes(nodeType)); + const oneOf = Object.hasOwn(frame.node, "oneOf") ? frame.node.oneOf : void 0; + if (oneOf !== void 0) { + frame.kind = "oneOf"; + frame.children = Array.from(oneOf, (branch) => ({ + node: branch, + value: frame.value, + path: frame.path + })); + frame.childIndex = 0; + frame.matches = 0; + frame.phase = "children"; + continue; + } + if (nodeType === void 0) { + finish(safelyIsJsonValue(frame.value) ? [] : losslessValueViolation(frame.path)); + continue; + } + switch (nodeType) { + case "object": { + if (!isPlainJsonRecord(frame.value)) { + finish([`"${diagnosticPath(frame.path)}" must be an object`]); + break; + } + const properties = Object.hasOwn(frame.node, "properties") ? frame.node.properties ?? {} : {}; + const violations = []; + const required = Object.hasOwn(frame.node, "required") ? frame.node.required ?? [] : []; + for (const key of required) if (!Object.hasOwn(frame.value, key) || frame.value[key] === void 0) violations.push(`missing required property "${propertyPath(frame.path, key)}"`); + const children = []; + for (const [key, child] of Object.entries(properties)) { + if (!Object.hasOwn(frame.value, key) || frame.value[key] === void 0) continue; + children.push({ + node: child, + value: frame.value[key], + path: propertyPath(frame.path, key) + }); + } + const tailViolations = []; + if (Object.hasOwn(frame.node, "additionalProperties") && frame.node.additionalProperties === false) { + for (const key of Object.keys(frame.value)) if (!Object.hasOwn(properties, key)) tailViolations.push(`"${propertyPath(frame.path, key)}" is not a declared property (additionalProperties: false)`); + } + frame.kind = "object"; + frame.children = children; + frame.childIndex = 0; + frame.violations = violations; + frame.tailViolations = tailViolations; + frame.phase = "children"; + break; + } + case "array": { + if (!Array.isArray(frame.value)) { + finish([`"${diagnosticPath(frame.path)}" must be an array`]); + break; + } + const items = Object.hasOwn(frame.node, "items") ? frame.node.items : void 0; + const children = items === void 0 ? [] : frame.value.flatMap((entry, index) => [{ + node: items, + value: entry, + path: `${frame.path}[${index}]` + }]); + frame.kind = "array"; + frame.children = children; + frame.childIndex = 0; + frame.violations = []; + frame.phase = "children"; + break; + } + case "string": + finish(typeof frame.value === "string" ? checkScalarValue(frame.node, frame.value, frame.path) : [`"${diagnosticPath(frame.path)}" must be a string`]); + break; + case "number": + finish(typeof frame.value !== "number" ? [`"${diagnosticPath(frame.path)}" must be a number`] : !isJsonNumber(frame.value) ? [`"${diagnosticPath(frame.path)}" must be a finite JSON number`] : checkScalarValue(frame.node, frame.value, frame.path)); + break; + case "integer": + finish(!isJsonNumber(frame.value) || !Number.isInteger(frame.value) ? [`"${diagnosticPath(frame.path)}" must be an integer`] : checkScalarValue(frame.node, frame.value, frame.path)); + break; + case "boolean": + finish(typeof frame.value === "boolean" ? checkScalarValue(frame.node, frame.value, frame.path) : [`"${diagnosticPath(frame.path)}" must be a boolean`]); + break; + case "null": + finish(frame.value === null ? checkScalarValue(frame.node, frame.value, frame.path) : [`"${diagnosticPath(frame.path)}" must be null`]); + break; + default: finish(assertNever(nodeType, "JsonSchemaType")); + } + } catch (error) { + let failed = frames.pop(); + while (failed !== void 0 && !failed.catches) failed = frames.pop(); + if (failed === void 0) throw error; + receive(losslessValueViolation(failed.path)); + } + } + /* v8 ignore next -- every root frame finishes or throws. */ + return rootResult ?? losslessValueViolation(path); +} +/** +* Validate a candidate value against an asserted raw schema. The function is +* total for arbitrary values and returns path-qualified violations. +* @param schema - a schema accepted by {@link assertSupportedJsonSchema}. +* @param value - the candidate JSON value. +* @param path - root label used in diagnostics. +* @returns All violations in walk order; empty means valid. +*/ +function validateJsonSchemaValue(schema, value, path = "value") { + return checkValue(schema, value, path); +} +//#endregion +//#region lib/types/schema.js +/** Unified JSON-value schema DSL, inference, compilation, and typed tool helper. @module dsh-tools/schema */ +const ANNOTATION_KEYS = [ + "description", + "title", + "default", + "examples" +]; +/** Throw one author-schema violation through the shared schema error type. */ +function authorError(message) { + throw new JsonSchemaError([message]); +} +/** Copy own annotation fields for validation by the raw-schema boundary. */ +function copyAnnotations(source, target) { + if (Object.hasOwn(source, "description")) target.description = source.description; + if (Object.hasOwn(source, "title")) target.title = source.title; + if (Object.hasOwn(source, "default")) target.default = source.default; + if (Object.hasOwn(source, "examples")) target.examples = source.examples; +} +/** Reject author-only keys outside one node's declared vocabulary. */ +function assertAuthorKeys(source, path, allowed) { + for (const key of Object.keys(source)) if (!allowed.includes(key)) authorError(`${path}.${key} is not supported by the value schema DSL`); +} +/** Install a compiled node without giving `__proto__` assignment semantics. */ +function assignCompiledNode(destination, node) { + switch (destination.kind) { + case "root": + destination.holder.value = node; + break; + case "property": + Object.defineProperty(destination.target, destination.key, { + value: node, + enumerable: true, + configurable: true, + writable: true + }); + break; + case "item": + destination.target.items = node; + break; + case "one-of": + destination.target[destination.index] = node; + break; + } +} +/** Install a compiled property map at its root or containing object node. */ +function assignCompiledPropertyMap(destination, compiled) { + if (destination.kind === "root") destination.holder.value = compiled; + else destination.target.properties = compiled.properties; +} +/** Execute an author-schema compilation task graph without recursive descent. */ +function runSchemaCompiler(initial) { + const seen = /* @__PURE__ */ new Set(); + const tasks = [initial]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "leave") { + seen.delete(task.input); + continue; + } + if (task.kind === "property-map-tail") { + if (task.required.length > 0) { + task.compiled.required = task.required; + if (task.destination.kind === "object") task.destination.target.required = task.required; + } + continue; + } + if (task.kind === "property") { + if (!isJsonSchemaRecord(task.property)) authorError(`${task.path} must be a value schema object`); + if (Object.hasOwn(task.property, "required") && task.property.required !== true) authorError(`${task.path}.required must be true when present`); + if (Object.hasOwn(task.property, "required") && task.property.required === true) task.required.push(task.key); + tasks.push({ + kind: "value", + input: task.property, + path: task.path, + allowRequired: true, + destination: { + kind: "property", + target: task.properties, + key: task.key + } + }); + continue; + } + if (task.kind === "property-map") { + if (!isJsonSchemaRecord(task.input)) authorError(`${task.path} must be an object of value schemas`); + if (seen.has(task.input)) authorError(`${task.path} is circular`); + seen.add(task.input); + const compiled = { properties: {} }; + const required = []; + assignCompiledPropertyMap(task.destination, compiled); + tasks.push({ + kind: "leave", + input: task.input + }); + tasks.push({ + kind: "property-map-tail", + compiled, + required, + destination: task.destination + }); + const entries = Object.entries(task.input); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === void 0) continue; + tasks.push({ + kind: "property", + property: entry[1], + path: `${task.path}.${entry[0]}`, + key: entry[0], + properties: compiled.properties, + required + }); + } + continue; + } + const { input, path } = task; + if (!isJsonSchemaRecord(input)) authorError(`${path} must be a value schema object`); + if (seen.has(input)) authorError(`${path} is circular`); + seen.add(input); + const authorKeys = [...ANNOTATION_KEYS, ...task.allowRequired ? ["required"] : []]; + const node = {}; + assignCompiledNode(task.destination, node); + tasks.push({ + kind: "leave", + input + }); + if (Object.hasOwn(input, "oneOf")) { + assertAuthorKeys(input, path, [ + ...authorKeys, + "oneOf", + "type" + ]); + if (Object.hasOwn(input, "type")) authorError(`${path} cannot declare both type and oneOf`); + if (!isPlainJsonArray(input.oneOf)) authorError(`${path}.oneOf must be an array of at least two value schemas`); + const branches = []; + node.oneOf = branches; + copyAnnotations(input, node); + for (let index = input.oneOf.length - 1; index >= 0; index--) tasks.push({ + kind: "value", + input: input.oneOf[index], + path: `${path}.oneOf[${index}]`, + allowRequired: false, + destination: { + kind: "one-of", + target: branches, + index + } + }); + continue; + } + const inputType = Object.hasOwn(input, "type") ? input.type : void 0; + switch (inputType) { + case "json": + assertAuthorKeys(input, path, [...authorKeys, "type"]); + copyAnnotations(input, node); + break; + case "object": + assertAuthorKeys(input, path, [ + ...authorKeys, + "type", + "properties", + "additionalProperties" + ]); + if (!Object.hasOwn(input, "additionalProperties") || typeof input.additionalProperties !== "boolean") authorError(`${path}.additionalProperties must be explicitly true or false`); + node.type = "object"; + copyAnnotations(input, node); + node.additionalProperties = input.additionalProperties; + if (Object.hasOwn(input, "properties")) tasks.push({ + kind: "property-map", + input: input.properties, + path: `${path}.properties`, + destination: { + kind: "object", + target: node + } + }); + break; + case "array": + assertAuthorKeys(input, path, [ + ...authorKeys, + "type", + "items" + ]); + node.type = "array"; + copyAnnotations(input, node); + if (Object.hasOwn(input, "items")) tasks.push({ + kind: "value", + input: input.items, + path: `${path}.items`, + allowRequired: false, + destination: { + kind: "item", + target: node + } + }); + break; + case "string": + case "number": + case "integer": + case "boolean": + case "null": + assertAuthorKeys(input, path, [ + ...authorKeys, + "type", + "enum", + "const" + ]); + node.type = inputType; + copyAnnotations(input, node); + if (Object.hasOwn(input, "enum")) { + if (!isPlainJsonArray(input.enum)) authorError(`${path}.enum must be a non-empty array of scalar values`); + node.enum = Array.from(input.enum, (entry) => entry); + } + if (Object.hasOwn(input, "const")) node.const = input.const; + break; + default: authorError(`${path}.type must be string/number/integer/boolean/null/array/object/json, or use oneOf`); + } + } +} +/** Compile one implicit property map, collecting per-property requiredness. */ +function compilePropertyMap(input, path) { + const holder = {}; + runSchemaCompiler({ + kind: "property-map", + input, + path, + destination: { + kind: "root", + holder + } + }); + /* v8 ignore next -- the root task assigns before scheduling any descendants. */ + return holder.value ?? authorError(`${path} did not compile`); +} +/** Compile one author node without applying any consumer root restriction. */ +function compileValueSchema(input, path) { + const holder = {}; + runSchemaCompiler({ + kind: "value", + input, + path, + allowRequired: false, + destination: { + kind: "root", + holder + } + }); + /* v8 ignore next -- the root task assigns before scheduling any descendants. */ + return holder.value ?? authorError(`${path} did not compile`); +} +/** +* Compile one author-facing value schema to the enforced raw JSON Schema +* subset. The author-only `json` node becomes an annotation-only schema. +* @param spec - schema for any JSON-value root. +* @returns The asserted raw schema projection. +*/ +function valueSchemaSpecToJsonSchema(spec) { + const schema = compileValueSchema(spec, "schema"); + assertSupportedJsonSchema(schema); + return schema; +} +/** +* Compile the implicit open parameter object into raw JSON Schema. +* @param spec - per-property parameter definitions. +* @returns An object-rooted raw schema with no implicit-root openness override. +*/ +function parameterSchemaSpecToJsonSchema(spec) { + const compiled = compilePropertyMap(spec, "parameters"); + const schema = { + type: "object", + properties: compiled.properties, + ...compiled.required === void 0 ? {} : { required: compiled.required } + }; + assertSupportedJsonSchema(schema); + return schema; +} +/** Invalid model-generated arguments for a typed tool. */ +var ToolArgsError = class extends HarnessError { + /** Individual violations in schema-walk order. */ + violations; + constructor(violations) { + super(`invalid arguments: ${violations.join("; ")}`, "INVALID_ARGS"); + this.name = "ToolArgsError"; + this.violations = violations; + } +}; +/** +* Validate model-generated arguments against an implicit parameter schema. +* @param spec - declared parameter schema. +* @param args - candidate arguments, however malformed. +* @returns Path-qualified violations; empty means valid. +*/ +function validateArgs(spec, args) { + return validateJsonSchemaValue(parameterSchemaSpecToJsonSchema(spec), args, ""); +} +/** +* Define a first-party tool with inferred arguments and strict execution +* validation. Replay-only presenters validate softly and fall back to generic +* rendering for obsolete logged arguments. +* @param options - typed definition and optional finalizer and presenters. +* @returns A registry-ready definition. +*/ +function defineTool(options) { + const userExecute = options.execute; + const userFinalizeContent = options.finalizeContent; + const userRender = options.output.render; + const userPresentationMeta = options.output.presentationMeta; + const userPresentCall = options.presentCall; + const userPresentResult = options.presentResult; + const userIsConcurrencySafe = options.isConcurrencySafe; + if (options.timeoutMs !== void 0 && (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) throw new Error(`defineTool(${options.name}): timeoutMs must be a positive finite number`); + const parameters = parameterSchemaSpecToJsonSchema(options.parameters); + const outputSchema = valueSchemaSpecToJsonSchema(options.output.schema); + const validate = (args) => validateJsonSchemaValue(parameters, args, ""); + const tool = { + name: options.name, + description: options.description, + parameters, + output: { + schema: outputSchema, + render(args, value) { + return userRender(args, value); + }, + ...userPresentationMeta !== void 0 ? { presentationMeta(args, value) { + return userPresentationMeta(args, value); + } } : {} + }, + ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}, + async execute(args, exec) { + const violations = validate(args); + if (violations.length > 0) throw new ToolArgsError(violations); + return userExecute(args, exec); + } + }; + if (userFinalizeContent) tool.finalizeContent = (exec, result) => userFinalizeContent(exec, result); + if (userPresentCall) tool.presentCall = (args) => { + if (validate(args).length > 0) return void 0; + return userPresentCall(args); + }; + if (userPresentResult) tool.presentResult = (args, result) => { + if (validate(args).length > 0) return void 0; + return userPresentResult(args, result); + }; + if (userIsConcurrencySafe) tool.isConcurrencySafe = (args) => { + if (validate(args).length > 0) return false; + return userIsConcurrencySafe(args); + }; + return tool; +} +//#endregion +//#region lib/types/code-mode.js +/** +* Code Mode `run_code` transport. Programs call the registry's agent-visible +* tools through nested executions scheduled under the native concurrency +* contract; each sub-dispatch is logged for reconstruction, while only the +* outer curated result enters model history. +* @module @deepseek-ai/dsh-tools/src/code-mode +*/ +/** The model-facing name of the Code Mode tool. */ +const RUN_CODE_NAME = "run_code"; +/** +* The TypeScript flavor: the fallback for a schema read with no runtime +* mounted ({@link resolveFlavor} owns which readers reach that). A real +* assembly always resolves a runtime first, so the model never sees this +* fallback outside its own language. +*/ +const TYPESCRIPT_FLAVOR = { + description: "Execute a TypeScript program against the available tools. Takes two required arguments: `code`, the BODY of an async function (erasable syntax only; top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.", + codeDescription: "The program: the body of an async TypeScript function." +}; +/** Per-language `run_code` schema flavors (see {@link RunCodeFlavor}); one entry per {@link CodeSdkLanguage}. */ +const RUN_CODE_FLAVORS = { + typescript: TYPESCRIPT_FLAVOR, + python: { + description: "Execute a Python program against the available tools. Takes two required arguments: `code`, the BODY of an async function (top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Answer with `print(...)` and/or `return ` — only that comes back, so curate it.", + codeDescription: "The program: the body of an async Python function." + } +}; +/** +* The `description` parameter's model-facing description: language-independent +* (the UI label contract is the same for every runtime), shared between the +* static spec and the language-aware `parameters` getter so the two emissions +* can never drift. +*/ +const RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION = "Clear, concise description of what this program does in active voice, 5-10 words (shown in the UI). Examples: \"Count TODO markers across packages\"; \"Read failing test and its fixture\"; \"Rename config key in every cordis.yml\"."; +/** +* Resolve the {@link RunCodeFlavor} for the loaded runtime's language, read at +* schema-emission time so the model-visible `run_code` schema always matches +* the SDK section's language. `peekRuntime` returns `undefined` only when no +* runtime is mounted, which reaches this function through definition readers +* and `schemas()` — the doc-catalog harvest is the only shipped one, and none +* of them feeds a model, because `wireSchemas` calls `requireCodeRuntime` +* before projecting — so that path degrades to {@link TYPESCRIPT_FLAVOR}. A +* mounted runtime whose language has no flavor entry fails loud, exactly as +* `requireCodeRuntime` rejects it at assembly. Keeping this table in step with +* `SDK_RENDERERS` is the compiler's job ({@link CodeSdkLanguage}); what this +* guard owns is the runtime-supplied language neither table knows, which never +* yields a wrong-language schema for a real runtime. +*/ +function resolveFlavor(peekRuntime) { + const runtime = peekRuntime(); + if (runtime === void 0) return TYPESCRIPT_FLAVOR; + const flavor = RUN_CODE_FLAVORS[runtime.language]; + if (!Object.hasOwn(RUN_CODE_FLAVORS, runtime.language) || flavor === void 0) { + const known = Object.keys(RUN_CODE_FLAVORS).map((name) => JSON.stringify(name)).join(", "); + throw new Error(`dsh-tools: no run_code schema flavor registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`); + } + return flavor; +} +/** +* Thrown by `run_code` when the program run itself failed — a program +* exception, a budget expiry, an abort, or substrate death. Extends +* {@link HarnessError} (`code: 'CODE_RUN_FAILED'`); the registry's execution +* pipeline converts it into a structured `isError` result whose text carries +* the failure kind plus the captured logs, so the model can self-correct. +*/ +var CodeRunFailedError = class extends HarnessError { + constructor(message) { + super(message, "CODE_RUN_FAILED"); + this.name = "CodeRunFailedError"; + } +}; +/** +* Snapshot one binding call's argument as lossless JSON, then snapshot that +* detached value again so dispatch and logging stay independent without +* reintroducing structured-clone's platform-specific nesting limit. +*/ +function jsonNormalizeArgs(value) { + let snapshot; + try { + snapshot = snapshotJsonValue(value); + } catch (error) { + throw new Error(`tool arguments must be lossless JSON: ${error instanceof Error ? error.message : String(error)}`); + } + if (snapshot === void 0) throw new Error("tool arguments must be lossless JSON (call the tool with an arguments object, e.g. `{}`)"); + const logged = snapshotJsonValue(snapshot); + /* v8 ignore next -- snapshot is already a detached lossless JSON value. */ + if (logged === void 0) throw new Error("tool arguments could not be detached for durable logging"); + return { + dispatched: snapshot, + logged + }; +} +/** Two-space JSON presentation, matching the existing shallow `run_code` text contract. */ +const JSON_INDENT = " "; +/** +* ECMAScript caps `JSON.stringify`'s `space` string at ten characters. The +* renderer also caps TOTAL indentation there, compacting deeper subtrees, so +* formatted output remains linear in the canonical JSON size. +*/ +const MAX_JSON_INDENT_CHARS = 10; +/** Render one non-string JSON root without recursive traversal or unbounded indentation growth. */ +function renderJsonValue(value) { + const chunks = []; + const tasks = [{ + kind: "value", + value, + depth: 0, + compact: false + }]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "text") { + chunks.push(task.text); + continue; + } + const current = task.value; + if (current === null || typeof current === "boolean" || typeof current === "number") { + chunks.push(String(current)); + continue; + } + if (typeof current === "string") { + chunks.push(JSON.stringify(current)); + continue; + } + const compact = task.compact || (task.depth + 1) * 2 > MAX_JSON_INDENT_CHARS; + const childDepth = task.depth + 1; + if (Array.isArray(current)) { + chunks.push("["); + if (current.length === 0) { + chunks.push("]"); + continue; + } + tasks.push({ + kind: "text", + text: compact ? "]" : `\n${JSON_INDENT.repeat(task.depth)}]` + }); + for (let index = current.length - 1; index >= 0; index--) { + const item = current[index]; + /* v8 ignore next -- canonical JsonValue arrays are dense. */ + if (item === void 0) throw new Error("cannot render a sparse JSON array"); + tasks.push({ + kind: "value", + value: item, + depth: childDepth, + compact + }); + tasks.push({ + kind: "text", + text: compact ? index === 0 ? "" : "," : `${index === 0 ? "\n" : ",\n"}${JSON_INDENT.repeat(childDepth)}` + }); + } + continue; + } + const keys = Object.keys(current); + chunks.push("{"); + if (keys.length === 0) { + chunks.push("}"); + continue; + } + tasks.push({ + kind: "text", + text: compact ? "}" : `\n${JSON_INDENT.repeat(task.depth)}}` + }); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === void 0) throw new Error("cannot render a missing JSON object key"); + const item = current[key]; + /* v8 ignore next -- canonical JsonValue records contain no undefined properties. */ + if (item === void 0) throw new Error("cannot render an undefined JSON object property"); + tasks.push({ + kind: "value", + value: item, + depth: childDepth, + compact + }); + tasks.push({ + kind: "text", + text: compact ? `${index === 0 ? "" : ","}${JSON.stringify(key)}:` : `${index === 0 ? "\n" : ",\n"}${JSON_INDENT.repeat(childDepth)}${JSON.stringify(key)}: ` + }); + } + } + return chunks.join(""); +} +/** Render one present program completion value for the model-facing result text. */ +function renderValue(value) { + return typeof value === "string" ? value : renderJsonValue(value); +} +/** +* Build the `run_code` {@link ToolDefinition}: required `code` and +* `description` parameters, executed through the dispatch bridge described +* above. The +* registry reserves it as presentation infrastructure under non-native modes, +* outside the filterable global/scoped capability layers. +* @param registry - the owning registry (sub-calls go through its `execute`, +* bindings cover its registered tools). +* @param options - the registry-private capabilities described above. +* @returns the registry-ready definition. +*/ +function createRunCodeTool(registry, options) { + const { requireRuntime, peekRuntime, maxParallel, shapeDispatchLog } = options; + const definition = defineTool({ + name: RUN_CODE_NAME, + description: TYPESCRIPT_FLAVOR.description, + parameters: { + code: { + type: "string", + required: true, + description: TYPESCRIPT_FLAVOR.codeDescription + }, + description: { + type: "string", + required: true, + description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION + } + }, + output: { + schema: { + type: "object", + additionalProperties: false, + properties: { + logs: { + type: "array", + required: true, + items: { type: "string" } + }, + result: { type: "json" } + } + }, + render: (_args, value) => { + const rendered = value.result === void 0 ? "" : renderValue(value.result); + const parts = [value.logs.join("\n"), rendered].filter((part) => part.length > 0); + return [{ + type: "text", + text: parts.length > 0 ? parts.join("\n") : "(run_code completed with no output)" + }]; + } + }, + async execute(args, exec) { + if (args.description.trim().length === 0) throw new Error("invalid description: expected a non-empty string"); + const runtime = requireRuntime(); + const runController = new AbortController(); + const onOuterAbort = () => { + runController.abort(exec.signal.reason); + }; + exec.signal.addEventListener("abort", onOuterAbort, { once: true }); + let dispatches = 0; + const pendingQueue = []; + const inFlight = /* @__PURE__ */ new Set(); + /** Tracked settle-event side work (log-content listener + append), drained at run settlement. */ + const logWork = /* @__PURE__ */ new Set(); + const commitQueue = []; + let exclusiveActive = false; + let driving = false; + let driverRun = Promise.resolve(); + let wake; + const wakeup = () => { + const release = wake; + wake = void 0; + release?.(); + }; + /** + * The single ordered lane. Each pass commits the head-of-line settled + * dispatch (ordered post-execute), then starts the next queued entry if + * its slot is free (ordered pre-execute), and otherwise sleeps until a + * body settles or a new submission arrives. One run reaching the + * empty-queues/empty-pool state is quiescence. + */ + const drive = () => { + if (driving) return driverRun; + driving = true; + driverRun = (async () => { + try { + for (;;) { + const signal = new Promise((resolve) => { + wake = resolve; + }); + const commitHead = commitQueue[0]; + if (commitHead !== void 0 && commitHead.settled) { + commitQueue.shift(); + await commitHead.commit(); + if (commitHead.mode === "exclusive") exclusiveActive = false; + continue; + } + const head = pendingQueue[0]; + if (head !== void 0) { + if (runController.signal.aborted) { + pendingQueue.shift(); + head.abandon(); + continue; + } + const mode = head.classify(); + if (!exclusiveActive && (mode === "exclusive" ? inFlight.size === 0 : inFlight.size < maxParallel)) { + if (mode === "exclusive") exclusiveActive = true; + head.mode = mode; + pendingQueue.shift(); + commitQueue.push(head); + await head.start(); + const flight = head.flight.finally(() => { + inFlight.delete(flight); + wakeup(); + }); + inFlight.add(flight); + continue; + } + } + if (pendingQueue.length === 0 && commitQueue.length === 0 && inFlight.size === 0) return; + await signal; + } + } finally { + driving = false; + wake = void 0; + } + })(); + return driverRun; + }; + /** Every dispatch settled AND committed; nothing can start (the run is aborted at call time). */ + const drainDispatches = async () => { + await drive(); + while (logWork.size > 0) await Promise.allSettled([...logWork]); + }; + const runOver = () => runController.signal.aborted; + const binding = (name) => async (rawArgs) => { + if (runOver()) throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} not dispatched`); + const normalized = jsonNormalizeArgs(rawArgs); + const n = ++dispatches; + const subCallId = CallId(`${String(exec.callId)}:code:${n}`); + const input = { + callId: subCallId, + rootCallId: exec.rootCallId, + name, + arguments: normalized.dispatched, + ...exec.agent ? { agent: exec.agent } : {}, + parent: exec.token, + signal: runController.signal + }; + const scheduler = registry[TOOL_RUNTIME_SCHEDULER]; + const outcome = await new Promise((resolve, reject) => { + let parked; + const settle = (result) => { + resolve(result.isError ? { + isError: true, + message: result.error.message + } : { + isError: false, + value: result.value + }); + const agent = exec.agent; + if (agent === void 0) return; + const task = (async () => { + const logged = await shapeDispatchLog({ + exec, + agent, + subCallId, + name, + isError: result.isError, + content: result.content + }); + agent.session.append("tool/code-dispatch", { + rootCallId: exec.rootCallId, + parentCallId: exec.callId, + subCallId, + name, + arguments: normalized.logged, + isError: result.isError, + content: logged + }); + })().finally(() => { + logWork.delete(task); + }); + logWork.add(task); + }; + pendingQueue.push({ + flight: Promise.resolve(), + settled: false, + classify: () => registry.executionMode(input).kind, + abandon: () => { + reject(/* @__PURE__ */ new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} tool call abandoned`)); + }, + async start() { + exec.agent?.session.append("tool/code-dispatch-start", { + rootCallId: exec.rootCallId, + parentCallId: exec.callId, + subCallId, + name, + arguments: normalized.logged + }); + const prepared = await scheduler.prepare(input); + if (prepared.kind === "dispatch") { + this.flight = scheduler.dispatch(prepared.exec).then((dispatchOutcome) => { + parked = { + kind: dispatchOutcome.kind, + exec: prepared.exec, + result: dispatchOutcome.result + }; + this.settled = true; + }); + return; + } + parked = { + kind: prepared.kind, + exec: prepared.exec, + result: prepared.result + }; + this.settled = true; + }, + async commit() { + /* v8 ignore next -- commit() runs only after `settled` flipped, which set parked. */ + if (parked === void 0) return; + const result = parked.kind === "post-result" ? await scheduler.finalize(parked.exec, parked.result) : scheduler.finish(parked.exec, parked.result); + for (const context of result.additionalContexts ?? []) exec.deferContext(context); + if (result.concludesTurn) exec.concludeTurn(); + settle(result); + while (logWork.size > maxParallel) await Promise.race(logWork); + } + }); + wakeup(); + drive(); + }); + if (runOver()) throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} result discarded`); + if (outcome.isError) throw new Error(outcome.message); + return outcome.value; + }; + const functions = Object.create(null); + for (const schema of registry.schemas(exec.agent)) { + if (schema.name === "run_code") continue; + Object.defineProperty(functions, schema.name, { + enumerable: true, + value: binding(schema.name) + }); + } + try { + let result; + try { + result = await runtime.run({ + program: args.code, + bindings: [{ + global: "tools", + functions, + errorClass: { + name: "ToolCallError", + memberNameProperty: "toolName" + } + }], + signal: runController.signal + }); + } finally { + runController.abort("run_code settled"); + await drainDispatches(); + } + if (result.error) { + const logsText = result.logs.length > 0 ? `\nCaptured output:\n${result.logs.join("\n")}` : ""; + throw new CodeRunFailedError(`code run failed (${result.error.kind}): ${result.error.message}${logsText}`); + } + return { + logs: result.logs, + ...result.value !== void 0 ? { result: result.value } : {} + }; + } finally { + exec.signal.removeEventListener("abort", onOuterAbort); + } + }, + presentCall: (args) => ({ + card: "generic", + title: args.description, + kind: "execute", + rawInput: args.code + }) + }); + Object.defineProperty(definition, "description", { + enumerable: true, + get: () => resolveFlavor(peekRuntime).description + }); + Object.defineProperty(definition, "parameters", { + enumerable: true, + get: () => parameterSchemaSpecToJsonSchema({ + code: { + type: "string", + required: true, + description: resolveFlavor(peekRuntime).codeDescription + }, + description: { + type: "string", + required: true, + description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION + } + }) + }); + return definition; +} +//#endregion +//#region lib/types/ts-types.js +/** +* Code Mode codegen: the pure projection from registered tool schemas to the TypeScript SDK +* text the model programs against (the `tools:sdk` prompt section). Sibling of +* `json-schema.ts` — `schemas()` (native function calling) and this module (the generated +* `declare const tools` API) are two projections of the same store. +* @module @deepseek-ai/dsh-tools/src/ts-types +*/ +/** Property names that are valid bare TS identifiers; anything else is quoted. */ +const IDENTIFIER$1 = /^[A-Za-z_$][A-Za-z0-9_$]*$/; +/** Render an object key: bare when it is a valid identifier, quoted otherwise (every name stays reachable, no aliasing). */ +function renderKey(name) { + return IDENTIFIER$1.test(name) ? name : JSON.stringify(name); +} +/** One `indent`-deep line prefix (two spaces per level). */ +function pad$1(indent) { + return " ".repeat(indent); +} +/** A one-line JSDoc block for a schema `description`, or no lines when there is none. */ +function docLines$1(description, indent) { + if (typeof description !== "string" || description.length === 0) return []; + const collapsed = description.replace(/\s+/g, " ").trim(); + return [`${pad$1(indent)}/** ${collapsed.replaceAll("*/", String.raw`*\/`)} */`]; +} +/** Render one scalar already validated by the unified schema boundary. */ +function renderScalar(value) { + return JSON.stringify(value); +} +/** Render a validated scalar `const`/`enum`, falling back to the broad type. */ +function renderConstrainedScalar$1(node, type) { + const broad = type === "integer" ? "number" : type; + if (Object.hasOwn(node, "const")) return renderScalar(node.const); + if (Object.hasOwn(node, "enum")) return node.enum.map(renderScalar).join(" | "); + return broad; +} +/** Build one document from captured parts while retaining the legacy array-parenthesization test. */ +function typeDocumentFrom(parts) { + return { + parts, + containsUnionOrIntersection: parts.some((part) => typeof part === "string" ? part.includes("|") || part.includes("&") : part.containsUnionOrIntersection) + }; +} +/** Build a small document without an intermediate array at each call site. */ +function typeDocument(...parts) { + return typeDocumentFrom(parts); +} +/** Flatten a nested document with an explicit work stack. */ +function flattenTypeDocument(document) { + const chunks = []; + const tasks = [document]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (typeof task === "string") { + chunks.push(task); + continue; + } + for (let index = task.parts.length - 1; index >= 0; index--) { + const part = task.parts[index]; + /* v8 ignore next -- the loop is bounded by the captured part count. */ + if (part !== void 0) tasks.push(part); + } + } + return chunks.join(""); +} +/** Initialize one schema-render frame with empty aggregation state. */ +function schemaRenderFrame(node, indent) { + return { + node, + indent, + phase: "start", + children: [], + childIndex: 0, + childDocuments: [], + entries: [] + }; +} +/** Render an already asserted schema to a composable document. */ +function renderSupportedSchema(schema, indent) { + const frames = [schemaRenderFrame(schema, indent)]; + let rootDocument; + const finish = (document) => { + frames.pop(); + const parent = frames.at(-1); + if (parent === void 0) rootDocument = document; + else parent.childDocuments.push(document); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === void 0) break; + if (frame.phase === "children") { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === void 0) throw new Error("missing schema render child"); + frame.childIndex++; + frames.push(schemaRenderFrame(child.node, child.indent)); + continue; + } + if (frame.kind === "oneOf") { + const parts = []; + for (let index = 0; index < frame.childDocuments.length; index++) { + if (index > 0) parts.push(" | "); + const child = frame.childDocuments[index]; + /* v8 ignore next -- child documents correspond one-to-one with children. */ + if (child !== void 0) parts.push(child); + } + finish(typeDocumentFrom(parts)); + continue; + } + if (frame.kind === "array") { + const child = frame.childDocuments[0]; + /* v8 ignore next -- array frames always schedule exactly one child. */ + if (child === void 0) throw new Error("missing array item type"); + finish(child.containsUnionOrIntersection ? typeDocument("(", child, ")[]") : typeDocument(child, "[]")); + continue; + } + const required = new Set(frame.node.required); + const parts = ["{"]; + for (let index = 0; index < frame.entries.length; index++) { + const entry = frame.entries[index]; + const child = frame.childDocuments[index]; + /* v8 ignore next -- object entries and child documents have the same length. */ + if (entry === void 0 || child === void 0) throw new Error("missing object property type"); + const [name, prop] = entry; + for (const line of docLines$1(prop.description, frame.indent + 1)) parts.push("\n", line); + parts.push("\n", `${pad$1(frame.indent + 1)}${renderKey(name)}${required.has(name) ? "" : "?"}: `, child, ";"); + } + parts.push("\n", `${pad$1(frame.indent)}}`); + const declared = typeDocumentFrom(parts); + finish(frame.node.additionalProperties === false ? declared : typeDocument(declared, " & Record")); + continue; + } + const node = frame.node; + if (node.oneOf !== void 0) { + frame.kind = "oneOf"; + frame.children = Array.from(node.oneOf, (child) => ({ + node: child, + indent: frame.indent + })); + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = "children"; + continue; + } + if (node.type === void 0) { + finish(typeDocument("JsonValue")); + continue; + } + switch (node.type) { + case "string": + case "number": + case "integer": + case "boolean": + case "null": + finish(typeDocument(renderConstrainedScalar$1(node, node.type))); + break; + case "array": + if (node.items === void 0) finish(typeDocument("JsonValue[]")); + else { + frame.kind = "array"; + frame.children = [{ + node: node.items, + indent: frame.indent + }]; + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = "children"; + } + break; + case "object": { + const open = node.additionalProperties !== false; + const entries = Object.entries(node.properties ?? {}); + if (entries.length === 0) finish(typeDocument(open ? "Record" : "Record")); + else { + frame.kind = "object"; + frame.entries = entries; + frame.children = entries.map(([, child]) => ({ + node: child, + indent: frame.indent + 1 + })); + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = "children"; + } + break; + } + /* v8 ignore next -- assertSupportedJsonSchema narrowed this closed type union. */ + default: finish(typeDocument("unknown")); + } + } + /* v8 ignore next -- every root frame produces one document. */ + return rootDocument ?? typeDocument("unknown"); +} +/** +* Map one enforced JSON-Schema node to a TypeScript type literal. Supports +* every unified schema construct and returns `unknown` for malformed or +* unsupported inputs without throwing. +* @param schema - the JSON-Schema node (any shape; hostile inputs degrade). +* @param indent - the indentation level for nested object members. +* @returns the TS type text (multi-line for objects with properties). +*/ +function jsonSchemaToTs(schema, indent = 0) { + try { + assertSupportedJsonSchema(schema); + return flattenTypeDocument(renderSupportedSchema(schema, indent)); + } catch { + return "unknown"; + } +} +/** The fixed model-facing usage contract rendered above the declarations (see the Code Mode Agent Note's "What the model sees"). */ +const SDK_INSTRUCTIONS$1 = `## Writing code for run_code + +\`run_code\` takes two required arguments: \`code\` — the body of an async TypeScript function (erasable syntax only — no \`enum\` or namespaces; type annotations are advisory, the code runs type-stripped) — and \`description\`, a short summary of what the program does. Inside the program: + +- Call tools as \`await tools.name(args)\` — quoted access for exotic names: \`tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose \`message\` is human-readable — \`try/catch\` it to handle and continue. +- Independent read-only calls MAY overlap under \`Promise.all\` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with \`await\`. +- Emit results with \`return\` and/or \`console.log(...)\`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. + +The available tools:`; +/** +* Render the full `tools:sdk` prompt section: the fixed usage instructions +* plus one `declare const tools` interface covering every given tool. +* Deterministic — tools are emitted in lexicographic name order, so an +* unchanged tool set produces byte-identical text across assemblies. The sort +* is not a total order on byte-equal names, so two schemas sharing a name +* would render in argument order; the caller's visible-capability map is keyed +* by name, so the input never carries a duplicate. +* @param schemas - the tool schemas to declare (the caller excludes +* `run_code` itself). +* @returns the complete section text. +*/ +function renderToolsSdk(schemas) { + const sorted = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0); + const argsMembers = []; + const outputMembers = []; + for (const schema of sorted) { + argsMembers.push(...docLines$1(schema.description, 1)); + argsMembers.push(`${pad$1(1)}${renderKey(schema.name)}: ${jsonSchemaToTs(schema.parameters, 1)};`); + outputMembers.push(`${pad$1(1)}${renderKey(schema.name)}: ${jsonSchemaToTs(schema.output, 1)};`); + } + return `${SDK_INSTRUCTIONS$1}\n\n\`\`\`ts\ntype JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue }\n\n${[ + `interface ToolArgsMap {${argsMembers.length > 0 ? `\n${argsMembers.join("\n")}\n` : ""}}`, + `interface ToolOutputMap {${outputMembers.length > 0 ? `\n${outputMembers.join("\n")}\n` : ""}}`, + "type ToolName = keyof ToolOutputMap", + [ + "declare class ToolCallError extends Error {", + " readonly name: \"ToolCallError\";", + " readonly toolName: ToolName;", + "}" + ].join("\n"), + [ + "declare const tools: {", + " [K in ToolName]: (args: ToolArgsMap[K]) => Promise;", + "}" + ].join("\n") + ].join("\n\n")}\n\`\`\``; +} +//#endregion +//#region lib/types/py-types.js +/** +* Code Mode codegen — Python flavor. The pure projection from registered tool schemas to the +* Python SDK text the model programs against under `runtime.language === 'python'`. Sibling of +* {@link ./ts-types.ts | ts-types.ts}; the two files are two projections of the same registry +* store, keyed by the loaded {@link @deepseek-ai/dsh-code-runtime#CodeRuntime.language | code +* runtime's language}. +* +* Under `mode: 'code'` the native tool schemas are omitted from the request, so this generated +* SDK is the model's ONLY source for each tool's argument names, required fields, types, +* descriptions, and canonical output shapes; under `mode: 'both'` the native schemas ship +* alongside it and it is one of two. Object-shaped arguments and outputs therefore render as one +* named `TypedDict` per tool (and per nested object), not an opaque `dict[str, Any]`, so the +* shape survives into the program under the mode that has nothing else to carry it. +* @module @deepseek-ai/dsh-tools/src/py-types +*/ +/** +* The reference grammar's `xid_start xid_continue*` — the set +* `str.isidentifier()` accepts on a CPython whose Unicode tables match the +* engine's. See {@link isBareIdentifier} for what a version skew does. +*/ +const IDENTIFIER = /^[\p{XID_Start}_]\p{XID_Continue}*$/u; +/** +* Whether a name can be emitted as a bare Python identifier rather than +* routed to the subscript/`dict[str, Any]` path. +* +* Python identifiers are not ASCII: `路径` is as legal a field name as `path`, +* and rejecting it would degrade the whole enclosing object, dropping every +* field's name, requiredness, and type — information whose only source under +* `mode: 'code'` is this generated text. +* +* NFKC stability is a second and separate condition, because CPython +* normalizes identifiers at compile time while JSON keys are compared as +* written: `field` would be declared and reachable as `field`, so the SDK would +* advertise a key under a spelling the harness never accepts, and two keys +* that normalize together would collapse into one declaration. Those names +* take the subscript path, which carries their exact bytes. +* +* `IDENTIFIER` matches `str.isidentifier()` (measured on Node 22.23.1 vs +* CPython 3.9.6 tables): the equivalence holds inside the two versions' shared +* tables, and the skew characters below are exactly where that pair diverges. +* The predicate as a whole is deliberately stricter than `isidentifier()`, +* which does not test NFKC stability: `'field'.isidentifier()` is True and +* this returns false. +* +* Both conditions are evaluated against the ENGINE's Unicode tables, and the +* two sides are versioned independently — `\p{XID_Start}`/`\p{XID_Continue}` +* follow the running engine (Node 22.23.1 reports Unicode 17.0) while CPython +* follows its own (3.9.6 reports 13.0.0). The skew is not symmetric. A CPython +* older than the engine is the dangerous direction: a character added to either +* property since its tables (U+10570 Vithkuqi and U+1E290 Toto, 14.0; U+1E4D0 +* Nag Mundari, 15.0; U+1C89 Cyrillic TJE, 16.0 — ages per `DerivedAge.txt`; all +* four are NFKC-stable and accepted here, and all four are `Cn` on that 3.9.6, +* which rejects them) is emitted bare and its tokenizer refuses the character, +* taking the whole SDK block down — the same parseability invariant +* {@link UNPRINTABLE}, {@link LONE_SURROGATE} and {@link MAX_LIST_NESTING} +* exist for. Both properties carry it: a character added only to `XID_Continue` +* passes the trailing `\p{XID_Continue}*` in a tail position and fails the same +* way — U+200C ZWNJ and U+200D ZWJ are that case, gaining `XID_Continue` in UCD +* 15.1 and absent from it in 13.0.0, 14.0.0 and 15.0.0, so `a\u{200C}b` is +* emitted bare here while `isidentifier()` is False on 3.9.6 and on 3.12.13 +* (15.0.0). A CPython newer than the engine only routes a legal name to the +* subscript/`dict[str, Any]` path: less readable, still correct. The NFKC +* condition reduces to the same skew, since normalization stability guarantees +* an assigned character's normalization never changes afterwards. +* +* This predicate is not the only reader of engine tables. {@link camelCase} +* reads them at three further points — its split set, its head test, and its +* `toUpperCase()` case mapping — and this predicate's verdict gates none of +* them: a class name derived there reaches emitted text whenever any object +* shape in the tool's schema declares a `TypedDict`, including for a tool this +* predicate rejected. A tool named `zz-\u{1E4D0}x` with such parameters never +* reaches the skew here (the `-` rejects it outright) yet emits `class +* Zz\u{1E4D0}xArgs`, which that same 3.9.6 refuses — Nag Mundari arrived two +* releases after its tables. The case mapping is a separate table rather than +* an XID membership test, and it fails on names both conditions above accept: +* `\u{019B}` is XID_Start and NFKC-stable, so this predicate accepts it and +* `async def \u{019B}` compiles on 3.9.6, but Node uppercases it to +* `\u{A7DC}` — unassigned in that CPython, whose own `.upper()` is the identity +* here — and the declared `class \u{A7DC}Args` fails with `invalid +* non-printable character U+A7DC`. Closing the exposure therefore covers all +* four read points, not this predicate alone; it needs the target interpreter's +* version, which the backend reporting `language: 'python'` owns; the +* language-dispatch Agent Note records the deferral. +* +* The `ts-types` sibling keeps its own ASCII rule rather than sharing this +* one: ECMAScript identifiers are a different set (`$`) and are never +* normalized, so one predicate cannot be correct for both. ZWJ/ZWNJ are not +* part of that difference — both sets carry them on the engine's tables; what +* separates the two there is the CPython table version above. +* @param name - the raw schema field or tool name. +* @returns whether the name can be emitted bare. +*/ +function isBareIdentifier(name) { + return IDENTIFIER.test(name) && name.normalize("NFKC") === name; +} +/** +* Python hard keywords: reserved everywhere, so a tool or field named +* ``class`` or ``lambda`` is legal on the wire but not as an attribute +* (``tools.class`` would be a SyntaxError in the model program) and not as a +* class-syntax `TypedDict` field. Such a tool renders under subscript access +* and such an object degrades to ``dict[str, Any]`` — the model still reaches +* every tool and field without collisions. +* Soft keywords (``match``, ``case``, ``type``, ``_`` — the language +* reference's whole set) are deliberately ABSENT: each is special in exactly +* one syntactic position — a statement head (``match``, ``type``), a ``match`` +* statement's clause head (``case``), or a pattern (``_``) — so ``match: str`` +* as a field and ``async def match(...)`` as a method are both legal, and +* including them would needlessly degrade common search/regex tool fields to +* ``dict[str, Any]``. Underscore-leading names are handled separately, not +* here: a non-dunder ``__token`` name-mangles, a dunder present on +* ``object``/``type`` resolves before the proxy hook, and implicit +* special-method lookup bypasses the hook. +*/ +const RESERVED = new Set([ + "False", + "None", + "True", + "and", + "as", + "assert", + "async", + "await", + "break", + "class", + "continue", + "def", + "del", + "elif", + "else", + "except", + "finally", + "for", + "from", + "global", + "if", + "import", + "in", + "is", + "lambda", + "nonlocal", + "not", + "or", + "pass", + "raise", + "return", + "try", + "while", + "with", + "yield", + "__debug__" +]); +/** `typing` symbols this module may emit, in the deterministic import order. */ +const TYPING_ORDER = [ + "Any", + "Literal", + "NotRequired", + "Protocol", + "TypedDict" +]; +/** `indent`-deep line prefix (four spaces per level to match PEP 8 output). */ +function pad(indent) { + return " ".repeat(indent); +} +/** +* The `Cc` code points that survive the whitespace collapse in {@link describe} +* and have no printable form: the C0 controls, DEL, and the C1 controls. Only +* U+0009 to U+000D are absent, because ECMAScript `\s` already collapsed them — +* `\s` is TAB/VT/FF/SP/NBSP/ZWNBSP/Zs plus LF/CR/LS/PS, so no C1 code point is +* in it and the whole U+0080 to U+009F block reaches this rule intact. Those +* are not hypothetical input: they are what Windows-1252 bytes 0x80 to 0x9F +* (smart quotes, em dash) become when decoded as Latin-1. +* CPython rejects source containing a NUL outright +* (`SyntaxError: source code string cannot contain null bytes`), whether it +* sits in a docstring or in a comment, so one such byte anywhere in a schema +* description would make the whole generated SDK unparseable — under +* `mode: 'code'`, the model's only declaration of the tools. The rest are +* legal but invisible; escaping them with the same rule keeps the emitted text +* readable and the treatment uniform. +* +* The boundary is the category, not per-code-point addressability: `\xNN` +* addresses U+0000 to U+00FF, so one escape form covers `Cc` exactly. The +* invisible `Cf` formatting characters pass through by design — of them only +* U+00AD soft hyphen would fit `\xNN` at all, and escaping that one while +* U+200B ZWSP, U+200E/U+200F bidi marks, and U+2060 word joiner passed through +* would leave a rule that is neither category- nor addressability-shaped. The +* whole family is legal in both consumers, since only LF and CR terminate a +* Python string literal or a `#` comment. That set is the tokenizer's, not +* `str.splitlines()`': NEL (U+0085), LS (U+2028), and PS (U+2029) split a +* string at run time but do not end a physical line in source — measured on +* CPython 3.9.6 and 3.12.13, each accepted in both positions with the value +* round-tripping — so they are safe raw wherever they reach emitted text +* unescaped, which for all three is `JSON.stringify`, at two call sites: +* {@link pyScalar}'s literal path, and the subscript tool-name comment's own +* call, which a name carrying any of them always reaches, none being +* `XID_Continue`. The `description` path escapes NEL under the class above and +* folds LS and PS in {@link describe}'s `\s+` collapse, both being `\s`. +*/ +const UNPRINTABLE = /[\u0000-\u0008\u000e-\u001f\u007f-\u009f]/g; +/** +* Unpaired surrogate code points, escaped by {@link describe} as `\uNNNN` — +* its own form, since `\xNN` stops at U+00FF. The `u` flag is what makes this +* the LONE ones: in Unicode mode a well-formed pair is a single astral code +* point outside D800 to DFFF, so an emoji in a description survives untouched. +* +* This is the NUL case from {@link UNPRINTABLE}, not the invisible-character +* case. Python source must be UTF-8-encodable and a lone surrogate is not, so +* `compile()` raises `UnicodeEncodeError: surrogates not allowed` for one +* anywhere in the text — measured on 3.9 for a string literal and for a `#` +* comment alike. A raw or MCP tool description reaches this: `JSON.parse` on a +* wire `"\ud800"` escape yields exactly such a code point. +*/ +const LONE_SURROGATE = /[\ud800-\udfff]/gu; +/** +* The collapsed one-line `description` of a schema node (byte-stable across +* formatting churn), or `undefined` when the node carries none. Every caller +* passes an object — a validated property node, the `ToolSdkSchema` itself, or +* the `{ description }` wrapper {@link docLines} synthesizes — so only the +* description field needs guarding. A description that collapses +* to nothing (empty, or whitespace only) is `undefined` too: it documents the +* node no better than an absent one, and emitting it would leave an empty +* `"""` docstring or a bare `# ` line in the SDK. Only ECMAScript whitespace +* folds, so a description of whitespace plus one surviving control character is +* NOT absent: it collapses to that character's visible escape. +* +* Control characters left over after the whitespace collapse are rendered as +* their `\xNN` escapes (see {@link UNPRINTABLE}) and unpaired surrogates as +* their `\uNNNN` escapes (see {@link LONE_SURROGATE}); the escape's own backslash is +* emitted literally by both consumers, since {@link docLines} doubles it into a +* Python source escape and a `#` comment carries it verbatim. +*/ +function describe(schema) { + const description = schema.description; + if (typeof description !== "string") return void 0; + const collapsed = description.replace(/\s+/g, " ").replace(UNPRINTABLE, (char) => `\\x${char.charCodeAt(0).toString(16).padStart(2, "0")}`).replace(LONE_SURROGATE, (char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`).trim(); + return collapsed.length === 0 ? void 0 : collapsed; +} +/** +* One-line docstring for a tool `description`, or no lines when there is none. +* Backslashes are doubled first, every quote is escaped, and a trailing +* backslash cannot survive: a description ending in `"` or an odd backslash +* would otherwise merge with (or escape) the closing triple quote and make +* the generated block — Code Mode's only SDK — syntactically invalid Python. +*/ +function docLines(description, indent) { + const collapsed = describe({ description }); + if (collapsed === void 0) return []; + const escaped = collapsed.replaceAll("\\", "\\\\").replaceAll("\"", "\\\""); + return [`${pad(indent)}"""${escaped}"""`]; +} +/** +* CamelCase a name into a Python type identifier: non-identifier characters +* split words, `_` splits too (it is `XID_Continue`, so the split set names it +* explicitly), and a head that cannot start an identifier takes a `Tool` +* prefix. Unicode survives, so a `路径` field yields `路径`-based class names +* instead of collapsing to the bare prefix. A character that is not +* `XID_Continue` splits even when it is a letter, so a name whose NFKC folding +* would leave the identifier set is not carried through — the split set is the +* grammar's, not an ASCII approximation of it. +* +* The result is NFKC-normalized: these names are generated, never matched +* against a JSON key, so normalizing is free here and keeps what CPython +* compiles identical to what is emitted — unlike {@link isBareIdentifier}, +* which must reject unstable names outright. Normalizing AFTER the prefix +* decision is what makes that hold at the seam the prefix creates: `Tool` + +* a combining-mark head composes there (`U+0301` gives `Tooĺ`, U+013A), so +* normalizing only the un-prefixed part would emit a name CPython compiles to +* a different symbol. The second call is idempotent on the un-prefixed arm. +* +* The split set, the head test, and `toUpperCase()` all read the engine's +* Unicode tables, so this function carries the same version skew +* {@link isBareIdentifier} documents, by paths independent of it: a class name +* derived here reaches emitted text whenever any object shape in the tool's +* schema declares a `TypedDict`, and the predicate's verdict on the tool name +* does not gate that. The case mapping is the one that can fail on a name the +* predicate accepted; the worked example is there. +* @param raw - the schema field or tool name to derive from. +* @returns a class-name segment safe to emit. +*/ +function camelCase(raw) { + const joined = raw.split(/[^\p{XID_Continue}]+|_+/u).filter((part) => part.length > 0).map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join("").normalize("NFKC"); + return (/^\p{XID_Start}/u.test(joined) ? joined : `Tool${joined}`).normalize("NFKC"); +} +/** Class-name base cap keeping each emitted name — and total text — linear in schema depth. */ +const MAX_CLASS_NAME_BASE = 120; +/** +* Deepest `list[…]` nesting emitted into one annotation before the item type +* degrades to `Any`. CPython's tokenizer rejects a logical line holding more +* than 200 simultaneously-open brackets (`MAXLEVEL`, `SyntaxError: too many +* nested parentheses`), so an array chain deeper than that would render an SDK +* block that is not valid Python at all — the same failure the docstring +* escaping in {@link docLines} exists to prevent. 180 leaves headroom for the +* few brackets an annotation can add around the chain, all of which count +* toward the same limit. Per emission site, counting brackets open at the +* chain's innermost point: +* +* - Return annotation, `async def f(self, args: X) -> chain:` — 180 `list[` +* plus an innermost `Literal[`. The parameter list's `(` closed at the `)` +* before the `->`, so it is NOT open here: 181. +* - TypedDict field, `field: NotRequired[chain]` — a class-body line with no +* other open bracket, and its children start at `listDepth: 1` to reserve +* the `NotRequired[`, so 179 `list[` plus `Literal[`: 181. Required fields +* share that start for uniformity, spending one level of representable depth +* on a bracket they never emit. +* - Argument annotation, `async def f(self, args: chain) -> Y:` — the `(` IS +* still open around it: 180 `list[` plus `Literal[` plus the paren, 182, the +* worst case. Reachable only through a raw `register()` whose `parameters` +* is an array reached from the root through `oneOf` arms alone — the root +* array itself, or one nested under any depth of unions, since an arm +* inherits the enclosing depth unchanged (`A | B` opens no bracket). An +* object ancestor takes it out of this case: its fields restart the chain at +* the 181 site. `defineTool` compiles an object root, so the annotation is a +* bare TypedDict class name or a one-bracket `dict[str, Any]` when that +* object degrades — never a chain. +* +* A CPython grammar limit, not a deployment choice, so it is fixed rather than +* configurable. The sibling `ts-types` renderer needs no counterpart: nothing +* in the TypeScript grammar bounds nesting, and its SDK block is never type- +* checked. Only bracket nesting counts — a `oneOf` renders as a flat `A | B` +* chain and nested objects render as separate `class` statements, so neither +* accumulates open brackets at any depth. The invariant this cap serves is +* grammatical validity; see the `oneOf` arm in {@link renderType} for the one +* interpreter limit deliberately left uncapped. +*/ +const MAX_LIST_NESTING = 180; +/** +* Cap a class-name base at {@link MAX_CLASS_NAME_BASE} (see the callers for +* why capping keeps the render linear). `slice` counts UTF-16 code units, so +* an astral character straddling the boundary would be cut in half and leave a +* lone surrogate — not an identifier character, and not even well-formed text; +* drop it rather than emit it. +*/ +function capClassNameBase(base) { + if (base.length <= MAX_CLASS_NAME_BASE) return base; + const capped = base.slice(0, MAX_CLASS_NAME_BASE); + return /[\uD800-\uDBFF]$/.test(capped) ? capped.slice(0, -1) : capped; +} +/** +* Reserve a unique class name from a base, suffixing `2`, `3`, … on collision. +* The base is capped at {@link MAX_CLASS_NAME_BASE} first: child class names +* derive from their parent's allocated name (`ParentChild`), so an unbounded +* schema of single-field objects would otherwise grow each name by one field +* per level and the sum of all names to Θ(depth²). Capping the base keeps each +* name — and the total emitted text — linear in depth. Collisions resume from +* the per-base counter in `state.nextClassCounter` rather than rescanning from +* `2`, so a deep chain sharing one capped base stays O(1) per allocation +* (amortized) instead of Θ(depth²) in time. +*/ +function allocateClassName(base, state) { + const capped = capClassNameBase(base); + let name = capped; + if (state.usedClassNames.has(name)) { + let n = state.nextClassCounter.get(capped) ?? 2; + while (state.usedClassNames.has(`${capped}${n}`)) n++; + name = `${capped}${n}`; + state.nextClassCounter.set(capped, n + 1); + } + state.usedClassNames.add(name); + return name; +} +/** +* Append a child-name segment to a parent class-name base, capping the result +* at {@link MAX_CLASS_NAME_BASE}. Capping AT PROPAGATION (not only inside +* {@link allocateClassName}) keeps each level O(1): a deep `oneOf`- or +* object-chain would otherwise carry an ever-growing ConsString down the tree +* and re-materialize it (via `.length`/`.slice`) at every level — Θ(depth²). +* The bounded base plus the collision counter still yields unique names. +* +* The join is NFKC-normalized because both sides are separately normalized yet +* their concatenation need not be: a base ending in a Hangul L jamo or LV +* syllable composes with a following V or T jamo head (`가` + `ᆨ` gives `각`), +* so the emitted class name would differ from the symbol CPython compiles, and +* two byte-distinct names could fold onto one — `usedClassNames` dedupes by the +* raw bytes, so the collision counter would not see it. Normalizing costs +* O(cap + segment) per level, the same order as the `slice` it feeds. The other +* two join points need no counterpart: `Args`/`Output` start with `A`/`O` and +* {@link allocateClassName}'s suffix is digits, none of which compose backwards. +*/ +function childClassName(base, segment) { + return capClassNameBase(`${base}${segment}`.normalize("NFKC")); +} +/** +* Render one validated scalar as Python literal text (`True`/`False`, +* JSON-quoted strings, bare numbers). `null` cannot reach here: the `null` +* type renders directly as `None`, and the unified validator rejects a null +* `const`/`enum` entry on every other scalar type. +* +* A beyond-safe-range integral number takes `BigInt` digits rather than +* `String`: Python integers are arbitrary-precision, so the emitted digits ARE +* the value the model programs against, and `String` can give a different +* integer than the double holds (`2 ** 60` prints the rounded `...847000`, not +* the exact `...846976`) or no integer literal at all (`1e21` prints `1e+21`). +* `String`'s rounding is not a bug in it: `Number::toString` emits the shortest +* decimal string that re-reads to the same double, then pads to the exponent +* with zeros (1 significant digit for `1e20`, 16 for `2 ** 60`) — and when the +* shortest string is shorter than the double's exact value, those padded digits +* name an integer no double holds. Passing one back would have to cross the +* argument boundary as a JSON number — a double again — so the SDK would +* document a value no program can pass. `BigInt` needs no case split: where +* `String` is already exact (`2 ** 53`, `1e20`) the two agree byte for byte, +* and where it is not, `BigInt` is the exact one. The TS flavor needs no +* counterpart at all: its literal is re-read by a JS parser back into the same +* double. +* +* `JSON.stringify` is also what keeps this path's output parseable, and it is +* the only thing that does. It covers both classes of hazard: the two kinds of +* code point CPython refuses anywhere in source — NUL among the C0 controls, +* and the whole D800–DFFF unpaired-surrogate block, escaped under ES2019 +* well-formed stringification, which the engines range guarantees — and the +* ones that break this line in particular, a bare `"` closing the literal +* early, a trailing odd backslash eating the closing quote, and a bare LF/CR +* ending it before its terminator. The `description` path carries +* {@link UNPRINTABLE} and {@link LONE_SURROGATE} because nothing quotes it, +* and folds newlines in {@link describe}. +* +* That leans on a coincidence worth naming: every escape `JSON.stringify` can +* emit (`\"`, `\\`, `\b`, `\f`, `\n`, `\r`, `\t`, `\uXXXX`) is also a Python +* escape denoting the same character, so the emitted `Literal[...]` both +* parses and decodes back to the value the schema declared. DEL, the C1 +* controls (NEL among them), and LS/PS (U+2028/U+2029) do reach it raw — +* legal but invisible, byte-for-byte as in the TS flavor; escaping them is a +* both-flavors change. Those last three are legal here for the reason +* {@link UNPRINTABLE} records: they are `str.splitlines()` boundaries, not +* tokenizer line terminators. The subscript tool-name comment quotes its name +* through its own call to the same `JSON.stringify`, never through this +* function, and inherits both halves — escapes and pass-throughs alike. +*/ +function pyScalar(value) { + if (value === true) return "True"; + if (value === false) return "False"; + if (typeof value === "string") return JSON.stringify(value); + if (typeof value === "number" && Number.isInteger(value) && !Number.isSafeInteger(value)) return BigInt(value).toString(); + return String(value); +} +/** +* Render a validated scalar `const`/`enum` as `Literal[...]`, falling back to +* the broad type. Deliberately deviates from PEP 586, which restricts `Literal` +* parameters to int/bool/str/bytes/enum/None: a non-integral number +* `const`/`enum` emits a float literal (`Literal[1.5]`) a strict checker would +* reject. An integral one does not deviate — {@link pyScalar} emits int digits, +* including for the beyond-safe-range values it widens through `BigInt`, and +* PEP 586 admits int parameters. Harmless either way — the stub is advisory +* prompt text, only required to parse — and keeping the exact value +* communicates the constraint to the model. +*/ +function renderConstrainedScalar(node, broad, state) { + if (node.const !== void 0) { + state.typing.add("Literal"); + return `Literal[${pyScalar(node.const)}]`; + } + if (node.enum !== void 0) { + state.typing.add("Literal"); + return `Literal[${node.enum.map(pyScalar).join(", ")}]`; + } + return broad; +} +/** +* Map one JSON-Schema node to a Python type expression, threading `state` to +* collect the `TypedDict` declarations and `typing` symbols a full render +* needs. `className` is the name to give an object node with properties (and +* the prefix for its nested objects). Handles every unified schema construct — +* `oneOf` (→ `X | Y`), `const`/`enum` (→ `Literal[...]`), `integer` (→ `int`), +* `null` (→ `None`) — and degrades an unsupported or malformed schema to `Any` +* without throwing, the same trusted-after-validation stance as the sibling +* {@link ./ts-types.ts | ts-types} renderer. {@link jsonSchemaToPy} is the +* context-free entry point; this is the collecting core. +*/ +function renderType(schema, className, state) { + const newFrame = (schema, className, listDepth) => ({ + schema, + className, + phase: "start", + listDepth, + children: [], + childIndex: 0, + childTypes: [], + entries: [] + }); + try { + assertSupportedJsonSchema(schema); + const frames = [newFrame(schema, className, 0)]; + let result; + const finish = (type) => { + frames.pop(); + const parent = frames.at(-1); + if (parent === void 0) result = type; + else parent.childTypes.push(type); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === void 0) break; + if (frame.phase === "children") { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === void 0) throw new Error("missing python render child"); + frame.childIndex++; + frames.push(newFrame(child.schema, child.className, child.listDepth)); + continue; + } + if (frame.kind === "oneOf") { + let union = ""; + for (const [index, childType] of frame.childTypes.entries()) union = index === 0 ? childType : `${union} | ${childType}`; + finish(union); + continue; + } + if (frame.kind === "array") { + /* v8 ignore next -- the ?? arm needs a childless array frame, which start never builds. */ + finish(`list[${frame.childTypes[0] ?? "Any"}]`); + continue; + } + const node = frame.node; + const name = frame.allocated; + /* v8 ignore next -- typeddict frames always set node and allocated at start. */ + if (node === void 0 || name === void 0) throw new Error("missing typeddict frame state"); + const required = new Set(node.required); + const lines = [`class ${name}(TypedDict):`]; + for (let index = 0; index < frame.entries.length; index++) { + const entry = frame.entries[index]; + const fieldType = frame.childTypes[index]; + /* v8 ignore next -- entries and childTypes correspond one-to-one. */ + if (entry === void 0 || fieldType === void 0) throw new Error("missing typeddict field type"); + const [field, fieldSchema] = entry; + const description = describe(fieldSchema); + if (description !== void 0) lines.push(`${pad(1)}# ${description}`); + if (required.has(field)) lines.push(`${pad(1)}${field}: ${fieldType}`); + else { + state.typing.add("NotRequired"); + lines.push(`${pad(1)}${field}: NotRequired[${fieldType}]`); + } + } + if (node.additionalProperties !== false) lines.push(`${pad(1)}# Additional keys beyond those declared are allowed.`); + if (lines.length === 1) lines.push(`${pad(1)}pass`); + state.classes.push(lines.join("\n")); + finish(name); + continue; + } + frame.phase = "children"; + const node = frame.schema; + if (node.oneOf !== void 0) { + frame.kind = "oneOf"; + frame.children = node.oneOf.map((branch, index) => ({ + schema: branch, + className: childClassName(frame.className, `${index + 1}`), + listDepth: frame.listDepth + })); + continue; + } + if (node.type === void 0) { + state.typing.add("Any"); + finish("Any"); + continue; + } + switch (node.type) { + case "string": + finish(renderConstrainedScalar(node, "str", state)); + break; + case "number": + finish(renderConstrainedScalar(node, "float", state)); + break; + case "integer": + finish(renderConstrainedScalar(node, "int", state)); + break; + case "boolean": + finish(renderConstrainedScalar(node, "bool", state)); + break; + case "null": + finish("None"); + break; + case "array": + if (node.items === void 0) { + state.typing.add("Any"); + finish("list[Any]"); + break; + } + if (frame.listDepth >= MAX_LIST_NESTING) { + state.typing.add("Any"); + finish("Any"); + break; + } + frame.kind = "array"; + frame.children = [{ + schema: node.items, + className: frame.className, + listDepth: frame.listDepth + 1 + }]; + break; + case "object": { + const entries = Object.entries(node.properties ?? {}); + if (className === "" || !entries.every(([name]) => isBareIdentifier(name) && !RESERVED.has(name) && !(name.startsWith("__") && !name.endsWith("__")))) { + state.typing.add("Any"); + finish("dict[str, Any]"); + break; + } + if (entries.length === 0 && node.additionalProperties !== false) { + state.typing.add("Any"); + finish("dict[str, Any]"); + break; + } + frame.kind = "typeddict"; + frame.node = node; + frame.allocated = allocateClassName(frame.className, state); + state.typing.add("TypedDict"); + frame.entries = entries; + /* v8 ignore next -- allocated is always set before children are built. */ + frame.children = entries.map(([field, child]) => ({ + schema: child, + className: childClassName(frame.allocated ?? "", camelCase(field)), + listDepth: 1 + })); + break; + } + /* v8 ignore next 4 -- assertSupportedJsonSchema narrowed this closed type union. */ + default: + state.typing.add("Any"); + finish("Any"); + } + } + /* v8 ignore next -- every root frame produces one expression. */ + return result ?? "Any"; + } catch { + state.typing.add("Any"); + return "Any"; + } +} +/** +* Map one JSON-Schema node to a context-free Python type expression from the +* `typing` module. Handles every unified schema construct — `object` (degraded +* to `dict[str, Any]`: naming a `TypedDict` requires the render context that +* {@link renderToolsSdkPy} supplies), `const`/`enum` (→ `Literal[...]`), +* `oneOf` (→ union), `string`/`number`/`integer`/`boolean`/`null`, `array` +* (`items` → `list[T]`) — and returns `Any` for an unsupported or malformed +* schema, matching the TS flavor's `unknown` fallback. Type annotations in the +* emitted SDK are advisory: Python does not enforce them at runtime. +* @param schema - the JSON-Schema node. +* @returns the Python type text. +*/ +function jsonSchemaToPy(schema) { + return renderType(schema, "", { + classes: [], + usedClassNames: /* @__PURE__ */ new Set(), + nextClassCounter: /* @__PURE__ */ new Map(), + typing: /* @__PURE__ */ new Set() + }); +} +/** The fixed model-facing usage contract rendered above the declarations. */ +const SDK_INSTRUCTIONS = `## Writing code for run_code + +\`run_code\` takes two required arguments: \`code\` — the body of an async Python function (top-level \`await\` and \`return\` both work) — and \`description\`, a short summary of what the program does. At run time exactly two of the names declared below are bound: \`tools\` and \`ToolCallError\`. Everything else is a STATIC STUB describing argument and return types — in particular the \`TypedDict\` classes do NOT exist at run time, so build arguments as plain \`dict\`/\`list\` JSON values: \`await tools.name({"field": 1})\`, never \`FooArgs(field=1)\`, which raises \`NameError\`. Inside the program: + +- Call tools as \`await tools.name(args)\` — subscript access for exotic, reserved, or underscore-leading names: \`await tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value (each method's return type below). Tool arguments must be lossless JSON. +- A FAILED tool call raises \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose message is human-readable — wrap in \`try/except\` to handle and continue. +- Independent read-only calls MAY overlap under \`asyncio.gather\` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with \`await\`. +- Emit the run's answer with \`print(...)\` and/or a top-level \`return \`; the returned value must be lossless JSON. ONLY what you print and the returned value come back — intermediate tool results never enter the conversation, so extract just what you need. + +The available tools:`; +/** +* Render the full `tools:sdk` prompt section under `runtime.language === +* 'python'`: the Python-flavored usage instructions plus one named `TypedDict` +* per tool argument or output object (and per nested object) and one awaitable +* method per visible tool on a `Tools` protocol — typed args in, the tool's +* canonical output value out — with a `tools: Tools` singleton the model calls +* into. The `typing` import line lists exactly the symbols the render used. +* Deterministic — tools are emitted in lexicographic name order, and class +* declarations precede the protocol in that same order (nested classes before +* the parent that references them), so an unchanged tool set produces +* byte-identical text across assemblies. The sort is not a total order on +* byte-equal names, so two schemas sharing a name would render in argument +* order; the caller's visible-capability map is keyed by name, so the input +* never carries a duplicate. +* @param schemas - the tool schemas plus canonical output schemas to declare +* (the caller excludes `run_code` itself). +* @returns the complete section text. +*/ +function renderToolsSdkPy(schemas) { + const sorted = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0); + const state = { + classes: [], + usedClassNames: /* @__PURE__ */ new Set(), + nextClassCounter: /* @__PURE__ */ new Map(), + typing: new Set(["Protocol"]) + }; + const members = []; + let statements = 0; + for (const schema of sorted) { + const argType = renderType(schema.parameters, `${camelCase(schema.name)}Args`, state); + const outputType = renderType(schema.output, `${camelCase(schema.name)}Output`, state); + if (isBareIdentifier(schema.name) && !RESERVED.has(schema.name) && !schema.name.startsWith("_")) { + const doc = docLines(schema.description, 2); + members.push(doc.length > 0 ? `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}:` : `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}: ...`); + members.push(...doc); + statements += 1; + } else { + members.push(`${pad(1)}# tools[${JSON.stringify(schema.name)}](args: ${argType}) -> ${outputType}`); + const description = describe(schema); + if (description !== void 0) members.push(`${pad(1)}# ${description}`); + } + } + const body = (statements > 0 ? members : [`${pad(1)}pass`, ...members]).join("\n"); + const imports = TYPING_ORDER.filter((symbol) => state.typing.has(symbol)); + const classBlock = state.classes.length > 0 ? `${state.classes.join("\n\n")}\n\n` : ""; + return `${SDK_INSTRUCTIONS}\n\n\`\`\`python\n${`from typing import ${imports.join(", ")}\n\nclass ToolCallError(Exception): + toolName: str\n\n${classBlock}class Tools(Protocol):\n${body}\n\ntools: Tools`}\n\`\`\``; +} +//#endregion +//#region lib/types/testing.js +/** Canonical tool-definition fixtures for repository tests. @module dsh-tools/testing */ +const CONTENT_VALUE_SCHEMA = { + type: "array", + items: { type: "json" } +}; +/** +* Define a test fixture that deliberately uses its content blocks as the +* canonical JSON value. Product tools must declare domain-owned DTOs instead. +* @param options - ordinary fixture fields plus a content-producing body. +* @returns a registry-ready tool with an explicit JSON-array output contract. +* @internal +*/ +function defineContentToolFixture(options) { + const execute = options.execute; + return defineTool({ + ...options, + output: { + schema: CONTENT_VALUE_SCHEMA, + render: (_args, value) => value + }, + async execute(args, exec) { + return await execute(args, exec); + } + }); +} +//#endregion +//#region lib/types/index.js +/** +* Tool registry, model presentation modes, and pre/guard/around/post/result +* execution pipeline. +* @module @deepseek-ai/dsh-tools +*/ +/** +* Language → SDK-section renderer. The registry looks up the loaded +* `ctx.codeRuntime.language` in this table when assembling the `tools:sdk` +* section under a non-native mode; a runtime whose language is not a key +* fails the assembly loudly (same idiom as `toolOrder` violations). Adding a +* new backend language is three parallel edits — a {@link CodeSdkLanguage} +* member, an entry here, and a `RUN_CODE_FLAVORS` entry in `code-mode.ts` for +* its `run_code` schema strings — plus the renderer function this table points +* at. The `satisfies` clause pins this table's key set to that union, which +* the flavor table is checked against too, so any of the three left out is a +* typecheck failure. What no check reaches is the prose that names the values +* instead of deriving them: the seam's `dsh-code-runtime` README pair, its +* `CodeRuntime.language` JSDoc, and `docs/subsystems/code-runtime.md` +* with its zh pair, plus this package's own README pair and the +* {@link Config.mode} JSDoc. +*/ +/** +* Prompt order of the `code` collapse statement: after the persona and before +* the 100-199 per-tool guidance band, so the model reads which tools it may +* call before it reads what each one is for. +*/ +const COLLAPSE_SECTION_ORDER = 99; +/** +* The model-facing statement of the `code` collapse. Names the consequence +* (the call fails) and the route (inside the program), because a rule the +* model can only discover by being denied is one it corrects too late. +*/ +const CODE_ONLY_INSTRUCTION = `\`${RUN_CODE_NAME}\` is the only tool you can call directly — a tool call naming any other tool fails. Reach every tool the SDK declares below from inside the program.`; +const SDK_RENDERERS = { + typescript: renderToolsSdk, + python: renderToolsSdkPy +}; +/** +* Scheduler entry point omitted from the generated named service API. +* @internal +*/ +const TOOL_RUNTIME_SCHEDULER = Symbol("@deepseek-ai/dsh-tools.scheduler"); +/** Canonical error code for cancellation after a tool body was invoked. */ +const TOOL_ABORTED = "ABORTED"; +/** Canonical error code for cancellation before a tool body was invoked. */ +const TOOL_ABORTED_BEFORE_DISPATCH = "ABORTED_BEFORE_DISPATCH"; +/** +* Thrown (internally) when the model requests a tool that isn't registered. +* Extends {@link HarnessError} (`code: 'UNKNOWN_TOOL'`) so an unknown-tool +* failure is as routable as a tool-thrown one — retry/sandbox/replay code can +* distinguish it from a tool body's own error. +*/ +var ToolNotFoundError = class extends HarnessError { + /** + * @param toolName - the name the caller asked for. + * @param reachableFrom - how the model reaches this tool instead, when the + * name IS visible and only the presentation denies calling it directly. + * Omitted for a name that is registered nowhere. + */ + constructor(toolName, reachableFrom) { + super(reachableFrom === void 0 ? `unknown tool "${toolName}"` : `unknown tool "${toolName}": ${reachableFrom}`, "UNKNOWN_TOOL"); + this.name = "ToolNotFoundError"; + } +}; +/** Thrown when a tool body or post-policy value violates its declared output. */ +var ToolOutputError = class extends HarnessError { + /** Schema/value violations in validation order. */ + violations; + constructor(toolName, violations) { + super(`tool "${toolName}" returned invalid output: ${violations.join("; ")}`, "INVALID_TOOL_OUTPUT"); + this.name = "ToolOutputError"; + this.violations = violations; + } +}; +/** Convert one projector exception into the canonical invalid-output failure. */ +function projectionError(toolName, projector, error) { + return new ToolOutputError(toolName, [`output.${projector} failed: ${errorMessage(error)}`]); +} +/** Snapshot one projector result before later durable-result materialization. */ +function snapshotProjection(toolName, projector, candidate) { + try { + const detached = snapshotJsonValue(candidate); + if (detached === void 0) throw new ToolOutputError(toolName, [`output.${projector} returned non-lossless JSON`]); + return detached; + } catch (error) { + if (error instanceof ToolOutputError) throw error; + throw projectionError(toolName, projector, error); + } +} +/** Snapshot one body or policy value into the canonical invalid-output failure class. */ +function snapshotToolValue(toolName, candidate) { + try { + const detached = snapshotJsonValue(candidate); + if (detached === void 0) throw new ToolOutputError(toolName, ["value is not lossless JSON"]); + return detached; + } catch (error) { + if (error instanceof ToolOutputError) throw error; + throw new ToolOutputError(toolName, [`value snapshot failed: ${errorMessage(error)}`]); + } +} +/** +* Best-effort human-readable message from an arbitrary thrown value: Error +* instances use `.message`; non-Error objects with a string `message` +* property (e.g. `throw { message: 'denied' }`) use it too; everything else +* is stringified. +*/ +function errorMessage(error) { + try { + if (error instanceof Error) return error.message; + if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") return error.message; + return String(error); + } catch { + return ""; + } +} +/** Derive one failure message from policy feedback without changing its rendered blocks. */ +function failureMessageFromContent(content) { + const text = content.map((block) => block.type === "text" ? block.text : `[${block.type} content]`).join("\n"); + return text.length > 0 ? text : "tool result blocked by post-execute policy"; +} +/** Snapshot and freeze one durable tool-result projection or reject lossy data. */ +function materializePresentation(candidate) { + const detached = snapshotJsonValue(candidate); + if (detached === void 0) throw new TypeError("tool result must be losslessly JSON-serializable"); + return deepFreeze(detached); +} +/** Structured `{ name, code }` for a thrown HarnessError, else undefined. */ +function errorInfo(error) { + try { + return error instanceof HarnessError ? { + name: error.name, + code: error.code + } : void 0; + } catch { + return; + } +} +/** One scope's complete tool-registry contribution. */ +var ToolLayer = class { + tools; + restrictions = new AnonymousEntries(); + guards = new AnonymousEntries(); + /** + * Presentation this scope's agent declared for itself, shadowing the + * deployment default. One cell rather than an entry table: two answers to + * "which form does the model see" is a contradiction, not a merge. + */ + mode; + constructor(scope) { + this.tools = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `tool "${name}" is already registered (for a per-agent variant, register through that agent's \`agent.ctx\` instead)` : `tool "${name}" is already registered in this scope`)); + } + /** Whether every contribution table in this aggregate layer is empty. */ + isEmpty() { + return this.tools.isEmpty() && this.restrictions.isEmpty() && this.guards.isEmpty() && this.mode === void 0; + } + /** Whether every compiled restriction in this layer admits a global tool name. */ + admits(name) { + for (const filter of this.restrictions.values()) if (filter.allow !== void 0 && !filter.allow.has(name) || filter.deny !== void 0 && filter.deny.has(name)) return false; + return true; + } + /** First monotonic denial from this layer's live guard registrations. */ + guardReason(exec) { + for (const guard of this.guards.values()) { + const reason = guard(exec); + if (reason !== void 0) return reason; + } + } +}; +/** Resolve the run_code overlap cap at the owning config boundary (direct construction bypasses the Loader schema). */ +function resolveMaxParallelSubCalls(value) { + const maxParallelSubCalls = value ?? 10; + if (!Number.isInteger(maxParallelSubCalls) || maxParallelSubCalls < 1) throw new Error("maxParallelSubCalls must be a positive integer"); + return maxParallelSubCalls; +} +/** +* Tool registry and execution pipeline. Scoped registrations shadow globals; +* one visibility resolver feeds presentation, lookup, and dispatch. +*/ +var ToolRuntime = class extends Service { + static inject = ["systemPrompt"]; + static Config = z.object({ + mode: z.union([ + "native", + "code", + "both" + ]).default("native"), + maxParallelSubCalls: z.natural().min(1).default(10) + }); + /** Internal staged view consumed by `dsh-agent-loop`'s parallel scheduler. */ + [TOOL_RUNTIME_SCHEDULER] = { + prepare: (exec) => this.prepareScheduledExecution(exec), + dispatch: (exec) => this.dispatchScheduledExecution(exec), + finalize: (exec, result) => this.finalizeScheduledExecution(exec, result), + finish: (exec, result) => this.finishScheduledExecution(exec, result) + }; + /** Context deferred by a running tool body, keyed by its scheduler-owned execution. */ + deferredContexts = /* @__PURE__ */ new WeakMap(); + /** Executions whose tool body declared the current turn complete. */ + concludingExecutions = /* @__PURE__ */ new WeakSet(); + /** Original caller cancellation, kept outside the wrapper-mutable execution object. */ + cancellationStates = /* @__PURE__ */ new WeakMap(); + /** Definition-owned final content transform snapshotted before policy begins. */ + contentFinalizers = /* @__PURE__ */ new WeakMap(); + layers = new ScopedLayers((scope) => new ToolLayer(scope), () => { + this.ctx.emit("tools/change"); + }); + /** Presentation for scopes that declare none; {@link presentAs} shadows it per scope. */ + defaultMode; + maxParallelSubCalls; + /** + * Reserved presentation transport, kept outside the filterable registration + * layers. Built on first need rather than at construction: which agents run + * a code mode is no longer known when the service is constructed, and the + * transport is stateless beyond its closures over `this`. + */ + codeTransport; + constructor(ctx, config = {}) { + super(ctx, "tools"); + this.defaultMode = config.mode ?? "native"; + this.maxParallelSubCalls = resolveMaxParallelSubCalls(config.maxParallelSubCalls); + ctx.systemPrompt.tools((context) => this.wireSchemas(context.scope)); + if (this.defaultMode !== "native") { + ctx.systemPrompt.section(this.collapseSection()); + ctx.systemPrompt.section(this.sdkSection()); + } + } + /** + * The prompt statement of the `code` executor collapse, registered wherever + * {@link sdkSection} is and rendering empty outside an effective `code`. + * + * Every tool contributes its own guidance section naming its tool, none of + * them qualify how that tool is reached, and they all render before the SDK + * (orders 100-199 against {@link SDK_SECTION_ORDER}). Without this the model + * reads a catalog of tools it is told to use and no statement that only + * `run_code` may be called, so it emits a native call, receives + * `UNKNOWN_TOOL` for a tool the prompt just declared, and concludes the + * deployment is inconsistent. {@link COLLAPSE_SECTION_ORDER} places the rule + * before that guidance rather than after it. + * + * `both` renders empty: native calls do execute there, so the rule is false. + * @returns the section registration. + */ + collapseSection() { + return { + name: "tools:code-only", + order: COLLAPSE_SECTION_ORDER, + text: (context) => this.modeFor(context.scope) === "code" ? CODE_ONLY_INSTRUCTION : "" + }; + } + /** + * The generated-SDK prompt section, registered globally by a code-mode + * deployment and per scope by {@link presentAs}. + * + * The body regenerates from the CALLING scope, and renders empty for an + * agent presenting natively — an agent that opted out under a code-mode + * deployment still sees the global registration, and an empty section is + * dropped from the rendered prompt. + * @returns the section registration. + */ + sdkSection() { + return { + name: "tools:sdk", + order: 150, + text: (context) => { + const mode = this.modeFor(context.scope); + if (mode === "native") return ""; + const runtime = this.requireCodeRuntime(mode); + const render = SDK_RENDERERS[runtime.language]; + /* v8 ignore next -- requireCodeRuntime rejects an unknown language before this runs. */ + if (render === void 0) throw new Error(`dsh-tools: no SDK renderer for ${runtime.language}`); + return render(this.sdkSchemas(context.scope)); + } + }; + } + /** + * The presentation one scope's agent sees: its own declaration, else the + * deployment default. + * @param scope - the calling agent, or undefined for the global view. + * @returns the resolved presentation mode. + */ + modeFor(scope) { + const layers = this.layers.chainLayers(scope); + for (let index = layers.length - 1; index >= 0; index -= 1) { + const mode = layers[index]?.mode; + if (mode !== void 0) return mode; + } + return this.defaultMode; + } + /** + * The reserved `run_code` transport, built on first need. + * + * It never enters the global layer: per-agent restrictions must not remove + * it, and a scoped registration must not shadow it. The visibility resolver + * appends it after resolving the filterable global/scoped capability layers, + * and only for scopes whose mode actually presents it. + * @returns the shared transport definition. + */ + requireCodeTransport() { + this.codeTransport ??= createRunCodeTool(this, { + requireRuntime: () => this.requireCodeRuntime(this.defaultMode), + peekRuntime: () => this.ctx.get("codeRuntime"), + maxParallel: this.maxParallelSubCalls, + shapeDispatchLog: (dispatch) => this.shapeDispatchLog(dispatch) + }); + return this.codeTransport; + } + /** + * Present the calling scope's tools in `mode` instead of the deployment + * default. Nearest scope on the chain wins, so a preset's standing + * declaration covers every agent joined under it. + * + * Scoped only, and one declaration per scope: this is how an agent preset + * composes Code Mode agents beside native ones in the same process, and a + * process-global override would be the `mode` config field instead. + * @param mode - the presentation the covered agents' models see. + * @returns the exact disposer that restores the deployment default. + */ + presentAs(mode) { + const ctx = this.ctx; + if (scopeOf(ctx) === void 0) throw new Error("tools.presentAs() requires a scoped context (agent.ctx): a context-global presentation is the `mode` config field on the tools row"); + return ctx.effect(function* () { + yield this.layers.effect(ctx, (layer) => { + if (layer.mode !== void 0) throw new Error(`tools.presentAs("${mode}") conflicts with "${layer.mode}" already declared for this scope; one composition selects one presentation`); + layer.mode = mode; + return () => { + layer.mode = void 0; + }; + }, { label: "tools.presentAs()" }); + if (mode !== "native") { + yield ctx.systemPrompt.section(this.collapseSection()); + yield ctx.systemPrompt.section(this.sdkSection()); + } + }.bind(this), "tools.presentAs()"); + } + /** + * Build one scope's wire schemas and names for prompt-order validation. + * Restrictions do not make known tools invalid, but a mode collapse does. + */ + wireSchemas(scope) { + const view = this.view(scope); + const mode = this.modeFor(scope); + if (mode === "native") return { + schemas: [...view.visible.values()].map((definition) => this.schemaOf(definition, false)), + knownNames: [...view.knownNames] + }; + this.requireCodeRuntime(mode); + const schemas = [...view.visible.values()].map((definition) => this.schemaOf(definition, false)); + if (mode === "code") return { + schemas: schemas.filter((schema) => schema.name === RUN_CODE_NAME), + knownNames: [RUN_CODE_NAME] + }; + return { + schemas, + knownNames: [...view.knownNames, RUN_CODE_NAME] + }; + } + /** + * Resolve the code runtime or throw the actionable misconfiguration error. + * Read at use time (assembly / run_code execution), NOT via static + * `inject`: an inject entry would hold `ctx.tools` — and every tool plugin + * behind it — hostage to a code runtime existing even under `mode: + * 'native'` (the loop's optional-backend idiom, same as + * `sessionPersistence`). + * + * Assembly and `run_code` execution read separately, so the language is not + * bound to a request. Harmless while one published backend exists — both + * reads return the same flavor — but a reload that swapped in a second + * language between them would hand a program written against one SDK to the + * other. Binding it is deferred until a second backend ships (the first + * point it is testable); rationale in the + * [language-dispatch note](../../../../.agents/notes/implemented/feature/2026-07-31-code-mode-language-dispatch.md). + */ + requireCodeRuntime(mode) { + const runtime = this.ctx.get("codeRuntime"); + if (!runtime) throw new Error(`dsh-tools: mode "${mode}" requires a code runtime — load a ctx.codeRuntime implementation (e.g. @deepseek-ai/dsh-code-runtime-worker-thread) or set tools mode to "native"`); + if (!Object.hasOwn(SDK_RENDERERS, runtime.language)) { + const known = Object.keys(SDK_RENDERERS).map((name) => JSON.stringify(name)).join(", "); + throw new Error(`dsh-tools: no SDK renderer registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`); + } + return runtime; + } + /** + * Register globally or in the calling agent scope. Scoped tools shadow + * globals; duplicates within one layer and the reserved `run_code` name fail. + * @param definition - tool schema, execution, and optional finalization/presentation callbacks. + * @returns the exact disposer that unregisters the tool. + */ + register(definition) { + const name = definition.name; + const output = definition.output; + if (output === void 0 || typeof output !== "object" || typeof output.render !== "function" || output.presentationMeta !== void 0 && typeof output.presentationMeta !== "function") throw new TypeError(`tool "${name}" must declare output { schema, render, presentationMeta? }`); + assertSupportedJsonSchema(output.schema); + const timeoutMs = definition.timeoutMs; + if (timeoutMs !== void 0 && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) throw new TypeError(`tool "${name}" timeoutMs must be a positive finite number`); + if (name === "run_code") throw new Error(`tool name "${RUN_CODE_NAME}" is reserved for the Code Mode presentation transport and cannot be registered or shadowed`); + return this.layers.effect(this.ctx, (layer) => layer.tools.insert(name, definition), { label: "tools.register()" }); + } + /** + * Restrict global tools for the calling agent scope. Empty filters, unknown + * names, scope-local names, and reserved transport names fail. Restrictions + * intersect; scoped registrations remain visible. + * @param filter - global-tool mask: `allow` (keep only) and/or `deny` (remove). + * @returns the exact disposer that lifts this restriction. + */ + restrict(filter) { + const scope = scopeOf(this.ctx); + if (scope === void 0) throw new Error("tools.restrict() requires a scoped context (agent.ctx): a context-global restriction would mask every agent — deny the tool for the intended agent instead"); + const allow = filter.allow; + const deny = filter.deny; + if (allow === void 0 && deny === void 0) throw new Error("tools.restrict({}) is a no-op: pass `allow` and/or `deny` (an empty filter is almost always a materialized-empty-config bug)"); + const compiled = { + ...allow !== void 0 ? { allow: new Set(allow) } : {}, + ...deny !== void 0 ? { deny: new Set(deny) } : {} + }; + if ([...allow ?? [], ...deny ?? []].includes("run_code")) throw new Error(`tools.restrict() cannot name reserved Code Mode presentation transport "${RUN_CODE_NAME}"; restrict end-capability tools instead`); + const known = this.view(scope).restrictableNames; + const unknown = [...allow ?? [], ...deny ?? []].filter((name) => !known.has(name)); + if (unknown.length > 0) throw new Error(`tools.restrict() names unknown global tool${unknown.length > 1 ? "s" : ""} ${unknown.map((n) => `"${n}"`).join(", ")}; known global tools: ${[...known].sort().join(", ") || "(none)"}`); + return this.layers.effect(this.ctx, (layer) => layer.restrictions.append(compiled), { label: "tools.restrict()" }); + } + /** + * Register a monotonic guard after the extensible `tools/pre-execute` + * waterfall. A plain-context guard applies globally; one registered through + * `agent.ctx` applies only to that agent. Any matching guard may deny by + * returning a reason, while no guard can force-allow a call another guard + * denied. The exact effect disposer is returned for ordered ownership and + * HMR cleanup. + * @param guard - synchronous check; a returned string denies the execution. + * @returns the exact disposer that unregisters the guard. + */ + guard(guard) { + return this.layers.effect(this.ctx, (layer) => layer.guards.append(guard), { + label: "tools.guard()", + notify: false + }); + } + /** First monotonic denial from the global then the scope chain's guard layers, farthest first. */ + guardReason(exec) { + const globalReason = this.layers.global.guardReason(exec); + if (globalReason !== void 0) return globalReason; + if (exec.agent === void 0) return void 0; + for (const layer of this.layers.chainLayers(exec.agent)) { + const reason = layer.guardReason(exec); + if (reason !== void 0) return reason; + } + } + /** + * Resolve every registry fact one scope needs in one layer traversal. The + * visible map applies restrictions to the INHERITED surface, then the + * scope's own registrations and the reserved presentation transport; the + * other sets retain the pre-restriction facts needed by restriction and + * prompt-order validation. + * + * A restriction filters what a scope inherits — the global layer and every + * ancestor layer on its chain — and never what its OWN layer registers. + * That exemption is what a per-child capability filter has to keep intact: + * the delegation runtime registers a child's reporting and structured-output + * tools into the child's own layer, and a filter naming the capabilities the + * child may use must not strip the machinery it answers through. + * + * Reading the exempt set as "the global layer" instead of "not mine" held + * only while every model-facing tool sat in the host composition. Once + * presets moved them onto the agent plane they became an ANCESTOR + * contribution, so a child's filter silently stopped constraining anything + * it was given. + * @param scope - the viewing scope (the agent), or undefined for the global view. + * @returns the complete derived view for that scope. + */ + view(scope) { + const layers = this.layers.chainLayers(scope); + const own = this.layers.peek(scope); + const inherited = new Map(this.layers.global.tools.entries()); + for (const layer of layers) { + if (layer === own) continue; + for (const [name, definition] of layer.tools.entries()) inherited.set(name, definition); + } + const visible = /* @__PURE__ */ new Map(); + const knownNames = /* @__PURE__ */ new Set(); + const restrictableNames = /* @__PURE__ */ new Set(); + for (const [name, definition] of inherited) { + knownNames.add(name); + restrictableNames.add(name); + if (layers.every((layer) => layer.admits(name))) visible.set(name, definition); + } + if (own !== void 0) for (const [name, definition] of own.tools.entries()) { + knownNames.add(name); + visible.set(name, definition); + } + if (this.modeFor(scope) !== "native") visible.set(RUN_CODE_NAME, this.requireCodeTransport()); + return { + visible, + knownNames, + restrictableNames + }; + } + /** + * Look up a tool as one scope sees it (scoped + * shadows global; a restricted-away global reads as absent). Presenters pass + * the calling agent so the rendered card matches the definition that + * actually executed. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns the definition the scope resolves, or undefined when none is visible. + */ + get(name, scope) { + return this.view(scope).visible.get(name); + } + /** + * Resolve the definition that MAY EXECUTE for a call, applying the mode + * collapse at the operation boundary that owns it. The registry view + * (`get`) is presentation-agnostic; here a MODEL-DIRECT call under `code` + * may only name the reserved `run_code` transport, while a nested + * sub-dispatch (a `parent` token set — the `run_code` SDK calling a tool + * it bound) may call any visible tool. Denial surfaces as `UNKNOWN_TOOL` + * through the executor, matching an absent definition. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + * @returns the definition that may run, or undefined when the call must be rejected. + */ + resolveExecution(name, scope, nested) { + const tool = this.get(name, scope); + if (tool === void 0) return void 0; + if (this.collapses(name, scope, nested)) return void 0; + return tool; + } + /** + * Project visible definitions onto the allowlisted model-facing schema fields, + * excluding execution and presentation callbacks. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns one deep-cloned schema per visible tool. + */ + schemas(scope) { + return [...this.view(scope).visible.values()].map((definition) => this.schemaOf(definition, true)); + } + /** Project visible callable tools onto the generated Code Mode SDK contract. */ + sdkSchemas(scope) { + return [...this.view(scope).visible.values()].filter((definition) => definition.name !== RUN_CODE_NAME).map((definition) => { + const output = snapshotJsonValue(definition.output.schema); + /* v8 ignore next -- registration already validated and retained this schema as lossless JSON. */ + if (output === void 0) throw new Error(`tool "${definition.name}" output schema must be lossless JSON before SDK projection`); + return { + ...this.schemaOf(definition, true), + output + }; + }); + } + /** Project one definition onto the model-facing schema fields. */ + schemaOf(definition, detachParameters) { + const { name, description, parameters } = definition; + const detached = detachParameters ? snapshotJsonValue(parameters) : parameters; + if (detached === void 0) throw new Error(`tool "${name}" parameters must be lossless JSON before schema projection`); + return { + name, + description, + parameters: detached + }; + } + /** + * Classify a pending call through the caller's visible tool definition. Only + * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or + * throwing classifiers are exclusive. + * @param exec - call name, parsed arguments, and optional agent scope. + * @returns the fail-closed scheduling mode. + */ + executionMode(exec) { + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== void 0); + if (!tool?.isConcurrencySafe) return { kind: "exclusive" }; + try { + return tool.isConcurrencySafe(exec.arguments) === true ? { kind: "parallel" } : { kind: "exclusive" }; + } catch { + return { kind: "exclusive" }; + } + } + /** + * Run the `tools/code-dispatch-log` waterfall over one settled sub-dispatch + * and return the content the bridge should log on `tool/code-dispatch`. + * Contained: when a listener throws, the method logs the original settled + * content; that failure must not fail the dispatch or omit the settle event. Private: + * the ONE consumer is the `run_code` bridge this registry constructs, which + * receives it as a capability parameter (the `requireRuntime` idiom) — the + * waterfall, not this invoker, is the public extension point. + */ + async shapeDispatchLog(dispatch) { + try { + return await this.ctx.waterfall(scopeTarget(this, dispatch.agent), "tools/code-dispatch-log", dispatch, () => Promise.resolve(dispatch.content)); + } catch (error) { + this.ctx.logger.warn(`tools: code-dispatch-log listener failed for ${dispatch.name}: ${errorMessage(error)}; logging the original settled content`); + return dispatch.content; + } + } + /** + * Whether the `code` mode collapse denies a model-direct call: only the + * reserved `run_code` transport may be named. Nested sub-dispatches (a + * `parent` token set) bypass the collapse. One home for the + * security-relevant predicate, shared by {@link resolveExecution} and + * {@link createExecution} so the two can never drift apart. + * + * Resolved through {@link modeFor}, NOT `defaultMode`: an agent given `code` + * by an agent preset under a native deployment is the composition + * `dsh-agent-tool-presentation` exists for, and reading the deployment default would + * leave exactly that agent uncollapsed — announcing one surface while + * executing another, which is the bypass this collapse closes. + * @param name - the tool name as registered. + * @param scope - the viewing scope whose effective presentation mode applies. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + */ + collapses(name, scope, nested) { + return !nested && this.modeFor(scope) === "code" && name !== "run_code"; + } + /** + * Execute through pre-policy, guards, around-dispatch, post-policy, + * definition-owned content finalization, and final notification. Tool and + * listener failures resolve as materialized error results; an invisible tool + * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen + * snapshot final observers receive. Cancellation + * arriving after entry and before final result materialization skips a + * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a + * successful started outcome with `ABORTED`; already-started work is still + * drained and may retain a tool-owned structured error. + * @param exec - the typed same-process call input. The registry assigns its + * correlation token before policy begins. + * @returns the materialized final result. + */ + async execute(exec) { + return this.prepareExecution(exec, (prepared) => this.completeScheduledExecution(prepared)); + } + async completeScheduledExecution(prepared) { + switch (prepared.kind) { + case "dispatch": { + const dispatched = await this.dispatchScheduledExecution(prepared.exec); + return dispatched.kind === "post-result" ? await this.finalizeScheduledExecution(prepared.exec, dispatched.result) : this.finishScheduledExecution(prepared.exec, dispatched.result); + } + case "post-result": return await this.finalizeScheduledExecution(prepared.exec, prepared.result); + case "final-result": return this.finishScheduledExecution(prepared.exec, prepared.result); + /* v8 ignore next -- closed-union exhaustiveness guard */ + default: return assertNever(prepared, "scheduled tool preparation"); + } + } + createExecution(exec) { + const deferredContexts = []; + const token = createExecutionToken(); + const callId = exec.callId; + const rootCallId = exec.rootCallId ?? callId; + const name = exec.name; + const agent = exec.agent; + const parent = exec.parent; + const signal = exec.signal; + const visible = this.get(name, agent); + const collapsed = visible !== void 0 && this.collapses(name, agent, parent !== void 0); + const concludingExecutions = this.concludingExecutions; + const base = { + token, + callId, + rootCallId, + name, + signal, + ...agent !== void 0 ? { agent } : {}, + ...parent !== void 0 ? { parent } : {}, + deferContext(context) { + deferredContexts.push(context); + }, + concludeTurn() { + concludingExecutions.add(this); + } + }; + const capturedFinalizer = visible?.finalizeContent?.bind(visible); + const finalizerFor = () => collapsed && !signal.aborted ? void 0 : capturedFinalizer; + try { + const detached = snapshotJsonValue(exec.arguments); + if (detached === void 0) throw new TypeError("tool execution arguments must be losslessly JSON-serializable"); + const execution = { + ...base, + arguments: deepFreeze(detached) + }; + this.deferredContexts.set(execution, deferredContexts); + this.contentFinalizers.set(execution, finalizerFor()); + this.cancellationStates.set(execution, { + callerSignal: signal, + bodyInvoked: false + }); + if (collapsed) { + if (signal.aborted) return { + kind: "final-result", + exec: execution, + result: toolAbortedBeforeDispatchResult() + }; + return { + kind: "final-result", + exec: execution, + result: toolErrorResult(new ToolNotFoundError(name, `only \`${RUN_CODE_NAME}\` is callable directly — call \`${name}\` from inside a \`${RUN_CODE_NAME}\` program instead`)) + }; + } + return { + kind: "ready", + exec: execution + }; + } catch (error) { + const execution = { + ...base, + arguments: void 0 + }; + this.contentFinalizers.set(execution, finalizerFor()); + return { + kind: "final-result", + exec: execution, + result: toolErrorResult(error) + }; + } + } + /** + * Run the ordered pre-execute and monotonic guard stages for the scheduler. + * @param input - the caller-supplied execution input. + * @returns the prepared execution plus the next scheduler stage. + * @internal + */ + async prepareScheduledExecution(input) { + return this.prepareExecution(input, (prepared) => prepared); + } + async prepareExecution(input, next) { + const created = this.createExecution(input); + if (created.kind !== "ready") return next(created); + const exec = created.exec; + if (this.callerCancelled(exec)) return next({ + kind: "final-result", + exec, + result: toolAbortedBeforeDispatchResult() + }); + try { + const carrier = scopeTarget(this, exec.agent); + const gate = await this.ctx.waterfall(carrier, "tools/pre-execute", exec, () => Promise.resolve({ kind: "allow" })); + const askResolution = gate.kind === "ask" ? await this.serviceAsk(exec, gate) : { + decision: gate, + approvalCancelled: false + }; + const { decision } = askResolution; + if (this.callerCancelled(exec) && askResolution.approvalCancelled) return await next({ + kind: "post-result", + exec, + result: toolAbortedBeforeDispatchResult() + }); + const denialReason = decision.kind === "allow" ? this.guardReason(exec) : decision.reason; + if (denialReason !== void 0) return await next({ + kind: "post-result", + exec, + result: this.materializeFinalResult({ + content: [{ + type: "text", + text: `Error: ${denialReason}` + }], + isError: true, + error: { message: denialReason } + }) + }); + if (this.callerCancelled(exec)) return await next({ + kind: "post-result", + exec, + result: toolAbortedBeforeDispatchResult() + }); + return await next({ + kind: "dispatch", + exec + }); + } catch (error) { + return next({ + kind: "final-result", + exec, + result: toolErrorResult(error) + }); + } + } + /** Whether the original caller signal is currently aborted. */ + callerCancelled(exec) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === void 0) throw new Error("tool registry scheduler invariant violated: missing cancellation state"); + return state.callerSignal.aborted; + } + /** Canonical cancellation outcome selected by whether the tool body started. */ + cancellationResult(exec, prior) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === void 0) throw new Error("tool registry scheduler invariant violated: missing cancellation state"); + return state.bodyInvoked ? toolAbortedResult(prior) : toolAbortedBeforeDispatchResult(prior); + } + /** + * Dispatch the registered body with the original caller signal fused back + * into any around-wrapper replacement. Cancellation never abandons the body: + * a started promise reaches quiescence before its outcome becomes `ABORTED`. + */ + async dispatchToolBody(exec) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === void 0) throw new Error("tool registry scheduler invariant violated: missing cancellation state"); + const wrapperSignal = exec.signal; + const fused = fuseToolSignals(state.callerSignal, wrapperSignal); + const signal = fused.signal; + if (isAborted(signal)) { + fused.dispose(); + return toolAbortedBeforeDispatchResult(); + } + exec.signal = signal; + try { + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== void 0); + if (!tool) throw new ToolNotFoundError(exec.name); + state.bodyInvoked = true; + const returned = await tool.execute(exec.arguments, exec); + const result = this.createSuccessResult(exec, tool, returned); + return isAborted(signal) ? toolAbortedResult(result) : result; + } catch (error) { + return toolErrorResult(error); + } finally { + fused.dispose(); + exec.signal = wrapperSignal; + } + } + /** + * Run around-dispatch and the tool body. Tool and unknown-tool failures still + * receive post-execute; pipeline failures are already final. + * @param exec - the prepared execution. + * @returns whether the result still needs post-execute. + * @internal + */ + async dispatchScheduledExecution(exec) { + try { + const mutableExec = exec; + const carrier = scopeTarget(this, exec.agent); + const result = await this.ctx.waterfall(carrier, "tools/execute", mutableExec, () => this.dispatchToolBody(mutableExec)); + const normalized = this.normalizeDispatchResult(exec, result); + const deferredContexts = this.deferredContexts.get(exec); + /* v8 ignore next -- dispatch only receives executions minted by this registry's prepare stage */ + if (deferredContexts === void 0) throw new Error("tool registry scheduler invariant violated: unprepared execution"); + const resultWithDeferredContexts = deferredContexts.length === 0 ? normalized : this.markCanonical(exec, { + ...normalized, + additionalContexts: [...deferredContexts, ...normalized.additionalContexts ?? []] + }); + return { + kind: "post-result", + result: this.callerCancelled(exec) && !resultWithDeferredContexts.isError ? this.cancellationResult(exec, resultWithDeferredContexts) : resultWithDeferredContexts + }; + } catch (error) { + return { + kind: "final-result", + result: toolErrorResult(error) + }; + } + } + /** + * Run ordered post-execute, then apply definition-owned content finalization, + * materialize, and notify the final outcome. + * @param exec - the prepared execution. + * @param result - dispatch/pre result that still needs post-execute. + * @returns the materialized final result. + * @internal + */ + async finalizeScheduledExecution(exec, result) { + try { + const postResult = await this.postExecute(exec, result); + return this.finishScheduledExecution(exec, this.callerCancelled(exec) && !postResult.isError ? this.cancellationResult(exec, postResult) : postResult); + } catch (error) { + return this.finishScheduledExecution(exec, toolErrorResult(error)); + } + } + /** + * Materialize the candidate, apply definition-owned content finalization, + * then materialize and notify the authoritative result. + * @param exec - the prepared execution. + * @param result - final result. + * @returns the materialized final result. + * @internal + */ + finishScheduledExecution(exec, result) { + let materializedResult; + try { + materializedResult = this.materializeFinalResult(result); + } catch (error) { + materializedResult = this.materializeFinalResult(toolErrorResult(error)); + } + let finalResult; + try { + finalResult = this.materializeFinalResult(this.applyFinalContent(exec, materializedResult)); + } catch (error) { + finalResult = this.materializeFinalResult(toolErrorResult(error)); + } + this.notifyResult(exec, finalResult); + return finalResult; + } + /** Apply the snapshotted tool-owned content transform without exposing other result fields. */ + applyFinalContent(exec, result) { + const finalizeContent = this.contentFinalizers.get(exec); + if (finalizeContent === void 0) return result; + const content = finalizeContent(exec, result); + return content === void 0 ? result : { + ...result, + content + }; + } + /** Notify observers without exposing a mutation or error channel into the outcome. */ + notifyResult(exec, result) { + Object.freeze(exec); + const { name: toolName, callId } = exec; + const reportFailure = (error) => { + this.ctx.logger.warn(`tool "${toolName}" (${callId}): tools/result observer failed: ${errorMessage(error)}`); + }; + const callbacks = this.ctx.events.dispatch("emit", [ + scopeTarget(this, exec.agent), + "tools/result", + exec, + result + ]); + for (const callback of callbacks) try { + const returned = callback(exec, result); + Promise.resolve(returned).catch(reportFailure); + } catch (error) { + reportFailure(error); + } + } + /** + * Resolve an `ask` decision to allow/deny through the approval seam. The + * seam is consumed opportunistically with `ctx.get('approval')` — a + * deployment that composes no ApprovalService keeps the historical degrade + * to deny, and an unmount mid-session degrades the same way on the next ask. + * An agent-less execution also degrades: without an agent there is no + * session to audit to and no UI to route to. Otherwise the outcome maps + * one-to-one — `allowed-once` proceeds; the three non-grants deny with + * distinct reasons so the model can tell a human "no" from an absent + * approval channel. + */ + async serviceAsk(exec, ask) { + const approval = this.ctx.get("approval"); + if (approval === void 0) return { + decision: { + kind: "deny", + reason: ask.reason ?? `tool "${exec.name}" requires approval (not yet supported)` + }, + approvalCancelled: false + }; + if (exec.agent === void 0) return { + decision: { + kind: "deny", + reason: `tool "${exec.name}" requires approval, but the call has no agent to route it through` + }, + approvalCancelled: false + }; + const outcome = await approval.request({ + agent: exec.agent, + toolName: exec.name, + callId: exec.callId, + ...ask.reason !== void 0 ? { reason: ask.reason } : {}, + signal: exec.signal + }); + switch (outcome) { + case "allowed-once": return { + decision: { kind: "allow" }, + approvalCancelled: false + }; + case "rejected": return { + decision: { + kind: "deny", + reason: `the user rejected tool "${exec.name}"` + }, + approvalCancelled: false + }; + case "cancelled": return { + decision: { + kind: "deny", + reason: `approval for tool "${exec.name}" was cancelled` + }, + approvalCancelled: true + }; + case "unavailable": return { + decision: { + kind: "deny", + reason: `tool "${exec.name}" requires approval, but no approval channel is available` + }, + approvalCancelled: false + }; + default: return assertNever(outcome, "ApprovalOutcome"); + } + } + /** + * Run the `tools/post-execute` waterfall over a dispatched `result` and apply + * its {@link PostToolDecision}: `accept` keeps the call successful (replacing + * `content` when given), `block` turns it into an `isError` whose content is + * the corrective `feedback`. Either decision may attach `additionalContexts`, + * which are ferried on the returned result for the loop's active-batch FIFO. + * Context deferred by the tool body survives an accepted result but is + * discarded when the outer call is blocked; a block exposes only context the + * blocking decision explicitly supplied. + * Runs inside `execute`'s outer try/catch (a throwing listener → isError). + */ + async postExecute(exec, result) { + const decision = await this.ctx.waterfall(scopeTarget(this, exec.agent), "tools/post-execute", exec, result, () => Promise.resolve({ kind: "accept" })); + const decisionContexts = decision.additionalContexts ?? []; + if (decision.kind === "block") { + const message = failureMessageFromContent(decision.feedback); + return this.markCanonical(exec, { + content: decision.feedback, + isError: true, + error: { message }, + ...decisionContexts.length > 0 ? { additionalContexts: decisionContexts } : {} + }); + } + if (Object.hasOwn(decision, "content") && Object.hasOwn(decision, "value")) throw new TypeError("tools/post-execute accept decision cannot replace both value and content"); + const additionalContexts = [...result.additionalContexts ?? [], ...decisionContexts]; + if (Object.hasOwn(decision, "value")) { + if (result.isError) throw new TypeError("tools/post-execute cannot replace the value of a failed result"); + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== void 0); + if (tool === void 0) throw new ToolNotFoundError(exec.name); + const replaced = this.createSuccessResult(exec, tool, decision.value); + return this.markCanonical(exec, { + ...replaced, + ...additionalContexts.length > 0 ? { additionalContexts } : {} + }); + } + return this.markCanonical(exec, { + ...result, + ...decision.content !== void 0 ? { content: decision.content } : {}, + ...additionalContexts.length > 0 ? { additionalContexts } : {} + }); + } + /** Registry-normalized results and the exact dispatch that validated each value. */ + canonicalResults = /* @__PURE__ */ new WeakMap(); + /** Mark one registry-normalized result as canonical only for its owning dispatch. */ + markCanonical(exec, result) { + this.canonicalResults.set(result, exec.token); + return result; + } + /** Snapshot, validate, render, and optionally project one successful body value. */ + createSuccessResult(exec, tool, candidate) { + const detached = snapshotToolValue(tool.name, candidate); + const violations = validateJsonSchemaValue(tool.output.schema, detached, "value"); + if (violations.length > 0) throw new ToolOutputError(tool.name, violations); + const value = deepFreeze(detached); + let rendered; + try { + rendered = tool.output.render(exec.arguments, value); + } catch (error) { + throw projectionError(tool.name, "render", error); + } + const content = snapshotProjection(tool.name, "render", rendered); + let meta; + if (exec.parent === void 0 && tool.output.presentationMeta !== void 0) { + let projected; + try { + projected = tool.output.presentationMeta(exec.arguments, value); + } catch (error) { + throw projectionError(tool.name, "presentationMeta", error); + } + meta = snapshotProjection(tool.name, "presentationMeta", projected); + } + const concludesTurn = this.concludingExecutions.has(exec); + return this.markCanonical(exec, this.materializeFinalResult({ + isError: false, + value, + content, + ...meta !== void 0 ? { meta } : {}, + ...concludesTurn ? { concludesTurn: true } : {} + })); + } + /** Normalize an around-dispatch wrapper's authored result through the owning output contract. */ + normalizeDispatchResult(exec, result) { + if (this.canonicalResults.get(result) === exec.token) return result; + if (result.isError) return this.markCanonical(exec, { + isError: true, + error: result.error, + content: result.content, + ...result.meta !== void 0 ? { meta: result.meta } : {}, + ...result.additionalContexts !== void 0 ? { additionalContexts: result.additionalContexts } : {} + }); + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== void 0); + if (tool === void 0) throw new ToolNotFoundError(exec.name); + const normalized = this.createSuccessResult(exec, tool, result.value); + return this.markCanonical(exec, { + ...normalized, + ...result.additionalContexts !== void 0 ? { additionalContexts: result.additionalContexts } : {} + }); + } + /** Materialize the authoritative commit outcome once, immediately before `tools/result`. */ + materializeFinalResult(result) { + const presentation = { + content: result.content, + ...result.meta !== void 0 ? { meta: result.meta } : {}, + ...result.additionalContexts !== void 0 ? { additionalContexts: result.additionalContexts } : {} + }; + if (result.isError) return materializePresentation({ + isError: true, + error: result.error, + ...presentation + }); + return deepFreeze({ + ...materializePresentation({ + isError: false, + ...presentation, + ...result.concludesTurn === true ? { concludesTurn: true } : {} + }), + value: result.value + }); + } +}; +/** Mint a same-process correlation token whose identity is its value. */ +function createExecutionToken() { + return Symbol("dsh.tool.execution"); +} +function toolErrorResult(error) { + const info = errorInfo(error); + const message = errorMessage(error); + return { + content: [{ + type: "text", + text: `Error: ${message}` + }], + isError: true, + error: { + message, + ...info ? { info } : {} + } + }; +} +/** Read live abort state across an await without treating it as synchronously immutable. */ +function isAborted(signal) { + return signal.aborted; +} +/** +* Fuse caller and wrapper cancellation without nesting `AbortSignal.any`. +* Keeping the relay dispatch-scoped also removes listeners when work settles. +*/ +function fuseToolSignals(caller, wrapper) { + if (caller === wrapper) return { + signal: caller, + dispose() {} + }; + const controller = new AbortController(); + let listening = false; + const dispose = () => { + if (!listening) return; + listening = false; + caller.removeEventListener("abort", abortFromCaller); + wrapper.removeEventListener("abort", abortFromWrapper); + }; + const abortFrom = (source) => { + const reason = source.reason; + controller.abort(reason); + dispose(); + }; + const abortFromCaller = () => { + abortFrom(caller); + }; + const abortFromWrapper = () => { + abortFrom(wrapper); + }; + if (wrapper.aborted) abortFromWrapper(); + else if (caller.aborted) abortFromCaller(); + else { + listening = true; + caller.addEventListener("abort", abortFromCaller, { once: true }); + wrapper.addEventListener("abort", abortFromWrapper, { once: true }); + } + return { + signal: controller.signal, + dispose + }; +} +/** Canonical result when cancellation supersedes success after body invocation. */ +function toolAbortedResult(prior) { + const additionalContexts = prior?.additionalContexts ?? []; + return { + content: [{ + type: "text", + text: "Error: tool call aborted" + }], + isError: true, + error: { + message: "tool call aborted", + info: { + name: "AbortError", + code: TOOL_ABORTED + } + }, + ...additionalContexts.length > 0 ? { additionalContexts } : {} + }; +} +/** Canonical result when cancellation prevents tool body invocation. */ +function toolAbortedBeforeDispatchResult(prior) { + const additionalContexts = prior?.additionalContexts ?? []; + return { + content: [{ + type: "text", + text: "Error: tool call aborted before dispatch" + }], + isError: true, + error: { + message: "tool call aborted before dispatch", + info: { + name: "AbortError", + code: TOOL_ABORTED_BEFORE_DISPATCH + } + }, + ...additionalContexts.length > 0 ? { additionalContexts } : {} + }; +} +//#endregion +export { CodeRunFailedError, JsonSchemaError, RUN_CODE_NAME, TOOL_ABORTED, TOOL_ABORTED_BEFORE_DISPATCH, TOOL_RUNTIME_SCHEDULER, ToolArgsError, ToolNotFoundError, ToolOutputError, ToolRuntime, ToolRuntime as default, assertObjectJsonSchema, assertSupportedJsonSchema, defineContentToolFixture, defineTool, jsonSchemaToPy, jsonSchemaToTs, parameterSchemaSpecToJsonSchema, renderToolsSdk, renderToolsSdkPy, validateArgs, validateJsonSchemaValue, valueSchemaSpecToJsonSchema }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/invariant.js new file mode 100644 index 0000000..98bc0fa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/invariant.js @@ -0,0 +1,100 @@ +//#region lib/types/invariant.js +/** Package-owned tool-pipeline invariants. @module @deepseek-ai/dsh-tools/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-tools"; +/** Cordis companion plugin name. */ +const name = "tools-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Validate the immutable final execution/result snapshot. */ +function validateResult(exec, result, fail) { + if (!Object.isFrozen(exec)) fail("tools/result execution must be frozen before publication"); + if (!Object.isFrozen(result) || !Object.isFrozen(result.content)) fail("tools/result outcome and content must be frozen before publication"); + if (exec.name.length === 0 || String(exec.callId).length === 0) fail("tools/result execution must carry non-empty name and callId"); +} +/** Install monotonic pipeline, final-snapshot, and code-dispatch enclosure checks. */ +const install = Object.assign((ctx, fail) => { + const stages = /* @__PURE__ */ new WeakMap(); + const openTurns = /* @__PURE__ */ new WeakMap(); + const dispatchRoots = /* @__PURE__ */ new WeakMap(); + const validateDispatch = (session, event) => { + if (event.type !== "tool/code-dispatch-start" && event.type !== "tool/code-dispatch") return; + const root = String(event.data.rootCallId); + const parent = String(event.data.parentCallId); + const child = String(event.data.subCallId); + if (root.length === 0 || parent.length === 0 || child.length === 0) { + fail(`${event.type} must carry non-empty rootCallId, parentCallId, and subCallId`); + return; + } + const roots = dispatchRoots.get(session); + const known = roots?.get(child); + if (known !== void 0 && known !== root) fail(`${event.type} changed rootCallId for subCallId ${child}`); + if (parent !== root && roots?.get(parent) !== root) fail(`${event.type} parentCallId ${parent} does not belong to rootCallId ${root}`); + }; + const commitDispatch = (session, event) => { + if (event.type !== "tool/code-dispatch-start" && event.type !== "tool/code-dispatch") return; + dispatchRoots.get(session).set(String(event.data.subCallId), String(event.data.rootCallId)); + }; + const seed = (session) => { + let openTurn = null; + dispatchRoots.set(session, /* @__PURE__ */ new Map()); + for (const event of session.events) { + validateDispatch(session, event); + commitDispatch(session, event); + if (event.type === "turn/start") openTurn = event.data.turn; + else if (event.type === "turn/end") openTurn = null; + else if ((event.type === "tool/code-dispatch-start" || event.type === "tool/code-dispatch") && openTurn === null) fail(`${event.type} appended outside any open turn`); + } + openTurns.set(session, openTurn); + return openTurn; + }; + const openTurnFor = (session) => openTurns.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) seed(session); + ctx.on("session/created", (session) => { + seed(session); + }, { global: true }); + ctx.on("session/event", (session, event) => { + validateDispatch(session, event); + commitDispatch(session, event); + if (event.type === "turn/start") openTurns.set(session, event.data.turn); + else if (event.type === "turn/end") openTurns.set(session, null); + }, { global: true }); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName === "session/event") { + const [session, event] = args; + validateDispatch(session, event); + if ((event.type === "tool/code-dispatch-start" || event.type === "tool/code-dispatch") && openTurnFor(session) === null) fail(`${event.type} appended outside any open turn`); + return; + } + if (eventName === "tools/pre-execute") { + const exec = args[0]; + if (stages.has(exec)) fail("tools/pre-execute repeated for one execution"); + stages.set(exec, "pre"); + return; + } + if (eventName === "tools/execute") { + const exec = args[0]; + if (stages.get(exec) !== "pre") fail("tools/execute must follow tools/pre-execute"); + stages.set(exec, "execute"); + return; + } + if (eventName === "tools/post-execute") { + const exec = args[0]; + const previous = stages.get(exec); + if (previous !== "pre" && previous !== "execute") fail("tools/post-execute must follow tools/pre-execute or tools/execute"); + stages.set(exec, "post"); + return; + } + if (eventName !== "tools/result") return; + const [exec, result] = args; + validateResult(exec, result, fail); + stages.delete(exec); + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register the tools invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.d.ts new file mode 100644 index 0000000..b995376 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.d.ts @@ -0,0 +1,68 @@ +/** + * Code Mode `run_code` transport. Programs call the registry's agent-visible + * tools through nested executions scheduled under the native concurrency + * contract; each sub-dispatch is logged for reconstruction, while only the + * outer curated result enters model history. + * @module @deepseek-ai/dsh-tools/src/code-mode + */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { CodeRuntime } from '@deepseek-ai/dsh-code-runtime'; +import type { CodeDispatchLog, ToolDefinition, ToolRuntime } from './index.ts'; +/** The model-facing name of the Code Mode tool. */ +export declare const RUN_CODE_NAME = "run_code"; +/** The `tools:sdk` section order: inside the 100–199 tool-guidance band, after per-tool guidance sections. */ +export declare const SDK_SECTION_ORDER = 150; +/** + * The languages Code Mode ships a presentation for. Both per-language tables — + * {@link RUN_CODE_FLAVORS} here and `SDK_RENDERERS` in {@link ./index.ts} — are + * checked against this union with `satisfies`, so a language added to one and + * not the other fails `typecheck` instead of waiting for a runtime that reports + * it. The tables stay declared `Record` because `CodeRuntime.language` + * is an unconstrained `string`: this union pins what the harness ships, while the + * `Object.hasOwn` guards reject what a mounted runtime may report. + */ +export type CodeSdkLanguage = 'typescript' | 'python'; +/** + * Thrown by `run_code` when the program run itself failed — a program + * exception, a budget expiry, an abort, or substrate death. Extends + * {@link HarnessError} (`code: 'CODE_RUN_FAILED'`); the registry's execution + * pipeline converts it into a structured `isError` result whose text carries + * the failure kind plus the captured logs, so the model can self-correct. + */ +export declare class CodeRunFailedError extends HarnessError { + constructor(message: string); +} +/** + * Registry-private capabilities the bridge receives at construction — the + * `requireRuntime` idiom: operations only the owning registry can mint stay + * off its public service API and flow here as closures instead. + */ +export interface RunCodeBridgeOptions { + /** Resolves `ctx.codeRuntime` or throws the loud misconfiguration error (shared with the registry's assembly-time checks). */ + requireRuntime: () => CodeRuntime; + /** + * Reads `ctx.codeRuntime` without throwing: `undefined` when none is mounted. + * Lets schema emission tell "no runtime" (degrade to TS; the readers that + * reach it are {@link resolveFlavor}'s) apart from "unknown language" (fail + * loud). + */ + peekRuntime: () => CodeRuntime | undefined; + /** The run's overlap cap for parallel-classified sub-calls (the registry passes its validated `maxParallelSubCalls`). */ + maxParallel: number; + /** Runs the contained `tools/code-dispatch-log` waterfall over one settled sub-dispatch (the registry's private invoker). */ + shapeDispatchLog: (dispatch: CodeDispatchLog) => Promise; +} +/** + * Build the `run_code` {@link ToolDefinition}: required `code` and + * `description` parameters, executed through the dispatch bridge described + * above. The + * registry reserves it as presentation infrastructure under non-native modes, + * outside the filterable global/scoped capability layers. + * @param registry - the owning registry (sub-calls go through its `execute`, + * bindings cover its registered tools). + * @param options - the registry-private capabilities described above. + * @returns the registry-ready definition. + */ +export declare function createRunCodeTool(registry: ToolRuntime, options: RunCodeBridgeOptions): ToolDefinition; +//# sourceMappingURL=code-mode.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.js new file mode 100644 index 0000000..b3f428d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.js @@ -0,0 +1,572 @@ +/** + * Code Mode `run_code` transport. Programs call the registry's agent-visible + * tools through nested executions scheduled under the native concurrency + * contract; each sub-dispatch is logged for reconstruction, while only the + * outer curated result enters model history. + * @module @deepseek-ai/dsh-tools/src/code-mode + */ +import { CallId, HarnessError } from '@deepseek-ai/dsh-llm'; +import { snapshotJsonValue } from '@deepseek-ai/dsh-session'; +import { defineTool, parameterSchemaSpecToJsonSchema } from "./schema.js"; +import { TOOL_RUNTIME_SCHEDULER } from "./index.js"; +/** The model-facing name of the Code Mode tool. */ +export const RUN_CODE_NAME = 'run_code'; +/** The `tools:sdk` section order: inside the 100–199 tool-guidance band, after per-tool guidance sections. */ +export const SDK_SECTION_ORDER = 150; +/** + * The TypeScript flavor: the fallback for a schema read with no runtime + * mounted ({@link resolveFlavor} owns which readers reach that). A real + * assembly always resolves a runtime first, so the model never sees this + * fallback outside its own language. + */ +const TYPESCRIPT_FLAVOR = { + description: 'Execute a TypeScript program against the available tools. Takes two required ' + + 'arguments: `code`, the BODY of an async function (erasable syntax only; top-level ' + + '`await` and `return` work), and `description`, a short summary of what the program ' + + 'does. Call tools as `await tools.name(args)` per the declarations in the system ' + + 'prompt. Only what you print or return comes back — curate it.', + codeDescription: 'The program: the body of an async TypeScript function.', +}; +/** + * The Python flavor: the body of an async function, top-level `await` and + * `return`, answer via `print` and/or the returned value, matching + * {@link ./py-types.ts}'s SDK instructions. + */ +const PYTHON_FLAVOR = { + description: 'Execute a Python program against the available tools. Takes two required ' + + 'arguments: `code`, the BODY of an async function (top-level `await` and `return` ' + + 'work), and `description`, a short summary of what the program does. Call tools as ' + + '`await tools.name(args)` per the declarations in the system prompt. Answer ' + + 'with `print(...)` and/or `return ` — only that comes back, so curate it.', + codeDescription: 'The program: the body of an async Python function.', +}; +/** Per-language `run_code` schema flavors (see {@link RunCodeFlavor}); one entry per {@link CodeSdkLanguage}. */ +const RUN_CODE_FLAVORS = { + typescript: TYPESCRIPT_FLAVOR, + python: PYTHON_FLAVOR, +}; +/** + * The `description` parameter's model-facing description: language-independent + * (the UI label contract is the same for every runtime), shared between the + * static spec and the language-aware `parameters` getter so the two emissions + * can never drift. + */ +const RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION = 'Clear, concise description of what this program does in active voice, ' + + '5-10 words (shown in the UI). Examples: "Count TODO markers across packages"; ' + + '"Read failing test and its fixture"; "Rename config key in every cordis.yml".'; +/** + * Resolve the {@link RunCodeFlavor} for the loaded runtime's language, read at + * schema-emission time so the model-visible `run_code` schema always matches + * the SDK section's language. `peekRuntime` returns `undefined` only when no + * runtime is mounted, which reaches this function through definition readers + * and `schemas()` — the doc-catalog harvest is the only shipped one, and none + * of them feeds a model, because `wireSchemas` calls `requireCodeRuntime` + * before projecting — so that path degrades to {@link TYPESCRIPT_FLAVOR}. A + * mounted runtime whose language has no flavor entry fails loud, exactly as + * `requireCodeRuntime` rejects it at assembly. Keeping this table in step with + * `SDK_RENDERERS` is the compiler's job ({@link CodeSdkLanguage}); what this + * guard owns is the runtime-supplied language neither table knows, which never + * yields a wrong-language schema for a real runtime. + */ +function resolveFlavor(peekRuntime) { + const runtime = peekRuntime(); + if (runtime === undefined) { + // No runtime mounted: reached by definition readers and `schemas()`, of + // which the doc-catalog harvest is the only shipped one. None feeds a + // model — `wireSchemas` calls `requireCodeRuntime` before projecting, so + // the assembly path never arrives here. Degrade to the TS default. + return TYPESCRIPT_FLAVOR; + } + // Own-property read: a language like `toString`/`constructor` would otherwise + // resolve an inherited Object.prototype member as a flavor. + const flavor = RUN_CODE_FLAVORS[runtime.language]; + if (!Object.hasOwn(RUN_CODE_FLAVORS, runtime.language) || flavor === undefined) { + const known = Object.keys(RUN_CODE_FLAVORS).map(name => JSON.stringify(name)).join(', '); + throw new Error(`dsh-tools: no run_code schema flavor registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`); + } + return flavor; +} +/** + * Thrown by `run_code` when the program run itself failed — a program + * exception, a budget expiry, an abort, or substrate death. Extends + * {@link HarnessError} (`code: 'CODE_RUN_FAILED'`); the registry's execution + * pipeline converts it into a structured `isError` result whose text carries + * the failure kind plus the captured logs, so the model can self-correct. + */ +export class CodeRunFailedError extends HarnessError { + constructor(message) { + super(message, 'CODE_RUN_FAILED'); + this.name = 'CodeRunFailedError'; + } +} +/** + * Snapshot one binding call's argument as lossless JSON, then snapshot that + * detached value again so dispatch and logging stay independent without + * reintroducing structured-clone's platform-specific nesting limit. + */ +function jsonNormalizeArgs(value) { + let snapshot; + try { + snapshot = snapshotJsonValue(value); + } + catch (error) { + throw new Error(`tool arguments must be lossless JSON: ${error instanceof Error ? error.message : String(error)}`); + } + if (snapshot === undefined) { + throw new Error('tool arguments must be lossless JSON (call the tool with an arguments object, e.g. `{}`)'); + } + const logged = snapshotJsonValue(snapshot); + /* v8 ignore next -- snapshot is already a detached lossless JSON value. */ + if (logged === undefined) { + throw new Error('tool arguments could not be detached for durable logging'); + } + return { dispatched: snapshot, logged }; +} +/** Two-space JSON presentation, matching the existing shallow `run_code` text contract. */ +const JSON_INDENT = ' '; +/** + * ECMAScript caps `JSON.stringify`'s `space` string at ten characters. The + * renderer also caps TOTAL indentation there, compacting deeper subtrees, so + * formatted output remains linear in the canonical JSON size. + */ +const MAX_JSON_INDENT_CHARS = 10; +/** Render one non-string JSON root without recursive traversal or unbounded indentation growth. */ +function renderJsonValue(value) { + const chunks = []; + const tasks = [{ kind: 'value', value, depth: 0, compact: false }]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'text') { + chunks.push(task.text); + continue; + } + const current = task.value; + if (current === null || typeof current === 'boolean' || typeof current === 'number') { + chunks.push(String(current)); + continue; + } + if (typeof current === 'string') { + chunks.push(JSON.stringify(current)); + continue; + } + const compact = task.compact || (task.depth + 1) * JSON_INDENT.length > MAX_JSON_INDENT_CHARS; + const childDepth = task.depth + 1; + if (Array.isArray(current)) { + chunks.push('['); + if (current.length === 0) { + chunks.push(']'); + continue; + } + tasks.push({ kind: 'text', text: compact ? ']' : `\n${JSON_INDENT.repeat(task.depth)}]` }); + for (let index = current.length - 1; index >= 0; index--) { + const item = current[index]; + /* v8 ignore next -- canonical JsonValue arrays are dense. */ + if (item === undefined) + throw new Error('cannot render a sparse JSON array'); + tasks.push({ kind: 'value', value: item, depth: childDepth, compact }); + tasks.push({ + kind: 'text', + text: compact + ? index === 0 ? '' : ',' + : `${index === 0 ? '\n' : ',\n'}${JSON_INDENT.repeat(childDepth)}`, + }); + } + continue; + } + const keys = Object.keys(current); + chunks.push('{'); + if (keys.length === 0) { + chunks.push('}'); + continue; + } + tasks.push({ kind: 'text', text: compact ? '}' : `\n${JSON_INDENT.repeat(task.depth)}}` }); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) + throw new Error('cannot render a missing JSON object key'); + const item = current[key]; + /* v8 ignore next -- canonical JsonValue records contain no undefined properties. */ + if (item === undefined) + throw new Error('cannot render an undefined JSON object property'); + tasks.push({ kind: 'value', value: item, depth: childDepth, compact }); + tasks.push({ + kind: 'text', + text: compact + ? `${index === 0 ? '' : ','}${JSON.stringify(key)}:` + : `${index === 0 ? '\n' : ',\n'}${JSON_INDENT.repeat(childDepth)}${JSON.stringify(key)}: `, + }); + } + } + return chunks.join(''); +} +/** Render one present program completion value for the model-facing result text. */ +function renderValue(value) { + return typeof value === 'string' ? value : renderJsonValue(value); +} +/** + * Build the `run_code` {@link ToolDefinition}: required `code` and + * `description` parameters, executed through the dispatch bridge described + * above. The + * registry reserves it as presentation infrastructure under non-native modes, + * outside the filterable global/scoped capability layers. + * @param registry - the owning registry (sub-calls go through its `execute`, + * bindings cover its registered tools). + * @param options - the registry-private capabilities described above. + * @returns the registry-ready definition. + */ +export function createRunCodeTool(registry, options) { + const { requireRuntime, peekRuntime, maxParallel, shapeDispatchLog } = options; + const definition = defineTool({ + name: RUN_CODE_NAME, + // The description and `code` parameter description are placeholders here: + // the language-aware getters installed below replace both, resolving the + // loaded runtime's flavor at schema-emission time so the schema the MODEL + // sees matches the SDK section's language. Argument VALIDATION still keys + // off this static spec (defineTool closes over it), which is language- + // independent (one required string `code`). + description: TYPESCRIPT_FLAVOR.description, + parameters: { + code: { type: 'string', required: true, description: TYPESCRIPT_FLAVOR.codeDescription }, + description: { + type: 'string', + required: true, + description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION, + }, + }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + logs: { type: 'array', required: true, items: { type: 'string' } }, + result: { type: 'json' }, + }, + }, + render: (_args, value) => { + const rendered = value.result === undefined ? '' : renderValue(value.result); + const parts = [value.logs.join('\n'), rendered].filter(part => part.length > 0); + return [{ type: 'text', text: parts.length > 0 ? parts.join('\n') : '(run_code completed with no output)' }]; + }, + }, + async execute(args, exec) { + if (args.description.trim().length === 0) { + throw new Error('invalid description: expected a non-empty string'); + } + const runtime = requireRuntime(); + // The run-scoped abort: follows the outer signal in, and fires when the + // run settles for ANY reason, so an in-flight sub-dispatch is aborted + // (its executor kills on this signal) instead of orphaned, and + // queued-unstarted dispatches are abandoned. + const runController = new AbortController(); + const onOuterAbort = () => { runController.abort(exec.signal.reason); }; + exec.signal.addEventListener('abort', onOuterAbort, { once: true }); + let dispatches = 0; + const pendingQueue = []; + const inFlight = new Set(); + /** Tracked settle-event side work (log-content listener + append), drained at run settlement. */ + const logWork = new Set(); + const commitQueue = []; + let exclusiveActive = false; + let driving = false; + let driverRun = Promise.resolve(); + let wake; + const wakeup = () => { + const release = wake; + wake = undefined; + release?.(); + }; + /** + * The single ordered lane. Each pass commits the head-of-line settled + * dispatch (ordered post-execute), then starts the next queued entry if + * its slot is free (ordered pre-execute), and otherwise sleeps until a + * body settles or a new submission arrives. One run reaching the + * empty-queues/empty-pool state is quiescence. + */ + const drive = () => { + if (driving) + return driverRun; + driving = true; + driverRun = (async () => { + try { + for (;;) { + // Create the wakeup promise before inspecting state so a settle or submission arriving + // between the checks and the await below cannot be lost. + const signal = new Promise((resolve) => { wake = resolve; }); + const commitHead = commitQueue[0]; + if (commitHead !== undefined && commitHead.settled) { + commitQueue.shift(); + await commitHead.commit(); + // The barrier covers post-execute: later starts wait for the + // exclusive call's full pipeline, as under the native loop. + if (commitHead.mode === 'exclusive') + exclusiveActive = false; + continue; + } + const head = pendingQueue[0]; + if (head !== undefined) { + if (runController.signal.aborted) { + pendingQueue.shift(); + head.abandon(); + continue; + } + // Reclassify at start time (fail-closed on registry changes). + const mode = head.classify(); + const capacity = !exclusiveActive + && (mode === 'exclusive' ? inFlight.size === 0 : inFlight.size < maxParallel); + if (capacity) { + if (mode === 'exclusive') + exclusiveActive = true; + head.mode = mode; + pendingQueue.shift(); + // Joined before start() so the commit cursor sees submission + // order; nothing commits it until `settled` flips. + commitQueue.push(head); + await head.start(); + const flight = head.flight.finally(() => { + inFlight.delete(flight); + wakeup(); + }); + inFlight.add(flight); + continue; + } + } + if (pendingQueue.length === 0 && commitQueue.length === 0 && inFlight.size === 0) + return; + await signal; + } + } + finally { + driving = false; + wake = undefined; + } + })(); + return driverRun; + }; + /** Every dispatch settled AND committed; nothing can start (the run is aborted at call time). */ + const drainDispatches = async () => { + // The abort already fired: the driver abandons queued-unstarted + // entries, awaits the live pool, and drains the ordered commit lane — + // including a commit already in progress when the program returned. + await drive(); + // Every settle event is appended inside the open run_code turn + // (tasks self-remove on settlement). + while (logWork.size > 0) + await Promise.allSettled([...logWork]); + }; + // Read through a call, not a bare property: the abort state genuinely + // changes across awaits, and a direct `.aborted` re-check after one + // would be narrowed away by control flow analysis. + const runOver = () => runController.signal.aborted; + const binding = (name) => async (rawArgs) => { + if (runOver()) { + throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} not dispatched`); + } + const normalized = jsonNormalizeArgs(rawArgs); + const n = ++dispatches; + const subCallId = CallId(`${String(exec.callId)}:code:${n}`); + const input = { + callId: subCallId, + rootCallId: exec.rootCallId, + name, + arguments: normalized.dispatched, + ...exec.agent ? { agent: exec.agent } : {}, + parent: exec.token, + signal: runController.signal, + }; + const scheduler = registry[TOOL_RUNTIME_SCHEDULER]; + const outcome = await new Promise((resolve, reject) => { + // Set by the dispatch stage (or start() for a pre-settled result): what commit() finalizes in submission order. + let parked; + const settle = (result) => { + // The program gets its value NOW: the log-content listener (for + // example, a spill backend) must never delay the binding or occupy + // a dispatch slot. The event append is tracked side work; the run's + // settlement drains logWork so every settle event is still appended + // inside the open turn (shapeDispatchLog is contained, so this + // chain cannot reject). + resolve(result.isError + ? { isError: true, message: result.error.message } + : { isError: false, value: result.value }); + const agent = exec.agent; + if (agent === undefined) + return; + const task = (async () => { + // The listener may replace the durable copy with a preview and + // locator; the program's value and model-visible result are + // untouched. + const logged = await shapeDispatchLog({ + exec, agent, subCallId, name, isError: result.isError, + // The registry deep-froze this projection at result + // finalization; append snapshots the final copy again, so + // the log stays detached. + content: result.content, + }); + agent.session.append('tool/code-dispatch', { + rootCallId: exec.rootCallId, + parentCallId: exec.callId, + subCallId, + name, + // The SIBLING parse of the dispatched value: byte-identical JSON, + // but a separate object — a tool mutating its args cannot desync + // this record from what it actually received. + arguments: normalized.logged, + isError: result.isError, + content: logged, + }); + })().finally(() => { logWork.delete(task); }); + logWork.add(task); + }; + pendingQueue.push({ + flight: Promise.resolve(), + settled: false, + // Re-read per driver pass against the same agent view the SDK + // declared; fail-closed exclusive when undeclared/invalid. + classify: () => registry.executionMode(input).kind, + abandon: () => { + reject(new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} tool call abandoned`)); + }, + async start() { + exec.agent?.session.append('tool/code-dispatch-start', { + rootCallId: exec.rootCallId, + parentCallId: exec.callId, + subCallId, + name, + arguments: normalized.logged, + }); + // Ordered prepare runs INSIDE the driver lane: the next entry's + // pre-execute waits for this resolution, as under the native + // scheduler. Only the launched body below overlaps. + const prepared = await scheduler.prepare(input); + if (prepared.kind === 'dispatch') { + this.flight = scheduler.dispatch(prepared.exec).then((dispatchOutcome) => { + parked = { kind: dispatchOutcome.kind, exec: prepared.exec, result: dispatchOutcome.result }; + this.settled = true; + }); + return; + } + parked = { kind: prepared.kind, exec: prepared.exec, result: prepared.result }; + this.settled = true; + }, + async commit() { + /* v8 ignore next -- commit() runs only after `settled` flipped, which set parked. */ + if (parked === undefined) + return; + const result = parked.kind === 'post-result' + ? await scheduler.finalize(parked.exec, parked.result) + : scheduler.finish(parked.exec, parked.result); + for (const context of result.additionalContexts ?? []) { + exec.deferContext(context); + } + // The composite forwards `additionalContexts` above and + // `concludesTurn` here from the nested result. Only a successful + // nested result can carry the terminal marker + // (ToolExecutionFailure types it never), so a policy-converted + // failure cannot stop the turn through a recovering program. + if (result.concludesTurn) + exec.concludeTurn(); + settle(result); + // Backpressure on pending event-append tasks: each task retains + // a full result while a slow backend stores it, so the pool cap + // bounds their count. Beyond the cap, the + // ordered lane waits, so later sub-calls cannot start and + // pending I/O/memory cannot grow without bound. + while (logWork.size > maxParallel) + await Promise.race(logWork); + }, + }); + wakeup(); + void drive(); + }); + // A budget expiry or outer cancel that occurs while this call was in + // flight already aborted the dispatch; stop the program now rather + // than hand it a result from a run that is over. + if (runOver()) { + throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} result discarded`); + } + // The worker turns a binding rejection into ToolCallError and adds + // only the binding name. Native content and internal error metadata + // stay outside the program-facing failure contract. + if (outcome.isError) + throw new Error(outcome.message); + return outcome.value; + }; + // Null-prototype + defineProperty, mirroring the worker-side namespace + // build: a registered tool named `__proto__` must become an ordinary + // own key (a plain-object assignment would hit the prototype setter, + // silently dropping the binding), and the runtime host resolves + // binding names as own properties only. + const functions = Object.create(null); + // Enumerate the CALLING AGENT's visible set (scoped tools join, + // restricted globals vanish) — the same view the SDK section declared, + // so a program can bind exactly what its prompt promised; sub-dispatch + // re-resolves per call through the same view (exec.agent threads down). + for (const schema of registry.schemas(exec.agent)) { + if (schema.name === RUN_CODE_NAME) + continue; + Object.defineProperty(functions, schema.name, { enumerable: true, value: binding(schema.name) }); + } + try { + let result; + try { + result = await runtime.run({ + program: args.code, + bindings: [{ + global: 'tools', + functions, + errorClass: { name: 'ToolCallError', memberNameProperty: 'toolName' }, + }], + signal: runController.signal, + }); + } + finally { + // Abort sub-dispatches and drain every in-flight dispatch before + // closing the turn (queued-unstarted ones are abandoned unlogged). + // Binding failures remain observable through their individual promises. + runController.abort('run_code settled'); + await drainDispatches(); + } + if (result.error) { + const logsText = result.logs.length > 0 ? `\nCaptured output:\n${result.logs.join('\n')}` : ''; + throw new CodeRunFailedError(`code run failed (${result.error.kind}): ${result.error.message}${logsText}`); + } + return { + logs: result.logs, + ...result.value !== undefined ? { result: result.value } : {}, + }; + } + finally { + exec.signal.removeEventListener('abort', onOuterAbort); + } + }, + // The model-authored description is the call's always-visible UI label + // (the bash `description` precedent); the program itself rides rawInput. + presentCall: args => ({ + card: 'generic', + title: args.description, + kind: 'execute', + rawInput: args.code, + }), + // Deliberately no presentResult: the generic card fallback keeps this + // title and reads durable result content without duplicating a large raw + // result into the host view payload. + }); + // Resolve the language flavor lazily, at the moment the registry projects the + // schema (`schemaOf` destructures `description`/`parameters`). The definition + // is minted once at registration, before a runtime is known; deferring here + // is the least invasive point that still emits the loaded runtime's language. + Object.defineProperty(definition, 'description', { + enumerable: true, + get: () => resolveFlavor(peekRuntime).description, + }); + Object.defineProperty(definition, 'parameters', { + enumerable: true, + // Recompile through the same spec→schema projection defineTool used, so + // the emitted schema always matches the validated specification. + get: () => parameterSchemaSpecToJsonSchema({ + code: { type: 'string', required: true, description: resolveFlavor(peekRuntime).codeDescription }, + description: { type: 'string', required: true, description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION }, + }), + }); + return definition; +} +//# sourceMappingURL=code-mode.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/index.d.ts new file mode 100644 index 0000000..810014d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/index.d.ts @@ -0,0 +1,819 @@ +/** + * Tool registry, model presentation modes, and pre/guard/around/post/result + * execution pipeline. + * @module @deepseek-ai/dsh-tools + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { ScopeKey, Scoped } from '@deepseek-ai/dsh-scope'; +import type { CallId, ContentBlock, ToolSchema } from '@deepseek-ai/dsh-llm'; +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { JsonValue, UserMessage } from '@deepseek-ai/dsh-session'; +import type { ToolCallView, ToolResultView } from './presentation.ts'; +import type { JsonSchemaNode } from './json-schema.ts'; +export { defineTool, valueSchemaSpecToJsonSchema, parameterSchemaSpecToJsonSchema, validateArgs, ToolArgsError, type ValueSchemaAnnotations, type StringValueSchemaSpec, type NumberValueSchemaSpec, type IntegerValueSchemaSpec, type BooleanValueSchemaSpec, type NullValueSchemaSpec, type ArrayValueSchemaSpec, type ObjectValueSchemaSpec, type JsonValueSchemaSpec, type OneOfValueSchemaSpec, type ValueSchemaSpec, type ParameterPropertySpec, type ParameterSchemaSpec, type ParameterJsonSchema, type InferValue, type InferArgs, type DefineToolOptions, } from './schema.ts'; +export { assertSupportedJsonSchema, assertObjectJsonSchema, validateJsonSchemaValue, JsonSchemaError, type JsonSchemaNode, type ObjectJsonSchema, type JsonSchemaType, type JsonSchemaScalar, } from './json-schema.ts'; +export type { JsonValue } from '@deepseek-ai/dsh-session'; +export type { CodeDispatchEventData, CodeDispatchStartEventData } from './types.ts'; +export { CodeRunFailedError, RUN_CODE_NAME } from './code-mode.ts'; +export { jsonSchemaToTs, renderToolsSdk } from './ts-types.ts'; +export { jsonSchemaToPy, renderToolsSdkPy } from './py-types.ts'; +export { defineContentToolFixture, type ContentToolFixtureOptions } from './testing.ts'; +export type { ToolCallKind, FileLocation, FileDiff, ReadFileLine, ToolCallView, GenericCallView, TerminalCallView, DiffCallView, ToolResultView, GenericResultView, TerminalResultView, DiffResultView, SearchResultView, SearchMatchesResultView, SearchPathsResultView, SearchFileMatches, SearchLineMatch, ReadResultView, WebResultView, WebSearchResultView, WebFetchResultView, WebSource, } from './presentation.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + tools: ToolRuntime; + } + interface Events { + /** + * Allow, deny, or ask before dispatch. `next()` delegates to allow; missing + * approval support turns `ask` into denial. Async gates must observe + * `exec.signal`; the registry rechecks cancellation after they settle but + * never abandons their promise. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls. + * @param exec - the pending call (name, parsed arguments, caller agent). + * @mode waterfall + */ + 'tools/pre-execute'(this: Scoped, exec: ToolExecution, next: () => Promise): Promise; + /** + * Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns + * a normalized result; wrappers may change only `exec.signal`, while call + * identity remains immutable. The registry re-fuses the original caller + * signal before the body, so replacement cannot detach caller cancellation; + * wrappers must still restore their signal and reach quiescence. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls. + * @param exec - the allowed call about to dispatch (name, parsed arguments, caller agent, signal). + * @mode waterfall + */ + 'tools/execute'(this: Scoped, exec: ToolDispatchExecution, next: () => Promise): Promise; + /** + * Accept, replace, enrich, or block a normalized dispatch result. `next()` + * accepts it unchanged; thrown tools still reach this waterfall as errors. Async + * listeners must observe `exec.signal`; after they settle, caller + * cancellation replaces only a successful accepted outcome with the code + * selected by whether the tool body was invoked. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls. + * @param exec - the call that just ran (name, parsed arguments, caller agent). + * @param result - the dispatch outcome a listener may accept, replace, or block. + * @mode waterfall + */ + 'tools/post-execute'(this: Scoped, exec: ToolExecution, result: Readonly, next: () => Promise): Promise; + /** + * Allow a listener to replace content in the DURABLE LOG COPY of one + * `run_code` sub-dispatch outcome before the bridge appends its + * `tool/code-dispatch` event. `next()` keeps the + * content unchanged; a listener may return replacement blocks (e.g. the + * spill policy's preview + locator for an oversized text result). Only the + * logged copy is affected — the program already received the complete + * value, and the model sees neither. A throwing listener is contained: + * the bridge falls back to logging the original settled content. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches. + * @param dispatch - the parent execution, sub-call identity, and the settled content to log. + * @mode waterfall + */ + 'tools/code-dispatch-log'(this: Scoped, dispatch: CodeDispatchLog, next: () => Promise): Promise; + /** + * Observe the frozen, lossless-JSON final outcome. Listener failures are contained. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): keyed by `exec.agent`. + * @param exec - the execution object that traversed the pipeline. + * @param result - a deep-frozen snapshot of the final returned result. + * @mode emit + */ + 'tools/result'(this: Scoped, exec: Readonly, result: Readonly): undefined; + /** + * A tool was registered or unregistered, or a scoped restriction changed + * (the available tool set changed — possibly for one scope only). An + * UNFILTERED registry-subject notification, deliberately not scope-filtered + * dispatch: a global change concerns every agent's next assembly, so a + * scoped listener subscribing here sees every change, not just its own + * scope's. + * @mode emit + */ + 'tools/change'(): void; + } +} +/** Tool-owned canonical output contract used after the body returns a JSON value. */ +export interface ToolOutputDefinition { + /** Raw supported JSON Schema enforced against every successful canonical value. */ + readonly schema: JsonSchemaNode; + /** Pure projection from validated arguments and value to Native/model content. */ + render(args: unknown, value: JsonValue): ContentBlock[]; + /** Pure replayable presentation projection, computed only for top-level calls. */ + presentationMeta?(args: unknown, value: JsonValue): JsonValue; +} +/** A registered tool: its schema plus the execution function. */ +export interface ToolDefinition extends ToolSchema { + /** Mandatory canonical output declaration. */ + readonly output: ToolOutputDefinition; + /** + * Run one accepted call and return only its canonical lossless-JSON value. + * Async work must observe or forward `exec.signal` and settle only after its + * owned work reaches quiescence. The registry preserves caller cancellation + * through around-dispatch signal replacement and does not abandon this + * promise, but it cannot hard-kill same-process code. + * @param args - losslessly snapshotted, frozen model arguments. + * @param exec - execution identity, cancellation signal, and context deferral. + * @returns the canonical value declared by `output.schema`. + */ + execute(args: unknown, exec: ToolRunContext): Promise; + /** + * Synchronous last-mile transform for model-facing content. The registry + * snapshots this callback when execution starts and invokes it exactly once + * for every normalized outcome, including pipeline failures that bypass + * `tools/post-execute`, immediately before lossless materialization. + * Returning `undefined` preserves the content; every other result field + * remains registry-owned. The callback must be total and must not throw. + * @param exec - immutable execution identity and arguments. + * @param result - complete normalized outcome before materialization. + * @returns replacement content, or `undefined` to preserve it. + */ + finalizeContent?(exec: Readonly, result: Readonly): ContentBlock[] | undefined; + /** + * Cooperative tool-call timeout budget in milliseconds. Omit for no deadline. + * Enforced by `@deepseek-ai/dsh-tool-call-timeout-policy` (a `tools/execute` wrapper); it + * is NEVER sent to the model — `schemas()` whitelists only name/description/ + * parameters. Declaring it asserts this tool forwards `exec.signal` to a + * cooperative implementation that can reach quiescence when the signal aborts. + */ + timeoutMs?: number; + /** + * Pure synchronous classifier for overlap with sibling tool calls. Only + * `true` opts in; omission, exceptions, non-`true` returns, and invalid + * `defineTool` arguments are exclusive. This metadata is never model-visible. + * + * Opted-in executions must not mutate parent-owned state. Shared state must + * tolerate concurrent dispatch; recorder races are permitted only when they + * commute or fail closed. See the + * [parallel-tool-call Agent Note](../../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) + * for the full contract. + * @param args - parsed arguments; `defineTool` validates before calling. + * @returns Whether this call may join a parallel group. + */ + isConcurrencySafe?(args: unknown): boolean; + /** + * Optional: how to present the PENDING state of one call in a UI, derived from + * the call's `args` (parsed arguments, `unknown` — the tool validates/narrows + * its own input). Returns a {@link ToolCallView} (a `card`-tagged render intent), + * or `undefined` (or omit the method) to fall back to a generic presentation + * (title = tool name, raw args as input). Pure and side-effect-free: a UI may + * call it during live streaming AND a session-log replay, so it must depend + * only on `args`. + */ + presentCall?(args: unknown): ToolCallView | undefined; + /** + * Optional: how to present the COMPLETED state, given the same `args` and the + * durable result projection (`content`, failure state, and optional `meta`). Returns a + * {@link ToolResultView}, or `undefined` (or omit the method) to keep the + * pending title and render the raw result content. Pure and side-effect-free + * for the same replay reason. + */ + presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined; +} +/** The completed outcome handed to {@link ToolDefinition.presentResult}. */ +export interface ToolResult { + /** The final model-facing content (or the rendered error text on failure). */ + content: ContentBlock[]; + /** Whether the call failed. */ + isError: boolean; + /** + * The tool-private presentation payload projected by its output declaration + * and threaded verbatim from the `tool/result` event. Absent when the tool + * declared no projector or the call was nested under a composite transport. + */ + meta?: JsonValue; +} +declare const toolExecutionTokenBrand: unique symbol; +/** Opaque call identity that permits correlation without exposing mutable execution state. */ +export type ToolExecutionToken = symbol & { + readonly [toolExecutionTokenBrand]: true; +}; +/** + * Caller-supplied description of one tool call. {@link ToolRuntime.execute} + * adds the registry-owned token to form a pipeline {@link ToolExecution}; + * callers do not choose that token. + */ +export interface ToolExecutionInput { + readonly callId: CallId; + /** + * Root model-requested call owning this execution tree. Callers omit it for + * a root execution; nested dispatchers propagate the enclosing value. + */ + readonly rootCallId?: CallId; + readonly name: string; + /** Losslessly JSON-serializable parsed arguments (tools validate their own schema). */ + readonly arguments: unknown; + /** The agent on whose behalf the call runs (set by the agent loop). */ + readonly agent?: Agent; + /** + * Opaque token of the enclosing transport execution, when one exists. Code + * Mode sets this on SDK sub-dispatches so commit-style observers can wait for + * the outer `run_code` outcome without receiving its live mutable execution. + * The token also marks the call as a transport sub-dispatch rather than a + * model-direct call: under `mode: 'code'`, only calls WITH a parent may + * execute a native tool name — a model-direct call (no parent) is denied as + * `UNKNOWN_TOOL` before the policy pipeline. See {@link ToolRuntime.execute}. + */ + readonly parent?: ToolExecutionToken; + /** Required caller-owned cancellation for this invocation. */ + readonly signal: AbortSignal; +} +/** + * Scheduling mode for one pending call. `parallel` may overlap with siblings; + * `exclusive` runs alone and forms an ordering barrier. + */ +export type ToolExecutionMode = { + kind: 'parallel'; +} | { + kind: 'exclusive'; +}; +/** + * One settled `run_code` sub-dispatch about to be logged, as seen by the + * `tools/code-dispatch-log` waterfall: the parent execution (session owner, + * outer call identity), the sub-call identity, and the outcome whose durable + * copy a listener may reshape. `content` is the RENDERED result projection + * (what a native `tool/result` would carry) — the program itself received + * the structured `value` (or just the error message on failure); only the + * `tool/code-dispatch` event's copy changes. + */ +export interface CodeDispatchLog { + /** The outer `run_code` execution. */ + readonly exec: ToolExecution; + /** The calling agent (the scope routing key and the spill owner), when the outer call has one. */ + readonly agent?: Agent; + /** Deterministic sub-call id (`:code:`). */ + readonly subCallId: CallId; + /** The dispatched sub-tool name. */ + readonly name: string; + /** Whether the sub-call settled as an error. */ + readonly isError: boolean; + /** The sub-call's complete model-facing content (the settle event's default payload). */ + readonly content: ContentBlock[]; +} +/** + * One pending tool call inside the registry pipeline. Parsed arguments cross + * one lossless-JSON materialization boundary before policy and are deep-frozen; + * call identity, the caller signal, and the registry-assigned {@link token} are + * readonly. The registry freezes the complete object before `tools/result` + * observers run. + */ +export interface ToolExecution extends ToolExecutionInput { + /** Root model-requested call, resolved for every root and nested execution. */ + readonly rootCallId: CallId; + /** Registry-assigned identity shared with nested calls only as their opaque `parent` token. */ + readonly token: ToolExecutionToken; +} +/** + * Around-dispatch view of a {@link ToolExecution}. A `tools/execute` wrapper + * may replace the signal for its delegated lifetime, but it cannot remove it. + * The registry fuses every replacement with the captured caller signal. + */ +export interface ToolDispatchExecution extends Omit { + /** Cancellation signal visible to the next wrapper or tool body. */ + signal: AbortSignal; +} +/** + * Runtime context handed to a tool implementation after the registry has + * accepted a {@link ToolExecution}. {@link deferContext} attaches context to + * this execution's own result — a composite tool ferries nested-dispatch + * context back to the outer result, and a leaf tool may mint a fresh + * plugin-sourced instruction; the loop appends it only after the + * `tool/result`. + */ +export interface ToolRunContext extends ToolExecution { + /** + * Defer one context — typically a nested-dispatch context ferried by a + * composite tool, or a fresh plugin-sourced instruction — until this tool's + * final result reaches the agent loop. Contexts retain their individual + * source and metadata and are emitted in call order. + */ + deferContext(context: UserMessage): void; + /** + * Mark a successful final result as terminal for the current agent turn. + * The marker rides this execution's own result (`concludesTurn` exists only + * on {@link ToolExecutionSuccess}); a composite that dispatches nested + * calls forwards it from the nested result, exactly like + * `additionalContexts`, so only an authoritative nested success can + * conclude the enclosing run. + */ + concludeTurn(): void; +} +/** + * Scheduler-only result after ordered pre-execute and guards. A `post-result` + * still receives post-execute; a `final-result` bypasses it. + * @internal + */ +export type ScheduledToolPreparation = { + kind: 'dispatch'; + exec: ToolRunContext; +} | { + kind: 'post-result'; + exec: ToolRunContext; + result: ToolExecutionResult; +} | { + kind: 'final-result'; + exec: ToolRunContext; + result: ToolExecutionResult; +}; +/** + * Scheduler-only dispatch result. A `post-result` still receives post-execute; + * a `final-result` already matches {@link ToolRuntime.execute} failure semantics. + * @internal + */ +export type ScheduledToolDispatch = { + kind: 'post-result'; + result: ToolExecutionResult; +} | { + kind: 'final-result'; + result: ToolExecutionResult; +}; +/** + * Symbol-keyed scheduler view that keeps pre/post policy ordered while + * overlapping dispatch. Ordinary callers use {@link ToolRuntime.execute}; + * this is not a plugin extension point. + * @internal + */ +export interface ToolRuntimeScheduler { + /** Materialize input, run the ordered pre-execute/guard gate, and decide what stage follows. */ + prepare(exec: ToolExecutionInput): Promise; + /** Run only the around-dispatch/body stage. */ + dispatch(exec: ToolRunContext): Promise; + /** Run post-execute and definition-owned content finalization, then materialize and notify. */ + finalize(exec: ToolRunContext, result: ToolExecutionResult): Promise; + /** Run definition-owned content finalization, then materialize and notify without post-execute. */ + finish(exec: ToolRunContext, result: ToolExecutionResult): ToolExecutionResult; +} +/** + * Scheduler entry point omitted from the generated named service API. + * @internal + */ +export declare const TOOL_RUNTIME_SCHEDULER: unique symbol; +/** Canonical error code for cancellation after a tool body was invoked. */ +export declare const TOOL_ABORTED = "ABORTED"; +/** Canonical error code for cancellation before a tool body was invoked. */ +export declare const TOOL_ABORTED_BEFORE_DISPATCH = "ABORTED_BEFORE_DISPATCH"; +/** Structured error metadata for a failed tool call (alongside the model-facing text). */ +export interface ToolErrorInfo { + name: string; + code: string; +} +/** Canonical failure detail; internal routing information remains optional. */ +export interface ToolFailure { + /** Human-readable failure message without the Native `Error: ` envelope. */ + message: string; + /** Internal error class/code used by policy and durable diagnostics. */ + info?: ToolErrorInfo; +} +/** + * Thrown (internally) when the model requests a tool that isn't registered. + * Extends {@link HarnessError} (`code: 'UNKNOWN_TOOL'`) so an unknown-tool + * failure is as routable as a tool-thrown one — retry/sandbox/replay code can + * distinguish it from a tool body's own error. + */ +export declare class ToolNotFoundError extends HarnessError { + /** + * @param toolName - the name the caller asked for. + * @param reachableFrom - how the model reaches this tool instead, when the + * name IS visible and only the presentation denies calling it directly. + * Omitted for a name that is registered nowhere. + */ + constructor(toolName: string, reachableFrom?: string); +} +/** Thrown when a tool body or post-policy value violates its declared output. */ +export declare class ToolOutputError extends HarnessError { + /** Schema/value violations in validation order. */ + readonly violations: string[]; + constructor(toolName: string, violations: string[]); +} +/** Successful canonical tool execution, including its Native/model projection. */ +export interface ToolExecutionSuccess { + readonly isError: false; + /** Execution-local canonical value; deliberately omitted from durable events. */ + readonly value: JsonValue; + readonly content: ContentBlock[]; + readonly error?: never; + readonly meta?: JsonValue; + readonly additionalContexts?: UserMessage[]; + /** The agent loop stops after committing this successful result batch. */ + readonly concludesTurn?: true; +} +/** Failed canonical tool execution; failures never carry a successful value. */ +export interface ToolExecutionFailure { + readonly isError: true; + readonly error: ToolFailure; + readonly value?: never; + readonly content: ContentBlock[]; + readonly meta?: JsonValue; + readonly additionalContexts?: UserMessage[]; + readonly concludesTurn?: never; +} +/** The discriminated, execution-local outcome of one tool call. */ +export type ToolExecutionResult = ToolExecutionSuccess | ToolExecutionFailure; +/** + * Pre-dispatch decision. `allow` runs the call; `deny` materializes an error; + * `ask` runs only after an approval service returns `allowed-once` and otherwise + * denies. Input rewriting is excluded because arguments are already logged and + * presented. + */ +export type PreToolDecision = { + kind: 'allow'; +} | { + kind: 'deny'; + reason: string; +} | { + kind: 'ask'; + reason?: string; +}; +/** + * Post-dispatch decision: accept, replace one projection, attach context for the + * next request, or block by turning corrective feedback into an error result. + */ +export type PostToolDecision = { + kind: 'accept'; + content?: ContentBlock[]; + value?: never; + additionalContexts?: UserMessage[]; +} | { + kind: 'accept'; + value: JsonValue; + content?: never; + additionalContexts?: UserMessage[]; +} | { + kind: 'block'; + feedback: ContentBlock[]; + additionalContexts?: UserMessage[]; +}; +/** How the registry presents its tools to the model (see {@link Config.mode}). */ +export type ToolPresentationMode = 'native' | 'code' | 'both'; +/** Plugin config: how the registered tools are presented to the model. */ +export interface Config { + /** + * Model presentation. `native` (default) sends every visible schema; `code` + * sends only `run_code` plus a generated SDK prompt and collapses the + * executor to the same surface (a model-direct call may only name + * `run_code`; `run_code` SDK sub-dispatches keep every visible tool); `both` + * sends both forms. Code modes require a `ctx.codeRuntime` whose `language` + * has a registered SDK renderer (TypeScript or Python) and fail prompt + * assembly when it is absent or has no renderer. Under `code`, native names + * in `toolOrder` are invalid. + */ + mode?: ToolPresentationMode; + /** + * Concurrency cap for a `run_code` program's overlapping sub-calls + * (default 10, the loop scheduler's own default). Sub-calls follow the + * native scheduling contract — only calls whose tools classify + * concurrency-safe overlap; exclusive calls form barriers — so `1` + * restores strictly serial dispatch. Must be a positive integer. + */ + maxParallelSubCalls?: number; +} +/** + * Per-scope filter over global tools. Restrictions intersect and do not affect + * scoped registrations or the reserved Code Mode transport. + */ +export interface ToolRestriction { + /** Global tool names that stay visible; everything else is removed. */ + readonly allow?: readonly string[]; + /** Global tool names removed from visibility. */ + readonly deny?: readonly string[]; +} +/** + * A monotonic execution guard evaluated after every `tools/pre-execute` + * listener and before the tool body. Returning a reason denies the call; + * returning `undefined` leaves it unchanged. Because guards have no allow + * result, listener ordering cannot turn a denial back into permission. + * @param execution - the identity-protected call after extensible pre-execute policy completed. + * @returns a final denial reason, or `undefined` to leave the call allowed. + */ +export type ToolGuard = (execution: Readonly) => string | undefined; +/** + * Tool registry and execution pipeline. Scoped registrations shadow globals; + * one visibility resolver feeds presentation, lookup, and dispatch. + */ +export declare class ToolRuntime extends Service { + static inject: string[]; + static Config: z; + /** Internal staged view consumed by `dsh-agent-loop`'s parallel scheduler. */ + readonly [TOOL_RUNTIME_SCHEDULER]: ToolRuntimeScheduler; + /** Context deferred by a running tool body, keyed by its scheduler-owned execution. */ + private deferredContexts; + /** Executions whose tool body declared the current turn complete. */ + private concludingExecutions; + /** Original caller cancellation, kept outside the wrapper-mutable execution object. */ + private cancellationStates; + /** Definition-owned final content transform snapshotted before policy begins. */ + private contentFinalizers; + private readonly layers; + /** Presentation for scopes that declare none; {@link presentAs} shadows it per scope. */ + private readonly defaultMode; + private readonly maxParallelSubCalls; + /** + * Reserved presentation transport, kept outside the filterable registration + * layers. Built on first need rather than at construction: which agents run + * a code mode is no longer known when the service is constructed, and the + * transport is stateless beyond its closures over `this`. + */ + private codeTransport; + constructor(ctx: Context, config?: Config); + /** + * The prompt statement of the `code` executor collapse, registered wherever + * {@link sdkSection} is and rendering empty outside an effective `code`. + * + * Every tool contributes its own guidance section naming its tool, none of + * them qualify how that tool is reached, and they all render before the SDK + * (orders 100-199 against {@link SDK_SECTION_ORDER}). Without this the model + * reads a catalog of tools it is told to use and no statement that only + * `run_code` may be called, so it emits a native call, receives + * `UNKNOWN_TOOL` for a tool the prompt just declared, and concludes the + * deployment is inconsistent. {@link COLLAPSE_SECTION_ORDER} places the rule + * before that guidance rather than after it. + * + * `both` renders empty: native calls do execute there, so the rule is false. + * @returns the section registration. + */ + private collapseSection; + /** + * The generated-SDK prompt section, registered globally by a code-mode + * deployment and per scope by {@link presentAs}. + * + * The body regenerates from the CALLING scope, and renders empty for an + * agent presenting natively — an agent that opted out under a code-mode + * deployment still sees the global registration, and an empty section is + * dropped from the rendered prompt. + * @returns the section registration. + */ + private sdkSection; + /** + * The presentation one scope's agent sees: its own declaration, else the + * deployment default. + * @param scope - the calling agent, or undefined for the global view. + * @returns the resolved presentation mode. + */ + private modeFor; + /** + * The reserved `run_code` transport, built on first need. + * + * It never enters the global layer: per-agent restrictions must not remove + * it, and a scoped registration must not shadow it. The visibility resolver + * appends it after resolving the filterable global/scoped capability layers, + * and only for scopes whose mode actually presents it. + * @returns the shared transport definition. + */ + private requireCodeTransport; + /** + * Present the calling scope's tools in `mode` instead of the deployment + * default. Nearest scope on the chain wins, so a preset's standing + * declaration covers every agent joined under it. + * + * Scoped only, and one declaration per scope: this is how an agent preset + * composes Code Mode agents beside native ones in the same process, and a + * process-global override would be the `mode` config field instead. + * @param mode - the presentation the covered agents' models see. + * @returns the exact disposer that restores the deployment default. + */ + presentAs(mode: ToolPresentationMode): () => void; + /** + * Build one scope's wire schemas and names for prompt-order validation. + * Restrictions do not make known tools invalid, but a mode collapse does. + */ + private wireSchemas; + /** + * Resolve the code runtime or throw the actionable misconfiguration error. + * Read at use time (assembly / run_code execution), NOT via static + * `inject`: an inject entry would hold `ctx.tools` — and every tool plugin + * behind it — hostage to a code runtime existing even under `mode: + * 'native'` (the loop's optional-backend idiom, same as + * `sessionPersistence`). + * + * Assembly and `run_code` execution read separately, so the language is not + * bound to a request. Harmless while one published backend exists — both + * reads return the same flavor — but a reload that swapped in a second + * language between them would hand a program written against one SDK to the + * other. Binding it is deferred until a second backend ships (the first + * point it is testable); rationale in the + * [language-dispatch note](../../../../.agents/notes/implemented/feature/2026-07-31-code-mode-language-dispatch.md). + */ + private requireCodeRuntime; + /** + * Register globally or in the calling agent scope. Scoped tools shadow + * globals; duplicates within one layer and the reserved `run_code` name fail. + * @param definition - tool schema, execution, and optional finalization/presentation callbacks. + * @returns the exact disposer that unregisters the tool. + */ + register(definition: ToolDefinition): () => void; + /** + * Restrict global tools for the calling agent scope. Empty filters, unknown + * names, scope-local names, and reserved transport names fail. Restrictions + * intersect; scoped registrations remain visible. + * @param filter - global-tool mask: `allow` (keep only) and/or `deny` (remove). + * @returns the exact disposer that lifts this restriction. + */ + restrict(filter: ToolRestriction): () => void; + /** + * Register a monotonic guard after the extensible `tools/pre-execute` + * waterfall. A plain-context guard applies globally; one registered through + * `agent.ctx` applies only to that agent. Any matching guard may deny by + * returning a reason, while no guard can force-allow a call another guard + * denied. The exact effect disposer is returned for ordered ownership and + * HMR cleanup. + * @param guard - synchronous check; a returned string denies the execution. + * @returns the exact disposer that unregisters the guard. + */ + guard(guard: ToolGuard): () => void; + /** First monotonic denial from the global then the scope chain's guard layers, farthest first. */ + private guardReason; + /** + * Resolve every registry fact one scope needs in one layer traversal. The + * visible map applies restrictions to the INHERITED surface, then the + * scope's own registrations and the reserved presentation transport; the + * other sets retain the pre-restriction facts needed by restriction and + * prompt-order validation. + * + * A restriction filters what a scope inherits — the global layer and every + * ancestor layer on its chain — and never what its OWN layer registers. + * That exemption is what a per-child capability filter has to keep intact: + * the delegation runtime registers a child's reporting and structured-output + * tools into the child's own layer, and a filter naming the capabilities the + * child may use must not strip the machinery it answers through. + * + * Reading the exempt set as "the global layer" instead of "not mine" held + * only while every model-facing tool sat in the host composition. Once + * presets moved them onto the agent plane they became an ANCESTOR + * contribution, so a child's filter silently stopped constraining anything + * it was given. + * @param scope - the viewing scope (the agent), or undefined for the global view. + * @returns the complete derived view for that scope. + */ + private view; + /** + * Look up a tool as one scope sees it (scoped + * shadows global; a restricted-away global reads as absent). Presenters pass + * the calling agent so the rendered card matches the definition that + * actually executed. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns the definition the scope resolves, or undefined when none is visible. + */ + get(name: string, scope?: ScopeKey): ToolDefinition | undefined; + /** + * Resolve the definition that MAY EXECUTE for a call, applying the mode + * collapse at the operation boundary that owns it. The registry view + * (`get`) is presentation-agnostic; here a MODEL-DIRECT call under `code` + * may only name the reserved `run_code` transport, while a nested + * sub-dispatch (a `parent` token set — the `run_code` SDK calling a tool + * it bound) may call any visible tool. Denial surfaces as `UNKNOWN_TOOL` + * through the executor, matching an absent definition. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + * @returns the definition that may run, or undefined when the call must be rejected. + */ + private resolveExecution; + /** + * Project visible definitions onto the allowlisted model-facing schema fields, + * excluding execution and presentation callbacks. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns one deep-cloned schema per visible tool. + */ + schemas(scope?: ScopeKey): ToolSchema[]; + /** Project visible callable tools onto the generated Code Mode SDK contract. */ + private sdkSchemas; + /** Project one definition onto the model-facing schema fields. */ + private schemaOf; + /** + * Classify a pending call through the caller's visible tool definition. Only + * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or + * throwing classifiers are exclusive. + * @param exec - call name, parsed arguments, and optional agent scope. + * @returns the fail-closed scheduling mode. + */ + executionMode(exec: ToolExecutionInput): ToolExecutionMode; + /** + * Run the `tools/code-dispatch-log` waterfall over one settled sub-dispatch + * and return the content the bridge should log on `tool/code-dispatch`. + * Contained: when a listener throws, the method logs the original settled + * content; that failure must not fail the dispatch or omit the settle event. Private: + * the ONE consumer is the `run_code` bridge this registry constructs, which + * receives it as a capability parameter (the `requireRuntime` idiom) — the + * waterfall, not this invoker, is the public extension point. + */ + private shapeDispatchLog; + /** + * Whether the `code` mode collapse denies a model-direct call: only the + * reserved `run_code` transport may be named. Nested sub-dispatches (a + * `parent` token set) bypass the collapse. One home for the + * security-relevant predicate, shared by {@link resolveExecution} and + * {@link createExecution} so the two can never drift apart. + * + * Resolved through {@link modeFor}, NOT `defaultMode`: an agent given `code` + * by an agent preset under a native deployment is the composition + * `dsh-agent-tool-presentation` exists for, and reading the deployment default would + * leave exactly that agent uncollapsed — announcing one surface while + * executing another, which is the bypass this collapse closes. + * @param name - the tool name as registered. + * @param scope - the viewing scope whose effective presentation mode applies. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + */ + private collapses; + /** + * Execute through pre-policy, guards, around-dispatch, post-policy, + * definition-owned content finalization, and final notification. Tool and + * listener failures resolve as materialized error results; an invisible tool + * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen + * snapshot final observers receive. Cancellation + * arriving after entry and before final result materialization skips a + * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a + * successful started outcome with `ABORTED`; already-started work is still + * drained and may retain a tool-owned structured error. + * @param exec - the typed same-process call input. The registry assigns its + * correlation token before policy begins. + * @returns the materialized final result. + */ + execute(exec: ToolExecutionInput): Promise; + private completeScheduledExecution; + private createExecution; + /** + * Run the ordered pre-execute and monotonic guard stages for the scheduler. + * @param input - the caller-supplied execution input. + * @returns the prepared execution plus the next scheduler stage. + * @internal + */ + private prepareScheduledExecution; + private prepareExecution; + /** Whether the original caller signal is currently aborted. */ + private callerCancelled; + /** Canonical cancellation outcome selected by whether the tool body started. */ + private cancellationResult; + /** + * Dispatch the registered body with the original caller signal fused back + * into any around-wrapper replacement. Cancellation never abandons the body: + * a started promise reaches quiescence before its outcome becomes `ABORTED`. + */ + private dispatchToolBody; + /** + * Run around-dispatch and the tool body. Tool and unknown-tool failures still + * receive post-execute; pipeline failures are already final. + * @param exec - the prepared execution. + * @returns whether the result still needs post-execute. + * @internal + */ + private dispatchScheduledExecution; + /** + * Run ordered post-execute, then apply definition-owned content finalization, + * materialize, and notify the final outcome. + * @param exec - the prepared execution. + * @param result - dispatch/pre result that still needs post-execute. + * @returns the materialized final result. + * @internal + */ + private finalizeScheduledExecution; + /** + * Materialize the candidate, apply definition-owned content finalization, + * then materialize and notify the authoritative result. + * @param exec - the prepared execution. + * @param result - final result. + * @returns the materialized final result. + * @internal + */ + private finishScheduledExecution; + /** Apply the snapshotted tool-owned content transform without exposing other result fields. */ + private applyFinalContent; + /** Notify observers without exposing a mutation or error channel into the outcome. */ + private notifyResult; + /** + * Resolve an `ask` decision to allow/deny through the approval seam. The + * seam is consumed opportunistically with `ctx.get('approval')` — a + * deployment that composes no ApprovalService keeps the historical degrade + * to deny, and an unmount mid-session degrades the same way on the next ask. + * An agent-less execution also degrades: without an agent there is no + * session to audit to and no UI to route to. Otherwise the outcome maps + * one-to-one — `allowed-once` proceeds; the three non-grants deny with + * distinct reasons so the model can tell a human "no" from an absent + * approval channel. + */ + private serviceAsk; + /** + * Run the `tools/post-execute` waterfall over a dispatched `result` and apply + * its {@link PostToolDecision}: `accept` keeps the call successful (replacing + * `content` when given), `block` turns it into an `isError` whose content is + * the corrective `feedback`. Either decision may attach `additionalContexts`, + * which are ferried on the returned result for the loop's active-batch FIFO. + * Context deferred by the tool body survives an accepted result but is + * discarded when the outer call is blocked; a block exposes only context the + * blocking decision explicitly supplied. + * Runs inside `execute`'s outer try/catch (a throwing listener → isError). + */ + private postExecute; + /** Registry-normalized results and the exact dispatch that validated each value. */ + private readonly canonicalResults; + /** Mark one registry-normalized result as canonical only for its owning dispatch. */ + private markCanonical; + /** Snapshot, validate, render, and optionally project one successful body value. */ + private createSuccessResult; + /** Normalize an around-dispatch wrapper's authored result through the owning output contract. */ + private normalizeDispatchResult; + /** Materialize the authoritative commit outcome once, immediately before `tools/result`. */ + private materializeFinalResult; +} +export default ToolRuntime; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/index.js new file mode 100644 index 0000000..24d86f1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/index.js @@ -0,0 +1,1326 @@ +/** + * Tool registry, model presentation modes, and pre/guard/around/post/result + * execution pipeline. + * @module @deepseek-ai/dsh-tools + */ +import { Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { AnonymousEntries, NamedEntries, ScopedLayers, scopeOf, scopeTarget } from '@deepseek-ai/dsh-scope'; +import { assertNever, deepFreeze, HarnessError } from '@deepseek-ai/dsh-llm'; +import { snapshotJsonValue } from '@deepseek-ai/dsh-session'; +import { assertSupportedJsonSchema, validateJsonSchemaValue } from "./json-schema.js"; +import { createRunCodeTool, RUN_CODE_NAME, SDK_SECTION_ORDER } from "./code-mode.js"; +import { renderToolsSdk } from "./ts-types.js"; +import { renderToolsSdkPy } from "./py-types.js"; +/** + * Language → SDK-section renderer. The registry looks up the loaded + * `ctx.codeRuntime.language` in this table when assembling the `tools:sdk` + * section under a non-native mode; a runtime whose language is not a key + * fails the assembly loudly (same idiom as `toolOrder` violations). Adding a + * new backend language is three parallel edits — a {@link CodeSdkLanguage} + * member, an entry here, and a `RUN_CODE_FLAVORS` entry in `code-mode.ts` for + * its `run_code` schema strings — plus the renderer function this table points + * at. The `satisfies` clause pins this table's key set to that union, which + * the flavor table is checked against too, so any of the three left out is a + * typecheck failure. What no check reaches is the prose that names the values + * instead of deriving them: the seam's `dsh-code-runtime` README pair, its + * `CodeRuntime.language` JSDoc, and `docs/subsystems/code-runtime.md` + * with its zh pair, plus this package's own README pair and the + * {@link Config.mode} JSDoc. + */ +/** + * Prompt order of the `code` collapse statement: after the persona and before + * the 100-199 per-tool guidance band, so the model reads which tools it may + * call before it reads what each one is for. + */ +const COLLAPSE_SECTION_ORDER = 99; +/** + * The model-facing statement of the `code` collapse. Names the consequence + * (the call fails) and the route (inside the program), because a rule the + * model can only discover by being denied is one it corrects too late. + */ +const CODE_ONLY_INSTRUCTION = `\`${RUN_CODE_NAME}\` is the only tool you can call directly — a tool call naming any other tool fails. Reach every tool the SDK declares below from inside the program.`; +const SDK_RENDERERS = { + typescript: renderToolsSdk, + python: renderToolsSdkPy, +}; +export { defineTool, valueSchemaSpecToJsonSchema, parameterSchemaSpecToJsonSchema, validateArgs, ToolArgsError, } from "./schema.js"; +export { assertSupportedJsonSchema, assertObjectJsonSchema, validateJsonSchemaValue, JsonSchemaError, } from "./json-schema.js"; +export { CodeRunFailedError, RUN_CODE_NAME } from "./code-mode.js"; +export { jsonSchemaToTs, renderToolsSdk } from "./ts-types.js"; +export { jsonSchemaToPy, renderToolsSdkPy } from "./py-types.js"; +export { defineContentToolFixture } from "./testing.js"; +/** + * Scheduler entry point omitted from the generated named service API. + * @internal + */ +export const TOOL_RUNTIME_SCHEDULER = Symbol('@deepseek-ai/dsh-tools.scheduler'); +/** Canonical error code for cancellation after a tool body was invoked. */ +export const TOOL_ABORTED = 'ABORTED'; +/** Canonical error code for cancellation before a tool body was invoked. */ +export const TOOL_ABORTED_BEFORE_DISPATCH = 'ABORTED_BEFORE_DISPATCH'; +/** + * Thrown (internally) when the model requests a tool that isn't registered. + * Extends {@link HarnessError} (`code: 'UNKNOWN_TOOL'`) so an unknown-tool + * failure is as routable as a tool-thrown one — retry/sandbox/replay code can + * distinguish it from a tool body's own error. + */ +export class ToolNotFoundError extends HarnessError { + /** + * @param toolName - the name the caller asked for. + * @param reachableFrom - how the model reaches this tool instead, when the + * name IS visible and only the presentation denies calling it directly. + * Omitted for a name that is registered nowhere. + */ + constructor(toolName, reachableFrom) { + super(reachableFrom === undefined + ? `unknown tool "${toolName}"` + : `unknown tool "${toolName}": ${reachableFrom}`, 'UNKNOWN_TOOL'); + this.name = 'ToolNotFoundError'; + } +} +/** Thrown when a tool body or post-policy value violates its declared output. */ +export class ToolOutputError extends HarnessError { + /** Schema/value violations in validation order. */ + violations; + constructor(toolName, violations) { + super(`tool "${toolName}" returned invalid output: ${violations.join('; ')}`, 'INVALID_TOOL_OUTPUT'); + this.name = 'ToolOutputError'; + this.violations = violations; + } +} +/** Convert one projector exception into the canonical invalid-output failure. */ +function projectionError(toolName, projector, error) { + return new ToolOutputError(toolName, [`output.${projector} failed: ${errorMessage(error)}`]); +} +/** Snapshot one projector result before later durable-result materialization. */ +function snapshotProjection(toolName, projector, candidate) { + try { + const detached = snapshotJsonValue(candidate); + if (detached === undefined) { + throw new ToolOutputError(toolName, [`output.${projector} returned non-lossless JSON`]); + } + return detached; + } + catch (error) { + if (error instanceof ToolOutputError) + throw error; + throw projectionError(toolName, projector, error); + } +} +/** Snapshot one body or policy value into the canonical invalid-output failure class. */ +function snapshotToolValue(toolName, candidate) { + try { + const detached = snapshotJsonValue(candidate); + if (detached === undefined) + throw new ToolOutputError(toolName, ['value is not lossless JSON']); + return detached; + } + catch (error) { + if (error instanceof ToolOutputError) + throw error; + throw new ToolOutputError(toolName, [`value snapshot failed: ${errorMessage(error)}`]); + } +} +/** + * Best-effort human-readable message from an arbitrary thrown value: Error + * instances use `.message`; non-Error objects with a string `message` + * property (e.g. `throw { message: 'denied' }`) use it too; everything else + * is stringified. + */ +function errorMessage(error) { + try { + if (error instanceof Error) + return error.message; + if (typeof error === 'object' && error !== null + && 'message' in error && typeof error.message === 'string') { + return error.message; + } + return String(error); + } + catch { + // A hostile thrown value can trap `instanceof`, property access, or string + // coercion. Error normalization is the outermost safety boundary, so its + // fallback must itself be total. + return ''; + } +} +/** Derive one failure message from policy feedback without changing its rendered blocks. */ +function failureMessageFromContent(content) { + const text = content + .map(block => block.type === 'text' ? block.text : `[${block.type} content]`) + .join('\n'); + return text.length > 0 ? text : 'tool result blocked by post-execute policy'; +} +/** Snapshot and freeze one durable tool-result projection or reject lossy data. */ +function materializePresentation(candidate) { + const detached = snapshotJsonValue(candidate); + if (detached === undefined) { + throw new TypeError('tool result must be losslessly JSON-serializable'); + } + return deepFreeze(detached); +} +/** Structured `{ name, code }` for a thrown HarnessError, else undefined. */ +function errorInfo(error) { + try { + return error instanceof HarnessError ? { name: error.name, code: error.code } : undefined; + } + catch { + return undefined; + } +} +/** One scope's complete tool-registry contribution. */ +class ToolLayer { + tools; + restrictions = new AnonymousEntries(); + guards = new AnonymousEntries(); + /** + * Presentation this scope's agent declared for itself, shadowing the + * deployment default. One cell rather than an entry table: two answers to + * "which form does the model see" is a contradiction, not a merge. + */ + mode; + constructor(scope) { + this.tools = new NamedEntries(name => new Error(scope === undefined + ? `tool "${name}" is already registered (for a per-agent variant, register through that agent's \`agent.ctx\` instead)` + : `tool "${name}" is already registered in this scope`)); + } + /** Whether every contribution table in this aggregate layer is empty. */ + isEmpty() { + return this.tools.isEmpty() && this.restrictions.isEmpty() && this.guards.isEmpty() + && this.mode === undefined; + } + /** Whether every compiled restriction in this layer admits a global tool name. */ + admits(name) { + for (const filter of this.restrictions.values()) { + if ((filter.allow !== undefined && !filter.allow.has(name)) + || (filter.deny !== undefined && filter.deny.has(name))) + return false; + } + return true; + } + /** First monotonic denial from this layer's live guard registrations. */ + guardReason(exec) { + for (const guard of this.guards.values()) { + const reason = guard(exec); + if (reason !== undefined) + return reason; + } + return undefined; + } +} +/** Resolve the run_code overlap cap at the owning config boundary (direct construction bypasses the Loader schema). */ +function resolveMaxParallelSubCalls(value) { + const maxParallelSubCalls = value ?? 10; + if (!Number.isInteger(maxParallelSubCalls) || maxParallelSubCalls < 1) { + throw new Error('maxParallelSubCalls must be a positive integer'); + } + return maxParallelSubCalls; +} +/** + * Tool registry and execution pipeline. Scoped registrations shadow globals; + * one visibility resolver feeds presentation, lookup, and dispatch. + */ +export class ToolRuntime extends Service { + static inject = ['systemPrompt']; + static Config = z.object({ + mode: z.union(['native', 'code', 'both']).default('native'), + maxParallelSubCalls: z.natural().min(1).default(10), + }); + /** Internal staged view consumed by `dsh-agent-loop`'s parallel scheduler. */ + [TOOL_RUNTIME_SCHEDULER] = { + prepare: exec => this.prepareScheduledExecution(exec), + dispatch: exec => this.dispatchScheduledExecution(exec), + finalize: (exec, result) => this.finalizeScheduledExecution(exec, result), + finish: (exec, result) => this.finishScheduledExecution(exec, result), + }; + /** Context deferred by a running tool body, keyed by its scheduler-owned execution. */ + deferredContexts = new WeakMap(); + /** Executions whose tool body declared the current turn complete. */ + concludingExecutions = new WeakSet(); + /** Original caller cancellation, kept outside the wrapper-mutable execution object. */ + cancellationStates = new WeakMap(); + /** Definition-owned final content transform snapshotted before policy begins. */ + contentFinalizers = new WeakMap(); + layers = new ScopedLayers(scope => new ToolLayer(scope), () => { this.ctx.emit('tools/change'); }); + /** Presentation for scopes that declare none; {@link presentAs} shadows it per scope. */ + defaultMode; + maxParallelSubCalls; + /** + * Reserved presentation transport, kept outside the filterable registration + * layers. Built on first need rather than at construction: which agents run + * a code mode is no longer known when the service is constructed, and the + * transport is stateless beyond its closures over `this`. + */ + codeTransport; + constructor(ctx, config = {}) { + super(ctx, 'tools'); + // The schema already defaulted an omitted mode; the ?? narrows the + // optional-input type for direct (non-Loader) construction in tests. + this.defaultMode = config.mode ?? 'native'; + this.maxParallelSubCalls = resolveMaxParallelSubCalls(config.maxParallelSubCalls); + ctx.systemPrompt.tools(context => this.wireSchemas(context.scope)); + if (this.defaultMode !== 'native') { + ctx.systemPrompt.section(this.collapseSection()); + ctx.systemPrompt.section(this.sdkSection()); + } + } + /** + * The prompt statement of the `code` executor collapse, registered wherever + * {@link sdkSection} is and rendering empty outside an effective `code`. + * + * Every tool contributes its own guidance section naming its tool, none of + * them qualify how that tool is reached, and they all render before the SDK + * (orders 100-199 against {@link SDK_SECTION_ORDER}). Without this the model + * reads a catalog of tools it is told to use and no statement that only + * `run_code` may be called, so it emits a native call, receives + * `UNKNOWN_TOOL` for a tool the prompt just declared, and concludes the + * deployment is inconsistent. {@link COLLAPSE_SECTION_ORDER} places the rule + * before that guidance rather than after it. + * + * `both` renders empty: native calls do execute there, so the rule is false. + * @returns the section registration. + */ + collapseSection() { + return { + name: 'tools:code-only', + order: COLLAPSE_SECTION_ORDER, + // The SAME predicate the executor denies by, so the prompt cannot state + // a rule the registry does not enforce (see `collapses`). + text: context => this.modeFor(context.scope) === 'code' ? CODE_ONLY_INSTRUCTION : '', + }; + } + /** + * The generated-SDK prompt section, registered globally by a code-mode + * deployment and per scope by {@link presentAs}. + * + * The body regenerates from the CALLING scope, and renders empty for an + * agent presenting natively — an agent that opted out under a code-mode + * deployment still sees the global registration, and an empty section is + * dropped from the rendered prompt. + * @returns the section registration. + */ + sdkSection() { + return { + name: 'tools:sdk', + order: SDK_SECTION_ORDER, + // Regenerate from the calling scope's visible tools in stable order. + text: (context) => { + const mode = this.modeFor(context.scope); + if (mode === 'native') + return ''; + const runtime = this.requireCodeRuntime(mode); + // Own-property read: a language like `toString`/`constructor` would + // otherwise resolve an inherited Object.prototype member as a renderer. + const render = SDK_RENDERERS[runtime.language]; + /* v8 ignore next -- requireCodeRuntime rejects an unknown language before this runs. */ + if (render === undefined) + throw new Error(`dsh-tools: no SDK renderer for ${runtime.language}`); + return render(this.sdkSchemas(context.scope)); + }, + }; + } + /** + * The presentation one scope's agent sees: its own declaration, else the + * deployment default. + * @param scope - the calling agent, or undefined for the global view. + * @returns the resolved presentation mode. + */ + modeFor(scope) { + // Nearest scope wins along the chain: a preset's standing declaration + // covers every agent parented under it, and an agent's own (were one ever + // declared) would override its preset's. The mode decides what the model + // SEES, which is exactly the class of fact the chain inherits. + const layers = this.layers.chainLayers(scope); + for (let index = layers.length - 1; index >= 0; index -= 1) { + const mode = layers[index]?.mode; + if (mode !== undefined) + return mode; + } + return this.defaultMode; + } + /** + * The reserved `run_code` transport, built on first need. + * + * It never enters the global layer: per-agent restrictions must not remove + * it, and a scoped registration must not shadow it. The visibility resolver + * appends it after resolving the filterable global/scoped capability layers, + * and only for scopes whose mode actually presents it. + * @returns the shared transport definition. + */ + requireCodeTransport() { + this.codeTransport ??= createRunCodeTool(this, { + requireRuntime: () => this.requireCodeRuntime(this.defaultMode), + // The language-aware description/parameters getters read the runtime + // without demanding one, so a native-default process can still project + // the transport for an agent that chose code. + peekRuntime: () => this.ctx.get('codeRuntime'), + maxParallel: this.maxParallelSubCalls, + shapeDispatchLog: dispatch => this.shapeDispatchLog(dispatch), + }); + return this.codeTransport; + } + /** + * Present the calling scope's tools in `mode` instead of the deployment + * default. Nearest scope on the chain wins, so a preset's standing + * declaration covers every agent joined under it. + * + * Scoped only, and one declaration per scope: this is how an agent preset + * composes Code Mode agents beside native ones in the same process, and a + * process-global override would be the `mode` config field instead. + * @param mode - the presentation the covered agents' models see. + * @returns the exact disposer that restores the deployment default. + */ + presentAs(mode) { + const ctx = this.ctx; + if (scopeOf(ctx) === undefined) { + throw new Error('tools.presentAs() requires a scoped context (agent.ctx): a context-global presentation is the `mode` config field on the tools row'); + } + const dispose = ctx.effect(function* () { + yield this.layers.effect(ctx, (layer) => { + if (layer.mode !== undefined) { + throw new Error(`tools.presentAs("${mode}") conflicts with "${layer.mode}" already declared for this scope; one composition selects one presentation`); + } + layer.mode = mode; + return () => { layer.mode = undefined; }; + }, { label: 'tools.presentAs()' }); + // The SDK and collapse sections are per scope for the same reason the + // mode is. Under a deployment that already defaults to a code mode this + // shadows the global registration with an identical body, which costs + // nothing and keeps one rule instead of a case analysis. + if (mode !== 'native') { + yield ctx.systemPrompt.section(this.collapseSection()); + yield ctx.systemPrompt.section(this.sdkSection()); + } + }.bind(this), 'tools.presentAs()'); + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous composite teardown; direct return preserves disposer identity + return dispose; + } + /** + * Build one scope's wire schemas and names for prompt-order validation. + * Restrictions do not make known tools invalid, but a mode collapse does. + */ + wireSchemas(scope) { + const view = this.view(scope); + const mode = this.modeFor(scope); + if (mode === 'native') { + const schemas = [...view.visible.values()].map(definition => this.schemaOf(definition, false)); + return { schemas, knownNames: [...view.knownNames] }; + } + // Validate the runtime language BEFORE projecting schemas: schemaOf reads + // run_code's language-aware description/parameters getters, whose own + // flavor-table guard would otherwise surface first. This keeps the + // renderer-table rejection the canonical assembly-time error for a + // language with no SDK renderer. + this.requireCodeRuntime(mode); + const schemas = [...view.visible.values()].map(definition => this.schemaOf(definition, false)); + if (mode === 'code') { + return { + schemas: schemas.filter(schema => schema.name === RUN_CODE_NAME), + knownNames: [RUN_CODE_NAME], + }; + } + return { schemas, knownNames: [...view.knownNames, RUN_CODE_NAME] }; + } + /** + * Resolve the code runtime or throw the actionable misconfiguration error. + * Read at use time (assembly / run_code execution), NOT via static + * `inject`: an inject entry would hold `ctx.tools` — and every tool plugin + * behind it — hostage to a code runtime existing even under `mode: + * 'native'` (the loop's optional-backend idiom, same as + * `sessionPersistence`). + * + * Assembly and `run_code` execution read separately, so the language is not + * bound to a request. Harmless while one published backend exists — both + * reads return the same flavor — but a reload that swapped in a second + * language between them would hand a program written against one SDK to the + * other. Binding it is deferred until a second backend ships (the first + * point it is testable); rationale in the + * [language-dispatch note](../../../../.agents/notes/implemented/feature/2026-07-31-code-mode-language-dispatch.md). + */ + requireCodeRuntime(mode) { + const runtime = this.ctx.get('codeRuntime'); + if (!runtime) { + throw new Error(`dsh-tools: mode "${mode}" requires a code runtime — load a ctx.codeRuntime implementation (e.g. @deepseek-ai/dsh-code-runtime-worker-thread) or set tools mode to "native"`); + } + if (!Object.hasOwn(SDK_RENDERERS, runtime.language)) { + const known = Object.keys(SDK_RENDERERS).map(name => JSON.stringify(name)).join(', '); + throw new Error(`dsh-tools: no SDK renderer registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`); + } + return runtime; + } + /** + * Register globally or in the calling agent scope. Scoped tools shadow + * globals; duplicates within one layer and the reserved `run_code` name fail. + * @param definition - tool schema, execution, and optional finalization/presentation callbacks. + * @returns the exact disposer that unregisters the tool. + */ + register(definition) { + const name = definition.name; + const output = definition.output; + if (output === undefined || typeof output !== 'object' + || typeof output.render !== 'function' + || (output.presentationMeta !== undefined && typeof output.presentationMeta !== 'function')) { + throw new TypeError(`tool "${name}" must declare output { schema, render, presentationMeta? }`); + } + assertSupportedJsonSchema(output.schema); + const timeoutMs = definition.timeoutMs; + if (timeoutMs !== undefined + && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) { + throw new TypeError(`tool "${name}" timeoutMs must be a positive finite number`); + } + // Reserved unconditionally: any agent may select a code mode for itself, + // so a name free to take under the deployment default would become a + // collision the moment a preset mounted. + if (name === RUN_CODE_NAME) { + throw new Error(`tool name "${RUN_CODE_NAME}" is reserved for the Code Mode presentation transport and cannot be registered or shadowed`); + } + return this.layers.effect(this.ctx, layer => layer.tools.insert(name, definition), { label: 'tools.register()' }); + } + /** + * Restrict global tools for the calling agent scope. Empty filters, unknown + * names, scope-local names, and reserved transport names fail. Restrictions + * intersect; scoped registrations remain visible. + * @param filter - global-tool mask: `allow` (keep only) and/or `deny` (remove). + * @returns the exact disposer that lifts this restriction. + */ + restrict(filter) { + const scope = scopeOf(this.ctx); + if (scope === undefined) { + throw new Error('tools.restrict() requires a scoped context (agent.ctx): a context-global restriction would mask every agent — deny the tool for the intended agent instead'); + } + const allow = filter.allow; + const deny = filter.deny; + if (allow === undefined && deny === undefined) { + throw new Error('tools.restrict({}) is a no-op: pass `allow` and/or `deny` (an empty filter is almost always a materialized-empty-config bug)'); + } + const compiled = { + ...allow !== undefined ? { allow: new Set(allow) } : {}, + ...deny !== undefined ? { deny: new Set(deny) } : {}, + }; + if ([...allow ?? [], ...deny ?? []].includes(RUN_CODE_NAME)) { + throw new Error(`tools.restrict() cannot name reserved Code Mode presentation transport "${RUN_CODE_NAME}"; restrict end-capability tools instead`); + } + const known = this.view(scope).restrictableNames; + const unknown = [...allow ?? [], ...deny ?? []].filter(name => !known.has(name)); + if (unknown.length > 0) { + throw new Error(`tools.restrict() names unknown global tool${unknown.length > 1 ? 's' : ''} ${unknown.map(n => `"${n}"`).join(', ')}; known global tools: ${[...known].sort().join(', ') || '(none)'}`); + } + return this.layers.effect(this.ctx, layer => layer.restrictions.append(compiled), { label: 'tools.restrict()' }); + } + /** + * Register a monotonic guard after the extensible `tools/pre-execute` + * waterfall. A plain-context guard applies globally; one registered through + * `agent.ctx` applies only to that agent. Any matching guard may deny by + * returning a reason, while no guard can force-allow a call another guard + * denied. The exact effect disposer is returned for ordered ownership and + * HMR cleanup. + * @param guard - synchronous check; a returned string denies the execution. + * @returns the exact disposer that unregisters the guard. + */ + guard(guard) { + return this.layers.effect(this.ctx, layer => layer.guards.append(guard), { label: 'tools.guard()', notify: false }); + } + /** First monotonic denial from the global then the scope chain's guard layers, farthest first. */ + guardReason(exec) { + const globalReason = this.layers.global.guardReason(exec); + if (globalReason !== undefined) + return globalReason; + if (exec.agent === undefined) + return undefined; + for (const layer of this.layers.chainLayers(exec.agent)) { + const reason = layer.guardReason(exec); + if (reason !== undefined) + return reason; + } + return undefined; + } + /** + * Resolve every registry fact one scope needs in one layer traversal. The + * visible map applies restrictions to the INHERITED surface, then the + * scope's own registrations and the reserved presentation transport; the + * other sets retain the pre-restriction facts needed by restriction and + * prompt-order validation. + * + * A restriction filters what a scope inherits — the global layer and every + * ancestor layer on its chain — and never what its OWN layer registers. + * That exemption is what a per-child capability filter has to keep intact: + * the delegation runtime registers a child's reporting and structured-output + * tools into the child's own layer, and a filter naming the capabilities the + * child may use must not strip the machinery it answers through. + * + * Reading the exempt set as "the global layer" instead of "not mine" held + * only while every model-facing tool sat in the host composition. Once + * presets moved them onto the agent plane they became an ANCESTOR + * contribution, so a child's filter silently stopped constraining anything + * it was given. + * @param scope - the viewing scope (the agent), or undefined for the global view. + * @returns the complete derived view for that scope. + */ + view(scope) { + // Scope-chain layers, farthest ancestor first, the exact scope last. + const layers = this.layers.chainLayers(scope); + // Chain-blind on purpose: this is the ONE layer whose registrations the + // scope owns rather than inherits, and it is absent until the scope + // contributes something. + const own = this.layers.peek(scope); + // Inherited surface, nearest ancestor last: a nearer scope's same-name + // entry shadows a farther one, and the global layer is the farthest. + const inherited = new Map(this.layers.global.tools.entries()); + for (const layer of layers) { + if (layer === own) + continue; + for (const [name, definition] of layer.tools.entries()) + inherited.set(name, definition); + } + const visible = new Map(); + const knownNames = new Set(); + const restrictableNames = new Set(); + for (const [name, definition] of inherited) { + knownNames.add(name); + restrictableNames.add(name); + // Restrictions intersect across the whole chain: any scope on it may + // mask an inherited name for everything nested inside it. + if (layers.every(layer => layer.admits(name))) + visible.set(name, definition); + } + // The scope's own registrations last, shadowing an inherited name and + // outside the filter above. + if (own !== undefined) { + for (const [name, definition] of own.tools.entries()) { + knownNames.add(name); + visible.set(name, definition); + } + } + // Presentation infrastructure is resolved last and outside capability + // filtering. Registration rejects this reserved name, so the insertion is + // an invariant assertion as well as protection against future layer + // changes. Per scope: a native agent must not find `run_code` in its + // dispatch table because some other agent in the process presents it. + if (this.modeFor(scope) !== 'native') { + visible.set(RUN_CODE_NAME, this.requireCodeTransport()); + } + return { visible, knownNames, restrictableNames }; + } + /** + * Look up a tool as one scope sees it (scoped + * shadows global; a restricted-away global reads as absent). Presenters pass + * the calling agent so the rendered card matches the definition that + * actually executed. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns the definition the scope resolves, or undefined when none is visible. + */ + get(name, scope) { + return this.view(scope).visible.get(name); + } + /** + * Resolve the definition that MAY EXECUTE for a call, applying the mode + * collapse at the operation boundary that owns it. The registry view + * (`get`) is presentation-agnostic; here a MODEL-DIRECT call under `code` + * may only name the reserved `run_code` transport, while a nested + * sub-dispatch (a `parent` token set — the `run_code` SDK calling a tool + * it bound) may call any visible tool. Denial surfaces as `UNKNOWN_TOOL` + * through the executor, matching an absent definition. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + * @returns the definition that may run, or undefined when the call must be rejected. + */ + resolveExecution(name, scope, nested) { + const tool = this.get(name, scope); + if (tool === undefined) + return undefined; + if (this.collapses(name, scope, nested)) + return undefined; + return tool; + } + /** + * Project visible definitions onto the allowlisted model-facing schema fields, + * excluding execution and presentation callbacks. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns one deep-cloned schema per visible tool. + */ + schemas(scope) { + return [...this.view(scope).visible.values()].map(definition => this.schemaOf(definition, true)); + } + /** Project visible callable tools onto the generated Code Mode SDK contract. */ + sdkSchemas(scope) { + return [...this.view(scope).visible.values()] + .filter(definition => definition.name !== RUN_CODE_NAME) + .map((definition) => { + const output = snapshotJsonValue(definition.output.schema); + /* v8 ignore next -- registration already validated and retained this schema as lossless JSON. */ + if (output === undefined) { + throw new Error(`tool "${definition.name}" output schema must be lossless JSON before SDK projection`); + } + return { + ...this.schemaOf(definition, true), + output, + }; + }); + } + /** Project one definition onto the model-facing schema fields. */ + schemaOf(definition, detachParameters) { + const { name, description, parameters } = definition; + const detached = detachParameters ? snapshotJsonValue(parameters) : parameters; + if (detached === undefined) { + throw new Error(`tool "${name}" parameters must be lossless JSON before schema projection`); + } + return { + name, + description, + parameters: detached, + }; + } + /** + * Classify a pending call through the caller's visible tool definition. Only + * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or + * throwing classifiers are exclusive. + * @param exec - call name, parsed arguments, and optional agent scope. + * @returns the fail-closed scheduling mode. + */ + executionMode(exec) { + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined); + if (!tool?.isConcurrencySafe) + return { kind: 'exclusive' }; + try { + const concurrencySafe = tool.isConcurrencySafe(exec.arguments); + return concurrencySafe === true ? { kind: 'parallel' } : { kind: 'exclusive' }; + } + catch { + return { kind: 'exclusive' }; + } + } + /** + * Run the `tools/code-dispatch-log` waterfall over one settled sub-dispatch + * and return the content the bridge should log on `tool/code-dispatch`. + * Contained: when a listener throws, the method logs the original settled + * content; that failure must not fail the dispatch or omit the settle event. Private: + * the ONE consumer is the `run_code` bridge this registry constructs, which + * receives it as a capability parameter (the `requireRuntime` idiom) — the + * waterfall, not this invoker, is the public extension point. + */ + async shapeDispatchLog(dispatch) { + try { + return await this.ctx.waterfall(scopeTarget(this, dispatch.agent), 'tools/code-dispatch-log', dispatch, () => Promise.resolve(dispatch.content)); + } + catch (error) { + this.ctx.logger.warn(`tools: code-dispatch-log listener failed for ${dispatch.name}: ${errorMessage(error)}; logging the original settled content`); + return dispatch.content; + } + } + /** + * Whether the `code` mode collapse denies a model-direct call: only the + * reserved `run_code` transport may be named. Nested sub-dispatches (a + * `parent` token set) bypass the collapse. One home for the + * security-relevant predicate, shared by {@link resolveExecution} and + * {@link createExecution} so the two can never drift apart. + * + * Resolved through {@link modeFor}, NOT `defaultMode`: an agent given `code` + * by an agent preset under a native deployment is the composition + * `dsh-agent-tool-presentation` exists for, and reading the deployment default would + * leave exactly that agent uncollapsed — announcing one surface while + * executing another, which is the bypass this collapse closes. + * @param name - the tool name as registered. + * @param scope - the viewing scope whose effective presentation mode applies. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + */ + collapses(name, scope, nested) { + return !nested && this.modeFor(scope) === 'code' && name !== RUN_CODE_NAME; + } + /** + * Execute through pre-policy, guards, around-dispatch, post-policy, + * definition-owned content finalization, and final notification. Tool and + * listener failures resolve as materialized error results; an invisible tool + * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen + * snapshot final observers receive. Cancellation + * arriving after entry and before final result materialization skips a + * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a + * successful started outcome with `ABORTED`; already-started work is still + * drained and may retain a tool-owned structured error. + * @param exec - the typed same-process call input. The registry assigns its + * correlation token before policy begins. + * @returns the materialized final result. + */ + async execute(exec) { + return this.prepareExecution(exec, prepared => this.completeScheduledExecution(prepared)); + } + async completeScheduledExecution(prepared) { + switch (prepared.kind) { + case 'dispatch': { + const dispatched = await this.dispatchScheduledExecution(prepared.exec); + return dispatched.kind === 'post-result' + ? await this.finalizeScheduledExecution(prepared.exec, dispatched.result) + : this.finishScheduledExecution(prepared.exec, dispatched.result); + } + case 'post-result': + return await this.finalizeScheduledExecution(prepared.exec, prepared.result); + case 'final-result': + return this.finishScheduledExecution(prepared.exec, prepared.result); + /* v8 ignore next -- closed-union exhaustiveness guard */ + default: + return assertNever(prepared, 'scheduled tool preparation'); + } + } + createExecution(exec) { + const deferredContexts = []; + const token = createExecutionToken(); + const callId = exec.callId; + const rootCallId = exec.rootCallId ?? callId; + const name = exec.name; + const agent = exec.agent; + const parent = exec.parent; + const signal = exec.signal; + // Distinguish a mode-collapsed call (visible in the scope, denied only by + // the `code` collapse) from a genuinely unknown tool. A collapsed call is + // deterministically denied, so it terminates BEFORE the extensible policy + // pipeline: pre-execute listeners, approval `ask`, and guards must never + // observe — or worse, approve — a call that can only fail. An unknown tool + // keeps the historical dispatch-stage `UNKNOWN_TOOL` path so policy + // listeners still see every name that reaches the registry. + const visible = this.get(name, agent); + const collapsed = visible !== undefined && this.collapses(name, agent, parent !== undefined); + const concludingExecutions = this.concludingExecutions; + const base = { + token, + callId, + rootCallId, + name, + signal, + ...agent !== undefined ? { agent } : {}, + ...parent !== undefined ? { parent } : {}, + deferContext(context) { + deferredContexts.push(context); + }, + concludeTurn() { + concludingExecutions.add(this); + }, + }; + // Capture the finalizer BEFORE argument materialization: the + // `finalizeContent` contract snapshots the callback when the call starts, + // and an arguments getter can replace or clear the registered callback + // during `snapshotJsonValue`. The collapse only decides whether the + // CAPTURED callback is retained: the pre-dispatch abort path keeps it + // (the cancellation contract routes aborted results through it — a getter + // that aborts mid-materialization before an invalid-args failure lands in + // the same retained path), while the `UNKNOWN_TOOL` denial and the + // invalid-args failure of a NON-ABORTED collapsed call drop it (the call + // could never execute). + const capturedFinalizer = visible?.finalizeContent?.bind(visible); + const finalizerFor = () => collapsed && !signal.aborted ? undefined : capturedFinalizer; + try { + const detached = snapshotJsonValue(exec.arguments); + if (detached === undefined) { + throw new TypeError('tool execution arguments must be losslessly JSON-serializable'); + } + const execution = { ...base, arguments: deepFreeze(detached) }; + this.deferredContexts.set(execution, deferredContexts); + this.contentFinalizers.set(execution, finalizerFor()); + this.cancellationStates.set(execution, { + callerSignal: signal, + bodyInvoked: false, + }); + if (collapsed) { + // The collapse denies the call before the policy pipeline, but a + // pre-dispatch abort still keeps the established cancellation + // contract: `prepare`'s caller-cancellation check is skipped for + // final-results, so honor the abort here instead of surfacing + // `UNKNOWN_TOOL` on an already-cancelled call. + if (signal.aborted) { + return { kind: 'final-result', exec: execution, result: toolAbortedBeforeDispatchResult() }; + } + // The name IS visible here, so the denial carries the route the model + // must take instead. Without it the model reads a bare `unknown tool` + // for a tool the prompt just declared and concludes the deployment is + // broken rather than correcting itself. + return { + kind: 'final-result', + exec: execution, + result: toolErrorResult(new ToolNotFoundError(name, `only \`${RUN_CODE_NAME}\` is callable directly — call \`${name}\` from inside a \`${RUN_CODE_NAME}\` program instead`)), + }; + } + return { kind: 'ready', exec: execution }; + } + catch (error) { + const execution = { ...base, arguments: undefined }; + this.contentFinalizers.set(execution, finalizerFor()); + return { kind: 'final-result', exec: execution, result: toolErrorResult(error) }; + } + } + /** + * Run the ordered pre-execute and monotonic guard stages for the scheduler. + * @param input - the caller-supplied execution input. + * @returns the prepared execution plus the next scheduler stage. + * @internal + */ + async prepareScheduledExecution(input) { + return this.prepareExecution(input, prepared => prepared); + } + async prepareExecution(input, next) { + const created = this.createExecution(input); + if (created.kind !== 'ready') + return next(created); + const exec = created.exec; + if (this.callerCancelled(exec)) { + return next({ kind: 'final-result', exec, result: toolAbortedBeforeDispatchResult() }); + } + try { + const carrier = scopeTarget(this, exec.agent); + const gate = await this.ctx.waterfall(carrier, 'tools/pre-execute', exec, () => Promise.resolve({ kind: 'allow' })); + const askResolution = gate.kind === 'ask' + ? await this.serviceAsk(exec, gate) + : { decision: gate, approvalCancelled: false }; + const { decision } = askResolution; + if (this.callerCancelled(exec) && askResolution.approvalCancelled) { + return await next({ kind: 'post-result', exec, result: toolAbortedBeforeDispatchResult() }); + } + const denialReason = decision.kind === 'allow' + ? this.guardReason(exec) + : decision.reason; + if (denialReason !== undefined) { + return await next({ + kind: 'post-result', + exec, + result: this.materializeFinalResult({ + content: [{ type: 'text', text: `Error: ${denialReason}` }], + isError: true, + error: { message: denialReason }, + }), + }); + } + if (this.callerCancelled(exec)) { + return await next({ kind: 'post-result', exec, result: toolAbortedBeforeDispatchResult() }); + } + return await next({ kind: 'dispatch', exec }); + } + catch (error) { + return next({ kind: 'final-result', exec, result: toolErrorResult(error) }); + } + } + /** Whether the original caller signal is currently aborted. */ + callerCancelled(exec) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === undefined) + throw new Error('tool registry scheduler invariant violated: missing cancellation state'); + return state.callerSignal.aborted; + } + /** Canonical cancellation outcome selected by whether the tool body started. */ + cancellationResult(exec, prior) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === undefined) + throw new Error('tool registry scheduler invariant violated: missing cancellation state'); + return state.bodyInvoked + ? toolAbortedResult(prior) + : toolAbortedBeforeDispatchResult(prior); + } + /** + * Dispatch the registered body with the original caller signal fused back + * into any around-wrapper replacement. Cancellation never abandons the body: + * a started promise reaches quiescence before its outcome becomes `ABORTED`. + */ + async dispatchToolBody(exec) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === undefined) + throw new Error('tool registry scheduler invariant violated: missing cancellation state'); + const wrapperSignal = exec.signal; + const fused = fuseToolSignals(state.callerSignal, wrapperSignal); + const signal = fused.signal; + if (isAborted(signal)) { + fused.dispose(); + return toolAbortedBeforeDispatchResult(); + } + exec.signal = signal; + try { + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined); + if (!tool) + throw new ToolNotFoundError(exec.name); + state.bodyInvoked = true; + const returned = await tool.execute(exec.arguments, exec); + const result = this.createSuccessResult(exec, tool, returned); + return isAborted(signal) + ? toolAbortedResult(result) + : result; + } + catch (error) { + return toolErrorResult(error); + } + finally { + fused.dispose(); + exec.signal = wrapperSignal; + } + } + /** + * Run around-dispatch and the tool body. Tool and unknown-tool failures still + * receive post-execute; pipeline failures are already final. + * @param exec - the prepared execution. + * @returns whether the result still needs post-execute. + * @internal + */ + async dispatchScheduledExecution(exec) { + try { + const mutableExec = exec; + const carrier = scopeTarget(this, exec.agent); + const result = await this.ctx.waterfall(carrier, 'tools/execute', mutableExec, () => this.dispatchToolBody(mutableExec)); + const normalized = this.normalizeDispatchResult(exec, result); + const deferredContexts = this.deferredContexts.get(exec); + /* v8 ignore next -- dispatch only receives executions minted by this registry's prepare stage */ + if (deferredContexts === undefined) + throw new Error('tool registry scheduler invariant violated: unprepared execution'); + const resultWithDeferredContexts = deferredContexts.length === 0 + ? normalized + : this.markCanonical(exec, { + ...normalized, + additionalContexts: [ + ...deferredContexts, + ...normalized.additionalContexts ?? [], + ], + }); + return { + kind: 'post-result', + result: this.callerCancelled(exec) && !resultWithDeferredContexts.isError + ? this.cancellationResult(exec, resultWithDeferredContexts) + : resultWithDeferredContexts, + }; + } + catch (error) { + return { kind: 'final-result', result: toolErrorResult(error) }; + } + } + /** + * Run ordered post-execute, then apply definition-owned content finalization, + * materialize, and notify the final outcome. + * @param exec - the prepared execution. + * @param result - dispatch/pre result that still needs post-execute. + * @returns the materialized final result. + * @internal + */ + async finalizeScheduledExecution(exec, result) { + try { + const postResult = await this.postExecute(exec, result); + return this.finishScheduledExecution(exec, this.callerCancelled(exec) && !postResult.isError + ? this.cancellationResult(exec, postResult) + : postResult); + } + catch (error) { + return this.finishScheduledExecution(exec, toolErrorResult(error)); + } + } + /** + * Materialize the candidate, apply definition-owned content finalization, + * then materialize and notify the authoritative result. + * @param exec - the prepared execution. + * @param result - final result. + * @returns the materialized final result. + * @internal + */ + finishScheduledExecution(exec, result) { + let materializedResult; + try { + materializedResult = this.materializeFinalResult(result); + } + catch (error) { + materializedResult = this.materializeFinalResult(toolErrorResult(error)); + } + let finalResult; + try { + finalResult = this.materializeFinalResult(this.applyFinalContent(exec, materializedResult)); + } + catch (error) { + finalResult = this.materializeFinalResult(toolErrorResult(error)); + } + this.notifyResult(exec, finalResult); + return finalResult; + } + /** Apply the snapshotted tool-owned content transform without exposing other result fields. */ + applyFinalContent(exec, result) { + const finalizeContent = this.contentFinalizers.get(exec); + if (finalizeContent === undefined) + return result; + const content = finalizeContent(exec, result); + return content === undefined ? result : { ...result, content }; + } + /** Notify observers without exposing a mutation or error channel into the outcome. */ + notifyResult(exec, result) { + // Freeze the registry's live object before observers receive its readonly + // WeakMap-keyable view. + Object.freeze(exec); + const { name: toolName, callId } = exec; + const reportFailure = (error) => { + this.ctx.logger.warn(`tool "${toolName}" (${callId}): tools/result observer failed: ${errorMessage(error)}`); + }; + const callbacks = this.ctx.events.dispatch('emit', [ + scopeTarget(this, exec.agent), 'tools/result', exec, result, + ]); + for (const callback of callbacks) { + try { + const returned = callback(exec, result); + void Promise.resolve(returned).catch(reportFailure); + } + catch (error) { + reportFailure(error); + } + } + } + /** + * Resolve an `ask` decision to allow/deny through the approval seam. The + * seam is consumed opportunistically with `ctx.get('approval')` — a + * deployment that composes no ApprovalService keeps the historical degrade + * to deny, and an unmount mid-session degrades the same way on the next ask. + * An agent-less execution also degrades: without an agent there is no + * session to audit to and no UI to route to. Otherwise the outcome maps + * one-to-one — `allowed-once` proceeds; the three non-grants deny with + * distinct reasons so the model can tell a human "no" from an absent + * approval channel. + */ + async serviceAsk(exec, ask) { + const approval = this.ctx.get('approval'); + if (approval === undefined) { + return { + decision: { kind: 'deny', reason: ask.reason ?? `tool "${exec.name}" requires approval (not yet supported)` }, + approvalCancelled: false, + }; + } + if (exec.agent === undefined) { + return { + decision: { kind: 'deny', reason: `tool "${exec.name}" requires approval, but the call has no agent to route it through` }, + approvalCancelled: false, + }; + } + const outcome = await approval.request({ + agent: exec.agent, + toolName: exec.name, + callId: exec.callId, + ...ask.reason !== undefined ? { reason: ask.reason } : {}, + signal: exec.signal, + }); + switch (outcome) { + case 'allowed-once': return { decision: { kind: 'allow' }, approvalCancelled: false }; + case 'rejected': return { + decision: { kind: 'deny', reason: `the user rejected tool "${exec.name}"` }, + approvalCancelled: false, + }; + case 'cancelled': return { + decision: { kind: 'deny', reason: `approval for tool "${exec.name}" was cancelled` }, + approvalCancelled: true, + }; + case 'unavailable': return { + decision: { kind: 'deny', reason: `tool "${exec.name}" requires approval, but no approval channel is available` }, + approvalCancelled: false, + }; + default: return assertNever(outcome, 'ApprovalOutcome'); + } + } + /** + * Run the `tools/post-execute` waterfall over a dispatched `result` and apply + * its {@link PostToolDecision}: `accept` keeps the call successful (replacing + * `content` when given), `block` turns it into an `isError` whose content is + * the corrective `feedback`. Either decision may attach `additionalContexts`, + * which are ferried on the returned result for the loop's active-batch FIFO. + * Context deferred by the tool body survives an accepted result but is + * discarded when the outer call is blocked; a block exposes only context the + * blocking decision explicitly supplied. + * Runs inside `execute`'s outer try/catch (a throwing listener → isError). + */ + async postExecute(exec, result) { + const decision = await this.ctx.waterfall(scopeTarget(this, exec.agent), 'tools/post-execute', exec, result, () => Promise.resolve({ kind: 'accept' })); + const decisionContexts = decision.additionalContexts ?? []; + if (decision.kind === 'block') { + const message = failureMessageFromContent(decision.feedback); + return this.markCanonical(exec, { + content: decision.feedback, + isError: true, + error: { message }, + ...decisionContexts.length > 0 ? { additionalContexts: decisionContexts } : {}, + }); + } + if (Object.hasOwn(decision, 'content') && Object.hasOwn(decision, 'value')) { + throw new TypeError('tools/post-execute accept decision cannot replace both value and content'); + } + const additionalContexts = [ + ...result.additionalContexts ?? [], + ...decisionContexts, + ]; + if (Object.hasOwn(decision, 'value')) { + if (result.isError) { + throw new TypeError('tools/post-execute cannot replace the value of a failed result'); + } + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined); + if (tool === undefined) + throw new ToolNotFoundError(exec.name); + const replaced = this.createSuccessResult(exec, tool, decision.value); + return this.markCanonical(exec, { + ...replaced, + ...additionalContexts.length > 0 ? { additionalContexts } : {}, + }); + } + return this.markCanonical(exec, { + ...result, + ...decision.content !== undefined ? { content: decision.content } : {}, + ...additionalContexts.length > 0 ? { additionalContexts } : {}, + }); + } + /** Registry-normalized results and the exact dispatch that validated each value. */ + canonicalResults = new WeakMap(); + /** Mark one registry-normalized result as canonical only for its owning dispatch. */ + markCanonical(exec, result) { + this.canonicalResults.set(result, exec.token); + return result; + } + /** Snapshot, validate, render, and optionally project one successful body value. */ + createSuccessResult(exec, tool, candidate) { + const detached = snapshotToolValue(tool.name, candidate); + const violations = validateJsonSchemaValue(tool.output.schema, detached, 'value'); + if (violations.length > 0) + throw new ToolOutputError(tool.name, violations); + const value = deepFreeze(detached); + let rendered; + try { + rendered = tool.output.render(exec.arguments, value); + } + catch (error) { + throw projectionError(tool.name, 'render', error); + } + const content = snapshotProjection(tool.name, 'render', rendered); + let meta; + if (exec.parent === undefined && tool.output.presentationMeta !== undefined) { + let projected; + try { + projected = tool.output.presentationMeta(exec.arguments, value); + } + catch (error) { + throw projectionError(tool.name, 'presentationMeta', error); + } + meta = snapshotProjection(tool.name, 'presentationMeta', projected); + } + const concludesTurn = this.concludingExecutions.has(exec); + return this.markCanonical(exec, this.materializeFinalResult({ + isError: false, + value, + content, + ...meta !== undefined ? { meta } : {}, + ...concludesTurn ? { concludesTurn: true } : {}, + })); + } + /** Normalize an around-dispatch wrapper's authored result through the owning output contract. */ + normalizeDispatchResult(exec, result) { + if (this.canonicalResults.get(result) === exec.token) + return result; + if (result.isError) { + return this.markCanonical(exec, { + isError: true, + error: result.error, + content: result.content, + ...result.meta !== undefined ? { meta: result.meta } : {}, + ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, + }); + } + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined); + if (tool === undefined) + throw new ToolNotFoundError(exec.name); + const normalized = this.createSuccessResult(exec, tool, result.value); + return this.markCanonical(exec, { + ...normalized, + ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, + }); + } + /** Materialize the authoritative commit outcome once, immediately before `tools/result`. */ + materializeFinalResult(result) { + const presentation = { + content: result.content, + ...result.meta !== undefined ? { meta: result.meta } : {}, + ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, + }; + if (result.isError) { + return materializePresentation({ isError: true, error: result.error, ...presentation }); + } + const detached = materializePresentation({ + isError: false, + ...presentation, + ...result.concludesTurn === true ? { concludesTurn: true } : {}, + }); + return deepFreeze({ ...detached, value: result.value }); + } +} +/** Mint a same-process correlation token whose identity is its value. */ +function createExecutionToken() { + return Symbol('dsh.tool.execution'); +} +function toolErrorResult(error) { + const info = errorInfo(error); + const message = errorMessage(error); + return { + content: [{ type: 'text', text: `Error: ${message}` }], + isError: true, + error: { message, ...info ? { info } : {} }, + }; +} +/** Read live abort state across an await without treating it as synchronously immutable. */ +function isAborted(signal) { + return signal.aborted; +} +/** + * Fuse caller and wrapper cancellation without nesting `AbortSignal.any`. + * Keeping the relay dispatch-scoped also removes listeners when work settles. + */ +function fuseToolSignals(caller, wrapper) { + if (caller === wrapper) + return { signal: caller, dispose() { } }; + const controller = new AbortController(); + let listening = false; + const dispose = () => { + if (!listening) + return; + listening = false; + caller.removeEventListener('abort', abortFromCaller); + wrapper.removeEventListener('abort', abortFromWrapper); + }; + const abortFrom = (source) => { + const reason = source.reason; + controller.abort(reason); + dispose(); + }; + const abortFromCaller = () => { abortFrom(caller); }; + const abortFromWrapper = () => { abortFrom(wrapper); }; + if (wrapper.aborted) + abortFromWrapper(); + else if (caller.aborted) + abortFromCaller(); + else { + listening = true; + caller.addEventListener('abort', abortFromCaller, { once: true }); + wrapper.addEventListener('abort', abortFromWrapper, { once: true }); + } + return { signal: controller.signal, dispose }; +} +/** Canonical result when cancellation supersedes success after body invocation. */ +function toolAbortedResult(prior) { + const additionalContexts = prior?.additionalContexts ?? []; + return { + content: [{ type: 'text', text: 'Error: tool call aborted' }], + isError: true, + error: { + message: 'tool call aborted', + info: { name: 'AbortError', code: TOOL_ABORTED }, + }, + ...additionalContexts.length > 0 ? { additionalContexts } : {}, + }; +} +/** Canonical result when cancellation prevents tool body invocation. */ +function toolAbortedBeforeDispatchResult(prior) { + const additionalContexts = prior?.additionalContexts ?? []; + return { + content: [{ type: 'text', text: 'Error: tool call aborted before dispatch' }], + isError: true, + error: { + message: 'tool call aborted before dispatch', + info: { name: 'AbortError', code: TOOL_ABORTED_BEFORE_DISPATCH }, + }, + ...additionalContexts.length > 0 ? { additionalContexts } : {}, + }; +} +export default ToolRuntime; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.d.ts new file mode 100644 index 0000000..ea7bdb3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned tool-pipeline invariants. @module @deepseek-ai/dsh-tools/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "tools-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the tools invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.js new file mode 100644 index 0000000..6002429 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.js @@ -0,0 +1,123 @@ +/** Package-owned tool-pipeline invariants. @module @deepseek-ai/dsh-tools/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-tools'; +/** Cordis companion plugin name. */ +export const name = 'tools-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Validate the immutable final execution/result snapshot. */ +function validateResult(exec, result, fail) { + if (!Object.isFrozen(exec)) + fail('tools/result execution must be frozen before publication'); + if (!Object.isFrozen(result) || !Object.isFrozen(result.content)) { + fail('tools/result outcome and content must be frozen before publication'); + } + if (exec.name.length === 0 || String(exec.callId).length === 0) { + fail('tools/result execution must carry non-empty name and callId'); + } +} +/** Install monotonic pipeline, final-snapshot, and code-dispatch enclosure checks. */ +const install = Object.assign((ctx, fail) => { + const stages = new WeakMap(); + const openTurns = new WeakMap(); + const dispatchRoots = new WeakMap(); + const validateDispatch = (session, event) => { + if (event.type !== 'tool/code-dispatch-start' && event.type !== 'tool/code-dispatch') + return; + const root = String(event.data.rootCallId); + const parent = String(event.data.parentCallId); + const child = String(event.data.subCallId); + if (root.length === 0 || parent.length === 0 || child.length === 0) { + fail(`${event.type} must carry non-empty rootCallId, parentCallId, and subCallId`); + return; + } + const roots = dispatchRoots.get(session); + const known = roots?.get(child); + if (known !== undefined && known !== root) + fail(`${event.type} changed rootCallId for subCallId ${child}`); + if (parent !== root && roots?.get(parent) !== root) { + fail(`${event.type} parentCallId ${parent} does not belong to rootCallId ${root}`); + } + }; + const commitDispatch = (session, event) => { + if (event.type !== 'tool/code-dispatch-start' && event.type !== 'tool/code-dispatch') + return; + const roots = dispatchRoots.get(session); + roots.set(String(event.data.subCallId), String(event.data.rootCallId)); + }; + const seed = (session) => { + let openTurn = null; + dispatchRoots.set(session, new Map()); + for (const event of session.events) { + validateDispatch(session, event); + commitDispatch(session, event); + if (event.type === 'turn/start') + openTurn = event.data.turn; + else if (event.type === 'turn/end') + openTurn = null; + else if ((event.type === 'tool/code-dispatch-start' || event.type === 'tool/code-dispatch') + && openTurn === null) { + fail(`${event.type} appended outside any open turn`); + } + } + openTurns.set(session, openTurn); + return openTurn; + }; + const openTurnFor = (session) => openTurns.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) + seed(session); + ctx.on('session/created', (session) => { seed(session); }, { global: true }); + ctx.on('session/event', (session, event) => { + validateDispatch(session, event); + commitDispatch(session, event); + if (event.type === 'turn/start') + openTurns.set(session, event.data.turn); + else if (event.type === 'turn/end') + openTurns.set(session, null); + }, { global: true }); + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName === 'session/event') { + const [session, event] = args; + validateDispatch(session, event); + if ((event.type === 'tool/code-dispatch-start' || event.type === 'tool/code-dispatch') + && openTurnFor(session) === null) { + fail(`${event.type} appended outside any open turn`); + } + return; + } + if (eventName === 'tools/pre-execute') { + const exec = args[0]; + if (stages.has(exec)) + fail('tools/pre-execute repeated for one execution'); + stages.set(exec, 'pre'); + return; + } + if (eventName === 'tools/execute') { + const exec = args[0]; + if (stages.get(exec) !== 'pre') + fail('tools/execute must follow tools/pre-execute'); + stages.set(exec, 'execute'); + return; + } + if (eventName === 'tools/post-execute') { + const exec = args[0]; + const previous = stages.get(exec); + if (previous !== 'pre' && previous !== 'execute') { + fail('tools/post-execute must follow tools/pre-execute or tools/execute'); + } + stages.set(exec, 'post'); + return; + } + if (eventName !== 'tools/result') + return; + const [exec, result] = args; + validateResult(exec, result, fail); + stages.delete(exec); + }, { global: true }); +}, { inject: ['sessions'] }); +/** + * Register the tools invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.d.ts new file mode 100644 index 0000000..399879a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.d.ts @@ -0,0 +1,106 @@ +/** + * Enforced JSON Schema subset shared by tool outputs, generated Code Mode + * types, subagents, and workflows. The subset accepts any JSON root, an + * annotation-only schema for unconstrained JSON, one scalar `type`, object + * `properties`/`required`/boolean `additionalProperties`, array `items`, + * type-correct scalar `enum`/`const`, and exact-one `oneOf`. + * + * Unsupported or misplaced keywords reject rather than being accepted without + * enforcement. Consumers that require an object root apply + * {@link assertObjectJsonSchema} before accepting input. + * @module dsh-tools/json-schema + */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import { type JsonValue } from '@deepseek-ai/dsh-session'; +/** Scalar JSON values supported by `enum` and `const`. */ +export type JsonSchemaScalar = string | number | boolean | null; +/** Single-type keywords accepted by the enforced subset. */ +export type JsonSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null'; +/** + * One raw JSON Schema node in the enforced subset. The optional fields express + * the external wire schema; {@link assertSupportedJsonSchema} rejects invalid + * combinations before a caller treats the node as trusted. + */ +export interface JsonSchemaNode { + /** Omit with no constraints for any JSON value, or use `oneOf`. */ + type?: JsonSchemaType; + /** Exactly one branch must validate; at least two branches are required. */ + oneOf?: JsonSchemaNode[]; + /** Nested property schemas (`type: 'object'` only). */ + properties?: Record; + /** Required property names; each must appear in `properties`. */ + required?: string[]; + /** `false` rejects undeclared keys; absent/`true` follows JSON Schema's open default. */ + additionalProperties?: boolean; + /** Item schema (`type: 'array'` only); absent accepts any JSON item. */ + items?: JsonSchemaNode; + /** Allowed values for a scalar node. */ + enum?: JsonSchemaScalar[]; + /** The single allowed value for a scalar node. */ + const?: JsonSchemaScalar; + /** Annotation, ignored for validation. */ + description?: string; + /** Annotation, ignored for validation. */ + title?: string; + /** Annotation, ignored for validation but required to be lossless JSON. */ + default?: JsonValue; + /** Annotation, ignored for validation but required to be lossless JSON. */ + examples?: JsonValue; +} +/** A consumer-constrained object-rooted schema. */ +export type ObjectJsonSchema = JsonSchemaNode & { + type: 'object'; +}; +/** + * Thrown when a raw schema falls outside the enforced subset. `violations` + * lists every offending path instead of stopping at the first author error. + */ +export declare class JsonSchemaError extends HarnessError { + /** Individual schema violations in walk order. */ + readonly violations: string[]; + constructor(violations: string[]); +} +/** + * Test for a realm-agnostic plain JSON record without accepting arrays or + * exotic objects. + * @param value - candidate record from any JavaScript realm. + * @returns Whether the value has a plain-object prototype chain. + */ +export declare function isPlainJsonRecord(value: unknown): value is Record; +/** + * Test for an ordinary schema record whose keys survive JSON projection. + * @param value - candidate record from any JavaScript realm. + * @returns Whether the record has an intrinsic prototype and only own enumerable string keys. + */ +export declare function isJsonSchemaRecord(value: unknown): value is Record; +/** + * Test for a dense ordinary array with no JSON-invisible decorations. + * @param value - candidate array from any JavaScript realm. + * @returns Whether the array is intrinsic, dense, and undecorated. + */ +export declare function isPlainJsonArray(value: unknown): value is unknown[]; +/** + * Assert that an arbitrary raw schema uses only the enforced subset. + * Annotation-only schemas are accepted as the standard unconstrained-JSON + * form; callers that require an object root use {@link assertObjectJsonSchema}. + * @param schema - untrusted raw JSON Schema. + * @returns Assertion that the schema belongs to the supported subset. + */ +export declare function assertSupportedJsonSchema(schema: unknown): asserts schema is JsonSchemaNode; +/** + * Assert the enforced subset plus the object-root constraint retained by + * subagent and workflow structured outputs. + * @param schema - untrusted caller-supplied schema. + * @returns Assertion that the schema belongs to the supported subset and has an object root. + */ +export declare function assertObjectJsonSchema(schema: unknown): asserts schema is ObjectJsonSchema; +/** + * Validate a candidate value against an asserted raw schema. The function is + * total for arbitrary values and returns path-qualified violations. + * @param schema - a schema accepted by {@link assertSupportedJsonSchema}. + * @param value - the candidate JSON value. + * @param path - root label used in diagnostics. + * @returns All violations in walk order; empty means valid. + */ +export declare function validateJsonSchemaValue(schema: JsonSchemaNode, value: unknown, path?: string): string[]; +//# sourceMappingURL=json-schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.js new file mode 100644 index 0000000..d6e9e1a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.js @@ -0,0 +1,577 @@ +/** + * Enforced JSON Schema subset shared by tool outputs, generated Code Mode + * types, subagents, and workflows. The subset accepts any JSON root, an + * annotation-only schema for unconstrained JSON, one scalar `type`, object + * `properties`/`required`/boolean `additionalProperties`, array `items`, + * type-correct scalar `enum`/`const`, and exact-one `oneOf`. + * + * Unsupported or misplaced keywords reject rather than being accepted without + * enforcement. Consumers that require an object root apply + * {@link assertObjectJsonSchema} before accepting input. + * @module dsh-tools/json-schema + */ +import { assertNever, HarnessError } from '@deepseek-ai/dsh-llm'; +import { isJsonValue } from '@deepseek-ai/dsh-session'; +/** + * Thrown when a raw schema falls outside the enforced subset. `violations` + * lists every offending path instead of stopping at the first author error. + */ +export class JsonSchemaError extends HarnessError { + /** Individual schema violations in walk order. */ + violations; + constructor(violations) { + super(`unsupported JSON schema: ${violations.join('; ')}`, 'UNSUPPORTED_SCHEMA'); + this.name = 'JsonSchemaError'; + this.violations = violations; + } +} +const CONSTRAINT_KEYWORDS = new Set([ + 'type', + 'oneOf', + 'properties', + 'required', + 'additionalProperties', + 'items', + 'enum', + 'const', +]); +const ANNOTATION_KEYWORDS = new Set(['description', 'title', 'default', 'examples']); +const SCHEMA_TYPES = ['object', 'array', 'string', 'number', 'integer', 'boolean', 'null']; +/* jscpd:ignore-start -- this realm boundary mirrors the session-owned lossless-JSON intrinsic test */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor'); + const constructor = descriptor?.value; + if (typeof constructor !== 'function') + return false; + try { + return constructor.name === name + && constructor.prototype === prototype + && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } + catch { + return false; + } +} +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value) { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, 'Object'); +} +/** + * Test for a realm-agnostic plain JSON record without accepting arrays or + * exotic objects. + * @param value - candidate record from any JavaScript realm. + * @returns Whether the value has a plain-object prototype chain. + */ +export function isPlainJsonRecord(value) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) + return false; + try { + const prototype = Object.getPrototypeOf(value); + return prototype === null + || typeof prototype === 'object' && isIntrinsicObjectPrototype(prototype); + } + catch { + return false; + } +} +/** Whether an array uses one realm's intrinsic `Array.prototype`. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) + return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === 'object' + && objectPrototype !== null + && isIntrinsicObjectPrototype(objectPrototype); +} +/* jscpd:ignore-end */ +/** Return whether a record contains only own enumerable string keys. */ +function hasOnlyEnumerableStringKeys(value) { + try { + return Reflect.ownKeys(value) + .every(key => typeof key === 'string' && Object.prototype.propertyIsEnumerable.call(value, key)); + } + catch { + return false; + } +} +/** + * Test for an ordinary schema record whose keys survive JSON projection. + * @param value - candidate record from any JavaScript realm. + * @returns Whether the record has an intrinsic prototype and only own enumerable string keys. + */ +export function isJsonSchemaRecord(value) { + return isPlainJsonRecord(value) && hasOnlyEnumerableStringKeys(value); +} +/** + * Test for a dense ordinary array with no JSON-invisible decorations. + * @param value - candidate array from any JavaScript realm. + * @returns Whether the array is intrinsic, dense, and undecorated. + */ +export function isPlainJsonArray(value) { + if (!Array.isArray(value)) + return false; + try { + if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) + return false; + for (let index = 0; index < value.length; index++) { + if (!Object.hasOwn(value, index)) + return false; + } + return true; + } + catch { + return false; + } +} +/** Lossless finite JSON number, excluding negative zero. */ +function isJsonNumber(value) { + return typeof value === 'number' && Number.isFinite(value) && !Object.is(value, -0); +} +/** Whether a scalar is valid for one declared schema type. */ +function scalarMatches(type, value) { + switch (type) { + case 'string': return typeof value === 'string'; + case 'number': return isJsonNumber(value); + case 'integer': return isJsonNumber(value) && Number.isInteger(value); + case 'boolean': return typeof value === 'boolean'; + case 'null': return value === null; + /* v8 ignore next -- JsonSchemaScalarType is closed; this retains compile-time exhaustiveness. */ + default: return assertNever(type, 'JsonSchemaType'); + } +} +/** Keywords that are invalid beside `oneOf`. */ +const ONE_OF_SIBLING_KEYWORDS = ['properties', 'required', 'additionalProperties', 'items', 'enum', 'const']; +/** Validate object-only fields after its property schemas have been visited. */ +function checkObjectSchemaTail(node, path, properties, violations) { + const hasRequired = Object.hasOwn(node, 'required'); + const required = hasRequired ? node.required : undefined; + if (hasRequired) { + if (!isPlainJsonArray(required) || required.some(entry => typeof entry !== 'string')) { + violations.push(`${path}.required must be an array of strings`); + } + else { + const declared = isJsonSchemaRecord(properties) ? properties : {}; + for (const key of required) { + if (!Object.hasOwn(declared, key)) + violations.push(`${path}.required names "${key}" which is not in properties`); + } + } + } + if (Object.hasOwn(node, 'additionalProperties') && typeof node.additionalProperties !== 'boolean') { + violations.push(`${path}.additionalProperties must be a boolean`); + } +} +/** Collect every violation for one raw schema tree without using the JavaScript call stack. */ +function checkSchemaNode(root, rootPath, violations, seen) { + const tasks = [{ kind: 'enter', node: root, path: rootPath }]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + seen.delete(task.node); + continue; + } + if (task.kind === 'one-of-tail') { + for (const key of ONE_OF_SIBLING_KEYWORDS) { + if (Object.hasOwn(task.node, key)) + violations.push(`${task.path}.${key} is not supported beside oneOf`); + } + continue; + } + if (task.kind === 'object-tail') { + checkObjectSchemaTail(task.node, task.path, task.properties, violations); + continue; + } + const { node, path } = task; + if (!isJsonSchemaRecord(node)) { + violations.push(`${path} must be a schema object`); + continue; + } + if (seen.has(node)) { + violations.push(`${path} is circular`); + continue; + } + seen.add(node); + tasks.push({ kind: 'leave', node }); + for (const key of Object.keys(node)) { + if (CONSTRAINT_KEYWORDS.has(key)) + continue; + if (ANNOTATION_KEYWORDS.has(key)) { + try { + if (!isJsonValue(node[key])) + violations.push(`${path}.${key} annotation must be lossless JSON data`); + } + catch { + violations.push(`${path}.${key} annotation must be lossless JSON data`); + } + continue; + } + violations.push(`${path}.${key} is not a supported keyword (subset: type/oneOf/properties/required/additionalProperties/items/enum/const + annotations)`); + } + if (Object.hasOwn(node, 'description') && typeof node.description !== 'string') { + violations.push(`${path}.description must be a string`); + } + if (Object.hasOwn(node, 'title') && typeof node.title !== 'string') { + violations.push(`${path}.title must be a string`); + } + const hasType = Object.hasOwn(node, 'type'); + const hasOneOf = Object.hasOwn(node, 'oneOf'); + if (hasType && hasOneOf) { + violations.push(`${path} cannot declare both type and oneOf`); + continue; + } + if (!hasType && !hasOneOf) { + for (const key of ONE_OF_SIBLING_KEYWORDS) { + if (Object.hasOwn(node, key)) + violations.push(`${path}.${key} requires type or oneOf`); + } + continue; + } + if (hasOneOf) { + const oneOf = node.oneOf; + tasks.push({ kind: 'one-of-tail', node, path }); + if (!isPlainJsonArray(oneOf) || oneOf.length < 2) { + violations.push(`${path}.oneOf must be an array of at least two schemas`); + } + else { + for (let index = oneOf.length - 1; index >= 0; index--) { + tasks.push({ kind: 'enter', node: oneOf[index], path: `${path}.oneOf[${index}]` }); + } + } + continue; + } + const type = node.type; + if (typeof type !== 'string' || !SCHEMA_TYPES.includes(type)) { + violations.push(Array.isArray(type) + ? `${path}.type must be a single type string (type arrays are not supported)` + : `${path}.type must be one of ${SCHEMA_TYPES.join('/')}`); + continue; + } + const schemaType = type; + const allowedFor = { + properties: ['object'], + required: ['object'], + additionalProperties: ['object'], + items: ['array'], + enum: ['string', 'number', 'integer', 'boolean', 'null'], + const: ['string', 'number', 'integer', 'boolean', 'null'], + }; + for (const [key, types] of Object.entries(allowedFor)) { + if (Object.hasOwn(node, key) && !types.includes(schemaType)) { + violations.push(`${path}.${key} is not supported on type "${schemaType}"`); + } + } + switch (schemaType) { + case 'object': { + const properties = Object.hasOwn(node, 'properties') ? node.properties : undefined; + tasks.push({ kind: 'object-tail', node, path, properties }); + if (Object.hasOwn(node, 'properties')) { + if (!isJsonSchemaRecord(properties)) { + violations.push(`${path}.properties must be an object of schemas`); + } + else { + const entries = Object.entries(properties); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) + continue; + tasks.push({ kind: 'enter', node: entry[1], path: `${path}.properties.${entry[0]}` }); + } + } + } + break; + } + case 'array': { + if (Object.hasOwn(node, 'items')) + tasks.push({ kind: 'enter', node: node.items, path: `${path}.items` }); + break; + } + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': { + const hasEnum = Object.hasOwn(node, 'enum'); + const allowed = hasEnum ? node.enum : undefined; + const enumValid = isPlainJsonArray(allowed) + && allowed.length > 0 + && allowed.every(entry => scalarMatches(schemaType, entry)); + if (hasEnum && !enumValid) { + violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`); + } + const hasConst = Object.hasOwn(node, 'const'); + const declaredConst = hasConst ? node.const : undefined; + const constValid = scalarMatches(schemaType, declaredConst); + if (hasConst) { + if (!constValid) { + violations.push(`${path}.const must be a ${schemaType} value`); + } + else if (enumValid && !allowed.includes(declaredConst)) { + violations.push(`${path}.const must be one of ${path}.enum when both are declared`); + } + } + break; + } + /* v8 ignore next -- schemaType was narrowed from the closed SCHEMA_TYPES table above. */ + default: assertNever(schemaType, 'JsonSchemaType'); + } + } +} +/** + * Assert that an arbitrary raw schema uses only the enforced subset. + * Annotation-only schemas are accepted as the standard unconstrained-JSON + * form; callers that require an object root use {@link assertObjectJsonSchema}. + * @param schema - untrusted raw JSON Schema. + * @returns Assertion that the schema belongs to the supported subset. + */ +export function assertSupportedJsonSchema(schema) { + const violations = []; + checkSchemaNode(schema, 'schema', violations, new Set()); + if (violations.length > 0) + throw new JsonSchemaError(violations); +} +/** + * Assert the enforced subset plus the object-root constraint retained by + * subagent and workflow structured outputs. + * @param schema - untrusted caller-supplied schema. + * @returns Assertion that the schema belongs to the supported subset and has an object root. + */ +export function assertObjectJsonSchema(schema) { + const violations = []; + checkSchemaNode(schema, 'schema', violations, new Set()); + if (violations.length === 0 + && (!isJsonSchemaRecord(schema) || !Object.hasOwn(schema, 'type') || schema.type !== 'object')) { + violations.push('schema.type must be "object" (structured output is object-rooted)'); + } + if (violations.length > 0) + throw new JsonSchemaError(violations); +} +/** Safely test the lossless JSON boundary when a getter may throw. */ +function safelyIsJsonValue(value) { + try { + return isJsonValue(value); + } + catch { + return false; + } +} +/** Root-aware diagnostic path for the parameter validator's empty sentinel. */ +function diagnosticPath(path) { + return path === '' ? 'arguments' : path; +} +/** Append one object property without a leading dot at an implicit root. */ +function propertyPath(path, key) { + return path === '' ? key : `${path}.${key}`; +} +/** The generic exception-containment diagnostic owned by one valid schema node. */ +function losslessValueViolation(path) { + return [`"${diagnosticPath(path)}" must be a lossless JSON value`]; +} +/** Append diagnostics without spreading a potentially wide child result as call arguments. */ +function appendViolations(target, source) { + for (const violation of source) + target.push(violation); +} +/** Initialize one validation frame with empty aggregation state. */ +function valueFrame(node, value, path) { + return { + node, + value, + path, + catches: false, + phase: 'start', + children: [], + childIndex: 0, + violations: [], + tailViolations: [], + matches: 0, + }; +} +/** Validate one scalar node after its primitive type check. */ +function checkScalarValue(node, value, path) { + const allowed = Object.hasOwn(node, 'enum') ? node.enum : undefined; + if (allowed !== undefined && !allowed.includes(value)) { + return [`"${diagnosticPath(path)}" must be one of ${JSON.stringify(allowed)}`]; + } + if (Object.hasOwn(node, 'const') && value !== node.const) { + return [`"${diagnosticPath(path)}" must be ${JSON.stringify(node.const)}`]; + } + return []; +} +/** Validate one trusted schema/value pair with explicit frames rather than recursive calls. */ +function checkValue(schema, value, path) { + const frames = [valueFrame(schema, value, path)]; + let rootResult; + const receive = (result) => { + const parent = frames.at(-1); + if (parent === undefined) { + rootResult = result; + return; + } + if (parent.kind === 'oneOf') { + if (result.length === 0) + parent.matches++; + } + else { + appendViolations(parent.violations, result); + } + }; + const finish = (result) => { + frames.pop(); + receive(result); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === undefined) + break; + try { + if (frame.phase === 'children') { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === undefined) + throw new Error('missing schema-value child frame'); + frame.childIndex++; + frames.push(valueFrame(child.node, child.value, child.path)); + continue; + } + if (frame.kind === 'oneOf') { + finish(frame.matches === 1 ? [] : [`"${diagnosticPath(frame.path)}" must match exactly one oneOf branch (matched ${frame.matches})`]); + continue; + } + appendViolations(frame.violations, frame.tailViolations); + if (frame.violations.length > 0) { + finish(frame.violations); + } + else if (frame.kind === 'object') { + finish(safelyIsJsonValue(frame.value) ? [] : [`"${diagnosticPath(frame.path)}" must be a lossless JSON object`]); + } + else { + finish(safelyIsJsonValue(frame.value) ? [] : [`"${diagnosticPath(frame.path)}" must be a dense lossless JSON array`]); + } + continue; + } + const nodeType = Object.hasOwn(frame.node, 'type') ? frame.node.type : undefined; + frame.catches = !(nodeType !== undefined && !SCHEMA_TYPES.includes(nodeType)); + const oneOf = Object.hasOwn(frame.node, 'oneOf') ? frame.node.oneOf : undefined; + if (oneOf !== undefined) { + frame.kind = 'oneOf'; + frame.children = Array.from(oneOf, branch => ({ node: branch, value: frame.value, path: frame.path })); + frame.childIndex = 0; + frame.matches = 0; + frame.phase = 'children'; + continue; + } + if (nodeType === undefined) { + finish(safelyIsJsonValue(frame.value) ? [] : losslessValueViolation(frame.path)); + continue; + } + switch (nodeType) { + case 'object': { + if (!isPlainJsonRecord(frame.value)) { + finish([`"${diagnosticPath(frame.path)}" must be an object`]); + break; + } + const properties = Object.hasOwn(frame.node, 'properties') ? frame.node.properties ?? {} : {}; + const violations = []; + const required = Object.hasOwn(frame.node, 'required') ? frame.node.required ?? [] : []; + for (const key of required) { + if (!Object.hasOwn(frame.value, key) || frame.value[key] === undefined) { + violations.push(`missing required property "${propertyPath(frame.path, key)}"`); + } + } + const children = []; + for (const [key, child] of Object.entries(properties)) { + if (!Object.hasOwn(frame.value, key) || frame.value[key] === undefined) + continue; + children.push({ node: child, value: frame.value[key], path: propertyPath(frame.path, key) }); + } + const tailViolations = []; + if (Object.hasOwn(frame.node, 'additionalProperties') && frame.node.additionalProperties === false) { + for (const key of Object.keys(frame.value)) { + if (!Object.hasOwn(properties, key)) { + tailViolations.push(`"${propertyPath(frame.path, key)}" is not a declared property (additionalProperties: false)`); + } + } + } + frame.kind = 'object'; + frame.children = children; + frame.childIndex = 0; + frame.violations = violations; + frame.tailViolations = tailViolations; + frame.phase = 'children'; + break; + } + case 'array': { + if (!Array.isArray(frame.value)) { + finish([`"${diagnosticPath(frame.path)}" must be an array`]); + break; + } + const items = Object.hasOwn(frame.node, 'items') ? frame.node.items : undefined; + const children = items === undefined + ? [] + : frame.value.flatMap((entry, index) => [{ node: items, value: entry, path: `${frame.path}[${index}]` }]); + frame.kind = 'array'; + frame.children = children; + frame.childIndex = 0; + frame.violations = []; + frame.phase = 'children'; + break; + } + case 'string': + finish(typeof frame.value === 'string' + ? checkScalarValue(frame.node, frame.value, frame.path) + : [`"${diagnosticPath(frame.path)}" must be a string`]); + break; + case 'number': + finish(typeof frame.value !== 'number' + ? [`"${diagnosticPath(frame.path)}" must be a number`] + : !isJsonNumber(frame.value) + ? [`"${diagnosticPath(frame.path)}" must be a finite JSON number`] + : checkScalarValue(frame.node, frame.value, frame.path)); + break; + case 'integer': + finish(!isJsonNumber(frame.value) || !Number.isInteger(frame.value) + ? [`"${diagnosticPath(frame.path)}" must be an integer`] + : checkScalarValue(frame.node, frame.value, frame.path)); + break; + case 'boolean': + finish(typeof frame.value === 'boolean' + ? checkScalarValue(frame.node, frame.value, frame.path) + : [`"${diagnosticPath(frame.path)}" must be a boolean`]); + break; + case 'null': + finish(frame.value === null + ? checkScalarValue(frame.node, frame.value, frame.path) + : [`"${diagnosticPath(frame.path)}" must be null`]); + break; + default: + finish(assertNever(nodeType, 'JsonSchemaType')); + } + } + catch (error) { + let failed = frames.pop(); + while (failed !== undefined && !failed.catches) + failed = frames.pop(); + if (failed === undefined) + throw error; + receive(losslessValueViolation(failed.path)); + } + } + /* v8 ignore next -- every root frame finishes or throws. */ + return rootResult ?? losslessValueViolation(path); +} +/** + * Validate a candidate value against an asserted raw schema. The function is + * total for arbitrary values and returns path-qualified violations. + * @param schema - a schema accepted by {@link assertSupportedJsonSchema}. + * @param value - the candidate JSON value. + * @param path - root label used in diagnostics. + * @returns All violations in walk order; empty means valid. + */ +export function validateJsonSchemaValue(schema, value, path = 'value') { + return checkValue(schema, value, path); +} +//# sourceMappingURL=json-schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.d.ts new file mode 100644 index 0000000..2cf0fb9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.d.ts @@ -0,0 +1,367 @@ +/** + * Tool render-intent vocabulary: the provider-neutral types a tool declares via + * `ToolDefinition.presentCall`/`ToolDefinition.presentResult` to say how one of its calls + * renders in a UI (an editor's tool-call card, a CLI log line). + * @module @deepseek-ai/dsh-tools/src/presentation + */ +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +/** + * Category of a tool call, used by a UI to pick an icon or treatment. The + * provider-neutral vocabulary lets tools describe themselves without depending + * on a particular client; `other` is the default. + */ +export type ToolCallKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other'; +/** + * A file location a tool reads or modifies, so a capable UI can "follow along" — + * highlight or jump to the file (and line) as the tool runs. `path` is what the + * tool operated on (the model-facing path); `line` is an optional 1-based line + * to focus (e.g. a read's offset). + */ +export interface FileLocation { + path: string; + line?: number; +} +/** + * A single-file change a tool is about to make, for a UI that renders inline + * diffs. `oldText` is `null` for a new-file create (nothing to diff against); + * an overwrite also uses `null`, because a call-time presenter has no access to + * the file's prior content. + */ +export interface FileDiff { + path: string; + /** Prior content, or `null` for a new file / an overwrite (no prior content available at call time). */ + oldText: string | null; + /** Content after the change. */ + newText: string; +} +/** + * Provider-neutral pending-call presentation. Tools declare one tagged intent; + * UI bridges map it without special-casing tool names. + */ +export type ToolCallView = GenericCallView | TerminalCallView | DiffCallView; +/** + * The default card: a titled tool-call row with an optional category icon, a + * salient raw input, extra content blocks, and follow-along file locations. Any + * tool whose call is not a terminal or a diff uses this. + */ +export interface GenericCallView { + card: 'generic'; + /** + * Human-readable, always-visible label describing what THIS call does. Keep it + * short — a UI shows it as a card header / log line. + */ + title: string; + /** Category for icon/treatment; defaults to `other` when omitted. */ + kind?: ToolCallKind; + /** + * The salient input to show in a detail/expanded view (e.g. a background + * job id). Omit to show nothing; a string renders as-is, an object as pretty + * JSON. NOT the full raw args object unless that is genuinely what a reader wants. + */ + rawInput?: unknown; + /** + * UI-facing content blocks to show on the pending call alongside the title. + * Omit to show none. A UI maps these to its own content blocks. + */ + content?: ContentBlock[]; + /** Files this call reads/modifies, for editor follow-along. Omit for a call that touches no file. */ + locations?: FileLocation[]; +} +/** + * A call that IS a shell command running in a working directory: a capable UI + * renders it as a terminal card (cwd-headed, with the command as the title and + * live/afterward output from the {@link TerminalResultView}); an incapable UI + * falls back to a generic card whose body is the fenced command output. Set by a + * tool whose call is a foreground command (e.g. `bash`). + */ +export interface TerminalCallView { + card: 'terminal'; + /** The command, shown as the terminal card's title / header line. */ + title: string; + /** + * A human-readable one-line summary of what the command does, rendered ABOVE + * the terminal card (the card itself has no description slot). Omit for none. + */ + description?: string; + /** + * Working directory the command runs in, shown as the terminal header. An + * ABSOLUTE path is used as-is; a RELATIVE path is resolved by the UI bridge + * against the session workspace (the pure presenter can't see the session cwd). + * Omit entirely to let the bridge use the session workspace. + */ + cwd?: string; +} +/** + * A call that creates or modifies files, rendered as an inline diff card by a + * capable UI. Set by a tool whose call writes/edits a file (e.g. `write`, + * `edit`). The diffs are derived from the call ARGUMENTS (a create's `oldText` is + * `null`); the tool emits a separate {@link DiffResultView} after `execute` — the + * applied change (an edit/overwrite hunk with context, or a whole-file diff for a + * create). + */ +export interface DiffCallView { + card: 'diff'; + /** Card header (e.g. `Write foo.txt`). */ + title: string; + /** One entry per file the call changes. */ + diffs: FileDiff[]; + /** Files this call modifies, for editor follow-along (usually the diffs' paths). */ + locations?: FileLocation[]; +} +/** + * One numbered line of a file, the unit a {@link ReadResultView} carries so a + * capable UI can render a syntax-highlighted, line-numbered code view. `number` + * is the 1-based line number in the file (a window past `offset` keeps the file's + * own numbering, not a 1-based re-count); `text` is the line without its trailing + * newline, already truncated to the read tool's per-line cap. + */ +export interface ReadFileLine { + number: number; + text: string; +} +/** + * How a tool wants the COMPLETED call shown — the *result* state, after `execute` + * returns. A `card`-tagged union mirroring {@link ToolCallView}: a UI switches on + * `card`. Lets the tool reformat its result for a UI distinctly from the + * model-facing text it returned from `execute`. Returned by + * `ToolDefinition.presentResult`; omitting the method keeps the pending + * title and renders the raw result content. + */ +export type ToolResultView = GenericResultView | TerminalResultView | DiffResultView | SearchResultView | ReadResultView | WebResultView; +/** + * The default completed card: an optional replacement title and reformatted + * content. Omit a field to keep the pending title / render the raw result content. + */ +export interface GenericResultView { + card: 'generic'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** + * UI-facing result content (harness {@link ContentBlock}s), reformatted from + * the model-facing result. Omit to let the UI render the raw result content. + */ + content?: ContentBlock[]; +} +/** + * The completed state of a {@link TerminalCallView}: the captured output and exit + * status. A capable UI renders `output` in the terminal card and shows an + * exit-status pill; an incapable UI gets a fenced ```console fallback the BRIDGE + * derives from `output` (the tool does not double-encode it). + */ +export interface TerminalResultView { + card: 'terminal'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** Captured command output (stdout+stderr as the tool chooses to combine them). */ + output?: string; + /** + * Process exit code, when the run ended by exiting (not a signal). Lets a + * capable UI show an exit-status pill. Omit when killed by a signal or unknown. + */ + exitCode?: number; + /** Signal name that killed the process (e.g. `SIGTERM`). Mutually exclusive with `exitCode`. */ + signal?: string; +} +/** + * A completed file mutation rendered as an inline diff card, the result-time + * analogue of {@link DiffCallView}. Because a completed UI update replaces the + * pending card content, mutation tools return this even when it repeats the + * call-time diff; otherwise raw result text would replace the diff. + */ +export interface DiffResultView { + card: 'diff'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** The change to show, in file order — applied contextual hunks, or a whole-file diff when there is no before-image. */ + diffs: FileDiff[]; +} +/** One matched line inside a {@link SearchFileMatches} group: its 1-based line number and text. */ +export interface SearchLineMatch { + /** 1-based line number of the match within its file. */ + lineNumber: number; + /** The matched line text, as the tool surfaced it (the per-line preview budget already applied). */ + line: string; +} +/** One file's grouped content matches for a {@link SearchMatchesResultView}, in first-seen file order. */ +export interface SearchFileMatches { + /** The file the matches belong to (the model-facing display path). */ + path: string; + /** The file's matched lines, in output order. */ + matches: SearchLineMatch[]; +} +/** + * A completed content search (`grep`) rendered as a search card whose matches are + * grouped by file, so a capable UI can list each file as an expandable group of + * its matched lines. `shape: 'matches'` discriminates this variant from the path + * variant ({@link SearchPathsResultView}) within {@link SearchResultView}. The + * discriminant is `shape`, not `kind`, so it never collides with the + * {@link ToolCallKind} `kind` an icon-picking bridge reads off a call view. + */ +export interface SearchMatchesResultView { + card: 'search'; + shape: 'matches'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** Matched lines grouped by file, in first-seen file order. */ + files: SearchFileMatches[]; + /** + * Whether the tool capped the inline result: `files` carries only the retained + * matches, not every match the search found. A UI shows a capped indicator so it + * never presents a partial group as complete. + */ + truncated: boolean; + /** Total matches the search found before capping (equals the retained count when not `truncated`). */ + total: number; +} +/** + * A completed path search (`glob`) rendered as a search card whose result is a flat + * path list. `shape: 'paths'` discriminates this variant from the grouped-matches + * variant ({@link SearchMatchesResultView}) within {@link SearchResultView}. + */ +export interface SearchPathsResultView { + card: 'search'; + shape: 'paths'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** The discovered paths, in the tool's result order (the retained page when `truncated`). */ + paths: string[]; + /** + * Whether the tool capped the inline result: `paths` carries only the retained + * page, not every path the search found. A UI shows a capped indicator so it + * never presents a partial list as complete. + */ + truncated: boolean; + /** Total paths the search found before capping (equals `paths.length` when not `truncated`). */ + total: number; +} +/** + * A completed search rendered as a search card, the result-time view a discovery + * tool (`grep`, `glob`) returns from `presentResult`. One `card: 'search'` view + * with two `shape`-discriminated variants: grouped-by-file content matches + * ({@link SearchMatchesResultView}) and a flat path list + * ({@link SearchPathsResultView}). Both carry a `truncated`/`total` signal so a UI + * never presents a capped result as complete. The view carries no result text: a + * UI without a search card falls back to the raw `tool/result` content. There is + * no call-time analogue: a search call stays a {@link GenericCallView} + * (`kind: 'search'`) because the pending state has no matches or paths to show — + * the structured shape exists only after `execute`. + */ +export type SearchResultView = SearchMatchesResultView | SearchPathsResultView; +/** + * A completed file read rendered as a line-numbered, optionally syntax-highlighted + * code view by a capable UI. Set by a tool whose call reads file text (e.g. + * `read`); the pending state stays a {@link GenericCallView} (`kind: 'read'`) + * because a call carries no content until `execute` returns. The structured + * `lines`/`path`/`lang`/`totalLines` fields cannot be reconstructed from the + * model-facing result text alone, so the read tool projects them through its + * `output.presentationMeta` (persisted with the session log) and `presentResult` + * narrows that metadata back into this view on live and replay paths alike. A UI + * without the read capability falls back to `content` (the model-facing text with + * its envelope stripped), so this view degrades to the generic text card. + */ +export interface ReadResultView { + card: 'read'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** The read file's path (the model-facing path; the bridge relativizes it). */ + path: string; + /** + * The 1-based first line the window requested, preserved even when `lines` is + * empty (a byte cap below the first selected line yields an empty window) so a + * UI knows where the window starts and where a continuation resumes. + */ + offset: number; + /** The returned window's lines, in file order, each keeping its file line number. */ + lines: ReadFileLine[]; + /** Exact total line count in the file, so a UI can show a "showing N of M" affordance. */ + totalLines: number; + /** + * A syntax-highlighting language hint derived from the file extension (e.g. + * `ts`, `py`), or omitted when the extension maps to no known language so a UI + * renders the lines as plain text. + */ + lang?: string; + /** + * The model-facing result content with its envelope stripped, for a UI without + * the read capability. Omit to let such a UI render the raw result content. + */ + content?: ContentBlock[]; +} +/** + * One citeable source in a completed {@link WebSearchResultView}, the faithful + * projection of one web-search source. The presentation projection of `dsh-web`'s + * `WebSearchSource`: that Service Definition type is authoritative (core cannot depend + * on the web Service Definition, so the two are declared separately and MUST evolve together). + * A web tool projects this shape through `output.presentationMeta` because the + * render text cannot losslessly carry it (see the web-result-card Agent Note); its + * `presentResult` reads it back. + */ +export interface WebSource { + /** The source URL. */ + url: string; + /** The source title, when the provider returned one. */ + title?: string; + /** A short excerpt or summary, when the provider returned one. */ + snippet?: string; + /** Publication/crawl timestamp as a provider-supplied ISO-8601 string, when present. */ + publishedAt?: string; +} +/** + * A completed web retrieval rendered as a structured card by a capable UI. Set + * by a web tool whose call retrieves from the web (`web_search`, `web_fetch`). + * One `kind`-tagged union carries both shapes because both are web retrieval and + * a UI renders them with one component family; a UI switches on `kind`. An + * incapable UI falls back to the raw `tool/result` content (this view carries no + * `content` copy — see the web-result-card Agent Note). This is the result-time + * analogue of the `web_search`/`web_fetch` calls' generic call views + * (`kind: 'search'`/`'fetch'`); those tools keep their generic pending card and + * add only this completed card. + * + * The `kind` field here is this union's own discriminant, NOT a + * {@link ToolCallKind}: the two values deliberately match the tools' pending + * `ToolCallKind` (`'search'`/`'fetch'`) so a call and its result read as one + * category, but a new arm is a union edit plus a consumer branch, not any + * arbitrary `ToolCallKind` value. + */ +export type WebResultView = WebSearchResultView | WebFetchResultView; +/** + * The completed state of a `web_search` call: the structured sources the model + * cited, an optional provider answer, and whether the source list was cut to the + * result cap. A capable UI renders the sources as a citation list; a UI without + * the `web` capability falls back to the raw `tool/result` content. + */ +export interface WebSearchResultView { + card: 'web'; + kind: 'search'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** The faithful, structured sources — the field render text cannot losslessly carry. */ + sources: WebSource[]; + /** The provider-generated answer text, when any. */ + answer?: string; + /** True when the web service cut the source list to honor the result cap. */ + truncated: boolean; +} +/** + * The completed state of a `web_fetch` call: the fetched URL, its HTTP status, + * and whether the content was cut. The body itself is already markdown in the + * raw `tool/result` content, so this card carries only the retrieval summary and + * a UI without the `web` capability falls back to that content. + */ +export interface WebFetchResultView { + card: 'web'; + kind: 'fetch'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** The final URL after allowed redirects. */ + url: string; + /** HTTP status code of the fetched response. */ + statusCode: number; + /** + * True when the provider capped the decoded body, or the output cap or a + * pre-conversion source cut trimmed the rendered text (the effective + * truncation the model-facing text also reflects). + */ + truncated: boolean; +} +//# sourceMappingURL=presentation.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.js new file mode 100644 index 0000000..a83855c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.js @@ -0,0 +1,8 @@ +/** + * Tool render-intent vocabulary: the provider-neutral types a tool declares via + * `ToolDefinition.presentCall`/`ToolDefinition.presentResult` to say how one of its calls + * renders in a UI (an editor's tool-call card, a CLI log line). + * @module @deepseek-ai/dsh-tools/src/presentation + */ +export {}; +//# sourceMappingURL=presentation.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.d.ts new file mode 100644 index 0000000..e59df0b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.d.ts @@ -0,0 +1,49 @@ +/** + * Code Mode codegen — Python flavor. The pure projection from registered tool schemas to the + * Python SDK text the model programs against under `runtime.language === 'python'`. Sibling of + * {@link ./ts-types.ts | ts-types.ts}; the two files are two projections of the same registry + * store, keyed by the loaded {@link @deepseek-ai/dsh-code-runtime#CodeRuntime.language | code + * runtime's language}. + * + * Under `mode: 'code'` the native tool schemas are omitted from the request, so this generated + * SDK is the model's ONLY source for each tool's argument names, required fields, types, + * descriptions, and canonical output shapes; under `mode: 'both'` the native schemas ship + * alongside it and it is one of two. Object-shaped arguments and outputs therefore render as one + * named `TypedDict` per tool (and per nested object), not an opaque `dict[str, Any]`, so the + * shape survives into the program under the mode that has nothing else to carry it. + * @module @deepseek-ai/dsh-tools/src/py-types + */ +import type { ToolSdkSchema } from './ts-types.ts'; +/** + * Map one JSON-Schema node to a context-free Python type expression from the + * `typing` module. Handles every unified schema construct — `object` (degraded + * to `dict[str, Any]`: naming a `TypedDict` requires the render context that + * {@link renderToolsSdkPy} supplies), `const`/`enum` (→ `Literal[...]`), + * `oneOf` (→ union), `string`/`number`/`integer`/`boolean`/`null`, `array` + * (`items` → `list[T]`) — and returns `Any` for an unsupported or malformed + * schema, matching the TS flavor's `unknown` fallback. Type annotations in the + * emitted SDK are advisory: Python does not enforce them at runtime. + * @param schema - the JSON-Schema node. + * @returns the Python type text. + */ +export declare function jsonSchemaToPy(schema: unknown): string; +/** + * Render the full `tools:sdk` prompt section under `runtime.language === + * 'python'`: the Python-flavored usage instructions plus one named `TypedDict` + * per tool argument or output object (and per nested object) and one awaitable + * method per visible tool on a `Tools` protocol — typed args in, the tool's + * canonical output value out — with a `tools: Tools` singleton the model calls + * into. The `typing` import line lists exactly the symbols the render used. + * Deterministic — tools are emitted in lexicographic name order, and class + * declarations precede the protocol in that same order (nested classes before + * the parent that references them), so an unchanged tool set produces + * byte-identical text across assemblies. The sort is not a total order on + * byte-equal names, so two schemas sharing a name would render in argument + * order; the caller's visible-capability map is keyed by name, so the input + * never carries a duplicate. + * @param schemas - the tool schemas plus canonical output schemas to declare + * (the caller excludes `run_code` itself). + * @returns the complete section text. + */ +export declare function renderToolsSdkPy(schemas: ToolSdkSchema[]): string; +//# sourceMappingURL=py-types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.js new file mode 100644 index 0000000..7ba9313 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.js @@ -0,0 +1,788 @@ +/** + * Code Mode codegen — Python flavor. The pure projection from registered tool schemas to the + * Python SDK text the model programs against under `runtime.language === 'python'`. Sibling of + * {@link ./ts-types.ts | ts-types.ts}; the two files are two projections of the same registry + * store, keyed by the loaded {@link @deepseek-ai/dsh-code-runtime#CodeRuntime.language | code + * runtime's language}. + * + * Under `mode: 'code'` the native tool schemas are omitted from the request, so this generated + * SDK is the model's ONLY source for each tool's argument names, required fields, types, + * descriptions, and canonical output shapes; under `mode: 'both'` the native schemas ship + * alongside it and it is one of two. Object-shaped arguments and outputs therefore render as one + * named `TypedDict` per tool (and per nested object), not an opaque `dict[str, Any]`, so the + * shape survives into the program under the mode that has nothing else to carry it. + * @module @deepseek-ai/dsh-tools/src/py-types + */ +import { assertSupportedJsonSchema } from "./json-schema.js"; +/** + * The reference grammar's `xid_start xid_continue*` — the set + * `str.isidentifier()` accepts on a CPython whose Unicode tables match the + * engine's. See {@link isBareIdentifier} for what a version skew does. + */ +const IDENTIFIER = /^[\p{XID_Start}_]\p{XID_Continue}*$/u; +/** + * Whether a name can be emitted as a bare Python identifier rather than + * routed to the subscript/`dict[str, Any]` path. + * + * Python identifiers are not ASCII: `路径` is as legal a field name as `path`, + * and rejecting it would degrade the whole enclosing object, dropping every + * field's name, requiredness, and type — information whose only source under + * `mode: 'code'` is this generated text. + * + * NFKC stability is a second and separate condition, because CPython + * normalizes identifiers at compile time while JSON keys are compared as + * written: `field` would be declared and reachable as `field`, so the SDK would + * advertise a key under a spelling the harness never accepts, and two keys + * that normalize together would collapse into one declaration. Those names + * take the subscript path, which carries their exact bytes. + * + * `IDENTIFIER` matches `str.isidentifier()` (measured on Node 22.23.1 vs + * CPython 3.9.6 tables): the equivalence holds inside the two versions' shared + * tables, and the skew characters below are exactly where that pair diverges. + * The predicate as a whole is deliberately stricter than `isidentifier()`, + * which does not test NFKC stability: `'field'.isidentifier()` is True and + * this returns false. + * + * Both conditions are evaluated against the ENGINE's Unicode tables, and the + * two sides are versioned independently — `\p{XID_Start}`/`\p{XID_Continue}` + * follow the running engine (Node 22.23.1 reports Unicode 17.0) while CPython + * follows its own (3.9.6 reports 13.0.0). The skew is not symmetric. A CPython + * older than the engine is the dangerous direction: a character added to either + * property since its tables (U+10570 Vithkuqi and U+1E290 Toto, 14.0; U+1E4D0 + * Nag Mundari, 15.0; U+1C89 Cyrillic TJE, 16.0 — ages per `DerivedAge.txt`; all + * four are NFKC-stable and accepted here, and all four are `Cn` on that 3.9.6, + * which rejects them) is emitted bare and its tokenizer refuses the character, + * taking the whole SDK block down — the same parseability invariant + * {@link UNPRINTABLE}, {@link LONE_SURROGATE} and {@link MAX_LIST_NESTING} + * exist for. Both properties carry it: a character added only to `XID_Continue` + * passes the trailing `\p{XID_Continue}*` in a tail position and fails the same + * way — U+200C ZWNJ and U+200D ZWJ are that case, gaining `XID_Continue` in UCD + * 15.1 and absent from it in 13.0.0, 14.0.0 and 15.0.0, so `a\u{200C}b` is + * emitted bare here while `isidentifier()` is False on 3.9.6 and on 3.12.13 + * (15.0.0). A CPython newer than the engine only routes a legal name to the + * subscript/`dict[str, Any]` path: less readable, still correct. The NFKC + * condition reduces to the same skew, since normalization stability guarantees + * an assigned character's normalization never changes afterwards. + * + * This predicate is not the only reader of engine tables. {@link camelCase} + * reads them at three further points — its split set, its head test, and its + * `toUpperCase()` case mapping — and this predicate's verdict gates none of + * them: a class name derived there reaches emitted text whenever any object + * shape in the tool's schema declares a `TypedDict`, including for a tool this + * predicate rejected. A tool named `zz-\u{1E4D0}x` with such parameters never + * reaches the skew here (the `-` rejects it outright) yet emits `class + * Zz\u{1E4D0}xArgs`, which that same 3.9.6 refuses — Nag Mundari arrived two + * releases after its tables. The case mapping is a separate table rather than + * an XID membership test, and it fails on names both conditions above accept: + * `\u{019B}` is XID_Start and NFKC-stable, so this predicate accepts it and + * `async def \u{019B}` compiles on 3.9.6, but Node uppercases it to + * `\u{A7DC}` — unassigned in that CPython, whose own `.upper()` is the identity + * here — and the declared `class \u{A7DC}Args` fails with `invalid + * non-printable character U+A7DC`. Closing the exposure therefore covers all + * four read points, not this predicate alone; it needs the target interpreter's + * version, which the backend reporting `language: 'python'` owns; the + * language-dispatch Agent Note records the deferral. + * + * The `ts-types` sibling keeps its own ASCII rule rather than sharing this + * one: ECMAScript identifiers are a different set (`$`) and are never + * normalized, so one predicate cannot be correct for both. ZWJ/ZWNJ are not + * part of that difference — both sets carry them on the engine's tables; what + * separates the two there is the CPython table version above. + * @param name - the raw schema field or tool name. + * @returns whether the name can be emitted bare. + */ +function isBareIdentifier(name) { + return IDENTIFIER.test(name) && name.normalize('NFKC') === name; +} +/** + * Python hard keywords: reserved everywhere, so a tool or field named + * ``class`` or ``lambda`` is legal on the wire but not as an attribute + * (``tools.class`` would be a SyntaxError in the model program) and not as a + * class-syntax `TypedDict` field. Such a tool renders under subscript access + * and such an object degrades to ``dict[str, Any]`` — the model still reaches + * every tool and field without collisions. + * Soft keywords (``match``, ``case``, ``type``, ``_`` — the language + * reference's whole set) are deliberately ABSENT: each is special in exactly + * one syntactic position — a statement head (``match``, ``type``), a ``match`` + * statement's clause head (``case``), or a pattern (``_``) — so ``match: str`` + * as a field and ``async def match(...)`` as a method are both legal, and + * including them would needlessly degrade common search/regex tool fields to + * ``dict[str, Any]``. Underscore-leading names are handled separately, not + * here: a non-dunder ``__token`` name-mangles, a dunder present on + * ``object``/``type`` resolves before the proxy hook, and implicit + * special-method lookup bypasses the hook. + */ +const RESERVED = new Set([ + 'False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', + 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', + 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', + 'return', 'try', 'while', 'with', 'yield', + // Not a keyword, but CPython refuses to ASSIGN it at compile time + // (`SyntaxError: cannot assign to __debug__`), which is what a TypedDict + // field, a parameter name, and a keyword argument all are. + '__debug__', +]); +/** `typing` symbols this module may emit, in the deterministic import order. */ +const TYPING_ORDER = ['Any', 'Literal', 'NotRequired', 'Protocol', 'TypedDict']; +/** `indent`-deep line prefix (four spaces per level to match PEP 8 output). */ +function pad(indent) { + return ' '.repeat(indent); +} +/** + * The `Cc` code points that survive the whitespace collapse in {@link describe} + * and have no printable form: the C0 controls, DEL, and the C1 controls. Only + * U+0009 to U+000D are absent, because ECMAScript `\s` already collapsed them — + * `\s` is TAB/VT/FF/SP/NBSP/ZWNBSP/Zs plus LF/CR/LS/PS, so no C1 code point is + * in it and the whole U+0080 to U+009F block reaches this rule intact. Those + * are not hypothetical input: they are what Windows-1252 bytes 0x80 to 0x9F + * (smart quotes, em dash) become when decoded as Latin-1. + * CPython rejects source containing a NUL outright + * (`SyntaxError: source code string cannot contain null bytes`), whether it + * sits in a docstring or in a comment, so one such byte anywhere in a schema + * description would make the whole generated SDK unparseable — under + * `mode: 'code'`, the model's only declaration of the tools. The rest are + * legal but invisible; escaping them with the same rule keeps the emitted text + * readable and the treatment uniform. + * + * The boundary is the category, not per-code-point addressability: `\xNN` + * addresses U+0000 to U+00FF, so one escape form covers `Cc` exactly. The + * invisible `Cf` formatting characters pass through by design — of them only + * U+00AD soft hyphen would fit `\xNN` at all, and escaping that one while + * U+200B ZWSP, U+200E/U+200F bidi marks, and U+2060 word joiner passed through + * would leave a rule that is neither category- nor addressability-shaped. The + * whole family is legal in both consumers, since only LF and CR terminate a + * Python string literal or a `#` comment. That set is the tokenizer's, not + * `str.splitlines()`': NEL (U+0085), LS (U+2028), and PS (U+2029) split a + * string at run time but do not end a physical line in source — measured on + * CPython 3.9.6 and 3.12.13, each accepted in both positions with the value + * round-tripping — so they are safe raw wherever they reach emitted text + * unescaped, which for all three is `JSON.stringify`, at two call sites: + * {@link pyScalar}'s literal path, and the subscript tool-name comment's own + * call, which a name carrying any of them always reaches, none being + * `XID_Continue`. The `description` path escapes NEL under the class above and + * folds LS and PS in {@link describe}'s `\s+` collapse, both being `\s`. + */ +const UNPRINTABLE = /[\u0000-\u0008\u000e-\u001f\u007f-\u009f]/g; +/** + * Unpaired surrogate code points, escaped by {@link describe} as `\uNNNN` — + * its own form, since `\xNN` stops at U+00FF. The `u` flag is what makes this + * the LONE ones: in Unicode mode a well-formed pair is a single astral code + * point outside D800 to DFFF, so an emoji in a description survives untouched. + * + * This is the NUL case from {@link UNPRINTABLE}, not the invisible-character + * case. Python source must be UTF-8-encodable and a lone surrogate is not, so + * `compile()` raises `UnicodeEncodeError: surrogates not allowed` for one + * anywhere in the text — measured on 3.9 for a string literal and for a `#` + * comment alike. A raw or MCP tool description reaches this: `JSON.parse` on a + * wire `"\ud800"` escape yields exactly such a code point. + */ +const LONE_SURROGATE = /[\ud800-\udfff]/gu; +/** + * The collapsed one-line `description` of a schema node (byte-stable across + * formatting churn), or `undefined` when the node carries none. Every caller + * passes an object — a validated property node, the `ToolSdkSchema` itself, or + * the `{ description }` wrapper {@link docLines} synthesizes — so only the + * description field needs guarding. A description that collapses + * to nothing (empty, or whitespace only) is `undefined` too: it documents the + * node no better than an absent one, and emitting it would leave an empty + * `"""` docstring or a bare `# ` line in the SDK. Only ECMAScript whitespace + * folds, so a description of whitespace plus one surviving control character is + * NOT absent: it collapses to that character's visible escape. + * + * Control characters left over after the whitespace collapse are rendered as + * their `\xNN` escapes (see {@link UNPRINTABLE}) and unpaired surrogates as + * their `\uNNNN` escapes (see {@link LONE_SURROGATE}); the escape's own backslash is + * emitted literally by both consumers, since {@link docLines} doubles it into a + * Python source escape and a `#` comment carries it verbatim. + */ +function describe(schema) { + const description = schema.description; + if (typeof description !== 'string') + return undefined; + const collapsed = description + .replace(/\s+/g, ' ') + .replace(UNPRINTABLE, char => `\\x${char.charCodeAt(0).toString(16).padStart(2, '0')}`) + .replace(LONE_SURROGATE, char => `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`) + .trim(); + return collapsed.length === 0 ? undefined : collapsed; +} +/** + * One-line docstring for a tool `description`, or no lines when there is none. + * Backslashes are doubled first, every quote is escaped, and a trailing + * backslash cannot survive: a description ending in `"` or an odd backslash + * would otherwise merge with (or escape) the closing triple quote and make + * the generated block — Code Mode's only SDK — syntactically invalid Python. + */ +function docLines(description, indent) { + const collapsed = describe({ description }); + if (collapsed === undefined) + return []; + const escaped = collapsed.replaceAll('\\', '\\\\').replaceAll('"', '\\"'); + return [`${pad(indent)}"""${escaped}"""`]; +} +/** + * CamelCase a name into a Python type identifier: non-identifier characters + * split words, `_` splits too (it is `XID_Continue`, so the split set names it + * explicitly), and a head that cannot start an identifier takes a `Tool` + * prefix. Unicode survives, so a `路径` field yields `路径`-based class names + * instead of collapsing to the bare prefix. A character that is not + * `XID_Continue` splits even when it is a letter, so a name whose NFKC folding + * would leave the identifier set is not carried through — the split set is the + * grammar's, not an ASCII approximation of it. + * + * The result is NFKC-normalized: these names are generated, never matched + * against a JSON key, so normalizing is free here and keeps what CPython + * compiles identical to what is emitted — unlike {@link isBareIdentifier}, + * which must reject unstable names outright. Normalizing AFTER the prefix + * decision is what makes that hold at the seam the prefix creates: `Tool` + + * a combining-mark head composes there (`U+0301` gives `Tooĺ`, U+013A), so + * normalizing only the un-prefixed part would emit a name CPython compiles to + * a different symbol. The second call is idempotent on the un-prefixed arm. + * + * The split set, the head test, and `toUpperCase()` all read the engine's + * Unicode tables, so this function carries the same version skew + * {@link isBareIdentifier} documents, by paths independent of it: a class name + * derived here reaches emitted text whenever any object shape in the tool's + * schema declares a `TypedDict`, and the predicate's verdict on the tool name + * does not gate that. The case mapping is the one that can fail on a name the + * predicate accepted; the worked example is there. + * @param raw - the schema field or tool name to derive from. + * @returns a class-name segment safe to emit. + */ +function camelCase(raw) { + const joined = raw + .split(/[^\p{XID_Continue}]+|_+/u) + .filter(part => part.length > 0) + .map(part => `${part.charAt(0).toUpperCase()}${part.slice(1)}`) + .join('') + .normalize('NFKC'); + return (/^\p{XID_Start}/u.test(joined) ? joined : `Tool${joined}`).normalize('NFKC'); +} +/** Class-name base cap keeping each emitted name — and total text — linear in schema depth. */ +const MAX_CLASS_NAME_BASE = 120; +/** + * Deepest `list[…]` nesting emitted into one annotation before the item type + * degrades to `Any`. CPython's tokenizer rejects a logical line holding more + * than 200 simultaneously-open brackets (`MAXLEVEL`, `SyntaxError: too many + * nested parentheses`), so an array chain deeper than that would render an SDK + * block that is not valid Python at all — the same failure the docstring + * escaping in {@link docLines} exists to prevent. 180 leaves headroom for the + * few brackets an annotation can add around the chain, all of which count + * toward the same limit. Per emission site, counting brackets open at the + * chain's innermost point: + * + * - Return annotation, `async def f(self, args: X) -> chain:` — 180 `list[` + * plus an innermost `Literal[`. The parameter list's `(` closed at the `)` + * before the `->`, so it is NOT open here: 181. + * - TypedDict field, `field: NotRequired[chain]` — a class-body line with no + * other open bracket, and its children start at `listDepth: 1` to reserve + * the `NotRequired[`, so 179 `list[` plus `Literal[`: 181. Required fields + * share that start for uniformity, spending one level of representable depth + * on a bracket they never emit. + * - Argument annotation, `async def f(self, args: chain) -> Y:` — the `(` IS + * still open around it: 180 `list[` plus `Literal[` plus the paren, 182, the + * worst case. Reachable only through a raw `register()` whose `parameters` + * is an array reached from the root through `oneOf` arms alone — the root + * array itself, or one nested under any depth of unions, since an arm + * inherits the enclosing depth unchanged (`A | B` opens no bracket). An + * object ancestor takes it out of this case: its fields restart the chain at + * the 181 site. `defineTool` compiles an object root, so the annotation is a + * bare TypedDict class name or a one-bracket `dict[str, Any]` when that + * object degrades — never a chain. + * + * A CPython grammar limit, not a deployment choice, so it is fixed rather than + * configurable. The sibling `ts-types` renderer needs no counterpart: nothing + * in the TypeScript grammar bounds nesting, and its SDK block is never type- + * checked. Only bracket nesting counts — a `oneOf` renders as a flat `A | B` + * chain and nested objects render as separate `class` statements, so neither + * accumulates open brackets at any depth. The invariant this cap serves is + * grammatical validity; see the `oneOf` arm in {@link renderType} for the one + * interpreter limit deliberately left uncapped. + */ +const MAX_LIST_NESTING = 180; +/** + * Cap a class-name base at {@link MAX_CLASS_NAME_BASE} (see the callers for + * why capping keeps the render linear). `slice` counts UTF-16 code units, so + * an astral character straddling the boundary would be cut in half and leave a + * lone surrogate — not an identifier character, and not even well-formed text; + * drop it rather than emit it. + */ +function capClassNameBase(base) { + if (base.length <= MAX_CLASS_NAME_BASE) + return base; + const capped = base.slice(0, MAX_CLASS_NAME_BASE); + return /[\uD800-\uDBFF]$/.test(capped) ? capped.slice(0, -1) : capped; +} +/** + * Reserve a unique class name from a base, suffixing `2`, `3`, … on collision. + * The base is capped at {@link MAX_CLASS_NAME_BASE} first: child class names + * derive from their parent's allocated name (`ParentChild`), so an unbounded + * schema of single-field objects would otherwise grow each name by one field + * per level and the sum of all names to Θ(depth²). Capping the base keeps each + * name — and the total emitted text — linear in depth. Collisions resume from + * the per-base counter in `state.nextClassCounter` rather than rescanning from + * `2`, so a deep chain sharing one capped base stays O(1) per allocation + * (amortized) instead of Θ(depth²) in time. + */ +function allocateClassName(base, state) { + const capped = capClassNameBase(base); + let name = capped; + if (state.usedClassNames.has(name)) { + let n = state.nextClassCounter.get(capped) ?? 2; + while (state.usedClassNames.has(`${capped}${n}`)) + n++; + name = `${capped}${n}`; + state.nextClassCounter.set(capped, n + 1); + } + state.usedClassNames.add(name); + return name; +} +/** + * Append a child-name segment to a parent class-name base, capping the result + * at {@link MAX_CLASS_NAME_BASE}. Capping AT PROPAGATION (not only inside + * {@link allocateClassName}) keeps each level O(1): a deep `oneOf`- or + * object-chain would otherwise carry an ever-growing ConsString down the tree + * and re-materialize it (via `.length`/`.slice`) at every level — Θ(depth²). + * The bounded base plus the collision counter still yields unique names. + * + * The join is NFKC-normalized because both sides are separately normalized yet + * their concatenation need not be: a base ending in a Hangul L jamo or LV + * syllable composes with a following V or T jamo head (`가` + `ᆨ` gives `각`), + * so the emitted class name would differ from the symbol CPython compiles, and + * two byte-distinct names could fold onto one — `usedClassNames` dedupes by the + * raw bytes, so the collision counter would not see it. Normalizing costs + * O(cap + segment) per level, the same order as the `slice` it feeds. The other + * two join points need no counterpart: `Args`/`Output` start with `A`/`O` and + * {@link allocateClassName}'s suffix is digits, none of which compose backwards. + */ +function childClassName(base, segment) { + return capClassNameBase(`${base}${segment}`.normalize('NFKC')); +} +/** + * Render one validated scalar as Python literal text (`True`/`False`, + * JSON-quoted strings, bare numbers). `null` cannot reach here: the `null` + * type renders directly as `None`, and the unified validator rejects a null + * `const`/`enum` entry on every other scalar type. + * + * A beyond-safe-range integral number takes `BigInt` digits rather than + * `String`: Python integers are arbitrary-precision, so the emitted digits ARE + * the value the model programs against, and `String` can give a different + * integer than the double holds (`2 ** 60` prints the rounded `...847000`, not + * the exact `...846976`) or no integer literal at all (`1e21` prints `1e+21`). + * `String`'s rounding is not a bug in it: `Number::toString` emits the shortest + * decimal string that re-reads to the same double, then pads to the exponent + * with zeros (1 significant digit for `1e20`, 16 for `2 ** 60`) — and when the + * shortest string is shorter than the double's exact value, those padded digits + * name an integer no double holds. Passing one back would have to cross the + * argument boundary as a JSON number — a double again — so the SDK would + * document a value no program can pass. `BigInt` needs no case split: where + * `String` is already exact (`2 ** 53`, `1e20`) the two agree byte for byte, + * and where it is not, `BigInt` is the exact one. The TS flavor needs no + * counterpart at all: its literal is re-read by a JS parser back into the same + * double. + * + * `JSON.stringify` is also what keeps this path's output parseable, and it is + * the only thing that does. It covers both classes of hazard: the two kinds of + * code point CPython refuses anywhere in source — NUL among the C0 controls, + * and the whole D800–DFFF unpaired-surrogate block, escaped under ES2019 + * well-formed stringification, which the engines range guarantees — and the + * ones that break this line in particular, a bare `"` closing the literal + * early, a trailing odd backslash eating the closing quote, and a bare LF/CR + * ending it before its terminator. The `description` path carries + * {@link UNPRINTABLE} and {@link LONE_SURROGATE} because nothing quotes it, + * and folds newlines in {@link describe}. + * + * That leans on a coincidence worth naming: every escape `JSON.stringify` can + * emit (`\"`, `\\`, `\b`, `\f`, `\n`, `\r`, `\t`, `\uXXXX`) is also a Python + * escape denoting the same character, so the emitted `Literal[...]` both + * parses and decodes back to the value the schema declared. DEL, the C1 + * controls (NEL among them), and LS/PS (U+2028/U+2029) do reach it raw — + * legal but invisible, byte-for-byte as in the TS flavor; escaping them is a + * both-flavors change. Those last three are legal here for the reason + * {@link UNPRINTABLE} records: they are `str.splitlines()` boundaries, not + * tokenizer line terminators. The subscript tool-name comment quotes its name + * through its own call to the same `JSON.stringify`, never through this + * function, and inherits both halves — escapes and pass-throughs alike. + */ +function pyScalar(value) { + if (value === true) + return 'True'; + if (value === false) + return 'False'; + if (typeof value === 'string') + return JSON.stringify(value); + if (typeof value === 'number' && Number.isInteger(value) && !Number.isSafeInteger(value)) { + return BigInt(value).toString(); + } + return String(value); +} +/** + * Render a validated scalar `const`/`enum` as `Literal[...]`, falling back to + * the broad type. Deliberately deviates from PEP 586, which restricts `Literal` + * parameters to int/bool/str/bytes/enum/None: a non-integral number + * `const`/`enum` emits a float literal (`Literal[1.5]`) a strict checker would + * reject. An integral one does not deviate — {@link pyScalar} emits int digits, + * including for the beyond-safe-range values it widens through `BigInt`, and + * PEP 586 admits int parameters. Harmless either way — the stub is advisory + * prompt text, only required to parse — and keeping the exact value + * communicates the constraint to the model. + */ +function renderConstrainedScalar(node, broad, state) { + if (node.const !== undefined) { + state.typing.add('Literal'); + return `Literal[${pyScalar(node.const)}]`; + } + if (node.enum !== undefined) { + state.typing.add('Literal'); + return `Literal[${node.enum.map(pyScalar).join(', ')}]`; + } + return broad; +} +/** + * Map one JSON-Schema node to a Python type expression, threading `state` to + * collect the `TypedDict` declarations and `typing` symbols a full render + * needs. `className` is the name to give an object node with properties (and + * the prefix for its nested objects). Handles every unified schema construct — + * `oneOf` (→ `X | Y`), `const`/`enum` (→ `Literal[...]`), `integer` (→ `int`), + * `null` (→ `None`) — and degrades an unsupported or malformed schema to `Any` + * without throwing, the same trusted-after-validation stance as the sibling + * {@link ./ts-types.ts | ts-types} renderer. {@link jsonSchemaToPy} is the + * context-free entry point; this is the collecting core. + */ +function renderType(schema, className, state) { + const newFrame = (schema, className, listDepth) => ({ schema, className, phase: 'start', listDepth, children: [], childIndex: 0, childTypes: [], entries: [] }); + try { + // Validate the WHOLE tree once, then trust it — the same contract the + // sibling ts-types renderer follows at a typed same-process boundary. Every + // node past this point is a validated JSON-schema node, so the walk reads + // its fields without re-checking. An unsupported or malformed schema throws + // here (before anything is emitted) and degrades to `Any`, the Python + // counterpart of the TS flavor's `unknown`. + assertSupportedJsonSchema(schema); + const frames = [newFrame(schema, className, 0)]; + let result; + /* jscpd:ignore-start -- the explicit-stack walk skeleton deliberately parallels + ts-types.ts's renderSupportedSchema; the two sibling renderers keep symmetric shapes. */ + const finish = (type) => { + frames.pop(); + const parent = frames.at(-1); + if (parent === undefined) + result = type; + else + parent.childTypes.push(type); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === undefined) + break; + if (frame.phase === 'children') { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === undefined) + throw new Error('missing python render child'); + frame.childIndex++; + frames.push(newFrame(child.schema, child.className, child.listDepth)); + continue; + } + if (frame.kind === 'oneOf') { + // Concatenate incrementally (template literal, not `Array.join`): V8 + // builds a lazy ConsString, so a deep oneOf chain materializes once + // at the root instead of re-materializing the accumulated string at + // every level (which `join` would, making it Θ(depth²)). This matches + // the array arm's template-literal laziness and ts-types' composable- + // document approach — the whole walk stays linear in schema depth. + let union = ''; + for (const [index, childType] of frame.childTypes.entries()) { + union = index === 0 ? childType : `${union} | ${childType}`; + } + finish(union); + continue; + } + /* jscpd:ignore-end */ + if (frame.kind === 'array') { + // `list[A | B]` needs no parentheses in Python. Array frames always + // schedule exactly one child, so its type is present. + /* v8 ignore next -- the ?? arm needs a childless array frame, which start never builds. */ + finish(`list[${frame.childTypes[0] ?? 'Any'}]`); + continue; + } + // typeddict: assemble AFTER the children so any nested class this one + // references is already declared (declaration order = reference order). + const node = frame.node; + const name = frame.allocated; + /* v8 ignore next -- typeddict frames always set node and allocated at start. */ + if (node === undefined || name === undefined) + throw new Error('missing typeddict frame state'); + const required = new Set(node.required); + const lines = [`class ${name}(TypedDict):`]; + for (let index = 0; index < frame.entries.length; index++) { + const entry = frame.entries[index]; + const fieldType = frame.childTypes[index]; + /* v8 ignore next -- entries and childTypes correspond one-to-one. */ + if (entry === undefined || fieldType === undefined) + throw new Error('missing typeddict field type'); + const [field, fieldSchema] = entry; + // The parent node passed assertSupportedJsonSchema, so every property + // value is a validated schema node. + const description = describe(fieldSchema); + if (description !== undefined) + lines.push(`${pad(1)}# ${description}`); + if (required.has(field)) { + lines.push(`${pad(1)}${field}: ${fieldType}`); + } + else { + state.typing.add('NotRequired'); + lines.push(`${pad(1)}${field}: NotRequired[${fieldType}]`); + } + } + // TypedDict syntax cannot express openness, so an open object states it + // in-band: the annotation is advisory either way, and `mode: 'code'` + // omits the native schemas, making this line the model's only signal + // that extra keys are accepted. + if (node.additionalProperties !== false) { + lines.push(`${pad(1)}# Additional keys beyond those declared are allowed.`); + } + // A closed empty object still needs a class body (`pass`) to be valid + // Python; the declared emptiness is the information. + if (lines.length === 1) + lines.push(`${pad(1)}pass`); + state.classes.push(lines.join('\n')); + finish(name); + continue; + } + frame.phase = 'children'; + const node = frame.schema; + if (node.oneOf !== undefined) { + frame.kind = 'oneOf'; + // A union renders as `A | B` — no brackets of its own, so the branches + // inherit the enclosing depth unchanged. + // + // Union LENGTH is deliberately uncapped, unlike list nesting. The two + // limits are different in kind: >200 open brackets is a SyntaxError + // from the tokenizer, so the text is not Python; a long `A | B | …` + // chain is grammatically valid at any length and only defeats CPython's + // C-recursion when `compile()` walks the left-nested BinOp spine + // (measured: 1,000 branches compile, 5,000 raise RecursionError). This + // block is prompt text — nothing compiles it — so that limit costs + // nothing here, while capping would retire the deep-chain tests that + // pin the walk's linear time and the class-name propagation cap. The + // standard this renderer holds is grammatical validity, not + // compilability under one interpreter's stack. + frame.children = node.oneOf.map((branch, index) => ({ schema: branch, className: childClassName(frame.className, `${index + 1}`), listDepth: frame.listDepth })); + continue; + } + if (node.type === undefined) { + state.typing.add('Any'); + finish('Any'); + continue; + } + switch (node.type) { + case 'string': + finish(renderConstrainedScalar(node, 'str', state)); + break; + case 'number': + finish(renderConstrainedScalar(node, 'float', state)); + break; + case 'integer': + finish(renderConstrainedScalar(node, 'int', state)); + break; + case 'boolean': + finish(renderConstrainedScalar(node, 'bool', state)); + break; + case 'null': + finish('None'); + break; + case 'array': { + if (node.items === undefined) { + state.typing.add('Any'); + finish('list[Any]'); + break; + } + // Past MAX_LIST_NESTING another `list[` would push the annotation + // beyond CPython's open-bracket limit and make the whole SDK block + // unparseable, so the chain degrades here instead — an unusable + // annotation either way, and this one is valid Python. + if (frame.listDepth >= MAX_LIST_NESTING) { + state.typing.add('Any'); + finish('Any'); + break; + } + // An array of objects names its item type after the array field. + frame.kind = 'array'; + frame.children = [{ schema: node.items, className: frame.className, listDepth: frame.listDepth + 1 }]; + break; + } + case 'object': { + // A missing `properties` is an empty property map, exactly as the + // unified validator and the TS renderer read it — NOT an unknown + // shape. The openness of the resulting empty object is decided below, + // so a closed empty object still declares an empty TypedDict rather + // than a permissive `dict[str, Any]`. + const entries = Object.entries(node.properties ?? {}); + // An empty `className` marks the context-free `jsonSchemaToPy` entry: + // there is no naming context to declare into, so degrade. This reads + // the CALL's className, not `frame.className`: the marker belongs to + // the whole walk, and frames propagate a derived name (a `oneOf` + // branch of the context-free root gets the index-derived name `1` — + // `childClassName` concatenates and caps, it does not go through + // `camelCase`), so a per-frame read would declare classes the caller + // has no way to receive, under a name that is not even a legal + // identifier: `class 1(TypedDict):`. A field + // name that is not a legal Python attribute is inexpressible as a + // class-syntax `TypedDict` field, so such an object degrades whole. + // A leading-double-underscore non-dunder field (`__token`) would be + // NAME-MANGLED inside class syntax (`_ClassName__token`), describing a + // different JSON key than the registered schema — degrade like any + // other inexpressible field name. + if (className === '' || !entries.every(([name]) => isBareIdentifier(name) && !RESERVED.has(name) && !(name.startsWith('__') && !name.endsWith('__')))) { + state.typing.add('Any'); + finish('dict[str, Any]'); + break; + } + // An OPEN empty object is any dict; a CLOSED empty object declares an + // empty TypedDict so "no keys accepted" survives into the SDK. + if (entries.length === 0 && node.additionalProperties !== false) { + state.typing.add('Any'); + finish('dict[str, Any]'); + break; + } + frame.kind = 'typeddict'; + frame.node = node; + frame.allocated = allocateClassName(frame.className, state); + state.typing.add('TypedDict'); + frame.entries = entries; + // A field annotation is its own logical line, so nesting restarts — + // at 1, reserving the bracket an optional field's `NotRequired[…]` + // wraps around it. frame.allocated was assigned three statements up; + // the ?? arm is for the type system only. + /* v8 ignore next -- allocated is always set before children are built. */ + frame.children = entries.map(([field, child]) => ({ schema: child, className: childClassName(frame.allocated ?? '', camelCase(field)), listDepth: 1 })); + break; + } + /* v8 ignore next 4 -- assertSupportedJsonSchema narrowed this closed type union. */ + default: { + state.typing.add('Any'); + finish('Any'); + } + } + } + /* v8 ignore next -- every root frame produces one expression. */ + return result ?? 'Any'; + } + catch { + // An unsupported or malformed schema failed validation (before any + // emission), or an unreachable internal invariant tripped. Either degrades + // the node to `Any` rather than crashing prompt assembly — the Python + // counterpart of the TS flavor's `unknown` fallback. + state.typing.add('Any'); + return 'Any'; + } +} +/** + * Map one JSON-Schema node to a context-free Python type expression from the + * `typing` module. Handles every unified schema construct — `object` (degraded + * to `dict[str, Any]`: naming a `TypedDict` requires the render context that + * {@link renderToolsSdkPy} supplies), `const`/`enum` (→ `Literal[...]`), + * `oneOf` (→ union), `string`/`number`/`integer`/`boolean`/`null`, `array` + * (`items` → `list[T]`) — and returns `Any` for an unsupported or malformed + * schema, matching the TS flavor's `unknown` fallback. Type annotations in the + * emitted SDK are advisory: Python does not enforce them at runtime. + * @param schema - the JSON-Schema node. + * @returns the Python type text. + */ +export function jsonSchemaToPy(schema) { + // A throwaway state whose class collector never escapes: an object with + // properties has nowhere to declare its TypedDict and degrades to + // dict[str, Any]. renderToolsSdkPy drives the named-TypedDict path. + return renderType(schema, '', { classes: [], usedClassNames: new Set(), nextClassCounter: new Map(), typing: new Set() }); +} +/** The fixed model-facing usage contract rendered above the declarations. */ +const SDK_INSTRUCTIONS = `## Writing code for run_code + +\`run_code\` takes two required arguments: \`code\` — the body of an async Python function (top-level \`await\` and \`return\` both work) — and \`description\`, a short summary of what the program does. At run time exactly two of the names declared below are bound: \`tools\` and \`ToolCallError\`. Everything else is a STATIC STUB describing argument and return types — in particular the \`TypedDict\` classes do NOT exist at run time, so build arguments as plain \`dict\`/\`list\` JSON values: \`await tools.name({"field": 1})\`, never \`FooArgs(field=1)\`, which raises \`NameError\`. Inside the program: + +- Call tools as \`await tools.name(args)\` — subscript access for exotic, reserved, or underscore-leading names: \`await tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value (each method's return type below). Tool arguments must be lossless JSON. +- A FAILED tool call raises \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose message is human-readable — wrap in \`try/except\` to handle and continue. +- Independent read-only calls MAY overlap under \`asyncio.gather\` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with \`await\`. +- Emit the run's answer with \`print(...)\` and/or a top-level \`return \`; the returned value must be lossless JSON. ONLY what you print and the returned value come back — intermediate tool results never enter the conversation, so extract just what you need. + +The available tools:`; +/** + * Render the full `tools:sdk` prompt section under `runtime.language === + * 'python'`: the Python-flavored usage instructions plus one named `TypedDict` + * per tool argument or output object (and per nested object) and one awaitable + * method per visible tool on a `Tools` protocol — typed args in, the tool's + * canonical output value out — with a `tools: Tools` singleton the model calls + * into. The `typing` import line lists exactly the symbols the render used. + * Deterministic — tools are emitted in lexicographic name order, and class + * declarations precede the protocol in that same order (nested classes before + * the parent that references them), so an unchanged tool set produces + * byte-identical text across assemblies. The sort is not a total order on + * byte-equal names, so two schemas sharing a name would render in argument + * order; the caller's visible-capability map is keyed by name, so the input + * never carries a duplicate. + * @param schemas - the tool schemas plus canonical output schemas to declare + * (the caller excludes `run_code` itself). + * @returns the complete section text. + */ +export function renderToolsSdkPy(schemas) { + const sorted = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0); + const state = { classes: [], usedClassNames: new Set(), nextClassCounter: new Map(), typing: new Set(['Protocol']) }; + // ONE ordered member stream, matching the documented lexicographic contract + // and the TypeScript flavor (which quotes exotic keys in place rather than + // partitioning them out). Interleaving is free here: a comment line between + // two `async def` lines is not a statement, so it changes nothing about how + // the class body parses. + const members = []; + let statements = 0; + for (const schema of sorted) { + const argType = renderType(schema.parameters, `${camelCase(schema.name)}Args`, state); + const outputType = renderType(schema.output, `${camelCase(schema.name)}Output`, state); + if (isBareIdentifier(schema.name) && !RESERVED.has(schema.name) && !schema.name.startsWith('_')) { + // A docstring only documents its method when it is the FIRST statement + // of that method's body. Emitted before the `async def` it would instead + // become the `Tools` class docstring (for the first tool) or a dead + // expression (for every later one), leaving every method undocumented — + // and under `mode: 'code'` this SDK is the model's only description of + // what a tool does. A docstring is a complete body, so the `...` stub is + // only for the description-less case. + const doc = docLines(schema.description, 2); + members.push(doc.length > 0 + ? `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}:` + : `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}: ...`); + members.push(...doc); + statements += 1; + } + else { + // Not reachable as ``tools.name`` — the model reaches it via + // ``tools[name]``. Exotic names and hard keywords are not legal + // attributes at all; an underscore-leading name (``_foo``) IS a legal + // attribute and is routed here anyway, because the forms that break + // split three ways — a non-dunder ``__token`` name-mangles at the CALL + // site, a dunder that exists on ``object``/``type`` (``__class__``, + // ``__doc__``) resolves before ``__getattr__`` ever runs, and implicit + // special-method lookup skips the hook entirely — and one rule over the + // whole family costs nothing while a per-form rule would have to + // enumerate them (see {@link RESERVED}). The stub lists it as a subscript comment + // (referencing the named TypedDicts too) so a reader sees what is + // accessible; runtime resolution goes through the proxy's __getitem__. + members.push(`${pad(1)}# tools[${JSON.stringify(schema.name)}](args: ${argType}) -> ${outputType}`); + const description = describe(schema); + if (description !== undefined) + members.push(`${pad(1)}# ${description}`); + } + } + // Subscript entries are COMMENTS, not statements: a class body of only + // comments fails to parse, so `pass` is required whenever no method was + // emitted — including the subscript-only tool set. + const bodyLines = statements > 0 ? members : [`${pad(1)}pass`, ...members]; + const body = bodyLines.join('\n'); + const imports = TYPING_ORDER.filter(symbol => state.typing.has(symbol)); + const classBlock = state.classes.length > 0 ? `${state.classes.join('\n\n')}\n\n` : ''; + const errorDeclaration = 'class ToolCallError(Exception):\n toolName: str'; + const declaration = `from typing import ${imports.join(', ')}\n\n${errorDeclaration}\n\n${classBlock}class Tools(Protocol):\n${body}\n\ntools: Tools`; + return `${SDK_INSTRUCTIONS}\n\n\`\`\`python\n${declaration}\n\`\`\``; +} +//# sourceMappingURL=py-types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.d.ts new file mode 100644 index 0000000..7c38bf1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.d.ts @@ -0,0 +1,241 @@ +/** Unified JSON-value schema DSL, inference, compilation, and typed tool helper. @module dsh-tools/schema */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { JsonValue } from '@deepseek-ai/dsh-session'; +import type { ToolDefinition, ToolExecution, ToolExecutionResult, ToolRunContext, ToolResult } from './index.ts'; +import type { JsonSchemaNode, ObjectJsonSchema } from './json-schema.ts'; +import type { ToolCallView, ToolResultView } from './presentation.ts'; +/** Annotation keywords shared by every author-facing schema node. */ +export interface ValueSchemaAnnotations { + /** Human-readable description projected into JSON Schema and generated types. */ + description?: string; + /** Human-readable title projected into JSON Schema. */ + title?: string; + /** Non-validating default annotation; it must be lossless JSON data. */ + default?: JsonValue; + /** Non-validating examples annotation; it must be lossless JSON data. */ + examples?: JsonValue; +} +/** String value schema with type-correct literal constraints. */ +export interface StringValueSchemaSpec extends ValueSchemaAnnotations { + type: 'string'; + enum?: readonly string[]; + const?: string; +} +/** Finite JSON-number schema with type-correct literal constraints. */ +export interface NumberValueSchemaSpec extends ValueSchemaAnnotations { + type: 'number'; + enum?: readonly number[]; + const?: number; +} +/** Integer schema with type-correct literal constraints. */ +export interface IntegerValueSchemaSpec extends ValueSchemaAnnotations { + type: 'integer'; + enum?: readonly number[]; + const?: number; +} +/** Boolean value schema with type-correct literal constraints. */ +export interface BooleanValueSchemaSpec extends ValueSchemaAnnotations { + type: 'boolean'; + enum?: readonly boolean[]; + const?: boolean; +} +/** Null value schema with type-correct literal constraints. */ +export interface NullValueSchemaSpec extends ValueSchemaAnnotations { + type: 'null'; + enum?: readonly null[]; + const?: null; +} +/** Array value schema; omitted `items` accepts any lossless JSON item. */ +export interface ArrayValueSchemaSpec extends ValueSchemaAnnotations { + type: 'array'; + items?: ValueSchemaSpec; +} +/** + * Explicit object value schema. Openness is mandatory so a nested or output + * object never acquires an accidental JSON Schema default. + */ +export interface ObjectValueSchemaSpec extends ValueSchemaAnnotations { + type: 'object'; + properties?: ParameterSchemaSpec; + additionalProperties: boolean; +} +/** Author-only unconstrained lossless JSON node. */ +export interface JsonValueSchemaSpec extends ValueSchemaAnnotations { + type: 'json'; +} +/** Exact-one union schema; at least two branches are required. */ +export interface OneOfValueSchemaSpec extends ValueSchemaAnnotations { + oneOf: readonly [ValueSchemaSpec, ValueSchemaSpec, ...ValueSchemaSpec[]]; +} +/** One author-facing schema for any lossless JSON value root. */ +export type ValueSchemaSpec = StringValueSchemaSpec | NumberValueSchemaSpec | IntegerValueSchemaSpec | BooleanValueSchemaSpec | NullValueSchemaSpec | ArrayValueSchemaSpec | ObjectValueSchemaSpec | JsonValueSchemaSpec | OneOfValueSchemaSpec; +/** One implicit parameter-root property, optionally required. */ +export type ParameterPropertySpec = ValueSchemaSpec & { + required?: true; +}; +/** + * Tool parameter schema. The map itself is an implicit open object root; + * requiredness remains a per-property `required: true` annotation. + */ +export type ParameterSchemaSpec = { + [key: string]: ParameterPropertySpec; + [key: symbol]: never; +}; +/** Raw JSON Schema projection of the implicit parameter object. */ +export interface ParameterJsonSchema extends ObjectJsonSchema { + properties: Record; +} +/** Flatten an intersection into one object type for readable hovers. */ +type Simplify = { + [K in keyof T]: T[K]; +} & {}; +/** String keys of one property map; runtime compilation rejects symbol keys. */ +type StringKeyOf = Extract; +/** Keys of a property map marked `required: true`. */ +type RequiredKeys = { + [K in StringKeyOf]: S[K] extends { + required: true; + } ? K : never; +}[StringKeyOf]; +/** Infer the declared value of one parameter property without key optionality. */ +type InferProperty = InferValueAt; +/** Infer an implicit property map into required and optional object keys. */ +type InferProperties = Simplify<{ + [K in RequiredKeys]: InferProperty; +} & { + [K in Exclude, RequiredKeys>]?: InferProperty; +}>; +/** Infer an explicit object node, including its declared openness. */ +type InferObject = S extends { + properties: infer P; +} ? S['additionalProperties'] extends true ? InferProperties & Record : InferProperties : S['additionalProperties'] extends true ? Record : Record; +/** Infer a scalar node's literal constraint before its broad primitive type. */ +type InferScalar = S extends { + const: infer C; +} ? C : S extends { + enum: readonly (infer E)[]; +} ? E : Fallback; +/** Add one schema-container level to bounded compile-time inference. */ +type NextInferenceDepth = [unknown, ...Depth]; +/** Infer one node without recursively checking it against the full author union. */ +type InferValueAt = Depth['length'] extends 16 ? JsonValue : S extends { + type: 'string'; +} ? InferScalar : S extends { + type: 'number' | 'integer'; +} ? InferScalar : S extends { + type: 'boolean'; +} ? InferScalar : S extends { + type: 'null'; +} ? null : S extends { + type: 'array'; +} ? S extends { + items: infer I; +} ? InferValueAt>[] : JsonValue[] : S extends { + type: 'object'; + additionalProperties: boolean; +} ? InferObject> : S extends { + type: 'json'; +} ? JsonValue : S extends { + oneOf: readonly unknown[]; +} ? InferValueAt> : never; +/** + * Infer the TypeScript value accepted by an author-facing value schema. Exact + * inference is bounded to 16 container levels, then falls back to `JsonValue`. + */ +export type InferValue = InferValueAt; +/** Infer the TypeScript argument object for an implicit parameter schema. */ +export type InferArgs = InferProperties; +/** + * Compile one author-facing value schema to the enforced raw JSON Schema + * subset. The author-only `json` node becomes an annotation-only schema. + * @param spec - schema for any JSON-value root. + * @returns The asserted raw schema projection. + */ +export declare function valueSchemaSpecToJsonSchema(spec: ValueSchemaSpec): JsonSchemaNode; +/** + * Compile the implicit open parameter object into raw JSON Schema. + * @param spec - per-property parameter definitions. + * @returns An object-rooted raw schema with no implicit-root openness override. + */ +export declare function parameterSchemaSpecToJsonSchema(spec: ParameterSchemaSpec): ParameterJsonSchema; +/** Invalid model-generated arguments for a typed tool. */ +export declare class ToolArgsError extends HarnessError { + /** Individual violations in schema-walk order. */ + readonly violations: string[]; + constructor(violations: string[]); +} +/** + * Validate model-generated arguments against an implicit parameter schema. + * @param spec - declared parameter schema. + * @param args - candidate arguments, however malformed. + * @returns Path-qualified violations; empty means valid. + */ +export declare function validateArgs(spec: ParameterSchemaSpec, args: unknown): string[]; +/** Options for {@link defineTool}. */ +export interface DefineToolOptions { + /** Tool name (must be unique). */ + readonly name: string; + /** Human-readable description sent to the model. */ + readonly description: string; + /** Per-property parameter schema compiled to an implicit open object root. */ + readonly parameters: S; + /** Canonical output schema plus pure Native and presentation projections. */ + readonly output: { + /** Schema enforced against every successful body or policy-replaced value. */ + readonly schema: O; + /** Pure Native/model rendering of one validated canonical value. */ + render(args: InferArgs, value: InferValue>): ContentBlock[]; + /** Pure replayable presentation metadata for direct top-level calls. */ + presentationMeta?(args: InferArgs, value: InferValue>): JsonValue; + }; + /** Optional positive cooperative timeout budget in milliseconds. */ + readonly timeoutMs?: number; + /** + * Pure classifier for sibling overlap. + * @param args - typed validated arguments. + * @returns Whether the call may join a parallel group. + */ + isConcurrencySafe?(args: InferArgs): boolean; + /** + * Execute the tool after argument validation. + * @param args - typed validated arguments. + * @param exec - execution identity, caller, cancellation, and nesting data. + * @returns The canonical value declared by `output.schema`. + */ + execute(args: InferArgs, exec: ToolRunContext): Promise>>; + /** + * Optional last-mile content transform for every normalized outcome. Unlike + * `execute`, arguments remain `unknown` because invalid-input failures also + * reach this callback. See {@link ToolDefinition.finalizeContent}. + * @param exec - immutable execution identity and arguments. + * @param result - complete normalized outcome before materialization. + * @returns replacement content, or `undefined` to preserve it. + */ + finalizeContent?(exec: Readonly, result: Readonly): ContentBlock[] | undefined; + /** + * Pure pending-state presenter. + * @param args - typed validated arguments. + * @returns Tool-owned render intent, or `undefined` for the generic card. + */ + presentCall?(args: InferArgs): ToolCallView | undefined; + /** + * Pure completed-state presenter. + * @param args - typed validated arguments. + * @param result - final model-facing tool result. + * @returns Tool-owned render intent, or `undefined` for the generic card. + */ + presentResult?(args: InferArgs, result: ToolResult): ToolResultView | undefined; +} +/** + * Define a first-party tool with inferred arguments and strict execution + * validation. Replay-only presenters validate softly and fall back to generic + * rendering for obsolete logged arguments. + * @param options - typed definition and optional finalizer and presenters. + * @returns A registry-ready definition. + */ +export declare function defineTool(options: DefineToolOptions): ToolDefinition; +export {}; +//# sourceMappingURL=schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.js new file mode 100644 index 0000000..cde42bc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.js @@ -0,0 +1,349 @@ +/** Unified JSON-value schema DSL, inference, compilation, and typed tool helper. @module dsh-tools/schema */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import { assertSupportedJsonSchema, isJsonSchemaRecord, isPlainJsonArray, JsonSchemaError, validateJsonSchemaValue } from "./json-schema.js"; +const ANNOTATION_KEYS = ['description', 'title', 'default', 'examples']; +/** Throw one author-schema violation through the shared schema error type. */ +function authorError(message) { + throw new JsonSchemaError([message]); +} +/** Copy own annotation fields for validation by the raw-schema boundary. */ +function copyAnnotations(source, target) { + if (Object.hasOwn(source, 'description')) + target.description = source.description; + if (Object.hasOwn(source, 'title')) + target.title = source.title; + if (Object.hasOwn(source, 'default')) + target.default = source.default; + if (Object.hasOwn(source, 'examples')) + target.examples = source.examples; +} +/** Reject author-only keys outside one node's declared vocabulary. */ +function assertAuthorKeys(source, path, allowed) { + for (const key of Object.keys(source)) { + if (!allowed.includes(key)) + authorError(`${path}.${key} is not supported by the value schema DSL`); + } +} +/** Install a compiled node without giving `__proto__` assignment semantics. */ +function assignCompiledNode(destination, node) { + switch (destination.kind) { + case 'root': + destination.holder.value = node; + break; + case 'property': + Object.defineProperty(destination.target, destination.key, { + value: node, + enumerable: true, + configurable: true, + writable: true, + }); + break; + case 'item': + destination.target.items = node; + break; + case 'one-of': + destination.target[destination.index] = node; + break; + } +} +/** Install a compiled property map at its root or containing object node. */ +function assignCompiledPropertyMap(destination, compiled) { + if (destination.kind === 'root') { + destination.holder.value = compiled; + } + else { + destination.target.properties = compiled.properties; + } +} +/** Execute an author-schema compilation task graph without recursive descent. */ +function runSchemaCompiler(initial) { + const seen = new Set(); + const tasks = [initial]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + seen.delete(task.input); + continue; + } + if (task.kind === 'property-map-tail') { + if (task.required.length > 0) { + task.compiled.required = task.required; + if (task.destination.kind === 'object') + task.destination.target.required = task.required; + } + continue; + } + if (task.kind === 'property') { + if (!isJsonSchemaRecord(task.property)) + authorError(`${task.path} must be a value schema object`); + if (Object.hasOwn(task.property, 'required') && task.property.required !== true) { + authorError(`${task.path}.required must be true when present`); + } + if (Object.hasOwn(task.property, 'required') && task.property.required === true) + task.required.push(task.key); + tasks.push({ + kind: 'value', + input: task.property, + path: task.path, + allowRequired: true, + destination: { kind: 'property', target: task.properties, key: task.key }, + }); + continue; + } + if (task.kind === 'property-map') { + if (!isJsonSchemaRecord(task.input)) + authorError(`${task.path} must be an object of value schemas`); + if (seen.has(task.input)) + authorError(`${task.path} is circular`); + seen.add(task.input); + const compiled = { properties: {} }; + const required = []; + assignCompiledPropertyMap(task.destination, compiled); + tasks.push({ kind: 'leave', input: task.input }); + tasks.push({ kind: 'property-map-tail', compiled, required, destination: task.destination }); + const entries = Object.entries(task.input); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) + continue; + tasks.push({ + kind: 'property', + property: entry[1], + path: `${task.path}.${entry[0]}`, + key: entry[0], + properties: compiled.properties, + required, + }); + } + continue; + } + const { input, path } = task; + if (!isJsonSchemaRecord(input)) + authorError(`${path} must be a value schema object`); + if (seen.has(input)) + authorError(`${path} is circular`); + seen.add(input); + const authorKeys = [...ANNOTATION_KEYS, ...(task.allowRequired ? ['required'] : [])]; + const node = {}; + assignCompiledNode(task.destination, node); + tasks.push({ kind: 'leave', input }); + if (Object.hasOwn(input, 'oneOf')) { + assertAuthorKeys(input, path, [...authorKeys, 'oneOf', 'type']); + if (Object.hasOwn(input, 'type')) + authorError(`${path} cannot declare both type and oneOf`); + if (!isPlainJsonArray(input.oneOf)) + authorError(`${path}.oneOf must be an array of at least two value schemas`); + const branches = []; + node.oneOf = branches; + copyAnnotations(input, node); + for (let index = input.oneOf.length - 1; index >= 0; index--) { + tasks.push({ + kind: 'value', + input: input.oneOf[index], + path: `${path}.oneOf[${index}]`, + allowRequired: false, + destination: { kind: 'one-of', target: branches, index }, + }); + } + continue; + } + const inputType = Object.hasOwn(input, 'type') ? input.type : undefined; + switch (inputType) { + case 'json': + assertAuthorKeys(input, path, [...authorKeys, 'type']); + copyAnnotations(input, node); + break; + case 'object': + assertAuthorKeys(input, path, [...authorKeys, 'type', 'properties', 'additionalProperties']); + if (!Object.hasOwn(input, 'additionalProperties') || typeof input.additionalProperties !== 'boolean') { + authorError(`${path}.additionalProperties must be explicitly true or false`); + } + node.type = 'object'; + copyAnnotations(input, node); + node.additionalProperties = input.additionalProperties; + if (Object.hasOwn(input, 'properties')) { + tasks.push({ + kind: 'property-map', + input: input.properties, + path: `${path}.properties`, + destination: { kind: 'object', target: node }, + }); + } + break; + case 'array': + assertAuthorKeys(input, path, [...authorKeys, 'type', 'items']); + node.type = 'array'; + copyAnnotations(input, node); + if (Object.hasOwn(input, 'items')) { + tasks.push({ + kind: 'value', + input: input.items, + path: `${path}.items`, + allowRequired: false, + destination: { kind: 'item', target: node }, + }); + } + break; + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': + assertAuthorKeys(input, path, [...authorKeys, 'type', 'enum', 'const']); + node.type = inputType; + copyAnnotations(input, node); + if (Object.hasOwn(input, 'enum')) { + if (!isPlainJsonArray(input.enum)) + authorError(`${path}.enum must be a non-empty array of scalar values`); + node.enum = Array.from(input.enum, entry => entry); + } + if (Object.hasOwn(input, 'const')) + node.const = input.const; + break; + default: + authorError(`${path}.type must be string/number/integer/boolean/null/array/object/json, or use oneOf`); + } + } +} +/** Compile one implicit property map, collecting per-property requiredness. */ +function compilePropertyMap(input, path) { + const holder = {}; + runSchemaCompiler({ kind: 'property-map', input, path, destination: { kind: 'root', holder } }); + /* v8 ignore next -- the root task assigns before scheduling any descendants. */ + return holder.value ?? authorError(`${path} did not compile`); +} +/** Compile one author node without applying any consumer root restriction. */ +function compileValueSchema(input, path) { + const holder = {}; + runSchemaCompiler({ kind: 'value', input, path, allowRequired: false, destination: { kind: 'root', holder } }); + /* v8 ignore next -- the root task assigns before scheduling any descendants. */ + return holder.value ?? authorError(`${path} did not compile`); +} +/** + * Compile one author-facing value schema to the enforced raw JSON Schema + * subset. The author-only `json` node becomes an annotation-only schema. + * @param spec - schema for any JSON-value root. + * @returns The asserted raw schema projection. + */ +export function valueSchemaSpecToJsonSchema(spec) { + const schema = compileValueSchema(spec, 'schema'); + assertSupportedJsonSchema(schema); + return schema; +} +/** + * Compile the implicit open parameter object into raw JSON Schema. + * @param spec - per-property parameter definitions. + * @returns An object-rooted raw schema with no implicit-root openness override. + */ +export function parameterSchemaSpecToJsonSchema(spec) { + const compiled = compilePropertyMap(spec, 'parameters'); + const schema = { + type: 'object', + properties: compiled.properties, + ...(compiled.required === undefined ? {} : { required: compiled.required }), + }; + assertSupportedJsonSchema(schema); + return schema; +} +/** Invalid model-generated arguments for a typed tool. */ +export class ToolArgsError extends HarnessError { + /** Individual violations in schema-walk order. */ + violations; + constructor(violations) { + super(`invalid arguments: ${violations.join('; ')}`, 'INVALID_ARGS'); + this.name = 'ToolArgsError'; + this.violations = violations; + } +} +/** + * Validate model-generated arguments against an implicit parameter schema. + * @param spec - declared parameter schema. + * @param args - candidate arguments, however malformed. + * @returns Path-qualified violations; empty means valid. + */ +export function validateArgs(spec, args) { + return validateJsonSchemaValue(parameterSchemaSpecToJsonSchema(spec), args, ''); +} +/** + * Define a first-party tool with inferred arguments and strict execution + * validation. Replay-only presenters validate softly and fall back to generic + * rendering for obsolete logged arguments. + * @param options - typed definition and optional finalizer and presenters. + * @returns A registry-ready definition. + */ +export function defineTool(options) { + // Object-literal methods do not use `this`; retaining references is safe. + // oxlint-disable-next-line typescript/unbound-method + const userExecute = options.execute; + // oxlint-disable-next-line typescript/unbound-method + const userFinalizeContent = options.finalizeContent; + // oxlint-disable-next-line typescript/unbound-method + const userRender = options.output.render; + // oxlint-disable-next-line typescript/unbound-method + const userPresentationMeta = options.output.presentationMeta; + // oxlint-disable-next-line typescript/unbound-method + const userPresentCall = options.presentCall; + // oxlint-disable-next-line typescript/unbound-method + const userPresentResult = options.presentResult; + // oxlint-disable-next-line typescript/unbound-method + const userIsConcurrencySafe = options.isConcurrencySafe; + if (options.timeoutMs !== undefined && (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) { + throw new Error(`defineTool(${options.name}): timeoutMs must be a positive finite number`); + } + const parameters = parameterSchemaSpecToJsonSchema(options.parameters); + const outputSchema = valueSchemaSpecToJsonSchema(options.output.schema); + const validate = (args) => validateJsonSchemaValue(parameters, args, ''); + const tool = { + name: options.name, + description: options.description, + parameters: parameters, + output: { + schema: outputSchema, + render(args, value) { + return userRender(args, value); + }, + ...userPresentationMeta !== undefined ? { + presentationMeta(args, value) { + return userPresentationMeta(args, value); + }, + } : {}, + }, + ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}), + async execute(args, exec) { + const violations = validate(args); + if (violations.length > 0) + throw new ToolArgsError(violations); + return userExecute(args, exec); + }, + }; + if (userFinalizeContent) { + tool.finalizeContent = (exec, result) => userFinalizeContent(exec, result); + } + // Presentation is display-only and may run on REPLAY of arbitrary logged args + // (possibly from an older schema), so it must never throw: validate softly and + // fall back to `undefined` (a generic UI presentation) on any mismatch, rather + // than the hard `ToolArgsError` the execute path raises. + if (userPresentCall) { + tool.presentCall = (args) => { + if (validate(args).length > 0) + return undefined; + return userPresentCall(args); + }; + } + if (userPresentResult) { + tool.presentResult = (args, result) => { + if (validate(args).length > 0) + return undefined; + return userPresentResult(args, result); + }; + } + if (userIsConcurrencySafe) { + tool.isConcurrencySafe = (args) => { + if (validate(args).length > 0) + return false; + return userIsConcurrencySafe(args); + }; + } + return tool; +} +//# sourceMappingURL=schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.d.ts new file mode 100644 index 0000000..40d83ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.d.ts @@ -0,0 +1,25 @@ +/** Canonical tool-definition fixtures for repository tests. @module dsh-tools/testing */ +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { DefineToolOptions, ParameterSchemaSpec } from './schema.ts'; +import type { ToolDefinition, ToolRunContext } from './index.ts'; +declare const CONTENT_VALUE_SCHEMA: { + readonly type: "array"; + readonly items: { + readonly type: "json"; + }; +}; +/** Options for a fixture whose canonical value is its rendered content array. */ +export type ContentToolFixtureOptions = Omit, 'output' | 'execute'> & { + /** Produce the fixture's content blocks as its canonical test value. */ + execute(args: import('./schema.ts').InferArgs, exec: ToolRunContext): Promise; +}; +/** + * Define a test fixture that deliberately uses its content blocks as the + * canonical JSON value. Product tools must declare domain-owned DTOs instead. + * @param options - ordinary fixture fields plus a content-producing body. + * @returns a registry-ready tool with an explicit JSON-array output contract. + * @internal + */ +export declare function defineContentToolFixture(options: ContentToolFixtureOptions): ToolDefinition; +export {}; +//# sourceMappingURL=testing.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.js new file mode 100644 index 0000000..fe03f8e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.js @@ -0,0 +1,25 @@ +/** Canonical tool-definition fixtures for repository tests. @module dsh-tools/testing */ +import { defineTool } from "./schema.js"; +const CONTENT_VALUE_SCHEMA = { type: 'array', items: { type: 'json' } }; +/** + * Define a test fixture that deliberately uses its content blocks as the + * canonical JSON value. Product tools must declare domain-owned DTOs instead. + * @param options - ordinary fixture fields plus a content-producing body. + * @returns a registry-ready tool with an explicit JSON-array output contract. + * @internal + */ +export function defineContentToolFixture(options) { + // oxlint-disable-next-line typescript/unbound-method + const execute = options.execute; + return defineTool({ + ...options, + output: { + schema: CONTENT_VALUE_SCHEMA, + render: (_args, value) => value, + }, + async execute(args, exec) { + return await execute(args, exec); + }, + }); +} +//# sourceMappingURL=testing.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.d.ts new file mode 100644 index 0000000..1d504e9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.d.ts @@ -0,0 +1,37 @@ +/** + * Code Mode codegen: the pure projection from registered tool schemas to the TypeScript SDK + * text the model programs against (the `tools:sdk` prompt section). Sibling of + * `json-schema.ts` — `schemas()` (native function calling) and this module (the generated + * `declare const tools` API) are two projections of the same store. + * @module @deepseek-ai/dsh-tools/src/ts-types + */ +import type { ToolSchema } from '@deepseek-ai/dsh-llm'; +import type { JsonSchemaNode } from './json-schema.ts'; +/** Internal Code Mode projection: the model-facing schema plus the canonical output schema. */ +export interface ToolSdkSchema extends ToolSchema { + /** Validated canonical value returned by the tool binding. */ + output: JsonSchemaNode; +} +/** + * Map one enforced JSON-Schema node to a TypeScript type literal. Supports + * every unified schema construct and returns `unknown` for malformed or + * unsupported inputs without throwing. + * @param schema - the JSON-Schema node (any shape; hostile inputs degrade). + * @param indent - the indentation level for nested object members. + * @returns the TS type text (multi-line for objects with properties). + */ +export declare function jsonSchemaToTs(schema: unknown, indent?: number): string; +/** + * Render the full `tools:sdk` prompt section: the fixed usage instructions + * plus one `declare const tools` interface covering every given tool. + * Deterministic — tools are emitted in lexicographic name order, so an + * unchanged tool set produces byte-identical text across assemblies. The sort + * is not a total order on byte-equal names, so two schemas sharing a name + * would render in argument order; the caller's visible-capability map is keyed + * by name, so the input never carries a duplicate. + * @param schemas - the tool schemas to declare (the caller excludes + * `run_code` itself). + * @returns the complete section text. + */ +export declare function renderToolsSdk(schemas: ToolSdkSchema[]): string; +//# sourceMappingURL=ts-types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.js new file mode 100644 index 0000000..68a65cc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.js @@ -0,0 +1,265 @@ +/** + * Code Mode codegen: the pure projection from registered tool schemas to the TypeScript SDK + * text the model programs against (the `tools:sdk` prompt section). Sibling of + * `json-schema.ts` — `schemas()` (native function calling) and this module (the generated + * `declare const tools` API) are two projections of the same store. + * @module @deepseek-ai/dsh-tools/src/ts-types + */ +import { assertSupportedJsonSchema } from "./json-schema.js"; +/** Property names that are valid bare TS identifiers; anything else is quoted. */ +const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/; +/** Render an object key: bare when it is a valid identifier, quoted otherwise (every name stays reachable, no aliasing). */ +function renderKey(name) { + return IDENTIFIER.test(name) ? name : JSON.stringify(name); +} +/** One `indent`-deep line prefix (two spaces per level). */ +function pad(indent) { + return ' '.repeat(indent); +} +/** A one-line JSDoc block for a schema `description`, or no lines when there is none. */ +function docLines(description, indent) { + if (typeof description !== 'string' || description.length === 0) + return []; + // Collapse prose to stable one-line docs and escape comment closers so a + // schema description cannot terminate generated JSDoc. + const collapsed = description.replace(/\s+/g, ' ').trim(); + return [`${pad(indent)}/** ${collapsed.replaceAll('*/', String.raw `*\/`)} */`]; +} +/** Render one scalar already validated by the unified schema boundary. */ +function renderScalar(value) { + return JSON.stringify(value); +} +/** Render a validated scalar `const`/`enum`, falling back to the broad type. */ +function renderConstrainedScalar(node, type) { + const broad = type === 'integer' ? 'number' : type; + if (Object.hasOwn(node, 'const')) + return renderScalar(node.const); + if (Object.hasOwn(node, 'enum')) { + return node.enum.map(renderScalar).join(' | '); + } + return broad; +} +/** Build one document from captured parts while retaining the legacy array-parenthesization test. */ +function typeDocumentFrom(parts) { + return { + parts, + containsUnionOrIntersection: parts.some(part => typeof part === 'string' + ? part.includes('|') || part.includes('&') + : part.containsUnionOrIntersection), + }; +} +/** Build a small document without an intermediate array at each call site. */ +function typeDocument(...parts) { + return typeDocumentFrom(parts); +} +/** Flatten a nested document with an explicit work stack. */ +function flattenTypeDocument(document) { + const chunks = []; + const tasks = [document]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (typeof task === 'string') { + chunks.push(task); + continue; + } + for (let index = task.parts.length - 1; index >= 0; index--) { + const part = task.parts[index]; + /* v8 ignore next -- the loop is bounded by the captured part count. */ + if (part !== undefined) + tasks.push(part); + } + } + return chunks.join(''); +} +/** Initialize one schema-render frame with empty aggregation state. */ +function schemaRenderFrame(node, indent) { + return { node, indent, phase: 'start', children: [], childIndex: 0, childDocuments: [], entries: [] }; +} +/** Render an already asserted schema to a composable document. */ +function renderSupportedSchema(schema, indent) { + const frames = [schemaRenderFrame(schema, indent)]; + let rootDocument; + const finish = (document) => { + frames.pop(); + const parent = frames.at(-1); + if (parent === undefined) + rootDocument = document; + else + parent.childDocuments.push(document); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === undefined) + break; + if (frame.phase === 'children') { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === undefined) + throw new Error('missing schema render child'); + frame.childIndex++; + frames.push(schemaRenderFrame(child.node, child.indent)); + continue; + } + if (frame.kind === 'oneOf') { + const parts = []; + for (let index = 0; index < frame.childDocuments.length; index++) { + if (index > 0) + parts.push(' | '); + const child = frame.childDocuments[index]; + /* v8 ignore next -- child documents correspond one-to-one with children. */ + if (child !== undefined) + parts.push(child); + } + finish(typeDocumentFrom(parts)); + continue; + } + if (frame.kind === 'array') { + const child = frame.childDocuments[0]; + /* v8 ignore next -- array frames always schedule exactly one child. */ + if (child === undefined) + throw new Error('missing array item type'); + finish(child.containsUnionOrIntersection + ? typeDocument('(', child, ')[]') + : typeDocument(child, '[]')); + continue; + } + const required = new Set(frame.node.required); + const parts = ['{']; + for (let index = 0; index < frame.entries.length; index++) { + const entry = frame.entries[index]; + const child = frame.childDocuments[index]; + /* v8 ignore next -- object entries and child documents have the same length. */ + if (entry === undefined || child === undefined) + throw new Error('missing object property type'); + const [name, prop] = entry; + for (const line of docLines(prop.description, frame.indent + 1)) + parts.push('\n', line); + parts.push('\n', `${pad(frame.indent + 1)}${renderKey(name)}${required.has(name) ? '' : '?'}: `, child, ';'); + } + parts.push('\n', `${pad(frame.indent)}}`); + const declared = typeDocumentFrom(parts); + finish(frame.node.additionalProperties === false + ? declared + : typeDocument(declared, ' & Record')); + continue; + } + const node = frame.node; + if (node.oneOf !== undefined) { + frame.kind = 'oneOf'; + frame.children = Array.from(node.oneOf, child => ({ node: child, indent: frame.indent })); + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = 'children'; + continue; + } + if (node.type === undefined) { + finish(typeDocument('JsonValue')); + continue; + } + switch (node.type) { + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': + finish(typeDocument(renderConstrainedScalar(node, node.type))); + break; + case 'array': + if (node.items === undefined) { + finish(typeDocument('JsonValue[]')); + } + else { + frame.kind = 'array'; + frame.children = [{ node: node.items, indent: frame.indent }]; + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = 'children'; + } + break; + case 'object': { + const open = node.additionalProperties !== false; + const entries = Object.entries(node.properties ?? {}); + if (entries.length === 0) { + finish(typeDocument(open ? 'Record' : 'Record')); + } + else { + frame.kind = 'object'; + frame.entries = entries; + frame.children = entries.map(([, child]) => ({ node: child, indent: frame.indent + 1 })); + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = 'children'; + } + break; + } + /* v8 ignore next -- assertSupportedJsonSchema narrowed this closed type union. */ + default: + finish(typeDocument('unknown')); + } + } + /* v8 ignore next -- every root frame produces one document. */ + return rootDocument ?? typeDocument('unknown'); +} +/** + * Map one enforced JSON-Schema node to a TypeScript type literal. Supports + * every unified schema construct and returns `unknown` for malformed or + * unsupported inputs without throwing. + * @param schema - the JSON-Schema node (any shape; hostile inputs degrade). + * @param indent - the indentation level for nested object members. + * @returns the TS type text (multi-line for objects with properties). + */ +export function jsonSchemaToTs(schema, indent = 0) { + try { + assertSupportedJsonSchema(schema); + return flattenTypeDocument(renderSupportedSchema(schema, indent)); + } + catch { + return 'unknown'; + } +} +/** The fixed model-facing usage contract rendered above the declarations (see the Code Mode Agent Note's "What the model sees"). */ +const SDK_INSTRUCTIONS = `## Writing code for run_code + +\`run_code\` takes two required arguments: \`code\` — the body of an async TypeScript function (erasable syntax only — no \`enum\` or namespaces; type annotations are advisory, the code runs type-stripped) — and \`description\`, a short summary of what the program does. Inside the program: + +- Call tools as \`await tools.name(args)\` — quoted access for exotic names: \`tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose \`message\` is human-readable — \`try/catch\` it to handle and continue. +- Independent read-only calls MAY overlap under \`Promise.all\` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with \`await\`. +- Emit results with \`return\` and/or \`console.log(...)\`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. + +The available tools:`; +/** + * Render the full `tools:sdk` prompt section: the fixed usage instructions + * plus one `declare const tools` interface covering every given tool. + * Deterministic — tools are emitted in lexicographic name order, so an + * unchanged tool set produces byte-identical text across assemblies. The sort + * is not a total order on byte-equal names, so two schemas sharing a name + * would render in argument order; the caller's visible-capability map is keyed + * by name, so the input never carries a duplicate. + * @param schemas - the tool schemas to declare (the caller excludes + * `run_code` itself). + * @returns the complete section text. + */ +export function renderToolsSdk(schemas) { + const sorted = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0); + const argsMembers = []; + const outputMembers = []; + for (const schema of sorted) { + argsMembers.push(...docLines(schema.description, 1)); + argsMembers.push(`${pad(1)}${renderKey(schema.name)}: ${jsonSchemaToTs(schema.parameters, 1)};`); + outputMembers.push(`${pad(1)}${renderKey(schema.name)}: ${jsonSchemaToTs(schema.output, 1)};`); + } + const argsMap = `interface ToolArgsMap {${argsMembers.length > 0 ? `\n${argsMembers.join('\n')}\n` : ''}}`; + const outputMap = `interface ToolOutputMap {${outputMembers.length > 0 ? `\n${outputMembers.join('\n')}\n` : ''}}`; + const declaration = [ + argsMap, + outputMap, + 'type ToolName = keyof ToolOutputMap', + ['declare class ToolCallError extends Error {', ' readonly name: "ToolCallError";', ' readonly toolName: ToolName;', '}'].join('\n'), + ['declare const tools: {', ' [K in ToolName]: (args: ToolArgsMap[K]) => Promise;', '}'].join('\n'), + ].join('\n\n'); + const jsonValue = 'type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue }'; + return `${SDK_INSTRUCTIONS}\n\n\`\`\`ts\n${jsonValue}\n\n${declaration}\n\`\`\``; +} +//# sourceMappingURL=ts-types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/types.d.ts new file mode 100644 index 0000000..301bc9f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/types.d.ts @@ -0,0 +1,55 @@ +/** + * Durable Tool event vocabulary shared with type-only consumers. + * + * @module @deepseek-ai/dsh-tools/types + */ +import type { CallId } from '@deepseek-ai/dsh-llm/brand'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm/types'; +/** Payload recorded when one nested Code Mode Tool dispatch starts. */ +export interface CodeDispatchStartEventData { + rootCallId: CallId; + parentCallId: CallId; + subCallId: CallId; + name: string; + arguments: unknown; +} +/** Payload recorded when one nested Code Mode Tool dispatch settles. */ +export interface CodeDispatchEventData extends CodeDispatchStartEventData { + isError: boolean; + content: ContentBlock[]; +} +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * One sub-dispatch STARTING inside a `run_code` program: the parent + * `run_code` call id, the deterministic sub-call id (`:code:`, + * numbered in submission order), and the tool `name` with its + * JSON-normalized `arguments` — the exact value dispatched, normalized + * BEFORE dispatch, so this append can never fail on payload shape. + * Appended when the scheduler actually starts the call (not at + * submission), so a start means the tool body pipeline was entered; a + * call abandoned in the queue logs nothing. Log-only: `deriveMessages()` + * ignores it; UIs use it for live per-sub-call running state and pair it + * with `tool/code-dispatch` by `subCallId` (timing = the two events' + * `time` fields). + */ + 'tool/code-dispatch-start': CodeDispatchStartEventData; + /** + * One bridged sub-dispatch SETTLING: the pairing ids (matching the + * `tool/code-dispatch-start` with the same `subCallId`), the tool `name` + * with the same JSON-normalized `arguments`, and the sub-call's complete + * model-facing outcome in `tool/result`'s own vocabulary + * (`content` + `isError`), so UIs render a sub-call through the exact + * code path that renders a native call. Every started sub-call settles + * with exactly one of these (abort included: the aborted pipeline result + * is an `isError` outcome). + * Log-only: `deriveMessages()` ignores it, so sub-calls never re-enter + * model context; persistence and UIs get every call. Appended inside the + * parent `run_code`'s execution (the bridge drains in-flight dispatches + * before returning), so its execution-enclosure relation holds by + * construction. + */ + 'tool/code-dispatch': CodeDispatchEventData; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/types.js new file mode 100644 index 0000000..1cce147 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Durable Tool event vocabulary shared with type-only consumers. + * + * @module @deepseek-ai/dsh-tools/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/package.json new file mode 100644 index 0000000..40b1519 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-tools/package.json @@ -0,0 +1,68 @@ +{ + "name": "@deepseek-ai/dsh-tools", + "description": "Tool registry and execution pipeline for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/tools" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./presentation": { + "types": "./lib/types/presentation.d.ts", + "default": "./lib/types/presentation.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-user-approval b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-user-approval new file mode 120000 index 0000000..fd6eee4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/dsh-user-approval @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.6_f8724372086ccc1457fc84e7becee2e0/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-code-runtime b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-code-runtime new file mode 120000 index 0000000..d73549d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-code-runtime @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-system-prompt b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-system-prompt new file mode 120000 index 0000000..943dd86 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-system-prompt @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.i18n.yaml new file mode 100644 index 0000000..626269b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/core/tools/README.md +README.md: dd20b1b8fdc4ff57ff9850683d6070fdb219e25a +README.zh.md: 3c687ed0aa1347e3ce66da3b7fa2b48f69267b83 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.md new file mode 100644 index 0000000..dd20b1b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.md @@ -0,0 +1,198 @@ +# dsh-tools + +English | [中文](README.zh.md) + +Tool registry and execution pipeline. Tool plugins register their schemas and executors; the agent loop executes each call through `tools/pre-execute` (the extensible allow/deny gate) → monotonic registered guards → `tools/execute` (an around-dispatch wrapper for timeout/retry/metrics plugins) → `tools/post-execute` (inspect/replace the result, attach context) → the definition-owned `finalizeContent` boundary → the observe-only `tools/result` notification. The registry also owns HOW its tools are presented to the model — its `mode` config selects native function calling, [Code Mode](#code-mode), or both, and one agent shadows that default for itself with `presentAs`. + +## Service: `ToolRuntime` (ctx key: `tools`) + +### Config + +```yaml +tools: + mode: native # native (default) | code | both +``` + +`native` contributes visible tools as function definitions. `code` contributes the reserved `run_code` transport, the generated `tools:sdk` section, and the `tools:code-only` rule stating that only `run_code` may be called directly — which the executor then enforces, resolving a model-direct call naming any other tool to `UNKNOWN_TOOL` before policy runs; `both` contributes both forms and states no such rule, because its native calls do execute. This is the default for agents that declare none of their own — an agent preset selects its own with [`dsh-agent-tool-presentation`](../agent-tool-presentation/README.md). The reserved transport cannot be registered, shadowed, restricted, or removed, and its name is reserved whatever the configured mode, because any agent may select a code mode. Non-native modes require a `ctx.codeRuntime` whose `language` has a registered SDK renderer — TypeScript ships via [`dsh-code-runtime-worker-thread`](../../code-runtime/code-runtime-worker-thread/README.md); a Python renderer is built in and drives any runtime that reports `language: 'python'` (a first-party `dsh-code-runtime-python` backend is delivered separately). A runtime language with no renderer fails prompt assembly loudly, and a `systemPrompt.toolOrder` entry for a tool the mode does not contribute rejects prompt assembly. A `system-prompt/assemble` listener may replace the registry's contributions; its returned assembly is authoritative, so that listener owns preserving a usable Code Mode protocol. + +### Public API + +- `ctx.tools.register(definition: ToolDefinition): () => void` Register a trusted typed same-process definition with a mandatory canonical `output` declaration. The layer is the calling context's scope: a plain plugin context registers globally; an agent's `agent.ctx` registers for that agent alone, shadowing a same-named global tool there. Duplicate names within one layer throw; non-native modes also reject the reserved `run_code` transport name. Missing or unsupported output declarations and a non-positive or non-finite `timeoutMs` fail at registration. The optional synchronous `finalizeContent` callback is snapshotted when a call starts and may replace only final model-facing content after every pipeline outcome is normalized, including an error discovered while materializing another result field. Disposed with the calling fiber. +- `ctx.tools.presentAs(mode: ToolPresentationMode): () => void` selects this agent's model-facing presentation, shadowing the `mode` config for that agent alone; it throws from a plain context (a process-wide presentation is the config field) and from a second declaration in the same scope. A code mode also registers that agent's own `tools:sdk` section. The catalog is unchanged — `schemas(agent)` still reports the agent's capabilities; only the assembly's tools collapse. Disposed with the calling fiber. +- `ctx.tools.restrict(filter)` applies an agent-scoped allow/deny mask to global tools and throws from a plain context. The filter is snapshotted at registration; multiple masks intersect and scope-local tools merge afterwards. Deny masks admit later unnamed globals, while allow masks exclude later names. Unknown, local, or reserved names and empty filters reject. This is live visibility composition, not an authority boundary; see the [scope security non-goal](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals). +- `ctx.tools.get(name: string, scope?: ScopeKey): ToolDefinition | undefined` Resolution as one scope sees it (shadowing applied; a restricted-away global reads as absent) — presenters pass the calling agent so the card matches what executed. +- `ctx.tools.schemas(scope?: ScopeKey): ToolSchema[]` Schemas of everything the scope can see (without the `execute` functions). The shipped tools' schemas are catalogued in [docs/tool-catalog.md](../../../docs/tool-catalog.md), generated by booting each tool plugin and harvesting this method (see [the tool-schema-catalog Agent Note](../../../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md)). +- `ctx.tools.guard(guard: ToolGuard): () => void` Register a monotonic synchronous execution guard after `tools/pre-execute`: returning a reason denies the call, while `undefined` leaves it unchanged. A plain-context guard applies globally; an `agent.ctx` guard applies only to that agent. Later waterfall listeners cannot turn a guard denial back into permission. Disposed with the calling fiber. +- `ctx.tools.execute(exec)` losslessly snapshots and freezes arguments, assigns an opaque token, runs the complete policy/dispatch/result pipeline, then independently snapshots the authoritative outcome before final observation. Invalid arguments use the same result path without reaching policy or the body. Around wrappers may replace only `signal`; the registry re-fuses the original caller signal immediately before the body. +- `ctx.tools.executionMode(exec)` returns `parallel` only when the visible definition's `isConcurrencySafe(exec.arguments)` classifier returns exactly `true`; unknown, hidden, undeclared, invalid, or throwing classifications are exclusive. + +### Injected services + +`SystemPrompt` — the registry automatically feeds its tool schemas into the system-prompt assembly via `ctx.systemPrompt.tools()`. The approval seam is consumed opportunistically instead (`ctx.get('approval')`, no static inject): a deployment without it keeps the ask→deny degrade, and the registry stays active either way. + +### Cancellation + +Cancellation is cooperative and quiescent. Every typed invocation supplies a caller-owned `AbortSignal`; tool bodies receive it as required readonly `exec.signal`, while only `tools/execute` wrappers may temporarily replace the required signal. The registry preserves caller cancellation through replacement and never races away from a started same-process promise. Cancellation before body invocation is `ABORTED_BEFORE_DISPATCH`; cancellation after invocation can replace only a successful outcome with `ABORTED`. A denial, wrapper failure, tool failure, post-policy failure, or timeout-owned `TOOL_TIMEOUT` remains more specific. A pre-aborted entry materializes and freezes arguments, then skips every policy and dispatch phase and publishes one result. Every async tool must observe or forward the signal and settle only after owned work stops. The [tool-cancellation Agent Note](../../../.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md) owns the full contract and hard-termination limit. + +### Live events + +The live registry pipeline has three transformable waterfalls, then the definition-owned content finalizer, then the observe-only `tools/result` event; registry changes are deliberately unfiltered shared-state notifications. Exact signatures, dispatch modes, scope filtering, and failure containment contracts live in the generated region of [tools.md](../../../docs/subsystems/tools.md#cordis-surface), while the complete ordering is visualized in the generated [tool execution pipeline](../../../docs/tool-execution-pipeline.md). `tools/result` is live; the similarly named `tool/result` is the durable session event the agent loop appends afterwards. + +### Key types + +- `ToolDefinition` — `ToolSchema` + mandatory `output { schema, render, presentationMeta? }` + `execute(args, exec)`, optional final-content and presentation callbacks, cooperative `timeoutMs`, and optional per-call `isConcurrencySafe(args)` classification. A body returns only the canonical JSON value declared by the output schema and cooperatively stops through `exec.signal`. `finalizeContent(exec, result)` runs exactly once for every normalized result, including failures that bypass post-policy, and can replace only `content`; it must be synchronous and total. +- `ToolExecutionInput` — the caller-supplied call description: `{ callId, name, arguments, signal, agent?, parent? }`; `signal` is required and readonly, callers may pass an enclosing execution's opaque token as `parent`, and callers never choose the new execution's own token. +- `ToolExecutionToken` — a fresh branded `Symbol` assigned by the registry. It supports equality correlation only and never crosses a model, log, or worker boundary. +- `ToolExecution` — the readonly pipeline view: immutable `{ token, callId, name, arguments, signal, agent?, parent? }`; the registry separately retains and re-fuses the original caller signal. `ToolDispatchExecution` is the `tools/execute`-only view whose required signal is mutable, so a wrapper may replace and restore it but cannot delete it. A nested call's `parent` is a `ToolExecutionToken`, not an execution object. +- `ToolRunContext` — the execution passed to a tool body, extending `ToolExecution` with `deferContext(context)`. It defers one context until the tool's final result reaches the loop — typically a nested-dispatch context ferried by a composite tool, or a fresh plugin-sourced instruction minted by a leaf tool (`tool-goal`'s wrap-up) — even when the tool later throws or cancellation wins; it never injects immediately. +- `ToolExecutionResult` — discriminated execution-local outcome. Success is `{ isError:false, value:JsonValue, content, meta?, additionalContexts? }`; failure is `{ isError:true, error:{ message, info? }, content, meta?, additionalContexts? }` and has no value. Call identity stays on the immutable `ToolExecution`. The registry snapshots, validates, and freezes the canonical value before rendering, then materializes the durable presentation fields before final observation. `ToolFailure.info` carries an internal `{ name, code }` for a `HarnessError`; `additionalContexts` preserves every deferred or post-execute identified `UserMessage` for the loop's post-result FIFO. +- `PreToolDecision` — `{kind:'allow'}` | `{kind:'deny', reason}` | `{kind:'ask', reason?}`. Input rewrite is deliberately not offered; `ask` is serviced by [`ctx.approval`](../../interaction/user-approval/README.md) when mounted and otherwise degrades to deny. +- `PostToolDecision` — accept may replace `content` or `value`, never both, and may attach `additionalContexts`; block turns feedback into a valueless failure. Content replacement preserves the canonical value and metadata. Value replacement is revalidated and rerenders content/metadata. Accept preserves tool-deferred contexts before decision contexts; block discards tool-deferred contexts and exposes only contexts explicitly supplied by the blocking decision. +- `ToolGuard` — `(execution) => string | undefined`; the returned string is a final monotonic denial reason evaluated after the reorderable pre-execute waterfall and before dispatch. +- `ToolCallView` / `ToolResultView` — provider-neutral `card`-tagged render intents a tool returns from `presentCall` / `presentResult` to own how a UI renders ITS calls (see "Tool-owned UI presentation"). + +### Extension points + +- Tool plugins call `ctx.tools.register()` — schemas flow into the assembly automatically. +- `tools/pre-execute` is the reorderable allow/deny/ask gate; `ctx.tools.guard()` adds monotonic owner policy after it. +- `tools/execute` wraps normalized canonical dispatch for timeout, retry, or metrics. Wrappers may replace only the operational signal; a wrapper-authored success is normalized through the resolved tool's output declaration. Each canonical result belongs to one immutable dispatch token, so a cached result from another call or tool is revalidated under the active declaration. +- `tools/post-execute` may replace presentation content, replace the canonical value, block with feedback, or attach ordered contexts. A definition's optional `finalizeContent` then owns its last content-only invariant across normal results and outer pipeline failures; `tools/result` observes the immutable final outcome. Content replacement is not a confidentiality boundary: block or replace the value when programmatic consumers must not receive it. +- Exact signatures and ordering live in the generated region of [tools.md](../../../docs/subsystems/tools.md#cordis-surface) and [pipeline](../../../docs/tool-execution-pipeline.md). +- MCP servers: one plugin per server, discover tools, call `ctx.tools.register()` with the server's schemas. + +### Typed tool parameter schemas + +First-party plugin authors can use the `defineTool()` helper (exported from this package) for typed tool parameter schemas: + +```ts +import { readFile } from 'node:fs/promises' +import type { Context } from '@deepseek-ai/cordis' +import { defineTool } from '@deepseek-ai/dsh-tools' + +declare const ctx: Context + +ctx.tools.register(defineTool({ + name: 'read_file', + description: 'Read a file from disk.', + parameters: { + path: { type: 'string', required: true, description: 'Absolute file path' }, + offset: { type: 'number' }, + limit: { type: 'number' }, + }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, + async execute(args, exec) { + // args is typed: { path: string; offset?: number; limit?: number } + return readFile(args.path, { encoding: 'utf8', signal: exec.signal }) + }, +})) +``` + +The unified schema DSL uses `ParameterSchemaSpec` for the implicit open parameter object and `ValueSchemaSpec` for any JSON-value root. It supports `string`, `number`, `integer`, `boolean`, `null`, `array`, `object`, author-only `json`, and exact-one `oneOf`; scalar `enum`/`const` values are type-correct. Every explicit DSL object declares `additionalProperties: true | false`, while the implicit parameter root and raw JSON Schema keep the standard open default. Schema records accept only own enumerable string keys, and schema arrays must be dense ordinary arrays. Compilation, validation, registry detachment, and schema-to-TypeScript rendering use explicit work stacks, so runtime processing of valid deep schemas is memory-bounded rather than call-stack-bounded; `InferValue` preserves exact types through 16 container levels and then falls back to `JsonValue` so TypeScript itself remains stack-safe. + +A `defineTool` definition validates model arguments before execution and turns missing required values, wrong primitives, invalid enum members, and nested violations into `ToolArgsError` (`INVALID_ARGS`) for the normal error-result path. It also infers the body return and pure output projectors from `output.schema`; the registry snapshots and validates the returned lossless JSON before presentation. The implicit parameter root is open; an explicit object accepts extra keys only with `additionalProperties: true`, and a closed object with no declared properties accepts only `{}`. Raw JSON Schema objects remain open unless they explicitly set `additionalProperties: false`. Defaults are not applied; open objects without `properties` and arrays without `items` receive only a container type check. Raw-registered tools own input validation but still declare and receive registry-enforced output. + +See `defineTool`, `validateArgs`, `ToolArgsError`, `ValueSchemaSpec`, `ParameterSchemaSpec`, `InferValue`, `InferArgs`, `valueSchemaSpecToJsonSchema`, and `parameterSchemaSpecToJsonSchema` in the public API for details. + +Optional `timeoutMs` must be positive and finite; it is policy metadata, not model-visible schema. + +Optional `isConcurrencySafe(args)` receives typed, softly validated arguments. Exact `true` permits concurrent dispatch/body execution; invalid input and all other outcomes remain exclusive. Opted-in bodies do not mutate parent-owned state, and shared-state races must commute or fail closed. The [parallel tool-call Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) owns the full safety contract. + +### Enforced raw JSON Schema subset + +`JsonSchemaNode` is the raw counterpart shared by tool outputs, Code Mode generation, subagents, and workflows. It permits any JSON root, an annotation-only unconstrained JSON node, and exact-one `oneOf`; annotations must remain lossless JSON. `assertSupportedJsonSchema()` rejects unsupported constructs, while `validateJsonSchemaValue()` returns path-qualified violations. Subagents and workflows retain their caller-defined object-root requirement through `assertObjectJsonSchema()` and `ObjectJsonSchema`, not through a limitation in the shared vocabulary. + +### Tool-owned UI presentation + +Tools optionally own pure `presentCall()` and `presentResult()` render intents, so UIs do not special-case tool names: + +- Call views are `{ card: 'generic', title, kind?, rawInput?, content?, locations? }`, `{ card: 'terminal', title, description?, cwd? }`, or `{ card: 'diff', title, diffs, locations? }`. +- Result views are `{ card: 'generic', title?, content? }`, `{ card: 'terminal', title?, output?, exitCode?, signal? }`, `{ card: 'diff', title?, diffs }`, `{ card: 'search', shape, title?, truncated, total, … }` (a completed discovery search — grouped-by-file matches for `shape: 'matches'` (grep) or a flat path list for `shape: 'paths'` (glob), with `truncated`/`total` so a UI never presents a capped result as complete; the view carries no result text and a search has no `card: 'search'` call-time analogue), `{ card: 'read', title?, path, offset, lines, totalLines, lang?, content? }` (a completed file read → a line-numbered, optionally syntax-highlighted code view; `offset` is the 1-based first line the window requested, kept even when `lines` is empty; `lines` is `{ number, text }[]` keeping each file line number, and `content` is the envelope-stripped text a UI without read support falls back to), or `{ card: 'web', kind: 'search' | 'fetch', title?, … }` (a completed web retrieval; the `kind` arms carry the structured search sources or the fetch summary, and a UI without the `web` capability falls back to the raw result content). + +Returning `undefined` selects generic fallback. Presenters depend only on their arguments and the durable result because UIs call them during live streaming and log replay. `output.presentationMeta(args, value)` derives JSON metadata for direct top-level calls; that metadata persists with `tool/result` and returns to `presentResult`, while the canonical value itself remains execution-local and is never replayed. Nested Code dispatches do not compute metadata. `defineTool` soft-validates older logged arguments and falls back instead of crashing replay. `dsh-tool-bash` and `dsh-tool-fs` are the reference implementations; the [canonical-output Agent Note](../../../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md) owns the value/presentation split and the [render-intent Agent Note](../../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md) owns card vocabulary. + +### Code Mode + +Under `code` or `both`, the registry exposes the reserved `run_code` transport and a deterministic SDK for the current scope, generated in the loaded runtime's language — the registry selects the renderer by `ctx.codeRuntime.language` (`typescript` → the TypeScript SDK below, `python` → the Python SDK). The SDK declares exact per-tool argument and canonical-output types for every visible tool (`ToolArgsMap`/`ToolOutputMap` in TypeScript, named `TypedDict`s in Python), and each binding resolves to the tool's canonical JSON value. Each lossless-JSON binding call re-enters the complete tool pipeline under the native scheduling contract (concurrency-safe calls may overlap up to `maxParallelSubCalls`; exclusive calls run alone as ordering barriers) with logged correlation to the outer call. Denials and other failed results reject with the real program-visible `ToolCallError` carrying only `toolName` and `message`; Native content and internal error codes stay outside the Code contract. The program's outer logs and return value re-enter model context; when a successfully settled sub-call's final Native content contains an image, the bridge also defers that complete ordered content through the parent result so the image is not lost behind the JSON-only binding. Final post-execute blocking or content replacement is authoritative. Ordinary side effects are not rolled back, and sub-call `additionalContexts` are deferred through the parent result to preserve call/result adjacency. Run settlement aborts and drains outstanding bindings; runtime failures surface as `CodeRunFailedError`. + +Under `code` — not `both` — the transport is also the only entry the model may use: a model-direct call naming any other visible tool resolves to `UNKNOWN_TOOL` at execution creation, before `tools/pre-execute`, approval `ask`, and guards, so nothing observes or approves a call that can only fail. The denial names the route back (`only \`run_code\` is callable directly — call \`\` from inside a \`run_code\` program instead`), because the same prompt declares that tool and a bare `unknown tool` reads as a broken deployment. SDK sub-dispatches carry the outer execution's `parent` token and are exempt, so programs keep every binding the SDK declared. See the [executor-collapse note](../../../.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md), the [Code Mode foundation](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md), [typed-return contract](../../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md), and [code-runtime seam](../../code-runtime/README.md). Try `pnpm run demo:code-mode`. + +- **The SDK section** (`tools:sdk`, order 150): a lazy prompt section regenerating the language-appropriate SDK text at each assembly. In the TypeScript flavor it emits `JsonValue`, exact `ToolArgsMap` / `ToolOutputMap`, `ToolName`, the `ToolCallError` declaration, and a mapped `tools` namespace for the calling scope's visible end capabilities (exotic names via quoted keys), plus fixed usage instructions; the Python flavor (`ctx.codeRuntime.language === 'python'`) emits the equivalent named `TypedDict`s and a `tools` object with matching usage instructions. Deterministic — lexicographic tool order, byte-identical text for an unchanged tool set (prefix-cache-friendly). Both codegens are exported and never throw during prompt assembly: `jsonSchemaToTs` handles every unified schema construct and degrades unsupported raw constructs to `unknown`; `jsonSchemaToPy` does the same, degrading to `Any` (and a whole object to `dict[str, Any]` when a field name is not a legal `TypedDict` attribute, or whenever it is called outside the SDK render, which supplies the naming context a `TypedDict` declaration needs). +- **The dispatch bridge** (`run_code`'s execute): every binding call is snapshotted as lossless JSON before dispatch (`undefined`, `BigInt`, cycles, sparse arrays, `-0`, and exotic objects reject that one call), scheduled through a per-run pool that reuses the native concurrency contract — calls start strictly in submission order, consecutive `isConcurrencySafe` calls overlap up to the validated `maxParallelSubCalls` config (default 10; `1` restores serial dispatch), and an exclusive-classified call drains the pool, runs alone, and bars later calls — given the outer execution's opaque token as `parent`, and run through the complete pre-execute → guards → execute → post-execute → result pipeline. A success returns the final canonical value after policy; a failure reaches the worker as one message and becomes `ToolCallError(toolName, message)`. Each started sub-call logs a `tool/code-dispatch-start` event (deterministic id `:code:`, numbered by submission) at pipeline entry and settles with one `tool/code-dispatch` event carrying the complete model-facing `content`/`isError` outcome (the `tool/result` vocabulary, so UIs render sub-calls through the native path — the pair's `time` fields carry per-sub-call timing); a queued call abandoned by run settlement logs neither. `deriveMessages()` surfaces neither event nor persists the canonical value. Token correlation lets commit-style observers defer an inner success until the final `run_code` result without exposing the live outer execution; ordinary tool side effects are not rolled back. Every sub-call `additionalContexts` entry and every successful final content sequence containing an image is deferred through the outer `ToolRunContext` in dispatch order; the loop appends those contexts only after the parent `run_code` result, preserving adjacency and source attribution even when the program later fails. +- **Settlement discipline**: the bridge owns a run-scoped abort that follows the outer signal in and fires when the run settles for any reason, so a budget expiry aborts an in-flight sub-tool instead of orphaning it; the bridge then drains its queue BEFORE returning, so every `tool/code-dispatch` lands inside the open turn. A failed run throws `CodeRunFailedError` (`code: 'CODE_RUN_FAILED'`, message = the failure kind + captured logs), which the pipeline converts to a structured `isError` the model self-corrects from. +- **Result size**: intermediate binding values cross the worker process whole and have no per-binding byte cap. `run_code` returns canonical `{ logs: string[], result?: JsonValue }`; strings render raw, every other present JSON root renders through a stack-safe pretty JSON traversal whose total indentation is capped at ten characters (deeper subtrees stay compact), `null` remains explicit, and absent `result` means the program returned `undefined`. The worker's configurable `maxOutputBytes` (default 64 MiB) applies only to the combined serialized outer log-array, completion-value, or failure-message payloads; fixed result-envelope syntax and presentation whitespace are outside that limit. Invalid and over-limit completions fail explicitly, and only this outer result is eligible for ordinary spill. + +### Parallel execution + +The agent loop groups consecutive `parallel` calls into a bounded rolling pool and treats each `exclusive` call as an ordering barrier. Only dispatch/body overlaps; policy, durable results, and context retain model order. Code Mode bindings reuse the same classification through the bridge's own pool. The [parallel tool-call Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) owns the shipped declarations and rationale. + +## Model Experience + +### Normal tool schemas + +#### What the model sees + +In normal mode the model sees each visible definition's exact name, description, and JSON schema; the shipped definitions are recorded in the generated [tool package map and schema sections](../../../docs/tool-catalog.md#tool-package-map). Agent-scoped restrictions, shadows, and extension registrations change that agent's end-tool set. + +#### Token effect + +Fixed per-request cost proportional to the visible definitions. Restrictions that hide tools remove their entire schema cost for that agent. + +#### KV Cache effect + +Prefix-stable while visible definitions and their order are unchanged. Registration, disposal, or scoped restriction may invalidate reuse from the first changed schema token. + +### Code Mode schema and system prompt + +#### What the model sees + +Code Mode exposes the generated [`run_code` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tools), the SDK instructions below, and the generated exact SDK block for the loaded runtime's language (the TypeScript `declare const tools` block, or the Python `tools` declaration). `both` exposes normal schemas and this Code Mode API. Under `code` the prompt also carries the `tools:code-only` rule, ordered ahead of the per-tool guidance band so the model reads which tools it may call before it reads what each one is for; `both` renders it empty. The instructions and SDK block match the loaded runtime's language; the TypeScript version (via [`dsh-code-runtime-worker-thread`](../../code-runtime/code-runtime-worker-thread/README.md)) is shown below, and the Python version (for any runtime reporting `language: 'python'`) has the same operations and types in Python syntax (`await tools.name(args)`, subscript access for exotic names, `print(...)` and top-level `return`). + +##### Code Mode SDK instructions + +```markdown +## Writing code for run_code + +`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program: + +- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue. +- Independent read-only calls MAY overlap under `Promise.all` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with `await`. +- Emit results with `return` and/or `console.log(...)`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. + +The available tools: +``` + +#### Token effect + +Fixed per-request cost proportional to the visible definitions. Code Mode trades end-tool schemas for generated SDK text plus one transport schema rather than promising a universal reduction. + +#### KV Cache effect + +Prefix-stable while the Code Mode selection, generated SDK, transport schema, and visible tool set are unchanged. Mode or filter changes may invalidate reuse from the first changed prompt or schema token. + +### Tool-call history and results + +#### What the model sees + +The loop retains model-emitted arguments and the registry's final content. Any thrown or denied call becomes exactly `Error: `. Code Mode renders the outer program's printed lines and return value, `(run_code completed with no output)` when both are empty, or `Error: code run failed (): ` followed conditionally by `Captured output:` and the captured lines. Inner dispatch events stay log-only, while a successful image-bearing sub-result is appended after the outer result as source-attributed context; post-execute listeners may append other source-attributed context at the same boundary. + +#### Token effect + +Arguments, results, and additional context are data-dependent and resent until compaction. Restrictions that hide tools also remove their schemas before the model can call them. + +#### KV Cache effect + +Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries. + +## Known Limitations and Deferred Work + +- **Concurrency policy is not an event gate** — `executionMode()` reads the resolved tool definition directly; plugins can only declare a classifier on definitions they own. +- **`tools/pre-execute` deliberately cannot rewrite `exec.arguments`** — logged and rendered args would desync from what ran; the rewrite design is [a proposed Agent Note](../../../.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.md). +- **Caller-defined subagent and workflow structured outputs remain object-rooted** — this is a consumer-level guard; the shared schema vocabulary and tool outputs support every JSON root. +- **`timeoutMs` on a definition is declarative only** — the registry never enforces deadlines; enforcement requires the `@deepseek-ai/dsh-tool-call-timeout-policy` wrapper. +- **Code Mode's SDK language follows the one loaded runtime, and a presentation is per agent rather than per tool** — `mode: code`/`both` rejects prompt assembly unless `ctx.codeRuntime.language` has a registered SDK renderer (TypeScript or Python); scoped restrictions/shadows and `presentAs` choose each agent's visible bindings and their form, but within one agent no tool can be native-only while another is code-only. +- **Code Mode intermediate values are execution-local and unbounded by bytes** — the canonical typed values cannot be reconstructed from session replay and may exhaust process or worker memory; only the outer `run_code` output has the worker's configurable hard cap. The durable log copy of each sub-call IS bounded: the `tools/code-dispatch-log` waterfall lets the spill policy replace an oversized `tool/code-dispatch` content with a preview + locator ([rationale](../../../.agents/notes/implemented/feature/2026-07-26-code-dispatch-log-spill.md)). +- **`run_code` state is fresh per run** — a persistent REPL-style kernel is rejected for the MVP (cross-call state would be invisible to the log); see [the Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md). diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.zh.md new file mode 100644 index 0000000..3c687ed --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/README.zh.md @@ -0,0 +1,198 @@ +# dsh-tools + +[English](README.md) | 中文 + +工具注册表与执行流水线。工具插件注册各自的 schema 和执行器;agent loop(智能体循环)依次让每次调用经过 `tools/pre-execute`(可扩展的允许/拒绝门禁)→ 已注册的单调守卫 → `tools/execute`(供超时/重试/指标插件使用的环绕分发包装层)→ `tools/post-execute`(检查/替换结果、附加上下文)→ 由工具定义持有的 `finalizeContent` 边界 → 仅观测的 `tools/result` 通知。注册表还决定以何种方式向模型呈现工具:`mode` 配置可以选择原生 Function Calling(函数调用)、[Code Mode](#code-mode),或同时选择两者;单个 agent 可用 `presentAs` 为自己遮蔽该默认值。 + +## 服务:`ToolRuntime`(ctx 键:`tools`) + +### 配置 + +```yaml +tools: + mode: native # native (default) | code | both +``` + +`native` 以函数定义的形式贡献可见工具。`code` 会提供保留的 `run_code` 传输、生成的 `tools:sdk` 段,以及声明「只有 `run_code` 可被直接调用」的 `tools:code-only` 规则。执行器随后强制执行该规则:模型直接调用其他任何工具时,会在策略运行前将该调用解析为 `UNKNOWN_TOOL`;`both` 同时提供两种形式,且不声明该规则,因为其中的原生调用确实可以执行。没有单独声明呈现模式的 agent 默认采用此配置;agent preset 可通过 [`dsh-agent-tool-presentation`](../agent-tool-presentation/README.md) 自行选择呈现模式。不能注册、遮蔽、限制或移除该保留传输,且无论配置何种模式,该名称都是保留的,因为任何 agent 都可能选择 code 模式。非原生模式要求所加载 `ctx.codeRuntime` 的 `language` 有已注册的 SDK 渲染器——TypeScript 经 [`dsh-code-runtime-worker-thread`](../../code-runtime/code-runtime-worker-thread/README.md) 交付;Python 渲染器内置,驱动任何报告 `language: 'python'` 的运行时(第一方 `dsh-code-runtime-python` 后端另行交付)。没有渲染器的运行时语言会导致提示词组装明确失败;如果 `systemPrompt.toolOrder` 条目指向当前模式未贡献的工具,系统会拒绝组装提示词。`system-prompt/assemble` 监听器可以替换注册表贡献;它返回的组装结果具有权威性,因此该监听器负责保留可用的 Code Mode 协议。 + +### 公开 API + +- `ctx.tools.register(definition: ToolDefinition): () => void`:注册一个受信任、带类型的同进程定义,其中必须包含规范的 `output` 声明。所在层由调用上下文的作用域决定:普通插件上下文会全局注册;agent 的 `agent.ctx` 只为该 agent 注册,并在此处遮蔽同名全局工具。同一层内名称重复会抛出;非原生模式还会拒绝保留的 `run_code` 传输名称。缺失或不受支持的输出声明,以及非正数或非有限的 `timeoutMs`,都会使注册失败。可选的同步 `finalizeContent` 回调会在调用开始时纳入快照;在所有流水线结果(包括实体化其他结果字段时发现的错误)规范化之后,它只能替换最终面向模型的内容。该注册会随调用方 fiber 一同 dispose(资源释放)。 +- `ctx.tools.presentAs(mode: ToolPresentationMode): () => void`:为本 agent 选择面向模型的呈现方式,仅对该 agent 遮蔽 `mode` 配置;从普通上下文调用会抛出(进程级呈现方式是那个配置字段),同一 scope 内第二次声明也会抛出。code 类模式还会为该 agent 注册它自己的 `tools:sdk` 段。工具目录保持不变:`schemas(agent)` 仍会报告该 agent 的能力;只有组装结果中的工具列表会按所选呈现方式收束。随调用方 fiber dispose。 +- `ctx.tools.restrict(filter)`:对全局工具应用 agent 作用域的允许/拒绝掩码;从普通上下文调用会抛出。筛选器在注册时创建快照;多个掩码取交集,随后再合并作用域本地工具。拒绝掩码会接纳后来出现且未点名的全局工具,而允许掩码会排除后来出现的名称。未知、本地或保留名称以及空筛选器都会被拒绝。这是实时可见性组合,不是权限边界;参见[作用域安全非目标](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals)。 +- `ctx.tools.get(name: string, scope?: ScopeKey): ToolDefinition | undefined`:返回指定作用域可见的解析结果,其中已应用名称遮蔽;被作用域限制排除的全局工具会被视为不存在。呈现器会传入发起调用的 agent,使卡片与实际执行内容一致。 +- `ctx.tools.schemas(scope?: ScopeKey): ToolSchema[]`:返回该作用域可见的所有 schema(不含 `execute` 函数)。已交付工具的 schema 收录在 [docs/tool-catalog.md](../../../docs/tool-catalog.md) 中;该目录通过启动每个工具插件并采集此方法的结果生成(参见[工具 schema 目录 Agent Note](../../../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md))。 +- `ctx.tools.guard(guard: ToolGuard): () => void`:在 `tools/pre-execute` 之后注册单调同步执行守卫:返回理由会拒绝调用,返回 `undefined` 则保持原决定。普通上下文守卫全局生效;`agent.ctx` 守卫只对该 agent 生效。后续 waterfall(瀑布式事件)监听器无法将守卫的拒绝重新变为允许。随调用 fiber dispose。 +- `ctx.tools.execute(exec)`:以无损方式快照并冻结参数,分配不透明 token,运行完整的策略/分发/结果流水线,然后在最终观测前独立快照权威结果。无效参数会进入同一结果路径,但不会到达策略或工具主体。环绕包装层只能替换 `signal`;注册表会在进入工具主体之前,立即将调用方的原始信号重新合并到当前信号中。 +- `ctx.tools.executionMode(exec)`:返回 `parallel` 的唯一条件是可见定义的 `isConcurrencySafe(exec.arguments)` 分类器恰好返回 `true`;未知、隐藏、未声明、无效或抛出异常的分类结果均为独占。 + +### 注入的服务 + +`SystemPrompt`:注册表通过 `ctx.systemPrompt.tools()` 自动将工具 schema 送入系统提示词组装。审批 seam 则在可用时使用(`ctx.get('approval')`,无静态注入):未部署该 seam 时仍会将询问退化为拒绝,而无论是否存在该 seam,注册表都会保持活动。 + +### 取消 + +取消采用协作方式,并等待完全停稳。每次类型化调用都提供由调用方拥有的 `AbortSignal`;工具主体通过必填的只读 `exec.signal` 接收它,只有 `tools/execute` 包装层可以临时替换这个必填信号。注册表会在替换期间保留调用方取消,并且绝不会在已启动的同进程 Promise 尚未结算时提前返回。工具主体调用前发生的取消为 `ABORTED_BEFORE_DISPATCH`;工具主体被调用后发生的取消,只能将成功结果替换为 `ABORTED`。拒绝、包装层失败、工具失败、后置策略失败或由超时机制产生的 `TOOL_TIMEOUT` 仍保留更具体的结果。入口处已中止的调用会实体化并冻结参数,随后跳过所有策略和分发阶段,只发布一个结果。每个异步工具都必须观测或转发该信号,并且只能在其负责的工作停止后结算。[工具取消 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md) 规定完整约定和强制终止边界。 + +### 实时事件 + +实时注册表流水线先经过 3 道可转换的 waterfall,再经过由工具定义持有的内容终结器,最后发布仅供观测的 `tools/result` 事件;注册表变更通知有意不作过滤,并作为共享状态通知发布。确切签名、分发 mode、作用域筛选和失败隔离约定位于 [tools.md](../../../docs/subsystems/tools.md#cordis-surface) 的生成区块,完整顺序则在生成的[工具执行流水线](../../../docs/tool-execution-pipeline.md)中可视化。`tools/result` 是实时事件;名称相近的 `tool/result` 是 agent loop 随后追加的持久会话事件。 + +### 关键类型 + +- `ToolDefinition`:`ToolSchema` + 必填的 `output { schema, render, presentationMeta? }` + `execute(args, exec)`,以及可选的最终内容回调、呈现回调、协作式 `timeoutMs` 和逐调用的 `isConcurrencySafe(args)` 分类器。主体只能返回输出 schema 声明的规范 JSON 值,并通过 `exec.signal` 协作停止。`finalizeContent(exec, result)` 对每个规范化结果都恰好运行一次,包括绕过后置策略的失败,并且只能替换 `content`;它必须是同步且对所有输入都有定义的函数。 +- `ToolExecutionInput`:调用方提供的调用描述:`{ callId, name, arguments, signal, agent?, parent? }`;`signal` 必填且只读,调用方可以将外层执行的不透明 token 作为 `parent` 传入,但绝不能选择新执行自身的 token。 +- `ToolExecutionToken`:注册表分配的全新带品牌 `Symbol`。它只支持通过相等性进行关联,绝不会跨越模型、日志或 worker 边界。 +- `ToolExecution`:只读流水线视图:不可变的 `{ token, callId, name, arguments, signal, agent?, parent? }`;注册表会另行保留并重新融合调用方的原始信号。`ToolDispatchExecution` 是仅供 `tools/execute` 使用的视图,其必填信号可变,因此包装层可以替换并还原它,但不能删除它。嵌套调用的 `parent` 是 `ToolExecutionToken`,而不是执行对象。 +- `ToolRunContext`:传给工具主体的执行上下文,在 `ToolExecution` 基础上增加 `deferContext(context)`。它把一条上下文推迟到该工具的最终结果抵达循环时——通常是组合工具转运的嵌套分发上下文,也可以是叶子工具创建的全新插件来源指令(如 `tool-goal` 的收尾注入)——即使工具后来抛出或取消胜出也不例外;该方法绝不会立即注入上下文。 +- `ToolExecutionResult`:带判别标记的执行局部结果。成功形态为 `{ isError:false, value:JsonValue, content, meta?, additionalContexts? }`;失败形态为 `{ isError:true, error:{ message, info? }, content, meta?, additionalContexts? }`,且不含值。调用身份保留在不可变的 `ToolExecution` 上。注册表会在呈现前快照、验证并冻结规范值,随后在最终观测前实体化持久呈现字段。`ToolFailure.info` 携带内部的 `{ name, code }`,用于表示 `HarnessError`;`additionalContexts` 会保留每个通过延迟或 post-execute 加入且带标识的 `UserMessage`,供循环在结果后按 FIFO 顺序处理。 +- `PreToolDecision`:`{kind:'allow'}` | `{kind:'deny', reason}` | `{kind:'ask', reason?}`。该类型有意不提供输入改写;`ask` 在挂载 [`ctx.approval`](../../interaction/user-approval/README.md) 时由它处理,否则退化为拒绝。 +- `PostToolDecision`:接受决定可以替换 `content` 或 `value`(不能同时替换),并可附加 `additionalContexts`;阻止决定会把反馈变成无值失败。替换内容会保留规范值和元数据。替换值会重新验证,并重新呈现内容/元数据。接受决定会先保留工具延迟的上下文,再附加决定上下文;阻止决定会丢弃工具延迟的上下文,只公开阻止决定显式提供的上下文。 +- `ToolGuard`:`(execution) => string | undefined`;返回的字符串是最终单调拒绝理由,在可重排的前置执行 waterfall 之后、分发之前求值。 +- `ToolCallView` / `ToolResultView`:提供方无关、带 `card` 标签的呈现意图;工具通过 `presentCall` / `presentResult` 返回该意图,从而拥有 UI 呈现其自身调用的方式(参见「工具拥有的 UI 呈现」)。 + +### 扩展点 + +- 工具插件调用 `ctx.tools.register()`:schema 会自动流入组装结果。 +- `tools/pre-execute` 是可重排的允许/拒绝/询问门禁;`ctx.tools.guard()` 在其后添加单调的拥有方策略。 +- `tools/execute` 会环绕包装规范化后的规范分发,以支持超时、重试或指标采集。包装层只能替换操作信号;包装层生成的成功结果会根据已解析工具的输出声明进行规范化。每个规范结果属于一个不可变分发 token,因此来自其他调用或工具的缓存结果会根据当前声明重新验证。 +- `tools/post-execute` 可以替换呈现内容、替换规范值、通过反馈阻止,或附加有序上下文。随后,定义可选的 `finalizeContent` 会在普通结果和外层流水线失败中维护其最终、仅涉及内容的不变式;`tools/result` 观测不可变的最终结果。内容替换不是保密边界:当编程消费方不得接收某个值时,应阻止或替换该值。 +- 确切签名与顺序位于 [tools.md](../../../docs/subsystems/tools.md#cordis-surface) 的生成区块和[流水线](../../../docs/tool-execution-pipeline.md)中。 +- MCP 服务器:每个服务器使用一个插件;发现工具后,使用服务器的 schema 调用 `ctx.tools.register()`。 + +### 类型化工具参数 schema + +第一方插件作者可以使用本包导出的 `defineTool()` 辅助函数定义类型化工具参数 schema: + +```ts +import { readFile } from 'node:fs/promises' +import type { Context } from '@deepseek-ai/cordis' +import { defineTool } from '@deepseek-ai/dsh-tools' + +declare const ctx: Context + +ctx.tools.register(defineTool({ + name: 'read_file', + description: 'Read a file from disk.', + parameters: { + path: { type: 'string', required: true, description: 'Absolute file path' }, + offset: { type: 'number' }, + limit: { type: 'number' }, + }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, + async execute(args, exec) { + // args is typed: { path: string; offset?: number; limit?: number } + return readFile(args.path, { encoding: 'utf8', signal: exec.signal }) + }, +})) +``` + +统一 schema DSL 使用 `ParameterSchemaSpec` 表示隐式开放参数对象,使用 `ValueSchemaSpec` 表示任意 JSON 值根。它支持 `string`、`number`、`integer`、`boolean`、`null`、`array`、`object`、仅供作者使用的 `json`,以及恰好匹配一个分支的 `oneOf`;标量 `enum`/`const` 值必须符合其声明类型。每个显式 DSL 对象都声明 `additionalProperties: true | false`,而隐式参数根和原始 JSON Schema 保持标准的开放默认值。schema 记录只接受自身可枚举字符串键,schema 数组必须是稠密普通数组。编译、验证、从注册表分离以及 schema 到 TypeScript 的呈现均使用显式工作栈,因此,对有效深层 schema 的运行时处理受内存而非调用栈限制;`InferValue` 在 16 层容器内保留精确类型,之后回退到 `JsonValue`,使 TypeScript 自身也保持栈安全。 + +`defineTool` 定义会在执行前验证模型参数,并把缺失必填值、基本类型错误、无效枚举成员和嵌套违规转换为 `ToolArgsError`(`INVALID_ARGS`),进入普通错误结果路径。它还会根据 `output.schema` 推断主体返回类型和纯输出投影器;注册表在呈现前快照并验证返回的无损 JSON。隐式参数根是开放的;显式对象只有在设置 `additionalProperties: true` 时才接受额外键,而没有声明属性的封闭对象只接受 `{}`。原始 JSON Schema 对象保持开放,除非显式设置 `additionalProperties: false`。系统不会应用默认值;没有 `properties` 的开放对象和没有 `items` 的数组只接受容器类型检查。通过原始方式注册的工具负责输入验证,但仍需声明输出,并由注册表强制校验输出。 + +有关详细信息,请参阅公开 API 中的 `defineTool`、`validateArgs`、`ToolArgsError`、`ValueSchemaSpec`、`ParameterSchemaSpec`、`InferValue`、`InferArgs`、`valueSchemaSpecToJsonSchema` 和 `parameterSchemaSpecToJsonSchema`。 + +可选的 `timeoutMs` 必须为正数且为有限值;它是策略元数据,不是模型可见的 schema。 + +可选的 `isConcurrencySafe(args)` 接收经过软验证的类型化参数。只有确切的 `true` 才允许并发分发/主体执行;无效输入和所有其他结果仍为独占。选择并发的主体不得改变父级拥有的状态;共享状态竞态必须具有交换性,否则必须安全拒绝。[并行工具调用 Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) 规定完整安全约定。 + +### 强制执行的原始 JSON Schema 子集 + +`JsonSchemaNode` 是工具输出、Code Mode 生成、subagent 和工作流共享的原始 JSON Schema 对应类型。它允许任意 JSON 根、仅含注解且不施加约束的 JSON 节点,以及恰好匹配一个分支的 `oneOf`;注解必须保持为无损 JSON。`assertSupportedJsonSchema()` 拒绝不受支持的构造,而 `validateJsonSchemaValue()` 返回带路径的违规信息。subagent 和工作流通过 `assertObjectJsonSchema()` 与 `ObjectJsonSchema` 保留调用方定义的对象根要求,而不是依赖共享词汇的限制。 + +### 由工具定义的 UI 呈现 + +工具可以选择通过纯函数 `presentCall()` 和 `presentResult()` 定义呈现意图,使 UI 无需针对工具名称编写特殊逻辑: + +- 调用视图为 `{ card: 'generic', title, kind?, rawInput?, content?, locations? }`、`{ card: 'terminal', title, description?, cwd? }` 或 `{ card: 'diff', title, diffs, locations? }`。 +- 结果视图为 `{ card: 'generic', title?, content? }`、`{ card: 'terminal', title?, output?, exitCode?, signal? }`、`{ card: 'diff', title?, diffs }`、`{ card: 'search', shape, title?, truncated, total, … }`(已完成的发现型搜索——`shape: 'matches'`(grep)为按文件分组的匹配,`shape: 'paths'`(glob)为扁平路径列表,配 `truncated`/`total` 使 UI 永不把被截断的结果当作完整结果呈现;该视图不携带结果文本,且搜索没有 `card: 'search'` 的调用时对应视图)、`{ card: 'read', title?, path, offset, lines, totalLines, lang?, content? }`(已完成的文件读取→带行号、可选语法高亮的代码视图;`offset` 是窗口请求的 1-based 起始行,即使 `lines` 为空也保留;`lines` 是 `{ number, text }[]`,保留每一行的文件行号,`content` 是去除读取结果外层封装后的正文,供不支持读取视图的 UI 回退显示)或 `{ card: 'web', kind: 'search' | 'fetch', title?, … }`(已完成的 web 检索;`kind` 各分支携带结构化的搜索来源或抓取摘要,不具备 `web` 能力的 UI 回退到原始结果内容)。 + +返回 `undefined` 会选择通用回退。呈现器只依赖其参数和持久结果,因为 UI 会在实时流式输出和日志回放期间调用它们。`output.presentationMeta(args, value)` 为直接的顶层调用派生 JSON 元数据;该元数据随 `tool/result` 持久化并传回 `presentResult`,而规范值本身仍只存在于执行局部,绝不会回放。嵌套 Code 分发不会计算元数据。`defineTool` 会软验证较旧的日志参数并回退,而不会使回放崩溃。`dsh-tool-bash` 与 `dsh-tool-fs` 是参考实现;[规范输出 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md) 规定值/呈现拆分,[呈现意图 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md) 规定卡片词汇。 + +### Code Mode + +在 `code` 或 `both` 模式下,注册表为当前作用域公开保留的 `run_code` 传输和按所加载运行时语言生成的确定性 SDK——注册表按 `ctx.codeRuntime.language` 选择渲染器(`typescript` → 下方的 TypeScript SDK,`python` → Python SDK)。SDK 为每个可见工具声明精确的参数与规范输出类型(TypeScript 为 `ToolArgsMap`/`ToolOutputMap`,Python 为具名 `TypedDict`),每个绑定都会解析为该工具的规范 JSON 值。每个无损 JSON 绑定调用都会在原生调度约定下重新进入完整工具流水线(并发安全的调用最多可重叠 `maxParallelSubCalls` 个;独占调用单独运行并构成排序屏障),并在日志中与外层调用建立关联。拒绝及其他失败结果会以程序实际可见的 `ToolCallError` 形式拒绝,且只携带 `toolName` 和 `message`;Native 内容和内部错误码留在 Code 约定之外。程序的外层日志与返回值会重新进入模型上下文;当成功结算的子调用最终 Native 内容包含图片时,桥接层还会经父结果延后完整有序内容,避免图片被 JSON 专用绑定遮蔽。最终 post-execute 阻止或内容替换具有权威性。普通副作用不会回滚,子调用的 `additionalContexts` 会通过父结果延迟,以保持调用/结果相邻。运行结算会中止并排空尚未完成的绑定;运行时失败以 `CodeRunFailedError` 形式出现。 + +在 `code`(而非 `both`)下,该传输同时也是模型唯一可用的入口:模型直呼其他任何可见工具名,都会在创建执行时、早于 `tools/pre-execute`、审批 `ask` 和 guards 解析为 `UNKNOWN_TOOL`,因此没有任何一方会观察或批准一个注定失败的调用。拒绝信息会给出正确路径(`only \`run_code\` is callable directly — call \`\` from inside a \`run_code\` program instead`),因为同一份提示词刚刚声明过那个工具,只说 `unknown tool` 会被读成部署损坏。SDK 子分发携带外层执行的 `parent` token,不受此限制,因此程序保留 SDK 声明的全部绑定。参见[执行器塌缩 note](../../../.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md)、[Code Mode 基础](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)、[类型化返回约定](../../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md)和[代码运行时 seam](../../code-runtime/README.md)。可以运行 `pnpm run demo:code-mode` 试用。 + +- **SDK 段**(`tools:sdk`,顺序 150):一个在组装时求值的提示词段,每次组装都会重新生成与所加载运行时语言相符的 SDK 文本。TypeScript 形态会生成 `JsonValue`、精确的 `ToolArgsMap` / `ToolOutputMap`、`ToolName`、`ToolCallError` 声明,以及映射调用作用域最终可见工具的 `tools` 命名空间(特殊名称使用带引号的键),并附带固定的使用说明;Python 形态(`ctx.codeRuntime.language === 'python'`)发出等价的具名 `TypedDict` 与一个带相同用法说明的 `tools` 对象。其输出具有确定性:工具按字典序排列;工具集合不变时,文本逐字节相同(有利于前缀 cache)。两个代码生成器都已导出,且绝不会在提示词组装期间抛出:`jsonSchemaToTs` 处理统一 schema 的每种构造并将不受支持的原始构造降级为 `unknown`;`jsonSchemaToPy` 同理,降级为 `Any`(当某字段名不是合法的 `TypedDict` 属性时,或在 SDK 渲染之外被调用时——`TypedDict` 声明所需的命名上下文由该渲染提供——整个对象降级为 `dict[str, Any]`)。 +- **分发桥接层**(`run_code` 的 execute):每个绑定调用都会在分发前快照为无损 JSON(`undefined`、`BigInt`、循环、稀疏数组、`-0` 和特殊对象会使该次调用被拒绝),经由每次运行独有、复用原生并发约定的池调度——调用严格按提交顺序启动,连续的 `isConcurrencySafe` 调用最多可重叠经校验的 `maxParallelSubCalls` 配置个(默认 10;设为 `1` 即恢复串行分发),被分类为独占的调用先排空池、单独运行并阻挡其后的调用——以外层执行的不透明 token 作为 `parent`,并经过完整的 pre-execute → guards → execute → post-execute → result 流水线。成功会返回策略处理后的最终规范值;失败以一条消息到达 worker,并成为 `ToolCallError(toolName, message)`。每个已启动的子调用在进入流水线时记录一条 `tool/code-dispatch-start` 事件(确定性 id `:code:`,按提交顺序编号),并以一条携带完整模型可见 `content`/`isError` 结果的 `tool/code-dispatch` 事件完结(采用 `tool/result` 词汇,因此 UI 会沿原生路径呈现子调用——这对事件的 `time` 字段承载每个子调用的计时);因 run 结算而被放弃的排队调用两者都不记录。`deriveMessages()` 既不公开这两个事件,也不持久化规范值。token 关联使按提交语义工作的观察器可以延后提交内部调用的成功结果,直到最终 `run_code` 结果确定,而无需暴露进行中的外层执行;普通工具副作用不会回滚。每个子调用的 `additionalContexts` 条目以及每份成功且含图片的最终内容序列都会按分发顺序通过外层 `ToolRunContext` 延迟;循环只在父级 `run_code` 结果之后追加这些上下文,从而保持相邻关系和来源归属,即使程序后来失败也不例外。 +- **结算纪律**:桥接层拥有一个运行作用域的中止机制;该中止会跟随传入的外层信号,并在运行因任何原因结算时触发,因此预算耗尽会中止正在运行的子工具,而不会将其遗留。桥接层随后会在返回之前排空队列,使每个 `tool/code-dispatch` 都落在仍打开的轮次内。失败的运行会抛出 `CodeRunFailedError`(`code: 'CODE_RUN_FAILED'`,message = 失败类型 + 已捕获日志),流水线会将其转换为模型可据以自我修正的结构化 `isError`。 +- **结果大小**:中间绑定值会完整传入 worker 进程,且没有逐绑定字节上限。`run_code` 返回规范的 `{ logs: string[], result?: JsonValue }`;字符串原样呈现,其他所有存在的 JSON 根都通过栈安全的美化 JSON 遍历呈现,总缩进最多为 10 个字符(更深的子树保持紧凑),`null` 保持显式,而缺少 `result` 表示程序返回 `undefined`。worker 可配置的 `maxOutputBytes`(默认 64 MiB)只应用于组合序列化后的外层日志数组、完成值或失败消息载荷;固定的结果封装语法和呈现空白不计入该上限。无效和超限的完成会明确失败,只有这个外层结果可以按常规 spill 机制处理。 + +### 并行执行 + +agent loop 将连续的 `parallel` 调用归入有界滚动池,并把每个 `exclusive` 调用视为顺序屏障。只有分发/主体会重叠;策略、持久结果和上下文仍保持模型顺序。Code Mode 绑定通过桥接层自己的池复用同一套分类。[并行工具调用 Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) 规定已交付声明及其原理。 + +## 模型体验 + +### 普通工具 schema + +#### 模型看到的内容 + +在普通模式下,模型会看到每个可见定义的确切名称、描述和 JSON Schema;已交付定义记录在生成的[工具包映射和 schema 章节](../../../docs/tool-catalog.md#tool-package-map)中。agent 作用域的限制、遮蔽和扩展注册会改变该 agent 的最终工具集合。 + +#### Token 影响 + +每次请求的固定成本与可见定义成正比。隐藏工具的限制会为该 agent 移除其全部 schema 成本。 + +#### KV Cache 影响 + +只要可见定义及其顺序不变,前缀就保持稳定。注册、dispose 或作用域限制可能从第一个改变的 schema token 起使复用失效。 + +### Code Mode schema 与系统提示词 + +#### 模型看到的内容 + +Code Mode 会公开生成的 [`run_code` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tools)、下方 SDK 说明,以及按所加载运行时语言生成的精确 SDK 块(TypeScript 的 `declare const tools` 块,或 Python 的 `tools` 声明)。`both` 会同时公开普通 schema 与此 Code Mode API。在 `code` 下,提示词还会带上 `tools:code-only` 规则,其顺序排在逐工具指导段之前,让模型先读到「可以调用哪些工具」再读「每个工具做什么」;`both` 下它渲染为空。说明与 SDK 块随所加载运行时的语言切换;下方展示 TypeScript 版本(经 [`dsh-code-runtime-worker-thread`](../../code-runtime/code-runtime-worker-thread/README.md)),Python 版本(用于任何报告 `language: 'python'` 的运行时)以 Python 语法提供相同操作和类型(`await tools.name(args)`、特殊名称用下标访问、`print(...)` 与顶层 `return`)。 + +##### Code Mode SDK 说明 + +```markdown +## Writing code for run_code + +`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program: + +- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue. +- Independent read-only calls MAY overlap under `Promise.all` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with `await`. +- Emit results with `return` and/or `console.log(...)`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. + +The available tools: +``` + +#### Token 影响 + +每次请求的固定成本与可见定义成正比。Code Mode 使用生成的 SDK 文本加一个传输 schema 取代最终工具 schema,但不承诺普遍减少成本。 + +#### KV Cache 影响 + +只要 Code Mode 选择、生成的 SDK、传输 schema 和可见工具集合不变,前缀就保持稳定。模式或筛选器变更可能从第一个改变的提示词或 schema token 起使复用失效。 + +### 工具调用历史与结果 + +#### 模型看到的内容 + +循环会保留模型发出的参数和注册表的最终内容。任何抛出异常或遭到拒绝的调用,都会转换为确切的 `Error: `。Code Mode 只返回外层程序打印的行和呈现后的返回值;两者都为空时返回 `(run_code completed with no output)`;失败时返回 `Error: code run failed (): `,并根据是否存在已捕获内容,在其后附加 `Captured output:` 与捕获的行。内部分发事件只保留在日志中;成功且含图片的子结果会在外层结果之后作为带来源归属的上下文追加,后置执行监听器也可以在同一边界追加其他带来源归属的上下文。 + +#### Token 影响 + +参数、结果和附加上下文取决于数据,并会重复发送直至压缩(compaction)。隐藏工具的限制还会在模型可以调用这些工具之前移除其 schema。 + +#### KV Cache 影响 + +仅追加;新的可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。 + +## 已知限制与暂缓事项 + +- **并发策略不是事件门禁**:`executionMode()` 直接读取已解析的工具定义;插件只能在自身拥有的定义上声明分类器。 +- **`tools/pre-execute` 有意不允许改写 `exec.arguments`**:否则日志记录和呈现的参数会与实际运行内容失去同步;改写设计记录在[拟议的 Agent Note](../../../.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.md)中。 +- **调用方定义的 subagent 与工作流结构化输出仍要求对象根**:这是消费方层面的守卫;共享 schema 词汇和工具输出支持任意 JSON 根。 +- **定义中的 `timeoutMs` 仅作声明之用**:注册表绝不会强制执行截止时间;要强制执行,必须使用 `@deepseek-ai/dsh-tool-call-timeout-policy` 包装层。 +- **Code Mode 的 SDK 语言由当前加载的运行时决定,且呈现方式按 agent 而非按工具**:`mode: code`/`both` 会拒绝组装提示词,除非 `ctx.codeRuntime.language` 有已注册的 SDK 渲染器(TypeScript 或 Python);作用域限制/遮蔽与 `presentAs` 会选择每个 agent 的可见绑定及其形态,但在同一个 agent 内不能让一个工具仅使用 Native,而另一个仅使用 Code。 +- **Code Mode 中间值只存在于执行局部,且没有字节上限**:这些规范的类型化值无法从会话回放重建,并可能耗尽进程或 worker 内存;只有外层 `run_code` 输出受 worker 可配置的硬上限约束。每个子调用的持久日志副本则确实有上限:`tools/code-dispatch-log` waterfall 允许 spill 策略把过大的 `tool/code-dispatch` 内容替换为预览加定位符([原理](../../../.agents/notes/implemented/feature/2026-07-26-code-dispatch-log-spill.md))。 +- **每次运行都会获得全新的 `run_code` 状态**:MVP 不采用持久 REPL 风格内核(跨调用状态不会出现在日志中);参见 [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/index.js new file mode 100644 index 0000000..ba71664 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/index.js @@ -0,0 +1,3577 @@ +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { AnonymousEntries, NamedEntries, ScopedLayers, scopeOf, scopeTarget } from "@deepseek-ai/dsh-scope"; +import { CallId, HarnessError, assertNever, createUserMessage, deepFreeze } from "@deepseek-ai/dsh-llm"; +import { isJsonValue, snapshotJsonValue } from "@deepseek-ai/dsh-session"; +//#region lib/types/json-schema.js +/** +* Enforced JSON Schema subset shared by tool outputs, generated Code Mode +* types, subagents, and workflows. The subset accepts any JSON root, an +* annotation-only schema for unconstrained JSON, one scalar `type`, object +* `properties`/`required`/boolean `additionalProperties`, array `items`, +* type-correct scalar `enum`/`const`, and exact-one `oneOf`. +* +* Unsupported or misplaced keywords reject rather than being accepted without +* enforcement. Consumers that require an object root apply +* {@link assertObjectJsonSchema} before accepting input. +* @module dsh-tools/json-schema +*/ +/** +* Thrown when a raw schema falls outside the enforced subset. `violations` +* lists every offending path instead of stopping at the first author error. +*/ +var JsonSchemaError = class extends HarnessError { + /** Individual schema violations in walk order. */ + violations; + constructor(violations) { + super(`unsupported JSON schema: ${violations.join("; ")}`, "UNSUPPORTED_SCHEMA"); + this.name = "JsonSchemaError"; + this.violations = violations; + } +}; +const CONSTRAINT_KEYWORDS = new Set([ + "type", + "oneOf", + "properties", + "required", + "additionalProperties", + "items", + "enum", + "const" +]); +const ANNOTATION_KEYWORDS = new Set([ + "description", + "title", + "default", + "examples" +]); +const SCHEMA_TYPES = [ + "object", + "array", + "string", + "number", + "integer", + "boolean", + "null" +]; +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const constructor = Object.getOwnPropertyDescriptor(prototype, "constructor")?.value; + if (typeof constructor !== "function") return false; + try { + return constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } catch { + return false; + } +} +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value) { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, "Object"); +} +/** +* Test for a realm-agnostic plain JSON record without accepting arrays or +* exotic objects. +* @param value - candidate record from any JavaScript realm. +* @returns Whether the value has a plain-object prototype chain. +*/ +function isPlainJsonRecord(value) { + if (typeof value !== "object" || value === null || Array.isArray(value)) return false; + try { + const prototype = Object.getPrototypeOf(value); + return prototype === null || typeof prototype === "object" && isIntrinsicObjectPrototype(prototype); + } catch { + return false; + } +} +/** Whether an array uses one realm's intrinsic `Array.prototype`. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, "Array")) return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === "object" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype); +} +/** Return whether a record contains only own enumerable string keys. */ +function hasOnlyEnumerableStringKeys(value) { + try { + return Reflect.ownKeys(value).every((key) => typeof key === "string" && Object.prototype.propertyIsEnumerable.call(value, key)); + } catch { + return false; + } +} +/** +* Test for an ordinary schema record whose keys survive JSON projection. +* @param value - candidate record from any JavaScript realm. +* @returns Whether the record has an intrinsic prototype and only own enumerable string keys. +*/ +function isJsonSchemaRecord(value) { + return isPlainJsonRecord(value) && hasOnlyEnumerableStringKeys(value); +} +/** +* Test for a dense ordinary array with no JSON-invisible decorations. +* @param value - candidate array from any JavaScript realm. +* @returns Whether the array is intrinsic, dense, and undecorated. +*/ +function isPlainJsonArray(value) { + if (!Array.isArray(value)) return false; + try { + if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false; + for (let index = 0; index < value.length; index++) if (!Object.hasOwn(value, index)) return false; + return true; + } catch { + return false; + } +} +/** Lossless finite JSON number, excluding negative zero. */ +function isJsonNumber(value) { + return typeof value === "number" && Number.isFinite(value) && !Object.is(value, -0); +} +/** Whether a scalar is valid for one declared schema type. */ +function scalarMatches(type, value) { + switch (type) { + case "string": return typeof value === "string"; + case "number": return isJsonNumber(value); + case "integer": return isJsonNumber(value) && Number.isInteger(value); + case "boolean": return typeof value === "boolean"; + case "null": return value === null; + /* v8 ignore next -- JsonSchemaScalarType is closed; this retains compile-time exhaustiveness. */ + default: return assertNever(type, "JsonSchemaType"); + } +} +/** Keywords that are invalid beside `oneOf`. */ +const ONE_OF_SIBLING_KEYWORDS = [ + "properties", + "required", + "additionalProperties", + "items", + "enum", + "const" +]; +/** Validate object-only fields after its property schemas have been visited. */ +function checkObjectSchemaTail(node, path, properties, violations) { + const hasRequired = Object.hasOwn(node, "required"); + const required = hasRequired ? node.required : void 0; + if (hasRequired) if (!isPlainJsonArray(required) || required.some((entry) => typeof entry !== "string")) violations.push(`${path}.required must be an array of strings`); + else { + const declared = isJsonSchemaRecord(properties) ? properties : {}; + for (const key of required) if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names "${key}" which is not in properties`); + } + if (Object.hasOwn(node, "additionalProperties") && typeof node.additionalProperties !== "boolean") violations.push(`${path}.additionalProperties must be a boolean`); +} +/** Collect every violation for one raw schema tree without using the JavaScript call stack. */ +function checkSchemaNode(root, rootPath, violations, seen) { + const tasks = [{ + kind: "enter", + node: root, + path: rootPath + }]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "leave") { + seen.delete(task.node); + continue; + } + if (task.kind === "one-of-tail") { + for (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(task.node, key)) violations.push(`${task.path}.${key} is not supported beside oneOf`); + continue; + } + if (task.kind === "object-tail") { + checkObjectSchemaTail(task.node, task.path, task.properties, violations); + continue; + } + const { node, path } = task; + if (!isJsonSchemaRecord(node)) { + violations.push(`${path} must be a schema object`); + continue; + } + if (seen.has(node)) { + violations.push(`${path} is circular`); + continue; + } + seen.add(node); + tasks.push({ + kind: "leave", + node + }); + for (const key of Object.keys(node)) { + if (CONSTRAINT_KEYWORDS.has(key)) continue; + if (ANNOTATION_KEYWORDS.has(key)) { + try { + if (!isJsonValue(node[key])) violations.push(`${path}.${key} annotation must be lossless JSON data`); + } catch { + violations.push(`${path}.${key} annotation must be lossless JSON data`); + } + continue; + } + violations.push(`${path}.${key} is not a supported keyword (subset: type/oneOf/properties/required/additionalProperties/items/enum/const + annotations)`); + } + if (Object.hasOwn(node, "description") && typeof node.description !== "string") violations.push(`${path}.description must be a string`); + if (Object.hasOwn(node, "title") && typeof node.title !== "string") violations.push(`${path}.title must be a string`); + const hasType = Object.hasOwn(node, "type"); + const hasOneOf = Object.hasOwn(node, "oneOf"); + if (hasType && hasOneOf) { + violations.push(`${path} cannot declare both type and oneOf`); + continue; + } + if (!hasType && !hasOneOf) { + for (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(node, key)) violations.push(`${path}.${key} requires type or oneOf`); + continue; + } + if (hasOneOf) { + const oneOf = node.oneOf; + tasks.push({ + kind: "one-of-tail", + node, + path + }); + if (!isPlainJsonArray(oneOf) || oneOf.length < 2) violations.push(`${path}.oneOf must be an array of at least two schemas`); + else for (let index = oneOf.length - 1; index >= 0; index--) tasks.push({ + kind: "enter", + node: oneOf[index], + path: `${path}.oneOf[${index}]` + }); + continue; + } + const type = node.type; + if (typeof type !== "string" || !SCHEMA_TYPES.includes(type)) { + violations.push(Array.isArray(type) ? `${path}.type must be a single type string (type arrays are not supported)` : `${path}.type must be one of ${SCHEMA_TYPES.join("/")}`); + continue; + } + const schemaType = type; + for (const [key, types] of Object.entries({ + properties: ["object"], + required: ["object"], + additionalProperties: ["object"], + items: ["array"], + enum: [ + "string", + "number", + "integer", + "boolean", + "null" + ], + const: [ + "string", + "number", + "integer", + "boolean", + "null" + ] + })) if (Object.hasOwn(node, key) && !types.includes(schemaType)) violations.push(`${path}.${key} is not supported on type "${schemaType}"`); + switch (schemaType) { + case "object": { + const properties = Object.hasOwn(node, "properties") ? node.properties : void 0; + tasks.push({ + kind: "object-tail", + node, + path, + properties + }); + if (Object.hasOwn(node, "properties")) if (!isJsonSchemaRecord(properties)) violations.push(`${path}.properties must be an object of schemas`); + else { + const entries = Object.entries(properties); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === void 0) continue; + tasks.push({ + kind: "enter", + node: entry[1], + path: `${path}.properties.${entry[0]}` + }); + } + } + break; + } + case "array": + if (Object.hasOwn(node, "items")) tasks.push({ + kind: "enter", + node: node.items, + path: `${path}.items` + }); + break; + case "string": + case "number": + case "integer": + case "boolean": + case "null": { + const hasEnum = Object.hasOwn(node, "enum"); + const allowed = hasEnum ? node.enum : void 0; + const enumValid = isPlainJsonArray(allowed) && allowed.length > 0 && allowed.every((entry) => scalarMatches(schemaType, entry)); + if (hasEnum && !enumValid) violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`); + const hasConst = Object.hasOwn(node, "const"); + const declaredConst = hasConst ? node.const : void 0; + const constValid = scalarMatches(schemaType, declaredConst); + if (hasConst) { + if (!constValid) violations.push(`${path}.const must be a ${schemaType} value`); + else if (enumValid && !allowed.includes(declaredConst)) violations.push(`${path}.const must be one of ${path}.enum when both are declared`); + } + break; + } + /* v8 ignore next -- schemaType was narrowed from the closed SCHEMA_TYPES table above. */ + default: assertNever(schemaType, "JsonSchemaType"); + } + } +} +/** +* Assert that an arbitrary raw schema uses only the enforced subset. +* Annotation-only schemas are accepted as the standard unconstrained-JSON +* form; callers that require an object root use {@link assertObjectJsonSchema}. +* @param schema - untrusted raw JSON Schema. +* @returns Assertion that the schema belongs to the supported subset. +*/ +function assertSupportedJsonSchema(schema) { + const violations = []; + checkSchemaNode(schema, "schema", violations, /* @__PURE__ */ new Set()); + if (violations.length > 0) throw new JsonSchemaError(violations); +} +/** +* Assert the enforced subset plus the object-root constraint retained by +* subagent and workflow structured outputs. +* @param schema - untrusted caller-supplied schema. +* @returns Assertion that the schema belongs to the supported subset and has an object root. +*/ +function assertObjectJsonSchema(schema) { + const violations = []; + checkSchemaNode(schema, "schema", violations, /* @__PURE__ */ new Set()); + if (violations.length === 0 && (!isJsonSchemaRecord(schema) || !Object.hasOwn(schema, "type") || schema.type !== "object")) violations.push("schema.type must be \"object\" (structured output is object-rooted)"); + if (violations.length > 0) throw new JsonSchemaError(violations); +} +/** Safely test the lossless JSON boundary when a getter may throw. */ +function safelyIsJsonValue(value) { + try { + return isJsonValue(value); + } catch { + return false; + } +} +/** Root-aware diagnostic path for the parameter validator's empty sentinel. */ +function diagnosticPath(path) { + return path === "" ? "arguments" : path; +} +/** Append one object property without a leading dot at an implicit root. */ +function propertyPath(path, key) { + return path === "" ? key : `${path}.${key}`; +} +/** The generic exception-containment diagnostic owned by one valid schema node. */ +function losslessValueViolation(path) { + return [`"${diagnosticPath(path)}" must be a lossless JSON value`]; +} +/** Append diagnostics without spreading a potentially wide child result as call arguments. */ +function appendViolations(target, source) { + for (const violation of source) target.push(violation); +} +/** Initialize one validation frame with empty aggregation state. */ +function valueFrame(node, value, path) { + return { + node, + value, + path, + catches: false, + phase: "start", + children: [], + childIndex: 0, + violations: [], + tailViolations: [], + matches: 0 + }; +} +/** Validate one scalar node after its primitive type check. */ +function checkScalarValue(node, value, path) { + const allowed = Object.hasOwn(node, "enum") ? node.enum : void 0; + if (allowed !== void 0 && !allowed.includes(value)) return [`"${diagnosticPath(path)}" must be one of ${JSON.stringify(allowed)}`]; + if (Object.hasOwn(node, "const") && value !== node.const) return [`"${diagnosticPath(path)}" must be ${JSON.stringify(node.const)}`]; + return []; +} +/** Validate one trusted schema/value pair with explicit frames rather than recursive calls. */ +function checkValue(schema, value, path) { + const frames = [valueFrame(schema, value, path)]; + let rootResult; + const receive = (result) => { + const parent = frames.at(-1); + if (parent === void 0) { + rootResult = result; + return; + } + if (parent.kind === "oneOf") { + if (result.length === 0) parent.matches++; + } else appendViolations(parent.violations, result); + }; + const finish = (result) => { + frames.pop(); + receive(result); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === void 0) break; + try { + if (frame.phase === "children") { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === void 0) throw new Error("missing schema-value child frame"); + frame.childIndex++; + frames.push(valueFrame(child.node, child.value, child.path)); + continue; + } + if (frame.kind === "oneOf") { + finish(frame.matches === 1 ? [] : [`"${diagnosticPath(frame.path)}" must match exactly one oneOf branch (matched ${frame.matches})`]); + continue; + } + appendViolations(frame.violations, frame.tailViolations); + if (frame.violations.length > 0) finish(frame.violations); + else if (frame.kind === "object") finish(safelyIsJsonValue(frame.value) ? [] : [`"${diagnosticPath(frame.path)}" must be a lossless JSON object`]); + else finish(safelyIsJsonValue(frame.value) ? [] : [`"${diagnosticPath(frame.path)}" must be a dense lossless JSON array`]); + continue; + } + const nodeType = Object.hasOwn(frame.node, "type") ? frame.node.type : void 0; + frame.catches = !(nodeType !== void 0 && !SCHEMA_TYPES.includes(nodeType)); + const oneOf = Object.hasOwn(frame.node, "oneOf") ? frame.node.oneOf : void 0; + if (oneOf !== void 0) { + frame.kind = "oneOf"; + frame.children = Array.from(oneOf, (branch) => ({ + node: branch, + value: frame.value, + path: frame.path + })); + frame.childIndex = 0; + frame.matches = 0; + frame.phase = "children"; + continue; + } + if (nodeType === void 0) { + finish(safelyIsJsonValue(frame.value) ? [] : losslessValueViolation(frame.path)); + continue; + } + switch (nodeType) { + case "object": { + if (!isPlainJsonRecord(frame.value)) { + finish([`"${diagnosticPath(frame.path)}" must be an object`]); + break; + } + const properties = Object.hasOwn(frame.node, "properties") ? frame.node.properties ?? {} : {}; + const violations = []; + const required = Object.hasOwn(frame.node, "required") ? frame.node.required ?? [] : []; + for (const key of required) if (!Object.hasOwn(frame.value, key) || frame.value[key] === void 0) violations.push(`missing required property "${propertyPath(frame.path, key)}"`); + const children = []; + for (const [key, child] of Object.entries(properties)) { + if (!Object.hasOwn(frame.value, key) || frame.value[key] === void 0) continue; + children.push({ + node: child, + value: frame.value[key], + path: propertyPath(frame.path, key) + }); + } + const tailViolations = []; + if (Object.hasOwn(frame.node, "additionalProperties") && frame.node.additionalProperties === false) { + for (const key of Object.keys(frame.value)) if (!Object.hasOwn(properties, key)) tailViolations.push(`"${propertyPath(frame.path, key)}" is not a declared property (additionalProperties: false)`); + } + frame.kind = "object"; + frame.children = children; + frame.childIndex = 0; + frame.violations = violations; + frame.tailViolations = tailViolations; + frame.phase = "children"; + break; + } + case "array": { + if (!Array.isArray(frame.value)) { + finish([`"${diagnosticPath(frame.path)}" must be an array`]); + break; + } + const items = Object.hasOwn(frame.node, "items") ? frame.node.items : void 0; + const children = items === void 0 ? [] : frame.value.flatMap((entry, index) => [{ + node: items, + value: entry, + path: `${frame.path}[${index}]` + }]); + frame.kind = "array"; + frame.children = children; + frame.childIndex = 0; + frame.violations = []; + frame.phase = "children"; + break; + } + case "string": + finish(typeof frame.value === "string" ? checkScalarValue(frame.node, frame.value, frame.path) : [`"${diagnosticPath(frame.path)}" must be a string`]); + break; + case "number": + finish(typeof frame.value !== "number" ? [`"${diagnosticPath(frame.path)}" must be a number`] : !isJsonNumber(frame.value) ? [`"${diagnosticPath(frame.path)}" must be a finite JSON number`] : checkScalarValue(frame.node, frame.value, frame.path)); + break; + case "integer": + finish(!isJsonNumber(frame.value) || !Number.isInteger(frame.value) ? [`"${diagnosticPath(frame.path)}" must be an integer`] : checkScalarValue(frame.node, frame.value, frame.path)); + break; + case "boolean": + finish(typeof frame.value === "boolean" ? checkScalarValue(frame.node, frame.value, frame.path) : [`"${diagnosticPath(frame.path)}" must be a boolean`]); + break; + case "null": + finish(frame.value === null ? checkScalarValue(frame.node, frame.value, frame.path) : [`"${diagnosticPath(frame.path)}" must be null`]); + break; + default: finish(assertNever(nodeType, "JsonSchemaType")); + } + } catch (error) { + let failed = frames.pop(); + while (failed !== void 0 && !failed.catches) failed = frames.pop(); + if (failed === void 0) throw error; + receive(losslessValueViolation(failed.path)); + } + } + /* v8 ignore next -- every root frame finishes or throws. */ + return rootResult ?? losslessValueViolation(path); +} +/** +* Validate a candidate value against an asserted raw schema. The function is +* total for arbitrary values and returns path-qualified violations. +* @param schema - a schema accepted by {@link assertSupportedJsonSchema}. +* @param value - the candidate JSON value. +* @param path - root label used in diagnostics. +* @returns All violations in walk order; empty means valid. +*/ +function validateJsonSchemaValue(schema, value, path = "value") { + return checkValue(schema, value, path); +} +//#endregion +//#region lib/types/schema.js +/** Unified JSON-value schema DSL, inference, compilation, and typed tool helper. @module dsh-tools/schema */ +const ANNOTATION_KEYS = [ + "description", + "title", + "default", + "examples" +]; +/** Throw one author-schema violation through the shared schema error type. */ +function authorError(message) { + throw new JsonSchemaError([message]); +} +/** Copy own annotation fields for validation by the raw-schema boundary. */ +function copyAnnotations(source, target) { + if (Object.hasOwn(source, "description")) target.description = source.description; + if (Object.hasOwn(source, "title")) target.title = source.title; + if (Object.hasOwn(source, "default")) target.default = source.default; + if (Object.hasOwn(source, "examples")) target.examples = source.examples; +} +/** Reject author-only keys outside one node's declared vocabulary. */ +function assertAuthorKeys(source, path, allowed) { + for (const key of Object.keys(source)) if (!allowed.includes(key)) authorError(`${path}.${key} is not supported by the value schema DSL`); +} +/** Install a compiled node without giving `__proto__` assignment semantics. */ +function assignCompiledNode(destination, node) { + switch (destination.kind) { + case "root": + destination.holder.value = node; + break; + case "property": + Object.defineProperty(destination.target, destination.key, { + value: node, + enumerable: true, + configurable: true, + writable: true + }); + break; + case "item": + destination.target.items = node; + break; + case "one-of": + destination.target[destination.index] = node; + break; + } +} +/** Install a compiled property map at its root or containing object node. */ +function assignCompiledPropertyMap(destination, compiled) { + if (destination.kind === "root") destination.holder.value = compiled; + else destination.target.properties = compiled.properties; +} +/** Execute an author-schema compilation task graph without recursive descent. */ +function runSchemaCompiler(initial) { + const seen = /* @__PURE__ */ new Set(); + const tasks = [initial]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "leave") { + seen.delete(task.input); + continue; + } + if (task.kind === "property-map-tail") { + if (task.required.length > 0) { + task.compiled.required = task.required; + if (task.destination.kind === "object") task.destination.target.required = task.required; + } + continue; + } + if (task.kind === "property") { + if (!isJsonSchemaRecord(task.property)) authorError(`${task.path} must be a value schema object`); + if (Object.hasOwn(task.property, "required") && task.property.required !== true) authorError(`${task.path}.required must be true when present`); + if (Object.hasOwn(task.property, "required") && task.property.required === true) task.required.push(task.key); + tasks.push({ + kind: "value", + input: task.property, + path: task.path, + allowRequired: true, + destination: { + kind: "property", + target: task.properties, + key: task.key + } + }); + continue; + } + if (task.kind === "property-map") { + if (!isJsonSchemaRecord(task.input)) authorError(`${task.path} must be an object of value schemas`); + if (seen.has(task.input)) authorError(`${task.path} is circular`); + seen.add(task.input); + const compiled = { properties: {} }; + const required = []; + assignCompiledPropertyMap(task.destination, compiled); + tasks.push({ + kind: "leave", + input: task.input + }); + tasks.push({ + kind: "property-map-tail", + compiled, + required, + destination: task.destination + }); + const entries = Object.entries(task.input); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === void 0) continue; + tasks.push({ + kind: "property", + property: entry[1], + path: `${task.path}.${entry[0]}`, + key: entry[0], + properties: compiled.properties, + required + }); + } + continue; + } + const { input, path } = task; + if (!isJsonSchemaRecord(input)) authorError(`${path} must be a value schema object`); + if (seen.has(input)) authorError(`${path} is circular`); + seen.add(input); + const authorKeys = [...ANNOTATION_KEYS, ...task.allowRequired ? ["required"] : []]; + const node = {}; + assignCompiledNode(task.destination, node); + tasks.push({ + kind: "leave", + input + }); + if (Object.hasOwn(input, "oneOf")) { + assertAuthorKeys(input, path, [ + ...authorKeys, + "oneOf", + "type" + ]); + if (Object.hasOwn(input, "type")) authorError(`${path} cannot declare both type and oneOf`); + if (!isPlainJsonArray(input.oneOf)) authorError(`${path}.oneOf must be an array of at least two value schemas`); + const branches = []; + node.oneOf = branches; + copyAnnotations(input, node); + for (let index = input.oneOf.length - 1; index >= 0; index--) tasks.push({ + kind: "value", + input: input.oneOf[index], + path: `${path}.oneOf[${index}]`, + allowRequired: false, + destination: { + kind: "one-of", + target: branches, + index + } + }); + continue; + } + const inputType = Object.hasOwn(input, "type") ? input.type : void 0; + switch (inputType) { + case "json": + assertAuthorKeys(input, path, [...authorKeys, "type"]); + copyAnnotations(input, node); + break; + case "object": + assertAuthorKeys(input, path, [ + ...authorKeys, + "type", + "properties", + "additionalProperties" + ]); + if (!Object.hasOwn(input, "additionalProperties") || typeof input.additionalProperties !== "boolean") authorError(`${path}.additionalProperties must be explicitly true or false`); + node.type = "object"; + copyAnnotations(input, node); + node.additionalProperties = input.additionalProperties; + if (Object.hasOwn(input, "properties")) tasks.push({ + kind: "property-map", + input: input.properties, + path: `${path}.properties`, + destination: { + kind: "object", + target: node + } + }); + break; + case "array": + assertAuthorKeys(input, path, [ + ...authorKeys, + "type", + "items" + ]); + node.type = "array"; + copyAnnotations(input, node); + if (Object.hasOwn(input, "items")) tasks.push({ + kind: "value", + input: input.items, + path: `${path}.items`, + allowRequired: false, + destination: { + kind: "item", + target: node + } + }); + break; + case "string": + case "number": + case "integer": + case "boolean": + case "null": + assertAuthorKeys(input, path, [ + ...authorKeys, + "type", + "enum", + "const" + ]); + node.type = inputType; + copyAnnotations(input, node); + if (Object.hasOwn(input, "enum")) { + if (!isPlainJsonArray(input.enum)) authorError(`${path}.enum must be a non-empty array of scalar values`); + node.enum = Array.from(input.enum, (entry) => entry); + } + if (Object.hasOwn(input, "const")) node.const = input.const; + break; + default: authorError(`${path}.type must be string/number/integer/boolean/null/array/object/json, or use oneOf`); + } + } +} +/** Compile one implicit property map, collecting per-property requiredness. */ +function compilePropertyMap(input, path) { + const holder = {}; + runSchemaCompiler({ + kind: "property-map", + input, + path, + destination: { + kind: "root", + holder + } + }); + /* v8 ignore next -- the root task assigns before scheduling any descendants. */ + return holder.value ?? authorError(`${path} did not compile`); +} +/** Compile one author node without applying any consumer root restriction. */ +function compileValueSchema(input, path) { + const holder = {}; + runSchemaCompiler({ + kind: "value", + input, + path, + allowRequired: false, + destination: { + kind: "root", + holder + } + }); + /* v8 ignore next -- the root task assigns before scheduling any descendants. */ + return holder.value ?? authorError(`${path} did not compile`); +} +/** +* Compile one author-facing value schema to the enforced raw JSON Schema +* subset. The author-only `json` node becomes an annotation-only schema. +* @param spec - schema for any JSON-value root. +* @returns The asserted raw schema projection. +*/ +function valueSchemaSpecToJsonSchema(spec) { + const schema = compileValueSchema(spec, "schema"); + assertSupportedJsonSchema(schema); + return schema; +} +/** +* Compile the implicit open parameter object into raw JSON Schema. +* @param spec - per-property parameter definitions. +* @returns An object-rooted raw schema with no implicit-root openness override. +*/ +function parameterSchemaSpecToJsonSchema(spec) { + const compiled = compilePropertyMap(spec, "parameters"); + const schema = { + type: "object", + properties: compiled.properties, + ...compiled.required === void 0 ? {} : { required: compiled.required } + }; + assertSupportedJsonSchema(schema); + return schema; +} +/** Invalid model-generated arguments for a typed tool. */ +var ToolArgsError = class extends HarnessError { + /** Individual violations in schema-walk order. */ + violations; + constructor(violations) { + super(`invalid arguments: ${violations.join("; ")}`, "INVALID_ARGS"); + this.name = "ToolArgsError"; + this.violations = violations; + } +}; +/** +* Validate model-generated arguments against an implicit parameter schema. +* @param spec - declared parameter schema. +* @param args - candidate arguments, however malformed. +* @returns Path-qualified violations; empty means valid. +*/ +function validateArgs(spec, args) { + return validateJsonSchemaValue(parameterSchemaSpecToJsonSchema(spec), args, ""); +} +/** +* Define a first-party tool with inferred arguments and strict execution +* validation. Replay-only presenters validate softly and fall back to generic +* rendering for obsolete logged arguments. +* @param options - typed definition and optional finalizer and presenters. +* @returns A registry-ready definition. +*/ +function defineTool(options) { + const userExecute = options.execute; + const userFinalizeContent = options.finalizeContent; + const userRender = options.output.render; + const userPresentationMeta = options.output.presentationMeta; + const userPresentCall = options.presentCall; + const userPresentResult = options.presentResult; + const userIsConcurrencySafe = options.isConcurrencySafe; + if (options.timeoutMs !== void 0 && (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) throw new Error(`defineTool(${options.name}): timeoutMs must be a positive finite number`); + const parameters = parameterSchemaSpecToJsonSchema(options.parameters); + const outputSchema = valueSchemaSpecToJsonSchema(options.output.schema); + const validate = (args) => validateJsonSchemaValue(parameters, args, ""); + const tool = { + name: options.name, + description: options.description, + parameters, + output: { + schema: outputSchema, + render(args, value) { + return userRender(args, value); + }, + ...userPresentationMeta !== void 0 ? { presentationMeta(args, value) { + return userPresentationMeta(args, value); + } } : {} + }, + ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}, + async execute(args, exec) { + const violations = validate(args); + if (violations.length > 0) throw new ToolArgsError(violations); + return userExecute(args, exec); + } + }; + if (userFinalizeContent) tool.finalizeContent = (exec, result) => userFinalizeContent(exec, result); + if (userPresentCall) tool.presentCall = (args) => { + if (validate(args).length > 0) return void 0; + return userPresentCall(args); + }; + if (userPresentResult) tool.presentResult = (args, result) => { + if (validate(args).length > 0) return void 0; + return userPresentResult(args, result); + }; + if (userIsConcurrencySafe) tool.isConcurrencySafe = (args) => { + if (validate(args).length > 0) return false; + return userIsConcurrencySafe(args); + }; + return tool; +} +//#endregion +//#region lib/types/code-mode.js +/** +* Code Mode `run_code` transport. Programs call the registry's agent-visible +* tools through nested executions scheduled under the native concurrency +* contract; each sub-dispatch is logged for reconstruction, while only the +* outer curated result enters model history. +* @module @deepseek-ai/dsh-tools/src/code-mode +*/ +/** The model-facing name of the Code Mode tool. */ +const RUN_CODE_NAME = "run_code"; +/** +* The TypeScript flavor: the fallback for a schema read with no runtime +* mounted ({@link resolveFlavor} owns which readers reach that). A real +* assembly always resolves a runtime first, so the model never sees this +* fallback outside its own language. +*/ +const TYPESCRIPT_FLAVOR = { + description: "Execute a TypeScript program against the available tools. Takes two required arguments: `code`, the BODY of an async function (erasable syntax only; top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return is program output — curate it. Image-bearing subtool results are attached after the run.", + codeDescription: "The program: the body of an async TypeScript function." +}; +/** Per-language `run_code` schema flavors (see {@link RunCodeFlavor}); one entry per {@link CodeSdkLanguage}. */ +const RUN_CODE_FLAVORS = { + typescript: TYPESCRIPT_FLAVOR, + python: { + description: "Execute a Python program against the available tools. Takes two required arguments: `code`, the BODY of an async function (top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Use `print(...)` and/or `return ` for program output — curate it. Image-bearing subtool results are attached after the run.", + codeDescription: "The program: the body of an async Python function." + } +}; +/** +* The `description` parameter's model-facing description: language-independent +* (the UI label contract is the same for every runtime), shared between the +* static spec and the language-aware `parameters` getter so the two emissions +* can never drift. +*/ +const RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION = "Clear, concise description of what this program does in active voice, 5-10 words (shown in the UI). Examples: \"Count TODO markers across packages\"; \"Read failing test and its fixture\"; \"Rename config key in every cordis.yml\"."; +/** +* Resolve the {@link RunCodeFlavor} for the loaded runtime's language, read at +* schema-emission time so the model-visible `run_code` schema always matches +* the SDK section's language. `peekRuntime` returns `undefined` only when no +* runtime is mounted, which reaches this function through definition readers +* and `schemas()` — the doc-catalog harvest is the only shipped one, and none +* of them feeds a model, because `wireSchemas` calls `requireCodeRuntime` +* before projecting — so that path degrades to {@link TYPESCRIPT_FLAVOR}. A +* mounted runtime whose language has no flavor entry fails loud, exactly as +* `requireCodeRuntime` rejects it at assembly. Keeping this table in step with +* `SDK_RENDERERS` is the compiler's job ({@link CodeSdkLanguage}); what this +* guard owns is the runtime-supplied language neither table knows, which never +* yields a wrong-language schema for a real runtime. +*/ +function resolveFlavor(peekRuntime) { + const runtime = peekRuntime(); + if (runtime === void 0) return TYPESCRIPT_FLAVOR; + const flavor = RUN_CODE_FLAVORS[runtime.language]; + if (!Object.hasOwn(RUN_CODE_FLAVORS, runtime.language) || flavor === void 0) { + const known = Object.keys(RUN_CODE_FLAVORS).map((name) => JSON.stringify(name)).join(", "); + throw new Error(`dsh-tools: no run_code schema flavor registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`); + } + return flavor; +} +/** +* Thrown by `run_code` when the program run itself failed — a program +* exception, a budget expiry, an abort, or substrate death. Extends +* {@link HarnessError} (`code: 'CODE_RUN_FAILED'`); the registry's execution +* pipeline converts it into a structured `isError` result whose text carries +* the failure kind plus the captured logs, so the model can self-correct. +*/ +var CodeRunFailedError = class extends HarnessError { + constructor(message) { + super(message, "CODE_RUN_FAILED"); + this.name = "CodeRunFailedError"; + } +}; +/** +* Snapshot one binding call's argument as lossless JSON, then snapshot that +* detached value again so dispatch and logging stay independent without +* reintroducing structured-clone's platform-specific nesting limit. +*/ +function jsonNormalizeArgs(value) { + let snapshot; + try { + snapshot = snapshotJsonValue(value); + } catch (error) { + throw new Error(`tool arguments must be lossless JSON: ${error instanceof Error ? error.message : String(error)}`); + } + if (snapshot === void 0) throw new Error("tool arguments must be lossless JSON (call the tool with an arguments object, e.g. `{}`)"); + const logged = snapshotJsonValue(snapshot); + /* v8 ignore next -- snapshot is already a detached lossless JSON value. */ + if (logged === void 0) throw new Error("tool arguments could not be detached for durable logging"); + return { + dispatched: snapshot, + logged + }; +} +/** Two-space JSON presentation, matching the existing shallow `run_code` text contract. */ +const JSON_INDENT = " "; +/** +* ECMAScript caps `JSON.stringify`'s `space` string at ten characters. The +* renderer also caps TOTAL indentation there, compacting deeper subtrees, so +* formatted output remains linear in the canonical JSON size. +*/ +const MAX_JSON_INDENT_CHARS = 10; +/** Render one non-string JSON root without recursive traversal or unbounded indentation growth. */ +function renderJsonValue(value) { + const chunks = []; + const tasks = [{ + kind: "value", + value, + depth: 0, + compact: false + }]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (task.kind === "text") { + chunks.push(task.text); + continue; + } + const current = task.value; + if (current === null || typeof current === "boolean" || typeof current === "number") { + chunks.push(String(current)); + continue; + } + if (typeof current === "string") { + chunks.push(JSON.stringify(current)); + continue; + } + const compact = task.compact || (task.depth + 1) * 2 > MAX_JSON_INDENT_CHARS; + const childDepth = task.depth + 1; + if (Array.isArray(current)) { + chunks.push("["); + if (current.length === 0) { + chunks.push("]"); + continue; + } + tasks.push({ + kind: "text", + text: compact ? "]" : `\n${JSON_INDENT.repeat(task.depth)}]` + }); + for (let index = current.length - 1; index >= 0; index--) { + const item = current[index]; + /* v8 ignore next -- canonical JsonValue arrays are dense. */ + if (item === void 0) throw new Error("cannot render a sparse JSON array"); + tasks.push({ + kind: "value", + value: item, + depth: childDepth, + compact + }); + tasks.push({ + kind: "text", + text: compact ? index === 0 ? "" : "," : `${index === 0 ? "\n" : ",\n"}${JSON_INDENT.repeat(childDepth)}` + }); + } + continue; + } + const keys = Object.keys(current); + chunks.push("{"); + if (keys.length === 0) { + chunks.push("}"); + continue; + } + tasks.push({ + kind: "text", + text: compact ? "}" : `\n${JSON_INDENT.repeat(task.depth)}}` + }); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === void 0) throw new Error("cannot render a missing JSON object key"); + const item = current[key]; + /* v8 ignore next -- canonical JsonValue records contain no undefined properties. */ + if (item === void 0) throw new Error("cannot render an undefined JSON object property"); + tasks.push({ + kind: "value", + value: item, + depth: childDepth, + compact + }); + tasks.push({ + kind: "text", + text: compact ? `${index === 0 ? "" : ","}${JSON.stringify(key)}:` : `${index === 0 ? "\n" : ",\n"}${JSON_INDENT.repeat(childDepth)}${JSON.stringify(key)}: ` + }); + } + } + return chunks.join(""); +} +/** Render one present program completion value for the model-facing result text. */ +function renderValue(value) { + return typeof value === "string" ? value : renderJsonValue(value); +} +/** +* Build the `run_code` {@link ToolDefinition}: required `code` and +* `description` parameters, executed through the dispatch bridge described +* above. The +* registry reserves it as presentation infrastructure under non-native modes, +* outside the filterable global/scoped capability layers. +* @param registry - the owning registry (sub-calls go through its `execute`, +* bindings cover its registered tools). +* @param options - the registry-private capabilities described above. +* @returns the registry-ready definition. +*/ +function createRunCodeTool(registry, options) { + const { requireRuntime, peekRuntime, maxParallel, shapeDispatchLog } = options; + const definition = defineTool({ + name: RUN_CODE_NAME, + description: TYPESCRIPT_FLAVOR.description, + parameters: { + code: { + type: "string", + required: true, + description: TYPESCRIPT_FLAVOR.codeDescription + }, + description: { + type: "string", + required: true, + description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION + } + }, + output: { + schema: { + type: "object", + additionalProperties: false, + properties: { + logs: { + type: "array", + required: true, + items: { type: "string" } + }, + result: { type: "json" } + } + }, + render: (_args, value) => { + const rendered = value.result === void 0 ? "" : renderValue(value.result); + const parts = [value.logs.join("\n"), rendered].filter((part) => part.length > 0); + return [{ + type: "text", + text: parts.length > 0 ? parts.join("\n") : "(run_code completed with no output)" + }]; + } + }, + async execute(args, exec) { + if (args.description.trim().length === 0) throw new Error("invalid description: expected a non-empty string"); + const runtime = requireRuntime(); + const runController = new AbortController(); + const onOuterAbort = () => { + runController.abort(exec.signal.reason); + }; + exec.signal.addEventListener("abort", onOuterAbort, { once: true }); + let dispatches = 0; + const pendingQueue = []; + const inFlight = /* @__PURE__ */ new Set(); + /** Tracked settle-event side work (log-content listener + append), drained at run settlement. */ + const logWork = /* @__PURE__ */ new Set(); + const commitQueue = []; + let exclusiveActive = false; + let driving = false; + let driverRun = Promise.resolve(); + let wake; + const wakeup = () => { + const release = wake; + wake = void 0; + release?.(); + }; + /** + * The single ordered lane. Each pass commits the head-of-line settled + * dispatch (ordered post-execute), then starts the next queued entry if + * its slot is free (ordered pre-execute), and otherwise sleeps until a + * body settles or a new submission arrives. One run reaching the + * empty-queues/empty-pool state is quiescence. + */ + const drive = () => { + if (driving) return driverRun; + driving = true; + driverRun = (async () => { + try { + for (;;) { + const signal = new Promise((resolve) => { + wake = resolve; + }); + const commitHead = commitQueue[0]; + if (commitHead !== void 0 && commitHead.settled) { + commitQueue.shift(); + await commitHead.commit(); + if (commitHead.mode === "exclusive") exclusiveActive = false; + continue; + } + const head = pendingQueue[0]; + if (head !== void 0) { + if (runController.signal.aborted) { + pendingQueue.shift(); + head.abandon(); + continue; + } + const mode = head.classify(); + if (!exclusiveActive && (mode === "exclusive" ? inFlight.size === 0 : inFlight.size < maxParallel)) { + if (mode === "exclusive") exclusiveActive = true; + head.mode = mode; + pendingQueue.shift(); + commitQueue.push(head); + await head.start(); + const flight = head.flight.finally(() => { + inFlight.delete(flight); + wakeup(); + }); + inFlight.add(flight); + continue; + } + } + if (pendingQueue.length === 0 && commitQueue.length === 0 && inFlight.size === 0) return; + await signal; + } + } finally { + driving = false; + wake = void 0; + } + })(); + return driverRun; + }; + /** Every dispatch settled AND committed; nothing can start (the run is aborted at call time). */ + const drainDispatches = async () => { + await drive(); + while (logWork.size > 0) await Promise.allSettled([...logWork]); + }; + const runOver = () => runController.signal.aborted; + const binding = (name) => async (rawArgs) => { + if (runOver()) throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} not dispatched`); + const normalized = jsonNormalizeArgs(rawArgs); + const n = ++dispatches; + const subCallId = CallId(`${String(exec.callId)}:code:${n}`); + const input = { + callId: subCallId, + rootCallId: exec.rootCallId, + name, + arguments: normalized.dispatched, + ...exec.agent ? { agent: exec.agent } : {}, + parent: exec.token, + signal: runController.signal + }; + const scheduler = registry[TOOL_RUNTIME_SCHEDULER]; + const outcome = await new Promise((resolve, reject) => { + let parked; + const settle = (result) => { + resolve(result.isError ? { + isError: true, + message: result.error.message + } : { + isError: false, + value: result.value + }); + const agent = exec.agent; + if (agent === void 0) return; + const task = (async () => { + const logged = await shapeDispatchLog({ + exec, + agent, + subCallId, + name, + isError: result.isError, + content: result.content + }); + agent.session.append("tool/code-dispatch", { + rootCallId: exec.rootCallId, + parentCallId: exec.callId, + subCallId, + name, + arguments: normalized.logged, + isError: result.isError, + content: logged + }); + })().finally(() => { + logWork.delete(task); + }); + logWork.add(task); + }; + pendingQueue.push({ + flight: Promise.resolve(), + settled: false, + classify: () => registry.executionMode(input).kind, + abandon: () => { + reject(/* @__PURE__ */ new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} tool call abandoned`)); + }, + async start() { + exec.agent?.session.append("tool/code-dispatch-start", { + rootCallId: exec.rootCallId, + parentCallId: exec.callId, + subCallId, + name, + arguments: normalized.logged + }); + const prepared = await scheduler.prepare(input); + if (prepared.kind === "dispatch") { + this.flight = scheduler.dispatch(prepared.exec).then((dispatchOutcome) => { + parked = { + kind: dispatchOutcome.kind, + exec: prepared.exec, + result: dispatchOutcome.result + }; + this.settled = true; + }); + return; + } + parked = { + kind: prepared.kind, + exec: prepared.exec, + result: prepared.result + }; + this.settled = true; + }, + async commit() { + /* v8 ignore next -- commit() runs only after `settled` flipped, which set parked. */ + if (parked === void 0) return; + const result = parked.kind === "post-result" ? await scheduler.finalize(parked.exec, parked.result) : scheduler.finish(parked.exec, parked.result); + if (!result.isError && result.content.some((block) => block.type === "image")) exec.deferContext(createUserMessage({ + content: result.content, + source: { + kind: "plugin", + plugin: "tools-code-mode" + } + })); + for (const context of result.additionalContexts ?? []) exec.deferContext(context); + if (result.concludesTurn) exec.concludeTurn(); + settle(result); + while (logWork.size > maxParallel) await Promise.race(logWork); + } + }); + wakeup(); + drive(); + }); + if (runOver()) throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} result discarded`); + if (outcome.isError) throw new Error(outcome.message); + return outcome.value; + }; + const functions = Object.create(null); + for (const schema of registry.schemas(exec.agent)) { + if (schema.name === "run_code") continue; + Object.defineProperty(functions, schema.name, { + enumerable: true, + value: binding(schema.name) + }); + } + try { + let result; + try { + result = await runtime.run({ + program: args.code, + bindings: [{ + global: "tools", + functions, + errorClass: { + name: "ToolCallError", + memberNameProperty: "toolName" + } + }], + signal: runController.signal + }); + } finally { + runController.abort("run_code settled"); + await drainDispatches(); + } + if (result.error) { + const logsText = result.logs.length > 0 ? `\nCaptured output:\n${result.logs.join("\n")}` : ""; + throw new CodeRunFailedError(`code run failed (${result.error.kind}): ${result.error.message}${logsText}`); + } + return { + logs: result.logs, + ...result.value !== void 0 ? { result: result.value } : {} + }; + } finally { + exec.signal.removeEventListener("abort", onOuterAbort); + } + }, + presentCall: (args) => ({ + card: "generic", + title: args.description, + kind: "execute", + rawInput: args.code + }) + }); + Object.defineProperty(definition, "description", { + enumerable: true, + get: () => resolveFlavor(peekRuntime).description + }); + Object.defineProperty(definition, "parameters", { + enumerable: true, + get: () => parameterSchemaSpecToJsonSchema({ + code: { + type: "string", + required: true, + description: resolveFlavor(peekRuntime).codeDescription + }, + description: { + type: "string", + required: true, + description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION + } + }) + }); + return definition; +} +//#endregion +//#region lib/types/ts-types.js +/** +* Code Mode codegen: the pure projection from registered tool schemas to the TypeScript SDK +* text the model programs against (the `tools:sdk` prompt section). Sibling of +* `json-schema.ts` — `schemas()` (native function calling) and this module (the generated +* `declare const tools` API) are two projections of the same store. +* @module @deepseek-ai/dsh-tools/src/ts-types +*/ +/** Property names that are valid bare TS identifiers; anything else is quoted. */ +const IDENTIFIER$1 = /^[A-Za-z_$][A-Za-z0-9_$]*$/; +/** Render an object key: bare when it is a valid identifier, quoted otherwise (every name stays reachable, no aliasing). */ +function renderKey(name) { + return IDENTIFIER$1.test(name) ? name : JSON.stringify(name); +} +/** One `indent`-deep line prefix (two spaces per level). */ +function pad$1(indent) { + return " ".repeat(indent); +} +/** A one-line JSDoc block for a schema `description`, or no lines when there is none. */ +function docLines$1(description, indent) { + if (typeof description !== "string" || description.length === 0) return []; + const collapsed = description.replace(/\s+/g, " ").trim(); + return [`${pad$1(indent)}/** ${collapsed.replaceAll("*/", String.raw`*\/`)} */`]; +} +/** Render one scalar already validated by the unified schema boundary. */ +function renderScalar(value) { + return JSON.stringify(value); +} +/** Render a validated scalar `const`/`enum`, falling back to the broad type. */ +function renderConstrainedScalar$1(node, type) { + const broad = type === "integer" ? "number" : type; + if (Object.hasOwn(node, "const")) return renderScalar(node.const); + if (Object.hasOwn(node, "enum")) return node.enum.map(renderScalar).join(" | "); + return broad; +} +/** Build one document from captured parts while retaining the legacy array-parenthesization test. */ +function typeDocumentFrom(parts) { + return { + parts, + containsUnionOrIntersection: parts.some((part) => typeof part === "string" ? part.includes("|") || part.includes("&") : part.containsUnionOrIntersection) + }; +} +/** Build a small document without an intermediate array at each call site. */ +function typeDocument(...parts) { + return typeDocumentFrom(parts); +} +/** Flatten a nested document with an explicit work stack. */ +function flattenTypeDocument(document) { + const chunks = []; + const tasks = [document]; + for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) { + if (typeof task === "string") { + chunks.push(task); + continue; + } + for (let index = task.parts.length - 1; index >= 0; index--) { + const part = task.parts[index]; + /* v8 ignore next -- the loop is bounded by the captured part count. */ + if (part !== void 0) tasks.push(part); + } + } + return chunks.join(""); +} +/** Initialize one schema-render frame with empty aggregation state. */ +function schemaRenderFrame(node, indent) { + return { + node, + indent, + phase: "start", + children: [], + childIndex: 0, + childDocuments: [], + entries: [] + }; +} +/** Render an already asserted schema to a composable document. */ +function renderSupportedSchema(schema, indent) { + const frames = [schemaRenderFrame(schema, indent)]; + let rootDocument; + const finish = (document) => { + frames.pop(); + const parent = frames.at(-1); + if (parent === void 0) rootDocument = document; + else parent.childDocuments.push(document); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === void 0) break; + if (frame.phase === "children") { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === void 0) throw new Error("missing schema render child"); + frame.childIndex++; + frames.push(schemaRenderFrame(child.node, child.indent)); + continue; + } + if (frame.kind === "oneOf") { + const parts = []; + for (let index = 0; index < frame.childDocuments.length; index++) { + if (index > 0) parts.push(" | "); + const child = frame.childDocuments[index]; + /* v8 ignore next -- child documents correspond one-to-one with children. */ + if (child !== void 0) parts.push(child); + } + finish(typeDocumentFrom(parts)); + continue; + } + if (frame.kind === "array") { + const child = frame.childDocuments[0]; + /* v8 ignore next -- array frames always schedule exactly one child. */ + if (child === void 0) throw new Error("missing array item type"); + finish(child.containsUnionOrIntersection ? typeDocument("(", child, ")[]") : typeDocument(child, "[]")); + continue; + } + const required = new Set(frame.node.required); + const parts = ["{"]; + for (let index = 0; index < frame.entries.length; index++) { + const entry = frame.entries[index]; + const child = frame.childDocuments[index]; + /* v8 ignore next -- object entries and child documents have the same length. */ + if (entry === void 0 || child === void 0) throw new Error("missing object property type"); + const [name, prop] = entry; + for (const line of docLines$1(prop.description, frame.indent + 1)) parts.push("\n", line); + parts.push("\n", `${pad$1(frame.indent + 1)}${renderKey(name)}${required.has(name) ? "" : "?"}: `, child, ";"); + } + parts.push("\n", `${pad$1(frame.indent)}}`); + const declared = typeDocumentFrom(parts); + finish(frame.node.additionalProperties === false ? declared : typeDocument(declared, " & Record")); + continue; + } + const node = frame.node; + if (node.oneOf !== void 0) { + frame.kind = "oneOf"; + frame.children = Array.from(node.oneOf, (child) => ({ + node: child, + indent: frame.indent + })); + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = "children"; + continue; + } + if (node.type === void 0) { + finish(typeDocument("JsonValue")); + continue; + } + switch (node.type) { + case "string": + case "number": + case "integer": + case "boolean": + case "null": + finish(typeDocument(renderConstrainedScalar$1(node, node.type))); + break; + case "array": + if (node.items === void 0) finish(typeDocument("JsonValue[]")); + else { + frame.kind = "array"; + frame.children = [{ + node: node.items, + indent: frame.indent + }]; + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = "children"; + } + break; + case "object": { + const open = node.additionalProperties !== false; + const entries = Object.entries(node.properties ?? {}); + if (entries.length === 0) finish(typeDocument(open ? "Record" : "Record")); + else { + frame.kind = "object"; + frame.entries = entries; + frame.children = entries.map(([, child]) => ({ + node: child, + indent: frame.indent + 1 + })); + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = "children"; + } + break; + } + /* v8 ignore next -- assertSupportedJsonSchema narrowed this closed type union. */ + default: finish(typeDocument("unknown")); + } + } + /* v8 ignore next -- every root frame produces one document. */ + return rootDocument ?? typeDocument("unknown"); +} +/** +* Map one enforced JSON-Schema node to a TypeScript type literal. Supports +* every unified schema construct and returns `unknown` for malformed or +* unsupported inputs without throwing. +* @param schema - the JSON-Schema node (any shape; hostile inputs degrade). +* @param indent - the indentation level for nested object members. +* @returns the TS type text (multi-line for objects with properties). +*/ +function jsonSchemaToTs(schema, indent = 0) { + try { + assertSupportedJsonSchema(schema); + return flattenTypeDocument(renderSupportedSchema(schema, indent)); + } catch { + return "unknown"; + } +} +/** The fixed model-facing usage contract rendered above the declarations (see the Code Mode Agent Note's "What the model sees"). */ +const SDK_INSTRUCTIONS$1 = `## Writing code for run_code + +\`run_code\` takes two required arguments: \`code\` — the body of an async TypeScript function (erasable syntax only — no \`enum\` or namespaces; type annotations are advisory, the code runs type-stripped) — and \`description\`, a short summary of what the program does. Inside the program: + +- Call tools as \`await tools.name(args)\` — quoted access for exotic names: \`tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose \`message\` is human-readable — \`try/catch\` it to handle and continue. +- Independent read-only calls MAY overlap under \`Promise.all\` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with \`await\`. +- Emit results with \`return\` and/or \`console.log(...)\`. Only what you print or return is program output. A successful tool result containing an image is attached after the run so you can inspect it on the next step; every other intermediate result stays out of the conversation, so extract just what you need. + +The available tools:`; +/** +* Render the full `tools:sdk` prompt section: the fixed usage instructions +* plus one `declare const tools` interface covering every given tool. +* Deterministic — tools are emitted in lexicographic name order, so an +* unchanged tool set produces byte-identical text across assemblies. The sort +* is not a total order on byte-equal names, so two schemas sharing a name +* would render in argument order; the caller's visible-capability map is keyed +* by name, so the input never carries a duplicate. +* @param schemas - the tool schemas to declare (the caller excludes +* `run_code` itself). +* @returns the complete section text. +*/ +function renderToolsSdk(schemas) { + const sorted = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0); + const argsMembers = []; + const outputMembers = []; + for (const schema of sorted) { + argsMembers.push(...docLines$1(schema.description, 1)); + argsMembers.push(`${pad$1(1)}${renderKey(schema.name)}: ${jsonSchemaToTs(schema.parameters, 1)};`); + outputMembers.push(`${pad$1(1)}${renderKey(schema.name)}: ${jsonSchemaToTs(schema.output, 1)};`); + } + return `${SDK_INSTRUCTIONS$1}\n\n\`\`\`ts\ntype JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue }\n\n${[ + `interface ToolArgsMap {${argsMembers.length > 0 ? `\n${argsMembers.join("\n")}\n` : ""}}`, + `interface ToolOutputMap {${outputMembers.length > 0 ? `\n${outputMembers.join("\n")}\n` : ""}}`, + "type ToolName = keyof ToolOutputMap", + [ + "declare class ToolCallError extends Error {", + " readonly name: \"ToolCallError\";", + " readonly toolName: ToolName;", + "}" + ].join("\n"), + [ + "declare const tools: {", + " [K in ToolName]: (args: ToolArgsMap[K]) => Promise;", + "}" + ].join("\n") + ].join("\n\n")}\n\`\`\``; +} +//#endregion +//#region lib/types/py-types.js +/** +* Code Mode codegen — Python flavor. The pure projection from registered tool schemas to the +* Python SDK text the model programs against under `runtime.language === 'python'`. Sibling of +* {@link ./ts-types.ts | ts-types.ts}; the two files are two projections of the same registry +* store, keyed by the loaded {@link @deepseek-ai/dsh-code-runtime#CodeRuntime.language | code +* runtime's language}. +* +* Under `mode: 'code'` the native tool schemas are omitted from the request, so this generated +* SDK is the model's ONLY source for each tool's argument names, required fields, types, +* descriptions, and canonical output shapes; under `mode: 'both'` the native schemas ship +* alongside it and it is one of two. Object-shaped arguments and outputs therefore render as one +* named `TypedDict` per tool (and per nested object), not an opaque `dict[str, Any]`, so the +* shape survives into the program under the mode that has nothing else to carry it. +* @module @deepseek-ai/dsh-tools/src/py-types +*/ +/** +* The reference grammar's `xid_start xid_continue*` — the set +* `str.isidentifier()` accepts on a CPython whose Unicode tables match the +* engine's. See {@link isBareIdentifier} for what a version skew does. +*/ +const IDENTIFIER = /^[\p{XID_Start}_]\p{XID_Continue}*$/u; +/** +* Whether a name can be emitted as a bare Python identifier rather than +* routed to the subscript/`dict[str, Any]` path. +* +* Python identifiers are not ASCII: `路径` is as legal a field name as `path`, +* and rejecting it would degrade the whole enclosing object, dropping every +* field's name, requiredness, and type — information whose only source under +* `mode: 'code'` is this generated text. +* +* NFKC stability is a second and separate condition, because CPython +* normalizes identifiers at compile time while JSON keys are compared as +* written: `field` would be declared and reachable as `field`, so the SDK would +* advertise a key under a spelling the harness never accepts, and two keys +* that normalize together would collapse into one declaration. Those names +* take the subscript path, which carries their exact bytes. +* +* `IDENTIFIER` matches `str.isidentifier()` (measured on Node 22.23.1 vs +* CPython 3.9.6 tables): the equivalence holds inside the two versions' shared +* tables, and the skew characters below are exactly where that pair diverges. +* The predicate as a whole is deliberately stricter than `isidentifier()`, +* which does not test NFKC stability: `'field'.isidentifier()` is True and +* this returns false. +* +* Both conditions are evaluated against the ENGINE's Unicode tables, and the +* two sides are versioned independently — `\p{XID_Start}`/`\p{XID_Continue}` +* follow the running engine (Node 22.23.1 reports Unicode 17.0) while CPython +* follows its own (3.9.6 reports 13.0.0). The skew is not symmetric. A CPython +* older than the engine is the dangerous direction: a character added to either +* property since its tables (U+10570 Vithkuqi and U+1E290 Toto, 14.0; U+1E4D0 +* Nag Mundari, 15.0; U+1C89 Cyrillic TJE, 16.0 — ages per `DerivedAge.txt`; all +* four are NFKC-stable and accepted here, and all four are `Cn` on that 3.9.6, +* which rejects them) is emitted bare and its tokenizer refuses the character, +* taking the whole SDK block down — the same parseability invariant +* {@link UNPRINTABLE}, {@link LONE_SURROGATE} and {@link MAX_LIST_NESTING} +* exist for. Both properties carry it: a character added only to `XID_Continue` +* passes the trailing `\p{XID_Continue}*` in a tail position and fails the same +* way — U+200C ZWNJ and U+200D ZWJ are that case, gaining `XID_Continue` in UCD +* 15.1 and absent from it in 13.0.0, 14.0.0 and 15.0.0, so `a\u{200C}b` is +* emitted bare here while `isidentifier()` is False on 3.9.6 and on 3.12.13 +* (15.0.0). A CPython newer than the engine only routes a legal name to the +* subscript/`dict[str, Any]` path: less readable, still correct. The NFKC +* condition reduces to the same skew, since normalization stability guarantees +* an assigned character's normalization never changes afterwards. +* +* This predicate is not the only reader of engine tables. {@link camelCase} +* reads them at three further points — its split set, its head test, and its +* `toUpperCase()` case mapping — and this predicate's verdict gates none of +* them: a class name derived there reaches emitted text whenever any object +* shape in the tool's schema declares a `TypedDict`, including for a tool this +* predicate rejected. A tool named `zz-\u{1E4D0}x` with such parameters never +* reaches the skew here (the `-` rejects it outright) yet emits `class +* Zz\u{1E4D0}xArgs`, which that same 3.9.6 refuses — Nag Mundari arrived two +* releases after its tables. The case mapping is a separate table rather than +* an XID membership test, and it fails on names both conditions above accept: +* `\u{019B}` is XID_Start and NFKC-stable, so this predicate accepts it and +* `async def \u{019B}` compiles on 3.9.6, but Node uppercases it to +* `\u{A7DC}` — unassigned in that CPython, whose own `.upper()` is the identity +* here — and the declared `class \u{A7DC}Args` fails with `invalid +* non-printable character U+A7DC`. Closing the exposure therefore covers all +* four read points, not this predicate alone; it needs the target interpreter's +* version, which the backend reporting `language: 'python'` owns; the +* language-dispatch Agent Note records the deferral. +* +* The `ts-types` sibling keeps its own ASCII rule rather than sharing this +* one: ECMAScript identifiers are a different set (`$`) and are never +* normalized, so one predicate cannot be correct for both. ZWJ/ZWNJ are not +* part of that difference — both sets carry them on the engine's tables; what +* separates the two there is the CPython table version above. +* @param name - the raw schema field or tool name. +* @returns whether the name can be emitted bare. +*/ +function isBareIdentifier(name) { + return IDENTIFIER.test(name) && name.normalize("NFKC") === name; +} +/** +* Python hard keywords: reserved everywhere, so a tool or field named +* ``class`` or ``lambda`` is legal on the wire but not as an attribute +* (``tools.class`` would be a SyntaxError in the model program) and not as a +* class-syntax `TypedDict` field. Such a tool renders under subscript access +* and such an object degrades to ``dict[str, Any]`` — the model still reaches +* every tool and field without collisions. +* Soft keywords (``match``, ``case``, ``type``, ``_`` — the language +* reference's whole set) are deliberately ABSENT: each is special in exactly +* one syntactic position — a statement head (``match``, ``type``), a ``match`` +* statement's clause head (``case``), or a pattern (``_``) — so ``match: str`` +* as a field and ``async def match(...)`` as a method are both legal, and +* including them would needlessly degrade common search/regex tool fields to +* ``dict[str, Any]``. Underscore-leading names are handled separately, not +* here: a non-dunder ``__token`` name-mangles, a dunder present on +* ``object``/``type`` resolves before the proxy hook, and implicit +* special-method lookup bypasses the hook. +*/ +const RESERVED = new Set([ + "False", + "None", + "True", + "and", + "as", + "assert", + "async", + "await", + "break", + "class", + "continue", + "def", + "del", + "elif", + "else", + "except", + "finally", + "for", + "from", + "global", + "if", + "import", + "in", + "is", + "lambda", + "nonlocal", + "not", + "or", + "pass", + "raise", + "return", + "try", + "while", + "with", + "yield", + "__debug__" +]); +/** `typing` symbols this module may emit, in the deterministic import order. */ +const TYPING_ORDER = [ + "Any", + "Literal", + "NotRequired", + "Protocol", + "TypedDict" +]; +/** `indent`-deep line prefix (four spaces per level to match PEP 8 output). */ +function pad(indent) { + return " ".repeat(indent); +} +/** +* The `Cc` code points that survive the whitespace collapse in {@link describe} +* and have no printable form: the C0 controls, DEL, and the C1 controls. Only +* U+0009 to U+000D are absent, because ECMAScript `\s` already collapsed them — +* `\s` is TAB/VT/FF/SP/NBSP/ZWNBSP/Zs plus LF/CR/LS/PS, so no C1 code point is +* in it and the whole U+0080 to U+009F block reaches this rule intact. Those +* are not hypothetical input: they are what Windows-1252 bytes 0x80 to 0x9F +* (smart quotes, em dash) become when decoded as Latin-1. +* CPython rejects source containing a NUL outright +* (`SyntaxError: source code string cannot contain null bytes`), whether it +* sits in a docstring or in a comment, so one such byte anywhere in a schema +* description would make the whole generated SDK unparseable — under +* `mode: 'code'`, the model's only declaration of the tools. The rest are +* legal but invisible; escaping them with the same rule keeps the emitted text +* readable and the treatment uniform. +* +* The boundary is the category, not per-code-point addressability: `\xNN` +* addresses U+0000 to U+00FF, so one escape form covers `Cc` exactly. The +* invisible `Cf` formatting characters pass through by design — of them only +* U+00AD soft hyphen would fit `\xNN` at all, and escaping that one while +* U+200B ZWSP, U+200E/U+200F bidi marks, and U+2060 word joiner passed through +* would leave a rule that is neither category- nor addressability-shaped. The +* whole family is legal in both consumers, since only LF and CR terminate a +* Python string literal or a `#` comment. That set is the tokenizer's, not +* `str.splitlines()`': NEL (U+0085), LS (U+2028), and PS (U+2029) split a +* string at run time but do not end a physical line in source — measured on +* CPython 3.9.6 and 3.12.13, each accepted in both positions with the value +* round-tripping — so they are safe raw wherever they reach emitted text +* unescaped, which for all three is `JSON.stringify`, at two call sites: +* {@link pyScalar}'s literal path, and the subscript tool-name comment's own +* call, which a name carrying any of them always reaches, none being +* `XID_Continue`. The `description` path escapes NEL under the class above and +* folds LS and PS in {@link describe}'s `\s+` collapse, both being `\s`. +*/ +const UNPRINTABLE = /[\u0000-\u0008\u000e-\u001f\u007f-\u009f]/g; +/** +* Unpaired surrogate code points, escaped by {@link describe} as `\uNNNN` — +* its own form, since `\xNN` stops at U+00FF. The `u` flag is what makes this +* the LONE ones: in Unicode mode a well-formed pair is a single astral code +* point outside D800 to DFFF, so an emoji in a description survives untouched. +* +* This is the NUL case from {@link UNPRINTABLE}, not the invisible-character +* case. Python source must be UTF-8-encodable and a lone surrogate is not, so +* `compile()` raises `UnicodeEncodeError: surrogates not allowed` for one +* anywhere in the text — measured on 3.9 for a string literal and for a `#` +* comment alike. A raw or MCP tool description reaches this: `JSON.parse` on a +* wire `"\ud800"` escape yields exactly such a code point. +*/ +const LONE_SURROGATE = /[\ud800-\udfff]/gu; +/** +* The collapsed one-line `description` of a schema node (byte-stable across +* formatting churn), or `undefined` when the node carries none. Every caller +* passes an object — a validated property node, the `ToolSdkSchema` itself, or +* the `{ description }` wrapper {@link docLines} synthesizes — so only the +* description field needs guarding. A description that collapses +* to nothing (empty, or whitespace only) is `undefined` too: it documents the +* node no better than an absent one, and emitting it would leave an empty +* `"""` docstring or a bare `# ` line in the SDK. Only ECMAScript whitespace +* folds, so a description of whitespace plus one surviving control character is +* NOT absent: it collapses to that character's visible escape. +* +* Control characters left over after the whitespace collapse are rendered as +* their `\xNN` escapes (see {@link UNPRINTABLE}) and unpaired surrogates as +* their `\uNNNN` escapes (see {@link LONE_SURROGATE}); the escape's own backslash is +* emitted literally by both consumers, since {@link docLines} doubles it into a +* Python source escape and a `#` comment carries it verbatim. +*/ +function describe(schema) { + const description = schema.description; + if (typeof description !== "string") return void 0; + const collapsed = description.replace(/\s+/g, " ").replace(UNPRINTABLE, (char) => `\\x${char.charCodeAt(0).toString(16).padStart(2, "0")}`).replace(LONE_SURROGATE, (char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`).trim(); + return collapsed.length === 0 ? void 0 : collapsed; +} +/** +* One-line docstring for a tool `description`, or no lines when there is none. +* Backslashes are doubled first, every quote is escaped, and a trailing +* backslash cannot survive: a description ending in `"` or an odd backslash +* would otherwise merge with (or escape) the closing triple quote and make +* the generated block — Code Mode's only SDK — syntactically invalid Python. +*/ +function docLines(description, indent) { + const collapsed = describe({ description }); + if (collapsed === void 0) return []; + const escaped = collapsed.replaceAll("\\", "\\\\").replaceAll("\"", "\\\""); + return [`${pad(indent)}"""${escaped}"""`]; +} +/** +* CamelCase a name into a Python type identifier: non-identifier characters +* split words, `_` splits too (it is `XID_Continue`, so the split set names it +* explicitly), and a head that cannot start an identifier takes a `Tool` +* prefix. Unicode survives, so a `路径` field yields `路径`-based class names +* instead of collapsing to the bare prefix. A character that is not +* `XID_Continue` splits even when it is a letter, so a name whose NFKC folding +* would leave the identifier set is not carried through — the split set is the +* grammar's, not an ASCII approximation of it. +* +* The result is NFKC-normalized: these names are generated, never matched +* against a JSON key, so normalizing is free here and keeps what CPython +* compiles identical to what is emitted — unlike {@link isBareIdentifier}, +* which must reject unstable names outright. Normalizing AFTER the prefix +* decision is what makes that hold at the seam the prefix creates: `Tool` + +* a combining-mark head composes there (`U+0301` gives `Tooĺ`, U+013A), so +* normalizing only the un-prefixed part would emit a name CPython compiles to +* a different symbol. The second call is idempotent on the un-prefixed arm. +* +* The split set, the head test, and `toUpperCase()` all read the engine's +* Unicode tables, so this function carries the same version skew +* {@link isBareIdentifier} documents, by paths independent of it: a class name +* derived here reaches emitted text whenever any object shape in the tool's +* schema declares a `TypedDict`, and the predicate's verdict on the tool name +* does not gate that. The case mapping is the one that can fail on a name the +* predicate accepted; the worked example is there. +* @param raw - the schema field or tool name to derive from. +* @returns a class-name segment safe to emit. +*/ +function camelCase(raw) { + const joined = raw.split(/[^\p{XID_Continue}]+|_+/u).filter((part) => part.length > 0).map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join("").normalize("NFKC"); + return (/^\p{XID_Start}/u.test(joined) ? joined : `Tool${joined}`).normalize("NFKC"); +} +/** Class-name base cap keeping each emitted name — and total text — linear in schema depth. */ +const MAX_CLASS_NAME_BASE = 120; +/** +* Deepest `list[…]` nesting emitted into one annotation before the item type +* degrades to `Any`. CPython's tokenizer rejects a logical line holding more +* than 200 simultaneously-open brackets (`MAXLEVEL`, `SyntaxError: too many +* nested parentheses`), so an array chain deeper than that would render an SDK +* block that is not valid Python at all — the same failure the docstring +* escaping in {@link docLines} exists to prevent. 180 leaves headroom for the +* few brackets an annotation can add around the chain, all of which count +* toward the same limit. Per emission site, counting brackets open at the +* chain's innermost point: +* +* - Return annotation, `async def f(self, args: X) -> chain:` — 180 `list[` +* plus an innermost `Literal[`. The parameter list's `(` closed at the `)` +* before the `->`, so it is NOT open here: 181. +* - TypedDict field, `field: NotRequired[chain]` — a class-body line with no +* other open bracket, and its children start at `listDepth: 1` to reserve +* the `NotRequired[`, so 179 `list[` plus `Literal[`: 181. Required fields +* share that start for uniformity, spending one level of representable depth +* on a bracket they never emit. +* - Argument annotation, `async def f(self, args: chain) -> Y:` — the `(` IS +* still open around it: 180 `list[` plus `Literal[` plus the paren, 182, the +* worst case. Reachable only through a raw `register()` whose `parameters` +* is an array reached from the root through `oneOf` arms alone — the root +* array itself, or one nested under any depth of unions, since an arm +* inherits the enclosing depth unchanged (`A | B` opens no bracket). An +* object ancestor takes it out of this case: its fields restart the chain at +* the 181 site. `defineTool` compiles an object root, so the annotation is a +* bare TypedDict class name or a one-bracket `dict[str, Any]` when that +* object degrades — never a chain. +* +* A CPython grammar limit, not a deployment choice, so it is fixed rather than +* configurable. The sibling `ts-types` renderer needs no counterpart: nothing +* in the TypeScript grammar bounds nesting, and its SDK block is never type- +* checked. Only bracket nesting counts — a `oneOf` renders as a flat `A | B` +* chain and nested objects render as separate `class` statements, so neither +* accumulates open brackets at any depth. The invariant this cap serves is +* grammatical validity; see the `oneOf` arm in {@link renderType} for the one +* interpreter limit deliberately left uncapped. +*/ +const MAX_LIST_NESTING = 180; +/** +* Cap a class-name base at {@link MAX_CLASS_NAME_BASE} (see the callers for +* why capping keeps the render linear). `slice` counts UTF-16 code units, so +* an astral character straddling the boundary would be cut in half and leave a +* lone surrogate — not an identifier character, and not even well-formed text; +* drop it rather than emit it. +*/ +function capClassNameBase(base) { + if (base.length <= MAX_CLASS_NAME_BASE) return base; + const capped = base.slice(0, MAX_CLASS_NAME_BASE); + return /[\uD800-\uDBFF]$/.test(capped) ? capped.slice(0, -1) : capped; +} +/** +* Reserve a unique class name from a base, suffixing `2`, `3`, … on collision. +* The base is capped at {@link MAX_CLASS_NAME_BASE} first: child class names +* derive from their parent's allocated name (`ParentChild`), so an unbounded +* schema of single-field objects would otherwise grow each name by one field +* per level and the sum of all names to Θ(depth²). Capping the base keeps each +* name — and the total emitted text — linear in depth. Collisions resume from +* the per-base counter in `state.nextClassCounter` rather than rescanning from +* `2`, so a deep chain sharing one capped base stays O(1) per allocation +* (amortized) instead of Θ(depth²) in time. +*/ +function allocateClassName(base, state) { + const capped = capClassNameBase(base); + let name = capped; + if (state.usedClassNames.has(name)) { + let n = state.nextClassCounter.get(capped) ?? 2; + while (state.usedClassNames.has(`${capped}${n}`)) n++; + name = `${capped}${n}`; + state.nextClassCounter.set(capped, n + 1); + } + state.usedClassNames.add(name); + return name; +} +/** +* Append a child-name segment to a parent class-name base, capping the result +* at {@link MAX_CLASS_NAME_BASE}. Capping AT PROPAGATION (not only inside +* {@link allocateClassName}) keeps each level O(1): a deep `oneOf`- or +* object-chain would otherwise carry an ever-growing ConsString down the tree +* and re-materialize it (via `.length`/`.slice`) at every level — Θ(depth²). +* The bounded base plus the collision counter still yields unique names. +* +* The join is NFKC-normalized because both sides are separately normalized yet +* their concatenation need not be: a base ending in a Hangul L jamo or LV +* syllable composes with a following V or T jamo head (`가` + `ᆨ` gives `각`), +* so the emitted class name would differ from the symbol CPython compiles, and +* two byte-distinct names could fold onto one — `usedClassNames` dedupes by the +* raw bytes, so the collision counter would not see it. Normalizing costs +* O(cap + segment) per level, the same order as the `slice` it feeds. The other +* two join points need no counterpart: `Args`/`Output` start with `A`/`O` and +* {@link allocateClassName}'s suffix is digits, none of which compose backwards. +*/ +function childClassName(base, segment) { + return capClassNameBase(`${base}${segment}`.normalize("NFKC")); +} +/** +* Render one validated scalar as Python literal text (`True`/`False`, +* JSON-quoted strings, bare numbers). `null` cannot reach here: the `null` +* type renders directly as `None`, and the unified validator rejects a null +* `const`/`enum` entry on every other scalar type. +* +* A beyond-safe-range integral number takes `BigInt` digits rather than +* `String`: Python integers are arbitrary-precision, so the emitted digits ARE +* the value the model programs against, and `String` can give a different +* integer than the double holds (`2 ** 60` prints the rounded `...847000`, not +* the exact `...846976`) or no integer literal at all (`1e21` prints `1e+21`). +* `String`'s rounding is not a bug in it: `Number::toString` emits the shortest +* decimal string that re-reads to the same double, then pads to the exponent +* with zeros (1 significant digit for `1e20`, 16 for `2 ** 60`) — and when the +* shortest string is shorter than the double's exact value, those padded digits +* name an integer no double holds. Passing one back would have to cross the +* argument boundary as a JSON number — a double again — so the SDK would +* document a value no program can pass. `BigInt` needs no case split: where +* `String` is already exact (`2 ** 53`, `1e20`) the two agree byte for byte, +* and where it is not, `BigInt` is the exact one. The TS flavor needs no +* counterpart at all: its literal is re-read by a JS parser back into the same +* double. +* +* `JSON.stringify` is also what keeps this path's output parseable, and it is +* the only thing that does. It covers both classes of hazard: the two kinds of +* code point CPython refuses anywhere in source — NUL among the C0 controls, +* and the whole D800–DFFF unpaired-surrogate block, escaped under ES2019 +* well-formed stringification, which the engines range guarantees — and the +* ones that break this line in particular, a bare `"` closing the literal +* early, a trailing odd backslash eating the closing quote, and a bare LF/CR +* ending it before its terminator. The `description` path carries +* {@link UNPRINTABLE} and {@link LONE_SURROGATE} because nothing quotes it, +* and folds newlines in {@link describe}. +* +* That leans on a coincidence worth naming: every escape `JSON.stringify` can +* emit (`\"`, `\\`, `\b`, `\f`, `\n`, `\r`, `\t`, `\uXXXX`) is also a Python +* escape denoting the same character, so the emitted `Literal[...]` both +* parses and decodes back to the value the schema declared. DEL, the C1 +* controls (NEL among them), and LS/PS (U+2028/U+2029) do reach it raw — +* legal but invisible, byte-for-byte as in the TS flavor; escaping them is a +* both-flavors change. Those last three are legal here for the reason +* {@link UNPRINTABLE} records: they are `str.splitlines()` boundaries, not +* tokenizer line terminators. The subscript tool-name comment quotes its name +* through its own call to the same `JSON.stringify`, never through this +* function, and inherits both halves — escapes and pass-throughs alike. +*/ +function pyScalar(value) { + if (value === true) return "True"; + if (value === false) return "False"; + if (typeof value === "string") return JSON.stringify(value); + if (typeof value === "number" && Number.isInteger(value) && !Number.isSafeInteger(value)) return BigInt(value).toString(); + return String(value); +} +/** +* Render a validated scalar `const`/`enum` as `Literal[...]`, falling back to +* the broad type. Deliberately deviates from PEP 586, which restricts `Literal` +* parameters to int/bool/str/bytes/enum/None: a non-integral number +* `const`/`enum` emits a float literal (`Literal[1.5]`) a strict checker would +* reject. An integral one does not deviate — {@link pyScalar} emits int digits, +* including for the beyond-safe-range values it widens through `BigInt`, and +* PEP 586 admits int parameters. Harmless either way — the stub is advisory +* prompt text, only required to parse — and keeping the exact value +* communicates the constraint to the model. +*/ +function renderConstrainedScalar(node, broad, state) { + if (node.const !== void 0) { + state.typing.add("Literal"); + return `Literal[${pyScalar(node.const)}]`; + } + if (node.enum !== void 0) { + state.typing.add("Literal"); + return `Literal[${node.enum.map(pyScalar).join(", ")}]`; + } + return broad; +} +/** +* Map one JSON-Schema node to a Python type expression, threading `state` to +* collect the `TypedDict` declarations and `typing` symbols a full render +* needs. `className` is the name to give an object node with properties (and +* the prefix for its nested objects). Handles every unified schema construct — +* `oneOf` (→ `X | Y`), `const`/`enum` (→ `Literal[...]`), `integer` (→ `int`), +* `null` (→ `None`) — and degrades an unsupported or malformed schema to `Any` +* without throwing, the same trusted-after-validation stance as the sibling +* {@link ./ts-types.ts | ts-types} renderer. {@link jsonSchemaToPy} is the +* context-free entry point; this is the collecting core. +*/ +function renderType(schema, className, state) { + const newFrame = (schema, className, listDepth) => ({ + schema, + className, + phase: "start", + listDepth, + children: [], + childIndex: 0, + childTypes: [], + entries: [] + }); + try { + assertSupportedJsonSchema(schema); + const frames = [newFrame(schema, className, 0)]; + let result; + const finish = (type) => { + frames.pop(); + const parent = frames.at(-1); + if (parent === void 0) result = type; + else parent.childTypes.push(type); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === void 0) break; + if (frame.phase === "children") { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === void 0) throw new Error("missing python render child"); + frame.childIndex++; + frames.push(newFrame(child.schema, child.className, child.listDepth)); + continue; + } + if (frame.kind === "oneOf") { + let union = ""; + for (const [index, childType] of frame.childTypes.entries()) union = index === 0 ? childType : `${union} | ${childType}`; + finish(union); + continue; + } + if (frame.kind === "array") { + /* v8 ignore next -- the ?? arm needs a childless array frame, which start never builds. */ + finish(`list[${frame.childTypes[0] ?? "Any"}]`); + continue; + } + const node = frame.node; + const name = frame.allocated; + /* v8 ignore next -- typeddict frames always set node and allocated at start. */ + if (node === void 0 || name === void 0) throw new Error("missing typeddict frame state"); + const required = new Set(node.required); + const lines = [`class ${name}(TypedDict):`]; + for (let index = 0; index < frame.entries.length; index++) { + const entry = frame.entries[index]; + const fieldType = frame.childTypes[index]; + /* v8 ignore next -- entries and childTypes correspond one-to-one. */ + if (entry === void 0 || fieldType === void 0) throw new Error("missing typeddict field type"); + const [field, fieldSchema] = entry; + const description = describe(fieldSchema); + if (description !== void 0) lines.push(`${pad(1)}# ${description}`); + if (required.has(field)) lines.push(`${pad(1)}${field}: ${fieldType}`); + else { + state.typing.add("NotRequired"); + lines.push(`${pad(1)}${field}: NotRequired[${fieldType}]`); + } + } + if (node.additionalProperties !== false) lines.push(`${pad(1)}# Additional keys beyond those declared are allowed.`); + if (lines.length === 1) lines.push(`${pad(1)}pass`); + state.classes.push(lines.join("\n")); + finish(name); + continue; + } + frame.phase = "children"; + const node = frame.schema; + if (node.oneOf !== void 0) { + frame.kind = "oneOf"; + frame.children = node.oneOf.map((branch, index) => ({ + schema: branch, + className: childClassName(frame.className, `${index + 1}`), + listDepth: frame.listDepth + })); + continue; + } + if (node.type === void 0) { + state.typing.add("Any"); + finish("Any"); + continue; + } + switch (node.type) { + case "string": + finish(renderConstrainedScalar(node, "str", state)); + break; + case "number": + finish(renderConstrainedScalar(node, "float", state)); + break; + case "integer": + finish(renderConstrainedScalar(node, "int", state)); + break; + case "boolean": + finish(renderConstrainedScalar(node, "bool", state)); + break; + case "null": + finish("None"); + break; + case "array": + if (node.items === void 0) { + state.typing.add("Any"); + finish("list[Any]"); + break; + } + if (frame.listDepth >= MAX_LIST_NESTING) { + state.typing.add("Any"); + finish("Any"); + break; + } + frame.kind = "array"; + frame.children = [{ + schema: node.items, + className: frame.className, + listDepth: frame.listDepth + 1 + }]; + break; + case "object": { + const entries = Object.entries(node.properties ?? {}); + if (className === "" || !entries.every(([name]) => isBareIdentifier(name) && !RESERVED.has(name) && !(name.startsWith("__") && !name.endsWith("__")))) { + state.typing.add("Any"); + finish("dict[str, Any]"); + break; + } + if (entries.length === 0 && node.additionalProperties !== false) { + state.typing.add("Any"); + finish("dict[str, Any]"); + break; + } + frame.kind = "typeddict"; + frame.node = node; + frame.allocated = allocateClassName(frame.className, state); + state.typing.add("TypedDict"); + frame.entries = entries; + /* v8 ignore next -- allocated is always set before children are built. */ + frame.children = entries.map(([field, child]) => ({ + schema: child, + className: childClassName(frame.allocated ?? "", camelCase(field)), + listDepth: 1 + })); + break; + } + /* v8 ignore next 4 -- assertSupportedJsonSchema narrowed this closed type union. */ + default: + state.typing.add("Any"); + finish("Any"); + } + } + /* v8 ignore next -- every root frame produces one expression. */ + return result ?? "Any"; + } catch { + state.typing.add("Any"); + return "Any"; + } +} +/** +* Map one JSON-Schema node to a context-free Python type expression from the +* `typing` module. Handles every unified schema construct — `object` (degraded +* to `dict[str, Any]`: naming a `TypedDict` requires the render context that +* {@link renderToolsSdkPy} supplies), `const`/`enum` (→ `Literal[...]`), +* `oneOf` (→ union), `string`/`number`/`integer`/`boolean`/`null`, `array` +* (`items` → `list[T]`) — and returns `Any` for an unsupported or malformed +* schema, matching the TS flavor's `unknown` fallback. Type annotations in the +* emitted SDK are advisory: Python does not enforce them at runtime. +* @param schema - the JSON-Schema node. +* @returns the Python type text. +*/ +function jsonSchemaToPy(schema) { + return renderType(schema, "", { + classes: [], + usedClassNames: /* @__PURE__ */ new Set(), + nextClassCounter: /* @__PURE__ */ new Map(), + typing: /* @__PURE__ */ new Set() + }); +} +/** The fixed model-facing usage contract rendered above the declarations. */ +const SDK_INSTRUCTIONS = `## Writing code for run_code + +\`run_code\` takes two required arguments: \`code\` — the body of an async Python function (top-level \`await\` and \`return\` both work) — and \`description\`, a short summary of what the program does. At run time exactly two of the names declared below are bound: \`tools\` and \`ToolCallError\`. Everything else is a STATIC STUB describing argument and return types — in particular the \`TypedDict\` classes do NOT exist at run time, so build arguments as plain \`dict\`/\`list\` JSON values: \`await tools.name({"field": 1})\`, never \`FooArgs(field=1)\`, which raises \`NameError\`. Inside the program: + +- Call tools as \`await tools.name(args)\` — subscript access for exotic, reserved, or underscore-leading names: \`await tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value (each method's return type below). Tool arguments must be lossless JSON. +- A FAILED tool call raises \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose message is human-readable — wrap in \`try/except\` to handle and continue. +- Independent read-only calls MAY overlap under \`asyncio.gather\` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with \`await\`. +- Emit the run's answer with \`print(...)\` and/or a top-level \`return \`; the returned value must be lossless JSON. Only what you print and return is program output. A successful tool result containing an image is attached after the run so you can inspect it on the next step; every other intermediate result stays out of the conversation, so extract just what you need. + +The available tools:`; +/** +* Render the full `tools:sdk` prompt section under `runtime.language === +* 'python'`: the Python-flavored usage instructions plus one named `TypedDict` +* per tool argument or output object (and per nested object) and one awaitable +* method per visible tool on a `Tools` protocol — typed args in, the tool's +* canonical output value out — with a `tools: Tools` singleton the model calls +* into. The `typing` import line lists exactly the symbols the render used. +* Deterministic — tools are emitted in lexicographic name order, and class +* declarations precede the protocol in that same order (nested classes before +* the parent that references them), so an unchanged tool set produces +* byte-identical text across assemblies. The sort is not a total order on +* byte-equal names, so two schemas sharing a name would render in argument +* order; the caller's visible-capability map is keyed by name, so the input +* never carries a duplicate. +* @param schemas - the tool schemas plus canonical output schemas to declare +* (the caller excludes `run_code` itself). +* @returns the complete section text. +*/ +function renderToolsSdkPy(schemas) { + const sorted = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0); + const state = { + classes: [], + usedClassNames: /* @__PURE__ */ new Set(), + nextClassCounter: /* @__PURE__ */ new Map(), + typing: new Set(["Protocol"]) + }; + const members = []; + let statements = 0; + for (const schema of sorted) { + const argType = renderType(schema.parameters, `${camelCase(schema.name)}Args`, state); + const outputType = renderType(schema.output, `${camelCase(schema.name)}Output`, state); + if (isBareIdentifier(schema.name) && !RESERVED.has(schema.name) && !schema.name.startsWith("_")) { + const doc = docLines(schema.description, 2); + members.push(doc.length > 0 ? `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}:` : `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}: ...`); + members.push(...doc); + statements += 1; + } else { + members.push(`${pad(1)}# tools[${JSON.stringify(schema.name)}](args: ${argType}) -> ${outputType}`); + const description = describe(schema); + if (description !== void 0) members.push(`${pad(1)}# ${description}`); + } + } + const body = (statements > 0 ? members : [`${pad(1)}pass`, ...members]).join("\n"); + const imports = TYPING_ORDER.filter((symbol) => state.typing.has(symbol)); + const classBlock = state.classes.length > 0 ? `${state.classes.join("\n\n")}\n\n` : ""; + return `${SDK_INSTRUCTIONS}\n\n\`\`\`python\n${`from typing import ${imports.join(", ")}\n\nclass ToolCallError(Exception): + toolName: str\n\n${classBlock}class Tools(Protocol):\n${body}\n\ntools: Tools`}\n\`\`\``; +} +//#endregion +//#region lib/types/testing.js +/** Canonical tool-definition fixtures for repository tests. @module dsh-tools/testing */ +const CONTENT_VALUE_SCHEMA = { + type: "array", + items: { type: "json" } +}; +/** +* Define a test fixture that deliberately uses its content blocks as the +* canonical JSON value. Product tools must declare domain-owned DTOs instead. +* @param options - ordinary fixture fields plus a content-producing body. +* @returns a registry-ready tool with an explicit JSON-array output contract. +* @internal +*/ +function defineContentToolFixture(options) { + const execute = options.execute; + return defineTool({ + ...options, + output: { + schema: CONTENT_VALUE_SCHEMA, + render: (_args, value) => value + }, + async execute(args, exec) { + return await execute(args, exec); + } + }); +} +//#endregion +//#region lib/types/index.js +/** +* Tool registry, model presentation modes, and pre/guard/around/post/result +* execution pipeline. +* @module @deepseek-ai/dsh-tools +*/ +/** +* Language → SDK-section renderer. The registry looks up the loaded +* `ctx.codeRuntime.language` in this table when assembling the `tools:sdk` +* section under a non-native mode; a runtime whose language is not a key +* fails the assembly loudly (same idiom as `toolOrder` violations). Adding a +* new backend language is three parallel edits — a {@link CodeSdkLanguage} +* member, an entry here, and a `RUN_CODE_FLAVORS` entry in `code-mode.ts` for +* its `run_code` schema strings — plus the renderer function this table points +* at. The `satisfies` clause pins this table's key set to that union, which +* the flavor table is checked against too, so any of the three left out is a +* typecheck failure. What no check reaches is the prose that names the values +* instead of deriving them: the seam's `dsh-code-runtime` README pair, its +* `CodeRuntime.language` JSDoc, and `docs/subsystems/code-runtime.md` +* with its zh pair, plus this package's own README pair and the +* {@link Config.mode} JSDoc. +*/ +/** +* Prompt order of the `code` collapse statement: after the persona and before +* the 100-199 per-tool guidance band, so the model reads which tools it may +* call before it reads what each one is for. +*/ +const COLLAPSE_SECTION_ORDER = 99; +/** +* The model-facing statement of the `code` collapse. Names the consequence +* (the call fails) and the route (inside the program), because a rule the +* model can only discover by being denied is one it corrects too late. +*/ +const CODE_ONLY_INSTRUCTION = `\`${RUN_CODE_NAME}\` is the only tool you can call directly — a tool call naming any other tool fails. Reach every tool the SDK declares below from inside the program.`; +const SDK_RENDERERS = { + typescript: renderToolsSdk, + python: renderToolsSdkPy +}; +/** +* Scheduler entry point omitted from the generated named service API. +* @internal +*/ +const TOOL_RUNTIME_SCHEDULER = Symbol("@deepseek-ai/dsh-tools.scheduler"); +/** Canonical error code for cancellation after a tool body was invoked. */ +const TOOL_ABORTED = "ABORTED"; +/** Canonical error code for cancellation before a tool body was invoked. */ +const TOOL_ABORTED_BEFORE_DISPATCH = "ABORTED_BEFORE_DISPATCH"; +/** +* Thrown (internally) when the model requests a tool that isn't registered. +* Extends {@link HarnessError} (`code: 'UNKNOWN_TOOL'`) so an unknown-tool +* failure is as routable as a tool-thrown one — retry/sandbox/replay code can +* distinguish it from a tool body's own error. +*/ +var ToolNotFoundError = class extends HarnessError { + /** + * @param toolName - the name the caller asked for. + * @param reachableFrom - how the model reaches this tool instead, when the + * name IS visible and only the presentation denies calling it directly. + * Omitted for a name that is registered nowhere. + */ + constructor(toolName, reachableFrom) { + super(reachableFrom === void 0 ? `unknown tool "${toolName}"` : `unknown tool "${toolName}": ${reachableFrom}`, "UNKNOWN_TOOL"); + this.name = "ToolNotFoundError"; + } +}; +/** Thrown when a tool body or post-policy value violates its declared output. */ +var ToolOutputError = class extends HarnessError { + /** Schema/value violations in validation order. */ + violations; + constructor(toolName, violations) { + super(`tool "${toolName}" returned invalid output: ${violations.join("; ")}`, "INVALID_TOOL_OUTPUT"); + this.name = "ToolOutputError"; + this.violations = violations; + } +}; +/** Convert one projector exception into the canonical invalid-output failure. */ +function projectionError(toolName, projector, error) { + return new ToolOutputError(toolName, [`output.${projector} failed: ${errorMessage(error)}`]); +} +/** Snapshot one projector result before later durable-result materialization. */ +function snapshotProjection(toolName, projector, candidate) { + try { + const detached = snapshotJsonValue(candidate); + if (detached === void 0) throw new ToolOutputError(toolName, [`output.${projector} returned non-lossless JSON`]); + return detached; + } catch (error) { + if (error instanceof ToolOutputError) throw error; + throw projectionError(toolName, projector, error); + } +} +/** Snapshot one body or policy value into the canonical invalid-output failure class. */ +function snapshotToolValue(toolName, candidate) { + try { + const detached = snapshotJsonValue(candidate); + if (detached === void 0) throw new ToolOutputError(toolName, ["value is not lossless JSON"]); + return detached; + } catch (error) { + if (error instanceof ToolOutputError) throw error; + throw new ToolOutputError(toolName, [`value snapshot failed: ${errorMessage(error)}`]); + } +} +/** +* Best-effort human-readable message from an arbitrary thrown value: Error +* instances use `.message`; non-Error objects with a string `message` +* property (e.g. `throw { message: 'denied' }`) use it too; everything else +* is stringified. +*/ +function errorMessage(error) { + try { + if (error instanceof Error) return error.message; + if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") return error.message; + return String(error); + } catch { + return ""; + } +} +/** Derive one failure message from policy feedback without changing its rendered blocks. */ +function failureMessageFromContent(content) { + const text = content.map((block) => block.type === "text" ? block.text : `[${block.type} content]`).join("\n"); + return text.length > 0 ? text : "tool result blocked by post-execute policy"; +} +/** Snapshot and freeze one durable tool-result projection or reject lossy data. */ +function materializePresentation(candidate) { + const detached = snapshotJsonValue(candidate); + if (detached === void 0) throw new TypeError("tool result must be losslessly JSON-serializable"); + return deepFreeze(detached); +} +/** Structured `{ name, code }` for a thrown HarnessError, else undefined. */ +function errorInfo(error) { + try { + return error instanceof HarnessError ? { + name: error.name, + code: error.code + } : void 0; + } catch { + return; + } +} +/** One scope's complete tool-registry contribution. */ +var ToolLayer = class { + tools; + restrictions = new AnonymousEntries(); + guards = new AnonymousEntries(); + /** + * Presentation this scope's agent declared for itself, shadowing the + * deployment default. One cell rather than an entry table: two answers to + * "which form does the model see" is a contradiction, not a merge. + */ + mode; + constructor(scope) { + this.tools = new NamedEntries((name) => /* @__PURE__ */ new Error(scope === void 0 ? `tool "${name}" is already registered (for a per-agent variant, register through that agent's \`agent.ctx\` instead)` : `tool "${name}" is already registered in this scope`)); + } + /** Whether every contribution table in this aggregate layer is empty. */ + isEmpty() { + return this.tools.isEmpty() && this.restrictions.isEmpty() && this.guards.isEmpty() && this.mode === void 0; + } + /** Whether every compiled restriction in this layer admits a global tool name. */ + admits(name) { + for (const filter of this.restrictions.values()) if (filter.allow !== void 0 && !filter.allow.has(name) || filter.deny !== void 0 && filter.deny.has(name)) return false; + return true; + } + /** First monotonic denial from this layer's live guard registrations. */ + guardReason(exec) { + for (const guard of this.guards.values()) { + const reason = guard(exec); + if (reason !== void 0) return reason; + } + } +}; +/** Resolve the run_code overlap cap at the owning config boundary (direct construction bypasses the Loader schema). */ +function resolveMaxParallelSubCalls(value) { + const maxParallelSubCalls = value ?? 10; + if (!Number.isInteger(maxParallelSubCalls) || maxParallelSubCalls < 1) throw new Error("maxParallelSubCalls must be a positive integer"); + return maxParallelSubCalls; +} +/** +* Tool registry and execution pipeline. Scoped registrations shadow globals; +* one visibility resolver feeds presentation, lookup, and dispatch. +*/ +var ToolRuntime = class extends Service { + static inject = ["systemPrompt"]; + static Config = z.object({ + mode: z.union([ + "native", + "code", + "both" + ]).default("native"), + maxParallelSubCalls: z.natural().min(1).default(10) + }); + /** Internal staged view consumed by `dsh-agent-loop`'s parallel scheduler. */ + [TOOL_RUNTIME_SCHEDULER] = { + prepare: (exec) => this.prepareScheduledExecution(exec), + dispatch: (exec) => this.dispatchScheduledExecution(exec), + finalize: (exec, result) => this.finalizeScheduledExecution(exec, result), + finish: (exec, result) => this.finishScheduledExecution(exec, result) + }; + /** Context deferred by a running tool body, keyed by its scheduler-owned execution. */ + deferredContexts = /* @__PURE__ */ new WeakMap(); + /** Executions whose tool body declared the current turn complete. */ + concludingExecutions = /* @__PURE__ */ new WeakSet(); + /** Original caller cancellation, kept outside the wrapper-mutable execution object. */ + cancellationStates = /* @__PURE__ */ new WeakMap(); + /** Definition-owned final content transform snapshotted before policy begins. */ + contentFinalizers = /* @__PURE__ */ new WeakMap(); + layers = new ScopedLayers((scope) => new ToolLayer(scope), () => { + this.ctx.emit("tools/change"); + }); + /** Presentation for scopes that declare none; {@link presentAs} shadows it per scope. */ + defaultMode; + maxParallelSubCalls; + /** + * Reserved presentation transport, kept outside the filterable registration + * layers. Built on first need rather than at construction: which agents run + * a code mode is no longer known when the service is constructed, and the + * transport is stateless beyond its closures over `this`. + */ + codeTransport; + constructor(ctx, config = {}) { + super(ctx, "tools"); + this.defaultMode = config.mode ?? "native"; + this.maxParallelSubCalls = resolveMaxParallelSubCalls(config.maxParallelSubCalls); + ctx.systemPrompt.tools((context) => this.wireSchemas(context.scope)); + if (this.defaultMode !== "native") { + ctx.systemPrompt.section(this.collapseSection()); + ctx.systemPrompt.section(this.sdkSection()); + } + } + /** + * The prompt statement of the `code` executor collapse, registered wherever + * {@link sdkSection} is and rendering empty outside an effective `code`. + * + * Every tool contributes its own guidance section naming its tool, none of + * them qualify how that tool is reached, and they all render before the SDK + * (orders 100-199 against {@link SDK_SECTION_ORDER}). Without this the model + * reads a catalog of tools it is told to use and no statement that only + * `run_code` may be called, so it emits a native call, receives + * `UNKNOWN_TOOL` for a tool the prompt just declared, and concludes the + * deployment is inconsistent. {@link COLLAPSE_SECTION_ORDER} places the rule + * before that guidance rather than after it. + * + * `both` renders empty: native calls do execute there, so the rule is false. + * @returns the section registration. + */ + collapseSection() { + return { + name: "tools:code-only", + order: COLLAPSE_SECTION_ORDER, + text: (context) => this.modeFor(context.scope) === "code" ? CODE_ONLY_INSTRUCTION : "" + }; + } + /** + * The generated-SDK prompt section, registered globally by a code-mode + * deployment and per scope by {@link presentAs}. + * + * The body regenerates from the CALLING scope, and renders empty for an + * agent presenting natively — an agent that opted out under a code-mode + * deployment still sees the global registration, and an empty section is + * dropped from the rendered prompt. + * @returns the section registration. + */ + sdkSection() { + return { + name: "tools:sdk", + order: 150, + text: (context) => { + const mode = this.modeFor(context.scope); + if (mode === "native") return ""; + const runtime = this.requireCodeRuntime(mode); + const render = SDK_RENDERERS[runtime.language]; + /* v8 ignore next -- requireCodeRuntime rejects an unknown language before this runs. */ + if (render === void 0) throw new Error(`dsh-tools: no SDK renderer for ${runtime.language}`); + return render(this.sdkSchemas(context.scope)); + } + }; + } + /** + * The presentation one scope's agent sees: its own declaration, else the + * deployment default. + * @param scope - the calling agent, or undefined for the global view. + * @returns the resolved presentation mode. + */ + modeFor(scope) { + const layers = this.layers.chainLayers(scope); + for (let index = layers.length - 1; index >= 0; index -= 1) { + const mode = layers[index]?.mode; + if (mode !== void 0) return mode; + } + return this.defaultMode; + } + /** + * The reserved `run_code` transport, built on first need. + * + * It never enters the global layer: per-agent restrictions must not remove + * it, and a scoped registration must not shadow it. The visibility resolver + * appends it after resolving the filterable global/scoped capability layers, + * and only for scopes whose mode actually presents it. + * @returns the shared transport definition. + */ + requireCodeTransport() { + this.codeTransport ??= createRunCodeTool(this, { + requireRuntime: () => this.requireCodeRuntime(this.defaultMode), + peekRuntime: () => this.ctx.get("codeRuntime"), + maxParallel: this.maxParallelSubCalls, + shapeDispatchLog: (dispatch) => this.shapeDispatchLog(dispatch) + }); + return this.codeTransport; + } + /** + * Present the calling scope's tools in `mode` instead of the deployment + * default. Nearest scope on the chain wins, so a preset's standing + * declaration covers every agent joined under it. + * + * Scoped only, and one declaration per scope: this is how an agent preset + * composes Code Mode agents beside native ones in the same process, and a + * process-global override would be the `mode` config field instead. + * @param mode - the presentation the covered agents' models see. + * @returns the exact disposer that restores the deployment default. + */ + presentAs(mode) { + const ctx = this.ctx; + if (scopeOf(ctx) === void 0) throw new Error("tools.presentAs() requires a scoped context (agent.ctx): a context-global presentation is the `mode` config field on the tools row"); + return ctx.effect(function* () { + yield this.layers.effect(ctx, (layer) => { + if (layer.mode !== void 0) throw new Error(`tools.presentAs("${mode}") conflicts with "${layer.mode}" already declared for this scope; one composition selects one presentation`); + layer.mode = mode; + return () => { + layer.mode = void 0; + }; + }, { label: "tools.presentAs()" }); + if (mode !== "native") { + yield ctx.systemPrompt.section(this.collapseSection()); + yield ctx.systemPrompt.section(this.sdkSection()); + } + }.bind(this), "tools.presentAs()"); + } + /** + * Build one scope's wire schemas and names for prompt-order validation. + * Restrictions do not make known tools invalid, but a mode collapse does. + */ + wireSchemas(scope) { + const view = this.view(scope); + const mode = this.modeFor(scope); + if (mode === "native") return { + schemas: [...view.visible.values()].map((definition) => this.schemaOf(definition, false)), + knownNames: [...view.knownNames] + }; + this.requireCodeRuntime(mode); + const schemas = [...view.visible.values()].map((definition) => this.schemaOf(definition, false)); + if (mode === "code") return { + schemas: schemas.filter((schema) => schema.name === RUN_CODE_NAME), + knownNames: [RUN_CODE_NAME] + }; + return { + schemas, + knownNames: [...view.knownNames, RUN_CODE_NAME] + }; + } + /** + * Resolve the code runtime or throw the actionable misconfiguration error. + * Read at use time (assembly / run_code execution), NOT via static + * `inject`: an inject entry would hold `ctx.tools` — and every tool plugin + * behind it — hostage to a code runtime existing even under `mode: + * 'native'` (the loop's optional-backend idiom, same as + * `sessionPersistence`). + * + * Assembly and `run_code` execution read separately, so the language is not + * bound to a request. Harmless while one published backend exists — both + * reads return the same flavor — but a reload that swapped in a second + * language between them would hand a program written against one SDK to the + * other. Binding it is deferred until a second backend ships (the first + * point it is testable); rationale in the + * [language-dispatch note](../../../../.agents/notes/implemented/feature/2026-07-31-code-mode-language-dispatch.md). + */ + requireCodeRuntime(mode) { + const runtime = this.ctx.get("codeRuntime"); + if (!runtime) throw new Error(`dsh-tools: mode "${mode}" requires a code runtime — load a ctx.codeRuntime implementation (e.g. @deepseek-ai/dsh-code-runtime-worker-thread) or set tools mode to "native"`); + if (!Object.hasOwn(SDK_RENDERERS, runtime.language)) { + const known = Object.keys(SDK_RENDERERS).map((name) => JSON.stringify(name)).join(", "); + throw new Error(`dsh-tools: no SDK renderer registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`); + } + return runtime; + } + /** + * Register globally or in the calling agent scope. Scoped tools shadow + * globals; duplicates within one layer and the reserved `run_code` name fail. + * @param definition - tool schema, execution, and optional finalization/presentation callbacks. + * @returns the exact disposer that unregisters the tool. + */ + register(definition) { + const name = definition.name; + const output = definition.output; + if (output === void 0 || typeof output !== "object" || typeof output.render !== "function" || output.presentationMeta !== void 0 && typeof output.presentationMeta !== "function") throw new TypeError(`tool "${name}" must declare output { schema, render, presentationMeta? }`); + assertSupportedJsonSchema(output.schema); + const timeoutMs = definition.timeoutMs; + if (timeoutMs !== void 0 && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) throw new TypeError(`tool "${name}" timeoutMs must be a positive finite number`); + if (name === "run_code") throw new Error(`tool name "${RUN_CODE_NAME}" is reserved for the Code Mode presentation transport and cannot be registered or shadowed`); + return this.layers.effect(this.ctx, (layer) => layer.tools.insert(name, definition), { label: "tools.register()" }); + } + /** + * Restrict global tools for the calling agent scope. Empty filters, unknown + * names, scope-local names, and reserved transport names fail. Restrictions + * intersect; scoped registrations remain visible. + * @param filter - global-tool mask: `allow` (keep only) and/or `deny` (remove). + * @returns the exact disposer that lifts this restriction. + */ + restrict(filter) { + const scope = scopeOf(this.ctx); + if (scope === void 0) throw new Error("tools.restrict() requires a scoped context (agent.ctx): a context-global restriction would mask every agent — deny the tool for the intended agent instead"); + const allow = filter.allow; + const deny = filter.deny; + if (allow === void 0 && deny === void 0) throw new Error("tools.restrict({}) is a no-op: pass `allow` and/or `deny` (an empty filter is almost always a materialized-empty-config bug)"); + const compiled = { + ...allow !== void 0 ? { allow: new Set(allow) } : {}, + ...deny !== void 0 ? { deny: new Set(deny) } : {} + }; + if ([...allow ?? [], ...deny ?? []].includes("run_code")) throw new Error(`tools.restrict() cannot name reserved Code Mode presentation transport "${RUN_CODE_NAME}"; restrict end-capability tools instead`); + const known = this.view(scope).restrictableNames; + const unknown = [...allow ?? [], ...deny ?? []].filter((name) => !known.has(name)); + if (unknown.length > 0) throw new Error(`tools.restrict() names unknown global tool${unknown.length > 1 ? "s" : ""} ${unknown.map((n) => `"${n}"`).join(", ")}; known global tools: ${[...known].sort().join(", ") || "(none)"}`); + return this.layers.effect(this.ctx, (layer) => layer.restrictions.append(compiled), { label: "tools.restrict()" }); + } + /** + * Register a monotonic guard after the extensible `tools/pre-execute` + * waterfall. A plain-context guard applies globally; one registered through + * `agent.ctx` applies only to that agent. Any matching guard may deny by + * returning a reason, while no guard can force-allow a call another guard + * denied. The exact effect disposer is returned for ordered ownership and + * HMR cleanup. + * @param guard - synchronous check; a returned string denies the execution. + * @returns the exact disposer that unregisters the guard. + */ + guard(guard) { + return this.layers.effect(this.ctx, (layer) => layer.guards.append(guard), { + label: "tools.guard()", + notify: false + }); + } + /** First monotonic denial from the global then the scope chain's guard layers, farthest first. */ + guardReason(exec) { + const globalReason = this.layers.global.guardReason(exec); + if (globalReason !== void 0) return globalReason; + if (exec.agent === void 0) return void 0; + for (const layer of this.layers.chainLayers(exec.agent)) { + const reason = layer.guardReason(exec); + if (reason !== void 0) return reason; + } + } + /** + * Resolve every registry fact one scope needs in one layer traversal. The + * visible map applies restrictions to the INHERITED surface, then the + * scope's own registrations and the reserved presentation transport; the + * other sets retain the pre-restriction facts needed by restriction and + * prompt-order validation. + * + * A restriction filters what a scope inherits — the global layer and every + * ancestor layer on its chain — and never what its OWN layer registers. + * That exemption is what a per-child capability filter has to keep intact: + * the delegation runtime registers a child's reporting and structured-output + * tools into the child's own layer, and a filter naming the capabilities the + * child may use must not strip the machinery it answers through. + * + * Reading the exempt set as "the global layer" instead of "not mine" held + * only while every model-facing tool sat in the host composition. Once + * presets moved them onto the agent plane they became an ANCESTOR + * contribution, so a child's filter silently stopped constraining anything + * it was given. + * @param scope - the viewing scope (the agent), or undefined for the global view. + * @returns the complete derived view for that scope. + */ + view(scope) { + const layers = this.layers.chainLayers(scope); + const own = this.layers.peek(scope); + const inherited = new Map(this.layers.global.tools.entries()); + for (const layer of layers) { + if (layer === own) continue; + for (const [name, definition] of layer.tools.entries()) inherited.set(name, definition); + } + const visible = /* @__PURE__ */ new Map(); + const knownNames = /* @__PURE__ */ new Set(); + const restrictableNames = /* @__PURE__ */ new Set(); + for (const [name, definition] of inherited) { + knownNames.add(name); + restrictableNames.add(name); + if (layers.every((layer) => layer.admits(name))) visible.set(name, definition); + } + if (own !== void 0) for (const [name, definition] of own.tools.entries()) { + knownNames.add(name); + visible.set(name, definition); + } + if (this.modeFor(scope) !== "native") visible.set(RUN_CODE_NAME, this.requireCodeTransport()); + return { + visible, + knownNames, + restrictableNames + }; + } + /** + * Look up a tool as one scope sees it (scoped + * shadows global; a restricted-away global reads as absent). Presenters pass + * the calling agent so the rendered card matches the definition that + * actually executed. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns the definition the scope resolves, or undefined when none is visible. + */ + get(name, scope) { + return this.view(scope).visible.get(name); + } + /** + * Resolve the definition that MAY EXECUTE for a call, applying the mode + * collapse at the operation boundary that owns it. The registry view + * (`get`) is presentation-agnostic; here a MODEL-DIRECT call under `code` + * may only name the reserved `run_code` transport, while a nested + * sub-dispatch (a `parent` token set — the `run_code` SDK calling a tool + * it bound) may call any visible tool. Denial surfaces as `UNKNOWN_TOOL` + * through the executor, matching an absent definition. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + * @returns the definition that may run, or undefined when the call must be rejected. + */ + resolveExecution(name, scope, nested) { + const tool = this.get(name, scope); + if (tool === void 0) return void 0; + if (this.collapses(name, scope, nested)) return void 0; + return tool; + } + /** + * Project visible definitions onto the allowlisted model-facing schema fields, + * excluding execution and presentation callbacks. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns one deep-cloned schema per visible tool. + */ + schemas(scope) { + return [...this.view(scope).visible.values()].map((definition) => this.schemaOf(definition, true)); + } + /** Project visible callable tools onto the generated Code Mode SDK contract. */ + sdkSchemas(scope) { + return [...this.view(scope).visible.values()].filter((definition) => definition.name !== RUN_CODE_NAME).map((definition) => { + const output = snapshotJsonValue(definition.output.schema); + /* v8 ignore next -- registration already validated and retained this schema as lossless JSON. */ + if (output === void 0) throw new Error(`tool "${definition.name}" output schema must be lossless JSON before SDK projection`); + return { + ...this.schemaOf(definition, true), + output + }; + }); + } + /** Project one definition onto the model-facing schema fields. */ + schemaOf(definition, detachParameters) { + const { name, description, parameters } = definition; + const detached = detachParameters ? snapshotJsonValue(parameters) : parameters; + if (detached === void 0) throw new Error(`tool "${name}" parameters must be lossless JSON before schema projection`); + return { + name, + description, + parameters: detached + }; + } + /** + * Classify a pending call through the caller's visible tool definition. Only + * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or + * throwing classifiers are exclusive. + * @param exec - call name, parsed arguments, and optional agent scope. + * @returns the fail-closed scheduling mode. + */ + executionMode(exec) { + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== void 0); + if (!tool?.isConcurrencySafe) return { kind: "exclusive" }; + try { + return tool.isConcurrencySafe(exec.arguments) === true ? { kind: "parallel" } : { kind: "exclusive" }; + } catch { + return { kind: "exclusive" }; + } + } + /** + * Run the `tools/code-dispatch-log` waterfall over one settled sub-dispatch + * and return the content the bridge should log on `tool/code-dispatch`. + * Contained: when a listener throws, the method logs the original settled + * content; that failure must not fail the dispatch or omit the settle event. Private: + * the ONE consumer is the `run_code` bridge this registry constructs, which + * receives it as a capability parameter (the `requireRuntime` idiom) — the + * waterfall, not this invoker, is the public extension point. + */ + async shapeDispatchLog(dispatch) { + try { + return await this.ctx.waterfall(scopeTarget(this, dispatch.agent), "tools/code-dispatch-log", dispatch, () => Promise.resolve(dispatch.content)); + } catch (error) { + this.ctx.logger.warn(`tools: code-dispatch-log listener failed for ${dispatch.name}: ${errorMessage(error)}; logging the original settled content`); + return dispatch.content; + } + } + /** + * Whether the `code` mode collapse denies a model-direct call: only the + * reserved `run_code` transport may be named. Nested sub-dispatches (a + * `parent` token set) bypass the collapse. One home for the + * security-relevant predicate, shared by {@link resolveExecution} and + * {@link createExecution} so the two can never drift apart. + * + * Resolved through {@link modeFor}, NOT `defaultMode`: an agent given `code` + * by an agent preset under a native deployment is the composition + * `dsh-agent-tool-presentation` exists for, and reading the deployment default would + * leave exactly that agent uncollapsed — announcing one surface while + * executing another, which is the bypass this collapse closes. + * @param name - the tool name as registered. + * @param scope - the viewing scope whose effective presentation mode applies. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + */ + collapses(name, scope, nested) { + return !nested && this.modeFor(scope) === "code" && name !== "run_code"; + } + /** + * Execute through pre-policy, guards, around-dispatch, post-policy, + * definition-owned content finalization, and final notification. Tool and + * listener failures resolve as materialized error results; an invisible tool + * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen + * snapshot final observers receive. Cancellation + * arriving after entry and before final result materialization skips a + * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a + * successful started outcome with `ABORTED`; already-started work is still + * drained and may retain a tool-owned structured error. + * @param exec - the typed same-process call input. The registry assigns its + * correlation token before policy begins. + * @returns the materialized final result. + */ + async execute(exec) { + return this.prepareExecution(exec, (prepared) => this.completeScheduledExecution(prepared)); + } + async completeScheduledExecution(prepared) { + switch (prepared.kind) { + case "dispatch": { + const dispatched = await this.dispatchScheduledExecution(prepared.exec); + return dispatched.kind === "post-result" ? await this.finalizeScheduledExecution(prepared.exec, dispatched.result) : this.finishScheduledExecution(prepared.exec, dispatched.result); + } + case "post-result": return await this.finalizeScheduledExecution(prepared.exec, prepared.result); + case "final-result": return this.finishScheduledExecution(prepared.exec, prepared.result); + /* v8 ignore next -- closed-union exhaustiveness guard */ + default: return assertNever(prepared, "scheduled tool preparation"); + } + } + createExecution(exec) { + const deferredContexts = []; + const token = createExecutionToken(); + const callId = exec.callId; + const rootCallId = exec.rootCallId ?? callId; + const name = exec.name; + const agent = exec.agent; + const parent = exec.parent; + const signal = exec.signal; + const visible = this.get(name, agent); + const collapsed = visible !== void 0 && this.collapses(name, agent, parent !== void 0); + const concludingExecutions = this.concludingExecutions; + const base = { + token, + callId, + rootCallId, + name, + signal, + ...agent !== void 0 ? { agent } : {}, + ...parent !== void 0 ? { parent } : {}, + deferContext(context) { + deferredContexts.push(context); + }, + concludeTurn() { + concludingExecutions.add(this); + } + }; + const capturedFinalizer = visible?.finalizeContent?.bind(visible); + const finalizerFor = () => collapsed && !signal.aborted ? void 0 : capturedFinalizer; + try { + const detached = snapshotJsonValue(exec.arguments); + if (detached === void 0) throw new TypeError("tool execution arguments must be losslessly JSON-serializable"); + const execution = { + ...base, + arguments: deepFreeze(detached) + }; + this.deferredContexts.set(execution, deferredContexts); + this.contentFinalizers.set(execution, finalizerFor()); + this.cancellationStates.set(execution, { + callerSignal: signal, + bodyInvoked: false + }); + if (collapsed) { + if (signal.aborted) return { + kind: "final-result", + exec: execution, + result: toolAbortedBeforeDispatchResult() + }; + return { + kind: "final-result", + exec: execution, + result: toolErrorResult(new ToolNotFoundError(name, `only \`${RUN_CODE_NAME}\` is callable directly — call \`${name}\` from inside a \`${RUN_CODE_NAME}\` program instead`)) + }; + } + return { + kind: "ready", + exec: execution + }; + } catch (error) { + const execution = { + ...base, + arguments: void 0 + }; + this.contentFinalizers.set(execution, finalizerFor()); + return { + kind: "final-result", + exec: execution, + result: toolErrorResult(error) + }; + } + } + /** + * Run the ordered pre-execute and monotonic guard stages for the scheduler. + * @param input - the caller-supplied execution input. + * @returns the prepared execution plus the next scheduler stage. + * @internal + */ + async prepareScheduledExecution(input) { + return this.prepareExecution(input, (prepared) => prepared); + } + async prepareExecution(input, next) { + const created = this.createExecution(input); + if (created.kind !== "ready") return next(created); + const exec = created.exec; + if (this.callerCancelled(exec)) return next({ + kind: "final-result", + exec, + result: toolAbortedBeforeDispatchResult() + }); + try { + const carrier = scopeTarget(this, exec.agent); + const gate = await this.ctx.waterfall(carrier, "tools/pre-execute", exec, () => Promise.resolve({ kind: "allow" })); + const askResolution = gate.kind === "ask" ? await this.serviceAsk(exec, gate) : { + decision: gate, + approvalCancelled: false + }; + const { decision } = askResolution; + if (this.callerCancelled(exec) && askResolution.approvalCancelled) return await next({ + kind: "post-result", + exec, + result: toolAbortedBeforeDispatchResult() + }); + const denialReason = decision.kind === "allow" ? this.guardReason(exec) : decision.reason; + if (denialReason !== void 0) return await next({ + kind: "post-result", + exec, + result: this.materializeFinalResult({ + content: [{ + type: "text", + text: `Error: ${denialReason}` + }], + isError: true, + error: { message: denialReason } + }) + }); + if (this.callerCancelled(exec)) return await next({ + kind: "post-result", + exec, + result: toolAbortedBeforeDispatchResult() + }); + return await next({ + kind: "dispatch", + exec + }); + } catch (error) { + return next({ + kind: "final-result", + exec, + result: toolErrorResult(error) + }); + } + } + /** Whether the original caller signal is currently aborted. */ + callerCancelled(exec) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === void 0) throw new Error("tool registry scheduler invariant violated: missing cancellation state"); + return state.callerSignal.aborted; + } + /** Canonical cancellation outcome selected by whether the tool body started. */ + cancellationResult(exec, prior) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === void 0) throw new Error("tool registry scheduler invariant violated: missing cancellation state"); + return state.bodyInvoked ? toolAbortedResult(prior) : toolAbortedBeforeDispatchResult(prior); + } + /** + * Dispatch the registered body with the original caller signal fused back + * into any around-wrapper replacement. Cancellation never abandons the body: + * a started promise reaches quiescence before its outcome becomes `ABORTED`. + */ + async dispatchToolBody(exec) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === void 0) throw new Error("tool registry scheduler invariant violated: missing cancellation state"); + const wrapperSignal = exec.signal; + const fused = fuseToolSignals(state.callerSignal, wrapperSignal); + const signal = fused.signal; + if (isAborted(signal)) { + fused.dispose(); + return toolAbortedBeforeDispatchResult(); + } + exec.signal = signal; + try { + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== void 0); + if (!tool) throw new ToolNotFoundError(exec.name); + state.bodyInvoked = true; + const returned = await tool.execute(exec.arguments, exec); + const result = this.createSuccessResult(exec, tool, returned); + return isAborted(signal) ? toolAbortedResult(result) : result; + } catch (error) { + return toolErrorResult(error); + } finally { + fused.dispose(); + exec.signal = wrapperSignal; + } + } + /** + * Run around-dispatch and the tool body. Tool and unknown-tool failures still + * receive post-execute; pipeline failures are already final. + * @param exec - the prepared execution. + * @returns whether the result still needs post-execute. + * @internal + */ + async dispatchScheduledExecution(exec) { + try { + const mutableExec = exec; + const carrier = scopeTarget(this, exec.agent); + const result = await this.ctx.waterfall(carrier, "tools/execute", mutableExec, () => this.dispatchToolBody(mutableExec)); + const normalized = this.normalizeDispatchResult(exec, result); + const deferredContexts = this.deferredContexts.get(exec); + /* v8 ignore next -- dispatch only receives executions minted by this registry's prepare stage */ + if (deferredContexts === void 0) throw new Error("tool registry scheduler invariant violated: unprepared execution"); + const resultWithDeferredContexts = deferredContexts.length === 0 ? normalized : this.markCanonical(exec, { + ...normalized, + additionalContexts: [...deferredContexts, ...normalized.additionalContexts ?? []] + }); + return { + kind: "post-result", + result: this.callerCancelled(exec) && !resultWithDeferredContexts.isError ? this.cancellationResult(exec, resultWithDeferredContexts) : resultWithDeferredContexts + }; + } catch (error) { + return { + kind: "final-result", + result: toolErrorResult(error) + }; + } + } + /** + * Run ordered post-execute, then apply definition-owned content finalization, + * materialize, and notify the final outcome. + * @param exec - the prepared execution. + * @param result - dispatch/pre result that still needs post-execute. + * @returns the materialized final result. + * @internal + */ + async finalizeScheduledExecution(exec, result) { + try { + const postResult = await this.postExecute(exec, result); + return this.finishScheduledExecution(exec, this.callerCancelled(exec) && !postResult.isError ? this.cancellationResult(exec, postResult) : postResult); + } catch (error) { + return this.finishScheduledExecution(exec, toolErrorResult(error)); + } + } + /** + * Materialize the candidate, apply definition-owned content finalization, + * then materialize and notify the authoritative result. + * @param exec - the prepared execution. + * @param result - final result. + * @returns the materialized final result. + * @internal + */ + finishScheduledExecution(exec, result) { + let materializedResult; + try { + materializedResult = this.materializeFinalResult(result); + } catch (error) { + materializedResult = this.materializeFinalResult(toolErrorResult(error)); + } + let finalResult; + try { + finalResult = this.materializeFinalResult(this.applyFinalContent(exec, materializedResult)); + } catch (error) { + finalResult = this.materializeFinalResult(toolErrorResult(error)); + } + this.notifyResult(exec, finalResult); + return finalResult; + } + /** Apply the snapshotted tool-owned content transform without exposing other result fields. */ + applyFinalContent(exec, result) { + const finalizeContent = this.contentFinalizers.get(exec); + if (finalizeContent === void 0) return result; + const content = finalizeContent(exec, result); + return content === void 0 ? result : { + ...result, + content + }; + } + /** Notify observers without exposing a mutation or error channel into the outcome. */ + notifyResult(exec, result) { + Object.freeze(exec); + const { name: toolName, callId } = exec; + const reportFailure = (error) => { + this.ctx.logger.warn(`tool "${toolName}" (${callId}): tools/result observer failed: ${errorMessage(error)}`); + }; + const callbacks = this.ctx.events.dispatch("emit", [ + scopeTarget(this, exec.agent), + "tools/result", + exec, + result + ]); + for (const callback of callbacks) try { + const returned = callback(exec, result); + Promise.resolve(returned).catch(reportFailure); + } catch (error) { + reportFailure(error); + } + } + /** + * Resolve an `ask` decision to allow/deny through the approval seam. The + * seam is consumed opportunistically with `ctx.get('approval')` — a + * deployment that composes no ApprovalService keeps the historical degrade + * to deny, and an unmount mid-session degrades the same way on the next ask. + * An agent-less execution also degrades: without an agent there is no + * session to audit to and no UI to route to. Otherwise the outcome maps + * one-to-one — `allowed-once` proceeds; the three non-grants deny with + * distinct reasons so the model can tell a human "no" from an absent + * approval channel. + */ + async serviceAsk(exec, ask) { + const approval = this.ctx.get("approval"); + if (approval === void 0) return { + decision: { + kind: "deny", + reason: ask.reason ?? `tool "${exec.name}" requires approval (not yet supported)` + }, + approvalCancelled: false + }; + if (exec.agent === void 0) return { + decision: { + kind: "deny", + reason: `tool "${exec.name}" requires approval, but the call has no agent to route it through` + }, + approvalCancelled: false + }; + const outcome = await approval.request({ + agent: exec.agent, + toolName: exec.name, + callId: exec.callId, + ...ask.reason !== void 0 ? { reason: ask.reason } : {}, + signal: exec.signal + }); + switch (outcome) { + case "allowed-once": return { + decision: { kind: "allow" }, + approvalCancelled: false + }; + case "rejected": return { + decision: { + kind: "deny", + reason: `the user rejected tool "${exec.name}"` + }, + approvalCancelled: false + }; + case "cancelled": return { + decision: { + kind: "deny", + reason: `approval for tool "${exec.name}" was cancelled` + }, + approvalCancelled: true + }; + case "unavailable": return { + decision: { + kind: "deny", + reason: `tool "${exec.name}" requires approval, but no approval channel is available` + }, + approvalCancelled: false + }; + default: return assertNever(outcome, "ApprovalOutcome"); + } + } + /** + * Run the `tools/post-execute` waterfall over a dispatched `result` and apply + * its {@link PostToolDecision}: `accept` keeps the call successful (replacing + * `content` when given), `block` turns it into an `isError` whose content is + * the corrective `feedback`. Either decision may attach `additionalContexts`, + * which are ferried on the returned result for the loop's active-batch FIFO. + * Context deferred by the tool body survives an accepted result but is + * discarded when the outer call is blocked; a block exposes only context the + * blocking decision explicitly supplied. + * Runs inside `execute`'s outer try/catch (a throwing listener → isError). + */ + async postExecute(exec, result) { + const decision = await this.ctx.waterfall(scopeTarget(this, exec.agent), "tools/post-execute", exec, result, () => Promise.resolve({ kind: "accept" })); + const decisionContexts = decision.additionalContexts ?? []; + if (decision.kind === "block") { + const message = failureMessageFromContent(decision.feedback); + return this.markCanonical(exec, { + content: decision.feedback, + isError: true, + error: { message }, + ...decisionContexts.length > 0 ? { additionalContexts: decisionContexts } : {} + }); + } + if (Object.hasOwn(decision, "content") && Object.hasOwn(decision, "value")) throw new TypeError("tools/post-execute accept decision cannot replace both value and content"); + const additionalContexts = [...result.additionalContexts ?? [], ...decisionContexts]; + if (Object.hasOwn(decision, "value")) { + if (result.isError) throw new TypeError("tools/post-execute cannot replace the value of a failed result"); + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== void 0); + if (tool === void 0) throw new ToolNotFoundError(exec.name); + const replaced = this.createSuccessResult(exec, tool, decision.value); + return this.markCanonical(exec, { + ...replaced, + ...additionalContexts.length > 0 ? { additionalContexts } : {} + }); + } + return this.markCanonical(exec, { + ...result, + ...decision.content !== void 0 ? { content: decision.content } : {}, + ...additionalContexts.length > 0 ? { additionalContexts } : {} + }); + } + /** Registry-normalized results and the exact dispatch that validated each value. */ + canonicalResults = /* @__PURE__ */ new WeakMap(); + /** Mark one registry-normalized result as canonical only for its owning dispatch. */ + markCanonical(exec, result) { + this.canonicalResults.set(result, exec.token); + return result; + } + /** Snapshot, validate, render, and optionally project one successful body value. */ + createSuccessResult(exec, tool, candidate) { + const detached = snapshotToolValue(tool.name, candidate); + const violations = validateJsonSchemaValue(tool.output.schema, detached, "value"); + if (violations.length > 0) throw new ToolOutputError(tool.name, violations); + const value = deepFreeze(detached); + let rendered; + try { + rendered = tool.output.render(exec.arguments, value); + } catch (error) { + throw projectionError(tool.name, "render", error); + } + const content = snapshotProjection(tool.name, "render", rendered); + let meta; + if (exec.parent === void 0 && tool.output.presentationMeta !== void 0) { + let projected; + try { + projected = tool.output.presentationMeta(exec.arguments, value); + } catch (error) { + throw projectionError(tool.name, "presentationMeta", error); + } + meta = snapshotProjection(tool.name, "presentationMeta", projected); + } + const concludesTurn = this.concludingExecutions.has(exec); + return this.markCanonical(exec, this.materializeFinalResult({ + isError: false, + value, + content, + ...meta !== void 0 ? { meta } : {}, + ...concludesTurn ? { concludesTurn: true } : {} + })); + } + /** Normalize an around-dispatch wrapper's authored result through the owning output contract. */ + normalizeDispatchResult(exec, result) { + if (this.canonicalResults.get(result) === exec.token) return result; + if (result.isError) return this.markCanonical(exec, { + isError: true, + error: result.error, + content: result.content, + ...result.meta !== void 0 ? { meta: result.meta } : {}, + ...result.additionalContexts !== void 0 ? { additionalContexts: result.additionalContexts } : {} + }); + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== void 0); + if (tool === void 0) throw new ToolNotFoundError(exec.name); + const normalized = this.createSuccessResult(exec, tool, result.value); + return this.markCanonical(exec, { + ...normalized, + ...result.additionalContexts !== void 0 ? { additionalContexts: result.additionalContexts } : {} + }); + } + /** Materialize the authoritative commit outcome once, immediately before `tools/result`. */ + materializeFinalResult(result) { + const presentation = { + content: result.content, + ...result.meta !== void 0 ? { meta: result.meta } : {}, + ...result.additionalContexts !== void 0 ? { additionalContexts: result.additionalContexts } : {} + }; + if (result.isError) return materializePresentation({ + isError: true, + error: result.error, + ...presentation + }); + return deepFreeze({ + ...materializePresentation({ + isError: false, + ...presentation, + ...result.concludesTurn === true ? { concludesTurn: true } : {} + }), + value: result.value + }); + } +}; +/** Mint a same-process correlation token whose identity is its value. */ +function createExecutionToken() { + return Symbol("dsh.tool.execution"); +} +function toolErrorResult(error) { + const info = errorInfo(error); + const message = errorMessage(error); + return { + content: [{ + type: "text", + text: `Error: ${message}` + }], + isError: true, + error: { + message, + ...info ? { info } : {} + } + }; +} +/** Read live abort state across an await without treating it as synchronously immutable. */ +function isAborted(signal) { + return signal.aborted; +} +/** +* Fuse caller and wrapper cancellation without nesting `AbortSignal.any`. +* Keeping the relay dispatch-scoped also removes listeners when work settles. +*/ +function fuseToolSignals(caller, wrapper) { + if (caller === wrapper) return { + signal: caller, + dispose() {} + }; + const controller = new AbortController(); + let listening = false; + const dispose = () => { + if (!listening) return; + listening = false; + caller.removeEventListener("abort", abortFromCaller); + wrapper.removeEventListener("abort", abortFromWrapper); + }; + const abortFrom = (source) => { + const reason = source.reason; + controller.abort(reason); + dispose(); + }; + const abortFromCaller = () => { + abortFrom(caller); + }; + const abortFromWrapper = () => { + abortFrom(wrapper); + }; + if (wrapper.aborted) abortFromWrapper(); + else if (caller.aborted) abortFromCaller(); + else { + listening = true; + caller.addEventListener("abort", abortFromCaller, { once: true }); + wrapper.addEventListener("abort", abortFromWrapper, { once: true }); + } + return { + signal: controller.signal, + dispose + }; +} +/** Canonical result when cancellation supersedes success after body invocation. */ +function toolAbortedResult(prior) { + const additionalContexts = prior?.additionalContexts ?? []; + return { + content: [{ + type: "text", + text: "Error: tool call aborted" + }], + isError: true, + error: { + message: "tool call aborted", + info: { + name: "AbortError", + code: TOOL_ABORTED + } + }, + ...additionalContexts.length > 0 ? { additionalContexts } : {} + }; +} +/** Canonical result when cancellation prevents tool body invocation. */ +function toolAbortedBeforeDispatchResult(prior) { + const additionalContexts = prior?.additionalContexts ?? []; + return { + content: [{ + type: "text", + text: "Error: tool call aborted before dispatch" + }], + isError: true, + error: { + message: "tool call aborted before dispatch", + info: { + name: "AbortError", + code: TOOL_ABORTED_BEFORE_DISPATCH + } + }, + ...additionalContexts.length > 0 ? { additionalContexts } : {} + }; +} +//#endregion +export { CodeRunFailedError, JsonSchemaError, RUN_CODE_NAME, TOOL_ABORTED, TOOL_ABORTED_BEFORE_DISPATCH, TOOL_RUNTIME_SCHEDULER, ToolArgsError, ToolNotFoundError, ToolOutputError, ToolRuntime, ToolRuntime as default, assertObjectJsonSchema, assertSupportedJsonSchema, defineContentToolFixture, defineTool, jsonSchemaToPy, jsonSchemaToTs, parameterSchemaSpecToJsonSchema, renderToolsSdk, renderToolsSdkPy, validateArgs, validateJsonSchemaValue, valueSchemaSpecToJsonSchema }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/invariant.js new file mode 100644 index 0000000..98bc0fa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/invariant.js @@ -0,0 +1,100 @@ +//#region lib/types/invariant.js +/** Package-owned tool-pipeline invariants. @module @deepseek-ai/dsh-tools/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-tools"; +/** Cordis companion plugin name. */ +const name = "tools-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Validate the immutable final execution/result snapshot. */ +function validateResult(exec, result, fail) { + if (!Object.isFrozen(exec)) fail("tools/result execution must be frozen before publication"); + if (!Object.isFrozen(result) || !Object.isFrozen(result.content)) fail("tools/result outcome and content must be frozen before publication"); + if (exec.name.length === 0 || String(exec.callId).length === 0) fail("tools/result execution must carry non-empty name and callId"); +} +/** Install monotonic pipeline, final-snapshot, and code-dispatch enclosure checks. */ +const install = Object.assign((ctx, fail) => { + const stages = /* @__PURE__ */ new WeakMap(); + const openTurns = /* @__PURE__ */ new WeakMap(); + const dispatchRoots = /* @__PURE__ */ new WeakMap(); + const validateDispatch = (session, event) => { + if (event.type !== "tool/code-dispatch-start" && event.type !== "tool/code-dispatch") return; + const root = String(event.data.rootCallId); + const parent = String(event.data.parentCallId); + const child = String(event.data.subCallId); + if (root.length === 0 || parent.length === 0 || child.length === 0) { + fail(`${event.type} must carry non-empty rootCallId, parentCallId, and subCallId`); + return; + } + const roots = dispatchRoots.get(session); + const known = roots?.get(child); + if (known !== void 0 && known !== root) fail(`${event.type} changed rootCallId for subCallId ${child}`); + if (parent !== root && roots?.get(parent) !== root) fail(`${event.type} parentCallId ${parent} does not belong to rootCallId ${root}`); + }; + const commitDispatch = (session, event) => { + if (event.type !== "tool/code-dispatch-start" && event.type !== "tool/code-dispatch") return; + dispatchRoots.get(session).set(String(event.data.subCallId), String(event.data.rootCallId)); + }; + const seed = (session) => { + let openTurn = null; + dispatchRoots.set(session, /* @__PURE__ */ new Map()); + for (const event of session.events) { + validateDispatch(session, event); + commitDispatch(session, event); + if (event.type === "turn/start") openTurn = event.data.turn; + else if (event.type === "turn/end") openTurn = null; + else if ((event.type === "tool/code-dispatch-start" || event.type === "tool/code-dispatch") && openTurn === null) fail(`${event.type} appended outside any open turn`); + } + openTurns.set(session, openTurn); + return openTurn; + }; + const openTurnFor = (session) => openTurns.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) seed(session); + ctx.on("session/created", (session) => { + seed(session); + }, { global: true }); + ctx.on("session/event", (session, event) => { + validateDispatch(session, event); + commitDispatch(session, event); + if (event.type === "turn/start") openTurns.set(session, event.data.turn); + else if (event.type === "turn/end") openTurns.set(session, null); + }, { global: true }); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName === "session/event") { + const [session, event] = args; + validateDispatch(session, event); + if ((event.type === "tool/code-dispatch-start" || event.type === "tool/code-dispatch") && openTurnFor(session) === null) fail(`${event.type} appended outside any open turn`); + return; + } + if (eventName === "tools/pre-execute") { + const exec = args[0]; + if (stages.has(exec)) fail("tools/pre-execute repeated for one execution"); + stages.set(exec, "pre"); + return; + } + if (eventName === "tools/execute") { + const exec = args[0]; + if (stages.get(exec) !== "pre") fail("tools/execute must follow tools/pre-execute"); + stages.set(exec, "execute"); + return; + } + if (eventName === "tools/post-execute") { + const exec = args[0]; + const previous = stages.get(exec); + if (previous !== "pre" && previous !== "execute") fail("tools/post-execute must follow tools/pre-execute or tools/execute"); + stages.set(exec, "post"); + return; + } + if (eventName !== "tools/result") return; + const [exec, result] = args; + validateResult(exec, result, fail); + stages.delete(exec); + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register the tools invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.d.ts new file mode 100644 index 0000000..b995376 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.d.ts @@ -0,0 +1,68 @@ +/** + * Code Mode `run_code` transport. Programs call the registry's agent-visible + * tools through nested executions scheduled under the native concurrency + * contract; each sub-dispatch is logged for reconstruction, while only the + * outer curated result enters model history. + * @module @deepseek-ai/dsh-tools/src/code-mode + */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { CodeRuntime } from '@deepseek-ai/dsh-code-runtime'; +import type { CodeDispatchLog, ToolDefinition, ToolRuntime } from './index.ts'; +/** The model-facing name of the Code Mode tool. */ +export declare const RUN_CODE_NAME = "run_code"; +/** The `tools:sdk` section order: inside the 100–199 tool-guidance band, after per-tool guidance sections. */ +export declare const SDK_SECTION_ORDER = 150; +/** + * The languages Code Mode ships a presentation for. Both per-language tables — + * {@link RUN_CODE_FLAVORS} here and `SDK_RENDERERS` in {@link ./index.ts} — are + * checked against this union with `satisfies`, so a language added to one and + * not the other fails `typecheck` instead of waiting for a runtime that reports + * it. The tables stay declared `Record` because `CodeRuntime.language` + * is an unconstrained `string`: this union pins what the harness ships, while the + * `Object.hasOwn` guards reject what a mounted runtime may report. + */ +export type CodeSdkLanguage = 'typescript' | 'python'; +/** + * Thrown by `run_code` when the program run itself failed — a program + * exception, a budget expiry, an abort, or substrate death. Extends + * {@link HarnessError} (`code: 'CODE_RUN_FAILED'`); the registry's execution + * pipeline converts it into a structured `isError` result whose text carries + * the failure kind plus the captured logs, so the model can self-correct. + */ +export declare class CodeRunFailedError extends HarnessError { + constructor(message: string); +} +/** + * Registry-private capabilities the bridge receives at construction — the + * `requireRuntime` idiom: operations only the owning registry can mint stay + * off its public service API and flow here as closures instead. + */ +export interface RunCodeBridgeOptions { + /** Resolves `ctx.codeRuntime` or throws the loud misconfiguration error (shared with the registry's assembly-time checks). */ + requireRuntime: () => CodeRuntime; + /** + * Reads `ctx.codeRuntime` without throwing: `undefined` when none is mounted. + * Lets schema emission tell "no runtime" (degrade to TS; the readers that + * reach it are {@link resolveFlavor}'s) apart from "unknown language" (fail + * loud). + */ + peekRuntime: () => CodeRuntime | undefined; + /** The run's overlap cap for parallel-classified sub-calls (the registry passes its validated `maxParallelSubCalls`). */ + maxParallel: number; + /** Runs the contained `tools/code-dispatch-log` waterfall over one settled sub-dispatch (the registry's private invoker). */ + shapeDispatchLog: (dispatch: CodeDispatchLog) => Promise; +} +/** + * Build the `run_code` {@link ToolDefinition}: required `code` and + * `description` parameters, executed through the dispatch bridge described + * above. The + * registry reserves it as presentation infrastructure under non-native modes, + * outside the filterable global/scoped capability layers. + * @param registry - the owning registry (sub-calls go through its `execute`, + * bindings cover its registered tools). + * @param options - the registry-private capabilities described above. + * @returns the registry-ready definition. + */ +export declare function createRunCodeTool(registry: ToolRuntime, options: RunCodeBridgeOptions): ToolDefinition; +//# sourceMappingURL=code-mode.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.js new file mode 100644 index 0000000..20f8310 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/code-mode.js @@ -0,0 +1,580 @@ +/** + * Code Mode `run_code` transport. Programs call the registry's agent-visible + * tools through nested executions scheduled under the native concurrency + * contract; each sub-dispatch is logged for reconstruction, while only the + * outer curated result enters model history. + * @module @deepseek-ai/dsh-tools/src/code-mode + */ +import { CallId, createUserMessage, HarnessError } from '@deepseek-ai/dsh-llm'; +import { snapshotJsonValue } from '@deepseek-ai/dsh-session'; +import { defineTool, parameterSchemaSpecToJsonSchema } from "./schema.js"; +import { TOOL_RUNTIME_SCHEDULER } from "./index.js"; +/** The model-facing name of the Code Mode tool. */ +export const RUN_CODE_NAME = 'run_code'; +/** The `tools:sdk` section order: inside the 100–199 tool-guidance band, after per-tool guidance sections. */ +export const SDK_SECTION_ORDER = 150; +/** + * The TypeScript flavor: the fallback for a schema read with no runtime + * mounted ({@link resolveFlavor} owns which readers reach that). A real + * assembly always resolves a runtime first, so the model never sees this + * fallback outside its own language. + */ +const TYPESCRIPT_FLAVOR = { + description: 'Execute a TypeScript program against the available tools. Takes two required ' + + 'arguments: `code`, the BODY of an async function (erasable syntax only; top-level ' + + '`await` and `return` work), and `description`, a short summary of what the program ' + + 'does. Call tools as `await tools.name(args)` per the declarations in the system ' + + 'prompt. Only what you print or return is program output — curate it. Image-bearing ' + + 'subtool results are attached after the run.', + codeDescription: 'The program: the body of an async TypeScript function.', +}; +/** + * The Python flavor: the body of an async function, top-level `await` and + * `return`, answer via `print` and/or the returned value, matching + * {@link ./py-types.ts}'s SDK instructions. + */ +const PYTHON_FLAVOR = { + description: 'Execute a Python program against the available tools. Takes two required ' + + 'arguments: `code`, the BODY of an async function (top-level `await` and `return` ' + + 'work), and `description`, a short summary of what the program does. Call tools as ' + + '`await tools.name(args)` per the declarations in the system prompt. Use ' + + '`print(...)` and/or `return ` for program output — curate it. Image-bearing ' + + 'subtool results are attached after the run.', + codeDescription: 'The program: the body of an async Python function.', +}; +/** Per-language `run_code` schema flavors (see {@link RunCodeFlavor}); one entry per {@link CodeSdkLanguage}. */ +const RUN_CODE_FLAVORS = { + typescript: TYPESCRIPT_FLAVOR, + python: PYTHON_FLAVOR, +}; +/** + * The `description` parameter's model-facing description: language-independent + * (the UI label contract is the same for every runtime), shared between the + * static spec and the language-aware `parameters` getter so the two emissions + * can never drift. + */ +const RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION = 'Clear, concise description of what this program does in active voice, ' + + '5-10 words (shown in the UI). Examples: "Count TODO markers across packages"; ' + + '"Read failing test and its fixture"; "Rename config key in every cordis.yml".'; +/** + * Resolve the {@link RunCodeFlavor} for the loaded runtime's language, read at + * schema-emission time so the model-visible `run_code` schema always matches + * the SDK section's language. `peekRuntime` returns `undefined` only when no + * runtime is mounted, which reaches this function through definition readers + * and `schemas()` — the doc-catalog harvest is the only shipped one, and none + * of them feeds a model, because `wireSchemas` calls `requireCodeRuntime` + * before projecting — so that path degrades to {@link TYPESCRIPT_FLAVOR}. A + * mounted runtime whose language has no flavor entry fails loud, exactly as + * `requireCodeRuntime` rejects it at assembly. Keeping this table in step with + * `SDK_RENDERERS` is the compiler's job ({@link CodeSdkLanguage}); what this + * guard owns is the runtime-supplied language neither table knows, which never + * yields a wrong-language schema for a real runtime. + */ +function resolveFlavor(peekRuntime) { + const runtime = peekRuntime(); + if (runtime === undefined) { + // No runtime mounted: reached by definition readers and `schemas()`, of + // which the doc-catalog harvest is the only shipped one. None feeds a + // model — `wireSchemas` calls `requireCodeRuntime` before projecting, so + // the assembly path never arrives here. Degrade to the TS default. + return TYPESCRIPT_FLAVOR; + } + // Own-property read: a language like `toString`/`constructor` would otherwise + // resolve an inherited Object.prototype member as a flavor. + const flavor = RUN_CODE_FLAVORS[runtime.language]; + if (!Object.hasOwn(RUN_CODE_FLAVORS, runtime.language) || flavor === undefined) { + const known = Object.keys(RUN_CODE_FLAVORS).map(name => JSON.stringify(name)).join(', '); + throw new Error(`dsh-tools: no run_code schema flavor registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`); + } + return flavor; +} +/** + * Thrown by `run_code` when the program run itself failed — a program + * exception, a budget expiry, an abort, or substrate death. Extends + * {@link HarnessError} (`code: 'CODE_RUN_FAILED'`); the registry's execution + * pipeline converts it into a structured `isError` result whose text carries + * the failure kind plus the captured logs, so the model can self-correct. + */ +export class CodeRunFailedError extends HarnessError { + constructor(message) { + super(message, 'CODE_RUN_FAILED'); + this.name = 'CodeRunFailedError'; + } +} +/** + * Snapshot one binding call's argument as lossless JSON, then snapshot that + * detached value again so dispatch and logging stay independent without + * reintroducing structured-clone's platform-specific nesting limit. + */ +function jsonNormalizeArgs(value) { + let snapshot; + try { + snapshot = snapshotJsonValue(value); + } + catch (error) { + throw new Error(`tool arguments must be lossless JSON: ${error instanceof Error ? error.message : String(error)}`); + } + if (snapshot === undefined) { + throw new Error('tool arguments must be lossless JSON (call the tool with an arguments object, e.g. `{}`)'); + } + const logged = snapshotJsonValue(snapshot); + /* v8 ignore next -- snapshot is already a detached lossless JSON value. */ + if (logged === undefined) { + throw new Error('tool arguments could not be detached for durable logging'); + } + return { dispatched: snapshot, logged }; +} +/** Two-space JSON presentation, matching the existing shallow `run_code` text contract. */ +const JSON_INDENT = ' '; +/** + * ECMAScript caps `JSON.stringify`'s `space` string at ten characters. The + * renderer also caps TOTAL indentation there, compacting deeper subtrees, so + * formatted output remains linear in the canonical JSON size. + */ +const MAX_JSON_INDENT_CHARS = 10; +/** Render one non-string JSON root without recursive traversal or unbounded indentation growth. */ +function renderJsonValue(value) { + const chunks = []; + const tasks = [{ kind: 'value', value, depth: 0, compact: false }]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'text') { + chunks.push(task.text); + continue; + } + const current = task.value; + if (current === null || typeof current === 'boolean' || typeof current === 'number') { + chunks.push(String(current)); + continue; + } + if (typeof current === 'string') { + chunks.push(JSON.stringify(current)); + continue; + } + const compact = task.compact || (task.depth + 1) * JSON_INDENT.length > MAX_JSON_INDENT_CHARS; + const childDepth = task.depth + 1; + if (Array.isArray(current)) { + chunks.push('['); + if (current.length === 0) { + chunks.push(']'); + continue; + } + tasks.push({ kind: 'text', text: compact ? ']' : `\n${JSON_INDENT.repeat(task.depth)}]` }); + for (let index = current.length - 1; index >= 0; index--) { + const item = current[index]; + /* v8 ignore next -- canonical JsonValue arrays are dense. */ + if (item === undefined) + throw new Error('cannot render a sparse JSON array'); + tasks.push({ kind: 'value', value: item, depth: childDepth, compact }); + tasks.push({ + kind: 'text', + text: compact + ? index === 0 ? '' : ',' + : `${index === 0 ? '\n' : ',\n'}${JSON_INDENT.repeat(childDepth)}`, + }); + } + continue; + } + const keys = Object.keys(current); + chunks.push('{'); + if (keys.length === 0) { + chunks.push('}'); + continue; + } + tasks.push({ kind: 'text', text: compact ? '}' : `\n${JSON_INDENT.repeat(task.depth)}}` }); + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index]; + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) + throw new Error('cannot render a missing JSON object key'); + const item = current[key]; + /* v8 ignore next -- canonical JsonValue records contain no undefined properties. */ + if (item === undefined) + throw new Error('cannot render an undefined JSON object property'); + tasks.push({ kind: 'value', value: item, depth: childDepth, compact }); + tasks.push({ + kind: 'text', + text: compact + ? `${index === 0 ? '' : ','}${JSON.stringify(key)}:` + : `${index === 0 ? '\n' : ',\n'}${JSON_INDENT.repeat(childDepth)}${JSON.stringify(key)}: `, + }); + } + } + return chunks.join(''); +} +/** Render one present program completion value for the model-facing result text. */ +function renderValue(value) { + return typeof value === 'string' ? value : renderJsonValue(value); +} +/** + * Build the `run_code` {@link ToolDefinition}: required `code` and + * `description` parameters, executed through the dispatch bridge described + * above. The + * registry reserves it as presentation infrastructure under non-native modes, + * outside the filterable global/scoped capability layers. + * @param registry - the owning registry (sub-calls go through its `execute`, + * bindings cover its registered tools). + * @param options - the registry-private capabilities described above. + * @returns the registry-ready definition. + */ +export function createRunCodeTool(registry, options) { + const { requireRuntime, peekRuntime, maxParallel, shapeDispatchLog } = options; + const definition = defineTool({ + name: RUN_CODE_NAME, + // The description and `code` parameter description are placeholders here: + // the language-aware getters installed below replace both, resolving the + // loaded runtime's flavor at schema-emission time so the schema the MODEL + // sees matches the SDK section's language. Argument VALIDATION still keys + // off this static spec (defineTool closes over it), which is language- + // independent (one required string `code`). + description: TYPESCRIPT_FLAVOR.description, + parameters: { + code: { type: 'string', required: true, description: TYPESCRIPT_FLAVOR.codeDescription }, + description: { + type: 'string', + required: true, + description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION, + }, + }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + logs: { type: 'array', required: true, items: { type: 'string' } }, + result: { type: 'json' }, + }, + }, + render: (_args, value) => { + const rendered = value.result === undefined ? '' : renderValue(value.result); + const parts = [value.logs.join('\n'), rendered].filter(part => part.length > 0); + return [{ type: 'text', text: parts.length > 0 ? parts.join('\n') : '(run_code completed with no output)' }]; + }, + }, + async execute(args, exec) { + if (args.description.trim().length === 0) { + throw new Error('invalid description: expected a non-empty string'); + } + const runtime = requireRuntime(); + // The run-scoped abort: follows the outer signal in, and fires when the + // run settles for ANY reason, so an in-flight sub-dispatch is aborted + // (its executor kills on this signal) instead of orphaned, and + // queued-unstarted dispatches are abandoned. + const runController = new AbortController(); + const onOuterAbort = () => { runController.abort(exec.signal.reason); }; + exec.signal.addEventListener('abort', onOuterAbort, { once: true }); + let dispatches = 0; + const pendingQueue = []; + const inFlight = new Set(); + /** Tracked settle-event side work (log-content listener + append), drained at run settlement. */ + const logWork = new Set(); + const commitQueue = []; + let exclusiveActive = false; + let driving = false; + let driverRun = Promise.resolve(); + let wake; + const wakeup = () => { + const release = wake; + wake = undefined; + release?.(); + }; + /** + * The single ordered lane. Each pass commits the head-of-line settled + * dispatch (ordered post-execute), then starts the next queued entry if + * its slot is free (ordered pre-execute), and otherwise sleeps until a + * body settles or a new submission arrives. One run reaching the + * empty-queues/empty-pool state is quiescence. + */ + const drive = () => { + if (driving) + return driverRun; + driving = true; + driverRun = (async () => { + try { + for (;;) { + // Create the wakeup promise before inspecting state so a settle or submission arriving + // between the checks and the await below cannot be lost. + const signal = new Promise((resolve) => { wake = resolve; }); + const commitHead = commitQueue[0]; + if (commitHead !== undefined && commitHead.settled) { + commitQueue.shift(); + await commitHead.commit(); + // The barrier covers post-execute: later starts wait for the + // exclusive call's full pipeline, as under the native loop. + if (commitHead.mode === 'exclusive') + exclusiveActive = false; + continue; + } + const head = pendingQueue[0]; + if (head !== undefined) { + if (runController.signal.aborted) { + pendingQueue.shift(); + head.abandon(); + continue; + } + // Reclassify at start time (fail-closed on registry changes). + const mode = head.classify(); + const capacity = !exclusiveActive + && (mode === 'exclusive' ? inFlight.size === 0 : inFlight.size < maxParallel); + if (capacity) { + if (mode === 'exclusive') + exclusiveActive = true; + head.mode = mode; + pendingQueue.shift(); + // Joined before start() so the commit cursor sees submission + // order; nothing commits it until `settled` flips. + commitQueue.push(head); + await head.start(); + const flight = head.flight.finally(() => { + inFlight.delete(flight); + wakeup(); + }); + inFlight.add(flight); + continue; + } + } + if (pendingQueue.length === 0 && commitQueue.length === 0 && inFlight.size === 0) + return; + await signal; + } + } + finally { + driving = false; + wake = undefined; + } + })(); + return driverRun; + }; + /** Every dispatch settled AND committed; nothing can start (the run is aborted at call time). */ + const drainDispatches = async () => { + // The abort already fired: the driver abandons queued-unstarted + // entries, awaits the live pool, and drains the ordered commit lane — + // including a commit already in progress when the program returned. + await drive(); + // Every settle event is appended inside the open run_code turn + // (tasks self-remove on settlement). + while (logWork.size > 0) + await Promise.allSettled([...logWork]); + }; + // Read through a call, not a bare property: the abort state genuinely + // changes across awaits, and a direct `.aborted` re-check after one + // would be narrowed away by control flow analysis. + const runOver = () => runController.signal.aborted; + const binding = (name) => async (rawArgs) => { + if (runOver()) { + throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} not dispatched`); + } + const normalized = jsonNormalizeArgs(rawArgs); + const n = ++dispatches; + const subCallId = CallId(`${String(exec.callId)}:code:${n}`); + const input = { + callId: subCallId, + rootCallId: exec.rootCallId, + name, + arguments: normalized.dispatched, + ...exec.agent ? { agent: exec.agent } : {}, + parent: exec.token, + signal: runController.signal, + }; + const scheduler = registry[TOOL_RUNTIME_SCHEDULER]; + const outcome = await new Promise((resolve, reject) => { + // Set by the dispatch stage (or start() for a pre-settled result): what commit() finalizes in submission order. + let parked; + const settle = (result) => { + // The program gets its value NOW: the log-content listener (for + // example, a spill backend) must never delay the binding or occupy + // a dispatch slot. The event append is tracked side work; the run's + // settlement drains logWork so every settle event is still appended + // inside the open turn (shapeDispatchLog is contained, so this + // chain cannot reject). + resolve(result.isError + ? { isError: true, message: result.error.message } + : { isError: false, value: result.value }); + const agent = exec.agent; + if (agent === undefined) + return; + const task = (async () => { + // The listener may replace the durable copy with a preview and + // locator; the program's value and model-visible result are + // untouched. + const logged = await shapeDispatchLog({ + exec, agent, subCallId, name, isError: result.isError, + // The registry deep-froze this projection at result + // finalization; append snapshots the final copy again, so + // the log stays detached. + content: result.content, + }); + agent.session.append('tool/code-dispatch', { + rootCallId: exec.rootCallId, + parentCallId: exec.callId, + subCallId, + name, + // The SIBLING parse of the dispatched value: byte-identical JSON, + // but a separate object — a tool mutating its args cannot desync + // this record from what it actually received. + arguments: normalized.logged, + isError: result.isError, + content: logged, + }); + })().finally(() => { logWork.delete(task); }); + logWork.add(task); + }; + pendingQueue.push({ + flight: Promise.resolve(), + settled: false, + // Re-read per driver pass against the same agent view the SDK + // declared; fail-closed exclusive when undeclared/invalid. + classify: () => registry.executionMode(input).kind, + abandon: () => { + reject(new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} tool call abandoned`)); + }, + async start() { + exec.agent?.session.append('tool/code-dispatch-start', { + rootCallId: exec.rootCallId, + parentCallId: exec.callId, + subCallId, + name, + arguments: normalized.logged, + }); + // Ordered prepare runs INSIDE the driver lane: the next entry's + // pre-execute waits for this resolution, as under the native + // scheduler. Only the launched body below overlaps. + const prepared = await scheduler.prepare(input); + if (prepared.kind === 'dispatch') { + this.flight = scheduler.dispatch(prepared.exec).then((dispatchOutcome) => { + parked = { kind: dispatchOutcome.kind, exec: prepared.exec, result: dispatchOutcome.result }; + this.settled = true; + }); + return; + } + parked = { kind: prepared.kind, exec: prepared.exec, result: prepared.result }; + this.settled = true; + }, + async commit() { + /* v8 ignore next -- commit() runs only after `settled` flipped, which set parked. */ + if (parked === undefined) + return; + const result = parked.kind === 'post-result' + ? await scheduler.finalize(parked.exec, parked.result) + : scheduler.finish(parked.exec, parked.result); + if (!result.isError && result.content.some(block => block.type === 'image')) { + exec.deferContext(createUserMessage({ + content: result.content, + source: { kind: 'plugin', plugin: 'tools-code-mode' }, + })); + } + for (const context of result.additionalContexts ?? []) { + exec.deferContext(context); + } + // The composite forwards `additionalContexts` above and + // `concludesTurn` here from the nested result. Only a successful + // nested result can carry the terminal marker + // (ToolExecutionFailure types it never), so a policy-converted + // failure cannot stop the turn through a recovering program. + if (result.concludesTurn) + exec.concludeTurn(); + settle(result); + // Backpressure on pending event-append tasks: each task retains + // a full result while a slow backend stores it, so the pool cap + // bounds their count. Beyond the cap, the + // ordered lane waits, so later sub-calls cannot start and + // pending I/O/memory cannot grow without bound. + while (logWork.size > maxParallel) + await Promise.race(logWork); + }, + }); + wakeup(); + void drive(); + }); + // A budget expiry or outer cancel that occurs while this call was in + // flight already aborted the dispatch; stop the program now rather + // than hand it a result from a run that is over. + if (runOver()) { + throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} result discarded`); + } + // The worker turns a binding rejection into ToolCallError and adds + // only the binding name. Native content and internal error metadata + // stay outside the program-facing failure contract. + if (outcome.isError) + throw new Error(outcome.message); + return outcome.value; + }; + // Null-prototype + defineProperty, mirroring the worker-side namespace + // build: a registered tool named `__proto__` must become an ordinary + // own key (a plain-object assignment would hit the prototype setter, + // silently dropping the binding), and the runtime host resolves + // binding names as own properties only. + const functions = Object.create(null); + // Enumerate the CALLING AGENT's visible set (scoped tools join, + // restricted globals vanish) — the same view the SDK section declared, + // so a program can bind exactly what its prompt promised; sub-dispatch + // re-resolves per call through the same view (exec.agent threads down). + for (const schema of registry.schemas(exec.agent)) { + if (schema.name === RUN_CODE_NAME) + continue; + Object.defineProperty(functions, schema.name, { enumerable: true, value: binding(schema.name) }); + } + try { + let result; + try { + result = await runtime.run({ + program: args.code, + bindings: [{ + global: 'tools', + functions, + errorClass: { name: 'ToolCallError', memberNameProperty: 'toolName' }, + }], + signal: runController.signal, + }); + } + finally { + // Abort sub-dispatches and drain every in-flight dispatch before + // closing the turn (queued-unstarted ones are abandoned unlogged). + // Binding failures remain observable through their individual promises. + runController.abort('run_code settled'); + await drainDispatches(); + } + if (result.error) { + const logsText = result.logs.length > 0 ? `\nCaptured output:\n${result.logs.join('\n')}` : ''; + throw new CodeRunFailedError(`code run failed (${result.error.kind}): ${result.error.message}${logsText}`); + } + return { + logs: result.logs, + ...result.value !== undefined ? { result: result.value } : {}, + }; + } + finally { + exec.signal.removeEventListener('abort', onOuterAbort); + } + }, + // The model-authored description is the call's always-visible UI label + // (the bash `description` precedent); the program itself rides rawInput. + presentCall: args => ({ + card: 'generic', + title: args.description, + kind: 'execute', + rawInput: args.code, + }), + // Deliberately no presentResult: the generic card fallback keeps this + // title and reads durable result content without duplicating a large raw + // result into the host view payload. + }); + // Resolve the language flavor lazily, at the moment the registry projects the + // schema (`schemaOf` destructures `description`/`parameters`). The definition + // is minted once at registration, before a runtime is known; deferring here + // is the least invasive point that still emits the loaded runtime's language. + Object.defineProperty(definition, 'description', { + enumerable: true, + get: () => resolveFlavor(peekRuntime).description, + }); + Object.defineProperty(definition, 'parameters', { + enumerable: true, + // Recompile through the same spec→schema projection defineTool used, so + // the emitted schema always matches the validated specification. + get: () => parameterSchemaSpecToJsonSchema({ + code: { type: 'string', required: true, description: resolveFlavor(peekRuntime).codeDescription }, + description: { type: 'string', required: true, description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION }, + }), + }); + return definition; +} +//# sourceMappingURL=code-mode.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/index.d.ts new file mode 100644 index 0000000..810014d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/index.d.ts @@ -0,0 +1,819 @@ +/** + * Tool registry, model presentation modes, and pre/guard/around/post/result + * execution pipeline. + * @module @deepseek-ai/dsh-tools + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { ScopeKey, Scoped } from '@deepseek-ai/dsh-scope'; +import type { CallId, ContentBlock, ToolSchema } from '@deepseek-ai/dsh-llm'; +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import type { JsonValue, UserMessage } from '@deepseek-ai/dsh-session'; +import type { ToolCallView, ToolResultView } from './presentation.ts'; +import type { JsonSchemaNode } from './json-schema.ts'; +export { defineTool, valueSchemaSpecToJsonSchema, parameterSchemaSpecToJsonSchema, validateArgs, ToolArgsError, type ValueSchemaAnnotations, type StringValueSchemaSpec, type NumberValueSchemaSpec, type IntegerValueSchemaSpec, type BooleanValueSchemaSpec, type NullValueSchemaSpec, type ArrayValueSchemaSpec, type ObjectValueSchemaSpec, type JsonValueSchemaSpec, type OneOfValueSchemaSpec, type ValueSchemaSpec, type ParameterPropertySpec, type ParameterSchemaSpec, type ParameterJsonSchema, type InferValue, type InferArgs, type DefineToolOptions, } from './schema.ts'; +export { assertSupportedJsonSchema, assertObjectJsonSchema, validateJsonSchemaValue, JsonSchemaError, type JsonSchemaNode, type ObjectJsonSchema, type JsonSchemaType, type JsonSchemaScalar, } from './json-schema.ts'; +export type { JsonValue } from '@deepseek-ai/dsh-session'; +export type { CodeDispatchEventData, CodeDispatchStartEventData } from './types.ts'; +export { CodeRunFailedError, RUN_CODE_NAME } from './code-mode.ts'; +export { jsonSchemaToTs, renderToolsSdk } from './ts-types.ts'; +export { jsonSchemaToPy, renderToolsSdkPy } from './py-types.ts'; +export { defineContentToolFixture, type ContentToolFixtureOptions } from './testing.ts'; +export type { ToolCallKind, FileLocation, FileDiff, ReadFileLine, ToolCallView, GenericCallView, TerminalCallView, DiffCallView, ToolResultView, GenericResultView, TerminalResultView, DiffResultView, SearchResultView, SearchMatchesResultView, SearchPathsResultView, SearchFileMatches, SearchLineMatch, ReadResultView, WebResultView, WebSearchResultView, WebFetchResultView, WebSource, } from './presentation.ts'; +declare module '@deepseek-ai/cordis' { + interface Context { + tools: ToolRuntime; + } + interface Events { + /** + * Allow, deny, or ask before dispatch. `next()` delegates to allow; missing + * approval support turns `ask` into denial. Async gates must observe + * `exec.signal`; the registry rechecks cancellation after they settle but + * never abandons their promise. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls. + * @param exec - the pending call (name, parsed arguments, caller agent). + * @mode waterfall + */ + 'tools/pre-execute'(this: Scoped, exec: ToolExecution, next: () => Promise): Promise; + /** + * Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns + * a normalized result; wrappers may change only `exec.signal`, while call + * identity remains immutable. The registry re-fuses the original caller + * signal before the body, so replacement cannot detach caller cancellation; + * wrappers must still restore their signal and reach quiescence. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls. + * @param exec - the allowed call about to dispatch (name, parsed arguments, caller agent, signal). + * @mode waterfall + */ + 'tools/execute'(this: Scoped, exec: ToolDispatchExecution, next: () => Promise): Promise; + /** + * Accept, replace, enrich, or block a normalized dispatch result. `next()` + * accepts it unchanged; thrown tools still reach this waterfall as errors. Async + * listeners must observe `exec.signal`; after they settle, caller + * cancellation replaces only a successful accepted outcome with the code + * selected by whether the tool body was invoked. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls. + * @param exec - the call that just ran (name, parsed arguments, caller agent). + * @param result - the dispatch outcome a listener may accept, replace, or block. + * @mode waterfall + */ + 'tools/post-execute'(this: Scoped, exec: ToolExecution, result: Readonly, next: () => Promise): Promise; + /** + * Allow a listener to replace content in the DURABLE LOG COPY of one + * `run_code` sub-dispatch outcome before the bridge appends its + * `tool/code-dispatch` event. `next()` keeps the + * content unchanged; a listener may return replacement blocks (e.g. the + * spill policy's preview + locator for an oversized text result). Only the + * logged copy is affected — the program already received the complete + * value, and the model sees neither. A throwing listener is contained: + * the bridge falls back to logging the original settled content. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches. + * @param dispatch - the parent execution, sub-call identity, and the settled content to log. + * @mode waterfall + */ + 'tools/code-dispatch-log'(this: Scoped, dispatch: CodeDispatchLog, next: () => Promise): Promise; + /** + * Observe the frozen, lossless-JSON final outcome. Listener failures are contained. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): keyed by `exec.agent`. + * @param exec - the execution object that traversed the pipeline. + * @param result - a deep-frozen snapshot of the final returned result. + * @mode emit + */ + 'tools/result'(this: Scoped, exec: Readonly, result: Readonly): undefined; + /** + * A tool was registered or unregistered, or a scoped restriction changed + * (the available tool set changed — possibly for one scope only). An + * UNFILTERED registry-subject notification, deliberately not scope-filtered + * dispatch: a global change concerns every agent's next assembly, so a + * scoped listener subscribing here sees every change, not just its own + * scope's. + * @mode emit + */ + 'tools/change'(): void; + } +} +/** Tool-owned canonical output contract used after the body returns a JSON value. */ +export interface ToolOutputDefinition { + /** Raw supported JSON Schema enforced against every successful canonical value. */ + readonly schema: JsonSchemaNode; + /** Pure projection from validated arguments and value to Native/model content. */ + render(args: unknown, value: JsonValue): ContentBlock[]; + /** Pure replayable presentation projection, computed only for top-level calls. */ + presentationMeta?(args: unknown, value: JsonValue): JsonValue; +} +/** A registered tool: its schema plus the execution function. */ +export interface ToolDefinition extends ToolSchema { + /** Mandatory canonical output declaration. */ + readonly output: ToolOutputDefinition; + /** + * Run one accepted call and return only its canonical lossless-JSON value. + * Async work must observe or forward `exec.signal` and settle only after its + * owned work reaches quiescence. The registry preserves caller cancellation + * through around-dispatch signal replacement and does not abandon this + * promise, but it cannot hard-kill same-process code. + * @param args - losslessly snapshotted, frozen model arguments. + * @param exec - execution identity, cancellation signal, and context deferral. + * @returns the canonical value declared by `output.schema`. + */ + execute(args: unknown, exec: ToolRunContext): Promise; + /** + * Synchronous last-mile transform for model-facing content. The registry + * snapshots this callback when execution starts and invokes it exactly once + * for every normalized outcome, including pipeline failures that bypass + * `tools/post-execute`, immediately before lossless materialization. + * Returning `undefined` preserves the content; every other result field + * remains registry-owned. The callback must be total and must not throw. + * @param exec - immutable execution identity and arguments. + * @param result - complete normalized outcome before materialization. + * @returns replacement content, or `undefined` to preserve it. + */ + finalizeContent?(exec: Readonly, result: Readonly): ContentBlock[] | undefined; + /** + * Cooperative tool-call timeout budget in milliseconds. Omit for no deadline. + * Enforced by `@deepseek-ai/dsh-tool-call-timeout-policy` (a `tools/execute` wrapper); it + * is NEVER sent to the model — `schemas()` whitelists only name/description/ + * parameters. Declaring it asserts this tool forwards `exec.signal` to a + * cooperative implementation that can reach quiescence when the signal aborts. + */ + timeoutMs?: number; + /** + * Pure synchronous classifier for overlap with sibling tool calls. Only + * `true` opts in; omission, exceptions, non-`true` returns, and invalid + * `defineTool` arguments are exclusive. This metadata is never model-visible. + * + * Opted-in executions must not mutate parent-owned state. Shared state must + * tolerate concurrent dispatch; recorder races are permitted only when they + * commute or fail closed. See the + * [parallel-tool-call Agent Note](../../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) + * for the full contract. + * @param args - parsed arguments; `defineTool` validates before calling. + * @returns Whether this call may join a parallel group. + */ + isConcurrencySafe?(args: unknown): boolean; + /** + * Optional: how to present the PENDING state of one call in a UI, derived from + * the call's `args` (parsed arguments, `unknown` — the tool validates/narrows + * its own input). Returns a {@link ToolCallView} (a `card`-tagged render intent), + * or `undefined` (or omit the method) to fall back to a generic presentation + * (title = tool name, raw args as input). Pure and side-effect-free: a UI may + * call it during live streaming AND a session-log replay, so it must depend + * only on `args`. + */ + presentCall?(args: unknown): ToolCallView | undefined; + /** + * Optional: how to present the COMPLETED state, given the same `args` and the + * durable result projection (`content`, failure state, and optional `meta`). Returns a + * {@link ToolResultView}, or `undefined` (or omit the method) to keep the + * pending title and render the raw result content. Pure and side-effect-free + * for the same replay reason. + */ + presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined; +} +/** The completed outcome handed to {@link ToolDefinition.presentResult}. */ +export interface ToolResult { + /** The final model-facing content (or the rendered error text on failure). */ + content: ContentBlock[]; + /** Whether the call failed. */ + isError: boolean; + /** + * The tool-private presentation payload projected by its output declaration + * and threaded verbatim from the `tool/result` event. Absent when the tool + * declared no projector or the call was nested under a composite transport. + */ + meta?: JsonValue; +} +declare const toolExecutionTokenBrand: unique symbol; +/** Opaque call identity that permits correlation without exposing mutable execution state. */ +export type ToolExecutionToken = symbol & { + readonly [toolExecutionTokenBrand]: true; +}; +/** + * Caller-supplied description of one tool call. {@link ToolRuntime.execute} + * adds the registry-owned token to form a pipeline {@link ToolExecution}; + * callers do not choose that token. + */ +export interface ToolExecutionInput { + readonly callId: CallId; + /** + * Root model-requested call owning this execution tree. Callers omit it for + * a root execution; nested dispatchers propagate the enclosing value. + */ + readonly rootCallId?: CallId; + readonly name: string; + /** Losslessly JSON-serializable parsed arguments (tools validate their own schema). */ + readonly arguments: unknown; + /** The agent on whose behalf the call runs (set by the agent loop). */ + readonly agent?: Agent; + /** + * Opaque token of the enclosing transport execution, when one exists. Code + * Mode sets this on SDK sub-dispatches so commit-style observers can wait for + * the outer `run_code` outcome without receiving its live mutable execution. + * The token also marks the call as a transport sub-dispatch rather than a + * model-direct call: under `mode: 'code'`, only calls WITH a parent may + * execute a native tool name — a model-direct call (no parent) is denied as + * `UNKNOWN_TOOL` before the policy pipeline. See {@link ToolRuntime.execute}. + */ + readonly parent?: ToolExecutionToken; + /** Required caller-owned cancellation for this invocation. */ + readonly signal: AbortSignal; +} +/** + * Scheduling mode for one pending call. `parallel` may overlap with siblings; + * `exclusive` runs alone and forms an ordering barrier. + */ +export type ToolExecutionMode = { + kind: 'parallel'; +} | { + kind: 'exclusive'; +}; +/** + * One settled `run_code` sub-dispatch about to be logged, as seen by the + * `tools/code-dispatch-log` waterfall: the parent execution (session owner, + * outer call identity), the sub-call identity, and the outcome whose durable + * copy a listener may reshape. `content` is the RENDERED result projection + * (what a native `tool/result` would carry) — the program itself received + * the structured `value` (or just the error message on failure); only the + * `tool/code-dispatch` event's copy changes. + */ +export interface CodeDispatchLog { + /** The outer `run_code` execution. */ + readonly exec: ToolExecution; + /** The calling agent (the scope routing key and the spill owner), when the outer call has one. */ + readonly agent?: Agent; + /** Deterministic sub-call id (`:code:`). */ + readonly subCallId: CallId; + /** The dispatched sub-tool name. */ + readonly name: string; + /** Whether the sub-call settled as an error. */ + readonly isError: boolean; + /** The sub-call's complete model-facing content (the settle event's default payload). */ + readonly content: ContentBlock[]; +} +/** + * One pending tool call inside the registry pipeline. Parsed arguments cross + * one lossless-JSON materialization boundary before policy and are deep-frozen; + * call identity, the caller signal, and the registry-assigned {@link token} are + * readonly. The registry freezes the complete object before `tools/result` + * observers run. + */ +export interface ToolExecution extends ToolExecutionInput { + /** Root model-requested call, resolved for every root and nested execution. */ + readonly rootCallId: CallId; + /** Registry-assigned identity shared with nested calls only as their opaque `parent` token. */ + readonly token: ToolExecutionToken; +} +/** + * Around-dispatch view of a {@link ToolExecution}. A `tools/execute` wrapper + * may replace the signal for its delegated lifetime, but it cannot remove it. + * The registry fuses every replacement with the captured caller signal. + */ +export interface ToolDispatchExecution extends Omit { + /** Cancellation signal visible to the next wrapper or tool body. */ + signal: AbortSignal; +} +/** + * Runtime context handed to a tool implementation after the registry has + * accepted a {@link ToolExecution}. {@link deferContext} attaches context to + * this execution's own result — a composite tool ferries nested-dispatch + * context back to the outer result, and a leaf tool may mint a fresh + * plugin-sourced instruction; the loop appends it only after the + * `tool/result`. + */ +export interface ToolRunContext extends ToolExecution { + /** + * Defer one context — typically a nested-dispatch context ferried by a + * composite tool, or a fresh plugin-sourced instruction — until this tool's + * final result reaches the agent loop. Contexts retain their individual + * source and metadata and are emitted in call order. + */ + deferContext(context: UserMessage): void; + /** + * Mark a successful final result as terminal for the current agent turn. + * The marker rides this execution's own result (`concludesTurn` exists only + * on {@link ToolExecutionSuccess}); a composite that dispatches nested + * calls forwards it from the nested result, exactly like + * `additionalContexts`, so only an authoritative nested success can + * conclude the enclosing run. + */ + concludeTurn(): void; +} +/** + * Scheduler-only result after ordered pre-execute and guards. A `post-result` + * still receives post-execute; a `final-result` bypasses it. + * @internal + */ +export type ScheduledToolPreparation = { + kind: 'dispatch'; + exec: ToolRunContext; +} | { + kind: 'post-result'; + exec: ToolRunContext; + result: ToolExecutionResult; +} | { + kind: 'final-result'; + exec: ToolRunContext; + result: ToolExecutionResult; +}; +/** + * Scheduler-only dispatch result. A `post-result` still receives post-execute; + * a `final-result` already matches {@link ToolRuntime.execute} failure semantics. + * @internal + */ +export type ScheduledToolDispatch = { + kind: 'post-result'; + result: ToolExecutionResult; +} | { + kind: 'final-result'; + result: ToolExecutionResult; +}; +/** + * Symbol-keyed scheduler view that keeps pre/post policy ordered while + * overlapping dispatch. Ordinary callers use {@link ToolRuntime.execute}; + * this is not a plugin extension point. + * @internal + */ +export interface ToolRuntimeScheduler { + /** Materialize input, run the ordered pre-execute/guard gate, and decide what stage follows. */ + prepare(exec: ToolExecutionInput): Promise; + /** Run only the around-dispatch/body stage. */ + dispatch(exec: ToolRunContext): Promise; + /** Run post-execute and definition-owned content finalization, then materialize and notify. */ + finalize(exec: ToolRunContext, result: ToolExecutionResult): Promise; + /** Run definition-owned content finalization, then materialize and notify without post-execute. */ + finish(exec: ToolRunContext, result: ToolExecutionResult): ToolExecutionResult; +} +/** + * Scheduler entry point omitted from the generated named service API. + * @internal + */ +export declare const TOOL_RUNTIME_SCHEDULER: unique symbol; +/** Canonical error code for cancellation after a tool body was invoked. */ +export declare const TOOL_ABORTED = "ABORTED"; +/** Canonical error code for cancellation before a tool body was invoked. */ +export declare const TOOL_ABORTED_BEFORE_DISPATCH = "ABORTED_BEFORE_DISPATCH"; +/** Structured error metadata for a failed tool call (alongside the model-facing text). */ +export interface ToolErrorInfo { + name: string; + code: string; +} +/** Canonical failure detail; internal routing information remains optional. */ +export interface ToolFailure { + /** Human-readable failure message without the Native `Error: ` envelope. */ + message: string; + /** Internal error class/code used by policy and durable diagnostics. */ + info?: ToolErrorInfo; +} +/** + * Thrown (internally) when the model requests a tool that isn't registered. + * Extends {@link HarnessError} (`code: 'UNKNOWN_TOOL'`) so an unknown-tool + * failure is as routable as a tool-thrown one — retry/sandbox/replay code can + * distinguish it from a tool body's own error. + */ +export declare class ToolNotFoundError extends HarnessError { + /** + * @param toolName - the name the caller asked for. + * @param reachableFrom - how the model reaches this tool instead, when the + * name IS visible and only the presentation denies calling it directly. + * Omitted for a name that is registered nowhere. + */ + constructor(toolName: string, reachableFrom?: string); +} +/** Thrown when a tool body or post-policy value violates its declared output. */ +export declare class ToolOutputError extends HarnessError { + /** Schema/value violations in validation order. */ + readonly violations: string[]; + constructor(toolName: string, violations: string[]); +} +/** Successful canonical tool execution, including its Native/model projection. */ +export interface ToolExecutionSuccess { + readonly isError: false; + /** Execution-local canonical value; deliberately omitted from durable events. */ + readonly value: JsonValue; + readonly content: ContentBlock[]; + readonly error?: never; + readonly meta?: JsonValue; + readonly additionalContexts?: UserMessage[]; + /** The agent loop stops after committing this successful result batch. */ + readonly concludesTurn?: true; +} +/** Failed canonical tool execution; failures never carry a successful value. */ +export interface ToolExecutionFailure { + readonly isError: true; + readonly error: ToolFailure; + readonly value?: never; + readonly content: ContentBlock[]; + readonly meta?: JsonValue; + readonly additionalContexts?: UserMessage[]; + readonly concludesTurn?: never; +} +/** The discriminated, execution-local outcome of one tool call. */ +export type ToolExecutionResult = ToolExecutionSuccess | ToolExecutionFailure; +/** + * Pre-dispatch decision. `allow` runs the call; `deny` materializes an error; + * `ask` runs only after an approval service returns `allowed-once` and otherwise + * denies. Input rewriting is excluded because arguments are already logged and + * presented. + */ +export type PreToolDecision = { + kind: 'allow'; +} | { + kind: 'deny'; + reason: string; +} | { + kind: 'ask'; + reason?: string; +}; +/** + * Post-dispatch decision: accept, replace one projection, attach context for the + * next request, or block by turning corrective feedback into an error result. + */ +export type PostToolDecision = { + kind: 'accept'; + content?: ContentBlock[]; + value?: never; + additionalContexts?: UserMessage[]; +} | { + kind: 'accept'; + value: JsonValue; + content?: never; + additionalContexts?: UserMessage[]; +} | { + kind: 'block'; + feedback: ContentBlock[]; + additionalContexts?: UserMessage[]; +}; +/** How the registry presents its tools to the model (see {@link Config.mode}). */ +export type ToolPresentationMode = 'native' | 'code' | 'both'; +/** Plugin config: how the registered tools are presented to the model. */ +export interface Config { + /** + * Model presentation. `native` (default) sends every visible schema; `code` + * sends only `run_code` plus a generated SDK prompt and collapses the + * executor to the same surface (a model-direct call may only name + * `run_code`; `run_code` SDK sub-dispatches keep every visible tool); `both` + * sends both forms. Code modes require a `ctx.codeRuntime` whose `language` + * has a registered SDK renderer (TypeScript or Python) and fail prompt + * assembly when it is absent or has no renderer. Under `code`, native names + * in `toolOrder` are invalid. + */ + mode?: ToolPresentationMode; + /** + * Concurrency cap for a `run_code` program's overlapping sub-calls + * (default 10, the loop scheduler's own default). Sub-calls follow the + * native scheduling contract — only calls whose tools classify + * concurrency-safe overlap; exclusive calls form barriers — so `1` + * restores strictly serial dispatch. Must be a positive integer. + */ + maxParallelSubCalls?: number; +} +/** + * Per-scope filter over global tools. Restrictions intersect and do not affect + * scoped registrations or the reserved Code Mode transport. + */ +export interface ToolRestriction { + /** Global tool names that stay visible; everything else is removed. */ + readonly allow?: readonly string[]; + /** Global tool names removed from visibility. */ + readonly deny?: readonly string[]; +} +/** + * A monotonic execution guard evaluated after every `tools/pre-execute` + * listener and before the tool body. Returning a reason denies the call; + * returning `undefined` leaves it unchanged. Because guards have no allow + * result, listener ordering cannot turn a denial back into permission. + * @param execution - the identity-protected call after extensible pre-execute policy completed. + * @returns a final denial reason, or `undefined` to leave the call allowed. + */ +export type ToolGuard = (execution: Readonly) => string | undefined; +/** + * Tool registry and execution pipeline. Scoped registrations shadow globals; + * one visibility resolver feeds presentation, lookup, and dispatch. + */ +export declare class ToolRuntime extends Service { + static inject: string[]; + static Config: z; + /** Internal staged view consumed by `dsh-agent-loop`'s parallel scheduler. */ + readonly [TOOL_RUNTIME_SCHEDULER]: ToolRuntimeScheduler; + /** Context deferred by a running tool body, keyed by its scheduler-owned execution. */ + private deferredContexts; + /** Executions whose tool body declared the current turn complete. */ + private concludingExecutions; + /** Original caller cancellation, kept outside the wrapper-mutable execution object. */ + private cancellationStates; + /** Definition-owned final content transform snapshotted before policy begins. */ + private contentFinalizers; + private readonly layers; + /** Presentation for scopes that declare none; {@link presentAs} shadows it per scope. */ + private readonly defaultMode; + private readonly maxParallelSubCalls; + /** + * Reserved presentation transport, kept outside the filterable registration + * layers. Built on first need rather than at construction: which agents run + * a code mode is no longer known when the service is constructed, and the + * transport is stateless beyond its closures over `this`. + */ + private codeTransport; + constructor(ctx: Context, config?: Config); + /** + * The prompt statement of the `code` executor collapse, registered wherever + * {@link sdkSection} is and rendering empty outside an effective `code`. + * + * Every tool contributes its own guidance section naming its tool, none of + * them qualify how that tool is reached, and they all render before the SDK + * (orders 100-199 against {@link SDK_SECTION_ORDER}). Without this the model + * reads a catalog of tools it is told to use and no statement that only + * `run_code` may be called, so it emits a native call, receives + * `UNKNOWN_TOOL` for a tool the prompt just declared, and concludes the + * deployment is inconsistent. {@link COLLAPSE_SECTION_ORDER} places the rule + * before that guidance rather than after it. + * + * `both` renders empty: native calls do execute there, so the rule is false. + * @returns the section registration. + */ + private collapseSection; + /** + * The generated-SDK prompt section, registered globally by a code-mode + * deployment and per scope by {@link presentAs}. + * + * The body regenerates from the CALLING scope, and renders empty for an + * agent presenting natively — an agent that opted out under a code-mode + * deployment still sees the global registration, and an empty section is + * dropped from the rendered prompt. + * @returns the section registration. + */ + private sdkSection; + /** + * The presentation one scope's agent sees: its own declaration, else the + * deployment default. + * @param scope - the calling agent, or undefined for the global view. + * @returns the resolved presentation mode. + */ + private modeFor; + /** + * The reserved `run_code` transport, built on first need. + * + * It never enters the global layer: per-agent restrictions must not remove + * it, and a scoped registration must not shadow it. The visibility resolver + * appends it after resolving the filterable global/scoped capability layers, + * and only for scopes whose mode actually presents it. + * @returns the shared transport definition. + */ + private requireCodeTransport; + /** + * Present the calling scope's tools in `mode` instead of the deployment + * default. Nearest scope on the chain wins, so a preset's standing + * declaration covers every agent joined under it. + * + * Scoped only, and one declaration per scope: this is how an agent preset + * composes Code Mode agents beside native ones in the same process, and a + * process-global override would be the `mode` config field instead. + * @param mode - the presentation the covered agents' models see. + * @returns the exact disposer that restores the deployment default. + */ + presentAs(mode: ToolPresentationMode): () => void; + /** + * Build one scope's wire schemas and names for prompt-order validation. + * Restrictions do not make known tools invalid, but a mode collapse does. + */ + private wireSchemas; + /** + * Resolve the code runtime or throw the actionable misconfiguration error. + * Read at use time (assembly / run_code execution), NOT via static + * `inject`: an inject entry would hold `ctx.tools` — and every tool plugin + * behind it — hostage to a code runtime existing even under `mode: + * 'native'` (the loop's optional-backend idiom, same as + * `sessionPersistence`). + * + * Assembly and `run_code` execution read separately, so the language is not + * bound to a request. Harmless while one published backend exists — both + * reads return the same flavor — but a reload that swapped in a second + * language between them would hand a program written against one SDK to the + * other. Binding it is deferred until a second backend ships (the first + * point it is testable); rationale in the + * [language-dispatch note](../../../../.agents/notes/implemented/feature/2026-07-31-code-mode-language-dispatch.md). + */ + private requireCodeRuntime; + /** + * Register globally or in the calling agent scope. Scoped tools shadow + * globals; duplicates within one layer and the reserved `run_code` name fail. + * @param definition - tool schema, execution, and optional finalization/presentation callbacks. + * @returns the exact disposer that unregisters the tool. + */ + register(definition: ToolDefinition): () => void; + /** + * Restrict global tools for the calling agent scope. Empty filters, unknown + * names, scope-local names, and reserved transport names fail. Restrictions + * intersect; scoped registrations remain visible. + * @param filter - global-tool mask: `allow` (keep only) and/or `deny` (remove). + * @returns the exact disposer that lifts this restriction. + */ + restrict(filter: ToolRestriction): () => void; + /** + * Register a monotonic guard after the extensible `tools/pre-execute` + * waterfall. A plain-context guard applies globally; one registered through + * `agent.ctx` applies only to that agent. Any matching guard may deny by + * returning a reason, while no guard can force-allow a call another guard + * denied. The exact effect disposer is returned for ordered ownership and + * HMR cleanup. + * @param guard - synchronous check; a returned string denies the execution. + * @returns the exact disposer that unregisters the guard. + */ + guard(guard: ToolGuard): () => void; + /** First monotonic denial from the global then the scope chain's guard layers, farthest first. */ + private guardReason; + /** + * Resolve every registry fact one scope needs in one layer traversal. The + * visible map applies restrictions to the INHERITED surface, then the + * scope's own registrations and the reserved presentation transport; the + * other sets retain the pre-restriction facts needed by restriction and + * prompt-order validation. + * + * A restriction filters what a scope inherits — the global layer and every + * ancestor layer on its chain — and never what its OWN layer registers. + * That exemption is what a per-child capability filter has to keep intact: + * the delegation runtime registers a child's reporting and structured-output + * tools into the child's own layer, and a filter naming the capabilities the + * child may use must not strip the machinery it answers through. + * + * Reading the exempt set as "the global layer" instead of "not mine" held + * only while every model-facing tool sat in the host composition. Once + * presets moved them onto the agent plane they became an ANCESTOR + * contribution, so a child's filter silently stopped constraining anything + * it was given. + * @param scope - the viewing scope (the agent), or undefined for the global view. + * @returns the complete derived view for that scope. + */ + private view; + /** + * Look up a tool as one scope sees it (scoped + * shadows global; a restricted-away global reads as absent). Presenters pass + * the calling agent so the rendered card matches the definition that + * actually executed. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns the definition the scope resolves, or undefined when none is visible. + */ + get(name: string, scope?: ScopeKey): ToolDefinition | undefined; + /** + * Resolve the definition that MAY EXECUTE for a call, applying the mode + * collapse at the operation boundary that owns it. The registry view + * (`get`) is presentation-agnostic; here a MODEL-DIRECT call under `code` + * may only name the reserved `run_code` transport, while a nested + * sub-dispatch (a `parent` token set — the `run_code` SDK calling a tool + * it bound) may call any visible tool. Denial surfaces as `UNKNOWN_TOOL` + * through the executor, matching an absent definition. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + * @returns the definition that may run, or undefined when the call must be rejected. + */ + private resolveExecution; + /** + * Project visible definitions onto the allowlisted model-facing schema fields, + * excluding execution and presentation callbacks. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns one deep-cloned schema per visible tool. + */ + schemas(scope?: ScopeKey): ToolSchema[]; + /** Project visible callable tools onto the generated Code Mode SDK contract. */ + private sdkSchemas; + /** Project one definition onto the model-facing schema fields. */ + private schemaOf; + /** + * Classify a pending call through the caller's visible tool definition. Only + * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or + * throwing classifiers are exclusive. + * @param exec - call name, parsed arguments, and optional agent scope. + * @returns the fail-closed scheduling mode. + */ + executionMode(exec: ToolExecutionInput): ToolExecutionMode; + /** + * Run the `tools/code-dispatch-log` waterfall over one settled sub-dispatch + * and return the content the bridge should log on `tool/code-dispatch`. + * Contained: when a listener throws, the method logs the original settled + * content; that failure must not fail the dispatch or omit the settle event. Private: + * the ONE consumer is the `run_code` bridge this registry constructs, which + * receives it as a capability parameter (the `requireRuntime` idiom) — the + * waterfall, not this invoker, is the public extension point. + */ + private shapeDispatchLog; + /** + * Whether the `code` mode collapse denies a model-direct call: only the + * reserved `run_code` transport may be named. Nested sub-dispatches (a + * `parent` token set) bypass the collapse. One home for the + * security-relevant predicate, shared by {@link resolveExecution} and + * {@link createExecution} so the two can never drift apart. + * + * Resolved through {@link modeFor}, NOT `defaultMode`: an agent given `code` + * by an agent preset under a native deployment is the composition + * `dsh-agent-tool-presentation` exists for, and reading the deployment default would + * leave exactly that agent uncollapsed — announcing one surface while + * executing another, which is the bypass this collapse closes. + * @param name - the tool name as registered. + * @param scope - the viewing scope whose effective presentation mode applies. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + */ + private collapses; + /** + * Execute through pre-policy, guards, around-dispatch, post-policy, + * definition-owned content finalization, and final notification. Tool and + * listener failures resolve as materialized error results; an invisible tool + * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen + * snapshot final observers receive. Cancellation + * arriving after entry and before final result materialization skips a + * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a + * successful started outcome with `ABORTED`; already-started work is still + * drained and may retain a tool-owned structured error. + * @param exec - the typed same-process call input. The registry assigns its + * correlation token before policy begins. + * @returns the materialized final result. + */ + execute(exec: ToolExecutionInput): Promise; + private completeScheduledExecution; + private createExecution; + /** + * Run the ordered pre-execute and monotonic guard stages for the scheduler. + * @param input - the caller-supplied execution input. + * @returns the prepared execution plus the next scheduler stage. + * @internal + */ + private prepareScheduledExecution; + private prepareExecution; + /** Whether the original caller signal is currently aborted. */ + private callerCancelled; + /** Canonical cancellation outcome selected by whether the tool body started. */ + private cancellationResult; + /** + * Dispatch the registered body with the original caller signal fused back + * into any around-wrapper replacement. Cancellation never abandons the body: + * a started promise reaches quiescence before its outcome becomes `ABORTED`. + */ + private dispatchToolBody; + /** + * Run around-dispatch and the tool body. Tool and unknown-tool failures still + * receive post-execute; pipeline failures are already final. + * @param exec - the prepared execution. + * @returns whether the result still needs post-execute. + * @internal + */ + private dispatchScheduledExecution; + /** + * Run ordered post-execute, then apply definition-owned content finalization, + * materialize, and notify the final outcome. + * @param exec - the prepared execution. + * @param result - dispatch/pre result that still needs post-execute. + * @returns the materialized final result. + * @internal + */ + private finalizeScheduledExecution; + /** + * Materialize the candidate, apply definition-owned content finalization, + * then materialize and notify the authoritative result. + * @param exec - the prepared execution. + * @param result - final result. + * @returns the materialized final result. + * @internal + */ + private finishScheduledExecution; + /** Apply the snapshotted tool-owned content transform without exposing other result fields. */ + private applyFinalContent; + /** Notify observers without exposing a mutation or error channel into the outcome. */ + private notifyResult; + /** + * Resolve an `ask` decision to allow/deny through the approval seam. The + * seam is consumed opportunistically with `ctx.get('approval')` — a + * deployment that composes no ApprovalService keeps the historical degrade + * to deny, and an unmount mid-session degrades the same way on the next ask. + * An agent-less execution also degrades: without an agent there is no + * session to audit to and no UI to route to. Otherwise the outcome maps + * one-to-one — `allowed-once` proceeds; the three non-grants deny with + * distinct reasons so the model can tell a human "no" from an absent + * approval channel. + */ + private serviceAsk; + /** + * Run the `tools/post-execute` waterfall over a dispatched `result` and apply + * its {@link PostToolDecision}: `accept` keeps the call successful (replacing + * `content` when given), `block` turns it into an `isError` whose content is + * the corrective `feedback`. Either decision may attach `additionalContexts`, + * which are ferried on the returned result for the loop's active-batch FIFO. + * Context deferred by the tool body survives an accepted result but is + * discarded when the outer call is blocked; a block exposes only context the + * blocking decision explicitly supplied. + * Runs inside `execute`'s outer try/catch (a throwing listener → isError). + */ + private postExecute; + /** Registry-normalized results and the exact dispatch that validated each value. */ + private readonly canonicalResults; + /** Mark one registry-normalized result as canonical only for its owning dispatch. */ + private markCanonical; + /** Snapshot, validate, render, and optionally project one successful body value. */ + private createSuccessResult; + /** Normalize an around-dispatch wrapper's authored result through the owning output contract. */ + private normalizeDispatchResult; + /** Materialize the authoritative commit outcome once, immediately before `tools/result`. */ + private materializeFinalResult; +} +export default ToolRuntime; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/index.js new file mode 100644 index 0000000..24d86f1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/index.js @@ -0,0 +1,1326 @@ +/** + * Tool registry, model presentation modes, and pre/guard/around/post/result + * execution pipeline. + * @module @deepseek-ai/dsh-tools + */ +import { Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { AnonymousEntries, NamedEntries, ScopedLayers, scopeOf, scopeTarget } from '@deepseek-ai/dsh-scope'; +import { assertNever, deepFreeze, HarnessError } from '@deepseek-ai/dsh-llm'; +import { snapshotJsonValue } from '@deepseek-ai/dsh-session'; +import { assertSupportedJsonSchema, validateJsonSchemaValue } from "./json-schema.js"; +import { createRunCodeTool, RUN_CODE_NAME, SDK_SECTION_ORDER } from "./code-mode.js"; +import { renderToolsSdk } from "./ts-types.js"; +import { renderToolsSdkPy } from "./py-types.js"; +/** + * Language → SDK-section renderer. The registry looks up the loaded + * `ctx.codeRuntime.language` in this table when assembling the `tools:sdk` + * section under a non-native mode; a runtime whose language is not a key + * fails the assembly loudly (same idiom as `toolOrder` violations). Adding a + * new backend language is three parallel edits — a {@link CodeSdkLanguage} + * member, an entry here, and a `RUN_CODE_FLAVORS` entry in `code-mode.ts` for + * its `run_code` schema strings — plus the renderer function this table points + * at. The `satisfies` clause pins this table's key set to that union, which + * the flavor table is checked against too, so any of the three left out is a + * typecheck failure. What no check reaches is the prose that names the values + * instead of deriving them: the seam's `dsh-code-runtime` README pair, its + * `CodeRuntime.language` JSDoc, and `docs/subsystems/code-runtime.md` + * with its zh pair, plus this package's own README pair and the + * {@link Config.mode} JSDoc. + */ +/** + * Prompt order of the `code` collapse statement: after the persona and before + * the 100-199 per-tool guidance band, so the model reads which tools it may + * call before it reads what each one is for. + */ +const COLLAPSE_SECTION_ORDER = 99; +/** + * The model-facing statement of the `code` collapse. Names the consequence + * (the call fails) and the route (inside the program), because a rule the + * model can only discover by being denied is one it corrects too late. + */ +const CODE_ONLY_INSTRUCTION = `\`${RUN_CODE_NAME}\` is the only tool you can call directly — a tool call naming any other tool fails. Reach every tool the SDK declares below from inside the program.`; +const SDK_RENDERERS = { + typescript: renderToolsSdk, + python: renderToolsSdkPy, +}; +export { defineTool, valueSchemaSpecToJsonSchema, parameterSchemaSpecToJsonSchema, validateArgs, ToolArgsError, } from "./schema.js"; +export { assertSupportedJsonSchema, assertObjectJsonSchema, validateJsonSchemaValue, JsonSchemaError, } from "./json-schema.js"; +export { CodeRunFailedError, RUN_CODE_NAME } from "./code-mode.js"; +export { jsonSchemaToTs, renderToolsSdk } from "./ts-types.js"; +export { jsonSchemaToPy, renderToolsSdkPy } from "./py-types.js"; +export { defineContentToolFixture } from "./testing.js"; +/** + * Scheduler entry point omitted from the generated named service API. + * @internal + */ +export const TOOL_RUNTIME_SCHEDULER = Symbol('@deepseek-ai/dsh-tools.scheduler'); +/** Canonical error code for cancellation after a tool body was invoked. */ +export const TOOL_ABORTED = 'ABORTED'; +/** Canonical error code for cancellation before a tool body was invoked. */ +export const TOOL_ABORTED_BEFORE_DISPATCH = 'ABORTED_BEFORE_DISPATCH'; +/** + * Thrown (internally) when the model requests a tool that isn't registered. + * Extends {@link HarnessError} (`code: 'UNKNOWN_TOOL'`) so an unknown-tool + * failure is as routable as a tool-thrown one — retry/sandbox/replay code can + * distinguish it from a tool body's own error. + */ +export class ToolNotFoundError extends HarnessError { + /** + * @param toolName - the name the caller asked for. + * @param reachableFrom - how the model reaches this tool instead, when the + * name IS visible and only the presentation denies calling it directly. + * Omitted for a name that is registered nowhere. + */ + constructor(toolName, reachableFrom) { + super(reachableFrom === undefined + ? `unknown tool "${toolName}"` + : `unknown tool "${toolName}": ${reachableFrom}`, 'UNKNOWN_TOOL'); + this.name = 'ToolNotFoundError'; + } +} +/** Thrown when a tool body or post-policy value violates its declared output. */ +export class ToolOutputError extends HarnessError { + /** Schema/value violations in validation order. */ + violations; + constructor(toolName, violations) { + super(`tool "${toolName}" returned invalid output: ${violations.join('; ')}`, 'INVALID_TOOL_OUTPUT'); + this.name = 'ToolOutputError'; + this.violations = violations; + } +} +/** Convert one projector exception into the canonical invalid-output failure. */ +function projectionError(toolName, projector, error) { + return new ToolOutputError(toolName, [`output.${projector} failed: ${errorMessage(error)}`]); +} +/** Snapshot one projector result before later durable-result materialization. */ +function snapshotProjection(toolName, projector, candidate) { + try { + const detached = snapshotJsonValue(candidate); + if (detached === undefined) { + throw new ToolOutputError(toolName, [`output.${projector} returned non-lossless JSON`]); + } + return detached; + } + catch (error) { + if (error instanceof ToolOutputError) + throw error; + throw projectionError(toolName, projector, error); + } +} +/** Snapshot one body or policy value into the canonical invalid-output failure class. */ +function snapshotToolValue(toolName, candidate) { + try { + const detached = snapshotJsonValue(candidate); + if (detached === undefined) + throw new ToolOutputError(toolName, ['value is not lossless JSON']); + return detached; + } + catch (error) { + if (error instanceof ToolOutputError) + throw error; + throw new ToolOutputError(toolName, [`value snapshot failed: ${errorMessage(error)}`]); + } +} +/** + * Best-effort human-readable message from an arbitrary thrown value: Error + * instances use `.message`; non-Error objects with a string `message` + * property (e.g. `throw { message: 'denied' }`) use it too; everything else + * is stringified. + */ +function errorMessage(error) { + try { + if (error instanceof Error) + return error.message; + if (typeof error === 'object' && error !== null + && 'message' in error && typeof error.message === 'string') { + return error.message; + } + return String(error); + } + catch { + // A hostile thrown value can trap `instanceof`, property access, or string + // coercion. Error normalization is the outermost safety boundary, so its + // fallback must itself be total. + return ''; + } +} +/** Derive one failure message from policy feedback without changing its rendered blocks. */ +function failureMessageFromContent(content) { + const text = content + .map(block => block.type === 'text' ? block.text : `[${block.type} content]`) + .join('\n'); + return text.length > 0 ? text : 'tool result blocked by post-execute policy'; +} +/** Snapshot and freeze one durable tool-result projection or reject lossy data. */ +function materializePresentation(candidate) { + const detached = snapshotJsonValue(candidate); + if (detached === undefined) { + throw new TypeError('tool result must be losslessly JSON-serializable'); + } + return deepFreeze(detached); +} +/** Structured `{ name, code }` for a thrown HarnessError, else undefined. */ +function errorInfo(error) { + try { + return error instanceof HarnessError ? { name: error.name, code: error.code } : undefined; + } + catch { + return undefined; + } +} +/** One scope's complete tool-registry contribution. */ +class ToolLayer { + tools; + restrictions = new AnonymousEntries(); + guards = new AnonymousEntries(); + /** + * Presentation this scope's agent declared for itself, shadowing the + * deployment default. One cell rather than an entry table: two answers to + * "which form does the model see" is a contradiction, not a merge. + */ + mode; + constructor(scope) { + this.tools = new NamedEntries(name => new Error(scope === undefined + ? `tool "${name}" is already registered (for a per-agent variant, register through that agent's \`agent.ctx\` instead)` + : `tool "${name}" is already registered in this scope`)); + } + /** Whether every contribution table in this aggregate layer is empty. */ + isEmpty() { + return this.tools.isEmpty() && this.restrictions.isEmpty() && this.guards.isEmpty() + && this.mode === undefined; + } + /** Whether every compiled restriction in this layer admits a global tool name. */ + admits(name) { + for (const filter of this.restrictions.values()) { + if ((filter.allow !== undefined && !filter.allow.has(name)) + || (filter.deny !== undefined && filter.deny.has(name))) + return false; + } + return true; + } + /** First monotonic denial from this layer's live guard registrations. */ + guardReason(exec) { + for (const guard of this.guards.values()) { + const reason = guard(exec); + if (reason !== undefined) + return reason; + } + return undefined; + } +} +/** Resolve the run_code overlap cap at the owning config boundary (direct construction bypasses the Loader schema). */ +function resolveMaxParallelSubCalls(value) { + const maxParallelSubCalls = value ?? 10; + if (!Number.isInteger(maxParallelSubCalls) || maxParallelSubCalls < 1) { + throw new Error('maxParallelSubCalls must be a positive integer'); + } + return maxParallelSubCalls; +} +/** + * Tool registry and execution pipeline. Scoped registrations shadow globals; + * one visibility resolver feeds presentation, lookup, and dispatch. + */ +export class ToolRuntime extends Service { + static inject = ['systemPrompt']; + static Config = z.object({ + mode: z.union(['native', 'code', 'both']).default('native'), + maxParallelSubCalls: z.natural().min(1).default(10), + }); + /** Internal staged view consumed by `dsh-agent-loop`'s parallel scheduler. */ + [TOOL_RUNTIME_SCHEDULER] = { + prepare: exec => this.prepareScheduledExecution(exec), + dispatch: exec => this.dispatchScheduledExecution(exec), + finalize: (exec, result) => this.finalizeScheduledExecution(exec, result), + finish: (exec, result) => this.finishScheduledExecution(exec, result), + }; + /** Context deferred by a running tool body, keyed by its scheduler-owned execution. */ + deferredContexts = new WeakMap(); + /** Executions whose tool body declared the current turn complete. */ + concludingExecutions = new WeakSet(); + /** Original caller cancellation, kept outside the wrapper-mutable execution object. */ + cancellationStates = new WeakMap(); + /** Definition-owned final content transform snapshotted before policy begins. */ + contentFinalizers = new WeakMap(); + layers = new ScopedLayers(scope => new ToolLayer(scope), () => { this.ctx.emit('tools/change'); }); + /** Presentation for scopes that declare none; {@link presentAs} shadows it per scope. */ + defaultMode; + maxParallelSubCalls; + /** + * Reserved presentation transport, kept outside the filterable registration + * layers. Built on first need rather than at construction: which agents run + * a code mode is no longer known when the service is constructed, and the + * transport is stateless beyond its closures over `this`. + */ + codeTransport; + constructor(ctx, config = {}) { + super(ctx, 'tools'); + // The schema already defaulted an omitted mode; the ?? narrows the + // optional-input type for direct (non-Loader) construction in tests. + this.defaultMode = config.mode ?? 'native'; + this.maxParallelSubCalls = resolveMaxParallelSubCalls(config.maxParallelSubCalls); + ctx.systemPrompt.tools(context => this.wireSchemas(context.scope)); + if (this.defaultMode !== 'native') { + ctx.systemPrompt.section(this.collapseSection()); + ctx.systemPrompt.section(this.sdkSection()); + } + } + /** + * The prompt statement of the `code` executor collapse, registered wherever + * {@link sdkSection} is and rendering empty outside an effective `code`. + * + * Every tool contributes its own guidance section naming its tool, none of + * them qualify how that tool is reached, and they all render before the SDK + * (orders 100-199 against {@link SDK_SECTION_ORDER}). Without this the model + * reads a catalog of tools it is told to use and no statement that only + * `run_code` may be called, so it emits a native call, receives + * `UNKNOWN_TOOL` for a tool the prompt just declared, and concludes the + * deployment is inconsistent. {@link COLLAPSE_SECTION_ORDER} places the rule + * before that guidance rather than after it. + * + * `both` renders empty: native calls do execute there, so the rule is false. + * @returns the section registration. + */ + collapseSection() { + return { + name: 'tools:code-only', + order: COLLAPSE_SECTION_ORDER, + // The SAME predicate the executor denies by, so the prompt cannot state + // a rule the registry does not enforce (see `collapses`). + text: context => this.modeFor(context.scope) === 'code' ? CODE_ONLY_INSTRUCTION : '', + }; + } + /** + * The generated-SDK prompt section, registered globally by a code-mode + * deployment and per scope by {@link presentAs}. + * + * The body regenerates from the CALLING scope, and renders empty for an + * agent presenting natively — an agent that opted out under a code-mode + * deployment still sees the global registration, and an empty section is + * dropped from the rendered prompt. + * @returns the section registration. + */ + sdkSection() { + return { + name: 'tools:sdk', + order: SDK_SECTION_ORDER, + // Regenerate from the calling scope's visible tools in stable order. + text: (context) => { + const mode = this.modeFor(context.scope); + if (mode === 'native') + return ''; + const runtime = this.requireCodeRuntime(mode); + // Own-property read: a language like `toString`/`constructor` would + // otherwise resolve an inherited Object.prototype member as a renderer. + const render = SDK_RENDERERS[runtime.language]; + /* v8 ignore next -- requireCodeRuntime rejects an unknown language before this runs. */ + if (render === undefined) + throw new Error(`dsh-tools: no SDK renderer for ${runtime.language}`); + return render(this.sdkSchemas(context.scope)); + }, + }; + } + /** + * The presentation one scope's agent sees: its own declaration, else the + * deployment default. + * @param scope - the calling agent, or undefined for the global view. + * @returns the resolved presentation mode. + */ + modeFor(scope) { + // Nearest scope wins along the chain: a preset's standing declaration + // covers every agent parented under it, and an agent's own (were one ever + // declared) would override its preset's. The mode decides what the model + // SEES, which is exactly the class of fact the chain inherits. + const layers = this.layers.chainLayers(scope); + for (let index = layers.length - 1; index >= 0; index -= 1) { + const mode = layers[index]?.mode; + if (mode !== undefined) + return mode; + } + return this.defaultMode; + } + /** + * The reserved `run_code` transport, built on first need. + * + * It never enters the global layer: per-agent restrictions must not remove + * it, and a scoped registration must not shadow it. The visibility resolver + * appends it after resolving the filterable global/scoped capability layers, + * and only for scopes whose mode actually presents it. + * @returns the shared transport definition. + */ + requireCodeTransport() { + this.codeTransport ??= createRunCodeTool(this, { + requireRuntime: () => this.requireCodeRuntime(this.defaultMode), + // The language-aware description/parameters getters read the runtime + // without demanding one, so a native-default process can still project + // the transport for an agent that chose code. + peekRuntime: () => this.ctx.get('codeRuntime'), + maxParallel: this.maxParallelSubCalls, + shapeDispatchLog: dispatch => this.shapeDispatchLog(dispatch), + }); + return this.codeTransport; + } + /** + * Present the calling scope's tools in `mode` instead of the deployment + * default. Nearest scope on the chain wins, so a preset's standing + * declaration covers every agent joined under it. + * + * Scoped only, and one declaration per scope: this is how an agent preset + * composes Code Mode agents beside native ones in the same process, and a + * process-global override would be the `mode` config field instead. + * @param mode - the presentation the covered agents' models see. + * @returns the exact disposer that restores the deployment default. + */ + presentAs(mode) { + const ctx = this.ctx; + if (scopeOf(ctx) === undefined) { + throw new Error('tools.presentAs() requires a scoped context (agent.ctx): a context-global presentation is the `mode` config field on the tools row'); + } + const dispose = ctx.effect(function* () { + yield this.layers.effect(ctx, (layer) => { + if (layer.mode !== undefined) { + throw new Error(`tools.presentAs("${mode}") conflicts with "${layer.mode}" already declared for this scope; one composition selects one presentation`); + } + layer.mode = mode; + return () => { layer.mode = undefined; }; + }, { label: 'tools.presentAs()' }); + // The SDK and collapse sections are per scope for the same reason the + // mode is. Under a deployment that already defaults to a code mode this + // shadows the global registration with an identical body, which costs + // nothing and keeps one rule instead of a case analysis. + if (mode !== 'native') { + yield ctx.systemPrompt.section(this.collapseSection()); + yield ctx.systemPrompt.section(this.sdkSection()); + } + }.bind(this), 'tools.presentAs()'); + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous composite teardown; direct return preserves disposer identity + return dispose; + } + /** + * Build one scope's wire schemas and names for prompt-order validation. + * Restrictions do not make known tools invalid, but a mode collapse does. + */ + wireSchemas(scope) { + const view = this.view(scope); + const mode = this.modeFor(scope); + if (mode === 'native') { + const schemas = [...view.visible.values()].map(definition => this.schemaOf(definition, false)); + return { schemas, knownNames: [...view.knownNames] }; + } + // Validate the runtime language BEFORE projecting schemas: schemaOf reads + // run_code's language-aware description/parameters getters, whose own + // flavor-table guard would otherwise surface first. This keeps the + // renderer-table rejection the canonical assembly-time error for a + // language with no SDK renderer. + this.requireCodeRuntime(mode); + const schemas = [...view.visible.values()].map(definition => this.schemaOf(definition, false)); + if (mode === 'code') { + return { + schemas: schemas.filter(schema => schema.name === RUN_CODE_NAME), + knownNames: [RUN_CODE_NAME], + }; + } + return { schemas, knownNames: [...view.knownNames, RUN_CODE_NAME] }; + } + /** + * Resolve the code runtime or throw the actionable misconfiguration error. + * Read at use time (assembly / run_code execution), NOT via static + * `inject`: an inject entry would hold `ctx.tools` — and every tool plugin + * behind it — hostage to a code runtime existing even under `mode: + * 'native'` (the loop's optional-backend idiom, same as + * `sessionPersistence`). + * + * Assembly and `run_code` execution read separately, so the language is not + * bound to a request. Harmless while one published backend exists — both + * reads return the same flavor — but a reload that swapped in a second + * language between them would hand a program written against one SDK to the + * other. Binding it is deferred until a second backend ships (the first + * point it is testable); rationale in the + * [language-dispatch note](../../../../.agents/notes/implemented/feature/2026-07-31-code-mode-language-dispatch.md). + */ + requireCodeRuntime(mode) { + const runtime = this.ctx.get('codeRuntime'); + if (!runtime) { + throw new Error(`dsh-tools: mode "${mode}" requires a code runtime — load a ctx.codeRuntime implementation (e.g. @deepseek-ai/dsh-code-runtime-worker-thread) or set tools mode to "native"`); + } + if (!Object.hasOwn(SDK_RENDERERS, runtime.language)) { + const known = Object.keys(SDK_RENDERERS).map(name => JSON.stringify(name)).join(', '); + throw new Error(`dsh-tools: no SDK renderer registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`); + } + return runtime; + } + /** + * Register globally or in the calling agent scope. Scoped tools shadow + * globals; duplicates within one layer and the reserved `run_code` name fail. + * @param definition - tool schema, execution, and optional finalization/presentation callbacks. + * @returns the exact disposer that unregisters the tool. + */ + register(definition) { + const name = definition.name; + const output = definition.output; + if (output === undefined || typeof output !== 'object' + || typeof output.render !== 'function' + || (output.presentationMeta !== undefined && typeof output.presentationMeta !== 'function')) { + throw new TypeError(`tool "${name}" must declare output { schema, render, presentationMeta? }`); + } + assertSupportedJsonSchema(output.schema); + const timeoutMs = definition.timeoutMs; + if (timeoutMs !== undefined + && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) { + throw new TypeError(`tool "${name}" timeoutMs must be a positive finite number`); + } + // Reserved unconditionally: any agent may select a code mode for itself, + // so a name free to take under the deployment default would become a + // collision the moment a preset mounted. + if (name === RUN_CODE_NAME) { + throw new Error(`tool name "${RUN_CODE_NAME}" is reserved for the Code Mode presentation transport and cannot be registered or shadowed`); + } + return this.layers.effect(this.ctx, layer => layer.tools.insert(name, definition), { label: 'tools.register()' }); + } + /** + * Restrict global tools for the calling agent scope. Empty filters, unknown + * names, scope-local names, and reserved transport names fail. Restrictions + * intersect; scoped registrations remain visible. + * @param filter - global-tool mask: `allow` (keep only) and/or `deny` (remove). + * @returns the exact disposer that lifts this restriction. + */ + restrict(filter) { + const scope = scopeOf(this.ctx); + if (scope === undefined) { + throw new Error('tools.restrict() requires a scoped context (agent.ctx): a context-global restriction would mask every agent — deny the tool for the intended agent instead'); + } + const allow = filter.allow; + const deny = filter.deny; + if (allow === undefined && deny === undefined) { + throw new Error('tools.restrict({}) is a no-op: pass `allow` and/or `deny` (an empty filter is almost always a materialized-empty-config bug)'); + } + const compiled = { + ...allow !== undefined ? { allow: new Set(allow) } : {}, + ...deny !== undefined ? { deny: new Set(deny) } : {}, + }; + if ([...allow ?? [], ...deny ?? []].includes(RUN_CODE_NAME)) { + throw new Error(`tools.restrict() cannot name reserved Code Mode presentation transport "${RUN_CODE_NAME}"; restrict end-capability tools instead`); + } + const known = this.view(scope).restrictableNames; + const unknown = [...allow ?? [], ...deny ?? []].filter(name => !known.has(name)); + if (unknown.length > 0) { + throw new Error(`tools.restrict() names unknown global tool${unknown.length > 1 ? 's' : ''} ${unknown.map(n => `"${n}"`).join(', ')}; known global tools: ${[...known].sort().join(', ') || '(none)'}`); + } + return this.layers.effect(this.ctx, layer => layer.restrictions.append(compiled), { label: 'tools.restrict()' }); + } + /** + * Register a monotonic guard after the extensible `tools/pre-execute` + * waterfall. A plain-context guard applies globally; one registered through + * `agent.ctx` applies only to that agent. Any matching guard may deny by + * returning a reason, while no guard can force-allow a call another guard + * denied. The exact effect disposer is returned for ordered ownership and + * HMR cleanup. + * @param guard - synchronous check; a returned string denies the execution. + * @returns the exact disposer that unregisters the guard. + */ + guard(guard) { + return this.layers.effect(this.ctx, layer => layer.guards.append(guard), { label: 'tools.guard()', notify: false }); + } + /** First monotonic denial from the global then the scope chain's guard layers, farthest first. */ + guardReason(exec) { + const globalReason = this.layers.global.guardReason(exec); + if (globalReason !== undefined) + return globalReason; + if (exec.agent === undefined) + return undefined; + for (const layer of this.layers.chainLayers(exec.agent)) { + const reason = layer.guardReason(exec); + if (reason !== undefined) + return reason; + } + return undefined; + } + /** + * Resolve every registry fact one scope needs in one layer traversal. The + * visible map applies restrictions to the INHERITED surface, then the + * scope's own registrations and the reserved presentation transport; the + * other sets retain the pre-restriction facts needed by restriction and + * prompt-order validation. + * + * A restriction filters what a scope inherits — the global layer and every + * ancestor layer on its chain — and never what its OWN layer registers. + * That exemption is what a per-child capability filter has to keep intact: + * the delegation runtime registers a child's reporting and structured-output + * tools into the child's own layer, and a filter naming the capabilities the + * child may use must not strip the machinery it answers through. + * + * Reading the exempt set as "the global layer" instead of "not mine" held + * only while every model-facing tool sat in the host composition. Once + * presets moved them onto the agent plane they became an ANCESTOR + * contribution, so a child's filter silently stopped constraining anything + * it was given. + * @param scope - the viewing scope (the agent), or undefined for the global view. + * @returns the complete derived view for that scope. + */ + view(scope) { + // Scope-chain layers, farthest ancestor first, the exact scope last. + const layers = this.layers.chainLayers(scope); + // Chain-blind on purpose: this is the ONE layer whose registrations the + // scope owns rather than inherits, and it is absent until the scope + // contributes something. + const own = this.layers.peek(scope); + // Inherited surface, nearest ancestor last: a nearer scope's same-name + // entry shadows a farther one, and the global layer is the farthest. + const inherited = new Map(this.layers.global.tools.entries()); + for (const layer of layers) { + if (layer === own) + continue; + for (const [name, definition] of layer.tools.entries()) + inherited.set(name, definition); + } + const visible = new Map(); + const knownNames = new Set(); + const restrictableNames = new Set(); + for (const [name, definition] of inherited) { + knownNames.add(name); + restrictableNames.add(name); + // Restrictions intersect across the whole chain: any scope on it may + // mask an inherited name for everything nested inside it. + if (layers.every(layer => layer.admits(name))) + visible.set(name, definition); + } + // The scope's own registrations last, shadowing an inherited name and + // outside the filter above. + if (own !== undefined) { + for (const [name, definition] of own.tools.entries()) { + knownNames.add(name); + visible.set(name, definition); + } + } + // Presentation infrastructure is resolved last and outside capability + // filtering. Registration rejects this reserved name, so the insertion is + // an invariant assertion as well as protection against future layer + // changes. Per scope: a native agent must not find `run_code` in its + // dispatch table because some other agent in the process presents it. + if (this.modeFor(scope) !== 'native') { + visible.set(RUN_CODE_NAME, this.requireCodeTransport()); + } + return { visible, knownNames, restrictableNames }; + } + /** + * Look up a tool as one scope sees it (scoped + * shadows global; a restricted-away global reads as absent). Presenters pass + * the calling agent so the rendered card matches the definition that + * actually executed. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns the definition the scope resolves, or undefined when none is visible. + */ + get(name, scope) { + return this.view(scope).visible.get(name); + } + /** + * Resolve the definition that MAY EXECUTE for a call, applying the mode + * collapse at the operation boundary that owns it. The registry view + * (`get`) is presentation-agnostic; here a MODEL-DIRECT call under `code` + * may only name the reserved `run_code` transport, while a nested + * sub-dispatch (a `parent` token set — the `run_code` SDK calling a tool + * it bound) may call any visible tool. Denial surfaces as `UNKNOWN_TOOL` + * through the executor, matching an absent definition. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + * @returns the definition that may run, or undefined when the call must be rejected. + */ + resolveExecution(name, scope, nested) { + const tool = this.get(name, scope); + if (tool === undefined) + return undefined; + if (this.collapses(name, scope, nested)) + return undefined; + return tool; + } + /** + * Project visible definitions onto the allowlisted model-facing schema fields, + * excluding execution and presentation callbacks. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @returns one deep-cloned schema per visible tool. + */ + schemas(scope) { + return [...this.view(scope).visible.values()].map(definition => this.schemaOf(definition, true)); + } + /** Project visible callable tools onto the generated Code Mode SDK contract. */ + sdkSchemas(scope) { + return [...this.view(scope).visible.values()] + .filter(definition => definition.name !== RUN_CODE_NAME) + .map((definition) => { + const output = snapshotJsonValue(definition.output.schema); + /* v8 ignore next -- registration already validated and retained this schema as lossless JSON. */ + if (output === undefined) { + throw new Error(`tool "${definition.name}" output schema must be lossless JSON before SDK projection`); + } + return { + ...this.schemaOf(definition, true), + output, + }; + }); + } + /** Project one definition onto the model-facing schema fields. */ + schemaOf(definition, detachParameters) { + const { name, description, parameters } = definition; + const detached = detachParameters ? snapshotJsonValue(parameters) : parameters; + if (detached === undefined) { + throw new Error(`tool "${name}" parameters must be lossless JSON before schema projection`); + } + return { + name, + description, + parameters: detached, + }; + } + /** + * Classify a pending call through the caller's visible tool definition. Only + * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or + * throwing classifiers are exclusive. + * @param exec - call name, parsed arguments, and optional agent scope. + * @returns the fail-closed scheduling mode. + */ + executionMode(exec) { + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined); + if (!tool?.isConcurrencySafe) + return { kind: 'exclusive' }; + try { + const concurrencySafe = tool.isConcurrencySafe(exec.arguments); + return concurrencySafe === true ? { kind: 'parallel' } : { kind: 'exclusive' }; + } + catch { + return { kind: 'exclusive' }; + } + } + /** + * Run the `tools/code-dispatch-log` waterfall over one settled sub-dispatch + * and return the content the bridge should log on `tool/code-dispatch`. + * Contained: when a listener throws, the method logs the original settled + * content; that failure must not fail the dispatch or omit the settle event. Private: + * the ONE consumer is the `run_code` bridge this registry constructs, which + * receives it as a capability parameter (the `requireRuntime` idiom) — the + * waterfall, not this invoker, is the public extension point. + */ + async shapeDispatchLog(dispatch) { + try { + return await this.ctx.waterfall(scopeTarget(this, dispatch.agent), 'tools/code-dispatch-log', dispatch, () => Promise.resolve(dispatch.content)); + } + catch (error) { + this.ctx.logger.warn(`tools: code-dispatch-log listener failed for ${dispatch.name}: ${errorMessage(error)}; logging the original settled content`); + return dispatch.content; + } + } + /** + * Whether the `code` mode collapse denies a model-direct call: only the + * reserved `run_code` transport may be named. Nested sub-dispatches (a + * `parent` token set) bypass the collapse. One home for the + * security-relevant predicate, shared by {@link resolveExecution} and + * {@link createExecution} so the two can never drift apart. + * + * Resolved through {@link modeFor}, NOT `defaultMode`: an agent given `code` + * by an agent preset under a native deployment is the composition + * `dsh-agent-tool-presentation` exists for, and reading the deployment default would + * leave exactly that agent uncollapsed — announcing one surface while + * executing another, which is the bypass this collapse closes. + * @param name - the tool name as registered. + * @param scope - the viewing scope whose effective presentation mode applies. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + */ + collapses(name, scope, nested) { + return !nested && this.modeFor(scope) === 'code' && name !== RUN_CODE_NAME; + } + /** + * Execute through pre-policy, guards, around-dispatch, post-policy, + * definition-owned content finalization, and final notification. Tool and + * listener failures resolve as materialized error results; an invisible tool + * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen + * snapshot final observers receive. Cancellation + * arriving after entry and before final result materialization skips a + * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a + * successful started outcome with `ABORTED`; already-started work is still + * drained and may retain a tool-owned structured error. + * @param exec - the typed same-process call input. The registry assigns its + * correlation token before policy begins. + * @returns the materialized final result. + */ + async execute(exec) { + return this.prepareExecution(exec, prepared => this.completeScheduledExecution(prepared)); + } + async completeScheduledExecution(prepared) { + switch (prepared.kind) { + case 'dispatch': { + const dispatched = await this.dispatchScheduledExecution(prepared.exec); + return dispatched.kind === 'post-result' + ? await this.finalizeScheduledExecution(prepared.exec, dispatched.result) + : this.finishScheduledExecution(prepared.exec, dispatched.result); + } + case 'post-result': + return await this.finalizeScheduledExecution(prepared.exec, prepared.result); + case 'final-result': + return this.finishScheduledExecution(prepared.exec, prepared.result); + /* v8 ignore next -- closed-union exhaustiveness guard */ + default: + return assertNever(prepared, 'scheduled tool preparation'); + } + } + createExecution(exec) { + const deferredContexts = []; + const token = createExecutionToken(); + const callId = exec.callId; + const rootCallId = exec.rootCallId ?? callId; + const name = exec.name; + const agent = exec.agent; + const parent = exec.parent; + const signal = exec.signal; + // Distinguish a mode-collapsed call (visible in the scope, denied only by + // the `code` collapse) from a genuinely unknown tool. A collapsed call is + // deterministically denied, so it terminates BEFORE the extensible policy + // pipeline: pre-execute listeners, approval `ask`, and guards must never + // observe — or worse, approve — a call that can only fail. An unknown tool + // keeps the historical dispatch-stage `UNKNOWN_TOOL` path so policy + // listeners still see every name that reaches the registry. + const visible = this.get(name, agent); + const collapsed = visible !== undefined && this.collapses(name, agent, parent !== undefined); + const concludingExecutions = this.concludingExecutions; + const base = { + token, + callId, + rootCallId, + name, + signal, + ...agent !== undefined ? { agent } : {}, + ...parent !== undefined ? { parent } : {}, + deferContext(context) { + deferredContexts.push(context); + }, + concludeTurn() { + concludingExecutions.add(this); + }, + }; + // Capture the finalizer BEFORE argument materialization: the + // `finalizeContent` contract snapshots the callback when the call starts, + // and an arguments getter can replace or clear the registered callback + // during `snapshotJsonValue`. The collapse only decides whether the + // CAPTURED callback is retained: the pre-dispatch abort path keeps it + // (the cancellation contract routes aborted results through it — a getter + // that aborts mid-materialization before an invalid-args failure lands in + // the same retained path), while the `UNKNOWN_TOOL` denial and the + // invalid-args failure of a NON-ABORTED collapsed call drop it (the call + // could never execute). + const capturedFinalizer = visible?.finalizeContent?.bind(visible); + const finalizerFor = () => collapsed && !signal.aborted ? undefined : capturedFinalizer; + try { + const detached = snapshotJsonValue(exec.arguments); + if (detached === undefined) { + throw new TypeError('tool execution arguments must be losslessly JSON-serializable'); + } + const execution = { ...base, arguments: deepFreeze(detached) }; + this.deferredContexts.set(execution, deferredContexts); + this.contentFinalizers.set(execution, finalizerFor()); + this.cancellationStates.set(execution, { + callerSignal: signal, + bodyInvoked: false, + }); + if (collapsed) { + // The collapse denies the call before the policy pipeline, but a + // pre-dispatch abort still keeps the established cancellation + // contract: `prepare`'s caller-cancellation check is skipped for + // final-results, so honor the abort here instead of surfacing + // `UNKNOWN_TOOL` on an already-cancelled call. + if (signal.aborted) { + return { kind: 'final-result', exec: execution, result: toolAbortedBeforeDispatchResult() }; + } + // The name IS visible here, so the denial carries the route the model + // must take instead. Without it the model reads a bare `unknown tool` + // for a tool the prompt just declared and concludes the deployment is + // broken rather than correcting itself. + return { + kind: 'final-result', + exec: execution, + result: toolErrorResult(new ToolNotFoundError(name, `only \`${RUN_CODE_NAME}\` is callable directly — call \`${name}\` from inside a \`${RUN_CODE_NAME}\` program instead`)), + }; + } + return { kind: 'ready', exec: execution }; + } + catch (error) { + const execution = { ...base, arguments: undefined }; + this.contentFinalizers.set(execution, finalizerFor()); + return { kind: 'final-result', exec: execution, result: toolErrorResult(error) }; + } + } + /** + * Run the ordered pre-execute and monotonic guard stages for the scheduler. + * @param input - the caller-supplied execution input. + * @returns the prepared execution plus the next scheduler stage. + * @internal + */ + async prepareScheduledExecution(input) { + return this.prepareExecution(input, prepared => prepared); + } + async prepareExecution(input, next) { + const created = this.createExecution(input); + if (created.kind !== 'ready') + return next(created); + const exec = created.exec; + if (this.callerCancelled(exec)) { + return next({ kind: 'final-result', exec, result: toolAbortedBeforeDispatchResult() }); + } + try { + const carrier = scopeTarget(this, exec.agent); + const gate = await this.ctx.waterfall(carrier, 'tools/pre-execute', exec, () => Promise.resolve({ kind: 'allow' })); + const askResolution = gate.kind === 'ask' + ? await this.serviceAsk(exec, gate) + : { decision: gate, approvalCancelled: false }; + const { decision } = askResolution; + if (this.callerCancelled(exec) && askResolution.approvalCancelled) { + return await next({ kind: 'post-result', exec, result: toolAbortedBeforeDispatchResult() }); + } + const denialReason = decision.kind === 'allow' + ? this.guardReason(exec) + : decision.reason; + if (denialReason !== undefined) { + return await next({ + kind: 'post-result', + exec, + result: this.materializeFinalResult({ + content: [{ type: 'text', text: `Error: ${denialReason}` }], + isError: true, + error: { message: denialReason }, + }), + }); + } + if (this.callerCancelled(exec)) { + return await next({ kind: 'post-result', exec, result: toolAbortedBeforeDispatchResult() }); + } + return await next({ kind: 'dispatch', exec }); + } + catch (error) { + return next({ kind: 'final-result', exec, result: toolErrorResult(error) }); + } + } + /** Whether the original caller signal is currently aborted. */ + callerCancelled(exec) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === undefined) + throw new Error('tool registry scheduler invariant violated: missing cancellation state'); + return state.callerSignal.aborted; + } + /** Canonical cancellation outcome selected by whether the tool body started. */ + cancellationResult(exec, prior) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === undefined) + throw new Error('tool registry scheduler invariant violated: missing cancellation state'); + return state.bodyInvoked + ? toolAbortedResult(prior) + : toolAbortedBeforeDispatchResult(prior); + } + /** + * Dispatch the registered body with the original caller signal fused back + * into any around-wrapper replacement. Cancellation never abandons the body: + * a started promise reaches quiescence before its outcome becomes `ABORTED`. + */ + async dispatchToolBody(exec) { + const state = this.cancellationStates.get(exec); + /* v8 ignore next -- only registry-minted executions reach the staged scheduler methods */ + if (state === undefined) + throw new Error('tool registry scheduler invariant violated: missing cancellation state'); + const wrapperSignal = exec.signal; + const fused = fuseToolSignals(state.callerSignal, wrapperSignal); + const signal = fused.signal; + if (isAborted(signal)) { + fused.dispose(); + return toolAbortedBeforeDispatchResult(); + } + exec.signal = signal; + try { + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined); + if (!tool) + throw new ToolNotFoundError(exec.name); + state.bodyInvoked = true; + const returned = await tool.execute(exec.arguments, exec); + const result = this.createSuccessResult(exec, tool, returned); + return isAborted(signal) + ? toolAbortedResult(result) + : result; + } + catch (error) { + return toolErrorResult(error); + } + finally { + fused.dispose(); + exec.signal = wrapperSignal; + } + } + /** + * Run around-dispatch and the tool body. Tool and unknown-tool failures still + * receive post-execute; pipeline failures are already final. + * @param exec - the prepared execution. + * @returns whether the result still needs post-execute. + * @internal + */ + async dispatchScheduledExecution(exec) { + try { + const mutableExec = exec; + const carrier = scopeTarget(this, exec.agent); + const result = await this.ctx.waterfall(carrier, 'tools/execute', mutableExec, () => this.dispatchToolBody(mutableExec)); + const normalized = this.normalizeDispatchResult(exec, result); + const deferredContexts = this.deferredContexts.get(exec); + /* v8 ignore next -- dispatch only receives executions minted by this registry's prepare stage */ + if (deferredContexts === undefined) + throw new Error('tool registry scheduler invariant violated: unprepared execution'); + const resultWithDeferredContexts = deferredContexts.length === 0 + ? normalized + : this.markCanonical(exec, { + ...normalized, + additionalContexts: [ + ...deferredContexts, + ...normalized.additionalContexts ?? [], + ], + }); + return { + kind: 'post-result', + result: this.callerCancelled(exec) && !resultWithDeferredContexts.isError + ? this.cancellationResult(exec, resultWithDeferredContexts) + : resultWithDeferredContexts, + }; + } + catch (error) { + return { kind: 'final-result', result: toolErrorResult(error) }; + } + } + /** + * Run ordered post-execute, then apply definition-owned content finalization, + * materialize, and notify the final outcome. + * @param exec - the prepared execution. + * @param result - dispatch/pre result that still needs post-execute. + * @returns the materialized final result. + * @internal + */ + async finalizeScheduledExecution(exec, result) { + try { + const postResult = await this.postExecute(exec, result); + return this.finishScheduledExecution(exec, this.callerCancelled(exec) && !postResult.isError + ? this.cancellationResult(exec, postResult) + : postResult); + } + catch (error) { + return this.finishScheduledExecution(exec, toolErrorResult(error)); + } + } + /** + * Materialize the candidate, apply definition-owned content finalization, + * then materialize and notify the authoritative result. + * @param exec - the prepared execution. + * @param result - final result. + * @returns the materialized final result. + * @internal + */ + finishScheduledExecution(exec, result) { + let materializedResult; + try { + materializedResult = this.materializeFinalResult(result); + } + catch (error) { + materializedResult = this.materializeFinalResult(toolErrorResult(error)); + } + let finalResult; + try { + finalResult = this.materializeFinalResult(this.applyFinalContent(exec, materializedResult)); + } + catch (error) { + finalResult = this.materializeFinalResult(toolErrorResult(error)); + } + this.notifyResult(exec, finalResult); + return finalResult; + } + /** Apply the snapshotted tool-owned content transform without exposing other result fields. */ + applyFinalContent(exec, result) { + const finalizeContent = this.contentFinalizers.get(exec); + if (finalizeContent === undefined) + return result; + const content = finalizeContent(exec, result); + return content === undefined ? result : { ...result, content }; + } + /** Notify observers without exposing a mutation or error channel into the outcome. */ + notifyResult(exec, result) { + // Freeze the registry's live object before observers receive its readonly + // WeakMap-keyable view. + Object.freeze(exec); + const { name: toolName, callId } = exec; + const reportFailure = (error) => { + this.ctx.logger.warn(`tool "${toolName}" (${callId}): tools/result observer failed: ${errorMessage(error)}`); + }; + const callbacks = this.ctx.events.dispatch('emit', [ + scopeTarget(this, exec.agent), 'tools/result', exec, result, + ]); + for (const callback of callbacks) { + try { + const returned = callback(exec, result); + void Promise.resolve(returned).catch(reportFailure); + } + catch (error) { + reportFailure(error); + } + } + } + /** + * Resolve an `ask` decision to allow/deny through the approval seam. The + * seam is consumed opportunistically with `ctx.get('approval')` — a + * deployment that composes no ApprovalService keeps the historical degrade + * to deny, and an unmount mid-session degrades the same way on the next ask. + * An agent-less execution also degrades: without an agent there is no + * session to audit to and no UI to route to. Otherwise the outcome maps + * one-to-one — `allowed-once` proceeds; the three non-grants deny with + * distinct reasons so the model can tell a human "no" from an absent + * approval channel. + */ + async serviceAsk(exec, ask) { + const approval = this.ctx.get('approval'); + if (approval === undefined) { + return { + decision: { kind: 'deny', reason: ask.reason ?? `tool "${exec.name}" requires approval (not yet supported)` }, + approvalCancelled: false, + }; + } + if (exec.agent === undefined) { + return { + decision: { kind: 'deny', reason: `tool "${exec.name}" requires approval, but the call has no agent to route it through` }, + approvalCancelled: false, + }; + } + const outcome = await approval.request({ + agent: exec.agent, + toolName: exec.name, + callId: exec.callId, + ...ask.reason !== undefined ? { reason: ask.reason } : {}, + signal: exec.signal, + }); + switch (outcome) { + case 'allowed-once': return { decision: { kind: 'allow' }, approvalCancelled: false }; + case 'rejected': return { + decision: { kind: 'deny', reason: `the user rejected tool "${exec.name}"` }, + approvalCancelled: false, + }; + case 'cancelled': return { + decision: { kind: 'deny', reason: `approval for tool "${exec.name}" was cancelled` }, + approvalCancelled: true, + }; + case 'unavailable': return { + decision: { kind: 'deny', reason: `tool "${exec.name}" requires approval, but no approval channel is available` }, + approvalCancelled: false, + }; + default: return assertNever(outcome, 'ApprovalOutcome'); + } + } + /** + * Run the `tools/post-execute` waterfall over a dispatched `result` and apply + * its {@link PostToolDecision}: `accept` keeps the call successful (replacing + * `content` when given), `block` turns it into an `isError` whose content is + * the corrective `feedback`. Either decision may attach `additionalContexts`, + * which are ferried on the returned result for the loop's active-batch FIFO. + * Context deferred by the tool body survives an accepted result but is + * discarded when the outer call is blocked; a block exposes only context the + * blocking decision explicitly supplied. + * Runs inside `execute`'s outer try/catch (a throwing listener → isError). + */ + async postExecute(exec, result) { + const decision = await this.ctx.waterfall(scopeTarget(this, exec.agent), 'tools/post-execute', exec, result, () => Promise.resolve({ kind: 'accept' })); + const decisionContexts = decision.additionalContexts ?? []; + if (decision.kind === 'block') { + const message = failureMessageFromContent(decision.feedback); + return this.markCanonical(exec, { + content: decision.feedback, + isError: true, + error: { message }, + ...decisionContexts.length > 0 ? { additionalContexts: decisionContexts } : {}, + }); + } + if (Object.hasOwn(decision, 'content') && Object.hasOwn(decision, 'value')) { + throw new TypeError('tools/post-execute accept decision cannot replace both value and content'); + } + const additionalContexts = [ + ...result.additionalContexts ?? [], + ...decisionContexts, + ]; + if (Object.hasOwn(decision, 'value')) { + if (result.isError) { + throw new TypeError('tools/post-execute cannot replace the value of a failed result'); + } + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined); + if (tool === undefined) + throw new ToolNotFoundError(exec.name); + const replaced = this.createSuccessResult(exec, tool, decision.value); + return this.markCanonical(exec, { + ...replaced, + ...additionalContexts.length > 0 ? { additionalContexts } : {}, + }); + } + return this.markCanonical(exec, { + ...result, + ...decision.content !== undefined ? { content: decision.content } : {}, + ...additionalContexts.length > 0 ? { additionalContexts } : {}, + }); + } + /** Registry-normalized results and the exact dispatch that validated each value. */ + canonicalResults = new WeakMap(); + /** Mark one registry-normalized result as canonical only for its owning dispatch. */ + markCanonical(exec, result) { + this.canonicalResults.set(result, exec.token); + return result; + } + /** Snapshot, validate, render, and optionally project one successful body value. */ + createSuccessResult(exec, tool, candidate) { + const detached = snapshotToolValue(tool.name, candidate); + const violations = validateJsonSchemaValue(tool.output.schema, detached, 'value'); + if (violations.length > 0) + throw new ToolOutputError(tool.name, violations); + const value = deepFreeze(detached); + let rendered; + try { + rendered = tool.output.render(exec.arguments, value); + } + catch (error) { + throw projectionError(tool.name, 'render', error); + } + const content = snapshotProjection(tool.name, 'render', rendered); + let meta; + if (exec.parent === undefined && tool.output.presentationMeta !== undefined) { + let projected; + try { + projected = tool.output.presentationMeta(exec.arguments, value); + } + catch (error) { + throw projectionError(tool.name, 'presentationMeta', error); + } + meta = snapshotProjection(tool.name, 'presentationMeta', projected); + } + const concludesTurn = this.concludingExecutions.has(exec); + return this.markCanonical(exec, this.materializeFinalResult({ + isError: false, + value, + content, + ...meta !== undefined ? { meta } : {}, + ...concludesTurn ? { concludesTurn: true } : {}, + })); + } + /** Normalize an around-dispatch wrapper's authored result through the owning output contract. */ + normalizeDispatchResult(exec, result) { + if (this.canonicalResults.get(result) === exec.token) + return result; + if (result.isError) { + return this.markCanonical(exec, { + isError: true, + error: result.error, + content: result.content, + ...result.meta !== undefined ? { meta: result.meta } : {}, + ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, + }); + } + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined); + if (tool === undefined) + throw new ToolNotFoundError(exec.name); + const normalized = this.createSuccessResult(exec, tool, result.value); + return this.markCanonical(exec, { + ...normalized, + ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, + }); + } + /** Materialize the authoritative commit outcome once, immediately before `tools/result`. */ + materializeFinalResult(result) { + const presentation = { + content: result.content, + ...result.meta !== undefined ? { meta: result.meta } : {}, + ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, + }; + if (result.isError) { + return materializePresentation({ isError: true, error: result.error, ...presentation }); + } + const detached = materializePresentation({ + isError: false, + ...presentation, + ...result.concludesTurn === true ? { concludesTurn: true } : {}, + }); + return deepFreeze({ ...detached, value: result.value }); + } +} +/** Mint a same-process correlation token whose identity is its value. */ +function createExecutionToken() { + return Symbol('dsh.tool.execution'); +} +function toolErrorResult(error) { + const info = errorInfo(error); + const message = errorMessage(error); + return { + content: [{ type: 'text', text: `Error: ${message}` }], + isError: true, + error: { message, ...info ? { info } : {} }, + }; +} +/** Read live abort state across an await without treating it as synchronously immutable. */ +function isAborted(signal) { + return signal.aborted; +} +/** + * Fuse caller and wrapper cancellation without nesting `AbortSignal.any`. + * Keeping the relay dispatch-scoped also removes listeners when work settles. + */ +function fuseToolSignals(caller, wrapper) { + if (caller === wrapper) + return { signal: caller, dispose() { } }; + const controller = new AbortController(); + let listening = false; + const dispose = () => { + if (!listening) + return; + listening = false; + caller.removeEventListener('abort', abortFromCaller); + wrapper.removeEventListener('abort', abortFromWrapper); + }; + const abortFrom = (source) => { + const reason = source.reason; + controller.abort(reason); + dispose(); + }; + const abortFromCaller = () => { abortFrom(caller); }; + const abortFromWrapper = () => { abortFrom(wrapper); }; + if (wrapper.aborted) + abortFromWrapper(); + else if (caller.aborted) + abortFromCaller(); + else { + listening = true; + caller.addEventListener('abort', abortFromCaller, { once: true }); + wrapper.addEventListener('abort', abortFromWrapper, { once: true }); + } + return { signal: controller.signal, dispose }; +} +/** Canonical result when cancellation supersedes success after body invocation. */ +function toolAbortedResult(prior) { + const additionalContexts = prior?.additionalContexts ?? []; + return { + content: [{ type: 'text', text: 'Error: tool call aborted' }], + isError: true, + error: { + message: 'tool call aborted', + info: { name: 'AbortError', code: TOOL_ABORTED }, + }, + ...additionalContexts.length > 0 ? { additionalContexts } : {}, + }; +} +/** Canonical result when cancellation prevents tool body invocation. */ +function toolAbortedBeforeDispatchResult(prior) { + const additionalContexts = prior?.additionalContexts ?? []; + return { + content: [{ type: 'text', text: 'Error: tool call aborted before dispatch' }], + isError: true, + error: { + message: 'tool call aborted before dispatch', + info: { name: 'AbortError', code: TOOL_ABORTED_BEFORE_DISPATCH }, + }, + ...additionalContexts.length > 0 ? { additionalContexts } : {}, + }; +} +export default ToolRuntime; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.d.ts new file mode 100644 index 0000000..ea7bdb3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned tool-pipeline invariants. @module @deepseek-ai/dsh-tools/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "tools-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the tools invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.js new file mode 100644 index 0000000..6002429 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/invariant.js @@ -0,0 +1,123 @@ +/** Package-owned tool-pipeline invariants. @module @deepseek-ai/dsh-tools/invariant */ +const PACKAGE_NAME = '@deepseek-ai/dsh-tools'; +/** Cordis companion plugin name. */ +export const name = 'tools-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Validate the immutable final execution/result snapshot. */ +function validateResult(exec, result, fail) { + if (!Object.isFrozen(exec)) + fail('tools/result execution must be frozen before publication'); + if (!Object.isFrozen(result) || !Object.isFrozen(result.content)) { + fail('tools/result outcome and content must be frozen before publication'); + } + if (exec.name.length === 0 || String(exec.callId).length === 0) { + fail('tools/result execution must carry non-empty name and callId'); + } +} +/** Install monotonic pipeline, final-snapshot, and code-dispatch enclosure checks. */ +const install = Object.assign((ctx, fail) => { + const stages = new WeakMap(); + const openTurns = new WeakMap(); + const dispatchRoots = new WeakMap(); + const validateDispatch = (session, event) => { + if (event.type !== 'tool/code-dispatch-start' && event.type !== 'tool/code-dispatch') + return; + const root = String(event.data.rootCallId); + const parent = String(event.data.parentCallId); + const child = String(event.data.subCallId); + if (root.length === 0 || parent.length === 0 || child.length === 0) { + fail(`${event.type} must carry non-empty rootCallId, parentCallId, and subCallId`); + return; + } + const roots = dispatchRoots.get(session); + const known = roots?.get(child); + if (known !== undefined && known !== root) + fail(`${event.type} changed rootCallId for subCallId ${child}`); + if (parent !== root && roots?.get(parent) !== root) { + fail(`${event.type} parentCallId ${parent} does not belong to rootCallId ${root}`); + } + }; + const commitDispatch = (session, event) => { + if (event.type !== 'tool/code-dispatch-start' && event.type !== 'tool/code-dispatch') + return; + const roots = dispatchRoots.get(session); + roots.set(String(event.data.subCallId), String(event.data.rootCallId)); + }; + const seed = (session) => { + let openTurn = null; + dispatchRoots.set(session, new Map()); + for (const event of session.events) { + validateDispatch(session, event); + commitDispatch(session, event); + if (event.type === 'turn/start') + openTurn = event.data.turn; + else if (event.type === 'turn/end') + openTurn = null; + else if ((event.type === 'tool/code-dispatch-start' || event.type === 'tool/code-dispatch') + && openTurn === null) { + fail(`${event.type} appended outside any open turn`); + } + } + openTurns.set(session, openTurn); + return openTurn; + }; + const openTurnFor = (session) => openTurns.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) + seed(session); + ctx.on('session/created', (session) => { seed(session); }, { global: true }); + ctx.on('session/event', (session, event) => { + validateDispatch(session, event); + commitDispatch(session, event); + if (event.type === 'turn/start') + openTurns.set(session, event.data.turn); + else if (event.type === 'turn/end') + openTurns.set(session, null); + }, { global: true }); + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName === 'session/event') { + const [session, event] = args; + validateDispatch(session, event); + if ((event.type === 'tool/code-dispatch-start' || event.type === 'tool/code-dispatch') + && openTurnFor(session) === null) { + fail(`${event.type} appended outside any open turn`); + } + return; + } + if (eventName === 'tools/pre-execute') { + const exec = args[0]; + if (stages.has(exec)) + fail('tools/pre-execute repeated for one execution'); + stages.set(exec, 'pre'); + return; + } + if (eventName === 'tools/execute') { + const exec = args[0]; + if (stages.get(exec) !== 'pre') + fail('tools/execute must follow tools/pre-execute'); + stages.set(exec, 'execute'); + return; + } + if (eventName === 'tools/post-execute') { + const exec = args[0]; + const previous = stages.get(exec); + if (previous !== 'pre' && previous !== 'execute') { + fail('tools/post-execute must follow tools/pre-execute or tools/execute'); + } + stages.set(exec, 'post'); + return; + } + if (eventName !== 'tools/result') + return; + const [exec, result] = args; + validateResult(exec, result, fail); + stages.delete(exec); + }, { global: true }); +}, { inject: ['sessions'] }); +/** + * Register the tools invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.d.ts new file mode 100644 index 0000000..399879a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.d.ts @@ -0,0 +1,106 @@ +/** + * Enforced JSON Schema subset shared by tool outputs, generated Code Mode + * types, subagents, and workflows. The subset accepts any JSON root, an + * annotation-only schema for unconstrained JSON, one scalar `type`, object + * `properties`/`required`/boolean `additionalProperties`, array `items`, + * type-correct scalar `enum`/`const`, and exact-one `oneOf`. + * + * Unsupported or misplaced keywords reject rather than being accepted without + * enforcement. Consumers that require an object root apply + * {@link assertObjectJsonSchema} before accepting input. + * @module dsh-tools/json-schema + */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import { type JsonValue } from '@deepseek-ai/dsh-session'; +/** Scalar JSON values supported by `enum` and `const`. */ +export type JsonSchemaScalar = string | number | boolean | null; +/** Single-type keywords accepted by the enforced subset. */ +export type JsonSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null'; +/** + * One raw JSON Schema node in the enforced subset. The optional fields express + * the external wire schema; {@link assertSupportedJsonSchema} rejects invalid + * combinations before a caller treats the node as trusted. + */ +export interface JsonSchemaNode { + /** Omit with no constraints for any JSON value, or use `oneOf`. */ + type?: JsonSchemaType; + /** Exactly one branch must validate; at least two branches are required. */ + oneOf?: JsonSchemaNode[]; + /** Nested property schemas (`type: 'object'` only). */ + properties?: Record; + /** Required property names; each must appear in `properties`. */ + required?: string[]; + /** `false` rejects undeclared keys; absent/`true` follows JSON Schema's open default. */ + additionalProperties?: boolean; + /** Item schema (`type: 'array'` only); absent accepts any JSON item. */ + items?: JsonSchemaNode; + /** Allowed values for a scalar node. */ + enum?: JsonSchemaScalar[]; + /** The single allowed value for a scalar node. */ + const?: JsonSchemaScalar; + /** Annotation, ignored for validation. */ + description?: string; + /** Annotation, ignored for validation. */ + title?: string; + /** Annotation, ignored for validation but required to be lossless JSON. */ + default?: JsonValue; + /** Annotation, ignored for validation but required to be lossless JSON. */ + examples?: JsonValue; +} +/** A consumer-constrained object-rooted schema. */ +export type ObjectJsonSchema = JsonSchemaNode & { + type: 'object'; +}; +/** + * Thrown when a raw schema falls outside the enforced subset. `violations` + * lists every offending path instead of stopping at the first author error. + */ +export declare class JsonSchemaError extends HarnessError { + /** Individual schema violations in walk order. */ + readonly violations: string[]; + constructor(violations: string[]); +} +/** + * Test for a realm-agnostic plain JSON record without accepting arrays or + * exotic objects. + * @param value - candidate record from any JavaScript realm. + * @returns Whether the value has a plain-object prototype chain. + */ +export declare function isPlainJsonRecord(value: unknown): value is Record; +/** + * Test for an ordinary schema record whose keys survive JSON projection. + * @param value - candidate record from any JavaScript realm. + * @returns Whether the record has an intrinsic prototype and only own enumerable string keys. + */ +export declare function isJsonSchemaRecord(value: unknown): value is Record; +/** + * Test for a dense ordinary array with no JSON-invisible decorations. + * @param value - candidate array from any JavaScript realm. + * @returns Whether the array is intrinsic, dense, and undecorated. + */ +export declare function isPlainJsonArray(value: unknown): value is unknown[]; +/** + * Assert that an arbitrary raw schema uses only the enforced subset. + * Annotation-only schemas are accepted as the standard unconstrained-JSON + * form; callers that require an object root use {@link assertObjectJsonSchema}. + * @param schema - untrusted raw JSON Schema. + * @returns Assertion that the schema belongs to the supported subset. + */ +export declare function assertSupportedJsonSchema(schema: unknown): asserts schema is JsonSchemaNode; +/** + * Assert the enforced subset plus the object-root constraint retained by + * subagent and workflow structured outputs. + * @param schema - untrusted caller-supplied schema. + * @returns Assertion that the schema belongs to the supported subset and has an object root. + */ +export declare function assertObjectJsonSchema(schema: unknown): asserts schema is ObjectJsonSchema; +/** + * Validate a candidate value against an asserted raw schema. The function is + * total for arbitrary values and returns path-qualified violations. + * @param schema - a schema accepted by {@link assertSupportedJsonSchema}. + * @param value - the candidate JSON value. + * @param path - root label used in diagnostics. + * @returns All violations in walk order; empty means valid. + */ +export declare function validateJsonSchemaValue(schema: JsonSchemaNode, value: unknown, path?: string): string[]; +//# sourceMappingURL=json-schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.js new file mode 100644 index 0000000..d6e9e1a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/json-schema.js @@ -0,0 +1,577 @@ +/** + * Enforced JSON Schema subset shared by tool outputs, generated Code Mode + * types, subagents, and workflows. The subset accepts any JSON root, an + * annotation-only schema for unconstrained JSON, one scalar `type`, object + * `properties`/`required`/boolean `additionalProperties`, array `items`, + * type-correct scalar `enum`/`const`, and exact-one `oneOf`. + * + * Unsupported or misplaced keywords reject rather than being accepted without + * enforcement. Consumers that require an object root apply + * {@link assertObjectJsonSchema} before accepting input. + * @module dsh-tools/json-schema + */ +import { assertNever, HarnessError } from '@deepseek-ai/dsh-llm'; +import { isJsonValue } from '@deepseek-ai/dsh-session'; +/** + * Thrown when a raw schema falls outside the enforced subset. `violations` + * lists every offending path instead of stopping at the first author error. + */ +export class JsonSchemaError extends HarnessError { + /** Individual schema violations in walk order. */ + violations; + constructor(violations) { + super(`unsupported JSON schema: ${violations.join('; ')}`, 'UNSUPPORTED_SCHEMA'); + this.name = 'JsonSchemaError'; + this.violations = violations; + } +} +const CONSTRAINT_KEYWORDS = new Set([ + 'type', + 'oneOf', + 'properties', + 'required', + 'additionalProperties', + 'items', + 'enum', + 'const', +]); +const ANNOTATION_KEYWORDS = new Set(['description', 'title', 'default', 'examples']); +const SCHEMA_TYPES = ['object', 'array', 'string', 'number', 'integer', 'boolean', 'null']; +/* jscpd:ignore-start -- this realm boundary mirrors the session-owned lossless-JSON intrinsic test */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype, name) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor'); + const constructor = descriptor?.value; + if (typeof constructor !== 'function') + return false; + try { + return constructor.name === name + && constructor.prototype === prototype + && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`; + } + catch { + return false; + } +} +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value) { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, 'Object'); +} +/** + * Test for a realm-agnostic plain JSON record without accepting arrays or + * exotic objects. + * @param value - candidate record from any JavaScript realm. + * @returns Whether the value has a plain-object prototype chain. + */ +export function isPlainJsonRecord(value) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) + return false; + try { + const prototype = Object.getPrototypeOf(value); + return prototype === null + || typeof prototype === 'object' && isIntrinsicObjectPrototype(prototype); + } + catch { + return false; + } +} +/** Whether an array uses one realm's intrinsic `Array.prototype`. */ +function hasPlainArrayPrototype(value) { + const prototype = Object.getPrototypeOf(value); + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) + return false; + const objectPrototype = Object.getPrototypeOf(prototype); + return typeof objectPrototype === 'object' + && objectPrototype !== null + && isIntrinsicObjectPrototype(objectPrototype); +} +/* jscpd:ignore-end */ +/** Return whether a record contains only own enumerable string keys. */ +function hasOnlyEnumerableStringKeys(value) { + try { + return Reflect.ownKeys(value) + .every(key => typeof key === 'string' && Object.prototype.propertyIsEnumerable.call(value, key)); + } + catch { + return false; + } +} +/** + * Test for an ordinary schema record whose keys survive JSON projection. + * @param value - candidate record from any JavaScript realm. + * @returns Whether the record has an intrinsic prototype and only own enumerable string keys. + */ +export function isJsonSchemaRecord(value) { + return isPlainJsonRecord(value) && hasOnlyEnumerableStringKeys(value); +} +/** + * Test for a dense ordinary array with no JSON-invisible decorations. + * @param value - candidate array from any JavaScript realm. + * @returns Whether the array is intrinsic, dense, and undecorated. + */ +export function isPlainJsonArray(value) { + if (!Array.isArray(value)) + return false; + try { + if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) + return false; + for (let index = 0; index < value.length; index++) { + if (!Object.hasOwn(value, index)) + return false; + } + return true; + } + catch { + return false; + } +} +/** Lossless finite JSON number, excluding negative zero. */ +function isJsonNumber(value) { + return typeof value === 'number' && Number.isFinite(value) && !Object.is(value, -0); +} +/** Whether a scalar is valid for one declared schema type. */ +function scalarMatches(type, value) { + switch (type) { + case 'string': return typeof value === 'string'; + case 'number': return isJsonNumber(value); + case 'integer': return isJsonNumber(value) && Number.isInteger(value); + case 'boolean': return typeof value === 'boolean'; + case 'null': return value === null; + /* v8 ignore next -- JsonSchemaScalarType is closed; this retains compile-time exhaustiveness. */ + default: return assertNever(type, 'JsonSchemaType'); + } +} +/** Keywords that are invalid beside `oneOf`. */ +const ONE_OF_SIBLING_KEYWORDS = ['properties', 'required', 'additionalProperties', 'items', 'enum', 'const']; +/** Validate object-only fields after its property schemas have been visited. */ +function checkObjectSchemaTail(node, path, properties, violations) { + const hasRequired = Object.hasOwn(node, 'required'); + const required = hasRequired ? node.required : undefined; + if (hasRequired) { + if (!isPlainJsonArray(required) || required.some(entry => typeof entry !== 'string')) { + violations.push(`${path}.required must be an array of strings`); + } + else { + const declared = isJsonSchemaRecord(properties) ? properties : {}; + for (const key of required) { + if (!Object.hasOwn(declared, key)) + violations.push(`${path}.required names "${key}" which is not in properties`); + } + } + } + if (Object.hasOwn(node, 'additionalProperties') && typeof node.additionalProperties !== 'boolean') { + violations.push(`${path}.additionalProperties must be a boolean`); + } +} +/** Collect every violation for one raw schema tree without using the JavaScript call stack. */ +function checkSchemaNode(root, rootPath, violations, seen) { + const tasks = [{ kind: 'enter', node: root, path: rootPath }]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + seen.delete(task.node); + continue; + } + if (task.kind === 'one-of-tail') { + for (const key of ONE_OF_SIBLING_KEYWORDS) { + if (Object.hasOwn(task.node, key)) + violations.push(`${task.path}.${key} is not supported beside oneOf`); + } + continue; + } + if (task.kind === 'object-tail') { + checkObjectSchemaTail(task.node, task.path, task.properties, violations); + continue; + } + const { node, path } = task; + if (!isJsonSchemaRecord(node)) { + violations.push(`${path} must be a schema object`); + continue; + } + if (seen.has(node)) { + violations.push(`${path} is circular`); + continue; + } + seen.add(node); + tasks.push({ kind: 'leave', node }); + for (const key of Object.keys(node)) { + if (CONSTRAINT_KEYWORDS.has(key)) + continue; + if (ANNOTATION_KEYWORDS.has(key)) { + try { + if (!isJsonValue(node[key])) + violations.push(`${path}.${key} annotation must be lossless JSON data`); + } + catch { + violations.push(`${path}.${key} annotation must be lossless JSON data`); + } + continue; + } + violations.push(`${path}.${key} is not a supported keyword (subset: type/oneOf/properties/required/additionalProperties/items/enum/const + annotations)`); + } + if (Object.hasOwn(node, 'description') && typeof node.description !== 'string') { + violations.push(`${path}.description must be a string`); + } + if (Object.hasOwn(node, 'title') && typeof node.title !== 'string') { + violations.push(`${path}.title must be a string`); + } + const hasType = Object.hasOwn(node, 'type'); + const hasOneOf = Object.hasOwn(node, 'oneOf'); + if (hasType && hasOneOf) { + violations.push(`${path} cannot declare both type and oneOf`); + continue; + } + if (!hasType && !hasOneOf) { + for (const key of ONE_OF_SIBLING_KEYWORDS) { + if (Object.hasOwn(node, key)) + violations.push(`${path}.${key} requires type or oneOf`); + } + continue; + } + if (hasOneOf) { + const oneOf = node.oneOf; + tasks.push({ kind: 'one-of-tail', node, path }); + if (!isPlainJsonArray(oneOf) || oneOf.length < 2) { + violations.push(`${path}.oneOf must be an array of at least two schemas`); + } + else { + for (let index = oneOf.length - 1; index >= 0; index--) { + tasks.push({ kind: 'enter', node: oneOf[index], path: `${path}.oneOf[${index}]` }); + } + } + continue; + } + const type = node.type; + if (typeof type !== 'string' || !SCHEMA_TYPES.includes(type)) { + violations.push(Array.isArray(type) + ? `${path}.type must be a single type string (type arrays are not supported)` + : `${path}.type must be one of ${SCHEMA_TYPES.join('/')}`); + continue; + } + const schemaType = type; + const allowedFor = { + properties: ['object'], + required: ['object'], + additionalProperties: ['object'], + items: ['array'], + enum: ['string', 'number', 'integer', 'boolean', 'null'], + const: ['string', 'number', 'integer', 'boolean', 'null'], + }; + for (const [key, types] of Object.entries(allowedFor)) { + if (Object.hasOwn(node, key) && !types.includes(schemaType)) { + violations.push(`${path}.${key} is not supported on type "${schemaType}"`); + } + } + switch (schemaType) { + case 'object': { + const properties = Object.hasOwn(node, 'properties') ? node.properties : undefined; + tasks.push({ kind: 'object-tail', node, path, properties }); + if (Object.hasOwn(node, 'properties')) { + if (!isJsonSchemaRecord(properties)) { + violations.push(`${path}.properties must be an object of schemas`); + } + else { + const entries = Object.entries(properties); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) + continue; + tasks.push({ kind: 'enter', node: entry[1], path: `${path}.properties.${entry[0]}` }); + } + } + } + break; + } + case 'array': { + if (Object.hasOwn(node, 'items')) + tasks.push({ kind: 'enter', node: node.items, path: `${path}.items` }); + break; + } + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': { + const hasEnum = Object.hasOwn(node, 'enum'); + const allowed = hasEnum ? node.enum : undefined; + const enumValid = isPlainJsonArray(allowed) + && allowed.length > 0 + && allowed.every(entry => scalarMatches(schemaType, entry)); + if (hasEnum && !enumValid) { + violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`); + } + const hasConst = Object.hasOwn(node, 'const'); + const declaredConst = hasConst ? node.const : undefined; + const constValid = scalarMatches(schemaType, declaredConst); + if (hasConst) { + if (!constValid) { + violations.push(`${path}.const must be a ${schemaType} value`); + } + else if (enumValid && !allowed.includes(declaredConst)) { + violations.push(`${path}.const must be one of ${path}.enum when both are declared`); + } + } + break; + } + /* v8 ignore next -- schemaType was narrowed from the closed SCHEMA_TYPES table above. */ + default: assertNever(schemaType, 'JsonSchemaType'); + } + } +} +/** + * Assert that an arbitrary raw schema uses only the enforced subset. + * Annotation-only schemas are accepted as the standard unconstrained-JSON + * form; callers that require an object root use {@link assertObjectJsonSchema}. + * @param schema - untrusted raw JSON Schema. + * @returns Assertion that the schema belongs to the supported subset. + */ +export function assertSupportedJsonSchema(schema) { + const violations = []; + checkSchemaNode(schema, 'schema', violations, new Set()); + if (violations.length > 0) + throw new JsonSchemaError(violations); +} +/** + * Assert the enforced subset plus the object-root constraint retained by + * subagent and workflow structured outputs. + * @param schema - untrusted caller-supplied schema. + * @returns Assertion that the schema belongs to the supported subset and has an object root. + */ +export function assertObjectJsonSchema(schema) { + const violations = []; + checkSchemaNode(schema, 'schema', violations, new Set()); + if (violations.length === 0 + && (!isJsonSchemaRecord(schema) || !Object.hasOwn(schema, 'type') || schema.type !== 'object')) { + violations.push('schema.type must be "object" (structured output is object-rooted)'); + } + if (violations.length > 0) + throw new JsonSchemaError(violations); +} +/** Safely test the lossless JSON boundary when a getter may throw. */ +function safelyIsJsonValue(value) { + try { + return isJsonValue(value); + } + catch { + return false; + } +} +/** Root-aware diagnostic path for the parameter validator's empty sentinel. */ +function diagnosticPath(path) { + return path === '' ? 'arguments' : path; +} +/** Append one object property without a leading dot at an implicit root. */ +function propertyPath(path, key) { + return path === '' ? key : `${path}.${key}`; +} +/** The generic exception-containment diagnostic owned by one valid schema node. */ +function losslessValueViolation(path) { + return [`"${diagnosticPath(path)}" must be a lossless JSON value`]; +} +/** Append diagnostics without spreading a potentially wide child result as call arguments. */ +function appendViolations(target, source) { + for (const violation of source) + target.push(violation); +} +/** Initialize one validation frame with empty aggregation state. */ +function valueFrame(node, value, path) { + return { + node, + value, + path, + catches: false, + phase: 'start', + children: [], + childIndex: 0, + violations: [], + tailViolations: [], + matches: 0, + }; +} +/** Validate one scalar node after its primitive type check. */ +function checkScalarValue(node, value, path) { + const allowed = Object.hasOwn(node, 'enum') ? node.enum : undefined; + if (allowed !== undefined && !allowed.includes(value)) { + return [`"${diagnosticPath(path)}" must be one of ${JSON.stringify(allowed)}`]; + } + if (Object.hasOwn(node, 'const') && value !== node.const) { + return [`"${diagnosticPath(path)}" must be ${JSON.stringify(node.const)}`]; + } + return []; +} +/** Validate one trusted schema/value pair with explicit frames rather than recursive calls. */ +function checkValue(schema, value, path) { + const frames = [valueFrame(schema, value, path)]; + let rootResult; + const receive = (result) => { + const parent = frames.at(-1); + if (parent === undefined) { + rootResult = result; + return; + } + if (parent.kind === 'oneOf') { + if (result.length === 0) + parent.matches++; + } + else { + appendViolations(parent.violations, result); + } + }; + const finish = (result) => { + frames.pop(); + receive(result); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === undefined) + break; + try { + if (frame.phase === 'children') { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === undefined) + throw new Error('missing schema-value child frame'); + frame.childIndex++; + frames.push(valueFrame(child.node, child.value, child.path)); + continue; + } + if (frame.kind === 'oneOf') { + finish(frame.matches === 1 ? [] : [`"${diagnosticPath(frame.path)}" must match exactly one oneOf branch (matched ${frame.matches})`]); + continue; + } + appendViolations(frame.violations, frame.tailViolations); + if (frame.violations.length > 0) { + finish(frame.violations); + } + else if (frame.kind === 'object') { + finish(safelyIsJsonValue(frame.value) ? [] : [`"${diagnosticPath(frame.path)}" must be a lossless JSON object`]); + } + else { + finish(safelyIsJsonValue(frame.value) ? [] : [`"${diagnosticPath(frame.path)}" must be a dense lossless JSON array`]); + } + continue; + } + const nodeType = Object.hasOwn(frame.node, 'type') ? frame.node.type : undefined; + frame.catches = !(nodeType !== undefined && !SCHEMA_TYPES.includes(nodeType)); + const oneOf = Object.hasOwn(frame.node, 'oneOf') ? frame.node.oneOf : undefined; + if (oneOf !== undefined) { + frame.kind = 'oneOf'; + frame.children = Array.from(oneOf, branch => ({ node: branch, value: frame.value, path: frame.path })); + frame.childIndex = 0; + frame.matches = 0; + frame.phase = 'children'; + continue; + } + if (nodeType === undefined) { + finish(safelyIsJsonValue(frame.value) ? [] : losslessValueViolation(frame.path)); + continue; + } + switch (nodeType) { + case 'object': { + if (!isPlainJsonRecord(frame.value)) { + finish([`"${diagnosticPath(frame.path)}" must be an object`]); + break; + } + const properties = Object.hasOwn(frame.node, 'properties') ? frame.node.properties ?? {} : {}; + const violations = []; + const required = Object.hasOwn(frame.node, 'required') ? frame.node.required ?? [] : []; + for (const key of required) { + if (!Object.hasOwn(frame.value, key) || frame.value[key] === undefined) { + violations.push(`missing required property "${propertyPath(frame.path, key)}"`); + } + } + const children = []; + for (const [key, child] of Object.entries(properties)) { + if (!Object.hasOwn(frame.value, key) || frame.value[key] === undefined) + continue; + children.push({ node: child, value: frame.value[key], path: propertyPath(frame.path, key) }); + } + const tailViolations = []; + if (Object.hasOwn(frame.node, 'additionalProperties') && frame.node.additionalProperties === false) { + for (const key of Object.keys(frame.value)) { + if (!Object.hasOwn(properties, key)) { + tailViolations.push(`"${propertyPath(frame.path, key)}" is not a declared property (additionalProperties: false)`); + } + } + } + frame.kind = 'object'; + frame.children = children; + frame.childIndex = 0; + frame.violations = violations; + frame.tailViolations = tailViolations; + frame.phase = 'children'; + break; + } + case 'array': { + if (!Array.isArray(frame.value)) { + finish([`"${diagnosticPath(frame.path)}" must be an array`]); + break; + } + const items = Object.hasOwn(frame.node, 'items') ? frame.node.items : undefined; + const children = items === undefined + ? [] + : frame.value.flatMap((entry, index) => [{ node: items, value: entry, path: `${frame.path}[${index}]` }]); + frame.kind = 'array'; + frame.children = children; + frame.childIndex = 0; + frame.violations = []; + frame.phase = 'children'; + break; + } + case 'string': + finish(typeof frame.value === 'string' + ? checkScalarValue(frame.node, frame.value, frame.path) + : [`"${diagnosticPath(frame.path)}" must be a string`]); + break; + case 'number': + finish(typeof frame.value !== 'number' + ? [`"${diagnosticPath(frame.path)}" must be a number`] + : !isJsonNumber(frame.value) + ? [`"${diagnosticPath(frame.path)}" must be a finite JSON number`] + : checkScalarValue(frame.node, frame.value, frame.path)); + break; + case 'integer': + finish(!isJsonNumber(frame.value) || !Number.isInteger(frame.value) + ? [`"${diagnosticPath(frame.path)}" must be an integer`] + : checkScalarValue(frame.node, frame.value, frame.path)); + break; + case 'boolean': + finish(typeof frame.value === 'boolean' + ? checkScalarValue(frame.node, frame.value, frame.path) + : [`"${diagnosticPath(frame.path)}" must be a boolean`]); + break; + case 'null': + finish(frame.value === null + ? checkScalarValue(frame.node, frame.value, frame.path) + : [`"${diagnosticPath(frame.path)}" must be null`]); + break; + default: + finish(assertNever(nodeType, 'JsonSchemaType')); + } + } + catch (error) { + let failed = frames.pop(); + while (failed !== undefined && !failed.catches) + failed = frames.pop(); + if (failed === undefined) + throw error; + receive(losslessValueViolation(failed.path)); + } + } + /* v8 ignore next -- every root frame finishes or throws. */ + return rootResult ?? losslessValueViolation(path); +} +/** + * Validate a candidate value against an asserted raw schema. The function is + * total for arbitrary values and returns path-qualified violations. + * @param schema - a schema accepted by {@link assertSupportedJsonSchema}. + * @param value - the candidate JSON value. + * @param path - root label used in diagnostics. + * @returns All violations in walk order; empty means valid. + */ +export function validateJsonSchemaValue(schema, value, path = 'value') { + return checkValue(schema, value, path); +} +//# sourceMappingURL=json-schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.d.ts new file mode 100644 index 0000000..2cf0fb9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.d.ts @@ -0,0 +1,367 @@ +/** + * Tool render-intent vocabulary: the provider-neutral types a tool declares via + * `ToolDefinition.presentCall`/`ToolDefinition.presentResult` to say how one of its calls + * renders in a UI (an editor's tool-call card, a CLI log line). + * @module @deepseek-ai/dsh-tools/src/presentation + */ +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +/** + * Category of a tool call, used by a UI to pick an icon or treatment. The + * provider-neutral vocabulary lets tools describe themselves without depending + * on a particular client; `other` is the default. + */ +export type ToolCallKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other'; +/** + * A file location a tool reads or modifies, so a capable UI can "follow along" — + * highlight or jump to the file (and line) as the tool runs. `path` is what the + * tool operated on (the model-facing path); `line` is an optional 1-based line + * to focus (e.g. a read's offset). + */ +export interface FileLocation { + path: string; + line?: number; +} +/** + * A single-file change a tool is about to make, for a UI that renders inline + * diffs. `oldText` is `null` for a new-file create (nothing to diff against); + * an overwrite also uses `null`, because a call-time presenter has no access to + * the file's prior content. + */ +export interface FileDiff { + path: string; + /** Prior content, or `null` for a new file / an overwrite (no prior content available at call time). */ + oldText: string | null; + /** Content after the change. */ + newText: string; +} +/** + * Provider-neutral pending-call presentation. Tools declare one tagged intent; + * UI bridges map it without special-casing tool names. + */ +export type ToolCallView = GenericCallView | TerminalCallView | DiffCallView; +/** + * The default card: a titled tool-call row with an optional category icon, a + * salient raw input, extra content blocks, and follow-along file locations. Any + * tool whose call is not a terminal or a diff uses this. + */ +export interface GenericCallView { + card: 'generic'; + /** + * Human-readable, always-visible label describing what THIS call does. Keep it + * short — a UI shows it as a card header / log line. + */ + title: string; + /** Category for icon/treatment; defaults to `other` when omitted. */ + kind?: ToolCallKind; + /** + * The salient input to show in a detail/expanded view (e.g. a background + * job id). Omit to show nothing; a string renders as-is, an object as pretty + * JSON. NOT the full raw args object unless that is genuinely what a reader wants. + */ + rawInput?: unknown; + /** + * UI-facing content blocks to show on the pending call alongside the title. + * Omit to show none. A UI maps these to its own content blocks. + */ + content?: ContentBlock[]; + /** Files this call reads/modifies, for editor follow-along. Omit for a call that touches no file. */ + locations?: FileLocation[]; +} +/** + * A call that IS a shell command running in a working directory: a capable UI + * renders it as a terminal card (cwd-headed, with the command as the title and + * live/afterward output from the {@link TerminalResultView}); an incapable UI + * falls back to a generic card whose body is the fenced command output. Set by a + * tool whose call is a foreground command (e.g. `bash`). + */ +export interface TerminalCallView { + card: 'terminal'; + /** The command, shown as the terminal card's title / header line. */ + title: string; + /** + * A human-readable one-line summary of what the command does, rendered ABOVE + * the terminal card (the card itself has no description slot). Omit for none. + */ + description?: string; + /** + * Working directory the command runs in, shown as the terminal header. An + * ABSOLUTE path is used as-is; a RELATIVE path is resolved by the UI bridge + * against the session workspace (the pure presenter can't see the session cwd). + * Omit entirely to let the bridge use the session workspace. + */ + cwd?: string; +} +/** + * A call that creates or modifies files, rendered as an inline diff card by a + * capable UI. Set by a tool whose call writes/edits a file (e.g. `write`, + * `edit`). The diffs are derived from the call ARGUMENTS (a create's `oldText` is + * `null`); the tool emits a separate {@link DiffResultView} after `execute` — the + * applied change (an edit/overwrite hunk with context, or a whole-file diff for a + * create). + */ +export interface DiffCallView { + card: 'diff'; + /** Card header (e.g. `Write foo.txt`). */ + title: string; + /** One entry per file the call changes. */ + diffs: FileDiff[]; + /** Files this call modifies, for editor follow-along (usually the diffs' paths). */ + locations?: FileLocation[]; +} +/** + * One numbered line of a file, the unit a {@link ReadResultView} carries so a + * capable UI can render a syntax-highlighted, line-numbered code view. `number` + * is the 1-based line number in the file (a window past `offset` keeps the file's + * own numbering, not a 1-based re-count); `text` is the line without its trailing + * newline, already truncated to the read tool's per-line cap. + */ +export interface ReadFileLine { + number: number; + text: string; +} +/** + * How a tool wants the COMPLETED call shown — the *result* state, after `execute` + * returns. A `card`-tagged union mirroring {@link ToolCallView}: a UI switches on + * `card`. Lets the tool reformat its result for a UI distinctly from the + * model-facing text it returned from `execute`. Returned by + * `ToolDefinition.presentResult`; omitting the method keeps the pending + * title and renders the raw result content. + */ +export type ToolResultView = GenericResultView | TerminalResultView | DiffResultView | SearchResultView | ReadResultView | WebResultView; +/** + * The default completed card: an optional replacement title and reformatted + * content. Omit a field to keep the pending title / render the raw result content. + */ +export interface GenericResultView { + card: 'generic'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** + * UI-facing result content (harness {@link ContentBlock}s), reformatted from + * the model-facing result. Omit to let the UI render the raw result content. + */ + content?: ContentBlock[]; +} +/** + * The completed state of a {@link TerminalCallView}: the captured output and exit + * status. A capable UI renders `output` in the terminal card and shows an + * exit-status pill; an incapable UI gets a fenced ```console fallback the BRIDGE + * derives from `output` (the tool does not double-encode it). + */ +export interface TerminalResultView { + card: 'terminal'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** Captured command output (stdout+stderr as the tool chooses to combine them). */ + output?: string; + /** + * Process exit code, when the run ended by exiting (not a signal). Lets a + * capable UI show an exit-status pill. Omit when killed by a signal or unknown. + */ + exitCode?: number; + /** Signal name that killed the process (e.g. `SIGTERM`). Mutually exclusive with `exitCode`. */ + signal?: string; +} +/** + * A completed file mutation rendered as an inline diff card, the result-time + * analogue of {@link DiffCallView}. Because a completed UI update replaces the + * pending card content, mutation tools return this even when it repeats the + * call-time diff; otherwise raw result text would replace the diff. + */ +export interface DiffResultView { + card: 'diff'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** The change to show, in file order — applied contextual hunks, or a whole-file diff when there is no before-image. */ + diffs: FileDiff[]; +} +/** One matched line inside a {@link SearchFileMatches} group: its 1-based line number and text. */ +export interface SearchLineMatch { + /** 1-based line number of the match within its file. */ + lineNumber: number; + /** The matched line text, as the tool surfaced it (the per-line preview budget already applied). */ + line: string; +} +/** One file's grouped content matches for a {@link SearchMatchesResultView}, in first-seen file order. */ +export interface SearchFileMatches { + /** The file the matches belong to (the model-facing display path). */ + path: string; + /** The file's matched lines, in output order. */ + matches: SearchLineMatch[]; +} +/** + * A completed content search (`grep`) rendered as a search card whose matches are + * grouped by file, so a capable UI can list each file as an expandable group of + * its matched lines. `shape: 'matches'` discriminates this variant from the path + * variant ({@link SearchPathsResultView}) within {@link SearchResultView}. The + * discriminant is `shape`, not `kind`, so it never collides with the + * {@link ToolCallKind} `kind` an icon-picking bridge reads off a call view. + */ +export interface SearchMatchesResultView { + card: 'search'; + shape: 'matches'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** Matched lines grouped by file, in first-seen file order. */ + files: SearchFileMatches[]; + /** + * Whether the tool capped the inline result: `files` carries only the retained + * matches, not every match the search found. A UI shows a capped indicator so it + * never presents a partial group as complete. + */ + truncated: boolean; + /** Total matches the search found before capping (equals the retained count when not `truncated`). */ + total: number; +} +/** + * A completed path search (`glob`) rendered as a search card whose result is a flat + * path list. `shape: 'paths'` discriminates this variant from the grouped-matches + * variant ({@link SearchMatchesResultView}) within {@link SearchResultView}. + */ +export interface SearchPathsResultView { + card: 'search'; + shape: 'paths'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** The discovered paths, in the tool's result order (the retained page when `truncated`). */ + paths: string[]; + /** + * Whether the tool capped the inline result: `paths` carries only the retained + * page, not every path the search found. A UI shows a capped indicator so it + * never presents a partial list as complete. + */ + truncated: boolean; + /** Total paths the search found before capping (equals `paths.length` when not `truncated`). */ + total: number; +} +/** + * A completed search rendered as a search card, the result-time view a discovery + * tool (`grep`, `glob`) returns from `presentResult`. One `card: 'search'` view + * with two `shape`-discriminated variants: grouped-by-file content matches + * ({@link SearchMatchesResultView}) and a flat path list + * ({@link SearchPathsResultView}). Both carry a `truncated`/`total` signal so a UI + * never presents a capped result as complete. The view carries no result text: a + * UI without a search card falls back to the raw `tool/result` content. There is + * no call-time analogue: a search call stays a {@link GenericCallView} + * (`kind: 'search'`) because the pending state has no matches or paths to show — + * the structured shape exists only after `execute`. + */ +export type SearchResultView = SearchMatchesResultView | SearchPathsResultView; +/** + * A completed file read rendered as a line-numbered, optionally syntax-highlighted + * code view by a capable UI. Set by a tool whose call reads file text (e.g. + * `read`); the pending state stays a {@link GenericCallView} (`kind: 'read'`) + * because a call carries no content until `execute` returns. The structured + * `lines`/`path`/`lang`/`totalLines` fields cannot be reconstructed from the + * model-facing result text alone, so the read tool projects them through its + * `output.presentationMeta` (persisted with the session log) and `presentResult` + * narrows that metadata back into this view on live and replay paths alike. A UI + * without the read capability falls back to `content` (the model-facing text with + * its envelope stripped), so this view degrades to the generic text card. + */ +export interface ReadResultView { + card: 'read'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** The read file's path (the model-facing path; the bridge relativizes it). */ + path: string; + /** + * The 1-based first line the window requested, preserved even when `lines` is + * empty (a byte cap below the first selected line yields an empty window) so a + * UI knows where the window starts and where a continuation resumes. + */ + offset: number; + /** The returned window's lines, in file order, each keeping its file line number. */ + lines: ReadFileLine[]; + /** Exact total line count in the file, so a UI can show a "showing N of M" affordance. */ + totalLines: number; + /** + * A syntax-highlighting language hint derived from the file extension (e.g. + * `ts`, `py`), or omitted when the extension maps to no known language so a UI + * renders the lines as plain text. + */ + lang?: string; + /** + * The model-facing result content with its envelope stripped, for a UI without + * the read capability. Omit to let such a UI render the raw result content. + */ + content?: ContentBlock[]; +} +/** + * One citeable source in a completed {@link WebSearchResultView}, the faithful + * projection of one web-search source. The presentation projection of `dsh-web`'s + * `WebSearchSource`: that Service Definition type is authoritative (core cannot depend + * on the web Service Definition, so the two are declared separately and MUST evolve together). + * A web tool projects this shape through `output.presentationMeta` because the + * render text cannot losslessly carry it (see the web-result-card Agent Note); its + * `presentResult` reads it back. + */ +export interface WebSource { + /** The source URL. */ + url: string; + /** The source title, when the provider returned one. */ + title?: string; + /** A short excerpt or summary, when the provider returned one. */ + snippet?: string; + /** Publication/crawl timestamp as a provider-supplied ISO-8601 string, when present. */ + publishedAt?: string; +} +/** + * A completed web retrieval rendered as a structured card by a capable UI. Set + * by a web tool whose call retrieves from the web (`web_search`, `web_fetch`). + * One `kind`-tagged union carries both shapes because both are web retrieval and + * a UI renders them with one component family; a UI switches on `kind`. An + * incapable UI falls back to the raw `tool/result` content (this view carries no + * `content` copy — see the web-result-card Agent Note). This is the result-time + * analogue of the `web_search`/`web_fetch` calls' generic call views + * (`kind: 'search'`/`'fetch'`); those tools keep their generic pending card and + * add only this completed card. + * + * The `kind` field here is this union's own discriminant, NOT a + * {@link ToolCallKind}: the two values deliberately match the tools' pending + * `ToolCallKind` (`'search'`/`'fetch'`) so a call and its result read as one + * category, but a new arm is a union edit plus a consumer branch, not any + * arbitrary `ToolCallKind` value. + */ +export type WebResultView = WebSearchResultView | WebFetchResultView; +/** + * The completed state of a `web_search` call: the structured sources the model + * cited, an optional provider answer, and whether the source list was cut to the + * result cap. A capable UI renders the sources as a citation list; a UI without + * the `web` capability falls back to the raw `tool/result` content. + */ +export interface WebSearchResultView { + card: 'web'; + kind: 'search'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** The faithful, structured sources — the field render text cannot losslessly carry. */ + sources: WebSource[]; + /** The provider-generated answer text, when any. */ + answer?: string; + /** True when the web service cut the source list to honor the result cap. */ + truncated: boolean; +} +/** + * The completed state of a `web_fetch` call: the fetched URL, its HTTP status, + * and whether the content was cut. The body itself is already markdown in the + * raw `tool/result` content, so this card carries only the retrieval summary and + * a UI without the `web` capability falls back to that content. + */ +export interface WebFetchResultView { + card: 'web'; + kind: 'fetch'; + /** Replacement title for the completed call. Omit to keep the pending-state title. */ + title?: string; + /** The final URL after allowed redirects. */ + url: string; + /** HTTP status code of the fetched response. */ + statusCode: number; + /** + * True when the provider capped the decoded body, or the output cap or a + * pre-conversion source cut trimmed the rendered text (the effective + * truncation the model-facing text also reflects). + */ + truncated: boolean; +} +//# sourceMappingURL=presentation.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.js new file mode 100644 index 0000000..a83855c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/presentation.js @@ -0,0 +1,8 @@ +/** + * Tool render-intent vocabulary: the provider-neutral types a tool declares via + * `ToolDefinition.presentCall`/`ToolDefinition.presentResult` to say how one of its calls + * renders in a UI (an editor's tool-call card, a CLI log line). + * @module @deepseek-ai/dsh-tools/src/presentation + */ +export {}; +//# sourceMappingURL=presentation.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.d.ts new file mode 100644 index 0000000..e59df0b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.d.ts @@ -0,0 +1,49 @@ +/** + * Code Mode codegen — Python flavor. The pure projection from registered tool schemas to the + * Python SDK text the model programs against under `runtime.language === 'python'`. Sibling of + * {@link ./ts-types.ts | ts-types.ts}; the two files are two projections of the same registry + * store, keyed by the loaded {@link @deepseek-ai/dsh-code-runtime#CodeRuntime.language | code + * runtime's language}. + * + * Under `mode: 'code'` the native tool schemas are omitted from the request, so this generated + * SDK is the model's ONLY source for each tool's argument names, required fields, types, + * descriptions, and canonical output shapes; under `mode: 'both'` the native schemas ship + * alongside it and it is one of two. Object-shaped arguments and outputs therefore render as one + * named `TypedDict` per tool (and per nested object), not an opaque `dict[str, Any]`, so the + * shape survives into the program under the mode that has nothing else to carry it. + * @module @deepseek-ai/dsh-tools/src/py-types + */ +import type { ToolSdkSchema } from './ts-types.ts'; +/** + * Map one JSON-Schema node to a context-free Python type expression from the + * `typing` module. Handles every unified schema construct — `object` (degraded + * to `dict[str, Any]`: naming a `TypedDict` requires the render context that + * {@link renderToolsSdkPy} supplies), `const`/`enum` (→ `Literal[...]`), + * `oneOf` (→ union), `string`/`number`/`integer`/`boolean`/`null`, `array` + * (`items` → `list[T]`) — and returns `Any` for an unsupported or malformed + * schema, matching the TS flavor's `unknown` fallback. Type annotations in the + * emitted SDK are advisory: Python does not enforce them at runtime. + * @param schema - the JSON-Schema node. + * @returns the Python type text. + */ +export declare function jsonSchemaToPy(schema: unknown): string; +/** + * Render the full `tools:sdk` prompt section under `runtime.language === + * 'python'`: the Python-flavored usage instructions plus one named `TypedDict` + * per tool argument or output object (and per nested object) and one awaitable + * method per visible tool on a `Tools` protocol — typed args in, the tool's + * canonical output value out — with a `tools: Tools` singleton the model calls + * into. The `typing` import line lists exactly the symbols the render used. + * Deterministic — tools are emitted in lexicographic name order, and class + * declarations precede the protocol in that same order (nested classes before + * the parent that references them), so an unchanged tool set produces + * byte-identical text across assemblies. The sort is not a total order on + * byte-equal names, so two schemas sharing a name would render in argument + * order; the caller's visible-capability map is keyed by name, so the input + * never carries a duplicate. + * @param schemas - the tool schemas plus canonical output schemas to declare + * (the caller excludes `run_code` itself). + * @returns the complete section text. + */ +export declare function renderToolsSdkPy(schemas: ToolSdkSchema[]): string; +//# sourceMappingURL=py-types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.js new file mode 100644 index 0000000..9ad4033 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/py-types.js @@ -0,0 +1,788 @@ +/** + * Code Mode codegen — Python flavor. The pure projection from registered tool schemas to the + * Python SDK text the model programs against under `runtime.language === 'python'`. Sibling of + * {@link ./ts-types.ts | ts-types.ts}; the two files are two projections of the same registry + * store, keyed by the loaded {@link @deepseek-ai/dsh-code-runtime#CodeRuntime.language | code + * runtime's language}. + * + * Under `mode: 'code'` the native tool schemas are omitted from the request, so this generated + * SDK is the model's ONLY source for each tool's argument names, required fields, types, + * descriptions, and canonical output shapes; under `mode: 'both'` the native schemas ship + * alongside it and it is one of two. Object-shaped arguments and outputs therefore render as one + * named `TypedDict` per tool (and per nested object), not an opaque `dict[str, Any]`, so the + * shape survives into the program under the mode that has nothing else to carry it. + * @module @deepseek-ai/dsh-tools/src/py-types + */ +import { assertSupportedJsonSchema } from "./json-schema.js"; +/** + * The reference grammar's `xid_start xid_continue*` — the set + * `str.isidentifier()` accepts on a CPython whose Unicode tables match the + * engine's. See {@link isBareIdentifier} for what a version skew does. + */ +const IDENTIFIER = /^[\p{XID_Start}_]\p{XID_Continue}*$/u; +/** + * Whether a name can be emitted as a bare Python identifier rather than + * routed to the subscript/`dict[str, Any]` path. + * + * Python identifiers are not ASCII: `路径` is as legal a field name as `path`, + * and rejecting it would degrade the whole enclosing object, dropping every + * field's name, requiredness, and type — information whose only source under + * `mode: 'code'` is this generated text. + * + * NFKC stability is a second and separate condition, because CPython + * normalizes identifiers at compile time while JSON keys are compared as + * written: `field` would be declared and reachable as `field`, so the SDK would + * advertise a key under a spelling the harness never accepts, and two keys + * that normalize together would collapse into one declaration. Those names + * take the subscript path, which carries their exact bytes. + * + * `IDENTIFIER` matches `str.isidentifier()` (measured on Node 22.23.1 vs + * CPython 3.9.6 tables): the equivalence holds inside the two versions' shared + * tables, and the skew characters below are exactly where that pair diverges. + * The predicate as a whole is deliberately stricter than `isidentifier()`, + * which does not test NFKC stability: `'field'.isidentifier()` is True and + * this returns false. + * + * Both conditions are evaluated against the ENGINE's Unicode tables, and the + * two sides are versioned independently — `\p{XID_Start}`/`\p{XID_Continue}` + * follow the running engine (Node 22.23.1 reports Unicode 17.0) while CPython + * follows its own (3.9.6 reports 13.0.0). The skew is not symmetric. A CPython + * older than the engine is the dangerous direction: a character added to either + * property since its tables (U+10570 Vithkuqi and U+1E290 Toto, 14.0; U+1E4D0 + * Nag Mundari, 15.0; U+1C89 Cyrillic TJE, 16.0 — ages per `DerivedAge.txt`; all + * four are NFKC-stable and accepted here, and all four are `Cn` on that 3.9.6, + * which rejects them) is emitted bare and its tokenizer refuses the character, + * taking the whole SDK block down — the same parseability invariant + * {@link UNPRINTABLE}, {@link LONE_SURROGATE} and {@link MAX_LIST_NESTING} + * exist for. Both properties carry it: a character added only to `XID_Continue` + * passes the trailing `\p{XID_Continue}*` in a tail position and fails the same + * way — U+200C ZWNJ and U+200D ZWJ are that case, gaining `XID_Continue` in UCD + * 15.1 and absent from it in 13.0.0, 14.0.0 and 15.0.0, so `a\u{200C}b` is + * emitted bare here while `isidentifier()` is False on 3.9.6 and on 3.12.13 + * (15.0.0). A CPython newer than the engine only routes a legal name to the + * subscript/`dict[str, Any]` path: less readable, still correct. The NFKC + * condition reduces to the same skew, since normalization stability guarantees + * an assigned character's normalization never changes afterwards. + * + * This predicate is not the only reader of engine tables. {@link camelCase} + * reads them at three further points — its split set, its head test, and its + * `toUpperCase()` case mapping — and this predicate's verdict gates none of + * them: a class name derived there reaches emitted text whenever any object + * shape in the tool's schema declares a `TypedDict`, including for a tool this + * predicate rejected. A tool named `zz-\u{1E4D0}x` with such parameters never + * reaches the skew here (the `-` rejects it outright) yet emits `class + * Zz\u{1E4D0}xArgs`, which that same 3.9.6 refuses — Nag Mundari arrived two + * releases after its tables. The case mapping is a separate table rather than + * an XID membership test, and it fails on names both conditions above accept: + * `\u{019B}` is XID_Start and NFKC-stable, so this predicate accepts it and + * `async def \u{019B}` compiles on 3.9.6, but Node uppercases it to + * `\u{A7DC}` — unassigned in that CPython, whose own `.upper()` is the identity + * here — and the declared `class \u{A7DC}Args` fails with `invalid + * non-printable character U+A7DC`. Closing the exposure therefore covers all + * four read points, not this predicate alone; it needs the target interpreter's + * version, which the backend reporting `language: 'python'` owns; the + * language-dispatch Agent Note records the deferral. + * + * The `ts-types` sibling keeps its own ASCII rule rather than sharing this + * one: ECMAScript identifiers are a different set (`$`) and are never + * normalized, so one predicate cannot be correct for both. ZWJ/ZWNJ are not + * part of that difference — both sets carry them on the engine's tables; what + * separates the two there is the CPython table version above. + * @param name - the raw schema field or tool name. + * @returns whether the name can be emitted bare. + */ +function isBareIdentifier(name) { + return IDENTIFIER.test(name) && name.normalize('NFKC') === name; +} +/** + * Python hard keywords: reserved everywhere, so a tool or field named + * ``class`` or ``lambda`` is legal on the wire but not as an attribute + * (``tools.class`` would be a SyntaxError in the model program) and not as a + * class-syntax `TypedDict` field. Such a tool renders under subscript access + * and such an object degrades to ``dict[str, Any]`` — the model still reaches + * every tool and field without collisions. + * Soft keywords (``match``, ``case``, ``type``, ``_`` — the language + * reference's whole set) are deliberately ABSENT: each is special in exactly + * one syntactic position — a statement head (``match``, ``type``), a ``match`` + * statement's clause head (``case``), or a pattern (``_``) — so ``match: str`` + * as a field and ``async def match(...)`` as a method are both legal, and + * including them would needlessly degrade common search/regex tool fields to + * ``dict[str, Any]``. Underscore-leading names are handled separately, not + * here: a non-dunder ``__token`` name-mangles, a dunder present on + * ``object``/``type`` resolves before the proxy hook, and implicit + * special-method lookup bypasses the hook. + */ +const RESERVED = new Set([ + 'False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', + 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', + 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', + 'return', 'try', 'while', 'with', 'yield', + // Not a keyword, but CPython refuses to ASSIGN it at compile time + // (`SyntaxError: cannot assign to __debug__`), which is what a TypedDict + // field, a parameter name, and a keyword argument all are. + '__debug__', +]); +/** `typing` symbols this module may emit, in the deterministic import order. */ +const TYPING_ORDER = ['Any', 'Literal', 'NotRequired', 'Protocol', 'TypedDict']; +/** `indent`-deep line prefix (four spaces per level to match PEP 8 output). */ +function pad(indent) { + return ' '.repeat(indent); +} +/** + * The `Cc` code points that survive the whitespace collapse in {@link describe} + * and have no printable form: the C0 controls, DEL, and the C1 controls. Only + * U+0009 to U+000D are absent, because ECMAScript `\s` already collapsed them — + * `\s` is TAB/VT/FF/SP/NBSP/ZWNBSP/Zs plus LF/CR/LS/PS, so no C1 code point is + * in it and the whole U+0080 to U+009F block reaches this rule intact. Those + * are not hypothetical input: they are what Windows-1252 bytes 0x80 to 0x9F + * (smart quotes, em dash) become when decoded as Latin-1. + * CPython rejects source containing a NUL outright + * (`SyntaxError: source code string cannot contain null bytes`), whether it + * sits in a docstring or in a comment, so one such byte anywhere in a schema + * description would make the whole generated SDK unparseable — under + * `mode: 'code'`, the model's only declaration of the tools. The rest are + * legal but invisible; escaping them with the same rule keeps the emitted text + * readable and the treatment uniform. + * + * The boundary is the category, not per-code-point addressability: `\xNN` + * addresses U+0000 to U+00FF, so one escape form covers `Cc` exactly. The + * invisible `Cf` formatting characters pass through by design — of them only + * U+00AD soft hyphen would fit `\xNN` at all, and escaping that one while + * U+200B ZWSP, U+200E/U+200F bidi marks, and U+2060 word joiner passed through + * would leave a rule that is neither category- nor addressability-shaped. The + * whole family is legal in both consumers, since only LF and CR terminate a + * Python string literal or a `#` comment. That set is the tokenizer's, not + * `str.splitlines()`': NEL (U+0085), LS (U+2028), and PS (U+2029) split a + * string at run time but do not end a physical line in source — measured on + * CPython 3.9.6 and 3.12.13, each accepted in both positions with the value + * round-tripping — so they are safe raw wherever they reach emitted text + * unescaped, which for all three is `JSON.stringify`, at two call sites: + * {@link pyScalar}'s literal path, and the subscript tool-name comment's own + * call, which a name carrying any of them always reaches, none being + * `XID_Continue`. The `description` path escapes NEL under the class above and + * folds LS and PS in {@link describe}'s `\s+` collapse, both being `\s`. + */ +const UNPRINTABLE = /[\u0000-\u0008\u000e-\u001f\u007f-\u009f]/g; +/** + * Unpaired surrogate code points, escaped by {@link describe} as `\uNNNN` — + * its own form, since `\xNN` stops at U+00FF. The `u` flag is what makes this + * the LONE ones: in Unicode mode a well-formed pair is a single astral code + * point outside D800 to DFFF, so an emoji in a description survives untouched. + * + * This is the NUL case from {@link UNPRINTABLE}, not the invisible-character + * case. Python source must be UTF-8-encodable and a lone surrogate is not, so + * `compile()` raises `UnicodeEncodeError: surrogates not allowed` for one + * anywhere in the text — measured on 3.9 for a string literal and for a `#` + * comment alike. A raw or MCP tool description reaches this: `JSON.parse` on a + * wire `"\ud800"` escape yields exactly such a code point. + */ +const LONE_SURROGATE = /[\ud800-\udfff]/gu; +/** + * The collapsed one-line `description` of a schema node (byte-stable across + * formatting churn), or `undefined` when the node carries none. Every caller + * passes an object — a validated property node, the `ToolSdkSchema` itself, or + * the `{ description }` wrapper {@link docLines} synthesizes — so only the + * description field needs guarding. A description that collapses + * to nothing (empty, or whitespace only) is `undefined` too: it documents the + * node no better than an absent one, and emitting it would leave an empty + * `"""` docstring or a bare `# ` line in the SDK. Only ECMAScript whitespace + * folds, so a description of whitespace plus one surviving control character is + * NOT absent: it collapses to that character's visible escape. + * + * Control characters left over after the whitespace collapse are rendered as + * their `\xNN` escapes (see {@link UNPRINTABLE}) and unpaired surrogates as + * their `\uNNNN` escapes (see {@link LONE_SURROGATE}); the escape's own backslash is + * emitted literally by both consumers, since {@link docLines} doubles it into a + * Python source escape and a `#` comment carries it verbatim. + */ +function describe(schema) { + const description = schema.description; + if (typeof description !== 'string') + return undefined; + const collapsed = description + .replace(/\s+/g, ' ') + .replace(UNPRINTABLE, char => `\\x${char.charCodeAt(0).toString(16).padStart(2, '0')}`) + .replace(LONE_SURROGATE, char => `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`) + .trim(); + return collapsed.length === 0 ? undefined : collapsed; +} +/** + * One-line docstring for a tool `description`, or no lines when there is none. + * Backslashes are doubled first, every quote is escaped, and a trailing + * backslash cannot survive: a description ending in `"` or an odd backslash + * would otherwise merge with (or escape) the closing triple quote and make + * the generated block — Code Mode's only SDK — syntactically invalid Python. + */ +function docLines(description, indent) { + const collapsed = describe({ description }); + if (collapsed === undefined) + return []; + const escaped = collapsed.replaceAll('\\', '\\\\').replaceAll('"', '\\"'); + return [`${pad(indent)}"""${escaped}"""`]; +} +/** + * CamelCase a name into a Python type identifier: non-identifier characters + * split words, `_` splits too (it is `XID_Continue`, so the split set names it + * explicitly), and a head that cannot start an identifier takes a `Tool` + * prefix. Unicode survives, so a `路径` field yields `路径`-based class names + * instead of collapsing to the bare prefix. A character that is not + * `XID_Continue` splits even when it is a letter, so a name whose NFKC folding + * would leave the identifier set is not carried through — the split set is the + * grammar's, not an ASCII approximation of it. + * + * The result is NFKC-normalized: these names are generated, never matched + * against a JSON key, so normalizing is free here and keeps what CPython + * compiles identical to what is emitted — unlike {@link isBareIdentifier}, + * which must reject unstable names outright. Normalizing AFTER the prefix + * decision is what makes that hold at the seam the prefix creates: `Tool` + + * a combining-mark head composes there (`U+0301` gives `Tooĺ`, U+013A), so + * normalizing only the un-prefixed part would emit a name CPython compiles to + * a different symbol. The second call is idempotent on the un-prefixed arm. + * + * The split set, the head test, and `toUpperCase()` all read the engine's + * Unicode tables, so this function carries the same version skew + * {@link isBareIdentifier} documents, by paths independent of it: a class name + * derived here reaches emitted text whenever any object shape in the tool's + * schema declares a `TypedDict`, and the predicate's verdict on the tool name + * does not gate that. The case mapping is the one that can fail on a name the + * predicate accepted; the worked example is there. + * @param raw - the schema field or tool name to derive from. + * @returns a class-name segment safe to emit. + */ +function camelCase(raw) { + const joined = raw + .split(/[^\p{XID_Continue}]+|_+/u) + .filter(part => part.length > 0) + .map(part => `${part.charAt(0).toUpperCase()}${part.slice(1)}`) + .join('') + .normalize('NFKC'); + return (/^\p{XID_Start}/u.test(joined) ? joined : `Tool${joined}`).normalize('NFKC'); +} +/** Class-name base cap keeping each emitted name — and total text — linear in schema depth. */ +const MAX_CLASS_NAME_BASE = 120; +/** + * Deepest `list[…]` nesting emitted into one annotation before the item type + * degrades to `Any`. CPython's tokenizer rejects a logical line holding more + * than 200 simultaneously-open brackets (`MAXLEVEL`, `SyntaxError: too many + * nested parentheses`), so an array chain deeper than that would render an SDK + * block that is not valid Python at all — the same failure the docstring + * escaping in {@link docLines} exists to prevent. 180 leaves headroom for the + * few brackets an annotation can add around the chain, all of which count + * toward the same limit. Per emission site, counting brackets open at the + * chain's innermost point: + * + * - Return annotation, `async def f(self, args: X) -> chain:` — 180 `list[` + * plus an innermost `Literal[`. The parameter list's `(` closed at the `)` + * before the `->`, so it is NOT open here: 181. + * - TypedDict field, `field: NotRequired[chain]` — a class-body line with no + * other open bracket, and its children start at `listDepth: 1` to reserve + * the `NotRequired[`, so 179 `list[` plus `Literal[`: 181. Required fields + * share that start for uniformity, spending one level of representable depth + * on a bracket they never emit. + * - Argument annotation, `async def f(self, args: chain) -> Y:` — the `(` IS + * still open around it: 180 `list[` plus `Literal[` plus the paren, 182, the + * worst case. Reachable only through a raw `register()` whose `parameters` + * is an array reached from the root through `oneOf` arms alone — the root + * array itself, or one nested under any depth of unions, since an arm + * inherits the enclosing depth unchanged (`A | B` opens no bracket). An + * object ancestor takes it out of this case: its fields restart the chain at + * the 181 site. `defineTool` compiles an object root, so the annotation is a + * bare TypedDict class name or a one-bracket `dict[str, Any]` when that + * object degrades — never a chain. + * + * A CPython grammar limit, not a deployment choice, so it is fixed rather than + * configurable. The sibling `ts-types` renderer needs no counterpart: nothing + * in the TypeScript grammar bounds nesting, and its SDK block is never type- + * checked. Only bracket nesting counts — a `oneOf` renders as a flat `A | B` + * chain and nested objects render as separate `class` statements, so neither + * accumulates open brackets at any depth. The invariant this cap serves is + * grammatical validity; see the `oneOf` arm in {@link renderType} for the one + * interpreter limit deliberately left uncapped. + */ +const MAX_LIST_NESTING = 180; +/** + * Cap a class-name base at {@link MAX_CLASS_NAME_BASE} (see the callers for + * why capping keeps the render linear). `slice` counts UTF-16 code units, so + * an astral character straddling the boundary would be cut in half and leave a + * lone surrogate — not an identifier character, and not even well-formed text; + * drop it rather than emit it. + */ +function capClassNameBase(base) { + if (base.length <= MAX_CLASS_NAME_BASE) + return base; + const capped = base.slice(0, MAX_CLASS_NAME_BASE); + return /[\uD800-\uDBFF]$/.test(capped) ? capped.slice(0, -1) : capped; +} +/** + * Reserve a unique class name from a base, suffixing `2`, `3`, … on collision. + * The base is capped at {@link MAX_CLASS_NAME_BASE} first: child class names + * derive from their parent's allocated name (`ParentChild`), so an unbounded + * schema of single-field objects would otherwise grow each name by one field + * per level and the sum of all names to Θ(depth²). Capping the base keeps each + * name — and the total emitted text — linear in depth. Collisions resume from + * the per-base counter in `state.nextClassCounter` rather than rescanning from + * `2`, so a deep chain sharing one capped base stays O(1) per allocation + * (amortized) instead of Θ(depth²) in time. + */ +function allocateClassName(base, state) { + const capped = capClassNameBase(base); + let name = capped; + if (state.usedClassNames.has(name)) { + let n = state.nextClassCounter.get(capped) ?? 2; + while (state.usedClassNames.has(`${capped}${n}`)) + n++; + name = `${capped}${n}`; + state.nextClassCounter.set(capped, n + 1); + } + state.usedClassNames.add(name); + return name; +} +/** + * Append a child-name segment to a parent class-name base, capping the result + * at {@link MAX_CLASS_NAME_BASE}. Capping AT PROPAGATION (not only inside + * {@link allocateClassName}) keeps each level O(1): a deep `oneOf`- or + * object-chain would otherwise carry an ever-growing ConsString down the tree + * and re-materialize it (via `.length`/`.slice`) at every level — Θ(depth²). + * The bounded base plus the collision counter still yields unique names. + * + * The join is NFKC-normalized because both sides are separately normalized yet + * their concatenation need not be: a base ending in a Hangul L jamo or LV + * syllable composes with a following V or T jamo head (`가` + `ᆨ` gives `각`), + * so the emitted class name would differ from the symbol CPython compiles, and + * two byte-distinct names could fold onto one — `usedClassNames` dedupes by the + * raw bytes, so the collision counter would not see it. Normalizing costs + * O(cap + segment) per level, the same order as the `slice` it feeds. The other + * two join points need no counterpart: `Args`/`Output` start with `A`/`O` and + * {@link allocateClassName}'s suffix is digits, none of which compose backwards. + */ +function childClassName(base, segment) { + return capClassNameBase(`${base}${segment}`.normalize('NFKC')); +} +/** + * Render one validated scalar as Python literal text (`True`/`False`, + * JSON-quoted strings, bare numbers). `null` cannot reach here: the `null` + * type renders directly as `None`, and the unified validator rejects a null + * `const`/`enum` entry on every other scalar type. + * + * A beyond-safe-range integral number takes `BigInt` digits rather than + * `String`: Python integers are arbitrary-precision, so the emitted digits ARE + * the value the model programs against, and `String` can give a different + * integer than the double holds (`2 ** 60` prints the rounded `...847000`, not + * the exact `...846976`) or no integer literal at all (`1e21` prints `1e+21`). + * `String`'s rounding is not a bug in it: `Number::toString` emits the shortest + * decimal string that re-reads to the same double, then pads to the exponent + * with zeros (1 significant digit for `1e20`, 16 for `2 ** 60`) — and when the + * shortest string is shorter than the double's exact value, those padded digits + * name an integer no double holds. Passing one back would have to cross the + * argument boundary as a JSON number — a double again — so the SDK would + * document a value no program can pass. `BigInt` needs no case split: where + * `String` is already exact (`2 ** 53`, `1e20`) the two agree byte for byte, + * and where it is not, `BigInt` is the exact one. The TS flavor needs no + * counterpart at all: its literal is re-read by a JS parser back into the same + * double. + * + * `JSON.stringify` is also what keeps this path's output parseable, and it is + * the only thing that does. It covers both classes of hazard: the two kinds of + * code point CPython refuses anywhere in source — NUL among the C0 controls, + * and the whole D800–DFFF unpaired-surrogate block, escaped under ES2019 + * well-formed stringification, which the engines range guarantees — and the + * ones that break this line in particular, a bare `"` closing the literal + * early, a trailing odd backslash eating the closing quote, and a bare LF/CR + * ending it before its terminator. The `description` path carries + * {@link UNPRINTABLE} and {@link LONE_SURROGATE} because nothing quotes it, + * and folds newlines in {@link describe}. + * + * That leans on a coincidence worth naming: every escape `JSON.stringify` can + * emit (`\"`, `\\`, `\b`, `\f`, `\n`, `\r`, `\t`, `\uXXXX`) is also a Python + * escape denoting the same character, so the emitted `Literal[...]` both + * parses and decodes back to the value the schema declared. DEL, the C1 + * controls (NEL among them), and LS/PS (U+2028/U+2029) do reach it raw — + * legal but invisible, byte-for-byte as in the TS flavor; escaping them is a + * both-flavors change. Those last three are legal here for the reason + * {@link UNPRINTABLE} records: they are `str.splitlines()` boundaries, not + * tokenizer line terminators. The subscript tool-name comment quotes its name + * through its own call to the same `JSON.stringify`, never through this + * function, and inherits both halves — escapes and pass-throughs alike. + */ +function pyScalar(value) { + if (value === true) + return 'True'; + if (value === false) + return 'False'; + if (typeof value === 'string') + return JSON.stringify(value); + if (typeof value === 'number' && Number.isInteger(value) && !Number.isSafeInteger(value)) { + return BigInt(value).toString(); + } + return String(value); +} +/** + * Render a validated scalar `const`/`enum` as `Literal[...]`, falling back to + * the broad type. Deliberately deviates from PEP 586, which restricts `Literal` + * parameters to int/bool/str/bytes/enum/None: a non-integral number + * `const`/`enum` emits a float literal (`Literal[1.5]`) a strict checker would + * reject. An integral one does not deviate — {@link pyScalar} emits int digits, + * including for the beyond-safe-range values it widens through `BigInt`, and + * PEP 586 admits int parameters. Harmless either way — the stub is advisory + * prompt text, only required to parse — and keeping the exact value + * communicates the constraint to the model. + */ +function renderConstrainedScalar(node, broad, state) { + if (node.const !== undefined) { + state.typing.add('Literal'); + return `Literal[${pyScalar(node.const)}]`; + } + if (node.enum !== undefined) { + state.typing.add('Literal'); + return `Literal[${node.enum.map(pyScalar).join(', ')}]`; + } + return broad; +} +/** + * Map one JSON-Schema node to a Python type expression, threading `state` to + * collect the `TypedDict` declarations and `typing` symbols a full render + * needs. `className` is the name to give an object node with properties (and + * the prefix for its nested objects). Handles every unified schema construct — + * `oneOf` (→ `X | Y`), `const`/`enum` (→ `Literal[...]`), `integer` (→ `int`), + * `null` (→ `None`) — and degrades an unsupported or malformed schema to `Any` + * without throwing, the same trusted-after-validation stance as the sibling + * {@link ./ts-types.ts | ts-types} renderer. {@link jsonSchemaToPy} is the + * context-free entry point; this is the collecting core. + */ +function renderType(schema, className, state) { + const newFrame = (schema, className, listDepth) => ({ schema, className, phase: 'start', listDepth, children: [], childIndex: 0, childTypes: [], entries: [] }); + try { + // Validate the WHOLE tree once, then trust it — the same contract the + // sibling ts-types renderer follows at a typed same-process boundary. Every + // node past this point is a validated JSON-schema node, so the walk reads + // its fields without re-checking. An unsupported or malformed schema throws + // here (before anything is emitted) and degrades to `Any`, the Python + // counterpart of the TS flavor's `unknown`. + assertSupportedJsonSchema(schema); + const frames = [newFrame(schema, className, 0)]; + let result; + /* jscpd:ignore-start -- the explicit-stack walk skeleton deliberately parallels + ts-types.ts's renderSupportedSchema; the two sibling renderers keep symmetric shapes. */ + const finish = (type) => { + frames.pop(); + const parent = frames.at(-1); + if (parent === undefined) + result = type; + else + parent.childTypes.push(type); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === undefined) + break; + if (frame.phase === 'children') { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === undefined) + throw new Error('missing python render child'); + frame.childIndex++; + frames.push(newFrame(child.schema, child.className, child.listDepth)); + continue; + } + if (frame.kind === 'oneOf') { + // Concatenate incrementally (template literal, not `Array.join`): V8 + // builds a lazy ConsString, so a deep oneOf chain materializes once + // at the root instead of re-materializing the accumulated string at + // every level (which `join` would, making it Θ(depth²)). This matches + // the array arm's template-literal laziness and ts-types' composable- + // document approach — the whole walk stays linear in schema depth. + let union = ''; + for (const [index, childType] of frame.childTypes.entries()) { + union = index === 0 ? childType : `${union} | ${childType}`; + } + finish(union); + continue; + } + /* jscpd:ignore-end */ + if (frame.kind === 'array') { + // `list[A | B]` needs no parentheses in Python. Array frames always + // schedule exactly one child, so its type is present. + /* v8 ignore next -- the ?? arm needs a childless array frame, which start never builds. */ + finish(`list[${frame.childTypes[0] ?? 'Any'}]`); + continue; + } + // typeddict: assemble AFTER the children so any nested class this one + // references is already declared (declaration order = reference order). + const node = frame.node; + const name = frame.allocated; + /* v8 ignore next -- typeddict frames always set node and allocated at start. */ + if (node === undefined || name === undefined) + throw new Error('missing typeddict frame state'); + const required = new Set(node.required); + const lines = [`class ${name}(TypedDict):`]; + for (let index = 0; index < frame.entries.length; index++) { + const entry = frame.entries[index]; + const fieldType = frame.childTypes[index]; + /* v8 ignore next -- entries and childTypes correspond one-to-one. */ + if (entry === undefined || fieldType === undefined) + throw new Error('missing typeddict field type'); + const [field, fieldSchema] = entry; + // The parent node passed assertSupportedJsonSchema, so every property + // value is a validated schema node. + const description = describe(fieldSchema); + if (description !== undefined) + lines.push(`${pad(1)}# ${description}`); + if (required.has(field)) { + lines.push(`${pad(1)}${field}: ${fieldType}`); + } + else { + state.typing.add('NotRequired'); + lines.push(`${pad(1)}${field}: NotRequired[${fieldType}]`); + } + } + // TypedDict syntax cannot express openness, so an open object states it + // in-band: the annotation is advisory either way, and `mode: 'code'` + // omits the native schemas, making this line the model's only signal + // that extra keys are accepted. + if (node.additionalProperties !== false) { + lines.push(`${pad(1)}# Additional keys beyond those declared are allowed.`); + } + // A closed empty object still needs a class body (`pass`) to be valid + // Python; the declared emptiness is the information. + if (lines.length === 1) + lines.push(`${pad(1)}pass`); + state.classes.push(lines.join('\n')); + finish(name); + continue; + } + frame.phase = 'children'; + const node = frame.schema; + if (node.oneOf !== undefined) { + frame.kind = 'oneOf'; + // A union renders as `A | B` — no brackets of its own, so the branches + // inherit the enclosing depth unchanged. + // + // Union LENGTH is deliberately uncapped, unlike list nesting. The two + // limits are different in kind: >200 open brackets is a SyntaxError + // from the tokenizer, so the text is not Python; a long `A | B | …` + // chain is grammatically valid at any length and only defeats CPython's + // C-recursion when `compile()` walks the left-nested BinOp spine + // (measured: 1,000 branches compile, 5,000 raise RecursionError). This + // block is prompt text — nothing compiles it — so that limit costs + // nothing here, while capping would retire the deep-chain tests that + // pin the walk's linear time and the class-name propagation cap. The + // standard this renderer holds is grammatical validity, not + // compilability under one interpreter's stack. + frame.children = node.oneOf.map((branch, index) => ({ schema: branch, className: childClassName(frame.className, `${index + 1}`), listDepth: frame.listDepth })); + continue; + } + if (node.type === undefined) { + state.typing.add('Any'); + finish('Any'); + continue; + } + switch (node.type) { + case 'string': + finish(renderConstrainedScalar(node, 'str', state)); + break; + case 'number': + finish(renderConstrainedScalar(node, 'float', state)); + break; + case 'integer': + finish(renderConstrainedScalar(node, 'int', state)); + break; + case 'boolean': + finish(renderConstrainedScalar(node, 'bool', state)); + break; + case 'null': + finish('None'); + break; + case 'array': { + if (node.items === undefined) { + state.typing.add('Any'); + finish('list[Any]'); + break; + } + // Past MAX_LIST_NESTING another `list[` would push the annotation + // beyond CPython's open-bracket limit and make the whole SDK block + // unparseable, so the chain degrades here instead — an unusable + // annotation either way, and this one is valid Python. + if (frame.listDepth >= MAX_LIST_NESTING) { + state.typing.add('Any'); + finish('Any'); + break; + } + // An array of objects names its item type after the array field. + frame.kind = 'array'; + frame.children = [{ schema: node.items, className: frame.className, listDepth: frame.listDepth + 1 }]; + break; + } + case 'object': { + // A missing `properties` is an empty property map, exactly as the + // unified validator and the TS renderer read it — NOT an unknown + // shape. The openness of the resulting empty object is decided below, + // so a closed empty object still declares an empty TypedDict rather + // than a permissive `dict[str, Any]`. + const entries = Object.entries(node.properties ?? {}); + // An empty `className` marks the context-free `jsonSchemaToPy` entry: + // there is no naming context to declare into, so degrade. This reads + // the CALL's className, not `frame.className`: the marker belongs to + // the whole walk, and frames propagate a derived name (a `oneOf` + // branch of the context-free root gets the index-derived name `1` — + // `childClassName` concatenates and caps, it does not go through + // `camelCase`), so a per-frame read would declare classes the caller + // has no way to receive, under a name that is not even a legal + // identifier: `class 1(TypedDict):`. A field + // name that is not a legal Python attribute is inexpressible as a + // class-syntax `TypedDict` field, so such an object degrades whole. + // A leading-double-underscore non-dunder field (`__token`) would be + // NAME-MANGLED inside class syntax (`_ClassName__token`), describing a + // different JSON key than the registered schema — degrade like any + // other inexpressible field name. + if (className === '' || !entries.every(([name]) => isBareIdentifier(name) && !RESERVED.has(name) && !(name.startsWith('__') && !name.endsWith('__')))) { + state.typing.add('Any'); + finish('dict[str, Any]'); + break; + } + // An OPEN empty object is any dict; a CLOSED empty object declares an + // empty TypedDict so "no keys accepted" survives into the SDK. + if (entries.length === 0 && node.additionalProperties !== false) { + state.typing.add('Any'); + finish('dict[str, Any]'); + break; + } + frame.kind = 'typeddict'; + frame.node = node; + frame.allocated = allocateClassName(frame.className, state); + state.typing.add('TypedDict'); + frame.entries = entries; + // A field annotation is its own logical line, so nesting restarts — + // at 1, reserving the bracket an optional field's `NotRequired[…]` + // wraps around it. frame.allocated was assigned three statements up; + // the ?? arm is for the type system only. + /* v8 ignore next -- allocated is always set before children are built. */ + frame.children = entries.map(([field, child]) => ({ schema: child, className: childClassName(frame.allocated ?? '', camelCase(field)), listDepth: 1 })); + break; + } + /* v8 ignore next 4 -- assertSupportedJsonSchema narrowed this closed type union. */ + default: { + state.typing.add('Any'); + finish('Any'); + } + } + } + /* v8 ignore next -- every root frame produces one expression. */ + return result ?? 'Any'; + } + catch { + // An unsupported or malformed schema failed validation (before any + // emission), or an unreachable internal invariant tripped. Either degrades + // the node to `Any` rather than crashing prompt assembly — the Python + // counterpart of the TS flavor's `unknown` fallback. + state.typing.add('Any'); + return 'Any'; + } +} +/** + * Map one JSON-Schema node to a context-free Python type expression from the + * `typing` module. Handles every unified schema construct — `object` (degraded + * to `dict[str, Any]`: naming a `TypedDict` requires the render context that + * {@link renderToolsSdkPy} supplies), `const`/`enum` (→ `Literal[...]`), + * `oneOf` (→ union), `string`/`number`/`integer`/`boolean`/`null`, `array` + * (`items` → `list[T]`) — and returns `Any` for an unsupported or malformed + * schema, matching the TS flavor's `unknown` fallback. Type annotations in the + * emitted SDK are advisory: Python does not enforce them at runtime. + * @param schema - the JSON-Schema node. + * @returns the Python type text. + */ +export function jsonSchemaToPy(schema) { + // A throwaway state whose class collector never escapes: an object with + // properties has nowhere to declare its TypedDict and degrades to + // dict[str, Any]. renderToolsSdkPy drives the named-TypedDict path. + return renderType(schema, '', { classes: [], usedClassNames: new Set(), nextClassCounter: new Map(), typing: new Set() }); +} +/** The fixed model-facing usage contract rendered above the declarations. */ +const SDK_INSTRUCTIONS = `## Writing code for run_code + +\`run_code\` takes two required arguments: \`code\` — the body of an async Python function (top-level \`await\` and \`return\` both work) — and \`description\`, a short summary of what the program does. At run time exactly two of the names declared below are bound: \`tools\` and \`ToolCallError\`. Everything else is a STATIC STUB describing argument and return types — in particular the \`TypedDict\` classes do NOT exist at run time, so build arguments as plain \`dict\`/\`list\` JSON values: \`await tools.name({"field": 1})\`, never \`FooArgs(field=1)\`, which raises \`NameError\`. Inside the program: + +- Call tools as \`await tools.name(args)\` — subscript access for exotic, reserved, or underscore-leading names: \`await tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value (each method's return type below). Tool arguments must be lossless JSON. +- A FAILED tool call raises \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose message is human-readable — wrap in \`try/except\` to handle and continue. +- Independent read-only calls MAY overlap under \`asyncio.gather\` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with \`await\`. +- Emit the run's answer with \`print(...)\` and/or a top-level \`return \`; the returned value must be lossless JSON. Only what you print and return is program output. A successful tool result containing an image is attached after the run so you can inspect it on the next step; every other intermediate result stays out of the conversation, so extract just what you need. + +The available tools:`; +/** + * Render the full `tools:sdk` prompt section under `runtime.language === + * 'python'`: the Python-flavored usage instructions plus one named `TypedDict` + * per tool argument or output object (and per nested object) and one awaitable + * method per visible tool on a `Tools` protocol — typed args in, the tool's + * canonical output value out — with a `tools: Tools` singleton the model calls + * into. The `typing` import line lists exactly the symbols the render used. + * Deterministic — tools are emitted in lexicographic name order, and class + * declarations precede the protocol in that same order (nested classes before + * the parent that references them), so an unchanged tool set produces + * byte-identical text across assemblies. The sort is not a total order on + * byte-equal names, so two schemas sharing a name would render in argument + * order; the caller's visible-capability map is keyed by name, so the input + * never carries a duplicate. + * @param schemas - the tool schemas plus canonical output schemas to declare + * (the caller excludes `run_code` itself). + * @returns the complete section text. + */ +export function renderToolsSdkPy(schemas) { + const sorted = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0); + const state = { classes: [], usedClassNames: new Set(), nextClassCounter: new Map(), typing: new Set(['Protocol']) }; + // ONE ordered member stream, matching the documented lexicographic contract + // and the TypeScript flavor (which quotes exotic keys in place rather than + // partitioning them out). Interleaving is free here: a comment line between + // two `async def` lines is not a statement, so it changes nothing about how + // the class body parses. + const members = []; + let statements = 0; + for (const schema of sorted) { + const argType = renderType(schema.parameters, `${camelCase(schema.name)}Args`, state); + const outputType = renderType(schema.output, `${camelCase(schema.name)}Output`, state); + if (isBareIdentifier(schema.name) && !RESERVED.has(schema.name) && !schema.name.startsWith('_')) { + // A docstring only documents its method when it is the FIRST statement + // of that method's body. Emitted before the `async def` it would instead + // become the `Tools` class docstring (for the first tool) or a dead + // expression (for every later one), leaving every method undocumented — + // and under `mode: 'code'` this SDK is the model's only description of + // what a tool does. A docstring is a complete body, so the `...` stub is + // only for the description-less case. + const doc = docLines(schema.description, 2); + members.push(doc.length > 0 + ? `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}:` + : `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}: ...`); + members.push(...doc); + statements += 1; + } + else { + // Not reachable as ``tools.name`` — the model reaches it via + // ``tools[name]``. Exotic names and hard keywords are not legal + // attributes at all; an underscore-leading name (``_foo``) IS a legal + // attribute and is routed here anyway, because the forms that break + // split three ways — a non-dunder ``__token`` name-mangles at the CALL + // site, a dunder that exists on ``object``/``type`` (``__class__``, + // ``__doc__``) resolves before ``__getattr__`` ever runs, and implicit + // special-method lookup skips the hook entirely — and one rule over the + // whole family costs nothing while a per-form rule would have to + // enumerate them (see {@link RESERVED}). The stub lists it as a subscript comment + // (referencing the named TypedDicts too) so a reader sees what is + // accessible; runtime resolution goes through the proxy's __getitem__. + members.push(`${pad(1)}# tools[${JSON.stringify(schema.name)}](args: ${argType}) -> ${outputType}`); + const description = describe(schema); + if (description !== undefined) + members.push(`${pad(1)}# ${description}`); + } + } + // Subscript entries are COMMENTS, not statements: a class body of only + // comments fails to parse, so `pass` is required whenever no method was + // emitted — including the subscript-only tool set. + const bodyLines = statements > 0 ? members : [`${pad(1)}pass`, ...members]; + const body = bodyLines.join('\n'); + const imports = TYPING_ORDER.filter(symbol => state.typing.has(symbol)); + const classBlock = state.classes.length > 0 ? `${state.classes.join('\n\n')}\n\n` : ''; + const errorDeclaration = 'class ToolCallError(Exception):\n toolName: str'; + const declaration = `from typing import ${imports.join(', ')}\n\n${errorDeclaration}\n\n${classBlock}class Tools(Protocol):\n${body}\n\ntools: Tools`; + return `${SDK_INSTRUCTIONS}\n\n\`\`\`python\n${declaration}\n\`\`\``; +} +//# sourceMappingURL=py-types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.d.ts new file mode 100644 index 0000000..7c38bf1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.d.ts @@ -0,0 +1,241 @@ +/** Unified JSON-value schema DSL, inference, compilation, and typed tool helper. @module dsh-tools/schema */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { JsonValue } from '@deepseek-ai/dsh-session'; +import type { ToolDefinition, ToolExecution, ToolExecutionResult, ToolRunContext, ToolResult } from './index.ts'; +import type { JsonSchemaNode, ObjectJsonSchema } from './json-schema.ts'; +import type { ToolCallView, ToolResultView } from './presentation.ts'; +/** Annotation keywords shared by every author-facing schema node. */ +export interface ValueSchemaAnnotations { + /** Human-readable description projected into JSON Schema and generated types. */ + description?: string; + /** Human-readable title projected into JSON Schema. */ + title?: string; + /** Non-validating default annotation; it must be lossless JSON data. */ + default?: JsonValue; + /** Non-validating examples annotation; it must be lossless JSON data. */ + examples?: JsonValue; +} +/** String value schema with type-correct literal constraints. */ +export interface StringValueSchemaSpec extends ValueSchemaAnnotations { + type: 'string'; + enum?: readonly string[]; + const?: string; +} +/** Finite JSON-number schema with type-correct literal constraints. */ +export interface NumberValueSchemaSpec extends ValueSchemaAnnotations { + type: 'number'; + enum?: readonly number[]; + const?: number; +} +/** Integer schema with type-correct literal constraints. */ +export interface IntegerValueSchemaSpec extends ValueSchemaAnnotations { + type: 'integer'; + enum?: readonly number[]; + const?: number; +} +/** Boolean value schema with type-correct literal constraints. */ +export interface BooleanValueSchemaSpec extends ValueSchemaAnnotations { + type: 'boolean'; + enum?: readonly boolean[]; + const?: boolean; +} +/** Null value schema with type-correct literal constraints. */ +export interface NullValueSchemaSpec extends ValueSchemaAnnotations { + type: 'null'; + enum?: readonly null[]; + const?: null; +} +/** Array value schema; omitted `items` accepts any lossless JSON item. */ +export interface ArrayValueSchemaSpec extends ValueSchemaAnnotations { + type: 'array'; + items?: ValueSchemaSpec; +} +/** + * Explicit object value schema. Openness is mandatory so a nested or output + * object never acquires an accidental JSON Schema default. + */ +export interface ObjectValueSchemaSpec extends ValueSchemaAnnotations { + type: 'object'; + properties?: ParameterSchemaSpec; + additionalProperties: boolean; +} +/** Author-only unconstrained lossless JSON node. */ +export interface JsonValueSchemaSpec extends ValueSchemaAnnotations { + type: 'json'; +} +/** Exact-one union schema; at least two branches are required. */ +export interface OneOfValueSchemaSpec extends ValueSchemaAnnotations { + oneOf: readonly [ValueSchemaSpec, ValueSchemaSpec, ...ValueSchemaSpec[]]; +} +/** One author-facing schema for any lossless JSON value root. */ +export type ValueSchemaSpec = StringValueSchemaSpec | NumberValueSchemaSpec | IntegerValueSchemaSpec | BooleanValueSchemaSpec | NullValueSchemaSpec | ArrayValueSchemaSpec | ObjectValueSchemaSpec | JsonValueSchemaSpec | OneOfValueSchemaSpec; +/** One implicit parameter-root property, optionally required. */ +export type ParameterPropertySpec = ValueSchemaSpec & { + required?: true; +}; +/** + * Tool parameter schema. The map itself is an implicit open object root; + * requiredness remains a per-property `required: true` annotation. + */ +export type ParameterSchemaSpec = { + [key: string]: ParameterPropertySpec; + [key: symbol]: never; +}; +/** Raw JSON Schema projection of the implicit parameter object. */ +export interface ParameterJsonSchema extends ObjectJsonSchema { + properties: Record; +} +/** Flatten an intersection into one object type for readable hovers. */ +type Simplify = { + [K in keyof T]: T[K]; +} & {}; +/** String keys of one property map; runtime compilation rejects symbol keys. */ +type StringKeyOf = Extract; +/** Keys of a property map marked `required: true`. */ +type RequiredKeys = { + [K in StringKeyOf]: S[K] extends { + required: true; + } ? K : never; +}[StringKeyOf]; +/** Infer the declared value of one parameter property without key optionality. */ +type InferProperty = InferValueAt; +/** Infer an implicit property map into required and optional object keys. */ +type InferProperties = Simplify<{ + [K in RequiredKeys]: InferProperty; +} & { + [K in Exclude, RequiredKeys>]?: InferProperty; +}>; +/** Infer an explicit object node, including its declared openness. */ +type InferObject = S extends { + properties: infer P; +} ? S['additionalProperties'] extends true ? InferProperties & Record : InferProperties : S['additionalProperties'] extends true ? Record : Record; +/** Infer a scalar node's literal constraint before its broad primitive type. */ +type InferScalar = S extends { + const: infer C; +} ? C : S extends { + enum: readonly (infer E)[]; +} ? E : Fallback; +/** Add one schema-container level to bounded compile-time inference. */ +type NextInferenceDepth = [unknown, ...Depth]; +/** Infer one node without recursively checking it against the full author union. */ +type InferValueAt = Depth['length'] extends 16 ? JsonValue : S extends { + type: 'string'; +} ? InferScalar : S extends { + type: 'number' | 'integer'; +} ? InferScalar : S extends { + type: 'boolean'; +} ? InferScalar : S extends { + type: 'null'; +} ? null : S extends { + type: 'array'; +} ? S extends { + items: infer I; +} ? InferValueAt>[] : JsonValue[] : S extends { + type: 'object'; + additionalProperties: boolean; +} ? InferObject> : S extends { + type: 'json'; +} ? JsonValue : S extends { + oneOf: readonly unknown[]; +} ? InferValueAt> : never; +/** + * Infer the TypeScript value accepted by an author-facing value schema. Exact + * inference is bounded to 16 container levels, then falls back to `JsonValue`. + */ +export type InferValue = InferValueAt; +/** Infer the TypeScript argument object for an implicit parameter schema. */ +export type InferArgs = InferProperties; +/** + * Compile one author-facing value schema to the enforced raw JSON Schema + * subset. The author-only `json` node becomes an annotation-only schema. + * @param spec - schema for any JSON-value root. + * @returns The asserted raw schema projection. + */ +export declare function valueSchemaSpecToJsonSchema(spec: ValueSchemaSpec): JsonSchemaNode; +/** + * Compile the implicit open parameter object into raw JSON Schema. + * @param spec - per-property parameter definitions. + * @returns An object-rooted raw schema with no implicit-root openness override. + */ +export declare function parameterSchemaSpecToJsonSchema(spec: ParameterSchemaSpec): ParameterJsonSchema; +/** Invalid model-generated arguments for a typed tool. */ +export declare class ToolArgsError extends HarnessError { + /** Individual violations in schema-walk order. */ + readonly violations: string[]; + constructor(violations: string[]); +} +/** + * Validate model-generated arguments against an implicit parameter schema. + * @param spec - declared parameter schema. + * @param args - candidate arguments, however malformed. + * @returns Path-qualified violations; empty means valid. + */ +export declare function validateArgs(spec: ParameterSchemaSpec, args: unknown): string[]; +/** Options for {@link defineTool}. */ +export interface DefineToolOptions { + /** Tool name (must be unique). */ + readonly name: string; + /** Human-readable description sent to the model. */ + readonly description: string; + /** Per-property parameter schema compiled to an implicit open object root. */ + readonly parameters: S; + /** Canonical output schema plus pure Native and presentation projections. */ + readonly output: { + /** Schema enforced against every successful body or policy-replaced value. */ + readonly schema: O; + /** Pure Native/model rendering of one validated canonical value. */ + render(args: InferArgs, value: InferValue>): ContentBlock[]; + /** Pure replayable presentation metadata for direct top-level calls. */ + presentationMeta?(args: InferArgs, value: InferValue>): JsonValue; + }; + /** Optional positive cooperative timeout budget in milliseconds. */ + readonly timeoutMs?: number; + /** + * Pure classifier for sibling overlap. + * @param args - typed validated arguments. + * @returns Whether the call may join a parallel group. + */ + isConcurrencySafe?(args: InferArgs): boolean; + /** + * Execute the tool after argument validation. + * @param args - typed validated arguments. + * @param exec - execution identity, caller, cancellation, and nesting data. + * @returns The canonical value declared by `output.schema`. + */ + execute(args: InferArgs, exec: ToolRunContext): Promise>>; + /** + * Optional last-mile content transform for every normalized outcome. Unlike + * `execute`, arguments remain `unknown` because invalid-input failures also + * reach this callback. See {@link ToolDefinition.finalizeContent}. + * @param exec - immutable execution identity and arguments. + * @param result - complete normalized outcome before materialization. + * @returns replacement content, or `undefined` to preserve it. + */ + finalizeContent?(exec: Readonly, result: Readonly): ContentBlock[] | undefined; + /** + * Pure pending-state presenter. + * @param args - typed validated arguments. + * @returns Tool-owned render intent, or `undefined` for the generic card. + */ + presentCall?(args: InferArgs): ToolCallView | undefined; + /** + * Pure completed-state presenter. + * @param args - typed validated arguments. + * @param result - final model-facing tool result. + * @returns Tool-owned render intent, or `undefined` for the generic card. + */ + presentResult?(args: InferArgs, result: ToolResult): ToolResultView | undefined; +} +/** + * Define a first-party tool with inferred arguments and strict execution + * validation. Replay-only presenters validate softly and fall back to generic + * rendering for obsolete logged arguments. + * @param options - typed definition and optional finalizer and presenters. + * @returns A registry-ready definition. + */ +export declare function defineTool(options: DefineToolOptions): ToolDefinition; +export {}; +//# sourceMappingURL=schema.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.js new file mode 100644 index 0000000..cde42bc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/schema.js @@ -0,0 +1,349 @@ +/** Unified JSON-value schema DSL, inference, compilation, and typed tool helper. @module dsh-tools/schema */ +import { HarnessError } from '@deepseek-ai/dsh-llm'; +import { assertSupportedJsonSchema, isJsonSchemaRecord, isPlainJsonArray, JsonSchemaError, validateJsonSchemaValue } from "./json-schema.js"; +const ANNOTATION_KEYS = ['description', 'title', 'default', 'examples']; +/** Throw one author-schema violation through the shared schema error type. */ +function authorError(message) { + throw new JsonSchemaError([message]); +} +/** Copy own annotation fields for validation by the raw-schema boundary. */ +function copyAnnotations(source, target) { + if (Object.hasOwn(source, 'description')) + target.description = source.description; + if (Object.hasOwn(source, 'title')) + target.title = source.title; + if (Object.hasOwn(source, 'default')) + target.default = source.default; + if (Object.hasOwn(source, 'examples')) + target.examples = source.examples; +} +/** Reject author-only keys outside one node's declared vocabulary. */ +function assertAuthorKeys(source, path, allowed) { + for (const key of Object.keys(source)) { + if (!allowed.includes(key)) + authorError(`${path}.${key} is not supported by the value schema DSL`); + } +} +/** Install a compiled node without giving `__proto__` assignment semantics. */ +function assignCompiledNode(destination, node) { + switch (destination.kind) { + case 'root': + destination.holder.value = node; + break; + case 'property': + Object.defineProperty(destination.target, destination.key, { + value: node, + enumerable: true, + configurable: true, + writable: true, + }); + break; + case 'item': + destination.target.items = node; + break; + case 'one-of': + destination.target[destination.index] = node; + break; + } +} +/** Install a compiled property map at its root or containing object node. */ +function assignCompiledPropertyMap(destination, compiled) { + if (destination.kind === 'root') { + destination.holder.value = compiled; + } + else { + destination.target.properties = compiled.properties; + } +} +/** Execute an author-schema compilation task graph without recursive descent. */ +function runSchemaCompiler(initial) { + const seen = new Set(); + const tasks = [initial]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + seen.delete(task.input); + continue; + } + if (task.kind === 'property-map-tail') { + if (task.required.length > 0) { + task.compiled.required = task.required; + if (task.destination.kind === 'object') + task.destination.target.required = task.required; + } + continue; + } + if (task.kind === 'property') { + if (!isJsonSchemaRecord(task.property)) + authorError(`${task.path} must be a value schema object`); + if (Object.hasOwn(task.property, 'required') && task.property.required !== true) { + authorError(`${task.path}.required must be true when present`); + } + if (Object.hasOwn(task.property, 'required') && task.property.required === true) + task.required.push(task.key); + tasks.push({ + kind: 'value', + input: task.property, + path: task.path, + allowRequired: true, + destination: { kind: 'property', target: task.properties, key: task.key }, + }); + continue; + } + if (task.kind === 'property-map') { + if (!isJsonSchemaRecord(task.input)) + authorError(`${task.path} must be an object of value schemas`); + if (seen.has(task.input)) + authorError(`${task.path} is circular`); + seen.add(task.input); + const compiled = { properties: {} }; + const required = []; + assignCompiledPropertyMap(task.destination, compiled); + tasks.push({ kind: 'leave', input: task.input }); + tasks.push({ kind: 'property-map-tail', compiled, required, destination: task.destination }); + const entries = Object.entries(task.input); + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index]; + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) + continue; + tasks.push({ + kind: 'property', + property: entry[1], + path: `${task.path}.${entry[0]}`, + key: entry[0], + properties: compiled.properties, + required, + }); + } + continue; + } + const { input, path } = task; + if (!isJsonSchemaRecord(input)) + authorError(`${path} must be a value schema object`); + if (seen.has(input)) + authorError(`${path} is circular`); + seen.add(input); + const authorKeys = [...ANNOTATION_KEYS, ...(task.allowRequired ? ['required'] : [])]; + const node = {}; + assignCompiledNode(task.destination, node); + tasks.push({ kind: 'leave', input }); + if (Object.hasOwn(input, 'oneOf')) { + assertAuthorKeys(input, path, [...authorKeys, 'oneOf', 'type']); + if (Object.hasOwn(input, 'type')) + authorError(`${path} cannot declare both type and oneOf`); + if (!isPlainJsonArray(input.oneOf)) + authorError(`${path}.oneOf must be an array of at least two value schemas`); + const branches = []; + node.oneOf = branches; + copyAnnotations(input, node); + for (let index = input.oneOf.length - 1; index >= 0; index--) { + tasks.push({ + kind: 'value', + input: input.oneOf[index], + path: `${path}.oneOf[${index}]`, + allowRequired: false, + destination: { kind: 'one-of', target: branches, index }, + }); + } + continue; + } + const inputType = Object.hasOwn(input, 'type') ? input.type : undefined; + switch (inputType) { + case 'json': + assertAuthorKeys(input, path, [...authorKeys, 'type']); + copyAnnotations(input, node); + break; + case 'object': + assertAuthorKeys(input, path, [...authorKeys, 'type', 'properties', 'additionalProperties']); + if (!Object.hasOwn(input, 'additionalProperties') || typeof input.additionalProperties !== 'boolean') { + authorError(`${path}.additionalProperties must be explicitly true or false`); + } + node.type = 'object'; + copyAnnotations(input, node); + node.additionalProperties = input.additionalProperties; + if (Object.hasOwn(input, 'properties')) { + tasks.push({ + kind: 'property-map', + input: input.properties, + path: `${path}.properties`, + destination: { kind: 'object', target: node }, + }); + } + break; + case 'array': + assertAuthorKeys(input, path, [...authorKeys, 'type', 'items']); + node.type = 'array'; + copyAnnotations(input, node); + if (Object.hasOwn(input, 'items')) { + tasks.push({ + kind: 'value', + input: input.items, + path: `${path}.items`, + allowRequired: false, + destination: { kind: 'item', target: node }, + }); + } + break; + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': + assertAuthorKeys(input, path, [...authorKeys, 'type', 'enum', 'const']); + node.type = inputType; + copyAnnotations(input, node); + if (Object.hasOwn(input, 'enum')) { + if (!isPlainJsonArray(input.enum)) + authorError(`${path}.enum must be a non-empty array of scalar values`); + node.enum = Array.from(input.enum, entry => entry); + } + if (Object.hasOwn(input, 'const')) + node.const = input.const; + break; + default: + authorError(`${path}.type must be string/number/integer/boolean/null/array/object/json, or use oneOf`); + } + } +} +/** Compile one implicit property map, collecting per-property requiredness. */ +function compilePropertyMap(input, path) { + const holder = {}; + runSchemaCompiler({ kind: 'property-map', input, path, destination: { kind: 'root', holder } }); + /* v8 ignore next -- the root task assigns before scheduling any descendants. */ + return holder.value ?? authorError(`${path} did not compile`); +} +/** Compile one author node without applying any consumer root restriction. */ +function compileValueSchema(input, path) { + const holder = {}; + runSchemaCompiler({ kind: 'value', input, path, allowRequired: false, destination: { kind: 'root', holder } }); + /* v8 ignore next -- the root task assigns before scheduling any descendants. */ + return holder.value ?? authorError(`${path} did not compile`); +} +/** + * Compile one author-facing value schema to the enforced raw JSON Schema + * subset. The author-only `json` node becomes an annotation-only schema. + * @param spec - schema for any JSON-value root. + * @returns The asserted raw schema projection. + */ +export function valueSchemaSpecToJsonSchema(spec) { + const schema = compileValueSchema(spec, 'schema'); + assertSupportedJsonSchema(schema); + return schema; +} +/** + * Compile the implicit open parameter object into raw JSON Schema. + * @param spec - per-property parameter definitions. + * @returns An object-rooted raw schema with no implicit-root openness override. + */ +export function parameterSchemaSpecToJsonSchema(spec) { + const compiled = compilePropertyMap(spec, 'parameters'); + const schema = { + type: 'object', + properties: compiled.properties, + ...(compiled.required === undefined ? {} : { required: compiled.required }), + }; + assertSupportedJsonSchema(schema); + return schema; +} +/** Invalid model-generated arguments for a typed tool. */ +export class ToolArgsError extends HarnessError { + /** Individual violations in schema-walk order. */ + violations; + constructor(violations) { + super(`invalid arguments: ${violations.join('; ')}`, 'INVALID_ARGS'); + this.name = 'ToolArgsError'; + this.violations = violations; + } +} +/** + * Validate model-generated arguments against an implicit parameter schema. + * @param spec - declared parameter schema. + * @param args - candidate arguments, however malformed. + * @returns Path-qualified violations; empty means valid. + */ +export function validateArgs(spec, args) { + return validateJsonSchemaValue(parameterSchemaSpecToJsonSchema(spec), args, ''); +} +/** + * Define a first-party tool with inferred arguments and strict execution + * validation. Replay-only presenters validate softly and fall back to generic + * rendering for obsolete logged arguments. + * @param options - typed definition and optional finalizer and presenters. + * @returns A registry-ready definition. + */ +export function defineTool(options) { + // Object-literal methods do not use `this`; retaining references is safe. + // oxlint-disable-next-line typescript/unbound-method + const userExecute = options.execute; + // oxlint-disable-next-line typescript/unbound-method + const userFinalizeContent = options.finalizeContent; + // oxlint-disable-next-line typescript/unbound-method + const userRender = options.output.render; + // oxlint-disable-next-line typescript/unbound-method + const userPresentationMeta = options.output.presentationMeta; + // oxlint-disable-next-line typescript/unbound-method + const userPresentCall = options.presentCall; + // oxlint-disable-next-line typescript/unbound-method + const userPresentResult = options.presentResult; + // oxlint-disable-next-line typescript/unbound-method + const userIsConcurrencySafe = options.isConcurrencySafe; + if (options.timeoutMs !== undefined && (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) { + throw new Error(`defineTool(${options.name}): timeoutMs must be a positive finite number`); + } + const parameters = parameterSchemaSpecToJsonSchema(options.parameters); + const outputSchema = valueSchemaSpecToJsonSchema(options.output.schema); + const validate = (args) => validateJsonSchemaValue(parameters, args, ''); + const tool = { + name: options.name, + description: options.description, + parameters: parameters, + output: { + schema: outputSchema, + render(args, value) { + return userRender(args, value); + }, + ...userPresentationMeta !== undefined ? { + presentationMeta(args, value) { + return userPresentationMeta(args, value); + }, + } : {}, + }, + ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}), + async execute(args, exec) { + const violations = validate(args); + if (violations.length > 0) + throw new ToolArgsError(violations); + return userExecute(args, exec); + }, + }; + if (userFinalizeContent) { + tool.finalizeContent = (exec, result) => userFinalizeContent(exec, result); + } + // Presentation is display-only and may run on REPLAY of arbitrary logged args + // (possibly from an older schema), so it must never throw: validate softly and + // fall back to `undefined` (a generic UI presentation) on any mismatch, rather + // than the hard `ToolArgsError` the execute path raises. + if (userPresentCall) { + tool.presentCall = (args) => { + if (validate(args).length > 0) + return undefined; + return userPresentCall(args); + }; + } + if (userPresentResult) { + tool.presentResult = (args, result) => { + if (validate(args).length > 0) + return undefined; + return userPresentResult(args, result); + }; + } + if (userIsConcurrencySafe) { + tool.isConcurrencySafe = (args) => { + if (validate(args).length > 0) + return false; + return userIsConcurrencySafe(args); + }; + } + return tool; +} +//# sourceMappingURL=schema.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.d.ts new file mode 100644 index 0000000..40d83ac --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.d.ts @@ -0,0 +1,25 @@ +/** Canonical tool-definition fixtures for repository tests. @module dsh-tools/testing */ +import type { ContentBlock } from '@deepseek-ai/dsh-llm'; +import type { DefineToolOptions, ParameterSchemaSpec } from './schema.ts'; +import type { ToolDefinition, ToolRunContext } from './index.ts'; +declare const CONTENT_VALUE_SCHEMA: { + readonly type: "array"; + readonly items: { + readonly type: "json"; + }; +}; +/** Options for a fixture whose canonical value is its rendered content array. */ +export type ContentToolFixtureOptions = Omit, 'output' | 'execute'> & { + /** Produce the fixture's content blocks as its canonical test value. */ + execute(args: import('./schema.ts').InferArgs, exec: ToolRunContext): Promise; +}; +/** + * Define a test fixture that deliberately uses its content blocks as the + * canonical JSON value. Product tools must declare domain-owned DTOs instead. + * @param options - ordinary fixture fields plus a content-producing body. + * @returns a registry-ready tool with an explicit JSON-array output contract. + * @internal + */ +export declare function defineContentToolFixture(options: ContentToolFixtureOptions): ToolDefinition; +export {}; +//# sourceMappingURL=testing.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.js new file mode 100644 index 0000000..fe03f8e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/testing.js @@ -0,0 +1,25 @@ +/** Canonical tool-definition fixtures for repository tests. @module dsh-tools/testing */ +import { defineTool } from "./schema.js"; +const CONTENT_VALUE_SCHEMA = { type: 'array', items: { type: 'json' } }; +/** + * Define a test fixture that deliberately uses its content blocks as the + * canonical JSON value. Product tools must declare domain-owned DTOs instead. + * @param options - ordinary fixture fields plus a content-producing body. + * @returns a registry-ready tool with an explicit JSON-array output contract. + * @internal + */ +export function defineContentToolFixture(options) { + // oxlint-disable-next-line typescript/unbound-method + const execute = options.execute; + return defineTool({ + ...options, + output: { + schema: CONTENT_VALUE_SCHEMA, + render: (_args, value) => value, + }, + async execute(args, exec) { + return await execute(args, exec); + }, + }); +} +//# sourceMappingURL=testing.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.d.ts new file mode 100644 index 0000000..1d504e9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.d.ts @@ -0,0 +1,37 @@ +/** + * Code Mode codegen: the pure projection from registered tool schemas to the TypeScript SDK + * text the model programs against (the `tools:sdk` prompt section). Sibling of + * `json-schema.ts` — `schemas()` (native function calling) and this module (the generated + * `declare const tools` API) are two projections of the same store. + * @module @deepseek-ai/dsh-tools/src/ts-types + */ +import type { ToolSchema } from '@deepseek-ai/dsh-llm'; +import type { JsonSchemaNode } from './json-schema.ts'; +/** Internal Code Mode projection: the model-facing schema plus the canonical output schema. */ +export interface ToolSdkSchema extends ToolSchema { + /** Validated canonical value returned by the tool binding. */ + output: JsonSchemaNode; +} +/** + * Map one enforced JSON-Schema node to a TypeScript type literal. Supports + * every unified schema construct and returns `unknown` for malformed or + * unsupported inputs without throwing. + * @param schema - the JSON-Schema node (any shape; hostile inputs degrade). + * @param indent - the indentation level for nested object members. + * @returns the TS type text (multi-line for objects with properties). + */ +export declare function jsonSchemaToTs(schema: unknown, indent?: number): string; +/** + * Render the full `tools:sdk` prompt section: the fixed usage instructions + * plus one `declare const tools` interface covering every given tool. + * Deterministic — tools are emitted in lexicographic name order, so an + * unchanged tool set produces byte-identical text across assemblies. The sort + * is not a total order on byte-equal names, so two schemas sharing a name + * would render in argument order; the caller's visible-capability map is keyed + * by name, so the input never carries a duplicate. + * @param schemas - the tool schemas to declare (the caller excludes + * `run_code` itself). + * @returns the complete section text. + */ +export declare function renderToolsSdk(schemas: ToolSdkSchema[]): string; +//# sourceMappingURL=ts-types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.js new file mode 100644 index 0000000..68c4f5a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/ts-types.js @@ -0,0 +1,265 @@ +/** + * Code Mode codegen: the pure projection from registered tool schemas to the TypeScript SDK + * text the model programs against (the `tools:sdk` prompt section). Sibling of + * `json-schema.ts` — `schemas()` (native function calling) and this module (the generated + * `declare const tools` API) are two projections of the same store. + * @module @deepseek-ai/dsh-tools/src/ts-types + */ +import { assertSupportedJsonSchema } from "./json-schema.js"; +/** Property names that are valid bare TS identifiers; anything else is quoted. */ +const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/; +/** Render an object key: bare when it is a valid identifier, quoted otherwise (every name stays reachable, no aliasing). */ +function renderKey(name) { + return IDENTIFIER.test(name) ? name : JSON.stringify(name); +} +/** One `indent`-deep line prefix (two spaces per level). */ +function pad(indent) { + return ' '.repeat(indent); +} +/** A one-line JSDoc block for a schema `description`, or no lines when there is none. */ +function docLines(description, indent) { + if (typeof description !== 'string' || description.length === 0) + return []; + // Collapse prose to stable one-line docs and escape comment closers so a + // schema description cannot terminate generated JSDoc. + const collapsed = description.replace(/\s+/g, ' ').trim(); + return [`${pad(indent)}/** ${collapsed.replaceAll('*/', String.raw `*\/`)} */`]; +} +/** Render one scalar already validated by the unified schema boundary. */ +function renderScalar(value) { + return JSON.stringify(value); +} +/** Render a validated scalar `const`/`enum`, falling back to the broad type. */ +function renderConstrainedScalar(node, type) { + const broad = type === 'integer' ? 'number' : type; + if (Object.hasOwn(node, 'const')) + return renderScalar(node.const); + if (Object.hasOwn(node, 'enum')) { + return node.enum.map(renderScalar).join(' | '); + } + return broad; +} +/** Build one document from captured parts while retaining the legacy array-parenthesization test. */ +function typeDocumentFrom(parts) { + return { + parts, + containsUnionOrIntersection: parts.some(part => typeof part === 'string' + ? part.includes('|') || part.includes('&') + : part.containsUnionOrIntersection), + }; +} +/** Build a small document without an intermediate array at each call site. */ +function typeDocument(...parts) { + return typeDocumentFrom(parts); +} +/** Flatten a nested document with an explicit work stack. */ +function flattenTypeDocument(document) { + const chunks = []; + const tasks = [document]; + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (typeof task === 'string') { + chunks.push(task); + continue; + } + for (let index = task.parts.length - 1; index >= 0; index--) { + const part = task.parts[index]; + /* v8 ignore next -- the loop is bounded by the captured part count. */ + if (part !== undefined) + tasks.push(part); + } + } + return chunks.join(''); +} +/** Initialize one schema-render frame with empty aggregation state. */ +function schemaRenderFrame(node, indent) { + return { node, indent, phase: 'start', children: [], childIndex: 0, childDocuments: [], entries: [] }; +} +/** Render an already asserted schema to a composable document. */ +function renderSupportedSchema(schema, indent) { + const frames = [schemaRenderFrame(schema, indent)]; + let rootDocument; + const finish = (document) => { + frames.pop(); + const parent = frames.at(-1); + if (parent === undefined) + rootDocument = document; + else + parent.childDocuments.push(document); + }; + while (frames.length > 0) { + const frame = frames.at(-1); + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === undefined) + break; + if (frame.phase === 'children') { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex]; + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === undefined) + throw new Error('missing schema render child'); + frame.childIndex++; + frames.push(schemaRenderFrame(child.node, child.indent)); + continue; + } + if (frame.kind === 'oneOf') { + const parts = []; + for (let index = 0; index < frame.childDocuments.length; index++) { + if (index > 0) + parts.push(' | '); + const child = frame.childDocuments[index]; + /* v8 ignore next -- child documents correspond one-to-one with children. */ + if (child !== undefined) + parts.push(child); + } + finish(typeDocumentFrom(parts)); + continue; + } + if (frame.kind === 'array') { + const child = frame.childDocuments[0]; + /* v8 ignore next -- array frames always schedule exactly one child. */ + if (child === undefined) + throw new Error('missing array item type'); + finish(child.containsUnionOrIntersection + ? typeDocument('(', child, ')[]') + : typeDocument(child, '[]')); + continue; + } + const required = new Set(frame.node.required); + const parts = ['{']; + for (let index = 0; index < frame.entries.length; index++) { + const entry = frame.entries[index]; + const child = frame.childDocuments[index]; + /* v8 ignore next -- object entries and child documents have the same length. */ + if (entry === undefined || child === undefined) + throw new Error('missing object property type'); + const [name, prop] = entry; + for (const line of docLines(prop.description, frame.indent + 1)) + parts.push('\n', line); + parts.push('\n', `${pad(frame.indent + 1)}${renderKey(name)}${required.has(name) ? '' : '?'}: `, child, ';'); + } + parts.push('\n', `${pad(frame.indent)}}`); + const declared = typeDocumentFrom(parts); + finish(frame.node.additionalProperties === false + ? declared + : typeDocument(declared, ' & Record')); + continue; + } + const node = frame.node; + if (node.oneOf !== undefined) { + frame.kind = 'oneOf'; + frame.children = Array.from(node.oneOf, child => ({ node: child, indent: frame.indent })); + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = 'children'; + continue; + } + if (node.type === undefined) { + finish(typeDocument('JsonValue')); + continue; + } + switch (node.type) { + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': + finish(typeDocument(renderConstrainedScalar(node, node.type))); + break; + case 'array': + if (node.items === undefined) { + finish(typeDocument('JsonValue[]')); + } + else { + frame.kind = 'array'; + frame.children = [{ node: node.items, indent: frame.indent }]; + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = 'children'; + } + break; + case 'object': { + const open = node.additionalProperties !== false; + const entries = Object.entries(node.properties ?? {}); + if (entries.length === 0) { + finish(typeDocument(open ? 'Record' : 'Record')); + } + else { + frame.kind = 'object'; + frame.entries = entries; + frame.children = entries.map(([, child]) => ({ node: child, indent: frame.indent + 1 })); + frame.childIndex = 0; + frame.childDocuments = []; + frame.phase = 'children'; + } + break; + } + /* v8 ignore next -- assertSupportedJsonSchema narrowed this closed type union. */ + default: + finish(typeDocument('unknown')); + } + } + /* v8 ignore next -- every root frame produces one document. */ + return rootDocument ?? typeDocument('unknown'); +} +/** + * Map one enforced JSON-Schema node to a TypeScript type literal. Supports + * every unified schema construct and returns `unknown` for malformed or + * unsupported inputs without throwing. + * @param schema - the JSON-Schema node (any shape; hostile inputs degrade). + * @param indent - the indentation level for nested object members. + * @returns the TS type text (multi-line for objects with properties). + */ +export function jsonSchemaToTs(schema, indent = 0) { + try { + assertSupportedJsonSchema(schema); + return flattenTypeDocument(renderSupportedSchema(schema, indent)); + } + catch { + return 'unknown'; + } +} +/** The fixed model-facing usage contract rendered above the declarations (see the Code Mode Agent Note's "What the model sees"). */ +const SDK_INSTRUCTIONS = `## Writing code for run_code + +\`run_code\` takes two required arguments: \`code\` — the body of an async TypeScript function (erasable syntax only — no \`enum\` or namespaces; type annotations are advisory, the code runs type-stripped) — and \`description\`, a short summary of what the program does. Inside the program: + +- Call tools as \`await tools.name(args)\` — quoted access for exotic names: \`tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose \`message\` is human-readable — \`try/catch\` it to handle and continue. +- Independent read-only calls MAY overlap under \`Promise.all\` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with \`await\`. +- Emit results with \`return\` and/or \`console.log(...)\`. Only what you print or return is program output. A successful tool result containing an image is attached after the run so you can inspect it on the next step; every other intermediate result stays out of the conversation, so extract just what you need. + +The available tools:`; +/** + * Render the full `tools:sdk` prompt section: the fixed usage instructions + * plus one `declare const tools` interface covering every given tool. + * Deterministic — tools are emitted in lexicographic name order, so an + * unchanged tool set produces byte-identical text across assemblies. The sort + * is not a total order on byte-equal names, so two schemas sharing a name + * would render in argument order; the caller's visible-capability map is keyed + * by name, so the input never carries a duplicate. + * @param schemas - the tool schemas to declare (the caller excludes + * `run_code` itself). + * @returns the complete section text. + */ +export function renderToolsSdk(schemas) { + const sorted = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0); + const argsMembers = []; + const outputMembers = []; + for (const schema of sorted) { + argsMembers.push(...docLines(schema.description, 1)); + argsMembers.push(`${pad(1)}${renderKey(schema.name)}: ${jsonSchemaToTs(schema.parameters, 1)};`); + outputMembers.push(`${pad(1)}${renderKey(schema.name)}: ${jsonSchemaToTs(schema.output, 1)};`); + } + const argsMap = `interface ToolArgsMap {${argsMembers.length > 0 ? `\n${argsMembers.join('\n')}\n` : ''}}`; + const outputMap = `interface ToolOutputMap {${outputMembers.length > 0 ? `\n${outputMembers.join('\n')}\n` : ''}}`; + const declaration = [ + argsMap, + outputMap, + 'type ToolName = keyof ToolOutputMap', + ['declare class ToolCallError extends Error {', ' readonly name: "ToolCallError";', ' readonly toolName: ToolName;', '}'].join('\n'), + ['declare const tools: {', ' [K in ToolName]: (args: ToolArgsMap[K]) => Promise;', '}'].join('\n'), + ].join('\n\n'); + const jsonValue = 'type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue }'; + return `${SDK_INSTRUCTIONS}\n\n\`\`\`ts\n${jsonValue}\n\n${declaration}\n\`\`\``; +} +//# sourceMappingURL=ts-types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/types.d.ts new file mode 100644 index 0000000..301bc9f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/types.d.ts @@ -0,0 +1,55 @@ +/** + * Durable Tool event vocabulary shared with type-only consumers. + * + * @module @deepseek-ai/dsh-tools/types + */ +import type { CallId } from '@deepseek-ai/dsh-llm/brand'; +import type { ContentBlock } from '@deepseek-ai/dsh-llm/types'; +/** Payload recorded when one nested Code Mode Tool dispatch starts. */ +export interface CodeDispatchStartEventData { + rootCallId: CallId; + parentCallId: CallId; + subCallId: CallId; + name: string; + arguments: unknown; +} +/** Payload recorded when one nested Code Mode Tool dispatch settles. */ +export interface CodeDispatchEventData extends CodeDispatchStartEventData { + isError: boolean; + content: ContentBlock[]; +} +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * One sub-dispatch STARTING inside a `run_code` program: the parent + * `run_code` call id, the deterministic sub-call id (`:code:`, + * numbered in submission order), and the tool `name` with its + * JSON-normalized `arguments` — the exact value dispatched, normalized + * BEFORE dispatch, so this append can never fail on payload shape. + * Appended when the scheduler actually starts the call (not at + * submission), so a start means the tool body pipeline was entered; a + * call abandoned in the queue logs nothing. Log-only: `deriveMessages()` + * ignores it; UIs use it for live per-sub-call running state and pair it + * with `tool/code-dispatch` by `subCallId` (timing = the two events' + * `time` fields). + */ + 'tool/code-dispatch-start': CodeDispatchStartEventData; + /** + * One bridged sub-dispatch SETTLING: the pairing ids (matching the + * `tool/code-dispatch-start` with the same `subCallId`), the tool `name` + * with the same JSON-normalized `arguments`, and the sub-call's complete + * model-facing outcome in `tool/result`'s own vocabulary + * (`content` + `isError`), so UIs render a sub-call through the exact + * code path that renders a native call. Every started sub-call settles + * with exactly one of these (abort included: the aborted pipeline result + * is an `isError` outcome). + * Log-only: `deriveMessages()` ignores it, so sub-calls never re-enter + * model context; persistence and UIs get every call. Appended inside the + * parent `run_code`'s execution (the bridge drains in-flight dispatches + * before returning), so its execution-enclosure relation holds by + * construction. + */ + 'tool/code-dispatch': CodeDispatchEventData; + } +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/types.js new file mode 100644 index 0000000..1cce147 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Durable Tool event vocabulary shared with type-only consumers. + * + * @module @deepseek-ai/dsh-tools/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/package.json new file mode 100644 index 0000000..b15a2b5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools/package.json @@ -0,0 +1,68 @@ +{ + "name": "@deepseek-ai/dsh-tools", + "description": "Tool registry and execution pipeline for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/core/tools" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./presentation": { + "types": "./lib/types/presentation.d.ts", + "default": "./lib/types/presentation.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.7", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.7" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-user-approval b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-user-approval new file mode 120000 index 0000000..7a0ea6d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-user-approval @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.i18n.yaml new file mode 100644 index 0000000..af84089 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/typert/protocol/README.md +README.md: 84f9f1b31cca35cffce5dc5fc84db1017adaad08 +README.zh.md: 97e4734a7292f0a305ff8ed00ff1d72d1a53b5e9 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.md new file mode 100644 index 0000000..84f9f1b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.md @@ -0,0 +1,38 @@ +# @deepseek-ai/dsh-typert-protocol + +English | [中文](README.zh.md) + +Compiler-independent declarations shared by business packages, generated Typert artifacts, the Host Gateway, and Client API. This package owns the Remote Service base, decorators, explicit binding fallback, merge-extensible protocol maps, invocation descriptors, codecs, and provider contracts; it does not run TypeScript analysis or register a concrete Cordis service. + +## Remote declarations + +- `@Remote` marks a public instance method for direct invocation on its registered Cordis Service. +- `@RemoteScope(key)` marks a method whose receiver is selected from a merge-declared scoped Context kind. +- `TypertRemoteService` binds the Cordis key passed to `super(ctx, serviceKey, options?)` to the same default wire namespace. +- `bindTypertRemote(this, serviceKey, options?)` provides the same visible, frozen binding for a Service that cannot inherit from `TypertRemoteService`. +- `remoteMethods(service)` returns a detached declaration-order snapshot used by the Gateway's SRC fallback. + +A Host method opts into cooperative cancellation by declaring `signal: AbortSignal` as its final parameter. `InvocationDescriptor.cancellation` records that reserved injection point; the signal never becomes a JSON parameter or lookup field. SRC recognizes the final parameter name, while strict generation also verifies the global `AbortSignal` type. + +Decorator initializers retain markers in a module-private `WeakMap` keyed by the Service prototype. They do not add constructor symbols, prototype properties, parameter metadata, or runtime reflection fields. A `TypertRemoteService` exposes the same public readonly `typertRemote` binding that the explicit helper returns. + +## Typert protocol + +Business packages extend `TypertLookupMap` and `TypertContextMap` to associate Host objects or scoped Contexts with their wire identities. Generated artifacts extend `TypertRemoteMap`, `TypertRemoteScopeMap`, and `TypertRemoteNamespaceMap` so Client imports expose only selected Remote methods. `InvocationDescriptor` is the shared runtime form consumed by the registry, Gateway, and Client Remote. + +The Host assembly extends `TypertRemoteEventSelection` with the Host events it forwards to consumers, which narrows the `ctx.remote.$on` key face; `TypertForwardableEvent` states the shapes a one-way delivery can carry at all, excluding Scope-bound and answered events. `TypertClientRemote` carries both roles of that surface: consumers subscribe through `$on`, and the Client half owning the host frame sink hands frames over through `$dispatch`. + +Lookup and Context packages own both sides of their contract: declaration merging supplies the static association, while runtime providers register identity resolution with `ctx.typert`. A lookup or Host Context provider supplies the stable declaration and default resolver, while Host composition may separately configure a synchronous or asynchronous resolver; policy rejections may use `TypertLookupFailure` to carry a failure value owned by the boundary adapter. Strict codecs carry generated schemas; `src-json` codecs identify the weaker source-launch path. + +## Model Experience + +None, as this protocol package declares application reflection and registers nothing model-facing. + +#### KV Cache effect + +No direct effect. + +## Known Limitations and Deferred Work + +- Decorator markers contain only the method name and direct or Context invocation mode. Parameter, result, lookup, and schema reflection require the Typert build pipeline. +- Remote decorators accept only public, non-static instance methods with string names. SRC execution cannot represent overloaded, destructured, defaulted, or rest-parameter signatures. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.zh.md new file mode 100644 index 0000000..97e4734 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/README.zh.md @@ -0,0 +1,38 @@ +# @deepseek-ai/dsh-typert-protocol + +[English](README.md) | 中文 + +该包提供不依赖编译器的声明,由业务包、生成的 Typert 产物、宿主网关和客户端 API 共享。它负责 Remote 服务基类、装饰器、显式绑定回退、可通过声明合并扩展的协议映射、调用描述符、编解码器和提供方约定;它不执行 TypeScript 分析,也不注册具体 Cordis 服务。 + +## Remote 声明 + +- `@Remote` 将公开实例方法标记为可在其注册的 Cordis 服务上直接调用。 +- `@RemoteScope(key)` 标记接收者选自合并声明的作用域 Context 类型的方法。 +- `TypertRemoteService` 将传给 `super(ctx, serviceKey, options?)` 的 Cordis 键绑定到同一默认协议命名空间。 +- `bindTypertRemote(this, serviceKey, options?)` 为无法继承 `TypertRemoteService` 的服务提供同样可见且冻结的绑定。 +- `remoteMethods(service)` 返回按声明顺序排列、与内部状态分离的快照,供 Gateway 的 SRC 回退路径使用。 + +宿主方法通过将 `signal: AbortSignal` 声明为最后一个参数来启用协作式取消。`InvocationDescriptor.cancellation` 记录这个保留的注入点;该信号绝不会成为 JSON 参数或查找字段。SRC 识别末位参数名,严格生成还会校验它是否具有全局 `AbortSignal` 类型。 + +装饰器初始化器将标记保存在以服务原型为键的模块私有 `WeakMap` 中。它们不会在构造函数上添加符号,也不会添加原型属性、参数元数据或运行时反射字段。`TypertRemoteService` 会暴露与显式辅助函数相同的公开只读 `typertRemote` 绑定。 + +## Typert 协议 + +业务包扩展 `TypertLookupMap` 和 `TypertContextMap`,以关联宿主对象或作用域 Context 与其协议身份。生成的产物扩展 `TypertRemoteMap`、`TypertRemoteScopeMap` 和 `TypertRemoteNamespaceMap`,使客户端导入后仅暴露选定的 Remote 方法。`InvocationDescriptor` 是供注册表、网关和客户端 Remote 使用的共享运行时形式。 + +Host 装配以转发给消费端的 Host 事件扩展 `TypertRemoteEventSelection`,从而收窄 `ctx.remote.$on` 的键面;`TypertForwardableEvent` 陈述单向投递根本能承载哪些形状,把 Scope 化事件与有返回值的事件排除在外。`TypertClientRemote` 承载该面的两种角色:消费方经 `$on` 订阅,持有 Host 帧 sink 的 Client 半经 `$dispatch` 交出帧。 + +查找包与 Context 包同时负责该约定的两侧:声明合并提供静态关联,运行时提供方则向 `ctx.typert` 注册身份解析。查找提供方或宿主 Context 提供方提供稳定声明与默认解析器,宿主组合可以另行配置同步或异步解析器;策略拒绝可用 `TypertLookupFailure` 携带由边界适配器拥有的失败值。严格编解码器携带生成的 schema;`src-json` 编解码器标识约束更弱的源码启动路径。 + +## 模型体验 + +无,因为该协议包声明应用反射,不注册任何面向模型的内容。 + +#### KV Cache 影响 + +无直接影响。 + +## 已知限制与暂缓事项 + +- 装饰器标记仅包含方法名,以及直接调用或 Context 调用模式。参数、结果、查找和 schema 反射需要 Typert 构建流水线。 +- Remote 装饰器只接受具有字符串名称的公开、非静态实例方法。SRC 执行无法表示重载签名,以及包含解构参数、默认参数或剩余参数的方法签名。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js new file mode 100644 index 0000000..15ad367 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js @@ -0,0 +1,140 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/index.js +/** +* Remote decorators and explicit Gateway bindings backed only by private +* module state. Strict reflection remains a Typert compiler responsibility. +* @module @deepseek-ai/dsh-typert-protocol +*/ +const TYPERT_REMOTE_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/; +/** +* Test one generated Remote name against the Connection endpoint grammar. +* @param value - namespace, method, lookup, or Context segment. +* @returns whether the value can cross the shared RPC carrier unchanged. +*/ +function isTypertRemoteSegment(value) { + return value !== "." && value !== ".." && TYPERT_REMOTE_SEGMENT_PATTERN.test(value); +} +/** +* A lookup policy rejection whose typed payload belongs to the active boundary adapter. +* Gateway adapters preserve this payload instead of collapsing it into an infrastructure failure. +*/ +var TypertLookupFailure = class extends Error { + /** Adapter-owned failure returned to the caller. */ + failure; + /** + * Wrap one adapter failure without exposing the rejected identity. + * @param failure - typed failure owned by the active boundary adapter. + */ + constructor(failure) { + super("Typert lookup policy rejected the requested identity"); + this.name = "TypertLookupFailure"; + this.failure = failure; + } +}; +const markers = /* @__PURE__ */ new WeakMap(); +/** +* Bind one visible Service field to a Cordis key and Remote namespace. +* @param service - owning Service instance, normally `this`. +* @param serviceKey - exact Cordis service key. +* @param options - optional distinct wire namespace. +* @returns a frozen, inspectable binding with no compiler-injected metadata. +*/ +function bindTypertRemote(service, serviceKey, options = {}) { + validateName("service key", serviceKey); + const namespace = options.namespace ?? serviceKey; + validateName("namespace", namespace); + return Object.freeze({ + service, + serviceKey, + namespace + }); +} +/** Cordis Service base that exposes its registered name through Typert Gateway. */ +var TypertRemoteService = class extends Service { + /** Visible binding consumed by the Gateway's source-mode discovery. */ + typertRemote; + /** + * Register the Service and bind the same key to Typert Gateway. + * @param ctx - owning Cordis Context. + * @param serviceKey - exact Cordis service key and default wire namespace. + * @param options - optional distinct wire namespace. + */ + constructor(ctx, serviceKey, options = {}) { + super(ctx, serviceKey); + this.typertRemote = bindTypertRemote(this, this.name, options); + } +}; +function Remote(methodOrExportName, context) { + if (typeof methodOrExportName === "string") { + validateName("Remote export name", methodOrExportName); + return function(_method, decoratorContext) { + addMarkerInitializer(decoratorContext, { kind: "direct" }, methodOrExportName); + }; + } + if (context === void 0) throw new TypeError("typert-protocol: Remote decorator context is missing"); + addMarkerInitializer(context, { kind: "direct" }); +} +/** +* Create a decorator for a method resolved from one Remote Scope. +* @param key - scope key declared through the Context map. +* @param exportName - optional Remote export name; defaults to the method name. +* @returns a standard method decorator that records only private module state. +*/ +function RemoteScope(key, exportName) { + validateName("Scope key", key); + if (exportName !== void 0) validateName("Remote export name", exportName); + return function(_method, context) { + addMarkerInitializer(context, { + kind: "context", + context: key + }, exportName); + }; +} +/** +* Read Remote markers attached to a live Service by decorator initializers. +* The returned snapshot cannot mutate the private marker table. +* @param service - live Service instance. +* @returns markers in class declaration order. +*/ +function remoteMethods(service) { + const prototype = Object.getPrototypeOf(service); + if (prototype === null) return []; + return [...markers.get(prototype) ?? []].map(([method, marker]) => ({ + method, + ...marker + })); +} +function addMarkerInitializer(context, invocation, exportName) { + if (context.private || context.static || typeof context.name !== "string") throw new TypeError("typert-protocol: Remote decorators require a public instance method with a string name"); + const method = context.name; + context.addInitializer(function() { + const prototype = Object.getPrototypeOf(this); + if (prototype === null) throw new TypeError(`typert-protocol: cannot mark Remote method "${method}" on an object without a prototype`); + mark(prototype, method, invocation, exportName); + }); +} +function mark(prototype, method, invocation, exportName) { + let table = markers.get(prototype); + if (table === void 0) { + table = /* @__PURE__ */ new Map(); + markers.set(prototype, table); + } + const marker = { + ...exportName === void 0 || exportName === method ? {} : { exportName }, + invocation: Object.freeze(invocation) + }; + const current = table.get(method); + if (current !== void 0) { + if (current.exportName === marker.exportName && sameInvocation(current.invocation, invocation)) return; + throw new Error(`typert-protocol: Remote method "${method}" has conflicting invocation markers`); + } + table.set(method, Object.freeze(marker)); +} +function sameInvocation(left, right) { + return left.kind === right.kind && (left.kind === "direct" || right.kind === "context" && left.context === right.context); +} +function validateName(subject, value) { + if (!isTypertRemoteSegment(value)) throw new TypeError(`typert-protocol: ${subject} must contain only RPC endpoint segment characters`); +} +//#endregion +export { Remote, RemoteScope, TypertLookupFailure, TypertRemoteService, bindTypertRemote, isTypertRemoteSegment, remoteMethods }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/invariant.js new file mode 100644 index 0000000..8581038 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-typert-protocol`. +* @module @deepseek-ai/dsh-typert-protocol/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-typert-protocol"; +/** Cordis companion plugin name. */ +const name = "typert-protocol-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: decorators retain private immutable declarations and +* bindings are frozen values with no independent event stream to cross-check. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.d.ts new file mode 100644 index 0000000..f4c9be5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.d.ts @@ -0,0 +1,101 @@ +/** + * Remote decorators and explicit Gateway bindings backed only by private + * module state. Strict reflection remains a Typert compiler responsibility. + * @module @deepseek-ai/dsh-typert-protocol + */ +import { Service, type Context } from '@deepseek-ai/cordis'; +import type { TypertContextMap } from './types.ts'; +/** + * Test one generated Remote name against the Connection endpoint grammar. + * @param value - namespace, method, lookup, or Context segment. + * @returns whether the value can cross the shared RPC carrier unchanged. + */ +export declare function isTypertRemoteSegment(value: string): boolean; +/** + * A lookup policy rejection whose typed payload belongs to the active boundary adapter. + * Gateway adapters preserve this payload instead of collapsing it into an infrastructure failure. + */ +export declare class TypertLookupFailure extends Error { + /** Adapter-owned failure returned to the caller. */ + readonly failure: Failure; + /** + * Wrap one adapter failure without exposing the rejected identity. + * @param failure - typed failure owned by the active boundary adapter. + */ + constructor(failure: Failure); +} +export type { InvocationDescriptor, InvocationParameterDescriptor, InvocationSourceLocation, RemoteFailure, RemoteResult, TypertClientRemote, TypertClientContextBinder, TypertCodec, TypertContext, TypertContextMap, TypertContextRegistry, TypertContextWire, TypertDisposer, TypertForwardableEvent, TypertHostContextProvider, TypertHostContextResolver, TypertLocalRegistry, TypertLookup, TypertLookupDefinition, TypertLookupHost, TypertLookupMap, TypertLookupProvider, TypertLookupResolver, TypertLookupRegistry, TypertLookupWire, TypertRemoteScopeApi, TypertRemoteScopeMap, TypertRemoteScopeNamespace, TypertRemoteContribution, TypertRemoteEvent, TypertRemoteEventSelection, TypertRemoteMap, TypertRemoteNamespace, TypertRemoteNamespaceMap, TypertRemoteRegistry, TypertRegistryChange, TypertRegistryListener, TypertSchema, TypertRegistryContract, } from './types.ts'; +/** Options for an explicit Service-to-Gateway binding. */ +export interface TypertGatewayBindingOptions { + /** Wire namespace; defaults to the Cordis service key. */ + readonly namespace?: string; +} +/** Visible declaration that one Service participates in Typert Gateway export. */ +export interface TypertGatewayBinding { + readonly service: Service; + readonly serviceKey: string; + readonly namespace: string; +} +/** Invocation mode recorded by a Remote method decorator. */ +export type RemoteInvocationMarker = { + readonly kind: 'direct'; +} | { + readonly kind: 'context'; + readonly context: string; +}; +/** One decorator marker discovered for a live Service instance. */ +export interface RemoteMethodMarker { + /** Public instance method carrying the implementation. */ + readonly method: string; + /** Endpoint method when it differs from the implementation member. */ + readonly exportName?: string; + readonly invocation: RemoteInvocationMarker; +} +type RemoteMethodDecorator = (method: (this: This, ...args: Args) => Result, context: ClassMethodDecoratorContext Result>) => void; +/** + * Bind one visible Service field to a Cordis key and Remote namespace. + * @param service - owning Service instance, normally `this`. + * @param serviceKey - exact Cordis service key. + * @param options - optional distinct wire namespace. + * @returns a frozen, inspectable binding with no compiler-injected metadata. + */ +export declare function bindTypertRemote(service: Service, serviceKey: string, options?: TypertGatewayBindingOptions): TypertGatewayBinding; +/** Cordis Service base that exposes its registered name through Typert Gateway. */ +export declare abstract class TypertRemoteService extends Service { + /** Visible binding consumed by the Gateway's source-mode discovery. */ + readonly typertRemote: TypertGatewayBinding; + /** + * Register the Service and bind the same key to Typert Gateway. + * @param ctx - owning Cordis Context. + * @param serviceKey - exact Cordis service key and default wire namespace. + * @param options - optional distinct wire namespace. + */ + protected constructor(ctx: Context, serviceKey: string, options?: TypertGatewayBindingOptions); +} +/** + * Mark one public instance method as a direct Remote invocation. + * @param _method - decorated method; retained only by the class itself. + * @param context - standard decorator context used to schedule private marking. + */ +export declare function Remote(_method: (this: This, ...args: Args) => Result, context: ClassMethodDecoratorContext Result>): void; +/** + * Mark one public instance method under a distinct exported method name. + * @param exportName - Remote endpoint method, without a namespace or slash. + * @returns a standard method decorator. + */ +export declare function Remote(exportName: string): RemoteMethodDecorator; +/** + * Create a decorator for a method resolved from one Remote Scope. + * @param key - scope key declared through the Context map. + * @param exportName - optional Remote export name; defaults to the method name. + * @returns a standard method decorator that records only private module state. + */ +export declare function RemoteScope(key: Extract, exportName?: string): RemoteMethodDecorator; +/** + * Read Remote markers attached to a live Service by decorator initializers. + * The returned snapshot cannot mutate the private marker table. + * @param service - live Service instance. + * @returns markers in class declaration order. + */ +export declare function remoteMethods(service: object): readonly RemoteMethodMarker[]; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.js new file mode 100644 index 0000000..7da4fb7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.js @@ -0,0 +1,139 @@ +/** + * Remote decorators and explicit Gateway bindings backed only by private + * module state. Strict reflection remains a Typert compiler responsibility. + * @module @deepseek-ai/dsh-typert-protocol + */ +import { Service } from '@deepseek-ai/cordis'; +const TYPERT_REMOTE_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/; +/** + * Test one generated Remote name against the Connection endpoint grammar. + * @param value - namespace, method, lookup, or Context segment. + * @returns whether the value can cross the shared RPC carrier unchanged. + */ +export function isTypertRemoteSegment(value) { + return value !== '.' && value !== '..' && TYPERT_REMOTE_SEGMENT_PATTERN.test(value); +} +/** + * A lookup policy rejection whose typed payload belongs to the active boundary adapter. + * Gateway adapters preserve this payload instead of collapsing it into an infrastructure failure. + */ +export class TypertLookupFailure extends Error { + /** Adapter-owned failure returned to the caller. */ + failure; + /** + * Wrap one adapter failure without exposing the rejected identity. + * @param failure - typed failure owned by the active boundary adapter. + */ + constructor(failure) { + super('Typert lookup policy rejected the requested identity'); + this.name = 'TypertLookupFailure'; + this.failure = failure; + } +} +const markers = new WeakMap(); +/** + * Bind one visible Service field to a Cordis key and Remote namespace. + * @param service - owning Service instance, normally `this`. + * @param serviceKey - exact Cordis service key. + * @param options - optional distinct wire namespace. + * @returns a frozen, inspectable binding with no compiler-injected metadata. + */ +export function bindTypertRemote(service, serviceKey, options = {}) { + validateName('service key', serviceKey); + const namespace = options.namespace ?? serviceKey; + validateName('namespace', namespace); + return Object.freeze({ service, serviceKey, namespace }); +} +/** Cordis Service base that exposes its registered name through Typert Gateway. */ +export class TypertRemoteService extends Service { + /** Visible binding consumed by the Gateway's source-mode discovery. */ + typertRemote; + /** + * Register the Service and bind the same key to Typert Gateway. + * @param ctx - owning Cordis Context. + * @param serviceKey - exact Cordis service key and default wire namespace. + * @param options - optional distinct wire namespace. + */ + constructor(ctx, serviceKey, options = {}) { + super(ctx, serviceKey); + this.typertRemote = bindTypertRemote(this, this.name, options); + } +} +export function Remote(methodOrExportName, context) { + if (typeof methodOrExportName === 'string') { + validateName('Remote export name', methodOrExportName); + return function (_method, decoratorContext) { + addMarkerInitializer(decoratorContext, { kind: 'direct' }, methodOrExportName); + }; + } + if (context === undefined) + throw new TypeError('typert-protocol: Remote decorator context is missing'); + addMarkerInitializer(context, { kind: 'direct' }); +} +/** + * Create a decorator for a method resolved from one Remote Scope. + * @param key - scope key declared through the Context map. + * @param exportName - optional Remote export name; defaults to the method name. + * @returns a standard method decorator that records only private module state. + */ +export function RemoteScope(key, exportName) { + validateName('Scope key', key); + if (exportName !== undefined) + validateName('Remote export name', exportName); + return function (_method, context) { + addMarkerInitializer(context, { kind: 'context', context: key }, exportName); + }; +} +/** + * Read Remote markers attached to a live Service by decorator initializers. + * The returned snapshot cannot mutate the private marker table. + * @param service - live Service instance. + * @returns markers in class declaration order. + */ +export function remoteMethods(service) { + const prototype = Object.getPrototypeOf(service); + if (prototype === null) + return []; + return [...(markers.get(prototype) ?? [])].map(([method, marker]) => ({ method, ...marker })); +} +function addMarkerInitializer(context, invocation, exportName) { + if (context.private || context.static || typeof context.name !== 'string') { + throw new TypeError('typert-protocol: Remote decorators require a public instance method with a string name'); + } + const method = context.name; + context.addInitializer(function () { + const prototype = Object.getPrototypeOf(this); + if (prototype === null) { + throw new TypeError(`typert-protocol: cannot mark Remote method "${method}" on an object without a prototype`); + } + mark(prototype, method, invocation, exportName); + }); +} +function mark(prototype, method, invocation, exportName) { + let table = markers.get(prototype); + if (table === undefined) { + table = new Map(); + markers.set(prototype, table); + } + const marker = { + ...(exportName === undefined || exportName === method ? {} : { exportName }), + invocation: Object.freeze(invocation), + }; + const current = table.get(method); + if (current !== undefined) { + if (current.exportName === marker.exportName && sameInvocation(current.invocation, invocation)) + return; + throw new Error(`typert-protocol: Remote method "${method}" has conflicting invocation markers`); + } + table.set(method, Object.freeze(marker)); +} +function sameInvocation(left, right) { + return left.kind === right.kind + && (left.kind === 'direct' || (right.kind === 'context' && left.context === right.context)); +} +function validateName(subject, value) { + if (!isTypertRemoteSegment(value)) { + throw new TypeError(`typert-protocol: ${subject} must contain only RPC endpoint segment characters`); + } +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.d.ts new file mode 100644 index 0000000..8349620 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-typert-protocol`. + * @module @deepseek-ai/dsh-typert-protocol/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "typert-protocol-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.js new file mode 100644 index 0000000..f2db7ae --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.js @@ -0,0 +1,22 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-typert-protocol`. + * @module @deepseek-ai/dsh-typert-protocol/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-typert-protocol'; +/** Cordis companion plugin name. */ +export const name = 'typert-protocol-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: decorators retain private immutable declarations and + * bindings are frozen values with no independent event stream to cross-check. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.d.ts new file mode 100644 index 0000000..cf2e664 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.d.ts @@ -0,0 +1,419 @@ +/** + * Compiler-independent Typert protocol shared by business packages, generated + * Remote artifacts, the Host Gateway, and Client API implementations. + * @module @deepseek-ai/dsh-typert-protocol/types + */ +import type { Context, Events } from '@deepseek-ai/cordis'; +declare const LOOKUP_HOST: unique symbol; +declare const LOOKUP_WIRE: unique symbol; +declare const CONTEXT_WIRE: unique symbol; +/** Type-level association between a Host object and its wire identity. */ +export interface TypertLookup { + readonly [LOOKUP_HOST]: Host; + readonly [LOOKUP_WIRE]: Wire; +} +/** Extract the Host object associated with one lookup declaration. */ +export type TypertLookupHost = Lookup extends TypertLookup ? Host : never; +/** Extract the wire identity associated with one lookup declaration. */ +export type TypertLookupWire = Lookup extends TypertLookup ? Wire : never; +/** Type-level association between a scoped Context kind and its wire identity. */ +export interface TypertContext { + readonly [CONTEXT_WIRE]: Wire; +} +/** Extract the wire identity associated with one scoped Context declaration. */ +export type TypertContextWire = ContextType extends TypertContext ? Wire : never; +/** Merge-extensible Host object lookup declarations. */ +export interface TypertLookupMap { +} +/** Merge-extensible scoped Context declarations. */ +export interface TypertContextMap { +} +/** Merge-extensible direct Remote method signatures generated for consumers. */ +export interface TypertRemoteMap { +} +/** + * One Remote call's failure as the carrier reported it. `code` stays open here: + * the closed RPC code union belongs to the carrier package, which already + * depends on this one, so naming it would invert that edge. + */ +export interface RemoteFailure { + readonly code: string; + readonly message: string; + readonly details: object; +} +/** + * What every generated Remote method resolves to. The Remote face itself folds + * carrier failures into the error branch, so no consumer wraps a call to + * recover one; only assembly faults (arity, an unmounted method, a missing + * Context binder) still reject. + * @template T - the Host method's business result. + */ +export type RemoteResult = { + readonly ok: true; + readonly value: T; +} | { + readonly ok: false; + readonly error: RemoteFailure; +}; +/** Merge-extensible scoped Remote method signatures generated for consumers. */ +export interface TypertRemoteScopeMap { +} +/** + * Cordis event names whose shape a one-way Remote delivery can carry: unbound + * from any Scope and returning `void`. Which ones are actually forwarded is the + * Host assembly's selection; this predicate only excludes shapes the carrier + * cannot represent. + */ +export type TypertForwardableEvent = { + [Event in keyof Events]: unknown extends ThisParameterType ? ReturnType extends void ? Event : never : never; +}[keyof Events]; +/** Merge-extensible forwarding selection declared once by the Host assembly. */ +export interface TypertRemoteEventSelection { +} +/** Legal `$on` keys: selected events that exist in the current compilation face. */ +export type TypertRemoteEvent = Extract; +/** + * Resolve one direct Remote namespace from the generated flat endpoint map. + * @template Namespace - wire namespace before the endpoint slash. + */ +export type TypertRemoteNamespace = { + [Endpoint in keyof TypertRemoteMap as Endpoint extends `${Namespace}/${infer Method}` ? Method : never]: TypertRemoteMap[Endpoint]; +}; +/** + * Resolve one scoped Remote namespace across every generated Context kind. + * The calling Cordis Context supplies the concrete identity at runtime. + * @template Namespace - wire namespace between the Context prefix and method. + */ +export type TypertRemoteScopeNamespace = { + [Endpoint in keyof TypertRemoteScopeMap as Endpoint extends `${ContextKey}:${Namespace}/${infer Method}` ? Method : never]: TypertRemoteScopeMap[Endpoint]; +}; +type TypertRemoteScopeNamespaceKey = Endpoint extends `${ContextKey}:${infer Namespace}/${string}` ? Namespace : never; +/** Generated scoped Remote namespaces available to one Context kind. */ +export type TypertRemoteScopeApi = { + [Namespace in TypertRemoteScopeNamespaceKey]: TypertRemoteScopeNamespace; +}; +/** Merge-extensible direct namespace surface generated for Client Remote services. */ +export interface TypertRemoteNamespaceMap { +} +/** Awaitable disposer returned by Cordis-owned Typert registrations. */ +export type TypertDisposer = () => Promise; +type StringKeyOf = Extract; +/** Minimal runtime-schema capability carried by strict generated codecs. */ +export interface TypertSchema { + /** + * Parse and validate one boundary value. + * @param value - untrusted boundary value. + * @returns the validated value. + */ + parse(value: unknown): Output; +} +/** Codec attached to one invocation parameter or result. */ +export type TypertCodec = { + readonly mode: 'strict'; + readonly typeSymbol: string; + readonly schema: TypertSchema; +} | { + readonly mode: 'src-json'; +}; +/** One ordered business parameter in a Remote invocation. */ +export interface InvocationParameterDescriptor { + /** Source-level parameter name. */ + readonly name: string; + /** Required key in the wire `args` object. */ + readonly wire: string; + /** Whether the value is JSON or requires a registered Host lookup. */ + readonly source: 'json' | 'lookup'; + /** Lookup key when `source` is `lookup`. */ + readonly lookup?: string; + /** Boundary codec for the wire representation. */ + readonly codec: TypertCodec; + /** Missing wire fields decode to `undefined` only for an explicitly declared `T | undefined`. */ + readonly acceptsUndefined?: true; +} +/** Source position retained for diagnostics from generated definitions. */ +export interface InvocationSourceLocation { + readonly file: string; + readonly line: number; + readonly column: number; +} +/** Carrier-independent description of one exported method invocation. */ +export interface InvocationDescriptor { + /** Globally stable generated identity. */ + readonly id: string; + /** Cordis service key owning the method. */ + readonly service: string; + /** Wire namespace, defaulting to the service key. */ + readonly namespace: string; + /** Public instance method name. */ + readonly method: string; + /** Service member invoked when the exported method name is an alias. */ + readonly implementation?: string; + /** Receiver selection mode. */ + readonly invocation: { + readonly kind: 'direct'; + } | { + readonly kind: 'context'; + readonly context: string; + readonly wire: string; + readonly codec: TypertCodec; + }; + /** Optional consuming-Context projection for one direct lookup parameter. */ + readonly scope?: { + /** Context kind whose Client binder supplies the identity. */ + readonly context: string; + /** Lookup parameter wire field replaced by the Context identity. */ + readonly wire: string; + }; + /** Ordered business parameters. */ + readonly parameters: readonly InvocationParameterDescriptor[]; + /** Transport cancellation injected after business parameters instead of entering wire args. */ + readonly cancellation?: { + /** Reserved final Host method parameter. */ + readonly parameter: 'signal'; + }; + /** Codec for the resolved method result. */ + readonly result: TypertCodec; + /** Source declaration used only for diagnostics. */ + readonly sourceLocation?: InvocationSourceLocation; +} +/** Generated Host contract selected explicitly by a Client assembly. */ +export interface TypertRemoteContribution { + /** npm package that owns the Remote methods. */ + readonly package: string; + /** Consumer-side invocation descriptors generated from that package. */ + readonly descriptors: readonly InvocationDescriptor[]; +} +/** Client Remote capability implemented by the Gateway and consumed by Remote assemblies. */ +export interface TypertClientRemote extends TypertRemoteNamespaceMap { + /** + * Mount one generated Host-for-Client contribution in the caller's fiber. + * @param contribution - explicitly selected Remote package artifact. + * @returns disposer after namespace services and concrete methods are ready. + */ + $mount(contribution: TypertRemoteContribution): Promise; + /** + * Subscribe to one forwarded Host event; delivery is one-way, in registration + * order, and isolates a throwing listener from the rest. + * @template Event - forwarded event name selected by the Host assembly. + * @param event - forwarded Host event name, unchanged on the wire. + * @param listener - receives the Host's argument list as declared by Cordis `Events`. + * @returns disposer owned by the calling fiber. + */ + $on(event: Event, listener: Events[Event]): () => void; + /** + * Hand one decoded forwarded frame to the subscription table. The carrier + * owning the Host frame sink calls this; a consumer subscribes with + * {@link TypertClientRemote.$on} and never calls it. + * + * `event` is a plain string because this is the wire boundary: the name is + * whatever the Host assembly's allowlist selected, and one nobody subscribed + * to is dropped silently. + * @param event - forwarded Host event name, exactly as the Host emitted it. + * @param args - the Host argument list, already JSON-decoded. + */ + $dispatch(event: string, args: readonly unknown[]): void; +} +/** + * Resolve one validated wire identity, synchronously or asynchronously. + * @param id - validated wire identity. + * @returns the Host object, or `undefined` when unavailable. + */ +export type TypertLookupResolver = (id: Wire) => Host | undefined | Promise; +/** Runtime provider for one declared Host object lookup. */ +export interface TypertLookupProvider { + /** Source parameter name recognized by the SRC weak parser. */ + readonly parameter: string; + /** Wire field replacing the Host object parameter. */ + readonly wire: string; + /** Canonical Host type symbol used by strict generation. */ + readonly hostTypeSymbol: string; + /** Canonical wire type symbol used by strict generation. */ + readonly wireTypeSymbol: string; + /** + * Resolve a wire identity through the provider's default policy. + * @param id - validated wire identity. + * @returns the object, `undefined` when unavailable, or either asynchronously. + */ + resolve(id: Wire): Host | undefined | Promise; +} +/** Stable wire declaration retained after a lookup provider unloads. */ +export interface TypertLookupDefinition { + /** Merge-declared lookup key. */ + readonly key: string; + /** Source parameter name recognized by the SRC weak parser. */ + readonly parameter: string; + /** Wire field replacing the Host object parameter. */ + readonly wire: string; + /** Canonical Host type symbol used by strict generation. */ + readonly hostTypeSymbol: string; + /** Canonical wire type symbol used by strict generation. */ + readonly wireTypeSymbol: string; +} +/** Host resolver for one scoped Remote kind. */ +export interface TypertHostContextProvider { + /** Wire field carrying the Context identity. */ + readonly wire: string; + /** Canonical wire type symbol used by strict generation. */ + readonly wireTypeSymbol: string; + /** + * Resolve a wire identity to its live scoped Context. + * @param id - validated wire identity. + * @returns the scoped Context, or `undefined` when unavailable. + */ + resolve(id: Wire): Context | undefined | Promise; +} +/** Composition-owned resolver replacing one Host Context provider's default lookup policy. */ +export type TypertHostContextResolver = (id: Wire) => Context | undefined | Promise; +/** Client resolver for the identity carried by the calling scoped Context. */ +export interface TypertClientContextBinder { + /** + * Read the Remote identity represented by a calling Context. + * @param ctx - Context rebound by the Cordis service tracker. + * @returns the wire identity, or `undefined` when the Context has the wrong scope. + */ + identity(ctx: Context): Wire | undefined; +} +/** Notification emitted after a Typert runtime registry changes. */ +export interface TypertRegistryChange { + readonly kind: 'local' | 'remote' | 'lookup' | 'host-context' | 'client-context'; + readonly key: string; +} +/** Listener for one Typert runtime registry. */ +export type TypertRegistryListener = (change: TypertRegistryChange) => void; +/** Current-environment invocation definitions. */ +export interface TypertLocalRegistry { + /** + * Look up one invocation by `/`. + * @param endpoint - canonical endpoint. + * @returns the live descriptor, or `undefined` when absent. + */ + get(endpoint: string): InvocationDescriptor | undefined; + /** + * Report whether a strict definition has existed during this Typert Service lifetime. + * @param endpoint - canonical endpoint. + * @returns `true` after the endpoint has been registered at least once, even if withdrawn. + */ + hasSeen(endpoint: string): boolean; + /** @returns a registration-order snapshot of local descriptors. */ + list(): readonly InvocationDescriptor[]; + /** + * Observe later local-definition changes. + * @param listener - synchronous contained observer. + * @returns disposer for this subscription. + */ + subscribe(listener: TypertRegistryListener): TypertDisposer; +} +/** Consumer-selected Remote contribution registry. */ +export interface TypertRemoteRegistry { + /** + * Register one generated contribution for the calling Cordis fiber. + * @param contribution - generated Remote descriptors. + * @returns disposer withdrawing the exact contribution. + */ + register(contribution: TypertRemoteContribution): TypertDisposer; + /** + * Look up one Remote descriptor by endpoint. + * @param endpoint - canonical endpoint. + * @returns the descriptor, or `undefined` when unmounted. + */ + get(endpoint: string): InvocationDescriptor | undefined; + /** @returns a registration-order snapshot of Remote descriptors. */ + list(): readonly InvocationDescriptor[]; + /** + * Observe later Remote contribution changes. + * @param listener - synchronous contained observer. + * @returns disposer for this subscription. + */ + subscribe(listener: TypertRegistryListener): TypertDisposer; +} +/** Runtime registry for Host object lookup providers. */ +export interface TypertLookupRegistry { + /** + * Register one provider under its merge-declared key. + * @param key - lookup key. + * @param provider - owning package's live resolver. + * @returns disposer withdrawing the exact provider. + */ + register>(key: K, provider: TypertLookupProvider, TypertLookupWire>): TypertDisposer; + /** + * Replace one provider's default resolution policy while this contribution is active. + * Configuration may precede provider registration; without a live provider, `get()` remains unavailable. + * @param key - lookup key whose wire declaration remains provider-owned. + * @param resolver - composition-owned resolver used by every lookup of this key. + * @returns disposer restoring the provider's default resolver. + */ + configure>(key: K, resolver: TypertLookupResolver, TypertLookupWire>): TypertDisposer; + /** + * Look up one provider by runtime key. + * @param key - descriptor lookup key. + * @returns the live provider, or `undefined` when absent. + */ + get(key: string): TypertLookupProvider | undefined; + /** @returns lookup declarations observed during this Typert Service lifetime. */ + definitions(): readonly TypertLookupDefinition[]; + /** @returns a snapshot of registered provider keys. */ + keys(): readonly string[]; + /** + * Observe later lookup changes. + * @param listener - synchronous contained observer. + * @returns disposer for this subscription. + */ + subscribe(listener: TypertRegistryListener): TypertDisposer; +} +/** Runtime registry for Host Context resolvers and Client Context binders. */ +export interface TypertContextRegistry { + /** + * Register a Host Context resolver. + * @param key - merge-declared Context key. + * @param provider - owning package's Host resolver. + * @returns disposer withdrawing the exact provider. + */ + registerHost>(key: K, provider: TypertHostContextProvider>): TypertDisposer; + /** + * Override one Host Context key's identity policy for the calling fiber. + * Configuration may precede provider registration and restores the provider's default resolver on disposal. + * @param key - merge-declared Context key. + * @param resolver - composition-owned resolver used by every Host Context lookup of this key. + * @returns disposer restoring the provider's default resolver. + */ + configureHost>(key: K, resolver: TypertHostContextResolver>): TypertDisposer; + /** + * Register a Client Context identity binder. + * @param key - merge-declared Context key. + * @param binder - Client scope identity resolver. + * @returns disposer withdrawing the exact binder. + */ + registerClient>(key: K, binder: TypertClientContextBinder>): TypertDisposer; + /** + * Look up a Host Context resolver. + * @param key - descriptor Context key. + * @returns the provider, or `undefined` when absent. + */ + getHost(key: string): TypertHostContextProvider | undefined; + /** + * Look up a Client Context binder. + * @param key - descriptor Context key. + * @returns the binder, or `undefined` when absent. + */ + getClient(key: string): TypertClientContextBinder | undefined; + /** + * Observe later Context provider changes. + * @param listener - synchronous contained observer. + * @returns disposer for this subscription. + */ + subscribe(listener: TypertRegistryListener): TypertDisposer; +} +/** Minimal Typert runtime consumed through dependency inversion. */ +export interface TypertRegistryContract { + readonly local: TypertLocalRegistry; + readonly remotes: TypertRemoteRegistry; + readonly lookups: TypertLookupRegistry; + readonly contexts: TypertContextRegistry; +} +declare module '@deepseek-ai/cordis' { + interface Context { + typert: TypertRegistryContract; + } +} +export {}; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.js new file mode 100644 index 0000000..69b9894 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Compiler-independent Typert protocol shared by business packages, generated + * Remote artifacts, the Host Gateway, and Client API implementations. + * @module @deepseek-ai/dsh-typert-protocol/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/package.json new file mode 100644 index 0000000..c039431 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol/package.json @@ -0,0 +1,47 @@ +{ + "name": "@deepseek-ai/dsh-typert-protocol", + "description": "Compiler-independent Remote metadata and Typert provider protocols", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/typert/protocol" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.i18n.yaml new file mode 100644 index 0000000..af84089 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/typert/protocol/README.md +README.md: 84f9f1b31cca35cffce5dc5fc84db1017adaad08 +README.zh.md: 97e4734a7292f0a305ff8ed00ff1d72d1a53b5e9 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.md new file mode 100644 index 0000000..84f9f1b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.md @@ -0,0 +1,38 @@ +# @deepseek-ai/dsh-typert-protocol + +English | [中文](README.zh.md) + +Compiler-independent declarations shared by business packages, generated Typert artifacts, the Host Gateway, and Client API. This package owns the Remote Service base, decorators, explicit binding fallback, merge-extensible protocol maps, invocation descriptors, codecs, and provider contracts; it does not run TypeScript analysis or register a concrete Cordis service. + +## Remote declarations + +- `@Remote` marks a public instance method for direct invocation on its registered Cordis Service. +- `@RemoteScope(key)` marks a method whose receiver is selected from a merge-declared scoped Context kind. +- `TypertRemoteService` binds the Cordis key passed to `super(ctx, serviceKey, options?)` to the same default wire namespace. +- `bindTypertRemote(this, serviceKey, options?)` provides the same visible, frozen binding for a Service that cannot inherit from `TypertRemoteService`. +- `remoteMethods(service)` returns a detached declaration-order snapshot used by the Gateway's SRC fallback. + +A Host method opts into cooperative cancellation by declaring `signal: AbortSignal` as its final parameter. `InvocationDescriptor.cancellation` records that reserved injection point; the signal never becomes a JSON parameter or lookup field. SRC recognizes the final parameter name, while strict generation also verifies the global `AbortSignal` type. + +Decorator initializers retain markers in a module-private `WeakMap` keyed by the Service prototype. They do not add constructor symbols, prototype properties, parameter metadata, or runtime reflection fields. A `TypertRemoteService` exposes the same public readonly `typertRemote` binding that the explicit helper returns. + +## Typert protocol + +Business packages extend `TypertLookupMap` and `TypertContextMap` to associate Host objects or scoped Contexts with their wire identities. Generated artifacts extend `TypertRemoteMap`, `TypertRemoteScopeMap`, and `TypertRemoteNamespaceMap` so Client imports expose only selected Remote methods. `InvocationDescriptor` is the shared runtime form consumed by the registry, Gateway, and Client Remote. + +The Host assembly extends `TypertRemoteEventSelection` with the Host events it forwards to consumers, which narrows the `ctx.remote.$on` key face; `TypertForwardableEvent` states the shapes a one-way delivery can carry at all, excluding Scope-bound and answered events. `TypertClientRemote` carries both roles of that surface: consumers subscribe through `$on`, and the Client half owning the host frame sink hands frames over through `$dispatch`. + +Lookup and Context packages own both sides of their contract: declaration merging supplies the static association, while runtime providers register identity resolution with `ctx.typert`. A lookup or Host Context provider supplies the stable declaration and default resolver, while Host composition may separately configure a synchronous or asynchronous resolver; policy rejections may use `TypertLookupFailure` to carry a failure value owned by the boundary adapter. Strict codecs carry generated schemas; `src-json` codecs identify the weaker source-launch path. + +## Model Experience + +None, as this protocol package declares application reflection and registers nothing model-facing. + +#### KV Cache effect + +No direct effect. + +## Known Limitations and Deferred Work + +- Decorator markers contain only the method name and direct or Context invocation mode. Parameter, result, lookup, and schema reflection require the Typert build pipeline. +- Remote decorators accept only public, non-static instance methods with string names. SRC execution cannot represent overloaded, destructured, defaulted, or rest-parameter signatures. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.zh.md new file mode 100644 index 0000000..97e4734 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/README.zh.md @@ -0,0 +1,38 @@ +# @deepseek-ai/dsh-typert-protocol + +[English](README.md) | 中文 + +该包提供不依赖编译器的声明,由业务包、生成的 Typert 产物、宿主网关和客户端 API 共享。它负责 Remote 服务基类、装饰器、显式绑定回退、可通过声明合并扩展的协议映射、调用描述符、编解码器和提供方约定;它不执行 TypeScript 分析,也不注册具体 Cordis 服务。 + +## Remote 声明 + +- `@Remote` 将公开实例方法标记为可在其注册的 Cordis 服务上直接调用。 +- `@RemoteScope(key)` 标记接收者选自合并声明的作用域 Context 类型的方法。 +- `TypertRemoteService` 将传给 `super(ctx, serviceKey, options?)` 的 Cordis 键绑定到同一默认协议命名空间。 +- `bindTypertRemote(this, serviceKey, options?)` 为无法继承 `TypertRemoteService` 的服务提供同样可见且冻结的绑定。 +- `remoteMethods(service)` 返回按声明顺序排列、与内部状态分离的快照,供 Gateway 的 SRC 回退路径使用。 + +宿主方法通过将 `signal: AbortSignal` 声明为最后一个参数来启用协作式取消。`InvocationDescriptor.cancellation` 记录这个保留的注入点;该信号绝不会成为 JSON 参数或查找字段。SRC 识别末位参数名,严格生成还会校验它是否具有全局 `AbortSignal` 类型。 + +装饰器初始化器将标记保存在以服务原型为键的模块私有 `WeakMap` 中。它们不会在构造函数上添加符号,也不会添加原型属性、参数元数据或运行时反射字段。`TypertRemoteService` 会暴露与显式辅助函数相同的公开只读 `typertRemote` 绑定。 + +## Typert 协议 + +业务包扩展 `TypertLookupMap` 和 `TypertContextMap`,以关联宿主对象或作用域 Context 与其协议身份。生成的产物扩展 `TypertRemoteMap`、`TypertRemoteScopeMap` 和 `TypertRemoteNamespaceMap`,使客户端导入后仅暴露选定的 Remote 方法。`InvocationDescriptor` 是供注册表、网关和客户端 Remote 使用的共享运行时形式。 + +Host 装配以转发给消费端的 Host 事件扩展 `TypertRemoteEventSelection`,从而收窄 `ctx.remote.$on` 的键面;`TypertForwardableEvent` 陈述单向投递根本能承载哪些形状,把 Scope 化事件与有返回值的事件排除在外。`TypertClientRemote` 承载该面的两种角色:消费方经 `$on` 订阅,持有 Host 帧 sink 的 Client 半经 `$dispatch` 交出帧。 + +查找包与 Context 包同时负责该约定的两侧:声明合并提供静态关联,运行时提供方则向 `ctx.typert` 注册身份解析。查找提供方或宿主 Context 提供方提供稳定声明与默认解析器,宿主组合可以另行配置同步或异步解析器;策略拒绝可用 `TypertLookupFailure` 携带由边界适配器拥有的失败值。严格编解码器携带生成的 schema;`src-json` 编解码器标识约束更弱的源码启动路径。 + +## 模型体验 + +无,因为该协议包声明应用反射,不注册任何面向模型的内容。 + +#### KV Cache 影响 + +无直接影响。 + +## 已知限制与暂缓事项 + +- 装饰器标记仅包含方法名,以及直接调用或 Context 调用模式。参数、结果、查找和 schema 反射需要 Typert 构建流水线。 +- Remote 装饰器只接受具有字符串名称的公开、非静态实例方法。SRC 执行无法表示重载签名,以及包含解构参数、默认参数或剩余参数的方法签名。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js new file mode 100644 index 0000000..15ad367 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js @@ -0,0 +1,140 @@ +import { Service } from "@deepseek-ai/cordis"; +//#region lib/types/index.js +/** +* Remote decorators and explicit Gateway bindings backed only by private +* module state. Strict reflection remains a Typert compiler responsibility. +* @module @deepseek-ai/dsh-typert-protocol +*/ +const TYPERT_REMOTE_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/; +/** +* Test one generated Remote name against the Connection endpoint grammar. +* @param value - namespace, method, lookup, or Context segment. +* @returns whether the value can cross the shared RPC carrier unchanged. +*/ +function isTypertRemoteSegment(value) { + return value !== "." && value !== ".." && TYPERT_REMOTE_SEGMENT_PATTERN.test(value); +} +/** +* A lookup policy rejection whose typed payload belongs to the active boundary adapter. +* Gateway adapters preserve this payload instead of collapsing it into an infrastructure failure. +*/ +var TypertLookupFailure = class extends Error { + /** Adapter-owned failure returned to the caller. */ + failure; + /** + * Wrap one adapter failure without exposing the rejected identity. + * @param failure - typed failure owned by the active boundary adapter. + */ + constructor(failure) { + super("Typert lookup policy rejected the requested identity"); + this.name = "TypertLookupFailure"; + this.failure = failure; + } +}; +const markers = /* @__PURE__ */ new WeakMap(); +/** +* Bind one visible Service field to a Cordis key and Remote namespace. +* @param service - owning Service instance, normally `this`. +* @param serviceKey - exact Cordis service key. +* @param options - optional distinct wire namespace. +* @returns a frozen, inspectable binding with no compiler-injected metadata. +*/ +function bindTypertRemote(service, serviceKey, options = {}) { + validateName("service key", serviceKey); + const namespace = options.namespace ?? serviceKey; + validateName("namespace", namespace); + return Object.freeze({ + service, + serviceKey, + namespace + }); +} +/** Cordis Service base that exposes its registered name through Typert Gateway. */ +var TypertRemoteService = class extends Service { + /** Visible binding consumed by the Gateway's source-mode discovery. */ + typertRemote; + /** + * Register the Service and bind the same key to Typert Gateway. + * @param ctx - owning Cordis Context. + * @param serviceKey - exact Cordis service key and default wire namespace. + * @param options - optional distinct wire namespace. + */ + constructor(ctx, serviceKey, options = {}) { + super(ctx, serviceKey); + this.typertRemote = bindTypertRemote(this, this.name, options); + } +}; +function Remote(methodOrExportName, context) { + if (typeof methodOrExportName === "string") { + validateName("Remote export name", methodOrExportName); + return function(_method, decoratorContext) { + addMarkerInitializer(decoratorContext, { kind: "direct" }, methodOrExportName); + }; + } + if (context === void 0) throw new TypeError("typert-protocol: Remote decorator context is missing"); + addMarkerInitializer(context, { kind: "direct" }); +} +/** +* Create a decorator for a method resolved from one Remote Scope. +* @param key - scope key declared through the Context map. +* @param exportName - optional Remote export name; defaults to the method name. +* @returns a standard method decorator that records only private module state. +*/ +function RemoteScope(key, exportName) { + validateName("Scope key", key); + if (exportName !== void 0) validateName("Remote export name", exportName); + return function(_method, context) { + addMarkerInitializer(context, { + kind: "context", + context: key + }, exportName); + }; +} +/** +* Read Remote markers attached to a live Service by decorator initializers. +* The returned snapshot cannot mutate the private marker table. +* @param service - live Service instance. +* @returns markers in class declaration order. +*/ +function remoteMethods(service) { + const prototype = Object.getPrototypeOf(service); + if (prototype === null) return []; + return [...markers.get(prototype) ?? []].map(([method, marker]) => ({ + method, + ...marker + })); +} +function addMarkerInitializer(context, invocation, exportName) { + if (context.private || context.static || typeof context.name !== "string") throw new TypeError("typert-protocol: Remote decorators require a public instance method with a string name"); + const method = context.name; + context.addInitializer(function() { + const prototype = Object.getPrototypeOf(this); + if (prototype === null) throw new TypeError(`typert-protocol: cannot mark Remote method "${method}" on an object without a prototype`); + mark(prototype, method, invocation, exportName); + }); +} +function mark(prototype, method, invocation, exportName) { + let table = markers.get(prototype); + if (table === void 0) { + table = /* @__PURE__ */ new Map(); + markers.set(prototype, table); + } + const marker = { + ...exportName === void 0 || exportName === method ? {} : { exportName }, + invocation: Object.freeze(invocation) + }; + const current = table.get(method); + if (current !== void 0) { + if (current.exportName === marker.exportName && sameInvocation(current.invocation, invocation)) return; + throw new Error(`typert-protocol: Remote method "${method}" has conflicting invocation markers`); + } + table.set(method, Object.freeze(marker)); +} +function sameInvocation(left, right) { + return left.kind === right.kind && (left.kind === "direct" || right.kind === "context" && left.context === right.context); +} +function validateName(subject, value) { + if (!isTypertRemoteSegment(value)) throw new TypeError(`typert-protocol: ${subject} must contain only RPC endpoint segment characters`); +} +//#endregion +export { Remote, RemoteScope, TypertLookupFailure, TypertRemoteService, bindTypertRemote, isTypertRemoteSegment, remoteMethods }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/invariant.js new file mode 100644 index 0000000..8581038 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-typert-protocol`. +* @module @deepseek-ai/dsh-typert-protocol/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-typert-protocol"; +/** Cordis companion plugin name. */ +const name = "typert-protocol-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: decorators retain private immutable declarations and +* bindings are frozen values with no independent event stream to cross-check. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.d.ts new file mode 100644 index 0000000..f4c9be5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.d.ts @@ -0,0 +1,101 @@ +/** + * Remote decorators and explicit Gateway bindings backed only by private + * module state. Strict reflection remains a Typert compiler responsibility. + * @module @deepseek-ai/dsh-typert-protocol + */ +import { Service, type Context } from '@deepseek-ai/cordis'; +import type { TypertContextMap } from './types.ts'; +/** + * Test one generated Remote name against the Connection endpoint grammar. + * @param value - namespace, method, lookup, or Context segment. + * @returns whether the value can cross the shared RPC carrier unchanged. + */ +export declare function isTypertRemoteSegment(value: string): boolean; +/** + * A lookup policy rejection whose typed payload belongs to the active boundary adapter. + * Gateway adapters preserve this payload instead of collapsing it into an infrastructure failure. + */ +export declare class TypertLookupFailure extends Error { + /** Adapter-owned failure returned to the caller. */ + readonly failure: Failure; + /** + * Wrap one adapter failure without exposing the rejected identity. + * @param failure - typed failure owned by the active boundary adapter. + */ + constructor(failure: Failure); +} +export type { InvocationDescriptor, InvocationParameterDescriptor, InvocationSourceLocation, RemoteFailure, RemoteResult, TypertClientRemote, TypertClientContextBinder, TypertCodec, TypertContext, TypertContextMap, TypertContextRegistry, TypertContextWire, TypertDisposer, TypertForwardableEvent, TypertHostContextProvider, TypertHostContextResolver, TypertLocalRegistry, TypertLookup, TypertLookupDefinition, TypertLookupHost, TypertLookupMap, TypertLookupProvider, TypertLookupResolver, TypertLookupRegistry, TypertLookupWire, TypertRemoteScopeApi, TypertRemoteScopeMap, TypertRemoteScopeNamespace, TypertRemoteContribution, TypertRemoteEvent, TypertRemoteEventSelection, TypertRemoteMap, TypertRemoteNamespace, TypertRemoteNamespaceMap, TypertRemoteRegistry, TypertRegistryChange, TypertRegistryListener, TypertSchema, TypertRegistryContract, } from './types.ts'; +/** Options for an explicit Service-to-Gateway binding. */ +export interface TypertGatewayBindingOptions { + /** Wire namespace; defaults to the Cordis service key. */ + readonly namespace?: string; +} +/** Visible declaration that one Service participates in Typert Gateway export. */ +export interface TypertGatewayBinding { + readonly service: Service; + readonly serviceKey: string; + readonly namespace: string; +} +/** Invocation mode recorded by a Remote method decorator. */ +export type RemoteInvocationMarker = { + readonly kind: 'direct'; +} | { + readonly kind: 'context'; + readonly context: string; +}; +/** One decorator marker discovered for a live Service instance. */ +export interface RemoteMethodMarker { + /** Public instance method carrying the implementation. */ + readonly method: string; + /** Endpoint method when it differs from the implementation member. */ + readonly exportName?: string; + readonly invocation: RemoteInvocationMarker; +} +type RemoteMethodDecorator = (method: (this: This, ...args: Args) => Result, context: ClassMethodDecoratorContext Result>) => void; +/** + * Bind one visible Service field to a Cordis key and Remote namespace. + * @param service - owning Service instance, normally `this`. + * @param serviceKey - exact Cordis service key. + * @param options - optional distinct wire namespace. + * @returns a frozen, inspectable binding with no compiler-injected metadata. + */ +export declare function bindTypertRemote(service: Service, serviceKey: string, options?: TypertGatewayBindingOptions): TypertGatewayBinding; +/** Cordis Service base that exposes its registered name through Typert Gateway. */ +export declare abstract class TypertRemoteService extends Service { + /** Visible binding consumed by the Gateway's source-mode discovery. */ + readonly typertRemote: TypertGatewayBinding; + /** + * Register the Service and bind the same key to Typert Gateway. + * @param ctx - owning Cordis Context. + * @param serviceKey - exact Cordis service key and default wire namespace. + * @param options - optional distinct wire namespace. + */ + protected constructor(ctx: Context, serviceKey: string, options?: TypertGatewayBindingOptions); +} +/** + * Mark one public instance method as a direct Remote invocation. + * @param _method - decorated method; retained only by the class itself. + * @param context - standard decorator context used to schedule private marking. + */ +export declare function Remote(_method: (this: This, ...args: Args) => Result, context: ClassMethodDecoratorContext Result>): void; +/** + * Mark one public instance method under a distinct exported method name. + * @param exportName - Remote endpoint method, without a namespace or slash. + * @returns a standard method decorator. + */ +export declare function Remote(exportName: string): RemoteMethodDecorator; +/** + * Create a decorator for a method resolved from one Remote Scope. + * @param key - scope key declared through the Context map. + * @param exportName - optional Remote export name; defaults to the method name. + * @returns a standard method decorator that records only private module state. + */ +export declare function RemoteScope(key: Extract, exportName?: string): RemoteMethodDecorator; +/** + * Read Remote markers attached to a live Service by decorator initializers. + * The returned snapshot cannot mutate the private marker table. + * @param service - live Service instance. + * @returns markers in class declaration order. + */ +export declare function remoteMethods(service: object): readonly RemoteMethodMarker[]; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.js new file mode 100644 index 0000000..7da4fb7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/index.js @@ -0,0 +1,139 @@ +/** + * Remote decorators and explicit Gateway bindings backed only by private + * module state. Strict reflection remains a Typert compiler responsibility. + * @module @deepseek-ai/dsh-typert-protocol + */ +import { Service } from '@deepseek-ai/cordis'; +const TYPERT_REMOTE_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/; +/** + * Test one generated Remote name against the Connection endpoint grammar. + * @param value - namespace, method, lookup, or Context segment. + * @returns whether the value can cross the shared RPC carrier unchanged. + */ +export function isTypertRemoteSegment(value) { + return value !== '.' && value !== '..' && TYPERT_REMOTE_SEGMENT_PATTERN.test(value); +} +/** + * A lookup policy rejection whose typed payload belongs to the active boundary adapter. + * Gateway adapters preserve this payload instead of collapsing it into an infrastructure failure. + */ +export class TypertLookupFailure extends Error { + /** Adapter-owned failure returned to the caller. */ + failure; + /** + * Wrap one adapter failure without exposing the rejected identity. + * @param failure - typed failure owned by the active boundary adapter. + */ + constructor(failure) { + super('Typert lookup policy rejected the requested identity'); + this.name = 'TypertLookupFailure'; + this.failure = failure; + } +} +const markers = new WeakMap(); +/** + * Bind one visible Service field to a Cordis key and Remote namespace. + * @param service - owning Service instance, normally `this`. + * @param serviceKey - exact Cordis service key. + * @param options - optional distinct wire namespace. + * @returns a frozen, inspectable binding with no compiler-injected metadata. + */ +export function bindTypertRemote(service, serviceKey, options = {}) { + validateName('service key', serviceKey); + const namespace = options.namespace ?? serviceKey; + validateName('namespace', namespace); + return Object.freeze({ service, serviceKey, namespace }); +} +/** Cordis Service base that exposes its registered name through Typert Gateway. */ +export class TypertRemoteService extends Service { + /** Visible binding consumed by the Gateway's source-mode discovery. */ + typertRemote; + /** + * Register the Service and bind the same key to Typert Gateway. + * @param ctx - owning Cordis Context. + * @param serviceKey - exact Cordis service key and default wire namespace. + * @param options - optional distinct wire namespace. + */ + constructor(ctx, serviceKey, options = {}) { + super(ctx, serviceKey); + this.typertRemote = bindTypertRemote(this, this.name, options); + } +} +export function Remote(methodOrExportName, context) { + if (typeof methodOrExportName === 'string') { + validateName('Remote export name', methodOrExportName); + return function (_method, decoratorContext) { + addMarkerInitializer(decoratorContext, { kind: 'direct' }, methodOrExportName); + }; + } + if (context === undefined) + throw new TypeError('typert-protocol: Remote decorator context is missing'); + addMarkerInitializer(context, { kind: 'direct' }); +} +/** + * Create a decorator for a method resolved from one Remote Scope. + * @param key - scope key declared through the Context map. + * @param exportName - optional Remote export name; defaults to the method name. + * @returns a standard method decorator that records only private module state. + */ +export function RemoteScope(key, exportName) { + validateName('Scope key', key); + if (exportName !== undefined) + validateName('Remote export name', exportName); + return function (_method, context) { + addMarkerInitializer(context, { kind: 'context', context: key }, exportName); + }; +} +/** + * Read Remote markers attached to a live Service by decorator initializers. + * The returned snapshot cannot mutate the private marker table. + * @param service - live Service instance. + * @returns markers in class declaration order. + */ +export function remoteMethods(service) { + const prototype = Object.getPrototypeOf(service); + if (prototype === null) + return []; + return [...(markers.get(prototype) ?? [])].map(([method, marker]) => ({ method, ...marker })); +} +function addMarkerInitializer(context, invocation, exportName) { + if (context.private || context.static || typeof context.name !== 'string') { + throw new TypeError('typert-protocol: Remote decorators require a public instance method with a string name'); + } + const method = context.name; + context.addInitializer(function () { + const prototype = Object.getPrototypeOf(this); + if (prototype === null) { + throw new TypeError(`typert-protocol: cannot mark Remote method "${method}" on an object without a prototype`); + } + mark(prototype, method, invocation, exportName); + }); +} +function mark(prototype, method, invocation, exportName) { + let table = markers.get(prototype); + if (table === undefined) { + table = new Map(); + markers.set(prototype, table); + } + const marker = { + ...(exportName === undefined || exportName === method ? {} : { exportName }), + invocation: Object.freeze(invocation), + }; + const current = table.get(method); + if (current !== undefined) { + if (current.exportName === marker.exportName && sameInvocation(current.invocation, invocation)) + return; + throw new Error(`typert-protocol: Remote method "${method}" has conflicting invocation markers`); + } + table.set(method, Object.freeze(marker)); +} +function sameInvocation(left, right) { + return left.kind === right.kind + && (left.kind === 'direct' || (right.kind === 'context' && left.context === right.context)); +} +function validateName(subject, value) { + if (!isTypertRemoteSegment(value)) { + throw new TypeError(`typert-protocol: ${subject} must contain only RPC endpoint segment characters`); + } +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.d.ts new file mode 100644 index 0000000..8349620 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-typert-protocol`. + * @module @deepseek-ai/dsh-typert-protocol/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "typert-protocol-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.js new file mode 100644 index 0000000..f2db7ae --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/invariant.js @@ -0,0 +1,22 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-typert-protocol`. + * @module @deepseek-ai/dsh-typert-protocol/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-typert-protocol'; +/** Cordis companion plugin name. */ +export const name = 'typert-protocol-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: decorators retain private immutable declarations and + * bindings are frozen values with no independent event stream to cross-check. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.d.ts new file mode 100644 index 0000000..cf2e664 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.d.ts @@ -0,0 +1,419 @@ +/** + * Compiler-independent Typert protocol shared by business packages, generated + * Remote artifacts, the Host Gateway, and Client API implementations. + * @module @deepseek-ai/dsh-typert-protocol/types + */ +import type { Context, Events } from '@deepseek-ai/cordis'; +declare const LOOKUP_HOST: unique symbol; +declare const LOOKUP_WIRE: unique symbol; +declare const CONTEXT_WIRE: unique symbol; +/** Type-level association between a Host object and its wire identity. */ +export interface TypertLookup { + readonly [LOOKUP_HOST]: Host; + readonly [LOOKUP_WIRE]: Wire; +} +/** Extract the Host object associated with one lookup declaration. */ +export type TypertLookupHost = Lookup extends TypertLookup ? Host : never; +/** Extract the wire identity associated with one lookup declaration. */ +export type TypertLookupWire = Lookup extends TypertLookup ? Wire : never; +/** Type-level association between a scoped Context kind and its wire identity. */ +export interface TypertContext { + readonly [CONTEXT_WIRE]: Wire; +} +/** Extract the wire identity associated with one scoped Context declaration. */ +export type TypertContextWire = ContextType extends TypertContext ? Wire : never; +/** Merge-extensible Host object lookup declarations. */ +export interface TypertLookupMap { +} +/** Merge-extensible scoped Context declarations. */ +export interface TypertContextMap { +} +/** Merge-extensible direct Remote method signatures generated for consumers. */ +export interface TypertRemoteMap { +} +/** + * One Remote call's failure as the carrier reported it. `code` stays open here: + * the closed RPC code union belongs to the carrier package, which already + * depends on this one, so naming it would invert that edge. + */ +export interface RemoteFailure { + readonly code: string; + readonly message: string; + readonly details: object; +} +/** + * What every generated Remote method resolves to. The Remote face itself folds + * carrier failures into the error branch, so no consumer wraps a call to + * recover one; only assembly faults (arity, an unmounted method, a missing + * Context binder) still reject. + * @template T - the Host method's business result. + */ +export type RemoteResult = { + readonly ok: true; + readonly value: T; +} | { + readonly ok: false; + readonly error: RemoteFailure; +}; +/** Merge-extensible scoped Remote method signatures generated for consumers. */ +export interface TypertRemoteScopeMap { +} +/** + * Cordis event names whose shape a one-way Remote delivery can carry: unbound + * from any Scope and returning `void`. Which ones are actually forwarded is the + * Host assembly's selection; this predicate only excludes shapes the carrier + * cannot represent. + */ +export type TypertForwardableEvent = { + [Event in keyof Events]: unknown extends ThisParameterType ? ReturnType extends void ? Event : never : never; +}[keyof Events]; +/** Merge-extensible forwarding selection declared once by the Host assembly. */ +export interface TypertRemoteEventSelection { +} +/** Legal `$on` keys: selected events that exist in the current compilation face. */ +export type TypertRemoteEvent = Extract; +/** + * Resolve one direct Remote namespace from the generated flat endpoint map. + * @template Namespace - wire namespace before the endpoint slash. + */ +export type TypertRemoteNamespace = { + [Endpoint in keyof TypertRemoteMap as Endpoint extends `${Namespace}/${infer Method}` ? Method : never]: TypertRemoteMap[Endpoint]; +}; +/** + * Resolve one scoped Remote namespace across every generated Context kind. + * The calling Cordis Context supplies the concrete identity at runtime. + * @template Namespace - wire namespace between the Context prefix and method. + */ +export type TypertRemoteScopeNamespace = { + [Endpoint in keyof TypertRemoteScopeMap as Endpoint extends `${ContextKey}:${Namespace}/${infer Method}` ? Method : never]: TypertRemoteScopeMap[Endpoint]; +}; +type TypertRemoteScopeNamespaceKey = Endpoint extends `${ContextKey}:${infer Namespace}/${string}` ? Namespace : never; +/** Generated scoped Remote namespaces available to one Context kind. */ +export type TypertRemoteScopeApi = { + [Namespace in TypertRemoteScopeNamespaceKey]: TypertRemoteScopeNamespace; +}; +/** Merge-extensible direct namespace surface generated for Client Remote services. */ +export interface TypertRemoteNamespaceMap { +} +/** Awaitable disposer returned by Cordis-owned Typert registrations. */ +export type TypertDisposer = () => Promise; +type StringKeyOf = Extract; +/** Minimal runtime-schema capability carried by strict generated codecs. */ +export interface TypertSchema { + /** + * Parse and validate one boundary value. + * @param value - untrusted boundary value. + * @returns the validated value. + */ + parse(value: unknown): Output; +} +/** Codec attached to one invocation parameter or result. */ +export type TypertCodec = { + readonly mode: 'strict'; + readonly typeSymbol: string; + readonly schema: TypertSchema; +} | { + readonly mode: 'src-json'; +}; +/** One ordered business parameter in a Remote invocation. */ +export interface InvocationParameterDescriptor { + /** Source-level parameter name. */ + readonly name: string; + /** Required key in the wire `args` object. */ + readonly wire: string; + /** Whether the value is JSON or requires a registered Host lookup. */ + readonly source: 'json' | 'lookup'; + /** Lookup key when `source` is `lookup`. */ + readonly lookup?: string; + /** Boundary codec for the wire representation. */ + readonly codec: TypertCodec; + /** Missing wire fields decode to `undefined` only for an explicitly declared `T | undefined`. */ + readonly acceptsUndefined?: true; +} +/** Source position retained for diagnostics from generated definitions. */ +export interface InvocationSourceLocation { + readonly file: string; + readonly line: number; + readonly column: number; +} +/** Carrier-independent description of one exported method invocation. */ +export interface InvocationDescriptor { + /** Globally stable generated identity. */ + readonly id: string; + /** Cordis service key owning the method. */ + readonly service: string; + /** Wire namespace, defaulting to the service key. */ + readonly namespace: string; + /** Public instance method name. */ + readonly method: string; + /** Service member invoked when the exported method name is an alias. */ + readonly implementation?: string; + /** Receiver selection mode. */ + readonly invocation: { + readonly kind: 'direct'; + } | { + readonly kind: 'context'; + readonly context: string; + readonly wire: string; + readonly codec: TypertCodec; + }; + /** Optional consuming-Context projection for one direct lookup parameter. */ + readonly scope?: { + /** Context kind whose Client binder supplies the identity. */ + readonly context: string; + /** Lookup parameter wire field replaced by the Context identity. */ + readonly wire: string; + }; + /** Ordered business parameters. */ + readonly parameters: readonly InvocationParameterDescriptor[]; + /** Transport cancellation injected after business parameters instead of entering wire args. */ + readonly cancellation?: { + /** Reserved final Host method parameter. */ + readonly parameter: 'signal'; + }; + /** Codec for the resolved method result. */ + readonly result: TypertCodec; + /** Source declaration used only for diagnostics. */ + readonly sourceLocation?: InvocationSourceLocation; +} +/** Generated Host contract selected explicitly by a Client assembly. */ +export interface TypertRemoteContribution { + /** npm package that owns the Remote methods. */ + readonly package: string; + /** Consumer-side invocation descriptors generated from that package. */ + readonly descriptors: readonly InvocationDescriptor[]; +} +/** Client Remote capability implemented by the Gateway and consumed by Remote assemblies. */ +export interface TypertClientRemote extends TypertRemoteNamespaceMap { + /** + * Mount one generated Host-for-Client contribution in the caller's fiber. + * @param contribution - explicitly selected Remote package artifact. + * @returns disposer after namespace services and concrete methods are ready. + */ + $mount(contribution: TypertRemoteContribution): Promise; + /** + * Subscribe to one forwarded Host event; delivery is one-way, in registration + * order, and isolates a throwing listener from the rest. + * @template Event - forwarded event name selected by the Host assembly. + * @param event - forwarded Host event name, unchanged on the wire. + * @param listener - receives the Host's argument list as declared by Cordis `Events`. + * @returns disposer owned by the calling fiber. + */ + $on(event: Event, listener: Events[Event]): () => void; + /** + * Hand one decoded forwarded frame to the subscription table. The carrier + * owning the Host frame sink calls this; a consumer subscribes with + * {@link TypertClientRemote.$on} and never calls it. + * + * `event` is a plain string because this is the wire boundary: the name is + * whatever the Host assembly's allowlist selected, and one nobody subscribed + * to is dropped silently. + * @param event - forwarded Host event name, exactly as the Host emitted it. + * @param args - the Host argument list, already JSON-decoded. + */ + $dispatch(event: string, args: readonly unknown[]): void; +} +/** + * Resolve one validated wire identity, synchronously or asynchronously. + * @param id - validated wire identity. + * @returns the Host object, or `undefined` when unavailable. + */ +export type TypertLookupResolver = (id: Wire) => Host | undefined | Promise; +/** Runtime provider for one declared Host object lookup. */ +export interface TypertLookupProvider { + /** Source parameter name recognized by the SRC weak parser. */ + readonly parameter: string; + /** Wire field replacing the Host object parameter. */ + readonly wire: string; + /** Canonical Host type symbol used by strict generation. */ + readonly hostTypeSymbol: string; + /** Canonical wire type symbol used by strict generation. */ + readonly wireTypeSymbol: string; + /** + * Resolve a wire identity through the provider's default policy. + * @param id - validated wire identity. + * @returns the object, `undefined` when unavailable, or either asynchronously. + */ + resolve(id: Wire): Host | undefined | Promise; +} +/** Stable wire declaration retained after a lookup provider unloads. */ +export interface TypertLookupDefinition { + /** Merge-declared lookup key. */ + readonly key: string; + /** Source parameter name recognized by the SRC weak parser. */ + readonly parameter: string; + /** Wire field replacing the Host object parameter. */ + readonly wire: string; + /** Canonical Host type symbol used by strict generation. */ + readonly hostTypeSymbol: string; + /** Canonical wire type symbol used by strict generation. */ + readonly wireTypeSymbol: string; +} +/** Host resolver for one scoped Remote kind. */ +export interface TypertHostContextProvider { + /** Wire field carrying the Context identity. */ + readonly wire: string; + /** Canonical wire type symbol used by strict generation. */ + readonly wireTypeSymbol: string; + /** + * Resolve a wire identity to its live scoped Context. + * @param id - validated wire identity. + * @returns the scoped Context, or `undefined` when unavailable. + */ + resolve(id: Wire): Context | undefined | Promise; +} +/** Composition-owned resolver replacing one Host Context provider's default lookup policy. */ +export type TypertHostContextResolver = (id: Wire) => Context | undefined | Promise; +/** Client resolver for the identity carried by the calling scoped Context. */ +export interface TypertClientContextBinder { + /** + * Read the Remote identity represented by a calling Context. + * @param ctx - Context rebound by the Cordis service tracker. + * @returns the wire identity, or `undefined` when the Context has the wrong scope. + */ + identity(ctx: Context): Wire | undefined; +} +/** Notification emitted after a Typert runtime registry changes. */ +export interface TypertRegistryChange { + readonly kind: 'local' | 'remote' | 'lookup' | 'host-context' | 'client-context'; + readonly key: string; +} +/** Listener for one Typert runtime registry. */ +export type TypertRegistryListener = (change: TypertRegistryChange) => void; +/** Current-environment invocation definitions. */ +export interface TypertLocalRegistry { + /** + * Look up one invocation by `/`. + * @param endpoint - canonical endpoint. + * @returns the live descriptor, or `undefined` when absent. + */ + get(endpoint: string): InvocationDescriptor | undefined; + /** + * Report whether a strict definition has existed during this Typert Service lifetime. + * @param endpoint - canonical endpoint. + * @returns `true` after the endpoint has been registered at least once, even if withdrawn. + */ + hasSeen(endpoint: string): boolean; + /** @returns a registration-order snapshot of local descriptors. */ + list(): readonly InvocationDescriptor[]; + /** + * Observe later local-definition changes. + * @param listener - synchronous contained observer. + * @returns disposer for this subscription. + */ + subscribe(listener: TypertRegistryListener): TypertDisposer; +} +/** Consumer-selected Remote contribution registry. */ +export interface TypertRemoteRegistry { + /** + * Register one generated contribution for the calling Cordis fiber. + * @param contribution - generated Remote descriptors. + * @returns disposer withdrawing the exact contribution. + */ + register(contribution: TypertRemoteContribution): TypertDisposer; + /** + * Look up one Remote descriptor by endpoint. + * @param endpoint - canonical endpoint. + * @returns the descriptor, or `undefined` when unmounted. + */ + get(endpoint: string): InvocationDescriptor | undefined; + /** @returns a registration-order snapshot of Remote descriptors. */ + list(): readonly InvocationDescriptor[]; + /** + * Observe later Remote contribution changes. + * @param listener - synchronous contained observer. + * @returns disposer for this subscription. + */ + subscribe(listener: TypertRegistryListener): TypertDisposer; +} +/** Runtime registry for Host object lookup providers. */ +export interface TypertLookupRegistry { + /** + * Register one provider under its merge-declared key. + * @param key - lookup key. + * @param provider - owning package's live resolver. + * @returns disposer withdrawing the exact provider. + */ + register>(key: K, provider: TypertLookupProvider, TypertLookupWire>): TypertDisposer; + /** + * Replace one provider's default resolution policy while this contribution is active. + * Configuration may precede provider registration; without a live provider, `get()` remains unavailable. + * @param key - lookup key whose wire declaration remains provider-owned. + * @param resolver - composition-owned resolver used by every lookup of this key. + * @returns disposer restoring the provider's default resolver. + */ + configure>(key: K, resolver: TypertLookupResolver, TypertLookupWire>): TypertDisposer; + /** + * Look up one provider by runtime key. + * @param key - descriptor lookup key. + * @returns the live provider, or `undefined` when absent. + */ + get(key: string): TypertLookupProvider | undefined; + /** @returns lookup declarations observed during this Typert Service lifetime. */ + definitions(): readonly TypertLookupDefinition[]; + /** @returns a snapshot of registered provider keys. */ + keys(): readonly string[]; + /** + * Observe later lookup changes. + * @param listener - synchronous contained observer. + * @returns disposer for this subscription. + */ + subscribe(listener: TypertRegistryListener): TypertDisposer; +} +/** Runtime registry for Host Context resolvers and Client Context binders. */ +export interface TypertContextRegistry { + /** + * Register a Host Context resolver. + * @param key - merge-declared Context key. + * @param provider - owning package's Host resolver. + * @returns disposer withdrawing the exact provider. + */ + registerHost>(key: K, provider: TypertHostContextProvider>): TypertDisposer; + /** + * Override one Host Context key's identity policy for the calling fiber. + * Configuration may precede provider registration and restores the provider's default resolver on disposal. + * @param key - merge-declared Context key. + * @param resolver - composition-owned resolver used by every Host Context lookup of this key. + * @returns disposer restoring the provider's default resolver. + */ + configureHost>(key: K, resolver: TypertHostContextResolver>): TypertDisposer; + /** + * Register a Client Context identity binder. + * @param key - merge-declared Context key. + * @param binder - Client scope identity resolver. + * @returns disposer withdrawing the exact binder. + */ + registerClient>(key: K, binder: TypertClientContextBinder>): TypertDisposer; + /** + * Look up a Host Context resolver. + * @param key - descriptor Context key. + * @returns the provider, or `undefined` when absent. + */ + getHost(key: string): TypertHostContextProvider | undefined; + /** + * Look up a Client Context binder. + * @param key - descriptor Context key. + * @returns the binder, or `undefined` when absent. + */ + getClient(key: string): TypertClientContextBinder | undefined; + /** + * Observe later Context provider changes. + * @param listener - synchronous contained observer. + * @returns disposer for this subscription. + */ + subscribe(listener: TypertRegistryListener): TypertDisposer; +} +/** Minimal Typert runtime consumed through dependency inversion. */ +export interface TypertRegistryContract { + readonly local: TypertLocalRegistry; + readonly remotes: TypertRemoteRegistry; + readonly lookups: TypertLookupRegistry; + readonly contexts: TypertContextRegistry; +} +declare module '@deepseek-ai/cordis' { + interface Context { + typert: TypertRegistryContract; + } +} +export {}; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.js new file mode 100644 index 0000000..69b9894 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Compiler-independent Typert protocol shared by business packages, generated + * Remote artifacts, the Host Gateway, and Client API implementations. + * @module @deepseek-ai/dsh-typert-protocol/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/package.json new file mode 100644 index 0000000..fc66add --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol/package.json @@ -0,0 +1,47 @@ +{ + "name": "@deepseek-ai/dsh-typert-protocol", + "description": "Compiler-independent Remote metadata and Typert provider protocols", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/typert/protocol" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..aa2ae83 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ee0216bcd98c4ea06ecb5223639c3e04/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.i18n.yaml new file mode 100644 index 0000000..5730472 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/typert/registry/README.md +README.md: fa227b1c8faf1abd5a6492d4b8fe7d0c51ceeef1 +README.zh.md: b708e536acb7a5c4dc47e8c83180728e2ce150cd diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.md new file mode 100644 index 0000000..fa227b1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.md @@ -0,0 +1,33 @@ +# @deepseek-ai/dsh-typert-registry + +English | [中文](README.zh.md) + +Runtime registry for generated Typert artifacts. A contribution carries one package face's business reflection and optional live Zod schemas; `ctx.typert` registers both atomically and withdraws them with the calling Cordis fiber. TypeScript analysis and code generation live in [`dsh-typert-generator`](../generator/README.md). + +Package reflection is keyed by `#`. Schemas are keyed by `#` and retain the producer's Zod instance. JSON Schema is computed on demand at the consumer edge. + +## Public API + +- `TypertRegistry` is the default plugin and provides `ctx.typert`. +- `ctx.typert.lookups.register()` registers the wire declaration and default resolver owned by the business package; `configure()` registers a resolver owned by Host composition that may run asynchronously. Their lifetimes are independent: configuration may precede the provider, and unloading the configuration restores the default policy. +- `ctx.typert.contexts.registerHost()` and `configureHost()` apply the same ownership split to scoped Context identity; `registerClient()` supplies the corresponding Client Context binder. +- `register(contribution)` rejects malformed identities and duplicate package-face or schema keys before committing anything, then returns the exact Cordis effect disposer. +- `get(key)`, `resolve(key)`, and `list(filter?)` query live schemas. `resolve()` distinguishes a malformed key, an absent package, and a package that contributes no schema under that name. +- `getPackage(packageName, face?)` and `listPackages(filter?)` query generated service, event, and object reflection; the default face is `host`. +- `toJSONSchema(key, params?)` projects a live schema with `z.toJSONSchema()` without caching the result. +- `typertKey()` and `typertPackageKey()` compose the two stable identity forms. + +The `@deepseek-ai/dsh-typert-registry/types` subpath contains the pure contribution and record contracts. [`dsh-typert-loader`](../loader/README.md) discovers and registers generated host artifacts in Loader compositions; direct `ctx.typert.register()` supports other composition owners. + +## Model Experience + +None, as the registry contributes no prompt, tool, or session event; consumers such as `cordis_inspect` own any model-visible projection. + +#### KV Cache effect + +No direct effect. A consumer that places reflection in a request owns the resulting prefix change. + +## Known Limitations and Deferred Work + +- The registry stores generated reflection but does not merge host and client graphs or resolve TypeScript references. Those are analyzer and emitter concerns. +- Schema keys omit the face because host and client run in separate contexts. Registering same-named schemas from both faces into one context is rejected as a duplicate. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.zh.md new file mode 100644 index 0000000..b708e53 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/README.zh.md @@ -0,0 +1,33 @@ +# @deepseek-ai/dsh-typert-registry + +[English](README.md) | 中文 + +生成的 Typert 产物所用的运行时注册表。每个注册项包含某个包在一个 face 上的业务反射信息,以及可选的运行时 Zod schema;`ctx.typert` 会以原子方式同时注册两者,并在发起调用的 Cordis fiber 释放时一并移除它们。TypeScript 分析和代码生成由 [`dsh-typert-generator`](../generator/README.md) 负责。 + +包反射信息以 `#` 为键。schema 以 `#` 为键,并保留生成方的 Zod 实例。系统按需在消费方边界计算 JSON Schema。 + +## 公开 API + +- `TypertRegistry` 是默认插件,并提供 `ctx.typert`。 +- `ctx.typert.lookups.register()` 注册由业务包拥有的协议声明和默认解析器;`configure()` 注册由宿主组合拥有且可异步执行的解析器。两者的生命周期相互独立:配置可以先于提供方注册,卸载配置会恢复默认策略。 +- `ctx.typert.contexts.registerHost()` 和 `configureHost()` 对具作用域的上下文身份采用同样的所有权划分;`registerClient()` 提供对应的客户端上下文绑定器。 +- `register(contribution)` 会在提交任何内容之前拒绝格式错误的标识,以及重复的包与 face 组合键或 schema 键,随后返回 Cordis effect 提供的同一资源释放函数。 +- `get(key)`、`resolve(key)` 和 `list(filter?)` 查询当前有效的 schema。`resolve()` 能区分格式错误的键、未注册的包,以及已注册但未以该名称提供 schema 的包。 +- `getPackage(packageName, face?)` 和 `listPackages(filter?)` 查询生成的服务、事件和对象反射信息;默认 face 为 `host`。 +- `toJSONSchema(key, params?)` 使用 `z.toJSONSchema()` 投影当前有效的 schema,且不缓存结果。 +- `typertKey()` 和 `typertPackageKey()` 构造两种稳定的标识形式。 + +`@deepseek-ai/dsh-typert-registry/types` 子路径包含注册项和记录的纯类型约定。[`dsh-typert-loader`](../loader/README.md) 会在 Loader 组合中发现并注册生成的宿主侧产物;其他组合所有者可以直接调用 `ctx.typert.register()`。 + +## 模型体验 + +无。注册表不会提供提示词、工具或会话事件;所有模型可见投影均由 `cordis_inspect` 等消费方负责。 + +#### KV Cache 影响 + +无直接影响。将反射信息放入请求的消费方负责由此产生的前缀变化。 + +## 已知限制与暂缓事项 + +- 注册表存储生成的反射信息,但不会合并宿主侧与客户端侧的图,也不会解析 TypeScript 引用;这些由分析器和产物输出器负责。 +- schema 键不包含 face,因为宿主侧和客户端侧在不同的上下文中运行。若在同一上下文中注册来自两个 face 的同名 schema,系统会将其作为重复项拒绝。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/client.js new file mode 100644 index 0000000..c2a30e3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/client.js @@ -0,0 +1,1372 @@ +window.__ModuleLoader__.load({ + id: "@deepseek-ai/dsh-typert-registry", + factory: (require) => { + var module = { exports: {} }; + var exports = module.exports; + Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); + let _deepseek_ai_cordis = require("@deepseek-ai/cordis"); + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.js + function getEnumValues(entries) { + const numericValues = Object.values(entries).filter((v) => typeof v === "number"); + return Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v); + } + "captureStackTrace" in Error && Error.captureStackTrace; + Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, -Number.MAX_VALUE, Number.MAX_VALUE; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.js + var _a; + var $ZodRegistry = class { + constructor() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + } + add(schema, ..._meta) { + const meta = _meta[0]; + this._map.set(schema, meta); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.set(meta.id, schema); + return this; + } + clear() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + return this; + } + remove(schema) { + const meta = this._map.get(schema); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.delete(meta.id); + this._map.delete(schema); + return this; + } + get(schema) { + const p = schema._zod.parent; + if (p) { + const pm = { ...this.get(p) ?? {} }; + delete pm.id; + const f = { + ...pm, + ...this._map.get(schema) + }; + return Object.keys(f).length ? f : void 0; + } + return this._map.get(schema); + } + has(schema) { + return this._map.has(schema); + } + }; + function registry() { + return new $ZodRegistry(); + } + (_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry()); + const globalRegistry = globalThis.__zod_globalRegistry; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.js + function initializeContext(params) { + let target = params?.target ?? "draft-2020-12"; + if (target === "draft-4") target = "draft-04"; + if (target === "draft-7") target = "draft-07"; + return { + processors: params.processors ?? {}, + metadataRegistry: params?.metadata ?? globalRegistry, + target, + unrepresentable: params?.unrepresentable ?? "throw", + override: params?.override ?? (() => {}), + io: params?.io ?? "output", + counter: 0, + seen: /* @__PURE__ */ new Map(), + cycles: params?.cycles ?? "ref", + reused: params?.reused ?? "inline", + external: params?.external ?? void 0 + }; + } + function process(schema, ctx, _params = { + path: [], + schemaPath: [] + }) { + var _a; + const def = schema._zod.def; + const seen = ctx.seen.get(schema); + if (seen) { + seen.count++; + if (_params.schemaPath.includes(schema)) seen.cycle = _params.path; + return seen.schema; + } + const result = { + schema: {}, + count: 1, + cycle: void 0, + path: _params.path + }; + ctx.seen.set(schema, result); + const overrideSchema = schema._zod.toJSONSchema?.(); + if (overrideSchema) result.schema = overrideSchema; + else { + const params = { + ..._params, + schemaPath: [..._params.schemaPath, schema], + path: _params.path + }; + if (schema._zod.processJSONSchema) schema._zod.processJSONSchema(ctx, result.schema, params); + else { + const _json = result.schema; + const processor = ctx.processors[def.type]; + if (!processor) throw new Error(`[toJSONSchema]: Non-representable type encountered: ${def.type}`); + processor(schema, ctx, _json, params); + } + const parent = schema._zod.parent; + if (parent) { + if (!result.ref) result.ref = parent; + process(parent, ctx, params); + ctx.seen.get(parent).isParent = true; + } + } + const meta = ctx.metadataRegistry.get(schema); + if (meta) Object.assign(result.schema, meta); + if (ctx.io === "input" && isTransforming(schema)) { + delete result.schema.examples; + delete result.schema.default; + } + if (ctx.io === "input" && "_prefault" in result.schema) (_a = result.schema).default ?? (_a.default = result.schema._prefault); + delete result.schema._prefault; + return ctx.seen.get(schema).schema; + } + function extractDefs(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const idToSchema = /* @__PURE__ */ new Map(); + for (const entry of ctx.seen.entries()) { + const id = ctx.metadataRegistry.get(entry[0])?.id; + if (id) { + const existing = idToSchema.get(id); + if (existing && existing !== entry[0]) throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`); + idToSchema.set(id, entry[0]); + } + } + const makeURI = (entry) => { + const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions"; + if (ctx.external) { + const externalId = ctx.external.registry.get(entry[0])?.id; + const uriGenerator = ctx.external.uri ?? ((id) => id); + if (externalId) return { ref: uriGenerator(externalId) }; + const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`; + entry[1].defId = id; + return { + defId: id, + ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` + }; + } + if (entry[1] === root) return { ref: "#" }; + const defUriPrefix = `#/${defsSegment}/`; + const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`; + return { + defId, + ref: defUriPrefix + defId + }; + }; + const extractToDef = (entry) => { + if (entry[1].schema.$ref) return; + const seen = entry[1]; + const { ref, defId } = makeURI(entry); + seen.def = { ...seen.schema }; + if (defId) seen.defId = defId; + const schema = seen.schema; + for (const key in schema) delete schema[key]; + schema.$ref = ref; + }; + if (ctx.cycles === "throw") for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.cycle) throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/ + +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`); + } + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (schema === entry[0]) { + extractToDef(entry); + continue; + } + if (ctx.external) { + const ext = ctx.external.registry.get(entry[0])?.id; + if (schema !== entry[0] && ext) { + extractToDef(entry); + continue; + } + } + if (ctx.metadataRegistry.get(entry[0])?.id) { + extractToDef(entry); + continue; + } + if (seen.cycle) { + extractToDef(entry); + continue; + } + if (seen.count > 1) { + if (ctx.reused === "ref") { + extractToDef(entry); + continue; + } + } + } + } + function finalize(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const flattenRef = (zodSchema) => { + const seen = ctx.seen.get(zodSchema); + if (seen.ref === null) return; + const schema = seen.def ?? seen.schema; + const _cached = { ...schema }; + const ref = seen.ref; + seen.ref = null; + if (ref) { + flattenRef(ref); + const refSeen = ctx.seen.get(ref); + const refSchema = refSeen.schema; + if (refSchema.$ref && (ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0")) { + schema.allOf = schema.allOf ?? []; + schema.allOf.push(refSchema); + } else Object.assign(schema, refSchema); + Object.assign(schema, _cached); + if (zodSchema._zod.parent === ref) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (!(key in _cached)) delete schema[key]; + } + if (refSchema.$ref && refSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in refSeen.def && JSON.stringify(schema[key]) === JSON.stringify(refSeen.def[key])) delete schema[key]; + } + } + const parent = zodSchema._zod.parent; + if (parent && parent !== ref) { + flattenRef(parent); + const parentSeen = ctx.seen.get(parent); + if (parentSeen?.schema.$ref) { + schema.$ref = parentSeen.schema.$ref; + if (parentSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in parentSeen.def && JSON.stringify(schema[key]) === JSON.stringify(parentSeen.def[key])) delete schema[key]; + } + } + } + ctx.override({ + zodSchema, + jsonSchema: schema, + path: seen.path ?? [] + }); + }; + for (const entry of [...ctx.seen.entries()].reverse()) flattenRef(entry[0]); + const result = {}; + if (ctx.target === "draft-2020-12") result.$schema = "https://json-schema.org/draft/2020-12/schema"; + else if (ctx.target === "draft-07") result.$schema = "http://json-schema.org/draft-07/schema#"; + else if (ctx.target === "draft-04") result.$schema = "http://json-schema.org/draft-04/schema#"; + else if (ctx.target === "openapi-3.0") {} + if (ctx.external?.uri) { + const id = ctx.external.registry.get(schema)?.id; + if (!id) throw new Error("Schema is missing an `id` property"); + result.$id = ctx.external.uri(id); + } + Object.assign(result, root.def ?? root.schema); + const rootMetaId = ctx.metadataRegistry.get(schema)?.id; + if (rootMetaId !== void 0 && result.id === rootMetaId) delete result.id; + const defs = ctx.external?.defs ?? {}; + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.def && seen.defId) { + if (seen.def.id === seen.defId) delete seen.def.id; + defs[seen.defId] = seen.def; + } + } + if (ctx.external) {} else if (Object.keys(defs).length > 0) if (ctx.target === "draft-2020-12") result.$defs = defs; + else result.definitions = defs; + try { + const finalized = JSON.parse(JSON.stringify(result)); + Object.defineProperty(finalized, "~standard", { + value: { + ...schema["~standard"], + jsonSchema: { + input: createStandardJSONSchemaMethod(schema, "input", ctx.processors), + output: createStandardJSONSchemaMethod(schema, "output", ctx.processors) + } + }, + enumerable: false, + writable: false + }); + return finalized; + } catch (_err) { + throw new Error("Error converting schema to JSON."); + } + } + function isTransforming(_schema, _ctx) { + const ctx = _ctx ?? { seen: /* @__PURE__ */ new Set() }; + if (ctx.seen.has(_schema)) return false; + ctx.seen.add(_schema); + const def = _schema._zod.def; + if (def.type === "transform") return true; + if (def.type === "array") return isTransforming(def.element, ctx); + if (def.type === "set") return isTransforming(def.valueType, ctx); + if (def.type === "lazy") return isTransforming(def.getter(), ctx); + if (def.type === "promise" || def.type === "optional" || def.type === "nonoptional" || def.type === "nullable" || def.type === "readonly" || def.type === "default" || def.type === "prefault") return isTransforming(def.innerType, ctx); + if (def.type === "intersection") return isTransforming(def.left, ctx) || isTransforming(def.right, ctx); + if (def.type === "record" || def.type === "map") return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); + if (def.type === "pipe") { + if (_schema._zod.traits.has("$ZodCodec")) return true; + return isTransforming(def.in, ctx) || isTransforming(def.out, ctx); + } + if (def.type === "object") { + for (const key in def.shape) if (isTransforming(def.shape[key], ctx)) return true; + return false; + } + if (def.type === "union") { + for (const option of def.options) if (isTransforming(option, ctx)) return true; + return false; + } + if (def.type === "tuple") { + for (const item of def.items) if (isTransforming(item, ctx)) return true; + if (def.rest && isTransforming(def.rest, ctx)) return true; + return false; + } + return false; + } + const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => { + const { libraryOptions, target } = params ?? {}; + const ctx = initializeContext({ + ...libraryOptions ?? {}, + target, + io, + processors + }); + process(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.js + const formatMap = { + guid: "uuid", + url: "uri", + datetime: "date-time", + json_string: "json-string", + regex: "" + }; + const stringProcessor = (schema, ctx, _json, _params) => { + const json = _json; + json.type = "string"; + const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag; + if (typeof minimum === "number") json.minLength = minimum; + if (typeof maximum === "number") json.maxLength = maximum; + if (format) { + json.format = formatMap[format] ?? format; + if (json.format === "") delete json.format; + if (format === "time") delete json.format; + } + if (contentEncoding) json.contentEncoding = contentEncoding; + if (patterns && patterns.size > 0) { + const regexes = [...patterns]; + if (regexes.length === 1) json.pattern = regexes[0].source; + else if (regexes.length > 1) json.allOf = [...regexes.map((regex) => ({ + ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {}, + pattern: regex.source + }))]; + } + }; + const numberProcessor = (schema, ctx, _json, _params) => { + const json = _json; + const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; + if (typeof format === "string" && format.includes("int")) json.type = "integer"; + else json.type = "number"; + const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY); + const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY); + const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0"; + if (exMin) if (legacy) { + json.minimum = exclusiveMinimum; + json.exclusiveMinimum = true; + } else json.exclusiveMinimum = exclusiveMinimum; + else if (typeof minimum === "number") json.minimum = minimum; + if (exMax) if (legacy) { + json.maximum = exclusiveMaximum; + json.exclusiveMaximum = true; + } else json.exclusiveMaximum = exclusiveMaximum; + else if (typeof maximum === "number") json.maximum = maximum; + if (typeof multipleOf === "number") json.multipleOf = multipleOf; + }; + const booleanProcessor = (_schema, _ctx, json, _params) => { + json.type = "boolean"; + }; + const bigintProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("BigInt cannot be represented in JSON Schema"); + }; + const symbolProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Symbols cannot be represented in JSON Schema"); + }; + const nullProcessor = (_schema, ctx, json, _params) => { + if (ctx.target === "openapi-3.0") { + json.type = "string"; + json.nullable = true; + json.enum = [null]; + } else json.type = "null"; + }; + const undefinedProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Undefined cannot be represented in JSON Schema"); + }; + const voidProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Void cannot be represented in JSON Schema"); + }; + const neverProcessor = (_schema, _ctx, json, _params) => { + json.not = {}; + }; + const anyProcessor = (_schema, _ctx, _json, _params) => {}; + const unknownProcessor = (_schema, _ctx, _json, _params) => {}; + const dateProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Date cannot be represented in JSON Schema"); + }; + const enumProcessor = (schema, _ctx, json, _params) => { + const def = schema._zod.def; + const values = getEnumValues(def.entries); + if (values.every((v) => typeof v === "number")) json.type = "number"; + if (values.every((v) => typeof v === "string")) json.type = "string"; + json.enum = values; + }; + const literalProcessor = (schema, ctx, json, _params) => { + const def = schema._zod.def; + const vals = []; + for (const val of def.values) if (val === void 0) { + if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema"); + } else if (typeof val === "bigint") if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema"); + else vals.push(Number(val)); + else vals.push(val); + if (vals.length === 0) {} else if (vals.length === 1) { + const val = vals[0]; + json.type = val === null ? "null" : typeof val; + if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") json.enum = [val]; + else json.const = val; + } else { + if (vals.every((v) => typeof v === "number")) json.type = "number"; + if (vals.every((v) => typeof v === "string")) json.type = "string"; + if (vals.every((v) => typeof v === "boolean")) json.type = "boolean"; + if (vals.every((v) => v === null)) json.type = "null"; + json.enum = vals; + } + }; + const nanProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("NaN cannot be represented in JSON Schema"); + }; + const templateLiteralProcessor = (schema, _ctx, json, _params) => { + const _json = json; + const pattern = schema._zod.pattern; + if (!pattern) throw new Error("Pattern not found in template literal"); + _json.type = "string"; + _json.pattern = pattern.source; + }; + const fileProcessor = (schema, _ctx, json, _params) => { + const _json = json; + const file = { + type: "string", + format: "binary", + contentEncoding: "binary" + }; + const { minimum, maximum, mime } = schema._zod.bag; + if (minimum !== void 0) file.minLength = minimum; + if (maximum !== void 0) file.maxLength = maximum; + if (mime) if (mime.length === 1) { + file.contentMediaType = mime[0]; + Object.assign(_json, file); + } else { + Object.assign(_json, file); + _json.anyOf = mime.map((m) => ({ contentMediaType: m })); + } + else Object.assign(_json, file); + }; + const successProcessor = (_schema, _ctx, json, _params) => { + json.type = "boolean"; + }; + const customProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Custom types cannot be represented in JSON Schema"); + }; + const functionProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Function types cannot be represented in JSON Schema"); + }; + const transformProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Transforms cannot be represented in JSON Schema"); + }; + const mapProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Map cannot be represented in JSON Schema"); + }; + const setProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Set cannot be represented in JSON Schema"); + }; + const arrayProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") json.minItems = minimum; + if (typeof maximum === "number") json.maxItems = maximum; + json.type = "array"; + json.items = process(def.element, ctx, { + ...params, + path: [...params.path, "items"] + }); + }; + const objectProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + json.properties = {}; + const shape = def.shape; + for (const key in shape) json.properties[key] = process(shape[key], ctx, { + ...params, + path: [ + ...params.path, + "properties", + key + ] + }); + const allKeys = new Set(Object.keys(shape)); + const requiredKeys = new Set([...allKeys].filter((key) => { + const v = def.shape[key]._zod; + if (ctx.io === "input") return v.optin === void 0; + else return v.optout === void 0; + })); + if (requiredKeys.size > 0) json.required = Array.from(requiredKeys); + if (def.catchall?._zod.def.type === "never") json.additionalProperties = false; + else if (!def.catchall) { + if (ctx.io === "output") json.additionalProperties = false; + } else if (def.catchall) json.additionalProperties = process(def.catchall, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + }; + const unionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const isExclusive = def.inclusive === false; + const options = def.options.map((x, i) => process(x, ctx, { + ...params, + path: [ + ...params.path, + isExclusive ? "oneOf" : "anyOf", + i + ] + })); + if (isExclusive) json.oneOf = options; + else json.anyOf = options; + }; + const intersectionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const a = process(def.left, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 0 + ] + }); + const b = process(def.right, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 1 + ] + }); + const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1; + json.allOf = [...isSimpleIntersection(a) ? a.allOf : [a], ...isSimpleIntersection(b) ? b.allOf : [b]]; + }; + const tupleProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "array"; + const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items"; + const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems"; + const prefixItems = def.items.map((x, i) => process(x, ctx, { + ...params, + path: [ + ...params.path, + prefixPath, + i + ] + })); + const rest = def.rest ? process(def.rest, ctx, { + ...params, + path: [ + ...params.path, + restPath, + ...ctx.target === "openapi-3.0" ? [def.items.length] : [] + ] + }) : null; + if (ctx.target === "draft-2020-12") { + json.prefixItems = prefixItems; + if (rest) json.items = rest; + } else if (ctx.target === "openapi-3.0") { + json.items = { anyOf: prefixItems }; + if (rest) json.items.anyOf.push(rest); + json.minItems = prefixItems.length; + if (!rest) json.maxItems = prefixItems.length; + } else { + json.items = prefixItems; + if (rest) json.additionalItems = rest; + } + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") json.minItems = minimum; + if (typeof maximum === "number") json.maxItems = maximum; + }; + const recordProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + const keyType = def.keyType; + const patterns = keyType._zod.bag?.patterns; + if (def.mode === "loose" && patterns && patterns.size > 0) { + const valueSchema = process(def.valueType, ctx, { + ...params, + path: [ + ...params.path, + "patternProperties", + "*" + ] + }); + json.patternProperties = {}; + for (const pattern of patterns) json.patternProperties[pattern.source] = valueSchema; + } else { + if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") json.propertyNames = process(def.keyType, ctx, { + ...params, + path: [...params.path, "propertyNames"] + }); + json.additionalProperties = process(def.valueType, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + } + const keyValues = keyType._zod.values; + if (keyValues) { + const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number"); + if (validKeyValues.length > 0) json.required = validKeyValues; + } + }; + const nullableProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const inner = process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + if (ctx.target === "openapi-3.0") { + seen.ref = def.innerType; + json.nullable = true; + } else json.anyOf = [inner, { type: "null" }]; + }; + const nonoptionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const defaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.default = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const prefaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + if (ctx.io === "input") json._prefault = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const catchProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + let catchValue; + try { + catchValue = def.catchValue(void 0); + } catch { + throw new Error("Dynamic catch values are not supported in JSON Schema"); + } + json.default = catchValue; + }; + const pipeProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + const inIsTransform = def.in._zod.traits.has("$ZodTransform"); + const innerType = ctx.io === "input" ? inIsTransform ? def.out : def.in : def.out; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + const readonlyProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.readOnly = true; + }; + const promiseProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const optionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const lazyProcessor = (schema, ctx, _json, params) => { + const innerType = schema._zod.innerType; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + const allProcessors = { + string: stringProcessor, + number: numberProcessor, + boolean: booleanProcessor, + bigint: bigintProcessor, + symbol: symbolProcessor, + null: nullProcessor, + undefined: undefinedProcessor, + void: voidProcessor, + never: neverProcessor, + any: anyProcessor, + unknown: unknownProcessor, + date: dateProcessor, + enum: enumProcessor, + literal: literalProcessor, + nan: nanProcessor, + template_literal: templateLiteralProcessor, + file: fileProcessor, + success: successProcessor, + custom: customProcessor, + function: functionProcessor, + transform: transformProcessor, + map: mapProcessor, + set: setProcessor, + array: arrayProcessor, + object: objectProcessor, + union: unionProcessor, + intersection: intersectionProcessor, + tuple: tupleProcessor, + record: recordProcessor, + nullable: nullableProcessor, + nonoptional: nonoptionalProcessor, + default: defaultProcessor, + prefault: prefaultProcessor, + catch: catchProcessor, + pipe: pipeProcessor, + readonly: readonlyProcessor, + promise: promiseProcessor, + optional: optionalProcessor, + lazy: lazyProcessor + }; + function toJSONSchema(input, params) { + if ("_idmap" in input) { + const registry = input; + const ctx = initializeContext({ + ...params, + processors: allProcessors + }); + const defs = {}; + for (const entry of registry._idmap.entries()) { + const [_, schema] = entry; + process(schema, ctx); + } + const schemas = {}; + ctx.external = { + registry, + uri: params?.uri, + defs + }; + for (const entry of registry._idmap.entries()) { + const [key, schema] = entry; + extractDefs(ctx, schema); + schemas[key] = finalize(ctx, schema); + } + if (Object.keys(defs).length > 0) schemas.__shared = { [ctx.target === "draft-2020-12" ? "$defs" : "definitions"]: defs }; + return { schemas }; + } + const ctx = initializeContext({ + ...params, + processors: allProcessors + }); + process(input, ctx); + extractDefs(ctx, input); + return finalize(ctx, input); + } + //#endregion + //#region lib/types/service.js + /** + * Runtime registry for generated Typert reflection, Remote invocations, and + * dependency-inverted lookup/Context providers. It performs no TypeScript + * analysis or schema generation. + * @module @deepseek-ai/dsh-typert-registry + */ + /** + * Compose the global key of one generated schema. + * @param packageName - contributing npm package. + * @param name - schema export name. + * @returns `#`. + */ + function typertKey(packageName, name) { + return `${packageName}#${name}`; + } + /** + * Compose the identity of one package-face model. + * @param packageName - contributing npm package. + * @param face - independently compiled face. + * @returns `#`. + */ + function typertPackageKey(packageName, face) { + return `${packageName}#${face}`; + } + /** + * Compose the endpoint key used by local and Remote invocation registries. + * @param descriptor - invocation whose namespace and method form the endpoint. + * @returns `/`. + */ + function typertEndpoint(descriptor) { + return `${descriptor.namespace}/${descriptor.method}`; + } + var ChangeSource = class { + report; + listeners = /* @__PURE__ */ new Set(); + constructor(report) { + this.report = report; + } + subscribe(ctx, listener) { + const { listeners } = this; + return ctx.effect(function* () { + listeners.add(listener); + yield () => { + listeners.delete(listener); + }; + }, "typert registry subscription"); + } + emit(change) { + for (const listener of [...this.listeners]) try { + listener(change); + } catch (error) { + this.report(change, error); + } + } + }; + var DescriptorStore = class { + kind; + entries = /* @__PURE__ */ new Map(); + ids = /* @__PURE__ */ new Map(); + history = /* @__PURE__ */ new Set(); + changes; + constructor(kind, report) { + this.kind = kind; + this.changes = new ChangeSource(report); + } + validate(descriptors) { + const endpoints = /* @__PURE__ */ new Set(); + const ids = /* @__PURE__ */ new Set(); + for (const descriptor of descriptors) { + validateInvocation(descriptor); + const endpoint = typertEndpoint(descriptor); + if (endpoints.has(endpoint) || this.entries.has(endpoint)) throw new Error(`typert: ${this.kind} endpoint "${endpoint}" is already registered`); + if (ids.has(descriptor.id) || this.ids.has(descriptor.id)) throw new Error(`typert: ${this.kind} invocation id "${descriptor.id}" is already registered`); + endpoints.add(endpoint); + ids.add(descriptor.id); + } + } + commit(owner, descriptors) { + for (const descriptor of descriptors) { + const entry = { + descriptor, + owner + }; + const endpoint = typertEndpoint(descriptor); + this.entries.set(endpoint, entry); + this.ids.set(descriptor.id, entry); + this.history.add(endpoint); + } + for (const descriptor of descriptors) this.changes.emit({ + kind: this.kind, + key: typertEndpoint(descriptor) + }); + } + withdraw(owner, descriptors) { + const removed = []; + for (const descriptor of descriptors) { + const endpoint = typertEndpoint(descriptor); + const entry = this.entries.get(endpoint); + /* v8 ignore next -- duplicate registration is rejected, so no later owner can replace this entry before its effect disposes. */ + if (entry?.owner !== owner) continue; + this.entries.delete(endpoint); + /* v8 ignore next -- ids and endpoints are committed and withdrawn together under the same unique owner. */ + if (this.ids.get(descriptor.id) === entry) this.ids.delete(descriptor.id); + removed.push(endpoint); + } + for (const endpoint of removed) this.changes.emit({ + kind: this.kind, + key: endpoint + }); + } + get(endpoint) { + return this.entries.get(endpoint)?.descriptor; + } + hasSeen(endpoint) { + return this.history.has(endpoint); + } + list() { + return [...this.entries.values()].map((entry) => entry.descriptor); + } + subscribe(ctx, listener) { + return this.changes.subscribe(ctx, listener); + } + }; + var RemoteStore = class { + descriptors; + packages = /* @__PURE__ */ new Map(); + constructor(descriptors) { + this.descriptors = descriptors; + } + view(ctx) { + return { + register: (contribution) => this.register(ctx, contribution), + get: (endpoint) => this.descriptors.get(endpoint), + list: () => this.descriptors.list(), + subscribe: (listener) => this.descriptors.subscribe(ctx, listener) + }; + } + register(ctx, contribution) { + validateSegment("Remote package name", contribution.package); + if (this.packages.has(contribution.package)) throw new Error(`typert: Remote package "${contribution.package}" is already registered`); + this.descriptors.validate(contribution.descriptors); + const owner = {}; + const { packages, descriptors } = this; + return ctx.effect(function* () { + packages.set(contribution.package, owner); + descriptors.commit(owner, contribution.descriptors); + yield () => { + /* v8 ignore else -- duplicate package registration is rejected, so this effect remains the package's unique owner. */ + if (packages.get(contribution.package) === owner) packages.delete(contribution.package); + descriptors.withdraw(owner, contribution.descriptors); + }; + }, `typert.remotes.register(${JSON.stringify(contribution.package)})`); + } + }; + var LookupStore = class { + providers = /* @__PURE__ */ new Map(); + resolvers = /* @__PURE__ */ new Map(); + definitions = /* @__PURE__ */ new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + register: (key, provider) => this.register(ctx, key, provider), + configure: (key, resolver) => this.configure(ctx, key, resolver), + get: (key) => this.get(key), + definitions: () => [...this.definitions.values()], + keys: () => [...this.providers.keys()], + subscribe: (listener) => this.changes.subscribe(ctx, listener) + }; + } + get(key) { + const provider = this.providers.get(key)?.provider; + if (provider === void 0) return void 0; + const resolver = this.resolvers.get(key)?.provider; + if (resolver === void 0) return provider; + return { + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: (id) => resolver.resolve(id) + }; + } + configure(ctx, key, resolver) { + validateSegment("lookup key", key); + if (this.resolvers.has(key)) throw new Error(`typert: lookup "${key}" resolver is already configured`); + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner: {} + }; + const { resolvers, changes } = this; + return ctx.effect(function* () { + resolvers.set(key, entry); + changes.emit({ + kind: "lookup", + key + }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (resolvers.get(key) !== entry) return; + resolvers.delete(key); + changes.emit({ + kind: "lookup", + key + }); + }; + }, `typert.lookups.configure(${JSON.stringify(key)})`); + } + register(ctx, key, provider) { + validateSegment("lookup key", key); + validateSegment("lookup parameter", provider.parameter); + validateWireName("lookup wire field", provider.wire); + validateNonempty("lookup Host type symbol", provider.hostTypeSymbol); + validateNonempty("lookup wire type symbol", provider.wireTypeSymbol); + if (this.providers.has(key)) throw new Error(`typert: lookup "${key}" is already registered`); + const definition = { + key, + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol + }; + const known = this.definitions.get(key); + if (known !== void 0 && !lookupDefinitionEquals(known, definition)) throw new Error(`typert: lookup "${key}" changed its wire declaration during this registry lifetime`); + const entry = { + provider, + owner: {} + }; + const { definitions, providers, changes } = this; + return ctx.effect(function* () { + definitions.set(key, definition); + providers.set(key, entry); + changes.emit({ + kind: "lookup", + key + }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (providers.get(key) !== entry) return; + providers.delete(key); + changes.emit({ + kind: "lookup", + key + }); + }; + }, `typert.lookups.register(${JSON.stringify(key)})`); + } + }; + function lookupDefinitionEquals(left, right) { + return left.parameter === right.parameter && left.wire === right.wire && left.hostTypeSymbol === right.hostTypeSymbol && left.wireTypeSymbol === right.wireTypeSymbol; + } + var ContextStore = class { + hosts = /* @__PURE__ */ new Map(); + hostResolvers = /* @__PURE__ */ new Map(); + clients = /* @__PURE__ */ new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + registerHost: (key, provider) => this.registerHost(ctx, key, provider), + configureHost: (key, resolver) => this.configureHost(ctx, key, resolver), + registerClient: (key, binder) => this.registerClient(ctx, key, binder), + getHost: (key) => this.getHost(key), + getClient: (key) => this.clients.get(key)?.provider, + subscribe: (listener) => this.changes.subscribe(ctx, listener) + }; + } + getHost(key) { + const provider = this.hosts.get(key)?.provider; + if (provider === void 0) return void 0; + const resolver = this.hostResolvers.get(key)?.provider; + if (resolver === void 0) return provider; + return { + wire: provider.wire, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: (id) => resolver.resolve(id) + }; + } + configureHost(ctx, key, resolver) { + validateSegment("Context key", key); + if (this.hostResolvers.has(key)) throw new Error(`typert: host-context "${key}" resolver is already configured`); + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner: {} + }; + const { hostResolvers, changes } = this; + return ctx.effect(function* () { + hostResolvers.set(key, entry); + changes.emit({ + kind: "host-context", + key + }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (hostResolvers.get(key) !== entry) return; + hostResolvers.delete(key); + changes.emit({ + kind: "host-context", + key + }); + }; + }, `typert.contexts.configureHost(${JSON.stringify(key)})`); + } + registerHost(ctx, key, provider) { + validateSegment("Context key", key); + validateWireName("Context wire field", provider.wire); + validateNonempty("Context wire type symbol", provider.wireTypeSymbol); + return this.registerProvider(ctx, this.hosts, "host-context", key, provider); + } + registerClient(ctx, key, binder) { + validateSegment("Context key", key); + return this.registerProvider(ctx, this.clients, "client-context", key, binder); + } + registerProvider(ctx, table, kind, key, provider) { + if (table.has(key)) throw new Error(`typert: ${kind} provider "${key}" is already registered`); + const entry = { + provider, + owner: {} + }; + const { changes } = this; + return ctx.effect(function* () { + table.set(key, entry); + changes.emit({ + kind, + key + }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (table.get(key) !== entry) return; + table.delete(key); + changes.emit({ + kind, + key + }); + }; + }, `typert.contexts.register(${JSON.stringify(key)})`); + } + }; + /** + * Registry of generated schemas, package reflection, invocations, and Remote + * dependency providers. + * @typert service typert + */ + var TypertRegistry = class extends _deepseek_ai_cordis.Service { + schemas = /* @__PURE__ */ new Map(); + packages = /* @__PURE__ */ new Map(); + localStore; + remoteStore; + lookupStore; + contextStore; + constructor(ctx) { + super(ctx, "typert"); + const report = (change, error) => { + ctx.logger.warn(`typert: ${change.kind} observer for "${change.key}" failed`); + ctx.logger.warn(error); + }; + this.localStore = new DescriptorStore("local", report); + this.remoteStore = new RemoteStore(new DescriptorStore("remote", report)); + this.lookupStore = new LookupStore(report); + this.contextStore = new ContextStore(report); + } + /** Current-environment invocation definitions. */ + get local() { + const ctx = this.ctx; + return { + get: (endpoint) => this.localStore.get(endpoint), + hasSeen: (endpoint) => this.localStore.hasSeen(endpoint), + list: () => this.localStore.list(), + subscribe: (listener) => this.localStore.subscribe(ctx, listener) + }; + } + /** Consumer-selected Remote definitions. */ + get remotes() { + return this.remoteStore.view(this.ctx); + } + /** Host object lookup providers. */ + get lookups() { + return this.lookupStore.view(this.ctx); + } + /** Host Context providers and Client Context binders. */ + get contexts() { + return this.contextStore.view(this.ctx); + } + /** + * Register one generated contribution atomically for the calling fiber. + * Duplicate package-face identities, schemas, invocation ids, or endpoints + * reject the whole batch. + * @param contribution - generated schemas, reflection, and Host invocations. + * @returns the exact effect disposer that removes this contribution. + */ + register(contribution) { + const packageRecord = this.validatePackage(contribution); + const schemaRecords = this.validateSchemas(contribution); + const invocations = contribution.invocations; + this.localStore.validate(invocations); + const owner = {}; + const { schemas, packages, localStore } = this; + return this.ctx.effect(function* () { + packages.set(packageRecord.key, packageRecord); + for (const record of schemaRecords) schemas.set(record.key, record); + localStore.commit(owner, invocations); + yield () => { + /* v8 ignore else -- duplicate package-face registration is rejected, so this effect remains its unique owner. */ + if (packages.get(packageRecord.key) === packageRecord) packages.delete(packageRecord.key); + for (const record of schemaRecords) + /* v8 ignore else -- duplicate schema registration is rejected, so this contribution remains each record's unique owner. */ + if (schemas.get(record.key) === record) schemas.delete(record.key); + localStore.withdraw(owner, invocations); + }; + }, "typert.register()"); + } + /** + * Look up one schema by `#`. + * @param key - global schema key. + * @returns the live schema record, or `undefined` when absent. + */ + get(key) { + return this.schemas.get(key); + } + /** + * Resolve one required schema. + * @param key - global schema key. + * @returns the live schema record. + * @throws when the key is malformed, the package face is absent, or the schema is not contributed. + */ + resolve(key) { + const record = this.schemas.get(key); + if (record !== void 0) return record; + const hash = key.indexOf("#"); + if (hash <= 0 || hash === key.length - 1) throw new Error(`typert: invalid schema key "${key}" — expected "#"`); + const packageName = key.slice(0, hash); + if ([...this.packages.values()].some((candidate) => candidate.package === packageName)) throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" is registered but contributes no schema named "${key.slice(hash + 1)}"`); + throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" has no registered contribution`); + } + /** + * Enumerate live schemas in registration order. + * @param filter - optional package and face restriction. + * @returns matching schema records. + */ + list(filter = {}) { + return [...this.schemas.values()].filter((record) => matches(record, filter)); + } + /** + * Look up generated reflection for one package face. + * @param packageName - exact npm package name. + * @param face - face to query; defaults to the host runtime. + * @returns the live package record, or `undefined` when absent. + */ + getPackage(packageName, face = "host") { + return this.packages.get(typertPackageKey(packageName, face)); + } + /** + * Enumerate generated package reflection in registration order. + * @param filter - optional package and face restriction. + * @returns matching package records. + */ + listPackages(filter = {}) { + return [...this.packages.values()].filter((record) => matches(record, filter)); + } + /** + * Project a live Zod schema to JSON Schema without caching the result. + * @param key - global schema key. + * @param params - Zod projection parameters. + * @returns a fresh JSON Schema document. + */ + toJSONSchema(key, params) { + return toJSONSchema(this.resolve(key).schema, params); + } + validatePackage(contribution) { + validateSegment("package name", contribution.package); + const face = contribution.face; + if (face !== "host" && face !== "client") throw new Error(`typert: invalid face ${JSON.stringify(face)} — expected "host" or "client"`); + const key = typertPackageKey(contribution.package, contribution.face); + if (this.packages.has(key)) throw new Error(`typert: package face "${key}" is already registered`); + return { + package: contribution.package, + face, + key, + model: contribution.model + }; + } + validateSchemas(contribution) { + const records = []; + const batch = /* @__PURE__ */ new Set(); + for (const schema of contribution.schemas) { + validateSegment("schema name", schema.name); + const key = typertKey(contribution.package, schema.name); + if (batch.has(key) || this.schemas.has(key)) throw new Error(`typert: schema "${key}" is already registered`); + batch.add(key); + records.push({ + ...schema, + package: contribution.package, + face: contribution.face, + key + }); + } + return records; + } + }; + function matches(record, filter) { + return (filter.package === void 0 || record.package === filter.package) && (filter.face === void 0 || record.face === filter.face); + } + function validateInvocation(descriptor) { + validateNonempty("invocation id", descriptor.id); + validateSegment("invocation service key", descriptor.service); + validateWireName("invocation namespace", descriptor.namespace); + validateWireName("invocation method", descriptor.method); + if (descriptor.implementation !== void 0) validateWireName("invocation implementation method", descriptor.implementation); + validateCodec(descriptor.result, `${descriptor.id} result`); + const wires = /* @__PURE__ */ new Set(); + for (const parameter of descriptor.parameters) { + validateWireName("parameter name", parameter.name); + validateWireName("parameter wire field", parameter.wire); + if (wires.has(parameter.wire)) throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${parameter.wire}"`); + wires.add(parameter.wire); + if (parameter.source === "lookup") { + if (parameter.acceptsUndefined !== void 0) throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" cannot accept undefined`); + if (parameter.lookup === void 0) throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" has no lookup key`); + validateSegment("lookup key", parameter.lookup); + } else if (parameter.lookup !== void 0) throw new Error(`typert: invocation "${descriptor.id}" JSON parameter "${parameter.name}" declares a lookup key`); + validateCodec(parameter.codec, `${descriptor.id} parameter ${parameter.name}`); + } + const cancellation = descriptor.cancellation; + if (cancellation !== void 0 && cancellation.parameter !== "signal") throw new Error(`typert: invocation "${descriptor.id}" cancellation parameter must be "signal"`); + if (descriptor.scope !== void 0) { + if (descriptor.invocation.kind !== "direct") throw new Error(`typert: invocation "${descriptor.id}" Context receiver cannot declare a direct scope projection`); + validateSegment("scope Context key", descriptor.scope.context); + validateWireName("scope wire field", descriptor.scope.wire); + const lookups = descriptor.parameters.filter((candidate) => candidate.source === "lookup"); + const parameter = lookups.length === 1 ? lookups[0] : void 0; + if (parameter === void 0 || parameter.wire !== descriptor.scope.wire || parameter.lookup !== descriptor.scope.context) throw new Error(`typert: invocation "${descriptor.id}" scope wire "${descriptor.scope.wire}" must select its only lookup parameter`); + } + if (descriptor.invocation.kind === "context") { + validateSegment("Context key", descriptor.invocation.context); + validateWireName("Context wire field", descriptor.invocation.wire); + if (wires.has(descriptor.invocation.wire)) throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${descriptor.invocation.wire}"`); + validateCodec(descriptor.invocation.codec, `${descriptor.id} Context`); + } + } + function validateCodec(codec, subject) { + if (codec.mode === "src-json") return; + validateNonempty(`${subject} type symbol`, codec.typeSymbol); + if (typeof codec.schema.parse !== "function") throw new Error(`typert: ${subject} strict codec has no parse() method`); + } + function validateWireName(subject, value) { + if (value === "." || value === ".." || !/^[A-Za-z0-9_$.-]+$/.test(value)) throw new Error(`typert: invalid ${subject} "${value}" — must contain only RPC endpoint segment characters`); + } + function validateSegment(subject, value) { + if (value.length === 0 || value.includes("#")) throw new Error(`typert: invalid ${subject} "${value}" — must be nonempty and must not contain "#"`); + } + function validateNonempty(subject, value) { + if (value.length === 0) throw new Error(`typert: invalid ${subject} — must be nonempty`); + } + //#endregion + //#region lib/types/client/index.js + /** Browser face of the shared Typert runtime registry. */ + /** Required services: none; this is the Client reflection root. */ + const inject = []; + /** + * Install the same registry implementation used by the Host face. + * @param ctx - Client Cordis root. + */ + function apply(ctx) { + new TypertRegistry(ctx); + } + //#endregion + exports.apply = apply; + exports.inject = inject; + return module.exports; + } +}); + +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/index.js new file mode 100644 index 0000000..ab2eaa4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/index.js @@ -0,0 +1,562 @@ +import { Service } from "@deepseek-ai/cordis"; +import { z } from "zod"; +//#region lib/types/service.js +/** +* Runtime registry for generated Typert reflection, Remote invocations, and +* dependency-inverted lookup/Context providers. It performs no TypeScript +* analysis or schema generation. +* @module @deepseek-ai/dsh-typert-registry +*/ +/** +* Compose the global key of one generated schema. +* @param packageName - contributing npm package. +* @param name - schema export name. +* @returns `#`. +*/ +function typertKey(packageName, name) { + return `${packageName}#${name}`; +} +/** +* Compose the identity of one package-face model. +* @param packageName - contributing npm package. +* @param face - independently compiled face. +* @returns `#`. +*/ +function typertPackageKey(packageName, face) { + return `${packageName}#${face}`; +} +/** +* Compose the endpoint key used by local and Remote invocation registries. +* @param descriptor - invocation whose namespace and method form the endpoint. +* @returns `/`. +*/ +function typertEndpoint(descriptor) { + return `${descriptor.namespace}/${descriptor.method}`; +} +var ChangeSource = class { + report; + listeners = /* @__PURE__ */ new Set(); + constructor(report) { + this.report = report; + } + subscribe(ctx, listener) { + const { listeners } = this; + return ctx.effect(function* () { + listeners.add(listener); + yield () => { + listeners.delete(listener); + }; + }, "typert registry subscription"); + } + emit(change) { + for (const listener of [...this.listeners]) try { + listener(change); + } catch (error) { + this.report(change, error); + } + } +}; +var DescriptorStore = class { + kind; + entries = /* @__PURE__ */ new Map(); + ids = /* @__PURE__ */ new Map(); + history = /* @__PURE__ */ new Set(); + changes; + constructor(kind, report) { + this.kind = kind; + this.changes = new ChangeSource(report); + } + validate(descriptors) { + const endpoints = /* @__PURE__ */ new Set(); + const ids = /* @__PURE__ */ new Set(); + for (const descriptor of descriptors) { + validateInvocation(descriptor); + const endpoint = typertEndpoint(descriptor); + if (endpoints.has(endpoint) || this.entries.has(endpoint)) throw new Error(`typert: ${this.kind} endpoint "${endpoint}" is already registered`); + if (ids.has(descriptor.id) || this.ids.has(descriptor.id)) throw new Error(`typert: ${this.kind} invocation id "${descriptor.id}" is already registered`); + endpoints.add(endpoint); + ids.add(descriptor.id); + } + } + commit(owner, descriptors) { + for (const descriptor of descriptors) { + const entry = { + descriptor, + owner + }; + const endpoint = typertEndpoint(descriptor); + this.entries.set(endpoint, entry); + this.ids.set(descriptor.id, entry); + this.history.add(endpoint); + } + for (const descriptor of descriptors) this.changes.emit({ + kind: this.kind, + key: typertEndpoint(descriptor) + }); + } + withdraw(owner, descriptors) { + const removed = []; + for (const descriptor of descriptors) { + const endpoint = typertEndpoint(descriptor); + const entry = this.entries.get(endpoint); + /* v8 ignore next -- duplicate registration is rejected, so no later owner can replace this entry before its effect disposes. */ + if (entry?.owner !== owner) continue; + this.entries.delete(endpoint); + /* v8 ignore next -- ids and endpoints are committed and withdrawn together under the same unique owner. */ + if (this.ids.get(descriptor.id) === entry) this.ids.delete(descriptor.id); + removed.push(endpoint); + } + for (const endpoint of removed) this.changes.emit({ + kind: this.kind, + key: endpoint + }); + } + get(endpoint) { + return this.entries.get(endpoint)?.descriptor; + } + hasSeen(endpoint) { + return this.history.has(endpoint); + } + list() { + return [...this.entries.values()].map((entry) => entry.descriptor); + } + subscribe(ctx, listener) { + return this.changes.subscribe(ctx, listener); + } +}; +var RemoteStore = class { + descriptors; + packages = /* @__PURE__ */ new Map(); + constructor(descriptors) { + this.descriptors = descriptors; + } + view(ctx) { + return { + register: (contribution) => this.register(ctx, contribution), + get: (endpoint) => this.descriptors.get(endpoint), + list: () => this.descriptors.list(), + subscribe: (listener) => this.descriptors.subscribe(ctx, listener) + }; + } + register(ctx, contribution) { + validateSegment("Remote package name", contribution.package); + if (this.packages.has(contribution.package)) throw new Error(`typert: Remote package "${contribution.package}" is already registered`); + this.descriptors.validate(contribution.descriptors); + const owner = {}; + const { packages, descriptors } = this; + return ctx.effect(function* () { + packages.set(contribution.package, owner); + descriptors.commit(owner, contribution.descriptors); + yield () => { + /* v8 ignore else -- duplicate package registration is rejected, so this effect remains the package's unique owner. */ + if (packages.get(contribution.package) === owner) packages.delete(contribution.package); + descriptors.withdraw(owner, contribution.descriptors); + }; + }, `typert.remotes.register(${JSON.stringify(contribution.package)})`); + } +}; +var LookupStore = class { + providers = /* @__PURE__ */ new Map(); + resolvers = /* @__PURE__ */ new Map(); + definitions = /* @__PURE__ */ new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + register: (key, provider) => this.register(ctx, key, provider), + configure: (key, resolver) => this.configure(ctx, key, resolver), + get: (key) => this.get(key), + definitions: () => [...this.definitions.values()], + keys: () => [...this.providers.keys()], + subscribe: (listener) => this.changes.subscribe(ctx, listener) + }; + } + get(key) { + const provider = this.providers.get(key)?.provider; + if (provider === void 0) return void 0; + const resolver = this.resolvers.get(key)?.provider; + if (resolver === void 0) return provider; + return { + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: (id) => resolver.resolve(id) + }; + } + configure(ctx, key, resolver) { + validateSegment("lookup key", key); + if (this.resolvers.has(key)) throw new Error(`typert: lookup "${key}" resolver is already configured`); + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner: {} + }; + const { resolvers, changes } = this; + return ctx.effect(function* () { + resolvers.set(key, entry); + changes.emit({ + kind: "lookup", + key + }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (resolvers.get(key) !== entry) return; + resolvers.delete(key); + changes.emit({ + kind: "lookup", + key + }); + }; + }, `typert.lookups.configure(${JSON.stringify(key)})`); + } + register(ctx, key, provider) { + validateSegment("lookup key", key); + validateSegment("lookup parameter", provider.parameter); + validateWireName("lookup wire field", provider.wire); + validateNonempty("lookup Host type symbol", provider.hostTypeSymbol); + validateNonempty("lookup wire type symbol", provider.wireTypeSymbol); + if (this.providers.has(key)) throw new Error(`typert: lookup "${key}" is already registered`); + const definition = { + key, + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol + }; + const known = this.definitions.get(key); + if (known !== void 0 && !lookupDefinitionEquals(known, definition)) throw new Error(`typert: lookup "${key}" changed its wire declaration during this registry lifetime`); + const entry = { + provider, + owner: {} + }; + const { definitions, providers, changes } = this; + return ctx.effect(function* () { + definitions.set(key, definition); + providers.set(key, entry); + changes.emit({ + kind: "lookup", + key + }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (providers.get(key) !== entry) return; + providers.delete(key); + changes.emit({ + kind: "lookup", + key + }); + }; + }, `typert.lookups.register(${JSON.stringify(key)})`); + } +}; +function lookupDefinitionEquals(left, right) { + return left.parameter === right.parameter && left.wire === right.wire && left.hostTypeSymbol === right.hostTypeSymbol && left.wireTypeSymbol === right.wireTypeSymbol; +} +var ContextStore = class { + hosts = /* @__PURE__ */ new Map(); + hostResolvers = /* @__PURE__ */ new Map(); + clients = /* @__PURE__ */ new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + registerHost: (key, provider) => this.registerHost(ctx, key, provider), + configureHost: (key, resolver) => this.configureHost(ctx, key, resolver), + registerClient: (key, binder) => this.registerClient(ctx, key, binder), + getHost: (key) => this.getHost(key), + getClient: (key) => this.clients.get(key)?.provider, + subscribe: (listener) => this.changes.subscribe(ctx, listener) + }; + } + getHost(key) { + const provider = this.hosts.get(key)?.provider; + if (provider === void 0) return void 0; + const resolver = this.hostResolvers.get(key)?.provider; + if (resolver === void 0) return provider; + return { + wire: provider.wire, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: (id) => resolver.resolve(id) + }; + } + configureHost(ctx, key, resolver) { + validateSegment("Context key", key); + if (this.hostResolvers.has(key)) throw new Error(`typert: host-context "${key}" resolver is already configured`); + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner: {} + }; + const { hostResolvers, changes } = this; + return ctx.effect(function* () { + hostResolvers.set(key, entry); + changes.emit({ + kind: "host-context", + key + }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (hostResolvers.get(key) !== entry) return; + hostResolvers.delete(key); + changes.emit({ + kind: "host-context", + key + }); + }; + }, `typert.contexts.configureHost(${JSON.stringify(key)})`); + } + registerHost(ctx, key, provider) { + validateSegment("Context key", key); + validateWireName("Context wire field", provider.wire); + validateNonempty("Context wire type symbol", provider.wireTypeSymbol); + return this.registerProvider(ctx, this.hosts, "host-context", key, provider); + } + registerClient(ctx, key, binder) { + validateSegment("Context key", key); + return this.registerProvider(ctx, this.clients, "client-context", key, binder); + } + registerProvider(ctx, table, kind, key, provider) { + if (table.has(key)) throw new Error(`typert: ${kind} provider "${key}" is already registered`); + const entry = { + provider, + owner: {} + }; + const { changes } = this; + return ctx.effect(function* () { + table.set(key, entry); + changes.emit({ + kind, + key + }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (table.get(key) !== entry) return; + table.delete(key); + changes.emit({ + kind, + key + }); + }; + }, `typert.contexts.register(${JSON.stringify(key)})`); + } +}; +/** +* Registry of generated schemas, package reflection, invocations, and Remote +* dependency providers. +* @typert service typert +*/ +var TypertRegistry = class extends Service { + schemas = /* @__PURE__ */ new Map(); + packages = /* @__PURE__ */ new Map(); + localStore; + remoteStore; + lookupStore; + contextStore; + constructor(ctx) { + super(ctx, "typert"); + const report = (change, error) => { + ctx.logger.warn(`typert: ${change.kind} observer for "${change.key}" failed`); + ctx.logger.warn(error); + }; + this.localStore = new DescriptorStore("local", report); + this.remoteStore = new RemoteStore(new DescriptorStore("remote", report)); + this.lookupStore = new LookupStore(report); + this.contextStore = new ContextStore(report); + } + /** Current-environment invocation definitions. */ + get local() { + const ctx = this.ctx; + return { + get: (endpoint) => this.localStore.get(endpoint), + hasSeen: (endpoint) => this.localStore.hasSeen(endpoint), + list: () => this.localStore.list(), + subscribe: (listener) => this.localStore.subscribe(ctx, listener) + }; + } + /** Consumer-selected Remote definitions. */ + get remotes() { + return this.remoteStore.view(this.ctx); + } + /** Host object lookup providers. */ + get lookups() { + return this.lookupStore.view(this.ctx); + } + /** Host Context providers and Client Context binders. */ + get contexts() { + return this.contextStore.view(this.ctx); + } + /** + * Register one generated contribution atomically for the calling fiber. + * Duplicate package-face identities, schemas, invocation ids, or endpoints + * reject the whole batch. + * @param contribution - generated schemas, reflection, and Host invocations. + * @returns the exact effect disposer that removes this contribution. + */ + register(contribution) { + const packageRecord = this.validatePackage(contribution); + const schemaRecords = this.validateSchemas(contribution); + const invocations = contribution.invocations; + this.localStore.validate(invocations); + const owner = {}; + const { schemas, packages, localStore } = this; + return this.ctx.effect(function* () { + packages.set(packageRecord.key, packageRecord); + for (const record of schemaRecords) schemas.set(record.key, record); + localStore.commit(owner, invocations); + yield () => { + /* v8 ignore else -- duplicate package-face registration is rejected, so this effect remains its unique owner. */ + if (packages.get(packageRecord.key) === packageRecord) packages.delete(packageRecord.key); + for (const record of schemaRecords) + /* v8 ignore else -- duplicate schema registration is rejected, so this contribution remains each record's unique owner. */ + if (schemas.get(record.key) === record) schemas.delete(record.key); + localStore.withdraw(owner, invocations); + }; + }, "typert.register()"); + } + /** + * Look up one schema by `#`. + * @param key - global schema key. + * @returns the live schema record, or `undefined` when absent. + */ + get(key) { + return this.schemas.get(key); + } + /** + * Resolve one required schema. + * @param key - global schema key. + * @returns the live schema record. + * @throws when the key is malformed, the package face is absent, or the schema is not contributed. + */ + resolve(key) { + const record = this.schemas.get(key); + if (record !== void 0) return record; + const hash = key.indexOf("#"); + if (hash <= 0 || hash === key.length - 1) throw new Error(`typert: invalid schema key "${key}" — expected "#"`); + const packageName = key.slice(0, hash); + if ([...this.packages.values()].some((candidate) => candidate.package === packageName)) throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" is registered but contributes no schema named "${key.slice(hash + 1)}"`); + throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" has no registered contribution`); + } + /** + * Enumerate live schemas in registration order. + * @param filter - optional package and face restriction. + * @returns matching schema records. + */ + list(filter = {}) { + return [...this.schemas.values()].filter((record) => matches(record, filter)); + } + /** + * Look up generated reflection for one package face. + * @param packageName - exact npm package name. + * @param face - face to query; defaults to the host runtime. + * @returns the live package record, or `undefined` when absent. + */ + getPackage(packageName, face = "host") { + return this.packages.get(typertPackageKey(packageName, face)); + } + /** + * Enumerate generated package reflection in registration order. + * @param filter - optional package and face restriction. + * @returns matching package records. + */ + listPackages(filter = {}) { + return [...this.packages.values()].filter((record) => matches(record, filter)); + } + /** + * Project a live Zod schema to JSON Schema without caching the result. + * @param key - global schema key. + * @param params - Zod projection parameters. + * @returns a fresh JSON Schema document. + */ + toJSONSchema(key, params) { + return z.toJSONSchema(this.resolve(key).schema, params); + } + validatePackage(contribution) { + validateSegment("package name", contribution.package); + const face = contribution.face; + if (face !== "host" && face !== "client") throw new Error(`typert: invalid face ${JSON.stringify(face)} — expected "host" or "client"`); + const key = typertPackageKey(contribution.package, contribution.face); + if (this.packages.has(key)) throw new Error(`typert: package face "${key}" is already registered`); + return { + package: contribution.package, + face, + key, + model: contribution.model + }; + } + validateSchemas(contribution) { + const records = []; + const batch = /* @__PURE__ */ new Set(); + for (const schema of contribution.schemas) { + validateSegment("schema name", schema.name); + const key = typertKey(contribution.package, schema.name); + if (batch.has(key) || this.schemas.has(key)) throw new Error(`typert: schema "${key}" is already registered`); + batch.add(key); + records.push({ + ...schema, + package: contribution.package, + face: contribution.face, + key + }); + } + return records; + } +}; +function matches(record, filter) { + return (filter.package === void 0 || record.package === filter.package) && (filter.face === void 0 || record.face === filter.face); +} +function validateInvocation(descriptor) { + validateNonempty("invocation id", descriptor.id); + validateSegment("invocation service key", descriptor.service); + validateWireName("invocation namespace", descriptor.namespace); + validateWireName("invocation method", descriptor.method); + if (descriptor.implementation !== void 0) validateWireName("invocation implementation method", descriptor.implementation); + validateCodec(descriptor.result, `${descriptor.id} result`); + const wires = /* @__PURE__ */ new Set(); + for (const parameter of descriptor.parameters) { + validateWireName("parameter name", parameter.name); + validateWireName("parameter wire field", parameter.wire); + if (wires.has(parameter.wire)) throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${parameter.wire}"`); + wires.add(parameter.wire); + if (parameter.source === "lookup") { + if (parameter.acceptsUndefined !== void 0) throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" cannot accept undefined`); + if (parameter.lookup === void 0) throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" has no lookup key`); + validateSegment("lookup key", parameter.lookup); + } else if (parameter.lookup !== void 0) throw new Error(`typert: invocation "${descriptor.id}" JSON parameter "${parameter.name}" declares a lookup key`); + validateCodec(parameter.codec, `${descriptor.id} parameter ${parameter.name}`); + } + const cancellation = descriptor.cancellation; + if (cancellation !== void 0 && cancellation.parameter !== "signal") throw new Error(`typert: invocation "${descriptor.id}" cancellation parameter must be "signal"`); + if (descriptor.scope !== void 0) { + if (descriptor.invocation.kind !== "direct") throw new Error(`typert: invocation "${descriptor.id}" Context receiver cannot declare a direct scope projection`); + validateSegment("scope Context key", descriptor.scope.context); + validateWireName("scope wire field", descriptor.scope.wire); + const lookups = descriptor.parameters.filter((candidate) => candidate.source === "lookup"); + const parameter = lookups.length === 1 ? lookups[0] : void 0; + if (parameter === void 0 || parameter.wire !== descriptor.scope.wire || parameter.lookup !== descriptor.scope.context) throw new Error(`typert: invocation "${descriptor.id}" scope wire "${descriptor.scope.wire}" must select its only lookup parameter`); + } + if (descriptor.invocation.kind === "context") { + validateSegment("Context key", descriptor.invocation.context); + validateWireName("Context wire field", descriptor.invocation.wire); + if (wires.has(descriptor.invocation.wire)) throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${descriptor.invocation.wire}"`); + validateCodec(descriptor.invocation.codec, `${descriptor.id} Context`); + } +} +function validateCodec(codec, subject) { + if (codec.mode === "src-json") return; + validateNonempty(`${subject} type symbol`, codec.typeSymbol); + if (typeof codec.schema.parse !== "function") throw new Error(`typert: ${subject} strict codec has no parse() method`); +} +function validateWireName(subject, value) { + if (value === "." || value === ".." || !/^[A-Za-z0-9_$.-]+$/.test(value)) throw new Error(`typert: invalid ${subject} "${value}" — must contain only RPC endpoint segment characters`); +} +function validateSegment(subject, value) { + if (value.length === 0 || value.includes("#")) throw new Error(`typert: invalid ${subject} "${value}" — must be nonempty and must not contain "#"`); +} +function validateNonempty(subject, value) { + if (value.length === 0) throw new Error(`typert: invalid ${subject} — must be nonempty`); +} +//#endregion +export { TypertRegistry, TypertRegistry as default, typertEndpoint, typertKey, typertPackageKey }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/invariant.js new file mode 100644 index 0000000..3702db6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/invariant.js @@ -0,0 +1,24 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-typert-registry`. +* @module @deepseek-ai/dsh-typert-registry/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-typert-registry"; +/** Cordis companion plugin name. */ +const name = "typert-registry-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: schema and package-reflection records mutate together +* inside register/dispose, with no independent event or second data source to +* cross-check; duplicate identities fail at the owning operation boundary. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.d.ts new file mode 100644 index 0000000..d8bea52 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.d.ts @@ -0,0 +1,10 @@ +/** Browser face of the shared Typert runtime registry. */ +import type { Context } from '@deepseek-ai/cordis'; +/** Required services: none; this is the Client reflection root. */ +export declare const inject: string[]; +/** + * Install the same registry implementation used by the Host face. + * @param ctx - Client Cordis root. + */ +export declare function apply(ctx: Context): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.js new file mode 100644 index 0000000..1e1e875 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.js @@ -0,0 +1,12 @@ +/** Browser face of the shared Typert runtime registry. */ +import { TypertRegistry } from "../service.js"; +/** Required services: none; this is the Client reflection root. */ +export const inject = []; +/** + * Install the same registry implementation used by the Host face. + * @param ctx - Client Cordis root. + */ +export function apply(ctx) { + new TypertRegistry(ctx); +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.d.ts new file mode 100644 index 0000000..8ec53b9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.d.ts @@ -0,0 +1,18 @@ +/** Host entry for the shared Typert runtime registry. */ +import type { z } from 'zod'; +import type { TypertDisposer } from '@deepseek-ai/dsh-typert-protocol'; +import type { TypertContribution, TypertFace, TypertPackageFilter, TypertPackageRecord, TypertSchemaFilter, TypertSchemaRecord } from './types.ts'; +export { default, TypertRegistry, typertEndpoint, typertKey, typertPackageKey } from './service.ts'; +export type * from './types.ts'; +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRegistryContract { + register(contribution: TypertContribution): TypertDisposer; + get(key: string): TypertSchemaRecord | undefined; + resolve(key: string): TypertSchemaRecord; + list(filter?: TypertSchemaFilter): TypertSchemaRecord[]; + getPackage(packageName: string, face?: TypertFace): TypertPackageRecord | undefined; + listPackages(filter?: TypertPackageFilter): TypertPackageRecord[]; + toJSONSchema(key: string, params?: z.core.ToJSONSchemaParams): z.core.JSONSchema.BaseSchema; + } +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.js new file mode 100644 index 0000000..9a5a3fa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.js @@ -0,0 +1,3 @@ +/** Host entry for the shared Typert runtime registry. */ +export { default, TypertRegistry, typertEndpoint, typertKey, typertPackageKey } from "./service.js"; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.d.ts new file mode 100644 index 0000000..6ebf43c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-typert-registry`. + * @module @deepseek-ai/dsh-typert-registry/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "typert-registry-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.js new file mode 100644 index 0000000..ae83f94 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.js @@ -0,0 +1,23 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-typert-registry`. + * @module @deepseek-ai/dsh-typert-registry/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-typert-registry'; +/** Cordis companion plugin name. */ +export const name = 'typert-registry-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: schema and package-reflection records mutate together + * inside register/dispose, with no independent event or second data source to + * cross-check; duplicate identities fail at the owning operation boundary. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.d.ts new file mode 100644 index 0000000..e1304f0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.d.ts @@ -0,0 +1,103 @@ +/** + * Runtime registry for generated Typert reflection, Remote invocations, and + * dependency-inverted lookup/Context providers. It performs no TypeScript + * analysis or schema generation. + * @module @deepseek-ai/dsh-typert-registry + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import { z } from 'zod'; +import type { InvocationDescriptor, TypertContextRegistry, TypertDisposer, TypertLocalRegistry, TypertLookupRegistry, TypertRemoteRegistry, TypertRegistryContract } from '@deepseek-ai/dsh-typert-protocol'; +import type { TypertContribution, TypertFace, TypertPackageFilter, TypertPackageRecord, TypertSchemaFilter, TypertSchemaRecord } from './types.ts'; +/** + * Compose the global key of one generated schema. + * @param packageName - contributing npm package. + * @param name - schema export name. + * @returns `#`. + */ +export declare function typertKey(packageName: string, name: string): string; +/** + * Compose the identity of one package-face model. + * @param packageName - contributing npm package. + * @param face - independently compiled face. + * @returns `#`. + */ +export declare function typertPackageKey(packageName: string, face: TypertFace): string; +/** + * Compose the endpoint key used by local and Remote invocation registries. + * @param descriptor - invocation whose namespace and method form the endpoint. + * @returns `/`. + */ +export declare function typertEndpoint(descriptor: Pick): string; +/** + * Registry of generated schemas, package reflection, invocations, and Remote + * dependency providers. + * @typert service typert + */ +export declare class TypertRegistry extends Service implements TypertRegistryContract { + private readonly schemas; + private readonly packages; + private readonly localStore; + private readonly remoteStore; + private readonly lookupStore; + private readonly contextStore; + constructor(ctx: Context); + /** Current-environment invocation definitions. */ + get local(): TypertLocalRegistry; + /** Consumer-selected Remote definitions. */ + get remotes(): TypertRemoteRegistry; + /** Host object lookup providers. */ + get lookups(): TypertLookupRegistry; + /** Host Context providers and Client Context binders. */ + get contexts(): TypertContextRegistry; + /** + * Register one generated contribution atomically for the calling fiber. + * Duplicate package-face identities, schemas, invocation ids, or endpoints + * reject the whole batch. + * @param contribution - generated schemas, reflection, and Host invocations. + * @returns the exact effect disposer that removes this contribution. + */ + register(contribution: TypertContribution): TypertDisposer; + /** + * Look up one schema by `#`. + * @param key - global schema key. + * @returns the live schema record, or `undefined` when absent. + */ + get(key: string): TypertSchemaRecord | undefined; + /** + * Resolve one required schema. + * @param key - global schema key. + * @returns the live schema record. + * @throws when the key is malformed, the package face is absent, or the schema is not contributed. + */ + resolve(key: string): TypertSchemaRecord; + /** + * Enumerate live schemas in registration order. + * @param filter - optional package and face restriction. + * @returns matching schema records. + */ + list(filter?: TypertSchemaFilter): TypertSchemaRecord[]; + /** + * Look up generated reflection for one package face. + * @param packageName - exact npm package name. + * @param face - face to query; defaults to the host runtime. + * @returns the live package record, or `undefined` when absent. + */ + getPackage(packageName: string, face?: TypertFace): TypertPackageRecord | undefined; + /** + * Enumerate generated package reflection in registration order. + * @param filter - optional package and face restriction. + * @returns matching package records. + */ + listPackages(filter?: TypertPackageFilter): TypertPackageRecord[]; + /** + * Project a live Zod schema to JSON Schema without caching the result. + * @param key - global schema key. + * @param params - Zod projection parameters. + * @returns a fresh JSON Schema document. + */ + toJSONSchema(key: string, params?: z.core.ToJSONSchemaParams): z.core.JSONSchema.BaseSchema; + private validatePackage; + private validateSchemas; +} +export default TypertRegistry; +//# sourceMappingURL=service.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.js new file mode 100644 index 0000000..66bcd24 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.js @@ -0,0 +1,600 @@ +/** + * Runtime registry for generated Typert reflection, Remote invocations, and + * dependency-inverted lookup/Context providers. It performs no TypeScript + * analysis or schema generation. + * @module @deepseek-ai/dsh-typert-registry + */ +import { Service } from '@deepseek-ai/cordis'; +import { z } from 'zod'; +/** + * Compose the global key of one generated schema. + * @param packageName - contributing npm package. + * @param name - schema export name. + * @returns `#`. + */ +export function typertKey(packageName, name) { + return `${packageName}#${name}`; +} +/** + * Compose the identity of one package-face model. + * @param packageName - contributing npm package. + * @param face - independently compiled face. + * @returns `#`. + */ +export function typertPackageKey(packageName, face) { + return `${packageName}#${face}`; +} +/** + * Compose the endpoint key used by local and Remote invocation registries. + * @param descriptor - invocation whose namespace and method form the endpoint. + * @returns `/`. + */ +export function typertEndpoint(descriptor) { + return `${descriptor.namespace}/${descriptor.method}`; +} +class ChangeSource { + report; + listeners = new Set(); + constructor(report) { + this.report = report; + } + subscribe(ctx, listener) { + const { listeners } = this; + return ctx.effect(function* () { + listeners.add(listener); + yield () => { listeners.delete(listener); }; + }, 'typert registry subscription'); + } + emit(change) { + for (const listener of [...this.listeners]) { + try { + listener(change); + } + catch (error) { + this.report(change, error); + } + } + } +} +class DescriptorStore { + kind; + entries = new Map(); + ids = new Map(); + history = new Set(); + changes; + constructor(kind, report) { + this.kind = kind; + this.changes = new ChangeSource(report); + } + validate(descriptors) { + const endpoints = new Set(); + const ids = new Set(); + for (const descriptor of descriptors) { + validateInvocation(descriptor); + const endpoint = typertEndpoint(descriptor); + if (endpoints.has(endpoint) || this.entries.has(endpoint)) { + throw new Error(`typert: ${this.kind} endpoint "${endpoint}" is already registered`); + } + if (ids.has(descriptor.id) || this.ids.has(descriptor.id)) { + throw new Error(`typert: ${this.kind} invocation id "${descriptor.id}" is already registered`); + } + endpoints.add(endpoint); + ids.add(descriptor.id); + } + } + commit(owner, descriptors) { + for (const descriptor of descriptors) { + const entry = { descriptor, owner }; + const endpoint = typertEndpoint(descriptor); + this.entries.set(endpoint, entry); + this.ids.set(descriptor.id, entry); + this.history.add(endpoint); + } + for (const descriptor of descriptors) { + this.changes.emit({ kind: this.kind, key: typertEndpoint(descriptor) }); + } + } + withdraw(owner, descriptors) { + const removed = []; + for (const descriptor of descriptors) { + const endpoint = typertEndpoint(descriptor); + const entry = this.entries.get(endpoint); + /* v8 ignore next -- duplicate registration is rejected, so no later owner can replace this entry before its effect disposes. */ + if (entry?.owner !== owner) + continue; + this.entries.delete(endpoint); + /* v8 ignore next -- ids and endpoints are committed and withdrawn together under the same unique owner. */ + if (this.ids.get(descriptor.id) === entry) + this.ids.delete(descriptor.id); + removed.push(endpoint); + } + for (const endpoint of removed) + this.changes.emit({ kind: this.kind, key: endpoint }); + } + get(endpoint) { + return this.entries.get(endpoint)?.descriptor; + } + hasSeen(endpoint) { + return this.history.has(endpoint); + } + list() { + return [...this.entries.values()].map(entry => entry.descriptor); + } + subscribe(ctx, listener) { + return this.changes.subscribe(ctx, listener); + } +} +class RemoteStore { + descriptors; + packages = new Map(); + constructor(descriptors) { + this.descriptors = descriptors; + } + view(ctx) { + return { + register: contribution => this.register(ctx, contribution), + get: endpoint => this.descriptors.get(endpoint), + list: () => this.descriptors.list(), + subscribe: listener => this.descriptors.subscribe(ctx, listener), + }; + } + register(ctx, contribution) { + validateSegment('Remote package name', contribution.package); + if (this.packages.has(contribution.package)) { + throw new Error(`typert: Remote package "${contribution.package}" is already registered`); + } + this.descriptors.validate(contribution.descriptors); + const owner = {}; + const { packages, descriptors } = this; + return ctx.effect(function* () { + packages.set(contribution.package, owner); + descriptors.commit(owner, contribution.descriptors); + yield () => { + /* v8 ignore else -- duplicate package registration is rejected, so this effect remains the package's unique owner. */ + if (packages.get(contribution.package) === owner) + packages.delete(contribution.package); + descriptors.withdraw(owner, contribution.descriptors); + }; + }, `typert.remotes.register(${JSON.stringify(contribution.package)})`); + } +} +class LookupStore { + providers = new Map(); + resolvers = new Map(); + definitions = new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + register: (key, provider) => this.register(ctx, key, provider), + configure: (key, resolver) => this.configure(ctx, key, resolver), + get: key => this.get(key), + definitions: () => [...this.definitions.values()], + keys: () => [...this.providers.keys()], + subscribe: listener => this.changes.subscribe(ctx, listener), + }; + } + get(key) { + const provider = this.providers.get(key)?.provider; + if (provider === undefined) + return undefined; + const resolver = this.resolvers.get(key)?.provider; + if (resolver === undefined) + return provider; + return { + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: id => resolver.resolve(id), + }; + } + configure(ctx, key, resolver) { + validateSegment('lookup key', key); + if (this.resolvers.has(key)) + throw new Error(`typert: lookup "${key}" resolver is already configured`); + const owner = {}; + // The map erases each merge-declared Wire type; restore it only at the + // typed configure() boundary so strict function variance remains sound. + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner, + }; + const { resolvers, changes } = this; + return ctx.effect(function* () { + resolvers.set(key, entry); + changes.emit({ kind: 'lookup', key }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (resolvers.get(key) !== entry) + return; + resolvers.delete(key); + changes.emit({ kind: 'lookup', key }); + }; + }, `typert.lookups.configure(${JSON.stringify(key)})`); + } + register(ctx, key, provider) { + validateSegment('lookup key', key); + validateSegment('lookup parameter', provider.parameter); + validateWireName('lookup wire field', provider.wire); + validateNonempty('lookup Host type symbol', provider.hostTypeSymbol); + validateNonempty('lookup wire type symbol', provider.wireTypeSymbol); + if (this.providers.has(key)) + throw new Error(`typert: lookup "${key}" is already registered`); + const definition = { + key, + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol, + }; + const known = this.definitions.get(key); + if (known !== undefined && !lookupDefinitionEquals(known, definition)) { + throw new Error(`typert: lookup "${key}" changed its wire declaration during this registry lifetime`); + } + const owner = {}; + const entry = { provider, owner }; + const { definitions, providers, changes } = this; + return ctx.effect(function* () { + definitions.set(key, definition); + providers.set(key, entry); + changes.emit({ kind: 'lookup', key }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (providers.get(key) !== entry) + return; + providers.delete(key); + changes.emit({ kind: 'lookup', key }); + }; + }, `typert.lookups.register(${JSON.stringify(key)})`); + } +} +function lookupDefinitionEquals(left, right) { + return left.parameter === right.parameter + && left.wire === right.wire + && left.hostTypeSymbol === right.hostTypeSymbol + && left.wireTypeSymbol === right.wireTypeSymbol; +} +class ContextStore { + hosts = new Map(); + hostResolvers = new Map(); + clients = new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + registerHost: (key, provider) => this.registerHost(ctx, key, provider), + configureHost: (key, resolver) => this.configureHost(ctx, key, resolver), + registerClient: (key, binder) => this.registerClient(ctx, key, binder), + getHost: key => this.getHost(key), + getClient: key => this.clients.get(key)?.provider, + subscribe: listener => this.changes.subscribe(ctx, listener), + }; + } + getHost(key) { + const provider = this.hosts.get(key)?.provider; + if (provider === undefined) + return undefined; + const resolver = this.hostResolvers.get(key)?.provider; + if (resolver === undefined) + return provider; + return { + wire: provider.wire, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: id => resolver.resolve(id), + }; + } + configureHost(ctx, key, resolver) { + validateSegment('Context key', key); + if (this.hostResolvers.has(key)) + throw new Error(`typert: host-context "${key}" resolver is already configured`); + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner: {}, + }; + const { hostResolvers, changes } = this; + return ctx.effect(function* () { + hostResolvers.set(key, entry); + changes.emit({ kind: 'host-context', key }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (hostResolvers.get(key) !== entry) + return; + hostResolvers.delete(key); + changes.emit({ kind: 'host-context', key }); + }; + }, `typert.contexts.configureHost(${JSON.stringify(key)})`); + } + registerHost(ctx, key, provider) { + validateSegment('Context key', key); + validateWireName('Context wire field', provider.wire); + validateNonempty('Context wire type symbol', provider.wireTypeSymbol); + return this.registerProvider(ctx, this.hosts, 'host-context', key, provider); + } + registerClient(ctx, key, binder) { + validateSegment('Context key', key); + return this.registerProvider(ctx, this.clients, 'client-context', key, binder); + } + registerProvider(ctx, table, kind, key, provider) { + if (table.has(key)) + throw new Error(`typert: ${kind} provider "${key}" is already registered`); + const entry = { provider, owner: {} }; + const { changes } = this; + return ctx.effect(function* () { + table.set(key, entry); + changes.emit({ kind, key }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (table.get(key) !== entry) + return; + table.delete(key); + changes.emit({ kind, key }); + }; + }, `typert.contexts.register(${JSON.stringify(key)})`); + } +} +/** + * Registry of generated schemas, package reflection, invocations, and Remote + * dependency providers. + * @typert service typert + */ +export class TypertRegistry extends Service { + schemas = new Map(); + packages = new Map(); + localStore; + remoteStore; + lookupStore; + contextStore; + constructor(ctx) { + super(ctx, 'typert'); + const report = (change, error) => { + ctx.logger.warn(`typert: ${change.kind} observer for "${change.key}" failed`); + ctx.logger.warn(error); + }; + this.localStore = new DescriptorStore('local', report); + this.remoteStore = new RemoteStore(new DescriptorStore('remote', report)); + this.lookupStore = new LookupStore(report); + this.contextStore = new ContextStore(report); + } + /** Current-environment invocation definitions. */ + get local() { + const ctx = this.ctx; + return { + get: endpoint => this.localStore.get(endpoint), + hasSeen: endpoint => this.localStore.hasSeen(endpoint), + list: () => this.localStore.list(), + subscribe: listener => this.localStore.subscribe(ctx, listener), + }; + } + /** Consumer-selected Remote definitions. */ + get remotes() { + return this.remoteStore.view(this.ctx); + } + /** Host object lookup providers. */ + get lookups() { + return this.lookupStore.view(this.ctx); + } + /** Host Context providers and Client Context binders. */ + get contexts() { + return this.contextStore.view(this.ctx); + } + /** + * Register one generated contribution atomically for the calling fiber. + * Duplicate package-face identities, schemas, invocation ids, or endpoints + * reject the whole batch. + * @param contribution - generated schemas, reflection, and Host invocations. + * @returns the exact effect disposer that removes this contribution. + */ + register(contribution) { + const packageRecord = this.validatePackage(contribution); + const schemaRecords = this.validateSchemas(contribution); + const invocations = contribution.invocations; + this.localStore.validate(invocations); + const owner = {}; + const { schemas, packages, localStore } = this; + return this.ctx.effect(function* () { + packages.set(packageRecord.key, packageRecord); + for (const record of schemaRecords) + schemas.set(record.key, record); + localStore.commit(owner, invocations); + yield () => { + /* v8 ignore else -- duplicate package-face registration is rejected, so this effect remains its unique owner. */ + if (packages.get(packageRecord.key) === packageRecord) + packages.delete(packageRecord.key); + for (const record of schemaRecords) { + /* v8 ignore else -- duplicate schema registration is rejected, so this contribution remains each record's unique owner. */ + if (schemas.get(record.key) === record) + schemas.delete(record.key); + } + localStore.withdraw(owner, invocations); + }; + }, 'typert.register()'); + } + /** + * Look up one schema by `#`. + * @param key - global schema key. + * @returns the live schema record, or `undefined` when absent. + */ + get(key) { + return this.schemas.get(key); + } + /** + * Resolve one required schema. + * @param key - global schema key. + * @returns the live schema record. + * @throws when the key is malformed, the package face is absent, or the schema is not contributed. + */ + resolve(key) { + const record = this.schemas.get(key); + if (record !== undefined) + return record; + const hash = key.indexOf('#'); + if (hash <= 0 || hash === key.length - 1) { + throw new Error(`typert: invalid schema key "${key}" — expected "#"`); + } + const packageName = key.slice(0, hash); + if ([...this.packages.values()].some(candidate => candidate.package === packageName)) { + throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" is registered but contributes no schema named "${key.slice(hash + 1)}"`); + } + throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" has no registered contribution`); + } + /** + * Enumerate live schemas in registration order. + * @param filter - optional package and face restriction. + * @returns matching schema records. + */ + list(filter = {}) { + return [...this.schemas.values()].filter(record => matches(record, filter)); + } + /** + * Look up generated reflection for one package face. + * @param packageName - exact npm package name. + * @param face - face to query; defaults to the host runtime. + * @returns the live package record, or `undefined` when absent. + */ + getPackage(packageName, face = 'host') { + return this.packages.get(typertPackageKey(packageName, face)); + } + /** + * Enumerate generated package reflection in registration order. + * @param filter - optional package and face restriction. + * @returns matching package records. + */ + listPackages(filter = {}) { + return [...this.packages.values()].filter(record => matches(record, filter)); + } + /** + * Project a live Zod schema to JSON Schema without caching the result. + * @param key - global schema key. + * @param params - Zod projection parameters. + * @returns a fresh JSON Schema document. + */ + toJSONSchema(key, params) { + return z.toJSONSchema(this.resolve(key).schema, params); + } + validatePackage(contribution) { + validateSegment('package name', contribution.package); + const face = contribution.face; + if (face !== 'host' && face !== 'client') { + throw new Error(`typert: invalid face ${JSON.stringify(face)} — expected "host" or "client"`); + } + const key = typertPackageKey(contribution.package, contribution.face); + if (this.packages.has(key)) { + throw new Error(`typert: package face "${key}" is already registered`); + } + return { + package: contribution.package, + face, + key, + model: contribution.model, + }; + } + validateSchemas(contribution) { + const records = []; + const batch = new Set(); + for (const schema of contribution.schemas) { + validateSegment('schema name', schema.name); + const key = typertKey(contribution.package, schema.name); + if (batch.has(key) || this.schemas.has(key)) { + throw new Error(`typert: schema "${key}" is already registered`); + } + batch.add(key); + records.push({ + ...schema, + package: contribution.package, + face: contribution.face, + key, + }); + } + return records; + } +} +function matches(record, filter) { + return (filter.package === undefined || record.package === filter.package) + && (filter.face === undefined || record.face === filter.face); +} +function validateInvocation(descriptor) { + validateNonempty('invocation id', descriptor.id); + validateSegment('invocation service key', descriptor.service); + validateWireName('invocation namespace', descriptor.namespace); + validateWireName('invocation method', descriptor.method); + if (descriptor.implementation !== undefined) { + validateWireName('invocation implementation method', descriptor.implementation); + } + validateCodec(descriptor.result, `${descriptor.id} result`); + const wires = new Set(); + for (const parameter of descriptor.parameters) { + validateWireName('parameter name', parameter.name); + validateWireName('parameter wire field', parameter.wire); + if (wires.has(parameter.wire)) { + throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${parameter.wire}"`); + } + wires.add(parameter.wire); + if (parameter.source === 'lookup') { + if (parameter.acceptsUndefined !== undefined) { + throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" cannot accept undefined`); + } + if (parameter.lookup === undefined) { + throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" has no lookup key`); + } + validateSegment('lookup key', parameter.lookup); + } + else if (parameter.lookup !== undefined) { + throw new Error(`typert: invocation "${descriptor.id}" JSON parameter "${parameter.name}" declares a lookup key`); + } + validateCodec(parameter.codec, `${descriptor.id} parameter ${parameter.name}`); + } + const cancellation = descriptor.cancellation; + if (cancellation !== undefined && cancellation.parameter !== 'signal') { + throw new Error(`typert: invocation "${descriptor.id}" cancellation parameter must be "signal"`); + } + if (descriptor.scope !== undefined) { + if (descriptor.invocation.kind !== 'direct') { + throw new Error(`typert: invocation "${descriptor.id}" Context receiver cannot declare a direct scope projection`); + } + validateSegment('scope Context key', descriptor.scope.context); + validateWireName('scope wire field', descriptor.scope.wire); + const lookups = descriptor.parameters.filter(candidate => candidate.source === 'lookup'); + const parameter = lookups.length === 1 ? lookups[0] : undefined; + if (parameter === undefined || parameter.wire !== descriptor.scope.wire + || parameter.lookup !== descriptor.scope.context) { + throw new Error(`typert: invocation "${descriptor.id}" scope wire "${descriptor.scope.wire}" must select its only lookup parameter`); + } + } + if (descriptor.invocation.kind === 'context') { + validateSegment('Context key', descriptor.invocation.context); + validateWireName('Context wire field', descriptor.invocation.wire); + if (wires.has(descriptor.invocation.wire)) { + throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${descriptor.invocation.wire}"`); + } + validateCodec(descriptor.invocation.codec, `${descriptor.id} Context`); + } +} +function validateCodec(codec, subject) { + if (codec.mode === 'src-json') + return; + validateNonempty(`${subject} type symbol`, codec.typeSymbol); + if (typeof codec.schema.parse !== 'function') { + throw new Error(`typert: ${subject} strict codec has no parse() method`); + } +} +function validateWireName(subject, value) { + if (value === '.' || value === '..' || !/^[A-Za-z0-9_$.-]+$/.test(value)) { + throw new Error(`typert: invalid ${subject} "${value}" — must contain only RPC endpoint segment characters`); + } +} +function validateSegment(subject, value) { + if (value.length === 0 || value.includes('#')) { + throw new Error(`typert: invalid ${subject} "${value}" — must be nonempty and must not contain "#"`); + } +} +function validateNonempty(subject, value) { + if (value.length === 0) + throw new Error(`typert: invalid ${subject} — must be nonempty`); +} +export default TypertRegistry; +//# sourceMappingURL=service.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.d.ts new file mode 100644 index 0000000..19acd82 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.d.ts @@ -0,0 +1,100 @@ +/** + * Pure generated-artifact and runtime-registry types. The registry stores Zod + * schemas separately from generated package reflection metadata. + * @module @deepseek-ai/dsh-typert-registry/types + */ +import type { z } from 'zod'; +import type { InvocationDescriptor } from '@deepseek-ai/dsh-typert-protocol'; +/** Independently compiled side that produced a contribution. */ +export type TypertFace = 'host' | 'client'; +/** Structured JSDoc tag retained by generated runtime metadata. */ +export interface TypertDocTag { + readonly name: string; + readonly argument?: string; + readonly comment?: string; + readonly text: string; +} +/** Source documentation retained on reflected package elements. */ +export interface TypertDocumentation { + readonly description?: string; + readonly summary?: string; + readonly tags: readonly TypertDocTag[]; + readonly jsDoc?: string; +} +/** One generated public member signature. */ +export interface TypertMemberModel { + readonly kind: 'property' | 'method' | 'getter' | 'setter' | 'call' | 'construct' | 'index'; + readonly name: string; + readonly signature: string; + readonly summary?: string; + readonly jsDoc?: string; +} +/** One named type declaration referenced by a reflected business surface. */ +export interface TypertTypeModel { + readonly name: string; + readonly declaration: string; +} +/** Runtime reflection metadata for one Cordis service. */ +export interface TypertServiceModel extends TypertDocumentation { + readonly key: string; + readonly exportName: string; + readonly members: readonly TypertMemberModel[]; + readonly types: readonly TypertTypeModel[]; +} +/** Runtime reflection metadata for one Cordis event. */ +export interface TypertEventModel extends TypertDocumentation { + readonly name: string; + readonly mode?: string; + readonly signature: string; +} +/** Runtime reflection metadata for one explicitly exported reference object. */ +export interface TypertObjectModel extends TypertDocumentation { + readonly name: string; + readonly exportName: string; + readonly members: readonly TypertMemberModel[]; + readonly types: readonly TypertTypeModel[]; +} +/** Generated business reflection for one package on one face. */ +export interface TypertPackageModel { + readonly services: readonly TypertServiceModel[]; + readonly events: readonly TypertEventModel[]; + readonly objects: readonly TypertObjectModel[]; +} +/** One generated live Zod schema. */ +export interface TypertSchema { + readonly name: string; + readonly schema: z.ZodType; +} +/** One generated package contribution registered and withdrawn atomically. */ +export interface TypertContribution { + readonly package: string; + readonly face: TypertFace; + readonly schemas: readonly TypertSchema[]; + readonly model: TypertPackageModel; + /** Host invocation definitions, empty when the package exports no Remote methods. */ + readonly invocations: readonly InvocationDescriptor[]; +} +/** A live schema plus its contribution identity. */ +export interface TypertSchemaRecord extends TypertSchema { + readonly package: string; + readonly face: TypertFace; + readonly key: string; +} +/** A live generated package model plus its stable identity. */ +export interface TypertPackageRecord { + readonly package: string; + readonly face: TypertFace; + readonly key: string; + readonly model: TypertPackageModel; +} +/** Filter for schema enumeration. */ +export interface TypertSchemaFilter { + readonly package?: string; + readonly face?: TypertFace; +} +/** Filter for package-model enumeration. */ +export interface TypertPackageFilter { + readonly package?: string; + readonly face?: TypertFace; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.js new file mode 100644 index 0000000..2891b59 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Pure generated-artifact and runtime-registry types. The registry stores Zod + * schemas separately from generated package reflection metadata. + * @module @deepseek-ai/dsh-typert-registry/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/package.json new file mode 100644 index 0000000..0b53b36 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/@deepseek-ai/dsh-typert-registry/package.json @@ -0,0 +1,67 @@ +{ + "name": "@deepseek-ai/dsh-typert-registry", + "description": "Runtime registry for generated package reflection and Zod schemas", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/typert/registry" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client/index.d.ts", + "default": "./lib/client.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "dsh": { + "client": { + "inject": [], + "platform": "web", + "immediately": true + } + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/client.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "scripts": { + "bundle": "tsdown", + "watch": "tsdown --watch" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_240a621969f076592d510095a63d96ca/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..a2fcff1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.i18n.yaml new file mode 100644 index 0000000..5730472 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/typert/registry/README.md +README.md: fa227b1c8faf1abd5a6492d4b8fe7d0c51ceeef1 +README.zh.md: b708e536acb7a5c4dc47e8c83180728e2ce150cd diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.md new file mode 100644 index 0000000..fa227b1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.md @@ -0,0 +1,33 @@ +# @deepseek-ai/dsh-typert-registry + +English | [中文](README.zh.md) + +Runtime registry for generated Typert artifacts. A contribution carries one package face's business reflection and optional live Zod schemas; `ctx.typert` registers both atomically and withdraws them with the calling Cordis fiber. TypeScript analysis and code generation live in [`dsh-typert-generator`](../generator/README.md). + +Package reflection is keyed by `#`. Schemas are keyed by `#` and retain the producer's Zod instance. JSON Schema is computed on demand at the consumer edge. + +## Public API + +- `TypertRegistry` is the default plugin and provides `ctx.typert`. +- `ctx.typert.lookups.register()` registers the wire declaration and default resolver owned by the business package; `configure()` registers a resolver owned by Host composition that may run asynchronously. Their lifetimes are independent: configuration may precede the provider, and unloading the configuration restores the default policy. +- `ctx.typert.contexts.registerHost()` and `configureHost()` apply the same ownership split to scoped Context identity; `registerClient()` supplies the corresponding Client Context binder. +- `register(contribution)` rejects malformed identities and duplicate package-face or schema keys before committing anything, then returns the exact Cordis effect disposer. +- `get(key)`, `resolve(key)`, and `list(filter?)` query live schemas. `resolve()` distinguishes a malformed key, an absent package, and a package that contributes no schema under that name. +- `getPackage(packageName, face?)` and `listPackages(filter?)` query generated service, event, and object reflection; the default face is `host`. +- `toJSONSchema(key, params?)` projects a live schema with `z.toJSONSchema()` without caching the result. +- `typertKey()` and `typertPackageKey()` compose the two stable identity forms. + +The `@deepseek-ai/dsh-typert-registry/types` subpath contains the pure contribution and record contracts. [`dsh-typert-loader`](../loader/README.md) discovers and registers generated host artifacts in Loader compositions; direct `ctx.typert.register()` supports other composition owners. + +## Model Experience + +None, as the registry contributes no prompt, tool, or session event; consumers such as `cordis_inspect` own any model-visible projection. + +#### KV Cache effect + +No direct effect. A consumer that places reflection in a request owns the resulting prefix change. + +## Known Limitations and Deferred Work + +- The registry stores generated reflection but does not merge host and client graphs or resolve TypeScript references. Those are analyzer and emitter concerns. +- Schema keys omit the face because host and client run in separate contexts. Registering same-named schemas from both faces into one context is rejected as a duplicate. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.zh.md new file mode 100644 index 0000000..b708e53 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/README.zh.md @@ -0,0 +1,33 @@ +# @deepseek-ai/dsh-typert-registry + +[English](README.md) | 中文 + +生成的 Typert 产物所用的运行时注册表。每个注册项包含某个包在一个 face 上的业务反射信息,以及可选的运行时 Zod schema;`ctx.typert` 会以原子方式同时注册两者,并在发起调用的 Cordis fiber 释放时一并移除它们。TypeScript 分析和代码生成由 [`dsh-typert-generator`](../generator/README.md) 负责。 + +包反射信息以 `#` 为键。schema 以 `#` 为键,并保留生成方的 Zod 实例。系统按需在消费方边界计算 JSON Schema。 + +## 公开 API + +- `TypertRegistry` 是默认插件,并提供 `ctx.typert`。 +- `ctx.typert.lookups.register()` 注册由业务包拥有的协议声明和默认解析器;`configure()` 注册由宿主组合拥有且可异步执行的解析器。两者的生命周期相互独立:配置可以先于提供方注册,卸载配置会恢复默认策略。 +- `ctx.typert.contexts.registerHost()` 和 `configureHost()` 对具作用域的上下文身份采用同样的所有权划分;`registerClient()` 提供对应的客户端上下文绑定器。 +- `register(contribution)` 会在提交任何内容之前拒绝格式错误的标识,以及重复的包与 face 组合键或 schema 键,随后返回 Cordis effect 提供的同一资源释放函数。 +- `get(key)`、`resolve(key)` 和 `list(filter?)` 查询当前有效的 schema。`resolve()` 能区分格式错误的键、未注册的包,以及已注册但未以该名称提供 schema 的包。 +- `getPackage(packageName, face?)` 和 `listPackages(filter?)` 查询生成的服务、事件和对象反射信息;默认 face 为 `host`。 +- `toJSONSchema(key, params?)` 使用 `z.toJSONSchema()` 投影当前有效的 schema,且不缓存结果。 +- `typertKey()` 和 `typertPackageKey()` 构造两种稳定的标识形式。 + +`@deepseek-ai/dsh-typert-registry/types` 子路径包含注册项和记录的纯类型约定。[`dsh-typert-loader`](../loader/README.md) 会在 Loader 组合中发现并注册生成的宿主侧产物;其他组合所有者可以直接调用 `ctx.typert.register()`。 + +## 模型体验 + +无。注册表不会提供提示词、工具或会话事件;所有模型可见投影均由 `cordis_inspect` 等消费方负责。 + +#### KV Cache 影响 + +无直接影响。将反射信息放入请求的消费方负责由此产生的前缀变化。 + +## 已知限制与暂缓事项 + +- 注册表存储生成的反射信息,但不会合并宿主侧与客户端侧的图,也不会解析 TypeScript 引用;这些由分析器和产物输出器负责。 +- schema 键不包含 face,因为宿主侧和客户端侧在不同的上下文中运行。若在同一上下文中注册来自两个 face 的同名 schema,系统会将其作为重复项拒绝。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/client.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/client.js new file mode 100644 index 0000000..c2a30e3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/client.js @@ -0,0 +1,1372 @@ +window.__ModuleLoader__.load({ + id: "@deepseek-ai/dsh-typert-registry", + factory: (require) => { + var module = { exports: {} }; + var exports = module.exports; + Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); + let _deepseek_ai_cordis = require("@deepseek-ai/cordis"); + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.js + function getEnumValues(entries) { + const numericValues = Object.values(entries).filter((v) => typeof v === "number"); + return Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v); + } + "captureStackTrace" in Error && Error.captureStackTrace; + Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, -Number.MAX_VALUE, Number.MAX_VALUE; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.js + var _a; + var $ZodRegistry = class { + constructor() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + } + add(schema, ..._meta) { + const meta = _meta[0]; + this._map.set(schema, meta); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.set(meta.id, schema); + return this; + } + clear() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + return this; + } + remove(schema) { + const meta = this._map.get(schema); + if (meta && typeof meta === "object" && "id" in meta) this._idmap.delete(meta.id); + this._map.delete(schema); + return this; + } + get(schema) { + const p = schema._zod.parent; + if (p) { + const pm = { ...this.get(p) ?? {} }; + delete pm.id; + const f = { + ...pm, + ...this._map.get(schema) + }; + return Object.keys(f).length ? f : void 0; + } + return this._map.get(schema); + } + has(schema) { + return this._map.has(schema); + } + }; + function registry() { + return new $ZodRegistry(); + } + (_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry()); + const globalRegistry = globalThis.__zod_globalRegistry; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.js + function initializeContext(params) { + let target = params?.target ?? "draft-2020-12"; + if (target === "draft-4") target = "draft-04"; + if (target === "draft-7") target = "draft-07"; + return { + processors: params.processors ?? {}, + metadataRegistry: params?.metadata ?? globalRegistry, + target, + unrepresentable: params?.unrepresentable ?? "throw", + override: params?.override ?? (() => {}), + io: params?.io ?? "output", + counter: 0, + seen: /* @__PURE__ */ new Map(), + cycles: params?.cycles ?? "ref", + reused: params?.reused ?? "inline", + external: params?.external ?? void 0 + }; + } + function process(schema, ctx, _params = { + path: [], + schemaPath: [] + }) { + var _a; + const def = schema._zod.def; + const seen = ctx.seen.get(schema); + if (seen) { + seen.count++; + if (_params.schemaPath.includes(schema)) seen.cycle = _params.path; + return seen.schema; + } + const result = { + schema: {}, + count: 1, + cycle: void 0, + path: _params.path + }; + ctx.seen.set(schema, result); + const overrideSchema = schema._zod.toJSONSchema?.(); + if (overrideSchema) result.schema = overrideSchema; + else { + const params = { + ..._params, + schemaPath: [..._params.schemaPath, schema], + path: _params.path + }; + if (schema._zod.processJSONSchema) schema._zod.processJSONSchema(ctx, result.schema, params); + else { + const _json = result.schema; + const processor = ctx.processors[def.type]; + if (!processor) throw new Error(`[toJSONSchema]: Non-representable type encountered: ${def.type}`); + processor(schema, ctx, _json, params); + } + const parent = schema._zod.parent; + if (parent) { + if (!result.ref) result.ref = parent; + process(parent, ctx, params); + ctx.seen.get(parent).isParent = true; + } + } + const meta = ctx.metadataRegistry.get(schema); + if (meta) Object.assign(result.schema, meta); + if (ctx.io === "input" && isTransforming(schema)) { + delete result.schema.examples; + delete result.schema.default; + } + if (ctx.io === "input" && "_prefault" in result.schema) (_a = result.schema).default ?? (_a.default = result.schema._prefault); + delete result.schema._prefault; + return ctx.seen.get(schema).schema; + } + function extractDefs(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const idToSchema = /* @__PURE__ */ new Map(); + for (const entry of ctx.seen.entries()) { + const id = ctx.metadataRegistry.get(entry[0])?.id; + if (id) { + const existing = idToSchema.get(id); + if (existing && existing !== entry[0]) throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`); + idToSchema.set(id, entry[0]); + } + } + const makeURI = (entry) => { + const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions"; + if (ctx.external) { + const externalId = ctx.external.registry.get(entry[0])?.id; + const uriGenerator = ctx.external.uri ?? ((id) => id); + if (externalId) return { ref: uriGenerator(externalId) }; + const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`; + entry[1].defId = id; + return { + defId: id, + ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` + }; + } + if (entry[1] === root) return { ref: "#" }; + const defUriPrefix = `#/${defsSegment}/`; + const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`; + return { + defId, + ref: defUriPrefix + defId + }; + }; + const extractToDef = (entry) => { + if (entry[1].schema.$ref) return; + const seen = entry[1]; + const { ref, defId } = makeURI(entry); + seen.def = { ...seen.schema }; + if (defId) seen.defId = defId; + const schema = seen.schema; + for (const key in schema) delete schema[key]; + schema.$ref = ref; + }; + if (ctx.cycles === "throw") for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.cycle) throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/ + +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`); + } + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (schema === entry[0]) { + extractToDef(entry); + continue; + } + if (ctx.external) { + const ext = ctx.external.registry.get(entry[0])?.id; + if (schema !== entry[0] && ext) { + extractToDef(entry); + continue; + } + } + if (ctx.metadataRegistry.get(entry[0])?.id) { + extractToDef(entry); + continue; + } + if (seen.cycle) { + extractToDef(entry); + continue; + } + if (seen.count > 1) { + if (ctx.reused === "ref") { + extractToDef(entry); + continue; + } + } + } + } + function finalize(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) throw new Error("Unprocessed schema. This is a bug in Zod."); + const flattenRef = (zodSchema) => { + const seen = ctx.seen.get(zodSchema); + if (seen.ref === null) return; + const schema = seen.def ?? seen.schema; + const _cached = { ...schema }; + const ref = seen.ref; + seen.ref = null; + if (ref) { + flattenRef(ref); + const refSeen = ctx.seen.get(ref); + const refSchema = refSeen.schema; + if (refSchema.$ref && (ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0")) { + schema.allOf = schema.allOf ?? []; + schema.allOf.push(refSchema); + } else Object.assign(schema, refSchema); + Object.assign(schema, _cached); + if (zodSchema._zod.parent === ref) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (!(key in _cached)) delete schema[key]; + } + if (refSchema.$ref && refSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in refSeen.def && JSON.stringify(schema[key]) === JSON.stringify(refSeen.def[key])) delete schema[key]; + } + } + const parent = zodSchema._zod.parent; + if (parent && parent !== ref) { + flattenRef(parent); + const parentSeen = ctx.seen.get(parent); + if (parentSeen?.schema.$ref) { + schema.$ref = parentSeen.schema.$ref; + if (parentSeen.def) for (const key in schema) { + if (key === "$ref" || key === "allOf") continue; + if (key in parentSeen.def && JSON.stringify(schema[key]) === JSON.stringify(parentSeen.def[key])) delete schema[key]; + } + } + } + ctx.override({ + zodSchema, + jsonSchema: schema, + path: seen.path ?? [] + }); + }; + for (const entry of [...ctx.seen.entries()].reverse()) flattenRef(entry[0]); + const result = {}; + if (ctx.target === "draft-2020-12") result.$schema = "https://json-schema.org/draft/2020-12/schema"; + else if (ctx.target === "draft-07") result.$schema = "http://json-schema.org/draft-07/schema#"; + else if (ctx.target === "draft-04") result.$schema = "http://json-schema.org/draft-04/schema#"; + else if (ctx.target === "openapi-3.0") {} + if (ctx.external?.uri) { + const id = ctx.external.registry.get(schema)?.id; + if (!id) throw new Error("Schema is missing an `id` property"); + result.$id = ctx.external.uri(id); + } + Object.assign(result, root.def ?? root.schema); + const rootMetaId = ctx.metadataRegistry.get(schema)?.id; + if (rootMetaId !== void 0 && result.id === rootMetaId) delete result.id; + const defs = ctx.external?.defs ?? {}; + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.def && seen.defId) { + if (seen.def.id === seen.defId) delete seen.def.id; + defs[seen.defId] = seen.def; + } + } + if (ctx.external) {} else if (Object.keys(defs).length > 0) if (ctx.target === "draft-2020-12") result.$defs = defs; + else result.definitions = defs; + try { + const finalized = JSON.parse(JSON.stringify(result)); + Object.defineProperty(finalized, "~standard", { + value: { + ...schema["~standard"], + jsonSchema: { + input: createStandardJSONSchemaMethod(schema, "input", ctx.processors), + output: createStandardJSONSchemaMethod(schema, "output", ctx.processors) + } + }, + enumerable: false, + writable: false + }); + return finalized; + } catch (_err) { + throw new Error("Error converting schema to JSON."); + } + } + function isTransforming(_schema, _ctx) { + const ctx = _ctx ?? { seen: /* @__PURE__ */ new Set() }; + if (ctx.seen.has(_schema)) return false; + ctx.seen.add(_schema); + const def = _schema._zod.def; + if (def.type === "transform") return true; + if (def.type === "array") return isTransforming(def.element, ctx); + if (def.type === "set") return isTransforming(def.valueType, ctx); + if (def.type === "lazy") return isTransforming(def.getter(), ctx); + if (def.type === "promise" || def.type === "optional" || def.type === "nonoptional" || def.type === "nullable" || def.type === "readonly" || def.type === "default" || def.type === "prefault") return isTransforming(def.innerType, ctx); + if (def.type === "intersection") return isTransforming(def.left, ctx) || isTransforming(def.right, ctx); + if (def.type === "record" || def.type === "map") return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); + if (def.type === "pipe") { + if (_schema._zod.traits.has("$ZodCodec")) return true; + return isTransforming(def.in, ctx) || isTransforming(def.out, ctx); + } + if (def.type === "object") { + for (const key in def.shape) if (isTransforming(def.shape[key], ctx)) return true; + return false; + } + if (def.type === "union") { + for (const option of def.options) if (isTransforming(option, ctx)) return true; + return false; + } + if (def.type === "tuple") { + for (const item of def.items) if (isTransforming(item, ctx)) return true; + if (def.rest && isTransforming(def.rest, ctx)) return true; + return false; + } + return false; + } + const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => { + const { libraryOptions, target } = params ?? {}; + const ctx = initializeContext({ + ...libraryOptions ?? {}, + target, + io, + processors + }); + process(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); + }; + //#endregion + //#region ../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.js + const formatMap = { + guid: "uuid", + url: "uri", + datetime: "date-time", + json_string: "json-string", + regex: "" + }; + const stringProcessor = (schema, ctx, _json, _params) => { + const json = _json; + json.type = "string"; + const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag; + if (typeof minimum === "number") json.minLength = minimum; + if (typeof maximum === "number") json.maxLength = maximum; + if (format) { + json.format = formatMap[format] ?? format; + if (json.format === "") delete json.format; + if (format === "time") delete json.format; + } + if (contentEncoding) json.contentEncoding = contentEncoding; + if (patterns && patterns.size > 0) { + const regexes = [...patterns]; + if (regexes.length === 1) json.pattern = regexes[0].source; + else if (regexes.length > 1) json.allOf = [...regexes.map((regex) => ({ + ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {}, + pattern: regex.source + }))]; + } + }; + const numberProcessor = (schema, ctx, _json, _params) => { + const json = _json; + const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; + if (typeof format === "string" && format.includes("int")) json.type = "integer"; + else json.type = "number"; + const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY); + const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY); + const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0"; + if (exMin) if (legacy) { + json.minimum = exclusiveMinimum; + json.exclusiveMinimum = true; + } else json.exclusiveMinimum = exclusiveMinimum; + else if (typeof minimum === "number") json.minimum = minimum; + if (exMax) if (legacy) { + json.maximum = exclusiveMaximum; + json.exclusiveMaximum = true; + } else json.exclusiveMaximum = exclusiveMaximum; + else if (typeof maximum === "number") json.maximum = maximum; + if (typeof multipleOf === "number") json.multipleOf = multipleOf; + }; + const booleanProcessor = (_schema, _ctx, json, _params) => { + json.type = "boolean"; + }; + const bigintProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("BigInt cannot be represented in JSON Schema"); + }; + const symbolProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Symbols cannot be represented in JSON Schema"); + }; + const nullProcessor = (_schema, ctx, json, _params) => { + if (ctx.target === "openapi-3.0") { + json.type = "string"; + json.nullable = true; + json.enum = [null]; + } else json.type = "null"; + }; + const undefinedProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Undefined cannot be represented in JSON Schema"); + }; + const voidProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Void cannot be represented in JSON Schema"); + }; + const neverProcessor = (_schema, _ctx, json, _params) => { + json.not = {}; + }; + const anyProcessor = (_schema, _ctx, _json, _params) => {}; + const unknownProcessor = (_schema, _ctx, _json, _params) => {}; + const dateProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Date cannot be represented in JSON Schema"); + }; + const enumProcessor = (schema, _ctx, json, _params) => { + const def = schema._zod.def; + const values = getEnumValues(def.entries); + if (values.every((v) => typeof v === "number")) json.type = "number"; + if (values.every((v) => typeof v === "string")) json.type = "string"; + json.enum = values; + }; + const literalProcessor = (schema, ctx, json, _params) => { + const def = schema._zod.def; + const vals = []; + for (const val of def.values) if (val === void 0) { + if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema"); + } else if (typeof val === "bigint") if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema"); + else vals.push(Number(val)); + else vals.push(val); + if (vals.length === 0) {} else if (vals.length === 1) { + const val = vals[0]; + json.type = val === null ? "null" : typeof val; + if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") json.enum = [val]; + else json.const = val; + } else { + if (vals.every((v) => typeof v === "number")) json.type = "number"; + if (vals.every((v) => typeof v === "string")) json.type = "string"; + if (vals.every((v) => typeof v === "boolean")) json.type = "boolean"; + if (vals.every((v) => v === null)) json.type = "null"; + json.enum = vals; + } + }; + const nanProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("NaN cannot be represented in JSON Schema"); + }; + const templateLiteralProcessor = (schema, _ctx, json, _params) => { + const _json = json; + const pattern = schema._zod.pattern; + if (!pattern) throw new Error("Pattern not found in template literal"); + _json.type = "string"; + _json.pattern = pattern.source; + }; + const fileProcessor = (schema, _ctx, json, _params) => { + const _json = json; + const file = { + type: "string", + format: "binary", + contentEncoding: "binary" + }; + const { minimum, maximum, mime } = schema._zod.bag; + if (minimum !== void 0) file.minLength = minimum; + if (maximum !== void 0) file.maxLength = maximum; + if (mime) if (mime.length === 1) { + file.contentMediaType = mime[0]; + Object.assign(_json, file); + } else { + Object.assign(_json, file); + _json.anyOf = mime.map((m) => ({ contentMediaType: m })); + } + else Object.assign(_json, file); + }; + const successProcessor = (_schema, _ctx, json, _params) => { + json.type = "boolean"; + }; + const customProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Custom types cannot be represented in JSON Schema"); + }; + const functionProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Function types cannot be represented in JSON Schema"); + }; + const transformProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Transforms cannot be represented in JSON Schema"); + }; + const mapProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Map cannot be represented in JSON Schema"); + }; + const setProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") throw new Error("Set cannot be represented in JSON Schema"); + }; + const arrayProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") json.minItems = minimum; + if (typeof maximum === "number") json.maxItems = maximum; + json.type = "array"; + json.items = process(def.element, ctx, { + ...params, + path: [...params.path, "items"] + }); + }; + const objectProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + json.properties = {}; + const shape = def.shape; + for (const key in shape) json.properties[key] = process(shape[key], ctx, { + ...params, + path: [ + ...params.path, + "properties", + key + ] + }); + const allKeys = new Set(Object.keys(shape)); + const requiredKeys = new Set([...allKeys].filter((key) => { + const v = def.shape[key]._zod; + if (ctx.io === "input") return v.optin === void 0; + else return v.optout === void 0; + })); + if (requiredKeys.size > 0) json.required = Array.from(requiredKeys); + if (def.catchall?._zod.def.type === "never") json.additionalProperties = false; + else if (!def.catchall) { + if (ctx.io === "output") json.additionalProperties = false; + } else if (def.catchall) json.additionalProperties = process(def.catchall, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + }; + const unionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const isExclusive = def.inclusive === false; + const options = def.options.map((x, i) => process(x, ctx, { + ...params, + path: [ + ...params.path, + isExclusive ? "oneOf" : "anyOf", + i + ] + })); + if (isExclusive) json.oneOf = options; + else json.anyOf = options; + }; + const intersectionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const a = process(def.left, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 0 + ] + }); + const b = process(def.right, ctx, { + ...params, + path: [ + ...params.path, + "allOf", + 1 + ] + }); + const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1; + json.allOf = [...isSimpleIntersection(a) ? a.allOf : [a], ...isSimpleIntersection(b) ? b.allOf : [b]]; + }; + const tupleProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "array"; + const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items"; + const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems"; + const prefixItems = def.items.map((x, i) => process(x, ctx, { + ...params, + path: [ + ...params.path, + prefixPath, + i + ] + })); + const rest = def.rest ? process(def.rest, ctx, { + ...params, + path: [ + ...params.path, + restPath, + ...ctx.target === "openapi-3.0" ? [def.items.length] : [] + ] + }) : null; + if (ctx.target === "draft-2020-12") { + json.prefixItems = prefixItems; + if (rest) json.items = rest; + } else if (ctx.target === "openapi-3.0") { + json.items = { anyOf: prefixItems }; + if (rest) json.items.anyOf.push(rest); + json.minItems = prefixItems.length; + if (!rest) json.maxItems = prefixItems.length; + } else { + json.items = prefixItems; + if (rest) json.additionalItems = rest; + } + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") json.minItems = minimum; + if (typeof maximum === "number") json.maxItems = maximum; + }; + const recordProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + const keyType = def.keyType; + const patterns = keyType._zod.bag?.patterns; + if (def.mode === "loose" && patterns && patterns.size > 0) { + const valueSchema = process(def.valueType, ctx, { + ...params, + path: [ + ...params.path, + "patternProperties", + "*" + ] + }); + json.patternProperties = {}; + for (const pattern of patterns) json.patternProperties[pattern.source] = valueSchema; + } else { + if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") json.propertyNames = process(def.keyType, ctx, { + ...params, + path: [...params.path, "propertyNames"] + }); + json.additionalProperties = process(def.valueType, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + } + const keyValues = keyType._zod.values; + if (keyValues) { + const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number"); + if (validKeyValues.length > 0) json.required = validKeyValues; + } + }; + const nullableProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const inner = process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + if (ctx.target === "openapi-3.0") { + seen.ref = def.innerType; + json.nullable = true; + } else json.anyOf = [inner, { type: "null" }]; + }; + const nonoptionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const defaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.default = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const prefaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + if (ctx.io === "input") json._prefault = JSON.parse(JSON.stringify(def.defaultValue)); + }; + const catchProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + let catchValue; + try { + catchValue = def.catchValue(void 0); + } catch { + throw new Error("Dynamic catch values are not supported in JSON Schema"); + } + json.default = catchValue; + }; + const pipeProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + const inIsTransform = def.in._zod.traits.has("$ZodTransform"); + const innerType = ctx.io === "input" ? inIsTransform ? def.out : def.in : def.out; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + const readonlyProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.readOnly = true; + }; + const promiseProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const optionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + }; + const lazyProcessor = (schema, ctx, _json, params) => { + const innerType = schema._zod.innerType; + process(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; + }; + const allProcessors = { + string: stringProcessor, + number: numberProcessor, + boolean: booleanProcessor, + bigint: bigintProcessor, + symbol: symbolProcessor, + null: nullProcessor, + undefined: undefinedProcessor, + void: voidProcessor, + never: neverProcessor, + any: anyProcessor, + unknown: unknownProcessor, + date: dateProcessor, + enum: enumProcessor, + literal: literalProcessor, + nan: nanProcessor, + template_literal: templateLiteralProcessor, + file: fileProcessor, + success: successProcessor, + custom: customProcessor, + function: functionProcessor, + transform: transformProcessor, + map: mapProcessor, + set: setProcessor, + array: arrayProcessor, + object: objectProcessor, + union: unionProcessor, + intersection: intersectionProcessor, + tuple: tupleProcessor, + record: recordProcessor, + nullable: nullableProcessor, + nonoptional: nonoptionalProcessor, + default: defaultProcessor, + prefault: prefaultProcessor, + catch: catchProcessor, + pipe: pipeProcessor, + readonly: readonlyProcessor, + promise: promiseProcessor, + optional: optionalProcessor, + lazy: lazyProcessor + }; + function toJSONSchema(input, params) { + if ("_idmap" in input) { + const registry = input; + const ctx = initializeContext({ + ...params, + processors: allProcessors + }); + const defs = {}; + for (const entry of registry._idmap.entries()) { + const [_, schema] = entry; + process(schema, ctx); + } + const schemas = {}; + ctx.external = { + registry, + uri: params?.uri, + defs + }; + for (const entry of registry._idmap.entries()) { + const [key, schema] = entry; + extractDefs(ctx, schema); + schemas[key] = finalize(ctx, schema); + } + if (Object.keys(defs).length > 0) schemas.__shared = { [ctx.target === "draft-2020-12" ? "$defs" : "definitions"]: defs }; + return { schemas }; + } + const ctx = initializeContext({ + ...params, + processors: allProcessors + }); + process(input, ctx); + extractDefs(ctx, input); + return finalize(ctx, input); + } + //#endregion + //#region lib/types/service.js + /** + * Runtime registry for generated Typert reflection, Remote invocations, and + * dependency-inverted lookup/Context providers. It performs no TypeScript + * analysis or schema generation. + * @module @deepseek-ai/dsh-typert-registry + */ + /** + * Compose the global key of one generated schema. + * @param packageName - contributing npm package. + * @param name - schema export name. + * @returns `#`. + */ + function typertKey(packageName, name) { + return `${packageName}#${name}`; + } + /** + * Compose the identity of one package-face model. + * @param packageName - contributing npm package. + * @param face - independently compiled face. + * @returns `#`. + */ + function typertPackageKey(packageName, face) { + return `${packageName}#${face}`; + } + /** + * Compose the endpoint key used by local and Remote invocation registries. + * @param descriptor - invocation whose namespace and method form the endpoint. + * @returns `/`. + */ + function typertEndpoint(descriptor) { + return `${descriptor.namespace}/${descriptor.method}`; + } + var ChangeSource = class { + report; + listeners = /* @__PURE__ */ new Set(); + constructor(report) { + this.report = report; + } + subscribe(ctx, listener) { + const { listeners } = this; + return ctx.effect(function* () { + listeners.add(listener); + yield () => { + listeners.delete(listener); + }; + }, "typert registry subscription"); + } + emit(change) { + for (const listener of [...this.listeners]) try { + listener(change); + } catch (error) { + this.report(change, error); + } + } + }; + var DescriptorStore = class { + kind; + entries = /* @__PURE__ */ new Map(); + ids = /* @__PURE__ */ new Map(); + history = /* @__PURE__ */ new Set(); + changes; + constructor(kind, report) { + this.kind = kind; + this.changes = new ChangeSource(report); + } + validate(descriptors) { + const endpoints = /* @__PURE__ */ new Set(); + const ids = /* @__PURE__ */ new Set(); + for (const descriptor of descriptors) { + validateInvocation(descriptor); + const endpoint = typertEndpoint(descriptor); + if (endpoints.has(endpoint) || this.entries.has(endpoint)) throw new Error(`typert: ${this.kind} endpoint "${endpoint}" is already registered`); + if (ids.has(descriptor.id) || this.ids.has(descriptor.id)) throw new Error(`typert: ${this.kind} invocation id "${descriptor.id}" is already registered`); + endpoints.add(endpoint); + ids.add(descriptor.id); + } + } + commit(owner, descriptors) { + for (const descriptor of descriptors) { + const entry = { + descriptor, + owner + }; + const endpoint = typertEndpoint(descriptor); + this.entries.set(endpoint, entry); + this.ids.set(descriptor.id, entry); + this.history.add(endpoint); + } + for (const descriptor of descriptors) this.changes.emit({ + kind: this.kind, + key: typertEndpoint(descriptor) + }); + } + withdraw(owner, descriptors) { + const removed = []; + for (const descriptor of descriptors) { + const endpoint = typertEndpoint(descriptor); + const entry = this.entries.get(endpoint); + /* v8 ignore next -- duplicate registration is rejected, so no later owner can replace this entry before its effect disposes. */ + if (entry?.owner !== owner) continue; + this.entries.delete(endpoint); + /* v8 ignore next -- ids and endpoints are committed and withdrawn together under the same unique owner. */ + if (this.ids.get(descriptor.id) === entry) this.ids.delete(descriptor.id); + removed.push(endpoint); + } + for (const endpoint of removed) this.changes.emit({ + kind: this.kind, + key: endpoint + }); + } + get(endpoint) { + return this.entries.get(endpoint)?.descriptor; + } + hasSeen(endpoint) { + return this.history.has(endpoint); + } + list() { + return [...this.entries.values()].map((entry) => entry.descriptor); + } + subscribe(ctx, listener) { + return this.changes.subscribe(ctx, listener); + } + }; + var RemoteStore = class { + descriptors; + packages = /* @__PURE__ */ new Map(); + constructor(descriptors) { + this.descriptors = descriptors; + } + view(ctx) { + return { + register: (contribution) => this.register(ctx, contribution), + get: (endpoint) => this.descriptors.get(endpoint), + list: () => this.descriptors.list(), + subscribe: (listener) => this.descriptors.subscribe(ctx, listener) + }; + } + register(ctx, contribution) { + validateSegment("Remote package name", contribution.package); + if (this.packages.has(contribution.package)) throw new Error(`typert: Remote package "${contribution.package}" is already registered`); + this.descriptors.validate(contribution.descriptors); + const owner = {}; + const { packages, descriptors } = this; + return ctx.effect(function* () { + packages.set(contribution.package, owner); + descriptors.commit(owner, contribution.descriptors); + yield () => { + /* v8 ignore else -- duplicate package registration is rejected, so this effect remains the package's unique owner. */ + if (packages.get(contribution.package) === owner) packages.delete(contribution.package); + descriptors.withdraw(owner, contribution.descriptors); + }; + }, `typert.remotes.register(${JSON.stringify(contribution.package)})`); + } + }; + var LookupStore = class { + providers = /* @__PURE__ */ new Map(); + resolvers = /* @__PURE__ */ new Map(); + definitions = /* @__PURE__ */ new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + register: (key, provider) => this.register(ctx, key, provider), + configure: (key, resolver) => this.configure(ctx, key, resolver), + get: (key) => this.get(key), + definitions: () => [...this.definitions.values()], + keys: () => [...this.providers.keys()], + subscribe: (listener) => this.changes.subscribe(ctx, listener) + }; + } + get(key) { + const provider = this.providers.get(key)?.provider; + if (provider === void 0) return void 0; + const resolver = this.resolvers.get(key)?.provider; + if (resolver === void 0) return provider; + return { + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: (id) => resolver.resolve(id) + }; + } + configure(ctx, key, resolver) { + validateSegment("lookup key", key); + if (this.resolvers.has(key)) throw new Error(`typert: lookup "${key}" resolver is already configured`); + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner: {} + }; + const { resolvers, changes } = this; + return ctx.effect(function* () { + resolvers.set(key, entry); + changes.emit({ + kind: "lookup", + key + }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (resolvers.get(key) !== entry) return; + resolvers.delete(key); + changes.emit({ + kind: "lookup", + key + }); + }; + }, `typert.lookups.configure(${JSON.stringify(key)})`); + } + register(ctx, key, provider) { + validateSegment("lookup key", key); + validateSegment("lookup parameter", provider.parameter); + validateWireName("lookup wire field", provider.wire); + validateNonempty("lookup Host type symbol", provider.hostTypeSymbol); + validateNonempty("lookup wire type symbol", provider.wireTypeSymbol); + if (this.providers.has(key)) throw new Error(`typert: lookup "${key}" is already registered`); + const definition = { + key, + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol + }; + const known = this.definitions.get(key); + if (known !== void 0 && !lookupDefinitionEquals(known, definition)) throw new Error(`typert: lookup "${key}" changed its wire declaration during this registry lifetime`); + const entry = { + provider, + owner: {} + }; + const { definitions, providers, changes } = this; + return ctx.effect(function* () { + definitions.set(key, definition); + providers.set(key, entry); + changes.emit({ + kind: "lookup", + key + }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (providers.get(key) !== entry) return; + providers.delete(key); + changes.emit({ + kind: "lookup", + key + }); + }; + }, `typert.lookups.register(${JSON.stringify(key)})`); + } + }; + function lookupDefinitionEquals(left, right) { + return left.parameter === right.parameter && left.wire === right.wire && left.hostTypeSymbol === right.hostTypeSymbol && left.wireTypeSymbol === right.wireTypeSymbol; + } + var ContextStore = class { + hosts = /* @__PURE__ */ new Map(); + hostResolvers = /* @__PURE__ */ new Map(); + clients = /* @__PURE__ */ new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + registerHost: (key, provider) => this.registerHost(ctx, key, provider), + configureHost: (key, resolver) => this.configureHost(ctx, key, resolver), + registerClient: (key, binder) => this.registerClient(ctx, key, binder), + getHost: (key) => this.getHost(key), + getClient: (key) => this.clients.get(key)?.provider, + subscribe: (listener) => this.changes.subscribe(ctx, listener) + }; + } + getHost(key) { + const provider = this.hosts.get(key)?.provider; + if (provider === void 0) return void 0; + const resolver = this.hostResolvers.get(key)?.provider; + if (resolver === void 0) return provider; + return { + wire: provider.wire, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: (id) => resolver.resolve(id) + }; + } + configureHost(ctx, key, resolver) { + validateSegment("Context key", key); + if (this.hostResolvers.has(key)) throw new Error(`typert: host-context "${key}" resolver is already configured`); + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner: {} + }; + const { hostResolvers, changes } = this; + return ctx.effect(function* () { + hostResolvers.set(key, entry); + changes.emit({ + kind: "host-context", + key + }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (hostResolvers.get(key) !== entry) return; + hostResolvers.delete(key); + changes.emit({ + kind: "host-context", + key + }); + }; + }, `typert.contexts.configureHost(${JSON.stringify(key)})`); + } + registerHost(ctx, key, provider) { + validateSegment("Context key", key); + validateWireName("Context wire field", provider.wire); + validateNonempty("Context wire type symbol", provider.wireTypeSymbol); + return this.registerProvider(ctx, this.hosts, "host-context", key, provider); + } + registerClient(ctx, key, binder) { + validateSegment("Context key", key); + return this.registerProvider(ctx, this.clients, "client-context", key, binder); + } + registerProvider(ctx, table, kind, key, provider) { + if (table.has(key)) throw new Error(`typert: ${kind} provider "${key}" is already registered`); + const entry = { + provider, + owner: {} + }; + const { changes } = this; + return ctx.effect(function* () { + table.set(key, entry); + changes.emit({ + kind, + key + }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (table.get(key) !== entry) return; + table.delete(key); + changes.emit({ + kind, + key + }); + }; + }, `typert.contexts.register(${JSON.stringify(key)})`); + } + }; + /** + * Registry of generated schemas, package reflection, invocations, and Remote + * dependency providers. + * @typert service typert + */ + var TypertRegistry = class extends _deepseek_ai_cordis.Service { + schemas = /* @__PURE__ */ new Map(); + packages = /* @__PURE__ */ new Map(); + localStore; + remoteStore; + lookupStore; + contextStore; + constructor(ctx) { + super(ctx, "typert"); + const report = (change, error) => { + ctx.logger.warn(`typert: ${change.kind} observer for "${change.key}" failed`); + ctx.logger.warn(error); + }; + this.localStore = new DescriptorStore("local", report); + this.remoteStore = new RemoteStore(new DescriptorStore("remote", report)); + this.lookupStore = new LookupStore(report); + this.contextStore = new ContextStore(report); + } + /** Current-environment invocation definitions. */ + get local() { + const ctx = this.ctx; + return { + get: (endpoint) => this.localStore.get(endpoint), + hasSeen: (endpoint) => this.localStore.hasSeen(endpoint), + list: () => this.localStore.list(), + subscribe: (listener) => this.localStore.subscribe(ctx, listener) + }; + } + /** Consumer-selected Remote definitions. */ + get remotes() { + return this.remoteStore.view(this.ctx); + } + /** Host object lookup providers. */ + get lookups() { + return this.lookupStore.view(this.ctx); + } + /** Host Context providers and Client Context binders. */ + get contexts() { + return this.contextStore.view(this.ctx); + } + /** + * Register one generated contribution atomically for the calling fiber. + * Duplicate package-face identities, schemas, invocation ids, or endpoints + * reject the whole batch. + * @param contribution - generated schemas, reflection, and Host invocations. + * @returns the exact effect disposer that removes this contribution. + */ + register(contribution) { + const packageRecord = this.validatePackage(contribution); + const schemaRecords = this.validateSchemas(contribution); + const invocations = contribution.invocations; + this.localStore.validate(invocations); + const owner = {}; + const { schemas, packages, localStore } = this; + return this.ctx.effect(function* () { + packages.set(packageRecord.key, packageRecord); + for (const record of schemaRecords) schemas.set(record.key, record); + localStore.commit(owner, invocations); + yield () => { + /* v8 ignore else -- duplicate package-face registration is rejected, so this effect remains its unique owner. */ + if (packages.get(packageRecord.key) === packageRecord) packages.delete(packageRecord.key); + for (const record of schemaRecords) + /* v8 ignore else -- duplicate schema registration is rejected, so this contribution remains each record's unique owner. */ + if (schemas.get(record.key) === record) schemas.delete(record.key); + localStore.withdraw(owner, invocations); + }; + }, "typert.register()"); + } + /** + * Look up one schema by `#`. + * @param key - global schema key. + * @returns the live schema record, or `undefined` when absent. + */ + get(key) { + return this.schemas.get(key); + } + /** + * Resolve one required schema. + * @param key - global schema key. + * @returns the live schema record. + * @throws when the key is malformed, the package face is absent, or the schema is not contributed. + */ + resolve(key) { + const record = this.schemas.get(key); + if (record !== void 0) return record; + const hash = key.indexOf("#"); + if (hash <= 0 || hash === key.length - 1) throw new Error(`typert: invalid schema key "${key}" — expected "#"`); + const packageName = key.slice(0, hash); + if ([...this.packages.values()].some((candidate) => candidate.package === packageName)) throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" is registered but contributes no schema named "${key.slice(hash + 1)}"`); + throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" has no registered contribution`); + } + /** + * Enumerate live schemas in registration order. + * @param filter - optional package and face restriction. + * @returns matching schema records. + */ + list(filter = {}) { + return [...this.schemas.values()].filter((record) => matches(record, filter)); + } + /** + * Look up generated reflection for one package face. + * @param packageName - exact npm package name. + * @param face - face to query; defaults to the host runtime. + * @returns the live package record, or `undefined` when absent. + */ + getPackage(packageName, face = "host") { + return this.packages.get(typertPackageKey(packageName, face)); + } + /** + * Enumerate generated package reflection in registration order. + * @param filter - optional package and face restriction. + * @returns matching package records. + */ + listPackages(filter = {}) { + return [...this.packages.values()].filter((record) => matches(record, filter)); + } + /** + * Project a live Zod schema to JSON Schema without caching the result. + * @param key - global schema key. + * @param params - Zod projection parameters. + * @returns a fresh JSON Schema document. + */ + toJSONSchema(key, params) { + return toJSONSchema(this.resolve(key).schema, params); + } + validatePackage(contribution) { + validateSegment("package name", contribution.package); + const face = contribution.face; + if (face !== "host" && face !== "client") throw new Error(`typert: invalid face ${JSON.stringify(face)} — expected "host" or "client"`); + const key = typertPackageKey(contribution.package, contribution.face); + if (this.packages.has(key)) throw new Error(`typert: package face "${key}" is already registered`); + return { + package: contribution.package, + face, + key, + model: contribution.model + }; + } + validateSchemas(contribution) { + const records = []; + const batch = /* @__PURE__ */ new Set(); + for (const schema of contribution.schemas) { + validateSegment("schema name", schema.name); + const key = typertKey(contribution.package, schema.name); + if (batch.has(key) || this.schemas.has(key)) throw new Error(`typert: schema "${key}" is already registered`); + batch.add(key); + records.push({ + ...schema, + package: contribution.package, + face: contribution.face, + key + }); + } + return records; + } + }; + function matches(record, filter) { + return (filter.package === void 0 || record.package === filter.package) && (filter.face === void 0 || record.face === filter.face); + } + function validateInvocation(descriptor) { + validateNonempty("invocation id", descriptor.id); + validateSegment("invocation service key", descriptor.service); + validateWireName("invocation namespace", descriptor.namespace); + validateWireName("invocation method", descriptor.method); + if (descriptor.implementation !== void 0) validateWireName("invocation implementation method", descriptor.implementation); + validateCodec(descriptor.result, `${descriptor.id} result`); + const wires = /* @__PURE__ */ new Set(); + for (const parameter of descriptor.parameters) { + validateWireName("parameter name", parameter.name); + validateWireName("parameter wire field", parameter.wire); + if (wires.has(parameter.wire)) throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${parameter.wire}"`); + wires.add(parameter.wire); + if (parameter.source === "lookup") { + if (parameter.acceptsUndefined !== void 0) throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" cannot accept undefined`); + if (parameter.lookup === void 0) throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" has no lookup key`); + validateSegment("lookup key", parameter.lookup); + } else if (parameter.lookup !== void 0) throw new Error(`typert: invocation "${descriptor.id}" JSON parameter "${parameter.name}" declares a lookup key`); + validateCodec(parameter.codec, `${descriptor.id} parameter ${parameter.name}`); + } + const cancellation = descriptor.cancellation; + if (cancellation !== void 0 && cancellation.parameter !== "signal") throw new Error(`typert: invocation "${descriptor.id}" cancellation parameter must be "signal"`); + if (descriptor.scope !== void 0) { + if (descriptor.invocation.kind !== "direct") throw new Error(`typert: invocation "${descriptor.id}" Context receiver cannot declare a direct scope projection`); + validateSegment("scope Context key", descriptor.scope.context); + validateWireName("scope wire field", descriptor.scope.wire); + const lookups = descriptor.parameters.filter((candidate) => candidate.source === "lookup"); + const parameter = lookups.length === 1 ? lookups[0] : void 0; + if (parameter === void 0 || parameter.wire !== descriptor.scope.wire || parameter.lookup !== descriptor.scope.context) throw new Error(`typert: invocation "${descriptor.id}" scope wire "${descriptor.scope.wire}" must select its only lookup parameter`); + } + if (descriptor.invocation.kind === "context") { + validateSegment("Context key", descriptor.invocation.context); + validateWireName("Context wire field", descriptor.invocation.wire); + if (wires.has(descriptor.invocation.wire)) throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${descriptor.invocation.wire}"`); + validateCodec(descriptor.invocation.codec, `${descriptor.id} Context`); + } + } + function validateCodec(codec, subject) { + if (codec.mode === "src-json") return; + validateNonempty(`${subject} type symbol`, codec.typeSymbol); + if (typeof codec.schema.parse !== "function") throw new Error(`typert: ${subject} strict codec has no parse() method`); + } + function validateWireName(subject, value) { + if (value === "." || value === ".." || !/^[A-Za-z0-9_$.-]+$/.test(value)) throw new Error(`typert: invalid ${subject} "${value}" — must contain only RPC endpoint segment characters`); + } + function validateSegment(subject, value) { + if (value.length === 0 || value.includes("#")) throw new Error(`typert: invalid ${subject} "${value}" — must be nonempty and must not contain "#"`); + } + function validateNonempty(subject, value) { + if (value.length === 0) throw new Error(`typert: invalid ${subject} — must be nonempty`); + } + //#endregion + //#region lib/types/client/index.js + /** Browser face of the shared Typert runtime registry. */ + /** Required services: none; this is the Client reflection root. */ + const inject = []; + /** + * Install the same registry implementation used by the Host face. + * @param ctx - Client Cordis root. + */ + function apply(ctx) { + new TypertRegistry(ctx); + } + //#endregion + exports.apply = apply; + exports.inject = inject; + return module.exports; + } +}); + +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/index.js new file mode 100644 index 0000000..ab2eaa4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/index.js @@ -0,0 +1,562 @@ +import { Service } from "@deepseek-ai/cordis"; +import { z } from "zod"; +//#region lib/types/service.js +/** +* Runtime registry for generated Typert reflection, Remote invocations, and +* dependency-inverted lookup/Context providers. It performs no TypeScript +* analysis or schema generation. +* @module @deepseek-ai/dsh-typert-registry +*/ +/** +* Compose the global key of one generated schema. +* @param packageName - contributing npm package. +* @param name - schema export name. +* @returns `#`. +*/ +function typertKey(packageName, name) { + return `${packageName}#${name}`; +} +/** +* Compose the identity of one package-face model. +* @param packageName - contributing npm package. +* @param face - independently compiled face. +* @returns `#`. +*/ +function typertPackageKey(packageName, face) { + return `${packageName}#${face}`; +} +/** +* Compose the endpoint key used by local and Remote invocation registries. +* @param descriptor - invocation whose namespace and method form the endpoint. +* @returns `/`. +*/ +function typertEndpoint(descriptor) { + return `${descriptor.namespace}/${descriptor.method}`; +} +var ChangeSource = class { + report; + listeners = /* @__PURE__ */ new Set(); + constructor(report) { + this.report = report; + } + subscribe(ctx, listener) { + const { listeners } = this; + return ctx.effect(function* () { + listeners.add(listener); + yield () => { + listeners.delete(listener); + }; + }, "typert registry subscription"); + } + emit(change) { + for (const listener of [...this.listeners]) try { + listener(change); + } catch (error) { + this.report(change, error); + } + } +}; +var DescriptorStore = class { + kind; + entries = /* @__PURE__ */ new Map(); + ids = /* @__PURE__ */ new Map(); + history = /* @__PURE__ */ new Set(); + changes; + constructor(kind, report) { + this.kind = kind; + this.changes = new ChangeSource(report); + } + validate(descriptors) { + const endpoints = /* @__PURE__ */ new Set(); + const ids = /* @__PURE__ */ new Set(); + for (const descriptor of descriptors) { + validateInvocation(descriptor); + const endpoint = typertEndpoint(descriptor); + if (endpoints.has(endpoint) || this.entries.has(endpoint)) throw new Error(`typert: ${this.kind} endpoint "${endpoint}" is already registered`); + if (ids.has(descriptor.id) || this.ids.has(descriptor.id)) throw new Error(`typert: ${this.kind} invocation id "${descriptor.id}" is already registered`); + endpoints.add(endpoint); + ids.add(descriptor.id); + } + } + commit(owner, descriptors) { + for (const descriptor of descriptors) { + const entry = { + descriptor, + owner + }; + const endpoint = typertEndpoint(descriptor); + this.entries.set(endpoint, entry); + this.ids.set(descriptor.id, entry); + this.history.add(endpoint); + } + for (const descriptor of descriptors) this.changes.emit({ + kind: this.kind, + key: typertEndpoint(descriptor) + }); + } + withdraw(owner, descriptors) { + const removed = []; + for (const descriptor of descriptors) { + const endpoint = typertEndpoint(descriptor); + const entry = this.entries.get(endpoint); + /* v8 ignore next -- duplicate registration is rejected, so no later owner can replace this entry before its effect disposes. */ + if (entry?.owner !== owner) continue; + this.entries.delete(endpoint); + /* v8 ignore next -- ids and endpoints are committed and withdrawn together under the same unique owner. */ + if (this.ids.get(descriptor.id) === entry) this.ids.delete(descriptor.id); + removed.push(endpoint); + } + for (const endpoint of removed) this.changes.emit({ + kind: this.kind, + key: endpoint + }); + } + get(endpoint) { + return this.entries.get(endpoint)?.descriptor; + } + hasSeen(endpoint) { + return this.history.has(endpoint); + } + list() { + return [...this.entries.values()].map((entry) => entry.descriptor); + } + subscribe(ctx, listener) { + return this.changes.subscribe(ctx, listener); + } +}; +var RemoteStore = class { + descriptors; + packages = /* @__PURE__ */ new Map(); + constructor(descriptors) { + this.descriptors = descriptors; + } + view(ctx) { + return { + register: (contribution) => this.register(ctx, contribution), + get: (endpoint) => this.descriptors.get(endpoint), + list: () => this.descriptors.list(), + subscribe: (listener) => this.descriptors.subscribe(ctx, listener) + }; + } + register(ctx, contribution) { + validateSegment("Remote package name", contribution.package); + if (this.packages.has(contribution.package)) throw new Error(`typert: Remote package "${contribution.package}" is already registered`); + this.descriptors.validate(contribution.descriptors); + const owner = {}; + const { packages, descriptors } = this; + return ctx.effect(function* () { + packages.set(contribution.package, owner); + descriptors.commit(owner, contribution.descriptors); + yield () => { + /* v8 ignore else -- duplicate package registration is rejected, so this effect remains the package's unique owner. */ + if (packages.get(contribution.package) === owner) packages.delete(contribution.package); + descriptors.withdraw(owner, contribution.descriptors); + }; + }, `typert.remotes.register(${JSON.stringify(contribution.package)})`); + } +}; +var LookupStore = class { + providers = /* @__PURE__ */ new Map(); + resolvers = /* @__PURE__ */ new Map(); + definitions = /* @__PURE__ */ new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + register: (key, provider) => this.register(ctx, key, provider), + configure: (key, resolver) => this.configure(ctx, key, resolver), + get: (key) => this.get(key), + definitions: () => [...this.definitions.values()], + keys: () => [...this.providers.keys()], + subscribe: (listener) => this.changes.subscribe(ctx, listener) + }; + } + get(key) { + const provider = this.providers.get(key)?.provider; + if (provider === void 0) return void 0; + const resolver = this.resolvers.get(key)?.provider; + if (resolver === void 0) return provider; + return { + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: (id) => resolver.resolve(id) + }; + } + configure(ctx, key, resolver) { + validateSegment("lookup key", key); + if (this.resolvers.has(key)) throw new Error(`typert: lookup "${key}" resolver is already configured`); + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner: {} + }; + const { resolvers, changes } = this; + return ctx.effect(function* () { + resolvers.set(key, entry); + changes.emit({ + kind: "lookup", + key + }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (resolvers.get(key) !== entry) return; + resolvers.delete(key); + changes.emit({ + kind: "lookup", + key + }); + }; + }, `typert.lookups.configure(${JSON.stringify(key)})`); + } + register(ctx, key, provider) { + validateSegment("lookup key", key); + validateSegment("lookup parameter", provider.parameter); + validateWireName("lookup wire field", provider.wire); + validateNonempty("lookup Host type symbol", provider.hostTypeSymbol); + validateNonempty("lookup wire type symbol", provider.wireTypeSymbol); + if (this.providers.has(key)) throw new Error(`typert: lookup "${key}" is already registered`); + const definition = { + key, + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol + }; + const known = this.definitions.get(key); + if (known !== void 0 && !lookupDefinitionEquals(known, definition)) throw new Error(`typert: lookup "${key}" changed its wire declaration during this registry lifetime`); + const entry = { + provider, + owner: {} + }; + const { definitions, providers, changes } = this; + return ctx.effect(function* () { + definitions.set(key, definition); + providers.set(key, entry); + changes.emit({ + kind: "lookup", + key + }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (providers.get(key) !== entry) return; + providers.delete(key); + changes.emit({ + kind: "lookup", + key + }); + }; + }, `typert.lookups.register(${JSON.stringify(key)})`); + } +}; +function lookupDefinitionEquals(left, right) { + return left.parameter === right.parameter && left.wire === right.wire && left.hostTypeSymbol === right.hostTypeSymbol && left.wireTypeSymbol === right.wireTypeSymbol; +} +var ContextStore = class { + hosts = /* @__PURE__ */ new Map(); + hostResolvers = /* @__PURE__ */ new Map(); + clients = /* @__PURE__ */ new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + registerHost: (key, provider) => this.registerHost(ctx, key, provider), + configureHost: (key, resolver) => this.configureHost(ctx, key, resolver), + registerClient: (key, binder) => this.registerClient(ctx, key, binder), + getHost: (key) => this.getHost(key), + getClient: (key) => this.clients.get(key)?.provider, + subscribe: (listener) => this.changes.subscribe(ctx, listener) + }; + } + getHost(key) { + const provider = this.hosts.get(key)?.provider; + if (provider === void 0) return void 0; + const resolver = this.hostResolvers.get(key)?.provider; + if (resolver === void 0) return provider; + return { + wire: provider.wire, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: (id) => resolver.resolve(id) + }; + } + configureHost(ctx, key, resolver) { + validateSegment("Context key", key); + if (this.hostResolvers.has(key)) throw new Error(`typert: host-context "${key}" resolver is already configured`); + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner: {} + }; + const { hostResolvers, changes } = this; + return ctx.effect(function* () { + hostResolvers.set(key, entry); + changes.emit({ + kind: "host-context", + key + }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (hostResolvers.get(key) !== entry) return; + hostResolvers.delete(key); + changes.emit({ + kind: "host-context", + key + }); + }; + }, `typert.contexts.configureHost(${JSON.stringify(key)})`); + } + registerHost(ctx, key, provider) { + validateSegment("Context key", key); + validateWireName("Context wire field", provider.wire); + validateNonempty("Context wire type symbol", provider.wireTypeSymbol); + return this.registerProvider(ctx, this.hosts, "host-context", key, provider); + } + registerClient(ctx, key, binder) { + validateSegment("Context key", key); + return this.registerProvider(ctx, this.clients, "client-context", key, binder); + } + registerProvider(ctx, table, kind, key, provider) { + if (table.has(key)) throw new Error(`typert: ${kind} provider "${key}" is already registered`); + const entry = { + provider, + owner: {} + }; + const { changes } = this; + return ctx.effect(function* () { + table.set(key, entry); + changes.emit({ + kind, + key + }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (table.get(key) !== entry) return; + table.delete(key); + changes.emit({ + kind, + key + }); + }; + }, `typert.contexts.register(${JSON.stringify(key)})`); + } +}; +/** +* Registry of generated schemas, package reflection, invocations, and Remote +* dependency providers. +* @typert service typert +*/ +var TypertRegistry = class extends Service { + schemas = /* @__PURE__ */ new Map(); + packages = /* @__PURE__ */ new Map(); + localStore; + remoteStore; + lookupStore; + contextStore; + constructor(ctx) { + super(ctx, "typert"); + const report = (change, error) => { + ctx.logger.warn(`typert: ${change.kind} observer for "${change.key}" failed`); + ctx.logger.warn(error); + }; + this.localStore = new DescriptorStore("local", report); + this.remoteStore = new RemoteStore(new DescriptorStore("remote", report)); + this.lookupStore = new LookupStore(report); + this.contextStore = new ContextStore(report); + } + /** Current-environment invocation definitions. */ + get local() { + const ctx = this.ctx; + return { + get: (endpoint) => this.localStore.get(endpoint), + hasSeen: (endpoint) => this.localStore.hasSeen(endpoint), + list: () => this.localStore.list(), + subscribe: (listener) => this.localStore.subscribe(ctx, listener) + }; + } + /** Consumer-selected Remote definitions. */ + get remotes() { + return this.remoteStore.view(this.ctx); + } + /** Host object lookup providers. */ + get lookups() { + return this.lookupStore.view(this.ctx); + } + /** Host Context providers and Client Context binders. */ + get contexts() { + return this.contextStore.view(this.ctx); + } + /** + * Register one generated contribution atomically for the calling fiber. + * Duplicate package-face identities, schemas, invocation ids, or endpoints + * reject the whole batch. + * @param contribution - generated schemas, reflection, and Host invocations. + * @returns the exact effect disposer that removes this contribution. + */ + register(contribution) { + const packageRecord = this.validatePackage(contribution); + const schemaRecords = this.validateSchemas(contribution); + const invocations = contribution.invocations; + this.localStore.validate(invocations); + const owner = {}; + const { schemas, packages, localStore } = this; + return this.ctx.effect(function* () { + packages.set(packageRecord.key, packageRecord); + for (const record of schemaRecords) schemas.set(record.key, record); + localStore.commit(owner, invocations); + yield () => { + /* v8 ignore else -- duplicate package-face registration is rejected, so this effect remains its unique owner. */ + if (packages.get(packageRecord.key) === packageRecord) packages.delete(packageRecord.key); + for (const record of schemaRecords) + /* v8 ignore else -- duplicate schema registration is rejected, so this contribution remains each record's unique owner. */ + if (schemas.get(record.key) === record) schemas.delete(record.key); + localStore.withdraw(owner, invocations); + }; + }, "typert.register()"); + } + /** + * Look up one schema by `#`. + * @param key - global schema key. + * @returns the live schema record, or `undefined` when absent. + */ + get(key) { + return this.schemas.get(key); + } + /** + * Resolve one required schema. + * @param key - global schema key. + * @returns the live schema record. + * @throws when the key is malformed, the package face is absent, or the schema is not contributed. + */ + resolve(key) { + const record = this.schemas.get(key); + if (record !== void 0) return record; + const hash = key.indexOf("#"); + if (hash <= 0 || hash === key.length - 1) throw new Error(`typert: invalid schema key "${key}" — expected "#"`); + const packageName = key.slice(0, hash); + if ([...this.packages.values()].some((candidate) => candidate.package === packageName)) throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" is registered but contributes no schema named "${key.slice(hash + 1)}"`); + throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" has no registered contribution`); + } + /** + * Enumerate live schemas in registration order. + * @param filter - optional package and face restriction. + * @returns matching schema records. + */ + list(filter = {}) { + return [...this.schemas.values()].filter((record) => matches(record, filter)); + } + /** + * Look up generated reflection for one package face. + * @param packageName - exact npm package name. + * @param face - face to query; defaults to the host runtime. + * @returns the live package record, or `undefined` when absent. + */ + getPackage(packageName, face = "host") { + return this.packages.get(typertPackageKey(packageName, face)); + } + /** + * Enumerate generated package reflection in registration order. + * @param filter - optional package and face restriction. + * @returns matching package records. + */ + listPackages(filter = {}) { + return [...this.packages.values()].filter((record) => matches(record, filter)); + } + /** + * Project a live Zod schema to JSON Schema without caching the result. + * @param key - global schema key. + * @param params - Zod projection parameters. + * @returns a fresh JSON Schema document. + */ + toJSONSchema(key, params) { + return z.toJSONSchema(this.resolve(key).schema, params); + } + validatePackage(contribution) { + validateSegment("package name", contribution.package); + const face = contribution.face; + if (face !== "host" && face !== "client") throw new Error(`typert: invalid face ${JSON.stringify(face)} — expected "host" or "client"`); + const key = typertPackageKey(contribution.package, contribution.face); + if (this.packages.has(key)) throw new Error(`typert: package face "${key}" is already registered`); + return { + package: contribution.package, + face, + key, + model: contribution.model + }; + } + validateSchemas(contribution) { + const records = []; + const batch = /* @__PURE__ */ new Set(); + for (const schema of contribution.schemas) { + validateSegment("schema name", schema.name); + const key = typertKey(contribution.package, schema.name); + if (batch.has(key) || this.schemas.has(key)) throw new Error(`typert: schema "${key}" is already registered`); + batch.add(key); + records.push({ + ...schema, + package: contribution.package, + face: contribution.face, + key + }); + } + return records; + } +}; +function matches(record, filter) { + return (filter.package === void 0 || record.package === filter.package) && (filter.face === void 0 || record.face === filter.face); +} +function validateInvocation(descriptor) { + validateNonempty("invocation id", descriptor.id); + validateSegment("invocation service key", descriptor.service); + validateWireName("invocation namespace", descriptor.namespace); + validateWireName("invocation method", descriptor.method); + if (descriptor.implementation !== void 0) validateWireName("invocation implementation method", descriptor.implementation); + validateCodec(descriptor.result, `${descriptor.id} result`); + const wires = /* @__PURE__ */ new Set(); + for (const parameter of descriptor.parameters) { + validateWireName("parameter name", parameter.name); + validateWireName("parameter wire field", parameter.wire); + if (wires.has(parameter.wire)) throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${parameter.wire}"`); + wires.add(parameter.wire); + if (parameter.source === "lookup") { + if (parameter.acceptsUndefined !== void 0) throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" cannot accept undefined`); + if (parameter.lookup === void 0) throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" has no lookup key`); + validateSegment("lookup key", parameter.lookup); + } else if (parameter.lookup !== void 0) throw new Error(`typert: invocation "${descriptor.id}" JSON parameter "${parameter.name}" declares a lookup key`); + validateCodec(parameter.codec, `${descriptor.id} parameter ${parameter.name}`); + } + const cancellation = descriptor.cancellation; + if (cancellation !== void 0 && cancellation.parameter !== "signal") throw new Error(`typert: invocation "${descriptor.id}" cancellation parameter must be "signal"`); + if (descriptor.scope !== void 0) { + if (descriptor.invocation.kind !== "direct") throw new Error(`typert: invocation "${descriptor.id}" Context receiver cannot declare a direct scope projection`); + validateSegment("scope Context key", descriptor.scope.context); + validateWireName("scope wire field", descriptor.scope.wire); + const lookups = descriptor.parameters.filter((candidate) => candidate.source === "lookup"); + const parameter = lookups.length === 1 ? lookups[0] : void 0; + if (parameter === void 0 || parameter.wire !== descriptor.scope.wire || parameter.lookup !== descriptor.scope.context) throw new Error(`typert: invocation "${descriptor.id}" scope wire "${descriptor.scope.wire}" must select its only lookup parameter`); + } + if (descriptor.invocation.kind === "context") { + validateSegment("Context key", descriptor.invocation.context); + validateWireName("Context wire field", descriptor.invocation.wire); + if (wires.has(descriptor.invocation.wire)) throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${descriptor.invocation.wire}"`); + validateCodec(descriptor.invocation.codec, `${descriptor.id} Context`); + } +} +function validateCodec(codec, subject) { + if (codec.mode === "src-json") return; + validateNonempty(`${subject} type symbol`, codec.typeSymbol); + if (typeof codec.schema.parse !== "function") throw new Error(`typert: ${subject} strict codec has no parse() method`); +} +function validateWireName(subject, value) { + if (value === "." || value === ".." || !/^[A-Za-z0-9_$.-]+$/.test(value)) throw new Error(`typert: invalid ${subject} "${value}" — must contain only RPC endpoint segment characters`); +} +function validateSegment(subject, value) { + if (value.length === 0 || value.includes("#")) throw new Error(`typert: invalid ${subject} "${value}" — must be nonempty and must not contain "#"`); +} +function validateNonempty(subject, value) { + if (value.length === 0) throw new Error(`typert: invalid ${subject} — must be nonempty`); +} +//#endregion +export { TypertRegistry, TypertRegistry as default, typertEndpoint, typertKey, typertPackageKey }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/invariant.js new file mode 100644 index 0000000..3702db6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/invariant.js @@ -0,0 +1,24 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-typert-registry`. +* @module @deepseek-ai/dsh-typert-registry/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-typert-registry"; +/** Cordis companion plugin name. */ +const name = "typert-registry-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: schema and package-reflection records mutate together +* inside register/dispose, with no independent event or second data source to +* cross-check; duplicate identities fail at the owning operation boundary. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.d.ts new file mode 100644 index 0000000..d8bea52 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.d.ts @@ -0,0 +1,10 @@ +/** Browser face of the shared Typert runtime registry. */ +import type { Context } from '@deepseek-ai/cordis'; +/** Required services: none; this is the Client reflection root. */ +export declare const inject: string[]; +/** + * Install the same registry implementation used by the Host face. + * @param ctx - Client Cordis root. + */ +export declare function apply(ctx: Context): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.js new file mode 100644 index 0000000..1e1e875 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/client/index.js @@ -0,0 +1,12 @@ +/** Browser face of the shared Typert runtime registry. */ +import { TypertRegistry } from "../service.js"; +/** Required services: none; this is the Client reflection root. */ +export const inject = []; +/** + * Install the same registry implementation used by the Host face. + * @param ctx - Client Cordis root. + */ +export function apply(ctx) { + new TypertRegistry(ctx); +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.d.ts new file mode 100644 index 0000000..8ec53b9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.d.ts @@ -0,0 +1,18 @@ +/** Host entry for the shared Typert runtime registry. */ +import type { z } from 'zod'; +import type { TypertDisposer } from '@deepseek-ai/dsh-typert-protocol'; +import type { TypertContribution, TypertFace, TypertPackageFilter, TypertPackageRecord, TypertSchemaFilter, TypertSchemaRecord } from './types.ts'; +export { default, TypertRegistry, typertEndpoint, typertKey, typertPackageKey } from './service.ts'; +export type * from './types.ts'; +declare module '@deepseek-ai/dsh-typert-protocol' { + interface TypertRegistryContract { + register(contribution: TypertContribution): TypertDisposer; + get(key: string): TypertSchemaRecord | undefined; + resolve(key: string): TypertSchemaRecord; + list(filter?: TypertSchemaFilter): TypertSchemaRecord[]; + getPackage(packageName: string, face?: TypertFace): TypertPackageRecord | undefined; + listPackages(filter?: TypertPackageFilter): TypertPackageRecord[]; + toJSONSchema(key: string, params?: z.core.ToJSONSchemaParams): z.core.JSONSchema.BaseSchema; + } +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.js new file mode 100644 index 0000000..9a5a3fa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/index.js @@ -0,0 +1,3 @@ +/** Host entry for the shared Typert runtime registry. */ +export { default, TypertRegistry, typertEndpoint, typertKey, typertPackageKey } from "./service.js"; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.d.ts new file mode 100644 index 0000000..6ebf43c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-typert-registry`. + * @module @deepseek-ai/dsh-typert-registry/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "typert-registry-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.js new file mode 100644 index 0000000..ae83f94 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/invariant.js @@ -0,0 +1,23 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-typert-registry`. + * @module @deepseek-ai/dsh-typert-registry/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-typert-registry'; +/** Cordis companion plugin name. */ +export const name = 'typert-registry-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: schema and package-reflection records mutate together + * inside register/dispose, with no independent event or second data source to + * cross-check; duplicate identities fail at the owning operation boundary. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.d.ts new file mode 100644 index 0000000..e1304f0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.d.ts @@ -0,0 +1,103 @@ +/** + * Runtime registry for generated Typert reflection, Remote invocations, and + * dependency-inverted lookup/Context providers. It performs no TypeScript + * analysis or schema generation. + * @module @deepseek-ai/dsh-typert-registry + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import { z } from 'zod'; +import type { InvocationDescriptor, TypertContextRegistry, TypertDisposer, TypertLocalRegistry, TypertLookupRegistry, TypertRemoteRegistry, TypertRegistryContract } from '@deepseek-ai/dsh-typert-protocol'; +import type { TypertContribution, TypertFace, TypertPackageFilter, TypertPackageRecord, TypertSchemaFilter, TypertSchemaRecord } from './types.ts'; +/** + * Compose the global key of one generated schema. + * @param packageName - contributing npm package. + * @param name - schema export name. + * @returns `#`. + */ +export declare function typertKey(packageName: string, name: string): string; +/** + * Compose the identity of one package-face model. + * @param packageName - contributing npm package. + * @param face - independently compiled face. + * @returns `#`. + */ +export declare function typertPackageKey(packageName: string, face: TypertFace): string; +/** + * Compose the endpoint key used by local and Remote invocation registries. + * @param descriptor - invocation whose namespace and method form the endpoint. + * @returns `/`. + */ +export declare function typertEndpoint(descriptor: Pick): string; +/** + * Registry of generated schemas, package reflection, invocations, and Remote + * dependency providers. + * @typert service typert + */ +export declare class TypertRegistry extends Service implements TypertRegistryContract { + private readonly schemas; + private readonly packages; + private readonly localStore; + private readonly remoteStore; + private readonly lookupStore; + private readonly contextStore; + constructor(ctx: Context); + /** Current-environment invocation definitions. */ + get local(): TypertLocalRegistry; + /** Consumer-selected Remote definitions. */ + get remotes(): TypertRemoteRegistry; + /** Host object lookup providers. */ + get lookups(): TypertLookupRegistry; + /** Host Context providers and Client Context binders. */ + get contexts(): TypertContextRegistry; + /** + * Register one generated contribution atomically for the calling fiber. + * Duplicate package-face identities, schemas, invocation ids, or endpoints + * reject the whole batch. + * @param contribution - generated schemas, reflection, and Host invocations. + * @returns the exact effect disposer that removes this contribution. + */ + register(contribution: TypertContribution): TypertDisposer; + /** + * Look up one schema by `#`. + * @param key - global schema key. + * @returns the live schema record, or `undefined` when absent. + */ + get(key: string): TypertSchemaRecord | undefined; + /** + * Resolve one required schema. + * @param key - global schema key. + * @returns the live schema record. + * @throws when the key is malformed, the package face is absent, or the schema is not contributed. + */ + resolve(key: string): TypertSchemaRecord; + /** + * Enumerate live schemas in registration order. + * @param filter - optional package and face restriction. + * @returns matching schema records. + */ + list(filter?: TypertSchemaFilter): TypertSchemaRecord[]; + /** + * Look up generated reflection for one package face. + * @param packageName - exact npm package name. + * @param face - face to query; defaults to the host runtime. + * @returns the live package record, or `undefined` when absent. + */ + getPackage(packageName: string, face?: TypertFace): TypertPackageRecord | undefined; + /** + * Enumerate generated package reflection in registration order. + * @param filter - optional package and face restriction. + * @returns matching package records. + */ + listPackages(filter?: TypertPackageFilter): TypertPackageRecord[]; + /** + * Project a live Zod schema to JSON Schema without caching the result. + * @param key - global schema key. + * @param params - Zod projection parameters. + * @returns a fresh JSON Schema document. + */ + toJSONSchema(key: string, params?: z.core.ToJSONSchemaParams): z.core.JSONSchema.BaseSchema; + private validatePackage; + private validateSchemas; +} +export default TypertRegistry; +//# sourceMappingURL=service.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.js new file mode 100644 index 0000000..66bcd24 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/service.js @@ -0,0 +1,600 @@ +/** + * Runtime registry for generated Typert reflection, Remote invocations, and + * dependency-inverted lookup/Context providers. It performs no TypeScript + * analysis or schema generation. + * @module @deepseek-ai/dsh-typert-registry + */ +import { Service } from '@deepseek-ai/cordis'; +import { z } from 'zod'; +/** + * Compose the global key of one generated schema. + * @param packageName - contributing npm package. + * @param name - schema export name. + * @returns `#`. + */ +export function typertKey(packageName, name) { + return `${packageName}#${name}`; +} +/** + * Compose the identity of one package-face model. + * @param packageName - contributing npm package. + * @param face - independently compiled face. + * @returns `#`. + */ +export function typertPackageKey(packageName, face) { + return `${packageName}#${face}`; +} +/** + * Compose the endpoint key used by local and Remote invocation registries. + * @param descriptor - invocation whose namespace and method form the endpoint. + * @returns `/`. + */ +export function typertEndpoint(descriptor) { + return `${descriptor.namespace}/${descriptor.method}`; +} +class ChangeSource { + report; + listeners = new Set(); + constructor(report) { + this.report = report; + } + subscribe(ctx, listener) { + const { listeners } = this; + return ctx.effect(function* () { + listeners.add(listener); + yield () => { listeners.delete(listener); }; + }, 'typert registry subscription'); + } + emit(change) { + for (const listener of [...this.listeners]) { + try { + listener(change); + } + catch (error) { + this.report(change, error); + } + } + } +} +class DescriptorStore { + kind; + entries = new Map(); + ids = new Map(); + history = new Set(); + changes; + constructor(kind, report) { + this.kind = kind; + this.changes = new ChangeSource(report); + } + validate(descriptors) { + const endpoints = new Set(); + const ids = new Set(); + for (const descriptor of descriptors) { + validateInvocation(descriptor); + const endpoint = typertEndpoint(descriptor); + if (endpoints.has(endpoint) || this.entries.has(endpoint)) { + throw new Error(`typert: ${this.kind} endpoint "${endpoint}" is already registered`); + } + if (ids.has(descriptor.id) || this.ids.has(descriptor.id)) { + throw new Error(`typert: ${this.kind} invocation id "${descriptor.id}" is already registered`); + } + endpoints.add(endpoint); + ids.add(descriptor.id); + } + } + commit(owner, descriptors) { + for (const descriptor of descriptors) { + const entry = { descriptor, owner }; + const endpoint = typertEndpoint(descriptor); + this.entries.set(endpoint, entry); + this.ids.set(descriptor.id, entry); + this.history.add(endpoint); + } + for (const descriptor of descriptors) { + this.changes.emit({ kind: this.kind, key: typertEndpoint(descriptor) }); + } + } + withdraw(owner, descriptors) { + const removed = []; + for (const descriptor of descriptors) { + const endpoint = typertEndpoint(descriptor); + const entry = this.entries.get(endpoint); + /* v8 ignore next -- duplicate registration is rejected, so no later owner can replace this entry before its effect disposes. */ + if (entry?.owner !== owner) + continue; + this.entries.delete(endpoint); + /* v8 ignore next -- ids and endpoints are committed and withdrawn together under the same unique owner. */ + if (this.ids.get(descriptor.id) === entry) + this.ids.delete(descriptor.id); + removed.push(endpoint); + } + for (const endpoint of removed) + this.changes.emit({ kind: this.kind, key: endpoint }); + } + get(endpoint) { + return this.entries.get(endpoint)?.descriptor; + } + hasSeen(endpoint) { + return this.history.has(endpoint); + } + list() { + return [...this.entries.values()].map(entry => entry.descriptor); + } + subscribe(ctx, listener) { + return this.changes.subscribe(ctx, listener); + } +} +class RemoteStore { + descriptors; + packages = new Map(); + constructor(descriptors) { + this.descriptors = descriptors; + } + view(ctx) { + return { + register: contribution => this.register(ctx, contribution), + get: endpoint => this.descriptors.get(endpoint), + list: () => this.descriptors.list(), + subscribe: listener => this.descriptors.subscribe(ctx, listener), + }; + } + register(ctx, contribution) { + validateSegment('Remote package name', contribution.package); + if (this.packages.has(contribution.package)) { + throw new Error(`typert: Remote package "${contribution.package}" is already registered`); + } + this.descriptors.validate(contribution.descriptors); + const owner = {}; + const { packages, descriptors } = this; + return ctx.effect(function* () { + packages.set(contribution.package, owner); + descriptors.commit(owner, contribution.descriptors); + yield () => { + /* v8 ignore else -- duplicate package registration is rejected, so this effect remains the package's unique owner. */ + if (packages.get(contribution.package) === owner) + packages.delete(contribution.package); + descriptors.withdraw(owner, contribution.descriptors); + }; + }, `typert.remotes.register(${JSON.stringify(contribution.package)})`); + } +} +class LookupStore { + providers = new Map(); + resolvers = new Map(); + definitions = new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + register: (key, provider) => this.register(ctx, key, provider), + configure: (key, resolver) => this.configure(ctx, key, resolver), + get: key => this.get(key), + definitions: () => [...this.definitions.values()], + keys: () => [...this.providers.keys()], + subscribe: listener => this.changes.subscribe(ctx, listener), + }; + } + get(key) { + const provider = this.providers.get(key)?.provider; + if (provider === undefined) + return undefined; + const resolver = this.resolvers.get(key)?.provider; + if (resolver === undefined) + return provider; + return { + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: id => resolver.resolve(id), + }; + } + configure(ctx, key, resolver) { + validateSegment('lookup key', key); + if (this.resolvers.has(key)) + throw new Error(`typert: lookup "${key}" resolver is already configured`); + const owner = {}; + // The map erases each merge-declared Wire type; restore it only at the + // typed configure() boundary so strict function variance remains sound. + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner, + }; + const { resolvers, changes } = this; + return ctx.effect(function* () { + resolvers.set(key, entry); + changes.emit({ kind: 'lookup', key }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (resolvers.get(key) !== entry) + return; + resolvers.delete(key); + changes.emit({ kind: 'lookup', key }); + }; + }, `typert.lookups.configure(${JSON.stringify(key)})`); + } + register(ctx, key, provider) { + validateSegment('lookup key', key); + validateSegment('lookup parameter', provider.parameter); + validateWireName('lookup wire field', provider.wire); + validateNonempty('lookup Host type symbol', provider.hostTypeSymbol); + validateNonempty('lookup wire type symbol', provider.wireTypeSymbol); + if (this.providers.has(key)) + throw new Error(`typert: lookup "${key}" is already registered`); + const definition = { + key, + parameter: provider.parameter, + wire: provider.wire, + hostTypeSymbol: provider.hostTypeSymbol, + wireTypeSymbol: provider.wireTypeSymbol, + }; + const known = this.definitions.get(key); + if (known !== undefined && !lookupDefinitionEquals(known, definition)) { + throw new Error(`typert: lookup "${key}" changed its wire declaration during this registry lifetime`); + } + const owner = {}; + const entry = { provider, owner }; + const { definitions, providers, changes } = this; + return ctx.effect(function* () { + definitions.set(key, definition); + providers.set(key, entry); + changes.emit({ kind: 'lookup', key }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (providers.get(key) !== entry) + return; + providers.delete(key); + changes.emit({ kind: 'lookup', key }); + }; + }, `typert.lookups.register(${JSON.stringify(key)})`); + } +} +function lookupDefinitionEquals(left, right) { + return left.parameter === right.parameter + && left.wire === right.wire + && left.hostTypeSymbol === right.hostTypeSymbol + && left.wireTypeSymbol === right.wireTypeSymbol; +} +class ContextStore { + hosts = new Map(); + hostResolvers = new Map(); + clients = new Map(); + changes; + constructor(report) { + this.changes = new ChangeSource(report); + } + view(ctx) { + return { + registerHost: (key, provider) => this.registerHost(ctx, key, provider), + configureHost: (key, resolver) => this.configureHost(ctx, key, resolver), + registerClient: (key, binder) => this.registerClient(ctx, key, binder), + getHost: key => this.getHost(key), + getClient: key => this.clients.get(key)?.provider, + subscribe: listener => this.changes.subscribe(ctx, listener), + }; + } + getHost(key) { + const provider = this.hosts.get(key)?.provider; + if (provider === undefined) + return undefined; + const resolver = this.hostResolvers.get(key)?.provider; + if (resolver === undefined) + return provider; + return { + wire: provider.wire, + wireTypeSymbol: provider.wireTypeSymbol, + resolve: id => resolver.resolve(id), + }; + } + configureHost(ctx, key, resolver) { + validateSegment('Context key', key); + if (this.hostResolvers.has(key)) + throw new Error(`typert: host-context "${key}" resolver is already configured`); + const entry = { + provider: { resolve: async (id) => resolver(id) }, + owner: {}, + }; + const { hostResolvers, changes } = this; + return ctx.effect(function* () { + hostResolvers.set(key, entry); + changes.emit({ kind: 'host-context', key }); + yield () => { + /* v8 ignore next -- duplicate configuration is rejected, so this effect remains the key's unique owner. */ + if (hostResolvers.get(key) !== entry) + return; + hostResolvers.delete(key); + changes.emit({ kind: 'host-context', key }); + }; + }, `typert.contexts.configureHost(${JSON.stringify(key)})`); + } + registerHost(ctx, key, provider) { + validateSegment('Context key', key); + validateWireName('Context wire field', provider.wire); + validateNonempty('Context wire type symbol', provider.wireTypeSymbol); + return this.registerProvider(ctx, this.hosts, 'host-context', key, provider); + } + registerClient(ctx, key, binder) { + validateSegment('Context key', key); + return this.registerProvider(ctx, this.clients, 'client-context', key, binder); + } + registerProvider(ctx, table, kind, key, provider) { + if (table.has(key)) + throw new Error(`typert: ${kind} provider "${key}" is already registered`); + const entry = { provider, owner: {} }; + const { changes } = this; + return ctx.effect(function* () { + table.set(key, entry); + changes.emit({ kind, key }); + yield () => { + /* v8 ignore next -- duplicate registration is rejected, so this effect remains the key's unique owner. */ + if (table.get(key) !== entry) + return; + table.delete(key); + changes.emit({ kind, key }); + }; + }, `typert.contexts.register(${JSON.stringify(key)})`); + } +} +/** + * Registry of generated schemas, package reflection, invocations, and Remote + * dependency providers. + * @typert service typert + */ +export class TypertRegistry extends Service { + schemas = new Map(); + packages = new Map(); + localStore; + remoteStore; + lookupStore; + contextStore; + constructor(ctx) { + super(ctx, 'typert'); + const report = (change, error) => { + ctx.logger.warn(`typert: ${change.kind} observer for "${change.key}" failed`); + ctx.logger.warn(error); + }; + this.localStore = new DescriptorStore('local', report); + this.remoteStore = new RemoteStore(new DescriptorStore('remote', report)); + this.lookupStore = new LookupStore(report); + this.contextStore = new ContextStore(report); + } + /** Current-environment invocation definitions. */ + get local() { + const ctx = this.ctx; + return { + get: endpoint => this.localStore.get(endpoint), + hasSeen: endpoint => this.localStore.hasSeen(endpoint), + list: () => this.localStore.list(), + subscribe: listener => this.localStore.subscribe(ctx, listener), + }; + } + /** Consumer-selected Remote definitions. */ + get remotes() { + return this.remoteStore.view(this.ctx); + } + /** Host object lookup providers. */ + get lookups() { + return this.lookupStore.view(this.ctx); + } + /** Host Context providers and Client Context binders. */ + get contexts() { + return this.contextStore.view(this.ctx); + } + /** + * Register one generated contribution atomically for the calling fiber. + * Duplicate package-face identities, schemas, invocation ids, or endpoints + * reject the whole batch. + * @param contribution - generated schemas, reflection, and Host invocations. + * @returns the exact effect disposer that removes this contribution. + */ + register(contribution) { + const packageRecord = this.validatePackage(contribution); + const schemaRecords = this.validateSchemas(contribution); + const invocations = contribution.invocations; + this.localStore.validate(invocations); + const owner = {}; + const { schemas, packages, localStore } = this; + return this.ctx.effect(function* () { + packages.set(packageRecord.key, packageRecord); + for (const record of schemaRecords) + schemas.set(record.key, record); + localStore.commit(owner, invocations); + yield () => { + /* v8 ignore else -- duplicate package-face registration is rejected, so this effect remains its unique owner. */ + if (packages.get(packageRecord.key) === packageRecord) + packages.delete(packageRecord.key); + for (const record of schemaRecords) { + /* v8 ignore else -- duplicate schema registration is rejected, so this contribution remains each record's unique owner. */ + if (schemas.get(record.key) === record) + schemas.delete(record.key); + } + localStore.withdraw(owner, invocations); + }; + }, 'typert.register()'); + } + /** + * Look up one schema by `#`. + * @param key - global schema key. + * @returns the live schema record, or `undefined` when absent. + */ + get(key) { + return this.schemas.get(key); + } + /** + * Resolve one required schema. + * @param key - global schema key. + * @returns the live schema record. + * @throws when the key is malformed, the package face is absent, or the schema is not contributed. + */ + resolve(key) { + const record = this.schemas.get(key); + if (record !== undefined) + return record; + const hash = key.indexOf('#'); + if (hash <= 0 || hash === key.length - 1) { + throw new Error(`typert: invalid schema key "${key}" — expected "#"`); + } + const packageName = key.slice(0, hash); + if ([...this.packages.values()].some(candidate => candidate.package === packageName)) { + throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" is registered but contributes no schema named "${key.slice(hash + 1)}"`); + } + throw new Error(`typert: cannot resolve "${key}" — package "${packageName}" has no registered contribution`); + } + /** + * Enumerate live schemas in registration order. + * @param filter - optional package and face restriction. + * @returns matching schema records. + */ + list(filter = {}) { + return [...this.schemas.values()].filter(record => matches(record, filter)); + } + /** + * Look up generated reflection for one package face. + * @param packageName - exact npm package name. + * @param face - face to query; defaults to the host runtime. + * @returns the live package record, or `undefined` when absent. + */ + getPackage(packageName, face = 'host') { + return this.packages.get(typertPackageKey(packageName, face)); + } + /** + * Enumerate generated package reflection in registration order. + * @param filter - optional package and face restriction. + * @returns matching package records. + */ + listPackages(filter = {}) { + return [...this.packages.values()].filter(record => matches(record, filter)); + } + /** + * Project a live Zod schema to JSON Schema without caching the result. + * @param key - global schema key. + * @param params - Zod projection parameters. + * @returns a fresh JSON Schema document. + */ + toJSONSchema(key, params) { + return z.toJSONSchema(this.resolve(key).schema, params); + } + validatePackage(contribution) { + validateSegment('package name', contribution.package); + const face = contribution.face; + if (face !== 'host' && face !== 'client') { + throw new Error(`typert: invalid face ${JSON.stringify(face)} — expected "host" or "client"`); + } + const key = typertPackageKey(contribution.package, contribution.face); + if (this.packages.has(key)) { + throw new Error(`typert: package face "${key}" is already registered`); + } + return { + package: contribution.package, + face, + key, + model: contribution.model, + }; + } + validateSchemas(contribution) { + const records = []; + const batch = new Set(); + for (const schema of contribution.schemas) { + validateSegment('schema name', schema.name); + const key = typertKey(contribution.package, schema.name); + if (batch.has(key) || this.schemas.has(key)) { + throw new Error(`typert: schema "${key}" is already registered`); + } + batch.add(key); + records.push({ + ...schema, + package: contribution.package, + face: contribution.face, + key, + }); + } + return records; + } +} +function matches(record, filter) { + return (filter.package === undefined || record.package === filter.package) + && (filter.face === undefined || record.face === filter.face); +} +function validateInvocation(descriptor) { + validateNonempty('invocation id', descriptor.id); + validateSegment('invocation service key', descriptor.service); + validateWireName('invocation namespace', descriptor.namespace); + validateWireName('invocation method', descriptor.method); + if (descriptor.implementation !== undefined) { + validateWireName('invocation implementation method', descriptor.implementation); + } + validateCodec(descriptor.result, `${descriptor.id} result`); + const wires = new Set(); + for (const parameter of descriptor.parameters) { + validateWireName('parameter name', parameter.name); + validateWireName('parameter wire field', parameter.wire); + if (wires.has(parameter.wire)) { + throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${parameter.wire}"`); + } + wires.add(parameter.wire); + if (parameter.source === 'lookup') { + if (parameter.acceptsUndefined !== undefined) { + throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" cannot accept undefined`); + } + if (parameter.lookup === undefined) { + throw new Error(`typert: invocation "${descriptor.id}" lookup parameter "${parameter.name}" has no lookup key`); + } + validateSegment('lookup key', parameter.lookup); + } + else if (parameter.lookup !== undefined) { + throw new Error(`typert: invocation "${descriptor.id}" JSON parameter "${parameter.name}" declares a lookup key`); + } + validateCodec(parameter.codec, `${descriptor.id} parameter ${parameter.name}`); + } + const cancellation = descriptor.cancellation; + if (cancellation !== undefined && cancellation.parameter !== 'signal') { + throw new Error(`typert: invocation "${descriptor.id}" cancellation parameter must be "signal"`); + } + if (descriptor.scope !== undefined) { + if (descriptor.invocation.kind !== 'direct') { + throw new Error(`typert: invocation "${descriptor.id}" Context receiver cannot declare a direct scope projection`); + } + validateSegment('scope Context key', descriptor.scope.context); + validateWireName('scope wire field', descriptor.scope.wire); + const lookups = descriptor.parameters.filter(candidate => candidate.source === 'lookup'); + const parameter = lookups.length === 1 ? lookups[0] : undefined; + if (parameter === undefined || parameter.wire !== descriptor.scope.wire + || parameter.lookup !== descriptor.scope.context) { + throw new Error(`typert: invocation "${descriptor.id}" scope wire "${descriptor.scope.wire}" must select its only lookup parameter`); + } + } + if (descriptor.invocation.kind === 'context') { + validateSegment('Context key', descriptor.invocation.context); + validateWireName('Context wire field', descriptor.invocation.wire); + if (wires.has(descriptor.invocation.wire)) { + throw new Error(`typert: invocation "${descriptor.id}" repeats wire field "${descriptor.invocation.wire}"`); + } + validateCodec(descriptor.invocation.codec, `${descriptor.id} Context`); + } +} +function validateCodec(codec, subject) { + if (codec.mode === 'src-json') + return; + validateNonempty(`${subject} type symbol`, codec.typeSymbol); + if (typeof codec.schema.parse !== 'function') { + throw new Error(`typert: ${subject} strict codec has no parse() method`); + } +} +function validateWireName(subject, value) { + if (value === '.' || value === '..' || !/^[A-Za-z0-9_$.-]+$/.test(value)) { + throw new Error(`typert: invalid ${subject} "${value}" — must contain only RPC endpoint segment characters`); + } +} +function validateSegment(subject, value) { + if (value.length === 0 || value.includes('#')) { + throw new Error(`typert: invalid ${subject} "${value}" — must be nonempty and must not contain "#"`); + } +} +function validateNonempty(subject, value) { + if (value.length === 0) + throw new Error(`typert: invalid ${subject} — must be nonempty`); +} +export default TypertRegistry; +//# sourceMappingURL=service.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.d.ts new file mode 100644 index 0000000..19acd82 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.d.ts @@ -0,0 +1,100 @@ +/** + * Pure generated-artifact and runtime-registry types. The registry stores Zod + * schemas separately from generated package reflection metadata. + * @module @deepseek-ai/dsh-typert-registry/types + */ +import type { z } from 'zod'; +import type { InvocationDescriptor } from '@deepseek-ai/dsh-typert-protocol'; +/** Independently compiled side that produced a contribution. */ +export type TypertFace = 'host' | 'client'; +/** Structured JSDoc tag retained by generated runtime metadata. */ +export interface TypertDocTag { + readonly name: string; + readonly argument?: string; + readonly comment?: string; + readonly text: string; +} +/** Source documentation retained on reflected package elements. */ +export interface TypertDocumentation { + readonly description?: string; + readonly summary?: string; + readonly tags: readonly TypertDocTag[]; + readonly jsDoc?: string; +} +/** One generated public member signature. */ +export interface TypertMemberModel { + readonly kind: 'property' | 'method' | 'getter' | 'setter' | 'call' | 'construct' | 'index'; + readonly name: string; + readonly signature: string; + readonly summary?: string; + readonly jsDoc?: string; +} +/** One named type declaration referenced by a reflected business surface. */ +export interface TypertTypeModel { + readonly name: string; + readonly declaration: string; +} +/** Runtime reflection metadata for one Cordis service. */ +export interface TypertServiceModel extends TypertDocumentation { + readonly key: string; + readonly exportName: string; + readonly members: readonly TypertMemberModel[]; + readonly types: readonly TypertTypeModel[]; +} +/** Runtime reflection metadata for one Cordis event. */ +export interface TypertEventModel extends TypertDocumentation { + readonly name: string; + readonly mode?: string; + readonly signature: string; +} +/** Runtime reflection metadata for one explicitly exported reference object. */ +export interface TypertObjectModel extends TypertDocumentation { + readonly name: string; + readonly exportName: string; + readonly members: readonly TypertMemberModel[]; + readonly types: readonly TypertTypeModel[]; +} +/** Generated business reflection for one package on one face. */ +export interface TypertPackageModel { + readonly services: readonly TypertServiceModel[]; + readonly events: readonly TypertEventModel[]; + readonly objects: readonly TypertObjectModel[]; +} +/** One generated live Zod schema. */ +export interface TypertSchema { + readonly name: string; + readonly schema: z.ZodType; +} +/** One generated package contribution registered and withdrawn atomically. */ +export interface TypertContribution { + readonly package: string; + readonly face: TypertFace; + readonly schemas: readonly TypertSchema[]; + readonly model: TypertPackageModel; + /** Host invocation definitions, empty when the package exports no Remote methods. */ + readonly invocations: readonly InvocationDescriptor[]; +} +/** A live schema plus its contribution identity. */ +export interface TypertSchemaRecord extends TypertSchema { + readonly package: string; + readonly face: TypertFace; + readonly key: string; +} +/** A live generated package model plus its stable identity. */ +export interface TypertPackageRecord { + readonly package: string; + readonly face: TypertFace; + readonly key: string; + readonly model: TypertPackageModel; +} +/** Filter for schema enumeration. */ +export interface TypertSchemaFilter { + readonly package?: string; + readonly face?: TypertFace; +} +/** Filter for package-model enumeration. */ +export interface TypertPackageFilter { + readonly package?: string; + readonly face?: TypertFace; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.js new file mode 100644 index 0000000..2891b59 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/lib/types/types.js @@ -0,0 +1,7 @@ +/** + * Pure generated-artifact and runtime-registry types. The registry stores Zod + * schemas separately from generated package reflection metadata. + * @module @deepseek-ai/dsh-typert-registry/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/package.json new file mode 100644 index 0000000..08c243a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry/package.json @@ -0,0 +1,67 @@ +{ + "name": "@deepseek-ai/dsh-typert-registry", + "description": "Runtime registry for generated package reflection and Zod schemas", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/typert/registry" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client/index.d.ts", + "default": "./lib/client.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "dsh": { + "client": { + "inject": [], + "platform": "web", + "immediately": true + } + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/client.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dependencies": { + "zod": "^4.4.3", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "scripts": { + "bundle": "tsdown", + "watch": "tsdown --watch" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..c833522 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6f3351786c779449c277f079a737f571/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-system-prompt b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-system-prompt new file mode 120000 index 0000000..7b9075d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-system-prompt @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-system-prompt@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_ae19c1446da8797d55176bf5f8e2b0ad/node_modules/@deepseek-ai/dsh-system-prompt \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.i18n.yaml new file mode 100644 index 0000000..07843b5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/interaction/user-approval/README.md +README.md: 0cf5d458863194e29f8c84168a6f089baabbf3d2 +README.zh.md: ccd8641e30d8a78611eabf602fa46d2705f24487 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.md new file mode 100644 index 0000000..0cf5d45 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.md @@ -0,0 +1,62 @@ +# @deepseek-ai/dsh-user-approval + +English | [中文](README.zh.md) + +Channel-neutral one-shot approval seam. `ctx.approval.request(req)` returns `allowed-once`, `rejected`, `cancelled`, or `unavailable`; missing or failing answerers fail closed, and a grant applies only to the requested action. Exact event signatures live in the generated region of [approval.md](../../../docs/subsystems/approval.md#cordis-surface). + +Each request must belong to an open agent turn. The service appends a paired `approval/asked` and `approval/decided` audit record, while the model sees only the resulting logged tool outcome. An aborted request resolves `cancelled`; an audit append that fails before commit rejects rather than returning an unlogged decision. + +Answerers are `approval/request` waterfall listeners. Return an outcome to answer for an owned agent or call `next()` to delegate. Agent-scoped listeners receive only that agent's requests; compose one terminal answerer per deployment because sibling listener order is not a policy priority mechanism. The ACP automation bridge supplies one-shot machine decisions for sessions it owns. + +`ApprovalPolicy` is `'ask'` or `'never'`. The effective value is the last `approval/policy` event, falling back to config; `setApprovalPolicy()` is the write path. `'never'` rejects before interactive dispatch. Both policies contribute their complete current meaning to the cache-safe runtime-context snapshot. + +The tools pipeline routes `ask` decisions through this seam and fails closed when it is absent; the sandboxed bash tool also uses it for escalated retries. The ACP automation bridge answers calls for its own agents through the client's machine policy. Audit events remain log-only, so the model sees only the asking consumer's result. See the [approval-seam Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-approval-seam.md) and [sandbox Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md). + +## Model Experience + +### Current approval policy context + +#### What the model sees + +The first request and each effective policy change append a full runtime-context snapshot after retained history. Under `ask`, the approval contribution states that configured answerers may be consulted and absence fails closed. Under `never`, it states the deterministic rejection and non-escalation consequence. Unchanged requests retain the earlier snapshot without adding another message. + +##### Ask-policy contribution + +```markdown +Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed. +``` + +##### Never-policy contribution + +```markdown +Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`). +``` + +#### Token effect + +One concise context message on the first request and on an effective change; unchanged requests add no duplicate policy tokens. + +#### KV Cache effect + +Append-only after retained history. An `ask`/`never` switch preserves the stable system and conversation prefix instead of rewriting the first wire message. + +### Tool outcome + +#### What the model sees + +`approval/asked` and `approval/decided` are log-only. The model sees only the asking consumer's eventual allowed, rejected, cancelled, or unavailable tool outcome; the human permission UI is not context. + +#### Token effect + +Zero duplicate audit tokens. A rejection may replace a normal tool result with a small retained error, while an allowance leaves the consumer's ordinary result. + +#### KV Cache effect + +Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries. + +## Known Limitations and Deferred Work + +- **Requests are valid only inside an open turn** — an idle or between-turn caller throws before auditing; a durable out-of-turn approval workflow is deferred. +- **Only one-shot grants exist** — the outcome vocabulary has `allowed-once` but no `allow-always`, remembered rule, revocation, or grant store; session policy is only `ask` / `never`. +- **The request carries no tool arguments** — an answerer sees the tool name, reason, and optional call id; the ACP machine channel requires a call id and delegates requests without one. +- **No built-in answerer** — headless or incompletely composed deployments resolve `unavailable` and fail closed; the service itself never prompts a human. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.zh.md new file mode 100644 index 0000000..ccd8641 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/README.zh.md @@ -0,0 +1,62 @@ +# @deepseek-ai/dsh-user-approval + +[English](README.md) | 中文 + +与通道无关的一次性审批 seam。`ctx.approval.request(req)` 返回 `allowed-once`、`rejected`、`cancelled` 或 `unavailable`;应答者缺失或失败时会以拒绝方式关闭,授权也只适用于所请求的操作。确切事件签名见 [approval.md](../../../docs/subsystems/approval.md#cordis-surface) 的生成区块。 + +每个请求都必须属于一个尚未结束的 agent(智能体)轮次。服务会追加一对 `approval/asked` 与 `approval/decided` 审计记录,而模型只会看到由此产生且已写入日志的工具结果。已中止的请求会解析为 `cancelled`;如果审计记录的追加在提交前失败,Promise 会被拒绝,而不会返回一项未记录的决定。 + +应答者是 `approval/request` waterfall(瀑布式事件)监听器。要回答其负责的 agent 请求,请返回一个结果;否则调用 `next()` 委托。限定到 agent 的监听器只接收该 agent 的请求;每项部署应当组合一个最终应答者,因为同级监听器的顺序不是策略优先级机制。ACP(Agent Client Protocol)自动化桥接层为其负责的会话提供一次性机器决定。 + +`ApprovalPolicy` 为 `'ask'` 或 `'never'`。实际值取最后一条 `approval/policy` 事件,并回退到配置;`setApprovalPolicy()` 是写入路径。`'never'` 会在交互式分发之前拒绝请求。两种策略都会将各自完整的当前含义贡献给缓存安全的运行时上下文快照。 + +工具流水线通过此 seam 路由 `ask` 决定,并在该 seam 缺失时以拒绝方式关闭;沙箱 bash 工具也会将它用于升权重试。ACP 自动化桥接层根据客户端的机器策略,回答其自有 agent 的调用。审计事件仍只写入日志,因此模型只会看到发起请求的消费方所返回的结果。详见[审批 seam Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-approval-seam.md)和[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。 + +## 模型体验 + +### 当前审批策略上下文 + +#### 模型看到的内容 + +首次请求和有效策略每次变化时,都会在保留的历史后追加一份完整运行时上下文快照。在 `ask` 下,审批上下文内容会说明系统可以咨询已配置的应答者,缺少可用应答者时则以拒绝方式关闭。在 `never` 下,它会说明确定性的拒绝与非升权后果。未变化的请求会保留先前快照,不增加另一条消息。 + +##### Ask 策略贡献 + +```markdown +Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed. +``` + +##### Never 策略贡献 + +```markdown +Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`). +``` + +#### Token 影响 + +首次请求和策略实际变化时增加一条简洁的上下文消息;未变化的请求不增加重复的策略 token。 + +#### KV Cache 影响 + +在保留的历史之后仅追加。`ask`/`never` 切换会保留稳定的系统与对话前缀,而不会改写第一条 wire 消息。 + +### 工具结果 + +#### 模型看到的内容 + +`approval/asked` 和 `approval/decided` 只写入日志。模型只会看到发起请求的消费方最终给出的允许、拒绝、取消或不可用工具结果;面向人类的权限 UI 不属于上下文。 + +#### Token 影响 + +不会产生重复的审计 token。拒绝可能以一条简短且会保留的错误信息替换正常工具结果,而允许会保留消费方的普通结果。 + +#### KV Cache 影响 + +仅追加;新出现的可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。 + +## 已知限制与暂缓事项 + +- **请求只在尚未结束的轮次内有效**:在空闲时或轮次之间发起调用,会在审计前抛出异常;持久化的轮次外审批工作流仍属暂缓事项。 +- **仅存在一次性授权**:结果词汇包含 `allowed-once`,但不含 `allow-always`、已记住的规则、撤销或授权存储;会话策略只有 `ask`/`never`。 +- **请求不携带工具参数**:应答者会看到工具名称、原因和可选调用 id;ACP 机器通道要求调用 id,并会委托不含 id 的请求。 +- **没有内置应答者**:无头或组合不完整的部署会返回 `unavailable` 并以拒绝方式关闭;服务自身绝不会提示人类。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/index.js new file mode 100644 index 0000000..6160210 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/index.js @@ -0,0 +1,205 @@ +import { randomUUID } from "node:crypto"; +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { createUserMessage } from "@deepseek-ai/dsh-llm"; +import { scopeTarget } from "@deepseek-ai/dsh-scope"; +//#region lib/types/types.js +/** +* Wire-safe approval identifiers and outcome vocabulary, free of +* cordis/service imports so browser type chains (apiproxy api → client) can +* consume them without loading this package's Context augmentation. +* @module @deepseek-ai/dsh-user-approval/types +*/ +/** +* Brand a string as an {@link ApprovalRequestId}. +* @param id - the raw id string to brand. +* @returns the same string carrying the brand. +*/ +function ApprovalRequestId(id) { + return id; +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for the approval capability seam, covering requests, cancellation, audit, and per-session policy. Missing +* answerers fail closed; grants apply only to the requested action. +* @module @deepseek-ai/dsh-user-approval +*/ +/** Every {@link ApprovalOutcome}, for runtime normalization of answerer returns. */ +const OUTCOMES = [ + "allowed-once", + "rejected", + "cancelled", + "unavailable" +]; +/** Every {@link ApprovalPolicy}, for option advertisement and runtime validation of untrusted policy strings. */ +const APPROVAL_POLICIES = ["ask", "never"]; +/** Model-facing statement for the deterministic `'never'` policy. */ +const NEVER_SENTENCE = "Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."; +/** Model-facing statement for an interactive policy that may still fail closed. */ +const ASK_SENTENCE = "Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."; +/** +* The session's approval-policy override: the last `approval/policy` event in +* the log, or undefined when the session never switched (callers apply the +* plugin's configured default). The pure fold — resume needs no catch-up +* machinery because replaying the log IS the state. +* @param events - session events in log order (other event types are skipped). +* @returns the policy of the last switch event, or undefined without one. +*/ +function effectiveApprovalPolicy(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const event = events[index]; + if (event.type === "approval/policy") return event.data.policy; + } +} +/** +* Whether the log currently sits inside an open turn (a `turn/start` not yet +* closed by a `turn/end`) — the {@link ApprovalService.request} precondition. +* The audit pair must be turn-enclosed: the turn is the durable log's +* commit/replay boundary, so a bare event appended between turns is +* indistinguishable from a crash tail and silently dropped on reload. +*/ +function hasOpenTurn(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const type = events[index].type; + if (type === "turn/start") return true; + if (type === "turn/end") return false; + } + return false; +} +/** +* Append the sole durable representation of a session policy override. Invalid +* values throw before the log changes; consumers fold the new value on each read. +* @param session - the session the override belongs to. +* @param policy - the policy in effect until the next switch. +*/ +function setApprovalPolicy(session, policy) { + if (!APPROVAL_POLICIES.includes(policy)) throw new TypeError("approval policy must be one of \"ask\" or \"never\""); + session.append("approval/policy", { policy }); +} +/** +* Approval service that applies session policy before answerers and logs every +* ask/outcome pair to the requesting session. It exposes deterministic policy +* changes to the model through the runtime-context snapshot and switch notices. +*/ +var ApprovalService = class extends Service { + config; + static Config = z.object({ policy: z.union(["ask", "never"]).default("ask") }); + constructor(ctx, config) { + super(ctx, "approval"); + this.config = config; + const effective = (agent) => this.effectivePolicy(agent.session); + ctx.inject(["systemPrompt"], (scope) => { + scope.systemPrompt.context({ + name: "approval:policy", + order: 115, + text: (context) => { + const agent = context.agent; + if (agent === void 0) return ""; + return effective(agent) === "never" ? NEVER_SENTENCE : ASK_SENTENCE; + } + }); + }); + } + /** + * Switch one live agent's policy and queue the transition for its next model + * step. Session initialization uses {@link setApprovalPolicy} directly + * because there is no previously visible policy to change. + * @param agent - the live agent whose policy is changing. + * @param policy - the new effective policy. + */ + setPolicy(agent, policy) { + const previous = this.effectivePolicy(agent.session); + if (previous === policy) return; + setApprovalPolicy(agent.session, policy); + agent.inject(createUserMessage({ + content: [{ + type: "text", + text: `The approval policy changed from "${previous}" to "${policy}" (changed by the user).` + }], + source: { + kind: "plugin", + plugin: "user-approval" + } + })); + } + /** + * Ask the composed answerers to decide one readonly same-process request. + * The service borrows the request, agent, session, and live signal directly. + * The request requires an open turn because the audit pair must be enclosed + * by the durable log's commit/replay boundary; an idle ask rejects before + * appending anything. The answerer phase always produces an outcome: an + * aborted signal yields `'cancelled'`, a missing or throwing answerer yields + * `'unavailable'` (fail closed), and a rogue non-vocabulary return value is + * normalized to `'unavailable'`. A failure that prevents either audit append + * from committing still rejects because returning an unlogged decision would + * violate the pair. Session contains post-commit observer failures, so an + * authoritative append cannot reject the request or suppress its matching + * audit event. + * @param req - the pending decision (agent, tool identity, reason, signal). + * @returns the closed outcome; `'allowed-once'` is the only grant. + * @throws when no turn is open or either audit event fails before the session + * append commit point. + */ + async request(req) { + const session = req.agent.session; + if (!hasOpenTurn(session.events)) throw new Error("approval.request() outside an open turn: the approval/asked + approval/decided audit pair must be turn-enclosed (a bare event between turns is crash-tail garbage on reload). Ask from inside the turn that needs the decision."); + const id = ApprovalRequestId(randomUUID()); + session.append("approval/asked", { + id, + toolName: req.toolName, + ...req.callId !== void 0 ? { callId: req.callId } : {}, + ...req.reason !== void 0 ? { reason: req.reason } : {} + }); + const outcome = await this.decide(req, session); + session.append("approval/decided", { + id, + outcome + }); + return outcome; + } + /** + * The session's effective policy: its own `approval/policy` fold, else the + * configured default (the schema already defaulted an omitted policy to + * `'ask'`; the `??` only narrows the optional-input TYPE). + * @param session - the exact accepted session whose policy applies. + * @returns the policy every ask for this session resolves under right now. + */ + effectivePolicy(session) { + return this.overrideOf(session) ?? this.config.policy ?? "ask"; + } + /** + * Read the session override without applying the configured default. + * @param session - session whose log supplies the override. + * @returns the last logged policy, or `undefined` without one. + */ + overrideOf(session) { + return effectiveApprovalPolicy(session.events); + } + /** + * Dispatch the waterfall, contained and raced against the request signal. + * @param req - the borrowed public request. + * @param session - the request agent's session used for policy lookup. + * @returns the normalized closed outcome. + */ + async decide(req, session) { + const signal = req.signal; + if (signal?.aborted) return "cancelled"; + if (this.effectivePolicy(session) === "never") return "rejected"; + const answer = Promise.resolve().then(() => this.ctx.waterfall(scopeTarget(this, req.agent), "approval/request", req, () => Promise.resolve("unavailable"))).then((outcome) => OUTCOMES.includes(outcome) ? outcome : "unavailable", () => "unavailable"); + if (signal === void 0) return answer; + return await new Promise((resolve) => { + const onAbort = () => { + signal.removeEventListener("abort", onAbort); + resolve("cancelled"); + }; + signal.addEventListener("abort", onAbort, { once: true }); + answer.then((outcome) => { + signal.removeEventListener("abort", onAbort); + resolve(outcome); + }); + }); + } +}; +//#endregion +export { APPROVAL_POLICIES, ApprovalRequestId, ApprovalService, ApprovalService as default, effectiveApprovalPolicy, setApprovalPolicy }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/invariant.js new file mode 100644 index 0000000..1dd84b9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/invariant.js @@ -0,0 +1,297 @@ +import { randomUUID } from "node:crypto"; +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { createUserMessage } from "@deepseek-ai/dsh-llm"; +import { scopeTarget } from "@deepseek-ai/dsh-scope"; +//#region lib/types/types.js +/** +* Wire-safe approval identifiers and outcome vocabulary, free of +* cordis/service imports so browser type chains (apiproxy api → client) can +* consume them without loading this package's Context augmentation. +* @module @deepseek-ai/dsh-user-approval/types +*/ +/** +* Brand a string as an {@link ApprovalRequestId}. +* @param id - the raw id string to brand. +* @returns the same string carrying the brand. +*/ +function ApprovalRequestId(id) { + return id; +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for the approval capability seam, covering requests, cancellation, audit, and per-session policy. Missing +* answerers fail closed; grants apply only to the requested action. +* @module @deepseek-ai/dsh-user-approval +*/ +/** Every {@link ApprovalOutcome}, for runtime normalization of answerer returns. */ +const OUTCOMES = [ + "allowed-once", + "rejected", + "cancelled", + "unavailable" +]; +/** Every {@link ApprovalPolicy}, for option advertisement and runtime validation of untrusted policy strings. */ +const APPROVAL_POLICIES = ["ask", "never"]; +/** Model-facing statement for the deterministic `'never'` policy. */ +const NEVER_SENTENCE = "Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."; +/** Model-facing statement for an interactive policy that may still fail closed. */ +const ASK_SENTENCE = "Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."; +/** +* The session's approval-policy override: the last `approval/policy` event in +* the log, or undefined when the session never switched (callers apply the +* plugin's configured default). The pure fold — resume needs no catch-up +* machinery because replaying the log IS the state. +* @param events - session events in log order (other event types are skipped). +* @returns the policy of the last switch event, or undefined without one. +*/ +function effectiveApprovalPolicy(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const event = events[index]; + if (event.type === "approval/policy") return event.data.policy; + } +} +/** +* Whether the log currently sits inside an open turn (a `turn/start` not yet +* closed by a `turn/end`) — the {@link ApprovalService.request} precondition. +* The audit pair must be turn-enclosed: the turn is the durable log's +* commit/replay boundary, so a bare event appended between turns is +* indistinguishable from a crash tail and silently dropped on reload. +*/ +function hasOpenTurn(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const type = events[index].type; + if (type === "turn/start") return true; + if (type === "turn/end") return false; + } + return false; +} +/** +* Append the sole durable representation of a session policy override. Invalid +* values throw before the log changes; consumers fold the new value on each read. +* @param session - the session the override belongs to. +* @param policy - the policy in effect until the next switch. +*/ +function setApprovalPolicy(session, policy) { + if (!APPROVAL_POLICIES.includes(policy)) throw new TypeError("approval policy must be one of \"ask\" or \"never\""); + session.append("approval/policy", { policy }); +} +(class extends Service { + config; + static Config = z.object({ policy: z.union(["ask", "never"]).default("ask") }); + constructor(ctx, config) { + super(ctx, "approval"); + this.config = config; + const effective = (agent) => this.effectivePolicy(agent.session); + ctx.inject(["systemPrompt"], (scope) => { + scope.systemPrompt.context({ + name: "approval:policy", + order: 115, + text: (context) => { + const agent = context.agent; + if (agent === void 0) return ""; + return effective(agent) === "never" ? NEVER_SENTENCE : ASK_SENTENCE; + } + }); + }); + } + /** + * Switch one live agent's policy and queue the transition for its next model + * step. Session initialization uses {@link setApprovalPolicy} directly + * because there is no previously visible policy to change. + * @param agent - the live agent whose policy is changing. + * @param policy - the new effective policy. + */ + setPolicy(agent, policy) { + const previous = this.effectivePolicy(agent.session); + if (previous === policy) return; + setApprovalPolicy(agent.session, policy); + agent.inject(createUserMessage({ + content: [{ + type: "text", + text: `The approval policy changed from "${previous}" to "${policy}" (changed by the user).` + }], + source: { + kind: "plugin", + plugin: "user-approval" + } + })); + } + /** + * Ask the composed answerers to decide one readonly same-process request. + * The service borrows the request, agent, session, and live signal directly. + * The request requires an open turn because the audit pair must be enclosed + * by the durable log's commit/replay boundary; an idle ask rejects before + * appending anything. The answerer phase always produces an outcome: an + * aborted signal yields `'cancelled'`, a missing or throwing answerer yields + * `'unavailable'` (fail closed), and a rogue non-vocabulary return value is + * normalized to `'unavailable'`. A failure that prevents either audit append + * from committing still rejects because returning an unlogged decision would + * violate the pair. Session contains post-commit observer failures, so an + * authoritative append cannot reject the request or suppress its matching + * audit event. + * @param req - the pending decision (agent, tool identity, reason, signal). + * @returns the closed outcome; `'allowed-once'` is the only grant. + * @throws when no turn is open or either audit event fails before the session + * append commit point. + */ + async request(req) { + const session = req.agent.session; + if (!hasOpenTurn(session.events)) throw new Error("approval.request() outside an open turn: the approval/asked + approval/decided audit pair must be turn-enclosed (a bare event between turns is crash-tail garbage on reload). Ask from inside the turn that needs the decision."); + const id = ApprovalRequestId(randomUUID()); + session.append("approval/asked", { + id, + toolName: req.toolName, + ...req.callId !== void 0 ? { callId: req.callId } : {}, + ...req.reason !== void 0 ? { reason: req.reason } : {} + }); + const outcome = await this.decide(req, session); + session.append("approval/decided", { + id, + outcome + }); + return outcome; + } + /** + * The session's effective policy: its own `approval/policy` fold, else the + * configured default (the schema already defaulted an omitted policy to + * `'ask'`; the `??` only narrows the optional-input TYPE). + * @param session - the exact accepted session whose policy applies. + * @returns the policy every ask for this session resolves under right now. + */ + effectivePolicy(session) { + return this.overrideOf(session) ?? this.config.policy ?? "ask"; + } + /** + * Read the session override without applying the configured default. + * @param session - session whose log supplies the override. + * @returns the last logged policy, or `undefined` without one. + */ + overrideOf(session) { + return effectiveApprovalPolicy(session.events); + } + /** + * Dispatch the waterfall, contained and raced against the request signal. + * @param req - the borrowed public request. + * @param session - the request agent's session used for policy lookup. + * @returns the normalized closed outcome. + */ + async decide(req, session) { + const signal = req.signal; + if (signal?.aborted) return "cancelled"; + if (this.effectivePolicy(session) === "never") return "rejected"; + const answer = Promise.resolve().then(() => this.ctx.waterfall(scopeTarget(this, req.agent), "approval/request", req, () => Promise.resolve("unavailable"))).then((outcome) => OUTCOMES.includes(outcome) ? outcome : "unavailable", () => "unavailable"); + if (signal === void 0) return answer; + return await new Promise((resolve) => { + const onAbort = () => { + signal.removeEventListener("abort", onAbort); + resolve("cancelled"); + }; + signal.addEventListener("abort", onAbort, { once: true }); + answer.then((outcome) => { + signal.removeEventListener("abort", onAbort); + resolve(outcome); + }); + }); + } +}); +//#endregion +//#region lib/types/invariant.js +/** Package-owned approval audit-stream invariants. @module @deepseek-ai/dsh-user-approval/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-user-approval"; +const APPROVAL_OUTCOMES = [ + "allowed-once", + "rejected", + "cancelled", + "unavailable" +]; +/** Cordis companion plugin name. */ +const name = "user-approval-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Validate one approval event against committed unmatched questions. */ +function validateApprovalEvent(trace, event, fail) { + if (event.type === "approval/asked") { + if (trace.openTurn === null) fail("approval/asked appended outside any open turn"); + if (event.data.toolName.length === 0) fail("approval/asked toolName must be non-empty"); + if (trace.pending.has(event.data.id)) fail(`approval/asked repeated open id ${JSON.stringify(event.data.id)}`); + return { + kind: "asked", + id: event.data.id + }; + } + if (event.type === "approval/decided") { + if (trace.openTurn === null) fail("approval/decided appended outside any open turn"); + if (!trace.pending.has(event.data.id)) fail(`approval/decided has no matching approval/asked for id ${JSON.stringify(event.data.id)}`); + if (!APPROVAL_OUTCOMES.includes(event.data.outcome)) fail(`approval/decided carries unknown outcome ${JSON.stringify(event.data.outcome)}`); + return { + kind: "decided", + id: event.data.id + }; + } + if (event.type === "approval/policy" && !APPROVAL_POLICIES.includes(event.data.policy)) fail(`approval/policy carries unknown policy ${JSON.stringify(event.data.policy)}`); +} +/** Apply one accepted approval-pair transition. */ +function applyApprovalTransition(pending, transition) { + if (transition.kind === "asked") pending.add(transition.id); + else pending.delete(transition.id); +} +/** Install audit pairing and closed-vocabulary checks. */ +const install = Object.assign((ctx, fail) => { + const traces = /* @__PURE__ */ new WeakMap(); + const staged = /* @__PURE__ */ new WeakMap(); + const seed = (session) => { + const trace = { + openTurn: null, + pending: /* @__PURE__ */ new Set() + }; + traces.set(session, trace); + for (const event of session.events) { + if (event.type === "turn/start") trace.openTurn = event.data.turn; + else if (event.type === "turn/end") trace.openTurn = null; + const transition = validateApprovalEvent(trace, event, fail); + if (transition !== void 0) applyApprovalTransition(trace.pending, transition); + } + return trace; + }; + const traceFor = (session) => traces.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) seed(session); + ctx.on("session/created", (session) => { + seed(session); + }, { global: true }); + ctx.on("session/event", (session, event) => { + const trace = traceFor(session); + if (event.type === "turn/start") { + trace.openTurn = event.data.turn; + return; + } + if (event.type === "turn/end") { + trace.openTurn = null; + return; + } + if (event.type !== "approval/asked" && event.type !== "approval/decided") return; + const candidate = staged.get(event); + /* v8 ignore next -- internal/dispatch stages every package-owned pair event */ + if (candidate === void 0 || candidate.session !== session) return fail("approval audit event published without pre-commit validation"); + staged.delete(event); + applyApprovalTransition(trace.pending, candidate.transition); + }, { global: true }); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName !== "session/event") return; + const [session, event] = args; + const transition = validateApprovalEvent(traceFor(session), event, fail); + if (transition !== void 0) staged.set(event, { + session, + transition + }); + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register the approval invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.d.ts new file mode 100644 index 0000000..f2849a0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.d.ts @@ -0,0 +1,195 @@ +/** + * Service Definition for the approval capability seam, covering requests, cancellation, audit, and per-session policy. Missing + * answerers fail closed; grants apply only to the requested action. + * @module @deepseek-ai/dsh-user-approval + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import { type CallId } from '@deepseek-ai/dsh-llm'; +import type { Scoped } from '@deepseek-ai/dsh-scope'; +import type { Session, SessionEvent } from '@deepseek-ai/dsh-session'; +declare module '@deepseek-ai/cordis' { + interface Context { + approval: ApprovalService; + } + interface Events { + /** + * Ask composed answerers for one decision. Return an outcome to claim the + * request or call `next()`; failure yields the fail-closed default. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @param req - the pending decision (agent, tool identity, reason, signal). + * @mode waterfall + */ + 'approval/request'(this: Scoped, req: ApprovalRequest, next: () => Promise): Promise; + } +} +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * An approval question was put to the answerer chain — log-only audit + * (like `hook/*`; NOT a surface event, carries no `surfaceOp`). `id` pairs + * it with the `approval/decided` that always follows; `toolName` is the + * tool the question is about, `callId` the exact tool call when the asker + * had one, `reason` the asker's human-readable explanation (e.g. a hook's + * permission-decision reason). + */ + 'approval/asked': { + id: ApprovalRequestId; + toolName: string; + callId?: CallId; + reason?: string; + }; + /** + * The outcome of a prior `approval/asked` (same `id`) — log-only audit. + * Exactly one per ask, appended when the outcome is known: a decision, a + * cancellation, or the fail-closed `'unavailable'`. + */ + 'approval/decided': { + id: ApprovalRequestId; + outcome: ApprovalOutcome; + }; + /** + * The session's approval policy was switched — log-only, durable, + * replayable, never in the model transcript (the model learns the policy + * from the runtime-context snapshot and live switch notices). The LAST + * such event is the session's override ({@link effectiveApprovalPolicy}). + * `source: 'delegation'` marks an override seeded into a child; an absent + * source is a runtime switch. + */ + 'approval/policy': { + policy: ApprovalPolicy; + /** Marks an override seeded into a child at delegation. */ + source?: 'delegation'; + }; + } +} +import { ApprovalRequestId } from './types.ts'; +import type { ApprovalOutcome } from './types.ts'; +export { ApprovalRequestId } from './types.ts'; +export type { ApprovalOutcome } from './types.ts'; +/** + * A session's approval policy — what happens to an {@link ApprovalService} + * ask BEFORE any interactive answerer sees it: + * + * - `'ask'` (the default) — delegate to the composed answerers; with none + * composed the chain falls through to the fail-closed `'unavailable'`. + * - `'never'` — never prompt anyone: every ask resolves `'rejected'` + * deterministically. The strict headless stance (CI, unattended runs) and + * the policy whose outcome is knowable without asking. + */ +export type ApprovalPolicy = 'ask' | 'never'; +/** Every {@link ApprovalPolicy}, for option advertisement and runtime validation of untrusted policy strings. */ +export declare const APPROVAL_POLICIES: readonly ApprovalPolicy[]; +/** + * The session's approval-policy override: the last `approval/policy` event in + * the log, or undefined when the session never switched (callers apply the + * plugin's configured default). The pure fold — resume needs no catch-up + * machinery because replaying the log IS the state. + * @param events - session events in log order (other event types are skipped). + * @returns the policy of the last switch event, or undefined without one. + */ +export declare function effectiveApprovalPolicy(events: readonly SessionEvent[]): ApprovalPolicy | undefined; +/** + * Append the sole durable representation of a session policy override. Invalid + * values throw before the log changes; consumers fold the new value on each read. + * @param session - the session the override belongs to. + * @param policy - the policy in effect until the next switch. + */ +export declare function setApprovalPolicy(session: Session, policy: ApprovalPolicy): void; +/** + * Readonly same-process permission question. `callId` links to an already + * presented tool call, so arguments are not duplicated here. + */ +export interface ApprovalRequest { + /** + * The agent on whose behalf the question is asked. Routes the question (a + * UI answerer only answers for agents it owns) and receives the audit + * events on its session log. + */ + readonly agent: Agent; + /** The tool the question is about (presentation and audit). */ + readonly toolName: string; + /** + * The exact tool call being decided, when the asker has one — lets a UI + * attach the prompt to the tool call it already streamed. + */ + readonly callId?: CallId; + /** The asker's human-readable explanation of WHY it is asking. */ + readonly reason?: string; + /** + * Aborting withdraws the question: the request settles `'cancelled'` + * immediately and a late answer from a still-pending answerer is discarded. + */ + readonly signal?: AbortSignal; +} +/** Plugin config. All optional — `static Config` supplies the defaults. */ +export interface Config { + /** + * The deployment's default {@link ApprovalPolicy} for sessions without an + * `approval/policy` override — `'ask'` delegates to the composed answerers + * (fail-closed with none); `'never'` auto-rejects every ask without + * prompting (the deterministic CI/unattended stance). + */ + readonly policy?: ApprovalPolicy; +} +/** + * Approval service that applies session policy before answerers and logs every + * ask/outcome pair to the requesting session. It exposes deterministic policy + * changes to the model through the runtime-context snapshot and switch notices. + */ +export declare class ApprovalService extends Service { + config: Config; + static Config: z; + constructor(ctx: Context, config: Config); + /** + * Switch one live agent's policy and queue the transition for its next model + * step. Session initialization uses {@link setApprovalPolicy} directly + * because there is no previously visible policy to change. + * @param agent - the live agent whose policy is changing. + * @param policy - the new effective policy. + */ + setPolicy(agent: Agent, policy: ApprovalPolicy): void; + /** + * Ask the composed answerers to decide one readonly same-process request. + * The service borrows the request, agent, session, and live signal directly. + * The request requires an open turn because the audit pair must be enclosed + * by the durable log's commit/replay boundary; an idle ask rejects before + * appending anything. The answerer phase always produces an outcome: an + * aborted signal yields `'cancelled'`, a missing or throwing answerer yields + * `'unavailable'` (fail closed), and a rogue non-vocabulary return value is + * normalized to `'unavailable'`. A failure that prevents either audit append + * from committing still rejects because returning an unlogged decision would + * violate the pair. Session contains post-commit observer failures, so an + * authoritative append cannot reject the request or suppress its matching + * audit event. + * @param req - the pending decision (agent, tool identity, reason, signal). + * @returns the closed outcome; `'allowed-once'` is the only grant. + * @throws when no turn is open or either audit event fails before the session + * append commit point. + */ + request(req: ApprovalRequest): Promise; + /** + * The session's effective policy: its own `approval/policy` fold, else the + * configured default (the schema already defaulted an omitted policy to + * `'ask'`; the `??` only narrows the optional-input TYPE). + * @param session - the exact accepted session whose policy applies. + * @returns the policy every ask for this session resolves under right now. + */ + private effectivePolicy; + /** + * Read the session override without applying the configured default. + * @param session - session whose log supplies the override. + * @returns the last logged policy, or `undefined` without one. + */ + overrideOf(session: Session): ApprovalPolicy | undefined; + /** + * Dispatch the waterfall, contained and raced against the request signal. + * @param req - the borrowed public request. + * @param session - the request agent's session used for policy lookup. + * @returns the normalized closed outcome. + */ + private decide; +} +export default ApprovalService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.js new file mode 100644 index 0000000..aa5a0cd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.js @@ -0,0 +1,217 @@ +/** + * Service Definition for the approval capability seam, covering requests, cancellation, audit, and per-session policy. Missing + * answerers fail closed; grants apply only to the requested action. + * @module @deepseek-ai/dsh-user-approval + */ +import { randomUUID } from 'node:crypto'; +import { Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { createUserMessage } from '@deepseek-ai/dsh-llm'; +import { scopeTarget } from '@deepseek-ai/dsh-scope'; +import { ApprovalRequestId } from "./types.js"; +export { ApprovalRequestId } from "./types.js"; +/** Every {@link ApprovalOutcome}, for runtime normalization of answerer returns. */ +const OUTCOMES = ['allowed-once', 'rejected', 'cancelled', 'unavailable']; +/** Every {@link ApprovalPolicy}, for option advertisement and runtime validation of untrusted policy strings. */ +export const APPROVAL_POLICIES = ['ask', 'never']; +/** Model-facing statement for the deterministic `'never'` policy. */ +const NEVER_SENTENCE = 'Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).'; +/** Model-facing statement for an interactive policy that may still fail closed. */ +const ASK_SENTENCE = 'Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.'; +/** + * The session's approval-policy override: the last `approval/policy` event in + * the log, or undefined when the session never switched (callers apply the + * plugin's configured default). The pure fold — resume needs no catch-up + * machinery because replaying the log IS the state. + * @param events - session events in log order (other event types are skipped). + * @returns the policy of the last switch event, or undefined without one. + */ +export function effectiveApprovalPolicy(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const event = events[index]; + if (event.type === 'approval/policy') + return event.data.policy; + } + return undefined; +} +/** + * Whether the log currently sits inside an open turn (a `turn/start` not yet + * closed by a `turn/end`) — the {@link ApprovalService.request} precondition. + * The audit pair must be turn-enclosed: the turn is the durable log's + * commit/replay boundary, so a bare event appended between turns is + * indistinguishable from a crash tail and silently dropped on reload. + */ +function hasOpenTurn(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const type = events[index].type; + if (type === 'turn/start') + return true; + if (type === 'turn/end') + return false; + } + return false; +} +/** + * Append the sole durable representation of a session policy override. Invalid + * values throw before the log changes; consumers fold the new value on each read. + * @param session - the session the override belongs to. + * @param policy - the policy in effect until the next switch. + */ +export function setApprovalPolicy(session, policy) { + if (!APPROVAL_POLICIES.includes(policy)) { + throw new TypeError('approval policy must be one of "ask" or "never"'); + } + session.append('approval/policy', { policy }); +} +/** + * Approval service that applies session policy before answerers and logs every + * ask/outcome pair to the requesting session. It exposes deterministic policy + * changes to the model through the runtime-context snapshot and switch notices. + */ +export class ApprovalService extends Service { + config; + static Config = z.object({ + policy: z.union(['ask', 'never']).default('ask'), + }); + constructor(ctx, config) { + super(ctx, 'approval'); + this.config = config; + const effective = (agent) => this.effectivePolicy(agent.session); + // The complete current value travels after retained history, so switching + // policy does not rewrite the stable system-prompt cache prefix. + ctx.inject(['systemPrompt'], (scope) => { + scope.systemPrompt.context({ + name: 'approval:policy', + order: 115, + text: (context) => { + const agent = context.agent; + // A bare assemble() (tests, diagnostics) has no session to state. + if (agent === undefined) + return ''; + const policy = effective(agent); + return policy === 'never' ? NEVER_SENTENCE : ASK_SENTENCE; + }, + }); + }); + } + /** + * Switch one live agent's policy and queue the transition for its next model + * step. Session initialization uses {@link setApprovalPolicy} directly + * because there is no previously visible policy to change. + * @param agent - the live agent whose policy is changing. + * @param policy - the new effective policy. + */ + setPolicy(agent, policy) { + const previous = this.effectivePolicy(agent.session); + if (previous === policy) + return; + setApprovalPolicy(agent.session, policy); + agent.inject(createUserMessage({ + content: [{ + type: 'text', + text: `The approval policy changed from "${previous}" to "${policy}" (changed by the user).`, + }], + source: { kind: 'plugin', plugin: 'user-approval' }, + })); + } + /** + * Ask the composed answerers to decide one readonly same-process request. + * The service borrows the request, agent, session, and live signal directly. + * The request requires an open turn because the audit pair must be enclosed + * by the durable log's commit/replay boundary; an idle ask rejects before + * appending anything. The answerer phase always produces an outcome: an + * aborted signal yields `'cancelled'`, a missing or throwing answerer yields + * `'unavailable'` (fail closed), and a rogue non-vocabulary return value is + * normalized to `'unavailable'`. A failure that prevents either audit append + * from committing still rejects because returning an unlogged decision would + * violate the pair. Session contains post-commit observer failures, so an + * authoritative append cannot reject the request or suppress its matching + * audit event. + * @param req - the pending decision (agent, tool identity, reason, signal). + * @returns the closed outcome; `'allowed-once'` is the only grant. + * @throws when no turn is open or either audit event fails before the session + * append commit point. + */ + async request(req) { + const session = req.agent.session; + if (!hasOpenTurn(session.events)) { + throw new Error('approval.request() outside an open turn: the approval/asked + approval/decided audit pair ' + + 'must be turn-enclosed (a bare event between turns is crash-tail garbage on reload). ' + + 'Ask from inside the turn that needs the decision.'); + } + const id = ApprovalRequestId(randomUUID()); + session.append('approval/asked', { + id, + toolName: req.toolName, + ...req.callId !== undefined ? { callId: req.callId } : {}, + ...req.reason !== undefined ? { reason: req.reason } : {}, + }); + const outcome = await this.decide(req, session); + session.append('approval/decided', { id, outcome }); + return outcome; + } + /** + * The session's effective policy: its own `approval/policy` fold, else the + * configured default (the schema already defaulted an omitted policy to + * `'ask'`; the `??` only narrows the optional-input TYPE). + * @param session - the exact accepted session whose policy applies. + * @returns the policy every ask for this session resolves under right now. + */ + effectivePolicy(session) { + return this.overrideOf(session) ?? this.config.policy ?? 'ask'; + } + /** + * Read the session override without applying the configured default. + * @param session - session whose log supplies the override. + * @returns the last logged policy, or `undefined` without one. + */ + overrideOf(session) { + return effectiveApprovalPolicy(session.events); + } + /** + * Dispatch the waterfall, contained and raced against the request signal. + * @param req - the borrowed public request. + * @param session - the request agent's session used for policy lookup. + * @returns the normalized closed outcome. + */ + async decide(req, session) { + const signal = req.signal; + if (signal?.aborted) + return 'cancelled'; + // The 'never' policy is decided HERE, before any dispatch: a listener + // registered with `prepend: true` after this service mounts would sit + // ahead of any gate LISTENER, so a listener-shaped gate cannot keep the + // documented promise that 'never' rejects deterministically regardless + // of registration order — only the service's own request path can. + if (this.effectivePolicy(session) === 'never') + return 'rejected'; + // Enter the promise chain BEFORE dispatching: a listener that throws + // SYNCHRONOUSLY (before its first await) must land in the same rejection + // path as an async one — `Promise.resolve(call())` would let it escape + // the containment into the caller. + const answer = Promise.resolve().then(() => this.ctx.waterfall(scopeTarget(this, req.agent), 'approval/request', req, () => Promise.resolve('unavailable'))).then( + // Normalize a rogue (non-vocabulary) answerer return to the fail-closed + // outcome instead of leaking it into callers' closed-union switches. + outcome => OUTCOMES.includes(outcome) ? outcome : 'unavailable', + // A throwing answerer must fail the QUESTION closed, not the caller's + // tool call open — the seam contains its callbacks. + () => 'unavailable'); + if (signal === undefined) + return answer; + return await new Promise((resolve) => { + const onAbort = () => { + signal.removeEventListener('abort', onAbort); + resolve('cancelled'); + }; + signal.addEventListener('abort', onAbort, { once: true }); + void answer.then((outcome) => { + signal.removeEventListener('abort', onAbort); + // After an abort won the race this resolve is a settled-promise no-op: + // the late answer is discarded by construction. + resolve(outcome); + }); + }); + } +} +export default ApprovalService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.d.ts new file mode 100644 index 0000000..aff2f05 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned approval audit-stream invariants. @module @deepseek-ai/dsh-user-approval/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "user-approval-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the approval invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.js new file mode 100644 index 0000000..b79a940 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.js @@ -0,0 +1,101 @@ +/** Package-owned approval audit-stream invariants. @module @deepseek-ai/dsh-user-approval/invariant */ +import { APPROVAL_POLICIES } from "./index.js"; +const PACKAGE_NAME = '@deepseek-ai/dsh-user-approval'; +const APPROVAL_OUTCOMES = ['allowed-once', 'rejected', 'cancelled', 'unavailable']; +/** Cordis companion plugin name. */ +export const name = 'user-approval-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Validate one approval event against committed unmatched questions. */ +function validateApprovalEvent(trace, event, fail) { + if (event.type === 'approval/asked') { + if (trace.openTurn === null) + fail('approval/asked appended outside any open turn'); + if (event.data.toolName.length === 0) + fail('approval/asked toolName must be non-empty'); + if (trace.pending.has(event.data.id)) + fail(`approval/asked repeated open id ${JSON.stringify(event.data.id)}`); + return { kind: 'asked', id: event.data.id }; + } + if (event.type === 'approval/decided') { + if (trace.openTurn === null) + fail('approval/decided appended outside any open turn'); + if (!trace.pending.has(event.data.id)) + fail(`approval/decided has no matching approval/asked for id ${JSON.stringify(event.data.id)}`); + if (!APPROVAL_OUTCOMES.includes(event.data.outcome)) { + fail(`approval/decided carries unknown outcome ${JSON.stringify(event.data.outcome)}`); + } + return { kind: 'decided', id: event.data.id }; + } + if (event.type === 'approval/policy' && !APPROVAL_POLICIES.includes(event.data.policy)) { + fail(`approval/policy carries unknown policy ${JSON.stringify(event.data.policy)}`); + } + return undefined; +} +/** Apply one accepted approval-pair transition. */ +function applyApprovalTransition(pending, transition) { + if (transition.kind === 'asked') + pending.add(transition.id); + else + pending.delete(transition.id); +} +/** Install audit pairing and closed-vocabulary checks. */ +// Event owners keep precommit staging local so their vocabularies never move into a central helper. +/* jscpd:ignore-start */ +const install = Object.assign((ctx, fail) => { + const traces = new WeakMap(); + const staged = new WeakMap(); + const seed = (session) => { + const trace = { openTurn: null, pending: new Set() }; + traces.set(session, trace); + for (const event of session.events) { + if (event.type === 'turn/start') + trace.openTurn = event.data.turn; + else if (event.type === 'turn/end') + trace.openTurn = null; + const transition = validateApprovalEvent(trace, event, fail); + if (transition !== undefined) + applyApprovalTransition(trace.pending, transition); + } + return trace; + }; + const traceFor = (session) => traces.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) + seed(session); + ctx.on('session/created', (session) => { seed(session); }, { global: true }); + ctx.on('session/event', (session, event) => { + const trace = traceFor(session); + if (event.type === 'turn/start') { + trace.openTurn = event.data.turn; + return; + } + if (event.type === 'turn/end') { + trace.openTurn = null; + return; + } + if (event.type !== 'approval/asked' && event.type !== 'approval/decided') + return; + const candidate = staged.get(event); + /* v8 ignore next -- internal/dispatch stages every package-owned pair event */ + if (candidate === undefined || candidate.session !== session) + return fail('approval audit event published without pre-commit validation'); + staged.delete(event); + applyApprovalTransition(trace.pending, candidate.transition); + }, { global: true }); + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') + return; + const [session, event] = args; + const transition = validateApprovalEvent(traceFor(session), event, fail); + if (transition !== undefined) + staged.set(event, { session, transition }); + }, { global: true }); +}, { inject: ['sessions'] }); +/* jscpd:ignore-end */ +/** + * Register the approval invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.d.ts new file mode 100644 index 0000000..734d11e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.d.ts @@ -0,0 +1,24 @@ +/** + * Wire-safe approval identifiers and outcome vocabulary, free of + * cordis/service imports so browser type chains (apiproxy api → client) can + * consume them without loading this package's Context augmentation. + * @module @deepseek-ai/dsh-user-approval/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** + * Pairs one `approval/asked` audit event with its `approval/decided`. + * Service-issued (one fresh id per {@link ApprovalService.request} call). + */ +export type ApprovalRequestId = Branded<'ApprovalRequestId'>; +/** + * Brand a string as an {@link ApprovalRequestId}. + * @param id - the raw id string to brand. + * @returns the same string carrying the brand. + */ +export declare function ApprovalRequestId(id: string): ApprovalRequestId; +/** + * Closed approval outcomes: a one-shot grant, explicit rejection, withdrawn + * request, or unavailable answerer. Callers fail closed on `unavailable`. + */ +export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable'; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.js new file mode 100644 index 0000000..08ed322 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.js @@ -0,0 +1,15 @@ +/** + * Wire-safe approval identifiers and outcome vocabulary, free of + * cordis/service imports so browser type chains (apiproxy api → client) can + * consume them without loading this package's Context augmentation. + * @module @deepseek-ai/dsh-user-approval/types + */ +/** + * Brand a string as an {@link ApprovalRequestId}. + * @param id - the raw id string to brand. + * @returns the same string carrying the brand. + */ +export function ApprovalRequestId(id) { + return id; +} +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/package.json new file mode 100644 index 0000000..7f7b47a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/dsh-user-approval/package.json @@ -0,0 +1,62 @@ +{ + "name": "@deepseek-ai/dsh-user-approval", + "description": "User-approval seam (ctx.approval) for the DeepSeek Harness: one-shot permission decisions dispatched to composed answerers over the approval/request waterfall, fail-closed by default", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/interaction/user-approval" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.6_dbdaba06c174c5e30e3a58edf3cc27a9/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..e19b533 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-system-prompt b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-system-prompt new file mode 120000 index 0000000..943dd86 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-system-prompt @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.i18n.yaml new file mode 100644 index 0000000..07843b5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/interaction/user-approval/README.md +README.md: 0cf5d458863194e29f8c84168a6f089baabbf3d2 +README.zh.md: ccd8641e30d8a78611eabf602fa46d2705f24487 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.md new file mode 100644 index 0000000..0cf5d45 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.md @@ -0,0 +1,62 @@ +# @deepseek-ai/dsh-user-approval + +English | [中文](README.zh.md) + +Channel-neutral one-shot approval seam. `ctx.approval.request(req)` returns `allowed-once`, `rejected`, `cancelled`, or `unavailable`; missing or failing answerers fail closed, and a grant applies only to the requested action. Exact event signatures live in the generated region of [approval.md](../../../docs/subsystems/approval.md#cordis-surface). + +Each request must belong to an open agent turn. The service appends a paired `approval/asked` and `approval/decided` audit record, while the model sees only the resulting logged tool outcome. An aborted request resolves `cancelled`; an audit append that fails before commit rejects rather than returning an unlogged decision. + +Answerers are `approval/request` waterfall listeners. Return an outcome to answer for an owned agent or call `next()` to delegate. Agent-scoped listeners receive only that agent's requests; compose one terminal answerer per deployment because sibling listener order is not a policy priority mechanism. The ACP automation bridge supplies one-shot machine decisions for sessions it owns. + +`ApprovalPolicy` is `'ask'` or `'never'`. The effective value is the last `approval/policy` event, falling back to config; `setApprovalPolicy()` is the write path. `'never'` rejects before interactive dispatch. Both policies contribute their complete current meaning to the cache-safe runtime-context snapshot. + +The tools pipeline routes `ask` decisions through this seam and fails closed when it is absent; the sandboxed bash tool also uses it for escalated retries. The ACP automation bridge answers calls for its own agents through the client's machine policy. Audit events remain log-only, so the model sees only the asking consumer's result. See the [approval-seam Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-approval-seam.md) and [sandbox Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md). + +## Model Experience + +### Current approval policy context + +#### What the model sees + +The first request and each effective policy change append a full runtime-context snapshot after retained history. Under `ask`, the approval contribution states that configured answerers may be consulted and absence fails closed. Under `never`, it states the deterministic rejection and non-escalation consequence. Unchanged requests retain the earlier snapshot without adding another message. + +##### Ask-policy contribution + +```markdown +Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed. +``` + +##### Never-policy contribution + +```markdown +Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`). +``` + +#### Token effect + +One concise context message on the first request and on an effective change; unchanged requests add no duplicate policy tokens. + +#### KV Cache effect + +Append-only after retained history. An `ask`/`never` switch preserves the stable system and conversation prefix instead of rewriting the first wire message. + +### Tool outcome + +#### What the model sees + +`approval/asked` and `approval/decided` are log-only. The model sees only the asking consumer's eventual allowed, rejected, cancelled, or unavailable tool outcome; the human permission UI is not context. + +#### Token effect + +Zero duplicate audit tokens. A rejection may replace a normal tool result with a small retained error, while an allowance leaves the consumer's ordinary result. + +#### KV Cache effect + +Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries. + +## Known Limitations and Deferred Work + +- **Requests are valid only inside an open turn** — an idle or between-turn caller throws before auditing; a durable out-of-turn approval workflow is deferred. +- **Only one-shot grants exist** — the outcome vocabulary has `allowed-once` but no `allow-always`, remembered rule, revocation, or grant store; session policy is only `ask` / `never`. +- **The request carries no tool arguments** — an answerer sees the tool name, reason, and optional call id; the ACP machine channel requires a call id and delegates requests without one. +- **No built-in answerer** — headless or incompletely composed deployments resolve `unavailable` and fail closed; the service itself never prompts a human. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.zh.md new file mode 100644 index 0000000..ccd8641 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/README.zh.md @@ -0,0 +1,62 @@ +# @deepseek-ai/dsh-user-approval + +[English](README.md) | 中文 + +与通道无关的一次性审批 seam。`ctx.approval.request(req)` 返回 `allowed-once`、`rejected`、`cancelled` 或 `unavailable`;应答者缺失或失败时会以拒绝方式关闭,授权也只适用于所请求的操作。确切事件签名见 [approval.md](../../../docs/subsystems/approval.md#cordis-surface) 的生成区块。 + +每个请求都必须属于一个尚未结束的 agent(智能体)轮次。服务会追加一对 `approval/asked` 与 `approval/decided` 审计记录,而模型只会看到由此产生且已写入日志的工具结果。已中止的请求会解析为 `cancelled`;如果审计记录的追加在提交前失败,Promise 会被拒绝,而不会返回一项未记录的决定。 + +应答者是 `approval/request` waterfall(瀑布式事件)监听器。要回答其负责的 agent 请求,请返回一个结果;否则调用 `next()` 委托。限定到 agent 的监听器只接收该 agent 的请求;每项部署应当组合一个最终应答者,因为同级监听器的顺序不是策略优先级机制。ACP(Agent Client Protocol)自动化桥接层为其负责的会话提供一次性机器决定。 + +`ApprovalPolicy` 为 `'ask'` 或 `'never'`。实际值取最后一条 `approval/policy` 事件,并回退到配置;`setApprovalPolicy()` 是写入路径。`'never'` 会在交互式分发之前拒绝请求。两种策略都会将各自完整的当前含义贡献给缓存安全的运行时上下文快照。 + +工具流水线通过此 seam 路由 `ask` 决定,并在该 seam 缺失时以拒绝方式关闭;沙箱 bash 工具也会将它用于升权重试。ACP 自动化桥接层根据客户端的机器策略,回答其自有 agent 的调用。审计事件仍只写入日志,因此模型只会看到发起请求的消费方所返回的结果。详见[审批 seam Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-approval-seam.md)和[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。 + +## 模型体验 + +### 当前审批策略上下文 + +#### 模型看到的内容 + +首次请求和有效策略每次变化时,都会在保留的历史后追加一份完整运行时上下文快照。在 `ask` 下,审批上下文内容会说明系统可以咨询已配置的应答者,缺少可用应答者时则以拒绝方式关闭。在 `never` 下,它会说明确定性的拒绝与非升权后果。未变化的请求会保留先前快照,不增加另一条消息。 + +##### Ask 策略贡献 + +```markdown +Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed. +``` + +##### Never 策略贡献 + +```markdown +Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`). +``` + +#### Token 影响 + +首次请求和策略实际变化时增加一条简洁的上下文消息;未变化的请求不增加重复的策略 token。 + +#### KV Cache 影响 + +在保留的历史之后仅追加。`ask`/`never` 切换会保留稳定的系统与对话前缀,而不会改写第一条 wire 消息。 + +### 工具结果 + +#### 模型看到的内容 + +`approval/asked` 和 `approval/decided` 只写入日志。模型只会看到发起请求的消费方最终给出的允许、拒绝、取消或不可用工具结果;面向人类的权限 UI 不属于上下文。 + +#### Token 影响 + +不会产生重复的审计 token。拒绝可能以一条简短且会保留的错误信息替换正常工具结果,而允许会保留消费方的普通结果。 + +#### KV Cache 影响 + +仅追加;新出现的可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。 + +## 已知限制与暂缓事项 + +- **请求只在尚未结束的轮次内有效**:在空闲时或轮次之间发起调用,会在审计前抛出异常;持久化的轮次外审批工作流仍属暂缓事项。 +- **仅存在一次性授权**:结果词汇包含 `allowed-once`,但不含 `allow-always`、已记住的规则、撤销或授权存储;会话策略只有 `ask`/`never`。 +- **请求不携带工具参数**:应答者会看到工具名称、原因和可选调用 id;ACP 机器通道要求调用 id,并会委托不含 id 的请求。 +- **没有内置应答者**:无头或组合不完整的部署会返回 `unavailable` 并以拒绝方式关闭;服务自身绝不会提示人类。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/index.js new file mode 100644 index 0000000..6160210 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/index.js @@ -0,0 +1,205 @@ +import { randomUUID } from "node:crypto"; +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { createUserMessage } from "@deepseek-ai/dsh-llm"; +import { scopeTarget } from "@deepseek-ai/dsh-scope"; +//#region lib/types/types.js +/** +* Wire-safe approval identifiers and outcome vocabulary, free of +* cordis/service imports so browser type chains (apiproxy api → client) can +* consume them without loading this package's Context augmentation. +* @module @deepseek-ai/dsh-user-approval/types +*/ +/** +* Brand a string as an {@link ApprovalRequestId}. +* @param id - the raw id string to brand. +* @returns the same string carrying the brand. +*/ +function ApprovalRequestId(id) { + return id; +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for the approval capability seam, covering requests, cancellation, audit, and per-session policy. Missing +* answerers fail closed; grants apply only to the requested action. +* @module @deepseek-ai/dsh-user-approval +*/ +/** Every {@link ApprovalOutcome}, for runtime normalization of answerer returns. */ +const OUTCOMES = [ + "allowed-once", + "rejected", + "cancelled", + "unavailable" +]; +/** Every {@link ApprovalPolicy}, for option advertisement and runtime validation of untrusted policy strings. */ +const APPROVAL_POLICIES = ["ask", "never"]; +/** Model-facing statement for the deterministic `'never'` policy. */ +const NEVER_SENTENCE = "Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."; +/** Model-facing statement for an interactive policy that may still fail closed. */ +const ASK_SENTENCE = "Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."; +/** +* The session's approval-policy override: the last `approval/policy` event in +* the log, or undefined when the session never switched (callers apply the +* plugin's configured default). The pure fold — resume needs no catch-up +* machinery because replaying the log IS the state. +* @param events - session events in log order (other event types are skipped). +* @returns the policy of the last switch event, or undefined without one. +*/ +function effectiveApprovalPolicy(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const event = events[index]; + if (event.type === "approval/policy") return event.data.policy; + } +} +/** +* Whether the log currently sits inside an open turn (a `turn/start` not yet +* closed by a `turn/end`) — the {@link ApprovalService.request} precondition. +* The audit pair must be turn-enclosed: the turn is the durable log's +* commit/replay boundary, so a bare event appended between turns is +* indistinguishable from a crash tail and silently dropped on reload. +*/ +function hasOpenTurn(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const type = events[index].type; + if (type === "turn/start") return true; + if (type === "turn/end") return false; + } + return false; +} +/** +* Append the sole durable representation of a session policy override. Invalid +* values throw before the log changes; consumers fold the new value on each read. +* @param session - the session the override belongs to. +* @param policy - the policy in effect until the next switch. +*/ +function setApprovalPolicy(session, policy) { + if (!APPROVAL_POLICIES.includes(policy)) throw new TypeError("approval policy must be one of \"ask\" or \"never\""); + session.append("approval/policy", { policy }); +} +/** +* Approval service that applies session policy before answerers and logs every +* ask/outcome pair to the requesting session. It exposes deterministic policy +* changes to the model through the runtime-context snapshot and switch notices. +*/ +var ApprovalService = class extends Service { + config; + static Config = z.object({ policy: z.union(["ask", "never"]).default("ask") }); + constructor(ctx, config) { + super(ctx, "approval"); + this.config = config; + const effective = (agent) => this.effectivePolicy(agent.session); + ctx.inject(["systemPrompt"], (scope) => { + scope.systemPrompt.context({ + name: "approval:policy", + order: 115, + text: (context) => { + const agent = context.agent; + if (agent === void 0) return ""; + return effective(agent) === "never" ? NEVER_SENTENCE : ASK_SENTENCE; + } + }); + }); + } + /** + * Switch one live agent's policy and queue the transition for its next model + * step. Session initialization uses {@link setApprovalPolicy} directly + * because there is no previously visible policy to change. + * @param agent - the live agent whose policy is changing. + * @param policy - the new effective policy. + */ + setPolicy(agent, policy) { + const previous = this.effectivePolicy(agent.session); + if (previous === policy) return; + setApprovalPolicy(agent.session, policy); + agent.inject(createUserMessage({ + content: [{ + type: "text", + text: `The approval policy changed from "${previous}" to "${policy}" (changed by the user).` + }], + source: { + kind: "plugin", + plugin: "user-approval" + } + })); + } + /** + * Ask the composed answerers to decide one readonly same-process request. + * The service borrows the request, agent, session, and live signal directly. + * The request requires an open turn because the audit pair must be enclosed + * by the durable log's commit/replay boundary; an idle ask rejects before + * appending anything. The answerer phase always produces an outcome: an + * aborted signal yields `'cancelled'`, a missing or throwing answerer yields + * `'unavailable'` (fail closed), and a rogue non-vocabulary return value is + * normalized to `'unavailable'`. A failure that prevents either audit append + * from committing still rejects because returning an unlogged decision would + * violate the pair. Session contains post-commit observer failures, so an + * authoritative append cannot reject the request or suppress its matching + * audit event. + * @param req - the pending decision (agent, tool identity, reason, signal). + * @returns the closed outcome; `'allowed-once'` is the only grant. + * @throws when no turn is open or either audit event fails before the session + * append commit point. + */ + async request(req) { + const session = req.agent.session; + if (!hasOpenTurn(session.events)) throw new Error("approval.request() outside an open turn: the approval/asked + approval/decided audit pair must be turn-enclosed (a bare event between turns is crash-tail garbage on reload). Ask from inside the turn that needs the decision."); + const id = ApprovalRequestId(randomUUID()); + session.append("approval/asked", { + id, + toolName: req.toolName, + ...req.callId !== void 0 ? { callId: req.callId } : {}, + ...req.reason !== void 0 ? { reason: req.reason } : {} + }); + const outcome = await this.decide(req, session); + session.append("approval/decided", { + id, + outcome + }); + return outcome; + } + /** + * The session's effective policy: its own `approval/policy` fold, else the + * configured default (the schema already defaulted an omitted policy to + * `'ask'`; the `??` only narrows the optional-input TYPE). + * @param session - the exact accepted session whose policy applies. + * @returns the policy every ask for this session resolves under right now. + */ + effectivePolicy(session) { + return this.overrideOf(session) ?? this.config.policy ?? "ask"; + } + /** + * Read the session override without applying the configured default. + * @param session - session whose log supplies the override. + * @returns the last logged policy, or `undefined` without one. + */ + overrideOf(session) { + return effectiveApprovalPolicy(session.events); + } + /** + * Dispatch the waterfall, contained and raced against the request signal. + * @param req - the borrowed public request. + * @param session - the request agent's session used for policy lookup. + * @returns the normalized closed outcome. + */ + async decide(req, session) { + const signal = req.signal; + if (signal?.aborted) return "cancelled"; + if (this.effectivePolicy(session) === "never") return "rejected"; + const answer = Promise.resolve().then(() => this.ctx.waterfall(scopeTarget(this, req.agent), "approval/request", req, () => Promise.resolve("unavailable"))).then((outcome) => OUTCOMES.includes(outcome) ? outcome : "unavailable", () => "unavailable"); + if (signal === void 0) return answer; + return await new Promise((resolve) => { + const onAbort = () => { + signal.removeEventListener("abort", onAbort); + resolve("cancelled"); + }; + signal.addEventListener("abort", onAbort, { once: true }); + answer.then((outcome) => { + signal.removeEventListener("abort", onAbort); + resolve(outcome); + }); + }); + } +}; +//#endregion +export { APPROVAL_POLICIES, ApprovalRequestId, ApprovalService, ApprovalService as default, effectiveApprovalPolicy, setApprovalPolicy }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/invariant.js new file mode 100644 index 0000000..1dd84b9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/invariant.js @@ -0,0 +1,297 @@ +import { randomUUID } from "node:crypto"; +import { Service } from "@deepseek-ai/cordis"; +import z from "@deepseek-ai/schemastery"; +import { createUserMessage } from "@deepseek-ai/dsh-llm"; +import { scopeTarget } from "@deepseek-ai/dsh-scope"; +//#region lib/types/types.js +/** +* Wire-safe approval identifiers and outcome vocabulary, free of +* cordis/service imports so browser type chains (apiproxy api → client) can +* consume them without loading this package's Context augmentation. +* @module @deepseek-ai/dsh-user-approval/types +*/ +/** +* Brand a string as an {@link ApprovalRequestId}. +* @param id - the raw id string to brand. +* @returns the same string carrying the brand. +*/ +function ApprovalRequestId(id) { + return id; +} +//#endregion +//#region lib/types/index.js +/** +* Service Definition for the approval capability seam, covering requests, cancellation, audit, and per-session policy. Missing +* answerers fail closed; grants apply only to the requested action. +* @module @deepseek-ai/dsh-user-approval +*/ +/** Every {@link ApprovalOutcome}, for runtime normalization of answerer returns. */ +const OUTCOMES = [ + "allowed-once", + "rejected", + "cancelled", + "unavailable" +]; +/** Every {@link ApprovalPolicy}, for option advertisement and runtime validation of untrusted policy strings. */ +const APPROVAL_POLICIES = ["ask", "never"]; +/** Model-facing statement for the deterministic `'never'` policy. */ +const NEVER_SENTENCE = "Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."; +/** Model-facing statement for an interactive policy that may still fail closed. */ +const ASK_SENTENCE = "Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."; +/** +* The session's approval-policy override: the last `approval/policy` event in +* the log, or undefined when the session never switched (callers apply the +* plugin's configured default). The pure fold — resume needs no catch-up +* machinery because replaying the log IS the state. +* @param events - session events in log order (other event types are skipped). +* @returns the policy of the last switch event, or undefined without one. +*/ +function effectiveApprovalPolicy(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const event = events[index]; + if (event.type === "approval/policy") return event.data.policy; + } +} +/** +* Whether the log currently sits inside an open turn (a `turn/start` not yet +* closed by a `turn/end`) — the {@link ApprovalService.request} precondition. +* The audit pair must be turn-enclosed: the turn is the durable log's +* commit/replay boundary, so a bare event appended between turns is +* indistinguishable from a crash tail and silently dropped on reload. +*/ +function hasOpenTurn(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const type = events[index].type; + if (type === "turn/start") return true; + if (type === "turn/end") return false; + } + return false; +} +/** +* Append the sole durable representation of a session policy override. Invalid +* values throw before the log changes; consumers fold the new value on each read. +* @param session - the session the override belongs to. +* @param policy - the policy in effect until the next switch. +*/ +function setApprovalPolicy(session, policy) { + if (!APPROVAL_POLICIES.includes(policy)) throw new TypeError("approval policy must be one of \"ask\" or \"never\""); + session.append("approval/policy", { policy }); +} +(class extends Service { + config; + static Config = z.object({ policy: z.union(["ask", "never"]).default("ask") }); + constructor(ctx, config) { + super(ctx, "approval"); + this.config = config; + const effective = (agent) => this.effectivePolicy(agent.session); + ctx.inject(["systemPrompt"], (scope) => { + scope.systemPrompt.context({ + name: "approval:policy", + order: 115, + text: (context) => { + const agent = context.agent; + if (agent === void 0) return ""; + return effective(agent) === "never" ? NEVER_SENTENCE : ASK_SENTENCE; + } + }); + }); + } + /** + * Switch one live agent's policy and queue the transition for its next model + * step. Session initialization uses {@link setApprovalPolicy} directly + * because there is no previously visible policy to change. + * @param agent - the live agent whose policy is changing. + * @param policy - the new effective policy. + */ + setPolicy(agent, policy) { + const previous = this.effectivePolicy(agent.session); + if (previous === policy) return; + setApprovalPolicy(agent.session, policy); + agent.inject(createUserMessage({ + content: [{ + type: "text", + text: `The approval policy changed from "${previous}" to "${policy}" (changed by the user).` + }], + source: { + kind: "plugin", + plugin: "user-approval" + } + })); + } + /** + * Ask the composed answerers to decide one readonly same-process request. + * The service borrows the request, agent, session, and live signal directly. + * The request requires an open turn because the audit pair must be enclosed + * by the durable log's commit/replay boundary; an idle ask rejects before + * appending anything. The answerer phase always produces an outcome: an + * aborted signal yields `'cancelled'`, a missing or throwing answerer yields + * `'unavailable'` (fail closed), and a rogue non-vocabulary return value is + * normalized to `'unavailable'`. A failure that prevents either audit append + * from committing still rejects because returning an unlogged decision would + * violate the pair. Session contains post-commit observer failures, so an + * authoritative append cannot reject the request or suppress its matching + * audit event. + * @param req - the pending decision (agent, tool identity, reason, signal). + * @returns the closed outcome; `'allowed-once'` is the only grant. + * @throws when no turn is open or either audit event fails before the session + * append commit point. + */ + async request(req) { + const session = req.agent.session; + if (!hasOpenTurn(session.events)) throw new Error("approval.request() outside an open turn: the approval/asked + approval/decided audit pair must be turn-enclosed (a bare event between turns is crash-tail garbage on reload). Ask from inside the turn that needs the decision."); + const id = ApprovalRequestId(randomUUID()); + session.append("approval/asked", { + id, + toolName: req.toolName, + ...req.callId !== void 0 ? { callId: req.callId } : {}, + ...req.reason !== void 0 ? { reason: req.reason } : {} + }); + const outcome = await this.decide(req, session); + session.append("approval/decided", { + id, + outcome + }); + return outcome; + } + /** + * The session's effective policy: its own `approval/policy` fold, else the + * configured default (the schema already defaulted an omitted policy to + * `'ask'`; the `??` only narrows the optional-input TYPE). + * @param session - the exact accepted session whose policy applies. + * @returns the policy every ask for this session resolves under right now. + */ + effectivePolicy(session) { + return this.overrideOf(session) ?? this.config.policy ?? "ask"; + } + /** + * Read the session override without applying the configured default. + * @param session - session whose log supplies the override. + * @returns the last logged policy, or `undefined` without one. + */ + overrideOf(session) { + return effectiveApprovalPolicy(session.events); + } + /** + * Dispatch the waterfall, contained and raced against the request signal. + * @param req - the borrowed public request. + * @param session - the request agent's session used for policy lookup. + * @returns the normalized closed outcome. + */ + async decide(req, session) { + const signal = req.signal; + if (signal?.aborted) return "cancelled"; + if (this.effectivePolicy(session) === "never") return "rejected"; + const answer = Promise.resolve().then(() => this.ctx.waterfall(scopeTarget(this, req.agent), "approval/request", req, () => Promise.resolve("unavailable"))).then((outcome) => OUTCOMES.includes(outcome) ? outcome : "unavailable", () => "unavailable"); + if (signal === void 0) return answer; + return await new Promise((resolve) => { + const onAbort = () => { + signal.removeEventListener("abort", onAbort); + resolve("cancelled"); + }; + signal.addEventListener("abort", onAbort, { once: true }); + answer.then((outcome) => { + signal.removeEventListener("abort", onAbort); + resolve(outcome); + }); + }); + } +}); +//#endregion +//#region lib/types/invariant.js +/** Package-owned approval audit-stream invariants. @module @deepseek-ai/dsh-user-approval/invariant */ +const PACKAGE_NAME = "@deepseek-ai/dsh-user-approval"; +const APPROVAL_OUTCOMES = [ + "allowed-once", + "rejected", + "cancelled", + "unavailable" +]; +/** Cordis companion plugin name. */ +const name = "user-approval-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** Validate one approval event against committed unmatched questions. */ +function validateApprovalEvent(trace, event, fail) { + if (event.type === "approval/asked") { + if (trace.openTurn === null) fail("approval/asked appended outside any open turn"); + if (event.data.toolName.length === 0) fail("approval/asked toolName must be non-empty"); + if (trace.pending.has(event.data.id)) fail(`approval/asked repeated open id ${JSON.stringify(event.data.id)}`); + return { + kind: "asked", + id: event.data.id + }; + } + if (event.type === "approval/decided") { + if (trace.openTurn === null) fail("approval/decided appended outside any open turn"); + if (!trace.pending.has(event.data.id)) fail(`approval/decided has no matching approval/asked for id ${JSON.stringify(event.data.id)}`); + if (!APPROVAL_OUTCOMES.includes(event.data.outcome)) fail(`approval/decided carries unknown outcome ${JSON.stringify(event.data.outcome)}`); + return { + kind: "decided", + id: event.data.id + }; + } + if (event.type === "approval/policy" && !APPROVAL_POLICIES.includes(event.data.policy)) fail(`approval/policy carries unknown policy ${JSON.stringify(event.data.policy)}`); +} +/** Apply one accepted approval-pair transition. */ +function applyApprovalTransition(pending, transition) { + if (transition.kind === "asked") pending.add(transition.id); + else pending.delete(transition.id); +} +/** Install audit pairing and closed-vocabulary checks. */ +const install = Object.assign((ctx, fail) => { + const traces = /* @__PURE__ */ new WeakMap(); + const staged = /* @__PURE__ */ new WeakMap(); + const seed = (session) => { + const trace = { + openTurn: null, + pending: /* @__PURE__ */ new Set() + }; + traces.set(session, trace); + for (const event of session.events) { + if (event.type === "turn/start") trace.openTurn = event.data.turn; + else if (event.type === "turn/end") trace.openTurn = null; + const transition = validateApprovalEvent(trace, event, fail); + if (transition !== void 0) applyApprovalTransition(trace.pending, transition); + } + return trace; + }; + const traceFor = (session) => traces.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) seed(session); + ctx.on("session/created", (session) => { + seed(session); + }, { global: true }); + ctx.on("session/event", (session, event) => { + const trace = traceFor(session); + if (event.type === "turn/start") { + trace.openTurn = event.data.turn; + return; + } + if (event.type === "turn/end") { + trace.openTurn = null; + return; + } + if (event.type !== "approval/asked" && event.type !== "approval/decided") return; + const candidate = staged.get(event); + /* v8 ignore next -- internal/dispatch stages every package-owned pair event */ + if (candidate === void 0 || candidate.session !== session) return fail("approval audit event published without pre-commit validation"); + staged.delete(event); + applyApprovalTransition(trace.pending, candidate.transition); + }, { global: true }); + ctx.on("internal/dispatch", (_mode, eventName, args) => { + if (eventName !== "session/event") return; + const [session, event] = args; + const transition = validateApprovalEvent(traceFor(session), event, fail); + if (transition !== void 0) staged.set(event, { + session, + transition + }); + }, { global: true }); +}, { inject: ["sessions"] }); +/** +* Register the approval invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.d.ts new file mode 100644 index 0000000..f2849a0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.d.ts @@ -0,0 +1,195 @@ +/** + * Service Definition for the approval capability seam, covering requests, cancellation, audit, and per-session policy. Missing + * answerers fail closed; grants apply only to the requested action. + * @module @deepseek-ai/dsh-user-approval + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import { type CallId } from '@deepseek-ai/dsh-llm'; +import type { Scoped } from '@deepseek-ai/dsh-scope'; +import type { Session, SessionEvent } from '@deepseek-ai/dsh-session'; +declare module '@deepseek-ai/cordis' { + interface Context { + approval: ApprovalService; + } + interface Events { + /** + * Ask composed answerers for one decision. Return an outcome to claim the + * request or call `next()`; failure yields the fail-closed default. + * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent. + * @param req - the pending decision (agent, tool identity, reason, signal). + * @mode waterfall + */ + 'approval/request'(this: Scoped, req: ApprovalRequest, next: () => Promise): Promise; + } +} +declare module '@deepseek-ai/dsh-session/types' { + interface SessionEventMap { + /** + * An approval question was put to the answerer chain — log-only audit + * (like `hook/*`; NOT a surface event, carries no `surfaceOp`). `id` pairs + * it with the `approval/decided` that always follows; `toolName` is the + * tool the question is about, `callId` the exact tool call when the asker + * had one, `reason` the asker's human-readable explanation (e.g. a hook's + * permission-decision reason). + */ + 'approval/asked': { + id: ApprovalRequestId; + toolName: string; + callId?: CallId; + reason?: string; + }; + /** + * The outcome of a prior `approval/asked` (same `id`) — log-only audit. + * Exactly one per ask, appended when the outcome is known: a decision, a + * cancellation, or the fail-closed `'unavailable'`. + */ + 'approval/decided': { + id: ApprovalRequestId; + outcome: ApprovalOutcome; + }; + /** + * The session's approval policy was switched — log-only, durable, + * replayable, never in the model transcript (the model learns the policy + * from the runtime-context snapshot and live switch notices). The LAST + * such event is the session's override ({@link effectiveApprovalPolicy}). + * `source: 'delegation'` marks an override seeded into a child; an absent + * source is a runtime switch. + */ + 'approval/policy': { + policy: ApprovalPolicy; + /** Marks an override seeded into a child at delegation. */ + source?: 'delegation'; + }; + } +} +import { ApprovalRequestId } from './types.ts'; +import type { ApprovalOutcome } from './types.ts'; +export { ApprovalRequestId } from './types.ts'; +export type { ApprovalOutcome } from './types.ts'; +/** + * A session's approval policy — what happens to an {@link ApprovalService} + * ask BEFORE any interactive answerer sees it: + * + * - `'ask'` (the default) — delegate to the composed answerers; with none + * composed the chain falls through to the fail-closed `'unavailable'`. + * - `'never'` — never prompt anyone: every ask resolves `'rejected'` + * deterministically. The strict headless stance (CI, unattended runs) and + * the policy whose outcome is knowable without asking. + */ +export type ApprovalPolicy = 'ask' | 'never'; +/** Every {@link ApprovalPolicy}, for option advertisement and runtime validation of untrusted policy strings. */ +export declare const APPROVAL_POLICIES: readonly ApprovalPolicy[]; +/** + * The session's approval-policy override: the last `approval/policy` event in + * the log, or undefined when the session never switched (callers apply the + * plugin's configured default). The pure fold — resume needs no catch-up + * machinery because replaying the log IS the state. + * @param events - session events in log order (other event types are skipped). + * @returns the policy of the last switch event, or undefined without one. + */ +export declare function effectiveApprovalPolicy(events: readonly SessionEvent[]): ApprovalPolicy | undefined; +/** + * Append the sole durable representation of a session policy override. Invalid + * values throw before the log changes; consumers fold the new value on each read. + * @param session - the session the override belongs to. + * @param policy - the policy in effect until the next switch. + */ +export declare function setApprovalPolicy(session: Session, policy: ApprovalPolicy): void; +/** + * Readonly same-process permission question. `callId` links to an already + * presented tool call, so arguments are not duplicated here. + */ +export interface ApprovalRequest { + /** + * The agent on whose behalf the question is asked. Routes the question (a + * UI answerer only answers for agents it owns) and receives the audit + * events on its session log. + */ + readonly agent: Agent; + /** The tool the question is about (presentation and audit). */ + readonly toolName: string; + /** + * The exact tool call being decided, when the asker has one — lets a UI + * attach the prompt to the tool call it already streamed. + */ + readonly callId?: CallId; + /** The asker's human-readable explanation of WHY it is asking. */ + readonly reason?: string; + /** + * Aborting withdraws the question: the request settles `'cancelled'` + * immediately and a late answer from a still-pending answerer is discarded. + */ + readonly signal?: AbortSignal; +} +/** Plugin config. All optional — `static Config` supplies the defaults. */ +export interface Config { + /** + * The deployment's default {@link ApprovalPolicy} for sessions without an + * `approval/policy` override — `'ask'` delegates to the composed answerers + * (fail-closed with none); `'never'` auto-rejects every ask without + * prompting (the deterministic CI/unattended stance). + */ + readonly policy?: ApprovalPolicy; +} +/** + * Approval service that applies session policy before answerers and logs every + * ask/outcome pair to the requesting session. It exposes deterministic policy + * changes to the model through the runtime-context snapshot and switch notices. + */ +export declare class ApprovalService extends Service { + config: Config; + static Config: z; + constructor(ctx: Context, config: Config); + /** + * Switch one live agent's policy and queue the transition for its next model + * step. Session initialization uses {@link setApprovalPolicy} directly + * because there is no previously visible policy to change. + * @param agent - the live agent whose policy is changing. + * @param policy - the new effective policy. + */ + setPolicy(agent: Agent, policy: ApprovalPolicy): void; + /** + * Ask the composed answerers to decide one readonly same-process request. + * The service borrows the request, agent, session, and live signal directly. + * The request requires an open turn because the audit pair must be enclosed + * by the durable log's commit/replay boundary; an idle ask rejects before + * appending anything. The answerer phase always produces an outcome: an + * aborted signal yields `'cancelled'`, a missing or throwing answerer yields + * `'unavailable'` (fail closed), and a rogue non-vocabulary return value is + * normalized to `'unavailable'`. A failure that prevents either audit append + * from committing still rejects because returning an unlogged decision would + * violate the pair. Session contains post-commit observer failures, so an + * authoritative append cannot reject the request or suppress its matching + * audit event. + * @param req - the pending decision (agent, tool identity, reason, signal). + * @returns the closed outcome; `'allowed-once'` is the only grant. + * @throws when no turn is open or either audit event fails before the session + * append commit point. + */ + request(req: ApprovalRequest): Promise; + /** + * The session's effective policy: its own `approval/policy` fold, else the + * configured default (the schema already defaulted an omitted policy to + * `'ask'`; the `??` only narrows the optional-input TYPE). + * @param session - the exact accepted session whose policy applies. + * @returns the policy every ask for this session resolves under right now. + */ + private effectivePolicy; + /** + * Read the session override without applying the configured default. + * @param session - session whose log supplies the override. + * @returns the last logged policy, or `undefined` without one. + */ + overrideOf(session: Session): ApprovalPolicy | undefined; + /** + * Dispatch the waterfall, contained and raced against the request signal. + * @param req - the borrowed public request. + * @param session - the request agent's session used for policy lookup. + * @returns the normalized closed outcome. + */ + private decide; +} +export default ApprovalService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.js new file mode 100644 index 0000000..aa5a0cd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/index.js @@ -0,0 +1,217 @@ +/** + * Service Definition for the approval capability seam, covering requests, cancellation, audit, and per-session policy. Missing + * answerers fail closed; grants apply only to the requested action. + * @module @deepseek-ai/dsh-user-approval + */ +import { randomUUID } from 'node:crypto'; +import { Service } from '@deepseek-ai/cordis'; +import z from '@deepseek-ai/schemastery'; +import { createUserMessage } from '@deepseek-ai/dsh-llm'; +import { scopeTarget } from '@deepseek-ai/dsh-scope'; +import { ApprovalRequestId } from "./types.js"; +export { ApprovalRequestId } from "./types.js"; +/** Every {@link ApprovalOutcome}, for runtime normalization of answerer returns. */ +const OUTCOMES = ['allowed-once', 'rejected', 'cancelled', 'unavailable']; +/** Every {@link ApprovalPolicy}, for option advertisement and runtime validation of untrusted policy strings. */ +export const APPROVAL_POLICIES = ['ask', 'never']; +/** Model-facing statement for the deterministic `'never'` policy. */ +const NEVER_SENTENCE = 'Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).'; +/** Model-facing statement for an interactive policy that may still fail closed. */ +const ASK_SENTENCE = 'Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.'; +/** + * The session's approval-policy override: the last `approval/policy` event in + * the log, or undefined when the session never switched (callers apply the + * plugin's configured default). The pure fold — resume needs no catch-up + * machinery because replaying the log IS the state. + * @param events - session events in log order (other event types are skipped). + * @returns the policy of the last switch event, or undefined without one. + */ +export function effectiveApprovalPolicy(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const event = events[index]; + if (event.type === 'approval/policy') + return event.data.policy; + } + return undefined; +} +/** + * Whether the log currently sits inside an open turn (a `turn/start` not yet + * closed by a `turn/end`) — the {@link ApprovalService.request} precondition. + * The audit pair must be turn-enclosed: the turn is the durable log's + * commit/replay boundary, so a bare event appended between turns is + * indistinguishable from a crash tail and silently dropped on reload. + */ +function hasOpenTurn(events) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const type = events[index].type; + if (type === 'turn/start') + return true; + if (type === 'turn/end') + return false; + } + return false; +} +/** + * Append the sole durable representation of a session policy override. Invalid + * values throw before the log changes; consumers fold the new value on each read. + * @param session - the session the override belongs to. + * @param policy - the policy in effect until the next switch. + */ +export function setApprovalPolicy(session, policy) { + if (!APPROVAL_POLICIES.includes(policy)) { + throw new TypeError('approval policy must be one of "ask" or "never"'); + } + session.append('approval/policy', { policy }); +} +/** + * Approval service that applies session policy before answerers and logs every + * ask/outcome pair to the requesting session. It exposes deterministic policy + * changes to the model through the runtime-context snapshot and switch notices. + */ +export class ApprovalService extends Service { + config; + static Config = z.object({ + policy: z.union(['ask', 'never']).default('ask'), + }); + constructor(ctx, config) { + super(ctx, 'approval'); + this.config = config; + const effective = (agent) => this.effectivePolicy(agent.session); + // The complete current value travels after retained history, so switching + // policy does not rewrite the stable system-prompt cache prefix. + ctx.inject(['systemPrompt'], (scope) => { + scope.systemPrompt.context({ + name: 'approval:policy', + order: 115, + text: (context) => { + const agent = context.agent; + // A bare assemble() (tests, diagnostics) has no session to state. + if (agent === undefined) + return ''; + const policy = effective(agent); + return policy === 'never' ? NEVER_SENTENCE : ASK_SENTENCE; + }, + }); + }); + } + /** + * Switch one live agent's policy and queue the transition for its next model + * step. Session initialization uses {@link setApprovalPolicy} directly + * because there is no previously visible policy to change. + * @param agent - the live agent whose policy is changing. + * @param policy - the new effective policy. + */ + setPolicy(agent, policy) { + const previous = this.effectivePolicy(agent.session); + if (previous === policy) + return; + setApprovalPolicy(agent.session, policy); + agent.inject(createUserMessage({ + content: [{ + type: 'text', + text: `The approval policy changed from "${previous}" to "${policy}" (changed by the user).`, + }], + source: { kind: 'plugin', plugin: 'user-approval' }, + })); + } + /** + * Ask the composed answerers to decide one readonly same-process request. + * The service borrows the request, agent, session, and live signal directly. + * The request requires an open turn because the audit pair must be enclosed + * by the durable log's commit/replay boundary; an idle ask rejects before + * appending anything. The answerer phase always produces an outcome: an + * aborted signal yields `'cancelled'`, a missing or throwing answerer yields + * `'unavailable'` (fail closed), and a rogue non-vocabulary return value is + * normalized to `'unavailable'`. A failure that prevents either audit append + * from committing still rejects because returning an unlogged decision would + * violate the pair. Session contains post-commit observer failures, so an + * authoritative append cannot reject the request or suppress its matching + * audit event. + * @param req - the pending decision (agent, tool identity, reason, signal). + * @returns the closed outcome; `'allowed-once'` is the only grant. + * @throws when no turn is open or either audit event fails before the session + * append commit point. + */ + async request(req) { + const session = req.agent.session; + if (!hasOpenTurn(session.events)) { + throw new Error('approval.request() outside an open turn: the approval/asked + approval/decided audit pair ' + + 'must be turn-enclosed (a bare event between turns is crash-tail garbage on reload). ' + + 'Ask from inside the turn that needs the decision.'); + } + const id = ApprovalRequestId(randomUUID()); + session.append('approval/asked', { + id, + toolName: req.toolName, + ...req.callId !== undefined ? { callId: req.callId } : {}, + ...req.reason !== undefined ? { reason: req.reason } : {}, + }); + const outcome = await this.decide(req, session); + session.append('approval/decided', { id, outcome }); + return outcome; + } + /** + * The session's effective policy: its own `approval/policy` fold, else the + * configured default (the schema already defaulted an omitted policy to + * `'ask'`; the `??` only narrows the optional-input TYPE). + * @param session - the exact accepted session whose policy applies. + * @returns the policy every ask for this session resolves under right now. + */ + effectivePolicy(session) { + return this.overrideOf(session) ?? this.config.policy ?? 'ask'; + } + /** + * Read the session override without applying the configured default. + * @param session - session whose log supplies the override. + * @returns the last logged policy, or `undefined` without one. + */ + overrideOf(session) { + return effectiveApprovalPolicy(session.events); + } + /** + * Dispatch the waterfall, contained and raced against the request signal. + * @param req - the borrowed public request. + * @param session - the request agent's session used for policy lookup. + * @returns the normalized closed outcome. + */ + async decide(req, session) { + const signal = req.signal; + if (signal?.aborted) + return 'cancelled'; + // The 'never' policy is decided HERE, before any dispatch: a listener + // registered with `prepend: true` after this service mounts would sit + // ahead of any gate LISTENER, so a listener-shaped gate cannot keep the + // documented promise that 'never' rejects deterministically regardless + // of registration order — only the service's own request path can. + if (this.effectivePolicy(session) === 'never') + return 'rejected'; + // Enter the promise chain BEFORE dispatching: a listener that throws + // SYNCHRONOUSLY (before its first await) must land in the same rejection + // path as an async one — `Promise.resolve(call())` would let it escape + // the containment into the caller. + const answer = Promise.resolve().then(() => this.ctx.waterfall(scopeTarget(this, req.agent), 'approval/request', req, () => Promise.resolve('unavailable'))).then( + // Normalize a rogue (non-vocabulary) answerer return to the fail-closed + // outcome instead of leaking it into callers' closed-union switches. + outcome => OUTCOMES.includes(outcome) ? outcome : 'unavailable', + // A throwing answerer must fail the QUESTION closed, not the caller's + // tool call open — the seam contains its callbacks. + () => 'unavailable'); + if (signal === undefined) + return answer; + return await new Promise((resolve) => { + const onAbort = () => { + signal.removeEventListener('abort', onAbort); + resolve('cancelled'); + }; + signal.addEventListener('abort', onAbort, { once: true }); + void answer.then((outcome) => { + signal.removeEventListener('abort', onAbort); + // After an abort won the race this resolve is a settled-promise no-op: + // the late answer is discarded by construction. + resolve(outcome); + }); + }); + } +} +export default ApprovalService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.d.ts new file mode 100644 index 0000000..aff2f05 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.d.ts @@ -0,0 +1,13 @@ +/** Package-owned approval audit-stream invariants. @module @deepseek-ai/dsh-user-approval/invariant */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "user-approval-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register the approval invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.js new file mode 100644 index 0000000..b79a940 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/invariant.js @@ -0,0 +1,101 @@ +/** Package-owned approval audit-stream invariants. @module @deepseek-ai/dsh-user-approval/invariant */ +import { APPROVAL_POLICIES } from "./index.js"; +const PACKAGE_NAME = '@deepseek-ai/dsh-user-approval'; +const APPROVAL_OUTCOMES = ['allowed-once', 'rejected', 'cancelled', 'unavailable']; +/** Cordis companion plugin name. */ +export const name = 'user-approval-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** Validate one approval event against committed unmatched questions. */ +function validateApprovalEvent(trace, event, fail) { + if (event.type === 'approval/asked') { + if (trace.openTurn === null) + fail('approval/asked appended outside any open turn'); + if (event.data.toolName.length === 0) + fail('approval/asked toolName must be non-empty'); + if (trace.pending.has(event.data.id)) + fail(`approval/asked repeated open id ${JSON.stringify(event.data.id)}`); + return { kind: 'asked', id: event.data.id }; + } + if (event.type === 'approval/decided') { + if (trace.openTurn === null) + fail('approval/decided appended outside any open turn'); + if (!trace.pending.has(event.data.id)) + fail(`approval/decided has no matching approval/asked for id ${JSON.stringify(event.data.id)}`); + if (!APPROVAL_OUTCOMES.includes(event.data.outcome)) { + fail(`approval/decided carries unknown outcome ${JSON.stringify(event.data.outcome)}`); + } + return { kind: 'decided', id: event.data.id }; + } + if (event.type === 'approval/policy' && !APPROVAL_POLICIES.includes(event.data.policy)) { + fail(`approval/policy carries unknown policy ${JSON.stringify(event.data.policy)}`); + } + return undefined; +} +/** Apply one accepted approval-pair transition. */ +function applyApprovalTransition(pending, transition) { + if (transition.kind === 'asked') + pending.add(transition.id); + else + pending.delete(transition.id); +} +/** Install audit pairing and closed-vocabulary checks. */ +// Event owners keep precommit staging local so their vocabularies never move into a central helper. +/* jscpd:ignore-start */ +const install = Object.assign((ctx, fail) => { + const traces = new WeakMap(); + const staged = new WeakMap(); + const seed = (session) => { + const trace = { openTurn: null, pending: new Set() }; + traces.set(session, trace); + for (const event of session.events) { + if (event.type === 'turn/start') + trace.openTurn = event.data.turn; + else if (event.type === 'turn/end') + trace.openTurn = null; + const transition = validateApprovalEvent(trace, event, fail); + if (transition !== undefined) + applyApprovalTransition(trace.pending, transition); + } + return trace; + }; + const traceFor = (session) => traces.get(session) ?? seed(session); + for (const session of ctx.sessions.list()) + seed(session); + ctx.on('session/created', (session) => { seed(session); }, { global: true }); + ctx.on('session/event', (session, event) => { + const trace = traceFor(session); + if (event.type === 'turn/start') { + trace.openTurn = event.data.turn; + return; + } + if (event.type === 'turn/end') { + trace.openTurn = null; + return; + } + if (event.type !== 'approval/asked' && event.type !== 'approval/decided') + return; + const candidate = staged.get(event); + /* v8 ignore next -- internal/dispatch stages every package-owned pair event */ + if (candidate === undefined || candidate.session !== session) + return fail('approval audit event published without pre-commit validation'); + staged.delete(event); + applyApprovalTransition(trace.pending, candidate.transition); + }, { global: true }); + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') + return; + const [session, event] = args; + const transition = validateApprovalEvent(traceFor(session), event, fail); + if (transition !== undefined) + staged.set(event, { session, transition }); + }, { global: true }); +}, { inject: ['sessions'] }); +/* jscpd:ignore-end */ +/** + * Register the approval invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.d.ts new file mode 100644 index 0000000..734d11e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.d.ts @@ -0,0 +1,24 @@ +/** + * Wire-safe approval identifiers and outcome vocabulary, free of + * cordis/service imports so browser type chains (apiproxy api → client) can + * consume them without loading this package's Context augmentation. + * @module @deepseek-ai/dsh-user-approval/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +/** + * Pairs one `approval/asked` audit event with its `approval/decided`. + * Service-issued (one fresh id per {@link ApprovalService.request} call). + */ +export type ApprovalRequestId = Branded<'ApprovalRequestId'>; +/** + * Brand a string as an {@link ApprovalRequestId}. + * @param id - the raw id string to brand. + * @returns the same string carrying the brand. + */ +export declare function ApprovalRequestId(id: string): ApprovalRequestId; +/** + * Closed approval outcomes: a one-shot grant, explicit rejection, withdrawn + * request, or unavailable answerer. Callers fail closed on `unavailable`. + */ +export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable'; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.js new file mode 100644 index 0000000..08ed322 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/lib/types/types.js @@ -0,0 +1,15 @@ +/** + * Wire-safe approval identifiers and outcome vocabulary, free of + * cordis/service imports so browser type chains (apiproxy api → client) can + * consume them without loading this package's Context augmentation. + * @module @deepseek-ai/dsh-user-approval/types + */ +/** + * Brand a string as an {@link ApprovalRequestId}. + * @param id - the raw id string to brand. + * @returns the same string carrying the brand. + */ +export function ApprovalRequestId(id) { + return id; +} +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/package.json new file mode 100644 index 0000000..511deab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval/package.json @@ -0,0 +1,62 @@ +{ + "name": "@deepseek-ai/dsh-user-approval", + "description": "User-approval seam (ctx.approval) for the DeepSeek Harness: one-shot permission decisions dispatched to composed answerers over the approval/request waterfall, fail-closed by default", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/interaction/user-approval" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..8a90915 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..eea96f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.6_b0514d7a320728b6d8f5a31eb3960e10/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..c3e8c49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_4ed4e5c71eb965b0bd6912871e829940/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.i18n.yaml new file mode 100644 index 0000000..bdcbeee --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/interaction/user-questions/README.md +README.md: 53459c39c75d5d3907b002239c83db5f82e024f5 +README.zh.md: 3a1f016aef6efa0a2167523fd4e1a938fa53eb71 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.md new file mode 100644 index 0000000..53459c3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.md @@ -0,0 +1,46 @@ +# @deepseek-ai/dsh-user-questions + +English | [中文](README.zh.md) + +User-interaction Service Definition. It owns `ctx.userQuestions`, the service a model-facing tool or permission plugin uses when it needs to pause work and ask the human for a decision. + +## Service: `UserQuestionService` (ctx key: `userQuestions`) + +### Public API + +- `ctx.userQuestions.registerProvider(provider): () => void` Register the UI-side provider. Only one provider may be active in a context; disposal unregisters it. +- `ctx.userQuestions.ask(request): Promise` Ask the active provider and wait for the answer. + +### Key Types + +- `AskUserQuestionRequest` — `{ questions: [{ id, question, detail?, header?, options?, multiSelect?, intent? }], agent?, signal? }`; `detail` supplies supporting text that providers render with the question without turning it into an option label. When present, `agent` must be the registry's exact live runtime root. +- `AskUserQuestionOption` — `{ label, description? }`. +- `AskUserQuestionIntent` — `{ kind: 'plan-review', approve }`; the tagged presentation intent below. +- `AskUserQuestionAnswer` — `{ answers: [{ id, selected, custom? }] }`. +- `UserQuestionProvider` — UI implementation with `ask(request)`. +- `UserQuestionError` — `HarnessError` subclass with codes such as `EMPTY_QUESTIONS`, `BAD_INTENT`, `NO_PROVIDER`, `DUPLICATE_PROVIDER`, `ASK_ABORTED`, `CALLER_NOT_LIVE`, and `DELEGATED_CALLER`. + +For a single-select question, `custom` overrides the selected choice and `selected` is empty. For a multi-select question, `custom` may supplement the labels in `selected`. A UI may preserve a skipped item as `{ id, selected: [] }`, keeping the existing answer shape while retaining other answers in the batch. + +When a request carries an agent, `ask()` authenticates its exact identity through the live `AgentRegistry` and admits only a runtime root. Durable lineage is not authority: a session with historical delegation depth may ask after it is resumed as a new runtime root, while a live child owned by another agent is rejected even if its durable depth is zero. Agentless programmatic requests retain the existing provider path. + +### Presentation intent + +`intent` declares that a question IS a known kind of decision, so a UI that recognises the tag may present it as such — `plan-review` says `detail` is a plan under review, and `dsh-plan-mode` sets it on the `exit_plan_mode` question. An intent changes presentation only: a UI honouring it answers with the same option labels a generic UI would send, and a UI that does not know the tag renders the generic option list, so callers read the same answer fields either way. `approve` names the label that approves rather than relying on option order. `ask()` rejects with `BAD_INTENT` the two assertions no type can carry: an `approve` naming none of that question's own options, and an intent on a question with no `detail` — the thing it declares itself a review of. + +## Role + +This is the Service Definition package. Consumers such as `@deepseek-ai/dsh-tool-ask-user` depend on this service; the Web host runtime supplies the shipped Service Provider. The loop stays unchanged: a tool call awaits a promise, and the tool result resumes the normal agent loop. + +## Model Experience + +Indirectly, through `dsh-tool-ask-user`, which retains a successful provider answer as compact JSON or one of these failures: `Error: ask_user_question was aborted before the user answered`, `Error: ask_user_question requires at least one question`, `Error: human interaction requires the exact live calling agent when an agent is supplied`, `Error: human interaction is unavailable while the calling agent is owned by another live agent; include the unresolved question or decision in the child agent's final result`, `Error: no user-questions provider is registered`, or `Error: `. Waiting for the human adds no tokens. + +#### KV Cache effect + +No direct invalidation; the named consumer owns any request-prefix changes. + +## Known Limitations and Deferred Work + +- **One provider per context** — there is no routing or fan-out to multiple UIs; a second registration throws `DUPLICATE_PROVIDER`, and with none registered `ask()` throws `NO_PROVIDER` rather than degrading. +- **The vocabulary is the question-form shape only** — selectable options plus optional custom text; richer interaction shapes (file pickers, diff-preview confirmations) have no seam vocabulary yet. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.zh.md new file mode 100644 index 0000000..3a1f016 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/README.zh.md @@ -0,0 +1,46 @@ +# @deepseek-ai/dsh-user-questions + +[English](README.md) | 中文 + +用户交互 Service Definition。它定义 `ctx.userQuestions`,供面向模型的工具或权限插件在需要暂停工作并询问人类决定时使用。 + +## 服务:`UserQuestionService`(ctx 键:`userQuestions`) + +### 公开 API + +- `ctx.userQuestions.registerProvider(provider): () => void` 注册 UI 侧提供方。同一上下文中只能有一个活跃提供方;dispose(资源释放)会将其注销。 +- `ctx.userQuestions.ask(request): Promise` 向活跃提供方提问并等待回答。 + +### 关键类型 + +- `AskUserQuestionRequest`:`{ questions: [{ id, question, detail?, header?, options?, multiSelect?, intent? }], agent?, signal? }`;`detail` 提供辅助文本,提供方会将其随问题一起渲染,而不会将其变成选项标签。如提供 `agent`,它必须与注册表中的存活运行时根 agent(智能体)是同一对象。 +- `AskUserQuestionOption`:`{ label, description? }`。 +- `AskUserQuestionIntent`:`{ kind: 'plan-review', approve }`;即下文的带标签呈现意图。 +- `AskUserQuestionAnswer`:`{ answers: [{ id, selected, custom? }] }`。 +- `UserQuestionProvider`:包含 `ask(request)` 的 UI 实现。 +- `UserQuestionError`:`HarnessError` 的子类,包含 `EMPTY_QUESTIONS`、`BAD_INTENT`、`NO_PROVIDER`、`DUPLICATE_PROVIDER`、`ASK_ABORTED`、`CALLER_NOT_LIVE` 和 `DELEGATED_CALLER` 等代码。 + +对于单选题,`custom` 会覆盖选中的选项,且 `selected` 为空。对于多选题,`custom` 可以补充 `selected` 中的标签。UI 可以把跳过的条目保留为 `{ id, selected: [] }`,既维持现有回答形态,也保留该批次中的其他回答。 + +请求包含 agent 时,`ask()` 会通过当前 `AgentRegistry` 验证该 agent 与注册表中的存活实例是同一对象,并且只允许运行时根调用。持久谱系不构成权限依据:带有历史委托深度的会话恢复为新的运行时根后可以提问;归属于另一个 agent 的存活子级即使持久化记录的委托深度为零也会被拒绝。不含 agent 的程序化请求继续沿用现有提供方路径。 + +### 呈现意图 + +`intent` 声明某个问题本身就是一种已知决策,因此认识该标签的 UI 可以照此呈现——`plan-review` 表示 `detail` 是一份待审阅的计划,`dsh-plan-mode` 会在 `exit_plan_mode` 的问题上设置它。意图只改变呈现:遵循它的 UI 回答的仍是通用 UI 会发送的那些选项标签,不认识该标签的 UI 渲染通用选项列表,因此调用方两种情况下读到的回答字段相同。`approve` 指名表示批准的标签,而不依赖选项顺序。有两项断言无法通过类型表达,`ask()` 会以 `BAD_INTENT` 拒绝它们:`approve` 未命中该问题自身的任一选项,以及意图落在没有 `detail` 的问题上——而 `detail` 正是它自称在审阅的东西。 + +## 职责 + +这是 Service Definition 包。`@deepseek-ai/dsh-tool-ask-user` 等 Consumer 依赖此服务;Web 宿主运行时提供随产品交付的 Service Provider。循环保持不变:工具调用等待 Promise,工具结果随后恢复正常的 agent loop(智能体循环)。 + +## 模型体验 + +间接地,通过 `dsh-tool-ask-user`:它会将成功的提供方回答保留为紧凑 JSON,或返回以下失败之一:`Error: ask_user_question was aborted before the user answered`、`Error: ask_user_question requires at least one question`、`Error: human interaction requires the exact live calling agent when an agent is supplied`、`Error: human interaction is unavailable while the calling agent is owned by another live agent; include the unresolved question or decision in the child agent's final result`、`Error: no user-questions provider is registered` 或 `Error: `。等待人类回答不会增加 token。 + +#### KV Cache 影响 + +不会直接使 KV Cache 失效;请求前缀的任何变更均由上述消费方负责。 + +## 已知限制与暂缓事项 + +- **每个上下文只能有一个提供方**:不支持路由或扇出到多个 UI;第二次注册会抛出 `DUPLICATE_PROVIDER`,未注册任何提供方时,`ask()` 会抛出 `NO_PROVIDER`,而不会降级。 +- **词汇仅包含问题表单形态**:可供选择的选项加可选的自定义文本;更丰富的交互形态(文件选择器、diff 预览确认)尚无 seam 词汇。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/index.js new file mode 100644 index 0000000..2fe2165 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/index.js @@ -0,0 +1,76 @@ +import { Service } from "@deepseek-ai/cordis"; +import { HarnessError } from "@deepseek-ai/dsh-llm"; +//#region lib/types/index.js +/** +* Service Definition for the user-questions capability seam (`ctx.userQuestions`): a UI-backed service for +* pausing an agent tool call until the human answers a question. The model- +* facing tool lives in `@deepseek-ai/dsh-tool-ask-user`; UI packages provide +* the single active provider. +* +* @module @deepseek-ai/dsh-user-questions +*/ +/** Stable error taxonomy for user-questions failures. */ +var UserQuestionError = class extends HarnessError { + constructor(message, code, options) { + super(message, code, options); + this.name = "UserQuestionError"; + } +}; +/** `ctx.userQuestions`: one active UI provider plus an `ask()` API. */ +var UserQuestionService = class extends Service { + provider; + constructor(ctx) { + super(ctx, "userQuestions"); + } + /** + * Register the UI provider. Only one provider may be active in a context. + * + * @param provider UI-side implementation that collects answers. + * @returns Disposer that unregisters this provider. + */ + registerProvider(provider) { + const dispose = this.ctx.effect(function* () { + if (this.provider !== void 0) throw new UserQuestionError("a user-questions provider is already registered", "DUPLICATE_PROVIDER"); + this.provider = provider; + yield () => { + this.provider = void 0; + }; + }.bind(this), "userInteraction.registerProvider()"); + return () => void dispose(); + } + /** + * Ask the active UI provider and wait for the user's answer. + * + * When a caller supplies an agent, human interaction is valid only for the + * exact live runtime root. Runtime ownership, not durable session lineage, + * decides this boundary: an owned child has no human answerer and would + * block forever, while a lineage-bearing session resumed as a new runtime + * root may ask normally. + * + * @param request Questions, owner agent, and abort signal. + * @returns The answer chosen or typed by the human. + * @throws {UserQuestionError} code `CALLER_NOT_LIVE` when a supplied + * agent is not the registry's exact live instance, or `DELEGATED_CALLER` + * when that live agent is owned by another agent. + */ + async ask(request) { + if (request.signal?.aborted) throw new UserQuestionError("ask_user_question was aborted before the user answered", "ASK_ABORTED"); + if (request.questions.length === 0) throw new UserQuestionError("ask_user_question requires at least one question", "EMPTY_QUESTIONS"); + const agent = request.agent; + if (agent !== void 0) { + const agents = this.ctx.get("agents"); + if (agents === void 0 || agents.get(agent.id) !== agent) throw new UserQuestionError("human interaction requires the exact live calling agent when an agent is supplied", "CALLER_NOT_LIVE"); + if (!agents.roots().includes(agent)) throw new UserQuestionError("human interaction is unavailable while the calling agent is owned by another live agent; include the unresolved question or decision in the child agent's final result", "DELEGATED_CALLER"); + } + for (const question of request.questions) { + const intent = question.intent; + if (intent === void 0) continue; + if (!(question.options ?? []).some((option) => option.label === intent.approve)) throw new UserQuestionError(`question ${question.id} declares intent ${intent.kind} whose approve label ${JSON.stringify(intent.approve)} names none of its options`, "BAD_INTENT"); + if (question.detail === void 0) throw new UserQuestionError(`question ${question.id} declares intent ${intent.kind} without the detail it reviews`, "BAD_INTENT"); + } + if (this.provider === void 0) throw new UserQuestionError("no user-questions provider is registered", "NO_PROVIDER"); + return this.provider.ask(request); + } +}; +//#endregion +export { UserQuestionError, UserQuestionService, UserQuestionService as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/invariant.js new file mode 100644 index 0000000..1633e55 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-user-questions`. +* @module @deepseek-ai/dsh-user-questions/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-user-questions"; +/** Cordis companion plugin name. */ +const name = "user-questions-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the single provider slot is validated at registration and asks return +* directly to their caller; the seam publishes no independent request/answer audit stream. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.d.ts new file mode 100644 index 0000000..efeb18c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.d.ts @@ -0,0 +1,65 @@ +/** + * Service Definition for the user-questions capability seam (`ctx.userQuestions`): a UI-backed service for + * pausing an agent tool call until the human answers a question. The model- + * facing tool lives in `@deepseek-ai/dsh-tool-ask-user`; UI packages provide + * the single active provider. + * + * @module @deepseek-ai/dsh-user-questions + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import { HarnessError } from '@deepseek-ai/dsh-llm'; +declare module '@deepseek-ai/cordis' { + interface Context { + userQuestions: UserQuestionService; + } +} +import type { AskUserQuestionAnswer, AskUserQuestionItem } from './types.ts'; +export type { AskUserQuestionAnswer, AskUserQuestionAnswerItem, AskUserQuestionIntent, AskUserQuestionItem, AskUserQuestionOption, } from './types.ts'; +/** Request for a human answer. */ +export interface AskUserQuestionRequest { + /** Questions to display. */ + questions: AskUserQuestionItem[]; + /** Exact live calling agent, when the request came from an agent tool call. */ + agent?: Agent; + /** Abort signal for the owning tool/step. */ + signal?: AbortSignal; +} +/** UI-side provider for user questions. */ +export interface UserQuestionProvider { + ask(request: AskUserQuestionRequest): Promise; +} +/** Stable error taxonomy for user-questions failures. */ +export declare class UserQuestionError extends HarnessError { + constructor(message: string, code: string, options?: ErrorOptions); +} +/** `ctx.userQuestions`: one active UI provider plus an `ask()` API. */ +export declare class UserQuestionService extends Service { + private provider; + constructor(ctx: Context); + /** + * Register the UI provider. Only one provider may be active in a context. + * + * @param provider UI-side implementation that collects answers. + * @returns Disposer that unregisters this provider. + */ + registerProvider(provider: UserQuestionProvider): () => void; + /** + * Ask the active UI provider and wait for the user's answer. + * + * When a caller supplies an agent, human interaction is valid only for the + * exact live runtime root. Runtime ownership, not durable session lineage, + * decides this boundary: an owned child has no human answerer and would + * block forever, while a lineage-bearing session resumed as a new runtime + * root may ask normally. + * + * @param request Questions, owner agent, and abort signal. + * @returns The answer chosen or typed by the human. + * @throws {UserQuestionError} code `CALLER_NOT_LIVE` when a supplied + * agent is not the registry's exact live instance, or `DELEGATED_CALLER` + * when that live agent is owned by another agent. + */ + ask(request: AskUserQuestionRequest): Promise; +} +export default UserQuestionService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.js new file mode 100644 index 0000000..aa9effd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.js @@ -0,0 +1,101 @@ +/** + * Service Definition for the user-questions capability seam (`ctx.userQuestions`): a UI-backed service for + * pausing an agent tool call until the human answers a question. The model- + * facing tool lives in `@deepseek-ai/dsh-tool-ask-user`; UI packages provide + * the single active provider. + * + * @module @deepseek-ai/dsh-user-questions + */ +import { Service } from '@deepseek-ai/cordis'; +import { HarnessError } from '@deepseek-ai/dsh-llm'; +/** Stable error taxonomy for user-questions failures. */ +export class UserQuestionError extends HarnessError { + constructor(message, code, options) { + super(message, code, options); + this.name = 'UserQuestionError'; + } +} +/** `ctx.userQuestions`: one active UI provider plus an `ask()` API. */ +export class UserQuestionService extends Service { + provider; + constructor(ctx) { + super(ctx, 'userQuestions'); + } + /** + * Register the UI provider. Only one provider may be active in a context. + * + * @param provider UI-side implementation that collects answers. + * @returns Disposer that unregisters this provider. + */ + registerProvider(provider) { + const dispose = this.ctx.effect(function* () { + if (this.provider !== undefined) { + throw new UserQuestionError('a user-questions provider is already registered', 'DUPLICATE_PROVIDER'); + } + this.provider = provider; + yield () => { + this.provider = undefined; + }; + }.bind(this), 'userInteraction.registerProvider()'); + return () => void dispose(); + } + /** + * Ask the active UI provider and wait for the user's answer. + * + * When a caller supplies an agent, human interaction is valid only for the + * exact live runtime root. Runtime ownership, not durable session lineage, + * decides this boundary: an owned child has no human answerer and would + * block forever, while a lineage-bearing session resumed as a new runtime + * root may ask normally. + * + * @param request Questions, owner agent, and abort signal. + * @returns The answer chosen or typed by the human. + * @throws {UserQuestionError} code `CALLER_NOT_LIVE` when a supplied + * agent is not the registry's exact live instance, or `DELEGATED_CALLER` + * when that live agent is owned by another agent. + */ + async ask(request) { + if (request.signal?.aborted) { + throw new UserQuestionError('ask_user_question was aborted before the user answered', 'ASK_ABORTED'); + } + if (request.questions.length === 0) { + throw new UserQuestionError('ask_user_question requires at least one question', 'EMPTY_QUESTIONS'); + } + const agent = request.agent; + if (agent !== undefined) { + const agents = this.ctx.get('agents'); + if (agents === undefined || agents.get(agent.id) !== agent) { + throw new UserQuestionError('human interaction requires the exact live calling agent when an agent is supplied', 'CALLER_NOT_LIVE'); + } + if (!agents.roots().includes(agent)) { + throw new UserQuestionError('human interaction is unavailable while the calling agent is owned by another live agent; ' + + "include the unresolved question or decision in the child agent's final result", 'DELEGATED_CALLER'); + } + } + // A presentation intent asserts two things the types cannot: that the + // named approve label is one of this question's own options, and that a + // plan-review carries the plan it is a review of. A UI honouring the + // intent answers with that label, and shows that detail as the plan, so + // either gap would put a choice the asker never offered — or an approval of + // something invisible — in front of the user. Caught at the asker, where + // the mistake is, rather than in each UI. + for (const question of request.questions) { + const intent = question.intent; + if (intent === undefined) + continue; + if (!(question.options ?? []).some(option => option.label === intent.approve)) { + throw new UserQuestionError(`question ${question.id} declares intent ${intent.kind} whose approve label ` + + `${JSON.stringify(intent.approve)} names none of its options`, 'BAD_INTENT'); + } + if (question.detail === undefined) { + throw new UserQuestionError(`question ${question.id} declares intent ${intent.kind} without the detail it reviews`, 'BAD_INTENT'); + } + } + if (this.provider === undefined) { + throw new UserQuestionError('no user-questions provider is registered', 'NO_PROVIDER'); + } + return this.provider.ask(request); + } +} +export default UserQuestionService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.d.ts new file mode 100644 index 0000000..d7f64c6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-user-questions`. + * @module @deepseek-ai/dsh-user-questions/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "user-questions-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.js new file mode 100644 index 0000000..b06edb6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.js @@ -0,0 +1,22 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-user-questions`. + * @module @deepseek-ai/dsh-user-questions/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-user-questions'; +/** Cordis companion plugin name. */ +export const name = 'user-questions-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: the single provider slot is validated at registration and asks return + * directly to their caller; the seam publishes no independent request/answer audit stream. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.d.ts new file mode 100644 index 0000000..2887da5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.d.ts @@ -0,0 +1,62 @@ +/** + * Wire-safe question and answer types, free of cordis/service imports so browser + * type chains (apiproxy api → client) can consume them without loading this + * package's Context augmentation. + * @module @deepseek-ai/dsh-user-questions/types + */ +/** One selectable answer offered to the user. */ +export interface AskUserQuestionOption { + /** User-facing label. */ + label: string; + /** Optional extra context rendered by capable UIs. */ + description?: string; +} +/** + * A caller-declared presentation intent: the question IS this kind of + * decision, so a UI that recognises the tag may present it as such instead of as a + * generic option list. Tagged so further intents can be added; a UI that does + * not know a tag renders the generic flow, and the answer encoding is identical + * either way — an intent changes presentation only, never the protocol. + */ +export type AskUserQuestionIntent = { + /** A plan submitted for review: `detail` is the plan markdown `ask()` requires, and the decision approves or declines it. */ + kind: 'plan-review'; + /** + * The option label that approves the plan; every other option declines it. + * Named rather than positional so no UI infers the verdict from option order. + * An `approve` naming no option of its own question is rejected at `ask()`. + */ + approve: string; +}; +/** One question in a user-questions request. */ +export interface AskUserQuestionItem { + /** Stable caller-provided question id, echoed in the answer. */ + id: string; + /** The question to display. */ + question: string; + /** Optional supporting detail rendered with the question but kept out of option labels. */ + detail?: string; + /** Optional short heading/group label. */ + header?: string; + /** Optional choices the UI can render as a menu. */ + options?: AskUserQuestionOption[]; + /** Whether more than one option may be selected. Defaults to single-select. */ + multiSelect?: boolean; + /** Optional presentation intent for capable UIs; absent asks for the generic option list. */ + intent?: AskUserQuestionIntent; +} +/** Answer to one question. */ +export interface AskUserQuestionAnswerItem { + /** The answered question id. */ + id: string; + /** Selected option labels. May accompany custom text for a multi-select question. */ + selected: string[]; + /** Optional free-text "Other" answer. */ + custom?: string; +} +/** The human's answer. */ +export interface AskUserQuestionAnswer { + /** Structured answers keyed by question id. */ + answers: AskUserQuestionAnswerItem[]; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.js new file mode 100644 index 0000000..653a00a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.js @@ -0,0 +1,8 @@ +/** + * Wire-safe question and answer types, free of cordis/service imports so browser + * type chains (apiproxy api → client) can consume them without loading this + * package's Context augmentation. + * @module @deepseek-ai/dsh-user-questions/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/package.json new file mode 100644 index 0000000..f899f49 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_a3039a5be3cb503b5a072f54d8d7db3e/node_modules/@deepseek-ai/dsh-user-questions/package.json @@ -0,0 +1,51 @@ +{ + "name": "@deepseek-ai/dsh-user-questions", + "description": "Abstract user-questions seam (ctx.userQuestions) for asking the human during agent runs", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/interaction/user-questions" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.6", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..8c634a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..864c5b6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.i18n.yaml new file mode 100644 index 0000000..bdcbeee --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/interaction/user-questions/README.md +README.md: 53459c39c75d5d3907b002239c83db5f82e024f5 +README.zh.md: 3a1f016aef6efa0a2167523fd4e1a938fa53eb71 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.md new file mode 100644 index 0000000..53459c3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.md @@ -0,0 +1,46 @@ +# @deepseek-ai/dsh-user-questions + +English | [中文](README.zh.md) + +User-interaction Service Definition. It owns `ctx.userQuestions`, the service a model-facing tool or permission plugin uses when it needs to pause work and ask the human for a decision. + +## Service: `UserQuestionService` (ctx key: `userQuestions`) + +### Public API + +- `ctx.userQuestions.registerProvider(provider): () => void` Register the UI-side provider. Only one provider may be active in a context; disposal unregisters it. +- `ctx.userQuestions.ask(request): Promise` Ask the active provider and wait for the answer. + +### Key Types + +- `AskUserQuestionRequest` — `{ questions: [{ id, question, detail?, header?, options?, multiSelect?, intent? }], agent?, signal? }`; `detail` supplies supporting text that providers render with the question without turning it into an option label. When present, `agent` must be the registry's exact live runtime root. +- `AskUserQuestionOption` — `{ label, description? }`. +- `AskUserQuestionIntent` — `{ kind: 'plan-review', approve }`; the tagged presentation intent below. +- `AskUserQuestionAnswer` — `{ answers: [{ id, selected, custom? }] }`. +- `UserQuestionProvider` — UI implementation with `ask(request)`. +- `UserQuestionError` — `HarnessError` subclass with codes such as `EMPTY_QUESTIONS`, `BAD_INTENT`, `NO_PROVIDER`, `DUPLICATE_PROVIDER`, `ASK_ABORTED`, `CALLER_NOT_LIVE`, and `DELEGATED_CALLER`. + +For a single-select question, `custom` overrides the selected choice and `selected` is empty. For a multi-select question, `custom` may supplement the labels in `selected`. A UI may preserve a skipped item as `{ id, selected: [] }`, keeping the existing answer shape while retaining other answers in the batch. + +When a request carries an agent, `ask()` authenticates its exact identity through the live `AgentRegistry` and admits only a runtime root. Durable lineage is not authority: a session with historical delegation depth may ask after it is resumed as a new runtime root, while a live child owned by another agent is rejected even if its durable depth is zero. Agentless programmatic requests retain the existing provider path. + +### Presentation intent + +`intent` declares that a question IS a known kind of decision, so a UI that recognises the tag may present it as such — `plan-review` says `detail` is a plan under review, and `dsh-plan-mode` sets it on the `exit_plan_mode` question. An intent changes presentation only: a UI honouring it answers with the same option labels a generic UI would send, and a UI that does not know the tag renders the generic option list, so callers read the same answer fields either way. `approve` names the label that approves rather than relying on option order. `ask()` rejects with `BAD_INTENT` the two assertions no type can carry: an `approve` naming none of that question's own options, and an intent on a question with no `detail` — the thing it declares itself a review of. + +## Role + +This is the Service Definition package. Consumers such as `@deepseek-ai/dsh-tool-ask-user` depend on this service; the Web host runtime supplies the shipped Service Provider. The loop stays unchanged: a tool call awaits a promise, and the tool result resumes the normal agent loop. + +## Model Experience + +Indirectly, through `dsh-tool-ask-user`, which retains a successful provider answer as compact JSON or one of these failures: `Error: ask_user_question was aborted before the user answered`, `Error: ask_user_question requires at least one question`, `Error: human interaction requires the exact live calling agent when an agent is supplied`, `Error: human interaction is unavailable while the calling agent is owned by another live agent; include the unresolved question or decision in the child agent's final result`, `Error: no user-questions provider is registered`, or `Error: `. Waiting for the human adds no tokens. + +#### KV Cache effect + +No direct invalidation; the named consumer owns any request-prefix changes. + +## Known Limitations and Deferred Work + +- **One provider per context** — there is no routing or fan-out to multiple UIs; a second registration throws `DUPLICATE_PROVIDER`, and with none registered `ask()` throws `NO_PROVIDER` rather than degrading. +- **The vocabulary is the question-form shape only** — selectable options plus optional custom text; richer interaction shapes (file pickers, diff-preview confirmations) have no seam vocabulary yet. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.zh.md new file mode 100644 index 0000000..3a1f016 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/README.zh.md @@ -0,0 +1,46 @@ +# @deepseek-ai/dsh-user-questions + +[English](README.md) | 中文 + +用户交互 Service Definition。它定义 `ctx.userQuestions`,供面向模型的工具或权限插件在需要暂停工作并询问人类决定时使用。 + +## 服务:`UserQuestionService`(ctx 键:`userQuestions`) + +### 公开 API + +- `ctx.userQuestions.registerProvider(provider): () => void` 注册 UI 侧提供方。同一上下文中只能有一个活跃提供方;dispose(资源释放)会将其注销。 +- `ctx.userQuestions.ask(request): Promise` 向活跃提供方提问并等待回答。 + +### 关键类型 + +- `AskUserQuestionRequest`:`{ questions: [{ id, question, detail?, header?, options?, multiSelect?, intent? }], agent?, signal? }`;`detail` 提供辅助文本,提供方会将其随问题一起渲染,而不会将其变成选项标签。如提供 `agent`,它必须与注册表中的存活运行时根 agent(智能体)是同一对象。 +- `AskUserQuestionOption`:`{ label, description? }`。 +- `AskUserQuestionIntent`:`{ kind: 'plan-review', approve }`;即下文的带标签呈现意图。 +- `AskUserQuestionAnswer`:`{ answers: [{ id, selected, custom? }] }`。 +- `UserQuestionProvider`:包含 `ask(request)` 的 UI 实现。 +- `UserQuestionError`:`HarnessError` 的子类,包含 `EMPTY_QUESTIONS`、`BAD_INTENT`、`NO_PROVIDER`、`DUPLICATE_PROVIDER`、`ASK_ABORTED`、`CALLER_NOT_LIVE` 和 `DELEGATED_CALLER` 等代码。 + +对于单选题,`custom` 会覆盖选中的选项,且 `selected` 为空。对于多选题,`custom` 可以补充 `selected` 中的标签。UI 可以把跳过的条目保留为 `{ id, selected: [] }`,既维持现有回答形态,也保留该批次中的其他回答。 + +请求包含 agent 时,`ask()` 会通过当前 `AgentRegistry` 验证该 agent 与注册表中的存活实例是同一对象,并且只允许运行时根调用。持久谱系不构成权限依据:带有历史委托深度的会话恢复为新的运行时根后可以提问;归属于另一个 agent 的存活子级即使持久化记录的委托深度为零也会被拒绝。不含 agent 的程序化请求继续沿用现有提供方路径。 + +### 呈现意图 + +`intent` 声明某个问题本身就是一种已知决策,因此认识该标签的 UI 可以照此呈现——`plan-review` 表示 `detail` 是一份待审阅的计划,`dsh-plan-mode` 会在 `exit_plan_mode` 的问题上设置它。意图只改变呈现:遵循它的 UI 回答的仍是通用 UI 会发送的那些选项标签,不认识该标签的 UI 渲染通用选项列表,因此调用方两种情况下读到的回答字段相同。`approve` 指名表示批准的标签,而不依赖选项顺序。有两项断言无法通过类型表达,`ask()` 会以 `BAD_INTENT` 拒绝它们:`approve` 未命中该问题自身的任一选项,以及意图落在没有 `detail` 的问题上——而 `detail` 正是它自称在审阅的东西。 + +## 职责 + +这是 Service Definition 包。`@deepseek-ai/dsh-tool-ask-user` 等 Consumer 依赖此服务;Web 宿主运行时提供随产品交付的 Service Provider。循环保持不变:工具调用等待 Promise,工具结果随后恢复正常的 agent loop(智能体循环)。 + +## 模型体验 + +间接地,通过 `dsh-tool-ask-user`:它会将成功的提供方回答保留为紧凑 JSON,或返回以下失败之一:`Error: ask_user_question was aborted before the user answered`、`Error: ask_user_question requires at least one question`、`Error: human interaction requires the exact live calling agent when an agent is supplied`、`Error: human interaction is unavailable while the calling agent is owned by another live agent; include the unresolved question or decision in the child agent's final result`、`Error: no user-questions provider is registered` 或 `Error: `。等待人类回答不会增加 token。 + +#### KV Cache 影响 + +不会直接使 KV Cache 失效;请求前缀的任何变更均由上述消费方负责。 + +## 已知限制与暂缓事项 + +- **每个上下文只能有一个提供方**:不支持路由或扇出到多个 UI;第二次注册会抛出 `DUPLICATE_PROVIDER`,未注册任何提供方时,`ask()` 会抛出 `NO_PROVIDER`,而不会降级。 +- **词汇仅包含问题表单形态**:可供选择的选项加可选的自定义文本;更丰富的交互形态(文件选择器、diff 预览确认)尚无 seam 词汇。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/index.js new file mode 100644 index 0000000..2fe2165 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/index.js @@ -0,0 +1,76 @@ +import { Service } from "@deepseek-ai/cordis"; +import { HarnessError } from "@deepseek-ai/dsh-llm"; +//#region lib/types/index.js +/** +* Service Definition for the user-questions capability seam (`ctx.userQuestions`): a UI-backed service for +* pausing an agent tool call until the human answers a question. The model- +* facing tool lives in `@deepseek-ai/dsh-tool-ask-user`; UI packages provide +* the single active provider. +* +* @module @deepseek-ai/dsh-user-questions +*/ +/** Stable error taxonomy for user-questions failures. */ +var UserQuestionError = class extends HarnessError { + constructor(message, code, options) { + super(message, code, options); + this.name = "UserQuestionError"; + } +}; +/** `ctx.userQuestions`: one active UI provider plus an `ask()` API. */ +var UserQuestionService = class extends Service { + provider; + constructor(ctx) { + super(ctx, "userQuestions"); + } + /** + * Register the UI provider. Only one provider may be active in a context. + * + * @param provider UI-side implementation that collects answers. + * @returns Disposer that unregisters this provider. + */ + registerProvider(provider) { + const dispose = this.ctx.effect(function* () { + if (this.provider !== void 0) throw new UserQuestionError("a user-questions provider is already registered", "DUPLICATE_PROVIDER"); + this.provider = provider; + yield () => { + this.provider = void 0; + }; + }.bind(this), "userInteraction.registerProvider()"); + return () => void dispose(); + } + /** + * Ask the active UI provider and wait for the user's answer. + * + * When a caller supplies an agent, human interaction is valid only for the + * exact live runtime root. Runtime ownership, not durable session lineage, + * decides this boundary: an owned child has no human answerer and would + * block forever, while a lineage-bearing session resumed as a new runtime + * root may ask normally. + * + * @param request Questions, owner agent, and abort signal. + * @returns The answer chosen or typed by the human. + * @throws {UserQuestionError} code `CALLER_NOT_LIVE` when a supplied + * agent is not the registry's exact live instance, or `DELEGATED_CALLER` + * when that live agent is owned by another agent. + */ + async ask(request) { + if (request.signal?.aborted) throw new UserQuestionError("ask_user_question was aborted before the user answered", "ASK_ABORTED"); + if (request.questions.length === 0) throw new UserQuestionError("ask_user_question requires at least one question", "EMPTY_QUESTIONS"); + const agent = request.agent; + if (agent !== void 0) { + const agents = this.ctx.get("agents"); + if (agents === void 0 || agents.get(agent.id) !== agent) throw new UserQuestionError("human interaction requires the exact live calling agent when an agent is supplied", "CALLER_NOT_LIVE"); + if (!agents.roots().includes(agent)) throw new UserQuestionError("human interaction is unavailable while the calling agent is owned by another live agent; include the unresolved question or decision in the child agent's final result", "DELEGATED_CALLER"); + } + for (const question of request.questions) { + const intent = question.intent; + if (intent === void 0) continue; + if (!(question.options ?? []).some((option) => option.label === intent.approve)) throw new UserQuestionError(`question ${question.id} declares intent ${intent.kind} whose approve label ${JSON.stringify(intent.approve)} names none of its options`, "BAD_INTENT"); + if (question.detail === void 0) throw new UserQuestionError(`question ${question.id} declares intent ${intent.kind} without the detail it reviews`, "BAD_INTENT"); + } + if (this.provider === void 0) throw new UserQuestionError("no user-questions provider is registered", "NO_PROVIDER"); + return this.provider.ask(request); + } +}; +//#endregion +export { UserQuestionError, UserQuestionService, UserQuestionService as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/invariant.js new file mode 100644 index 0000000..1633e55 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/invariant.js @@ -0,0 +1,23 @@ +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-user-questions`. +* @module @deepseek-ai/dsh-user-questions/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-user-questions"; +/** Cordis companion plugin name. */ +const name = "user-questions-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* No runtime invariant: the single provider slot is validated at registration and asks return +* directly to their caller; the seam publishes no independent request/answer audit stream. +*/ +const install = () => {}; +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.d.ts new file mode 100644 index 0000000..efeb18c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.d.ts @@ -0,0 +1,65 @@ +/** + * Service Definition for the user-questions capability seam (`ctx.userQuestions`): a UI-backed service for + * pausing an agent tool call until the human answers a question. The model- + * facing tool lives in `@deepseek-ai/dsh-tool-ask-user`; UI packages provide + * the single active provider. + * + * @module @deepseek-ai/dsh-user-questions + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { Agent } from '@deepseek-ai/dsh-agent'; +import { HarnessError } from '@deepseek-ai/dsh-llm'; +declare module '@deepseek-ai/cordis' { + interface Context { + userQuestions: UserQuestionService; + } +} +import type { AskUserQuestionAnswer, AskUserQuestionItem } from './types.ts'; +export type { AskUserQuestionAnswer, AskUserQuestionAnswerItem, AskUserQuestionIntent, AskUserQuestionItem, AskUserQuestionOption, } from './types.ts'; +/** Request for a human answer. */ +export interface AskUserQuestionRequest { + /** Questions to display. */ + questions: AskUserQuestionItem[]; + /** Exact live calling agent, when the request came from an agent tool call. */ + agent?: Agent; + /** Abort signal for the owning tool/step. */ + signal?: AbortSignal; +} +/** UI-side provider for user questions. */ +export interface UserQuestionProvider { + ask(request: AskUserQuestionRequest): Promise; +} +/** Stable error taxonomy for user-questions failures. */ +export declare class UserQuestionError extends HarnessError { + constructor(message: string, code: string, options?: ErrorOptions); +} +/** `ctx.userQuestions`: one active UI provider plus an `ask()` API. */ +export declare class UserQuestionService extends Service { + private provider; + constructor(ctx: Context); + /** + * Register the UI provider. Only one provider may be active in a context. + * + * @param provider UI-side implementation that collects answers. + * @returns Disposer that unregisters this provider. + */ + registerProvider(provider: UserQuestionProvider): () => void; + /** + * Ask the active UI provider and wait for the user's answer. + * + * When a caller supplies an agent, human interaction is valid only for the + * exact live runtime root. Runtime ownership, not durable session lineage, + * decides this boundary: an owned child has no human answerer and would + * block forever, while a lineage-bearing session resumed as a new runtime + * root may ask normally. + * + * @param request Questions, owner agent, and abort signal. + * @returns The answer chosen or typed by the human. + * @throws {UserQuestionError} code `CALLER_NOT_LIVE` when a supplied + * agent is not the registry's exact live instance, or `DELEGATED_CALLER` + * when that live agent is owned by another agent. + */ + ask(request: AskUserQuestionRequest): Promise; +} +export default UserQuestionService; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.js new file mode 100644 index 0000000..aa9effd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/index.js @@ -0,0 +1,101 @@ +/** + * Service Definition for the user-questions capability seam (`ctx.userQuestions`): a UI-backed service for + * pausing an agent tool call until the human answers a question. The model- + * facing tool lives in `@deepseek-ai/dsh-tool-ask-user`; UI packages provide + * the single active provider. + * + * @module @deepseek-ai/dsh-user-questions + */ +import { Service } from '@deepseek-ai/cordis'; +import { HarnessError } from '@deepseek-ai/dsh-llm'; +/** Stable error taxonomy for user-questions failures. */ +export class UserQuestionError extends HarnessError { + constructor(message, code, options) { + super(message, code, options); + this.name = 'UserQuestionError'; + } +} +/** `ctx.userQuestions`: one active UI provider plus an `ask()` API. */ +export class UserQuestionService extends Service { + provider; + constructor(ctx) { + super(ctx, 'userQuestions'); + } + /** + * Register the UI provider. Only one provider may be active in a context. + * + * @param provider UI-side implementation that collects answers. + * @returns Disposer that unregisters this provider. + */ + registerProvider(provider) { + const dispose = this.ctx.effect(function* () { + if (this.provider !== undefined) { + throw new UserQuestionError('a user-questions provider is already registered', 'DUPLICATE_PROVIDER'); + } + this.provider = provider; + yield () => { + this.provider = undefined; + }; + }.bind(this), 'userInteraction.registerProvider()'); + return () => void dispose(); + } + /** + * Ask the active UI provider and wait for the user's answer. + * + * When a caller supplies an agent, human interaction is valid only for the + * exact live runtime root. Runtime ownership, not durable session lineage, + * decides this boundary: an owned child has no human answerer and would + * block forever, while a lineage-bearing session resumed as a new runtime + * root may ask normally. + * + * @param request Questions, owner agent, and abort signal. + * @returns The answer chosen or typed by the human. + * @throws {UserQuestionError} code `CALLER_NOT_LIVE` when a supplied + * agent is not the registry's exact live instance, or `DELEGATED_CALLER` + * when that live agent is owned by another agent. + */ + async ask(request) { + if (request.signal?.aborted) { + throw new UserQuestionError('ask_user_question was aborted before the user answered', 'ASK_ABORTED'); + } + if (request.questions.length === 0) { + throw new UserQuestionError('ask_user_question requires at least one question', 'EMPTY_QUESTIONS'); + } + const agent = request.agent; + if (agent !== undefined) { + const agents = this.ctx.get('agents'); + if (agents === undefined || agents.get(agent.id) !== agent) { + throw new UserQuestionError('human interaction requires the exact live calling agent when an agent is supplied', 'CALLER_NOT_LIVE'); + } + if (!agents.roots().includes(agent)) { + throw new UserQuestionError('human interaction is unavailable while the calling agent is owned by another live agent; ' + + "include the unresolved question or decision in the child agent's final result", 'DELEGATED_CALLER'); + } + } + // A presentation intent asserts two things the types cannot: that the + // named approve label is one of this question's own options, and that a + // plan-review carries the plan it is a review of. A UI honouring the + // intent answers with that label, and shows that detail as the plan, so + // either gap would put a choice the asker never offered — or an approval of + // something invisible — in front of the user. Caught at the asker, where + // the mistake is, rather than in each UI. + for (const question of request.questions) { + const intent = question.intent; + if (intent === undefined) + continue; + if (!(question.options ?? []).some(option => option.label === intent.approve)) { + throw new UserQuestionError(`question ${question.id} declares intent ${intent.kind} whose approve label ` + + `${JSON.stringify(intent.approve)} names none of its options`, 'BAD_INTENT'); + } + if (question.detail === undefined) { + throw new UserQuestionError(`question ${question.id} declares intent ${intent.kind} without the detail it reviews`, 'BAD_INTENT'); + } + } + if (this.provider === undefined) { + throw new UserQuestionError('no user-questions provider is registered', 'NO_PROVIDER'); + } + return this.provider.ask(request); + } +} +export default UserQuestionService; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.d.ts new file mode 100644 index 0000000..d7f64c6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-user-questions`. + * @module @deepseek-ai/dsh-user-questions/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "user-questions-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.js new file mode 100644 index 0000000..b06edb6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/invariant.js @@ -0,0 +1,22 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-user-questions`. + * @module @deepseek-ai/dsh-user-questions/invariant + */ +const PACKAGE_NAME = '@deepseek-ai/dsh-user-questions'; +/** Cordis companion plugin name. */ +export const name = 'user-questions-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * No runtime invariant: the single provider slot is validated at registration and asks return + * directly to their caller; the seam publishes no independent request/answer audit stream. + */ +const install = () => { }; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +/* jscpd:ignore-end */ +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.d.ts new file mode 100644 index 0000000..2887da5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.d.ts @@ -0,0 +1,62 @@ +/** + * Wire-safe question and answer types, free of cordis/service imports so browser + * type chains (apiproxy api → client) can consume them without loading this + * package's Context augmentation. + * @module @deepseek-ai/dsh-user-questions/types + */ +/** One selectable answer offered to the user. */ +export interface AskUserQuestionOption { + /** User-facing label. */ + label: string; + /** Optional extra context rendered by capable UIs. */ + description?: string; +} +/** + * A caller-declared presentation intent: the question IS this kind of + * decision, so a UI that recognises the tag may present it as such instead of as a + * generic option list. Tagged so further intents can be added; a UI that does + * not know a tag renders the generic flow, and the answer encoding is identical + * either way — an intent changes presentation only, never the protocol. + */ +export type AskUserQuestionIntent = { + /** A plan submitted for review: `detail` is the plan markdown `ask()` requires, and the decision approves or declines it. */ + kind: 'plan-review'; + /** + * The option label that approves the plan; every other option declines it. + * Named rather than positional so no UI infers the verdict from option order. + * An `approve` naming no option of its own question is rejected at `ask()`. + */ + approve: string; +}; +/** One question in a user-questions request. */ +export interface AskUserQuestionItem { + /** Stable caller-provided question id, echoed in the answer. */ + id: string; + /** The question to display. */ + question: string; + /** Optional supporting detail rendered with the question but kept out of option labels. */ + detail?: string; + /** Optional short heading/group label. */ + header?: string; + /** Optional choices the UI can render as a menu. */ + options?: AskUserQuestionOption[]; + /** Whether more than one option may be selected. Defaults to single-select. */ + multiSelect?: boolean; + /** Optional presentation intent for capable UIs; absent asks for the generic option list. */ + intent?: AskUserQuestionIntent; +} +/** Answer to one question. */ +export interface AskUserQuestionAnswerItem { + /** The answered question id. */ + id: string; + /** Selected option labels. May accompany custom text for a multi-select question. */ + selected: string[]; + /** Optional free-text "Other" answer. */ + custom?: string; +} +/** The human's answer. */ +export interface AskUserQuestionAnswer { + /** Structured answers keyed by question id. */ + answers: AskUserQuestionAnswerItem[]; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.js new file mode 100644 index 0000000..653a00a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/lib/types/types.js @@ -0,0 +1,8 @@ +/** + * Wire-safe question and answer types, free of cordis/service imports so browser + * type chains (apiproxy api → client) can consume them without loading this + * package's Context augmentation. + * @module @deepseek-ai/dsh-user-questions/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/package.json new file mode 100644 index 0000000..d0820a5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions/package.json @@ -0,0 +1,51 @@ +{ + "name": "@deepseek-ai/dsh-user-questions", + "description": "Abstract user-questions seam (ctx.userQuestions) for asking the human during agent runs", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/interaction/user-questions" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..4fb6efc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_757bf6a984ac37281430ad822ab10469/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..d9c7728 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..4f44694 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.6_6fd26f59436a18b115f326d6060415e6/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..a0535b0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_44e99b6af254bac1babe371ca181e1a4/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-storage b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-storage new file mode 120000 index 0000000..e659a28 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-storage @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-storage@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_4a86070269a1adf95a907c37090343bc/node_modules/@deepseek-ai/dsh-storage \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-storage-domain b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-storage-domain new file mode 120000 index 0000000..0ab7747 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-storage-domain @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-storage-domain@0.1.0-rc.6_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_01bd56e0b17620b22dea6547cbb0fb04/node_modules/@deepseek-ai/dsh-storage-domain \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.i18n.yaml new file mode 100644 index 0000000..20f5d3b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/workspace/workspace/README.md +README.md: c1c4309efdc85f4bc7a6b0f128df6d9f4f810ae1 +README.zh.md: f44ad04be0c63061200a256c5ce8cb24a4d3c54b diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.md new file mode 100644 index 0000000..c1c4309 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.md @@ -0,0 +1,44 @@ +# @deepseek-ai/dsh-workspace + +English | [中文](README.zh.md) + +Workspace entity registry (`ctx.workspaceRegistry`) for the DeepSeek Harness: durable workspace records, stable workspace order, and a newest-first candidate session index stored through the domain data form. Consumers see the `Workspace` interface; the entity implementation stays package-private. + +The entity/storage rationale lives in the [domain Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md); header-only bootstrap and GUI ordering live in the [Workspace UI product-flow Agent Note](../../../.agents/notes/implemented/feature/2026-07-25-workspace-ui-product-flow.md). + +## Shape + +- `ctx.workspaceRegistry.create(path, title?)` — canonicalizes `path` via `fs.realpath`, rejects a nonexistent or non-directory path, creates at most one record per canonical path, and prepends a new record to durable workspace order. Repeated calls for that path return the existing workspace without changing its title; different paths may share a display title. +- `ctx.workspaceRegistry.get(id)` / `list()` / `resolveByPath(path)` — cache-served lookups. `list()` is synchronous and follows durable registry order; `resolveByPath` is async because it applies the same `realpath` canon and rejects a missing path rather than creating it. +- `ctx.workspaceRegistry.insertBefore(id, before?)` — moves a registered Workspace within durable registry order, DOM-insertBefore-like: before the anchor, or appended when the anchor is omitted. A source or anchor absent from the registry rejects without writing; a self-anchor or move to the current position resolves without writing. The returned id list is the complete committed order. +- `ctx.workspaceRegistry.delete(id)` — removes only the Workspace registration, its durable order entry, and its session account. Unknown ids return `false`; a removed record returns `true`. The directory, user files, live Sessions, and persisted session logs are never touched, so those Sessions become Ungrouped. A table-write failure restores the prior order and published entity. +- `Workspace.attachSession(id)` — validates a live or persisted session header cwd against the workspace path and prepends a new id. Unknown sessions, absent/unresolvable/non-directory cwd values, and mismatches reject without writing. `detachSession` removes only the candidate index entry. +- `Workspace.insertSessionBefore(id, before?)` — moves an accounted session within the manual order, DOM-insertBefore-like: before the anchor, or appended when the anchor is omitted. A session or anchor absent from the account rejects without writing; a move to the current position resolves without writing. Registry Workspace order never changes. +- `ctx.workspaceRegistry.archiveSession(id)` / `archivedSessionIds` — the registry-global archive set, layered over workspace accounting: an archived session disappears from grouping surfaces but keeps its session log and its `sessionIds` slot, so a future unarchive restores its position. Archiving accepts any live or persisted session (accounted or Ungrouped), resolves without writing for an already archived id, and rejects an unknown id. State written before the field existed parses with an empty set. +- `Workspace.sessionIds` — synchronous id-plus-canonical-cwd membership projection in durable candidate order. Missing headers, invalid cwd values, and mismatches are filtered; the next workspace mutation prunes them. A medium indexing one session under two workspaces, claiming one path from two records, or diverging from durable workspace order rejects at startup. +- `Workspace.status()` — uncached directory check, `'ok' | 'missing-dir'`; a missing directory never mutates the record. + +`storageDomain` and `sessionPersistence` are required startup dependencies. An unavailable peer leaves the plugin pending and cannot commit an empty initialized marker. On the first successful start, the registry calls `SessionPersistence.list()` and uses only header `id`, `cwd`, and `createdAt` to group valid historical directories and persist initial order; it never reads event bodies. The initialized marker is written last, so partial bootstrap writes are reused safely after restart. Later cwd-only sessions remain Ungrouped. + +Create and delete persist an explicit pending-mutation marker before their record and order can diverge. Startup completes only the marked mutation, then clears the marker; an unmarked order/table mismatch remains unexplained corruption and fails loud. Deleting and re-registering the same path creates a fresh Workspace id and does not automatically re-adopt the retained Sessions. + +## Model Experience + +### Workspace records and session accounts + +#### What the model sees + +Nothing. `ctx.workspaceRegistry` serves workspace records to host-side consumers only: the package registers no tools, injects no prompts, and writes no session events, so no request field ever carries this package's data. + +#### Token effect + +Zero direct tokens on every request. + +#### KV Cache effect + +Independent of live requests: the package never touches a request prefix, so it cannot invalidate provider cache reuse. + +## Known Limitations and Deferred Work + +- Session deletion and destructive folder removal are separate, absent capabilities; Workspace registration deletion never substitutes for either ([decision](../../../.agents/notes/implemented/feature/2026-07-27-workspace-registration-deletion.md)). +- The header index refreshes at startup and when attach must resolve an uncached persisted id; deletion or cwd damage performed by another process is observed after the next refresh or restart. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.zh.md new file mode 100644 index 0000000..f44ad04 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/README.zh.md @@ -0,0 +1,44 @@ +# @deepseek-ai/dsh-workspace + +[English](README.md) | 中文 + +DeepSeek Harness 的 Workspace 实体注册表(`ctx.workspaceRegistry`):通过领域数据形式存储持久 workspace 记录、稳定 workspace 顺序和按新到旧排列的候选会话索引。消费方看到 `Workspace` 接口;实体实现保持包私有。 + +实体/存储理由见[领域 Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md);仅使用头部的引导初始化和 GUI 排序见 [Workspace UI 产品流 Agent Note](../../../.agents/notes/implemented/feature/2026-07-25-workspace-ui-product-flow.md)。 + +## 结构 + +- `ctx.workspaceRegistry.create(path, title?)`:规范化 `path` 时使用 `fs.realpath`,拒绝不存在或非目录的路径,每个规范路径最多创建一条记录,并将新记录前置到持久 workspace 顺序。对同一路径重复调用会返回现有 workspace,且不改变其标题;不同路径可以共用显示标题。 +- `ctx.workspaceRegistry.get(id)`/`list()`/`resolveByPath(path)`:由缓存提供的查找。`list()` 为同步操作,并遵循持久注册表顺序;`resolveByPath` 为异步操作,因为它采用相同的 `realpath` 规范化方式,并会拒绝缺失路径,而不是创建路径。 +- `ctx.workspaceRegistry.insertBefore(id, before?)`:在持久注册表顺序内移动一个已注册 Workspace,语义类似 DOM 的 insertBefore:插到锚点之前,省略锚点则追加到末尾。来源或锚点不在注册表中时拒绝且不写入;以自身为锚点或移动到当前位置时直接完成且不写入。返回的 id 列表是完整的已提交顺序。 +- `ctx.workspaceRegistry.delete(id)`:只移除 Workspace 注册记录、对应的持久顺序条目及会话归属记录。未知 id 返回 `false`,成功移除记录则返回 `true`。目录、用户文件、活跃会话和持久化会话日志绝不受影响,因此相关会话会进入 Ungrouped。表写入失败时会恢复原顺序和此前发布的实体。 +- `Workspace.attachSession(id)`:对照 workspace 路径验证实时或已持久化的会话头 cwd,并将新 id 前置。未知会话、缺失/无法解析/非目录的 cwd 值和不匹配情况都会在不写入的前提下被拒绝。`detachSession` 只移除候选索引条目。 +- `Workspace.insertSessionBefore(id, before?)`:在手动顺序内移动一个已记账的会话,语义类似 DOM 的 insertBefore:插到锚点之前,省略锚点则追加到末尾。会话或锚点不在记账中时拒绝且不写入;移动到当前位置时直接完成且不写入。注册表中的 Workspace 顺序绝不改变。 +- `ctx.workspaceRegistry.archiveSession(id)`/`archivedSessionIds`:覆盖在 workspace 记账之上的注册表级全局归档集合:被归档的会话从各分组视图中消失,但其会话日志和 `sessionIds` 席位保持不变,未来取消归档时可恢复原位置。归档接受任何实时或已持久化的会话(无论已记账还是 Ungrouped),对已归档的 id 直接完成而不写入,并拒绝未知 id。在该字段出现之前写入的状态解析为一个空集合。 +- `Workspace.sessionIds`:按持久候选顺序提供同步 id 加规范 cwd 成员投影。缺失头部、无效 cwd 值和不匹配情况都被过滤;下一次 workspace 变更会剪除它们。如果同一存储介质将一个会话索引到两个 workspace 下、用两条记录声明同一路径,或偏离持久 workspace 顺序,启动会被拒绝。 +- `Workspace.status()`:未缓存的目录检查,返回 `'ok' | 'missing-dir'`;目录缺失绝不会改动记录。 + +`storageDomain` 和 `sessionPersistence` 是启动必需依赖。任一依赖服务不可用时,插件保持待处理,且不能提交空的已初始化标记。首次成功启动时,注册表调用 `SessionPersistence.list()`,仅使用头部 `id`、`cwd` 和 `createdAt` 对有效历史目录分组并持久化初始顺序;它绝不读取事件正文。已初始化标记最后写入,因此重启后可安全复用引导初始化期间的部分写入。后续仅能通过 cwd 识别的会话仍属于 Ungrouped。 + +创建和删除操作会在记录和顺序可能分叉之前,先持久化明确的待处理变更标记。启动时只补全该标记所指明的变更,随后清除标记;没有标记的顺序/表不一致仍属于来源不明的损坏,并会明确报错。删除后重新注册同一路径会生成新的 Workspace id,且不会自动重新接纳保留下来的会话。 + +## 模型体验 + +### Workspace 记录与会话记账 + +#### 模型看到的内容 + +没有。`ctx.workspaceRegistry` 只向宿主侧消费方提供 workspace 记录:此包不注册工具、不注入提示词、不写入会话事件,因此没有请求字段会携带此包数据。 + +#### Token 影响 + +每个请求的直接 token 为零。 + +#### KV Cache 影响 + +与实时请求无关:此包绝不触及请求前缀,因此不会使提供方缓存复用失效。 + +## 已知限制与暂缓事项 + +- 会话删除与破坏性的文件夹移除是彼此独立且尚未提供的功能;删除 Workspace 注册记录绝不能替代二者(参见[决策记录](../../../.agents/notes/implemented/feature/2026-07-27-workspace-registration-deletion.md))。 +- 头部索引会在启动时刷新,也会在 attach 必须解析未缓存持久 id 时刷新;另一进程执行的删除或造成的 cwd 损坏会在下次刷新或重启后被发现。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/index.js new file mode 100644 index 0000000..b9d5a8e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/index.js @@ -0,0 +1,757 @@ +import { randomUUID } from "node:crypto"; +import { realpath, stat } from "node:fs/promises"; +import { basename } from "node:path"; +import { Service } from "@deepseek-ai/cordis"; +import { z } from "zod"; +import { SessionId } from "@deepseek-ai/dsh-session"; +import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain"; +//#region lib/types/paths.js +/** +* Path canonicalization for workspace identity. +* @module @deepseek-ai/dsh-workspace/src/paths +*/ +/** +* Canonicalize a directory path via `fs.realpath`: trailing slashes, `..` +* segments, and symlinks are all resolved. This is the ONE uniqueness canon of +* the package — workspace paths are stored canonicalized, uniqueness is +* string equality of canonicalized paths (a symlink to an existing +* workspace's directory collides), and attach-time session `cwd` checks go +* through the same canon. A path that does not exist rejects with the +* original `ENOENT` — this is `create`'s reject path (a workspace must point +* at an existing directory). +* @param path - The path to canonicalize. +* @returns the canonical absolute path. +*/ +async function realpathNormalize(path) { + return await realpath(path); +} +//#endregion +//#region lib/types/entity.js +/** +* Package-private workspace entity: the single {@link Workspace} +* implementation. Holds a record snapshot that is swapped in place after each +* durable mutation; every write funnels through the private `mutate` so +* `updatedAt` stamping and invalid-account pruning happen exactly once. +* Not re-exported from the package entrypoint — consumers see only the +* `Workspace` interface. +* @module @deepseek-ai/dsh-workspace/src/entity +*/ +/** An insertSessionBefore request named a session or anchor not on the account (storage failures stay plain errors). */ +var WorkspaceMoveInvalidError = class extends Error { + /** + * @param message - Which id was unaccounted and where. + */ + constructor(message) { + super(message); + this.name = "WorkspaceMoveInvalidError"; + } +}; +/** Chain-slot abort sentinel thrown by the update fn when the record needs no change; only `mutate` observes it. */ +const unchangedSentinel = /* @__PURE__ */ new Error("workspace record unchanged (internal sentinel)"); +/** The single {@link Workspace} implementation; constructed only by the registry. */ +var WorkspaceEntity = class { + host; + id; + record; + /** + * @param host - Registry-owned table, session-path index, and header reads. + * @param id - The record's stable id. + * @param record - The validated record snapshot loaded or just written. + */ + constructor(host, id, record) { + this.host = host; + this.id = id; + this.record = record; + } + get path() { + return this.record.path; + } + get title() { + return this.record.title; + } + get createdAt() { + return this.record.createdAt; + } + get updatedAt() { + return this.record.updatedAt; + } + get sessionIds() { + return this.record.sessionIds.filter((id) => this.host.sessionPath(id) === this.record.path); + } + async setTitle(title) { + await this.mutate((record) => ({ + ...record, + title + })); + } + async attachSession(sessionId) { + if (!this.record.sessionIds.includes(sessionId)) { + const header = await this.host.readSessionHeader(sessionId); + if (header.cwd === void 0) throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': its stored header carries no cwd to validate against`); + let cwd; + try { + cwd = await realpathNormalize(header.cwd); + } catch (error) { + throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': its cwd '${header.cwd}' does not resolve, so it cannot be validated`, { cause: error }); + } + if (!(await stat(cwd)).isDirectory()) throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': its cwd '${header.cwd}' is not a directory`); + if (cwd !== this.record.path) throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': its cwd resolves to '${cwd}'`); + this.host.rememberSessionPath(sessionId, cwd); + } + await this.mutate((record) => record.sessionIds.includes(sessionId) ? record : { + ...record, + sessionIds: [sessionId, ...record.sessionIds] + }); + } + async insertSessionBefore(sessionId, beforeSessionId) { + await this.mutate((record) => { + if (!record.sessionIds.includes(sessionId)) throw new WorkspaceMoveInvalidError(`cannot move session '${sessionId}' in workspace '${record.path}': the session is not accounted`); + if (beforeSessionId !== void 0 && !record.sessionIds.includes(beforeSessionId)) throw new WorkspaceMoveInvalidError(`cannot move session '${sessionId}' before '${beforeSessionId}' in workspace '${record.path}': the anchor session is not accounted`); + if (beforeSessionId === sessionId) return record; + const without = record.sessionIds.filter((id) => id !== sessionId); + const at = beforeSessionId === void 0 ? without.length : without.indexOf(beforeSessionId); + const sessionIds = [ + ...without.slice(0, at), + sessionId, + ...without.slice(at) + ]; + return sessionIds.every((id, index) => id === record.sessionIds[index]) ? record : { + ...record, + sessionIds + }; + }); + } + async detachSession(sessionId) { + await this.mutate((record) => record.sessionIds.includes(sessionId) ? { + ...record, + sessionIds: record.sessionIds.filter((id) => id !== sessionId) + } : record); + } + async status() { + try { + return (await stat(this.record.path)).isDirectory() ? "ok" : "missing-dir"; + } catch { + return "missing-dir"; + } + } + /** + * The single write path: run `fn` on the domain write chain via + * `table.update`, stamping `updatedAt` and pruning candidates that no + * longer pass the id-plus-canonical-cwd membership check, then swap the + * snapshot. + * + * `fn` sees the value current at its chain slot, so membership decisions + * (attach/detach idempotence) are race-free against queued writes; a fn + * signalling no change by returning `current` verbatim aborts the slot + * through the sentinel when pruning also finds nothing, so a no-op neither + * rewrites the medium nor emits a change event. + */ + async mutate(fn) { + let next; + try { + next = await this.host.table().update(this.id, (current) => { + const changed = fn(current); + const sessionIds = changed.sessionIds.filter((id) => this.host.sessionPath(id) === changed.path); + if (changed === current && sessionIds.length === current.sessionIds.length) throw unchangedSentinel; + return { + ...changed, + sessionIds, + updatedAt: (/* @__PURE__ */ new Date()).toISOString() + }; + }); + } catch (error) { + if (error === unchangedSentinel) return; + throw error; + } + this.record = next; + } +}; +//#endregion +//#region lib/types/spec.js +/** +* The workspace domain declaration: record schema and the `defineDomain` spec +* the registry opens. The zod schema is the durable-boundary validator today +* and the direct source of the RPC wire projection in a later phase. +* @module @deepseek-ai/dsh-workspace/src/spec +*/ +/** Workspace id schema at the durable boundary; branding has no runtime representation. */ +const workspaceId = z.string().transform((value) => value); +/** +* Durable shape of one workspace record. `path` is the `fs.realpath` canon +* stamped at create; `sessionIds` is the ordered ownership account (array +* order is display order); timestamps are ISO-8601 strings. +*/ +const workspaceRecord = z.object({ + path: z.string(), + title: z.string(), + sessionIds: z.array(z.string().transform(SessionId)), + createdAt: z.string(), + updatedAt: z.string() +}); +/** +* Recoverable two-write mutation marker. The marker is persisted before the +* record/order pair can diverge, so startup can distinguish an interrupted +* registry operation from unexplained medium corruption. +*/ +const workspacePendingMutation = z.discriminatedUnion("operation", [z.object({ + operation: z.literal("create"), + workspaceId +}), z.object({ + operation: z.literal("delete"), + workspaceId +})]); +/** +* Durable registry state. `initialized` distinguishes a valid empty registry +* from one that still needs the header-only history bootstrap; +* `workspaceIds` is the authoritative display order. `archivedSessionIds` is +* the registry-global archive set layered over workspace accounting: an +* archived session keeps its `sessionIds` slot (unarchiving must restore the +* position), so the set never participates in the one-owner accounting +* invariant. Defaulted so records written before the field parse unchanged. +*/ +const workspaceDomainState = z.object({ + initialized: z.boolean(), + workspaceIds: z.array(workspaceId), + archivedSessionIds: z.array(z.string().transform(SessionId)).default([]), + pendingMutation: workspacePendingMutation.optional() +}); +/** +* The workspace domain spec: one `workspaces` table keyed by +* {@link WorkspaceId} plus the bootstrap/order singleton. The registry opens +* this through `ctx.storage.domain`; the spec object is the single source of +* the domain's identity, version, and schemas. +*/ +const workspaceDomainSpec = defineDomain({ + name: "workspace", + version: 2, + global: { + schema: workspaceDomainState, + initial: { + initialized: false, + workspaceIds: [], + archivedSessionIds: [] + } + }, + tables: { workspaces: domainTable(workspaceRecord) } +}); +//#endregion +//#region lib/types/index.js +/** +* Workspace entity registry (`ctx.workspaceRegistry`): durable workspace records, +* stable registry order, and header-validated session membership over the +* domain data form. +* @module @deepseek-ai/dsh-workspace +*/ +/** +* Brand a string as a {@link WorkspaceId}. +* @param id - Raw workspace id string. +* @returns the same string, branded at compile time. +*/ +function WorkspaceId(id) { + return id; +} +/** +* An archiveSession request named a session neither live nor in session +* persistence — a definite miss only; storage faults propagate as themselves. +*/ +var WorkspaceUnknownSessionError = class extends Error { + sessionId; + /** + * @param sessionId - The unknown session id. + */ + constructor(sessionId) { + super(`cannot archive session '${sessionId}': live sessions and session persistence hold no such session`); + this.sessionId = sessionId; + this.name = "WorkspaceUnknownSessionError"; + } +}; +/** A workspace reorder named a source or anchor absent from the durable registry order. */ +var WorkspaceOrderInvalidError = class extends Error { + workspaceId; + /** + * @param workspaceId - Missing source or anchor id. + */ + constructor(workspaceId) { + super(`cannot reorder unknown workspace '${workspaceId}'`); + this.workspaceId = workspaceId; + this.name = "WorkspaceOrderInvalidError"; + } +}; +const sameIds = (left, right) => left.length === right.length && left.every((id, index) => id === right[index]); +const compareHeaders = (left, right) => right.createdAt - left.createdAt || String(left.id).localeCompare(String(right.id)); +/** +* Durable workspace registry. Startup waits for `sessionPersistence`, builds +* one canonical-cwd header index, and completes the one-time history +* bootstrap before the service becomes active. The persistence dependency is +* mandatory so an unavailable peer can never be mistaken for an empty +* history and commit the initialized marker. +*/ +var WorkspaceRegistry = class extends Service { + static inject = ["storageDomain", "sessionPersistence"]; + table; + global; + state; + entities = /* @__PURE__ */ new Map(); + headers = /* @__PURE__ */ new Map(); + sessionPaths = /* @__PURE__ */ new Map(); + invalidSessionPaths = /* @__PURE__ */ new Map(); + operationTail = Promise.resolve(); + host = { + table: () => this.requireTable(), + sessionPath: (id) => this.sessionPaths.get(id), + readSessionHeader: (id) => this.readSessionHeader(id), + rememberSessionPath: (id, path) => { + this.sessionPaths.set(id, path); + this.invalidSessionPaths.delete(id); + } + }; + constructor(ctx) { + super(ctx, "workspaceRegistry"); + } + /** Open the domain, finish bootstrap when required, and rebuild the ordered cache. */ + async [Service.init]() { + const domain = await this.ctx.storageDomain.open(workspaceDomainSpec); + this.ctx.effect(() => () => domain.close(), "workspace.domainClose"); + this.table = domain.table("workspaces"); + this.global = domain.global; + this.state = domain.global.get(); + await this.recoverPendingMutation(); + this.validateStoredState(this.state); + if (!this.state.initialized) { + const headers = await this.ctx.sessionPersistence.list(); + await this.replaceHeaderIndex(headers); + await this.bootstrap(headers); + } else if (this.table.size > 0) await this.replaceHeaderIndex(await this.ctx.sessionPersistence.list()); + await this.indexLiveSessions(); + this.validateStoredState(this.requireState()); + this.rebuildEntities(); + this.reportFilteredCandidates(); + } + /** + * Create or reuse a workspace for an existing directory. The path is + * canonicalized through `fs.realpath`; a nonexistent path rejects with the + * original error and a non-directory rejects. Repeated calls for the same + * canonical path return the existing entity without changing its title. + * A newly created workspace is prepended to the durable registry order. + * Different canonical paths may share a display title. + * @param path - Existing directory to own, in any path spelling. + * @param title - Display title used only when a new record is created. + * @returns the existing or newly durable workspace. + */ + async create(path, title) { + const canonical = await realpathNormalize(path); + if (!(await stat(canonical)).isDirectory()) throw new Error(`cannot create a workspace at '${canonical}': path is not a directory`); + return await this.enqueueOperation(() => this.createCanonical(canonical, title)); + } + /** + * Look up a workspace by id. + * @param id - Workspace id. + * @returns the workspace, or `undefined` when unknown. + */ + get(id) { + return this.entities.get(id); + } + /** + * Synchronous workspace projection in durable registry order. Every + * entity's `sessionIds` getter is already filtered by the startup/live + * canonical-cwd header index; this method performs no persistence reads. + * @returns a fresh ordered array of workspace entities. + */ + list() { + return this.requireState().workspaceIds.map((id) => { + const entity = this.entities.get(id); + if (entity === void 0) throw new Error(`workspace registry order references missing workspace '${id}'`); + return entity; + }); + } + /** + * Delete one workspace registration while retaining its directory and every + * session log. The durable order is updated before the table deletion; a + * failed table write restores the prior order and keeps the entity + * published. Unknown ids are an idempotent no-op for domain callers. + * @param id - Workspace registration to remove. + * @returns `true` when a record was deleted, `false` when it was unknown. + */ + delete(id) { + return this.enqueueOperation(() => this.deleteKnown(id)); + } + /** + * Move one workspace within the durable display order, DOM-insertBefore-like. + * With an anchor it lands before that workspace; without one it appends. + * @param id - Workspace to move. + * @param beforeId - Workspace anchor; omitted appends. + * @returns the complete committed workspace order. + */ + insertBefore(id, beforeId) { + return this.enqueueOperation(async () => { + const state = this.requireState(); + if (!state.workspaceIds.includes(id)) throw new WorkspaceOrderInvalidError(id); + if (beforeId !== void 0 && !state.workspaceIds.includes(beforeId)) throw new WorkspaceOrderInvalidError(beforeId); + if (beforeId === id) return state.workspaceIds; + const without = state.workspaceIds.filter((workspaceId) => workspaceId !== id); + const at = beforeId === void 0 ? without.length : without.indexOf(beforeId); + const workspaceIds = [ + ...without.slice(0, at), + id, + ...without.slice(at) + ]; + if (sameIds(workspaceIds, state.workspaceIds)) return state.workspaceIds; + await this.setState({ + ...state, + workspaceIds + }); + return workspaceIds; + }); + } + /** + * The registry-global archive set: sessions hidden from every grouping + * surface. Archiving never touches workspace accounting — an archived + * session keeps its `sessionIds` slot so unarchiving restores its position. + * @returns the archived session ids in archive order. + */ + get archivedSessionIds() { + return this.requireState().archivedSessionIds; + } + /** + * Archive one session durably. The session must exist (live or in session + * persistence); its workspace accounting — or lack of one — is irrelevant. + * An already archived id resolves without writing. + * @param sessionId - The session to archive. + * @returns resolution after durability. + */ + archiveSession(sessionId) { + return this.enqueueOperation(async () => { + if (this.requireState().archivedSessionIds.includes(sessionId)) return; + if (!await this.sessionKnown(sessionId)) throw new WorkspaceUnknownSessionError(sessionId); + const state = this.requireState(); + await this.setState({ + ...state, + archivedSessionIds: [...state.archivedSessionIds, sessionId] + }); + }); + } + /** + * Whether a session is live, header-indexed, or present in a fresh + * persistence listing. Only a definite miss returns false — a failing + * `sessionPersistence.list()` propagates so storage faults never + * masquerade as an unknown session. + */ + async sessionKnown(id) { + if (this.ctx.get("sessions")?.get(id) !== void 0) return true; + if (this.headers.has(id)) return true; + await this.indexHeaders(await this.ctx.sessionPersistence.list()); + return this.headers.has(id); + } + /** + * Resolve by canonical directory path without creating or mutating a + * workspace. A missing path rejects during `realpath`; an existing unowned + * directory returns `undefined`. + * @param path - Existing directory path in any spelling. + * @returns the workspace owning the canonical path, when one exists. + */ + async resolveByPath(path) { + const canonical = await realpathNormalize(path); + for (const entity of this.entities.values()) if (entity.path === canonical) return entity; + } + async createCanonical(canonical, title) { + for (const entity of this.entities.values()) if (entity.path === canonical) return entity; + const workspaceName = title ?? basename(canonical); + const table = this.requireTable(); + const state = this.requireState(); + const id = WorkspaceId(randomUUID()); + const now = (/* @__PURE__ */ new Date()).toISOString(); + const record = { + path: canonical, + title: workspaceName, + sessionIds: [], + createdAt: now, + updatedAt: now + }; + const entity = new WorkspaceEntity(this.host, id, record); + this.entities.set(id, entity); + const pendingState = { + ...state, + pendingMutation: { + operation: "create", + workspaceId: id + } + }; + try { + await this.setState(pendingState); + } catch (error) { + this.entities.delete(id); + throw error; + } + try { + await table.put(id, record); + } catch (error) { + this.entities.delete(id); + try { + await this.setState(state); + } catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' record write and pending-marker rollback both failed`); + } + throw error; + } + try { + await this.setState({ + initialized: true, + workspaceIds: [id, ...state.workspaceIds], + archivedSessionIds: state.archivedSessionIds + }); + } catch (error) { + this.entities.delete(id); + try { + await table.delete(id); + } catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' order write and record rollback both failed; the pending marker remains recoverable`); + } + try { + await this.setState(state); + } catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' order write and pending-marker rollback both failed`); + } + throw error; + } + return entity; + } + async deleteKnown(id) { + const entity = this.entities.get(id); + if (entity === void 0) return false; + const state = this.requireState(); + const nextState = { + initialized: true, + workspaceIds: state.workspaceIds.filter((workspaceId) => workspaceId !== id), + archivedSessionIds: state.archivedSessionIds + }; + await this.setState({ + ...nextState, + pendingMutation: { + operation: "delete", + workspaceId: id + } + }); + this.entities.delete(id); + try { + await this.requireTable().delete(id); + } catch (error) { + this.entities.set(id, entity); + try { + await this.setState(state); + } catch (rollbackError) { + this.entities.delete(id); + throw new AggregateError([error, rollbackError], `workspace '${id}' record deletion and registry-order rollback both failed`); + } + throw error; + } + try { + await this.setState(nextState); + } catch (error) { + this.ctx.logger.warn(`workspace '${id}' was deleted but its pending marker could not be cleared: ${String(error)}`); + } + return true; + } + /** + * Complete the one mutation explicitly named by durable state. Unexplained + * order/table divergence still reaches {@link validateStoredState} and + * fails loud; this path never guesses which operation created a row from its shape alone. + */ + async recoverPendingMutation() { + const state = this.requireState(); + const pending = state.pendingMutation; + if (pending === void 0) return; + if (state.workspaceIds.includes(pending.workspaceId)) throw new Error(`workspace domain is inconsistent: pending ${pending.operation} workspace '${pending.workspaceId}' is still present in registry order`); + await this.requireTable().delete(pending.workspaceId); + await this.setState({ + initialized: state.initialized, + workspaceIds: state.workspaceIds, + archivedSessionIds: state.archivedSessionIds + }); + } + async bootstrap(headers) { + const table = this.requireTable(); + const state = this.requireState(); + const groupsByPath = /* @__PURE__ */ new Map(); + for (const header of headers) { + const path = this.sessionPaths.get(header.id); + if (path === void 0) continue; + const group = groupsByPath.get(path); + if (group === void 0) groupsByPath.set(path, [header]); + else group.push(header); + } + const groups = [...groupsByPath].map(([path, groupHeaders]) => { + groupHeaders.sort(compareHeaders); + return { + path, + headers: groupHeaders, + newestAt: groupHeaders[0].createdAt + }; + }).sort((left, right) => right.newestAt - left.newestAt || left.path.localeCompare(right.path)); + const byPath = /* @__PURE__ */ new Map(); + const accounted = /* @__PURE__ */ new Map(); + for (const [id, record] of table.entries()) { + byPath.set(record.path, id); + for (const sessionId of record.sessionIds) accounted.set(sessionId, id); + } + for (const group of groups) { + let id = byPath.get(group.path); + if (id === void 0) { + const sessionIds = group.headers.map((header) => header.id).filter((sessionId) => !accounted.has(sessionId)); + if (sessionIds.length === 0) continue; + id = WorkspaceId(randomUUID()); + const createdAt = new Date(group.newestAt).toISOString(); + const record = { + path: group.path, + title: basename(group.path), + sessionIds, + createdAt, + updatedAt: createdAt + }; + await table.put(id, record); + byPath.set(group.path, id); + for (const sessionId of sessionIds) accounted.set(sessionId, id); + continue; + } + const current = table.get(id); + const historical = group.headers.map((header) => header.id).filter((sessionId) => accounted.get(sessionId) === void 0 || accounted.get(sessionId) === id); + const historicalSet = new Set(historical); + const sessionIds = [...historical, ...current.sessionIds.filter((sessionId) => !historicalSet.has(sessionId))]; + if (sameSessionIds(current.sessionIds, sessionIds)) continue; + await table.update(id, (record) => ({ + ...record, + sessionIds, + updatedAt: (/* @__PURE__ */ new Date()).toISOString() + })); + for (const sessionId of historical) accounted.set(sessionId, id); + } + const groupRank = new Map(groups.map((group) => [group.path, group.newestAt])); + const priorRank = new Map(state.workspaceIds.map((id, index) => [id, index])); + const workspaceIds = [...table.entries()].sort(([leftId, left], [rightId, right]) => { + const leftTime = groupRank.get(left.path) ?? Date.parse(left.createdAt); + return (groupRank.get(right.path) ?? Date.parse(right.createdAt)) - leftTime || (priorRank.get(leftId) ?? Number.MAX_SAFE_INTEGER) - (priorRank.get(rightId) ?? Number.MAX_SAFE_INTEGER) || String(leftId).localeCompare(String(rightId)); + }).map(([id]) => id); + if (!sameIds(state.workspaceIds, workspaceIds)) await this.setState({ + initialized: false, + workspaceIds, + archivedSessionIds: state.archivedSessionIds + }); + await this.setState({ + initialized: true, + workspaceIds, + archivedSessionIds: state.archivedSessionIds + }); + } + validateStoredState(state) { + const table = this.requireTable(); + const order = /* @__PURE__ */ new Set(); + for (const id of state.workspaceIds) { + if (order.has(id)) throw new Error(`workspace domain is inconsistent: registry order repeats workspace '${id}'`); + if (table.get(id) === void 0) throw new Error(`workspace domain is inconsistent: registry order references missing workspace '${id}'`); + order.add(id); + } + if (state.initialized && order.size !== table.size) { + const orphan = [...table.keys()].find((id) => !order.has(id)); + throw new Error(`workspace domain is inconsistent: workspace '${orphan}' is absent from registry order`); + } + const paths = /* @__PURE__ */ new Map(); + const accounted = /* @__PURE__ */ new Map(); + for (const [id, record] of table.entries()) { + const pathHolder = paths.get(record.path); + if (pathHolder !== void 0) throw new Error(`workspace domain is inconsistent: path '${record.path}' is claimed by both workspace '${pathHolder}' and workspace '${id}'`); + paths.set(record.path, id); + for (const sessionId of record.sessionIds) { + const holder = accounted.get(sessionId); + if (holder !== void 0) throw new Error(`workspace domain is inconsistent: session '${sessionId}' is accounted by both workspace '${holder}' and workspace '${id}'`); + accounted.set(sessionId, id); + } + } + } + rebuildEntities() { + this.entities.clear(); + for (const id of this.requireState().workspaceIds) { + const record = this.requireTable().get(id); + this.entities.set(id, new WorkspaceEntity(this.host, id, record)); + } + } + async replaceHeaderIndex(headers) { + this.headers.clear(); + this.sessionPaths.clear(); + this.invalidSessionPaths.clear(); + await this.indexHeaders(headers); + } + async indexHeaders(headers) { + for (const header of headers) await this.indexHeader(header); + } + async indexHeader(header) { + this.headers.set(header.id, header); + this.sessionPaths.delete(header.id); + if (header.cwd === void 0) { + this.invalidSessionPaths.set(header.id, "header has no cwd"); + return; + } + try { + const path = await realpathNormalize(header.cwd); + if (!(await stat(path)).isDirectory()) { + this.invalidSessionPaths.set(header.id, `cwd '${header.cwd}' is not a directory`); + return; + } + this.sessionPaths.set(header.id, path); + this.invalidSessionPaths.delete(header.id); + } catch { + this.invalidSessionPaths.set(header.id, `cwd '${header.cwd}' does not resolve`); + } + } + async indexLiveSessions() { + const sessions = this.ctx.get("sessions"); + if (sessions === void 0) return; + await this.indexHeaders(sessions.list().map((session) => session.header)); + } + reportFilteredCandidates() { + for (const entity of this.entities.values()) { + const record = this.requireTable().get(entity.id); + for (const sessionId of record.sessionIds) { + const path = this.sessionPaths.get(sessionId); + if (path === record.path) continue; + const reason = this.invalidSessionPaths.get(sessionId) ?? (this.headers.has(sessionId) ? `canonical cwd '${path}' differs from workspace path '${record.path}'` : "session header is missing"); + this.ctx.logger.warn(`workspace '${entity.id}' filtered session '${sessionId}' from membership: ${reason}`); + } + } + } + async readSessionHeader(id) { + const live = this.ctx.get("sessions")?.get(id); + if (live !== void 0) { + this.headers.set(id, live.header); + return live.header; + } + const cached = this.headers.get(id); + if (cached !== void 0) return cached; + const headers = await this.ctx.sessionPersistence.list(); + await this.indexHeaders(headers); + const header = this.headers.get(id); + if (header === void 0) throw new Error(`cannot validate session '${id}': session persistence holds no such session`); + return header; + } + requireTable() { + if (this.table === void 0) throw new Error("workspace registry is not started yet"); + return this.table; + } + requireState() { + if (this.state === void 0) throw new Error("workspace registry is not started yet"); + return this.state; + } + async setState(state) { + await this.global.set(state); + this.state = state; + } + enqueueOperation(operation) { + const result = this.operationTail.then(async () => { + await this.recoverPendingMutation(); + return await operation(); + }); + this.operationTail = result.then(() => {}, () => {}); + return result; + } +}; +const sameSessionIds = (left, right) => left.length === right.length && left.every((id, index) => id === right[index]); +//#endregion +export { WorkspaceId, WorkspaceMoveInvalidError, WorkspaceOrderInvalidError, WorkspaceRegistry, WorkspaceRegistry as default, WorkspaceUnknownSessionError, realpathNormalize, workspaceDomainSpec, workspaceDomainState, workspaceRecord }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/invariant.js new file mode 100644 index 0000000..cc04791 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/invariant.js @@ -0,0 +1,114 @@ +import "node:crypto"; +import "node:fs/promises"; +import "node:path"; +import { Service } from "@deepseek-ai/cordis"; +import { z } from "zod"; +import { SessionId } from "@deepseek-ai/dsh-session"; +import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain"; +//#endregion +//#region src/spec.ts +/** +* The workspace domain declaration: record schema and the `defineDomain` spec +* the registry opens. The zod schema is the durable-boundary validator today +* and the direct source of the RPC wire projection in a later phase. +* @module @deepseek-ai/dsh-workspace/src/spec +*/ +/** Workspace id schema at the durable boundary; branding has no runtime representation. */ +const workspaceId = z.string().transform((value) => value); +/** +* Durable shape of one workspace record. `path` is the `fs.realpath` canon +* stamped at create; `sessionIds` is the ordered ownership account (array +* order is display order); timestamps are ISO-8601 strings. +*/ +const workspaceRecord = z.object({ + path: z.string(), + title: z.string(), + sessionIds: z.array(z.string().transform(SessionId)), + createdAt: z.string(), + updatedAt: z.string() +}); +/** +* Recoverable two-write mutation marker. The marker is persisted before the +* record/order pair can diverge, so startup can distinguish an interrupted +* registry operation from unexplained medium corruption. +*/ +const workspacePendingMutation = z.discriminatedUnion("operation", [z.object({ + operation: z.literal("create"), + workspaceId +}), z.object({ + operation: z.literal("delete"), + workspaceId +})]); +defineDomain({ + name: "workspace", + version: 2, + global: { + schema: z.object({ + initialized: z.boolean(), + workspaceIds: z.array(workspaceId), + archivedSessionIds: z.array(z.string().transform(SessionId)).default([]), + pendingMutation: workspacePendingMutation.optional() + }), + initial: { + initialized: false, + workspaceIds: [], + archivedSessionIds: [] + } + }, + tables: { workspaces: domainTable(workspaceRecord) } +}); +//#endregion +//#region src/index.ts +/** +* Workspace entity registry (`ctx.workspaceRegistry`): durable workspace records, +* stable registry order, and header-validated session membership over the +* domain data form. +* @module @deepseek-ai/dsh-workspace +*/ +/** +* Brand a string as a {@link WorkspaceId}. +* @param id - Raw workspace id string. +* @returns the same string, branded at compile time. +*/ +function WorkspaceId(id) { + return id; +} +Service.init; +//#endregion +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-workspace`. +* @module @deepseek-ai/dsh-workspace/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-workspace"; +/** Cordis companion plugin name. */ +const name = "workspace-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* Owned relationship: the registry's entity cache mirrors the workspace +* domain's durable table. Every `domain/changed` for the `workspaces` table +* must name a record the cache already holds an entity for (the registry +* caches before the durable put and mutates only through cached entities). +* A delete is valid only after the registry has removed the entity from its +* cache, whether for create rollback or an explicit registration deletion; +* deleting while the cache still publishes the entity proves a bypass. +*/ +const install = Object.assign((ctx, fail) => { + ctx.on("domain/changed", (change) => { + if (change.domain !== "workspace" || change.table !== "workspaces") return; + if (change.operation === "deleted") { + if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) !== void 0) fail(`workspace record '${change.key}' was deleted while the registry cache still publishes it — some write path bypassed ctx.workspaceRegistry`); + return; + } + if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) === void 0) fail(`workspace record '${change.key}' landed durably but the registry cache holds no entity for it — the cache and the domain table have diverged`); + }); +}, { inject: ["workspaceRegistry"] }); +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.d.ts new file mode 100644 index 0000000..55ab56b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.d.ts @@ -0,0 +1,88 @@ +/** + * Package-private workspace entity: the single {@link Workspace} + * implementation. Holds a record snapshot that is swapped in place after each + * durable mutation; every write funnels through the private `mutate` so + * `updatedAt` stamping and invalid-account pruning happen exactly once. + * Not re-exported from the package entrypoint — consumers see only the + * `Workspace` interface. + * @module @deepseek-ai/dsh-workspace/src/entity + */ +import type { SessionHeader, SessionId } from '@deepseek-ai/dsh-session'; +import type { KvTable } from '@deepseek-ai/dsh-storage-domain'; +import type { WorkspaceRecord } from './spec.ts'; +import type { Workspace, WorkspaceId } from './types.ts'; +/** An insertSessionBefore request named a session or anchor not on the account (storage failures stay plain errors). */ +export declare class WorkspaceMoveInvalidError extends Error { + /** + * @param message - Which id was unaccounted and where. + */ + constructor(message: string); +} +/** + * The registry-owned machinery an entity mutates through. Entities never see + * the registry itself — only the open table, the canonical session-path + * index backing the `sessionIds` projection, and attach-time header reads. + */ +export interface WorkspaceEntityHost { + /** + * Resolve the open `workspaces` table. + * @returns the table; throws while the registry has not started yet. + */ + table(): KvTable; + /** + * Read a session's canonical directory from the registry's header index. + * @param id - Session whose indexed path is requested. + * @returns the canonical directory, or `undefined` when the header is + * missing or its cwd cannot identify an existing directory. + */ + sessionPath(id: SessionId): string | undefined; + /** + * Read one stored session header for attach validation. + * @param id - The session whose header to read. + * @returns the header; rejects when session persistence is absent or holds + * no session with this id. + */ + readSessionHeader(id: SessionId): Promise; + /** + * Publish a successfully validated canonical cwd to the projection index. + * @param id - Validated session id. + * @param path - Canonical existing directory from the immutable header cwd. + */ + rememberSessionPath(id: SessionId, path: string): void; +} +/** The single {@link Workspace} implementation; constructed only by the registry. */ +export declare class WorkspaceEntity implements Workspace { + private readonly host; + readonly id: WorkspaceId; + private record; + /** + * @param host - Registry-owned table, session-path index, and header reads. + * @param id - The record's stable id. + * @param record - The validated record snapshot loaded or just written. + */ + constructor(host: WorkspaceEntityHost, id: WorkspaceId, record: WorkspaceRecord); + get path(): string; + get title(): string; + get createdAt(): string; + get updatedAt(): string; + get sessionIds(): readonly SessionId[]; + setTitle(title: string): Promise; + attachSession(sessionId: SessionId): Promise; + insertSessionBefore(sessionId: SessionId, beforeSessionId?: SessionId): Promise; + detachSession(sessionId: SessionId): Promise; + status(): Promise<'ok' | 'missing-dir'>; + /** + * The single write path: run `fn` on the domain write chain via + * `table.update`, stamping `updatedAt` and pruning candidates that no + * longer pass the id-plus-canonical-cwd membership check, then swap the + * snapshot. + * + * `fn` sees the value current at its chain slot, so membership decisions + * (attach/detach idempotence) are race-free against queued writes; a fn + * signalling no change by returning `current` verbatim aborts the slot + * through the sentinel when pruning also finds nothing, so a no-op neither + * rewrites the medium nor emits a change event. + */ + private mutate; +} +//# sourceMappingURL=entity.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.js new file mode 100644 index 0000000..95aae5e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.js @@ -0,0 +1,156 @@ +/** + * Package-private workspace entity: the single {@link Workspace} + * implementation. Holds a record snapshot that is swapped in place after each + * durable mutation; every write funnels through the private `mutate` so + * `updatedAt` stamping and invalid-account pruning happen exactly once. + * Not re-exported from the package entrypoint — consumers see only the + * `Workspace` interface. + * @module @deepseek-ai/dsh-workspace/src/entity + */ +import { stat } from 'node:fs/promises'; +import { realpathNormalize } from "./paths.js"; +/** An insertSessionBefore request named a session or anchor not on the account (storage failures stay plain errors). */ +export class WorkspaceMoveInvalidError extends Error { + /** + * @param message - Which id was unaccounted and where. + */ + constructor(message) { + super(message); + this.name = 'WorkspaceMoveInvalidError'; + } +} +/** Chain-slot abort sentinel thrown by the update fn when the record needs no change; only `mutate` observes it. */ +const unchangedSentinel = new Error('workspace record unchanged (internal sentinel)'); +/** The single {@link Workspace} implementation; constructed only by the registry. */ +export class WorkspaceEntity { + host; + id; + record; + /** + * @param host - Registry-owned table, session-path index, and header reads. + * @param id - The record's stable id. + * @param record - The validated record snapshot loaded or just written. + */ + constructor(host, id, record) { + this.host = host; + this.id = id; + this.record = record; + } + get path() { + return this.record.path; + } + get title() { + return this.record.title; + } + get createdAt() { + return this.record.createdAt; + } + get updatedAt() { + return this.record.updatedAt; + } + get sessionIds() { + return this.record.sessionIds.filter(id => this.host.sessionPath(id) === this.record.path); + } + async setTitle(title) { + await this.mutate(record => ({ ...record, title })); + } + async attachSession(sessionId) { + // Validation is skipped when the settled snapshot already accounts the + // id: the cwd fact was checked when it first attached and both inputs + // (stored header cwd, workspace path) are immutable. Membership itself is + // decided on the write chain inside `mutate`, never on this snapshot. + if (!this.record.sessionIds.includes(sessionId)) { + const header = await this.host.readSessionHeader(sessionId); + if (header.cwd === undefined) { + throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': ` + + 'its stored header carries no cwd to validate against'); + } + let cwd; + try { + cwd = await realpathNormalize(header.cwd); + } + catch (error) { + throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': ` + + `its cwd '${header.cwd}' does not resolve, so it cannot be validated`, { cause: error }); + } + if (!(await stat(cwd)).isDirectory()) { + throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': ` + + `its cwd '${header.cwd}' is not a directory`); + } + if (cwd !== this.record.path) { + throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': ` + + `its cwd resolves to '${cwd}'`); + } + this.host.rememberSessionPath(sessionId, cwd); + } + await this.mutate(record => record.sessionIds.includes(sessionId) + ? record + : { ...record, sessionIds: [sessionId, ...record.sessionIds] }); + } + async insertSessionBefore(sessionId, beforeSessionId) { + await this.mutate((record) => { + if (!record.sessionIds.includes(sessionId)) { + throw new WorkspaceMoveInvalidError(`cannot move session '${sessionId}' in workspace '${record.path}': the session is not accounted`); + } + if (beforeSessionId !== undefined && !record.sessionIds.includes(beforeSessionId)) { + throw new WorkspaceMoveInvalidError(`cannot move session '${sessionId}' before '${beforeSessionId}' in workspace '${record.path}': ` + + 'the anchor session is not accounted'); + } + if (beforeSessionId === sessionId) + return record; + const without = record.sessionIds.filter(id => id !== sessionId); + const at = beforeSessionId === undefined ? without.length : without.indexOf(beforeSessionId); + const sessionIds = [...without.slice(0, at), sessionId, ...without.slice(at)]; + return sessionIds.every((id, index) => id === record.sessionIds[index]) + ? record + : { ...record, sessionIds }; + }); + } + async detachSession(sessionId) { + await this.mutate(record => record.sessionIds.includes(sessionId) + ? { ...record, sessionIds: record.sessionIds.filter(id => id !== sessionId) } + : record); + } + async status() { + try { + return (await stat(this.record.path)).isDirectory() ? 'ok' : 'missing-dir'; + } + catch { + // Any stat failure (ENOENT, dangling parent, permission loss) means the + // directory is not usable right now; the record itself never mutates. + return 'missing-dir'; + } + } + /** + * The single write path: run `fn` on the domain write chain via + * `table.update`, stamping `updatedAt` and pruning candidates that no + * longer pass the id-plus-canonical-cwd membership check, then swap the + * snapshot. + * + * `fn` sees the value current at its chain slot, so membership decisions + * (attach/detach idempotence) are race-free against queued writes; a fn + * signalling no change by returning `current` verbatim aborts the slot + * through the sentinel when pruning also finds nothing, so a no-op neither + * rewrites the medium nor emits a change event. + */ + async mutate(fn) { + let next; + try { + next = await this.host.table().update(this.id, (current) => { + const changed = fn(current); + const sessionIds = changed.sessionIds.filter(id => this.host.sessionPath(id) === changed.path); + if (changed === current && sessionIds.length === current.sessionIds.length) { + throw unchangedSentinel; + } + return { ...changed, sessionIds, updatedAt: new Date().toISOString() }; + }); + } + catch (error) { + if (error === unchangedSentinel) + return; + throw error; + } + this.record = next; + } +} +//# sourceMappingURL=entity.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts new file mode 100644 index 0000000..8b389ad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts @@ -0,0 +1,163 @@ +/** + * Workspace entity registry (`ctx.workspaceRegistry`): durable workspace records, + * stable registry order, and header-validated session membership over the + * domain data form. + * @module @deepseek-ai/dsh-workspace + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +export { WorkspaceMoveInvalidError } from './entity.ts'; +import type { Workspace, WorkspaceId as WorkspaceIdBrand } from './types.ts'; +export type { Workspace } from './types.ts'; +export { workspaceDomainState, workspaceRecord, workspaceDomainSpec } from './spec.ts'; +export type { WorkspaceDomainState, WorkspaceRecord } from './spec.ts'; +export { realpathNormalize } from './paths.ts'; +/** Identifies one workspace record (see `src/types.ts` for the brand rationale). */ +export type WorkspaceId = WorkspaceIdBrand; +/** + * Brand a string as a {@link WorkspaceId}. + * @param id - Raw workspace id string. + * @returns the same string, branded at compile time. + */ +export declare function WorkspaceId(id: string): WorkspaceId; +/** + * An archiveSession request named a session neither live nor in session + * persistence — a definite miss only; storage faults propagate as themselves. + */ +export declare class WorkspaceUnknownSessionError extends Error { + readonly sessionId: SessionId; + /** + * @param sessionId - The unknown session id. + */ + constructor(sessionId: SessionId); +} +/** A workspace reorder named a source or anchor absent from the durable registry order. */ +export declare class WorkspaceOrderInvalidError extends Error { + readonly workspaceId: WorkspaceId; + /** + * @param workspaceId - Missing source or anchor id. + */ + constructor(workspaceId: WorkspaceId); +} +declare module '@deepseek-ai/cordis' { + interface Context { + workspaceRegistry: WorkspaceRegistry; + } +} +/** + * Durable workspace registry. Startup waits for `sessionPersistence`, builds + * one canonical-cwd header index, and completes the one-time history + * bootstrap before the service becomes active. The persistence dependency is + * mandatory so an unavailable peer can never be mistaken for an empty + * history and commit the initialized marker. + */ +export declare class WorkspaceRegistry extends Service { + static inject: string[]; + private table?; + private global?; + private state?; + private readonly entities; + private readonly headers; + private readonly sessionPaths; + private readonly invalidSessionPaths; + private operationTail; + private readonly host; + constructor(ctx: Context); + /** Open the domain, finish bootstrap when required, and rebuild the ordered cache. */ + protected [Service.init](): Promise; + /** + * Create or reuse a workspace for an existing directory. The path is + * canonicalized through `fs.realpath`; a nonexistent path rejects with the + * original error and a non-directory rejects. Repeated calls for the same + * canonical path return the existing entity without changing its title. + * A newly created workspace is prepended to the durable registry order. + * Different canonical paths may share a display title. + * @param path - Existing directory to own, in any path spelling. + * @param title - Display title used only when a new record is created. + * @returns the existing or newly durable workspace. + */ + create(path: string, title?: string): Promise; + /** + * Look up a workspace by id. + * @param id - Workspace id. + * @returns the workspace, or `undefined` when unknown. + */ + get(id: WorkspaceId): Workspace | undefined; + /** + * Synchronous workspace projection in durable registry order. Every + * entity's `sessionIds` getter is already filtered by the startup/live + * canonical-cwd header index; this method performs no persistence reads. + * @returns a fresh ordered array of workspace entities. + */ + list(): Workspace[]; + /** + * Delete one workspace registration while retaining its directory and every + * session log. The durable order is updated before the table deletion; a + * failed table write restores the prior order and keeps the entity + * published. Unknown ids are an idempotent no-op for domain callers. + * @param id - Workspace registration to remove. + * @returns `true` when a record was deleted, `false` when it was unknown. + */ + delete(id: WorkspaceId): Promise; + /** + * Move one workspace within the durable display order, DOM-insertBefore-like. + * With an anchor it lands before that workspace; without one it appends. + * @param id - Workspace to move. + * @param beforeId - Workspace anchor; omitted appends. + * @returns the complete committed workspace order. + */ + insertBefore(id: WorkspaceId, beforeId?: WorkspaceId): Promise; + /** + * The registry-global archive set: sessions hidden from every grouping + * surface. Archiving never touches workspace accounting — an archived + * session keeps its `sessionIds` slot so unarchiving restores its position. + * @returns the archived session ids in archive order. + */ + get archivedSessionIds(): readonly SessionId[]; + /** + * Archive one session durably. The session must exist (live or in session + * persistence); its workspace accounting — or lack of one — is irrelevant. + * An already archived id resolves without writing. + * @param sessionId - The session to archive. + * @returns resolution after durability. + */ + archiveSession(sessionId: SessionId): Promise; + /** + * Whether a session is live, header-indexed, or present in a fresh + * persistence listing. Only a definite miss returns false — a failing + * `sessionPersistence.list()` propagates so storage faults never + * masquerade as an unknown session. + */ + private sessionKnown; + /** + * Resolve by canonical directory path without creating or mutating a + * workspace. A missing path rejects during `realpath`; an existing unowned + * directory returns `undefined`. + * @param path - Existing directory path in any spelling. + * @returns the workspace owning the canonical path, when one exists. + */ + resolveByPath(path: string): Promise; + private createCanonical; + private deleteKnown; + /** + * Complete the one mutation explicitly named by durable state. Unexplained + * order/table divergence still reaches {@link validateStoredState} and + * fails loud; this path never guesses which operation created a row from its shape alone. + */ + private recoverPendingMutation; + private bootstrap; + private validateStoredState; + private rebuildEntities; + private replaceHeaderIndex; + private indexHeaders; + private indexHeader; + private indexLiveSessions; + private reportFilteredCandidates; + private readSessionHeader; + private requireTable; + private requireState; + private setState; + private enqueueOperation; +} +export default WorkspaceRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.js new file mode 100644 index 0000000..4bc255d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.js @@ -0,0 +1,600 @@ +/** + * Workspace entity registry (`ctx.workspaceRegistry`): durable workspace records, + * stable registry order, and header-validated session membership over the + * domain data form. + * @module @deepseek-ai/dsh-workspace + */ +import { randomUUID } from 'node:crypto'; +import { stat } from 'node:fs/promises'; +import { basename } from 'node:path'; +import { Service } from '@deepseek-ai/cordis'; +import { WorkspaceEntity } from "./entity.js"; +export { WorkspaceMoveInvalidError } from "./entity.js"; +import { realpathNormalize } from "./paths.js"; +import { workspaceDomainSpec } from "./spec.js"; +export { workspaceDomainState, workspaceRecord, workspaceDomainSpec } from "./spec.js"; +export { realpathNormalize } from "./paths.js"; +/** + * Brand a string as a {@link WorkspaceId}. + * @param id - Raw workspace id string. + * @returns the same string, branded at compile time. + */ +export function WorkspaceId(id) { + return id; +} +/** + * An archiveSession request named a session neither live nor in session + * persistence — a definite miss only; storage faults propagate as themselves. + */ +export class WorkspaceUnknownSessionError extends Error { + sessionId; + /** + * @param sessionId - The unknown session id. + */ + constructor(sessionId) { + super(`cannot archive session '${sessionId}': live sessions and session persistence hold no such session`); + this.sessionId = sessionId; + this.name = 'WorkspaceUnknownSessionError'; + } +} +/** A workspace reorder named a source or anchor absent from the durable registry order. */ +export class WorkspaceOrderInvalidError extends Error { + workspaceId; + /** + * @param workspaceId - Missing source or anchor id. + */ + constructor(workspaceId) { + super(`cannot reorder unknown workspace '${workspaceId}'`); + this.workspaceId = workspaceId; + this.name = 'WorkspaceOrderInvalidError'; + } +} +const sameIds = (left, right) => left.length === right.length && left.every((id, index) => id === right[index]); +const compareHeaders = (left, right) => right.createdAt - left.createdAt || String(left.id).localeCompare(String(right.id)); +/** + * Durable workspace registry. Startup waits for `sessionPersistence`, builds + * one canonical-cwd header index, and completes the one-time history + * bootstrap before the service becomes active. The persistence dependency is + * mandatory so an unavailable peer can never be mistaken for an empty + * history and commit the initialized marker. + */ +export class WorkspaceRegistry extends Service { + static inject = ['storageDomain', 'sessionPersistence']; + table; + global; + state; + entities = new Map(); + headers = new Map(); + sessionPaths = new Map(); + invalidSessionPaths = new Map(); + operationTail = Promise.resolve(); + host = { + table: () => this.requireTable(), + sessionPath: id => this.sessionPaths.get(id), + readSessionHeader: id => this.readSessionHeader(id), + rememberSessionPath: (id, path) => { + this.sessionPaths.set(id, path); + this.invalidSessionPaths.delete(id); + }, + }; + constructor(ctx) { + super(ctx, 'workspaceRegistry'); + } + /** Open the domain, finish bootstrap when required, and rebuild the ordered cache. */ + async [Service.init]() { + const domain = await this.ctx.storageDomain.open(workspaceDomainSpec); + this.ctx.effect(() => () => domain.close(), 'workspace.domainClose'); + this.table = domain.table('workspaces'); + this.global = domain.global; + this.state = domain.global.get(); + await this.recoverPendingMutation(); + this.validateStoredState(this.state); + if (!this.state.initialized) { + const headers = await this.ctx.sessionPersistence.list(); + await this.replaceHeaderIndex(headers); + await this.bootstrap(headers); + } + else if (this.table.size > 0) { + await this.replaceHeaderIndex(await this.ctx.sessionPersistence.list()); + } + await this.indexLiveSessions(); + this.validateStoredState(this.requireState()); + this.rebuildEntities(); + this.reportFilteredCandidates(); + } + /** + * Create or reuse a workspace for an existing directory. The path is + * canonicalized through `fs.realpath`; a nonexistent path rejects with the + * original error and a non-directory rejects. Repeated calls for the same + * canonical path return the existing entity without changing its title. + * A newly created workspace is prepended to the durable registry order. + * Different canonical paths may share a display title. + * @param path - Existing directory to own, in any path spelling. + * @param title - Display title used only when a new record is created. + * @returns the existing or newly durable workspace. + */ + // TODO: `title` lost its last production caller when the gateway's + // create-by-name branch was deleted + // (.agents/notes/implemented/simplification/2026-07-31-one-route-to-add-a-workspace.md); + // drop the parameter with its @param clause and the `create(path, title?)` + // lines in this package's README pair. + async create(path, title) { + const canonical = await realpathNormalize(path); + if (!(await stat(canonical)).isDirectory()) { + throw new Error(`cannot create a workspace at '${canonical}': path is not a directory`); + } + return await this.enqueueOperation(() => this.createCanonical(canonical, title)); + } + /** + * Look up a workspace by id. + * @param id - Workspace id. + * @returns the workspace, or `undefined` when unknown. + */ + get(id) { + return this.entities.get(id); + } + /** + * Synchronous workspace projection in durable registry order. Every + * entity's `sessionIds` getter is already filtered by the startup/live + * canonical-cwd header index; this method performs no persistence reads. + * @returns a fresh ordered array of workspace entities. + */ + list() { + return this.requireState().workspaceIds.map((id) => { + const entity = this.entities.get(id); + if (entity === undefined) { + throw new Error(`workspace registry order references missing workspace '${id}'`); + } + return entity; + }); + } + /** + * Delete one workspace registration while retaining its directory and every + * session log. The durable order is updated before the table deletion; a + * failed table write restores the prior order and keeps the entity + * published. Unknown ids are an idempotent no-op for domain callers. + * @param id - Workspace registration to remove. + * @returns `true` when a record was deleted, `false` when it was unknown. + */ + delete(id) { + return this.enqueueOperation(() => this.deleteKnown(id)); + } + /** + * Move one workspace within the durable display order, DOM-insertBefore-like. + * With an anchor it lands before that workspace; without one it appends. + * @param id - Workspace to move. + * @param beforeId - Workspace anchor; omitted appends. + * @returns the complete committed workspace order. + */ + insertBefore(id, beforeId) { + return this.enqueueOperation(async () => { + const state = this.requireState(); + if (!state.workspaceIds.includes(id)) + throw new WorkspaceOrderInvalidError(id); + if (beforeId !== undefined && !state.workspaceIds.includes(beforeId)) { + throw new WorkspaceOrderInvalidError(beforeId); + } + if (beforeId === id) + return state.workspaceIds; + const without = state.workspaceIds.filter(workspaceId => workspaceId !== id); + const at = beforeId === undefined ? without.length : without.indexOf(beforeId); + const workspaceIds = [...without.slice(0, at), id, ...without.slice(at)]; + if (sameIds(workspaceIds, state.workspaceIds)) + return state.workspaceIds; + await this.setState({ ...state, workspaceIds }); + return workspaceIds; + }); + } + /** + * The registry-global archive set: sessions hidden from every grouping + * surface. Archiving never touches workspace accounting — an archived + * session keeps its `sessionIds` slot so unarchiving restores its position. + * @returns the archived session ids in archive order. + */ + get archivedSessionIds() { + return this.requireState().archivedSessionIds; + } + /** + * Archive one session durably. The session must exist (live or in session + * persistence); its workspace accounting — or lack of one — is irrelevant. + * An already archived id resolves without writing. + * @param sessionId - The session to archive. + * @returns resolution after durability. + */ + archiveSession(sessionId) { + return this.enqueueOperation(async () => { + // The chain slot serializes against every other registry write, so this + // check-then-write pair cannot interleave with another archive. + if (this.requireState().archivedSessionIds.includes(sessionId)) + return; + if (!(await this.sessionKnown(sessionId))) { + throw new WorkspaceUnknownSessionError(sessionId); + } + const state = this.requireState(); + await this.setState({ ...state, archivedSessionIds: [...state.archivedSessionIds, sessionId] }); + }); + } + /** + * Whether a session is live, header-indexed, or present in a fresh + * persistence listing. Only a definite miss returns false — a failing + * `sessionPersistence.list()` propagates so storage faults never + * masquerade as an unknown session. + */ + async sessionKnown(id) { + if (this.ctx.get('sessions')?.get(id) !== undefined) + return true; + if (this.headers.has(id)) + return true; + await this.indexHeaders(await this.ctx.sessionPersistence.list()); + return this.headers.has(id); + } + /** + * Resolve by canonical directory path without creating or mutating a + * workspace. A missing path rejects during `realpath`; an existing unowned + * directory returns `undefined`. + * @param path - Existing directory path in any spelling. + * @returns the workspace owning the canonical path, when one exists. + */ + async resolveByPath(path) { + const canonical = await realpathNormalize(path); + for (const entity of this.entities.values()) { + if (entity.path === canonical) + return entity; + } + return undefined; + } + async createCanonical(canonical, title) { + for (const entity of this.entities.values()) { + if (entity.path === canonical) + return entity; + } + const workspaceName = title ?? basename(canonical); + const table = this.requireTable(); + const state = this.requireState(); + const id = WorkspaceId(randomUUID()); + const now = new Date().toISOString(); + const record = { + path: canonical, + title: workspaceName, + sessionIds: [], + createdAt: now, + updatedAt: now, + }; + const entity = new WorkspaceEntity(this.host, id, record); + this.entities.set(id, entity); + const pendingState = { + ...state, + pendingMutation: { operation: 'create', workspaceId: id }, + }; + try { + await this.setState(pendingState); + } + catch (error) { + this.entities.delete(id); + throw error; + } + try { + await table.put(id, record); + } + catch (error) { + this.entities.delete(id); + try { + await this.setState(state); + } + catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' record write and pending-marker rollback both failed`); + } + throw error; + } + try { + await this.setState({ + initialized: true, + workspaceIds: [id, ...state.workspaceIds], + archivedSessionIds: state.archivedSessionIds, + }); + } + catch (error) { + this.entities.delete(id); + try { + await table.delete(id); + } + catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' order write and record rollback both failed; the pending marker remains recoverable`); + } + try { + await this.setState(state); + } + catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' order write and pending-marker rollback both failed`); + } + throw error; + } + return entity; + } + async deleteKnown(id) { + const entity = this.entities.get(id); + if (entity === undefined) + return false; + const state = this.requireState(); + const nextState = { + initialized: true, + workspaceIds: state.workspaceIds.filter(workspaceId => workspaceId !== id), + archivedSessionIds: state.archivedSessionIds, + }; + await this.setState({ + ...nextState, + pendingMutation: { operation: 'delete', workspaceId: id }, + }); + this.entities.delete(id); + try { + await this.requireTable().delete(id); + } + catch (error) { + this.entities.set(id, entity); + try { + await this.setState(state); + } + catch (rollbackError) { + // The durable marker still says to finish deletion, so the cache must + // agree with that recoverable direction rather than republish a row + // absent from the persisted order. + this.entities.delete(id); + throw new AggregateError([error, rollbackError], `workspace '${id}' record deletion and registry-order rollback both failed`); + } + throw error; + } + try { + await this.setState(nextState); + } + catch (error) { + // The deletion committed at the table write and was already published + // to Host streams. Keep the durable marker for startup recovery rather + // than reporting failure after the requested state became true. + this.ctx.logger.warn(`workspace '${id}' was deleted but its pending marker could not be cleared: ${String(error)}`); + } + return true; + } + /** + * Complete the one mutation explicitly named by durable state. Unexplained + * order/table divergence still reaches {@link validateStoredState} and + * fails loud; this path never guesses which operation created a row from its shape alone. + */ + async recoverPendingMutation() { + const state = this.requireState(); + const pending = state.pendingMutation; + if (pending === undefined) + return; + if (state.workspaceIds.includes(pending.workspaceId)) { + throw new Error(`workspace domain is inconsistent: pending ${pending.operation} workspace ` + + `'${pending.workspaceId}' is still present in registry order`); + } + await this.requireTable().delete(pending.workspaceId); + await this.setState({ + initialized: state.initialized, + workspaceIds: state.workspaceIds, + archivedSessionIds: state.archivedSessionIds, + }); + } + async bootstrap(headers) { + const table = this.requireTable(); + const state = this.requireState(); + const groupsByPath = new Map(); + for (const header of headers) { + const path = this.sessionPaths.get(header.id); + if (path === undefined) + continue; + const group = groupsByPath.get(path); + if (group === undefined) + groupsByPath.set(path, [header]); + else + group.push(header); + } + const groups = [...groupsByPath].map(([path, groupHeaders]) => { + groupHeaders.sort(compareHeaders); + const newest = groupHeaders[0]; + return { path, headers: groupHeaders, newestAt: newest.createdAt }; + }).sort((left, right) => right.newestAt - left.newestAt || left.path.localeCompare(right.path)); + const byPath = new Map(); + const accounted = new Map(); + for (const [id, record] of table.entries()) { + byPath.set(record.path, id); + for (const sessionId of record.sessionIds) + accounted.set(sessionId, id); + } + for (const group of groups) { + let id = byPath.get(group.path); + if (id === undefined) { + const sessionIds = group.headers + .map(header => header.id) + .filter(sessionId => !accounted.has(sessionId)); + if (sessionIds.length === 0) + continue; + id = WorkspaceId(randomUUID()); + const createdAt = new Date(group.newestAt).toISOString(); + const record = { + path: group.path, + title: basename(group.path), + sessionIds, + createdAt, + updatedAt: createdAt, + }; + await table.put(id, record); + byPath.set(group.path, id); + for (const sessionId of sessionIds) + accounted.set(sessionId, id); + continue; + } + const current = table.get(id); + const historical = group.headers + .map(header => header.id) + .filter(sessionId => accounted.get(sessionId) === undefined || accounted.get(sessionId) === id); + const historicalSet = new Set(historical); + const sessionIds = [ + ...historical, + ...current.sessionIds.filter(sessionId => !historicalSet.has(sessionId)), + ]; + if (sameSessionIds(current.sessionIds, sessionIds)) + continue; + await table.update(id, record => ({ + ...record, + sessionIds, + updatedAt: new Date().toISOString(), + })); + for (const sessionId of historical) + accounted.set(sessionId, id); + } + const groupRank = new Map(groups.map(group => [group.path, group.newestAt])); + const priorRank = new Map(state.workspaceIds.map((id, index) => [id, index])); + const workspaceIds = [...table.entries()] + .sort(([leftId, left], [rightId, right]) => { + const leftTime = groupRank.get(left.path) ?? Date.parse(left.createdAt); + const rightTime = groupRank.get(right.path) ?? Date.parse(right.createdAt); + return rightTime - leftTime + || (priorRank.get(leftId) ?? Number.MAX_SAFE_INTEGER) + - (priorRank.get(rightId) ?? Number.MAX_SAFE_INTEGER) + || String(leftId).localeCompare(String(rightId)); + }) + .map(([id]) => id); + if (!sameIds(state.workspaceIds, workspaceIds)) { + await this.setState({ initialized: false, workspaceIds, archivedSessionIds: state.archivedSessionIds }); + } + await this.setState({ initialized: true, workspaceIds, archivedSessionIds: state.archivedSessionIds }); + } + validateStoredState(state) { + const table = this.requireTable(); + const order = new Set(); + for (const id of state.workspaceIds) { + if (order.has(id)) { + throw new Error(`workspace domain is inconsistent: registry order repeats workspace '${id}'`); + } + if (table.get(id) === undefined) { + throw new Error(`workspace domain is inconsistent: registry order references missing workspace '${id}'`); + } + order.add(id); + } + if (state.initialized && order.size !== table.size) { + const orphan = [...table.keys()].find(id => !order.has(id)); + throw new Error(`workspace domain is inconsistent: workspace '${orphan}' is absent from registry order`); + } + const paths = new Map(); + const accounted = new Map(); + for (const [id, record] of table.entries()) { + const pathHolder = paths.get(record.path); + if (pathHolder !== undefined) { + throw new Error(`workspace domain is inconsistent: path '${record.path}' is claimed ` + + `by both workspace '${pathHolder}' and workspace '${id}'`); + } + paths.set(record.path, id); + for (const sessionId of record.sessionIds) { + const holder = accounted.get(sessionId); + if (holder !== undefined) { + throw new Error(`workspace domain is inconsistent: session '${sessionId}' is accounted ` + + `by both workspace '${holder}' and workspace '${id}'`); + } + accounted.set(sessionId, id); + } + } + } + rebuildEntities() { + this.entities.clear(); + for (const id of this.requireState().workspaceIds) { + const record = this.requireTable().get(id); + this.entities.set(id, new WorkspaceEntity(this.host, id, record)); + } + } + async replaceHeaderIndex(headers) { + this.headers.clear(); + this.sessionPaths.clear(); + this.invalidSessionPaths.clear(); + await this.indexHeaders(headers); + } + async indexHeaders(headers) { + for (const header of headers) + await this.indexHeader(header); + } + async indexHeader(header) { + this.headers.set(header.id, header); + this.sessionPaths.delete(header.id); + if (header.cwd === undefined) { + this.invalidSessionPaths.set(header.id, 'header has no cwd'); + return; + } + try { + const path = await realpathNormalize(header.cwd); + if (!(await stat(path)).isDirectory()) { + this.invalidSessionPaths.set(header.id, `cwd '${header.cwd}' is not a directory`); + return; + } + this.sessionPaths.set(header.id, path); + this.invalidSessionPaths.delete(header.id); + } + catch { + this.invalidSessionPaths.set(header.id, `cwd '${header.cwd}' does not resolve`); + } + } + async indexLiveSessions() { + const sessions = this.ctx.get('sessions'); + if (sessions === undefined) + return; + await this.indexHeaders(sessions.list().map(session => session.header)); + } + reportFilteredCandidates() { + for (const entity of this.entities.values()) { + const record = this.requireTable().get(entity.id); + for (const sessionId of record.sessionIds) { + const path = this.sessionPaths.get(sessionId); + if (path === record.path) + continue; + const reason = this.invalidSessionPaths.get(sessionId) + ?? (this.headers.has(sessionId) + ? `canonical cwd '${path}' differs from workspace path '${record.path}'` + : 'session header is missing'); + this.ctx.logger.warn(`workspace '${entity.id}' filtered session '${sessionId}' from membership: ${reason}`); + } + } + } + async readSessionHeader(id) { + const live = this.ctx.get('sessions')?.get(id); + if (live !== undefined) { + this.headers.set(id, live.header); + return live.header; + } + const cached = this.headers.get(id); + if (cached !== undefined) + return cached; + const headers = await this.ctx.sessionPersistence.list(); + await this.indexHeaders(headers); + const header = this.headers.get(id); + if (header === undefined) { + throw new Error(`cannot validate session '${id}': session persistence holds no such session`); + } + return header; + } + requireTable() { + if (this.table === undefined) + throw new Error('workspace registry is not started yet'); + return this.table; + } + requireState() { + if (this.state === undefined) + throw new Error('workspace registry is not started yet'); + return this.state; + } + async setState(state) { + await this.global.set(state); + this.state = state; + } + enqueueOperation(operation) { + const result = this.operationTail.then(async () => { + // A committed delete may leave only its marker cleanup pending. Retry + // recovery before another create/delete can overwrite that pending operation record. + await this.recoverPendingMutation(); + return await operation(); + }); + this.operationTail = result.then(() => { }, () => { }); + return result; + } +} +const sameSessionIds = (left, right) => left.length === right.length && left.every((id, index) => id === right[index]); +export default WorkspaceRegistry; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.d.ts new file mode 100644 index 0000000..528291e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-workspace`. + * @module @deepseek-ai/dsh-workspace/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "workspace-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.js new file mode 100644 index 0000000..47f0d36 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.js @@ -0,0 +1,43 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-workspace`. + * @module @deepseek-ai/dsh-workspace/invariant + */ +import { WorkspaceId } from '@deepseek-ai/dsh-workspace'; +const PACKAGE_NAME = '@deepseek-ai/dsh-workspace'; +/** Cordis companion plugin name. */ +export const name = 'workspace-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * Owned relationship: the registry's entity cache mirrors the workspace + * domain's durable table. Every `domain/changed` for the `workspaces` table + * must name a record the cache already holds an entity for (the registry + * caches before the durable put and mutates only through cached entities). + * A delete is valid only after the registry has removed the entity from its + * cache, whether for create rollback or an explicit registration deletion; + * deleting while the cache still publishes the entity proves a bypass. + */ +const install = Object.assign((ctx, fail) => { + ctx.on('domain/changed', (change) => { + if (change.domain !== 'workspace' || change.table !== 'workspaces') + return; + if (change.operation === 'deleted') { + if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) !== undefined) { + fail(`workspace record '${change.key}' was deleted while the registry cache still ` + + 'publishes it — some write path bypassed ctx.workspaceRegistry'); + } + return; + } + if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) === undefined) { + fail(`workspace record '${change.key}' landed durably but the registry cache holds ` + + 'no entity for it — the cache and the domain table have diverged'); + } + }); +}, { inject: ['workspaceRegistry'] }); +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.d.ts new file mode 100644 index 0000000..a0b2ed5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.d.ts @@ -0,0 +1,18 @@ +/** + * Path canonicalization for workspace identity. + * @module @deepseek-ai/dsh-workspace/src/paths + */ +/** + * Canonicalize a directory path via `fs.realpath`: trailing slashes, `..` + * segments, and symlinks are all resolved. This is the ONE uniqueness canon of + * the package — workspace paths are stored canonicalized, uniqueness is + * string equality of canonicalized paths (a symlink to an existing + * workspace's directory collides), and attach-time session `cwd` checks go + * through the same canon. A path that does not exist rejects with the + * original `ENOENT` — this is `create`'s reject path (a workspace must point + * at an existing directory). + * @param path - The path to canonicalize. + * @returns the canonical absolute path. + */ +export declare function realpathNormalize(path: string): Promise; +//# sourceMappingURL=paths.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.js new file mode 100644 index 0000000..0209f6a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.js @@ -0,0 +1,21 @@ +/** + * Path canonicalization for workspace identity. + * @module @deepseek-ai/dsh-workspace/src/paths + */ +import { realpath } from 'node:fs/promises'; +/** + * Canonicalize a directory path via `fs.realpath`: trailing slashes, `..` + * segments, and symlinks are all resolved. This is the ONE uniqueness canon of + * the package — workspace paths are stored canonicalized, uniqueness is + * string equality of canonicalized paths (a symlink to an existing + * workspace's directory collides), and attach-time session `cwd` checks go + * through the same canon. A path that does not exist rejects with the + * original `ENOENT` — this is `create`'s reject path (a workspace must point + * at an existing directory). + * @param path - The path to canonicalize. + * @returns the canonical absolute path. + */ +export async function realpathNormalize(path) { + return await realpath(path); +} +//# sourceMappingURL=paths.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.d.ts new file mode 100644 index 0000000..65a053a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.d.ts @@ -0,0 +1,85 @@ +/** + * The workspace domain declaration: record schema and the `defineDomain` spec + * the registry opens. The zod schema is the durable-boundary validator today + * and the direct source of the RPC wire projection in a later phase. + * @module @deepseek-ai/dsh-workspace/src/spec + */ +import { z } from 'zod'; +import { SessionId } from '@deepseek-ai/dsh-session'; +import type { WorkspaceId } from './types.ts'; +/** + * Durable shape of one workspace record. `path` is the `fs.realpath` canon + * stamped at create; `sessionIds` is the ordered ownership account (array + * order is display order); timestamps are ISO-8601 strings. + */ +export declare const workspaceRecord: z.ZodObject<{ + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; +}, z.core.$strip>; +/** One stored workspace record, inferred from {@link workspaceRecord}. */ +export type WorkspaceRecord = z.infer; +/** + * Durable registry state. `initialized` distinguishes a valid empty registry + * from one that still needs the header-only history bootstrap; + * `workspaceIds` is the authoritative display order. `archivedSessionIds` is + * the registry-global archive set layered over workspace accounting: an + * archived session keeps its `sessionIds` slot (unarchiving must restore the + * position), so the set never participates in the one-owner accounting + * invariant. Defaulted so records written before the field parse unchanged. + */ +export declare const workspaceDomainState: z.ZodObject<{ + initialized: z.ZodBoolean; + workspaceIds: z.ZodArray>>; + archivedSessionIds: z.ZodDefault>>>; + pendingMutation: z.ZodOptional; + workspaceId: z.ZodPipe>; + }, z.core.$strip>, z.ZodObject<{ + operation: z.ZodLiteral<"delete">; + workspaceId: z.ZodPipe>; + }, z.core.$strip>], "operation">>; +}, z.core.$strip>; +/** Durable registry state inferred from {@link workspaceDomainState}. */ +export type WorkspaceDomainState = z.infer; +/** + * The workspace domain spec: one `workspaces` table keyed by + * {@link WorkspaceId} plus the bootstrap/order singleton. The registry opens + * this through `ctx.storage.domain`; the spec object is the single source of + * the domain's identity, version, and schemas. + */ +export declare const workspaceDomainSpec: { + name: string; + version: number; + global: { + schema: z.ZodObject<{ + initialized: z.ZodBoolean; + workspaceIds: z.ZodArray>>; + archivedSessionIds: z.ZodDefault>>>; + pendingMutation: z.ZodOptional; + workspaceId: z.ZodPipe>; + }, z.core.$strip>, z.ZodObject<{ + operation: z.ZodLiteral<"delete">; + workspaceId: z.ZodPipe>; + }, z.core.$strip>], "operation">>; + }, z.core.$strip>; + initial: { + initialized: boolean; + workspaceIds: never[]; + archivedSessionIds: never[]; + }; + }; + tables: { + workspaces: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec; + }; +}; +//# sourceMappingURL=spec.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.js new file mode 100644 index 0000000..39f707f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.js @@ -0,0 +1,63 @@ +/** + * The workspace domain declaration: record schema and the `defineDomain` spec + * the registry opens. The zod schema is the durable-boundary validator today + * and the direct source of the RPC wire projection in a later phase. + * @module @deepseek-ai/dsh-workspace/src/spec + */ +import { z } from 'zod'; +import { SessionId } from '@deepseek-ai/dsh-session'; +import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'; +/** Workspace id schema at the durable boundary; branding has no runtime representation. */ +const workspaceId = z.string().transform(value => value); +/** + * Durable shape of one workspace record. `path` is the `fs.realpath` canon + * stamped at create; `sessionIds` is the ordered ownership account (array + * order is display order); timestamps are ISO-8601 strings. + */ +export const workspaceRecord = z.object({ + path: z.string(), + title: z.string(), + sessionIds: z.array(z.string().transform(SessionId)), + createdAt: z.string(), + updatedAt: z.string(), +}); +/** + * Recoverable two-write mutation marker. The marker is persisted before the + * record/order pair can diverge, so startup can distinguish an interrupted + * registry operation from unexplained medium corruption. + */ +const workspacePendingMutation = z.discriminatedUnion('operation', [ + z.object({ operation: z.literal('create'), workspaceId }), + z.object({ operation: z.literal('delete'), workspaceId }), +]); +/** + * Durable registry state. `initialized` distinguishes a valid empty registry + * from one that still needs the header-only history bootstrap; + * `workspaceIds` is the authoritative display order. `archivedSessionIds` is + * the registry-global archive set layered over workspace accounting: an + * archived session keeps its `sessionIds` slot (unarchiving must restore the + * position), so the set never participates in the one-owner accounting + * invariant. Defaulted so records written before the field parse unchanged. + */ +export const workspaceDomainState = z.object({ + initialized: z.boolean(), + workspaceIds: z.array(workspaceId), + archivedSessionIds: z.array(z.string().transform(SessionId)).default([]), + pendingMutation: workspacePendingMutation.optional(), +}); +/** + * The workspace domain spec: one `workspaces` table keyed by + * {@link WorkspaceId} plus the bootstrap/order singleton. The registry opens + * this through `ctx.storage.domain`; the spec object is the single source of + * the domain's identity, version, and schemas. + */ +export const workspaceDomainSpec = defineDomain({ + name: 'workspace', + version: 2, + global: { + schema: workspaceDomainState, + initial: { initialized: false, workspaceIds: [], archivedSessionIds: [] }, + }, + tables: { workspaces: domainTable(workspaceRecord) }, +}); +//# sourceMappingURL=spec.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.d.ts new file mode 100644 index 0000000..a1f63c8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.d.ts @@ -0,0 +1,92 @@ +/** + * Public type vocabulary of the workspace entity: the `WorkspaceId` brand and + * the `Workspace` consumer interface. Types only — the `WorkspaceId` factory + * lives in `index.ts` (this file carries no runtime code). + * @module @deepseek-ai/dsh-workspace/src/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +/** + * Identifies one workspace record. A generated uuid, never the path: path + * normalization rewrites paths, and a reference anchor must stay stable. + */ +export type WorkspaceId = Branded<'WorkspaceId'>; +/** + * One workspace: a stable id over an existing directory, a display title, and + * an ordered candidate account of sessions. Membership requires both an id in + * that account and a session header whose canonical cwd equals the workspace + * path. Consumers only see this interface; the implementation stays private. + */ +export interface Workspace { + /** Stable record id (generated uuid). */ + readonly id: WorkspaceId; + /** + * Canonical directory path: the `fs.realpath` of the path given at create + * time (trailing slashes, `..`, and symlinks all resolved). Never rewritten + * afterwards, even when the directory disappears (see {@link status}). + */ + readonly path: string; + /** Display title. Defaults to `basename(path)` at create; duplicates are allowed. */ + readonly title: string; + /** ISO-8601 creation instant, stamped at create and never rewritten. */ + readonly createdAt: string; + /** ISO-8601 instant of the last durable mutation (create counts as one). */ + readonly updatedAt: string; + /** + * Header-validated sessions in manually owned order: a new session is + * prepended at attach, explicit reordering goes through + * `insertSessionBefore`, and activity never reorders. The durable candidate + * account is filtered synchronously: missing headers, invalid cwd values, + * and canonical cwd mismatches are never returned. A subsequent workspace + * mutation prunes those filtered candidates durably. + */ + readonly sessionIds: readonly SessionId[]; + /** + * Replace the display title durably. + * @param title - New title; any string, duplicates across workspaces allowed. + * @returns resolution after durability. + */ + setTitle(title: string): Promise; + /** + * Prepend a session to this workspace's candidate account. An already + * accounted id resolves without writing, aside from the durable + * filtered-candidate prune every accepted mutation performs. A new id's + * live or persisted + * header cwd must resolve to an existing directory equal to {@link path}; + * unknown ids, missing or invalid cwd values, and mismatches reject without + * writing. + * @param sessionId - The session to record. + * @returns resolution after durability. + */ + attachSession(sessionId: SessionId): Promise; + /** + * Move an accounted session within the manual order, DOM-insertBefore-like: + * with an anchor the session lands before it, without one it appends to the + * end. Only the moved id changes position. A session or anchor absent from + * the account rejects without writing; a move to the current position + * resolves without writing, aside from the durable filtered-candidate + * prune every accepted mutation performs; decided on the domain write + * chain. + * @param sessionId - The accounted session to move. + * @param beforeSessionId - Accounted anchor to insert before; omitted appends. + * @returns resolution after durability. + */ + insertSessionBefore(sessionId: SessionId, beforeSessionId?: SessionId): Promise; + /** + * Remove a session from this workspace's account. Idempotent: an id not on + * the account resolves without writing, aside from the durable + * filtered-candidate prune every accepted mutation performs; decided on + * the domain write chain like attach. Never touches the session's own stored log. + * @param sessionId - The session to remove. + * @returns resolution after durability. + */ + detachSession(sessionId: SessionId): Promise; + /** + * Live directory check, uncached: whether {@link path} currently exists and + * is a directory. A missing directory never mutates the record — the + * directory may only be temporarily moved. + * @returns `'ok'` when the directory exists, `'missing-dir'` otherwise. + */ + status(): Promise<'ok' | 'missing-dir'>; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.js new file mode 100644 index 0000000..1777ef5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.js @@ -0,0 +1,8 @@ +/** + * Public type vocabulary of the workspace entity: the `WorkspaceId` brand and + * the `Workspace` consumer interface. Types only — the `WorkspaceId` factory + * lives in `index.ts` (this file carries no runtime code). + * @module @deepseek-ai/dsh-workspace/src/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/package.json new file mode 100644 index 0000000..482a6ae --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/@deepseek-ai/dsh-workspace/package.json @@ -0,0 +1,60 @@ +{ + "name": "@deepseek-ai/dsh-workspace", + "description": "Workspace entity registry (ctx.workspaceRegistry): durable workspace records with validated session attachment over the domain data form for the DeepSeek Harness", + "version": "0.1.0-rc.6", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/workspace/workspace" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + }, + "dependencies": { + "zod": "^4.4.3" + }, + "devDependencies": { + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.6", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session": "^0.1.0-rc.6", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.6", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.6_1cc52dfbc7fc17aad1b6b9c3711f64fc/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..1e1f040 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..0773c4e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..982b6de --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..792c72b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..5362978 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-storage b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-storage new file mode 120000 index 0000000..c3ed99b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-storage @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-storage-domain b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-storage-domain new file mode 120000 index 0000000..f157433 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-storage-domain @@ -0,0 +1 @@ +../../../@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/LICENSE new file mode 100644 index 0000000..c1f7a78 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DeepSeek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.i18n.yaml b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.i18n.yaml new file mode 100644 index 0000000..20f5d3b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/workspace/workspace/README.md +README.md: c1c4309efdc85f4bc7a6b0f128df6d9f4f810ae1 +README.zh.md: f44ad04be0c63061200a256c5ce8cb24a4d3c54b diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.md new file mode 100644 index 0000000..c1c4309 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.md @@ -0,0 +1,44 @@ +# @deepseek-ai/dsh-workspace + +English | [中文](README.zh.md) + +Workspace entity registry (`ctx.workspaceRegistry`) for the DeepSeek Harness: durable workspace records, stable workspace order, and a newest-first candidate session index stored through the domain data form. Consumers see the `Workspace` interface; the entity implementation stays package-private. + +The entity/storage rationale lives in the [domain Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md); header-only bootstrap and GUI ordering live in the [Workspace UI product-flow Agent Note](../../../.agents/notes/implemented/feature/2026-07-25-workspace-ui-product-flow.md). + +## Shape + +- `ctx.workspaceRegistry.create(path, title?)` — canonicalizes `path` via `fs.realpath`, rejects a nonexistent or non-directory path, creates at most one record per canonical path, and prepends a new record to durable workspace order. Repeated calls for that path return the existing workspace without changing its title; different paths may share a display title. +- `ctx.workspaceRegistry.get(id)` / `list()` / `resolveByPath(path)` — cache-served lookups. `list()` is synchronous and follows durable registry order; `resolveByPath` is async because it applies the same `realpath` canon and rejects a missing path rather than creating it. +- `ctx.workspaceRegistry.insertBefore(id, before?)` — moves a registered Workspace within durable registry order, DOM-insertBefore-like: before the anchor, or appended when the anchor is omitted. A source or anchor absent from the registry rejects without writing; a self-anchor or move to the current position resolves without writing. The returned id list is the complete committed order. +- `ctx.workspaceRegistry.delete(id)` — removes only the Workspace registration, its durable order entry, and its session account. Unknown ids return `false`; a removed record returns `true`. The directory, user files, live Sessions, and persisted session logs are never touched, so those Sessions become Ungrouped. A table-write failure restores the prior order and published entity. +- `Workspace.attachSession(id)` — validates a live or persisted session header cwd against the workspace path and prepends a new id. Unknown sessions, absent/unresolvable/non-directory cwd values, and mismatches reject without writing. `detachSession` removes only the candidate index entry. +- `Workspace.insertSessionBefore(id, before?)` — moves an accounted session within the manual order, DOM-insertBefore-like: before the anchor, or appended when the anchor is omitted. A session or anchor absent from the account rejects without writing; a move to the current position resolves without writing. Registry Workspace order never changes. +- `ctx.workspaceRegistry.archiveSession(id)` / `archivedSessionIds` — the registry-global archive set, layered over workspace accounting: an archived session disappears from grouping surfaces but keeps its session log and its `sessionIds` slot, so a future unarchive restores its position. Archiving accepts any live or persisted session (accounted or Ungrouped), resolves without writing for an already archived id, and rejects an unknown id. State written before the field existed parses with an empty set. +- `Workspace.sessionIds` — synchronous id-plus-canonical-cwd membership projection in durable candidate order. Missing headers, invalid cwd values, and mismatches are filtered; the next workspace mutation prunes them. A medium indexing one session under two workspaces, claiming one path from two records, or diverging from durable workspace order rejects at startup. +- `Workspace.status()` — uncached directory check, `'ok' | 'missing-dir'`; a missing directory never mutates the record. + +`storageDomain` and `sessionPersistence` are required startup dependencies. An unavailable peer leaves the plugin pending and cannot commit an empty initialized marker. On the first successful start, the registry calls `SessionPersistence.list()` and uses only header `id`, `cwd`, and `createdAt` to group valid historical directories and persist initial order; it never reads event bodies. The initialized marker is written last, so partial bootstrap writes are reused safely after restart. Later cwd-only sessions remain Ungrouped. + +Create and delete persist an explicit pending-mutation marker before their record and order can diverge. Startup completes only the marked mutation, then clears the marker; an unmarked order/table mismatch remains unexplained corruption and fails loud. Deleting and re-registering the same path creates a fresh Workspace id and does not automatically re-adopt the retained Sessions. + +## Model Experience + +### Workspace records and session accounts + +#### What the model sees + +Nothing. `ctx.workspaceRegistry` serves workspace records to host-side consumers only: the package registers no tools, injects no prompts, and writes no session events, so no request field ever carries this package's data. + +#### Token effect + +Zero direct tokens on every request. + +#### KV Cache effect + +Independent of live requests: the package never touches a request prefix, so it cannot invalidate provider cache reuse. + +## Known Limitations and Deferred Work + +- Session deletion and destructive folder removal are separate, absent capabilities; Workspace registration deletion never substitutes for either ([decision](../../../.agents/notes/implemented/feature/2026-07-27-workspace-registration-deletion.md)). +- The header index refreshes at startup and when attach must resolve an uncached persisted id; deletion or cwd damage performed by another process is observed after the next refresh or restart. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.zh.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.zh.md new file mode 100644 index 0000000..f44ad04 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/README.zh.md @@ -0,0 +1,44 @@ +# @deepseek-ai/dsh-workspace + +[English](README.md) | 中文 + +DeepSeek Harness 的 Workspace 实体注册表(`ctx.workspaceRegistry`):通过领域数据形式存储持久 workspace 记录、稳定 workspace 顺序和按新到旧排列的候选会话索引。消费方看到 `Workspace` 接口;实体实现保持包私有。 + +实体/存储理由见[领域 Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md);仅使用头部的引导初始化和 GUI 排序见 [Workspace UI 产品流 Agent Note](../../../.agents/notes/implemented/feature/2026-07-25-workspace-ui-product-flow.md)。 + +## 结构 + +- `ctx.workspaceRegistry.create(path, title?)`:规范化 `path` 时使用 `fs.realpath`,拒绝不存在或非目录的路径,每个规范路径最多创建一条记录,并将新记录前置到持久 workspace 顺序。对同一路径重复调用会返回现有 workspace,且不改变其标题;不同路径可以共用显示标题。 +- `ctx.workspaceRegistry.get(id)`/`list()`/`resolveByPath(path)`:由缓存提供的查找。`list()` 为同步操作,并遵循持久注册表顺序;`resolveByPath` 为异步操作,因为它采用相同的 `realpath` 规范化方式,并会拒绝缺失路径,而不是创建路径。 +- `ctx.workspaceRegistry.insertBefore(id, before?)`:在持久注册表顺序内移动一个已注册 Workspace,语义类似 DOM 的 insertBefore:插到锚点之前,省略锚点则追加到末尾。来源或锚点不在注册表中时拒绝且不写入;以自身为锚点或移动到当前位置时直接完成且不写入。返回的 id 列表是完整的已提交顺序。 +- `ctx.workspaceRegistry.delete(id)`:只移除 Workspace 注册记录、对应的持久顺序条目及会话归属记录。未知 id 返回 `false`,成功移除记录则返回 `true`。目录、用户文件、活跃会话和持久化会话日志绝不受影响,因此相关会话会进入 Ungrouped。表写入失败时会恢复原顺序和此前发布的实体。 +- `Workspace.attachSession(id)`:对照 workspace 路径验证实时或已持久化的会话头 cwd,并将新 id 前置。未知会话、缺失/无法解析/非目录的 cwd 值和不匹配情况都会在不写入的前提下被拒绝。`detachSession` 只移除候选索引条目。 +- `Workspace.insertSessionBefore(id, before?)`:在手动顺序内移动一个已记账的会话,语义类似 DOM 的 insertBefore:插到锚点之前,省略锚点则追加到末尾。会话或锚点不在记账中时拒绝且不写入;移动到当前位置时直接完成且不写入。注册表中的 Workspace 顺序绝不改变。 +- `ctx.workspaceRegistry.archiveSession(id)`/`archivedSessionIds`:覆盖在 workspace 记账之上的注册表级全局归档集合:被归档的会话从各分组视图中消失,但其会话日志和 `sessionIds` 席位保持不变,未来取消归档时可恢复原位置。归档接受任何实时或已持久化的会话(无论已记账还是 Ungrouped),对已归档的 id 直接完成而不写入,并拒绝未知 id。在该字段出现之前写入的状态解析为一个空集合。 +- `Workspace.sessionIds`:按持久候选顺序提供同步 id 加规范 cwd 成员投影。缺失头部、无效 cwd 值和不匹配情况都被过滤;下一次 workspace 变更会剪除它们。如果同一存储介质将一个会话索引到两个 workspace 下、用两条记录声明同一路径,或偏离持久 workspace 顺序,启动会被拒绝。 +- `Workspace.status()`:未缓存的目录检查,返回 `'ok' | 'missing-dir'`;目录缺失绝不会改动记录。 + +`storageDomain` 和 `sessionPersistence` 是启动必需依赖。任一依赖服务不可用时,插件保持待处理,且不能提交空的已初始化标记。首次成功启动时,注册表调用 `SessionPersistence.list()`,仅使用头部 `id`、`cwd` 和 `createdAt` 对有效历史目录分组并持久化初始顺序;它绝不读取事件正文。已初始化标记最后写入,因此重启后可安全复用引导初始化期间的部分写入。后续仅能通过 cwd 识别的会话仍属于 Ungrouped。 + +创建和删除操作会在记录和顺序可能分叉之前,先持久化明确的待处理变更标记。启动时只补全该标记所指明的变更,随后清除标记;没有标记的顺序/表不一致仍属于来源不明的损坏,并会明确报错。删除后重新注册同一路径会生成新的 Workspace id,且不会自动重新接纳保留下来的会话。 + +## 模型体验 + +### Workspace 记录与会话记账 + +#### 模型看到的内容 + +没有。`ctx.workspaceRegistry` 只向宿主侧消费方提供 workspace 记录:此包不注册工具、不注入提示词、不写入会话事件,因此没有请求字段会携带此包数据。 + +#### Token 影响 + +每个请求的直接 token 为零。 + +#### KV Cache 影响 + +与实时请求无关:此包绝不触及请求前缀,因此不会使提供方缓存复用失效。 + +## 已知限制与暂缓事项 + +- 会话删除与破坏性的文件夹移除是彼此独立且尚未提供的功能;删除 Workspace 注册记录绝不能替代二者(参见[决策记录](../../../.agents/notes/implemented/feature/2026-07-27-workspace-registration-deletion.md))。 +- 头部索引会在启动时刷新,也会在 attach 必须解析未缓存持久 id 时刷新;另一进程执行的删除或造成的 cwd 损坏会在下次刷新或重启后被发现。 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/index.js new file mode 100644 index 0000000..b9d5a8e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/index.js @@ -0,0 +1,757 @@ +import { randomUUID } from "node:crypto"; +import { realpath, stat } from "node:fs/promises"; +import { basename } from "node:path"; +import { Service } from "@deepseek-ai/cordis"; +import { z } from "zod"; +import { SessionId } from "@deepseek-ai/dsh-session"; +import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain"; +//#region lib/types/paths.js +/** +* Path canonicalization for workspace identity. +* @module @deepseek-ai/dsh-workspace/src/paths +*/ +/** +* Canonicalize a directory path via `fs.realpath`: trailing slashes, `..` +* segments, and symlinks are all resolved. This is the ONE uniqueness canon of +* the package — workspace paths are stored canonicalized, uniqueness is +* string equality of canonicalized paths (a symlink to an existing +* workspace's directory collides), and attach-time session `cwd` checks go +* through the same canon. A path that does not exist rejects with the +* original `ENOENT` — this is `create`'s reject path (a workspace must point +* at an existing directory). +* @param path - The path to canonicalize. +* @returns the canonical absolute path. +*/ +async function realpathNormalize(path) { + return await realpath(path); +} +//#endregion +//#region lib/types/entity.js +/** +* Package-private workspace entity: the single {@link Workspace} +* implementation. Holds a record snapshot that is swapped in place after each +* durable mutation; every write funnels through the private `mutate` so +* `updatedAt` stamping and invalid-account pruning happen exactly once. +* Not re-exported from the package entrypoint — consumers see only the +* `Workspace` interface. +* @module @deepseek-ai/dsh-workspace/src/entity +*/ +/** An insertSessionBefore request named a session or anchor not on the account (storage failures stay plain errors). */ +var WorkspaceMoveInvalidError = class extends Error { + /** + * @param message - Which id was unaccounted and where. + */ + constructor(message) { + super(message); + this.name = "WorkspaceMoveInvalidError"; + } +}; +/** Chain-slot abort sentinel thrown by the update fn when the record needs no change; only `mutate` observes it. */ +const unchangedSentinel = /* @__PURE__ */ new Error("workspace record unchanged (internal sentinel)"); +/** The single {@link Workspace} implementation; constructed only by the registry. */ +var WorkspaceEntity = class { + host; + id; + record; + /** + * @param host - Registry-owned table, session-path index, and header reads. + * @param id - The record's stable id. + * @param record - The validated record snapshot loaded or just written. + */ + constructor(host, id, record) { + this.host = host; + this.id = id; + this.record = record; + } + get path() { + return this.record.path; + } + get title() { + return this.record.title; + } + get createdAt() { + return this.record.createdAt; + } + get updatedAt() { + return this.record.updatedAt; + } + get sessionIds() { + return this.record.sessionIds.filter((id) => this.host.sessionPath(id) === this.record.path); + } + async setTitle(title) { + await this.mutate((record) => ({ + ...record, + title + })); + } + async attachSession(sessionId) { + if (!this.record.sessionIds.includes(sessionId)) { + const header = await this.host.readSessionHeader(sessionId); + if (header.cwd === void 0) throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': its stored header carries no cwd to validate against`); + let cwd; + try { + cwd = await realpathNormalize(header.cwd); + } catch (error) { + throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': its cwd '${header.cwd}' does not resolve, so it cannot be validated`, { cause: error }); + } + if (!(await stat(cwd)).isDirectory()) throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': its cwd '${header.cwd}' is not a directory`); + if (cwd !== this.record.path) throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': its cwd resolves to '${cwd}'`); + this.host.rememberSessionPath(sessionId, cwd); + } + await this.mutate((record) => record.sessionIds.includes(sessionId) ? record : { + ...record, + sessionIds: [sessionId, ...record.sessionIds] + }); + } + async insertSessionBefore(sessionId, beforeSessionId) { + await this.mutate((record) => { + if (!record.sessionIds.includes(sessionId)) throw new WorkspaceMoveInvalidError(`cannot move session '${sessionId}' in workspace '${record.path}': the session is not accounted`); + if (beforeSessionId !== void 0 && !record.sessionIds.includes(beforeSessionId)) throw new WorkspaceMoveInvalidError(`cannot move session '${sessionId}' before '${beforeSessionId}' in workspace '${record.path}': the anchor session is not accounted`); + if (beforeSessionId === sessionId) return record; + const without = record.sessionIds.filter((id) => id !== sessionId); + const at = beforeSessionId === void 0 ? without.length : without.indexOf(beforeSessionId); + const sessionIds = [ + ...without.slice(0, at), + sessionId, + ...without.slice(at) + ]; + return sessionIds.every((id, index) => id === record.sessionIds[index]) ? record : { + ...record, + sessionIds + }; + }); + } + async detachSession(sessionId) { + await this.mutate((record) => record.sessionIds.includes(sessionId) ? { + ...record, + sessionIds: record.sessionIds.filter((id) => id !== sessionId) + } : record); + } + async status() { + try { + return (await stat(this.record.path)).isDirectory() ? "ok" : "missing-dir"; + } catch { + return "missing-dir"; + } + } + /** + * The single write path: run `fn` on the domain write chain via + * `table.update`, stamping `updatedAt` and pruning candidates that no + * longer pass the id-plus-canonical-cwd membership check, then swap the + * snapshot. + * + * `fn` sees the value current at its chain slot, so membership decisions + * (attach/detach idempotence) are race-free against queued writes; a fn + * signalling no change by returning `current` verbatim aborts the slot + * through the sentinel when pruning also finds nothing, so a no-op neither + * rewrites the medium nor emits a change event. + */ + async mutate(fn) { + let next; + try { + next = await this.host.table().update(this.id, (current) => { + const changed = fn(current); + const sessionIds = changed.sessionIds.filter((id) => this.host.sessionPath(id) === changed.path); + if (changed === current && sessionIds.length === current.sessionIds.length) throw unchangedSentinel; + return { + ...changed, + sessionIds, + updatedAt: (/* @__PURE__ */ new Date()).toISOString() + }; + }); + } catch (error) { + if (error === unchangedSentinel) return; + throw error; + } + this.record = next; + } +}; +//#endregion +//#region lib/types/spec.js +/** +* The workspace domain declaration: record schema and the `defineDomain` spec +* the registry opens. The zod schema is the durable-boundary validator today +* and the direct source of the RPC wire projection in a later phase. +* @module @deepseek-ai/dsh-workspace/src/spec +*/ +/** Workspace id schema at the durable boundary; branding has no runtime representation. */ +const workspaceId = z.string().transform((value) => value); +/** +* Durable shape of one workspace record. `path` is the `fs.realpath` canon +* stamped at create; `sessionIds` is the ordered ownership account (array +* order is display order); timestamps are ISO-8601 strings. +*/ +const workspaceRecord = z.object({ + path: z.string(), + title: z.string(), + sessionIds: z.array(z.string().transform(SessionId)), + createdAt: z.string(), + updatedAt: z.string() +}); +/** +* Recoverable two-write mutation marker. The marker is persisted before the +* record/order pair can diverge, so startup can distinguish an interrupted +* registry operation from unexplained medium corruption. +*/ +const workspacePendingMutation = z.discriminatedUnion("operation", [z.object({ + operation: z.literal("create"), + workspaceId +}), z.object({ + operation: z.literal("delete"), + workspaceId +})]); +/** +* Durable registry state. `initialized` distinguishes a valid empty registry +* from one that still needs the header-only history bootstrap; +* `workspaceIds` is the authoritative display order. `archivedSessionIds` is +* the registry-global archive set layered over workspace accounting: an +* archived session keeps its `sessionIds` slot (unarchiving must restore the +* position), so the set never participates in the one-owner accounting +* invariant. Defaulted so records written before the field parse unchanged. +*/ +const workspaceDomainState = z.object({ + initialized: z.boolean(), + workspaceIds: z.array(workspaceId), + archivedSessionIds: z.array(z.string().transform(SessionId)).default([]), + pendingMutation: workspacePendingMutation.optional() +}); +/** +* The workspace domain spec: one `workspaces` table keyed by +* {@link WorkspaceId} plus the bootstrap/order singleton. The registry opens +* this through `ctx.storage.domain`; the spec object is the single source of +* the domain's identity, version, and schemas. +*/ +const workspaceDomainSpec = defineDomain({ + name: "workspace", + version: 2, + global: { + schema: workspaceDomainState, + initial: { + initialized: false, + workspaceIds: [], + archivedSessionIds: [] + } + }, + tables: { workspaces: domainTable(workspaceRecord) } +}); +//#endregion +//#region lib/types/index.js +/** +* Workspace entity registry (`ctx.workspaceRegistry`): durable workspace records, +* stable registry order, and header-validated session membership over the +* domain data form. +* @module @deepseek-ai/dsh-workspace +*/ +/** +* Brand a string as a {@link WorkspaceId}. +* @param id - Raw workspace id string. +* @returns the same string, branded at compile time. +*/ +function WorkspaceId(id) { + return id; +} +/** +* An archiveSession request named a session neither live nor in session +* persistence — a definite miss only; storage faults propagate as themselves. +*/ +var WorkspaceUnknownSessionError = class extends Error { + sessionId; + /** + * @param sessionId - The unknown session id. + */ + constructor(sessionId) { + super(`cannot archive session '${sessionId}': live sessions and session persistence hold no such session`); + this.sessionId = sessionId; + this.name = "WorkspaceUnknownSessionError"; + } +}; +/** A workspace reorder named a source or anchor absent from the durable registry order. */ +var WorkspaceOrderInvalidError = class extends Error { + workspaceId; + /** + * @param workspaceId - Missing source or anchor id. + */ + constructor(workspaceId) { + super(`cannot reorder unknown workspace '${workspaceId}'`); + this.workspaceId = workspaceId; + this.name = "WorkspaceOrderInvalidError"; + } +}; +const sameIds = (left, right) => left.length === right.length && left.every((id, index) => id === right[index]); +const compareHeaders = (left, right) => right.createdAt - left.createdAt || String(left.id).localeCompare(String(right.id)); +/** +* Durable workspace registry. Startup waits for `sessionPersistence`, builds +* one canonical-cwd header index, and completes the one-time history +* bootstrap before the service becomes active. The persistence dependency is +* mandatory so an unavailable peer can never be mistaken for an empty +* history and commit the initialized marker. +*/ +var WorkspaceRegistry = class extends Service { + static inject = ["storageDomain", "sessionPersistence"]; + table; + global; + state; + entities = /* @__PURE__ */ new Map(); + headers = /* @__PURE__ */ new Map(); + sessionPaths = /* @__PURE__ */ new Map(); + invalidSessionPaths = /* @__PURE__ */ new Map(); + operationTail = Promise.resolve(); + host = { + table: () => this.requireTable(), + sessionPath: (id) => this.sessionPaths.get(id), + readSessionHeader: (id) => this.readSessionHeader(id), + rememberSessionPath: (id, path) => { + this.sessionPaths.set(id, path); + this.invalidSessionPaths.delete(id); + } + }; + constructor(ctx) { + super(ctx, "workspaceRegistry"); + } + /** Open the domain, finish bootstrap when required, and rebuild the ordered cache. */ + async [Service.init]() { + const domain = await this.ctx.storageDomain.open(workspaceDomainSpec); + this.ctx.effect(() => () => domain.close(), "workspace.domainClose"); + this.table = domain.table("workspaces"); + this.global = domain.global; + this.state = domain.global.get(); + await this.recoverPendingMutation(); + this.validateStoredState(this.state); + if (!this.state.initialized) { + const headers = await this.ctx.sessionPersistence.list(); + await this.replaceHeaderIndex(headers); + await this.bootstrap(headers); + } else if (this.table.size > 0) await this.replaceHeaderIndex(await this.ctx.sessionPersistence.list()); + await this.indexLiveSessions(); + this.validateStoredState(this.requireState()); + this.rebuildEntities(); + this.reportFilteredCandidates(); + } + /** + * Create or reuse a workspace for an existing directory. The path is + * canonicalized through `fs.realpath`; a nonexistent path rejects with the + * original error and a non-directory rejects. Repeated calls for the same + * canonical path return the existing entity without changing its title. + * A newly created workspace is prepended to the durable registry order. + * Different canonical paths may share a display title. + * @param path - Existing directory to own, in any path spelling. + * @param title - Display title used only when a new record is created. + * @returns the existing or newly durable workspace. + */ + async create(path, title) { + const canonical = await realpathNormalize(path); + if (!(await stat(canonical)).isDirectory()) throw new Error(`cannot create a workspace at '${canonical}': path is not a directory`); + return await this.enqueueOperation(() => this.createCanonical(canonical, title)); + } + /** + * Look up a workspace by id. + * @param id - Workspace id. + * @returns the workspace, or `undefined` when unknown. + */ + get(id) { + return this.entities.get(id); + } + /** + * Synchronous workspace projection in durable registry order. Every + * entity's `sessionIds` getter is already filtered by the startup/live + * canonical-cwd header index; this method performs no persistence reads. + * @returns a fresh ordered array of workspace entities. + */ + list() { + return this.requireState().workspaceIds.map((id) => { + const entity = this.entities.get(id); + if (entity === void 0) throw new Error(`workspace registry order references missing workspace '${id}'`); + return entity; + }); + } + /** + * Delete one workspace registration while retaining its directory and every + * session log. The durable order is updated before the table deletion; a + * failed table write restores the prior order and keeps the entity + * published. Unknown ids are an idempotent no-op for domain callers. + * @param id - Workspace registration to remove. + * @returns `true` when a record was deleted, `false` when it was unknown. + */ + delete(id) { + return this.enqueueOperation(() => this.deleteKnown(id)); + } + /** + * Move one workspace within the durable display order, DOM-insertBefore-like. + * With an anchor it lands before that workspace; without one it appends. + * @param id - Workspace to move. + * @param beforeId - Workspace anchor; omitted appends. + * @returns the complete committed workspace order. + */ + insertBefore(id, beforeId) { + return this.enqueueOperation(async () => { + const state = this.requireState(); + if (!state.workspaceIds.includes(id)) throw new WorkspaceOrderInvalidError(id); + if (beforeId !== void 0 && !state.workspaceIds.includes(beforeId)) throw new WorkspaceOrderInvalidError(beforeId); + if (beforeId === id) return state.workspaceIds; + const without = state.workspaceIds.filter((workspaceId) => workspaceId !== id); + const at = beforeId === void 0 ? without.length : without.indexOf(beforeId); + const workspaceIds = [ + ...without.slice(0, at), + id, + ...without.slice(at) + ]; + if (sameIds(workspaceIds, state.workspaceIds)) return state.workspaceIds; + await this.setState({ + ...state, + workspaceIds + }); + return workspaceIds; + }); + } + /** + * The registry-global archive set: sessions hidden from every grouping + * surface. Archiving never touches workspace accounting — an archived + * session keeps its `sessionIds` slot so unarchiving restores its position. + * @returns the archived session ids in archive order. + */ + get archivedSessionIds() { + return this.requireState().archivedSessionIds; + } + /** + * Archive one session durably. The session must exist (live or in session + * persistence); its workspace accounting — or lack of one — is irrelevant. + * An already archived id resolves without writing. + * @param sessionId - The session to archive. + * @returns resolution after durability. + */ + archiveSession(sessionId) { + return this.enqueueOperation(async () => { + if (this.requireState().archivedSessionIds.includes(sessionId)) return; + if (!await this.sessionKnown(sessionId)) throw new WorkspaceUnknownSessionError(sessionId); + const state = this.requireState(); + await this.setState({ + ...state, + archivedSessionIds: [...state.archivedSessionIds, sessionId] + }); + }); + } + /** + * Whether a session is live, header-indexed, or present in a fresh + * persistence listing. Only a definite miss returns false — a failing + * `sessionPersistence.list()` propagates so storage faults never + * masquerade as an unknown session. + */ + async sessionKnown(id) { + if (this.ctx.get("sessions")?.get(id) !== void 0) return true; + if (this.headers.has(id)) return true; + await this.indexHeaders(await this.ctx.sessionPersistence.list()); + return this.headers.has(id); + } + /** + * Resolve by canonical directory path without creating or mutating a + * workspace. A missing path rejects during `realpath`; an existing unowned + * directory returns `undefined`. + * @param path - Existing directory path in any spelling. + * @returns the workspace owning the canonical path, when one exists. + */ + async resolveByPath(path) { + const canonical = await realpathNormalize(path); + for (const entity of this.entities.values()) if (entity.path === canonical) return entity; + } + async createCanonical(canonical, title) { + for (const entity of this.entities.values()) if (entity.path === canonical) return entity; + const workspaceName = title ?? basename(canonical); + const table = this.requireTable(); + const state = this.requireState(); + const id = WorkspaceId(randomUUID()); + const now = (/* @__PURE__ */ new Date()).toISOString(); + const record = { + path: canonical, + title: workspaceName, + sessionIds: [], + createdAt: now, + updatedAt: now + }; + const entity = new WorkspaceEntity(this.host, id, record); + this.entities.set(id, entity); + const pendingState = { + ...state, + pendingMutation: { + operation: "create", + workspaceId: id + } + }; + try { + await this.setState(pendingState); + } catch (error) { + this.entities.delete(id); + throw error; + } + try { + await table.put(id, record); + } catch (error) { + this.entities.delete(id); + try { + await this.setState(state); + } catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' record write and pending-marker rollback both failed`); + } + throw error; + } + try { + await this.setState({ + initialized: true, + workspaceIds: [id, ...state.workspaceIds], + archivedSessionIds: state.archivedSessionIds + }); + } catch (error) { + this.entities.delete(id); + try { + await table.delete(id); + } catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' order write and record rollback both failed; the pending marker remains recoverable`); + } + try { + await this.setState(state); + } catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' order write and pending-marker rollback both failed`); + } + throw error; + } + return entity; + } + async deleteKnown(id) { + const entity = this.entities.get(id); + if (entity === void 0) return false; + const state = this.requireState(); + const nextState = { + initialized: true, + workspaceIds: state.workspaceIds.filter((workspaceId) => workspaceId !== id), + archivedSessionIds: state.archivedSessionIds + }; + await this.setState({ + ...nextState, + pendingMutation: { + operation: "delete", + workspaceId: id + } + }); + this.entities.delete(id); + try { + await this.requireTable().delete(id); + } catch (error) { + this.entities.set(id, entity); + try { + await this.setState(state); + } catch (rollbackError) { + this.entities.delete(id); + throw new AggregateError([error, rollbackError], `workspace '${id}' record deletion and registry-order rollback both failed`); + } + throw error; + } + try { + await this.setState(nextState); + } catch (error) { + this.ctx.logger.warn(`workspace '${id}' was deleted but its pending marker could not be cleared: ${String(error)}`); + } + return true; + } + /** + * Complete the one mutation explicitly named by durable state. Unexplained + * order/table divergence still reaches {@link validateStoredState} and + * fails loud; this path never guesses which operation created a row from its shape alone. + */ + async recoverPendingMutation() { + const state = this.requireState(); + const pending = state.pendingMutation; + if (pending === void 0) return; + if (state.workspaceIds.includes(pending.workspaceId)) throw new Error(`workspace domain is inconsistent: pending ${pending.operation} workspace '${pending.workspaceId}' is still present in registry order`); + await this.requireTable().delete(pending.workspaceId); + await this.setState({ + initialized: state.initialized, + workspaceIds: state.workspaceIds, + archivedSessionIds: state.archivedSessionIds + }); + } + async bootstrap(headers) { + const table = this.requireTable(); + const state = this.requireState(); + const groupsByPath = /* @__PURE__ */ new Map(); + for (const header of headers) { + const path = this.sessionPaths.get(header.id); + if (path === void 0) continue; + const group = groupsByPath.get(path); + if (group === void 0) groupsByPath.set(path, [header]); + else group.push(header); + } + const groups = [...groupsByPath].map(([path, groupHeaders]) => { + groupHeaders.sort(compareHeaders); + return { + path, + headers: groupHeaders, + newestAt: groupHeaders[0].createdAt + }; + }).sort((left, right) => right.newestAt - left.newestAt || left.path.localeCompare(right.path)); + const byPath = /* @__PURE__ */ new Map(); + const accounted = /* @__PURE__ */ new Map(); + for (const [id, record] of table.entries()) { + byPath.set(record.path, id); + for (const sessionId of record.sessionIds) accounted.set(sessionId, id); + } + for (const group of groups) { + let id = byPath.get(group.path); + if (id === void 0) { + const sessionIds = group.headers.map((header) => header.id).filter((sessionId) => !accounted.has(sessionId)); + if (sessionIds.length === 0) continue; + id = WorkspaceId(randomUUID()); + const createdAt = new Date(group.newestAt).toISOString(); + const record = { + path: group.path, + title: basename(group.path), + sessionIds, + createdAt, + updatedAt: createdAt + }; + await table.put(id, record); + byPath.set(group.path, id); + for (const sessionId of sessionIds) accounted.set(sessionId, id); + continue; + } + const current = table.get(id); + const historical = group.headers.map((header) => header.id).filter((sessionId) => accounted.get(sessionId) === void 0 || accounted.get(sessionId) === id); + const historicalSet = new Set(historical); + const sessionIds = [...historical, ...current.sessionIds.filter((sessionId) => !historicalSet.has(sessionId))]; + if (sameSessionIds(current.sessionIds, sessionIds)) continue; + await table.update(id, (record) => ({ + ...record, + sessionIds, + updatedAt: (/* @__PURE__ */ new Date()).toISOString() + })); + for (const sessionId of historical) accounted.set(sessionId, id); + } + const groupRank = new Map(groups.map((group) => [group.path, group.newestAt])); + const priorRank = new Map(state.workspaceIds.map((id, index) => [id, index])); + const workspaceIds = [...table.entries()].sort(([leftId, left], [rightId, right]) => { + const leftTime = groupRank.get(left.path) ?? Date.parse(left.createdAt); + return (groupRank.get(right.path) ?? Date.parse(right.createdAt)) - leftTime || (priorRank.get(leftId) ?? Number.MAX_SAFE_INTEGER) - (priorRank.get(rightId) ?? Number.MAX_SAFE_INTEGER) || String(leftId).localeCompare(String(rightId)); + }).map(([id]) => id); + if (!sameIds(state.workspaceIds, workspaceIds)) await this.setState({ + initialized: false, + workspaceIds, + archivedSessionIds: state.archivedSessionIds + }); + await this.setState({ + initialized: true, + workspaceIds, + archivedSessionIds: state.archivedSessionIds + }); + } + validateStoredState(state) { + const table = this.requireTable(); + const order = /* @__PURE__ */ new Set(); + for (const id of state.workspaceIds) { + if (order.has(id)) throw new Error(`workspace domain is inconsistent: registry order repeats workspace '${id}'`); + if (table.get(id) === void 0) throw new Error(`workspace domain is inconsistent: registry order references missing workspace '${id}'`); + order.add(id); + } + if (state.initialized && order.size !== table.size) { + const orphan = [...table.keys()].find((id) => !order.has(id)); + throw new Error(`workspace domain is inconsistent: workspace '${orphan}' is absent from registry order`); + } + const paths = /* @__PURE__ */ new Map(); + const accounted = /* @__PURE__ */ new Map(); + for (const [id, record] of table.entries()) { + const pathHolder = paths.get(record.path); + if (pathHolder !== void 0) throw new Error(`workspace domain is inconsistent: path '${record.path}' is claimed by both workspace '${pathHolder}' and workspace '${id}'`); + paths.set(record.path, id); + for (const sessionId of record.sessionIds) { + const holder = accounted.get(sessionId); + if (holder !== void 0) throw new Error(`workspace domain is inconsistent: session '${sessionId}' is accounted by both workspace '${holder}' and workspace '${id}'`); + accounted.set(sessionId, id); + } + } + } + rebuildEntities() { + this.entities.clear(); + for (const id of this.requireState().workspaceIds) { + const record = this.requireTable().get(id); + this.entities.set(id, new WorkspaceEntity(this.host, id, record)); + } + } + async replaceHeaderIndex(headers) { + this.headers.clear(); + this.sessionPaths.clear(); + this.invalidSessionPaths.clear(); + await this.indexHeaders(headers); + } + async indexHeaders(headers) { + for (const header of headers) await this.indexHeader(header); + } + async indexHeader(header) { + this.headers.set(header.id, header); + this.sessionPaths.delete(header.id); + if (header.cwd === void 0) { + this.invalidSessionPaths.set(header.id, "header has no cwd"); + return; + } + try { + const path = await realpathNormalize(header.cwd); + if (!(await stat(path)).isDirectory()) { + this.invalidSessionPaths.set(header.id, `cwd '${header.cwd}' is not a directory`); + return; + } + this.sessionPaths.set(header.id, path); + this.invalidSessionPaths.delete(header.id); + } catch { + this.invalidSessionPaths.set(header.id, `cwd '${header.cwd}' does not resolve`); + } + } + async indexLiveSessions() { + const sessions = this.ctx.get("sessions"); + if (sessions === void 0) return; + await this.indexHeaders(sessions.list().map((session) => session.header)); + } + reportFilteredCandidates() { + for (const entity of this.entities.values()) { + const record = this.requireTable().get(entity.id); + for (const sessionId of record.sessionIds) { + const path = this.sessionPaths.get(sessionId); + if (path === record.path) continue; + const reason = this.invalidSessionPaths.get(sessionId) ?? (this.headers.has(sessionId) ? `canonical cwd '${path}' differs from workspace path '${record.path}'` : "session header is missing"); + this.ctx.logger.warn(`workspace '${entity.id}' filtered session '${sessionId}' from membership: ${reason}`); + } + } + } + async readSessionHeader(id) { + const live = this.ctx.get("sessions")?.get(id); + if (live !== void 0) { + this.headers.set(id, live.header); + return live.header; + } + const cached = this.headers.get(id); + if (cached !== void 0) return cached; + const headers = await this.ctx.sessionPersistence.list(); + await this.indexHeaders(headers); + const header = this.headers.get(id); + if (header === void 0) throw new Error(`cannot validate session '${id}': session persistence holds no such session`); + return header; + } + requireTable() { + if (this.table === void 0) throw new Error("workspace registry is not started yet"); + return this.table; + } + requireState() { + if (this.state === void 0) throw new Error("workspace registry is not started yet"); + return this.state; + } + async setState(state) { + await this.global.set(state); + this.state = state; + } + enqueueOperation(operation) { + const result = this.operationTail.then(async () => { + await this.recoverPendingMutation(); + return await operation(); + }); + this.operationTail = result.then(() => {}, () => {}); + return result; + } +}; +const sameSessionIds = (left, right) => left.length === right.length && left.every((id, index) => id === right[index]); +//#endregion +export { WorkspaceId, WorkspaceMoveInvalidError, WorkspaceOrderInvalidError, WorkspaceRegistry, WorkspaceRegistry as default, WorkspaceUnknownSessionError, realpathNormalize, workspaceDomainSpec, workspaceDomainState, workspaceRecord }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/invariant.js new file mode 100644 index 0000000..cc04791 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/invariant.js @@ -0,0 +1,114 @@ +import "node:crypto"; +import "node:fs/promises"; +import "node:path"; +import { Service } from "@deepseek-ai/cordis"; +import { z } from "zod"; +import { SessionId } from "@deepseek-ai/dsh-session"; +import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain"; +//#endregion +//#region src/spec.ts +/** +* The workspace domain declaration: record schema and the `defineDomain` spec +* the registry opens. The zod schema is the durable-boundary validator today +* and the direct source of the RPC wire projection in a later phase. +* @module @deepseek-ai/dsh-workspace/src/spec +*/ +/** Workspace id schema at the durable boundary; branding has no runtime representation. */ +const workspaceId = z.string().transform((value) => value); +/** +* Durable shape of one workspace record. `path` is the `fs.realpath` canon +* stamped at create; `sessionIds` is the ordered ownership account (array +* order is display order); timestamps are ISO-8601 strings. +*/ +const workspaceRecord = z.object({ + path: z.string(), + title: z.string(), + sessionIds: z.array(z.string().transform(SessionId)), + createdAt: z.string(), + updatedAt: z.string() +}); +/** +* Recoverable two-write mutation marker. The marker is persisted before the +* record/order pair can diverge, so startup can distinguish an interrupted +* registry operation from unexplained medium corruption. +*/ +const workspacePendingMutation = z.discriminatedUnion("operation", [z.object({ + operation: z.literal("create"), + workspaceId +}), z.object({ + operation: z.literal("delete"), + workspaceId +})]); +defineDomain({ + name: "workspace", + version: 2, + global: { + schema: z.object({ + initialized: z.boolean(), + workspaceIds: z.array(workspaceId), + archivedSessionIds: z.array(z.string().transform(SessionId)).default([]), + pendingMutation: workspacePendingMutation.optional() + }), + initial: { + initialized: false, + workspaceIds: [], + archivedSessionIds: [] + } + }, + tables: { workspaces: domainTable(workspaceRecord) } +}); +//#endregion +//#region src/index.ts +/** +* Workspace entity registry (`ctx.workspaceRegistry`): durable workspace records, +* stable registry order, and header-validated session membership over the +* domain data form. +* @module @deepseek-ai/dsh-workspace +*/ +/** +* Brand a string as a {@link WorkspaceId}. +* @param id - Raw workspace id string. +* @returns the same string, branded at compile time. +*/ +function WorkspaceId(id) { + return id; +} +Service.init; +//#endregion +//#region lib/types/invariant.js +/** +* Package-owned invariant companion for `@deepseek-ai/dsh-workspace`. +* @module @deepseek-ai/dsh-workspace/invariant +*/ +const PACKAGE_NAME = "@deepseek-ai/dsh-workspace"; +/** Cordis companion plugin name. */ +const name = "workspace-invariant"; +/** Service required before the companion can reserve package ownership. */ +const inject = ["invariants"]; +/** +* Owned relationship: the registry's entity cache mirrors the workspace +* domain's durable table. Every `domain/changed` for the `workspaces` table +* must name a record the cache already holds an entity for (the registry +* caches before the durable put and mutates only through cached entities). +* A delete is valid only after the registry has removed the entity from its +* cache, whether for create rollback or an explicit registration deletion; +* deleting while the cache still publishes the entity proves a bypass. +*/ +const install = Object.assign((ctx, fail) => { + ctx.on("domain/changed", (change) => { + if (change.domain !== "workspace" || change.table !== "workspaces") return; + if (change.operation === "deleted") { + if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) !== void 0) fail(`workspace record '${change.key}' was deleted while the registry cache still publishes it — some write path bypassed ctx.workspaceRegistry`); + return; + } + if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) === void 0) fail(`workspace record '${change.key}' landed durably but the registry cache holds no entity for it — the cache and the domain table have diverged`); + }); +}, { inject: ["workspaceRegistry"] }); +/** +* Register this package's invariant companion. +* @param ctx - Cordis context carrying the invariant service. +* @returns the installed registration's disposer after setup succeeds. +*/ +const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//#endregion +export { apply, inject, name }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.d.ts new file mode 100644 index 0000000..55ab56b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.d.ts @@ -0,0 +1,88 @@ +/** + * Package-private workspace entity: the single {@link Workspace} + * implementation. Holds a record snapshot that is swapped in place after each + * durable mutation; every write funnels through the private `mutate` so + * `updatedAt` stamping and invalid-account pruning happen exactly once. + * Not re-exported from the package entrypoint — consumers see only the + * `Workspace` interface. + * @module @deepseek-ai/dsh-workspace/src/entity + */ +import type { SessionHeader, SessionId } from '@deepseek-ai/dsh-session'; +import type { KvTable } from '@deepseek-ai/dsh-storage-domain'; +import type { WorkspaceRecord } from './spec.ts'; +import type { Workspace, WorkspaceId } from './types.ts'; +/** An insertSessionBefore request named a session or anchor not on the account (storage failures stay plain errors). */ +export declare class WorkspaceMoveInvalidError extends Error { + /** + * @param message - Which id was unaccounted and where. + */ + constructor(message: string); +} +/** + * The registry-owned machinery an entity mutates through. Entities never see + * the registry itself — only the open table, the canonical session-path + * index backing the `sessionIds` projection, and attach-time header reads. + */ +export interface WorkspaceEntityHost { + /** + * Resolve the open `workspaces` table. + * @returns the table; throws while the registry has not started yet. + */ + table(): KvTable; + /** + * Read a session's canonical directory from the registry's header index. + * @param id - Session whose indexed path is requested. + * @returns the canonical directory, or `undefined` when the header is + * missing or its cwd cannot identify an existing directory. + */ + sessionPath(id: SessionId): string | undefined; + /** + * Read one stored session header for attach validation. + * @param id - The session whose header to read. + * @returns the header; rejects when session persistence is absent or holds + * no session with this id. + */ + readSessionHeader(id: SessionId): Promise; + /** + * Publish a successfully validated canonical cwd to the projection index. + * @param id - Validated session id. + * @param path - Canonical existing directory from the immutable header cwd. + */ + rememberSessionPath(id: SessionId, path: string): void; +} +/** The single {@link Workspace} implementation; constructed only by the registry. */ +export declare class WorkspaceEntity implements Workspace { + private readonly host; + readonly id: WorkspaceId; + private record; + /** + * @param host - Registry-owned table, session-path index, and header reads. + * @param id - The record's stable id. + * @param record - The validated record snapshot loaded or just written. + */ + constructor(host: WorkspaceEntityHost, id: WorkspaceId, record: WorkspaceRecord); + get path(): string; + get title(): string; + get createdAt(): string; + get updatedAt(): string; + get sessionIds(): readonly SessionId[]; + setTitle(title: string): Promise; + attachSession(sessionId: SessionId): Promise; + insertSessionBefore(sessionId: SessionId, beforeSessionId?: SessionId): Promise; + detachSession(sessionId: SessionId): Promise; + status(): Promise<'ok' | 'missing-dir'>; + /** + * The single write path: run `fn` on the domain write chain via + * `table.update`, stamping `updatedAt` and pruning candidates that no + * longer pass the id-plus-canonical-cwd membership check, then swap the + * snapshot. + * + * `fn` sees the value current at its chain slot, so membership decisions + * (attach/detach idempotence) are race-free against queued writes; a fn + * signalling no change by returning `current` verbatim aborts the slot + * through the sentinel when pruning also finds nothing, so a no-op neither + * rewrites the medium nor emits a change event. + */ + private mutate; +} +//# sourceMappingURL=entity.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.js new file mode 100644 index 0000000..95aae5e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/entity.js @@ -0,0 +1,156 @@ +/** + * Package-private workspace entity: the single {@link Workspace} + * implementation. Holds a record snapshot that is swapped in place after each + * durable mutation; every write funnels through the private `mutate` so + * `updatedAt` stamping and invalid-account pruning happen exactly once. + * Not re-exported from the package entrypoint — consumers see only the + * `Workspace` interface. + * @module @deepseek-ai/dsh-workspace/src/entity + */ +import { stat } from 'node:fs/promises'; +import { realpathNormalize } from "./paths.js"; +/** An insertSessionBefore request named a session or anchor not on the account (storage failures stay plain errors). */ +export class WorkspaceMoveInvalidError extends Error { + /** + * @param message - Which id was unaccounted and where. + */ + constructor(message) { + super(message); + this.name = 'WorkspaceMoveInvalidError'; + } +} +/** Chain-slot abort sentinel thrown by the update fn when the record needs no change; only `mutate` observes it. */ +const unchangedSentinel = new Error('workspace record unchanged (internal sentinel)'); +/** The single {@link Workspace} implementation; constructed only by the registry. */ +export class WorkspaceEntity { + host; + id; + record; + /** + * @param host - Registry-owned table, session-path index, and header reads. + * @param id - The record's stable id. + * @param record - The validated record snapshot loaded or just written. + */ + constructor(host, id, record) { + this.host = host; + this.id = id; + this.record = record; + } + get path() { + return this.record.path; + } + get title() { + return this.record.title; + } + get createdAt() { + return this.record.createdAt; + } + get updatedAt() { + return this.record.updatedAt; + } + get sessionIds() { + return this.record.sessionIds.filter(id => this.host.sessionPath(id) === this.record.path); + } + async setTitle(title) { + await this.mutate(record => ({ ...record, title })); + } + async attachSession(sessionId) { + // Validation is skipped when the settled snapshot already accounts the + // id: the cwd fact was checked when it first attached and both inputs + // (stored header cwd, workspace path) are immutable. Membership itself is + // decided on the write chain inside `mutate`, never on this snapshot. + if (!this.record.sessionIds.includes(sessionId)) { + const header = await this.host.readSessionHeader(sessionId); + if (header.cwd === undefined) { + throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': ` + + 'its stored header carries no cwd to validate against'); + } + let cwd; + try { + cwd = await realpathNormalize(header.cwd); + } + catch (error) { + throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': ` + + `its cwd '${header.cwd}' does not resolve, so it cannot be validated`, { cause: error }); + } + if (!(await stat(cwd)).isDirectory()) { + throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': ` + + `its cwd '${header.cwd}' is not a directory`); + } + if (cwd !== this.record.path) { + throw new Error(`cannot attach session '${sessionId}' to workspace '${this.record.path}': ` + + `its cwd resolves to '${cwd}'`); + } + this.host.rememberSessionPath(sessionId, cwd); + } + await this.mutate(record => record.sessionIds.includes(sessionId) + ? record + : { ...record, sessionIds: [sessionId, ...record.sessionIds] }); + } + async insertSessionBefore(sessionId, beforeSessionId) { + await this.mutate((record) => { + if (!record.sessionIds.includes(sessionId)) { + throw new WorkspaceMoveInvalidError(`cannot move session '${sessionId}' in workspace '${record.path}': the session is not accounted`); + } + if (beforeSessionId !== undefined && !record.sessionIds.includes(beforeSessionId)) { + throw new WorkspaceMoveInvalidError(`cannot move session '${sessionId}' before '${beforeSessionId}' in workspace '${record.path}': ` + + 'the anchor session is not accounted'); + } + if (beforeSessionId === sessionId) + return record; + const without = record.sessionIds.filter(id => id !== sessionId); + const at = beforeSessionId === undefined ? without.length : without.indexOf(beforeSessionId); + const sessionIds = [...without.slice(0, at), sessionId, ...without.slice(at)]; + return sessionIds.every((id, index) => id === record.sessionIds[index]) + ? record + : { ...record, sessionIds }; + }); + } + async detachSession(sessionId) { + await this.mutate(record => record.sessionIds.includes(sessionId) + ? { ...record, sessionIds: record.sessionIds.filter(id => id !== sessionId) } + : record); + } + async status() { + try { + return (await stat(this.record.path)).isDirectory() ? 'ok' : 'missing-dir'; + } + catch { + // Any stat failure (ENOENT, dangling parent, permission loss) means the + // directory is not usable right now; the record itself never mutates. + return 'missing-dir'; + } + } + /** + * The single write path: run `fn` on the domain write chain via + * `table.update`, stamping `updatedAt` and pruning candidates that no + * longer pass the id-plus-canonical-cwd membership check, then swap the + * snapshot. + * + * `fn` sees the value current at its chain slot, so membership decisions + * (attach/detach idempotence) are race-free against queued writes; a fn + * signalling no change by returning `current` verbatim aborts the slot + * through the sentinel when pruning also finds nothing, so a no-op neither + * rewrites the medium nor emits a change event. + */ + async mutate(fn) { + let next; + try { + next = await this.host.table().update(this.id, (current) => { + const changed = fn(current); + const sessionIds = changed.sessionIds.filter(id => this.host.sessionPath(id) === changed.path); + if (changed === current && sessionIds.length === current.sessionIds.length) { + throw unchangedSentinel; + } + return { ...changed, sessionIds, updatedAt: new Date().toISOString() }; + }); + } + catch (error) { + if (error === unchangedSentinel) + return; + throw error; + } + this.record = next; + } +} +//# sourceMappingURL=entity.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts new file mode 100644 index 0000000..8b389ad --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts @@ -0,0 +1,163 @@ +/** + * Workspace entity registry (`ctx.workspaceRegistry`): durable workspace records, + * stable registry order, and header-validated session membership over the + * domain data form. + * @module @deepseek-ai/dsh-workspace + */ +import { Context, Service } from '@deepseek-ai/cordis'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +export { WorkspaceMoveInvalidError } from './entity.ts'; +import type { Workspace, WorkspaceId as WorkspaceIdBrand } from './types.ts'; +export type { Workspace } from './types.ts'; +export { workspaceDomainState, workspaceRecord, workspaceDomainSpec } from './spec.ts'; +export type { WorkspaceDomainState, WorkspaceRecord } from './spec.ts'; +export { realpathNormalize } from './paths.ts'; +/** Identifies one workspace record (see `src/types.ts` for the brand rationale). */ +export type WorkspaceId = WorkspaceIdBrand; +/** + * Brand a string as a {@link WorkspaceId}. + * @param id - Raw workspace id string. + * @returns the same string, branded at compile time. + */ +export declare function WorkspaceId(id: string): WorkspaceId; +/** + * An archiveSession request named a session neither live nor in session + * persistence — a definite miss only; storage faults propagate as themselves. + */ +export declare class WorkspaceUnknownSessionError extends Error { + readonly sessionId: SessionId; + /** + * @param sessionId - The unknown session id. + */ + constructor(sessionId: SessionId); +} +/** A workspace reorder named a source or anchor absent from the durable registry order. */ +export declare class WorkspaceOrderInvalidError extends Error { + readonly workspaceId: WorkspaceId; + /** + * @param workspaceId - Missing source or anchor id. + */ + constructor(workspaceId: WorkspaceId); +} +declare module '@deepseek-ai/cordis' { + interface Context { + workspaceRegistry: WorkspaceRegistry; + } +} +/** + * Durable workspace registry. Startup waits for `sessionPersistence`, builds + * one canonical-cwd header index, and completes the one-time history + * bootstrap before the service becomes active. The persistence dependency is + * mandatory so an unavailable peer can never be mistaken for an empty + * history and commit the initialized marker. + */ +export declare class WorkspaceRegistry extends Service { + static inject: string[]; + private table?; + private global?; + private state?; + private readonly entities; + private readonly headers; + private readonly sessionPaths; + private readonly invalidSessionPaths; + private operationTail; + private readonly host; + constructor(ctx: Context); + /** Open the domain, finish bootstrap when required, and rebuild the ordered cache. */ + protected [Service.init](): Promise; + /** + * Create or reuse a workspace for an existing directory. The path is + * canonicalized through `fs.realpath`; a nonexistent path rejects with the + * original error and a non-directory rejects. Repeated calls for the same + * canonical path return the existing entity without changing its title. + * A newly created workspace is prepended to the durable registry order. + * Different canonical paths may share a display title. + * @param path - Existing directory to own, in any path spelling. + * @param title - Display title used only when a new record is created. + * @returns the existing or newly durable workspace. + */ + create(path: string, title?: string): Promise; + /** + * Look up a workspace by id. + * @param id - Workspace id. + * @returns the workspace, or `undefined` when unknown. + */ + get(id: WorkspaceId): Workspace | undefined; + /** + * Synchronous workspace projection in durable registry order. Every + * entity's `sessionIds` getter is already filtered by the startup/live + * canonical-cwd header index; this method performs no persistence reads. + * @returns a fresh ordered array of workspace entities. + */ + list(): Workspace[]; + /** + * Delete one workspace registration while retaining its directory and every + * session log. The durable order is updated before the table deletion; a + * failed table write restores the prior order and keeps the entity + * published. Unknown ids are an idempotent no-op for domain callers. + * @param id - Workspace registration to remove. + * @returns `true` when a record was deleted, `false` when it was unknown. + */ + delete(id: WorkspaceId): Promise; + /** + * Move one workspace within the durable display order, DOM-insertBefore-like. + * With an anchor it lands before that workspace; without one it appends. + * @param id - Workspace to move. + * @param beforeId - Workspace anchor; omitted appends. + * @returns the complete committed workspace order. + */ + insertBefore(id: WorkspaceId, beforeId?: WorkspaceId): Promise; + /** + * The registry-global archive set: sessions hidden from every grouping + * surface. Archiving never touches workspace accounting — an archived + * session keeps its `sessionIds` slot so unarchiving restores its position. + * @returns the archived session ids in archive order. + */ + get archivedSessionIds(): readonly SessionId[]; + /** + * Archive one session durably. The session must exist (live or in session + * persistence); its workspace accounting — or lack of one — is irrelevant. + * An already archived id resolves without writing. + * @param sessionId - The session to archive. + * @returns resolution after durability. + */ + archiveSession(sessionId: SessionId): Promise; + /** + * Whether a session is live, header-indexed, or present in a fresh + * persistence listing. Only a definite miss returns false — a failing + * `sessionPersistence.list()` propagates so storage faults never + * masquerade as an unknown session. + */ + private sessionKnown; + /** + * Resolve by canonical directory path without creating or mutating a + * workspace. A missing path rejects during `realpath`; an existing unowned + * directory returns `undefined`. + * @param path - Existing directory path in any spelling. + * @returns the workspace owning the canonical path, when one exists. + */ + resolveByPath(path: string): Promise; + private createCanonical; + private deleteKnown; + /** + * Complete the one mutation explicitly named by durable state. Unexplained + * order/table divergence still reaches {@link validateStoredState} and + * fails loud; this path never guesses which operation created a row from its shape alone. + */ + private recoverPendingMutation; + private bootstrap; + private validateStoredState; + private rebuildEntities; + private replaceHeaderIndex; + private indexHeaders; + private indexHeader; + private indexLiveSessions; + private reportFilteredCandidates; + private readSessionHeader; + private requireTable; + private requireState; + private setState; + private enqueueOperation; +} +export default WorkspaceRegistry; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.js new file mode 100644 index 0000000..4bc255d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.js @@ -0,0 +1,600 @@ +/** + * Workspace entity registry (`ctx.workspaceRegistry`): durable workspace records, + * stable registry order, and header-validated session membership over the + * domain data form. + * @module @deepseek-ai/dsh-workspace + */ +import { randomUUID } from 'node:crypto'; +import { stat } from 'node:fs/promises'; +import { basename } from 'node:path'; +import { Service } from '@deepseek-ai/cordis'; +import { WorkspaceEntity } from "./entity.js"; +export { WorkspaceMoveInvalidError } from "./entity.js"; +import { realpathNormalize } from "./paths.js"; +import { workspaceDomainSpec } from "./spec.js"; +export { workspaceDomainState, workspaceRecord, workspaceDomainSpec } from "./spec.js"; +export { realpathNormalize } from "./paths.js"; +/** + * Brand a string as a {@link WorkspaceId}. + * @param id - Raw workspace id string. + * @returns the same string, branded at compile time. + */ +export function WorkspaceId(id) { + return id; +} +/** + * An archiveSession request named a session neither live nor in session + * persistence — a definite miss only; storage faults propagate as themselves. + */ +export class WorkspaceUnknownSessionError extends Error { + sessionId; + /** + * @param sessionId - The unknown session id. + */ + constructor(sessionId) { + super(`cannot archive session '${sessionId}': live sessions and session persistence hold no such session`); + this.sessionId = sessionId; + this.name = 'WorkspaceUnknownSessionError'; + } +} +/** A workspace reorder named a source or anchor absent from the durable registry order. */ +export class WorkspaceOrderInvalidError extends Error { + workspaceId; + /** + * @param workspaceId - Missing source or anchor id. + */ + constructor(workspaceId) { + super(`cannot reorder unknown workspace '${workspaceId}'`); + this.workspaceId = workspaceId; + this.name = 'WorkspaceOrderInvalidError'; + } +} +const sameIds = (left, right) => left.length === right.length && left.every((id, index) => id === right[index]); +const compareHeaders = (left, right) => right.createdAt - left.createdAt || String(left.id).localeCompare(String(right.id)); +/** + * Durable workspace registry. Startup waits for `sessionPersistence`, builds + * one canonical-cwd header index, and completes the one-time history + * bootstrap before the service becomes active. The persistence dependency is + * mandatory so an unavailable peer can never be mistaken for an empty + * history and commit the initialized marker. + */ +export class WorkspaceRegistry extends Service { + static inject = ['storageDomain', 'sessionPersistence']; + table; + global; + state; + entities = new Map(); + headers = new Map(); + sessionPaths = new Map(); + invalidSessionPaths = new Map(); + operationTail = Promise.resolve(); + host = { + table: () => this.requireTable(), + sessionPath: id => this.sessionPaths.get(id), + readSessionHeader: id => this.readSessionHeader(id), + rememberSessionPath: (id, path) => { + this.sessionPaths.set(id, path); + this.invalidSessionPaths.delete(id); + }, + }; + constructor(ctx) { + super(ctx, 'workspaceRegistry'); + } + /** Open the domain, finish bootstrap when required, and rebuild the ordered cache. */ + async [Service.init]() { + const domain = await this.ctx.storageDomain.open(workspaceDomainSpec); + this.ctx.effect(() => () => domain.close(), 'workspace.domainClose'); + this.table = domain.table('workspaces'); + this.global = domain.global; + this.state = domain.global.get(); + await this.recoverPendingMutation(); + this.validateStoredState(this.state); + if (!this.state.initialized) { + const headers = await this.ctx.sessionPersistence.list(); + await this.replaceHeaderIndex(headers); + await this.bootstrap(headers); + } + else if (this.table.size > 0) { + await this.replaceHeaderIndex(await this.ctx.sessionPersistence.list()); + } + await this.indexLiveSessions(); + this.validateStoredState(this.requireState()); + this.rebuildEntities(); + this.reportFilteredCandidates(); + } + /** + * Create or reuse a workspace for an existing directory. The path is + * canonicalized through `fs.realpath`; a nonexistent path rejects with the + * original error and a non-directory rejects. Repeated calls for the same + * canonical path return the existing entity without changing its title. + * A newly created workspace is prepended to the durable registry order. + * Different canonical paths may share a display title. + * @param path - Existing directory to own, in any path spelling. + * @param title - Display title used only when a new record is created. + * @returns the existing or newly durable workspace. + */ + // TODO: `title` lost its last production caller when the gateway's + // create-by-name branch was deleted + // (.agents/notes/implemented/simplification/2026-07-31-one-route-to-add-a-workspace.md); + // drop the parameter with its @param clause and the `create(path, title?)` + // lines in this package's README pair. + async create(path, title) { + const canonical = await realpathNormalize(path); + if (!(await stat(canonical)).isDirectory()) { + throw new Error(`cannot create a workspace at '${canonical}': path is not a directory`); + } + return await this.enqueueOperation(() => this.createCanonical(canonical, title)); + } + /** + * Look up a workspace by id. + * @param id - Workspace id. + * @returns the workspace, or `undefined` when unknown. + */ + get(id) { + return this.entities.get(id); + } + /** + * Synchronous workspace projection in durable registry order. Every + * entity's `sessionIds` getter is already filtered by the startup/live + * canonical-cwd header index; this method performs no persistence reads. + * @returns a fresh ordered array of workspace entities. + */ + list() { + return this.requireState().workspaceIds.map((id) => { + const entity = this.entities.get(id); + if (entity === undefined) { + throw new Error(`workspace registry order references missing workspace '${id}'`); + } + return entity; + }); + } + /** + * Delete one workspace registration while retaining its directory and every + * session log. The durable order is updated before the table deletion; a + * failed table write restores the prior order and keeps the entity + * published. Unknown ids are an idempotent no-op for domain callers. + * @param id - Workspace registration to remove. + * @returns `true` when a record was deleted, `false` when it was unknown. + */ + delete(id) { + return this.enqueueOperation(() => this.deleteKnown(id)); + } + /** + * Move one workspace within the durable display order, DOM-insertBefore-like. + * With an anchor it lands before that workspace; without one it appends. + * @param id - Workspace to move. + * @param beforeId - Workspace anchor; omitted appends. + * @returns the complete committed workspace order. + */ + insertBefore(id, beforeId) { + return this.enqueueOperation(async () => { + const state = this.requireState(); + if (!state.workspaceIds.includes(id)) + throw new WorkspaceOrderInvalidError(id); + if (beforeId !== undefined && !state.workspaceIds.includes(beforeId)) { + throw new WorkspaceOrderInvalidError(beforeId); + } + if (beforeId === id) + return state.workspaceIds; + const without = state.workspaceIds.filter(workspaceId => workspaceId !== id); + const at = beforeId === undefined ? without.length : without.indexOf(beforeId); + const workspaceIds = [...without.slice(0, at), id, ...without.slice(at)]; + if (sameIds(workspaceIds, state.workspaceIds)) + return state.workspaceIds; + await this.setState({ ...state, workspaceIds }); + return workspaceIds; + }); + } + /** + * The registry-global archive set: sessions hidden from every grouping + * surface. Archiving never touches workspace accounting — an archived + * session keeps its `sessionIds` slot so unarchiving restores its position. + * @returns the archived session ids in archive order. + */ + get archivedSessionIds() { + return this.requireState().archivedSessionIds; + } + /** + * Archive one session durably. The session must exist (live or in session + * persistence); its workspace accounting — or lack of one — is irrelevant. + * An already archived id resolves without writing. + * @param sessionId - The session to archive. + * @returns resolution after durability. + */ + archiveSession(sessionId) { + return this.enqueueOperation(async () => { + // The chain slot serializes against every other registry write, so this + // check-then-write pair cannot interleave with another archive. + if (this.requireState().archivedSessionIds.includes(sessionId)) + return; + if (!(await this.sessionKnown(sessionId))) { + throw new WorkspaceUnknownSessionError(sessionId); + } + const state = this.requireState(); + await this.setState({ ...state, archivedSessionIds: [...state.archivedSessionIds, sessionId] }); + }); + } + /** + * Whether a session is live, header-indexed, or present in a fresh + * persistence listing. Only a definite miss returns false — a failing + * `sessionPersistence.list()` propagates so storage faults never + * masquerade as an unknown session. + */ + async sessionKnown(id) { + if (this.ctx.get('sessions')?.get(id) !== undefined) + return true; + if (this.headers.has(id)) + return true; + await this.indexHeaders(await this.ctx.sessionPersistence.list()); + return this.headers.has(id); + } + /** + * Resolve by canonical directory path without creating or mutating a + * workspace. A missing path rejects during `realpath`; an existing unowned + * directory returns `undefined`. + * @param path - Existing directory path in any spelling. + * @returns the workspace owning the canonical path, when one exists. + */ + async resolveByPath(path) { + const canonical = await realpathNormalize(path); + for (const entity of this.entities.values()) { + if (entity.path === canonical) + return entity; + } + return undefined; + } + async createCanonical(canonical, title) { + for (const entity of this.entities.values()) { + if (entity.path === canonical) + return entity; + } + const workspaceName = title ?? basename(canonical); + const table = this.requireTable(); + const state = this.requireState(); + const id = WorkspaceId(randomUUID()); + const now = new Date().toISOString(); + const record = { + path: canonical, + title: workspaceName, + sessionIds: [], + createdAt: now, + updatedAt: now, + }; + const entity = new WorkspaceEntity(this.host, id, record); + this.entities.set(id, entity); + const pendingState = { + ...state, + pendingMutation: { operation: 'create', workspaceId: id }, + }; + try { + await this.setState(pendingState); + } + catch (error) { + this.entities.delete(id); + throw error; + } + try { + await table.put(id, record); + } + catch (error) { + this.entities.delete(id); + try { + await this.setState(state); + } + catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' record write and pending-marker rollback both failed`); + } + throw error; + } + try { + await this.setState({ + initialized: true, + workspaceIds: [id, ...state.workspaceIds], + archivedSessionIds: state.archivedSessionIds, + }); + } + catch (error) { + this.entities.delete(id); + try { + await table.delete(id); + } + catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' order write and record rollback both failed; the pending marker remains recoverable`); + } + try { + await this.setState(state); + } + catch (rollbackError) { + throw new AggregateError([error, rollbackError], `workspace '${id}' order write and pending-marker rollback both failed`); + } + throw error; + } + return entity; + } + async deleteKnown(id) { + const entity = this.entities.get(id); + if (entity === undefined) + return false; + const state = this.requireState(); + const nextState = { + initialized: true, + workspaceIds: state.workspaceIds.filter(workspaceId => workspaceId !== id), + archivedSessionIds: state.archivedSessionIds, + }; + await this.setState({ + ...nextState, + pendingMutation: { operation: 'delete', workspaceId: id }, + }); + this.entities.delete(id); + try { + await this.requireTable().delete(id); + } + catch (error) { + this.entities.set(id, entity); + try { + await this.setState(state); + } + catch (rollbackError) { + // The durable marker still says to finish deletion, so the cache must + // agree with that recoverable direction rather than republish a row + // absent from the persisted order. + this.entities.delete(id); + throw new AggregateError([error, rollbackError], `workspace '${id}' record deletion and registry-order rollback both failed`); + } + throw error; + } + try { + await this.setState(nextState); + } + catch (error) { + // The deletion committed at the table write and was already published + // to Host streams. Keep the durable marker for startup recovery rather + // than reporting failure after the requested state became true. + this.ctx.logger.warn(`workspace '${id}' was deleted but its pending marker could not be cleared: ${String(error)}`); + } + return true; + } + /** + * Complete the one mutation explicitly named by durable state. Unexplained + * order/table divergence still reaches {@link validateStoredState} and + * fails loud; this path never guesses which operation created a row from its shape alone. + */ + async recoverPendingMutation() { + const state = this.requireState(); + const pending = state.pendingMutation; + if (pending === undefined) + return; + if (state.workspaceIds.includes(pending.workspaceId)) { + throw new Error(`workspace domain is inconsistent: pending ${pending.operation} workspace ` + + `'${pending.workspaceId}' is still present in registry order`); + } + await this.requireTable().delete(pending.workspaceId); + await this.setState({ + initialized: state.initialized, + workspaceIds: state.workspaceIds, + archivedSessionIds: state.archivedSessionIds, + }); + } + async bootstrap(headers) { + const table = this.requireTable(); + const state = this.requireState(); + const groupsByPath = new Map(); + for (const header of headers) { + const path = this.sessionPaths.get(header.id); + if (path === undefined) + continue; + const group = groupsByPath.get(path); + if (group === undefined) + groupsByPath.set(path, [header]); + else + group.push(header); + } + const groups = [...groupsByPath].map(([path, groupHeaders]) => { + groupHeaders.sort(compareHeaders); + const newest = groupHeaders[0]; + return { path, headers: groupHeaders, newestAt: newest.createdAt }; + }).sort((left, right) => right.newestAt - left.newestAt || left.path.localeCompare(right.path)); + const byPath = new Map(); + const accounted = new Map(); + for (const [id, record] of table.entries()) { + byPath.set(record.path, id); + for (const sessionId of record.sessionIds) + accounted.set(sessionId, id); + } + for (const group of groups) { + let id = byPath.get(group.path); + if (id === undefined) { + const sessionIds = group.headers + .map(header => header.id) + .filter(sessionId => !accounted.has(sessionId)); + if (sessionIds.length === 0) + continue; + id = WorkspaceId(randomUUID()); + const createdAt = new Date(group.newestAt).toISOString(); + const record = { + path: group.path, + title: basename(group.path), + sessionIds, + createdAt, + updatedAt: createdAt, + }; + await table.put(id, record); + byPath.set(group.path, id); + for (const sessionId of sessionIds) + accounted.set(sessionId, id); + continue; + } + const current = table.get(id); + const historical = group.headers + .map(header => header.id) + .filter(sessionId => accounted.get(sessionId) === undefined || accounted.get(sessionId) === id); + const historicalSet = new Set(historical); + const sessionIds = [ + ...historical, + ...current.sessionIds.filter(sessionId => !historicalSet.has(sessionId)), + ]; + if (sameSessionIds(current.sessionIds, sessionIds)) + continue; + await table.update(id, record => ({ + ...record, + sessionIds, + updatedAt: new Date().toISOString(), + })); + for (const sessionId of historical) + accounted.set(sessionId, id); + } + const groupRank = new Map(groups.map(group => [group.path, group.newestAt])); + const priorRank = new Map(state.workspaceIds.map((id, index) => [id, index])); + const workspaceIds = [...table.entries()] + .sort(([leftId, left], [rightId, right]) => { + const leftTime = groupRank.get(left.path) ?? Date.parse(left.createdAt); + const rightTime = groupRank.get(right.path) ?? Date.parse(right.createdAt); + return rightTime - leftTime + || (priorRank.get(leftId) ?? Number.MAX_SAFE_INTEGER) + - (priorRank.get(rightId) ?? Number.MAX_SAFE_INTEGER) + || String(leftId).localeCompare(String(rightId)); + }) + .map(([id]) => id); + if (!sameIds(state.workspaceIds, workspaceIds)) { + await this.setState({ initialized: false, workspaceIds, archivedSessionIds: state.archivedSessionIds }); + } + await this.setState({ initialized: true, workspaceIds, archivedSessionIds: state.archivedSessionIds }); + } + validateStoredState(state) { + const table = this.requireTable(); + const order = new Set(); + for (const id of state.workspaceIds) { + if (order.has(id)) { + throw new Error(`workspace domain is inconsistent: registry order repeats workspace '${id}'`); + } + if (table.get(id) === undefined) { + throw new Error(`workspace domain is inconsistent: registry order references missing workspace '${id}'`); + } + order.add(id); + } + if (state.initialized && order.size !== table.size) { + const orphan = [...table.keys()].find(id => !order.has(id)); + throw new Error(`workspace domain is inconsistent: workspace '${orphan}' is absent from registry order`); + } + const paths = new Map(); + const accounted = new Map(); + for (const [id, record] of table.entries()) { + const pathHolder = paths.get(record.path); + if (pathHolder !== undefined) { + throw new Error(`workspace domain is inconsistent: path '${record.path}' is claimed ` + + `by both workspace '${pathHolder}' and workspace '${id}'`); + } + paths.set(record.path, id); + for (const sessionId of record.sessionIds) { + const holder = accounted.get(sessionId); + if (holder !== undefined) { + throw new Error(`workspace domain is inconsistent: session '${sessionId}' is accounted ` + + `by both workspace '${holder}' and workspace '${id}'`); + } + accounted.set(sessionId, id); + } + } + } + rebuildEntities() { + this.entities.clear(); + for (const id of this.requireState().workspaceIds) { + const record = this.requireTable().get(id); + this.entities.set(id, new WorkspaceEntity(this.host, id, record)); + } + } + async replaceHeaderIndex(headers) { + this.headers.clear(); + this.sessionPaths.clear(); + this.invalidSessionPaths.clear(); + await this.indexHeaders(headers); + } + async indexHeaders(headers) { + for (const header of headers) + await this.indexHeader(header); + } + async indexHeader(header) { + this.headers.set(header.id, header); + this.sessionPaths.delete(header.id); + if (header.cwd === undefined) { + this.invalidSessionPaths.set(header.id, 'header has no cwd'); + return; + } + try { + const path = await realpathNormalize(header.cwd); + if (!(await stat(path)).isDirectory()) { + this.invalidSessionPaths.set(header.id, `cwd '${header.cwd}' is not a directory`); + return; + } + this.sessionPaths.set(header.id, path); + this.invalidSessionPaths.delete(header.id); + } + catch { + this.invalidSessionPaths.set(header.id, `cwd '${header.cwd}' does not resolve`); + } + } + async indexLiveSessions() { + const sessions = this.ctx.get('sessions'); + if (sessions === undefined) + return; + await this.indexHeaders(sessions.list().map(session => session.header)); + } + reportFilteredCandidates() { + for (const entity of this.entities.values()) { + const record = this.requireTable().get(entity.id); + for (const sessionId of record.sessionIds) { + const path = this.sessionPaths.get(sessionId); + if (path === record.path) + continue; + const reason = this.invalidSessionPaths.get(sessionId) + ?? (this.headers.has(sessionId) + ? `canonical cwd '${path}' differs from workspace path '${record.path}'` + : 'session header is missing'); + this.ctx.logger.warn(`workspace '${entity.id}' filtered session '${sessionId}' from membership: ${reason}`); + } + } + } + async readSessionHeader(id) { + const live = this.ctx.get('sessions')?.get(id); + if (live !== undefined) { + this.headers.set(id, live.header); + return live.header; + } + const cached = this.headers.get(id); + if (cached !== undefined) + return cached; + const headers = await this.ctx.sessionPersistence.list(); + await this.indexHeaders(headers); + const header = this.headers.get(id); + if (header === undefined) { + throw new Error(`cannot validate session '${id}': session persistence holds no such session`); + } + return header; + } + requireTable() { + if (this.table === undefined) + throw new Error('workspace registry is not started yet'); + return this.table; + } + requireState() { + if (this.state === undefined) + throw new Error('workspace registry is not started yet'); + return this.state; + } + async setState(state) { + await this.global.set(state); + this.state = state; + } + enqueueOperation(operation) { + const result = this.operationTail.then(async () => { + // A committed delete may leave only its marker cleanup pending. Retry + // recovery before another create/delete can overwrite that pending operation record. + await this.recoverPendingMutation(); + return await operation(); + }); + this.operationTail = result.then(() => { }, () => { }); + return result; + } +} +const sameSessionIds = (left, right) => left.length === right.length && left.every((id, index) => id === right[index]); +export default WorkspaceRegistry; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.d.ts new file mode 100644 index 0000000..528291e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.d.ts @@ -0,0 +1,16 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-workspace`. + * @module @deepseek-ai/dsh-workspace/invariant + */ +import type { Context } from '@deepseek-ai/cordis'; +/** Cordis companion plugin name. */ +export declare const name = "workspace-invariant"; +/** Service required before the companion can reserve package ownership. */ +export declare const inject: string[]; +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export declare const apply: (ctx: Context) => Promise<() => void>; +//# sourceMappingURL=invariant.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.js new file mode 100644 index 0000000..47f0d36 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/invariant.js @@ -0,0 +1,43 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-workspace`. + * @module @deepseek-ai/dsh-workspace/invariant + */ +import { WorkspaceId } from '@deepseek-ai/dsh-workspace'; +const PACKAGE_NAME = '@deepseek-ai/dsh-workspace'; +/** Cordis companion plugin name. */ +export const name = 'workspace-invariant'; +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants']; +/** + * Owned relationship: the registry's entity cache mirrors the workspace + * domain's durable table. Every `domain/changed` for the `workspaces` table + * must name a record the cache already holds an entity for (the registry + * caches before the durable put and mutates only through cached entities). + * A delete is valid only after the registry has removed the entity from its + * cache, whether for create rollback or an explicit registration deletion; + * deleting while the cache still publishes the entity proves a bypass. + */ +const install = Object.assign((ctx, fail) => { + ctx.on('domain/changed', (change) => { + if (change.domain !== 'workspace' || change.table !== 'workspaces') + return; + if (change.operation === 'deleted') { + if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) !== undefined) { + fail(`workspace record '${change.key}' was deleted while the registry cache still ` + + 'publishes it — some write path bypassed ctx.workspaceRegistry'); + } + return; + } + if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) === undefined) { + fail(`workspace record '${change.key}' landed durably but the registry cache holds ` + + 'no entity for it — the cache and the domain table have diverged'); + } + }); +}, { inject: ['workspaceRegistry'] }); +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)); +//# sourceMappingURL=invariant.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.d.ts new file mode 100644 index 0000000..a0b2ed5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.d.ts @@ -0,0 +1,18 @@ +/** + * Path canonicalization for workspace identity. + * @module @deepseek-ai/dsh-workspace/src/paths + */ +/** + * Canonicalize a directory path via `fs.realpath`: trailing slashes, `..` + * segments, and symlinks are all resolved. This is the ONE uniqueness canon of + * the package — workspace paths are stored canonicalized, uniqueness is + * string equality of canonicalized paths (a symlink to an existing + * workspace's directory collides), and attach-time session `cwd` checks go + * through the same canon. A path that does not exist rejects with the + * original `ENOENT` — this is `create`'s reject path (a workspace must point + * at an existing directory). + * @param path - The path to canonicalize. + * @returns the canonical absolute path. + */ +export declare function realpathNormalize(path: string): Promise; +//# sourceMappingURL=paths.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.js new file mode 100644 index 0000000..0209f6a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/paths.js @@ -0,0 +1,21 @@ +/** + * Path canonicalization for workspace identity. + * @module @deepseek-ai/dsh-workspace/src/paths + */ +import { realpath } from 'node:fs/promises'; +/** + * Canonicalize a directory path via `fs.realpath`: trailing slashes, `..` + * segments, and symlinks are all resolved. This is the ONE uniqueness canon of + * the package — workspace paths are stored canonicalized, uniqueness is + * string equality of canonicalized paths (a symlink to an existing + * workspace's directory collides), and attach-time session `cwd` checks go + * through the same canon. A path that does not exist rejects with the + * original `ENOENT` — this is `create`'s reject path (a workspace must point + * at an existing directory). + * @param path - The path to canonicalize. + * @returns the canonical absolute path. + */ +export async function realpathNormalize(path) { + return await realpath(path); +} +//# sourceMappingURL=paths.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.d.ts new file mode 100644 index 0000000..65a053a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.d.ts @@ -0,0 +1,85 @@ +/** + * The workspace domain declaration: record schema and the `defineDomain` spec + * the registry opens. The zod schema is the durable-boundary validator today + * and the direct source of the RPC wire projection in a later phase. + * @module @deepseek-ai/dsh-workspace/src/spec + */ +import { z } from 'zod'; +import { SessionId } from '@deepseek-ai/dsh-session'; +import type { WorkspaceId } from './types.ts'; +/** + * Durable shape of one workspace record. `path` is the `fs.realpath` canon + * stamped at create; `sessionIds` is the ordered ownership account (array + * order is display order); timestamps are ISO-8601 strings. + */ +export declare const workspaceRecord: z.ZodObject<{ + path: z.ZodString; + title: z.ZodString; + sessionIds: z.ZodArray>>; + createdAt: z.ZodString; + updatedAt: z.ZodString; +}, z.core.$strip>; +/** One stored workspace record, inferred from {@link workspaceRecord}. */ +export type WorkspaceRecord = z.infer; +/** + * Durable registry state. `initialized` distinguishes a valid empty registry + * from one that still needs the header-only history bootstrap; + * `workspaceIds` is the authoritative display order. `archivedSessionIds` is + * the registry-global archive set layered over workspace accounting: an + * archived session keeps its `sessionIds` slot (unarchiving must restore the + * position), so the set never participates in the one-owner accounting + * invariant. Defaulted so records written before the field parse unchanged. + */ +export declare const workspaceDomainState: z.ZodObject<{ + initialized: z.ZodBoolean; + workspaceIds: z.ZodArray>>; + archivedSessionIds: z.ZodDefault>>>; + pendingMutation: z.ZodOptional; + workspaceId: z.ZodPipe>; + }, z.core.$strip>, z.ZodObject<{ + operation: z.ZodLiteral<"delete">; + workspaceId: z.ZodPipe>; + }, z.core.$strip>], "operation">>; +}, z.core.$strip>; +/** Durable registry state inferred from {@link workspaceDomainState}. */ +export type WorkspaceDomainState = z.infer; +/** + * The workspace domain spec: one `workspaces` table keyed by + * {@link WorkspaceId} plus the bootstrap/order singleton. The registry opens + * this through `ctx.storage.domain`; the spec object is the single source of + * the domain's identity, version, and schemas. + */ +export declare const workspaceDomainSpec: { + name: string; + version: number; + global: { + schema: z.ZodObject<{ + initialized: z.ZodBoolean; + workspaceIds: z.ZodArray>>; + archivedSessionIds: z.ZodDefault>>>; + pendingMutation: z.ZodOptional; + workspaceId: z.ZodPipe>; + }, z.core.$strip>, z.ZodObject<{ + operation: z.ZodLiteral<"delete">; + workspaceId: z.ZodPipe>; + }, z.core.$strip>], "operation">>; + }, z.core.$strip>; + initial: { + initialized: boolean; + workspaceIds: never[]; + archivedSessionIds: never[]; + }; + }; + tables: { + workspaces: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec; + }; +}; +//# sourceMappingURL=spec.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.js new file mode 100644 index 0000000..39f707f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.js @@ -0,0 +1,63 @@ +/** + * The workspace domain declaration: record schema and the `defineDomain` spec + * the registry opens. The zod schema is the durable-boundary validator today + * and the direct source of the RPC wire projection in a later phase. + * @module @deepseek-ai/dsh-workspace/src/spec + */ +import { z } from 'zod'; +import { SessionId } from '@deepseek-ai/dsh-session'; +import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'; +/** Workspace id schema at the durable boundary; branding has no runtime representation. */ +const workspaceId = z.string().transform(value => value); +/** + * Durable shape of one workspace record. `path` is the `fs.realpath` canon + * stamped at create; `sessionIds` is the ordered ownership account (array + * order is display order); timestamps are ISO-8601 strings. + */ +export const workspaceRecord = z.object({ + path: z.string(), + title: z.string(), + sessionIds: z.array(z.string().transform(SessionId)), + createdAt: z.string(), + updatedAt: z.string(), +}); +/** + * Recoverable two-write mutation marker. The marker is persisted before the + * record/order pair can diverge, so startup can distinguish an interrupted + * registry operation from unexplained medium corruption. + */ +const workspacePendingMutation = z.discriminatedUnion('operation', [ + z.object({ operation: z.literal('create'), workspaceId }), + z.object({ operation: z.literal('delete'), workspaceId }), +]); +/** + * Durable registry state. `initialized` distinguishes a valid empty registry + * from one that still needs the header-only history bootstrap; + * `workspaceIds` is the authoritative display order. `archivedSessionIds` is + * the registry-global archive set layered over workspace accounting: an + * archived session keeps its `sessionIds` slot (unarchiving must restore the + * position), so the set never participates in the one-owner accounting + * invariant. Defaulted so records written before the field parse unchanged. + */ +export const workspaceDomainState = z.object({ + initialized: z.boolean(), + workspaceIds: z.array(workspaceId), + archivedSessionIds: z.array(z.string().transform(SessionId)).default([]), + pendingMutation: workspacePendingMutation.optional(), +}); +/** + * The workspace domain spec: one `workspaces` table keyed by + * {@link WorkspaceId} plus the bootstrap/order singleton. The registry opens + * this through `ctx.storage.domain`; the spec object is the single source of + * the domain's identity, version, and schemas. + */ +export const workspaceDomainSpec = defineDomain({ + name: 'workspace', + version: 2, + global: { + schema: workspaceDomainState, + initial: { initialized: false, workspaceIds: [], archivedSessionIds: [] }, + }, + tables: { workspaces: domainTable(workspaceRecord) }, +}); +//# sourceMappingURL=spec.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.d.ts new file mode 100644 index 0000000..a1f63c8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.d.ts @@ -0,0 +1,92 @@ +/** + * Public type vocabulary of the workspace entity: the `WorkspaceId` brand and + * the `Workspace` consumer interface. Types only — the `WorkspaceId` factory + * lives in `index.ts` (this file carries no runtime code). + * @module @deepseek-ai/dsh-workspace/src/types + */ +import type { Branded } from '@deepseek-ai/dsh-brand'; +import type { SessionId } from '@deepseek-ai/dsh-session'; +/** + * Identifies one workspace record. A generated uuid, never the path: path + * normalization rewrites paths, and a reference anchor must stay stable. + */ +export type WorkspaceId = Branded<'WorkspaceId'>; +/** + * One workspace: a stable id over an existing directory, a display title, and + * an ordered candidate account of sessions. Membership requires both an id in + * that account and a session header whose canonical cwd equals the workspace + * path. Consumers only see this interface; the implementation stays private. + */ +export interface Workspace { + /** Stable record id (generated uuid). */ + readonly id: WorkspaceId; + /** + * Canonical directory path: the `fs.realpath` of the path given at create + * time (trailing slashes, `..`, and symlinks all resolved). Never rewritten + * afterwards, even when the directory disappears (see {@link status}). + */ + readonly path: string; + /** Display title. Defaults to `basename(path)` at create; duplicates are allowed. */ + readonly title: string; + /** ISO-8601 creation instant, stamped at create and never rewritten. */ + readonly createdAt: string; + /** ISO-8601 instant of the last durable mutation (create counts as one). */ + readonly updatedAt: string; + /** + * Header-validated sessions in manually owned order: a new session is + * prepended at attach, explicit reordering goes through + * `insertSessionBefore`, and activity never reorders. The durable candidate + * account is filtered synchronously: missing headers, invalid cwd values, + * and canonical cwd mismatches are never returned. A subsequent workspace + * mutation prunes those filtered candidates durably. + */ + readonly sessionIds: readonly SessionId[]; + /** + * Replace the display title durably. + * @param title - New title; any string, duplicates across workspaces allowed. + * @returns resolution after durability. + */ + setTitle(title: string): Promise; + /** + * Prepend a session to this workspace's candidate account. An already + * accounted id resolves without writing, aside from the durable + * filtered-candidate prune every accepted mutation performs. A new id's + * live or persisted + * header cwd must resolve to an existing directory equal to {@link path}; + * unknown ids, missing or invalid cwd values, and mismatches reject without + * writing. + * @param sessionId - The session to record. + * @returns resolution after durability. + */ + attachSession(sessionId: SessionId): Promise; + /** + * Move an accounted session within the manual order, DOM-insertBefore-like: + * with an anchor the session lands before it, without one it appends to the + * end. Only the moved id changes position. A session or anchor absent from + * the account rejects without writing; a move to the current position + * resolves without writing, aside from the durable filtered-candidate + * prune every accepted mutation performs; decided on the domain write + * chain. + * @param sessionId - The accounted session to move. + * @param beforeSessionId - Accounted anchor to insert before; omitted appends. + * @returns resolution after durability. + */ + insertSessionBefore(sessionId: SessionId, beforeSessionId?: SessionId): Promise; + /** + * Remove a session from this workspace's account. Idempotent: an id not on + * the account resolves without writing, aside from the durable + * filtered-candidate prune every accepted mutation performs; decided on + * the domain write chain like attach. Never touches the session's own stored log. + * @param sessionId - The session to remove. + * @returns resolution after durability. + */ + detachSession(sessionId: SessionId): Promise; + /** + * Live directory check, uncached: whether {@link path} currently exists and + * is a directory. A missing directory never mutates the record — the + * directory may only be temporarily moved. + * @returns `'ok'` when the directory exists, `'missing-dir'` otherwise. + */ + status(): Promise<'ok' | 'missing-dir'>; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.js b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.js new file mode 100644 index 0000000..1777ef5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/lib/types/types.js @@ -0,0 +1,8 @@ +/** + * Public type vocabulary of the workspace entity: the `WorkspaceId` brand and + * the `Workspace` consumer interface. Types only — the `WorkspaceId` factory + * lives in `index.ts` (this file carries no runtime code). + * @module @deepseek-ai/dsh-workspace/src/types + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/node_modules/.bin/cordis new file mode 100755 index 0000000..d9e4347 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../../../../../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/package.json new file mode 100644 index 0000000..24d6524 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace/package.json @@ -0,0 +1,60 @@ +{ + "name": "@deepseek-ai/dsh-workspace", + "description": "Workspace entity registry (ctx.workspaceRegistry): durable workspace records with validated session attachment over the domain data form for the DeepSeek Harness", + "version": "0.1.0-rc.7", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/workspace/workspace" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./types": { + "types": "./lib/types/types.d.ts", + "default": "./lib/types/types.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.7" + }, + "dependencies": { + "zod": "^4.4.3" + }, + "devDependencies": { + "@deepseek-ai/dsh-brand": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.7", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session": "^0.1.0-rc.7", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.7", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.7", + "@deepseek-ai/cordis": "^4.0.1" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/zod new file mode 120000 index 0000000..806bd97 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/zod @@ -0,0 +1 @@ +../../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/cosmokit b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/cosmokit new file mode 120000 index 0000000..dfc2397 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/cosmokit @@ -0,0 +1 @@ +../../../@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/LICENSE new file mode 100644 index 0000000..9fdec8c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-present Shigma + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/README.md b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/README.md new file mode 100644 index 0000000..24fdf36 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/README.md @@ -0,0 +1,389 @@ +# Schemastery + +[![Codecov](https://img.shields.io/codecov/c/github/shigma/schemastery?style=flat-square)](https://codecov.io/gh/shigma/schemastery) +[![downloads](https://img.shields.io/npm/dm/schemastery?style=flat-square)](https://www.npmjs.com/package/schemastery) +[![npm](https://img.shields.io/npm/v/schemastery?style=flat-square)](https://www.npmjs.com/package/schemastery) +[![GitHub](https://img.shields.io/github/license/shigma/schemastery?style=flat-square)](https://github.com/shigma/schemastery/blob/master/LICENSE) + +Type Driven Schema Validator. + +## Features + +- **Lightweight.** Much smaller than other validation libraries. +- **Easy to use.** You can use any schema as a function or constructor directly. +- **Powerful.** Schemastery supports some advanced types such as `union`, `intersect` and `transform`. +- **Extensible.** You can create your own schema types via `Schema.extend()`. +- **Serializable.** Schema objects can be serialized into JSON and then be hydrated in another environment. + +## Basic Examples + +### use as validator (JavaScript) + +```js +const Schema = require('schemastery') + +const validate = Schema.number().default(10) + +validate(0) // 0 +validate(null) // 10 +validate('') // TypeError +``` + +### use as constructor (TypeScript) + +```ts +import Schema from 'schemastery' + +interface Config { + foo: Record + bar: string[] +} + +const Config = Schema.object({ + foo: Schema.dict(Schema.string()).default({}), + bar: Schema.array(Schema.string()).default([]), +}) + +// config is an instance of Config +// in this case, that is { foo: {}, bar: [] } +const config = new Config() +``` + +## General Types + +### Schema.any() + +Assert that the value is of any type. + +```js +const validate = Schema.any() + +validate() // undefined +validate(0) // 0 +validate({}) // {} +``` + +### Schema.never() + +Assert that the value is nullable. + +```js +const validate = Schema.never() + +validate() // undefined +validate(0) // TypeError +validate({}) // TypeError +``` + +### Schema.const(value) + +Assert that the value is equal to the given constant. + +```js +const validate = Schema.const(10) + +validate(10) // 10 +validate(0) // TypeError +``` + +### Schema.number() + +Assert that the value is a number. + +```js +const validate = Schema.number() + +validate() // undefined +validate(1) // 1 +validate('') // TypeError +``` + +### Schema.string() + +Assert that the value is a string. + +```js +const validate = Schema.string() + +validate() // undefined +validate(0) // TypeError +validate('foo') // 'foo' +``` + +### Schema.boolean() + +Assert that the value is a boolean. + +```js +const validate = Schema.boolean() + +validate() // undefined +validate(0) // TypeError +validate(true) // true +``` + +### Schema.is(constructor) + +Assert that the value is an instance of the given constructor. + +```js +const validate = Schema.is(RegExp) + +validate() // undefined +validate(/foo/) // /foo/ +validate('foo') // TypeError +``` + +### Schema.array(inner) + +Assert that the value is an array of `inner`. The default value will be `[]` if not specified. + +```js +const validate = Schema.array(Schema.number()) + +validate() // [] +validate(0) // TypeError +validate([0, 1]) // [0, 1] +validate([0, '1']) // TypeError +``` + +### Schema.dict(inner) + +Assert that the value is a dictionary of `inner`. The default value will be `{}` if not specified. + +```js +const validate = Schema.dict(Schema.number()) + +validate() // {} +validate(0) // TypeError +validate({ a: 0, b: 1 }) // { a: 0, b: 1 } +validate({ a: 0, b: '1' }) // TypeError +``` + +### Schema.tuple(list) + +Assert that the value is a tuple whose each element is of corresponding subtype. The default value will be `[]` if not specified. + +```js +const validate = Schema.tuple([ + Schema.number(), + Schema.string(), +]) + +validate() // [] +validate([0]) // { a: 0 } +validate([0, 1]) // TypeError +validate([0, '1']) // [0, '1'] +``` + +### Schema.object(dict) + +Assert that the value is an object whose each property is of corresponding subtype. The default value will be `{}` if not specified. + +```js +const validate = Schema.object({ + a: Schema.number(), + b: Schema.string(), +}) + +validate() // {} +validate({ a: 0 }) // { a: 0 } +validate({ a: 0, b: 1 }) // TypeError +validate({ a: 0, b: '1' }) // { a: 0, b: '1' } +``` + +### Schema.union(list) + +Assert that the value is one of the specified types. + +```js +const validate = Schema.union([ + Schema.number(), + Schema.string(), +]) + +validate() // undefined +validate(0) // 0 +validate('1') // '1' +validate(true) // TypeError +``` + +### Schema.intersect(list) + +Assert that the value should match each specified type. + +```js +const validate = Schema.intersect([ + Schema.object({ a: Schema.string().required() }), + Schema.object({ b: Schema.number().default(0) }), +]) + +validate() // TypeError +validate({ a: '' }) // { a: '', b: 0 } +validate({ a: '', b: 1 }) // { a: '', b: 1 } +validate({ a: '', b: '2' }) // TypeError +``` + +### Schema.transform(inner, callback) + +Assert that the value is of the specified subtype and then transformed by `callback`. + +```js +const validate = Schema.transform(Schema.number().default(0), n => n + 1) + +validate() // 1 +validate('0') // TypeError +validate(10) // 11 +``` + +## Instance Methods + +Note: `default` and `required` are mutually exclusive. + +### schema.required() + +Assert that the value is not nullable. + +### schema.default(value) + +Set the fallback value when nullable. + +### schema.description(text) + +Set the description of the schema. + +### schema.simplify(value) + +Normalize a value by removing parts that are equal to schema defaults. This is +useful when storing user configuration and keeping persisted files compact. + +```js +const Config = Schema.object({ + foo: Schema.string().default(''), + bar: Schema.number().default(0), +}) + +Config.simplify({ foo: '', bar: 1 }) // { bar: 1 } +``` + +## Validation Options + +All schemas are callable. The second argument accepts validation options: + +```js +const Config = Schema.object({ + foo: Schema.number(), +}) + +Config({ foo: '1' }, { autofix: true }) // {} +``` + +- `autofix`: remove invalid object properties where possible. +- `ignore`: skip validation for selected values and schema nodes. +- `path`: provide an initial path for nested validation errors. + +## Shorthand Syntax + +Some shorthand syntax is available for inner types. + +- `undefined` -> `Schema.any()` +- `String` -> `Schema.string()` +- `Number` -> `Schema.number()` +- `Boolean` -> `Schema.boolean()` +- `1` -> `Schema.const(1)` (only for primitive types) +- `Date` -> `Schema.is(Date)` + +```js +Schema.array(String) // Schema.array(Schema.string()) +Schema.dict(RegExp) // Schema.dict(Schema.is(RegExp)) +Schema.union([1, 2]) // Schema.union([Schema.const(1), Schema.const(2)]) +``` + +You can also use `Schema.from()` to get the inferred schema from a shorthand value. + +```js +Schema.from() // Schema.any() +Schema.from(Date) // Schema.is(Date) +Schema.from('foo') // Schema.const('foo') +``` + +## Advanced Examples + +Here are some examples which demonstrate how to define advanced types. + +### Enumeration + +```js +const Enum = Schema.union(['red', 'blue']) + +Enum('red') // 'red' +Enum('blue') // 'blue' +Enum('green') // TypeError +``` + +### ToString + +```js +const ToString = Schema.transform(Schema.any(), v => String(v)) + +ToString('') // '' +ToString(0) // '0' +ToString({}) // '{}' +``` + +### Listable + +```js +const Listable = Schema.union([ + Schema.array(Number), + Schema.transform(Number, n => [n]), +]).default([]) + +Listable() // [] +Listable(0) // [0] +Listable([1, 2]) // [1, 2] +``` + +### Alias + +```js +const Config = Schema.dict(Number, Schema.union([ + 'foo', + Schema.transform('bar', () => 'foo'), +])) + +Config({ foo: 1 }) // { foo: 1 } +Config({ bar: 2 }) // { foo: 2 } +Config({ bar: '3' }) // TypeError +``` + +## Extensibility + +Custom schema types are registered with `Schema.extend(type, resolve)`. A +resolver receives the input value, schema node, validation options, and a strict +flag. Return `[value]` for accepted input, or `[value, adapted]` when the caller +should write an adapted value back to the source object. + +```js +Schema.extend('trimmed', (data, schema, options) => { + if (typeof data !== 'string') { + throw new Schema.ValidationError(`expected string but got ${data}`, options) + } + return [data.trim()] +}) +``` + +## Serializability + +```js +const schema1 = Schema.object({ + foo: Schema.string(), + bar: Schema.number(), +}) + +// should have the same effect as schema1 +const schema2 = new Schema(JSON.parse(JSON.stringify(schema1))) +``` + +Schemastery also exposes the Standard Schema `~standard` property, so compatible +tools can validate values without depending on Schemastery-specific APIs. diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/index.cjs b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/index.cjs new file mode 100644 index 0000000..3699837 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/index.cjs @@ -0,0 +1,596 @@ +let _deepseek_ai_cosmokit = require("@deepseek-ai/cosmokit"); +//#region lib/types/index.js +const kSchema = Symbol.for("schemastery"); +const kValidationError = Symbol.for("ValidationError"); +globalThis.__schemastery_index__ ??= 0; +globalThis.__schemastery_refs__ = void 0; +var ValidationError = class extends TypeError { + options; + name = "ValidationError"; + constructor(message, options) { + let prefix = "$"; + for (const segment of options.path || []) if (typeof segment === "string") prefix += "." + segment; + else if (typeof segment === "number") prefix += "[" + segment + "]"; + else if (typeof segment === "symbol") prefix += `[Symbol(${segment.toString()})]`; + if (prefix.startsWith(".")) prefix = prefix.slice(1); + super((prefix === "$" ? "" : `${prefix} `) + message); + this.options = options; + } + static is(error) { + return !!error?.[kValidationError]; + } +}; +Object.defineProperty(ValidationError.prototype, kValidationError, { value: true }); +const Schema = function(options) { + const schema = function(data, options = {}) { + return Schema.resolve(data, schema, options)[0]; + }; + if (options.refs) { + const refs = (0, _deepseek_ai_cosmokit.valueMap)(options.refs, (options) => new Schema(options)); + const getRef = (uid) => refs[uid]; + for (const key in refs) { + const options = refs[key]; + options.sKey = getRef(options.sKey); + options.inner = getRef(options.inner); + options.list = options.list && options.list.map(getRef); + options.dict = options.dict && (0, _deepseek_ai_cosmokit.valueMap)(options.dict, getRef); + } + return refs[options.uid]; + } + Object.assign(schema, options); + if (typeof schema.callback === "string") try { + schema.callback = new Function("return " + schema.callback)(); + } catch {} + Object.defineProperty(schema, "uid", { value: globalThis.__schemastery_index__++ }); + Object.setPrototypeOf(schema, Schema.prototype); + schema.meta ||= {}; + schema.toString = schema.toString.bind(schema); + return schema; +}; +Schema.prototype = Object.create(Function.prototype); +Schema.prototype[kSchema] = true; +Object.defineProperty(Schema.prototype, "~standard", { get() { + return { + version: 1, + vendor: "schemastery", + validate: (value) => { + try { + return { value: Schema.resolve(value, this, {})[0] }; + } catch (error) { + if (ValidationError.is(error)) return { issues: [{ + message: error.message, + path: error.options.path + }] }; + throw error; + } + } + }; +} }); +Schema.ValidationError = ValidationError; +Schema.prototype.toJSON = function toJSON() { + if (globalThis.__schemastery_refs__) { + globalThis.__schemastery_refs__[this.uid] ??= JSON.parse(JSON.stringify({ ...this })); + return this.uid; + } + globalThis.__schemastery_refs__ = { [this.uid]: { ...this } }; + globalThis.__schemastery_refs__[this.uid] = JSON.parse(JSON.stringify({ ...this })); + const result = { + uid: this.uid, + refs: globalThis.__schemastery_refs__ + }; + globalThis.__schemastery_refs__ = void 0; + return result; +}; +Schema.prototype.set = function set(key, value) { + this.dict[key] = value; + return this; +}; +Schema.prototype.push = function push(value) { + this.list.push(value); + return this; +}; +function mergeDesc(original, messages) { + const result = typeof original === "string" ? { "": original } : { ...original }; + for (const locale in messages) { + const value = messages[locale]; + if (value?.$description || value?.$desc) result[locale] = value.$description || value.$desc; + else if (typeof value === "string") result[locale] = value; + } + return result; +} +function getInner(value) { + return value?.$value ?? value?.$inner; +} +function extractKeys(data) { + return (0, _deepseek_ai_cosmokit.filterKeys)(data ?? {}, (key) => !key.startsWith("$")); +} +Schema.prototype.i18n = function i18n(messages) { + const schema = Schema(this); + const desc = mergeDesc(schema.meta.description, messages); + if (Object.keys(desc).length) schema.meta.description = desc; + if (schema.dict) schema.dict = (0, _deepseek_ai_cosmokit.valueMap)(schema.dict, (inner, key) => { + return inner.i18n((0, _deepseek_ai_cosmokit.valueMap)(messages, (data) => getInner(data)?.[key] ?? data?.[key])); + }); + if (schema.list) schema.list = schema.list.map((inner, index) => { + return inner.i18n((0, _deepseek_ai_cosmokit.valueMap)(messages, (data = {}) => { + if (Array.isArray(getInner(data))) return getInner(data)[index]; + if (Array.isArray(data)) return data[index]; + return extractKeys(data); + })); + }); + if (schema.inner) schema.inner = schema.inner.i18n((0, _deepseek_ai_cosmokit.valueMap)(messages, (data) => { + if (getInner(data)) return getInner(data); + return extractKeys(data); + })); + if (schema.sKey) schema.sKey = schema.sKey.i18n((0, _deepseek_ai_cosmokit.valueMap)(messages, (data) => data?.$key)); + return schema; +}; +Schema.prototype.extra = function extra(key, value) { + const schema = Schema(this); + schema.meta = { + ...schema.meta, + [key]: value + }; + return schema; +}; +for (const key of [ + "required", + "disabled", + "collapse", + "hidden", + "loose" +]) Object.assign(Schema.prototype, { [key](value = true) { + const schema = Schema(this); + schema.meta = { + ...schema.meta, + [key]: value + }; + return schema; +} }); +Schema.prototype.deprecated = function deprecated() { + const schema = Schema(this); + schema.meta.badges ||= []; + schema.meta.badges.push({ + text: "deprecated", + type: "danger" + }); + return schema; +}; +Schema.prototype.experimental = function experimental() { + const schema = Schema(this); + schema.meta.badges ||= []; + schema.meta.badges.push({ + text: "experimental", + type: "warning" + }); + return schema; +}; +Schema.prototype.pattern = function pattern(regexp) { + const schema = Schema(this); + const pattern = (0, _deepseek_ai_cosmokit.pick)(regexp, ["source", "flags"]); + schema.meta = { + ...schema.meta, + pattern + }; + return schema; +}; +Schema.prototype.simplify = function simplify(value) { + if ((0, _deepseek_ai_cosmokit.deepEqual)(value, this.meta.default, this.type === "dict")) return null; + if ((0, _deepseek_ai_cosmokit.isNullable)(value)) return value; + if (this.type === "object" || this.type === "dict") { + const result = {}; + for (const key in value) { + const item = (this.type === "object" ? this.dict[key] : this.inner)?.simplify(value[key]); + if (this.type === "dict" || !(0, _deepseek_ai_cosmokit.isNullable)(item)) result[key] = item; + } + if ((0, _deepseek_ai_cosmokit.deepEqual)(result, this.meta.default, this.type === "dict")) return null; + return result; + } else if (this.type === "array" || this.type === "tuple") { + const result = []; + value.forEach((value, index) => { + const schema = this.type === "array" ? this.inner : this.list[index]; + const item = schema ? schema.simplify(value) : value; + result.push(item); + }); + return result; + } else if (this.type === "intersect") { + const result = {}; + for (const item of this.list) Object.assign(result, item.simplify(value)); + return result; + } else if (this.type === "union") for (const schema of this.list) try { + Schema.resolve(value, schema, {}); + return schema.simplify(value); + } catch {} + return value; +}; +Schema.prototype.toString = function toString(inline) { + return formatters[this.type]?.(this, inline) ?? `Schema<${this.type}>`; +}; +Schema.prototype.role = function role(role, extra) { + const schema = Schema(this); + schema.meta = { + ...schema.meta, + role, + extra + }; + return schema; +}; +for (const key of [ + "default", + "link", + "comment", + "description", + "max", + "min", + "step" +]) Object.assign(Schema.prototype, { [key](value) { + const schema = Schema(this); + schema.meta = { + ...schema.meta, + [key]: value + }; + return schema; +} }); +const resolvers = {}; +Schema.extend = function extend(type, resolve) { + resolvers[type] = resolve; +}; +Schema.resolve = function resolve(data, schema, options = {}, strict = false) { + if (!schema) return [data]; + if (options.ignore?.(data, schema)) return [data]; + if ((0, _deepseek_ai_cosmokit.isNullable)(data) && schema.type !== "lazy") { + if (schema.meta.required) throw new ValidationError(`missing required value`, options); + let current = schema; + let fallback = schema.meta.default; + while (current?.type === "intersect" && (0, _deepseek_ai_cosmokit.isNullable)(fallback)) { + current = current.list[0]; + fallback = current?.meta.default; + } + if ((0, _deepseek_ai_cosmokit.isNullable)(fallback)) return [data]; + data = (0, _deepseek_ai_cosmokit.clone)(fallback); + } + const callback = resolvers[schema.type]; + if (!callback) throw new ValidationError(`unsupported type "${schema.type}"`, options); + try { + return callback(data, schema, options, strict); + } catch (error) { + if (!schema.meta.loose) throw error; + return [schema.meta.default]; + } +}; +Schema.from = function from(source) { + if ((0, _deepseek_ai_cosmokit.isNullable)(source)) return Schema.any(); + else if ([ + "string", + "number", + "boolean" + ].includes(typeof source)) return Schema.const(source).required(); + else if (source[kSchema]) return source; + else if (typeof source === "function") switch (source) { + case String: return Schema.string().required(); + case Number: return Schema.number().required(); + case Boolean: return Schema.boolean().required(); + case Function: return Schema.function().required(); + default: return Schema.is(source).required(); + } + else throw new TypeError(`cannot infer schema from ${source}`); +}; +Schema.lazy = function lazy(builder) { + const toJSON = () => { + if (!schema.inner[kSchema]) { + schema.inner = schema.builder(); + schema.inner.meta = { + ...schema.meta, + ...schema.inner.meta + }; + } + return schema.inner.toJSON(); + }; + const schema = new Schema({ + type: "lazy", + builder, + inner: { toJSON } + }); + return schema; +}; +Schema.natural = function natural() { + return Schema.number().step(1).min(0); +}; +Schema.percent = function percent() { + return Schema.number().step(.01).min(0).max(1).role("slider"); +}; +Schema.date = function date() { + return Schema.union([Schema.is(Date), Schema.transform(Schema.string().role("datetime"), (value, options) => { + const date = new Date(value); + if (isNaN(+date)) throw new ValidationError(`invalid date "${value}"`, options); + return date; + }, true)]); +}; +Schema.regExp = function regExp(flag = "") { + return Schema.union([Schema.is(RegExp), Schema.transform(Schema.string().role("regexp", { flag }), (value, options) => { + try { + return new RegExp(value, flag); + } catch (e) { + throw new ValidationError(e.message, options); + } + }, true)]); +}; +Schema.arrayBuffer = function arrayBuffer(encoding) { + return Schema.union([ + Schema.is(ArrayBuffer), + Schema.is(SharedArrayBuffer), + Schema.transform(Schema.any(), (value, options) => { + if (_deepseek_ai_cosmokit.Binary.isSource(value)) return _deepseek_ai_cosmokit.Binary.fromSource(value); + throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options); + }, true), + ...encoding ? [Schema.transform(Schema.string(), (value, options) => { + try { + return encoding === "base64" ? _deepseek_ai_cosmokit.Binary.fromBase64(value) : _deepseek_ai_cosmokit.Binary.fromHex(value); + } catch (e) { + throw new ValidationError(e.message, options); + } + }, true)] : [] + ]); +}; +Schema.extend("lazy", (data, schema, options, strict) => { + if (!schema.inner[kSchema]) { + schema.inner = schema.builder(); + schema.inner.meta = { + ...schema.meta, + ...schema.inner.meta + }; + } + return Schema.resolve(data, schema.inner, options, strict); +}); +Schema.extend("any", (data) => { + return [data]; +}); +Schema.extend("never", (data, _, options) => { + throw new ValidationError(`expected nullable but got ${data}`, options); +}); +Schema.extend("const", (data, { value }, options) => { + if ((0, _deepseek_ai_cosmokit.deepEqual)(data, value)) return [value]; + throw new ValidationError(`expected ${value} but got ${data}`, options); +}); +function checkWithinRange(data, meta, description, options, skipMin = false) { + const { max = Infinity, min = -Infinity } = meta; + if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options); + if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options); +} +Schema.extend("string", (data, { meta }, options) => { + if (typeof data !== "string") throw new ValidationError(`expected string but got ${data}`, options); + if (meta.pattern) { + const regexp = new RegExp(meta.pattern.source, meta.pattern.flags); + if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options); + } + checkWithinRange(data.length, meta, "string length", options); + return [data]; +}); +function decimalShift(data, digits) { + const str = data.toString(); + if (str.includes("e")) return data * Math.pow(10, digits); + const index = str.indexOf("."); + if (index === -1) return data * Math.pow(10, digits); + const frac = str.slice(index + 1); + const integer = str.slice(0, index); + if (frac.length <= digits) return +(integer + frac.padEnd(digits, "0")); + return +(integer + frac.slice(0, digits) + "." + frac.slice(digits)); +} +function isMultipleOf(data, min, step) { + step = Math.abs(step); + if (!/^\d+\.\d+$/.test(step.toString())) return (data - min) % step === 0; + const index = step.toString().indexOf("."); + const digits = step.toString().slice(index + 1).length; + return Math.abs(decimalShift(data, digits) - decimalShift(min, digits)) % decimalShift(step, digits) === 0; +} +Schema.extend("number", (data, { meta }, options) => { + if (typeof data !== "number") throw new ValidationError(`expected number but got ${data}`, options); + checkWithinRange(data, meta, "number", options); + const { step } = meta; + if (step && !isMultipleOf(data, meta.min ?? 0, step)) throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options); + return [data]; +}); +Schema.extend("boolean", (data, _, options) => { + if (typeof data === "boolean") return [data]; + throw new ValidationError(`expected boolean but got ${data}`, options); +}); +Schema.extend("bitset", (data, { bits, meta }, options) => { + let value = 0, keys = []; + if (typeof data === "number") { + value = data; + for (const key in bits) if (data & bits[key]) keys.push(key); + } else if (Array.isArray(data)) { + keys = data; + for (const key of keys) { + if (typeof key !== "string") throw new ValidationError(`expected string but got ${key}`, options); + if (key in bits) value |= bits[key]; + } + } else throw new ValidationError(`expected number or array but got ${data}`, options); + if (value === meta.default) return [value]; + return [value, keys]; +}); +Schema.extend("function", (data, _, options) => { + if (typeof data === "function") return [data]; + throw new ValidationError(`expected function but got ${data}`, options); +}); +Schema.extend("is", (data, { constructor }, options) => { + if (typeof constructor === "function") { + if (data instanceof constructor) return [data]; + throw new ValidationError(`expected ${constructor.name} but got ${data}`, options); + } else { + if ((0, _deepseek_ai_cosmokit.isNullable)(data)) throw new ValidationError(`expected ${constructor} but got ${data}`, options); + let prototype = Object.getPrototypeOf(data); + while (prototype) { + if (prototype.constructor?.name === constructor) return [data]; + prototype = Object.getPrototypeOf(prototype); + } + throw new ValidationError(`expected ${constructor} but got ${data}`, options); + } +}); +function property(data, key, schema, options) { + try { + const [value, adapted] = Schema.resolve(data[key], schema, { + ...options, + path: [...options.path || [], key] + }); + if (adapted !== void 0) data[key] = adapted; + return value; + } catch (e) { + if (!options?.autofix) throw e; + delete data[key]; + return schema.meta.default; + } +} +Schema.extend("array", (data, { inner, meta }, options) => { + if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options); + checkWithinRange(data.length, meta, "array length", options, !(0, _deepseek_ai_cosmokit.isNullable)(inner.meta.default)); + return [data.map((_, index) => property(data, index, inner, options))]; +}); +Schema.extend("dict", (data, { inner, sKey }, options, strict) => { + if (!(0, _deepseek_ai_cosmokit.isPlainObject)(data)) throw new ValidationError(`expected object but got ${data}`, options); + const result = {}; + for (const key in data) { + let rKey; + try { + rKey = Schema.resolve(key, sKey, options)[0]; + } catch (error) { + if (strict) continue; + throw error; + } + result[rKey] = property(data, key, inner, options); + data[rKey] = data[key]; + if (key !== rKey) delete data[key]; + } + return [result]; +}); +Schema.extend("tuple", (data, { list }, options, strict) => { + if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options); + const result = list.map((inner, index) => property(data, index, inner, options)); + if (strict) return [result]; + result.push(...data.slice(list.length)); + return [result]; +}); +function merge(result, data) { + for (const key in data) { + if (key in result) continue; + result[key] = data[key]; + } +} +Schema.extend("object", (data, { dict }, options, strict) => { + if (!(0, _deepseek_ai_cosmokit.isPlainObject)(data)) throw new ValidationError(`expected object but got ${data}`, options); + const result = {}; + for (const key in dict) { + const value = property(data, key, dict[key], options); + if (!(0, _deepseek_ai_cosmokit.isNullable)(value) || key in data) result[key] = value; + } + if (!strict) merge(result, data); + return [result]; +}); +Schema.extend("union", (data, { list, toString }, options, strict) => { + const messages = []; + for (const inner of list) try { + return Schema.resolve(data, inner, options, strict); + } catch (error) { + messages.push(error); + } + throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options); +}); +Schema.extend("intersect", (data, { list, toString }, options, strict) => { + if (!list.length) return [data]; + let result; + for (const inner of list) { + const value = Schema.resolve(data, inner, options, true)[0]; + if ((0, _deepseek_ai_cosmokit.isNullable)(value)) continue; + if ((0, _deepseek_ai_cosmokit.isNullable)(result)) result = value; + else if (typeof result !== typeof value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options); + else if (typeof value === "object") merge(result ??= {}, value); + else if (result !== value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options); + } + if (!strict && (0, _deepseek_ai_cosmokit.isPlainObject)(data)) merge(result, data); + return [result]; +}); +Schema.extend("transform", (data, { inner, callback, preserve }, options) => { + const [result, adapted = data] = Schema.resolve(data, inner, options, true); + if (preserve) return [callback(result)]; + else return [callback(result), callback(adapted)]; +}); +const formatters = {}; +function defineMethod(name, keys, format) { + formatters[name] = format; + Object.assign(Schema, { [name](...args) { + const schema = new Schema({ type: name }); + keys.forEach((key, index) => { + switch (key) { + case "sKey": + schema.sKey = args[index] ?? Schema.string(); + break; + case "inner": + schema.inner = Schema.from(args[index]); + break; + case "list": + schema.list = args[index].map(Schema.from); + break; + case "dict": + schema.dict = (0, _deepseek_ai_cosmokit.valueMap)(args[index], Schema.from); + break; + case "bits": + schema.bits = {}; + for (const key in args[index]) { + if (typeof args[index][key] !== "number") continue; + schema.bits[key] = args[index][key]; + } + break; + case "callback": { + const callback = schema.callback = args[index]; + callback["toJSON"] ||= () => callback.toString(); + break; + } + case "constructor": { + const constructor = schema.constructor = args[index]; + if (typeof constructor === "function") constructor["toJSON"] ||= () => constructor["name"]; + break; + } + default: schema[key] = args[index]; + } + }); + if (name === "object" || name === "dict") schema.meta.default = {}; + else if (name === "array" || name === "tuple") schema.meta.default = []; + else if (name === "bitset") schema.meta.default = 0; + return schema; + } }); +} +defineMethod("is", ["constructor"], ({ constructor }) => { + if (typeof constructor === "function") return constructor.name; + else return constructor; +}); +defineMethod("any", [], () => "any"); +defineMethod("never", [], () => "never"); +defineMethod("const", ["value"], ({ value }) => typeof value === "string" ? JSON.stringify(value) : value); +defineMethod("string", [], () => "string"); +defineMethod("number", [], () => "number"); +defineMethod("boolean", [], () => "boolean"); +defineMethod("bitset", ["bits"], () => "bitset"); +defineMethod("function", [], () => "function"); +defineMethod("array", ["inner"], ({ inner }) => `${inner.toString(true)}[]`); +defineMethod("dict", ["inner", "sKey"], ({ inner, sKey }) => `{ [key: ${sKey.toString()}]: ${inner.toString()} }`); +defineMethod("tuple", ["list"], ({ list }) => `[${list.map((inner) => inner.toString()).join(", ")}]`); +defineMethod("object", ["dict"], ({ dict }) => { + if (Object.keys(dict).length === 0) return "{}"; + return `{ ${Object.entries(dict).map(([key, inner]) => { + return `${key}${inner.meta.required ? "" : "?"}: ${inner.toString()}`; + }).join(", ")} }`; +}); +defineMethod("union", ["list"], ({ list }, inline) => { + const result = list.map(({ toString: format }) => format()).join(" | "); + return inline ? `(${result})` : result; +}); +defineMethod("intersect", ["list"], ({ list }) => { + return `${list.map((inner) => inner.toString(true)).join(" & ")}`; +}); +defineMethod("transform", [ + "inner", + "callback", + "preserve" +], ({ inner }, isInner) => inner.toString(isInner)); +//#endregion +module.exports = Schema; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/index.mjs b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/index.mjs new file mode 100644 index 0000000..3fd964c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/index.mjs @@ -0,0 +1,596 @@ +import { Binary, clone, deepEqual, filterKeys, isNullable, isPlainObject, pick, valueMap } from "@deepseek-ai/cosmokit"; +//#region lib/types/index.js +const kSchema = Symbol.for("schemastery"); +const kValidationError = Symbol.for("ValidationError"); +globalThis.__schemastery_index__ ??= 0; +globalThis.__schemastery_refs__ = void 0; +var ValidationError = class extends TypeError { + options; + name = "ValidationError"; + constructor(message, options) { + let prefix = "$"; + for (const segment of options.path || []) if (typeof segment === "string") prefix += "." + segment; + else if (typeof segment === "number") prefix += "[" + segment + "]"; + else if (typeof segment === "symbol") prefix += `[Symbol(${segment.toString()})]`; + if (prefix.startsWith(".")) prefix = prefix.slice(1); + super((prefix === "$" ? "" : `${prefix} `) + message); + this.options = options; + } + static is(error) { + return !!error?.[kValidationError]; + } +}; +Object.defineProperty(ValidationError.prototype, kValidationError, { value: true }); +const Schema = function(options) { + const schema = function(data, options = {}) { + return Schema.resolve(data, schema, options)[0]; + }; + if (options.refs) { + const refs = valueMap(options.refs, (options) => new Schema(options)); + const getRef = (uid) => refs[uid]; + for (const key in refs) { + const options = refs[key]; + options.sKey = getRef(options.sKey); + options.inner = getRef(options.inner); + options.list = options.list && options.list.map(getRef); + options.dict = options.dict && valueMap(options.dict, getRef); + } + return refs[options.uid]; + } + Object.assign(schema, options); + if (typeof schema.callback === "string") try { + schema.callback = new Function("return " + schema.callback)(); + } catch {} + Object.defineProperty(schema, "uid", { value: globalThis.__schemastery_index__++ }); + Object.setPrototypeOf(schema, Schema.prototype); + schema.meta ||= {}; + schema.toString = schema.toString.bind(schema); + return schema; +}; +Schema.prototype = Object.create(Function.prototype); +Schema.prototype[kSchema] = true; +Object.defineProperty(Schema.prototype, "~standard", { get() { + return { + version: 1, + vendor: "schemastery", + validate: (value) => { + try { + return { value: Schema.resolve(value, this, {})[0] }; + } catch (error) { + if (ValidationError.is(error)) return { issues: [{ + message: error.message, + path: error.options.path + }] }; + throw error; + } + } + }; +} }); +Schema.ValidationError = ValidationError; +Schema.prototype.toJSON = function toJSON() { + if (globalThis.__schemastery_refs__) { + globalThis.__schemastery_refs__[this.uid] ??= JSON.parse(JSON.stringify({ ...this })); + return this.uid; + } + globalThis.__schemastery_refs__ = { [this.uid]: { ...this } }; + globalThis.__schemastery_refs__[this.uid] = JSON.parse(JSON.stringify({ ...this })); + const result = { + uid: this.uid, + refs: globalThis.__schemastery_refs__ + }; + globalThis.__schemastery_refs__ = void 0; + return result; +}; +Schema.prototype.set = function set(key, value) { + this.dict[key] = value; + return this; +}; +Schema.prototype.push = function push(value) { + this.list.push(value); + return this; +}; +function mergeDesc(original, messages) { + const result = typeof original === "string" ? { "": original } : { ...original }; + for (const locale in messages) { + const value = messages[locale]; + if (value?.$description || value?.$desc) result[locale] = value.$description || value.$desc; + else if (typeof value === "string") result[locale] = value; + } + return result; +} +function getInner(value) { + return value?.$value ?? value?.$inner; +} +function extractKeys(data) { + return filterKeys(data ?? {}, (key) => !key.startsWith("$")); +} +Schema.prototype.i18n = function i18n(messages) { + const schema = Schema(this); + const desc = mergeDesc(schema.meta.description, messages); + if (Object.keys(desc).length) schema.meta.description = desc; + if (schema.dict) schema.dict = valueMap(schema.dict, (inner, key) => { + return inner.i18n(valueMap(messages, (data) => getInner(data)?.[key] ?? data?.[key])); + }); + if (schema.list) schema.list = schema.list.map((inner, index) => { + return inner.i18n(valueMap(messages, (data = {}) => { + if (Array.isArray(getInner(data))) return getInner(data)[index]; + if (Array.isArray(data)) return data[index]; + return extractKeys(data); + })); + }); + if (schema.inner) schema.inner = schema.inner.i18n(valueMap(messages, (data) => { + if (getInner(data)) return getInner(data); + return extractKeys(data); + })); + if (schema.sKey) schema.sKey = schema.sKey.i18n(valueMap(messages, (data) => data?.$key)); + return schema; +}; +Schema.prototype.extra = function extra(key, value) { + const schema = Schema(this); + schema.meta = { + ...schema.meta, + [key]: value + }; + return schema; +}; +for (const key of [ + "required", + "disabled", + "collapse", + "hidden", + "loose" +]) Object.assign(Schema.prototype, { [key](value = true) { + const schema = Schema(this); + schema.meta = { + ...schema.meta, + [key]: value + }; + return schema; +} }); +Schema.prototype.deprecated = function deprecated() { + const schema = Schema(this); + schema.meta.badges ||= []; + schema.meta.badges.push({ + text: "deprecated", + type: "danger" + }); + return schema; +}; +Schema.prototype.experimental = function experimental() { + const schema = Schema(this); + schema.meta.badges ||= []; + schema.meta.badges.push({ + text: "experimental", + type: "warning" + }); + return schema; +}; +Schema.prototype.pattern = function pattern(regexp) { + const schema = Schema(this); + const pattern = pick(regexp, ["source", "flags"]); + schema.meta = { + ...schema.meta, + pattern + }; + return schema; +}; +Schema.prototype.simplify = function simplify(value) { + if (deepEqual(value, this.meta.default, this.type === "dict")) return null; + if (isNullable(value)) return value; + if (this.type === "object" || this.type === "dict") { + const result = {}; + for (const key in value) { + const item = (this.type === "object" ? this.dict[key] : this.inner)?.simplify(value[key]); + if (this.type === "dict" || !isNullable(item)) result[key] = item; + } + if (deepEqual(result, this.meta.default, this.type === "dict")) return null; + return result; + } else if (this.type === "array" || this.type === "tuple") { + const result = []; + value.forEach((value, index) => { + const schema = this.type === "array" ? this.inner : this.list[index]; + const item = schema ? schema.simplify(value) : value; + result.push(item); + }); + return result; + } else if (this.type === "intersect") { + const result = {}; + for (const item of this.list) Object.assign(result, item.simplify(value)); + return result; + } else if (this.type === "union") for (const schema of this.list) try { + Schema.resolve(value, schema, {}); + return schema.simplify(value); + } catch {} + return value; +}; +Schema.prototype.toString = function toString(inline) { + return formatters[this.type]?.(this, inline) ?? `Schema<${this.type}>`; +}; +Schema.prototype.role = function role(role, extra) { + const schema = Schema(this); + schema.meta = { + ...schema.meta, + role, + extra + }; + return schema; +}; +for (const key of [ + "default", + "link", + "comment", + "description", + "max", + "min", + "step" +]) Object.assign(Schema.prototype, { [key](value) { + const schema = Schema(this); + schema.meta = { + ...schema.meta, + [key]: value + }; + return schema; +} }); +const resolvers = {}; +Schema.extend = function extend(type, resolve) { + resolvers[type] = resolve; +}; +Schema.resolve = function resolve(data, schema, options = {}, strict = false) { + if (!schema) return [data]; + if (options.ignore?.(data, schema)) return [data]; + if (isNullable(data) && schema.type !== "lazy") { + if (schema.meta.required) throw new ValidationError(`missing required value`, options); + let current = schema; + let fallback = schema.meta.default; + while (current?.type === "intersect" && isNullable(fallback)) { + current = current.list[0]; + fallback = current?.meta.default; + } + if (isNullable(fallback)) return [data]; + data = clone(fallback); + } + const callback = resolvers[schema.type]; + if (!callback) throw new ValidationError(`unsupported type "${schema.type}"`, options); + try { + return callback(data, schema, options, strict); + } catch (error) { + if (!schema.meta.loose) throw error; + return [schema.meta.default]; + } +}; +Schema.from = function from(source) { + if (isNullable(source)) return Schema.any(); + else if ([ + "string", + "number", + "boolean" + ].includes(typeof source)) return Schema.const(source).required(); + else if (source[kSchema]) return source; + else if (typeof source === "function") switch (source) { + case String: return Schema.string().required(); + case Number: return Schema.number().required(); + case Boolean: return Schema.boolean().required(); + case Function: return Schema.function().required(); + default: return Schema.is(source).required(); + } + else throw new TypeError(`cannot infer schema from ${source}`); +}; +Schema.lazy = function lazy(builder) { + const toJSON = () => { + if (!schema.inner[kSchema]) { + schema.inner = schema.builder(); + schema.inner.meta = { + ...schema.meta, + ...schema.inner.meta + }; + } + return schema.inner.toJSON(); + }; + const schema = new Schema({ + type: "lazy", + builder, + inner: { toJSON } + }); + return schema; +}; +Schema.natural = function natural() { + return Schema.number().step(1).min(0); +}; +Schema.percent = function percent() { + return Schema.number().step(.01).min(0).max(1).role("slider"); +}; +Schema.date = function date() { + return Schema.union([Schema.is(Date), Schema.transform(Schema.string().role("datetime"), (value, options) => { + const date = new Date(value); + if (isNaN(+date)) throw new ValidationError(`invalid date "${value}"`, options); + return date; + }, true)]); +}; +Schema.regExp = function regExp(flag = "") { + return Schema.union([Schema.is(RegExp), Schema.transform(Schema.string().role("regexp", { flag }), (value, options) => { + try { + return new RegExp(value, flag); + } catch (e) { + throw new ValidationError(e.message, options); + } + }, true)]); +}; +Schema.arrayBuffer = function arrayBuffer(encoding) { + return Schema.union([ + Schema.is(ArrayBuffer), + Schema.is(SharedArrayBuffer), + Schema.transform(Schema.any(), (value, options) => { + if (Binary.isSource(value)) return Binary.fromSource(value); + throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options); + }, true), + ...encoding ? [Schema.transform(Schema.string(), (value, options) => { + try { + return encoding === "base64" ? Binary.fromBase64(value) : Binary.fromHex(value); + } catch (e) { + throw new ValidationError(e.message, options); + } + }, true)] : [] + ]); +}; +Schema.extend("lazy", (data, schema, options, strict) => { + if (!schema.inner[kSchema]) { + schema.inner = schema.builder(); + schema.inner.meta = { + ...schema.meta, + ...schema.inner.meta + }; + } + return Schema.resolve(data, schema.inner, options, strict); +}); +Schema.extend("any", (data) => { + return [data]; +}); +Schema.extend("never", (data, _, options) => { + throw new ValidationError(`expected nullable but got ${data}`, options); +}); +Schema.extend("const", (data, { value }, options) => { + if (deepEqual(data, value)) return [value]; + throw new ValidationError(`expected ${value} but got ${data}`, options); +}); +function checkWithinRange(data, meta, description, options, skipMin = false) { + const { max = Infinity, min = -Infinity } = meta; + if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options); + if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options); +} +Schema.extend("string", (data, { meta }, options) => { + if (typeof data !== "string") throw new ValidationError(`expected string but got ${data}`, options); + if (meta.pattern) { + const regexp = new RegExp(meta.pattern.source, meta.pattern.flags); + if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options); + } + checkWithinRange(data.length, meta, "string length", options); + return [data]; +}); +function decimalShift(data, digits) { + const str = data.toString(); + if (str.includes("e")) return data * Math.pow(10, digits); + const index = str.indexOf("."); + if (index === -1) return data * Math.pow(10, digits); + const frac = str.slice(index + 1); + const integer = str.slice(0, index); + if (frac.length <= digits) return +(integer + frac.padEnd(digits, "0")); + return +(integer + frac.slice(0, digits) + "." + frac.slice(digits)); +} +function isMultipleOf(data, min, step) { + step = Math.abs(step); + if (!/^\d+\.\d+$/.test(step.toString())) return (data - min) % step === 0; + const index = step.toString().indexOf("."); + const digits = step.toString().slice(index + 1).length; + return Math.abs(decimalShift(data, digits) - decimalShift(min, digits)) % decimalShift(step, digits) === 0; +} +Schema.extend("number", (data, { meta }, options) => { + if (typeof data !== "number") throw new ValidationError(`expected number but got ${data}`, options); + checkWithinRange(data, meta, "number", options); + const { step } = meta; + if (step && !isMultipleOf(data, meta.min ?? 0, step)) throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options); + return [data]; +}); +Schema.extend("boolean", (data, _, options) => { + if (typeof data === "boolean") return [data]; + throw new ValidationError(`expected boolean but got ${data}`, options); +}); +Schema.extend("bitset", (data, { bits, meta }, options) => { + let value = 0, keys = []; + if (typeof data === "number") { + value = data; + for (const key in bits) if (data & bits[key]) keys.push(key); + } else if (Array.isArray(data)) { + keys = data; + for (const key of keys) { + if (typeof key !== "string") throw new ValidationError(`expected string but got ${key}`, options); + if (key in bits) value |= bits[key]; + } + } else throw new ValidationError(`expected number or array but got ${data}`, options); + if (value === meta.default) return [value]; + return [value, keys]; +}); +Schema.extend("function", (data, _, options) => { + if (typeof data === "function") return [data]; + throw new ValidationError(`expected function but got ${data}`, options); +}); +Schema.extend("is", (data, { constructor }, options) => { + if (typeof constructor === "function") { + if (data instanceof constructor) return [data]; + throw new ValidationError(`expected ${constructor.name} but got ${data}`, options); + } else { + if (isNullable(data)) throw new ValidationError(`expected ${constructor} but got ${data}`, options); + let prototype = Object.getPrototypeOf(data); + while (prototype) { + if (prototype.constructor?.name === constructor) return [data]; + prototype = Object.getPrototypeOf(prototype); + } + throw new ValidationError(`expected ${constructor} but got ${data}`, options); + } +}); +function property(data, key, schema, options) { + try { + const [value, adapted] = Schema.resolve(data[key], schema, { + ...options, + path: [...options.path || [], key] + }); + if (adapted !== void 0) data[key] = adapted; + return value; + } catch (e) { + if (!options?.autofix) throw e; + delete data[key]; + return schema.meta.default; + } +} +Schema.extend("array", (data, { inner, meta }, options) => { + if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options); + checkWithinRange(data.length, meta, "array length", options, !isNullable(inner.meta.default)); + return [data.map((_, index) => property(data, index, inner, options))]; +}); +Schema.extend("dict", (data, { inner, sKey }, options, strict) => { + if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options); + const result = {}; + for (const key in data) { + let rKey; + try { + rKey = Schema.resolve(key, sKey, options)[0]; + } catch (error) { + if (strict) continue; + throw error; + } + result[rKey] = property(data, key, inner, options); + data[rKey] = data[key]; + if (key !== rKey) delete data[key]; + } + return [result]; +}); +Schema.extend("tuple", (data, { list }, options, strict) => { + if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options); + const result = list.map((inner, index) => property(data, index, inner, options)); + if (strict) return [result]; + result.push(...data.slice(list.length)); + return [result]; +}); +function merge(result, data) { + for (const key in data) { + if (key in result) continue; + result[key] = data[key]; + } +} +Schema.extend("object", (data, { dict }, options, strict) => { + if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options); + const result = {}; + for (const key in dict) { + const value = property(data, key, dict[key], options); + if (!isNullable(value) || key in data) result[key] = value; + } + if (!strict) merge(result, data); + return [result]; +}); +Schema.extend("union", (data, { list, toString }, options, strict) => { + const messages = []; + for (const inner of list) try { + return Schema.resolve(data, inner, options, strict); + } catch (error) { + messages.push(error); + } + throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options); +}); +Schema.extend("intersect", (data, { list, toString }, options, strict) => { + if (!list.length) return [data]; + let result; + for (const inner of list) { + const value = Schema.resolve(data, inner, options, true)[0]; + if (isNullable(value)) continue; + if (isNullable(result)) result = value; + else if (typeof result !== typeof value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options); + else if (typeof value === "object") merge(result ??= {}, value); + else if (result !== value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options); + } + if (!strict && isPlainObject(data)) merge(result, data); + return [result]; +}); +Schema.extend("transform", (data, { inner, callback, preserve }, options) => { + const [result, adapted = data] = Schema.resolve(data, inner, options, true); + if (preserve) return [callback(result)]; + else return [callback(result), callback(adapted)]; +}); +const formatters = {}; +function defineMethod(name, keys, format) { + formatters[name] = format; + Object.assign(Schema, { [name](...args) { + const schema = new Schema({ type: name }); + keys.forEach((key, index) => { + switch (key) { + case "sKey": + schema.sKey = args[index] ?? Schema.string(); + break; + case "inner": + schema.inner = Schema.from(args[index]); + break; + case "list": + schema.list = args[index].map(Schema.from); + break; + case "dict": + schema.dict = valueMap(args[index], Schema.from); + break; + case "bits": + schema.bits = {}; + for (const key in args[index]) { + if (typeof args[index][key] !== "number") continue; + schema.bits[key] = args[index][key]; + } + break; + case "callback": { + const callback = schema.callback = args[index]; + callback["toJSON"] ||= () => callback.toString(); + break; + } + case "constructor": { + const constructor = schema.constructor = args[index]; + if (typeof constructor === "function") constructor["toJSON"] ||= () => constructor["name"]; + break; + } + default: schema[key] = args[index]; + } + }); + if (name === "object" || name === "dict") schema.meta.default = {}; + else if (name === "array" || name === "tuple") schema.meta.default = []; + else if (name === "bitset") schema.meta.default = 0; + return schema; + } }); +} +defineMethod("is", ["constructor"], ({ constructor }) => { + if (typeof constructor === "function") return constructor.name; + else return constructor; +}); +defineMethod("any", [], () => "any"); +defineMethod("never", [], () => "never"); +defineMethod("const", ["value"], ({ value }) => typeof value === "string" ? JSON.stringify(value) : value); +defineMethod("string", [], () => "string"); +defineMethod("number", [], () => "number"); +defineMethod("boolean", [], () => "boolean"); +defineMethod("bitset", ["bits"], () => "bitset"); +defineMethod("function", [], () => "function"); +defineMethod("array", ["inner"], ({ inner }) => `${inner.toString(true)}[]`); +defineMethod("dict", ["inner", "sKey"], ({ inner, sKey }) => `{ [key: ${sKey.toString()}]: ${inner.toString()} }`); +defineMethod("tuple", ["list"], ({ list }) => `[${list.map((inner) => inner.toString()).join(", ")}]`); +defineMethod("object", ["dict"], ({ dict }) => { + if (Object.keys(dict).length === 0) return "{}"; + return `{ ${Object.entries(dict).map(([key, inner]) => { + return `${key}${inner.meta.required ? "" : "?"}: ${inner.toString()}`; + }).join(", ")} }`; +}); +defineMethod("union", ["list"], ({ list }, inline) => { + const result = list.map(({ toString: format }) => format()).join(" | "); + return inline ? `(${result})` : result; +}); +defineMethod("intersect", ["list"], ({ list }) => { + return `${list.map((inner) => inner.toString(true)).join(" & ")}`; +}); +defineMethod("transform", [ + "inner", + "callback", + "preserve" +], ({ inner }, isInner) => inner.toString(isInner)); +//#endregion +export { Schema as default }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts new file mode 100644 index 0000000..9e9fa80 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts @@ -0,0 +1,200 @@ +import { Binary, type Dict } from '@deepseek-ai/cosmokit'; +import type { StandardSchemaV1 } from '@standard-schema/spec'; +declare const kSchema: unique symbol; +declare global { + namespace Schemastery { + /** Convert primitive constructors, constants, and existing schemas into a schema type. */ + type From = X extends string | number | boolean ? Schema : X extends Schema ? X : X extends typeof String ? Schema : X extends typeof Number ? Schema : X extends typeof Boolean ? Schema : X extends typeof Function ? Schema any> : X extends Constructor ? Schema : never; + type TypeS1 = X extends Schema ? S : never; + type Inverse = X extends Schema ? (arg: Y) => void : never; + /** Input type accepted by a schema-like value. */ + type TypeS = TypeS1>; + /** Output type returned by a schema-like value after validation. */ + type TypeT = ReturnType>; + /** Resolver callback used by custom schema types registered with `Schema.extend()`. */ + type Resolve = (data: any, schema: Schema, options: Options, strict?: boolean) => [any, any?]; + /** Input type accepted by one schema in an intersection. */ + type IntersectS = From extends Schema ? S : never; + /** Output type returned by one schema in an intersection. */ + type IntersectT = Inverse> extends ((arg: infer T) => void) ? T : never; + type TupleS = X extends readonly [infer L, ...infer R] ? [TypeS?, ...TupleS] : any[]; + type TupleT = X extends readonly [infer L, ...infer R] ? [TypeT?, ...TupleT] : any[]; + type ObjectS = { + [K in keyof X]?: TypeS | null; + } & Dict; + type ObjectT = { + [K in keyof X]: TypeT; + } & Dict; + type Constructor = new (...args: any[]) => T; + /** Static constructor and factory methods exposed by the default `Schema` export. */ + interface Static { + (options: Partial>): Schema; + new (options: Partial>): Schema; + prototype: Schema; + /** Validate a value against a schema node and return `[output, adaptedInput?]`. */ + resolve: Resolve; + /** Infer a schema from a primitive value, constructor, or existing schema. */ + from(source?: X): From; + /** Register a resolver for a custom schema `type`. */ + extend(type: string, resolve: Resolve): void; + /** Accept any value without validation. */ + any(): Schema; + /** Accept only nullable input. */ + never(): Schema; + /** Accept exactly one constant value. */ + const(value: T): Schema; + /** Accept strings, with optional metadata constraints added by instance methods. */ + string(): Schema; + /** Accept numbers, with optional range and step constraints. */ + number(): Schema; + /** Accept non-negative integer numbers. */ + natural(): Schema; + /** Accept a number between 0 and 1 and mark it as a slider. */ + percent(): Schema; + /** Accept booleans. */ + boolean(): Schema; + /** Accept `Date` instances or parse datetime strings into `Date` objects. */ + date(): Schema; + /** Accept `RegExp` instances or parse strings into regular expressions. */ + regExp(flag?: string): Schema; + /** Accept binary sources and normalize them to `ArrayBufferLike`. */ + arrayBuffer(): Schema; + arrayBuffer(encoding: 'hex' | 'base64'): Schema; + /** Accept a numeric bitset or string keys and normalize to a number. */ + bitset(bits: Partial>): Schema; + /** Accept functions. */ + function(): Schema any>; + /** Accept instances of a constructor or objects whose constructor name matches. */ + is(constructor: string): Schema; + is(constructor: Constructor): Schema; + /** Accept arrays whose elements match `inner`. */ + array(inner: X): Schema[], TypeT[]>; + /** Accept plain objects with values matching `inner` and optional key schema. */ + dict = Schema>(inner: X, sKey?: Y): Schema, TypeS>, Dict, TypeT>>; + /** Accept tuple arrays where each index matches the corresponding schema. */ + tuple(list: X): Schema, TupleT>; + /** Accept plain objects whose declared properties match the schema dictionary. */ + object(dict: X): Schema, ObjectT>; + /** Accept values matching at least one schema in `list`. */ + union(list: readonly X[]): Schema, TypeT>; + /** Accept values matching every schema in `list`, merging object outputs. */ + intersect(list: readonly X[]): Schema, IntersectT>; + /** Validate with `inner`, then convert the result with `callback`. */ + transform(inner: X, callback: (value: TypeS, options: Schemastery.Options) => T, preserve?: boolean): Schema, T>; + /** Defer construction of a recursive schema until validation or serialization. */ + lazy(callback: () => X): X; + ValidationError: typeof ValidationError; + } + /** Runtime validation options shared by all schema calls. */ + interface Options { + /** Remove invalid object properties instead of throwing when possible. */ + autofix?: boolean; + /** Skip validation for selected values and schema nodes. */ + ignore?(data: any, schema: Schema): boolean; + /** Path used to format nested validation errors. */ + path?: (keyof any)[]; + } + /** UI and validation metadata attached by schema builder methods. */ + interface Meta { + default?: T extends {} ? Partial : T; + required?: boolean; + disabled?: boolean; + collapse?: boolean; + badges?: { + text: string; + type: string; + }[]; + hidden?: boolean; + loose?: boolean; + role?: string; + extra?: any; + link?: string; + description?: string | Dict; + comment?: string; + pattern?: { + source: string; + flags?: string; + }; + max?: number; + min?: number; + step?: number; + } + } + /** Callable schema instance that validates input and returns normalized output. */ + interface Schemastery { + (data?: S | null, options?: Schemastery.Options): T; + new (data?: S | null, options?: Schemastery.Options): T; + [kSchema]: true; + uid: number; + meta: Schemastery.Meta; + type: string; + sKey?: Schema; + inner?: Schema; + list?: Schema[]; + dict?: Dict; + bits?: Dict; + callback?: Function; + constructor?: string | Function; + builder?: Function; + value?: T; + refs?: Dict; + preserve?: boolean; + '~standard': StandardSchemaV1.Props; + /** Format this schema as a compact TypeScript-like type string. */ + toString(inline?: boolean): string; + /** Serialize this schema, preserving shared and recursive references. */ + toJSON(): Schema; + /** Mark nullable input as invalid unless a default supplies a fallback. */ + required(value?: boolean): Schema; + /** Hide this schema node from UI renderers. */ + hidden(value?: boolean): Schema; + /** Return the default value instead of throwing when validation fails. */ + loose(value?: boolean): Schema; + /** Attach a renderer role and optional role-specific metadata. */ + role(text: string, extra?: any): Schema; + /** Attach an external documentation link. */ + link(link: string): Schema; + /** Set the fallback value used for nullable input. */ + default(value: T): Schema; + /** Attach an auxiliary comment for documentation or form UIs. */ + comment(text: string): Schema; + /** Attach a localized or plain description for documentation or form UIs. */ + description(text: string): Schema; + /** Mark this schema node as disabled for form UIs. */ + disabled(value?: boolean): Schema; + /** Request collapsed rendering for nested form UIs. */ + collapse(value?: boolean): Schema; + /** Add a deprecated badge to this schema node. */ + deprecated(): Schema; + /** Add an experimental badge to this schema node. */ + experimental(): Schema; + /** Require strings to match a regular expression. */ + pattern(regexp: RegExp): Schema; + /** Set an inclusive maximum for numbers or collection lengths. */ + max(value: number): Schema; + /** Set an inclusive minimum for numbers or collection lengths. */ + min(value: number): Schema; + /** Set the numeric increment constraint. */ + step(value: number): Schema; + /** Add or replace an object property schema. */ + set(key: string, value: Schema): Schema; + /** Append a tuple, union, or intersection member schema. */ + push(value: Schema): Schema; + /** Remove values equal to schema defaults from normalized output. */ + simplify(value?: any): any; + /** Return a schema clone with descriptions merged from locale messages. */ + i18n(messages: Dict): Schema; + /** Attach arbitrary metadata consumed by form renderers and downstream tools. */ + extra(key: K, value: Schemastery.Meta[K]): Schema; + } +} +declare class ValidationError extends TypeError { + options: Schemastery.Options; + name: string; + constructor(message: string, options: Schemastery.Options); + static is(error: any): error is ValidationError; +} +type Schema = Schemastery; +declare const Schema: Schemastery.Static; +export default Schema; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts.map b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts.map new file mode 100644 index 0000000..350f4b7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA2E,KAAK,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAClI,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAE7D,QAAA,MAAM,OAAO,eAA4B,CAAA;AAGzC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,WAAW,CAAC;QACpB,0FAA0F;QAC1F,KAAY,IAAI,CAAC,CAAC,IACd,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,GAC/C,CAAC,SAAS,MAAM,GAAG,CAAC,GACpB,CAAC,SAAS,OAAO,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GACxC,CAAC,SAAS,OAAO,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GACxC,CAAC,SAAS,OAAO,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAC1C,CAAC,SAAS,OAAO,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GACrE,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAC1C,KAAK,CAAA;QAET,KAAK,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QAC/D,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,CAAA;QAE3E,kDAAkD;QAClD,KAAY,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QACtC,oEAAoE;QACpE,KAAY,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QAC1C,uFAAuF;QACvF,KAAY,OAAO,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;QAEpG,4DAA4D;QAC5D,KAAY,UAAU,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QAChF,6DAA6D;QAC7D,KAAY,UAAU,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QAEzF,KAAK,MAAM,CAAC,CAAC,SAAS,SAAS,GAAG,EAAE,IAAI,CAAC,SAAS,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAA;QACpH,KAAK,MAAM,CAAC,CAAC,SAAS,SAAS,GAAG,EAAE,IAAI,CAAC,SAAS,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAA;QACpH,KAAK,OAAO,CAAC,CAAC,SAAS,IAAI,IAAI;aAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;SAAE,GAAG,IAAI,CAAA;QAC7E,KAAK,OAAO,CAAC,CAAC,SAAS,IAAI,IAAI;aAAG,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAAE,GAAG,IAAI,CAAA;QACrE,KAAK,WAAW,CAAC,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;QAErD,qFAAqF;QACrF,UAAiB,MAAM;YACrB,CAAC,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;YACjD,KAAK,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;YACrD,SAAS,EAAE,MAAM,CAAA;YACjB,mFAAmF;YACnF,OAAO,EAAE,OAAO,CAAA;YAChB,8EAA8E;YAC9E,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YAClC,sDAAsD;YACtD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;YAC5C,2CAA2C;YAC3C,GAAG,CAAC,CAAC,GAAG,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,CAAA;YACzB,kCAAkC;YAClC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAA;YACtB,yCAAyC;YACzC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;YACnC,oFAAoF;YACpF,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,CAAA;YACxB,gEAAgE;YAChE,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,CAAA;YACxB,2CAA2C;YAC3C,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,CAAA;YACzB,+DAA+D;YAC/D,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,CAAA;YACzB,uBAAuB;YACvB,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,CAAA;YAC1B,6EAA6E;YAC7E,IAAI,IAAI,MAAM,CAAC,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,CAAA;YACnC,2EAA2E;YAC3E,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,CAAA;YACtD,qEAAqE;YACrE,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;YACrD,WAAW,CAAC,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,eAAe,CAAC,CAAA;YACxF,wEAAwE;YACxE,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;YACjG,wBAAwB;YACxB,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAA;YACrD,mFAAmF;YACnF,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAA;YAC/B,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;YAC7C,kDAAkD;YAClD,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;YAClD,iFAAiF;YACjF,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACvI,6EAA6E;YAC7E,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,SAAS,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;YAC5E,kFAAkF;YAClF,MAAM,CAAC,CAAC,SAAS,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;YAC/D,4DAA4D;YAC5D,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;YAC9D,6EAA6E;YAC7E,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;YAC5E,sEAAsE;YACtE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,KAAK,CAAC,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YAClI,kFAAkF;YAClF,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAAA;YAC5C,eAAe,EAAE,OAAO,eAAe,CAAA;SACxC;QAED,6DAA6D;QAC7D,UAAU,OAAO;YACf,0EAA0E;YAC1E,OAAO,CAAC,EAAE,OAAO,CAAA;YACjB,4DAA4D;YAC5D,MAAM,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;YAC3C,oDAAoD;YACpD,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAA;SACrB;QAED,qEAAqE;QACrE,UAAiB,IAAI,CAAC,CAAC,GAAG,GAAG;YAC3B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YACvC,QAAQ,CAAC,EAAE,OAAO,CAAA;YAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;YAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;YAClB,MAAM,CAAC,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,EAAE,CAAA;YACzC,MAAM,CAAC,EAAE,OAAO,CAAA;YAChB,KAAK,CAAC,EAAE,OAAO,CAAA;YACf,IAAI,CAAC,EAAE,MAAM,CAAA;YACb,KAAK,CAAC,EAAE,GAAG,CAAA;YACX,IAAI,CAAC,EAAE,MAAM,CAAA;YACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;YACnC,OAAO,CAAC,EAAE,MAAM,CAAA;YAChB,OAAO,CAAC,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;YAC5C,GAAG,CAAC,EAAE,MAAM,CAAA;YACZ,GAAG,CAAC,EAAE,MAAM,CAAA;YACZ,IAAI,CAAC,EAAE,MAAM,CAAA;SACd;KACF;IAED,mFAAmF;IACnF,UAAU,WAAW,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC;QAClC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,WAAW,CAAC,OAAO,GAAG,CAAC,CAAA;QACnD,KAAK,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,WAAW,CAAC,OAAO,GAAG,CAAC,CAAA;QACvD,CAAC,OAAO,CAAC,EAAE,IAAI,CAAA;QACf,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACzB,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;QACf,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QACnB,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QACnB,QAAQ,CAAC,EAAE,QAAQ,CAAA;QACnB,WAAW,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;QAC/B,OAAO,CAAC,EAAE,QAAQ,CAAA;QAClB,KAAK,CAAC,EAAE,CAAC,CAAA;QACT,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,WAAW,EAAE,gBAAgB,CAAC,KAAK,CAAA;QACnC,mEAAmE;QACnE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;QAClC,yEAAyE;QACzE,MAAM,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACtB,2EAA2E;QAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACvC,+CAA+C;QAC/C,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACrC,0EAA0E;QAC1E,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACpC,kEAAkE;QAClE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC7C,6CAA6C;QAC7C,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAChC,sDAAsD;QACtD,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC/B,iEAAiE;QACjE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACnC,6EAA6E;QAC7E,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACvC,sDAAsD;QACtD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACvC,uDAAuD;QACvD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACvC,kDAAkD;QAClD,UAAU,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC1B,qDAAqD;QACrD,YAAY,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC5B,qDAAqD;QACrD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACrC,kEAAkE;QAClE,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAChC,kEAAkE;QAClE,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAChC,4CAA4C;QAC5C,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACjC,gDAAgD;QAChD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC7C,4DAA4D;QAC5D,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACjC,qEAAqE;QACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,GAAG,GAAG,CAAA;QAC1B,2EAA2E;QAC3E,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAClC,iFAAiF;QACjF,KAAK,CAAC,CAAC,SAAS,MAAM,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;KAC1F;CACF;AAWD,cAAM,eAAgB,SAAQ,SAAS;IAGD,OAAO,EAAE,WAAW,CAAC,OAAO;IAFhE,IAAI,SAAoB;gBAEZ,OAAO,EAAE,MAAM,EAAS,OAAO,EAAE,WAAW,CAAC,OAAO;IAehE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,eAAe;CAGhD;AAMD,KAAK,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAE/C,QAAA,MAAM,MAAM,EA8BP,WAAW,CAAC,MAAM,CAAA;AAynBvB,eAAe,MAAM,CAAA"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/package.json b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/package.json new file mode 100644 index 0000000..29c9ce1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/package.json @@ -0,0 +1,39 @@ +{ + "name": "@deepseek-ai/schemastery", + "description": "Type driven schema validator", + "version": "3.18.1", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "vendor/schemastery" + }, + "type": "module", + "main": "lib/index.cjs", + "module": "lib/index.mjs", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "import": "./lib/index.mjs", + "require": "./lib/index.cjs" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.mjs", + "lib/index.cjs", + "lib/types/**/*.d.ts", + "lib/types/**/*.d.ts.map", + "src" + ], + "author": "Shigma ", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@deepseek-ai/cosmokit": "^1.8.2" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/src/index.ts b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/src/index.ts new file mode 100644 index 0000000..56a499e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery/src/index.ts @@ -0,0 +1,902 @@ +import { Binary, clone, deepEqual, filterKeys, isNullable, isPlainObject, pick, valueMap, type Dict } from '@deepseek-ai/cosmokit' +import type { StandardSchemaV1 } from '@standard-schema/spec' + +const kSchema = Symbol.for('schemastery') +const kValidationError = Symbol.for('ValidationError') + +declare global { + namespace Schemastery { + /** Convert primitive constructors, constants, and existing schemas into a schema type. */ + export type From = + | X extends string | number | boolean ? Schema + : X extends Schema ? X + : X extends typeof String ? Schema + : X extends typeof Number ? Schema + : X extends typeof Boolean ? Schema + : X extends typeof Function ? Schema any> + : X extends Constructor ? Schema + : never + + type TypeS1 = X extends Schema ? S : never + type Inverse = X extends Schema ? (arg: Y) => void : never + + /** Input type accepted by a schema-like value. */ + export type TypeS = TypeS1> + /** Output type returned by a schema-like value after validation. */ + export type TypeT = ReturnType> + /** Resolver callback used by custom schema types registered with `Schema.extend()`. */ + export type Resolve = (data: any, schema: Schema, options: Options, strict?: boolean) => [any, any?] + + /** Input type accepted by one schema in an intersection. */ + export type IntersectS = From extends Schema ? S : never + /** Output type returned by one schema in an intersection. */ + export type IntersectT = Inverse> extends ((arg: infer T) => void) ? T : never + + type TupleS = X extends readonly [infer L, ...infer R] ? [TypeS?, ...TupleS] : any[] + type TupleT = X extends readonly [infer L, ...infer R] ? [TypeT?, ...TupleT] : any[] + type ObjectS = { [K in keyof X]?: TypeS | null } & Dict + type ObjectT = { [K in keyof X]: TypeT } & Dict + type Constructor = new (...args: any[]) => T + + /** Static constructor and factory methods exposed by the default `Schema` export. */ + export interface Static { + (options: Partial>): Schema + new (options: Partial>): Schema + prototype: Schema + /** Validate a value against a schema node and return `[output, adaptedInput?]`. */ + resolve: Resolve + /** Infer a schema from a primitive value, constructor, or existing schema. */ + from(source?: X): From + /** Register a resolver for a custom schema `type`. */ + extend(type: string, resolve: Resolve): void + /** Accept any value without validation. */ + any(): Schema + /** Accept only nullable input. */ + never(): Schema + /** Accept exactly one constant value. */ + const(value: T): Schema + /** Accept strings, with optional metadata constraints added by instance methods. */ + string(): Schema + /** Accept numbers, with optional range and step constraints. */ + number(): Schema + /** Accept non-negative integer numbers. */ + natural(): Schema + /** Accept a number between 0 and 1 and mark it as a slider. */ + percent(): Schema + /** Accept booleans. */ + boolean(): Schema + /** Accept `Date` instances or parse datetime strings into `Date` objects. */ + date(): Schema + /** Accept `RegExp` instances or parse strings into regular expressions. */ + regExp(flag?: string): Schema + /** Accept binary sources and normalize them to `ArrayBufferLike`. */ + arrayBuffer(): Schema + arrayBuffer(encoding: 'hex' | 'base64'): Schema + /** Accept a numeric bitset or string keys and normalize to a number. */ + bitset(bits: Partial>): Schema + /** Accept functions. */ + function(): Schema any> + /** Accept instances of a constructor or objects whose constructor name matches. */ + is(constructor: string): Schema + is(constructor: Constructor): Schema + /** Accept arrays whose elements match `inner`. */ + array(inner: X): Schema[], TypeT[]> + /** Accept plain objects with values matching `inner` and optional key schema. */ + dict = Schema>(inner: X, sKey?: Y): Schema, TypeS>, Dict, TypeT>> + /** Accept tuple arrays where each index matches the corresponding schema. */ + tuple(list: X): Schema, TupleT> + /** Accept plain objects whose declared properties match the schema dictionary. */ + object(dict: X): Schema, ObjectT> + /** Accept values matching at least one schema in `list`. */ + union(list: readonly X[]): Schema, TypeT> + /** Accept values matching every schema in `list`, merging object outputs. */ + intersect(list: readonly X[]): Schema, IntersectT> + /** Validate with `inner`, then convert the result with `callback`. */ + transform(inner: X, callback: (value: TypeS, options: Schemastery.Options) => T, preserve?: boolean): Schema, T> + /** Defer construction of a recursive schema until validation or serialization. */ + lazy(callback: () => X): X + ValidationError: typeof ValidationError + } + + /** Runtime validation options shared by all schema calls. */ + interface Options { + /** Remove invalid object properties instead of throwing when possible. */ + autofix?: boolean + /** Skip validation for selected values and schema nodes. */ + ignore?(data: any, schema: Schema): boolean + /** Path used to format nested validation errors. */ + path?: (keyof any)[] + } + + /** UI and validation metadata attached by schema builder methods. */ + export interface Meta { + default?: T extends {} ? Partial : T + required?: boolean + disabled?: boolean + collapse?: boolean + badges?: { text: string; type: string }[] + hidden?: boolean + loose?: boolean + role?: string + extra?: any + link?: string + description?: string | Dict + comment?: string + pattern?: { source: string; flags?: string } + max?: number + min?: number + step?: number + } + } + + /** Callable schema instance that validates input and returns normalized output. */ + interface Schemastery { + (data?: S | null, options?: Schemastery.Options): T + new (data?: S | null, options?: Schemastery.Options): T + [kSchema]: true + uid: number + meta: Schemastery.Meta + type: string + sKey?: Schema + inner?: Schema + list?: Schema[] + dict?: Dict + bits?: Dict + callback?: Function + constructor?: string | Function + builder?: Function + value?: T + refs?: Dict + preserve?: boolean + '~standard': StandardSchemaV1.Props // + /** Format this schema as a compact TypeScript-like type string. */ + toString(inline?: boolean): string + /** Serialize this schema, preserving shared and recursive references. */ + toJSON(): Schema + /** Mark nullable input as invalid unless a default supplies a fallback. */ + required(value?: boolean): Schema + /** Hide this schema node from UI renderers. */ + hidden(value?: boolean): Schema + /** Return the default value instead of throwing when validation fails. */ + loose(value?: boolean): Schema + /** Attach a renderer role and optional role-specific metadata. */ + role(text: string, extra?: any): Schema + /** Attach an external documentation link. */ + link(link: string): Schema + /** Set the fallback value used for nullable input. */ + default(value: T): Schema + /** Attach an auxiliary comment for documentation or form UIs. */ + comment(text: string): Schema + /** Attach a localized or plain description for documentation or form UIs. */ + description(text: string): Schema + /** Mark this schema node as disabled for form UIs. */ + disabled(value?: boolean): Schema + /** Request collapsed rendering for nested form UIs. */ + collapse(value?: boolean): Schema + /** Add a deprecated badge to this schema node. */ + deprecated(): Schema + /** Add an experimental badge to this schema node. */ + experimental(): Schema + /** Require strings to match a regular expression. */ + pattern(regexp: RegExp): Schema + /** Set an inclusive maximum for numbers or collection lengths. */ + max(value: number): Schema + /** Set an inclusive minimum for numbers or collection lengths. */ + min(value: number): Schema + /** Set the numeric increment constraint. */ + step(value: number): Schema + /** Add or replace an object property schema. */ + set(key: string, value: Schema): Schema + /** Append a tuple, union, or intersection member schema. */ + push(value: Schema): Schema + /** Remove values equal to schema defaults from normalized output. */ + simplify(value?: any): any + /** Return a schema clone with descriptions merged from locale messages. */ + i18n(messages: Dict): Schema + /** Attach arbitrary metadata consumed by form renderers and downstream tools. */ + extra(key: K, value: Schemastery.Meta[K]): Schema + } +} + +declare namespace globalThis { + // eslint-disable-next-line @typescript-eslint/naming-convention + export let __schemastery_index__: number + export let __schemastery_refs__: Record | undefined +} + +globalThis.__schemastery_index__ ??= 0 +globalThis.__schemastery_refs__ = undefined + +class ValidationError extends TypeError { + name = 'ValidationError' + + constructor(message: string, public options: Schemastery.Options) { + let prefix = '$' + for (const segment of options.path || []) { + if (typeof segment === 'string') { + prefix += '.' + segment + } else if (typeof segment === 'number') { + prefix += '[' + segment + ']' + } else if (typeof segment === 'symbol') { + prefix += `[Symbol(${segment.toString()})]` + } + } + if (prefix.startsWith('.')) prefix = prefix.slice(1) + super((prefix === '$' ? '' : `${prefix} `) + message) + } + + static is(error: any): error is ValidationError { + return !!error?.[kValidationError] + } +} + +Object.defineProperty(ValidationError.prototype, kValidationError, { + value: true, +}) + +type Schema = Schemastery + +const Schema = function (options: Schema) { + const schema = function (data: any, options: Schemastery.Options = {}) { + return Schema.resolve(data, schema, options)[0] + } as Schema + + if (options.refs) { + const refs = valueMap(options.refs, options => new Schema(options)) + const getRef = (uid: any) => refs[uid]! + for (const key in refs) { + const options = refs[key]! + options.sKey = getRef(options.sKey) + options.inner = getRef(options.inner) + options.list = options.list && options.list.map(getRef) + options.dict = options.dict && valueMap(options.dict, getRef) + } + return refs[options.uid!] + } + + Object.assign(schema, options) + if (typeof schema.callback === 'string') { + try { + // eslint-disable-next-line no-new-func + schema.callback = new Function('return ' + schema.callback)() + } catch {} + } + Object.defineProperty(schema, 'uid', { value: globalThis.__schemastery_index__++ }) + Object.setPrototypeOf(schema, Schema.prototype) + schema.meta ||= {} + schema.toString = schema.toString.bind(schema) + return schema +} as Schemastery.Static + +Schema.prototype = Object.create(Function.prototype) + +Schema.prototype[kSchema] = true + +Object.defineProperty(Schema.prototype, '~standard', { + get(this: Schema) { + return { + version: 1, + vendor: 'schemastery', + validate: (value: unknown) => { + try { + return { value: Schema.resolve(value, this, {})[0] } + } catch (error) { + if (ValidationError.is(error)) { + return { issues: [{ message: error.message, path: error.options.path }] } + } + throw error + } + }, + } + }, +}) + +Schema.ValidationError = ValidationError + +Schema.prototype.toJSON = function toJSON() { + if (globalThis.__schemastery_refs__) { + globalThis.__schemastery_refs__[this.uid] ??= JSON.parse(JSON.stringify({ ...this })) + return this.uid as any + } + + globalThis.__schemastery_refs__ = { [this.uid]: { ...this } as Schema } + globalThis.__schemastery_refs__[this.uid] = JSON.parse(JSON.stringify({ ...this })) + const result = { uid: this.uid, refs: globalThis.__schemastery_refs__ } + globalThis.__schemastery_refs__ = undefined + return result +} + +Schema.prototype.set = function set(key, value) { + this.dict![key] = value + return this +} + +Schema.prototype.push = function push(value) { + this.list!.push(value) + return this +} + +function mergeDesc(original: undefined | string | Dict, messages: Dict) { + const result: Dict = typeof original === 'string' ? { '': original } : { ...original } + for (const locale in messages) { + const value = messages[locale] + if (value?.$description || value?.$desc) { + result[locale] = value.$description || value.$desc + } else if (typeof value === 'string') { + result[locale] = value + } + } + return result +} + +function getInner(value: any) { + return value?.$value ?? value?.$inner +} + +function extractKeys(data: any) { + return filterKeys(data ?? {}, key => !key.startsWith('$')) +} + +Schema.prototype.i18n = function i18n(messages) { + const schema = Schema(this) + const desc = mergeDesc(schema.meta.description, messages) + if (Object.keys(desc).length) schema.meta.description = desc + if (schema.dict) { + schema.dict = valueMap(schema.dict, (inner, key) => { + return inner.i18n(valueMap(messages, (data) => getInner(data)?.[key] ?? data?.[key])) + }) + } + if (schema.list) { + schema.list = schema.list!.map((inner, index) => { + return inner.i18n(valueMap(messages, (data = {}) => { + if (Array.isArray(getInner(data))) return getInner(data)[index] + if (Array.isArray(data)) return data[index] + return extractKeys(data) + })) + }) + } + if (schema.inner) { + schema.inner = schema.inner.i18n(valueMap(messages, (data) => { + if (getInner(data)) return getInner(data) + return extractKeys(data) + })) + } + if (schema.sKey) { + schema.sKey = schema.sKey.i18n(valueMap(messages, (data) => data?.$key)) + } + return schema +} + +Schema.prototype.extra = function extra(key, value) { + const schema = Schema(this) + schema.meta = { ...schema.meta, [key]: value } + return schema +} + +for (const key of ['required', 'disabled', 'collapse', 'hidden', 'loose']) { + Object.assign(Schema.prototype, { + [key](this: Schema, value = true) { + const schema = Schema(this) + schema.meta = { ...schema.meta, [key]: value } + return schema + }, + }) +} + +Schema.prototype.deprecated = function deprecated() { + const schema = Schema(this) + schema.meta.badges ||= [] + schema.meta.badges.push({ text: 'deprecated', type: 'danger' }) + return schema +} + +Schema.prototype.experimental = function experimental() { + const schema = Schema(this) + schema.meta.badges ||= [] + schema.meta.badges.push({ text: 'experimental', type: 'warning' }) + return schema +} + +Schema.prototype.pattern = function pattern(regexp) { + const schema = Schema(this) + const pattern = pick(regexp, ['source', 'flags']) + schema.meta = { ...schema.meta, pattern } + return schema +} + +Schema.prototype.simplify = function simplify(this: Schema, value) { + if (deepEqual(value, this.meta.default, this.type === 'dict')) return null + if (isNullable(value)) return value + if (this.type === 'object' || this.type === 'dict') { + const result: Dict = {} + for (const key in value) { + const schema = this.type === 'object' ? this.dict![key] : this.inner + const item = schema?.simplify(value[key]) + if (this.type === 'dict' || !isNullable(item)) result[key] = item + } + if (deepEqual(result, this.meta.default, this.type === 'dict')) return null + return result + } else if (this.type === 'array' || this.type === 'tuple') { + const result: any[] = [] + ;(value as any[]).forEach((value, index) => { + const schema = this.type === 'array' ? this.inner : this.list![index] + const item = schema ? schema.simplify(value) : value + result.push(item) + }) + return result + } else if (this.type === 'intersect') { + const result: Dict = {} + for (const item of this.list!) { + Object.assign(result, item.simplify(value)) + } + return result + } else if (this.type === 'union') { + for (const schema of this.list!) { + try { + Schema.resolve(value, schema, {}) + return schema.simplify(value) + } catch {} + } + } + return value +} + +Schema.prototype.toString = function toString(inline?: boolean) { + return formatters[this.type]?.(this, inline) ?? `Schema<${this.type}>` +} + +Schema.prototype.role = function role(role, extra) { + const schema = Schema(this) + schema.meta = { ...schema.meta, role, extra } + return schema +} + +for (const key of ['default', 'link', 'comment', 'description', 'max', 'min', 'step']) { + Object.assign(Schema.prototype, { + [key](this: Schema, value: any) { + const schema = Schema(this) + schema.meta = { ...schema.meta, [key]: value } + return schema + }, + }) +} + +const resolvers: Dict = {} + +Schema.extend = function extend(type, resolve) { + resolvers[type] = resolve +} + +Schema.resolve = function resolve(data, schema, options = {}, strict = false) { + if (!schema) return [data] + if (options.ignore?.(data, schema)) return [data] + + if (isNullable(data) && schema.type !== 'lazy') { + if (schema.meta.required) throw new ValidationError(`missing required value`, options) + let current = schema + let fallback = schema.meta.default + while (current?.type === 'intersect' && isNullable(fallback)) { + current = current.list![0] + fallback = current?.meta.default + } + if (isNullable(fallback)) return [data] + data = clone(fallback) + } + + const callback = resolvers[schema.type] + if (!callback) throw new ValidationError(`unsupported type "${schema.type}"`, options) + + try { + return callback(data, schema, options, strict) + } catch (error) { + if (!schema.meta.loose) throw error + return [schema.meta.default] + } +} + +Schema.from = function from(source: any) { + if (isNullable(source)) { + return Schema.any() + } else if (['string', 'number', 'boolean'].includes(typeof source)) { + return Schema.const(source).required() + } else if (source[kSchema]) { + return source + } else if (typeof source === 'function') { + switch (source) { + case String: return Schema.string().required() + case Number: return Schema.number().required() + case Boolean: return Schema.boolean().required() + case Function: return Schema.function().required() + default: return Schema.is(source).required() + } + } else { + throw new TypeError(`cannot infer schema from ${source}`) + } +} + +Schema.lazy = function lazy(builder) { + const toJSON = () => { + if (!schema.inner![kSchema]) { + schema.inner = schema.builder!() + schema.inner!.meta = { ...schema.meta, ...schema.inner!.meta } + } + return schema.inner!.toJSON() + } + const schema = new Schema({ type: 'lazy', builder, inner: { toJSON } as any }) + return schema as any +} + +Schema.natural = function natural() { + return Schema.number().step(1).min(0) +} + +Schema.percent = function percent() { + return Schema.number().step(0.01).min(0).max(1).role('slider') +} + +Schema.date = function date() { + return Schema.union([ + Schema.is(Date), + Schema.transform(Schema.string().role('datetime'), (value, options) => { + const date = new Date(value) + if (isNaN(+date)) throw new ValidationError(`invalid date "${value}"`, options) + return date + }, true), + ]) +} + +Schema.regExp = function regExp(flag = '') { + return Schema.union([ + Schema.is(RegExp), + Schema.transform(Schema.string().role('regexp', { flag }), (value, options) => { + try { + return new RegExp(value, flag) + } catch (e: any) { + throw new ValidationError(e.message, options) + } + }, true), + ]) +} + +Schema.arrayBuffer = function arrayBuffer(encoding?: 'hex' | 'base64'): any { + return Schema.union([ + Schema.is(ArrayBuffer), + Schema.is(SharedArrayBuffer), + Schema.transform(Schema.any(), (value, options) => { + if (Binary.isSource(value)) return Binary.fromSource(value) + throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options) + }, true), + ...encoding ? [Schema.transform(Schema.string(), (value, options) => { + try { + return encoding === 'base64' + ? Binary.fromBase64(value) + : Binary.fromHex(value) + } catch (e: any) { + throw new ValidationError(e.message, options) + } + }, true)] as const : [], + ]) +} + +Schema.extend('lazy', (data, schema, options, strict) => { + if (!schema.inner![kSchema]) { + schema.inner = schema.builder!() + schema.inner!.meta = { ...schema.meta, ...schema.inner!.meta } + } + return Schema.resolve(data, schema.inner!, options, strict) +}) + +Schema.extend('any', (data) => { + return [data] +}) + +Schema.extend('never', (data, _, options) => { + throw new ValidationError(`expected nullable but got ${data}`, options) +}) + +Schema.extend('const', (data, { value }, options) => { + if (deepEqual(data, value)) return [value] + throw new ValidationError(`expected ${value} but got ${data}`, options) +}) + +function checkWithinRange(data: number, meta: Schemastery.Meta, description: string, options: Schemastery.Options, skipMin = false) { + const { max = Infinity, min = -Infinity } = meta + if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options) + if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options) +} + +Schema.extend('string', (data, { meta }, options) => { + if (typeof data !== 'string') throw new ValidationError(`expected string but got ${data}`, options) + if (meta.pattern) { + const regexp = new RegExp(meta.pattern.source, meta.pattern.flags) + if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options) + } + checkWithinRange(data.length, meta, 'string length', options) + return [data] +}) + +function decimalShift(data: number, digits: number) { + const str = data.toString() + if (str.includes('e')) return data * Math.pow(10, digits) + const index = str.indexOf('.') + if (index === -1) return data * Math.pow(10, digits) + const frac = str.slice(index + 1) + const integer = str.slice(0, index) + if (frac.length <= digits) return +(integer + frac.padEnd(digits, '0')) + return +(integer + frac.slice(0, digits) + '.' + frac.slice(digits)) +} + +function isMultipleOf(data: number, min: number, step: number) { + step = Math.abs(step) + if (!/^\d+\.\d+$/.test(step.toString())) { + return (data - min) % step === 0 + } + const index = step.toString().indexOf('.') + const digits = step.toString().slice(index + 1).length + return Math.abs(decimalShift(data, digits) - decimalShift(min, digits)) % decimalShift(step, digits) === 0 +} + +Schema.extend('number', (data, { meta }, options) => { + if (typeof data !== 'number') throw new ValidationError(`expected number but got ${data}`, options) + checkWithinRange(data, meta, 'number', options) + const { step } = meta + if (step && !isMultipleOf(data, meta.min ?? 0, step)) { + throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options) + } + return [data] +}) + +Schema.extend('boolean', (data, _, options) => { + if (typeof data === 'boolean') return [data] + throw new ValidationError(`expected boolean but got ${data}`, options) +}) + +Schema.extend('bitset', (data, { bits, meta }, options) => { + let value = 0, keys: string[] = [] + if (typeof data === 'number') { + value = data + for (const key in bits!) { + if (data & bits![key]!) { + keys.push(key) + } + } + } else if (Array.isArray(data)) { + keys = data + for (const key of keys) { + if (typeof key !== 'string') throw new ValidationError(`expected string but got ${key}`, options) + if (key in bits!) value |= bits![key]! + } + } else { + throw new ValidationError(`expected number or array but got ${data}`, options) + } + if (value === meta.default) return [value] + return [value, keys] +}) + +Schema.extend('function', (data, _, options) => { + if (typeof data === 'function') return [data] + throw new ValidationError(`expected function but got ${data}`, options) +}) + +Schema.extend('is', (data, { constructor }, options) => { + if (typeof constructor === 'function') { + if (data instanceof constructor) return [data] + throw new ValidationError(`expected ${constructor.name} but got ${data}`, options) + } else { + if (isNullable(data)) { + throw new ValidationError(`expected ${constructor} but got ${data}`, options) + } + let prototype = Object.getPrototypeOf(data) + while (prototype) { + if (prototype.constructor?.name === constructor) return [data] + prototype = Object.getPrototypeOf(prototype) + } + throw new ValidationError(`expected ${constructor} but got ${data}`, options) + } +}) + +function property(data: any, key: keyof any, schema: Schema, options: Schemastery.Options) { + try { + const [value, adapted] = Schema.resolve(data[key], schema, { + ...options, + path: [...options.path || [], key], + }) + if (adapted !== undefined) data[key] = adapted + return value + } catch (e) { + if (!options?.autofix) throw e + delete data[key] + return schema.meta.default + } +} + +Schema.extend('array', (data, { inner, meta }, options) => { + if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options) + checkWithinRange(data.length, meta, 'array length', options, !isNullable(inner!.meta.default)) + return [data.map((_, index) => property(data, index, inner!, options))] +}) + +Schema.extend('dict', (data, { inner, sKey }, options, strict) => { + if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options) + const result: any = {} + for (const key in data) { + let rKey: string + try { + rKey = Schema.resolve(key, sKey!, options)[0] + } catch (error) { + if (strict) continue + throw error + } + result[rKey] = property(data, key, inner!, options) + data[rKey] = data[key] + if (key !== rKey) delete data[key] + } + return [result] +}) + +Schema.extend('tuple', (data, { list }, options, strict) => { + if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options) + const result = list!.map((inner, index) => property(data, index, inner, options)) + if (strict) return [result] + result.push(...data.slice(list!.length)) + return [result] +}) + +function merge(result: any, data: any) { + for (const key in data) { + if (key in result) continue + result[key] = data[key] + } +} + +Schema.extend('object', (data, { dict }, options, strict) => { + if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options) + const result: any = {} + for (const key in dict) { + const value = property(data, key, dict![key]!, options) + if (!isNullable(value) || key in data) { + result[key] = value + } + } + if (!strict) merge(result, data) + return [result] +}) + +Schema.extend('union', (data, { list, toString }, options, strict) => { + const messages: any[] = [] + for (const inner of list!) { + try { + return Schema.resolve(data, inner, options, strict) + } catch (error) { + messages.push(error) + } + } + throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options) +}) + +Schema.extend('intersect', (data, { list, toString }, options, strict) => { + if (!list!.length) return [data] + let result + for (const inner of list!) { + const value: any = Schema.resolve(data, inner, options, true)[0] + if (isNullable(value)) continue + if (isNullable(result)) { + result = value + } else if (typeof result !== typeof value) { + throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options) + } else if (typeof value === 'object') { + merge(result ??= {}, value) + } else if (result !== value) { + throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options) + } + } + if (!strict && isPlainObject(data)) merge(result, data) + return [result] +}) + +Schema.extend('transform', (data, { inner, callback, preserve }, options) => { + const [result, adapted = data] = Schema.resolve(data, inner!, options, true) + if (preserve) { + return [callback!(result)] + // } else if (isPlainObject(data)) { + // const temp: any = {} + // for (const key in result) { + // if (!(key in data)) continue + // temp[key] = data[key] + // delete data[key] + // } + // Object.assign(data, callback!(temp)) + // return [callback!(result)] + } else { + return [callback!(result), callback!(adapted)] + } +}) + +type Formatter = (schema: Schema, inline?: boolean) => string +const formatters: Dict = {} + +function defineMethod(name: string, keys: (keyof Schema)[], format: Formatter) { + formatters[name] = format + Object.assign(Schema, { + [name](...args: any[]) { + const schema = new Schema({ type: name } as Schema) + keys.forEach((key, index) => { + switch (key) { + case 'sKey': schema.sKey = args[index] ?? Schema.string(); break + case 'inner': schema.inner = Schema.from(args[index]); break + case 'list': schema.list = args[index].map(Schema.from); break + case 'dict': schema.dict = valueMap(args[index], Schema.from); break + case 'bits': { + schema.bits = {} + for (const key in args[index]) { + if (typeof args[index][key] !== 'number') continue + schema.bits[key] = args[index][key] + } + break + } + case 'callback': { + const callback = schema.callback = args[index] + ;callback['toJSON'] ||= () => callback.toString() + break + } + case 'constructor': { + const constructor = schema.constructor = args[index] + if (typeof constructor === 'function') { + ;constructor['toJSON'] ||= () => constructor['name'] + } + break + } + default: schema[key] = args[index] as never + } + }) + if (name === 'object' || name === 'dict') { + schema.meta.default = {} + } else if (name === 'array' || name === 'tuple') { + schema.meta.default = [] + } else if (name === 'bitset') { + schema.meta.default = 0 + } + return schema + }, + }) +} + +defineMethod('is', ['constructor'], ({ constructor }) => { + if (typeof constructor === 'function') { + return constructor.name + } else { + return constructor! + } +}) + +defineMethod('any', [], () => 'any') +defineMethod('never', [], () => 'never') +defineMethod('const', ['value'], ({ value }) => typeof value === 'string' ? JSON.stringify(value) : value) +defineMethod('string', [], () => 'string') +defineMethod('number', [], () => 'number') +defineMethod('boolean', [], () => 'boolean') +defineMethod('bitset', ['bits'], () => 'bitset') +defineMethod('function', [], () => 'function') +defineMethod('array', ['inner'], ({ inner }) => `${inner!.toString(true)}[]`) +defineMethod('dict', ['inner', 'sKey'], ({ inner, sKey }) => `{ [key: ${sKey!.toString()}]: ${inner!.toString()} }`) +defineMethod('tuple', ['list'], ({ list }) => `[${list!.map((inner) => inner.toString()).join(', ')}]`) + +defineMethod('object', ['dict'], ({ dict }) => { + if (Object.keys(dict!).length === 0) return '{}' + return `{ ${Object.entries(dict!).map(([key, inner]) => { + return `${key}${inner!.meta.required ? '' : '?'}: ${inner!.toString()}` + }).join(', ')} }` +}) + +defineMethod('union', ['list'], ({ list }, inline) => { + const result = list!.map(({ toString: format }) => format()).join(' | ') + return inline ? `(${result})` : result +}) + +defineMethod('intersect', ['list'], ({ list }) => { + return `${list!.map((inner) => inner.toString(true)).join(' & ')}` +}) + +defineMethod('transform', ['inner', 'callback', 'preserve'], ({ inner }, isInner) => inner!.toString(isInner)) + +export default Schema diff --git a/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@standard-schema/spec b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@standard-schema/spec new file mode 120000 index 0000000..f2c558c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+schemastery@3.18.1/node_modules/@standard-schema/spec @@ -0,0 +1 @@ +../../../@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/LICENSE new file mode 100644 index 0000000..ea54e0d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Colin McDonnell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/README.md b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/README.md new file mode 100644 index 0000000..f9813ff --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/README.md @@ -0,0 +1,198 @@ +

+ Standard Schema fire logo +
+ Standard Schema

+

+ A family of specs for interoperable TypeScript +
+ standardschema.dev +

+
+ + + +The Standard Schema project is a set of interfaces that standardize the provision and consumption of shared functionality in the TypeScript ecosystem. + +Its goal is to allow tools to accept a single input that includes all the types and capabilities they need— no library-specific adapters, no extra dependencies. The result is an ecosystem that's fair for implementers, friendly for consumers, and open for end users. + +## The specifications + +The specifications can be found below in their entirety. Libraries wishing to implement a spec can copy/paste the code block below into their codebase. They're also available at `@standard-schema/spec` on [npm](https://www.npmjs.com/package/@standard-schema/spec) and [JSR](https://jsr.io/@standard-schema/spec). + +```ts +// ######################### +// ### Standard Typed ### +// ######################### + +/** The Standard Typed interface. This is a base type extended by other specs. */ +export interface StandardTypedV1 { + /** The Standard properties. */ + readonly "~standard": StandardTypedV1.Props; +} + +export declare namespace StandardTypedV1 { + /** The Standard Typed properties interface. */ + export interface Props { + /** The version number of the standard. */ + readonly version: 1; + /** The vendor name of the schema library. */ + readonly vendor: string; + /** Inferred types associated with the schema. */ + readonly types?: Types | undefined; + } + + /** The Standard Typed types interface. */ + export interface Types { + /** The input type of the schema. */ + readonly input: Input; + /** The output type of the schema. */ + readonly output: Output; + } + + /** Infers the input type of a Standard Typed. */ + export type InferInput = NonNullable< + Schema["~standard"]["types"] + >["input"]; + + /** Infers the output type of a Standard Typed. */ + export type InferOutput = NonNullable< + Schema["~standard"]["types"] + >["output"]; +} + +// ########################## +// ### Standard Schema ### +// ########################## + +/** The Standard Schema interface. */ +export interface StandardSchemaV1 { + /** The Standard Schema properties. */ + readonly "~standard": StandardSchemaV1.Props; +} + +export declare namespace StandardSchemaV1 { + /** The Standard Schema properties interface. */ + export interface Props + extends StandardTypedV1.Props { + /** Validates unknown input values. */ + readonly validate: ( + value: unknown, + options?: StandardSchemaV1.Options | undefined + ) => Result | Promise>; + } + + /** The result interface of the validate function. */ + export type Result = SuccessResult | FailureResult; + + /** The result interface if validation succeeds. */ + export interface SuccessResult { + /** The typed output value. */ + readonly value: Output; + /** A falsy value for `issues` indicates success. */ + readonly issues?: undefined; + } + + export interface Options { + /** Explicit support for additional vendor-specific parameters, if needed. */ + readonly libraryOptions?: Record | undefined; + } + + /** The result interface if validation fails. */ + export interface FailureResult { + /** The issues of failed validation. */ + readonly issues: ReadonlyArray; + } + + /** The issue interface of the failure output. */ + export interface Issue { + /** The error message of the issue. */ + readonly message: string; + /** The path of the issue, if any. */ + readonly path?: ReadonlyArray | undefined; + } + + /** The path segment interface of the issue. */ + export interface PathSegment { + /** The key representing a path segment. */ + readonly key: PropertyKey; + } + + /** The Standard types interface. */ + export interface Types + extends StandardTypedV1.Types {} + + /** Infers the input type of a Standard. */ + export type InferInput = + StandardTypedV1.InferInput; + + /** Infers the output type of a Standard. */ + export type InferOutput = + StandardTypedV1.InferOutput; +} + +// ############################### +// ### Standard JSON Schema ### +// ############################### + +/** The Standard JSON Schema interface. */ +export interface StandardJSONSchemaV1 { + /** The Standard JSON Schema properties. */ + readonly "~standard": StandardJSONSchemaV1.Props; +} + +export declare namespace StandardJSONSchemaV1 { + /** The Standard JSON Schema properties interface. */ + export interface Props + extends StandardTypedV1.Props { + /** Methods for generating the input/output JSON Schema. */ + readonly jsonSchema: StandardJSONSchemaV1.Converter; + } + + /** The Standard JSON Schema converter interface. */ + export interface Converter { + /** Converts the input type to JSON Schema. May throw if conversion is not supported. */ + readonly input: ( + options: StandardJSONSchemaV1.Options + ) => Record; + /** Converts the output type to JSON Schema. May throw if conversion is not supported. */ + readonly output: ( + options: StandardJSONSchemaV1.Options + ) => Record; + } + + /** + * The target version of the generated JSON Schema. + * + * It is *strongly recommended* that implementers support `"draft-2020-12"` and `"draft-07"`, as they are both in wide use. All other targets can be implemented on a best-effort basis. Libraries should throw if they don't support a specified target. + * + * The `"openapi-3.0"` target is intended as a standardized specifier for OpenAPI 3.0 which is a superset of JSON Schema `"draft-04"`. + */ + export type Target = + | "draft-2020-12" + | "draft-07" + | "openapi-3.0" + // Accepts any string for future targets while preserving autocomplete + | ({} & string); + + /** The options for the input/output methods. */ + export interface Options { + /** Specifies the target version of the generated JSON Schema. Support for all versions is on a best-effort basis. If a given version is not supported, the library should throw. */ + readonly target: Target; + + /** Explicit support for additional vendor-specific parameters, if needed. */ + readonly libraryOptions?: Record | undefined; + } + + /** The Standard types interface. */ + export interface Types + extends StandardTypedV1.Types {} + + /** Infers the input type of a Standard. */ + export type InferInput = + StandardTypedV1.InferInput; + + /** Infers the output type of a Standard. */ + export type InferOutput = + StandardTypedV1.InferOutput; +} +``` diff --git a/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.cjs b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.cjs new file mode 100644 index 0000000..321666e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.cjs @@ -0,0 +1,18 @@ +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/index.ts +var src_exports = {}; +module.exports = __toCommonJS(src_exports); diff --git a/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.cts b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.cts new file mode 100644 index 0000000..5e4acaa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.cts @@ -0,0 +1,119 @@ +/** The Standard Typed interface. This is a base type extended by other specs. */ +interface StandardTypedV1 { + /** The Standard properties. */ + readonly "~standard": StandardTypedV1.Props; +} +declare namespace StandardTypedV1 { + /** The Standard Typed properties interface. */ + interface Props { + /** The version number of the standard. */ + readonly version: 1; + /** The vendor name of the schema library. */ + readonly vendor: string; + /** Inferred types associated with the schema. */ + readonly types?: Types | undefined; + } + /** The Standard Typed types interface. */ + interface Types { + /** The input type of the schema. */ + readonly input: Input; + /** The output type of the schema. */ + readonly output: Output; + } + /** Infers the input type of a Standard Typed. */ + type InferInput = NonNullable["input"]; + /** Infers the output type of a Standard Typed. */ + type InferOutput = NonNullable["output"]; +} +/** The Standard Schema interface. */ +interface StandardSchemaV1 { + /** The Standard Schema properties. */ + readonly "~standard": StandardSchemaV1.Props; +} +declare namespace StandardSchemaV1 { + /** The Standard Schema properties interface. */ + interface Props extends StandardTypedV1.Props { + /** Validates unknown input values. */ + readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result | Promise>; + } + /** The result interface of the validate function. */ + type Result = SuccessResult | FailureResult; + /** The result interface if validation succeeds. */ + interface SuccessResult { + /** The typed output value. */ + readonly value: Output; + /** A falsy value for `issues` indicates success. */ + readonly issues?: undefined; + } + interface Options { + /** Explicit support for additional vendor-specific parameters, if needed. */ + readonly libraryOptions?: Record | undefined; + } + /** The result interface if validation fails. */ + interface FailureResult { + /** The issues of failed validation. */ + readonly issues: ReadonlyArray; + } + /** The issue interface of the failure output. */ + interface Issue { + /** The error message of the issue. */ + readonly message: string; + /** The path of the issue, if any. */ + readonly path?: ReadonlyArray | undefined; + } + /** The path segment interface of the issue. */ + interface PathSegment { + /** The key representing a path segment. */ + readonly key: PropertyKey; + } + /** The Standard types interface. */ + interface Types extends StandardTypedV1.Types { + } + /** Infers the input type of a Standard. */ + type InferInput = StandardTypedV1.InferInput; + /** Infers the output type of a Standard. */ + type InferOutput = StandardTypedV1.InferOutput; +} +/** The Standard JSON Schema interface. */ +interface StandardJSONSchemaV1 { + /** The Standard JSON Schema properties. */ + readonly "~standard": StandardJSONSchemaV1.Props; +} +declare namespace StandardJSONSchemaV1 { + /** The Standard JSON Schema properties interface. */ + interface Props extends StandardTypedV1.Props { + /** Methods for generating the input/output JSON Schema. */ + readonly jsonSchema: StandardJSONSchemaV1.Converter; + } + /** The Standard JSON Schema converter interface. */ + interface Converter { + /** Converts the input type to JSON Schema. May throw if conversion is not supported. */ + readonly input: (options: StandardJSONSchemaV1.Options) => Record; + /** Converts the output type to JSON Schema. May throw if conversion is not supported. */ + readonly output: (options: StandardJSONSchemaV1.Options) => Record; + } + /** + * The target version of the generated JSON Schema. + * + * It is *strongly recommended* that implementers support `"draft-2020-12"` and `"draft-07"`, as they are both in wide use. All other targets can be implemented on a best-effort basis. Libraries should throw if they don't support a specified target. + * + * The `"openapi-3.0"` target is intended as a standardized specifier for OpenAPI 3.0 which is a superset of JSON Schema `"draft-04"`. + */ + type Target = "draft-2020-12" | "draft-07" | "openapi-3.0" | ({} & string); + /** The options for the input/output methods. */ + interface Options { + /** Specifies the target version of the generated JSON Schema. Support for all versions is on a best-effort basis. If a given version is not supported, the library should throw. */ + readonly target: Target; + /** Explicit support for additional vendor-specific parameters, if needed. */ + readonly libraryOptions?: Record | undefined; + } + /** The Standard types interface. */ + interface Types extends StandardTypedV1.Types { + } + /** Infers the input type of a Standard. */ + type InferInput = StandardTypedV1.InferInput; + /** Infers the output type of a Standard. */ + type InferOutput = StandardTypedV1.InferOutput; +} + +export { StandardJSONSchemaV1, StandardSchemaV1, StandardTypedV1 }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.ts new file mode 100644 index 0000000..5e4acaa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.ts @@ -0,0 +1,119 @@ +/** The Standard Typed interface. This is a base type extended by other specs. */ +interface StandardTypedV1 { + /** The Standard properties. */ + readonly "~standard": StandardTypedV1.Props; +} +declare namespace StandardTypedV1 { + /** The Standard Typed properties interface. */ + interface Props { + /** The version number of the standard. */ + readonly version: 1; + /** The vendor name of the schema library. */ + readonly vendor: string; + /** Inferred types associated with the schema. */ + readonly types?: Types | undefined; + } + /** The Standard Typed types interface. */ + interface Types { + /** The input type of the schema. */ + readonly input: Input; + /** The output type of the schema. */ + readonly output: Output; + } + /** Infers the input type of a Standard Typed. */ + type InferInput = NonNullable["input"]; + /** Infers the output type of a Standard Typed. */ + type InferOutput = NonNullable["output"]; +} +/** The Standard Schema interface. */ +interface StandardSchemaV1 { + /** The Standard Schema properties. */ + readonly "~standard": StandardSchemaV1.Props; +} +declare namespace StandardSchemaV1 { + /** The Standard Schema properties interface. */ + interface Props extends StandardTypedV1.Props { + /** Validates unknown input values. */ + readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result | Promise>; + } + /** The result interface of the validate function. */ + type Result = SuccessResult | FailureResult; + /** The result interface if validation succeeds. */ + interface SuccessResult { + /** The typed output value. */ + readonly value: Output; + /** A falsy value for `issues` indicates success. */ + readonly issues?: undefined; + } + interface Options { + /** Explicit support for additional vendor-specific parameters, if needed. */ + readonly libraryOptions?: Record | undefined; + } + /** The result interface if validation fails. */ + interface FailureResult { + /** The issues of failed validation. */ + readonly issues: ReadonlyArray; + } + /** The issue interface of the failure output. */ + interface Issue { + /** The error message of the issue. */ + readonly message: string; + /** The path of the issue, if any. */ + readonly path?: ReadonlyArray | undefined; + } + /** The path segment interface of the issue. */ + interface PathSegment { + /** The key representing a path segment. */ + readonly key: PropertyKey; + } + /** The Standard types interface. */ + interface Types extends StandardTypedV1.Types { + } + /** Infers the input type of a Standard. */ + type InferInput = StandardTypedV1.InferInput; + /** Infers the output type of a Standard. */ + type InferOutput = StandardTypedV1.InferOutput; +} +/** The Standard JSON Schema interface. */ +interface StandardJSONSchemaV1 { + /** The Standard JSON Schema properties. */ + readonly "~standard": StandardJSONSchemaV1.Props; +} +declare namespace StandardJSONSchemaV1 { + /** The Standard JSON Schema properties interface. */ + interface Props extends StandardTypedV1.Props { + /** Methods for generating the input/output JSON Schema. */ + readonly jsonSchema: StandardJSONSchemaV1.Converter; + } + /** The Standard JSON Schema converter interface. */ + interface Converter { + /** Converts the input type to JSON Schema. May throw if conversion is not supported. */ + readonly input: (options: StandardJSONSchemaV1.Options) => Record; + /** Converts the output type to JSON Schema. May throw if conversion is not supported. */ + readonly output: (options: StandardJSONSchemaV1.Options) => Record; + } + /** + * The target version of the generated JSON Schema. + * + * It is *strongly recommended* that implementers support `"draft-2020-12"` and `"draft-07"`, as they are both in wide use. All other targets can be implemented on a best-effort basis. Libraries should throw if they don't support a specified target. + * + * The `"openapi-3.0"` target is intended as a standardized specifier for OpenAPI 3.0 which is a superset of JSON Schema `"draft-04"`. + */ + type Target = "draft-2020-12" | "draft-07" | "openapi-3.0" | ({} & string); + /** The options for the input/output methods. */ + interface Options { + /** Specifies the target version of the generated JSON Schema. Support for all versions is on a best-effort basis. If a given version is not supported, the library should throw. */ + readonly target: Target; + /** Explicit support for additional vendor-specific parameters, if needed. */ + readonly libraryOptions?: Record | undefined; + } + /** The Standard types interface. */ + interface Types extends StandardTypedV1.Types { + } + /** Infers the input type of a Standard. */ + type InferInput = StandardTypedV1.InferInput; + /** Infers the output type of a Standard. */ + type InferOutput = StandardTypedV1.InferOutput; +} + +export { StandardJSONSchemaV1, StandardSchemaV1, StandardTypedV1 }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.js b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.js new file mode 100644 index 0000000..e69de29 diff --git a/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/package.json b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/package.json new file mode 100644 index 0000000..62bb551 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/package.json @@ -0,0 +1,52 @@ +{ + "name": "@standard-schema/spec", + "description": "A family of specs for interoperable TypeScript", + "version": "1.1.0", + "license": "MIT", + "author": "Colin McDonnell", + "homepage": "https://standardschema.dev", + "repository": { + "type": "git", + "url": "https://github.com/standard-schema/standard-schema" + }, + "keywords": [ + "typescript", + "schema", + "validation", + "standard", + "interface" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "standard-schema-spec": "./src/index.ts", + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } + } + }, + "sideEffects": false, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "tsup": "^8.3.0", + "typescript": "^5.6.2" + }, + "scripts": { + "lint": "pnpm biome lint ./src", + "format": "pnpm biome format --write ./src", + "check": "pnpm biome check ./src", + "build": "tsup" + } +} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/CHANGELOG.md b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/CHANGELOG.md new file mode 100644 index 0000000..dc39ed6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/CHANGELOG.md @@ -0,0 +1,216 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [2.0.1] - 2020-08-29 +### Fixed +- Fix issue with `process.argv` when used with interpreters (`coffee`, `ts-node`, etc.), #150. + + +## [2.0.0] - 2020-08-14 +### Changed +- Full rewrite. Now port from python 3.9.0 & more precise following. + See [doc](./doc) for difference and migration info. +- node.js 10+ required +- Removed most of local docs in favour of original ones. + + +## [1.0.10] - 2018-02-15 +### Fixed +- Use .concat instead of + for arrays, #122. + + +## [1.0.9] - 2016-09-29 +### Changed +- Rerelease after 1.0.8 - deps cleanup. + + +## [1.0.8] - 2016-09-29 +### Changed +- Maintenance (deps bump, fix node 6.5+ tests, coverage report). + + +## [1.0.7] - 2016-03-17 +### Changed +- Teach `addArgument` to accept string arg names. #97, @tomxtobin. + + +## [1.0.6] - 2016-02-06 +### Changed +- Maintenance: moved to eslint & updated CS. + + +## [1.0.5] - 2016-02-05 +### Changed +- Removed lodash dependency to significantly reduce install size. + Thanks to @mourner. + + +## [1.0.4] - 2016-01-17 +### Changed +- Maintenance: lodash update to 4.0.0. + + +## [1.0.3] - 2015-10-27 +### Fixed +- Fix parse `=` in args: `--examplepath="C:\myfolder\env=x64"`. #84, @CatWithApple. + + +## [1.0.2] - 2015-03-22 +### Changed +- Relaxed lodash version dependency. + + +## [1.0.1] - 2015-02-20 +### Changed +- Changed dependencies to be compatible with ancient nodejs. + + +## [1.0.0] - 2015-02-19 +### Changed +- Maintenance release. +- Replaced `underscore` with `lodash`. +- Bumped version to 1.0.0 to better reflect semver meaning. +- HISTORY.md -> CHANGELOG.md + + +## [0.1.16] - 2013-12-01 +### Changed +- Maintenance release. Updated dependencies and docs. + + +## [0.1.15] - 2013-05-13 +### Fixed +- Fixed #55, @trebor89 + + +## [0.1.14] - 2013-05-12 +### Fixed +- Fixed #62, @maxtaco + + +## [0.1.13] - 2013-04-08 +### Changed +- Added `.npmignore` to reduce package size + + +## [0.1.12] - 2013-02-10 +### Fixed +- Fixed conflictHandler (#46), @hpaulj + + +## [0.1.11] - 2013-02-07 +### Added +- Added 70+ tests (ported from python), @hpaulj +- Added conflictHandler, @applepicke +- Added fromfilePrefixChar, @hpaulj + +### Fixed +- Multiple bugfixes, @hpaulj + + +## [0.1.10] - 2012-12-30 +### Added +- Added [mutual exclusion](http://docs.python.org/dev/library/argparse.html#mutual-exclusion) + support, thanks to @hpaulj + +### Fixed +- Fixed options check for `storeConst` & `appendConst` actions, thanks to @hpaulj + + +## [0.1.9] - 2012-12-27 +### Fixed +- Fixed option dest interferens with other options (issue #23), thanks to @hpaulj +- Fixed default value behavior with `*` positionals, thanks to @hpaulj +- Improve `getDefault()` behavior, thanks to @hpaulj +- Improve negative argument parsing, thanks to @hpaulj + + +## [0.1.8] - 2012-12-01 +### Fixed +- Fixed parser parents (issue #19), thanks to @hpaulj +- Fixed negative argument parse (issue #20), thanks to @hpaulj + + +## [0.1.7] - 2012-10-14 +### Fixed +- Fixed 'choices' argument parse (issue #16) +- Fixed stderr output (issue #15) + + +## [0.1.6] - 2012-09-09 +### Fixed +- Fixed check for conflict of options (thanks to @tomxtobin) + + +## [0.1.5] - 2012-09-03 +### Fixed +- Fix parser #setDefaults method (thanks to @tomxtobin) + + +## [0.1.4] - 2012-07-30 +### Fixed +- Fixed pseudo-argument support (thanks to @CGamesPlay) +- Fixed addHelp default (should be true), if not set (thanks to @benblank) + + +## [0.1.3] - 2012-06-27 +### Fixed +- Fixed formatter api name: Formatter -> HelpFormatter + + +## [0.1.2] - 2012-05-29 +### Fixed +- Removed excess whitespace in help +- Fixed error reporting, when parcer with subcommands + called with empty arguments + +### Added +- Added basic tests + + +## [0.1.1] - 2012-05-23 +### Fixed +- Fixed line wrapping in help formatter +- Added better error reporting on invalid arguments + + +## [0.1.0] - 2012-05-16 +### Added +- First release. + + +[2.0.1]: https://github.com/nodeca/argparse/compare/2.0.0...2.0.1 +[2.0.0]: https://github.com/nodeca/argparse/compare/1.0.10...2.0.0 +[1.0.10]: https://github.com/nodeca/argparse/compare/1.0.9...1.0.10 +[1.0.9]: https://github.com/nodeca/argparse/compare/1.0.8...1.0.9 +[1.0.8]: https://github.com/nodeca/argparse/compare/1.0.7...1.0.8 +[1.0.7]: https://github.com/nodeca/argparse/compare/1.0.6...1.0.7 +[1.0.6]: https://github.com/nodeca/argparse/compare/1.0.5...1.0.6 +[1.0.5]: https://github.com/nodeca/argparse/compare/1.0.4...1.0.5 +[1.0.4]: https://github.com/nodeca/argparse/compare/1.0.3...1.0.4 +[1.0.3]: https://github.com/nodeca/argparse/compare/1.0.2...1.0.3 +[1.0.2]: https://github.com/nodeca/argparse/compare/1.0.1...1.0.2 +[1.0.1]: https://github.com/nodeca/argparse/compare/1.0.0...1.0.1 +[1.0.0]: https://github.com/nodeca/argparse/compare/0.1.16...1.0.0 +[0.1.16]: https://github.com/nodeca/argparse/compare/0.1.15...0.1.16 +[0.1.15]: https://github.com/nodeca/argparse/compare/0.1.14...0.1.15 +[0.1.14]: https://github.com/nodeca/argparse/compare/0.1.13...0.1.14 +[0.1.13]: https://github.com/nodeca/argparse/compare/0.1.12...0.1.13 +[0.1.12]: https://github.com/nodeca/argparse/compare/0.1.11...0.1.12 +[0.1.11]: https://github.com/nodeca/argparse/compare/0.1.10...0.1.11 +[0.1.10]: https://github.com/nodeca/argparse/compare/0.1.9...0.1.10 +[0.1.9]: https://github.com/nodeca/argparse/compare/0.1.8...0.1.9 +[0.1.8]: https://github.com/nodeca/argparse/compare/0.1.7...0.1.8 +[0.1.7]: https://github.com/nodeca/argparse/compare/0.1.6...0.1.7 +[0.1.6]: https://github.com/nodeca/argparse/compare/0.1.5...0.1.6 +[0.1.5]: https://github.com/nodeca/argparse/compare/0.1.4...0.1.5 +[0.1.4]: https://github.com/nodeca/argparse/compare/0.1.3...0.1.4 +[0.1.3]: https://github.com/nodeca/argparse/compare/0.1.2...0.1.3 +[0.1.2]: https://github.com/nodeca/argparse/compare/0.1.1...0.1.2 +[0.1.1]: https://github.com/nodeca/argparse/compare/0.1.0...0.1.1 +[0.1.0]: https://github.com/nodeca/argparse/releases/tag/0.1.0 diff --git a/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/LICENSE new file mode 100644 index 0000000..66a3ac8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/LICENSE @@ -0,0 +1,254 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations, which became +Zope Corporation. In 2001, the Python Software Foundation (PSF, see +https://www.python.org/psf/) was formed, a non-profit organization +created specifically to own Python-related Intellectual Property. +Zope Corporation was a sponsoring member of the PSF. + +All Python releases are Open Source (see http://www.opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2 and above 2.1.1 2001-now PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the Internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the Internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/README.md b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/README.md new file mode 100644 index 0000000..550b5c9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/README.md @@ -0,0 +1,84 @@ +argparse +======== + +[![Build Status](https://secure.travis-ci.org/nodeca/argparse.svg?branch=master)](http://travis-ci.org/nodeca/argparse) +[![NPM version](https://img.shields.io/npm/v/argparse.svg)](https://www.npmjs.org/package/argparse) + +CLI arguments parser for node.js, with [sub-commands](https://docs.python.org/3.9/library/argparse.html#sub-commands) support. Port of python's [argparse](http://docs.python.org/dev/library/argparse.html) (version [3.9.0](https://github.com/python/cpython/blob/v3.9.0rc1/Lib/argparse.py)). + +**Difference with original.** + +- JS has no keyword arguments support. + - Pass options instead: `new ArgumentParser({ description: 'example', add_help: true })`. +- JS has no python's types `int`, `float`, ... + - Use string-typed names: `.add_argument('-b', { type: 'int', help: 'help' })`. +- `%r` format specifier uses `require('util').inspect()`. + +More details in [doc](./doc). + + +Example +------- + +`test.js` file: + +```javascript +#!/usr/bin/env node +'use strict'; + +const { ArgumentParser } = require('argparse'); +const { version } = require('./package.json'); + +const parser = new ArgumentParser({ + description: 'Argparse example' +}); + +parser.add_argument('-v', '--version', { action: 'version', version }); +parser.add_argument('-f', '--foo', { help: 'foo bar' }); +parser.add_argument('-b', '--bar', { help: 'bar foo' }); +parser.add_argument('--baz', { help: 'baz bar' }); + +console.dir(parser.parse_args()); +``` + +Display help: + +``` +$ ./test.js -h +usage: test.js [-h] [-v] [-f FOO] [-b BAR] [--baz BAZ] + +Argparse example + +optional arguments: + -h, --help show this help message and exit + -v, --version show program's version number and exit + -f FOO, --foo FOO foo bar + -b BAR, --bar BAR bar foo + --baz BAZ baz bar +``` + +Parse arguments: + +``` +$ ./test.js -f=3 --bar=4 --baz 5 +{ foo: '3', bar: '4', baz: '5' } +``` + + +API docs +-------- + +Since this is a port with minimal divergence, there's no separate documentation. +Use original one instead, with notes about difference. + +1. [Original doc](https://docs.python.org/3.9/library/argparse.html). +2. [Original tutorial](https://docs.python.org/3.9/howto/argparse.html). +3. [Difference with python](./doc). + + +argparse for enterprise +----------------------- + +Available as part of the Tidelift Subscription + +The maintainers of argparse and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-argparse?utm_source=npm-argparse&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) diff --git a/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/argparse.js b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/argparse.js new file mode 100644 index 0000000..2b8c8c6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/argparse.js @@ -0,0 +1,3707 @@ +// Port of python's argparse module, version 3.9.0: +// https://github.com/python/cpython/blob/v3.9.0rc1/Lib/argparse.py + +'use strict' + +// Copyright (C) 2010-2020 Python Software Foundation. +// Copyright (C) 2020 argparse.js authors + +/* + * Command-line parsing library + * + * This module is an optparse-inspired command-line parsing library that: + * + * - handles both optional and positional arguments + * - produces highly informative usage messages + * - supports parsers that dispatch to sub-parsers + * + * The following is a simple usage example that sums integers from the + * command-line and writes the result to a file:: + * + * parser = argparse.ArgumentParser( + * description='sum the integers at the command line') + * parser.add_argument( + * 'integers', metavar='int', nargs='+', type=int, + * help='an integer to be summed') + * parser.add_argument( + * '--log', default=sys.stdout, type=argparse.FileType('w'), + * help='the file where the sum should be written') + * args = parser.parse_args() + * args.log.write('%s' % sum(args.integers)) + * args.log.close() + * + * The module contains the following public classes: + * + * - ArgumentParser -- The main entry point for command-line parsing. As the + * example above shows, the add_argument() method is used to populate + * the parser with actions for optional and positional arguments. Then + * the parse_args() method is invoked to convert the args at the + * command-line into an object with attributes. + * + * - ArgumentError -- The exception raised by ArgumentParser objects when + * there are errors with the parser's actions. Errors raised while + * parsing the command-line are caught by ArgumentParser and emitted + * as command-line messages. + * + * - FileType -- A factory for defining types of files to be created. As the + * example above shows, instances of FileType are typically passed as + * the type= argument of add_argument() calls. + * + * - Action -- The base class for parser actions. Typically actions are + * selected by passing strings like 'store_true' or 'append_const' to + * the action= argument of add_argument(). However, for greater + * customization of ArgumentParser actions, subclasses of Action may + * be defined and passed as the action= argument. + * + * - HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter, + * ArgumentDefaultsHelpFormatter -- Formatter classes which + * may be passed as the formatter_class= argument to the + * ArgumentParser constructor. HelpFormatter is the default, + * RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser + * not to change the formatting for help text, and + * ArgumentDefaultsHelpFormatter adds information about argument defaults + * to the help. + * + * All other classes in this module are considered implementation details. + * (Also note that HelpFormatter and RawDescriptionHelpFormatter are only + * considered public as object names -- the API of the formatter objects is + * still considered an implementation detail.) + */ + +const SUPPRESS = '==SUPPRESS==' + +const OPTIONAL = '?' +const ZERO_OR_MORE = '*' +const ONE_OR_MORE = '+' +const PARSER = 'A...' +const REMAINDER = '...' +const _UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args' + + +// ================================== +// Utility functions used for porting +// ================================== +const assert = require('assert') +const util = require('util') +const fs = require('fs') +const sub = require('./lib/sub') +const path = require('path') +const repr = util.inspect + +function get_argv() { + // omit first argument (which is assumed to be interpreter - `node`, `coffee`, `ts-node`, etc.) + return process.argv.slice(1) +} + +function get_terminal_size() { + return { + columns: +process.env.COLUMNS || process.stdout.columns || 80 + } +} + +function hasattr(object, name) { + return Object.prototype.hasOwnProperty.call(object, name) +} + +function getattr(object, name, value) { + return hasattr(object, name) ? object[name] : value +} + +function setattr(object, name, value) { + object[name] = value +} + +function setdefault(object, name, value) { + if (!hasattr(object, name)) object[name] = value + return object[name] +} + +function delattr(object, name) { + delete object[name] +} + +function range(from, to, step=1) { + // range(10) is equivalent to range(0, 10) + if (arguments.length === 1) [ to, from ] = [ from, 0 ] + if (typeof from !== 'number' || typeof to !== 'number' || typeof step !== 'number') { + throw new TypeError('argument cannot be interpreted as an integer') + } + if (step === 0) throw new TypeError('range() arg 3 must not be zero') + + let result = [] + if (step > 0) { + for (let i = from; i < to; i += step) result.push(i) + } else { + for (let i = from; i > to; i += step) result.push(i) + } + return result +} + +function splitlines(str, keepends = false) { + let result + if (!keepends) { + result = str.split(/\r\n|[\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029]/) + } else { + result = [] + let parts = str.split(/(\r\n|[\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029])/) + for (let i = 0; i < parts.length; i += 2) { + result.push(parts[i] + (i + 1 < parts.length ? parts[i + 1] : '')) + } + } + if (!result[result.length - 1]) result.pop() + return result +} + +function _string_lstrip(string, prefix_chars) { + let idx = 0 + while (idx < string.length && prefix_chars.includes(string[idx])) idx++ + return idx ? string.slice(idx) : string +} + +function _string_split(string, sep, maxsplit) { + let result = string.split(sep) + if (result.length > maxsplit) { + result = result.slice(0, maxsplit).concat([ result.slice(maxsplit).join(sep) ]) + } + return result +} + +function _array_equal(array1, array2) { + if (array1.length !== array2.length) return false + for (let i = 0; i < array1.length; i++) { + if (array1[i] !== array2[i]) return false + } + return true +} + +function _array_remove(array, item) { + let idx = array.indexOf(item) + if (idx === -1) throw new TypeError(sub('%r not in list', item)) + array.splice(idx, 1) +} + +// normalize choices to array; +// this isn't required in python because `in` and `map` operators work with anything, +// but in js dealing with multiple types here is too clunky +function _choices_to_array(choices) { + if (choices === undefined) { + return [] + } else if (Array.isArray(choices)) { + return choices + } else if (choices !== null && typeof choices[Symbol.iterator] === 'function') { + return Array.from(choices) + } else if (typeof choices === 'object' && choices !== null) { + return Object.keys(choices) + } else { + throw new Error(sub('invalid choices value: %r', choices)) + } +} + +// decorator that allows a class to be called without new +function _callable(cls) { + let result = { // object is needed for inferred class name + [cls.name]: function (...args) { + let this_class = new.target === result || !new.target + return Reflect.construct(cls, args, this_class ? cls : new.target) + } + } + result[cls.name].prototype = cls.prototype + // fix default tag for toString, e.g. [object Action] instead of [object Object] + cls.prototype[Symbol.toStringTag] = cls.name + return result[cls.name] +} + +function _alias(object, from, to) { + try { + let name = object.constructor.name + Object.defineProperty(object, from, { + value: util.deprecate(object[to], sub('%s.%s() is renamed to %s.%s()', + name, from, name, to)), + enumerable: false + }) + } catch {} +} + +// decorator that allows snake_case class methods to be called with camelCase and vice versa +function _camelcase_alias(_class) { + for (let name of Object.getOwnPropertyNames(_class.prototype)) { + let camelcase = name.replace(/\w_[a-z]/g, s => s[0] + s[2].toUpperCase()) + if (camelcase !== name) _alias(_class.prototype, camelcase, name) + } + return _class +} + +function _to_legacy_name(key) { + key = key.replace(/\w_[a-z]/g, s => s[0] + s[2].toUpperCase()) + if (key === 'default') key = 'defaultValue' + if (key === 'const') key = 'constant' + return key +} + +function _to_new_name(key) { + if (key === 'defaultValue') key = 'default' + if (key === 'constant') key = 'const' + key = key.replace(/[A-Z]/g, c => '_' + c.toLowerCase()) + return key +} + +// parse options +let no_default = Symbol('no_default_value') +function _parse_opts(args, descriptor) { + function get_name() { + let stack = new Error().stack.split('\n') + .map(x => x.match(/^ at (.*) \(.*\)$/)) + .filter(Boolean) + .map(m => m[1]) + .map(fn => fn.match(/[^ .]*$/)[0]) + + if (stack.length && stack[0] === get_name.name) stack.shift() + if (stack.length && stack[0] === _parse_opts.name) stack.shift() + return stack.length ? stack[0] : '' + } + + args = Array.from(args) + let kwargs = {} + let result = [] + let last_opt = args.length && args[args.length - 1] + + if (typeof last_opt === 'object' && last_opt !== null && !Array.isArray(last_opt) && + (!last_opt.constructor || last_opt.constructor.name === 'Object')) { + kwargs = Object.assign({}, args.pop()) + } + + // LEGACY (v1 compatibility): camelcase + let renames = [] + for (let key of Object.keys(descriptor)) { + let old_name = _to_legacy_name(key) + if (old_name !== key && (old_name in kwargs)) { + if (key in kwargs) { + // default and defaultValue specified at the same time, happens often in old tests + //throw new TypeError(sub('%s() got multiple values for argument %r', get_name(), key)) + } else { + kwargs[key] = kwargs[old_name] + } + renames.push([ old_name, key ]) + delete kwargs[old_name] + } + } + if (renames.length) { + let name = get_name() + deprecate('camelcase_' + name, sub('%s(): following options are renamed: %s', + name, renames.map(([ a, b ]) => sub('%r -> %r', a, b)))) + } + // end + + let missing_positionals = [] + let positional_count = args.length + + for (let [ key, def ] of Object.entries(descriptor)) { + if (key[0] === '*') { + if (key.length > 0 && key[1] === '*') { + // LEGACY (v1 compatibility): camelcase + let renames = [] + for (let key of Object.keys(kwargs)) { + let new_name = _to_new_name(key) + if (new_name !== key && (key in kwargs)) { + if (new_name in kwargs) { + // default and defaultValue specified at the same time, happens often in old tests + //throw new TypeError(sub('%s() got multiple values for argument %r', get_name(), new_name)) + } else { + kwargs[new_name] = kwargs[key] + } + renames.push([ key, new_name ]) + delete kwargs[key] + } + } + if (renames.length) { + let name = get_name() + deprecate('camelcase_' + name, sub('%s(): following options are renamed: %s', + name, renames.map(([ a, b ]) => sub('%r -> %r', a, b)))) + } + // end + result.push(kwargs) + kwargs = {} + } else { + result.push(args) + args = [] + } + } else if (key in kwargs && args.length > 0) { + throw new TypeError(sub('%s() got multiple values for argument %r', get_name(), key)) + } else if (key in kwargs) { + result.push(kwargs[key]) + delete kwargs[key] + } else if (args.length > 0) { + result.push(args.shift()) + } else if (def !== no_default) { + result.push(def) + } else { + missing_positionals.push(key) + } + } + + if (Object.keys(kwargs).length) { + throw new TypeError(sub('%s() got an unexpected keyword argument %r', + get_name(), Object.keys(kwargs)[0])) + } + + if (args.length) { + let from = Object.entries(descriptor).filter(([ k, v ]) => k[0] !== '*' && v !== no_default).length + let to = Object.entries(descriptor).filter(([ k ]) => k[0] !== '*').length + throw new TypeError(sub('%s() takes %s positional argument%s but %s %s given', + get_name(), + from === to ? sub('from %s to %s', from, to) : to, + from === to && to === 1 ? '' : 's', + positional_count, + positional_count === 1 ? 'was' : 'were')) + } + + if (missing_positionals.length) { + let strs = missing_positionals.map(repr) + if (strs.length > 1) strs[strs.length - 1] = 'and ' + strs[strs.length - 1] + let str_joined = strs.join(strs.length === 2 ? '' : ', ') + throw new TypeError(sub('%s() missing %i required positional argument%s: %s', + get_name(), strs.length, strs.length === 1 ? '' : 's', str_joined)) + } + + return result +} + +let _deprecations = {} +function deprecate(id, string) { + _deprecations[id] = _deprecations[id] || util.deprecate(() => {}, string) + _deprecations[id]() +} + + +// ============================= +// Utility functions and classes +// ============================= +function _AttributeHolder(cls = Object) { + /* + * Abstract base class that provides __repr__. + * + * The __repr__ method returns a string in the format:: + * ClassName(attr=name, attr=name, ...) + * The attributes are determined either by a class-level attribute, + * '_kwarg_names', or by inspecting the instance __dict__. + */ + + return class _AttributeHolder extends cls { + [util.inspect.custom]() { + let type_name = this.constructor.name + let arg_strings = [] + let star_args = {} + for (let arg of this._get_args()) { + arg_strings.push(repr(arg)) + } + for (let [ name, value ] of this._get_kwargs()) { + if (/^[a-z_][a-z0-9_$]*$/i.test(name)) { + arg_strings.push(sub('%s=%r', name, value)) + } else { + star_args[name] = value + } + } + if (Object.keys(star_args).length) { + arg_strings.push(sub('**%s', repr(star_args))) + } + return sub('%s(%s)', type_name, arg_strings.join(', ')) + } + + toString() { + return this[util.inspect.custom]() + } + + _get_kwargs() { + return Object.entries(this) + } + + _get_args() { + return [] + } + } +} + + +function _copy_items(items) { + if (items === undefined) { + return [] + } + return items.slice(0) +} + + +// =============== +// Formatting Help +// =============== +const HelpFormatter = _camelcase_alias(_callable(class HelpFormatter { + /* + * Formatter for generating usage messages and argument help strings. + * + * Only the name of this class is considered a public API. All the methods + * provided by the class are considered an implementation detail. + */ + + constructor() { + let [ + prog, + indent_increment, + max_help_position, + width + ] = _parse_opts(arguments, { + prog: no_default, + indent_increment: 2, + max_help_position: 24, + width: undefined + }) + + // default setting for width + if (width === undefined) { + width = get_terminal_size().columns + width -= 2 + } + + this._prog = prog + this._indent_increment = indent_increment + this._max_help_position = Math.min(max_help_position, + Math.max(width - 20, indent_increment * 2)) + this._width = width + + this._current_indent = 0 + this._level = 0 + this._action_max_length = 0 + + this._root_section = this._Section(this, undefined) + this._current_section = this._root_section + + this._whitespace_matcher = /[ \t\n\r\f\v]+/g // equivalent to python /\s+/ with ASCII flag + this._long_break_matcher = /\n\n\n+/g + } + + // =============================== + // Section and indentation methods + // =============================== + _indent() { + this._current_indent += this._indent_increment + this._level += 1 + } + + _dedent() { + this._current_indent -= this._indent_increment + assert(this._current_indent >= 0, 'Indent decreased below 0.') + this._level -= 1 + } + + _add_item(func, args) { + this._current_section.items.push([ func, args ]) + } + + // ======================== + // Message building methods + // ======================== + start_section(heading) { + this._indent() + let section = this._Section(this, this._current_section, heading) + this._add_item(section.format_help.bind(section), []) + this._current_section = section + } + + end_section() { + this._current_section = this._current_section.parent + this._dedent() + } + + add_text(text) { + if (text !== SUPPRESS && text !== undefined) { + this._add_item(this._format_text.bind(this), [text]) + } + } + + add_usage(usage, actions, groups, prefix = undefined) { + if (usage !== SUPPRESS) { + let args = [ usage, actions, groups, prefix ] + this._add_item(this._format_usage.bind(this), args) + } + } + + add_argument(action) { + if (action.help !== SUPPRESS) { + + // find all invocations + let invocations = [this._format_action_invocation(action)] + for (let subaction of this._iter_indented_subactions(action)) { + invocations.push(this._format_action_invocation(subaction)) + } + + // update the maximum item length + let invocation_length = Math.max(...invocations.map(invocation => invocation.length)) + let action_length = invocation_length + this._current_indent + this._action_max_length = Math.max(this._action_max_length, + action_length) + + // add the item to the list + this._add_item(this._format_action.bind(this), [action]) + } + } + + add_arguments(actions) { + for (let action of actions) { + this.add_argument(action) + } + } + + // ======================= + // Help-formatting methods + // ======================= + format_help() { + let help = this._root_section.format_help() + if (help) { + help = help.replace(this._long_break_matcher, '\n\n') + help = help.replace(/^\n+|\n+$/g, '') + '\n' + } + return help + } + + _join_parts(part_strings) { + return part_strings.filter(part => part && part !== SUPPRESS).join('') + } + + _format_usage(usage, actions, groups, prefix) { + if (prefix === undefined) { + prefix = 'usage: ' + } + + // if usage is specified, use that + if (usage !== undefined) { + usage = sub(usage, { prog: this._prog }) + + // if no optionals or positionals are available, usage is just prog + } else if (usage === undefined && !actions.length) { + usage = sub('%(prog)s', { prog: this._prog }) + + // if optionals and positionals are available, calculate usage + } else if (usage === undefined) { + let prog = sub('%(prog)s', { prog: this._prog }) + + // split optionals from positionals + let optionals = [] + let positionals = [] + for (let action of actions) { + if (action.option_strings.length) { + optionals.push(action) + } else { + positionals.push(action) + } + } + + // build full usage string + let action_usage = this._format_actions_usage([].concat(optionals).concat(positionals), groups) + usage = [ prog, action_usage ].map(String).join(' ') + + // wrap the usage parts if it's too long + let text_width = this._width - this._current_indent + if (prefix.length + usage.length > text_width) { + + // break usage into wrappable parts + let part_regexp = /\(.*?\)+(?=\s|$)|\[.*?\]+(?=\s|$)|\S+/g + let opt_usage = this._format_actions_usage(optionals, groups) + let pos_usage = this._format_actions_usage(positionals, groups) + let opt_parts = opt_usage.match(part_regexp) || [] + let pos_parts = pos_usage.match(part_regexp) || [] + assert(opt_parts.join(' ') === opt_usage) + assert(pos_parts.join(' ') === pos_usage) + + // helper for wrapping lines + let get_lines = (parts, indent, prefix = undefined) => { + let lines = [] + let line = [] + let line_len + if (prefix !== undefined) { + line_len = prefix.length - 1 + } else { + line_len = indent.length - 1 + } + for (let part of parts) { + if (line_len + 1 + part.length > text_width && line) { + lines.push(indent + line.join(' ')) + line = [] + line_len = indent.length - 1 + } + line.push(part) + line_len += part.length + 1 + } + if (line.length) { + lines.push(indent + line.join(' ')) + } + if (prefix !== undefined) { + lines[0] = lines[0].slice(indent.length) + } + return lines + } + + let lines + + // if prog is short, follow it with optionals or positionals + if (prefix.length + prog.length <= 0.75 * text_width) { + let indent = ' '.repeat(prefix.length + prog.length + 1) + if (opt_parts.length) { + lines = get_lines([prog].concat(opt_parts), indent, prefix) + lines = lines.concat(get_lines(pos_parts, indent)) + } else if (pos_parts.length) { + lines = get_lines([prog].concat(pos_parts), indent, prefix) + } else { + lines = [prog] + } + + // if prog is long, put it on its own line + } else { + let indent = ' '.repeat(prefix.length) + let parts = [].concat(opt_parts).concat(pos_parts) + lines = get_lines(parts, indent) + if (lines.length > 1) { + lines = [] + lines = lines.concat(get_lines(opt_parts, indent)) + lines = lines.concat(get_lines(pos_parts, indent)) + } + lines = [prog].concat(lines) + } + + // join lines into usage + usage = lines.join('\n') + } + } + + // prefix with 'usage:' + return sub('%s%s\n\n', prefix, usage) + } + + _format_actions_usage(actions, groups) { + // find group indices and identify actions in groups + let group_actions = new Set() + let inserts = {} + for (let group of groups) { + let start = actions.indexOf(group._group_actions[0]) + if (start === -1) { + continue + } else { + let end = start + group._group_actions.length + if (_array_equal(actions.slice(start, end), group._group_actions)) { + for (let action of group._group_actions) { + group_actions.add(action) + } + if (!group.required) { + if (start in inserts) { + inserts[start] += ' [' + } else { + inserts[start] = '[' + } + if (end in inserts) { + inserts[end] += ']' + } else { + inserts[end] = ']' + } + } else { + if (start in inserts) { + inserts[start] += ' (' + } else { + inserts[start] = '(' + } + if (end in inserts) { + inserts[end] += ')' + } else { + inserts[end] = ')' + } + } + for (let i of range(start + 1, end)) { + inserts[i] = '|' + } + } + } + } + + // collect all actions format strings + let parts = [] + for (let [ i, action ] of Object.entries(actions)) { + + // suppressed arguments are marked with None + // remove | separators for suppressed arguments + if (action.help === SUPPRESS) { + parts.push(undefined) + if (inserts[+i] === '|') { + delete inserts[+i] + } else if (inserts[+i + 1] === '|') { + delete inserts[+i + 1] + } + + // produce all arg strings + } else if (!action.option_strings.length) { + let default_value = this._get_default_metavar_for_positional(action) + let part = this._format_args(action, default_value) + + // if it's in a group, strip the outer [] + if (group_actions.has(action)) { + if (part[0] === '[' && part[part.length - 1] === ']') { + part = part.slice(1, -1) + } + } + + // add the action string to the list + parts.push(part) + + // produce the first way to invoke the option in brackets + } else { + let option_string = action.option_strings[0] + let part + + // if the Optional doesn't take a value, format is: + // -s or --long + if (action.nargs === 0) { + part = action.format_usage() + + // if the Optional takes a value, format is: + // -s ARGS or --long ARGS + } else { + let default_value = this._get_default_metavar_for_optional(action) + let args_string = this._format_args(action, default_value) + part = sub('%s %s', option_string, args_string) + } + + // make it look optional if it's not required or in a group + if (!action.required && !group_actions.has(action)) { + part = sub('[%s]', part) + } + + // add the action string to the list + parts.push(part) + } + } + + // insert things at the necessary indices + for (let i of Object.keys(inserts).map(Number).sort((a, b) => b - a)) { + parts.splice(+i, 0, inserts[+i]) + } + + // join all the action items with spaces + let text = parts.filter(Boolean).join(' ') + + // clean up separators for mutually exclusive groups + text = text.replace(/([\[(]) /g, '$1') + text = text.replace(/ ([\])])/g, '$1') + text = text.replace(/[\[(] *[\])]/g, '') + text = text.replace(/\(([^|]*)\)/g, '$1', text) + text = text.trim() + + // return the text + return text + } + + _format_text(text) { + if (text.includes('%(prog)')) { + text = sub(text, { prog: this._prog }) + } + let text_width = Math.max(this._width - this._current_indent, 11) + let indent = ' '.repeat(this._current_indent) + return this._fill_text(text, text_width, indent) + '\n\n' + } + + _format_action(action) { + // determine the required width and the entry label + let help_position = Math.min(this._action_max_length + 2, + this._max_help_position) + let help_width = Math.max(this._width - help_position, 11) + let action_width = help_position - this._current_indent - 2 + let action_header = this._format_action_invocation(action) + let indent_first + + // no help; start on same line and add a final newline + if (!action.help) { + let tup = [ this._current_indent, '', action_header ] + action_header = sub('%*s%s\n', ...tup) + + // short action name; start on the same line and pad two spaces + } else if (action_header.length <= action_width) { + let tup = [ this._current_indent, '', action_width, action_header ] + action_header = sub('%*s%-*s ', ...tup) + indent_first = 0 + + // long action name; start on the next line + } else { + let tup = [ this._current_indent, '', action_header ] + action_header = sub('%*s%s\n', ...tup) + indent_first = help_position + } + + // collect the pieces of the action help + let parts = [action_header] + + // if there was help for the action, add lines of help text + if (action.help) { + let help_text = this._expand_help(action) + let help_lines = this._split_lines(help_text, help_width) + parts.push(sub('%*s%s\n', indent_first, '', help_lines[0])) + for (let line of help_lines.slice(1)) { + parts.push(sub('%*s%s\n', help_position, '', line)) + } + + // or add a newline if the description doesn't end with one + } else if (!action_header.endsWith('\n')) { + parts.push('\n') + } + + // if there are any sub-actions, add their help as well + for (let subaction of this._iter_indented_subactions(action)) { + parts.push(this._format_action(subaction)) + } + + // return a single string + return this._join_parts(parts) + } + + _format_action_invocation(action) { + if (!action.option_strings.length) { + let default_value = this._get_default_metavar_for_positional(action) + let metavar = this._metavar_formatter(action, default_value)(1)[0] + return metavar + + } else { + let parts = [] + + // if the Optional doesn't take a value, format is: + // -s, --long + if (action.nargs === 0) { + parts = parts.concat(action.option_strings) + + // if the Optional takes a value, format is: + // -s ARGS, --long ARGS + } else { + let default_value = this._get_default_metavar_for_optional(action) + let args_string = this._format_args(action, default_value) + for (let option_string of action.option_strings) { + parts.push(sub('%s %s', option_string, args_string)) + } + } + + return parts.join(', ') + } + } + + _metavar_formatter(action, default_metavar) { + let result + if (action.metavar !== undefined) { + result = action.metavar + } else if (action.choices !== undefined) { + let choice_strs = _choices_to_array(action.choices).map(String) + result = sub('{%s}', choice_strs.join(',')) + } else { + result = default_metavar + } + + function format(tuple_size) { + if (Array.isArray(result)) { + return result + } else { + return Array(tuple_size).fill(result) + } + } + return format + } + + _format_args(action, default_metavar) { + let get_metavar = this._metavar_formatter(action, default_metavar) + let result + if (action.nargs === undefined) { + result = sub('%s', ...get_metavar(1)) + } else if (action.nargs === OPTIONAL) { + result = sub('[%s]', ...get_metavar(1)) + } else if (action.nargs === ZERO_OR_MORE) { + let metavar = get_metavar(1) + if (metavar.length === 2) { + result = sub('[%s [%s ...]]', ...metavar) + } else { + result = sub('[%s ...]', ...metavar) + } + } else if (action.nargs === ONE_OR_MORE) { + result = sub('%s [%s ...]', ...get_metavar(2)) + } else if (action.nargs === REMAINDER) { + result = '...' + } else if (action.nargs === PARSER) { + result = sub('%s ...', ...get_metavar(1)) + } else if (action.nargs === SUPPRESS) { + result = '' + } else { + let formats + try { + formats = range(action.nargs).map(() => '%s') + } catch (err) { + throw new TypeError('invalid nargs value') + } + result = sub(formats.join(' '), ...get_metavar(action.nargs)) + } + return result + } + + _expand_help(action) { + let params = Object.assign({ prog: this._prog }, action) + for (let name of Object.keys(params)) { + if (params[name] === SUPPRESS) { + delete params[name] + } + } + for (let name of Object.keys(params)) { + if (params[name] && params[name].name) { + params[name] = params[name].name + } + } + if (params.choices !== undefined) { + let choices_str = _choices_to_array(params.choices).map(String).join(', ') + params.choices = choices_str + } + // LEGACY (v1 compatibility): camelcase + for (let key of Object.keys(params)) { + let old_name = _to_legacy_name(key) + if (old_name !== key) { + params[old_name] = params[key] + } + } + // end + return sub(this._get_help_string(action), params) + } + + * _iter_indented_subactions(action) { + if (typeof action._get_subactions === 'function') { + this._indent() + yield* action._get_subactions() + this._dedent() + } + } + + _split_lines(text, width) { + text = text.replace(this._whitespace_matcher, ' ').trim() + // The textwrap module is used only for formatting help. + // Delay its import for speeding up the common usage of argparse. + let textwrap = require('./lib/textwrap') + return textwrap.wrap(text, { width }) + } + + _fill_text(text, width, indent) { + text = text.replace(this._whitespace_matcher, ' ').trim() + let textwrap = require('./lib/textwrap') + return textwrap.fill(text, { width, + initial_indent: indent, + subsequent_indent: indent }) + } + + _get_help_string(action) { + return action.help + } + + _get_default_metavar_for_optional(action) { + return action.dest.toUpperCase() + } + + _get_default_metavar_for_positional(action) { + return action.dest + } +})) + +HelpFormatter.prototype._Section = _callable(class _Section { + + constructor(formatter, parent, heading = undefined) { + this.formatter = formatter + this.parent = parent + this.heading = heading + this.items = [] + } + + format_help() { + // format the indented section + if (this.parent !== undefined) { + this.formatter._indent() + } + let item_help = this.formatter._join_parts(this.items.map(([ func, args ]) => func.apply(null, args))) + if (this.parent !== undefined) { + this.formatter._dedent() + } + + // return nothing if the section was empty + if (!item_help) { + return '' + } + + // add the heading if the section was non-empty + let heading + if (this.heading !== SUPPRESS && this.heading !== undefined) { + let current_indent = this.formatter._current_indent + heading = sub('%*s%s:\n', current_indent, '', this.heading) + } else { + heading = '' + } + + // join the section-initial newline, the heading and the help + return this.formatter._join_parts(['\n', heading, item_help, '\n']) + } +}) + + +const RawDescriptionHelpFormatter = _camelcase_alias(_callable(class RawDescriptionHelpFormatter extends HelpFormatter { + /* + * Help message formatter which retains any formatting in descriptions. + * + * Only the name of this class is considered a public API. All the methods + * provided by the class are considered an implementation detail. + */ + + _fill_text(text, width, indent) { + return splitlines(text, true).map(line => indent + line).join('') + } +})) + + +const RawTextHelpFormatter = _camelcase_alias(_callable(class RawTextHelpFormatter extends RawDescriptionHelpFormatter { + /* + * Help message formatter which retains formatting of all help text. + * + * Only the name of this class is considered a public API. All the methods + * provided by the class are considered an implementation detail. + */ + + _split_lines(text/*, width*/) { + return splitlines(text) + } +})) + + +const ArgumentDefaultsHelpFormatter = _camelcase_alias(_callable(class ArgumentDefaultsHelpFormatter extends HelpFormatter { + /* + * Help message formatter which adds default values to argument help. + * + * Only the name of this class is considered a public API. All the methods + * provided by the class are considered an implementation detail. + */ + + _get_help_string(action) { + let help = action.help + // LEGACY (v1 compatibility): additional check for defaultValue needed + if (!action.help.includes('%(default)') && !action.help.includes('%(defaultValue)')) { + if (action.default !== SUPPRESS) { + let defaulting_nargs = [OPTIONAL, ZERO_OR_MORE] + if (action.option_strings.length || defaulting_nargs.includes(action.nargs)) { + help += ' (default: %(default)s)' + } + } + } + return help + } +})) + + +const MetavarTypeHelpFormatter = _camelcase_alias(_callable(class MetavarTypeHelpFormatter extends HelpFormatter { + /* + * Help message formatter which uses the argument 'type' as the default + * metavar value (instead of the argument 'dest') + * + * Only the name of this class is considered a public API. All the methods + * provided by the class are considered an implementation detail. + */ + + _get_default_metavar_for_optional(action) { + return typeof action.type === 'function' ? action.type.name : action.type + } + + _get_default_metavar_for_positional(action) { + return typeof action.type === 'function' ? action.type.name : action.type + } +})) + + +// ===================== +// Options and Arguments +// ===================== +function _get_action_name(argument) { + if (argument === undefined) { + return undefined + } else if (argument.option_strings.length) { + return argument.option_strings.join('/') + } else if (![ undefined, SUPPRESS ].includes(argument.metavar)) { + return argument.metavar + } else if (![ undefined, SUPPRESS ].includes(argument.dest)) { + return argument.dest + } else { + return undefined + } +} + + +const ArgumentError = _callable(class ArgumentError extends Error { + /* + * An error from creating or using an argument (optional or positional). + * + * The string value of this exception is the message, augmented with + * information about the argument that caused it. + */ + + constructor(argument, message) { + super() + this.name = 'ArgumentError' + this._argument_name = _get_action_name(argument) + this._message = message + this.message = this.str() + } + + str() { + let format + if (this._argument_name === undefined) { + format = '%(message)s' + } else { + format = 'argument %(argument_name)s: %(message)s' + } + return sub(format, { message: this._message, + argument_name: this._argument_name }) + } +}) + + +const ArgumentTypeError = _callable(class ArgumentTypeError extends Error { + /* + * An error from trying to convert a command line string to a type. + */ + + constructor(message) { + super(message) + this.name = 'ArgumentTypeError' + } +}) + + +// ============== +// Action classes +// ============== +const Action = _camelcase_alias(_callable(class Action extends _AttributeHolder(Function) { + /* + * Information about how to convert command line strings to Python objects. + * + * Action objects are used by an ArgumentParser to represent the information + * needed to parse a single argument from one or more strings from the + * command line. The keyword arguments to the Action constructor are also + * all attributes of Action instances. + * + * Keyword Arguments: + * + * - option_strings -- A list of command-line option strings which + * should be associated with this action. + * + * - dest -- The name of the attribute to hold the created object(s) + * + * - nargs -- The number of command-line arguments that should be + * consumed. By default, one argument will be consumed and a single + * value will be produced. Other values include: + * - N (an integer) consumes N arguments (and produces a list) + * - '?' consumes zero or one arguments + * - '*' consumes zero or more arguments (and produces a list) + * - '+' consumes one or more arguments (and produces a list) + * Note that the difference between the default and nargs=1 is that + * with the default, a single value will be produced, while with + * nargs=1, a list containing a single value will be produced. + * + * - const -- The value to be produced if the option is specified and the + * option uses an action that takes no values. + * + * - default -- The value to be produced if the option is not specified. + * + * - type -- A callable that accepts a single string argument, and + * returns the converted value. The standard Python types str, int, + * float, and complex are useful examples of such callables. If None, + * str is used. + * + * - choices -- A container of values that should be allowed. If not None, + * after a command-line argument has been converted to the appropriate + * type, an exception will be raised if it is not a member of this + * collection. + * + * - required -- True if the action must always be specified at the + * command line. This is only meaningful for optional command-line + * arguments. + * + * - help -- The help string describing the argument. + * + * - metavar -- The name to be used for the option's argument with the + * help string. If None, the 'dest' value will be used as the name. + */ + + constructor() { + let [ + option_strings, + dest, + nargs, + const_value, + default_value, + type, + choices, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + nargs: undefined, + const: undefined, + default: undefined, + type: undefined, + choices: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + // when this class is called as a function, redirect it to .call() method of itself + super('return arguments.callee.call.apply(arguments.callee, arguments)') + + this.option_strings = option_strings + this.dest = dest + this.nargs = nargs + this.const = const_value + this.default = default_value + this.type = type + this.choices = choices + this.required = required + this.help = help + this.metavar = metavar + } + + _get_kwargs() { + let names = [ + 'option_strings', + 'dest', + 'nargs', + 'const', + 'default', + 'type', + 'choices', + 'help', + 'metavar' + ] + return names.map(name => [ name, getattr(this, name) ]) + } + + format_usage() { + return this.option_strings[0] + } + + call(/*parser, namespace, values, option_string = undefined*/) { + throw new Error('.call() not defined') + } +})) + + +const BooleanOptionalAction = _camelcase_alias(_callable(class BooleanOptionalAction extends Action { + + constructor() { + let [ + option_strings, + dest, + default_value, + type, + choices, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + default: undefined, + type: undefined, + choices: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + let _option_strings = [] + for (let option_string of option_strings) { + _option_strings.push(option_string) + + if (option_string.startsWith('--')) { + option_string = '--no-' + option_string.slice(2) + _option_strings.push(option_string) + } + } + + if (help !== undefined && default_value !== undefined) { + help += ` (default: ${default_value})` + } + + super({ + option_strings: _option_strings, + dest, + nargs: 0, + default: default_value, + type, + choices, + required, + help, + metavar + }) + } + + call(parser, namespace, values, option_string = undefined) { + if (this.option_strings.includes(option_string)) { + setattr(namespace, this.dest, !option_string.startsWith('--no-')) + } + } + + format_usage() { + return this.option_strings.join(' | ') + } +})) + + +const _StoreAction = _callable(class _StoreAction extends Action { + + constructor() { + let [ + option_strings, + dest, + nargs, + const_value, + default_value, + type, + choices, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + nargs: undefined, + const: undefined, + default: undefined, + type: undefined, + choices: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + if (nargs === 0) { + throw new TypeError('nargs for store actions must be != 0; if you ' + + 'have nothing to store, actions such as store ' + + 'true or store const may be more appropriate') + } + if (const_value !== undefined && nargs !== OPTIONAL) { + throw new TypeError(sub('nargs must be %r to supply const', OPTIONAL)) + } + super({ + option_strings, + dest, + nargs, + const: const_value, + default: default_value, + type, + choices, + required, + help, + metavar + }) + } + + call(parser, namespace, values/*, option_string = undefined*/) { + setattr(namespace, this.dest, values) + } +}) + + +const _StoreConstAction = _callable(class _StoreConstAction extends Action { + + constructor() { + let [ + option_strings, + dest, + const_value, + default_value, + required, + help + //, metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + const: no_default, + default: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + super({ + option_strings, + dest, + nargs: 0, + const: const_value, + default: default_value, + required, + help + }) + } + + call(parser, namespace/*, values, option_string = undefined*/) { + setattr(namespace, this.dest, this.const) + } +}) + + +const _StoreTrueAction = _callable(class _StoreTrueAction extends _StoreConstAction { + + constructor() { + let [ + option_strings, + dest, + default_value, + required, + help + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + default: false, + required: false, + help: undefined + }) + + super({ + option_strings, + dest, + const: true, + default: default_value, + required, + help + }) + } +}) + + +const _StoreFalseAction = _callable(class _StoreFalseAction extends _StoreConstAction { + + constructor() { + let [ + option_strings, + dest, + default_value, + required, + help + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + default: true, + required: false, + help: undefined + }) + + super({ + option_strings, + dest, + const: false, + default: default_value, + required, + help + }) + } +}) + + +const _AppendAction = _callable(class _AppendAction extends Action { + + constructor() { + let [ + option_strings, + dest, + nargs, + const_value, + default_value, + type, + choices, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + nargs: undefined, + const: undefined, + default: undefined, + type: undefined, + choices: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + if (nargs === 0) { + throw new TypeError('nargs for append actions must be != 0; if arg ' + + 'strings are not supplying the value to append, ' + + 'the append const action may be more appropriate') + } + if (const_value !== undefined && nargs !== OPTIONAL) { + throw new TypeError(sub('nargs must be %r to supply const', OPTIONAL)) + } + super({ + option_strings, + dest, + nargs, + const: const_value, + default: default_value, + type, + choices, + required, + help, + metavar + }) + } + + call(parser, namespace, values/*, option_string = undefined*/) { + let items = getattr(namespace, this.dest, undefined) + items = _copy_items(items) + items.push(values) + setattr(namespace, this.dest, items) + } +}) + + +const _AppendConstAction = _callable(class _AppendConstAction extends Action { + + constructor() { + let [ + option_strings, + dest, + const_value, + default_value, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + const: no_default, + default: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + super({ + option_strings, + dest, + nargs: 0, + const: const_value, + default: default_value, + required, + help, + metavar + }) + } + + call(parser, namespace/*, values, option_string = undefined*/) { + let items = getattr(namespace, this.dest, undefined) + items = _copy_items(items) + items.push(this.const) + setattr(namespace, this.dest, items) + } +}) + + +const _CountAction = _callable(class _CountAction extends Action { + + constructor() { + let [ + option_strings, + dest, + default_value, + required, + help + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + default: undefined, + required: false, + help: undefined + }) + + super({ + option_strings, + dest, + nargs: 0, + default: default_value, + required, + help + }) + } + + call(parser, namespace/*, values, option_string = undefined*/) { + let count = getattr(namespace, this.dest, undefined) + if (count === undefined) { + count = 0 + } + setattr(namespace, this.dest, count + 1) + } +}) + + +const _HelpAction = _callable(class _HelpAction extends Action { + + constructor() { + let [ + option_strings, + dest, + default_value, + help + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: SUPPRESS, + default: SUPPRESS, + help: undefined + }) + + super({ + option_strings, + dest, + default: default_value, + nargs: 0, + help + }) + } + + call(parser/*, namespace, values, option_string = undefined*/) { + parser.print_help() + parser.exit() + } +}) + + +const _VersionAction = _callable(class _VersionAction extends Action { + + constructor() { + let [ + option_strings, + version, + dest, + default_value, + help + ] = _parse_opts(arguments, { + option_strings: no_default, + version: undefined, + dest: SUPPRESS, + default: SUPPRESS, + help: "show program's version number and exit" + }) + + super({ + option_strings, + dest, + default: default_value, + nargs: 0, + help + }) + this.version = version + } + + call(parser/*, namespace, values, option_string = undefined*/) { + let version = this.version + if (version === undefined) { + version = parser.version + } + let formatter = parser._get_formatter() + formatter.add_text(version) + parser._print_message(formatter.format_help(), process.stdout) + parser.exit() + } +}) + + +const _SubParsersAction = _camelcase_alias(_callable(class _SubParsersAction extends Action { + + constructor() { + let [ + option_strings, + prog, + parser_class, + dest, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + prog: no_default, + parser_class: no_default, + dest: SUPPRESS, + required: false, + help: undefined, + metavar: undefined + }) + + let name_parser_map = {} + + super({ + option_strings, + dest, + nargs: PARSER, + choices: name_parser_map, + required, + help, + metavar + }) + + this._prog_prefix = prog + this._parser_class = parser_class + this._name_parser_map = name_parser_map + this._choices_actions = [] + } + + add_parser() { + let [ + name, + kwargs + ] = _parse_opts(arguments, { + name: no_default, + '**kwargs': no_default + }) + + // set prog from the existing prefix + if (kwargs.prog === undefined) { + kwargs.prog = sub('%s %s', this._prog_prefix, name) + } + + let aliases = getattr(kwargs, 'aliases', []) + delete kwargs.aliases + + // create a pseudo-action to hold the choice help + if ('help' in kwargs) { + let help = kwargs.help + delete kwargs.help + let choice_action = this._ChoicesPseudoAction(name, aliases, help) + this._choices_actions.push(choice_action) + } + + // create the parser and add it to the map + let parser = new this._parser_class(kwargs) + this._name_parser_map[name] = parser + + // make parser available under aliases also + for (let alias of aliases) { + this._name_parser_map[alias] = parser + } + + return parser + } + + _get_subactions() { + return this._choices_actions + } + + call(parser, namespace, values/*, option_string = undefined*/) { + let parser_name = values[0] + let arg_strings = values.slice(1) + + // set the parser name if requested + if (this.dest !== SUPPRESS) { + setattr(namespace, this.dest, parser_name) + } + + // select the parser + if (hasattr(this._name_parser_map, parser_name)) { + parser = this._name_parser_map[parser_name] + } else { + let args = {parser_name, + choices: this._name_parser_map.join(', ')} + let msg = sub('unknown parser %(parser_name)r (choices: %(choices)s)', args) + throw new ArgumentError(this, msg) + } + + // parse all the remaining options into the namespace + // store any unrecognized options on the object, so that the top + // level parser can decide what to do with them + + // In case this subparser defines new defaults, we parse them + // in a new namespace object and then update the original + // namespace for the relevant parts. + let subnamespace + [ subnamespace, arg_strings ] = parser.parse_known_args(arg_strings, undefined) + for (let [ key, value ] of Object.entries(subnamespace)) { + setattr(namespace, key, value) + } + + if (arg_strings.length) { + setdefault(namespace, _UNRECOGNIZED_ARGS_ATTR, []) + getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).push(...arg_strings) + } + } +})) + + +_SubParsersAction.prototype._ChoicesPseudoAction = _callable(class _ChoicesPseudoAction extends Action { + constructor(name, aliases, help) { + let metavar = name, dest = name + if (aliases.length) { + metavar += sub(' (%s)', aliases.join(', ')) + } + super({ option_strings: [], dest, help, metavar }) + } +}) + + +const _ExtendAction = _callable(class _ExtendAction extends _AppendAction { + call(parser, namespace, values/*, option_string = undefined*/) { + let items = getattr(namespace, this.dest, undefined) + items = _copy_items(items) + items = items.concat(values) + setattr(namespace, this.dest, items) + } +}) + + +// ============== +// Type classes +// ============== +const FileType = _callable(class FileType extends Function { + /* + * Factory for creating file object types + * + * Instances of FileType are typically passed as type= arguments to the + * ArgumentParser add_argument() method. + * + * Keyword Arguments: + * - mode -- A string indicating how the file is to be opened. Accepts the + * same values as the builtin open() function. + * - bufsize -- The file's desired buffer size. Accepts the same values as + * the builtin open() function. + * - encoding -- The file's encoding. Accepts the same values as the + * builtin open() function. + * - errors -- A string indicating how encoding and decoding errors are to + * be handled. Accepts the same value as the builtin open() function. + */ + + constructor() { + let [ + flags, + encoding, + mode, + autoClose, + emitClose, + start, + end, + highWaterMark, + fs + ] = _parse_opts(arguments, { + flags: 'r', + encoding: undefined, + mode: undefined, // 0o666 + autoClose: undefined, // true + emitClose: undefined, // false + start: undefined, // 0 + end: undefined, // Infinity + highWaterMark: undefined, // 64 * 1024 + fs: undefined + }) + + // when this class is called as a function, redirect it to .call() method of itself + super('return arguments.callee.call.apply(arguments.callee, arguments)') + + Object.defineProperty(this, 'name', { + get() { + return sub('FileType(%r)', flags) + } + }) + this._flags = flags + this._options = {} + if (encoding !== undefined) this._options.encoding = encoding + if (mode !== undefined) this._options.mode = mode + if (autoClose !== undefined) this._options.autoClose = autoClose + if (emitClose !== undefined) this._options.emitClose = emitClose + if (start !== undefined) this._options.start = start + if (end !== undefined) this._options.end = end + if (highWaterMark !== undefined) this._options.highWaterMark = highWaterMark + if (fs !== undefined) this._options.fs = fs + } + + call(string) { + // the special argument "-" means sys.std{in,out} + if (string === '-') { + if (this._flags.includes('r')) { + return process.stdin + } else if (this._flags.includes('w')) { + return process.stdout + } else { + let msg = sub('argument "-" with mode %r', this._flags) + throw new TypeError(msg) + } + } + + // all other arguments are used as file names + let fd + try { + fd = fs.openSync(string, this._flags, this._options.mode) + } catch (e) { + let args = { filename: string, error: e.message } + let message = "can't open '%(filename)s': %(error)s" + throw new ArgumentTypeError(sub(message, args)) + } + + let options = Object.assign({ fd, flags: this._flags }, this._options) + if (this._flags.includes('r')) { + return fs.createReadStream(undefined, options) + } else if (this._flags.includes('w')) { + return fs.createWriteStream(undefined, options) + } else { + let msg = sub('argument "%s" with mode %r', string, this._flags) + throw new TypeError(msg) + } + } + + [util.inspect.custom]() { + let args = [ this._flags ] + let kwargs = Object.entries(this._options).map(([ k, v ]) => { + if (k === 'mode') v = { value: v, [util.inspect.custom]() { return '0o' + this.value.toString(8) } } + return [ k, v ] + }) + let args_str = [] + .concat(args.filter(arg => arg !== -1).map(repr)) + .concat(kwargs.filter(([/*kw*/, arg]) => arg !== undefined) + .map(([kw, arg]) => sub('%s=%r', kw, arg))) + .join(', ') + return sub('%s(%s)', this.constructor.name, args_str) + } + + toString() { + return this[util.inspect.custom]() + } +}) + +// =========================== +// Optional and Positional Parsing +// =========================== +const Namespace = _callable(class Namespace extends _AttributeHolder() { + /* + * Simple object for storing attributes. + * + * Implements equality by attribute names and values, and provides a simple + * string representation. + */ + + constructor(options = {}) { + super() + Object.assign(this, options) + } +}) + +// unset string tag to mimic plain object +Namespace.prototype[Symbol.toStringTag] = undefined + + +const _ActionsContainer = _camelcase_alias(_callable(class _ActionsContainer { + + constructor() { + let [ + description, + prefix_chars, + argument_default, + conflict_handler + ] = _parse_opts(arguments, { + description: no_default, + prefix_chars: no_default, + argument_default: no_default, + conflict_handler: no_default + }) + + this.description = description + this.argument_default = argument_default + this.prefix_chars = prefix_chars + this.conflict_handler = conflict_handler + + // set up registries + this._registries = {} + + // register actions + this.register('action', undefined, _StoreAction) + this.register('action', 'store', _StoreAction) + this.register('action', 'store_const', _StoreConstAction) + this.register('action', 'store_true', _StoreTrueAction) + this.register('action', 'store_false', _StoreFalseAction) + this.register('action', 'append', _AppendAction) + this.register('action', 'append_const', _AppendConstAction) + this.register('action', 'count', _CountAction) + this.register('action', 'help', _HelpAction) + this.register('action', 'version', _VersionAction) + this.register('action', 'parsers', _SubParsersAction) + this.register('action', 'extend', _ExtendAction) + // LEGACY (v1 compatibility): camelcase variants + ;[ 'storeConst', 'storeTrue', 'storeFalse', 'appendConst' ].forEach(old_name => { + let new_name = _to_new_name(old_name) + this.register('action', old_name, util.deprecate(this._registry_get('action', new_name), + sub('{action: "%s"} is renamed to {action: "%s"}', old_name, new_name))) + }) + // end + + // raise an exception if the conflict handler is invalid + this._get_handler() + + // action storage + this._actions = [] + this._option_string_actions = {} + + // groups + this._action_groups = [] + this._mutually_exclusive_groups = [] + + // defaults storage + this._defaults = {} + + // determines whether an "option" looks like a negative number + this._negative_number_matcher = /^-\d+$|^-\d*\.\d+$/ + + // whether or not there are any optionals that look like negative + // numbers -- uses a list so it can be shared and edited + this._has_negative_number_optionals = [] + } + + // ==================== + // Registration methods + // ==================== + register(registry_name, value, object) { + let registry = setdefault(this._registries, registry_name, {}) + registry[value] = object + } + + _registry_get(registry_name, value, default_value = undefined) { + return getattr(this._registries[registry_name], value, default_value) + } + + // ================================== + // Namespace default accessor methods + // ================================== + set_defaults(kwargs) { + Object.assign(this._defaults, kwargs) + + // if these defaults match any existing arguments, replace + // the previous default on the object with the new one + for (let action of this._actions) { + if (action.dest in kwargs) { + action.default = kwargs[action.dest] + } + } + } + + get_default(dest) { + for (let action of this._actions) { + if (action.dest === dest && action.default !== undefined) { + return action.default + } + } + return this._defaults[dest] + } + + + // ======================= + // Adding argument actions + // ======================= + add_argument() { + /* + * add_argument(dest, ..., name=value, ...) + * add_argument(option_string, option_string, ..., name=value, ...) + */ + let [ + args, + kwargs + ] = _parse_opts(arguments, { + '*args': no_default, + '**kwargs': no_default + }) + // LEGACY (v1 compatibility), old-style add_argument([ args ], { options }) + if (args.length === 1 && Array.isArray(args[0])) { + args = args[0] + deprecate('argument-array', + sub('use add_argument(%(args)s, {...}) instead of add_argument([ %(args)s ], { ... })', { + args: args.map(repr).join(', ') + })) + } + // end + + // if no positional args are supplied or only one is supplied and + // it doesn't look like an option string, parse a positional + // argument + let chars = this.prefix_chars + if (!args.length || args.length === 1 && !chars.includes(args[0][0])) { + if (args.length && 'dest' in kwargs) { + throw new TypeError('dest supplied twice for positional argument') + } + kwargs = this._get_positional_kwargs(...args, kwargs) + + // otherwise, we're adding an optional argument + } else { + kwargs = this._get_optional_kwargs(...args, kwargs) + } + + // if no default was supplied, use the parser-level default + if (!('default' in kwargs)) { + let dest = kwargs.dest + if (dest in this._defaults) { + kwargs.default = this._defaults[dest] + } else if (this.argument_default !== undefined) { + kwargs.default = this.argument_default + } + } + + // create the action object, and add it to the parser + let action_class = this._pop_action_class(kwargs) + if (typeof action_class !== 'function') { + throw new TypeError(sub('unknown action "%s"', action_class)) + } + // eslint-disable-next-line new-cap + let action = new action_class(kwargs) + + // raise an error if the action type is not callable + let type_func = this._registry_get('type', action.type, action.type) + if (typeof type_func !== 'function') { + throw new TypeError(sub('%r is not callable', type_func)) + } + + if (type_func === FileType) { + throw new TypeError(sub('%r is a FileType class object, instance of it' + + ' must be passed', type_func)) + } + + // raise an error if the metavar does not match the type + if ('_get_formatter' in this) { + try { + this._get_formatter()._format_args(action, undefined) + } catch (err) { + // check for 'invalid nargs value' is an artifact of TypeError and ValueError in js being the same + if (err instanceof TypeError && err.message !== 'invalid nargs value') { + throw new TypeError('length of metavar tuple does not match nargs') + } else { + throw err + } + } + } + + return this._add_action(action) + } + + add_argument_group() { + let group = _ArgumentGroup(this, ...arguments) + this._action_groups.push(group) + return group + } + + add_mutually_exclusive_group() { + // eslint-disable-next-line no-use-before-define + let group = _MutuallyExclusiveGroup(this, ...arguments) + this._mutually_exclusive_groups.push(group) + return group + } + + _add_action(action) { + // resolve any conflicts + this._check_conflict(action) + + // add to actions list + this._actions.push(action) + action.container = this + + // index the action by any option strings it has + for (let option_string of action.option_strings) { + this._option_string_actions[option_string] = action + } + + // set the flag if any option strings look like negative numbers + for (let option_string of action.option_strings) { + if (this._negative_number_matcher.test(option_string)) { + if (!this._has_negative_number_optionals.length) { + this._has_negative_number_optionals.push(true) + } + } + } + + // return the created action + return action + } + + _remove_action(action) { + _array_remove(this._actions, action) + } + + _add_container_actions(container) { + // collect groups by titles + let title_group_map = {} + for (let group of this._action_groups) { + if (group.title in title_group_map) { + let msg = 'cannot merge actions - two groups are named %r' + throw new TypeError(sub(msg, group.title)) + } + title_group_map[group.title] = group + } + + // map each action to its group + let group_map = new Map() + for (let group of container._action_groups) { + + // if a group with the title exists, use that, otherwise + // create a new group matching the container's group + if (!(group.title in title_group_map)) { + title_group_map[group.title] = this.add_argument_group({ + title: group.title, + description: group.description, + conflict_handler: group.conflict_handler + }) + } + + // map the actions to their new group + for (let action of group._group_actions) { + group_map.set(action, title_group_map[group.title]) + } + } + + // add container's mutually exclusive groups + // NOTE: if add_mutually_exclusive_group ever gains title= and + // description= then this code will need to be expanded as above + for (let group of container._mutually_exclusive_groups) { + let mutex_group = this.add_mutually_exclusive_group({ + required: group.required + }) + + // map the actions to their new mutex group + for (let action of group._group_actions) { + group_map.set(action, mutex_group) + } + } + + // add all actions to this container or their group + for (let action of container._actions) { + group_map.get(action)._add_action(action) + } + } + + _get_positional_kwargs() { + let [ + dest, + kwargs + ] = _parse_opts(arguments, { + dest: no_default, + '**kwargs': no_default + }) + + // make sure required is not specified + if ('required' in kwargs) { + let msg = "'required' is an invalid argument for positionals" + throw new TypeError(msg) + } + + // mark positional arguments as required if at least one is + // always required + if (![OPTIONAL, ZERO_OR_MORE].includes(kwargs.nargs)) { + kwargs.required = true + } + if (kwargs.nargs === ZERO_OR_MORE && !('default' in kwargs)) { + kwargs.required = true + } + + // return the keyword arguments with no option strings + return Object.assign(kwargs, { dest, option_strings: [] }) + } + + _get_optional_kwargs() { + let [ + args, + kwargs + ] = _parse_opts(arguments, { + '*args': no_default, + '**kwargs': no_default + }) + + // determine short and long option strings + let option_strings = [] + let long_option_strings = [] + let option_string + for (option_string of args) { + // error on strings that don't start with an appropriate prefix + if (!this.prefix_chars.includes(option_string[0])) { + let args = {option: option_string, + prefix_chars: this.prefix_chars} + let msg = 'invalid option string %(option)r: ' + + 'must start with a character %(prefix_chars)r' + throw new TypeError(sub(msg, args)) + } + + // strings starting with two prefix characters are long options + option_strings.push(option_string) + if (option_string.length > 1 && this.prefix_chars.includes(option_string[1])) { + long_option_strings.push(option_string) + } + } + + // infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x' + let dest = kwargs.dest + delete kwargs.dest + if (dest === undefined) { + let dest_option_string + if (long_option_strings.length) { + dest_option_string = long_option_strings[0] + } else { + dest_option_string = option_strings[0] + } + dest = _string_lstrip(dest_option_string, this.prefix_chars) + if (!dest) { + let msg = 'dest= is required for options like %r' + throw new TypeError(sub(msg, option_string)) + } + dest = dest.replace(/-/g, '_') + } + + // return the updated keyword arguments + return Object.assign(kwargs, { dest, option_strings }) + } + + _pop_action_class(kwargs, default_value = undefined) { + let action = getattr(kwargs, 'action', default_value) + delete kwargs.action + return this._registry_get('action', action, action) + } + + _get_handler() { + // determine function from conflict handler string + let handler_func_name = sub('_handle_conflict_%s', this.conflict_handler) + if (typeof this[handler_func_name] === 'function') { + return this[handler_func_name] + } else { + let msg = 'invalid conflict_resolution value: %r' + throw new TypeError(sub(msg, this.conflict_handler)) + } + } + + _check_conflict(action) { + + // find all options that conflict with this option + let confl_optionals = [] + for (let option_string of action.option_strings) { + if (hasattr(this._option_string_actions, option_string)) { + let confl_optional = this._option_string_actions[option_string] + confl_optionals.push([ option_string, confl_optional ]) + } + } + + // resolve any conflicts + if (confl_optionals.length) { + let conflict_handler = this._get_handler() + conflict_handler.call(this, action, confl_optionals) + } + } + + _handle_conflict_error(action, conflicting_actions) { + let message = conflicting_actions.length === 1 ? + 'conflicting option string: %s' : + 'conflicting option strings: %s' + let conflict_string = conflicting_actions.map(([ option_string/*, action*/ ]) => option_string).join(', ') + throw new ArgumentError(action, sub(message, conflict_string)) + } + + _handle_conflict_resolve(action, conflicting_actions) { + + // remove all conflicting options + for (let [ option_string, action ] of conflicting_actions) { + + // remove the conflicting option + _array_remove(action.option_strings, option_string) + delete this._option_string_actions[option_string] + + // if the option now has no option string, remove it from the + // container holding it + if (!action.option_strings.length) { + action.container._remove_action(action) + } + } + } +})) + + +const _ArgumentGroup = _callable(class _ArgumentGroup extends _ActionsContainer { + + constructor() { + let [ + container, + title, + description, + kwargs + ] = _parse_opts(arguments, { + container: no_default, + title: undefined, + description: undefined, + '**kwargs': no_default + }) + + // add any missing keyword arguments by checking the container + setdefault(kwargs, 'conflict_handler', container.conflict_handler) + setdefault(kwargs, 'prefix_chars', container.prefix_chars) + setdefault(kwargs, 'argument_default', container.argument_default) + super(Object.assign({ description }, kwargs)) + + // group attributes + this.title = title + this._group_actions = [] + + // share most attributes with the container + this._registries = container._registries + this._actions = container._actions + this._option_string_actions = container._option_string_actions + this._defaults = container._defaults + this._has_negative_number_optionals = + container._has_negative_number_optionals + this._mutually_exclusive_groups = container._mutually_exclusive_groups + } + + _add_action(action) { + action = super._add_action(action) + this._group_actions.push(action) + return action + } + + _remove_action(action) { + super._remove_action(action) + _array_remove(this._group_actions, action) + } +}) + + +const _MutuallyExclusiveGroup = _callable(class _MutuallyExclusiveGroup extends _ArgumentGroup { + + constructor() { + let [ + container, + required + ] = _parse_opts(arguments, { + container: no_default, + required: false + }) + + super(container) + this.required = required + this._container = container + } + + _add_action(action) { + if (action.required) { + let msg = 'mutually exclusive arguments must be optional' + throw new TypeError(msg) + } + action = this._container._add_action(action) + this._group_actions.push(action) + return action + } + + _remove_action(action) { + this._container._remove_action(action) + _array_remove(this._group_actions, action) + } +}) + + +const ArgumentParser = _camelcase_alias(_callable(class ArgumentParser extends _AttributeHolder(_ActionsContainer) { + /* + * Object for parsing command line strings into Python objects. + * + * Keyword Arguments: + * - prog -- The name of the program (default: sys.argv[0]) + * - usage -- A usage message (default: auto-generated from arguments) + * - description -- A description of what the program does + * - epilog -- Text following the argument descriptions + * - parents -- Parsers whose arguments should be copied into this one + * - formatter_class -- HelpFormatter class for printing help messages + * - prefix_chars -- Characters that prefix optional arguments + * - fromfile_prefix_chars -- Characters that prefix files containing + * additional arguments + * - argument_default -- The default value for all arguments + * - conflict_handler -- String indicating how to handle conflicts + * - add_help -- Add a -h/-help option + * - allow_abbrev -- Allow long options to be abbreviated unambiguously + * - exit_on_error -- Determines whether or not ArgumentParser exits with + * error info when an error occurs + */ + + constructor() { + let [ + prog, + usage, + description, + epilog, + parents, + formatter_class, + prefix_chars, + fromfile_prefix_chars, + argument_default, + conflict_handler, + add_help, + allow_abbrev, + exit_on_error, + debug, // LEGACY (v1 compatibility), debug mode + version // LEGACY (v1 compatibility), version + ] = _parse_opts(arguments, { + prog: undefined, + usage: undefined, + description: undefined, + epilog: undefined, + parents: [], + formatter_class: HelpFormatter, + prefix_chars: '-', + fromfile_prefix_chars: undefined, + argument_default: undefined, + conflict_handler: 'error', + add_help: true, + allow_abbrev: true, + exit_on_error: true, + debug: undefined, // LEGACY (v1 compatibility), debug mode + version: undefined // LEGACY (v1 compatibility), version + }) + + // LEGACY (v1 compatibility) + if (debug !== undefined) { + deprecate('debug', + 'The "debug" argument to ArgumentParser is deprecated. Please ' + + 'override ArgumentParser.exit function instead.' + ) + } + + if (version !== undefined) { + deprecate('version', + 'The "version" argument to ArgumentParser is deprecated. Please use ' + + "add_argument(..., { action: 'version', version: 'N', ... }) instead." + ) + } + // end + + super({ + description, + prefix_chars, + argument_default, + conflict_handler + }) + + // default setting for prog + if (prog === undefined) { + prog = path.basename(get_argv()[0] || '') + } + + this.prog = prog + this.usage = usage + this.epilog = epilog + this.formatter_class = formatter_class + this.fromfile_prefix_chars = fromfile_prefix_chars + this.add_help = add_help + this.allow_abbrev = allow_abbrev + this.exit_on_error = exit_on_error + // LEGACY (v1 compatibility), debug mode + this.debug = debug + // end + + this._positionals = this.add_argument_group('positional arguments') + this._optionals = this.add_argument_group('optional arguments') + this._subparsers = undefined + + // register types + function identity(string) { + return string + } + this.register('type', undefined, identity) + this.register('type', null, identity) + this.register('type', 'auto', identity) + this.register('type', 'int', function (x) { + let result = Number(x) + if (!Number.isInteger(result)) { + throw new TypeError(sub('could not convert string to int: %r', x)) + } + return result + }) + this.register('type', 'float', function (x) { + let result = Number(x) + if (isNaN(result)) { + throw new TypeError(sub('could not convert string to float: %r', x)) + } + return result + }) + this.register('type', 'str', String) + // LEGACY (v1 compatibility): custom types + this.register('type', 'string', + util.deprecate(String, 'use {type:"str"} or {type:String} instead of {type:"string"}')) + // end + + // add help argument if necessary + // (using explicit default to override global argument_default) + let default_prefix = prefix_chars.includes('-') ? '-' : prefix_chars[0] + if (this.add_help) { + this.add_argument( + default_prefix + 'h', + default_prefix.repeat(2) + 'help', + { + action: 'help', + default: SUPPRESS, + help: 'show this help message and exit' + } + ) + } + // LEGACY (v1 compatibility), version + if (version) { + this.add_argument( + default_prefix + 'v', + default_prefix.repeat(2) + 'version', + { + action: 'version', + default: SUPPRESS, + version: this.version, + help: "show program's version number and exit" + } + ) + } + // end + + // add parent arguments and defaults + for (let parent of parents) { + this._add_container_actions(parent) + Object.assign(this._defaults, parent._defaults) + } + } + + // ======================= + // Pretty __repr__ methods + // ======================= + _get_kwargs() { + let names = [ + 'prog', + 'usage', + 'description', + 'formatter_class', + 'conflict_handler', + 'add_help' + ] + return names.map(name => [ name, getattr(this, name) ]) + } + + // ================================== + // Optional/Positional adding methods + // ================================== + add_subparsers() { + let [ + kwargs + ] = _parse_opts(arguments, { + '**kwargs': no_default + }) + + if (this._subparsers !== undefined) { + this.error('cannot have multiple subparser arguments') + } + + // add the parser class to the arguments if it's not present + setdefault(kwargs, 'parser_class', this.constructor) + + if ('title' in kwargs || 'description' in kwargs) { + let title = getattr(kwargs, 'title', 'subcommands') + let description = getattr(kwargs, 'description', undefined) + delete kwargs.title + delete kwargs.description + this._subparsers = this.add_argument_group(title, description) + } else { + this._subparsers = this._positionals + } + + // prog defaults to the usage message of this parser, skipping + // optional arguments and with no "usage:" prefix + if (kwargs.prog === undefined) { + let formatter = this._get_formatter() + let positionals = this._get_positional_actions() + let groups = this._mutually_exclusive_groups + formatter.add_usage(this.usage, positionals, groups, '') + kwargs.prog = formatter.format_help().trim() + } + + // create the parsers action and add it to the positionals list + let parsers_class = this._pop_action_class(kwargs, 'parsers') + // eslint-disable-next-line new-cap + let action = new parsers_class(Object.assign({ option_strings: [] }, kwargs)) + this._subparsers._add_action(action) + + // return the created parsers action + return action + } + + _add_action(action) { + if (action.option_strings.length) { + this._optionals._add_action(action) + } else { + this._positionals._add_action(action) + } + return action + } + + _get_optional_actions() { + return this._actions.filter(action => action.option_strings.length) + } + + _get_positional_actions() { + return this._actions.filter(action => !action.option_strings.length) + } + + // ===================================== + // Command line argument parsing methods + // ===================================== + parse_args(args = undefined, namespace = undefined) { + let argv + [ args, argv ] = this.parse_known_args(args, namespace) + if (argv && argv.length > 0) { + let msg = 'unrecognized arguments: %s' + this.error(sub(msg, argv.join(' '))) + } + return args + } + + parse_known_args(args = undefined, namespace = undefined) { + if (args === undefined) { + args = get_argv().slice(1) + } + + // default Namespace built from parser defaults + if (namespace === undefined) { + namespace = new Namespace() + } + + // add any action defaults that aren't present + for (let action of this._actions) { + if (action.dest !== SUPPRESS) { + if (!hasattr(namespace, action.dest)) { + if (action.default !== SUPPRESS) { + setattr(namespace, action.dest, action.default) + } + } + } + } + + // add any parser defaults that aren't present + for (let dest of Object.keys(this._defaults)) { + if (!hasattr(namespace, dest)) { + setattr(namespace, dest, this._defaults[dest]) + } + } + + // parse the arguments and exit if there are any errors + if (this.exit_on_error) { + try { + [ namespace, args ] = this._parse_known_args(args, namespace) + } catch (err) { + if (err instanceof ArgumentError) { + this.error(err.message) + } else { + throw err + } + } + } else { + [ namespace, args ] = this._parse_known_args(args, namespace) + } + + if (hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) { + args = args.concat(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) + delattr(namespace, _UNRECOGNIZED_ARGS_ATTR) + } + + return [ namespace, args ] + } + + _parse_known_args(arg_strings, namespace) { + // replace arg strings that are file references + if (this.fromfile_prefix_chars !== undefined) { + arg_strings = this._read_args_from_files(arg_strings) + } + + // map all mutually exclusive arguments to the other arguments + // they can't occur with + let action_conflicts = new Map() + for (let mutex_group of this._mutually_exclusive_groups) { + let group_actions = mutex_group._group_actions + for (let [ i, mutex_action ] of Object.entries(mutex_group._group_actions)) { + let conflicts = action_conflicts.get(mutex_action) || [] + conflicts = conflicts.concat(group_actions.slice(0, +i)) + conflicts = conflicts.concat(group_actions.slice(+i + 1)) + action_conflicts.set(mutex_action, conflicts) + } + } + + // find all option indices, and determine the arg_string_pattern + // which has an 'O' if there is an option at an index, + // an 'A' if there is an argument, or a '-' if there is a '--' + let option_string_indices = {} + let arg_string_pattern_parts = [] + let arg_strings_iter = Object.entries(arg_strings)[Symbol.iterator]() + for (let [ i, arg_string ] of arg_strings_iter) { + + // all args after -- are non-options + if (arg_string === '--') { + arg_string_pattern_parts.push('-') + for ([ i, arg_string ] of arg_strings_iter) { + arg_string_pattern_parts.push('A') + } + + // otherwise, add the arg to the arg strings + // and note the index if it was an option + } else { + let option_tuple = this._parse_optional(arg_string) + let pattern + if (option_tuple === undefined) { + pattern = 'A' + } else { + option_string_indices[i] = option_tuple + pattern = 'O' + } + arg_string_pattern_parts.push(pattern) + } + } + + // join the pieces together to form the pattern + let arg_strings_pattern = arg_string_pattern_parts.join('') + + // converts arg strings to the appropriate and then takes the action + let seen_actions = new Set() + let seen_non_default_actions = new Set() + let extras + + let take_action = (action, argument_strings, option_string = undefined) => { + seen_actions.add(action) + let argument_values = this._get_values(action, argument_strings) + + // error if this argument is not allowed with other previously + // seen arguments, assuming that actions that use the default + // value don't really count as "present" + if (argument_values !== action.default) { + seen_non_default_actions.add(action) + for (let conflict_action of action_conflicts.get(action) || []) { + if (seen_non_default_actions.has(conflict_action)) { + let msg = 'not allowed with argument %s' + let action_name = _get_action_name(conflict_action) + throw new ArgumentError(action, sub(msg, action_name)) + } + } + } + + // take the action if we didn't receive a SUPPRESS value + // (e.g. from a default) + if (argument_values !== SUPPRESS) { + action(this, namespace, argument_values, option_string) + } + } + + // function to convert arg_strings into an optional action + let consume_optional = start_index => { + + // get the optional identified at this index + let option_tuple = option_string_indices[start_index] + let [ action, option_string, explicit_arg ] = option_tuple + + // identify additional optionals in the same arg string + // (e.g. -xyz is the same as -x -y -z if no args are required) + let action_tuples = [] + let stop + for (;;) { + + // if we found no optional action, skip it + if (action === undefined) { + extras.push(arg_strings[start_index]) + return start_index + 1 + } + + // if there is an explicit argument, try to match the + // optional's string arguments to only this + if (explicit_arg !== undefined) { + let arg_count = this._match_argument(action, 'A') + + // if the action is a single-dash option and takes no + // arguments, try to parse more single-dash options out + // of the tail of the option string + let chars = this.prefix_chars + if (arg_count === 0 && !chars.includes(option_string[1])) { + action_tuples.push([ action, [], option_string ]) + let char = option_string[0] + option_string = char + explicit_arg[0] + let new_explicit_arg = explicit_arg.slice(1) || undefined + let optionals_map = this._option_string_actions + if (hasattr(optionals_map, option_string)) { + action = optionals_map[option_string] + explicit_arg = new_explicit_arg + } else { + let msg = 'ignored explicit argument %r' + throw new ArgumentError(action, sub(msg, explicit_arg)) + } + + // if the action expect exactly one argument, we've + // successfully matched the option; exit the loop + } else if (arg_count === 1) { + stop = start_index + 1 + let args = [ explicit_arg ] + action_tuples.push([ action, args, option_string ]) + break + + // error if a double-dash option did not use the + // explicit argument + } else { + let msg = 'ignored explicit argument %r' + throw new ArgumentError(action, sub(msg, explicit_arg)) + } + + // if there is no explicit argument, try to match the + // optional's string arguments with the following strings + // if successful, exit the loop + } else { + let start = start_index + 1 + let selected_patterns = arg_strings_pattern.slice(start) + let arg_count = this._match_argument(action, selected_patterns) + stop = start + arg_count + let args = arg_strings.slice(start, stop) + action_tuples.push([ action, args, option_string ]) + break + } + } + + // add the Optional to the list and return the index at which + // the Optional's string args stopped + assert(action_tuples.length) + for (let [ action, args, option_string ] of action_tuples) { + take_action(action, args, option_string) + } + return stop + } + + // the list of Positionals left to be parsed; this is modified + // by consume_positionals() + let positionals = this._get_positional_actions() + + // function to convert arg_strings into positional actions + let consume_positionals = start_index => { + // match as many Positionals as possible + let selected_pattern = arg_strings_pattern.slice(start_index) + let arg_counts = this._match_arguments_partial(positionals, selected_pattern) + + // slice off the appropriate arg strings for each Positional + // and add the Positional and its args to the list + for (let i = 0; i < positionals.length && i < arg_counts.length; i++) { + let action = positionals[i] + let arg_count = arg_counts[i] + let args = arg_strings.slice(start_index, start_index + arg_count) + start_index += arg_count + take_action(action, args) + } + + // slice off the Positionals that we just parsed and return the + // index at which the Positionals' string args stopped + positionals = positionals.slice(arg_counts.length) + return start_index + } + + // consume Positionals and Optionals alternately, until we have + // passed the last option string + extras = [] + let start_index = 0 + let max_option_string_index = Math.max(-1, ...Object.keys(option_string_indices).map(Number)) + while (start_index <= max_option_string_index) { + + // consume any Positionals preceding the next option + let next_option_string_index = Math.min( + // eslint-disable-next-line no-loop-func + ...Object.keys(option_string_indices).map(Number).filter(index => index >= start_index) + ) + if (start_index !== next_option_string_index) { + let positionals_end_index = consume_positionals(start_index) + + // only try to parse the next optional if we didn't consume + // the option string during the positionals parsing + if (positionals_end_index > start_index) { + start_index = positionals_end_index + continue + } else { + start_index = positionals_end_index + } + } + + // if we consumed all the positionals we could and we're not + // at the index of an option string, there were extra arguments + if (!(start_index in option_string_indices)) { + let strings = arg_strings.slice(start_index, next_option_string_index) + extras = extras.concat(strings) + start_index = next_option_string_index + } + + // consume the next optional and any arguments for it + start_index = consume_optional(start_index) + } + + // consume any positionals following the last Optional + let stop_index = consume_positionals(start_index) + + // if we didn't consume all the argument strings, there were extras + extras = extras.concat(arg_strings.slice(stop_index)) + + // make sure all required actions were present and also convert + // action defaults which were not given as arguments + let required_actions = [] + for (let action of this._actions) { + if (!seen_actions.has(action)) { + if (action.required) { + required_actions.push(_get_action_name(action)) + } else { + // Convert action default now instead of doing it before + // parsing arguments to avoid calling convert functions + // twice (which may fail) if the argument was given, but + // only if it was defined already in the namespace + if (action.default !== undefined && + typeof action.default === 'string' && + hasattr(namespace, action.dest) && + action.default === getattr(namespace, action.dest)) { + setattr(namespace, action.dest, + this._get_value(action, action.default)) + } + } + } + } + + if (required_actions.length) { + this.error(sub('the following arguments are required: %s', + required_actions.join(', '))) + } + + // make sure all required groups had one option present + for (let group of this._mutually_exclusive_groups) { + if (group.required) { + let no_actions_used = true + for (let action of group._group_actions) { + if (seen_non_default_actions.has(action)) { + no_actions_used = false + break + } + } + + // if no actions were used, report the error + if (no_actions_used) { + let names = group._group_actions + .filter(action => action.help !== SUPPRESS) + .map(action => _get_action_name(action)) + let msg = 'one of the arguments %s is required' + this.error(sub(msg, names.join(' '))) + } + } + } + + // return the updated namespace and the extra arguments + return [ namespace, extras ] + } + + _read_args_from_files(arg_strings) { + // expand arguments referencing files + let new_arg_strings = [] + for (let arg_string of arg_strings) { + + // for regular arguments, just add them back into the list + if (!arg_string || !this.fromfile_prefix_chars.includes(arg_string[0])) { + new_arg_strings.push(arg_string) + + // replace arguments referencing files with the file content + } else { + try { + let args_file = fs.readFileSync(arg_string.slice(1), 'utf8') + let arg_strings = [] + for (let arg_line of splitlines(args_file)) { + for (let arg of this.convert_arg_line_to_args(arg_line)) { + arg_strings.push(arg) + } + } + arg_strings = this._read_args_from_files(arg_strings) + new_arg_strings = new_arg_strings.concat(arg_strings) + } catch (err) { + this.error(err.message) + } + } + } + + // return the modified argument list + return new_arg_strings + } + + convert_arg_line_to_args(arg_line) { + return [arg_line] + } + + _match_argument(action, arg_strings_pattern) { + // match the pattern for this action to the arg strings + let nargs_pattern = this._get_nargs_pattern(action) + let match = arg_strings_pattern.match(new RegExp('^' + nargs_pattern)) + + // raise an exception if we weren't able to find a match + if (match === null) { + let nargs_errors = { + undefined: 'expected one argument', + [OPTIONAL]: 'expected at most one argument', + [ONE_OR_MORE]: 'expected at least one argument' + } + let msg = nargs_errors[action.nargs] + if (msg === undefined) { + msg = sub(action.nargs === 1 ? 'expected %s argument' : 'expected %s arguments', action.nargs) + } + throw new ArgumentError(action, msg) + } + + // return the number of arguments matched + return match[1].length + } + + _match_arguments_partial(actions, arg_strings_pattern) { + // progressively shorten the actions list by slicing off the + // final actions until we find a match + let result = [] + for (let i of range(actions.length, 0, -1)) { + let actions_slice = actions.slice(0, i) + let pattern = actions_slice.map(action => this._get_nargs_pattern(action)).join('') + let match = arg_strings_pattern.match(new RegExp('^' + pattern)) + if (match !== null) { + result = result.concat(match.slice(1).map(string => string.length)) + break + } + } + + // return the list of arg string counts + return result + } + + _parse_optional(arg_string) { + // if it's an empty string, it was meant to be a positional + if (!arg_string) { + return undefined + } + + // if it doesn't start with a prefix, it was meant to be positional + if (!this.prefix_chars.includes(arg_string[0])) { + return undefined + } + + // if the option string is present in the parser, return the action + if (arg_string in this._option_string_actions) { + let action = this._option_string_actions[arg_string] + return [ action, arg_string, undefined ] + } + + // if it's just a single character, it was meant to be positional + if (arg_string.length === 1) { + return undefined + } + + // if the option string before the "=" is present, return the action + if (arg_string.includes('=')) { + let [ option_string, explicit_arg ] = _string_split(arg_string, '=', 1) + if (option_string in this._option_string_actions) { + let action = this._option_string_actions[option_string] + return [ action, option_string, explicit_arg ] + } + } + + // search through all possible prefixes of the option string + // and all actions in the parser for possible interpretations + let option_tuples = this._get_option_tuples(arg_string) + + // if multiple actions match, the option string was ambiguous + if (option_tuples.length > 1) { + let options = option_tuples.map(([ /*action*/, option_string/*, explicit_arg*/ ]) => option_string).join(', ') + let args = {option: arg_string, matches: options} + let msg = 'ambiguous option: %(option)s could match %(matches)s' + this.error(sub(msg, args)) + + // if exactly one action matched, this segmentation is good, + // so return the parsed action + } else if (option_tuples.length === 1) { + let [ option_tuple ] = option_tuples + return option_tuple + } + + // if it was not found as an option, but it looks like a negative + // number, it was meant to be positional + // unless there are negative-number-like options + if (this._negative_number_matcher.test(arg_string)) { + if (!this._has_negative_number_optionals.length) { + return undefined + } + } + + // if it contains a space, it was meant to be a positional + if (arg_string.includes(' ')) { + return undefined + } + + // it was meant to be an optional but there is no such option + // in this parser (though it might be a valid option in a subparser) + return [ undefined, arg_string, undefined ] + } + + _get_option_tuples(option_string) { + let result = [] + + // option strings starting with two prefix characters are only + // split at the '=' + let chars = this.prefix_chars + if (chars.includes(option_string[0]) && chars.includes(option_string[1])) { + if (this.allow_abbrev) { + let option_prefix, explicit_arg + if (option_string.includes('=')) { + [ option_prefix, explicit_arg ] = _string_split(option_string, '=', 1) + } else { + option_prefix = option_string + explicit_arg = undefined + } + for (let option_string of Object.keys(this._option_string_actions)) { + if (option_string.startsWith(option_prefix)) { + let action = this._option_string_actions[option_string] + let tup = [ action, option_string, explicit_arg ] + result.push(tup) + } + } + } + + // single character options can be concatenated with their arguments + // but multiple character options always have to have their argument + // separate + } else if (chars.includes(option_string[0]) && !chars.includes(option_string[1])) { + let option_prefix = option_string + let explicit_arg = undefined + let short_option_prefix = option_string.slice(0, 2) + let short_explicit_arg = option_string.slice(2) + + for (let option_string of Object.keys(this._option_string_actions)) { + if (option_string === short_option_prefix) { + let action = this._option_string_actions[option_string] + let tup = [ action, option_string, short_explicit_arg ] + result.push(tup) + } else if (option_string.startsWith(option_prefix)) { + let action = this._option_string_actions[option_string] + let tup = [ action, option_string, explicit_arg ] + result.push(tup) + } + } + + // shouldn't ever get here + } else { + this.error(sub('unexpected option string: %s', option_string)) + } + + // return the collected option tuples + return result + } + + _get_nargs_pattern(action) { + // in all examples below, we have to allow for '--' args + // which are represented as '-' in the pattern + let nargs = action.nargs + let nargs_pattern + + // the default (None) is assumed to be a single argument + if (nargs === undefined) { + nargs_pattern = '(-*A-*)' + + // allow zero or one arguments + } else if (nargs === OPTIONAL) { + nargs_pattern = '(-*A?-*)' + + // allow zero or more arguments + } else if (nargs === ZERO_OR_MORE) { + nargs_pattern = '(-*[A-]*)' + + // allow one or more arguments + } else if (nargs === ONE_OR_MORE) { + nargs_pattern = '(-*A[A-]*)' + + // allow any number of options or arguments + } else if (nargs === REMAINDER) { + nargs_pattern = '([-AO]*)' + + // allow one argument followed by any number of options or arguments + } else if (nargs === PARSER) { + nargs_pattern = '(-*A[-AO]*)' + + // suppress action, like nargs=0 + } else if (nargs === SUPPRESS) { + nargs_pattern = '(-*-*)' + + // all others should be integers + } else { + nargs_pattern = sub('(-*%s-*)', 'A'.repeat(nargs).split('').join('-*')) + } + + // if this is an optional action, -- is not allowed + if (action.option_strings.length) { + nargs_pattern = nargs_pattern.replace(/-\*/g, '') + nargs_pattern = nargs_pattern.replace(/-/g, '') + } + + // return the pattern + return nargs_pattern + } + + // ======================== + // Alt command line argument parsing, allowing free intermix + // ======================== + + parse_intermixed_args(args = undefined, namespace = undefined) { + let argv + [ args, argv ] = this.parse_known_intermixed_args(args, namespace) + if (argv.length) { + let msg = 'unrecognized arguments: %s' + this.error(sub(msg, argv.join(' '))) + } + return args + } + + parse_known_intermixed_args(args = undefined, namespace = undefined) { + // returns a namespace and list of extras + // + // positional can be freely intermixed with optionals. optionals are + // first parsed with all positional arguments deactivated. The 'extras' + // are then parsed. If the parser definition is incompatible with the + // intermixed assumptions (e.g. use of REMAINDER, subparsers) a + // TypeError is raised. + // + // positionals are 'deactivated' by setting nargs and default to + // SUPPRESS. This blocks the addition of that positional to the + // namespace + + let extras + let positionals = this._get_positional_actions() + let a = positionals.filter(action => [ PARSER, REMAINDER ].includes(action.nargs)) + if (a.length) { + throw new TypeError(sub('parse_intermixed_args: positional arg' + + ' with nargs=%s', a[0].nargs)) + } + + for (let group of this._mutually_exclusive_groups) { + for (let action of group._group_actions) { + if (positionals.includes(action)) { + throw new TypeError('parse_intermixed_args: positional in' + + ' mutuallyExclusiveGroup') + } + } + } + + let save_usage + try { + save_usage = this.usage + let remaining_args + try { + if (this.usage === undefined) { + // capture the full usage for use in error messages + this.usage = this.format_usage().slice(7) + } + for (let action of positionals) { + // deactivate positionals + action.save_nargs = action.nargs + // action.nargs = 0 + action.nargs = SUPPRESS + action.save_default = action.default + action.default = SUPPRESS + } + [ namespace, remaining_args ] = this.parse_known_args(args, + namespace) + for (let action of positionals) { + // remove the empty positional values from namespace + let attr = getattr(namespace, action.dest) + if (Array.isArray(attr) && attr.length === 0) { + // eslint-disable-next-line no-console + console.warn(sub('Do not expect %s in %s', action.dest, namespace)) + delattr(namespace, action.dest) + } + } + } finally { + // restore nargs and usage before exiting + for (let action of positionals) { + action.nargs = action.save_nargs + action.default = action.save_default + } + } + let optionals = this._get_optional_actions() + try { + // parse positionals. optionals aren't normally required, but + // they could be, so make sure they aren't. + for (let action of optionals) { + action.save_required = action.required + action.required = false + } + for (let group of this._mutually_exclusive_groups) { + group.save_required = group.required + group.required = false + } + [ namespace, extras ] = this.parse_known_args(remaining_args, + namespace) + } finally { + // restore parser values before exiting + for (let action of optionals) { + action.required = action.save_required + } + for (let group of this._mutually_exclusive_groups) { + group.required = group.save_required + } + } + } finally { + this.usage = save_usage + } + return [ namespace, extras ] + } + + // ======================== + // Value conversion methods + // ======================== + _get_values(action, arg_strings) { + // for everything but PARSER, REMAINDER args, strip out first '--' + if (![PARSER, REMAINDER].includes(action.nargs)) { + try { + _array_remove(arg_strings, '--') + } catch (err) {} + } + + let value + // optional argument produces a default when not present + if (!arg_strings.length && action.nargs === OPTIONAL) { + if (action.option_strings.length) { + value = action.const + } else { + value = action.default + } + if (typeof value === 'string') { + value = this._get_value(action, value) + this._check_value(action, value) + } + + // when nargs='*' on a positional, if there were no command-line + // args, use the default if it is anything other than None + } else if (!arg_strings.length && action.nargs === ZERO_OR_MORE && + !action.option_strings.length) { + if (action.default !== undefined) { + value = action.default + } else { + value = arg_strings + } + this._check_value(action, value) + + // single argument or optional argument produces a single value + } else if (arg_strings.length === 1 && [undefined, OPTIONAL].includes(action.nargs)) { + let arg_string = arg_strings[0] + value = this._get_value(action, arg_string) + this._check_value(action, value) + + // REMAINDER arguments convert all values, checking none + } else if (action.nargs === REMAINDER) { + value = arg_strings.map(v => this._get_value(action, v)) + + // PARSER arguments convert all values, but check only the first + } else if (action.nargs === PARSER) { + value = arg_strings.map(v => this._get_value(action, v)) + this._check_value(action, value[0]) + + // SUPPRESS argument does not put anything in the namespace + } else if (action.nargs === SUPPRESS) { + value = SUPPRESS + + // all other types of nargs produce a list + } else { + value = arg_strings.map(v => this._get_value(action, v)) + for (let v of value) { + this._check_value(action, v) + } + } + + // return the converted value + return value + } + + _get_value(action, arg_string) { + let type_func = this._registry_get('type', action.type, action.type) + if (typeof type_func !== 'function') { + let msg = '%r is not callable' + throw new ArgumentError(action, sub(msg, type_func)) + } + + // convert the value to the appropriate type + let result + try { + try { + result = type_func(arg_string) + } catch (err) { + // Dear TC39, why would you ever consider making es6 classes not callable? + // We had one universal interface, [[Call]], which worked for anything + // (with familiar this-instanceof guard for classes). Now we have two. + if (err instanceof TypeError && + /Class constructor .* cannot be invoked without 'new'/.test(err.message)) { + // eslint-disable-next-line new-cap + result = new type_func(arg_string) + } else { + throw err + } + } + + } catch (err) { + // ArgumentTypeErrors indicate errors + if (err instanceof ArgumentTypeError) { + //let name = getattr(action.type, 'name', repr(action.type)) + let msg = err.message + throw new ArgumentError(action, msg) + + // TypeErrors or ValueErrors also indicate errors + } else if (err instanceof TypeError) { + let name = getattr(action.type, 'name', repr(action.type)) + let args = {type: name, value: arg_string} + let msg = 'invalid %(type)s value: %(value)r' + throw new ArgumentError(action, sub(msg, args)) + } else { + throw err + } + } + + // return the converted value + return result + } + + _check_value(action, value) { + // converted value must be one of the choices (if specified) + if (action.choices !== undefined && !_choices_to_array(action.choices).includes(value)) { + let args = {value, + choices: _choices_to_array(action.choices).map(repr).join(', ')} + let msg = 'invalid choice: %(value)r (choose from %(choices)s)' + throw new ArgumentError(action, sub(msg, args)) + } + } + + // ======================= + // Help-formatting methods + // ======================= + format_usage() { + let formatter = this._get_formatter() + formatter.add_usage(this.usage, this._actions, + this._mutually_exclusive_groups) + return formatter.format_help() + } + + format_help() { + let formatter = this._get_formatter() + + // usage + formatter.add_usage(this.usage, this._actions, + this._mutually_exclusive_groups) + + // description + formatter.add_text(this.description) + + // positionals, optionals and user-defined groups + for (let action_group of this._action_groups) { + formatter.start_section(action_group.title) + formatter.add_text(action_group.description) + formatter.add_arguments(action_group._group_actions) + formatter.end_section() + } + + // epilog + formatter.add_text(this.epilog) + + // determine help from format above + return formatter.format_help() + } + + _get_formatter() { + // eslint-disable-next-line new-cap + return new this.formatter_class({ prog: this.prog }) + } + + // ===================== + // Help-printing methods + // ===================== + print_usage(file = undefined) { + if (file === undefined) file = process.stdout + this._print_message(this.format_usage(), file) + } + + print_help(file = undefined) { + if (file === undefined) file = process.stdout + this._print_message(this.format_help(), file) + } + + _print_message(message, file = undefined) { + if (message) { + if (file === undefined) file = process.stderr + file.write(message) + } + } + + // =============== + // Exiting methods + // =============== + exit(status = 0, message = undefined) { + if (message) { + this._print_message(message, process.stderr) + } + process.exit(status) + } + + error(message) { + /* + * error(message: string) + * + * Prints a usage message incorporating the message to stderr and + * exits. + * + * If you override this in a subclass, it should not return -- it + * should either exit or raise an exception. + */ + + // LEGACY (v1 compatibility), debug mode + if (this.debug === true) throw new Error(message) + // end + this.print_usage(process.stderr) + let args = {prog: this.prog, message: message} + this.exit(2, sub('%(prog)s: error: %(message)s\n', args)) + } +})) + + +module.exports = { + ArgumentParser, + ArgumentError, + ArgumentTypeError, + BooleanOptionalAction, + FileType, + HelpFormatter, + ArgumentDefaultsHelpFormatter, + RawDescriptionHelpFormatter, + RawTextHelpFormatter, + MetavarTypeHelpFormatter, + Namespace, + Action, + ONE_OR_MORE, + OPTIONAL, + PARSER, + REMAINDER, + SUPPRESS, + ZERO_OR_MORE +} + +// LEGACY (v1 compatibility), Const alias +Object.defineProperty(module.exports, 'Const', { + get() { + let result = {} + Object.entries({ ONE_OR_MORE, OPTIONAL, PARSER, REMAINDER, SUPPRESS, ZERO_OR_MORE }).forEach(([ n, v ]) => { + Object.defineProperty(result, n, { + get() { + deprecate(n, sub('use argparse.%s instead of argparse.Const.%s', n, n)) + return v + } + }) + }) + Object.entries({ _UNRECOGNIZED_ARGS_ATTR }).forEach(([ n, v ]) => { + Object.defineProperty(result, n, { + get() { + deprecate(n, sub('argparse.Const.%s is an internal symbol and will no longer be available', n)) + return v + } + }) + }) + return result + }, + enumerable: false +}) +// end diff --git a/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/lib/sub.js b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/lib/sub.js new file mode 100644 index 0000000..e3eb321 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/lib/sub.js @@ -0,0 +1,67 @@ +// Limited implementation of python % string operator, supports only %s and %r for now +// (other formats are not used here, but may appear in custom templates) + +'use strict' + +const { inspect } = require('util') + + +module.exports = function sub(pattern, ...values) { + let regex = /%(?:(%)|(-)?(\*)?(?:\((\w+)\))?([A-Za-z]))/g + + let result = pattern.replace(regex, function (_, is_literal, is_left_align, is_padded, name, format) { + if (is_literal) return '%' + + let padded_count = 0 + if (is_padded) { + if (values.length === 0) throw new TypeError('not enough arguments for format string') + padded_count = values.shift() + if (!Number.isInteger(padded_count)) throw new TypeError('* wants int') + } + + let str + if (name !== undefined) { + let dict = values[0] + if (typeof dict !== 'object' || dict === null) throw new TypeError('format requires a mapping') + if (!(name in dict)) throw new TypeError(`no such key: '${name}'`) + str = dict[name] + } else { + if (values.length === 0) throw new TypeError('not enough arguments for format string') + str = values.shift() + } + + switch (format) { + case 's': + str = String(str) + break + case 'r': + str = inspect(str) + break + case 'd': + case 'i': + if (typeof str !== 'number') { + throw new TypeError(`%${format} format: a number is required, not ${typeof str}`) + } + str = String(str.toFixed(0)) + break + default: + throw new TypeError(`unsupported format character '${format}'`) + } + + if (padded_count > 0) { + return is_left_align ? str.padEnd(padded_count) : str.padStart(padded_count) + } else { + return str + } + }) + + if (values.length) { + if (values.length === 1 && typeof values[0] === 'object' && values[0] !== null) { + // mapping + } else { + throw new TypeError('not all arguments converted during string formatting') + } + } + + return result +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/lib/textwrap.js b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/lib/textwrap.js new file mode 100644 index 0000000..23d51cd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/lib/textwrap.js @@ -0,0 +1,440 @@ +// Partial port of python's argparse module, version 3.9.0 (only wrap and fill functions): +// https://github.com/python/cpython/blob/v3.9.0b4/Lib/textwrap.py + +'use strict' + +/* + * Text wrapping and filling. + */ + +// Copyright (C) 1999-2001 Gregory P. Ward. +// Copyright (C) 2002, 2003 Python Software Foundation. +// Copyright (C) 2020 argparse.js authors +// Originally written by Greg Ward + +// Hardcode the recognized whitespace characters to the US-ASCII +// whitespace characters. The main reason for doing this is that +// some Unicode spaces (like \u00a0) are non-breaking whitespaces. +// +// This less funky little regex just split on recognized spaces. E.g. +// "Hello there -- you goof-ball, use the -b option!" +// splits into +// Hello/ /there/ /--/ /you/ /goof-ball,/ /use/ /the/ /-b/ /option!/ +const wordsep_simple_re = /([\t\n\x0b\x0c\r ]+)/ + +class TextWrapper { + /* + * Object for wrapping/filling text. The public interface consists of + * the wrap() and fill() methods; the other methods are just there for + * subclasses to override in order to tweak the default behaviour. + * If you want to completely replace the main wrapping algorithm, + * you'll probably have to override _wrap_chunks(). + * + * Several instance attributes control various aspects of wrapping: + * width (default: 70) + * the maximum width of wrapped lines (unless break_long_words + * is false) + * initial_indent (default: "") + * string that will be prepended to the first line of wrapped + * output. Counts towards the line's width. + * subsequent_indent (default: "") + * string that will be prepended to all lines save the first + * of wrapped output; also counts towards each line's width. + * expand_tabs (default: true) + * Expand tabs in input text to spaces before further processing. + * Each tab will become 0 .. 'tabsize' spaces, depending on its position + * in its line. If false, each tab is treated as a single character. + * tabsize (default: 8) + * Expand tabs in input text to 0 .. 'tabsize' spaces, unless + * 'expand_tabs' is false. + * replace_whitespace (default: true) + * Replace all whitespace characters in the input text by spaces + * after tab expansion. Note that if expand_tabs is false and + * replace_whitespace is true, every tab will be converted to a + * single space! + * fix_sentence_endings (default: false) + * Ensure that sentence-ending punctuation is always followed + * by two spaces. Off by default because the algorithm is + * (unavoidably) imperfect. + * break_long_words (default: true) + * Break words longer than 'width'. If false, those words will not + * be broken, and some lines might be longer than 'width'. + * break_on_hyphens (default: true) + * Allow breaking hyphenated words. If true, wrapping will occur + * preferably on whitespaces and right after hyphens part of + * compound words. + * drop_whitespace (default: true) + * Drop leading and trailing whitespace from lines. + * max_lines (default: None) + * Truncate wrapped lines. + * placeholder (default: ' [...]') + * Append to the last line of truncated text. + */ + + constructor(options = {}) { + let { + width = 70, + initial_indent = '', + subsequent_indent = '', + expand_tabs = true, + replace_whitespace = true, + fix_sentence_endings = false, + break_long_words = true, + drop_whitespace = true, + break_on_hyphens = true, + tabsize = 8, + max_lines = undefined, + placeholder=' [...]' + } = options + + this.width = width + this.initial_indent = initial_indent + this.subsequent_indent = subsequent_indent + this.expand_tabs = expand_tabs + this.replace_whitespace = replace_whitespace + this.fix_sentence_endings = fix_sentence_endings + this.break_long_words = break_long_words + this.drop_whitespace = drop_whitespace + this.break_on_hyphens = break_on_hyphens + this.tabsize = tabsize + this.max_lines = max_lines + this.placeholder = placeholder + } + + + // -- Private methods ----------------------------------------------- + // (possibly useful for subclasses to override) + + _munge_whitespace(text) { + /* + * _munge_whitespace(text : string) -> string + * + * Munge whitespace in text: expand tabs and convert all other + * whitespace characters to spaces. Eg. " foo\\tbar\\n\\nbaz" + * becomes " foo bar baz". + */ + if (this.expand_tabs) { + text = text.replace(/\t/g, ' '.repeat(this.tabsize)) // not strictly correct in js + } + if (this.replace_whitespace) { + text = text.replace(/[\t\n\x0b\x0c\r]/g, ' ') + } + return text + } + + _split(text) { + /* + * _split(text : string) -> [string] + * + * Split the text to wrap into indivisible chunks. Chunks are + * not quite the same as words; see _wrap_chunks() for full + * details. As an example, the text + * Look, goof-ball -- use the -b option! + * breaks into the following chunks: + * 'Look,', ' ', 'goof-', 'ball', ' ', '--', ' ', + * 'use', ' ', 'the', ' ', '-b', ' ', 'option!' + * if break_on_hyphens is True, or in: + * 'Look,', ' ', 'goof-ball', ' ', '--', ' ', + * 'use', ' ', 'the', ' ', '-b', ' ', option!' + * otherwise. + */ + let chunks = text.split(wordsep_simple_re) + chunks = chunks.filter(Boolean) + return chunks + } + + _handle_long_word(reversed_chunks, cur_line, cur_len, width) { + /* + * _handle_long_word(chunks : [string], + * cur_line : [string], + * cur_len : int, width : int) + * + * Handle a chunk of text (most likely a word, not whitespace) that + * is too long to fit in any line. + */ + // Figure out when indent is larger than the specified width, and make + // sure at least one character is stripped off on every pass + let space_left + if (width < 1) { + space_left = 1 + } else { + space_left = width - cur_len + } + + // If we're allowed to break long words, then do so: put as much + // of the next chunk onto the current line as will fit. + if (this.break_long_words) { + cur_line.push(reversed_chunks[reversed_chunks.length - 1].slice(0, space_left)) + reversed_chunks[reversed_chunks.length - 1] = reversed_chunks[reversed_chunks.length - 1].slice(space_left) + + // Otherwise, we have to preserve the long word intact. Only add + // it to the current line if there's nothing already there -- + // that minimizes how much we violate the width constraint. + } else if (!cur_line) { + cur_line.push(...reversed_chunks.pop()) + } + + // If we're not allowed to break long words, and there's already + // text on the current line, do nothing. Next time through the + // main loop of _wrap_chunks(), we'll wind up here again, but + // cur_len will be zero, so the next line will be entirely + // devoted to the long word that we can't handle right now. + } + + _wrap_chunks(chunks) { + /* + * _wrap_chunks(chunks : [string]) -> [string] + * + * Wrap a sequence of text chunks and return a list of lines of + * length 'self.width' or less. (If 'break_long_words' is false, + * some lines may be longer than this.) Chunks correspond roughly + * to words and the whitespace between them: each chunk is + * indivisible (modulo 'break_long_words'), but a line break can + * come between any two chunks. Chunks should not have internal + * whitespace; ie. a chunk is either all whitespace or a "word". + * Whitespace chunks will be removed from the beginning and end of + * lines, but apart from that whitespace is preserved. + */ + let lines = [] + let indent + if (this.width <= 0) { + throw Error(`invalid width ${this.width} (must be > 0)`) + } + if (this.max_lines !== undefined) { + if (this.max_lines > 1) { + indent = this.subsequent_indent + } else { + indent = this.initial_indent + } + if (indent.length + this.placeholder.trimStart().length > this.width) { + throw Error('placeholder too large for max width') + } + } + + // Arrange in reverse order so items can be efficiently popped + // from a stack of chucks. + chunks = chunks.reverse() + + while (chunks.length > 0) { + + // Start the list of chunks that will make up the current line. + // cur_len is just the length of all the chunks in cur_line. + let cur_line = [] + let cur_len = 0 + + // Figure out which static string will prefix this line. + let indent + if (lines) { + indent = this.subsequent_indent + } else { + indent = this.initial_indent + } + + // Maximum width for this line. + let width = this.width - indent.length + + // First chunk on line is whitespace -- drop it, unless this + // is the very beginning of the text (ie. no lines started yet). + if (this.drop_whitespace && chunks[chunks.length - 1].trim() === '' && lines.length > 0) { + chunks.pop() + } + + while (chunks.length > 0) { + let l = chunks[chunks.length - 1].length + + // Can at least squeeze this chunk onto the current line. + if (cur_len + l <= width) { + cur_line.push(chunks.pop()) + cur_len += l + + // Nope, this line is full. + } else { + break + } + } + + // The current line is full, and the next chunk is too big to + // fit on *any* line (not just this one). + if (chunks.length && chunks[chunks.length - 1].length > width) { + this._handle_long_word(chunks, cur_line, cur_len, width) + cur_len = cur_line.map(l => l.length).reduce((a, b) => a + b, 0) + } + + // If the last chunk on this line is all whitespace, drop it. + if (this.drop_whitespace && cur_line.length > 0 && cur_line[cur_line.length - 1].trim() === '') { + cur_len -= cur_line[cur_line.length - 1].length + cur_line.pop() + } + + if (cur_line) { + if (this.max_lines === undefined || + lines.length + 1 < this.max_lines || + (chunks.length === 0 || + this.drop_whitespace && + chunks.length === 1 && + !chunks[0].trim()) && cur_len <= width) { + // Convert current line back to a string and store it in + // list of all lines (return value). + lines.push(indent + cur_line.join('')) + } else { + let had_break = false + while (cur_line) { + if (cur_line[cur_line.length - 1].trim() && + cur_len + this.placeholder.length <= width) { + cur_line.push(this.placeholder) + lines.push(indent + cur_line.join('')) + had_break = true + break + } + cur_len -= cur_line[-1].length + cur_line.pop() + } + if (!had_break) { + if (lines) { + let prev_line = lines[lines.length - 1].trimEnd() + if (prev_line.length + this.placeholder.length <= + this.width) { + lines[lines.length - 1] = prev_line + this.placeholder + break + } + } + lines.push(indent + this.placeholder.lstrip()) + } + break + } + } + } + + return lines + } + + _split_chunks(text) { + text = this._munge_whitespace(text) + return this._split(text) + } + + // -- Public interface ---------------------------------------------- + + wrap(text) { + /* + * wrap(text : string) -> [string] + * + * Reformat the single paragraph in 'text' so it fits in lines of + * no more than 'self.width' columns, and return a list of wrapped + * lines. Tabs in 'text' are expanded with string.expandtabs(), + * and all other whitespace characters (including newline) are + * converted to space. + */ + let chunks = this._split_chunks(text) + // not implemented in js + //if (this.fix_sentence_endings) { + // this._fix_sentence_endings(chunks) + //} + return this._wrap_chunks(chunks) + } + + fill(text) { + /* + * fill(text : string) -> string + * + * Reformat the single paragraph in 'text' to fit in lines of no + * more than 'self.width' columns, and return a new string + * containing the entire wrapped paragraph. + */ + return this.wrap(text).join('\n') + } +} + + +// -- Convenience interface --------------------------------------------- + +function wrap(text, options = {}) { + /* + * Wrap a single paragraph of text, returning a list of wrapped lines. + * + * Reformat the single paragraph in 'text' so it fits in lines of no + * more than 'width' columns, and return a list of wrapped lines. By + * default, tabs in 'text' are expanded with string.expandtabs(), and + * all other whitespace characters (including newline) are converted to + * space. See TextWrapper class for available keyword args to customize + * wrapping behaviour. + */ + let { width = 70, ...kwargs } = options + let w = new TextWrapper(Object.assign({ width }, kwargs)) + return w.wrap(text) +} + +function fill(text, options = {}) { + /* + * Fill a single paragraph of text, returning a new string. + * + * Reformat the single paragraph in 'text' to fit in lines of no more + * than 'width' columns, and return a new string containing the entire + * wrapped paragraph. As with wrap(), tabs are expanded and other + * whitespace characters converted to space. See TextWrapper class for + * available keyword args to customize wrapping behaviour. + */ + let { width = 70, ...kwargs } = options + let w = new TextWrapper(Object.assign({ width }, kwargs)) + return w.fill(text) +} + +// -- Loosely related functionality ------------------------------------- + +let _whitespace_only_re = /^[ \t]+$/mg +let _leading_whitespace_re = /(^[ \t]*)(?:[^ \t\n])/mg + +function dedent(text) { + /* + * Remove any common leading whitespace from every line in `text`. + * + * This can be used to make triple-quoted strings line up with the left + * edge of the display, while still presenting them in the source code + * in indented form. + * + * Note that tabs and spaces are both treated as whitespace, but they + * are not equal: the lines " hello" and "\\thello" are + * considered to have no common leading whitespace. + * + * Entirely blank lines are normalized to a newline character. + */ + // Look for the longest leading string of spaces and tabs common to + // all lines. + let margin = undefined + text = text.replace(_whitespace_only_re, '') + let indents = text.match(_leading_whitespace_re) || [] + for (let indent of indents) { + indent = indent.slice(0, -1) + + if (margin === undefined) { + margin = indent + + // Current line more deeply indented than previous winner: + // no change (previous winner is still on top). + } else if (indent.startsWith(margin)) { + // pass + + // Current line consistent with and no deeper than previous winner: + // it's the new winner. + } else if (margin.startsWith(indent)) { + margin = indent + + // Find the largest common whitespace between current line and previous + // winner. + } else { + for (let i = 0; i < margin.length && i < indent.length; i++) { + if (margin[i] !== indent[i]) { + margin = margin.slice(0, i) + break + } + } + } + } + + if (margin) { + text = text.replace(new RegExp('^' + margin, 'mg'), '') + } + return text +} + +module.exports = { wrap, fill, dedent } diff --git a/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/package.json b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/package.json new file mode 100644 index 0000000..647d2af --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/argparse@2.0.1/node_modules/argparse/package.json @@ -0,0 +1,31 @@ +{ + "name": "argparse", + "description": "CLI arguments parser. Native port of python's argparse.", + "version": "2.0.1", + "keywords": [ + "cli", + "parser", + "argparse", + "option", + "args" + ], + "main": "argparse.js", + "files": [ + "argparse.js", + "lib/" + ], + "license": "Python-2.0", + "repository": "nodeca/argparse", + "scripts": { + "lint": "eslint .", + "test": "npm run lint && nyc mocha", + "coverage": "npm run test && nyc report --reporter html" + }, + "devDependencies": { + "@babel/eslint-parser": "^7.11.0", + "@babel/plugin-syntax-class-properties": "^7.10.4", + "eslint": "^7.5.0", + "mocha": "^8.0.1", + "nyc": "^15.1.0" + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/CHANGELOG.md b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/CHANGELOG.md new file mode 100644 index 0000000..6e288d3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/CHANGELOG.md @@ -0,0 +1,125 @@ +## 0.8.3 +- Fix buffer over-read for Zip64 extra fields +- Support sync flushes (`Z_SYNC_FLUSH` in zlib) + - Allows for immediate decompression of all pushed bytes + - Enables DEFLATE stream concatenation +- Fix `zip`/`zipSync` when using cross-realm `Uint8Array` +- Improve Zip64 support for streamed or undersized archives +- Update performance estimates in README +- Fix typings for TypeScript v5.7+ +- Reduce memory consumption after compression stream completion +## 0.8.2 +- Fixed broken UMD build +- Fixed edge-case causing skipped data during streaming compression +- Fixed bug in GZIP streaming on member boundary +- Improved streaming performance on inconsistent chunk sizes +- Improved `unzip` performance on undercompressed archives +- Added flushing support into streaming API +- Added backpressure support into async streaming API + - Use new `ondrain` handler and `queuedSize` +## 0.8.1 +- Fixed reallocating on pre-supplied buffer in `inflateSync` and `unzlibSync` +- Minor documentation fixes +## 0.8.0 +- BREAKING: synchronous decompression functions now take an options object rather than an output buffer as a second parameter + - `inflateSync(compressed, outBuf)` is now `inflateSync(compressed, { out: outBuf })` +- Support dictionaries in compression and decompression +- Support multi-member files in GZIP streaming decompression +- Dramatically improved streaming performance +- Fixed missing error on certain malformed GZIP files +## 0.7.3 +- Fix folder creation for certain operating system + - Create 0-length "files" for each directory specified with "object" syntax" + - Support empty folders + - Add options for folders +- Fix minification in SWC + - Remove instanceof, no-whitespace assumptions in async functions +## 0.7.2 +- Fixed TypeScript typing for errors when using `strictNullChecks` +- Fixed failure to compress files above 64kB with `{ level: 0 }` +- Fixed AMD module definition in UMD build +## 0.7.1 +- Removed requirement for `setTimeout` +- Added support for unzip file filters (thanks to [@manucorporat](https://github.com/manucorporat): #67) +- Fixed streaming gunzip and unzlib bug causing corruption +## 0.7.0 +- Improved errors + - Now errors are error objects instead of strings + - Check the error code to apply custom logic based on error type +- Made async operations always call callbacks asynchronously +- Fixed bug that caused errors to not appear in asynchronous operations in browsers +## 0.6.10 +- Fixed async operations on Node.js with native ESM +## 0.6.5 +- Fixed streams not recognizing final chunk +- Fixed streaming UTF-8 decoder bug +## 0.6.4 +- Made streaming inflate consume all data possible +- Optimized use of values near 32-bit boundary +## 0.6.3 +- Patch exports of async functions +- Fix streaming unzip +## 0.6.2 +- Replace Adler-32 implementation (used in Zlib compression) with one more optimized for V8 + - Advice from @SheetJSDev +- Add support for extra fields, file comments in ZIP files +- Work on Rust version +## 0.6.0 +- Revamped streaming unzip for compatibility and performance improvements +- Fixed streaming data bugs +- Fixed inflation errors +- Planned new tests +## 0.5.2 +- General bugfixes +## 0.5.0 +- Add streaming zip, unzip +- Fix import issues with certain environments + - If you had problems with `worker_threads` being included in your bundle, try updating! +## 0.4.8 +- Support strict Content Security Policy + - Remove `new Function` +## 0.4.7 +- Fix data streaming bugs +## 0.4.5 +- Zip64 support + - Still not possible to have above 4GB files +## 0.4.4 +- Files up to 4GB supported + - Hey, that's better than even Node.js `zlib`! +## 0.4.1 +- Fix ZIP failure bug +- Make ZIP options work better +- Improve docs +- Fix async inflate failure +- Work on Rust version +## 0.3.11 +- Fix docs +## 0.3.9 +- Fixed issue with unzipping +## 0.3.7 +- Patched streaming compression bugs +- Added demo page +## 0.3.6 +- Allowed true ESM imports +## 0.3.4 +- Fixed rare overflow bug causing corruption +- Added async stream termination +- Added UMD bundle +## 0.3.0 +- Added support for asynchronous and synchronous streaming +- Reduced bundle size by autogenerating worker code, even in minified environments +- Error detection rather than hanging +- Improved performance +## 0.2.3 +- Improved Zlib autodetection +## 0.2.2 +- Fixed Node Worker +## 0.2.1 +- Fixed ZIP bug +## 0.2.0 +- Added support for ZIP files (parallelized) +- Added ability to terminate running asynchronous operations +## 0.1.0 +- Rewrote API: added support for asynchronous (Worker) compression/decompression, fixed critical bug involving fixed Huffman trees +## 0.0.1 +- Created, works on basic input \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/LICENSE new file mode 100644 index 0000000..bd36874 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Arjun Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/README.md b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/README.md new file mode 100644 index 0000000..36e0654 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/README.md @@ -0,0 +1,558 @@ +# fflate +High performance (de)compression in an 8kB package + +## Why fflate? +`fflate` (short for fast flate) is the **fastest, smallest, and most versatile** pure JavaScript compression and decompression library in existence, handily beating [`pako`](https://npmjs.com/package/pako), [`tiny-inflate`](https://npmjs.com/package/tiny-inflate), and [`UZIP.js`](https://github.com/photopea/UZIP.js) in performance benchmarks while being multiple times more lightweight. Its compression ratios are often better than even the original Zlib C library. It includes support for DEFLATE, GZIP, and Zlib data. Data compressed by `fflate` can be decompressed by other tools, and vice versa. + +In addition to the base decompression and compression APIs, `fflate` supports high-speed ZIP file archiving for an extra 3 kB. In fact, the compressor, in synchronous mode, compresses both more quickly and with a higher compression ratio than most compression software (even Info-ZIP, a C program), and in asynchronous mode it can utilize multiple threads to achieve over 3x the performance of virtually any other utility. + +| | `pako` | `tiny-inflate` | `UZIP.js` | `fflate` | +|-----------------------------|--------|------------------------|-----------------------|--------------------------------| +| Decompression performance | 1x | Up to 40% slower | **Up to 25% faster** | **Up to 25% faster** | +| Compression performance | 1x | N/A | Up to 25% faster | **Up to 50% faster** | +| Base bundle size (minified) | 45.6kB | **3kB (inflate only)** | 14.2kB | 8kB **(3kB for inflate only)** | +| Decompression support | ✅ | ✅ | ✅ | ✅ | +| Compression support | ✅ | ❌ | ✅ | ✅ | +| ZIP support | ❌ | ❌ | ✅ | ✅ | +| Streaming support | ✅ | ❌ | ❌ | ✅ | +| GZIP support | ✅ | ❌ | ❌ | ✅ | +| Supports files up to 4GB | ✅ | ❌ | ❌ | ✅ | +| Doesn't hang on error | ✅ | ❌ | ❌ | ✅ | +| Dictionary support | ✅ | ❌ | ❌ | ✅ | +| Multi-thread/Asynchronous | ❌ | ❌ | ❌ | ✅ | +| Streaming ZIP support | ❌ | ❌ | ❌ | ✅ | +| Uses ES Modules | ❌ | ❌ | ❌ | ✅ | + +## Demo +If you'd like to try `fflate` for yourself without installing it, you can take a look at the [browser demo](https://101arrowz.github.io/fflate). Since `fflate` is a pure JavaScript library, it works in both the browser and Node.js (see [Browser support](https://github.com/101arrowz/fflate/#browser-support) for more info). + +## Usage + +Install `fflate`: +```sh +npm i fflate # or yarn add fflate, or pnpm add fflate +``` + +Import: +```js +// I will assume that you use the following for the rest of this guide +import * as fflate from 'fflate'; + +// However, you should import ONLY what you need to minimize bloat. +// So, if you just need GZIP compression support: +import { gzipSync } from 'fflate'; +// Woo! You just saved 20 kB off your bundle with one line. +``` + +If your environment doesn't support ES Modules (e.g. Node.js): +```js +// Try to avoid this when using fflate in the browser, as it will import +// all of fflate's components, even those that you aren't using. +const fflate = require('fflate'); +``` + +If you want to load from a CDN in the browser: +```html + + + + + + + +``` + +If you are using Deno: +```js +// Don't use the ?dts Skypack flag; it isn't necessary for Deno support +// The @deno-types comment adds TypeScript typings + +// @deno-types="https://cdn.skypack.dev/fflate@0.8.3/lib/index.d.ts" +import * as fflate from 'https://cdn.skypack.dev/fflate@0.8.3?min'; +``` + + +If your environment doesn't support bundling: +```js +// Again, try to import just what you need + +// For the browser: +import * as fflate from 'fflate/esm/browser.js'; +// If the standard ESM import fails on Node (i.e. older version): +import * as fflate from 'fflate/esm'; +``` + +And use: +```js +// This is an ArrayBuffer of data +const massiveFileBuf = await fetch('/aMassiveFile').then( + res => res.arrayBuffer() +); +// To use fflate, you need a Uint8Array +const massiveFile = new Uint8Array(massiveFileBuf); +// Note that Node.js Buffers work just fine as well: +// const massiveFile = require('fs').readFileSync('aMassiveFile.txt'); + +// Higher level means lower performance but better compression +// The level ranges from 0 (no compression) to 9 (max compression) +// The default level is 6 +const notSoMassive = fflate.zlibSync(massiveFile, { level: 9 }); +const massiveAgain = fflate.unzlibSync(notSoMassive); +const gzipped = fflate.gzipSync(massiveFile, { + // GZIP-specific: the filename to use when decompressed + filename: 'aMassiveFile.txt', + // GZIP-specific: the modification time. Can be a Date, date string, + // or Unix timestamp + mtime: '9/1/16 2:00 PM' +}); +``` +`fflate` can autodetect a compressed file's format as well: +```js +const compressed = new Uint8Array( + await fetch('/GZIPorZLIBorDEFLATE').then(res => res.arrayBuffer()) +); +// Above example with Node.js Buffers: +// Buffer.from('H4sIAAAAAAAAE8tIzcnJBwCGphA2BQAAAA==', 'base64'); + +const decompressed = fflate.decompressSync(compressed); +``` + +Using strings is easy with `fflate`'s string conversion API: +```js +const buf = fflate.strToU8('Hello world!'); + +// The default compression method is gzip +// Increasing mem may increase performance at the cost of memory +// The mem ranges from 0 to 12, where 4 is the default +const compressed = fflate.compressSync(buf, { level: 6, mem: 8 }); + +// When you need to decompress: +const decompressed = fflate.decompressSync(compressed); +const origText = fflate.strFromU8(decompressed); +console.log(origText); // Hello world! +``` + +If you need to use an (albeit inefficient) binary string, you can set the second argument to `true`. +```js +const buf = fflate.strToU8('Hello world!'); + +// The second argument, latin1, is a boolean that indicates that the data +// is not Unicode but rather should be encoded and decoded as Latin-1. +// This is useful for creating a string from binary data that isn't +// necessarily valid UTF-8. However, binary strings are incredibly +// inefficient and tend to double file size, so they're not recommended. +const compressedString = fflate.strFromU8( + fflate.compressSync(buf), + true +); +const decompressed = fflate.decompressSync( + fflate.strToU8(compressedString, true) +); +const origText = fflate.strFromU8(decompressed); +console.log(origText); // Hello world! +``` + +You can use streams as well to incrementally add data to be compressed or decompressed: +```js +// This example uses synchronous streams, but for the best experience +// you'll definitely want to use asynchronous streams. + +let outStr = ''; +const gzipStream = new fflate.Gzip({ level: 9 }, (chunk, isLast) => { + // accumulate in an inefficient binary string (just an example) + outStr += fflate.strFromU8(chunk, true); +}); + +// You can also attach the data handler separately if you don't want to +// do so in the constructor. +gzipStream.ondata = (chunk, final) => { ... } + +// Since this is synchronous, all errors will be thrown by stream.push() +gzipStream.push(chunk1); +gzipStream.push(chunk2); + +... + +// You should mark the last chunk by using true in the second argument +// In addition to being necessary for the stream to work properly, this +// will also set the isLast parameter in the handler to true. +gzipStream.push(lastChunk, true); + +console.log(outStr); // The compressed binary string is now available + +// The options parameter for compression streams is optional; you can +// provide one parameter (the handler) or none at all if you set +// deflateStream.ondata later. +const deflateStream = new fflate.Deflate((chunk, final) => { + console.log(chunk, final); +}); + +// If you want to create a stream from strings, use EncodeUTF8 +const utfEncode = new fflate.EncodeUTF8((data, final) => { + // Chaining streams together is done by pushing to the + // next stream in the handler for the previous stream + deflateStream.push(data, final); +}); + +utfEncode.push('Hello'.repeat(1000)); +utfEncode.push(' '.repeat(100)); +utfEncode.push('world!'.repeat(10), true); + +// The deflateStream has logged the compressed data + +const inflateStream = new fflate.Inflate(); +inflateStream.ondata = (decompressedChunk, final) => { ... }; + +let stringData = ''; + +// Streaming UTF-8 decode is available too +const utfDecode = new fflate.DecodeUTF8((data, final) => { + stringData += data; +}); + +// Decompress streams auto-detect the compression method, as the +// non-streaming decompress() method does. +const dcmpStrm = new fflate.Decompress((chunk, final) => { + console.log(chunk, 'was encoded with GZIP, Zlib, or DEFLATE'); + utfDecode.push(chunk, final); +}); + +dcmpStrm.push(zlibJSONData1); +dcmpStrm.push(zlibJSONData2, true); + +// This succeeds; the UTF-8 decoder chained with the unknown compression format +// stream to reach a string as a sink. +console.log(JSON.parse(stringData)); +``` + +You can create multi-file ZIP archives easily as well. Note that by default, compression is enabled for all files, which is not useful when ZIPping many PNGs, JPEGs, PDFs, etc. because those formats are already compressed. You should either override the level on a per-file basis or globally to avoid wasting resources. +```js +// Note that the asynchronous version (see below) runs in parallel and +// is *much* (up to 3x) faster for larger archives. +const zipped = fflate.zipSync({ + // Directories can be nested structures, as in an actual filesystem + 'dir1': { + 'nested': { + // You can use Unicode in filenames + '你好.txt': fflate.strToU8('Hey there!') + }, + // You can also manually write out a directory path + 'other/tmp.txt': new Uint8Array([97, 98, 99, 100]) + }, + + // You can also provide compression options + 'massiveImage.bmp': [aMassiveFile, { + level: 9, + mem: 12 + }], + // PNG is pre-compressed; no need to waste time + 'superTinyFile.png': [aPNGFile, { level: 0 }], + + // Directories take options too + 'exec': [{ + 'hello.sh': [fflate.strToU8('echo hello world'), { + // ZIP only: Set the operating system to Unix + os: 3, + // ZIP only: Make this file executable on Unix + attrs: 0o755 << 16 + }] + }, { + // ZIP and GZIP support mtime (defaults to current time) + mtime: new Date('10/20/2020') + }] +}, { + // These options are the defaults for all files, but file-specific + // options take precedence. + level: 1, + // Obfuscate last modified time by default + mtime: new Date('1/1/1980') +}); + +// If you write the zipped data to myzip.zip and unzip, the folder +// structure will be outputted as: + +// myzip.zip (original file) +// dir1 +// |-> nested +// | |-> 你好.txt +// |-> other +// | |-> tmp.txt +// massiveImage.bmp +// superTinyFile.png + +// When decompressing, folders are not nested; all filepaths are fully +// written out in the keys. For example, the return value may be: +// { 'nested/directory/structure.txt': Uint8Array(2) [97, 97] } +const decompressed = fflate.unzipSync(zipped, { + // You may optionally supply a filter for files. By default, all files in a + // ZIP archive are extracted, but a filter can save resources by telling + // the library not to decompress certain files + filter(file) { + // Don't decompress the massive image or any files larger than 10 MiB + return file.name != 'massiveImage.bmp' && file.originalSize <= 10_000_000; + } +}); +``` + +If you need extremely high performance or custom ZIP compression formats, you can use the highly-extensible ZIP streams. They take streams as both input and output. You can even use custom compression/decompression algorithms from other libraries, as long as they [are defined in the ZIP spec](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT) (see section 4.4.5). If you'd like more info on using custom compressors, [feel free to ask](https://github.com/101arrowz/fflate/discussions). +```js +// ZIP object +// Can also specify zip.ondata outside of the constructor +const zip = new fflate.Zip((err, dat, final) => { + if (!err) { + // output of the streams + console.log(dat, final); + } +}); + +const helloTxt = new fflate.ZipDeflate('hello.txt', { + level: 9 +}); + +// Always add streams to ZIP archives before pushing to those streams +zip.add(helloTxt); + +helloTxt.push(chunk1); +// Last chunk +helloTxt.push(chunk2, true); + +// ZipPassThrough is like ZipDeflate with level 0, but allows for tree shaking +const nonStreamingFile = new fflate.ZipPassThrough('test.png'); +zip.add(nonStreamingFile); +// If you have data already loaded, just .push(data, true) +nonStreamingFile.push(pngData, true); + +// You need to call .end() after finishing +// This ensures the ZIP is valid +zip.end(); + +// Unzip object +const unzipper = new fflate.Unzip(); + +// This function will almost always have to be called. It is used to support +// compression algorithms such as BZIP2 or LZMA in ZIP files if just DEFLATE +// is not enough (though it almost always is). +// If your ZIP files are not compressed, this line is not needed. +unzipper.register(fflate.UnzipInflate); + +const neededFiles = ['file1.txt', 'example.json']; + +// Can specify handler in constructor too +unzipper.onfile = file => { + // file.name is a string, file is a stream + if (neededFiles.includes(file.name)) { + file.ondata = (err, dat, final) => { + // Stream output here + console.log(dat, final); + }; + + console.log('Reading:', file.name); + + // File sizes are sometimes not set if the ZIP file did not encode + // them, so you may want to check that file.size != undefined + console.log('Compressed size', file.size); + console.log('Decompressed size', file.originalSize); + + // You should only start the stream if you plan to use it to improve + // performance. Only after starting the stream will ondata be called. + // This method will throw if the compression method hasn't been registered + file.start(); + } +}; + +// Try to keep under 5,000 files per chunk to avoid stack limit errors +// For example, if all files are a few kB, multi-megabyte chunks are OK +// If files are mostly under 100 bytes, 64kB chunks are the limit +unzipper.push(zipChunk1); +unzipper.push(zipChunk2); +unzipper.push(zipChunk3, true); +``` + +As you may have guessed, there is an asynchronous version of every method as well. Unlike most libraries, this will cause the compression or decompression run in a separate thread entirely and automatically by using Web (or Node) Workers. This means that the processing will not block the main thread at all. + +Note that there is a significant initial overhead to using workers of about 50ms for each asynchronous function. For instance, if you call `unzip` ten times, the overhead only applies for the first call, but if you call `unzip` and `zlib`, they will each cause the 50ms delay. For small (under about 50kB) payloads, the asynchronous APIs will be much slower. However, if you're compressing larger files/multiple files at once, or if the synchronous API causes the main thread to hang for too long, the callback APIs are an order of magnitude better. +```js +import { + gzip, zlib, AsyncGzip, zip, unzip, strFromU8, + Zip, AsyncZipDeflate, Unzip, AsyncUnzipInflate +} from 'fflate'; + +// Workers will work in almost any browser (even IE11!) +// All of the async APIs use a node-style callback as so: +const terminate = gzip(aMassiveFile, (err, data) => { + if (err) { + // The compressed data was likely corrupt, so we have to handle + // the error. + return; + } + // Use data however you like + console.log(data.length); +}); + +if (needToCancel) { + // The return value of any of the asynchronous APIs is a function that, + // when called, will immediately cancel the operation. The callback + // will not be called. + terminate(); +} + +// If you wish to provide options, use the second argument. + +// The consume option will render the data inside aMassiveFile unusable, +// but can improve performance and dramatically reduce memory usage. +zlib(aMassiveFile, { consume: true, level: 9 }, (err, data) => { + // Use the data +}); + +// Asynchronous streams are similar to synchronous streams, but the +// handler has the error that occurred (if any) as the first parameter, +// and they don't block the main thread. + +// Additionally, any buffers that are pushed in will be consumed and +// rendered unusable; if you need to use a buffer you push in, you +// should clone it first. +const gzs = new AsyncGzip({ level: 9, mem: 12, filename: 'hello.txt' }); +let wasCallbackCalled = false; +gzs.ondata = (err, chunk, final) => { + // Note the new err parameter + if (err) { + // Note that after this occurs, the stream becomes corrupt and must + // be discarded. You can't continue pushing chunks and expect it to + // work. + console.error(err); + return; + } + wasCallbackCalled = true; +} +gzs.push(chunk); + +// Since the stream is asynchronous, the callback will not be called +// immediately. If such behavior is absolutely necessary (it shouldn't +// be), use synchronous streams. +console.log(wasCallbackCalled) // false + +// To terminate an asynchronous stream's internal worker, call +// stream.terminate(). +gzs.terminate(); + +// This is way faster than zipSync because the compression of multiple +// files runs in parallel. In fact, the fact that it's parallelized +// makes it faster than most standalone ZIP CLIs. The effect is most +// significant for multiple large files; less so for many small ones. +zip({ f1: aMassiveFile, 'f2.txt': anotherMassiveFile }, { + // The options object is still optional, you can still do just + // zip(archive, callback) + level: 6 +}, (err, data) => { + // Save the ZIP file +}); + +// unzip is the only async function without support for consume option +// It is parallelized, so unzip is also often much faster than unzipSync +unzip(aMassiveZIPFile, (err, unzipped) => { + // If the archive has data.xml, log it here + console.log(unzipped['data.xml']); + // Conversion to string + console.log(strFromU8(unzipped['data.xml'])) +}); + +// Streaming ZIP archives can accept asynchronous streams. This automatically +// uses multicore compression. +const zip = new Zip(); +zip.ondata = (err, chunk, final) => { ... }; +// The JSON and BMP are compressed in parallel +const exampleFile = new AsyncZipDeflate('example.json'); +zip.add(exampleFile); +exampleFile.push(JSON.stringify({ large: 'object' }), true); +const exampleFile2 = new AsyncZipDeflate('example2.bmp', { level: 9 }); +zip.add(exampleFile2); +exampleFile2.push(ec2a); +exampleFile2.push(ec2b); +exampleFile2.push(ec2c); +... +exampleFile2.push(ec2Final, true); +zip.end(); + +// Streaming Unzip should register the asynchronous inflation algorithm +// for parallel processing. +const unzip = new Unzip(stream => { + if (stream.name.endsWith('.json')) { + stream.ondata = (err, chunk, final) => { ... }; + stream.start(); + + if (needToCancel) { + // To cancel these streams, call .terminate() + stream.terminate(); + } + } +}); +unzip.register(AsyncUnzipInflate); +unzip.push(data, true); +``` + +See the [documentation](https://github.com/101arrowz/fflate/blob/master/docs/README.md) for more detailed information about the API. + +## Bundle size estimates + +The bundle size measurements for `fflate` on sites like Bundlephobia include every feature of the library and should be seen as an upper bound. As long as you are using tree shaking or dead code elimination, this table should give you a general idea of `fflate`'s bundle size for the features you need. + +The maximum bundle size that is possible with `fflate` is about 33kB (12.5kB gzipped) if you use every single feature, but feature parity with `pako` is only around 10kB (as opposed to 45kB from `pako`). If your bundle size increases dramatically after adding `fflate`, please [create an issue](https://github.com/101arrowz/fflate/issues/new). + +| Feature | Bundle size (minified) | Nearest competitor | +|-------------------------|--------------------------------|-------------------------| +| Decompression | 3kB | `tiny-inflate` | +| Compression | 5kB | `UZIP.js`, 2.84x larger | +| Async decompression | 4kB (1kB + raw decompression) | N/A | +| Async compression | 6kB (1kB + raw compression) | N/A | +| ZIP decompression | 5kB (2kB + raw decompression) | `UZIP.js`, 2.84x larger | +| ZIP compression | 7kB (2kB + raw compression) | `UZIP.js`, 2.03x larger | +| GZIP/Zlib decompression | 4kB (1kB + raw decompression) | `pako`, 11.4x larger | +| GZIP/Zlib compression | 5kB (1kB + raw compression) | `pako`, 9.12x larger | +| Streaming decompression | 4kB (1kB + raw decompression) | `pako`, 11.4x larger | +| Streaming compression | 5kB (1kB + raw compression) | `pako`, 9.12x larger | + +## What makes `fflate` so fast? +Many JavaScript compression/decompression libraries exist. However, the most popular one, [`pako`](https://npmjs.com/package/pako), is merely a clone of Zlib rewritten nearly line-for-line in JavaScript. Although it is by no means poorly made, `pako` doesn't recognize the many differences between JavaScript and C, and therefore is suboptimal for performance. Moreover, even when minified, the library is 45 kB; it may not seem like much, but for anyone concerned with optimizing bundle size (especially library authors), it's more weight than necessary. + +Note that there exist some small libraries like [`tiny-inflate`](https://npmjs.com/package/tiny-inflate) for solely decompression, and with a minified size of 3 kB, it can be appealing; however, its performance is lackluster, typically 40% worse than `pako` in my tests. + +[`UZIP.js`](https://github.com/photopea/UZIP.js) is both faster (by up to 25%) and smaller (14 kB minified) than `pako`, and it contains a variety of innovations that make it excellent for both performance and compression ratio. However, the developer made a variety of tiny mistakes and inefficient design choices that make it imperfect. Moreover, it does not support GZIP or Zlib data directly; one must remove the headers manually to use `UZIP.js`. + +So what makes `fflate` different? It takes the brilliant innovations of `UZIP.js` and optimizes them while adding direct support for GZIP and Zlib data. And unlike all of the above libraries, it uses ES Modules to allow for partial builds through tree shaking, meaning that it can rival even `tiny-inflate` in size while maintaining excellent performance. The end result is a library that, in total, weighs 8kB minified for the core build (3kB for decompression only and 5kB for compression only), is about 25% faster than `UZIP.js` or up to 50% faster than `pako`, and achieves the same or better compression ratio than the rest. + +Before you decide that `fflate` is the end-all compression library, you should note that JavaScript simply cannot rival the performance of a native program. If you're only using Node.js, it's probably better to use the [native Zlib bindings](https://nodejs.org/api/zlib.html), which tend to offer the best performance. Though note that even against Zlib, `fflate` is only around 30% slower in decompression and 10% slower in compression, and can still achieve better compression ratios! + +## What about `CompressionStream`? +Like `fflate`, the [Compression Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Compression_Streams_API) provides DEFLATE, GZIP, and Zlib compression and decompression support. It's a good option if you'd like to compress or decompress data without installing any third-party libraries, and it wraps native Zlib bindings to achieve better performance than what most JavaScript programs can achieve. + +However, browsers do not offer any native non-streaming compression API, and `CompressionStream` has surprisingly poor performance on data already loaded into memory; `fflate` tends to be faster even for files that are dozens of megabytes large. Similarly, `fflate` is much faster for files under a megabyte because it avoids marshalling overheads. Even when streaming hundreds of megabytes of data, the native API usually performs between 30% faster and 10% slower than `fflate`. And Compression Streams have many other disadvantages - no ability to control compression level, poor support for older browsers, no ZIP support, etc. + +If you'd still prefer to depend upon a native browser API but want to support older browsers, you can use an `fflate`-based [Compression Streams ponyfill](https://github.com/101arrowz/compression-streams-polyfill). + +## Browser support +`fflate` makes heavy use of typed arrays (`Uint8Array`, `Uint16Array`, etc.). Typed arrays can be polyfilled at the cost of performance, but the most recent browser that doesn't support them [is from 2011](https://caniuse.com/typedarrays), so I wouldn't bother. + +The asynchronous APIs also use `Worker`, which is not supported in a few browsers (however, the vast majority of browsers that support typed arrays support `Worker`). + +Other than that, `fflate` is completely ES3, meaning you probably won't even need a bundler to use it. + +## Testing +You can validate the performance of `fflate` with `npm test`. It validates that the module is working as expected, ensures the outputs are no more than 5% larger than competitors at max compression, and outputs performance metrics to `test/results`. + +Note that the time it takes for the CLI to show the completion of each test is not representative of the time each package took, so please check the JSON output if you want accurate measurements. + +## License + +This software is [MIT Licensed](./LICENSE), with special exemptions for projects +and organizations as noted below: + +- [SheetJS](https://github.com/SheetJS/) is exempt from MIT licensing and may + license any source code from this software under the BSD Zero Clause License diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/browser.d.ts b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/browser.d.ts new file mode 100644 index 0000000..d430faf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/browser.d.ts @@ -0,0 +1,1539 @@ +/** + * Codes for errors generated within this library + */ +export declare const FlateErrorCode: { + readonly UnexpectedEOF: 0; + readonly InvalidBlockType: 1; + readonly InvalidLengthLiteral: 2; + readonly InvalidDistance: 3; + readonly StreamFinished: 4; + readonly NoStreamHandler: 5; + readonly InvalidHeader: 6; + readonly NoCallback: 7; + readonly InvalidUTF8: 8; + readonly ExtraFieldTooLong: 9; + readonly InvalidDate: 10; + readonly FilenameTooLong: 11; + readonly StreamFinishing: 12; + readonly InvalidZipData: 13; + readonly UnknownCompressionMethod: 14; +}; +/** + * An error generated within this library + */ +export interface FlateError extends Error { + /** + * The code associated with this error + */ + code: number; +} +/** + * Options for decompressing a DEFLATE stream + */ +export interface InflateStreamOptions { + /** + * The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect. + * + * Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error. + */ + dictionary?: Uint8Array; +} +/** + * Options for decompressing DEFLATE data + */ +export interface InflateOptions extends InflateStreamOptions { + /** + * The buffer into which to write the decompressed data. Saves memory if you know the decompressed size in advance. + * + * Note that if the decompression result is larger than the size of this buffer, it will be truncated to fit. + */ + out?: Uint8Array; +} +/** + * Options for decompressing a GZIP stream + */ +export interface GunzipStreamOptions extends InflateStreamOptions { +} +/** + * Options for decompressing GZIP data + */ +export interface GunzipOptions extends InflateStreamOptions { + /** + * The buffer into which to write the decompressed data. GZIP already encodes the output size, so providing this doesn't save memory. + * + * Note that if the decompression result is larger than the size of this buffer, it will be truncated to fit. + */ + out?: Uint8Array; +} +/** + * Options for decompressing a Zlib stream + */ +export interface UnzlibStreamOptions extends InflateStreamOptions { +} +/** + * Options for decompressing Zlib data + */ +export interface UnzlibOptions extends InflateOptions { +} +/** + * Options for compressing data into a DEFLATE format + */ +export interface DeflateOptions { + /** + * The level of compression to use, ranging from 0-9. + * + * 0 will store the data without compression. + * 1 is fastest but compresses the worst, 9 is slowest but compresses the best. + * The default level is 6. + * + * Typically, binary data benefits much more from higher values than text data. + * In both cases, higher values usually take disproportionately longer than the reduction in final size that results. + * + * For example, a 1 MB text file could: + * - become 1.01 MB with level 0 in 1ms + * - become 400 kB with level 1 in 10ms + * - become 320 kB with level 9 in 100ms + */ + level?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; + /** + * The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory. + * + * Note that this is exponential: while level 0 uses 8 kB, level 4 uses 128 kB, level 8 uses 2 MB, and level 12 uses 32 MB. + * It is recommended not to lower the value below 4, since that tends to hurt performance. + * In addition, values above 8 tend to help very little on most data and can even hurt performance. + * + * The default value is automatically determined based on the size of the input data. + */ + mem?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + /** + * A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios. + * + * Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input. + * The decompressor must supply the same dictionary as the compressor to extract the original data. + * + * Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise. + * + * Avoid using dictionaries with GZIP and ZIP to maximize software compatibility. + */ + dictionary?: Uint8Array; +} +/** + * Options for compressing data into a GZIP format + */ +export interface GzipOptions extends DeflateOptions { + /** + * When the file was last modified. Defaults to the current time. + * Set this to 0 to avoid revealing a modification date entirely. + */ + mtime?: Date | string | number; + /** + * The filename of the data. If the `gunzip` command is used to decompress the data, it will output a file + * with this name instead of the name of the compressed file. + */ + filename?: string; +} +/** + * Options for compressing data into a Zlib format + */ +export interface ZlibOptions extends DeflateOptions { +} +/** + * Handler for data (de)compression streams + * @param data The data output from the stream processor + * @param final Whether this is the final block + */ +export type FlateStreamHandler = (data: Uint8Array, final: boolean) => void; +/** + * Handler for asynchronous data (de)compression streams + * @param err Any error that occurred + * @param data The data output from the stream processor + * @param final Whether this is the final block + */ +export type AsyncFlateStreamHandler = (err: FlateError | null, data: Uint8Array, final: boolean) => void; +/** + * Handler for the asynchronous completion of (de)compression for a data chunk + * @param size The number of bytes that were processed. This is measured in terms of the input + * (i.e. compressed bytes for decompression, uncompressed bytes for compression.) + */ +export type AsyncFlateDrainHandler = (size: number) => void; +/** + * Callback for asynchronous (de)compression methods + * @param err Any error that occurred + * @param data The resulting data. Only present if `err` is null + */ +export type FlateCallback = (err: FlateError | null, data: Uint8Array) => void; +interface AsyncOptions { + /** + * Whether or not to "consume" the source data. This will make the typed array/buffer you pass in + * unusable but will increase performance and reduce memory usage. + */ + consume?: boolean; +} +/** + * Options for compressing data asynchronously into a DEFLATE format + */ +export interface AsyncDeflateOptions extends DeflateOptions, AsyncOptions { +} +/** + * Options for decompressing DEFLATE data asynchronously + */ +export interface AsyncInflateOptions extends AsyncOptions, InflateStreamOptions { + /** + * The original size of the data. Currently, the asynchronous API disallows + * writing into a buffer you provide; the best you can do is provide the + * size in bytes and be given back a new typed array. + */ + size?: number; +} +/** + * Options for compressing data asynchronously into a GZIP format + */ +export interface AsyncGzipOptions extends GzipOptions, AsyncOptions { +} +/** + * Options for decompressing GZIP data asynchronously + */ +export interface AsyncGunzipOptions extends AsyncOptions, InflateStreamOptions { +} +/** + * Options for compressing data asynchronously into a Zlib format + */ +export interface AsyncZlibOptions extends ZlibOptions, AsyncOptions { +} +/** + * Options for decompressing Zlib data asynchronously + */ +export interface AsyncUnzlibOptions extends AsyncInflateOptions { +} +/** + * A terminable compression/decompression process + */ +export interface AsyncTerminable { + /** + * Terminates the worker thread immediately. The callback will not be called. + */ + (): void; +} +/** + * Streaming DEFLATE compression + */ +export declare class Deflate { + /** + * Creates a DEFLATE stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: DeflateOptions, cb?: FlateStreamHandler); + /** + * Creates a DEFLATE stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + private b; + private s; + private o; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + private p; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE compression + */ +export declare class AsyncDeflate { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous DEFLATE stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: DeflateOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous DEFLATE stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function deflate(data: Uint8Array, opts: AsyncDeflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param cb The function to be called upon compression completion + */ +export declare function deflate(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @returns The deflated version of the data + */ +export declare function deflateSync(data: Uint8Array, opts?: DeflateOptions): Uint8Array; +/** + * Streaming DEFLATE decompression + */ +export declare class Inflate { + private s; + private o; + private p; + private d; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a DEFLATE decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: InflateStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a DEFLATE decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + private e; + private c; + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the final chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE decompression + */ +export declare class AsyncInflate { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous DEFLATE decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: InflateStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous DEFLATE decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function inflate(data: Uint8Array, opts: AsyncInflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function inflate(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands DEFLATE data with no wrapper + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function inflateSync(data: Uint8Array): Uint8Array; +/** + * Expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function inflateSync(data: Uint8Array, opts?: InflateOptions): Uint8Array; +/** + * Streaming GZIP compression + */ +export declare class Gzip { + private c; + private l; + private v; + private o; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a GZIP stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: GzipOptions, cb?: FlateStreamHandler); + /** + * Creates a GZIP stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + private p; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming GZIP compression + */ +export declare class AsyncGzip { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous GZIP stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: GzipOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous GZIP stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function gzip(data: Uint8Array, opts: AsyncGzipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with GZIP + * @param data The data to compress + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gzip(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @returns The gzipped version of the data + */ +export declare function gzipSync(data: Uint8Array, opts?: GzipOptions): Uint8Array; +/** + * Handler for new GZIP members in concatenated GZIP streams. Useful for building indices used to perform random-access reads on compressed files. + * @param offset The offset of the new member relative to the start of the stream + */ +export type GunzipMemberHandler = (offset: number) => void; +/** + * Streaming single or multi-member GZIP decompression + */ +export declare class Gunzip { + private v; + private r; + private o; + private p; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * The handler to call whenever a new GZIP member is found + */ + onmember?: GunzipMemberHandler; + /** + * Creates a GUNZIP stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: GunzipStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a GUNZIP stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming single or multi-member GZIP decompression + */ +export declare class AsyncGunzip { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * The handler to call whenever a new GZIP member is found + */ + onmember?: GunzipMemberHandler; + /** + * Creates an asynchronous GUNZIP stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: GunzipStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous GUNZIP stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands GZIP data + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gunzip(data: Uint8Array, opts: AsyncGunzipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands GZIP data + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gunzip(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands GZIP data + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function gunzipSync(data: Uint8Array): Uint8Array; +/** + * Expands GZIP data + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function gunzipSync(data: Uint8Array, opts?: GunzipOptions): Uint8Array; +/** + * Streaming Zlib compression + */ +export declare class Zlib { + private c; + private v; + private o; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a Zlib stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: ZlibOptions, cb?: FlateStreamHandler); + /** + * Creates a Zlib stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be zlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + private p; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming Zlib compression + */ +export declare class AsyncZlib { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous Zlib stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: ZlibOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous Zlib stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with Zlib + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + */ +export declare function zlib(data: Uint8Array, opts: AsyncZlibOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with Zlib + * @param data The data to compress + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zlib(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compress data with Zlib + * @param data The data to compress + * @param opts The compression options + * @returns The zlib-compressed version of the data + */ +export declare function zlibSync(data: Uint8Array, opts?: ZlibOptions): Uint8Array; +/** + * Streaming Zlib decompression + */ +export declare class Unzlib { + private v; + private p; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a Zlib decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: UnzlibStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a Zlib decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be unzlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming Zlib decompression + */ +export declare class AsyncUnzlib { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous Zlib decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: UnzlibStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous Zlib decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be decompressed from Zlib + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands Zlib data + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function unzlib(data: Uint8Array, opts: AsyncUnzlibOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands Zlib data + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function unzlib(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands Zlib data + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function unzlibSync(data: Uint8Array): Uint8Array; +/** + * Expands Zlib data + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function unzlibSync(data: Uint8Array, opts?: UnzlibOptions): Uint8Array; +export { gzip as compress, AsyncGzip as AsyncCompress }; +export { gzipSync as compressSync, Gzip as Compress }; +/** + * Streaming GZIP, Zlib, or raw DEFLATE decompression + */ +export declare class Decompress { + private G; + private I; + private Z; + private o; + private s; + private p; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is decompressed + */ + constructor(opts: InflateStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a decompression stream + * @param cb The callback to call whenever data is decompressed + */ + constructor(cb?: FlateStreamHandler); + private i; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression + */ +export declare class AsyncDecompress { + private G; + private I; + private Z; + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is decompressed + */ + constructor(opts: InflateStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous decompression stream + * @param cb The callback to call whenever data is decompressed + */ + constructor(cb?: AsyncFlateStreamHandler); + private i; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchrononously expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function decompress(data: Uint8Array, opts: AsyncInflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchrononously expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function decompress(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function decompressSync(data: Uint8Array, opts?: InflateOptions): Uint8Array; +/** + * Attributes for files added to a ZIP archive object + */ +export interface ZipAttributes { + /** + * The operating system of origin for this file. The value is defined + * by PKZIP's APPNOTE.txt, section 4.4.2.2. For example, 0 (the default) + * is MS/DOS, 3 is Unix, 19 is macOS. + */ + os?: number; + /** + * The file's attributes. These are traditionally somewhat complicated + * and platform-dependent, so using them is scarcely necessary. However, + * here is a representation of what this is, bit by bit: + * + * `TTTTugtrwxrwxrwx0000000000ADVSHR` + * + * TTTT = file type (rarely useful) + * + * u = setuid, g = setgid, t = sticky + * + * rwx = user permissions, rwx = group permissions, rwx = other permissions + * + * 0000000000 = unused + * + * A = archive, D = directory, V = volume label, S = system file, H = hidden, R = read-only + * + * If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0o644 << 16. + * Note that attributes usually only work in conjunction with the `os` setting: you must use + * `os` = 3 (Unix) if you want to set Unix permissions + */ + attrs?: number; + /** + * Extra metadata to add to the file. This field is defined by PKZIP's APPNOTE.txt, + * section 4.4.28. At most 65,535 bytes may be used in each ID. The ID must be an + * integer between 0 and 65,535, inclusive. + * + * This field is incredibly rare and almost never needed except for compliance with + * proprietary standards and software. + */ + extra?: Record; + /** + * The comment to attach to the file. This field is defined by PKZIP's APPNOTE.txt, + * section 4.4.26. The comment must be at most 65,535 bytes long UTF-8 encoded. This + * field is not read by consumer software. + */ + comment?: string; + /** + * When the file was last modified. Defaults to the current time. + */ + mtime?: GzipOptions['mtime']; +} +/** + * Options for creating a ZIP archive + */ +export interface ZipOptions extends DeflateOptions, ZipAttributes { +} +/** + * Options for expanding a ZIP archive + */ +export interface UnzipOptions { + /** + * A filter function to extract only certain files from a ZIP archive + */ + filter?: UnzipFileFilter; +} +/** + * Options for asynchronously creating a ZIP archive + */ +export interface AsyncZipOptions extends AsyncDeflateOptions, ZipAttributes { +} +/** + * Options for asynchronously expanding a ZIP archive + */ +export interface AsyncUnzipOptions extends UnzipOptions { +} +/** + * A file that can be used to create a ZIP archive + */ +export type ZippableFile = Uint8Array | Zippable | [Uint8Array | Zippable, ZipOptions]; +/** + * A file that can be used to asynchronously create a ZIP archive + */ +export type AsyncZippableFile = Uint8Array | AsyncZippable | [Uint8Array | AsyncZippable, AsyncZipOptions]; +/** + * The complete directory structure of a ZIPpable archive + */ +export interface Zippable { + [path: string]: ZippableFile; +} +/** + * The complete directory structure of an asynchronously ZIPpable archive + */ +export interface AsyncZippable { + [path: string]: AsyncZippableFile; +} +/** + * An unzipped archive. The full path of each file is used as the key, + * and the file is the value + */ +export interface Unzipped { + [path: string]: Uint8Array; +} +/** + * Handler for string generation streams + * @param data The string output from the stream processor + * @param final Whether this is the final block + */ +export type StringStreamHandler = (data: string, final: boolean) => void; +/** + * Callback for asynchronous ZIP decompression + * @param err Any error that occurred + * @param data The decompressed ZIP archive + */ +export type UnzipCallback = (err: FlateError | null, data: Unzipped) => void; +/** + * Handler for streaming ZIP decompression + * @param file The file that was found in the archive + */ +export type UnzipFileHandler = (file: UnzipFile) => void; +/** + * Streaming UTF-8 decoding + */ +export declare class DecodeUTF8 { + private p; + private t; + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is decoded + */ + constructor(cb?: StringStreamHandler); + /** + * Pushes a chunk to be decoded from UTF-8 binary + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * The handler to call whenever data is available + */ + ondata: StringStreamHandler; +} +/** + * Streaming UTF-8 encoding + */ +export declare class EncodeUTF8 { + private d; + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is encoded + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be encoded to UTF-8 + * @param chunk The string data to push + * @param final Whether this is the last chunk + */ + push(chunk: string, final?: boolean): void; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; +} +/** + * Converts a string into a Uint8Array for use with compression/decompression methods + * @param str The string to encode + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless decoding a binary string. + * @returns The string encoded in UTF-8/Latin-1 binary + */ +export declare function strToU8(str: string, latin1?: boolean): Uint8Array; +/** + * Converts a Uint8Array to a string + * @param dat The data to decode to string + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless encoding to binary string. + * @returns The original UTF-8/Latin-1 string + */ +export declare function strFromU8(dat: Uint8Array, latin1?: boolean): string; +/** + * A stream that can be used to create a file in a ZIP archive + */ +export interface ZipInputFile extends ZipAttributes { + /** + * The filename to associate with the data provided to this stream. If you + * want a file in a subdirectory, use forward slashes as a separator (e.g. + * `directory/filename.ext`). This will still work on Windows. + */ + filename: string; + /** + * The size of the file in bytes. This attribute may be invalid after + * the file is added to the ZIP archive; it must be correct only before the + * stream completes. + * + * If you don't want to have to compute this yourself, consider extending the + * ZipPassThrough class and overriding its process() method, or using one of + * ZipDeflate or AsyncZipDeflate. + */ + size: number; + /** + * A CRC of the original file contents. This attribute may be invalid after + * the file is added to the ZIP archive; it must be correct only before the + * stream completes. + * + * If you don't want to have to generate this yourself, consider extending the + * ZipPassThrough class and overriding its process() method, or using one of + * ZipDeflate or AsyncZipDeflate. + */ + crc: number; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA + */ + compression: number; + /** + * Bits 1 and 2 of the general purpose bit flag, specified in PKZIP's + * APPNOTE.txt, section 4.4.4. Should be between 0 and 3. This is unlikely + * to be necessary. + */ + flag?: number; + /** + * The handler to be called when data is added. After passing this stream to + * the ZIP file object, this handler will always be defined. To call it: + * + * `stream.ondata(error, chunk, final)` + * + * error = any error that occurred (null if there was no error) + * + * chunk = a Uint8Array of the data that was added (null if there was an + * error) + * + * final = boolean, whether this is the final chunk in the stream + */ + ondata?: AsyncFlateStreamHandler; + /** + * A method called when the stream is no longer needed, for clean-up + * purposes. This will not always be called after the stream completes, + * so you may wish to call this.terminate() after the final chunk is + * processed if you have clean-up logic. + */ + terminate?: AsyncTerminable; +} +/** + * A pass-through stream to keep data uncompressed in a ZIP archive. + */ +export declare class ZipPassThrough implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private c; + /** + * Creates a pass-through stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + */ + constructor(filename: string); + /** + * Processes a chunk and pushes to the output stream. You can override this + * method in a subclass for custom behavior, but by default this passes + * the data through. You must call this.ondata(err, chunk, final) at some + * point in this method. + * @param chunk The chunk to process + * @param final Whether this is the last chunk + */ + protected process(chunk: Uint8Array, final: boolean): void; + /** + * Pushes a chunk to be added. If you are subclassing this with a custom + * compression algorithm, note that you must push data from the source + * file only, pre-compression. + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate + * for better performance + */ +export declare class ZipDeflate implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + flag: 0 | 1 | 2 | 3; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private d; + /** + * Creates a DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + constructor(filename: string, opts?: DeflateOptions); + private process; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE compression for ZIP archives + */ +export declare class AsyncZipDeflate implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + flag: 0 | 1 | 2 | 3; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private d; + terminate: AsyncTerminable; + /** + * Creates an asynchronous DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + constructor(filename: string, opts?: DeflateOptions); + private process; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * A zippable archive to which files can incrementally be added + */ +export declare class Zip { + private u; + private d; + /** + * Creates an empty ZIP archive to which files can be added + * @param cb The callback to call whenever data for the generated ZIP archive + * is available + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Adds a file to the ZIP archive + * @param file The file stream to add + */ + add(file: ZipInputFile): void; + /** + * Ends the process of adding files and prepares to emit the final chunks. + * This *must* be called after adding all desired files for the resulting + * ZIP file to work properly. + */ + end(): void; + private e; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to add() will fail. + */ + terminate(): void; + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; +} +/** + * Asynchronously creates a ZIP file + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @param cb The callback to call with the generated ZIP archive + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zip(data: AsyncZippable, opts: AsyncZipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously creates a ZIP file + * @param data The directory structure for the ZIP archive + * @param cb The callback to call with the generated ZIP archive + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zip(data: AsyncZippable, cb: FlateCallback): AsyncTerminable; +/** + * Synchronously creates a ZIP file. Prefer using `zip` for better performance + * with more than one file. + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @returns The generated ZIP archive + */ +export declare function zipSync(data: Zippable, opts?: ZipOptions): Uint8Array; +/** + * A decoder for files in ZIP streams + */ +export interface UnzipDecoder { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * Pushes a chunk to be decompressed + * @param chunk The data in this chunk. Do not consume (detach) this buffer. + * @param final Whether this is the last chunk in the data stream + */ + push(chunk: Uint8Array, final: boolean): void; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to push() should silently fail. + */ + terminate?: AsyncTerminable; +} +/** + * A constructor for a decoder for unzip streams + */ +export interface UnzipDecoderConstructor { + /** + * Creates an instance of the decoder + * @param filename The name of the file + * @param size The compressed size of the file + * @param originalSize The original size of the file + */ + new (filename: string, size?: number, originalSize?: number): UnzipDecoder; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA + */ + compression: number; +} +/** + * Information about a file to be extracted from a ZIP archive + */ +export interface UnzipFileInfo { + /** + * The name of the file + */ + name: string; + /** + * The compressed size of the file + */ + size: number; + /** + * The original size of the file + */ + originalSize: number; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA. If the filter function returns true + * but this value is not 8, the unzip function will throw. + */ + compression: number; +} +/** + * A filter for files to be extracted during the unzipping process + * @param file The info for the current file being processed + * @returns Whether or not to extract the current file + */ +export type UnzipFileFilter = (file: UnzipFileInfo) => boolean; +/** + * Streaming file extraction from ZIP archives + */ +export interface UnzipFile { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The name of the file + */ + name: string; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA. If start() is called but there is no + * decompression stream available for this method, start() will throw. + */ + compression: number; + /** + * The compressed size of the file. Will not be present for archives created + * in a streaming fashion. + */ + size?: number; + /** + * The original size of the file. Will not be present for archives created + * in a streaming fashion. + */ + originalSize?: number; + /** + * Starts reading from the stream. Calling this function will always enable + * this stream, but ocassionally the stream will be enabled even without + * this being called. + */ + start(): void; + /** + * A method to terminate any internal workers used by the stream. ondata + * will not be called any further. + */ + terminate: AsyncTerminable; +} +/** + * Streaming pass-through decompression for ZIP archives + */ +export declare class UnzipPassThrough implements UnzipDecoder { + static compression: number; + ondata: AsyncFlateStreamHandler; + push(chunk: Uint8Array, final: boolean): void; +} +/** + * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for + * better performance. + */ +export declare class UnzipInflate implements UnzipDecoder { + static compression: number; + private i; + ondata: AsyncFlateStreamHandler; + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + constructor(); + push(chunk: Uint8Array, final: boolean): void; +} +/** + * Asynchronous streaming DEFLATE decompression for ZIP archives + */ +export declare class AsyncUnzipInflate implements UnzipDecoder { + static compression: number; + private i; + ondata: AsyncFlateStreamHandler; + terminate: AsyncTerminable; + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + constructor(_: string, sz?: number); + push(chunk: Uint8Array, final: boolean): void; +} +/** + * A ZIP archive decompression stream that emits files as they are discovered + */ +export declare class Unzip { + private d; + private c; + private p; + private k; + private o; + /** + * Creates a ZIP decompression stream + * @param cb The callback to call whenever a file in the ZIP archive is found + */ + constructor(cb?: UnzipFileHandler); + /** + * Pushes a chunk to be unzipped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Registers a decoder with the stream, allowing for files compressed with + * the compression type provided to be expanded correctly + * @param decoder The decoder constructor + */ + register(decoder: UnzipDecoderConstructor): void; + /** + * The handler to call whenever a file is discovered + */ + onfile: UnzipFileHandler; +} +/** + * Asynchronously decompresses a ZIP archive + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @param cb The callback to call with the decompressed files + * @returns A function that can be used to immediately terminate the unzipping + */ +export declare function unzip(data: Uint8Array, opts: AsyncUnzipOptions, cb: UnzipCallback): AsyncTerminable; +/** + * Asynchronously decompresses a ZIP archive + * @param data The raw compressed ZIP file + * @param cb The callback to call with the decompressed files + * @returns A function that can be used to immediately terminate the unzipping + */ +export declare function unzip(data: Uint8Array, cb: UnzipCallback): AsyncTerminable; +/** + * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better + * performance with more than one file. + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @returns The decompressed files + */ +export declare function unzipSync(data: Uint8Array, opts?: UnzipOptions): Unzipped; diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/browser.js b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/browser.js new file mode 100644 index 0000000..82af0fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/browser.js @@ -0,0 +1,2692 @@ +// DEFLATE is a complex format; to read this code, you should probably check the RFC first: +// https://tools.ietf.org/html/rfc1951 +// You may also wish to take a look at the guide I made about this program: +// https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad +// Some of the following code is similar to that of UZIP.js: +// https://github.com/photopea/UZIP.js +// However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size. +// Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint +// is better for memory in most engines (I *think*). +var ch2 = {}; +var wk = (function (c, id, msg, transfer, cb) { + var w = new Worker(ch2[id] || (ch2[id] = URL.createObjectURL(new Blob([ + c + ';addEventListener("error",function(e){e=e.error;postMessage({$e$:[e.message,e.code,e.stack]})})' + ], { type: 'text/javascript' })))); + w.onmessage = function (e) { + var d = e.data, ed = d.$e$; + if (ed) { + var err = new Error(ed[0]); + err['code'] = ed[1]; + err.stack = ed[2]; + cb(err, null); + } + else + cb(null, d); + }; + w.postMessage(msg, transfer); + return w; +}); + +// aliases for shorter compressed code (most minifers don't do this) +var u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array; +// fixed length extra bits +var fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]); +// fixed distance extra bits +var fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]); +// code length index map +var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); +// get base, reverse index map from extra bits +var freb = function (eb, start) { + var b = new u16(31); + for (var i = 0; i < 31; ++i) { + b[i] = start += 1 << eb[i - 1]; + } + // numbers here are at max 18 bits + var r = new i32(b[30]); + for (var i = 1; i < 30; ++i) { + for (var j = b[i]; j < b[i + 1]; ++j) { + r[j] = ((j - b[i]) << 5) | i; + } + } + return { b: b, r: r }; +}; +var _a = freb(fleb, 2), fl = _a.b, revfl = _a.r; +// we can ignore the fact that the other numbers are wrong; they never happen anyway +fl[28] = 258, revfl[258] = 28; +var _b = freb(fdeb, 0), fd = _b.b, revfd = _b.r; +// map of value to reverse (assuming 16 bits) +var rev = new u16(32768); +for (var i = 0; i < 32768; ++i) { + // reverse table algorithm from SO + var x = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1); + x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2); + x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4); + rev[i] = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) >> 1; +} +// create huffman tree from u8 "map": index -> code length for code index +// mb (max bits) must be at most 15 +// TODO: optimize/split up? +var hMap = (function (cd, mb, r) { + var s = cd.length; + // index + var i = 0; + // u16 "map": index -> # of codes with bit length = index + var l = new u16(mb); + // length of cd must be 288 (total # of codes) + for (; i < s; ++i) { + if (cd[i]) + ++l[cd[i] - 1]; + } + // u16 "map": index -> minimum code for bit length = index + var le = new u16(mb); + for (i = 1; i < mb; ++i) { + le[i] = (le[i - 1] + l[i - 1]) << 1; + } + var co; + if (r) { + // u16 "map": index -> number of actual bits, symbol for code + co = new u16(1 << mb); + // bits to remove for reverser + var rvb = 15 - mb; + for (i = 0; i < s; ++i) { + // ignore 0 lengths + if (cd[i]) { + // num encoding both symbol and bits read + var sv = (i << 4) | cd[i]; + // free bits + var r_1 = mb - cd[i]; + // start value + var v = le[cd[i] - 1]++ << r_1; + // m is end value + for (var m = v | ((1 << r_1) - 1); v <= m; ++v) { + // every 16 bit value starting with the code yields the same result + co[rev[v] >> rvb] = sv; + } + } + } + } + else { + co = new u16(s); + for (i = 0; i < s; ++i) { + if (cd[i]) { + co[i] = rev[le[cd[i] - 1]++] >> (15 - cd[i]); + } + } + } + return co; +}); +// fixed length tree +var flt = new u8(288); +for (var i = 0; i < 144; ++i) + flt[i] = 8; +for (var i = 144; i < 256; ++i) + flt[i] = 9; +for (var i = 256; i < 280; ++i) + flt[i] = 7; +for (var i = 280; i < 288; ++i) + flt[i] = 8; +// fixed distance tree +var fdt = new u8(32); +for (var i = 0; i < 32; ++i) + fdt[i] = 5; +// fixed length map +var flm = /*#__PURE__*/ hMap(flt, 9, 0), flrm = /*#__PURE__*/ hMap(flt, 9, 1); +// fixed distance map +var fdm = /*#__PURE__*/ hMap(fdt, 5, 0), fdrm = /*#__PURE__*/ hMap(fdt, 5, 1); +// find max of array +var max = function (a) { + var m = a[0]; + for (var i = 1; i < a.length; ++i) { + if (a[i] > m) + m = a[i]; + } + return m; +}; +// read d, starting at bit p and mask with m +var bits = function (d, p, m) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m; +}; +// read d, starting at bit p continuing for at least 16 bits +var bits16 = function (d, p) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7)); +}; +// get end of byte +var shft = function (p) { return ((p + 7) / 8) | 0; }; +// typed array slice - allows garbage collector to free original reference, +// while being more compatible than .slice +var slc = function (v, s, e) { + if (s == null || s < 0) + s = 0; + if (e == null || e > v.length) + e = v.length; + // can't use .constructor in case user-supplied + return new u8(v.subarray(s, e)); +}; +/** + * Codes for errors generated within this library + */ +export var FlateErrorCode = { + UnexpectedEOF: 0, + InvalidBlockType: 1, + InvalidLengthLiteral: 2, + InvalidDistance: 3, + StreamFinished: 4, + NoStreamHandler: 5, + InvalidHeader: 6, + NoCallback: 7, + InvalidUTF8: 8, + ExtraFieldTooLong: 9, + InvalidDate: 10, + FilenameTooLong: 11, + StreamFinishing: 12, + InvalidZipData: 13, + UnknownCompressionMethod: 14 +}; +// error codes +var ec = [ + 'unexpected EOF', + 'invalid block type', + 'invalid length/literal', + 'invalid distance', + 'stream finished', + 'no stream handler', + , // determined by compression function + 'no callback', + 'invalid UTF-8 data', + 'extra field too long', + 'date not in range 1980-2099', + 'filename too long', + 'stream finishing', + 'invalid zip data' + // determined by unknown compression method +]; +; +var err = function (ind, msg, nt) { + var e = new Error(msg || ec[ind]); + e.code = ind; + if (Error.captureStackTrace) + Error.captureStackTrace(e, err); + if (!nt) + throw e; + return e; +}; +// expands raw DEFLATE data +var inflt = function (dat, st, buf, dict) { + // source length dict length + var sl = dat.length, dl = dict ? dict.length : 0; + if (!sl || st.f && !st.l) + return buf || new u8(0); + var noBuf = !buf; + // have to estimate size + var resize = noBuf || st.i != 2; + // no state + var noSt = st.i; + // Assumes roughly 33% compression ratio average + if (noBuf) + buf = new u8(sl * 3); + // ensure buffer can fit at least l elements + var cbuf = function (l) { + var bl = buf.length; + // need to increase size to fit + if (l > bl) { + // Double or set to necessary, whichever is greater + var nbuf = new u8(Math.max(bl * 2, l)); + nbuf.set(buf); + buf = nbuf; + } + }; + // last chunk bitpos bytes + var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; + // total bits + var tbts = sl * 8; + do { + if (!lm) { + // BFINAL - this is only 1 when last chunk is next + final = bits(dat, pos, 1); + // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman + var type = bits(dat, pos + 1, 3); + pos += 3; + if (!type) { + // go to end of byte boundary + var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l; + if (t > sl) { + if (noSt) + err(0); + break; + } + // ensure size + if (resize) + cbuf(bt + l); + // Copy over uncompressed data + buf.set(dat.subarray(s, t), bt); + // Get new bitpos, update byte count + st.b = bt += l, st.p = pos = t * 8, st.f = final; + continue; + } + else if (type == 1) + lm = flrm, dm = fdrm, lbt = 9, dbt = 5; + else if (type == 2) { + // literal lengths + var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; + var tl = hLit + bits(dat, pos + 5, 31) + 1; + pos += 14; + // length+distance tree + var ldt = new u8(tl); + // code length tree + var clt = new u8(19); + for (var i = 0; i < hcLen; ++i) { + // use index map to get real code + clt[clim[i]] = bits(dat, pos + i * 3, 7); + } + pos += hcLen * 3; + // code lengths bits + var clb = max(clt), clbmsk = (1 << clb) - 1; + // code lengths map + var clm = hMap(clt, clb, 1); + for (var i = 0; i < tl;) { + var r = clm[bits(dat, pos, clbmsk)]; + // bits read + pos += r & 15; + // symbol + var s = r >> 4; + // code length to copy + if (s < 16) { + ldt[i++] = s; + } + else { + // copy count + var c = 0, n = 0; + if (s == 16) + n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; + else if (s == 17) + n = 3 + bits(dat, pos, 7), pos += 3; + else if (s == 18) + n = 11 + bits(dat, pos, 127), pos += 7; + while (n--) + ldt[i++] = c; + } + } + // length tree distance tree + var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); + // max length bits + lbt = max(lt); + // max dist bits + dbt = max(dt); + lm = hMap(lt, lbt, 1); + dm = hMap(dt, dbt, 1); + } + else + err(1); + if (pos > tbts) { + if (noSt) + err(0); + break; + } + } + // Make sure the buffer can hold this + the largest possible addition + // Maximum chunk size (practically, theoretically infinite) is 2^17 + if (resize) + cbuf(bt + 131072); + var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; + var lpos = pos; + for (;; lpos = pos) { + // bits read, code + var c = lm[bits16(dat, pos) & lms], sym = c >> 4; + pos += c & 15; + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (!c) + err(2); + if (sym < 256) + buf[bt++] = sym; + else if (sym == 256) { + lpos = pos, lm = null; + break; + } + else { + var add = sym - 254; + // no extra bits needed if less + if (sym > 264) { + // index + var i = sym - 257, b = fleb[i]; + add = bits(dat, pos, (1 << b) - 1) + fl[i]; + pos += b; + } + // dist + var d = dm[bits16(dat, pos) & dms], dsym = d >> 4; + if (!d) + err(3); + pos += d & 15; + var dt = fd[dsym]; + if (dsym > 3) { + var b = fdeb[dsym]; + dt += bits16(dat, pos) & (1 << b) - 1, pos += b; + } + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (resize) + cbuf(bt + 131072); + var end = bt + add; + if (bt < dt) { + var shift = dl - dt, dend = Math.min(dt, end); + if (shift + bt < 0) + err(3); + for (; bt < dend; ++bt) + buf[bt] = dict[shift + bt]; + } + for (; bt < end; ++bt) + buf[bt] = buf[bt - dt]; + } + } + st.l = lm, st.p = lpos, st.b = bt, st.f = final; + if (lm) + final = 1, st.m = lbt, st.d = dm, st.n = dbt; + } while (!final); + // don't reallocate for streams or user buffers + return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt); +}; +// starting at p, write the minimum number of bits that can hold v to d +var wbits = function (d, p, v) { + v <<= p & 7; + var o = (p / 8) | 0; + d[o] |= v; + d[o + 1] |= v >> 8; +}; +// starting at p, write the minimum number of bits (>8) that can hold v to d +var wbits16 = function (d, p, v) { + v <<= p & 7; + var o = (p / 8) | 0; + d[o] |= v; + d[o + 1] |= v >> 8; + d[o + 2] |= v >> 16; +}; +// creates code lengths from a frequency table +var hTree = function (d, mb) { + // Need extra info to make a tree + var t = []; + for (var i = 0; i < d.length; ++i) { + if (d[i]) + t.push({ s: i, f: d[i] }); + } + var s = t.length; + var t2 = t.slice(); + if (!s) + return { t: et, l: 0 }; + if (s == 1) { + var v = new u8(t[0].s + 1); + v[t[0].s] = 1; + return { t: v, l: 1 }; + } + t.sort(function (a, b) { return a.f - b.f; }); + // after i2 reaches last ind, will be stopped + // freq must be greater than largest possible number of symbols + t.push({ s: -1, f: 25001 }); + var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2; + t[0] = { s: -1, f: l.f + r.f, l: l, r: r }; + // efficient algorithm from UZIP.js + // i0 is lookbehind, i2 is lookahead - after processing two low-freq + // symbols that combined have high freq, will start processing i2 (high-freq, + // non-composite) symbols instead + // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/ + while (i1 != s - 1) { + l = t[t[i0].f < t[i2].f ? i0++ : i2++]; + r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++]; + t[i1++] = { s: -1, f: l.f + r.f, l: l, r: r }; + } + var maxSym = t2[0].s; + for (var i = 1; i < s; ++i) { + if (t2[i].s > maxSym) + maxSym = t2[i].s; + } + // code lengths + var tr = new u16(maxSym + 1); + // max bits in tree + var mbt = ln(t[i1 - 1], tr, 0); + if (mbt > mb) { + // more algorithms from UZIP.js + // TODO: find out how this code works (debt) + // ind debt + var i = 0, dt = 0; + // left cost + var lft = mbt - mb, cst = 1 << lft; + t2.sort(function (a, b) { return tr[b.s] - tr[a.s] || a.f - b.f; }); + for (; i < s; ++i) { + var i2_1 = t2[i].s; + if (tr[i2_1] > mb) { + dt += cst - (1 << (mbt - tr[i2_1])); + tr[i2_1] = mb; + } + else + break; + } + dt >>= lft; + while (dt > 0) { + var i2_2 = t2[i].s; + if (tr[i2_2] < mb) + dt -= 1 << (mb - tr[i2_2]++ - 1); + else + ++i; + } + for (; i >= 0 && dt; --i) { + var i2_3 = t2[i].s; + if (tr[i2_3] == mb) { + --tr[i2_3]; + ++dt; + } + } + mbt = mb; + } + return { t: new u8(tr), l: mbt }; +}; +// get the max length and assign length codes +var ln = function (n, l, d) { + return n.s == -1 + ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) + : (l[n.s] = d); +}; +// length codes generation +var lc = function (c) { + var s = c.length; + // Note that the semicolon was intentional + while (s && !c[--s]) + ; + var cl = new u16(++s); + // ind num streak + var cli = 0, cln = c[0], cls = 1; + var w = function (v) { cl[cli++] = v; }; + for (var i = 1; i <= s; ++i) { + if (c[i] == cln && i != s) + ++cls; + else { + if (!cln && cls > 2) { + for (; cls > 138; cls -= 138) + w(32754); + if (cls > 2) { + w(cls > 10 ? ((cls - 11) << 5) | 28690 : ((cls - 3) << 5) | 12305); + cls = 0; + } + } + else if (cls > 3) { + w(cln), --cls; + for (; cls > 6; cls -= 6) + w(8304); + if (cls > 2) + w(((cls - 3) << 5) | 8208), cls = 0; + } + while (cls--) + w(cln); + cls = 1; + cln = c[i]; + } + } + return { c: cl.subarray(0, cli), n: s }; +}; +// calculate the length of output from tree, code lengths +var clen = function (cf, cl) { + var l = 0; + for (var i = 0; i < cl.length; ++i) + l += cf[i] * cl[i]; + return l; +}; +// writes a fixed block +// returns the new bit pos +var wfblk = function (out, pos, dat) { + // no need to write 00 as type: TypedArray defaults to 0 + var s = dat.length; + var o = shft(pos + 2); + out[o] = s & 255; + out[o + 1] = s >> 8; + out[o + 2] = out[o] ^ 255; + out[o + 3] = out[o + 1] ^ 255; + for (var i = 0; i < s; ++i) + out[o + i + 4] = dat[i]; + return (o + 4 + s) * 8; +}; +// writes a block +var wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) { + wbits(out, p++, final); + ++lf[256]; + var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l; + var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l; + var _c = lc(dlt), lclt = _c.c, nlc = _c.n; + var _d = lc(ddt), lcdt = _d.c, ndc = _d.n; + var lcfreq = new u16(19); + for (var i = 0; i < lclt.length; ++i) + ++lcfreq[lclt[i] & 31]; + for (var i = 0; i < lcdt.length; ++i) + ++lcfreq[lcdt[i] & 31]; + var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l; + var nlcc = 19; + for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc) + ; + var flen = (bl + 5) << 3; + var ftlen = clen(lf, flt) + clen(df, fdt) + eb; + var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18]; + if (bs >= 0 && flen <= ftlen && flen <= dtlen) + return wfblk(out, p, dat.subarray(bs, bs + bl)); + var lm, ll, dm, dl; + wbits(out, p, 1 + (dtlen < ftlen)), p += 2; + if (dtlen < ftlen) { + lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt; + var llm = hMap(lct, mlcb, 0); + wbits(out, p, nlc - 257); + wbits(out, p + 5, ndc - 1); + wbits(out, p + 10, nlcc - 4); + p += 14; + for (var i = 0; i < nlcc; ++i) + wbits(out, p + 3 * i, lct[clim[i]]); + p += 3 * nlcc; + var lcts = [lclt, lcdt]; + for (var it = 0; it < 2; ++it) { + var clct = lcts[it]; + for (var i = 0; i < clct.length; ++i) { + var len = clct[i] & 31; + wbits(out, p, llm[len]), p += lct[len]; + if (len > 15) + wbits(out, p, (clct[i] >> 5) & 127), p += clct[i] >> 12; + } + } + } + else { + lm = flm, ll = flt, dm = fdm, dl = fdt; + } + for (var i = 0; i < li; ++i) { + var sym = syms[i]; + if (sym > 255) { + var len = (sym >> 18) & 31; + wbits16(out, p, lm[len + 257]), p += ll[len + 257]; + if (len > 7) + wbits(out, p, (sym >> 23) & 31), p += fleb[len]; + var dst = sym & 31; + wbits16(out, p, dm[dst]), p += dl[dst]; + if (dst > 3) + wbits16(out, p, (sym >> 5) & 8191), p += fdeb[dst]; + } + else { + wbits16(out, p, lm[sym]), p += ll[sym]; + } + } + wbits16(out, p, lm[256]); + return p + ll[256]; +}; +// deflate options (nice << 13) | chain +var deo = /*#__PURE__*/ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]); +// empty +var et = /*#__PURE__*/ new u8(0); +// compresses data into a raw DEFLATE buffer +var dflt = function (dat, lvl, plvl, pre, post, st) { + var s = st.z || dat.length; + var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7000)) + post); + // writing to this writes to the output buffer + var w = o.subarray(pre, o.length - post); + var lst = st.l; + var pos = (st.r || 0) & 7; + if (lvl) { + if (pos) + w[0] = st.r >> 3; + var opt = deo[lvl - 1]; + var n = opt >> 13, c = opt & 8191; + var msk_1 = (1 << plvl) - 1; + // prev 2-byte val map curr 2-byte val map + var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1); + var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1; + var hsh = function (i) { return (dat[i] ^ (dat[i + 1] << bs1_1) ^ (dat[i + 2] << bs2_1)) & msk_1; }; + // 24576 is an arbitrary number of maximum symbols per block + // 424 buffer for last block + var syms = new i32(25000); + // length/literal freq distance freq + var lf = new u16(288), df = new u16(32); + // l/lcnt exbits index l/lind waitdx blkpos + var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0; + for (; i + 2 < s; ++i) { + // hash value + var hv = hsh(i); + // index mod 32768 previous index mod + var imod = i & 32767, pimod = head[hv]; + prev[imod] = pimod; + head[hv] = imod; + // We always should modify head and prev, but only add symbols if + // this data is not yet processed ("wait" for wait index) + if (wi <= i) { + // bytes remaining + var rem = s - i; + if ((lc_1 > 7000 || li > 24576) && (rem > 423 || !lst)) { + pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos); + li = lc_1 = eb = 0, bs = i; + for (var j = 0; j < 286; ++j) + lf[j] = 0; + for (var j = 0; j < 30; ++j) + df[j] = 0; + } + // len dist chain + var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767; + if (rem > 2 && hv == hsh(i - dif)) { + var maxn = Math.min(n, rem) - 1; + var maxd = Math.min(32767, i); + // max possible length + // not capped at dif because decompressors implement "rolling" index population + var ml = Math.min(258, rem); + while (dif <= maxd && --ch_1 && imod != pimod) { + if (dat[i + l] == dat[i + l - dif]) { + var nl = 0; + for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl) + ; + if (nl > l) { + l = nl, d = dif; + // break out early when we reach "nice" (we are satisfied enough) + if (nl > maxn) + break; + // now, find the rarest 2-byte sequence within this + // length of literals and search for that instead. + // Much faster than just using the start + var mmd = Math.min(dif, nl - 2); + var md = 0; + for (var j = 0; j < mmd; ++j) { + var ti = i - dif + j & 32767; + var pti = prev[ti]; + var cd = ti - pti & 32767; + if (cd > md) + md = cd, pimod = ti; + } + } + } + // check the previous match + imod = pimod, pimod = prev[imod]; + dif += imod - pimod & 32767; + } + } + // d will be nonzero only when a match was found + if (d) { + // store both dist and len data in one int32 + // Make sure this is recognized as a len/dist with 28th bit (2^28) + syms[li++] = 268435456 | (revfl[l] << 18) | revfd[d]; + var lin = revfl[l] & 31, din = revfd[d] & 31; + eb += fleb[lin] + fdeb[din]; + ++lf[257 + lin]; + ++df[din]; + wi = i + l; + ++lc_1; + } + else { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + } + } + for (i = Math.max(i, wi); i < s; ++i) { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos); + if (!lst) { + st.r = (pos & 7) | w[(pos / 8) | 0] << 3; + // shft(pos) now 1 less if pos & 7 != 0 + pos -= 7; + st.h = head, st.p = prev, st.i = i, st.w = wi; + } + } + else { + for (var i = st.w || 0; i < s + lst; i += 65535) { + // end + var e = i + 65535; + if (e >= s) { + // write final block + w[(pos / 8) | 0] = lst; + e = s; + } + pos = wfblk(w, pos + 1, dat.subarray(i, e)); + } + st.i = s; + } + return slc(o, 0, pre + shft(pos) + post); +}; +// CRC32 table +var crct = /*#__PURE__*/ (function () { + var t = new Int32Array(256); + for (var i = 0; i < 256; ++i) { + var c = i, k = 9; + while (--k) + c = ((c & 1) && -306674912) ^ (c >>> 1); + t[i] = c; + } + return t; +})(); +// CRC32 +var crc = function () { + var c = -1; + return { + p: function (d) { + // closures have awful performance + var cr = c; + for (var i = 0; i < d.length; ++i) + cr = crct[(cr & 255) ^ d[i]] ^ (cr >>> 8); + c = cr; + }, + d: function () { return ~c; } + }; +}; +// Adler32 +var adler = function () { + var a = 1, b = 0; + return { + p: function (d) { + // closures have awful performance + var n = a, m = b; + var l = d.length | 0; + for (var i = 0; i != l;) { + var e = Math.min(i + 2655, l); + for (; i < e; ++i) + m += n += d[i]; + n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16); + } + a = n, b = m; + }, + d: function () { + a %= 65521, b %= 65521; + return (a & 255) << 24 | (a & 0xFF00) << 8 | (b & 255) << 8 | (b >> 8); + } + }; +}; +; +// deflate with opts +var dopt = function (dat, opt, pre, post, st) { + if (!st) { + st = { l: 1 }; + if (opt.dictionary) { + var dict = opt.dictionary.subarray(-32768); + var newDat = new u8(dict.length + dat.length); + newDat.set(dict); + newDat.set(dat, dict.length); + dat = newDat; + st.w = dict.length; + } + } + return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? (st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20) : (12 + opt.mem), pre, post, st); +}; +// Walmart object spread +var mrg = function (a, b) { + var o = {}; + for (var k in a) + o[k] = a[k]; + for (var k in b) + o[k] = b[k]; + return o; +}; +// worker clone +// This is possibly the craziest part of the entire codebase, despite how simple it may seem. +// The only parameter to this function is a closure that returns an array of variables outside of the function scope. +// We're going to try to figure out the variable names used in the closure as strings because that is crucial for workerization. +// We will return an object mapping of true variable name to value (basically, the current scope as a JS object). +// The reason we can't just use the original variable names is minifiers mangling the toplevel scope. +// This took me three weeks to figure out how to do. +var wcln = function (fn, fnStr, td) { + var dt = fn(); + var st = fn.toString(); + var ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/\s+/g, '').split(','); + for (var i = 0; i < dt.length; ++i) { + var v = dt[i], k = ks[i]; + if (typeof v == 'function') { + fnStr += ';' + k + '='; + var st_1 = v.toString(); + if (v.prototype) { + // for global objects + if (st_1.indexOf('[native code]') != -1) { + var spInd = st_1.indexOf(' ', 8) + 1; + fnStr += st_1.slice(spInd, st_1.indexOf('(', spInd)); + } + else { + fnStr += st_1; + for (var t in v.prototype) + fnStr += ';' + k + '.prototype.' + t + '=' + v.prototype[t].toString(); + } + } + else + fnStr += st_1; + } + else + td[k] = v; + } + return fnStr; +}; +var ch = []; +// clone bufs +var cbfs = function (v) { + var tl = []; + for (var k in v) { + if (v[k].buffer) { + tl.push((v[k] = new v[k].constructor(v[k])).buffer); + } + } + return tl; +}; +// use a worker to execute code +var wrkr = function (fns, init, id, cb) { + if (!ch[id]) { + var fnStr = '', td_1 = {}, m = fns.length - 1; + for (var i = 0; i < m; ++i) + fnStr = wcln(fns[i], fnStr, td_1); + ch[id] = { c: wcln(fns[m], fnStr, td_1), e: td_1 }; + } + var td = mrg({}, ch[id].e); + return wk(ch[id].c + ';onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage=' + init.toString() + '}', id, td, cbfs(td), cb); +}; +// base async inflate fn +var bInflt = function () { return [u8, u16, i32, fleb, fdeb, clim, fl, fd, flrm, fdrm, rev, ec, hMap, max, bits, bits16, shft, slc, err, inflt, inflateSync, pbf, gopt]; }; +var bDflt = function () { return [u8, u16, i32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; }; +// gzip extra +var gze = function () { return [gzh, gzhl, wbytes, crc, crct]; }; +// gunzip extra +var guze = function () { return [gzs, gzl]; }; +// zlib extra +var zle = function () { return [zlh, wbytes, adler]; }; +// unzlib extra +var zule = function () { return [zls]; }; +// post buf +var pbf = function (msg) { return postMessage(msg, [msg.buffer]); }; +// get opts +var gopt = function (o) { return o && { + out: o.size && new u8(o.size), + dictionary: o.dictionary +}; }; +// async helper +var cbify = function (dat, opts, fns, init, id, cb) { + var w = wrkr(fns, init, id, function (err, dat) { + w.terminate(); + cb(err, dat); + }); + w.postMessage([dat, opts], opts.consume ? [dat.buffer] : []); + return function () { w.terminate(); }; +}; +// auto stream +var astrm = function (strm) { + strm.ondata = function (dat, final) { return postMessage([dat, final], [dat.buffer]); }; + return function (ev) { + if (ev.data[0]) { + strm.push(ev.data[0], ev.data[1]); + postMessage([ev.data[0].length]); + } + else + strm.flush(ev.data[1]); + }; +}; +// async stream attach +var astrmify = function (fns, strm, opts, init, id, flush, ext) { + var t; + var w = wrkr(fns, init, id, function (err, dat) { + if (err) + w.terminate(), strm.ondata.call(strm, err); + else if (!Array.isArray(dat)) + ext(dat); + else if (dat.length == 1) { + strm.queuedSize -= dat[0]; + if (strm.ondrain) + strm.ondrain(dat[0]); + } + else { + if (dat[1]) + w.terminate(); + strm.ondata.call(strm, err, dat[0], dat[1]); + } + }); + w.postMessage(opts); + strm.queuedSize = 0; + strm.push = function (d, f) { + if (!strm.ondata) + err(5); + if (t) + strm.ondata(err(4, 0, 1), null, !!f); + strm.queuedSize += d.length; + // can fail for cross-realm Uint8Array, but ok - only a small performance penalty + w.postMessage([d, t = f], d.buffer instanceof ArrayBuffer ? [d.buffer] : []); + }; + strm.terminate = function () { w.terminate(); }; + if (flush) { + strm.flush = function (sync) { w.postMessage([0, sync]); }; + } +}; +// read 2 bytes +var b2 = function (d, b) { return d[b] | (d[b + 1] << 8); }; +// read 4 bytes +var b4 = function (d, b) { return (d[b] | (d[b + 1] << 8) | (d[b + 2] << 16) | (d[b + 3] << 24)) >>> 0; }; +// read 8 bytes +var b8 = function (d, b) { return b4(d, b) + (b4(d, b + 4) * 4294967296); }; +// write bytes +var wbytes = function (d, b, v) { + for (; v; ++b) + d[b] = v, v >>>= 8; +}; +// gzip header +var gzh = function (c, o) { + var fn = o.filename; + c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3; // assume Unix + if (o.mtime != 0) + wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1000)); + if (fn) { + c[3] = 8; + for (var i = 0; i <= fn.length; ++i) + c[i + 10] = fn.charCodeAt(i); + } +}; +// gzip footer: -8 to -4 = CRC, -4 to -0 is length +// gzip start +var gzs = function (d) { + if (d[0] != 31 || d[1] != 139 || d[2] != 8) + err(6, 'invalid gzip data'); + var flg = d[3]; + var st = 10; + if (flg & 4) + st += (d[10] | d[11] << 8) + 2; + for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++]) + ; + return st + (flg & 2); +}; +// gzip length +var gzl = function (d) { + var l = d.length; + return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0; +}; +// gzip header length +var gzhl = function (o) { return 10 + (o.filename ? o.filename.length + 1 : 0); }; +// zlib header +var zlh = function (c, o) { + var lv = o.level, fl = lv == 0 ? 0 : lv < 6 ? 1 : lv == 9 ? 3 : 2; + c[0] = 120, c[1] = (fl << 6) | (o.dictionary && 32); + c[1] |= 31 - ((c[0] << 8) | c[1]) % 31; + if (o.dictionary) { + var h = adler(); + h.p(o.dictionary); + wbytes(c, 2, h.d()); + } +}; +// zlib start +var zls = function (d, dict) { + if ((d[0] & 15) != 8 || (d[0] >> 4) > 7 || ((d[0] << 8 | d[1]) % 31)) + err(6, 'invalid zlib data'); + if ((d[1] >> 5 & 1) == +!dict) + err(6, 'invalid zlib data: ' + (d[1] & 32 ? 'need' : 'unexpected') + ' dictionary'); + return (d[1] >> 3 & 4) + 2; +}; +function StrmOpt(opts, cb) { + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + return opts; +} +/** + * Streaming DEFLATE compression + */ +var Deflate = /*#__PURE__*/ (function () { + function Deflate(opts, cb) { + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + this.o = opts || {}; + this.s = { l: 0, i: 32768, w: 32768, z: 32768 }; + // Buffer length must always be 0 mod 32768 for index calculations to be correct when modifying head and prev + // 98304 = 32768 (lookback) + 65536 (common chunk size) + this.b = new u8(98304); + if (this.o.dictionary) { + var dict = this.o.dictionary.subarray(-32768); + this.b.set(dict, 32768 - dict.length); + this.s.i = 32768 - dict.length; + } + } + Deflate.prototype.p = function (c, f) { + this.ondata(dopt(c, this.o, 0, 0, this.s), f); + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Deflate.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (this.s.l) + err(4); + var endLen = chunk.length + this.s.z; + if (endLen > this.b.length) { + if (endLen > 2 * this.b.length - 32768) { + var newBuf = new u8(endLen & -32768); + newBuf.set(this.b.subarray(0, this.s.z)); + this.b = newBuf; + } + var split = this.b.length - this.s.z; + this.b.set(chunk.subarray(0, split), this.s.z); + this.s.z = this.b.length; + this.p(this.b, false); + this.b.set(this.b.subarray(-32768)); + this.b.set(chunk.subarray(split), 32768); + this.s.z = chunk.length - split + 32768; + this.s.i = 32766, this.s.w = 32768; + } + else { + this.b.set(chunk, this.s.z); + this.s.z += chunk.length; + } + this.s.l = final & 1; + if (this.s.z > this.s.w + 8191 || final) { + this.p(this.b, final || false); + this.s.w = this.s.i, this.s.i -= 2; + } + if (final) { + // cleanup unneeded buffers/state to reduce memory usage + this.s = this.o = {}; + this.b = et; + } + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + Deflate.prototype.flush = function (sync) { + if (!this.ondata) + err(5); + if (this.s.l) + err(4); + this.p(this.b, false); + this.s.w = this.s.i, this.s.i -= 2; + // could technically skip writing the type-0 block for (this.s.r & 7) == 0, + // but the deterministic trailer (00 00 FF FF) is useful in some situations + if (sync) { + var c = new u8(6); + c[0] = this.s.r >> 3; + // write empty, non-final type-0 block + var ep = wfblk(c, this.s.r, et); + this.s.r = 0; + this.ondata(c.subarray(0, ep >> 3), false); + } + }; + return Deflate; +}()); +export { Deflate }; +/** + * Asynchronous streaming DEFLATE compression + */ +var AsyncDeflate = /*#__PURE__*/ (function () { + function AsyncDeflate(opts, cb) { + astrmify([ + bDflt, + function () { return [astrm, Deflate]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Deflate(ev.data); + onmessage = astrm(strm); + }, 6, 1); + } + return AsyncDeflate; +}()); +export { AsyncDeflate }; +export function deflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + ], function (ev) { return pbf(deflateSync(ev.data[0], ev.data[1])); }, 0, cb); +} +/** + * Compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @returns The deflated version of the data + */ +export function deflateSync(data, opts) { + return dopt(data, opts || {}, 0, 0); +} +/** + * Streaming DEFLATE decompression + */ +var Inflate = /*#__PURE__*/ (function () { + function Inflate(opts, cb) { + // no StrmOpt here to avoid adding to workerizer + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768); + this.s = { i: 0, b: dict ? dict.length : 0 }; + this.o = new u8(32768); + this.p = new u8(0); + if (dict) + this.o.set(dict); + } + Inflate.prototype.e = function (c) { + if (!this.ondata) + err(5); + if (this.d) + err(4); + if (!this.p.length) + this.p = c; + else if (c.length) { + var n = new u8(this.p.length + c.length); + n.set(this.p), n.set(c, this.p.length), this.p = n; + } + }; + Inflate.prototype.c = function (final) { + this.s.i = +(this.d = final || false); + var bts = this.s.b; + var dt = inflt(this.p, this.s, this.o); + this.ondata(slc(dt, bts, this.s.b), this.d); + this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length; + this.p = slc(this.p, (this.s.p / 8) | 0), this.s.p &= 7; + }; + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the final chunk + */ + Inflate.prototype.push = function (chunk, final) { + this.e(chunk), this.c(final); + }; + return Inflate; +}()); +export { Inflate }; +/** + * Asynchronous streaming DEFLATE decompression + */ +var AsyncInflate = /*#__PURE__*/ (function () { + function AsyncInflate(opts, cb) { + astrmify([ + bInflt, + function () { return [astrm, Inflate]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Inflate(ev.data); + onmessage = astrm(strm); + }, 7, 0); + } + return AsyncInflate; +}()); +export { AsyncInflate }; +export function inflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt + ], function (ev) { return pbf(inflateSync(ev.data[0], gopt(ev.data[1]))); }, 1, cb); +} +export function inflateSync(data, opts) { + return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary); +} +// before you yell at me for not just using extends, my reason is that TS inheritance is hard to workerize. +/** + * Streaming GZIP compression + */ +var Gzip = /*#__PURE__*/ (function () { + function Gzip(opts, cb) { + this.c = crc(); + this.l = 0; + this.v = 1; + Deflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Gzip.prototype.push = function (chunk, final) { + this.c.p(chunk); + this.l += chunk.length; + Deflate.prototype.push.call(this, chunk, final); + }; + Gzip.prototype.p = function (c, f) { + var raw = dopt(c, this.o, this.v && gzhl(this.o), f && 8, this.s); + if (this.v) + gzh(raw, this.o), this.v = 0; + if (f) + wbytes(raw, raw.length - 8, this.c.d()), wbytes(raw, raw.length - 4, this.l); + this.ondata(raw, f); + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + Gzip.prototype.flush = function (sync) { + Deflate.prototype.flush.call(this, sync); + }; + return Gzip; +}()); +export { Gzip }; +/** + * Asynchronous streaming GZIP compression + */ +var AsyncGzip = /*#__PURE__*/ (function () { + function AsyncGzip(opts, cb) { + astrmify([ + bDflt, + gze, + function () { return [astrm, Deflate, Gzip]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Gzip(ev.data); + onmessage = astrm(strm); + }, 8, 1); + } + return AsyncGzip; +}()); +export { AsyncGzip }; +export function gzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + gze, + function () { return [gzipSync]; } + ], function (ev) { return pbf(gzipSync(ev.data[0], ev.data[1])); }, 2, cb); +} +/** + * Compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @returns The gzipped version of the data + */ +export function gzipSync(data, opts) { + if (!opts) + opts = {}; + var c = crc(), l = data.length; + c.p(data); + var d = dopt(data, opts, gzhl(opts), 8), s = d.length; + return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d; +} +/** + * Streaming single or multi-member GZIP decompression + */ +var Gunzip = /*#__PURE__*/ (function () { + function Gunzip(opts, cb) { + this.v = 1; + this.r = 0; + Inflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Gunzip.prototype.push = function (chunk, final) { + Inflate.prototype.e.call(this, chunk); + this.r += chunk.length; + if (this.v) { + var p = this.p.subarray(this.v - 1); + var s = p.length > 3 ? gzs(p) : 4; + if (s > p.length) { + if (!final) + return; + } + else if (this.v > 1 && this.onmember) { + this.onmember(this.r - p.length); + } + this.p = p.subarray(s), this.v = 0; + } + // necessary to prevent TS from using the closure value + // This allows for workerization to function correctly + Inflate.prototype.c.call(this, 0); + // process concatenated GZIP + if (this.s.f && !this.s.l) { + this.v = shft(this.s.p) + 9; + this.s = { i: 0 }; + this.o = new u8(0); + this.push(new u8(0), final); + } + else if (final) { + Inflate.prototype.c.call(this, final); + } + }; + return Gunzip; +}()); +export { Gunzip }; +/** + * Asynchronous streaming single or multi-member GZIP decompression + */ +var AsyncGunzip = /*#__PURE__*/ (function () { + function AsyncGunzip(opts, cb) { + var _this = this; + astrmify([ + bInflt, + guze, + function () { return [astrm, Inflate, Gunzip]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Gunzip(ev.data); + strm.onmember = function (offset) { return postMessage(offset); }; + onmessage = astrm(strm); + }, 9, 0, function (offset) { return _this.onmember && _this.onmember(offset); }); + } + return AsyncGunzip; +}()); +export { AsyncGunzip }; +export function gunzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt, + guze, + function () { return [gunzipSync]; } + ], function (ev) { return pbf(gunzipSync(ev.data[0], ev.data[1])); }, 3, cb); +} +export function gunzipSync(data, opts) { + var st = gzs(data); + if (st + 8 > data.length) + err(6, 'invalid gzip data'); + return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary); +} +/** + * Streaming Zlib compression + */ +var Zlib = /*#__PURE__*/ (function () { + function Zlib(opts, cb) { + this.c = adler(); + this.v = 1; + Deflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be zlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Zlib.prototype.push = function (chunk, final) { + this.c.p(chunk); + Deflate.prototype.push.call(this, chunk, final); + }; + Zlib.prototype.p = function (c, f) { + var raw = dopt(c, this.o, this.v && (this.o.dictionary ? 6 : 2), f && 4, this.s); + if (this.v) + zlh(raw, this.o), this.v = 0; + if (f) + wbytes(raw, raw.length - 4, this.c.d()); + this.ondata(raw, f); + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + Zlib.prototype.flush = function (sync) { + Deflate.prototype.flush.call(this, sync); + }; + return Zlib; +}()); +export { Zlib }; +/** + * Asynchronous streaming Zlib compression + */ +var AsyncZlib = /*#__PURE__*/ (function () { + function AsyncZlib(opts, cb) { + astrmify([ + bDflt, + zle, + function () { return [astrm, Deflate, Zlib]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Zlib(ev.data); + onmessage = astrm(strm); + }, 10, 1); + } + return AsyncZlib; +}()); +export { AsyncZlib }; +export function zlib(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + zle, + function () { return [zlibSync]; } + ], function (ev) { return pbf(zlibSync(ev.data[0], ev.data[1])); }, 4, cb); +} +/** + * Compress data with Zlib + * @param data The data to compress + * @param opts The compression options + * @returns The zlib-compressed version of the data + */ +export function zlibSync(data, opts) { + if (!opts) + opts = {}; + var a = adler(); + a.p(data); + var d = dopt(data, opts, opts.dictionary ? 6 : 2, 4); + return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d; +} +/** + * Streaming Zlib decompression + */ +var Unzlib = /*#__PURE__*/ (function () { + function Unzlib(opts, cb) { + Inflate.call(this, opts, cb); + this.v = opts && opts.dictionary ? 2 : 1; + } + /** + * Pushes a chunk to be unzlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Unzlib.prototype.push = function (chunk, final) { + Inflate.prototype.e.call(this, chunk); + if (this.v) { + if (this.p.length < 6 && !final) + return; + this.p = this.p.subarray(zls(this.p, this.v - 1)), this.v = 0; + } + if (final) { + if (this.p.length < 4) + err(6, 'invalid zlib data'); + this.p = this.p.subarray(0, -4); + } + // necessary to prevent TS from using the closure value + // This allows for workerization to function correctly + Inflate.prototype.c.call(this, final); + }; + return Unzlib; +}()); +export { Unzlib }; +/** + * Asynchronous streaming Zlib decompression + */ +var AsyncUnzlib = /*#__PURE__*/ (function () { + function AsyncUnzlib(opts, cb) { + astrmify([ + bInflt, + zule, + function () { return [astrm, Inflate, Unzlib]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Unzlib(ev.data); + onmessage = astrm(strm); + }, 11, 0); + } + return AsyncUnzlib; +}()); +export { AsyncUnzlib }; +export function unzlib(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt, + zule, + function () { return [unzlibSync]; } + ], function (ev) { return pbf(unzlibSync(ev.data[0], gopt(ev.data[1]))); }, 5, cb); +} +export function unzlibSync(data, opts) { + return inflt(data.subarray(zls(data, opts && opts.dictionary), -4), { i: 2 }, opts && opts.out, opts && opts.dictionary); +} +// Default algorithm for compression (used because having a known output size allows faster decompression) +export { gzip as compress, AsyncGzip as AsyncCompress }; +export { gzipSync as compressSync, Gzip as Compress }; +/** + * Streaming GZIP, Zlib, or raw DEFLATE decompression + */ +var Decompress = /*#__PURE__*/ (function () { + function Decompress(opts, cb) { + this.o = StrmOpt.call(this, opts, cb) || {}; + this.G = Gunzip; + this.I = Inflate; + this.Z = Unzlib; + } + // init substream + // overriden by AsyncDecompress + Decompress.prototype.i = function () { + var _this = this; + this.s.ondata = function (dat, final) { + _this.ondata(dat, final); + }; + }; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Decompress.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (!this.s) { + if (this.p && this.p.length) { + var n = new u8(this.p.length + chunk.length); + n.set(this.p), n.set(chunk, this.p.length); + } + else + this.p = chunk; + if (this.p.length > 2) { + this.s = (this.p[0] == 31 && this.p[1] == 139 && this.p[2] == 8) + ? new this.G(this.o) + : ((this.p[0] & 15) != 8 || (this.p[0] >> 4) > 7 || ((this.p[0] << 8 | this.p[1]) % 31)) + ? new this.I(this.o) + : new this.Z(this.o); + this.i(); + this.s.push(this.p, final); + this.p = null; + } + } + else + this.s.push(chunk, final); + }; + return Decompress; +}()); +export { Decompress }; +/** + * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression + */ +var AsyncDecompress = /*#__PURE__*/ (function () { + function AsyncDecompress(opts, cb) { + Decompress.call(this, opts, cb); + this.queuedSize = 0; + this.G = AsyncGunzip; + this.I = AsyncInflate; + this.Z = AsyncUnzlib; + } + AsyncDecompress.prototype.i = function () { + var _this = this; + this.s.ondata = function (err, dat, final) { + _this.ondata(err, dat, final); + }; + this.s.ondrain = function (size) { + _this.queuedSize -= size; + if (_this.ondrain) + _this.ondrain(size); + }; + }; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + AsyncDecompress.prototype.push = function (chunk, final) { + this.queuedSize += chunk.length; + Decompress.prototype.push.call(this, chunk, final); + }; + return AsyncDecompress; +}()); +export { AsyncDecompress }; +export function decompress(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return (data[0] == 31 && data[1] == 139 && data[2] == 8) + ? gunzip(data, opts, cb) + : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31)) + ? inflate(data, opts, cb) + : unzlib(data, opts, cb); +} +/** + * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export function decompressSync(data, opts) { + return (data[0] == 31 && data[1] == 139 && data[2] == 8) + ? gunzipSync(data, opts) + : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31)) + ? inflateSync(data, opts) + : unzlibSync(data, opts); +} +// flatten a directory structure +var fltn = function (d, p, t, o) { + for (var k in d) { + var val = d[k], n = p + k, op = o; + if (Array.isArray(val)) + op = mrg(o, val[1]), val = val[0]; + if (ArrayBuffer.isView(val)) + t[n] = [val, op]; + else { + t[n += '/'] = [new u8(0), op]; + fltn(val, n, t, o); + } + } +}; +// text encoder +var te = typeof TextEncoder != 'undefined' && /*#__PURE__*/ new TextEncoder(); +// text decoder +var td = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder(); +// text decoder stream +var tds = 0; +try { + td.decode(et, { stream: true }); + tds = 1; +} +catch (e) { } +// decode UTF8 +var dutf8 = function (d) { + for (var r = '', i = 0;;) { + var c = d[i++]; + var eb = (c > 127) + (c > 223) + (c > 239); + if (i + eb > d.length) + return { s: r, r: slc(d, i - 1) }; + if (!eb) + r += String.fromCharCode(c); + else if (eb == 3) { + c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)) - 65536, + r += String.fromCharCode(55296 | (c >> 10), 56320 | (c & 1023)); + } + else if (eb & 1) + r += String.fromCharCode((c & 31) << 6 | (d[i++] & 63)); + else + r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)); + } +}; +/** + * Streaming UTF-8 decoding + */ +var DecodeUTF8 = /*#__PURE__*/ (function () { + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is decoded + */ + function DecodeUTF8(cb) { + this.ondata = cb; + if (tds) + this.t = new TextDecoder(); + else + this.p = et; + } + /** + * Pushes a chunk to be decoded from UTF-8 binary + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + DecodeUTF8.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + final = !!final; + if (this.t) { + this.ondata(this.t.decode(chunk, { stream: true }), final); + if (final) { + if (this.t.decode().length) + err(8); + this.t = null; + } + return; + } + if (!this.p) + err(4); + var dat = new u8(this.p.length + chunk.length); + dat.set(this.p); + dat.set(chunk, this.p.length); + var _a = dutf8(dat), s = _a.s, r = _a.r; + if (final) { + if (r.length) + err(8); + this.p = null; + } + else + this.p = r; + this.ondata(s, final); + }; + return DecodeUTF8; +}()); +export { DecodeUTF8 }; +/** + * Streaming UTF-8 encoding + */ +var EncodeUTF8 = /*#__PURE__*/ (function () { + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is encoded + */ + function EncodeUTF8(cb) { + this.ondata = cb; + } + /** + * Pushes a chunk to be encoded to UTF-8 + * @param chunk The string data to push + * @param final Whether this is the last chunk + */ + EncodeUTF8.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (this.d) + err(4); + this.ondata(strToU8(chunk), this.d = final || false); + }; + return EncodeUTF8; +}()); +export { EncodeUTF8 }; +/** + * Converts a string into a Uint8Array for use with compression/decompression methods + * @param str The string to encode + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless decoding a binary string. + * @returns The string encoded in UTF-8/Latin-1 binary + */ +export function strToU8(str, latin1) { + if (latin1) { + var ar_1 = new u8(str.length); + for (var i = 0; i < str.length; ++i) + ar_1[i] = str.charCodeAt(i); + return ar_1; + } + if (te) + return te.encode(str); + var l = str.length; + var ar = new u8(str.length + (str.length >> 1)); + var ai = 0; + var w = function (v) { ar[ai++] = v; }; + for (var i = 0; i < l; ++i) { + if (ai + 5 > ar.length) { + var n = new u8(ai + 8 + ((l - i) << 1)); + n.set(ar); + ar = n; + } + var c = str.charCodeAt(i); + if (c < 128 || latin1) + w(c); + else if (c < 2048) + w(192 | (c >> 6)), w(128 | (c & 63)); + else if (c > 55295 && c < 57344) + c = 65536 + (c & 1023 << 10) | (str.charCodeAt(++i) & 1023), + w(240 | (c >> 18)), w(128 | ((c >> 12) & 63)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63)); + else + w(224 | (c >> 12)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63)); + } + return slc(ar, 0, ai); +} +/** + * Converts a Uint8Array to a string + * @param dat The data to decode to string + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless encoding to binary string. + * @returns The original UTF-8/Latin-1 string + */ +export function strFromU8(dat, latin1) { + if (latin1) { + var r = ''; + for (var i = 0; i < dat.length; i += 16384) + r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384)); + return r; + } + else if (td) { + return td.decode(dat); + } + else { + var _a = dutf8(dat), s = _a.s, r = _a.r; + if (r.length) + err(8); + return s; + } +} +; +// deflate bit flag +var dbf = function (l) { return l == 1 ? 3 : l < 6 ? 2 : l == 9 ? 1 : 0; }; +// skip local zip header +var slzh = function (d, b) { return b + 30 + b2(d, b + 26) + b2(d, b + 28); }; +// read zip header +var zh = function (d, b, z) { + var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl; + var _a = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a[0], su = _a[1], off = _a[2]; + return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off]; +}; +// read zip64 header sizes +var z64hs = function (d, b, l, z, sc, su, off) { + var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l; + var nf = nsc + nsu + noff; + if (z && nf) { + for (; b + 4 < e; b += 4 + b2(d, b + 2)) { + if (b2(d, b) == 1) { + return [ + nsc ? b8(d, b + 4 + 8 * nsu) : sc, + nsu ? b8(d, b + 4) : su, + noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off, + 1 + ]; + } + } + // z == 2 for unknown whether or not zip64 + if (z < 2) + err(13); + } + return [sc, su, off, 0]; +}; +// extra field length +var exfl = function (ex) { + var le = 0; + if (ex) { + for (var k in ex) { + var l = ex[k].length; + if (l > 65535) + err(9); + le += l + 4; + } + } + return le; +}; +// write zip header +var wzh = function (d, b, f, fn, u, c, ce, co) { + var fl = fn.length, ex = f.extra, col = co && co.length; + var exl = exfl(ex); + wbytes(d, b, ce != null ? 0x2014B50 : 0x4034B50), b += 4; + if (ce != null) + d[b++] = 20, d[b++] = f.os; + d[b] = 20, b += 2; // spec compliance? what's that? + d[b++] = (f.flag << 1) | (c < 0 && 8), d[b++] = u && 8; + d[b++] = f.compression & 255, d[b++] = f.compression >> 8; + var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980; + if (y < 0 || y > 119) + err(10); + wbytes(d, b, (y << 25) | ((dt.getMonth() + 1) << 21) | (dt.getDate() << 16) | (dt.getHours() << 11) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1)), b += 4; + if (c != -1) { + wbytes(d, b, f.crc); + wbytes(d, b + 4, c < 0 ? -c - 2 : c); + wbytes(d, b + 8, f.size); + } + wbytes(d, b + 12, fl); + wbytes(d, b + 14, exl), b += 16; + if (ce != null) { + wbytes(d, b, col); + wbytes(d, b + 6, f.attrs); + wbytes(d, b + 10, ce), b += 14; + } + d.set(fn, b); + b += fl; + if (exl) { + for (var k in ex) { + var exf = ex[k], l = exf.length; + wbytes(d, b, +k); + wbytes(d, b + 2, l); + d.set(exf, b + 4), b += 4 + l; + } + } + if (col) + d.set(co, b), b += col; + return b; +}; +// write zip footer (end of central directory) +var wzf = function (o, b, c, d, e) { + wbytes(o, b, 0x6054B50); // skip disk + wbytes(o, b + 8, c); + wbytes(o, b + 10, c); + wbytes(o, b + 12, d); + wbytes(o, b + 16, e); +}; +/** + * A pass-through stream to keep data uncompressed in a ZIP archive. + */ +var ZipPassThrough = /*#__PURE__*/ (function () { + /** + * Creates a pass-through stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + */ + function ZipPassThrough(filename) { + this.filename = filename; + this.c = crc(); + this.size = 0; + this.compression = 0; + } + /** + * Processes a chunk and pushes to the output stream. You can override this + * method in a subclass for custom behavior, but by default this passes + * the data through. You must call this.ondata(err, chunk, final) at some + * point in this method. + * @param chunk The chunk to process + * @param final Whether this is the last chunk + */ + ZipPassThrough.prototype.process = function (chunk, final) { + this.ondata(null, chunk, final); + }; + /** + * Pushes a chunk to be added. If you are subclassing this with a custom + * compression algorithm, note that you must push data from the source + * file only, pre-compression. + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + ZipPassThrough.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + this.c.p(chunk); + this.size += chunk.length; + if (final) + this.crc = this.c.d(); + // we shouldn't really do this cast, but properly handling ArrayBufferLike + // makes the API unergonomic with Buffer + this.process(chunk, final || false); + }; + return ZipPassThrough; +}()); +export { ZipPassThrough }; +// I don't extend because TypeScript extension adds 1kB of runtime bloat +/** + * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate + * for better performance + */ +var ZipDeflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + function ZipDeflate(filename, opts) { + var _this = this; + if (!opts) + opts = {}; + ZipPassThrough.call(this, filename); + this.d = new Deflate(opts, function (dat, final) { + _this.ondata(null, dat, final); + }); + this.compression = 8; + this.flag = dbf(opts.level); + } + ZipDeflate.prototype.process = function (chunk, final) { + try { + this.d.push(chunk, final); + } + catch (e) { + this.ondata(e, null, final); + } + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + ZipDeflate.prototype.push = function (chunk, final) { + ZipPassThrough.prototype.push.call(this, chunk, final); + }; + return ZipDeflate; +}()); +export { ZipDeflate }; +/** + * Asynchronous streaming DEFLATE compression for ZIP archives + */ +var AsyncZipDeflate = /*#__PURE__*/ (function () { + /** + * Creates an asynchronous DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + function AsyncZipDeflate(filename, opts) { + var _this = this; + if (!opts) + opts = {}; + ZipPassThrough.call(this, filename); + this.d = new AsyncDeflate(opts, function (err, dat, final) { + _this.ondata(err, dat, final); + }); + this.compression = 8; + this.flag = dbf(opts.level); + this.terminate = this.d.terminate; + } + AsyncZipDeflate.prototype.process = function (chunk, final) { + this.d.push(chunk, final); + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + AsyncZipDeflate.prototype.push = function (chunk, final) { + ZipPassThrough.prototype.push.call(this, chunk, final); + }; + return AsyncZipDeflate; +}()); +export { AsyncZipDeflate }; +// TODO: Better tree shaking +/** + * A zippable archive to which files can incrementally be added + */ +var Zip = /*#__PURE__*/ (function () { + /** + * Creates an empty ZIP archive to which files can be added + * @param cb The callback to call whenever data for the generated ZIP archive + * is available + */ + function Zip(cb) { + this.ondata = cb; + this.u = []; + this.d = 1; + } + /** + * Adds a file to the ZIP archive + * @param file The file stream to add + */ + Zip.prototype.add = function (file) { + var _this = this; + if (!this.ondata) + err(5); + // finishing or finished + if (this.d & 2) + this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, false); + else { + var f = strToU8(file.filename), fl_1 = f.length; + var com = file.comment, o = com && strToU8(com); + var u = fl_1 != file.filename.length || (o && (com.length != o.length)); + var hl_1 = fl_1 + exfl(file.extra) + 30; + if (fl_1 > 65535) + this.ondata(err(11, 0, 1), null, false); + var header = new u8(hl_1); + wzh(header, 0, file, f, u, -1); + var chks_1 = [header]; + var pAll_1 = function () { + for (var _i = 0, chks_2 = chks_1; _i < chks_2.length; _i++) { + var chk = chks_2[_i]; + _this.ondata(null, chk, false); + } + chks_1 = []; + }; + var tr_1 = this.d; + this.d = 0; + var ind_1 = this.u.length; + var uf_1 = mrg(file, { + f: f, + u: u, + o: o, + t: function () { + if (file.terminate) + file.terminate(); + }, + r: function () { + pAll_1(); + if (tr_1) { + var nxt = _this.u[ind_1 + 1]; + if (nxt) + nxt.r(); + else + _this.d = 1; + } + tr_1 = 1; + } + }); + var cl_1 = 0; + file.ondata = function (err, dat, final) { + if (err) { + _this.ondata(err, dat, final); + _this.terminate(); + } + else { + cl_1 += dat.length; + chks_1.push(dat); + if (final) { + var dd = new u8(16); + wbytes(dd, 0, 0x8074B50); + wbytes(dd, 4, file.crc); + wbytes(dd, 8, cl_1); + wbytes(dd, 12, file.size); + chks_1.push(dd); + uf_1.c = cl_1, uf_1.b = hl_1 + cl_1 + 16, uf_1.crc = file.crc, uf_1.size = file.size; + if (tr_1) + uf_1.r(); + tr_1 = 1; + } + else if (tr_1) + pAll_1(); + } + }; + this.u.push(uf_1); + } + }; + /** + * Ends the process of adding files and prepares to emit the final chunks. + * This *must* be called after adding all desired files for the resulting + * ZIP file to work properly. + */ + Zip.prototype.end = function () { + var _this = this; + if (this.d & 2) { + this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, true); + return; + } + if (this.d) + this.e(); + else + this.u.push({ + r: function () { + if (!(_this.d & 1)) + return; + _this.u.splice(-1, 1); + _this.e(); + }, + t: function () { } + }); + this.d = 3; + }; + Zip.prototype.e = function () { + var bt = 0, l = 0, tl = 0; + for (var _i = 0, _a = this.u; _i < _a.length; _i++) { + var f = _a[_i]; + tl += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0); + } + var out = new u8(tl + 22); + for (var _b = 0, _c = this.u; _b < _c.length; _b++) { + var f = _c[_b]; + wzh(out, bt, f, f.f, f.u, -f.c - 2, l, f.o); + bt += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0), l += f.b; + } + wzf(out, bt, this.u.length, tl, l); + this.ondata(null, out, true); + this.d = 2; + }; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to add() will fail. + */ + Zip.prototype.terminate = function () { + for (var _i = 0, _a = this.u; _i < _a.length; _i++) { + var f = _a[_i]; + f.t(); + } + this.d = 2; + }; + return Zip; +}()); +export { Zip }; +export function zip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + var r = {}; + fltn(data, '', r, opts); + var k = Object.keys(r); + var lft = k.length, o = 0, tot = 0; + var slft = lft, files = new Array(lft); + var term = []; + var tAll = function () { + for (var i = 0; i < term.length; ++i) + term[i](); + }; + var cbd = function (a, b) { + mt(function () { cb(a, b); }); + }; + mt(function () { cbd = cb; }); + var cbf = function () { + var out = new u8(tot + 22), oe = o, cdl = tot - o; + tot = 0; + for (var i = 0; i < slft; ++i) { + var f = files[i]; + try { + var l = f.c.length; + wzh(out, tot, f, f.f, f.u, l); + var badd = 30 + f.f.length + exfl(f.extra); + var loc = tot + badd; + out.set(f.c, loc); + wzh(out, o, f, f.f, f.u, l, tot, f.m), o += 16 + badd + (f.m ? f.m.length : 0), tot = loc + l; + } + catch (e) { + return cbd(e, null); + } + } + wzf(out, o, files.length, cdl, oe); + cbd(null, out); + }; + if (!lft) + cbf(); + var _loop_1 = function (i) { + var fn = k[i]; + var _a = r[fn], file = _a[0], p = _a[1]; + var c = crc(), size = file.length; + c.p(file); + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + var compression = p.level == 0 ? 0 : 8; + var cbl = function (e, d) { + if (e) { + tAll(); + cbd(e, null); + } + else { + var l = d.length; + files[i] = mrg(p, { + size: size, + crc: c.d(), + c: d, + f: f, + m: m, + u: s != fn.length || (m && (com.length != ms)), + compression: compression + }); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + if (!--lft) + cbf(); + } + }; + if (s > 65535) + cbl(err(11, 0, 1), null); + if (!compression) + cbl(null, file); + else if (size < 160000) { + try { + cbl(null, deflateSync(file, p)); + } + catch (e) { + cbl(e, null); + } + } + else + term.push(deflate(file, p, cbl)); + }; + // Cannot use lft because it can decrease + for (var i = 0; i < slft; ++i) { + _loop_1(i); + } + return tAll; +} +/** + * Synchronously creates a ZIP file. Prefer using `zip` for better performance + * with more than one file. + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @returns The generated ZIP archive + */ +export function zipSync(data, opts) { + if (!opts) + opts = {}; + var r = {}; + var files = []; + fltn(data, '', r, opts); + var o = 0; + var tot = 0; + for (var fn in r) { + var _a = r[fn], file = _a[0], p = _a[1]; + var compression = p.level == 0 ? 0 : 8; + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + if (s > 65535) + err(11); + var d = compression ? deflateSync(file, p) : file, l = d.length; + var c = crc(); + c.p(file); + files.push(mrg(p, { + size: file.length, + crc: c.d(), + c: d, + f: f, + m: m, + u: s != fn.length || (m && (com.length != ms)), + o: o, + compression: compression + })); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + } + var out = new u8(tot + 22), oe = o, cdl = tot - o; + for (var i = 0; i < files.length; ++i) { + var f = files[i]; + wzh(out, f.o, f, f.f, f.u, f.c.length); + var badd = 30 + f.f.length + exfl(f.extra); + out.set(f.c, f.o + badd); + wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0); + } + wzf(out, o, files.length, cdl, oe); + return out; +} +/** + * Streaming pass-through decompression for ZIP archives + */ +var UnzipPassThrough = /*#__PURE__*/ (function () { + function UnzipPassThrough() { + } + UnzipPassThrough.prototype.push = function (chunk, final) { + // same as ZipPassThrough: cast to retain Buffer ergonomics + this.ondata(null, chunk, final); + }; + UnzipPassThrough.compression = 0; + return UnzipPassThrough; +}()); +export { UnzipPassThrough }; +/** + * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for + * better performance. + */ +var UnzipInflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + function UnzipInflate() { + var _this = this; + this.i = new Inflate(function (dat, final) { + _this.ondata(null, dat, final); + }); + } + UnzipInflate.prototype.push = function (chunk, final) { + try { + this.i.push(chunk, final); + } + catch (e) { + this.ondata(e, null, final); + } + }; + UnzipInflate.compression = 8; + return UnzipInflate; +}()); +export { UnzipInflate }; +/** + * Asynchronous streaming DEFLATE decompression for ZIP archives + */ +var AsyncUnzipInflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + function AsyncUnzipInflate(_, sz) { + var _this = this; + if (sz < 320000) { + this.i = new Inflate(function (dat, final) { + _this.ondata(null, dat, final); + }); + } + else { + this.i = new AsyncInflate(function (err, dat, final) { + _this.ondata(err, dat, final); + }); + this.terminate = this.i.terminate; + } + } + AsyncUnzipInflate.prototype.push = function (chunk, final) { + if (this.i.terminate) + chunk = slc(chunk, 0); + this.i.push(chunk, final); + }; + AsyncUnzipInflate.compression = 8; + return AsyncUnzipInflate; +}()); +export { AsyncUnzipInflate }; +/** + * A ZIP archive decompression stream that emits files as they are discovered + */ +var Unzip = /*#__PURE__*/ (function () { + /** + * Creates a ZIP decompression stream + * @param cb The callback to call whenever a file in the ZIP archive is found + */ + function Unzip(cb) { + this.onfile = cb; + this.k = []; + this.o = { + 0: UnzipPassThrough + }; + this.p = et; + } + /** + * Pushes a chunk to be unzipped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Unzip.prototype.push = function (chunk, final) { + var _this = this; + if (!this.onfile) + err(5); + if (!this.p) + err(4); + if (this.c > 0) { + var len = Math.min(this.c, chunk.length); + var toAdd = chunk.subarray(0, len); + this.c -= len; + if (this.d) + this.d.push(toAdd, !this.c); + else + this.k[0].push(toAdd); + chunk = chunk.subarray(len); + if (chunk.length) + return this.push(chunk, final); + } + else { + var f = 0, i = 0, is = void 0, buf = void 0; + if (!this.p.length) + buf = chunk; + else if (!chunk.length) + buf = this.p; + else { + buf = new u8(this.p.length + chunk.length); + buf.set(this.p), buf.set(chunk, this.p.length); + } + var l = buf.length, oc = this.c, add = oc && this.d; + var _loop_2 = function () { + var sig = b4(buf, i); + if (sig == 0x4034B50) { + f = 1, is = i; + this_1.d = null; + this_1.c = 0; + var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28); + if (l > i + 30 + fnl + es) { + var chks_3 = []; + this_1.k.unshift(chks_3); + f = 2; + var lsc = b4(buf, i + 18), lsu = b4(buf, i + 22); + var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u); + var _a = z64hs(buf, i, es, 2, lsc, lsu, 0), sc_1 = _a[0], su_1 = _a[1], z64 = _a[3]; + if (dd) + sc_1 = -1 - z64; + i += es; + this_1.c = sc_1; + var d_1; + var file_1 = { + name: fn_1, + compression: cmp_1, + start: function () { + if (!file_1.ondata) + err(5); + if (!sc_1) + file_1.ondata(null, et, true); + else { + var ctr = _this.o[cmp_1]; + if (!ctr) + file_1.ondata(err(14, 'unknown compression type ' + cmp_1, 1), null, false); + d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1); + d_1.ondata = function (err, dat, final) { file_1.ondata(err, dat, final); }; + for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) { + var dat = chks_4[_i]; + d_1.push(dat, false); + } + if (_this.k[0] == chks_3 && _this.c) + _this.d = d_1; + else + d_1.push(et, true); + } + }, + terminate: function () { + if (d_1 && d_1.terminate) + d_1.terminate(); + } + }; + if (sc_1 >= 0) + file_1.size = sc_1, file_1.originalSize = su_1; + this_1.onfile(file_1); + } + return "break"; + } + else if (oc) { + if (sig == 0x8074B50) { + is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0; + return "break"; + } + else if (sig == 0x2014B50) { + is = i -= 4, f = 3, this_1.c = 0; + return "break"; + } + } + }; + var this_1 = this; + for (; i < l - 4; ++i) { + var state_1 = _loop_2(); + if (state_1 === "break") + break; + } + this.p = et; + if (oc < 0) { + var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 0x8074B50 && 4)) : buf.subarray(0, i); + if (add) + add.push(dat, !!f); + else + this.k[+(f == 2)].push(dat); + } + if (f & 2) + return this.push(buf.subarray(i), final); + this.p = buf.subarray(i); + } + if (final) { + if (this.c) + err(13); + this.p = null; + } + }; + /** + * Registers a decoder with the stream, allowing for files compressed with + * the compression type provided to be expanded correctly + * @param decoder The decoder constructor + */ + Unzip.prototype.register = function (decoder) { + this.o[decoder.compression] = decoder; + }; + return Unzip; +}()); +export { Unzip }; +var mt = typeof queueMicrotask == 'function' ? queueMicrotask : typeof setTimeout == 'function' ? setTimeout : function (fn) { fn(); }; +export function unzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + var term = []; + var tAll = function () { + for (var i = 0; i < term.length; ++i) + term[i](); + }; + var files = {}; + var cbd = function (a, b) { + mt(function () { cb(a, b); }); + }; + mt(function () { cbd = cb; }); + var e = data.length - 22; + for (; b4(data, e) != 0x6054B50; --e) { + if (!e || data.length - e > 65558) { + cbd(err(13, 0, 1), null); + return tAll; + } + } + ; + var lft = b2(data, e + 8); + if (lft) { + var c = lft; + var o = b4(data, e + 16); + var z = b4(data, e - 20) == 0x7064B50; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 0x6064B50; + if (z) { + c = lft = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + var _loop_3 = function (i) { + var _a = zh(data, o, z), c_1 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off); + o = no; + var cbl = function (e, d) { + if (e) { + tAll(); + cbd(e, null); + } + else { + if (d) + files[fn] = d; + if (!--lft) + cbd(null, files); + } + }; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_1 + })) { + if (!c_1) + cbl(null, slc(data, b, b + sc)); + else if (c_1 == 8) { + var infl = data.subarray(b, b + sc); + // Synchronously decompress under 512KB, or barely-compressed data + if (su < 524288 || sc > 0.8 * su) { + try { + cbl(null, inflateSync(infl, { out: new u8(su) })); + } + catch (e) { + cbl(e, null); + } + } + else + term.push(inflate(infl, { size: su }, cbl)); + } + else + cbl(err(14, 'unknown compression type ' + c_1, 1), null); + } + else + cbl(null, null); + }; + for (var i = 0; i < c; ++i) { + _loop_3(i); + } + } + else + cbd(null, {}); + return tAll; +} +/** + * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better + * performance with more than one file. + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @returns The decompressed files + */ +export function unzipSync(data, opts) { + var files = {}; + var e = data.length - 22; + for (; b4(data, e) != 0x6054B50; --e) { + if (!e || data.length - e > 65558) + err(13); + } + ; + var c = b2(data, e + 8); + if (!c) + return {}; + var o = b4(data, e + 16); + var z = b4(data, e - 20) == 0x7064B50; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 0x6064B50; + if (z) { + c = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + for (var i = 0; i < c; ++i) { + var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off); + o = no; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_2 + })) { + if (!c_2) + files[fn] = slc(data, b, b + sc); + else if (c_2 == 8) + files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) }); + else + err(14, 'unknown compression type ' + c_2); + } + } + return files; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.d.mts b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.d.mts new file mode 100644 index 0000000..d430faf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.d.mts @@ -0,0 +1,1539 @@ +/** + * Codes for errors generated within this library + */ +export declare const FlateErrorCode: { + readonly UnexpectedEOF: 0; + readonly InvalidBlockType: 1; + readonly InvalidLengthLiteral: 2; + readonly InvalidDistance: 3; + readonly StreamFinished: 4; + readonly NoStreamHandler: 5; + readonly InvalidHeader: 6; + readonly NoCallback: 7; + readonly InvalidUTF8: 8; + readonly ExtraFieldTooLong: 9; + readonly InvalidDate: 10; + readonly FilenameTooLong: 11; + readonly StreamFinishing: 12; + readonly InvalidZipData: 13; + readonly UnknownCompressionMethod: 14; +}; +/** + * An error generated within this library + */ +export interface FlateError extends Error { + /** + * The code associated with this error + */ + code: number; +} +/** + * Options for decompressing a DEFLATE stream + */ +export interface InflateStreamOptions { + /** + * The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect. + * + * Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error. + */ + dictionary?: Uint8Array; +} +/** + * Options for decompressing DEFLATE data + */ +export interface InflateOptions extends InflateStreamOptions { + /** + * The buffer into which to write the decompressed data. Saves memory if you know the decompressed size in advance. + * + * Note that if the decompression result is larger than the size of this buffer, it will be truncated to fit. + */ + out?: Uint8Array; +} +/** + * Options for decompressing a GZIP stream + */ +export interface GunzipStreamOptions extends InflateStreamOptions { +} +/** + * Options for decompressing GZIP data + */ +export interface GunzipOptions extends InflateStreamOptions { + /** + * The buffer into which to write the decompressed data. GZIP already encodes the output size, so providing this doesn't save memory. + * + * Note that if the decompression result is larger than the size of this buffer, it will be truncated to fit. + */ + out?: Uint8Array; +} +/** + * Options for decompressing a Zlib stream + */ +export interface UnzlibStreamOptions extends InflateStreamOptions { +} +/** + * Options for decompressing Zlib data + */ +export interface UnzlibOptions extends InflateOptions { +} +/** + * Options for compressing data into a DEFLATE format + */ +export interface DeflateOptions { + /** + * The level of compression to use, ranging from 0-9. + * + * 0 will store the data without compression. + * 1 is fastest but compresses the worst, 9 is slowest but compresses the best. + * The default level is 6. + * + * Typically, binary data benefits much more from higher values than text data. + * In both cases, higher values usually take disproportionately longer than the reduction in final size that results. + * + * For example, a 1 MB text file could: + * - become 1.01 MB with level 0 in 1ms + * - become 400 kB with level 1 in 10ms + * - become 320 kB with level 9 in 100ms + */ + level?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; + /** + * The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory. + * + * Note that this is exponential: while level 0 uses 8 kB, level 4 uses 128 kB, level 8 uses 2 MB, and level 12 uses 32 MB. + * It is recommended not to lower the value below 4, since that tends to hurt performance. + * In addition, values above 8 tend to help very little on most data and can even hurt performance. + * + * The default value is automatically determined based on the size of the input data. + */ + mem?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + /** + * A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios. + * + * Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input. + * The decompressor must supply the same dictionary as the compressor to extract the original data. + * + * Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise. + * + * Avoid using dictionaries with GZIP and ZIP to maximize software compatibility. + */ + dictionary?: Uint8Array; +} +/** + * Options for compressing data into a GZIP format + */ +export interface GzipOptions extends DeflateOptions { + /** + * When the file was last modified. Defaults to the current time. + * Set this to 0 to avoid revealing a modification date entirely. + */ + mtime?: Date | string | number; + /** + * The filename of the data. If the `gunzip` command is used to decompress the data, it will output a file + * with this name instead of the name of the compressed file. + */ + filename?: string; +} +/** + * Options for compressing data into a Zlib format + */ +export interface ZlibOptions extends DeflateOptions { +} +/** + * Handler for data (de)compression streams + * @param data The data output from the stream processor + * @param final Whether this is the final block + */ +export type FlateStreamHandler = (data: Uint8Array, final: boolean) => void; +/** + * Handler for asynchronous data (de)compression streams + * @param err Any error that occurred + * @param data The data output from the stream processor + * @param final Whether this is the final block + */ +export type AsyncFlateStreamHandler = (err: FlateError | null, data: Uint8Array, final: boolean) => void; +/** + * Handler for the asynchronous completion of (de)compression for a data chunk + * @param size The number of bytes that were processed. This is measured in terms of the input + * (i.e. compressed bytes for decompression, uncompressed bytes for compression.) + */ +export type AsyncFlateDrainHandler = (size: number) => void; +/** + * Callback for asynchronous (de)compression methods + * @param err Any error that occurred + * @param data The resulting data. Only present if `err` is null + */ +export type FlateCallback = (err: FlateError | null, data: Uint8Array) => void; +interface AsyncOptions { + /** + * Whether or not to "consume" the source data. This will make the typed array/buffer you pass in + * unusable but will increase performance and reduce memory usage. + */ + consume?: boolean; +} +/** + * Options for compressing data asynchronously into a DEFLATE format + */ +export interface AsyncDeflateOptions extends DeflateOptions, AsyncOptions { +} +/** + * Options for decompressing DEFLATE data asynchronously + */ +export interface AsyncInflateOptions extends AsyncOptions, InflateStreamOptions { + /** + * The original size of the data. Currently, the asynchronous API disallows + * writing into a buffer you provide; the best you can do is provide the + * size in bytes and be given back a new typed array. + */ + size?: number; +} +/** + * Options for compressing data asynchronously into a GZIP format + */ +export interface AsyncGzipOptions extends GzipOptions, AsyncOptions { +} +/** + * Options for decompressing GZIP data asynchronously + */ +export interface AsyncGunzipOptions extends AsyncOptions, InflateStreamOptions { +} +/** + * Options for compressing data asynchronously into a Zlib format + */ +export interface AsyncZlibOptions extends ZlibOptions, AsyncOptions { +} +/** + * Options for decompressing Zlib data asynchronously + */ +export interface AsyncUnzlibOptions extends AsyncInflateOptions { +} +/** + * A terminable compression/decompression process + */ +export interface AsyncTerminable { + /** + * Terminates the worker thread immediately. The callback will not be called. + */ + (): void; +} +/** + * Streaming DEFLATE compression + */ +export declare class Deflate { + /** + * Creates a DEFLATE stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: DeflateOptions, cb?: FlateStreamHandler); + /** + * Creates a DEFLATE stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + private b; + private s; + private o; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + private p; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE compression + */ +export declare class AsyncDeflate { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous DEFLATE stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: DeflateOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous DEFLATE stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function deflate(data: Uint8Array, opts: AsyncDeflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param cb The function to be called upon compression completion + */ +export declare function deflate(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @returns The deflated version of the data + */ +export declare function deflateSync(data: Uint8Array, opts?: DeflateOptions): Uint8Array; +/** + * Streaming DEFLATE decompression + */ +export declare class Inflate { + private s; + private o; + private p; + private d; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a DEFLATE decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: InflateStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a DEFLATE decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + private e; + private c; + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the final chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE decompression + */ +export declare class AsyncInflate { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous DEFLATE decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: InflateStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous DEFLATE decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function inflate(data: Uint8Array, opts: AsyncInflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function inflate(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands DEFLATE data with no wrapper + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function inflateSync(data: Uint8Array): Uint8Array; +/** + * Expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function inflateSync(data: Uint8Array, opts?: InflateOptions): Uint8Array; +/** + * Streaming GZIP compression + */ +export declare class Gzip { + private c; + private l; + private v; + private o; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a GZIP stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: GzipOptions, cb?: FlateStreamHandler); + /** + * Creates a GZIP stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + private p; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming GZIP compression + */ +export declare class AsyncGzip { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous GZIP stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: GzipOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous GZIP stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function gzip(data: Uint8Array, opts: AsyncGzipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with GZIP + * @param data The data to compress + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gzip(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @returns The gzipped version of the data + */ +export declare function gzipSync(data: Uint8Array, opts?: GzipOptions): Uint8Array; +/** + * Handler for new GZIP members in concatenated GZIP streams. Useful for building indices used to perform random-access reads on compressed files. + * @param offset The offset of the new member relative to the start of the stream + */ +export type GunzipMemberHandler = (offset: number) => void; +/** + * Streaming single or multi-member GZIP decompression + */ +export declare class Gunzip { + private v; + private r; + private o; + private p; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * The handler to call whenever a new GZIP member is found + */ + onmember?: GunzipMemberHandler; + /** + * Creates a GUNZIP stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: GunzipStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a GUNZIP stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming single or multi-member GZIP decompression + */ +export declare class AsyncGunzip { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * The handler to call whenever a new GZIP member is found + */ + onmember?: GunzipMemberHandler; + /** + * Creates an asynchronous GUNZIP stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: GunzipStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous GUNZIP stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands GZIP data + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gunzip(data: Uint8Array, opts: AsyncGunzipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands GZIP data + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gunzip(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands GZIP data + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function gunzipSync(data: Uint8Array): Uint8Array; +/** + * Expands GZIP data + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function gunzipSync(data: Uint8Array, opts?: GunzipOptions): Uint8Array; +/** + * Streaming Zlib compression + */ +export declare class Zlib { + private c; + private v; + private o; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a Zlib stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: ZlibOptions, cb?: FlateStreamHandler); + /** + * Creates a Zlib stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be zlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + private p; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming Zlib compression + */ +export declare class AsyncZlib { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous Zlib stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: ZlibOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous Zlib stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with Zlib + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + */ +export declare function zlib(data: Uint8Array, opts: AsyncZlibOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with Zlib + * @param data The data to compress + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zlib(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compress data with Zlib + * @param data The data to compress + * @param opts The compression options + * @returns The zlib-compressed version of the data + */ +export declare function zlibSync(data: Uint8Array, opts?: ZlibOptions): Uint8Array; +/** + * Streaming Zlib decompression + */ +export declare class Unzlib { + private v; + private p; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a Zlib decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: UnzlibStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a Zlib decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be unzlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming Zlib decompression + */ +export declare class AsyncUnzlib { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous Zlib decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: UnzlibStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous Zlib decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be decompressed from Zlib + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands Zlib data + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function unzlib(data: Uint8Array, opts: AsyncUnzlibOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands Zlib data + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function unzlib(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands Zlib data + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function unzlibSync(data: Uint8Array): Uint8Array; +/** + * Expands Zlib data + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function unzlibSync(data: Uint8Array, opts?: UnzlibOptions): Uint8Array; +export { gzip as compress, AsyncGzip as AsyncCompress }; +export { gzipSync as compressSync, Gzip as Compress }; +/** + * Streaming GZIP, Zlib, or raw DEFLATE decompression + */ +export declare class Decompress { + private G; + private I; + private Z; + private o; + private s; + private p; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is decompressed + */ + constructor(opts: InflateStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a decompression stream + * @param cb The callback to call whenever data is decompressed + */ + constructor(cb?: FlateStreamHandler); + private i; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression + */ +export declare class AsyncDecompress { + private G; + private I; + private Z; + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is decompressed + */ + constructor(opts: InflateStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous decompression stream + * @param cb The callback to call whenever data is decompressed + */ + constructor(cb?: AsyncFlateStreamHandler); + private i; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchrononously expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function decompress(data: Uint8Array, opts: AsyncInflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchrononously expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function decompress(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function decompressSync(data: Uint8Array, opts?: InflateOptions): Uint8Array; +/** + * Attributes for files added to a ZIP archive object + */ +export interface ZipAttributes { + /** + * The operating system of origin for this file. The value is defined + * by PKZIP's APPNOTE.txt, section 4.4.2.2. For example, 0 (the default) + * is MS/DOS, 3 is Unix, 19 is macOS. + */ + os?: number; + /** + * The file's attributes. These are traditionally somewhat complicated + * and platform-dependent, so using them is scarcely necessary. However, + * here is a representation of what this is, bit by bit: + * + * `TTTTugtrwxrwxrwx0000000000ADVSHR` + * + * TTTT = file type (rarely useful) + * + * u = setuid, g = setgid, t = sticky + * + * rwx = user permissions, rwx = group permissions, rwx = other permissions + * + * 0000000000 = unused + * + * A = archive, D = directory, V = volume label, S = system file, H = hidden, R = read-only + * + * If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0o644 << 16. + * Note that attributes usually only work in conjunction with the `os` setting: you must use + * `os` = 3 (Unix) if you want to set Unix permissions + */ + attrs?: number; + /** + * Extra metadata to add to the file. This field is defined by PKZIP's APPNOTE.txt, + * section 4.4.28. At most 65,535 bytes may be used in each ID. The ID must be an + * integer between 0 and 65,535, inclusive. + * + * This field is incredibly rare and almost never needed except for compliance with + * proprietary standards and software. + */ + extra?: Record; + /** + * The comment to attach to the file. This field is defined by PKZIP's APPNOTE.txt, + * section 4.4.26. The comment must be at most 65,535 bytes long UTF-8 encoded. This + * field is not read by consumer software. + */ + comment?: string; + /** + * When the file was last modified. Defaults to the current time. + */ + mtime?: GzipOptions['mtime']; +} +/** + * Options for creating a ZIP archive + */ +export interface ZipOptions extends DeflateOptions, ZipAttributes { +} +/** + * Options for expanding a ZIP archive + */ +export interface UnzipOptions { + /** + * A filter function to extract only certain files from a ZIP archive + */ + filter?: UnzipFileFilter; +} +/** + * Options for asynchronously creating a ZIP archive + */ +export interface AsyncZipOptions extends AsyncDeflateOptions, ZipAttributes { +} +/** + * Options for asynchronously expanding a ZIP archive + */ +export interface AsyncUnzipOptions extends UnzipOptions { +} +/** + * A file that can be used to create a ZIP archive + */ +export type ZippableFile = Uint8Array | Zippable | [Uint8Array | Zippable, ZipOptions]; +/** + * A file that can be used to asynchronously create a ZIP archive + */ +export type AsyncZippableFile = Uint8Array | AsyncZippable | [Uint8Array | AsyncZippable, AsyncZipOptions]; +/** + * The complete directory structure of a ZIPpable archive + */ +export interface Zippable { + [path: string]: ZippableFile; +} +/** + * The complete directory structure of an asynchronously ZIPpable archive + */ +export interface AsyncZippable { + [path: string]: AsyncZippableFile; +} +/** + * An unzipped archive. The full path of each file is used as the key, + * and the file is the value + */ +export interface Unzipped { + [path: string]: Uint8Array; +} +/** + * Handler for string generation streams + * @param data The string output from the stream processor + * @param final Whether this is the final block + */ +export type StringStreamHandler = (data: string, final: boolean) => void; +/** + * Callback for asynchronous ZIP decompression + * @param err Any error that occurred + * @param data The decompressed ZIP archive + */ +export type UnzipCallback = (err: FlateError | null, data: Unzipped) => void; +/** + * Handler for streaming ZIP decompression + * @param file The file that was found in the archive + */ +export type UnzipFileHandler = (file: UnzipFile) => void; +/** + * Streaming UTF-8 decoding + */ +export declare class DecodeUTF8 { + private p; + private t; + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is decoded + */ + constructor(cb?: StringStreamHandler); + /** + * Pushes a chunk to be decoded from UTF-8 binary + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * The handler to call whenever data is available + */ + ondata: StringStreamHandler; +} +/** + * Streaming UTF-8 encoding + */ +export declare class EncodeUTF8 { + private d; + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is encoded + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be encoded to UTF-8 + * @param chunk The string data to push + * @param final Whether this is the last chunk + */ + push(chunk: string, final?: boolean): void; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; +} +/** + * Converts a string into a Uint8Array for use with compression/decompression methods + * @param str The string to encode + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless decoding a binary string. + * @returns The string encoded in UTF-8/Latin-1 binary + */ +export declare function strToU8(str: string, latin1?: boolean): Uint8Array; +/** + * Converts a Uint8Array to a string + * @param dat The data to decode to string + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless encoding to binary string. + * @returns The original UTF-8/Latin-1 string + */ +export declare function strFromU8(dat: Uint8Array, latin1?: boolean): string; +/** + * A stream that can be used to create a file in a ZIP archive + */ +export interface ZipInputFile extends ZipAttributes { + /** + * The filename to associate with the data provided to this stream. If you + * want a file in a subdirectory, use forward slashes as a separator (e.g. + * `directory/filename.ext`). This will still work on Windows. + */ + filename: string; + /** + * The size of the file in bytes. This attribute may be invalid after + * the file is added to the ZIP archive; it must be correct only before the + * stream completes. + * + * If you don't want to have to compute this yourself, consider extending the + * ZipPassThrough class and overriding its process() method, or using one of + * ZipDeflate or AsyncZipDeflate. + */ + size: number; + /** + * A CRC of the original file contents. This attribute may be invalid after + * the file is added to the ZIP archive; it must be correct only before the + * stream completes. + * + * If you don't want to have to generate this yourself, consider extending the + * ZipPassThrough class and overriding its process() method, or using one of + * ZipDeflate or AsyncZipDeflate. + */ + crc: number; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA + */ + compression: number; + /** + * Bits 1 and 2 of the general purpose bit flag, specified in PKZIP's + * APPNOTE.txt, section 4.4.4. Should be between 0 and 3. This is unlikely + * to be necessary. + */ + flag?: number; + /** + * The handler to be called when data is added. After passing this stream to + * the ZIP file object, this handler will always be defined. To call it: + * + * `stream.ondata(error, chunk, final)` + * + * error = any error that occurred (null if there was no error) + * + * chunk = a Uint8Array of the data that was added (null if there was an + * error) + * + * final = boolean, whether this is the final chunk in the stream + */ + ondata?: AsyncFlateStreamHandler; + /** + * A method called when the stream is no longer needed, for clean-up + * purposes. This will not always be called after the stream completes, + * so you may wish to call this.terminate() after the final chunk is + * processed if you have clean-up logic. + */ + terminate?: AsyncTerminable; +} +/** + * A pass-through stream to keep data uncompressed in a ZIP archive. + */ +export declare class ZipPassThrough implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private c; + /** + * Creates a pass-through stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + */ + constructor(filename: string); + /** + * Processes a chunk and pushes to the output stream. You can override this + * method in a subclass for custom behavior, but by default this passes + * the data through. You must call this.ondata(err, chunk, final) at some + * point in this method. + * @param chunk The chunk to process + * @param final Whether this is the last chunk + */ + protected process(chunk: Uint8Array, final: boolean): void; + /** + * Pushes a chunk to be added. If you are subclassing this with a custom + * compression algorithm, note that you must push data from the source + * file only, pre-compression. + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate + * for better performance + */ +export declare class ZipDeflate implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + flag: 0 | 1 | 2 | 3; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private d; + /** + * Creates a DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + constructor(filename: string, opts?: DeflateOptions); + private process; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE compression for ZIP archives + */ +export declare class AsyncZipDeflate implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + flag: 0 | 1 | 2 | 3; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private d; + terminate: AsyncTerminable; + /** + * Creates an asynchronous DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + constructor(filename: string, opts?: DeflateOptions); + private process; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * A zippable archive to which files can incrementally be added + */ +export declare class Zip { + private u; + private d; + /** + * Creates an empty ZIP archive to which files can be added + * @param cb The callback to call whenever data for the generated ZIP archive + * is available + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Adds a file to the ZIP archive + * @param file The file stream to add + */ + add(file: ZipInputFile): void; + /** + * Ends the process of adding files and prepares to emit the final chunks. + * This *must* be called after adding all desired files for the resulting + * ZIP file to work properly. + */ + end(): void; + private e; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to add() will fail. + */ + terminate(): void; + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; +} +/** + * Asynchronously creates a ZIP file + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @param cb The callback to call with the generated ZIP archive + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zip(data: AsyncZippable, opts: AsyncZipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously creates a ZIP file + * @param data The directory structure for the ZIP archive + * @param cb The callback to call with the generated ZIP archive + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zip(data: AsyncZippable, cb: FlateCallback): AsyncTerminable; +/** + * Synchronously creates a ZIP file. Prefer using `zip` for better performance + * with more than one file. + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @returns The generated ZIP archive + */ +export declare function zipSync(data: Zippable, opts?: ZipOptions): Uint8Array; +/** + * A decoder for files in ZIP streams + */ +export interface UnzipDecoder { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * Pushes a chunk to be decompressed + * @param chunk The data in this chunk. Do not consume (detach) this buffer. + * @param final Whether this is the last chunk in the data stream + */ + push(chunk: Uint8Array, final: boolean): void; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to push() should silently fail. + */ + terminate?: AsyncTerminable; +} +/** + * A constructor for a decoder for unzip streams + */ +export interface UnzipDecoderConstructor { + /** + * Creates an instance of the decoder + * @param filename The name of the file + * @param size The compressed size of the file + * @param originalSize The original size of the file + */ + new (filename: string, size?: number, originalSize?: number): UnzipDecoder; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA + */ + compression: number; +} +/** + * Information about a file to be extracted from a ZIP archive + */ +export interface UnzipFileInfo { + /** + * The name of the file + */ + name: string; + /** + * The compressed size of the file + */ + size: number; + /** + * The original size of the file + */ + originalSize: number; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA. If the filter function returns true + * but this value is not 8, the unzip function will throw. + */ + compression: number; +} +/** + * A filter for files to be extracted during the unzipping process + * @param file The info for the current file being processed + * @returns Whether or not to extract the current file + */ +export type UnzipFileFilter = (file: UnzipFileInfo) => boolean; +/** + * Streaming file extraction from ZIP archives + */ +export interface UnzipFile { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The name of the file + */ + name: string; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA. If start() is called but there is no + * decompression stream available for this method, start() will throw. + */ + compression: number; + /** + * The compressed size of the file. Will not be present for archives created + * in a streaming fashion. + */ + size?: number; + /** + * The original size of the file. Will not be present for archives created + * in a streaming fashion. + */ + originalSize?: number; + /** + * Starts reading from the stream. Calling this function will always enable + * this stream, but ocassionally the stream will be enabled even without + * this being called. + */ + start(): void; + /** + * A method to terminate any internal workers used by the stream. ondata + * will not be called any further. + */ + terminate: AsyncTerminable; +} +/** + * Streaming pass-through decompression for ZIP archives + */ +export declare class UnzipPassThrough implements UnzipDecoder { + static compression: number; + ondata: AsyncFlateStreamHandler; + push(chunk: Uint8Array, final: boolean): void; +} +/** + * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for + * better performance. + */ +export declare class UnzipInflate implements UnzipDecoder { + static compression: number; + private i; + ondata: AsyncFlateStreamHandler; + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + constructor(); + push(chunk: Uint8Array, final: boolean): void; +} +/** + * Asynchronous streaming DEFLATE decompression for ZIP archives + */ +export declare class AsyncUnzipInflate implements UnzipDecoder { + static compression: number; + private i; + ondata: AsyncFlateStreamHandler; + terminate: AsyncTerminable; + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + constructor(_: string, sz?: number); + push(chunk: Uint8Array, final: boolean): void; +} +/** + * A ZIP archive decompression stream that emits files as they are discovered + */ +export declare class Unzip { + private d; + private c; + private p; + private k; + private o; + /** + * Creates a ZIP decompression stream + * @param cb The callback to call whenever a file in the ZIP archive is found + */ + constructor(cb?: UnzipFileHandler); + /** + * Pushes a chunk to be unzipped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Registers a decoder with the stream, allowing for files compressed with + * the compression type provided to be expanded correctly + * @param decoder The decoder constructor + */ + register(decoder: UnzipDecoderConstructor): void; + /** + * The handler to call whenever a file is discovered + */ + onfile: UnzipFileHandler; +} +/** + * Asynchronously decompresses a ZIP archive + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @param cb The callback to call with the decompressed files + * @returns A function that can be used to immediately terminate the unzipping + */ +export declare function unzip(data: Uint8Array, opts: AsyncUnzipOptions, cb: UnzipCallback): AsyncTerminable; +/** + * Asynchronously decompresses a ZIP archive + * @param data The raw compressed ZIP file + * @param cb The callback to call with the decompressed files + * @returns A function that can be used to immediately terminate the unzipping + */ +export declare function unzip(data: Uint8Array, cb: UnzipCallback): AsyncTerminable; +/** + * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better + * performance with more than one file. + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @returns The decompressed files + */ +export declare function unzipSync(data: Uint8Array, opts?: UnzipOptions): Unzipped; diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.mjs b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.mjs new file mode 100644 index 0000000..4c057ee --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.mjs @@ -0,0 +1,2710 @@ +import { createRequire } from 'module'; +var require = createRequire('/'); +// DEFLATE is a complex format; to read this code, you should probably check the RFC first: +// https://tools.ietf.org/html/rfc1951 +// You may also wish to take a look at the guide I made about this program: +// https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad +// Some of the following code is similar to that of UZIP.js: +// https://github.com/photopea/UZIP.js +// However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size. +// Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint +// is better for memory in most engines (I *think*). +var _a; +// Mediocre shim +var Worker; +var isMarkedAsUntransferable; +var workerAdd = ";var __w=require('worker_threads');__w.parentPort.on('message',function(m){onmessage({data:m})}),postMessage=function(m,t){__w.parentPort.postMessage(m,t)},close=process.exit;self=global"; +try { + (_a = require('worker_threads'), Worker = _a.Worker, isMarkedAsUntransferable = _a.isMarkedAsUntransferable); +} +catch (e) { +} +var wk = Worker ? function (c, _, msg, transfer, cb) { + var done = false; + var w = new Worker(c + workerAdd, { eval: true }) + .on('error', function (e) { return cb(e, null); }) + .on('message', function (m) { return cb(null, m); }) + .on('exit', function (c) { + if (c && !done) + cb(new Error('exited with code ' + c), null); + }); + if (isMarkedAsUntransferable) + transfer = transfer.filter(function (t) { return !isMarkedAsUntransferable(t); }); + w.postMessage(msg, transfer); + w.terminate = function () { + done = true; + return Worker.prototype.terminate.call(w); + }; + return w; +} : function (_, __, ___, ____, cb) { + setImmediate(function () { return cb(new Error('async operations unsupported - update to Node 12+ (or Node 10-11 with the --experimental-worker CLI flag)'), null); }); + var NOP = function () { }; + return { + terminate: NOP, + postMessage: NOP + }; +}; + +// aliases for shorter compressed code (most minifers don't do this) +var u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array; +// fixed length extra bits +var fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]); +// fixed distance extra bits +var fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]); +// code length index map +var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); +// get base, reverse index map from extra bits +var freb = function (eb, start) { + var b = new u16(31); + for (var i = 0; i < 31; ++i) { + b[i] = start += 1 << eb[i - 1]; + } + // numbers here are at max 18 bits + var r = new i32(b[30]); + for (var i = 1; i < 30; ++i) { + for (var j = b[i]; j < b[i + 1]; ++j) { + r[j] = ((j - b[i]) << 5) | i; + } + } + return { b: b, r: r }; +}; +var _a = freb(fleb, 2), fl = _a.b, revfl = _a.r; +// we can ignore the fact that the other numbers are wrong; they never happen anyway +fl[28] = 258, revfl[258] = 28; +var _b = freb(fdeb, 0), fd = _b.b, revfd = _b.r; +// map of value to reverse (assuming 16 bits) +var rev = new u16(32768); +for (var i = 0; i < 32768; ++i) { + // reverse table algorithm from SO + var x = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1); + x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2); + x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4); + rev[i] = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) >> 1; +} +// create huffman tree from u8 "map": index -> code length for code index +// mb (max bits) must be at most 15 +// TODO: optimize/split up? +var hMap = (function (cd, mb, r) { + var s = cd.length; + // index + var i = 0; + // u16 "map": index -> # of codes with bit length = index + var l = new u16(mb); + // length of cd must be 288 (total # of codes) + for (; i < s; ++i) { + if (cd[i]) + ++l[cd[i] - 1]; + } + // u16 "map": index -> minimum code for bit length = index + var le = new u16(mb); + for (i = 1; i < mb; ++i) { + le[i] = (le[i - 1] + l[i - 1]) << 1; + } + var co; + if (r) { + // u16 "map": index -> number of actual bits, symbol for code + co = new u16(1 << mb); + // bits to remove for reverser + var rvb = 15 - mb; + for (i = 0; i < s; ++i) { + // ignore 0 lengths + if (cd[i]) { + // num encoding both symbol and bits read + var sv = (i << 4) | cd[i]; + // free bits + var r_1 = mb - cd[i]; + // start value + var v = le[cd[i] - 1]++ << r_1; + // m is end value + for (var m = v | ((1 << r_1) - 1); v <= m; ++v) { + // every 16 bit value starting with the code yields the same result + co[rev[v] >> rvb] = sv; + } + } + } + } + else { + co = new u16(s); + for (i = 0; i < s; ++i) { + if (cd[i]) { + co[i] = rev[le[cd[i] - 1]++] >> (15 - cd[i]); + } + } + } + return co; +}); +// fixed length tree +var flt = new u8(288); +for (var i = 0; i < 144; ++i) + flt[i] = 8; +for (var i = 144; i < 256; ++i) + flt[i] = 9; +for (var i = 256; i < 280; ++i) + flt[i] = 7; +for (var i = 280; i < 288; ++i) + flt[i] = 8; +// fixed distance tree +var fdt = new u8(32); +for (var i = 0; i < 32; ++i) + fdt[i] = 5; +// fixed length map +var flm = /*#__PURE__*/ hMap(flt, 9, 0), flrm = /*#__PURE__*/ hMap(flt, 9, 1); +// fixed distance map +var fdm = /*#__PURE__*/ hMap(fdt, 5, 0), fdrm = /*#__PURE__*/ hMap(fdt, 5, 1); +// find max of array +var max = function (a) { + var m = a[0]; + for (var i = 1; i < a.length; ++i) { + if (a[i] > m) + m = a[i]; + } + return m; +}; +// read d, starting at bit p and mask with m +var bits = function (d, p, m) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m; +}; +// read d, starting at bit p continuing for at least 16 bits +var bits16 = function (d, p) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7)); +}; +// get end of byte +var shft = function (p) { return ((p + 7) / 8) | 0; }; +// typed array slice - allows garbage collector to free original reference, +// while being more compatible than .slice +var slc = function (v, s, e) { + if (s == null || s < 0) + s = 0; + if (e == null || e > v.length) + e = v.length; + // can't use .constructor in case user-supplied + return new u8(v.subarray(s, e)); +}; +/** + * Codes for errors generated within this library + */ +export var FlateErrorCode = { + UnexpectedEOF: 0, + InvalidBlockType: 1, + InvalidLengthLiteral: 2, + InvalidDistance: 3, + StreamFinished: 4, + NoStreamHandler: 5, + InvalidHeader: 6, + NoCallback: 7, + InvalidUTF8: 8, + ExtraFieldTooLong: 9, + InvalidDate: 10, + FilenameTooLong: 11, + StreamFinishing: 12, + InvalidZipData: 13, + UnknownCompressionMethod: 14 +}; +// error codes +var ec = [ + 'unexpected EOF', + 'invalid block type', + 'invalid length/literal', + 'invalid distance', + 'stream finished', + 'no stream handler', + , // determined by compression function + 'no callback', + 'invalid UTF-8 data', + 'extra field too long', + 'date not in range 1980-2099', + 'filename too long', + 'stream finishing', + 'invalid zip data' + // determined by unknown compression method +]; +; +var err = function (ind, msg, nt) { + var e = new Error(msg || ec[ind]); + e.code = ind; + if (Error.captureStackTrace) + Error.captureStackTrace(e, err); + if (!nt) + throw e; + return e; +}; +// expands raw DEFLATE data +var inflt = function (dat, st, buf, dict) { + // source length dict length + var sl = dat.length, dl = dict ? dict.length : 0; + if (!sl || st.f && !st.l) + return buf || new u8(0); + var noBuf = !buf; + // have to estimate size + var resize = noBuf || st.i != 2; + // no state + var noSt = st.i; + // Assumes roughly 33% compression ratio average + if (noBuf) + buf = new u8(sl * 3); + // ensure buffer can fit at least l elements + var cbuf = function (l) { + var bl = buf.length; + // need to increase size to fit + if (l > bl) { + // Double or set to necessary, whichever is greater + var nbuf = new u8(Math.max(bl * 2, l)); + nbuf.set(buf); + buf = nbuf; + } + }; + // last chunk bitpos bytes + var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; + // total bits + var tbts = sl * 8; + do { + if (!lm) { + // BFINAL - this is only 1 when last chunk is next + final = bits(dat, pos, 1); + // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman + var type = bits(dat, pos + 1, 3); + pos += 3; + if (!type) { + // go to end of byte boundary + var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l; + if (t > sl) { + if (noSt) + err(0); + break; + } + // ensure size + if (resize) + cbuf(bt + l); + // Copy over uncompressed data + buf.set(dat.subarray(s, t), bt); + // Get new bitpos, update byte count + st.b = bt += l, st.p = pos = t * 8, st.f = final; + continue; + } + else if (type == 1) + lm = flrm, dm = fdrm, lbt = 9, dbt = 5; + else if (type == 2) { + // literal lengths + var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; + var tl = hLit + bits(dat, pos + 5, 31) + 1; + pos += 14; + // length+distance tree + var ldt = new u8(tl); + // code length tree + var clt = new u8(19); + for (var i = 0; i < hcLen; ++i) { + // use index map to get real code + clt[clim[i]] = bits(dat, pos + i * 3, 7); + } + pos += hcLen * 3; + // code lengths bits + var clb = max(clt), clbmsk = (1 << clb) - 1; + // code lengths map + var clm = hMap(clt, clb, 1); + for (var i = 0; i < tl;) { + var r = clm[bits(dat, pos, clbmsk)]; + // bits read + pos += r & 15; + // symbol + var s = r >> 4; + // code length to copy + if (s < 16) { + ldt[i++] = s; + } + else { + // copy count + var c = 0, n = 0; + if (s == 16) + n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; + else if (s == 17) + n = 3 + bits(dat, pos, 7), pos += 3; + else if (s == 18) + n = 11 + bits(dat, pos, 127), pos += 7; + while (n--) + ldt[i++] = c; + } + } + // length tree distance tree + var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); + // max length bits + lbt = max(lt); + // max dist bits + dbt = max(dt); + lm = hMap(lt, lbt, 1); + dm = hMap(dt, dbt, 1); + } + else + err(1); + if (pos > tbts) { + if (noSt) + err(0); + break; + } + } + // Make sure the buffer can hold this + the largest possible addition + // Maximum chunk size (practically, theoretically infinite) is 2^17 + if (resize) + cbuf(bt + 131072); + var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; + var lpos = pos; + for (;; lpos = pos) { + // bits read, code + var c = lm[bits16(dat, pos) & lms], sym = c >> 4; + pos += c & 15; + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (!c) + err(2); + if (sym < 256) + buf[bt++] = sym; + else if (sym == 256) { + lpos = pos, lm = null; + break; + } + else { + var add = sym - 254; + // no extra bits needed if less + if (sym > 264) { + // index + var i = sym - 257, b = fleb[i]; + add = bits(dat, pos, (1 << b) - 1) + fl[i]; + pos += b; + } + // dist + var d = dm[bits16(dat, pos) & dms], dsym = d >> 4; + if (!d) + err(3); + pos += d & 15; + var dt = fd[dsym]; + if (dsym > 3) { + var b = fdeb[dsym]; + dt += bits16(dat, pos) & (1 << b) - 1, pos += b; + } + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (resize) + cbuf(bt + 131072); + var end = bt + add; + if (bt < dt) { + var shift = dl - dt, dend = Math.min(dt, end); + if (shift + bt < 0) + err(3); + for (; bt < dend; ++bt) + buf[bt] = dict[shift + bt]; + } + for (; bt < end; ++bt) + buf[bt] = buf[bt - dt]; + } + } + st.l = lm, st.p = lpos, st.b = bt, st.f = final; + if (lm) + final = 1, st.m = lbt, st.d = dm, st.n = dbt; + } while (!final); + // don't reallocate for streams or user buffers + return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt); +}; +// starting at p, write the minimum number of bits that can hold v to d +var wbits = function (d, p, v) { + v <<= p & 7; + var o = (p / 8) | 0; + d[o] |= v; + d[o + 1] |= v >> 8; +}; +// starting at p, write the minimum number of bits (>8) that can hold v to d +var wbits16 = function (d, p, v) { + v <<= p & 7; + var o = (p / 8) | 0; + d[o] |= v; + d[o + 1] |= v >> 8; + d[o + 2] |= v >> 16; +}; +// creates code lengths from a frequency table +var hTree = function (d, mb) { + // Need extra info to make a tree + var t = []; + for (var i = 0; i < d.length; ++i) { + if (d[i]) + t.push({ s: i, f: d[i] }); + } + var s = t.length; + var t2 = t.slice(); + if (!s) + return { t: et, l: 0 }; + if (s == 1) { + var v = new u8(t[0].s + 1); + v[t[0].s] = 1; + return { t: v, l: 1 }; + } + t.sort(function (a, b) { return a.f - b.f; }); + // after i2 reaches last ind, will be stopped + // freq must be greater than largest possible number of symbols + t.push({ s: -1, f: 25001 }); + var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2; + t[0] = { s: -1, f: l.f + r.f, l: l, r: r }; + // efficient algorithm from UZIP.js + // i0 is lookbehind, i2 is lookahead - after processing two low-freq + // symbols that combined have high freq, will start processing i2 (high-freq, + // non-composite) symbols instead + // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/ + while (i1 != s - 1) { + l = t[t[i0].f < t[i2].f ? i0++ : i2++]; + r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++]; + t[i1++] = { s: -1, f: l.f + r.f, l: l, r: r }; + } + var maxSym = t2[0].s; + for (var i = 1; i < s; ++i) { + if (t2[i].s > maxSym) + maxSym = t2[i].s; + } + // code lengths + var tr = new u16(maxSym + 1); + // max bits in tree + var mbt = ln(t[i1 - 1], tr, 0); + if (mbt > mb) { + // more algorithms from UZIP.js + // TODO: find out how this code works (debt) + // ind debt + var i = 0, dt = 0; + // left cost + var lft = mbt - mb, cst = 1 << lft; + t2.sort(function (a, b) { return tr[b.s] - tr[a.s] || a.f - b.f; }); + for (; i < s; ++i) { + var i2_1 = t2[i].s; + if (tr[i2_1] > mb) { + dt += cst - (1 << (mbt - tr[i2_1])); + tr[i2_1] = mb; + } + else + break; + } + dt >>= lft; + while (dt > 0) { + var i2_2 = t2[i].s; + if (tr[i2_2] < mb) + dt -= 1 << (mb - tr[i2_2]++ - 1); + else + ++i; + } + for (; i >= 0 && dt; --i) { + var i2_3 = t2[i].s; + if (tr[i2_3] == mb) { + --tr[i2_3]; + ++dt; + } + } + mbt = mb; + } + return { t: new u8(tr), l: mbt }; +}; +// get the max length and assign length codes +var ln = function (n, l, d) { + return n.s == -1 + ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) + : (l[n.s] = d); +}; +// length codes generation +var lc = function (c) { + var s = c.length; + // Note that the semicolon was intentional + while (s && !c[--s]) + ; + var cl = new u16(++s); + // ind num streak + var cli = 0, cln = c[0], cls = 1; + var w = function (v) { cl[cli++] = v; }; + for (var i = 1; i <= s; ++i) { + if (c[i] == cln && i != s) + ++cls; + else { + if (!cln && cls > 2) { + for (; cls > 138; cls -= 138) + w(32754); + if (cls > 2) { + w(cls > 10 ? ((cls - 11) << 5) | 28690 : ((cls - 3) << 5) | 12305); + cls = 0; + } + } + else if (cls > 3) { + w(cln), --cls; + for (; cls > 6; cls -= 6) + w(8304); + if (cls > 2) + w(((cls - 3) << 5) | 8208), cls = 0; + } + while (cls--) + w(cln); + cls = 1; + cln = c[i]; + } + } + return { c: cl.subarray(0, cli), n: s }; +}; +// calculate the length of output from tree, code lengths +var clen = function (cf, cl) { + var l = 0; + for (var i = 0; i < cl.length; ++i) + l += cf[i] * cl[i]; + return l; +}; +// writes a fixed block +// returns the new bit pos +var wfblk = function (out, pos, dat) { + // no need to write 00 as type: TypedArray defaults to 0 + var s = dat.length; + var o = shft(pos + 2); + out[o] = s & 255; + out[o + 1] = s >> 8; + out[o + 2] = out[o] ^ 255; + out[o + 3] = out[o + 1] ^ 255; + for (var i = 0; i < s; ++i) + out[o + i + 4] = dat[i]; + return (o + 4 + s) * 8; +}; +// writes a block +var wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) { + wbits(out, p++, final); + ++lf[256]; + var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l; + var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l; + var _c = lc(dlt), lclt = _c.c, nlc = _c.n; + var _d = lc(ddt), lcdt = _d.c, ndc = _d.n; + var lcfreq = new u16(19); + for (var i = 0; i < lclt.length; ++i) + ++lcfreq[lclt[i] & 31]; + for (var i = 0; i < lcdt.length; ++i) + ++lcfreq[lcdt[i] & 31]; + var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l; + var nlcc = 19; + for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc) + ; + var flen = (bl + 5) << 3; + var ftlen = clen(lf, flt) + clen(df, fdt) + eb; + var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18]; + if (bs >= 0 && flen <= ftlen && flen <= dtlen) + return wfblk(out, p, dat.subarray(bs, bs + bl)); + var lm, ll, dm, dl; + wbits(out, p, 1 + (dtlen < ftlen)), p += 2; + if (dtlen < ftlen) { + lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt; + var llm = hMap(lct, mlcb, 0); + wbits(out, p, nlc - 257); + wbits(out, p + 5, ndc - 1); + wbits(out, p + 10, nlcc - 4); + p += 14; + for (var i = 0; i < nlcc; ++i) + wbits(out, p + 3 * i, lct[clim[i]]); + p += 3 * nlcc; + var lcts = [lclt, lcdt]; + for (var it = 0; it < 2; ++it) { + var clct = lcts[it]; + for (var i = 0; i < clct.length; ++i) { + var len = clct[i] & 31; + wbits(out, p, llm[len]), p += lct[len]; + if (len > 15) + wbits(out, p, (clct[i] >> 5) & 127), p += clct[i] >> 12; + } + } + } + else { + lm = flm, ll = flt, dm = fdm, dl = fdt; + } + for (var i = 0; i < li; ++i) { + var sym = syms[i]; + if (sym > 255) { + var len = (sym >> 18) & 31; + wbits16(out, p, lm[len + 257]), p += ll[len + 257]; + if (len > 7) + wbits(out, p, (sym >> 23) & 31), p += fleb[len]; + var dst = sym & 31; + wbits16(out, p, dm[dst]), p += dl[dst]; + if (dst > 3) + wbits16(out, p, (sym >> 5) & 8191), p += fdeb[dst]; + } + else { + wbits16(out, p, lm[sym]), p += ll[sym]; + } + } + wbits16(out, p, lm[256]); + return p + ll[256]; +}; +// deflate options (nice << 13) | chain +var deo = /*#__PURE__*/ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]); +// empty +var et = /*#__PURE__*/ new u8(0); +// compresses data into a raw DEFLATE buffer +var dflt = function (dat, lvl, plvl, pre, post, st) { + var s = st.z || dat.length; + var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7000)) + post); + // writing to this writes to the output buffer + var w = o.subarray(pre, o.length - post); + var lst = st.l; + var pos = (st.r || 0) & 7; + if (lvl) { + if (pos) + w[0] = st.r >> 3; + var opt = deo[lvl - 1]; + var n = opt >> 13, c = opt & 8191; + var msk_1 = (1 << plvl) - 1; + // prev 2-byte val map curr 2-byte val map + var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1); + var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1; + var hsh = function (i) { return (dat[i] ^ (dat[i + 1] << bs1_1) ^ (dat[i + 2] << bs2_1)) & msk_1; }; + // 24576 is an arbitrary number of maximum symbols per block + // 424 buffer for last block + var syms = new i32(25000); + // length/literal freq distance freq + var lf = new u16(288), df = new u16(32); + // l/lcnt exbits index l/lind waitdx blkpos + var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0; + for (; i + 2 < s; ++i) { + // hash value + var hv = hsh(i); + // index mod 32768 previous index mod + var imod = i & 32767, pimod = head[hv]; + prev[imod] = pimod; + head[hv] = imod; + // We always should modify head and prev, but only add symbols if + // this data is not yet processed ("wait" for wait index) + if (wi <= i) { + // bytes remaining + var rem = s - i; + if ((lc_1 > 7000 || li > 24576) && (rem > 423 || !lst)) { + pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos); + li = lc_1 = eb = 0, bs = i; + for (var j = 0; j < 286; ++j) + lf[j] = 0; + for (var j = 0; j < 30; ++j) + df[j] = 0; + } + // len dist chain + var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767; + if (rem > 2 && hv == hsh(i - dif)) { + var maxn = Math.min(n, rem) - 1; + var maxd = Math.min(32767, i); + // max possible length + // not capped at dif because decompressors implement "rolling" index population + var ml = Math.min(258, rem); + while (dif <= maxd && --ch_1 && imod != pimod) { + if (dat[i + l] == dat[i + l - dif]) { + var nl = 0; + for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl) + ; + if (nl > l) { + l = nl, d = dif; + // break out early when we reach "nice" (we are satisfied enough) + if (nl > maxn) + break; + // now, find the rarest 2-byte sequence within this + // length of literals and search for that instead. + // Much faster than just using the start + var mmd = Math.min(dif, nl - 2); + var md = 0; + for (var j = 0; j < mmd; ++j) { + var ti = i - dif + j & 32767; + var pti = prev[ti]; + var cd = ti - pti & 32767; + if (cd > md) + md = cd, pimod = ti; + } + } + } + // check the previous match + imod = pimod, pimod = prev[imod]; + dif += imod - pimod & 32767; + } + } + // d will be nonzero only when a match was found + if (d) { + // store both dist and len data in one int32 + // Make sure this is recognized as a len/dist with 28th bit (2^28) + syms[li++] = 268435456 | (revfl[l] << 18) | revfd[d]; + var lin = revfl[l] & 31, din = revfd[d] & 31; + eb += fleb[lin] + fdeb[din]; + ++lf[257 + lin]; + ++df[din]; + wi = i + l; + ++lc_1; + } + else { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + } + } + for (i = Math.max(i, wi); i < s; ++i) { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos); + if (!lst) { + st.r = (pos & 7) | w[(pos / 8) | 0] << 3; + // shft(pos) now 1 less if pos & 7 != 0 + pos -= 7; + st.h = head, st.p = prev, st.i = i, st.w = wi; + } + } + else { + for (var i = st.w || 0; i < s + lst; i += 65535) { + // end + var e = i + 65535; + if (e >= s) { + // write final block + w[(pos / 8) | 0] = lst; + e = s; + } + pos = wfblk(w, pos + 1, dat.subarray(i, e)); + } + st.i = s; + } + return slc(o, 0, pre + shft(pos) + post); +}; +// CRC32 table +var crct = /*#__PURE__*/ (function () { + var t = new Int32Array(256); + for (var i = 0; i < 256; ++i) { + var c = i, k = 9; + while (--k) + c = ((c & 1) && -306674912) ^ (c >>> 1); + t[i] = c; + } + return t; +})(); +// CRC32 +var crc = function () { + var c = -1; + return { + p: function (d) { + // closures have awful performance + var cr = c; + for (var i = 0; i < d.length; ++i) + cr = crct[(cr & 255) ^ d[i]] ^ (cr >>> 8); + c = cr; + }, + d: function () { return ~c; } + }; +}; +// Adler32 +var adler = function () { + var a = 1, b = 0; + return { + p: function (d) { + // closures have awful performance + var n = a, m = b; + var l = d.length | 0; + for (var i = 0; i != l;) { + var e = Math.min(i + 2655, l); + for (; i < e; ++i) + m += n += d[i]; + n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16); + } + a = n, b = m; + }, + d: function () { + a %= 65521, b %= 65521; + return (a & 255) << 24 | (a & 0xFF00) << 8 | (b & 255) << 8 | (b >> 8); + } + }; +}; +; +// deflate with opts +var dopt = function (dat, opt, pre, post, st) { + if (!st) { + st = { l: 1 }; + if (opt.dictionary) { + var dict = opt.dictionary.subarray(-32768); + var newDat = new u8(dict.length + dat.length); + newDat.set(dict); + newDat.set(dat, dict.length); + dat = newDat; + st.w = dict.length; + } + } + return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? (st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20) : (12 + opt.mem), pre, post, st); +}; +// Walmart object spread +var mrg = function (a, b) { + var o = {}; + for (var k in a) + o[k] = a[k]; + for (var k in b) + o[k] = b[k]; + return o; +}; +// worker clone +// This is possibly the craziest part of the entire codebase, despite how simple it may seem. +// The only parameter to this function is a closure that returns an array of variables outside of the function scope. +// We're going to try to figure out the variable names used in the closure as strings because that is crucial for workerization. +// We will return an object mapping of true variable name to value (basically, the current scope as a JS object). +// The reason we can't just use the original variable names is minifiers mangling the toplevel scope. +// This took me three weeks to figure out how to do. +var wcln = function (fn, fnStr, td) { + var dt = fn(); + var st = fn.toString(); + var ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/\s+/g, '').split(','); + for (var i = 0; i < dt.length; ++i) { + var v = dt[i], k = ks[i]; + if (typeof v == 'function') { + fnStr += ';' + k + '='; + var st_1 = v.toString(); + if (v.prototype) { + // for global objects + if (st_1.indexOf('[native code]') != -1) { + var spInd = st_1.indexOf(' ', 8) + 1; + fnStr += st_1.slice(spInd, st_1.indexOf('(', spInd)); + } + else { + fnStr += st_1; + for (var t in v.prototype) + fnStr += ';' + k + '.prototype.' + t + '=' + v.prototype[t].toString(); + } + } + else + fnStr += st_1; + } + else + td[k] = v; + } + return fnStr; +}; +var ch = []; +// clone bufs +var cbfs = function (v) { + var tl = []; + for (var k in v) { + if (v[k].buffer) { + tl.push((v[k] = new v[k].constructor(v[k])).buffer); + } + } + return tl; +}; +// use a worker to execute code +var wrkr = function (fns, init, id, cb) { + if (!ch[id]) { + var fnStr = '', td_1 = {}, m = fns.length - 1; + for (var i = 0; i < m; ++i) + fnStr = wcln(fns[i], fnStr, td_1); + ch[id] = { c: wcln(fns[m], fnStr, td_1), e: td_1 }; + } + var td = mrg({}, ch[id].e); + return wk(ch[id].c + ';onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage=' + init.toString() + '}', id, td, cbfs(td), cb); +}; +// base async inflate fn +var bInflt = function () { return [u8, u16, i32, fleb, fdeb, clim, fl, fd, flrm, fdrm, rev, ec, hMap, max, bits, bits16, shft, slc, err, inflt, inflateSync, pbf, gopt]; }; +var bDflt = function () { return [u8, u16, i32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; }; +// gzip extra +var gze = function () { return [gzh, gzhl, wbytes, crc, crct]; }; +// gunzip extra +var guze = function () { return [gzs, gzl]; }; +// zlib extra +var zle = function () { return [zlh, wbytes, adler]; }; +// unzlib extra +var zule = function () { return [zls]; }; +// post buf +var pbf = function (msg) { return postMessage(msg, [msg.buffer]); }; +// get opts +var gopt = function (o) { return o && { + out: o.size && new u8(o.size), + dictionary: o.dictionary +}; }; +// async helper +var cbify = function (dat, opts, fns, init, id, cb) { + var w = wrkr(fns, init, id, function (err, dat) { + w.terminate(); + cb(err, dat); + }); + w.postMessage([dat, opts], opts.consume ? [dat.buffer] : []); + return function () { w.terminate(); }; +}; +// auto stream +var astrm = function (strm) { + strm.ondata = function (dat, final) { return postMessage([dat, final], [dat.buffer]); }; + return function (ev) { + if (ev.data[0]) { + strm.push(ev.data[0], ev.data[1]); + postMessage([ev.data[0].length]); + } + else + strm.flush(ev.data[1]); + }; +}; +// async stream attach +var astrmify = function (fns, strm, opts, init, id, flush, ext) { + var t; + var w = wrkr(fns, init, id, function (err, dat) { + if (err) + w.terminate(), strm.ondata.call(strm, err); + else if (!Array.isArray(dat)) + ext(dat); + else if (dat.length == 1) { + strm.queuedSize -= dat[0]; + if (strm.ondrain) + strm.ondrain(dat[0]); + } + else { + if (dat[1]) + w.terminate(); + strm.ondata.call(strm, err, dat[0], dat[1]); + } + }); + w.postMessage(opts); + strm.queuedSize = 0; + strm.push = function (d, f) { + if (!strm.ondata) + err(5); + if (t) + strm.ondata(err(4, 0, 1), null, !!f); + strm.queuedSize += d.length; + // can fail for cross-realm Uint8Array, but ok - only a small performance penalty + w.postMessage([d, t = f], d.buffer instanceof ArrayBuffer ? [d.buffer] : []); + }; + strm.terminate = function () { w.terminate(); }; + if (flush) { + strm.flush = function (sync) { w.postMessage([0, sync]); }; + } +}; +// read 2 bytes +var b2 = function (d, b) { return d[b] | (d[b + 1] << 8); }; +// read 4 bytes +var b4 = function (d, b) { return (d[b] | (d[b + 1] << 8) | (d[b + 2] << 16) | (d[b + 3] << 24)) >>> 0; }; +// read 8 bytes +var b8 = function (d, b) { return b4(d, b) + (b4(d, b + 4) * 4294967296); }; +// write bytes +var wbytes = function (d, b, v) { + for (; v; ++b) + d[b] = v, v >>>= 8; +}; +// gzip header +var gzh = function (c, o) { + var fn = o.filename; + c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3; // assume Unix + if (o.mtime != 0) + wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1000)); + if (fn) { + c[3] = 8; + for (var i = 0; i <= fn.length; ++i) + c[i + 10] = fn.charCodeAt(i); + } +}; +// gzip footer: -8 to -4 = CRC, -4 to -0 is length +// gzip start +var gzs = function (d) { + if (d[0] != 31 || d[1] != 139 || d[2] != 8) + err(6, 'invalid gzip data'); + var flg = d[3]; + var st = 10; + if (flg & 4) + st += (d[10] | d[11] << 8) + 2; + for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++]) + ; + return st + (flg & 2); +}; +// gzip length +var gzl = function (d) { + var l = d.length; + return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0; +}; +// gzip header length +var gzhl = function (o) { return 10 + (o.filename ? o.filename.length + 1 : 0); }; +// zlib header +var zlh = function (c, o) { + var lv = o.level, fl = lv == 0 ? 0 : lv < 6 ? 1 : lv == 9 ? 3 : 2; + c[0] = 120, c[1] = (fl << 6) | (o.dictionary && 32); + c[1] |= 31 - ((c[0] << 8) | c[1]) % 31; + if (o.dictionary) { + var h = adler(); + h.p(o.dictionary); + wbytes(c, 2, h.d()); + } +}; +// zlib start +var zls = function (d, dict) { + if ((d[0] & 15) != 8 || (d[0] >> 4) > 7 || ((d[0] << 8 | d[1]) % 31)) + err(6, 'invalid zlib data'); + if ((d[1] >> 5 & 1) == +!dict) + err(6, 'invalid zlib data: ' + (d[1] & 32 ? 'need' : 'unexpected') + ' dictionary'); + return (d[1] >> 3 & 4) + 2; +}; +function StrmOpt(opts, cb) { + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + return opts; +} +/** + * Streaming DEFLATE compression + */ +var Deflate = /*#__PURE__*/ (function () { + function Deflate(opts, cb) { + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + this.o = opts || {}; + this.s = { l: 0, i: 32768, w: 32768, z: 32768 }; + // Buffer length must always be 0 mod 32768 for index calculations to be correct when modifying head and prev + // 98304 = 32768 (lookback) + 65536 (common chunk size) + this.b = new u8(98304); + if (this.o.dictionary) { + var dict = this.o.dictionary.subarray(-32768); + this.b.set(dict, 32768 - dict.length); + this.s.i = 32768 - dict.length; + } + } + Deflate.prototype.p = function (c, f) { + this.ondata(dopt(c, this.o, 0, 0, this.s), f); + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Deflate.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (this.s.l) + err(4); + var endLen = chunk.length + this.s.z; + if (endLen > this.b.length) { + if (endLen > 2 * this.b.length - 32768) { + var newBuf = new u8(endLen & -32768); + newBuf.set(this.b.subarray(0, this.s.z)); + this.b = newBuf; + } + var split = this.b.length - this.s.z; + this.b.set(chunk.subarray(0, split), this.s.z); + this.s.z = this.b.length; + this.p(this.b, false); + this.b.set(this.b.subarray(-32768)); + this.b.set(chunk.subarray(split), 32768); + this.s.z = chunk.length - split + 32768; + this.s.i = 32766, this.s.w = 32768; + } + else { + this.b.set(chunk, this.s.z); + this.s.z += chunk.length; + } + this.s.l = final & 1; + if (this.s.z > this.s.w + 8191 || final) { + this.p(this.b, final || false); + this.s.w = this.s.i, this.s.i -= 2; + } + if (final) { + // cleanup unneeded buffers/state to reduce memory usage + this.s = this.o = {}; + this.b = et; + } + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + Deflate.prototype.flush = function (sync) { + if (!this.ondata) + err(5); + if (this.s.l) + err(4); + this.p(this.b, false); + this.s.w = this.s.i, this.s.i -= 2; + // could technically skip writing the type-0 block for (this.s.r & 7) == 0, + // but the deterministic trailer (00 00 FF FF) is useful in some situations + if (sync) { + var c = new u8(6); + c[0] = this.s.r >> 3; + // write empty, non-final type-0 block + var ep = wfblk(c, this.s.r, et); + this.s.r = 0; + this.ondata(c.subarray(0, ep >> 3), false); + } + }; + return Deflate; +}()); +export { Deflate }; +/** + * Asynchronous streaming DEFLATE compression + */ +var AsyncDeflate = /*#__PURE__*/ (function () { + function AsyncDeflate(opts, cb) { + astrmify([ + bDflt, + function () { return [astrm, Deflate]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Deflate(ev.data); + onmessage = astrm(strm); + }, 6, 1); + } + return AsyncDeflate; +}()); +export { AsyncDeflate }; +export function deflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + ], function (ev) { return pbf(deflateSync(ev.data[0], ev.data[1])); }, 0, cb); +} +/** + * Compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @returns The deflated version of the data + */ +export function deflateSync(data, opts) { + return dopt(data, opts || {}, 0, 0); +} +/** + * Streaming DEFLATE decompression + */ +var Inflate = /*#__PURE__*/ (function () { + function Inflate(opts, cb) { + // no StrmOpt here to avoid adding to workerizer + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768); + this.s = { i: 0, b: dict ? dict.length : 0 }; + this.o = new u8(32768); + this.p = new u8(0); + if (dict) + this.o.set(dict); + } + Inflate.prototype.e = function (c) { + if (!this.ondata) + err(5); + if (this.d) + err(4); + if (!this.p.length) + this.p = c; + else if (c.length) { + var n = new u8(this.p.length + c.length); + n.set(this.p), n.set(c, this.p.length), this.p = n; + } + }; + Inflate.prototype.c = function (final) { + this.s.i = +(this.d = final || false); + var bts = this.s.b; + var dt = inflt(this.p, this.s, this.o); + this.ondata(slc(dt, bts, this.s.b), this.d); + this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length; + this.p = slc(this.p, (this.s.p / 8) | 0), this.s.p &= 7; + }; + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the final chunk + */ + Inflate.prototype.push = function (chunk, final) { + this.e(chunk), this.c(final); + }; + return Inflate; +}()); +export { Inflate }; +/** + * Asynchronous streaming DEFLATE decompression + */ +var AsyncInflate = /*#__PURE__*/ (function () { + function AsyncInflate(opts, cb) { + astrmify([ + bInflt, + function () { return [astrm, Inflate]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Inflate(ev.data); + onmessage = astrm(strm); + }, 7, 0); + } + return AsyncInflate; +}()); +export { AsyncInflate }; +export function inflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt + ], function (ev) { return pbf(inflateSync(ev.data[0], gopt(ev.data[1]))); }, 1, cb); +} +export function inflateSync(data, opts) { + return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary); +} +// before you yell at me for not just using extends, my reason is that TS inheritance is hard to workerize. +/** + * Streaming GZIP compression + */ +var Gzip = /*#__PURE__*/ (function () { + function Gzip(opts, cb) { + this.c = crc(); + this.l = 0; + this.v = 1; + Deflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Gzip.prototype.push = function (chunk, final) { + this.c.p(chunk); + this.l += chunk.length; + Deflate.prototype.push.call(this, chunk, final); + }; + Gzip.prototype.p = function (c, f) { + var raw = dopt(c, this.o, this.v && gzhl(this.o), f && 8, this.s); + if (this.v) + gzh(raw, this.o), this.v = 0; + if (f) + wbytes(raw, raw.length - 8, this.c.d()), wbytes(raw, raw.length - 4, this.l); + this.ondata(raw, f); + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + Gzip.prototype.flush = function (sync) { + Deflate.prototype.flush.call(this, sync); + }; + return Gzip; +}()); +export { Gzip }; +/** + * Asynchronous streaming GZIP compression + */ +var AsyncGzip = /*#__PURE__*/ (function () { + function AsyncGzip(opts, cb) { + astrmify([ + bDflt, + gze, + function () { return [astrm, Deflate, Gzip]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Gzip(ev.data); + onmessage = astrm(strm); + }, 8, 1); + } + return AsyncGzip; +}()); +export { AsyncGzip }; +export function gzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + gze, + function () { return [gzipSync]; } + ], function (ev) { return pbf(gzipSync(ev.data[0], ev.data[1])); }, 2, cb); +} +/** + * Compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @returns The gzipped version of the data + */ +export function gzipSync(data, opts) { + if (!opts) + opts = {}; + var c = crc(), l = data.length; + c.p(data); + var d = dopt(data, opts, gzhl(opts), 8), s = d.length; + return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d; +} +/** + * Streaming single or multi-member GZIP decompression + */ +var Gunzip = /*#__PURE__*/ (function () { + function Gunzip(opts, cb) { + this.v = 1; + this.r = 0; + Inflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Gunzip.prototype.push = function (chunk, final) { + Inflate.prototype.e.call(this, chunk); + this.r += chunk.length; + if (this.v) { + var p = this.p.subarray(this.v - 1); + var s = p.length > 3 ? gzs(p) : 4; + if (s > p.length) { + if (!final) + return; + } + else if (this.v > 1 && this.onmember) { + this.onmember(this.r - p.length); + } + this.p = p.subarray(s), this.v = 0; + } + // necessary to prevent TS from using the closure value + // This allows for workerization to function correctly + Inflate.prototype.c.call(this, 0); + // process concatenated GZIP + if (this.s.f && !this.s.l) { + this.v = shft(this.s.p) + 9; + this.s = { i: 0 }; + this.o = new u8(0); + this.push(new u8(0), final); + } + else if (final) { + Inflate.prototype.c.call(this, final); + } + }; + return Gunzip; +}()); +export { Gunzip }; +/** + * Asynchronous streaming single or multi-member GZIP decompression + */ +var AsyncGunzip = /*#__PURE__*/ (function () { + function AsyncGunzip(opts, cb) { + var _this = this; + astrmify([ + bInflt, + guze, + function () { return [astrm, Inflate, Gunzip]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Gunzip(ev.data); + strm.onmember = function (offset) { return postMessage(offset); }; + onmessage = astrm(strm); + }, 9, 0, function (offset) { return _this.onmember && _this.onmember(offset); }); + } + return AsyncGunzip; +}()); +export { AsyncGunzip }; +export function gunzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt, + guze, + function () { return [gunzipSync]; } + ], function (ev) { return pbf(gunzipSync(ev.data[0], ev.data[1])); }, 3, cb); +} +export function gunzipSync(data, opts) { + var st = gzs(data); + if (st + 8 > data.length) + err(6, 'invalid gzip data'); + return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary); +} +/** + * Streaming Zlib compression + */ +var Zlib = /*#__PURE__*/ (function () { + function Zlib(opts, cb) { + this.c = adler(); + this.v = 1; + Deflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be zlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Zlib.prototype.push = function (chunk, final) { + this.c.p(chunk); + Deflate.prototype.push.call(this, chunk, final); + }; + Zlib.prototype.p = function (c, f) { + var raw = dopt(c, this.o, this.v && (this.o.dictionary ? 6 : 2), f && 4, this.s); + if (this.v) + zlh(raw, this.o), this.v = 0; + if (f) + wbytes(raw, raw.length - 4, this.c.d()); + this.ondata(raw, f); + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + Zlib.prototype.flush = function (sync) { + Deflate.prototype.flush.call(this, sync); + }; + return Zlib; +}()); +export { Zlib }; +/** + * Asynchronous streaming Zlib compression + */ +var AsyncZlib = /*#__PURE__*/ (function () { + function AsyncZlib(opts, cb) { + astrmify([ + bDflt, + zle, + function () { return [astrm, Deflate, Zlib]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Zlib(ev.data); + onmessage = astrm(strm); + }, 10, 1); + } + return AsyncZlib; +}()); +export { AsyncZlib }; +export function zlib(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + zle, + function () { return [zlibSync]; } + ], function (ev) { return pbf(zlibSync(ev.data[0], ev.data[1])); }, 4, cb); +} +/** + * Compress data with Zlib + * @param data The data to compress + * @param opts The compression options + * @returns The zlib-compressed version of the data + */ +export function zlibSync(data, opts) { + if (!opts) + opts = {}; + var a = adler(); + a.p(data); + var d = dopt(data, opts, opts.dictionary ? 6 : 2, 4); + return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d; +} +/** + * Streaming Zlib decompression + */ +var Unzlib = /*#__PURE__*/ (function () { + function Unzlib(opts, cb) { + Inflate.call(this, opts, cb); + this.v = opts && opts.dictionary ? 2 : 1; + } + /** + * Pushes a chunk to be unzlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Unzlib.prototype.push = function (chunk, final) { + Inflate.prototype.e.call(this, chunk); + if (this.v) { + if (this.p.length < 6 && !final) + return; + this.p = this.p.subarray(zls(this.p, this.v - 1)), this.v = 0; + } + if (final) { + if (this.p.length < 4) + err(6, 'invalid zlib data'); + this.p = this.p.subarray(0, -4); + } + // necessary to prevent TS from using the closure value + // This allows for workerization to function correctly + Inflate.prototype.c.call(this, final); + }; + return Unzlib; +}()); +export { Unzlib }; +/** + * Asynchronous streaming Zlib decompression + */ +var AsyncUnzlib = /*#__PURE__*/ (function () { + function AsyncUnzlib(opts, cb) { + astrmify([ + bInflt, + zule, + function () { return [astrm, Inflate, Unzlib]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Unzlib(ev.data); + onmessage = astrm(strm); + }, 11, 0); + } + return AsyncUnzlib; +}()); +export { AsyncUnzlib }; +export function unzlib(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt, + zule, + function () { return [unzlibSync]; } + ], function (ev) { return pbf(unzlibSync(ev.data[0], gopt(ev.data[1]))); }, 5, cb); +} +export function unzlibSync(data, opts) { + return inflt(data.subarray(zls(data, opts && opts.dictionary), -4), { i: 2 }, opts && opts.out, opts && opts.dictionary); +} +// Default algorithm for compression (used because having a known output size allows faster decompression) +export { gzip as compress, AsyncGzip as AsyncCompress }; +export { gzipSync as compressSync, Gzip as Compress }; +/** + * Streaming GZIP, Zlib, or raw DEFLATE decompression + */ +var Decompress = /*#__PURE__*/ (function () { + function Decompress(opts, cb) { + this.o = StrmOpt.call(this, opts, cb) || {}; + this.G = Gunzip; + this.I = Inflate; + this.Z = Unzlib; + } + // init substream + // overriden by AsyncDecompress + Decompress.prototype.i = function () { + var _this = this; + this.s.ondata = function (dat, final) { + _this.ondata(dat, final); + }; + }; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Decompress.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (!this.s) { + if (this.p && this.p.length) { + var n = new u8(this.p.length + chunk.length); + n.set(this.p), n.set(chunk, this.p.length); + } + else + this.p = chunk; + if (this.p.length > 2) { + this.s = (this.p[0] == 31 && this.p[1] == 139 && this.p[2] == 8) + ? new this.G(this.o) + : ((this.p[0] & 15) != 8 || (this.p[0] >> 4) > 7 || ((this.p[0] << 8 | this.p[1]) % 31)) + ? new this.I(this.o) + : new this.Z(this.o); + this.i(); + this.s.push(this.p, final); + this.p = null; + } + } + else + this.s.push(chunk, final); + }; + return Decompress; +}()); +export { Decompress }; +/** + * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression + */ +var AsyncDecompress = /*#__PURE__*/ (function () { + function AsyncDecompress(opts, cb) { + Decompress.call(this, opts, cb); + this.queuedSize = 0; + this.G = AsyncGunzip; + this.I = AsyncInflate; + this.Z = AsyncUnzlib; + } + AsyncDecompress.prototype.i = function () { + var _this = this; + this.s.ondata = function (err, dat, final) { + _this.ondata(err, dat, final); + }; + this.s.ondrain = function (size) { + _this.queuedSize -= size; + if (_this.ondrain) + _this.ondrain(size); + }; + }; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + AsyncDecompress.prototype.push = function (chunk, final) { + this.queuedSize += chunk.length; + Decompress.prototype.push.call(this, chunk, final); + }; + return AsyncDecompress; +}()); +export { AsyncDecompress }; +export function decompress(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return (data[0] == 31 && data[1] == 139 && data[2] == 8) + ? gunzip(data, opts, cb) + : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31)) + ? inflate(data, opts, cb) + : unzlib(data, opts, cb); +} +/** + * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export function decompressSync(data, opts) { + return (data[0] == 31 && data[1] == 139 && data[2] == 8) + ? gunzipSync(data, opts) + : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31)) + ? inflateSync(data, opts) + : unzlibSync(data, opts); +} +// flatten a directory structure +var fltn = function (d, p, t, o) { + for (var k in d) { + var val = d[k], n = p + k, op = o; + if (Array.isArray(val)) + op = mrg(o, val[1]), val = val[0]; + if (ArrayBuffer.isView(val)) + t[n] = [val, op]; + else { + t[n += '/'] = [new u8(0), op]; + fltn(val, n, t, o); + } + } +}; +// text encoder +var te = typeof TextEncoder != 'undefined' && /*#__PURE__*/ new TextEncoder(); +// text decoder +var td = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder(); +// text decoder stream +var tds = 0; +try { + td.decode(et, { stream: true }); + tds = 1; +} +catch (e) { } +// decode UTF8 +var dutf8 = function (d) { + for (var r = '', i = 0;;) { + var c = d[i++]; + var eb = (c > 127) + (c > 223) + (c > 239); + if (i + eb > d.length) + return { s: r, r: slc(d, i - 1) }; + if (!eb) + r += String.fromCharCode(c); + else if (eb == 3) { + c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)) - 65536, + r += String.fromCharCode(55296 | (c >> 10), 56320 | (c & 1023)); + } + else if (eb & 1) + r += String.fromCharCode((c & 31) << 6 | (d[i++] & 63)); + else + r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)); + } +}; +/** + * Streaming UTF-8 decoding + */ +var DecodeUTF8 = /*#__PURE__*/ (function () { + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is decoded + */ + function DecodeUTF8(cb) { + this.ondata = cb; + if (tds) + this.t = new TextDecoder(); + else + this.p = et; + } + /** + * Pushes a chunk to be decoded from UTF-8 binary + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + DecodeUTF8.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + final = !!final; + if (this.t) { + this.ondata(this.t.decode(chunk, { stream: true }), final); + if (final) { + if (this.t.decode().length) + err(8); + this.t = null; + } + return; + } + if (!this.p) + err(4); + var dat = new u8(this.p.length + chunk.length); + dat.set(this.p); + dat.set(chunk, this.p.length); + var _a = dutf8(dat), s = _a.s, r = _a.r; + if (final) { + if (r.length) + err(8); + this.p = null; + } + else + this.p = r; + this.ondata(s, final); + }; + return DecodeUTF8; +}()); +export { DecodeUTF8 }; +/** + * Streaming UTF-8 encoding + */ +var EncodeUTF8 = /*#__PURE__*/ (function () { + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is encoded + */ + function EncodeUTF8(cb) { + this.ondata = cb; + } + /** + * Pushes a chunk to be encoded to UTF-8 + * @param chunk The string data to push + * @param final Whether this is the last chunk + */ + EncodeUTF8.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (this.d) + err(4); + this.ondata(strToU8(chunk), this.d = final || false); + }; + return EncodeUTF8; +}()); +export { EncodeUTF8 }; +/** + * Converts a string into a Uint8Array for use with compression/decompression methods + * @param str The string to encode + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless decoding a binary string. + * @returns The string encoded in UTF-8/Latin-1 binary + */ +export function strToU8(str, latin1) { + if (latin1) { + var ar_1 = new u8(str.length); + for (var i = 0; i < str.length; ++i) + ar_1[i] = str.charCodeAt(i); + return ar_1; + } + if (te) + return te.encode(str); + var l = str.length; + var ar = new u8(str.length + (str.length >> 1)); + var ai = 0; + var w = function (v) { ar[ai++] = v; }; + for (var i = 0; i < l; ++i) { + if (ai + 5 > ar.length) { + var n = new u8(ai + 8 + ((l - i) << 1)); + n.set(ar); + ar = n; + } + var c = str.charCodeAt(i); + if (c < 128 || latin1) + w(c); + else if (c < 2048) + w(192 | (c >> 6)), w(128 | (c & 63)); + else if (c > 55295 && c < 57344) + c = 65536 + (c & 1023 << 10) | (str.charCodeAt(++i) & 1023), + w(240 | (c >> 18)), w(128 | ((c >> 12) & 63)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63)); + else + w(224 | (c >> 12)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63)); + } + return slc(ar, 0, ai); +} +/** + * Converts a Uint8Array to a string + * @param dat The data to decode to string + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless encoding to binary string. + * @returns The original UTF-8/Latin-1 string + */ +export function strFromU8(dat, latin1) { + if (latin1) { + var r = ''; + for (var i = 0; i < dat.length; i += 16384) + r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384)); + return r; + } + else if (td) { + return td.decode(dat); + } + else { + var _a = dutf8(dat), s = _a.s, r = _a.r; + if (r.length) + err(8); + return s; + } +} +; +// deflate bit flag +var dbf = function (l) { return l == 1 ? 3 : l < 6 ? 2 : l == 9 ? 1 : 0; }; +// skip local zip header +var slzh = function (d, b) { return b + 30 + b2(d, b + 26) + b2(d, b + 28); }; +// read zip header +var zh = function (d, b, z) { + var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl; + var _a = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a[0], su = _a[1], off = _a[2]; + return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off]; +}; +// read zip64 header sizes +var z64hs = function (d, b, l, z, sc, su, off) { + var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l; + var nf = nsc + nsu + noff; + if (z && nf) { + for (; b + 4 < e; b += 4 + b2(d, b + 2)) { + if (b2(d, b) == 1) { + return [ + nsc ? b8(d, b + 4 + 8 * nsu) : sc, + nsu ? b8(d, b + 4) : su, + noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off, + 1 + ]; + } + } + // z == 2 for unknown whether or not zip64 + if (z < 2) + err(13); + } + return [sc, su, off, 0]; +}; +// extra field length +var exfl = function (ex) { + var le = 0; + if (ex) { + for (var k in ex) { + var l = ex[k].length; + if (l > 65535) + err(9); + le += l + 4; + } + } + return le; +}; +// write zip header +var wzh = function (d, b, f, fn, u, c, ce, co) { + var fl = fn.length, ex = f.extra, col = co && co.length; + var exl = exfl(ex); + wbytes(d, b, ce != null ? 0x2014B50 : 0x4034B50), b += 4; + if (ce != null) + d[b++] = 20, d[b++] = f.os; + d[b] = 20, b += 2; // spec compliance? what's that? + d[b++] = (f.flag << 1) | (c < 0 && 8), d[b++] = u && 8; + d[b++] = f.compression & 255, d[b++] = f.compression >> 8; + var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980; + if (y < 0 || y > 119) + err(10); + wbytes(d, b, (y << 25) | ((dt.getMonth() + 1) << 21) | (dt.getDate() << 16) | (dt.getHours() << 11) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1)), b += 4; + if (c != -1) { + wbytes(d, b, f.crc); + wbytes(d, b + 4, c < 0 ? -c - 2 : c); + wbytes(d, b + 8, f.size); + } + wbytes(d, b + 12, fl); + wbytes(d, b + 14, exl), b += 16; + if (ce != null) { + wbytes(d, b, col); + wbytes(d, b + 6, f.attrs); + wbytes(d, b + 10, ce), b += 14; + } + d.set(fn, b); + b += fl; + if (exl) { + for (var k in ex) { + var exf = ex[k], l = exf.length; + wbytes(d, b, +k); + wbytes(d, b + 2, l); + d.set(exf, b + 4), b += 4 + l; + } + } + if (col) + d.set(co, b), b += col; + return b; +}; +// write zip footer (end of central directory) +var wzf = function (o, b, c, d, e) { + wbytes(o, b, 0x6054B50); // skip disk + wbytes(o, b + 8, c); + wbytes(o, b + 10, c); + wbytes(o, b + 12, d); + wbytes(o, b + 16, e); +}; +/** + * A pass-through stream to keep data uncompressed in a ZIP archive. + */ +var ZipPassThrough = /*#__PURE__*/ (function () { + /** + * Creates a pass-through stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + */ + function ZipPassThrough(filename) { + this.filename = filename; + this.c = crc(); + this.size = 0; + this.compression = 0; + } + /** + * Processes a chunk and pushes to the output stream. You can override this + * method in a subclass for custom behavior, but by default this passes + * the data through. You must call this.ondata(err, chunk, final) at some + * point in this method. + * @param chunk The chunk to process + * @param final Whether this is the last chunk + */ + ZipPassThrough.prototype.process = function (chunk, final) { + this.ondata(null, chunk, final); + }; + /** + * Pushes a chunk to be added. If you are subclassing this with a custom + * compression algorithm, note that you must push data from the source + * file only, pre-compression. + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + ZipPassThrough.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + this.c.p(chunk); + this.size += chunk.length; + if (final) + this.crc = this.c.d(); + // we shouldn't really do this cast, but properly handling ArrayBufferLike + // makes the API unergonomic with Buffer + this.process(chunk, final || false); + }; + return ZipPassThrough; +}()); +export { ZipPassThrough }; +// I don't extend because TypeScript extension adds 1kB of runtime bloat +/** + * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate + * for better performance + */ +var ZipDeflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + function ZipDeflate(filename, opts) { + var _this = this; + if (!opts) + opts = {}; + ZipPassThrough.call(this, filename); + this.d = new Deflate(opts, function (dat, final) { + _this.ondata(null, dat, final); + }); + this.compression = 8; + this.flag = dbf(opts.level); + } + ZipDeflate.prototype.process = function (chunk, final) { + try { + this.d.push(chunk, final); + } + catch (e) { + this.ondata(e, null, final); + } + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + ZipDeflate.prototype.push = function (chunk, final) { + ZipPassThrough.prototype.push.call(this, chunk, final); + }; + return ZipDeflate; +}()); +export { ZipDeflate }; +/** + * Asynchronous streaming DEFLATE compression for ZIP archives + */ +var AsyncZipDeflate = /*#__PURE__*/ (function () { + /** + * Creates an asynchronous DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + function AsyncZipDeflate(filename, opts) { + var _this = this; + if (!opts) + opts = {}; + ZipPassThrough.call(this, filename); + this.d = new AsyncDeflate(opts, function (err, dat, final) { + _this.ondata(err, dat, final); + }); + this.compression = 8; + this.flag = dbf(opts.level); + this.terminate = this.d.terminate; + } + AsyncZipDeflate.prototype.process = function (chunk, final) { + this.d.push(chunk, final); + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + AsyncZipDeflate.prototype.push = function (chunk, final) { + ZipPassThrough.prototype.push.call(this, chunk, final); + }; + return AsyncZipDeflate; +}()); +export { AsyncZipDeflate }; +// TODO: Better tree shaking +/** + * A zippable archive to which files can incrementally be added + */ +var Zip = /*#__PURE__*/ (function () { + /** + * Creates an empty ZIP archive to which files can be added + * @param cb The callback to call whenever data for the generated ZIP archive + * is available + */ + function Zip(cb) { + this.ondata = cb; + this.u = []; + this.d = 1; + } + /** + * Adds a file to the ZIP archive + * @param file The file stream to add + */ + Zip.prototype.add = function (file) { + var _this = this; + if (!this.ondata) + err(5); + // finishing or finished + if (this.d & 2) + this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, false); + else { + var f = strToU8(file.filename), fl_1 = f.length; + var com = file.comment, o = com && strToU8(com); + var u = fl_1 != file.filename.length || (o && (com.length != o.length)); + var hl_1 = fl_1 + exfl(file.extra) + 30; + if (fl_1 > 65535) + this.ondata(err(11, 0, 1), null, false); + var header = new u8(hl_1); + wzh(header, 0, file, f, u, -1); + var chks_1 = [header]; + var pAll_1 = function () { + for (var _i = 0, chks_2 = chks_1; _i < chks_2.length; _i++) { + var chk = chks_2[_i]; + _this.ondata(null, chk, false); + } + chks_1 = []; + }; + var tr_1 = this.d; + this.d = 0; + var ind_1 = this.u.length; + var uf_1 = mrg(file, { + f: f, + u: u, + o: o, + t: function () { + if (file.terminate) + file.terminate(); + }, + r: function () { + pAll_1(); + if (tr_1) { + var nxt = _this.u[ind_1 + 1]; + if (nxt) + nxt.r(); + else + _this.d = 1; + } + tr_1 = 1; + } + }); + var cl_1 = 0; + file.ondata = function (err, dat, final) { + if (err) { + _this.ondata(err, dat, final); + _this.terminate(); + } + else { + cl_1 += dat.length; + chks_1.push(dat); + if (final) { + var dd = new u8(16); + wbytes(dd, 0, 0x8074B50); + wbytes(dd, 4, file.crc); + wbytes(dd, 8, cl_1); + wbytes(dd, 12, file.size); + chks_1.push(dd); + uf_1.c = cl_1, uf_1.b = hl_1 + cl_1 + 16, uf_1.crc = file.crc, uf_1.size = file.size; + if (tr_1) + uf_1.r(); + tr_1 = 1; + } + else if (tr_1) + pAll_1(); + } + }; + this.u.push(uf_1); + } + }; + /** + * Ends the process of adding files and prepares to emit the final chunks. + * This *must* be called after adding all desired files for the resulting + * ZIP file to work properly. + */ + Zip.prototype.end = function () { + var _this = this; + if (this.d & 2) { + this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, true); + return; + } + if (this.d) + this.e(); + else + this.u.push({ + r: function () { + if (!(_this.d & 1)) + return; + _this.u.splice(-1, 1); + _this.e(); + }, + t: function () { } + }); + this.d = 3; + }; + Zip.prototype.e = function () { + var bt = 0, l = 0, tl = 0; + for (var _i = 0, _a = this.u; _i < _a.length; _i++) { + var f = _a[_i]; + tl += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0); + } + var out = new u8(tl + 22); + for (var _b = 0, _c = this.u; _b < _c.length; _b++) { + var f = _c[_b]; + wzh(out, bt, f, f.f, f.u, -f.c - 2, l, f.o); + bt += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0), l += f.b; + } + wzf(out, bt, this.u.length, tl, l); + this.ondata(null, out, true); + this.d = 2; + }; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to add() will fail. + */ + Zip.prototype.terminate = function () { + for (var _i = 0, _a = this.u; _i < _a.length; _i++) { + var f = _a[_i]; + f.t(); + } + this.d = 2; + }; + return Zip; +}()); +export { Zip }; +export function zip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + var r = {}; + fltn(data, '', r, opts); + var k = Object.keys(r); + var lft = k.length, o = 0, tot = 0; + var slft = lft, files = new Array(lft); + var term = []; + var tAll = function () { + for (var i = 0; i < term.length; ++i) + term[i](); + }; + var cbd = function (a, b) { + mt(function () { cb(a, b); }); + }; + mt(function () { cbd = cb; }); + var cbf = function () { + var out = new u8(tot + 22), oe = o, cdl = tot - o; + tot = 0; + for (var i = 0; i < slft; ++i) { + var f = files[i]; + try { + var l = f.c.length; + wzh(out, tot, f, f.f, f.u, l); + var badd = 30 + f.f.length + exfl(f.extra); + var loc = tot + badd; + out.set(f.c, loc); + wzh(out, o, f, f.f, f.u, l, tot, f.m), o += 16 + badd + (f.m ? f.m.length : 0), tot = loc + l; + } + catch (e) { + return cbd(e, null); + } + } + wzf(out, o, files.length, cdl, oe); + cbd(null, out); + }; + if (!lft) + cbf(); + var _loop_1 = function (i) { + var fn = k[i]; + var _a = r[fn], file = _a[0], p = _a[1]; + var c = crc(), size = file.length; + c.p(file); + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + var compression = p.level == 0 ? 0 : 8; + var cbl = function (e, d) { + if (e) { + tAll(); + cbd(e, null); + } + else { + var l = d.length; + files[i] = mrg(p, { + size: size, + crc: c.d(), + c: d, + f: f, + m: m, + u: s != fn.length || (m && (com.length != ms)), + compression: compression + }); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + if (!--lft) + cbf(); + } + }; + if (s > 65535) + cbl(err(11, 0, 1), null); + if (!compression) + cbl(null, file); + else if (size < 160000) { + try { + cbl(null, deflateSync(file, p)); + } + catch (e) { + cbl(e, null); + } + } + else + term.push(deflate(file, p, cbl)); + }; + // Cannot use lft because it can decrease + for (var i = 0; i < slft; ++i) { + _loop_1(i); + } + return tAll; +} +/** + * Synchronously creates a ZIP file. Prefer using `zip` for better performance + * with more than one file. + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @returns The generated ZIP archive + */ +export function zipSync(data, opts) { + if (!opts) + opts = {}; + var r = {}; + var files = []; + fltn(data, '', r, opts); + var o = 0; + var tot = 0; + for (var fn in r) { + var _a = r[fn], file = _a[0], p = _a[1]; + var compression = p.level == 0 ? 0 : 8; + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + if (s > 65535) + err(11); + var d = compression ? deflateSync(file, p) : file, l = d.length; + var c = crc(); + c.p(file); + files.push(mrg(p, { + size: file.length, + crc: c.d(), + c: d, + f: f, + m: m, + u: s != fn.length || (m && (com.length != ms)), + o: o, + compression: compression + })); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + } + var out = new u8(tot + 22), oe = o, cdl = tot - o; + for (var i = 0; i < files.length; ++i) { + var f = files[i]; + wzh(out, f.o, f, f.f, f.u, f.c.length); + var badd = 30 + f.f.length + exfl(f.extra); + out.set(f.c, f.o + badd); + wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0); + } + wzf(out, o, files.length, cdl, oe); + return out; +} +/** + * Streaming pass-through decompression for ZIP archives + */ +var UnzipPassThrough = /*#__PURE__*/ (function () { + function UnzipPassThrough() { + } + UnzipPassThrough.prototype.push = function (chunk, final) { + // same as ZipPassThrough: cast to retain Buffer ergonomics + this.ondata(null, chunk, final); + }; + UnzipPassThrough.compression = 0; + return UnzipPassThrough; +}()); +export { UnzipPassThrough }; +/** + * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for + * better performance. + */ +var UnzipInflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + function UnzipInflate() { + var _this = this; + this.i = new Inflate(function (dat, final) { + _this.ondata(null, dat, final); + }); + } + UnzipInflate.prototype.push = function (chunk, final) { + try { + this.i.push(chunk, final); + } + catch (e) { + this.ondata(e, null, final); + } + }; + UnzipInflate.compression = 8; + return UnzipInflate; +}()); +export { UnzipInflate }; +/** + * Asynchronous streaming DEFLATE decompression for ZIP archives + */ +var AsyncUnzipInflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + function AsyncUnzipInflate(_, sz) { + var _this = this; + if (sz < 320000) { + this.i = new Inflate(function (dat, final) { + _this.ondata(null, dat, final); + }); + } + else { + this.i = new AsyncInflate(function (err, dat, final) { + _this.ondata(err, dat, final); + }); + this.terminate = this.i.terminate; + } + } + AsyncUnzipInflate.prototype.push = function (chunk, final) { + if (this.i.terminate) + chunk = slc(chunk, 0); + this.i.push(chunk, final); + }; + AsyncUnzipInflate.compression = 8; + return AsyncUnzipInflate; +}()); +export { AsyncUnzipInflate }; +/** + * A ZIP archive decompression stream that emits files as they are discovered + */ +var Unzip = /*#__PURE__*/ (function () { + /** + * Creates a ZIP decompression stream + * @param cb The callback to call whenever a file in the ZIP archive is found + */ + function Unzip(cb) { + this.onfile = cb; + this.k = []; + this.o = { + 0: UnzipPassThrough + }; + this.p = et; + } + /** + * Pushes a chunk to be unzipped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Unzip.prototype.push = function (chunk, final) { + var _this = this; + if (!this.onfile) + err(5); + if (!this.p) + err(4); + if (this.c > 0) { + var len = Math.min(this.c, chunk.length); + var toAdd = chunk.subarray(0, len); + this.c -= len; + if (this.d) + this.d.push(toAdd, !this.c); + else + this.k[0].push(toAdd); + chunk = chunk.subarray(len); + if (chunk.length) + return this.push(chunk, final); + } + else { + var f = 0, i = 0, is = void 0, buf = void 0; + if (!this.p.length) + buf = chunk; + else if (!chunk.length) + buf = this.p; + else { + buf = new u8(this.p.length + chunk.length); + buf.set(this.p), buf.set(chunk, this.p.length); + } + var l = buf.length, oc = this.c, add = oc && this.d; + var _loop_2 = function () { + var sig = b4(buf, i); + if (sig == 0x4034B50) { + f = 1, is = i; + this_1.d = null; + this_1.c = 0; + var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28); + if (l > i + 30 + fnl + es) { + var chks_3 = []; + this_1.k.unshift(chks_3); + f = 2; + var lsc = b4(buf, i + 18), lsu = b4(buf, i + 22); + var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u); + var _a = z64hs(buf, i, es, 2, lsc, lsu, 0), sc_1 = _a[0], su_1 = _a[1], z64 = _a[3]; + if (dd) + sc_1 = -1 - z64; + i += es; + this_1.c = sc_1; + var d_1; + var file_1 = { + name: fn_1, + compression: cmp_1, + start: function () { + if (!file_1.ondata) + err(5); + if (!sc_1) + file_1.ondata(null, et, true); + else { + var ctr = _this.o[cmp_1]; + if (!ctr) + file_1.ondata(err(14, 'unknown compression type ' + cmp_1, 1), null, false); + d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1); + d_1.ondata = function (err, dat, final) { file_1.ondata(err, dat, final); }; + for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) { + var dat = chks_4[_i]; + d_1.push(dat, false); + } + if (_this.k[0] == chks_3 && _this.c) + _this.d = d_1; + else + d_1.push(et, true); + } + }, + terminate: function () { + if (d_1 && d_1.terminate) + d_1.terminate(); + } + }; + if (sc_1 >= 0) + file_1.size = sc_1, file_1.originalSize = su_1; + this_1.onfile(file_1); + } + return "break"; + } + else if (oc) { + if (sig == 0x8074B50) { + is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0; + return "break"; + } + else if (sig == 0x2014B50) { + is = i -= 4, f = 3, this_1.c = 0; + return "break"; + } + } + }; + var this_1 = this; + for (; i < l - 4; ++i) { + var state_1 = _loop_2(); + if (state_1 === "break") + break; + } + this.p = et; + if (oc < 0) { + var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 0x8074B50 && 4)) : buf.subarray(0, i); + if (add) + add.push(dat, !!f); + else + this.k[+(f == 2)].push(dat); + } + if (f & 2) + return this.push(buf.subarray(i), final); + this.p = buf.subarray(i); + } + if (final) { + if (this.c) + err(13); + this.p = null; + } + }; + /** + * Registers a decoder with the stream, allowing for files compressed with + * the compression type provided to be expanded correctly + * @param decoder The decoder constructor + */ + Unzip.prototype.register = function (decoder) { + this.o[decoder.compression] = decoder; + }; + return Unzip; +}()); +export { Unzip }; +var mt = typeof queueMicrotask == 'function' ? queueMicrotask : typeof setTimeout == 'function' ? setTimeout : function (fn) { fn(); }; +export function unzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + var term = []; + var tAll = function () { + for (var i = 0; i < term.length; ++i) + term[i](); + }; + var files = {}; + var cbd = function (a, b) { + mt(function () { cb(a, b); }); + }; + mt(function () { cbd = cb; }); + var e = data.length - 22; + for (; b4(data, e) != 0x6054B50; --e) { + if (!e || data.length - e > 65558) { + cbd(err(13, 0, 1), null); + return tAll; + } + } + ; + var lft = b2(data, e + 8); + if (lft) { + var c = lft; + var o = b4(data, e + 16); + var z = b4(data, e - 20) == 0x7064B50; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 0x6064B50; + if (z) { + c = lft = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + var _loop_3 = function (i) { + var _a = zh(data, o, z), c_1 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off); + o = no; + var cbl = function (e, d) { + if (e) { + tAll(); + cbd(e, null); + } + else { + if (d) + files[fn] = d; + if (!--lft) + cbd(null, files); + } + }; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_1 + })) { + if (!c_1) + cbl(null, slc(data, b, b + sc)); + else if (c_1 == 8) { + var infl = data.subarray(b, b + sc); + // Synchronously decompress under 512KB, or barely-compressed data + if (su < 524288 || sc > 0.8 * su) { + try { + cbl(null, inflateSync(infl, { out: new u8(su) })); + } + catch (e) { + cbl(e, null); + } + } + else + term.push(inflate(infl, { size: su }, cbl)); + } + else + cbl(err(14, 'unknown compression type ' + c_1, 1), null); + } + else + cbl(null, null); + }; + for (var i = 0; i < c; ++i) { + _loop_3(i); + } + } + else + cbd(null, {}); + return tAll; +} +/** + * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better + * performance with more than one file. + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @returns The decompressed files + */ +export function unzipSync(data, opts) { + var files = {}; + var e = data.length - 22; + for (; b4(data, e) != 0x6054B50; --e) { + if (!e || data.length - e > 65558) + err(13); + } + ; + var c = b2(data, e + 8); + if (!c) + return {}; + var o = b4(data, e + 16); + var z = b4(data, e - 20) == 0x7064B50; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 0x6064B50; + if (z) { + c = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + for (var i = 0; i < c; ++i) { + var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off); + o = no; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_2 + })) { + if (!c_2) + files[fn] = slc(data, b, b + sc); + else if (c_2 == 8) + files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) }); + else + err(14, 'unknown compression type ' + c_2); + } + } + return files; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/browser.cjs b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/browser.cjs new file mode 100644 index 0000000..d3427ca --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/browser.cjs @@ -0,0 +1,2717 @@ +"use strict"; +// DEFLATE is a complex format; to read this code, you should probably check the RFC first: +// https://tools.ietf.org/html/rfc1951 +// You may also wish to take a look at the guide I made about this program: +// https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad +exports.deflate = deflate; +exports.deflateSync = deflateSync; +exports.inflate = inflate; +exports.inflateSync = inflateSync; +exports.gzip = gzip; +exports.compress = gzip; +exports.gzipSync = gzipSync; +exports.compressSync = gzipSync; +exports.gunzip = gunzip; +exports.gunzipSync = gunzipSync; +exports.zlib = zlib; +exports.zlibSync = zlibSync; +exports.unzlib = unzlib; +exports.unzlibSync = unzlibSync; +exports.gzip = gzip; +exports.compress = gzip; +exports.decompress = decompress; +exports.decompressSync = decompressSync; +exports.strToU8 = strToU8; +exports.strFromU8 = strFromU8; +exports.zip = zip; +exports.zipSync = zipSync; +exports.unzip = unzip; +exports.unzipSync = unzipSync; +// Some of the following code is similar to that of UZIP.js: +// https://github.com/photopea/UZIP.js +// However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size. +// Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint +// is better for memory in most engines (I *think*). +var ch2 = {}; +var node_worker_1 = {}; +node_worker_1["default"] = (function (c, id, msg, transfer, cb) { + var w = new Worker(ch2[id] || (ch2[id] = URL.createObjectURL(new Blob([ + c + ';addEventListener("error",function(e){e=e.error;postMessage({$e$:[e.message,e.code,e.stack]})})' + ], { type: 'text/javascript' })))); + w.onmessage = function (e) { + var d = e.data, ed = d.$e$; + if (ed) { + var err = new Error(ed[0]); + err['code'] = ed[1]; + err.stack = ed[2]; + cb(err, null); + } + else + cb(null, d); + }; + w.postMessage(msg, transfer); + return w; +}); + +// aliases for shorter compressed code (most minifers don't do this) +var u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array; +// fixed length extra bits +var fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]); +// fixed distance extra bits +var fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]); +// code length index map +var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); +// get base, reverse index map from extra bits +var freb = function (eb, start) { + var b = new u16(31); + for (var i = 0; i < 31; ++i) { + b[i] = start += 1 << eb[i - 1]; + } + // numbers here are at max 18 bits + var r = new i32(b[30]); + for (var i = 1; i < 30; ++i) { + for (var j = b[i]; j < b[i + 1]; ++j) { + r[j] = ((j - b[i]) << 5) | i; + } + } + return { b: b, r: r }; +}; +var _a = freb(fleb, 2), fl = _a.b, revfl = _a.r; +// we can ignore the fact that the other numbers are wrong; they never happen anyway +fl[28] = 258, revfl[258] = 28; +var _b = freb(fdeb, 0), fd = _b.b, revfd = _b.r; +// map of value to reverse (assuming 16 bits) +var rev = new u16(32768); +for (var i = 0; i < 32768; ++i) { + // reverse table algorithm from SO + var x = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1); + x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2); + x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4); + rev[i] = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) >> 1; +} +// create huffman tree from u8 "map": index -> code length for code index +// mb (max bits) must be at most 15 +// TODO: optimize/split up? +var hMap = (function (cd, mb, r) { + var s = cd.length; + // index + var i = 0; + // u16 "map": index -> # of codes with bit length = index + var l = new u16(mb); + // length of cd must be 288 (total # of codes) + for (; i < s; ++i) { + if (cd[i]) + ++l[cd[i] - 1]; + } + // u16 "map": index -> minimum code for bit length = index + var le = new u16(mb); + for (i = 1; i < mb; ++i) { + le[i] = (le[i - 1] + l[i - 1]) << 1; + } + var co; + if (r) { + // u16 "map": index -> number of actual bits, symbol for code + co = new u16(1 << mb); + // bits to remove for reverser + var rvb = 15 - mb; + for (i = 0; i < s; ++i) { + // ignore 0 lengths + if (cd[i]) { + // num encoding both symbol and bits read + var sv = (i << 4) | cd[i]; + // free bits + var r_1 = mb - cd[i]; + // start value + var v = le[cd[i] - 1]++ << r_1; + // m is end value + for (var m = v | ((1 << r_1) - 1); v <= m; ++v) { + // every 16 bit value starting with the code yields the same result + co[rev[v] >> rvb] = sv; + } + } + } + } + else { + co = new u16(s); + for (i = 0; i < s; ++i) { + if (cd[i]) { + co[i] = rev[le[cd[i] - 1]++] >> (15 - cd[i]); + } + } + } + return co; +}); +// fixed length tree +var flt = new u8(288); +for (var i = 0; i < 144; ++i) + flt[i] = 8; +for (var i = 144; i < 256; ++i) + flt[i] = 9; +for (var i = 256; i < 280; ++i) + flt[i] = 7; +for (var i = 280; i < 288; ++i) + flt[i] = 8; +// fixed distance tree +var fdt = new u8(32); +for (var i = 0; i < 32; ++i) + fdt[i] = 5; +// fixed length map +var flm = /*#__PURE__*/ hMap(flt, 9, 0), flrm = /*#__PURE__*/ hMap(flt, 9, 1); +// fixed distance map +var fdm = /*#__PURE__*/ hMap(fdt, 5, 0), fdrm = /*#__PURE__*/ hMap(fdt, 5, 1); +// find max of array +var max = function (a) { + var m = a[0]; + for (var i = 1; i < a.length; ++i) { + if (a[i] > m) + m = a[i]; + } + return m; +}; +// read d, starting at bit p and mask with m +var bits = function (d, p, m) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m; +}; +// read d, starting at bit p continuing for at least 16 bits +var bits16 = function (d, p) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7)); +}; +// get end of byte +var shft = function (p) { return ((p + 7) / 8) | 0; }; +// typed array slice - allows garbage collector to free original reference, +// while being more compatible than .slice +var slc = function (v, s, e) { + if (s == null || s < 0) + s = 0; + if (e == null || e > v.length) + e = v.length; + // can't use .constructor in case user-supplied + return new u8(v.subarray(s, e)); +}; +/** + * Codes for errors generated within this library + */ +exports.FlateErrorCode = { + UnexpectedEOF: 0, + InvalidBlockType: 1, + InvalidLengthLiteral: 2, + InvalidDistance: 3, + StreamFinished: 4, + NoStreamHandler: 5, + InvalidHeader: 6, + NoCallback: 7, + InvalidUTF8: 8, + ExtraFieldTooLong: 9, + InvalidDate: 10, + FilenameTooLong: 11, + StreamFinishing: 12, + InvalidZipData: 13, + UnknownCompressionMethod: 14 +}; +// error codes +var ec = [ + 'unexpected EOF', + 'invalid block type', + 'invalid length/literal', + 'invalid distance', + 'stream finished', + 'no stream handler', + , // determined by compression function + 'no callback', + 'invalid UTF-8 data', + 'extra field too long', + 'date not in range 1980-2099', + 'filename too long', + 'stream finishing', + 'invalid zip data' + // determined by unknown compression method +]; +; +var err = function (ind, msg, nt) { + var e = new Error(msg || ec[ind]); + e.code = ind; + if (Error.captureStackTrace) + Error.captureStackTrace(e, err); + if (!nt) + throw e; + return e; +}; +// expands raw DEFLATE data +var inflt = function (dat, st, buf, dict) { + // source length dict length + var sl = dat.length, dl = dict ? dict.length : 0; + if (!sl || st.f && !st.l) + return buf || new u8(0); + var noBuf = !buf; + // have to estimate size + var resize = noBuf || st.i != 2; + // no state + var noSt = st.i; + // Assumes roughly 33% compression ratio average + if (noBuf) + buf = new u8(sl * 3); + // ensure buffer can fit at least l elements + var cbuf = function (l) { + var bl = buf.length; + // need to increase size to fit + if (l > bl) { + // Double or set to necessary, whichever is greater + var nbuf = new u8(Math.max(bl * 2, l)); + nbuf.set(buf); + buf = nbuf; + } + }; + // last chunk bitpos bytes + var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; + // total bits + var tbts = sl * 8; + do { + if (!lm) { + // BFINAL - this is only 1 when last chunk is next + final = bits(dat, pos, 1); + // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman + var type = bits(dat, pos + 1, 3); + pos += 3; + if (!type) { + // go to end of byte boundary + var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l; + if (t > sl) { + if (noSt) + err(0); + break; + } + // ensure size + if (resize) + cbuf(bt + l); + // Copy over uncompressed data + buf.set(dat.subarray(s, t), bt); + // Get new bitpos, update byte count + st.b = bt += l, st.p = pos = t * 8, st.f = final; + continue; + } + else if (type == 1) + lm = flrm, dm = fdrm, lbt = 9, dbt = 5; + else if (type == 2) { + // literal lengths + var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; + var tl = hLit + bits(dat, pos + 5, 31) + 1; + pos += 14; + // length+distance tree + var ldt = new u8(tl); + // code length tree + var clt = new u8(19); + for (var i = 0; i < hcLen; ++i) { + // use index map to get real code + clt[clim[i]] = bits(dat, pos + i * 3, 7); + } + pos += hcLen * 3; + // code lengths bits + var clb = max(clt), clbmsk = (1 << clb) - 1; + // code lengths map + var clm = hMap(clt, clb, 1); + for (var i = 0; i < tl;) { + var r = clm[bits(dat, pos, clbmsk)]; + // bits read + pos += r & 15; + // symbol + var s = r >> 4; + // code length to copy + if (s < 16) { + ldt[i++] = s; + } + else { + // copy count + var c = 0, n = 0; + if (s == 16) + n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; + else if (s == 17) + n = 3 + bits(dat, pos, 7), pos += 3; + else if (s == 18) + n = 11 + bits(dat, pos, 127), pos += 7; + while (n--) + ldt[i++] = c; + } + } + // length tree distance tree + var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); + // max length bits + lbt = max(lt); + // max dist bits + dbt = max(dt); + lm = hMap(lt, lbt, 1); + dm = hMap(dt, dbt, 1); + } + else + err(1); + if (pos > tbts) { + if (noSt) + err(0); + break; + } + } + // Make sure the buffer can hold this + the largest possible addition + // Maximum chunk size (practically, theoretically infinite) is 2^17 + if (resize) + cbuf(bt + 131072); + var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; + var lpos = pos; + for (;; lpos = pos) { + // bits read, code + var c = lm[bits16(dat, pos) & lms], sym = c >> 4; + pos += c & 15; + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (!c) + err(2); + if (sym < 256) + buf[bt++] = sym; + else if (sym == 256) { + lpos = pos, lm = null; + break; + } + else { + var add = sym - 254; + // no extra bits needed if less + if (sym > 264) { + // index + var i = sym - 257, b = fleb[i]; + add = bits(dat, pos, (1 << b) - 1) + fl[i]; + pos += b; + } + // dist + var d = dm[bits16(dat, pos) & dms], dsym = d >> 4; + if (!d) + err(3); + pos += d & 15; + var dt = fd[dsym]; + if (dsym > 3) { + var b = fdeb[dsym]; + dt += bits16(dat, pos) & (1 << b) - 1, pos += b; + } + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (resize) + cbuf(bt + 131072); + var end = bt + add; + if (bt < dt) { + var shift = dl - dt, dend = Math.min(dt, end); + if (shift + bt < 0) + err(3); + for (; bt < dend; ++bt) + buf[bt] = dict[shift + bt]; + } + for (; bt < end; ++bt) + buf[bt] = buf[bt - dt]; + } + } + st.l = lm, st.p = lpos, st.b = bt, st.f = final; + if (lm) + final = 1, st.m = lbt, st.d = dm, st.n = dbt; + } while (!final); + // don't reallocate for streams or user buffers + return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt); +}; +// starting at p, write the minimum number of bits that can hold v to d +var wbits = function (d, p, v) { + v <<= p & 7; + var o = (p / 8) | 0; + d[o] |= v; + d[o + 1] |= v >> 8; +}; +// starting at p, write the minimum number of bits (>8) that can hold v to d +var wbits16 = function (d, p, v) { + v <<= p & 7; + var o = (p / 8) | 0; + d[o] |= v; + d[o + 1] |= v >> 8; + d[o + 2] |= v >> 16; +}; +// creates code lengths from a frequency table +var hTree = function (d, mb) { + // Need extra info to make a tree + var t = []; + for (var i = 0; i < d.length; ++i) { + if (d[i]) + t.push({ s: i, f: d[i] }); + } + var s = t.length; + var t2 = t.slice(); + if (!s) + return { t: et, l: 0 }; + if (s == 1) { + var v = new u8(t[0].s + 1); + v[t[0].s] = 1; + return { t: v, l: 1 }; + } + t.sort(function (a, b) { return a.f - b.f; }); + // after i2 reaches last ind, will be stopped + // freq must be greater than largest possible number of symbols + t.push({ s: -1, f: 25001 }); + var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2; + t[0] = { s: -1, f: l.f + r.f, l: l, r: r }; + // efficient algorithm from UZIP.js + // i0 is lookbehind, i2 is lookahead - after processing two low-freq + // symbols that combined have high freq, will start processing i2 (high-freq, + // non-composite) symbols instead + // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/ + while (i1 != s - 1) { + l = t[t[i0].f < t[i2].f ? i0++ : i2++]; + r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++]; + t[i1++] = { s: -1, f: l.f + r.f, l: l, r: r }; + } + var maxSym = t2[0].s; + for (var i = 1; i < s; ++i) { + if (t2[i].s > maxSym) + maxSym = t2[i].s; + } + // code lengths + var tr = new u16(maxSym + 1); + // max bits in tree + var mbt = ln(t[i1 - 1], tr, 0); + if (mbt > mb) { + // more algorithms from UZIP.js + // TODO: find out how this code works (debt) + // ind debt + var i = 0, dt = 0; + // left cost + var lft = mbt - mb, cst = 1 << lft; + t2.sort(function (a, b) { return tr[b.s] - tr[a.s] || a.f - b.f; }); + for (; i < s; ++i) { + var i2_1 = t2[i].s; + if (tr[i2_1] > mb) { + dt += cst - (1 << (mbt - tr[i2_1])); + tr[i2_1] = mb; + } + else + break; + } + dt >>= lft; + while (dt > 0) { + var i2_2 = t2[i].s; + if (tr[i2_2] < mb) + dt -= 1 << (mb - tr[i2_2]++ - 1); + else + ++i; + } + for (; i >= 0 && dt; --i) { + var i2_3 = t2[i].s; + if (tr[i2_3] == mb) { + --tr[i2_3]; + ++dt; + } + } + mbt = mb; + } + return { t: new u8(tr), l: mbt }; +}; +// get the max length and assign length codes +var ln = function (n, l, d) { + return n.s == -1 + ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) + : (l[n.s] = d); +}; +// length codes generation +var lc = function (c) { + var s = c.length; + // Note that the semicolon was intentional + while (s && !c[--s]) + ; + var cl = new u16(++s); + // ind num streak + var cli = 0, cln = c[0], cls = 1; + var w = function (v) { cl[cli++] = v; }; + for (var i = 1; i <= s; ++i) { + if (c[i] == cln && i != s) + ++cls; + else { + if (!cln && cls > 2) { + for (; cls > 138; cls -= 138) + w(32754); + if (cls > 2) { + w(cls > 10 ? ((cls - 11) << 5) | 28690 : ((cls - 3) << 5) | 12305); + cls = 0; + } + } + else if (cls > 3) { + w(cln), --cls; + for (; cls > 6; cls -= 6) + w(8304); + if (cls > 2) + w(((cls - 3) << 5) | 8208), cls = 0; + } + while (cls--) + w(cln); + cls = 1; + cln = c[i]; + } + } + return { c: cl.subarray(0, cli), n: s }; +}; +// calculate the length of output from tree, code lengths +var clen = function (cf, cl) { + var l = 0; + for (var i = 0; i < cl.length; ++i) + l += cf[i] * cl[i]; + return l; +}; +// writes a fixed block +// returns the new bit pos +var wfblk = function (out, pos, dat) { + // no need to write 00 as type: TypedArray defaults to 0 + var s = dat.length; + var o = shft(pos + 2); + out[o] = s & 255; + out[o + 1] = s >> 8; + out[o + 2] = out[o] ^ 255; + out[o + 3] = out[o + 1] ^ 255; + for (var i = 0; i < s; ++i) + out[o + i + 4] = dat[i]; + return (o + 4 + s) * 8; +}; +// writes a block +var wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) { + wbits(out, p++, final); + ++lf[256]; + var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l; + var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l; + var _c = lc(dlt), lclt = _c.c, nlc = _c.n; + var _d = lc(ddt), lcdt = _d.c, ndc = _d.n; + var lcfreq = new u16(19); + for (var i = 0; i < lclt.length; ++i) + ++lcfreq[lclt[i] & 31]; + for (var i = 0; i < lcdt.length; ++i) + ++lcfreq[lcdt[i] & 31]; + var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l; + var nlcc = 19; + for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc) + ; + var flen = (bl + 5) << 3; + var ftlen = clen(lf, flt) + clen(df, fdt) + eb; + var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18]; + if (bs >= 0 && flen <= ftlen && flen <= dtlen) + return wfblk(out, p, dat.subarray(bs, bs + bl)); + var lm, ll, dm, dl; + wbits(out, p, 1 + (dtlen < ftlen)), p += 2; + if (dtlen < ftlen) { + lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt; + var llm = hMap(lct, mlcb, 0); + wbits(out, p, nlc - 257); + wbits(out, p + 5, ndc - 1); + wbits(out, p + 10, nlcc - 4); + p += 14; + for (var i = 0; i < nlcc; ++i) + wbits(out, p + 3 * i, lct[clim[i]]); + p += 3 * nlcc; + var lcts = [lclt, lcdt]; + for (var it = 0; it < 2; ++it) { + var clct = lcts[it]; + for (var i = 0; i < clct.length; ++i) { + var len = clct[i] & 31; + wbits(out, p, llm[len]), p += lct[len]; + if (len > 15) + wbits(out, p, (clct[i] >> 5) & 127), p += clct[i] >> 12; + } + } + } + else { + lm = flm, ll = flt, dm = fdm, dl = fdt; + } + for (var i = 0; i < li; ++i) { + var sym = syms[i]; + if (sym > 255) { + var len = (sym >> 18) & 31; + wbits16(out, p, lm[len + 257]), p += ll[len + 257]; + if (len > 7) + wbits(out, p, (sym >> 23) & 31), p += fleb[len]; + var dst = sym & 31; + wbits16(out, p, dm[dst]), p += dl[dst]; + if (dst > 3) + wbits16(out, p, (sym >> 5) & 8191), p += fdeb[dst]; + } + else { + wbits16(out, p, lm[sym]), p += ll[sym]; + } + } + wbits16(out, p, lm[256]); + return p + ll[256]; +}; +// deflate options (nice << 13) | chain +var deo = /*#__PURE__*/ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]); +// empty +var et = /*#__PURE__*/ new u8(0); +// compresses data into a raw DEFLATE buffer +var dflt = function (dat, lvl, plvl, pre, post, st) { + var s = st.z || dat.length; + var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7000)) + post); + // writing to this writes to the output buffer + var w = o.subarray(pre, o.length - post); + var lst = st.l; + var pos = (st.r || 0) & 7; + if (lvl) { + if (pos) + w[0] = st.r >> 3; + var opt = deo[lvl - 1]; + var n = opt >> 13, c = opt & 8191; + var msk_1 = (1 << plvl) - 1; + // prev 2-byte val map curr 2-byte val map + var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1); + var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1; + var hsh = function (i) { return (dat[i] ^ (dat[i + 1] << bs1_1) ^ (dat[i + 2] << bs2_1)) & msk_1; }; + // 24576 is an arbitrary number of maximum symbols per block + // 424 buffer for last block + var syms = new i32(25000); + // length/literal freq distance freq + var lf = new u16(288), df = new u16(32); + // l/lcnt exbits index l/lind waitdx blkpos + var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0; + for (; i + 2 < s; ++i) { + // hash value + var hv = hsh(i); + // index mod 32768 previous index mod + var imod = i & 32767, pimod = head[hv]; + prev[imod] = pimod; + head[hv] = imod; + // We always should modify head and prev, but only add symbols if + // this data is not yet processed ("wait" for wait index) + if (wi <= i) { + // bytes remaining + var rem = s - i; + if ((lc_1 > 7000 || li > 24576) && (rem > 423 || !lst)) { + pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos); + li = lc_1 = eb = 0, bs = i; + for (var j = 0; j < 286; ++j) + lf[j] = 0; + for (var j = 0; j < 30; ++j) + df[j] = 0; + } + // len dist chain + var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767; + if (rem > 2 && hv == hsh(i - dif)) { + var maxn = Math.min(n, rem) - 1; + var maxd = Math.min(32767, i); + // max possible length + // not capped at dif because decompressors implement "rolling" index population + var ml = Math.min(258, rem); + while (dif <= maxd && --ch_1 && imod != pimod) { + if (dat[i + l] == dat[i + l - dif]) { + var nl = 0; + for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl) + ; + if (nl > l) { + l = nl, d = dif; + // break out early when we reach "nice" (we are satisfied enough) + if (nl > maxn) + break; + // now, find the rarest 2-byte sequence within this + // length of literals and search for that instead. + // Much faster than just using the start + var mmd = Math.min(dif, nl - 2); + var md = 0; + for (var j = 0; j < mmd; ++j) { + var ti = i - dif + j & 32767; + var pti = prev[ti]; + var cd = ti - pti & 32767; + if (cd > md) + md = cd, pimod = ti; + } + } + } + // check the previous match + imod = pimod, pimod = prev[imod]; + dif += imod - pimod & 32767; + } + } + // d will be nonzero only when a match was found + if (d) { + // store both dist and len data in one int32 + // Make sure this is recognized as a len/dist with 28th bit (2^28) + syms[li++] = 268435456 | (revfl[l] << 18) | revfd[d]; + var lin = revfl[l] & 31, din = revfd[d] & 31; + eb += fleb[lin] + fdeb[din]; + ++lf[257 + lin]; + ++df[din]; + wi = i + l; + ++lc_1; + } + else { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + } + } + for (i = Math.max(i, wi); i < s; ++i) { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos); + if (!lst) { + st.r = (pos & 7) | w[(pos / 8) | 0] << 3; + // shft(pos) now 1 less if pos & 7 != 0 + pos -= 7; + st.h = head, st.p = prev, st.i = i, st.w = wi; + } + } + else { + for (var i = st.w || 0; i < s + lst; i += 65535) { + // end + var e = i + 65535; + if (e >= s) { + // write final block + w[(pos / 8) | 0] = lst; + e = s; + } + pos = wfblk(w, pos + 1, dat.subarray(i, e)); + } + st.i = s; + } + return slc(o, 0, pre + shft(pos) + post); +}; +// CRC32 table +var crct = /*#__PURE__*/ (function () { + var t = new Int32Array(256); + for (var i = 0; i < 256; ++i) { + var c = i, k = 9; + while (--k) + c = ((c & 1) && -306674912) ^ (c >>> 1); + t[i] = c; + } + return t; +})(); +// CRC32 +var crc = function () { + var c = -1; + return { + p: function (d) { + // closures have awful performance + var cr = c; + for (var i = 0; i < d.length; ++i) + cr = crct[(cr & 255) ^ d[i]] ^ (cr >>> 8); + c = cr; + }, + d: function () { return ~c; } + }; +}; +// Adler32 +var adler = function () { + var a = 1, b = 0; + return { + p: function (d) { + // closures have awful performance + var n = a, m = b; + var l = d.length | 0; + for (var i = 0; i != l;) { + var e = Math.min(i + 2655, l); + for (; i < e; ++i) + m += n += d[i]; + n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16); + } + a = n, b = m; + }, + d: function () { + a %= 65521, b %= 65521; + return (a & 255) << 24 | (a & 0xFF00) << 8 | (b & 255) << 8 | (b >> 8); + } + }; +}; +; +// deflate with opts +var dopt = function (dat, opt, pre, post, st) { + if (!st) { + st = { l: 1 }; + if (opt.dictionary) { + var dict = opt.dictionary.subarray(-32768); + var newDat = new u8(dict.length + dat.length); + newDat.set(dict); + newDat.set(dat, dict.length); + dat = newDat; + st.w = dict.length; + } + } + return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? (st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20) : (12 + opt.mem), pre, post, st); +}; +// Walmart object spread +var mrg = function (a, b) { + var o = {}; + for (var k in a) + o[k] = a[k]; + for (var k in b) + o[k] = b[k]; + return o; +}; +// worker clone +// This is possibly the craziest part of the entire codebase, despite how simple it may seem. +// The only parameter to this function is a closure that returns an array of variables outside of the function scope. +// We're going to try to figure out the variable names used in the closure as strings because that is crucial for workerization. +// We will return an object mapping of true variable name to value (basically, the current scope as a JS object). +// The reason we can't just use the original variable names is minifiers mangling the toplevel scope. +// This took me three weeks to figure out how to do. +var wcln = function (fn, fnStr, td) { + var dt = fn(); + var st = fn.toString(); + var ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/\s+/g, '').split(','); + for (var i = 0; i < dt.length; ++i) { + var v = dt[i], k = ks[i]; + if (typeof v == 'function') { + fnStr += ';' + k + '='; + var st_1 = v.toString(); + if (v.prototype) { + // for global objects + if (st_1.indexOf('[native code]') != -1) { + var spInd = st_1.indexOf(' ', 8) + 1; + fnStr += st_1.slice(spInd, st_1.indexOf('(', spInd)); + } + else { + fnStr += st_1; + for (var t in v.prototype) + fnStr += ';' + k + '.prototype.' + t + '=' + v.prototype[t].toString(); + } + } + else + fnStr += st_1; + } + else + td[k] = v; + } + return fnStr; +}; +var ch = []; +// clone bufs +var cbfs = function (v) { + var tl = []; + for (var k in v) { + if (v[k].buffer) { + tl.push((v[k] = new v[k].constructor(v[k])).buffer); + } + } + return tl; +}; +// use a worker to execute code +var wrkr = function (fns, init, id, cb) { + if (!ch[id]) { + var fnStr = '', td_1 = {}, m = fns.length - 1; + for (var i = 0; i < m; ++i) + fnStr = wcln(fns[i], fnStr, td_1); + ch[id] = { c: wcln(fns[m], fnStr, td_1), e: td_1 }; + } + var td = mrg({}, ch[id].e); + return (0, node_worker_1.default)(ch[id].c + ';onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage=' + init.toString() + '}', id, td, cbfs(td), cb); +}; +// base async inflate fn +var bInflt = function () { return [u8, u16, i32, fleb, fdeb, clim, fl, fd, flrm, fdrm, rev, ec, hMap, max, bits, bits16, shft, slc, err, inflt, inflateSync, pbf, gopt]; }; +var bDflt = function () { return [u8, u16, i32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; }; +// gzip extra +var gze = function () { return [gzh, gzhl, wbytes, crc, crct]; }; +// gunzip extra +var guze = function () { return [gzs, gzl]; }; +// zlib extra +var zle = function () { return [zlh, wbytes, adler]; }; +// unzlib extra +var zule = function () { return [zls]; }; +// post buf +var pbf = function (msg) { return postMessage(msg, [msg.buffer]); }; +// get opts +var gopt = function (o) { return o && { + out: o.size && new u8(o.size), + dictionary: o.dictionary +}; }; +// async helper +var cbify = function (dat, opts, fns, init, id, cb) { + var w = wrkr(fns, init, id, function (err, dat) { + w.terminate(); + cb(err, dat); + }); + w.postMessage([dat, opts], opts.consume ? [dat.buffer] : []); + return function () { w.terminate(); }; +}; +// auto stream +var astrm = function (strm) { + strm.ondata = function (dat, final) { return postMessage([dat, final], [dat.buffer]); }; + return function (ev) { + if (ev.data[0]) { + strm.push(ev.data[0], ev.data[1]); + postMessage([ev.data[0].length]); + } + else + strm.flush(ev.data[1]); + }; +}; +// async stream attach +var astrmify = function (fns, strm, opts, init, id, flush, ext) { + var t; + var w = wrkr(fns, init, id, function (err, dat) { + if (err) + w.terminate(), strm.ondata.call(strm, err); + else if (!Array.isArray(dat)) + ext(dat); + else if (dat.length == 1) { + strm.queuedSize -= dat[0]; + if (strm.ondrain) + strm.ondrain(dat[0]); + } + else { + if (dat[1]) + w.terminate(); + strm.ondata.call(strm, err, dat[0], dat[1]); + } + }); + w.postMessage(opts); + strm.queuedSize = 0; + strm.push = function (d, f) { + if (!strm.ondata) + err(5); + if (t) + strm.ondata(err(4, 0, 1), null, !!f); + strm.queuedSize += d.length; + // can fail for cross-realm Uint8Array, but ok - only a small performance penalty + w.postMessage([d, t = f], d.buffer instanceof ArrayBuffer ? [d.buffer] : []); + }; + strm.terminate = function () { w.terminate(); }; + if (flush) { + strm.flush = function (sync) { w.postMessage([0, sync]); }; + } +}; +// read 2 bytes +var b2 = function (d, b) { return d[b] | (d[b + 1] << 8); }; +// read 4 bytes +var b4 = function (d, b) { return (d[b] | (d[b + 1] << 8) | (d[b + 2] << 16) | (d[b + 3] << 24)) >>> 0; }; +// read 8 bytes +var b8 = function (d, b) { return b4(d, b) + (b4(d, b + 4) * 4294967296); }; +// write bytes +var wbytes = function (d, b, v) { + for (; v; ++b) + d[b] = v, v >>>= 8; +}; +// gzip header +var gzh = function (c, o) { + var fn = o.filename; + c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3; // assume Unix + if (o.mtime != 0) + wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1000)); + if (fn) { + c[3] = 8; + for (var i = 0; i <= fn.length; ++i) + c[i + 10] = fn.charCodeAt(i); + } +}; +// gzip footer: -8 to -4 = CRC, -4 to -0 is length +// gzip start +var gzs = function (d) { + if (d[0] != 31 || d[1] != 139 || d[2] != 8) + err(6, 'invalid gzip data'); + var flg = d[3]; + var st = 10; + if (flg & 4) + st += (d[10] | d[11] << 8) + 2; + for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++]) + ; + return st + (flg & 2); +}; +// gzip length +var gzl = function (d) { + var l = d.length; + return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0; +}; +// gzip header length +var gzhl = function (o) { return 10 + (o.filename ? o.filename.length + 1 : 0); }; +// zlib header +var zlh = function (c, o) { + var lv = o.level, fl = lv == 0 ? 0 : lv < 6 ? 1 : lv == 9 ? 3 : 2; + c[0] = 120, c[1] = (fl << 6) | (o.dictionary && 32); + c[1] |= 31 - ((c[0] << 8) | c[1]) % 31; + if (o.dictionary) { + var h = adler(); + h.p(o.dictionary); + wbytes(c, 2, h.d()); + } +}; +// zlib start +var zls = function (d, dict) { + if ((d[0] & 15) != 8 || (d[0] >> 4) > 7 || ((d[0] << 8 | d[1]) % 31)) + err(6, 'invalid zlib data'); + if ((d[1] >> 5 & 1) == +!dict) + err(6, 'invalid zlib data: ' + (d[1] & 32 ? 'need' : 'unexpected') + ' dictionary'); + return (d[1] >> 3 & 4) + 2; +}; +function StrmOpt(opts, cb) { + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + return opts; +} +/** + * Streaming DEFLATE compression + */ +var Deflate = /*#__PURE__*/ (function () { + function Deflate(opts, cb) { + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + this.o = opts || {}; + this.s = { l: 0, i: 32768, w: 32768, z: 32768 }; + // Buffer length must always be 0 mod 32768 for index calculations to be correct when modifying head and prev + // 98304 = 32768 (lookback) + 65536 (common chunk size) + this.b = new u8(98304); + if (this.o.dictionary) { + var dict = this.o.dictionary.subarray(-32768); + this.b.set(dict, 32768 - dict.length); + this.s.i = 32768 - dict.length; + } + } + Deflate.prototype.p = function (c, f) { + this.ondata(dopt(c, this.o, 0, 0, this.s), f); + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Deflate.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (this.s.l) + err(4); + var endLen = chunk.length + this.s.z; + if (endLen > this.b.length) { + if (endLen > 2 * this.b.length - 32768) { + var newBuf = new u8(endLen & -32768); + newBuf.set(this.b.subarray(0, this.s.z)); + this.b = newBuf; + } + var split = this.b.length - this.s.z; + this.b.set(chunk.subarray(0, split), this.s.z); + this.s.z = this.b.length; + this.p(this.b, false); + this.b.set(this.b.subarray(-32768)); + this.b.set(chunk.subarray(split), 32768); + this.s.z = chunk.length - split + 32768; + this.s.i = 32766, this.s.w = 32768; + } + else { + this.b.set(chunk, this.s.z); + this.s.z += chunk.length; + } + this.s.l = final & 1; + if (this.s.z > this.s.w + 8191 || final) { + this.p(this.b, final || false); + this.s.w = this.s.i, this.s.i -= 2; + } + if (final) { + // cleanup unneeded buffers/state to reduce memory usage + this.s = this.o = {}; + this.b = et; + } + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + Deflate.prototype.flush = function (sync) { + if (!this.ondata) + err(5); + if (this.s.l) + err(4); + this.p(this.b, false); + this.s.w = this.s.i, this.s.i -= 2; + // could technically skip writing the type-0 block for (this.s.r & 7) == 0, + // but the deterministic trailer (00 00 FF FF) is useful in some situations + if (sync) { + var c = new u8(6); + c[0] = this.s.r >> 3; + // write empty, non-final type-0 block + var ep = wfblk(c, this.s.r, et); + this.s.r = 0; + this.ondata(c.subarray(0, ep >> 3), false); + } + }; + return Deflate; +}()); +exports.Deflate = Deflate; +/** + * Asynchronous streaming DEFLATE compression + */ +var AsyncDeflate = /*#__PURE__*/ (function () { + function AsyncDeflate(opts, cb) { + astrmify([ + bDflt, + function () { return [astrm, Deflate]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Deflate(ev.data); + onmessage = astrm(strm); + }, 6, 1); + } + return AsyncDeflate; +}()); +exports.AsyncDeflate = AsyncDeflate; +function deflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + ], function (ev) { return pbf(deflateSync(ev.data[0], ev.data[1])); }, 0, cb); +} +/** + * Compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @returns The deflated version of the data + */ +function deflateSync(data, opts) { + return dopt(data, opts || {}, 0, 0); +} +/** + * Streaming DEFLATE decompression + */ +var Inflate = /*#__PURE__*/ (function () { + function Inflate(opts, cb) { + // no StrmOpt here to avoid adding to workerizer + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768); + this.s = { i: 0, b: dict ? dict.length : 0 }; + this.o = new u8(32768); + this.p = new u8(0); + if (dict) + this.o.set(dict); + } + Inflate.prototype.e = function (c) { + if (!this.ondata) + err(5); + if (this.d) + err(4); + if (!this.p.length) + this.p = c; + else if (c.length) { + var n = new u8(this.p.length + c.length); + n.set(this.p), n.set(c, this.p.length), this.p = n; + } + }; + Inflate.prototype.c = function (final) { + this.s.i = +(this.d = final || false); + var bts = this.s.b; + var dt = inflt(this.p, this.s, this.o); + this.ondata(slc(dt, bts, this.s.b), this.d); + this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length; + this.p = slc(this.p, (this.s.p / 8) | 0), this.s.p &= 7; + }; + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the final chunk + */ + Inflate.prototype.push = function (chunk, final) { + this.e(chunk), this.c(final); + }; + return Inflate; +}()); +exports.Inflate = Inflate; +/** + * Asynchronous streaming DEFLATE decompression + */ +var AsyncInflate = /*#__PURE__*/ (function () { + function AsyncInflate(opts, cb) { + astrmify([ + bInflt, + function () { return [astrm, Inflate]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Inflate(ev.data); + onmessage = astrm(strm); + }, 7, 0); + } + return AsyncInflate; +}()); +exports.AsyncInflate = AsyncInflate; +function inflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt + ], function (ev) { return pbf(inflateSync(ev.data[0], gopt(ev.data[1]))); }, 1, cb); +} +function inflateSync(data, opts) { + return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary); +} +// before you yell at me for not just using extends, my reason is that TS inheritance is hard to workerize. +/** + * Streaming GZIP compression + */ +var Gzip = /*#__PURE__*/ (function () { + function Gzip(opts, cb) { + this.c = crc(); + this.l = 0; + this.v = 1; + Deflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Gzip.prototype.push = function (chunk, final) { + this.c.p(chunk); + this.l += chunk.length; + Deflate.prototype.push.call(this, chunk, final); + }; + Gzip.prototype.p = function (c, f) { + var raw = dopt(c, this.o, this.v && gzhl(this.o), f && 8, this.s); + if (this.v) + gzh(raw, this.o), this.v = 0; + if (f) + wbytes(raw, raw.length - 8, this.c.d()), wbytes(raw, raw.length - 4, this.l); + this.ondata(raw, f); + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + Gzip.prototype.flush = function (sync) { + Deflate.prototype.flush.call(this, sync); + }; + return Gzip; +}()); +exports.Gzip = Gzip; +exports.Compress = Gzip; +/** + * Asynchronous streaming GZIP compression + */ +var AsyncGzip = /*#__PURE__*/ (function () { + function AsyncGzip(opts, cb) { + astrmify([ + bDflt, + gze, + function () { return [astrm, Deflate, Gzip]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Gzip(ev.data); + onmessage = astrm(strm); + }, 8, 1); + } + return AsyncGzip; +}()); +exports.AsyncGzip = AsyncGzip; +exports.AsyncCompress = AsyncGzip; +function gzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + gze, + function () { return [gzipSync]; } + ], function (ev) { return pbf(gzipSync(ev.data[0], ev.data[1])); }, 2, cb); +} +/** + * Compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @returns The gzipped version of the data + */ +function gzipSync(data, opts) { + if (!opts) + opts = {}; + var c = crc(), l = data.length; + c.p(data); + var d = dopt(data, opts, gzhl(opts), 8), s = d.length; + return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d; +} +/** + * Streaming single or multi-member GZIP decompression + */ +var Gunzip = /*#__PURE__*/ (function () { + function Gunzip(opts, cb) { + this.v = 1; + this.r = 0; + Inflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Gunzip.prototype.push = function (chunk, final) { + Inflate.prototype.e.call(this, chunk); + this.r += chunk.length; + if (this.v) { + var p = this.p.subarray(this.v - 1); + var s = p.length > 3 ? gzs(p) : 4; + if (s > p.length) { + if (!final) + return; + } + else if (this.v > 1 && this.onmember) { + this.onmember(this.r - p.length); + } + this.p = p.subarray(s), this.v = 0; + } + // necessary to prevent TS from using the closure value + // This allows for workerization to function correctly + Inflate.prototype.c.call(this, 0); + // process concatenated GZIP + if (this.s.f && !this.s.l) { + this.v = shft(this.s.p) + 9; + this.s = { i: 0 }; + this.o = new u8(0); + this.push(new u8(0), final); + } + else if (final) { + Inflate.prototype.c.call(this, final); + } + }; + return Gunzip; +}()); +exports.Gunzip = Gunzip; +/** + * Asynchronous streaming single or multi-member GZIP decompression + */ +var AsyncGunzip = /*#__PURE__*/ (function () { + function AsyncGunzip(opts, cb) { + var _this = this; + astrmify([ + bInflt, + guze, + function () { return [astrm, Inflate, Gunzip]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Gunzip(ev.data); + strm.onmember = function (offset) { return postMessage(offset); }; + onmessage = astrm(strm); + }, 9, 0, function (offset) { return _this.onmember && _this.onmember(offset); }); + } + return AsyncGunzip; +}()); +exports.AsyncGunzip = AsyncGunzip; +function gunzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt, + guze, + function () { return [gunzipSync]; } + ], function (ev) { return pbf(gunzipSync(ev.data[0], ev.data[1])); }, 3, cb); +} +function gunzipSync(data, opts) { + var st = gzs(data); + if (st + 8 > data.length) + err(6, 'invalid gzip data'); + return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary); +} +/** + * Streaming Zlib compression + */ +var Zlib = /*#__PURE__*/ (function () { + function Zlib(opts, cb) { + this.c = adler(); + this.v = 1; + Deflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be zlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Zlib.prototype.push = function (chunk, final) { + this.c.p(chunk); + Deflate.prototype.push.call(this, chunk, final); + }; + Zlib.prototype.p = function (c, f) { + var raw = dopt(c, this.o, this.v && (this.o.dictionary ? 6 : 2), f && 4, this.s); + if (this.v) + zlh(raw, this.o), this.v = 0; + if (f) + wbytes(raw, raw.length - 4, this.c.d()); + this.ondata(raw, f); + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + Zlib.prototype.flush = function (sync) { + Deflate.prototype.flush.call(this, sync); + }; + return Zlib; +}()); +exports.Zlib = Zlib; +/** + * Asynchronous streaming Zlib compression + */ +var AsyncZlib = /*#__PURE__*/ (function () { + function AsyncZlib(opts, cb) { + astrmify([ + bDflt, + zle, + function () { return [astrm, Deflate, Zlib]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Zlib(ev.data); + onmessage = astrm(strm); + }, 10, 1); + } + return AsyncZlib; +}()); +exports.AsyncZlib = AsyncZlib; +function zlib(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + zle, + function () { return [zlibSync]; } + ], function (ev) { return pbf(zlibSync(ev.data[0], ev.data[1])); }, 4, cb); +} +/** + * Compress data with Zlib + * @param data The data to compress + * @param opts The compression options + * @returns The zlib-compressed version of the data + */ +function zlibSync(data, opts) { + if (!opts) + opts = {}; + var a = adler(); + a.p(data); + var d = dopt(data, opts, opts.dictionary ? 6 : 2, 4); + return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d; +} +/** + * Streaming Zlib decompression + */ +var Unzlib = /*#__PURE__*/ (function () { + function Unzlib(opts, cb) { + Inflate.call(this, opts, cb); + this.v = opts && opts.dictionary ? 2 : 1; + } + /** + * Pushes a chunk to be unzlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Unzlib.prototype.push = function (chunk, final) { + Inflate.prototype.e.call(this, chunk); + if (this.v) { + if (this.p.length < 6 && !final) + return; + this.p = this.p.subarray(zls(this.p, this.v - 1)), this.v = 0; + } + if (final) { + if (this.p.length < 4) + err(6, 'invalid zlib data'); + this.p = this.p.subarray(0, -4); + } + // necessary to prevent TS from using the closure value + // This allows for workerization to function correctly + Inflate.prototype.c.call(this, final); + }; + return Unzlib; +}()); +exports.Unzlib = Unzlib; +/** + * Asynchronous streaming Zlib decompression + */ +var AsyncUnzlib = /*#__PURE__*/ (function () { + function AsyncUnzlib(opts, cb) { + astrmify([ + bInflt, + zule, + function () { return [astrm, Inflate, Unzlib]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Unzlib(ev.data); + onmessage = astrm(strm); + }, 11, 0); + } + return AsyncUnzlib; +}()); +exports.AsyncUnzlib = AsyncUnzlib; +function unzlib(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt, + zule, + function () { return [unzlibSync]; } + ], function (ev) { return pbf(unzlibSync(ev.data[0], gopt(ev.data[1]))); }, 5, cb); +} +function unzlibSync(data, opts) { + return inflt(data.subarray(zls(data, opts && opts.dictionary), -4), { i: 2 }, opts && opts.out, opts && opts.dictionary); +} +/** + * Streaming GZIP, Zlib, or raw DEFLATE decompression + */ +var Decompress = /*#__PURE__*/ (function () { + function Decompress(opts, cb) { + this.o = StrmOpt.call(this, opts, cb) || {}; + this.G = Gunzip; + this.I = Inflate; + this.Z = Unzlib; + } + // init substream + // overriden by AsyncDecompress + Decompress.prototype.i = function () { + var _this = this; + this.s.ondata = function (dat, final) { + _this.ondata(dat, final); + }; + }; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Decompress.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (!this.s) { + if (this.p && this.p.length) { + var n = new u8(this.p.length + chunk.length); + n.set(this.p), n.set(chunk, this.p.length); + } + else + this.p = chunk; + if (this.p.length > 2) { + this.s = (this.p[0] == 31 && this.p[1] == 139 && this.p[2] == 8) + ? new this.G(this.o) + : ((this.p[0] & 15) != 8 || (this.p[0] >> 4) > 7 || ((this.p[0] << 8 | this.p[1]) % 31)) + ? new this.I(this.o) + : new this.Z(this.o); + this.i(); + this.s.push(this.p, final); + this.p = null; + } + } + else + this.s.push(chunk, final); + }; + return Decompress; +}()); +exports.Decompress = Decompress; +/** + * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression + */ +var AsyncDecompress = /*#__PURE__*/ (function () { + function AsyncDecompress(opts, cb) { + Decompress.call(this, opts, cb); + this.queuedSize = 0; + this.G = AsyncGunzip; + this.I = AsyncInflate; + this.Z = AsyncUnzlib; + } + AsyncDecompress.prototype.i = function () { + var _this = this; + this.s.ondata = function (err, dat, final) { + _this.ondata(err, dat, final); + }; + this.s.ondrain = function (size) { + _this.queuedSize -= size; + if (_this.ondrain) + _this.ondrain(size); + }; + }; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + AsyncDecompress.prototype.push = function (chunk, final) { + this.queuedSize += chunk.length; + Decompress.prototype.push.call(this, chunk, final); + }; + return AsyncDecompress; +}()); +exports.AsyncDecompress = AsyncDecompress; +function decompress(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return (data[0] == 31 && data[1] == 139 && data[2] == 8) + ? gunzip(data, opts, cb) + : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31)) + ? inflate(data, opts, cb) + : unzlib(data, opts, cb); +} +/** + * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +function decompressSync(data, opts) { + return (data[0] == 31 && data[1] == 139 && data[2] == 8) + ? gunzipSync(data, opts) + : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31)) + ? inflateSync(data, opts) + : unzlibSync(data, opts); +} +// flatten a directory structure +var fltn = function (d, p, t, o) { + for (var k in d) { + var val = d[k], n = p + k, op = o; + if (Array.isArray(val)) + op = mrg(o, val[1]), val = val[0]; + if (ArrayBuffer.isView(val)) + t[n] = [val, op]; + else { + t[n += '/'] = [new u8(0), op]; + fltn(val, n, t, o); + } + } +}; +// text encoder +var te = typeof TextEncoder != 'undefined' && /*#__PURE__*/ new TextEncoder(); +// text decoder +var td = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder(); +// text decoder stream +var tds = 0; +try { + td.decode(et, { stream: true }); + tds = 1; +} +catch (e) { } +// decode UTF8 +var dutf8 = function (d) { + for (var r = '', i = 0;;) { + var c = d[i++]; + var eb = (c > 127) + (c > 223) + (c > 239); + if (i + eb > d.length) + return { s: r, r: slc(d, i - 1) }; + if (!eb) + r += String.fromCharCode(c); + else if (eb == 3) { + c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)) - 65536, + r += String.fromCharCode(55296 | (c >> 10), 56320 | (c & 1023)); + } + else if (eb & 1) + r += String.fromCharCode((c & 31) << 6 | (d[i++] & 63)); + else + r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)); + } +}; +/** + * Streaming UTF-8 decoding + */ +var DecodeUTF8 = /*#__PURE__*/ (function () { + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is decoded + */ + function DecodeUTF8(cb) { + this.ondata = cb; + if (tds) + this.t = new TextDecoder(); + else + this.p = et; + } + /** + * Pushes a chunk to be decoded from UTF-8 binary + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + DecodeUTF8.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + final = !!final; + if (this.t) { + this.ondata(this.t.decode(chunk, { stream: true }), final); + if (final) { + if (this.t.decode().length) + err(8); + this.t = null; + } + return; + } + if (!this.p) + err(4); + var dat = new u8(this.p.length + chunk.length); + dat.set(this.p); + dat.set(chunk, this.p.length); + var _a = dutf8(dat), s = _a.s, r = _a.r; + if (final) { + if (r.length) + err(8); + this.p = null; + } + else + this.p = r; + this.ondata(s, final); + }; + return DecodeUTF8; +}()); +exports.DecodeUTF8 = DecodeUTF8; +/** + * Streaming UTF-8 encoding + */ +var EncodeUTF8 = /*#__PURE__*/ (function () { + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is encoded + */ + function EncodeUTF8(cb) { + this.ondata = cb; + } + /** + * Pushes a chunk to be encoded to UTF-8 + * @param chunk The string data to push + * @param final Whether this is the last chunk + */ + EncodeUTF8.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (this.d) + err(4); + this.ondata(strToU8(chunk), this.d = final || false); + }; + return EncodeUTF8; +}()); +exports.EncodeUTF8 = EncodeUTF8; +/** + * Converts a string into a Uint8Array for use with compression/decompression methods + * @param str The string to encode + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless decoding a binary string. + * @returns The string encoded in UTF-8/Latin-1 binary + */ +function strToU8(str, latin1) { + if (latin1) { + var ar_1 = new u8(str.length); + for (var i = 0; i < str.length; ++i) + ar_1[i] = str.charCodeAt(i); + return ar_1; + } + if (te) + return te.encode(str); + var l = str.length; + var ar = new u8(str.length + (str.length >> 1)); + var ai = 0; + var w = function (v) { ar[ai++] = v; }; + for (var i = 0; i < l; ++i) { + if (ai + 5 > ar.length) { + var n = new u8(ai + 8 + ((l - i) << 1)); + n.set(ar); + ar = n; + } + var c = str.charCodeAt(i); + if (c < 128 || latin1) + w(c); + else if (c < 2048) + w(192 | (c >> 6)), w(128 | (c & 63)); + else if (c > 55295 && c < 57344) + c = 65536 + (c & 1023 << 10) | (str.charCodeAt(++i) & 1023), + w(240 | (c >> 18)), w(128 | ((c >> 12) & 63)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63)); + else + w(224 | (c >> 12)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63)); + } + return slc(ar, 0, ai); +} +/** + * Converts a Uint8Array to a string + * @param dat The data to decode to string + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless encoding to binary string. + * @returns The original UTF-8/Latin-1 string + */ +function strFromU8(dat, latin1) { + if (latin1) { + var r = ''; + for (var i = 0; i < dat.length; i += 16384) + r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384)); + return r; + } + else if (td) { + return td.decode(dat); + } + else { + var _a = dutf8(dat), s = _a.s, r = _a.r; + if (r.length) + err(8); + return s; + } +} +; +// deflate bit flag +var dbf = function (l) { return l == 1 ? 3 : l < 6 ? 2 : l == 9 ? 1 : 0; }; +// skip local zip header +var slzh = function (d, b) { return b + 30 + b2(d, b + 26) + b2(d, b + 28); }; +// read zip header +var zh = function (d, b, z) { + var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl; + var _a = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a[0], su = _a[1], off = _a[2]; + return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off]; +}; +// read zip64 header sizes +var z64hs = function (d, b, l, z, sc, su, off) { + var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l; + var nf = nsc + nsu + noff; + if (z && nf) { + for (; b + 4 < e; b += 4 + b2(d, b + 2)) { + if (b2(d, b) == 1) { + return [ + nsc ? b8(d, b + 4 + 8 * nsu) : sc, + nsu ? b8(d, b + 4) : su, + noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off, + 1 + ]; + } + } + // z == 2 for unknown whether or not zip64 + if (z < 2) + err(13); + } + return [sc, su, off, 0]; +}; +// extra field length +var exfl = function (ex) { + var le = 0; + if (ex) { + for (var k in ex) { + var l = ex[k].length; + if (l > 65535) + err(9); + le += l + 4; + } + } + return le; +}; +// write zip header +var wzh = function (d, b, f, fn, u, c, ce, co) { + var fl = fn.length, ex = f.extra, col = co && co.length; + var exl = exfl(ex); + wbytes(d, b, ce != null ? 0x2014B50 : 0x4034B50), b += 4; + if (ce != null) + d[b++] = 20, d[b++] = f.os; + d[b] = 20, b += 2; // spec compliance? what's that? + d[b++] = (f.flag << 1) | (c < 0 && 8), d[b++] = u && 8; + d[b++] = f.compression & 255, d[b++] = f.compression >> 8; + var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980; + if (y < 0 || y > 119) + err(10); + wbytes(d, b, (y << 25) | ((dt.getMonth() + 1) << 21) | (dt.getDate() << 16) | (dt.getHours() << 11) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1)), b += 4; + if (c != -1) { + wbytes(d, b, f.crc); + wbytes(d, b + 4, c < 0 ? -c - 2 : c); + wbytes(d, b + 8, f.size); + } + wbytes(d, b + 12, fl); + wbytes(d, b + 14, exl), b += 16; + if (ce != null) { + wbytes(d, b, col); + wbytes(d, b + 6, f.attrs); + wbytes(d, b + 10, ce), b += 14; + } + d.set(fn, b); + b += fl; + if (exl) { + for (var k in ex) { + var exf = ex[k], l = exf.length; + wbytes(d, b, +k); + wbytes(d, b + 2, l); + d.set(exf, b + 4), b += 4 + l; + } + } + if (col) + d.set(co, b), b += col; + return b; +}; +// write zip footer (end of central directory) +var wzf = function (o, b, c, d, e) { + wbytes(o, b, 0x6054B50); // skip disk + wbytes(o, b + 8, c); + wbytes(o, b + 10, c); + wbytes(o, b + 12, d); + wbytes(o, b + 16, e); +}; +/** + * A pass-through stream to keep data uncompressed in a ZIP archive. + */ +var ZipPassThrough = /*#__PURE__*/ (function () { + /** + * Creates a pass-through stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + */ + function ZipPassThrough(filename) { + this.filename = filename; + this.c = crc(); + this.size = 0; + this.compression = 0; + } + /** + * Processes a chunk and pushes to the output stream. You can override this + * method in a subclass for custom behavior, but by default this passes + * the data through. You must call this.ondata(err, chunk, final) at some + * point in this method. + * @param chunk The chunk to process + * @param final Whether this is the last chunk + */ + ZipPassThrough.prototype.process = function (chunk, final) { + this.ondata(null, chunk, final); + }; + /** + * Pushes a chunk to be added. If you are subclassing this with a custom + * compression algorithm, note that you must push data from the source + * file only, pre-compression. + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + ZipPassThrough.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + this.c.p(chunk); + this.size += chunk.length; + if (final) + this.crc = this.c.d(); + // we shouldn't really do this cast, but properly handling ArrayBufferLike + // makes the API unergonomic with Buffer + this.process(chunk, final || false); + }; + return ZipPassThrough; +}()); +exports.ZipPassThrough = ZipPassThrough; +// I don't extend because TypeScript extension adds 1kB of runtime bloat +/** + * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate + * for better performance + */ +var ZipDeflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + function ZipDeflate(filename, opts) { + var _this = this; + if (!opts) + opts = {}; + ZipPassThrough.call(this, filename); + this.d = new Deflate(opts, function (dat, final) { + _this.ondata(null, dat, final); + }); + this.compression = 8; + this.flag = dbf(opts.level); + } + ZipDeflate.prototype.process = function (chunk, final) { + try { + this.d.push(chunk, final); + } + catch (e) { + this.ondata(e, null, final); + } + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + ZipDeflate.prototype.push = function (chunk, final) { + ZipPassThrough.prototype.push.call(this, chunk, final); + }; + return ZipDeflate; +}()); +exports.ZipDeflate = ZipDeflate; +/** + * Asynchronous streaming DEFLATE compression for ZIP archives + */ +var AsyncZipDeflate = /*#__PURE__*/ (function () { + /** + * Creates an asynchronous DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + function AsyncZipDeflate(filename, opts) { + var _this = this; + if (!opts) + opts = {}; + ZipPassThrough.call(this, filename); + this.d = new AsyncDeflate(opts, function (err, dat, final) { + _this.ondata(err, dat, final); + }); + this.compression = 8; + this.flag = dbf(opts.level); + this.terminate = this.d.terminate; + } + AsyncZipDeflate.prototype.process = function (chunk, final) { + this.d.push(chunk, final); + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + AsyncZipDeflate.prototype.push = function (chunk, final) { + ZipPassThrough.prototype.push.call(this, chunk, final); + }; + return AsyncZipDeflate; +}()); +exports.AsyncZipDeflate = AsyncZipDeflate; +// TODO: Better tree shaking +/** + * A zippable archive to which files can incrementally be added + */ +var Zip = /*#__PURE__*/ (function () { + /** + * Creates an empty ZIP archive to which files can be added + * @param cb The callback to call whenever data for the generated ZIP archive + * is available + */ + function Zip(cb) { + this.ondata = cb; + this.u = []; + this.d = 1; + } + /** + * Adds a file to the ZIP archive + * @param file The file stream to add + */ + Zip.prototype.add = function (file) { + var _this = this; + if (!this.ondata) + err(5); + // finishing or finished + if (this.d & 2) + this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, false); + else { + var f = strToU8(file.filename), fl_1 = f.length; + var com = file.comment, o = com && strToU8(com); + var u = fl_1 != file.filename.length || (o && (com.length != o.length)); + var hl_1 = fl_1 + exfl(file.extra) + 30; + if (fl_1 > 65535) + this.ondata(err(11, 0, 1), null, false); + var header = new u8(hl_1); + wzh(header, 0, file, f, u, -1); + var chks_1 = [header]; + var pAll_1 = function () { + for (var _i = 0, chks_2 = chks_1; _i < chks_2.length; _i++) { + var chk = chks_2[_i]; + _this.ondata(null, chk, false); + } + chks_1 = []; + }; + var tr_1 = this.d; + this.d = 0; + var ind_1 = this.u.length; + var uf_1 = mrg(file, { + f: f, + u: u, + o: o, + t: function () { + if (file.terminate) + file.terminate(); + }, + r: function () { + pAll_1(); + if (tr_1) { + var nxt = _this.u[ind_1 + 1]; + if (nxt) + nxt.r(); + else + _this.d = 1; + } + tr_1 = 1; + } + }); + var cl_1 = 0; + file.ondata = function (err, dat, final) { + if (err) { + _this.ondata(err, dat, final); + _this.terminate(); + } + else { + cl_1 += dat.length; + chks_1.push(dat); + if (final) { + var dd = new u8(16); + wbytes(dd, 0, 0x8074B50); + wbytes(dd, 4, file.crc); + wbytes(dd, 8, cl_1); + wbytes(dd, 12, file.size); + chks_1.push(dd); + uf_1.c = cl_1, uf_1.b = hl_1 + cl_1 + 16, uf_1.crc = file.crc, uf_1.size = file.size; + if (tr_1) + uf_1.r(); + tr_1 = 1; + } + else if (tr_1) + pAll_1(); + } + }; + this.u.push(uf_1); + } + }; + /** + * Ends the process of adding files and prepares to emit the final chunks. + * This *must* be called after adding all desired files for the resulting + * ZIP file to work properly. + */ + Zip.prototype.end = function () { + var _this = this; + if (this.d & 2) { + this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, true); + return; + } + if (this.d) + this.e(); + else + this.u.push({ + r: function () { + if (!(_this.d & 1)) + return; + _this.u.splice(-1, 1); + _this.e(); + }, + t: function () { } + }); + this.d = 3; + }; + Zip.prototype.e = function () { + var bt = 0, l = 0, tl = 0; + for (var _i = 0, _a = this.u; _i < _a.length; _i++) { + var f = _a[_i]; + tl += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0); + } + var out = new u8(tl + 22); + for (var _b = 0, _c = this.u; _b < _c.length; _b++) { + var f = _c[_b]; + wzh(out, bt, f, f.f, f.u, -f.c - 2, l, f.o); + bt += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0), l += f.b; + } + wzf(out, bt, this.u.length, tl, l); + this.ondata(null, out, true); + this.d = 2; + }; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to add() will fail. + */ + Zip.prototype.terminate = function () { + for (var _i = 0, _a = this.u; _i < _a.length; _i++) { + var f = _a[_i]; + f.t(); + } + this.d = 2; + }; + return Zip; +}()); +exports.Zip = Zip; +function zip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + var r = {}; + fltn(data, '', r, opts); + var k = Object.keys(r); + var lft = k.length, o = 0, tot = 0; + var slft = lft, files = new Array(lft); + var term = []; + var tAll = function () { + for (var i = 0; i < term.length; ++i) + term[i](); + }; + var cbd = function (a, b) { + mt(function () { cb(a, b); }); + }; + mt(function () { cbd = cb; }); + var cbf = function () { + var out = new u8(tot + 22), oe = o, cdl = tot - o; + tot = 0; + for (var i = 0; i < slft; ++i) { + var f = files[i]; + try { + var l = f.c.length; + wzh(out, tot, f, f.f, f.u, l); + var badd = 30 + f.f.length + exfl(f.extra); + var loc = tot + badd; + out.set(f.c, loc); + wzh(out, o, f, f.f, f.u, l, tot, f.m), o += 16 + badd + (f.m ? f.m.length : 0), tot = loc + l; + } + catch (e) { + return cbd(e, null); + } + } + wzf(out, o, files.length, cdl, oe); + cbd(null, out); + }; + if (!lft) + cbf(); + var _loop_1 = function (i) { + var fn = k[i]; + var _a = r[fn], file = _a[0], p = _a[1]; + var c = crc(), size = file.length; + c.p(file); + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + var compression = p.level == 0 ? 0 : 8; + var cbl = function (e, d) { + if (e) { + tAll(); + cbd(e, null); + } + else { + var l = d.length; + files[i] = mrg(p, { + size: size, + crc: c.d(), + c: d, + f: f, + m: m, + u: s != fn.length || (m && (com.length != ms)), + compression: compression + }); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + if (!--lft) + cbf(); + } + }; + if (s > 65535) + cbl(err(11, 0, 1), null); + if (!compression) + cbl(null, file); + else if (size < 160000) { + try { + cbl(null, deflateSync(file, p)); + } + catch (e) { + cbl(e, null); + } + } + else + term.push(deflate(file, p, cbl)); + }; + // Cannot use lft because it can decrease + for (var i = 0; i < slft; ++i) { + _loop_1(i); + } + return tAll; +} +/** + * Synchronously creates a ZIP file. Prefer using `zip` for better performance + * with more than one file. + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @returns The generated ZIP archive + */ +function zipSync(data, opts) { + if (!opts) + opts = {}; + var r = {}; + var files = []; + fltn(data, '', r, opts); + var o = 0; + var tot = 0; + for (var fn in r) { + var _a = r[fn], file = _a[0], p = _a[1]; + var compression = p.level == 0 ? 0 : 8; + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + if (s > 65535) + err(11); + var d = compression ? deflateSync(file, p) : file, l = d.length; + var c = crc(); + c.p(file); + files.push(mrg(p, { + size: file.length, + crc: c.d(), + c: d, + f: f, + m: m, + u: s != fn.length || (m && (com.length != ms)), + o: o, + compression: compression + })); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + } + var out = new u8(tot + 22), oe = o, cdl = tot - o; + for (var i = 0; i < files.length; ++i) { + var f = files[i]; + wzh(out, f.o, f, f.f, f.u, f.c.length); + var badd = 30 + f.f.length + exfl(f.extra); + out.set(f.c, f.o + badd); + wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0); + } + wzf(out, o, files.length, cdl, oe); + return out; +} +/** + * Streaming pass-through decompression for ZIP archives + */ +var UnzipPassThrough = /*#__PURE__*/ (function () { + function UnzipPassThrough() { + } + UnzipPassThrough.prototype.push = function (chunk, final) { + // same as ZipPassThrough: cast to retain Buffer ergonomics + this.ondata(null, chunk, final); + }; + UnzipPassThrough.compression = 0; + return UnzipPassThrough; +}()); +exports.UnzipPassThrough = UnzipPassThrough; +/** + * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for + * better performance. + */ +var UnzipInflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + function UnzipInflate() { + var _this = this; + this.i = new Inflate(function (dat, final) { + _this.ondata(null, dat, final); + }); + } + UnzipInflate.prototype.push = function (chunk, final) { + try { + this.i.push(chunk, final); + } + catch (e) { + this.ondata(e, null, final); + } + }; + UnzipInflate.compression = 8; + return UnzipInflate; +}()); +exports.UnzipInflate = UnzipInflate; +/** + * Asynchronous streaming DEFLATE decompression for ZIP archives + */ +var AsyncUnzipInflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + function AsyncUnzipInflate(_, sz) { + var _this = this; + if (sz < 320000) { + this.i = new Inflate(function (dat, final) { + _this.ondata(null, dat, final); + }); + } + else { + this.i = new AsyncInflate(function (err, dat, final) { + _this.ondata(err, dat, final); + }); + this.terminate = this.i.terminate; + } + } + AsyncUnzipInflate.prototype.push = function (chunk, final) { + if (this.i.terminate) + chunk = slc(chunk, 0); + this.i.push(chunk, final); + }; + AsyncUnzipInflate.compression = 8; + return AsyncUnzipInflate; +}()); +exports.AsyncUnzipInflate = AsyncUnzipInflate; +/** + * A ZIP archive decompression stream that emits files as they are discovered + */ +var Unzip = /*#__PURE__*/ (function () { + /** + * Creates a ZIP decompression stream + * @param cb The callback to call whenever a file in the ZIP archive is found + */ + function Unzip(cb) { + this.onfile = cb; + this.k = []; + this.o = { + 0: UnzipPassThrough + }; + this.p = et; + } + /** + * Pushes a chunk to be unzipped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Unzip.prototype.push = function (chunk, final) { + var _this = this; + if (!this.onfile) + err(5); + if (!this.p) + err(4); + if (this.c > 0) { + var len = Math.min(this.c, chunk.length); + var toAdd = chunk.subarray(0, len); + this.c -= len; + if (this.d) + this.d.push(toAdd, !this.c); + else + this.k[0].push(toAdd); + chunk = chunk.subarray(len); + if (chunk.length) + return this.push(chunk, final); + } + else { + var f = 0, i = 0, is = void 0, buf = void 0; + if (!this.p.length) + buf = chunk; + else if (!chunk.length) + buf = this.p; + else { + buf = new u8(this.p.length + chunk.length); + buf.set(this.p), buf.set(chunk, this.p.length); + } + var l = buf.length, oc = this.c, add = oc && this.d; + var _loop_2 = function () { + var sig = b4(buf, i); + if (sig == 0x4034B50) { + f = 1, is = i; + this_1.d = null; + this_1.c = 0; + var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28); + if (l > i + 30 + fnl + es) { + var chks_3 = []; + this_1.k.unshift(chks_3); + f = 2; + var lsc = b4(buf, i + 18), lsu = b4(buf, i + 22); + var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u); + var _a = z64hs(buf, i, es, 2, lsc, lsu, 0), sc_1 = _a[0], su_1 = _a[1], z64 = _a[3]; + if (dd) + sc_1 = -1 - z64; + i += es; + this_1.c = sc_1; + var d_1; + var file_1 = { + name: fn_1, + compression: cmp_1, + start: function () { + if (!file_1.ondata) + err(5); + if (!sc_1) + file_1.ondata(null, et, true); + else { + var ctr = _this.o[cmp_1]; + if (!ctr) + file_1.ondata(err(14, 'unknown compression type ' + cmp_1, 1), null, false); + d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1); + d_1.ondata = function (err, dat, final) { file_1.ondata(err, dat, final); }; + for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) { + var dat = chks_4[_i]; + d_1.push(dat, false); + } + if (_this.k[0] == chks_3 && _this.c) + _this.d = d_1; + else + d_1.push(et, true); + } + }, + terminate: function () { + if (d_1 && d_1.terminate) + d_1.terminate(); + } + }; + if (sc_1 >= 0) + file_1.size = sc_1, file_1.originalSize = su_1; + this_1.onfile(file_1); + } + return "break"; + } + else if (oc) { + if (sig == 0x8074B50) { + is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0; + return "break"; + } + else if (sig == 0x2014B50) { + is = i -= 4, f = 3, this_1.c = 0; + return "break"; + } + } + }; + var this_1 = this; + for (; i < l - 4; ++i) { + var state_1 = _loop_2(); + if (state_1 === "break") + break; + } + this.p = et; + if (oc < 0) { + var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 0x8074B50 && 4)) : buf.subarray(0, i); + if (add) + add.push(dat, !!f); + else + this.k[+(f == 2)].push(dat); + } + if (f & 2) + return this.push(buf.subarray(i), final); + this.p = buf.subarray(i); + } + if (final) { + if (this.c) + err(13); + this.p = null; + } + }; + /** + * Registers a decoder with the stream, allowing for files compressed with + * the compression type provided to be expanded correctly + * @param decoder The decoder constructor + */ + Unzip.prototype.register = function (decoder) { + this.o[decoder.compression] = decoder; + }; + return Unzip; +}()); +exports.Unzip = Unzip; +var mt = typeof queueMicrotask == 'function' ? queueMicrotask : typeof setTimeout == 'function' ? setTimeout : function (fn) { fn(); }; +function unzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + var term = []; + var tAll = function () { + for (var i = 0; i < term.length; ++i) + term[i](); + }; + var files = {}; + var cbd = function (a, b) { + mt(function () { cb(a, b); }); + }; + mt(function () { cbd = cb; }); + var e = data.length - 22; + for (; b4(data, e) != 0x6054B50; --e) { + if (!e || data.length - e > 65558) { + cbd(err(13, 0, 1), null); + return tAll; + } + } + ; + var lft = b2(data, e + 8); + if (lft) { + var c = lft; + var o = b4(data, e + 16); + var z = b4(data, e - 20) == 0x7064B50; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 0x6064B50; + if (z) { + c = lft = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + var _loop_3 = function (i) { + var _a = zh(data, o, z), c_1 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off); + o = no; + var cbl = function (e, d) { + if (e) { + tAll(); + cbd(e, null); + } + else { + if (d) + files[fn] = d; + if (!--lft) + cbd(null, files); + } + }; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_1 + })) { + if (!c_1) + cbl(null, slc(data, b, b + sc)); + else if (c_1 == 8) { + var infl = data.subarray(b, b + sc); + // Synchronously decompress under 512KB, or barely-compressed data + if (su < 524288 || sc > 0.8 * su) { + try { + cbl(null, inflateSync(infl, { out: new u8(su) })); + } + catch (e) { + cbl(e, null); + } + } + else + term.push(inflate(infl, { size: su }, cbl)); + } + else + cbl(err(14, 'unknown compression type ' + c_1, 1), null); + } + else + cbl(null, null); + }; + for (var i = 0; i < c; ++i) { + _loop_3(i); + } + } + else + cbd(null, {}); + return tAll; +} +/** + * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better + * performance with more than one file. + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @returns The decompressed files + */ +function unzipSync(data, opts) { + var files = {}; + var e = data.length - 22; + for (; b4(data, e) != 0x6054B50; --e) { + if (!e || data.length - e > 65558) + err(13); + } + ; + var c = b2(data, e + 8); + if (!c) + return {}; + var o = b4(data, e + 16); + var z = b4(data, e - 20) == 0x7064B50; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 0x6064B50; + if (z) { + c = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + for (var i = 0; i < c; ++i) { + var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off); + o = no; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_2 + })) { + if (!c_2) + files[fn] = slc(data, b, b + sc); + else if (c_2 == 8) + files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) }); + else + err(14, 'unknown compression type ' + c_2); + } + } + return files; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/browser.d.cts b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/browser.d.cts new file mode 100644 index 0000000..d430faf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/browser.d.cts @@ -0,0 +1,1539 @@ +/** + * Codes for errors generated within this library + */ +export declare const FlateErrorCode: { + readonly UnexpectedEOF: 0; + readonly InvalidBlockType: 1; + readonly InvalidLengthLiteral: 2; + readonly InvalidDistance: 3; + readonly StreamFinished: 4; + readonly NoStreamHandler: 5; + readonly InvalidHeader: 6; + readonly NoCallback: 7; + readonly InvalidUTF8: 8; + readonly ExtraFieldTooLong: 9; + readonly InvalidDate: 10; + readonly FilenameTooLong: 11; + readonly StreamFinishing: 12; + readonly InvalidZipData: 13; + readonly UnknownCompressionMethod: 14; +}; +/** + * An error generated within this library + */ +export interface FlateError extends Error { + /** + * The code associated with this error + */ + code: number; +} +/** + * Options for decompressing a DEFLATE stream + */ +export interface InflateStreamOptions { + /** + * The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect. + * + * Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error. + */ + dictionary?: Uint8Array; +} +/** + * Options for decompressing DEFLATE data + */ +export interface InflateOptions extends InflateStreamOptions { + /** + * The buffer into which to write the decompressed data. Saves memory if you know the decompressed size in advance. + * + * Note that if the decompression result is larger than the size of this buffer, it will be truncated to fit. + */ + out?: Uint8Array; +} +/** + * Options for decompressing a GZIP stream + */ +export interface GunzipStreamOptions extends InflateStreamOptions { +} +/** + * Options for decompressing GZIP data + */ +export interface GunzipOptions extends InflateStreamOptions { + /** + * The buffer into which to write the decompressed data. GZIP already encodes the output size, so providing this doesn't save memory. + * + * Note that if the decompression result is larger than the size of this buffer, it will be truncated to fit. + */ + out?: Uint8Array; +} +/** + * Options for decompressing a Zlib stream + */ +export interface UnzlibStreamOptions extends InflateStreamOptions { +} +/** + * Options for decompressing Zlib data + */ +export interface UnzlibOptions extends InflateOptions { +} +/** + * Options for compressing data into a DEFLATE format + */ +export interface DeflateOptions { + /** + * The level of compression to use, ranging from 0-9. + * + * 0 will store the data without compression. + * 1 is fastest but compresses the worst, 9 is slowest but compresses the best. + * The default level is 6. + * + * Typically, binary data benefits much more from higher values than text data. + * In both cases, higher values usually take disproportionately longer than the reduction in final size that results. + * + * For example, a 1 MB text file could: + * - become 1.01 MB with level 0 in 1ms + * - become 400 kB with level 1 in 10ms + * - become 320 kB with level 9 in 100ms + */ + level?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; + /** + * The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory. + * + * Note that this is exponential: while level 0 uses 8 kB, level 4 uses 128 kB, level 8 uses 2 MB, and level 12 uses 32 MB. + * It is recommended not to lower the value below 4, since that tends to hurt performance. + * In addition, values above 8 tend to help very little on most data and can even hurt performance. + * + * The default value is automatically determined based on the size of the input data. + */ + mem?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + /** + * A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios. + * + * Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input. + * The decompressor must supply the same dictionary as the compressor to extract the original data. + * + * Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise. + * + * Avoid using dictionaries with GZIP and ZIP to maximize software compatibility. + */ + dictionary?: Uint8Array; +} +/** + * Options for compressing data into a GZIP format + */ +export interface GzipOptions extends DeflateOptions { + /** + * When the file was last modified. Defaults to the current time. + * Set this to 0 to avoid revealing a modification date entirely. + */ + mtime?: Date | string | number; + /** + * The filename of the data. If the `gunzip` command is used to decompress the data, it will output a file + * with this name instead of the name of the compressed file. + */ + filename?: string; +} +/** + * Options for compressing data into a Zlib format + */ +export interface ZlibOptions extends DeflateOptions { +} +/** + * Handler for data (de)compression streams + * @param data The data output from the stream processor + * @param final Whether this is the final block + */ +export type FlateStreamHandler = (data: Uint8Array, final: boolean) => void; +/** + * Handler for asynchronous data (de)compression streams + * @param err Any error that occurred + * @param data The data output from the stream processor + * @param final Whether this is the final block + */ +export type AsyncFlateStreamHandler = (err: FlateError | null, data: Uint8Array, final: boolean) => void; +/** + * Handler for the asynchronous completion of (de)compression for a data chunk + * @param size The number of bytes that were processed. This is measured in terms of the input + * (i.e. compressed bytes for decompression, uncompressed bytes for compression.) + */ +export type AsyncFlateDrainHandler = (size: number) => void; +/** + * Callback for asynchronous (de)compression methods + * @param err Any error that occurred + * @param data The resulting data. Only present if `err` is null + */ +export type FlateCallback = (err: FlateError | null, data: Uint8Array) => void; +interface AsyncOptions { + /** + * Whether or not to "consume" the source data. This will make the typed array/buffer you pass in + * unusable but will increase performance and reduce memory usage. + */ + consume?: boolean; +} +/** + * Options for compressing data asynchronously into a DEFLATE format + */ +export interface AsyncDeflateOptions extends DeflateOptions, AsyncOptions { +} +/** + * Options for decompressing DEFLATE data asynchronously + */ +export interface AsyncInflateOptions extends AsyncOptions, InflateStreamOptions { + /** + * The original size of the data. Currently, the asynchronous API disallows + * writing into a buffer you provide; the best you can do is provide the + * size in bytes and be given back a new typed array. + */ + size?: number; +} +/** + * Options for compressing data asynchronously into a GZIP format + */ +export interface AsyncGzipOptions extends GzipOptions, AsyncOptions { +} +/** + * Options for decompressing GZIP data asynchronously + */ +export interface AsyncGunzipOptions extends AsyncOptions, InflateStreamOptions { +} +/** + * Options for compressing data asynchronously into a Zlib format + */ +export interface AsyncZlibOptions extends ZlibOptions, AsyncOptions { +} +/** + * Options for decompressing Zlib data asynchronously + */ +export interface AsyncUnzlibOptions extends AsyncInflateOptions { +} +/** + * A terminable compression/decompression process + */ +export interface AsyncTerminable { + /** + * Terminates the worker thread immediately. The callback will not be called. + */ + (): void; +} +/** + * Streaming DEFLATE compression + */ +export declare class Deflate { + /** + * Creates a DEFLATE stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: DeflateOptions, cb?: FlateStreamHandler); + /** + * Creates a DEFLATE stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + private b; + private s; + private o; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + private p; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE compression + */ +export declare class AsyncDeflate { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous DEFLATE stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: DeflateOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous DEFLATE stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function deflate(data: Uint8Array, opts: AsyncDeflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param cb The function to be called upon compression completion + */ +export declare function deflate(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @returns The deflated version of the data + */ +export declare function deflateSync(data: Uint8Array, opts?: DeflateOptions): Uint8Array; +/** + * Streaming DEFLATE decompression + */ +export declare class Inflate { + private s; + private o; + private p; + private d; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a DEFLATE decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: InflateStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a DEFLATE decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + private e; + private c; + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the final chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE decompression + */ +export declare class AsyncInflate { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous DEFLATE decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: InflateStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous DEFLATE decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function inflate(data: Uint8Array, opts: AsyncInflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function inflate(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands DEFLATE data with no wrapper + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function inflateSync(data: Uint8Array): Uint8Array; +/** + * Expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function inflateSync(data: Uint8Array, opts?: InflateOptions): Uint8Array; +/** + * Streaming GZIP compression + */ +export declare class Gzip { + private c; + private l; + private v; + private o; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a GZIP stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: GzipOptions, cb?: FlateStreamHandler); + /** + * Creates a GZIP stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + private p; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming GZIP compression + */ +export declare class AsyncGzip { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous GZIP stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: GzipOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous GZIP stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function gzip(data: Uint8Array, opts: AsyncGzipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with GZIP + * @param data The data to compress + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gzip(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @returns The gzipped version of the data + */ +export declare function gzipSync(data: Uint8Array, opts?: GzipOptions): Uint8Array; +/** + * Handler for new GZIP members in concatenated GZIP streams. Useful for building indices used to perform random-access reads on compressed files. + * @param offset The offset of the new member relative to the start of the stream + */ +export type GunzipMemberHandler = (offset: number) => void; +/** + * Streaming single or multi-member GZIP decompression + */ +export declare class Gunzip { + private v; + private r; + private o; + private p; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * The handler to call whenever a new GZIP member is found + */ + onmember?: GunzipMemberHandler; + /** + * Creates a GUNZIP stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: GunzipStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a GUNZIP stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming single or multi-member GZIP decompression + */ +export declare class AsyncGunzip { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * The handler to call whenever a new GZIP member is found + */ + onmember?: GunzipMemberHandler; + /** + * Creates an asynchronous GUNZIP stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: GunzipStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous GUNZIP stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands GZIP data + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gunzip(data: Uint8Array, opts: AsyncGunzipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands GZIP data + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gunzip(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands GZIP data + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function gunzipSync(data: Uint8Array): Uint8Array; +/** + * Expands GZIP data + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function gunzipSync(data: Uint8Array, opts?: GunzipOptions): Uint8Array; +/** + * Streaming Zlib compression + */ +export declare class Zlib { + private c; + private v; + private o; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a Zlib stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: ZlibOptions, cb?: FlateStreamHandler); + /** + * Creates a Zlib stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be zlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + private p; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming Zlib compression + */ +export declare class AsyncZlib { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous Zlib stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: ZlibOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous Zlib stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with Zlib + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + */ +export declare function zlib(data: Uint8Array, opts: AsyncZlibOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with Zlib + * @param data The data to compress + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zlib(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compress data with Zlib + * @param data The data to compress + * @param opts The compression options + * @returns The zlib-compressed version of the data + */ +export declare function zlibSync(data: Uint8Array, opts?: ZlibOptions): Uint8Array; +/** + * Streaming Zlib decompression + */ +export declare class Unzlib { + private v; + private p; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a Zlib decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: UnzlibStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a Zlib decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be unzlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming Zlib decompression + */ +export declare class AsyncUnzlib { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous Zlib decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: UnzlibStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous Zlib decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be decompressed from Zlib + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands Zlib data + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function unzlib(data: Uint8Array, opts: AsyncUnzlibOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands Zlib data + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function unzlib(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands Zlib data + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function unzlibSync(data: Uint8Array): Uint8Array; +/** + * Expands Zlib data + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function unzlibSync(data: Uint8Array, opts?: UnzlibOptions): Uint8Array; +export { gzip as compress, AsyncGzip as AsyncCompress }; +export { gzipSync as compressSync, Gzip as Compress }; +/** + * Streaming GZIP, Zlib, or raw DEFLATE decompression + */ +export declare class Decompress { + private G; + private I; + private Z; + private o; + private s; + private p; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is decompressed + */ + constructor(opts: InflateStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a decompression stream + * @param cb The callback to call whenever data is decompressed + */ + constructor(cb?: FlateStreamHandler); + private i; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression + */ +export declare class AsyncDecompress { + private G; + private I; + private Z; + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is decompressed + */ + constructor(opts: InflateStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous decompression stream + * @param cb The callback to call whenever data is decompressed + */ + constructor(cb?: AsyncFlateStreamHandler); + private i; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchrononously expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function decompress(data: Uint8Array, opts: AsyncInflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchrononously expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function decompress(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function decompressSync(data: Uint8Array, opts?: InflateOptions): Uint8Array; +/** + * Attributes for files added to a ZIP archive object + */ +export interface ZipAttributes { + /** + * The operating system of origin for this file. The value is defined + * by PKZIP's APPNOTE.txt, section 4.4.2.2. For example, 0 (the default) + * is MS/DOS, 3 is Unix, 19 is macOS. + */ + os?: number; + /** + * The file's attributes. These are traditionally somewhat complicated + * and platform-dependent, so using them is scarcely necessary. However, + * here is a representation of what this is, bit by bit: + * + * `TTTTugtrwxrwxrwx0000000000ADVSHR` + * + * TTTT = file type (rarely useful) + * + * u = setuid, g = setgid, t = sticky + * + * rwx = user permissions, rwx = group permissions, rwx = other permissions + * + * 0000000000 = unused + * + * A = archive, D = directory, V = volume label, S = system file, H = hidden, R = read-only + * + * If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0o644 << 16. + * Note that attributes usually only work in conjunction with the `os` setting: you must use + * `os` = 3 (Unix) if you want to set Unix permissions + */ + attrs?: number; + /** + * Extra metadata to add to the file. This field is defined by PKZIP's APPNOTE.txt, + * section 4.4.28. At most 65,535 bytes may be used in each ID. The ID must be an + * integer between 0 and 65,535, inclusive. + * + * This field is incredibly rare and almost never needed except for compliance with + * proprietary standards and software. + */ + extra?: Record; + /** + * The comment to attach to the file. This field is defined by PKZIP's APPNOTE.txt, + * section 4.4.26. The comment must be at most 65,535 bytes long UTF-8 encoded. This + * field is not read by consumer software. + */ + comment?: string; + /** + * When the file was last modified. Defaults to the current time. + */ + mtime?: GzipOptions['mtime']; +} +/** + * Options for creating a ZIP archive + */ +export interface ZipOptions extends DeflateOptions, ZipAttributes { +} +/** + * Options for expanding a ZIP archive + */ +export interface UnzipOptions { + /** + * A filter function to extract only certain files from a ZIP archive + */ + filter?: UnzipFileFilter; +} +/** + * Options for asynchronously creating a ZIP archive + */ +export interface AsyncZipOptions extends AsyncDeflateOptions, ZipAttributes { +} +/** + * Options for asynchronously expanding a ZIP archive + */ +export interface AsyncUnzipOptions extends UnzipOptions { +} +/** + * A file that can be used to create a ZIP archive + */ +export type ZippableFile = Uint8Array | Zippable | [Uint8Array | Zippable, ZipOptions]; +/** + * A file that can be used to asynchronously create a ZIP archive + */ +export type AsyncZippableFile = Uint8Array | AsyncZippable | [Uint8Array | AsyncZippable, AsyncZipOptions]; +/** + * The complete directory structure of a ZIPpable archive + */ +export interface Zippable { + [path: string]: ZippableFile; +} +/** + * The complete directory structure of an asynchronously ZIPpable archive + */ +export interface AsyncZippable { + [path: string]: AsyncZippableFile; +} +/** + * An unzipped archive. The full path of each file is used as the key, + * and the file is the value + */ +export interface Unzipped { + [path: string]: Uint8Array; +} +/** + * Handler for string generation streams + * @param data The string output from the stream processor + * @param final Whether this is the final block + */ +export type StringStreamHandler = (data: string, final: boolean) => void; +/** + * Callback for asynchronous ZIP decompression + * @param err Any error that occurred + * @param data The decompressed ZIP archive + */ +export type UnzipCallback = (err: FlateError | null, data: Unzipped) => void; +/** + * Handler for streaming ZIP decompression + * @param file The file that was found in the archive + */ +export type UnzipFileHandler = (file: UnzipFile) => void; +/** + * Streaming UTF-8 decoding + */ +export declare class DecodeUTF8 { + private p; + private t; + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is decoded + */ + constructor(cb?: StringStreamHandler); + /** + * Pushes a chunk to be decoded from UTF-8 binary + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * The handler to call whenever data is available + */ + ondata: StringStreamHandler; +} +/** + * Streaming UTF-8 encoding + */ +export declare class EncodeUTF8 { + private d; + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is encoded + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be encoded to UTF-8 + * @param chunk The string data to push + * @param final Whether this is the last chunk + */ + push(chunk: string, final?: boolean): void; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; +} +/** + * Converts a string into a Uint8Array for use with compression/decompression methods + * @param str The string to encode + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless decoding a binary string. + * @returns The string encoded in UTF-8/Latin-1 binary + */ +export declare function strToU8(str: string, latin1?: boolean): Uint8Array; +/** + * Converts a Uint8Array to a string + * @param dat The data to decode to string + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless encoding to binary string. + * @returns The original UTF-8/Latin-1 string + */ +export declare function strFromU8(dat: Uint8Array, latin1?: boolean): string; +/** + * A stream that can be used to create a file in a ZIP archive + */ +export interface ZipInputFile extends ZipAttributes { + /** + * The filename to associate with the data provided to this stream. If you + * want a file in a subdirectory, use forward slashes as a separator (e.g. + * `directory/filename.ext`). This will still work on Windows. + */ + filename: string; + /** + * The size of the file in bytes. This attribute may be invalid after + * the file is added to the ZIP archive; it must be correct only before the + * stream completes. + * + * If you don't want to have to compute this yourself, consider extending the + * ZipPassThrough class and overriding its process() method, or using one of + * ZipDeflate or AsyncZipDeflate. + */ + size: number; + /** + * A CRC of the original file contents. This attribute may be invalid after + * the file is added to the ZIP archive; it must be correct only before the + * stream completes. + * + * If you don't want to have to generate this yourself, consider extending the + * ZipPassThrough class and overriding its process() method, or using one of + * ZipDeflate or AsyncZipDeflate. + */ + crc: number; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA + */ + compression: number; + /** + * Bits 1 and 2 of the general purpose bit flag, specified in PKZIP's + * APPNOTE.txt, section 4.4.4. Should be between 0 and 3. This is unlikely + * to be necessary. + */ + flag?: number; + /** + * The handler to be called when data is added. After passing this stream to + * the ZIP file object, this handler will always be defined. To call it: + * + * `stream.ondata(error, chunk, final)` + * + * error = any error that occurred (null if there was no error) + * + * chunk = a Uint8Array of the data that was added (null if there was an + * error) + * + * final = boolean, whether this is the final chunk in the stream + */ + ondata?: AsyncFlateStreamHandler; + /** + * A method called when the stream is no longer needed, for clean-up + * purposes. This will not always be called after the stream completes, + * so you may wish to call this.terminate() after the final chunk is + * processed if you have clean-up logic. + */ + terminate?: AsyncTerminable; +} +/** + * A pass-through stream to keep data uncompressed in a ZIP archive. + */ +export declare class ZipPassThrough implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private c; + /** + * Creates a pass-through stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + */ + constructor(filename: string); + /** + * Processes a chunk and pushes to the output stream. You can override this + * method in a subclass for custom behavior, but by default this passes + * the data through. You must call this.ondata(err, chunk, final) at some + * point in this method. + * @param chunk The chunk to process + * @param final Whether this is the last chunk + */ + protected process(chunk: Uint8Array, final: boolean): void; + /** + * Pushes a chunk to be added. If you are subclassing this with a custom + * compression algorithm, note that you must push data from the source + * file only, pre-compression. + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate + * for better performance + */ +export declare class ZipDeflate implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + flag: 0 | 1 | 2 | 3; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private d; + /** + * Creates a DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + constructor(filename: string, opts?: DeflateOptions); + private process; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE compression for ZIP archives + */ +export declare class AsyncZipDeflate implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + flag: 0 | 1 | 2 | 3; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private d; + terminate: AsyncTerminable; + /** + * Creates an asynchronous DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + constructor(filename: string, opts?: DeflateOptions); + private process; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * A zippable archive to which files can incrementally be added + */ +export declare class Zip { + private u; + private d; + /** + * Creates an empty ZIP archive to which files can be added + * @param cb The callback to call whenever data for the generated ZIP archive + * is available + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Adds a file to the ZIP archive + * @param file The file stream to add + */ + add(file: ZipInputFile): void; + /** + * Ends the process of adding files and prepares to emit the final chunks. + * This *must* be called after adding all desired files for the resulting + * ZIP file to work properly. + */ + end(): void; + private e; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to add() will fail. + */ + terminate(): void; + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; +} +/** + * Asynchronously creates a ZIP file + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @param cb The callback to call with the generated ZIP archive + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zip(data: AsyncZippable, opts: AsyncZipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously creates a ZIP file + * @param data The directory structure for the ZIP archive + * @param cb The callback to call with the generated ZIP archive + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zip(data: AsyncZippable, cb: FlateCallback): AsyncTerminable; +/** + * Synchronously creates a ZIP file. Prefer using `zip` for better performance + * with more than one file. + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @returns The generated ZIP archive + */ +export declare function zipSync(data: Zippable, opts?: ZipOptions): Uint8Array; +/** + * A decoder for files in ZIP streams + */ +export interface UnzipDecoder { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * Pushes a chunk to be decompressed + * @param chunk The data in this chunk. Do not consume (detach) this buffer. + * @param final Whether this is the last chunk in the data stream + */ + push(chunk: Uint8Array, final: boolean): void; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to push() should silently fail. + */ + terminate?: AsyncTerminable; +} +/** + * A constructor for a decoder for unzip streams + */ +export interface UnzipDecoderConstructor { + /** + * Creates an instance of the decoder + * @param filename The name of the file + * @param size The compressed size of the file + * @param originalSize The original size of the file + */ + new (filename: string, size?: number, originalSize?: number): UnzipDecoder; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA + */ + compression: number; +} +/** + * Information about a file to be extracted from a ZIP archive + */ +export interface UnzipFileInfo { + /** + * The name of the file + */ + name: string; + /** + * The compressed size of the file + */ + size: number; + /** + * The original size of the file + */ + originalSize: number; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA. If the filter function returns true + * but this value is not 8, the unzip function will throw. + */ + compression: number; +} +/** + * A filter for files to be extracted during the unzipping process + * @param file The info for the current file being processed + * @returns Whether or not to extract the current file + */ +export type UnzipFileFilter = (file: UnzipFileInfo) => boolean; +/** + * Streaming file extraction from ZIP archives + */ +export interface UnzipFile { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The name of the file + */ + name: string; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA. If start() is called but there is no + * decompression stream available for this method, start() will throw. + */ + compression: number; + /** + * The compressed size of the file. Will not be present for archives created + * in a streaming fashion. + */ + size?: number; + /** + * The original size of the file. Will not be present for archives created + * in a streaming fashion. + */ + originalSize?: number; + /** + * Starts reading from the stream. Calling this function will always enable + * this stream, but ocassionally the stream will be enabled even without + * this being called. + */ + start(): void; + /** + * A method to terminate any internal workers used by the stream. ondata + * will not be called any further. + */ + terminate: AsyncTerminable; +} +/** + * Streaming pass-through decompression for ZIP archives + */ +export declare class UnzipPassThrough implements UnzipDecoder { + static compression: number; + ondata: AsyncFlateStreamHandler; + push(chunk: Uint8Array, final: boolean): void; +} +/** + * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for + * better performance. + */ +export declare class UnzipInflate implements UnzipDecoder { + static compression: number; + private i; + ondata: AsyncFlateStreamHandler; + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + constructor(); + push(chunk: Uint8Array, final: boolean): void; +} +/** + * Asynchronous streaming DEFLATE decompression for ZIP archives + */ +export declare class AsyncUnzipInflate implements UnzipDecoder { + static compression: number; + private i; + ondata: AsyncFlateStreamHandler; + terminate: AsyncTerminable; + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + constructor(_: string, sz?: number); + push(chunk: Uint8Array, final: boolean): void; +} +/** + * A ZIP archive decompression stream that emits files as they are discovered + */ +export declare class Unzip { + private d; + private c; + private p; + private k; + private o; + /** + * Creates a ZIP decompression stream + * @param cb The callback to call whenever a file in the ZIP archive is found + */ + constructor(cb?: UnzipFileHandler); + /** + * Pushes a chunk to be unzipped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Registers a decoder with the stream, allowing for files compressed with + * the compression type provided to be expanded correctly + * @param decoder The decoder constructor + */ + register(decoder: UnzipDecoderConstructor): void; + /** + * The handler to call whenever a file is discovered + */ + onfile: UnzipFileHandler; +} +/** + * Asynchronously decompresses a ZIP archive + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @param cb The callback to call with the decompressed files + * @returns A function that can be used to immediately terminate the unzipping + */ +export declare function unzip(data: Uint8Array, opts: AsyncUnzipOptions, cb: UnzipCallback): AsyncTerminable; +/** + * Asynchronously decompresses a ZIP archive + * @param data The raw compressed ZIP file + * @param cb The callback to call with the decompressed files + * @returns A function that can be used to immediately terminate the unzipping + */ +export declare function unzip(data: Uint8Array, cb: UnzipCallback): AsyncTerminable; +/** + * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better + * performance with more than one file. + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @returns The decompressed files + */ +export declare function unzipSync(data: Uint8Array, opts?: UnzipOptions): Unzipped; diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/index.cjs b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/index.cjs new file mode 100644 index 0000000..ea4da56 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/index.cjs @@ -0,0 +1,2697 @@ +"use strict"; +// DEFLATE is a complex format; to read this code, you should probably check the RFC first: +// https://tools.ietf.org/html/rfc1951 +// You may also wish to take a look at the guide I made about this program: +// https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad +exports.deflate = deflate; +exports.deflateSync = deflateSync; +exports.inflate = inflate; +exports.inflateSync = inflateSync; +exports.gzip = gzip; +exports.compress = gzip; +exports.gzipSync = gzipSync; +exports.compressSync = gzipSync; +exports.gunzip = gunzip; +exports.gunzipSync = gunzipSync; +exports.zlib = zlib; +exports.zlibSync = zlibSync; +exports.unzlib = unzlib; +exports.unzlibSync = unzlibSync; +exports.gzip = gzip; +exports.compress = gzip; +exports.decompress = decompress; +exports.decompressSync = decompressSync; +exports.strToU8 = strToU8; +exports.strFromU8 = strFromU8; +exports.zip = zip; +exports.zipSync = zipSync; +exports.unzip = unzip; +exports.unzipSync = unzipSync; +// Some of the following code is similar to that of UZIP.js: +// https://github.com/photopea/UZIP.js +// However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size. +// Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint +// is better for memory in most engines (I *think*). +var node_worker_1 = require("./node-worker.cjs"); +// aliases for shorter compressed code (most minifers don't do this) +var u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array; +// fixed length extra bits +var fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]); +// fixed distance extra bits +var fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]); +// code length index map +var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); +// get base, reverse index map from extra bits +var freb = function (eb, start) { + var b = new u16(31); + for (var i = 0; i < 31; ++i) { + b[i] = start += 1 << eb[i - 1]; + } + // numbers here are at max 18 bits + var r = new i32(b[30]); + for (var i = 1; i < 30; ++i) { + for (var j = b[i]; j < b[i + 1]; ++j) { + r[j] = ((j - b[i]) << 5) | i; + } + } + return { b: b, r: r }; +}; +var _a = freb(fleb, 2), fl = _a.b, revfl = _a.r; +// we can ignore the fact that the other numbers are wrong; they never happen anyway +fl[28] = 258, revfl[258] = 28; +var _b = freb(fdeb, 0), fd = _b.b, revfd = _b.r; +// map of value to reverse (assuming 16 bits) +var rev = new u16(32768); +for (var i = 0; i < 32768; ++i) { + // reverse table algorithm from SO + var x = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1); + x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2); + x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4); + rev[i] = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) >> 1; +} +// create huffman tree from u8 "map": index -> code length for code index +// mb (max bits) must be at most 15 +// TODO: optimize/split up? +var hMap = (function (cd, mb, r) { + var s = cd.length; + // index + var i = 0; + // u16 "map": index -> # of codes with bit length = index + var l = new u16(mb); + // length of cd must be 288 (total # of codes) + for (; i < s; ++i) { + if (cd[i]) + ++l[cd[i] - 1]; + } + // u16 "map": index -> minimum code for bit length = index + var le = new u16(mb); + for (i = 1; i < mb; ++i) { + le[i] = (le[i - 1] + l[i - 1]) << 1; + } + var co; + if (r) { + // u16 "map": index -> number of actual bits, symbol for code + co = new u16(1 << mb); + // bits to remove for reverser + var rvb = 15 - mb; + for (i = 0; i < s; ++i) { + // ignore 0 lengths + if (cd[i]) { + // num encoding both symbol and bits read + var sv = (i << 4) | cd[i]; + // free bits + var r_1 = mb - cd[i]; + // start value + var v = le[cd[i] - 1]++ << r_1; + // m is end value + for (var m = v | ((1 << r_1) - 1); v <= m; ++v) { + // every 16 bit value starting with the code yields the same result + co[rev[v] >> rvb] = sv; + } + } + } + } + else { + co = new u16(s); + for (i = 0; i < s; ++i) { + if (cd[i]) { + co[i] = rev[le[cd[i] - 1]++] >> (15 - cd[i]); + } + } + } + return co; +}); +// fixed length tree +var flt = new u8(288); +for (var i = 0; i < 144; ++i) + flt[i] = 8; +for (var i = 144; i < 256; ++i) + flt[i] = 9; +for (var i = 256; i < 280; ++i) + flt[i] = 7; +for (var i = 280; i < 288; ++i) + flt[i] = 8; +// fixed distance tree +var fdt = new u8(32); +for (var i = 0; i < 32; ++i) + fdt[i] = 5; +// fixed length map +var flm = /*#__PURE__*/ hMap(flt, 9, 0), flrm = /*#__PURE__*/ hMap(flt, 9, 1); +// fixed distance map +var fdm = /*#__PURE__*/ hMap(fdt, 5, 0), fdrm = /*#__PURE__*/ hMap(fdt, 5, 1); +// find max of array +var max = function (a) { + var m = a[0]; + for (var i = 1; i < a.length; ++i) { + if (a[i] > m) + m = a[i]; + } + return m; +}; +// read d, starting at bit p and mask with m +var bits = function (d, p, m) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m; +}; +// read d, starting at bit p continuing for at least 16 bits +var bits16 = function (d, p) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7)); +}; +// get end of byte +var shft = function (p) { return ((p + 7) / 8) | 0; }; +// typed array slice - allows garbage collector to free original reference, +// while being more compatible than .slice +var slc = function (v, s, e) { + if (s == null || s < 0) + s = 0; + if (e == null || e > v.length) + e = v.length; + // can't use .constructor in case user-supplied + return new u8(v.subarray(s, e)); +}; +/** + * Codes for errors generated within this library + */ +exports.FlateErrorCode = { + UnexpectedEOF: 0, + InvalidBlockType: 1, + InvalidLengthLiteral: 2, + InvalidDistance: 3, + StreamFinished: 4, + NoStreamHandler: 5, + InvalidHeader: 6, + NoCallback: 7, + InvalidUTF8: 8, + ExtraFieldTooLong: 9, + InvalidDate: 10, + FilenameTooLong: 11, + StreamFinishing: 12, + InvalidZipData: 13, + UnknownCompressionMethod: 14 +}; +// error codes +var ec = [ + 'unexpected EOF', + 'invalid block type', + 'invalid length/literal', + 'invalid distance', + 'stream finished', + 'no stream handler', + , // determined by compression function + 'no callback', + 'invalid UTF-8 data', + 'extra field too long', + 'date not in range 1980-2099', + 'filename too long', + 'stream finishing', + 'invalid zip data' + // determined by unknown compression method +]; +; +var err = function (ind, msg, nt) { + var e = new Error(msg || ec[ind]); + e.code = ind; + if (Error.captureStackTrace) + Error.captureStackTrace(e, err); + if (!nt) + throw e; + return e; +}; +// expands raw DEFLATE data +var inflt = function (dat, st, buf, dict) { + // source length dict length + var sl = dat.length, dl = dict ? dict.length : 0; + if (!sl || st.f && !st.l) + return buf || new u8(0); + var noBuf = !buf; + // have to estimate size + var resize = noBuf || st.i != 2; + // no state + var noSt = st.i; + // Assumes roughly 33% compression ratio average + if (noBuf) + buf = new u8(sl * 3); + // ensure buffer can fit at least l elements + var cbuf = function (l) { + var bl = buf.length; + // need to increase size to fit + if (l > bl) { + // Double or set to necessary, whichever is greater + var nbuf = new u8(Math.max(bl * 2, l)); + nbuf.set(buf); + buf = nbuf; + } + }; + // last chunk bitpos bytes + var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; + // total bits + var tbts = sl * 8; + do { + if (!lm) { + // BFINAL - this is only 1 when last chunk is next + final = bits(dat, pos, 1); + // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman + var type = bits(dat, pos + 1, 3); + pos += 3; + if (!type) { + // go to end of byte boundary + var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l; + if (t > sl) { + if (noSt) + err(0); + break; + } + // ensure size + if (resize) + cbuf(bt + l); + // Copy over uncompressed data + buf.set(dat.subarray(s, t), bt); + // Get new bitpos, update byte count + st.b = bt += l, st.p = pos = t * 8, st.f = final; + continue; + } + else if (type == 1) + lm = flrm, dm = fdrm, lbt = 9, dbt = 5; + else if (type == 2) { + // literal lengths + var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; + var tl = hLit + bits(dat, pos + 5, 31) + 1; + pos += 14; + // length+distance tree + var ldt = new u8(tl); + // code length tree + var clt = new u8(19); + for (var i = 0; i < hcLen; ++i) { + // use index map to get real code + clt[clim[i]] = bits(dat, pos + i * 3, 7); + } + pos += hcLen * 3; + // code lengths bits + var clb = max(clt), clbmsk = (1 << clb) - 1; + // code lengths map + var clm = hMap(clt, clb, 1); + for (var i = 0; i < tl;) { + var r = clm[bits(dat, pos, clbmsk)]; + // bits read + pos += r & 15; + // symbol + var s = r >> 4; + // code length to copy + if (s < 16) { + ldt[i++] = s; + } + else { + // copy count + var c = 0, n = 0; + if (s == 16) + n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; + else if (s == 17) + n = 3 + bits(dat, pos, 7), pos += 3; + else if (s == 18) + n = 11 + bits(dat, pos, 127), pos += 7; + while (n--) + ldt[i++] = c; + } + } + // length tree distance tree + var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); + // max length bits + lbt = max(lt); + // max dist bits + dbt = max(dt); + lm = hMap(lt, lbt, 1); + dm = hMap(dt, dbt, 1); + } + else + err(1); + if (pos > tbts) { + if (noSt) + err(0); + break; + } + } + // Make sure the buffer can hold this + the largest possible addition + // Maximum chunk size (practically, theoretically infinite) is 2^17 + if (resize) + cbuf(bt + 131072); + var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; + var lpos = pos; + for (;; lpos = pos) { + // bits read, code + var c = lm[bits16(dat, pos) & lms], sym = c >> 4; + pos += c & 15; + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (!c) + err(2); + if (sym < 256) + buf[bt++] = sym; + else if (sym == 256) { + lpos = pos, lm = null; + break; + } + else { + var add = sym - 254; + // no extra bits needed if less + if (sym > 264) { + // index + var i = sym - 257, b = fleb[i]; + add = bits(dat, pos, (1 << b) - 1) + fl[i]; + pos += b; + } + // dist + var d = dm[bits16(dat, pos) & dms], dsym = d >> 4; + if (!d) + err(3); + pos += d & 15; + var dt = fd[dsym]; + if (dsym > 3) { + var b = fdeb[dsym]; + dt += bits16(dat, pos) & (1 << b) - 1, pos += b; + } + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (resize) + cbuf(bt + 131072); + var end = bt + add; + if (bt < dt) { + var shift = dl - dt, dend = Math.min(dt, end); + if (shift + bt < 0) + err(3); + for (; bt < dend; ++bt) + buf[bt] = dict[shift + bt]; + } + for (; bt < end; ++bt) + buf[bt] = buf[bt - dt]; + } + } + st.l = lm, st.p = lpos, st.b = bt, st.f = final; + if (lm) + final = 1, st.m = lbt, st.d = dm, st.n = dbt; + } while (!final); + // don't reallocate for streams or user buffers + return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt); +}; +// starting at p, write the minimum number of bits that can hold v to d +var wbits = function (d, p, v) { + v <<= p & 7; + var o = (p / 8) | 0; + d[o] |= v; + d[o + 1] |= v >> 8; +}; +// starting at p, write the minimum number of bits (>8) that can hold v to d +var wbits16 = function (d, p, v) { + v <<= p & 7; + var o = (p / 8) | 0; + d[o] |= v; + d[o + 1] |= v >> 8; + d[o + 2] |= v >> 16; +}; +// creates code lengths from a frequency table +var hTree = function (d, mb) { + // Need extra info to make a tree + var t = []; + for (var i = 0; i < d.length; ++i) { + if (d[i]) + t.push({ s: i, f: d[i] }); + } + var s = t.length; + var t2 = t.slice(); + if (!s) + return { t: et, l: 0 }; + if (s == 1) { + var v = new u8(t[0].s + 1); + v[t[0].s] = 1; + return { t: v, l: 1 }; + } + t.sort(function (a, b) { return a.f - b.f; }); + // after i2 reaches last ind, will be stopped + // freq must be greater than largest possible number of symbols + t.push({ s: -1, f: 25001 }); + var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2; + t[0] = { s: -1, f: l.f + r.f, l: l, r: r }; + // efficient algorithm from UZIP.js + // i0 is lookbehind, i2 is lookahead - after processing two low-freq + // symbols that combined have high freq, will start processing i2 (high-freq, + // non-composite) symbols instead + // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/ + while (i1 != s - 1) { + l = t[t[i0].f < t[i2].f ? i0++ : i2++]; + r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++]; + t[i1++] = { s: -1, f: l.f + r.f, l: l, r: r }; + } + var maxSym = t2[0].s; + for (var i = 1; i < s; ++i) { + if (t2[i].s > maxSym) + maxSym = t2[i].s; + } + // code lengths + var tr = new u16(maxSym + 1); + // max bits in tree + var mbt = ln(t[i1 - 1], tr, 0); + if (mbt > mb) { + // more algorithms from UZIP.js + // TODO: find out how this code works (debt) + // ind debt + var i = 0, dt = 0; + // left cost + var lft = mbt - mb, cst = 1 << lft; + t2.sort(function (a, b) { return tr[b.s] - tr[a.s] || a.f - b.f; }); + for (; i < s; ++i) { + var i2_1 = t2[i].s; + if (tr[i2_1] > mb) { + dt += cst - (1 << (mbt - tr[i2_1])); + tr[i2_1] = mb; + } + else + break; + } + dt >>= lft; + while (dt > 0) { + var i2_2 = t2[i].s; + if (tr[i2_2] < mb) + dt -= 1 << (mb - tr[i2_2]++ - 1); + else + ++i; + } + for (; i >= 0 && dt; --i) { + var i2_3 = t2[i].s; + if (tr[i2_3] == mb) { + --tr[i2_3]; + ++dt; + } + } + mbt = mb; + } + return { t: new u8(tr), l: mbt }; +}; +// get the max length and assign length codes +var ln = function (n, l, d) { + return n.s == -1 + ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) + : (l[n.s] = d); +}; +// length codes generation +var lc = function (c) { + var s = c.length; + // Note that the semicolon was intentional + while (s && !c[--s]) + ; + var cl = new u16(++s); + // ind num streak + var cli = 0, cln = c[0], cls = 1; + var w = function (v) { cl[cli++] = v; }; + for (var i = 1; i <= s; ++i) { + if (c[i] == cln && i != s) + ++cls; + else { + if (!cln && cls > 2) { + for (; cls > 138; cls -= 138) + w(32754); + if (cls > 2) { + w(cls > 10 ? ((cls - 11) << 5) | 28690 : ((cls - 3) << 5) | 12305); + cls = 0; + } + } + else if (cls > 3) { + w(cln), --cls; + for (; cls > 6; cls -= 6) + w(8304); + if (cls > 2) + w(((cls - 3) << 5) | 8208), cls = 0; + } + while (cls--) + w(cln); + cls = 1; + cln = c[i]; + } + } + return { c: cl.subarray(0, cli), n: s }; +}; +// calculate the length of output from tree, code lengths +var clen = function (cf, cl) { + var l = 0; + for (var i = 0; i < cl.length; ++i) + l += cf[i] * cl[i]; + return l; +}; +// writes a fixed block +// returns the new bit pos +var wfblk = function (out, pos, dat) { + // no need to write 00 as type: TypedArray defaults to 0 + var s = dat.length; + var o = shft(pos + 2); + out[o] = s & 255; + out[o + 1] = s >> 8; + out[o + 2] = out[o] ^ 255; + out[o + 3] = out[o + 1] ^ 255; + for (var i = 0; i < s; ++i) + out[o + i + 4] = dat[i]; + return (o + 4 + s) * 8; +}; +// writes a block +var wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) { + wbits(out, p++, final); + ++lf[256]; + var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l; + var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l; + var _c = lc(dlt), lclt = _c.c, nlc = _c.n; + var _d = lc(ddt), lcdt = _d.c, ndc = _d.n; + var lcfreq = new u16(19); + for (var i = 0; i < lclt.length; ++i) + ++lcfreq[lclt[i] & 31]; + for (var i = 0; i < lcdt.length; ++i) + ++lcfreq[lcdt[i] & 31]; + var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l; + var nlcc = 19; + for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc) + ; + var flen = (bl + 5) << 3; + var ftlen = clen(lf, flt) + clen(df, fdt) + eb; + var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18]; + if (bs >= 0 && flen <= ftlen && flen <= dtlen) + return wfblk(out, p, dat.subarray(bs, bs + bl)); + var lm, ll, dm, dl; + wbits(out, p, 1 + (dtlen < ftlen)), p += 2; + if (dtlen < ftlen) { + lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt; + var llm = hMap(lct, mlcb, 0); + wbits(out, p, nlc - 257); + wbits(out, p + 5, ndc - 1); + wbits(out, p + 10, nlcc - 4); + p += 14; + for (var i = 0; i < nlcc; ++i) + wbits(out, p + 3 * i, lct[clim[i]]); + p += 3 * nlcc; + var lcts = [lclt, lcdt]; + for (var it = 0; it < 2; ++it) { + var clct = lcts[it]; + for (var i = 0; i < clct.length; ++i) { + var len = clct[i] & 31; + wbits(out, p, llm[len]), p += lct[len]; + if (len > 15) + wbits(out, p, (clct[i] >> 5) & 127), p += clct[i] >> 12; + } + } + } + else { + lm = flm, ll = flt, dm = fdm, dl = fdt; + } + for (var i = 0; i < li; ++i) { + var sym = syms[i]; + if (sym > 255) { + var len = (sym >> 18) & 31; + wbits16(out, p, lm[len + 257]), p += ll[len + 257]; + if (len > 7) + wbits(out, p, (sym >> 23) & 31), p += fleb[len]; + var dst = sym & 31; + wbits16(out, p, dm[dst]), p += dl[dst]; + if (dst > 3) + wbits16(out, p, (sym >> 5) & 8191), p += fdeb[dst]; + } + else { + wbits16(out, p, lm[sym]), p += ll[sym]; + } + } + wbits16(out, p, lm[256]); + return p + ll[256]; +}; +// deflate options (nice << 13) | chain +var deo = /*#__PURE__*/ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]); +// empty +var et = /*#__PURE__*/ new u8(0); +// compresses data into a raw DEFLATE buffer +var dflt = function (dat, lvl, plvl, pre, post, st) { + var s = st.z || dat.length; + var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7000)) + post); + // writing to this writes to the output buffer + var w = o.subarray(pre, o.length - post); + var lst = st.l; + var pos = (st.r || 0) & 7; + if (lvl) { + if (pos) + w[0] = st.r >> 3; + var opt = deo[lvl - 1]; + var n = opt >> 13, c = opt & 8191; + var msk_1 = (1 << plvl) - 1; + // prev 2-byte val map curr 2-byte val map + var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1); + var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1; + var hsh = function (i) { return (dat[i] ^ (dat[i + 1] << bs1_1) ^ (dat[i + 2] << bs2_1)) & msk_1; }; + // 24576 is an arbitrary number of maximum symbols per block + // 424 buffer for last block + var syms = new i32(25000); + // length/literal freq distance freq + var lf = new u16(288), df = new u16(32); + // l/lcnt exbits index l/lind waitdx blkpos + var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0; + for (; i + 2 < s; ++i) { + // hash value + var hv = hsh(i); + // index mod 32768 previous index mod + var imod = i & 32767, pimod = head[hv]; + prev[imod] = pimod; + head[hv] = imod; + // We always should modify head and prev, but only add symbols if + // this data is not yet processed ("wait" for wait index) + if (wi <= i) { + // bytes remaining + var rem = s - i; + if ((lc_1 > 7000 || li > 24576) && (rem > 423 || !lst)) { + pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos); + li = lc_1 = eb = 0, bs = i; + for (var j = 0; j < 286; ++j) + lf[j] = 0; + for (var j = 0; j < 30; ++j) + df[j] = 0; + } + // len dist chain + var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767; + if (rem > 2 && hv == hsh(i - dif)) { + var maxn = Math.min(n, rem) - 1; + var maxd = Math.min(32767, i); + // max possible length + // not capped at dif because decompressors implement "rolling" index population + var ml = Math.min(258, rem); + while (dif <= maxd && --ch_1 && imod != pimod) { + if (dat[i + l] == dat[i + l - dif]) { + var nl = 0; + for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl) + ; + if (nl > l) { + l = nl, d = dif; + // break out early when we reach "nice" (we are satisfied enough) + if (nl > maxn) + break; + // now, find the rarest 2-byte sequence within this + // length of literals and search for that instead. + // Much faster than just using the start + var mmd = Math.min(dif, nl - 2); + var md = 0; + for (var j = 0; j < mmd; ++j) { + var ti = i - dif + j & 32767; + var pti = prev[ti]; + var cd = ti - pti & 32767; + if (cd > md) + md = cd, pimod = ti; + } + } + } + // check the previous match + imod = pimod, pimod = prev[imod]; + dif += imod - pimod & 32767; + } + } + // d will be nonzero only when a match was found + if (d) { + // store both dist and len data in one int32 + // Make sure this is recognized as a len/dist with 28th bit (2^28) + syms[li++] = 268435456 | (revfl[l] << 18) | revfd[d]; + var lin = revfl[l] & 31, din = revfd[d] & 31; + eb += fleb[lin] + fdeb[din]; + ++lf[257 + lin]; + ++df[din]; + wi = i + l; + ++lc_1; + } + else { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + } + } + for (i = Math.max(i, wi); i < s; ++i) { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos); + if (!lst) { + st.r = (pos & 7) | w[(pos / 8) | 0] << 3; + // shft(pos) now 1 less if pos & 7 != 0 + pos -= 7; + st.h = head, st.p = prev, st.i = i, st.w = wi; + } + } + else { + for (var i = st.w || 0; i < s + lst; i += 65535) { + // end + var e = i + 65535; + if (e >= s) { + // write final block + w[(pos / 8) | 0] = lst; + e = s; + } + pos = wfblk(w, pos + 1, dat.subarray(i, e)); + } + st.i = s; + } + return slc(o, 0, pre + shft(pos) + post); +}; +// CRC32 table +var crct = /*#__PURE__*/ (function () { + var t = new Int32Array(256); + for (var i = 0; i < 256; ++i) { + var c = i, k = 9; + while (--k) + c = ((c & 1) && -306674912) ^ (c >>> 1); + t[i] = c; + } + return t; +})(); +// CRC32 +var crc = function () { + var c = -1; + return { + p: function (d) { + // closures have awful performance + var cr = c; + for (var i = 0; i < d.length; ++i) + cr = crct[(cr & 255) ^ d[i]] ^ (cr >>> 8); + c = cr; + }, + d: function () { return ~c; } + }; +}; +// Adler32 +var adler = function () { + var a = 1, b = 0; + return { + p: function (d) { + // closures have awful performance + var n = a, m = b; + var l = d.length | 0; + for (var i = 0; i != l;) { + var e = Math.min(i + 2655, l); + for (; i < e; ++i) + m += n += d[i]; + n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16); + } + a = n, b = m; + }, + d: function () { + a %= 65521, b %= 65521; + return (a & 255) << 24 | (a & 0xFF00) << 8 | (b & 255) << 8 | (b >> 8); + } + }; +}; +; +// deflate with opts +var dopt = function (dat, opt, pre, post, st) { + if (!st) { + st = { l: 1 }; + if (opt.dictionary) { + var dict = opt.dictionary.subarray(-32768); + var newDat = new u8(dict.length + dat.length); + newDat.set(dict); + newDat.set(dat, dict.length); + dat = newDat; + st.w = dict.length; + } + } + return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? (st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20) : (12 + opt.mem), pre, post, st); +}; +// Walmart object spread +var mrg = function (a, b) { + var o = {}; + for (var k in a) + o[k] = a[k]; + for (var k in b) + o[k] = b[k]; + return o; +}; +// worker clone +// This is possibly the craziest part of the entire codebase, despite how simple it may seem. +// The only parameter to this function is a closure that returns an array of variables outside of the function scope. +// We're going to try to figure out the variable names used in the closure as strings because that is crucial for workerization. +// We will return an object mapping of true variable name to value (basically, the current scope as a JS object). +// The reason we can't just use the original variable names is minifiers mangling the toplevel scope. +// This took me three weeks to figure out how to do. +var wcln = function (fn, fnStr, td) { + var dt = fn(); + var st = fn.toString(); + var ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/\s+/g, '').split(','); + for (var i = 0; i < dt.length; ++i) { + var v = dt[i], k = ks[i]; + if (typeof v == 'function') { + fnStr += ';' + k + '='; + var st_1 = v.toString(); + if (v.prototype) { + // for global objects + if (st_1.indexOf('[native code]') != -1) { + var spInd = st_1.indexOf(' ', 8) + 1; + fnStr += st_1.slice(spInd, st_1.indexOf('(', spInd)); + } + else { + fnStr += st_1; + for (var t in v.prototype) + fnStr += ';' + k + '.prototype.' + t + '=' + v.prototype[t].toString(); + } + } + else + fnStr += st_1; + } + else + td[k] = v; + } + return fnStr; +}; +var ch = []; +// clone bufs +var cbfs = function (v) { + var tl = []; + for (var k in v) { + if (v[k].buffer) { + tl.push((v[k] = new v[k].constructor(v[k])).buffer); + } + } + return tl; +}; +// use a worker to execute code +var wrkr = function (fns, init, id, cb) { + if (!ch[id]) { + var fnStr = '', td_1 = {}, m = fns.length - 1; + for (var i = 0; i < m; ++i) + fnStr = wcln(fns[i], fnStr, td_1); + ch[id] = { c: wcln(fns[m], fnStr, td_1), e: td_1 }; + } + var td = mrg({}, ch[id].e); + return (0, node_worker_1.default)(ch[id].c + ';onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage=' + init.toString() + '}', id, td, cbfs(td), cb); +}; +// base async inflate fn +var bInflt = function () { return [u8, u16, i32, fleb, fdeb, clim, fl, fd, flrm, fdrm, rev, ec, hMap, max, bits, bits16, shft, slc, err, inflt, inflateSync, pbf, gopt]; }; +var bDflt = function () { return [u8, u16, i32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; }; +// gzip extra +var gze = function () { return [gzh, gzhl, wbytes, crc, crct]; }; +// gunzip extra +var guze = function () { return [gzs, gzl]; }; +// zlib extra +var zle = function () { return [zlh, wbytes, adler]; }; +// unzlib extra +var zule = function () { return [zls]; }; +// post buf +var pbf = function (msg) { return postMessage(msg, [msg.buffer]); }; +// get opts +var gopt = function (o) { return o && { + out: o.size && new u8(o.size), + dictionary: o.dictionary +}; }; +// async helper +var cbify = function (dat, opts, fns, init, id, cb) { + var w = wrkr(fns, init, id, function (err, dat) { + w.terminate(); + cb(err, dat); + }); + w.postMessage([dat, opts], opts.consume ? [dat.buffer] : []); + return function () { w.terminate(); }; +}; +// auto stream +var astrm = function (strm) { + strm.ondata = function (dat, final) { return postMessage([dat, final], [dat.buffer]); }; + return function (ev) { + if (ev.data[0]) { + strm.push(ev.data[0], ev.data[1]); + postMessage([ev.data[0].length]); + } + else + strm.flush(ev.data[1]); + }; +}; +// async stream attach +var astrmify = function (fns, strm, opts, init, id, flush, ext) { + var t; + var w = wrkr(fns, init, id, function (err, dat) { + if (err) + w.terminate(), strm.ondata.call(strm, err); + else if (!Array.isArray(dat)) + ext(dat); + else if (dat.length == 1) { + strm.queuedSize -= dat[0]; + if (strm.ondrain) + strm.ondrain(dat[0]); + } + else { + if (dat[1]) + w.terminate(); + strm.ondata.call(strm, err, dat[0], dat[1]); + } + }); + w.postMessage(opts); + strm.queuedSize = 0; + strm.push = function (d, f) { + if (!strm.ondata) + err(5); + if (t) + strm.ondata(err(4, 0, 1), null, !!f); + strm.queuedSize += d.length; + // can fail for cross-realm Uint8Array, but ok - only a small performance penalty + w.postMessage([d, t = f], d.buffer instanceof ArrayBuffer ? [d.buffer] : []); + }; + strm.terminate = function () { w.terminate(); }; + if (flush) { + strm.flush = function (sync) { w.postMessage([0, sync]); }; + } +}; +// read 2 bytes +var b2 = function (d, b) { return d[b] | (d[b + 1] << 8); }; +// read 4 bytes +var b4 = function (d, b) { return (d[b] | (d[b + 1] << 8) | (d[b + 2] << 16) | (d[b + 3] << 24)) >>> 0; }; +// read 8 bytes +var b8 = function (d, b) { return b4(d, b) + (b4(d, b + 4) * 4294967296); }; +// write bytes +var wbytes = function (d, b, v) { + for (; v; ++b) + d[b] = v, v >>>= 8; +}; +// gzip header +var gzh = function (c, o) { + var fn = o.filename; + c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3; // assume Unix + if (o.mtime != 0) + wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1000)); + if (fn) { + c[3] = 8; + for (var i = 0; i <= fn.length; ++i) + c[i + 10] = fn.charCodeAt(i); + } +}; +// gzip footer: -8 to -4 = CRC, -4 to -0 is length +// gzip start +var gzs = function (d) { + if (d[0] != 31 || d[1] != 139 || d[2] != 8) + err(6, 'invalid gzip data'); + var flg = d[3]; + var st = 10; + if (flg & 4) + st += (d[10] | d[11] << 8) + 2; + for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++]) + ; + return st + (flg & 2); +}; +// gzip length +var gzl = function (d) { + var l = d.length; + return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0; +}; +// gzip header length +var gzhl = function (o) { return 10 + (o.filename ? o.filename.length + 1 : 0); }; +// zlib header +var zlh = function (c, o) { + var lv = o.level, fl = lv == 0 ? 0 : lv < 6 ? 1 : lv == 9 ? 3 : 2; + c[0] = 120, c[1] = (fl << 6) | (o.dictionary && 32); + c[1] |= 31 - ((c[0] << 8) | c[1]) % 31; + if (o.dictionary) { + var h = adler(); + h.p(o.dictionary); + wbytes(c, 2, h.d()); + } +}; +// zlib start +var zls = function (d, dict) { + if ((d[0] & 15) != 8 || (d[0] >> 4) > 7 || ((d[0] << 8 | d[1]) % 31)) + err(6, 'invalid zlib data'); + if ((d[1] >> 5 & 1) == +!dict) + err(6, 'invalid zlib data: ' + (d[1] & 32 ? 'need' : 'unexpected') + ' dictionary'); + return (d[1] >> 3 & 4) + 2; +}; +function StrmOpt(opts, cb) { + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + return opts; +} +/** + * Streaming DEFLATE compression + */ +var Deflate = /*#__PURE__*/ (function () { + function Deflate(opts, cb) { + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + this.o = opts || {}; + this.s = { l: 0, i: 32768, w: 32768, z: 32768 }; + // Buffer length must always be 0 mod 32768 for index calculations to be correct when modifying head and prev + // 98304 = 32768 (lookback) + 65536 (common chunk size) + this.b = new u8(98304); + if (this.o.dictionary) { + var dict = this.o.dictionary.subarray(-32768); + this.b.set(dict, 32768 - dict.length); + this.s.i = 32768 - dict.length; + } + } + Deflate.prototype.p = function (c, f) { + this.ondata(dopt(c, this.o, 0, 0, this.s), f); + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Deflate.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (this.s.l) + err(4); + var endLen = chunk.length + this.s.z; + if (endLen > this.b.length) { + if (endLen > 2 * this.b.length - 32768) { + var newBuf = new u8(endLen & -32768); + newBuf.set(this.b.subarray(0, this.s.z)); + this.b = newBuf; + } + var split = this.b.length - this.s.z; + this.b.set(chunk.subarray(0, split), this.s.z); + this.s.z = this.b.length; + this.p(this.b, false); + this.b.set(this.b.subarray(-32768)); + this.b.set(chunk.subarray(split), 32768); + this.s.z = chunk.length - split + 32768; + this.s.i = 32766, this.s.w = 32768; + } + else { + this.b.set(chunk, this.s.z); + this.s.z += chunk.length; + } + this.s.l = final & 1; + if (this.s.z > this.s.w + 8191 || final) { + this.p(this.b, final || false); + this.s.w = this.s.i, this.s.i -= 2; + } + if (final) { + // cleanup unneeded buffers/state to reduce memory usage + this.s = this.o = {}; + this.b = et; + } + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + Deflate.prototype.flush = function (sync) { + if (!this.ondata) + err(5); + if (this.s.l) + err(4); + this.p(this.b, false); + this.s.w = this.s.i, this.s.i -= 2; + // could technically skip writing the type-0 block for (this.s.r & 7) == 0, + // but the deterministic trailer (00 00 FF FF) is useful in some situations + if (sync) { + var c = new u8(6); + c[0] = this.s.r >> 3; + // write empty, non-final type-0 block + var ep = wfblk(c, this.s.r, et); + this.s.r = 0; + this.ondata(c.subarray(0, ep >> 3), false); + } + }; + return Deflate; +}()); +exports.Deflate = Deflate; +/** + * Asynchronous streaming DEFLATE compression + */ +var AsyncDeflate = /*#__PURE__*/ (function () { + function AsyncDeflate(opts, cb) { + astrmify([ + bDflt, + function () { return [astrm, Deflate]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Deflate(ev.data); + onmessage = astrm(strm); + }, 6, 1); + } + return AsyncDeflate; +}()); +exports.AsyncDeflate = AsyncDeflate; +function deflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + ], function (ev) { return pbf(deflateSync(ev.data[0], ev.data[1])); }, 0, cb); +} +/** + * Compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @returns The deflated version of the data + */ +function deflateSync(data, opts) { + return dopt(data, opts || {}, 0, 0); +} +/** + * Streaming DEFLATE decompression + */ +var Inflate = /*#__PURE__*/ (function () { + function Inflate(opts, cb) { + // no StrmOpt here to avoid adding to workerizer + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768); + this.s = { i: 0, b: dict ? dict.length : 0 }; + this.o = new u8(32768); + this.p = new u8(0); + if (dict) + this.o.set(dict); + } + Inflate.prototype.e = function (c) { + if (!this.ondata) + err(5); + if (this.d) + err(4); + if (!this.p.length) + this.p = c; + else if (c.length) { + var n = new u8(this.p.length + c.length); + n.set(this.p), n.set(c, this.p.length), this.p = n; + } + }; + Inflate.prototype.c = function (final) { + this.s.i = +(this.d = final || false); + var bts = this.s.b; + var dt = inflt(this.p, this.s, this.o); + this.ondata(slc(dt, bts, this.s.b), this.d); + this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length; + this.p = slc(this.p, (this.s.p / 8) | 0), this.s.p &= 7; + }; + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the final chunk + */ + Inflate.prototype.push = function (chunk, final) { + this.e(chunk), this.c(final); + }; + return Inflate; +}()); +exports.Inflate = Inflate; +/** + * Asynchronous streaming DEFLATE decompression + */ +var AsyncInflate = /*#__PURE__*/ (function () { + function AsyncInflate(opts, cb) { + astrmify([ + bInflt, + function () { return [astrm, Inflate]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Inflate(ev.data); + onmessage = astrm(strm); + }, 7, 0); + } + return AsyncInflate; +}()); +exports.AsyncInflate = AsyncInflate; +function inflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt + ], function (ev) { return pbf(inflateSync(ev.data[0], gopt(ev.data[1]))); }, 1, cb); +} +function inflateSync(data, opts) { + return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary); +} +// before you yell at me for not just using extends, my reason is that TS inheritance is hard to workerize. +/** + * Streaming GZIP compression + */ +var Gzip = /*#__PURE__*/ (function () { + function Gzip(opts, cb) { + this.c = crc(); + this.l = 0; + this.v = 1; + Deflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Gzip.prototype.push = function (chunk, final) { + this.c.p(chunk); + this.l += chunk.length; + Deflate.prototype.push.call(this, chunk, final); + }; + Gzip.prototype.p = function (c, f) { + var raw = dopt(c, this.o, this.v && gzhl(this.o), f && 8, this.s); + if (this.v) + gzh(raw, this.o), this.v = 0; + if (f) + wbytes(raw, raw.length - 8, this.c.d()), wbytes(raw, raw.length - 4, this.l); + this.ondata(raw, f); + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + Gzip.prototype.flush = function (sync) { + Deflate.prototype.flush.call(this, sync); + }; + return Gzip; +}()); +exports.Gzip = Gzip; +exports.Compress = Gzip; +/** + * Asynchronous streaming GZIP compression + */ +var AsyncGzip = /*#__PURE__*/ (function () { + function AsyncGzip(opts, cb) { + astrmify([ + bDflt, + gze, + function () { return [astrm, Deflate, Gzip]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Gzip(ev.data); + onmessage = astrm(strm); + }, 8, 1); + } + return AsyncGzip; +}()); +exports.AsyncGzip = AsyncGzip; +exports.AsyncCompress = AsyncGzip; +function gzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + gze, + function () { return [gzipSync]; } + ], function (ev) { return pbf(gzipSync(ev.data[0], ev.data[1])); }, 2, cb); +} +/** + * Compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @returns The gzipped version of the data + */ +function gzipSync(data, opts) { + if (!opts) + opts = {}; + var c = crc(), l = data.length; + c.p(data); + var d = dopt(data, opts, gzhl(opts), 8), s = d.length; + return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d; +} +/** + * Streaming single or multi-member GZIP decompression + */ +var Gunzip = /*#__PURE__*/ (function () { + function Gunzip(opts, cb) { + this.v = 1; + this.r = 0; + Inflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Gunzip.prototype.push = function (chunk, final) { + Inflate.prototype.e.call(this, chunk); + this.r += chunk.length; + if (this.v) { + var p = this.p.subarray(this.v - 1); + var s = p.length > 3 ? gzs(p) : 4; + if (s > p.length) { + if (!final) + return; + } + else if (this.v > 1 && this.onmember) { + this.onmember(this.r - p.length); + } + this.p = p.subarray(s), this.v = 0; + } + // necessary to prevent TS from using the closure value + // This allows for workerization to function correctly + Inflate.prototype.c.call(this, 0); + // process concatenated GZIP + if (this.s.f && !this.s.l) { + this.v = shft(this.s.p) + 9; + this.s = { i: 0 }; + this.o = new u8(0); + this.push(new u8(0), final); + } + else if (final) { + Inflate.prototype.c.call(this, final); + } + }; + return Gunzip; +}()); +exports.Gunzip = Gunzip; +/** + * Asynchronous streaming single or multi-member GZIP decompression + */ +var AsyncGunzip = /*#__PURE__*/ (function () { + function AsyncGunzip(opts, cb) { + var _this = this; + astrmify([ + bInflt, + guze, + function () { return [astrm, Inflate, Gunzip]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Gunzip(ev.data); + strm.onmember = function (offset) { return postMessage(offset); }; + onmessage = astrm(strm); + }, 9, 0, function (offset) { return _this.onmember && _this.onmember(offset); }); + } + return AsyncGunzip; +}()); +exports.AsyncGunzip = AsyncGunzip; +function gunzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt, + guze, + function () { return [gunzipSync]; } + ], function (ev) { return pbf(gunzipSync(ev.data[0], ev.data[1])); }, 3, cb); +} +function gunzipSync(data, opts) { + var st = gzs(data); + if (st + 8 > data.length) + err(6, 'invalid gzip data'); + return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary); +} +/** + * Streaming Zlib compression + */ +var Zlib = /*#__PURE__*/ (function () { + function Zlib(opts, cb) { + this.c = adler(); + this.v = 1; + Deflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be zlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Zlib.prototype.push = function (chunk, final) { + this.c.p(chunk); + Deflate.prototype.push.call(this, chunk, final); + }; + Zlib.prototype.p = function (c, f) { + var raw = dopt(c, this.o, this.v && (this.o.dictionary ? 6 : 2), f && 4, this.s); + if (this.v) + zlh(raw, this.o), this.v = 0; + if (f) + wbytes(raw, raw.length - 4, this.c.d()); + this.ondata(raw, f); + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + Zlib.prototype.flush = function (sync) { + Deflate.prototype.flush.call(this, sync); + }; + return Zlib; +}()); +exports.Zlib = Zlib; +/** + * Asynchronous streaming Zlib compression + */ +var AsyncZlib = /*#__PURE__*/ (function () { + function AsyncZlib(opts, cb) { + astrmify([ + bDflt, + zle, + function () { return [astrm, Deflate, Zlib]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Zlib(ev.data); + onmessage = astrm(strm); + }, 10, 1); + } + return AsyncZlib; +}()); +exports.AsyncZlib = AsyncZlib; +function zlib(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + zle, + function () { return [zlibSync]; } + ], function (ev) { return pbf(zlibSync(ev.data[0], ev.data[1])); }, 4, cb); +} +/** + * Compress data with Zlib + * @param data The data to compress + * @param opts The compression options + * @returns The zlib-compressed version of the data + */ +function zlibSync(data, opts) { + if (!opts) + opts = {}; + var a = adler(); + a.p(data); + var d = dopt(data, opts, opts.dictionary ? 6 : 2, 4); + return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d; +} +/** + * Streaming Zlib decompression + */ +var Unzlib = /*#__PURE__*/ (function () { + function Unzlib(opts, cb) { + Inflate.call(this, opts, cb); + this.v = opts && opts.dictionary ? 2 : 1; + } + /** + * Pushes a chunk to be unzlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Unzlib.prototype.push = function (chunk, final) { + Inflate.prototype.e.call(this, chunk); + if (this.v) { + if (this.p.length < 6 && !final) + return; + this.p = this.p.subarray(zls(this.p, this.v - 1)), this.v = 0; + } + if (final) { + if (this.p.length < 4) + err(6, 'invalid zlib data'); + this.p = this.p.subarray(0, -4); + } + // necessary to prevent TS from using the closure value + // This allows for workerization to function correctly + Inflate.prototype.c.call(this, final); + }; + return Unzlib; +}()); +exports.Unzlib = Unzlib; +/** + * Asynchronous streaming Zlib decompression + */ +var AsyncUnzlib = /*#__PURE__*/ (function () { + function AsyncUnzlib(opts, cb) { + astrmify([ + bInflt, + zule, + function () { return [astrm, Inflate, Unzlib]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Unzlib(ev.data); + onmessage = astrm(strm); + }, 11, 0); + } + return AsyncUnzlib; +}()); +exports.AsyncUnzlib = AsyncUnzlib; +function unzlib(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt, + zule, + function () { return [unzlibSync]; } + ], function (ev) { return pbf(unzlibSync(ev.data[0], gopt(ev.data[1]))); }, 5, cb); +} +function unzlibSync(data, opts) { + return inflt(data.subarray(zls(data, opts && opts.dictionary), -4), { i: 2 }, opts && opts.out, opts && opts.dictionary); +} +/** + * Streaming GZIP, Zlib, or raw DEFLATE decompression + */ +var Decompress = /*#__PURE__*/ (function () { + function Decompress(opts, cb) { + this.o = StrmOpt.call(this, opts, cb) || {}; + this.G = Gunzip; + this.I = Inflate; + this.Z = Unzlib; + } + // init substream + // overriden by AsyncDecompress + Decompress.prototype.i = function () { + var _this = this; + this.s.ondata = function (dat, final) { + _this.ondata(dat, final); + }; + }; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Decompress.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (!this.s) { + if (this.p && this.p.length) { + var n = new u8(this.p.length + chunk.length); + n.set(this.p), n.set(chunk, this.p.length); + } + else + this.p = chunk; + if (this.p.length > 2) { + this.s = (this.p[0] == 31 && this.p[1] == 139 && this.p[2] == 8) + ? new this.G(this.o) + : ((this.p[0] & 15) != 8 || (this.p[0] >> 4) > 7 || ((this.p[0] << 8 | this.p[1]) % 31)) + ? new this.I(this.o) + : new this.Z(this.o); + this.i(); + this.s.push(this.p, final); + this.p = null; + } + } + else + this.s.push(chunk, final); + }; + return Decompress; +}()); +exports.Decompress = Decompress; +/** + * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression + */ +var AsyncDecompress = /*#__PURE__*/ (function () { + function AsyncDecompress(opts, cb) { + Decompress.call(this, opts, cb); + this.queuedSize = 0; + this.G = AsyncGunzip; + this.I = AsyncInflate; + this.Z = AsyncUnzlib; + } + AsyncDecompress.prototype.i = function () { + var _this = this; + this.s.ondata = function (err, dat, final) { + _this.ondata(err, dat, final); + }; + this.s.ondrain = function (size) { + _this.queuedSize -= size; + if (_this.ondrain) + _this.ondrain(size); + }; + }; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + AsyncDecompress.prototype.push = function (chunk, final) { + this.queuedSize += chunk.length; + Decompress.prototype.push.call(this, chunk, final); + }; + return AsyncDecompress; +}()); +exports.AsyncDecompress = AsyncDecompress; +function decompress(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return (data[0] == 31 && data[1] == 139 && data[2] == 8) + ? gunzip(data, opts, cb) + : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31)) + ? inflate(data, opts, cb) + : unzlib(data, opts, cb); +} +/** + * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +function decompressSync(data, opts) { + return (data[0] == 31 && data[1] == 139 && data[2] == 8) + ? gunzipSync(data, opts) + : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31)) + ? inflateSync(data, opts) + : unzlibSync(data, opts); +} +// flatten a directory structure +var fltn = function (d, p, t, o) { + for (var k in d) { + var val = d[k], n = p + k, op = o; + if (Array.isArray(val)) + op = mrg(o, val[1]), val = val[0]; + if (ArrayBuffer.isView(val)) + t[n] = [val, op]; + else { + t[n += '/'] = [new u8(0), op]; + fltn(val, n, t, o); + } + } +}; +// text encoder +var te = typeof TextEncoder != 'undefined' && /*#__PURE__*/ new TextEncoder(); +// text decoder +var td = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder(); +// text decoder stream +var tds = 0; +try { + td.decode(et, { stream: true }); + tds = 1; +} +catch (e) { } +// decode UTF8 +var dutf8 = function (d) { + for (var r = '', i = 0;;) { + var c = d[i++]; + var eb = (c > 127) + (c > 223) + (c > 239); + if (i + eb > d.length) + return { s: r, r: slc(d, i - 1) }; + if (!eb) + r += String.fromCharCode(c); + else if (eb == 3) { + c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)) - 65536, + r += String.fromCharCode(55296 | (c >> 10), 56320 | (c & 1023)); + } + else if (eb & 1) + r += String.fromCharCode((c & 31) << 6 | (d[i++] & 63)); + else + r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)); + } +}; +/** + * Streaming UTF-8 decoding + */ +var DecodeUTF8 = /*#__PURE__*/ (function () { + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is decoded + */ + function DecodeUTF8(cb) { + this.ondata = cb; + if (tds) + this.t = new TextDecoder(); + else + this.p = et; + } + /** + * Pushes a chunk to be decoded from UTF-8 binary + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + DecodeUTF8.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + final = !!final; + if (this.t) { + this.ondata(this.t.decode(chunk, { stream: true }), final); + if (final) { + if (this.t.decode().length) + err(8); + this.t = null; + } + return; + } + if (!this.p) + err(4); + var dat = new u8(this.p.length + chunk.length); + dat.set(this.p); + dat.set(chunk, this.p.length); + var _a = dutf8(dat), s = _a.s, r = _a.r; + if (final) { + if (r.length) + err(8); + this.p = null; + } + else + this.p = r; + this.ondata(s, final); + }; + return DecodeUTF8; +}()); +exports.DecodeUTF8 = DecodeUTF8; +/** + * Streaming UTF-8 encoding + */ +var EncodeUTF8 = /*#__PURE__*/ (function () { + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is encoded + */ + function EncodeUTF8(cb) { + this.ondata = cb; + } + /** + * Pushes a chunk to be encoded to UTF-8 + * @param chunk The string data to push + * @param final Whether this is the last chunk + */ + EncodeUTF8.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (this.d) + err(4); + this.ondata(strToU8(chunk), this.d = final || false); + }; + return EncodeUTF8; +}()); +exports.EncodeUTF8 = EncodeUTF8; +/** + * Converts a string into a Uint8Array for use with compression/decompression methods + * @param str The string to encode + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless decoding a binary string. + * @returns The string encoded in UTF-8/Latin-1 binary + */ +function strToU8(str, latin1) { + if (latin1) { + var ar_1 = new u8(str.length); + for (var i = 0; i < str.length; ++i) + ar_1[i] = str.charCodeAt(i); + return ar_1; + } + if (te) + return te.encode(str); + var l = str.length; + var ar = new u8(str.length + (str.length >> 1)); + var ai = 0; + var w = function (v) { ar[ai++] = v; }; + for (var i = 0; i < l; ++i) { + if (ai + 5 > ar.length) { + var n = new u8(ai + 8 + ((l - i) << 1)); + n.set(ar); + ar = n; + } + var c = str.charCodeAt(i); + if (c < 128 || latin1) + w(c); + else if (c < 2048) + w(192 | (c >> 6)), w(128 | (c & 63)); + else if (c > 55295 && c < 57344) + c = 65536 + (c & 1023 << 10) | (str.charCodeAt(++i) & 1023), + w(240 | (c >> 18)), w(128 | ((c >> 12) & 63)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63)); + else + w(224 | (c >> 12)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63)); + } + return slc(ar, 0, ai); +} +/** + * Converts a Uint8Array to a string + * @param dat The data to decode to string + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless encoding to binary string. + * @returns The original UTF-8/Latin-1 string + */ +function strFromU8(dat, latin1) { + if (latin1) { + var r = ''; + for (var i = 0; i < dat.length; i += 16384) + r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384)); + return r; + } + else if (td) { + return td.decode(dat); + } + else { + var _a = dutf8(dat), s = _a.s, r = _a.r; + if (r.length) + err(8); + return s; + } +} +; +// deflate bit flag +var dbf = function (l) { return l == 1 ? 3 : l < 6 ? 2 : l == 9 ? 1 : 0; }; +// skip local zip header +var slzh = function (d, b) { return b + 30 + b2(d, b + 26) + b2(d, b + 28); }; +// read zip header +var zh = function (d, b, z) { + var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl; + var _a = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a[0], su = _a[1], off = _a[2]; + return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off]; +}; +// read zip64 header sizes +var z64hs = function (d, b, l, z, sc, su, off) { + var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l; + var nf = nsc + nsu + noff; + if (z && nf) { + for (; b + 4 < e; b += 4 + b2(d, b + 2)) { + if (b2(d, b) == 1) { + return [ + nsc ? b8(d, b + 4 + 8 * nsu) : sc, + nsu ? b8(d, b + 4) : su, + noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off, + 1 + ]; + } + } + // z == 2 for unknown whether or not zip64 + if (z < 2) + err(13); + } + return [sc, su, off, 0]; +}; +// extra field length +var exfl = function (ex) { + var le = 0; + if (ex) { + for (var k in ex) { + var l = ex[k].length; + if (l > 65535) + err(9); + le += l + 4; + } + } + return le; +}; +// write zip header +var wzh = function (d, b, f, fn, u, c, ce, co) { + var fl = fn.length, ex = f.extra, col = co && co.length; + var exl = exfl(ex); + wbytes(d, b, ce != null ? 0x2014B50 : 0x4034B50), b += 4; + if (ce != null) + d[b++] = 20, d[b++] = f.os; + d[b] = 20, b += 2; // spec compliance? what's that? + d[b++] = (f.flag << 1) | (c < 0 && 8), d[b++] = u && 8; + d[b++] = f.compression & 255, d[b++] = f.compression >> 8; + var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980; + if (y < 0 || y > 119) + err(10); + wbytes(d, b, (y << 25) | ((dt.getMonth() + 1) << 21) | (dt.getDate() << 16) | (dt.getHours() << 11) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1)), b += 4; + if (c != -1) { + wbytes(d, b, f.crc); + wbytes(d, b + 4, c < 0 ? -c - 2 : c); + wbytes(d, b + 8, f.size); + } + wbytes(d, b + 12, fl); + wbytes(d, b + 14, exl), b += 16; + if (ce != null) { + wbytes(d, b, col); + wbytes(d, b + 6, f.attrs); + wbytes(d, b + 10, ce), b += 14; + } + d.set(fn, b); + b += fl; + if (exl) { + for (var k in ex) { + var exf = ex[k], l = exf.length; + wbytes(d, b, +k); + wbytes(d, b + 2, l); + d.set(exf, b + 4), b += 4 + l; + } + } + if (col) + d.set(co, b), b += col; + return b; +}; +// write zip footer (end of central directory) +var wzf = function (o, b, c, d, e) { + wbytes(o, b, 0x6054B50); // skip disk + wbytes(o, b + 8, c); + wbytes(o, b + 10, c); + wbytes(o, b + 12, d); + wbytes(o, b + 16, e); +}; +/** + * A pass-through stream to keep data uncompressed in a ZIP archive. + */ +var ZipPassThrough = /*#__PURE__*/ (function () { + /** + * Creates a pass-through stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + */ + function ZipPassThrough(filename) { + this.filename = filename; + this.c = crc(); + this.size = 0; + this.compression = 0; + } + /** + * Processes a chunk and pushes to the output stream. You can override this + * method in a subclass for custom behavior, but by default this passes + * the data through. You must call this.ondata(err, chunk, final) at some + * point in this method. + * @param chunk The chunk to process + * @param final Whether this is the last chunk + */ + ZipPassThrough.prototype.process = function (chunk, final) { + this.ondata(null, chunk, final); + }; + /** + * Pushes a chunk to be added. If you are subclassing this with a custom + * compression algorithm, note that you must push data from the source + * file only, pre-compression. + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + ZipPassThrough.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + this.c.p(chunk); + this.size += chunk.length; + if (final) + this.crc = this.c.d(); + // we shouldn't really do this cast, but properly handling ArrayBufferLike + // makes the API unergonomic with Buffer + this.process(chunk, final || false); + }; + return ZipPassThrough; +}()); +exports.ZipPassThrough = ZipPassThrough; +// I don't extend because TypeScript extension adds 1kB of runtime bloat +/** + * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate + * for better performance + */ +var ZipDeflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + function ZipDeflate(filename, opts) { + var _this = this; + if (!opts) + opts = {}; + ZipPassThrough.call(this, filename); + this.d = new Deflate(opts, function (dat, final) { + _this.ondata(null, dat, final); + }); + this.compression = 8; + this.flag = dbf(opts.level); + } + ZipDeflate.prototype.process = function (chunk, final) { + try { + this.d.push(chunk, final); + } + catch (e) { + this.ondata(e, null, final); + } + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + ZipDeflate.prototype.push = function (chunk, final) { + ZipPassThrough.prototype.push.call(this, chunk, final); + }; + return ZipDeflate; +}()); +exports.ZipDeflate = ZipDeflate; +/** + * Asynchronous streaming DEFLATE compression for ZIP archives + */ +var AsyncZipDeflate = /*#__PURE__*/ (function () { + /** + * Creates an asynchronous DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + function AsyncZipDeflate(filename, opts) { + var _this = this; + if (!opts) + opts = {}; + ZipPassThrough.call(this, filename); + this.d = new AsyncDeflate(opts, function (err, dat, final) { + _this.ondata(err, dat, final); + }); + this.compression = 8; + this.flag = dbf(opts.level); + this.terminate = this.d.terminate; + } + AsyncZipDeflate.prototype.process = function (chunk, final) { + this.d.push(chunk, final); + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + AsyncZipDeflate.prototype.push = function (chunk, final) { + ZipPassThrough.prototype.push.call(this, chunk, final); + }; + return AsyncZipDeflate; +}()); +exports.AsyncZipDeflate = AsyncZipDeflate; +// TODO: Better tree shaking +/** + * A zippable archive to which files can incrementally be added + */ +var Zip = /*#__PURE__*/ (function () { + /** + * Creates an empty ZIP archive to which files can be added + * @param cb The callback to call whenever data for the generated ZIP archive + * is available + */ + function Zip(cb) { + this.ondata = cb; + this.u = []; + this.d = 1; + } + /** + * Adds a file to the ZIP archive + * @param file The file stream to add + */ + Zip.prototype.add = function (file) { + var _this = this; + if (!this.ondata) + err(5); + // finishing or finished + if (this.d & 2) + this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, false); + else { + var f = strToU8(file.filename), fl_1 = f.length; + var com = file.comment, o = com && strToU8(com); + var u = fl_1 != file.filename.length || (o && (com.length != o.length)); + var hl_1 = fl_1 + exfl(file.extra) + 30; + if (fl_1 > 65535) + this.ondata(err(11, 0, 1), null, false); + var header = new u8(hl_1); + wzh(header, 0, file, f, u, -1); + var chks_1 = [header]; + var pAll_1 = function () { + for (var _i = 0, chks_2 = chks_1; _i < chks_2.length; _i++) { + var chk = chks_2[_i]; + _this.ondata(null, chk, false); + } + chks_1 = []; + }; + var tr_1 = this.d; + this.d = 0; + var ind_1 = this.u.length; + var uf_1 = mrg(file, { + f: f, + u: u, + o: o, + t: function () { + if (file.terminate) + file.terminate(); + }, + r: function () { + pAll_1(); + if (tr_1) { + var nxt = _this.u[ind_1 + 1]; + if (nxt) + nxt.r(); + else + _this.d = 1; + } + tr_1 = 1; + } + }); + var cl_1 = 0; + file.ondata = function (err, dat, final) { + if (err) { + _this.ondata(err, dat, final); + _this.terminate(); + } + else { + cl_1 += dat.length; + chks_1.push(dat); + if (final) { + var dd = new u8(16); + wbytes(dd, 0, 0x8074B50); + wbytes(dd, 4, file.crc); + wbytes(dd, 8, cl_1); + wbytes(dd, 12, file.size); + chks_1.push(dd); + uf_1.c = cl_1, uf_1.b = hl_1 + cl_1 + 16, uf_1.crc = file.crc, uf_1.size = file.size; + if (tr_1) + uf_1.r(); + tr_1 = 1; + } + else if (tr_1) + pAll_1(); + } + }; + this.u.push(uf_1); + } + }; + /** + * Ends the process of adding files and prepares to emit the final chunks. + * This *must* be called after adding all desired files for the resulting + * ZIP file to work properly. + */ + Zip.prototype.end = function () { + var _this = this; + if (this.d & 2) { + this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, true); + return; + } + if (this.d) + this.e(); + else + this.u.push({ + r: function () { + if (!(_this.d & 1)) + return; + _this.u.splice(-1, 1); + _this.e(); + }, + t: function () { } + }); + this.d = 3; + }; + Zip.prototype.e = function () { + var bt = 0, l = 0, tl = 0; + for (var _i = 0, _a = this.u; _i < _a.length; _i++) { + var f = _a[_i]; + tl += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0); + } + var out = new u8(tl + 22); + for (var _b = 0, _c = this.u; _b < _c.length; _b++) { + var f = _c[_b]; + wzh(out, bt, f, f.f, f.u, -f.c - 2, l, f.o); + bt += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0), l += f.b; + } + wzf(out, bt, this.u.length, tl, l); + this.ondata(null, out, true); + this.d = 2; + }; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to add() will fail. + */ + Zip.prototype.terminate = function () { + for (var _i = 0, _a = this.u; _i < _a.length; _i++) { + var f = _a[_i]; + f.t(); + } + this.d = 2; + }; + return Zip; +}()); +exports.Zip = Zip; +function zip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + var r = {}; + fltn(data, '', r, opts); + var k = Object.keys(r); + var lft = k.length, o = 0, tot = 0; + var slft = lft, files = new Array(lft); + var term = []; + var tAll = function () { + for (var i = 0; i < term.length; ++i) + term[i](); + }; + var cbd = function (a, b) { + mt(function () { cb(a, b); }); + }; + mt(function () { cbd = cb; }); + var cbf = function () { + var out = new u8(tot + 22), oe = o, cdl = tot - o; + tot = 0; + for (var i = 0; i < slft; ++i) { + var f = files[i]; + try { + var l = f.c.length; + wzh(out, tot, f, f.f, f.u, l); + var badd = 30 + f.f.length + exfl(f.extra); + var loc = tot + badd; + out.set(f.c, loc); + wzh(out, o, f, f.f, f.u, l, tot, f.m), o += 16 + badd + (f.m ? f.m.length : 0), tot = loc + l; + } + catch (e) { + return cbd(e, null); + } + } + wzf(out, o, files.length, cdl, oe); + cbd(null, out); + }; + if (!lft) + cbf(); + var _loop_1 = function (i) { + var fn = k[i]; + var _a = r[fn], file = _a[0], p = _a[1]; + var c = crc(), size = file.length; + c.p(file); + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + var compression = p.level == 0 ? 0 : 8; + var cbl = function (e, d) { + if (e) { + tAll(); + cbd(e, null); + } + else { + var l = d.length; + files[i] = mrg(p, { + size: size, + crc: c.d(), + c: d, + f: f, + m: m, + u: s != fn.length || (m && (com.length != ms)), + compression: compression + }); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + if (!--lft) + cbf(); + } + }; + if (s > 65535) + cbl(err(11, 0, 1), null); + if (!compression) + cbl(null, file); + else if (size < 160000) { + try { + cbl(null, deflateSync(file, p)); + } + catch (e) { + cbl(e, null); + } + } + else + term.push(deflate(file, p, cbl)); + }; + // Cannot use lft because it can decrease + for (var i = 0; i < slft; ++i) { + _loop_1(i); + } + return tAll; +} +/** + * Synchronously creates a ZIP file. Prefer using `zip` for better performance + * with more than one file. + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @returns The generated ZIP archive + */ +function zipSync(data, opts) { + if (!opts) + opts = {}; + var r = {}; + var files = []; + fltn(data, '', r, opts); + var o = 0; + var tot = 0; + for (var fn in r) { + var _a = r[fn], file = _a[0], p = _a[1]; + var compression = p.level == 0 ? 0 : 8; + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + if (s > 65535) + err(11); + var d = compression ? deflateSync(file, p) : file, l = d.length; + var c = crc(); + c.p(file); + files.push(mrg(p, { + size: file.length, + crc: c.d(), + c: d, + f: f, + m: m, + u: s != fn.length || (m && (com.length != ms)), + o: o, + compression: compression + })); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + } + var out = new u8(tot + 22), oe = o, cdl = tot - o; + for (var i = 0; i < files.length; ++i) { + var f = files[i]; + wzh(out, f.o, f, f.f, f.u, f.c.length); + var badd = 30 + f.f.length + exfl(f.extra); + out.set(f.c, f.o + badd); + wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0); + } + wzf(out, o, files.length, cdl, oe); + return out; +} +/** + * Streaming pass-through decompression for ZIP archives + */ +var UnzipPassThrough = /*#__PURE__*/ (function () { + function UnzipPassThrough() { + } + UnzipPassThrough.prototype.push = function (chunk, final) { + // same as ZipPassThrough: cast to retain Buffer ergonomics + this.ondata(null, chunk, final); + }; + UnzipPassThrough.compression = 0; + return UnzipPassThrough; +}()); +exports.UnzipPassThrough = UnzipPassThrough; +/** + * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for + * better performance. + */ +var UnzipInflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + function UnzipInflate() { + var _this = this; + this.i = new Inflate(function (dat, final) { + _this.ondata(null, dat, final); + }); + } + UnzipInflate.prototype.push = function (chunk, final) { + try { + this.i.push(chunk, final); + } + catch (e) { + this.ondata(e, null, final); + } + }; + UnzipInflate.compression = 8; + return UnzipInflate; +}()); +exports.UnzipInflate = UnzipInflate; +/** + * Asynchronous streaming DEFLATE decompression for ZIP archives + */ +var AsyncUnzipInflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + function AsyncUnzipInflate(_, sz) { + var _this = this; + if (sz < 320000) { + this.i = new Inflate(function (dat, final) { + _this.ondata(null, dat, final); + }); + } + else { + this.i = new AsyncInflate(function (err, dat, final) { + _this.ondata(err, dat, final); + }); + this.terminate = this.i.terminate; + } + } + AsyncUnzipInflate.prototype.push = function (chunk, final) { + if (this.i.terminate) + chunk = slc(chunk, 0); + this.i.push(chunk, final); + }; + AsyncUnzipInflate.compression = 8; + return AsyncUnzipInflate; +}()); +exports.AsyncUnzipInflate = AsyncUnzipInflate; +/** + * A ZIP archive decompression stream that emits files as they are discovered + */ +var Unzip = /*#__PURE__*/ (function () { + /** + * Creates a ZIP decompression stream + * @param cb The callback to call whenever a file in the ZIP archive is found + */ + function Unzip(cb) { + this.onfile = cb; + this.k = []; + this.o = { + 0: UnzipPassThrough + }; + this.p = et; + } + /** + * Pushes a chunk to be unzipped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Unzip.prototype.push = function (chunk, final) { + var _this = this; + if (!this.onfile) + err(5); + if (!this.p) + err(4); + if (this.c > 0) { + var len = Math.min(this.c, chunk.length); + var toAdd = chunk.subarray(0, len); + this.c -= len; + if (this.d) + this.d.push(toAdd, !this.c); + else + this.k[0].push(toAdd); + chunk = chunk.subarray(len); + if (chunk.length) + return this.push(chunk, final); + } + else { + var f = 0, i = 0, is = void 0, buf = void 0; + if (!this.p.length) + buf = chunk; + else if (!chunk.length) + buf = this.p; + else { + buf = new u8(this.p.length + chunk.length); + buf.set(this.p), buf.set(chunk, this.p.length); + } + var l = buf.length, oc = this.c, add = oc && this.d; + var _loop_2 = function () { + var sig = b4(buf, i); + if (sig == 0x4034B50) { + f = 1, is = i; + this_1.d = null; + this_1.c = 0; + var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28); + if (l > i + 30 + fnl + es) { + var chks_3 = []; + this_1.k.unshift(chks_3); + f = 2; + var lsc = b4(buf, i + 18), lsu = b4(buf, i + 22); + var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u); + var _a = z64hs(buf, i, es, 2, lsc, lsu, 0), sc_1 = _a[0], su_1 = _a[1], z64 = _a[3]; + if (dd) + sc_1 = -1 - z64; + i += es; + this_1.c = sc_1; + var d_1; + var file_1 = { + name: fn_1, + compression: cmp_1, + start: function () { + if (!file_1.ondata) + err(5); + if (!sc_1) + file_1.ondata(null, et, true); + else { + var ctr = _this.o[cmp_1]; + if (!ctr) + file_1.ondata(err(14, 'unknown compression type ' + cmp_1, 1), null, false); + d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1); + d_1.ondata = function (err, dat, final) { file_1.ondata(err, dat, final); }; + for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) { + var dat = chks_4[_i]; + d_1.push(dat, false); + } + if (_this.k[0] == chks_3 && _this.c) + _this.d = d_1; + else + d_1.push(et, true); + } + }, + terminate: function () { + if (d_1 && d_1.terminate) + d_1.terminate(); + } + }; + if (sc_1 >= 0) + file_1.size = sc_1, file_1.originalSize = su_1; + this_1.onfile(file_1); + } + return "break"; + } + else if (oc) { + if (sig == 0x8074B50) { + is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0; + return "break"; + } + else if (sig == 0x2014B50) { + is = i -= 4, f = 3, this_1.c = 0; + return "break"; + } + } + }; + var this_1 = this; + for (; i < l - 4; ++i) { + var state_1 = _loop_2(); + if (state_1 === "break") + break; + } + this.p = et; + if (oc < 0) { + var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 0x8074B50 && 4)) : buf.subarray(0, i); + if (add) + add.push(dat, !!f); + else + this.k[+(f == 2)].push(dat); + } + if (f & 2) + return this.push(buf.subarray(i), final); + this.p = buf.subarray(i); + } + if (final) { + if (this.c) + err(13); + this.p = null; + } + }; + /** + * Registers a decoder with the stream, allowing for files compressed with + * the compression type provided to be expanded correctly + * @param decoder The decoder constructor + */ + Unzip.prototype.register = function (decoder) { + this.o[decoder.compression] = decoder; + }; + return Unzip; +}()); +exports.Unzip = Unzip; +var mt = typeof queueMicrotask == 'function' ? queueMicrotask : typeof setTimeout == 'function' ? setTimeout : function (fn) { fn(); }; +function unzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + var term = []; + var tAll = function () { + for (var i = 0; i < term.length; ++i) + term[i](); + }; + var files = {}; + var cbd = function (a, b) { + mt(function () { cb(a, b); }); + }; + mt(function () { cbd = cb; }); + var e = data.length - 22; + for (; b4(data, e) != 0x6054B50; --e) { + if (!e || data.length - e > 65558) { + cbd(err(13, 0, 1), null); + return tAll; + } + } + ; + var lft = b2(data, e + 8); + if (lft) { + var c = lft; + var o = b4(data, e + 16); + var z = b4(data, e - 20) == 0x7064B50; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 0x6064B50; + if (z) { + c = lft = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + var _loop_3 = function (i) { + var _a = zh(data, o, z), c_1 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off); + o = no; + var cbl = function (e, d) { + if (e) { + tAll(); + cbd(e, null); + } + else { + if (d) + files[fn] = d; + if (!--lft) + cbd(null, files); + } + }; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_1 + })) { + if (!c_1) + cbl(null, slc(data, b, b + sc)); + else if (c_1 == 8) { + var infl = data.subarray(b, b + sc); + // Synchronously decompress under 512KB, or barely-compressed data + if (su < 524288 || sc > 0.8 * su) { + try { + cbl(null, inflateSync(infl, { out: new u8(su) })); + } + catch (e) { + cbl(e, null); + } + } + else + term.push(inflate(infl, { size: su }, cbl)); + } + else + cbl(err(14, 'unknown compression type ' + c_1, 1), null); + } + else + cbl(null, null); + }; + for (var i = 0; i < c; ++i) { + _loop_3(i); + } + } + else + cbd(null, {}); + return tAll; +} +/** + * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better + * performance with more than one file. + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @returns The decompressed files + */ +function unzipSync(data, opts) { + var files = {}; + var e = data.length - 22; + for (; b4(data, e) != 0x6054B50; --e) { + if (!e || data.length - e > 65558) + err(13); + } + ; + var c = b2(data, e + 8); + if (!c) + return {}; + var o = b4(data, e + 16); + var z = b4(data, e - 20) == 0x7064B50; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 0x6064B50; + if (z) { + c = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + for (var i = 0; i < c; ++i) { + var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off); + o = no; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_2 + })) { + if (!c_2) + files[fn] = slc(data, b, b + sc); + else if (c_2 == 8) + files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) }); + else + err(14, 'unknown compression type ' + c_2); + } + } + return files; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/index.d.ts new file mode 100644 index 0000000..d430faf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/index.d.ts @@ -0,0 +1,1539 @@ +/** + * Codes for errors generated within this library + */ +export declare const FlateErrorCode: { + readonly UnexpectedEOF: 0; + readonly InvalidBlockType: 1; + readonly InvalidLengthLiteral: 2; + readonly InvalidDistance: 3; + readonly StreamFinished: 4; + readonly NoStreamHandler: 5; + readonly InvalidHeader: 6; + readonly NoCallback: 7; + readonly InvalidUTF8: 8; + readonly ExtraFieldTooLong: 9; + readonly InvalidDate: 10; + readonly FilenameTooLong: 11; + readonly StreamFinishing: 12; + readonly InvalidZipData: 13; + readonly UnknownCompressionMethod: 14; +}; +/** + * An error generated within this library + */ +export interface FlateError extends Error { + /** + * The code associated with this error + */ + code: number; +} +/** + * Options for decompressing a DEFLATE stream + */ +export interface InflateStreamOptions { + /** + * The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect. + * + * Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error. + */ + dictionary?: Uint8Array; +} +/** + * Options for decompressing DEFLATE data + */ +export interface InflateOptions extends InflateStreamOptions { + /** + * The buffer into which to write the decompressed data. Saves memory if you know the decompressed size in advance. + * + * Note that if the decompression result is larger than the size of this buffer, it will be truncated to fit. + */ + out?: Uint8Array; +} +/** + * Options for decompressing a GZIP stream + */ +export interface GunzipStreamOptions extends InflateStreamOptions { +} +/** + * Options for decompressing GZIP data + */ +export interface GunzipOptions extends InflateStreamOptions { + /** + * The buffer into which to write the decompressed data. GZIP already encodes the output size, so providing this doesn't save memory. + * + * Note that if the decompression result is larger than the size of this buffer, it will be truncated to fit. + */ + out?: Uint8Array; +} +/** + * Options for decompressing a Zlib stream + */ +export interface UnzlibStreamOptions extends InflateStreamOptions { +} +/** + * Options for decompressing Zlib data + */ +export interface UnzlibOptions extends InflateOptions { +} +/** + * Options for compressing data into a DEFLATE format + */ +export interface DeflateOptions { + /** + * The level of compression to use, ranging from 0-9. + * + * 0 will store the data without compression. + * 1 is fastest but compresses the worst, 9 is slowest but compresses the best. + * The default level is 6. + * + * Typically, binary data benefits much more from higher values than text data. + * In both cases, higher values usually take disproportionately longer than the reduction in final size that results. + * + * For example, a 1 MB text file could: + * - become 1.01 MB with level 0 in 1ms + * - become 400 kB with level 1 in 10ms + * - become 320 kB with level 9 in 100ms + */ + level?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; + /** + * The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory. + * + * Note that this is exponential: while level 0 uses 8 kB, level 4 uses 128 kB, level 8 uses 2 MB, and level 12 uses 32 MB. + * It is recommended not to lower the value below 4, since that tends to hurt performance. + * In addition, values above 8 tend to help very little on most data and can even hurt performance. + * + * The default value is automatically determined based on the size of the input data. + */ + mem?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + /** + * A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios. + * + * Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input. + * The decompressor must supply the same dictionary as the compressor to extract the original data. + * + * Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise. + * + * Avoid using dictionaries with GZIP and ZIP to maximize software compatibility. + */ + dictionary?: Uint8Array; +} +/** + * Options for compressing data into a GZIP format + */ +export interface GzipOptions extends DeflateOptions { + /** + * When the file was last modified. Defaults to the current time. + * Set this to 0 to avoid revealing a modification date entirely. + */ + mtime?: Date | string | number; + /** + * The filename of the data. If the `gunzip` command is used to decompress the data, it will output a file + * with this name instead of the name of the compressed file. + */ + filename?: string; +} +/** + * Options for compressing data into a Zlib format + */ +export interface ZlibOptions extends DeflateOptions { +} +/** + * Handler for data (de)compression streams + * @param data The data output from the stream processor + * @param final Whether this is the final block + */ +export type FlateStreamHandler = (data: Uint8Array, final: boolean) => void; +/** + * Handler for asynchronous data (de)compression streams + * @param err Any error that occurred + * @param data The data output from the stream processor + * @param final Whether this is the final block + */ +export type AsyncFlateStreamHandler = (err: FlateError | null, data: Uint8Array, final: boolean) => void; +/** + * Handler for the asynchronous completion of (de)compression for a data chunk + * @param size The number of bytes that were processed. This is measured in terms of the input + * (i.e. compressed bytes for decompression, uncompressed bytes for compression.) + */ +export type AsyncFlateDrainHandler = (size: number) => void; +/** + * Callback for asynchronous (de)compression methods + * @param err Any error that occurred + * @param data The resulting data. Only present if `err` is null + */ +export type FlateCallback = (err: FlateError | null, data: Uint8Array) => void; +interface AsyncOptions { + /** + * Whether or not to "consume" the source data. This will make the typed array/buffer you pass in + * unusable but will increase performance and reduce memory usage. + */ + consume?: boolean; +} +/** + * Options for compressing data asynchronously into a DEFLATE format + */ +export interface AsyncDeflateOptions extends DeflateOptions, AsyncOptions { +} +/** + * Options for decompressing DEFLATE data asynchronously + */ +export interface AsyncInflateOptions extends AsyncOptions, InflateStreamOptions { + /** + * The original size of the data. Currently, the asynchronous API disallows + * writing into a buffer you provide; the best you can do is provide the + * size in bytes and be given back a new typed array. + */ + size?: number; +} +/** + * Options for compressing data asynchronously into a GZIP format + */ +export interface AsyncGzipOptions extends GzipOptions, AsyncOptions { +} +/** + * Options for decompressing GZIP data asynchronously + */ +export interface AsyncGunzipOptions extends AsyncOptions, InflateStreamOptions { +} +/** + * Options for compressing data asynchronously into a Zlib format + */ +export interface AsyncZlibOptions extends ZlibOptions, AsyncOptions { +} +/** + * Options for decompressing Zlib data asynchronously + */ +export interface AsyncUnzlibOptions extends AsyncInflateOptions { +} +/** + * A terminable compression/decompression process + */ +export interface AsyncTerminable { + /** + * Terminates the worker thread immediately. The callback will not be called. + */ + (): void; +} +/** + * Streaming DEFLATE compression + */ +export declare class Deflate { + /** + * Creates a DEFLATE stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: DeflateOptions, cb?: FlateStreamHandler); + /** + * Creates a DEFLATE stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + private b; + private s; + private o; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + private p; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE compression + */ +export declare class AsyncDeflate { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous DEFLATE stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: DeflateOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous DEFLATE stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function deflate(data: Uint8Array, opts: AsyncDeflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param cb The function to be called upon compression completion + */ +export declare function deflate(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @returns The deflated version of the data + */ +export declare function deflateSync(data: Uint8Array, opts?: DeflateOptions): Uint8Array; +/** + * Streaming DEFLATE decompression + */ +export declare class Inflate { + private s; + private o; + private p; + private d; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a DEFLATE decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: InflateStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a DEFLATE decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + private e; + private c; + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the final chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE decompression + */ +export declare class AsyncInflate { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous DEFLATE decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: InflateStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous DEFLATE decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function inflate(data: Uint8Array, opts: AsyncInflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function inflate(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands DEFLATE data with no wrapper + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function inflateSync(data: Uint8Array): Uint8Array; +/** + * Expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function inflateSync(data: Uint8Array, opts?: InflateOptions): Uint8Array; +/** + * Streaming GZIP compression + */ +export declare class Gzip { + private c; + private l; + private v; + private o; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a GZIP stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: GzipOptions, cb?: FlateStreamHandler); + /** + * Creates a GZIP stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + private p; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming GZIP compression + */ +export declare class AsyncGzip { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous GZIP stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: GzipOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous GZIP stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function gzip(data: Uint8Array, opts: AsyncGzipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with GZIP + * @param data The data to compress + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gzip(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @returns The gzipped version of the data + */ +export declare function gzipSync(data: Uint8Array, opts?: GzipOptions): Uint8Array; +/** + * Handler for new GZIP members in concatenated GZIP streams. Useful for building indices used to perform random-access reads on compressed files. + * @param offset The offset of the new member relative to the start of the stream + */ +export type GunzipMemberHandler = (offset: number) => void; +/** + * Streaming single or multi-member GZIP decompression + */ +export declare class Gunzip { + private v; + private r; + private o; + private p; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * The handler to call whenever a new GZIP member is found + */ + onmember?: GunzipMemberHandler; + /** + * Creates a GUNZIP stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: GunzipStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a GUNZIP stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming single or multi-member GZIP decompression + */ +export declare class AsyncGunzip { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * The handler to call whenever a new GZIP member is found + */ + onmember?: GunzipMemberHandler; + /** + * Creates an asynchronous GUNZIP stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: GunzipStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous GUNZIP stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands GZIP data + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gunzip(data: Uint8Array, opts: AsyncGunzipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands GZIP data + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gunzip(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands GZIP data + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function gunzipSync(data: Uint8Array): Uint8Array; +/** + * Expands GZIP data + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function gunzipSync(data: Uint8Array, opts?: GunzipOptions): Uint8Array; +/** + * Streaming Zlib compression + */ +export declare class Zlib { + private c; + private v; + private o; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a Zlib stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: ZlibOptions, cb?: FlateStreamHandler); + /** + * Creates a Zlib stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be zlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + private p; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming Zlib compression + */ +export declare class AsyncZlib { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous Zlib stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: ZlibOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous Zlib stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with Zlib + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + */ +export declare function zlib(data: Uint8Array, opts: AsyncZlibOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with Zlib + * @param data The data to compress + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zlib(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compress data with Zlib + * @param data The data to compress + * @param opts The compression options + * @returns The zlib-compressed version of the data + */ +export declare function zlibSync(data: Uint8Array, opts?: ZlibOptions): Uint8Array; +/** + * Streaming Zlib decompression + */ +export declare class Unzlib { + private v; + private p; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a Zlib decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: UnzlibStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a Zlib decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be unzlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming Zlib decompression + */ +export declare class AsyncUnzlib { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous Zlib decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: UnzlibStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous Zlib decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be decompressed from Zlib + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands Zlib data + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function unzlib(data: Uint8Array, opts: AsyncUnzlibOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands Zlib data + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function unzlib(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands Zlib data + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function unzlibSync(data: Uint8Array): Uint8Array; +/** + * Expands Zlib data + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function unzlibSync(data: Uint8Array, opts?: UnzlibOptions): Uint8Array; +export { gzip as compress, AsyncGzip as AsyncCompress }; +export { gzipSync as compressSync, Gzip as Compress }; +/** + * Streaming GZIP, Zlib, or raw DEFLATE decompression + */ +export declare class Decompress { + private G; + private I; + private Z; + private o; + private s; + private p; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is decompressed + */ + constructor(opts: InflateStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a decompression stream + * @param cb The callback to call whenever data is decompressed + */ + constructor(cb?: FlateStreamHandler); + private i; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression + */ +export declare class AsyncDecompress { + private G; + private I; + private Z; + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is decompressed + */ + constructor(opts: InflateStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous decompression stream + * @param cb The callback to call whenever data is decompressed + */ + constructor(cb?: AsyncFlateStreamHandler); + private i; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchrononously expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function decompress(data: Uint8Array, opts: AsyncInflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchrononously expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function decompress(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function decompressSync(data: Uint8Array, opts?: InflateOptions): Uint8Array; +/** + * Attributes for files added to a ZIP archive object + */ +export interface ZipAttributes { + /** + * The operating system of origin for this file. The value is defined + * by PKZIP's APPNOTE.txt, section 4.4.2.2. For example, 0 (the default) + * is MS/DOS, 3 is Unix, 19 is macOS. + */ + os?: number; + /** + * The file's attributes. These are traditionally somewhat complicated + * and platform-dependent, so using them is scarcely necessary. However, + * here is a representation of what this is, bit by bit: + * + * `TTTTugtrwxrwxrwx0000000000ADVSHR` + * + * TTTT = file type (rarely useful) + * + * u = setuid, g = setgid, t = sticky + * + * rwx = user permissions, rwx = group permissions, rwx = other permissions + * + * 0000000000 = unused + * + * A = archive, D = directory, V = volume label, S = system file, H = hidden, R = read-only + * + * If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0o644 << 16. + * Note that attributes usually only work in conjunction with the `os` setting: you must use + * `os` = 3 (Unix) if you want to set Unix permissions + */ + attrs?: number; + /** + * Extra metadata to add to the file. This field is defined by PKZIP's APPNOTE.txt, + * section 4.4.28. At most 65,535 bytes may be used in each ID. The ID must be an + * integer between 0 and 65,535, inclusive. + * + * This field is incredibly rare and almost never needed except for compliance with + * proprietary standards and software. + */ + extra?: Record; + /** + * The comment to attach to the file. This field is defined by PKZIP's APPNOTE.txt, + * section 4.4.26. The comment must be at most 65,535 bytes long UTF-8 encoded. This + * field is not read by consumer software. + */ + comment?: string; + /** + * When the file was last modified. Defaults to the current time. + */ + mtime?: GzipOptions['mtime']; +} +/** + * Options for creating a ZIP archive + */ +export interface ZipOptions extends DeflateOptions, ZipAttributes { +} +/** + * Options for expanding a ZIP archive + */ +export interface UnzipOptions { + /** + * A filter function to extract only certain files from a ZIP archive + */ + filter?: UnzipFileFilter; +} +/** + * Options for asynchronously creating a ZIP archive + */ +export interface AsyncZipOptions extends AsyncDeflateOptions, ZipAttributes { +} +/** + * Options for asynchronously expanding a ZIP archive + */ +export interface AsyncUnzipOptions extends UnzipOptions { +} +/** + * A file that can be used to create a ZIP archive + */ +export type ZippableFile = Uint8Array | Zippable | [Uint8Array | Zippable, ZipOptions]; +/** + * A file that can be used to asynchronously create a ZIP archive + */ +export type AsyncZippableFile = Uint8Array | AsyncZippable | [Uint8Array | AsyncZippable, AsyncZipOptions]; +/** + * The complete directory structure of a ZIPpable archive + */ +export interface Zippable { + [path: string]: ZippableFile; +} +/** + * The complete directory structure of an asynchronously ZIPpable archive + */ +export interface AsyncZippable { + [path: string]: AsyncZippableFile; +} +/** + * An unzipped archive. The full path of each file is used as the key, + * and the file is the value + */ +export interface Unzipped { + [path: string]: Uint8Array; +} +/** + * Handler for string generation streams + * @param data The string output from the stream processor + * @param final Whether this is the final block + */ +export type StringStreamHandler = (data: string, final: boolean) => void; +/** + * Callback for asynchronous ZIP decompression + * @param err Any error that occurred + * @param data The decompressed ZIP archive + */ +export type UnzipCallback = (err: FlateError | null, data: Unzipped) => void; +/** + * Handler for streaming ZIP decompression + * @param file The file that was found in the archive + */ +export type UnzipFileHandler = (file: UnzipFile) => void; +/** + * Streaming UTF-8 decoding + */ +export declare class DecodeUTF8 { + private p; + private t; + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is decoded + */ + constructor(cb?: StringStreamHandler); + /** + * Pushes a chunk to be decoded from UTF-8 binary + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * The handler to call whenever data is available + */ + ondata: StringStreamHandler; +} +/** + * Streaming UTF-8 encoding + */ +export declare class EncodeUTF8 { + private d; + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is encoded + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be encoded to UTF-8 + * @param chunk The string data to push + * @param final Whether this is the last chunk + */ + push(chunk: string, final?: boolean): void; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; +} +/** + * Converts a string into a Uint8Array for use with compression/decompression methods + * @param str The string to encode + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless decoding a binary string. + * @returns The string encoded in UTF-8/Latin-1 binary + */ +export declare function strToU8(str: string, latin1?: boolean): Uint8Array; +/** + * Converts a Uint8Array to a string + * @param dat The data to decode to string + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless encoding to binary string. + * @returns The original UTF-8/Latin-1 string + */ +export declare function strFromU8(dat: Uint8Array, latin1?: boolean): string; +/** + * A stream that can be used to create a file in a ZIP archive + */ +export interface ZipInputFile extends ZipAttributes { + /** + * The filename to associate with the data provided to this stream. If you + * want a file in a subdirectory, use forward slashes as a separator (e.g. + * `directory/filename.ext`). This will still work on Windows. + */ + filename: string; + /** + * The size of the file in bytes. This attribute may be invalid after + * the file is added to the ZIP archive; it must be correct only before the + * stream completes. + * + * If you don't want to have to compute this yourself, consider extending the + * ZipPassThrough class and overriding its process() method, or using one of + * ZipDeflate or AsyncZipDeflate. + */ + size: number; + /** + * A CRC of the original file contents. This attribute may be invalid after + * the file is added to the ZIP archive; it must be correct only before the + * stream completes. + * + * If you don't want to have to generate this yourself, consider extending the + * ZipPassThrough class and overriding its process() method, or using one of + * ZipDeflate or AsyncZipDeflate. + */ + crc: number; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA + */ + compression: number; + /** + * Bits 1 and 2 of the general purpose bit flag, specified in PKZIP's + * APPNOTE.txt, section 4.4.4. Should be between 0 and 3. This is unlikely + * to be necessary. + */ + flag?: number; + /** + * The handler to be called when data is added. After passing this stream to + * the ZIP file object, this handler will always be defined. To call it: + * + * `stream.ondata(error, chunk, final)` + * + * error = any error that occurred (null if there was no error) + * + * chunk = a Uint8Array of the data that was added (null if there was an + * error) + * + * final = boolean, whether this is the final chunk in the stream + */ + ondata?: AsyncFlateStreamHandler; + /** + * A method called when the stream is no longer needed, for clean-up + * purposes. This will not always be called after the stream completes, + * so you may wish to call this.terminate() after the final chunk is + * processed if you have clean-up logic. + */ + terminate?: AsyncTerminable; +} +/** + * A pass-through stream to keep data uncompressed in a ZIP archive. + */ +export declare class ZipPassThrough implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private c; + /** + * Creates a pass-through stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + */ + constructor(filename: string); + /** + * Processes a chunk and pushes to the output stream. You can override this + * method in a subclass for custom behavior, but by default this passes + * the data through. You must call this.ondata(err, chunk, final) at some + * point in this method. + * @param chunk The chunk to process + * @param final Whether this is the last chunk + */ + protected process(chunk: Uint8Array, final: boolean): void; + /** + * Pushes a chunk to be added. If you are subclassing this with a custom + * compression algorithm, note that you must push data from the source + * file only, pre-compression. + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate + * for better performance + */ +export declare class ZipDeflate implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + flag: 0 | 1 | 2 | 3; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private d; + /** + * Creates a DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + constructor(filename: string, opts?: DeflateOptions); + private process; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE compression for ZIP archives + */ +export declare class AsyncZipDeflate implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + flag: 0 | 1 | 2 | 3; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private d; + terminate: AsyncTerminable; + /** + * Creates an asynchronous DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + constructor(filename: string, opts?: DeflateOptions); + private process; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * A zippable archive to which files can incrementally be added + */ +export declare class Zip { + private u; + private d; + /** + * Creates an empty ZIP archive to which files can be added + * @param cb The callback to call whenever data for the generated ZIP archive + * is available + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Adds a file to the ZIP archive + * @param file The file stream to add + */ + add(file: ZipInputFile): void; + /** + * Ends the process of adding files and prepares to emit the final chunks. + * This *must* be called after adding all desired files for the resulting + * ZIP file to work properly. + */ + end(): void; + private e; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to add() will fail. + */ + terminate(): void; + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; +} +/** + * Asynchronously creates a ZIP file + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @param cb The callback to call with the generated ZIP archive + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zip(data: AsyncZippable, opts: AsyncZipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously creates a ZIP file + * @param data The directory structure for the ZIP archive + * @param cb The callback to call with the generated ZIP archive + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zip(data: AsyncZippable, cb: FlateCallback): AsyncTerminable; +/** + * Synchronously creates a ZIP file. Prefer using `zip` for better performance + * with more than one file. + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @returns The generated ZIP archive + */ +export declare function zipSync(data: Zippable, opts?: ZipOptions): Uint8Array; +/** + * A decoder for files in ZIP streams + */ +export interface UnzipDecoder { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * Pushes a chunk to be decompressed + * @param chunk The data in this chunk. Do not consume (detach) this buffer. + * @param final Whether this is the last chunk in the data stream + */ + push(chunk: Uint8Array, final: boolean): void; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to push() should silently fail. + */ + terminate?: AsyncTerminable; +} +/** + * A constructor for a decoder for unzip streams + */ +export interface UnzipDecoderConstructor { + /** + * Creates an instance of the decoder + * @param filename The name of the file + * @param size The compressed size of the file + * @param originalSize The original size of the file + */ + new (filename: string, size?: number, originalSize?: number): UnzipDecoder; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA + */ + compression: number; +} +/** + * Information about a file to be extracted from a ZIP archive + */ +export interface UnzipFileInfo { + /** + * The name of the file + */ + name: string; + /** + * The compressed size of the file + */ + size: number; + /** + * The original size of the file + */ + originalSize: number; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA. If the filter function returns true + * but this value is not 8, the unzip function will throw. + */ + compression: number; +} +/** + * A filter for files to be extracted during the unzipping process + * @param file The info for the current file being processed + * @returns Whether or not to extract the current file + */ +export type UnzipFileFilter = (file: UnzipFileInfo) => boolean; +/** + * Streaming file extraction from ZIP archives + */ +export interface UnzipFile { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The name of the file + */ + name: string; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA. If start() is called but there is no + * decompression stream available for this method, start() will throw. + */ + compression: number; + /** + * The compressed size of the file. Will not be present for archives created + * in a streaming fashion. + */ + size?: number; + /** + * The original size of the file. Will not be present for archives created + * in a streaming fashion. + */ + originalSize?: number; + /** + * Starts reading from the stream. Calling this function will always enable + * this stream, but ocassionally the stream will be enabled even without + * this being called. + */ + start(): void; + /** + * A method to terminate any internal workers used by the stream. ondata + * will not be called any further. + */ + terminate: AsyncTerminable; +} +/** + * Streaming pass-through decompression for ZIP archives + */ +export declare class UnzipPassThrough implements UnzipDecoder { + static compression: number; + ondata: AsyncFlateStreamHandler; + push(chunk: Uint8Array, final: boolean): void; +} +/** + * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for + * better performance. + */ +export declare class UnzipInflate implements UnzipDecoder { + static compression: number; + private i; + ondata: AsyncFlateStreamHandler; + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + constructor(); + push(chunk: Uint8Array, final: boolean): void; +} +/** + * Asynchronous streaming DEFLATE decompression for ZIP archives + */ +export declare class AsyncUnzipInflate implements UnzipDecoder { + static compression: number; + private i; + ondata: AsyncFlateStreamHandler; + terminate: AsyncTerminable; + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + constructor(_: string, sz?: number); + push(chunk: Uint8Array, final: boolean): void; +} +/** + * A ZIP archive decompression stream that emits files as they are discovered + */ +export declare class Unzip { + private d; + private c; + private p; + private k; + private o; + /** + * Creates a ZIP decompression stream + * @param cb The callback to call whenever a file in the ZIP archive is found + */ + constructor(cb?: UnzipFileHandler); + /** + * Pushes a chunk to be unzipped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Registers a decoder with the stream, allowing for files compressed with + * the compression type provided to be expanded correctly + * @param decoder The decoder constructor + */ + register(decoder: UnzipDecoderConstructor): void; + /** + * The handler to call whenever a file is discovered + */ + onfile: UnzipFileHandler; +} +/** + * Asynchronously decompresses a ZIP archive + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @param cb The callback to call with the decompressed files + * @returns A function that can be used to immediately terminate the unzipping + */ +export declare function unzip(data: Uint8Array, opts: AsyncUnzipOptions, cb: UnzipCallback): AsyncTerminable; +/** + * Asynchronously decompresses a ZIP archive + * @param data The raw compressed ZIP file + * @param cb The callback to call with the decompressed files + * @returns A function that can be used to immediately terminate the unzipping + */ +export declare function unzip(data: Uint8Array, cb: UnzipCallback): AsyncTerminable; +/** + * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better + * performance with more than one file. + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @returns The decompressed files + */ +export declare function unzipSync(data: Uint8Array, opts?: UnzipOptions): Unzipped; diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node-worker.cjs b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node-worker.cjs new file mode 100644 index 0000000..6546f8e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node-worker.cjs @@ -0,0 +1,36 @@ +"use strict"; +var _a; +// Mediocre shim +var Worker; +var isMarkedAsUntransferable; +var workerAdd = ";var __w=require('worker_threads');__w.parentPort.on('message',function(m){onmessage({data:m})}),postMessage=function(m,t){__w.parentPort.postMessage(m,t)},close=process.exit;self=global"; +try { + (_a = require('worker_threads'), Worker = _a.Worker, isMarkedAsUntransferable = _a.isMarkedAsUntransferable); +} +catch (e) { +} +exports.default = Worker ? function (c, _, msg, transfer, cb) { + var done = false; + var w = new Worker(c + workerAdd, { eval: true }) + .on('error', function (e) { return cb(e, null); }) + .on('message', function (m) { return cb(null, m); }) + .on('exit', function (c) { + if (c && !done) + cb(new Error('exited with code ' + c), null); + }); + if (isMarkedAsUntransferable) + transfer = transfer.filter(function (t) { return !isMarkedAsUntransferable(t); }); + w.postMessage(msg, transfer); + w.terminate = function () { + done = true; + return Worker.prototype.terminate.call(w); + }; + return w; +} : function (_, __, ___, ____, cb) { + setImmediate(function () { return cb(new Error('async operations unsupported - update to Node 12+ (or Node 10-11 with the --experimental-worker CLI flag)'), null); }); + var NOP = function () { }; + return { + terminate: NOP, + postMessage: NOP + }; +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node.cjs b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node.cjs new file mode 100644 index 0000000..2af184e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node.cjs @@ -0,0 +1,2733 @@ +"use strict"; +// DEFLATE is a complex format; to read this code, you should probably check the RFC first: +// https://tools.ietf.org/html/rfc1951 +// You may also wish to take a look at the guide I made about this program: +// https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad +exports.deflate = deflate; +exports.deflateSync = deflateSync; +exports.inflate = inflate; +exports.inflateSync = inflateSync; +exports.gzip = gzip; +exports.compress = gzip; +exports.gzipSync = gzipSync; +exports.compressSync = gzipSync; +exports.gunzip = gunzip; +exports.gunzipSync = gunzipSync; +exports.zlib = zlib; +exports.zlibSync = zlibSync; +exports.unzlib = unzlib; +exports.unzlibSync = unzlibSync; +exports.gzip = gzip; +exports.compress = gzip; +exports.decompress = decompress; +exports.decompressSync = decompressSync; +exports.strToU8 = strToU8; +exports.strFromU8 = strFromU8; +exports.zip = zip; +exports.zipSync = zipSync; +exports.unzip = unzip; +exports.unzipSync = unzipSync; +// Some of the following code is similar to that of UZIP.js: +// https://github.com/photopea/UZIP.js +// However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size. +// Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint +// is better for memory in most engines (I *think*). +var _a; +// Mediocre shim +var Worker; +var isMarkedAsUntransferable; +var workerAdd = ";var __w=require('worker_threads');__w.parentPort.on('message',function(m){onmessage({data:m})}),postMessage=function(m,t){__w.parentPort.postMessage(m,t)},close=process.exit;self=global"; +try { + (_a = require('worker_threads'), Worker = _a.Worker, isMarkedAsUntransferable = _a.isMarkedAsUntransferable); +} +catch (e) { +} +var node_worker_1 = {}; +node_worker_1["default"] = Worker ? function (c, _, msg, transfer, cb) { + var done = false; + var w = new Worker(c + workerAdd, { eval: true }) + .on('error', function (e) { return cb(e, null); }) + .on('message', function (m) { return cb(null, m); }) + .on('exit', function (c) { + if (c && !done) + cb(new Error('exited with code ' + c), null); + }); + if (isMarkedAsUntransferable) + transfer = transfer.filter(function (t) { return !isMarkedAsUntransferable(t); }); + w.postMessage(msg, transfer); + w.terminate = function () { + done = true; + return Worker.prototype.terminate.call(w); + }; + return w; +} : function (_, __, ___, ____, cb) { + setImmediate(function () { return cb(new Error('async operations unsupported - update to Node 12+ (or Node 10-11 with the --experimental-worker CLI flag)'), null); }); + var NOP = function () { }; + return { + terminate: NOP, + postMessage: NOP + }; +}; + +// aliases for shorter compressed code (most minifers don't do this) +var u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array; +// fixed length extra bits +var fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]); +// fixed distance extra bits +var fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]); +// code length index map +var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); +// get base, reverse index map from extra bits +var freb = function (eb, start) { + var b = new u16(31); + for (var i = 0; i < 31; ++i) { + b[i] = start += 1 << eb[i - 1]; + } + // numbers here are at max 18 bits + var r = new i32(b[30]); + for (var i = 1; i < 30; ++i) { + for (var j = b[i]; j < b[i + 1]; ++j) { + r[j] = ((j - b[i]) << 5) | i; + } + } + return { b: b, r: r }; +}; +var _a = freb(fleb, 2), fl = _a.b, revfl = _a.r; +// we can ignore the fact that the other numbers are wrong; they never happen anyway +fl[28] = 258, revfl[258] = 28; +var _b = freb(fdeb, 0), fd = _b.b, revfd = _b.r; +// map of value to reverse (assuming 16 bits) +var rev = new u16(32768); +for (var i = 0; i < 32768; ++i) { + // reverse table algorithm from SO + var x = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1); + x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2); + x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4); + rev[i] = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) >> 1; +} +// create huffman tree from u8 "map": index -> code length for code index +// mb (max bits) must be at most 15 +// TODO: optimize/split up? +var hMap = (function (cd, mb, r) { + var s = cd.length; + // index + var i = 0; + // u16 "map": index -> # of codes with bit length = index + var l = new u16(mb); + // length of cd must be 288 (total # of codes) + for (; i < s; ++i) { + if (cd[i]) + ++l[cd[i] - 1]; + } + // u16 "map": index -> minimum code for bit length = index + var le = new u16(mb); + for (i = 1; i < mb; ++i) { + le[i] = (le[i - 1] + l[i - 1]) << 1; + } + var co; + if (r) { + // u16 "map": index -> number of actual bits, symbol for code + co = new u16(1 << mb); + // bits to remove for reverser + var rvb = 15 - mb; + for (i = 0; i < s; ++i) { + // ignore 0 lengths + if (cd[i]) { + // num encoding both symbol and bits read + var sv = (i << 4) | cd[i]; + // free bits + var r_1 = mb - cd[i]; + // start value + var v = le[cd[i] - 1]++ << r_1; + // m is end value + for (var m = v | ((1 << r_1) - 1); v <= m; ++v) { + // every 16 bit value starting with the code yields the same result + co[rev[v] >> rvb] = sv; + } + } + } + } + else { + co = new u16(s); + for (i = 0; i < s; ++i) { + if (cd[i]) { + co[i] = rev[le[cd[i] - 1]++] >> (15 - cd[i]); + } + } + } + return co; +}); +// fixed length tree +var flt = new u8(288); +for (var i = 0; i < 144; ++i) + flt[i] = 8; +for (var i = 144; i < 256; ++i) + flt[i] = 9; +for (var i = 256; i < 280; ++i) + flt[i] = 7; +for (var i = 280; i < 288; ++i) + flt[i] = 8; +// fixed distance tree +var fdt = new u8(32); +for (var i = 0; i < 32; ++i) + fdt[i] = 5; +// fixed length map +var flm = /*#__PURE__*/ hMap(flt, 9, 0), flrm = /*#__PURE__*/ hMap(flt, 9, 1); +// fixed distance map +var fdm = /*#__PURE__*/ hMap(fdt, 5, 0), fdrm = /*#__PURE__*/ hMap(fdt, 5, 1); +// find max of array +var max = function (a) { + var m = a[0]; + for (var i = 1; i < a.length; ++i) { + if (a[i] > m) + m = a[i]; + } + return m; +}; +// read d, starting at bit p and mask with m +var bits = function (d, p, m) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m; +}; +// read d, starting at bit p continuing for at least 16 bits +var bits16 = function (d, p) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7)); +}; +// get end of byte +var shft = function (p) { return ((p + 7) / 8) | 0; }; +// typed array slice - allows garbage collector to free original reference, +// while being more compatible than .slice +var slc = function (v, s, e) { + if (s == null || s < 0) + s = 0; + if (e == null || e > v.length) + e = v.length; + // can't use .constructor in case user-supplied + return new u8(v.subarray(s, e)); +}; +/** + * Codes for errors generated within this library + */ +exports.FlateErrorCode = { + UnexpectedEOF: 0, + InvalidBlockType: 1, + InvalidLengthLiteral: 2, + InvalidDistance: 3, + StreamFinished: 4, + NoStreamHandler: 5, + InvalidHeader: 6, + NoCallback: 7, + InvalidUTF8: 8, + ExtraFieldTooLong: 9, + InvalidDate: 10, + FilenameTooLong: 11, + StreamFinishing: 12, + InvalidZipData: 13, + UnknownCompressionMethod: 14 +}; +// error codes +var ec = [ + 'unexpected EOF', + 'invalid block type', + 'invalid length/literal', + 'invalid distance', + 'stream finished', + 'no stream handler', + , // determined by compression function + 'no callback', + 'invalid UTF-8 data', + 'extra field too long', + 'date not in range 1980-2099', + 'filename too long', + 'stream finishing', + 'invalid zip data' + // determined by unknown compression method +]; +; +var err = function (ind, msg, nt) { + var e = new Error(msg || ec[ind]); + e.code = ind; + if (Error.captureStackTrace) + Error.captureStackTrace(e, err); + if (!nt) + throw e; + return e; +}; +// expands raw DEFLATE data +var inflt = function (dat, st, buf, dict) { + // source length dict length + var sl = dat.length, dl = dict ? dict.length : 0; + if (!sl || st.f && !st.l) + return buf || new u8(0); + var noBuf = !buf; + // have to estimate size + var resize = noBuf || st.i != 2; + // no state + var noSt = st.i; + // Assumes roughly 33% compression ratio average + if (noBuf) + buf = new u8(sl * 3); + // ensure buffer can fit at least l elements + var cbuf = function (l) { + var bl = buf.length; + // need to increase size to fit + if (l > bl) { + // Double or set to necessary, whichever is greater + var nbuf = new u8(Math.max(bl * 2, l)); + nbuf.set(buf); + buf = nbuf; + } + }; + // last chunk bitpos bytes + var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; + // total bits + var tbts = sl * 8; + do { + if (!lm) { + // BFINAL - this is only 1 when last chunk is next + final = bits(dat, pos, 1); + // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman + var type = bits(dat, pos + 1, 3); + pos += 3; + if (!type) { + // go to end of byte boundary + var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l; + if (t > sl) { + if (noSt) + err(0); + break; + } + // ensure size + if (resize) + cbuf(bt + l); + // Copy over uncompressed data + buf.set(dat.subarray(s, t), bt); + // Get new bitpos, update byte count + st.b = bt += l, st.p = pos = t * 8, st.f = final; + continue; + } + else if (type == 1) + lm = flrm, dm = fdrm, lbt = 9, dbt = 5; + else if (type == 2) { + // literal lengths + var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; + var tl = hLit + bits(dat, pos + 5, 31) + 1; + pos += 14; + // length+distance tree + var ldt = new u8(tl); + // code length tree + var clt = new u8(19); + for (var i = 0; i < hcLen; ++i) { + // use index map to get real code + clt[clim[i]] = bits(dat, pos + i * 3, 7); + } + pos += hcLen * 3; + // code lengths bits + var clb = max(clt), clbmsk = (1 << clb) - 1; + // code lengths map + var clm = hMap(clt, clb, 1); + for (var i = 0; i < tl;) { + var r = clm[bits(dat, pos, clbmsk)]; + // bits read + pos += r & 15; + // symbol + var s = r >> 4; + // code length to copy + if (s < 16) { + ldt[i++] = s; + } + else { + // copy count + var c = 0, n = 0; + if (s == 16) + n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; + else if (s == 17) + n = 3 + bits(dat, pos, 7), pos += 3; + else if (s == 18) + n = 11 + bits(dat, pos, 127), pos += 7; + while (n--) + ldt[i++] = c; + } + } + // length tree distance tree + var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); + // max length bits + lbt = max(lt); + // max dist bits + dbt = max(dt); + lm = hMap(lt, lbt, 1); + dm = hMap(dt, dbt, 1); + } + else + err(1); + if (pos > tbts) { + if (noSt) + err(0); + break; + } + } + // Make sure the buffer can hold this + the largest possible addition + // Maximum chunk size (practically, theoretically infinite) is 2^17 + if (resize) + cbuf(bt + 131072); + var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; + var lpos = pos; + for (;; lpos = pos) { + // bits read, code + var c = lm[bits16(dat, pos) & lms], sym = c >> 4; + pos += c & 15; + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (!c) + err(2); + if (sym < 256) + buf[bt++] = sym; + else if (sym == 256) { + lpos = pos, lm = null; + break; + } + else { + var add = sym - 254; + // no extra bits needed if less + if (sym > 264) { + // index + var i = sym - 257, b = fleb[i]; + add = bits(dat, pos, (1 << b) - 1) + fl[i]; + pos += b; + } + // dist + var d = dm[bits16(dat, pos) & dms], dsym = d >> 4; + if (!d) + err(3); + pos += d & 15; + var dt = fd[dsym]; + if (dsym > 3) { + var b = fdeb[dsym]; + dt += bits16(dat, pos) & (1 << b) - 1, pos += b; + } + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (resize) + cbuf(bt + 131072); + var end = bt + add; + if (bt < dt) { + var shift = dl - dt, dend = Math.min(dt, end); + if (shift + bt < 0) + err(3); + for (; bt < dend; ++bt) + buf[bt] = dict[shift + bt]; + } + for (; bt < end; ++bt) + buf[bt] = buf[bt - dt]; + } + } + st.l = lm, st.p = lpos, st.b = bt, st.f = final; + if (lm) + final = 1, st.m = lbt, st.d = dm, st.n = dbt; + } while (!final); + // don't reallocate for streams or user buffers + return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt); +}; +// starting at p, write the minimum number of bits that can hold v to d +var wbits = function (d, p, v) { + v <<= p & 7; + var o = (p / 8) | 0; + d[o] |= v; + d[o + 1] |= v >> 8; +}; +// starting at p, write the minimum number of bits (>8) that can hold v to d +var wbits16 = function (d, p, v) { + v <<= p & 7; + var o = (p / 8) | 0; + d[o] |= v; + d[o + 1] |= v >> 8; + d[o + 2] |= v >> 16; +}; +// creates code lengths from a frequency table +var hTree = function (d, mb) { + // Need extra info to make a tree + var t = []; + for (var i = 0; i < d.length; ++i) { + if (d[i]) + t.push({ s: i, f: d[i] }); + } + var s = t.length; + var t2 = t.slice(); + if (!s) + return { t: et, l: 0 }; + if (s == 1) { + var v = new u8(t[0].s + 1); + v[t[0].s] = 1; + return { t: v, l: 1 }; + } + t.sort(function (a, b) { return a.f - b.f; }); + // after i2 reaches last ind, will be stopped + // freq must be greater than largest possible number of symbols + t.push({ s: -1, f: 25001 }); + var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2; + t[0] = { s: -1, f: l.f + r.f, l: l, r: r }; + // efficient algorithm from UZIP.js + // i0 is lookbehind, i2 is lookahead - after processing two low-freq + // symbols that combined have high freq, will start processing i2 (high-freq, + // non-composite) symbols instead + // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/ + while (i1 != s - 1) { + l = t[t[i0].f < t[i2].f ? i0++ : i2++]; + r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++]; + t[i1++] = { s: -1, f: l.f + r.f, l: l, r: r }; + } + var maxSym = t2[0].s; + for (var i = 1; i < s; ++i) { + if (t2[i].s > maxSym) + maxSym = t2[i].s; + } + // code lengths + var tr = new u16(maxSym + 1); + // max bits in tree + var mbt = ln(t[i1 - 1], tr, 0); + if (mbt > mb) { + // more algorithms from UZIP.js + // TODO: find out how this code works (debt) + // ind debt + var i = 0, dt = 0; + // left cost + var lft = mbt - mb, cst = 1 << lft; + t2.sort(function (a, b) { return tr[b.s] - tr[a.s] || a.f - b.f; }); + for (; i < s; ++i) { + var i2_1 = t2[i].s; + if (tr[i2_1] > mb) { + dt += cst - (1 << (mbt - tr[i2_1])); + tr[i2_1] = mb; + } + else + break; + } + dt >>= lft; + while (dt > 0) { + var i2_2 = t2[i].s; + if (tr[i2_2] < mb) + dt -= 1 << (mb - tr[i2_2]++ - 1); + else + ++i; + } + for (; i >= 0 && dt; --i) { + var i2_3 = t2[i].s; + if (tr[i2_3] == mb) { + --tr[i2_3]; + ++dt; + } + } + mbt = mb; + } + return { t: new u8(tr), l: mbt }; +}; +// get the max length and assign length codes +var ln = function (n, l, d) { + return n.s == -1 + ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) + : (l[n.s] = d); +}; +// length codes generation +var lc = function (c) { + var s = c.length; + // Note that the semicolon was intentional + while (s && !c[--s]) + ; + var cl = new u16(++s); + // ind num streak + var cli = 0, cln = c[0], cls = 1; + var w = function (v) { cl[cli++] = v; }; + for (var i = 1; i <= s; ++i) { + if (c[i] == cln && i != s) + ++cls; + else { + if (!cln && cls > 2) { + for (; cls > 138; cls -= 138) + w(32754); + if (cls > 2) { + w(cls > 10 ? ((cls - 11) << 5) | 28690 : ((cls - 3) << 5) | 12305); + cls = 0; + } + } + else if (cls > 3) { + w(cln), --cls; + for (; cls > 6; cls -= 6) + w(8304); + if (cls > 2) + w(((cls - 3) << 5) | 8208), cls = 0; + } + while (cls--) + w(cln); + cls = 1; + cln = c[i]; + } + } + return { c: cl.subarray(0, cli), n: s }; +}; +// calculate the length of output from tree, code lengths +var clen = function (cf, cl) { + var l = 0; + for (var i = 0; i < cl.length; ++i) + l += cf[i] * cl[i]; + return l; +}; +// writes a fixed block +// returns the new bit pos +var wfblk = function (out, pos, dat) { + // no need to write 00 as type: TypedArray defaults to 0 + var s = dat.length; + var o = shft(pos + 2); + out[o] = s & 255; + out[o + 1] = s >> 8; + out[o + 2] = out[o] ^ 255; + out[o + 3] = out[o + 1] ^ 255; + for (var i = 0; i < s; ++i) + out[o + i + 4] = dat[i]; + return (o + 4 + s) * 8; +}; +// writes a block +var wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) { + wbits(out, p++, final); + ++lf[256]; + var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l; + var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l; + var _c = lc(dlt), lclt = _c.c, nlc = _c.n; + var _d = lc(ddt), lcdt = _d.c, ndc = _d.n; + var lcfreq = new u16(19); + for (var i = 0; i < lclt.length; ++i) + ++lcfreq[lclt[i] & 31]; + for (var i = 0; i < lcdt.length; ++i) + ++lcfreq[lcdt[i] & 31]; + var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l; + var nlcc = 19; + for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc) + ; + var flen = (bl + 5) << 3; + var ftlen = clen(lf, flt) + clen(df, fdt) + eb; + var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18]; + if (bs >= 0 && flen <= ftlen && flen <= dtlen) + return wfblk(out, p, dat.subarray(bs, bs + bl)); + var lm, ll, dm, dl; + wbits(out, p, 1 + (dtlen < ftlen)), p += 2; + if (dtlen < ftlen) { + lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt; + var llm = hMap(lct, mlcb, 0); + wbits(out, p, nlc - 257); + wbits(out, p + 5, ndc - 1); + wbits(out, p + 10, nlcc - 4); + p += 14; + for (var i = 0; i < nlcc; ++i) + wbits(out, p + 3 * i, lct[clim[i]]); + p += 3 * nlcc; + var lcts = [lclt, lcdt]; + for (var it = 0; it < 2; ++it) { + var clct = lcts[it]; + for (var i = 0; i < clct.length; ++i) { + var len = clct[i] & 31; + wbits(out, p, llm[len]), p += lct[len]; + if (len > 15) + wbits(out, p, (clct[i] >> 5) & 127), p += clct[i] >> 12; + } + } + } + else { + lm = flm, ll = flt, dm = fdm, dl = fdt; + } + for (var i = 0; i < li; ++i) { + var sym = syms[i]; + if (sym > 255) { + var len = (sym >> 18) & 31; + wbits16(out, p, lm[len + 257]), p += ll[len + 257]; + if (len > 7) + wbits(out, p, (sym >> 23) & 31), p += fleb[len]; + var dst = sym & 31; + wbits16(out, p, dm[dst]), p += dl[dst]; + if (dst > 3) + wbits16(out, p, (sym >> 5) & 8191), p += fdeb[dst]; + } + else { + wbits16(out, p, lm[sym]), p += ll[sym]; + } + } + wbits16(out, p, lm[256]); + return p + ll[256]; +}; +// deflate options (nice << 13) | chain +var deo = /*#__PURE__*/ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]); +// empty +var et = /*#__PURE__*/ new u8(0); +// compresses data into a raw DEFLATE buffer +var dflt = function (dat, lvl, plvl, pre, post, st) { + var s = st.z || dat.length; + var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7000)) + post); + // writing to this writes to the output buffer + var w = o.subarray(pre, o.length - post); + var lst = st.l; + var pos = (st.r || 0) & 7; + if (lvl) { + if (pos) + w[0] = st.r >> 3; + var opt = deo[lvl - 1]; + var n = opt >> 13, c = opt & 8191; + var msk_1 = (1 << plvl) - 1; + // prev 2-byte val map curr 2-byte val map + var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1); + var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1; + var hsh = function (i) { return (dat[i] ^ (dat[i + 1] << bs1_1) ^ (dat[i + 2] << bs2_1)) & msk_1; }; + // 24576 is an arbitrary number of maximum symbols per block + // 424 buffer for last block + var syms = new i32(25000); + // length/literal freq distance freq + var lf = new u16(288), df = new u16(32); + // l/lcnt exbits index l/lind waitdx blkpos + var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0; + for (; i + 2 < s; ++i) { + // hash value + var hv = hsh(i); + // index mod 32768 previous index mod + var imod = i & 32767, pimod = head[hv]; + prev[imod] = pimod; + head[hv] = imod; + // We always should modify head and prev, but only add symbols if + // this data is not yet processed ("wait" for wait index) + if (wi <= i) { + // bytes remaining + var rem = s - i; + if ((lc_1 > 7000 || li > 24576) && (rem > 423 || !lst)) { + pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos); + li = lc_1 = eb = 0, bs = i; + for (var j = 0; j < 286; ++j) + lf[j] = 0; + for (var j = 0; j < 30; ++j) + df[j] = 0; + } + // len dist chain + var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767; + if (rem > 2 && hv == hsh(i - dif)) { + var maxn = Math.min(n, rem) - 1; + var maxd = Math.min(32767, i); + // max possible length + // not capped at dif because decompressors implement "rolling" index population + var ml = Math.min(258, rem); + while (dif <= maxd && --ch_1 && imod != pimod) { + if (dat[i + l] == dat[i + l - dif]) { + var nl = 0; + for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl) + ; + if (nl > l) { + l = nl, d = dif; + // break out early when we reach "nice" (we are satisfied enough) + if (nl > maxn) + break; + // now, find the rarest 2-byte sequence within this + // length of literals and search for that instead. + // Much faster than just using the start + var mmd = Math.min(dif, nl - 2); + var md = 0; + for (var j = 0; j < mmd; ++j) { + var ti = i - dif + j & 32767; + var pti = prev[ti]; + var cd = ti - pti & 32767; + if (cd > md) + md = cd, pimod = ti; + } + } + } + // check the previous match + imod = pimod, pimod = prev[imod]; + dif += imod - pimod & 32767; + } + } + // d will be nonzero only when a match was found + if (d) { + // store both dist and len data in one int32 + // Make sure this is recognized as a len/dist with 28th bit (2^28) + syms[li++] = 268435456 | (revfl[l] << 18) | revfd[d]; + var lin = revfl[l] & 31, din = revfd[d] & 31; + eb += fleb[lin] + fdeb[din]; + ++lf[257 + lin]; + ++df[din]; + wi = i + l; + ++lc_1; + } + else { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + } + } + for (i = Math.max(i, wi); i < s; ++i) { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos); + if (!lst) { + st.r = (pos & 7) | w[(pos / 8) | 0] << 3; + // shft(pos) now 1 less if pos & 7 != 0 + pos -= 7; + st.h = head, st.p = prev, st.i = i, st.w = wi; + } + } + else { + for (var i = st.w || 0; i < s + lst; i += 65535) { + // end + var e = i + 65535; + if (e >= s) { + // write final block + w[(pos / 8) | 0] = lst; + e = s; + } + pos = wfblk(w, pos + 1, dat.subarray(i, e)); + } + st.i = s; + } + return slc(o, 0, pre + shft(pos) + post); +}; +// CRC32 table +var crct = /*#__PURE__*/ (function () { + var t = new Int32Array(256); + for (var i = 0; i < 256; ++i) { + var c = i, k = 9; + while (--k) + c = ((c & 1) && -306674912) ^ (c >>> 1); + t[i] = c; + } + return t; +})(); +// CRC32 +var crc = function () { + var c = -1; + return { + p: function (d) { + // closures have awful performance + var cr = c; + for (var i = 0; i < d.length; ++i) + cr = crct[(cr & 255) ^ d[i]] ^ (cr >>> 8); + c = cr; + }, + d: function () { return ~c; } + }; +}; +// Adler32 +var adler = function () { + var a = 1, b = 0; + return { + p: function (d) { + // closures have awful performance + var n = a, m = b; + var l = d.length | 0; + for (var i = 0; i != l;) { + var e = Math.min(i + 2655, l); + for (; i < e; ++i) + m += n += d[i]; + n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16); + } + a = n, b = m; + }, + d: function () { + a %= 65521, b %= 65521; + return (a & 255) << 24 | (a & 0xFF00) << 8 | (b & 255) << 8 | (b >> 8); + } + }; +}; +; +// deflate with opts +var dopt = function (dat, opt, pre, post, st) { + if (!st) { + st = { l: 1 }; + if (opt.dictionary) { + var dict = opt.dictionary.subarray(-32768); + var newDat = new u8(dict.length + dat.length); + newDat.set(dict); + newDat.set(dat, dict.length); + dat = newDat; + st.w = dict.length; + } + } + return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? (st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20) : (12 + opt.mem), pre, post, st); +}; +// Walmart object spread +var mrg = function (a, b) { + var o = {}; + for (var k in a) + o[k] = a[k]; + for (var k in b) + o[k] = b[k]; + return o; +}; +// worker clone +// This is possibly the craziest part of the entire codebase, despite how simple it may seem. +// The only parameter to this function is a closure that returns an array of variables outside of the function scope. +// We're going to try to figure out the variable names used in the closure as strings because that is crucial for workerization. +// We will return an object mapping of true variable name to value (basically, the current scope as a JS object). +// The reason we can't just use the original variable names is minifiers mangling the toplevel scope. +// This took me three weeks to figure out how to do. +var wcln = function (fn, fnStr, td) { + var dt = fn(); + var st = fn.toString(); + var ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/\s+/g, '').split(','); + for (var i = 0; i < dt.length; ++i) { + var v = dt[i], k = ks[i]; + if (typeof v == 'function') { + fnStr += ';' + k + '='; + var st_1 = v.toString(); + if (v.prototype) { + // for global objects + if (st_1.indexOf('[native code]') != -1) { + var spInd = st_1.indexOf(' ', 8) + 1; + fnStr += st_1.slice(spInd, st_1.indexOf('(', spInd)); + } + else { + fnStr += st_1; + for (var t in v.prototype) + fnStr += ';' + k + '.prototype.' + t + '=' + v.prototype[t].toString(); + } + } + else + fnStr += st_1; + } + else + td[k] = v; + } + return fnStr; +}; +var ch = []; +// clone bufs +var cbfs = function (v) { + var tl = []; + for (var k in v) { + if (v[k].buffer) { + tl.push((v[k] = new v[k].constructor(v[k])).buffer); + } + } + return tl; +}; +// use a worker to execute code +var wrkr = function (fns, init, id, cb) { + if (!ch[id]) { + var fnStr = '', td_1 = {}, m = fns.length - 1; + for (var i = 0; i < m; ++i) + fnStr = wcln(fns[i], fnStr, td_1); + ch[id] = { c: wcln(fns[m], fnStr, td_1), e: td_1 }; + } + var td = mrg({}, ch[id].e); + return (0, node_worker_1.default)(ch[id].c + ';onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage=' + init.toString() + '}', id, td, cbfs(td), cb); +}; +// base async inflate fn +var bInflt = function () { return [u8, u16, i32, fleb, fdeb, clim, fl, fd, flrm, fdrm, rev, ec, hMap, max, bits, bits16, shft, slc, err, inflt, inflateSync, pbf, gopt]; }; +var bDflt = function () { return [u8, u16, i32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; }; +// gzip extra +var gze = function () { return [gzh, gzhl, wbytes, crc, crct]; }; +// gunzip extra +var guze = function () { return [gzs, gzl]; }; +// zlib extra +var zle = function () { return [zlh, wbytes, adler]; }; +// unzlib extra +var zule = function () { return [zls]; }; +// post buf +var pbf = function (msg) { return postMessage(msg, [msg.buffer]); }; +// get opts +var gopt = function (o) { return o && { + out: o.size && new u8(o.size), + dictionary: o.dictionary +}; }; +// async helper +var cbify = function (dat, opts, fns, init, id, cb) { + var w = wrkr(fns, init, id, function (err, dat) { + w.terminate(); + cb(err, dat); + }); + w.postMessage([dat, opts], opts.consume ? [dat.buffer] : []); + return function () { w.terminate(); }; +}; +// auto stream +var astrm = function (strm) { + strm.ondata = function (dat, final) { return postMessage([dat, final], [dat.buffer]); }; + return function (ev) { + if (ev.data[0]) { + strm.push(ev.data[0], ev.data[1]); + postMessage([ev.data[0].length]); + } + else + strm.flush(ev.data[1]); + }; +}; +// async stream attach +var astrmify = function (fns, strm, opts, init, id, flush, ext) { + var t; + var w = wrkr(fns, init, id, function (err, dat) { + if (err) + w.terminate(), strm.ondata.call(strm, err); + else if (!Array.isArray(dat)) + ext(dat); + else if (dat.length == 1) { + strm.queuedSize -= dat[0]; + if (strm.ondrain) + strm.ondrain(dat[0]); + } + else { + if (dat[1]) + w.terminate(); + strm.ondata.call(strm, err, dat[0], dat[1]); + } + }); + w.postMessage(opts); + strm.queuedSize = 0; + strm.push = function (d, f) { + if (!strm.ondata) + err(5); + if (t) + strm.ondata(err(4, 0, 1), null, !!f); + strm.queuedSize += d.length; + // can fail for cross-realm Uint8Array, but ok - only a small performance penalty + w.postMessage([d, t = f], d.buffer instanceof ArrayBuffer ? [d.buffer] : []); + }; + strm.terminate = function () { w.terminate(); }; + if (flush) { + strm.flush = function (sync) { w.postMessage([0, sync]); }; + } +}; +// read 2 bytes +var b2 = function (d, b) { return d[b] | (d[b + 1] << 8); }; +// read 4 bytes +var b4 = function (d, b) { return (d[b] | (d[b + 1] << 8) | (d[b + 2] << 16) | (d[b + 3] << 24)) >>> 0; }; +// read 8 bytes +var b8 = function (d, b) { return b4(d, b) + (b4(d, b + 4) * 4294967296); }; +// write bytes +var wbytes = function (d, b, v) { + for (; v; ++b) + d[b] = v, v >>>= 8; +}; +// gzip header +var gzh = function (c, o) { + var fn = o.filename; + c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3; // assume Unix + if (o.mtime != 0) + wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1000)); + if (fn) { + c[3] = 8; + for (var i = 0; i <= fn.length; ++i) + c[i + 10] = fn.charCodeAt(i); + } +}; +// gzip footer: -8 to -4 = CRC, -4 to -0 is length +// gzip start +var gzs = function (d) { + if (d[0] != 31 || d[1] != 139 || d[2] != 8) + err(6, 'invalid gzip data'); + var flg = d[3]; + var st = 10; + if (flg & 4) + st += (d[10] | d[11] << 8) + 2; + for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++]) + ; + return st + (flg & 2); +}; +// gzip length +var gzl = function (d) { + var l = d.length; + return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0; +}; +// gzip header length +var gzhl = function (o) { return 10 + (o.filename ? o.filename.length + 1 : 0); }; +// zlib header +var zlh = function (c, o) { + var lv = o.level, fl = lv == 0 ? 0 : lv < 6 ? 1 : lv == 9 ? 3 : 2; + c[0] = 120, c[1] = (fl << 6) | (o.dictionary && 32); + c[1] |= 31 - ((c[0] << 8) | c[1]) % 31; + if (o.dictionary) { + var h = adler(); + h.p(o.dictionary); + wbytes(c, 2, h.d()); + } +}; +// zlib start +var zls = function (d, dict) { + if ((d[0] & 15) != 8 || (d[0] >> 4) > 7 || ((d[0] << 8 | d[1]) % 31)) + err(6, 'invalid zlib data'); + if ((d[1] >> 5 & 1) == +!dict) + err(6, 'invalid zlib data: ' + (d[1] & 32 ? 'need' : 'unexpected') + ' dictionary'); + return (d[1] >> 3 & 4) + 2; +}; +function StrmOpt(opts, cb) { + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + return opts; +} +/** + * Streaming DEFLATE compression + */ +var Deflate = /*#__PURE__*/ (function () { + function Deflate(opts, cb) { + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + this.o = opts || {}; + this.s = { l: 0, i: 32768, w: 32768, z: 32768 }; + // Buffer length must always be 0 mod 32768 for index calculations to be correct when modifying head and prev + // 98304 = 32768 (lookback) + 65536 (common chunk size) + this.b = new u8(98304); + if (this.o.dictionary) { + var dict = this.o.dictionary.subarray(-32768); + this.b.set(dict, 32768 - dict.length); + this.s.i = 32768 - dict.length; + } + } + Deflate.prototype.p = function (c, f) { + this.ondata(dopt(c, this.o, 0, 0, this.s), f); + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Deflate.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (this.s.l) + err(4); + var endLen = chunk.length + this.s.z; + if (endLen > this.b.length) { + if (endLen > 2 * this.b.length - 32768) { + var newBuf = new u8(endLen & -32768); + newBuf.set(this.b.subarray(0, this.s.z)); + this.b = newBuf; + } + var split = this.b.length - this.s.z; + this.b.set(chunk.subarray(0, split), this.s.z); + this.s.z = this.b.length; + this.p(this.b, false); + this.b.set(this.b.subarray(-32768)); + this.b.set(chunk.subarray(split), 32768); + this.s.z = chunk.length - split + 32768; + this.s.i = 32766, this.s.w = 32768; + } + else { + this.b.set(chunk, this.s.z); + this.s.z += chunk.length; + } + this.s.l = final & 1; + if (this.s.z > this.s.w + 8191 || final) { + this.p(this.b, final || false); + this.s.w = this.s.i, this.s.i -= 2; + } + if (final) { + // cleanup unneeded buffers/state to reduce memory usage + this.s = this.o = {}; + this.b = et; + } + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + Deflate.prototype.flush = function (sync) { + if (!this.ondata) + err(5); + if (this.s.l) + err(4); + this.p(this.b, false); + this.s.w = this.s.i, this.s.i -= 2; + // could technically skip writing the type-0 block for (this.s.r & 7) == 0, + // but the deterministic trailer (00 00 FF FF) is useful in some situations + if (sync) { + var c = new u8(6); + c[0] = this.s.r >> 3; + // write empty, non-final type-0 block + var ep = wfblk(c, this.s.r, et); + this.s.r = 0; + this.ondata(c.subarray(0, ep >> 3), false); + } + }; + return Deflate; +}()); +exports.Deflate = Deflate; +/** + * Asynchronous streaming DEFLATE compression + */ +var AsyncDeflate = /*#__PURE__*/ (function () { + function AsyncDeflate(opts, cb) { + astrmify([ + bDflt, + function () { return [astrm, Deflate]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Deflate(ev.data); + onmessage = astrm(strm); + }, 6, 1); + } + return AsyncDeflate; +}()); +exports.AsyncDeflate = AsyncDeflate; +function deflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + ], function (ev) { return pbf(deflateSync(ev.data[0], ev.data[1])); }, 0, cb); +} +/** + * Compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @returns The deflated version of the data + */ +function deflateSync(data, opts) { + return dopt(data, opts || {}, 0, 0); +} +/** + * Streaming DEFLATE decompression + */ +var Inflate = /*#__PURE__*/ (function () { + function Inflate(opts, cb) { + // no StrmOpt here to avoid adding to workerizer + if (typeof opts == 'function') + cb = opts, opts = {}; + this.ondata = cb; + var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768); + this.s = { i: 0, b: dict ? dict.length : 0 }; + this.o = new u8(32768); + this.p = new u8(0); + if (dict) + this.o.set(dict); + } + Inflate.prototype.e = function (c) { + if (!this.ondata) + err(5); + if (this.d) + err(4); + if (!this.p.length) + this.p = c; + else if (c.length) { + var n = new u8(this.p.length + c.length); + n.set(this.p), n.set(c, this.p.length), this.p = n; + } + }; + Inflate.prototype.c = function (final) { + this.s.i = +(this.d = final || false); + var bts = this.s.b; + var dt = inflt(this.p, this.s, this.o); + this.ondata(slc(dt, bts, this.s.b), this.d); + this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length; + this.p = slc(this.p, (this.s.p / 8) | 0), this.s.p &= 7; + }; + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the final chunk + */ + Inflate.prototype.push = function (chunk, final) { + this.e(chunk), this.c(final); + }; + return Inflate; +}()); +exports.Inflate = Inflate; +/** + * Asynchronous streaming DEFLATE decompression + */ +var AsyncInflate = /*#__PURE__*/ (function () { + function AsyncInflate(opts, cb) { + astrmify([ + bInflt, + function () { return [astrm, Inflate]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Inflate(ev.data); + onmessage = astrm(strm); + }, 7, 0); + } + return AsyncInflate; +}()); +exports.AsyncInflate = AsyncInflate; +function inflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt + ], function (ev) { return pbf(inflateSync(ev.data[0], gopt(ev.data[1]))); }, 1, cb); +} +function inflateSync(data, opts) { + return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary); +} +// before you yell at me for not just using extends, my reason is that TS inheritance is hard to workerize. +/** + * Streaming GZIP compression + */ +var Gzip = /*#__PURE__*/ (function () { + function Gzip(opts, cb) { + this.c = crc(); + this.l = 0; + this.v = 1; + Deflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Gzip.prototype.push = function (chunk, final) { + this.c.p(chunk); + this.l += chunk.length; + Deflate.prototype.push.call(this, chunk, final); + }; + Gzip.prototype.p = function (c, f) { + var raw = dopt(c, this.o, this.v && gzhl(this.o), f && 8, this.s); + if (this.v) + gzh(raw, this.o), this.v = 0; + if (f) + wbytes(raw, raw.length - 8, this.c.d()), wbytes(raw, raw.length - 4, this.l); + this.ondata(raw, f); + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + Gzip.prototype.flush = function (sync) { + Deflate.prototype.flush.call(this, sync); + }; + return Gzip; +}()); +exports.Gzip = Gzip; +exports.Compress = Gzip; +/** + * Asynchronous streaming GZIP compression + */ +var AsyncGzip = /*#__PURE__*/ (function () { + function AsyncGzip(opts, cb) { + astrmify([ + bDflt, + gze, + function () { return [astrm, Deflate, Gzip]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Gzip(ev.data); + onmessage = astrm(strm); + }, 8, 1); + } + return AsyncGzip; +}()); +exports.AsyncGzip = AsyncGzip; +exports.AsyncCompress = AsyncGzip; +function gzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + gze, + function () { return [gzipSync]; } + ], function (ev) { return pbf(gzipSync(ev.data[0], ev.data[1])); }, 2, cb); +} +/** + * Compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @returns The gzipped version of the data + */ +function gzipSync(data, opts) { + if (!opts) + opts = {}; + var c = crc(), l = data.length; + c.p(data); + var d = dopt(data, opts, gzhl(opts), 8), s = d.length; + return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d; +} +/** + * Streaming single or multi-member GZIP decompression + */ +var Gunzip = /*#__PURE__*/ (function () { + function Gunzip(opts, cb) { + this.v = 1; + this.r = 0; + Inflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Gunzip.prototype.push = function (chunk, final) { + Inflate.prototype.e.call(this, chunk); + this.r += chunk.length; + if (this.v) { + var p = this.p.subarray(this.v - 1); + var s = p.length > 3 ? gzs(p) : 4; + if (s > p.length) { + if (!final) + return; + } + else if (this.v > 1 && this.onmember) { + this.onmember(this.r - p.length); + } + this.p = p.subarray(s), this.v = 0; + } + // necessary to prevent TS from using the closure value + // This allows for workerization to function correctly + Inflate.prototype.c.call(this, 0); + // process concatenated GZIP + if (this.s.f && !this.s.l) { + this.v = shft(this.s.p) + 9; + this.s = { i: 0 }; + this.o = new u8(0); + this.push(new u8(0), final); + } + else if (final) { + Inflate.prototype.c.call(this, final); + } + }; + return Gunzip; +}()); +exports.Gunzip = Gunzip; +/** + * Asynchronous streaming single or multi-member GZIP decompression + */ +var AsyncGunzip = /*#__PURE__*/ (function () { + function AsyncGunzip(opts, cb) { + var _this = this; + astrmify([ + bInflt, + guze, + function () { return [astrm, Inflate, Gunzip]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Gunzip(ev.data); + strm.onmember = function (offset) { return postMessage(offset); }; + onmessage = astrm(strm); + }, 9, 0, function (offset) { return _this.onmember && _this.onmember(offset); }); + } + return AsyncGunzip; +}()); +exports.AsyncGunzip = AsyncGunzip; +function gunzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt, + guze, + function () { return [gunzipSync]; } + ], function (ev) { return pbf(gunzipSync(ev.data[0], ev.data[1])); }, 3, cb); +} +function gunzipSync(data, opts) { + var st = gzs(data); + if (st + 8 > data.length) + err(6, 'invalid gzip data'); + return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary); +} +/** + * Streaming Zlib compression + */ +var Zlib = /*#__PURE__*/ (function () { + function Zlib(opts, cb) { + this.c = adler(); + this.v = 1; + Deflate.call(this, opts, cb); + } + /** + * Pushes a chunk to be zlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Zlib.prototype.push = function (chunk, final) { + this.c.p(chunk); + Deflate.prototype.push.call(this, chunk, final); + }; + Zlib.prototype.p = function (c, f) { + var raw = dopt(c, this.o, this.v && (this.o.dictionary ? 6 : 2), f && 4, this.s); + if (this.v) + zlh(raw, this.o), this.v = 0; + if (f) + wbytes(raw, raw.length - 4, this.c.d()); + this.ondata(raw, f); + }; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + Zlib.prototype.flush = function (sync) { + Deflate.prototype.flush.call(this, sync); + }; + return Zlib; +}()); +exports.Zlib = Zlib; +/** + * Asynchronous streaming Zlib compression + */ +var AsyncZlib = /*#__PURE__*/ (function () { + function AsyncZlib(opts, cb) { + astrmify([ + bDflt, + zle, + function () { return [astrm, Deflate, Zlib]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Zlib(ev.data); + onmessage = astrm(strm); + }, 10, 1); + } + return AsyncZlib; +}()); +exports.AsyncZlib = AsyncZlib; +function zlib(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bDflt, + zle, + function () { return [zlibSync]; } + ], function (ev) { return pbf(zlibSync(ev.data[0], ev.data[1])); }, 4, cb); +} +/** + * Compress data with Zlib + * @param data The data to compress + * @param opts The compression options + * @returns The zlib-compressed version of the data + */ +function zlibSync(data, opts) { + if (!opts) + opts = {}; + var a = adler(); + a.p(data); + var d = dopt(data, opts, opts.dictionary ? 6 : 2, 4); + return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d; +} +/** + * Streaming Zlib decompression + */ +var Unzlib = /*#__PURE__*/ (function () { + function Unzlib(opts, cb) { + Inflate.call(this, opts, cb); + this.v = opts && opts.dictionary ? 2 : 1; + } + /** + * Pushes a chunk to be unzlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Unzlib.prototype.push = function (chunk, final) { + Inflate.prototype.e.call(this, chunk); + if (this.v) { + if (this.p.length < 6 && !final) + return; + this.p = this.p.subarray(zls(this.p, this.v - 1)), this.v = 0; + } + if (final) { + if (this.p.length < 4) + err(6, 'invalid zlib data'); + this.p = this.p.subarray(0, -4); + } + // necessary to prevent TS from using the closure value + // This allows for workerization to function correctly + Inflate.prototype.c.call(this, final); + }; + return Unzlib; +}()); +exports.Unzlib = Unzlib; +/** + * Asynchronous streaming Zlib decompression + */ +var AsyncUnzlib = /*#__PURE__*/ (function () { + function AsyncUnzlib(opts, cb) { + astrmify([ + bInflt, + zule, + function () { return [astrm, Inflate, Unzlib]; } + ], this, StrmOpt.call(this, opts, cb), function (ev) { + var strm = new Unzlib(ev.data); + onmessage = astrm(strm); + }, 11, 0); + } + return AsyncUnzlib; +}()); +exports.AsyncUnzlib = AsyncUnzlib; +function unzlib(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return cbify(data, opts, [ + bInflt, + zule, + function () { return [unzlibSync]; } + ], function (ev) { return pbf(unzlibSync(ev.data[0], gopt(ev.data[1]))); }, 5, cb); +} +function unzlibSync(data, opts) { + return inflt(data.subarray(zls(data, opts && opts.dictionary), -4), { i: 2 }, opts && opts.out, opts && opts.dictionary); +} +/** + * Streaming GZIP, Zlib, or raw DEFLATE decompression + */ +var Decompress = /*#__PURE__*/ (function () { + function Decompress(opts, cb) { + this.o = StrmOpt.call(this, opts, cb) || {}; + this.G = Gunzip; + this.I = Inflate; + this.Z = Unzlib; + } + // init substream + // overriden by AsyncDecompress + Decompress.prototype.i = function () { + var _this = this; + this.s.ondata = function (dat, final) { + _this.ondata(dat, final); + }; + }; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Decompress.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (!this.s) { + if (this.p && this.p.length) { + var n = new u8(this.p.length + chunk.length); + n.set(this.p), n.set(chunk, this.p.length); + } + else + this.p = chunk; + if (this.p.length > 2) { + this.s = (this.p[0] == 31 && this.p[1] == 139 && this.p[2] == 8) + ? new this.G(this.o) + : ((this.p[0] & 15) != 8 || (this.p[0] >> 4) > 7 || ((this.p[0] << 8 | this.p[1]) % 31)) + ? new this.I(this.o) + : new this.Z(this.o); + this.i(); + this.s.push(this.p, final); + this.p = null; + } + } + else + this.s.push(chunk, final); + }; + return Decompress; +}()); +exports.Decompress = Decompress; +/** + * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression + */ +var AsyncDecompress = /*#__PURE__*/ (function () { + function AsyncDecompress(opts, cb) { + Decompress.call(this, opts, cb); + this.queuedSize = 0; + this.G = AsyncGunzip; + this.I = AsyncInflate; + this.Z = AsyncUnzlib; + } + AsyncDecompress.prototype.i = function () { + var _this = this; + this.s.ondata = function (err, dat, final) { + _this.ondata(err, dat, final); + }; + this.s.ondrain = function (size) { + _this.queuedSize -= size; + if (_this.ondrain) + _this.ondrain(size); + }; + }; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + AsyncDecompress.prototype.push = function (chunk, final) { + this.queuedSize += chunk.length; + Decompress.prototype.push.call(this, chunk, final); + }; + return AsyncDecompress; +}()); +exports.AsyncDecompress = AsyncDecompress; +function decompress(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + return (data[0] == 31 && data[1] == 139 && data[2] == 8) + ? gunzip(data, opts, cb) + : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31)) + ? inflate(data, opts, cb) + : unzlib(data, opts, cb); +} +/** + * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +function decompressSync(data, opts) { + return (data[0] == 31 && data[1] == 139 && data[2] == 8) + ? gunzipSync(data, opts) + : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31)) + ? inflateSync(data, opts) + : unzlibSync(data, opts); +} +// flatten a directory structure +var fltn = function (d, p, t, o) { + for (var k in d) { + var val = d[k], n = p + k, op = o; + if (Array.isArray(val)) + op = mrg(o, val[1]), val = val[0]; + if (ArrayBuffer.isView(val)) + t[n] = [val, op]; + else { + t[n += '/'] = [new u8(0), op]; + fltn(val, n, t, o); + } + } +}; +// text encoder +var te = typeof TextEncoder != 'undefined' && /*#__PURE__*/ new TextEncoder(); +// text decoder +var td = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder(); +// text decoder stream +var tds = 0; +try { + td.decode(et, { stream: true }); + tds = 1; +} +catch (e) { } +// decode UTF8 +var dutf8 = function (d) { + for (var r = '', i = 0;;) { + var c = d[i++]; + var eb = (c > 127) + (c > 223) + (c > 239); + if (i + eb > d.length) + return { s: r, r: slc(d, i - 1) }; + if (!eb) + r += String.fromCharCode(c); + else if (eb == 3) { + c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)) - 65536, + r += String.fromCharCode(55296 | (c >> 10), 56320 | (c & 1023)); + } + else if (eb & 1) + r += String.fromCharCode((c & 31) << 6 | (d[i++] & 63)); + else + r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)); + } +}; +/** + * Streaming UTF-8 decoding + */ +var DecodeUTF8 = /*#__PURE__*/ (function () { + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is decoded + */ + function DecodeUTF8(cb) { + this.ondata = cb; + if (tds) + this.t = new TextDecoder(); + else + this.p = et; + } + /** + * Pushes a chunk to be decoded from UTF-8 binary + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + DecodeUTF8.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + final = !!final; + if (this.t) { + this.ondata(this.t.decode(chunk, { stream: true }), final); + if (final) { + if (this.t.decode().length) + err(8); + this.t = null; + } + return; + } + if (!this.p) + err(4); + var dat = new u8(this.p.length + chunk.length); + dat.set(this.p); + dat.set(chunk, this.p.length); + var _a = dutf8(dat), s = _a.s, r = _a.r; + if (final) { + if (r.length) + err(8); + this.p = null; + } + else + this.p = r; + this.ondata(s, final); + }; + return DecodeUTF8; +}()); +exports.DecodeUTF8 = DecodeUTF8; +/** + * Streaming UTF-8 encoding + */ +var EncodeUTF8 = /*#__PURE__*/ (function () { + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is encoded + */ + function EncodeUTF8(cb) { + this.ondata = cb; + } + /** + * Pushes a chunk to be encoded to UTF-8 + * @param chunk The string data to push + * @param final Whether this is the last chunk + */ + EncodeUTF8.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + if (this.d) + err(4); + this.ondata(strToU8(chunk), this.d = final || false); + }; + return EncodeUTF8; +}()); +exports.EncodeUTF8 = EncodeUTF8; +/** + * Converts a string into a Uint8Array for use with compression/decompression methods + * @param str The string to encode + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless decoding a binary string. + * @returns The string encoded in UTF-8/Latin-1 binary + */ +function strToU8(str, latin1) { + if (latin1) { + var ar_1 = new u8(str.length); + for (var i = 0; i < str.length; ++i) + ar_1[i] = str.charCodeAt(i); + return ar_1; + } + if (te) + return te.encode(str); + var l = str.length; + var ar = new u8(str.length + (str.length >> 1)); + var ai = 0; + var w = function (v) { ar[ai++] = v; }; + for (var i = 0; i < l; ++i) { + if (ai + 5 > ar.length) { + var n = new u8(ai + 8 + ((l - i) << 1)); + n.set(ar); + ar = n; + } + var c = str.charCodeAt(i); + if (c < 128 || latin1) + w(c); + else if (c < 2048) + w(192 | (c >> 6)), w(128 | (c & 63)); + else if (c > 55295 && c < 57344) + c = 65536 + (c & 1023 << 10) | (str.charCodeAt(++i) & 1023), + w(240 | (c >> 18)), w(128 | ((c >> 12) & 63)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63)); + else + w(224 | (c >> 12)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63)); + } + return slc(ar, 0, ai); +} +/** + * Converts a Uint8Array to a string + * @param dat The data to decode to string + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless encoding to binary string. + * @returns The original UTF-8/Latin-1 string + */ +function strFromU8(dat, latin1) { + if (latin1) { + var r = ''; + for (var i = 0; i < dat.length; i += 16384) + r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384)); + return r; + } + else if (td) { + return td.decode(dat); + } + else { + var _a = dutf8(dat), s = _a.s, r = _a.r; + if (r.length) + err(8); + return s; + } +} +; +// deflate bit flag +var dbf = function (l) { return l == 1 ? 3 : l < 6 ? 2 : l == 9 ? 1 : 0; }; +// skip local zip header +var slzh = function (d, b) { return b + 30 + b2(d, b + 26) + b2(d, b + 28); }; +// read zip header +var zh = function (d, b, z) { + var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl; + var _a = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a[0], su = _a[1], off = _a[2]; + return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off]; +}; +// read zip64 header sizes +var z64hs = function (d, b, l, z, sc, su, off) { + var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l; + var nf = nsc + nsu + noff; + if (z && nf) { + for (; b + 4 < e; b += 4 + b2(d, b + 2)) { + if (b2(d, b) == 1) { + return [ + nsc ? b8(d, b + 4 + 8 * nsu) : sc, + nsu ? b8(d, b + 4) : su, + noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off, + 1 + ]; + } + } + // z == 2 for unknown whether or not zip64 + if (z < 2) + err(13); + } + return [sc, su, off, 0]; +}; +// extra field length +var exfl = function (ex) { + var le = 0; + if (ex) { + for (var k in ex) { + var l = ex[k].length; + if (l > 65535) + err(9); + le += l + 4; + } + } + return le; +}; +// write zip header +var wzh = function (d, b, f, fn, u, c, ce, co) { + var fl = fn.length, ex = f.extra, col = co && co.length; + var exl = exfl(ex); + wbytes(d, b, ce != null ? 0x2014B50 : 0x4034B50), b += 4; + if (ce != null) + d[b++] = 20, d[b++] = f.os; + d[b] = 20, b += 2; // spec compliance? what's that? + d[b++] = (f.flag << 1) | (c < 0 && 8), d[b++] = u && 8; + d[b++] = f.compression & 255, d[b++] = f.compression >> 8; + var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980; + if (y < 0 || y > 119) + err(10); + wbytes(d, b, (y << 25) | ((dt.getMonth() + 1) << 21) | (dt.getDate() << 16) | (dt.getHours() << 11) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1)), b += 4; + if (c != -1) { + wbytes(d, b, f.crc); + wbytes(d, b + 4, c < 0 ? -c - 2 : c); + wbytes(d, b + 8, f.size); + } + wbytes(d, b + 12, fl); + wbytes(d, b + 14, exl), b += 16; + if (ce != null) { + wbytes(d, b, col); + wbytes(d, b + 6, f.attrs); + wbytes(d, b + 10, ce), b += 14; + } + d.set(fn, b); + b += fl; + if (exl) { + for (var k in ex) { + var exf = ex[k], l = exf.length; + wbytes(d, b, +k); + wbytes(d, b + 2, l); + d.set(exf, b + 4), b += 4 + l; + } + } + if (col) + d.set(co, b), b += col; + return b; +}; +// write zip footer (end of central directory) +var wzf = function (o, b, c, d, e) { + wbytes(o, b, 0x6054B50); // skip disk + wbytes(o, b + 8, c); + wbytes(o, b + 10, c); + wbytes(o, b + 12, d); + wbytes(o, b + 16, e); +}; +/** + * A pass-through stream to keep data uncompressed in a ZIP archive. + */ +var ZipPassThrough = /*#__PURE__*/ (function () { + /** + * Creates a pass-through stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + */ + function ZipPassThrough(filename) { + this.filename = filename; + this.c = crc(); + this.size = 0; + this.compression = 0; + } + /** + * Processes a chunk and pushes to the output stream. You can override this + * method in a subclass for custom behavior, but by default this passes + * the data through. You must call this.ondata(err, chunk, final) at some + * point in this method. + * @param chunk The chunk to process + * @param final Whether this is the last chunk + */ + ZipPassThrough.prototype.process = function (chunk, final) { + this.ondata(null, chunk, final); + }; + /** + * Pushes a chunk to be added. If you are subclassing this with a custom + * compression algorithm, note that you must push data from the source + * file only, pre-compression. + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + ZipPassThrough.prototype.push = function (chunk, final) { + if (!this.ondata) + err(5); + this.c.p(chunk); + this.size += chunk.length; + if (final) + this.crc = this.c.d(); + // we shouldn't really do this cast, but properly handling ArrayBufferLike + // makes the API unergonomic with Buffer + this.process(chunk, final || false); + }; + return ZipPassThrough; +}()); +exports.ZipPassThrough = ZipPassThrough; +// I don't extend because TypeScript extension adds 1kB of runtime bloat +/** + * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate + * for better performance + */ +var ZipDeflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + function ZipDeflate(filename, opts) { + var _this = this; + if (!opts) + opts = {}; + ZipPassThrough.call(this, filename); + this.d = new Deflate(opts, function (dat, final) { + _this.ondata(null, dat, final); + }); + this.compression = 8; + this.flag = dbf(opts.level); + } + ZipDeflate.prototype.process = function (chunk, final) { + try { + this.d.push(chunk, final); + } + catch (e) { + this.ondata(e, null, final); + } + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + ZipDeflate.prototype.push = function (chunk, final) { + ZipPassThrough.prototype.push.call(this, chunk, final); + }; + return ZipDeflate; +}()); +exports.ZipDeflate = ZipDeflate; +/** + * Asynchronous streaming DEFLATE compression for ZIP archives + */ +var AsyncZipDeflate = /*#__PURE__*/ (function () { + /** + * Creates an asynchronous DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + function AsyncZipDeflate(filename, opts) { + var _this = this; + if (!opts) + opts = {}; + ZipPassThrough.call(this, filename); + this.d = new AsyncDeflate(opts, function (err, dat, final) { + _this.ondata(err, dat, final); + }); + this.compression = 8; + this.flag = dbf(opts.level); + this.terminate = this.d.terminate; + } + AsyncZipDeflate.prototype.process = function (chunk, final) { + this.d.push(chunk, final); + }; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + AsyncZipDeflate.prototype.push = function (chunk, final) { + ZipPassThrough.prototype.push.call(this, chunk, final); + }; + return AsyncZipDeflate; +}()); +exports.AsyncZipDeflate = AsyncZipDeflate; +// TODO: Better tree shaking +/** + * A zippable archive to which files can incrementally be added + */ +var Zip = /*#__PURE__*/ (function () { + /** + * Creates an empty ZIP archive to which files can be added + * @param cb The callback to call whenever data for the generated ZIP archive + * is available + */ + function Zip(cb) { + this.ondata = cb; + this.u = []; + this.d = 1; + } + /** + * Adds a file to the ZIP archive + * @param file The file stream to add + */ + Zip.prototype.add = function (file) { + var _this = this; + if (!this.ondata) + err(5); + // finishing or finished + if (this.d & 2) + this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, false); + else { + var f = strToU8(file.filename), fl_1 = f.length; + var com = file.comment, o = com && strToU8(com); + var u = fl_1 != file.filename.length || (o && (com.length != o.length)); + var hl_1 = fl_1 + exfl(file.extra) + 30; + if (fl_1 > 65535) + this.ondata(err(11, 0, 1), null, false); + var header = new u8(hl_1); + wzh(header, 0, file, f, u, -1); + var chks_1 = [header]; + var pAll_1 = function () { + for (var _i = 0, chks_2 = chks_1; _i < chks_2.length; _i++) { + var chk = chks_2[_i]; + _this.ondata(null, chk, false); + } + chks_1 = []; + }; + var tr_1 = this.d; + this.d = 0; + var ind_1 = this.u.length; + var uf_1 = mrg(file, { + f: f, + u: u, + o: o, + t: function () { + if (file.terminate) + file.terminate(); + }, + r: function () { + pAll_1(); + if (tr_1) { + var nxt = _this.u[ind_1 + 1]; + if (nxt) + nxt.r(); + else + _this.d = 1; + } + tr_1 = 1; + } + }); + var cl_1 = 0; + file.ondata = function (err, dat, final) { + if (err) { + _this.ondata(err, dat, final); + _this.terminate(); + } + else { + cl_1 += dat.length; + chks_1.push(dat); + if (final) { + var dd = new u8(16); + wbytes(dd, 0, 0x8074B50); + wbytes(dd, 4, file.crc); + wbytes(dd, 8, cl_1); + wbytes(dd, 12, file.size); + chks_1.push(dd); + uf_1.c = cl_1, uf_1.b = hl_1 + cl_1 + 16, uf_1.crc = file.crc, uf_1.size = file.size; + if (tr_1) + uf_1.r(); + tr_1 = 1; + } + else if (tr_1) + pAll_1(); + } + }; + this.u.push(uf_1); + } + }; + /** + * Ends the process of adding files and prepares to emit the final chunks. + * This *must* be called after adding all desired files for the resulting + * ZIP file to work properly. + */ + Zip.prototype.end = function () { + var _this = this; + if (this.d & 2) { + this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, true); + return; + } + if (this.d) + this.e(); + else + this.u.push({ + r: function () { + if (!(_this.d & 1)) + return; + _this.u.splice(-1, 1); + _this.e(); + }, + t: function () { } + }); + this.d = 3; + }; + Zip.prototype.e = function () { + var bt = 0, l = 0, tl = 0; + for (var _i = 0, _a = this.u; _i < _a.length; _i++) { + var f = _a[_i]; + tl += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0); + } + var out = new u8(tl + 22); + for (var _b = 0, _c = this.u; _b < _c.length; _b++) { + var f = _c[_b]; + wzh(out, bt, f, f.f, f.u, -f.c - 2, l, f.o); + bt += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0), l += f.b; + } + wzf(out, bt, this.u.length, tl, l); + this.ondata(null, out, true); + this.d = 2; + }; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to add() will fail. + */ + Zip.prototype.terminate = function () { + for (var _i = 0, _a = this.u; _i < _a.length; _i++) { + var f = _a[_i]; + f.t(); + } + this.d = 2; + }; + return Zip; +}()); +exports.Zip = Zip; +function zip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + var r = {}; + fltn(data, '', r, opts); + var k = Object.keys(r); + var lft = k.length, o = 0, tot = 0; + var slft = lft, files = new Array(lft); + var term = []; + var tAll = function () { + for (var i = 0; i < term.length; ++i) + term[i](); + }; + var cbd = function (a, b) { + mt(function () { cb(a, b); }); + }; + mt(function () { cbd = cb; }); + var cbf = function () { + var out = new u8(tot + 22), oe = o, cdl = tot - o; + tot = 0; + for (var i = 0; i < slft; ++i) { + var f = files[i]; + try { + var l = f.c.length; + wzh(out, tot, f, f.f, f.u, l); + var badd = 30 + f.f.length + exfl(f.extra); + var loc = tot + badd; + out.set(f.c, loc); + wzh(out, o, f, f.f, f.u, l, tot, f.m), o += 16 + badd + (f.m ? f.m.length : 0), tot = loc + l; + } + catch (e) { + return cbd(e, null); + } + } + wzf(out, o, files.length, cdl, oe); + cbd(null, out); + }; + if (!lft) + cbf(); + var _loop_1 = function (i) { + var fn = k[i]; + var _a = r[fn], file = _a[0], p = _a[1]; + var c = crc(), size = file.length; + c.p(file); + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + var compression = p.level == 0 ? 0 : 8; + var cbl = function (e, d) { + if (e) { + tAll(); + cbd(e, null); + } + else { + var l = d.length; + files[i] = mrg(p, { + size: size, + crc: c.d(), + c: d, + f: f, + m: m, + u: s != fn.length || (m && (com.length != ms)), + compression: compression + }); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + if (!--lft) + cbf(); + } + }; + if (s > 65535) + cbl(err(11, 0, 1), null); + if (!compression) + cbl(null, file); + else if (size < 160000) { + try { + cbl(null, deflateSync(file, p)); + } + catch (e) { + cbl(e, null); + } + } + else + term.push(deflate(file, p, cbl)); + }; + // Cannot use lft because it can decrease + for (var i = 0; i < slft; ++i) { + _loop_1(i); + } + return tAll; +} +/** + * Synchronously creates a ZIP file. Prefer using `zip` for better performance + * with more than one file. + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @returns The generated ZIP archive + */ +function zipSync(data, opts) { + if (!opts) + opts = {}; + var r = {}; + var files = []; + fltn(data, '', r, opts); + var o = 0; + var tot = 0; + for (var fn in r) { + var _a = r[fn], file = _a[0], p = _a[1]; + var compression = p.level == 0 ? 0 : 8; + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + if (s > 65535) + err(11); + var d = compression ? deflateSync(file, p) : file, l = d.length; + var c = crc(); + c.p(file); + files.push(mrg(p, { + size: file.length, + crc: c.d(), + c: d, + f: f, + m: m, + u: s != fn.length || (m && (com.length != ms)), + o: o, + compression: compression + })); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + } + var out = new u8(tot + 22), oe = o, cdl = tot - o; + for (var i = 0; i < files.length; ++i) { + var f = files[i]; + wzh(out, f.o, f, f.f, f.u, f.c.length); + var badd = 30 + f.f.length + exfl(f.extra); + out.set(f.c, f.o + badd); + wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0); + } + wzf(out, o, files.length, cdl, oe); + return out; +} +/** + * Streaming pass-through decompression for ZIP archives + */ +var UnzipPassThrough = /*#__PURE__*/ (function () { + function UnzipPassThrough() { + } + UnzipPassThrough.prototype.push = function (chunk, final) { + // same as ZipPassThrough: cast to retain Buffer ergonomics + this.ondata(null, chunk, final); + }; + UnzipPassThrough.compression = 0; + return UnzipPassThrough; +}()); +exports.UnzipPassThrough = UnzipPassThrough; +/** + * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for + * better performance. + */ +var UnzipInflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + function UnzipInflate() { + var _this = this; + this.i = new Inflate(function (dat, final) { + _this.ondata(null, dat, final); + }); + } + UnzipInflate.prototype.push = function (chunk, final) { + try { + this.i.push(chunk, final); + } + catch (e) { + this.ondata(e, null, final); + } + }; + UnzipInflate.compression = 8; + return UnzipInflate; +}()); +exports.UnzipInflate = UnzipInflate; +/** + * Asynchronous streaming DEFLATE decompression for ZIP archives + */ +var AsyncUnzipInflate = /*#__PURE__*/ (function () { + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + function AsyncUnzipInflate(_, sz) { + var _this = this; + if (sz < 320000) { + this.i = new Inflate(function (dat, final) { + _this.ondata(null, dat, final); + }); + } + else { + this.i = new AsyncInflate(function (err, dat, final) { + _this.ondata(err, dat, final); + }); + this.terminate = this.i.terminate; + } + } + AsyncUnzipInflate.prototype.push = function (chunk, final) { + if (this.i.terminate) + chunk = slc(chunk, 0); + this.i.push(chunk, final); + }; + AsyncUnzipInflate.compression = 8; + return AsyncUnzipInflate; +}()); +exports.AsyncUnzipInflate = AsyncUnzipInflate; +/** + * A ZIP archive decompression stream that emits files as they are discovered + */ +var Unzip = /*#__PURE__*/ (function () { + /** + * Creates a ZIP decompression stream + * @param cb The callback to call whenever a file in the ZIP archive is found + */ + function Unzip(cb) { + this.onfile = cb; + this.k = []; + this.o = { + 0: UnzipPassThrough + }; + this.p = et; + } + /** + * Pushes a chunk to be unzipped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + Unzip.prototype.push = function (chunk, final) { + var _this = this; + if (!this.onfile) + err(5); + if (!this.p) + err(4); + if (this.c > 0) { + var len = Math.min(this.c, chunk.length); + var toAdd = chunk.subarray(0, len); + this.c -= len; + if (this.d) + this.d.push(toAdd, !this.c); + else + this.k[0].push(toAdd); + chunk = chunk.subarray(len); + if (chunk.length) + return this.push(chunk, final); + } + else { + var f = 0, i = 0, is = void 0, buf = void 0; + if (!this.p.length) + buf = chunk; + else if (!chunk.length) + buf = this.p; + else { + buf = new u8(this.p.length + chunk.length); + buf.set(this.p), buf.set(chunk, this.p.length); + } + var l = buf.length, oc = this.c, add = oc && this.d; + var _loop_2 = function () { + var sig = b4(buf, i); + if (sig == 0x4034B50) { + f = 1, is = i; + this_1.d = null; + this_1.c = 0; + var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28); + if (l > i + 30 + fnl + es) { + var chks_3 = []; + this_1.k.unshift(chks_3); + f = 2; + var lsc = b4(buf, i + 18), lsu = b4(buf, i + 22); + var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u); + var _a = z64hs(buf, i, es, 2, lsc, lsu, 0), sc_1 = _a[0], su_1 = _a[1], z64 = _a[3]; + if (dd) + sc_1 = -1 - z64; + i += es; + this_1.c = sc_1; + var d_1; + var file_1 = { + name: fn_1, + compression: cmp_1, + start: function () { + if (!file_1.ondata) + err(5); + if (!sc_1) + file_1.ondata(null, et, true); + else { + var ctr = _this.o[cmp_1]; + if (!ctr) + file_1.ondata(err(14, 'unknown compression type ' + cmp_1, 1), null, false); + d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1); + d_1.ondata = function (err, dat, final) { file_1.ondata(err, dat, final); }; + for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) { + var dat = chks_4[_i]; + d_1.push(dat, false); + } + if (_this.k[0] == chks_3 && _this.c) + _this.d = d_1; + else + d_1.push(et, true); + } + }, + terminate: function () { + if (d_1 && d_1.terminate) + d_1.terminate(); + } + }; + if (sc_1 >= 0) + file_1.size = sc_1, file_1.originalSize = su_1; + this_1.onfile(file_1); + } + return "break"; + } + else if (oc) { + if (sig == 0x8074B50) { + is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0; + return "break"; + } + else if (sig == 0x2014B50) { + is = i -= 4, f = 3, this_1.c = 0; + return "break"; + } + } + }; + var this_1 = this; + for (; i < l - 4; ++i) { + var state_1 = _loop_2(); + if (state_1 === "break") + break; + } + this.p = et; + if (oc < 0) { + var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 0x8074B50 && 4)) : buf.subarray(0, i); + if (add) + add.push(dat, !!f); + else + this.k[+(f == 2)].push(dat); + } + if (f & 2) + return this.push(buf.subarray(i), final); + this.p = buf.subarray(i); + } + if (final) { + if (this.c) + err(13); + this.p = null; + } + }; + /** + * Registers a decoder with the stream, allowing for files compressed with + * the compression type provided to be expanded correctly + * @param decoder The decoder constructor + */ + Unzip.prototype.register = function (decoder) { + this.o[decoder.compression] = decoder; + }; + return Unzip; +}()); +exports.Unzip = Unzip; +var mt = typeof queueMicrotask == 'function' ? queueMicrotask : typeof setTimeout == 'function' ? setTimeout : function (fn) { fn(); }; +function unzip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != 'function') + err(7); + var term = []; + var tAll = function () { + for (var i = 0; i < term.length; ++i) + term[i](); + }; + var files = {}; + var cbd = function (a, b) { + mt(function () { cb(a, b); }); + }; + mt(function () { cbd = cb; }); + var e = data.length - 22; + for (; b4(data, e) != 0x6054B50; --e) { + if (!e || data.length - e > 65558) { + cbd(err(13, 0, 1), null); + return tAll; + } + } + ; + var lft = b2(data, e + 8); + if (lft) { + var c = lft; + var o = b4(data, e + 16); + var z = b4(data, e - 20) == 0x7064B50; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 0x6064B50; + if (z) { + c = lft = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + var _loop_3 = function (i) { + var _a = zh(data, o, z), c_1 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off); + o = no; + var cbl = function (e, d) { + if (e) { + tAll(); + cbd(e, null); + } + else { + if (d) + files[fn] = d; + if (!--lft) + cbd(null, files); + } + }; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_1 + })) { + if (!c_1) + cbl(null, slc(data, b, b + sc)); + else if (c_1 == 8) { + var infl = data.subarray(b, b + sc); + // Synchronously decompress under 512KB, or barely-compressed data + if (su < 524288 || sc > 0.8 * su) { + try { + cbl(null, inflateSync(infl, { out: new u8(su) })); + } + catch (e) { + cbl(e, null); + } + } + else + term.push(inflate(infl, { size: su }, cbl)); + } + else + cbl(err(14, 'unknown compression type ' + c_1, 1), null); + } + else + cbl(null, null); + }; + for (var i = 0; i < c; ++i) { + _loop_3(i); + } + } + else + cbd(null, {}); + return tAll; +} +/** + * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better + * performance with more than one file. + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @returns The decompressed files + */ +function unzipSync(data, opts) { + var files = {}; + var e = data.length - 22; + for (; b4(data, e) != 0x6054B50; --e) { + if (!e || data.length - e > 65558) + err(13); + } + ; + var c = b2(data, e + 8); + if (!c) + return {}; + var o = b4(data, e + 16); + var z = b4(data, e - 20) == 0x7064B50; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 0x6064B50; + if (z) { + c = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + for (var i = 0; i < c; ++i) { + var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off); + o = no; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_2 + })) { + if (!c_2) + files[fn] = slc(data, b, b + sc); + else if (c_2 == 8) + files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) }); + else + err(14, 'unknown compression type ' + c_2); + } + } + return files; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node.d.cts b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node.d.cts new file mode 100644 index 0000000..d430faf --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/node.d.cts @@ -0,0 +1,1539 @@ +/** + * Codes for errors generated within this library + */ +export declare const FlateErrorCode: { + readonly UnexpectedEOF: 0; + readonly InvalidBlockType: 1; + readonly InvalidLengthLiteral: 2; + readonly InvalidDistance: 3; + readonly StreamFinished: 4; + readonly NoStreamHandler: 5; + readonly InvalidHeader: 6; + readonly NoCallback: 7; + readonly InvalidUTF8: 8; + readonly ExtraFieldTooLong: 9; + readonly InvalidDate: 10; + readonly FilenameTooLong: 11; + readonly StreamFinishing: 12; + readonly InvalidZipData: 13; + readonly UnknownCompressionMethod: 14; +}; +/** + * An error generated within this library + */ +export interface FlateError extends Error { + /** + * The code associated with this error + */ + code: number; +} +/** + * Options for decompressing a DEFLATE stream + */ +export interface InflateStreamOptions { + /** + * The dictionary used to compress the original data. If no dictionary was used during compression, this option has no effect. + * + * Supplying the wrong dictionary during decompression usually yields corrupt output or causes an invalid distance error. + */ + dictionary?: Uint8Array; +} +/** + * Options for decompressing DEFLATE data + */ +export interface InflateOptions extends InflateStreamOptions { + /** + * The buffer into which to write the decompressed data. Saves memory if you know the decompressed size in advance. + * + * Note that if the decompression result is larger than the size of this buffer, it will be truncated to fit. + */ + out?: Uint8Array; +} +/** + * Options for decompressing a GZIP stream + */ +export interface GunzipStreamOptions extends InflateStreamOptions { +} +/** + * Options for decompressing GZIP data + */ +export interface GunzipOptions extends InflateStreamOptions { + /** + * The buffer into which to write the decompressed data. GZIP already encodes the output size, so providing this doesn't save memory. + * + * Note that if the decompression result is larger than the size of this buffer, it will be truncated to fit. + */ + out?: Uint8Array; +} +/** + * Options for decompressing a Zlib stream + */ +export interface UnzlibStreamOptions extends InflateStreamOptions { +} +/** + * Options for decompressing Zlib data + */ +export interface UnzlibOptions extends InflateOptions { +} +/** + * Options for compressing data into a DEFLATE format + */ +export interface DeflateOptions { + /** + * The level of compression to use, ranging from 0-9. + * + * 0 will store the data without compression. + * 1 is fastest but compresses the worst, 9 is slowest but compresses the best. + * The default level is 6. + * + * Typically, binary data benefits much more from higher values than text data. + * In both cases, higher values usually take disproportionately longer than the reduction in final size that results. + * + * For example, a 1 MB text file could: + * - become 1.01 MB with level 0 in 1ms + * - become 400 kB with level 1 in 10ms + * - become 320 kB with level 9 in 100ms + */ + level?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; + /** + * The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory. + * + * Note that this is exponential: while level 0 uses 8 kB, level 4 uses 128 kB, level 8 uses 2 MB, and level 12 uses 32 MB. + * It is recommended not to lower the value below 4, since that tends to hurt performance. + * In addition, values above 8 tend to help very little on most data and can even hurt performance. + * + * The default value is automatically determined based on the size of the input data. + */ + mem?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + /** + * A buffer containing common byte sequences in the input data that can be used to significantly improve compression ratios. + * + * Dictionaries should be 32kB or smaller and include strings or byte sequences likely to appear in the input. + * The decompressor must supply the same dictionary as the compressor to extract the original data. + * + * Dictionaries only improve aggregate compression ratio when reused across multiple small inputs. They should typically not be used otherwise. + * + * Avoid using dictionaries with GZIP and ZIP to maximize software compatibility. + */ + dictionary?: Uint8Array; +} +/** + * Options for compressing data into a GZIP format + */ +export interface GzipOptions extends DeflateOptions { + /** + * When the file was last modified. Defaults to the current time. + * Set this to 0 to avoid revealing a modification date entirely. + */ + mtime?: Date | string | number; + /** + * The filename of the data. If the `gunzip` command is used to decompress the data, it will output a file + * with this name instead of the name of the compressed file. + */ + filename?: string; +} +/** + * Options for compressing data into a Zlib format + */ +export interface ZlibOptions extends DeflateOptions { +} +/** + * Handler for data (de)compression streams + * @param data The data output from the stream processor + * @param final Whether this is the final block + */ +export type FlateStreamHandler = (data: Uint8Array, final: boolean) => void; +/** + * Handler for asynchronous data (de)compression streams + * @param err Any error that occurred + * @param data The data output from the stream processor + * @param final Whether this is the final block + */ +export type AsyncFlateStreamHandler = (err: FlateError | null, data: Uint8Array, final: boolean) => void; +/** + * Handler for the asynchronous completion of (de)compression for a data chunk + * @param size The number of bytes that were processed. This is measured in terms of the input + * (i.e. compressed bytes for decompression, uncompressed bytes for compression.) + */ +export type AsyncFlateDrainHandler = (size: number) => void; +/** + * Callback for asynchronous (de)compression methods + * @param err Any error that occurred + * @param data The resulting data. Only present if `err` is null + */ +export type FlateCallback = (err: FlateError | null, data: Uint8Array) => void; +interface AsyncOptions { + /** + * Whether or not to "consume" the source data. This will make the typed array/buffer you pass in + * unusable but will increase performance and reduce memory usage. + */ + consume?: boolean; +} +/** + * Options for compressing data asynchronously into a DEFLATE format + */ +export interface AsyncDeflateOptions extends DeflateOptions, AsyncOptions { +} +/** + * Options for decompressing DEFLATE data asynchronously + */ +export interface AsyncInflateOptions extends AsyncOptions, InflateStreamOptions { + /** + * The original size of the data. Currently, the asynchronous API disallows + * writing into a buffer you provide; the best you can do is provide the + * size in bytes and be given back a new typed array. + */ + size?: number; +} +/** + * Options for compressing data asynchronously into a GZIP format + */ +export interface AsyncGzipOptions extends GzipOptions, AsyncOptions { +} +/** + * Options for decompressing GZIP data asynchronously + */ +export interface AsyncGunzipOptions extends AsyncOptions, InflateStreamOptions { +} +/** + * Options for compressing data asynchronously into a Zlib format + */ +export interface AsyncZlibOptions extends ZlibOptions, AsyncOptions { +} +/** + * Options for decompressing Zlib data asynchronously + */ +export interface AsyncUnzlibOptions extends AsyncInflateOptions { +} +/** + * A terminable compression/decompression process + */ +export interface AsyncTerminable { + /** + * Terminates the worker thread immediately. The callback will not be called. + */ + (): void; +} +/** + * Streaming DEFLATE compression + */ +export declare class Deflate { + /** + * Creates a DEFLATE stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: DeflateOptions, cb?: FlateStreamHandler); + /** + * Creates a DEFLATE stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + private b; + private s; + private o; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + private p; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE compression + */ +export declare class AsyncDeflate { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous DEFLATE stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: DeflateOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous DEFLATE stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * deflated output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. A separate DEFLATE stream may be concatenated + * with the current output after a sync flush. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function deflate(data: Uint8Array, opts: AsyncDeflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param cb The function to be called upon compression completion + */ +export declare function deflate(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compresses data with DEFLATE without any wrapper + * @param data The data to compress + * @param opts The compression options + * @returns The deflated version of the data + */ +export declare function deflateSync(data: Uint8Array, opts?: DeflateOptions): Uint8Array; +/** + * Streaming DEFLATE decompression + */ +export declare class Inflate { + private s; + private o; + private p; + private d; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a DEFLATE decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: InflateStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a DEFLATE decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + private e; + private c; + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the final chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE decompression + */ +export declare class AsyncInflate { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous DEFLATE decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: InflateStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous DEFLATE decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be inflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function inflate(data: Uint8Array, opts: AsyncInflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function inflate(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands DEFLATE data with no wrapper + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function inflateSync(data: Uint8Array): Uint8Array; +/** + * Expands DEFLATE data with no wrapper + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function inflateSync(data: Uint8Array, opts?: InflateOptions): Uint8Array; +/** + * Streaming GZIP compression + */ +export declare class Gzip { + private c; + private l; + private v; + private o; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a GZIP stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: GzipOptions, cb?: FlateStreamHandler); + /** + * Creates a GZIP stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + private p; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming GZIP compression + */ +export declare class AsyncGzip { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous GZIP stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: GzipOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous GZIP stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be GZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * GZIPped output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function gzip(data: Uint8Array, opts: AsyncGzipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with GZIP + * @param data The data to compress + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gzip(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compresses data with GZIP + * @param data The data to compress + * @param opts The compression options + * @returns The gzipped version of the data + */ +export declare function gzipSync(data: Uint8Array, opts?: GzipOptions): Uint8Array; +/** + * Handler for new GZIP members in concatenated GZIP streams. Useful for building indices used to perform random-access reads on compressed files. + * @param offset The offset of the new member relative to the start of the stream + */ +export type GunzipMemberHandler = (offset: number) => void; +/** + * Streaming single or multi-member GZIP decompression + */ +export declare class Gunzip { + private v; + private r; + private o; + private p; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * The handler to call whenever a new GZIP member is found + */ + onmember?: GunzipMemberHandler; + /** + * Creates a GUNZIP stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: GunzipStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a GUNZIP stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming single or multi-member GZIP decompression + */ +export declare class AsyncGunzip { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * The handler to call whenever a new GZIP member is found + */ + onmember?: GunzipMemberHandler; + /** + * Creates an asynchronous GUNZIP stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: GunzipStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous GUNZIP stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be GUNZIPped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands GZIP data + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gunzip(data: Uint8Array, opts: AsyncGunzipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands GZIP data + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function gunzip(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands GZIP data + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function gunzipSync(data: Uint8Array): Uint8Array; +/** + * Expands GZIP data + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function gunzipSync(data: Uint8Array, opts?: GunzipOptions): Uint8Array; +/** + * Streaming Zlib compression + */ +export declare class Zlib { + private c; + private v; + private o; + private s; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a Zlib stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: ZlibOptions, cb?: FlateStreamHandler); + /** + * Creates a Zlib stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be zlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + private p; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; +} +/** + * Asynchronous streaming Zlib compression + */ +export declare class AsyncZlib { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of uncompressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous Zlib stream + * @param opts The compression options + * @param cb The callback to call whenever data is deflated + */ + constructor(opts: ZlibOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous Zlib stream + * @param cb The callback to call whenever data is deflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Flushes buffered uncompressed data. Useful to immediately retrieve the + * zlibbed output for small inputs. + * @param sync Whether to flush to a byte boundary. A sync flush takes 4-5 + * extra bytes, but guarantees all pushed data is immediately + * decompressible. + */ + flush(sync?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously compresses data with Zlib + * @param data The data to compress + * @param opts The compression options + * @param cb The function to be called upon compression completion + */ +export declare function zlib(data: Uint8Array, opts: AsyncZlibOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously compresses data with Zlib + * @param data The data to compress + * @param cb The function to be called upon compression completion + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zlib(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Compress data with Zlib + * @param data The data to compress + * @param opts The compression options + * @returns The zlib-compressed version of the data + */ +export declare function zlibSync(data: Uint8Array, opts?: ZlibOptions): Uint8Array; +/** + * Streaming Zlib decompression + */ +export declare class Unzlib { + private v; + private p; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a Zlib decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: UnzlibStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a Zlib decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be unzlibbed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming Zlib decompression + */ +export declare class AsyncUnzlib { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous Zlib decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is inflated + */ + constructor(opts: UnzlibStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous Zlib decompression stream + * @param cb The callback to call whenever data is inflated + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Pushes a chunk to be decompressed from Zlib + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * A method to terminate the stream's internal worker. Subsequent calls to + * push() will silently fail. + */ + terminate: AsyncTerminable; +} +/** + * Asynchronously expands Zlib data + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function unzlib(data: Uint8Array, opts: AsyncUnzlibOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously expands Zlib data + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function unzlib(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands Zlib data + * @param data The data to decompress + * @returns The decompressed version of the data + */ +export declare function unzlibSync(data: Uint8Array): Uint8Array; +/** + * Expands Zlib data + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function unzlibSync(data: Uint8Array, opts?: UnzlibOptions): Uint8Array; +export { gzip as compress, AsyncGzip as AsyncCompress }; +export { gzipSync as compressSync, Gzip as Compress }; +/** + * Streaming GZIP, Zlib, or raw DEFLATE decompression + */ +export declare class Decompress { + private G; + private I; + private Z; + private o; + private s; + private p; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; + /** + * Creates a decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is decompressed + */ + constructor(opts: InflateStreamOptions, cb?: FlateStreamHandler); + /** + * Creates a decompression stream + * @param cb The callback to call whenever data is decompressed + */ + constructor(cb?: FlateStreamHandler); + private i; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression + */ +export declare class AsyncDecompress { + private G; + private I; + private Z; + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The handler to call whenever buffered source data is processed (i.e. `queuedSize` updates) + */ + ondrain?: AsyncFlateDrainHandler; + /** + * The number of compressed bytes buffered in the stream + */ + queuedSize: number; + /** + * Creates an asynchronous decompression stream + * @param opts The decompression options + * @param cb The callback to call whenever data is decompressed + */ + constructor(opts: InflateStreamOptions, cb?: AsyncFlateStreamHandler); + /** + * Creates an asynchronous decompression stream + * @param cb The callback to call whenever data is decompressed + */ + constructor(cb?: AsyncFlateStreamHandler); + private i; + /** + * Pushes a chunk to be decompressed + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchrononously expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function decompress(data: Uint8Array, opts: AsyncInflateOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchrononously expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param cb The function to be called upon decompression completion + * @returns A function that can be used to immediately terminate the decompression + */ +export declare function decompress(data: Uint8Array, cb: FlateCallback): AsyncTerminable; +/** + * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format + * @param data The data to decompress + * @param opts The decompression options + * @returns The decompressed version of the data + */ +export declare function decompressSync(data: Uint8Array, opts?: InflateOptions): Uint8Array; +/** + * Attributes for files added to a ZIP archive object + */ +export interface ZipAttributes { + /** + * The operating system of origin for this file. The value is defined + * by PKZIP's APPNOTE.txt, section 4.4.2.2. For example, 0 (the default) + * is MS/DOS, 3 is Unix, 19 is macOS. + */ + os?: number; + /** + * The file's attributes. These are traditionally somewhat complicated + * and platform-dependent, so using them is scarcely necessary. However, + * here is a representation of what this is, bit by bit: + * + * `TTTTugtrwxrwxrwx0000000000ADVSHR` + * + * TTTT = file type (rarely useful) + * + * u = setuid, g = setgid, t = sticky + * + * rwx = user permissions, rwx = group permissions, rwx = other permissions + * + * 0000000000 = unused + * + * A = archive, D = directory, V = volume label, S = system file, H = hidden, R = read-only + * + * If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0o644 << 16. + * Note that attributes usually only work in conjunction with the `os` setting: you must use + * `os` = 3 (Unix) if you want to set Unix permissions + */ + attrs?: number; + /** + * Extra metadata to add to the file. This field is defined by PKZIP's APPNOTE.txt, + * section 4.4.28. At most 65,535 bytes may be used in each ID. The ID must be an + * integer between 0 and 65,535, inclusive. + * + * This field is incredibly rare and almost never needed except for compliance with + * proprietary standards and software. + */ + extra?: Record; + /** + * The comment to attach to the file. This field is defined by PKZIP's APPNOTE.txt, + * section 4.4.26. The comment must be at most 65,535 bytes long UTF-8 encoded. This + * field is not read by consumer software. + */ + comment?: string; + /** + * When the file was last modified. Defaults to the current time. + */ + mtime?: GzipOptions['mtime']; +} +/** + * Options for creating a ZIP archive + */ +export interface ZipOptions extends DeflateOptions, ZipAttributes { +} +/** + * Options for expanding a ZIP archive + */ +export interface UnzipOptions { + /** + * A filter function to extract only certain files from a ZIP archive + */ + filter?: UnzipFileFilter; +} +/** + * Options for asynchronously creating a ZIP archive + */ +export interface AsyncZipOptions extends AsyncDeflateOptions, ZipAttributes { +} +/** + * Options for asynchronously expanding a ZIP archive + */ +export interface AsyncUnzipOptions extends UnzipOptions { +} +/** + * A file that can be used to create a ZIP archive + */ +export type ZippableFile = Uint8Array | Zippable | [Uint8Array | Zippable, ZipOptions]; +/** + * A file that can be used to asynchronously create a ZIP archive + */ +export type AsyncZippableFile = Uint8Array | AsyncZippable | [Uint8Array | AsyncZippable, AsyncZipOptions]; +/** + * The complete directory structure of a ZIPpable archive + */ +export interface Zippable { + [path: string]: ZippableFile; +} +/** + * The complete directory structure of an asynchronously ZIPpable archive + */ +export interface AsyncZippable { + [path: string]: AsyncZippableFile; +} +/** + * An unzipped archive. The full path of each file is used as the key, + * and the file is the value + */ +export interface Unzipped { + [path: string]: Uint8Array; +} +/** + * Handler for string generation streams + * @param data The string output from the stream processor + * @param final Whether this is the final block + */ +export type StringStreamHandler = (data: string, final: boolean) => void; +/** + * Callback for asynchronous ZIP decompression + * @param err Any error that occurred + * @param data The decompressed ZIP archive + */ +export type UnzipCallback = (err: FlateError | null, data: Unzipped) => void; +/** + * Handler for streaming ZIP decompression + * @param file The file that was found in the archive + */ +export type UnzipFileHandler = (file: UnzipFile) => void; +/** + * Streaming UTF-8 decoding + */ +export declare class DecodeUTF8 { + private p; + private t; + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is decoded + */ + constructor(cb?: StringStreamHandler); + /** + * Pushes a chunk to be decoded from UTF-8 binary + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * The handler to call whenever data is available + */ + ondata: StringStreamHandler; +} +/** + * Streaming UTF-8 encoding + */ +export declare class EncodeUTF8 { + private d; + /** + * Creates a UTF-8 decoding stream + * @param cb The callback to call whenever data is encoded + */ + constructor(cb?: FlateStreamHandler); + /** + * Pushes a chunk to be encoded to UTF-8 + * @param chunk The string data to push + * @param final Whether this is the last chunk + */ + push(chunk: string, final?: boolean): void; + /** + * The handler to call whenever data is available + */ + ondata: FlateStreamHandler; +} +/** + * Converts a string into a Uint8Array for use with compression/decompression methods + * @param str The string to encode + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless decoding a binary string. + * @returns The string encoded in UTF-8/Latin-1 binary + */ +export declare function strToU8(str: string, latin1?: boolean): Uint8Array; +/** + * Converts a Uint8Array to a string + * @param dat The data to decode to string + * @param latin1 Whether or not to interpret the data as Latin-1. This should + * not need to be true unless encoding to binary string. + * @returns The original UTF-8/Latin-1 string + */ +export declare function strFromU8(dat: Uint8Array, latin1?: boolean): string; +/** + * A stream that can be used to create a file in a ZIP archive + */ +export interface ZipInputFile extends ZipAttributes { + /** + * The filename to associate with the data provided to this stream. If you + * want a file in a subdirectory, use forward slashes as a separator (e.g. + * `directory/filename.ext`). This will still work on Windows. + */ + filename: string; + /** + * The size of the file in bytes. This attribute may be invalid after + * the file is added to the ZIP archive; it must be correct only before the + * stream completes. + * + * If you don't want to have to compute this yourself, consider extending the + * ZipPassThrough class and overriding its process() method, or using one of + * ZipDeflate or AsyncZipDeflate. + */ + size: number; + /** + * A CRC of the original file contents. This attribute may be invalid after + * the file is added to the ZIP archive; it must be correct only before the + * stream completes. + * + * If you don't want to have to generate this yourself, consider extending the + * ZipPassThrough class and overriding its process() method, or using one of + * ZipDeflate or AsyncZipDeflate. + */ + crc: number; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA + */ + compression: number; + /** + * Bits 1 and 2 of the general purpose bit flag, specified in PKZIP's + * APPNOTE.txt, section 4.4.4. Should be between 0 and 3. This is unlikely + * to be necessary. + */ + flag?: number; + /** + * The handler to be called when data is added. After passing this stream to + * the ZIP file object, this handler will always be defined. To call it: + * + * `stream.ondata(error, chunk, final)` + * + * error = any error that occurred (null if there was no error) + * + * chunk = a Uint8Array of the data that was added (null if there was an + * error) + * + * final = boolean, whether this is the final chunk in the stream + */ + ondata?: AsyncFlateStreamHandler; + /** + * A method called when the stream is no longer needed, for clean-up + * purposes. This will not always be called after the stream completes, + * so you may wish to call this.terminate() after the final chunk is + * processed if you have clean-up logic. + */ + terminate?: AsyncTerminable; +} +/** + * A pass-through stream to keep data uncompressed in a ZIP archive. + */ +export declare class ZipPassThrough implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private c; + /** + * Creates a pass-through stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + */ + constructor(filename: string); + /** + * Processes a chunk and pushes to the output stream. You can override this + * method in a subclass for custom behavior, but by default this passes + * the data through. You must call this.ondata(err, chunk, final) at some + * point in this method. + * @param chunk The chunk to process + * @param final Whether this is the last chunk + */ + protected process(chunk: Uint8Array, final: boolean): void; + /** + * Pushes a chunk to be added. If you are subclassing this with a custom + * compression algorithm, note that you must push data from the source + * file only, pre-compression. + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate + * for better performance + */ +export declare class ZipDeflate implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + flag: 0 | 1 | 2 | 3; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private d; + /** + * Creates a DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + constructor(filename: string, opts?: DeflateOptions); + private process; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * Asynchronous streaming DEFLATE compression for ZIP archives + */ +export declare class AsyncZipDeflate implements ZipInputFile { + filename: string; + crc: number; + size: number; + compression: number; + flag: 0 | 1 | 2 | 3; + os?: number; + attrs?: number; + comment?: string; + extra?: Record; + mtime?: GzipOptions['mtime']; + ondata: AsyncFlateStreamHandler; + private d; + terminate: AsyncTerminable; + /** + * Creates an asynchronous DEFLATE stream that can be added to ZIP archives + * @param filename The filename to associate with this data stream + * @param opts The compression options + */ + constructor(filename: string, opts?: DeflateOptions); + private process; + /** + * Pushes a chunk to be deflated + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; +} +/** + * A zippable archive to which files can incrementally be added + */ +export declare class Zip { + private u; + private d; + /** + * Creates an empty ZIP archive to which files can be added + * @param cb The callback to call whenever data for the generated ZIP archive + * is available + */ + constructor(cb?: AsyncFlateStreamHandler); + /** + * Adds a file to the ZIP archive + * @param file The file stream to add + */ + add(file: ZipInputFile): void; + /** + * Ends the process of adding files and prepares to emit the final chunks. + * This *must* be called after adding all desired files for the resulting + * ZIP file to work properly. + */ + end(): void; + private e; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to add() will fail. + */ + terminate(): void; + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; +} +/** + * Asynchronously creates a ZIP file + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @param cb The callback to call with the generated ZIP archive + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zip(data: AsyncZippable, opts: AsyncZipOptions, cb: FlateCallback): AsyncTerminable; +/** + * Asynchronously creates a ZIP file + * @param data The directory structure for the ZIP archive + * @param cb The callback to call with the generated ZIP archive + * @returns A function that can be used to immediately terminate the compression + */ +export declare function zip(data: AsyncZippable, cb: FlateCallback): AsyncTerminable; +/** + * Synchronously creates a ZIP file. Prefer using `zip` for better performance + * with more than one file. + * @param data The directory structure for the ZIP archive + * @param opts The main options, merged with per-file options + * @returns The generated ZIP archive + */ +export declare function zipSync(data: Zippable, opts?: ZipOptions): Uint8Array; +/** + * A decoder for files in ZIP streams + */ +export interface UnzipDecoder { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * Pushes a chunk to be decompressed + * @param chunk The data in this chunk. Do not consume (detach) this buffer. + * @param final Whether this is the last chunk in the data stream + */ + push(chunk: Uint8Array, final: boolean): void; + /** + * A method to terminate any internal workers used by the stream. Subsequent + * calls to push() should silently fail. + */ + terminate?: AsyncTerminable; +} +/** + * A constructor for a decoder for unzip streams + */ +export interface UnzipDecoderConstructor { + /** + * Creates an instance of the decoder + * @param filename The name of the file + * @param size The compressed size of the file + * @param originalSize The original size of the file + */ + new (filename: string, size?: number, originalSize?: number): UnzipDecoder; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA + */ + compression: number; +} +/** + * Information about a file to be extracted from a ZIP archive + */ +export interface UnzipFileInfo { + /** + * The name of the file + */ + name: string; + /** + * The compressed size of the file + */ + size: number; + /** + * The original size of the file + */ + originalSize: number; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA. If the filter function returns true + * but this value is not 8, the unzip function will throw. + */ + compression: number; +} +/** + * A filter for files to be extracted during the unzipping process + * @param file The info for the current file being processed + * @returns Whether or not to extract the current file + */ +export type UnzipFileFilter = (file: UnzipFileInfo) => boolean; +/** + * Streaming file extraction from ZIP archives + */ +export interface UnzipFile { + /** + * The handler to call whenever data is available + */ + ondata: AsyncFlateStreamHandler; + /** + * The name of the file + */ + name: string; + /** + * The compression format for the data stream. This number is determined by + * the spec in PKZIP's APPNOTE.txt, section 4.4.5. For example, 0 = no + * compression, 8 = deflate, 14 = LZMA. If start() is called but there is no + * decompression stream available for this method, start() will throw. + */ + compression: number; + /** + * The compressed size of the file. Will not be present for archives created + * in a streaming fashion. + */ + size?: number; + /** + * The original size of the file. Will not be present for archives created + * in a streaming fashion. + */ + originalSize?: number; + /** + * Starts reading from the stream. Calling this function will always enable + * this stream, but ocassionally the stream will be enabled even without + * this being called. + */ + start(): void; + /** + * A method to terminate any internal workers used by the stream. ondata + * will not be called any further. + */ + terminate: AsyncTerminable; +} +/** + * Streaming pass-through decompression for ZIP archives + */ +export declare class UnzipPassThrough implements UnzipDecoder { + static compression: number; + ondata: AsyncFlateStreamHandler; + push(chunk: Uint8Array, final: boolean): void; +} +/** + * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for + * better performance. + */ +export declare class UnzipInflate implements UnzipDecoder { + static compression: number; + private i; + ondata: AsyncFlateStreamHandler; + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + constructor(); + push(chunk: Uint8Array, final: boolean): void; +} +/** + * Asynchronous streaming DEFLATE decompression for ZIP archives + */ +export declare class AsyncUnzipInflate implements UnzipDecoder { + static compression: number; + private i; + ondata: AsyncFlateStreamHandler; + terminate: AsyncTerminable; + /** + * Creates a DEFLATE decompression that can be used in ZIP archives + */ + constructor(_: string, sz?: number); + push(chunk: Uint8Array, final: boolean): void; +} +/** + * A ZIP archive decompression stream that emits files as they are discovered + */ +export declare class Unzip { + private d; + private c; + private p; + private k; + private o; + /** + * Creates a ZIP decompression stream + * @param cb The callback to call whenever a file in the ZIP archive is found + */ + constructor(cb?: UnzipFileHandler); + /** + * Pushes a chunk to be unzipped + * @param chunk The chunk to push + * @param final Whether this is the last chunk + */ + push(chunk: Uint8Array, final?: boolean): void; + /** + * Registers a decoder with the stream, allowing for files compressed with + * the compression type provided to be expanded correctly + * @param decoder The decoder constructor + */ + register(decoder: UnzipDecoderConstructor): void; + /** + * The handler to call whenever a file is discovered + */ + onfile: UnzipFileHandler; +} +/** + * Asynchronously decompresses a ZIP archive + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @param cb The callback to call with the decompressed files + * @returns A function that can be used to immediately terminate the unzipping + */ +export declare function unzip(data: Uint8Array, opts: AsyncUnzipOptions, cb: UnzipCallback): AsyncTerminable; +/** + * Asynchronously decompresses a ZIP archive + * @param data The raw compressed ZIP file + * @param cb The callback to call with the decompressed files + * @returns A function that can be used to immediately terminate the unzipping + */ +export declare function unzip(data: Uint8Array, cb: UnzipCallback): AsyncTerminable; +/** + * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better + * performance with more than one file. + * @param data The raw compressed ZIP file + * @param opts The ZIP extraction options + * @returns The decompressed files + */ +export declare function unzipSync(data: Uint8Array, opts?: UnzipOptions): Unzipped; diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/worker.cjs b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/worker.cjs new file mode 100644 index 0000000..9a283bd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/lib/worker.cjs @@ -0,0 +1,20 @@ +"use strict"; +var ch2 = {}; +exports.default = (function (c, id, msg, transfer, cb) { + var w = new Worker(ch2[id] || (ch2[id] = URL.createObjectURL(new Blob([ + c + ';addEventListener("error",function(e){e=e.error;postMessage({$e$:[e.message,e.code,e.stack]})})' + ], { type: 'text/javascript' })))); + w.onmessage = function (e) { + var d = e.data, ed = d.$e$; + if (ed) { + var err = new Error(ed[0]); + err['code'] = ed[1]; + err.stack = ed[2]; + cb(err, null); + } + else + cb(null, d); + }; + w.postMessage(msg, transfer); + return w; +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/package.json b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/package.json new file mode 100644 index 0000000..c37a536 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/package.json @@ -0,0 +1,128 @@ +{ + "name": "fflate", + "version": "0.8.3", + "description": "High performance (de)compression in an 8kB package", + "main": "./lib/index.cjs", + "module": "./esm/browser.js", + "types": "./lib/index.d.ts", + "unpkg": "./umd/index.js", + "jsdelivr": "./umd/index.js", + "browser": { + "./lib/node-worker.cjs": "./lib/worker.cjs" + }, + "exports": { + ".": { + "node": { + "import": { + "types": "./esm/index.d.mts", + "default": "./esm/index.mjs" + }, + "require": { + "types": "./lib/node.d.cts", + "default": "./lib/node.cjs" + } + }, + "import": { + "types": "./esm/browser.d.ts", + "default": "./esm/browser.js" + }, + "require": { + "types": "./lib/browser.d.cts", + "default": "./lib/browser.cjs" + } + }, + "./node": { + "import": { + "types": "./esm/index.d.mts", + "default": "./esm/index.mjs" + }, + "require": { + "types": "./lib/node.d.cts", + "default": "./lib/node.cjs" + } + }, + "./browser": { + "import": { + "types": "./esm/browser.d.ts", + "default": "./esm/browser.js" + }, + "require": { + "types": "./lib/browser.d.cts", + "default": "./lib/browser.cjs" + } + }, + "./package.json": "./package.json" + }, + "targets": { + "main": false, + "module": false, + "browser": false, + "types": false + }, + "sideEffects": false, + "homepage": "https://101arrowz.github.io/fflate", + "repository": "https://github.com/101arrowz/fflate", + "bugs": { + "email": "arjunbarrett@gmail.com", + "url": "https://github.com/101arrowz/fflate/issues" + }, + "author": "Arjun Barrett ", + "license": "MIT", + "keywords": [ + "gzip", + "gunzip", + "deflate", + "inflate", + "compression", + "decompression", + "zlib", + "pako", + "jszip", + "browser", + "node.js", + "tiny", + "fast", + "zip", + "unzip", + "non-blocking" + ], + "scripts": { + "build": "npm run build:lib && npm run build:docs && npm run build:demo", + "script": "node -r ts-node/register scripts/$SC.ts", + "build:lib": "tsc && tsc --project tsconfig.esm.json && npm run build:rewrite && npm run build:umd", + "build:umd": "SC=buildUMD npm run script", + "build:rewrite": "SC=rewriteBuilds npm run script", + "build:demo": "tsc --project tsconfig.demo.json && parcel build demo/index.html --no-cache --public-url \"./\" && SC=cpGHPages npm run script", + "build:docs": "typedoc --plugin typedoc-plugin-markdown --hideBreadcrumbs --readme none --disableSources --excludePrivate --excludeProtected --expandParameters --githubPages false --out docs/ src/index.ts", + "test": "TS_NODE_PROJECT=test/tsconfig.json uvu -b -r ts-node/register test", + "prepack": "npm run build && npm run test" + }, + "devDependencies": { + "@parcel/service-worker": "^2.9.3", + "@types/node": "^25.8.0", + "@types/pako": "*", + "@types/react": "^18.2.21", + "@types/react-dom": "^18.2.7", + "jszip": "^3.10.1", + "pako": "*", + "parcel": "^2.9.3", + "preact": "^10.17.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "simple-git": "^3.19.1", + "terser": "^5.47.1", + "tiny-inflate": "*", + "ts-node": "^10.9.2", + "typedoc": "^0.28.19", + "typedoc-plugin-markdown": "^4.11.0", + "typescript": "^6.0.3", + "uvu": "^0.5.6", + "uzip": "*" + }, + "alias": { + "react": "preact/compat", + "react-dom": "preact/compat", + "buffer": false, + "process": false + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/umd/index.js b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/umd/index.js new file mode 100644 index 0000000..df76237 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/umd/index.js @@ -0,0 +1 @@ +!function(f){typeof module!='undefined'&&typeof exports=='object'?module.exports=f():typeof define!='undefined'&&define.amd?define(f):(typeof self!='undefined'?self:this).fflate=f()}(function(){var _e={};"use strict";_e.deflate=zt,_e.deflateSync=kt,_e.inflate=At,_e.inflateSync=Tt,_e.gzip=It,_e.compress=It,_e.gzipSync=Ut,_e.compressSync=Ut,_e.gunzip=Zt,_e.gunzipSync=qt,_e.zlib=Lt,_e.zlibSync=Bt,_e.unzlib=Nt,_e.unzlibSync=Pt,_e.gzip=It,_e.compress=It,_e.decompress=Jt,_e.decompressSync=Kt,_e.strToU8=nn,_e.strFromU8=rn,_e.zip=dn,_e.zipSync=gn,_e.unzip=zn,_e.unzipSync=kn;var t=(typeof module!='undefined'&&typeof exports=='object'?function(_f){"use strict";var e,r,t,n=";var __w=require('worker_threads');__w.parentPort.on('message',function(m){onmessage({data:m})}),postMessage=function(m,t){__w.parentPort.postMessage(m,t)},close=process.exit;self=global";try{e=require("worker_threads"),r=e.Worker,t=e.isMarkedAsUntransferable}catch(e){}exports.default=r?function(e,o,a,s,u){var i=!1,l=new r(e+n,{eval:!0}).on("error",function(e){return u(e,null)}).on("message",function(e){return u(null,e)}).on("exit",function(e){e&&!i&&u(Error("exited with code "+e),null)});return t&&(s=s.filter(function(e){return!t(e)})),l.postMessage(a,s),l.terminate=function(){return i=!0,r.prototype.terminate.call(l)},l}:function(e,r,t,n,o){setImmediate(function(){return o(Error("async operations unsupported - update to Node 12+ (or Node 10-11 with the --experimental-worker CLI flag)"),null)});var a=function(){};return{terminate:a,postMessage:a}};return _f}:function(_f){"use strict";var e={};_f.default=function(r,t,s,a,n){var o=new Worker(e[t]||(e[t]=URL.createObjectURL(new Blob([r+';addEventListener("error",function(e){e=e.error;postMessage({$e$:[e.message,e.code,e.stack]})})'],{type:"text/javascript"}))));return o.onmessage=function(e){var r=e.data,t=r.$e$;if(t){var s=Error(t[0]);s.code=t[1],s.stack=t[2],n(s,null)}else n(null,r)},o.postMessage(s,a),o};return _f})({}),n=Uint8Array,r=Uint16Array,i=Int32Array,e=new n([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),o=new n([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),s=new n([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),a=function(t,n){for(var e=new r(31),o=0;o<31;++o)e[o]=n+=1<>1|(21845&d)<<1;v[d]=((65280&(g=(61680&(g=(52428&g)>>2|(13107&g)<<2))>>4|(3855&g)<<4))>>8|(255&g)<<8)>>1}var y=function(t,n,i){for(var e=t.length,o=0,s=new r(n);o>h]=f}else for(a=new r(e),o=0;o>15-t[o]);return a},m=new n(288);for(d=0;d<144;++d)m[d]=8;for(d=144;d<256;++d)m[d]=9;for(d=256;d<280;++d)m[d]=7;for(d=280;d<288;++d)m[d]=8;var b=new n(32);for(d=0;d<32;++d)b[d]=5;var w=y(m,9,0),x=y(m,9,1),z=y(b,5,0),k=y(b,5,1),M=function(t){for(var n=t[0],r=1;rn&&(n=t[r]);return n},S=function(t,n,r){var i=n/8|0;return(t[i]|t[i+1]<<8)>>(7&n)&r},A=function(t,n){var r=n/8|0;return(t[r]|t[r+1]<<8|t[r+2]<<16)>>(7&n)},T=function(t){return(t+7)/8|0},D=function(t,r,i){return(null==r||r<0)&&(r=0),(null==i||i>t.length)&&(i=t.length),new n(t.subarray(r,i))};_e.FlateErrorCode={UnexpectedEOF:0,InvalidBlockType:1,InvalidLengthLiteral:2,InvalidDistance:3,StreamFinished:4,NoStreamHandler:5,InvalidHeader:6,NoCallback:7,InvalidUTF8:8,ExtraFieldTooLong:9,InvalidDate:10,FilenameTooLong:11,StreamFinishing:12,InvalidZipData:13,UnknownCompressionMethod:14};var C=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],I=function(t,n,r){var i=Error(n||C[t]);if(i.code=t,Error.captureStackTrace&&Error.captureStackTrace(i,I),!r)throw i;return i},U=function(t,r,i,a){var u=t.length,f=a?a.length:0;if(!u||r.f&&!r.l)return i||new n(0);var c=!i,p=c||2!=r.i,v=r.i;c&&(i=new n(3*u));var d=function(t){var r=i.length;if(t>r){var e=new n(Math.max(2*r,t));e.set(i),i=e}},g=r.f||0,m=r.p||0,b=r.b||0,w=r.l,z=r.d,C=r.m,U=r.n,F=8*u;do{if(!w){g=S(t,m,1);var E=S(t,m+1,3);if(m+=3,!E){var Z=t[(Y=T(m)+4)-4]|t[Y-3]<<8,q=Y+Z;if(q>u){v&&I(0);break}p&&d(b+Z),i.set(t.subarray(Y,q),b),r.b=b+=Z,r.p=m=8*q,r.f=g;continue}if(1==E)w=x,z=k,C=9,U=5;else if(2==E){var O=S(t,m,31)+257,G=S(t,m+10,15)+4,L=O+S(t,m+5,31)+1;m+=14;for(var B=new n(L),H=new n(19),j=0;j>4)<16)B[j++]=Y;else{var K=0,Q=0;for(16==Y?(Q=3+S(t,m,3),m+=2,K=B[j-1]):17==Y?(Q=3+S(t,m,7),m+=3):18==Y&&(Q=11+S(t,m,127),m+=7);Q--;)B[j++]=K}}var R=B.subarray(0,O),W=B.subarray(O);C=M(R),U=M(W),w=y(R,C,1),z=y(W,U,1)}else I(1);if(m>F){v&&I(0);break}}p&&d(b+131072);for(var X=(1<>4;if((m+=15&K)>F){v&&I(0);break}if(K||I(2),tt<256)i[b++]=tt;else{if(256==tt){_=m,w=null;break}var nt=tt-254;tt>264&&(nt=S(t,m,(1<<(et=e[j=tt-257]))-1)+h[j],m+=et);var rt=z[A(t,m)&$],it=rt>>4;if(rt||I(3),m+=15&rt,W=l[it],it>3){var et=o[it];W+=A(t,m)&(1<F){v&&I(0);break}p&&d(b+131072);var ot=b+nt;if(b>8},E=function(t,n,r){var i=n/8|0;t[i]|=r<<=7&n,t[i+1]|=r>>8,t[i+2]|=r>>16},Z=function(t,i){for(var e=[],o=0;ov&&(v=a[o].s);var d=new r(v+1),g=q(e[l-1],d,0);if(g>i){o=0;var y=0,m=g-i,b=1<i))break;y+=b-(1<>=m;y>0;){var x=a[o].s;d[x]=0&&y;--o){var z=a[o].s;d[z]==i&&(--d[z],++y)}g=i}return{t:new n(d),l:g}},q=function(t,n,r){return-1==t.s?Math.max(q(t.l,n,r+1),q(t.r,n,r+1)):n[t.s]=r},O=function(t){for(var n=t.length;n&&!t[--n];);for(var i=new r(++n),e=0,o=t[0],s=1,a=function(t){i[e++]=t},u=1;u<=n;++u)if(t[u]==o&&u!=n)++s;else{if(!o&&s>2){for(;s>138;s-=138)a(32754);s>2&&(a(s>10?s-11<<5|28690:s-3<<5|12305),s=0)}else if(s>3){for(a(o),--s;s>6;s-=6)a(8304);s>2&&(a(s-3<<5|8208),s=0)}for(;s--;)a(o);s=1,o=t[u]}return{c:i.subarray(0,e),n:n}},G=function(t,n){for(var r=0,i=0;i>8,t[e+2]=255^t[e],t[e+3]=255^t[e+1];for(var o=0;o4&&!j[s[P-1]];--P);var V,Y,J,K,Q=p+5<<3,R=G(u,m)+G(h,b)+f,W=G(u,g)+G(h,M)+f+14+3*P+G(q,j)+2*q[16]+3*q[17]+7*q[18];if(l>=0&&Q<=R&&Q<=W)return L(n,v,t.subarray(l,l+p));if(F(n,v,1+(W15&&(F(n,v,tt[B]>>5&127),v+=tt[B]>>12)}}else V=w,Y=m,J=z,K=b;for(B=0;B255){var rt;E(n,v,V[257+(rt=nt>>18&31)]),v+=Y[rt+257],rt>7&&(F(n,v,nt>>23&31),v+=e[rt]);var it=31&nt;E(n,v,J[it]),v+=K[it],it>3&&(E(n,v,nt>>5&8191),v+=o[it])}else E(n,v,V[nt]),v+=Y[nt]}return E(n,v,V[256]),v+Y[256]},H=new i([65540,131080,131088,131104,262176,1048704,1048832,2114560,2117632]),j=new n(0),N=function(t,s,a,u,h,c){var l=c.z||t.length,v=new n(u+l+5*(1+Math.ceil(l/7e3))+h),d=v.subarray(u,v.length-h),g=c.l,y=7&(c.r||0);if(s){y&&(d[0]=c.r>>3);for(var m=H[s-1],b=m>>13,w=8191&m,x=(1<7e3||q>24576)&&(V>423||!g)){y=B(t,d,0,C,I,U,E,q,G,Z-G,y),q=F=E=0,G=Z;for(var Y=0;Y<286;++Y)I[Y]=0;for(Y=0;Y<30;++Y)U[Y]=0}var J=2,K=0,Q=w,R=N-P&32767;if(V>2&&j==A(Z-R))for(var W=Math.min(b,V)-1,X=Math.min(32767,Z),$=Math.min(258,V);R<=X&&--Q&&N!=P;){if(t[Z+J]==t[Z+J-R]){for(var _=0;_<$&&t[Z+_]==t[Z+_-R];++_);if(_>J){if(J=_,K=R,_>W)break;var tt=Math.min(R,_-2),nt=0;for(Y=0;Ynt&&(nt=it,P=rt)}}}R+=(N=P)-(P=z[N])&32767}if(K){C[q++]=268435456|f[J]<<18|p[K];var et=31&f[J],ot=31&p[K];E+=e[et]+o[ot],++I[257+et],++U[ot],O=Z+J,++F}else C[q++]=t[Z],++I[t[Z]]}}for(Z=Math.max(Z,O);Z=l&&(d[y/8|0]=g,st=l),y=L(d,y+1,t.subarray(Z,st))}c.i=l}return D(v,0,u+T(y)+h)},P=function(){for(var t=new Int32Array(256),n=0;n<256;++n){for(var r=n,i=9;--i;)r=(1&r&&-306674912)^r>>>1;t[n]=r}return t}(),V=function(){var t=-1;return{p:function(n){for(var r=t,i=0;i>>8;t=r},d:function(){return~t}}},Y=function(){var t=1,n=0;return{p:function(r){for(var i=t,e=n,o=0|r.length,s=0;s!=o;){for(var a=Math.min(s+2655,o);s>16),e=(65535&e)+15*(e>>16)}t=i,n=e},d:function(){return(255&(t%=65521))<<24|(65280&t)<<8|(255&(n%=65521))<<8|n>>8}}},J=function(t,r,i,e,o){if(!o&&(o={l:1},r.dictionary)){var s=r.dictionary.subarray(-32768),a=new n(s.length+t.length);a.set(s),a.set(t,s.length),t=a,o.w=s.length}return N(t,null==r.level?6:r.level,null==r.mem?o.l?Math.ceil(1.5*Math.max(8,Math.min(13,Math.log(t.length)))):20:12+r.mem,i,e,o)},K=function(t,n){var r={};for(var i in t)r[i]=t[i];for(var i in n)r[i]=n[i];return r},Q=function(t,n,r){for(var i=t(),e=""+t,o=e.slice(e.indexOf("[")+1,e.lastIndexOf("]")).replace(/\s+/g,"").split(","),s=0;s>>0},ct=function(t,n){return ft(t,n)+4294967296*ft(t,n+4)},lt=function(t,n,r){for(;r;++n)t[n]=r,r>>>=8},pt=function(t,n){var r=n.filename;if(t[0]=31,t[1]=139,t[2]=8,t[8]=n.level<2?4:9==n.level?2:0,t[9]=3,0!=n.mtime&<(t,4,Math.floor(new Date(n.mtime||Date.now())/1e3)),r){t[3]=8;for(var i=0;i<=r.length;++i)t[i+10]=r.charCodeAt(i)}},vt=function(t){31==t[0]&&139==t[1]&&8==t[2]||I(6,"invalid gzip data");var n=t[3],r=10;4&n&&(r+=2+(t[10]|t[11]<<8));for(var i=(n>>3&1)+(n>>4&1);i>0;i-=!t[r++]);return r+(2&n)},dt=function(t){var n=t.length;return(t[n-4]|t[n-3]<<8|t[n-2]<<16|t[n-1]<<24)>>>0},gt=function(t){return 10+(t.filename?t.filename.length+1:0)},yt=function(t,n){var r=n.level,i=0==r?0:r<6?1:9==r?3:2;if(t[0]=120,t[1]=i<<6|(n.dictionary&&32),t[1]|=31-(t[0]<<8|t[1])%31,n.dictionary){var e=Y();e.p(n.dictionary),lt(t,2,e.d())}},mt=function(t,n){return(8!=(15&t[0])||t[0]>>4>7||(t[0]<<8|t[1])%31)&&I(6,"invalid zlib data"),(t[1]>>5&1)==+!n&&I(6,"invalid zlib data: "+(32&t[1]?"need":"unexpected")+" dictionary"),2+(t[1]>>3&4)};function bt(t,n){return"function"==typeof t&&(n=t,t={}),this.ondata=n,t}var wt=function(){function t(t,r){if("function"==typeof t&&(r=t,t={}),this.ondata=r,this.o=t||{},this.s={l:0,i:32768,w:32768,z:32768},this.b=new n(98304),this.o.dictionary){var i=this.o.dictionary.subarray(-32768);this.b.set(i,32768-i.length),this.s.i=32768-i.length}}return t.prototype.p=function(t,n){this.ondata(J(t,this.o,0,0,this.s),n)},t.prototype.push=function(t,r){this.ondata||I(5),this.s.l&&I(4);var i=t.length+this.s.z;if(i>this.b.length){if(i>2*this.b.length-32768){var e=new n(-32768&i);e.set(this.b.subarray(0,this.s.z)),this.b=e}var o=this.b.length-this.s.z;this.b.set(t.subarray(0,o),this.s.z),this.s.z=this.b.length,this.p(this.b,!1),this.b.set(this.b.subarray(-32768)),this.b.set(t.subarray(o),32768),this.s.z=t.length-o+32768,this.s.i=32766,this.s.w=32768}else this.b.set(t,this.s.z),this.s.z+=t.length;this.s.l=1&r,(this.s.z>this.s.w+8191||r)&&(this.p(this.b,r||!1),this.s.w=this.s.i,this.s.i-=2),r&&(this.s=this.o={},this.b=j)},t.prototype.flush=function(t){if(this.ondata||I(5),this.s.l&&I(4),this.p(this.b,!1),this.s.w=this.s.i,this.s.i-=2,t){var r=new n(6);r[0]=this.s.r>>3;var i=L(r,this.s.r,j);this.s.r=0,this.ondata(r.subarray(0,i>>3),!1)}},t}();_e.Deflate=wt;var xt=function(){return function(t,n){ut([_,function(){return[at,wt]}],this,bt.call(this,t,n),function(t){var n=new wt(t.data);onmessage=at(n)},6,1)}}();function zt(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[_],function(t){return et(kt(t.data[0],t.data[1]))},0,r)}function kt(t,n){return J(t,n||{},0,0)}_e.AsyncDeflate=xt;var Mt=function(){function t(t,r){"function"==typeof t&&(r=t,t={}),this.ondata=r;var i=t&&t.dictionary&&t.dictionary.subarray(-32768);this.s={i:0,b:i?i.length:0},this.o=new n(32768),this.p=new n(0),i&&this.o.set(i)}return t.prototype.e=function(t){if(this.ondata||I(5),this.d&&I(4),this.p.length){if(t.length){var r=new n(this.p.length+t.length);r.set(this.p),r.set(t,this.p.length),this.p=r}}else this.p=t},t.prototype.c=function(t){this.s.i=+(this.d=t||!1);var n=this.s.b,r=U(this.p,this.s,this.o);this.ondata(D(r,n,this.s.b),this.d),this.o=D(r,this.s.b-32768),this.s.b=this.o.length,this.p=D(this.p,this.s.p/8|0),this.s.p&=7},t.prototype.push=function(t,n){this.e(t),this.c(n)},t}();_e.Inflate=Mt;var St=function(){return function(t,n){ut([$,function(){return[at,Mt]}],this,bt.call(this,t,n),function(t){var n=new Mt(t.data);onmessage=at(n)},7,0)}}();function At(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[$],function(t){return et(Tt(t.data[0],ot(t.data[1])))},1,r)}function Tt(t,n){return U(t,{i:2},n&&n.out,n&&n.dictionary)}_e.AsyncInflate=St;var Dt=function(){function t(t,n){this.c=V(),this.l=0,this.v=1,wt.call(this,t,n)}return t.prototype.push=function(t,n){this.c.p(t),this.l+=t.length,wt.prototype.push.call(this,t,n)},t.prototype.p=function(t,n){var r=J(t,this.o,this.v&>(this.o),n&&8,this.s);this.v&&(pt(r,this.o),this.v=0),n&&(lt(r,r.length-8,this.c.d()),lt(r,r.length-4,this.l)),this.ondata(r,n)},t.prototype.flush=function(t){wt.prototype.flush.call(this,t)},t}();_e.Gzip=Dt,_e.Compress=Dt;var Ct=function(){return function(t,n){ut([_,tt,function(){return[at,wt,Dt]}],this,bt.call(this,t,n),function(t){var n=new Dt(t.data);onmessage=at(n)},8,1)}}();function It(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[_,tt,function(){return[Ut]}],function(t){return et(Ut(t.data[0],t.data[1]))},2,r)}function Ut(t,n){n||(n={});var r=V(),i=t.length;r.p(t);var e=J(t,n,gt(n),8),o=e.length;return pt(e,n),lt(e,o-8,r.d()),lt(e,o-4,i),e}_e.AsyncGzip=Ct,_e.AsyncCompress=Ct;var Ft=function(){function t(t,n){this.v=1,this.r=0,Mt.call(this,t,n)}return t.prototype.push=function(t,r){if(Mt.prototype.e.call(this,t),this.r+=t.length,this.v){var i=this.p.subarray(this.v-1),e=i.length>3?vt(i):4;if(e>i.length){if(!r)return}else this.v>1&&this.onmember&&this.onmember(this.r-i.length);this.p=i.subarray(e),this.v=0}Mt.prototype.c.call(this,0),this.s.f&&!this.s.l?(this.v=T(this.s.p)+9,this.s={i:0},this.o=new n(0),this.push(new n(0),r)):r&&Mt.prototype.c.call(this,r)},t}();_e.Gunzip=Ft;var Et=function(){return function(t,n){var r=this;ut([$,nt,function(){return[at,Mt,Ft]}],this,bt.call(this,t,n),function(t){var n=new Ft(t.data);n.onmember=function(t){return postMessage(t)},onmessage=at(n)},9,0,function(t){return r.onmember&&r.onmember(t)})}}();function Zt(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[$,nt,function(){return[qt]}],function(t){return et(qt(t.data[0],t.data[1]))},3,r)}function qt(t,r){var i=vt(t);return i+8>t.length&&I(6,"invalid gzip data"),U(t.subarray(i,-8),{i:2},r&&r.out||new n(dt(t)),r&&r.dictionary)}_e.AsyncGunzip=Et;var Ot=function(){function t(t,n){this.c=Y(),this.v=1,wt.call(this,t,n)}return t.prototype.push=function(t,n){this.c.p(t),wt.prototype.push.call(this,t,n)},t.prototype.p=function(t,n){var r=J(t,this.o,this.v&&(this.o.dictionary?6:2),n&&4,this.s);this.v&&(yt(r,this.o),this.v=0),n&<(r,r.length-4,this.c.d()),this.ondata(r,n)},t.prototype.flush=function(t){wt.prototype.flush.call(this,t)},t}();_e.Zlib=Ot;var Gt=function(){return function(t,n){ut([_,rt,function(){return[at,wt,Ot]}],this,bt.call(this,t,n),function(t){var n=new Ot(t.data);onmessage=at(n)},10,1)}}();function Lt(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[_,rt,function(){return[Bt]}],function(t){return et(Bt(t.data[0],t.data[1]))},4,r)}function Bt(t,n){n||(n={});var r=Y();r.p(t);var i=J(t,n,n.dictionary?6:2,4);return yt(i,n),lt(i,i.length-4,r.d()),i}_e.AsyncZlib=Gt;var Ht=function(){function t(t,n){Mt.call(this,t,n),this.v=t&&t.dictionary?2:1}return t.prototype.push=function(t,n){if(Mt.prototype.e.call(this,t),this.v){if(this.p.length<6&&!n)return;this.p=this.p.subarray(mt(this.p,this.v-1)),this.v=0}n&&(this.p.length<4&&I(6,"invalid zlib data"),this.p=this.p.subarray(0,-4)),Mt.prototype.c.call(this,n)},t}();_e.Unzlib=Ht;var jt=function(){return function(t,n){ut([$,it,function(){return[at,Mt,Ht]}],this,bt.call(this,t,n),function(t){var n=new Ht(t.data);onmessage=at(n)},11,0)}}();function Nt(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[$,it,function(){return[Pt]}],function(t){return et(Pt(t.data[0],ot(t.data[1])))},5,r)}function Pt(t,n){return U(t.subarray(mt(t,n&&n.dictionary),-4),{i:2},n&&n.out,n&&n.dictionary)}_e.AsyncUnzlib=jt;var Vt=function(){function t(t,n){this.o=bt.call(this,t,n)||{},this.G=Ft,this.I=Mt,this.Z=Ht}return t.prototype.i=function(){var t=this;this.s.ondata=function(n,r){t.ondata(n,r)}},t.prototype.push=function(t,r){if(this.ondata||I(5),this.s)this.s.push(t,r);else{if(this.p&&this.p.length){var i=new n(this.p.length+t.length);i.set(this.p),i.set(t,this.p.length)}else this.p=t;this.p.length>2&&(this.s=31==this.p[0]&&139==this.p[1]&&8==this.p[2]?new this.G(this.o):8!=(15&this.p[0])||this.p[0]>>4>7||(this.p[0]<<8|this.p[1])%31?new this.I(this.o):new this.Z(this.o),this.i(),this.s.push(this.p,r),this.p=null)}},t}();_e.Decompress=Vt;var Yt=function(){function t(t,n){Vt.call(this,t,n),this.queuedSize=0,this.G=Et,this.I=St,this.Z=jt}return t.prototype.i=function(){var t=this;this.s.ondata=function(n,r,i){t.ondata(n,r,i)},this.s.ondrain=function(n){t.queuedSize-=n,t.ondrain&&t.ondrain(n)}},t.prototype.push=function(t,n){this.queuedSize+=t.length,Vt.prototype.push.call(this,t,n)},t}();function Jt(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),31==t[0]&&139==t[1]&&8==t[2]?Zt(t,n,r):8!=(15&t[0])||t[0]>>4>7||(t[0]<<8|t[1])%31?At(t,n,r):Nt(t,n,r)}function Kt(t,n){return 31==t[0]&&139==t[1]&&8==t[2]?qt(t,n):8!=(15&t[0])||t[0]>>4>7||(t[0]<<8|t[1])%31?Tt(t,n):Pt(t,n)}_e.AsyncDecompress=Yt;var Qt=function(t,r,i,e){for(var o in t){var s=t[o],a=r+o,u=e;Array.isArray(s)&&(u=K(e,s[1]),s=s[0]),ArrayBuffer.isView(s)?i[a]=[s,u]:(i[a+="/"]=[new n(0),u],Qt(s,a,i,e))}},Rt="undefined"!=typeof TextEncoder&&new TextEncoder,Wt="undefined"!=typeof TextDecoder&&new TextDecoder,Xt=0;try{Wt.decode(j,{stream:!0}),Xt=1}catch(t){}var $t=function(t){for(var n="",r=0;;){var i=t[r++],e=(i>127)+(i>223)+(i>239);if(r+e>t.length)return{s:n,r:D(t,r-1)};e?3==e?(i=((15&i)<<18|(63&t[r++])<<12|(63&t[r++])<<6|63&t[r++])-65536,n+=String.fromCharCode(55296|i>>10,56320|1023&i)):n+=String.fromCharCode(1&e?(31&i)<<6|63&t[r++]:(15&i)<<12|(63&t[r++])<<6|63&t[r++]):n+=String.fromCharCode(i)}},_t=function(){function t(t){this.ondata=t,Xt?this.t=new TextDecoder:this.p=j}return t.prototype.push=function(t,r){if(this.ondata||I(5),r=!!r,this.t)return this.ondata(this.t.decode(t,{stream:!0}),r),void(r&&(this.t.decode().length&&I(8),this.t=null));this.p||I(4);var i=new n(this.p.length+t.length);i.set(this.p),i.set(t,this.p.length);var e=$t(i),o=e.s,s=e.r;r?(s.length&&I(8),this.p=null):this.p=s,this.ondata(o,r)},t}();_e.DecodeUTF8=_t;var tn=function(){function t(t){this.ondata=t}return t.prototype.push=function(t,n){this.ondata||I(5),this.d&&I(4),this.ondata(nn(t),this.d=n||!1)},t}();function nn(t,r){if(r){for(var i=new n(t.length),e=0;e>1)),a=0,u=function(t){s[a++]=t};for(e=0;es.length){var h=new n(a+8+(o-e<<1));h.set(s),s=h}var f=t.charCodeAt(e);f<128||r?u(f):f<2048?(u(192|f>>6),u(128|63&f)):f>55295&&f<57344?(u(240|(f=65536+(1047552&f)|1023&t.charCodeAt(++e))>>18),u(128|f>>12&63),u(128|f>>6&63),u(128|63&f)):(u(224|f>>12),u(128|f>>6&63),u(128|63&f))}return D(s,0,a)}function rn(t,n){if(n){for(var r="",i=0;i65535&&I(9),n+=i+4}return n},hn=function(t,n,r,i,e,o,s,a){var u=i.length,h=r.extra,f=a&&a.length,c=un(h);lt(t,n,null!=s?33639248:67324752),n+=4,null!=s&&(t[n++]=20,t[n++]=r.os),t[n]=20,n+=2,t[n++]=r.flag<<1|(o<0&&8),t[n++]=e&&8,t[n++]=255&r.compression,t[n++]=r.compression>>8;var l=new Date(null==r.mtime?Date.now():r.mtime),p=l.getFullYear()-1980;if((p<0||p>119)&&I(10),lt(t,n,p<<25|l.getMonth()+1<<21|l.getDate()<<16|l.getHours()<<11|l.getMinutes()<<5|l.getSeconds()>>1),n+=4,-1!=o&&(lt(t,n,r.crc),lt(t,n+4,o<0?-o-2:o),lt(t,n+8,r.size)),lt(t,n+12,u),lt(t,n+14,c),n+=16,null!=s&&(lt(t,n,f),lt(t,n+6,r.attrs),lt(t,n+10,s),n+=14),t.set(i,n),n+=u,c)for(var v in h){var d=h[v],g=d.length;lt(t,n,+v),lt(t,n+2,g),t.set(d,n+4),n+=4+g}return f&&(t.set(a,n),n+=f),n},fn=function(t,n,r,i,e){lt(t,n,101010256),lt(t,n+8,r),lt(t,n+10,r),lt(t,n+12,i),lt(t,n+16,e)},cn=function(){function t(t){this.filename=t,this.c=V(),this.size=0,this.compression=0}return t.prototype.process=function(t,n){this.ondata(null,t,n)},t.prototype.push=function(t,n){this.ondata||I(5),this.c.p(t),this.size+=t.length,n&&(this.crc=this.c.d()),this.process(t,n||!1)},t}();_e.ZipPassThrough=cn;var ln=function(){function t(t,n){var r=this;n||(n={}),cn.call(this,t),this.d=new wt(n,function(t,n){r.ondata(null,t,n)}),this.compression=8,this.flag=en(n.level)}return t.prototype.process=function(t,n){try{this.d.push(t,n)}catch(t){this.ondata(t,null,n)}},t.prototype.push=function(t,n){cn.prototype.push.call(this,t,n)},t}();_e.ZipDeflate=ln;var pn=function(){function t(t,n){var r=this;n||(n={}),cn.call(this,t),this.d=new xt(n,function(t,n,i){r.ondata(t,n,i)}),this.compression=8,this.flag=en(n.level),this.terminate=this.d.terminate}return t.prototype.process=function(t,n){this.d.push(t,n)},t.prototype.push=function(t,n){cn.prototype.push.call(this,t,n)},t}();_e.AsyncZipDeflate=pn;var vn=function(){function t(t){this.ondata=t,this.u=[],this.d=1}return t.prototype.add=function(t){var r=this;if(this.ondata||I(5),2&this.d)this.ondata(I(4+8*(1&this.d),0,1),null,!1);else{var i=nn(t.filename),e=i.length,o=t.comment,s=o&&nn(o),a=e!=t.filename.length||s&&o.length!=s.length,u=e+un(t.extra)+30;e>65535&&this.ondata(I(11,0,1),null,!1);var h=new n(u);hn(h,0,t,i,a,-1);var f=[h],c=function(){for(var t=0,n=f;t65535&&M(I(11,0,1),null),k)if(g<16e4)try{M(null,kt(i,h))}catch(t){M(t,null)}else c.push(zt(i,h,M));else M(null,i)},g=0;g65535&&I(11);var y=c?kt(h,f):h,m=y.length,b=V();b.p(h),e.push(K(f,{size:h.length,crc:b.d(),c:y,f:M,m:v,u:l!=a.length||v&&p.length!=d,o:o,compression:c})),o+=30+l+g+m,s+=76+2*(l+g)+(d||0)+m}for(var w=new n(s+22),x=o,z=s-o,k=0;k0){var e=Math.min(this.c,t.length),o=t.subarray(0,e);if(this.c-=e,this.d?this.d.push(o,!this.c):this.k[0].push(o),(t=t.subarray(e)).length)return this.push(t,r)}else{var s=0,a=0,u=void 0,h=void 0;this.p.length?t.length?((h=new n(this.p.length+t.length)).set(this.p),h.set(t,this.p.length)):h=this.p:h=t;for(var f=h.length,c=this.c,l=c&&this.d,p=function(){var t=ft(h,a);if(67324752==t){s=1,u=a,v.d=null,v.c=0;var n=ht(h,a+6),r=ht(h,a+8),e=2048&n,o=8&n,l=ht(h,a+26),p=ht(h,a+28);if(f>a+30+l+p){var d=[];v.k.unshift(d),s=2;var g,y=ft(h,a+18),m=ft(h,a+22),b=rn(h.subarray(a+30,a+=30+l),!e),w=an(h,a,p,2,y,m,0),x=w[0],z=w[1];o&&(x=-1-w[3]),a+=p,v.c=x;var k={name:b,compression:r,start:function(){if(k.ondata||I(5),x){var t=i.o[r];t||k.ondata(I(14,"unknown compression type "+r,1),null,!1),(g=x<0?new t(b):new t(b,x,z)).ondata=function(t,n,r){k.ondata(t,n,r)};for(var n=0,e=d;n=0&&(k.size=x,k.originalSize=z),v.onfile(k)}return"break"}if(c){if(134695760==t)return u=a+=12+(-2==c&&8),s=3,v.c=0,"break";if(33639248==t)return u=a-=4,s=3,v.c=0,"break"}},v=this;a65558)return a(I(13,0,1),null),o;var h=ht(t,u+8);if(h){var f=h,c=ft(t,u+16),l=117853008==ft(t,u-20);if(l){var p=ft(t,u-12);(l=101075792==ft(t,p))&&(f=h=ft(t,p+32),c=ft(t,p+48))}for(var v=r&&r.filter,d=function(r){var i=sn(t,c,l),u=i[0],f=i[1],p=i[2],d=i[3],g=i[4],y=on(t,i[5]);c=g;var m=function(t,n){t?(o(),a(t,null)):(n&&(s[d]=n),--h||a(null,s))};if(!v||v({name:d,size:f,originalSize:p,compression:u}))if(u)if(8==u){var b=t.subarray(y,y+f);if(p<524288||f>.8*p)try{m(null,Tt(b,{out:new n(p)}))}catch(t){m(t,null)}else e.push(At(b,{size:p},m))}else m(I(14,"unknown compression type "+u,1),null);else m(null,D(t,y,y+f));else m(null,null)},g=0;g65558)&&I(13);var o=ht(t,e+8);if(!o)return{};var s=ft(t,e+16),a=117853008==ft(t,e-20);if(a){var u=ft(t,e-12);(a=101075792==ft(t,u))&&(o=ft(t,u+32),s=ft(t,u+48))}for(var h=r&&r.filter,f=0;f "style" map. Each tag may have own set of styles. +- `schema` _(default: `DEFAULT_SCHEMA`)_ specifies a schema to use. +- `sortKeys` _(default: `false`)_ - if `true`, sort keys when dumping YAML. If a + function, use the function to sort the keys. +- `lineWidth` _(default: `80`)_ - set max line width. Set `-1` for unlimited width. +- `noRefs` _(default: `false`)_ - if `true`, don't convert duplicate objects into references +- `noCompatMode` _(default: `false`)_ - if `true` don't try to be compatible with older + yaml versions. Currently: don't quote "yes", "no" and so on, as required for YAML 1.1 +- `condenseFlow` _(default: `false`)_ - if `true` flow sequences will be condensed, omitting the space between `a, b`. Eg. `'[a,b]'`, and omitting the space between `key: value` and quoting the key. Eg. `'{"a":b}'` Can be useful when using yaml for pretty URL query params as spaces are %-encoded. +- `quotingType` _(`'` or `"`, default: `'`)_ - strings will be quoted using this quoting style. If you specify single quotes, double quotes will still be used for non-printable characters. +- `forceQuotes` _(default: `false`)_ - if `true`, all non-key strings will be quoted even if they normally don't need to. +- `replacer` - callback `function (key, value)` called recursively on each key/value in source object (see `replacer` docs for `JSON.stringify`). + +The following table show availlable styles (e.g. "canonical", +"binary"...) available for each tag (.e.g. !!null, !!int ...). Yaml +output is shown on the right side after `=>` (default setting) or `->`: + +``` none +!!null + "canonical" -> "~" + "lowercase" => "null" + "uppercase" -> "NULL" + "camelcase" -> "Null" + "empty" -> "" + +!!int + "binary" -> "0b1", "0b101010", "0b1110001111010" + "octal" -> "0o1", "0o52", "0o16172" + "decimal" => "1", "42", "7290" + "hexadecimal" -> "0x1", "0x2A", "0x1C7A" + +!!bool + "lowercase" => "true", "false" + "uppercase" -> "TRUE", "FALSE" + "camelcase" -> "True", "False" + +!!float + "lowercase" => ".nan", '.inf' + "uppercase" -> ".NAN", '.INF' + "camelcase" -> ".NaN", '.Inf' +``` + +Example: + +``` javascript +dump(object, { + 'styles': { + '!!null': 'canonical' // dump null as ~ + }, + 'sortKeys': true // sort object keys +}); +``` + +Supported YAML types +-------------------- + +The list of standard YAML tags and corresponding JavaScript types. See also +[YAML tag discussion](https://pyyaml.org/wiki/YAMLTagDiscussion) and +[YAML types repository](https://yaml.org/type/). + +``` +!!null '' # null +!!bool 'yes' # bool +!!int '3...' # number +!!float '3.14...' # number +!!binary '...base64...' # buffer +!!timestamp 'YYYY-...' # date +!!omap [ ... ] # array of key-value pairs +!!pairs [ ... ] # array or array pairs +!!set { ... } # array of objects with given keys and null values +!!str '...' # string +!!seq [ ... ] # array +!!map { ... } # object +``` + +**JavaScript-specific tags** + +See [js-yaml-js-types](https://github.com/nodeca/js-yaml-js-types) for +extra types. + + +Caveats +------- + +Note, that you use arrays or objects as key in JS-YAML. JS does not allow objects +or arrays as keys, and stringifies (by calling `toString()` method) them at the +moment of adding them. + +``` yaml +--- +? [ foo, bar ] +: - baz +? { foo: bar } +: - baz + - baz +``` + +``` javascript +{ "foo,bar": ["baz"], "[object Object]": ["baz", "baz"] } +``` diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js new file mode 100755 index 0000000..abcd7e0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js @@ -0,0 +1,117 @@ +#!/usr/bin/env node + +'use strict' + +const fs = require('fs') +const argparse = require('argparse') +const yaml = require('..') + +/// ///////////////////////////////////////////////////////////////////////////// + +const cli = new argparse.ArgumentParser({ + prog: 'js-yaml', + add_help: true +}) + +cli.add_argument('-v', '--version', { + action: 'version', + version: require('../package.json').version +}) + +cli.add_argument('-c', '--compact', { + help: 'Display errors in compact mode', + action: 'store_true' +}) + +// deprecated (not needed after we removed output colors) +// option suppressed, but not completely removed for compatibility +cli.add_argument('-j', '--to-json', { + help: argparse.SUPPRESS, + dest: 'json', + action: 'store_true' +}) + +cli.add_argument('-t', '--trace', { + help: 'Show stack trace on error', + action: 'store_true' +}) + +cli.add_argument('file', { + help: 'File to read, utf-8 encoded without BOM', + nargs: '?', + default: '-' +}) + +/// ///////////////////////////////////////////////////////////////////////////// + +const options = cli.parse_args() + +/// ///////////////////////////////////////////////////////////////////////////// + +function readFile (filename, encoding, callback) { + if (options.file === '-') { + // read from stdin + + const chunks = [] + + process.stdin.on('data', function (chunk) { + chunks.push(chunk) + }) + + process.stdin.on('end', function () { + return callback(null, Buffer.concat(chunks).toString(encoding)) + }) + } else { + fs.readFile(filename, encoding, callback) + } +} + +readFile(options.file, 'utf8', function (error, input) { + let output + let isYaml + + if (error) { + if (error.code === 'ENOENT') { + console.error('File not found: ' + options.file) + process.exit(2) + } + + console.error( + (options.trace && error.stack) || + error.message || + String(error)) + + process.exit(1) + } + + try { + output = JSON.parse(input) + isYaml = false + } catch (err) { + if (err instanceof SyntaxError) { + try { + output = [] + yaml.loadAll(input, function (doc) { output.push(doc) }, {}) + isYaml = true + + if (output.length === 0) output = null + else if (output.length === 1) output = output[0] + } catch (e) { + if (options.trace && err.stack) console.error(e.stack) + else console.error(e.toString(options.compact)) + + process.exit(1) + } + } else { + console.error( + (options.trace && err.stack) || + err.message || + String(err)) + + process.exit(1) + } + } + + if (isYaml) console.log(JSON.stringify(output, null, ' ')) + else console.log(yaml.dump(output)) +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.js new file mode 100644 index 0000000..ba95c68 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.js @@ -0,0 +1,3014 @@ +(function(global, factory) { + typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define([ "exports" ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, + factory(global.jsyaml = {})); +})(this, function(exports2) { + "use strict"; + function getDefaultExportFromCjs(x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x; + } + var jsYaml = {}; + var loader = {}; + var common = {}; + var hasRequiredCommon; + function requireCommon() { + if (hasRequiredCommon) return common; + hasRequiredCommon = 1; + function _typeof(o) { + "@babel/helpers - typeof"; + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) { + return typeof o2; + } : function(o2) { + return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2; + }, _typeof(o); + } + function isNothing(subject) { + return typeof subject === "undefined" || subject === null; + } + function isObject(subject) { + return _typeof(subject) === "object" && subject !== null; + } + function toArray(sequence) { + if (Array.isArray(sequence)) return sequence; else if (isNothing(sequence)) return []; + return [ sequence ]; + } + function extend(target, source) { + if (source) { + var sourceKeys = Object.keys(source); + for (var index = 0, length = sourceKeys.length; index < length; index += 1) { + var key = sourceKeys[index]; + target[key] = source[key]; + } + } + return target; + } + function repeat(string, count) { + var result = ""; + for (var cycle = 0; cycle < count; cycle += 1) { + result += string; + } + return result; + } + function isNegativeZero(number) { + return number === 0 && Number.NEGATIVE_INFINITY === 1 / number; + } + common.isNothing = isNothing; + common.isObject = isObject; + common.toArray = toArray; + common.repeat = repeat; + common.isNegativeZero = isNegativeZero; + common.extend = extend; + return common; + } + var exception; + var hasRequiredException; + function requireException() { + if (hasRequiredException) return exception; + hasRequiredException = 1; + function formatError(exception2, compact) { + var where = ""; + var message = exception2.reason || "(unknown reason)"; + if (!exception2.mark) return message; + if (exception2.mark.name) { + where += 'in "' + exception2.mark.name + '" '; + } + where += "(" + (exception2.mark.line + 1) + ":" + (exception2.mark.column + 1) + ")"; + if (!compact && exception2.mark.snippet) { + where += "\n\n" + exception2.mark.snippet; + } + return message + " " + where; + } + function YAMLException2(reason, mark) { + Error.call(this); + this.name = "YAMLException"; + this.reason = reason; + this.mark = mark; + this.message = formatError(this, false); + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } else { + this.stack = (new Error).stack || ""; + } + } + YAMLException2.prototype = Object.create(Error.prototype); + YAMLException2.prototype.constructor = YAMLException2; + YAMLException2.prototype.toString = function toString(compact) { + return this.name + ": " + formatError(this, compact); + }; + exception = YAMLException2; + return exception; + } + var snippet; + var hasRequiredSnippet; + function requireSnippet() { + if (hasRequiredSnippet) return snippet; + hasRequiredSnippet = 1; + var common2 = requireCommon(); + function getLine(buffer, lineStart, lineEnd, position, maxLineLength) { + var head = ""; + var tail = ""; + var maxHalfLength = Math.floor(maxLineLength / 2) - 1; + if (position - lineStart > maxHalfLength) { + head = " ... "; + lineStart = position - maxHalfLength + head.length; + } + if (lineEnd - position > maxHalfLength) { + tail = " ..."; + lineEnd = position + maxHalfLength - tail.length; + } + return { + str: head + buffer.slice(lineStart, lineEnd).replace(/\t/g, "→") + tail, + pos: position - lineStart + head.length + }; + } + function padStart(string, max) { + return common2.repeat(" ", max - string.length) + string; + } + function makeSnippet(mark, options) { + options = Object.create(options || null); + if (!mark.buffer) return null; + if (!options.maxLength) options.maxLength = 79; + if (typeof options.indent !== "number") options.indent = 1; + if (typeof options.linesBefore !== "number") options.linesBefore = 3; + if (typeof options.linesAfter !== "number") options.linesAfter = 2; + var re = /\r?\n|\r|\0/g; + var lineStarts = [ 0 ]; + var lineEnds = []; + var match; + var foundLineNo = -1; + while (match = re.exec(mark.buffer)) { + lineEnds.push(match.index); + lineStarts.push(match.index + match[0].length); + if (mark.position <= match.index && foundLineNo < 0) { + foundLineNo = lineStarts.length - 2; + } + } + if (foundLineNo < 0) foundLineNo = lineStarts.length - 1; + var result = ""; + var lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length; + var maxLineLength = options.maxLength - (options.indent + lineNoLength + 3); + for (var i = 1; i <= options.linesBefore; i++) { + if (foundLineNo - i < 0) break; + var _line = getLine(mark.buffer, lineStarts[foundLineNo - i], lineEnds[foundLineNo - i], mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]), maxLineLength); + result = common2.repeat(" ", options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) + " | " + _line.str + "\n" + result; + } + var line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength); + result += common2.repeat(" ", options.indent) + padStart((mark.line + 1).toString(), lineNoLength) + " | " + line.str + "\n"; + result += common2.repeat("-", options.indent + lineNoLength + 3 + line.pos) + "^\n"; + for (var _i = 1; _i <= options.linesAfter; _i++) { + if (foundLineNo + _i >= lineEnds.length) break; + var _line2 = getLine(mark.buffer, lineStarts[foundLineNo + _i], lineEnds[foundLineNo + _i], mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + _i]), maxLineLength); + result += common2.repeat(" ", options.indent) + padStart((mark.line + _i + 1).toString(), lineNoLength) + " | " + _line2.str + "\n"; + } + return result.replace(/\n$/, ""); + } + snippet = makeSnippet; + return snippet; + } + var type; + var hasRequiredType; + function requireType() { + if (hasRequiredType) return type; + hasRequiredType = 1; + var YAMLException2 = requireException(); + var TYPE_CONSTRUCTOR_OPTIONS = [ "kind", "multi", "resolve", "construct", "instanceOf", "predicate", "represent", "representName", "defaultStyle", "styleAliases" ]; + var YAML_NODE_KINDS = [ "scalar", "sequence", "mapping" ]; + function compileStyleAliases(map2) { + var result = {}; + if (map2 !== null) { + Object.keys(map2).forEach(function(style) { + map2[style].forEach(function(alias) { + result[String(alias)] = style; + }); + }); + } + return result; + } + function Type2(tag, options) { + options = options || {}; + Object.keys(options).forEach(function(name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new YAMLException2('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + this.options = options; + this.tag = tag; + this.kind = options["kind"] || null; + this.resolve = options["resolve"] || function() { + return true; + }; + this.construct = options["construct"] || function(data) { + return data; + }; + this.instanceOf = options["instanceOf"] || null; + this.predicate = options["predicate"] || null; + this.represent = options["represent"] || null; + this.representName = options["representName"] || null; + this.defaultStyle = options["defaultStyle"] || null; + this.multi = options["multi"] || false; + this.styleAliases = compileStyleAliases(options["styleAliases"] || null); + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new YAMLException2('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } + } + type = Type2; + return type; + } + var schema; + var hasRequiredSchema; + function requireSchema() { + if (hasRequiredSchema) return schema; + hasRequiredSchema = 1; + var YAMLException2 = requireException(); + var Type2 = requireType(); + function compileList(schema2, name) { + var result = []; + schema2[name].forEach(function(currentType) { + var newIndex = result.length; + result.forEach(function(previousType, previousIndex) { + if (previousType.tag === currentType.tag && previousType.kind === currentType.kind && previousType.multi === currentType.multi) { + newIndex = previousIndex; + } + }); + result[newIndex] = currentType; + }); + return result; + } + function compileMap() { + var result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {}, + multi: { + scalar: [], + sequence: [], + mapping: [], + fallback: [] + } + }; + function collectType(type2) { + if (type2.multi) { + result.multi[type2.kind].push(type2); + result.multi["fallback"].push(type2); + } else { + result[type2.kind][type2.tag] = result["fallback"][type2.tag] = type2; + } + } + for (var index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType); + } + return result; + } + function Schema2(definition) { + return this.extend(definition); + } + Schema2.prototype.extend = function extend(definition) { + var implicit = []; + var explicit = []; + if (definition instanceof Type2) { + explicit.push(definition); + } else if (Array.isArray(definition)) { + explicit = explicit.concat(definition); + } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) { + if (definition.implicit) implicit = implicit.concat(definition.implicit); + if (definition.explicit) explicit = explicit.concat(definition.explicit); + } else { + throw new YAMLException2("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })"); + } + implicit.forEach(function(type2) { + if (!(type2 instanceof Type2)) { + throw new YAMLException2("Specified list of YAML types (or a single Type object) contains a non-Type object."); + } + if (type2.loadKind && type2.loadKind !== "scalar") { + throw new YAMLException2("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported."); + } + if (type2.multi) { + throw new YAMLException2("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit."); + } + }); + explicit.forEach(function(type2) { + if (!(type2 instanceof Type2)) { + throw new YAMLException2("Specified list of YAML types (or a single Type object) contains a non-Type object."); + } + }); + var result = Object.create(Schema2.prototype); + result.implicit = (this.implicit || []).concat(implicit); + result.explicit = (this.explicit || []).concat(explicit); + result.compiledImplicit = compileList(result, "implicit"); + result.compiledExplicit = compileList(result, "explicit"); + result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit); + return result; + }; + schema = Schema2; + return schema; + } + var str; + var hasRequiredStr; + function requireStr() { + if (hasRequiredStr) return str; + hasRequiredStr = 1; + var Type2 = requireType(); + str = new Type2("tag:yaml.org,2002:str", { + kind: "scalar", + construct: function construct(data) { + return data !== null ? data : ""; + } + }); + return str; + } + var seq; + var hasRequiredSeq; + function requireSeq() { + if (hasRequiredSeq) return seq; + hasRequiredSeq = 1; + var Type2 = requireType(); + seq = new Type2("tag:yaml.org,2002:seq", { + kind: "sequence", + construct: function construct(data) { + return data !== null ? data : []; + } + }); + return seq; + } + var map; + var hasRequiredMap; + function requireMap() { + if (hasRequiredMap) return map; + hasRequiredMap = 1; + var Type2 = requireType(); + map = new Type2("tag:yaml.org,2002:map", { + kind: "mapping", + construct: function construct(data) { + return data !== null ? data : {}; + } + }); + return map; + } + var failsafe; + var hasRequiredFailsafe; + function requireFailsafe() { + if (hasRequiredFailsafe) return failsafe; + hasRequiredFailsafe = 1; + var Schema2 = requireSchema(); + failsafe = new Schema2({ + explicit: [ requireStr(), requireSeq(), requireMap() ] + }); + return failsafe; + } + var _null; + var hasRequired_null; + function require_null() { + if (hasRequired_null) return _null; + hasRequired_null = 1; + var Type2 = requireType(); + function resolveYamlNull(data) { + if (data === null) return true; + var max = data.length; + return max === 1 && data === "~" || max === 4 && (data === "null" || data === "Null" || data === "NULL"); + } + function constructYamlNull() { + return null; + } + function isNull(object) { + return object === null; + } + _null = new Type2("tag:yaml.org,2002:null", { + kind: "scalar", + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function canonical() { + return "~"; + }, + lowercase: function lowercase() { + return "null"; + }, + uppercase: function uppercase() { + return "NULL"; + }, + camelcase: function camelcase() { + return "Null"; + }, + empty: function empty() { + return ""; + } + }, + defaultStyle: "lowercase" + }); + return _null; + } + var bool; + var hasRequiredBool; + function requireBool() { + if (hasRequiredBool) return bool; + hasRequiredBool = 1; + var Type2 = requireType(); + function resolveYamlBoolean(data) { + if (data === null) return false; + var max = data.length; + return max === 4 && (data === "true" || data === "True" || data === "TRUE") || max === 5 && (data === "false" || data === "False" || data === "FALSE"); + } + function constructYamlBoolean(data) { + return data === "true" || data === "True" || data === "TRUE"; + } + function isBoolean(object) { + return Object.prototype.toString.call(object) === "[object Boolean]"; + } + bool = new Type2("tag:yaml.org,2002:bool", { + kind: "scalar", + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function lowercase(object) { + return object ? "true" : "false"; + }, + uppercase: function uppercase(object) { + return object ? "TRUE" : "FALSE"; + }, + camelcase: function camelcase(object) { + return object ? "True" : "False"; + } + }, + defaultStyle: "lowercase" + }); + return bool; + } + var int; + var hasRequiredInt; + function requireInt() { + if (hasRequiredInt) return int; + hasRequiredInt = 1; + var common2 = requireCommon(); + var Type2 = requireType(); + function isHexCode(c) { + return c >= 48 && c <= 57 || c >= 65 && c <= 70 || c >= 97 && c <= 102; + } + function isOctCode(c) { + return c >= 48 && c <= 55; + } + function isDecCode(c) { + return c >= 48 && c <= 57; + } + function resolveYamlInteger(data) { + if (data === null) return false; + var max = data.length; + var index = 0; + var hasDigits = false; + if (!max) return false; + var ch = data[index]; + if (ch === "-" || ch === "+") { + ch = data[++index]; + } + if (ch === "0") { + if (index + 1 === max) return true; + ch = data[++index]; + if (ch === "b") { + index++; + for (;index < max; index++) { + ch = data[index]; + if (ch !== "0" && ch !== "1") return false; + hasDigits = true; + } + return hasDigits && isFinite(parseYamlInteger(data)); + } + if (ch === "x") { + index++; + for (;index < max; index++) { + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && isFinite(parseYamlInteger(data)); + } + if (ch === "o") { + index++; + for (;index < max; index++) { + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && isFinite(parseYamlInteger(data)); + } + } + for (;index < max; index++) { + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } + if (!hasDigits) return false; + return isFinite(parseYamlInteger(data)); + } + function parseYamlInteger(data) { + var value = data; + var sign = 1; + var ch = value[0]; + if (ch === "-" || ch === "+") { + if (ch === "-") sign = -1; + value = value.slice(1); + ch = value[0]; + } + if (value === "0") return 0; + if (ch === "0") { + if (value[1] === "b") return sign * parseInt(value.slice(2), 2); + if (value[1] === "x") return sign * parseInt(value.slice(2), 16); + if (value[1] === "o") return sign * parseInt(value.slice(2), 8); + } + return sign * parseInt(value, 10); + } + function constructYamlInteger(data) { + return parseYamlInteger(data); + } + function isInteger(object) { + return Object.prototype.toString.call(object) === "[object Number]" && object % 1 === 0 && !common2.isNegativeZero(object); + } + int = new Type2("tag:yaml.org,2002:int", { + kind: "scalar", + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function binary2(obj) { + return obj >= 0 ? "0b" + obj.toString(2) : "-0b" + obj.toString(2).slice(1); + }, + octal: function octal(obj) { + return obj >= 0 ? "0o" + obj.toString(8) : "-0o" + obj.toString(8).slice(1); + }, + decimal: function decimal(obj) { + return obj.toString(10); + }, + hexadecimal: function hexadecimal(obj) { + return obj >= 0 ? "0x" + obj.toString(16).toUpperCase() : "-0x" + obj.toString(16).toUpperCase().slice(1); + } + }, + defaultStyle: "decimal", + styleAliases: { + binary: [ 2, "bin" ], + octal: [ 8, "oct" ], + decimal: [ 10, "dec" ], + hexadecimal: [ 16, "hex" ] + } + }); + return int; + } + var float; + var hasRequiredFloat; + function requireFloat() { + if (hasRequiredFloat) return float; + hasRequiredFloat = 1; + var common2 = requireCommon(); + var Type2 = requireType(); + var YAML_FLOAT_PATTERN = new RegExp("^(?:[-+]?(?:[0-9]+)(?:\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"); + var YAML_FLOAT_SPECIAL_PATTERN = new RegExp("^(?:[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"); + function resolveYamlFloat(data) { + if (data === null) return false; + if (!YAML_FLOAT_PATTERN.test(data)) { + return false; + } + if (isFinite(parseFloat(data, 10))) { + return true; + } + return YAML_FLOAT_SPECIAL_PATTERN.test(data); + } + function constructYamlFloat(data) { + var value = data.toLowerCase(); + var sign = value[0] === "-" ? -1 : 1; + if ("+-".indexOf(value[0]) >= 0) { + value = value.slice(1); + } + if (value === ".inf") { + return sign === 1 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + } else if (value === ".nan") { + return NaN; + } + return sign * parseFloat(value, 10); + } + var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + function representYamlFloat(object, style) { + if (isNaN(object)) { + switch (style) { + case "lowercase": + return ".nan"; + + case "uppercase": + return ".NAN"; + + case "camelcase": + return ".NaN"; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case "lowercase": + return ".inf"; + + case "uppercase": + return ".INF"; + + case "camelcase": + return ".Inf"; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case "lowercase": + return "-.inf"; + + case "uppercase": + return "-.INF"; + + case "camelcase": + return "-.Inf"; + } + } else if (common2.isNegativeZero(object)) { + return "-0.0"; + } + var res = object.toString(10); + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace("e", ".e") : res; + } + function isFloat(object) { + return Object.prototype.toString.call(object) === "[object Number]" && (object % 1 !== 0 || common2.isNegativeZero(object)); + } + float = new Type2("tag:yaml.org,2002:float", { + kind: "scalar", + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: "lowercase" + }); + return float; + } + var json; + var hasRequiredJson; + function requireJson() { + if (hasRequiredJson) return json; + hasRequiredJson = 1; + json = requireFailsafe().extend({ + implicit: [ require_null(), requireBool(), requireInt(), requireFloat() ] + }); + return json; + } + var core; + var hasRequiredCore; + function requireCore() { + if (hasRequiredCore) return core; + hasRequiredCore = 1; + core = requireJson(); + return core; + } + var timestamp; + var hasRequiredTimestamp; + function requireTimestamp() { + if (hasRequiredTimestamp) return timestamp; + hasRequiredTimestamp = 1; + var Type2 = requireType(); + var YAML_DATE_REGEXP = new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"); + var YAML_TIMESTAMP_REGEXP = new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$"); + function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; + } + function constructYamlTimestamp(data) { + var fraction = 0; + var delta = null; + var match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + if (match === null) throw new Error("Date resolve error"); + var year = +match[1]; + var month = +match[2] - 1; + var day = +match[3]; + if (!match[4]) { + return new Date(Date.UTC(year, month, day)); + } + var hour = +match[4]; + var minute = +match[5]; + var second = +match[6]; + if (match[7]) { + fraction = match[7].slice(0, 3); + while (fraction.length < 3) { + fraction += "0"; + } + fraction = +fraction; + } + if (match[9]) { + var tzHour = +match[10]; + var tzMinute = +(match[11] || 0); + delta = (tzHour * 60 + tzMinute) * 6e4; + if (match[9] === "-") delta = -delta; + } + var date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + if (delta) date.setTime(date.getTime() - delta); + return date; + } + function representYamlTimestamp(object) { + return object.toISOString(); + } + timestamp = new Type2("tag:yaml.org,2002:timestamp", { + kind: "scalar", + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp + }); + return timestamp; + } + var merge; + var hasRequiredMerge; + function requireMerge() { + if (hasRequiredMerge) return merge; + hasRequiredMerge = 1; + var Type2 = requireType(); + function resolveYamlMerge(data) { + return data === "<<" || data === null; + } + merge = new Type2("tag:yaml.org,2002:merge", { + kind: "scalar", + resolve: resolveYamlMerge + }); + return merge; + } + var binary; + var hasRequiredBinary; + function requireBinary() { + if (hasRequiredBinary) return binary; + hasRequiredBinary = 1; + var Type2 = requireType(); + var BASE64_MAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r"; + function resolveYamlBinary(data) { + if (data === null) return false; + var bitlen = 0; + var max = data.length; + var map2 = BASE64_MAP; + for (var idx = 0; idx < max; idx++) { + var code = map2.indexOf(data.charAt(idx)); + if (code > 64) continue; + if (code < 0) return false; + bitlen += 6; + } + return bitlen % 8 === 0; + } + function constructYamlBinary(data) { + var input = data.replace(/[\r\n=]/g, ""); + var max = input.length; + var map2 = BASE64_MAP; + var bits = 0; + var result = []; + for (var idx = 0; idx < max; idx++) { + if (idx % 4 === 0 && idx) { + result.push(bits >> 16 & 255); + result.push(bits >> 8 & 255); + result.push(bits & 255); + } + bits = bits << 6 | map2.indexOf(input.charAt(idx)); + } + var tailbits = max % 4 * 6; + if (tailbits === 0) { + result.push(bits >> 16 & 255); + result.push(bits >> 8 & 255); + result.push(bits & 255); + } else if (tailbits === 18) { + result.push(bits >> 10 & 255); + result.push(bits >> 2 & 255); + } else if (tailbits === 12) { + result.push(bits >> 4 & 255); + } + return new Uint8Array(result); + } + function representYamlBinary(object) { + var result = ""; + var bits = 0; + var max = object.length; + var map2 = BASE64_MAP; + for (var idx = 0; idx < max; idx++) { + if (idx % 3 === 0 && idx) { + result += map2[bits >> 18 & 63]; + result += map2[bits >> 12 & 63]; + result += map2[bits >> 6 & 63]; + result += map2[bits & 63]; + } + bits = (bits << 8) + object[idx]; + } + var tail = max % 3; + if (tail === 0) { + result += map2[bits >> 18 & 63]; + result += map2[bits >> 12 & 63]; + result += map2[bits >> 6 & 63]; + result += map2[bits & 63]; + } else if (tail === 2) { + result += map2[bits >> 10 & 63]; + result += map2[bits >> 4 & 63]; + result += map2[bits << 2 & 63]; + result += map2[64]; + } else if (tail === 1) { + result += map2[bits >> 2 & 63]; + result += map2[bits << 4 & 63]; + result += map2[64]; + result += map2[64]; + } + return result; + } + function isBinary(obj) { + return Object.prototype.toString.call(obj) === "[object Uint8Array]"; + } + binary = new Type2("tag:yaml.org,2002:binary", { + kind: "scalar", + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary + }); + return binary; + } + var omap; + var hasRequiredOmap; + function requireOmap() { + if (hasRequiredOmap) return omap; + hasRequiredOmap = 1; + var Type2 = requireType(); + var _hasOwnProperty = Object.prototype.hasOwnProperty; + var _toString = Object.prototype.toString; + function resolveYamlOmap(data) { + if (data === null) return true; + var objectKeys = {}; + var object = data; + for (var index = 0, length = object.length; index < length; index += 1) { + var pair = object[index]; + var pairHasKey = false; + if (_toString.call(pair) !== "[object Object]") return false; + var pairKey = void 0; + for (pairKey in pair) { + if (_hasOwnProperty.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; else return false; + } + } + if (!pairHasKey) return false; + if (_hasOwnProperty.call(objectKeys, pairKey)) return false; + Object.defineProperty(objectKeys, pairKey, { + value: true + }); + } + return true; + } + function constructYamlOmap(data) { + return data !== null ? data : []; + } + omap = new Type2("tag:yaml.org,2002:omap", { + kind: "sequence", + resolve: resolveYamlOmap, + construct: constructYamlOmap + }); + return omap; + } + var pairs; + var hasRequiredPairs; + function requirePairs() { + if (hasRequiredPairs) return pairs; + hasRequiredPairs = 1; + var Type2 = requireType(); + var _toString = Object.prototype.toString; + function resolveYamlPairs(data) { + if (data === null) return true; + var object = data; + var result = new Array(object.length); + for (var index = 0, length = object.length; index < length; index += 1) { + var pair = object[index]; + if (_toString.call(pair) !== "[object Object]") return false; + var keys = Object.keys(pair); + if (keys.length !== 1) return false; + result[index] = [ keys[0], pair[keys[0]] ]; + } + return true; + } + function constructYamlPairs(data) { + if (data === null) return []; + var object = data; + var result = new Array(object.length); + for (var index = 0, length = object.length; index < length; index += 1) { + var pair = object[index]; + var keys = Object.keys(pair); + result[index] = [ keys[0], pair[keys[0]] ]; + } + return result; + } + pairs = new Type2("tag:yaml.org,2002:pairs", { + kind: "sequence", + resolve: resolveYamlPairs, + construct: constructYamlPairs + }); + return pairs; + } + var set; + var hasRequiredSet; + function requireSet() { + if (hasRequiredSet) return set; + hasRequiredSet = 1; + var Type2 = requireType(); + var _hasOwnProperty = Object.prototype.hasOwnProperty; + function resolveYamlSet(data) { + if (data === null) return true; + var object = data; + for (var key in object) { + if (_hasOwnProperty.call(object, key)) { + if (object[key] !== null) return false; + } + } + return true; + } + function constructYamlSet(data) { + return data !== null ? data : {}; + } + set = new Type2("tag:yaml.org,2002:set", { + kind: "mapping", + resolve: resolveYamlSet, + construct: constructYamlSet + }); + return set; + } + var _default; + var hasRequired_default; + function require_default() { + if (hasRequired_default) return _default; + hasRequired_default = 1; + _default = requireCore().extend({ + implicit: [ requireTimestamp(), requireMerge() ], + explicit: [ requireBinary(), requireOmap(), requirePairs(), requireSet() ] + }); + return _default; + } + var hasRequiredLoader; + function requireLoader() { + if (hasRequiredLoader) return loader; + hasRequiredLoader = 1; + function _typeof(o) { + "@babel/helpers - typeof"; + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) { + return typeof o2; + } : function(o2) { + return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2; + }, _typeof(o); + } + var common2 = requireCommon(); + var YAMLException2 = requireException(); + var makeSnippet = requireSnippet(); + var DEFAULT_SCHEMA2 = require_default(); + var _hasOwnProperty = Object.prototype.hasOwnProperty; + var CONTEXT_FLOW_IN = 1; + var CONTEXT_FLOW_OUT = 2; + var CONTEXT_BLOCK_IN = 3; + var CONTEXT_BLOCK_OUT = 4; + var CHOMPING_CLIP = 1; + var CHOMPING_STRIP = 2; + var CHOMPING_KEEP = 3; + var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; + var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; + var PATTERN_FLOW_INDICATORS = /[,\[\]{}]/; + var PATTERN_TAG_HANDLE = /^(?:!|!!|![0-9A-Za-z-]+!)$/; + var PATTERN_TAG_URI = /^(?:!|[^,\[\]{}])(?:%[0-9a-f]{2}|[0-9a-z\-#;/?:@&=+$,_.!~*'()\[\]])*$/i; + function _class(obj) { + return Object.prototype.toString.call(obj); + } + function isEol(c) { + return c === 10 || c === 13; + } + function isWhiteSpace(c) { + return c === 9 || c === 32; + } + function isWsOrEol(c) { + return c === 9 || c === 32 || c === 10 || c === 13; + } + function isFlowIndicator(c) { + return c === 44 || c === 91 || c === 93 || c === 123 || c === 125; + } + function fromHexCode(c) { + if (c >= 48 && c <= 57) { + return c - 48; + } + var lc = c | 32; + if (lc >= 97 && lc <= 102) { + return lc - 97 + 10; + } + return -1; + } + function escapedHexLen(c) { + if (c === 120) { + return 2; + } + if (c === 117) { + return 4; + } + if (c === 85) { + return 8; + } + return 0; + } + function fromDecimalCode(c) { + if (c >= 48 && c <= 57) { + return c - 48; + } + return -1; + } + function simpleEscapeSequence(c) { + switch (c) { + case 48: + return "\0"; + + case 97: + return ""; + + case 98: + return "\b"; + + case 116: + return "\t"; + + case 9: + return "\t"; + + case 110: + return "\n"; + + case 118: + return "\v"; + + case 102: + return "\f"; + + case 114: + return "\r"; + + case 101: + return ""; + + case 32: + return " "; + + case 34: + return '"'; + + case 47: + return "/"; + + case 92: + return "\\"; + + case 78: + return "…"; + + case 95: + return " "; + + case 76: + return "\u2028"; + + case 80: + return "\u2029"; + + default: + return ""; + } + } + function charFromCodepoint(c) { + if (c <= 65535) { + return String.fromCharCode(c); + } + return String.fromCharCode((c - 65536 >> 10) + 55296, (c - 65536 & 1023) + 56320); + } + function setProperty(object, key, value) { + if (key === "__proto__") { + Object.defineProperty(object, key, { + configurable: true, + enumerable: true, + writable: true, + value: value + }); + } else { + object[key] = value; + } + } + var simpleEscapeCheck = new Array(256); + var simpleEscapeMap = new Array(256); + for (var i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; + simpleEscapeMap[i] = simpleEscapeSequence(i); + } + function State(input, options) { + this.input = input; + this.filename = options["filename"] || null; + this.schema = options["schema"] || DEFAULT_SCHEMA2; + this.onWarning = options["onWarning"] || null; + this.legacy = options["legacy"] || false; + this.json = options["json"] || false; + this.listener = options["listener"] || null; + this.maxDepth = typeof options["maxDepth"] === "number" ? options["maxDepth"] : 100; + this.maxTotalMergeKeys = typeof options["maxTotalMergeKeys"] === "number" ? options["maxTotalMergeKeys"] : 1e4; + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + this.length = input.length; + this.position = 0; + this.line = 0; + this.lineStart = 0; + this.lineIndent = 0; + this.depth = 0; + this.totalMergeKeys = 0; + this.firstTabInLine = -1; + this.documents = []; + this.anchorMapTransactions = []; + } + function generateError(state, message) { + var mark = { + name: state.filename, + buffer: state.input.slice(0, -1), + position: state.position, + line: state.line, + column: state.position - state.lineStart + }; + mark.snippet = makeSnippet(mark); + return new YAMLException2(message, mark); + } + function throwError(state, message) { + throw generateError(state, message); + } + function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); + } + } + function storeAnchor(state, name, value) { + var transactions = state.anchorMapTransactions; + if (transactions.length !== 0) { + var transaction = transactions[transactions.length - 1]; + if (!_hasOwnProperty.call(transaction, name)) { + transaction[name] = { + existed: _hasOwnProperty.call(state.anchorMap, name), + value: state.anchorMap[name] + }; + } + } + state.anchorMap[name] = value; + } + function beginAnchorTransaction(state) { + state.anchorMapTransactions.push(Object.create(null)); + } + function commitAnchorTransaction(state) { + var transaction = state.anchorMapTransactions.pop(); + var transactions = state.anchorMapTransactions; + if (transactions.length === 0) return; + var parent = transactions[transactions.length - 1]; + var names = Object.keys(transaction); + for (var index = 0, length = names.length; index < length; index += 1) { + var name = names[index]; + if (!_hasOwnProperty.call(parent, name)) { + parent[name] = transaction[name]; + } + } + } + function rollbackAnchorTransaction(state) { + var transaction = state.anchorMapTransactions.pop(); + var names = Object.keys(transaction); + for (var index = names.length - 1; index >= 0; index -= 1) { + var entry = transaction[names[index]]; + if (entry.existed) { + state.anchorMap[names[index]] = entry.value; + } else { + delete state.anchorMap[names[index]]; + } + } + } + function snapshotState(state) { + return { + position: state.position, + line: state.line, + lineStart: state.lineStart, + lineIndent: state.lineIndent, + firstTabInLine: state.firstTabInLine, + tag: state.tag, + anchor: state.anchor, + kind: state.kind, + result: state.result + }; + } + function restoreState(state, snapshot) { + state.position = snapshot.position; + state.line = snapshot.line; + state.lineStart = snapshot.lineStart; + state.lineIndent = snapshot.lineIndent; + state.firstTabInLine = snapshot.firstTabInLine; + state.tag = snapshot.tag; + state.anchor = snapshot.anchor; + state.kind = snapshot.kind; + state.result = snapshot.result; + } + var directiveHandlers = { + YAML: function handleYamlDirective(state, name, args) { + if (state.version !== null) { + throwError(state, "duplication of %YAML directive"); + } + if (args.length !== 1) { + throwError(state, "YAML directive accepts exactly one argument"); + } + var match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + if (match === null) { + throwError(state, "ill-formed argument of the YAML directive"); + } + var major = parseInt(match[1], 10); + var minor = parseInt(match[2], 10); + if (major !== 1) { + throwError(state, "unacceptable YAML version of the document"); + } + state.version = args[0]; + state.checkLineBreaks = minor < 2; + if (minor !== 1 && minor !== 2) { + throwWarning(state, "unsupported YAML version of the document"); + } + }, + TAG: function handleTagDirective(state, name, args) { + var prefix; + if (args.length !== 2) { + throwError(state, "TAG directive accepts exactly two arguments"); + } + var handle = args[0]; + prefix = args[1]; + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, "ill-formed tag handle (first argument) of the TAG directive"); + } + if (_hasOwnProperty.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); + } + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, "ill-formed tag prefix (second argument) of the TAG directive"); + } + try { + prefix = decodeURIComponent(prefix); + } catch (err) { + throwError(state, "tag prefix is malformed: " + prefix); + } + state.tagMap[handle] = prefix; + } + }; + function captureSegment(state, start, end, checkJson) { + if (start < end) { + var _result = state.input.slice(start, end); + if (checkJson) { + for (var _position = 0, _length = _result.length; _position < _length; _position += 1) { + var _character = _result.charCodeAt(_position); + if (!(_character === 9 || _character >= 32 && _character <= 1114111)) { + throwError(state, "expected valid JSON character"); + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, "the stream contains non-printable characters"); + } + state.result += _result; + } + } + function mergeMappings(state, destination, source, overridableKeys) { + if (!common2.isObject(source)) { + throwError(state, "cannot merge mappings; the provided source object is unacceptable"); + } + var sourceKeys = Object.keys(source); + for (var index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + var key = sourceKeys[index]; + if (state.maxTotalMergeKeys !== -1 && ++state.totalMergeKeys > state.maxTotalMergeKeys) { + throwError(state, "merge keys exceeded maxTotalMergeKeys (" + state.maxTotalMergeKeys + ")"); + } + if (!_hasOwnProperty.call(destination, key)) { + setProperty(destination, key, source[key]); + overridableKeys[key] = true; + } + } + } + function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, startLine, startLineStart, startPos) { + if (Array.isArray(keyNode)) { + keyNode = Array.prototype.slice.call(keyNode); + for (var index = 0, quantity = keyNode.length; index < quantity; index += 1) { + if (Array.isArray(keyNode[index])) { + throwError(state, "nested arrays are not supported inside keys"); + } + if (_typeof(keyNode) === "object" && _class(keyNode[index]) === "[object Object]") { + keyNode[index] = "[object Object]"; + } + } + } + if (_typeof(keyNode) === "object" && _class(keyNode) === "[object Object]") { + keyNode = "[object Object]"; + } + keyNode = String(keyNode); + if (_result === null) { + _result = {}; + } + if (keyTag === "tag:yaml.org,2002:merge") { + if (Array.isArray(valueNode)) { + for (var _index = 0, _quantity = valueNode.length; _index < _quantity; _index += 1) { + mergeMappings(state, _result, valueNode[_index], overridableKeys); + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys); + } + } else { + if (!state.json && !_hasOwnProperty.call(overridableKeys, keyNode) && _hasOwnProperty.call(_result, keyNode)) { + state.line = startLine || state.line; + state.lineStart = startLineStart || state.lineStart; + state.position = startPos || state.position; + throwError(state, "duplicated mapping key"); + } + setProperty(_result, keyNode, valueNode); + delete overridableKeys[keyNode]; + } + return _result; + } + function readLineBreak(state) { + var ch = state.input.charCodeAt(state.position); + if (ch === 10) { + state.position++; + } else if (ch === 13) { + state.position++; + if (state.input.charCodeAt(state.position) === 10) { + state.position++; + } + } else { + throwError(state, "a line break is expected"); + } + state.line += 1; + state.lineStart = state.position; + state.firstTabInLine = -1; + } + function skipSeparationSpace(state, allowComments, checkIndent) { + var lineBreaks = 0; + var ch = state.input.charCodeAt(state.position); + while (ch !== 0) { + while (isWhiteSpace(ch)) { + if (ch === 9 && state.firstTabInLine === -1) { + state.firstTabInLine = state.position; + } + ch = state.input.charCodeAt(++state.position); + } + if (allowComments && ch === 35) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 10 && ch !== 13 && ch !== 0); + } + if (isEol(ch)) { + readLineBreak(state); + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; + while (ch === 32) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, "deficient indentation"); + } + return lineBreaks; + } + function testDocumentSeparator(state) { + var _position = state.position; + var ch = state.input.charCodeAt(_position); + if ((ch === 45 || ch === 46) && ch === state.input.charCodeAt(_position + 1) && ch === state.input.charCodeAt(_position + 2)) { + _position += 3; + ch = state.input.charCodeAt(_position); + if (ch === 0 || isWsOrEol(ch)) { + return true; + } + } + return false; + } + function writeFoldedLines(state, count) { + if (count === 1) { + state.result += " "; + } else if (count > 1) { + state.result += common2.repeat("\n", count - 1); + } + } + function readPlainScalar(state, nodeIndent, withinFlowCollection) { + var captureStart; + var captureEnd; + var hasPendingContent; + var _line; + var _lineStart; + var _lineIndent; + var _kind = state.kind; + var _result = state.result; + var ch = state.input.charCodeAt(state.position); + if (isWsOrEol(ch) || isFlowIndicator(ch) || ch === 35 || ch === 38 || ch === 42 || ch === 33 || ch === 124 || ch === 62 || ch === 39 || ch === 34 || ch === 37 || ch === 64 || ch === 96) { + return false; + } + if (ch === 63 || ch === 45) { + var following = state.input.charCodeAt(state.position + 1); + if (isWsOrEol(following) || withinFlowCollection && isFlowIndicator(following)) { + return false; + } + } + state.kind = "scalar"; + state.result = ""; + captureStart = captureEnd = state.position; + hasPendingContent = false; + while (ch !== 0) { + if (ch === 58) { + var _following = state.input.charCodeAt(state.position + 1); + if (isWsOrEol(_following) || withinFlowCollection && isFlowIndicator(_following)) { + break; + } + } else if (ch === 35) { + var preceding = state.input.charCodeAt(state.position - 1); + if (isWsOrEol(preceding)) { + break; + } + } else if (state.position === state.lineStart && testDocumentSeparator(state) || withinFlowCollection && isFlowIndicator(ch)) { + break; + } else if (isEol(ch)) { + _line = state.line; + _lineStart = state.lineStart; + _lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = _line; + state.lineStart = _lineStart; + state.lineIndent = _lineIndent; + break; + } + } + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - _line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } + if (!isWhiteSpace(ch)) { + captureEnd = state.position + 1; + } + ch = state.input.charCodeAt(++state.position); + } + captureSegment(state, captureStart, captureEnd, false); + if (state.result) { + return true; + } + state.kind = _kind; + state.result = _result; + return false; + } + function readSingleQuotedScalar(state, nodeIndent) { + var captureStart; + var captureEnd; + var ch = state.input.charCodeAt(state.position); + if (ch !== 39) { + return false; + } + state.kind = "scalar"; + state.result = ""; + state.position++; + captureStart = captureEnd = state.position; + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 39) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + if (ch === 39) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + } else if (isEol(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, "unexpected end of the document within a single quoted scalar"); + } else { + state.position++; + if (!isWhiteSpace(ch)) { + captureEnd = state.position; + } + } + } + throwError(state, "unexpected end of the stream within a single quoted scalar"); + } + function readDoubleQuotedScalar(state, nodeIndent) { + var captureStart; + var captureEnd; + var tmp; + var ch = state.input.charCodeAt(state.position); + if (ch !== 34) { + return false; + } + state.kind = "scalar"; + state.result = ""; + state.position++; + captureStart = captureEnd = state.position; + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 34) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + } else if (ch === 92) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + if (isEol(ch)) { + skipSeparationSpace(state, false, nodeIndent); + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; + } else if ((tmp = escapedHexLen(ch)) > 0) { + var hexLength = tmp; + var hexResult = 0; + for (;hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position); + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; + } else { + throwError(state, "expected hexadecimal character"); + } + } + state.result += charFromCodepoint(hexResult); + state.position++; + } else { + throwError(state, "unknown escape sequence"); + } + captureStart = captureEnd = state.position; + } else if (isEol(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, "unexpected end of the document within a double quoted scalar"); + } else { + state.position++; + if (!isWhiteSpace(ch)) { + captureEnd = state.position; + } + } + } + throwError(state, "unexpected end of the stream within a double quoted scalar"); + } + function readFlowCollection(state, nodeIndent) { + var readNext = true; + var _line; + var _lineStart; + var _pos; + var _tag = state.tag; + var _result; + var _anchor = state.anchor; + var terminator; + var isPair; + var isExplicitPair; + var isMapping; + var overridableKeys = Object.create(null); + var keyNode; + var keyTag; + var valueNode; + var ch = state.input.charCodeAt(state.position); + if (ch === 91) { + terminator = 93; + isMapping = false; + _result = []; + } else if (ch === 123) { + terminator = 125; + isMapping = true; + _result = {}; + } else { + return false; + } + if (state.anchor !== null) { + storeAnchor(state, state.anchor, _result); + } + ch = state.input.charCodeAt(++state.position); + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent); + ch = state.input.charCodeAt(state.position); + if (ch === terminator) { + state.position++; + state.tag = _tag; + state.anchor = _anchor; + state.kind = isMapping ? "mapping" : "sequence"; + state.result = _result; + return true; + } else if (!readNext) { + throwError(state, "missed comma between flow collection entries"); + } else if (ch === 44) { + throwError(state, "expected the node content, but found ','"); + } + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; + if (ch === 63) { + var following = state.input.charCodeAt(state.position + 1); + if (isWsOrEol(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } + _line = state.line; + _lineStart = state.lineStart; + _pos = state.position; + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + keyTag = state.tag; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + ch = state.input.charCodeAt(state.position); + if ((isExplicitPair || state.line === _line) && ch === 58) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + valueNode = state.result; + } + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos); + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)); + } else { + _result.push(keyNode); + } + skipSeparationSpace(state, true, nodeIndent); + ch = state.input.charCodeAt(state.position); + if (ch === 44) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } + throwError(state, "unexpected end of the stream within a flow collection"); + } + function readBlockScalar(state, nodeIndent) { + var folding; + var chomping = CHOMPING_CLIP; + var didReadContent = false; + var detectedIndent = false; + var textIndent = nodeIndent; + var emptyLines = 0; + var atMoreIndented = false; + var tmp; + var ch = state.input.charCodeAt(state.position); + if (ch === 124) { + folding = false; + } else if (ch === 62) { + folding = true; + } else { + return false; + } + state.kind = "scalar"; + state.result = ""; + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position); + if (ch === 43 || ch === 45) { + if (CHOMPING_CLIP === chomping) { + chomping = ch === 43 ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + throwError(state, "repeat of a chomping mode identifier"); + } + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, "bad explicit indentation width of a block scalar; it cannot be less than one"); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + throwError(state, "repeat of an indentation width identifier"); + } + } else { + break; + } + } + if (isWhiteSpace(ch)) { + do { + ch = state.input.charCodeAt(++state.position); + } while (isWhiteSpace(ch)); + if (ch === 35) { + do { + ch = state.input.charCodeAt(++state.position); + } while (!isEol(ch) && ch !== 0); + } + } + while (ch !== 0) { + readLineBreak(state); + state.lineIndent = 0; + ch = state.input.charCodeAt(state.position); + while ((!detectedIndent || state.lineIndent < textIndent) && ch === 32) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } + if (isEol(ch)) { + emptyLines++; + continue; + } + if (!detectedIndent && textIndent === 0) { + throwError(state, "missing indentation for block scalar"); + } + if (state.lineIndent < textIndent) { + if (chomping === CHOMPING_KEEP) { + state.result += common2.repeat("\n", didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { + state.result += "\n"; + } + } + break; + } + if (folding) { + if (isWhiteSpace(ch)) { + atMoreIndented = true; + state.result += common2.repeat("\n", didReadContent ? 1 + emptyLines : emptyLines); + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += common2.repeat("\n", emptyLines + 1); + } else if (emptyLines === 0) { + if (didReadContent) { + state.result += " "; + } + } else { + state.result += common2.repeat("\n", emptyLines); + } + } else { + state.result += common2.repeat("\n", didReadContent ? 1 + emptyLines : emptyLines); + } + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + var captureStart = state.position; + while (!isEol(ch) && ch !== 0) { + ch = state.input.charCodeAt(++state.position); + } + captureSegment(state, captureStart, state.position, false); + } + return true; + } + function readBlockSequence(state, nodeIndent) { + var _tag = state.tag; + var _anchor = state.anchor; + var _result = []; + var detected = false; + if (state.firstTabInLine !== -1) return false; + if (state.anchor !== null) { + storeAnchor(state, state.anchor, _result); + } + var ch = state.input.charCodeAt(state.position); + while (ch !== 0) { + if (state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, "tab characters must not be used in indentation"); + } + if (ch !== 45) { + break; + } + var following = state.input.charCodeAt(state.position + 1); + if (!isWsOrEol(following)) { + break; + } + detected = true; + state.position++; + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } + var _line = state.line; + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); + _result.push(state.result); + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + if ((state.line === _line || state.lineIndent > nodeIndent) && ch !== 0) { + throwError(state, "bad indentation of a sequence entry"); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = "sequence"; + state.result = _result; + return true; + } + return false; + } + function readBlockMapping(state, nodeIndent, flowIndent) { + var allowCompact; + var _keyLine; + var _keyLineStart; + var _keyPos; + var _tag = state.tag; + var _anchor = state.anchor; + var _result = {}; + var overridableKeys = Object.create(null); + var keyTag = null; + var keyNode = null; + var valueNode = null; + var atExplicitKey = false; + var detected = false; + if (state.firstTabInLine !== -1) return false; + if (state.anchor !== null) { + storeAnchor(state, state.anchor, _result); + } + var ch = state.input.charCodeAt(state.position); + while (ch !== 0) { + if (!atExplicitKey && state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, "tab characters must not be used in indentation"); + } + var following = state.input.charCodeAt(state.position + 1); + var _line = state.line; + if ((ch === 63 || ch === 58) && isWsOrEol(following)) { + if (ch === 63) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + detected = true; + atExplicitKey = true; + allowCompact = true; + } else if (atExplicitKey) { + atExplicitKey = false; + allowCompact = true; + } else { + throwError(state, "incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line"); + } + state.position += 1; + ch = following; + } else { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + break; + } + if (state.line === _line) { + ch = state.input.charCodeAt(state.position); + while (isWhiteSpace(ch)) { + ch = state.input.charCodeAt(++state.position); + } + if (ch === 58) { + ch = state.input.charCodeAt(++state.position); + if (!isWsOrEol(ch)) { + throwError(state, "a whitespace character is expected after the key-value separator within a block mapping"); + } + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; + } else if (detected) { + throwError(state, "can not read an implicit mapping pair; a colon is missed"); + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; + } + } else if (detected) { + throwError(state, "can not read a block mapping entry; a multiline key may not be an implicit key"); + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; + } + } + if (state.line === _line || state.lineIndent > nodeIndent) { + if (atExplicitKey) { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + } + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } + if ((state.line === _line || state.lineIndent > nodeIndent) && ch !== 0) { + throwError(state, "bad indentation of a mapping entry"); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + } + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = "mapping"; + state.result = _result; + } + return detected; + } + function readTagProperty(state) { + var isVerbatim = false; + var isNamed = false; + var tagHandle; + var tagName; + var ch = state.input.charCodeAt(state.position); + if (ch !== 33) return false; + if (state.tag !== null) { + throwError(state, "duplication of a tag property"); + } + ch = state.input.charCodeAt(++state.position); + if (ch === 60) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + } else if (ch === 33) { + isNamed = true; + tagHandle = "!!"; + ch = state.input.charCodeAt(++state.position); + } else { + tagHandle = "!"; + } + var _position = state.position; + if (isVerbatim) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0 && ch !== 62); + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + throwError(state, "unexpected end of the stream within a verbatim tag"); + } + } else { + while (ch !== 0 && !isWsOrEol(ch)) { + if (ch === 33) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1); + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, "named tag handle cannot contain such characters"); + } + isNamed = true; + _position = state.position + 1; + } else { + throwError(state, "tag suffix cannot contain exclamation marks"); + } + } + ch = state.input.charCodeAt(++state.position); + } + tagName = state.input.slice(_position, state.position); + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, "tag suffix cannot contain flow indicator characters"); + } + } + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, "tag name cannot contain such characters: " + tagName); + } + try { + tagName = decodeURIComponent(tagName); + } catch (err) { + throwError(state, "tag name is malformed: " + tagName); + } + if (isVerbatim) { + state.tag = tagName; + } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; + } else if (tagHandle === "!") { + state.tag = "!" + tagName; + } else if (tagHandle === "!!") { + state.tag = "tag:yaml.org,2002:" + tagName; + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"'); + } + return true; + } + function readAnchorProperty(state) { + var ch = state.input.charCodeAt(state.position); + if (ch !== 38) return false; + if (state.anchor !== null) { + throwError(state, "duplication of an anchor property"); + } + ch = state.input.charCodeAt(++state.position); + var _position = state.position; + while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) { + ch = state.input.charCodeAt(++state.position); + } + if (state.position === _position) { + throwError(state, "name of an anchor node must contain at least one character"); + } + state.anchor = state.input.slice(_position, state.position); + return true; + } + function readAlias(state) { + var ch = state.input.charCodeAt(state.position); + if (ch !== 42) return false; + ch = state.input.charCodeAt(++state.position); + var _position = state.position; + while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) { + ch = state.input.charCodeAt(++state.position); + } + if (state.position === _position) { + throwError(state, "name of an alias node must contain at least one character"); + } + var alias = state.input.slice(_position, state.position); + if (!_hasOwnProperty.call(state.anchorMap, alias)) { + throwError(state, 'unidentified alias "' + alias + '"'); + } + state.result = state.anchorMap[alias]; + skipSeparationSpace(state, true, -1); + return true; + } + function tryReadBlockMappingFromProperty(state, propertyStart, nodeIndent, flowIndent) { + var fallbackState = snapshotState(state); + beginAnchorTransaction(state); + restoreState(state, propertyStart); + state.tag = null; + state.anchor = null; + state.kind = null; + state.result = null; + if (readBlockMapping(state, nodeIndent, flowIndent) && state.kind === "mapping") { + commitAnchorTransaction(state); + return true; + } + rollbackAnchorTransaction(state); + restoreState(state, fallbackState); + return false; + } + function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + var allowBlockScalars; + var allowBlockCollections; + var indentStatus = 1; + var atNewLine = false; + var hasContent = false; + var propertyStart = null; + var type2; + var flowIndent; + var blockIndent; + if (state.depth >= state.maxDepth) { + throwError(state, "nesting exceeded maxDepth (" + state.maxDepth + ")"); + } + state.depth += 1; + if (state.listener !== null) { + state.listener("open", state); + } + state.tag = null; + state.anchor = null; + state.kind = null; + state.result = null; + var allowBlockStyles = allowBlockScalars = allowBlockCollections = CONTEXT_BLOCK_OUT === nodeContext || CONTEXT_BLOCK_IN === nodeContext; + if (allowToSeek) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } + if (indentStatus === 1) { + while (true) { + var ch = state.input.charCodeAt(state.position); + var propertyState = snapshotState(state); + if (atNewLine && (ch === 33 && state.tag !== null || ch === 38 && state.anchor !== null)) { + break; + } + if (!readTagProperty(state) && !readAnchorProperty(state)) { + break; + } + if (propertyStart === null) { + propertyStart = propertyState; + } + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent; + } else { + flowIndent = parentIndent + 1; + } + blockIndent = state.position - state.lineStart; + if (indentStatus === 1) { + if (allowBlockCollections && (readBlockSequence(state, blockIndent) || readBlockMapping(state, blockIndent, flowIndent)) || readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + var _ch = state.input.charCodeAt(state.position); + if (propertyStart !== null && allowBlockStyles && !allowBlockCollections && _ch !== 124 && _ch !== 62 && tryReadBlockMappingFromProperty(state, propertyStart, propertyStart.position - propertyStart.lineStart, flowIndent)) { + hasContent = true; + } else if (allowBlockScalars && readBlockScalar(state, flowIndent) || readSingleQuotedScalar(state, flowIndent) || readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + } else if (readAlias(state)) { + hasContent = true; + if (state.tag !== null || state.anchor !== null) { + throwError(state, "alias node should not have any properties"); + } + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true; + if (state.tag === null) { + state.tag = "?"; + } + } + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result); + } + } + } else if (indentStatus === 0) { + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } + if (state.tag === null) { + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result); + } + } else if (state.tag === "?") { + if (state.result !== null && state.kind !== "scalar") { + throwError(state, 'unacceptable node kind for ! tag; it should be "scalar", not "' + state.kind + '"'); + } + for (var typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) { + type2 = state.implicitTypes[typeIndex]; + if (type2.resolve(state.result)) { + state.result = type2.construct(state.result); + state.tag = type2.tag; + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result); + } + break; + } + } + } else if (state.tag !== "!") { + if (_hasOwnProperty.call(state.typeMap[state.kind || "fallback"], state.tag)) { + type2 = state.typeMap[state.kind || "fallback"][state.tag]; + } else { + type2 = null; + var typeList = state.typeMap.multi[state.kind || "fallback"]; + for (var _typeIndex = 0, _typeQuantity = typeList.length; _typeIndex < _typeQuantity; _typeIndex += 1) { + if (state.tag.slice(0, typeList[_typeIndex].tag.length) === typeList[_typeIndex].tag) { + type2 = typeList[_typeIndex]; + break; + } + } + } + if (!type2) { + throwError(state, "unknown tag !<" + state.tag + ">"); + } + if (state.result !== null && type2.kind !== state.kind) { + throwError(state, "unacceptable node kind for !<" + state.tag + '> tag; it should be "' + type2.kind + '", not "' + state.kind + '"'); + } + if (!type2.resolve(state.result, state.tag)) { + throwError(state, "cannot resolve a node with !<" + state.tag + "> explicit tag"); + } else { + state.result = type2.construct(state.result, state.tag); + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result); + } + } + } + if (state.listener !== null) { + state.listener("close", state); + } + state.depth -= 1; + return state.tag !== null || state.anchor !== null || hasContent; + } + function readDocument(state) { + var documentStart = state.position; + var hasDirectives = false; + var ch; + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = Object.create(null); + state.anchorMap = Object.create(null); + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + if (state.lineIndent > 0 || ch !== 37) { + break; + } + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + var _position = state.position; + while (ch !== 0 && !isWsOrEol(ch)) { + ch = state.input.charCodeAt(++state.position); + } + var directiveName = state.input.slice(_position, state.position); + var directiveArgs = []; + if (directiveName.length < 1) { + throwError(state, "directive name must not be less than one character in length"); + } + while (ch !== 0) { + while (isWhiteSpace(ch)) { + ch = state.input.charCodeAt(++state.position); + } + if (ch === 35) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0 && !isEol(ch)); + break; + } + if (isEol(ch)) break; + _position = state.position; + while (ch !== 0 && !isWsOrEol(ch)) { + ch = state.input.charCodeAt(++state.position); + } + directiveArgs.push(state.input.slice(_position, state.position)); + } + if (ch !== 0) readLineBreak(state); + if (_hasOwnProperty.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs); + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"'); + } + } + skipSeparationSpace(state, true, -1); + if (state.lineIndent === 0 && state.input.charCodeAt(state.position) === 45 && state.input.charCodeAt(state.position + 1) === 45 && state.input.charCodeAt(state.position + 2) === 45) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } else if (hasDirectives) { + throwError(state, "directives end mark is expected"); + } + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); + skipSeparationSpace(state, true, -1); + if (state.checkLineBreaks && PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, "non-ASCII line breaks are interpreted as content"); + } + state.documents.push(state.result); + if (state.position === state.lineStart && testDocumentSeparator(state)) { + if (state.input.charCodeAt(state.position) === 46) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } + if (state.position < state.length - 1) { + throwError(state, "end of the stream or a document separator is expected"); + } + } + function loadDocuments(input, options) { + input = String(input); + options = options || {}; + if (input.length !== 0) { + if (input.charCodeAt(input.length - 1) !== 10 && input.charCodeAt(input.length - 1) !== 13) { + input += "\n"; + } + if (input.charCodeAt(0) === 65279) { + input = input.slice(1); + } + } + var state = new State(input, options); + var nullpos = input.indexOf("\0"); + if (nullpos !== -1) { + state.position = nullpos; + throwError(state, "null byte is not allowed in input"); + } + state.input += "\0"; + while (state.input.charCodeAt(state.position) === 32) { + state.lineIndent += 1; + state.position += 1; + } + while (state.position < state.length - 1) { + readDocument(state); + } + return state.documents; + } + function loadAll2(input, iterator, options) { + if (iterator !== null && _typeof(iterator) === "object" && typeof options === "undefined") { + options = iterator; + iterator = null; + } + var documents = loadDocuments(input, options); + if (typeof iterator !== "function") { + return documents; + } + for (var index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]); + } + } + function load2(input, options) { + var documents = loadDocuments(input, options); + if (documents.length === 0) { + return void 0; + } else if (documents.length === 1) { + return documents[0]; + } + throw new YAMLException2("expected a single document in the stream, but found more"); + } + loader.loadAll = loadAll2; + loader.load = load2; + return loader; + } + var dumper = {}; + var hasRequiredDumper; + function requireDumper() { + if (hasRequiredDumper) return dumper; + hasRequiredDumper = 1; + function _typeof(o) { + "@babel/helpers - typeof"; + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) { + return typeof o2; + } : function(o2) { + return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2; + }, _typeof(o); + } + var common2 = requireCommon(); + var YAMLException2 = requireException(); + var DEFAULT_SCHEMA2 = require_default(); + var _toString = Object.prototype.toString; + var _hasOwnProperty = Object.prototype.hasOwnProperty; + var CHAR_BOM = 65279; + var CHAR_TAB = 9; + var CHAR_LINE_FEED = 10; + var CHAR_CARRIAGE_RETURN = 13; + var CHAR_SPACE = 32; + var CHAR_EXCLAMATION = 33; + var CHAR_DOUBLE_QUOTE = 34; + var CHAR_SHARP = 35; + var CHAR_PERCENT = 37; + var CHAR_AMPERSAND = 38; + var CHAR_SINGLE_QUOTE = 39; + var CHAR_ASTERISK = 42; + var CHAR_COMMA = 44; + var CHAR_MINUS = 45; + var CHAR_COLON = 58; + var CHAR_EQUALS = 61; + var CHAR_GREATER_THAN = 62; + var CHAR_QUESTION = 63; + var CHAR_COMMERCIAL_AT = 64; + var CHAR_LEFT_SQUARE_BRACKET = 91; + var CHAR_RIGHT_SQUARE_BRACKET = 93; + var CHAR_GRAVE_ACCENT = 96; + var CHAR_LEFT_CURLY_BRACKET = 123; + var CHAR_VERTICAL_LINE = 124; + var CHAR_RIGHT_CURLY_BRACKET = 125; + var ESCAPE_SEQUENCES = {}; + ESCAPE_SEQUENCES[0] = "\\0"; + ESCAPE_SEQUENCES[7] = "\\a"; + ESCAPE_SEQUENCES[8] = "\\b"; + ESCAPE_SEQUENCES[9] = "\\t"; + ESCAPE_SEQUENCES[10] = "\\n"; + ESCAPE_SEQUENCES[11] = "\\v"; + ESCAPE_SEQUENCES[12] = "\\f"; + ESCAPE_SEQUENCES[13] = "\\r"; + ESCAPE_SEQUENCES[27] = "\\e"; + ESCAPE_SEQUENCES[34] = '\\"'; + ESCAPE_SEQUENCES[92] = "\\\\"; + ESCAPE_SEQUENCES[133] = "\\N"; + ESCAPE_SEQUENCES[160] = "\\_"; + ESCAPE_SEQUENCES[8232] = "\\L"; + ESCAPE_SEQUENCES[8233] = "\\P"; + var DEPRECATED_BOOLEANS_SYNTAX = [ "y", "Y", "yes", "Yes", "YES", "on", "On", "ON", "n", "N", "no", "No", "NO", "off", "Off", "OFF" ]; + var DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/; + function compileStyleMap(schema2, map2) { + if (map2 === null) return {}; + var result = {}; + var keys = Object.keys(map2); + for (var index = 0, length = keys.length; index < length; index += 1) { + var tag = keys[index]; + var style = String(map2[tag]); + if (tag.slice(0, 2) === "!!") { + tag = "tag:yaml.org,2002:" + tag.slice(2); + } + var type2 = schema2.compiledTypeMap["fallback"][tag]; + if (type2 && _hasOwnProperty.call(type2.styleAliases, style)) { + style = type2.styleAliases[style]; + } + result[tag] = style; + } + return result; + } + function encodeHex(character) { + var handle; + var length; + var string = character.toString(16).toUpperCase(); + if (character <= 255) { + handle = "x"; + length = 2; + } else if (character <= 65535) { + handle = "u"; + length = 4; + } else if (character <= 4294967295) { + handle = "U"; + length = 8; + } else { + throw new YAMLException2("code point within a string may not be greater than 0xFFFFFFFF"); + } + return "\\" + handle + common2.repeat("0", length - string.length) + string; + } + var QUOTING_TYPE_SINGLE = 1; + var QUOTING_TYPE_DOUBLE = 2; + function State(options) { + this.schema = options["schema"] || DEFAULT_SCHEMA2; + this.indent = Math.max(1, options["indent"] || 2); + this.noArrayIndent = options["noArrayIndent"] || false; + this.skipInvalid = options["skipInvalid"] || false; + this.flowLevel = common2.isNothing(options["flowLevel"]) ? -1 : options["flowLevel"]; + this.styleMap = compileStyleMap(this.schema, options["styles"] || null); + this.sortKeys = options["sortKeys"] || false; + this.lineWidth = options["lineWidth"] || 80; + this.noRefs = options["noRefs"] || false; + this.noCompatMode = options["noCompatMode"] || false; + this.condenseFlow = options["condenseFlow"] || false; + this.quotingType = options["quotingType"] === '"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE; + this.forceQuotes = options["forceQuotes"] || false; + this.replacer = typeof options["replacer"] === "function" ? options["replacer"] : null; + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + this.tag = null; + this.result = ""; + this.duplicates = []; + this.usedDuplicates = null; + } + function indentString(string, spaces) { + var ind = common2.repeat(" ", spaces); + var position = 0; + var result = ""; + var length = string.length; + while (position < length) { + var line = void 0; + var next = string.indexOf("\n", position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + if (line.length && line !== "\n") result += ind; + result += line; + } + return result; + } + function generateNextLine(state, level) { + return "\n" + common2.repeat(" ", state.indent * level); + } + function testImplicitResolving(state, str2) { + for (var index = 0, length = state.implicitTypes.length; index < length; index += 1) { + var type2 = state.implicitTypes[index]; + if (type2.resolve(str2)) { + return true; + } + } + return false; + } + function isWhitespace(c) { + return c === CHAR_SPACE || c === CHAR_TAB; + } + function isPrintable(c) { + return c >= 32 && c <= 126 || c >= 161 && c <= 55295 && c !== 8232 && c !== 8233 || c >= 57344 && c <= 65533 && c !== CHAR_BOM || c >= 65536 && c <= 1114111; + } + function isNsCharOrWhitespace(c) { + return isPrintable(c) && c !== CHAR_BOM && c !== CHAR_CARRIAGE_RETURN && c !== CHAR_LINE_FEED; + } + function isPlainSafe(c, prev, inblock) { + var cIsNsCharOrWhitespace = isNsCharOrWhitespace(c); + var cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c); + return (inblock ? cIsNsCharOrWhitespace : cIsNsCharOrWhitespace && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET) && c !== CHAR_SHARP && !(prev === CHAR_COLON && !cIsNsChar) || isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP || prev === CHAR_COLON && cIsNsChar; + } + function isPlainSafeFirst(c) { + return isPrintable(c) && c !== CHAR_BOM && !isWhitespace(c) && c !== CHAR_MINUS && c !== CHAR_QUESTION && c !== CHAR_COLON && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET && c !== CHAR_SHARP && c !== CHAR_AMPERSAND && c !== CHAR_ASTERISK && c !== CHAR_EXCLAMATION && c !== CHAR_VERTICAL_LINE && c !== CHAR_EQUALS && c !== CHAR_GREATER_THAN && c !== CHAR_SINGLE_QUOTE && c !== CHAR_DOUBLE_QUOTE && c !== CHAR_PERCENT && c !== CHAR_COMMERCIAL_AT && c !== CHAR_GRAVE_ACCENT; + } + function isPlainSafeLast(c) { + return !isWhitespace(c) && c !== CHAR_COLON; + } + function codePointAt(string, pos) { + var first = string.charCodeAt(pos); + var second; + if (first >= 55296 && first <= 56319 && pos + 1 < string.length) { + second = string.charCodeAt(pos + 1); + if (second >= 56320 && second <= 57343) { + return (first - 55296) * 1024 + second - 56320 + 65536; + } + } + return first; + } + function needIndentIndicator(string) { + var leadingSpaceRe = /^\n* /; + return leadingSpaceRe.test(string); + } + var STYLE_PLAIN = 1; + var STYLE_SINGLE = 2; + var STYLE_LITERAL = 3; + var STYLE_FOLDED = 4; + var STYLE_DOUBLE = 5; + function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType, quotingType, forceQuotes, inblock) { + var i; + var char = 0; + var prevChar = null; + var hasLineBreak = false; + var hasFoldableLine = false; + var shouldTrackWidth = lineWidth !== -1; + var previousLineBreak = -1; + var plain = isPlainSafeFirst(codePointAt(string, 0)) && isPlainSafeLast(codePointAt(string, string.length - 1)); + if (singleLineOnly || forceQuotes) { + for (i = 0; i < string.length; char >= 65536 ? i += 2 : i++) { + char = codePointAt(string, i); + if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + } else { + for (i = 0; i < string.length; char >= 65536 ? i += 2 : i++) { + char = codePointAt(string, i); + if (char === CHAR_LINE_FEED) { + hasLineBreak = true; + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== " "; + previousLineBreak = i; + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + hasFoldableLine = hasFoldableLine || shouldTrackWidth && i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== " "; + } + if (!hasLineBreak && !hasFoldableLine) { + if (plain && !forceQuotes && !testAmbiguousType(string)) { + return STYLE_PLAIN; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + if (indentPerLevel > 9 && needIndentIndicator(string)) { + return STYLE_DOUBLE; + } + if (!forceQuotes) { + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + function writeScalar(state, string, level, iskey, inblock) { + state.dump = function() { + if (string.length === 0) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? '""' : "''"; + } + if (!state.noCompatMode) { + if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? '"' + string + '"' : "'" + string + "'"; + } + } + var indent = state.indent * Math.max(1, level); + var lineWidth = state.lineWidth === -1 ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + var singleLineOnly = iskey || state.flowLevel > -1 && level >= state.flowLevel; + function testAmbiguity(string2) { + return testImplicitResolving(state, string2); + } + switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, testAmbiguity, state.quotingType, state.forceQuotes && !iskey, inblock)) { + case STYLE_PLAIN: + return string; + + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'"; + + case STYLE_LITERAL: + return "|" + blockHeader(string, state.indent) + dropEndingNewline(indentString(string, indent)); + + case STYLE_FOLDED: + return ">" + blockHeader(string, state.indent) + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); + + case STYLE_DOUBLE: + return '"' + escapeString(string) + '"'; + + default: + throw new YAMLException2("impossible error: invalid scalar style"); + } + }(); + } + function blockHeader(string, indentPerLevel) { + var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ""; + var clip = string[string.length - 1] === "\n"; + var keep = clip && (string[string.length - 2] === "\n" || string === "\n"); + var chomp = keep ? "+" : clip ? "" : "-"; + return indentIndicator + chomp + "\n"; + } + function dropEndingNewline(string) { + return string[string.length - 1] === "\n" ? string.slice(0, -1) : string; + } + function foldString(string, width) { + var lineRe = /(\n+)([^\n]*)/g; + var result = function() { + var nextLF = string.indexOf("\n"); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + }(); + var prevMoreIndented = string[0] === "\n" || string[0] === " "; + var moreIndented; + var match; + while (match = lineRe.exec(string)) { + var prefix = match[1]; + var line = match[2]; + moreIndented = line[0] === " "; + result += prefix + (!prevMoreIndented && !moreIndented && line !== "" ? "\n" : "") + foldLine(line, width); + prevMoreIndented = moreIndented; + } + return result; + } + function foldLine(line, width) { + if (line === "" || line[0] === " ") return line; + var breakRe = / [^ ]/g; + var match; + var start = 0; + var end; + var curr = 0; + var next = 0; + var result = ""; + while (match = breakRe.exec(line)) { + next = match.index; + if (next - start > width) { + end = curr > start ? curr : next; + result += "\n" + line.slice(start, end); + start = end + 1; + } + curr = next; + } + result += "\n"; + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + "\n" + line.slice(curr + 1); + } else { + result += line.slice(start); + } + return result.slice(1); + } + function escapeString(string) { + var result = ""; + var char = 0; + for (var i = 0; i < string.length; char >= 65536 ? i += 2 : i++) { + char = codePointAt(string, i); + var escapeSeq = ESCAPE_SEQUENCES[char]; + if (!escapeSeq && isPrintable(char)) { + result += string[i]; + if (char >= 65536) result += string[i + 1]; + } else { + result += escapeSeq || encodeHex(char); + } + } + return result; + } + function writeFlowSequence(state, level, object) { + var _result = ""; + var _tag = state.tag; + for (var index = 0, length = object.length; index < length; index += 1) { + var value = object[index]; + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + if (writeNode(state, level, value, false, false) || typeof value === "undefined" && writeNode(state, level, null, false, false)) { + if (_result !== "") _result += "," + (!state.condenseFlow ? " " : ""); + _result += state.dump; + } + } + state.tag = _tag; + state.dump = "[" + _result + "]"; + } + function writeBlockSequence(state, level, object, compact) { + var _result = ""; + var _tag = state.tag; + for (var index = 0, length = object.length; index < length; index += 1) { + var value = object[index]; + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + if (writeNode(state, level + 1, value, true, true, false, true) || typeof value === "undefined" && writeNode(state, level + 1, null, true, true, false, true)) { + if (!compact || _result !== "") { + _result += generateNextLine(state, level); + } + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + _result += "-"; + } else { + _result += "- "; + } + _result += state.dump; + } + } + state.tag = _tag; + state.dump = _result || "[]"; + } + function writeFlowMapping(state, level, object) { + var _result = ""; + var _tag = state.tag; + var objectKeyList = Object.keys(object); + for (var index = 0, length = objectKeyList.length; index < length; index += 1) { + var pairBuffer = ""; + if (_result !== "") pairBuffer += ", "; + if (state.condenseFlow) pairBuffer += '"'; + var objectKey = objectKeyList[index]; + var objectValue = object[objectKey]; + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + if (!writeNode(state, level, objectKey, false, false)) { + continue; + } + if (state.dump.length > 1024) pairBuffer += "? "; + pairBuffer += state.dump + (state.condenseFlow ? '"' : "") + ":" + (state.condenseFlow ? "" : " "); + if (!writeNode(state, level, objectValue, false, false)) { + continue; + } + pairBuffer += state.dump; + _result += pairBuffer; + } + state.tag = _tag; + state.dump = "{" + _result + "}"; + } + function writeBlockMapping(state, level, object, compact) { + var _result = ""; + var _tag = state.tag; + var objectKeyList = Object.keys(object); + if (state.sortKeys === true) { + objectKeyList.sort(); + } else if (typeof state.sortKeys === "function") { + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + throw new YAMLException2("sortKeys must be a boolean or a function"); + } + for (var index = 0, length = objectKeyList.length; index < length; index += 1) { + var pairBuffer = ""; + if (!compact || _result !== "") { + pairBuffer += generateNextLine(state, level); + } + var objectKey = objectKeyList[index]; + var objectValue = object[objectKey]; + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; + } + var explicitPair = state.tag !== null && state.tag !== "?" || state.dump && state.dump.length > 1024; + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += "?"; + } else { + pairBuffer += "? "; + } + } + pairBuffer += state.dump; + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; + } + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ":"; + } else { + pairBuffer += ": "; + } + pairBuffer += state.dump; + _result += pairBuffer; + } + state.tag = _tag; + state.dump = _result || "{}"; + } + function detectType(state, object, explicit) { + var typeList = explicit ? state.explicitTypes : state.implicitTypes; + for (var index = 0, length = typeList.length; index < length; index += 1) { + var type2 = typeList[index]; + if ((type2.instanceOf || type2.predicate) && (!type2.instanceOf || _typeof(object) === "object" && object instanceof type2.instanceOf) && (!type2.predicate || type2.predicate(object))) { + if (explicit) { + if (type2.multi && type2.representName) { + state.tag = type2.representName(object); + } else { + state.tag = type2.tag; + } + } else { + state.tag = "?"; + } + if (type2.represent) { + var style = state.styleMap[type2.tag] || type2.defaultStyle; + var _result = void 0; + if (_toString.call(type2.represent) === "[object Function]") { + _result = type2.represent(object, style); + } else if (_hasOwnProperty.call(type2.represent, style)) { + _result = type2.represent[style](object, style); + } else { + throw new YAMLException2("!<" + type2.tag + '> tag resolver accepts not "' + style + '" style'); + } + state.dump = _result; + } + return true; + } + } + return false; + } + function writeNode(state, level, object, block, compact, iskey, isblockseq) { + state.tag = null; + state.dump = object; + if (!detectType(state, object, false)) { + detectType(state, object, true); + } + var type2 = _toString.call(state.dump); + var inblock = block; + if (block) { + block = state.flowLevel < 0 || state.flowLevel > level; + } + var objectOrArray = type2 === "[object Object]" || type2 === "[object Array]"; + var duplicateIndex; + var duplicate; + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } + if (state.tag !== null && state.tag !== "?" || duplicate || state.indent !== 2 && level > 0) { + compact = false; + } + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = "*ref_" + duplicateIndex; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type2 === "[object Object]") { + if (block && Object.keys(state.dump).length !== 0) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = "&ref_" + duplicateIndex + state.dump; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = "&ref_" + duplicateIndex + " " + state.dump; + } + } + } else if (type2 === "[object Array]") { + if (block && state.dump.length !== 0) { + if (state.noArrayIndent && !isblockseq && level > 0) { + writeBlockSequence(state, level - 1, state.dump, compact); + } else { + writeBlockSequence(state, level, state.dump, compact); + } + if (duplicate) { + state.dump = "&ref_" + duplicateIndex + state.dump; + } + } else { + writeFlowSequence(state, level, state.dump); + if (duplicate) { + state.dump = "&ref_" + duplicateIndex + " " + state.dump; + } + } + } else if (type2 === "[object String]") { + if (state.tag !== "?") { + writeScalar(state, state.dump, level, iskey, inblock); + } + } else if (type2 === "[object Undefined]") { + return false; + } else { + if (state.skipInvalid) return false; + throw new YAMLException2("unacceptable kind of an object to dump " + type2); + } + if (state.tag !== null && state.tag !== "?") { + var tagStr = encodeURI(state.tag[0] === "!" ? state.tag.slice(1) : state.tag).replace(/!/g, "%21"); + if (state.tag[0] === "!") { + tagStr = "!" + tagStr; + } else if (tagStr.slice(0, 18) === "tag:yaml.org,2002:") { + tagStr = "!!" + tagStr.slice(18); + } else { + tagStr = "!<" + tagStr + ">"; + } + state.dump = tagStr + " " + state.dump; + } + } + return true; + } + function getDuplicateReferences(object, state) { + var objects = []; + var duplicatesIndexes = []; + inspectNode(object, objects, duplicatesIndexes); + var length = duplicatesIndexes.length; + for (var index = 0; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = new Array(length); + } + function inspectNode(object, objects, duplicatesIndexes) { + if (object !== null && _typeof(object) === "object") { + var index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + if (Array.isArray(object)) { + for (var i = 0, length = object.length; i < length; i += 1) { + inspectNode(object[i], objects, duplicatesIndexes); + } + } else { + var objectKeyList = Object.keys(object); + for (var _i = 0, _length = objectKeyList.length; _i < _length; _i += 1) { + inspectNode(object[objectKeyList[_i]], objects, duplicatesIndexes); + } + } + } + } + } + function dump2(input, options) { + options = options || {}; + var state = new State(options); + if (!state.noRefs) getDuplicateReferences(input, state); + var value = input; + if (state.replacer) { + value = state.replacer.call({ + "": value + }, "", value); + } + if (writeNode(state, 0, value, true, true)) return state.dump + "\n"; + return ""; + } + dumper.dump = dump2; + return dumper; + } + var hasRequiredJsYaml; + function requireJsYaml() { + if (hasRequiredJsYaml) return jsYaml; + hasRequiredJsYaml = 1; + var loader2 = requireLoader(); + var dumper2 = requireDumper(); + function renamed(from, to) { + return function() { + throw new Error("Function yaml." + from + " is removed in js-yaml 4. Use yaml." + to + " instead, which is now safe by default."); + }; + } + jsYaml.Type = requireType(); + jsYaml.Schema = requireSchema(); + jsYaml.FAILSAFE_SCHEMA = requireFailsafe(); + jsYaml.JSON_SCHEMA = requireJson(); + jsYaml.CORE_SCHEMA = requireCore(); + jsYaml.DEFAULT_SCHEMA = require_default(); + jsYaml.load = loader2.load; + jsYaml.loadAll = loader2.loadAll; + jsYaml.dump = dumper2.dump; + jsYaml.YAMLException = requireException(); + jsYaml.types = { + binary: requireBinary(), + float: requireFloat(), + map: requireMap(), + null: require_null(), + pairs: requirePairs(), + set: requireSet(), + timestamp: requireTimestamp(), + bool: requireBool(), + int: requireInt(), + merge: requireMerge(), + omap: requireOmap(), + seq: requireSeq(), + str: requireStr() + }; + jsYaml.safeLoad = renamed("safeLoad", "load"); + jsYaml.safeLoadAll = renamed("safeLoadAll", "loadAll"); + jsYaml.safeDump = renamed("safeDump", "dump"); + return jsYaml; + } + var jsYamlExports = requireJsYaml(); + var yaml = getDefaultExportFromCjs(jsYamlExports); + var Type = yaml.Type, Schema = yaml.Schema, FAILSAFE_SCHEMA = yaml.FAILSAFE_SCHEMA, JSON_SCHEMA = yaml.JSON_SCHEMA, CORE_SCHEMA = yaml.CORE_SCHEMA, DEFAULT_SCHEMA = yaml.DEFAULT_SCHEMA, load = yaml.load, loadAll = yaml.loadAll, dump = yaml.dump, YAMLException = yaml.YAMLException, types = yaml.types, safeLoad = yaml.safeLoad, safeLoadAll = yaml.safeLoadAll, safeDump = yaml.safeDump; + exports2.CORE_SCHEMA = CORE_SCHEMA; + exports2.DEFAULT_SCHEMA = DEFAULT_SCHEMA; + exports2.FAILSAFE_SCHEMA = FAILSAFE_SCHEMA; + exports2.JSON_SCHEMA = JSON_SCHEMA; + exports2.Schema = Schema; + exports2.Type = Type; + exports2.YAMLException = YAMLException; + exports2.default = yaml; + exports2.dump = dump; + exports2.load = load; + exports2.loadAll = loadAll; + exports2.safeDump = safeDump; + exports2.safeLoad = safeLoad; + exports2.safeLoadAll = safeLoadAll; + exports2.types = types; + Object.defineProperty(exports2, "__esModule", { + value: true + }); +}); +//# sourceMappingURL=js-yaml.js.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.js.map b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.js.map new file mode 100644 index 0000000..fc3d4e2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.js.map @@ -0,0 +1 @@ +{"version":3,"file":"js-yaml.js","sources":["../lib/common.js","../lib/exception.js","../lib/snippet.js","../lib/type.js","../lib/schema.js","../lib/type/str.js","../lib/type/seq.js","../lib/type/map.js","../lib/schema/failsafe.js","../lib/type/null.js","../lib/type/bool.js","../lib/type/int.js","../lib/type/float.js","../lib/schema/json.js","../lib/schema/core.js","../lib/type/timestamp.js","../lib/type/merge.js","../lib/type/binary.js","../lib/type/omap.js","../lib/type/pairs.js","../lib/type/set.js","../lib/schema/default.js","../lib/loader.js","../lib/dumper.js","../index.js","../lib/index_vite_proxy.tmp.mjs"],"sourcesContent":["'use strict'\n\nfunction isNothing (subject) {\n return (typeof subject === 'undefined') || (subject === null)\n}\n\nfunction isObject (subject) {\n return (typeof subject === 'object') && (subject !== null)\n}\n\nfunction toArray (sequence) {\n if (Array.isArray(sequence)) return sequence\n else if (isNothing(sequence)) return []\n\n return [sequence]\n}\n\nfunction extend (target, source) {\n if (source) {\n const sourceKeys = Object.keys(source)\n\n for (let index = 0, length = sourceKeys.length; index < length; index += 1) {\n const key = sourceKeys[index]\n target[key] = source[key]\n }\n }\n\n return target\n}\n\nfunction repeat (string, count) {\n let result = ''\n\n for (let cycle = 0; cycle < count; cycle += 1) {\n result += string\n }\n\n return result\n}\n\nfunction isNegativeZero (number) {\n return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number)\n}\n\nmodule.exports.isNothing = isNothing\nmodule.exports.isObject = isObject\nmodule.exports.toArray = toArray\nmodule.exports.repeat = repeat\nmodule.exports.isNegativeZero = isNegativeZero\nmodule.exports.extend = extend\n","// YAML error class. http://stackoverflow.com/questions/8458984\n//\n'use strict'\n\nfunction formatError (exception, compact) {\n let where = ''\n const message = exception.reason || '(unknown reason)'\n\n if (!exception.mark) return message\n\n if (exception.mark.name) {\n where += 'in \"' + exception.mark.name + '\" '\n }\n\n where += '(' + (exception.mark.line + 1) + ':' + (exception.mark.column + 1) + ')'\n\n if (!compact && exception.mark.snippet) {\n where += '\\n\\n' + exception.mark.snippet\n }\n\n return message + ' ' + where\n}\n\nfunction YAMLException (reason, mark) {\n // Super constructor\n Error.call(this)\n\n this.name = 'YAMLException'\n this.reason = reason\n this.mark = mark\n this.message = formatError(this, false)\n\n // Include stack trace in error object\n if (Error.captureStackTrace) {\n // Chrome and NodeJS\n Error.captureStackTrace(this, this.constructor)\n } else {\n // FF, IE 10+ and Safari 6+. Fallback for others\n this.stack = (new Error()).stack || ''\n }\n}\n\n// Inherit from Error\nYAMLException.prototype = Object.create(Error.prototype)\nYAMLException.prototype.constructor = YAMLException\n\nYAMLException.prototype.toString = function toString (compact) {\n return this.name + ': ' + formatError(this, compact)\n}\n\nmodule.exports = YAMLException\n","'use strict'\n\nconst common = require('./common')\n\n// get snippet for a single line, respecting maxLength\nfunction getLine (buffer, lineStart, lineEnd, position, maxLineLength) {\n let head = ''\n let tail = ''\n const maxHalfLength = Math.floor(maxLineLength / 2) - 1\n\n if (position - lineStart > maxHalfLength) {\n head = ' ... '\n lineStart = position - maxHalfLength + head.length\n }\n\n if (lineEnd - position > maxHalfLength) {\n tail = ' ...'\n lineEnd = position + maxHalfLength - tail.length\n }\n\n return {\n str: head + buffer.slice(lineStart, lineEnd).replace(/\\t/g, '→') + tail,\n pos: position - lineStart + head.length // relative position\n }\n}\n\nfunction padStart (string, max) {\n return common.repeat(' ', max - string.length) + string\n}\n\nfunction makeSnippet (mark, options) {\n options = Object.create(options || null)\n\n if (!mark.buffer) return null\n\n if (!options.maxLength) options.maxLength = 79\n if (typeof options.indent !== 'number') options.indent = 1\n if (typeof options.linesBefore !== 'number') options.linesBefore = 3\n if (typeof options.linesAfter !== 'number') options.linesAfter = 2\n\n const re = /\\r?\\n|\\r|\\0/g\n const lineStarts = [0]\n const lineEnds = []\n let match\n let foundLineNo = -1\n\n while ((match = re.exec(mark.buffer))) {\n lineEnds.push(match.index)\n lineStarts.push(match.index + match[0].length)\n\n if (mark.position <= match.index && foundLineNo < 0) {\n foundLineNo = lineStarts.length - 2\n }\n }\n\n if (foundLineNo < 0) foundLineNo = lineStarts.length - 1\n\n let result = ''\n const lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length\n const maxLineLength = options.maxLength - (options.indent + lineNoLength + 3)\n\n for (let i = 1; i <= options.linesBefore; i++) {\n if (foundLineNo - i < 0) break\n const line = getLine(\n mark.buffer,\n lineStarts[foundLineNo - i],\n lineEnds[foundLineNo - i],\n mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]),\n maxLineLength\n )\n result = common.repeat(' ', options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) +\n ' | ' + line.str + '\\n' + result\n }\n\n const line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength)\n result += common.repeat(' ', options.indent) + padStart((mark.line + 1).toString(), lineNoLength) +\n ' | ' + line.str + '\\n'\n result += common.repeat('-', options.indent + lineNoLength + 3 + line.pos) + '^' + '\\n'\n\n for (let i = 1; i <= options.linesAfter; i++) {\n if (foundLineNo + i >= lineEnds.length) break\n const line = getLine(\n mark.buffer,\n lineStarts[foundLineNo + i],\n lineEnds[foundLineNo + i],\n mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]),\n maxLineLength\n )\n result += common.repeat(' ', options.indent) + padStart((mark.line + i + 1).toString(), lineNoLength) +\n ' | ' + line.str + '\\n'\n }\n\n return result.replace(/\\n$/, '')\n}\n\nmodule.exports = makeSnippet\n","'use strict'\n\nconst YAMLException = require('./exception')\n\nconst TYPE_CONSTRUCTOR_OPTIONS = [\n 'kind',\n 'multi',\n 'resolve',\n 'construct',\n 'instanceOf',\n 'predicate',\n 'represent',\n 'representName',\n 'defaultStyle',\n 'styleAliases'\n]\n\nconst YAML_NODE_KINDS = [\n 'scalar',\n 'sequence',\n 'mapping'\n]\n\nfunction compileStyleAliases (map) {\n const result = {}\n\n if (map !== null) {\n Object.keys(map).forEach(function (style) {\n map[style].forEach(function (alias) {\n result[String(alias)] = style\n })\n })\n }\n\n return result\n}\n\nfunction Type (tag, options) {\n options = options || {}\n\n Object.keys(options).forEach(function (name) {\n if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) {\n throw new YAMLException('Unknown option \"' + name + '\" is met in definition of \"' + tag + '\" YAML type.')\n }\n })\n\n // TODO: Add tag format check.\n this.options = options // keep original options in case user wants to extend this type later\n this.tag = tag\n this.kind = options['kind'] || null\n this.resolve = options['resolve'] || function () { return true }\n this.construct = options['construct'] || function (data) { return data }\n this.instanceOf = options['instanceOf'] || null\n this.predicate = options['predicate'] || null\n this.represent = options['represent'] || null\n this.representName = options['representName'] || null\n this.defaultStyle = options['defaultStyle'] || null\n this.multi = options['multi'] || false\n this.styleAliases = compileStyleAliases(options['styleAliases'] || null)\n\n if (YAML_NODE_KINDS.indexOf(this.kind) === -1) {\n throw new YAMLException('Unknown kind \"' + this.kind + '\" is specified for \"' + tag + '\" YAML type.')\n }\n}\n\nmodule.exports = Type\n","'use strict'\n\nconst YAMLException = require('./exception')\nconst Type = require('./type')\n\nfunction compileList (schema, name) {\n const result = []\n\n schema[name].forEach(function (currentType) {\n let newIndex = result.length\n\n result.forEach(function (previousType, previousIndex) {\n if (previousType.tag === currentType.tag &&\n previousType.kind === currentType.kind &&\n previousType.multi === currentType.multi) {\n newIndex = previousIndex\n }\n })\n\n result[newIndex] = currentType\n })\n\n return result\n}\n\nfunction compileMap (/* lists... */) {\n const result = {\n scalar: {},\n sequence: {},\n mapping: {},\n fallback: {},\n multi: {\n scalar: [],\n sequence: [],\n mapping: [],\n fallback: []\n }\n }\n function collectType (type) {\n if (type.multi) {\n result.multi[type.kind].push(type)\n result.multi['fallback'].push(type)\n } else {\n result[type.kind][type.tag] = result['fallback'][type.tag] = type\n }\n }\n\n for (let index = 0, length = arguments.length; index < length; index += 1) {\n arguments[index].forEach(collectType)\n }\n return result\n}\n\nfunction Schema (definition) {\n return this.extend(definition)\n}\n\nSchema.prototype.extend = function extend (definition) {\n let implicit = []\n let explicit = []\n\n if (definition instanceof Type) {\n // Schema.extend(type)\n explicit.push(definition)\n } else if (Array.isArray(definition)) {\n // Schema.extend([ type1, type2, ... ])\n explicit = explicit.concat(definition)\n } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) {\n // Schema.extend({ explicit: [ type1, type2, ... ], implicit: [ type1, type2, ... ] })\n if (definition.implicit) implicit = implicit.concat(definition.implicit)\n if (definition.explicit) explicit = explicit.concat(definition.explicit)\n } else {\n throw new YAMLException('Schema.extend argument should be a Type, [ Type ], ' +\n 'or a schema definition ({ implicit: [...], explicit: [...] })')\n }\n\n implicit.forEach(function (type) {\n if (!(type instanceof Type)) {\n throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.')\n }\n\n if (type.loadKind && type.loadKind !== 'scalar') {\n throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.')\n }\n\n if (type.multi) {\n throw new YAMLException('There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.')\n }\n })\n\n explicit.forEach(function (type) {\n if (!(type instanceof Type)) {\n throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.')\n }\n })\n\n const result = Object.create(Schema.prototype)\n\n result.implicit = (this.implicit || []).concat(implicit)\n result.explicit = (this.explicit || []).concat(explicit)\n\n result.compiledImplicit = compileList(result, 'implicit')\n result.compiledExplicit = compileList(result, 'explicit')\n result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit)\n\n return result\n}\n\nmodule.exports = Schema\n","'use strict'\n\nconst Type = require('../type')\n\nmodule.exports = new Type('tag:yaml.org,2002:str', {\n kind: 'scalar',\n construct: function (data) { return data !== null ? data : '' }\n})\n","'use strict'\n\nconst Type = require('../type')\n\nmodule.exports = new Type('tag:yaml.org,2002:seq', {\n kind: 'sequence',\n construct: function (data) { return data !== null ? data : [] }\n})\n","'use strict'\n\nconst Type = require('../type')\n\nmodule.exports = new Type('tag:yaml.org,2002:map', {\n kind: 'mapping',\n construct: function (data) { return data !== null ? data : {} }\n})\n","// Standard YAML's Failsafe schema.\n// http://www.yaml.org/spec/1.2/spec.html#id2802346\n\n'use strict'\n\nconst Schema = require('../schema')\n\nmodule.exports = new Schema({\n explicit: [\n require('../type/str'),\n require('../type/seq'),\n require('../type/map')\n ]\n})\n","'use strict'\n\nconst Type = require('../type')\n\nfunction resolveYamlNull (data) {\n if (data === null) return true\n\n const max = data.length\n\n return (max === 1 && data === '~') ||\n (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL'))\n}\n\nfunction constructYamlNull () {\n return null\n}\n\nfunction isNull (object) {\n return object === null\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:null', {\n kind: 'scalar',\n resolve: resolveYamlNull,\n construct: constructYamlNull,\n predicate: isNull,\n represent: {\n canonical: function () { return '~' },\n lowercase: function () { return 'null' },\n uppercase: function () { return 'NULL' },\n camelcase: function () { return 'Null' },\n empty: function () { return '' }\n },\n defaultStyle: 'lowercase'\n})\n","'use strict'\n\nconst Type = require('../type')\n\nfunction resolveYamlBoolean (data) {\n if (data === null) return false\n\n const max = data.length\n\n return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) ||\n (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE'))\n}\n\nfunction constructYamlBoolean (data) {\n return data === 'true' ||\n data === 'True' ||\n data === 'TRUE'\n}\n\nfunction isBoolean (object) {\n return Object.prototype.toString.call(object) === '[object Boolean]'\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:bool', {\n kind: 'scalar',\n resolve: resolveYamlBoolean,\n construct: constructYamlBoolean,\n predicate: isBoolean,\n represent: {\n lowercase: function (object) { return object ? 'true' : 'false' },\n uppercase: function (object) { return object ? 'TRUE' : 'FALSE' },\n camelcase: function (object) { return object ? 'True' : 'False' }\n },\n defaultStyle: 'lowercase'\n})\n","'use strict'\n\nconst common = require('../common')\nconst Type = require('../type')\n\nfunction isHexCode (c) {\n return ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) ||\n ((c >= 0x41/* A */) && (c <= 0x46/* F */)) ||\n ((c >= 0x61/* a */) && (c <= 0x66/* f */))\n}\n\nfunction isOctCode (c) {\n return ((c >= 0x30/* 0 */) && (c <= 0x37/* 7 */))\n}\n\nfunction isDecCode (c) {\n return ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */))\n}\n\nfunction resolveYamlInteger (data) {\n if (data === null) return false\n\n const max = data.length\n let index = 0\n let hasDigits = false\n\n if (!max) return false\n\n let ch = data[index]\n\n // sign\n if (ch === '-' || ch === '+') {\n ch = data[++index]\n }\n\n if (ch === '0') {\n // 0\n if (index + 1 === max) return true\n ch = data[++index]\n\n // base 2, base 8, base 16\n\n if (ch === 'b') {\n // base 2\n index++\n\n for (; index < max; index++) {\n ch = data[index]\n if (ch !== '0' && ch !== '1') return false\n hasDigits = true\n }\n return hasDigits && isFinite(parseYamlInteger(data))\n }\n\n if (ch === 'x') {\n // base 16\n index++\n\n for (; index < max; index++) {\n if (!isHexCode(data.charCodeAt(index))) return false\n hasDigits = true\n }\n return hasDigits && isFinite(parseYamlInteger(data))\n }\n\n if (ch === 'o') {\n // base 8\n index++\n\n for (; index < max; index++) {\n if (!isOctCode(data.charCodeAt(index))) return false\n hasDigits = true\n }\n return hasDigits && isFinite(parseYamlInteger(data))\n }\n }\n\n // base 10 (except 0)\n\n for (; index < max; index++) {\n if (!isDecCode(data.charCodeAt(index))) {\n return false\n }\n hasDigits = true\n }\n\n if (!hasDigits) return false\n\n return isFinite(parseYamlInteger(data))\n}\n\nfunction parseYamlInteger (data) {\n let value = data\n let sign = 1\n\n let ch = value[0]\n\n if (ch === '-' || ch === '+') {\n if (ch === '-') sign = -1\n value = value.slice(1)\n ch = value[0]\n }\n\n if (value === '0') return 0\n\n if (ch === '0') {\n if (value[1] === 'b') return sign * parseInt(value.slice(2), 2)\n if (value[1] === 'x') return sign * parseInt(value.slice(2), 16)\n if (value[1] === 'o') return sign * parseInt(value.slice(2), 8)\n }\n\n return sign * parseInt(value, 10)\n}\n\nfunction constructYamlInteger (data) {\n return parseYamlInteger(data)\n}\n\nfunction isInteger (object) {\n return (Object.prototype.toString.call(object)) === '[object Number]' &&\n (object % 1 === 0 && !common.isNegativeZero(object))\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:int', {\n kind: 'scalar',\n resolve: resolveYamlInteger,\n construct: constructYamlInteger,\n predicate: isInteger,\n represent: {\n binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1) },\n octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1) },\n decimal: function (obj) { return obj.toString(10) },\n hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1) }\n },\n defaultStyle: 'decimal',\n styleAliases: {\n binary: [2, 'bin'],\n octal: [8, 'oct'],\n decimal: [10, 'dec'],\n hexadecimal: [16, 'hex']\n }\n})\n","'use strict'\n\nconst common = require('../common')\nconst Type = require('../type')\n\nconst YAML_FLOAT_PATTERN = new RegExp(\n // 2.5e4, 2.5 and integers\n '^(?:[-+]?(?:[0-9]+)(?:\\\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?' +\n // .2e4, .2\n // special case, seems not from spec\n '|\\\\.[0-9]+(?:[eE][-+]?[0-9]+)?' +\n // .inf\n '|[-+]?\\\\.(?:inf|Inf|INF)' +\n // .nan\n '|\\\\.(?:nan|NaN|NAN))$')\n\nconst YAML_FLOAT_SPECIAL_PATTERN = new RegExp(\n '^(?:' +\n // .inf\n '[-+]?\\\\.(?:inf|Inf|INF)' +\n // .nan\n '|\\\\.(?:nan|NaN|NAN))$')\n\nfunction resolveYamlFloat (data) {\n if (data === null) return false\n\n if (!YAML_FLOAT_PATTERN.test(data)) {\n return false\n }\n\n if (isFinite(parseFloat(data, 10))) {\n return true\n }\n\n return YAML_FLOAT_SPECIAL_PATTERN.test(data)\n}\n\nfunction constructYamlFloat (data) {\n let value = data.toLowerCase()\n const sign = value[0] === '-' ? -1 : 1\n\n if ('+-'.indexOf(value[0]) >= 0) {\n value = value.slice(1)\n }\n\n if (value === '.inf') {\n return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY\n } else if (value === '.nan') {\n return NaN\n }\n return sign * parseFloat(value, 10)\n}\n\nconst SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/\n\nfunction representYamlFloat (object, style) {\n if (isNaN(object)) {\n switch (style) {\n case 'lowercase': return '.nan'\n case 'uppercase': return '.NAN'\n case 'camelcase': return '.NaN'\n }\n } else if (Number.POSITIVE_INFINITY === object) {\n switch (style) {\n case 'lowercase': return '.inf'\n case 'uppercase': return '.INF'\n case 'camelcase': return '.Inf'\n }\n } else if (Number.NEGATIVE_INFINITY === object) {\n switch (style) {\n case 'lowercase': return '-.inf'\n case 'uppercase': return '-.INF'\n case 'camelcase': return '-.Inf'\n }\n } else if (common.isNegativeZero(object)) {\n return '-0.0'\n }\n\n const res = object.toString(10)\n\n // JS stringifier can build scientific format without dots: 5e-100,\n // while YAML requres dot: 5.e-100. Fix it with simple hack\n\n return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res\n}\n\nfunction isFloat (object) {\n return (Object.prototype.toString.call(object) === '[object Number]') &&\n (object % 1 !== 0 || common.isNegativeZero(object))\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:float', {\n kind: 'scalar',\n resolve: resolveYamlFloat,\n construct: constructYamlFloat,\n predicate: isFloat,\n represent: representYamlFloat,\n defaultStyle: 'lowercase'\n})\n","// Standard YAML's JSON schema.\n// http://www.yaml.org/spec/1.2/spec.html#id2803231\n//\n// NOTE: JS-YAML does not support schema-specific tag resolution restrictions.\n// So, this schema is not such strict as defined in the YAML specification.\n// It allows numbers in binary notaion, use `Null` and `NULL` as `null`, etc.\n\n'use strict'\n\nmodule.exports = require('./failsafe').extend({\n implicit: [\n require('../type/null'),\n require('../type/bool'),\n require('../type/int'),\n require('../type/float')\n ]\n})\n","// Standard YAML's Core schema.\n// http://www.yaml.org/spec/1.2/spec.html#id2804923\n//\n// NOTE: JS-YAML does not support schema-specific tag resolution restrictions.\n// So, Core schema has no distinctions from JSON schema is JS-YAML.\n\n'use strict'\n\nmodule.exports = require('./json')\n","'use strict'\n\nconst Type = require('../type')\n\nconst YAML_DATE_REGEXP = new RegExp(\n '^([0-9][0-9][0-9][0-9])' + // [1] year\n '-([0-9][0-9])' + // [2] month\n '-([0-9][0-9])$') // [3] day\n\nconst YAML_TIMESTAMP_REGEXP = new RegExp(\n '^([0-9][0-9][0-9][0-9])' + // [1] year\n '-([0-9][0-9]?)' + // [2] month\n '-([0-9][0-9]?)' + // [3] day\n '(?:[Tt]|[ \\\\t]+)' + // ...\n '([0-9][0-9]?)' + // [4] hour\n ':([0-9][0-9])' + // [5] minute\n ':([0-9][0-9])' + // [6] second\n '(?:\\\\.([0-9]*))?' + // [7] fraction\n '(?:[ \\\\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tzHour\n '(?::([0-9][0-9]))?))?$') // [11] tzMinute\n\nfunction resolveYamlTimestamp (data) {\n if (data === null) return false\n if (YAML_DATE_REGEXP.exec(data) !== null) return true\n if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true\n return false\n}\n\nfunction constructYamlTimestamp (data) {\n let fraction = 0\n let delta = null\n\n let match = YAML_DATE_REGEXP.exec(data)\n if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data)\n\n if (match === null) throw new Error('Date resolve error')\n\n // match: [1] year [2] month [3] day\n\n const year = +(match[1])\n const month = +(match[2]) - 1 // JS month starts with 0\n const day = +(match[3])\n\n if (!match[4]) { // no hour\n return new Date(Date.UTC(year, month, day))\n }\n\n // match: [4] hour [5] minute [6] second [7] fraction\n\n const hour = +(match[4])\n const minute = +(match[5])\n const second = +(match[6])\n\n if (match[7]) {\n fraction = match[7].slice(0, 3)\n while (fraction.length < 3) { // milli-seconds\n fraction += '0'\n }\n fraction = +fraction\n }\n\n // match: [8] tz [9] tz_sign [10] tzHour [11] tzMinute\n\n if (match[9]) {\n const tzHour = +(match[10])\n const tzMinute = +(match[11] || 0)\n delta = (tzHour * 60 + tzMinute) * 60000 // delta in mili-seconds\n if (match[9] === '-') delta = -delta\n }\n\n const date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction))\n\n if (delta) date.setTime(date.getTime() - delta)\n\n return date\n}\n\nfunction representYamlTimestamp (object /*, style */) {\n return object.toISOString()\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:timestamp', {\n kind: 'scalar',\n resolve: resolveYamlTimestamp,\n construct: constructYamlTimestamp,\n instanceOf: Date,\n represent: representYamlTimestamp\n})\n","'use strict'\n\nconst Type = require('../type')\n\nfunction resolveYamlMerge (data) {\n return data === '<<' || data === null\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:merge', {\n kind: 'scalar',\n resolve: resolveYamlMerge\n})\n","'use strict'\n\nconst Type = require('../type')\n\n// [ 64, 65, 66 ] -> [ padding, CR, LF ]\nconst BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\\n\\r'\n\nfunction resolveYamlBinary (data) {\n if (data === null) return false\n\n let bitlen = 0\n const max = data.length\n const map = BASE64_MAP\n\n // Convert one by one.\n for (let idx = 0; idx < max; idx++) {\n const code = map.indexOf(data.charAt(idx))\n\n // Skip CR/LF\n if (code > 64) continue\n\n // Fail on illegal characters\n if (code < 0) return false\n\n bitlen += 6\n }\n\n // If there are any bits left, source was corrupted\n return (bitlen % 8) === 0\n}\n\nfunction constructYamlBinary (data) {\n const input = data.replace(/[\\r\\n=]/g, '') // remove CR/LF & padding to simplify scan\n const max = input.length\n const map = BASE64_MAP\n let bits = 0\n const result = []\n\n // Collect by 6*4 bits (3 bytes)\n\n for (let idx = 0; idx < max; idx++) {\n if ((idx % 4 === 0) && idx) {\n result.push((bits >> 16) & 0xFF)\n result.push((bits >> 8) & 0xFF)\n result.push(bits & 0xFF)\n }\n\n bits = (bits << 6) | map.indexOf(input.charAt(idx))\n }\n\n // Dump tail\n\n const tailbits = (max % 4) * 6\n\n if (tailbits === 0) {\n result.push((bits >> 16) & 0xFF)\n result.push((bits >> 8) & 0xFF)\n result.push(bits & 0xFF)\n } else if (tailbits === 18) {\n result.push((bits >> 10) & 0xFF)\n result.push((bits >> 2) & 0xFF)\n } else if (tailbits === 12) {\n result.push((bits >> 4) & 0xFF)\n }\n\n return new Uint8Array(result)\n}\n\nfunction representYamlBinary (object /*, style */) {\n let result = ''\n let bits = 0\n const max = object.length\n const map = BASE64_MAP\n\n // Convert every three bytes to 4 ASCII characters.\n\n for (let idx = 0; idx < max; idx++) {\n if ((idx % 3 === 0) && idx) {\n result += map[(bits >> 18) & 0x3F]\n result += map[(bits >> 12) & 0x3F]\n result += map[(bits >> 6) & 0x3F]\n result += map[bits & 0x3F]\n }\n\n bits = (bits << 8) + object[idx]\n }\n\n // Dump tail\n\n const tail = max % 3\n\n if (tail === 0) {\n result += map[(bits >> 18) & 0x3F]\n result += map[(bits >> 12) & 0x3F]\n result += map[(bits >> 6) & 0x3F]\n result += map[bits & 0x3F]\n } else if (tail === 2) {\n result += map[(bits >> 10) & 0x3F]\n result += map[(bits >> 4) & 0x3F]\n result += map[(bits << 2) & 0x3F]\n result += map[64]\n } else if (tail === 1) {\n result += map[(bits >> 2) & 0x3F]\n result += map[(bits << 4) & 0x3F]\n result += map[64]\n result += map[64]\n }\n\n return result\n}\n\nfunction isBinary (obj) {\n return Object.prototype.toString.call(obj) === '[object Uint8Array]'\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:binary', {\n kind: 'scalar',\n resolve: resolveYamlBinary,\n construct: constructYamlBinary,\n predicate: isBinary,\n represent: representYamlBinary\n})\n","'use strict'\n\nconst Type = require('../type')\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\nconst _toString = Object.prototype.toString\n\nfunction resolveYamlOmap (data) {\n if (data === null) return true\n\n const objectKeys = {}\n const object = data\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n const pair = object[index]\n let pairHasKey = false\n\n if (_toString.call(pair) !== '[object Object]') return false\n\n let pairKey\n for (pairKey in pair) {\n if (_hasOwnProperty.call(pair, pairKey)) {\n if (!pairHasKey) pairHasKey = true\n else return false\n }\n }\n\n if (!pairHasKey) return false\n\n if (_hasOwnProperty.call(objectKeys, pairKey)) return false\n Object.defineProperty(objectKeys, pairKey, { value: true })\n }\n\n return true\n}\n\nfunction constructYamlOmap (data) {\n return data !== null ? data : []\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:omap', {\n kind: 'sequence',\n resolve: resolveYamlOmap,\n construct: constructYamlOmap\n})\n","'use strict'\n\nconst Type = require('../type')\n\nconst _toString = Object.prototype.toString\n\nfunction resolveYamlPairs (data) {\n if (data === null) return true\n\n const object = data\n\n const result = new Array(object.length)\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n const pair = object[index]\n\n if (_toString.call(pair) !== '[object Object]') return false\n\n const keys = Object.keys(pair)\n\n if (keys.length !== 1) return false\n\n result[index] = [keys[0], pair[keys[0]]]\n }\n\n return true\n}\n\nfunction constructYamlPairs (data) {\n if (data === null) return []\n\n const object = data\n const result = new Array(object.length)\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n const pair = object[index]\n\n const keys = Object.keys(pair)\n\n result[index] = [keys[0], pair[keys[0]]]\n }\n\n return result\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:pairs', {\n kind: 'sequence',\n resolve: resolveYamlPairs,\n construct: constructYamlPairs\n})\n","'use strict'\n\nconst Type = require('../type')\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\n\nfunction resolveYamlSet (data) {\n if (data === null) return true\n\n const object = data\n\n for (const key in object) {\n if (_hasOwnProperty.call(object, key)) {\n if (object[key] !== null) return false\n }\n }\n\n return true\n}\n\nfunction constructYamlSet (data) {\n return data !== null ? data : {}\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:set', {\n kind: 'mapping',\n resolve: resolveYamlSet,\n construct: constructYamlSet\n})\n","// JS-YAML's default schema for `safeLoad` function.\n// It is not described in the YAML specification.\n//\n// This schema is based on standard YAML's Core schema and includes most of\n// extra types described at YAML tag repository. (http://yaml.org/type/)\n\n'use strict'\n\nmodule.exports = require('./core').extend({\n implicit: [\n require('../type/timestamp'),\n require('../type/merge')\n ],\n explicit: [\n require('../type/binary'),\n require('../type/omap'),\n require('../type/pairs'),\n require('../type/set')\n ]\n})\n","'use strict'\n\nconst common = require('./common')\nconst YAMLException = require('./exception')\nconst makeSnippet = require('./snippet')\nconst DEFAULT_SCHEMA = require('./schema/default')\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\n\nconst CONTEXT_FLOW_IN = 1\nconst CONTEXT_FLOW_OUT = 2\nconst CONTEXT_BLOCK_IN = 3\nconst CONTEXT_BLOCK_OUT = 4\n\nconst CHOMPING_CLIP = 1\nconst CHOMPING_STRIP = 2\nconst CHOMPING_KEEP = 3\n\n// eslint-disable-next-line no-control-regex\nconst PATTERN_NON_PRINTABLE = /[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x84\\x86-\\x9F\\uFFFE\\uFFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/\nconst PATTERN_NON_ASCII_LINE_BREAKS = /[\\x85\\u2028\\u2029]/\n// eslint-disable-next-line no-useless-escape\nconst PATTERN_FLOW_INDICATORS = /[,\\[\\]{}]/\n// eslint-disable-next-line no-useless-escape\nconst PATTERN_TAG_HANDLE = /^(?:!|!!|![0-9A-Za-z-]+!)$/\n// eslint-disable-next-line no-useless-escape\nconst PATTERN_TAG_URI = /^(?:!|[^,\\[\\]{}])(?:%[0-9a-f]{2}|[0-9a-z\\-#;/?:@&=+$,_.!~*'()\\[\\]])*$/i\n\nfunction _class (obj) { return Object.prototype.toString.call(obj) }\n\nfunction isEol (c) {\n return (c === 0x0A/* LF */) || (c === 0x0D/* CR */)\n}\n\nfunction isWhiteSpace (c) {\n return (c === 0x09/* Tab */) || (c === 0x20/* Space */)\n}\n\nfunction isWsOrEol (c) {\n return (c === 0x09/* Tab */) ||\n (c === 0x20/* Space */) ||\n (c === 0x0A/* LF */) ||\n (c === 0x0D/* CR */)\n}\n\nfunction isFlowIndicator (c) {\n return c === 0x2C/* , */ ||\n c === 0x5B/* [ */ ||\n c === 0x5D/* ] */ ||\n c === 0x7B/* { */ ||\n c === 0x7D/* } */\n}\n\nfunction fromHexCode (c) {\n if ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) {\n return c - 0x30\n }\n\n const lc = c | 0x20\n\n if ((lc >= 0x61/* a */) && (lc <= 0x66/* f */)) {\n return lc - 0x61 + 10\n }\n\n return -1\n}\n\nfunction escapedHexLen (c) {\n if (c === 0x78/* x */) { return 2 }\n if (c === 0x75/* u */) { return 4 }\n if (c === 0x55/* U */) { return 8 }\n return 0\n}\n\nfunction fromDecimalCode (c) {\n if ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) {\n return c - 0x30\n }\n\n return -1\n}\n\nfunction simpleEscapeSequence (c) {\n switch (c) {\n case 0x30/* 0 */: return '\\x00'\n case 0x61/* a */: return '\\x07'\n case 0x62/* b */: return '\\x08'\n case 0x74/* t */: return '\\x09'\n case 0x09/* Tab */: return '\\x09'\n case 0x6E/* n */: return '\\x0A'\n case 0x76/* v */: return '\\x0B'\n case 0x66/* f */: return '\\x0C'\n case 0x72/* r */: return '\\x0D'\n case 0x65/* e */: return '\\x1B'\n case 0x20/* Space */: return ' '\n case 0x22/* \" */: return '\\x22'\n case 0x2F/* / */: return '/'\n case 0x5C/* \\ */: return '\\x5C'\n case 0x4E/* N */: return '\\x85'\n case 0x5F/* _ */: return '\\xA0'\n case 0x4C/* L */: return '\\u2028'\n case 0x50/* P */: return '\\u2029'\n default: return ''\n }\n}\n\nfunction charFromCodepoint (c) {\n if (c <= 0xFFFF) {\n return String.fromCharCode(c)\n }\n // Encode UTF-16 surrogate pair\n // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF\n return String.fromCharCode(\n ((c - 0x010000) >> 10) + 0xD800,\n ((c - 0x010000) & 0x03FF) + 0xDC00\n )\n}\n\n// set a property of a literal object, while protecting against prototype pollution,\n// see https://github.com/nodeca/js-yaml/issues/164 for more details\nfunction setProperty (object, key, value) {\n // used for this specific key only because Object.defineProperty is slow\n if (key === '__proto__') {\n Object.defineProperty(object, key, {\n configurable: true,\n enumerable: true,\n writable: true,\n value: value\n })\n } else {\n object[key] = value\n }\n}\n\nconst simpleEscapeCheck = new Array(256) // integer, for fast access\nconst simpleEscapeMap = new Array(256)\nfor (let i = 0; i < 256; i++) {\n simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0\n simpleEscapeMap[i] = simpleEscapeSequence(i)\n}\n\nfunction State (input, options) {\n this.input = input\n\n this.filename = options['filename'] || null\n this.schema = options['schema'] || DEFAULT_SCHEMA\n this.onWarning = options['onWarning'] || null\n // (Hidden) Remove? makes the loader to expect YAML 1.1 documents\n // if such documents have no explicit %YAML directive\n this.legacy = options['legacy'] || false\n\n this.json = options['json'] || false\n this.listener = options['listener'] || null\n this.maxDepth = typeof options['maxDepth'] === 'number' ? options['maxDepth'] : 100\n this.maxTotalMergeKeys = typeof options['maxTotalMergeKeys'] === 'number' ? options['maxTotalMergeKeys'] : 10000\n\n this.implicitTypes = this.schema.compiledImplicit\n this.typeMap = this.schema.compiledTypeMap\n\n this.length = input.length\n this.position = 0\n this.line = 0\n this.lineStart = 0\n this.lineIndent = 0\n this.depth = 0\n this.totalMergeKeys = 0\n\n // position of first leading tab in the current line,\n // used to make sure there are no tabs in the indentation\n this.firstTabInLine = -1\n\n this.documents = []\n this.anchorMapTransactions = []\n\n /*\n this.version;\n this.checkLineBreaks;\n this.tagMap;\n this.anchorMap;\n this.tag;\n this.anchor;\n this.kind;\n this.result; */\n}\n\nfunction generateError (state, message) {\n const mark = {\n name: state.filename,\n buffer: state.input.slice(0, -1), // omit trailing \\0\n position: state.position,\n line: state.line,\n column: state.position - state.lineStart\n }\n\n mark.snippet = makeSnippet(mark)\n\n return new YAMLException(message, mark)\n}\n\nfunction throwError (state, message) {\n throw generateError(state, message)\n}\n\nfunction throwWarning (state, message) {\n if (state.onWarning) {\n state.onWarning.call(null, generateError(state, message))\n }\n}\n\nfunction storeAnchor (state, name, value) {\n const transactions = state.anchorMapTransactions\n\n if (transactions.length !== 0) {\n const transaction = transactions[transactions.length - 1]\n\n if (!_hasOwnProperty.call(transaction, name)) {\n transaction[name] = {\n existed: _hasOwnProperty.call(state.anchorMap, name),\n value: state.anchorMap[name]\n }\n }\n }\n\n state.anchorMap[name] = value\n}\n\nfunction beginAnchorTransaction (state) {\n state.anchorMapTransactions.push(Object.create(null))\n}\n\nfunction commitAnchorTransaction (state) {\n const transaction = state.anchorMapTransactions.pop()\n const transactions = state.anchorMapTransactions\n\n if (transactions.length === 0) return\n\n const parent = transactions[transactions.length - 1]\n const names = Object.keys(transaction)\n\n for (let index = 0, length = names.length; index < length; index += 1) {\n const name = names[index]\n\n if (!_hasOwnProperty.call(parent, name)) {\n parent[name] = transaction[name]\n }\n }\n}\n\nfunction rollbackAnchorTransaction (state) {\n const transaction = state.anchorMapTransactions.pop()\n const names = Object.keys(transaction)\n\n for (let index = names.length - 1; index >= 0; index -= 1) {\n const entry = transaction[names[index]]\n\n if (entry.existed) {\n state.anchorMap[names[index]] = entry.value\n } else {\n delete state.anchorMap[names[index]]\n }\n }\n}\n\nfunction snapshotState (state) {\n return {\n position: state.position,\n line: state.line,\n lineStart: state.lineStart,\n lineIndent: state.lineIndent,\n firstTabInLine: state.firstTabInLine,\n tag: state.tag,\n anchor: state.anchor,\n kind: state.kind,\n result: state.result\n }\n}\n\nfunction restoreState (state, snapshot) {\n state.position = snapshot.position\n state.line = snapshot.line\n state.lineStart = snapshot.lineStart\n state.lineIndent = snapshot.lineIndent\n state.firstTabInLine = snapshot.firstTabInLine\n state.tag = snapshot.tag\n state.anchor = snapshot.anchor\n state.kind = snapshot.kind\n state.result = snapshot.result\n}\n\nconst directiveHandlers = {\n\n YAML: function handleYamlDirective (state, name, args) {\n if (state.version !== null) {\n throwError(state, 'duplication of %YAML directive')\n }\n\n if (args.length !== 1) {\n throwError(state, 'YAML directive accepts exactly one argument')\n }\n\n const match = /^([0-9]+)\\.([0-9]+)$/.exec(args[0])\n\n if (match === null) {\n throwError(state, 'ill-formed argument of the YAML directive')\n }\n\n const major = parseInt(match[1], 10)\n const minor = parseInt(match[2], 10)\n\n if (major !== 1) {\n throwError(state, 'unacceptable YAML version of the document')\n }\n\n state.version = args[0]\n state.checkLineBreaks = (minor < 2)\n\n if (minor !== 1 && minor !== 2) {\n throwWarning(state, 'unsupported YAML version of the document')\n }\n },\n\n TAG: function handleTagDirective (state, name, args) {\n let prefix\n\n if (args.length !== 2) {\n throwError(state, 'TAG directive accepts exactly two arguments')\n }\n\n const handle = args[0]\n prefix = args[1]\n\n if (!PATTERN_TAG_HANDLE.test(handle)) {\n throwError(state, 'ill-formed tag handle (first argument) of the TAG directive')\n }\n\n if (_hasOwnProperty.call(state.tagMap, handle)) {\n throwError(state, 'there is a previously declared suffix for \"' + handle + '\" tag handle')\n }\n\n if (!PATTERN_TAG_URI.test(prefix)) {\n throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive')\n }\n\n try {\n prefix = decodeURIComponent(prefix)\n } catch (err) {\n throwError(state, 'tag prefix is malformed: ' + prefix)\n }\n\n state.tagMap[handle] = prefix\n }\n}\n\nfunction captureSegment (state, start, end, checkJson) {\n if (start < end) {\n const _result = state.input.slice(start, end)\n\n if (checkJson) {\n for (let _position = 0, _length = _result.length; _position < _length; _position += 1) {\n const _character = _result.charCodeAt(_position)\n if (!(_character === 0x09 ||\n (_character >= 0x20 && _character <= 0x10FFFF))) {\n throwError(state, 'expected valid JSON character')\n }\n }\n } else if (PATTERN_NON_PRINTABLE.test(_result)) {\n throwError(state, 'the stream contains non-printable characters')\n }\n\n state.result += _result\n }\n}\n\nfunction mergeMappings (state, destination, source, overridableKeys) {\n if (!common.isObject(source)) {\n throwError(state, 'cannot merge mappings; the provided source object is unacceptable')\n }\n\n const sourceKeys = Object.keys(source)\n\n for (let index = 0, quantity = sourceKeys.length; index < quantity; index += 1) {\n const key = sourceKeys[index]\n\n if (state.maxTotalMergeKeys !== -1 && ++state.totalMergeKeys > state.maxTotalMergeKeys) {\n throwError(state, 'merge keys exceeded maxTotalMergeKeys (' + state.maxTotalMergeKeys + ')')\n }\n\n if (!_hasOwnProperty.call(destination, key)) {\n setProperty(destination, key, source[key])\n overridableKeys[key] = true\n }\n }\n}\n\nfunction storeMappingPair (state, _result, overridableKeys, keyTag, keyNode, valueNode,\n startLine, startLineStart, startPos) {\n // The output is a plain object here, so keys can only be strings.\n // We need to convert keyNode to a string, but doing so can hang the process\n // (deeply nested arrays that explode exponentially using aliases).\n if (Array.isArray(keyNode)) {\n keyNode = Array.prototype.slice.call(keyNode)\n\n for (let index = 0, quantity = keyNode.length; index < quantity; index += 1) {\n if (Array.isArray(keyNode[index])) {\n throwError(state, 'nested arrays are not supported inside keys')\n }\n\n if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') {\n keyNode[index] = '[object Object]'\n }\n }\n }\n\n // Avoid code execution in load() via toString property\n // (still use its own toString for arrays, timestamps,\n // and whatever user schema extensions happen to have @@toStringTag)\n if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') {\n keyNode = '[object Object]'\n }\n\n keyNode = String(keyNode)\n\n if (_result === null) {\n _result = {}\n }\n\n if (keyTag === 'tag:yaml.org,2002:merge') {\n if (Array.isArray(valueNode)) {\n for (let index = 0, quantity = valueNode.length; index < quantity; index += 1) {\n mergeMappings(state, _result, valueNode[index], overridableKeys)\n }\n } else {\n mergeMappings(state, _result, valueNode, overridableKeys)\n }\n } else {\n if (!state.json &&\n !_hasOwnProperty.call(overridableKeys, keyNode) &&\n _hasOwnProperty.call(_result, keyNode)) {\n state.line = startLine || state.line\n state.lineStart = startLineStart || state.lineStart\n state.position = startPos || state.position\n throwError(state, 'duplicated mapping key')\n }\n\n setProperty(_result, keyNode, valueNode)\n delete overridableKeys[keyNode]\n }\n\n return _result\n}\n\nfunction readLineBreak (state) {\n const ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x0A/* LF */) {\n state.position++\n } else if (ch === 0x0D/* CR */) {\n state.position++\n if (state.input.charCodeAt(state.position) === 0x0A/* LF */) {\n state.position++\n }\n } else {\n throwError(state, 'a line break is expected')\n }\n\n state.line += 1\n state.lineStart = state.position\n state.firstTabInLine = -1\n}\n\nfunction skipSeparationSpace (state, allowComments, checkIndent) {\n let lineBreaks = 0\n let ch = state.input.charCodeAt(state.position)\n\n while (ch !== 0) {\n while (isWhiteSpace(ch)) {\n if (ch === 0x09/* Tab */ && state.firstTabInLine === -1) {\n state.firstTabInLine = state.position\n }\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (allowComments && ch === 0x23/* # */) {\n do {\n ch = state.input.charCodeAt(++state.position)\n } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0)\n }\n\n if (isEol(ch)) {\n readLineBreak(state)\n\n ch = state.input.charCodeAt(state.position)\n lineBreaks++\n state.lineIndent = 0\n\n while (ch === 0x20/* Space */) {\n state.lineIndent++\n ch = state.input.charCodeAt(++state.position)\n }\n } else {\n break\n }\n }\n\n if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) {\n throwWarning(state, 'deficient indentation')\n }\n\n return lineBreaks\n}\n\nfunction testDocumentSeparator (state) {\n let _position = state.position\n let ch = state.input.charCodeAt(_position)\n\n // Condition state.position === state.lineStart is tested\n // in parent on each call, for efficiency. No needs to test here again.\n if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) &&\n ch === state.input.charCodeAt(_position + 1) &&\n ch === state.input.charCodeAt(_position + 2)) {\n _position += 3\n\n ch = state.input.charCodeAt(_position)\n\n if (ch === 0 || isWsOrEol(ch)) {\n return true\n }\n }\n\n return false\n}\n\nfunction writeFoldedLines (state, count) {\n if (count === 1) {\n state.result += ' '\n } else if (count > 1) {\n state.result += common.repeat('\\n', count - 1)\n }\n}\n\nfunction readPlainScalar (state, nodeIndent, withinFlowCollection) {\n let captureStart\n let captureEnd\n let hasPendingContent\n let _line\n let _lineStart\n let _lineIndent\n const _kind = state.kind\n const _result = state.result\n\n let ch = state.input.charCodeAt(state.position)\n\n if (isWsOrEol(ch) ||\n isFlowIndicator(ch) ||\n ch === 0x23/* # */ ||\n ch === 0x26/* & */ ||\n ch === 0x2A/* * */ ||\n ch === 0x21/* ! */ ||\n ch === 0x7C/* | */ ||\n ch === 0x3E/* > */ ||\n ch === 0x27/* ' */ ||\n ch === 0x22/* \" */ ||\n ch === 0x25/* % */ ||\n ch === 0x40/* @ */ ||\n ch === 0x60/* ` */) {\n return false\n }\n\n if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) {\n const following = state.input.charCodeAt(state.position + 1)\n\n if (isWsOrEol(following) ||\n (withinFlowCollection && isFlowIndicator(following))) {\n return false\n }\n }\n\n state.kind = 'scalar'\n state.result = ''\n captureStart = captureEnd = state.position\n hasPendingContent = false\n\n while (ch !== 0) {\n if (ch === 0x3A/* : */) {\n const following = state.input.charCodeAt(state.position + 1)\n\n if (isWsOrEol(following) ||\n (withinFlowCollection && isFlowIndicator(following))) {\n break\n }\n } else if (ch === 0x23/* # */) {\n const preceding = state.input.charCodeAt(state.position - 1)\n\n if (isWsOrEol(preceding)) {\n break\n }\n } else if ((state.position === state.lineStart && testDocumentSeparator(state)) ||\n (withinFlowCollection && isFlowIndicator(ch))) {\n break\n } else if (isEol(ch)) {\n _line = state.line\n _lineStart = state.lineStart\n _lineIndent = state.lineIndent\n skipSeparationSpace(state, false, -1)\n\n if (state.lineIndent >= nodeIndent) {\n hasPendingContent = true\n ch = state.input.charCodeAt(state.position)\n continue\n } else {\n state.position = captureEnd\n state.line = _line\n state.lineStart = _lineStart\n state.lineIndent = _lineIndent\n break\n }\n }\n\n if (hasPendingContent) {\n captureSegment(state, captureStart, captureEnd, false)\n writeFoldedLines(state, state.line - _line)\n captureStart = captureEnd = state.position\n hasPendingContent = false\n }\n\n if (!isWhiteSpace(ch)) {\n captureEnd = state.position + 1\n }\n\n ch = state.input.charCodeAt(++state.position)\n }\n\n captureSegment(state, captureStart, captureEnd, false)\n\n if (state.result) {\n return true\n }\n\n state.kind = _kind\n state.result = _result\n return false\n}\n\nfunction readSingleQuotedScalar (state, nodeIndent) {\n let captureStart\n let captureEnd\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x27/* ' */) {\n return false\n }\n\n state.kind = 'scalar'\n state.result = ''\n state.position++\n captureStart = captureEnd = state.position\n\n while ((ch = state.input.charCodeAt(state.position)) !== 0) {\n if (ch === 0x27/* ' */) {\n captureSegment(state, captureStart, state.position, true)\n ch = state.input.charCodeAt(++state.position)\n\n if (ch === 0x27/* ' */) {\n captureStart = state.position\n state.position++\n captureEnd = state.position\n } else {\n return true\n }\n } else if (isEol(ch)) {\n captureSegment(state, captureStart, captureEnd, true)\n writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent))\n captureStart = captureEnd = state.position\n } else if (state.position === state.lineStart && testDocumentSeparator(state)) {\n throwError(state, 'unexpected end of the document within a single quoted scalar')\n } else {\n state.position++\n if (!isWhiteSpace(ch)) {\n captureEnd = state.position\n }\n }\n }\n\n throwError(state, 'unexpected end of the stream within a single quoted scalar')\n}\n\nfunction readDoubleQuotedScalar (state, nodeIndent) {\n let captureStart\n let captureEnd\n let tmp\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x22/* \" */) {\n return false\n }\n\n state.kind = 'scalar'\n state.result = ''\n state.position++\n captureStart = captureEnd = state.position\n\n while ((ch = state.input.charCodeAt(state.position)) !== 0) {\n if (ch === 0x22/* \" */) {\n captureSegment(state, captureStart, state.position, true)\n state.position++\n return true\n } else if (ch === 0x5C/* \\ */) {\n captureSegment(state, captureStart, state.position, true)\n ch = state.input.charCodeAt(++state.position)\n\n if (isEol(ch)) {\n skipSeparationSpace(state, false, nodeIndent)\n\n // TODO: rework to inline fn with no type cast?\n } else if (ch < 256 && simpleEscapeCheck[ch]) {\n state.result += simpleEscapeMap[ch]\n state.position++\n } else if ((tmp = escapedHexLen(ch)) > 0) {\n let hexLength = tmp\n let hexResult = 0\n\n for (; hexLength > 0; hexLength--) {\n ch = state.input.charCodeAt(++state.position)\n\n if ((tmp = fromHexCode(ch)) >= 0) {\n hexResult = (hexResult << 4) + tmp\n } else {\n throwError(state, 'expected hexadecimal character')\n }\n }\n\n state.result += charFromCodepoint(hexResult)\n\n state.position++\n } else {\n throwError(state, 'unknown escape sequence')\n }\n\n captureStart = captureEnd = state.position\n } else if (isEol(ch)) {\n captureSegment(state, captureStart, captureEnd, true)\n writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent))\n captureStart = captureEnd = state.position\n } else if (state.position === state.lineStart && testDocumentSeparator(state)) {\n throwError(state, 'unexpected end of the document within a double quoted scalar')\n } else {\n state.position++\n if (!isWhiteSpace(ch)) {\n captureEnd = state.position\n }\n }\n }\n\n throwError(state, 'unexpected end of the stream within a double quoted scalar')\n}\n\nfunction readFlowCollection (state, nodeIndent) {\n let readNext = true\n let _line\n let _lineStart\n let _pos\n const _tag = state.tag\n let _result\n const _anchor = state.anchor\n let terminator\n let isPair\n let isExplicitPair\n let isMapping\n const overridableKeys = Object.create(null)\n let keyNode\n let keyTag\n let valueNode\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x5B/* [ */) {\n terminator = 0x5D/* ] */\n isMapping = false\n _result = []\n } else if (ch === 0x7B/* { */) {\n terminator = 0x7D/* } */\n isMapping = true\n _result = {}\n } else {\n return false\n }\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, _result)\n }\n\n ch = state.input.charCodeAt(++state.position)\n\n while (ch !== 0) {\n skipSeparationSpace(state, true, nodeIndent)\n\n ch = state.input.charCodeAt(state.position)\n\n if (ch === terminator) {\n state.position++\n state.tag = _tag\n state.anchor = _anchor\n state.kind = isMapping ? 'mapping' : 'sequence'\n state.result = _result\n return true\n } else if (!readNext) {\n throwError(state, 'missed comma between flow collection entries')\n } else if (ch === 0x2C/* , */) {\n // \"flow collection entries can never be completely empty\", as per YAML 1.2, section 7.4\n throwError(state, \"expected the node content, but found ','\")\n }\n\n keyTag = keyNode = valueNode = null\n isPair = isExplicitPair = false\n\n if (ch === 0x3F/* ? */) {\n const following = state.input.charCodeAt(state.position + 1)\n\n if (isWsOrEol(following)) {\n isPair = isExplicitPair = true\n state.position++\n skipSeparationSpace(state, true, nodeIndent)\n }\n }\n\n _line = state.line // Save the current line.\n _lineStart = state.lineStart\n _pos = state.position\n composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true)\n keyTag = state.tag\n keyNode = state.result\n skipSeparationSpace(state, true, nodeIndent)\n\n ch = state.input.charCodeAt(state.position)\n\n if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) {\n isPair = true\n ch = state.input.charCodeAt(++state.position)\n skipSeparationSpace(state, true, nodeIndent)\n composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true)\n valueNode = state.result\n }\n\n if (isMapping) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)\n } else if (isPair) {\n _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos))\n } else {\n _result.push(keyNode)\n }\n\n skipSeparationSpace(state, true, nodeIndent)\n\n ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x2C/* , */) {\n readNext = true\n ch = state.input.charCodeAt(++state.position)\n } else {\n readNext = false\n }\n }\n\n throwError(state, 'unexpected end of the stream within a flow collection')\n}\n\nfunction readBlockScalar (state, nodeIndent) {\n let folding\n let chomping = CHOMPING_CLIP\n let didReadContent = false\n let detectedIndent = false\n let textIndent = nodeIndent\n let emptyLines = 0\n let atMoreIndented = false\n let tmp\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x7C/* | */) {\n folding = false\n } else if (ch === 0x3E/* > */) {\n folding = true\n } else {\n return false\n }\n\n state.kind = 'scalar'\n state.result = ''\n\n while (ch !== 0) {\n ch = state.input.charCodeAt(++state.position)\n\n if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {\n if (CHOMPING_CLIP === chomping) {\n chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP\n } else {\n throwError(state, 'repeat of a chomping mode identifier')\n }\n } else if ((tmp = fromDecimalCode(ch)) >= 0) {\n if (tmp === 0) {\n throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one')\n } else if (!detectedIndent) {\n textIndent = nodeIndent + tmp - 1\n detectedIndent = true\n } else {\n throwError(state, 'repeat of an indentation width identifier')\n }\n } else {\n break\n }\n }\n\n if (isWhiteSpace(ch)) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (isWhiteSpace(ch))\n\n if (ch === 0x23/* # */) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (!isEol(ch) && (ch !== 0))\n }\n }\n\n while (ch !== 0) {\n readLineBreak(state)\n state.lineIndent = 0\n\n ch = state.input.charCodeAt(state.position)\n\n // eslint-disable-next-line no-unmodified-loop-condition\n while ((!detectedIndent || state.lineIndent < textIndent) &&\n (ch === 0x20/* Space */)) {\n state.lineIndent++\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (!detectedIndent && state.lineIndent > textIndent) {\n textIndent = state.lineIndent\n }\n\n if (isEol(ch)) {\n emptyLines++\n continue\n }\n\n if (!detectedIndent && textIndent === 0) {\n throwError(state, 'missing indentation for block scalar')\n }\n\n // End of the scalar.\n if (state.lineIndent < textIndent) {\n // Perform the chomping.\n if (chomping === CHOMPING_KEEP) {\n state.result += common.repeat('\\n', didReadContent ? 1 + emptyLines : emptyLines)\n } else if (chomping === CHOMPING_CLIP) {\n if (didReadContent) { // i.e. only if the scalar is not empty.\n state.result += '\\n'\n }\n }\n\n // Break this `while` cycle and go to the funciton's epilogue.\n break\n }\n\n // Folded style: use fancy rules to handle line breaks.\n if (folding) {\n // Lines starting with white space characters (more-indented lines) are not folded.\n if (isWhiteSpace(ch)) {\n atMoreIndented = true\n // except for the first content line (cf. Example 8.1)\n state.result += common.repeat('\\n', didReadContent ? 1 + emptyLines : emptyLines)\n\n // End of more-indented block.\n } else if (atMoreIndented) {\n atMoreIndented = false\n state.result += common.repeat('\\n', emptyLines + 1)\n\n // Just one line break - perceive as the same line.\n } else if (emptyLines === 0) {\n if (didReadContent) { // i.e. only if we have already read some scalar content.\n state.result += ' '\n }\n\n // Several line breaks - perceive as different lines.\n } else {\n state.result += common.repeat('\\n', emptyLines)\n }\n\n // Literal style: just add exact number of line breaks between content lines.\n } else {\n // Keep all line breaks except the header line break.\n state.result += common.repeat('\\n', didReadContent ? 1 + emptyLines : emptyLines)\n }\n\n didReadContent = true\n detectedIndent = true\n emptyLines = 0\n const captureStart = state.position\n\n while (!isEol(ch) && (ch !== 0)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n captureSegment(state, captureStart, state.position, false)\n }\n\n return true\n}\n\nfunction readBlockSequence (state, nodeIndent) {\n const _tag = state.tag\n const _anchor = state.anchor\n const _result = []\n let detected = false\n\n // there is a leading tab before this token, so it can't be a block sequence/mapping;\n // it can still be flow sequence/mapping or a scalar\n if (state.firstTabInLine !== -1) return false\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, _result)\n }\n\n let ch = state.input.charCodeAt(state.position)\n\n while (ch !== 0) {\n if (state.firstTabInLine !== -1) {\n state.position = state.firstTabInLine\n throwError(state, 'tab characters must not be used in indentation')\n }\n\n if (ch !== 0x2D/* - */) {\n break\n }\n\n const following = state.input.charCodeAt(state.position + 1)\n\n if (!isWsOrEol(following)) {\n break\n }\n\n detected = true\n state.position++\n\n if (skipSeparationSpace(state, true, -1)) {\n if (state.lineIndent <= nodeIndent) {\n _result.push(null)\n ch = state.input.charCodeAt(state.position)\n continue\n }\n }\n\n const _line = state.line\n composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true)\n _result.push(state.result)\n skipSeparationSpace(state, true, -1)\n\n ch = state.input.charCodeAt(state.position)\n\n if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) {\n throwError(state, 'bad indentation of a sequence entry')\n } else if (state.lineIndent < nodeIndent) {\n break\n }\n }\n\n if (detected) {\n state.tag = _tag\n state.anchor = _anchor\n state.kind = 'sequence'\n state.result = _result\n return true\n }\n return false\n}\n\nfunction readBlockMapping (state, nodeIndent, flowIndent) {\n let allowCompact\n let _keyLine\n let _keyLineStart\n let _keyPos\n const _tag = state.tag\n const _anchor = state.anchor\n const _result = {}\n const overridableKeys = Object.create(null)\n let keyTag = null\n let keyNode = null\n let valueNode = null\n let atExplicitKey = false\n let detected = false\n\n // there is a leading tab before this token, so it can't be a block sequence/mapping;\n // it can still be flow sequence/mapping or a scalar\n if (state.firstTabInLine !== -1) return false\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, _result)\n }\n\n let ch = state.input.charCodeAt(state.position)\n\n while (ch !== 0) {\n if (!atExplicitKey && state.firstTabInLine !== -1) {\n state.position = state.firstTabInLine\n throwError(state, 'tab characters must not be used in indentation')\n }\n\n const following = state.input.charCodeAt(state.position + 1)\n const _line = state.line // Save the current line.\n\n //\n // Explicit notation case. There are two separate blocks:\n // first for the key (denoted by \"?\") and second for the value (denoted by \":\")\n //\n if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && isWsOrEol(following)) {\n if (ch === 0x3F/* ? */) {\n if (atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos)\n keyTag = keyNode = valueNode = null\n }\n\n detected = true\n atExplicitKey = true\n allowCompact = true\n } else if (atExplicitKey) {\n // i.e. 0x3A/* : */ === character after the explicit key.\n atExplicitKey = false\n allowCompact = true\n } else {\n throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line')\n }\n\n state.position += 1\n ch = following\n\n //\n // Implicit notation case. Flow-style node as the key first, then \":\", and the value.\n //\n } else {\n _keyLine = state.line\n _keyLineStart = state.lineStart\n _keyPos = state.position\n\n if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) {\n // Neither implicit nor explicit notation.\n // Reading is done. Go to the epilogue.\n break\n }\n\n if (state.line === _line) {\n ch = state.input.charCodeAt(state.position)\n\n while (isWhiteSpace(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (ch === 0x3A/* : */) {\n ch = state.input.charCodeAt(++state.position)\n\n if (!isWsOrEol(ch)) {\n throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping')\n }\n\n if (atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos)\n keyTag = keyNode = valueNode = null\n }\n\n detected = true\n atExplicitKey = false\n allowCompact = false\n keyTag = state.tag\n keyNode = state.result\n } else if (detected) {\n throwError(state, 'can not read an implicit mapping pair; a colon is missed')\n } else {\n state.tag = _tag\n state.anchor = _anchor\n return true // Keep the result of `composeNode`.\n }\n } else if (detected) {\n throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key')\n } else {\n state.tag = _tag\n state.anchor = _anchor\n return true // Keep the result of `composeNode`.\n }\n }\n\n //\n // Common reading code for both explicit and implicit notations.\n //\n if (state.line === _line || state.lineIndent > nodeIndent) {\n if (atExplicitKey) {\n _keyLine = state.line\n _keyLineStart = state.lineStart\n _keyPos = state.position\n }\n\n if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) {\n if (atExplicitKey) {\n keyNode = state.result\n } else {\n valueNode = state.result\n }\n }\n\n if (!atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos)\n keyTag = keyNode = valueNode = null\n }\n\n skipSeparationSpace(state, true, -1)\n ch = state.input.charCodeAt(state.position)\n }\n\n if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) {\n throwError(state, 'bad indentation of a mapping entry')\n } else if (state.lineIndent < nodeIndent) {\n break\n }\n }\n\n //\n // Epilogue.\n //\n\n // Special case: last mapping's node contains only the key in explicit notation.\n if (atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos)\n }\n\n // Expose the resulting mapping.\n if (detected) {\n state.tag = _tag\n state.anchor = _anchor\n state.kind = 'mapping'\n state.result = _result\n }\n\n return detected\n}\n\nfunction readTagProperty (state) {\n let isVerbatim = false\n let isNamed = false\n let tagHandle\n let tagName\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x21/* ! */) return false\n\n if (state.tag !== null) {\n throwError(state, 'duplication of a tag property')\n }\n\n ch = state.input.charCodeAt(++state.position)\n\n if (ch === 0x3C/* < */) {\n isVerbatim = true\n ch = state.input.charCodeAt(++state.position)\n } else if (ch === 0x21/* ! */) {\n isNamed = true\n tagHandle = '!!'\n ch = state.input.charCodeAt(++state.position)\n } else {\n tagHandle = '!'\n }\n\n let _position = state.position\n\n if (isVerbatim) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (ch !== 0 && ch !== 0x3E/* > */)\n\n if (state.position < state.length) {\n tagName = state.input.slice(_position, state.position)\n ch = state.input.charCodeAt(++state.position)\n } else {\n throwError(state, 'unexpected end of the stream within a verbatim tag')\n }\n } else {\n while (ch !== 0 && !isWsOrEol(ch)) {\n if (ch === 0x21/* ! */) {\n if (!isNamed) {\n tagHandle = state.input.slice(_position - 1, state.position + 1)\n\n if (!PATTERN_TAG_HANDLE.test(tagHandle)) {\n throwError(state, 'named tag handle cannot contain such characters')\n }\n\n isNamed = true\n _position = state.position + 1\n } else {\n throwError(state, 'tag suffix cannot contain exclamation marks')\n }\n }\n\n ch = state.input.charCodeAt(++state.position)\n }\n\n tagName = state.input.slice(_position, state.position)\n\n if (PATTERN_FLOW_INDICATORS.test(tagName)) {\n throwError(state, 'tag suffix cannot contain flow indicator characters')\n }\n }\n\n if (tagName && !PATTERN_TAG_URI.test(tagName)) {\n throwError(state, 'tag name cannot contain such characters: ' + tagName)\n }\n\n try {\n tagName = decodeURIComponent(tagName)\n } catch (err) {\n throwError(state, 'tag name is malformed: ' + tagName)\n }\n\n if (isVerbatim) {\n state.tag = tagName\n } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) {\n state.tag = state.tagMap[tagHandle] + tagName\n } else if (tagHandle === '!') {\n state.tag = '!' + tagName\n } else if (tagHandle === '!!') {\n state.tag = 'tag:yaml.org,2002:' + tagName\n } else {\n throwError(state, 'undeclared tag handle \"' + tagHandle + '\"')\n }\n\n return true\n}\n\nfunction readAnchorProperty (state) {\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x26/* & */) return false\n\n if (state.anchor !== null) {\n throwError(state, 'duplication of an anchor property')\n }\n\n ch = state.input.charCodeAt(++state.position)\n const _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (state.position === _position) {\n throwError(state, 'name of an anchor node must contain at least one character')\n }\n\n state.anchor = state.input.slice(_position, state.position)\n return true\n}\n\nfunction readAlias (state) {\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x2A/* * */) return false\n\n ch = state.input.charCodeAt(++state.position)\n const _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (state.position === _position) {\n throwError(state, 'name of an alias node must contain at least one character')\n }\n\n const alias = state.input.slice(_position, state.position)\n\n if (!_hasOwnProperty.call(state.anchorMap, alias)) {\n throwError(state, 'unidentified alias \"' + alias + '\"')\n }\n\n state.result = state.anchorMap[alias]\n skipSeparationSpace(state, true, -1)\n return true\n}\n\nfunction tryReadBlockMappingFromProperty (state, propertyStart, nodeIndent, flowIndent) {\n const fallbackState = snapshotState(state)\n\n beginAnchorTransaction(state)\n restoreState(state, propertyStart)\n\n // Re-read the leading properties as part of the first implicit key, not as\n // properties of the current node.\n state.tag = null\n state.anchor = null\n state.kind = null\n state.result = null\n\n if (readBlockMapping(state, nodeIndent, flowIndent) && state.kind === 'mapping') {\n commitAnchorTransaction(state)\n return true\n }\n\n rollbackAnchorTransaction(state)\n restoreState(state, fallbackState)\n return false\n}\n\nfunction composeNode (state, parentIndent, nodeContext, allowToSeek, allowCompact) {\n let allowBlockScalars\n let allowBlockCollections\n let indentStatus = 1 // 1: this>parent, 0: this=parent, -1: this= state.maxDepth) {\n throwError(state, 'nesting exceeded maxDepth (' + state.maxDepth + ')')\n }\n\n state.depth += 1\n\n if (state.listener !== null) {\n state.listener('open', state)\n }\n\n state.tag = null\n state.anchor = null\n state.kind = null\n state.result = null\n\n const allowBlockStyles = allowBlockScalars = allowBlockCollections =\n CONTEXT_BLOCK_OUT === nodeContext ||\n CONTEXT_BLOCK_IN === nodeContext\n\n if (allowToSeek) {\n if (skipSeparationSpace(state, true, -1)) {\n atNewLine = true\n\n if (state.lineIndent > parentIndent) {\n indentStatus = 1\n } else if (state.lineIndent === parentIndent) {\n indentStatus = 0\n } else if (state.lineIndent < parentIndent) {\n indentStatus = -1\n }\n }\n }\n\n if (indentStatus === 1) {\n while (true) {\n const ch = state.input.charCodeAt(state.position)\n const propertyState = snapshotState(state)\n\n // A duplicate property token after a line break can be the first key of\n // a nested block mapping, e.g. `!!map\\n !!str key: value`.\n if (atNewLine &&\n ((ch === 0x21/* ! */ && state.tag !== null) ||\n (ch === 0x26/* & */ && state.anchor !== null))) {\n break\n }\n\n if (!readTagProperty(state) && !readAnchorProperty(state)) {\n break\n }\n\n if (propertyStart === null) {\n propertyStart = propertyState\n }\n\n if (skipSeparationSpace(state, true, -1)) {\n atNewLine = true\n allowBlockCollections = allowBlockStyles\n\n if (state.lineIndent > parentIndent) {\n indentStatus = 1\n } else if (state.lineIndent === parentIndent) {\n indentStatus = 0\n } else if (state.lineIndent < parentIndent) {\n indentStatus = -1\n }\n } else {\n allowBlockCollections = false\n }\n }\n }\n\n if (allowBlockCollections) {\n allowBlockCollections = atNewLine || allowCompact\n }\n\n if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) {\n if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) {\n flowIndent = parentIndent\n } else {\n flowIndent = parentIndent + 1\n }\n\n blockIndent = state.position - state.lineStart\n\n if (indentStatus === 1) {\n if ((allowBlockCollections &&\n (readBlockSequence(state, blockIndent) || readBlockMapping(state, blockIndent, flowIndent))) ||\n readFlowCollection(state, flowIndent)) {\n hasContent = true\n } else {\n const ch = state.input.charCodeAt(state.position)\n\n if (propertyStart !== null && allowBlockStyles && !allowBlockCollections &&\n ch !== 0x7C/* | */ && ch !== 0x3E/* > */ &&\n tryReadBlockMappingFromProperty(\n state,\n propertyStart,\n propertyStart.position - propertyStart.lineStart,\n flowIndent\n )) {\n hasContent = true\n } else if ((allowBlockScalars && readBlockScalar(state, flowIndent)) ||\n readSingleQuotedScalar(state, flowIndent) ||\n readDoubleQuotedScalar(state, flowIndent)) {\n hasContent = true\n } else if (readAlias(state)) {\n hasContent = true\n\n if (state.tag !== null || state.anchor !== null) {\n throwError(state, 'alias node should not have any properties')\n }\n } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) {\n hasContent = true\n\n if (state.tag === null) {\n state.tag = '?'\n }\n }\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n }\n } else if (indentStatus === 0) {\n // Special case: block sequences are allowed to have same indentation level as the parent.\n // http://www.yaml.org/spec/1.2/spec.html#id2799784\n hasContent = allowBlockCollections && readBlockSequence(state, blockIndent)\n }\n }\n\n if (state.tag === null) {\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n } else if (state.tag === '?') {\n // Implicit resolving is not allowed for non-scalar types, and '?'\n // non-specific tag is only automatically assigned to plain scalars.\n //\n // We only need to check kind conformity in case user explicitly assigns '?'\n // tag, for example like this: \"! [0]\"\n //\n if (state.result !== null && state.kind !== 'scalar') {\n throwError(state, 'unacceptable node kind for ! tag; it should be \"scalar\", not \"' + state.kind + '\"')\n }\n\n for (let typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) {\n type = state.implicitTypes[typeIndex]\n\n if (type.resolve(state.result)) { // `state.result` updated in resolver if matched\n state.result = type.construct(state.result)\n state.tag = type.tag\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n break\n }\n }\n } else if (state.tag !== '!') {\n if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) {\n type = state.typeMap[state.kind || 'fallback'][state.tag]\n } else {\n // looking for multi type\n type = null\n const typeList = state.typeMap.multi[state.kind || 'fallback']\n\n for (let typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) {\n if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) {\n type = typeList[typeIndex]\n break\n }\n }\n }\n\n if (!type) {\n throwError(state, 'unknown tag !<' + state.tag + '>')\n }\n\n if (state.result !== null && type.kind !== state.kind) {\n throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be \"' + type.kind + '\", not \"' + state.kind + '\"')\n }\n\n if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched\n throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag')\n } else {\n state.result = type.construct(state.result, state.tag)\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n }\n }\n\n if (state.listener !== null) {\n state.listener('close', state)\n }\n\n state.depth -= 1\n return state.tag !== null || state.anchor !== null || hasContent\n}\n\nfunction readDocument (state) {\n const documentStart = state.position\n let hasDirectives = false\n let ch\n\n state.version = null\n state.checkLineBreaks = state.legacy\n state.tagMap = Object.create(null)\n state.anchorMap = Object.create(null)\n\n while ((ch = state.input.charCodeAt(state.position)) !== 0) {\n skipSeparationSpace(state, true, -1)\n\n ch = state.input.charCodeAt(state.position)\n\n if (state.lineIndent > 0 || ch !== 0x25/* % */) {\n break\n }\n\n hasDirectives = true\n ch = state.input.charCodeAt(++state.position)\n let _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n const directiveName = state.input.slice(_position, state.position)\n const directiveArgs = []\n\n if (directiveName.length < 1) {\n throwError(state, 'directive name must not be less than one character in length')\n }\n\n while (ch !== 0) {\n while (isWhiteSpace(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (ch === 0x23/* # */) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (ch !== 0 && !isEol(ch))\n break\n }\n\n if (isEol(ch)) break\n\n _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n directiveArgs.push(state.input.slice(_position, state.position))\n }\n\n if (ch !== 0) readLineBreak(state)\n\n if (_hasOwnProperty.call(directiveHandlers, directiveName)) {\n directiveHandlers[directiveName](state, directiveName, directiveArgs)\n } else {\n throwWarning(state, 'unknown document directive \"' + directiveName + '\"')\n }\n }\n\n skipSeparationSpace(state, true, -1)\n\n if (state.lineIndent === 0 &&\n state.input.charCodeAt(state.position) === 0x2D/* - */ &&\n state.input.charCodeAt(state.position + 1) === 0x2D/* - */ &&\n state.input.charCodeAt(state.position + 2) === 0x2D/* - */) {\n state.position += 3\n skipSeparationSpace(state, true, -1)\n } else if (hasDirectives) {\n throwError(state, 'directives end mark is expected')\n }\n\n composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true)\n skipSeparationSpace(state, true, -1)\n\n if (state.checkLineBreaks &&\n PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) {\n throwWarning(state, 'non-ASCII line breaks are interpreted as content')\n }\n\n state.documents.push(state.result)\n\n if (state.position === state.lineStart && testDocumentSeparator(state)) {\n if (state.input.charCodeAt(state.position) === 0x2E/* . */) {\n state.position += 3\n skipSeparationSpace(state, true, -1)\n }\n return\n }\n\n if (state.position < (state.length - 1)) {\n throwError(state, 'end of the stream or a document separator is expected')\n }\n}\n\nfunction loadDocuments (input, options) {\n input = String(input)\n options = options || {}\n\n if (input.length !== 0) {\n // Add tailing `\\n` if not exists\n if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ &&\n input.charCodeAt(input.length - 1) !== 0x0D/* CR */) {\n input += '\\n'\n }\n\n // Strip BOM\n if (input.charCodeAt(0) === 0xFEFF) {\n input = input.slice(1)\n }\n }\n\n const state = new State(input, options)\n\n const nullpos = input.indexOf('\\0')\n\n if (nullpos !== -1) {\n state.position = nullpos\n throwError(state, 'null byte is not allowed in input')\n }\n\n // Use 0 as string terminator. That significantly simplifies bounds check.\n state.input += '\\0'\n\n while (state.input.charCodeAt(state.position) === 0x20/* Space */) {\n state.lineIndent += 1\n state.position += 1\n }\n\n while (state.position < (state.length - 1)) {\n readDocument(state)\n }\n\n return state.documents\n}\n\nfunction loadAll (input, iterator, options) {\n if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') {\n options = iterator\n iterator = null\n }\n\n const documents = loadDocuments(input, options)\n\n if (typeof iterator !== 'function') {\n return documents\n }\n\n for (let index = 0, length = documents.length; index < length; index += 1) {\n iterator(documents[index])\n }\n}\n\nfunction load (input, options) {\n const documents = loadDocuments(input, options)\n\n if (documents.length === 0) {\n return undefined\n } else if (documents.length === 1) {\n return documents[0]\n }\n throw new YAMLException('expected a single document in the stream, but found more')\n}\n\nmodule.exports.loadAll = loadAll\nmodule.exports.load = load\n","'use strict'\n\nconst common = require('./common')\nconst YAMLException = require('./exception')\nconst DEFAULT_SCHEMA = require('./schema/default')\n\nconst _toString = Object.prototype.toString\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\n\nconst CHAR_BOM = 0xFEFF\nconst CHAR_TAB = 0x09 /* Tab */\nconst CHAR_LINE_FEED = 0x0A /* LF */\nconst CHAR_CARRIAGE_RETURN = 0x0D /* CR */\nconst CHAR_SPACE = 0x20 /* Space */\nconst CHAR_EXCLAMATION = 0x21 /* ! */\nconst CHAR_DOUBLE_QUOTE = 0x22 /* \" */\nconst CHAR_SHARP = 0x23 /* # */\nconst CHAR_PERCENT = 0x25 /* % */\nconst CHAR_AMPERSAND = 0x26 /* & */\nconst CHAR_SINGLE_QUOTE = 0x27 /* ' */\nconst CHAR_ASTERISK = 0x2A /* * */\nconst CHAR_COMMA = 0x2C /* , */\nconst CHAR_MINUS = 0x2D /* - */\nconst CHAR_COLON = 0x3A /* : */\nconst CHAR_EQUALS = 0x3D /* = */\nconst CHAR_GREATER_THAN = 0x3E /* > */\nconst CHAR_QUESTION = 0x3F /* ? */\nconst CHAR_COMMERCIAL_AT = 0x40 /* @ */\nconst CHAR_LEFT_SQUARE_BRACKET = 0x5B /* [ */\nconst CHAR_RIGHT_SQUARE_BRACKET = 0x5D /* ] */\nconst CHAR_GRAVE_ACCENT = 0x60 /* ` */\nconst CHAR_LEFT_CURLY_BRACKET = 0x7B /* { */\nconst CHAR_VERTICAL_LINE = 0x7C /* | */\nconst CHAR_RIGHT_CURLY_BRACKET = 0x7D /* } */\n\nconst ESCAPE_SEQUENCES = {}\n\nESCAPE_SEQUENCES[0x00] = '\\\\0'\nESCAPE_SEQUENCES[0x07] = '\\\\a'\nESCAPE_SEQUENCES[0x08] = '\\\\b'\nESCAPE_SEQUENCES[0x09] = '\\\\t'\nESCAPE_SEQUENCES[0x0A] = '\\\\n'\nESCAPE_SEQUENCES[0x0B] = '\\\\v'\nESCAPE_SEQUENCES[0x0C] = '\\\\f'\nESCAPE_SEQUENCES[0x0D] = '\\\\r'\nESCAPE_SEQUENCES[0x1B] = '\\\\e'\nESCAPE_SEQUENCES[0x22] = '\\\\\"'\nESCAPE_SEQUENCES[0x5C] = '\\\\\\\\'\nESCAPE_SEQUENCES[0x85] = '\\\\N'\nESCAPE_SEQUENCES[0xA0] = '\\\\_'\nESCAPE_SEQUENCES[0x2028] = '\\\\L'\nESCAPE_SEQUENCES[0x2029] = '\\\\P'\n\nconst DEPRECATED_BOOLEANS_SYNTAX = [\n 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON',\n 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF'\n]\n\nconst DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\\.[0-9_]*)?$/\n\nfunction compileStyleMap (schema, map) {\n if (map === null) return {}\n\n const result = {}\n const keys = Object.keys(map)\n\n for (let index = 0, length = keys.length; index < length; index += 1) {\n let tag = keys[index]\n let style = String(map[tag])\n\n if (tag.slice(0, 2) === '!!') {\n tag = 'tag:yaml.org,2002:' + tag.slice(2)\n }\n const type = schema.compiledTypeMap['fallback'][tag]\n\n if (type && _hasOwnProperty.call(type.styleAliases, style)) {\n style = type.styleAliases[style]\n }\n\n result[tag] = style\n }\n\n return result\n}\n\nfunction encodeHex (character) {\n let handle\n let length\n\n const string = character.toString(16).toUpperCase()\n\n if (character <= 0xFF) {\n handle = 'x'\n length = 2\n } else if (character <= 0xFFFF) {\n handle = 'u'\n length = 4\n } else if (character <= 0xFFFFFFFF) {\n handle = 'U'\n length = 8\n } else {\n throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF')\n }\n\n return '\\\\' + handle + common.repeat('0', length - string.length) + string\n}\n\nconst QUOTING_TYPE_SINGLE = 1\nconst QUOTING_TYPE_DOUBLE = 2\n\nfunction State (options) {\n this.schema = options['schema'] || DEFAULT_SCHEMA\n this.indent = Math.max(1, (options['indent'] || 2))\n this.noArrayIndent = options['noArrayIndent'] || false\n this.skipInvalid = options['skipInvalid'] || false\n this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel'])\n this.styleMap = compileStyleMap(this.schema, options['styles'] || null)\n this.sortKeys = options['sortKeys'] || false\n this.lineWidth = options['lineWidth'] || 80\n this.noRefs = options['noRefs'] || false\n this.noCompatMode = options['noCompatMode'] || false\n this.condenseFlow = options['condenseFlow'] || false\n this.quotingType = options['quotingType'] === '\"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE\n this.forceQuotes = options['forceQuotes'] || false\n this.replacer = typeof options['replacer'] === 'function' ? options['replacer'] : null\n\n this.implicitTypes = this.schema.compiledImplicit\n this.explicitTypes = this.schema.compiledExplicit\n\n this.tag = null\n this.result = ''\n\n this.duplicates = []\n this.usedDuplicates = null\n}\n\n// Indents every line in a string. Empty lines (\\n only) are not indented.\nfunction indentString (string, spaces) {\n const ind = common.repeat(' ', spaces)\n let position = 0\n let result = ''\n const length = string.length\n\n while (position < length) {\n let line\n const next = string.indexOf('\\n', position)\n if (next === -1) {\n line = string.slice(position)\n position = length\n } else {\n line = string.slice(position, next + 1)\n position = next + 1\n }\n\n if (line.length && line !== '\\n') result += ind\n\n result += line\n }\n\n return result\n}\n\nfunction generateNextLine (state, level) {\n return '\\n' + common.repeat(' ', state.indent * level)\n}\n\nfunction testImplicitResolving (state, str) {\n for (let index = 0, length = state.implicitTypes.length; index < length; index += 1) {\n const type = state.implicitTypes[index]\n\n if (type.resolve(str)) {\n return true\n }\n }\n\n return false\n}\n\n// [33] s-white ::= s-space | s-tab\nfunction isWhitespace (c) {\n return c === CHAR_SPACE || c === CHAR_TAB\n}\n\n// Returns true if the character can be printed without escaping.\n// From YAML 1.2: \"any allowed characters known to be non-printable\n// should also be escaped. [However,] This isn’t mandatory\"\n// Derived from nb-char - \\t - #x85 - #xA0 - #x2028 - #x2029.\nfunction isPrintable (c) {\n return (c >= 0x00020 && c <= 0x00007E) ||\n ((c >= 0x000A1 && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) ||\n ((c >= 0x0E000 && c <= 0x00FFFD) && c !== CHAR_BOM) ||\n (c >= 0x10000 && c <= 0x10FFFF)\n}\n\n// [34] ns-char ::= nb-char - s-white\n// [27] nb-char ::= c-printable - b-char - c-byte-order-mark\n// [26] b-char ::= b-line-feed | b-carriage-return\n// Including s-white (for some reason, examples doesn't match specs in this aspect)\n// ns-char ::= c-printable - b-line-feed - b-carriage-return - c-byte-order-mark\nfunction isNsCharOrWhitespace (c) {\n return isPrintable(c) &&\n c !== CHAR_BOM &&\n // - b-char\n c !== CHAR_CARRIAGE_RETURN &&\n c !== CHAR_LINE_FEED\n}\n\n// [127] ns-plain-safe(c) ::= c = flow-out ⇒ ns-plain-safe-out\n// c = flow-in ⇒ ns-plain-safe-in\n// c = block-key ⇒ ns-plain-safe-out\n// c = flow-key ⇒ ns-plain-safe-in\n// [128] ns-plain-safe-out ::= ns-char\n// [129] ns-plain-safe-in ::= ns-char - c-flow-indicator\n// [130] ns-plain-char(c) ::= ( ns-plain-safe(c) - “:” - “#” )\n// | ( /* An ns-char preceding */ “#” )\n// | ( “:” /* Followed by an ns-plain-safe(c) */ )\nfunction isPlainSafe (c, prev, inblock) {\n const cIsNsCharOrWhitespace = isNsCharOrWhitespace(c)\n const cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c)\n return (\n (\n // ns-plain-safe\n inblock // c = flow-in\n ? cIsNsCharOrWhitespace\n : cIsNsCharOrWhitespace &&\n // - c-flow-indicator\n c !== CHAR_COMMA &&\n c !== CHAR_LEFT_SQUARE_BRACKET &&\n c !== CHAR_RIGHT_SQUARE_BRACKET &&\n c !== CHAR_LEFT_CURLY_BRACKET &&\n c !== CHAR_RIGHT_CURLY_BRACKET\n ) &&\n // ns-plain-char\n c !== CHAR_SHARP && // false on '#'\n !(prev === CHAR_COLON && !cIsNsChar)\n ) || // false on ': '\n (isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP) || // change to true on '[^ ]#'\n (prev === CHAR_COLON && cIsNsChar) // change to true on ':[^ ]'\n}\n\n// Simplified test for values allowed as the first character in plain style.\nfunction isPlainSafeFirst (c) {\n // Uses a subset of ns-char - c-indicator\n // where ns-char = nb-char - s-white.\n // No support of ( ( “?” | “:” | “-” ) /* Followed by an ns-plain-safe(c)) */ ) part\n return isPrintable(c) &&\n c !== CHAR_BOM &&\n !isWhitespace(c) && // - s-white\n // - (c-indicator ::=\n // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}”\n c !== CHAR_MINUS &&\n c !== CHAR_QUESTION &&\n c !== CHAR_COLON &&\n c !== CHAR_COMMA &&\n c !== CHAR_LEFT_SQUARE_BRACKET &&\n c !== CHAR_RIGHT_SQUARE_BRACKET &&\n c !== CHAR_LEFT_CURLY_BRACKET &&\n c !== CHAR_RIGHT_CURLY_BRACKET &&\n // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “\"”\n c !== CHAR_SHARP &&\n c !== CHAR_AMPERSAND &&\n c !== CHAR_ASTERISK &&\n c !== CHAR_EXCLAMATION &&\n c !== CHAR_VERTICAL_LINE &&\n c !== CHAR_EQUALS &&\n c !== CHAR_GREATER_THAN &&\n c !== CHAR_SINGLE_QUOTE &&\n c !== CHAR_DOUBLE_QUOTE &&\n // | “%” | “@” | “`”)\n c !== CHAR_PERCENT &&\n c !== CHAR_COMMERCIAL_AT &&\n c !== CHAR_GRAVE_ACCENT\n}\n\n// Simplified test for values allowed as the last character in plain style.\nfunction isPlainSafeLast (c) {\n // just not whitespace or colon, it will be checked to be plain character later\n return !isWhitespace(c) && c !== CHAR_COLON\n}\n\n// Same as 'string'.codePointAt(pos), but works in older browsers.\nfunction codePointAt (string, pos) {\n const first = string.charCodeAt(pos)\n let second\n\n if (first >= 0xD800 && first <= 0xDBFF && pos + 1 < string.length) {\n second = string.charCodeAt(pos + 1)\n if (second >= 0xDC00 && second <= 0xDFFF) {\n // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000\n }\n }\n return first\n}\n\n// Determines whether block indentation indicator is required.\nfunction needIndentIndicator (string) {\n const leadingSpaceRe = /^\\n* /\n return leadingSpaceRe.test(string)\n}\n\nconst STYLE_PLAIN = 1\nconst STYLE_SINGLE = 2\nconst STYLE_LITERAL = 3\nconst STYLE_FOLDED = 4\nconst STYLE_DOUBLE = 5\n\n// Determines which scalar styles are possible and returns the preferred style.\n// lineWidth = -1 => no limit.\n// Pre-conditions: str.length > 0.\n// Post-conditions:\n// STYLE_PLAIN or STYLE_SINGLE => no \\n are in the string.\n// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1).\n// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1).\nfunction chooseScalarStyle (string, singleLineOnly, indentPerLevel, lineWidth,\n testAmbiguousType, quotingType, forceQuotes, inblock) {\n let i\n let char = 0\n let prevChar = null\n let hasLineBreak = false\n let hasFoldableLine = false // only checked if shouldTrackWidth\n const shouldTrackWidth = lineWidth !== -1\n let previousLineBreak = -1 // count the first line correctly\n let plain = isPlainSafeFirst(codePointAt(string, 0)) &&\n isPlainSafeLast(codePointAt(string, string.length - 1))\n\n if (singleLineOnly || forceQuotes) {\n // Case: no block styles.\n // Check for disallowed characters to rule out plain and single.\n for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) {\n char = codePointAt(string, i)\n if (!isPrintable(char)) {\n return STYLE_DOUBLE\n }\n plain = plain && isPlainSafe(char, prevChar, inblock)\n prevChar = char\n }\n } else {\n // Case: block styles permitted.\n for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) {\n char = codePointAt(string, i)\n if (char === CHAR_LINE_FEED) {\n hasLineBreak = true\n // Check if any line can be folded.\n if (shouldTrackWidth) {\n hasFoldableLine = hasFoldableLine ||\n // Foldable line = too long, and not more-indented.\n (i - previousLineBreak - 1 > lineWidth &&\n string[previousLineBreak + 1] !== ' ')\n previousLineBreak = i\n }\n } else if (!isPrintable(char)) {\n return STYLE_DOUBLE\n }\n plain = plain && isPlainSafe(char, prevChar, inblock)\n prevChar = char\n }\n // in case the end is missing a \\n\n hasFoldableLine = hasFoldableLine || (shouldTrackWidth &&\n (i - previousLineBreak - 1 > lineWidth &&\n string[previousLineBreak + 1] !== ' '))\n }\n // Although every style can represent \\n without escaping, prefer block styles\n // for multiline, since they're more readable and they don't add empty lines.\n // Also prefer folding a super-long line.\n if (!hasLineBreak && !hasFoldableLine) {\n // Strings interpretable as another type have to be quoted;\n // e.g. the string 'true' vs. the boolean true.\n if (plain && !forceQuotes && !testAmbiguousType(string)) {\n return STYLE_PLAIN\n }\n return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE\n }\n // Edge case: block indentation indicator can only have one digit.\n if (indentPerLevel > 9 && needIndentIndicator(string)) {\n return STYLE_DOUBLE\n }\n // At this point we know block styles are valid.\n // Prefer literal style unless we want to fold.\n if (!forceQuotes) {\n return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL\n }\n return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE\n}\n\n// Note: line breaking/folding is implemented for only the folded style.\n// NB. We drop the last trailing newline (if any) of a returned block scalar\n// since the dumper adds its own newline. This always works:\n// • No ending newline => unaffected; already using strip \"-\" chomping.\n// • Ending newline => removed then restored.\n// Importantly, this keeps the \"+\" chomp indicator from gaining an extra line.\nfunction writeScalar (state, string, level, iskey, inblock) {\n state.dump = (function () {\n if (string.length === 0) {\n return state.quotingType === QUOTING_TYPE_DOUBLE ? '\"\"' : \"''\"\n }\n if (!state.noCompatMode) {\n if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) {\n return state.quotingType === QUOTING_TYPE_DOUBLE ? ('\"' + string + '\"') : (\"'\" + string + \"'\")\n }\n }\n\n const indent = state.indent * Math.max(1, level) // no 0-indent scalars\n // As indentation gets deeper, let the width decrease monotonically\n // to the lower bound min(state.lineWidth, 40).\n // Note that this implies\n // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound.\n // state.lineWidth > 40 + state.indent: width decreases until the lower bound.\n // This behaves better than a constant minimum width which disallows narrower options,\n // or an indent threshold which causes the width to suddenly increase.\n const lineWidth = (state.lineWidth === -1)\n ? -1\n : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent)\n\n // Without knowing if keys are implicit/explicit, assume implicit for safety.\n const singleLineOnly = iskey ||\n // No block styles in flow mode.\n (state.flowLevel > -1 && level >= state.flowLevel)\n function testAmbiguity (string) {\n return testImplicitResolving(state, string)\n }\n\n switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth,\n testAmbiguity, state.quotingType, state.forceQuotes && !iskey, inblock)) {\n case STYLE_PLAIN:\n return string\n case STYLE_SINGLE:\n return \"'\" + string.replace(/'/g, \"''\") + \"'\"\n case STYLE_LITERAL:\n return '|' + blockHeader(string, state.indent) +\n dropEndingNewline(indentString(string, indent))\n case STYLE_FOLDED:\n return '>' + blockHeader(string, state.indent) +\n dropEndingNewline(indentString(foldString(string, lineWidth), indent))\n case STYLE_DOUBLE:\n return '\"' + escapeString(string, lineWidth) + '\"'\n default:\n throw new YAMLException('impossible error: invalid scalar style')\n }\n }())\n}\n\n// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9.\nfunction blockHeader (string, indentPerLevel) {\n const indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''\n\n // note the special case: the string '\\n' counts as a \"trailing\" empty line.\n const clip = string[string.length - 1] === '\\n'\n const keep = clip && (string[string.length - 2] === '\\n' || string === '\\n')\n const chomp = keep ? '+' : (clip ? '' : '-')\n\n return indentIndicator + chomp + '\\n'\n}\n\n// (See the note for writeScalar.)\nfunction dropEndingNewline (string) {\n return string[string.length - 1] === '\\n' ? string.slice(0, -1) : string\n}\n\n// Note: a long line without a suitable break point will exceed the width limit.\n// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0.\nfunction foldString (string, width) {\n // In folded style, $k$ consecutive newlines output as $k+1$ newlines—\n // unless they're before or after a more-indented line, or at the very\n // beginning or end, in which case $k$ maps to $k$.\n // Therefore, parse each chunk as newline(s) followed by a content line.\n const lineRe = /(\\n+)([^\\n]*)/g\n\n // first line (possibly an empty line)\n let result = (function () {\n let nextLF = string.indexOf('\\n')\n nextLF = nextLF !== -1 ? nextLF : string.length\n lineRe.lastIndex = nextLF\n return foldLine(string.slice(0, nextLF), width)\n }())\n // If we haven't reached the first content line yet, don't add an extra \\n.\n let prevMoreIndented = string[0] === '\\n' || string[0] === ' '\n let moreIndented\n\n // rest of the lines\n let match\n while ((match = lineRe.exec(string))) {\n const prefix = match[1]\n const line = match[2]\n\n moreIndented = (line[0] === ' ')\n result += prefix +\n ((!prevMoreIndented && !moreIndented && line !== '') ? '\\n' : '') +\n foldLine(line, width)\n prevMoreIndented = moreIndented\n }\n\n return result\n}\n\n// Greedy line breaking.\n// Picks the longest line under the limit each time,\n// otherwise settles for the shortest line over the limit.\n// NB. More-indented lines *cannot* be folded, as that would add an extra \\n.\nfunction foldLine (line, width) {\n if (line === '' || line[0] === ' ') return line\n\n // Since a more-indented line adds a \\n, breaks can't be followed by a space.\n const breakRe = / [^ ]/g // note: the match index will always be <= length-2.\n let match\n // start is an inclusive index. end, curr, and next are exclusive.\n let start = 0\n let end\n let curr = 0\n let next = 0\n let result = ''\n\n // Invariants: 0 <= start <= length-1.\n // 0 <= curr <= next <= max(0, length-2). curr - start <= width.\n // Inside the loop:\n // A match implies length >= 2, so curr and next are <= length-2.\n while ((match = breakRe.exec(line))) {\n next = match.index\n // maintain invariant: curr - start <= width\n if (next - start > width) {\n end = (curr > start) ? curr : next // derive end <= length-2\n result += '\\n' + line.slice(start, end)\n // skip the space that was output as \\n\n start = end + 1 // derive start <= length-1\n }\n curr = next\n }\n\n // By the invariants, start <= length-1, so there is something left over.\n // It is either the whole string or a part starting from non-whitespace.\n result += '\\n'\n // Insert a break if the remainder is too long and there is a break available.\n if (line.length - start > width && curr > start) {\n result += line.slice(start, curr) + '\\n' + line.slice(curr + 1)\n } else {\n result += line.slice(start)\n }\n\n return result.slice(1) // drop extra \\n joiner\n}\n\n// Escapes a double-quoted string.\nfunction escapeString (string) {\n let result = ''\n let char = 0\n\n for (let i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) {\n char = codePointAt(string, i)\n const escapeSeq = ESCAPE_SEQUENCES[char]\n\n if (!escapeSeq && isPrintable(char)) {\n result += string[i]\n if (char >= 0x10000) result += string[i + 1]\n } else {\n result += escapeSeq || encodeHex(char)\n }\n }\n\n return result\n}\n\nfunction writeFlowSequence (state, level, object) {\n let _result = ''\n const _tag = state.tag\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n let value = object[index]\n\n if (state.replacer) {\n value = state.replacer.call(object, String(index), value)\n }\n\n // Write only valid elements, put null instead of invalid elements.\n if (writeNode(state, level, value, false, false) ||\n (typeof value === 'undefined' &&\n writeNode(state, level, null, false, false))) {\n if (_result !== '') _result += ',' + (!state.condenseFlow ? ' ' : '')\n _result += state.dump\n }\n }\n\n state.tag = _tag\n state.dump = '[' + _result + ']'\n}\n\nfunction writeBlockSequence (state, level, object, compact) {\n let _result = ''\n const _tag = state.tag\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n let value = object[index]\n\n if (state.replacer) {\n value = state.replacer.call(object, String(index), value)\n }\n\n // Write only valid elements, put null instead of invalid elements.\n if (writeNode(state, level + 1, value, true, true, false, true) ||\n (typeof value === 'undefined' &&\n writeNode(state, level + 1, null, true, true, false, true))) {\n if (!compact || _result !== '') {\n _result += generateNextLine(state, level)\n }\n\n if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {\n _result += '-'\n } else {\n _result += '- '\n }\n\n _result += state.dump\n }\n }\n\n state.tag = _tag\n state.dump = _result || '[]' // Empty sequence if no valid values.\n}\n\nfunction writeFlowMapping (state, level, object) {\n let _result = ''\n const _tag = state.tag\n const objectKeyList = Object.keys(object)\n\n for (let index = 0, length = objectKeyList.length; index < length; index += 1) {\n let pairBuffer = ''\n if (_result !== '') pairBuffer += ', '\n\n if (state.condenseFlow) pairBuffer += '\"'\n\n const objectKey = objectKeyList[index]\n let objectValue = object[objectKey]\n\n if (state.replacer) {\n objectValue = state.replacer.call(object, objectKey, objectValue)\n }\n\n if (!writeNode(state, level, objectKey, false, false)) {\n continue // Skip this pair because of invalid key;\n }\n\n if (state.dump.length > 1024) pairBuffer += '? '\n\n pairBuffer += state.dump + (state.condenseFlow ? '\"' : '') + ':' + (state.condenseFlow ? '' : ' ')\n\n if (!writeNode(state, level, objectValue, false, false)) {\n continue // Skip this pair because of invalid value.\n }\n\n pairBuffer += state.dump\n\n // Both key and value are valid.\n _result += pairBuffer\n }\n\n state.tag = _tag\n state.dump = '{' + _result + '}'\n}\n\nfunction writeBlockMapping (state, level, object, compact) {\n let _result = ''\n const _tag = state.tag\n const objectKeyList = Object.keys(object)\n\n // Allow sorting keys so that the output file is deterministic\n if (state.sortKeys === true) {\n // Default sorting\n objectKeyList.sort()\n } else if (typeof state.sortKeys === 'function') {\n // Custom sort function\n objectKeyList.sort(state.sortKeys)\n } else if (state.sortKeys) {\n // Something is wrong\n throw new YAMLException('sortKeys must be a boolean or a function')\n }\n\n for (let index = 0, length = objectKeyList.length; index < length; index += 1) {\n let pairBuffer = ''\n\n if (!compact || _result !== '') {\n pairBuffer += generateNextLine(state, level)\n }\n\n const objectKey = objectKeyList[index]\n let objectValue = object[objectKey]\n\n if (state.replacer) {\n objectValue = state.replacer.call(object, objectKey, objectValue)\n }\n\n if (!writeNode(state, level + 1, objectKey, true, true, true)) {\n continue // Skip this pair because of invalid key.\n }\n\n const explicitPair = (state.tag !== null && state.tag !== '?') ||\n (state.dump && state.dump.length > 1024)\n\n if (explicitPair) {\n if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {\n pairBuffer += '?'\n } else {\n pairBuffer += '? '\n }\n }\n\n pairBuffer += state.dump\n\n if (explicitPair) {\n pairBuffer += generateNextLine(state, level)\n }\n\n if (!writeNode(state, level + 1, objectValue, true, explicitPair)) {\n continue // Skip this pair because of invalid value.\n }\n\n if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {\n pairBuffer += ':'\n } else {\n pairBuffer += ': '\n }\n\n pairBuffer += state.dump\n\n // Both key and value are valid.\n _result += pairBuffer\n }\n\n state.tag = _tag\n state.dump = _result || '{}' // Empty mapping if no valid pairs.\n}\n\nfunction detectType (state, object, explicit) {\n const typeList = explicit ? state.explicitTypes : state.implicitTypes\n\n for (let index = 0, length = typeList.length; index < length; index += 1) {\n const type = typeList[index]\n\n if ((type.instanceOf || type.predicate) &&\n (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) &&\n (!type.predicate || type.predicate(object))) {\n if (explicit) {\n if (type.multi && type.representName) {\n state.tag = type.representName(object)\n } else {\n state.tag = type.tag\n }\n } else {\n state.tag = '?'\n }\n\n if (type.represent) {\n const style = state.styleMap[type.tag] || type.defaultStyle\n\n let _result\n if (_toString.call(type.represent) === '[object Function]') {\n _result = type.represent(object, style)\n } else if (_hasOwnProperty.call(type.represent, style)) {\n _result = type.represent[style](object, style)\n } else {\n throw new YAMLException('!<' + type.tag + '> tag resolver accepts not \"' + style + '\" style')\n }\n\n state.dump = _result\n }\n\n return true\n }\n }\n\n return false\n}\n\n// Serializes `object` and writes it to global `result`.\n// Returns true on success, or false on invalid object.\n//\nfunction writeNode (state, level, object, block, compact, iskey, isblockseq) {\n state.tag = null\n state.dump = object\n\n if (!detectType(state, object, false)) {\n detectType(state, object, true)\n }\n\n const type = _toString.call(state.dump)\n const inblock = block\n\n if (block) {\n block = (state.flowLevel < 0 || state.flowLevel > level)\n }\n\n const objectOrArray = type === '[object Object]' || type === '[object Array]'\n let duplicateIndex\n let duplicate\n\n if (objectOrArray) {\n duplicateIndex = state.duplicates.indexOf(object)\n duplicate = duplicateIndex !== -1\n }\n\n if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) {\n compact = false\n }\n\n if (duplicate && state.usedDuplicates[duplicateIndex]) {\n state.dump = '*ref_' + duplicateIndex\n } else {\n if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) {\n state.usedDuplicates[duplicateIndex] = true\n }\n if (type === '[object Object]') {\n if (block && (Object.keys(state.dump).length !== 0)) {\n writeBlockMapping(state, level, state.dump, compact)\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + state.dump\n }\n } else {\n writeFlowMapping(state, level, state.dump)\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + ' ' + state.dump\n }\n }\n } else if (type === '[object Array]') {\n if (block && (state.dump.length !== 0)) {\n if (state.noArrayIndent && !isblockseq && level > 0) {\n writeBlockSequence(state, level - 1, state.dump, compact)\n } else {\n writeBlockSequence(state, level, state.dump, compact)\n }\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + state.dump\n }\n } else {\n writeFlowSequence(state, level, state.dump)\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + ' ' + state.dump\n }\n }\n } else if (type === '[object String]') {\n if (state.tag !== '?') {\n writeScalar(state, state.dump, level, iskey, inblock)\n }\n } else if (type === '[object Undefined]') {\n return false\n } else {\n if (state.skipInvalid) return false\n throw new YAMLException('unacceptable kind of an object to dump ' + type)\n }\n\n if (state.tag !== null && state.tag !== '?') {\n // Need to encode all characters except those allowed by the spec:\n //\n // [35] ns-dec-digit ::= [#x30-#x39] /* 0-9 */\n // [36] ns-hex-digit ::= ns-dec-digit\n // | [#x41-#x46] /* A-F */ | [#x61-#x66] /* a-f */\n // [37] ns-ascii-letter ::= [#x41-#x5A] /* A-Z */ | [#x61-#x7A] /* a-z */\n // [38] ns-word-char ::= ns-dec-digit | ns-ascii-letter | “-”\n // [39] ns-uri-char ::= “%” ns-hex-digit ns-hex-digit | ns-word-char | “#”\n // | “;” | “/” | “?” | “:” | “@” | “&” | “=” | “+” | “$” | “,”\n // | “_” | “.” | “!” | “~” | “*” | “'” | “(” | “)” | “[” | “]”\n //\n // Also need to encode '!' because it has special meaning (end of tag prefix).\n //\n let tagStr = encodeURI(\n state.tag[0] === '!' ? state.tag.slice(1) : state.tag\n ).replace(/!/g, '%21')\n\n if (state.tag[0] === '!') {\n tagStr = '!' + tagStr\n } else if (tagStr.slice(0, 18) === 'tag:yaml.org,2002:') {\n tagStr = '!!' + tagStr.slice(18)\n } else {\n tagStr = '!<' + tagStr + '>'\n }\n\n state.dump = tagStr + ' ' + state.dump\n }\n }\n\n return true\n}\n\nfunction getDuplicateReferences (object, state) {\n const objects = []\n const duplicatesIndexes = []\n\n inspectNode(object, objects, duplicatesIndexes)\n\n const length = duplicatesIndexes.length\n for (let index = 0; index < length; index += 1) {\n state.duplicates.push(objects[duplicatesIndexes[index]])\n }\n state.usedDuplicates = new Array(length)\n}\n\nfunction inspectNode (object, objects, duplicatesIndexes) {\n if (object !== null && typeof object === 'object') {\n const index = objects.indexOf(object)\n if (index !== -1) {\n if (duplicatesIndexes.indexOf(index) === -1) {\n duplicatesIndexes.push(index)\n }\n } else {\n objects.push(object)\n\n if (Array.isArray(object)) {\n for (let i = 0, length = object.length; i < length; i += 1) {\n inspectNode(object[i], objects, duplicatesIndexes)\n }\n } else {\n const objectKeyList = Object.keys(object)\n\n for (let i = 0, length = objectKeyList.length; i < length; i += 1) {\n inspectNode(object[objectKeyList[i]], objects, duplicatesIndexes)\n }\n }\n }\n }\n}\n\nfunction dump (input, options) {\n options = options || {}\n\n const state = new State(options)\n\n if (!state.noRefs) getDuplicateReferences(input, state)\n\n let value = input\n\n if (state.replacer) {\n value = state.replacer.call({ '': value }, '', value)\n }\n\n if (writeNode(state, 0, value, true, true)) return state.dump + '\\n'\n\n return ''\n}\n\nmodule.exports.dump = dump\n","'use strict'\n\nconst loader = require('./lib/loader')\nconst dumper = require('./lib/dumper')\n\nfunction renamed (from, to) {\n return function () {\n throw new Error('Function yaml.' + from + ' is removed in js-yaml 4. ' +\n 'Use yaml.' + to + ' instead, which is now safe by default.')\n }\n}\n\nmodule.exports.Type = require('./lib/type')\nmodule.exports.Schema = require('./lib/schema')\nmodule.exports.FAILSAFE_SCHEMA = require('./lib/schema/failsafe')\nmodule.exports.JSON_SCHEMA = require('./lib/schema/json')\nmodule.exports.CORE_SCHEMA = require('./lib/schema/core')\nmodule.exports.DEFAULT_SCHEMA = require('./lib/schema/default')\nmodule.exports.load = loader.load\nmodule.exports.loadAll = loader.loadAll\nmodule.exports.dump = dumper.dump\nmodule.exports.YAMLException = require('./lib/exception')\n\n// Re-export all types in case user wants to create custom schema\nmodule.exports.types = {\n binary: require('./lib/type/binary'),\n float: require('./lib/type/float'),\n map: require('./lib/type/map'),\n null: require('./lib/type/null'),\n pairs: require('./lib/type/pairs'),\n set: require('./lib/type/set'),\n timestamp: require('./lib/type/timestamp'),\n bool: require('./lib/type/bool'),\n int: require('./lib/type/int'),\n merge: require('./lib/type/merge'),\n omap: require('./lib/type/omap'),\n seq: require('./lib/type/seq'),\n str: require('./lib/type/str')\n}\n\n// Removed functions from JS-YAML 3.0.x\nmodule.exports.safeLoad = renamed('safeLoad', 'load')\nmodule.exports.safeLoadAll = renamed('safeLoadAll', 'loadAll')\nmodule.exports.safeDump = renamed('safeDump', 'dump')\n","import yaml from '../index.js'\n\nconst {\n Type,\n Schema,\n FAILSAFE_SCHEMA,\n JSON_SCHEMA,\n CORE_SCHEMA,\n DEFAULT_SCHEMA,\n load,\n loadAll,\n dump,\n YAMLException,\n types,\n safeLoad,\n safeLoadAll,\n safeDump\n} = yaml\n\nexport {\n Type,\n Schema,\n FAILSAFE_SCHEMA,\n JSON_SCHEMA,\n CORE_SCHEMA,\n DEFAULT_SCHEMA,\n load,\n loadAll,\n dump,\n YAMLException,\n types,\n safeLoad,\n safeLoadAll,\n safeDump\n}\n\nexport default yaml\n"],"names":["_typeof","o","Symbol","iterator","constructor","prototype","isNothing","subject","isObject","toArray","sequence","Array","isArray","extend","target","source","sourceKeys","Object","keys","index","length","key","repeat","string","count","result","cycle","isNegativeZero","number","Number","NEGATIVE_INFINITY","common","formatError","exception","compact","where","message","reason","mark","name","line","column","snippet","YAMLException","Error","call","this","captureStackTrace","stack","create","toString","require$$0","getLine","buffer","lineStart","lineEnd","position","maxLineLength","head","tail","maxHalfLength","Math","floor","str","slice","replace","pos","padStart","max","makeSnippet","options","maxLength","indent","linesBefore","linesAfter","re","lineStarts","lineEnds","match","foundLineNo","exec","push","lineNoLength","min","i","TYPE_CONSTRUCTOR_OPTIONS","YAML_NODE_KINDS","compileStyleAliases","map","forEach","style","alias","String","Type","tag","indexOf","kind","resolve","construct","data","instanceOf","predicate","represent","representName","defaultStyle","multi","styleAliases","type","require$$1","compileList","schema","currentType","newIndex","previousType","previousIndex","compileMap","scalar","mapping","fallback","collectType","arguments","Schema","definition","implicit","explicit","concat","loadKind","compiledImplicit","compiledExplicit","compiledTypeMap","seq","failsafe","require$$2","require$$3","resolveYamlNull","constructYamlNull","isNull","object","_null","canonical","lowercase","uppercase","camelcase","empty","resolveYamlBoolean","constructYamlBoolean","isBoolean","bool","isHexCode","c","isOctCode","isDecCode","resolveYamlInteger","hasDigits","ch","isFinite","parseYamlInteger","charCodeAt","value","sign","parseInt","constructYamlInteger","isInteger","int","binary","obj","octal","decimal","hexadecimal","toUpperCase","YAML_FLOAT_PATTERN","RegExp","YAML_FLOAT_SPECIAL_PATTERN","resolveYamlFloat","test","parseFloat","constructYamlFloat","toLowerCase","POSITIVE_INFINITY","NaN","SCIENTIFIC_WITHOUT_DOT","representYamlFloat","isNaN","res","isFloat","float","json","require$$4","core","YAML_DATE_REGEXP","YAML_TIMESTAMP_REGEXP","resolveYamlTimestamp","constructYamlTimestamp","fraction","delta","year","month","day","Date","UTC","hour","minute","second","tzHour","tzMinute","date","setTime","getTime","representYamlTimestamp","toISOString","timestamp","resolveYamlMerge","merge","BASE64_MAP","resolveYamlBinary","bitlen","idx","code","charAt","constructYamlBinary","input","bits","tailbits","Uint8Array","representYamlBinary","isBinary","_hasOwnProperty","hasOwnProperty","_toString","resolveYamlOmap","objectKeys","pair","pairHasKey","pairKey","defineProperty","constructYamlOmap","omap","resolveYamlPairs","constructYamlPairs","pairs","resolveYamlSet","constructYamlSet","set","_default","require$$5","require$$6","DEFAULT_SCHEMA","CONTEXT_FLOW_IN","CONTEXT_FLOW_OUT","CONTEXT_BLOCK_IN","CONTEXT_BLOCK_OUT","CHOMPING_CLIP","CHOMPING_STRIP","CHOMPING_KEEP","PATTERN_NON_PRINTABLE","PATTERN_NON_ASCII_LINE_BREAKS","PATTERN_FLOW_INDICATORS","PATTERN_TAG_HANDLE","PATTERN_TAG_URI","_class","isEol","isWhiteSpace","isWsOrEol","isFlowIndicator","fromHexCode","lc","escapedHexLen","fromDecimalCode","simpleEscapeSequence","charFromCodepoint","fromCharCode","setProperty","configurable","enumerable","writable","simpleEscapeCheck","simpleEscapeMap","State","filename","onWarning","legacy","listener","maxDepth","maxTotalMergeKeys","implicitTypes","typeMap","lineIndent","depth","totalMergeKeys","firstTabInLine","documents","anchorMapTransactions","generateError","state","throwError","throwWarning","storeAnchor","transactions","transaction","existed","anchorMap","beginAnchorTransaction","commitAnchorTransaction","pop","parent","names","rollbackAnchorTransaction","entry","snapshotState","anchor","restoreState","snapshot","directiveHandlers","YAML","handleYamlDirective","args","version","major","minor","checkLineBreaks","TAG","handleTagDirective","prefix","handle","tagMap","decodeURIComponent","err","captureSegment","start","end","checkJson","_result","_position","_length","_character","mergeMappings","destination","overridableKeys","quantity","storeMappingPair","keyTag","keyNode","valueNode","startLine","startLineStart","startPos","readLineBreak","skipSeparationSpace","allowComments","checkIndent","lineBreaks","testDocumentSeparator","writeFoldedLines","readPlainScalar","nodeIndent","withinFlowCollection","captureStart","captureEnd","hasPendingContent","_line","_lineStart","_lineIndent","_kind","following","preceding","readSingleQuotedScalar","readDoubleQuotedScalar","tmp","hexLength","hexResult","readFlowCollection","readNext","_pos","_tag","_anchor","terminator","isPair","isExplicitPair","isMapping","composeNode","readBlockScalar","folding","chomping","didReadContent","detectedIndent","textIndent","emptyLines","atMoreIndented","readBlockSequence","detected","readBlockMapping","flowIndent","allowCompact","_keyLine","_keyLineStart","_keyPos","atExplicitKey","readTagProperty","isVerbatim","isNamed","tagHandle","tagName","readAnchorProperty","readAlias","tryReadBlockMappingFromProperty","propertyStart","fallbackState","parentIndent","nodeContext","allowToSeek","allowBlockScalars","allowBlockCollections","indentStatus","atNewLine","hasContent","blockIndent","allowBlockStyles","propertyState","typeIndex","typeQuantity","typeList","readDocument","documentStart","hasDirectives","directiveName","directiveArgs","loadDocuments","nullpos","loadAll","load","loader","CHAR_BOM","CHAR_TAB","CHAR_LINE_FEED","CHAR_CARRIAGE_RETURN","CHAR_SPACE","CHAR_EXCLAMATION","CHAR_DOUBLE_QUOTE","CHAR_SHARP","CHAR_PERCENT","CHAR_AMPERSAND","CHAR_SINGLE_QUOTE","CHAR_ASTERISK","CHAR_COMMA","CHAR_MINUS","CHAR_COLON","CHAR_EQUALS","CHAR_GREATER_THAN","CHAR_QUESTION","CHAR_COMMERCIAL_AT","CHAR_LEFT_SQUARE_BRACKET","CHAR_RIGHT_SQUARE_BRACKET","CHAR_GRAVE_ACCENT","CHAR_LEFT_CURLY_BRACKET","CHAR_VERTICAL_LINE","CHAR_RIGHT_CURLY_BRACKET","ESCAPE_SEQUENCES","DEPRECATED_BOOLEANS_SYNTAX","DEPRECATED_BASE60_SYNTAX","compileStyleMap","encodeHex","character","QUOTING_TYPE_SINGLE","QUOTING_TYPE_DOUBLE","noArrayIndent","skipInvalid","flowLevel","styleMap","sortKeys","lineWidth","noRefs","noCompatMode","condenseFlow","quotingType","forceQuotes","replacer","explicitTypes","duplicates","usedDuplicates","indentString","spaces","ind","next","generateNextLine","level","testImplicitResolving","isWhitespace","isPrintable","isNsCharOrWhitespace","isPlainSafe","prev","inblock","cIsNsCharOrWhitespace","cIsNsChar","isPlainSafeFirst","isPlainSafeLast","codePointAt","first","needIndentIndicator","leadingSpaceRe","STYLE_PLAIN","STYLE_SINGLE","STYLE_LITERAL","STYLE_FOLDED","STYLE_DOUBLE","chooseScalarStyle","singleLineOnly","indentPerLevel","testAmbiguousType","char","prevChar","hasLineBreak","hasFoldableLine","shouldTrackWidth","previousLineBreak","plain","writeScalar","iskey","dump","testAmbiguity","blockHeader","dropEndingNewline","foldString","escapeString","indentIndicator","clip","keep","chomp","width","lineRe","nextLF","lastIndex","foldLine","prevMoreIndented","moreIndented","breakRe","curr","escapeSeq","writeFlowSequence","writeNode","writeBlockSequence","writeFlowMapping","objectKeyList","pairBuffer","objectKey","objectValue","writeBlockMapping","sort","explicitPair","detectType","block","isblockseq","objectOrArray","duplicateIndex","duplicate","tagStr","encodeURI","getDuplicateReferences","objects","duplicatesIndexes","inspectNode","dumper","renamed","from","to","jsYaml","FAILSAFE_SCHEMA","JSON_SCHEMA","CORE_SCHEMA","require$$7","require$$8","types","require$$9","require$$10","require$$11","null","require$$12","require$$13","require$$14","require$$15","require$$16","require$$17","require$$18","require$$19","require$$20","require$$21","safeLoad","safeLoadAll","safeDump","yaml"],"mappings":";;;;;;;;;;;;;;;QAAY,SAAAA,QAAAC;YAAA;YAAA,OAAAD,UAAA,qBAAAE,UAAA,mBAAAA,OAAAC,WAAA,SAAAF;gBAAA,cAAAA;gBAAA,SAAAA;gBAAA,OAAAA,MAAA,qBAAAC,UAAAD,GAAAG,gBAAAF,UAAAD,OAAAC,OAAAG,YAAA,kBAAAJ;AAAA,eAAAD,QAAAC;AAAA;QAEZ,SAASK,UAAWC;YAClB,cAAeA,YAAY,eAAiBA,YAAY;AAC1D;QAEA,SAASC,SAAUD;YACjB,OAAQP,QAAOO,aAAY,YAAcA,YAAY;AACvD;QAEA,SAASE,QAASC;YAChB,IAAIC,MAAMC,QAAQF,WAAW,OAAOA,eAAA,IAC3BJ,UAAUI,WAAW,OAAO;YAErC,OAAO,EAACA;AACV;QAEA,SAASG,OAAQC,QAAQC;YACvB,IAAIA,QAAQ;gBACV,IAAMC,aAAaC,OAAOC,KAAKH;gBAE/B,KAAA,IAASI,QAAQ,GAAGC,SAASJ,WAAWI,QAAQD,QAAQC,QAAQD,SAAS,GAAG;oBAC1E,IAAME,MAAML,WAAWG;oBACvBL,OAAOO,OAAON,OAAOM;AACvB;AACF;YAEA,OAAOP;AACT;QAEA,SAASQ,OAAQC,QAAQC;YACvB,IAAIC,SAAS;YAEb,KAAA,IAASC,QAAQ,GAAGA,QAAQF,OAAOE,SAAS,GAAG;gBAC7CD,UAAUF;AACZ;YAEA,OAAOE;AACT;QAEA,SAASE,eAAgBC;YACvB,OAAQA,WAAW,KAAOC,OAAOC,sBAAsB,IAAIF;AAC7D;QAEAG,OAAAzB,YAA2BA;QAC3ByB,OAAAvB,WAA0BA;QAC1BuB,OAAAtB,UAAyBA;QACzBsB,OAAAT,SAAwBA;QACxBS,OAAAJ,iBAAgCA;QAChCI,OAAAlB,SAAwBA;;;;;;;;QC7CxB,SAASmB,YAAaC,YAAWC;YAC/B,IAAIC,QAAQ;YACZ,IAAMC,UAAUH,WAAUI,UAAU;YAEpC,KAAKJ,WAAUK,MAAM,OAAOF;YAE5B,IAAIH,WAAUK,KAAKC,MAAM;gBACvBJ,SAAS,SAASF,WAAUK,KAAKC,OAAO;AAC1C;YAEAJ,SAAS,OAAOF,WAAUK,KAAKE,OAAO,KAAK,OAAOP,WAAUK,KAAKG,SAAS,KAAK;YAE/E,KAAKP,WAAWD,WAAUK,KAAKI,SAAS;gBACtCP,SAAS,SAASF,WAAUK,KAAKI;AACnC;YAEA,OAAON,UAAU,MAAMD;AACzB;QAEA,SAASQ,eAAeN,QAAQC;YAE9BM,MAAMC,KAAKC;YAEXA,KAAKP,OAAO;YACZO,KAAKT,SAASA;YACdS,KAAKR,OAAOA;YACZQ,KAAKV,UAAUJ,YAAYc,MAAM;YAGjC,IAAIF,MAAMG,mBAAmB;gBAE3BH,MAAMG,kBAAkBD,MAAMA,KAAK1C;AACrC,mBAAO;gBAEL0C,KAAKE,SAAS,IAAIJ,OAASI,SAAS;AACtC;AACF;QAGAL,eAActC,YAAYY,OAAOgC,OAAOL,MAAMvC;QAC9CsC,eAActC,UAAUD,cAAcuC;QAEtCA,eAActC,UAAU6C,WAAW,SAASA,SAAUhB;YACpD,OAAOY,KAAKP,OAAO,OAAOP,YAAYc,MAAMZ;AAC9C;QAEAD,YAAiBU;;;;;;;;QChDjB,IAAMZ,UAASoB;QAGf,SAASC,QAASC,QAAQC,WAAWC,SAASC,UAAUC;YACtD,IAAIC,OAAO;YACX,IAAIC,OAAO;YACX,IAAMC,gBAAgBC,KAAKC,MAAML,gBAAgB,KAAK;YAEtD,IAAID,WAAWF,YAAYM,eAAe;gBACxCF,OAAO;gBACPJ,YAAYE,WAAWI,gBAAgBF,KAAKtC;AAC9C;YAEA,IAAImC,UAAUC,WAAWI,eAAe;gBACtCD,OAAO;gBACPJ,UAAUC,WAAWI,gBAAgBD,KAAKvC;AAC5C;YAEA,OAAO;gBACL2C,KAAKL,OAAOL,OAAOW,MAAMV,WAAWC,SAASU,QAAQ,OAAO,OAAON;gBACnEO,KAAKV,WAAWF,YAAYI,KAAKtC;;AAErC;QAEA,SAAS+C,SAAU5C,QAAQ6C;YACzB,OAAOrC,QAAOT,OAAO,KAAK8C,MAAM7C,OAAOH,UAAUG;AACnD;QAEA,SAAS8C,YAAa/B,MAAMgC;YAC1BA,UAAUrD,OAAOgC,OAAOqB,WAAW;YAEnC,KAAKhC,KAAKe,QAAQ,OAAO;YAEzB,KAAKiB,QAAQC,WAAWD,QAAQC,YAAY;YAC5C,WAAWD,QAAQE,WAAW,kBAAkBA,SAAS;YACzD,WAAWF,QAAQG,gBAAgB,kBAAkBA,cAAc;YACnE,WAAWH,QAAQI,eAAe,kBAAkBA,aAAa;YAEjE,IAAMC,KAAK;YACX,IAAMC,aAAa,EAAC;YACpB,IAAMC,WAAW;YACjB,IAAIC;YACJ,IAAIC,eAAc;YAElB,OAAQD,QAAQH,GAAGK,KAAK1C,KAAKe,SAAU;gBACrCwB,SAASI,KAAKH,MAAM3D;gBACpByD,WAAWK,KAAKH,MAAM3D,QAAQ2D,MAAM,GAAG1D;gBAEvC,IAAIkB,KAAKkB,YAAYsB,MAAM3D,SAAS4D,cAAc,GAAG;oBACnDA,cAAcH,WAAWxD,SAAS;AACpC;AACF;YAEA,IAAI2D,cAAc,GAAGA,cAAcH,WAAWxD,SAAS;YAEvD,IAAIK,SAAS;YACb,IAAMyD,eAAerB,KAAKsB,IAAI7C,KAAKE,OAAO8B,QAAQI,YAAYG,SAASzD,QAAQ8B,WAAW9B;YAC1F,IAAMqC,gBAAgBa,QAAQC,aAAaD,QAAQE,SAASU,eAAe;YAE3E,KAAA,IAASE,IAAI,GAAGA,KAAKd,QAAQG,aAAaW,KAAK;gBAC7C,IAAIL,cAAcK,IAAI,GAAG;gBACzB,IAAM5C,QAAOY,QACXd,KAAKe,QACLuB,WAAWG,cAAcK,IACzBP,SAASE,cAAcK,IACvB9C,KAAKkB,YAAYoB,WAAWG,eAAeH,WAAWG,cAAcK,KACpE3B;gBAEFhC,SAASM,QAAOT,OAAO,KAAKgD,QAAQE,UAAUL,UAAU7B,KAAKE,OAAO4C,IAAI,GAAGlC,YAAYgC,gBACrF,QAAQ1C,MAAKuB,MAAM,OAAOtC;AAC9B;YAEA,IAAMe,OAAOY,QAAQd,KAAKe,QAAQuB,WAAWG,cAAcF,SAASE,cAAczC,KAAKkB,UAAUC;YACjGhC,UAAUM,QAAOT,OAAO,KAAKgD,QAAQE,UAAUL,UAAU7B,KAAKE,OAAO,GAAGU,YAAYgC,gBAClF,QAAQ1C,KAAKuB,MAAM;YACrBtC,UAAUM,QAAOT,OAAO,KAAKgD,QAAQE,SAASU,eAAe,IAAI1C,KAAK0B,OAAO;YAE7E,KAAA,IAASkB,KAAI,GAAGA,MAAKd,QAAQI,YAAYU,MAAK;gBAC5C,IAAIL,cAAcK,MAAKP,SAASzD,QAAQ;gBACxC,IAAMoB,SAAOY,QACXd,KAAKe,QACLuB,WAAWG,cAAcK,KACzBP,SAASE,cAAcK,KACvB9C,KAAKkB,YAAYoB,WAAWG,eAAeH,WAAWG,cAAcK,MACpE3B;gBAEFhC,UAAUM,QAAOT,OAAO,KAAKgD,QAAQE,UAAUL,UAAU7B,KAAKE,OAAO4C,KAAI,GAAGlC,YAAYgC,gBACtF,QAAQ1C,OAAKuB,MAAM;AACvB;YAEA,OAAOtC,OAAOwC,QAAQ,OAAO;AAC/B;QAEAvB,UAAiB2B;;;;;;;;QC7FjB,IAAM1B,iBAAgBQ;QAEtB,IAAMkC,2BAA2B,EAC/B,QACA,SACA,WACA,aACA,cACA,aACA,aACA,iBACA,gBACA;QAGF,IAAMC,kBAAkB,EACtB,UACA,YACA;QAGF,SAASC,oBAAqBC;YAC5B,IAAM/D,SAAS,CAAA;YAEf,IAAI+D,SAAQ,MAAM;gBAChBvE,OAAOC,KAAKsE,MAAKC,QAAQ,SAAUC;oBACjCF,KAAIE,OAAOD,QAAQ,SAAUE;wBAC3BlE,OAAOmE,OAAOD,UAAUD;AAC1B;AACF;AACF;YAEA,OAAOjE;AACT;QAEA,SAASoE,MAAMC,KAAKxB;YAClBA,UAAUA,WAAW,CAAA;YAErBrD,OAAOC,KAAKoD,SAASmB,QAAQ,SAAUlD;gBACrC,IAAI8C,yBAAyBU,QAAQxD,WAAU,GAAI;oBACjD,MAAM,IAAII,eAAc,qBAAqBJ,OAAO,gCAAgCuD,MAAM;AAC5F;AACF;YAGAhD,KAAKwB,UAAUA;YACfxB,KAAKgD,MAAMA;YACXhD,KAAKkD,OAAO1B,QAAQ,WAAW;YAC/BxB,KAAKmD,UAAU3B,QAAQ,cAAc;gBAAc,OAAO;;YAC1DxB,KAAKoD,YAAY5B,QAAQ,gBAAgB,SAAU6B;gBAAQ,OAAOA;;YAClErD,KAAKsD,aAAa9B,QAAQ,iBAAiB;YAC3CxB,KAAKuD,YAAY/B,QAAQ,gBAAgB;YACzCxB,KAAKwD,YAAYhC,QAAQ,gBAAgB;YACzCxB,KAAKyD,gBAAgBjC,QAAQ,oBAAoB;YACjDxB,KAAK0D,eAAelC,QAAQ,mBAAmB;YAC/CxB,KAAK2D,QAAQnC,QAAQ,YAAY;YACjCxB,KAAK4D,eAAenB,oBAAoBjB,QAAQ,mBAAmB;YAEnE,IAAIgB,gBAAgBS,QAAQjD,KAAKkD,WAAU,GAAI;gBAC7C,MAAM,IAAIrD,eAAc,mBAAmBG,KAAKkD,OAAO,yBAAyBF,MAAM;AACxF;AACF;QAEAa,OAAiBd;;;;;;;;QC/DjB,IAAMlD,iBAAgBQ;QACtB,IAAM0C,QAAOe;QAEb,SAASC,YAAaC,SAAQvE;YAC5B,IAAMd,SAAS;YAEfqF,QAAOvE,MAAMkD,QAAQ,SAAUsB;gBAC7B,IAAIC,WAAWvF,OAAOL;gBAEtBK,OAAOgE,QAAQ,SAAUwB,cAAcC;oBACrC,IAAID,aAAanB,QAAQiB,YAAYjB,OACjCmB,aAAajB,SAASe,YAAYf,QAClCiB,aAAaR,UAAUM,YAAYN,OAAO;wBAC5CO,WAAWE;AACb;AACF;gBAEAzF,OAAOuF,YAAYD;AACrB;YAEA,OAAOtF;AACT;QAEA,SAAS0F;YACP,IAAM1F,SAAS;gBACb2F,QAAQ,CAAA;gBACR1G,UAAU,CAAA;gBACV2G,SAAS,CAAA;gBACTC,UAAU,CAAA;gBACVb,OAAO;oBACLW,QAAQ;oBACR1G,UAAU;oBACV2G,SAAS;oBACTC,UAAU;;;YAGd,SAASC,YAAaZ;gBACpB,IAAIA,MAAKF,OAAO;oBACdhF,OAAOgF,MAAME,MAAKX,MAAMf,KAAK0B;oBAC7BlF,OAAOgF,MAAM,YAAYxB,KAAK0B;AAChC,uBAAO;oBACLlF,OAAOkF,MAAKX,MAAMW,MAAKb,OAAOrE,OAAO,YAAYkF,MAAKb,OAAOa;AAC/D;AACF;YAEA,KAAA,IAASxF,QAAQ,GAAGC,SAASoG,UAAUpG,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACzEqG,UAAUrG,OAAOsE,QAAQ8B;AAC3B;YACA,OAAO9F;AACT;QAEA,SAASgG,QAAQC;YACf,OAAO5E,KAAKjC,OAAO6G;AACrB;QAEAD,QAAOpH,UAAUQ,SAAS,SAASA,OAAQ6G;YACzC,IAAIC,WAAW;YACf,IAAIC,WAAW;YAEf,IAAIF,sBAAsB7B,OAAM;gBAE9B+B,SAAS3C,KAAKyC;uBACL/G,MAAMC,QAAQ8G,aAAa;gBAEpCE,WAAWA,SAASC,OAAOH;uBAClBA,eAAe/G,MAAMC,QAAQ8G,WAAWC,aAAahH,MAAMC,QAAQ8G,WAAWE,YAAY;gBAEnG,IAAIF,WAAWC,UAAUA,WAAWA,SAASE,OAAOH,WAAWC;gBAC/D,IAAID,WAAWE,UAAUA,WAAWA,SAASC,OAAOH,WAAWE;AACjE,mBAAO;gBACL,MAAM,IAAIjF,eAAc;AAE1B;YAEAgF,SAASlC,QAAQ,SAAUkB;gBACzB,MAAMA,iBAAgBd,QAAO;oBAC3B,MAAM,IAAIlD,eAAc;AAC1B;gBAEA,IAAIgE,MAAKmB,YAAYnB,MAAKmB,aAAa,UAAU;oBAC/C,MAAM,IAAInF,eAAc;AAC1B;gBAEA,IAAIgE,MAAKF,OAAO;oBACd,MAAM,IAAI9D,eAAc;AAC1B;AACF;YAEAiF,SAASnC,QAAQ,SAAUkB;gBACzB,MAAMA,iBAAgBd,QAAO;oBAC3B,MAAM,IAAIlD,eAAc;AAC1B;AACF;YAEA,IAAMlB,SAASR,OAAOgC,OAAOwE,QAAOpH;YAEpCoB,OAAOkG,YAAY7E,KAAK6E,YAAY,IAAIE,OAAOF;YAC/ClG,OAAOmG,YAAY9E,KAAK8E,YAAY,IAAIC,OAAOD;YAE/CnG,OAAOsG,mBAAmBlB,YAAYpF,QAAQ;YAC9CA,OAAOuG,mBAAmBnB,YAAYpF,QAAQ;YAC9CA,OAAOwG,kBAAkBd,WAAW1F,OAAOsG,kBAAkBtG,OAAOuG;YAEpE,OAAOvG;AACT;QAEAqF,SAAiBW;;;;;;;;QC1GjB,IAAM5B,QAAO1C;QAEbY,MAAiB,IAAI8B,MAAK,yBAAyB;YACjDG,MAAM;YACNE,WAAW,SAAXA,UAAqBC;gBAAQ,OAAOA,SAAS,OAAOA,OAAO;AAAG;;;;;;;;;QCJhE,IAAMN,QAAO1C;QAEb+E,MAAiB,IAAIrC,MAAK,yBAAyB;YACjDG,MAAM;YACNE,WAAW,SAAXA,UAAqBC;gBAAQ,OAAOA,SAAS,OAAOA,OAAO;AAAG;;;;;;;;;QCJhE,IAAMN,QAAO1C;QAEbqC,MAAiB,IAAIK,MAAK,yBAAyB;YACjDG,MAAM;YACNE,WAAW,SAAXA,UAAqBC;gBAAQ,OAAOA,SAAS,OAAOA,OAAO,CAAA;AAAG;;;;;;;;;QCDhE,IAAMsB,UAAStE;QAEfgF,WAAiB,IAAIV,QAAO;YAC1BG,UAAU,EACRhB,cACAwB,cACAC;;;;;;;;;QCTJ,IAAMxC,QAAO1C;QAEb,SAASmF,gBAAiBnC;YACxB,IAAIA,SAAS,MAAM,OAAO;YAE1B,IAAM/B,MAAM+B,KAAK/E;YAEjB,OAAQgD,QAAQ,KAAK+B,SAAS,OACtB/B,QAAQ,MAAM+B,SAAS,UAAUA,SAAS,UAAUA,SAAS;AACvE;QAEA,SAASoC;YACP,OAAO;AACT;QAEA,SAASC,OAAQC;YACf,OAAOA,WAAW;AACpB;QAEAC,QAAiB,IAAI7C,MAAK,0BAA0B;YAClDG,MAAM;YACNC,SAASqC;YACTpC,WAAWqC;YACXlC,WAAWmC;YACXlC,WAAW;gBACTqC,WAAW,SAAXA;oBAAyB,OAAO;;gBAChCC,WAAW,SAAXA;oBAAyB,OAAO;;gBAChCC,WAAW,SAAXA;oBAAyB,OAAO;;gBAChCC,WAAW,SAAXA;oBAAyB,OAAO;;gBAChCC,OAAO,SAAPA;oBAAqB,OAAO;AAAG;;YAEjCvC,cAAc;;;;;;;;;QC/BhB,IAAMX,QAAO1C;QAEb,SAAS6F,mBAAoB7C;YAC3B,IAAIA,SAAS,MAAM,OAAO;YAE1B,IAAM/B,MAAM+B,KAAK/E;YAEjB,OAAQgD,QAAQ,MAAM+B,SAAS,UAAUA,SAAS,UAAUA,SAAS,WAC7D/B,QAAQ,MAAM+B,SAAS,WAAWA,SAAS,WAAWA,SAAS;AACzE;QAEA,SAAS8C,qBAAsB9C;YAC7B,OAAOA,SAAS,UACTA,SAAS,UACTA,SAAS;AAClB;QAEA,SAAS+C,UAAWT;YAClB,OAAOxH,OAAOZ,UAAU6C,SAASL,KAAK4F,YAAY;AACpD;QAEAU,OAAiB,IAAItD,MAAK,0BAA0B;YAClDG,MAAM;YACNC,SAAS+C;YACT9C,WAAW+C;YACX5C,WAAW6C;YACX5C,WAAW;gBACTsC,WAAW,SAAXA,UAAqBH;oBAAU,OAAOA,SAAS,SAAS;;gBACxDI,WAAW,SAAXA,UAAqBJ;oBAAU,OAAOA,SAAS,SAAS;;gBACxDK,WAAW,SAAXA,UAAqBL;oBAAU,OAAOA,SAAS,SAAS;AAAQ;;YAElEjC,cAAc;;;;;;;;;QC/BhB,IAAMzE,UAASoB;QACf,IAAM0C,QAAOe;QAEb,SAASwC,UAAWC;YAClB,OAASA,KAAK,MAAiBA,KAAK,MAC3BA,KAAK,MAAiBA,KAAK,MAC3BA,KAAK,MAAiBA,KAAK;AACtC;QAEA,SAASC,UAAWD;YAClB,OAASA,KAAK,MAAiBA,KAAK;AACtC;QAEA,SAASE,UAAWF;YAClB,OAASA,KAAK,MAAiBA,KAAK;AACtC;QAEA,SAASG,mBAAoBrD;YAC3B,IAAIA,SAAS,MAAM,OAAO;YAE1B,IAAM/B,MAAM+B,KAAK/E;YACjB,IAAID,QAAQ;YACZ,IAAIsI,YAAY;YAEhB,KAAKrF,KAAK,OAAO;YAEjB,IAAIsF,KAAKvD,KAAKhF;YAGd,IAAIuI,OAAO,OAAOA,OAAO,KAAK;gBAC5BA,KAAKvD,OAAOhF;AACd;YAEA,IAAIuI,OAAO,KAAK;gBAEd,IAAIvI,QAAQ,MAAMiD,KAAK,OAAO;gBAC9BsF,KAAKvD,OAAOhF;gBAIZ,IAAIuI,OAAO,KAAK;oBAEdvI;oBAEA,MAAOA,QAAQiD,KAAKjD,SAAS;wBAC3BuI,KAAKvD,KAAKhF;wBACV,IAAIuI,OAAO,OAAOA,OAAO,KAAK,OAAO;wBACrCD,YAAY;AACd;oBACA,OAAOA,aAAaE,SAASC,iBAAiBzD;AAChD;gBAEA,IAAIuD,OAAO,KAAK;oBAEdvI;oBAEA,MAAOA,QAAQiD,KAAKjD,SAAS;wBAC3B,KAAKiI,UAAUjD,KAAK0D,WAAW1I,SAAS,OAAO;wBAC/CsI,YAAY;AACd;oBACA,OAAOA,aAAaE,SAASC,iBAAiBzD;AAChD;gBAEA,IAAIuD,OAAO,KAAK;oBAEdvI;oBAEA,MAAOA,QAAQiD,KAAKjD,SAAS;wBAC3B,KAAKmI,UAAUnD,KAAK0D,WAAW1I,SAAS,OAAO;wBAC/CsI,YAAY;AACd;oBACA,OAAOA,aAAaE,SAASC,iBAAiBzD;AAChD;AACF;YAIA,MAAOhF,QAAQiD,KAAKjD,SAAS;gBAC3B,KAAKoI,UAAUpD,KAAK0D,WAAW1I,SAAS;oBACtC,OAAO;AACT;gBACAsI,YAAY;AACd;YAEA,KAAKA,WAAW,OAAO;YAEvB,OAAOE,SAASC,iBAAiBzD;AACnC;QAEA,SAASyD,iBAAkBzD;YACzB,IAAI2D,QAAQ3D;YACZ,IAAI4D,OAAO;YAEX,IAAIL,KAAKI,MAAM;YAEf,IAAIJ,OAAO,OAAOA,OAAO,KAAK;gBAC5B,IAAIA,OAAO,KAAKK,QAAO;gBACvBD,QAAQA,MAAM9F,MAAM;gBACpB0F,KAAKI,MAAM;AACb;YAEA,IAAIA,UAAU,KAAK,OAAO;YAE1B,IAAIJ,OAAO,KAAK;gBACd,IAAII,MAAM,OAAO,KAAK,OAAOC,OAAOC,SAASF,MAAM9F,MAAM,IAAI;gBAC7D,IAAI8F,MAAM,OAAO,KAAK,OAAOC,OAAOC,SAASF,MAAM9F,MAAM,IAAI;gBAC7D,IAAI8F,MAAM,OAAO,KAAK,OAAOC,OAAOC,SAASF,MAAM9F,MAAM,IAAI;AAC/D;YAEA,OAAO+F,OAAOC,SAASF,OAAO;AAChC;QAEA,SAASG,qBAAsB9D;YAC7B,OAAOyD,iBAAiBzD;AAC1B;QAEA,SAAS+D,UAAWzB;YAClB,OAAQxH,OAAOZ,UAAU6C,SAASL,KAAK4F,YAAa,qBAC5CA,SAAS,MAAM,MAAM1G,QAAOJ,eAAe8G;AACrD;QAEA0B,MAAiB,IAAItE,MAAK,yBAAyB;YACjDG,MAAM;YACNC,SAASuD;YACTtD,WAAW+D;YACX5D,WAAW6D;YACX5D,WAAW;gBACT8D,QAAQ,SAARA,QAAkBC;oBAAO,OAAOA,OAAO,IAAI,OAAOA,IAAInH,SAAS,KAAK,QAAQmH,IAAInH,SAAS,GAAGc,MAAM;;gBAClGsG,OAAO,SAAPA,MAAiBD;oBAAO,OAAOA,OAAO,IAAI,OAAOA,IAAInH,SAAS,KAAK,QAAQmH,IAAInH,SAAS,GAAGc,MAAM;;gBACjGuG,SAAS,SAATA,QAAmBF;oBAAO,OAAOA,IAAInH,SAAS;;gBAC9CsH,aAAa,SAAbA,YAAuBH;oBAAO,OAAOA,OAAO,IAAI,OAAOA,IAAInH,SAAS,IAAIuH,gBAAgB,QAAQJ,IAAInH,SAAS,IAAIuH,cAAczG,MAAM;AAAG;;YAE1IwC,cAAc;YACdE,cAAc;gBACZ0D,QAAQ,EAAC,GAAG;gBACZE,OAAO,EAAC,GAAG;gBACXC,SAAS,EAAC,IAAI;gBACdC,aAAa,EAAC,IAAI;;;;;;;;;;QCzItB,IAAMzI,UAASoB;QACf,IAAM0C,QAAOe;QAEb,IAAM8D,qBAAqB,IAAIC,OAE7B;QASF,IAAMC,6BAA6B,IAAID,OACrC;QAMF,SAASE,iBAAkB1E;YACzB,IAAIA,SAAS,MAAM,OAAO;YAE1B,KAAKuE,mBAAmBI,KAAK3E,OAAO;gBAClC,OAAO;AACT;YAEA,IAAIwD,SAASoB,WAAW5E,MAAM,MAAM;gBAClC,OAAO;AACT;YAEA,OAAOyE,2BAA2BE,KAAK3E;AACzC;QAEA,SAAS6E,mBAAoB7E;YAC3B,IAAI2D,QAAQ3D,KAAK8E;YACjB,IAAMlB,OAAOD,MAAM,OAAO,OAAM,IAAK;YAErC,IAAI,KAAK/D,QAAQ+D,MAAM,OAAO,GAAG;gBAC/BA,QAAQA,MAAM9F,MAAM;AACtB;YAEA,IAAI8F,UAAU,QAAQ;gBACpB,OAAQC,SAAS,IAAKlI,OAAOqJ,oBAAoBrJ,OAAOC;AAC1D,mBAAA,IAAWgI,UAAU,QAAQ;gBAC3B,OAAOqB;AACT;YACA,OAAOpB,OAAOgB,WAAWjB,OAAO;AAClC;QAEA,IAAMsB,yBAAyB;QAE/B,SAASC,mBAAoB5C,QAAQ/C;YACnC,IAAI4F,MAAM7C,SAAS;gBACjB,QAAQ/C;kBACN,KAAK;oBAAa,OAAO;;kBACzB,KAAK;oBAAa,OAAO;;kBACzB,KAAK;oBAAa,OAAO;;AAE7B,mBAAA,IAAW7D,OAAOqJ,sBAAsBzC,QAAQ;gBAC9C,QAAQ/C;kBACN,KAAK;oBAAa,OAAO;;kBACzB,KAAK;oBAAa,OAAO;;kBACzB,KAAK;oBAAa,OAAO;;AAE7B,mBAAA,IAAW7D,OAAOC,sBAAsB2G,QAAQ;gBAC9C,QAAQ/C;kBACN,KAAK;oBAAa,OAAO;;kBACzB,KAAK;oBAAa,OAAO;;kBACzB,KAAK;oBAAa,OAAO;;uBAElB3D,QAAOJ,eAAe8G,SAAS;gBACxC,OAAO;AACT;YAEA,IAAM8C,MAAM9C,OAAOvF,SAAS;YAK5B,OAAOkI,uBAAuBN,KAAKS,OAAOA,IAAItH,QAAQ,KAAK,QAAQsH;AACrE;QAEA,SAASC,QAAS/C;YAChB,OAAQxH,OAAOZ,UAAU6C,SAASL,KAAK4F,YAAY,sBAC3CA,SAAS,MAAM,KAAK1G,QAAOJ,eAAe8G;AACpD;QAEAgD,QAAiB,IAAI5F,MAAK,2BAA2B;YACnDG,MAAM;YACNC,SAAS4E;YACT3E,WAAW8E;YACX3E,WAAWmF;YACXlF,WAAW+E;YACX7E,cAAc;;;;;;;;;QCxFhBkF,OAAiBvI,kBAAsBtC,OAAO;YAC5C8G,UAAU,EACRf,gBACAwB,eACAC,cACAsD;;;;;;;;;QCNJC,OAAiBzI;;;;;;;;QCNjB,IAAM0C,QAAO1C;QAEb,IAAM0I,mBAAmB,IAAIlB,OAC3B;QAIF,IAAMmB,wBAAwB,IAAInB,OAChC;QAWF,SAASoB,qBAAsB5F;YAC7B,IAAIA,SAAS,MAAM,OAAO;YAC1B,IAAI0F,iBAAiB7G,KAAKmB,UAAU,MAAM,OAAO;YACjD,IAAI2F,sBAAsB9G,KAAKmB,UAAU,MAAM,OAAO;YACtD,OAAO;AACT;QAEA,SAAS6F,uBAAwB7F;YAC/B,IAAI8F,WAAW;YACf,IAAIC,QAAQ;YAEZ,IAAIpH,QAAQ+G,iBAAiB7G,KAAKmB;YAClC,IAAIrB,UAAU,MAAMA,QAAQgH,sBAAsB9G,KAAKmB;YAEvD,IAAIrB,UAAU,MAAM,MAAM,IAAIlC,MAAM;YAIpC,IAAMuJ,QAASrH,MAAM;YACrB,IAAMsH,SAAUtH,MAAM,KAAM;YAC5B,IAAMuH,OAAQvH,MAAM;YAEpB,KAAKA,MAAM,IAAI;gBACb,OAAO,IAAIwH,KAAKA,KAAKC,IAAIJ,MAAMC,OAAOC;AACxC;YAIA,IAAMG,QAAS1H,MAAM;YACrB,IAAM2H,UAAW3H,MAAM;YACvB,IAAM4H,UAAW5H,MAAM;YAEvB,IAAIA,MAAM,IAAI;gBACZmH,WAAWnH,MAAM,GAAGd,MAAM,GAAG;gBAC7B,OAAOiI,SAAS7K,SAAS,GAAG;oBAC1B6K,YAAY;AACd;gBACAA,YAAYA;AACd;YAIA,IAAInH,MAAM,IAAI;gBACZ,IAAM6H,UAAW7H,MAAM;gBACvB,IAAM8H,aAAa9H,MAAM,OAAO;gBAChCoH,SAASS,SAAS,KAAKC,YAAY;gBACnC,IAAI9H,MAAM,OAAO,cAAcoH;AACjC;YAEA,IAAMW,OAAO,IAAIP,KAAKA,KAAKC,IAAIJ,MAAMC,OAAOC,KAAKG,MAAMC,QAAQC,QAAQT;YAEvE,IAAIC,OAAOW,KAAKC,QAAQD,KAAKE,YAAYb;YAEzC,OAAOW;AACT;QAEA,SAASG,uBAAwBvE;YAC/B,OAAOA,OAAOwE;AAChB;QAEAC,YAAiB,IAAIrH,MAAK,+BAA+B;YACvDG,MAAM;YACNC,SAAS8F;YACT7F,WAAW8F;YACX5F,YAAYkG;YACZhG,WAAW0G;;;;;;;;;QCpFb,IAAMnH,QAAO1C;QAEb,SAASgK,iBAAkBhH;YACzB,OAAOA,SAAS,QAAQA,SAAS;AACnC;QAEAiH,QAAiB,IAAIvH,MAAK,2BAA2B;YACnDG,MAAM;YACNC,SAASkH;;;;;;;;;QCRX,IAAMtH,QAAO1C;QAGb,IAAMkK,aAAa;QAEnB,SAASC,kBAAmBnH;YAC1B,IAAIA,SAAS,MAAM,OAAO;YAE1B,IAAIoH,SAAS;YACb,IAAMnJ,MAAM+B,KAAK/E;YACjB,IAAMoE,OAAM6H;YAGZ,KAAA,IAASG,MAAM,GAAGA,MAAMpJ,KAAKoJ,OAAO;gBAClC,IAAMC,OAAOjI,KAAIO,QAAQI,KAAKuH,OAAOF;gBAGrC,IAAIC,OAAO,IAAI;gBAGf,IAAIA,OAAO,GAAG,OAAO;gBAErBF,UAAU;AACZ;YAGA,OAAQA,SAAS,MAAO;AAC1B;QAEA,SAASI,oBAAqBxH;YAC5B,IAAMyH,QAAQzH,KAAKlC,QAAQ,YAAY;YACvC,IAAMG,MAAMwJ,MAAMxM;YAClB,IAAMoE,OAAM6H;YACZ,IAAIQ,OAAO;YACX,IAAMpM,SAAS;YAIf,KAAA,IAAS+L,MAAM,GAAGA,MAAMpJ,KAAKoJ,OAAO;gBAClC,IAAKA,MAAM,MAAM,KAAMA,KAAK;oBAC1B/L,OAAOwD,KAAM4I,QAAQ,KAAM;oBAC3BpM,OAAOwD,KAAM4I,QAAQ,IAAK;oBAC1BpM,OAAOwD,KAAK4I,OAAO;AACrB;gBAEAA,OAAQA,QAAQ,IAAKrI,KAAIO,QAAQ6H,MAAMF,OAAOF;AAChD;YAIA,IAAMM,WAAY1J,MAAM,IAAK;YAE7B,IAAI0J,aAAa,GAAG;gBAClBrM,OAAOwD,KAAM4I,QAAQ,KAAM;gBAC3BpM,OAAOwD,KAAM4I,QAAQ,IAAK;gBAC1BpM,OAAOwD,KAAK4I,OAAO;AACrB,mBAAA,IAAWC,aAAa,IAAI;gBAC1BrM,OAAOwD,KAAM4I,QAAQ,KAAM;gBAC3BpM,OAAOwD,KAAM4I,QAAQ,IAAK;AAC5B,mBAAA,IAAWC,aAAa,IAAI;gBAC1BrM,OAAOwD,KAAM4I,QAAQ,IAAK;AAC5B;YAEA,OAAO,IAAIE,WAAWtM;AACxB;QAEA,SAASuM,oBAAqBvF;YAC5B,IAAIhH,SAAS;YACb,IAAIoM,OAAO;YACX,IAAMzJ,MAAMqE,OAAOrH;YACnB,IAAMoE,OAAM6H;YAIZ,KAAA,IAASG,MAAM,GAAGA,MAAMpJ,KAAKoJ,OAAO;gBAClC,IAAKA,MAAM,MAAM,KAAMA,KAAK;oBAC1B/L,UAAU+D,KAAKqI,QAAQ,KAAM;oBAC7BpM,UAAU+D,KAAKqI,QAAQ,KAAM;oBAC7BpM,UAAU+D,KAAKqI,QAAQ,IAAK;oBAC5BpM,UAAU+D,KAAIqI,OAAO;AACvB;gBAEAA,QAAQA,QAAQ,KAAKpF,OAAO+E;AAC9B;YAIA,IAAM7J,OAAOS,MAAM;YAEnB,IAAIT,SAAS,GAAG;gBACdlC,UAAU+D,KAAKqI,QAAQ,KAAM;gBAC7BpM,UAAU+D,KAAKqI,QAAQ,KAAM;gBAC7BpM,UAAU+D,KAAKqI,QAAQ,IAAK;gBAC5BpM,UAAU+D,KAAIqI,OAAO;AACvB,mBAAA,IAAWlK,SAAS,GAAG;gBACrBlC,UAAU+D,KAAKqI,QAAQ,KAAM;gBAC7BpM,UAAU+D,KAAKqI,QAAQ,IAAK;gBAC5BpM,UAAU+D,KAAKqI,QAAQ,IAAK;gBAC5BpM,UAAU+D,KAAI;AAChB,mBAAA,IAAW7B,SAAS,GAAG;gBACrBlC,UAAU+D,KAAKqI,QAAQ,IAAK;gBAC5BpM,UAAU+D,KAAKqI,QAAQ,IAAK;gBAC5BpM,UAAU+D,KAAI;gBACd/D,UAAU+D,KAAI;AAChB;YAEA,OAAO/D;AACT;QAEA,SAASwM,SAAU5D;YACjB,OAAOpJ,OAAOZ,UAAU6C,SAASL,KAAKwH,SAAS;AACjD;QAEAD,SAAiB,IAAIvE,MAAK,4BAA4B;YACpDG,MAAM;YACNC,SAASqH;YACTpH,WAAWyH;YACXtH,WAAW4H;YACX3H,WAAW0H;;;;;;;;;QCtHb,IAAMnI,QAAO1C;QAEb,IAAM+K,kBAAkBjN,OAAOZ,UAAU8N;QACzC,IAAMC,YAAYnN,OAAOZ,UAAU6C;QAEnC,SAASmL,gBAAiBlI;YACxB,IAAIA,SAAS,MAAM,OAAO;YAE1B,IAAMmI,aAAa,CAAA;YACnB,IAAM7F,SAAStC;YAEf,KAAA,IAAShF,QAAQ,GAAGC,SAASqH,OAAOrH,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACtE,IAAMoN,OAAO9F,OAAOtH;gBACpB,IAAIqN,aAAa;gBAEjB,IAAIJ,UAAUvL,KAAK0L,UAAU,mBAAmB,OAAO;gBAEvD,IAAIE,eAAO;gBACX,KAAKA,WAAWF,MAAM;oBACpB,IAAIL,gBAAgBrL,KAAK0L,MAAME,UAAU;wBACvC,KAAKD,YAAYA,aAAa,WACzB,OAAO;AACd;AACF;gBAEA,KAAKA,YAAY,OAAO;gBAExB,IAAIN,gBAAgBrL,KAAKyL,YAAYG,UAAU,OAAO;gBACtDxN,OAAOyN,eAAeJ,YAAYG,SAAS;oBAAE3E,OAAO;;AACtD;YAEA,OAAO;AACT;QAEA,SAAS6E,kBAAmBxI;YAC1B,OAAOA,SAAS,OAAOA,OAAO;AAChC;QAEAyI,OAAiB,IAAI/I,MAAK,0BAA0B;YAClDG,MAAM;YACNC,SAASoI;YACTnI,WAAWyI;;;;;;;;;QCzCb,IAAM9I,QAAO1C;QAEb,IAAMiL,YAAYnN,OAAOZ,UAAU6C;QAEnC,SAAS2L,iBAAkB1I;YACzB,IAAIA,SAAS,MAAM,OAAO;YAE1B,IAAMsC,SAAStC;YAEf,IAAM1E,SAAS,IAAId,MAAM8H,OAAOrH;YAEhC,KAAA,IAASD,QAAQ,GAAGC,SAASqH,OAAOrH,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACtE,IAAMoN,OAAO9F,OAAOtH;gBAEpB,IAAIiN,UAAUvL,KAAK0L,UAAU,mBAAmB,OAAO;gBAEvD,IAAMrN,OAAOD,OAAOC,KAAKqN;gBAEzB,IAAIrN,KAAKE,WAAW,GAAG,OAAO;gBAE9BK,OAAON,SAAS,EAACD,KAAK,IAAIqN,KAAKrN,KAAK;AACtC;YAEA,OAAO;AACT;QAEA,SAAS4N,mBAAoB3I;YAC3B,IAAIA,SAAS,MAAM,OAAO;YAE1B,IAAMsC,SAAStC;YACf,IAAM1E,SAAS,IAAId,MAAM8H,OAAOrH;YAEhC,KAAA,IAASD,QAAQ,GAAGC,SAASqH,OAAOrH,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACtE,IAAMoN,OAAO9F,OAAOtH;gBAEpB,IAAMD,OAAOD,OAAOC,KAAKqN;gBAEzB9M,OAAON,SAAS,EAACD,KAAK,IAAIqN,KAAKrN,KAAK;AACtC;YAEA,OAAOO;AACT;QAEAsN,QAAiB,IAAIlJ,MAAK,2BAA2B;YACnDG,MAAM;YACNC,SAAS4I;YACT3I,WAAW4I;;;;;;;;;QC9Cb,IAAMjJ,QAAO1C;QAEb,IAAM+K,kBAAkBjN,OAAOZ,UAAU8N;QAEzC,SAASa,eAAgB7I;YACvB,IAAIA,SAAS,MAAM,OAAO;YAE1B,IAAMsC,SAAStC;YAEf,KAAA,IAAW9E,OAAOoH,QAAQ;gBACxB,IAAIyF,gBAAgBrL,KAAK4F,QAAQpH,MAAM;oBACrC,IAAIoH,OAAOpH,SAAS,MAAM,OAAO;AACnC;AACF;YAEA,OAAO;AACT;QAEA,SAAS4N,iBAAkB9I;YACzB,OAAOA,SAAS,OAAOA,OAAO,CAAA;AAChC;QAEA+I,MAAiB,IAAIrJ,MAAK,yBAAyB;YACjDG,MAAM;YACNC,SAAS+I;YACT9I,WAAW+I;;;;;;;;;QCnBbE,WAAiBhM,cAAkBtC,OAAO;YACxC8G,UAAU,EACRf,oBACAwB;YAEFR,UAAU,EACRS,iBACAsD,eACAyD,gBACAC;;;;;;;;QCjBQ,SAAArP,QAAAC;YAAA;YAAA,OAAAD,UAAA,qBAAAE,UAAA,mBAAAA,OAAAC,WAAA,SAAAF;gBAAA,cAAAA;gBAAA,SAAAA;gBAAA,OAAAA,MAAA,qBAAAC,UAAAD,GAAAG,gBAAAF,UAAAD,OAAAC,OAAAG,YAAA,kBAAAJ;AAAA,eAAAD,QAAAC;AAAA;QAEZ,IAAM8B,UAASoB;QACf,IAAMR,iBAAgBiE;QACtB,IAAMvC,cAAc+D;QACpB,IAAMkH,kBAAiBjH;QAEvB,IAAM6F,kBAAkBjN,OAAOZ,UAAU8N;QAEzC,IAAMoB,kBAAkB;QACxB,IAAMC,mBAAmB;QACzB,IAAMC,mBAAmB;QACzB,IAAMC,oBAAoB;QAE1B,IAAMC,gBAAgB;QACtB,IAAMC,iBAAiB;QACvB,IAAMC,gBAAgB;QAGtB,IAAMC,wBAAwB;QAC9B,IAAMC,gCAAgC;QAEtC,IAAMC,0BAA0B;QAEhC,IAAMC,qBAAqB;QAE3B,IAAMC,kBAAkB;QAExB,SAASC,OAAQ9F;YAAO,OAAOpJ,OAAOZ,UAAU6C,SAASL,KAAKwH;AAAK;QAEnE,SAAS+F,MAAO/G;YACd,OAAQA,MAAM,MAAkBA,MAAM;AACxC;QAEA,SAASgH,aAAchH;YACrB,OAAQA,MAAM,KAAmBA,MAAM;AACzC;QAEA,SAASiH,UAAWjH;YAClB,OAAQA,MAAM,KACNA,MAAM,MACNA,MAAM,MACNA,MAAM;AAChB;QAEA,SAASkH,gBAAiBlH;YACxB,OAAOA,MAAM,MACNA,MAAM,MACNA,MAAM,MACNA,MAAM,OACNA,MAAM;AACf;QAEA,SAASmH,YAAanH;YACpB,IAAKA,KAAK,MAAiBA,KAAK,IAAc;gBAC5C,OAAOA,IAAI;AACb;YAEA,IAAMoH,KAAKpH,IAAI;YAEf,IAAKoH,MAAM,MAAiBA,MAAM,KAAc;gBAC9C,OAAOA,KAAK,KAAO;AACrB;YAEA,QAAO;AACT;QAEA,SAASC,cAAerH;YACtB,IAAIA,MAAM,KAAa;gBAAE,OAAO;AAAE;YAClC,IAAIA,MAAM,KAAa;gBAAE,OAAO;AAAE;YAClC,IAAIA,MAAM,IAAa;gBAAE,OAAO;AAAE;YAClC,OAAO;AACT;QAEA,SAASsH,gBAAiBtH;YACxB,IAAKA,KAAK,MAAiBA,KAAK,IAAc;gBAC5C,OAAOA,IAAI;AACb;YAEA,QAAO;AACT;QAEA,SAASuH,qBAAsBvH;YAC7B,QAAQA;cACN,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAe,OAAO;;cAC3B,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAiB,OAAO;;cAC7B,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB,KAAK;gBAAa,OAAO;;cACzB;gBAAS,OAAO;;AAEpB;QAEA,SAASwH,kBAAmBxH;YAC1B,IAAIA,KAAK,OAAQ;gBACf,OAAOzD,OAAOkL,aAAazH;AAC7B;YAGA,OAAOzD,OAAOkL,cACVzH,IAAI,SAAa,MAAM,QACvBA,IAAI,QAAY,QAAU;AAEhC;QAIA,SAAS0H,YAAatI,QAAQpH,KAAKyI;YAEjC,IAAIzI,QAAQ,aAAa;gBACvBJ,OAAOyN,eAAejG,QAAQpH,KAAK;oBACjC2P,cAAc;oBACdC,YAAY;oBACZC,UAAU;oBACVpH;;AAEJ,mBAAO;gBACLrB,OAAOpH,OAAOyI;AAChB;AACF;QAEA,IAAMqH,oBAAoB,IAAIxQ,MAAM;QACpC,IAAMyQ,kBAAkB,IAAIzQ,MAAM;QAClC,KAAA,IAASyE,IAAI,GAAGA,IAAI,KAAKA,KAAK;YAC5B+L,kBAAkB/L,KAAKwL,qBAAqBxL,KAAK,IAAI;YACrDgM,gBAAgBhM,KAAKwL,qBAAqBxL;AAC5C;QAEA,SAASiM,MAAOzD,OAAOtJ;YACrBxB,KAAK8K,QAAQA;YAEb9K,KAAKwO,WAAWhN,QAAQ,eAAe;YACvCxB,KAAKgE,SAASxC,QAAQ,aAAagL;YACnCxM,KAAKyO,YAAYjN,QAAQ,gBAAgB;YAGzCxB,KAAK0O,SAASlN,QAAQ,aAAa;YAEnCxB,KAAK4I,OAAOpH,QAAQ,WAAW;YAC/BxB,KAAK2O,WAAWnN,QAAQ,eAAe;YACvCxB,KAAK4O,kBAAkBpN,QAAQ,gBAAgB,WAAWA,QAAQ,cAAc;YAChFxB,KAAK6O,2BAA2BrN,QAAQ,yBAAyB,WAAWA,QAAQ,uBAAuB;YAE3GxB,KAAK8O,gBAAgB9O,KAAKgE,OAAOiB;YACjCjF,KAAK+O,UAAU/O,KAAKgE,OAAOmB;YAE3BnF,KAAK1B,SAASwM,MAAMxM;YACpB0B,KAAKU,WAAW;YAChBV,KAAKN,OAAO;YACZM,KAAKQ,YAAY;YACjBR,KAAKgP,aAAa;YAClBhP,KAAKiP,QAAQ;YACbjP,KAAKkP,iBAAiB;YAItBlP,KAAKmP,kBAAiB;YAEtBnP,KAAKoP,YAAY;YACjBpP,KAAKqP,wBAAwB;AAW/B;QAEA,SAASC,cAAeC,OAAOjQ;YAC7B,IAAME,OAAO;gBACXC,MAAM8P,MAAMf;gBACZjO,QAAQgP,MAAMzE,MAAM5J,MAAM,IAAG;gBAC7BR,UAAU6O,MAAM7O;gBAChBhB,MAAM6P,MAAM7P;gBACZC,QAAQ4P,MAAM7O,WAAW6O,MAAM/O;;YAGjChB,KAAKI,UAAU2B,YAAY/B;YAE3B,OAAO,IAAIK,eAAcP,SAASE;AACpC;QAEA,SAASgQ,WAAYD,OAAOjQ;YAC1B,MAAMgQ,cAAcC,OAAOjQ;AAC7B;QAEA,SAASmQ,aAAcF,OAAOjQ;YAC5B,IAAIiQ,MAAMd,WAAW;gBACnBc,MAAMd,UAAU1O,KAAK,MAAMuP,cAAcC,OAAOjQ;AAClD;AACF;QAEA,SAASoQ,YAAaH,OAAO9P,MAAMuH;YACjC,IAAM2I,eAAeJ,MAAMF;YAE3B,IAAIM,aAAarR,WAAW,GAAG;gBAC7B,IAAMsR,cAAcD,aAAaA,aAAarR,SAAS;gBAEvD,KAAK8M,gBAAgBrL,KAAK6P,aAAanQ,OAAO;oBAC5CmQ,YAAYnQ,QAAQ;wBAClBoQ,SAASzE,gBAAgBrL,KAAKwP,MAAMO,WAAWrQ;wBAC/CuH,OAAOuI,MAAMO,UAAUrQ;;AAE3B;AACF;YAEA8P,MAAMO,UAAUrQ,QAAQuH;AAC1B;QAEA,SAAS+I,uBAAwBR;YAC/BA,MAAMF,sBAAsBlN,KAAKhE,OAAOgC,OAAO;AACjD;QAEA,SAAS6P,wBAAyBT;YAChC,IAAMK,cAAcL,MAAMF,sBAAsBY;YAChD,IAAMN,eAAeJ,MAAMF;YAE3B,IAAIM,aAAarR,WAAW,GAAG;YAE/B,IAAM4R,SAASP,aAAaA,aAAarR,SAAS;YAClD,IAAM6R,QAAQhS,OAAOC,KAAKwR;YAE1B,KAAA,IAASvR,QAAQ,GAAGC,SAAS6R,MAAM7R,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACrE,IAAMoB,OAAO0Q,MAAM9R;gBAEnB,KAAK+M,gBAAgBrL,KAAKmQ,QAAQzQ,OAAO;oBACvCyQ,OAAOzQ,QAAQmQ,YAAYnQ;AAC7B;AACF;AACF;QAEA,SAAS2Q,0BAA2Bb;YAClC,IAAMK,cAAcL,MAAMF,sBAAsBY;YAChD,IAAME,QAAQhS,OAAOC,KAAKwR;YAE1B,KAAA,IAASvR,QAAQ8R,MAAM7R,SAAS,GAAGD,SAAS,GAAGA,SAAS,GAAG;gBACzD,IAAMgS,QAAQT,YAAYO,MAAM9R;gBAEhC,IAAIgS,MAAMR,SAAS;oBACjBN,MAAMO,UAAUK,MAAM9R,UAAUgS,MAAMrJ;AACxC,uBAAO;2BACEuI,MAAMO,UAAUK,MAAM9R;AAC/B;AACF;AACF;QAEA,SAASiS,cAAef;YACtB,OAAO;gBACL7O,UAAU6O,MAAM7O;gBAChBhB,MAAM6P,MAAM7P;gBACZc,WAAW+O,MAAM/O;gBACjBwO,YAAYO,MAAMP;gBAClBG,gBAAgBI,MAAMJ;gBACtBnM,KAAKuM,MAAMvM;gBACXuN,QAAQhB,MAAMgB;gBACdrN,MAAMqM,MAAMrM;gBACZvE,QAAQ4Q,MAAM5Q;;AAElB;QAEA,SAAS6R,aAAcjB,OAAOkB;YAC5BlB,MAAM7O,WAAW+P,SAAS/P;YAC1B6O,MAAM7P,OAAO+Q,SAAS/Q;YACtB6P,MAAM/O,YAAYiQ,SAASjQ;YAC3B+O,MAAMP,aAAayB,SAASzB;YAC5BO,MAAMJ,iBAAiBsB,SAAStB;YAChCI,MAAMvM,MAAMyN,SAASzN;YACrBuM,MAAMgB,SAASE,SAASF;YACxBhB,MAAMrM,OAAOuN,SAASvN;YACtBqM,MAAM5Q,SAAS8R,SAAS9R;AAC1B;QAEA,IAAM+R,oBAAoB;YAExBC,MAAM,SAASC,oBAAqBrB,OAAO9P,MAAMoR;gBAC/C,IAAItB,MAAMuB,YAAY,MAAM;oBAC1BtB,WAAWD,OAAO;AACpB;gBAEA,IAAIsB,KAAKvS,WAAW,GAAG;oBACrBkR,WAAWD,OAAO;AACpB;gBAEA,IAAMvN,QAAQ,uBAAuBE,KAAK2O,KAAK;gBAE/C,IAAI7O,UAAU,MAAM;oBAClBwN,WAAWD,OAAO;AACpB;gBAEA,IAAMwB,QAAQ7J,SAASlF,MAAM,IAAI;gBACjC,IAAMgP,QAAQ9J,SAASlF,MAAM,IAAI;gBAEjC,IAAI+O,UAAU,GAAG;oBACfvB,WAAWD,OAAO;AACpB;gBAEAA,MAAMuB,UAAUD,KAAK;gBACrBtB,MAAM0B,kBAAmBD,QAAQ;gBAEjC,IAAIA,UAAU,KAAKA,UAAU,GAAG;oBAC9BvB,aAAaF,OAAO;AACtB;;YAGF2B,KAAK,SAASC,mBAAoB5B,OAAO9P,MAAMoR;gBAC7C,IAAIO;gBAEJ,IAAIP,KAAKvS,WAAW,GAAG;oBACrBkR,WAAWD,OAAO;AACpB;gBAEA,IAAM8B,SAASR,KAAK;gBACpBO,SAASP,KAAK;gBAEd,KAAK1D,mBAAmBnF,KAAKqJ,SAAS;oBACpC7B,WAAWD,OAAO;AACpB;gBAEA,IAAInE,gBAAgBrL,KAAKwP,MAAM+B,QAAQD,SAAS;oBAC9C7B,WAAWD,OAAO,gDAAgD8B,SAAS;AAC7E;gBAEA,KAAKjE,gBAAgBpF,KAAKoJ,SAAS;oBACjC5B,WAAWD,OAAO;AACpB;gBAEA;oBACE6B,SAASG,mBAAmBH;yBACrBI;oBACPhC,WAAWD,OAAO,8BAA8B6B;AAClD;gBAEA7B,MAAM+B,OAAOD,UAAUD;AACzB;;QAGF,SAASK,eAAgBlC,OAAOmC,OAAOC,KAAKC;YAC1C,IAAIF,QAAQC,KAAK;gBACf,IAAME,UAAUtC,MAAMzE,MAAM5J,MAAMwQ,OAAOC;gBAEzC,IAAIC,WAAW;oBACb,KAAA,IAASE,YAAY,GAAGC,UAAUF,QAAQvT,QAAQwT,YAAYC,SAASD,aAAa,GAAG;wBACrF,IAAME,aAAaH,QAAQ9K,WAAW+K;wBACtC,MAAME,eAAe,KACdA,cAAc,MAAQA,cAAc,UAAY;4BACrDxC,WAAWD,OAAO;AACpB;AACF;2BACSvC,sBAAsBhF,KAAK6J,UAAU;oBAC9CrC,WAAWD,OAAO;AACpB;gBAEAA,MAAM5Q,UAAUkT;AAClB;AACF;QAEA,SAASI,cAAe1C,OAAO2C,aAAajU,QAAQkU;YAClD,KAAKlT,QAAOvB,SAASO,SAAS;gBAC5BuR,WAAWD,OAAO;AACpB;YAEA,IAAMrR,aAAaC,OAAOC,KAAKH;YAE/B,KAAA,IAASI,QAAQ,GAAG+T,WAAWlU,WAAWI,QAAQD,QAAQ+T,UAAU/T,SAAS,GAAG;gBAC9E,IAAME,MAAML,WAAWG;gBAEvB,IAAIkR,MAAMV,uBAAsB,OAAQU,MAAML,iBAAiBK,MAAMV,mBAAmB;oBACtFW,WAAWD,OAAO,4CAA4CA,MAAMV,oBAAoB;AAC1F;gBAEA,KAAKzD,gBAAgBrL,KAAKmS,aAAa3T,MAAM;oBAC3C0P,YAAYiE,aAAa3T,KAAKN,OAAOM;oBACrC4T,gBAAgB5T,OAAO;AACzB;AACF;AACF;QAEA,SAAS8T,iBAAkB9C,OAAOsC,SAASM,iBAAiBG,QAAQC,SAASC,WAC3EC,WAAWC,gBAAgBC;YAI3B,IAAI9U,MAAMC,QAAQyU,UAAU;gBAC1BA,UAAU1U,MAAMN,UAAU2D,MAAMnB,KAAKwS;gBAErC,KAAA,IAASlU,QAAQ,GAAG+T,WAAWG,QAAQjU,QAAQD,QAAQ+T,UAAU/T,SAAS,GAAG;oBAC3E,IAAIR,MAAMC,QAAQyU,QAAQlU,SAAS;wBACjCmR,WAAWD,OAAO;AACpB;oBAEA,IAAIrS,QAAOqV,aAAY,YAAYlF,OAAOkF,QAAQlU,YAAY,mBAAmB;wBAC/EkU,QAAQlU,SAAS;AACnB;AACF;AACF;YAKA,IAAInB,QAAOqV,aAAY,YAAYlF,OAAOkF,aAAa,mBAAmB;gBACxEA,UAAU;AACZ;YAEAA,UAAUzP,OAAOyP;YAEjB,IAAIV,YAAY,MAAM;gBACpBA,UAAU,CAAA;AACZ;YAEA,IAAIS,WAAW,2BAA2B;gBACxC,IAAIzU,MAAMC,QAAQ0U,YAAY;oBAC5B,KAAA,IAASnU,SAAQ,GAAG+T,YAAWI,UAAUlU,QAAQD,SAAQ+T,WAAU/T,UAAS,GAAG;wBAC7E4T,cAAc1C,OAAOsC,SAASW,UAAUnU,SAAQ8T;AAClD;AACF,uBAAO;oBACLF,cAAc1C,OAAOsC,SAASW,WAAWL;AAC3C;AACF,mBAAO;gBACL,KAAK5C,MAAM3G,SACNwC,gBAAgBrL,KAAKoS,iBAAiBI,YACvCnH,gBAAgBrL,KAAK8R,SAASU,UAAU;oBAC1ChD,MAAM7P,OAAO+S,aAAalD,MAAM7P;oBAChC6P,MAAM/O,YAAYkS,kBAAkBnD,MAAM/O;oBAC1C+O,MAAM7O,WAAWiS,YAAYpD,MAAM7O;oBACnC8O,WAAWD,OAAO;AACpB;gBAEAtB,YAAY4D,SAASU,SAASC;uBACvBL,gBAAgBI;AACzB;YAEA,OAAOV;AACT;QAEA,SAASe,cAAerD;YACtB,IAAM3I,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAExC,IAAIkG,OAAO,IAAc;gBACvB2I,MAAM7O;AACR,mBAAA,IAAWkG,OAAO,IAAc;gBAC9B2I,MAAM7O;gBACN,IAAI6O,MAAMzE,MAAM/D,WAAWwI,MAAM7O,cAAc,IAAc;oBAC3D6O,MAAM7O;AACR;AACF,mBAAO;gBACL8O,WAAWD,OAAO;AACpB;YAEAA,MAAM7P,QAAQ;YACd6P,MAAM/O,YAAY+O,MAAM7O;YACxB6O,MAAMJ,kBAAiB;AACzB;QAEA,SAAS0D,oBAAqBtD,OAAOuD,eAAeC;YAClD,IAAIC,aAAa;YACjB,IAAIpM,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,OAAOkG,OAAO,GAAG;gBACf,OAAO2G,aAAa3G,KAAK;oBACvB,IAAIA,OAAO,KAAiB2I,MAAMJ,oBAAmB,GAAI;wBACvDI,MAAMJ,iBAAiBI,MAAM7O;AAC/B;oBACAkG,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;gBAEA,IAAIoS,iBAAiBlM,OAAO,IAAa;oBACvC,GAAG;wBACDA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;6BAC7BkG,OAAO,MAAgBA,OAAO,MAAgBA,OAAO;AAChE;gBAEA,IAAI0G,MAAM1G,KAAK;oBACbgM,cAAcrD;oBAEd3I,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;oBAClCsS;oBACAzD,MAAMP,aAAa;oBAEnB,OAAOpI,OAAO,IAAiB;wBAC7B2I,MAAMP;wBACNpI,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;AACF,uBAAO;oBACL;AACF;AACF;YAEA,IAAIqS,iBAAgB,KAAMC,eAAe,KAAKzD,MAAMP,aAAa+D,aAAa;gBAC5EtD,aAAaF,OAAO;AACtB;YAEA,OAAOyD;AACT;QAEA,SAASC,sBAAuB1D;YAC9B,IAAIuC,YAAYvC,MAAM7O;YACtB,IAAIkG,KAAK2I,MAAMzE,MAAM/D,WAAW+K;YAIhC,KAAKlL,OAAO,MAAeA,OAAO,OAC9BA,OAAO2I,MAAMzE,MAAM/D,WAAW+K,YAAY,MAC1ClL,OAAO2I,MAAMzE,MAAM/D,WAAW+K,YAAY,IAAI;gBAChDA,aAAa;gBAEblL,KAAK2I,MAAMzE,MAAM/D,WAAW+K;gBAE5B,IAAIlL,OAAO,KAAK4G,UAAU5G,KAAK;oBAC7B,OAAO;AACT;AACF;YAEA,OAAO;AACT;QAEA,SAASsM,iBAAkB3D,OAAO7Q;YAChC,IAAIA,UAAU,GAAG;gBACf6Q,MAAM5Q,UAAU;AAClB,mBAAA,IAAWD,QAAQ,GAAG;gBACpB6Q,MAAM5Q,UAAUM,QAAOT,OAAO,MAAME,QAAQ;AAC9C;AACF;QAEA,SAASyU,gBAAiB5D,OAAO6D,YAAYC;YAC3C,IAAIC;YACJ,IAAIC;YACJ,IAAIC;YACJ,IAAIC;YACJ,IAAIC;YACJ,IAAIC;YACJ,IAAMC,QAAQrE,MAAMrM;YACpB,IAAM2O,UAAUtC,MAAM5Q;YAEtB,IAAIiI,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,IAAI8M,UAAU5G,OACV6G,gBAAgB7G,OAChBA,OAAO,MACPA,OAAO,MACPA,OAAO,MACPA,OAAO,MACPA,OAAO,OACPA,OAAO,MACPA,OAAO,MACPA,OAAO,MACPA,OAAO,MACPA,OAAO,MACPA,OAAO,IAAa;gBACtB,OAAO;AACT;YAEA,IAAIA,OAAO,MAAeA,OAAO,IAAa;gBAC5C,IAAMiN,YAAYtE,MAAMzE,MAAM/D,WAAWwI,MAAM7O,WAAW;gBAE1D,IAAI8M,UAAUqG,cACTR,wBAAwB5F,gBAAgBoG,YAAa;oBACxD,OAAO;AACT;AACF;YAEAtE,MAAMrM,OAAO;YACbqM,MAAM5Q,SAAS;YACf2U,eAAeC,aAAahE,MAAM7O;YAClC8S,oBAAoB;YAEpB,OAAO5M,OAAO,GAAG;gBACf,IAAIA,OAAO,IAAa;oBACtB,IAAMiN,aAAYtE,MAAMzE,MAAM/D,WAAWwI,MAAM7O,WAAW;oBAE1D,IAAI8M,UAAUqG,eACTR,wBAAwB5F,gBAAgBoG,aAAa;wBACxD;AACF;AACF,uBAAA,IAAWjN,OAAO,IAAa;oBAC7B,IAAMkN,YAAYvE,MAAMzE,MAAM/D,WAAWwI,MAAM7O,WAAW;oBAE1D,IAAI8M,UAAUsG,YAAY;wBACxB;AACF;2BACUvE,MAAM7O,aAAa6O,MAAM/O,aAAayS,sBAAsB1D,UAC5D8D,wBAAwB5F,gBAAgB7G,KAAM;oBACxD;AACF,uBAAA,IAAW0G,MAAM1G,KAAK;oBACpB6M,QAAQlE,MAAM7P;oBACdgU,aAAanE,MAAM/O;oBACnBmT,cAAcpE,MAAMP;oBACpB6D,oBAAoBtD,OAAO,QAAO;oBAElC,IAAIA,MAAMP,cAAcoE,YAAY;wBAClCI,oBAAoB;wBACpB5M,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;wBAClC;AACF,2BAAO;wBACL6O,MAAM7O,WAAW6S;wBACjBhE,MAAM7P,OAAO+T;wBACblE,MAAM/O,YAAYkT;wBAClBnE,MAAMP,aAAa2E;wBACnB;AACF;AACF;gBAEA,IAAIH,mBAAmB;oBACrB/B,eAAelC,OAAO+D,cAAcC,YAAY;oBAChDL,iBAAiB3D,OAAOA,MAAM7P,OAAO+T;oBACrCH,eAAeC,aAAahE,MAAM7O;oBAClC8S,oBAAoB;AACtB;gBAEA,KAAKjG,aAAa3G,KAAK;oBACrB2M,aAAahE,MAAM7O,WAAW;AAChC;gBAEAkG,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;YAEA+Q,eAAelC,OAAO+D,cAAcC,YAAY;YAEhD,IAAIhE,MAAM5Q,QAAQ;gBAChB,OAAO;AACT;YAEA4Q,MAAMrM,OAAO0Q;YACbrE,MAAM5Q,SAASkT;YACf,OAAO;AACT;QAEA,SAASkC,uBAAwBxE,OAAO6D;YACtC,IAAIE;YACJ,IAAIC;YAEJ,IAAI3M,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,IAAIkG,OAAO,IAAa;gBACtB,OAAO;AACT;YAEA2I,MAAMrM,OAAO;YACbqM,MAAM5Q,SAAS;YACf4Q,MAAM7O;YACN4S,eAAeC,aAAahE,MAAM7O;YAElC,QAAQkG,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O,eAAe,GAAG;gBAC1D,IAAIkG,OAAO,IAAa;oBACtB6K,eAAelC,OAAO+D,cAAc/D,MAAM7O,UAAU;oBACpDkG,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;oBAEpC,IAAIkG,OAAO,IAAa;wBACtB0M,eAAe/D,MAAM7O;wBACrB6O,MAAM7O;wBACN6S,aAAahE,MAAM7O;AACrB,2BAAO;wBACL,OAAO;AACT;AACF,uBAAA,IAAW4M,MAAM1G,KAAK;oBACpB6K,eAAelC,OAAO+D,cAAcC,YAAY;oBAChDL,iBAAiB3D,OAAOsD,oBAAoBtD,OAAO,OAAO6D;oBAC1DE,eAAeC,aAAahE,MAAM7O;AACpC,2BAAW6O,MAAM7O,aAAa6O,MAAM/O,aAAayS,sBAAsB1D,QAAQ;oBAC7EC,WAAWD,OAAO;AACpB,uBAAO;oBACLA,MAAM7O;oBACN,KAAK6M,aAAa3G,KAAK;wBACrB2M,aAAahE,MAAM7O;AACrB;AACF;AACF;YAEA8O,WAAWD,OAAO;AACpB;QAEA,SAASyE,uBAAwBzE,OAAO6D;YACtC,IAAIE;YACJ,IAAIC;YACJ,IAAIU;YAEJ,IAAIrN,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,IAAIkG,OAAO,IAAa;gBACtB,OAAO;AACT;YAEA2I,MAAMrM,OAAO;YACbqM,MAAM5Q,SAAS;YACf4Q,MAAM7O;YACN4S,eAAeC,aAAahE,MAAM7O;YAElC,QAAQkG,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O,eAAe,GAAG;gBAC1D,IAAIkG,OAAO,IAAa;oBACtB6K,eAAelC,OAAO+D,cAAc/D,MAAM7O,UAAU;oBACpD6O,MAAM7O;oBACN,OAAO;AACT,uBAAA,IAAWkG,OAAO,IAAa;oBAC7B6K,eAAelC,OAAO+D,cAAc/D,MAAM7O,UAAU;oBACpDkG,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;oBAEpC,IAAI4M,MAAM1G,KAAK;wBACbiM,oBAAoBtD,OAAO,OAAO6D;+BAGzBxM,KAAK,OAAOyH,kBAAkBzH,KAAK;wBAC5C2I,MAAM5Q,UAAU2P,gBAAgB1H;wBAChC2I,MAAM7O;gCACIuT,MAAMrG,cAAchH,OAAO,GAAG;wBACxC,IAAIsN,YAAYD;wBAChB,IAAIE,YAAY;wBAEhB,MAAOD,YAAY,GAAGA,aAAa;4BACjCtN,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;4BAEpC,KAAKuT,MAAMvG,YAAY9G,QAAQ,GAAG;gCAChCuN,aAAaA,aAAa,KAAKF;AACjC,mCAAO;gCACLzE,WAAWD,OAAO;AACpB;AACF;wBAEAA,MAAM5Q,UAAUoP,kBAAkBoG;wBAElC5E,MAAM7O;AACR,2BAAO;wBACL8O,WAAWD,OAAO;AACpB;oBAEA+D,eAAeC,aAAahE,MAAM7O;AACpC,uBAAA,IAAW4M,MAAM1G,KAAK;oBACpB6K,eAAelC,OAAO+D,cAAcC,YAAY;oBAChDL,iBAAiB3D,OAAOsD,oBAAoBtD,OAAO,OAAO6D;oBAC1DE,eAAeC,aAAahE,MAAM7O;AACpC,2BAAW6O,MAAM7O,aAAa6O,MAAM/O,aAAayS,sBAAsB1D,QAAQ;oBAC7EC,WAAWD,OAAO;AACpB,uBAAO;oBACLA,MAAM7O;oBACN,KAAK6M,aAAa3G,KAAK;wBACrB2M,aAAahE,MAAM7O;AACrB;AACF;AACF;YAEA8O,WAAWD,OAAO;AACpB;QAEA,SAAS6E,mBAAoB7E,OAAO6D;YAClC,IAAIiB,WAAW;YACf,IAAIZ;YACJ,IAAIC;YACJ,IAAIY;YACJ,IAAMC,OAAOhF,MAAMvM;YACnB,IAAI6O;YACJ,IAAM2C,UAAUjF,MAAMgB;YACtB,IAAIkE;YACJ,IAAIC;YACJ,IAAIC;YACJ,IAAIC;YACJ,IAAMzC,kBAAkBhU,OAAOgC,OAAO;YACtC,IAAIoS;YACJ,IAAID;YACJ,IAAIE;YAEJ,IAAI5L,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,IAAIkG,OAAO,IAAa;gBACtB6N,aAAa;gBACbG,YAAY;gBACZ/C,UAAU;AACZ,mBAAA,IAAWjL,OAAO,KAAa;gBAC7B6N,aAAa;gBACbG,YAAY;gBACZ/C,UAAU,CAAA;AACZ,mBAAO;gBACL,OAAO;AACT;YAEA,IAAItC,MAAMgB,WAAW,MAAM;gBACzBb,YAAYH,OAAOA,MAAMgB,QAAQsB;AACnC;YAEAjL,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;YAEpC,OAAOkG,OAAO,GAAG;gBACfiM,oBAAoBtD,OAAO,MAAM6D;gBAEjCxM,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;gBAElC,IAAIkG,OAAO6N,YAAY;oBACrBlF,MAAM7O;oBACN6O,MAAMvM,MAAMuR;oBACZhF,MAAMgB,SAASiE;oBACfjF,MAAMrM,OAAO0R,YAAY,YAAY;oBACrCrF,MAAM5Q,SAASkT;oBACf,OAAO;AACT,uBAAA,KAAYwC,UAAU;oBACpB7E,WAAWD,OAAO;AACpB,uBAAA,IAAW3I,OAAO,IAAa;oBAE7B4I,WAAWD,OAAO;AACpB;gBAEA+C,SAASC,UAAUC,YAAY;gBAC/BkC,SAASC,iBAAiB;gBAE1B,IAAI/N,OAAO,IAAa;oBACtB,IAAMiN,YAAYtE,MAAMzE,MAAM/D,WAAWwI,MAAM7O,WAAW;oBAE1D,IAAI8M,UAAUqG,YAAY;wBACxBa,SAASC,iBAAiB;wBAC1BpF,MAAM7O;wBACNmS,oBAAoBtD,OAAO,MAAM6D;AACnC;AACF;gBAEAK,QAAQlE,MAAM7P;gBACdgU,aAAanE,MAAM/O;gBACnB8T,OAAO/E,MAAM7O;gBACbmU,YAAYtF,OAAO6D,YAAY3G,iBAAiB,OAAO;gBACvD6F,SAAS/C,MAAMvM;gBACfuP,UAAUhD,MAAM5Q;gBAChBkU,oBAAoBtD,OAAO,MAAM6D;gBAEjCxM,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;gBAElC,KAAKiU,kBAAkBpF,MAAM7P,SAAS+T,UAAU7M,OAAO,IAAa;oBAClE8N,SAAS;oBACT9N,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;oBACpCmS,oBAAoBtD,OAAO,MAAM6D;oBACjCyB,YAAYtF,OAAO6D,YAAY3G,iBAAiB,OAAO;oBACvD+F,YAAYjD,MAAM5Q;AACpB;gBAEA,IAAIiW,WAAW;oBACbvC,iBAAiB9C,OAAOsC,SAASM,iBAAiBG,QAAQC,SAASC,WAAWiB,OAAOC,YAAYY;2BACxFI,QAAQ;oBACjB7C,QAAQ1P,KAAKkQ,iBAAiB9C,OAAO,MAAM4C,iBAAiBG,QAAQC,SAASC,WAAWiB,OAAOC,YAAYY;AAC7G,uBAAO;oBACLzC,QAAQ1P,KAAKoQ;AACf;gBAEAM,oBAAoBtD,OAAO,MAAM6D;gBAEjCxM,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;gBAElC,IAAIkG,OAAO,IAAa;oBACtByN,WAAW;oBACXzN,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC,uBAAO;oBACL2T,WAAW;AACb;AACF;YAEA7E,WAAWD,OAAO;AACpB;QAEA,SAASuF,gBAAiBvF,OAAO6D;YAC/B,IAAI2B;YACJ,IAAIC,WAAWnI;YACf,IAAIoI,iBAAiB;YACrB,IAAIC,iBAAiB;YACrB,IAAIC,aAAa/B;YACjB,IAAIgC,aAAa;YACjB,IAAIC,iBAAiB;YACrB,IAAIpB;YAEJ,IAAIrN,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,IAAIkG,OAAO,KAAa;gBACtBmO,UAAU;AACZ,mBAAA,IAAWnO,OAAO,IAAa;gBAC7BmO,UAAU;AACZ,mBAAO;gBACL,OAAO;AACT;YAEAxF,MAAMrM,OAAO;YACbqM,MAAM5Q,SAAS;YAEf,OAAOiI,OAAO,GAAG;gBACfA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;gBAEpC,IAAIkG,OAAO,MAAeA,OAAO,IAAa;oBAC5C,IAAIiG,kBAAkBmI,UAAU;wBAC9BA,WAAYpO,OAAO,KAAemG,gBAAgBD;AACpD,2BAAO;wBACL0C,WAAWD,OAAO;AACpB;4BACU0E,MAAMpG,gBAAgBjH,QAAQ,GAAG;oBAC3C,IAAIqN,QAAQ,GAAG;wBACbzE,WAAWD,OAAO;AACpB,2BAAA,KAAY2F,gBAAgB;wBAC1BC,aAAa/B,aAAaa,MAAM;wBAChCiB,iBAAiB;AACnB,2BAAO;wBACL1F,WAAWD,OAAO;AACpB;AACF,uBAAO;oBACL;AACF;AACF;YAEA,IAAIhC,aAAa3G,KAAK;gBACpB,GAAG;oBAAEA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AAAU,yBAC5C6M,aAAa3G;gBAEpB,IAAIA,OAAO,IAAa;oBACtB,GAAG;wBAAEA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;8BACjC4M,MAAM1G,OAAQA,OAAO;AAC/B;AACF;YAEA,OAAOA,OAAO,GAAG;gBACfgM,cAAcrD;gBACdA,MAAMP,aAAa;gBAEnBpI,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;gBAGlC,SAASwU,kBAAkB3F,MAAMP,aAAamG,eACtCvO,OAAO,IAAkB;oBAC/B2I,MAAMP;oBACNpI,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;gBAEA,KAAKwU,kBAAkB3F,MAAMP,aAAamG,YAAY;oBACpDA,aAAa5F,MAAMP;AACrB;gBAEA,IAAI1B,MAAM1G,KAAK;oBACbwO;oBACA;AACF;gBAEA,KAAKF,kBAAkBC,eAAe,GAAG;oBACvC3F,WAAWD,OAAO;AACpB;gBAGA,IAAIA,MAAMP,aAAamG,YAAY;oBAEjC,IAAIH,aAAajI,eAAe;wBAC9BwC,MAAM5Q,UAAUM,QAAOT,OAAO,MAAMyW,iBAAiB,IAAIG,aAAaA;AACxE,2BAAA,IAAWJ,aAAanI,eAAe;wBACrC,IAAIoI,gBAAgB;4BAClB1F,MAAM5Q,UAAU;AAClB;AACF;oBAGA;AACF;gBAGA,IAAIoW,SAAS;oBAEX,IAAIxH,aAAa3G,KAAK;wBACpByO,iBAAiB;wBAEjB9F,MAAM5Q,UAAUM,QAAOT,OAAO,MAAMyW,iBAAiB,IAAIG,aAAaA;+BAG7DC,gBAAgB;wBACzBA,iBAAiB;wBACjB9F,MAAM5Q,UAAUM,QAAOT,OAAO,MAAM4W,aAAa;AAGnD,2BAAA,IAAWA,eAAe,GAAG;wBAC3B,IAAIH,gBAAgB;4BAClB1F,MAAM5Q,UAAU;AAClB;AAGF,2BAAO;wBACL4Q,MAAM5Q,UAAUM,QAAOT,OAAO,MAAM4W;AACtC;AAGF,uBAAO;oBAEL7F,MAAM5Q,UAAUM,QAAOT,OAAO,MAAMyW,iBAAiB,IAAIG,aAAaA;AACxE;gBAEAH,iBAAiB;gBACjBC,iBAAiB;gBACjBE,aAAa;gBACb,IAAM9B,eAAe/D,MAAM7O;gBAE3B,QAAQ4M,MAAM1G,OAAQA,OAAO,GAAI;oBAC/BA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;gBAEA+Q,eAAelC,OAAO+D,cAAc/D,MAAM7O,UAAU;AACtD;YAEA,OAAO;AACT;QAEA,SAAS4U,kBAAmB/F,OAAO6D;YACjC,IAAMmB,OAAOhF,MAAMvM;YACnB,IAAMwR,UAAUjF,MAAMgB;YACtB,IAAMsB,UAAU;YAChB,IAAI0D,WAAW;YAIf,IAAIhG,MAAMJ,oBAAmB,GAAI,OAAO;YAExC,IAAII,MAAMgB,WAAW,MAAM;gBACzBb,YAAYH,OAAOA,MAAMgB,QAAQsB;AACnC;YAEA,IAAIjL,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,OAAOkG,OAAO,GAAG;gBACf,IAAI2I,MAAMJ,oBAAmB,GAAI;oBAC/BI,MAAM7O,WAAW6O,MAAMJ;oBACvBK,WAAWD,OAAO;AACpB;gBAEA,IAAI3I,OAAO,IAAa;oBACtB;AACF;gBAEA,IAAMiN,YAAYtE,MAAMzE,MAAM/D,WAAWwI,MAAM7O,WAAW;gBAE1D,KAAK8M,UAAUqG,YAAY;oBACzB;AACF;gBAEA0B,WAAW;gBACXhG,MAAM7O;gBAEN,IAAImS,oBAAoBtD,OAAO,OAAM,IAAK;oBACxC,IAAIA,MAAMP,cAAcoE,YAAY;wBAClCvB,QAAQ1P,KAAK;wBACbyE,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;wBAClC;AACF;AACF;gBAEA,IAAM+S,QAAQlE,MAAM7P;gBACpBmV,YAAYtF,OAAO6D,YAAYzG,kBAAkB,OAAO;gBACxDkF,QAAQ1P,KAAKoN,MAAM5Q;gBACnBkU,oBAAoBtD,OAAO,OAAM;gBAEjC3I,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;gBAElC,KAAK6O,MAAM7P,SAAS+T,SAASlE,MAAMP,aAAaoE,eAAgBxM,OAAO,GAAI;oBACzE4I,WAAWD,OAAO;AACpB,uBAAA,IAAWA,MAAMP,aAAaoE,YAAY;oBACxC;AACF;AACF;YAEA,IAAImC,UAAU;gBACZhG,MAAMvM,MAAMuR;gBACZhF,MAAMgB,SAASiE;gBACfjF,MAAMrM,OAAO;gBACbqM,MAAM5Q,SAASkT;gBACf,OAAO;AACT;YACA,OAAO;AACT;QAEA,SAAS2D,iBAAkBjG,OAAO6D,YAAYqC;YAC5C,IAAIC;YACJ,IAAIC;YACJ,IAAIC;YACJ,IAAIC;YACJ,IAAMtB,OAAOhF,MAAMvM;YACnB,IAAMwR,UAAUjF,MAAMgB;YACtB,IAAMsB,UAAU,CAAA;YAChB,IAAMM,kBAAkBhU,OAAOgC,OAAO;YACtC,IAAImS,SAAS;YACb,IAAIC,UAAU;YACd,IAAIC,YAAY;YAChB,IAAIsD,gBAAgB;YACpB,IAAIP,WAAW;YAIf,IAAIhG,MAAMJ,oBAAmB,GAAI,OAAO;YAExC,IAAII,MAAMgB,WAAW,MAAM;gBACzBb,YAAYH,OAAOA,MAAMgB,QAAQsB;AACnC;YAEA,IAAIjL,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,OAAOkG,OAAO,GAAG;gBACf,KAAKkP,iBAAiBvG,MAAMJ,oBAAmB,GAAI;oBACjDI,MAAM7O,WAAW6O,MAAMJ;oBACvBK,WAAWD,OAAO;AACpB;gBAEA,IAAMsE,YAAYtE,MAAMzE,MAAM/D,WAAWwI,MAAM7O,WAAW;gBAC1D,IAAM+S,QAAQlE,MAAM7P;gBAMpB,KAAKkH,OAAO,MAAeA,OAAO,OAAgB4G,UAAUqG,YAAY;oBACtE,IAAIjN,OAAO,IAAa;wBACtB,IAAIkP,eAAe;4BACjBzD,iBAAiB9C,OAAOsC,SAASM,iBAAiBG,QAAQC,SAAS,MAAMoD,UAAUC,eAAeC;4BAClGvD,SAASC,UAAUC,YAAY;AACjC;wBAEA+C,WAAW;wBACXO,gBAAgB;wBAChBJ,eAAe;+BACNI,eAAe;wBAExBA,gBAAgB;wBAChBJ,eAAe;AACjB,2BAAO;wBACLlG,WAAWD,OAAO;AACpB;oBAEAA,MAAM7O,YAAY;oBAClBkG,KAAKiN;AAKP,uBAAO;oBACL8B,WAAWpG,MAAM7P;oBACjBkW,gBAAgBrG,MAAM/O;oBACtBqV,UAAUtG,MAAM7O;oBAEhB,KAAKmU,YAAYtF,OAAOkG,YAAY/I,kBAAkB,OAAO,OAAO;wBAGlE;AACF;oBAEA,IAAI6C,MAAM7P,SAAS+T,OAAO;wBACxB7M,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;wBAElC,OAAO6M,aAAa3G,KAAK;4BACvBA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;wBAEA,IAAIkG,OAAO,IAAa;4BACtBA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;4BAEpC,KAAK8M,UAAU5G,KAAK;gCAClB4I,WAAWD,OAAO;AACpB;4BAEA,IAAIuG,eAAe;gCACjBzD,iBAAiB9C,OAAOsC,SAASM,iBAAiBG,QAAQC,SAAS,MAAMoD,UAAUC,eAAeC;gCAClGvD,SAASC,UAAUC,YAAY;AACjC;4BAEA+C,WAAW;4BACXO,gBAAgB;4BAChBJ,eAAe;4BACfpD,SAAS/C,MAAMvM;4BACfuP,UAAUhD,MAAM5Q;mCACP4W,UAAU;4BACnB/F,WAAWD,OAAO;AACpB,+BAAO;4BACLA,MAAMvM,MAAMuR;4BACZhF,MAAMgB,SAASiE;4BACf,OAAO;AACT;+BACSe,UAAU;wBACnB/F,WAAWD,OAAO;AACpB,2BAAO;wBACLA,MAAMvM,MAAMuR;wBACZhF,MAAMgB,SAASiE;wBACf,OAAO;AACT;AACF;gBAKA,IAAIjF,MAAM7P,SAAS+T,SAASlE,MAAMP,aAAaoE,YAAY;oBACzD,IAAI0C,eAAe;wBACjBH,WAAWpG,MAAM7P;wBACjBkW,gBAAgBrG,MAAM/O;wBACtBqV,UAAUtG,MAAM7O;AAClB;oBAEA,IAAImU,YAAYtF,OAAO6D,YAAYxG,mBAAmB,MAAM8I,eAAe;wBACzE,IAAII,eAAe;4BACjBvD,UAAUhD,MAAM5Q;AAClB,+BAAO;4BACL6T,YAAYjD,MAAM5Q;AACpB;AACF;oBAEA,KAAKmX,eAAe;wBAClBzD,iBAAiB9C,OAAOsC,SAASM,iBAAiBG,QAAQC,SAASC,WAAWmD,UAAUC,eAAeC;wBACvGvD,SAASC,UAAUC,YAAY;AACjC;oBAEAK,oBAAoBtD,OAAO,OAAM;oBACjC3I,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;AACpC;gBAEA,KAAK6O,MAAM7P,SAAS+T,SAASlE,MAAMP,aAAaoE,eAAgBxM,OAAO,GAAI;oBACzE4I,WAAWD,OAAO;AACpB,uBAAA,IAAWA,MAAMP,aAAaoE,YAAY;oBACxC;AACF;AACF;YAOA,IAAI0C,eAAe;gBACjBzD,iBAAiB9C,OAAOsC,SAASM,iBAAiBG,QAAQC,SAAS,MAAMoD,UAAUC,eAAeC;AACpG;YAGA,IAAIN,UAAU;gBACZhG,MAAMvM,MAAMuR;gBACZhF,MAAMgB,SAASiE;gBACfjF,MAAMrM,OAAO;gBACbqM,MAAM5Q,SAASkT;AACjB;YAEA,OAAO0D;AACT;QAEA,SAASQ,gBAAiBxG;YACxB,IAAIyG,aAAa;YACjB,IAAIC,UAAU;YACd,IAAIC;YACJ,IAAIC;YAEJ,IAAIvP,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,IAAIkG,OAAO,IAAa,OAAO;YAE/B,IAAI2I,MAAMvM,QAAQ,MAAM;gBACtBwM,WAAWD,OAAO;AACpB;YAEA3I,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;YAEpC,IAAIkG,OAAO,IAAa;gBACtBoP,aAAa;gBACbpP,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC,mBAAA,IAAWkG,OAAO,IAAa;gBAC7BqP,UAAU;gBACVC,YAAY;gBACZtP,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC,mBAAO;gBACLwV,YAAY;AACd;YAEA,IAAIpE,YAAYvC,MAAM7O;YAEtB,IAAIsV,YAAY;gBACd,GAAG;oBAAEpP,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AAAU,yBAC5CkG,OAAO,KAAKA,OAAO;gBAE1B,IAAI2I,MAAM7O,WAAW6O,MAAMjR,QAAQ;oBACjC6X,UAAU5G,MAAMzE,MAAM5J,MAAM4Q,WAAWvC,MAAM7O;oBAC7CkG,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC,uBAAO;oBACL8O,WAAWD,OAAO;AACpB;AACF,mBAAO;gBACL,OAAO3I,OAAO,MAAM4G,UAAU5G,KAAK;oBACjC,IAAIA,OAAO,IAAa;wBACtB,KAAKqP,SAAS;4BACZC,YAAY3G,MAAMzE,MAAM5J,MAAM4Q,YAAY,GAAGvC,MAAM7O,WAAW;4BAE9D,KAAKyM,mBAAmBnF,KAAKkO,YAAY;gCACvC1G,WAAWD,OAAO;AACpB;4BAEA0G,UAAU;4BACVnE,YAAYvC,MAAM7O,WAAW;AAC/B,+BAAO;4BACL8O,WAAWD,OAAO;AACpB;AACF;oBAEA3I,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;gBAEAyV,UAAU5G,MAAMzE,MAAM5J,MAAM4Q,WAAWvC,MAAM7O;gBAE7C,IAAIwM,wBAAwBlF,KAAKmO,UAAU;oBACzC3G,WAAWD,OAAO;AACpB;AACF;YAEA,IAAI4G,YAAY/I,gBAAgBpF,KAAKmO,UAAU;gBAC7C3G,WAAWD,OAAO,8CAA8C4G;AAClE;YAEA;gBACEA,UAAU5E,mBAAmB4E;qBACtB3E;gBACPhC,WAAWD,OAAO,4BAA4B4G;AAChD;YAEA,IAAIH,YAAY;gBACdzG,MAAMvM,MAAMmT;AACd,uBAAW/K,gBAAgBrL,KAAKwP,MAAM+B,QAAQ4E,YAAY;gBACxD3G,MAAMvM,MAAMuM,MAAM+B,OAAO4E,aAAaC;AACxC,mBAAA,IAAWD,cAAc,KAAK;gBAC5B3G,MAAMvM,MAAM,MAAMmT;AACpB,mBAAA,IAAWD,cAAc,MAAM;gBAC7B3G,MAAMvM,MAAM,uBAAuBmT;AACrC,mBAAO;gBACL3G,WAAWD,OAAO,4BAA4B2G,YAAY;AAC5D;YAEA,OAAO;AACT;QAEA,SAASE,mBAAoB7G;YAC3B,IAAI3I,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,IAAIkG,OAAO,IAAa,OAAO;YAE/B,IAAI2I,MAAMgB,WAAW,MAAM;gBACzBf,WAAWD,OAAO;AACpB;YAEA3I,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;YACpC,IAAMoR,YAAYvC,MAAM7O;YAExB,OAAOkG,OAAO,MAAM4G,UAAU5G,QAAQ6G,gBAAgB7G,KAAK;gBACzDA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;YAEA,IAAI6O,MAAM7O,aAAaoR,WAAW;gBAChCtC,WAAWD,OAAO;AACpB;YAEAA,MAAMgB,SAAShB,MAAMzE,MAAM5J,MAAM4Q,WAAWvC,MAAM7O;YAClD,OAAO;AACT;QAEA,SAAS2V,UAAW9G;YAClB,IAAI3I,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;YAEtC,IAAIkG,OAAO,IAAa,OAAO;YAE/BA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;YACpC,IAAMoR,YAAYvC,MAAM7O;YAExB,OAAOkG,OAAO,MAAM4G,UAAU5G,QAAQ6G,gBAAgB7G,KAAK;gBACzDA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;YAEA,IAAI6O,MAAM7O,aAAaoR,WAAW;gBAChCtC,WAAWD,OAAO;AACpB;YAEA,IAAM1M,QAAQ0M,MAAMzE,MAAM5J,MAAM4Q,WAAWvC,MAAM7O;YAEjD,KAAK0K,gBAAgBrL,KAAKwP,MAAMO,WAAWjN,QAAQ;gBACjD2M,WAAWD,OAAO,yBAAyB1M,QAAQ;AACrD;YAEA0M,MAAM5Q,SAAS4Q,MAAMO,UAAUjN;YAC/BgQ,oBAAoBtD,OAAO,OAAM;YACjC,OAAO;AACT;QAEA,SAAS+G,gCAAiC/G,OAAOgH,eAAenD,YAAYqC;YAC1E,IAAMe,gBAAgBlG,cAAcf;YAEpCQ,uBAAuBR;YACvBiB,aAAajB,OAAOgH;YAIpBhH,MAAMvM,MAAM;YACZuM,MAAMgB,SAAS;YACfhB,MAAMrM,OAAO;YACbqM,MAAM5Q,SAAS;YAEf,IAAI6W,iBAAiBjG,OAAO6D,YAAYqC,eAAelG,MAAMrM,SAAS,WAAW;gBAC/E8M,wBAAwBT;gBACxB,OAAO;AACT;YAEAa,0BAA0Bb;YAC1BiB,aAAajB,OAAOiH;YACpB,OAAO;AACT;QAEA,SAAS3B,YAAatF,OAAOkH,cAAcC,aAAaC,aAAajB;YACnE,IAAIkB;YACJ,IAAIC;YACJ,IAAIC,eAAe;YACnB,IAAIC,YAAY;YAChB,IAAIC,aAAa;YACjB,IAAIT,gBAAgB;YACpB,IAAI1S;YACJ,IAAI4R;YACJ,IAAIwB;YAEJ,IAAI1H,MAAMN,SAASM,MAAMX,UAAU;gBACjCY,WAAWD,OAAO,gCAAgCA,MAAMX,WAAW;AACrE;YAEAW,MAAMN,SAAS;YAEf,IAAIM,MAAMZ,aAAa,MAAM;gBAC3BY,MAAMZ,SAAS,QAAQY;AACzB;YAEAA,MAAMvM,MAAM;YACZuM,MAAMgB,SAAS;YACfhB,MAAMrM,OAAO;YACbqM,MAAM5Q,SAAS;YAEf,IAAMuY,mBAAmBN,oBAAoBC,wBAC3CjK,sBAAsB8J,eACtB/J,qBAAqB+J;YAEvB,IAAIC,aAAa;gBACf,IAAI9D,oBAAoBtD,OAAO,OAAM,IAAK;oBACxCwH,YAAY;oBAEZ,IAAIxH,MAAMP,aAAayH,cAAc;wBACnCK,eAAe;AACjB,2BAAA,IAAWvH,MAAMP,eAAeyH,cAAc;wBAC5CK,eAAe;AACjB,2BAAA,IAAWvH,MAAMP,aAAayH,cAAc;wBAC1CK,gBAAe;AACjB;AACF;AACF;YAEA,IAAIA,iBAAiB,GAAG;gBACtB,OAAO,MAAM;oBACX,IAAMlQ,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;oBACxC,IAAMyW,gBAAgB7G,cAAcf;oBAIpC,IAAIwH,cACEnQ,OAAO,MAAe2I,MAAMvM,QAAQ,QACpC4D,OAAO,MAAe2I,MAAMgB,WAAW,OAAQ;wBACnD;AACF;oBAEA,KAAKwF,gBAAgBxG,WAAW6G,mBAAmB7G,QAAQ;wBACzD;AACF;oBAEA,IAAIgH,kBAAkB,MAAM;wBAC1BA,gBAAgBY;AAClB;oBAEA,IAAItE,oBAAoBtD,OAAO,OAAM,IAAK;wBACxCwH,YAAY;wBACZF,wBAAwBK;wBAExB,IAAI3H,MAAMP,aAAayH,cAAc;4BACnCK,eAAe;AACjB,+BAAA,IAAWvH,MAAMP,eAAeyH,cAAc;4BAC5CK,eAAe;AACjB,+BAAA,IAAWvH,MAAMP,aAAayH,cAAc;4BAC1CK,gBAAe;AACjB;AACF,2BAAO;wBACLD,wBAAwB;AAC1B;AACF;AACF;YAEA,IAAIA,uBAAuB;gBACzBA,wBAAwBE,aAAarB;AACvC;YAEA,IAAIoB,iBAAiB,KAAKlK,sBAAsB8J,aAAa;gBAC3D,IAAIjK,oBAAoBiK,eAAehK,qBAAqBgK,aAAa;oBACvEjB,aAAagB;AACf,uBAAO;oBACLhB,aAAagB,eAAe;AAC9B;gBAEAQ,cAAc1H,MAAM7O,WAAW6O,MAAM/O;gBAErC,IAAIsW,iBAAiB,GAAG;oBACtB,IAAKD,0BACAvB,kBAAkB/F,OAAO0H,gBAAgBzB,iBAAiBjG,OAAO0H,aAAaxB,gBAC/ErB,mBAAmB7E,OAAOkG,aAAa;wBACzCuB,aAAa;AACf,2BAAO;wBACL,IAAMpQ,MAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;wBAExC,IAAI6V,kBAAkB,QAAQW,qBAAqBL,yBAC/CjQ,QAAO,OAAeA,QAAO,MAC7B0P,gCACE/G,OACAgH,eACAA,cAAc7V,WAAW6V,cAAc/V,WACvCiV,aACC;4BACLuB,aAAa;mCACHJ,qBAAqB9B,gBAAgBvF,OAAOkG,eACpD1B,uBAAuBxE,OAAOkG,eAC9BzB,uBAAuBzE,OAAOkG,aAAa;4BAC7CuB,aAAa;AACf,+BAAA,IAAWX,UAAU9G,QAAQ;4BAC3ByH,aAAa;4BAEb,IAAIzH,MAAMvM,QAAQ,QAAQuM,MAAMgB,WAAW,MAAM;gCAC/Cf,WAAWD,OAAO;AACpB;AACF,mCAAW4D,gBAAgB5D,OAAOkG,YAAYhJ,oBAAoBiK,cAAc;4BAC9EM,aAAa;4BAEb,IAAIzH,MAAMvM,QAAQ,MAAM;gCACtBuM,MAAMvM,MAAM;AACd;AACF;wBAEA,IAAIuM,MAAMgB,WAAW,MAAM;4BACzBb,YAAYH,OAAOA,MAAMgB,QAAQhB,MAAM5Q;AACzC;AACF;AACF,uBAAA,IAAWmY,iBAAiB,GAAG;oBAG7BE,aAAaH,yBAAyBvB,kBAAkB/F,OAAO0H;AACjE;AACF;YAEA,IAAI1H,MAAMvM,QAAQ,MAAM;gBACtB,IAAIuM,MAAMgB,WAAW,MAAM;oBACzBb,YAAYH,OAAOA,MAAMgB,QAAQhB,MAAM5Q;AACzC;AACF,mBAAA,IAAW4Q,MAAMvM,QAAQ,KAAK;gBAO5B,IAAIuM,MAAM5Q,WAAW,QAAQ4Q,MAAMrM,SAAS,UAAU;oBACpDsM,WAAWD,OAAO,sEAAsEA,MAAMrM,OAAO;AACvG;gBAEA,KAAA,IAASkU,YAAY,GAAGC,eAAe9H,MAAMT,cAAcxQ,QAAQ8Y,YAAYC,cAAcD,aAAa,GAAG;oBAC3GvT,QAAO0L,MAAMT,cAAcsI;oBAE3B,IAAIvT,MAAKV,QAAQoM,MAAM5Q,SAAS;wBAC9B4Q,MAAM5Q,SAASkF,MAAKT,UAAUmM,MAAM5Q;wBACpC4Q,MAAMvM,MAAMa,MAAKb;wBACjB,IAAIuM,MAAMgB,WAAW,MAAM;4BACzBb,YAAYH,OAAOA,MAAMgB,QAAQhB,MAAM5Q;AACzC;wBACA;AACF;AACF;AACF,mBAAA,IAAW4Q,MAAMvM,QAAQ,KAAK;gBAC5B,IAAIoI,gBAAgBrL,KAAKwP,MAAMR,QAAQQ,MAAMrM,QAAQ,aAAaqM,MAAMvM,MAAM;oBAC5Ea,QAAO0L,MAAMR,QAAQQ,MAAMrM,QAAQ,YAAYqM,MAAMvM;AACvD,uBAAO;oBAELa,QAAO;oBACP,IAAMyT,WAAW/H,MAAMR,QAAQpL,MAAM4L,MAAMrM,QAAQ;oBAEnD,KAAA,IAASkU,aAAY,GAAGC,gBAAeC,SAAShZ,QAAQ8Y,aAAYC,eAAcD,cAAa,GAAG;wBAChG,IAAI7H,MAAMvM,IAAI9B,MAAM,GAAGoW,SAASF,YAAWpU,IAAI1E,YAAYgZ,SAASF,YAAWpU,KAAK;4BAClFa,QAAOyT,SAASF;4BAChB;AACF;AACF;AACF;gBAEA,KAAKvT,OAAM;oBACT2L,WAAWD,OAAO,mBAAmBA,MAAMvM,MAAM;AACnD;gBAEA,IAAIuM,MAAM5Q,WAAW,QAAQkF,MAAKX,SAASqM,MAAMrM,MAAM;oBACrDsM,WAAWD,OAAO,kCAAkCA,MAAMvM,MAAM,0BAA0Ba,MAAKX,OAAO,aAAaqM,MAAMrM,OAAO;AAClI;gBAEA,KAAKW,MAAKV,QAAQoM,MAAM5Q,QAAQ4Q,MAAMvM,MAAM;oBAC1CwM,WAAWD,OAAO,kCAAkCA,MAAMvM,MAAM;AAClE,uBAAO;oBACLuM,MAAM5Q,SAASkF,MAAKT,UAAUmM,MAAM5Q,QAAQ4Q,MAAMvM;oBAClD,IAAIuM,MAAMgB,WAAW,MAAM;wBACzBb,YAAYH,OAAOA,MAAMgB,QAAQhB,MAAM5Q;AACzC;AACF;AACF;YAEA,IAAI4Q,MAAMZ,aAAa,MAAM;gBAC3BY,MAAMZ,SAAS,SAASY;AAC1B;YAEAA,MAAMN,SAAS;YACf,OAAOM,MAAMvM,QAAQ,QAAQuM,MAAMgB,WAAW,QAAQyG;AACxD;QAEA,SAASO,aAAchI;YACrB,IAAMiI,gBAAgBjI,MAAM7O;YAC5B,IAAI+W,gBAAgB;YACpB,IAAI7Q;YAEJ2I,MAAMuB,UAAU;YAChBvB,MAAM0B,kBAAkB1B,MAAMb;YAC9Ba,MAAM+B,SAASnT,OAAOgC,OAAO;YAC7BoP,MAAMO,YAAY3R,OAAOgC,OAAO;YAEhC,QAAQyG,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O,eAAe,GAAG;gBAC1DmS,oBAAoBtD,OAAO,OAAM;gBAEjC3I,KAAK2I,MAAMzE,MAAM/D,WAAWwI,MAAM7O;gBAElC,IAAI6O,MAAMP,aAAa,KAAKpI,OAAO,IAAa;oBAC9C;AACF;gBAEA6Q,gBAAgB;gBAChB7Q,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;gBACpC,IAAIoR,YAAYvC,MAAM7O;gBAEtB,OAAOkG,OAAO,MAAM4G,UAAU5G,KAAK;oBACjCA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;gBAEA,IAAMgX,gBAAgBnI,MAAMzE,MAAM5J,MAAM4Q,WAAWvC,MAAM7O;gBACzD,IAAMiX,gBAAgB;gBAEtB,IAAID,cAAcpZ,SAAS,GAAG;oBAC5BkR,WAAWD,OAAO;AACpB;gBAEA,OAAO3I,OAAO,GAAG;oBACf,OAAO2G,aAAa3G,KAAK;wBACvBA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;oBAEA,IAAIkG,OAAO,IAAa;wBACtB,GAAG;4BAAEA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;iCAClCkG,OAAO,MAAM0G,MAAM1G;wBAC1B;AACF;oBAEA,IAAI0G,MAAM1G,KAAK;oBAEfkL,YAAYvC,MAAM7O;oBAElB,OAAOkG,OAAO,MAAM4G,UAAU5G,KAAK;wBACjCA,KAAK2I,MAAMzE,MAAM/D,aAAawI,MAAM7O;AACtC;oBAEAiX,cAAcxV,KAAKoN,MAAMzE,MAAM5J,MAAM4Q,WAAWvC,MAAM7O;AACxD;gBAEA,IAAIkG,OAAO,GAAGgM,cAAcrD;gBAE5B,IAAInE,gBAAgBrL,KAAK2Q,mBAAmBgH,gBAAgB;oBAC1DhH,kBAAkBgH,eAAenI,OAAOmI,eAAeC;AACzD,uBAAO;oBACLlI,aAAaF,OAAO,iCAAiCmI,gBAAgB;AACvE;AACF;YAEA7E,oBAAoBtD,OAAO,OAAM;YAEjC,IAAIA,MAAMP,eAAe,KACrBO,MAAMzE,MAAM/D,WAAWwI,MAAM7O,cAAc,MAC3C6O,MAAMzE,MAAM/D,WAAWwI,MAAM7O,WAAW,OAAO,MAC/C6O,MAAMzE,MAAM/D,WAAWwI,MAAM7O,WAAW,OAAO,IAAa;gBAC9D6O,MAAM7O,YAAY;gBAClBmS,oBAAoBtD,OAAO,OAAM;uBACxBkI,eAAe;gBACxBjI,WAAWD,OAAO;AACpB;YAEAsF,YAAYtF,OAAOA,MAAMP,aAAa,GAAGpC,mBAAmB,OAAO;YACnEiG,oBAAoBtD,OAAO,OAAM;YAEjC,IAAIA,MAAM0B,mBACNhE,8BAA8BjF,KAAKuH,MAAMzE,MAAM5J,MAAMsW,eAAejI,MAAM7O,YAAY;gBACxF+O,aAAaF,OAAO;AACtB;YAEAA,MAAMH,UAAUjN,KAAKoN,MAAM5Q;YAE3B,IAAI4Q,MAAM7O,aAAa6O,MAAM/O,aAAayS,sBAAsB1D,QAAQ;gBACtE,IAAIA,MAAMzE,MAAM/D,WAAWwI,MAAM7O,cAAc,IAAa;oBAC1D6O,MAAM7O,YAAY;oBAClBmS,oBAAoBtD,OAAO,OAAM;AACnC;gBACA;AACF;YAEA,IAAIA,MAAM7O,WAAY6O,MAAMjR,SAAS,GAAI;gBACvCkR,WAAWD,OAAO;AACpB;AACF;QAEA,SAASqI,cAAe9M,OAAOtJ;YAC7BsJ,QAAQhI,OAAOgI;YACftJ,UAAUA,WAAW,CAAA;YAErB,IAAIsJ,MAAMxM,WAAW,GAAG;gBAEtB,IAAIwM,MAAM/D,WAAW+D,MAAMxM,SAAS,OAAO,MACvCwM,MAAM/D,WAAW+D,MAAMxM,SAAS,OAAO,IAAc;oBACvDwM,SAAS;AACX;gBAGA,IAAIA,MAAM/D,WAAW,OAAO,OAAQ;oBAClC+D,QAAQA,MAAM5J,MAAM;AACtB;AACF;YAEA,IAAMqO,QAAQ,IAAIhB,MAAMzD,OAAOtJ;YAE/B,IAAMqW,UAAU/M,MAAM7H,QAAQ;YAE9B,IAAI4U,aAAY,GAAI;gBAClBtI,MAAM7O,WAAWmX;gBACjBrI,WAAWD,OAAO;AACpB;YAGAA,MAAMzE,SAAS;YAEf,OAAOyE,MAAMzE,MAAM/D,WAAWwI,MAAM7O,cAAc,IAAiB;gBACjE6O,MAAMP,cAAc;gBACpBO,MAAM7O,YAAY;AACpB;YAEA,OAAO6O,MAAM7O,WAAY6O,MAAMjR,SAAS,GAAI;gBAC1CiZ,aAAahI;AACf;YAEA,OAAOA,MAAMH;AACf;QAEA,SAAS0I,SAAShN,OAAOzN,UAAUmE;YACjC,IAAInE,aAAa,QAAQH,QAAOG,cAAa,mBAAmBmE,YAAY,aAAa;gBACvFA,UAAUnE;gBACVA,WAAW;AACb;YAEA,IAAM+R,YAAYwI,cAAc9M,OAAOtJ;YAEvC,WAAWnE,aAAa,YAAY;gBAClC,OAAO+R;AACT;YAEA,KAAA,IAAS/Q,QAAQ,GAAGC,SAAS8Q,UAAU9Q,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACzEhB,SAAS+R,UAAU/Q;AACrB;AACF;QAEA,SAAS0Z,MAAMjN,OAAOtJ;YACpB,IAAM4N,YAAYwI,cAAc9M,OAAOtJ;YAEvC,IAAI4N,UAAU9Q,WAAW,GAAG;gBAC1B,YAAO;AACT,mBAAA,IAAW8Q,UAAU9Q,WAAW,GAAG;gBACjC,OAAO8Q,UAAU;AACnB;YACA,MAAM,IAAIvP,eAAc;AAC1B;QAEAmY,OAAAF,UAAyBA;QACzBE,OAAAD,OAAsBA;;;;;;;;QC7vDV,SAAA7a,QAAAC;YAAA;YAAA,OAAAD,UAAA,qBAAAE,UAAA,mBAAAA,OAAAC,WAAA,SAAAF;gBAAA,cAAAA;gBAAA,SAAAA;gBAAA,OAAAA,MAAA,qBAAAC,UAAAD,GAAAG,gBAAAF,UAAAD,OAAAC,OAAAG,YAAA,kBAAAJ;AAAA,eAAAD,QAAAC;AAAA;QAEZ,IAAM8B,UAASoB;QACf,IAAMR,iBAAgBiE;QACtB,IAAM0I,kBAAiBlH;QAEvB,IAAMgG,YAAYnN,OAAOZ,UAAU6C;QACnC,IAAMgL,kBAAkBjN,OAAOZ,UAAU8N;QAEzC,IAAM4M,WAAW;QACjB,IAAMC,WAAW;QACjB,IAAMC,iBAAiB;QACvB,IAAMC,uBAAuB;QAC7B,IAAMC,aAAa;QACnB,IAAMC,mBAAmB;QACzB,IAAMC,oBAAoB;QAC1B,IAAMC,aAAa;QACnB,IAAMC,eAAe;QACrB,IAAMC,iBAAiB;QACvB,IAAMC,oBAAoB;QAC1B,IAAMC,gBAAgB;QACtB,IAAMC,aAAa;QACnB,IAAMC,aAAa;QACnB,IAAMC,aAAa;QACnB,IAAMC,cAAc;QACpB,IAAMC,oBAAoB;QAC1B,IAAMC,gBAAgB;QACtB,IAAMC,qBAAqB;QAC3B,IAAMC,2BAA2B;QACjC,IAAMC,4BAA4B;QAClC,IAAMC,oBAAoB;QAC1B,IAAMC,0BAA0B;QAChC,IAAMC,qBAAqB;QAC3B,IAAMC,2BAA2B;QAEjC,IAAMC,mBAAmB,CAAA;QAEzBA,iBAAiB,KAAQ;QACzBA,iBAAiB,KAAQ;QACzBA,iBAAiB,KAAQ;QACzBA,iBAAiB,KAAQ;QACzBA,iBAAiB,MAAQ;QACzBA,iBAAiB,MAAQ;QACzBA,iBAAiB,MAAQ;QACzBA,iBAAiB,MAAQ;QACzBA,iBAAiB,MAAQ;QACzBA,iBAAiB,MAAQ;QACzBA,iBAAiB,MAAQ;QACzBA,iBAAiB,OAAQ;QACzBA,iBAAiB,OAAQ;QACzBA,iBAAiB,QAAU;QAC3BA,iBAAiB,QAAU;QAE3B,IAAMC,6BAA6B,EACjC,KAAK,KAAK,OAAO,OAAO,OAAO,MAAM,MAAM,MAC3C,KAAK,KAAK,MAAM,MAAM,MAAM,OAAO,OAAO;QAG5C,IAAMC,2BAA2B;QAEjC,SAASC,gBAAiB7V,SAAQtB;YAChC,IAAIA,SAAQ,MAAM,OAAO,CAAA;YAEzB,IAAM/D,SAAS,CAAA;YACf,IAAMP,OAAOD,OAAOC,KAAKsE;YAEzB,KAAA,IAASrE,QAAQ,GAAGC,SAASF,KAAKE,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACpE,IAAI2E,MAAM5E,KAAKC;gBACf,IAAIuE,QAAQE,OAAOJ,KAAIM;gBAEvB,IAAIA,IAAI9B,MAAM,GAAG,OAAO,MAAM;oBAC5B8B,MAAM,uBAAuBA,IAAI9B,MAAM;AACzC;gBACA,IAAM2C,QAAOG,QAAOmB,gBAAgB,YAAYnC;gBAEhD,IAAIa,SAAQuH,gBAAgBrL,KAAK8D,MAAKD,cAAchB,QAAQ;oBAC1DA,QAAQiB,MAAKD,aAAahB;AAC5B;gBAEAjE,OAAOqE,OAAOJ;AAChB;YAEA,OAAOjE;AACT;QAEA,SAASmb,UAAWC;YAClB,IAAI1I;YACJ,IAAI/S;YAEJ,IAAMG,SAASsb,UAAU3Z,SAAS,IAAIuH;YAEtC,IAAIoS,aAAa,KAAM;gBACrB1I,SAAS;gBACT/S,SAAS;AACX,mBAAA,IAAWyb,aAAa,OAAQ;gBAC9B1I,SAAS;gBACT/S,SAAS;AACX,mBAAA,IAAWyb,aAAa,YAAY;gBAClC1I,SAAS;gBACT/S,SAAS;AACX,mBAAO;gBACL,MAAM,IAAIuB,eAAc;AAC1B;YAEA,OAAO,OAAOwR,SAASpS,QAAOT,OAAO,KAAKF,SAASG,OAAOH,UAAUG;AACtE;QAEA,IAAMub,sBAAsB;QAC5B,IAAMC,sBAAsB;QAE5B,SAAS1L,MAAO/M;YACdxB,KAAKgE,SAASxC,QAAQ,aAAagL;YACnCxM,KAAK0B,SAASX,KAAKO,IAAI,GAAIE,QAAQ,aAAa;YAChDxB,KAAKka,gBAAgB1Y,QAAQ,oBAAoB;YACjDxB,KAAKma,cAAc3Y,QAAQ,kBAAkB;YAC7CxB,KAAKoa,YAAanb,QAAOzB,UAAUgE,QAAQ,iBAAgB,IAAKA,QAAQ;YACxExB,KAAKqa,WAAWR,gBAAgB7Z,KAAKgE,QAAQxC,QAAQ,aAAa;YAClExB,KAAKsa,WAAW9Y,QAAQ,eAAe;YACvCxB,KAAKua,YAAY/Y,QAAQ,gBAAgB;YACzCxB,KAAKwa,SAAShZ,QAAQ,aAAa;YACnCxB,KAAKya,eAAejZ,QAAQ,mBAAmB;YAC/CxB,KAAK0a,eAAelZ,QAAQ,mBAAmB;YAC/CxB,KAAK2a,cAAcnZ,QAAQ,mBAAmB,MAAMyY,sBAAsBD;YAC1Eha,KAAK4a,cAAcpZ,QAAQ,kBAAkB;YAC7CxB,KAAK6a,kBAAkBrZ,QAAQ,gBAAgB,aAAaA,QAAQ,cAAc;YAElFxB,KAAK8O,gBAAgB9O,KAAKgE,OAAOiB;YACjCjF,KAAK8a,gBAAgB9a,KAAKgE,OAAOkB;YAEjClF,KAAKgD,MAAM;YACXhD,KAAKrB,SAAS;YAEdqB,KAAK+a,aAAa;YAClB/a,KAAKgb,iBAAiB;AACxB;QAGA,SAASC,aAAcxc,QAAQyc;YAC7B,IAAMC,MAAMlc,QAAOT,OAAO,KAAK0c;YAC/B,IAAIxa,WAAW;YACf,IAAI/B,SAAS;YACb,IAAML,SAASG,OAAOH;YAEtB,OAAOoC,WAAWpC,QAAQ;gBACxB,IAAIoB,YAAI;gBACR,IAAM0b,OAAO3c,OAAOwE,QAAQ,MAAMvC;gBAClC,IAAI0a,UAAS,GAAI;oBACf1b,OAAOjB,OAAOyC,MAAMR;oBACpBA,WAAWpC;AACb,uBAAO;oBACLoB,OAAOjB,OAAOyC,MAAMR,UAAU0a,OAAO;oBACrC1a,WAAW0a,OAAO;AACpB;gBAEA,IAAI1b,KAAKpB,UAAUoB,SAAS,MAAMf,UAAUwc;gBAE5Cxc,UAAUe;AACZ;YAEA,OAAOf;AACT;QAEA,SAAS0c,iBAAkB9L,OAAO+L;YAChC,OAAO,OAAOrc,QAAOT,OAAO,KAAK+Q,MAAM7N,SAAS4Z;AAClD;QAEA,SAASC,sBAAuBhM,OAAOtO;YACrC,KAAA,IAAS5C,QAAQ,GAAGC,SAASiR,MAAMT,cAAcxQ,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACnF,IAAMwF,QAAO0L,MAAMT,cAAczQ;gBAEjC,IAAIwF,MAAKV,QAAQlC,OAAM;oBACrB,OAAO;AACT;AACF;YAEA,OAAO;AACT;QAGA,SAASua,aAAcjV;YACrB,OAAOA,MAAM8R,cAAc9R,MAAM2R;AACnC;QAMA,SAASuD,YAAalV;YACpB,OAAQA,KAAK,MAAWA,KAAK,OACzBA,KAAK,OAAWA,KAAK,SAAaA,MAAM,QAAUA,MAAM,QACxDA,KAAK,SAAWA,KAAK,SAAaA,MAAM0R,YACzC1R,KAAK,SAAWA,KAAK;AAC1B;QAOA,SAASmV,qBAAsBnV;YAC7B,OAAOkV,YAAYlV,MACjBA,MAAM0R,YAEN1R,MAAM6R,wBACN7R,MAAM4R;AACV;QAWA,SAASwD,YAAapV,GAAGqV,MAAMC;YAC7B,IAAMC,wBAAwBJ,qBAAqBnV;YACnD,IAAMwV,YAAYD,0BAA0BN,aAAajV;YACzD,QAGIsV,UACIC,wBACAA,yBAEAvV,MAAMsS,cACNtS,MAAM6S,4BACN7S,MAAM8S,6BACN9S,MAAMgT,2BACNhT,MAAMkT,6BAGZlT,MAAMiS,gBACJoD,SAAS7C,eAAegD,cAE3BL,qBAAqBE,UAAUJ,aAAaI,SAASrV,MAAMiS,cAC3DoD,SAAS7C,cAAcgD;AAC1B;QAGA,SAASC,iBAAkBzV;YAIzB,OAAOkV,YAAYlV,MACjBA,MAAM0R,aACLuD,aAAajV,MAGdA,MAAMuS,cACNvS,MAAM2S,iBACN3S,MAAMwS,cACNxS,MAAMsS,cACNtS,MAAM6S,4BACN7S,MAAM8S,6BACN9S,MAAMgT,2BACNhT,MAAMkT,4BAENlT,MAAMiS,cACNjS,MAAMmS,kBACNnS,MAAMqS,iBACNrS,MAAM+R,oBACN/R,MAAMiT,sBACNjT,MAAMyS,eACNzS,MAAM0S,qBACN1S,MAAMoS,qBACNpS,MAAMgS,qBAENhS,MAAMkS,gBACNlS,MAAM4S,sBACN5S,MAAM+S;AACV;QAGA,SAAS2C,gBAAiB1V;YAExB,QAAQiV,aAAajV,MAAMA,MAAMwS;AACnC;QAGA,SAASmD,YAAazd,QAAQ2C;YAC5B,IAAM+a,QAAQ1d,OAAOsI,WAAW3F;YAChC,IAAIwI;YAEJ,IAAIuS,SAAS,SAAUA,SAAS,SAAU/a,MAAM,IAAI3C,OAAOH,QAAQ;gBACjEsL,SAASnL,OAAOsI,WAAW3F,MAAM;gBACjC,IAAIwI,UAAU,SAAUA,UAAU,OAAQ;oBAExC,QAAQuS,QAAQ,SAAU,OAAQvS,SAAS,QAAS;AACtD;AACF;YACA,OAAOuS;AACT;QAGA,SAASC,oBAAqB3d;YAC5B,IAAM4d,iBAAiB;YACvB,OAAOA,eAAerU,KAAKvJ;AAC7B;QAEA,IAAM6d,cAAc;QACpB,IAAMC,eAAe;QACrB,IAAMC,gBAAgB;QACtB,IAAMC,eAAe;QACrB,IAAMC,eAAe;QASrB,SAASC,kBAAmBle,QAAQme,gBAAgBC,gBAAgBtC,WAClEuC,mBAAmBnC,aAAaC,aAAaiB;YAC7C,IAAIvZ;YACJ,IAAIya,OAAO;YACX,IAAIC,WAAW;YACf,IAAIC,eAAe;YACnB,IAAIC,kBAAkB;YACtB,IAAMC,mBAAmB5C,eAAc;YACvC,IAAI6C,qBAAoB;YACxB,IAAIC,QAAQrB,iBAAiBE,YAAYzd,QAAQ,OAC/Cwd,gBAAgBC,YAAYzd,QAAQA,OAAOH,SAAS;YAEtD,IAAIse,kBAAkBhC,aAAa;gBAGjC,KAAKtY,IAAI,GAAGA,IAAI7D,OAAOH,QAAQye,QAAQ,QAAUza,KAAK,IAAIA,KAAK;oBAC7Dya,OAAOb,YAAYzd,QAAQ6D;oBAC3B,KAAKmZ,YAAYsB,OAAO;wBACtB,OAAOL;AACT;oBACAW,QAAQA,SAAS1B,YAAYoB,MAAMC,UAAUnB;oBAC7CmB,WAAWD;AACb;AACF,mBAAO;gBAEL,KAAKza,IAAI,GAAGA,IAAI7D,OAAOH,QAAQye,QAAQ,QAAUza,KAAK,IAAIA,KAAK;oBAC7Dya,OAAOb,YAAYzd,QAAQ6D;oBAC3B,IAAIya,SAAS5E,gBAAgB;wBAC3B8E,eAAe;wBAEf,IAAIE,kBAAkB;4BACpBD,kBAAkBA,mBAEf5a,IAAI8a,oBAAoB,IAAI7C,aAC5B9b,OAAO2e,oBAAoB,OAAO;4BACrCA,oBAAoB9a;AACtB;AACF,2BAAA,KAAYmZ,YAAYsB,OAAO;wBAC7B,OAAOL;AACT;oBACAW,QAAQA,SAAS1B,YAAYoB,MAAMC,UAAUnB;oBAC7CmB,WAAWD;AACb;gBAEAG,kBAAkBA,mBAAoBC,oBACnC7a,IAAI8a,oBAAoB,IAAI7C,aAC5B9b,OAAO2e,oBAAoB,OAAO;AACvC;YAIA,KAAKH,iBAAiBC,iBAAiB;gBAGrC,IAAIG,UAAUzC,gBAAgBkC,kBAAkBre,SAAS;oBACvD,OAAO6d;AACT;gBACA,OAAO3B,gBAAgBV,sBAAsByC,eAAeH;AAC9D;YAEA,IAAIM,iBAAiB,KAAKT,oBAAoB3d,SAAS;gBACrD,OAAOie;AACT;YAGA,KAAK9B,aAAa;gBAChB,OAAOsC,kBAAkBT,eAAeD;AAC1C;YACA,OAAO7B,gBAAgBV,sBAAsByC,eAAeH;AAC9D;QAQA,SAASe,YAAa/N,OAAO9Q,QAAQ6c,OAAOiC,OAAO1B;YACjDtM,MAAMiO;gBACJ,IAAI/e,OAAOH,WAAW,GAAG;oBACvB,OAAOiR,MAAMoL,gBAAgBV,sBAAsB,OAAO;AAC5D;gBACA,KAAK1K,MAAMkL,cAAc;oBACvB,IAAId,2BAA2B1W,QAAQxE,kBAAkBmb,yBAAyB5R,KAAKvJ,SAAS;wBAC9F,OAAO8Q,MAAMoL,gBAAgBV,sBAAuB,MAAMxb,SAAS,MAAQ,MAAMA,SAAS;AAC5F;AACF;gBAEA,IAAMiD,SAAS6N,MAAM7N,SAASX,KAAKO,IAAI,GAAGga;gBAQ1C,IAAMf,YAAahL,MAAMgL,eAAc,SAEnCxZ,KAAKO,IAAIP,KAAKsB,IAAIkN,MAAMgL,WAAW,KAAKhL,MAAMgL,YAAY7Y;gBAG9D,IAAMkb,iBAAiBW,SAEpBhO,MAAM6K,aAAY,KAAMkB,SAAS/L,MAAM6K;gBAC1C,SAASqD,cAAehf;oBACtB,OAAO8c,sBAAsBhM,OAAO9Q;AACtC;gBAEA,QAAQke,kBAAkBle,QAAQme,gBAAgBrN,MAAM7N,QAAQ6Y,WAC9DkD,eAAelO,MAAMoL,aAAapL,MAAMqL,gBAAgB2C,OAAO1B;kBAC/D,KAAKS;oBACH,OAAO7d;;kBACT,KAAK8d;oBACH,OAAO,MAAM9d,OAAO0C,QAAQ,MAAM,QAAQ;;kBAC5C,KAAKqb;oBACH,OAAO,MAAMkB,YAAYjf,QAAQ8Q,MAAM7N,UACrCic,kBAAkB1C,aAAaxc,QAAQiD;;kBAC3C,KAAK+a;oBACH,OAAO,MAAMiB,YAAYjf,QAAQ8Q,MAAM7N,UACrCic,kBAAkB1C,aAAa2C,WAAWnf,QAAQ8b,YAAY7Y;;kBAClE,KAAKgb;oBACH,OAAO,MAAMmB,aAAapf,UAAqB;;kBACjD;oBACE,MAAM,IAAIoB,eAAc;;AAE9B;AACF;QAGA,SAAS6d,YAAajf,QAAQoe;YAC5B,IAAMiB,kBAAkB1B,oBAAoB3d,UAAUqE,OAAO+Z,kBAAkB;YAG/E,IAAMkB,OAAOtf,OAAOA,OAAOH,SAAS,OAAO;YAC3C,IAAM0f,OAAOD,SAAStf,OAAOA,OAAOH,SAAS,OAAO,QAAQG,WAAW;YACvE,IAAMwf,QAAQD,OAAO,MAAOD,OAAO,KAAK;YAExC,OAAOD,kBAAkBG,QAAQ;AACnC;QAGA,SAASN,kBAAmBlf;YAC1B,OAAOA,OAAOA,OAAOH,SAAS,OAAO,OAAOG,OAAOyC,MAAM,IAAG,KAAMzC;AACpE;QAIA,SAASmf,WAAYnf,QAAQyf;YAK3B,IAAMC,SAAS;YAGf,IAAIxf;gBACF,IAAIyf,SAAS3f,OAAOwE,QAAQ;gBAC5Bmb,SAASA,YAAW,IAAKA,SAAS3f,OAAOH;gBACzC6f,OAAOE,YAAYD;gBACnB,OAAOE,SAAS7f,OAAOyC,MAAM,GAAGkd,SAASF;AAC3C;YAEA,IAAIK,mBAAmB9f,OAAO,OAAO,QAAQA,OAAO,OAAO;YAC3D,IAAI+f;YAGJ,IAAIxc;YACJ,OAAQA,QAAQmc,OAAOjc,KAAKzD,SAAU;gBACpC,IAAM2S,SAASpP,MAAM;gBACrB,IAAMtC,OAAOsC,MAAM;gBAEnBwc,eAAgB9e,KAAK,OAAO;gBAC5Bf,UAAUyS,WACLmN,qBAAqBC,gBAAgB9e,SAAS,KAAM,OAAO,MAC9D4e,SAAS5e,MAAMwe;gBACjBK,mBAAmBC;AACrB;YAEA,OAAO7f;AACT;QAMA,SAAS2f,SAAU5e,MAAMwe;YACvB,IAAIxe,SAAS,MAAMA,KAAK,OAAO,KAAK,OAAOA;YAG3C,IAAM+e,UAAU;YAChB,IAAIzc;YAEJ,IAAI0P,QAAQ;YACZ,IAAIC;YACJ,IAAI+M,OAAO;YACX,IAAItD,OAAO;YACX,IAAIzc,SAAS;YAMb,OAAQqD,QAAQyc,QAAQvc,KAAKxC,OAAQ;gBACnC0b,OAAOpZ,MAAM3D;gBAEb,IAAI+c,OAAO1J,QAAQwM,OAAO;oBACxBvM,MAAO+M,OAAOhN,QAASgN,OAAOtD;oBAC9Bzc,UAAU,OAAOe,KAAKwB,MAAMwQ,OAAOC;oBAEnCD,QAAQC,MAAM;AAChB;gBACA+M,OAAOtD;AACT;YAIAzc,UAAU;YAEV,IAAIe,KAAKpB,SAASoT,QAAQwM,SAASQ,OAAOhN,OAAO;gBAC/C/S,UAAUe,KAAKwB,MAAMwQ,OAAOgN,QAAQ,OAAOhf,KAAKwB,MAAMwd,OAAO;AAC/D,mBAAO;gBACL/f,UAAUe,KAAKwB,MAAMwQ;AACvB;YAEA,OAAO/S,OAAOuC,MAAM;AACtB;QAGA,SAAS2c,aAAcpf;YACrB,IAAIE,SAAS;YACb,IAAIoe,OAAO;YAEX,KAAA,IAASza,IAAI,GAAGA,IAAI7D,OAAOH,QAAQye,QAAQ,QAAUza,KAAK,IAAIA,KAAK;gBACjEya,OAAOb,YAAYzd,QAAQ6D;gBAC3B,IAAMqc,YAAYjF,iBAAiBqD;gBAEnC,KAAK4B,aAAalD,YAAYsB,OAAO;oBACnCpe,UAAUF,OAAO6D;oBACjB,IAAIya,QAAQ,OAASpe,UAAUF,OAAO6D,IAAI;AAC5C,uBAAO;oBACL3D,UAAUggB,aAAa7E,UAAUiD;AACnC;AACF;YAEA,OAAOpe;AACT;QAEA,SAASigB,kBAAmBrP,OAAO+L,OAAO3V;YACxC,IAAIkM,UAAU;YACd,IAAM0C,OAAOhF,MAAMvM;YAEnB,KAAA,IAAS3E,QAAQ,GAAGC,SAASqH,OAAOrH,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACtE,IAAI2I,QAAQrB,OAAOtH;gBAEnB,IAAIkR,MAAMsL,UAAU;oBAClB7T,QAAQuI,MAAMsL,SAAS9a,KAAK4F,QAAQ7C,OAAOzE,QAAQ2I;AACrD;gBAGA,IAAI6X,UAAUtP,OAAO+L,OAAOtU,OAAO,OAAO,iBAC9BA,UAAU,eACjB6X,UAAUtP,OAAO+L,OAAO,MAAM,OAAO,QAAS;oBACjD,IAAIzJ,YAAY,IAAIA,WAAW,QAAQtC,MAAMmL,eAAe,MAAM;oBAClE7I,WAAWtC,MAAMiO;AACnB;AACF;YAEAjO,MAAMvM,MAAMuR;YACZhF,MAAMiO,OAAO,MAAM3L,UAAU;AAC/B;QAEA,SAASiN,mBAAoBvP,OAAO+L,OAAO3V,QAAQvG;YACjD,IAAIyS,UAAU;YACd,IAAM0C,OAAOhF,MAAMvM;YAEnB,KAAA,IAAS3E,QAAQ,GAAGC,SAASqH,OAAOrH,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACtE,IAAI2I,QAAQrB,OAAOtH;gBAEnB,IAAIkR,MAAMsL,UAAU;oBAClB7T,QAAQuI,MAAMsL,SAAS9a,KAAK4F,QAAQ7C,OAAOzE,QAAQ2I;AACrD;gBAGA,IAAI6X,UAAUtP,OAAO+L,QAAQ,GAAGtU,OAAO,MAAM,MAAM,OAAO,gBAC9CA,UAAU,eACjB6X,UAAUtP,OAAO+L,QAAQ,GAAG,MAAM,MAAM,MAAM,OAAO,OAAQ;oBAChE,KAAKlc,WAAWyS,YAAY,IAAI;wBAC9BA,WAAWwJ,iBAAiB9L,OAAO+L;AACrC;oBAEA,IAAI/L,MAAMiO,QAAQrF,mBAAmB5I,MAAMiO,KAAKzW,WAAW,IAAI;wBAC7D8K,WAAW;AACb,2BAAO;wBACLA,WAAW;AACb;oBAEAA,WAAWtC,MAAMiO;AACnB;AACF;YAEAjO,MAAMvM,MAAMuR;YACZhF,MAAMiO,OAAO3L,WAAW;AAC1B;QAEA,SAASkN,iBAAkBxP,OAAO+L,OAAO3V;YACvC,IAAIkM,UAAU;YACd,IAAM0C,OAAOhF,MAAMvM;YACnB,IAAMgc,gBAAgB7gB,OAAOC,KAAKuH;YAElC,KAAA,IAAStH,QAAQ,GAAGC,SAAS0gB,cAAc1gB,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBAC7E,IAAI4gB,aAAa;gBACjB,IAAIpN,YAAY,IAAIoN,cAAc;gBAElC,IAAI1P,MAAMmL,cAAcuE,cAAc;gBAEtC,IAAMC,YAAYF,cAAc3gB;gBAChC,IAAI8gB,cAAcxZ,OAAOuZ;gBAEzB,IAAI3P,MAAMsL,UAAU;oBAClBsE,cAAc5P,MAAMsL,SAAS9a,KAAK4F,QAAQuZ,WAAWC;AACvD;gBAEA,KAAKN,UAAUtP,OAAO+L,OAAO4D,WAAW,OAAO,QAAQ;oBACrD;AACF;gBAEA,IAAI3P,MAAMiO,KAAKlf,SAAS,MAAM2gB,cAAc;gBAE5CA,cAAc1P,MAAMiO,QAAQjO,MAAMmL,eAAe,MAAM,MAAM,OAAOnL,MAAMmL,eAAe,KAAK;gBAE9F,KAAKmE,UAAUtP,OAAO+L,OAAO6D,aAAa,OAAO,QAAQ;oBACvD;AACF;gBAEAF,cAAc1P,MAAMiO;gBAGpB3L,WAAWoN;AACb;YAEA1P,MAAMvM,MAAMuR;YACZhF,MAAMiO,OAAO,MAAM3L,UAAU;AAC/B;QAEA,SAASuN,kBAAmB7P,OAAO+L,OAAO3V,QAAQvG;YAChD,IAAIyS,UAAU;YACd,IAAM0C,OAAOhF,MAAMvM;YACnB,IAAMgc,gBAAgB7gB,OAAOC,KAAKuH;YAGlC,IAAI4J,MAAM+K,aAAa,MAAM;gBAE3B0E,cAAcK;8BACE9P,MAAM+K,aAAa,YAAY;gBAE/C0E,cAAcK,KAAK9P,MAAM+K;AAC3B,mBAAA,IAAW/K,MAAM+K,UAAU;gBAEzB,MAAM,IAAIza,eAAc;AAC1B;YAEA,KAAA,IAASxB,QAAQ,GAAGC,SAAS0gB,cAAc1gB,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBAC7E,IAAI4gB,aAAa;gBAEjB,KAAK7f,WAAWyS,YAAY,IAAI;oBAC9BoN,cAAc5D,iBAAiB9L,OAAO+L;AACxC;gBAEA,IAAM4D,YAAYF,cAAc3gB;gBAChC,IAAI8gB,cAAcxZ,OAAOuZ;gBAEzB,IAAI3P,MAAMsL,UAAU;oBAClBsE,cAAc5P,MAAMsL,SAAS9a,KAAK4F,QAAQuZ,WAAWC;AACvD;gBAEA,KAAKN,UAAUtP,OAAO+L,QAAQ,GAAG4D,WAAW,MAAM,MAAM,OAAO;oBAC7D;AACF;gBAEA,IAAMI,eAAgB/P,MAAMvM,QAAQ,QAAQuM,MAAMvM,QAAQ,OAC1CuM,MAAMiO,QAAQjO,MAAMiO,KAAKlf,SAAS;gBAElD,IAAIghB,cAAc;oBAChB,IAAI/P,MAAMiO,QAAQrF,mBAAmB5I,MAAMiO,KAAKzW,WAAW,IAAI;wBAC7DkY,cAAc;AAChB,2BAAO;wBACLA,cAAc;AAChB;AACF;gBAEAA,cAAc1P,MAAMiO;gBAEpB,IAAI8B,cAAc;oBAChBL,cAAc5D,iBAAiB9L,OAAO+L;AACxC;gBAEA,KAAKuD,UAAUtP,OAAO+L,QAAQ,GAAG6D,aAAa,MAAMG,eAAe;oBACjE;AACF;gBAEA,IAAI/P,MAAMiO,QAAQrF,mBAAmB5I,MAAMiO,KAAKzW,WAAW,IAAI;oBAC7DkY,cAAc;AAChB,uBAAO;oBACLA,cAAc;AAChB;gBAEAA,cAAc1P,MAAMiO;gBAGpB3L,WAAWoN;AACb;YAEA1P,MAAMvM,MAAMuR;YACZhF,MAAMiO,OAAO3L,WAAW;AAC1B;QAEA,SAAS0N,WAAYhQ,OAAO5J,QAAQb;YAClC,IAAMwS,WAAWxS,WAAWyK,MAAMuL,gBAAgBvL,MAAMT;YAExD,KAAA,IAASzQ,QAAQ,GAAGC,SAASgZ,SAAShZ,QAAQD,QAAQC,QAAQD,SAAS,GAAG;gBACxE,IAAMwF,QAAOyT,SAASjZ;gBAEtB,KAAKwF,MAAKP,cAAcO,MAAKN,gBACvBM,MAAKP,cAAgBpG,QAAOyI,YAAW,YAAcA,kBAAkB9B,MAAKP,iBAC5EO,MAAKN,aAAaM,MAAKN,UAAUoC,UAAU;oBAC/C,IAAIb,UAAU;wBACZ,IAAIjB,MAAKF,SAASE,MAAKJ,eAAe;4BACpC8L,MAAMvM,MAAMa,MAAKJ,cAAckC;AACjC,+BAAO;4BACL4J,MAAMvM,MAAMa,MAAKb;AACnB;AACF,2BAAO;wBACLuM,MAAMvM,MAAM;AACd;oBAEA,IAAIa,MAAKL,WAAW;wBAClB,IAAMZ,QAAQ2M,MAAM8K,SAASxW,MAAKb,QAAQa,MAAKH;wBAE/C,IAAImO,eAAO;wBACX,IAAIvG,UAAUvL,KAAK8D,MAAKL,eAAe,qBAAqB;4BAC1DqO,UAAUhO,MAAKL,UAAUmC,QAAQ/C;AACnC,mCAAWwI,gBAAgBrL,KAAK8D,MAAKL,WAAWZ,QAAQ;4BACtDiP,UAAUhO,MAAKL,UAAUZ,OAAO+C,QAAQ/C;AAC1C,+BAAO;4BACL,MAAM,IAAI/C,eAAc,OAAOgE,MAAKb,MAAM,iCAAiCJ,QAAQ;AACrF;wBAEA2M,MAAMiO,OAAO3L;AACf;oBAEA,OAAO;AACT;AACF;YAEA,OAAO;AACT;QAKA,SAASgN,UAAWtP,OAAO+L,OAAO3V,QAAQ6Z,OAAOpgB,SAASme,OAAOkC;YAC/DlQ,MAAMvM,MAAM;YACZuM,MAAMiO,OAAO7X;YAEb,KAAK4Z,WAAWhQ,OAAO5J,QAAQ,QAAQ;gBACrC4Z,WAAWhQ,OAAO5J,QAAQ;AAC5B;YAEA,IAAM9B,QAAOyH,UAAUvL,KAAKwP,MAAMiO;YAClC,IAAM3B,UAAU2D;YAEhB,IAAIA,OAAO;gBACTA,QAASjQ,MAAM6K,YAAY,KAAK7K,MAAM6K,YAAYkB;AACpD;YAEA,IAAMoE,gBAAgB7b,UAAS,qBAAqBA,UAAS;YAC7D,IAAI8b;YACJ,IAAIC;YAEJ,IAAIF,eAAe;gBACjBC,iBAAiBpQ,MAAMwL,WAAW9X,QAAQ0C;gBAC1Cia,YAAYD,oBAAmB;AACjC;YAEA,IAAKpQ,MAAMvM,QAAQ,QAAQuM,MAAMvM,QAAQ,OAAQ4c,aAAcrQ,MAAM7N,WAAW,KAAK4Z,QAAQ,GAAI;gBAC/Flc,UAAU;AACZ;YAEA,IAAIwgB,aAAarQ,MAAMyL,eAAe2E,iBAAiB;gBACrDpQ,MAAMiO,OAAO,UAAUmC;AACzB,mBAAO;gBACL,IAAID,iBAAiBE,cAAcrQ,MAAMyL,eAAe2E,iBAAiB;oBACvEpQ,MAAMyL,eAAe2E,kBAAkB;AACzC;gBACA,IAAI9b,UAAS,mBAAmB;oBAC9B,IAAI2b,SAAUrhB,OAAOC,KAAKmR,MAAMiO,MAAMlf,WAAW,GAAI;wBACnD8gB,kBAAkB7P,OAAO+L,OAAO/L,MAAMiO,MAAMpe;wBAC5C,IAAIwgB,WAAW;4BACbrQ,MAAMiO,OAAO,UAAUmC,iBAAiBpQ,MAAMiO;AAChD;AACF,2BAAO;wBACLuB,iBAAiBxP,OAAO+L,OAAO/L,MAAMiO;wBACrC,IAAIoC,WAAW;4BACbrQ,MAAMiO,OAAO,UAAUmC,iBAAiB,MAAMpQ,MAAMiO;AACtD;AACF;AACF,uBAAA,IAAW3Z,UAAS,kBAAkB;oBACpC,IAAI2b,SAAUjQ,MAAMiO,KAAKlf,WAAW,GAAI;wBACtC,IAAIiR,MAAM2K,kBAAkBuF,cAAcnE,QAAQ,GAAG;4BACnDwD,mBAAmBvP,OAAO+L,QAAQ,GAAG/L,MAAMiO,MAAMpe;AACnD,+BAAO;4BACL0f,mBAAmBvP,OAAO+L,OAAO/L,MAAMiO,MAAMpe;AAC/C;wBACA,IAAIwgB,WAAW;4BACbrQ,MAAMiO,OAAO,UAAUmC,iBAAiBpQ,MAAMiO;AAChD;AACF,2BAAO;wBACLoB,kBAAkBrP,OAAO+L,OAAO/L,MAAMiO;wBACtC,IAAIoC,WAAW;4BACbrQ,MAAMiO,OAAO,UAAUmC,iBAAiB,MAAMpQ,MAAMiO;AACtD;AACF;AACF,uBAAA,IAAW3Z,UAAS,mBAAmB;oBACrC,IAAI0L,MAAMvM,QAAQ,KAAK;wBACrBsa,YAAY/N,OAAOA,MAAMiO,MAAMlC,OAAOiC,OAAO1B;AAC/C;AACF,uBAAA,IAAWhY,UAAS,sBAAsB;oBACxC,OAAO;AACT,uBAAO;oBACL,IAAI0L,MAAM4K,aAAa,OAAO;oBAC9B,MAAM,IAAIta,eAAc,4CAA4CgE;AACtE;gBAEA,IAAI0L,MAAMvM,QAAQ,QAAQuM,MAAMvM,QAAQ,KAAK;oBAc3C,IAAI6c,SAASC,UACXvQ,MAAMvM,IAAI,OAAO,MAAMuM,MAAMvM,IAAI9B,MAAM,KAAKqO,MAAMvM,KAClD7B,QAAQ,MAAM;oBAEhB,IAAIoO,MAAMvM,IAAI,OAAO,KAAK;wBACxB6c,SAAS,MAAMA;AACjB,+BAAWA,OAAO3e,MAAM,GAAG,QAAQ,sBAAsB;wBACvD2e,SAAS,OAAOA,OAAO3e,MAAM;AAC/B,2BAAO;wBACL2e,SAAS,OAAOA,SAAS;AAC3B;oBAEAtQ,MAAMiO,OAAOqC,SAAS,MAAMtQ,MAAMiO;AACpC;AACF;YAEA,OAAO;AACT;QAEA,SAASuC,uBAAwBpa,QAAQ4J;YACvC,IAAMyQ,UAAU;YAChB,IAAMC,oBAAoB;YAE1BC,YAAYva,QAAQqa,SAASC;YAE7B,IAAM3hB,SAAS2hB,kBAAkB3hB;YACjC,KAAA,IAASD,QAAQ,GAAGA,QAAQC,QAAQD,SAAS,GAAG;gBAC9CkR,MAAMwL,WAAW5Y,KAAK6d,QAAQC,kBAAkB5hB;AAClD;YACAkR,MAAMyL,iBAAiB,IAAInd,MAAMS;AACnC;QAEA,SAAS4hB,YAAava,QAAQqa,SAASC;YACrC,IAAIta,WAAW,QAAQzI,QAAOyI,YAAW,UAAU;gBACjD,IAAMtH,QAAQ2hB,QAAQ/c,QAAQ0C;gBAC9B,IAAItH,WAAU,GAAI;oBAChB,IAAI4hB,kBAAkBhd,QAAQ5E,YAAW,GAAI;wBAC3C4hB,kBAAkB9d,KAAK9D;AACzB;AACF,uBAAO;oBACL2hB,QAAQ7d,KAAKwD;oBAEb,IAAI9H,MAAMC,QAAQ6H,SAAS;wBACzB,KAAA,IAASrD,IAAI,GAAGhE,SAASqH,OAAOrH,QAAQgE,IAAIhE,QAAQgE,KAAK,GAAG;4BAC1D4d,YAAYva,OAAOrD,IAAI0d,SAASC;AAClC;AACF,2BAAO;wBACL,IAAMjB,gBAAgB7gB,OAAOC,KAAKuH;wBAElC,KAAA,IAASrD,KAAI,GAAGhE,UAAS0gB,cAAc1gB,QAAQgE,KAAIhE,SAAQgE,MAAK,GAAG;4BACjE4d,YAAYva,OAAOqZ,cAAc1c,MAAK0d,SAASC;AACjD;AACF;AACF;AACF;AACF;QAEA,SAASzC,MAAM1S,OAAOtJ;YACpBA,UAAUA,WAAW,CAAA;YAErB,IAAM+N,QAAQ,IAAIhB,MAAM/M;YAExB,KAAK+N,MAAMiL,QAAQuF,uBAAuBjV,OAAOyE;YAEjD,IAAIvI,QAAQ8D;YAEZ,IAAIyE,MAAMsL,UAAU;gBAClB7T,QAAQuI,MAAMsL,SAAS9a,KAAK;oBAAE,IAAIiH;mBAAS,IAAIA;AACjD;YAEA,IAAI6X,UAAUtP,OAAO,GAAGvI,OAAO,MAAM,OAAO,OAAOuI,MAAMiO,OAAO;YAEhE,OAAO;AACT;QAEA2C,OAAA3C,OAAsBA;;;;;;;QCt6BtB,IAAMxF,UAAS3X;QACf,IAAM8f,UAASrc;QAEf,SAASsc,QAASC,MAAMC;YACtB,OAAO;gBACL,MAAM,IAAIxgB,MAAM,mBAAmBugB,OAAO,wCAC1BC,KAAK;;AAEzB;QAEAC,OAAAxd,OAAsBuC;QACtBib,OAAA5b,SAAwBY;QACxBgb,OAAAC,kBAAiC3X;QACjC0X,OAAAE,cAA6BnU;QAC7BiU,OAAAG,cAA6BnU;QAC7BgU,OAAA/T,iBAAgCmU;QAChCJ,OAAAxI,OAAsBC,QAAOD;QAC7BwI,OAAAzI,UAAyBE,QAAOF;QAChCyI,OAAA/C,OAAsB2C,QAAO3C;QAC7B+C,OAAA1gB,gBAA+B+gB;QAG/BL,OAAAM,QAAuB;YACrBvZ,QAAQwZ;YACRnY,OAAOoY;YACPre,KAAKse;YACLC,MAAMC;YACNjV,OAAOkV;YACP/U,KAAKgV;YACLhX,WAAWiX;YACXhb,MAAMib;YACNja,KAAKka;YACLjX,OAAOkX;YACP1V,MAAM2V;YACNrc,KAAKsc;YACLzgB,KAAK0gB;;QAIPpB,OAAAqB,WAA0BxB,QAAQ,YAAY;QAC9CG,OAAAsB,cAA6BzB,QAAQ,eAAe;QACpDG,OAAAuB,WAA0B1B,QAAQ,YAAY;;;;;ICzC9C,IACErd,OAcEgf,KAdFhf,MACA4B,SAaEod,KAbFpd,QACA6b,kBAYEuB,KAZFvB,iBACAC,cAWEsB,KAXFtB,aACAC,cAUEqB,KAVFrB,aACAlU,iBASEuV,KATFvV,gBACAuL,OAQEgK,KARFhK,MACAD,UAOEiK,KAPFjK,SACA0F,OAMEuE,KANFvE,MACA3d,gBAKEkiB,KALFliB,eACAghB,QAIEkB,KAJFlB,OACAe,WAGEG,KAHFH,UACAC,cAEEE,KAFFF,aACAC,WACEC,KADFD;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.min.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.min.js new file mode 100644 index 0000000..c8818a2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.min.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).jsyaml={})}(this,function(e){"use strict";function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var n,r,i,o,a,l,u,c,s,p,f,d,h,m,g,y,v,b,A,k,w,x,C,S,I,T,O,j,M,F,E,N,L,_,D,U,Y,q,K,R,H,P,B,W,$={},G={},Z={};function V(){if(n)return Z;function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(t)}function t(e){return null==e}return n=1,Z.isNothing=t,Z.isObject=function(t){return"object"===e(t)&&null!==t},Z.toArray=function(e){return Array.isArray(e)?e:t(e)?[]:[e]},Z.repeat=function(e,t){for(var n="",r=0;r=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102}function r(e){return e>=48&&e<=55}function i(e){return e>=48&&e<=57}function o(e){var t=e,n=1,r=t[0];if("-"!==r&&"+"!==r||("-"===r&&(n=-1),r=(t=t.slice(1))[0]),"0"===t)return 0;if("0"===r){if("b"===t[1])return n*parseInt(t.slice(2),2);if("x"===t[1])return n*parseInt(t.slice(2),16);if("o"===t[1])return n*parseInt(t.slice(2),8)}return n*parseInt(t,10)}return x=new t("tag:yaml.org,2002:int",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t=e.length,a=0,l=!1;if(!t)return!1;var u=e[a];if("-"!==u&&"+"!==u||(u=e[++a]),"0"===u){if(a+1===t)return!0;if("b"===(u=e[++a])){for(a++;a=0?"0b"+e.toString(2):"-0b"+e.toString(2).slice(1)},octal:function(e){return e>=0?"0o"+e.toString(8):"-0o"+e.toString(8).slice(1)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return e>=0?"0x"+e.toString(16).toUpperCase():"-0x"+e.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}})}function ae(){if(I)return S;I=1;var e=V(),t=Q(),n=new RegExp("^(?:[-+]?(?:[0-9]+)(?:\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"),r=new RegExp("^(?:[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");var i=/^[-+]?[0-9]+e/;return S=new t("tag:yaml.org,2002:float",{kind:"scalar",resolve:function(e){return null!==e&&(!!n.test(e)&&(!!isFinite(parseFloat(e,10))||r.test(e)))},construct:function(e){var t=e.toLowerCase(),n="-"===t[0]?-1:1;return"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===n?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:n*parseFloat(t,10)},predicate:function(t){return"[object Number]"===Object.prototype.toString.call(t)&&(t%1!=0||e.isNegativeZero(t))},represent:function(t,n){if(isNaN(t))switch(n){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===t)switch(n){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===t)switch(n){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(e.isNegativeZero(t))return"-0.0";var r=t.toString(10);return i.test(r)?r.replace("e",".e"):r},defaultStyle:"lowercase"})}function le(){return O?T:(O=1,T=ne().extend({implicit:[re(),ie(),oe(),ae()]}))}function ue(){return M?j:(M=1,j=le())}function ce(){if(E)return F;E=1;var e=Q(),t=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),n=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");return F=new e("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:function(e){return null!==e&&(null!==t.exec(e)||null!==n.exec(e))},construct:function(e){var r=0,i=null,o=t.exec(e);if(null===o&&(o=n.exec(e)),null===o)throw new Error("Date resolve error");var a=+o[1],l=+o[2]-1,u=+o[3];if(!o[4])return new Date(Date.UTC(a,l,u));var c=+o[4],s=+o[5],p=+o[6];if(o[7]){for(r=o[7].slice(0,3);r.length<3;)r+="0";r=+r}o[9]&&(i=6e4*(60*+o[10]+ +(o[11]||0)),"-"===o[9]&&(i=-i));var f=new Date(Date.UTC(a,l,u,c,s,p,r));return i&&f.setTime(f.getTime()-i),f},instanceOf:Date,represent:function(e){return e.toISOString()}})}function se(){if(L)return N;L=1;var e=Q();return N=new e("tag:yaml.org,2002:merge",{kind:"scalar",resolve:function(e){return"<<"===e||null===e}})}function pe(){if(D)return _;D=1;var e=Q(),t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";return _=new e("tag:yaml.org,2002:binary",{kind:"scalar",resolve:function(e){if(null===e)return!1;for(var n=0,r=e.length,i=t,o=0;o64)){if(a<0)return!1;n+=6}}return n%8==0},construct:function(e){for(var n=e.replace(/[\r\n=]/g,""),r=n.length,i=t,o=0,a=[],l=0;l>16&255),a.push(o>>8&255),a.push(255&o)),o=o<<6|i.indexOf(n.charAt(l));var u=r%4*6;return 0===u?(a.push(o>>16&255),a.push(o>>8&255),a.push(255&o)):18===u?(a.push(o>>10&255),a.push(o>>2&255)):12===u&&a.push(o>>4&255),new Uint8Array(a)},predicate:function(e){return"[object Uint8Array]"===Object.prototype.toString.call(e)},represent:function(e){for(var n="",r=0,i=e.length,o=t,a=0;a>18&63],n+=o[r>>12&63],n+=o[r>>6&63],n+=o[63&r]),r=(r<<8)+e[a];var l=i%3;return 0===l?(n+=o[r>>18&63],n+=o[r>>12&63],n+=o[r>>6&63],n+=o[63&r]):2===l?(n+=o[r>>10&63],n+=o[r>>4&63],n+=o[r<<2&63],n+=o[64]):1===l&&(n+=o[r>>2&63],n+=o[r<<4&63],n+=o[64],n+=o[64]),n}})}function fe(){if(Y)return U;Y=1;var e=Q(),t=Object.prototype.hasOwnProperty,n=Object.prototype.toString;return U=new e("tag:yaml.org,2002:omap",{kind:"sequence",resolve:function(e){if(null===e)return!0;for(var r={},i=e,o=0,a=i.length;ol&&(t=r-l+(o=" ... ").length),n-r>l&&(n=r+l-(a=" ...").length),{str:o+e.slice(t,n).replace(/\t/g,"→")+a,pos:r-t+o.length}}function n(t,n){return e.repeat(" ",n-t.length)+t}return o=function(r,i){if(i=Object.create(i||null),!r.buffer)return null;i.maxLength||(i.maxLength=79),"number"!=typeof i.indent&&(i.indent=1),"number"!=typeof i.linesBefore&&(i.linesBefore=3),"number"!=typeof i.linesAfter&&(i.linesAfter=2);for(var o,a=/\r?\n|\r|\0/g,l=[0],u=[],c=-1;o=a.exec(r.buffer);)u.push(o.index),l.push(o.index+o[0].length),r.position<=o.index&&c<0&&(c=l.length-2);c<0&&(c=l.length-1);for(var s="",p=Math.min(r.line+i.linesAfter,u.length).toString().length,f=i.maxLength-(i.indent+p+3),d=1;d<=i.linesBefore&&!(c-d<0);d++){var h=t(r.buffer,l[c-d],u[c-d],r.position-(l[c]-l[c-d]),f);s=e.repeat(" ",i.indent)+n((r.line-d+1).toString(),p)+" | "+h.str+"\n"+s}var m=t(r.buffer,l[c],u[c],r.position,f);s+=e.repeat(" ",i.indent)+n((r.line+1).toString(),p)+" | "+m.str+"\n",s+=e.repeat("-",i.indent+p+3+m.pos)+"^\n";for(var g=1;g<=i.linesAfter&&!(c+g>=u.length);g++){var y=t(r.buffer,l[c+g],u[c+g],r.position-(l[c]-l[c+g]),f);s+=e.repeat(" ",i.indent)+n((r.line+g+1).toString(),p)+" | "+y.str+"\n"}return s.replace(/\n$/,"")}}(),i=me(),l=Object.prototype.hasOwnProperty,u=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,c=/[\x85\u2028\u2029]/,s=/[,\[\]{}]/,p=/^(?:!|!!|![0-9A-Za-z-]+!)$/,f=/^(?:!|[^,\[\]{}])(?:%[0-9a-f]{2}|[0-9a-z\-#;/?:@&=+$,_.!~*'()\[\]])*$/i;function d(e){return Object.prototype.toString.call(e)}function h(e){return 10===e||13===e}function m(e){return 9===e||32===e}function g(e){return 9===e||32===e||10===e||13===e}function y(e){return 44===e||91===e||93===e||123===e||125===e}function v(e){if(e>=48&&e<=57)return e-48;var t=32|e;return t>=97&&t<=102?t-97+10:-1}function b(e){return 120===e?2:117===e?4:85===e?8:0}function A(e){return e>=48&&e<=57?e-48:-1}function k(e){switch(e){case 48:return"\0";case 97:return"";case 98:return"\b";case 116:case 9:return"\t";case 110:return"\n";case 118:return"\v";case 102:return"\f";case 114:return"\r";case 101:return"";case 32:return" ";case 34:return'"';case 47:return"/";case 92:return"\\";case 78:return"…";case 95:return" ";case 76:return"\u2028";case 80:return"\u2029";default:return""}}function w(e){return e<=65535?String.fromCharCode(e):String.fromCharCode(55296+(e-65536>>10),56320+(e-65536&1023))}function x(e,t,n){"__proto__"===t?Object.defineProperty(e,t,{configurable:!0,enumerable:!0,writable:!0,value:n}):e[t]=n}for(var C=new Array(256),S=new Array(256),I=0;I<256;I++)C[I]=k(I)?1:0,S[I]=k(I);function T(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||i,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.maxDepth="number"==typeof t.maxDepth?t.maxDepth:100,this.maxTotalMergeKeys="number"==typeof t.maxTotalMergeKeys?t.maxTotalMergeKeys:1e4,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.depth=0,this.totalMergeKeys=0,this.firstTabInLine=-1,this.documents=[],this.anchorMapTransactions=[]}function O(e,t){var i={name:e.filename,buffer:e.input.slice(0,-1),position:e.position,line:e.line,column:e.position-e.lineStart};return i.snippet=r(i),new n(t,i)}function j(e,t){throw O(e,t)}function M(e,t){e.onWarning&&e.onWarning.call(null,O(e,t))}function F(e,t,n){var r=e.anchorMapTransactions;if(0!==r.length){var i=r[r.length-1];l.call(i,t)||(i[t]={existed:l.call(e.anchorMap,t),value:e.anchorMap[t]})}e.anchorMap[t]=n}function E(e){return{position:e.position,line:e.line,lineStart:e.lineStart,lineIndent:e.lineIndent,firstTabInLine:e.firstTabInLine,tag:e.tag,anchor:e.anchor,kind:e.kind,result:e.result}}function N(e,t){e.position=t.position,e.line=t.line,e.lineStart=t.lineStart,e.lineIndent=t.lineIndent,e.firstTabInLine=t.firstTabInLine,e.tag=t.tag,e.anchor=t.anchor,e.kind=t.kind,e.result=t.result}var L={YAML:function(e,t,n){null!==e.version&&j(e,"duplication of %YAML directive"),1!==n.length&&j(e,"YAML directive accepts exactly one argument");var r=/^([0-9]+)\.([0-9]+)$/.exec(n[0]);null===r&&j(e,"ill-formed argument of the YAML directive");var i=parseInt(r[1],10),o=parseInt(r[2],10);1!==i&&j(e,"unacceptable YAML version of the document"),e.version=n[0],e.checkLineBreaks=o<2,1!==o&&2!==o&&M(e,"unsupported YAML version of the document")},TAG:function(e,t,n){var r;2!==n.length&&j(e,"TAG directive accepts exactly two arguments");var i=n[0];r=n[1],p.test(i)||j(e,"ill-formed tag handle (first argument) of the TAG directive"),l.call(e.tagMap,i)&&j(e,'there is a previously declared suffix for "'+i+'" tag handle'),f.test(r)||j(e,"ill-formed tag prefix (second argument) of the TAG directive");try{r=decodeURIComponent(r)}catch(t){j(e,"tag prefix is malformed: "+r)}e.tagMap[i]=r}};function _(e,t,n,r){if(t=32&&l<=1114111||j(e,"expected valid JSON character")}else u.test(i)&&j(e,"the stream contains non-printable characters");e.result+=i}}function D(e,n,r,i){t.isObject(r)||j(e,"cannot merge mappings; the provided source object is unacceptable");for(var o=Object.keys(r),a=0,u=o.length;ae.maxTotalMergeKeys&&j(e,"merge keys exceeded maxTotalMergeKeys ("+e.maxTotalMergeKeys+")"),l.call(n,c)||(x(n,c,r[c]),i[c]=!0)}}function U(t,n,r,i,o,a,u,c,s){if(Array.isArray(o))for(var p=0,f=(o=Array.prototype.slice.call(o)).length;p1&&(e.result+=t.repeat("\n",n-1))}function H(e,t){var n=e.tag,r=e.anchor,i=[],o=!1;if(-1!==e.firstTabInLine)return!1;null!==e.anchor&&F(e,e.anchor,i);for(var a=e.input.charCodeAt(e.position);0!==a&&(-1!==e.firstTabInLine&&(e.position=e.firstTabInLine,j(e,"tab characters must not be used in indentation")),45===a);){if(!g(e.input.charCodeAt(e.position+1)))break;if(o=!0,e.position++,q(e,!0,-1)&&e.lineIndent<=t)i.push(null),a=e.input.charCodeAt(e.position);else{var l=e.line;if(Q(e,t,3,!1,!0),i.push(e.result),q(e,!0,-1),a=e.input.charCodeAt(e.position),(e.line===l||e.lineIndent>t)&&0!==a)j(e,"bad indentation of a sequence entry");else if(e.lineIndentt)&&(h&&(i=e.line,o=e.lineStart,a=e.position),Q(e,t,4,!0,r)&&(h?f=e.result:d=e.result),h||(U(e,c,s,p,f,d,i,o,a),p=f=d=null),q(e,!0,-1),v=e.input.charCodeAt(e.position)),(e.line===A||e.lineIndent>t)&&0!==v)j(e,"bad indentation of a mapping entry");else if(e.lineIndent=0;r-=1){var i=t[n[r]];i.existed?e.anchorMap[n[r]]=i.value:delete e.anchorMap[n[r]]}}(e),N(e,i),!1)}function Q(e,n,r,i,o){var a,u,c,s,p,f=1,d=!1,k=!1,x=null;e.depth>=e.maxDepth&&j(e,"nesting exceeded maxDepth ("+e.maxDepth+")"),e.depth+=1,null!==e.listener&&e.listener("open",e),e.tag=null,e.anchor=null,e.kind=null,e.result=null;var I=a=u=4===r||3===r;if(i&&q(e,!0,-1)&&(d=!0,e.lineIndent>n?f=1:e.lineIndent===n?f=0:e.lineIndentn?f=1:e.lineIndent===n?f=0:e.lineIndent=0))break;0===i?j(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):l?j(e,"repeat of an indentation width identifier"):(u=n+i-1,l=!0)}if(m(p)){do{p=e.input.charCodeAt(++e.position)}while(m(p));if(35===p)do{p=e.input.charCodeAt(++e.position)}while(!h(p)&&0!==p)}for(;0!==p;){for(Y(e),e.lineIndent=0,p=e.input.charCodeAt(e.position);(!l||e.lineIndentu&&(u=e.lineIndent),h(p))c++;else{if(l||0!==u||j(e,"missing indentation for block scalar"),e.lineIndent0){for(var a=i,l=0;a>0;a--)(i=v(o=e.input.charCodeAt(++e.position)))>=0?l=(l<<4)+i:j(e,"expected hexadecimal character");e.result+=w(l),e.position++}else j(e,"unknown escape sequence");n=r=e.position}else h(o)?(_(e,n,r,!0),R(e,q(e,!1,t)),n=r=e.position):e.position===e.lineStart&&K(e)?j(e,"unexpected end of the document within a double quoted scalar"):(e.position++,m(o)||(r=e.position))}j(e,"unexpected end of the stream within a double quoted scalar")}(e,s)?k=!0:!function(e){var t=e.input.charCodeAt(e.position);if(42!==t)return!1;t=e.input.charCodeAt(++e.position);for(var n=e.position;0!==t&&!g(t)&&!y(t);)t=e.input.charCodeAt(++e.position);e.position===n&&j(e,"name of an alias node must contain at least one character");var r=e.input.slice(n,e.position);return l.call(e.anchorMap,r)||j(e,'unidentified alias "'+r+'"'),e.result=e.anchorMap[r],q(e,!0,-1),!0}(e)?function(e,t,n){var r,i,o,a,l,u,c=e.kind,s=e.result,p=e.input.charCodeAt(e.position);if(g(p)||y(p)||35===p||38===p||42===p||33===p||124===p||62===p||39===p||34===p||37===p||64===p||96===p)return!1;if(63===p||45===p){var f=e.input.charCodeAt(e.position+1);if(g(f)||n&&y(f))return!1}for(e.kind="scalar",e.result="",r=i=e.position,o=!1;0!==p;){if(58===p){var d=e.input.charCodeAt(e.position+1);if(g(d)||n&&y(d))break}else if(35===p){if(g(e.input.charCodeAt(e.position-1)))break}else{if(e.position===e.lineStart&&K(e)||n&&y(p))break;if(h(p)){if(a=e.line,l=e.lineStart,u=e.lineIndent,q(e,!1,-1),e.lineIndent>=t){o=!0,p=e.input.charCodeAt(e.position);continue}e.position=i,e.line=a,e.lineStart=l,e.lineIndent=u;break}}o&&(_(e,r,i,!1),R(e,e.line-a),r=i=e.position,o=!1),m(p)||(i=e.position+1),p=e.input.charCodeAt(++e.position)}return _(e,r,i,!1),!!e.result||(e.kind=c,e.result=s,!1)}(e,s,1===r)&&(k=!0,null===e.tag&&(e.tag="?")):(k=!0,null===e.tag&&null===e.anchor||j(e,"alias node should not have any properties")),null!==e.anchor&&F(e,e.anchor,e.result)}else 0===f&&(k=u&&H(e,p));if(null===e.tag)null!==e.anchor&&F(e,e.anchor,e.result);else if("?"===e.tag){null!==e.result&&"scalar"!==e.kind&&j(e,'unacceptable node kind for ! tag; it should be "scalar", not "'+e.kind+'"');for(var N=0,L=e.implicitTypes.length;N"),null!==e.result&&c.kind!==e.kind&&j(e,"unacceptable node kind for !<"+e.tag+'> tag; it should be "'+c.kind+'", not "'+e.kind+'"'),c.resolve(e.result,e.tag)?(e.result=c.construct(e.result,e.tag),null!==e.anchor&&F(e,e.anchor,e.result)):j(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")}return null!==e.listener&&e.listener("close",e),e.depth-=1,null!==e.tag||null!==e.anchor||k}function z(e){var t,n=e.position,r=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap=Object.create(null),e.anchorMap=Object.create(null);0!==(t=e.input.charCodeAt(e.position))&&(q(e,!0,-1),t=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==t));){r=!0,t=e.input.charCodeAt(++e.position);for(var i=e.position;0!==t&&!g(t);)t=e.input.charCodeAt(++e.position);var o=e.input.slice(i,e.position),a=[];for(o.length<1&&j(e,"directive name must not be less than one character in length");0!==t;){for(;m(t);)t=e.input.charCodeAt(++e.position);if(35===t){do{t=e.input.charCodeAt(++e.position)}while(0!==t&&!h(t));break}if(h(t))break;for(i=e.position;0!==t&&!g(t);)t=e.input.charCodeAt(++e.position);a.push(e.input.slice(i,e.position))}0!==t&&Y(e),l.call(L,o)?L[o](e,o,a):M(e,'unknown document directive "'+o+'"')}q(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,q(e,!0,-1)):r&&j(e,"directives end mark is expected"),Q(e,e.lineIndent-1,4,!1,!0),q(e,!0,-1),e.checkLineBreaks&&c.test(e.input.slice(n,e.position))&&M(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&K(e)?46===e.input.charCodeAt(e.position)&&(e.position+=3,q(e,!0,-1)):e.position=32&&e<=126||e>=161&&e<=55295&&8232!==e&&8233!==e||e>=57344&&e<=65533&&e!==a||e>=65536&&e<=1114111}function g(e){return m(e)&&e!==a&&13!==e&&10!==e}function y(e,t,n){var r=g(e),i=r&&!h(e);return(n?r:r&&44!==e&&91!==e&&93!==e&&123!==e&&125!==e)&&35!==e&&!(58===t&&!i)||g(t)&&!h(t)&&35===e||58===t&&i}function v(e,t){var n,r=e.charCodeAt(t);return r>=55296&&r<=56319&&t+1=56320&&n<=57343?1024*(r-55296)+n-56320+65536:r}function b(e){return/^\n* /.test(e)}function A(e,t,n,r,i,o,l,u){var c,s,p=0,f=null,d=!1,g=!1,A=-1!==r,k=-1,w=m(s=v(e,0))&&s!==a&&!h(s)&&45!==s&&63!==s&&58!==s&&44!==s&&91!==s&&93!==s&&123!==s&&125!==s&&35!==s&&38!==s&&42!==s&&33!==s&&124!==s&&61!==s&&62!==s&&39!==s&&34!==s&&37!==s&&64!==s&&96!==s&&function(e){return!h(e)&&58!==e}(v(e,e.length-1));if(t||l)for(c=0;c=65536?c+=2:c++){if(!m(p=v(e,c)))return 5;w=w&&y(p,f,u),f=p}else{for(c=0;c=65536?c+=2:c++){if(10===(p=v(e,c)))d=!0,A&&(g=g||c-k-1>r&&" "!==e[k+1],k=c);else if(!m(p))return 5;w=w&&y(p,f,u),f=p}g=g||A&&c-k-1>r&&" "!==e[k+1]}return d||g?n>9&&b(e)?5:l?2===o?5:2:g?4:3:!w||l||i(e)?2===o?5:2:1}function k(e,t,r,i,o){e.dump=function(){if(0===t.length)return 2===e.quotingType?'""':"''";if(!e.noCompatMode&&(-1!==u.indexOf(t)||c.test(t)))return 2===e.quotingType?'"'+t+'"':"'"+t+"'";var a=e.indent*Math.max(1,r),p=-1===e.lineWidth?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-a),d=i||e.flowLevel>-1&&r>=e.flowLevel;switch(A(t,d,e.indent,p,function(t){return function(e,t){for(var n=0,r=e.implicitTypes.length;n"+w(t,e.indent)+x(f(function(e,t){var n,r,i=/(\n+)([^\n]*)/g,o=(l=e.indexOf("\n"),l=-1!==l?l:e.length,i.lastIndex=l,C(e.slice(0,l),t)),a="\n"===e[0]||" "===e[0];var l;for(;r=i.exec(e);){var u=r[1],c=r[2];n=" "===c[0],o+=u+(a||n||""===c?"":"\n")+C(c,t),a=n}return o}(t,p),a));case 5:return'"'+function(e){for(var t="",n=0,r=0;r=65536?r+=2:r++){n=v(e,r);var i=l[n];!i&&m(n)?(t+=e[r],n>=65536&&(t+=e[r+1])):t+=i||s(n)}return t}(t)+'"';default:throw new n("impossible error: invalid scalar style")}}()}function w(e,t){var n=b(e)?String(t):"",r="\n"===e[e.length-1];return n+(r&&("\n"===e[e.length-2]||"\n"===e)?"+":r?"":"-")+"\n"}function x(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function C(e,t){if(""===e||" "===e[0])return e;for(var n,r,i=/ [^ ]/g,o=0,a=0,l=0,u="";n=i.exec(e);)(l=n.index)-o>t&&(r=a>o?a:l,u+="\n"+e.slice(o,r),o=r+1),a=l;return u+="\n",e.length-o>t&&a>o?u+=e.slice(o,a)+"\n"+e.slice(a+1):u+=e.slice(o),u.slice(1)}function S(e,t,n,r){for(var i="",o=e.tag,a=0,l=n.length;a tag resolver accepts not "'+p+'" style');f=s.represent[p](r,p)}t.dump=f}return!0}}return!1}function T(e,t,r,o,a,l,u){e.tag=null,e.dump=r,I(e,r,!1)||I(e,r,!0);var c=i.call(e.dump),s=o;o&&(o=e.flowLevel<0||e.flowLevel>t);var p,f,h="[object Object]"===c||"[object Array]"===c;if(h&&(f=-1!==(p=e.duplicates.indexOf(r))),(null!==e.tag&&"?"!==e.tag||f||2!==e.indent&&t>0)&&(a=!1),f&&e.usedDuplicates[p])e.dump="*ref_"+p;else{if(h&&f&&!e.usedDuplicates[p]&&(e.usedDuplicates[p]=!0),"[object Object]"===c)o&&0!==Object.keys(e.dump).length?(!function(e,t,r,i){var o="",a=e.tag,l=Object.keys(r);if(!0===e.sortKeys)l.sort();else if("function"==typeof e.sortKeys)l.sort(e.sortKeys);else if(e.sortKeys)throw new n("sortKeys must be a boolean or a function");for(var u=0,c=l.length;u1024;h&&(e.dump&&10===e.dump.charCodeAt(0)?s+="?":s+="? "),s+=e.dump,h&&(s+=d(e,t)),T(e,t+1,f,!0,h)&&(e.dump&&10===e.dump.charCodeAt(0)?s+=":":s+=": ",o+=s+=e.dump)}}e.tag=a,e.dump=o||"{}"}(e,t,e.dump,a),f&&(e.dump="&ref_"+p+e.dump)):(!function(e,t,n){for(var r="",i=e.tag,o=Object.keys(n),a=0,l=o.length;a1024&&(u+="? "),u+=e.dump+(e.condenseFlow?'"':"")+":"+(e.condenseFlow?"":" "),T(e,t,s,!1,!1)&&(r+=u+=e.dump))}e.tag=i,e.dump="{"+r+"}"}(e,t,e.dump),f&&(e.dump="&ref_"+p+" "+e.dump));else if("[object Array]"===c)o&&0!==e.dump.length?(e.noArrayIndent&&!u&&t>0?S(e,t-1,e.dump,a):S(e,t,e.dump,a),f&&(e.dump="&ref_"+p+e.dump)):(!function(e,t,n){for(var r="",i=e.tag,o=0,a=n.length;o",e.dump=m+" "+e.dump}}return!0}function O(e,t){var n=[],r=[];j(e,n,r);for(var i=r.length,o=0;o= 0x30/* 0 */) && (c <= 0x39/* 9 */)) ||\n ((c >= 0x41/* A */) && (c <= 0x46/* F */)) ||\n ((c >= 0x61/* a */) && (c <= 0x66/* f */))\n}\n\nfunction isOctCode (c) {\n return ((c >= 0x30/* 0 */) && (c <= 0x37/* 7 */))\n}\n\nfunction isDecCode (c) {\n return ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */))\n}\n\nfunction resolveYamlInteger (data) {\n if (data === null) return false\n\n const max = data.length\n let index = 0\n let hasDigits = false\n\n if (!max) return false\n\n let ch = data[index]\n\n // sign\n if (ch === '-' || ch === '+') {\n ch = data[++index]\n }\n\n if (ch === '0') {\n // 0\n if (index + 1 === max) return true\n ch = data[++index]\n\n // base 2, base 8, base 16\n\n if (ch === 'b') {\n // base 2\n index++\n\n for (; index < max; index++) {\n ch = data[index]\n if (ch !== '0' && ch !== '1') return false\n hasDigits = true\n }\n return hasDigits && isFinite(parseYamlInteger(data))\n }\n\n if (ch === 'x') {\n // base 16\n index++\n\n for (; index < max; index++) {\n if (!isHexCode(data.charCodeAt(index))) return false\n hasDigits = true\n }\n return hasDigits && isFinite(parseYamlInteger(data))\n }\n\n if (ch === 'o') {\n // base 8\n index++\n\n for (; index < max; index++) {\n if (!isOctCode(data.charCodeAt(index))) return false\n hasDigits = true\n }\n return hasDigits && isFinite(parseYamlInteger(data))\n }\n }\n\n // base 10 (except 0)\n\n for (; index < max; index++) {\n if (!isDecCode(data.charCodeAt(index))) {\n return false\n }\n hasDigits = true\n }\n\n if (!hasDigits) return false\n\n return isFinite(parseYamlInteger(data))\n}\n\nfunction parseYamlInteger (data) {\n let value = data\n let sign = 1\n\n let ch = value[0]\n\n if (ch === '-' || ch === '+') {\n if (ch === '-') sign = -1\n value = value.slice(1)\n ch = value[0]\n }\n\n if (value === '0') return 0\n\n if (ch === '0') {\n if (value[1] === 'b') return sign * parseInt(value.slice(2), 2)\n if (value[1] === 'x') return sign * parseInt(value.slice(2), 16)\n if (value[1] === 'o') return sign * parseInt(value.slice(2), 8)\n }\n\n return sign * parseInt(value, 10)\n}\n\nfunction constructYamlInteger (data) {\n return parseYamlInteger(data)\n}\n\nfunction isInteger (object) {\n return (Object.prototype.toString.call(object)) === '[object Number]' &&\n (object % 1 === 0 && !common.isNegativeZero(object))\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:int', {\n kind: 'scalar',\n resolve: resolveYamlInteger,\n construct: constructYamlInteger,\n predicate: isInteger,\n represent: {\n binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1) },\n octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1) },\n decimal: function (obj) { return obj.toString(10) },\n hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1) }\n },\n defaultStyle: 'decimal',\n styleAliases: {\n binary: [2, 'bin'],\n octal: [8, 'oct'],\n decimal: [10, 'dec'],\n hexadecimal: [16, 'hex']\n }\n})\n","'use strict'\n\nconst common = require('../common')\nconst Type = require('../type')\n\nconst YAML_FLOAT_PATTERN = new RegExp(\n // 2.5e4, 2.5 and integers\n '^(?:[-+]?(?:[0-9]+)(?:\\\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?' +\n // .2e4, .2\n // special case, seems not from spec\n '|\\\\.[0-9]+(?:[eE][-+]?[0-9]+)?' +\n // .inf\n '|[-+]?\\\\.(?:inf|Inf|INF)' +\n // .nan\n '|\\\\.(?:nan|NaN|NAN))$')\n\nconst YAML_FLOAT_SPECIAL_PATTERN = new RegExp(\n '^(?:' +\n // .inf\n '[-+]?\\\\.(?:inf|Inf|INF)' +\n // .nan\n '|\\\\.(?:nan|NaN|NAN))$')\n\nfunction resolveYamlFloat (data) {\n if (data === null) return false\n\n if (!YAML_FLOAT_PATTERN.test(data)) {\n return false\n }\n\n if (isFinite(parseFloat(data, 10))) {\n return true\n }\n\n return YAML_FLOAT_SPECIAL_PATTERN.test(data)\n}\n\nfunction constructYamlFloat (data) {\n let value = data.toLowerCase()\n const sign = value[0] === '-' ? -1 : 1\n\n if ('+-'.indexOf(value[0]) >= 0) {\n value = value.slice(1)\n }\n\n if (value === '.inf') {\n return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY\n } else if (value === '.nan') {\n return NaN\n }\n return sign * parseFloat(value, 10)\n}\n\nconst SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/\n\nfunction representYamlFloat (object, style) {\n if (isNaN(object)) {\n switch (style) {\n case 'lowercase': return '.nan'\n case 'uppercase': return '.NAN'\n case 'camelcase': return '.NaN'\n }\n } else if (Number.POSITIVE_INFINITY === object) {\n switch (style) {\n case 'lowercase': return '.inf'\n case 'uppercase': return '.INF'\n case 'camelcase': return '.Inf'\n }\n } else if (Number.NEGATIVE_INFINITY === object) {\n switch (style) {\n case 'lowercase': return '-.inf'\n case 'uppercase': return '-.INF'\n case 'camelcase': return '-.Inf'\n }\n } else if (common.isNegativeZero(object)) {\n return '-0.0'\n }\n\n const res = object.toString(10)\n\n // JS stringifier can build scientific format without dots: 5e-100,\n // while YAML requres dot: 5.e-100. Fix it with simple hack\n\n return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res\n}\n\nfunction isFloat (object) {\n return (Object.prototype.toString.call(object) === '[object Number]') &&\n (object % 1 !== 0 || common.isNegativeZero(object))\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:float', {\n kind: 'scalar',\n resolve: resolveYamlFloat,\n construct: constructYamlFloat,\n predicate: isFloat,\n represent: representYamlFloat,\n defaultStyle: 'lowercase'\n})\n","// Standard YAML's JSON schema.\n// http://www.yaml.org/spec/1.2/spec.html#id2803231\n//\n// NOTE: JS-YAML does not support schema-specific tag resolution restrictions.\n// So, this schema is not such strict as defined in the YAML specification.\n// It allows numbers in binary notaion, use `Null` and `NULL` as `null`, etc.\n\n'use strict'\n\nmodule.exports = require('./failsafe').extend({\n implicit: [\n require('../type/null'),\n require('../type/bool'),\n require('../type/int'),\n require('../type/float')\n ]\n})\n","// Standard YAML's Core schema.\n// http://www.yaml.org/spec/1.2/spec.html#id2804923\n//\n// NOTE: JS-YAML does not support schema-specific tag resolution restrictions.\n// So, Core schema has no distinctions from JSON schema is JS-YAML.\n\n'use strict'\n\nmodule.exports = require('./json')\n","'use strict'\n\nconst Type = require('../type')\n\nconst YAML_DATE_REGEXP = new RegExp(\n '^([0-9][0-9][0-9][0-9])' + // [1] year\n '-([0-9][0-9])' + // [2] month\n '-([0-9][0-9])$') // [3] day\n\nconst YAML_TIMESTAMP_REGEXP = new RegExp(\n '^([0-9][0-9][0-9][0-9])' + // [1] year\n '-([0-9][0-9]?)' + // [2] month\n '-([0-9][0-9]?)' + // [3] day\n '(?:[Tt]|[ \\\\t]+)' + // ...\n '([0-9][0-9]?)' + // [4] hour\n ':([0-9][0-9])' + // [5] minute\n ':([0-9][0-9])' + // [6] second\n '(?:\\\\.([0-9]*))?' + // [7] fraction\n '(?:[ \\\\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tzHour\n '(?::([0-9][0-9]))?))?$') // [11] tzMinute\n\nfunction resolveYamlTimestamp (data) {\n if (data === null) return false\n if (YAML_DATE_REGEXP.exec(data) !== null) return true\n if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true\n return false\n}\n\nfunction constructYamlTimestamp (data) {\n let fraction = 0\n let delta = null\n\n let match = YAML_DATE_REGEXP.exec(data)\n if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data)\n\n if (match === null) throw new Error('Date resolve error')\n\n // match: [1] year [2] month [3] day\n\n const year = +(match[1])\n const month = +(match[2]) - 1 // JS month starts with 0\n const day = +(match[3])\n\n if (!match[4]) { // no hour\n return new Date(Date.UTC(year, month, day))\n }\n\n // match: [4] hour [5] minute [6] second [7] fraction\n\n const hour = +(match[4])\n const minute = +(match[5])\n const second = +(match[6])\n\n if (match[7]) {\n fraction = match[7].slice(0, 3)\n while (fraction.length < 3) { // milli-seconds\n fraction += '0'\n }\n fraction = +fraction\n }\n\n // match: [8] tz [9] tz_sign [10] tzHour [11] tzMinute\n\n if (match[9]) {\n const tzHour = +(match[10])\n const tzMinute = +(match[11] || 0)\n delta = (tzHour * 60 + tzMinute) * 60000 // delta in mili-seconds\n if (match[9] === '-') delta = -delta\n }\n\n const date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction))\n\n if (delta) date.setTime(date.getTime() - delta)\n\n return date\n}\n\nfunction representYamlTimestamp (object /*, style */) {\n return object.toISOString()\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:timestamp', {\n kind: 'scalar',\n resolve: resolveYamlTimestamp,\n construct: constructYamlTimestamp,\n instanceOf: Date,\n represent: representYamlTimestamp\n})\n","'use strict'\n\nconst Type = require('../type')\n\nfunction resolveYamlMerge (data) {\n return data === '<<' || data === null\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:merge', {\n kind: 'scalar',\n resolve: resolveYamlMerge\n})\n","'use strict'\n\nconst Type = require('../type')\n\n// [ 64, 65, 66 ] -> [ padding, CR, LF ]\nconst BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\\n\\r'\n\nfunction resolveYamlBinary (data) {\n if (data === null) return false\n\n let bitlen = 0\n const max = data.length\n const map = BASE64_MAP\n\n // Convert one by one.\n for (let idx = 0; idx < max; idx++) {\n const code = map.indexOf(data.charAt(idx))\n\n // Skip CR/LF\n if (code > 64) continue\n\n // Fail on illegal characters\n if (code < 0) return false\n\n bitlen += 6\n }\n\n // If there are any bits left, source was corrupted\n return (bitlen % 8) === 0\n}\n\nfunction constructYamlBinary (data) {\n const input = data.replace(/[\\r\\n=]/g, '') // remove CR/LF & padding to simplify scan\n const max = input.length\n const map = BASE64_MAP\n let bits = 0\n const result = []\n\n // Collect by 6*4 bits (3 bytes)\n\n for (let idx = 0; idx < max; idx++) {\n if ((idx % 4 === 0) && idx) {\n result.push((bits >> 16) & 0xFF)\n result.push((bits >> 8) & 0xFF)\n result.push(bits & 0xFF)\n }\n\n bits = (bits << 6) | map.indexOf(input.charAt(idx))\n }\n\n // Dump tail\n\n const tailbits = (max % 4) * 6\n\n if (tailbits === 0) {\n result.push((bits >> 16) & 0xFF)\n result.push((bits >> 8) & 0xFF)\n result.push(bits & 0xFF)\n } else if (tailbits === 18) {\n result.push((bits >> 10) & 0xFF)\n result.push((bits >> 2) & 0xFF)\n } else if (tailbits === 12) {\n result.push((bits >> 4) & 0xFF)\n }\n\n return new Uint8Array(result)\n}\n\nfunction representYamlBinary (object /*, style */) {\n let result = ''\n let bits = 0\n const max = object.length\n const map = BASE64_MAP\n\n // Convert every three bytes to 4 ASCII characters.\n\n for (let idx = 0; idx < max; idx++) {\n if ((idx % 3 === 0) && idx) {\n result += map[(bits >> 18) & 0x3F]\n result += map[(bits >> 12) & 0x3F]\n result += map[(bits >> 6) & 0x3F]\n result += map[bits & 0x3F]\n }\n\n bits = (bits << 8) + object[idx]\n }\n\n // Dump tail\n\n const tail = max % 3\n\n if (tail === 0) {\n result += map[(bits >> 18) & 0x3F]\n result += map[(bits >> 12) & 0x3F]\n result += map[(bits >> 6) & 0x3F]\n result += map[bits & 0x3F]\n } else if (tail === 2) {\n result += map[(bits >> 10) & 0x3F]\n result += map[(bits >> 4) & 0x3F]\n result += map[(bits << 2) & 0x3F]\n result += map[64]\n } else if (tail === 1) {\n result += map[(bits >> 2) & 0x3F]\n result += map[(bits << 4) & 0x3F]\n result += map[64]\n result += map[64]\n }\n\n return result\n}\n\nfunction isBinary (obj) {\n return Object.prototype.toString.call(obj) === '[object Uint8Array]'\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:binary', {\n kind: 'scalar',\n resolve: resolveYamlBinary,\n construct: constructYamlBinary,\n predicate: isBinary,\n represent: representYamlBinary\n})\n","'use strict'\n\nconst Type = require('../type')\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\nconst _toString = Object.prototype.toString\n\nfunction resolveYamlOmap (data) {\n if (data === null) return true\n\n const objectKeys = {}\n const object = data\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n const pair = object[index]\n let pairHasKey = false\n\n if (_toString.call(pair) !== '[object Object]') return false\n\n let pairKey\n for (pairKey in pair) {\n if (_hasOwnProperty.call(pair, pairKey)) {\n if (!pairHasKey) pairHasKey = true\n else return false\n }\n }\n\n if (!pairHasKey) return false\n\n if (_hasOwnProperty.call(objectKeys, pairKey)) return false\n Object.defineProperty(objectKeys, pairKey, { value: true })\n }\n\n return true\n}\n\nfunction constructYamlOmap (data) {\n return data !== null ? data : []\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:omap', {\n kind: 'sequence',\n resolve: resolveYamlOmap,\n construct: constructYamlOmap\n})\n","'use strict'\n\nconst Type = require('../type')\n\nconst _toString = Object.prototype.toString\n\nfunction resolveYamlPairs (data) {\n if (data === null) return true\n\n const object = data\n\n const result = new Array(object.length)\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n const pair = object[index]\n\n if (_toString.call(pair) !== '[object Object]') return false\n\n const keys = Object.keys(pair)\n\n if (keys.length !== 1) return false\n\n result[index] = [keys[0], pair[keys[0]]]\n }\n\n return true\n}\n\nfunction constructYamlPairs (data) {\n if (data === null) return []\n\n const object = data\n const result = new Array(object.length)\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n const pair = object[index]\n\n const keys = Object.keys(pair)\n\n result[index] = [keys[0], pair[keys[0]]]\n }\n\n return result\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:pairs', {\n kind: 'sequence',\n resolve: resolveYamlPairs,\n construct: constructYamlPairs\n})\n","'use strict'\n\nconst Type = require('../type')\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\n\nfunction resolveYamlSet (data) {\n if (data === null) return true\n\n const object = data\n\n for (const key in object) {\n if (_hasOwnProperty.call(object, key)) {\n if (object[key] !== null) return false\n }\n }\n\n return true\n}\n\nfunction constructYamlSet (data) {\n return data !== null ? data : {}\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:set', {\n kind: 'mapping',\n resolve: resolveYamlSet,\n construct: constructYamlSet\n})\n","// JS-YAML's default schema for `safeLoad` function.\n// It is not described in the YAML specification.\n//\n// This schema is based on standard YAML's Core schema and includes most of\n// extra types described at YAML tag repository. (http://yaml.org/type/)\n\n'use strict'\n\nmodule.exports = require('./core').extend({\n implicit: [\n require('../type/timestamp'),\n require('../type/merge')\n ],\n explicit: [\n require('../type/binary'),\n require('../type/omap'),\n require('../type/pairs'),\n require('../type/set')\n ]\n})\n","'use strict'\n\nconst common = require('./common')\nconst YAMLException = require('./exception')\nconst makeSnippet = require('./snippet')\nconst DEFAULT_SCHEMA = require('./schema/default')\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\n\nconst CONTEXT_FLOW_IN = 1\nconst CONTEXT_FLOW_OUT = 2\nconst CONTEXT_BLOCK_IN = 3\nconst CONTEXT_BLOCK_OUT = 4\n\nconst CHOMPING_CLIP = 1\nconst CHOMPING_STRIP = 2\nconst CHOMPING_KEEP = 3\n\n// eslint-disable-next-line no-control-regex\nconst PATTERN_NON_PRINTABLE = /[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x84\\x86-\\x9F\\uFFFE\\uFFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/\nconst PATTERN_NON_ASCII_LINE_BREAKS = /[\\x85\\u2028\\u2029]/\n// eslint-disable-next-line no-useless-escape\nconst PATTERN_FLOW_INDICATORS = /[,\\[\\]{}]/\n// eslint-disable-next-line no-useless-escape\nconst PATTERN_TAG_HANDLE = /^(?:!|!!|![0-9A-Za-z-]+!)$/\n// eslint-disable-next-line no-useless-escape\nconst PATTERN_TAG_URI = /^(?:!|[^,\\[\\]{}])(?:%[0-9a-f]{2}|[0-9a-z\\-#;/?:@&=+$,_.!~*'()\\[\\]])*$/i\n\nfunction _class (obj) { return Object.prototype.toString.call(obj) }\n\nfunction isEol (c) {\n return (c === 0x0A/* LF */) || (c === 0x0D/* CR */)\n}\n\nfunction isWhiteSpace (c) {\n return (c === 0x09/* Tab */) || (c === 0x20/* Space */)\n}\n\nfunction isWsOrEol (c) {\n return (c === 0x09/* Tab */) ||\n (c === 0x20/* Space */) ||\n (c === 0x0A/* LF */) ||\n (c === 0x0D/* CR */)\n}\n\nfunction isFlowIndicator (c) {\n return c === 0x2C/* , */ ||\n c === 0x5B/* [ */ ||\n c === 0x5D/* ] */ ||\n c === 0x7B/* { */ ||\n c === 0x7D/* } */\n}\n\nfunction fromHexCode (c) {\n if ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) {\n return c - 0x30\n }\n\n const lc = c | 0x20\n\n if ((lc >= 0x61/* a */) && (lc <= 0x66/* f */)) {\n return lc - 0x61 + 10\n }\n\n return -1\n}\n\nfunction escapedHexLen (c) {\n if (c === 0x78/* x */) { return 2 }\n if (c === 0x75/* u */) { return 4 }\n if (c === 0x55/* U */) { return 8 }\n return 0\n}\n\nfunction fromDecimalCode (c) {\n if ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) {\n return c - 0x30\n }\n\n return -1\n}\n\nfunction simpleEscapeSequence (c) {\n switch (c) {\n case 0x30/* 0 */: return '\\x00'\n case 0x61/* a */: return '\\x07'\n case 0x62/* b */: return '\\x08'\n case 0x74/* t */: return '\\x09'\n case 0x09/* Tab */: return '\\x09'\n case 0x6E/* n */: return '\\x0A'\n case 0x76/* v */: return '\\x0B'\n case 0x66/* f */: return '\\x0C'\n case 0x72/* r */: return '\\x0D'\n case 0x65/* e */: return '\\x1B'\n case 0x20/* Space */: return ' '\n case 0x22/* \" */: return '\\x22'\n case 0x2F/* / */: return '/'\n case 0x5C/* \\ */: return '\\x5C'\n case 0x4E/* N */: return '\\x85'\n case 0x5F/* _ */: return '\\xA0'\n case 0x4C/* L */: return '\\u2028'\n case 0x50/* P */: return '\\u2029'\n default: return ''\n }\n}\n\nfunction charFromCodepoint (c) {\n if (c <= 0xFFFF) {\n return String.fromCharCode(c)\n }\n // Encode UTF-16 surrogate pair\n // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF\n return String.fromCharCode(\n ((c - 0x010000) >> 10) + 0xD800,\n ((c - 0x010000) & 0x03FF) + 0xDC00\n )\n}\n\n// set a property of a literal object, while protecting against prototype pollution,\n// see https://github.com/nodeca/js-yaml/issues/164 for more details\nfunction setProperty (object, key, value) {\n // used for this specific key only because Object.defineProperty is slow\n if (key === '__proto__') {\n Object.defineProperty(object, key, {\n configurable: true,\n enumerable: true,\n writable: true,\n value: value\n })\n } else {\n object[key] = value\n }\n}\n\nconst simpleEscapeCheck = new Array(256) // integer, for fast access\nconst simpleEscapeMap = new Array(256)\nfor (let i = 0; i < 256; i++) {\n simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0\n simpleEscapeMap[i] = simpleEscapeSequence(i)\n}\n\nfunction State (input, options) {\n this.input = input\n\n this.filename = options['filename'] || null\n this.schema = options['schema'] || DEFAULT_SCHEMA\n this.onWarning = options['onWarning'] || null\n // (Hidden) Remove? makes the loader to expect YAML 1.1 documents\n // if such documents have no explicit %YAML directive\n this.legacy = options['legacy'] || false\n\n this.json = options['json'] || false\n this.listener = options['listener'] || null\n this.maxDepth = typeof options['maxDepth'] === 'number' ? options['maxDepth'] : 100\n this.maxTotalMergeKeys = typeof options['maxTotalMergeKeys'] === 'number' ? options['maxTotalMergeKeys'] : 10000\n\n this.implicitTypes = this.schema.compiledImplicit\n this.typeMap = this.schema.compiledTypeMap\n\n this.length = input.length\n this.position = 0\n this.line = 0\n this.lineStart = 0\n this.lineIndent = 0\n this.depth = 0\n this.totalMergeKeys = 0\n\n // position of first leading tab in the current line,\n // used to make sure there are no tabs in the indentation\n this.firstTabInLine = -1\n\n this.documents = []\n this.anchorMapTransactions = []\n\n /*\n this.version;\n this.checkLineBreaks;\n this.tagMap;\n this.anchorMap;\n this.tag;\n this.anchor;\n this.kind;\n this.result; */\n}\n\nfunction generateError (state, message) {\n const mark = {\n name: state.filename,\n buffer: state.input.slice(0, -1), // omit trailing \\0\n position: state.position,\n line: state.line,\n column: state.position - state.lineStart\n }\n\n mark.snippet = makeSnippet(mark)\n\n return new YAMLException(message, mark)\n}\n\nfunction throwError (state, message) {\n throw generateError(state, message)\n}\n\nfunction throwWarning (state, message) {\n if (state.onWarning) {\n state.onWarning.call(null, generateError(state, message))\n }\n}\n\nfunction storeAnchor (state, name, value) {\n const transactions = state.anchorMapTransactions\n\n if (transactions.length !== 0) {\n const transaction = transactions[transactions.length - 1]\n\n if (!_hasOwnProperty.call(transaction, name)) {\n transaction[name] = {\n existed: _hasOwnProperty.call(state.anchorMap, name),\n value: state.anchorMap[name]\n }\n }\n }\n\n state.anchorMap[name] = value\n}\n\nfunction beginAnchorTransaction (state) {\n state.anchorMapTransactions.push(Object.create(null))\n}\n\nfunction commitAnchorTransaction (state) {\n const transaction = state.anchorMapTransactions.pop()\n const transactions = state.anchorMapTransactions\n\n if (transactions.length === 0) return\n\n const parent = transactions[transactions.length - 1]\n const names = Object.keys(transaction)\n\n for (let index = 0, length = names.length; index < length; index += 1) {\n const name = names[index]\n\n if (!_hasOwnProperty.call(parent, name)) {\n parent[name] = transaction[name]\n }\n }\n}\n\nfunction rollbackAnchorTransaction (state) {\n const transaction = state.anchorMapTransactions.pop()\n const names = Object.keys(transaction)\n\n for (let index = names.length - 1; index >= 0; index -= 1) {\n const entry = transaction[names[index]]\n\n if (entry.existed) {\n state.anchorMap[names[index]] = entry.value\n } else {\n delete state.anchorMap[names[index]]\n }\n }\n}\n\nfunction snapshotState (state) {\n return {\n position: state.position,\n line: state.line,\n lineStart: state.lineStart,\n lineIndent: state.lineIndent,\n firstTabInLine: state.firstTabInLine,\n tag: state.tag,\n anchor: state.anchor,\n kind: state.kind,\n result: state.result\n }\n}\n\nfunction restoreState (state, snapshot) {\n state.position = snapshot.position\n state.line = snapshot.line\n state.lineStart = snapshot.lineStart\n state.lineIndent = snapshot.lineIndent\n state.firstTabInLine = snapshot.firstTabInLine\n state.tag = snapshot.tag\n state.anchor = snapshot.anchor\n state.kind = snapshot.kind\n state.result = snapshot.result\n}\n\nconst directiveHandlers = {\n\n YAML: function handleYamlDirective (state, name, args) {\n if (state.version !== null) {\n throwError(state, 'duplication of %YAML directive')\n }\n\n if (args.length !== 1) {\n throwError(state, 'YAML directive accepts exactly one argument')\n }\n\n const match = /^([0-9]+)\\.([0-9]+)$/.exec(args[0])\n\n if (match === null) {\n throwError(state, 'ill-formed argument of the YAML directive')\n }\n\n const major = parseInt(match[1], 10)\n const minor = parseInt(match[2], 10)\n\n if (major !== 1) {\n throwError(state, 'unacceptable YAML version of the document')\n }\n\n state.version = args[0]\n state.checkLineBreaks = (minor < 2)\n\n if (minor !== 1 && minor !== 2) {\n throwWarning(state, 'unsupported YAML version of the document')\n }\n },\n\n TAG: function handleTagDirective (state, name, args) {\n let prefix\n\n if (args.length !== 2) {\n throwError(state, 'TAG directive accepts exactly two arguments')\n }\n\n const handle = args[0]\n prefix = args[1]\n\n if (!PATTERN_TAG_HANDLE.test(handle)) {\n throwError(state, 'ill-formed tag handle (first argument) of the TAG directive')\n }\n\n if (_hasOwnProperty.call(state.tagMap, handle)) {\n throwError(state, 'there is a previously declared suffix for \"' + handle + '\" tag handle')\n }\n\n if (!PATTERN_TAG_URI.test(prefix)) {\n throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive')\n }\n\n try {\n prefix = decodeURIComponent(prefix)\n } catch (err) {\n throwError(state, 'tag prefix is malformed: ' + prefix)\n }\n\n state.tagMap[handle] = prefix\n }\n}\n\nfunction captureSegment (state, start, end, checkJson) {\n if (start < end) {\n const _result = state.input.slice(start, end)\n\n if (checkJson) {\n for (let _position = 0, _length = _result.length; _position < _length; _position += 1) {\n const _character = _result.charCodeAt(_position)\n if (!(_character === 0x09 ||\n (_character >= 0x20 && _character <= 0x10FFFF))) {\n throwError(state, 'expected valid JSON character')\n }\n }\n } else if (PATTERN_NON_PRINTABLE.test(_result)) {\n throwError(state, 'the stream contains non-printable characters')\n }\n\n state.result += _result\n }\n}\n\nfunction mergeMappings (state, destination, source, overridableKeys) {\n if (!common.isObject(source)) {\n throwError(state, 'cannot merge mappings; the provided source object is unacceptable')\n }\n\n const sourceKeys = Object.keys(source)\n\n for (let index = 0, quantity = sourceKeys.length; index < quantity; index += 1) {\n const key = sourceKeys[index]\n\n if (state.maxTotalMergeKeys !== -1 && ++state.totalMergeKeys > state.maxTotalMergeKeys) {\n throwError(state, 'merge keys exceeded maxTotalMergeKeys (' + state.maxTotalMergeKeys + ')')\n }\n\n if (!_hasOwnProperty.call(destination, key)) {\n setProperty(destination, key, source[key])\n overridableKeys[key] = true\n }\n }\n}\n\nfunction storeMappingPair (state, _result, overridableKeys, keyTag, keyNode, valueNode,\n startLine, startLineStart, startPos) {\n // The output is a plain object here, so keys can only be strings.\n // We need to convert keyNode to a string, but doing so can hang the process\n // (deeply nested arrays that explode exponentially using aliases).\n if (Array.isArray(keyNode)) {\n keyNode = Array.prototype.slice.call(keyNode)\n\n for (let index = 0, quantity = keyNode.length; index < quantity; index += 1) {\n if (Array.isArray(keyNode[index])) {\n throwError(state, 'nested arrays are not supported inside keys')\n }\n\n if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') {\n keyNode[index] = '[object Object]'\n }\n }\n }\n\n // Avoid code execution in load() via toString property\n // (still use its own toString for arrays, timestamps,\n // and whatever user schema extensions happen to have @@toStringTag)\n if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') {\n keyNode = '[object Object]'\n }\n\n keyNode = String(keyNode)\n\n if (_result === null) {\n _result = {}\n }\n\n if (keyTag === 'tag:yaml.org,2002:merge') {\n if (Array.isArray(valueNode)) {\n for (let index = 0, quantity = valueNode.length; index < quantity; index += 1) {\n mergeMappings(state, _result, valueNode[index], overridableKeys)\n }\n } else {\n mergeMappings(state, _result, valueNode, overridableKeys)\n }\n } else {\n if (!state.json &&\n !_hasOwnProperty.call(overridableKeys, keyNode) &&\n _hasOwnProperty.call(_result, keyNode)) {\n state.line = startLine || state.line\n state.lineStart = startLineStart || state.lineStart\n state.position = startPos || state.position\n throwError(state, 'duplicated mapping key')\n }\n\n setProperty(_result, keyNode, valueNode)\n delete overridableKeys[keyNode]\n }\n\n return _result\n}\n\nfunction readLineBreak (state) {\n const ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x0A/* LF */) {\n state.position++\n } else if (ch === 0x0D/* CR */) {\n state.position++\n if (state.input.charCodeAt(state.position) === 0x0A/* LF */) {\n state.position++\n }\n } else {\n throwError(state, 'a line break is expected')\n }\n\n state.line += 1\n state.lineStart = state.position\n state.firstTabInLine = -1\n}\n\nfunction skipSeparationSpace (state, allowComments, checkIndent) {\n let lineBreaks = 0\n let ch = state.input.charCodeAt(state.position)\n\n while (ch !== 0) {\n while (isWhiteSpace(ch)) {\n if (ch === 0x09/* Tab */ && state.firstTabInLine === -1) {\n state.firstTabInLine = state.position\n }\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (allowComments && ch === 0x23/* # */) {\n do {\n ch = state.input.charCodeAt(++state.position)\n } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0)\n }\n\n if (isEol(ch)) {\n readLineBreak(state)\n\n ch = state.input.charCodeAt(state.position)\n lineBreaks++\n state.lineIndent = 0\n\n while (ch === 0x20/* Space */) {\n state.lineIndent++\n ch = state.input.charCodeAt(++state.position)\n }\n } else {\n break\n }\n }\n\n if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) {\n throwWarning(state, 'deficient indentation')\n }\n\n return lineBreaks\n}\n\nfunction testDocumentSeparator (state) {\n let _position = state.position\n let ch = state.input.charCodeAt(_position)\n\n // Condition state.position === state.lineStart is tested\n // in parent on each call, for efficiency. No needs to test here again.\n if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) &&\n ch === state.input.charCodeAt(_position + 1) &&\n ch === state.input.charCodeAt(_position + 2)) {\n _position += 3\n\n ch = state.input.charCodeAt(_position)\n\n if (ch === 0 || isWsOrEol(ch)) {\n return true\n }\n }\n\n return false\n}\n\nfunction writeFoldedLines (state, count) {\n if (count === 1) {\n state.result += ' '\n } else if (count > 1) {\n state.result += common.repeat('\\n', count - 1)\n }\n}\n\nfunction readPlainScalar (state, nodeIndent, withinFlowCollection) {\n let captureStart\n let captureEnd\n let hasPendingContent\n let _line\n let _lineStart\n let _lineIndent\n const _kind = state.kind\n const _result = state.result\n\n let ch = state.input.charCodeAt(state.position)\n\n if (isWsOrEol(ch) ||\n isFlowIndicator(ch) ||\n ch === 0x23/* # */ ||\n ch === 0x26/* & */ ||\n ch === 0x2A/* * */ ||\n ch === 0x21/* ! */ ||\n ch === 0x7C/* | */ ||\n ch === 0x3E/* > */ ||\n ch === 0x27/* ' */ ||\n ch === 0x22/* \" */ ||\n ch === 0x25/* % */ ||\n ch === 0x40/* @ */ ||\n ch === 0x60/* ` */) {\n return false\n }\n\n if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) {\n const following = state.input.charCodeAt(state.position + 1)\n\n if (isWsOrEol(following) ||\n (withinFlowCollection && isFlowIndicator(following))) {\n return false\n }\n }\n\n state.kind = 'scalar'\n state.result = ''\n captureStart = captureEnd = state.position\n hasPendingContent = false\n\n while (ch !== 0) {\n if (ch === 0x3A/* : */) {\n const following = state.input.charCodeAt(state.position + 1)\n\n if (isWsOrEol(following) ||\n (withinFlowCollection && isFlowIndicator(following))) {\n break\n }\n } else if (ch === 0x23/* # */) {\n const preceding = state.input.charCodeAt(state.position - 1)\n\n if (isWsOrEol(preceding)) {\n break\n }\n } else if ((state.position === state.lineStart && testDocumentSeparator(state)) ||\n (withinFlowCollection && isFlowIndicator(ch))) {\n break\n } else if (isEol(ch)) {\n _line = state.line\n _lineStart = state.lineStart\n _lineIndent = state.lineIndent\n skipSeparationSpace(state, false, -1)\n\n if (state.lineIndent >= nodeIndent) {\n hasPendingContent = true\n ch = state.input.charCodeAt(state.position)\n continue\n } else {\n state.position = captureEnd\n state.line = _line\n state.lineStart = _lineStart\n state.lineIndent = _lineIndent\n break\n }\n }\n\n if (hasPendingContent) {\n captureSegment(state, captureStart, captureEnd, false)\n writeFoldedLines(state, state.line - _line)\n captureStart = captureEnd = state.position\n hasPendingContent = false\n }\n\n if (!isWhiteSpace(ch)) {\n captureEnd = state.position + 1\n }\n\n ch = state.input.charCodeAt(++state.position)\n }\n\n captureSegment(state, captureStart, captureEnd, false)\n\n if (state.result) {\n return true\n }\n\n state.kind = _kind\n state.result = _result\n return false\n}\n\nfunction readSingleQuotedScalar (state, nodeIndent) {\n let captureStart\n let captureEnd\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x27/* ' */) {\n return false\n }\n\n state.kind = 'scalar'\n state.result = ''\n state.position++\n captureStart = captureEnd = state.position\n\n while ((ch = state.input.charCodeAt(state.position)) !== 0) {\n if (ch === 0x27/* ' */) {\n captureSegment(state, captureStart, state.position, true)\n ch = state.input.charCodeAt(++state.position)\n\n if (ch === 0x27/* ' */) {\n captureStart = state.position\n state.position++\n captureEnd = state.position\n } else {\n return true\n }\n } else if (isEol(ch)) {\n captureSegment(state, captureStart, captureEnd, true)\n writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent))\n captureStart = captureEnd = state.position\n } else if (state.position === state.lineStart && testDocumentSeparator(state)) {\n throwError(state, 'unexpected end of the document within a single quoted scalar')\n } else {\n state.position++\n if (!isWhiteSpace(ch)) {\n captureEnd = state.position\n }\n }\n }\n\n throwError(state, 'unexpected end of the stream within a single quoted scalar')\n}\n\nfunction readDoubleQuotedScalar (state, nodeIndent) {\n let captureStart\n let captureEnd\n let tmp\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x22/* \" */) {\n return false\n }\n\n state.kind = 'scalar'\n state.result = ''\n state.position++\n captureStart = captureEnd = state.position\n\n while ((ch = state.input.charCodeAt(state.position)) !== 0) {\n if (ch === 0x22/* \" */) {\n captureSegment(state, captureStart, state.position, true)\n state.position++\n return true\n } else if (ch === 0x5C/* \\ */) {\n captureSegment(state, captureStart, state.position, true)\n ch = state.input.charCodeAt(++state.position)\n\n if (isEol(ch)) {\n skipSeparationSpace(state, false, nodeIndent)\n\n // TODO: rework to inline fn with no type cast?\n } else if (ch < 256 && simpleEscapeCheck[ch]) {\n state.result += simpleEscapeMap[ch]\n state.position++\n } else if ((tmp = escapedHexLen(ch)) > 0) {\n let hexLength = tmp\n let hexResult = 0\n\n for (; hexLength > 0; hexLength--) {\n ch = state.input.charCodeAt(++state.position)\n\n if ((tmp = fromHexCode(ch)) >= 0) {\n hexResult = (hexResult << 4) + tmp\n } else {\n throwError(state, 'expected hexadecimal character')\n }\n }\n\n state.result += charFromCodepoint(hexResult)\n\n state.position++\n } else {\n throwError(state, 'unknown escape sequence')\n }\n\n captureStart = captureEnd = state.position\n } else if (isEol(ch)) {\n captureSegment(state, captureStart, captureEnd, true)\n writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent))\n captureStart = captureEnd = state.position\n } else if (state.position === state.lineStart && testDocumentSeparator(state)) {\n throwError(state, 'unexpected end of the document within a double quoted scalar')\n } else {\n state.position++\n if (!isWhiteSpace(ch)) {\n captureEnd = state.position\n }\n }\n }\n\n throwError(state, 'unexpected end of the stream within a double quoted scalar')\n}\n\nfunction readFlowCollection (state, nodeIndent) {\n let readNext = true\n let _line\n let _lineStart\n let _pos\n const _tag = state.tag\n let _result\n const _anchor = state.anchor\n let terminator\n let isPair\n let isExplicitPair\n let isMapping\n const overridableKeys = Object.create(null)\n let keyNode\n let keyTag\n let valueNode\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x5B/* [ */) {\n terminator = 0x5D/* ] */\n isMapping = false\n _result = []\n } else if (ch === 0x7B/* { */) {\n terminator = 0x7D/* } */\n isMapping = true\n _result = {}\n } else {\n return false\n }\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, _result)\n }\n\n ch = state.input.charCodeAt(++state.position)\n\n while (ch !== 0) {\n skipSeparationSpace(state, true, nodeIndent)\n\n ch = state.input.charCodeAt(state.position)\n\n if (ch === terminator) {\n state.position++\n state.tag = _tag\n state.anchor = _anchor\n state.kind = isMapping ? 'mapping' : 'sequence'\n state.result = _result\n return true\n } else if (!readNext) {\n throwError(state, 'missed comma between flow collection entries')\n } else if (ch === 0x2C/* , */) {\n // \"flow collection entries can never be completely empty\", as per YAML 1.2, section 7.4\n throwError(state, \"expected the node content, but found ','\")\n }\n\n keyTag = keyNode = valueNode = null\n isPair = isExplicitPair = false\n\n if (ch === 0x3F/* ? */) {\n const following = state.input.charCodeAt(state.position + 1)\n\n if (isWsOrEol(following)) {\n isPair = isExplicitPair = true\n state.position++\n skipSeparationSpace(state, true, nodeIndent)\n }\n }\n\n _line = state.line // Save the current line.\n _lineStart = state.lineStart\n _pos = state.position\n composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true)\n keyTag = state.tag\n keyNode = state.result\n skipSeparationSpace(state, true, nodeIndent)\n\n ch = state.input.charCodeAt(state.position)\n\n if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) {\n isPair = true\n ch = state.input.charCodeAt(++state.position)\n skipSeparationSpace(state, true, nodeIndent)\n composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true)\n valueNode = state.result\n }\n\n if (isMapping) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)\n } else if (isPair) {\n _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos))\n } else {\n _result.push(keyNode)\n }\n\n skipSeparationSpace(state, true, nodeIndent)\n\n ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x2C/* , */) {\n readNext = true\n ch = state.input.charCodeAt(++state.position)\n } else {\n readNext = false\n }\n }\n\n throwError(state, 'unexpected end of the stream within a flow collection')\n}\n\nfunction readBlockScalar (state, nodeIndent) {\n let folding\n let chomping = CHOMPING_CLIP\n let didReadContent = false\n let detectedIndent = false\n let textIndent = nodeIndent\n let emptyLines = 0\n let atMoreIndented = false\n let tmp\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x7C/* | */) {\n folding = false\n } else if (ch === 0x3E/* > */) {\n folding = true\n } else {\n return false\n }\n\n state.kind = 'scalar'\n state.result = ''\n\n while (ch !== 0) {\n ch = state.input.charCodeAt(++state.position)\n\n if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {\n if (CHOMPING_CLIP === chomping) {\n chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP\n } else {\n throwError(state, 'repeat of a chomping mode identifier')\n }\n } else if ((tmp = fromDecimalCode(ch)) >= 0) {\n if (tmp === 0) {\n throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one')\n } else if (!detectedIndent) {\n textIndent = nodeIndent + tmp - 1\n detectedIndent = true\n } else {\n throwError(state, 'repeat of an indentation width identifier')\n }\n } else {\n break\n }\n }\n\n if (isWhiteSpace(ch)) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (isWhiteSpace(ch))\n\n if (ch === 0x23/* # */) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (!isEol(ch) && (ch !== 0))\n }\n }\n\n while (ch !== 0) {\n readLineBreak(state)\n state.lineIndent = 0\n\n ch = state.input.charCodeAt(state.position)\n\n // eslint-disable-next-line no-unmodified-loop-condition\n while ((!detectedIndent || state.lineIndent < textIndent) &&\n (ch === 0x20/* Space */)) {\n state.lineIndent++\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (!detectedIndent && state.lineIndent > textIndent) {\n textIndent = state.lineIndent\n }\n\n if (isEol(ch)) {\n emptyLines++\n continue\n }\n\n if (!detectedIndent && textIndent === 0) {\n throwError(state, 'missing indentation for block scalar')\n }\n\n // End of the scalar.\n if (state.lineIndent < textIndent) {\n // Perform the chomping.\n if (chomping === CHOMPING_KEEP) {\n state.result += common.repeat('\\n', didReadContent ? 1 + emptyLines : emptyLines)\n } else if (chomping === CHOMPING_CLIP) {\n if (didReadContent) { // i.e. only if the scalar is not empty.\n state.result += '\\n'\n }\n }\n\n // Break this `while` cycle and go to the funciton's epilogue.\n break\n }\n\n // Folded style: use fancy rules to handle line breaks.\n if (folding) {\n // Lines starting with white space characters (more-indented lines) are not folded.\n if (isWhiteSpace(ch)) {\n atMoreIndented = true\n // except for the first content line (cf. Example 8.1)\n state.result += common.repeat('\\n', didReadContent ? 1 + emptyLines : emptyLines)\n\n // End of more-indented block.\n } else if (atMoreIndented) {\n atMoreIndented = false\n state.result += common.repeat('\\n', emptyLines + 1)\n\n // Just one line break - perceive as the same line.\n } else if (emptyLines === 0) {\n if (didReadContent) { // i.e. only if we have already read some scalar content.\n state.result += ' '\n }\n\n // Several line breaks - perceive as different lines.\n } else {\n state.result += common.repeat('\\n', emptyLines)\n }\n\n // Literal style: just add exact number of line breaks between content lines.\n } else {\n // Keep all line breaks except the header line break.\n state.result += common.repeat('\\n', didReadContent ? 1 + emptyLines : emptyLines)\n }\n\n didReadContent = true\n detectedIndent = true\n emptyLines = 0\n const captureStart = state.position\n\n while (!isEol(ch) && (ch !== 0)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n captureSegment(state, captureStart, state.position, false)\n }\n\n return true\n}\n\nfunction readBlockSequence (state, nodeIndent) {\n const _tag = state.tag\n const _anchor = state.anchor\n const _result = []\n let detected = false\n\n // there is a leading tab before this token, so it can't be a block sequence/mapping;\n // it can still be flow sequence/mapping or a scalar\n if (state.firstTabInLine !== -1) return false\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, _result)\n }\n\n let ch = state.input.charCodeAt(state.position)\n\n while (ch !== 0) {\n if (state.firstTabInLine !== -1) {\n state.position = state.firstTabInLine\n throwError(state, 'tab characters must not be used in indentation')\n }\n\n if (ch !== 0x2D/* - */) {\n break\n }\n\n const following = state.input.charCodeAt(state.position + 1)\n\n if (!isWsOrEol(following)) {\n break\n }\n\n detected = true\n state.position++\n\n if (skipSeparationSpace(state, true, -1)) {\n if (state.lineIndent <= nodeIndent) {\n _result.push(null)\n ch = state.input.charCodeAt(state.position)\n continue\n }\n }\n\n const _line = state.line\n composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true)\n _result.push(state.result)\n skipSeparationSpace(state, true, -1)\n\n ch = state.input.charCodeAt(state.position)\n\n if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) {\n throwError(state, 'bad indentation of a sequence entry')\n } else if (state.lineIndent < nodeIndent) {\n break\n }\n }\n\n if (detected) {\n state.tag = _tag\n state.anchor = _anchor\n state.kind = 'sequence'\n state.result = _result\n return true\n }\n return false\n}\n\nfunction readBlockMapping (state, nodeIndent, flowIndent) {\n let allowCompact\n let _keyLine\n let _keyLineStart\n let _keyPos\n const _tag = state.tag\n const _anchor = state.anchor\n const _result = {}\n const overridableKeys = Object.create(null)\n let keyTag = null\n let keyNode = null\n let valueNode = null\n let atExplicitKey = false\n let detected = false\n\n // there is a leading tab before this token, so it can't be a block sequence/mapping;\n // it can still be flow sequence/mapping or a scalar\n if (state.firstTabInLine !== -1) return false\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, _result)\n }\n\n let ch = state.input.charCodeAt(state.position)\n\n while (ch !== 0) {\n if (!atExplicitKey && state.firstTabInLine !== -1) {\n state.position = state.firstTabInLine\n throwError(state, 'tab characters must not be used in indentation')\n }\n\n const following = state.input.charCodeAt(state.position + 1)\n const _line = state.line // Save the current line.\n\n //\n // Explicit notation case. There are two separate blocks:\n // first for the key (denoted by \"?\") and second for the value (denoted by \":\")\n //\n if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && isWsOrEol(following)) {\n if (ch === 0x3F/* ? */) {\n if (atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos)\n keyTag = keyNode = valueNode = null\n }\n\n detected = true\n atExplicitKey = true\n allowCompact = true\n } else if (atExplicitKey) {\n // i.e. 0x3A/* : */ === character after the explicit key.\n atExplicitKey = false\n allowCompact = true\n } else {\n throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line')\n }\n\n state.position += 1\n ch = following\n\n //\n // Implicit notation case. Flow-style node as the key first, then \":\", and the value.\n //\n } else {\n _keyLine = state.line\n _keyLineStart = state.lineStart\n _keyPos = state.position\n\n if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) {\n // Neither implicit nor explicit notation.\n // Reading is done. Go to the epilogue.\n break\n }\n\n if (state.line === _line) {\n ch = state.input.charCodeAt(state.position)\n\n while (isWhiteSpace(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (ch === 0x3A/* : */) {\n ch = state.input.charCodeAt(++state.position)\n\n if (!isWsOrEol(ch)) {\n throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping')\n }\n\n if (atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos)\n keyTag = keyNode = valueNode = null\n }\n\n detected = true\n atExplicitKey = false\n allowCompact = false\n keyTag = state.tag\n keyNode = state.result\n } else if (detected) {\n throwError(state, 'can not read an implicit mapping pair; a colon is missed')\n } else {\n state.tag = _tag\n state.anchor = _anchor\n return true // Keep the result of `composeNode`.\n }\n } else if (detected) {\n throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key')\n } else {\n state.tag = _tag\n state.anchor = _anchor\n return true // Keep the result of `composeNode`.\n }\n }\n\n //\n // Common reading code for both explicit and implicit notations.\n //\n if (state.line === _line || state.lineIndent > nodeIndent) {\n if (atExplicitKey) {\n _keyLine = state.line\n _keyLineStart = state.lineStart\n _keyPos = state.position\n }\n\n if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) {\n if (atExplicitKey) {\n keyNode = state.result\n } else {\n valueNode = state.result\n }\n }\n\n if (!atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos)\n keyTag = keyNode = valueNode = null\n }\n\n skipSeparationSpace(state, true, -1)\n ch = state.input.charCodeAt(state.position)\n }\n\n if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) {\n throwError(state, 'bad indentation of a mapping entry')\n } else if (state.lineIndent < nodeIndent) {\n break\n }\n }\n\n //\n // Epilogue.\n //\n\n // Special case: last mapping's node contains only the key in explicit notation.\n if (atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos)\n }\n\n // Expose the resulting mapping.\n if (detected) {\n state.tag = _tag\n state.anchor = _anchor\n state.kind = 'mapping'\n state.result = _result\n }\n\n return detected\n}\n\nfunction readTagProperty (state) {\n let isVerbatim = false\n let isNamed = false\n let tagHandle\n let tagName\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x21/* ! */) return false\n\n if (state.tag !== null) {\n throwError(state, 'duplication of a tag property')\n }\n\n ch = state.input.charCodeAt(++state.position)\n\n if (ch === 0x3C/* < */) {\n isVerbatim = true\n ch = state.input.charCodeAt(++state.position)\n } else if (ch === 0x21/* ! */) {\n isNamed = true\n tagHandle = '!!'\n ch = state.input.charCodeAt(++state.position)\n } else {\n tagHandle = '!'\n }\n\n let _position = state.position\n\n if (isVerbatim) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (ch !== 0 && ch !== 0x3E/* > */)\n\n if (state.position < state.length) {\n tagName = state.input.slice(_position, state.position)\n ch = state.input.charCodeAt(++state.position)\n } else {\n throwError(state, 'unexpected end of the stream within a verbatim tag')\n }\n } else {\n while (ch !== 0 && !isWsOrEol(ch)) {\n if (ch === 0x21/* ! */) {\n if (!isNamed) {\n tagHandle = state.input.slice(_position - 1, state.position + 1)\n\n if (!PATTERN_TAG_HANDLE.test(tagHandle)) {\n throwError(state, 'named tag handle cannot contain such characters')\n }\n\n isNamed = true\n _position = state.position + 1\n } else {\n throwError(state, 'tag suffix cannot contain exclamation marks')\n }\n }\n\n ch = state.input.charCodeAt(++state.position)\n }\n\n tagName = state.input.slice(_position, state.position)\n\n if (PATTERN_FLOW_INDICATORS.test(tagName)) {\n throwError(state, 'tag suffix cannot contain flow indicator characters')\n }\n }\n\n if (tagName && !PATTERN_TAG_URI.test(tagName)) {\n throwError(state, 'tag name cannot contain such characters: ' + tagName)\n }\n\n try {\n tagName = decodeURIComponent(tagName)\n } catch (err) {\n throwError(state, 'tag name is malformed: ' + tagName)\n }\n\n if (isVerbatim) {\n state.tag = tagName\n } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) {\n state.tag = state.tagMap[tagHandle] + tagName\n } else if (tagHandle === '!') {\n state.tag = '!' + tagName\n } else if (tagHandle === '!!') {\n state.tag = 'tag:yaml.org,2002:' + tagName\n } else {\n throwError(state, 'undeclared tag handle \"' + tagHandle + '\"')\n }\n\n return true\n}\n\nfunction readAnchorProperty (state) {\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x26/* & */) return false\n\n if (state.anchor !== null) {\n throwError(state, 'duplication of an anchor property')\n }\n\n ch = state.input.charCodeAt(++state.position)\n const _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (state.position === _position) {\n throwError(state, 'name of an anchor node must contain at least one character')\n }\n\n state.anchor = state.input.slice(_position, state.position)\n return true\n}\n\nfunction readAlias (state) {\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x2A/* * */) return false\n\n ch = state.input.charCodeAt(++state.position)\n const _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (state.position === _position) {\n throwError(state, 'name of an alias node must contain at least one character')\n }\n\n const alias = state.input.slice(_position, state.position)\n\n if (!_hasOwnProperty.call(state.anchorMap, alias)) {\n throwError(state, 'unidentified alias \"' + alias + '\"')\n }\n\n state.result = state.anchorMap[alias]\n skipSeparationSpace(state, true, -1)\n return true\n}\n\nfunction tryReadBlockMappingFromProperty (state, propertyStart, nodeIndent, flowIndent) {\n const fallbackState = snapshotState(state)\n\n beginAnchorTransaction(state)\n restoreState(state, propertyStart)\n\n // Re-read the leading properties as part of the first implicit key, not as\n // properties of the current node.\n state.tag = null\n state.anchor = null\n state.kind = null\n state.result = null\n\n if (readBlockMapping(state, nodeIndent, flowIndent) && state.kind === 'mapping') {\n commitAnchorTransaction(state)\n return true\n }\n\n rollbackAnchorTransaction(state)\n restoreState(state, fallbackState)\n return false\n}\n\nfunction composeNode (state, parentIndent, nodeContext, allowToSeek, allowCompact) {\n let allowBlockScalars\n let allowBlockCollections\n let indentStatus = 1 // 1: this>parent, 0: this=parent, -1: this= state.maxDepth) {\n throwError(state, 'nesting exceeded maxDepth (' + state.maxDepth + ')')\n }\n\n state.depth += 1\n\n if (state.listener !== null) {\n state.listener('open', state)\n }\n\n state.tag = null\n state.anchor = null\n state.kind = null\n state.result = null\n\n const allowBlockStyles = allowBlockScalars = allowBlockCollections =\n CONTEXT_BLOCK_OUT === nodeContext ||\n CONTEXT_BLOCK_IN === nodeContext\n\n if (allowToSeek) {\n if (skipSeparationSpace(state, true, -1)) {\n atNewLine = true\n\n if (state.lineIndent > parentIndent) {\n indentStatus = 1\n } else if (state.lineIndent === parentIndent) {\n indentStatus = 0\n } else if (state.lineIndent < parentIndent) {\n indentStatus = -1\n }\n }\n }\n\n if (indentStatus === 1) {\n while (true) {\n const ch = state.input.charCodeAt(state.position)\n const propertyState = snapshotState(state)\n\n // A duplicate property token after a line break can be the first key of\n // a nested block mapping, e.g. `!!map\\n !!str key: value`.\n if (atNewLine &&\n ((ch === 0x21/* ! */ && state.tag !== null) ||\n (ch === 0x26/* & */ && state.anchor !== null))) {\n break\n }\n\n if (!readTagProperty(state) && !readAnchorProperty(state)) {\n break\n }\n\n if (propertyStart === null) {\n propertyStart = propertyState\n }\n\n if (skipSeparationSpace(state, true, -1)) {\n atNewLine = true\n allowBlockCollections = allowBlockStyles\n\n if (state.lineIndent > parentIndent) {\n indentStatus = 1\n } else if (state.lineIndent === parentIndent) {\n indentStatus = 0\n } else if (state.lineIndent < parentIndent) {\n indentStatus = -1\n }\n } else {\n allowBlockCollections = false\n }\n }\n }\n\n if (allowBlockCollections) {\n allowBlockCollections = atNewLine || allowCompact\n }\n\n if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) {\n if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) {\n flowIndent = parentIndent\n } else {\n flowIndent = parentIndent + 1\n }\n\n blockIndent = state.position - state.lineStart\n\n if (indentStatus === 1) {\n if ((allowBlockCollections &&\n (readBlockSequence(state, blockIndent) || readBlockMapping(state, blockIndent, flowIndent))) ||\n readFlowCollection(state, flowIndent)) {\n hasContent = true\n } else {\n const ch = state.input.charCodeAt(state.position)\n\n if (propertyStart !== null && allowBlockStyles && !allowBlockCollections &&\n ch !== 0x7C/* | */ && ch !== 0x3E/* > */ &&\n tryReadBlockMappingFromProperty(\n state,\n propertyStart,\n propertyStart.position - propertyStart.lineStart,\n flowIndent\n )) {\n hasContent = true\n } else if ((allowBlockScalars && readBlockScalar(state, flowIndent)) ||\n readSingleQuotedScalar(state, flowIndent) ||\n readDoubleQuotedScalar(state, flowIndent)) {\n hasContent = true\n } else if (readAlias(state)) {\n hasContent = true\n\n if (state.tag !== null || state.anchor !== null) {\n throwError(state, 'alias node should not have any properties')\n }\n } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) {\n hasContent = true\n\n if (state.tag === null) {\n state.tag = '?'\n }\n }\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n }\n } else if (indentStatus === 0) {\n // Special case: block sequences are allowed to have same indentation level as the parent.\n // http://www.yaml.org/spec/1.2/spec.html#id2799784\n hasContent = allowBlockCollections && readBlockSequence(state, blockIndent)\n }\n }\n\n if (state.tag === null) {\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n } else if (state.tag === '?') {\n // Implicit resolving is not allowed for non-scalar types, and '?'\n // non-specific tag is only automatically assigned to plain scalars.\n //\n // We only need to check kind conformity in case user explicitly assigns '?'\n // tag, for example like this: \"! [0]\"\n //\n if (state.result !== null && state.kind !== 'scalar') {\n throwError(state, 'unacceptable node kind for ! tag; it should be \"scalar\", not \"' + state.kind + '\"')\n }\n\n for (let typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) {\n type = state.implicitTypes[typeIndex]\n\n if (type.resolve(state.result)) { // `state.result` updated in resolver if matched\n state.result = type.construct(state.result)\n state.tag = type.tag\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n break\n }\n }\n } else if (state.tag !== '!') {\n if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) {\n type = state.typeMap[state.kind || 'fallback'][state.tag]\n } else {\n // looking for multi type\n type = null\n const typeList = state.typeMap.multi[state.kind || 'fallback']\n\n for (let typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) {\n if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) {\n type = typeList[typeIndex]\n break\n }\n }\n }\n\n if (!type) {\n throwError(state, 'unknown tag !<' + state.tag + '>')\n }\n\n if (state.result !== null && type.kind !== state.kind) {\n throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be \"' + type.kind + '\", not \"' + state.kind + '\"')\n }\n\n if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched\n throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag')\n } else {\n state.result = type.construct(state.result, state.tag)\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n }\n }\n\n if (state.listener !== null) {\n state.listener('close', state)\n }\n\n state.depth -= 1\n return state.tag !== null || state.anchor !== null || hasContent\n}\n\nfunction readDocument (state) {\n const documentStart = state.position\n let hasDirectives = false\n let ch\n\n state.version = null\n state.checkLineBreaks = state.legacy\n state.tagMap = Object.create(null)\n state.anchorMap = Object.create(null)\n\n while ((ch = state.input.charCodeAt(state.position)) !== 0) {\n skipSeparationSpace(state, true, -1)\n\n ch = state.input.charCodeAt(state.position)\n\n if (state.lineIndent > 0 || ch !== 0x25/* % */) {\n break\n }\n\n hasDirectives = true\n ch = state.input.charCodeAt(++state.position)\n let _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n const directiveName = state.input.slice(_position, state.position)\n const directiveArgs = []\n\n if (directiveName.length < 1) {\n throwError(state, 'directive name must not be less than one character in length')\n }\n\n while (ch !== 0) {\n while (isWhiteSpace(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (ch === 0x23/* # */) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (ch !== 0 && !isEol(ch))\n break\n }\n\n if (isEol(ch)) break\n\n _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n directiveArgs.push(state.input.slice(_position, state.position))\n }\n\n if (ch !== 0) readLineBreak(state)\n\n if (_hasOwnProperty.call(directiveHandlers, directiveName)) {\n directiveHandlers[directiveName](state, directiveName, directiveArgs)\n } else {\n throwWarning(state, 'unknown document directive \"' + directiveName + '\"')\n }\n }\n\n skipSeparationSpace(state, true, -1)\n\n if (state.lineIndent === 0 &&\n state.input.charCodeAt(state.position) === 0x2D/* - */ &&\n state.input.charCodeAt(state.position + 1) === 0x2D/* - */ &&\n state.input.charCodeAt(state.position + 2) === 0x2D/* - */) {\n state.position += 3\n skipSeparationSpace(state, true, -1)\n } else if (hasDirectives) {\n throwError(state, 'directives end mark is expected')\n }\n\n composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true)\n skipSeparationSpace(state, true, -1)\n\n if (state.checkLineBreaks &&\n PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) {\n throwWarning(state, 'non-ASCII line breaks are interpreted as content')\n }\n\n state.documents.push(state.result)\n\n if (state.position === state.lineStart && testDocumentSeparator(state)) {\n if (state.input.charCodeAt(state.position) === 0x2E/* . */) {\n state.position += 3\n skipSeparationSpace(state, true, -1)\n }\n return\n }\n\n if (state.position < (state.length - 1)) {\n throwError(state, 'end of the stream or a document separator is expected')\n }\n}\n\nfunction loadDocuments (input, options) {\n input = String(input)\n options = options || {}\n\n if (input.length !== 0) {\n // Add tailing `\\n` if not exists\n if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ &&\n input.charCodeAt(input.length - 1) !== 0x0D/* CR */) {\n input += '\\n'\n }\n\n // Strip BOM\n if (input.charCodeAt(0) === 0xFEFF) {\n input = input.slice(1)\n }\n }\n\n const state = new State(input, options)\n\n const nullpos = input.indexOf('\\0')\n\n if (nullpos !== -1) {\n state.position = nullpos\n throwError(state, 'null byte is not allowed in input')\n }\n\n // Use 0 as string terminator. That significantly simplifies bounds check.\n state.input += '\\0'\n\n while (state.input.charCodeAt(state.position) === 0x20/* Space */) {\n state.lineIndent += 1\n state.position += 1\n }\n\n while (state.position < (state.length - 1)) {\n readDocument(state)\n }\n\n return state.documents\n}\n\nfunction loadAll (input, iterator, options) {\n if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') {\n options = iterator\n iterator = null\n }\n\n const documents = loadDocuments(input, options)\n\n if (typeof iterator !== 'function') {\n return documents\n }\n\n for (let index = 0, length = documents.length; index < length; index += 1) {\n iterator(documents[index])\n }\n}\n\nfunction load (input, options) {\n const documents = loadDocuments(input, options)\n\n if (documents.length === 0) {\n return undefined\n } else if (documents.length === 1) {\n return documents[0]\n }\n throw new YAMLException('expected a single document in the stream, but found more')\n}\n\nmodule.exports.loadAll = loadAll\nmodule.exports.load = load\n","'use strict'\n\nconst common = require('./common')\n\n// get snippet for a single line, respecting maxLength\nfunction getLine (buffer, lineStart, lineEnd, position, maxLineLength) {\n let head = ''\n let tail = ''\n const maxHalfLength = Math.floor(maxLineLength / 2) - 1\n\n if (position - lineStart > maxHalfLength) {\n head = ' ... '\n lineStart = position - maxHalfLength + head.length\n }\n\n if (lineEnd - position > maxHalfLength) {\n tail = ' ...'\n lineEnd = position + maxHalfLength - tail.length\n }\n\n return {\n str: head + buffer.slice(lineStart, lineEnd).replace(/\\t/g, '→') + tail,\n pos: position - lineStart + head.length // relative position\n }\n}\n\nfunction padStart (string, max) {\n return common.repeat(' ', max - string.length) + string\n}\n\nfunction makeSnippet (mark, options) {\n options = Object.create(options || null)\n\n if (!mark.buffer) return null\n\n if (!options.maxLength) options.maxLength = 79\n if (typeof options.indent !== 'number') options.indent = 1\n if (typeof options.linesBefore !== 'number') options.linesBefore = 3\n if (typeof options.linesAfter !== 'number') options.linesAfter = 2\n\n const re = /\\r?\\n|\\r|\\0/g\n const lineStarts = [0]\n const lineEnds = []\n let match\n let foundLineNo = -1\n\n while ((match = re.exec(mark.buffer))) {\n lineEnds.push(match.index)\n lineStarts.push(match.index + match[0].length)\n\n if (mark.position <= match.index && foundLineNo < 0) {\n foundLineNo = lineStarts.length - 2\n }\n }\n\n if (foundLineNo < 0) foundLineNo = lineStarts.length - 1\n\n let result = ''\n const lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length\n const maxLineLength = options.maxLength - (options.indent + lineNoLength + 3)\n\n for (let i = 1; i <= options.linesBefore; i++) {\n if (foundLineNo - i < 0) break\n const line = getLine(\n mark.buffer,\n lineStarts[foundLineNo - i],\n lineEnds[foundLineNo - i],\n mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]),\n maxLineLength\n )\n result = common.repeat(' ', options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) +\n ' | ' + line.str + '\\n' + result\n }\n\n const line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength)\n result += common.repeat(' ', options.indent) + padStart((mark.line + 1).toString(), lineNoLength) +\n ' | ' + line.str + '\\n'\n result += common.repeat('-', options.indent + lineNoLength + 3 + line.pos) + '^' + '\\n'\n\n for (let i = 1; i <= options.linesAfter; i++) {\n if (foundLineNo + i >= lineEnds.length) break\n const line = getLine(\n mark.buffer,\n lineStarts[foundLineNo + i],\n lineEnds[foundLineNo + i],\n mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]),\n maxLineLength\n )\n result += common.repeat(' ', options.indent) + padStart((mark.line + i + 1).toString(), lineNoLength) +\n ' | ' + line.str + '\\n'\n }\n\n return result.replace(/\\n$/, '')\n}\n\nmodule.exports = makeSnippet\n","'use strict'\n\nconst common = require('./common')\nconst YAMLException = require('./exception')\nconst DEFAULT_SCHEMA = require('./schema/default')\n\nconst _toString = Object.prototype.toString\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\n\nconst CHAR_BOM = 0xFEFF\nconst CHAR_TAB = 0x09 /* Tab */\nconst CHAR_LINE_FEED = 0x0A /* LF */\nconst CHAR_CARRIAGE_RETURN = 0x0D /* CR */\nconst CHAR_SPACE = 0x20 /* Space */\nconst CHAR_EXCLAMATION = 0x21 /* ! */\nconst CHAR_DOUBLE_QUOTE = 0x22 /* \" */\nconst CHAR_SHARP = 0x23 /* # */\nconst CHAR_PERCENT = 0x25 /* % */\nconst CHAR_AMPERSAND = 0x26 /* & */\nconst CHAR_SINGLE_QUOTE = 0x27 /* ' */\nconst CHAR_ASTERISK = 0x2A /* * */\nconst CHAR_COMMA = 0x2C /* , */\nconst CHAR_MINUS = 0x2D /* - */\nconst CHAR_COLON = 0x3A /* : */\nconst CHAR_EQUALS = 0x3D /* = */\nconst CHAR_GREATER_THAN = 0x3E /* > */\nconst CHAR_QUESTION = 0x3F /* ? */\nconst CHAR_COMMERCIAL_AT = 0x40 /* @ */\nconst CHAR_LEFT_SQUARE_BRACKET = 0x5B /* [ */\nconst CHAR_RIGHT_SQUARE_BRACKET = 0x5D /* ] */\nconst CHAR_GRAVE_ACCENT = 0x60 /* ` */\nconst CHAR_LEFT_CURLY_BRACKET = 0x7B /* { */\nconst CHAR_VERTICAL_LINE = 0x7C /* | */\nconst CHAR_RIGHT_CURLY_BRACKET = 0x7D /* } */\n\nconst ESCAPE_SEQUENCES = {}\n\nESCAPE_SEQUENCES[0x00] = '\\\\0'\nESCAPE_SEQUENCES[0x07] = '\\\\a'\nESCAPE_SEQUENCES[0x08] = '\\\\b'\nESCAPE_SEQUENCES[0x09] = '\\\\t'\nESCAPE_SEQUENCES[0x0A] = '\\\\n'\nESCAPE_SEQUENCES[0x0B] = '\\\\v'\nESCAPE_SEQUENCES[0x0C] = '\\\\f'\nESCAPE_SEQUENCES[0x0D] = '\\\\r'\nESCAPE_SEQUENCES[0x1B] = '\\\\e'\nESCAPE_SEQUENCES[0x22] = '\\\\\"'\nESCAPE_SEQUENCES[0x5C] = '\\\\\\\\'\nESCAPE_SEQUENCES[0x85] = '\\\\N'\nESCAPE_SEQUENCES[0xA0] = '\\\\_'\nESCAPE_SEQUENCES[0x2028] = '\\\\L'\nESCAPE_SEQUENCES[0x2029] = '\\\\P'\n\nconst DEPRECATED_BOOLEANS_SYNTAX = [\n 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON',\n 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF'\n]\n\nconst DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\\.[0-9_]*)?$/\n\nfunction compileStyleMap (schema, map) {\n if (map === null) return {}\n\n const result = {}\n const keys = Object.keys(map)\n\n for (let index = 0, length = keys.length; index < length; index += 1) {\n let tag = keys[index]\n let style = String(map[tag])\n\n if (tag.slice(0, 2) === '!!') {\n tag = 'tag:yaml.org,2002:' + tag.slice(2)\n }\n const type = schema.compiledTypeMap['fallback'][tag]\n\n if (type && _hasOwnProperty.call(type.styleAliases, style)) {\n style = type.styleAliases[style]\n }\n\n result[tag] = style\n }\n\n return result\n}\n\nfunction encodeHex (character) {\n let handle\n let length\n\n const string = character.toString(16).toUpperCase()\n\n if (character <= 0xFF) {\n handle = 'x'\n length = 2\n } else if (character <= 0xFFFF) {\n handle = 'u'\n length = 4\n } else if (character <= 0xFFFFFFFF) {\n handle = 'U'\n length = 8\n } else {\n throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF')\n }\n\n return '\\\\' + handle + common.repeat('0', length - string.length) + string\n}\n\nconst QUOTING_TYPE_SINGLE = 1\nconst QUOTING_TYPE_DOUBLE = 2\n\nfunction State (options) {\n this.schema = options['schema'] || DEFAULT_SCHEMA\n this.indent = Math.max(1, (options['indent'] || 2))\n this.noArrayIndent = options['noArrayIndent'] || false\n this.skipInvalid = options['skipInvalid'] || false\n this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel'])\n this.styleMap = compileStyleMap(this.schema, options['styles'] || null)\n this.sortKeys = options['sortKeys'] || false\n this.lineWidth = options['lineWidth'] || 80\n this.noRefs = options['noRefs'] || false\n this.noCompatMode = options['noCompatMode'] || false\n this.condenseFlow = options['condenseFlow'] || false\n this.quotingType = options['quotingType'] === '\"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE\n this.forceQuotes = options['forceQuotes'] || false\n this.replacer = typeof options['replacer'] === 'function' ? options['replacer'] : null\n\n this.implicitTypes = this.schema.compiledImplicit\n this.explicitTypes = this.schema.compiledExplicit\n\n this.tag = null\n this.result = ''\n\n this.duplicates = []\n this.usedDuplicates = null\n}\n\n// Indents every line in a string. Empty lines (\\n only) are not indented.\nfunction indentString (string, spaces) {\n const ind = common.repeat(' ', spaces)\n let position = 0\n let result = ''\n const length = string.length\n\n while (position < length) {\n let line\n const next = string.indexOf('\\n', position)\n if (next === -1) {\n line = string.slice(position)\n position = length\n } else {\n line = string.slice(position, next + 1)\n position = next + 1\n }\n\n if (line.length && line !== '\\n') result += ind\n\n result += line\n }\n\n return result\n}\n\nfunction generateNextLine (state, level) {\n return '\\n' + common.repeat(' ', state.indent * level)\n}\n\nfunction testImplicitResolving (state, str) {\n for (let index = 0, length = state.implicitTypes.length; index < length; index += 1) {\n const type = state.implicitTypes[index]\n\n if (type.resolve(str)) {\n return true\n }\n }\n\n return false\n}\n\n// [33] s-white ::= s-space | s-tab\nfunction isWhitespace (c) {\n return c === CHAR_SPACE || c === CHAR_TAB\n}\n\n// Returns true if the character can be printed without escaping.\n// From YAML 1.2: \"any allowed characters known to be non-printable\n// should also be escaped. [However,] This isn’t mandatory\"\n// Derived from nb-char - \\t - #x85 - #xA0 - #x2028 - #x2029.\nfunction isPrintable (c) {\n return (c >= 0x00020 && c <= 0x00007E) ||\n ((c >= 0x000A1 && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) ||\n ((c >= 0x0E000 && c <= 0x00FFFD) && c !== CHAR_BOM) ||\n (c >= 0x10000 && c <= 0x10FFFF)\n}\n\n// [34] ns-char ::= nb-char - s-white\n// [27] nb-char ::= c-printable - b-char - c-byte-order-mark\n// [26] b-char ::= b-line-feed | b-carriage-return\n// Including s-white (for some reason, examples doesn't match specs in this aspect)\n// ns-char ::= c-printable - b-line-feed - b-carriage-return - c-byte-order-mark\nfunction isNsCharOrWhitespace (c) {\n return isPrintable(c) &&\n c !== CHAR_BOM &&\n // - b-char\n c !== CHAR_CARRIAGE_RETURN &&\n c !== CHAR_LINE_FEED\n}\n\n// [127] ns-plain-safe(c) ::= c = flow-out ⇒ ns-plain-safe-out\n// c = flow-in ⇒ ns-plain-safe-in\n// c = block-key ⇒ ns-plain-safe-out\n// c = flow-key ⇒ ns-plain-safe-in\n// [128] ns-plain-safe-out ::= ns-char\n// [129] ns-plain-safe-in ::= ns-char - c-flow-indicator\n// [130] ns-plain-char(c) ::= ( ns-plain-safe(c) - “:” - “#” )\n// | ( /* An ns-char preceding */ “#” )\n// | ( “:” /* Followed by an ns-plain-safe(c) */ )\nfunction isPlainSafe (c, prev, inblock) {\n const cIsNsCharOrWhitespace = isNsCharOrWhitespace(c)\n const cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c)\n return (\n (\n // ns-plain-safe\n inblock // c = flow-in\n ? cIsNsCharOrWhitespace\n : cIsNsCharOrWhitespace &&\n // - c-flow-indicator\n c !== CHAR_COMMA &&\n c !== CHAR_LEFT_SQUARE_BRACKET &&\n c !== CHAR_RIGHT_SQUARE_BRACKET &&\n c !== CHAR_LEFT_CURLY_BRACKET &&\n c !== CHAR_RIGHT_CURLY_BRACKET\n ) &&\n // ns-plain-char\n c !== CHAR_SHARP && // false on '#'\n !(prev === CHAR_COLON && !cIsNsChar)\n ) || // false on ': '\n (isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP) || // change to true on '[^ ]#'\n (prev === CHAR_COLON && cIsNsChar) // change to true on ':[^ ]'\n}\n\n// Simplified test for values allowed as the first character in plain style.\nfunction isPlainSafeFirst (c) {\n // Uses a subset of ns-char - c-indicator\n // where ns-char = nb-char - s-white.\n // No support of ( ( “?” | “:” | “-” ) /* Followed by an ns-plain-safe(c)) */ ) part\n return isPrintable(c) &&\n c !== CHAR_BOM &&\n !isWhitespace(c) && // - s-white\n // - (c-indicator ::=\n // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}”\n c !== CHAR_MINUS &&\n c !== CHAR_QUESTION &&\n c !== CHAR_COLON &&\n c !== CHAR_COMMA &&\n c !== CHAR_LEFT_SQUARE_BRACKET &&\n c !== CHAR_RIGHT_SQUARE_BRACKET &&\n c !== CHAR_LEFT_CURLY_BRACKET &&\n c !== CHAR_RIGHT_CURLY_BRACKET &&\n // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “\"”\n c !== CHAR_SHARP &&\n c !== CHAR_AMPERSAND &&\n c !== CHAR_ASTERISK &&\n c !== CHAR_EXCLAMATION &&\n c !== CHAR_VERTICAL_LINE &&\n c !== CHAR_EQUALS &&\n c !== CHAR_GREATER_THAN &&\n c !== CHAR_SINGLE_QUOTE &&\n c !== CHAR_DOUBLE_QUOTE &&\n // | “%” | “@” | “`”)\n c !== CHAR_PERCENT &&\n c !== CHAR_COMMERCIAL_AT &&\n c !== CHAR_GRAVE_ACCENT\n}\n\n// Simplified test for values allowed as the last character in plain style.\nfunction isPlainSafeLast (c) {\n // just not whitespace or colon, it will be checked to be plain character later\n return !isWhitespace(c) && c !== CHAR_COLON\n}\n\n// Same as 'string'.codePointAt(pos), but works in older browsers.\nfunction codePointAt (string, pos) {\n const first = string.charCodeAt(pos)\n let second\n\n if (first >= 0xD800 && first <= 0xDBFF && pos + 1 < string.length) {\n second = string.charCodeAt(pos + 1)\n if (second >= 0xDC00 && second <= 0xDFFF) {\n // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000\n }\n }\n return first\n}\n\n// Determines whether block indentation indicator is required.\nfunction needIndentIndicator (string) {\n const leadingSpaceRe = /^\\n* /\n return leadingSpaceRe.test(string)\n}\n\nconst STYLE_PLAIN = 1\nconst STYLE_SINGLE = 2\nconst STYLE_LITERAL = 3\nconst STYLE_FOLDED = 4\nconst STYLE_DOUBLE = 5\n\n// Determines which scalar styles are possible and returns the preferred style.\n// lineWidth = -1 => no limit.\n// Pre-conditions: str.length > 0.\n// Post-conditions:\n// STYLE_PLAIN or STYLE_SINGLE => no \\n are in the string.\n// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1).\n// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1).\nfunction chooseScalarStyle (string, singleLineOnly, indentPerLevel, lineWidth,\n testAmbiguousType, quotingType, forceQuotes, inblock) {\n let i\n let char = 0\n let prevChar = null\n let hasLineBreak = false\n let hasFoldableLine = false // only checked if shouldTrackWidth\n const shouldTrackWidth = lineWidth !== -1\n let previousLineBreak = -1 // count the first line correctly\n let plain = isPlainSafeFirst(codePointAt(string, 0)) &&\n isPlainSafeLast(codePointAt(string, string.length - 1))\n\n if (singleLineOnly || forceQuotes) {\n // Case: no block styles.\n // Check for disallowed characters to rule out plain and single.\n for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) {\n char = codePointAt(string, i)\n if (!isPrintable(char)) {\n return STYLE_DOUBLE\n }\n plain = plain && isPlainSafe(char, prevChar, inblock)\n prevChar = char\n }\n } else {\n // Case: block styles permitted.\n for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) {\n char = codePointAt(string, i)\n if (char === CHAR_LINE_FEED) {\n hasLineBreak = true\n // Check if any line can be folded.\n if (shouldTrackWidth) {\n hasFoldableLine = hasFoldableLine ||\n // Foldable line = too long, and not more-indented.\n (i - previousLineBreak - 1 > lineWidth &&\n string[previousLineBreak + 1] !== ' ')\n previousLineBreak = i\n }\n } else if (!isPrintable(char)) {\n return STYLE_DOUBLE\n }\n plain = plain && isPlainSafe(char, prevChar, inblock)\n prevChar = char\n }\n // in case the end is missing a \\n\n hasFoldableLine = hasFoldableLine || (shouldTrackWidth &&\n (i - previousLineBreak - 1 > lineWidth &&\n string[previousLineBreak + 1] !== ' '))\n }\n // Although every style can represent \\n without escaping, prefer block styles\n // for multiline, since they're more readable and they don't add empty lines.\n // Also prefer folding a super-long line.\n if (!hasLineBreak && !hasFoldableLine) {\n // Strings interpretable as another type have to be quoted;\n // e.g. the string 'true' vs. the boolean true.\n if (plain && !forceQuotes && !testAmbiguousType(string)) {\n return STYLE_PLAIN\n }\n return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE\n }\n // Edge case: block indentation indicator can only have one digit.\n if (indentPerLevel > 9 && needIndentIndicator(string)) {\n return STYLE_DOUBLE\n }\n // At this point we know block styles are valid.\n // Prefer literal style unless we want to fold.\n if (!forceQuotes) {\n return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL\n }\n return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE\n}\n\n// Note: line breaking/folding is implemented for only the folded style.\n// NB. We drop the last trailing newline (if any) of a returned block scalar\n// since the dumper adds its own newline. This always works:\n// • No ending newline => unaffected; already using strip \"-\" chomping.\n// • Ending newline => removed then restored.\n// Importantly, this keeps the \"+\" chomp indicator from gaining an extra line.\nfunction writeScalar (state, string, level, iskey, inblock) {\n state.dump = (function () {\n if (string.length === 0) {\n return state.quotingType === QUOTING_TYPE_DOUBLE ? '\"\"' : \"''\"\n }\n if (!state.noCompatMode) {\n if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) {\n return state.quotingType === QUOTING_TYPE_DOUBLE ? ('\"' + string + '\"') : (\"'\" + string + \"'\")\n }\n }\n\n const indent = state.indent * Math.max(1, level) // no 0-indent scalars\n // As indentation gets deeper, let the width decrease monotonically\n // to the lower bound min(state.lineWidth, 40).\n // Note that this implies\n // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound.\n // state.lineWidth > 40 + state.indent: width decreases until the lower bound.\n // This behaves better than a constant minimum width which disallows narrower options,\n // or an indent threshold which causes the width to suddenly increase.\n const lineWidth = (state.lineWidth === -1)\n ? -1\n : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent)\n\n // Without knowing if keys are implicit/explicit, assume implicit for safety.\n const singleLineOnly = iskey ||\n // No block styles in flow mode.\n (state.flowLevel > -1 && level >= state.flowLevel)\n function testAmbiguity (string) {\n return testImplicitResolving(state, string)\n }\n\n switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth,\n testAmbiguity, state.quotingType, state.forceQuotes && !iskey, inblock)) {\n case STYLE_PLAIN:\n return string\n case STYLE_SINGLE:\n return \"'\" + string.replace(/'/g, \"''\") + \"'\"\n case STYLE_LITERAL:\n return '|' + blockHeader(string, state.indent) +\n dropEndingNewline(indentString(string, indent))\n case STYLE_FOLDED:\n return '>' + blockHeader(string, state.indent) +\n dropEndingNewline(indentString(foldString(string, lineWidth), indent))\n case STYLE_DOUBLE:\n return '\"' + escapeString(string, lineWidth) + '\"'\n default:\n throw new YAMLException('impossible error: invalid scalar style')\n }\n }())\n}\n\n// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9.\nfunction blockHeader (string, indentPerLevel) {\n const indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''\n\n // note the special case: the string '\\n' counts as a \"trailing\" empty line.\n const clip = string[string.length - 1] === '\\n'\n const keep = clip && (string[string.length - 2] === '\\n' || string === '\\n')\n const chomp = keep ? '+' : (clip ? '' : '-')\n\n return indentIndicator + chomp + '\\n'\n}\n\n// (See the note for writeScalar.)\nfunction dropEndingNewline (string) {\n return string[string.length - 1] === '\\n' ? string.slice(0, -1) : string\n}\n\n// Note: a long line without a suitable break point will exceed the width limit.\n// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0.\nfunction foldString (string, width) {\n // In folded style, $k$ consecutive newlines output as $k+1$ newlines—\n // unless they're before or after a more-indented line, or at the very\n // beginning or end, in which case $k$ maps to $k$.\n // Therefore, parse each chunk as newline(s) followed by a content line.\n const lineRe = /(\\n+)([^\\n]*)/g\n\n // first line (possibly an empty line)\n let result = (function () {\n let nextLF = string.indexOf('\\n')\n nextLF = nextLF !== -1 ? nextLF : string.length\n lineRe.lastIndex = nextLF\n return foldLine(string.slice(0, nextLF), width)\n }())\n // If we haven't reached the first content line yet, don't add an extra \\n.\n let prevMoreIndented = string[0] === '\\n' || string[0] === ' '\n let moreIndented\n\n // rest of the lines\n let match\n while ((match = lineRe.exec(string))) {\n const prefix = match[1]\n const line = match[2]\n\n moreIndented = (line[0] === ' ')\n result += prefix +\n ((!prevMoreIndented && !moreIndented && line !== '') ? '\\n' : '') +\n foldLine(line, width)\n prevMoreIndented = moreIndented\n }\n\n return result\n}\n\n// Greedy line breaking.\n// Picks the longest line under the limit each time,\n// otherwise settles for the shortest line over the limit.\n// NB. More-indented lines *cannot* be folded, as that would add an extra \\n.\nfunction foldLine (line, width) {\n if (line === '' || line[0] === ' ') return line\n\n // Since a more-indented line adds a \\n, breaks can't be followed by a space.\n const breakRe = / [^ ]/g // note: the match index will always be <= length-2.\n let match\n // start is an inclusive index. end, curr, and next are exclusive.\n let start = 0\n let end\n let curr = 0\n let next = 0\n let result = ''\n\n // Invariants: 0 <= start <= length-1.\n // 0 <= curr <= next <= max(0, length-2). curr - start <= width.\n // Inside the loop:\n // A match implies length >= 2, so curr and next are <= length-2.\n while ((match = breakRe.exec(line))) {\n next = match.index\n // maintain invariant: curr - start <= width\n if (next - start > width) {\n end = (curr > start) ? curr : next // derive end <= length-2\n result += '\\n' + line.slice(start, end)\n // skip the space that was output as \\n\n start = end + 1 // derive start <= length-1\n }\n curr = next\n }\n\n // By the invariants, start <= length-1, so there is something left over.\n // It is either the whole string or a part starting from non-whitespace.\n result += '\\n'\n // Insert a break if the remainder is too long and there is a break available.\n if (line.length - start > width && curr > start) {\n result += line.slice(start, curr) + '\\n' + line.slice(curr + 1)\n } else {\n result += line.slice(start)\n }\n\n return result.slice(1) // drop extra \\n joiner\n}\n\n// Escapes a double-quoted string.\nfunction escapeString (string) {\n let result = ''\n let char = 0\n\n for (let i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) {\n char = codePointAt(string, i)\n const escapeSeq = ESCAPE_SEQUENCES[char]\n\n if (!escapeSeq && isPrintable(char)) {\n result += string[i]\n if (char >= 0x10000) result += string[i + 1]\n } else {\n result += escapeSeq || encodeHex(char)\n }\n }\n\n return result\n}\n\nfunction writeFlowSequence (state, level, object) {\n let _result = ''\n const _tag = state.tag\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n let value = object[index]\n\n if (state.replacer) {\n value = state.replacer.call(object, String(index), value)\n }\n\n // Write only valid elements, put null instead of invalid elements.\n if (writeNode(state, level, value, false, false) ||\n (typeof value === 'undefined' &&\n writeNode(state, level, null, false, false))) {\n if (_result !== '') _result += ',' + (!state.condenseFlow ? ' ' : '')\n _result += state.dump\n }\n }\n\n state.tag = _tag\n state.dump = '[' + _result + ']'\n}\n\nfunction writeBlockSequence (state, level, object, compact) {\n let _result = ''\n const _tag = state.tag\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n let value = object[index]\n\n if (state.replacer) {\n value = state.replacer.call(object, String(index), value)\n }\n\n // Write only valid elements, put null instead of invalid elements.\n if (writeNode(state, level + 1, value, true, true, false, true) ||\n (typeof value === 'undefined' &&\n writeNode(state, level + 1, null, true, true, false, true))) {\n if (!compact || _result !== '') {\n _result += generateNextLine(state, level)\n }\n\n if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {\n _result += '-'\n } else {\n _result += '- '\n }\n\n _result += state.dump\n }\n }\n\n state.tag = _tag\n state.dump = _result || '[]' // Empty sequence if no valid values.\n}\n\nfunction writeFlowMapping (state, level, object) {\n let _result = ''\n const _tag = state.tag\n const objectKeyList = Object.keys(object)\n\n for (let index = 0, length = objectKeyList.length; index < length; index += 1) {\n let pairBuffer = ''\n if (_result !== '') pairBuffer += ', '\n\n if (state.condenseFlow) pairBuffer += '\"'\n\n const objectKey = objectKeyList[index]\n let objectValue = object[objectKey]\n\n if (state.replacer) {\n objectValue = state.replacer.call(object, objectKey, objectValue)\n }\n\n if (!writeNode(state, level, objectKey, false, false)) {\n continue // Skip this pair because of invalid key;\n }\n\n if (state.dump.length > 1024) pairBuffer += '? '\n\n pairBuffer += state.dump + (state.condenseFlow ? '\"' : '') + ':' + (state.condenseFlow ? '' : ' ')\n\n if (!writeNode(state, level, objectValue, false, false)) {\n continue // Skip this pair because of invalid value.\n }\n\n pairBuffer += state.dump\n\n // Both key and value are valid.\n _result += pairBuffer\n }\n\n state.tag = _tag\n state.dump = '{' + _result + '}'\n}\n\nfunction writeBlockMapping (state, level, object, compact) {\n let _result = ''\n const _tag = state.tag\n const objectKeyList = Object.keys(object)\n\n // Allow sorting keys so that the output file is deterministic\n if (state.sortKeys === true) {\n // Default sorting\n objectKeyList.sort()\n } else if (typeof state.sortKeys === 'function') {\n // Custom sort function\n objectKeyList.sort(state.sortKeys)\n } else if (state.sortKeys) {\n // Something is wrong\n throw new YAMLException('sortKeys must be a boolean or a function')\n }\n\n for (let index = 0, length = objectKeyList.length; index < length; index += 1) {\n let pairBuffer = ''\n\n if (!compact || _result !== '') {\n pairBuffer += generateNextLine(state, level)\n }\n\n const objectKey = objectKeyList[index]\n let objectValue = object[objectKey]\n\n if (state.replacer) {\n objectValue = state.replacer.call(object, objectKey, objectValue)\n }\n\n if (!writeNode(state, level + 1, objectKey, true, true, true)) {\n continue // Skip this pair because of invalid key.\n }\n\n const explicitPair = (state.tag !== null && state.tag !== '?') ||\n (state.dump && state.dump.length > 1024)\n\n if (explicitPair) {\n if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {\n pairBuffer += '?'\n } else {\n pairBuffer += '? '\n }\n }\n\n pairBuffer += state.dump\n\n if (explicitPair) {\n pairBuffer += generateNextLine(state, level)\n }\n\n if (!writeNode(state, level + 1, objectValue, true, explicitPair)) {\n continue // Skip this pair because of invalid value.\n }\n\n if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {\n pairBuffer += ':'\n } else {\n pairBuffer += ': '\n }\n\n pairBuffer += state.dump\n\n // Both key and value are valid.\n _result += pairBuffer\n }\n\n state.tag = _tag\n state.dump = _result || '{}' // Empty mapping if no valid pairs.\n}\n\nfunction detectType (state, object, explicit) {\n const typeList = explicit ? state.explicitTypes : state.implicitTypes\n\n for (let index = 0, length = typeList.length; index < length; index += 1) {\n const type = typeList[index]\n\n if ((type.instanceOf || type.predicate) &&\n (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) &&\n (!type.predicate || type.predicate(object))) {\n if (explicit) {\n if (type.multi && type.representName) {\n state.tag = type.representName(object)\n } else {\n state.tag = type.tag\n }\n } else {\n state.tag = '?'\n }\n\n if (type.represent) {\n const style = state.styleMap[type.tag] || type.defaultStyle\n\n let _result\n if (_toString.call(type.represent) === '[object Function]') {\n _result = type.represent(object, style)\n } else if (_hasOwnProperty.call(type.represent, style)) {\n _result = type.represent[style](object, style)\n } else {\n throw new YAMLException('!<' + type.tag + '> tag resolver accepts not \"' + style + '\" style')\n }\n\n state.dump = _result\n }\n\n return true\n }\n }\n\n return false\n}\n\n// Serializes `object` and writes it to global `result`.\n// Returns true on success, or false on invalid object.\n//\nfunction writeNode (state, level, object, block, compact, iskey, isblockseq) {\n state.tag = null\n state.dump = object\n\n if (!detectType(state, object, false)) {\n detectType(state, object, true)\n }\n\n const type = _toString.call(state.dump)\n const inblock = block\n\n if (block) {\n block = (state.flowLevel < 0 || state.flowLevel > level)\n }\n\n const objectOrArray = type === '[object Object]' || type === '[object Array]'\n let duplicateIndex\n let duplicate\n\n if (objectOrArray) {\n duplicateIndex = state.duplicates.indexOf(object)\n duplicate = duplicateIndex !== -1\n }\n\n if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) {\n compact = false\n }\n\n if (duplicate && state.usedDuplicates[duplicateIndex]) {\n state.dump = '*ref_' + duplicateIndex\n } else {\n if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) {\n state.usedDuplicates[duplicateIndex] = true\n }\n if (type === '[object Object]') {\n if (block && (Object.keys(state.dump).length !== 0)) {\n writeBlockMapping(state, level, state.dump, compact)\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + state.dump\n }\n } else {\n writeFlowMapping(state, level, state.dump)\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + ' ' + state.dump\n }\n }\n } else if (type === '[object Array]') {\n if (block && (state.dump.length !== 0)) {\n if (state.noArrayIndent && !isblockseq && level > 0) {\n writeBlockSequence(state, level - 1, state.dump, compact)\n } else {\n writeBlockSequence(state, level, state.dump, compact)\n }\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + state.dump\n }\n } else {\n writeFlowSequence(state, level, state.dump)\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + ' ' + state.dump\n }\n }\n } else if (type === '[object String]') {\n if (state.tag !== '?') {\n writeScalar(state, state.dump, level, iskey, inblock)\n }\n } else if (type === '[object Undefined]') {\n return false\n } else {\n if (state.skipInvalid) return false\n throw new YAMLException('unacceptable kind of an object to dump ' + type)\n }\n\n if (state.tag !== null && state.tag !== '?') {\n // Need to encode all characters except those allowed by the spec:\n //\n // [35] ns-dec-digit ::= [#x30-#x39] /* 0-9 */\n // [36] ns-hex-digit ::= ns-dec-digit\n // | [#x41-#x46] /* A-F */ | [#x61-#x66] /* a-f */\n // [37] ns-ascii-letter ::= [#x41-#x5A] /* A-Z */ | [#x61-#x7A] /* a-z */\n // [38] ns-word-char ::= ns-dec-digit | ns-ascii-letter | “-”\n // [39] ns-uri-char ::= “%” ns-hex-digit ns-hex-digit | ns-word-char | “#”\n // | “;” | “/” | “?” | “:” | “@” | “&” | “=” | “+” | “$” | “,”\n // | “_” | “.” | “!” | “~” | “*” | “'” | “(” | “)” | “[” | “]”\n //\n // Also need to encode '!' because it has special meaning (end of tag prefix).\n //\n let tagStr = encodeURI(\n state.tag[0] === '!' ? state.tag.slice(1) : state.tag\n ).replace(/!/g, '%21')\n\n if (state.tag[0] === '!') {\n tagStr = '!' + tagStr\n } else if (tagStr.slice(0, 18) === 'tag:yaml.org,2002:') {\n tagStr = '!!' + tagStr.slice(18)\n } else {\n tagStr = '!<' + tagStr + '>'\n }\n\n state.dump = tagStr + ' ' + state.dump\n }\n }\n\n return true\n}\n\nfunction getDuplicateReferences (object, state) {\n const objects = []\n const duplicatesIndexes = []\n\n inspectNode(object, objects, duplicatesIndexes)\n\n const length = duplicatesIndexes.length\n for (let index = 0; index < length; index += 1) {\n state.duplicates.push(objects[duplicatesIndexes[index]])\n }\n state.usedDuplicates = new Array(length)\n}\n\nfunction inspectNode (object, objects, duplicatesIndexes) {\n if (object !== null && typeof object === 'object') {\n const index = objects.indexOf(object)\n if (index !== -1) {\n if (duplicatesIndexes.indexOf(index) === -1) {\n duplicatesIndexes.push(index)\n }\n } else {\n objects.push(object)\n\n if (Array.isArray(object)) {\n for (let i = 0, length = object.length; i < length; i += 1) {\n inspectNode(object[i], objects, duplicatesIndexes)\n }\n } else {\n const objectKeyList = Object.keys(object)\n\n for (let i = 0, length = objectKeyList.length; i < length; i += 1) {\n inspectNode(object[objectKeyList[i]], objects, duplicatesIndexes)\n }\n }\n }\n }\n}\n\nfunction dump (input, options) {\n options = options || {}\n\n const state = new State(options)\n\n if (!state.noRefs) getDuplicateReferences(input, state)\n\n let value = input\n\n if (state.replacer) {\n value = state.replacer.call({ '': value }, '', value)\n }\n\n if (writeNode(state, 0, value, true, true)) return state.dump + '\\n'\n\n return ''\n}\n\nmodule.exports.dump = dump\n","'use strict'\n\nconst loader = require('./lib/loader')\nconst dumper = require('./lib/dumper')\n\nfunction renamed (from, to) {\n return function () {\n throw new Error('Function yaml.' + from + ' is removed in js-yaml 4. ' +\n 'Use yaml.' + to + ' instead, which is now safe by default.')\n }\n}\n\nmodule.exports.Type = require('./lib/type')\nmodule.exports.Schema = require('./lib/schema')\nmodule.exports.FAILSAFE_SCHEMA = require('./lib/schema/failsafe')\nmodule.exports.JSON_SCHEMA = require('./lib/schema/json')\nmodule.exports.CORE_SCHEMA = require('./lib/schema/core')\nmodule.exports.DEFAULT_SCHEMA = require('./lib/schema/default')\nmodule.exports.load = loader.load\nmodule.exports.loadAll = loader.loadAll\nmodule.exports.dump = dumper.dump\nmodule.exports.YAMLException = require('./lib/exception')\n\n// Re-export all types in case user wants to create custom schema\nmodule.exports.types = {\n binary: require('./lib/type/binary'),\n float: require('./lib/type/float'),\n map: require('./lib/type/map'),\n null: require('./lib/type/null'),\n pairs: require('./lib/type/pairs'),\n set: require('./lib/type/set'),\n timestamp: require('./lib/type/timestamp'),\n bool: require('./lib/type/bool'),\n int: require('./lib/type/int'),\n merge: require('./lib/type/merge'),\n omap: require('./lib/type/omap'),\n seq: require('./lib/type/seq'),\n str: require('./lib/type/str')\n}\n\n// Removed functions from JS-YAML 3.0.x\nmodule.exports.safeLoad = renamed('safeLoad', 'load')\nmodule.exports.safeLoadAll = renamed('safeLoadAll', 'loadAll')\nmodule.exports.safeDump = renamed('safeDump', 'dump')\n","import yaml from '../index.js'\n\nconst {\n Type,\n Schema,\n FAILSAFE_SCHEMA,\n JSON_SCHEMA,\n CORE_SCHEMA,\n DEFAULT_SCHEMA,\n load,\n loadAll,\n dump,\n YAMLException,\n types,\n safeLoad,\n safeLoadAll,\n safeDump\n} = yaml\n\nexport {\n Type,\n Schema,\n FAILSAFE_SCHEMA,\n JSON_SCHEMA,\n CORE_SCHEMA,\n DEFAULT_SCHEMA,\n load,\n loadAll,\n dump,\n YAMLException,\n types,\n safeLoad,\n safeLoadAll,\n safeDump\n}\n\nexport default yaml\n"],"names":["_typeof","o","Symbol","iterator","constructor","prototype","isNothing","subject","common","isObject","toArray","sequence","Array","isArray","repeat","string","count","result","cycle","isNegativeZero","number","Number","NEGATIVE_INFINITY","extend","target","source","sourceKeys","Object","keys","index","length","key","formatError","exception","compact","where","message","reason","mark","name","line","column","snippet","YAMLException","Error","call","this","captureStackTrace","stack","create","toString","require$$0","TYPE_CONSTRUCTOR_OPTIONS","YAML_NODE_KINDS","type","tag","options","map","forEach","indexOf","kind","resolve","construct","data","instanceOf","predicate","represent","representName","defaultStyle","multi","styleAliases","style","alias","String","Type","require$$1","compileList","schema","currentType","newIndex","previousType","previousIndex","Schema","definition","implicit","explicit","push","concat","loadKind","compiledImplicit","compiledExplicit","compiledTypeMap","scalar","mapping","fallback","collectType","arguments","compileMap","str","seq","failsafe","require$$2","require$$3","_null","max","object","canonical","lowercase","uppercase","camelcase","empty","bool","isHexCode","c","isOctCode","isDecCode","parseYamlInteger","value","sign","ch","slice","parseInt","int","hasDigits","isFinite","charCodeAt","binary","obj","octal","decimal","hexadecimal","toUpperCase","YAML_FLOAT_PATTERN","RegExp","YAML_FLOAT_SPECIAL_PATTERN","SCIENTIFIC_WITHOUT_DOT","float","test","parseFloat","toLowerCase","POSITIVE_INFINITY","NaN","isNaN","res","replace","json","require$$4","core","YAML_DATE_REGEXP","YAML_TIMESTAMP_REGEXP","timestamp","exec","fraction","delta","match","year","month","day","Date","UTC","hour","minute","second","date","setTime","getTime","toISOString","merge","BASE64_MAP","bitlen","idx","code","charAt","input","bits","tailbits","Uint8Array","tail","_hasOwnProperty","hasOwnProperty","_toString","omap","objectKeys","pair","pairHasKey","pairKey","defineProperty","pairs","set","_default","require$$5","require$$6","makeSnippet","getLine","buffer","lineStart","lineEnd","position","maxLineLength","head","maxHalfLength","Math","floor","pos","padStart","maxLength","indent","linesBefore","linesAfter","re","lineStarts","lineEnds","foundLineNo","lineNoLength","min","i","DEFAULT_SCHEMA","PATTERN_NON_PRINTABLE","PATTERN_NON_ASCII_LINE_BREAKS","PATTERN_FLOW_INDICATORS","PATTERN_TAG_HANDLE","PATTERN_TAG_URI","_class","isEol","isWhiteSpace","isWsOrEol","isFlowIndicator","fromHexCode","lc","escapedHexLen","fromDecimalCode","simpleEscapeSequence","charFromCodepoint","fromCharCode","setProperty","configurable","enumerable","writable","simpleEscapeCheck","simpleEscapeMap","State","filename","onWarning","legacy","listener","maxDepth","maxTotalMergeKeys","implicitTypes","typeMap","lineIndent","depth","totalMergeKeys","firstTabInLine","documents","anchorMapTransactions","generateError","state","throwError","throwWarning","storeAnchor","transactions","transaction","existed","anchorMap","snapshotState","anchor","restoreState","snapshot","directiveHandlers","YAML","args","version","major","minor","checkLineBreaks","TAG","prefix","handle","tagMap","decodeURIComponent","err","captureSegment","start","end","checkJson","_result","_position","_length","_character","mergeMappings","destination","overridableKeys","quantity","storeMappingPair","keyTag","keyNode","valueNode","startLine","startLineStart","startPos","readLineBreak","skipSeparationSpace","allowComments","checkIndent","lineBreaks","testDocumentSeparator","writeFoldedLines","readBlockSequence","nodeIndent","_tag","_anchor","detected","_line","composeNode","readBlockMapping","flowIndent","allowCompact","_keyLine","_keyLineStart","_keyPos","atExplicitKey","following","readTagProperty","tagHandle","tagName","isVerbatim","isNamed","readAnchorProperty","tryReadBlockMappingFromProperty","propertyStart","fallbackState","beginAnchorTransaction","pop","parent","names","commitAnchorTransaction","entry","rollbackAnchorTransaction","parentIndent","nodeContext","allowToSeek","allowBlockScalars","allowBlockCollections","blockIndent","indentStatus","atNewLine","hasContent","allowBlockStyles","propertyState","_lineStart","_pos","terminator","isPair","isExplicitPair","isMapping","readNext","readFlowCollection","folding","tmp","chomping","didReadContent","detectedIndent","textIndent","emptyLines","atMoreIndented","captureStart","readBlockScalar","captureEnd","readSingleQuotedScalar","hexLength","hexResult","readDoubleQuotedScalar","readAlias","withinFlowCollection","hasPendingContent","_lineIndent","_kind","readPlainScalar","typeIndex","typeQuantity","typeList","readDocument","documentStart","hasDirectives","directiveName","directiveArgs","loadDocuments","nullpos","loader","loadAll","load","CHAR_BOM","ESCAPE_SEQUENCES","DEPRECATED_BOOLEANS_SYNTAX","DEPRECATED_BASE60_SYNTAX","encodeHex","character","noArrayIndent","skipInvalid","flowLevel","styleMap","compileStyleMap","sortKeys","lineWidth","noRefs","noCompatMode","condenseFlow","quotingType","forceQuotes","replacer","explicitTypes","duplicates","usedDuplicates","indentString","spaces","ind","next","generateNextLine","level","isWhitespace","isPrintable","isNsCharOrWhitespace","isPlainSafe","prev","inblock","cIsNsCharOrWhitespace","cIsNsChar","codePointAt","first","needIndentIndicator","chooseScalarStyle","singleLineOnly","indentPerLevel","testAmbiguousType","char","prevChar","hasLineBreak","hasFoldableLine","shouldTrackWidth","previousLineBreak","plain","isPlainSafeLast","writeScalar","iskey","dump","testImplicitResolving","blockHeader","dropEndingNewline","width","moreIndented","lineRe","nextLF","lastIndex","foldLine","prevMoreIndented","foldString","escapeSeq","escapeString","indentIndicator","clip","breakRe","curr","writeBlockSequence","writeNode","detectType","block","isblockseq","duplicateIndex","duplicate","objectOrArray","objectKeyList","sort","pairBuffer","objectKey","objectValue","explicitPair","writeBlockMapping","writeFlowMapping","writeFlowSequence","tagStr","encodeURI","getDuplicateReferences","objects","duplicatesIndexes","inspectNode","dumper","renamed","from","to","jsYaml","FAILSAFE_SCHEMA","JSON_SCHEMA","CORE_SCHEMA","require$$7","require$$8","types","require$$9","require$$10","require$$11","null","require$$12","require$$13","require$$14","require$$15","require$$16","require$$17","require$$18","require$$19","require$$20","require$$21","safeLoad","safeLoadAll","safeDump","yaml"],"mappings":"udAAY,SAAAA,EAAAC,GAAA,OAAAD,EAAA,mBAAAE,QAAA,iBAAAA,OAAAC,SAAA,SAAAF,GAAA,cAAAA,GAAA,SAAAA,GAAA,OAAAA,GAAA,mBAAAC,QAAAD,EAAAG,cAAAF,QAAAD,IAAAC,OAAAG,UAAA,gBAAAJ,CAAA,GAAAA,EAAA,CAEZ,SAASK,EAAWC,GAClB,OAAQ,MAAOA,CACjB,YAwCAC,EAAAF,UAA2BA,EAC3BE,EAAAC,SAvCA,SAAmBF,GACjB,MAA2B,WAAnBP,EAAOO,IAAsC,OAAZA,CAC3C,EAsCAC,EAAAE,QApCA,SAAkBC,GAChB,OAAIC,MAAMC,QAAQF,GAAkBA,EAC3BL,EAAUK,GAAkB,GAE9B,CAACA,EACV,EAgCAH,EAAAM,OAjBA,SAAiBC,EAAQC,GAGvB,IAFA,IAAIC,EAAS,GAEJC,EAAQ,EAAGA,EAAQF,EAAOE,GAAS,EAC1CD,GAAUF,EAGZ,OAAOE,CACT,EAUAT,EAAAW,eARA,SAAyBC,GACvB,OAAmB,IAAXA,GAAkBC,OAAOC,oBAAsB,EAAIF,CAC7D,EAOAZ,EAAAe,OAhCA,SAAiBC,EAAQC,GACvB,GAAIA,EAGF,IAFA,IAAMC,EAAaC,OAAOC,KAAKH,GAEtBI,EAAQ,EAAGC,EAASJ,EAAWI,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CAC1E,IAAME,EAAML,EAAWG,GACvBL,EAAOO,GAAON,EAAOM,EACvB,CAGF,OAAOP,CACT,+BCxBA,SAASQ,EAAaC,EAAWC,GAC/B,IAAIC,EAAQ,GACNC,EAAUH,EAAUI,QAAU,mBAEpC,OAAKJ,EAAUK,MAEXL,EAAUK,KAAKC,OACjBJ,GAAS,OAASF,EAAUK,KAAKC,KAAO,MAG1CJ,GAAS,KAAOF,EAAUK,KAAKE,KAAO,GAAK,KAAOP,EAAUK,KAAKG,OAAS,GAAK,KAE1EP,GAAWD,EAAUK,KAAKI,UAC7BP,GAAS,OAASF,EAAUK,KAAKI,SAG5BN,EAAU,IAAMD,GAZKC,CAa9B,CAEA,SAASO,EAAeN,EAAQC,GAE9BM,MAAMC,KAAKC,MAEXA,KAAKP,KAAO,gBACZO,KAAKT,OAASA,EACdS,KAAKR,KAAOA,EACZQ,KAAKV,QAAUJ,EAAYc,MAAM,GAG7BF,MAAMG,kBAERH,MAAMG,kBAAkBD,KAAMA,KAAK1C,aAGnC0C,KAAKE,OAAS,IAAIJ,OAASI,OAAS,EAExC,YAGAL,EAActC,UAAYsB,OAAOsB,OAAOL,MAAMvC,WAC9CsC,EAActC,UAAUD,YAAcuC,EAEtCA,EAActC,UAAU6C,SAAW,SAAmBhB,GACpD,OAAOY,KAAKP,KAAO,KAAOP,EAAYc,KAAMZ,EAC9C,EAEAD,EAAiBU,iCChDjB,IAAMA,EAAgBQ,IAEhBC,EAA2B,CAC/B,OACA,QACA,UACA,YACA,aACA,YACA,YACA,gBACA,eACA,gBAGIC,EAAkB,CACtB,SACA,WACA,kBA6CFC,EA5BA,SAAeC,EAAKC,GAdpB,IAA8BC,EACtBxC,EAoCN,GAtBAuC,EAAUA,GAAW,CAAA,EAErB7B,OAAOC,KAAK4B,GAASE,QAAQ,SAAUnB,GACrC,IAA+C,IAA3Ca,EAAyBO,QAAQpB,GACnC,MAAM,IAAII,EAAc,mBAAqBJ,EAAO,8BAAgCgB,EAAM,eAE9F,GAGAT,KAAKU,QAAUA,EACfV,KAAKS,IAAMA,EACXT,KAAKc,KAAOJ,EAAc,MAAK,KAC/BV,KAAKe,QAAUL,EAAiB,SAAK,WAAc,OAAO,GAC1DV,KAAKgB,UAAYN,EAAmB,WAAK,SAAUO,GAAQ,OAAOA,GAClEjB,KAAKkB,WAAaR,EAAoB,YAAK,KAC3CV,KAAKmB,UAAYT,EAAmB,WAAK,KACzCV,KAAKoB,UAAYV,EAAmB,WAAK,KACzCV,KAAKqB,cAAgBX,EAAuB,eAAK,KACjDV,KAAKsB,aAAeZ,EAAsB,cAAK,KAC/CV,KAAKuB,MAAQb,EAAe,QAAK,EACjCV,KAAKwB,cAnCuBb,EAmCYD,EAAsB,cAAK,KAlC7DvC,EAAS,CAAA,EAEH,OAARwC,GACF9B,OAAOC,KAAK6B,GAAKC,QAAQ,SAAUa,GACjCd,EAAIc,GAAOb,QAAQ,SAAUc,GAC3BvD,EAAOwD,OAAOD,IAAUD,CAC1B,EACF,GAGKtD,IA0BoC,IAAvCoC,EAAgBM,QAAQb,KAAKc,MAC/B,MAAM,IAAIjB,EAAc,iBAAmBG,KAAKc,KAAO,uBAAyBL,EAAM,eAE1F,iCC7DA,IAAMZ,EAAgBQ,IAChBuB,EAAOC,IAEb,SAASC,EAAaC,EAAQtC,GAC5B,IAAMtB,EAAS,GAgBf,OAdA4D,EAAOtC,GAAMmB,QAAQ,SAAUoB,GAC7B,IAAIC,EAAW9D,EAAOa,OAEtBb,EAAOyC,QAAQ,SAAUsB,EAAcC,GACjCD,EAAazB,MAAQuB,EAAYvB,KACjCyB,EAAapB,OAASkB,EAAYlB,MAClCoB,EAAaX,QAAUS,EAAYT,QACrCU,EAAWE,EAEf,GAEAhE,EAAO8D,GAAYD,CACrB,GAEO7D,CACT,CA8BA,SAASiE,EAAQC,GACf,OAAOrC,KAAKvB,OAAO4D,EACrB,QAEAD,EAAO7E,UAAUkB,OAAS,SAAiB4D,GACzC,IAAIC,EAAW,GACXC,EAAW,GAEf,GAAIF,aAAsBT,EAExBW,EAASC,KAAKH,WACLvE,MAAMC,QAAQsE,GAEvBE,EAAWA,EAASE,OAAOJ,YAClBA,IAAevE,MAAMC,QAAQsE,EAAWC,YAAaxE,MAAMC,QAAQsE,EAAWE,UAKvF,MAAM,IAAI1C,EAAc,oHAHpBwC,EAAWC,WAAUA,EAAWA,EAASG,OAAOJ,EAAWC,WAC3DD,EAAWE,WAAUA,EAAWA,EAASE,OAAOJ,EAAWE,UAIjE,CAEAD,EAAS1B,QAAQ,SAAUJ,GACzB,KAAMA,aAAgBoB,GACpB,MAAM,IAAI/B,EAAc,sFAG1B,GAAIW,EAAKkC,UAA8B,WAAlBlC,EAAKkC,SACxB,MAAM,IAAI7C,EAAc,mHAG1B,GAAIW,EAAKe,MACP,MAAM,IAAI1B,EAAc,qGAE5B,GAEA0C,EAAS3B,QAAQ,SAAUJ,GACzB,KAAMA,aAAgBoB,GACpB,MAAM,IAAI/B,EAAc,qFAE5B,GAEA,IAAM1B,EAASU,OAAOsB,OAAOiC,EAAO7E,WASpC,OAPAY,EAAOmE,UAAYtC,KAAKsC,UAAY,IAAIG,OAAOH,GAC/CnE,EAAOoE,UAAYvC,KAAKuC,UAAY,IAAIE,OAAOF,GAE/CpE,EAAOwE,iBAAmBb,EAAY3D,EAAQ,YAC9CA,EAAOyE,iBAAmBd,EAAY3D,EAAQ,YAC9CA,EAAO0E,gBA9ET,WACE,IAAM1E,EAAS,CACb2E,OAAQ,CAAA,EACRjF,SAAU,CAAA,EACVkF,QAAS,CAAA,EACTC,SAAU,CAAA,EACVzB,MAAO,CACLuB,OAAQ,GACRjF,SAAU,GACVkF,QAAS,GACTC,SAAU,KAGd,SAASC,EAAazC,GAChBA,EAAKe,OACPpD,EAAOoD,MAAMf,EAAKM,MAAM0B,KAAKhC,GAC7BrC,EAAOoD,MAAgB,SAAEiB,KAAKhC,IAE9BrC,EAAOqC,EAAKM,MAAMN,EAAKC,KAAOtC,EAAiB,SAAEqC,EAAKC,KAAOD,CAEjE,CAEA,IAAA,IAASzB,EAAQ,EAAGC,EAASkE,UAAUlE,OAAQD,EAAQC,EAAQD,GAAS,EACtEmE,UAAUnE,GAAO6B,QAAQqC,GAE3B,OAAO9E,CACT,CAoD2BgF,CAAWhF,EAAOwE,iBAAkBxE,EAAOyE,kBAE7DzE,CACT,EAEA4D,EAAiBK,iCC1GjB,IAAMR,EAAOvB,WAEb+C,EAAiB,IAAIxB,EAAK,wBAAyB,CACjDd,KAAM,SACNE,UAAW,SAAUC,GAAQ,OAAgB,OAATA,EAAgBA,EAAO,EAAG,oCCJhE,IAAMW,EAAOvB,WAEbgD,EAAiB,IAAIzB,EAAK,wBAAyB,CACjDd,KAAM,WACNE,UAAW,SAAUC,GAAQ,OAAgB,OAATA,EAAgBA,EAAO,EAAG,oCCJhE,IAAMW,EAAOvB,WAEbM,EAAiB,IAAIiB,EAAK,wBAAyB,CACjDd,KAAM,UACNE,UAAW,SAAUC,GAAQ,OAAgB,OAATA,EAAgBA,EAAO,CAAA,CAAG,oCCDhE,IAAMmB,EAAS/B,WAEfiD,EAAiB,IAAIlB,EAAO,CAC1BG,SAAU,CACRV,IACA0B,KACAC,wCCTJ,IAAM5B,EAAOvB,WAmBboD,EAAiB,IAAI7B,EAAK,yBAA0B,CAClDd,KAAM,SACNC,QAnBF,SAA0BE,GACxB,GAAa,OAATA,EAAe,OAAO,EAE1B,IAAMyC,EAAMzC,EAAKjC,OAEjB,OAAgB,IAAR0E,GAAsB,MAATzC,GACL,IAARyC,IAAuB,SAATzC,GAA4B,SAATA,GAA4B,SAATA,EAC9D,EAaED,UAXF,WACE,OAAO,IACT,EAUEG,UARF,SAAiBwC,GACf,OAAkB,OAAXA,CACT,EAOEvC,UAAW,CACTwC,UAAW,WAAc,MAAO,KAChCC,UAAW,WAAc,MAAO,QAChCC,UAAW,WAAc,MAAO,QAChCC,UAAW,WAAc,MAAO,QAChCC,MAAO,WAAc,MAAO,EAAG,GAEjC1C,aAAc,8CC/BhB,IAAMM,EAAOvB,WAqBb4D,EAAiB,IAAIrC,EAAK,yBAA0B,CAClDd,KAAM,SACNC,QArBF,SAA6BE,GAC3B,GAAa,OAATA,EAAe,OAAO,EAE1B,IAAMyC,EAAMzC,EAAKjC,OAEjB,OAAgB,IAAR0E,IAAuB,SAATzC,GAA4B,SAATA,GAA4B,SAATA,IAC5C,IAARyC,IAAuB,UAATzC,GAA6B,UAATA,GAA6B,UAATA,EAChE,EAeED,UAbF,SAA+BC,GAC7B,MAAgB,SAATA,GACS,SAATA,GACS,SAATA,CACT,EAUEE,UARF,SAAoBwC,GAClB,MAAkD,qBAA3C9E,OAAOtB,UAAU6C,SAASL,KAAK4D,EACxC,EAOEvC,UAAW,CACTyC,UAAW,SAAUF,GAAU,OAAOA,EAAS,OAAS,SACxDG,UAAW,SAAUH,GAAU,OAAOA,EAAS,OAAS,SACxDI,UAAW,SAAUJ,GAAU,OAAOA,EAAS,OAAS,OAAQ,GAElErC,aAAc,8CC/BhB,IAAM5D,EAAS2C,IACTuB,EAAOC,IAEb,SAASqC,EAAWC,GAClB,OAASA,GAAK,IAAiBA,GAAK,IAC3BA,GAAK,IAAiBA,GAAK,IAC3BA,GAAK,IAAiBA,GAAK,GACtC,CAEA,SAASC,EAAWD,GAClB,OAASA,GAAK,IAAiBA,GAAK,EACtC,CAEA,SAASE,EAAWF,GAClB,OAASA,GAAK,IAAiBA,GAAK,EACtC,CA0EA,SAASG,EAAkBrD,GACzB,IAAIsD,EAAQtD,EACRuD,EAAO,EAEPC,EAAKF,EAAM,GAQf,GANW,MAAPE,GAAqB,MAAPA,IACL,MAAPA,IAAYD,GAAO,GAEvBC,GADAF,EAAQA,EAAMG,MAAM,IACT,IAGC,MAAVH,EAAe,OAAO,EAE1B,GAAW,MAAPE,EAAY,CACd,GAAiB,MAAbF,EAAM,GAAY,OAAOC,EAAOG,SAASJ,EAAMG,MAAM,GAAI,GAC7D,GAAiB,MAAbH,EAAM,GAAY,OAAOC,EAAOG,SAASJ,EAAMG,MAAM,GAAI,IAC7D,GAAiB,MAAbH,EAAM,GAAY,OAAOC,EAAOG,SAASJ,EAAMG,MAAM,GAAI,EAC/D,CAEA,OAAOF,EAAOG,SAASJ,EAAO,GAChC,QAWAK,EAAiB,IAAIhD,EAAK,wBAAyB,CACjDd,KAAM,SACNC,QA1GF,SAA6BE,GAC3B,GAAa,OAATA,EAAe,OAAO,EAE1B,IAAMyC,EAAMzC,EAAKjC,OACbD,EAAQ,EACR8F,GAAY,EAEhB,IAAKnB,EAAK,OAAO,EAEjB,IAAIe,EAAKxD,EAAKlC,GAOd,GAJW,MAAP0F,GAAqB,MAAPA,IAChBA,EAAKxD,IAAOlC,IAGH,MAAP0F,EAAY,CAEd,GAAI1F,EAAQ,IAAM2E,EAAK,OAAO,EAK9B,GAAW,OAJXe,EAAKxD,IAAOlC,IAII,CAId,IAFAA,IAEOA,EAAQ2E,EAAK3E,IAAS,CAE3B,GAAW,OADX0F,EAAKxD,EAAKlC,KACe,MAAP0F,EAAY,OAAO,EACrCI,GAAY,CACd,CACA,OAAOA,GAAaC,SAASR,EAAiBrD,GAChD,CAEA,GAAW,MAAPwD,EAAY,CAId,IAFA1F,IAEOA,EAAQ2E,EAAK3E,IAAS,CAC3B,IAAKmF,EAAUjD,EAAK8D,WAAWhG,IAAS,OAAO,EAC/C8F,GAAY,CACd,CACA,OAAOA,GAAaC,SAASR,EAAiBrD,GAChD,CAEA,GAAW,MAAPwD,EAAY,CAId,IAFA1F,IAEOA,EAAQ2E,EAAK3E,IAAS,CAC3B,IAAKqF,EAAUnD,EAAK8D,WAAWhG,IAAS,OAAO,EAC/C8F,GAAY,CACd,CACA,OAAOA,GAAaC,SAASR,EAAiBrD,GAChD,CACF,CAIA,KAAOlC,EAAQ2E,EAAK3E,IAAS,CAC3B,IAAKsF,EAAUpD,EAAK8D,WAAWhG,IAC7B,OAAO,EAET8F,GAAY,CACd,CAEA,QAAKA,GAEEC,SAASR,EAAiBrD,GACnC,EAqCED,UAZF,SAA+BC,GAC7B,OAAOqD,EAAiBrD,EAC1B,EAWEE,UATF,SAAoBwC,GAClB,MAAoD,oBAA5C9E,OAAOtB,UAAU6C,SAASL,KAAK4D,IAC/BA,EAAS,GAAM,IAAMjG,EAAOW,eAAesF,EACrD,EAOEvC,UAAW,CACT4D,OAAQ,SAAUC,GAAO,OAAOA,GAAO,EAAI,KAAOA,EAAI7E,SAAS,GAAK,MAAQ6E,EAAI7E,SAAS,GAAGsE,MAAM,IAClGQ,MAAO,SAAUD,GAAO,OAAOA,GAAO,EAAI,KAAOA,EAAI7E,SAAS,GAAK,MAAQ6E,EAAI7E,SAAS,GAAGsE,MAAM,IACjGS,QAAS,SAAUF,GAAO,OAAOA,EAAI7E,SAAS,KAC9CgF,YAAa,SAAUH,GAAO,OAAOA,GAAO,EAAI,KAAOA,EAAI7E,SAAS,IAAIiF,cAAgB,MAAQJ,EAAI7E,SAAS,IAAIiF,cAAcX,MAAM,EAAG,GAE1IpD,aAAc,UACdE,aAAc,CACZwD,OAAQ,CAAC,EAAG,OACZE,MAAO,CAAC,EAAG,OACXC,QAAS,CAAC,GAAI,OACdC,YAAa,CAAC,GAAI,0CCzItB,IAAM1H,EAAS2C,IACTuB,EAAOC,IAEPyD,EAAqB,IAAIC,OAE7B,oIASIC,EAA6B,IAAID,OACrC,oDAoCF,IAAME,EAAyB,uBAsC/BC,EAAiB,IAAI9D,EAAK,0BAA2B,CACnDd,KAAM,SACNC,QAtEF,SAA2BE,GACzB,OAAa,OAATA,MAECqE,EAAmBK,KAAK1E,OAIzB6D,SAASc,WAAW3E,EAAM,MAIvBuE,EAA2BG,KAAK1E,IACzC,EA2DED,UAzDF,SAA6BC,GAC3B,IAAIsD,EAAQtD,EAAK4E,cACXrB,EAAoB,MAAbD,EAAM,IAAa,EAAK,EAMrC,MAJI,KAAK1D,QAAQ0D,EAAM,KAAO,IAC5BA,EAAQA,EAAMG,MAAM,IAGR,SAAVH,EACe,IAATC,EAAcjG,OAAOuH,kBAAoBvH,OAAOC,kBACrC,SAAV+F,EACFwB,IAEFvB,EAAOoB,WAAWrB,EAAO,GAClC,EA4CEpD,UATF,SAAkBwC,GAChB,MAAmD,oBAA3C9E,OAAOtB,UAAU6C,SAASL,KAAK4D,KAC/BA,EAAS,GAAM,GAAKjG,EAAOW,eAAesF,GACpD,EAOEvC,UAzCF,SAA6BuC,EAAQlC,GACnC,GAAIuE,MAAMrC,GACR,OAAQlC,GACN,IAAK,YAAa,MAAO,OACzB,IAAK,YAAa,MAAO,OACzB,IAAK,YAAa,MAAO,YAE7B,GAAWlD,OAAOuH,oBAAsBnC,EACtC,OAAQlC,GACN,IAAK,YAAa,MAAO,OACzB,IAAK,YAAa,MAAO,OACzB,IAAK,YAAa,MAAO,YAE7B,GAAWlD,OAAOC,oBAAsBmF,EACtC,OAAQlC,GACN,IAAK,YAAa,MAAO,QACzB,IAAK,YAAa,MAAO,QACzB,IAAK,YAAa,MAAO,gBAElB/D,EAAOW,eAAesF,GAC/B,MAAO,OAGT,IAAMsC,EAAMtC,EAAOvD,SAAS,IAK5B,OAAOqF,EAAuBE,KAAKM,GAAOA,EAAIC,QAAQ,IAAK,MAAQD,CACrE,EAaE3E,aAAc,4CCxFhB6E,EAAiB9F,KAAsB5B,OAAO,CAC5C6D,SAAU,CACRT,KACA0B,KACAC,KACA4C,uCCNJC,EAAiBhG,sCCNjB,IAAMuB,EAAOvB,IAEPiG,EAAmB,IAAIf,OAC3B,sDAIIgB,EAAwB,IAAIhB,OAChC,2LAuEFiB,EAAiB,IAAI5E,EAAK,8BAA+B,CACvDd,KAAM,SACNC,QA9DF,SAA+BE,GAC7B,OAAa,OAATA,IACgC,OAAhCqF,EAAiBG,KAAKxF,IACe,OAArCsF,EAAsBE,KAAKxF,GAEjC,EA0DED,UAxDF,SAAiCC,GAC/B,IAAIyF,EAAW,EACXC,EAAQ,KAERC,EAAQN,EAAiBG,KAAKxF,GAGlC,GAFc,OAAV2F,IAAgBA,EAAQL,EAAsBE,KAAKxF,IAEzC,OAAV2F,EAAgB,MAAM,IAAI9G,MAAM,sBAIpC,IAAM+G,GAASD,EAAM,GACfE,GAAUF,EAAM,GAAM,EACtBG,GAAQH,EAAM,GAEpB,IAAKA,EAAM,GACT,OAAO,IAAII,KAAKA,KAAKC,IAAIJ,EAAMC,EAAOC,IAKxC,IAAMG,GAASN,EAAM,GACfO,GAAWP,EAAM,GACjBQ,GAAWR,EAAM,GAEvB,GAAIA,EAAM,GAAI,CAEZ,IADAF,EAAWE,EAAM,GAAGlC,MAAM,EAAG,GACtBgC,EAAS1H,OAAS,GACvB0H,GAAY,IAEdA,GAAYA,CACd,CAIIE,EAAM,KAGRD,EAAmC,KAAjB,IAFDC,EAAM,OACJA,EAAM,KAAO,IAEf,MAAbA,EAAM,QAAqBD,IAGjC,IAAMU,EAAO,IAAIL,KAAKA,KAAKC,IAAIJ,EAAMC,EAAOC,EAAKG,EAAMC,EAAQC,EAAQV,IAIvE,OAFIC,GAAOU,EAAKC,QAAQD,EAAKE,UAAYZ,GAElCU,CACT,EAUEnG,WAAY8F,KACZ5F,UATF,SAAiCuC,GAC/B,OAAOA,EAAO6D,aAChB,oCC7EA,IAAM5F,EAAOvB,WAMboH,EAAiB,IAAI7F,EAAK,0BAA2B,CACnDd,KAAM,SACNC,QANF,SAA2BE,GACzB,MAAgB,OAATA,GAA0B,OAATA,CAC1B,oCCJA,IAAMW,EAAOvB,IAGPqH,EAAa,+EA8GnB1C,EAAiB,IAAIpD,EAAK,2BAA4B,CACpDd,KAAM,SACNC,QA9GF,SAA4BE,GAC1B,GAAa,OAATA,EAAe,OAAO,EAO1B,IALA,IAAI0G,EAAS,EACPjE,EAAMzC,EAAKjC,OACX2B,EAAM+G,EAGHE,EAAM,EAAGA,EAAMlE,EAAKkE,IAAO,CAClC,IAAMC,EAAOlH,EAAIE,QAAQI,EAAK6G,OAAOF,IAGrC,KAAIC,EAAO,IAAX,CAGA,GAAIA,EAAO,EAAG,OAAO,EAErBF,GAAU,CALK,CAMjB,CAGA,OAAQA,EAAS,GAAO,CAC1B,EAyFE3G,UAvFF,SAA8BC,GAS5B,IARA,IAAM8G,EAAQ9G,EAAKiF,QAAQ,WAAY,IACjCxC,EAAMqE,EAAM/I,OACZ2B,EAAM+G,EACRM,EAAO,EACL7J,EAAS,GAINyJ,EAAM,EAAGA,EAAMlE,EAAKkE,IACtBA,EAAM,GAAM,GAAMA,IACrBzJ,EAAOqE,KAAMwF,GAAQ,GAAM,KAC3B7J,EAAOqE,KAAMwF,GAAQ,EAAK,KAC1B7J,EAAOqE,KAAY,IAAPwF,IAGdA,EAAQA,GAAQ,EAAKrH,EAAIE,QAAQkH,EAAMD,OAAOF,IAKhD,IAAMK,EAAYvE,EAAM,EAAK,EAa7B,OAXiB,IAAbuE,GACF9J,EAAOqE,KAAMwF,GAAQ,GAAM,KAC3B7J,EAAOqE,KAAMwF,GAAQ,EAAK,KAC1B7J,EAAOqE,KAAY,IAAPwF,IACU,KAAbC,GACT9J,EAAOqE,KAAMwF,GAAQ,GAAM,KAC3B7J,EAAOqE,KAAMwF,GAAQ,EAAK,MACJ,KAAbC,GACT9J,EAAOqE,KAAMwF,GAAQ,EAAK,KAGrB,IAAIE,WAAW/J,EACxB,EAqDEgD,UARF,SAAmB8D,GACjB,MAA+C,wBAAxCpG,OAAOtB,UAAU6C,SAASL,KAAKkF,EACxC,EAOE7D,UApDF,SAA8BuC,GAQ5B,IAPA,IAAIxF,EAAS,GACT6J,EAAO,EACLtE,EAAMC,EAAO3E,OACb2B,EAAM+G,EAIHE,EAAM,EAAGA,EAAMlE,EAAKkE,IACtBA,EAAM,GAAM,GAAMA,IACrBzJ,GAAUwC,EAAKqH,GAAQ,GAAM,IAC7B7J,GAAUwC,EAAKqH,GAAQ,GAAM,IAC7B7J,GAAUwC,EAAKqH,GAAQ,EAAK,IAC5B7J,GAAUwC,EAAW,GAAPqH,IAGhBA,GAAQA,GAAQ,GAAKrE,EAAOiE,GAK9B,IAAMO,EAAOzE,EAAM,EAmBnB,OAjBa,IAATyE,GACFhK,GAAUwC,EAAKqH,GAAQ,GAAM,IAC7B7J,GAAUwC,EAAKqH,GAAQ,GAAM,IAC7B7J,GAAUwC,EAAKqH,GAAQ,EAAK,IAC5B7J,GAAUwC,EAAW,GAAPqH,IACI,IAATG,GACThK,GAAUwC,EAAKqH,GAAQ,GAAM,IAC7B7J,GAAUwC,EAAKqH,GAAQ,EAAK,IAC5B7J,GAAUwC,EAAKqH,GAAQ,EAAK,IAC5B7J,GAAUwC,EAAI,KACI,IAATwH,IACThK,GAAUwC,EAAKqH,GAAQ,EAAK,IAC5B7J,GAAUwC,EAAKqH,GAAQ,EAAK,IAC5B7J,GAAUwC,EAAI,IACdxC,GAAUwC,EAAI,KAGTxC,CACT,oCC3GA,IAAMyD,EAAOvB,IAEP+H,EAAkBvJ,OAAOtB,UAAU8K,eACnCC,EAAYzJ,OAAOtB,UAAU6C,gBAmCnCmI,EAAiB,IAAI3G,EAAK,yBAA0B,CAClDd,KAAM,WACNC,QAnCF,SAA0BE,GACxB,GAAa,OAATA,EAAe,OAAO,EAK1B,IAHA,IAAMuH,EAAa,CAAA,EACb7E,EAAS1C,EAENlC,EAAQ,EAAGC,EAAS2E,EAAO3E,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CACtE,IAAM0J,EAAO9E,EAAO5E,GAChB2J,GAAa,EAEjB,GAA6B,oBAAzBJ,EAAUvI,KAAK0I,GAA6B,OAAO,EAEvD,IAAIE,OAAO,EACX,IAAKA,KAAWF,EACd,GAAIL,EAAgBrI,KAAK0I,EAAME,GAAU,CACvC,GAAKD,EACA,OAAO,EADKA,GAAa,CAEhC,CAGF,IAAKA,EAAY,OAAO,EAExB,GAAIN,EAAgBrI,KAAKyI,EAAYG,GAAU,OAAO,EACtD9J,OAAO+J,eAAeJ,EAAYG,EAAS,CAAEpE,OAAO,GACtD,CAEA,OAAO,CACT,EASEvD,UAPF,SAA4BC,GAC1B,OAAgB,OAATA,EAAgBA,EAAO,EAChC,oCCpCA,IAAMW,EAAOvB,IAEPiI,EAAYzJ,OAAOtB,UAAU6C,gBAyCnCyI,EAAiB,IAAIjH,EAAK,0BAA2B,CACnDd,KAAM,WACNC,QAzCF,SAA2BE,GACzB,GAAa,OAATA,EAAe,OAAO,EAM1B,IAJA,IAAM0C,EAAS1C,EAET9C,EAAS,IAAIL,MAAM6F,EAAO3E,QAEvBD,EAAQ,EAAGC,EAAS2E,EAAO3E,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CACtE,IAAM0J,EAAO9E,EAAO5E,GAEpB,GAA6B,oBAAzBuJ,EAAUvI,KAAK0I,GAA6B,OAAO,EAEvD,IAAM3J,EAAOD,OAAOC,KAAK2J,GAEzB,GAAoB,IAAhB3J,EAAKE,OAAc,OAAO,EAE9Bb,EAAOY,GAAS,CAACD,EAAK,GAAI2J,EAAK3J,EAAK,IACtC,CAEA,OAAO,CACT,EAsBEkC,UApBF,SAA6BC,GAC3B,GAAa,OAATA,EAAe,MAAO,GAK1B,IAHA,IAAM0C,EAAS1C,EACT9C,EAAS,IAAIL,MAAM6F,EAAO3E,QAEvBD,EAAQ,EAAGC,EAAS2E,EAAO3E,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CACtE,IAAM0J,EAAO9E,EAAO5E,GAEdD,EAAOD,OAAOC,KAAK2J,GAEzBtK,EAAOY,GAAS,CAACD,EAAK,GAAI2J,EAAK3J,EAAK,IACtC,CAEA,OAAOX,CACT,oCCzCA,IAAMyD,EAAOvB,IAEP+H,EAAkBvJ,OAAOtB,UAAU8K,sBAoBzCS,EAAiB,IAAIlH,EAAK,wBAAyB,CACjDd,KAAM,UACNC,QApBF,SAAyBE,GACvB,GAAa,OAATA,EAAe,OAAO,EAE1B,IAAM0C,EAAS1C,EAEf,IAAA,IAAWhC,KAAO0E,EAChB,GAAIyE,EAAgBrI,KAAK4D,EAAQ1E,IACX,OAAhB0E,EAAO1E,GAAe,OAAO,EAIrC,OAAO,CACT,EASE+B,UAPF,SAA2BC,GACzB,OAAgB,OAATA,EAAgBA,EAAO,CAAA,CAChC,kCCdA8H,EAAiB1I,KAAkB5B,OAAO,CACxC6D,SAAU,CACRT,KACA0B,MAEFhB,SAAU,CACRiB,KACA4C,KACA4C,KACAC,qCCjBQ,SAAA/L,EAAAC,GAAA,OAAAD,EAAA,mBAAAE,QAAA,iBAAAA,OAAAC,SAAA,SAAAF,GAAA,cAAAA,GAAA,SAAAA,GAAA,OAAAA,GAAA,mBAAAC,QAAAD,EAAAG,cAAAF,QAAAD,IAAAC,OAAAG,UAAA,gBAAAJ,CAAA,GAAAA,EAAA,KAEZ,IAAMO,EAAS2C,IACTR,EAAgBgC,IAChBqH,+BCFN,IAAMxL,EAAS2C,IAGf,SAAS8I,EAASC,EAAQC,EAAWC,EAASC,EAAUC,GACtD,IAAIC,EAAO,GACPtB,EAAO,GACLuB,EAAgBC,KAAKC,MAAMJ,EAAgB,GAAK,EAYtD,OAVID,EAAWF,EAAYK,IAEzBL,EAAYE,EAAWG,GADvBD,EAAO,SACqCzK,QAG1CsK,EAAUC,EAAWG,IAEvBJ,EAAUC,EAAWG,GADrBvB,EAAO,QACmCnJ,QAGrC,CACLoE,IAAKqG,EAAOL,EAAO1E,MAAM2E,EAAWC,GAASpD,QAAQ,MAAO,KAAOiC,EACnE0B,IAAKN,EAAWF,EAAYI,EAAKzK,OAErC,CAEA,SAAS8K,EAAU7L,EAAQyF,GACzB,OAAOhG,EAAOM,OAAO,IAAK0F,EAAMzF,EAAOe,QAAUf,CACnD,QAmEA2B,EAjEA,SAAsBJ,EAAMkB,GAG1B,GAFAA,EAAU7B,OAAOsB,OAAOO,GAAW,OAE9BlB,EAAK4J,OAAQ,OAAO,KAEpB1I,EAAQqJ,YAAWrJ,EAAQqJ,UAAY,IACd,iBAAnBrJ,EAAQsJ,WAA6BA,OAAS,GACtB,iBAAxBtJ,EAAQuJ,gBAAkCA,YAAc,GACjC,iBAAvBvJ,EAAQwJ,eAAiCA,WAAa,GAQjE,IANA,IAGItD,EAHEuD,EAAK,eACLC,EAAa,CAAC,GACdC,EAAW,GAEbC,GAAc,EAEV1D,EAAQuD,EAAG1D,KAAKjH,EAAK4J,SAC3BiB,EAAS7H,KAAKoE,EAAM7H,OACpBqL,EAAW5H,KAAKoE,EAAM7H,MAAQ6H,EAAM,GAAG5H,QAEnCQ,EAAK+J,UAAY3C,EAAM7H,OAASuL,EAAc,IAChDA,EAAcF,EAAWpL,OAAS,GAIlCsL,EAAc,IAAGA,EAAcF,EAAWpL,OAAS,GAMvD,IAJA,IAAIb,EAAS,GACPoM,EAAeZ,KAAKa,IAAIhL,EAAKE,KAAOgB,EAAQwJ,WAAYG,EAASrL,QAAQoB,WAAWpB,OACpFwK,EAAgB9I,EAAQqJ,WAAarJ,EAAQsJ,OAASO,EAAe,GAElEE,EAAI,EAAGA,GAAK/J,EAAQuJ,eACvBK,EAAcG,EAAI,GADkBA,IAAK,CAE7C,IAAM/K,EAAOyJ,EACX3J,EAAK4J,OACLgB,EAAWE,EAAcG,GACzBJ,EAASC,EAAcG,GACvBjL,EAAK+J,UAAYa,EAAWE,GAAeF,EAAWE,EAAcG,IACpEjB,GAEFrL,EAAST,EAAOM,OAAO,IAAK0C,EAAQsJ,QAAUF,GAAUtK,EAAKE,KAAO+K,EAAI,GAAGrK,WAAYmK,GACrF,MAAQ7K,EAAK0D,IAAM,KAAOjF,CAC9B,CAEA,IAAMuB,EAAOyJ,EAAQ3J,EAAK4J,OAAQgB,EAAWE,GAAcD,EAASC,GAAc9K,EAAK+J,SAAUC,GACjGrL,GAAUT,EAAOM,OAAO,IAAK0C,EAAQsJ,QAAUF,GAAUtK,EAAKE,KAAO,GAAGU,WAAYmK,GAClF,MAAQ7K,EAAK0D,IAAM,KACrBjF,GAAUT,EAAOM,OAAO,IAAK0C,EAAQsJ,OAASO,EAAe,EAAI7K,EAAKmK,KAAO,MAE7E,IAAA,IAASY,EAAI,EAAGA,GAAK/J,EAAQwJ,cACvBI,EAAcG,GAAKJ,EAASrL,QADOyL,IAAK,CAE5C,IAAM/K,EAAOyJ,EACX3J,EAAK4J,OACLgB,EAAWE,EAAcG,GACzBJ,EAASC,EAAcG,GACvBjL,EAAK+J,UAAYa,EAAWE,GAAeF,EAAWE,EAAcG,IACpEjB,GAEFrL,GAAUT,EAAOM,OAAO,IAAK0C,EAAQsJ,QAAUF,GAAUtK,EAAKE,KAAO+K,EAAI,GAAGrK,WAAYmK,GACtF,MAAQ7K,EAAK0D,IAAM,IACvB,CAEA,OAAOjF,EAAO+H,QAAQ,MAAO,GAC/B,EDzFoB3C,GACdmH,EAAiBlH,KAEjB4E,EAAkBvJ,OAAOtB,UAAU8K,eAYnCsC,EAAwB,sIACxBC,EAAgC,qBAEhCC,EAA0B,YAE1BC,EAAqB,6BAErBC,EAAkB,yEAExB,SAASC,EAAQ/F,GAAO,OAAOpG,OAAOtB,UAAU6C,SAASL,KAAKkF,EAAK,CAEnE,SAASgG,EAAO9G,GACd,OAAc,KAANA,GAA8B,KAANA,CAClC,CAEA,SAAS+G,EAAc/G,GACrB,OAAc,IAANA,GAA+B,KAANA,CACnC,CAEA,SAASgH,EAAWhH,GAClB,OAAc,IAANA,GACM,KAANA,GACM,KAANA,GACM,KAANA,CACV,CAEA,SAASiH,EAAiBjH,GACxB,OAAa,KAANA,GACM,KAANA,GACM,KAANA,GACM,MAANA,GACM,MAANA,CACT,CAEA,SAASkH,EAAalH,GACpB,GAAKA,GAAK,IAAiBA,GAAK,GAC9B,OAAOA,EAAI,GAGb,IAAMmH,EAAS,GAAJnH,EAEX,OAAKmH,GAAM,IAAiBA,GAAM,IACzBA,EAAK,GAAO,IAGd,CACT,CAEA,SAASC,EAAepH,GACtB,OAAU,MAANA,EAA4B,EACtB,MAANA,EAA4B,EACtB,KAANA,EAA4B,EACzB,CACT,CAEA,SAASqH,EAAiBrH,GACxB,OAAKA,GAAK,IAAiBA,GAAK,GACvBA,EAAI,IAGN,CACT,CAEA,SAASsH,EAAsBtH,GAC7B,OAAQA,GACN,KAAK,GAAa,MAAO,KACzB,KAAK,GAAa,MAAO,IACzB,KAAK,GAAa,MAAO,KACzB,KAAK,IACL,KAAK,EAAe,MAAO,KAC3B,KAAK,IAAa,MAAO,KACzB,KAAK,IAAa,MAAO,KACzB,KAAK,IAAa,MAAO,KACzB,KAAK,IAAa,MAAO,KACzB,KAAK,IAAa,MAAO,IACzB,KAAK,GAAiB,MAAO,IAC7B,KAAK,GAAa,MAAO,IACzB,KAAK,GAAa,MAAO,IACzB,KAAK,GAAa,MAAO,KACzB,KAAK,GAAa,MAAO,IACzB,KAAK,GAAa,MAAO,IACzB,KAAK,GAAa,MAAO,SACzB,KAAK,GAAa,MAAO,SACzB,QAAS,MAAO,GAEpB,CAEA,SAASuH,EAAmBvH,GAC1B,OAAIA,GAAK,MACAxC,OAAOgK,aAAaxH,GAItBxC,OAAOgK,aACa,OAAvBxH,EAAI,OAAa,IACS,OAA1BA,EAAI,MAAY,MAEtB,CAIA,SAASyH,EAAajI,EAAQ1E,EAAKsF,GAErB,cAARtF,EACFJ,OAAO+J,eAAejF,EAAQ1E,EAAK,CACjC4M,cAAc,EACdC,YAAY,EACZC,UAAU,EACVxH,UAGFZ,EAAO1E,GAAOsF,CAElB,CAIA,IAFA,IAAMyH,EAAoB,IAAIlO,MAAM,KAC9BmO,EAAkB,IAAInO,MAAM,KACzB2M,EAAI,EAAGA,EAAI,IAAKA,IACvBuB,EAAkBvB,GAAKgB,EAAqBhB,GAAK,EAAI,EACrDwB,EAAgBxB,GAAKgB,EAAqBhB,GAG5C,SAASyB,EAAOnE,EAAOrH,GACrBV,KAAK+H,MAAQA,EAEb/H,KAAKmM,SAAWzL,EAAkB,UAAK,KACvCV,KAAK+B,OAASrB,EAAgB,QAAKgK,EACnC1K,KAAKoM,UAAY1L,EAAmB,WAAK,KAGzCV,KAAKqM,OAAS3L,EAAgB,SAAK,EAEnCV,KAAKmG,KAAOzF,EAAc,OAAK,EAC/BV,KAAKsM,SAAW5L,EAAkB,UAAK,KACvCV,KAAKuM,SAA0C,iBAAxB7L,EAAkB,SAAiBA,EAAkB,SAAI,IAChFV,KAAKwM,kBAA4D,iBAAjC9L,EAA2B,kBAAiBA,EAA2B,kBAAI,IAE3GV,KAAKyM,cAAgBzM,KAAK+B,OAAOY,iBACjC3C,KAAK0M,QAAU1M,KAAK+B,OAAOc,gBAE3B7C,KAAKhB,OAAS+I,EAAM/I,OACpBgB,KAAKuJ,SAAW,EAChBvJ,KAAKN,KAAO,EACZM,KAAKqJ,UAAY,EACjBrJ,KAAK2M,WAAa,EAClB3M,KAAK4M,MAAQ,EACb5M,KAAK6M,eAAiB,EAItB7M,KAAK8M,gBAAiB,EAEtB9M,KAAK+M,UAAY,GACjB/M,KAAKgN,sBAAwB,EAW/B,CAEA,SAASC,EAAeC,EAAO5N,GAC7B,IAAME,EAAO,CACXC,KAAMyN,EAAMf,SACZ/C,OAAQ8D,EAAMnF,MAAMrD,MAAM,GAAG,GAC7B6E,SAAU2D,EAAM3D,SAChB7J,KAAMwN,EAAMxN,KACZC,OAAQuN,EAAM3D,SAAW2D,EAAM7D,WAKjC,OAFA7J,EAAKI,QAAUsJ,EAAY1J,GAEpB,IAAIK,EAAcP,EAASE,EACpC,CAEA,SAAS2N,EAAYD,EAAO5N,GAC1B,MAAM2N,EAAcC,EAAO5N,EAC7B,CAEA,SAAS8N,EAAcF,EAAO5N,GACxB4N,EAAMd,WACRc,EAAMd,UAAUrM,KAAK,KAAMkN,EAAcC,EAAO5N,GAEpD,CAEA,SAAS+N,EAAaH,EAAOzN,EAAM8E,GACjC,IAAM+I,EAAeJ,EAAMF,sBAE3B,GAA4B,IAAxBM,EAAatO,OAAc,CAC7B,IAAMuO,EAAcD,EAAaA,EAAatO,OAAS,GAElDoJ,EAAgBrI,KAAKwN,EAAa9N,KACrC8N,EAAY9N,GAAQ,CAClB+N,QAASpF,EAAgBrI,KAAKmN,EAAMO,UAAWhO,GAC/C8E,MAAO2I,EAAMO,UAAUhO,IAG7B,CAEAyN,EAAMO,UAAUhO,GAAQ8E,CAC1B,CAuCA,SAASmJ,EAAeR,GACtB,MAAO,CACL3D,SAAU2D,EAAM3D,SAChB7J,KAAMwN,EAAMxN,KACZ2J,UAAW6D,EAAM7D,UACjBsD,WAAYO,EAAMP,WAClBG,eAAgBI,EAAMJ,eACtBrM,IAAKyM,EAAMzM,IACXkN,OAAQT,EAAMS,OACd7M,KAAMoM,EAAMpM,KACZ3C,OAAQ+O,EAAM/O,OAElB,CAEA,SAASyP,EAAcV,EAAOW,GAC5BX,EAAM3D,SAAWsE,EAAStE,SAC1B2D,EAAMxN,KAAOmO,EAASnO,KACtBwN,EAAM7D,UAAYwE,EAASxE,UAC3B6D,EAAMP,WAAakB,EAASlB,WAC5BO,EAAMJ,eAAiBe,EAASf,eAChCI,EAAMzM,IAAMoN,EAASpN,IACrByM,EAAMS,OAASE,EAASF,OACxBT,EAAMpM,KAAO+M,EAAS/M,KACtBoM,EAAM/O,OAAS0P,EAAS1P,MAC1B,CAEA,IAAM2P,EAAoB,CAExBC,KAAM,SAA8Bb,EAAOzN,EAAMuO,GACzB,OAAlBd,EAAMe,SACRd,EAAWD,EAAO,kCAGA,IAAhBc,EAAKhP,QACPmO,EAAWD,EAAO,+CAGpB,IAAMtG,EAAQ,uBAAuBH,KAAKuH,EAAK,IAEjC,OAAVpH,GACFuG,EAAWD,EAAO,6CAGpB,IAAMgB,EAAQvJ,SAASiC,EAAM,GAAI,IAC3BuH,EAAQxJ,SAASiC,EAAM,GAAI,IAEnB,IAAVsH,GACFf,EAAWD,EAAO,6CAGpBA,EAAMe,QAAUD,EAAK,GACrBd,EAAMkB,gBAAmBD,EAAQ,EAEnB,IAAVA,GAAyB,IAAVA,GACjBf,EAAaF,EAAO,6CAIxBmB,IAAK,SAA6BnB,EAAOzN,EAAMuO,GAC7C,IAAIM,EAEgB,IAAhBN,EAAKhP,QACPmO,EAAWD,EAAO,+CAGpB,IAAMqB,EAASP,EAAK,GACpBM,EAASN,EAAK,GAETlD,EAAmBnF,KAAK4I,IAC3BpB,EAAWD,EAAO,+DAGhB9E,EAAgBrI,KAAKmN,EAAMsB,OAAQD,IACrCpB,EAAWD,EAAO,8CAAgDqB,EAAS,gBAGxExD,EAAgBpF,KAAK2I,IACxBnB,EAAWD,EAAO,gEAGpB,IACEoB,EAASG,mBAAmBH,SACrBI,GACPvB,EAAWD,EAAO,4BAA8BoB,EAClD,CAEApB,EAAMsB,OAAOD,GAAUD,CACzB,GAGF,SAASK,EAAgBzB,EAAO0B,EAAOC,EAAKC,GAC1C,GAAIF,EAAQC,EAAK,CACf,IAAME,EAAU7B,EAAMnF,MAAMrD,MAAMkK,EAAOC,GAEzC,GAAIC,EACF,IAAA,IAASE,EAAY,EAAGC,EAAUF,EAAQ/P,OAAQgQ,EAAYC,EAASD,GAAa,EAAG,CACrF,IAAME,EAAaH,EAAQhK,WAAWiK,GACjB,IAAfE,GACCA,GAAc,IAAQA,GAAc,SACzC/B,EAAWD,EAAO,gCAEtB,MACSvC,EAAsBhF,KAAKoJ,IACpC5B,EAAWD,EAAO,gDAGpBA,EAAM/O,QAAU4Q,CAClB,CACF,CAEA,SAASI,EAAejC,EAAOkC,EAAazQ,EAAQ0Q,GAC7C3R,EAAOC,SAASgB,IACnBwO,EAAWD,EAAO,qEAKpB,IAFA,IAAMtO,EAAaC,OAAOC,KAAKH,GAEtBI,EAAQ,EAAGuQ,EAAW1Q,EAAWI,OAAQD,EAAQuQ,EAAUvQ,GAAS,EAAG,CAC9E,IAAME,EAAML,EAAWG,IAES,IAA5BmO,EAAMV,qBAA8BU,EAAML,eAAiBK,EAAMV,mBACnEW,EAAWD,EAAO,0CAA4CA,EAAMV,kBAAoB,KAGrFpE,EAAgBrI,KAAKqP,EAAanQ,KACrC2M,EAAYwD,EAAanQ,EAAKN,EAAOM,IACrCoQ,EAAgBpQ,IAAO,EAE3B,CACF,CAEA,SAASsQ,EAAkBrC,EAAO6B,EAASM,EAAiBG,EAAQC,EAASC,EAC3EC,EAAWC,EAAgBC,GAI3B,GAAI/R,MAAMC,QAAQ0R,GAGhB,IAAA,IAAS1Q,EAAQ,EAAGuQ,GAFpBG,EAAU3R,MAAMP,UAAUmH,MAAM3E,KAAK0P,IAEEzQ,OAAQD,EAAQuQ,EAAUvQ,GAAS,EACpEjB,MAAMC,QAAQ0R,EAAQ1Q,KACxBoO,EAAWD,EAAO,+CAGG,WAAnBhQ,EAAOuS,IAAmD,oBAA3BzE,EAAOyE,EAAQ1Q,MAChD0Q,EAAQ1Q,GAAS,mBAkBvB,GAVuB,WAAnB7B,EAAOuS,IAA4C,oBAApBzE,EAAOyE,KACxCA,EAAU,mBAGZA,EAAU9N,OAAO8N,GAED,OAAZV,IACFA,EAAU,CAAA,GAGG,4BAAXS,EACF,GAAI1R,MAAMC,QAAQ2R,GAChB,IAAA,IAAS3Q,EAAQ,EAAGuQ,EAAWI,EAAU1Q,OAAQD,EAAQuQ,EAAUvQ,GAAS,EAC1EoQ,EAAcjC,EAAO6B,EAASW,EAAU3Q,GAAQsQ,QAGlDF,EAAcjC,EAAO6B,EAASW,EAAWL,QAGtCnC,EAAM/G,MACNiC,EAAgBrI,KAAKsP,EAAiBI,KACvCrH,EAAgBrI,KAAKgP,EAASU,KAChCvC,EAAMxN,KAAOiQ,GAAazC,EAAMxN,KAChCwN,EAAM7D,UAAYuG,GAAkB1C,EAAM7D,UAC1C6D,EAAM3D,SAAWsG,GAAY3C,EAAM3D,SACnC4D,EAAWD,EAAO,2BAGpBtB,EAAYmD,EAASU,EAASC,UACvBL,EAAgBI,GAGzB,OAAOV,CACT,CAEA,SAASe,EAAe5C,GACtB,IAAMzI,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAE7B,KAAP9E,EACFyI,EAAM3D,WACU,KAAP9E,GACTyI,EAAM3D,WACyC,KAA3C2D,EAAMnF,MAAMhD,WAAWmI,EAAM3D,WAC/B2D,EAAM3D,YAGR4D,EAAWD,EAAO,4BAGpBA,EAAMxN,MAAQ,EACdwN,EAAM7D,UAAY6D,EAAM3D,SACxB2D,EAAMJ,gBAAiB,CACzB,CAEA,SAASiD,EAAqB7C,EAAO8C,EAAeC,GAIlD,IAHA,IAAIC,EAAa,EACbzL,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAExB,IAAP9E,GAAU,CACf,KAAOyG,EAAazG,IACP,IAAPA,IAAiD,IAAzByI,EAAMJ,iBAChCI,EAAMJ,eAAiBI,EAAM3D,UAE/B9E,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGtC,GAAIyG,GAAwB,KAAPvL,EACnB,GACEA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,gBACtB,KAAP9E,GAA8B,KAAPA,GAA8B,IAAPA,GAGzD,IAAIwG,EAAMxG,GAYR,MALA,IANAqL,EAAc5C,GAEdzI,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAClC2G,IACAhD,EAAMP,WAAa,EAEL,KAAPlI,GACLyI,EAAMP,aACNlI,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,SAK1C,CAMA,OAJoB,IAAhB0G,GAAqC,IAAfC,GAAoBhD,EAAMP,WAAasD,GAC/D7C,EAAaF,EAAO,yBAGfgD,CACT,CAEA,SAASC,EAAuBjD,GAC9B,IAAI8B,EAAY9B,EAAM3D,SAClB9E,EAAKyI,EAAMnF,MAAMhD,WAAWiK,GAIhC,QAAY,KAAPvK,GAA6B,KAAPA,GACvBA,IAAOyI,EAAMnF,MAAMhD,WAAWiK,EAAY,IAC1CvK,IAAOyI,EAAMnF,MAAMhD,WAAWiK,EAAY,KAC5CA,GAAa,EAIF,KAFXvK,EAAKyI,EAAMnF,MAAMhD,WAAWiK,MAEZ7D,EAAU1G,IAM9B,CAEA,SAAS2L,EAAkBlD,EAAOhP,GAClB,IAAVA,EACFgP,EAAM/O,QAAU,IACPD,EAAQ,IACjBgP,EAAM/O,QAAUT,EAAOM,OAAO,KAAME,EAAQ,GAEhD,CAwdA,SAASmS,EAAmBnD,EAAOoD,GACjC,IAAMC,EAAOrD,EAAMzM,IACb+P,EAAUtD,EAAMS,OAChBoB,EAAU,GACZ0B,GAAW,EAIf,IAA6B,IAAzBvD,EAAMJ,eAAuB,OAAO,EAEnB,OAAjBI,EAAMS,QACRN,EAAYH,EAAOA,EAAMS,OAAQoB,GAKnC,IAFA,IAAItK,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAExB,IAAP9E,KACwB,IAAzByI,EAAMJ,iBACRI,EAAM3D,SAAW2D,EAAMJ,eACvBK,EAAWD,EAAO,mDAGT,KAAPzI,IANW,CAYf,IAAK0G,EAFa+B,EAAMnF,MAAMhD,WAAWmI,EAAM3D,SAAW,IAGxD,MAMF,GAHAkH,GAAW,EACXvD,EAAM3D,WAEFwG,EAAoB7C,GAAO,GAAM,IAC/BA,EAAMP,YAAc2D,EACtBvB,EAAQvM,KAAK,MACbiC,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,cAHtC,CAQA,IAAMmH,EAAQxD,EAAMxN,KAOpB,GANAiR,EAAYzD,EAAOoD,EAnhCE,GAmhC4B,GAAO,GACxDvB,EAAQvM,KAAK0K,EAAM/O,QACnB4R,EAAoB7C,GAAO,GAAM,GAEjCzI,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,WAE7B2D,EAAMxN,OAASgR,GAASxD,EAAMP,WAAa2D,IAAuB,IAAP7L,EAC9D0I,EAAWD,EAAO,4CACpB,GAAWA,EAAMP,WAAa2D,EAC5B,KAZF,CAcF,CAEA,QAAIG,IACFvD,EAAMzM,IAAM8P,EACZrD,EAAMS,OAAS6C,EACftD,EAAMpM,KAAO,WACboM,EAAM/O,OAAS4Q,GACR,EAGX,CAEA,SAAS6B,EAAkB1D,EAAOoD,EAAYO,GAC5C,IAAIC,EACAC,EACAC,EACAC,EACEV,EAAOrD,EAAMzM,IACb+P,EAAUtD,EAAMS,OAChBoB,EAAU,CAAA,EACVM,EAAkBxQ,OAAOsB,OAAO,MAClCqP,EAAS,KACTC,EAAU,KACVC,EAAY,KACZwB,GAAgB,EAChBT,GAAW,EAIf,IAA6B,IAAzBvD,EAAMJ,eAAuB,OAAO,EAEnB,OAAjBI,EAAMS,QACRN,EAAYH,EAAOA,EAAMS,OAAQoB,GAKnC,IAFA,IAAItK,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAExB,IAAP9E,GAAU,CACVyM,IAA0C,IAAzBhE,EAAMJ,iBAC1BI,EAAM3D,SAAW2D,EAAMJ,eACvBK,EAAWD,EAAO,mDAGpB,IAAMiE,EAAYjE,EAAMnF,MAAMhD,WAAWmI,EAAM3D,SAAW,GACpDmH,EAAQxD,EAAMxN,KAMpB,GAAY,KAAP+E,GAA6B,KAAPA,IAAuB0G,EAAUgG,GAwBrD,CAKL,GAJAJ,EAAW7D,EAAMxN,KACjBsR,EAAgB9D,EAAM7D,UACtB4H,EAAU/D,EAAM3D,UAEXoH,EAAYzD,EAAO2D,EA9mCL,GA8mCmC,GAAO,GAG3D,MAGF,GAAI3D,EAAMxN,OAASgR,EAAO,CAGxB,IAFAjM,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAE3B2B,EAAazG,IAClBA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGtC,GAAW,KAAP9E,EAGG0G,EAFL1G,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,YAGlC4D,EAAWD,EAAO,2FAGhBgE,IACF3B,EAAiBrC,EAAO6B,EAASM,EAAiBG,EAAQC,EAAS,KAAMsB,EAAUC,EAAeC,GAClGzB,EAASC,EAAUC,EAAY,MAGjCe,GAAW,EACXS,GAAgB,EAChBJ,GAAe,EACftB,EAAStC,EAAMzM,IACfgP,EAAUvC,EAAM/O,gBACPsS,EAKT,OAFAvD,EAAMzM,IAAM8P,EACZrD,EAAMS,OAAS6C,GACR,EAJPrD,EAAWD,EAAO,2DAKpB,WACSuD,EAKT,OAFAvD,EAAMzM,IAAM8P,EACZrD,EAAMS,OAAS6C,GACR,EAJPrD,EAAWD,EAAO,iFAKpB,CACF,MAxEa,KAAPzI,GACEyM,IACF3B,EAAiBrC,EAAO6B,EAASM,EAAiBG,EAAQC,EAAS,KAAMsB,EAAUC,EAAeC,GAClGzB,EAASC,EAAUC,EAAY,MAGjCe,GAAW,EACXS,GAAgB,EAChBJ,GAAe,GACNI,GAETA,GAAgB,EAChBJ,GAAe,GAEf3D,EAAWD,EAAO,qGAGpBA,EAAM3D,UAAY,EAClB9E,EAAK0M,EAmFP,IAxBIjE,EAAMxN,OAASgR,GAASxD,EAAMP,WAAa2D,KACzCY,IACFH,EAAW7D,EAAMxN,KACjBsR,EAAgB9D,EAAM7D,UACtB4H,EAAU/D,EAAM3D,UAGdoH,EAAYzD,EAAOoD,EApqCH,GAoqCkC,EAAMQ,KACtDI,EACFzB,EAAUvC,EAAM/O,OAEhBuR,EAAYxC,EAAM/O,QAIjB+S,IACH3B,EAAiBrC,EAAO6B,EAASM,EAAiBG,EAAQC,EAASC,EAAWqB,EAAUC,EAAeC,GACvGzB,EAASC,EAAUC,EAAY,MAGjCK,EAAoB7C,GAAO,GAAM,GACjCzI,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,YAG/B2D,EAAMxN,OAASgR,GAASxD,EAAMP,WAAa2D,IAAuB,IAAP7L,EAC9D0I,EAAWD,EAAO,2CACpB,GAAWA,EAAMP,WAAa2D,EAC5B,KAEJ,CAmBA,OAZIY,GACF3B,EAAiBrC,EAAO6B,EAASM,EAAiBG,EAAQC,EAAS,KAAMsB,EAAUC,EAAeC,GAIhGR,IACFvD,EAAMzM,IAAM8P,EACZrD,EAAMS,OAAS6C,EACftD,EAAMpM,KAAO,UACboM,EAAM/O,OAAS4Q,GAGV0B,CACT,CAEA,SAASW,EAAiBlE,GACxB,IAEImE,EACAC,EAHAC,GAAa,EACbC,GAAU,EAIV/M,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAEtC,GAAW,KAAP9E,EAAoB,OAAO,EAEb,OAAdyI,EAAMzM,KACR0M,EAAWD,EAAO,iCAKT,MAFXzI,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,YAGlCgI,GAAa,EACb9M,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,WACpB,KAAP9E,GACT+M,GAAU,EACVH,EAAY,KACZ5M,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,WAEpC8H,EAAY,IAGd,IAAIrC,EAAY9B,EAAM3D,SAEtB,GAAIgI,EAAY,CACd,GAAK9M,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,gBAC3B,IAAP9E,GAAmB,KAAPA,GAEfyI,EAAM3D,SAAW2D,EAAMlO,QACzBsS,EAAUpE,EAAMnF,MAAMrD,MAAMsK,EAAW9B,EAAM3D,UAC7C9E,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,WAEpC4D,EAAWD,EAAO,qDAEtB,KAAO,CACL,KAAc,IAAPzI,IAAa0G,EAAU1G,IACjB,KAAPA,IACG+M,EAUHrE,EAAWD,EAAO,gDATlBmE,EAAYnE,EAAMnF,MAAMrD,MAAMsK,EAAY,EAAG9B,EAAM3D,SAAW,GAEzDuB,EAAmBnF,KAAK0L,IAC3BlE,EAAWD,EAAO,mDAGpBsE,GAAU,EACVxC,EAAY9B,EAAM3D,SAAW,IAMjC9E,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGtC+H,EAAUpE,EAAMnF,MAAMrD,MAAMsK,EAAW9B,EAAM3D,UAEzCsB,EAAwBlF,KAAK2L,IAC/BnE,EAAWD,EAAO,sDAEtB,CAEIoE,IAAYvG,EAAgBpF,KAAK2L,IACnCnE,EAAWD,EAAO,4CAA8CoE,GAGlE,IACEA,EAAU7C,mBAAmB6C,SACtB5C,GACPvB,EAAWD,EAAO,0BAA4BoE,EAChD,CAcA,OAZIC,EACFrE,EAAMzM,IAAM6Q,EACHlJ,EAAgBrI,KAAKmN,EAAMsB,OAAQ6C,GAC5CnE,EAAMzM,IAAMyM,EAAMsB,OAAO6C,GAAaC,EACf,MAAdD,EACTnE,EAAMzM,IAAM,IAAM6Q,EACK,OAAdD,EACTnE,EAAMzM,IAAM,qBAAuB6Q,EAEnCnE,EAAWD,EAAO,0BAA4BmE,EAAY,MAGrD,CACT,CAEA,SAASI,EAAoBvE,GAC3B,IAAIzI,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAEtC,GAAW,KAAP9E,EAAoB,OAAO,EAEV,OAAjByI,EAAMS,QACRR,EAAWD,EAAO,qCAGpBzI,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGpC,IAFA,IAAMyF,EAAY9B,EAAM3D,SAEV,IAAP9E,IAAa0G,EAAU1G,KAAQ2G,EAAgB3G,IACpDA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAQtC,OALI2D,EAAM3D,WAAayF,GACrB7B,EAAWD,EAAO,8DAGpBA,EAAMS,OAAST,EAAMnF,MAAMrD,MAAMsK,EAAW9B,EAAM3D,WAC3C,CACT,CA6BA,SAASmI,EAAiCxE,EAAOyE,EAAerB,EAAYO,GAC1E,IAAMe,EAAgBlE,EAAcR,GAYpC,OArpCF,SAAiCA,GAC/BA,EAAMF,sBAAsBxK,KAAK3D,OAAOsB,OAAO,MACjD,CAyoCE0R,CAAuB3E,GACvBU,EAAaV,EAAOyE,GAIpBzE,EAAMzM,IAAM,KACZyM,EAAMS,OAAS,KACfT,EAAMpM,KAAO,KACboM,EAAM/O,OAAS,KAEXyS,EAAiB1D,EAAOoD,EAAYO,IAA8B,YAAf3D,EAAMpM,MAjpC/D,SAAkCoM,GAChC,IAAMK,EAAcL,EAAMF,sBAAsB8E,MAC1CxE,EAAeJ,EAAMF,sBAE3B,GAA4B,IAAxBM,EAAatO,OAKjB,IAHA,IAAM+S,EAASzE,EAAaA,EAAatO,OAAS,GAC5CgT,EAAQnT,OAAOC,KAAKyO,GAEjBxO,EAAQ,EAAGC,EAASgT,EAAMhT,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CACrE,IAAMU,EAAOuS,EAAMjT,GAEdqJ,EAAgBrI,KAAKgS,EAAQtS,KAChCsS,EAAOtS,GAAQ8N,EAAY9N,GAE/B,CACF,CAkoCIwS,CAAwB/E,IACjB,IAjoCX,SAAoCA,GAIlC,IAHA,IAAMK,EAAcL,EAAMF,sBAAsB8E,MAC1CE,EAAQnT,OAAOC,KAAKyO,GAEjBxO,EAAQiT,EAAMhT,OAAS,EAAGD,GAAS,EAAGA,GAAS,EAAG,CACzD,IAAMmT,EAAQ3E,EAAYyE,EAAMjT,IAE5BmT,EAAM1E,QACRN,EAAMO,UAAUuE,EAAMjT,IAAUmT,EAAM3N,aAE/B2I,EAAMO,UAAUuE,EAAMjT,GAEjC,CACF,CAunCEoT,CAA0BjF,GAC1BU,EAAaV,EAAO0E,IACb,EACT,CAEA,SAASjB,EAAazD,EAAOkF,EAAcC,EAAaC,EAAaxB,GACnE,IAAIyB,EACAC,EAKAhS,EACAqQ,EACA4B,EANAC,EAAe,EACfC,GAAY,EACZC,GAAa,EACbjB,EAAgB,KAKhBzE,EAAMN,OAASM,EAAMX,UACvBY,EAAWD,EAAO,8BAAgCA,EAAMX,SAAW,KAGrEW,EAAMN,OAAS,EAEQ,OAAnBM,EAAMZ,UACRY,EAAMZ,SAAS,OAAQY,GAGzBA,EAAMzM,IAAM,KACZyM,EAAMS,OAAS,KACfT,EAAMpM,KAAO,KACboM,EAAM/O,OAAS,KAEf,IAAM0U,EAAmBN,EAAoBC,EA/4CrB,IAg5CAH,GAj5CD,IAk5CAA,EAgBvB,GAdIC,GACEvC,EAAoB7C,GAAO,GAAM,KACnCyF,GAAY,EAERzF,EAAMP,WAAayF,EACrBM,EAAe,EACNxF,EAAMP,aAAeyF,EAC9BM,EAAe,EACNxF,EAAMP,WAAayF,IAC5BM,GAAe,IAKA,IAAjBA,EACF,OAAa,CACX,IAAMjO,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAClCuJ,EAAgBpF,EAAcR,GAIpC,GAAIyF,IACS,KAAPlO,GAAoC,OAAdyI,EAAMzM,KACrB,KAAPgE,GAAuC,OAAjByI,EAAMS,QAChC,MAGF,IAAKyD,EAAgBlE,KAAWuE,EAAmBvE,GACjD,MAGoB,OAAlByE,IACFA,EAAgBmB,GAGd/C,EAAoB7C,GAAO,GAAM,IACnCyF,GAAY,EACZH,EAAwBK,EAEpB3F,EAAMP,WAAayF,EACrBM,EAAe,EACNxF,EAAMP,aAAeyF,EAC9BM,EAAe,EACNxF,EAAMP,WAAayF,IAC5BM,GAAe,IAGjBF,GAAwB,CAE5B,CAOF,GAJIA,IACFA,EAAwBG,GAAa7B,GAGlB,IAAjB4B,GA38CoB,IA28CwBL,EAS9C,GAPExB,EAh9CkB,IA+8CIwB,GA98CH,IA88CuCA,EAC7CD,EAEAA,EAAe,EAG9BK,EAAcvF,EAAM3D,SAAW2D,EAAM7D,UAEhB,IAAjBqJ,EACF,GAAKF,IACAnC,EAAkBnD,EAAOuF,IAAgB7B,EAAiB1D,EAAOuF,EAAa5B,KA5uBzF,SAA6B3D,EAAOoD,GAClC,IACII,EACAqC,EACAC,EAEAjE,EAEAkE,EACAC,EACAC,EACAC,EAEA3D,EACAD,EACAE,EAdA2D,GAAW,EAIT9C,EAAOrD,EAAMzM,IAEb+P,EAAUtD,EAAMS,OAKhB0B,EAAkBxQ,OAAOsB,OAAO,MAKlCsE,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAEtC,GAAW,KAAP9E,EACFwO,EAAa,GACbG,GAAY,EACZrE,EAAU,OACZ,IAAkB,MAAPtK,EAKT,OAAO,EAJPwO,EAAa,IACbG,GAAY,EACZrE,EAAU,CAAA,CAGZ,CAQA,IANqB,OAAjB7B,EAAMS,QACRN,EAAYH,EAAOA,EAAMS,OAAQoB,GAGnCtK,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAEtB,IAAP9E,GAAU,CAKf,GAJAsL,EAAoB7C,GAAO,EAAMoD,IAEjC7L,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,aAEvB0J,EAMT,OALA/F,EAAM3D,WACN2D,EAAMzM,IAAM8P,EACZrD,EAAMS,OAAS6C,EACftD,EAAMpM,KAAOsS,EAAY,UAAY,WACrClG,EAAM/O,OAAS4Q,GACR,EACGsE,EAEM,KAAP5O,GAET0I,EAAWD,EAAO,4CAHlBC,EAAWD,EAAO,gDAMDwC,EAAY,KAC/BwD,EAASC,GAAiB,EAEf,KAAP1O,GAGE0G,EAFc+B,EAAMnF,MAAMhD,WAAWmI,EAAM3D,SAAW,MAGxD2J,EAASC,GAAiB,EAC1BjG,EAAM3D,WACNwG,EAAoB7C,GAAO,EAAMoD,IAIrCI,EAAQxD,EAAMxN,KACdqT,EAAa7F,EAAM7D,UACnB2J,EAAO9F,EAAM3D,SACboH,EAAYzD,EAAOoD,EArzBC,GAqzB4B,GAAO,GACvDd,EAAStC,EAAMzM,IACfgP,EAAUvC,EAAM/O,OAChB4R,EAAoB7C,GAAO,EAAMoD,GAEjC7L,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,WAE7B4J,GAAkBjG,EAAMxN,OAASgR,GAAiB,KAAPjM,IAC9CyO,GAAS,EACTzO,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UACpCwG,EAAoB7C,GAAO,EAAMoD,GACjCK,EAAYzD,EAAOoD,EAh0BD,GAg0B8B,GAAO,GACvDZ,EAAYxC,EAAM/O,QAGhBiV,EACF7D,EAAiBrC,EAAO6B,EAASM,EAAiBG,EAAQC,EAASC,EAAWgB,EAAOqC,EAAYC,GACxFE,EACTnE,EAAQvM,KAAK+M,EAAiBrC,EAAO,KAAMmC,EAAiBG,EAAQC,EAASC,EAAWgB,EAAOqC,EAAYC,IAE3GjE,EAAQvM,KAAKiN,GAGfM,EAAoB7C,GAAO,EAAMoD,GAItB,MAFX7L,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,YAGhC8J,GAAW,EACX5O,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,WAEpC8J,GAAW,CAEf,CAEAlG,EAAWD,EAAO,wDACpB,CAioBUoG,CAAmBpG,EAAO2D,GAC5B+B,GAAa,MACR,CACL,IAAMnO,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAElB,OAAlBoI,GAA0BkB,IAAqBL,GACxC,MAAP/N,GAA6B,KAAPA,GACtBiN,EACExE,EACAyE,EACAA,EAAcpI,SAAWoI,EAActI,UACvCwH,IAGM0B,GA7oBpB,SAA0BrF,EAAOoD,GAC/B,IAAIiD,EAOAC,EANAC,EAx1BgB,EAy1BhBC,GAAiB,EACjBC,GAAiB,EACjBC,EAAatD,EACbuD,EAAa,EACbC,GAAiB,EAGjBrP,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAEtC,GAAW,MAAP9E,EACF8O,GAAU,MACZ,IAAkB,KAAP9O,EAGT,OAAO,EAFP8O,GAAU,CAGZ,CAKA,IAHArG,EAAMpM,KAAO,SACboM,EAAM/O,OAAS,GAED,IAAPsG,GAGL,GAAW,MAFXA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,YAEH,KAAP9E,EAh3BR,IAi3BMgP,EACpBA,EAAmB,KAAPhP,EAh3BE,EADC,EAm3Bf0I,EAAWD,EAAO,mDAEVsG,EAAMhI,EAAgB/G,KAAQ,GAUxC,MATY,IAAR+O,EACFrG,EAAWD,EAAO,gFACRyG,EAIVxG,EAAWD,EAAO,8CAHlB0G,EAAatD,EAAakD,EAAM,EAChCG,GAAiB,EAMrB,CAGF,GAAIzI,EAAazG,GAAK,CACpB,GAAKA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,gBAClC2B,EAAazG,IAEpB,GAAW,KAAPA,EACF,GAAKA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,iBACjC0B,EAAMxG,IAAe,IAAPA,EAE1B,CAEA,KAAc,IAAPA,GAAU,CAOf,IANAqL,EAAc5C,GACdA,EAAMP,WAAa,EAEnBlI,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,YAGzBoK,GAAkBzG,EAAMP,WAAaiH,IAC/B,KAAPnP,GACNyI,EAAMP,aACNlI,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAOtC,IAJKoK,GAAkBzG,EAAMP,WAAaiH,IACxCA,EAAa1G,EAAMP,YAGjB1B,EAAMxG,GACRoP,QADF,CAUA,GALKF,GAAiC,IAAfC,GACrBzG,EAAWD,EAAO,wCAIhBA,EAAMP,WAAaiH,EAAY,CAv6BjB,IAy6BZH,EACFvG,EAAM/O,QAAUT,EAAOM,OAAO,KAAM0V,EAAiB,EAAIG,EAAaA,GA56BxD,IA66BLJ,GACLC,IACFxG,EAAM/O,QAAU,MAKpB,KACF,CAGIoV,EAEErI,EAAazG,IACfqP,GAAiB,EAEjB5G,EAAM/O,QAAUT,EAAOM,OAAO,KAAM0V,EAAiB,EAAIG,EAAaA,IAG7DC,GACTA,GAAiB,EACjB5G,EAAM/O,QAAUT,EAAOM,OAAO,KAAM6V,EAAa,IAGzB,IAAfA,EACLH,IACFxG,EAAM/O,QAAU,KAKlB+O,EAAM/O,QAAUT,EAAOM,OAAO,KAAM6V,GAMtC3G,EAAM/O,QAAUT,EAAOM,OAAO,KAAM0V,EAAiB,EAAIG,EAAaA,GAGxEH,GAAiB,EACjBC,GAAiB,EACjBE,EAAa,EAGb,IAFA,IAAME,EAAe7G,EAAM3D,UAEnB0B,EAAMxG,IAAe,IAAPA,GACpBA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGtCoF,EAAezB,EAAO6G,EAAc7G,EAAM3D,UAAU,EA5DpD,CA6DF,CAEA,OAAO,CACT,CAigByCyK,CAAgB9G,EAAO2D,IA92BhE,SAAiC3D,EAAOoD,GACtC,IAAIyD,EACAE,EAEAxP,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAEtC,GAAW,KAAP9E,EACF,OAAO,EAQT,IALAyI,EAAMpM,KAAO,SACboM,EAAM/O,OAAS,GACf+O,EAAM3D,WACNwK,EAAeE,EAAa/G,EAAM3D,SAEuB,KAAjD9E,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,YACxC,GAAW,KAAP9E,EAAoB,CAItB,GAHAkK,EAAezB,EAAO6G,EAAc7G,EAAM3D,UAAU,GAGzC,MAFX9E,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,WAOlC,OAAO,EAJPwK,EAAe7G,EAAM3D,SACrB2D,EAAM3D,WACN0K,EAAa/G,EAAM3D,QAIvB,MAAW0B,EAAMxG,IACfkK,EAAezB,EAAO6G,EAAcE,GAAY,GAChD7D,EAAiBlD,EAAO6C,EAAoB7C,GAAO,EAAOoD,IAC1DyD,EAAeE,EAAa/G,EAAM3D,UACzB2D,EAAM3D,WAAa2D,EAAM7D,WAAa8G,EAAsBjD,GACrEC,EAAWD,EAAO,iEAElBA,EAAM3D,WACD2B,EAAazG,KAChBwP,EAAa/G,EAAM3D,WAKzB4D,EAAWD,EAAO,6DACpB,CAq0BYgH,CAAuBhH,EAAO2D,IAn0B1C,SAAiC3D,EAAOoD,GACtC,IAAIyD,EACAE,EACAT,EAEA/O,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAEtC,GAAW,KAAP9E,EACF,OAAO,EAQT,IALAyI,EAAMpM,KAAO,SACboM,EAAM/O,OAAS,GACf+O,EAAM3D,WACNwK,EAAeE,EAAa/G,EAAM3D,SAEuB,KAAjD9E,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,YAAkB,CAC1D,GAAW,KAAP9E,EAGF,OAFAkK,EAAezB,EAAO6G,EAAc7G,EAAM3D,UAAU,GACpD2D,EAAM3D,YACC,EACT,GAAkB,KAAP9E,EAAoB,CAI7B,GAHAkK,EAAezB,EAAO6G,EAAc7G,EAAM3D,UAAU,GAGhD0B,EAFJxG,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,WAGlCwG,EAAoB7C,GAAO,EAAOoD,WAGzB7L,EAAK,KAAOuH,EAAkBvH,GACvCyI,EAAM/O,QAAU8N,EAAgBxH,GAChCyI,EAAM3D,oBACIiK,EAAMjI,EAAc9G,IAAO,EAAG,CAIxC,IAHA,IAAI0P,EAAYX,EACZY,EAAY,EAETD,EAAY,EAAGA,KAGfX,EAAMnI,EAFX5G,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,aAEL,EAC7B6K,GAAaA,GAAa,GAAKZ,EAE/BrG,EAAWD,EAAO,kCAItBA,EAAM/O,QAAUuN,EAAkB0I,GAElClH,EAAM3D,UACR,MACE4D,EAAWD,EAAO,2BAGpB6G,EAAeE,EAAa/G,EAAM3D,QACpC,MAAW0B,EAAMxG,IACfkK,EAAezB,EAAO6G,EAAcE,GAAY,GAChD7D,EAAiBlD,EAAO6C,EAAoB7C,GAAO,EAAOoD,IAC1DyD,EAAeE,EAAa/G,EAAM3D,UACzB2D,EAAM3D,WAAa2D,EAAM7D,WAAa8G,EAAsBjD,GACrEC,EAAWD,EAAO,iEAElBA,EAAM3D,WACD2B,EAAazG,KAChBwP,EAAa/G,EAAM3D,UAGzB,CAEA4D,EAAWD,EAAO,6DACpB,CA+vBYmH,CAAuBnH,EAAO2D,GAHhC+B,GAAa,GAjKvB,SAAoB1F,GAClB,IAAIzI,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAEtC,GAAW,KAAP9E,EAAoB,OAAO,EAE/BA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGpC,IAFA,IAAMyF,EAAY9B,EAAM3D,SAEV,IAAP9E,IAAa0G,EAAU1G,KAAQ2G,EAAgB3G,IACpDA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGlC2D,EAAM3D,WAAayF,GACrB7B,EAAWD,EAAO,6DAGpB,IAAMxL,EAAQwL,EAAMnF,MAAMrD,MAAMsK,EAAW9B,EAAM3D,UAQjD,OANKnB,EAAgBrI,KAAKmN,EAAMO,UAAW/L,IACzCyL,EAAWD,EAAO,uBAAyBxL,EAAQ,KAGrDwL,EAAM/O,OAAS+O,EAAMO,UAAU/L,GAC/BqO,EAAoB7C,GAAO,GAAM,IAC1B,CACT,CA6ImBoH,CAAUpH,GAz9B7B,SAA0BA,EAAOoD,EAAYiE,GAC3C,IAAIR,EACAE,EACAO,EACA9D,EACAqC,EACA0B,EACEC,EAAQxH,EAAMpM,KACdiO,EAAU7B,EAAM/O,OAElBsG,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAEtC,GAAI4B,EAAU1G,IACV2G,EAAgB3G,IACT,KAAPA,GACO,KAAPA,GACO,KAAPA,GACO,KAAPA,GACO,MAAPA,GACO,KAAPA,GACO,KAAPA,GACO,KAAPA,GACO,KAAPA,GACO,KAAPA,GACO,KAAPA,EACF,OAAO,EAGT,GAAW,KAAPA,GAA6B,KAAPA,EAAoB,CAC5C,IAAM0M,EAAYjE,EAAMnF,MAAMhD,WAAWmI,EAAM3D,SAAW,GAE1D,GAAI4B,EAAUgG,IACToD,GAAwBnJ,EAAgB+F,GAC3C,OAAO,CAEX,CAOA,IALAjE,EAAMpM,KAAO,SACboM,EAAM/O,OAAS,GACf4V,EAAeE,EAAa/G,EAAM3D,SAClCiL,GAAoB,EAEN,IAAP/P,GAAU,CACf,GAAW,KAAPA,EAAoB,CACtB,IAAM0M,EAAYjE,EAAMnF,MAAMhD,WAAWmI,EAAM3D,SAAW,GAE1D,GAAI4B,EAAUgG,IACToD,GAAwBnJ,EAAgB+F,GAC3C,KAEJ,MAAA,GAAkB,KAAP1M,GAGT,GAAI0G,EAFc+B,EAAMnF,MAAMhD,WAAWmI,EAAM3D,SAAW,IAGxD,cAEQ2D,EAAM3D,WAAa2D,EAAM7D,WAAa8G,EAAsBjD,IAC5DqH,GAAwBnJ,EAAgB3G,GAClD,MACF,GAAWwG,EAAMxG,GAAK,CAMpB,GALAiM,EAAQxD,EAAMxN,KACdqT,EAAa7F,EAAM7D,UACnBoL,EAAcvH,EAAMP,WACpBoD,EAAoB7C,GAAO,GAAO,GAE9BA,EAAMP,YAAc2D,EAAY,CAClCkE,GAAoB,EACpB/P,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,UAClC,QACF,CACE2D,EAAM3D,SAAW0K,EACjB/G,EAAMxN,KAAOgR,EACbxD,EAAM7D,UAAY0J,EAClB7F,EAAMP,WAAa8H,EACnB,KAEJ,EAEID,IACF7F,EAAezB,EAAO6G,EAAcE,GAAY,GAChD7D,EAAiBlD,EAAOA,EAAMxN,KAAOgR,GACrCqD,EAAeE,EAAa/G,EAAM3D,SAClCiL,GAAoB,GAGjBtJ,EAAazG,KAChBwP,EAAa/G,EAAM3D,SAAW,GAGhC9E,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,SACtC,CAIA,OAFAoF,EAAezB,EAAO6G,EAAcE,GAAY,KAE5C/G,EAAM/O,SAIV+O,EAAMpM,KAAO4T,EACbxH,EAAM/O,OAAS4Q,GACR,EACT,CA03BmB4F,CAAgBzH,EAAO2D,EAl/ClB,IAk/CkDwB,KAChEO,GAAa,EAEK,OAAd1F,EAAMzM,MACRyM,EAAMzM,IAAM,OATdmS,GAAa,EAEK,OAAd1F,EAAMzM,KAAiC,OAAjByM,EAAMS,QAC9BR,EAAWD,EAAO,8CAUD,OAAjBA,EAAMS,QACRN,EAAYH,EAAOA,EAAMS,OAAQT,EAAM/O,OAE3C,MAC0B,IAAjBuU,IAGTE,EAAaJ,GAAyBnC,EAAkBnD,EAAOuF,IAInE,GAAkB,OAAdvF,EAAMzM,IACa,OAAjByM,EAAMS,QACRN,EAAYH,EAAOA,EAAMS,OAAQT,EAAM/O,aAE3C,GAAyB,MAAd+O,EAAMzM,IAAa,CAOP,OAAjByM,EAAM/O,QAAkC,WAAf+O,EAAMpM,MACjCqM,EAAWD,EAAO,oEAAsEA,EAAMpM,KAAO,KAGvG,IAAA,IAAS8T,EAAY,EAAGC,EAAe3H,EAAMT,cAAczN,OAAQ4V,EAAYC,EAAcD,GAAa,EAGxG,IAFApU,EAAO0M,EAAMT,cAAcmI,IAElB7T,QAAQmM,EAAM/O,QAAS,CAC9B+O,EAAM/O,OAASqC,EAAKQ,UAAUkM,EAAM/O,QACpC+O,EAAMzM,IAAMD,EAAKC,IACI,OAAjByM,EAAMS,QACRN,EAAYH,EAAOA,EAAMS,OAAQT,EAAM/O,QAEzC,KACF,CAEJ,MAAA,GAAyB,MAAd+O,EAAMzM,IAAa,CAC5B,GAAI2H,EAAgBrI,KAAKmN,EAAMR,QAAQQ,EAAMpM,MAAQ,YAAaoM,EAAMzM,KACtED,EAAO0M,EAAMR,QAAQQ,EAAMpM,MAAQ,YAAYoM,EAAMzM,SAChD,CAELD,EAAO,KAGP,IAFA,IAAMsU,EAAW5H,EAAMR,QAAQnL,MAAM2L,EAAMpM,MAAQ,YAE1C8T,EAAY,EAAGC,EAAeC,EAAS9V,OAAQ4V,EAAYC,EAAcD,GAAa,EAC7F,GAAI1H,EAAMzM,IAAIiE,MAAM,EAAGoQ,EAASF,GAAWnU,IAAIzB,UAAY8V,EAASF,GAAWnU,IAAK,CAClFD,EAAOsU,EAASF,GAChB,KACF,CAEJ,CAEKpU,GACH2M,EAAWD,EAAO,iBAAmBA,EAAMzM,IAAM,KAG9B,OAAjByM,EAAM/O,QAAmBqC,EAAKM,OAASoM,EAAMpM,MAC/CqM,EAAWD,EAAO,gCAAkCA,EAAMzM,IAAM,wBAA0BD,EAAKM,KAAO,WAAaoM,EAAMpM,KAAO,KAG7HN,EAAKO,QAAQmM,EAAM/O,OAAQ+O,EAAMzM,MAGpCyM,EAAM/O,OAASqC,EAAKQ,UAAUkM,EAAM/O,OAAQ+O,EAAMzM,KAC7B,OAAjByM,EAAMS,QACRN,EAAYH,EAAOA,EAAMS,OAAQT,EAAM/O,SAJzCgP,EAAWD,EAAO,gCAAkCA,EAAMzM,IAAM,iBAOpE,CAOA,OALuB,OAAnByM,EAAMZ,UACRY,EAAMZ,SAAS,QAASY,GAG1BA,EAAMN,OAAS,EACM,OAAdM,EAAMzM,KAAiC,OAAjByM,EAAMS,QAAmBiF,CACxD,CAEA,SAASmC,EAAc7H,GACrB,IAEIzI,EAFEuQ,EAAgB9H,EAAM3D,SACxB0L,GAAgB,EAQpB,IALA/H,EAAMe,QAAU,KAChBf,EAAMkB,gBAAkBlB,EAAMb,OAC9Ba,EAAMsB,OAAS3P,OAAOsB,OAAO,MAC7B+M,EAAMO,UAAY5O,OAAOsB,OAAO,MAEyB,KAAjDsE,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,aACxCwG,EAAoB7C,GAAO,GAAM,GAEjCzI,EAAKyI,EAAMnF,MAAMhD,WAAWmI,EAAM3D,YAE9B2D,EAAMP,WAAa,GAAY,KAAPlI,KAL8B,CAS1DwQ,GAAgB,EAChBxQ,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGpC,IAFA,IAAIyF,EAAY9B,EAAM3D,SAER,IAAP9E,IAAa0G,EAAU1G,IAC5BA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGtC,IAAM2L,EAAgBhI,EAAMnF,MAAMrD,MAAMsK,EAAW9B,EAAM3D,UACnD4L,EAAgB,GAMtB,IAJID,EAAclW,OAAS,GACzBmO,EAAWD,EAAO,gEAGN,IAAPzI,GAAU,CACf,KAAOyG,EAAazG,IAClBA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGtC,GAAW,KAAP9E,EAAoB,CACtB,GAAKA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,gBAC3B,IAAP9E,IAAawG,EAAMxG,IAC1B,KACF,CAEA,GAAIwG,EAAMxG,GAAK,MAIf,IAFAuK,EAAY9B,EAAM3D,SAEJ,IAAP9E,IAAa0G,EAAU1G,IAC5BA,EAAKyI,EAAMnF,MAAMhD,aAAamI,EAAM3D,UAGtC4L,EAAc3S,KAAK0K,EAAMnF,MAAMrD,MAAMsK,EAAW9B,EAAM3D,UACxD,CAEW,IAAP9E,GAAUqL,EAAc5C,GAExB9E,EAAgBrI,KAAK+N,EAAmBoH,GAC1CpH,EAAkBoH,GAAehI,EAAOgI,EAAeC,GAEvD/H,EAAaF,EAAO,+BAAiCgI,EAAgB,IAEzE,CAEAnF,EAAoB7C,GAAO,GAAM,GAER,IAArBA,EAAMP,YACqC,KAA3CO,EAAMnF,MAAMhD,WAAWmI,EAAM3D,WACkB,KAA/C2D,EAAMnF,MAAMhD,WAAWmI,EAAM3D,SAAW,IACO,KAA/C2D,EAAMnF,MAAMhD,WAAWmI,EAAM3D,SAAW,IAC1C2D,EAAM3D,UAAY,EAClBwG,EAAoB7C,GAAO,GAAM,IACxB+H,GACT9H,EAAWD,EAAO,mCAGpByD,EAAYzD,EAAOA,EAAMP,WAAa,EAppDd,GAopDoC,GAAO,GACnEoD,EAAoB7C,GAAO,GAAM,GAE7BA,EAAMkB,iBACNxD,EAA8BjF,KAAKuH,EAAMnF,MAAMrD,MAAMsQ,EAAe9H,EAAM3D,YAC5E6D,EAAaF,EAAO,oDAGtBA,EAAMH,UAAUvK,KAAK0K,EAAM/O,QAEvB+O,EAAM3D,WAAa2D,EAAM7D,WAAa8G,EAAsBjD,GACf,KAA3CA,EAAMnF,MAAMhD,WAAWmI,EAAM3D,YAC/B2D,EAAM3D,UAAY,EAClBwG,EAAoB7C,GAAO,GAAM,IAKjCA,EAAM3D,SAAY2D,EAAMlO,OAAS,GACnCmO,EAAWD,EAAO,wDAEtB,CAEA,SAASkI,EAAerN,EAAOrH,GAE7BA,EAAUA,GAAW,CAAA,EAEA,KAHrBqH,EAAQpG,OAAOoG,IAGL/I,SAEmC,KAAvC+I,EAAMhD,WAAWgD,EAAM/I,OAAS,IACO,KAAvC+I,EAAMhD,WAAWgD,EAAM/I,OAAS,KAClC+I,GAAS,MAIiB,QAAxBA,EAAMhD,WAAW,KACnBgD,EAAQA,EAAMrD,MAAM,KAIxB,IAAMwI,EAAQ,IAAIhB,EAAMnE,EAAOrH,GAEzB2U,EAAUtN,EAAMlH,QAAQ,MAU9B,KARgB,IAAZwU,IACFnI,EAAM3D,SAAW8L,EACjBlI,EAAWD,EAAO,sCAIpBA,EAAMnF,OAAS,KAEmC,KAA3CmF,EAAMnF,MAAMhD,WAAWmI,EAAM3D,WAClC2D,EAAMP,YAAc,EACpBO,EAAM3D,UAAY,EAGpB,KAAO2D,EAAM3D,SAAY2D,EAAMlO,OAAS,GACtC+V,EAAa7H,GAGf,OAAOA,EAAMH,SACf,QA8BAuI,EAAAC,QA5BA,SAAkBxN,EAAO1K,EAAUqD,GAChB,OAAbrD,GAAyC,WAApBH,EAAOG,SAA4C,IAAZqD,IAC9DA,EAAUrD,EACVA,EAAW,MAGb,IAAM0P,EAAYqI,EAAcrN,EAAOrH,GAEvC,GAAwB,mBAAbrD,EACT,OAAO0P,EAGT,IAAA,IAAShO,EAAQ,EAAGC,EAAS+N,EAAU/N,OAAQD,EAAQC,EAAQD,GAAS,EACtE1B,EAAS0P,EAAUhO,GAEvB,EAcAuW,EAAAE,KAZA,SAAezN,EAAOrH,GACpB,IAAMqM,EAAYqI,EAAcrN,EAAOrH,GAEvC,GAAyB,IAArBqM,EAAU/N,OAAd,CAEA,GAAgC,IAArB+N,EAAU/N,OACnB,OAAO+N,EAAU,GAEnB,MAAM,IAAIlN,EAAc,2DADxB,CAEF,kDE1vDY,SAAA3C,EAAAC,GAAA,OAAAD,EAAA,mBAAAE,QAAA,iBAAAA,OAAAC,SAAA,SAAAF,GAAA,cAAAA,GAAA,SAAAA,GAAA,OAAAA,GAAA,mBAAAC,QAAAD,EAAAG,cAAAF,QAAAD,IAAAC,OAAAG,UAAA,gBAAAJ,CAAA,GAAAA,EAAA,MAEZ,IAAMO,EAAS2C,IACTR,EAAgBgC,IAChB6I,EAAiBnH,KAEjB+E,EAAYzJ,OAAOtB,UAAU6C,SAC7BgI,EAAkBvJ,OAAOtB,UAAU8K,eAEnCoN,EAAW,MA0BXC,EAAmB,CAEzBA,EAAyB,MACzBA,EAAyB,MACzBA,EAAyB,MACzBA,EAAyB,MACzBA,GAAyB,MACzBA,GAAyB,MACzBA,GAAyB,MACzBA,GAAyB,MACzBA,GAAyB,MACzBA,GAAyB,MACzBA,GAAyB,OACzBA,IAAyB,MACzBA,IAAyB,MACzBA,KAA2B,MAC3BA,KAA2B,OAErBC,EAA6B,CACjC,IAAK,IAAK,MAAO,MAAO,MAAO,KAAM,KAAM,KAC3C,IAAK,IAAK,KAAM,KAAM,KAAM,MAAO,MAAO,OAGtCC,EAA2B,4CA2BjC,SAASC,EAAWC,GAClB,IAAIvH,EACAvP,EAEEf,EAAS6X,EAAU1V,SAAS,IAAIiF,cAEtC,GAAIyQ,GAAa,IACfvH,EAAS,IACTvP,EAAS,OACX,GAAW8W,GAAa,MACtBvH,EAAS,IACTvP,EAAS,MACX,MAAW8W,GAAa,YAItB,MAAM,IAAIjW,EAAc,iEAHxB0O,EAAS,IACTvP,EAAS,CAGX,CAEA,MAAO,KAAOuP,EAAS7Q,EAAOM,OAAO,IAAKgB,EAASf,EAAOe,QAAUf,CACtE,CAKA,SAASiO,EAAOxL,GACdV,KAAK+B,OAASrB,EAAgB,QAAKgK,EACnC1K,KAAKgK,OAASL,KAAKjG,IAAI,EAAIhD,EAAgB,QAAK,GAChDV,KAAK+V,cAAgBrV,EAAuB,gBAAK,EACjDV,KAAKgW,YAActV,EAAqB,cAAK,EAC7CV,KAAKiW,UAAavY,EAAOF,UAAUkD,EAAmB,YAAK,EAAKA,EAAmB,UACnFV,KAAKkW,SAxDP,SAA0BnU,EAAQpB,GAChC,GAAY,OAARA,EAAc,MAAO,CAAA,EAKzB,IAHA,IAAMxC,EAAS,CAAA,EACTW,EAAOD,OAAOC,KAAK6B,GAEhB5B,EAAQ,EAAGC,EAASF,EAAKE,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CACpE,IAAI0B,EAAM3B,EAAKC,GACX0C,EAAQE,OAAOhB,EAAIF,IAEC,OAApBA,EAAIiE,MAAM,EAAG,KACfjE,EAAM,qBAAuBA,EAAIiE,MAAM,IAEzC,IAAMlE,EAAOuB,EAAOc,gBAA0B,SAAEpC,GAE5CD,GAAQ4H,EAAgBrI,KAAKS,EAAKgB,aAAcC,KAClDA,EAAQjB,EAAKgB,aAAaC,IAG5BtD,EAAOsC,GAAOgB,CAChB,CAEA,OAAOtD,CACT,CAiCkBgY,CAAgBnW,KAAK+B,OAAQrB,EAAgB,QAAK,MAClEV,KAAKoW,SAAW1V,EAAkB,WAAK,EACvCV,KAAKqW,UAAY3V,EAAmB,WAAK,GACzCV,KAAKsW,OAAS5V,EAAgB,SAAK,EACnCV,KAAKuW,aAAe7V,EAAsB,eAAK,EAC/CV,KAAKwW,aAAe9V,EAAsB,eAAK,EAC/CV,KAAKyW,YAAyC,MAA3B/V,EAAqB,YAdd,EADA,EAgB1BV,KAAK0W,YAAchW,EAAqB,cAAK,EAC7CV,KAAK2W,SAA0C,mBAAxBjW,EAAkB,SAAmBA,EAAkB,SAAI,KAElFV,KAAKyM,cAAgBzM,KAAK+B,OAAOY,iBACjC3C,KAAK4W,cAAgB5W,KAAK+B,OAAOa,iBAEjC5C,KAAKS,IAAM,KACXT,KAAK7B,OAAS,GAEd6B,KAAK6W,WAAa,GAClB7W,KAAK8W,eAAiB,IACxB,CAGA,SAASC,EAAc9Y,EAAQ+Y,GAM7B,IALA,IAAMC,EAAMvZ,EAAOM,OAAO,IAAKgZ,GAC3BzN,EAAW,EACXpL,EAAS,GACPa,EAASf,EAAOe,OAEfuK,EAAWvK,GAAQ,CACxB,IAAIU,OAAI,EACFwX,EAAOjZ,EAAO4C,QAAQ,KAAM0I,IACrB,IAAT2N,GACFxX,EAAOzB,EAAOyG,MAAM6E,GACpBA,EAAWvK,IAEXU,EAAOzB,EAAOyG,MAAM6E,EAAU2N,EAAO,GACrC3N,EAAW2N,EAAO,GAGhBxX,EAAKV,QAAmB,OAATU,IAAevB,GAAU8Y,GAE5C9Y,GAAUuB,CACZ,CAEA,OAAOvB,CACT,CAEA,SAASgZ,EAAkBjK,EAAOkK,GAChC,MAAO,KAAO1Z,EAAOM,OAAO,IAAKkP,EAAMlD,OAASoN,EAClD,CAeA,SAASC,EAAclT,GACrB,OAvKiB,KAuKVA,GA1KQ,IA0KYA,CAC7B,CAMA,SAASmT,EAAanT,GACpB,OAAQA,GAAK,IAAWA,GAAK,KACzBA,GAAK,KAAWA,GAAK,OAAmB,OAANA,GAAsB,OAANA,GAClDA,GAAK,OAAWA,GAAK,OAAaA,IAAMsR,GACzCtR,GAAK,OAAWA,GAAK,OAC1B,CAOA,SAASoT,EAAsBpT,GAC7B,OAAOmT,EAAYnT,IACjBA,IAAMsR,GA7LmB,KA+LzBtR,GAhMmB,KAiMnBA,CACJ,CAWA,SAASqT,EAAarT,EAAGsT,EAAMC,GAC7B,IAAMC,EAAwBJ,EAAqBpT,GAC7CyT,EAAYD,IAA0BN,EAAalT,GACzD,OAGIuT,EACIC,EACAA,GA3MS,KA6MTxT,GAtMuB,KAuMvBA,GAtMwB,KAuMxBA,GArMsB,MAsMtBA,GApMuB,MAqMvBA,IAtNS,KAyNfA,KAlNe,KAmNbsT,IAAwBG,IAE3BL,EAAqBE,KAAUJ,EAAaI,IA5N5B,KA4NqCtT,GArNrC,KAsNhBsT,GAAuBG,CAC1B,CA2CA,SAASC,EAAa5Z,EAAQ4L,GAC5B,IACIzC,EADE0Q,EAAQ7Z,EAAO8G,WAAW8E,GAGhC,OAAIiO,GAAS,OAAUA,GAAS,OAAUjO,EAAM,EAAI5L,EAAOe,SACzDoI,EAASnJ,EAAO8G,WAAW8E,EAAM,KACnB,OAAUzC,GAAU,MAEN,MAAlB0Q,EAAQ,OAAkB1Q,EAAS,MAAS,MAGjD0Q,CACT,CAGA,SAASC,EAAqB9Z,GAE5B,MADuB,QACD0H,KAAK1H,EAC7B,CAeA,SAAS+Z,EAAmB/Z,EAAQga,EAAgBC,EAAgB7B,EAClE8B,EAAmB1B,EAAaC,EAAagB,GAC7C,IAAIjN,EA3EqBtG,EA4ErBiU,EAAO,EACPC,EAAW,KACXC,GAAe,EACfC,GAAkB,EAChBC,GAAiC,IAAdnC,EACrBoC,GAAoB,EACpBC,EA9EGpB,EAJkBnT,EAkFI0T,EAAY5Z,EAAQ,KA7E/CkG,IAAMsR,IACL4B,EAAalT,IAjOC,KAoOfA,GAhOkB,KAiOlBA,GApOe,KAqOfA,GAvOe,KAwOfA,GAjO6B,KAkO7BA,GAjO8B,KAkO9BA,GAhO4B,MAiO5BA,GA/N6B,MAgO7BA,GAjPe,KAmPfA,GAjPmB,KAkPnBA,GAhPkB,KAiPlBA,GAvPqB,KAwPrBA,GAtOuB,MAuOvBA,GA/OgB,KAgPhBA,GA/OsB,KAgPtBA,GAtPsB,KAuPtBA,GA3PsB,KA4PtBA,GA1PiB,KA4PjBA,GAlPuB,KAmPvBA,GAhPsB,KAiPtBA,GAIJ,SAA0BA,GAExB,OAAQkT,EAAalT,IA9PJ,KA8PUA,CAC7B,CA8CIwU,CAAgBd,EAAY5Z,EAAQA,EAAOe,OAAS,IAEtD,GAAIiZ,GAAkBvB,EAGpB,IAAKjM,EAAI,EAAGA,EAAIxM,EAAOe,OAAQoZ,GAAQ,MAAU3N,GAAK,EAAIA,IAAK,CAE7D,IAAK6M,EADLc,EAAOP,EAAY5Z,EAAQwM,IAEzB,OA3Ba,EA6BfiO,EAAQA,GAASlB,EAAYY,EAAMC,EAAUX,GAC7CW,EAAWD,CACb,KACK,CAEL,IAAK3N,EAAI,EAAGA,EAAIxM,EAAOe,OAAQoZ,GAAQ,MAAU3N,GAAK,EAAIA,IAAK,CAE7D,GA1UiB,MAyUjB2N,EAAOP,EAAY5Z,EAAQwM,IAEzB6N,GAAe,EAEXE,IACFD,EAAkBA,GAEf9N,EAAIgO,EAAoB,EAAIpC,GACM,MAAlCpY,EAAOwa,EAAoB,GAC9BA,EAAoBhO,QAExB,IAAY6M,EAAYc,GACtB,OA/Ca,EAiDfM,EAAQA,GAASlB,EAAYY,EAAMC,EAAUX,GAC7CW,EAAWD,CACb,CAEAG,EAAkBA,GAAoBC,GACnC/N,EAAIgO,EAAoB,EAAIpC,GACM,MAAlCpY,EAAOwa,EAAoB,EAChC,CAIA,OAAKH,GAAiBC,EASlBL,EAAiB,GAAKH,EAAoB9Z,GArE3B,EA0EdyY,EA/QqB,IAkRnBD,EA7EY,EAHA,EA8EV8B,EA5EU,EADC,GAiEdG,GAAUhC,GAAgByB,EAAkBla,GApQxB,IAuQjBwY,EAlEU,EAHA,EADD,CAkFpB,CAQA,SAASmC,EAAa1L,EAAOjP,EAAQmZ,EAAOyB,EAAOnB,GACjDxK,EAAM4L,gBACJ,GAAsB,IAAlB7a,EAAOe,OACT,OA9RsB,IA8RfkO,EAAMuJ,YAAsC,KAAO,KAE5D,IAAKvJ,EAAMqJ,oBACLZ,EAA2B9U,QAAQ5C,IAAkB2X,EAAyBjQ,KAAK1H,IACrF,OAlSoB,IAkSbiP,EAAMuJ,YAAuC,IAAMxY,EAAS,IAAQ,IAAMA,EAAS,IAI9F,IAAM+L,EAASkD,EAAMlD,OAASL,KAAKjG,IAAI,EAAG0T,GAQpCf,GAAiC,IAApBnJ,EAAMmJ,aAErB1M,KAAKjG,IAAIiG,KAAKa,IAAI0C,EAAMmJ,UAAW,IAAKnJ,EAAMmJ,UAAYrM,GAGxDiO,EAAiBY,GAEpB3L,EAAM+I,WAAY,GAAMmB,GAASlK,EAAM+I,UAK1C,OAAQ+B,EAAkB/Z,EAAQga,EAAgB/K,EAAMlD,OAAQqM,EAJhE,SAAwBpY,GACtB,OA7PN,SAAgCiP,EAAO9J,GACrC,IAAA,IAASrE,EAAQ,EAAGC,EAASkO,EAAMT,cAAczN,OAAQD,EAAQC,EAAQD,GAAS,EAGhF,GAFamO,EAAMT,cAAc1N,GAExBgC,QAAQqC,GACf,OAAO,EAIX,OAAO,CACT,CAmPa2V,CAAsB7L,EAAOjP,EACtC,EAGiBiP,EAAMuJ,YAAavJ,EAAMwJ,cAAgBmC,EAAOnB,IAC/D,KA3Hc,EA4HZ,OAAOzZ,EACT,KA5He,EA6Hb,MAAO,IAAMA,EAAOiI,QAAQ,KAAM,MAAQ,IAC5C,KA7HgB,EA8Hd,MAAO,IAAM8S,EAAY/a,EAAQiP,EAAMlD,QACrCiP,EAAkBlC,EAAa9Y,EAAQ+L,IAC3C,KA/He,EAgIb,MAAO,IAAMgP,EAAY/a,EAAQiP,EAAMlD,QACrCiP,EAAkBlC,EA4B5B,SAAqB9Y,EAAQib,GAK3B,IAWIC,EAGAvS,EAdEwS,EAAS,iBAGXjb,GACEkb,EAASpb,EAAO4C,QAAQ,MAC5BwY,GAAoB,IAAXA,EAAgBA,EAASpb,EAAOe,OACzCoa,EAAOE,UAAYD,EACZE,EAAStb,EAAOyG,MAAM,EAAG2U,GAASH,IAGvCM,EAAiC,OAAdvb,EAAO,IAA6B,MAAdA,EAAO,OAN9Cob,EAWN,KAAQzS,EAAQwS,EAAO3S,KAAKxI,IAAU,CACpC,IAAMqQ,EAAS1H,EAAM,GACflH,EAAOkH,EAAM,GAEnBuS,EAA4B,MAAZzZ,EAAK,GACrBvB,GAAUmQ,GACLkL,GAAqBL,GAAyB,KAATzZ,EAAsB,GAAP,MACvD6Z,EAAS7Z,EAAMwZ,GACjBM,EAAmBL,CACrB,CAEA,OAAOhb,CACT,CA5DyCsb,CAAWxb,EAAQoY,GAAYrM,IAClE,KAjIe,EAkIb,MAAO,IA2Gf,SAAuB/L,GAIrB,IAHA,IAAIE,EAAS,GACTia,EAAO,EAEF3N,EAAI,EAAGA,EAAIxM,EAAOe,OAAQoZ,GAAQ,MAAU3N,GAAK,EAAIA,IAAK,CACjE2N,EAAOP,EAAY5Z,EAAQwM,GAC3B,IAAMiP,EAAYhE,EAAiB0C,IAE9BsB,GAAapC,EAAYc,IAC5Bja,GAAUF,EAAOwM,GACb2N,GAAQ,QAASja,GAAUF,EAAOwM,EAAI,KAE1CtM,GAAUub,GAAa7D,EAAUuC,EAErC,CAEA,OAAOja,CACT,CA5HqBwb,CAAa1b,GAAqB,IACjD,QACE,MAAM,IAAI4B,EAAc,0CAE9B,GACF,CAGA,SAASmZ,EAAa/a,EAAQia,GAC5B,IAAM0B,EAAkB7B,EAAoB9Z,GAAU0D,OAAOuW,GAAkB,GAGzE2B,EAAqC,OAA9B5b,EAAOA,EAAOe,OAAS,GAIpC,OAAO4a,GAHMC,IAAuC,OAA9B5b,EAAOA,EAAOe,OAAS,IAA0B,OAAXf,GACvC,IAAO4b,EAAO,GAAK,KAEP,IACnC,CAGA,SAASZ,EAAmBhb,GAC1B,MAAqC,OAA9BA,EAAOA,EAAOe,OAAS,GAAcf,EAAOyG,MAAM,GAAG,GAAMzG,CACpE,CA0CA,SAASsb,EAAU7Z,EAAMwZ,GACvB,GAAa,KAATxZ,GAA2B,MAAZA,EAAK,GAAY,OAAOA,EAgB3C,IAbA,IACIkH,EAGAiI,EAJEiL,EAAU,SAGZlL,EAAQ,EAERmL,EAAO,EACP7C,EAAO,EACP/Y,EAAS,GAMLyI,EAAQkT,EAAQrT,KAAK/G,KAC3BwX,EAAOtQ,EAAM7H,OAEF6P,EAAQsK,IACjBrK,EAAOkL,EAAOnL,EAASmL,EAAO7C,EAC9B/Y,GAAU,KAAOuB,EAAKgF,MAAMkK,EAAOC,GAEnCD,EAAQC,EAAM,GAEhBkL,EAAO7C,EAaT,OARA/Y,GAAU,KAENuB,EAAKV,OAAS4P,EAAQsK,GAASa,EAAOnL,EACxCzQ,GAAUuB,EAAKgF,MAAMkK,EAAOmL,GAAQ,KAAOra,EAAKgF,MAAMqV,EAAO,GAE7D5b,GAAUuB,EAAKgF,MAAMkK,GAGhBzQ,EAAOuG,MAAM,EACtB,CA8CA,SAASsV,EAAoB9M,EAAOkK,EAAOzT,EAAQvE,GAIjD,IAHA,IAAI2P,EAAU,GACRwB,EAAOrD,EAAMzM,IAEV1B,EAAQ,EAAGC,EAAS2E,EAAO3E,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CACtE,IAAIwF,EAAQZ,EAAO5E,GAEfmO,EAAMyJ,WACRpS,EAAQ2I,EAAMyJ,SAAS5W,KAAK4D,EAAQhC,OAAO5C,GAAQwF,KAIjD0V,EAAU/M,EAAOkK,EAAQ,EAAG7S,GAAO,GAAM,GAAM,GAAO,SACpC,IAAVA,GACP0V,EAAU/M,EAAOkK,EAAQ,EAAG,MAAM,GAAM,GAAM,GAAO,MACnDhY,GAAuB,KAAZ2P,IACdA,GAAWoI,EAAiBjK,EAAOkK,IAGjClK,EAAM4L,MAjlBO,KAilBoB5L,EAAM4L,KAAK/T,WAAW,GACzDgK,GAAW,IAEXA,GAAW,KAGbA,GAAW7B,EAAM4L,KAErB,CAEA5L,EAAMzM,IAAM8P,EACZrD,EAAM4L,KAAO/J,GAAW,IAC1B,CAkHA,SAASmL,EAAYhN,EAAOvJ,EAAQpB,GAGlC,IAFA,IAAMuS,EAAWvS,EAAW2K,EAAM0J,cAAgB1J,EAAMT,cAE/C1N,EAAQ,EAAGC,EAAS8V,EAAS9V,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CACxE,IAAMyB,EAAOsU,EAAS/V,GAEtB,IAAKyB,EAAKU,YAAcV,EAAKW,cACvBX,EAAKU,YAAkC,WAAlBhE,EAAOyG,IAAyBA,aAAkBnD,EAAKU,eAC5EV,EAAKW,WAAaX,EAAKW,UAAUwC,IAAU,CAW/C,GAVIpB,EACE/B,EAAKe,OAASf,EAAKa,cACrB6L,EAAMzM,IAAMD,EAAKa,cAAcsC,GAE/BuJ,EAAMzM,IAAMD,EAAKC,IAGnByM,EAAMzM,IAAM,IAGVD,EAAKY,UAAW,CAClB,IAAMK,EAAQyL,EAAMgJ,SAAS1V,EAAKC,MAAQD,EAAKc,aAE3CyN,OAAO,EACX,GAAuC,sBAAnCzG,EAAUvI,KAAKS,EAAKY,WACtB2N,EAAUvO,EAAKY,UAAUuC,EAAQlC,YACxB2G,EAAgBrI,KAAKS,EAAKY,UAAWK,GAG9C,MAAM,IAAI5B,EAAc,KAAOW,EAAKC,IAAM,+BAAiCgB,EAAQ,WAFnFsN,EAAUvO,EAAKY,UAAUK,GAAOkC,EAAQlC,EAG1C,CAEAyL,EAAM4L,KAAO/J,CACf,CAEA,OAAO,CACT,CACF,CAEA,OAAO,CACT,CAKA,SAASkL,EAAW/M,EAAOkK,EAAOzT,EAAQwW,EAAO/a,EAASyZ,EAAOuB,GAC/DlN,EAAMzM,IAAM,KACZyM,EAAM4L,KAAOnV,EAERuW,EAAWhN,EAAOvJ,GAAQ,IAC7BuW,EAAWhN,EAAOvJ,GAAQ,GAG5B,IAAMnD,EAAO8H,EAAUvI,KAAKmN,EAAM4L,MAC5BpB,EAAUyC,EAEZA,IACFA,EAASjN,EAAM+I,UAAY,GAAK/I,EAAM+I,UAAYmB,GAGpD,IACIiD,EACAC,EAFEC,EAAyB,oBAAT/Z,GAAuC,mBAATA,EAapD,GATI+Z,IAEFD,GAA+B,KAD/BD,EAAiBnN,EAAM2J,WAAWhW,QAAQ8C,MAIzB,OAAduJ,EAAMzM,KAA8B,MAAdyM,EAAMzM,KAAgB6Z,GAA+B,IAAjBpN,EAAMlD,QAAgBoN,EAAQ,KAC3FhY,GAAU,GAGRkb,GAAapN,EAAM4J,eAAeuD,GACpCnN,EAAM4L,KAAO,QAAUuB,MAClB,CAIL,GAHIE,GAAiBD,IAAcpN,EAAM4J,eAAeuD,KACtDnN,EAAM4J,eAAeuD,IAAkB,GAE5B,oBAAT7Z,EACE2Z,GAA6C,IAAnCtb,OAAOC,KAAKoO,EAAM4L,MAAM9Z,SAvJ5C,SAA4BkO,EAAOkK,EAAOzT,EAAQvE,GAChD,IAAI2P,EAAU,GACRwB,EAAOrD,EAAMzM,IACb+Z,EAAgB3b,OAAOC,KAAK6E,GAGlC,IAAuB,IAAnBuJ,EAAMkJ,SAERoE,EAAcC,eACqB,mBAAnBvN,EAAMkJ,SAEtBoE,EAAcC,KAAKvN,EAAMkJ,eAC3B,GAAWlJ,EAAMkJ,SAEf,MAAM,IAAIvW,EAAc,4CAG1B,IAAA,IAASd,EAAQ,EAAGC,EAASwb,EAAcxb,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CAC7E,IAAI2b,EAAa,GAEZtb,GAAuB,KAAZ2P,IACd2L,GAAcvD,EAAiBjK,EAAOkK,IAGxC,IAAMuD,EAAYH,EAAczb,GAC5B6b,EAAcjX,EAAOgX,GAMzB,GAJIzN,EAAMyJ,WACRiE,EAAc1N,EAAMyJ,SAAS5W,KAAK4D,EAAQgX,EAAWC,IAGlDX,EAAU/M,EAAOkK,EAAQ,EAAGuD,GAAW,GAAM,GAAM,GAAxD,CAIA,IAAME,EAA8B,OAAd3N,EAAMzM,KAA8B,MAAdyM,EAAMzM,KAClCyM,EAAM4L,MAAQ5L,EAAM4L,KAAK9Z,OAAS,KAE9C6b,IACE3N,EAAM4L,MA9qBO,KA8qBoB5L,EAAM4L,KAAK/T,WAAW,GACzD2V,GAAc,IAEdA,GAAc,MAIlBA,GAAcxN,EAAM4L,KAEhB+B,IACFH,GAAcvD,EAAiBjK,EAAOkK,IAGnC6C,EAAU/M,EAAOkK,EAAQ,EAAGwD,GAAa,EAAMC,KAIhD3N,EAAM4L,MA/rBS,KA+rBkB5L,EAAM4L,KAAK/T,WAAW,GACzD2V,GAAc,IAEdA,GAAc,KAMhB3L,GAHA2L,GAAcxN,EAAM4L,KA7BpB,CAiCF,CAEA5L,EAAMzM,IAAM8P,EACZrD,EAAM4L,KAAO/J,GAAW,IAC1B,CAkFQ+L,CAAkB5N,EAAOkK,EAAOlK,EAAM4L,KAAM1Z,GACxCkb,IACFpN,EAAM4L,KAAO,QAAUuB,EAAiBnN,EAAM4L,SAlMxD,SAA2B5L,EAAOkK,EAAOzT,GAKvC,IAJA,IAAIoL,EAAU,GACRwB,EAAOrD,EAAMzM,IACb+Z,EAAgB3b,OAAOC,KAAK6E,GAEzB5E,EAAQ,EAAGC,EAASwb,EAAcxb,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CAC7E,IAAI2b,EAAa,GACD,KAAZ3L,IAAgB2L,GAAc,MAE9BxN,EAAMsJ,eAAckE,GAAc,KAEtC,IAAMC,EAAYH,EAAczb,GAC5B6b,EAAcjX,EAAOgX,GAErBzN,EAAMyJ,WACRiE,EAAc1N,EAAMyJ,SAAS5W,KAAK4D,EAAQgX,EAAWC,IAGlDX,EAAU/M,EAAOkK,EAAOuD,GAAW,GAAO,KAI3CzN,EAAM4L,KAAK9Z,OAAS,OAAM0b,GAAc,MAE5CA,GAAcxN,EAAM4L,MAAQ5L,EAAMsJ,aAAe,IAAM,IAAM,KAAOtJ,EAAMsJ,aAAe,GAAK,KAEzFyD,EAAU/M,EAAOkK,EAAOwD,GAAa,GAAO,KAOjD7L,GAHA2L,GAAcxN,EAAM4L,MAItB,CAEA5L,EAAMzM,IAAM8P,EACZrD,EAAM4L,KAAO,IAAM/J,EAAU,GAC/B,CA+JQgM,CAAiB7N,EAAOkK,EAAOlK,EAAM4L,MACjCwB,IACFpN,EAAM4L,KAAO,QAAUuB,EAAiB,IAAMnN,EAAM4L,YAG1D,GAAoB,mBAATtY,EACL2Z,GAAgC,IAAtBjN,EAAM4L,KAAK9Z,QACnBkO,EAAM6I,gBAAkBqE,GAAchD,EAAQ,EAChD4C,EAAmB9M,EAAOkK,EAAQ,EAAGlK,EAAM4L,KAAM1Z,GAEjD4a,EAAmB9M,EAAOkK,EAAOlK,EAAM4L,KAAM1Z,GAE3Ckb,IACFpN,EAAM4L,KAAO,QAAUuB,EAAiBnN,EAAM4L,SA3QxD,SAA4B5L,EAAOkK,EAAOzT,GAIxC,IAHA,IAAIoL,EAAU,GACRwB,EAAOrD,EAAMzM,IAEV1B,EAAQ,EAAGC,EAAS2E,EAAO3E,OAAQD,EAAQC,EAAQD,GAAS,EAAG,CACtE,IAAIwF,EAAQZ,EAAO5E,GAEfmO,EAAMyJ,WACRpS,EAAQ2I,EAAMyJ,SAAS5W,KAAK4D,EAAQhC,OAAO5C,GAAQwF,KAIjD0V,EAAU/M,EAAOkK,EAAO7S,GAAO,GAAO,SACpB,IAAVA,GACP0V,EAAU/M,EAAOkK,EAAO,MAAM,GAAO,MACxB,KAAZrI,IAAgBA,GAAW,KAAQ7B,EAAMsJ,aAAqB,GAAN,MAC5DzH,GAAW7B,EAAM4L,KAErB,CAEA5L,EAAMzM,IAAM8P,EACZrD,EAAM4L,KAAO,IAAM/J,EAAU,GAC/B,CAwPQiM,CAAkB9N,EAAOkK,EAAOlK,EAAM4L,MAClCwB,IACFpN,EAAM4L,KAAO,QAAUuB,EAAiB,IAAMnN,EAAM4L,WAG1D,IAAoB,oBAATtY,EAIX,IAAoB,uBAATA,EACT,OAAO,EAEP,GAAI0M,EAAM8I,YAAa,OAAO,EAC9B,MAAM,IAAInW,EAAc,0CAA4CW,EACtE,CARoB,MAAd0M,EAAMzM,KACRmY,EAAY1L,EAAOA,EAAM4L,KAAM1B,EAAOyB,EAAOnB,EAOjD,CAEA,GAAkB,OAAdxK,EAAMzM,KAA8B,MAAdyM,EAAMzM,IAAa,CAc3C,IAAIwa,EAASC,UACM,MAAjBhO,EAAMzM,IAAI,GAAayM,EAAMzM,IAAIiE,MAAM,GAAKwI,EAAMzM,KAClDyF,QAAQ,KAAM,OAGd+U,EADmB,MAAjB/N,EAAMzM,IAAI,GACH,IAAMwa,EACkB,uBAAxBA,EAAOvW,MAAM,EAAG,IAChB,KAAOuW,EAAOvW,MAAM,IAEpB,KAAOuW,EAAS,IAG3B/N,EAAM4L,KAAOmC,EAAS,IAAM/N,EAAM4L,IACpC,CACF,CAEA,OAAO,CACT,CAEA,SAASqC,EAAwBxX,EAAQuJ,GACvC,IAAMkO,EAAU,GACVC,EAAoB,GAE1BC,EAAY3X,EAAQyX,EAASC,GAG7B,IADA,IAAMrc,EAASqc,EAAkBrc,OACxBD,EAAQ,EAAGA,EAAQC,EAAQD,GAAS,EAC3CmO,EAAM2J,WAAWrU,KAAK4Y,EAAQC,EAAkBtc,KAElDmO,EAAM4J,eAAiB,IAAIhZ,MAAMkB,EACnC,CAEA,SAASsc,EAAa3X,EAAQyX,EAASC,GACrC,GAAe,OAAX1X,GAAqC,WAAlBzG,EAAOyG,GAAqB,CACjD,IAAM5E,EAAQqc,EAAQva,QAAQ8C,GAC9B,IAAc,IAAV5E,GACuC,IAArCsc,EAAkBxa,QAAQ9B,IAC5Bsc,EAAkB7Y,KAAKzD,QAKzB,GAFAqc,EAAQ5Y,KAAKmB,GAET7F,MAAMC,QAAQ4F,GAChB,IAAA,IAAS8G,EAAI,EAAGzL,EAAS2E,EAAO3E,OAAQyL,EAAIzL,EAAQyL,GAAK,EACvD6Q,EAAY3X,EAAO8G,GAAI2Q,EAASC,QAKlC,IAFA,IAAMb,EAAgB3b,OAAOC,KAAK6E,GAEzB8G,EAAI,EAAGzL,EAASwb,EAAcxb,OAAQyL,EAAIzL,EAAQyL,GAAK,EAC9D6Q,EAAY3X,EAAO6W,EAAc/P,IAAK2Q,EAASC,EAIvD,CACF,QAoBAE,GAAAzC,KAlBA,SAAe/Q,EAAOrH,GAGpB,IAAMwM,EAAQ,IAAIhB,EAFlBxL,EAAUA,GAAW,CAAA,GAIhBwM,EAAMoJ,QAAQ6E,EAAuBpT,EAAOmF,GAEjD,IAAI3I,EAAQwD,EAMZ,OAJImF,EAAMyJ,WACRpS,EAAQ2I,EAAMyJ,SAAS5W,KAAK,CAAE,GAAIwE,GAAS,GAAIA,IAG7C0V,EAAU/M,EAAO,EAAG3I,GAAO,GAAM,GAAc2I,EAAM4L,KAAO,KAEzD,EACT,6CCp6BA,IAAMxD,EAASjV,KACTkb,EAAS1Z,KAEf,SAAS2Z,EAASC,EAAMC,GACtB,OAAO,WACL,MAAM,IAAI5b,MAAM,iBAAmB2b,EAAO,sCAC1BC,EAAK,2CAEzB,QAEAC,EAAA/Z,KAAsB2B,IACtBoY,EAAAvZ,OAAwBoB,IACxBmY,EAAAC,gBAAiCxV,KACjCuV,EAAAE,YAA6B7S,KAC7B2S,EAAAG,YAA6B7S,KAC7B0S,EAAAjR,eAAgCqR,KAChCJ,EAAAnG,KAAsBF,EAAOE,KAC7BmG,EAAApG,QAAyBD,EAAOC,QAChCoG,EAAA7C,KAAsByC,EAAOzC,KAC7B6C,EAAA9b,cAA+Bmc,IAG/BL,EAAAM,MAAuB,CACrBjX,OAAQkX,KACRxW,MAAOyW,KACPxb,IAAKyb,KACLC,KAAMC,KACNzT,MAAO0T,KACPzT,IAAK0T,KACLhW,UAAWiW,KACXxY,KAAMyY,KACN9X,IAAK+X,KACLlV,MAAOmV,KACPrU,KAAMsU,KACNxZ,IAAKyZ,KACL1Z,IAAK2Z,KAIPpB,EAAAqB,SAA0BxB,EAAQ,WAAY,QAC9CG,EAAAsB,YAA6BzB,EAAQ,cAAe,WACpDG,EAAAuB,SAA0B1B,EAAQ,WAAY,cCxC5C5Z,GAcEub,GAdFvb,KACAQ,GAaE+a,GAbF/a,OACAwZ,GAYEuB,GAZFvB,gBACAC,GAWEsB,GAXFtB,YACAC,GAUEqB,GAVFrB,YACApR,GASEyS,GATFzS,eACA8K,GAQE2H,GARF3H,KACAD,GAOE4H,GAPF5H,QACAuD,GAMEqE,GANFrE,KACAjZ,GAKEsd,GALFtd,cACAoc,GAIEkB,GAJFlB,MACAe,GAGEG,GAHFH,SACAC,GAEEE,GAFFF,YACAC,GACEC,GADFD"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.mjs b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.mjs new file mode 100644 index 0000000..8621c75 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.mjs @@ -0,0 +1,3074 @@ +function getDefaultExportFromCjs(x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x; +} +var jsYaml = {}; +var loader = {}; +var common = {}; +var hasRequiredCommon; +function requireCommon() { + if (hasRequiredCommon) return common; + hasRequiredCommon = 1; + function isNothing(subject) { + return typeof subject === "undefined" || subject === null; + } + function isObject(subject) { + return typeof subject === "object" && subject !== null; + } + function toArray(sequence) { + if (Array.isArray(sequence)) return sequence; + else if (isNothing(sequence)) return []; + return [sequence]; + } + function extend(target, source) { + if (source) { + const sourceKeys = Object.keys(source); + for (let index = 0, length = sourceKeys.length; index < length; index += 1) { + const key = sourceKeys[index]; + target[key] = source[key]; + } + } + return target; + } + function repeat(string, count) { + let result = ""; + for (let cycle = 0; cycle < count; cycle += 1) { + result += string; + } + return result; + } + function isNegativeZero(number) { + return number === 0 && Number.NEGATIVE_INFINITY === 1 / number; + } + common.isNothing = isNothing; + common.isObject = isObject; + common.toArray = toArray; + common.repeat = repeat; + common.isNegativeZero = isNegativeZero; + common.extend = extend; + return common; +} +var exception; +var hasRequiredException; +function requireException() { + if (hasRequiredException) return exception; + hasRequiredException = 1; + function formatError(exception2, compact) { + let where = ""; + const message = exception2.reason || "(unknown reason)"; + if (!exception2.mark) return message; + if (exception2.mark.name) { + where += 'in "' + exception2.mark.name + '" '; + } + where += "(" + (exception2.mark.line + 1) + ":" + (exception2.mark.column + 1) + ")"; + if (!compact && exception2.mark.snippet) { + where += "\n\n" + exception2.mark.snippet; + } + return message + " " + where; + } + function YAMLException2(reason, mark) { + Error.call(this); + this.name = "YAMLException"; + this.reason = reason; + this.mark = mark; + this.message = formatError(this, false); + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } else { + this.stack = new Error().stack || ""; + } + } + YAMLException2.prototype = Object.create(Error.prototype); + YAMLException2.prototype.constructor = YAMLException2; + YAMLException2.prototype.toString = function toString(compact) { + return this.name + ": " + formatError(this, compact); + }; + exception = YAMLException2; + return exception; +} +var snippet; +var hasRequiredSnippet; +function requireSnippet() { + if (hasRequiredSnippet) return snippet; + hasRequiredSnippet = 1; + const common2 = requireCommon(); + function getLine(buffer, lineStart, lineEnd, position, maxLineLength) { + let head = ""; + let tail = ""; + const maxHalfLength = Math.floor(maxLineLength / 2) - 1; + if (position - lineStart > maxHalfLength) { + head = " ... "; + lineStart = position - maxHalfLength + head.length; + } + if (lineEnd - position > maxHalfLength) { + tail = " ..."; + lineEnd = position + maxHalfLength - tail.length; + } + return { + str: head + buffer.slice(lineStart, lineEnd).replace(/\t/g, "→") + tail, + pos: position - lineStart + head.length + // relative position + }; + } + function padStart(string, max) { + return common2.repeat(" ", max - string.length) + string; + } + function makeSnippet(mark, options) { + options = Object.create(options || null); + if (!mark.buffer) return null; + if (!options.maxLength) options.maxLength = 79; + if (typeof options.indent !== "number") options.indent = 1; + if (typeof options.linesBefore !== "number") options.linesBefore = 3; + if (typeof options.linesAfter !== "number") options.linesAfter = 2; + const re = /\r?\n|\r|\0/g; + const lineStarts = [0]; + const lineEnds = []; + let match; + let foundLineNo = -1; + while (match = re.exec(mark.buffer)) { + lineEnds.push(match.index); + lineStarts.push(match.index + match[0].length); + if (mark.position <= match.index && foundLineNo < 0) { + foundLineNo = lineStarts.length - 2; + } + } + if (foundLineNo < 0) foundLineNo = lineStarts.length - 1; + let result = ""; + const lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length; + const maxLineLength = options.maxLength - (options.indent + lineNoLength + 3); + for (let i = 1; i <= options.linesBefore; i++) { + if (foundLineNo - i < 0) break; + const line2 = getLine( + mark.buffer, + lineStarts[foundLineNo - i], + lineEnds[foundLineNo - i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]), + maxLineLength + ); + result = common2.repeat(" ", options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) + " | " + line2.str + "\n" + result; + } + const line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength); + result += common2.repeat(" ", options.indent) + padStart((mark.line + 1).toString(), lineNoLength) + " | " + line.str + "\n"; + result += common2.repeat("-", options.indent + lineNoLength + 3 + line.pos) + "^\n"; + for (let i = 1; i <= options.linesAfter; i++) { + if (foundLineNo + i >= lineEnds.length) break; + const line2 = getLine( + mark.buffer, + lineStarts[foundLineNo + i], + lineEnds[foundLineNo + i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]), + maxLineLength + ); + result += common2.repeat(" ", options.indent) + padStart((mark.line + i + 1).toString(), lineNoLength) + " | " + line2.str + "\n"; + } + return result.replace(/\n$/, ""); + } + snippet = makeSnippet; + return snippet; +} +var type; +var hasRequiredType; +function requireType() { + if (hasRequiredType) return type; + hasRequiredType = 1; + const YAMLException2 = requireException(); + const TYPE_CONSTRUCTOR_OPTIONS = [ + "kind", + "multi", + "resolve", + "construct", + "instanceOf", + "predicate", + "represent", + "representName", + "defaultStyle", + "styleAliases" + ]; + const YAML_NODE_KINDS = [ + "scalar", + "sequence", + "mapping" + ]; + function compileStyleAliases(map2) { + const result = {}; + if (map2 !== null) { + Object.keys(map2).forEach(function(style) { + map2[style].forEach(function(alias) { + result[String(alias)] = style; + }); + }); + } + return result; + } + function Type2(tag, options) { + options = options || {}; + Object.keys(options).forEach(function(name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new YAMLException2('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + this.options = options; + this.tag = tag; + this.kind = options["kind"] || null; + this.resolve = options["resolve"] || function() { + return true; + }; + this.construct = options["construct"] || function(data) { + return data; + }; + this.instanceOf = options["instanceOf"] || null; + this.predicate = options["predicate"] || null; + this.represent = options["represent"] || null; + this.representName = options["representName"] || null; + this.defaultStyle = options["defaultStyle"] || null; + this.multi = options["multi"] || false; + this.styleAliases = compileStyleAliases(options["styleAliases"] || null); + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new YAMLException2('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } + } + type = Type2; + return type; +} +var schema; +var hasRequiredSchema; +function requireSchema() { + if (hasRequiredSchema) return schema; + hasRequiredSchema = 1; + const YAMLException2 = requireException(); + const Type2 = requireType(); + function compileList(schema2, name) { + const result = []; + schema2[name].forEach(function(currentType) { + let newIndex = result.length; + result.forEach(function(previousType, previousIndex) { + if (previousType.tag === currentType.tag && previousType.kind === currentType.kind && previousType.multi === currentType.multi) { + newIndex = previousIndex; + } + }); + result[newIndex] = currentType; + }); + return result; + } + function compileMap() { + const result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {}, + multi: { + scalar: [], + sequence: [], + mapping: [], + fallback: [] + } + }; + function collectType(type2) { + if (type2.multi) { + result.multi[type2.kind].push(type2); + result.multi["fallback"].push(type2); + } else { + result[type2.kind][type2.tag] = result["fallback"][type2.tag] = type2; + } + } + for (let index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType); + } + return result; + } + function Schema2(definition) { + return this.extend(definition); + } + Schema2.prototype.extend = function extend(definition) { + let implicit = []; + let explicit = []; + if (definition instanceof Type2) { + explicit.push(definition); + } else if (Array.isArray(definition)) { + explicit = explicit.concat(definition); + } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) { + if (definition.implicit) implicit = implicit.concat(definition.implicit); + if (definition.explicit) explicit = explicit.concat(definition.explicit); + } else { + throw new YAMLException2("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })"); + } + implicit.forEach(function(type2) { + if (!(type2 instanceof Type2)) { + throw new YAMLException2("Specified list of YAML types (or a single Type object) contains a non-Type object."); + } + if (type2.loadKind && type2.loadKind !== "scalar") { + throw new YAMLException2("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported."); + } + if (type2.multi) { + throw new YAMLException2("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit."); + } + }); + explicit.forEach(function(type2) { + if (!(type2 instanceof Type2)) { + throw new YAMLException2("Specified list of YAML types (or a single Type object) contains a non-Type object."); + } + }); + const result = Object.create(Schema2.prototype); + result.implicit = (this.implicit || []).concat(implicit); + result.explicit = (this.explicit || []).concat(explicit); + result.compiledImplicit = compileList(result, "implicit"); + result.compiledExplicit = compileList(result, "explicit"); + result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit); + return result; + }; + schema = Schema2; + return schema; +} +var str; +var hasRequiredStr; +function requireStr() { + if (hasRequiredStr) return str; + hasRequiredStr = 1; + const Type2 = requireType(); + str = new Type2("tag:yaml.org,2002:str", { + kind: "scalar", + construct: function(data) { + return data !== null ? data : ""; + } + }); + return str; +} +var seq; +var hasRequiredSeq; +function requireSeq() { + if (hasRequiredSeq) return seq; + hasRequiredSeq = 1; + const Type2 = requireType(); + seq = new Type2("tag:yaml.org,2002:seq", { + kind: "sequence", + construct: function(data) { + return data !== null ? data : []; + } + }); + return seq; +} +var map; +var hasRequiredMap; +function requireMap() { + if (hasRequiredMap) return map; + hasRequiredMap = 1; + const Type2 = requireType(); + map = new Type2("tag:yaml.org,2002:map", { + kind: "mapping", + construct: function(data) { + return data !== null ? data : {}; + } + }); + return map; +} +var failsafe; +var hasRequiredFailsafe; +function requireFailsafe() { + if (hasRequiredFailsafe) return failsafe; + hasRequiredFailsafe = 1; + const Schema2 = requireSchema(); + failsafe = new Schema2({ + explicit: [ + requireStr(), + requireSeq(), + requireMap() + ] + }); + return failsafe; +} +var _null; +var hasRequired_null; +function require_null() { + if (hasRequired_null) return _null; + hasRequired_null = 1; + const Type2 = requireType(); + function resolveYamlNull(data) { + if (data === null) return true; + const max = data.length; + return max === 1 && data === "~" || max === 4 && (data === "null" || data === "Null" || data === "NULL"); + } + function constructYamlNull() { + return null; + } + function isNull(object) { + return object === null; + } + _null = new Type2("tag:yaml.org,2002:null", { + kind: "scalar", + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function() { + return "~"; + }, + lowercase: function() { + return "null"; + }, + uppercase: function() { + return "NULL"; + }, + camelcase: function() { + return "Null"; + }, + empty: function() { + return ""; + } + }, + defaultStyle: "lowercase" + }); + return _null; +} +var bool; +var hasRequiredBool; +function requireBool() { + if (hasRequiredBool) return bool; + hasRequiredBool = 1; + const Type2 = requireType(); + function resolveYamlBoolean(data) { + if (data === null) return false; + const max = data.length; + return max === 4 && (data === "true" || data === "True" || data === "TRUE") || max === 5 && (data === "false" || data === "False" || data === "FALSE"); + } + function constructYamlBoolean(data) { + return data === "true" || data === "True" || data === "TRUE"; + } + function isBoolean(object) { + return Object.prototype.toString.call(object) === "[object Boolean]"; + } + bool = new Type2("tag:yaml.org,2002:bool", { + kind: "scalar", + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function(object) { + return object ? "true" : "false"; + }, + uppercase: function(object) { + return object ? "TRUE" : "FALSE"; + }, + camelcase: function(object) { + return object ? "True" : "False"; + } + }, + defaultStyle: "lowercase" + }); + return bool; +} +var int; +var hasRequiredInt; +function requireInt() { + if (hasRequiredInt) return int; + hasRequiredInt = 1; + const common2 = requireCommon(); + const Type2 = requireType(); + function isHexCode(c) { + return c >= 48 && c <= 57 || c >= 65 && c <= 70 || c >= 97 && c <= 102; + } + function isOctCode(c) { + return c >= 48 && c <= 55; + } + function isDecCode(c) { + return c >= 48 && c <= 57; + } + function resolveYamlInteger(data) { + if (data === null) return false; + const max = data.length; + let index = 0; + let hasDigits = false; + if (!max) return false; + let ch = data[index]; + if (ch === "-" || ch === "+") { + ch = data[++index]; + } + if (ch === "0") { + if (index + 1 === max) return true; + ch = data[++index]; + if (ch === "b") { + index++; + for (; index < max; index++) { + ch = data[index]; + if (ch !== "0" && ch !== "1") return false; + hasDigits = true; + } + return hasDigits && isFinite(parseYamlInteger(data)); + } + if (ch === "x") { + index++; + for (; index < max; index++) { + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && isFinite(parseYamlInteger(data)); + } + if (ch === "o") { + index++; + for (; index < max; index++) { + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && isFinite(parseYamlInteger(data)); + } + } + for (; index < max; index++) { + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } + if (!hasDigits) return false; + return isFinite(parseYamlInteger(data)); + } + function parseYamlInteger(data) { + let value = data; + let sign = 1; + let ch = value[0]; + if (ch === "-" || ch === "+") { + if (ch === "-") sign = -1; + value = value.slice(1); + ch = value[0]; + } + if (value === "0") return 0; + if (ch === "0") { + if (value[1] === "b") return sign * parseInt(value.slice(2), 2); + if (value[1] === "x") return sign * parseInt(value.slice(2), 16); + if (value[1] === "o") return sign * parseInt(value.slice(2), 8); + } + return sign * parseInt(value, 10); + } + function constructYamlInteger(data) { + return parseYamlInteger(data); + } + function isInteger(object) { + return Object.prototype.toString.call(object) === "[object Number]" && (object % 1 === 0 && !common2.isNegativeZero(object)); + } + int = new Type2("tag:yaml.org,2002:int", { + kind: "scalar", + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function(obj) { + return obj >= 0 ? "0b" + obj.toString(2) : "-0b" + obj.toString(2).slice(1); + }, + octal: function(obj) { + return obj >= 0 ? "0o" + obj.toString(8) : "-0o" + obj.toString(8).slice(1); + }, + decimal: function(obj) { + return obj.toString(10); + }, + hexadecimal: function(obj) { + return obj >= 0 ? "0x" + obj.toString(16).toUpperCase() : "-0x" + obj.toString(16).toUpperCase().slice(1); + } + }, + defaultStyle: "decimal", + styleAliases: { + binary: [2, "bin"], + octal: [8, "oct"], + decimal: [10, "dec"], + hexadecimal: [16, "hex"] + } + }); + return int; +} +var float; +var hasRequiredFloat; +function requireFloat() { + if (hasRequiredFloat) return float; + hasRequiredFloat = 1; + const common2 = requireCommon(); + const Type2 = requireType(); + const YAML_FLOAT_PATTERN = new RegExp( + // 2.5e4, 2.5 and integers + "^(?:[-+]?(?:[0-9]+)(?:\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$" + ); + const YAML_FLOAT_SPECIAL_PATTERN = new RegExp( + "^(?:[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$" + ); + function resolveYamlFloat(data) { + if (data === null) return false; + if (!YAML_FLOAT_PATTERN.test(data)) { + return false; + } + if (isFinite(parseFloat(data, 10))) { + return true; + } + return YAML_FLOAT_SPECIAL_PATTERN.test(data); + } + function constructYamlFloat(data) { + let value = data.toLowerCase(); + const sign = value[0] === "-" ? -1 : 1; + if ("+-".indexOf(value[0]) >= 0) { + value = value.slice(1); + } + if (value === ".inf") { + return sign === 1 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + } else if (value === ".nan") { + return NaN; + } + return sign * parseFloat(value, 10); + } + const SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + function representYamlFloat(object, style) { + if (isNaN(object)) { + switch (style) { + case "lowercase": + return ".nan"; + case "uppercase": + return ".NAN"; + case "camelcase": + return ".NaN"; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case "lowercase": + return ".inf"; + case "uppercase": + return ".INF"; + case "camelcase": + return ".Inf"; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case "lowercase": + return "-.inf"; + case "uppercase": + return "-.INF"; + case "camelcase": + return "-.Inf"; + } + } else if (common2.isNegativeZero(object)) { + return "-0.0"; + } + const res = object.toString(10); + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace("e", ".e") : res; + } + function isFloat(object) { + return Object.prototype.toString.call(object) === "[object Number]" && (object % 1 !== 0 || common2.isNegativeZero(object)); + } + float = new Type2("tag:yaml.org,2002:float", { + kind: "scalar", + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: "lowercase" + }); + return float; +} +var json; +var hasRequiredJson; +function requireJson() { + if (hasRequiredJson) return json; + hasRequiredJson = 1; + json = requireFailsafe().extend({ + implicit: [ + require_null(), + requireBool(), + requireInt(), + requireFloat() + ] + }); + return json; +} +var core; +var hasRequiredCore; +function requireCore() { + if (hasRequiredCore) return core; + hasRequiredCore = 1; + core = requireJson(); + return core; +} +var timestamp; +var hasRequiredTimestamp; +function requireTimestamp() { + if (hasRequiredTimestamp) return timestamp; + hasRequiredTimestamp = 1; + const Type2 = requireType(); + const YAML_DATE_REGEXP = new RegExp( + "^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$" + ); + const YAML_TIMESTAMP_REGEXP = new RegExp( + "^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$" + ); + function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; + } + function constructYamlTimestamp(data) { + let fraction = 0; + let delta = null; + let match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + if (match === null) throw new Error("Date resolve error"); + const year = +match[1]; + const month = +match[2] - 1; + const day = +match[3]; + if (!match[4]) { + return new Date(Date.UTC(year, month, day)); + } + const hour = +match[4]; + const minute = +match[5]; + const second = +match[6]; + if (match[7]) { + fraction = match[7].slice(0, 3); + while (fraction.length < 3) { + fraction += "0"; + } + fraction = +fraction; + } + if (match[9]) { + const tzHour = +match[10]; + const tzMinute = +(match[11] || 0); + delta = (tzHour * 60 + tzMinute) * 6e4; + if (match[9] === "-") delta = -delta; + } + const date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + if (delta) date.setTime(date.getTime() - delta); + return date; + } + function representYamlTimestamp(object) { + return object.toISOString(); + } + timestamp = new Type2("tag:yaml.org,2002:timestamp", { + kind: "scalar", + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp + }); + return timestamp; +} +var merge; +var hasRequiredMerge; +function requireMerge() { + if (hasRequiredMerge) return merge; + hasRequiredMerge = 1; + const Type2 = requireType(); + function resolveYamlMerge(data) { + return data === "<<" || data === null; + } + merge = new Type2("tag:yaml.org,2002:merge", { + kind: "scalar", + resolve: resolveYamlMerge + }); + return merge; +} +var binary; +var hasRequiredBinary; +function requireBinary() { + if (hasRequiredBinary) return binary; + hasRequiredBinary = 1; + const Type2 = requireType(); + const BASE64_MAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r"; + function resolveYamlBinary(data) { + if (data === null) return false; + let bitlen = 0; + const max = data.length; + const map2 = BASE64_MAP; + for (let idx = 0; idx < max; idx++) { + const code = map2.indexOf(data.charAt(idx)); + if (code > 64) continue; + if (code < 0) return false; + bitlen += 6; + } + return bitlen % 8 === 0; + } + function constructYamlBinary(data) { + const input = data.replace(/[\r\n=]/g, ""); + const max = input.length; + const map2 = BASE64_MAP; + let bits = 0; + const result = []; + for (let idx = 0; idx < max; idx++) { + if (idx % 4 === 0 && idx) { + result.push(bits >> 16 & 255); + result.push(bits >> 8 & 255); + result.push(bits & 255); + } + bits = bits << 6 | map2.indexOf(input.charAt(idx)); + } + const tailbits = max % 4 * 6; + if (tailbits === 0) { + result.push(bits >> 16 & 255); + result.push(bits >> 8 & 255); + result.push(bits & 255); + } else if (tailbits === 18) { + result.push(bits >> 10 & 255); + result.push(bits >> 2 & 255); + } else if (tailbits === 12) { + result.push(bits >> 4 & 255); + } + return new Uint8Array(result); + } + function representYamlBinary(object) { + let result = ""; + let bits = 0; + const max = object.length; + const map2 = BASE64_MAP; + for (let idx = 0; idx < max; idx++) { + if (idx % 3 === 0 && idx) { + result += map2[bits >> 18 & 63]; + result += map2[bits >> 12 & 63]; + result += map2[bits >> 6 & 63]; + result += map2[bits & 63]; + } + bits = (bits << 8) + object[idx]; + } + const tail = max % 3; + if (tail === 0) { + result += map2[bits >> 18 & 63]; + result += map2[bits >> 12 & 63]; + result += map2[bits >> 6 & 63]; + result += map2[bits & 63]; + } else if (tail === 2) { + result += map2[bits >> 10 & 63]; + result += map2[bits >> 4 & 63]; + result += map2[bits << 2 & 63]; + result += map2[64]; + } else if (tail === 1) { + result += map2[bits >> 2 & 63]; + result += map2[bits << 4 & 63]; + result += map2[64]; + result += map2[64]; + } + return result; + } + function isBinary(obj) { + return Object.prototype.toString.call(obj) === "[object Uint8Array]"; + } + binary = new Type2("tag:yaml.org,2002:binary", { + kind: "scalar", + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary + }); + return binary; +} +var omap; +var hasRequiredOmap; +function requireOmap() { + if (hasRequiredOmap) return omap; + hasRequiredOmap = 1; + const Type2 = requireType(); + const _hasOwnProperty = Object.prototype.hasOwnProperty; + const _toString = Object.prototype.toString; + function resolveYamlOmap(data) { + if (data === null) return true; + const objectKeys = {}; + const object = data; + for (let index = 0, length = object.length; index < length; index += 1) { + const pair = object[index]; + let pairHasKey = false; + if (_toString.call(pair) !== "[object Object]") return false; + let pairKey; + for (pairKey in pair) { + if (_hasOwnProperty.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; + else return false; + } + } + if (!pairHasKey) return false; + if (_hasOwnProperty.call(objectKeys, pairKey)) return false; + Object.defineProperty(objectKeys, pairKey, { value: true }); + } + return true; + } + function constructYamlOmap(data) { + return data !== null ? data : []; + } + omap = new Type2("tag:yaml.org,2002:omap", { + kind: "sequence", + resolve: resolveYamlOmap, + construct: constructYamlOmap + }); + return omap; +} +var pairs; +var hasRequiredPairs; +function requirePairs() { + if (hasRequiredPairs) return pairs; + hasRequiredPairs = 1; + const Type2 = requireType(); + const _toString = Object.prototype.toString; + function resolveYamlPairs(data) { + if (data === null) return true; + const object = data; + const result = new Array(object.length); + for (let index = 0, length = object.length; index < length; index += 1) { + const pair = object[index]; + if (_toString.call(pair) !== "[object Object]") return false; + const keys = Object.keys(pair); + if (keys.length !== 1) return false; + result[index] = [keys[0], pair[keys[0]]]; + } + return true; + } + function constructYamlPairs(data) { + if (data === null) return []; + const object = data; + const result = new Array(object.length); + for (let index = 0, length = object.length; index < length; index += 1) { + const pair = object[index]; + const keys = Object.keys(pair); + result[index] = [keys[0], pair[keys[0]]]; + } + return result; + } + pairs = new Type2("tag:yaml.org,2002:pairs", { + kind: "sequence", + resolve: resolveYamlPairs, + construct: constructYamlPairs + }); + return pairs; +} +var set; +var hasRequiredSet; +function requireSet() { + if (hasRequiredSet) return set; + hasRequiredSet = 1; + const Type2 = requireType(); + const _hasOwnProperty = Object.prototype.hasOwnProperty; + function resolveYamlSet(data) { + if (data === null) return true; + const object = data; + for (const key in object) { + if (_hasOwnProperty.call(object, key)) { + if (object[key] !== null) return false; + } + } + return true; + } + function constructYamlSet(data) { + return data !== null ? data : {}; + } + set = new Type2("tag:yaml.org,2002:set", { + kind: "mapping", + resolve: resolveYamlSet, + construct: constructYamlSet + }); + return set; +} +var _default; +var hasRequired_default; +function require_default() { + if (hasRequired_default) return _default; + hasRequired_default = 1; + _default = requireCore().extend({ + implicit: [ + requireTimestamp(), + requireMerge() + ], + explicit: [ + requireBinary(), + requireOmap(), + requirePairs(), + requireSet() + ] + }); + return _default; +} +var hasRequiredLoader; +function requireLoader() { + if (hasRequiredLoader) return loader; + hasRequiredLoader = 1; + const common2 = requireCommon(); + const YAMLException2 = requireException(); + const makeSnippet = requireSnippet(); + const DEFAULT_SCHEMA2 = require_default(); + const _hasOwnProperty = Object.prototype.hasOwnProperty; + const CONTEXT_FLOW_IN = 1; + const CONTEXT_FLOW_OUT = 2; + const CONTEXT_BLOCK_IN = 3; + const CONTEXT_BLOCK_OUT = 4; + const CHOMPING_CLIP = 1; + const CHOMPING_STRIP = 2; + const CHOMPING_KEEP = 3; + const PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; + const PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; + const PATTERN_FLOW_INDICATORS = /[,\[\]{}]/; + const PATTERN_TAG_HANDLE = /^(?:!|!!|![0-9A-Za-z-]+!)$/; + const PATTERN_TAG_URI = /^(?:!|[^,\[\]{}])(?:%[0-9a-f]{2}|[0-9a-z\-#;/?:@&=+$,_.!~*'()\[\]])*$/i; + function _class(obj) { + return Object.prototype.toString.call(obj); + } + function isEol(c) { + return c === 10 || c === 13; + } + function isWhiteSpace(c) { + return c === 9 || c === 32; + } + function isWsOrEol(c) { + return c === 9 || c === 32 || c === 10 || c === 13; + } + function isFlowIndicator(c) { + return c === 44 || c === 91 || c === 93 || c === 123 || c === 125; + } + function fromHexCode(c) { + if (c >= 48 && c <= 57) { + return c - 48; + } + const lc = c | 32; + if (lc >= 97 && lc <= 102) { + return lc - 97 + 10; + } + return -1; + } + function escapedHexLen(c) { + if (c === 120) { + return 2; + } + if (c === 117) { + return 4; + } + if (c === 85) { + return 8; + } + return 0; + } + function fromDecimalCode(c) { + if (c >= 48 && c <= 57) { + return c - 48; + } + return -1; + } + function simpleEscapeSequence(c) { + switch (c) { + case 48: + return "\0"; + case 97: + return "\x07"; + case 98: + return "\b"; + case 116: + return " "; + case 9: + return " "; + case 110: + return "\n"; + case 118: + return "\v"; + case 102: + return "\f"; + case 114: + return "\r"; + case 101: + return "\x1B"; + case 32: + return " "; + case 34: + return '"'; + case 47: + return "/"; + case 92: + return "\\"; + case 78: + return "…"; + case 95: + return " "; + case 76: + return "\u2028"; + case 80: + return "\u2029"; + default: + return ""; + } + } + function charFromCodepoint(c) { + if (c <= 65535) { + return String.fromCharCode(c); + } + return String.fromCharCode( + (c - 65536 >> 10) + 55296, + (c - 65536 & 1023) + 56320 + ); + } + function setProperty(object, key, value) { + if (key === "__proto__") { + Object.defineProperty(object, key, { + configurable: true, + enumerable: true, + writable: true, + value + }); + } else { + object[key] = value; + } + } + const simpleEscapeCheck = new Array(256); + const simpleEscapeMap = new Array(256); + for (let i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; + simpleEscapeMap[i] = simpleEscapeSequence(i); + } + function State(input, options) { + this.input = input; + this.filename = options["filename"] || null; + this.schema = options["schema"] || DEFAULT_SCHEMA2; + this.onWarning = options["onWarning"] || null; + this.legacy = options["legacy"] || false; + this.json = options["json"] || false; + this.listener = options["listener"] || null; + this.maxDepth = typeof options["maxDepth"] === "number" ? options["maxDepth"] : 100; + this.maxTotalMergeKeys = typeof options["maxTotalMergeKeys"] === "number" ? options["maxTotalMergeKeys"] : 1e4; + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + this.length = input.length; + this.position = 0; + this.line = 0; + this.lineStart = 0; + this.lineIndent = 0; + this.depth = 0; + this.totalMergeKeys = 0; + this.firstTabInLine = -1; + this.documents = []; + this.anchorMapTransactions = []; + } + function generateError(state, message) { + const mark = { + name: state.filename, + buffer: state.input.slice(0, -1), + // omit trailing \0 + position: state.position, + line: state.line, + column: state.position - state.lineStart + }; + mark.snippet = makeSnippet(mark); + return new YAMLException2(message, mark); + } + function throwError(state, message) { + throw generateError(state, message); + } + function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); + } + } + function storeAnchor(state, name, value) { + const transactions = state.anchorMapTransactions; + if (transactions.length !== 0) { + const transaction = transactions[transactions.length - 1]; + if (!_hasOwnProperty.call(transaction, name)) { + transaction[name] = { + existed: _hasOwnProperty.call(state.anchorMap, name), + value: state.anchorMap[name] + }; + } + } + state.anchorMap[name] = value; + } + function beginAnchorTransaction(state) { + state.anchorMapTransactions.push(/* @__PURE__ */ Object.create(null)); + } + function commitAnchorTransaction(state) { + const transaction = state.anchorMapTransactions.pop(); + const transactions = state.anchorMapTransactions; + if (transactions.length === 0) return; + const parent = transactions[transactions.length - 1]; + const names = Object.keys(transaction); + for (let index = 0, length = names.length; index < length; index += 1) { + const name = names[index]; + if (!_hasOwnProperty.call(parent, name)) { + parent[name] = transaction[name]; + } + } + } + function rollbackAnchorTransaction(state) { + const transaction = state.anchorMapTransactions.pop(); + const names = Object.keys(transaction); + for (let index = names.length - 1; index >= 0; index -= 1) { + const entry = transaction[names[index]]; + if (entry.existed) { + state.anchorMap[names[index]] = entry.value; + } else { + delete state.anchorMap[names[index]]; + } + } + } + function snapshotState(state) { + return { + position: state.position, + line: state.line, + lineStart: state.lineStart, + lineIndent: state.lineIndent, + firstTabInLine: state.firstTabInLine, + tag: state.tag, + anchor: state.anchor, + kind: state.kind, + result: state.result + }; + } + function restoreState(state, snapshot) { + state.position = snapshot.position; + state.line = snapshot.line; + state.lineStart = snapshot.lineStart; + state.lineIndent = snapshot.lineIndent; + state.firstTabInLine = snapshot.firstTabInLine; + state.tag = snapshot.tag; + state.anchor = snapshot.anchor; + state.kind = snapshot.kind; + state.result = snapshot.result; + } + const directiveHandlers = { + YAML: function handleYamlDirective(state, name, args) { + if (state.version !== null) { + throwError(state, "duplication of %YAML directive"); + } + if (args.length !== 1) { + throwError(state, "YAML directive accepts exactly one argument"); + } + const match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + if (match === null) { + throwError(state, "ill-formed argument of the YAML directive"); + } + const major = parseInt(match[1], 10); + const minor = parseInt(match[2], 10); + if (major !== 1) { + throwError(state, "unacceptable YAML version of the document"); + } + state.version = args[0]; + state.checkLineBreaks = minor < 2; + if (minor !== 1 && minor !== 2) { + throwWarning(state, "unsupported YAML version of the document"); + } + }, + TAG: function handleTagDirective(state, name, args) { + let prefix; + if (args.length !== 2) { + throwError(state, "TAG directive accepts exactly two arguments"); + } + const handle = args[0]; + prefix = args[1]; + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, "ill-formed tag handle (first argument) of the TAG directive"); + } + if (_hasOwnProperty.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); + } + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, "ill-formed tag prefix (second argument) of the TAG directive"); + } + try { + prefix = decodeURIComponent(prefix); + } catch (err) { + throwError(state, "tag prefix is malformed: " + prefix); + } + state.tagMap[handle] = prefix; + } + }; + function captureSegment(state, start, end, checkJson) { + if (start < end) { + const _result = state.input.slice(start, end); + if (checkJson) { + for (let _position = 0, _length = _result.length; _position < _length; _position += 1) { + const _character = _result.charCodeAt(_position); + if (!(_character === 9 || _character >= 32 && _character <= 1114111)) { + throwError(state, "expected valid JSON character"); + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, "the stream contains non-printable characters"); + } + state.result += _result; + } + } + function mergeMappings(state, destination, source, overridableKeys) { + if (!common2.isObject(source)) { + throwError(state, "cannot merge mappings; the provided source object is unacceptable"); + } + const sourceKeys = Object.keys(source); + for (let index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + const key = sourceKeys[index]; + if (state.maxTotalMergeKeys !== -1 && ++state.totalMergeKeys > state.maxTotalMergeKeys) { + throwError(state, "merge keys exceeded maxTotalMergeKeys (" + state.maxTotalMergeKeys + ")"); + } + if (!_hasOwnProperty.call(destination, key)) { + setProperty(destination, key, source[key]); + overridableKeys[key] = true; + } + } + } + function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, startLine, startLineStart, startPos) { + if (Array.isArray(keyNode)) { + keyNode = Array.prototype.slice.call(keyNode); + for (let index = 0, quantity = keyNode.length; index < quantity; index += 1) { + if (Array.isArray(keyNode[index])) { + throwError(state, "nested arrays are not supported inside keys"); + } + if (typeof keyNode === "object" && _class(keyNode[index]) === "[object Object]") { + keyNode[index] = "[object Object]"; + } + } + } + if (typeof keyNode === "object" && _class(keyNode) === "[object Object]") { + keyNode = "[object Object]"; + } + keyNode = String(keyNode); + if (_result === null) { + _result = {}; + } + if (keyTag === "tag:yaml.org,2002:merge") { + if (Array.isArray(valueNode)) { + for (let index = 0, quantity = valueNode.length; index < quantity; index += 1) { + mergeMappings(state, _result, valueNode[index], overridableKeys); + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys); + } + } else { + if (!state.json && !_hasOwnProperty.call(overridableKeys, keyNode) && _hasOwnProperty.call(_result, keyNode)) { + state.line = startLine || state.line; + state.lineStart = startLineStart || state.lineStart; + state.position = startPos || state.position; + throwError(state, "duplicated mapping key"); + } + setProperty(_result, keyNode, valueNode); + delete overridableKeys[keyNode]; + } + return _result; + } + function readLineBreak(state) { + const ch = state.input.charCodeAt(state.position); + if (ch === 10) { + state.position++; + } else if (ch === 13) { + state.position++; + if (state.input.charCodeAt(state.position) === 10) { + state.position++; + } + } else { + throwError(state, "a line break is expected"); + } + state.line += 1; + state.lineStart = state.position; + state.firstTabInLine = -1; + } + function skipSeparationSpace(state, allowComments, checkIndent) { + let lineBreaks = 0; + let ch = state.input.charCodeAt(state.position); + while (ch !== 0) { + while (isWhiteSpace(ch)) { + if (ch === 9 && state.firstTabInLine === -1) { + state.firstTabInLine = state.position; + } + ch = state.input.charCodeAt(++state.position); + } + if (allowComments && ch === 35) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 10 && ch !== 13 && ch !== 0); + } + if (isEol(ch)) { + readLineBreak(state); + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; + while (ch === 32) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, "deficient indentation"); + } + return lineBreaks; + } + function testDocumentSeparator(state) { + let _position = state.position; + let ch = state.input.charCodeAt(_position); + if ((ch === 45 || ch === 46) && ch === state.input.charCodeAt(_position + 1) && ch === state.input.charCodeAt(_position + 2)) { + _position += 3; + ch = state.input.charCodeAt(_position); + if (ch === 0 || isWsOrEol(ch)) { + return true; + } + } + return false; + } + function writeFoldedLines(state, count) { + if (count === 1) { + state.result += " "; + } else if (count > 1) { + state.result += common2.repeat("\n", count - 1); + } + } + function readPlainScalar(state, nodeIndent, withinFlowCollection) { + let captureStart; + let captureEnd; + let hasPendingContent; + let _line; + let _lineStart; + let _lineIndent; + const _kind = state.kind; + const _result = state.result; + let ch = state.input.charCodeAt(state.position); + if (isWsOrEol(ch) || isFlowIndicator(ch) || ch === 35 || ch === 38 || ch === 42 || ch === 33 || ch === 124 || ch === 62 || ch === 39 || ch === 34 || ch === 37 || ch === 64 || ch === 96) { + return false; + } + if (ch === 63 || ch === 45) { + const following = state.input.charCodeAt(state.position + 1); + if (isWsOrEol(following) || withinFlowCollection && isFlowIndicator(following)) { + return false; + } + } + state.kind = "scalar"; + state.result = ""; + captureStart = captureEnd = state.position; + hasPendingContent = false; + while (ch !== 0) { + if (ch === 58) { + const following = state.input.charCodeAt(state.position + 1); + if (isWsOrEol(following) || withinFlowCollection && isFlowIndicator(following)) { + break; + } + } else if (ch === 35) { + const preceding = state.input.charCodeAt(state.position - 1); + if (isWsOrEol(preceding)) { + break; + } + } else if (state.position === state.lineStart && testDocumentSeparator(state) || withinFlowCollection && isFlowIndicator(ch)) { + break; + } else if (isEol(ch)) { + _line = state.line; + _lineStart = state.lineStart; + _lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = _line; + state.lineStart = _lineStart; + state.lineIndent = _lineIndent; + break; + } + } + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - _line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } + if (!isWhiteSpace(ch)) { + captureEnd = state.position + 1; + } + ch = state.input.charCodeAt(++state.position); + } + captureSegment(state, captureStart, captureEnd, false); + if (state.result) { + return true; + } + state.kind = _kind; + state.result = _result; + return false; + } + function readSingleQuotedScalar(state, nodeIndent) { + let captureStart; + let captureEnd; + let ch = state.input.charCodeAt(state.position); + if (ch !== 39) { + return false; + } + state.kind = "scalar"; + state.result = ""; + state.position++; + captureStart = captureEnd = state.position; + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 39) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + if (ch === 39) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + } else if (isEol(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, "unexpected end of the document within a single quoted scalar"); + } else { + state.position++; + if (!isWhiteSpace(ch)) { + captureEnd = state.position; + } + } + } + throwError(state, "unexpected end of the stream within a single quoted scalar"); + } + function readDoubleQuotedScalar(state, nodeIndent) { + let captureStart; + let captureEnd; + let tmp; + let ch = state.input.charCodeAt(state.position); + if (ch !== 34) { + return false; + } + state.kind = "scalar"; + state.result = ""; + state.position++; + captureStart = captureEnd = state.position; + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 34) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + } else if (ch === 92) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + if (isEol(ch)) { + skipSeparationSpace(state, false, nodeIndent); + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; + } else if ((tmp = escapedHexLen(ch)) > 0) { + let hexLength = tmp; + let hexResult = 0; + for (; hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position); + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; + } else { + throwError(state, "expected hexadecimal character"); + } + } + state.result += charFromCodepoint(hexResult); + state.position++; + } else { + throwError(state, "unknown escape sequence"); + } + captureStart = captureEnd = state.position; + } else if (isEol(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, "unexpected end of the document within a double quoted scalar"); + } else { + state.position++; + if (!isWhiteSpace(ch)) { + captureEnd = state.position; + } + } + } + throwError(state, "unexpected end of the stream within a double quoted scalar"); + } + function readFlowCollection(state, nodeIndent) { + let readNext = true; + let _line; + let _lineStart; + let _pos; + const _tag = state.tag; + let _result; + const _anchor = state.anchor; + let terminator; + let isPair; + let isExplicitPair; + let isMapping; + const overridableKeys = /* @__PURE__ */ Object.create(null); + let keyNode; + let keyTag; + let valueNode; + let ch = state.input.charCodeAt(state.position); + if (ch === 91) { + terminator = 93; + isMapping = false; + _result = []; + } else if (ch === 123) { + terminator = 125; + isMapping = true; + _result = {}; + } else { + return false; + } + if (state.anchor !== null) { + storeAnchor(state, state.anchor, _result); + } + ch = state.input.charCodeAt(++state.position); + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent); + ch = state.input.charCodeAt(state.position); + if (ch === terminator) { + state.position++; + state.tag = _tag; + state.anchor = _anchor; + state.kind = isMapping ? "mapping" : "sequence"; + state.result = _result; + return true; + } else if (!readNext) { + throwError(state, "missed comma between flow collection entries"); + } else if (ch === 44) { + throwError(state, "expected the node content, but found ','"); + } + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; + if (ch === 63) { + const following = state.input.charCodeAt(state.position + 1); + if (isWsOrEol(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } + _line = state.line; + _lineStart = state.lineStart; + _pos = state.position; + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + keyTag = state.tag; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + ch = state.input.charCodeAt(state.position); + if ((isExplicitPair || state.line === _line) && ch === 58) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + valueNode = state.result; + } + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos); + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)); + } else { + _result.push(keyNode); + } + skipSeparationSpace(state, true, nodeIndent); + ch = state.input.charCodeAt(state.position); + if (ch === 44) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } + throwError(state, "unexpected end of the stream within a flow collection"); + } + function readBlockScalar(state, nodeIndent) { + let folding; + let chomping = CHOMPING_CLIP; + let didReadContent = false; + let detectedIndent = false; + let textIndent = nodeIndent; + let emptyLines = 0; + let atMoreIndented = false; + let tmp; + let ch = state.input.charCodeAt(state.position); + if (ch === 124) { + folding = false; + } else if (ch === 62) { + folding = true; + } else { + return false; + } + state.kind = "scalar"; + state.result = ""; + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position); + if (ch === 43 || ch === 45) { + if (CHOMPING_CLIP === chomping) { + chomping = ch === 43 ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + throwError(state, "repeat of a chomping mode identifier"); + } + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, "bad explicit indentation width of a block scalar; it cannot be less than one"); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + throwError(state, "repeat of an indentation width identifier"); + } + } else { + break; + } + } + if (isWhiteSpace(ch)) { + do { + ch = state.input.charCodeAt(++state.position); + } while (isWhiteSpace(ch)); + if (ch === 35) { + do { + ch = state.input.charCodeAt(++state.position); + } while (!isEol(ch) && ch !== 0); + } + } + while (ch !== 0) { + readLineBreak(state); + state.lineIndent = 0; + ch = state.input.charCodeAt(state.position); + while ((!detectedIndent || state.lineIndent < textIndent) && ch === 32) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } + if (isEol(ch)) { + emptyLines++; + continue; + } + if (!detectedIndent && textIndent === 0) { + throwError(state, "missing indentation for block scalar"); + } + if (state.lineIndent < textIndent) { + if (chomping === CHOMPING_KEEP) { + state.result += common2.repeat("\n", didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { + state.result += "\n"; + } + } + break; + } + if (folding) { + if (isWhiteSpace(ch)) { + atMoreIndented = true; + state.result += common2.repeat("\n", didReadContent ? 1 + emptyLines : emptyLines); + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += common2.repeat("\n", emptyLines + 1); + } else if (emptyLines === 0) { + if (didReadContent) { + state.result += " "; + } + } else { + state.result += common2.repeat("\n", emptyLines); + } + } else { + state.result += common2.repeat("\n", didReadContent ? 1 + emptyLines : emptyLines); + } + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + const captureStart = state.position; + while (!isEol(ch) && ch !== 0) { + ch = state.input.charCodeAt(++state.position); + } + captureSegment(state, captureStart, state.position, false); + } + return true; + } + function readBlockSequence(state, nodeIndent) { + const _tag = state.tag; + const _anchor = state.anchor; + const _result = []; + let detected = false; + if (state.firstTabInLine !== -1) return false; + if (state.anchor !== null) { + storeAnchor(state, state.anchor, _result); + } + let ch = state.input.charCodeAt(state.position); + while (ch !== 0) { + if (state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, "tab characters must not be used in indentation"); + } + if (ch !== 45) { + break; + } + const following = state.input.charCodeAt(state.position + 1); + if (!isWsOrEol(following)) { + break; + } + detected = true; + state.position++; + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } + const _line = state.line; + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); + _result.push(state.result); + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + if ((state.line === _line || state.lineIndent > nodeIndent) && ch !== 0) { + throwError(state, "bad indentation of a sequence entry"); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = "sequence"; + state.result = _result; + return true; + } + return false; + } + function readBlockMapping(state, nodeIndent, flowIndent) { + let allowCompact; + let _keyLine; + let _keyLineStart; + let _keyPos; + const _tag = state.tag; + const _anchor = state.anchor; + const _result = {}; + const overridableKeys = /* @__PURE__ */ Object.create(null); + let keyTag = null; + let keyNode = null; + let valueNode = null; + let atExplicitKey = false; + let detected = false; + if (state.firstTabInLine !== -1) return false; + if (state.anchor !== null) { + storeAnchor(state, state.anchor, _result); + } + let ch = state.input.charCodeAt(state.position); + while (ch !== 0) { + if (!atExplicitKey && state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, "tab characters must not be used in indentation"); + } + const following = state.input.charCodeAt(state.position + 1); + const _line = state.line; + if ((ch === 63 || ch === 58) && isWsOrEol(following)) { + if (ch === 63) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + detected = true; + atExplicitKey = true; + allowCompact = true; + } else if (atExplicitKey) { + atExplicitKey = false; + allowCompact = true; + } else { + throwError(state, "incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line"); + } + state.position += 1; + ch = following; + } else { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + break; + } + if (state.line === _line) { + ch = state.input.charCodeAt(state.position); + while (isWhiteSpace(ch)) { + ch = state.input.charCodeAt(++state.position); + } + if (ch === 58) { + ch = state.input.charCodeAt(++state.position); + if (!isWsOrEol(ch)) { + throwError(state, "a whitespace character is expected after the key-value separator within a block mapping"); + } + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; + } else if (detected) { + throwError(state, "can not read an implicit mapping pair; a colon is missed"); + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; + } + } else if (detected) { + throwError(state, "can not read a block mapping entry; a multiline key may not be an implicit key"); + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; + } + } + if (state.line === _line || state.lineIndent > nodeIndent) { + if (atExplicitKey) { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + } + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } + if ((state.line === _line || state.lineIndent > nodeIndent) && ch !== 0) { + throwError(state, "bad indentation of a mapping entry"); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + } + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = "mapping"; + state.result = _result; + } + return detected; + } + function readTagProperty(state) { + let isVerbatim = false; + let isNamed = false; + let tagHandle; + let tagName; + let ch = state.input.charCodeAt(state.position); + if (ch !== 33) return false; + if (state.tag !== null) { + throwError(state, "duplication of a tag property"); + } + ch = state.input.charCodeAt(++state.position); + if (ch === 60) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + } else if (ch === 33) { + isNamed = true; + tagHandle = "!!"; + ch = state.input.charCodeAt(++state.position); + } else { + tagHandle = "!"; + } + let _position = state.position; + if (isVerbatim) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0 && ch !== 62); + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + throwError(state, "unexpected end of the stream within a verbatim tag"); + } + } else { + while (ch !== 0 && !isWsOrEol(ch)) { + if (ch === 33) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1); + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, "named tag handle cannot contain such characters"); + } + isNamed = true; + _position = state.position + 1; + } else { + throwError(state, "tag suffix cannot contain exclamation marks"); + } + } + ch = state.input.charCodeAt(++state.position); + } + tagName = state.input.slice(_position, state.position); + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, "tag suffix cannot contain flow indicator characters"); + } + } + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, "tag name cannot contain such characters: " + tagName); + } + try { + tagName = decodeURIComponent(tagName); + } catch (err) { + throwError(state, "tag name is malformed: " + tagName); + } + if (isVerbatim) { + state.tag = tagName; + } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; + } else if (tagHandle === "!") { + state.tag = "!" + tagName; + } else if (tagHandle === "!!") { + state.tag = "tag:yaml.org,2002:" + tagName; + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"'); + } + return true; + } + function readAnchorProperty(state) { + let ch = state.input.charCodeAt(state.position); + if (ch !== 38) return false; + if (state.anchor !== null) { + throwError(state, "duplication of an anchor property"); + } + ch = state.input.charCodeAt(++state.position); + const _position = state.position; + while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) { + ch = state.input.charCodeAt(++state.position); + } + if (state.position === _position) { + throwError(state, "name of an anchor node must contain at least one character"); + } + state.anchor = state.input.slice(_position, state.position); + return true; + } + function readAlias(state) { + let ch = state.input.charCodeAt(state.position); + if (ch !== 42) return false; + ch = state.input.charCodeAt(++state.position); + const _position = state.position; + while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) { + ch = state.input.charCodeAt(++state.position); + } + if (state.position === _position) { + throwError(state, "name of an alias node must contain at least one character"); + } + const alias = state.input.slice(_position, state.position); + if (!_hasOwnProperty.call(state.anchorMap, alias)) { + throwError(state, 'unidentified alias "' + alias + '"'); + } + state.result = state.anchorMap[alias]; + skipSeparationSpace(state, true, -1); + return true; + } + function tryReadBlockMappingFromProperty(state, propertyStart, nodeIndent, flowIndent) { + const fallbackState = snapshotState(state); + beginAnchorTransaction(state); + restoreState(state, propertyStart); + state.tag = null; + state.anchor = null; + state.kind = null; + state.result = null; + if (readBlockMapping(state, nodeIndent, flowIndent) && state.kind === "mapping") { + commitAnchorTransaction(state); + return true; + } + rollbackAnchorTransaction(state); + restoreState(state, fallbackState); + return false; + } + function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + let allowBlockScalars; + let allowBlockCollections; + let indentStatus = 1; + let atNewLine = false; + let hasContent = false; + let propertyStart = null; + let type2; + let flowIndent; + let blockIndent; + if (state.depth >= state.maxDepth) { + throwError(state, "nesting exceeded maxDepth (" + state.maxDepth + ")"); + } + state.depth += 1; + if (state.listener !== null) { + state.listener("open", state); + } + state.tag = null; + state.anchor = null; + state.kind = null; + state.result = null; + const allowBlockStyles = allowBlockScalars = allowBlockCollections = CONTEXT_BLOCK_OUT === nodeContext || CONTEXT_BLOCK_IN === nodeContext; + if (allowToSeek) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } + if (indentStatus === 1) { + while (true) { + const ch = state.input.charCodeAt(state.position); + const propertyState = snapshotState(state); + if (atNewLine && (ch === 33 && state.tag !== null || ch === 38 && state.anchor !== null)) { + break; + } + if (!readTagProperty(state) && !readAnchorProperty(state)) { + break; + } + if (propertyStart === null) { + propertyStart = propertyState; + } + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent; + } else { + flowIndent = parentIndent + 1; + } + blockIndent = state.position - state.lineStart; + if (indentStatus === 1) { + if (allowBlockCollections && (readBlockSequence(state, blockIndent) || readBlockMapping(state, blockIndent, flowIndent)) || readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + const ch = state.input.charCodeAt(state.position); + if (propertyStart !== null && allowBlockStyles && !allowBlockCollections && ch !== 124 && ch !== 62 && tryReadBlockMappingFromProperty( + state, + propertyStart, + propertyStart.position - propertyStart.lineStart, + flowIndent + )) { + hasContent = true; + } else if (allowBlockScalars && readBlockScalar(state, flowIndent) || readSingleQuotedScalar(state, flowIndent) || readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + } else if (readAlias(state)) { + hasContent = true; + if (state.tag !== null || state.anchor !== null) { + throwError(state, "alias node should not have any properties"); + } + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true; + if (state.tag === null) { + state.tag = "?"; + } + } + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result); + } + } + } else if (indentStatus === 0) { + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } + if (state.tag === null) { + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result); + } + } else if (state.tag === "?") { + if (state.result !== null && state.kind !== "scalar") { + throwError(state, 'unacceptable node kind for ! tag; it should be "scalar", not "' + state.kind + '"'); + } + for (let typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) { + type2 = state.implicitTypes[typeIndex]; + if (type2.resolve(state.result)) { + state.result = type2.construct(state.result); + state.tag = type2.tag; + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result); + } + break; + } + } + } else if (state.tag !== "!") { + if (_hasOwnProperty.call(state.typeMap[state.kind || "fallback"], state.tag)) { + type2 = state.typeMap[state.kind || "fallback"][state.tag]; + } else { + type2 = null; + const typeList = state.typeMap.multi[state.kind || "fallback"]; + for (let typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) { + if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) { + type2 = typeList[typeIndex]; + break; + } + } + } + if (!type2) { + throwError(state, "unknown tag !<" + state.tag + ">"); + } + if (state.result !== null && type2.kind !== state.kind) { + throwError(state, "unacceptable node kind for !<" + state.tag + '> tag; it should be "' + type2.kind + '", not "' + state.kind + '"'); + } + if (!type2.resolve(state.result, state.tag)) { + throwError(state, "cannot resolve a node with !<" + state.tag + "> explicit tag"); + } else { + state.result = type2.construct(state.result, state.tag); + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result); + } + } + } + if (state.listener !== null) { + state.listener("close", state); + } + state.depth -= 1; + return state.tag !== null || state.anchor !== null || hasContent; + } + function readDocument(state) { + const documentStart = state.position; + let hasDirectives = false; + let ch; + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = /* @__PURE__ */ Object.create(null); + state.anchorMap = /* @__PURE__ */ Object.create(null); + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + if (state.lineIndent > 0 || ch !== 37) { + break; + } + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + let _position = state.position; + while (ch !== 0 && !isWsOrEol(ch)) { + ch = state.input.charCodeAt(++state.position); + } + const directiveName = state.input.slice(_position, state.position); + const directiveArgs = []; + if (directiveName.length < 1) { + throwError(state, "directive name must not be less than one character in length"); + } + while (ch !== 0) { + while (isWhiteSpace(ch)) { + ch = state.input.charCodeAt(++state.position); + } + if (ch === 35) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0 && !isEol(ch)); + break; + } + if (isEol(ch)) break; + _position = state.position; + while (ch !== 0 && !isWsOrEol(ch)) { + ch = state.input.charCodeAt(++state.position); + } + directiveArgs.push(state.input.slice(_position, state.position)); + } + if (ch !== 0) readLineBreak(state); + if (_hasOwnProperty.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs); + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"'); + } + } + skipSeparationSpace(state, true, -1); + if (state.lineIndent === 0 && state.input.charCodeAt(state.position) === 45 && state.input.charCodeAt(state.position + 1) === 45 && state.input.charCodeAt(state.position + 2) === 45) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } else if (hasDirectives) { + throwError(state, "directives end mark is expected"); + } + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); + skipSeparationSpace(state, true, -1); + if (state.checkLineBreaks && PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, "non-ASCII line breaks are interpreted as content"); + } + state.documents.push(state.result); + if (state.position === state.lineStart && testDocumentSeparator(state)) { + if (state.input.charCodeAt(state.position) === 46) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } + if (state.position < state.length - 1) { + throwError(state, "end of the stream or a document separator is expected"); + } + } + function loadDocuments(input, options) { + input = String(input); + options = options || {}; + if (input.length !== 0) { + if (input.charCodeAt(input.length - 1) !== 10 && input.charCodeAt(input.length - 1) !== 13) { + input += "\n"; + } + if (input.charCodeAt(0) === 65279) { + input = input.slice(1); + } + } + const state = new State(input, options); + const nullpos = input.indexOf("\0"); + if (nullpos !== -1) { + state.position = nullpos; + throwError(state, "null byte is not allowed in input"); + } + state.input += "\0"; + while (state.input.charCodeAt(state.position) === 32) { + state.lineIndent += 1; + state.position += 1; + } + while (state.position < state.length - 1) { + readDocument(state); + } + return state.documents; + } + function loadAll2(input, iterator, options) { + if (iterator !== null && typeof iterator === "object" && typeof options === "undefined") { + options = iterator; + iterator = null; + } + const documents = loadDocuments(input, options); + if (typeof iterator !== "function") { + return documents; + } + for (let index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]); + } + } + function load2(input, options) { + const documents = loadDocuments(input, options); + if (documents.length === 0) { + return void 0; + } else if (documents.length === 1) { + return documents[0]; + } + throw new YAMLException2("expected a single document in the stream, but found more"); + } + loader.loadAll = loadAll2; + loader.load = load2; + return loader; +} +var dumper = {}; +var hasRequiredDumper; +function requireDumper() { + if (hasRequiredDumper) return dumper; + hasRequiredDumper = 1; + const common2 = requireCommon(); + const YAMLException2 = requireException(); + const DEFAULT_SCHEMA2 = require_default(); + const _toString = Object.prototype.toString; + const _hasOwnProperty = Object.prototype.hasOwnProperty; + const CHAR_BOM = 65279; + const CHAR_TAB = 9; + const CHAR_LINE_FEED = 10; + const CHAR_CARRIAGE_RETURN = 13; + const CHAR_SPACE = 32; + const CHAR_EXCLAMATION = 33; + const CHAR_DOUBLE_QUOTE = 34; + const CHAR_SHARP = 35; + const CHAR_PERCENT = 37; + const CHAR_AMPERSAND = 38; + const CHAR_SINGLE_QUOTE = 39; + const CHAR_ASTERISK = 42; + const CHAR_COMMA = 44; + const CHAR_MINUS = 45; + const CHAR_COLON = 58; + const CHAR_EQUALS = 61; + const CHAR_GREATER_THAN = 62; + const CHAR_QUESTION = 63; + const CHAR_COMMERCIAL_AT = 64; + const CHAR_LEFT_SQUARE_BRACKET = 91; + const CHAR_RIGHT_SQUARE_BRACKET = 93; + const CHAR_GRAVE_ACCENT = 96; + const CHAR_LEFT_CURLY_BRACKET = 123; + const CHAR_VERTICAL_LINE = 124; + const CHAR_RIGHT_CURLY_BRACKET = 125; + const ESCAPE_SEQUENCES = {}; + ESCAPE_SEQUENCES[0] = "\\0"; + ESCAPE_SEQUENCES[7] = "\\a"; + ESCAPE_SEQUENCES[8] = "\\b"; + ESCAPE_SEQUENCES[9] = "\\t"; + ESCAPE_SEQUENCES[10] = "\\n"; + ESCAPE_SEQUENCES[11] = "\\v"; + ESCAPE_SEQUENCES[12] = "\\f"; + ESCAPE_SEQUENCES[13] = "\\r"; + ESCAPE_SEQUENCES[27] = "\\e"; + ESCAPE_SEQUENCES[34] = '\\"'; + ESCAPE_SEQUENCES[92] = "\\\\"; + ESCAPE_SEQUENCES[133] = "\\N"; + ESCAPE_SEQUENCES[160] = "\\_"; + ESCAPE_SEQUENCES[8232] = "\\L"; + ESCAPE_SEQUENCES[8233] = "\\P"; + const DEPRECATED_BOOLEANS_SYNTAX = [ + "y", + "Y", + "yes", + "Yes", + "YES", + "on", + "On", + "ON", + "n", + "N", + "no", + "No", + "NO", + "off", + "Off", + "OFF" + ]; + const DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/; + function compileStyleMap(schema2, map2) { + if (map2 === null) return {}; + const result = {}; + const keys = Object.keys(map2); + for (let index = 0, length = keys.length; index < length; index += 1) { + let tag = keys[index]; + let style = String(map2[tag]); + if (tag.slice(0, 2) === "!!") { + tag = "tag:yaml.org,2002:" + tag.slice(2); + } + const type2 = schema2.compiledTypeMap["fallback"][tag]; + if (type2 && _hasOwnProperty.call(type2.styleAliases, style)) { + style = type2.styleAliases[style]; + } + result[tag] = style; + } + return result; + } + function encodeHex(character) { + let handle; + let length; + const string = character.toString(16).toUpperCase(); + if (character <= 255) { + handle = "x"; + length = 2; + } else if (character <= 65535) { + handle = "u"; + length = 4; + } else if (character <= 4294967295) { + handle = "U"; + length = 8; + } else { + throw new YAMLException2("code point within a string may not be greater than 0xFFFFFFFF"); + } + return "\\" + handle + common2.repeat("0", length - string.length) + string; + } + const QUOTING_TYPE_SINGLE = 1; + const QUOTING_TYPE_DOUBLE = 2; + function State(options) { + this.schema = options["schema"] || DEFAULT_SCHEMA2; + this.indent = Math.max(1, options["indent"] || 2); + this.noArrayIndent = options["noArrayIndent"] || false; + this.skipInvalid = options["skipInvalid"] || false; + this.flowLevel = common2.isNothing(options["flowLevel"]) ? -1 : options["flowLevel"]; + this.styleMap = compileStyleMap(this.schema, options["styles"] || null); + this.sortKeys = options["sortKeys"] || false; + this.lineWidth = options["lineWidth"] || 80; + this.noRefs = options["noRefs"] || false; + this.noCompatMode = options["noCompatMode"] || false; + this.condenseFlow = options["condenseFlow"] || false; + this.quotingType = options["quotingType"] === '"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE; + this.forceQuotes = options["forceQuotes"] || false; + this.replacer = typeof options["replacer"] === "function" ? options["replacer"] : null; + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + this.tag = null; + this.result = ""; + this.duplicates = []; + this.usedDuplicates = null; + } + function indentString(string, spaces) { + const ind = common2.repeat(" ", spaces); + let position = 0; + let result = ""; + const length = string.length; + while (position < length) { + let line; + const next = string.indexOf("\n", position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + if (line.length && line !== "\n") result += ind; + result += line; + } + return result; + } + function generateNextLine(state, level) { + return "\n" + common2.repeat(" ", state.indent * level); + } + function testImplicitResolving(state, str2) { + for (let index = 0, length = state.implicitTypes.length; index < length; index += 1) { + const type2 = state.implicitTypes[index]; + if (type2.resolve(str2)) { + return true; + } + } + return false; + } + function isWhitespace(c) { + return c === CHAR_SPACE || c === CHAR_TAB; + } + function isPrintable(c) { + return c >= 32 && c <= 126 || c >= 161 && c <= 55295 && c !== 8232 && c !== 8233 || c >= 57344 && c <= 65533 && c !== CHAR_BOM || c >= 65536 && c <= 1114111; + } + function isNsCharOrWhitespace(c) { + return isPrintable(c) && c !== CHAR_BOM && // - b-char + c !== CHAR_CARRIAGE_RETURN && c !== CHAR_LINE_FEED; + } + function isPlainSafe(c, prev, inblock) { + const cIsNsCharOrWhitespace = isNsCharOrWhitespace(c); + const cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c); + return ( + // ns-plain-safe + (inblock ? cIsNsCharOrWhitespace : cIsNsCharOrWhitespace && // - c-flow-indicator + c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET) && // ns-plain-char + c !== CHAR_SHARP && // false on '#' + !(prev === CHAR_COLON && !cIsNsChar) || // false on ': ' + isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP || // change to true on '[^ ]#' + prev === CHAR_COLON && cIsNsChar + ); + } + function isPlainSafeFirst(c) { + return isPrintable(c) && c !== CHAR_BOM && !isWhitespace(c) && // - s-white + // - (c-indicator ::= + // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” + c !== CHAR_MINUS && c !== CHAR_QUESTION && c !== CHAR_COLON && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET && // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “"” + c !== CHAR_SHARP && c !== CHAR_AMPERSAND && c !== CHAR_ASTERISK && c !== CHAR_EXCLAMATION && c !== CHAR_VERTICAL_LINE && c !== CHAR_EQUALS && c !== CHAR_GREATER_THAN && c !== CHAR_SINGLE_QUOTE && c !== CHAR_DOUBLE_QUOTE && // | “%” | “@” | “`”) + c !== CHAR_PERCENT && c !== CHAR_COMMERCIAL_AT && c !== CHAR_GRAVE_ACCENT; + } + function isPlainSafeLast(c) { + return !isWhitespace(c) && c !== CHAR_COLON; + } + function codePointAt(string, pos) { + const first = string.charCodeAt(pos); + let second; + if (first >= 55296 && first <= 56319 && pos + 1 < string.length) { + second = string.charCodeAt(pos + 1); + if (second >= 56320 && second <= 57343) { + return (first - 55296) * 1024 + second - 56320 + 65536; + } + } + return first; + } + function needIndentIndicator(string) { + const leadingSpaceRe = /^\n* /; + return leadingSpaceRe.test(string); + } + const STYLE_PLAIN = 1; + const STYLE_SINGLE = 2; + const STYLE_LITERAL = 3; + const STYLE_FOLDED = 4; + const STYLE_DOUBLE = 5; + function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType, quotingType, forceQuotes, inblock) { + let i; + let char = 0; + let prevChar = null; + let hasLineBreak = false; + let hasFoldableLine = false; + const shouldTrackWidth = lineWidth !== -1; + let previousLineBreak = -1; + let plain = isPlainSafeFirst(codePointAt(string, 0)) && isPlainSafeLast(codePointAt(string, string.length - 1)); + if (singleLineOnly || forceQuotes) { + for (i = 0; i < string.length; char >= 65536 ? i += 2 : i++) { + char = codePointAt(string, i); + if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + } else { + for (i = 0; i < string.length; char >= 65536 ? i += 2 : i++) { + char = codePointAt(string, i); + if (char === CHAR_LINE_FEED) { + hasLineBreak = true; + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || // Foldable line = too long, and not more-indented. + i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== " "; + previousLineBreak = i; + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + hasFoldableLine = hasFoldableLine || shouldTrackWidth && (i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== " "); + } + if (!hasLineBreak && !hasFoldableLine) { + if (plain && !forceQuotes && !testAmbiguousType(string)) { + return STYLE_PLAIN; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + if (indentPerLevel > 9 && needIndentIndicator(string)) { + return STYLE_DOUBLE; + } + if (!forceQuotes) { + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + function writeScalar(state, string, level, iskey, inblock) { + state.dump = (function() { + if (string.length === 0) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? '""' : "''"; + } + if (!state.noCompatMode) { + if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? '"' + string + '"' : "'" + string + "'"; + } + } + const indent = state.indent * Math.max(1, level); + const lineWidth = state.lineWidth === -1 ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + const singleLineOnly = iskey || // No block styles in flow mode. + state.flowLevel > -1 && level >= state.flowLevel; + function testAmbiguity(string2) { + return testImplicitResolving(state, string2); + } + switch (chooseScalarStyle( + string, + singleLineOnly, + state.indent, + lineWidth, + testAmbiguity, + state.quotingType, + state.forceQuotes && !iskey, + inblock + )) { + case STYLE_PLAIN: + return string; + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'"; + case STYLE_LITERAL: + return "|" + blockHeader(string, state.indent) + dropEndingNewline(indentString(string, indent)); + case STYLE_FOLDED: + return ">" + blockHeader(string, state.indent) + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); + case STYLE_DOUBLE: + return '"' + escapeString(string) + '"'; + default: + throw new YAMLException2("impossible error: invalid scalar style"); + } + })(); + } + function blockHeader(string, indentPerLevel) { + const indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ""; + const clip = string[string.length - 1] === "\n"; + const keep = clip && (string[string.length - 2] === "\n" || string === "\n"); + const chomp = keep ? "+" : clip ? "" : "-"; + return indentIndicator + chomp + "\n"; + } + function dropEndingNewline(string) { + return string[string.length - 1] === "\n" ? string.slice(0, -1) : string; + } + function foldString(string, width) { + const lineRe = /(\n+)([^\n]*)/g; + let result = (function() { + let nextLF = string.indexOf("\n"); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + })(); + let prevMoreIndented = string[0] === "\n" || string[0] === " "; + let moreIndented; + let match; + while (match = lineRe.exec(string)) { + const prefix = match[1]; + const line = match[2]; + moreIndented = line[0] === " "; + result += prefix + (!prevMoreIndented && !moreIndented && line !== "" ? "\n" : "") + foldLine(line, width); + prevMoreIndented = moreIndented; + } + return result; + } + function foldLine(line, width) { + if (line === "" || line[0] === " ") return line; + const breakRe = / [^ ]/g; + let match; + let start = 0; + let end; + let curr = 0; + let next = 0; + let result = ""; + while (match = breakRe.exec(line)) { + next = match.index; + if (next - start > width) { + end = curr > start ? curr : next; + result += "\n" + line.slice(start, end); + start = end + 1; + } + curr = next; + } + result += "\n"; + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + "\n" + line.slice(curr + 1); + } else { + result += line.slice(start); + } + return result.slice(1); + } + function escapeString(string) { + let result = ""; + let char = 0; + for (let i = 0; i < string.length; char >= 65536 ? i += 2 : i++) { + char = codePointAt(string, i); + const escapeSeq = ESCAPE_SEQUENCES[char]; + if (!escapeSeq && isPrintable(char)) { + result += string[i]; + if (char >= 65536) result += string[i + 1]; + } else { + result += escapeSeq || encodeHex(char); + } + } + return result; + } + function writeFlowSequence(state, level, object) { + let _result = ""; + const _tag = state.tag; + for (let index = 0, length = object.length; index < length; index += 1) { + let value = object[index]; + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + if (writeNode(state, level, value, false, false) || typeof value === "undefined" && writeNode(state, level, null, false, false)) { + if (_result !== "") _result += "," + (!state.condenseFlow ? " " : ""); + _result += state.dump; + } + } + state.tag = _tag; + state.dump = "[" + _result + "]"; + } + function writeBlockSequence(state, level, object, compact) { + let _result = ""; + const _tag = state.tag; + for (let index = 0, length = object.length; index < length; index += 1) { + let value = object[index]; + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + if (writeNode(state, level + 1, value, true, true, false, true) || typeof value === "undefined" && writeNode(state, level + 1, null, true, true, false, true)) { + if (!compact || _result !== "") { + _result += generateNextLine(state, level); + } + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + _result += "-"; + } else { + _result += "- "; + } + _result += state.dump; + } + } + state.tag = _tag; + state.dump = _result || "[]"; + } + function writeFlowMapping(state, level, object) { + let _result = ""; + const _tag = state.tag; + const objectKeyList = Object.keys(object); + for (let index = 0, length = objectKeyList.length; index < length; index += 1) { + let pairBuffer = ""; + if (_result !== "") pairBuffer += ", "; + if (state.condenseFlow) pairBuffer += '"'; + const objectKey = objectKeyList[index]; + let objectValue = object[objectKey]; + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + if (!writeNode(state, level, objectKey, false, false)) { + continue; + } + if (state.dump.length > 1024) pairBuffer += "? "; + pairBuffer += state.dump + (state.condenseFlow ? '"' : "") + ":" + (state.condenseFlow ? "" : " "); + if (!writeNode(state, level, objectValue, false, false)) { + continue; + } + pairBuffer += state.dump; + _result += pairBuffer; + } + state.tag = _tag; + state.dump = "{" + _result + "}"; + } + function writeBlockMapping(state, level, object, compact) { + let _result = ""; + const _tag = state.tag; + const objectKeyList = Object.keys(object); + if (state.sortKeys === true) { + objectKeyList.sort(); + } else if (typeof state.sortKeys === "function") { + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + throw new YAMLException2("sortKeys must be a boolean or a function"); + } + for (let index = 0, length = objectKeyList.length; index < length; index += 1) { + let pairBuffer = ""; + if (!compact || _result !== "") { + pairBuffer += generateNextLine(state, level); + } + const objectKey = objectKeyList[index]; + let objectValue = object[objectKey]; + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; + } + const explicitPair = state.tag !== null && state.tag !== "?" || state.dump && state.dump.length > 1024; + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += "?"; + } else { + pairBuffer += "? "; + } + } + pairBuffer += state.dump; + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; + } + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ":"; + } else { + pairBuffer += ": "; + } + pairBuffer += state.dump; + _result += pairBuffer; + } + state.tag = _tag; + state.dump = _result || "{}"; + } + function detectType(state, object, explicit) { + const typeList = explicit ? state.explicitTypes : state.implicitTypes; + for (let index = 0, length = typeList.length; index < length; index += 1) { + const type2 = typeList[index]; + if ((type2.instanceOf || type2.predicate) && (!type2.instanceOf || typeof object === "object" && object instanceof type2.instanceOf) && (!type2.predicate || type2.predicate(object))) { + if (explicit) { + if (type2.multi && type2.representName) { + state.tag = type2.representName(object); + } else { + state.tag = type2.tag; + } + } else { + state.tag = "?"; + } + if (type2.represent) { + const style = state.styleMap[type2.tag] || type2.defaultStyle; + let _result; + if (_toString.call(type2.represent) === "[object Function]") { + _result = type2.represent(object, style); + } else if (_hasOwnProperty.call(type2.represent, style)) { + _result = type2.represent[style](object, style); + } else { + throw new YAMLException2("!<" + type2.tag + '> tag resolver accepts not "' + style + '" style'); + } + state.dump = _result; + } + return true; + } + } + return false; + } + function writeNode(state, level, object, block, compact, iskey, isblockseq) { + state.tag = null; + state.dump = object; + if (!detectType(state, object, false)) { + detectType(state, object, true); + } + const type2 = _toString.call(state.dump); + const inblock = block; + if (block) { + block = state.flowLevel < 0 || state.flowLevel > level; + } + const objectOrArray = type2 === "[object Object]" || type2 === "[object Array]"; + let duplicateIndex; + let duplicate; + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } + if (state.tag !== null && state.tag !== "?" || duplicate || state.indent !== 2 && level > 0) { + compact = false; + } + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = "*ref_" + duplicateIndex; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type2 === "[object Object]") { + if (block && Object.keys(state.dump).length !== 0) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = "&ref_" + duplicateIndex + state.dump; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = "&ref_" + duplicateIndex + " " + state.dump; + } + } + } else if (type2 === "[object Array]") { + if (block && state.dump.length !== 0) { + if (state.noArrayIndent && !isblockseq && level > 0) { + writeBlockSequence(state, level - 1, state.dump, compact); + } else { + writeBlockSequence(state, level, state.dump, compact); + } + if (duplicate) { + state.dump = "&ref_" + duplicateIndex + state.dump; + } + } else { + writeFlowSequence(state, level, state.dump); + if (duplicate) { + state.dump = "&ref_" + duplicateIndex + " " + state.dump; + } + } + } else if (type2 === "[object String]") { + if (state.tag !== "?") { + writeScalar(state, state.dump, level, iskey, inblock); + } + } else if (type2 === "[object Undefined]") { + return false; + } else { + if (state.skipInvalid) return false; + throw new YAMLException2("unacceptable kind of an object to dump " + type2); + } + if (state.tag !== null && state.tag !== "?") { + let tagStr = encodeURI( + state.tag[0] === "!" ? state.tag.slice(1) : state.tag + ).replace(/!/g, "%21"); + if (state.tag[0] === "!") { + tagStr = "!" + tagStr; + } else if (tagStr.slice(0, 18) === "tag:yaml.org,2002:") { + tagStr = "!!" + tagStr.slice(18); + } else { + tagStr = "!<" + tagStr + ">"; + } + state.dump = tagStr + " " + state.dump; + } + } + return true; + } + function getDuplicateReferences(object, state) { + const objects = []; + const duplicatesIndexes = []; + inspectNode(object, objects, duplicatesIndexes); + const length = duplicatesIndexes.length; + for (let index = 0; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = new Array(length); + } + function inspectNode(object, objects, duplicatesIndexes) { + if (object !== null && typeof object === "object") { + const index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + if (Array.isArray(object)) { + for (let i = 0, length = object.length; i < length; i += 1) { + inspectNode(object[i], objects, duplicatesIndexes); + } + } else { + const objectKeyList = Object.keys(object); + for (let i = 0, length = objectKeyList.length; i < length; i += 1) { + inspectNode(object[objectKeyList[i]], objects, duplicatesIndexes); + } + } + } + } + } + function dump2(input, options) { + options = options || {}; + const state = new State(options); + if (!state.noRefs) getDuplicateReferences(input, state); + let value = input; + if (state.replacer) { + value = state.replacer.call({ "": value }, "", value); + } + if (writeNode(state, 0, value, true, true)) return state.dump + "\n"; + return ""; + } + dumper.dump = dump2; + return dumper; +} +var hasRequiredJsYaml; +function requireJsYaml() { + if (hasRequiredJsYaml) return jsYaml; + hasRequiredJsYaml = 1; + const loader2 = requireLoader(); + const dumper2 = requireDumper(); + function renamed(from, to) { + return function() { + throw new Error("Function yaml." + from + " is removed in js-yaml 4. Use yaml." + to + " instead, which is now safe by default."); + }; + } + jsYaml.Type = requireType(); + jsYaml.Schema = requireSchema(); + jsYaml.FAILSAFE_SCHEMA = requireFailsafe(); + jsYaml.JSON_SCHEMA = requireJson(); + jsYaml.CORE_SCHEMA = requireCore(); + jsYaml.DEFAULT_SCHEMA = require_default(); + jsYaml.load = loader2.load; + jsYaml.loadAll = loader2.loadAll; + jsYaml.dump = dumper2.dump; + jsYaml.YAMLException = requireException(); + jsYaml.types = { + binary: requireBinary(), + float: requireFloat(), + map: requireMap(), + null: require_null(), + pairs: requirePairs(), + set: requireSet(), + timestamp: requireTimestamp(), + bool: requireBool(), + int: requireInt(), + merge: requireMerge(), + omap: requireOmap(), + seq: requireSeq(), + str: requireStr() + }; + jsYaml.safeLoad = renamed("safeLoad", "load"); + jsYaml.safeLoadAll = renamed("safeLoadAll", "loadAll"); + jsYaml.safeDump = renamed("safeDump", "dump"); + return jsYaml; +} +var jsYamlExports = requireJsYaml(); +const yaml = /* @__PURE__ */ getDefaultExportFromCjs(jsYamlExports); +const { + Type, + Schema, + FAILSAFE_SCHEMA, + JSON_SCHEMA, + CORE_SCHEMA, + DEFAULT_SCHEMA, + load, + loadAll, + dump, + YAMLException, + types, + safeLoad, + safeLoadAll, + safeDump +} = yaml; +export { + CORE_SCHEMA, + DEFAULT_SCHEMA, + FAILSAFE_SCHEMA, + JSON_SCHEMA, + Schema, + Type, + YAMLException, + yaml as default, + dump, + load, + loadAll, + safeDump, + safeLoad, + safeLoadAll, + types +}; +//# sourceMappingURL=js-yaml.mjs.map diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.mjs.map b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.mjs.map new file mode 100644 index 0000000..259b438 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.mjs.map @@ -0,0 +1 @@ +{"version":3,"file":"js-yaml.mjs","sources":["../lib/common.js","../lib/exception.js","../lib/snippet.js","../lib/type.js","../lib/schema.js","../lib/type/str.js","../lib/type/seq.js","../lib/type/map.js","../lib/schema/failsafe.js","../lib/type/null.js","../lib/type/bool.js","../lib/type/int.js","../lib/type/float.js","../lib/schema/json.js","../lib/schema/core.js","../lib/type/timestamp.js","../lib/type/merge.js","../lib/type/binary.js","../lib/type/omap.js","../lib/type/pairs.js","../lib/type/set.js","../lib/schema/default.js","../lib/loader.js","../lib/dumper.js","../index.js","../lib/index_vite_proxy.tmp.mjs"],"sourcesContent":["'use strict'\n\nfunction isNothing (subject) {\n return (typeof subject === 'undefined') || (subject === null)\n}\n\nfunction isObject (subject) {\n return (typeof subject === 'object') && (subject !== null)\n}\n\nfunction toArray (sequence) {\n if (Array.isArray(sequence)) return sequence\n else if (isNothing(sequence)) return []\n\n return [sequence]\n}\n\nfunction extend (target, source) {\n if (source) {\n const sourceKeys = Object.keys(source)\n\n for (let index = 0, length = sourceKeys.length; index < length; index += 1) {\n const key = sourceKeys[index]\n target[key] = source[key]\n }\n }\n\n return target\n}\n\nfunction repeat (string, count) {\n let result = ''\n\n for (let cycle = 0; cycle < count; cycle += 1) {\n result += string\n }\n\n return result\n}\n\nfunction isNegativeZero (number) {\n return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number)\n}\n\nmodule.exports.isNothing = isNothing\nmodule.exports.isObject = isObject\nmodule.exports.toArray = toArray\nmodule.exports.repeat = repeat\nmodule.exports.isNegativeZero = isNegativeZero\nmodule.exports.extend = extend\n","// YAML error class. http://stackoverflow.com/questions/8458984\n//\n'use strict'\n\nfunction formatError (exception, compact) {\n let where = ''\n const message = exception.reason || '(unknown reason)'\n\n if (!exception.mark) return message\n\n if (exception.mark.name) {\n where += 'in \"' + exception.mark.name + '\" '\n }\n\n where += '(' + (exception.mark.line + 1) + ':' + (exception.mark.column + 1) + ')'\n\n if (!compact && exception.mark.snippet) {\n where += '\\n\\n' + exception.mark.snippet\n }\n\n return message + ' ' + where\n}\n\nfunction YAMLException (reason, mark) {\n // Super constructor\n Error.call(this)\n\n this.name = 'YAMLException'\n this.reason = reason\n this.mark = mark\n this.message = formatError(this, false)\n\n // Include stack trace in error object\n if (Error.captureStackTrace) {\n // Chrome and NodeJS\n Error.captureStackTrace(this, this.constructor)\n } else {\n // FF, IE 10+ and Safari 6+. Fallback for others\n this.stack = (new Error()).stack || ''\n }\n}\n\n// Inherit from Error\nYAMLException.prototype = Object.create(Error.prototype)\nYAMLException.prototype.constructor = YAMLException\n\nYAMLException.prototype.toString = function toString (compact) {\n return this.name + ': ' + formatError(this, compact)\n}\n\nmodule.exports = YAMLException\n","'use strict'\n\nconst common = require('./common')\n\n// get snippet for a single line, respecting maxLength\nfunction getLine (buffer, lineStart, lineEnd, position, maxLineLength) {\n let head = ''\n let tail = ''\n const maxHalfLength = Math.floor(maxLineLength / 2) - 1\n\n if (position - lineStart > maxHalfLength) {\n head = ' ... '\n lineStart = position - maxHalfLength + head.length\n }\n\n if (lineEnd - position > maxHalfLength) {\n tail = ' ...'\n lineEnd = position + maxHalfLength - tail.length\n }\n\n return {\n str: head + buffer.slice(lineStart, lineEnd).replace(/\\t/g, '→') + tail,\n pos: position - lineStart + head.length // relative position\n }\n}\n\nfunction padStart (string, max) {\n return common.repeat(' ', max - string.length) + string\n}\n\nfunction makeSnippet (mark, options) {\n options = Object.create(options || null)\n\n if (!mark.buffer) return null\n\n if (!options.maxLength) options.maxLength = 79\n if (typeof options.indent !== 'number') options.indent = 1\n if (typeof options.linesBefore !== 'number') options.linesBefore = 3\n if (typeof options.linesAfter !== 'number') options.linesAfter = 2\n\n const re = /\\r?\\n|\\r|\\0/g\n const lineStarts = [0]\n const lineEnds = []\n let match\n let foundLineNo = -1\n\n while ((match = re.exec(mark.buffer))) {\n lineEnds.push(match.index)\n lineStarts.push(match.index + match[0].length)\n\n if (mark.position <= match.index && foundLineNo < 0) {\n foundLineNo = lineStarts.length - 2\n }\n }\n\n if (foundLineNo < 0) foundLineNo = lineStarts.length - 1\n\n let result = ''\n const lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length\n const maxLineLength = options.maxLength - (options.indent + lineNoLength + 3)\n\n for (let i = 1; i <= options.linesBefore; i++) {\n if (foundLineNo - i < 0) break\n const line = getLine(\n mark.buffer,\n lineStarts[foundLineNo - i],\n lineEnds[foundLineNo - i],\n mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]),\n maxLineLength\n )\n result = common.repeat(' ', options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) +\n ' | ' + line.str + '\\n' + result\n }\n\n const line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength)\n result += common.repeat(' ', options.indent) + padStart((mark.line + 1).toString(), lineNoLength) +\n ' | ' + line.str + '\\n'\n result += common.repeat('-', options.indent + lineNoLength + 3 + line.pos) + '^' + '\\n'\n\n for (let i = 1; i <= options.linesAfter; i++) {\n if (foundLineNo + i >= lineEnds.length) break\n const line = getLine(\n mark.buffer,\n lineStarts[foundLineNo + i],\n lineEnds[foundLineNo + i],\n mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]),\n maxLineLength\n )\n result += common.repeat(' ', options.indent) + padStart((mark.line + i + 1).toString(), lineNoLength) +\n ' | ' + line.str + '\\n'\n }\n\n return result.replace(/\\n$/, '')\n}\n\nmodule.exports = makeSnippet\n","'use strict'\n\nconst YAMLException = require('./exception')\n\nconst TYPE_CONSTRUCTOR_OPTIONS = [\n 'kind',\n 'multi',\n 'resolve',\n 'construct',\n 'instanceOf',\n 'predicate',\n 'represent',\n 'representName',\n 'defaultStyle',\n 'styleAliases'\n]\n\nconst YAML_NODE_KINDS = [\n 'scalar',\n 'sequence',\n 'mapping'\n]\n\nfunction compileStyleAliases (map) {\n const result = {}\n\n if (map !== null) {\n Object.keys(map).forEach(function (style) {\n map[style].forEach(function (alias) {\n result[String(alias)] = style\n })\n })\n }\n\n return result\n}\n\nfunction Type (tag, options) {\n options = options || {}\n\n Object.keys(options).forEach(function (name) {\n if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) {\n throw new YAMLException('Unknown option \"' + name + '\" is met in definition of \"' + tag + '\" YAML type.')\n }\n })\n\n // TODO: Add tag format check.\n this.options = options // keep original options in case user wants to extend this type later\n this.tag = tag\n this.kind = options['kind'] || null\n this.resolve = options['resolve'] || function () { return true }\n this.construct = options['construct'] || function (data) { return data }\n this.instanceOf = options['instanceOf'] || null\n this.predicate = options['predicate'] || null\n this.represent = options['represent'] || null\n this.representName = options['representName'] || null\n this.defaultStyle = options['defaultStyle'] || null\n this.multi = options['multi'] || false\n this.styleAliases = compileStyleAliases(options['styleAliases'] || null)\n\n if (YAML_NODE_KINDS.indexOf(this.kind) === -1) {\n throw new YAMLException('Unknown kind \"' + this.kind + '\" is specified for \"' + tag + '\" YAML type.')\n }\n}\n\nmodule.exports = Type\n","'use strict'\n\nconst YAMLException = require('./exception')\nconst Type = require('./type')\n\nfunction compileList (schema, name) {\n const result = []\n\n schema[name].forEach(function (currentType) {\n let newIndex = result.length\n\n result.forEach(function (previousType, previousIndex) {\n if (previousType.tag === currentType.tag &&\n previousType.kind === currentType.kind &&\n previousType.multi === currentType.multi) {\n newIndex = previousIndex\n }\n })\n\n result[newIndex] = currentType\n })\n\n return result\n}\n\nfunction compileMap (/* lists... */) {\n const result = {\n scalar: {},\n sequence: {},\n mapping: {},\n fallback: {},\n multi: {\n scalar: [],\n sequence: [],\n mapping: [],\n fallback: []\n }\n }\n function collectType (type) {\n if (type.multi) {\n result.multi[type.kind].push(type)\n result.multi['fallback'].push(type)\n } else {\n result[type.kind][type.tag] = result['fallback'][type.tag] = type\n }\n }\n\n for (let index = 0, length = arguments.length; index < length; index += 1) {\n arguments[index].forEach(collectType)\n }\n return result\n}\n\nfunction Schema (definition) {\n return this.extend(definition)\n}\n\nSchema.prototype.extend = function extend (definition) {\n let implicit = []\n let explicit = []\n\n if (definition instanceof Type) {\n // Schema.extend(type)\n explicit.push(definition)\n } else if (Array.isArray(definition)) {\n // Schema.extend([ type1, type2, ... ])\n explicit = explicit.concat(definition)\n } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) {\n // Schema.extend({ explicit: [ type1, type2, ... ], implicit: [ type1, type2, ... ] })\n if (definition.implicit) implicit = implicit.concat(definition.implicit)\n if (definition.explicit) explicit = explicit.concat(definition.explicit)\n } else {\n throw new YAMLException('Schema.extend argument should be a Type, [ Type ], ' +\n 'or a schema definition ({ implicit: [...], explicit: [...] })')\n }\n\n implicit.forEach(function (type) {\n if (!(type instanceof Type)) {\n throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.')\n }\n\n if (type.loadKind && type.loadKind !== 'scalar') {\n throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.')\n }\n\n if (type.multi) {\n throw new YAMLException('There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.')\n }\n })\n\n explicit.forEach(function (type) {\n if (!(type instanceof Type)) {\n throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.')\n }\n })\n\n const result = Object.create(Schema.prototype)\n\n result.implicit = (this.implicit || []).concat(implicit)\n result.explicit = (this.explicit || []).concat(explicit)\n\n result.compiledImplicit = compileList(result, 'implicit')\n result.compiledExplicit = compileList(result, 'explicit')\n result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit)\n\n return result\n}\n\nmodule.exports = Schema\n","'use strict'\n\nconst Type = require('../type')\n\nmodule.exports = new Type('tag:yaml.org,2002:str', {\n kind: 'scalar',\n construct: function (data) { return data !== null ? data : '' }\n})\n","'use strict'\n\nconst Type = require('../type')\n\nmodule.exports = new Type('tag:yaml.org,2002:seq', {\n kind: 'sequence',\n construct: function (data) { return data !== null ? data : [] }\n})\n","'use strict'\n\nconst Type = require('../type')\n\nmodule.exports = new Type('tag:yaml.org,2002:map', {\n kind: 'mapping',\n construct: function (data) { return data !== null ? data : {} }\n})\n","// Standard YAML's Failsafe schema.\n// http://www.yaml.org/spec/1.2/spec.html#id2802346\n\n'use strict'\n\nconst Schema = require('../schema')\n\nmodule.exports = new Schema({\n explicit: [\n require('../type/str'),\n require('../type/seq'),\n require('../type/map')\n ]\n})\n","'use strict'\n\nconst Type = require('../type')\n\nfunction resolveYamlNull (data) {\n if (data === null) return true\n\n const max = data.length\n\n return (max === 1 && data === '~') ||\n (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL'))\n}\n\nfunction constructYamlNull () {\n return null\n}\n\nfunction isNull (object) {\n return object === null\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:null', {\n kind: 'scalar',\n resolve: resolveYamlNull,\n construct: constructYamlNull,\n predicate: isNull,\n represent: {\n canonical: function () { return '~' },\n lowercase: function () { return 'null' },\n uppercase: function () { return 'NULL' },\n camelcase: function () { return 'Null' },\n empty: function () { return '' }\n },\n defaultStyle: 'lowercase'\n})\n","'use strict'\n\nconst Type = require('../type')\n\nfunction resolveYamlBoolean (data) {\n if (data === null) return false\n\n const max = data.length\n\n return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) ||\n (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE'))\n}\n\nfunction constructYamlBoolean (data) {\n return data === 'true' ||\n data === 'True' ||\n data === 'TRUE'\n}\n\nfunction isBoolean (object) {\n return Object.prototype.toString.call(object) === '[object Boolean]'\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:bool', {\n kind: 'scalar',\n resolve: resolveYamlBoolean,\n construct: constructYamlBoolean,\n predicate: isBoolean,\n represent: {\n lowercase: function (object) { return object ? 'true' : 'false' },\n uppercase: function (object) { return object ? 'TRUE' : 'FALSE' },\n camelcase: function (object) { return object ? 'True' : 'False' }\n },\n defaultStyle: 'lowercase'\n})\n","'use strict'\n\nconst common = require('../common')\nconst Type = require('../type')\n\nfunction isHexCode (c) {\n return ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) ||\n ((c >= 0x41/* A */) && (c <= 0x46/* F */)) ||\n ((c >= 0x61/* a */) && (c <= 0x66/* f */))\n}\n\nfunction isOctCode (c) {\n return ((c >= 0x30/* 0 */) && (c <= 0x37/* 7 */))\n}\n\nfunction isDecCode (c) {\n return ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */))\n}\n\nfunction resolveYamlInteger (data) {\n if (data === null) return false\n\n const max = data.length\n let index = 0\n let hasDigits = false\n\n if (!max) return false\n\n let ch = data[index]\n\n // sign\n if (ch === '-' || ch === '+') {\n ch = data[++index]\n }\n\n if (ch === '0') {\n // 0\n if (index + 1 === max) return true\n ch = data[++index]\n\n // base 2, base 8, base 16\n\n if (ch === 'b') {\n // base 2\n index++\n\n for (; index < max; index++) {\n ch = data[index]\n if (ch !== '0' && ch !== '1') return false\n hasDigits = true\n }\n return hasDigits && isFinite(parseYamlInteger(data))\n }\n\n if (ch === 'x') {\n // base 16\n index++\n\n for (; index < max; index++) {\n if (!isHexCode(data.charCodeAt(index))) return false\n hasDigits = true\n }\n return hasDigits && isFinite(parseYamlInteger(data))\n }\n\n if (ch === 'o') {\n // base 8\n index++\n\n for (; index < max; index++) {\n if (!isOctCode(data.charCodeAt(index))) return false\n hasDigits = true\n }\n return hasDigits && isFinite(parseYamlInteger(data))\n }\n }\n\n // base 10 (except 0)\n\n for (; index < max; index++) {\n if (!isDecCode(data.charCodeAt(index))) {\n return false\n }\n hasDigits = true\n }\n\n if (!hasDigits) return false\n\n return isFinite(parseYamlInteger(data))\n}\n\nfunction parseYamlInteger (data) {\n let value = data\n let sign = 1\n\n let ch = value[0]\n\n if (ch === '-' || ch === '+') {\n if (ch === '-') sign = -1\n value = value.slice(1)\n ch = value[0]\n }\n\n if (value === '0') return 0\n\n if (ch === '0') {\n if (value[1] === 'b') return sign * parseInt(value.slice(2), 2)\n if (value[1] === 'x') return sign * parseInt(value.slice(2), 16)\n if (value[1] === 'o') return sign * parseInt(value.slice(2), 8)\n }\n\n return sign * parseInt(value, 10)\n}\n\nfunction constructYamlInteger (data) {\n return parseYamlInteger(data)\n}\n\nfunction isInteger (object) {\n return (Object.prototype.toString.call(object)) === '[object Number]' &&\n (object % 1 === 0 && !common.isNegativeZero(object))\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:int', {\n kind: 'scalar',\n resolve: resolveYamlInteger,\n construct: constructYamlInteger,\n predicate: isInteger,\n represent: {\n binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1) },\n octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1) },\n decimal: function (obj) { return obj.toString(10) },\n hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1) }\n },\n defaultStyle: 'decimal',\n styleAliases: {\n binary: [2, 'bin'],\n octal: [8, 'oct'],\n decimal: [10, 'dec'],\n hexadecimal: [16, 'hex']\n }\n})\n","'use strict'\n\nconst common = require('../common')\nconst Type = require('../type')\n\nconst YAML_FLOAT_PATTERN = new RegExp(\n // 2.5e4, 2.5 and integers\n '^(?:[-+]?(?:[0-9]+)(?:\\\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?' +\n // .2e4, .2\n // special case, seems not from spec\n '|\\\\.[0-9]+(?:[eE][-+]?[0-9]+)?' +\n // .inf\n '|[-+]?\\\\.(?:inf|Inf|INF)' +\n // .nan\n '|\\\\.(?:nan|NaN|NAN))$')\n\nconst YAML_FLOAT_SPECIAL_PATTERN = new RegExp(\n '^(?:' +\n // .inf\n '[-+]?\\\\.(?:inf|Inf|INF)' +\n // .nan\n '|\\\\.(?:nan|NaN|NAN))$')\n\nfunction resolveYamlFloat (data) {\n if (data === null) return false\n\n if (!YAML_FLOAT_PATTERN.test(data)) {\n return false\n }\n\n if (isFinite(parseFloat(data, 10))) {\n return true\n }\n\n return YAML_FLOAT_SPECIAL_PATTERN.test(data)\n}\n\nfunction constructYamlFloat (data) {\n let value = data.toLowerCase()\n const sign = value[0] === '-' ? -1 : 1\n\n if ('+-'.indexOf(value[0]) >= 0) {\n value = value.slice(1)\n }\n\n if (value === '.inf') {\n return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY\n } else if (value === '.nan') {\n return NaN\n }\n return sign * parseFloat(value, 10)\n}\n\nconst SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/\n\nfunction representYamlFloat (object, style) {\n if (isNaN(object)) {\n switch (style) {\n case 'lowercase': return '.nan'\n case 'uppercase': return '.NAN'\n case 'camelcase': return '.NaN'\n }\n } else if (Number.POSITIVE_INFINITY === object) {\n switch (style) {\n case 'lowercase': return '.inf'\n case 'uppercase': return '.INF'\n case 'camelcase': return '.Inf'\n }\n } else if (Number.NEGATIVE_INFINITY === object) {\n switch (style) {\n case 'lowercase': return '-.inf'\n case 'uppercase': return '-.INF'\n case 'camelcase': return '-.Inf'\n }\n } else if (common.isNegativeZero(object)) {\n return '-0.0'\n }\n\n const res = object.toString(10)\n\n // JS stringifier can build scientific format without dots: 5e-100,\n // while YAML requres dot: 5.e-100. Fix it with simple hack\n\n return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res\n}\n\nfunction isFloat (object) {\n return (Object.prototype.toString.call(object) === '[object Number]') &&\n (object % 1 !== 0 || common.isNegativeZero(object))\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:float', {\n kind: 'scalar',\n resolve: resolveYamlFloat,\n construct: constructYamlFloat,\n predicate: isFloat,\n represent: representYamlFloat,\n defaultStyle: 'lowercase'\n})\n","// Standard YAML's JSON schema.\n// http://www.yaml.org/spec/1.2/spec.html#id2803231\n//\n// NOTE: JS-YAML does not support schema-specific tag resolution restrictions.\n// So, this schema is not such strict as defined in the YAML specification.\n// It allows numbers in binary notaion, use `Null` and `NULL` as `null`, etc.\n\n'use strict'\n\nmodule.exports = require('./failsafe').extend({\n implicit: [\n require('../type/null'),\n require('../type/bool'),\n require('../type/int'),\n require('../type/float')\n ]\n})\n","// Standard YAML's Core schema.\n// http://www.yaml.org/spec/1.2/spec.html#id2804923\n//\n// NOTE: JS-YAML does not support schema-specific tag resolution restrictions.\n// So, Core schema has no distinctions from JSON schema is JS-YAML.\n\n'use strict'\n\nmodule.exports = require('./json')\n","'use strict'\n\nconst Type = require('../type')\n\nconst YAML_DATE_REGEXP = new RegExp(\n '^([0-9][0-9][0-9][0-9])' + // [1] year\n '-([0-9][0-9])' + // [2] month\n '-([0-9][0-9])$') // [3] day\n\nconst YAML_TIMESTAMP_REGEXP = new RegExp(\n '^([0-9][0-9][0-9][0-9])' + // [1] year\n '-([0-9][0-9]?)' + // [2] month\n '-([0-9][0-9]?)' + // [3] day\n '(?:[Tt]|[ \\\\t]+)' + // ...\n '([0-9][0-9]?)' + // [4] hour\n ':([0-9][0-9])' + // [5] minute\n ':([0-9][0-9])' + // [6] second\n '(?:\\\\.([0-9]*))?' + // [7] fraction\n '(?:[ \\\\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tzHour\n '(?::([0-9][0-9]))?))?$') // [11] tzMinute\n\nfunction resolveYamlTimestamp (data) {\n if (data === null) return false\n if (YAML_DATE_REGEXP.exec(data) !== null) return true\n if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true\n return false\n}\n\nfunction constructYamlTimestamp (data) {\n let fraction = 0\n let delta = null\n\n let match = YAML_DATE_REGEXP.exec(data)\n if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data)\n\n if (match === null) throw new Error('Date resolve error')\n\n // match: [1] year [2] month [3] day\n\n const year = +(match[1])\n const month = +(match[2]) - 1 // JS month starts with 0\n const day = +(match[3])\n\n if (!match[4]) { // no hour\n return new Date(Date.UTC(year, month, day))\n }\n\n // match: [4] hour [5] minute [6] second [7] fraction\n\n const hour = +(match[4])\n const minute = +(match[5])\n const second = +(match[6])\n\n if (match[7]) {\n fraction = match[7].slice(0, 3)\n while (fraction.length < 3) { // milli-seconds\n fraction += '0'\n }\n fraction = +fraction\n }\n\n // match: [8] tz [9] tz_sign [10] tzHour [11] tzMinute\n\n if (match[9]) {\n const tzHour = +(match[10])\n const tzMinute = +(match[11] || 0)\n delta = (tzHour * 60 + tzMinute) * 60000 // delta in mili-seconds\n if (match[9] === '-') delta = -delta\n }\n\n const date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction))\n\n if (delta) date.setTime(date.getTime() - delta)\n\n return date\n}\n\nfunction representYamlTimestamp (object /*, style */) {\n return object.toISOString()\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:timestamp', {\n kind: 'scalar',\n resolve: resolveYamlTimestamp,\n construct: constructYamlTimestamp,\n instanceOf: Date,\n represent: representYamlTimestamp\n})\n","'use strict'\n\nconst Type = require('../type')\n\nfunction resolveYamlMerge (data) {\n return data === '<<' || data === null\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:merge', {\n kind: 'scalar',\n resolve: resolveYamlMerge\n})\n","'use strict'\n\nconst Type = require('../type')\n\n// [ 64, 65, 66 ] -> [ padding, CR, LF ]\nconst BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\\n\\r'\n\nfunction resolveYamlBinary (data) {\n if (data === null) return false\n\n let bitlen = 0\n const max = data.length\n const map = BASE64_MAP\n\n // Convert one by one.\n for (let idx = 0; idx < max; idx++) {\n const code = map.indexOf(data.charAt(idx))\n\n // Skip CR/LF\n if (code > 64) continue\n\n // Fail on illegal characters\n if (code < 0) return false\n\n bitlen += 6\n }\n\n // If there are any bits left, source was corrupted\n return (bitlen % 8) === 0\n}\n\nfunction constructYamlBinary (data) {\n const input = data.replace(/[\\r\\n=]/g, '') // remove CR/LF & padding to simplify scan\n const max = input.length\n const map = BASE64_MAP\n let bits = 0\n const result = []\n\n // Collect by 6*4 bits (3 bytes)\n\n for (let idx = 0; idx < max; idx++) {\n if ((idx % 4 === 0) && idx) {\n result.push((bits >> 16) & 0xFF)\n result.push((bits >> 8) & 0xFF)\n result.push(bits & 0xFF)\n }\n\n bits = (bits << 6) | map.indexOf(input.charAt(idx))\n }\n\n // Dump tail\n\n const tailbits = (max % 4) * 6\n\n if (tailbits === 0) {\n result.push((bits >> 16) & 0xFF)\n result.push((bits >> 8) & 0xFF)\n result.push(bits & 0xFF)\n } else if (tailbits === 18) {\n result.push((bits >> 10) & 0xFF)\n result.push((bits >> 2) & 0xFF)\n } else if (tailbits === 12) {\n result.push((bits >> 4) & 0xFF)\n }\n\n return new Uint8Array(result)\n}\n\nfunction representYamlBinary (object /*, style */) {\n let result = ''\n let bits = 0\n const max = object.length\n const map = BASE64_MAP\n\n // Convert every three bytes to 4 ASCII characters.\n\n for (let idx = 0; idx < max; idx++) {\n if ((idx % 3 === 0) && idx) {\n result += map[(bits >> 18) & 0x3F]\n result += map[(bits >> 12) & 0x3F]\n result += map[(bits >> 6) & 0x3F]\n result += map[bits & 0x3F]\n }\n\n bits = (bits << 8) + object[idx]\n }\n\n // Dump tail\n\n const tail = max % 3\n\n if (tail === 0) {\n result += map[(bits >> 18) & 0x3F]\n result += map[(bits >> 12) & 0x3F]\n result += map[(bits >> 6) & 0x3F]\n result += map[bits & 0x3F]\n } else if (tail === 2) {\n result += map[(bits >> 10) & 0x3F]\n result += map[(bits >> 4) & 0x3F]\n result += map[(bits << 2) & 0x3F]\n result += map[64]\n } else if (tail === 1) {\n result += map[(bits >> 2) & 0x3F]\n result += map[(bits << 4) & 0x3F]\n result += map[64]\n result += map[64]\n }\n\n return result\n}\n\nfunction isBinary (obj) {\n return Object.prototype.toString.call(obj) === '[object Uint8Array]'\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:binary', {\n kind: 'scalar',\n resolve: resolveYamlBinary,\n construct: constructYamlBinary,\n predicate: isBinary,\n represent: representYamlBinary\n})\n","'use strict'\n\nconst Type = require('../type')\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\nconst _toString = Object.prototype.toString\n\nfunction resolveYamlOmap (data) {\n if (data === null) return true\n\n const objectKeys = {}\n const object = data\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n const pair = object[index]\n let pairHasKey = false\n\n if (_toString.call(pair) !== '[object Object]') return false\n\n let pairKey\n for (pairKey in pair) {\n if (_hasOwnProperty.call(pair, pairKey)) {\n if (!pairHasKey) pairHasKey = true\n else return false\n }\n }\n\n if (!pairHasKey) return false\n\n if (_hasOwnProperty.call(objectKeys, pairKey)) return false\n Object.defineProperty(objectKeys, pairKey, { value: true })\n }\n\n return true\n}\n\nfunction constructYamlOmap (data) {\n return data !== null ? data : []\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:omap', {\n kind: 'sequence',\n resolve: resolveYamlOmap,\n construct: constructYamlOmap\n})\n","'use strict'\n\nconst Type = require('../type')\n\nconst _toString = Object.prototype.toString\n\nfunction resolveYamlPairs (data) {\n if (data === null) return true\n\n const object = data\n\n const result = new Array(object.length)\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n const pair = object[index]\n\n if (_toString.call(pair) !== '[object Object]') return false\n\n const keys = Object.keys(pair)\n\n if (keys.length !== 1) return false\n\n result[index] = [keys[0], pair[keys[0]]]\n }\n\n return true\n}\n\nfunction constructYamlPairs (data) {\n if (data === null) return []\n\n const object = data\n const result = new Array(object.length)\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n const pair = object[index]\n\n const keys = Object.keys(pair)\n\n result[index] = [keys[0], pair[keys[0]]]\n }\n\n return result\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:pairs', {\n kind: 'sequence',\n resolve: resolveYamlPairs,\n construct: constructYamlPairs\n})\n","'use strict'\n\nconst Type = require('../type')\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\n\nfunction resolveYamlSet (data) {\n if (data === null) return true\n\n const object = data\n\n for (const key in object) {\n if (_hasOwnProperty.call(object, key)) {\n if (object[key] !== null) return false\n }\n }\n\n return true\n}\n\nfunction constructYamlSet (data) {\n return data !== null ? data : {}\n}\n\nmodule.exports = new Type('tag:yaml.org,2002:set', {\n kind: 'mapping',\n resolve: resolveYamlSet,\n construct: constructYamlSet\n})\n","// JS-YAML's default schema for `safeLoad` function.\n// It is not described in the YAML specification.\n//\n// This schema is based on standard YAML's Core schema and includes most of\n// extra types described at YAML tag repository. (http://yaml.org/type/)\n\n'use strict'\n\nmodule.exports = require('./core').extend({\n implicit: [\n require('../type/timestamp'),\n require('../type/merge')\n ],\n explicit: [\n require('../type/binary'),\n require('../type/omap'),\n require('../type/pairs'),\n require('../type/set')\n ]\n})\n","'use strict'\n\nconst common = require('./common')\nconst YAMLException = require('./exception')\nconst makeSnippet = require('./snippet')\nconst DEFAULT_SCHEMA = require('./schema/default')\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\n\nconst CONTEXT_FLOW_IN = 1\nconst CONTEXT_FLOW_OUT = 2\nconst CONTEXT_BLOCK_IN = 3\nconst CONTEXT_BLOCK_OUT = 4\n\nconst CHOMPING_CLIP = 1\nconst CHOMPING_STRIP = 2\nconst CHOMPING_KEEP = 3\n\n// eslint-disable-next-line no-control-regex\nconst PATTERN_NON_PRINTABLE = /[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x84\\x86-\\x9F\\uFFFE\\uFFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/\nconst PATTERN_NON_ASCII_LINE_BREAKS = /[\\x85\\u2028\\u2029]/\n// eslint-disable-next-line no-useless-escape\nconst PATTERN_FLOW_INDICATORS = /[,\\[\\]{}]/\n// eslint-disable-next-line no-useless-escape\nconst PATTERN_TAG_HANDLE = /^(?:!|!!|![0-9A-Za-z-]+!)$/\n// eslint-disable-next-line no-useless-escape\nconst PATTERN_TAG_URI = /^(?:!|[^,\\[\\]{}])(?:%[0-9a-f]{2}|[0-9a-z\\-#;/?:@&=+$,_.!~*'()\\[\\]])*$/i\n\nfunction _class (obj) { return Object.prototype.toString.call(obj) }\n\nfunction isEol (c) {\n return (c === 0x0A/* LF */) || (c === 0x0D/* CR */)\n}\n\nfunction isWhiteSpace (c) {\n return (c === 0x09/* Tab */) || (c === 0x20/* Space */)\n}\n\nfunction isWsOrEol (c) {\n return (c === 0x09/* Tab */) ||\n (c === 0x20/* Space */) ||\n (c === 0x0A/* LF */) ||\n (c === 0x0D/* CR */)\n}\n\nfunction isFlowIndicator (c) {\n return c === 0x2C/* , */ ||\n c === 0x5B/* [ */ ||\n c === 0x5D/* ] */ ||\n c === 0x7B/* { */ ||\n c === 0x7D/* } */\n}\n\nfunction fromHexCode (c) {\n if ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) {\n return c - 0x30\n }\n\n const lc = c | 0x20\n\n if ((lc >= 0x61/* a */) && (lc <= 0x66/* f */)) {\n return lc - 0x61 + 10\n }\n\n return -1\n}\n\nfunction escapedHexLen (c) {\n if (c === 0x78/* x */) { return 2 }\n if (c === 0x75/* u */) { return 4 }\n if (c === 0x55/* U */) { return 8 }\n return 0\n}\n\nfunction fromDecimalCode (c) {\n if ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) {\n return c - 0x30\n }\n\n return -1\n}\n\nfunction simpleEscapeSequence (c) {\n switch (c) {\n case 0x30/* 0 */: return '\\x00'\n case 0x61/* a */: return '\\x07'\n case 0x62/* b */: return '\\x08'\n case 0x74/* t */: return '\\x09'\n case 0x09/* Tab */: return '\\x09'\n case 0x6E/* n */: return '\\x0A'\n case 0x76/* v */: return '\\x0B'\n case 0x66/* f */: return '\\x0C'\n case 0x72/* r */: return '\\x0D'\n case 0x65/* e */: return '\\x1B'\n case 0x20/* Space */: return ' '\n case 0x22/* \" */: return '\\x22'\n case 0x2F/* / */: return '/'\n case 0x5C/* \\ */: return '\\x5C'\n case 0x4E/* N */: return '\\x85'\n case 0x5F/* _ */: return '\\xA0'\n case 0x4C/* L */: return '\\u2028'\n case 0x50/* P */: return '\\u2029'\n default: return ''\n }\n}\n\nfunction charFromCodepoint (c) {\n if (c <= 0xFFFF) {\n return String.fromCharCode(c)\n }\n // Encode UTF-16 surrogate pair\n // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF\n return String.fromCharCode(\n ((c - 0x010000) >> 10) + 0xD800,\n ((c - 0x010000) & 0x03FF) + 0xDC00\n )\n}\n\n// set a property of a literal object, while protecting against prototype pollution,\n// see https://github.com/nodeca/js-yaml/issues/164 for more details\nfunction setProperty (object, key, value) {\n // used for this specific key only because Object.defineProperty is slow\n if (key === '__proto__') {\n Object.defineProperty(object, key, {\n configurable: true,\n enumerable: true,\n writable: true,\n value: value\n })\n } else {\n object[key] = value\n }\n}\n\nconst simpleEscapeCheck = new Array(256) // integer, for fast access\nconst simpleEscapeMap = new Array(256)\nfor (let i = 0; i < 256; i++) {\n simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0\n simpleEscapeMap[i] = simpleEscapeSequence(i)\n}\n\nfunction State (input, options) {\n this.input = input\n\n this.filename = options['filename'] || null\n this.schema = options['schema'] || DEFAULT_SCHEMA\n this.onWarning = options['onWarning'] || null\n // (Hidden) Remove? makes the loader to expect YAML 1.1 documents\n // if such documents have no explicit %YAML directive\n this.legacy = options['legacy'] || false\n\n this.json = options['json'] || false\n this.listener = options['listener'] || null\n this.maxDepth = typeof options['maxDepth'] === 'number' ? options['maxDepth'] : 100\n this.maxTotalMergeKeys = typeof options['maxTotalMergeKeys'] === 'number' ? options['maxTotalMergeKeys'] : 10000\n\n this.implicitTypes = this.schema.compiledImplicit\n this.typeMap = this.schema.compiledTypeMap\n\n this.length = input.length\n this.position = 0\n this.line = 0\n this.lineStart = 0\n this.lineIndent = 0\n this.depth = 0\n this.totalMergeKeys = 0\n\n // position of first leading tab in the current line,\n // used to make sure there are no tabs in the indentation\n this.firstTabInLine = -1\n\n this.documents = []\n this.anchorMapTransactions = []\n\n /*\n this.version;\n this.checkLineBreaks;\n this.tagMap;\n this.anchorMap;\n this.tag;\n this.anchor;\n this.kind;\n this.result; */\n}\n\nfunction generateError (state, message) {\n const mark = {\n name: state.filename,\n buffer: state.input.slice(0, -1), // omit trailing \\0\n position: state.position,\n line: state.line,\n column: state.position - state.lineStart\n }\n\n mark.snippet = makeSnippet(mark)\n\n return new YAMLException(message, mark)\n}\n\nfunction throwError (state, message) {\n throw generateError(state, message)\n}\n\nfunction throwWarning (state, message) {\n if (state.onWarning) {\n state.onWarning.call(null, generateError(state, message))\n }\n}\n\nfunction storeAnchor (state, name, value) {\n const transactions = state.anchorMapTransactions\n\n if (transactions.length !== 0) {\n const transaction = transactions[transactions.length - 1]\n\n if (!_hasOwnProperty.call(transaction, name)) {\n transaction[name] = {\n existed: _hasOwnProperty.call(state.anchorMap, name),\n value: state.anchorMap[name]\n }\n }\n }\n\n state.anchorMap[name] = value\n}\n\nfunction beginAnchorTransaction (state) {\n state.anchorMapTransactions.push(Object.create(null))\n}\n\nfunction commitAnchorTransaction (state) {\n const transaction = state.anchorMapTransactions.pop()\n const transactions = state.anchorMapTransactions\n\n if (transactions.length === 0) return\n\n const parent = transactions[transactions.length - 1]\n const names = Object.keys(transaction)\n\n for (let index = 0, length = names.length; index < length; index += 1) {\n const name = names[index]\n\n if (!_hasOwnProperty.call(parent, name)) {\n parent[name] = transaction[name]\n }\n }\n}\n\nfunction rollbackAnchorTransaction (state) {\n const transaction = state.anchorMapTransactions.pop()\n const names = Object.keys(transaction)\n\n for (let index = names.length - 1; index >= 0; index -= 1) {\n const entry = transaction[names[index]]\n\n if (entry.existed) {\n state.anchorMap[names[index]] = entry.value\n } else {\n delete state.anchorMap[names[index]]\n }\n }\n}\n\nfunction snapshotState (state) {\n return {\n position: state.position,\n line: state.line,\n lineStart: state.lineStart,\n lineIndent: state.lineIndent,\n firstTabInLine: state.firstTabInLine,\n tag: state.tag,\n anchor: state.anchor,\n kind: state.kind,\n result: state.result\n }\n}\n\nfunction restoreState (state, snapshot) {\n state.position = snapshot.position\n state.line = snapshot.line\n state.lineStart = snapshot.lineStart\n state.lineIndent = snapshot.lineIndent\n state.firstTabInLine = snapshot.firstTabInLine\n state.tag = snapshot.tag\n state.anchor = snapshot.anchor\n state.kind = snapshot.kind\n state.result = snapshot.result\n}\n\nconst directiveHandlers = {\n\n YAML: function handleYamlDirective (state, name, args) {\n if (state.version !== null) {\n throwError(state, 'duplication of %YAML directive')\n }\n\n if (args.length !== 1) {\n throwError(state, 'YAML directive accepts exactly one argument')\n }\n\n const match = /^([0-9]+)\\.([0-9]+)$/.exec(args[0])\n\n if (match === null) {\n throwError(state, 'ill-formed argument of the YAML directive')\n }\n\n const major = parseInt(match[1], 10)\n const minor = parseInt(match[2], 10)\n\n if (major !== 1) {\n throwError(state, 'unacceptable YAML version of the document')\n }\n\n state.version = args[0]\n state.checkLineBreaks = (minor < 2)\n\n if (minor !== 1 && minor !== 2) {\n throwWarning(state, 'unsupported YAML version of the document')\n }\n },\n\n TAG: function handleTagDirective (state, name, args) {\n let prefix\n\n if (args.length !== 2) {\n throwError(state, 'TAG directive accepts exactly two arguments')\n }\n\n const handle = args[0]\n prefix = args[1]\n\n if (!PATTERN_TAG_HANDLE.test(handle)) {\n throwError(state, 'ill-formed tag handle (first argument) of the TAG directive')\n }\n\n if (_hasOwnProperty.call(state.tagMap, handle)) {\n throwError(state, 'there is a previously declared suffix for \"' + handle + '\" tag handle')\n }\n\n if (!PATTERN_TAG_URI.test(prefix)) {\n throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive')\n }\n\n try {\n prefix = decodeURIComponent(prefix)\n } catch (err) {\n throwError(state, 'tag prefix is malformed: ' + prefix)\n }\n\n state.tagMap[handle] = prefix\n }\n}\n\nfunction captureSegment (state, start, end, checkJson) {\n if (start < end) {\n const _result = state.input.slice(start, end)\n\n if (checkJson) {\n for (let _position = 0, _length = _result.length; _position < _length; _position += 1) {\n const _character = _result.charCodeAt(_position)\n if (!(_character === 0x09 ||\n (_character >= 0x20 && _character <= 0x10FFFF))) {\n throwError(state, 'expected valid JSON character')\n }\n }\n } else if (PATTERN_NON_PRINTABLE.test(_result)) {\n throwError(state, 'the stream contains non-printable characters')\n }\n\n state.result += _result\n }\n}\n\nfunction mergeMappings (state, destination, source, overridableKeys) {\n if (!common.isObject(source)) {\n throwError(state, 'cannot merge mappings; the provided source object is unacceptable')\n }\n\n const sourceKeys = Object.keys(source)\n\n for (let index = 0, quantity = sourceKeys.length; index < quantity; index += 1) {\n const key = sourceKeys[index]\n\n if (state.maxTotalMergeKeys !== -1 && ++state.totalMergeKeys > state.maxTotalMergeKeys) {\n throwError(state, 'merge keys exceeded maxTotalMergeKeys (' + state.maxTotalMergeKeys + ')')\n }\n\n if (!_hasOwnProperty.call(destination, key)) {\n setProperty(destination, key, source[key])\n overridableKeys[key] = true\n }\n }\n}\n\nfunction storeMappingPair (state, _result, overridableKeys, keyTag, keyNode, valueNode,\n startLine, startLineStart, startPos) {\n // The output is a plain object here, so keys can only be strings.\n // We need to convert keyNode to a string, but doing so can hang the process\n // (deeply nested arrays that explode exponentially using aliases).\n if (Array.isArray(keyNode)) {\n keyNode = Array.prototype.slice.call(keyNode)\n\n for (let index = 0, quantity = keyNode.length; index < quantity; index += 1) {\n if (Array.isArray(keyNode[index])) {\n throwError(state, 'nested arrays are not supported inside keys')\n }\n\n if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') {\n keyNode[index] = '[object Object]'\n }\n }\n }\n\n // Avoid code execution in load() via toString property\n // (still use its own toString for arrays, timestamps,\n // and whatever user schema extensions happen to have @@toStringTag)\n if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') {\n keyNode = '[object Object]'\n }\n\n keyNode = String(keyNode)\n\n if (_result === null) {\n _result = {}\n }\n\n if (keyTag === 'tag:yaml.org,2002:merge') {\n if (Array.isArray(valueNode)) {\n for (let index = 0, quantity = valueNode.length; index < quantity; index += 1) {\n mergeMappings(state, _result, valueNode[index], overridableKeys)\n }\n } else {\n mergeMappings(state, _result, valueNode, overridableKeys)\n }\n } else {\n if (!state.json &&\n !_hasOwnProperty.call(overridableKeys, keyNode) &&\n _hasOwnProperty.call(_result, keyNode)) {\n state.line = startLine || state.line\n state.lineStart = startLineStart || state.lineStart\n state.position = startPos || state.position\n throwError(state, 'duplicated mapping key')\n }\n\n setProperty(_result, keyNode, valueNode)\n delete overridableKeys[keyNode]\n }\n\n return _result\n}\n\nfunction readLineBreak (state) {\n const ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x0A/* LF */) {\n state.position++\n } else if (ch === 0x0D/* CR */) {\n state.position++\n if (state.input.charCodeAt(state.position) === 0x0A/* LF */) {\n state.position++\n }\n } else {\n throwError(state, 'a line break is expected')\n }\n\n state.line += 1\n state.lineStart = state.position\n state.firstTabInLine = -1\n}\n\nfunction skipSeparationSpace (state, allowComments, checkIndent) {\n let lineBreaks = 0\n let ch = state.input.charCodeAt(state.position)\n\n while (ch !== 0) {\n while (isWhiteSpace(ch)) {\n if (ch === 0x09/* Tab */ && state.firstTabInLine === -1) {\n state.firstTabInLine = state.position\n }\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (allowComments && ch === 0x23/* # */) {\n do {\n ch = state.input.charCodeAt(++state.position)\n } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0)\n }\n\n if (isEol(ch)) {\n readLineBreak(state)\n\n ch = state.input.charCodeAt(state.position)\n lineBreaks++\n state.lineIndent = 0\n\n while (ch === 0x20/* Space */) {\n state.lineIndent++\n ch = state.input.charCodeAt(++state.position)\n }\n } else {\n break\n }\n }\n\n if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) {\n throwWarning(state, 'deficient indentation')\n }\n\n return lineBreaks\n}\n\nfunction testDocumentSeparator (state) {\n let _position = state.position\n let ch = state.input.charCodeAt(_position)\n\n // Condition state.position === state.lineStart is tested\n // in parent on each call, for efficiency. No needs to test here again.\n if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) &&\n ch === state.input.charCodeAt(_position + 1) &&\n ch === state.input.charCodeAt(_position + 2)) {\n _position += 3\n\n ch = state.input.charCodeAt(_position)\n\n if (ch === 0 || isWsOrEol(ch)) {\n return true\n }\n }\n\n return false\n}\n\nfunction writeFoldedLines (state, count) {\n if (count === 1) {\n state.result += ' '\n } else if (count > 1) {\n state.result += common.repeat('\\n', count - 1)\n }\n}\n\nfunction readPlainScalar (state, nodeIndent, withinFlowCollection) {\n let captureStart\n let captureEnd\n let hasPendingContent\n let _line\n let _lineStart\n let _lineIndent\n const _kind = state.kind\n const _result = state.result\n\n let ch = state.input.charCodeAt(state.position)\n\n if (isWsOrEol(ch) ||\n isFlowIndicator(ch) ||\n ch === 0x23/* # */ ||\n ch === 0x26/* & */ ||\n ch === 0x2A/* * */ ||\n ch === 0x21/* ! */ ||\n ch === 0x7C/* | */ ||\n ch === 0x3E/* > */ ||\n ch === 0x27/* ' */ ||\n ch === 0x22/* \" */ ||\n ch === 0x25/* % */ ||\n ch === 0x40/* @ */ ||\n ch === 0x60/* ` */) {\n return false\n }\n\n if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) {\n const following = state.input.charCodeAt(state.position + 1)\n\n if (isWsOrEol(following) ||\n (withinFlowCollection && isFlowIndicator(following))) {\n return false\n }\n }\n\n state.kind = 'scalar'\n state.result = ''\n captureStart = captureEnd = state.position\n hasPendingContent = false\n\n while (ch !== 0) {\n if (ch === 0x3A/* : */) {\n const following = state.input.charCodeAt(state.position + 1)\n\n if (isWsOrEol(following) ||\n (withinFlowCollection && isFlowIndicator(following))) {\n break\n }\n } else if (ch === 0x23/* # */) {\n const preceding = state.input.charCodeAt(state.position - 1)\n\n if (isWsOrEol(preceding)) {\n break\n }\n } else if ((state.position === state.lineStart && testDocumentSeparator(state)) ||\n (withinFlowCollection && isFlowIndicator(ch))) {\n break\n } else if (isEol(ch)) {\n _line = state.line\n _lineStart = state.lineStart\n _lineIndent = state.lineIndent\n skipSeparationSpace(state, false, -1)\n\n if (state.lineIndent >= nodeIndent) {\n hasPendingContent = true\n ch = state.input.charCodeAt(state.position)\n continue\n } else {\n state.position = captureEnd\n state.line = _line\n state.lineStart = _lineStart\n state.lineIndent = _lineIndent\n break\n }\n }\n\n if (hasPendingContent) {\n captureSegment(state, captureStart, captureEnd, false)\n writeFoldedLines(state, state.line - _line)\n captureStart = captureEnd = state.position\n hasPendingContent = false\n }\n\n if (!isWhiteSpace(ch)) {\n captureEnd = state.position + 1\n }\n\n ch = state.input.charCodeAt(++state.position)\n }\n\n captureSegment(state, captureStart, captureEnd, false)\n\n if (state.result) {\n return true\n }\n\n state.kind = _kind\n state.result = _result\n return false\n}\n\nfunction readSingleQuotedScalar (state, nodeIndent) {\n let captureStart\n let captureEnd\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x27/* ' */) {\n return false\n }\n\n state.kind = 'scalar'\n state.result = ''\n state.position++\n captureStart = captureEnd = state.position\n\n while ((ch = state.input.charCodeAt(state.position)) !== 0) {\n if (ch === 0x27/* ' */) {\n captureSegment(state, captureStart, state.position, true)\n ch = state.input.charCodeAt(++state.position)\n\n if (ch === 0x27/* ' */) {\n captureStart = state.position\n state.position++\n captureEnd = state.position\n } else {\n return true\n }\n } else if (isEol(ch)) {\n captureSegment(state, captureStart, captureEnd, true)\n writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent))\n captureStart = captureEnd = state.position\n } else if (state.position === state.lineStart && testDocumentSeparator(state)) {\n throwError(state, 'unexpected end of the document within a single quoted scalar')\n } else {\n state.position++\n if (!isWhiteSpace(ch)) {\n captureEnd = state.position\n }\n }\n }\n\n throwError(state, 'unexpected end of the stream within a single quoted scalar')\n}\n\nfunction readDoubleQuotedScalar (state, nodeIndent) {\n let captureStart\n let captureEnd\n let tmp\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x22/* \" */) {\n return false\n }\n\n state.kind = 'scalar'\n state.result = ''\n state.position++\n captureStart = captureEnd = state.position\n\n while ((ch = state.input.charCodeAt(state.position)) !== 0) {\n if (ch === 0x22/* \" */) {\n captureSegment(state, captureStart, state.position, true)\n state.position++\n return true\n } else if (ch === 0x5C/* \\ */) {\n captureSegment(state, captureStart, state.position, true)\n ch = state.input.charCodeAt(++state.position)\n\n if (isEol(ch)) {\n skipSeparationSpace(state, false, nodeIndent)\n\n // TODO: rework to inline fn with no type cast?\n } else if (ch < 256 && simpleEscapeCheck[ch]) {\n state.result += simpleEscapeMap[ch]\n state.position++\n } else if ((tmp = escapedHexLen(ch)) > 0) {\n let hexLength = tmp\n let hexResult = 0\n\n for (; hexLength > 0; hexLength--) {\n ch = state.input.charCodeAt(++state.position)\n\n if ((tmp = fromHexCode(ch)) >= 0) {\n hexResult = (hexResult << 4) + tmp\n } else {\n throwError(state, 'expected hexadecimal character')\n }\n }\n\n state.result += charFromCodepoint(hexResult)\n\n state.position++\n } else {\n throwError(state, 'unknown escape sequence')\n }\n\n captureStart = captureEnd = state.position\n } else if (isEol(ch)) {\n captureSegment(state, captureStart, captureEnd, true)\n writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent))\n captureStart = captureEnd = state.position\n } else if (state.position === state.lineStart && testDocumentSeparator(state)) {\n throwError(state, 'unexpected end of the document within a double quoted scalar')\n } else {\n state.position++\n if (!isWhiteSpace(ch)) {\n captureEnd = state.position\n }\n }\n }\n\n throwError(state, 'unexpected end of the stream within a double quoted scalar')\n}\n\nfunction readFlowCollection (state, nodeIndent) {\n let readNext = true\n let _line\n let _lineStart\n let _pos\n const _tag = state.tag\n let _result\n const _anchor = state.anchor\n let terminator\n let isPair\n let isExplicitPair\n let isMapping\n const overridableKeys = Object.create(null)\n let keyNode\n let keyTag\n let valueNode\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x5B/* [ */) {\n terminator = 0x5D/* ] */\n isMapping = false\n _result = []\n } else if (ch === 0x7B/* { */) {\n terminator = 0x7D/* } */\n isMapping = true\n _result = {}\n } else {\n return false\n }\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, _result)\n }\n\n ch = state.input.charCodeAt(++state.position)\n\n while (ch !== 0) {\n skipSeparationSpace(state, true, nodeIndent)\n\n ch = state.input.charCodeAt(state.position)\n\n if (ch === terminator) {\n state.position++\n state.tag = _tag\n state.anchor = _anchor\n state.kind = isMapping ? 'mapping' : 'sequence'\n state.result = _result\n return true\n } else if (!readNext) {\n throwError(state, 'missed comma between flow collection entries')\n } else if (ch === 0x2C/* , */) {\n // \"flow collection entries can never be completely empty\", as per YAML 1.2, section 7.4\n throwError(state, \"expected the node content, but found ','\")\n }\n\n keyTag = keyNode = valueNode = null\n isPair = isExplicitPair = false\n\n if (ch === 0x3F/* ? */) {\n const following = state.input.charCodeAt(state.position + 1)\n\n if (isWsOrEol(following)) {\n isPair = isExplicitPair = true\n state.position++\n skipSeparationSpace(state, true, nodeIndent)\n }\n }\n\n _line = state.line // Save the current line.\n _lineStart = state.lineStart\n _pos = state.position\n composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true)\n keyTag = state.tag\n keyNode = state.result\n skipSeparationSpace(state, true, nodeIndent)\n\n ch = state.input.charCodeAt(state.position)\n\n if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) {\n isPair = true\n ch = state.input.charCodeAt(++state.position)\n skipSeparationSpace(state, true, nodeIndent)\n composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true)\n valueNode = state.result\n }\n\n if (isMapping) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)\n } else if (isPair) {\n _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos))\n } else {\n _result.push(keyNode)\n }\n\n skipSeparationSpace(state, true, nodeIndent)\n\n ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x2C/* , */) {\n readNext = true\n ch = state.input.charCodeAt(++state.position)\n } else {\n readNext = false\n }\n }\n\n throwError(state, 'unexpected end of the stream within a flow collection')\n}\n\nfunction readBlockScalar (state, nodeIndent) {\n let folding\n let chomping = CHOMPING_CLIP\n let didReadContent = false\n let detectedIndent = false\n let textIndent = nodeIndent\n let emptyLines = 0\n let atMoreIndented = false\n let tmp\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch === 0x7C/* | */) {\n folding = false\n } else if (ch === 0x3E/* > */) {\n folding = true\n } else {\n return false\n }\n\n state.kind = 'scalar'\n state.result = ''\n\n while (ch !== 0) {\n ch = state.input.charCodeAt(++state.position)\n\n if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {\n if (CHOMPING_CLIP === chomping) {\n chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP\n } else {\n throwError(state, 'repeat of a chomping mode identifier')\n }\n } else if ((tmp = fromDecimalCode(ch)) >= 0) {\n if (tmp === 0) {\n throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one')\n } else if (!detectedIndent) {\n textIndent = nodeIndent + tmp - 1\n detectedIndent = true\n } else {\n throwError(state, 'repeat of an indentation width identifier')\n }\n } else {\n break\n }\n }\n\n if (isWhiteSpace(ch)) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (isWhiteSpace(ch))\n\n if (ch === 0x23/* # */) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (!isEol(ch) && (ch !== 0))\n }\n }\n\n while (ch !== 0) {\n readLineBreak(state)\n state.lineIndent = 0\n\n ch = state.input.charCodeAt(state.position)\n\n // eslint-disable-next-line no-unmodified-loop-condition\n while ((!detectedIndent || state.lineIndent < textIndent) &&\n (ch === 0x20/* Space */)) {\n state.lineIndent++\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (!detectedIndent && state.lineIndent > textIndent) {\n textIndent = state.lineIndent\n }\n\n if (isEol(ch)) {\n emptyLines++\n continue\n }\n\n if (!detectedIndent && textIndent === 0) {\n throwError(state, 'missing indentation for block scalar')\n }\n\n // End of the scalar.\n if (state.lineIndent < textIndent) {\n // Perform the chomping.\n if (chomping === CHOMPING_KEEP) {\n state.result += common.repeat('\\n', didReadContent ? 1 + emptyLines : emptyLines)\n } else if (chomping === CHOMPING_CLIP) {\n if (didReadContent) { // i.e. only if the scalar is not empty.\n state.result += '\\n'\n }\n }\n\n // Break this `while` cycle and go to the funciton's epilogue.\n break\n }\n\n // Folded style: use fancy rules to handle line breaks.\n if (folding) {\n // Lines starting with white space characters (more-indented lines) are not folded.\n if (isWhiteSpace(ch)) {\n atMoreIndented = true\n // except for the first content line (cf. Example 8.1)\n state.result += common.repeat('\\n', didReadContent ? 1 + emptyLines : emptyLines)\n\n // End of more-indented block.\n } else if (atMoreIndented) {\n atMoreIndented = false\n state.result += common.repeat('\\n', emptyLines + 1)\n\n // Just one line break - perceive as the same line.\n } else if (emptyLines === 0) {\n if (didReadContent) { // i.e. only if we have already read some scalar content.\n state.result += ' '\n }\n\n // Several line breaks - perceive as different lines.\n } else {\n state.result += common.repeat('\\n', emptyLines)\n }\n\n // Literal style: just add exact number of line breaks between content lines.\n } else {\n // Keep all line breaks except the header line break.\n state.result += common.repeat('\\n', didReadContent ? 1 + emptyLines : emptyLines)\n }\n\n didReadContent = true\n detectedIndent = true\n emptyLines = 0\n const captureStart = state.position\n\n while (!isEol(ch) && (ch !== 0)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n captureSegment(state, captureStart, state.position, false)\n }\n\n return true\n}\n\nfunction readBlockSequence (state, nodeIndent) {\n const _tag = state.tag\n const _anchor = state.anchor\n const _result = []\n let detected = false\n\n // there is a leading tab before this token, so it can't be a block sequence/mapping;\n // it can still be flow sequence/mapping or a scalar\n if (state.firstTabInLine !== -1) return false\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, _result)\n }\n\n let ch = state.input.charCodeAt(state.position)\n\n while (ch !== 0) {\n if (state.firstTabInLine !== -1) {\n state.position = state.firstTabInLine\n throwError(state, 'tab characters must not be used in indentation')\n }\n\n if (ch !== 0x2D/* - */) {\n break\n }\n\n const following = state.input.charCodeAt(state.position + 1)\n\n if (!isWsOrEol(following)) {\n break\n }\n\n detected = true\n state.position++\n\n if (skipSeparationSpace(state, true, -1)) {\n if (state.lineIndent <= nodeIndent) {\n _result.push(null)\n ch = state.input.charCodeAt(state.position)\n continue\n }\n }\n\n const _line = state.line\n composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true)\n _result.push(state.result)\n skipSeparationSpace(state, true, -1)\n\n ch = state.input.charCodeAt(state.position)\n\n if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) {\n throwError(state, 'bad indentation of a sequence entry')\n } else if (state.lineIndent < nodeIndent) {\n break\n }\n }\n\n if (detected) {\n state.tag = _tag\n state.anchor = _anchor\n state.kind = 'sequence'\n state.result = _result\n return true\n }\n return false\n}\n\nfunction readBlockMapping (state, nodeIndent, flowIndent) {\n let allowCompact\n let _keyLine\n let _keyLineStart\n let _keyPos\n const _tag = state.tag\n const _anchor = state.anchor\n const _result = {}\n const overridableKeys = Object.create(null)\n let keyTag = null\n let keyNode = null\n let valueNode = null\n let atExplicitKey = false\n let detected = false\n\n // there is a leading tab before this token, so it can't be a block sequence/mapping;\n // it can still be flow sequence/mapping or a scalar\n if (state.firstTabInLine !== -1) return false\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, _result)\n }\n\n let ch = state.input.charCodeAt(state.position)\n\n while (ch !== 0) {\n if (!atExplicitKey && state.firstTabInLine !== -1) {\n state.position = state.firstTabInLine\n throwError(state, 'tab characters must not be used in indentation')\n }\n\n const following = state.input.charCodeAt(state.position + 1)\n const _line = state.line // Save the current line.\n\n //\n // Explicit notation case. There are two separate blocks:\n // first for the key (denoted by \"?\") and second for the value (denoted by \":\")\n //\n if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && isWsOrEol(following)) {\n if (ch === 0x3F/* ? */) {\n if (atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos)\n keyTag = keyNode = valueNode = null\n }\n\n detected = true\n atExplicitKey = true\n allowCompact = true\n } else if (atExplicitKey) {\n // i.e. 0x3A/* : */ === character after the explicit key.\n atExplicitKey = false\n allowCompact = true\n } else {\n throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line')\n }\n\n state.position += 1\n ch = following\n\n //\n // Implicit notation case. Flow-style node as the key first, then \":\", and the value.\n //\n } else {\n _keyLine = state.line\n _keyLineStart = state.lineStart\n _keyPos = state.position\n\n if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) {\n // Neither implicit nor explicit notation.\n // Reading is done. Go to the epilogue.\n break\n }\n\n if (state.line === _line) {\n ch = state.input.charCodeAt(state.position)\n\n while (isWhiteSpace(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (ch === 0x3A/* : */) {\n ch = state.input.charCodeAt(++state.position)\n\n if (!isWsOrEol(ch)) {\n throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping')\n }\n\n if (atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos)\n keyTag = keyNode = valueNode = null\n }\n\n detected = true\n atExplicitKey = false\n allowCompact = false\n keyTag = state.tag\n keyNode = state.result\n } else if (detected) {\n throwError(state, 'can not read an implicit mapping pair; a colon is missed')\n } else {\n state.tag = _tag\n state.anchor = _anchor\n return true // Keep the result of `composeNode`.\n }\n } else if (detected) {\n throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key')\n } else {\n state.tag = _tag\n state.anchor = _anchor\n return true // Keep the result of `composeNode`.\n }\n }\n\n //\n // Common reading code for both explicit and implicit notations.\n //\n if (state.line === _line || state.lineIndent > nodeIndent) {\n if (atExplicitKey) {\n _keyLine = state.line\n _keyLineStart = state.lineStart\n _keyPos = state.position\n }\n\n if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) {\n if (atExplicitKey) {\n keyNode = state.result\n } else {\n valueNode = state.result\n }\n }\n\n if (!atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos)\n keyTag = keyNode = valueNode = null\n }\n\n skipSeparationSpace(state, true, -1)\n ch = state.input.charCodeAt(state.position)\n }\n\n if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) {\n throwError(state, 'bad indentation of a mapping entry')\n } else if (state.lineIndent < nodeIndent) {\n break\n }\n }\n\n //\n // Epilogue.\n //\n\n // Special case: last mapping's node contains only the key in explicit notation.\n if (atExplicitKey) {\n storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos)\n }\n\n // Expose the resulting mapping.\n if (detected) {\n state.tag = _tag\n state.anchor = _anchor\n state.kind = 'mapping'\n state.result = _result\n }\n\n return detected\n}\n\nfunction readTagProperty (state) {\n let isVerbatim = false\n let isNamed = false\n let tagHandle\n let tagName\n\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x21/* ! */) return false\n\n if (state.tag !== null) {\n throwError(state, 'duplication of a tag property')\n }\n\n ch = state.input.charCodeAt(++state.position)\n\n if (ch === 0x3C/* < */) {\n isVerbatim = true\n ch = state.input.charCodeAt(++state.position)\n } else if (ch === 0x21/* ! */) {\n isNamed = true\n tagHandle = '!!'\n ch = state.input.charCodeAt(++state.position)\n } else {\n tagHandle = '!'\n }\n\n let _position = state.position\n\n if (isVerbatim) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (ch !== 0 && ch !== 0x3E/* > */)\n\n if (state.position < state.length) {\n tagName = state.input.slice(_position, state.position)\n ch = state.input.charCodeAt(++state.position)\n } else {\n throwError(state, 'unexpected end of the stream within a verbatim tag')\n }\n } else {\n while (ch !== 0 && !isWsOrEol(ch)) {\n if (ch === 0x21/* ! */) {\n if (!isNamed) {\n tagHandle = state.input.slice(_position - 1, state.position + 1)\n\n if (!PATTERN_TAG_HANDLE.test(tagHandle)) {\n throwError(state, 'named tag handle cannot contain such characters')\n }\n\n isNamed = true\n _position = state.position + 1\n } else {\n throwError(state, 'tag suffix cannot contain exclamation marks')\n }\n }\n\n ch = state.input.charCodeAt(++state.position)\n }\n\n tagName = state.input.slice(_position, state.position)\n\n if (PATTERN_FLOW_INDICATORS.test(tagName)) {\n throwError(state, 'tag suffix cannot contain flow indicator characters')\n }\n }\n\n if (tagName && !PATTERN_TAG_URI.test(tagName)) {\n throwError(state, 'tag name cannot contain such characters: ' + tagName)\n }\n\n try {\n tagName = decodeURIComponent(tagName)\n } catch (err) {\n throwError(state, 'tag name is malformed: ' + tagName)\n }\n\n if (isVerbatim) {\n state.tag = tagName\n } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) {\n state.tag = state.tagMap[tagHandle] + tagName\n } else if (tagHandle === '!') {\n state.tag = '!' + tagName\n } else if (tagHandle === '!!') {\n state.tag = 'tag:yaml.org,2002:' + tagName\n } else {\n throwError(state, 'undeclared tag handle \"' + tagHandle + '\"')\n }\n\n return true\n}\n\nfunction readAnchorProperty (state) {\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x26/* & */) return false\n\n if (state.anchor !== null) {\n throwError(state, 'duplication of an anchor property')\n }\n\n ch = state.input.charCodeAt(++state.position)\n const _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (state.position === _position) {\n throwError(state, 'name of an anchor node must contain at least one character')\n }\n\n state.anchor = state.input.slice(_position, state.position)\n return true\n}\n\nfunction readAlias (state) {\n let ch = state.input.charCodeAt(state.position)\n\n if (ch !== 0x2A/* * */) return false\n\n ch = state.input.charCodeAt(++state.position)\n const _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (state.position === _position) {\n throwError(state, 'name of an alias node must contain at least one character')\n }\n\n const alias = state.input.slice(_position, state.position)\n\n if (!_hasOwnProperty.call(state.anchorMap, alias)) {\n throwError(state, 'unidentified alias \"' + alias + '\"')\n }\n\n state.result = state.anchorMap[alias]\n skipSeparationSpace(state, true, -1)\n return true\n}\n\nfunction tryReadBlockMappingFromProperty (state, propertyStart, nodeIndent, flowIndent) {\n const fallbackState = snapshotState(state)\n\n beginAnchorTransaction(state)\n restoreState(state, propertyStart)\n\n // Re-read the leading properties as part of the first implicit key, not as\n // properties of the current node.\n state.tag = null\n state.anchor = null\n state.kind = null\n state.result = null\n\n if (readBlockMapping(state, nodeIndent, flowIndent) && state.kind === 'mapping') {\n commitAnchorTransaction(state)\n return true\n }\n\n rollbackAnchorTransaction(state)\n restoreState(state, fallbackState)\n return false\n}\n\nfunction composeNode (state, parentIndent, nodeContext, allowToSeek, allowCompact) {\n let allowBlockScalars\n let allowBlockCollections\n let indentStatus = 1 // 1: this>parent, 0: this=parent, -1: this= state.maxDepth) {\n throwError(state, 'nesting exceeded maxDepth (' + state.maxDepth + ')')\n }\n\n state.depth += 1\n\n if (state.listener !== null) {\n state.listener('open', state)\n }\n\n state.tag = null\n state.anchor = null\n state.kind = null\n state.result = null\n\n const allowBlockStyles = allowBlockScalars = allowBlockCollections =\n CONTEXT_BLOCK_OUT === nodeContext ||\n CONTEXT_BLOCK_IN === nodeContext\n\n if (allowToSeek) {\n if (skipSeparationSpace(state, true, -1)) {\n atNewLine = true\n\n if (state.lineIndent > parentIndent) {\n indentStatus = 1\n } else if (state.lineIndent === parentIndent) {\n indentStatus = 0\n } else if (state.lineIndent < parentIndent) {\n indentStatus = -1\n }\n }\n }\n\n if (indentStatus === 1) {\n while (true) {\n const ch = state.input.charCodeAt(state.position)\n const propertyState = snapshotState(state)\n\n // A duplicate property token after a line break can be the first key of\n // a nested block mapping, e.g. `!!map\\n !!str key: value`.\n if (atNewLine &&\n ((ch === 0x21/* ! */ && state.tag !== null) ||\n (ch === 0x26/* & */ && state.anchor !== null))) {\n break\n }\n\n if (!readTagProperty(state) && !readAnchorProperty(state)) {\n break\n }\n\n if (propertyStart === null) {\n propertyStart = propertyState\n }\n\n if (skipSeparationSpace(state, true, -1)) {\n atNewLine = true\n allowBlockCollections = allowBlockStyles\n\n if (state.lineIndent > parentIndent) {\n indentStatus = 1\n } else if (state.lineIndent === parentIndent) {\n indentStatus = 0\n } else if (state.lineIndent < parentIndent) {\n indentStatus = -1\n }\n } else {\n allowBlockCollections = false\n }\n }\n }\n\n if (allowBlockCollections) {\n allowBlockCollections = atNewLine || allowCompact\n }\n\n if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) {\n if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) {\n flowIndent = parentIndent\n } else {\n flowIndent = parentIndent + 1\n }\n\n blockIndent = state.position - state.lineStart\n\n if (indentStatus === 1) {\n if ((allowBlockCollections &&\n (readBlockSequence(state, blockIndent) || readBlockMapping(state, blockIndent, flowIndent))) ||\n readFlowCollection(state, flowIndent)) {\n hasContent = true\n } else {\n const ch = state.input.charCodeAt(state.position)\n\n if (propertyStart !== null && allowBlockStyles && !allowBlockCollections &&\n ch !== 0x7C/* | */ && ch !== 0x3E/* > */ &&\n tryReadBlockMappingFromProperty(\n state,\n propertyStart,\n propertyStart.position - propertyStart.lineStart,\n flowIndent\n )) {\n hasContent = true\n } else if ((allowBlockScalars && readBlockScalar(state, flowIndent)) ||\n readSingleQuotedScalar(state, flowIndent) ||\n readDoubleQuotedScalar(state, flowIndent)) {\n hasContent = true\n } else if (readAlias(state)) {\n hasContent = true\n\n if (state.tag !== null || state.anchor !== null) {\n throwError(state, 'alias node should not have any properties')\n }\n } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) {\n hasContent = true\n\n if (state.tag === null) {\n state.tag = '?'\n }\n }\n\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n }\n } else if (indentStatus === 0) {\n // Special case: block sequences are allowed to have same indentation level as the parent.\n // http://www.yaml.org/spec/1.2/spec.html#id2799784\n hasContent = allowBlockCollections && readBlockSequence(state, blockIndent)\n }\n }\n\n if (state.tag === null) {\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n } else if (state.tag === '?') {\n // Implicit resolving is not allowed for non-scalar types, and '?'\n // non-specific tag is only automatically assigned to plain scalars.\n //\n // We only need to check kind conformity in case user explicitly assigns '?'\n // tag, for example like this: \"! [0]\"\n //\n if (state.result !== null && state.kind !== 'scalar') {\n throwError(state, 'unacceptable node kind for ! tag; it should be \"scalar\", not \"' + state.kind + '\"')\n }\n\n for (let typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) {\n type = state.implicitTypes[typeIndex]\n\n if (type.resolve(state.result)) { // `state.result` updated in resolver if matched\n state.result = type.construct(state.result)\n state.tag = type.tag\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n break\n }\n }\n } else if (state.tag !== '!') {\n if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) {\n type = state.typeMap[state.kind || 'fallback'][state.tag]\n } else {\n // looking for multi type\n type = null\n const typeList = state.typeMap.multi[state.kind || 'fallback']\n\n for (let typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) {\n if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) {\n type = typeList[typeIndex]\n break\n }\n }\n }\n\n if (!type) {\n throwError(state, 'unknown tag !<' + state.tag + '>')\n }\n\n if (state.result !== null && type.kind !== state.kind) {\n throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be \"' + type.kind + '\", not \"' + state.kind + '\"')\n }\n\n if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched\n throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag')\n } else {\n state.result = type.construct(state.result, state.tag)\n if (state.anchor !== null) {\n storeAnchor(state, state.anchor, state.result)\n }\n }\n }\n\n if (state.listener !== null) {\n state.listener('close', state)\n }\n\n state.depth -= 1\n return state.tag !== null || state.anchor !== null || hasContent\n}\n\nfunction readDocument (state) {\n const documentStart = state.position\n let hasDirectives = false\n let ch\n\n state.version = null\n state.checkLineBreaks = state.legacy\n state.tagMap = Object.create(null)\n state.anchorMap = Object.create(null)\n\n while ((ch = state.input.charCodeAt(state.position)) !== 0) {\n skipSeparationSpace(state, true, -1)\n\n ch = state.input.charCodeAt(state.position)\n\n if (state.lineIndent > 0 || ch !== 0x25/* % */) {\n break\n }\n\n hasDirectives = true\n ch = state.input.charCodeAt(++state.position)\n let _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n const directiveName = state.input.slice(_position, state.position)\n const directiveArgs = []\n\n if (directiveName.length < 1) {\n throwError(state, 'directive name must not be less than one character in length')\n }\n\n while (ch !== 0) {\n while (isWhiteSpace(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n if (ch === 0x23/* # */) {\n do { ch = state.input.charCodeAt(++state.position) }\n while (ch !== 0 && !isEol(ch))\n break\n }\n\n if (isEol(ch)) break\n\n _position = state.position\n\n while (ch !== 0 && !isWsOrEol(ch)) {\n ch = state.input.charCodeAt(++state.position)\n }\n\n directiveArgs.push(state.input.slice(_position, state.position))\n }\n\n if (ch !== 0) readLineBreak(state)\n\n if (_hasOwnProperty.call(directiveHandlers, directiveName)) {\n directiveHandlers[directiveName](state, directiveName, directiveArgs)\n } else {\n throwWarning(state, 'unknown document directive \"' + directiveName + '\"')\n }\n }\n\n skipSeparationSpace(state, true, -1)\n\n if (state.lineIndent === 0 &&\n state.input.charCodeAt(state.position) === 0x2D/* - */ &&\n state.input.charCodeAt(state.position + 1) === 0x2D/* - */ &&\n state.input.charCodeAt(state.position + 2) === 0x2D/* - */) {\n state.position += 3\n skipSeparationSpace(state, true, -1)\n } else if (hasDirectives) {\n throwError(state, 'directives end mark is expected')\n }\n\n composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true)\n skipSeparationSpace(state, true, -1)\n\n if (state.checkLineBreaks &&\n PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) {\n throwWarning(state, 'non-ASCII line breaks are interpreted as content')\n }\n\n state.documents.push(state.result)\n\n if (state.position === state.lineStart && testDocumentSeparator(state)) {\n if (state.input.charCodeAt(state.position) === 0x2E/* . */) {\n state.position += 3\n skipSeparationSpace(state, true, -1)\n }\n return\n }\n\n if (state.position < (state.length - 1)) {\n throwError(state, 'end of the stream or a document separator is expected')\n }\n}\n\nfunction loadDocuments (input, options) {\n input = String(input)\n options = options || {}\n\n if (input.length !== 0) {\n // Add tailing `\\n` if not exists\n if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ &&\n input.charCodeAt(input.length - 1) !== 0x0D/* CR */) {\n input += '\\n'\n }\n\n // Strip BOM\n if (input.charCodeAt(0) === 0xFEFF) {\n input = input.slice(1)\n }\n }\n\n const state = new State(input, options)\n\n const nullpos = input.indexOf('\\0')\n\n if (nullpos !== -1) {\n state.position = nullpos\n throwError(state, 'null byte is not allowed in input')\n }\n\n // Use 0 as string terminator. That significantly simplifies bounds check.\n state.input += '\\0'\n\n while (state.input.charCodeAt(state.position) === 0x20/* Space */) {\n state.lineIndent += 1\n state.position += 1\n }\n\n while (state.position < (state.length - 1)) {\n readDocument(state)\n }\n\n return state.documents\n}\n\nfunction loadAll (input, iterator, options) {\n if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') {\n options = iterator\n iterator = null\n }\n\n const documents = loadDocuments(input, options)\n\n if (typeof iterator !== 'function') {\n return documents\n }\n\n for (let index = 0, length = documents.length; index < length; index += 1) {\n iterator(documents[index])\n }\n}\n\nfunction load (input, options) {\n const documents = loadDocuments(input, options)\n\n if (documents.length === 0) {\n return undefined\n } else if (documents.length === 1) {\n return documents[0]\n }\n throw new YAMLException('expected a single document in the stream, but found more')\n}\n\nmodule.exports.loadAll = loadAll\nmodule.exports.load = load\n","'use strict'\n\nconst common = require('./common')\nconst YAMLException = require('./exception')\nconst DEFAULT_SCHEMA = require('./schema/default')\n\nconst _toString = Object.prototype.toString\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\n\nconst CHAR_BOM = 0xFEFF\nconst CHAR_TAB = 0x09 /* Tab */\nconst CHAR_LINE_FEED = 0x0A /* LF */\nconst CHAR_CARRIAGE_RETURN = 0x0D /* CR */\nconst CHAR_SPACE = 0x20 /* Space */\nconst CHAR_EXCLAMATION = 0x21 /* ! */\nconst CHAR_DOUBLE_QUOTE = 0x22 /* \" */\nconst CHAR_SHARP = 0x23 /* # */\nconst CHAR_PERCENT = 0x25 /* % */\nconst CHAR_AMPERSAND = 0x26 /* & */\nconst CHAR_SINGLE_QUOTE = 0x27 /* ' */\nconst CHAR_ASTERISK = 0x2A /* * */\nconst CHAR_COMMA = 0x2C /* , */\nconst CHAR_MINUS = 0x2D /* - */\nconst CHAR_COLON = 0x3A /* : */\nconst CHAR_EQUALS = 0x3D /* = */\nconst CHAR_GREATER_THAN = 0x3E /* > */\nconst CHAR_QUESTION = 0x3F /* ? */\nconst CHAR_COMMERCIAL_AT = 0x40 /* @ */\nconst CHAR_LEFT_SQUARE_BRACKET = 0x5B /* [ */\nconst CHAR_RIGHT_SQUARE_BRACKET = 0x5D /* ] */\nconst CHAR_GRAVE_ACCENT = 0x60 /* ` */\nconst CHAR_LEFT_CURLY_BRACKET = 0x7B /* { */\nconst CHAR_VERTICAL_LINE = 0x7C /* | */\nconst CHAR_RIGHT_CURLY_BRACKET = 0x7D /* } */\n\nconst ESCAPE_SEQUENCES = {}\n\nESCAPE_SEQUENCES[0x00] = '\\\\0'\nESCAPE_SEQUENCES[0x07] = '\\\\a'\nESCAPE_SEQUENCES[0x08] = '\\\\b'\nESCAPE_SEQUENCES[0x09] = '\\\\t'\nESCAPE_SEQUENCES[0x0A] = '\\\\n'\nESCAPE_SEQUENCES[0x0B] = '\\\\v'\nESCAPE_SEQUENCES[0x0C] = '\\\\f'\nESCAPE_SEQUENCES[0x0D] = '\\\\r'\nESCAPE_SEQUENCES[0x1B] = '\\\\e'\nESCAPE_SEQUENCES[0x22] = '\\\\\"'\nESCAPE_SEQUENCES[0x5C] = '\\\\\\\\'\nESCAPE_SEQUENCES[0x85] = '\\\\N'\nESCAPE_SEQUENCES[0xA0] = '\\\\_'\nESCAPE_SEQUENCES[0x2028] = '\\\\L'\nESCAPE_SEQUENCES[0x2029] = '\\\\P'\n\nconst DEPRECATED_BOOLEANS_SYNTAX = [\n 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON',\n 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF'\n]\n\nconst DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\\.[0-9_]*)?$/\n\nfunction compileStyleMap (schema, map) {\n if (map === null) return {}\n\n const result = {}\n const keys = Object.keys(map)\n\n for (let index = 0, length = keys.length; index < length; index += 1) {\n let tag = keys[index]\n let style = String(map[tag])\n\n if (tag.slice(0, 2) === '!!') {\n tag = 'tag:yaml.org,2002:' + tag.slice(2)\n }\n const type = schema.compiledTypeMap['fallback'][tag]\n\n if (type && _hasOwnProperty.call(type.styleAliases, style)) {\n style = type.styleAliases[style]\n }\n\n result[tag] = style\n }\n\n return result\n}\n\nfunction encodeHex (character) {\n let handle\n let length\n\n const string = character.toString(16).toUpperCase()\n\n if (character <= 0xFF) {\n handle = 'x'\n length = 2\n } else if (character <= 0xFFFF) {\n handle = 'u'\n length = 4\n } else if (character <= 0xFFFFFFFF) {\n handle = 'U'\n length = 8\n } else {\n throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF')\n }\n\n return '\\\\' + handle + common.repeat('0', length - string.length) + string\n}\n\nconst QUOTING_TYPE_SINGLE = 1\nconst QUOTING_TYPE_DOUBLE = 2\n\nfunction State (options) {\n this.schema = options['schema'] || DEFAULT_SCHEMA\n this.indent = Math.max(1, (options['indent'] || 2))\n this.noArrayIndent = options['noArrayIndent'] || false\n this.skipInvalid = options['skipInvalid'] || false\n this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel'])\n this.styleMap = compileStyleMap(this.schema, options['styles'] || null)\n this.sortKeys = options['sortKeys'] || false\n this.lineWidth = options['lineWidth'] || 80\n this.noRefs = options['noRefs'] || false\n this.noCompatMode = options['noCompatMode'] || false\n this.condenseFlow = options['condenseFlow'] || false\n this.quotingType = options['quotingType'] === '\"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE\n this.forceQuotes = options['forceQuotes'] || false\n this.replacer = typeof options['replacer'] === 'function' ? options['replacer'] : null\n\n this.implicitTypes = this.schema.compiledImplicit\n this.explicitTypes = this.schema.compiledExplicit\n\n this.tag = null\n this.result = ''\n\n this.duplicates = []\n this.usedDuplicates = null\n}\n\n// Indents every line in a string. Empty lines (\\n only) are not indented.\nfunction indentString (string, spaces) {\n const ind = common.repeat(' ', spaces)\n let position = 0\n let result = ''\n const length = string.length\n\n while (position < length) {\n let line\n const next = string.indexOf('\\n', position)\n if (next === -1) {\n line = string.slice(position)\n position = length\n } else {\n line = string.slice(position, next + 1)\n position = next + 1\n }\n\n if (line.length && line !== '\\n') result += ind\n\n result += line\n }\n\n return result\n}\n\nfunction generateNextLine (state, level) {\n return '\\n' + common.repeat(' ', state.indent * level)\n}\n\nfunction testImplicitResolving (state, str) {\n for (let index = 0, length = state.implicitTypes.length; index < length; index += 1) {\n const type = state.implicitTypes[index]\n\n if (type.resolve(str)) {\n return true\n }\n }\n\n return false\n}\n\n// [33] s-white ::= s-space | s-tab\nfunction isWhitespace (c) {\n return c === CHAR_SPACE || c === CHAR_TAB\n}\n\n// Returns true if the character can be printed without escaping.\n// From YAML 1.2: \"any allowed characters known to be non-printable\n// should also be escaped. [However,] This isn’t mandatory\"\n// Derived from nb-char - \\t - #x85 - #xA0 - #x2028 - #x2029.\nfunction isPrintable (c) {\n return (c >= 0x00020 && c <= 0x00007E) ||\n ((c >= 0x000A1 && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) ||\n ((c >= 0x0E000 && c <= 0x00FFFD) && c !== CHAR_BOM) ||\n (c >= 0x10000 && c <= 0x10FFFF)\n}\n\n// [34] ns-char ::= nb-char - s-white\n// [27] nb-char ::= c-printable - b-char - c-byte-order-mark\n// [26] b-char ::= b-line-feed | b-carriage-return\n// Including s-white (for some reason, examples doesn't match specs in this aspect)\n// ns-char ::= c-printable - b-line-feed - b-carriage-return - c-byte-order-mark\nfunction isNsCharOrWhitespace (c) {\n return isPrintable(c) &&\n c !== CHAR_BOM &&\n // - b-char\n c !== CHAR_CARRIAGE_RETURN &&\n c !== CHAR_LINE_FEED\n}\n\n// [127] ns-plain-safe(c) ::= c = flow-out ⇒ ns-plain-safe-out\n// c = flow-in ⇒ ns-plain-safe-in\n// c = block-key ⇒ ns-plain-safe-out\n// c = flow-key ⇒ ns-plain-safe-in\n// [128] ns-plain-safe-out ::= ns-char\n// [129] ns-plain-safe-in ::= ns-char - c-flow-indicator\n// [130] ns-plain-char(c) ::= ( ns-plain-safe(c) - “:” - “#” )\n// | ( /* An ns-char preceding */ “#” )\n// | ( “:” /* Followed by an ns-plain-safe(c) */ )\nfunction isPlainSafe (c, prev, inblock) {\n const cIsNsCharOrWhitespace = isNsCharOrWhitespace(c)\n const cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c)\n return (\n (\n // ns-plain-safe\n inblock // c = flow-in\n ? cIsNsCharOrWhitespace\n : cIsNsCharOrWhitespace &&\n // - c-flow-indicator\n c !== CHAR_COMMA &&\n c !== CHAR_LEFT_SQUARE_BRACKET &&\n c !== CHAR_RIGHT_SQUARE_BRACKET &&\n c !== CHAR_LEFT_CURLY_BRACKET &&\n c !== CHAR_RIGHT_CURLY_BRACKET\n ) &&\n // ns-plain-char\n c !== CHAR_SHARP && // false on '#'\n !(prev === CHAR_COLON && !cIsNsChar)\n ) || // false on ': '\n (isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP) || // change to true on '[^ ]#'\n (prev === CHAR_COLON && cIsNsChar) // change to true on ':[^ ]'\n}\n\n// Simplified test for values allowed as the first character in plain style.\nfunction isPlainSafeFirst (c) {\n // Uses a subset of ns-char - c-indicator\n // where ns-char = nb-char - s-white.\n // No support of ( ( “?” | “:” | “-” ) /* Followed by an ns-plain-safe(c)) */ ) part\n return isPrintable(c) &&\n c !== CHAR_BOM &&\n !isWhitespace(c) && // - s-white\n // - (c-indicator ::=\n // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}”\n c !== CHAR_MINUS &&\n c !== CHAR_QUESTION &&\n c !== CHAR_COLON &&\n c !== CHAR_COMMA &&\n c !== CHAR_LEFT_SQUARE_BRACKET &&\n c !== CHAR_RIGHT_SQUARE_BRACKET &&\n c !== CHAR_LEFT_CURLY_BRACKET &&\n c !== CHAR_RIGHT_CURLY_BRACKET &&\n // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “\"”\n c !== CHAR_SHARP &&\n c !== CHAR_AMPERSAND &&\n c !== CHAR_ASTERISK &&\n c !== CHAR_EXCLAMATION &&\n c !== CHAR_VERTICAL_LINE &&\n c !== CHAR_EQUALS &&\n c !== CHAR_GREATER_THAN &&\n c !== CHAR_SINGLE_QUOTE &&\n c !== CHAR_DOUBLE_QUOTE &&\n // | “%” | “@” | “`”)\n c !== CHAR_PERCENT &&\n c !== CHAR_COMMERCIAL_AT &&\n c !== CHAR_GRAVE_ACCENT\n}\n\n// Simplified test for values allowed as the last character in plain style.\nfunction isPlainSafeLast (c) {\n // just not whitespace or colon, it will be checked to be plain character later\n return !isWhitespace(c) && c !== CHAR_COLON\n}\n\n// Same as 'string'.codePointAt(pos), but works in older browsers.\nfunction codePointAt (string, pos) {\n const first = string.charCodeAt(pos)\n let second\n\n if (first >= 0xD800 && first <= 0xDBFF && pos + 1 < string.length) {\n second = string.charCodeAt(pos + 1)\n if (second >= 0xDC00 && second <= 0xDFFF) {\n // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000\n }\n }\n return first\n}\n\n// Determines whether block indentation indicator is required.\nfunction needIndentIndicator (string) {\n const leadingSpaceRe = /^\\n* /\n return leadingSpaceRe.test(string)\n}\n\nconst STYLE_PLAIN = 1\nconst STYLE_SINGLE = 2\nconst STYLE_LITERAL = 3\nconst STYLE_FOLDED = 4\nconst STYLE_DOUBLE = 5\n\n// Determines which scalar styles are possible and returns the preferred style.\n// lineWidth = -1 => no limit.\n// Pre-conditions: str.length > 0.\n// Post-conditions:\n// STYLE_PLAIN or STYLE_SINGLE => no \\n are in the string.\n// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1).\n// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1).\nfunction chooseScalarStyle (string, singleLineOnly, indentPerLevel, lineWidth,\n testAmbiguousType, quotingType, forceQuotes, inblock) {\n let i\n let char = 0\n let prevChar = null\n let hasLineBreak = false\n let hasFoldableLine = false // only checked if shouldTrackWidth\n const shouldTrackWidth = lineWidth !== -1\n let previousLineBreak = -1 // count the first line correctly\n let plain = isPlainSafeFirst(codePointAt(string, 0)) &&\n isPlainSafeLast(codePointAt(string, string.length - 1))\n\n if (singleLineOnly || forceQuotes) {\n // Case: no block styles.\n // Check for disallowed characters to rule out plain and single.\n for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) {\n char = codePointAt(string, i)\n if (!isPrintable(char)) {\n return STYLE_DOUBLE\n }\n plain = plain && isPlainSafe(char, prevChar, inblock)\n prevChar = char\n }\n } else {\n // Case: block styles permitted.\n for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) {\n char = codePointAt(string, i)\n if (char === CHAR_LINE_FEED) {\n hasLineBreak = true\n // Check if any line can be folded.\n if (shouldTrackWidth) {\n hasFoldableLine = hasFoldableLine ||\n // Foldable line = too long, and not more-indented.\n (i - previousLineBreak - 1 > lineWidth &&\n string[previousLineBreak + 1] !== ' ')\n previousLineBreak = i\n }\n } else if (!isPrintable(char)) {\n return STYLE_DOUBLE\n }\n plain = plain && isPlainSafe(char, prevChar, inblock)\n prevChar = char\n }\n // in case the end is missing a \\n\n hasFoldableLine = hasFoldableLine || (shouldTrackWidth &&\n (i - previousLineBreak - 1 > lineWidth &&\n string[previousLineBreak + 1] !== ' '))\n }\n // Although every style can represent \\n without escaping, prefer block styles\n // for multiline, since they're more readable and they don't add empty lines.\n // Also prefer folding a super-long line.\n if (!hasLineBreak && !hasFoldableLine) {\n // Strings interpretable as another type have to be quoted;\n // e.g. the string 'true' vs. the boolean true.\n if (plain && !forceQuotes && !testAmbiguousType(string)) {\n return STYLE_PLAIN\n }\n return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE\n }\n // Edge case: block indentation indicator can only have one digit.\n if (indentPerLevel > 9 && needIndentIndicator(string)) {\n return STYLE_DOUBLE\n }\n // At this point we know block styles are valid.\n // Prefer literal style unless we want to fold.\n if (!forceQuotes) {\n return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL\n }\n return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE\n}\n\n// Note: line breaking/folding is implemented for only the folded style.\n// NB. We drop the last trailing newline (if any) of a returned block scalar\n// since the dumper adds its own newline. This always works:\n// • No ending newline => unaffected; already using strip \"-\" chomping.\n// • Ending newline => removed then restored.\n// Importantly, this keeps the \"+\" chomp indicator from gaining an extra line.\nfunction writeScalar (state, string, level, iskey, inblock) {\n state.dump = (function () {\n if (string.length === 0) {\n return state.quotingType === QUOTING_TYPE_DOUBLE ? '\"\"' : \"''\"\n }\n if (!state.noCompatMode) {\n if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) {\n return state.quotingType === QUOTING_TYPE_DOUBLE ? ('\"' + string + '\"') : (\"'\" + string + \"'\")\n }\n }\n\n const indent = state.indent * Math.max(1, level) // no 0-indent scalars\n // As indentation gets deeper, let the width decrease monotonically\n // to the lower bound min(state.lineWidth, 40).\n // Note that this implies\n // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound.\n // state.lineWidth > 40 + state.indent: width decreases until the lower bound.\n // This behaves better than a constant minimum width which disallows narrower options,\n // or an indent threshold which causes the width to suddenly increase.\n const lineWidth = (state.lineWidth === -1)\n ? -1\n : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent)\n\n // Without knowing if keys are implicit/explicit, assume implicit for safety.\n const singleLineOnly = iskey ||\n // No block styles in flow mode.\n (state.flowLevel > -1 && level >= state.flowLevel)\n function testAmbiguity (string) {\n return testImplicitResolving(state, string)\n }\n\n switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth,\n testAmbiguity, state.quotingType, state.forceQuotes && !iskey, inblock)) {\n case STYLE_PLAIN:\n return string\n case STYLE_SINGLE:\n return \"'\" + string.replace(/'/g, \"''\") + \"'\"\n case STYLE_LITERAL:\n return '|' + blockHeader(string, state.indent) +\n dropEndingNewline(indentString(string, indent))\n case STYLE_FOLDED:\n return '>' + blockHeader(string, state.indent) +\n dropEndingNewline(indentString(foldString(string, lineWidth), indent))\n case STYLE_DOUBLE:\n return '\"' + escapeString(string, lineWidth) + '\"'\n default:\n throw new YAMLException('impossible error: invalid scalar style')\n }\n }())\n}\n\n// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9.\nfunction blockHeader (string, indentPerLevel) {\n const indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''\n\n // note the special case: the string '\\n' counts as a \"trailing\" empty line.\n const clip = string[string.length - 1] === '\\n'\n const keep = clip && (string[string.length - 2] === '\\n' || string === '\\n')\n const chomp = keep ? '+' : (clip ? '' : '-')\n\n return indentIndicator + chomp + '\\n'\n}\n\n// (See the note for writeScalar.)\nfunction dropEndingNewline (string) {\n return string[string.length - 1] === '\\n' ? string.slice(0, -1) : string\n}\n\n// Note: a long line without a suitable break point will exceed the width limit.\n// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0.\nfunction foldString (string, width) {\n // In folded style, $k$ consecutive newlines output as $k+1$ newlines—\n // unless they're before or after a more-indented line, or at the very\n // beginning or end, in which case $k$ maps to $k$.\n // Therefore, parse each chunk as newline(s) followed by a content line.\n const lineRe = /(\\n+)([^\\n]*)/g\n\n // first line (possibly an empty line)\n let result = (function () {\n let nextLF = string.indexOf('\\n')\n nextLF = nextLF !== -1 ? nextLF : string.length\n lineRe.lastIndex = nextLF\n return foldLine(string.slice(0, nextLF), width)\n }())\n // If we haven't reached the first content line yet, don't add an extra \\n.\n let prevMoreIndented = string[0] === '\\n' || string[0] === ' '\n let moreIndented\n\n // rest of the lines\n let match\n while ((match = lineRe.exec(string))) {\n const prefix = match[1]\n const line = match[2]\n\n moreIndented = (line[0] === ' ')\n result += prefix +\n ((!prevMoreIndented && !moreIndented && line !== '') ? '\\n' : '') +\n foldLine(line, width)\n prevMoreIndented = moreIndented\n }\n\n return result\n}\n\n// Greedy line breaking.\n// Picks the longest line under the limit each time,\n// otherwise settles for the shortest line over the limit.\n// NB. More-indented lines *cannot* be folded, as that would add an extra \\n.\nfunction foldLine (line, width) {\n if (line === '' || line[0] === ' ') return line\n\n // Since a more-indented line adds a \\n, breaks can't be followed by a space.\n const breakRe = / [^ ]/g // note: the match index will always be <= length-2.\n let match\n // start is an inclusive index. end, curr, and next are exclusive.\n let start = 0\n let end\n let curr = 0\n let next = 0\n let result = ''\n\n // Invariants: 0 <= start <= length-1.\n // 0 <= curr <= next <= max(0, length-2). curr - start <= width.\n // Inside the loop:\n // A match implies length >= 2, so curr and next are <= length-2.\n while ((match = breakRe.exec(line))) {\n next = match.index\n // maintain invariant: curr - start <= width\n if (next - start > width) {\n end = (curr > start) ? curr : next // derive end <= length-2\n result += '\\n' + line.slice(start, end)\n // skip the space that was output as \\n\n start = end + 1 // derive start <= length-1\n }\n curr = next\n }\n\n // By the invariants, start <= length-1, so there is something left over.\n // It is either the whole string or a part starting from non-whitespace.\n result += '\\n'\n // Insert a break if the remainder is too long and there is a break available.\n if (line.length - start > width && curr > start) {\n result += line.slice(start, curr) + '\\n' + line.slice(curr + 1)\n } else {\n result += line.slice(start)\n }\n\n return result.slice(1) // drop extra \\n joiner\n}\n\n// Escapes a double-quoted string.\nfunction escapeString (string) {\n let result = ''\n let char = 0\n\n for (let i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) {\n char = codePointAt(string, i)\n const escapeSeq = ESCAPE_SEQUENCES[char]\n\n if (!escapeSeq && isPrintable(char)) {\n result += string[i]\n if (char >= 0x10000) result += string[i + 1]\n } else {\n result += escapeSeq || encodeHex(char)\n }\n }\n\n return result\n}\n\nfunction writeFlowSequence (state, level, object) {\n let _result = ''\n const _tag = state.tag\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n let value = object[index]\n\n if (state.replacer) {\n value = state.replacer.call(object, String(index), value)\n }\n\n // Write only valid elements, put null instead of invalid elements.\n if (writeNode(state, level, value, false, false) ||\n (typeof value === 'undefined' &&\n writeNode(state, level, null, false, false))) {\n if (_result !== '') _result += ',' + (!state.condenseFlow ? ' ' : '')\n _result += state.dump\n }\n }\n\n state.tag = _tag\n state.dump = '[' + _result + ']'\n}\n\nfunction writeBlockSequence (state, level, object, compact) {\n let _result = ''\n const _tag = state.tag\n\n for (let index = 0, length = object.length; index < length; index += 1) {\n let value = object[index]\n\n if (state.replacer) {\n value = state.replacer.call(object, String(index), value)\n }\n\n // Write only valid elements, put null instead of invalid elements.\n if (writeNode(state, level + 1, value, true, true, false, true) ||\n (typeof value === 'undefined' &&\n writeNode(state, level + 1, null, true, true, false, true))) {\n if (!compact || _result !== '') {\n _result += generateNextLine(state, level)\n }\n\n if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {\n _result += '-'\n } else {\n _result += '- '\n }\n\n _result += state.dump\n }\n }\n\n state.tag = _tag\n state.dump = _result || '[]' // Empty sequence if no valid values.\n}\n\nfunction writeFlowMapping (state, level, object) {\n let _result = ''\n const _tag = state.tag\n const objectKeyList = Object.keys(object)\n\n for (let index = 0, length = objectKeyList.length; index < length; index += 1) {\n let pairBuffer = ''\n if (_result !== '') pairBuffer += ', '\n\n if (state.condenseFlow) pairBuffer += '\"'\n\n const objectKey = objectKeyList[index]\n let objectValue = object[objectKey]\n\n if (state.replacer) {\n objectValue = state.replacer.call(object, objectKey, objectValue)\n }\n\n if (!writeNode(state, level, objectKey, false, false)) {\n continue // Skip this pair because of invalid key;\n }\n\n if (state.dump.length > 1024) pairBuffer += '? '\n\n pairBuffer += state.dump + (state.condenseFlow ? '\"' : '') + ':' + (state.condenseFlow ? '' : ' ')\n\n if (!writeNode(state, level, objectValue, false, false)) {\n continue // Skip this pair because of invalid value.\n }\n\n pairBuffer += state.dump\n\n // Both key and value are valid.\n _result += pairBuffer\n }\n\n state.tag = _tag\n state.dump = '{' + _result + '}'\n}\n\nfunction writeBlockMapping (state, level, object, compact) {\n let _result = ''\n const _tag = state.tag\n const objectKeyList = Object.keys(object)\n\n // Allow sorting keys so that the output file is deterministic\n if (state.sortKeys === true) {\n // Default sorting\n objectKeyList.sort()\n } else if (typeof state.sortKeys === 'function') {\n // Custom sort function\n objectKeyList.sort(state.sortKeys)\n } else if (state.sortKeys) {\n // Something is wrong\n throw new YAMLException('sortKeys must be a boolean or a function')\n }\n\n for (let index = 0, length = objectKeyList.length; index < length; index += 1) {\n let pairBuffer = ''\n\n if (!compact || _result !== '') {\n pairBuffer += generateNextLine(state, level)\n }\n\n const objectKey = objectKeyList[index]\n let objectValue = object[objectKey]\n\n if (state.replacer) {\n objectValue = state.replacer.call(object, objectKey, objectValue)\n }\n\n if (!writeNode(state, level + 1, objectKey, true, true, true)) {\n continue // Skip this pair because of invalid key.\n }\n\n const explicitPair = (state.tag !== null && state.tag !== '?') ||\n (state.dump && state.dump.length > 1024)\n\n if (explicitPair) {\n if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {\n pairBuffer += '?'\n } else {\n pairBuffer += '? '\n }\n }\n\n pairBuffer += state.dump\n\n if (explicitPair) {\n pairBuffer += generateNextLine(state, level)\n }\n\n if (!writeNode(state, level + 1, objectValue, true, explicitPair)) {\n continue // Skip this pair because of invalid value.\n }\n\n if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {\n pairBuffer += ':'\n } else {\n pairBuffer += ': '\n }\n\n pairBuffer += state.dump\n\n // Both key and value are valid.\n _result += pairBuffer\n }\n\n state.tag = _tag\n state.dump = _result || '{}' // Empty mapping if no valid pairs.\n}\n\nfunction detectType (state, object, explicit) {\n const typeList = explicit ? state.explicitTypes : state.implicitTypes\n\n for (let index = 0, length = typeList.length; index < length; index += 1) {\n const type = typeList[index]\n\n if ((type.instanceOf || type.predicate) &&\n (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) &&\n (!type.predicate || type.predicate(object))) {\n if (explicit) {\n if (type.multi && type.representName) {\n state.tag = type.representName(object)\n } else {\n state.tag = type.tag\n }\n } else {\n state.tag = '?'\n }\n\n if (type.represent) {\n const style = state.styleMap[type.tag] || type.defaultStyle\n\n let _result\n if (_toString.call(type.represent) === '[object Function]') {\n _result = type.represent(object, style)\n } else if (_hasOwnProperty.call(type.represent, style)) {\n _result = type.represent[style](object, style)\n } else {\n throw new YAMLException('!<' + type.tag + '> tag resolver accepts not \"' + style + '\" style')\n }\n\n state.dump = _result\n }\n\n return true\n }\n }\n\n return false\n}\n\n// Serializes `object` and writes it to global `result`.\n// Returns true on success, or false on invalid object.\n//\nfunction writeNode (state, level, object, block, compact, iskey, isblockseq) {\n state.tag = null\n state.dump = object\n\n if (!detectType(state, object, false)) {\n detectType(state, object, true)\n }\n\n const type = _toString.call(state.dump)\n const inblock = block\n\n if (block) {\n block = (state.flowLevel < 0 || state.flowLevel > level)\n }\n\n const objectOrArray = type === '[object Object]' || type === '[object Array]'\n let duplicateIndex\n let duplicate\n\n if (objectOrArray) {\n duplicateIndex = state.duplicates.indexOf(object)\n duplicate = duplicateIndex !== -1\n }\n\n if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) {\n compact = false\n }\n\n if (duplicate && state.usedDuplicates[duplicateIndex]) {\n state.dump = '*ref_' + duplicateIndex\n } else {\n if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) {\n state.usedDuplicates[duplicateIndex] = true\n }\n if (type === '[object Object]') {\n if (block && (Object.keys(state.dump).length !== 0)) {\n writeBlockMapping(state, level, state.dump, compact)\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + state.dump\n }\n } else {\n writeFlowMapping(state, level, state.dump)\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + ' ' + state.dump\n }\n }\n } else if (type === '[object Array]') {\n if (block && (state.dump.length !== 0)) {\n if (state.noArrayIndent && !isblockseq && level > 0) {\n writeBlockSequence(state, level - 1, state.dump, compact)\n } else {\n writeBlockSequence(state, level, state.dump, compact)\n }\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + state.dump\n }\n } else {\n writeFlowSequence(state, level, state.dump)\n if (duplicate) {\n state.dump = '&ref_' + duplicateIndex + ' ' + state.dump\n }\n }\n } else if (type === '[object String]') {\n if (state.tag !== '?') {\n writeScalar(state, state.dump, level, iskey, inblock)\n }\n } else if (type === '[object Undefined]') {\n return false\n } else {\n if (state.skipInvalid) return false\n throw new YAMLException('unacceptable kind of an object to dump ' + type)\n }\n\n if (state.tag !== null && state.tag !== '?') {\n // Need to encode all characters except those allowed by the spec:\n //\n // [35] ns-dec-digit ::= [#x30-#x39] /* 0-9 */\n // [36] ns-hex-digit ::= ns-dec-digit\n // | [#x41-#x46] /* A-F */ | [#x61-#x66] /* a-f */\n // [37] ns-ascii-letter ::= [#x41-#x5A] /* A-Z */ | [#x61-#x7A] /* a-z */\n // [38] ns-word-char ::= ns-dec-digit | ns-ascii-letter | “-”\n // [39] ns-uri-char ::= “%” ns-hex-digit ns-hex-digit | ns-word-char | “#”\n // | “;” | “/” | “?” | “:” | “@” | “&” | “=” | “+” | “$” | “,”\n // | “_” | “.” | “!” | “~” | “*” | “'” | “(” | “)” | “[” | “]”\n //\n // Also need to encode '!' because it has special meaning (end of tag prefix).\n //\n let tagStr = encodeURI(\n state.tag[0] === '!' ? state.tag.slice(1) : state.tag\n ).replace(/!/g, '%21')\n\n if (state.tag[0] === '!') {\n tagStr = '!' + tagStr\n } else if (tagStr.slice(0, 18) === 'tag:yaml.org,2002:') {\n tagStr = '!!' + tagStr.slice(18)\n } else {\n tagStr = '!<' + tagStr + '>'\n }\n\n state.dump = tagStr + ' ' + state.dump\n }\n }\n\n return true\n}\n\nfunction getDuplicateReferences (object, state) {\n const objects = []\n const duplicatesIndexes = []\n\n inspectNode(object, objects, duplicatesIndexes)\n\n const length = duplicatesIndexes.length\n for (let index = 0; index < length; index += 1) {\n state.duplicates.push(objects[duplicatesIndexes[index]])\n }\n state.usedDuplicates = new Array(length)\n}\n\nfunction inspectNode (object, objects, duplicatesIndexes) {\n if (object !== null && typeof object === 'object') {\n const index = objects.indexOf(object)\n if (index !== -1) {\n if (duplicatesIndexes.indexOf(index) === -1) {\n duplicatesIndexes.push(index)\n }\n } else {\n objects.push(object)\n\n if (Array.isArray(object)) {\n for (let i = 0, length = object.length; i < length; i += 1) {\n inspectNode(object[i], objects, duplicatesIndexes)\n }\n } else {\n const objectKeyList = Object.keys(object)\n\n for (let i = 0, length = objectKeyList.length; i < length; i += 1) {\n inspectNode(object[objectKeyList[i]], objects, duplicatesIndexes)\n }\n }\n }\n }\n}\n\nfunction dump (input, options) {\n options = options || {}\n\n const state = new State(options)\n\n if (!state.noRefs) getDuplicateReferences(input, state)\n\n let value = input\n\n if (state.replacer) {\n value = state.replacer.call({ '': value }, '', value)\n }\n\n if (writeNode(state, 0, value, true, true)) return state.dump + '\\n'\n\n return ''\n}\n\nmodule.exports.dump = dump\n","'use strict'\n\nconst loader = require('./lib/loader')\nconst dumper = require('./lib/dumper')\n\nfunction renamed (from, to) {\n return function () {\n throw new Error('Function yaml.' + from + ' is removed in js-yaml 4. ' +\n 'Use yaml.' + to + ' instead, which is now safe by default.')\n }\n}\n\nmodule.exports.Type = require('./lib/type')\nmodule.exports.Schema = require('./lib/schema')\nmodule.exports.FAILSAFE_SCHEMA = require('./lib/schema/failsafe')\nmodule.exports.JSON_SCHEMA = require('./lib/schema/json')\nmodule.exports.CORE_SCHEMA = require('./lib/schema/core')\nmodule.exports.DEFAULT_SCHEMA = require('./lib/schema/default')\nmodule.exports.load = loader.load\nmodule.exports.loadAll = loader.loadAll\nmodule.exports.dump = dumper.dump\nmodule.exports.YAMLException = require('./lib/exception')\n\n// Re-export all types in case user wants to create custom schema\nmodule.exports.types = {\n binary: require('./lib/type/binary'),\n float: require('./lib/type/float'),\n map: require('./lib/type/map'),\n null: require('./lib/type/null'),\n pairs: require('./lib/type/pairs'),\n set: require('./lib/type/set'),\n timestamp: require('./lib/type/timestamp'),\n bool: require('./lib/type/bool'),\n int: require('./lib/type/int'),\n merge: require('./lib/type/merge'),\n omap: require('./lib/type/omap'),\n seq: require('./lib/type/seq'),\n str: require('./lib/type/str')\n}\n\n// Removed functions from JS-YAML 3.0.x\nmodule.exports.safeLoad = renamed('safeLoad', 'load')\nmodule.exports.safeLoadAll = renamed('safeLoadAll', 'loadAll')\nmodule.exports.safeDump = renamed('safeDump', 'dump')\n","import yaml from '../index.js'\n\nconst {\n Type,\n Schema,\n FAILSAFE_SCHEMA,\n JSON_SCHEMA,\n CORE_SCHEMA,\n DEFAULT_SCHEMA,\n load,\n loadAll,\n dump,\n YAMLException,\n types,\n safeLoad,\n safeLoadAll,\n safeDump\n} = yaml\n\nexport {\n Type,\n Schema,\n FAILSAFE_SCHEMA,\n JSON_SCHEMA,\n CORE_SCHEMA,\n DEFAULT_SCHEMA,\n load,\n loadAll,\n dump,\n YAMLException,\n types,\n safeLoad,\n safeLoadAll,\n safeDump\n}\n\nexport default yaml\n"],"names":["exception","YAMLException","common","require$$0","line","map","Type","require$$1","schema","type","Schema","require$$2","require$$3","require$$4","require$$5","require$$6","DEFAULT_SCHEMA","loadAll","load","str","string","dump","loader","dumper","require$$7","require$$8","require$$9","require$$10","require$$11","require$$12","require$$13","require$$14","require$$15","require$$16","require$$17","require$$18","require$$19","require$$20","require$$21"],"mappings":";;;;;;;;;;AAEA,WAAS,UAAW,SAAS;AAC3B,WAAQ,OAAO,YAAY,eAAiB,YAAY;AAAA,EAC1D;AAEA,WAAS,SAAU,SAAS;AAC1B,WAAQ,OAAO,YAAY,YAAc,YAAY;AAAA,EACvD;AAEA,WAAS,QAAS,UAAU;AAC1B,QAAI,MAAM,QAAQ,QAAQ,EAAG,QAAO;AAAA,aAC3B,UAAU,QAAQ,EAAG,QAAO,CAAA;AAErC,WAAO,CAAC,QAAQ;AAAA,EAClB;AAEA,WAAS,OAAQ,QAAQ,QAAQ;AAC/B,QAAI,QAAQ;AACV,YAAM,aAAa,OAAO,KAAK,MAAM;AAErC,eAAS,QAAQ,GAAG,SAAS,WAAW,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AAC1E,cAAM,MAAM,WAAW,KAAK;AAC5B,eAAO,GAAG,IAAI,OAAO,GAAG;AAAA,MAC9B;AAAA,IACA;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,OAAQ,QAAQ,OAAO;AAC9B,QAAI,SAAS;AAEb,aAAS,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;AAC7C,gBAAU;AAAA,IACd;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,eAAgB,QAAQ;AAC/B,WAAQ,WAAW,KAAO,OAAO,sBAAsB,IAAI;AAAA,EAC7D;AAEA,SAAA,YAA2B;AAC3B,SAAA,WAA0B;AAC1B,SAAA,UAAyB;AACzB,SAAA,SAAwB;AACxB,SAAA,iBAAgC;AAChC,SAAA,SAAwB;;;;;;;;AC7CxB,WAAS,YAAaA,YAAW,SAAS;AACxC,QAAI,QAAQ;AACZ,UAAM,UAAUA,WAAU,UAAU;AAEpC,QAAI,CAACA,WAAU,KAAM,QAAO;AAE5B,QAAIA,WAAU,KAAK,MAAM;AACvB,eAAS,SAASA,WAAU,KAAK,OAAO;AAAA,IAC5C;AAEE,aAAS,OAAOA,WAAU,KAAK,OAAO,KAAK,OAAOA,WAAU,KAAK,SAAS,KAAK;AAE/E,QAAI,CAAC,WAAWA,WAAU,KAAK,SAAS;AACtC,eAAS,SAASA,WAAU,KAAK;AAAA,IACrC;AAEE,WAAO,UAAU,MAAM;AAAA,EACzB;AAEA,WAASC,eAAe,QAAQ,MAAM;AAEpC,UAAM,KAAK,IAAI;AAEf,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,UAAU,YAAY,MAAM,KAAK;AAGtC,QAAI,MAAM,mBAAmB;AAE3B,YAAM,kBAAkB,MAAM,KAAK,WAAW;AAAA,IAClD,OAAS;AAEL,WAAK,QAAS,IAAI,MAAK,EAAI,SAAS;AAAA,IACxC;AAAA,EACA;AAGA,EAAAA,eAAc,YAAY,OAAO,OAAO,MAAM,SAAS;AACvD,EAAAA,eAAc,UAAU,cAAcA;AAEtC,EAAAA,eAAc,UAAU,WAAW,SAAS,SAAU,SAAS;AAC7D,WAAO,KAAK,OAAO,OAAO,YAAY,MAAM,OAAO;AAAA,EACrD;AAEA,cAAiBA;;;;;;;;AChDjB,QAAMC,UAASC,cAAA;AAGf,WAAS,QAAS,QAAQ,WAAW,SAAS,UAAU,eAAe;AACrE,QAAI,OAAO;AACX,QAAI,OAAO;AACX,UAAM,gBAAgB,KAAK,MAAM,gBAAgB,CAAC,IAAI;AAEtD,QAAI,WAAW,YAAY,eAAe;AACxC,aAAO;AACP,kBAAY,WAAW,gBAAgB,KAAK;AAAA,IAChD;AAEE,QAAI,UAAU,WAAW,eAAe;AACtC,aAAO;AACP,gBAAU,WAAW,gBAAgB,KAAK;AAAA,IAC9C;AAEE,WAAO;AAAA,MACL,KAAK,OAAO,OAAO,MAAM,WAAW,OAAO,EAAE,QAAQ,OAAO,GAAG,IAAI;AAAA,MACnE,KAAK,WAAW,YAAY,KAAK;AAAA;AAAA,IACrC;AAAA,EACA;AAEA,WAAS,SAAU,QAAQ,KAAK;AAC9B,WAAOD,QAAO,OAAO,KAAK,MAAM,OAAO,MAAM,IAAI;AAAA,EACnD;AAEA,WAAS,YAAa,MAAM,SAAS;AACnC,cAAU,OAAO,OAAO,WAAW,IAAI;AAEvC,QAAI,CAAC,KAAK,OAAQ,QAAO;AAEzB,QAAI,CAAC,QAAQ,UAAW,SAAQ,YAAY;AAC5C,QAAI,OAAO,QAAQ,WAAW,SAAU,SAAQ,SAAS;AACzD,QAAI,OAAO,QAAQ,gBAAgB,SAAU,SAAQ,cAAc;AACnE,QAAI,OAAO,QAAQ,eAAe,SAAU,SAAQ,aAAa;AAEjE,UAAM,KAAK;AACX,UAAM,aAAa,CAAC,CAAC;AACrB,UAAM,WAAW,CAAA;AACjB,QAAI;AACJ,QAAI,cAAc;AAElB,WAAQ,QAAQ,GAAG,KAAK,KAAK,MAAM,GAAI;AACrC,eAAS,KAAK,MAAM,KAAK;AACzB,iBAAW,KAAK,MAAM,QAAQ,MAAM,CAAC,EAAE,MAAM;AAE7C,UAAI,KAAK,YAAY,MAAM,SAAS,cAAc,GAAG;AACnD,sBAAc,WAAW,SAAS;AAAA,MACxC;AAAA,IACA;AAEE,QAAI,cAAc,EAAG,eAAc,WAAW,SAAS;AAEvD,QAAI,SAAS;AACb,UAAM,eAAe,KAAK,IAAI,KAAK,OAAO,QAAQ,YAAY,SAAS,MAAM,EAAE,SAAQ,EAAG;AAC1F,UAAM,gBAAgB,QAAQ,aAAa,QAAQ,SAAS,eAAe;AAE3E,aAAS,IAAI,GAAG,KAAK,QAAQ,aAAa,KAAK;AAC7C,UAAI,cAAc,IAAI,EAAG;AACzB,YAAME,QAAO;AAAA,QACX,KAAK;AAAA,QACL,WAAW,cAAc,CAAC;AAAA,QAC1B,SAAS,cAAc,CAAC;AAAA,QACxB,KAAK,YAAY,WAAW,WAAW,IAAI,WAAW,cAAc,CAAC;AAAA,QACrE;AAAA,MACN;AACI,eAASF,QAAO,OAAO,KAAK,QAAQ,MAAM,IAAI,UAAU,KAAK,OAAO,IAAI,GAAG,SAAQ,GAAI,YAAY,IACjG,QAAQE,MAAK,MAAM,OAAO;AAAA,IAChC;AAEE,UAAM,OAAO,QAAQ,KAAK,QAAQ,WAAW,WAAW,GAAG,SAAS,WAAW,GAAG,KAAK,UAAU,aAAa;AAC9G,cAAUF,QAAO,OAAO,KAAK,QAAQ,MAAM,IAAI,UAAU,KAAK,OAAO,GAAG,SAAQ,GAAI,YAAY,IAC9F,QAAQ,KAAK,MAAM;AACrB,cAAUA,QAAO,OAAO,KAAK,QAAQ,SAAS,eAAe,IAAI,KAAK,GAAG,IAAI;AAE7E,aAAS,IAAI,GAAG,KAAK,QAAQ,YAAY,KAAK;AAC5C,UAAI,cAAc,KAAK,SAAS,OAAQ;AACxC,YAAME,QAAO;AAAA,QACX,KAAK;AAAA,QACL,WAAW,cAAc,CAAC;AAAA,QAC1B,SAAS,cAAc,CAAC;AAAA,QACxB,KAAK,YAAY,WAAW,WAAW,IAAI,WAAW,cAAc,CAAC;AAAA,QACrE;AAAA,MACN;AACI,gBAAUF,QAAO,OAAO,KAAK,QAAQ,MAAM,IAAI,UAAU,KAAK,OAAO,IAAI,GAAG,SAAQ,GAAI,YAAY,IAClG,QAAQE,MAAK,MAAM;AAAA,IACzB;AAEE,WAAO,OAAO,QAAQ,OAAO,EAAE;AAAA,EACjC;AAEA,YAAiB;;;;;;;;AC7FjB,QAAMH,iBAAgBE,iBAAA;AAEtB,QAAM,2BAA2B;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,kBAAkB;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,WAAS,oBAAqBE,MAAK;AACjC,UAAM,SAAS,CAAA;AAEf,QAAIA,SAAQ,MAAM;AAChB,aAAO,KAAKA,IAAG,EAAE,QAAQ,SAAU,OAAO;AACxC,QAAAA,KAAI,KAAK,EAAE,QAAQ,SAAU,OAAO;AAClC,iBAAO,OAAO,KAAK,CAAC,IAAI;AAAA,QAChC,CAAO;AAAA,MACP,CAAK;AAAA,IACL;AAEE,WAAO;AAAA,EACT;AAEA,WAASC,MAAM,KAAK,SAAS;AAC3B,cAAU,WAAW,CAAA;AAErB,WAAO,KAAK,OAAO,EAAE,QAAQ,SAAU,MAAM;AAC3C,UAAI,yBAAyB,QAAQ,IAAI,MAAM,IAAI;AACjD,cAAM,IAAIL,eAAc,qBAAqB,OAAO,gCAAgC,MAAM,cAAc;AAAA,MAC9G;AAAA,IACA,CAAG;AAGD,SAAK,UAAU;AACf,SAAK,MAAM;AACX,SAAK,OAAO,QAAQ,MAAM,KAAK;AAC/B,SAAK,UAAU,QAAQ,SAAS,KAAK,WAAY;AAAE,aAAO;AAAA,IAAI;AAC9D,SAAK,YAAY,QAAQ,WAAW,KAAK,SAAU,MAAM;AAAE,aAAO;AAAA,IAAI;AACtE,SAAK,aAAa,QAAQ,YAAY,KAAK;AAC3C,SAAK,YAAY,QAAQ,WAAW,KAAK;AACzC,SAAK,YAAY,QAAQ,WAAW,KAAK;AACzC,SAAK,gBAAgB,QAAQ,eAAe,KAAK;AACjD,SAAK,eAAe,QAAQ,cAAc,KAAK;AAC/C,SAAK,QAAQ,QAAQ,OAAO,KAAK;AACjC,SAAK,eAAe,oBAAoB,QAAQ,cAAc,KAAK,IAAI;AAEvE,QAAI,gBAAgB,QAAQ,KAAK,IAAI,MAAM,IAAI;AAC7C,YAAM,IAAIA,eAAc,mBAAmB,KAAK,OAAO,yBAAyB,MAAM,cAAc;AAAA,IACxG;AAAA,EACA;AAEA,SAAiBK;;;;;;;;AC/DjB,QAAML,iBAAgBE,iBAAA;AACtB,QAAMG,QAAOC,YAAA;AAEb,WAAS,YAAaC,SAAQ,MAAM;AAClC,UAAM,SAAS,CAAA;AAEf,IAAAA,QAAO,IAAI,EAAE,QAAQ,SAAU,aAAa;AAC1C,UAAI,WAAW,OAAO;AAEtB,aAAO,QAAQ,SAAU,cAAc,eAAe;AACpD,YAAI,aAAa,QAAQ,YAAY,OACjC,aAAa,SAAS,YAAY,QAClC,aAAa,UAAU,YAAY,OAAO;AAC5C,qBAAW;AAAA,QACnB;AAAA,MACA,CAAK;AAED,aAAO,QAAQ,IAAI;AAAA,IACvB,CAAG;AAED,WAAO;AAAA,EACT;AAEA,WAAS,aAA4B;AACnC,UAAM,SAAS;AAAA,MACb,QAAQ,CAAA;AAAA,MACR,UAAU,CAAA;AAAA,MACV,SAAS,CAAA;AAAA,MACT,UAAU,CAAA;AAAA,MACV,OAAO;AAAA,QACL,QAAQ,CAAA;AAAA,QACR,UAAU,CAAA;AAAA,QACV,SAAS,CAAA;AAAA,QACT,UAAU,CAAA;AAAA,MAChB;AAAA,IACA;AACE,aAAS,YAAaC,OAAM;AAC1B,UAAIA,MAAK,OAAO;AACd,eAAO,MAAMA,MAAK,IAAI,EAAE,KAAKA,KAAI;AACjC,eAAO,MAAM,UAAU,EAAE,KAAKA,KAAI;AAAA,MACxC,OAAW;AACL,eAAOA,MAAK,IAAI,EAAEA,MAAK,GAAG,IAAI,OAAO,UAAU,EAAEA,MAAK,GAAG,IAAIA;AAAA,MACnE;AAAA,IACA;AAEE,aAAS,QAAQ,GAAG,SAAS,UAAU,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACzE,gBAAU,KAAK,EAAE,QAAQ,WAAW;AAAA,IACxC;AACE,WAAO;AAAA,EACT;AAEA,WAASC,QAAQ,YAAY;AAC3B,WAAO,KAAK,OAAO,UAAU;AAAA,EAC/B;AAEA,EAAAA,QAAO,UAAU,SAAS,SAAS,OAAQ,YAAY;AACrD,QAAI,WAAW,CAAA;AACf,QAAI,WAAW,CAAA;AAEf,QAAI,sBAAsBJ,OAAM;AAE9B,eAAS,KAAK,UAAU;AAAA,IAC5B,WAAa,MAAM,QAAQ,UAAU,GAAG;AAEpC,iBAAW,SAAS,OAAO,UAAU;AAAA,IACzC,WAAa,eAAe,MAAM,QAAQ,WAAW,QAAQ,KAAK,MAAM,QAAQ,WAAW,QAAQ,IAAI;AAEnG,UAAI,WAAW,SAAU,YAAW,SAAS,OAAO,WAAW,QAAQ;AACvE,UAAI,WAAW,SAAU,YAAW,SAAS,OAAO,WAAW,QAAQ;AAAA,IAC3E,OAAS;AACL,YAAM,IAAIL,eAAc,kHACyC;AAAA,IACrE;AAEE,aAAS,QAAQ,SAAUQ,OAAM;AAC/B,UAAI,EAAEA,iBAAgBH,QAAO;AAC3B,cAAM,IAAIL,eAAc,oFAAoF;AAAA,MAClH;AAEI,UAAIQ,MAAK,YAAYA,MAAK,aAAa,UAAU;AAC/C,cAAM,IAAIR,eAAc,iHAAiH;AAAA,MAC/I;AAEI,UAAIQ,MAAK,OAAO;AACd,cAAM,IAAIR,eAAc,oGAAoG;AAAA,MAClI;AAAA,IACA,CAAG;AAED,aAAS,QAAQ,SAAUQ,OAAM;AAC/B,UAAI,EAAEA,iBAAgBH,QAAO;AAC3B,cAAM,IAAIL,eAAc,oFAAoF;AAAA,MAClH;AAAA,IACA,CAAG;AAED,UAAM,SAAS,OAAO,OAAOS,QAAO,SAAS;AAE7C,WAAO,YAAY,KAAK,YAAY,CAAA,GAAI,OAAO,QAAQ;AACvD,WAAO,YAAY,KAAK,YAAY,CAAA,GAAI,OAAO,QAAQ;AAEvD,WAAO,mBAAmB,YAAY,QAAQ,UAAU;AACxD,WAAO,mBAAmB,YAAY,QAAQ,UAAU;AACxD,WAAO,kBAAkB,WAAW,OAAO,kBAAkB,OAAO,gBAAgB;AAEpF,WAAO;AAAA,EACT;AAEA,WAAiBA;;;;;;;;AC1GjB,QAAMJ,QAAOH,YAAA;AAEb,QAAiB,IAAIG,MAAK,yBAAyB;AAAA,IACjD,MAAM;AAAA,IACN,WAAW,SAAU,MAAM;AAAE,aAAO,SAAS,OAAO,OAAO;AAAA,IAAE;AAAA,GAC9D;;;;;;;;ACLD,QAAMA,QAAOH,YAAA;AAEb,QAAiB,IAAIG,MAAK,yBAAyB;AAAA,IACjD,MAAM;AAAA,IACN,WAAW,SAAU,MAAM;AAAE,aAAO,SAAS,OAAO,OAAO;IAAE;AAAA,GAC9D;;;;;;;;ACLD,QAAMA,QAAOH,YAAA;AAEb,QAAiB,IAAIG,MAAK,yBAAyB;AAAA,IACjD,MAAM;AAAA,IACN,WAAW,SAAU,MAAM;AAAE,aAAO,SAAS,OAAO,OAAO;IAAE;AAAA,GAC9D;;;;;;;;ACFD,QAAMI,UAASP,cAAA;AAEf,aAAiB,IAAIO,QAAO;AAAA,IAC1B,UAAU;AAAA,MACRH,WAAA;AAAA,MACAI,WAAA;AAAA,MACAC,WAAA;AAAA,IACJ;AAAA,GACC;;;;;;;;ACXD,QAAMN,QAAOH,YAAA;AAEb,WAAS,gBAAiB,MAAM;AAC9B,QAAI,SAAS,KAAM,QAAO;AAE1B,UAAM,MAAM,KAAK;AAEjB,WAAQ,QAAQ,KAAK,SAAS,OACtB,QAAQ,MAAM,SAAS,UAAU,SAAS,UAAU,SAAS;AAAA,EACvE;AAEA,WAAS,oBAAqB;AAC5B,WAAO;AAAA,EACT;AAEA,WAAS,OAAQ,QAAQ;AACvB,WAAO,WAAW;AAAA,EACpB;AAEA,UAAiB,IAAIG,MAAK,0BAA0B;AAAA,IAClD,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW;AAAA,MACT,WAAW,WAAY;AAAE,eAAO;AAAA,MAAG;AAAA,MACnC,WAAW,WAAY;AAAE,eAAO;AAAA,MAAM;AAAA,MACtC,WAAW,WAAY;AAAE,eAAO;AAAA,MAAM;AAAA,MACtC,WAAW,WAAY;AAAE,eAAO;AAAA,MAAM;AAAA,MACtC,OAAO,WAAY;AAAE,eAAO;AAAA,MAAE;AAAA;IAEhC,cAAc;AAAA,GACf;;;;;;;;AChCD,QAAMA,QAAOH,YAAA;AAEb,WAAS,mBAAoB,MAAM;AACjC,QAAI,SAAS,KAAM,QAAO;AAE1B,UAAM,MAAM,KAAK;AAEjB,WAAQ,QAAQ,MAAM,SAAS,UAAU,SAAS,UAAU,SAAS,WAC7D,QAAQ,MAAM,SAAS,WAAW,SAAS,WAAW,SAAS;AAAA,EACzE;AAEA,WAAS,qBAAsB,MAAM;AACnC,WAAO,SAAS,UACT,SAAS,UACT,SAAS;AAAA,EAClB;AAEA,WAAS,UAAW,QAAQ;AAC1B,WAAO,OAAO,UAAU,SAAS,KAAK,MAAM,MAAM;AAAA,EACpD;AAEA,SAAiB,IAAIG,MAAK,0BAA0B;AAAA,IAClD,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW;AAAA,MACT,WAAW,SAAU,QAAQ;AAAE,eAAO,SAAS,SAAS;AAAA,MAAO;AAAA,MAC/D,WAAW,SAAU,QAAQ;AAAE,eAAO,SAAS,SAAS;AAAA,MAAO;AAAA,MAC/D,WAAW,SAAU,QAAQ;AAAE,eAAO,SAAS,SAAS;AAAA,MAAO;AAAA;IAEjE,cAAc;AAAA,GACf;;;;;;;;AChCD,QAAMJ,UAASC,cAAA;AACf,QAAMG,QAAOC,YAAA;AAEb,WAAS,UAAW,GAAG;AACrB,WAAS,KAAK,MAAiB,KAAK,MAC3B,KAAK,MAAiB,KAAK,MAC3B,KAAK,MAAiB,KAAK;AAAA,EACtC;AAEA,WAAS,UAAW,GAAG;AACrB,WAAS,KAAK,MAAiB,KAAK;AAAA,EACtC;AAEA,WAAS,UAAW,GAAG;AACrB,WAAS,KAAK,MAAiB,KAAK;AAAA,EACtC;AAEA,WAAS,mBAAoB,MAAM;AACjC,QAAI,SAAS,KAAM,QAAO;AAE1B,UAAM,MAAM,KAAK;AACjB,QAAI,QAAQ;AACZ,QAAI,YAAY;AAEhB,QAAI,CAAC,IAAK,QAAO;AAEjB,QAAI,KAAK,KAAK,KAAK;AAGnB,QAAI,OAAO,OAAO,OAAO,KAAK;AAC5B,WAAK,KAAK,EAAE,KAAK;AAAA,IACrB;AAEE,QAAI,OAAO,KAAK;AAEd,UAAI,QAAQ,MAAM,IAAK,QAAO;AAC9B,WAAK,KAAK,EAAE,KAAK;AAIjB,UAAI,OAAO,KAAK;AAEd;AAEA,eAAO,QAAQ,KAAK,SAAS;AAC3B,eAAK,KAAK,KAAK;AACf,cAAI,OAAO,OAAO,OAAO,IAAK,QAAO;AACrC,sBAAY;AAAA,QACpB;AACM,eAAO,aAAa,SAAS,iBAAiB,IAAI,CAAC;AAAA,MACzD;AAEI,UAAI,OAAO,KAAK;AAEd;AAEA,eAAO,QAAQ,KAAK,SAAS;AAC3B,cAAI,CAAC,UAAU,KAAK,WAAW,KAAK,CAAC,EAAG,QAAO;AAC/C,sBAAY;AAAA,QACpB;AACM,eAAO,aAAa,SAAS,iBAAiB,IAAI,CAAC;AAAA,MACzD;AAEI,UAAI,OAAO,KAAK;AAEd;AAEA,eAAO,QAAQ,KAAK,SAAS;AAC3B,cAAI,CAAC,UAAU,KAAK,WAAW,KAAK,CAAC,EAAG,QAAO;AAC/C,sBAAY;AAAA,QACpB;AACM,eAAO,aAAa,SAAS,iBAAiB,IAAI,CAAC;AAAA,MACzD;AAAA,IACA;AAIE,WAAO,QAAQ,KAAK,SAAS;AAC3B,UAAI,CAAC,UAAU,KAAK,WAAW,KAAK,CAAC,GAAG;AACtC,eAAO;AAAA,MACb;AACI,kBAAY;AAAA,IAChB;AAEE,QAAI,CAAC,UAAW,QAAO;AAEvB,WAAO,SAAS,iBAAiB,IAAI,CAAC;AAAA,EACxC;AAEA,WAAS,iBAAkB,MAAM;AAC/B,QAAI,QAAQ;AACZ,QAAI,OAAO;AAEX,QAAI,KAAK,MAAM,CAAC;AAEhB,QAAI,OAAO,OAAO,OAAO,KAAK;AAC5B,UAAI,OAAO,IAAK,QAAO;AACvB,cAAQ,MAAM,MAAM,CAAC;AACrB,WAAK,MAAM,CAAC;AAAA,IAChB;AAEE,QAAI,UAAU,IAAK,QAAO;AAE1B,QAAI,OAAO,KAAK;AACd,UAAI,MAAM,CAAC,MAAM,IAAK,QAAO,OAAO,SAAS,MAAM,MAAM,CAAC,GAAG,CAAC;AAC9D,UAAI,MAAM,CAAC,MAAM,IAAK,QAAO,OAAO,SAAS,MAAM,MAAM,CAAC,GAAG,EAAE;AAC/D,UAAI,MAAM,CAAC,MAAM,IAAK,QAAO,OAAO,SAAS,MAAM,MAAM,CAAC,GAAG,CAAC;AAAA,IAClE;AAEE,WAAO,OAAO,SAAS,OAAO,EAAE;AAAA,EAClC;AAEA,WAAS,qBAAsB,MAAM;AACnC,WAAO,iBAAiB,IAAI;AAAA,EAC9B;AAEA,WAAS,UAAW,QAAQ;AAC1B,WAAQ,OAAO,UAAU,SAAS,KAAK,MAAM,MAAO,sBAC5C,SAAS,MAAM,KAAK,CAACL,QAAO,eAAe,MAAM;AAAA,EAC3D;AAEA,QAAiB,IAAII,MAAK,yBAAyB;AAAA,IACjD,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW;AAAA,MACT,QAAQ,SAAU,KAAK;AAAE,eAAO,OAAO,IAAI,OAAO,IAAI,SAAS,CAAC,IAAI,QAAQ,IAAI,SAAS,CAAC,EAAE,MAAM,CAAC;AAAA,MAAC;AAAA,MACpG,OAAO,SAAU,KAAK;AAAE,eAAO,OAAO,IAAI,OAAO,IAAI,SAAS,CAAC,IAAI,QAAQ,IAAI,SAAS,CAAC,EAAE,MAAM,CAAC;AAAA,MAAC;AAAA,MACnG,SAAS,SAAU,KAAK;AAAE,eAAO,IAAI,SAAS,EAAE;AAAA,MAAC;AAAA,MACjD,aAAa,SAAU,KAAK;AAAE,eAAO,OAAO,IAAI,OAAO,IAAI,SAAS,EAAE,EAAE,gBAAgB,QAAQ,IAAI,SAAS,EAAE,EAAE,YAAW,EAAG,MAAM,CAAC;AAAA,MAAC;AAAA;IAEzI,cAAc;AAAA,IACd,cAAc;AAAA,MACZ,QAAQ,CAAC,GAAG,KAAK;AAAA,MACjB,OAAO,CAAC,GAAG,KAAK;AAAA,MAChB,SAAS,CAAC,IAAI,KAAK;AAAA,MACnB,aAAa,CAAC,IAAI,KAAK;AAAA,IAC3B;AAAA,GACC;;;;;;;;AC3ID,QAAMJ,UAASC,cAAA;AACf,QAAMG,QAAOC,YAAA;AAEb,QAAM,qBAAqB,IAAI;AAAA;AAAA,IAE7B;AAAA,EAOuB;AAEzB,QAAM,6BAA6B,IAAI;AAAA,IACrC;AAAA,EAIuB;AAEzB,WAAS,iBAAkB,MAAM;AAC/B,QAAI,SAAS,KAAM,QAAO;AAE1B,QAAI,CAAC,mBAAmB,KAAK,IAAI,GAAG;AAClC,aAAO;AAAA,IACX;AAEE,QAAI,SAAS,WAAW,MAAM,EAAE,CAAC,GAAG;AAClC,aAAO;AAAA,IACX;AAEE,WAAO,2BAA2B,KAAK,IAAI;AAAA,EAC7C;AAEA,WAAS,mBAAoB,MAAM;AACjC,QAAI,QAAQ,KAAK,YAAW;AAC5B,UAAM,OAAO,MAAM,CAAC,MAAM,MAAM,KAAK;AAErC,QAAI,KAAK,QAAQ,MAAM,CAAC,CAAC,KAAK,GAAG;AAC/B,cAAQ,MAAM,MAAM,CAAC;AAAA,IACzB;AAEE,QAAI,UAAU,QAAQ;AACpB,aAAQ,SAAS,IAAK,OAAO,oBAAoB,OAAO;AAAA,IAC5D,WAAa,UAAU,QAAQ;AAC3B,aAAO;AAAA,IACX;AACE,WAAO,OAAO,WAAW,OAAO,EAAE;AAAA,EACpC;AAEA,QAAM,yBAAyB;AAE/B,WAAS,mBAAoB,QAAQ,OAAO;AAC1C,QAAI,MAAM,MAAM,GAAG;AACjB,cAAQ,OAAK;AAAA,QACX,KAAK;AAAa,iBAAO;AAAA,QACzB,KAAK;AAAa,iBAAO;AAAA,QACzB,KAAK;AAAa,iBAAO;AAAA,MAC/B;AAAA,IACA,WAAa,OAAO,sBAAsB,QAAQ;AAC9C,cAAQ,OAAK;AAAA,QACX,KAAK;AAAa,iBAAO;AAAA,QACzB,KAAK;AAAa,iBAAO;AAAA,QACzB,KAAK;AAAa,iBAAO;AAAA,MAC/B;AAAA,IACA,WAAa,OAAO,sBAAsB,QAAQ;AAC9C,cAAQ,OAAK;AAAA,QACX,KAAK;AAAa,iBAAO;AAAA,QACzB,KAAK;AAAa,iBAAO;AAAA,QACzB,KAAK;AAAa,iBAAO;AAAA,MAC/B;AAAA,IACA,WAAaL,QAAO,eAAe,MAAM,GAAG;AACxC,aAAO;AAAA,IACX;AAEE,UAAM,MAAM,OAAO,SAAS,EAAE;AAK9B,WAAO,uBAAuB,KAAK,GAAG,IAAI,IAAI,QAAQ,KAAK,IAAI,IAAI;AAAA,EACrE;AAEA,WAAS,QAAS,QAAQ;AACxB,WAAQ,OAAO,UAAU,SAAS,KAAK,MAAM,MAAM,sBAC3C,SAAS,MAAM,KAAKA,QAAO,eAAe,MAAM;AAAA,EAC1D;AAEA,UAAiB,IAAII,MAAK,2BAA2B;AAAA,IACnD,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW;AAAA,IACX,cAAc;AAAA,GACf;;;;;;;;ACzFD,SAAiBH,gBAAA,EAAsB,OAAO;AAAA,IAC5C,UAAU;AAAA,MACRI,aAAA;AAAA,MACAI,YAAA;AAAA,MACAC,WAAA;AAAA,MACAC,aAAA;AAAA,IACJ;AAAA,GACC;;;;;;;;ACRD,SAAiBV,YAAA;;;;;;;;ACNjB,QAAMG,QAAOH,YAAA;AAEb,QAAM,mBAAmB,IAAI;AAAA,IAC3B;AAAA,EAEgB;AAElB,QAAM,wBAAwB,IAAI;AAAA,IAChC;AAAA,EASwB;AAE1B,WAAS,qBAAsB,MAAM;AACnC,QAAI,SAAS,KAAM,QAAO;AAC1B,QAAI,iBAAiB,KAAK,IAAI,MAAM,KAAM,QAAO;AACjD,QAAI,sBAAsB,KAAK,IAAI,MAAM,KAAM,QAAO;AACtD,WAAO;AAAA,EACT;AAEA,WAAS,uBAAwB,MAAM;AACrC,QAAI,WAAW;AACf,QAAI,QAAQ;AAEZ,QAAI,QAAQ,iBAAiB,KAAK,IAAI;AACtC,QAAI,UAAU,KAAM,SAAQ,sBAAsB,KAAK,IAAI;AAE3D,QAAI,UAAU,KAAM,OAAM,IAAI,MAAM,oBAAoB;AAIxD,UAAM,OAAO,CAAE,MAAM,CAAC;AACtB,UAAM,QAAQ,CAAE,MAAM,CAAC,IAAK;AAC5B,UAAM,MAAM,CAAE,MAAM,CAAC;AAErB,QAAI,CAAC,MAAM,CAAC,GAAG;AACb,aAAO,IAAI,KAAK,KAAK,IAAI,MAAM,OAAO,GAAG,CAAC;AAAA,IAC9C;AAIE,UAAM,OAAO,CAAE,MAAM,CAAC;AACtB,UAAM,SAAS,CAAE,MAAM,CAAC;AACxB,UAAM,SAAS,CAAE,MAAM,CAAC;AAExB,QAAI,MAAM,CAAC,GAAG;AACZ,iBAAW,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC;AAC9B,aAAO,SAAS,SAAS,GAAG;AAC1B,oBAAY;AAAA,MAClB;AACI,iBAAW,CAAC;AAAA,IAChB;AAIE,QAAI,MAAM,CAAC,GAAG;AACZ,YAAM,SAAS,CAAE,MAAM,EAAE;AACzB,YAAM,WAAW,EAAE,MAAM,EAAE,KAAK;AAChC,eAAS,SAAS,KAAK,YAAY;AACnC,UAAI,MAAM,CAAC,MAAM,IAAK,SAAQ,CAAC;AAAA,IACnC;AAEE,UAAM,OAAO,IAAI,KAAK,KAAK,IAAI,MAAM,OAAO,KAAK,MAAM,QAAQ,QAAQ,QAAQ,CAAC;AAEhF,QAAI,MAAO,MAAK,QAAQ,KAAK,QAAO,IAAK,KAAK;AAE9C,WAAO;AAAA,EACT;AAEA,WAAS,uBAAwB,QAAqB;AACpD,WAAO,OAAO,YAAW;AAAA,EAC3B;AAEA,cAAiB,IAAIG,MAAK,+BAA+B;AAAA,IACvD,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,WAAW;AAAA,GACZ;;;;;;;;ACrFD,QAAMA,QAAOH,YAAA;AAEb,WAAS,iBAAkB,MAAM;AAC/B,WAAO,SAAS,QAAQ,SAAS;AAAA,EACnC;AAEA,UAAiB,IAAIG,MAAK,2BAA2B;AAAA,IACnD,MAAM;AAAA,IACN,SAAS;AAAA,GACV;;;;;;;;ACTD,QAAMA,QAAOH,YAAA;AAGb,QAAM,aAAa;AAEnB,WAAS,kBAAmB,MAAM;AAChC,QAAI,SAAS,KAAM,QAAO;AAE1B,QAAI,SAAS;AACb,UAAM,MAAM,KAAK;AACjB,UAAME,OAAM;AAGZ,aAAS,MAAM,GAAG,MAAM,KAAK,OAAO;AAClC,YAAM,OAAOA,KAAI,QAAQ,KAAK,OAAO,GAAG,CAAC;AAGzC,UAAI,OAAO,GAAI;AAGf,UAAI,OAAO,EAAG,QAAO;AAErB,gBAAU;AAAA,IACd;AAGE,WAAQ,SAAS,MAAO;AAAA,EAC1B;AAEA,WAAS,oBAAqB,MAAM;AAClC,UAAM,QAAQ,KAAK,QAAQ,YAAY,EAAE;AACzC,UAAM,MAAM,MAAM;AAClB,UAAMA,OAAM;AACZ,QAAI,OAAO;AACX,UAAM,SAAS,CAAA;AAIf,aAAS,MAAM,GAAG,MAAM,KAAK,OAAO;AAClC,UAAK,MAAM,MAAM,KAAM,KAAK;AAC1B,eAAO,KAAM,QAAQ,KAAM,GAAI;AAC/B,eAAO,KAAM,QAAQ,IAAK,GAAI;AAC9B,eAAO,KAAK,OAAO,GAAI;AAAA,MAC7B;AAEI,aAAQ,QAAQ,IAAKA,KAAI,QAAQ,MAAM,OAAO,GAAG,CAAC;AAAA,IACtD;AAIE,UAAM,WAAY,MAAM,IAAK;AAE7B,QAAI,aAAa,GAAG;AAClB,aAAO,KAAM,QAAQ,KAAM,GAAI;AAC/B,aAAO,KAAM,QAAQ,IAAK,GAAI;AAC9B,aAAO,KAAK,OAAO,GAAI;AAAA,IAC3B,WAAa,aAAa,IAAI;AAC1B,aAAO,KAAM,QAAQ,KAAM,GAAI;AAC/B,aAAO,KAAM,QAAQ,IAAK,GAAI;AAAA,IAClC,WAAa,aAAa,IAAI;AAC1B,aAAO,KAAM,QAAQ,IAAK,GAAI;AAAA,IAClC;AAEE,WAAO,IAAI,WAAW,MAAM;AAAA,EAC9B;AAEA,WAAS,oBAAqB,QAAqB;AACjD,QAAI,SAAS;AACb,QAAI,OAAO;AACX,UAAM,MAAM,OAAO;AACnB,UAAMA,OAAM;AAIZ,aAAS,MAAM,GAAG,MAAM,KAAK,OAAO;AAClC,UAAK,MAAM,MAAM,KAAM,KAAK;AAC1B,kBAAUA,KAAK,QAAQ,KAAM,EAAI;AACjC,kBAAUA,KAAK,QAAQ,KAAM,EAAI;AACjC,kBAAUA,KAAK,QAAQ,IAAK,EAAI;AAChC,kBAAUA,KAAI,OAAO,EAAI;AAAA,MAC/B;AAEI,cAAQ,QAAQ,KAAK,OAAO,GAAG;AAAA,IACnC;AAIE,UAAM,OAAO,MAAM;AAEnB,QAAI,SAAS,GAAG;AACd,gBAAUA,KAAK,QAAQ,KAAM,EAAI;AACjC,gBAAUA,KAAK,QAAQ,KAAM,EAAI;AACjC,gBAAUA,KAAK,QAAQ,IAAK,EAAI;AAChC,gBAAUA,KAAI,OAAO,EAAI;AAAA,IAC7B,WAAa,SAAS,GAAG;AACrB,gBAAUA,KAAK,QAAQ,KAAM,EAAI;AACjC,gBAAUA,KAAK,QAAQ,IAAK,EAAI;AAChC,gBAAUA,KAAK,QAAQ,IAAK,EAAI;AAChC,gBAAUA,KAAI,EAAE;AAAA,IACpB,WAAa,SAAS,GAAG;AACrB,gBAAUA,KAAK,QAAQ,IAAK,EAAI;AAChC,gBAAUA,KAAK,QAAQ,IAAK,EAAI;AAChC,gBAAUA,KAAI,EAAE;AAChB,gBAAUA,KAAI,EAAE;AAAA,IACpB;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,SAAU,KAAK;AACtB,WAAO,OAAO,UAAU,SAAS,KAAK,GAAG,MAAM;AAAA,EACjD;AAEA,WAAiB,IAAIC,MAAK,4BAA4B;AAAA,IACpD,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW;AAAA,GACZ;;;;;;;;ACvHD,QAAMA,QAAOH,YAAA;AAEb,QAAM,kBAAkB,OAAO,UAAU;AACzC,QAAM,YAAY,OAAO,UAAU;AAEnC,WAAS,gBAAiB,MAAM;AAC9B,QAAI,SAAS,KAAM,QAAO;AAE1B,UAAM,aAAa,CAAA;AACnB,UAAM,SAAS;AAEf,aAAS,QAAQ,GAAG,SAAS,OAAO,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtE,YAAM,OAAO,OAAO,KAAK;AACzB,UAAI,aAAa;AAEjB,UAAI,UAAU,KAAK,IAAI,MAAM,kBAAmB,QAAO;AAEvD,UAAI;AACJ,WAAK,WAAW,MAAM;AACpB,YAAI,gBAAgB,KAAK,MAAM,OAAO,GAAG;AACvC,cAAI,CAAC,WAAY,cAAa;AAAA,cACzB,QAAO;AAAA,QACpB;AAAA,MACA;AAEI,UAAI,CAAC,WAAY,QAAO;AAExB,UAAI,gBAAgB,KAAK,YAAY,OAAO,EAAG,QAAO;AACtD,aAAO,eAAe,YAAY,SAAS,EAAE,OAAO,KAAI,CAAE;AAAA,IAC9D;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,kBAAmB,MAAM;AAChC,WAAO,SAAS,OAAO,OAAO,CAAA;AAAA,EAChC;AAEA,SAAiB,IAAIG,MAAK,0BAA0B;AAAA,IAClD,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,GACZ;;;;;;;;AC1CD,QAAMA,QAAOH,YAAA;AAEb,QAAM,YAAY,OAAO,UAAU;AAEnC,WAAS,iBAAkB,MAAM;AAC/B,QAAI,SAAS,KAAM,QAAO;AAE1B,UAAM,SAAS;AAEf,UAAM,SAAS,IAAI,MAAM,OAAO,MAAM;AAEtC,aAAS,QAAQ,GAAG,SAAS,OAAO,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtE,YAAM,OAAO,OAAO,KAAK;AAEzB,UAAI,UAAU,KAAK,IAAI,MAAM,kBAAmB,QAAO;AAEvD,YAAM,OAAO,OAAO,KAAK,IAAI;AAE7B,UAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,aAAO,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC;AAAA,IAC3C;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,mBAAoB,MAAM;AACjC,QAAI,SAAS,KAAM,QAAO,CAAA;AAE1B,UAAM,SAAS;AACf,UAAM,SAAS,IAAI,MAAM,OAAO,MAAM;AAEtC,aAAS,QAAQ,GAAG,SAAS,OAAO,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtE,YAAM,OAAO,OAAO,KAAK;AAEzB,YAAM,OAAO,OAAO,KAAK,IAAI;AAE7B,aAAO,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC;AAAA,IAC3C;AAEE,WAAO;AAAA,EACT;AAEA,UAAiB,IAAIG,MAAK,2BAA2B;AAAA,IACnD,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,GACZ;;;;;;;;AC/CD,QAAMA,QAAOH,YAAA;AAEb,QAAM,kBAAkB,OAAO,UAAU;AAEzC,WAAS,eAAgB,MAAM;AAC7B,QAAI,SAAS,KAAM,QAAO;AAE1B,UAAM,SAAS;AAEf,eAAW,OAAO,QAAQ;AACxB,UAAI,gBAAgB,KAAK,QAAQ,GAAG,GAAG;AACrC,YAAI,OAAO,GAAG,MAAM,KAAM,QAAO;AAAA,MACvC;AAAA,IACA;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,iBAAkB,MAAM;AAC/B,WAAO,SAAS,OAAO,OAAO,CAAA;AAAA,EAChC;AAEA,QAAiB,IAAIG,MAAK,yBAAyB;AAAA,IACjD,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,GACZ;;;;;;;;ACpBD,aAAiBH,YAAA,EAAkB,OAAO;AAAA,IACxC,UAAU;AAAA,MACRI,iBAAA;AAAA,MACAI,aAAA;AAAA;IAEF,UAAU;AAAA,MACRC,cAAA;AAAA,MACAC,YAAA;AAAA,MACAC,aAAA;AAAA,MACAC,WAAA;AAAA,IACJ;AAAA,GACC;;;;;;;ACjBD,QAAMb,UAASC,cAAA;AACf,QAAMF,iBAAgBM,iBAAA;AACtB,QAAM,cAAcI,eAAA;AACpB,QAAMK,kBAAiBJ,gBAAA;AAEvB,QAAM,kBAAkB,OAAO,UAAU;AAEzC,QAAM,kBAAkB;AACxB,QAAM,mBAAmB;AACzB,QAAM,mBAAmB;AACzB,QAAM,oBAAoB;AAE1B,QAAM,gBAAgB;AACtB,QAAM,iBAAiB;AACvB,QAAM,gBAAgB;AAGtB,QAAM,wBAAwB;AAC9B,QAAM,gCAAgC;AAEtC,QAAM,0BAA0B;AAEhC,QAAM,qBAAqB;AAE3B,QAAM,kBAAkB;AAExB,WAAS,OAAQ,KAAK;AAAE,WAAO,OAAO,UAAU,SAAS,KAAK,GAAG;AAAA,EAAC;AAElE,WAAS,MAAO,GAAG;AACjB,WAAQ,MAAM,MAAkB,MAAM;AAAA,EACxC;AAEA,WAAS,aAAc,GAAG;AACxB,WAAQ,MAAM,KAAmB,MAAM;AAAA,EACzC;AAEA,WAAS,UAAW,GAAG;AACrB,WAAQ,MAAM,KACN,MAAM,MACN,MAAM,MACN,MAAM;AAAA,EAChB;AAEA,WAAS,gBAAiB,GAAG;AAC3B,WAAO,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,OACN,MAAM;AAAA,EACf;AAEA,WAAS,YAAa,GAAG;AACvB,QAAK,KAAK,MAAiB,KAAK,IAAc;AAC5C,aAAO,IAAI;AAAA,IACf;AAEE,UAAM,KAAK,IAAI;AAEf,QAAK,MAAM,MAAiB,MAAM,KAAc;AAC9C,aAAO,KAAK,KAAO;AAAA,IACvB;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,cAAe,GAAG;AACzB,QAAI,MAAM,KAAa;AAAE,aAAO;AAAA,IAAC;AACjC,QAAI,MAAM,KAAa;AAAE,aAAO;AAAA,IAAC;AACjC,QAAI,MAAM,IAAa;AAAE,aAAO;AAAA,IAAC;AACjC,WAAO;AAAA,EACT;AAEA,WAAS,gBAAiB,GAAG;AAC3B,QAAK,KAAK,MAAiB,KAAK,IAAc;AAC5C,aAAO,IAAI;AAAA,IACf;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,qBAAsB,GAAG;AAChC,YAAQ,GAAC;AAAA,MACP,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAe,eAAO;AAAA,MAC3B,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAiB,eAAO;AAAA,MAC7B,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB,KAAK;AAAa,eAAO;AAAA,MACzB;AAAS,eAAO;AAAA,IACpB;AAAA,EACA;AAEA,WAAS,kBAAmB,GAAG;AAC7B,QAAI,KAAK,OAAQ;AACf,aAAO,OAAO,aAAa,CAAC;AAAA,IAChC;AAGE,WAAO,OAAO;AAAA,OACV,IAAI,SAAa,MAAM;AAAA,OACvB,IAAI,QAAY,QAAU;AAAA,IAChC;AAAA,EACA;AAIA,WAAS,YAAa,QAAQ,KAAK,OAAO;AAExC,QAAI,QAAQ,aAAa;AACvB,aAAO,eAAe,QAAQ,KAAK;AAAA,QACjC,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,UAAU;AAAA,QACV;AAAA,OACD;AAAA,IACL,OAAS;AACL,aAAO,GAAG,IAAI;AAAA,IAClB;AAAA,EACA;AAEA,QAAM,oBAAoB,IAAI,MAAM,GAAG;AACvC,QAAM,kBAAkB,IAAI,MAAM,GAAG;AACrC,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,sBAAkB,CAAC,IAAI,qBAAqB,CAAC,IAAI,IAAI;AACrD,oBAAgB,CAAC,IAAI,qBAAqB,CAAC;AAAA,EAC7C;AAEA,WAAS,MAAO,OAAO,SAAS;AAC9B,SAAK,QAAQ;AAEb,SAAK,WAAW,QAAQ,UAAU,KAAK;AACvC,SAAK,SAAS,QAAQ,QAAQ,KAAKI;AACnC,SAAK,YAAY,QAAQ,WAAW,KAAK;AAGzC,SAAK,SAAS,QAAQ,QAAQ,KAAK;AAEnC,SAAK,OAAO,QAAQ,MAAM,KAAK;AAC/B,SAAK,WAAW,QAAQ,UAAU,KAAK;AACvC,SAAK,WAAW,OAAO,QAAQ,UAAU,MAAM,WAAW,QAAQ,UAAU,IAAI;AAChF,SAAK,oBAAoB,OAAO,QAAQ,mBAAmB,MAAM,WAAW,QAAQ,mBAAmB,IAAI;AAE3G,SAAK,gBAAgB,KAAK,OAAO;AACjC,SAAK,UAAU,KAAK,OAAO;AAE3B,SAAK,SAAS,MAAM;AACpB,SAAK,WAAW;AAChB,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,SAAK,aAAa;AAClB,SAAK,QAAQ;AACb,SAAK,iBAAiB;AAItB,SAAK,iBAAiB;AAEtB,SAAK,YAAY,CAAA;AACjB,SAAK,wBAAwB,CAAA;AAAA,EAW/B;AAEA,WAAS,cAAe,OAAO,SAAS;AACtC,UAAM,OAAO;AAAA,MACX,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM,MAAM,MAAM,GAAG,EAAE;AAAA;AAAA,MAC/B,UAAU,MAAM;AAAA,MAChB,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM,WAAW,MAAM;AAAA,IACnC;AAEE,SAAK,UAAU,YAAY,IAAI;AAE/B,WAAO,IAAIf,eAAc,SAAS,IAAI;AAAA,EACxC;AAEA,WAAS,WAAY,OAAO,SAAS;AACnC,UAAM,cAAc,OAAO,OAAO;AAAA,EACpC;AAEA,WAAS,aAAc,OAAO,SAAS;AACrC,QAAI,MAAM,WAAW;AACnB,YAAM,UAAU,KAAK,MAAM,cAAc,OAAO,OAAO,CAAC;AAAA,IAC5D;AAAA,EACA;AAEA,WAAS,YAAa,OAAO,MAAM,OAAO;AACxC,UAAM,eAAe,MAAM;AAE3B,QAAI,aAAa,WAAW,GAAG;AAC7B,YAAM,cAAc,aAAa,aAAa,SAAS,CAAC;AAExD,UAAI,CAAC,gBAAgB,KAAK,aAAa,IAAI,GAAG;AAC5C,oBAAY,IAAI,IAAI;AAAA,UAClB,SAAS,gBAAgB,KAAK,MAAM,WAAW,IAAI;AAAA,UACnD,OAAO,MAAM,UAAU,IAAI;AAAA,QACnC;AAAA,MACA;AAAA,IACA;AAEE,UAAM,UAAU,IAAI,IAAI;AAAA,EAC1B;AAEA,WAAS,uBAAwB,OAAO;AACtC,UAAM,sBAAsB,KAAK,uBAAO,OAAO,IAAI,CAAC;AAAA,EACtD;AAEA,WAAS,wBAAyB,OAAO;AACvC,UAAM,cAAc,MAAM,sBAAsB,IAAG;AACnD,UAAM,eAAe,MAAM;AAE3B,QAAI,aAAa,WAAW,EAAG;AAE/B,UAAM,SAAS,aAAa,aAAa,SAAS,CAAC;AACnD,UAAM,QAAQ,OAAO,KAAK,WAAW;AAErC,aAAS,QAAQ,GAAG,SAAS,MAAM,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACrE,YAAM,OAAO,MAAM,KAAK;AAExB,UAAI,CAAC,gBAAgB,KAAK,QAAQ,IAAI,GAAG;AACvC,eAAO,IAAI,IAAI,YAAY,IAAI;AAAA,MACrC;AAAA,IACA;AAAA,EACA;AAEA,WAAS,0BAA2B,OAAO;AACzC,UAAM,cAAc,MAAM,sBAAsB,IAAG;AACnD,UAAM,QAAQ,OAAO,KAAK,WAAW;AAErC,aAAS,QAAQ,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AACzD,YAAM,QAAQ,YAAY,MAAM,KAAK,CAAC;AAEtC,UAAI,MAAM,SAAS;AACjB,cAAM,UAAU,MAAM,KAAK,CAAC,IAAI,MAAM;AAAA,MAC5C,OAAW;AACL,eAAO,MAAM,UAAU,MAAM,KAAK,CAAC;AAAA,MACzC;AAAA,IACA;AAAA,EACA;AAEA,WAAS,cAAe,OAAO;AAC7B,WAAO;AAAA,MACL,UAAU,MAAM;AAAA,MAChB,MAAM,MAAM;AAAA,MACZ,WAAW,MAAM;AAAA,MACjB,YAAY,MAAM;AAAA,MAClB,gBAAgB,MAAM;AAAA,MACtB,KAAK,MAAM;AAAA,MACX,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,IAClB;AAAA,EACA;AAEA,WAAS,aAAc,OAAO,UAAU;AACtC,UAAM,WAAW,SAAS;AAC1B,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,SAAS;AAC3B,UAAM,aAAa,SAAS;AAC5B,UAAM,iBAAiB,SAAS;AAChC,UAAM,MAAM,SAAS;AACrB,UAAM,SAAS,SAAS;AACxB,UAAM,OAAO,SAAS;AACtB,UAAM,SAAS,SAAS;AAAA,EAC1B;AAEA,QAAM,oBAAoB;AAAA,IAExB,MAAM,SAAS,oBAAqB,OAAO,MAAM,MAAM;AACrD,UAAI,MAAM,YAAY,MAAM;AAC1B,mBAAW,OAAO,gCAAgC;AAAA,MACxD;AAEI,UAAI,KAAK,WAAW,GAAG;AACrB,mBAAW,OAAO,6CAA6C;AAAA,MACrE;AAEI,YAAM,QAAQ,uBAAuB,KAAK,KAAK,CAAC,CAAC;AAEjD,UAAI,UAAU,MAAM;AAClB,mBAAW,OAAO,2CAA2C;AAAA,MACnE;AAEI,YAAM,QAAQ,SAAS,MAAM,CAAC,GAAG,EAAE;AACnC,YAAM,QAAQ,SAAS,MAAM,CAAC,GAAG,EAAE;AAEnC,UAAI,UAAU,GAAG;AACf,mBAAW,OAAO,2CAA2C;AAAA,MACnE;AAEI,YAAM,UAAU,KAAK,CAAC;AACtB,YAAM,kBAAmB,QAAQ;AAEjC,UAAI,UAAU,KAAK,UAAU,GAAG;AAC9B,qBAAa,OAAO,0CAA0C;AAAA,MACpE;AAAA,IACA;AAAA,IAEE,KAAK,SAAS,mBAAoB,OAAO,MAAM,MAAM;AACnD,UAAI;AAEJ,UAAI,KAAK,WAAW,GAAG;AACrB,mBAAW,OAAO,6CAA6C;AAAA,MACrE;AAEI,YAAM,SAAS,KAAK,CAAC;AACrB,eAAS,KAAK,CAAC;AAEf,UAAI,CAAC,mBAAmB,KAAK,MAAM,GAAG;AACpC,mBAAW,OAAO,6DAA6D;AAAA,MACrF;AAEI,UAAI,gBAAgB,KAAK,MAAM,QAAQ,MAAM,GAAG;AAC9C,mBAAW,OAAO,gDAAgD,SAAS,cAAc;AAAA,MAC/F;AAEI,UAAI,CAAC,gBAAgB,KAAK,MAAM,GAAG;AACjC,mBAAW,OAAO,8DAA8D;AAAA,MACtF;AAEI,UAAI;AACF,iBAAS,mBAAmB,MAAM;AAAA,MACxC,SAAa,KAAK;AACZ,mBAAW,OAAO,8BAA8B,MAAM;AAAA,MAC5D;AAEI,YAAM,OAAO,MAAM,IAAI;AAAA,IAC3B;AAAA,EACA;AAEA,WAAS,eAAgB,OAAO,OAAO,KAAK,WAAW;AACrD,QAAI,QAAQ,KAAK;AACf,YAAM,UAAU,MAAM,MAAM,MAAM,OAAO,GAAG;AAE5C,UAAI,WAAW;AACb,iBAAS,YAAY,GAAG,UAAU,QAAQ,QAAQ,YAAY,SAAS,aAAa,GAAG;AACrF,gBAAM,aAAa,QAAQ,WAAW,SAAS;AAC/C,cAAI,EAAE,eAAe,KACd,cAAc,MAAQ,cAAc,UAAY;AACrD,uBAAW,OAAO,+BAA+B;AAAA,UAC3D;AAAA,QACA;AAAA,MACA,WAAe,sBAAsB,KAAK,OAAO,GAAG;AAC9C,mBAAW,OAAO,8CAA8C;AAAA,MACtE;AAEI,YAAM,UAAU;AAAA,IACpB;AAAA,EACA;AAEA,WAAS,cAAe,OAAO,aAAa,QAAQ,iBAAiB;AACnE,QAAI,CAACC,QAAO,SAAS,MAAM,GAAG;AAC5B,iBAAW,OAAO,mEAAmE;AAAA,IACzF;AAEE,UAAM,aAAa,OAAO,KAAK,MAAM;AAErC,aAAS,QAAQ,GAAG,WAAW,WAAW,QAAQ,QAAQ,UAAU,SAAS,GAAG;AAC9E,YAAM,MAAM,WAAW,KAAK;AAE5B,UAAI,MAAM,sBAAsB,MAAM,EAAE,MAAM,iBAAiB,MAAM,mBAAmB;AACtF,mBAAW,OAAO,4CAA4C,MAAM,oBAAoB,GAAG;AAAA,MACjG;AAEI,UAAI,CAAC,gBAAgB,KAAK,aAAa,GAAG,GAAG;AAC3C,oBAAY,aAAa,KAAK,OAAO,GAAG,CAAC;AACzC,wBAAgB,GAAG,IAAI;AAAA,MAC7B;AAAA,IACA;AAAA,EACA;AAEA,WAAS,iBAAkB,OAAO,SAAS,iBAAiB,QAAQ,SAAS,WAC3E,WAAW,gBAAgB,UAAU;AAIrC,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,gBAAU,MAAM,UAAU,MAAM,KAAK,OAAO;AAE5C,eAAS,QAAQ,GAAG,WAAW,QAAQ,QAAQ,QAAQ,UAAU,SAAS,GAAG;AAC3E,YAAI,MAAM,QAAQ,QAAQ,KAAK,CAAC,GAAG;AACjC,qBAAW,OAAO,6CAA6C;AAAA,QACvE;AAEM,YAAI,OAAO,YAAY,YAAY,OAAO,QAAQ,KAAK,CAAC,MAAM,mBAAmB;AAC/E,kBAAQ,KAAK,IAAI;AAAA,QACzB;AAAA,MACA;AAAA,IACA;AAKE,QAAI,OAAO,YAAY,YAAY,OAAO,OAAO,MAAM,mBAAmB;AACxE,gBAAU;AAAA,IACd;AAEE,cAAU,OAAO,OAAO;AAExB,QAAI,YAAY,MAAM;AACpB,gBAAU,CAAA;AAAA,IACd;AAEE,QAAI,WAAW,2BAA2B;AACxC,UAAI,MAAM,QAAQ,SAAS,GAAG;AAC5B,iBAAS,QAAQ,GAAG,WAAW,UAAU,QAAQ,QAAQ,UAAU,SAAS,GAAG;AAC7E,wBAAc,OAAO,SAAS,UAAU,KAAK,GAAG,eAAe;AAAA,QACvE;AAAA,MACA,OAAW;AACL,sBAAc,OAAO,SAAS,WAAW,eAAe;AAAA,MAC9D;AAAA,IACA,OAAS;AACL,UAAI,CAAC,MAAM,QACP,CAAC,gBAAgB,KAAK,iBAAiB,OAAO,KAC9C,gBAAgB,KAAK,SAAS,OAAO,GAAG;AAC1C,cAAM,OAAO,aAAa,MAAM;AAChC,cAAM,YAAY,kBAAkB,MAAM;AAC1C,cAAM,WAAW,YAAY,MAAM;AACnC,mBAAW,OAAO,wBAAwB;AAAA,MAChD;AAEI,kBAAY,SAAS,SAAS,SAAS;AACvC,aAAO,gBAAgB,OAAO;AAAA,IAClC;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,cAAe,OAAO;AAC7B,UAAM,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAEhD,QAAI,OAAO,IAAc;AACvB,YAAM;AAAA,IACV,WAAa,OAAO,IAAc;AAC9B,YAAM;AACN,UAAI,MAAM,MAAM,WAAW,MAAM,QAAQ,MAAM,IAAc;AAC3D,cAAM;AAAA,MACZ;AAAA,IACA,OAAS;AACL,iBAAW,OAAO,0BAA0B;AAAA,IAChD;AAEE,UAAM,QAAQ;AACd,UAAM,YAAY,MAAM;AACxB,UAAM,iBAAiB;AAAA,EACzB;AAEA,WAAS,oBAAqB,OAAO,eAAe,aAAa;AAC/D,QAAI,aAAa;AACjB,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,WAAO,OAAO,GAAG;AACf,aAAO,aAAa,EAAE,GAAG;AACvB,YAAI,OAAO,KAAiB,MAAM,mBAAmB,IAAI;AACvD,gBAAM,iBAAiB,MAAM;AAAA,QACrC;AACM,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,MAClD;AAEI,UAAI,iBAAiB,OAAO,IAAa;AACvC,WAAG;AACD,eAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,QACpD,SAAe,OAAO,MAAgB,OAAO,MAAgB,OAAO;AAAA,MACpE;AAEI,UAAI,MAAM,EAAE,GAAG;AACb,sBAAc,KAAK;AAEnB,aAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAC1C;AACA,cAAM,aAAa;AAEnB,eAAO,OAAO,IAAiB;AAC7B,gBAAM;AACN,eAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,QACpD;AAAA,MACA,OAAW;AACL;AAAA,MACN;AAAA,IACA;AAEE,QAAI,gBAAgB,MAAM,eAAe,KAAK,MAAM,aAAa,aAAa;AAC5E,mBAAa,OAAO,uBAAuB;AAAA,IAC/C;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,sBAAuB,OAAO;AACrC,QAAI,YAAY,MAAM;AACtB,QAAI,KAAK,MAAM,MAAM,WAAW,SAAS;AAIzC,SAAK,OAAO,MAAe,OAAO,OAC9B,OAAO,MAAM,MAAM,WAAW,YAAY,CAAC,KAC3C,OAAO,MAAM,MAAM,WAAW,YAAY,CAAC,GAAG;AAChD,mBAAa;AAEb,WAAK,MAAM,MAAM,WAAW,SAAS;AAErC,UAAI,OAAO,KAAK,UAAU,EAAE,GAAG;AAC7B,eAAO;AAAA,MACb;AAAA,IACA;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,iBAAkB,OAAO,OAAO;AACvC,QAAI,UAAU,GAAG;AACf,YAAM,UAAU;AAAA,IACpB,WAAa,QAAQ,GAAG;AACpB,YAAM,UAAUA,QAAO,OAAO,MAAM,QAAQ,CAAC;AAAA,IACjD;AAAA,EACA;AAEA,WAAS,gBAAiB,OAAO,YAAY,sBAAsB;AACjE,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,UAAM,QAAQ,MAAM;AACpB,UAAM,UAAU,MAAM;AAEtB,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,QAAI,UAAU,EAAE,KACZ,gBAAgB,EAAE,KAClB,OAAO,MACP,OAAO,MACP,OAAO,MACP,OAAO,MACP,OAAO,OACP,OAAO,MACP,OAAO,MACP,OAAO,MACP,OAAO,MACP,OAAO,MACP,OAAO,IAAa;AACtB,aAAO;AAAA,IACX;AAEE,QAAI,OAAO,MAAe,OAAO,IAAa;AAC5C,YAAM,YAAY,MAAM,MAAM,WAAW,MAAM,WAAW,CAAC;AAE3D,UAAI,UAAU,SAAS,KAClB,wBAAwB,gBAAgB,SAAS,GAAI;AACxD,eAAO;AAAA,MACb;AAAA,IACA;AAEE,UAAM,OAAO;AACb,UAAM,SAAS;AACf,mBAAe,aAAa,MAAM;AAClC,wBAAoB;AAEpB,WAAO,OAAO,GAAG;AACf,UAAI,OAAO,IAAa;AACtB,cAAM,YAAY,MAAM,MAAM,WAAW,MAAM,WAAW,CAAC;AAE3D,YAAI,UAAU,SAAS,KAClB,wBAAwB,gBAAgB,SAAS,GAAI;AACxD;AAAA,QACR;AAAA,MACA,WAAe,OAAO,IAAa;AAC7B,cAAM,YAAY,MAAM,MAAM,WAAW,MAAM,WAAW,CAAC;AAE3D,YAAI,UAAU,SAAS,GAAG;AACxB;AAAA,QACR;AAAA,MACA,WAAgB,MAAM,aAAa,MAAM,aAAa,sBAAsB,KAAK,KACjE,wBAAwB,gBAAgB,EAAE,GAAI;AACxD;AAAA,MACN,WAAe,MAAM,EAAE,GAAG;AACpB,gBAAQ,MAAM;AACd,qBAAa,MAAM;AACnB,sBAAc,MAAM;AACpB,4BAAoB,OAAO,OAAO,EAAE;AAEpC,YAAI,MAAM,cAAc,YAAY;AAClC,8BAAoB;AACpB,eAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAC1C;AAAA,QACR,OAAa;AACL,gBAAM,WAAW;AACjB,gBAAM,OAAO;AACb,gBAAM,YAAY;AAClB,gBAAM,aAAa;AACnB;AAAA,QACR;AAAA,MACA;AAEI,UAAI,mBAAmB;AACrB,uBAAe,OAAO,cAAc,YAAY,KAAK;AACrD,yBAAiB,OAAO,MAAM,OAAO,KAAK;AAC1C,uBAAe,aAAa,MAAM;AAClC,4BAAoB;AAAA,MAC1B;AAEI,UAAI,CAAC,aAAa,EAAE,GAAG;AACrB,qBAAa,MAAM,WAAW;AAAA,MACpC;AAEI,WAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,IAChD;AAEE,mBAAe,OAAO,cAAc,YAAY,KAAK;AAErD,QAAI,MAAM,QAAQ;AAChB,aAAO;AAAA,IACX;AAEE,UAAM,OAAO;AACb,UAAM,SAAS;AACf,WAAO;AAAA,EACT;AAEA,WAAS,uBAAwB,OAAO,YAAY;AAClD,QAAI;AACJ,QAAI;AAEJ,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,QAAI,OAAO,IAAa;AACtB,aAAO;AAAA,IACX;AAEE,UAAM,OAAO;AACb,UAAM,SAAS;AACf,UAAM;AACN,mBAAe,aAAa,MAAM;AAElC,YAAQ,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ,OAAO,GAAG;AAC1D,UAAI,OAAO,IAAa;AACtB,uBAAe,OAAO,cAAc,MAAM,UAAU,IAAI;AACxD,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAE5C,YAAI,OAAO,IAAa;AACtB,yBAAe,MAAM;AACrB,gBAAM;AACN,uBAAa,MAAM;AAAA,QAC3B,OAAa;AACL,iBAAO;AAAA,QACf;AAAA,MACA,WAAe,MAAM,EAAE,GAAG;AACpB,uBAAe,OAAO,cAAc,YAAY,IAAI;AACpD,yBAAiB,OAAO,oBAAoB,OAAO,OAAO,UAAU,CAAC;AACrE,uBAAe,aAAa,MAAM;AAAA,MACxC,WAAe,MAAM,aAAa,MAAM,aAAa,sBAAsB,KAAK,GAAG;AAC7E,mBAAW,OAAO,8DAA8D;AAAA,MACtF,OAAW;AACL,cAAM;AACN,YAAI,CAAC,aAAa,EAAE,GAAG;AACrB,uBAAa,MAAM;AAAA,QAC3B;AAAA,MACA;AAAA,IACA;AAEE,eAAW,OAAO,4DAA4D;AAAA,EAChF;AAEA,WAAS,uBAAwB,OAAO,YAAY;AAClD,QAAI;AACJ,QAAI;AACJ,QAAI;AAEJ,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,QAAI,OAAO,IAAa;AACtB,aAAO;AAAA,IACX;AAEE,UAAM,OAAO;AACb,UAAM,SAAS;AACf,UAAM;AACN,mBAAe,aAAa,MAAM;AAElC,YAAQ,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ,OAAO,GAAG;AAC1D,UAAI,OAAO,IAAa;AACtB,uBAAe,OAAO,cAAc,MAAM,UAAU,IAAI;AACxD,cAAM;AACN,eAAO;AAAA,MACb,WAAe,OAAO,IAAa;AAC7B,uBAAe,OAAO,cAAc,MAAM,UAAU,IAAI;AACxD,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAE5C,YAAI,MAAM,EAAE,GAAG;AACb,8BAAoB,OAAO,OAAO,UAAU;AAAA,QAGpD,WAAiB,KAAK,OAAO,kBAAkB,EAAE,GAAG;AAC5C,gBAAM,UAAU,gBAAgB,EAAE;AAClC,gBAAM;AAAA,QACd,YAAkB,MAAM,cAAc,EAAE,KAAK,GAAG;AACxC,cAAI,YAAY;AAChB,cAAI,YAAY;AAEhB,iBAAO,YAAY,GAAG,aAAa;AACjC,iBAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAE5C,iBAAK,MAAM,YAAY,EAAE,MAAM,GAAG;AAChC,2BAAa,aAAa,KAAK;AAAA,YAC3C,OAAiB;AACL,yBAAW,OAAO,gCAAgC;AAAA,YAC9D;AAAA,UACA;AAEQ,gBAAM,UAAU,kBAAkB,SAAS;AAE3C,gBAAM;AAAA,QACd,OAAa;AACL,qBAAW,OAAO,yBAAyB;AAAA,QACnD;AAEM,uBAAe,aAAa,MAAM;AAAA,MACxC,WAAe,MAAM,EAAE,GAAG;AACpB,uBAAe,OAAO,cAAc,YAAY,IAAI;AACpD,yBAAiB,OAAO,oBAAoB,OAAO,OAAO,UAAU,CAAC;AACrE,uBAAe,aAAa,MAAM;AAAA,MACxC,WAAe,MAAM,aAAa,MAAM,aAAa,sBAAsB,KAAK,GAAG;AAC7E,mBAAW,OAAO,8DAA8D;AAAA,MACtF,OAAW;AACL,cAAM;AACN,YAAI,CAAC,aAAa,EAAE,GAAG;AACrB,uBAAa,MAAM;AAAA,QAC3B;AAAA,MACA;AAAA,IACA;AAEE,eAAW,OAAO,4DAA4D;AAAA,EAChF;AAEA,WAAS,mBAAoB,OAAO,YAAY;AAC9C,QAAI,WAAW;AACf,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,UAAM,OAAO,MAAM;AACnB,QAAI;AACJ,UAAM,UAAU,MAAM;AACtB,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,UAAM,kBAAkB,uBAAO,OAAO,IAAI;AAC1C,QAAI;AACJ,QAAI;AACJ,QAAI;AAEJ,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,QAAI,OAAO,IAAa;AACtB,mBAAa;AACb,kBAAY;AACZ,gBAAU,CAAA;AAAA,IACd,WAAa,OAAO,KAAa;AAC7B,mBAAa;AACb,kBAAY;AACZ,gBAAU,CAAA;AAAA,IACd,OAAS;AACL,aAAO;AAAA,IACX;AAEE,QAAI,MAAM,WAAW,MAAM;AACzB,kBAAY,OAAO,MAAM,QAAQ,OAAO;AAAA,IAC5C;AAEE,SAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAE5C,WAAO,OAAO,GAAG;AACf,0BAAoB,OAAO,MAAM,UAAU;AAE3C,WAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE1C,UAAI,OAAO,YAAY;AACrB,cAAM;AACN,cAAM,MAAM;AACZ,cAAM,SAAS;AACf,cAAM,OAAO,YAAY,YAAY;AACrC,cAAM,SAAS;AACf,eAAO;AAAA,MACb,WAAe,CAAC,UAAU;AACpB,mBAAW,OAAO,8CAA8C;AAAA,MACtE,WAAe,OAAO,IAAa;AAE7B,mBAAW,OAAO,0CAA0C;AAAA,MAClE;AAEI,eAAS,UAAU,YAAY;AAC/B,eAAS,iBAAiB;AAE1B,UAAI,OAAO,IAAa;AACtB,cAAM,YAAY,MAAM,MAAM,WAAW,MAAM,WAAW,CAAC;AAE3D,YAAI,UAAU,SAAS,GAAG;AACxB,mBAAS,iBAAiB;AAC1B,gBAAM;AACN,8BAAoB,OAAO,MAAM,UAAU;AAAA,QACnD;AAAA,MACA;AAEI,cAAQ,MAAM;AACd,mBAAa,MAAM;AACnB,aAAO,MAAM;AACb,kBAAY,OAAO,YAAY,iBAAiB,OAAO,IAAI;AAC3D,eAAS,MAAM;AACf,gBAAU,MAAM;AAChB,0BAAoB,OAAO,MAAM,UAAU;AAE3C,WAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE1C,WAAK,kBAAkB,MAAM,SAAS,UAAU,OAAO,IAAa;AAClE,iBAAS;AACT,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAC5C,4BAAoB,OAAO,MAAM,UAAU;AAC3C,oBAAY,OAAO,YAAY,iBAAiB,OAAO,IAAI;AAC3D,oBAAY,MAAM;AAAA,MACxB;AAEI,UAAI,WAAW;AACb,yBAAiB,OAAO,SAAS,iBAAiB,QAAQ,SAAS,WAAW,OAAO,YAAY,IAAI;AAAA,MAC3G,WAAe,QAAQ;AACjB,gBAAQ,KAAK,iBAAiB,OAAO,MAAM,iBAAiB,QAAQ,SAAS,WAAW,OAAO,YAAY,IAAI,CAAC;AAAA,MACtH,OAAW;AACL,gBAAQ,KAAK,OAAO;AAAA,MAC1B;AAEI,0BAAoB,OAAO,MAAM,UAAU;AAE3C,WAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE1C,UAAI,OAAO,IAAa;AACtB,mBAAW;AACX,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,MAClD,OAAW;AACL,mBAAW;AAAA,MACjB;AAAA,IACA;AAEE,eAAW,OAAO,uDAAuD;AAAA,EAC3E;AAEA,WAAS,gBAAiB,OAAO,YAAY;AAC3C,QAAI;AACJ,QAAI,WAAW;AACf,QAAI,iBAAiB;AACrB,QAAI,iBAAiB;AACrB,QAAI,aAAa;AACjB,QAAI,aAAa;AACjB,QAAI,iBAAiB;AACrB,QAAI;AAEJ,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,QAAI,OAAO,KAAa;AACtB,gBAAU;AAAA,IACd,WAAa,OAAO,IAAa;AAC7B,gBAAU;AAAA,IACd,OAAS;AACL,aAAO;AAAA,IACX;AAEE,UAAM,OAAO;AACb,UAAM,SAAS;AAEf,WAAO,OAAO,GAAG;AACf,WAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAE5C,UAAI,OAAO,MAAe,OAAO,IAAa;AAC5C,YAAI,kBAAkB,UAAU;AAC9B,qBAAY,OAAO,KAAe,gBAAgB;AAAA,QAC1D,OAAa;AACL,qBAAW,OAAO,sCAAsC;AAAA,QAChE;AAAA,MACA,YAAgB,MAAM,gBAAgB,EAAE,MAAM,GAAG;AAC3C,YAAI,QAAQ,GAAG;AACb,qBAAW,OAAO,8EAA8E;AAAA,QACxG,WAAiB,CAAC,gBAAgB;AAC1B,uBAAa,aAAa,MAAM;AAChC,2BAAiB;AAAA,QACzB,OAAa;AACL,qBAAW,OAAO,2CAA2C;AAAA,QACrE;AAAA,MACA,OAAW;AACL;AAAA,MACN;AAAA,IACA;AAEE,QAAI,aAAa,EAAE,GAAG;AACpB,SAAG;AAAE,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,MAAC,SAC3C,aAAa,EAAE;AAEtB,UAAI,OAAO,IAAa;AACtB,WAAG;AAAE,eAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,QAAC,SAC3C,CAAC,MAAM,EAAE,KAAM,OAAO;AAAA,MACnC;AAAA,IACA;AAEE,WAAO,OAAO,GAAG;AACf,oBAAc,KAAK;AACnB,YAAM,aAAa;AAEnB,WAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAG1C,cAAQ,CAAC,kBAAkB,MAAM,aAAa,eACtC,OAAO,IAAkB;AAC/B,cAAM;AACN,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,MAClD;AAEI,UAAI,CAAC,kBAAkB,MAAM,aAAa,YAAY;AACpD,qBAAa,MAAM;AAAA,MACzB;AAEI,UAAI,MAAM,EAAE,GAAG;AACb;AACA;AAAA,MACN;AAEI,UAAI,CAAC,kBAAkB,eAAe,GAAG;AACvC,mBAAW,OAAO,sCAAsC;AAAA,MAC9D;AAGI,UAAI,MAAM,aAAa,YAAY;AAEjC,YAAI,aAAa,eAAe;AAC9B,gBAAM,UAAUA,QAAO,OAAO,MAAM,iBAAiB,IAAI,aAAa,UAAU;AAAA,QACxF,WAAiB,aAAa,eAAe;AACrC,cAAI,gBAAgB;AAClB,kBAAM,UAAU;AAAA,UAC1B;AAAA,QACA;AAGM;AAAA,MACN;AAGI,UAAI,SAAS;AAEX,YAAI,aAAa,EAAE,GAAG;AACpB,2BAAiB;AAEjB,gBAAM,UAAUA,QAAO,OAAO,MAAM,iBAAiB,IAAI,aAAa,UAAU;AAAA,QAGxF,WAAiB,gBAAgB;AACzB,2BAAiB;AACjB,gBAAM,UAAUA,QAAO,OAAO,MAAM,aAAa,CAAC;AAAA,QAG1D,WAAiB,eAAe,GAAG;AAC3B,cAAI,gBAAgB;AAClB,kBAAM,UAAU;AAAA,UAC1B;AAAA,QAGA,OAAa;AACL,gBAAM,UAAUA,QAAO,OAAO,MAAM,UAAU;AAAA,QACtD;AAAA,MAGA,OAAW;AAEL,cAAM,UAAUA,QAAO,OAAO,MAAM,iBAAiB,IAAI,aAAa,UAAU;AAAA,MACtF;AAEI,uBAAiB;AACjB,uBAAiB;AACjB,mBAAa;AACb,YAAM,eAAe,MAAM;AAE3B,aAAO,CAAC,MAAM,EAAE,KAAM,OAAO,GAAI;AAC/B,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,MAClD;AAEI,qBAAe,OAAO,cAAc,MAAM,UAAU,KAAK;AAAA,IAC7D;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,kBAAmB,OAAO,YAAY;AAC7C,UAAM,OAAO,MAAM;AACnB,UAAM,UAAU,MAAM;AACtB,UAAM,UAAU,CAAA;AAChB,QAAI,WAAW;AAIf,QAAI,MAAM,mBAAmB,GAAI,QAAO;AAExC,QAAI,MAAM,WAAW,MAAM;AACzB,kBAAY,OAAO,MAAM,QAAQ,OAAO;AAAA,IAC5C;AAEE,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,WAAO,OAAO,GAAG;AACf,UAAI,MAAM,mBAAmB,IAAI;AAC/B,cAAM,WAAW,MAAM;AACvB,mBAAW,OAAO,gDAAgD;AAAA,MACxE;AAEI,UAAI,OAAO,IAAa;AACtB;AAAA,MACN;AAEI,YAAM,YAAY,MAAM,MAAM,WAAW,MAAM,WAAW,CAAC;AAE3D,UAAI,CAAC,UAAU,SAAS,GAAG;AACzB;AAAA,MACN;AAEI,iBAAW;AACX,YAAM;AAEN,UAAI,oBAAoB,OAAO,MAAM,EAAE,GAAG;AACxC,YAAI,MAAM,cAAc,YAAY;AAClC,kBAAQ,KAAK,IAAI;AACjB,eAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAC1C;AAAA,QACR;AAAA,MACA;AAEI,YAAM,QAAQ,MAAM;AACpB,kBAAY,OAAO,YAAY,kBAAkB,OAAO,IAAI;AAC5D,cAAQ,KAAK,MAAM,MAAM;AACzB,0BAAoB,OAAO,MAAM,EAAE;AAEnC,WAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE1C,WAAK,MAAM,SAAS,SAAS,MAAM,aAAa,eAAgB,OAAO,GAAI;AACzE,mBAAW,OAAO,qCAAqC;AAAA,MAC7D,WAAe,MAAM,aAAa,YAAY;AACxC;AAAA,MACN;AAAA,IACA;AAEE,QAAI,UAAU;AACZ,YAAM,MAAM;AACZ,YAAM,SAAS;AACf,YAAM,OAAO;AACb,YAAM,SAAS;AACf,aAAO;AAAA,IACX;AACE,WAAO;AAAA,EACT;AAEA,WAAS,iBAAkB,OAAO,YAAY,YAAY;AACxD,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,UAAM,OAAO,MAAM;AACnB,UAAM,UAAU,MAAM;AACtB,UAAM,UAAU,CAAA;AAChB,UAAM,kBAAkB,uBAAO,OAAO,IAAI;AAC1C,QAAI,SAAS;AACb,QAAI,UAAU;AACd,QAAI,YAAY;AAChB,QAAI,gBAAgB;AACpB,QAAI,WAAW;AAIf,QAAI,MAAM,mBAAmB,GAAI,QAAO;AAExC,QAAI,MAAM,WAAW,MAAM;AACzB,kBAAY,OAAO,MAAM,QAAQ,OAAO;AAAA,IAC5C;AAEE,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,WAAO,OAAO,GAAG;AACf,UAAI,CAAC,iBAAiB,MAAM,mBAAmB,IAAI;AACjD,cAAM,WAAW,MAAM;AACvB,mBAAW,OAAO,gDAAgD;AAAA,MACxE;AAEI,YAAM,YAAY,MAAM,MAAM,WAAW,MAAM,WAAW,CAAC;AAC3D,YAAM,QAAQ,MAAM;AAMpB,WAAK,OAAO,MAAe,OAAO,OAAgB,UAAU,SAAS,GAAG;AACtE,YAAI,OAAO,IAAa;AACtB,cAAI,eAAe;AACjB,6BAAiB,OAAO,SAAS,iBAAiB,QAAQ,SAAS,MAAM,UAAU,eAAe,OAAO;AACzG,qBAAS,UAAU,YAAY;AAAA,UACzC;AAEQ,qBAAW;AACX,0BAAgB;AAChB,yBAAe;AAAA,QACvB,WAAiB,eAAe;AAExB,0BAAgB;AAChB,yBAAe;AAAA,QACvB,OAAa;AACL,qBAAW,OAAO,mGAAmG;AAAA,QAC7H;AAEM,cAAM,YAAY;AAClB,aAAK;AAAA,MAKX,OAAW;AACL,mBAAW,MAAM;AACjB,wBAAgB,MAAM;AACtB,kBAAU,MAAM;AAEhB,YAAI,CAAC,YAAY,OAAO,YAAY,kBAAkB,OAAO,IAAI,GAAG;AAGlE;AAAA,QACR;AAEM,YAAI,MAAM,SAAS,OAAO;AACxB,eAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE1C,iBAAO,aAAa,EAAE,GAAG;AACvB,iBAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,UACtD;AAEQ,cAAI,OAAO,IAAa;AACtB,iBAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAE5C,gBAAI,CAAC,UAAU,EAAE,GAAG;AAClB,yBAAW,OAAO,yFAAyF;AAAA,YACvH;AAEU,gBAAI,eAAe;AACjB,+BAAiB,OAAO,SAAS,iBAAiB,QAAQ,SAAS,MAAM,UAAU,eAAe,OAAO;AACzG,uBAAS,UAAU,YAAY;AAAA,YAC3C;AAEU,uBAAW;AACX,4BAAgB;AAChB,2BAAe;AACf,qBAAS,MAAM;AACf,sBAAU,MAAM;AAAA,UAC1B,WAAmB,UAAU;AACnB,uBAAW,OAAO,0DAA0D;AAAA,UACtF,OAAe;AACL,kBAAM,MAAM;AACZ,kBAAM,SAAS;AACf,mBAAO;AAAA,UACjB;AAAA,QACA,WAAiB,UAAU;AACnB,qBAAW,OAAO,gFAAgF;AAAA,QAC1G,OAAa;AACL,gBAAM,MAAM;AACZ,gBAAM,SAAS;AACf,iBAAO;AAAA,QACf;AAAA,MACA;AAKI,UAAI,MAAM,SAAS,SAAS,MAAM,aAAa,YAAY;AACzD,YAAI,eAAe;AACjB,qBAAW,MAAM;AACjB,0BAAgB,MAAM;AACtB,oBAAU,MAAM;AAAA,QACxB;AAEM,YAAI,YAAY,OAAO,YAAY,mBAAmB,MAAM,YAAY,GAAG;AACzE,cAAI,eAAe;AACjB,sBAAU,MAAM;AAAA,UAC1B,OAAe;AACL,wBAAY,MAAM;AAAA,UAC5B;AAAA,QACA;AAEM,YAAI,CAAC,eAAe;AAClB,2BAAiB,OAAO,SAAS,iBAAiB,QAAQ,SAAS,WAAW,UAAU,eAAe,OAAO;AAC9G,mBAAS,UAAU,YAAY;AAAA,QACvC;AAEM,4BAAoB,OAAO,MAAM,EAAE;AACnC,aAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAAA,MAChD;AAEI,WAAK,MAAM,SAAS,SAAS,MAAM,aAAa,eAAgB,OAAO,GAAI;AACzE,mBAAW,OAAO,oCAAoC;AAAA,MAC5D,WAAe,MAAM,aAAa,YAAY;AACxC;AAAA,MACN;AAAA,IACA;AAOE,QAAI,eAAe;AACjB,uBAAiB,OAAO,SAAS,iBAAiB,QAAQ,SAAS,MAAM,UAAU,eAAe,OAAO;AAAA,IAC7G;AAGE,QAAI,UAAU;AACZ,YAAM,MAAM;AACZ,YAAM,SAAS;AACf,YAAM,OAAO;AACb,YAAM,SAAS;AAAA,IACnB;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,gBAAiB,OAAO;AAC/B,QAAI,aAAa;AACjB,QAAI,UAAU;AACd,QAAI;AACJ,QAAI;AAEJ,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,QAAI,OAAO,GAAa,QAAO;AAE/B,QAAI,MAAM,QAAQ,MAAM;AACtB,iBAAW,OAAO,+BAA+B;AAAA,IACrD;AAEE,SAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAE5C,QAAI,OAAO,IAAa;AACtB,mBAAa;AACb,WAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,IAChD,WAAa,OAAO,IAAa;AAC7B,gBAAU;AACV,kBAAY;AACZ,WAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,IAChD,OAAS;AACL,kBAAY;AAAA,IAChB;AAEE,QAAI,YAAY,MAAM;AAEtB,QAAI,YAAY;AACd,SAAG;AAAE,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,MAAC,SAC3C,OAAO,KAAK,OAAO;AAE1B,UAAI,MAAM,WAAW,MAAM,QAAQ;AACjC,kBAAU,MAAM,MAAM,MAAM,WAAW,MAAM,QAAQ;AACrD,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,MAClD,OAAW;AACL,mBAAW,OAAO,oDAAoD;AAAA,MAC5E;AAAA,IACA,OAAS;AACL,aAAO,OAAO,KAAK,CAAC,UAAU,EAAE,GAAG;AACjC,YAAI,OAAO,IAAa;AACtB,cAAI,CAAC,SAAS;AACZ,wBAAY,MAAM,MAAM,MAAM,YAAY,GAAG,MAAM,WAAW,CAAC;AAE/D,gBAAI,CAAC,mBAAmB,KAAK,SAAS,GAAG;AACvC,yBAAW,OAAO,iDAAiD;AAAA,YAC/E;AAEU,sBAAU;AACV,wBAAY,MAAM,WAAW;AAAA,UACvC,OAAe;AACL,uBAAW,OAAO,6CAA6C;AAAA,UACzE;AAAA,QACA;AAEM,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,MAClD;AAEI,gBAAU,MAAM,MAAM,MAAM,WAAW,MAAM,QAAQ;AAErD,UAAI,wBAAwB,KAAK,OAAO,GAAG;AACzC,mBAAW,OAAO,qDAAqD;AAAA,MAC7E;AAAA,IACA;AAEE,QAAI,WAAW,CAAC,gBAAgB,KAAK,OAAO,GAAG;AAC7C,iBAAW,OAAO,8CAA8C,OAAO;AAAA,IAC3E;AAEE,QAAI;AACF,gBAAU,mBAAmB,OAAO;AAAA,IACxC,SAAW,KAAK;AACZ,iBAAW,OAAO,4BAA4B,OAAO;AAAA,IACzD;AAEE,QAAI,YAAY;AACd,YAAM,MAAM;AAAA,IAChB,WAAa,gBAAgB,KAAK,MAAM,QAAQ,SAAS,GAAG;AACxD,YAAM,MAAM,MAAM,OAAO,SAAS,IAAI;AAAA,IAC1C,WAAa,cAAc,KAAK;AAC5B,YAAM,MAAM,MAAM;AAAA,IACtB,WAAa,cAAc,MAAM;AAC7B,YAAM,MAAM,uBAAuB;AAAA,IACvC,OAAS;AACL,iBAAW,OAAO,4BAA4B,YAAY,GAAG;AAAA,IACjE;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,mBAAoB,OAAO;AAClC,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,QAAI,OAAO,GAAa,QAAO;AAE/B,QAAI,MAAM,WAAW,MAAM;AACzB,iBAAW,OAAO,mCAAmC;AAAA,IACzD;AAEE,SAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAC5C,UAAM,YAAY,MAAM;AAExB,WAAO,OAAO,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,gBAAgB,EAAE,GAAG;AACzD,WAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,IAChD;AAEE,QAAI,MAAM,aAAa,WAAW;AAChC,iBAAW,OAAO,4DAA4D;AAAA,IAClF;AAEE,UAAM,SAAS,MAAM,MAAM,MAAM,WAAW,MAAM,QAAQ;AAC1D,WAAO;AAAA,EACT;AAEA,WAAS,UAAW,OAAO;AACzB,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE9C,QAAI,OAAO,GAAa,QAAO;AAE/B,SAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAC5C,UAAM,YAAY,MAAM;AAExB,WAAO,OAAO,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,gBAAgB,EAAE,GAAG;AACzD,WAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,IAChD;AAEE,QAAI,MAAM,aAAa,WAAW;AAChC,iBAAW,OAAO,2DAA2D;AAAA,IACjF;AAEE,UAAM,QAAQ,MAAM,MAAM,MAAM,WAAW,MAAM,QAAQ;AAEzD,QAAI,CAAC,gBAAgB,KAAK,MAAM,WAAW,KAAK,GAAG;AACjD,iBAAW,OAAO,yBAAyB,QAAQ,GAAG;AAAA,IAC1D;AAEE,UAAM,SAAS,MAAM,UAAU,KAAK;AACpC,wBAAoB,OAAO,MAAM,EAAE;AACnC,WAAO;AAAA,EACT;AAEA,WAAS,gCAAiC,OAAO,eAAe,YAAY,YAAY;AACtF,UAAM,gBAAgB,cAAc,KAAK;AAEzC,2BAAuB,KAAK;AAC5B,iBAAa,OAAO,aAAa;AAIjC,UAAM,MAAM;AACZ,UAAM,SAAS;AACf,UAAM,OAAO;AACb,UAAM,SAAS;AAEf,QAAI,iBAAiB,OAAO,YAAY,UAAU,KAAK,MAAM,SAAS,WAAW;AAC/E,8BAAwB,KAAK;AAC7B,aAAO;AAAA,IACX;AAEE,8BAA0B,KAAK;AAC/B,iBAAa,OAAO,aAAa;AACjC,WAAO;AAAA,EACT;AAEA,WAAS,YAAa,OAAO,cAAc,aAAa,aAAa,cAAc;AACjF,QAAI;AACJ,QAAI;AACJ,QAAI,eAAe;AACnB,QAAI,YAAY;AAChB,QAAI,aAAa;AACjB,QAAI,gBAAgB;AACpB,QAAIO;AACJ,QAAI;AACJ,QAAI;AAEJ,QAAI,MAAM,SAAS,MAAM,UAAU;AACjC,iBAAW,OAAO,gCAAgC,MAAM,WAAW,GAAG;AAAA,IAC1E;AAEE,UAAM,SAAS;AAEf,QAAI,MAAM,aAAa,MAAM;AAC3B,YAAM,SAAS,QAAQ,KAAK;AAAA,IAChC;AAEE,UAAM,MAAM;AACZ,UAAM,SAAS;AACf,UAAM,OAAO;AACb,UAAM,SAAS;AAEf,UAAM,mBAAmB,oBAAoB,wBAC3C,sBAAsB,eACtB,qBAAqB;AAEvB,QAAI,aAAa;AACf,UAAI,oBAAoB,OAAO,MAAM,EAAE,GAAG;AACxC,oBAAY;AAEZ,YAAI,MAAM,aAAa,cAAc;AACnC,yBAAe;AAAA,QACvB,WAAiB,MAAM,eAAe,cAAc;AAC5C,yBAAe;AAAA,QACvB,WAAiB,MAAM,aAAa,cAAc;AAC1C,yBAAe;AAAA,QACvB;AAAA,MACA;AAAA,IACA;AAEE,QAAI,iBAAiB,GAAG;AACtB,aAAO,MAAM;AACX,cAAM,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAChD,cAAM,gBAAgB,cAAc,KAAK;AAIzC,YAAI,cACE,OAAO,MAAe,MAAM,QAAQ,QACpC,OAAO,MAAe,MAAM,WAAW,OAAQ;AACnD;AAAA,QACR;AAEM,YAAI,CAAC,gBAAgB,KAAK,KAAK,CAAC,mBAAmB,KAAK,GAAG;AACzD;AAAA,QACR;AAEM,YAAI,kBAAkB,MAAM;AAC1B,0BAAgB;AAAA,QACxB;AAEM,YAAI,oBAAoB,OAAO,MAAM,EAAE,GAAG;AACxC,sBAAY;AACZ,kCAAwB;AAExB,cAAI,MAAM,aAAa,cAAc;AACnC,2BAAe;AAAA,UACzB,WAAmB,MAAM,eAAe,cAAc;AAC5C,2BAAe;AAAA,UACzB,WAAmB,MAAM,aAAa,cAAc;AAC1C,2BAAe;AAAA,UACzB;AAAA,QACA,OAAa;AACL,kCAAwB;AAAA,QAChC;AAAA,MACA;AAAA,IACA;AAEE,QAAI,uBAAuB;AACzB,8BAAwB,aAAa;AAAA,IACzC;AAEE,QAAI,iBAAiB,KAAK,sBAAsB,aAAa;AAC3D,UAAI,oBAAoB,eAAe,qBAAqB,aAAa;AACvE,qBAAa;AAAA,MACnB,OAAW;AACL,qBAAa,eAAe;AAAA,MAClC;AAEI,oBAAc,MAAM,WAAW,MAAM;AAErC,UAAI,iBAAiB,GAAG;AACtB,YAAK,0BACA,kBAAkB,OAAO,WAAW,KAAK,iBAAiB,OAAO,aAAa,UAAU,MACzF,mBAAmB,OAAO,UAAU,GAAG;AACzC,uBAAa;AAAA,QACrB,OAAa;AACL,gBAAM,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAEhD,cAAI,kBAAkB,QAAQ,oBAAoB,CAAC,yBAC/C,OAAO,OAAe,OAAO,MAC7B;AAAA,YACE;AAAA,YACA;AAAA,YACA,cAAc,WAAW,cAAc;AAAA,YACvC;AAAA,UACd,GAAe;AACL,yBAAa;AAAA,UACvB,WAAoB,qBAAqB,gBAAgB,OAAO,UAAU,KAC9D,uBAAuB,OAAO,UAAU,KACxC,uBAAuB,OAAO,UAAU,GAAG;AAC7C,yBAAa;AAAA,UACvB,WAAmB,UAAU,KAAK,GAAG;AAC3B,yBAAa;AAEb,gBAAI,MAAM,QAAQ,QAAQ,MAAM,WAAW,MAAM;AAC/C,yBAAW,OAAO,2CAA2C;AAAA,YACzE;AAAA,UACA,WAAmB,gBAAgB,OAAO,YAAY,oBAAoB,WAAW,GAAG;AAC9E,yBAAa;AAEb,gBAAI,MAAM,QAAQ,MAAM;AACtB,oBAAM,MAAM;AAAA,YACxB;AAAA,UACA;AAEQ,cAAI,MAAM,WAAW,MAAM;AACzB,wBAAY,OAAO,MAAM,QAAQ,MAAM,MAAM;AAAA,UACvD;AAAA,QACA;AAAA,MACA,WAAe,iBAAiB,GAAG;AAG7B,qBAAa,yBAAyB,kBAAkB,OAAO,WAAW;AAAA,MAChF;AAAA,IACA;AAEE,QAAI,MAAM,QAAQ,MAAM;AACtB,UAAI,MAAM,WAAW,MAAM;AACzB,oBAAY,OAAO,MAAM,QAAQ,MAAM,MAAM;AAAA,MACnD;AAAA,IACA,WAAa,MAAM,QAAQ,KAAK;AAO5B,UAAI,MAAM,WAAW,QAAQ,MAAM,SAAS,UAAU;AACpD,mBAAW,OAAO,sEAAsE,MAAM,OAAO,GAAG;AAAA,MAC9G;AAEI,eAAS,YAAY,GAAG,eAAe,MAAM,cAAc,QAAQ,YAAY,cAAc,aAAa,GAAG;AAC3G,QAAAA,QAAO,MAAM,cAAc,SAAS;AAEpC,YAAIA,MAAK,QAAQ,MAAM,MAAM,GAAG;AAC9B,gBAAM,SAASA,MAAK,UAAU,MAAM,MAAM;AAC1C,gBAAM,MAAMA,MAAK;AACjB,cAAI,MAAM,WAAW,MAAM;AACzB,wBAAY,OAAO,MAAM,QAAQ,MAAM,MAAM;AAAA,UACvD;AACQ;AAAA,QACR;AAAA,MACA;AAAA,IACA,WAAa,MAAM,QAAQ,KAAK;AAC5B,UAAI,gBAAgB,KAAK,MAAM,QAAQ,MAAM,QAAQ,UAAU,GAAG,MAAM,GAAG,GAAG;AAC5E,QAAAA,QAAO,MAAM,QAAQ,MAAM,QAAQ,UAAU,EAAE,MAAM,GAAG;AAAA,MAC9D,OAAW;AAEL,QAAAA,QAAO;AACP,cAAM,WAAW,MAAM,QAAQ,MAAM,MAAM,QAAQ,UAAU;AAE7D,iBAAS,YAAY,GAAG,eAAe,SAAS,QAAQ,YAAY,cAAc,aAAa,GAAG;AAChG,cAAI,MAAM,IAAI,MAAM,GAAG,SAAS,SAAS,EAAE,IAAI,MAAM,MAAM,SAAS,SAAS,EAAE,KAAK;AAClF,YAAAA,QAAO,SAAS,SAAS;AACzB;AAAA,UACV;AAAA,QACA;AAAA,MACA;AAEI,UAAI,CAACA,OAAM;AACT,mBAAW,OAAO,mBAAmB,MAAM,MAAM,GAAG;AAAA,MAC1D;AAEI,UAAI,MAAM,WAAW,QAAQA,MAAK,SAAS,MAAM,MAAM;AACrD,mBAAW,OAAO,kCAAkC,MAAM,MAAM,0BAA0BA,MAAK,OAAO,aAAa,MAAM,OAAO,GAAG;AAAA,MACzI;AAEI,UAAI,CAACA,MAAK,QAAQ,MAAM,QAAQ,MAAM,GAAG,GAAG;AAC1C,mBAAW,OAAO,kCAAkC,MAAM,MAAM,gBAAgB;AAAA,MACtF,OAAW;AACL,cAAM,SAASA,MAAK,UAAU,MAAM,QAAQ,MAAM,GAAG;AACrD,YAAI,MAAM,WAAW,MAAM;AACzB,sBAAY,OAAO,MAAM,QAAQ,MAAM,MAAM;AAAA,QACrD;AAAA,MACA;AAAA,IACA;AAEE,QAAI,MAAM,aAAa,MAAM;AAC3B,YAAM,SAAS,SAAS,KAAK;AAAA,IACjC;AAEE,UAAM,SAAS;AACf,WAAO,MAAM,QAAQ,QAAQ,MAAM,WAAW,QAAQ;AAAA,EACxD;AAEA,WAAS,aAAc,OAAO;AAC5B,UAAM,gBAAgB,MAAM;AAC5B,QAAI,gBAAgB;AACpB,QAAI;AAEJ,UAAM,UAAU;AAChB,UAAM,kBAAkB,MAAM;AAC9B,UAAM,SAAS,uBAAO,OAAO,IAAI;AACjC,UAAM,YAAY,uBAAO,OAAO,IAAI;AAEpC,YAAQ,KAAK,MAAM,MAAM,WAAW,MAAM,QAAQ,OAAO,GAAG;AAC1D,0BAAoB,OAAO,MAAM,EAAE;AAEnC,WAAK,MAAM,MAAM,WAAW,MAAM,QAAQ;AAE1C,UAAI,MAAM,aAAa,KAAK,OAAO,IAAa;AAC9C;AAAA,MACN;AAEI,sBAAgB;AAChB,WAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAC5C,UAAI,YAAY,MAAM;AAEtB,aAAO,OAAO,KAAK,CAAC,UAAU,EAAE,GAAG;AACjC,aAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,MAClD;AAEI,YAAM,gBAAgB,MAAM,MAAM,MAAM,WAAW,MAAM,QAAQ;AACjE,YAAM,gBAAgB,CAAA;AAEtB,UAAI,cAAc,SAAS,GAAG;AAC5B,mBAAW,OAAO,8DAA8D;AAAA,MACtF;AAEI,aAAO,OAAO,GAAG;AACf,eAAO,aAAa,EAAE,GAAG;AACvB,eAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,QACpD;AAEM,YAAI,OAAO,IAAa;AACtB,aAAG;AAAE,iBAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,UAAC,SAC3C,OAAO,KAAK,CAAC,MAAM,EAAE;AAC5B;AAAA,QACR;AAEM,YAAI,MAAM,EAAE,EAAG;AAEf,oBAAY,MAAM;AAElB,eAAO,OAAO,KAAK,CAAC,UAAU,EAAE,GAAG;AACjC,eAAK,MAAM,MAAM,WAAW,EAAE,MAAM,QAAQ;AAAA,QACpD;AAEM,sBAAc,KAAK,MAAM,MAAM,MAAM,WAAW,MAAM,QAAQ,CAAC;AAAA,MACrE;AAEI,UAAI,OAAO,EAAG,eAAc,KAAK;AAEjC,UAAI,gBAAgB,KAAK,mBAAmB,aAAa,GAAG;AAC1D,0BAAkB,aAAa,EAAE,OAAO,eAAe,aAAa;AAAA,MAC1E,OAAW;AACL,qBAAa,OAAO,iCAAiC,gBAAgB,GAAG;AAAA,MAC9E;AAAA,IACA;AAEE,wBAAoB,OAAO,MAAM,EAAE;AAEnC,QAAI,MAAM,eAAe,KACrB,MAAM,MAAM,WAAW,MAAM,QAAQ,MAAM,MAC3C,MAAM,MAAM,WAAW,MAAM,WAAW,CAAC,MAAM,MAC/C,MAAM,MAAM,WAAW,MAAM,WAAW,CAAC,MAAM,IAAa;AAC9D,YAAM,YAAY;AAClB,0BAAoB,OAAO,MAAM,EAAE;AAAA,IACvC,WAAa,eAAe;AACxB,iBAAW,OAAO,iCAAiC;AAAA,IACvD;AAEE,gBAAY,OAAO,MAAM,aAAa,GAAG,mBAAmB,OAAO,IAAI;AACvE,wBAAoB,OAAO,MAAM,EAAE;AAEnC,QAAI,MAAM,mBACN,8BAA8B,KAAK,MAAM,MAAM,MAAM,eAAe,MAAM,QAAQ,CAAC,GAAG;AACxF,mBAAa,OAAO,kDAAkD;AAAA,IAC1E;AAEE,UAAM,UAAU,KAAK,MAAM,MAAM;AAEjC,QAAI,MAAM,aAAa,MAAM,aAAa,sBAAsB,KAAK,GAAG;AACtE,UAAI,MAAM,MAAM,WAAW,MAAM,QAAQ,MAAM,IAAa;AAC1D,cAAM,YAAY;AAClB,4BAAoB,OAAO,MAAM,EAAE;AAAA,MACzC;AACI;AAAA,IACJ;AAEE,QAAI,MAAM,WAAY,MAAM,SAAS,GAAI;AACvC,iBAAW,OAAO,uDAAuD;AAAA,IAC7E;AAAA,EACA;AAEA,WAAS,cAAe,OAAO,SAAS;AACtC,YAAQ,OAAO,KAAK;AACpB,cAAU,WAAW,CAAA;AAErB,QAAI,MAAM,WAAW,GAAG;AAEtB,UAAI,MAAM,WAAW,MAAM,SAAS,CAAC,MAAM,MACvC,MAAM,WAAW,MAAM,SAAS,CAAC,MAAM,IAAc;AACvD,iBAAS;AAAA,MACf;AAGI,UAAI,MAAM,WAAW,CAAC,MAAM,OAAQ;AAClC,gBAAQ,MAAM,MAAM,CAAC;AAAA,MAC3B;AAAA,IACA;AAEE,UAAM,QAAQ,IAAI,MAAM,OAAO,OAAO;AAEtC,UAAM,UAAU,MAAM,QAAQ,IAAI;AAElC,QAAI,YAAY,IAAI;AAClB,YAAM,WAAW;AACjB,iBAAW,OAAO,mCAAmC;AAAA,IACzD;AAGE,UAAM,SAAS;AAEf,WAAO,MAAM,MAAM,WAAW,MAAM,QAAQ,MAAM,IAAiB;AACjE,YAAM,cAAc;AACpB,YAAM,YAAY;AAAA,IACtB;AAEE,WAAO,MAAM,WAAY,MAAM,SAAS,GAAI;AAC1C,mBAAa,KAAK;AAAA,IACtB;AAEE,WAAO,MAAM;AAAA,EACf;AAEA,WAASQ,SAAS,OAAO,UAAU,SAAS;AAC1C,QAAI,aAAa,QAAQ,OAAO,aAAa,YAAY,OAAO,YAAY,aAAa;AACvF,gBAAU;AACV,iBAAW;AAAA,IACf;AAEE,UAAM,YAAY,cAAc,OAAO,OAAO;AAE9C,QAAI,OAAO,aAAa,YAAY;AAClC,aAAO;AAAA,IACX;AAEE,aAAS,QAAQ,GAAG,SAAS,UAAU,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACzE,eAAS,UAAU,KAAK,CAAC;AAAA,IAC7B;AAAA,EACA;AAEA,WAASC,MAAM,OAAO,SAAS;AAC7B,UAAM,YAAY,cAAc,OAAO,OAAO;AAE9C,QAAI,UAAU,WAAW,GAAG;AAC1B,aAAO;AAAA,IACX,WAAa,UAAU,WAAW,GAAG;AACjC,aAAO,UAAU,CAAC;AAAA,IACtB;AACE,UAAM,IAAIjB,eAAc,0DAA0D;AAAA,EACpF;AAEA,SAAA,UAAyBgB;AACzB,SAAA,OAAsBC;;;;;;;;AC3vDtB,QAAMhB,UAASC,cAAA;AACf,QAAMF,iBAAgBM,iBAAA;AACtB,QAAMS,kBAAiBL,gBAAA;AAEvB,QAAM,YAAY,OAAO,UAAU;AACnC,QAAM,kBAAkB,OAAO,UAAU;AAEzC,QAAM,WAAW;AACjB,QAAM,WAAW;AACjB,QAAM,iBAAiB;AACvB,QAAM,uBAAuB;AAC7B,QAAM,aAAa;AACnB,QAAM,mBAAmB;AACzB,QAAM,oBAAoB;AAC1B,QAAM,aAAa;AACnB,QAAM,eAAe;AACrB,QAAM,iBAAiB;AACvB,QAAM,oBAAoB;AAC1B,QAAM,gBAAgB;AACtB,QAAM,aAAa;AACnB,QAAM,aAAa;AACnB,QAAM,aAAa;AACnB,QAAM,cAAc;AACpB,QAAM,oBAAoB;AAC1B,QAAM,gBAAgB;AACtB,QAAM,qBAAqB;AAC3B,QAAM,2BAA2B;AACjC,QAAM,4BAA4B;AAClC,QAAM,oBAAoB;AAC1B,QAAM,0BAA0B;AAChC,QAAM,qBAAqB;AAC3B,QAAM,2BAA2B;AAEjC,QAAM,mBAAmB,CAAA;AAEzB,mBAAiB,CAAI,IAAI;AACzB,mBAAiB,CAAI,IAAI;AACzB,mBAAiB,CAAI,IAAI;AACzB,mBAAiB,CAAI,IAAI;AACzB,mBAAiB,EAAI,IAAI;AACzB,mBAAiB,EAAI,IAAI;AACzB,mBAAiB,EAAI,IAAI;AACzB,mBAAiB,EAAI,IAAI;AACzB,mBAAiB,EAAI,IAAI;AACzB,mBAAiB,EAAI,IAAI;AACzB,mBAAiB,EAAI,IAAI;AACzB,mBAAiB,GAAI,IAAI;AACzB,mBAAiB,GAAI,IAAI;AACzB,mBAAiB,IAAM,IAAI;AAC3B,mBAAiB,IAAM,IAAI;AAE3B,QAAM,6BAA6B;AAAA,IACjC;AAAA,IAAK;AAAA,IAAK;AAAA,IAAO;AAAA,IAAO;AAAA,IAAO;AAAA,IAAM;AAAA,IAAM;AAAA,IAC3C;AAAA,IAAK;AAAA,IAAK;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAAO;AAAA,IAAO;AAAA,EAC5C;AAEA,QAAM,2BAA2B;AAEjC,WAAS,gBAAiBH,SAAQH,MAAK;AACrC,QAAIA,SAAQ,KAAM,QAAO,CAAA;AAEzB,UAAM,SAAS,CAAA;AACf,UAAM,OAAO,OAAO,KAAKA,IAAG;AAE5B,aAAS,QAAQ,GAAG,SAAS,KAAK,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACpE,UAAI,MAAM,KAAK,KAAK;AACpB,UAAI,QAAQ,OAAOA,KAAI,GAAG,CAAC;AAE3B,UAAI,IAAI,MAAM,GAAG,CAAC,MAAM,MAAM;AAC5B,cAAM,uBAAuB,IAAI,MAAM,CAAC;AAAA,MAC9C;AACI,YAAMI,QAAOD,QAAO,gBAAgB,UAAU,EAAE,GAAG;AAEnD,UAAIC,SAAQ,gBAAgB,KAAKA,MAAK,cAAc,KAAK,GAAG;AAC1D,gBAAQA,MAAK,aAAa,KAAK;AAAA,MACrC;AAEI,aAAO,GAAG,IAAI;AAAA,IAClB;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,UAAW,WAAW;AAC7B,QAAI;AACJ,QAAI;AAEJ,UAAM,SAAS,UAAU,SAAS,EAAE,EAAE,YAAW;AAEjD,QAAI,aAAa,KAAM;AACrB,eAAS;AACT,eAAS;AAAA,IACb,WAAa,aAAa,OAAQ;AAC9B,eAAS;AACT,eAAS;AAAA,IACb,WAAa,aAAa,YAAY;AAClC,eAAS;AACT,eAAS;AAAA,IACb,OAAS;AACL,YAAM,IAAIR,eAAc,+DAA+D;AAAA,IAC3F;AAEE,WAAO,OAAO,SAASC,QAAO,OAAO,KAAK,SAAS,OAAO,MAAM,IAAI;AAAA,EACtE;AAEA,QAAM,sBAAsB;AAC5B,QAAM,sBAAsB;AAE5B,WAAS,MAAO,SAAS;AACvB,SAAK,SAAS,QAAQ,QAAQ,KAAKc;AACnC,SAAK,SAAS,KAAK,IAAI,GAAI,QAAQ,QAAQ,KAAK,CAAC;AACjD,SAAK,gBAAgB,QAAQ,eAAe,KAAK;AACjD,SAAK,cAAc,QAAQ,aAAa,KAAK;AAC7C,SAAK,YAAad,QAAO,UAAU,QAAQ,WAAW,CAAC,IAAI,KAAK,QAAQ,WAAW;AACnF,SAAK,WAAW,gBAAgB,KAAK,QAAQ,QAAQ,QAAQ,KAAK,IAAI;AACtE,SAAK,WAAW,QAAQ,UAAU,KAAK;AACvC,SAAK,YAAY,QAAQ,WAAW,KAAK;AACzC,SAAK,SAAS,QAAQ,QAAQ,KAAK;AACnC,SAAK,eAAe,QAAQ,cAAc,KAAK;AAC/C,SAAK,eAAe,QAAQ,cAAc,KAAK;AAC/C,SAAK,cAAc,QAAQ,aAAa,MAAM,MAAM,sBAAsB;AAC1E,SAAK,cAAc,QAAQ,aAAa,KAAK;AAC7C,SAAK,WAAW,OAAO,QAAQ,UAAU,MAAM,aAAa,QAAQ,UAAU,IAAI;AAElF,SAAK,gBAAgB,KAAK,OAAO;AACjC,SAAK,gBAAgB,KAAK,OAAO;AAEjC,SAAK,MAAM;AACX,SAAK,SAAS;AAEd,SAAK,aAAa,CAAA;AAClB,SAAK,iBAAiB;AAAA,EACxB;AAGA,WAAS,aAAc,QAAQ,QAAQ;AACrC,UAAM,MAAMA,QAAO,OAAO,KAAK,MAAM;AACrC,QAAI,WAAW;AACf,QAAI,SAAS;AACb,UAAM,SAAS,OAAO;AAEtB,WAAO,WAAW,QAAQ;AACxB,UAAI;AACJ,YAAM,OAAO,OAAO,QAAQ,MAAM,QAAQ;AAC1C,UAAI,SAAS,IAAI;AACf,eAAO,OAAO,MAAM,QAAQ;AAC5B,mBAAW;AAAA,MACjB,OAAW;AACL,eAAO,OAAO,MAAM,UAAU,OAAO,CAAC;AACtC,mBAAW,OAAO;AAAA,MACxB;AAEI,UAAI,KAAK,UAAU,SAAS,KAAM,WAAU;AAE5C,gBAAU;AAAA,IACd;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,iBAAkB,OAAO,OAAO;AACvC,WAAO,OAAOA,QAAO,OAAO,KAAK,MAAM,SAAS,KAAK;AAAA,EACvD;AAEA,WAAS,sBAAuB,OAAOiB,MAAK;AAC1C,aAAS,QAAQ,GAAG,SAAS,MAAM,cAAc,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACnF,YAAMV,QAAO,MAAM,cAAc,KAAK;AAEtC,UAAIA,MAAK,QAAQU,IAAG,GAAG;AACrB,eAAO;AAAA,MACb;AAAA,IACA;AAEE,WAAO;AAAA,EACT;AAGA,WAAS,aAAc,GAAG;AACxB,WAAO,MAAM,cAAc,MAAM;AAAA,EACnC;AAMA,WAAS,YAAa,GAAG;AACvB,WAAQ,KAAK,MAAW,KAAK,OACzB,KAAK,OAAW,KAAK,SAAa,MAAM,QAAU,MAAM,QACxD,KAAK,SAAW,KAAK,SAAa,MAAM,YACzC,KAAK,SAAW,KAAK;AAAA,EAC1B;AAOA,WAAS,qBAAsB,GAAG;AAChC,WAAO,YAAY,CAAC,KAClB,MAAM;AAAA,IAEN,MAAM,wBACN,MAAM;AAAA,EACV;AAWA,WAAS,YAAa,GAAG,MAAM,SAAS;AACtC,UAAM,wBAAwB,qBAAqB,CAAC;AACpD,UAAM,YAAY,yBAAyB,CAAC,aAAa,CAAC;AAC1D;AAAA;AAAA,OAGI,UACI,wBACA;AAAA,MAEA,MAAM,cACN,MAAM,4BACN,MAAM,6BACN,MAAM,2BACN,MAAM;AAAA,MAGZ,MAAM;AAAA,MACN,EAAE,SAAS,cAAc,CAAC;AAAA,MAE3B,qBAAqB,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,MAAM;AAAA,MAC3D,SAAS,cAAc;AAAA;AAAA,EAC1B;AAGA,WAAS,iBAAkB,GAAG;AAI5B,WAAO,YAAY,CAAC,KAClB,MAAM,YACN,CAAC,aAAa,CAAC;AAAA;AAAA;AAAA,IAGf,MAAM,cACN,MAAM,iBACN,MAAM,cACN,MAAM,cACN,MAAM,4BACN,MAAM,6BACN,MAAM,2BACN,MAAM;AAAA,IAEN,MAAM,cACN,MAAM,kBACN,MAAM,iBACN,MAAM,oBACN,MAAM,sBACN,MAAM,eACN,MAAM,qBACN,MAAM,qBACN,MAAM;AAAA,IAEN,MAAM,gBACN,MAAM,sBACN,MAAM;AAAA,EACV;AAGA,WAAS,gBAAiB,GAAG;AAE3B,WAAO,CAAC,aAAa,CAAC,KAAK,MAAM;AAAA,EACnC;AAGA,WAAS,YAAa,QAAQ,KAAK;AACjC,UAAM,QAAQ,OAAO,WAAW,GAAG;AACnC,QAAI;AAEJ,QAAI,SAAS,SAAU,SAAS,SAAU,MAAM,IAAI,OAAO,QAAQ;AACjE,eAAS,OAAO,WAAW,MAAM,CAAC;AAClC,UAAI,UAAU,SAAU,UAAU,OAAQ;AAExC,gBAAQ,QAAQ,SAAU,OAAQ,SAAS,QAAS;AAAA,MAC1D;AAAA,IACA;AACE,WAAO;AAAA,EACT;AAGA,WAAS,oBAAqB,QAAQ;AACpC,UAAM,iBAAiB;AACvB,WAAO,eAAe,KAAK,MAAM;AAAA,EACnC;AAEA,QAAM,cAAc;AACpB,QAAM,eAAe;AACrB,QAAM,gBAAgB;AACtB,QAAM,eAAe;AACrB,QAAM,eAAe;AASrB,WAAS,kBAAmB,QAAQ,gBAAgB,gBAAgB,WAClE,mBAAmB,aAAa,aAAa,SAAS;AACtD,QAAI;AACJ,QAAI,OAAO;AACX,QAAI,WAAW;AACf,QAAI,eAAe;AACnB,QAAI,kBAAkB;AACtB,UAAM,mBAAmB,cAAc;AACvC,QAAI,oBAAoB;AACxB,QAAI,QAAQ,iBAAiB,YAAY,QAAQ,CAAC,CAAC,KACjD,gBAAgB,YAAY,QAAQ,OAAO,SAAS,CAAC,CAAC;AAExD,QAAI,kBAAkB,aAAa;AAGjC,WAAK,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,QAAU,KAAK,IAAI,KAAK;AAC7D,eAAO,YAAY,QAAQ,CAAC;AAC5B,YAAI,CAAC,YAAY,IAAI,GAAG;AACtB,iBAAO;AAAA,QACf;AACM,gBAAQ,SAAS,YAAY,MAAM,UAAU,OAAO;AACpD,mBAAW;AAAA,MACjB;AAAA,IACA,OAAS;AAEL,WAAK,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,QAAU,KAAK,IAAI,KAAK;AAC7D,eAAO,YAAY,QAAQ,CAAC;AAC5B,YAAI,SAAS,gBAAgB;AAC3B,yBAAe;AAEf,cAAI,kBAAkB;AACpB,8BAAkB;AAAA,YAEf,IAAI,oBAAoB,IAAI,aAC5B,OAAO,oBAAoB,CAAC,MAAM;AACrC,gCAAoB;AAAA,UAC9B;AAAA,QACA,WAAiB,CAAC,YAAY,IAAI,GAAG;AAC7B,iBAAO;AAAA,QACf;AACM,gBAAQ,SAAS,YAAY,MAAM,UAAU,OAAO;AACpD,mBAAW;AAAA,MACjB;AAEI,wBAAkB,mBAAoB,qBACnC,IAAI,oBAAoB,IAAI,aAC5B,OAAO,oBAAoB,CAAC,MAAM;AAAA,IACzC;AAIE,QAAI,CAAC,gBAAgB,CAAC,iBAAiB;AAGrC,UAAI,SAAS,CAAC,eAAe,CAAC,kBAAkB,MAAM,GAAG;AACvD,eAAO;AAAA,MACb;AACI,aAAO,gBAAgB,sBAAsB,eAAe;AAAA,IAChE;AAEE,QAAI,iBAAiB,KAAK,oBAAoB,MAAM,GAAG;AACrD,aAAO;AAAA,IACX;AAGE,QAAI,CAAC,aAAa;AAChB,aAAO,kBAAkB,eAAe;AAAA,IAC5C;AACE,WAAO,gBAAgB,sBAAsB,eAAe;AAAA,EAC9D;AAQA,WAAS,YAAa,OAAO,QAAQ,OAAO,OAAO,SAAS;AAC1D,UAAM,QAAQ,WAAY;AACxB,UAAI,OAAO,WAAW,GAAG;AACvB,eAAO,MAAM,gBAAgB,sBAAsB,OAAO;AAAA,MAChE;AACI,UAAI,CAAC,MAAM,cAAc;AACvB,YAAI,2BAA2B,QAAQ,MAAM,MAAM,MAAM,yBAAyB,KAAK,MAAM,GAAG;AAC9F,iBAAO,MAAM,gBAAgB,sBAAuB,MAAM,SAAS,MAAQ,MAAM,SAAS;AAAA,QAClG;AAAA,MACA;AAEI,YAAM,SAAS,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK;AAQ/C,YAAM,YAAa,MAAM,cAAc,KACnC,KACA,KAAK,IAAI,KAAK,IAAI,MAAM,WAAW,EAAE,GAAG,MAAM,YAAY,MAAM;AAGpE,YAAM,iBAAiB;AAAA,MAEpB,MAAM,YAAY,MAAM,SAAS,MAAM;AAC1C,eAAS,cAAeC,SAAQ;AAC9B,eAAO,sBAAsB,OAAOA,OAAM;AAAA,MAChD;AAEI,cAAQ;AAAA,QAAkB;AAAA,QAAQ;AAAA,QAAgB,MAAM;AAAA,QAAQ;AAAA,QAC9D;AAAA,QAAe,MAAM;AAAA,QAAa,MAAM,eAAe,CAAC;AAAA,QAAO;AAAA,MAAO,GAAC;AAAA,QACvE,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO,MAAM,OAAO,QAAQ,MAAM,IAAI,IAAI;AAAA,QAC5C,KAAK;AACH,iBAAO,MAAM,YAAY,QAAQ,MAAM,MAAM,IAC3C,kBAAkB,aAAa,QAAQ,MAAM,CAAC;AAAA,QAClD,KAAK;AACH,iBAAO,MAAM,YAAY,QAAQ,MAAM,MAAM,IAC3C,kBAAkB,aAAa,WAAW,QAAQ,SAAS,GAAG,MAAM,CAAC;AAAA,QACzE,KAAK;AACH,iBAAO,MAAM,aAAa,MAAiB,IAAI;AAAA,QACjD;AACE,gBAAM,IAAInB,eAAc,wCAAwC;AAAA,MACxE;AAAA,IACA,GAAG;AAAA,EACH;AAGA,WAAS,YAAa,QAAQ,gBAAgB;AAC5C,UAAM,kBAAkB,oBAAoB,MAAM,IAAI,OAAO,cAAc,IAAI;AAG/E,UAAM,OAAO,OAAO,OAAO,SAAS,CAAC,MAAM;AAC3C,UAAM,OAAO,SAAS,OAAO,OAAO,SAAS,CAAC,MAAM,QAAQ,WAAW;AACvE,UAAM,QAAQ,OAAO,MAAO,OAAO,KAAK;AAExC,WAAO,kBAAkB,QAAQ;AAAA,EACnC;AAGA,WAAS,kBAAmB,QAAQ;AAClC,WAAO,OAAO,OAAO,SAAS,CAAC,MAAM,OAAO,OAAO,MAAM,GAAG,EAAE,IAAI;AAAA,EACpE;AAIA,WAAS,WAAY,QAAQ,OAAO;AAKlC,UAAM,SAAS;AAGf,QAAI,UAAU,WAAY;AACxB,UAAI,SAAS,OAAO,QAAQ,IAAI;AAChC,eAAS,WAAW,KAAK,SAAS,OAAO;AACzC,aAAO,YAAY;AACnB,aAAO,SAAS,OAAO,MAAM,GAAG,MAAM,GAAG,KAAK;AAAA,IAClD,GAAG;AAED,QAAI,mBAAmB,OAAO,CAAC,MAAM,QAAQ,OAAO,CAAC,MAAM;AAC3D,QAAI;AAGJ,QAAI;AACJ,WAAQ,QAAQ,OAAO,KAAK,MAAM,GAAI;AACpC,YAAM,SAAS,MAAM,CAAC;AACtB,YAAM,OAAO,MAAM,CAAC;AAEpB,qBAAgB,KAAK,CAAC,MAAM;AAC5B,gBAAU,UACN,CAAC,oBAAoB,CAAC,gBAAgB,SAAS,KAAM,OAAO,MAC9D,SAAS,MAAM,KAAK;AACtB,yBAAmB;AAAA,IACvB;AAEE,WAAO;AAAA,EACT;AAMA,WAAS,SAAU,MAAM,OAAO;AAC9B,QAAI,SAAS,MAAM,KAAK,CAAC,MAAM,IAAK,QAAO;AAG3C,UAAM,UAAU;AAChB,QAAI;AAEJ,QAAI,QAAQ;AACZ,QAAI;AACJ,QAAI,OAAO;AACX,QAAI,OAAO;AACX,QAAI,SAAS;AAMb,WAAQ,QAAQ,QAAQ,KAAK,IAAI,GAAI;AACnC,aAAO,MAAM;AAEb,UAAI,OAAO,QAAQ,OAAO;AACxB,cAAO,OAAO,QAAS,OAAO;AAC9B,kBAAU,OAAO,KAAK,MAAM,OAAO,GAAG;AAEtC,gBAAQ,MAAM;AAAA,MACpB;AACI,aAAO;AAAA,IACX;AAIE,cAAU;AAEV,QAAI,KAAK,SAAS,QAAQ,SAAS,OAAO,OAAO;AAC/C,gBAAU,KAAK,MAAM,OAAO,IAAI,IAAI,OAAO,KAAK,MAAM,OAAO,CAAC;AAAA,IAClE,OAAS;AACL,gBAAU,KAAK,MAAM,KAAK;AAAA,IAC9B;AAEE,WAAO,OAAO,MAAM,CAAC;AAAA,EACvB;AAGA,WAAS,aAAc,QAAQ;AAC7B,QAAI,SAAS;AACb,QAAI,OAAO;AAEX,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,QAAU,KAAK,IAAI,KAAK;AACjE,aAAO,YAAY,QAAQ,CAAC;AAC5B,YAAM,YAAY,iBAAiB,IAAI;AAEvC,UAAI,CAAC,aAAa,YAAY,IAAI,GAAG;AACnC,kBAAU,OAAO,CAAC;AAClB,YAAI,QAAQ,MAAS,WAAU,OAAO,IAAI,CAAC;AAAA,MACjD,OAAW;AACL,kBAAU,aAAa,UAAU,IAAI;AAAA,MAC3C;AAAA,IACA;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,kBAAmB,OAAO,OAAO,QAAQ;AAChD,QAAI,UAAU;AACd,UAAM,OAAO,MAAM;AAEnB,aAAS,QAAQ,GAAG,SAAS,OAAO,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtE,UAAI,QAAQ,OAAO,KAAK;AAExB,UAAI,MAAM,UAAU;AAClB,gBAAQ,MAAM,SAAS,KAAK,QAAQ,OAAO,KAAK,GAAG,KAAK;AAAA,MAC9D;AAGI,UAAI,UAAU,OAAO,OAAO,OAAO,OAAO,KAAK,KAC1C,OAAO,UAAU,eACjB,UAAU,OAAO,OAAO,MAAM,OAAO,KAAK,GAAI;AACjD,YAAI,YAAY,GAAI,YAAW,OAAO,CAAC,MAAM,eAAe,MAAM;AAClE,mBAAW,MAAM;AAAA,MACvB;AAAA,IACA;AAEE,UAAM,MAAM;AACZ,UAAM,OAAO,MAAM,UAAU;AAAA,EAC/B;AAEA,WAAS,mBAAoB,OAAO,OAAO,QAAQ,SAAS;AAC1D,QAAI,UAAU;AACd,UAAM,OAAO,MAAM;AAEnB,aAAS,QAAQ,GAAG,SAAS,OAAO,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtE,UAAI,QAAQ,OAAO,KAAK;AAExB,UAAI,MAAM,UAAU;AAClB,gBAAQ,MAAM,SAAS,KAAK,QAAQ,OAAO,KAAK,GAAG,KAAK;AAAA,MAC9D;AAGI,UAAI,UAAU,OAAO,QAAQ,GAAG,OAAO,MAAM,MAAM,OAAO,IAAI,KACzD,OAAO,UAAU,eACjB,UAAU,OAAO,QAAQ,GAAG,MAAM,MAAM,MAAM,OAAO,IAAI,GAAI;AAChE,YAAI,CAAC,WAAW,YAAY,IAAI;AAC9B,qBAAW,iBAAiB,OAAO,KAAK;AAAA,QAChD;AAEM,YAAI,MAAM,QAAQ,mBAAmB,MAAM,KAAK,WAAW,CAAC,GAAG;AAC7D,qBAAW;AAAA,QACnB,OAAa;AACL,qBAAW;AAAA,QACnB;AAEM,mBAAW,MAAM;AAAA,MACvB;AAAA,IACA;AAEE,UAAM,MAAM;AACZ,UAAM,OAAO,WAAW;AAAA,EAC1B;AAEA,WAAS,iBAAkB,OAAO,OAAO,QAAQ;AAC/C,QAAI,UAAU;AACd,UAAM,OAAO,MAAM;AACnB,UAAM,gBAAgB,OAAO,KAAK,MAAM;AAExC,aAAS,QAAQ,GAAG,SAAS,cAAc,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AAC7E,UAAI,aAAa;AACjB,UAAI,YAAY,GAAI,eAAc;AAElC,UAAI,MAAM,aAAc,eAAc;AAEtC,YAAM,YAAY,cAAc,KAAK;AACrC,UAAI,cAAc,OAAO,SAAS;AAElC,UAAI,MAAM,UAAU;AAClB,sBAAc,MAAM,SAAS,KAAK,QAAQ,WAAW,WAAW;AAAA,MACtE;AAEI,UAAI,CAAC,UAAU,OAAO,OAAO,WAAW,OAAO,KAAK,GAAG;AACrD;AAAA,MACN;AAEI,UAAI,MAAM,KAAK,SAAS,KAAM,eAAc;AAE5C,oBAAc,MAAM,QAAQ,MAAM,eAAe,MAAM,MAAM,OAAO,MAAM,eAAe,KAAK;AAE9F,UAAI,CAAC,UAAU,OAAO,OAAO,aAAa,OAAO,KAAK,GAAG;AACvD;AAAA,MACN;AAEI,oBAAc,MAAM;AAGpB,iBAAW;AAAA,IACf;AAEE,UAAM,MAAM;AACZ,UAAM,OAAO,MAAM,UAAU;AAAA,EAC/B;AAEA,WAAS,kBAAmB,OAAO,OAAO,QAAQ,SAAS;AACzD,QAAI,UAAU;AACd,UAAM,OAAO,MAAM;AACnB,UAAM,gBAAgB,OAAO,KAAK,MAAM;AAGxC,QAAI,MAAM,aAAa,MAAM;AAE3B,oBAAc,KAAI;AAAA,IACtB,WAAa,OAAO,MAAM,aAAa,YAAY;AAE/C,oBAAc,KAAK,MAAM,QAAQ;AAAA,IACrC,WAAa,MAAM,UAAU;AAEzB,YAAM,IAAIA,eAAc,0CAA0C;AAAA,IACtE;AAEE,aAAS,QAAQ,GAAG,SAAS,cAAc,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AAC7E,UAAI,aAAa;AAEjB,UAAI,CAAC,WAAW,YAAY,IAAI;AAC9B,sBAAc,iBAAiB,OAAO,KAAK;AAAA,MACjD;AAEI,YAAM,YAAY,cAAc,KAAK;AACrC,UAAI,cAAc,OAAO,SAAS;AAElC,UAAI,MAAM,UAAU;AAClB,sBAAc,MAAM,SAAS,KAAK,QAAQ,WAAW,WAAW;AAAA,MACtE;AAEI,UAAI,CAAC,UAAU,OAAO,QAAQ,GAAG,WAAW,MAAM,MAAM,IAAI,GAAG;AAC7D;AAAA,MACN;AAEI,YAAM,eAAgB,MAAM,QAAQ,QAAQ,MAAM,QAAQ,OAC1C,MAAM,QAAQ,MAAM,KAAK,SAAS;AAElD,UAAI,cAAc;AAChB,YAAI,MAAM,QAAQ,mBAAmB,MAAM,KAAK,WAAW,CAAC,GAAG;AAC7D,wBAAc;AAAA,QACtB,OAAa;AACL,wBAAc;AAAA,QACtB;AAAA,MACA;AAEI,oBAAc,MAAM;AAEpB,UAAI,cAAc;AAChB,sBAAc,iBAAiB,OAAO,KAAK;AAAA,MACjD;AAEI,UAAI,CAAC,UAAU,OAAO,QAAQ,GAAG,aAAa,MAAM,YAAY,GAAG;AACjE;AAAA,MACN;AAEI,UAAI,MAAM,QAAQ,mBAAmB,MAAM,KAAK,WAAW,CAAC,GAAG;AAC7D,sBAAc;AAAA,MACpB,OAAW;AACL,sBAAc;AAAA,MACpB;AAEI,oBAAc,MAAM;AAGpB,iBAAW;AAAA,IACf;AAEE,UAAM,MAAM;AACZ,UAAM,OAAO,WAAW;AAAA,EAC1B;AAEA,WAAS,WAAY,OAAO,QAAQ,UAAU;AAC5C,UAAM,WAAW,WAAW,MAAM,gBAAgB,MAAM;AAExD,aAAS,QAAQ,GAAG,SAAS,SAAS,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACxE,YAAMQ,QAAO,SAAS,KAAK;AAE3B,WAAKA,MAAK,cAAcA,MAAK,eACxB,CAACA,MAAK,cAAgB,OAAO,WAAW,YAAc,kBAAkBA,MAAK,gBAC7E,CAACA,MAAK,aAAaA,MAAK,UAAU,MAAM,IAAI;AAC/C,YAAI,UAAU;AACZ,cAAIA,MAAK,SAASA,MAAK,eAAe;AACpC,kBAAM,MAAMA,MAAK,cAAc,MAAM;AAAA,UAC/C,OAAe;AACL,kBAAM,MAAMA,MAAK;AAAA,UAC3B;AAAA,QACA,OAAa;AACL,gBAAM,MAAM;AAAA,QACpB;AAEM,YAAIA,MAAK,WAAW;AAClB,gBAAM,QAAQ,MAAM,SAASA,MAAK,GAAG,KAAKA,MAAK;AAE/C,cAAI;AACJ,cAAI,UAAU,KAAKA,MAAK,SAAS,MAAM,qBAAqB;AAC1D,sBAAUA,MAAK,UAAU,QAAQ,KAAK;AAAA,UAChD,WAAmB,gBAAgB,KAAKA,MAAK,WAAW,KAAK,GAAG;AACtD,sBAAUA,MAAK,UAAU,KAAK,EAAE,QAAQ,KAAK;AAAA,UACvD,OAAe;AACL,kBAAM,IAAIR,eAAc,OAAOQ,MAAK,MAAM,iCAAiC,QAAQ,SAAS;AAAA,UACtG;AAEQ,gBAAM,OAAO;AAAA,QACrB;AAEM,eAAO;AAAA,MACb;AAAA,IACA;AAEE,WAAO;AAAA,EACT;AAKA,WAAS,UAAW,OAAO,OAAO,QAAQ,OAAO,SAAS,OAAO,YAAY;AAC3E,UAAM,MAAM;AACZ,UAAM,OAAO;AAEb,QAAI,CAAC,WAAW,OAAO,QAAQ,KAAK,GAAG;AACrC,iBAAW,OAAO,QAAQ,IAAI;AAAA,IAClC;AAEE,UAAMA,QAAO,UAAU,KAAK,MAAM,IAAI;AACtC,UAAM,UAAU;AAEhB,QAAI,OAAO;AACT,cAAS,MAAM,YAAY,KAAK,MAAM,YAAY;AAAA,IACtD;AAEE,UAAM,gBAAgBA,UAAS,qBAAqBA,UAAS;AAC7D,QAAI;AACJ,QAAI;AAEJ,QAAI,eAAe;AACjB,uBAAiB,MAAM,WAAW,QAAQ,MAAM;AAChD,kBAAY,mBAAmB;AAAA,IACnC;AAEE,QAAK,MAAM,QAAQ,QAAQ,MAAM,QAAQ,OAAQ,aAAc,MAAM,WAAW,KAAK,QAAQ,GAAI;AAC/F,gBAAU;AAAA,IACd;AAEE,QAAI,aAAa,MAAM,eAAe,cAAc,GAAG;AACrD,YAAM,OAAO,UAAU;AAAA,IAC3B,OAAS;AACL,UAAI,iBAAiB,aAAa,CAAC,MAAM,eAAe,cAAc,GAAG;AACvE,cAAM,eAAe,cAAc,IAAI;AAAA,MAC7C;AACI,UAAIA,UAAS,mBAAmB;AAC9B,YAAI,SAAU,OAAO,KAAK,MAAM,IAAI,EAAE,WAAW,GAAI;AACnD,4BAAkB,OAAO,OAAO,MAAM,MAAM,OAAO;AACnD,cAAI,WAAW;AACb,kBAAM,OAAO,UAAU,iBAAiB,MAAM;AAAA,UACxD;AAAA,QACA,OAAa;AACL,2BAAiB,OAAO,OAAO,MAAM,IAAI;AACzC,cAAI,WAAW;AACb,kBAAM,OAAO,UAAU,iBAAiB,MAAM,MAAM;AAAA,UAC9D;AAAA,QACA;AAAA,MACA,WAAeA,UAAS,kBAAkB;AACpC,YAAI,SAAU,MAAM,KAAK,WAAW,GAAI;AACtC,cAAI,MAAM,iBAAiB,CAAC,cAAc,QAAQ,GAAG;AACnD,+BAAmB,OAAO,QAAQ,GAAG,MAAM,MAAM,OAAO;AAAA,UAClE,OAAe;AACL,+BAAmB,OAAO,OAAO,MAAM,MAAM,OAAO;AAAA,UAC9D;AACQ,cAAI,WAAW;AACb,kBAAM,OAAO,UAAU,iBAAiB,MAAM;AAAA,UACxD;AAAA,QACA,OAAa;AACL,4BAAkB,OAAO,OAAO,MAAM,IAAI;AAC1C,cAAI,WAAW;AACb,kBAAM,OAAO,UAAU,iBAAiB,MAAM,MAAM;AAAA,UAC9D;AAAA,QACA;AAAA,MACA,WAAeA,UAAS,mBAAmB;AACrC,YAAI,MAAM,QAAQ,KAAK;AACrB,sBAAY,OAAO,MAAM,MAAM,OAAO,OAAO,OAAO;AAAA,QAC5D;AAAA,MACA,WAAeA,UAAS,sBAAsB;AACxC,eAAO;AAAA,MACb,OAAW;AACL,YAAI,MAAM,YAAa,QAAO;AAC9B,cAAM,IAAIR,eAAc,4CAA4CQ,KAAI;AAAA,MAC9E;AAEI,UAAI,MAAM,QAAQ,QAAQ,MAAM,QAAQ,KAAK;AAc3C,YAAI,SAAS;AAAA,UACX,MAAM,IAAI,CAAC,MAAM,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,MAAM;AAAA,QAC1D,EAAQ,QAAQ,MAAM,KAAK;AAErB,YAAI,MAAM,IAAI,CAAC,MAAM,KAAK;AACxB,mBAAS,MAAM;AAAA,QACvB,WAAiB,OAAO,MAAM,GAAG,EAAE,MAAM,sBAAsB;AACvD,mBAAS,OAAO,OAAO,MAAM,EAAE;AAAA,QACvC,OAAa;AACL,mBAAS,OAAO,SAAS;AAAA,QACjC;AAEM,cAAM,OAAO,SAAS,MAAM,MAAM;AAAA,MACxC;AAAA,IACA;AAEE,WAAO;AAAA,EACT;AAEA,WAAS,uBAAwB,QAAQ,OAAO;AAC9C,UAAM,UAAU,CAAA;AAChB,UAAM,oBAAoB,CAAA;AAE1B,gBAAY,QAAQ,SAAS,iBAAiB;AAE9C,UAAM,SAAS,kBAAkB;AACjC,aAAS,QAAQ,GAAG,QAAQ,QAAQ,SAAS,GAAG;AAC9C,YAAM,WAAW,KAAK,QAAQ,kBAAkB,KAAK,CAAC,CAAC;AAAA,IAC3D;AACE,UAAM,iBAAiB,IAAI,MAAM,MAAM;AAAA,EACzC;AAEA,WAAS,YAAa,QAAQ,SAAS,mBAAmB;AACxD,QAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;AACjD,YAAM,QAAQ,QAAQ,QAAQ,MAAM;AACpC,UAAI,UAAU,IAAI;AAChB,YAAI,kBAAkB,QAAQ,KAAK,MAAM,IAAI;AAC3C,4BAAkB,KAAK,KAAK;AAAA,QACpC;AAAA,MACA,OAAW;AACL,gBAAQ,KAAK,MAAM;AAEnB,YAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,mBAAS,IAAI,GAAG,SAAS,OAAO,QAAQ,IAAI,QAAQ,KAAK,GAAG;AAC1D,wBAAY,OAAO,CAAC,GAAG,SAAS,iBAAiB;AAAA,UAC3D;AAAA,QACA,OAAa;AACL,gBAAM,gBAAgB,OAAO,KAAK,MAAM;AAExC,mBAAS,IAAI,GAAG,SAAS,cAAc,QAAQ,IAAI,QAAQ,KAAK,GAAG;AACjE,wBAAY,OAAO,cAAc,CAAC,CAAC,GAAG,SAAS,iBAAiB;AAAA,UAC1E;AAAA,QACA;AAAA,MACA;AAAA,IACA;AAAA,EACA;AAEA,WAASY,MAAM,OAAO,SAAS;AAC7B,cAAU,WAAW,CAAA;AAErB,UAAM,QAAQ,IAAI,MAAM,OAAO;AAE/B,QAAI,CAAC,MAAM,OAAQ,wBAAuB,OAAO,KAAK;AAEtD,QAAI,QAAQ;AAEZ,QAAI,MAAM,UAAU;AAClB,cAAQ,MAAM,SAAS,KAAK,EAAE,IAAI,MAAK,GAAI,IAAI,KAAK;AAAA,IACxD;AAEE,QAAI,UAAU,OAAO,GAAG,OAAO,MAAM,IAAI,EAAG,QAAO,MAAM,OAAO;AAEhE,WAAO;AAAA,EACT;AAEA,SAAA,OAAsBA;;;;;;;ACt6BtB,QAAMC,UAASnB,cAAA;AACf,QAAMoB,UAAShB,cAAA;AAEf,WAAS,QAAS,MAAM,IAAI;AAC1B,WAAO,WAAY;AACjB,YAAM,IAAI,MAAM,mBAAmB,OAAO,wCAC1B,KAAK,yCAAyC;AAAA,IAClE;AAAA,EACA;AAEA,SAAA,OAAsBI,YAAA;AACtB,SAAA,SAAwBC,cAAA;AACxB,SAAA,kBAAiCC,gBAAA;AACjC,SAAA,cAA6BC,YAAA;AAC7B,SAAA,cAA6BC,YAAA;AAC7B,SAAA,iBAAgCS,gBAAA;AAChC,SAAA,OAAsBF,QAAO;AAC7B,SAAA,UAAyBA,QAAO;AAChC,SAAA,OAAsBC,QAAO;AAC7B,SAAA,gBAA+BE,iBAAA;AAG/B,SAAA,QAAuB;AAAA,IACrB,QAAQC,cAAA;AAAA,IACR,OAAOC,aAAA;AAAA,IACP,KAAKC,WAAA;AAAA,IACL,MAAMC,aAAA;AAAA,IACN,OAAOC,aAAA;AAAA,IACP,KAAKC,WAAA;AAAA,IACL,WAAWC,iBAAA;AAAA,IACX,MAAMC,YAAA;AAAA,IACN,KAAKC,WAAA;AAAA,IACL,OAAOC,aAAA;AAAA,IACP,MAAMC,YAAA;AAAA,IACN,KAAKC,WAAA;AAAA,IACL,KAAKC,WAAA;AAAA,EACP;AAGA,SAAA,WAA0B,QAAQ,YAAY,MAAM;AACpD,SAAA,cAA6B,QAAQ,eAAe,SAAS;AAC7D,SAAA,WAA0B,QAAQ,YAAY,MAAM;;;;;ACzC/C,MAAC;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,IAAI;"} \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/index.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/index.js new file mode 100644 index 0000000..0b66b8f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/index.js @@ -0,0 +1,44 @@ +'use strict' + +const loader = require('./lib/loader') +const dumper = require('./lib/dumper') + +function renamed (from, to) { + return function () { + throw new Error('Function yaml.' + from + ' is removed in js-yaml 4. ' + + 'Use yaml.' + to + ' instead, which is now safe by default.') + } +} + +module.exports.Type = require('./lib/type') +module.exports.Schema = require('./lib/schema') +module.exports.FAILSAFE_SCHEMA = require('./lib/schema/failsafe') +module.exports.JSON_SCHEMA = require('./lib/schema/json') +module.exports.CORE_SCHEMA = require('./lib/schema/core') +module.exports.DEFAULT_SCHEMA = require('./lib/schema/default') +module.exports.load = loader.load +module.exports.loadAll = loader.loadAll +module.exports.dump = dumper.dump +module.exports.YAMLException = require('./lib/exception') + +// Re-export all types in case user wants to create custom schema +module.exports.types = { + binary: require('./lib/type/binary'), + float: require('./lib/type/float'), + map: require('./lib/type/map'), + null: require('./lib/type/null'), + pairs: require('./lib/type/pairs'), + set: require('./lib/type/set'), + timestamp: require('./lib/type/timestamp'), + bool: require('./lib/type/bool'), + int: require('./lib/type/int'), + merge: require('./lib/type/merge'), + omap: require('./lib/type/omap'), + seq: require('./lib/type/seq'), + str: require('./lib/type/str') +} + +// Removed functions from JS-YAML 3.0.x +module.exports.safeLoad = renamed('safeLoad', 'load') +module.exports.safeLoadAll = renamed('safeLoadAll', 'loadAll') +module.exports.safeDump = renamed('safeDump', 'dump') diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/common.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/common.js new file mode 100644 index 0000000..d1fd4dc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/common.js @@ -0,0 +1,50 @@ +'use strict' + +function isNothing (subject) { + return (typeof subject === 'undefined') || (subject === null) +} + +function isObject (subject) { + return (typeof subject === 'object') && (subject !== null) +} + +function toArray (sequence) { + if (Array.isArray(sequence)) return sequence + else if (isNothing(sequence)) return [] + + return [sequence] +} + +function extend (target, source) { + if (source) { + const sourceKeys = Object.keys(source) + + for (let index = 0, length = sourceKeys.length; index < length; index += 1) { + const key = sourceKeys[index] + target[key] = source[key] + } + } + + return target +} + +function repeat (string, count) { + let result = '' + + for (let cycle = 0; cycle < count; cycle += 1) { + result += string + } + + return result +} + +function isNegativeZero (number) { + return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number) +} + +module.exports.isNothing = isNothing +module.exports.isObject = isObject +module.exports.toArray = toArray +module.exports.repeat = repeat +module.exports.isNegativeZero = isNegativeZero +module.exports.extend = extend diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/dumper.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/dumper.js new file mode 100644 index 0000000..a5b6acd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/dumper.js @@ -0,0 +1,937 @@ +'use strict' + +const common = require('./common') +const YAMLException = require('./exception') +const DEFAULT_SCHEMA = require('./schema/default') + +const _toString = Object.prototype.toString +const _hasOwnProperty = Object.prototype.hasOwnProperty + +const CHAR_BOM = 0xFEFF +const CHAR_TAB = 0x09 /* Tab */ +const CHAR_LINE_FEED = 0x0A /* LF */ +const CHAR_CARRIAGE_RETURN = 0x0D /* CR */ +const CHAR_SPACE = 0x20 /* Space */ +const CHAR_EXCLAMATION = 0x21 /* ! */ +const CHAR_DOUBLE_QUOTE = 0x22 /* " */ +const CHAR_SHARP = 0x23 /* # */ +const CHAR_PERCENT = 0x25 /* % */ +const CHAR_AMPERSAND = 0x26 /* & */ +const CHAR_SINGLE_QUOTE = 0x27 /* ' */ +const CHAR_ASTERISK = 0x2A /* * */ +const CHAR_COMMA = 0x2C /* , */ +const CHAR_MINUS = 0x2D /* - */ +const CHAR_COLON = 0x3A /* : */ +const CHAR_EQUALS = 0x3D /* = */ +const CHAR_GREATER_THAN = 0x3E /* > */ +const CHAR_QUESTION = 0x3F /* ? */ +const CHAR_COMMERCIAL_AT = 0x40 /* @ */ +const CHAR_LEFT_SQUARE_BRACKET = 0x5B /* [ */ +const CHAR_RIGHT_SQUARE_BRACKET = 0x5D /* ] */ +const CHAR_GRAVE_ACCENT = 0x60 /* ` */ +const CHAR_LEFT_CURLY_BRACKET = 0x7B /* { */ +const CHAR_VERTICAL_LINE = 0x7C /* | */ +const CHAR_RIGHT_CURLY_BRACKET = 0x7D /* } */ + +const ESCAPE_SEQUENCES = {} + +ESCAPE_SEQUENCES[0x00] = '\\0' +ESCAPE_SEQUENCES[0x07] = '\\a' +ESCAPE_SEQUENCES[0x08] = '\\b' +ESCAPE_SEQUENCES[0x09] = '\\t' +ESCAPE_SEQUENCES[0x0A] = '\\n' +ESCAPE_SEQUENCES[0x0B] = '\\v' +ESCAPE_SEQUENCES[0x0C] = '\\f' +ESCAPE_SEQUENCES[0x0D] = '\\r' +ESCAPE_SEQUENCES[0x1B] = '\\e' +ESCAPE_SEQUENCES[0x22] = '\\"' +ESCAPE_SEQUENCES[0x5C] = '\\\\' +ESCAPE_SEQUENCES[0x85] = '\\N' +ESCAPE_SEQUENCES[0xA0] = '\\_' +ESCAPE_SEQUENCES[0x2028] = '\\L' +ESCAPE_SEQUENCES[0x2029] = '\\P' + +const DEPRECATED_BOOLEANS_SYNTAX = [ + 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', + 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' +] + +const DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/ + +function compileStyleMap (schema, map) { + if (map === null) return {} + + const result = {} + const keys = Object.keys(map) + + for (let index = 0, length = keys.length; index < length; index += 1) { + let tag = keys[index] + let style = String(map[tag]) + + if (tag.slice(0, 2) === '!!') { + tag = 'tag:yaml.org,2002:' + tag.slice(2) + } + const type = schema.compiledTypeMap['fallback'][tag] + + if (type && _hasOwnProperty.call(type.styleAliases, style)) { + style = type.styleAliases[style] + } + + result[tag] = style + } + + return result +} + +function encodeHex (character) { + let handle + let length + + const string = character.toString(16).toUpperCase() + + if (character <= 0xFF) { + handle = 'x' + length = 2 + } else if (character <= 0xFFFF) { + handle = 'u' + length = 4 + } else if (character <= 0xFFFFFFFF) { + handle = 'U' + length = 8 + } else { + throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF') + } + + return '\\' + handle + common.repeat('0', length - string.length) + string +} + +const QUOTING_TYPE_SINGLE = 1 +const QUOTING_TYPE_DOUBLE = 2 + +function State (options) { + this.schema = options['schema'] || DEFAULT_SCHEMA + this.indent = Math.max(1, (options['indent'] || 2)) + this.noArrayIndent = options['noArrayIndent'] || false + this.skipInvalid = options['skipInvalid'] || false + this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']) + this.styleMap = compileStyleMap(this.schema, options['styles'] || null) + this.sortKeys = options['sortKeys'] || false + this.lineWidth = options['lineWidth'] || 80 + this.noRefs = options['noRefs'] || false + this.noCompatMode = options['noCompatMode'] || false + this.condenseFlow = options['condenseFlow'] || false + this.quotingType = options['quotingType'] === '"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE + this.forceQuotes = options['forceQuotes'] || false + this.replacer = typeof options['replacer'] === 'function' ? options['replacer'] : null + + this.implicitTypes = this.schema.compiledImplicit + this.explicitTypes = this.schema.compiledExplicit + + this.tag = null + this.result = '' + + this.duplicates = [] + this.usedDuplicates = null +} + +// Indents every line in a string. Empty lines (\n only) are not indented. +function indentString (string, spaces) { + const ind = common.repeat(' ', spaces) + let position = 0 + let result = '' + const length = string.length + + while (position < length) { + let line + const next = string.indexOf('\n', position) + if (next === -1) { + line = string.slice(position) + position = length + } else { + line = string.slice(position, next + 1) + position = next + 1 + } + + if (line.length && line !== '\n') result += ind + + result += line + } + + return result +} + +function generateNextLine (state, level) { + return '\n' + common.repeat(' ', state.indent * level) +} + +function testImplicitResolving (state, str) { + for (let index = 0, length = state.implicitTypes.length; index < length; index += 1) { + const type = state.implicitTypes[index] + + if (type.resolve(str)) { + return true + } + } + + return false +} + +// [33] s-white ::= s-space | s-tab +function isWhitespace (c) { + return c === CHAR_SPACE || c === CHAR_TAB +} + +// Returns true if the character can be printed without escaping. +// From YAML 1.2: "any allowed characters known to be non-printable +// should also be escaped. [However,] This isn’t mandatory" +// Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. +function isPrintable (c) { + return (c >= 0x00020 && c <= 0x00007E) || + ((c >= 0x000A1 && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) || + ((c >= 0x0E000 && c <= 0x00FFFD) && c !== CHAR_BOM) || + (c >= 0x10000 && c <= 0x10FFFF) +} + +// [34] ns-char ::= nb-char - s-white +// [27] nb-char ::= c-printable - b-char - c-byte-order-mark +// [26] b-char ::= b-line-feed | b-carriage-return +// Including s-white (for some reason, examples doesn't match specs in this aspect) +// ns-char ::= c-printable - b-line-feed - b-carriage-return - c-byte-order-mark +function isNsCharOrWhitespace (c) { + return isPrintable(c) && + c !== CHAR_BOM && + // - b-char + c !== CHAR_CARRIAGE_RETURN && + c !== CHAR_LINE_FEED +} + +// [127] ns-plain-safe(c) ::= c = flow-out ⇒ ns-plain-safe-out +// c = flow-in ⇒ ns-plain-safe-in +// c = block-key ⇒ ns-plain-safe-out +// c = flow-key ⇒ ns-plain-safe-in +// [128] ns-plain-safe-out ::= ns-char +// [129] ns-plain-safe-in ::= ns-char - c-flow-indicator +// [130] ns-plain-char(c) ::= ( ns-plain-safe(c) - “:” - “#” ) +// | ( /* An ns-char preceding */ “#” ) +// | ( “:” /* Followed by an ns-plain-safe(c) */ ) +function isPlainSafe (c, prev, inblock) { + const cIsNsCharOrWhitespace = isNsCharOrWhitespace(c) + const cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c) + return ( + ( + // ns-plain-safe + inblock // c = flow-in + ? cIsNsCharOrWhitespace + : cIsNsCharOrWhitespace && + // - c-flow-indicator + c !== CHAR_COMMA && + c !== CHAR_LEFT_SQUARE_BRACKET && + c !== CHAR_RIGHT_SQUARE_BRACKET && + c !== CHAR_LEFT_CURLY_BRACKET && + c !== CHAR_RIGHT_CURLY_BRACKET + ) && + // ns-plain-char + c !== CHAR_SHARP && // false on '#' + !(prev === CHAR_COLON && !cIsNsChar) + ) || // false on ': ' + (isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP) || // change to true on '[^ ]#' + (prev === CHAR_COLON && cIsNsChar) // change to true on ':[^ ]' +} + +// Simplified test for values allowed as the first character in plain style. +function isPlainSafeFirst (c) { + // Uses a subset of ns-char - c-indicator + // where ns-char = nb-char - s-white. + // No support of ( ( “?” | “:” | “-” ) /* Followed by an ns-plain-safe(c)) */ ) part + return isPrintable(c) && + c !== CHAR_BOM && + !isWhitespace(c) && // - s-white + // - (c-indicator ::= + // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” + c !== CHAR_MINUS && + c !== CHAR_QUESTION && + c !== CHAR_COLON && + c !== CHAR_COMMA && + c !== CHAR_LEFT_SQUARE_BRACKET && + c !== CHAR_RIGHT_SQUARE_BRACKET && + c !== CHAR_LEFT_CURLY_BRACKET && + c !== CHAR_RIGHT_CURLY_BRACKET && + // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “"” + c !== CHAR_SHARP && + c !== CHAR_AMPERSAND && + c !== CHAR_ASTERISK && + c !== CHAR_EXCLAMATION && + c !== CHAR_VERTICAL_LINE && + c !== CHAR_EQUALS && + c !== CHAR_GREATER_THAN && + c !== CHAR_SINGLE_QUOTE && + c !== CHAR_DOUBLE_QUOTE && + // | “%” | “@” | “`”) + c !== CHAR_PERCENT && + c !== CHAR_COMMERCIAL_AT && + c !== CHAR_GRAVE_ACCENT +} + +// Simplified test for values allowed as the last character in plain style. +function isPlainSafeLast (c) { + // just not whitespace or colon, it will be checked to be plain character later + return !isWhitespace(c) && c !== CHAR_COLON +} + +// Same as 'string'.codePointAt(pos), but works in older browsers. +function codePointAt (string, pos) { + const first = string.charCodeAt(pos) + let second + + if (first >= 0xD800 && first <= 0xDBFF && pos + 1 < string.length) { + second = string.charCodeAt(pos + 1) + if (second >= 0xDC00 && second <= 0xDFFF) { + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000 + } + } + return first +} + +// Determines whether block indentation indicator is required. +function needIndentIndicator (string) { + const leadingSpaceRe = /^\n* / + return leadingSpaceRe.test(string) +} + +const STYLE_PLAIN = 1 +const STYLE_SINGLE = 2 +const STYLE_LITERAL = 3 +const STYLE_FOLDED = 4 +const STYLE_DOUBLE = 5 + +// Determines which scalar styles are possible and returns the preferred style. +// lineWidth = -1 => no limit. +// Pre-conditions: str.length > 0. +// Post-conditions: +// STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. +// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). +// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). +function chooseScalarStyle (string, singleLineOnly, indentPerLevel, lineWidth, + testAmbiguousType, quotingType, forceQuotes, inblock) { + let i + let char = 0 + let prevChar = null + let hasLineBreak = false + let hasFoldableLine = false // only checked if shouldTrackWidth + const shouldTrackWidth = lineWidth !== -1 + let previousLineBreak = -1 // count the first line correctly + let plain = isPlainSafeFirst(codePointAt(string, 0)) && + isPlainSafeLast(codePointAt(string, string.length - 1)) + + if (singleLineOnly || forceQuotes) { + // Case: no block styles. + // Check for disallowed characters to rule out plain and single. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i) + if (!isPrintable(char)) { + return STYLE_DOUBLE + } + plain = plain && isPlainSafe(char, prevChar, inblock) + prevChar = char + } + } else { + // Case: block styles permitted. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i) + if (char === CHAR_LINE_FEED) { + hasLineBreak = true + // Check if any line can be folded. + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || + // Foldable line = too long, and not more-indented. + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' ') + previousLineBreak = i + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE + } + plain = plain && isPlainSafe(char, prevChar, inblock) + prevChar = char + } + // in case the end is missing a \n + hasFoldableLine = hasFoldableLine || (shouldTrackWidth && + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' ')) + } + // Although every style can represent \n without escaping, prefer block styles + // for multiline, since they're more readable and they don't add empty lines. + // Also prefer folding a super-long line. + if (!hasLineBreak && !hasFoldableLine) { + // Strings interpretable as another type have to be quoted; + // e.g. the string 'true' vs. the boolean true. + if (plain && !forceQuotes && !testAmbiguousType(string)) { + return STYLE_PLAIN + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE + } + // Edge case: block indentation indicator can only have one digit. + if (indentPerLevel > 9 && needIndentIndicator(string)) { + return STYLE_DOUBLE + } + // At this point we know block styles are valid. + // Prefer literal style unless we want to fold. + if (!forceQuotes) { + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE +} + +// Note: line breaking/folding is implemented for only the folded style. +// NB. We drop the last trailing newline (if any) of a returned block scalar +// since the dumper adds its own newline. This always works: +// • No ending newline => unaffected; already using strip "-" chomping. +// • Ending newline => removed then restored. +// Importantly, this keeps the "+" chomp indicator from gaining an extra line. +function writeScalar (state, string, level, iskey, inblock) { + state.dump = (function () { + if (string.length === 0) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? '""' : "''" + } + if (!state.noCompatMode) { + if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? ('"' + string + '"') : ("'" + string + "'") + } + } + + const indent = state.indent * Math.max(1, level) // no 0-indent scalars + // As indentation gets deeper, let the width decrease monotonically + // to the lower bound min(state.lineWidth, 40). + // Note that this implies + // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. + // state.lineWidth > 40 + state.indent: width decreases until the lower bound. + // This behaves better than a constant minimum width which disallows narrower options, + // or an indent threshold which causes the width to suddenly increase. + const lineWidth = (state.lineWidth === -1) + ? -1 + : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent) + + // Without knowing if keys are implicit/explicit, assume implicit for safety. + const singleLineOnly = iskey || + // No block styles in flow mode. + (state.flowLevel > -1 && level >= state.flowLevel) + function testAmbiguity (string) { + return testImplicitResolving(state, string) + } + + switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, + testAmbiguity, state.quotingType, state.forceQuotes && !iskey, inblock)) { + case STYLE_PLAIN: + return string + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'" + case STYLE_LITERAL: + return '|' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(string, indent)) + case STYLE_FOLDED: + return '>' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(foldString(string, lineWidth), indent)) + case STYLE_DOUBLE: + return '"' + escapeString(string, lineWidth) + '"' + default: + throw new YAMLException('impossible error: invalid scalar style') + } + }()) +} + +// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. +function blockHeader (string, indentPerLevel) { + const indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : '' + + // note the special case: the string '\n' counts as a "trailing" empty line. + const clip = string[string.length - 1] === '\n' + const keep = clip && (string[string.length - 2] === '\n' || string === '\n') + const chomp = keep ? '+' : (clip ? '' : '-') + + return indentIndicator + chomp + '\n' +} + +// (See the note for writeScalar.) +function dropEndingNewline (string) { + return string[string.length - 1] === '\n' ? string.slice(0, -1) : string +} + +// Note: a long line without a suitable break point will exceed the width limit. +// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. +function foldString (string, width) { + // In folded style, $k$ consecutive newlines output as $k+1$ newlines— + // unless they're before or after a more-indented line, or at the very + // beginning or end, in which case $k$ maps to $k$. + // Therefore, parse each chunk as newline(s) followed by a content line. + const lineRe = /(\n+)([^\n]*)/g + + // first line (possibly an empty line) + let result = (function () { + let nextLF = string.indexOf('\n') + nextLF = nextLF !== -1 ? nextLF : string.length + lineRe.lastIndex = nextLF + return foldLine(string.slice(0, nextLF), width) + }()) + // If we haven't reached the first content line yet, don't add an extra \n. + let prevMoreIndented = string[0] === '\n' || string[0] === ' ' + let moreIndented + + // rest of the lines + let match + while ((match = lineRe.exec(string))) { + const prefix = match[1] + const line = match[2] + + moreIndented = (line[0] === ' ') + result += prefix + + ((!prevMoreIndented && !moreIndented && line !== '') ? '\n' : '') + + foldLine(line, width) + prevMoreIndented = moreIndented + } + + return result +} + +// Greedy line breaking. +// Picks the longest line under the limit each time, +// otherwise settles for the shortest line over the limit. +// NB. More-indented lines *cannot* be folded, as that would add an extra \n. +function foldLine (line, width) { + if (line === '' || line[0] === ' ') return line + + // Since a more-indented line adds a \n, breaks can't be followed by a space. + const breakRe = / [^ ]/g // note: the match index will always be <= length-2. + let match + // start is an inclusive index. end, curr, and next are exclusive. + let start = 0 + let end + let curr = 0 + let next = 0 + let result = '' + + // Invariants: 0 <= start <= length-1. + // 0 <= curr <= next <= max(0, length-2). curr - start <= width. + // Inside the loop: + // A match implies length >= 2, so curr and next are <= length-2. + while ((match = breakRe.exec(line))) { + next = match.index + // maintain invariant: curr - start <= width + if (next - start > width) { + end = (curr > start) ? curr : next // derive end <= length-2 + result += '\n' + line.slice(start, end) + // skip the space that was output as \n + start = end + 1 // derive start <= length-1 + } + curr = next + } + + // By the invariants, start <= length-1, so there is something left over. + // It is either the whole string or a part starting from non-whitespace. + result += '\n' + // Insert a break if the remainder is too long and there is a break available. + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + '\n' + line.slice(curr + 1) + } else { + result += line.slice(start) + } + + return result.slice(1) // drop extra \n joiner +} + +// Escapes a double-quoted string. +function escapeString (string) { + let result = '' + let char = 0 + + for (let i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i) + const escapeSeq = ESCAPE_SEQUENCES[char] + + if (!escapeSeq && isPrintable(char)) { + result += string[i] + if (char >= 0x10000) result += string[i + 1] + } else { + result += escapeSeq || encodeHex(char) + } + } + + return result +} + +function writeFlowSequence (state, level, object) { + let _result = '' + const _tag = state.tag + + for (let index = 0, length = object.length; index < length; index += 1) { + let value = object[index] + + if (state.replacer) { + value = state.replacer.call(object, String(index), value) + } + + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level, value, false, false) || + (typeof value === 'undefined' && + writeNode(state, level, null, false, false))) { + if (_result !== '') _result += ',' + (!state.condenseFlow ? ' ' : '') + _result += state.dump + } + } + + state.tag = _tag + state.dump = '[' + _result + ']' +} + +function writeBlockSequence (state, level, object, compact) { + let _result = '' + const _tag = state.tag + + for (let index = 0, length = object.length; index < length; index += 1) { + let value = object[index] + + if (state.replacer) { + value = state.replacer.call(object, String(index), value) + } + + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level + 1, value, true, true, false, true) || + (typeof value === 'undefined' && + writeNode(state, level + 1, null, true, true, false, true))) { + if (!compact || _result !== '') { + _result += generateNextLine(state, level) + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + _result += '-' + } else { + _result += '- ' + } + + _result += state.dump + } + } + + state.tag = _tag + state.dump = _result || '[]' // Empty sequence if no valid values. +} + +function writeFlowMapping (state, level, object) { + let _result = '' + const _tag = state.tag + const objectKeyList = Object.keys(object) + + for (let index = 0, length = objectKeyList.length; index < length; index += 1) { + let pairBuffer = '' + if (_result !== '') pairBuffer += ', ' + + if (state.condenseFlow) pairBuffer += '"' + + const objectKey = objectKeyList[index] + let objectValue = object[objectKey] + + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue) + } + + if (!writeNode(state, level, objectKey, false, false)) { + continue // Skip this pair because of invalid key; + } + + if (state.dump.length > 1024) pairBuffer += '? ' + + pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' ') + + if (!writeNode(state, level, objectValue, false, false)) { + continue // Skip this pair because of invalid value. + } + + pairBuffer += state.dump + + // Both key and value are valid. + _result += pairBuffer + } + + state.tag = _tag + state.dump = '{' + _result + '}' +} + +function writeBlockMapping (state, level, object, compact) { + let _result = '' + const _tag = state.tag + const objectKeyList = Object.keys(object) + + // Allow sorting keys so that the output file is deterministic + if (state.sortKeys === true) { + // Default sorting + objectKeyList.sort() + } else if (typeof state.sortKeys === 'function') { + // Custom sort function + objectKeyList.sort(state.sortKeys) + } else if (state.sortKeys) { + // Something is wrong + throw new YAMLException('sortKeys must be a boolean or a function') + } + + for (let index = 0, length = objectKeyList.length; index < length; index += 1) { + let pairBuffer = '' + + if (!compact || _result !== '') { + pairBuffer += generateNextLine(state, level) + } + + const objectKey = objectKeyList[index] + let objectValue = object[objectKey] + + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue) + } + + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue // Skip this pair because of invalid key. + } + + const explicitPair = (state.tag !== null && state.tag !== '?') || + (state.dump && state.dump.length > 1024) + + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += '?' + } else { + pairBuffer += '? ' + } + } + + pairBuffer += state.dump + + if (explicitPair) { + pairBuffer += generateNextLine(state, level) + } + + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue // Skip this pair because of invalid value. + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ':' + } else { + pairBuffer += ': ' + } + + pairBuffer += state.dump + + // Both key and value are valid. + _result += pairBuffer + } + + state.tag = _tag + state.dump = _result || '{}' // Empty mapping if no valid pairs. +} + +function detectType (state, object, explicit) { + const typeList = explicit ? state.explicitTypes : state.implicitTypes + + for (let index = 0, length = typeList.length; index < length; index += 1) { + const type = typeList[index] + + if ((type.instanceOf || type.predicate) && + (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) && + (!type.predicate || type.predicate(object))) { + if (explicit) { + if (type.multi && type.representName) { + state.tag = type.representName(object) + } else { + state.tag = type.tag + } + } else { + state.tag = '?' + } + + if (type.represent) { + const style = state.styleMap[type.tag] || type.defaultStyle + + let _result + if (_toString.call(type.represent) === '[object Function]') { + _result = type.represent(object, style) + } else if (_hasOwnProperty.call(type.represent, style)) { + _result = type.represent[style](object, style) + } else { + throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style') + } + + state.dump = _result + } + + return true + } + } + + return false +} + +// Serializes `object` and writes it to global `result`. +// Returns true on success, or false on invalid object. +// +function writeNode (state, level, object, block, compact, iskey, isblockseq) { + state.tag = null + state.dump = object + + if (!detectType(state, object, false)) { + detectType(state, object, true) + } + + const type = _toString.call(state.dump) + const inblock = block + + if (block) { + block = (state.flowLevel < 0 || state.flowLevel > level) + } + + const objectOrArray = type === '[object Object]' || type === '[object Array]' + let duplicateIndex + let duplicate + + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object) + duplicate = duplicateIndex !== -1 + } + + if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) { + compact = false + } + + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = '*ref_' + duplicateIndex + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true + } + if (type === '[object Object]') { + if (block && (Object.keys(state.dump).length !== 0)) { + writeBlockMapping(state, level, state.dump, compact) + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump + } + } else { + writeFlowMapping(state, level, state.dump) + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump + } + } + } else if (type === '[object Array]') { + if (block && (state.dump.length !== 0)) { + if (state.noArrayIndent && !isblockseq && level > 0) { + writeBlockSequence(state, level - 1, state.dump, compact) + } else { + writeBlockSequence(state, level, state.dump, compact) + } + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump + } + } else { + writeFlowSequence(state, level, state.dump) + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump + } + } + } else if (type === '[object String]') { + if (state.tag !== '?') { + writeScalar(state, state.dump, level, iskey, inblock) + } + } else if (type === '[object Undefined]') { + return false + } else { + if (state.skipInvalid) return false + throw new YAMLException('unacceptable kind of an object to dump ' + type) + } + + if (state.tag !== null && state.tag !== '?') { + // Need to encode all characters except those allowed by the spec: + // + // [35] ns-dec-digit ::= [#x30-#x39] /* 0-9 */ + // [36] ns-hex-digit ::= ns-dec-digit + // | [#x41-#x46] /* A-F */ | [#x61-#x66] /* a-f */ + // [37] ns-ascii-letter ::= [#x41-#x5A] /* A-Z */ | [#x61-#x7A] /* a-z */ + // [38] ns-word-char ::= ns-dec-digit | ns-ascii-letter | “-” + // [39] ns-uri-char ::= “%” ns-hex-digit ns-hex-digit | ns-word-char | “#” + // | “;” | “/” | “?” | “:” | “@” | “&” | “=” | “+” | “$” | “,” + // | “_” | “.” | “!” | “~” | “*” | “'” | “(” | “)” | “[” | “]” + // + // Also need to encode '!' because it has special meaning (end of tag prefix). + // + let tagStr = encodeURI( + state.tag[0] === '!' ? state.tag.slice(1) : state.tag + ).replace(/!/g, '%21') + + if (state.tag[0] === '!') { + tagStr = '!' + tagStr + } else if (tagStr.slice(0, 18) === 'tag:yaml.org,2002:') { + tagStr = '!!' + tagStr.slice(18) + } else { + tagStr = '!<' + tagStr + '>' + } + + state.dump = tagStr + ' ' + state.dump + } + } + + return true +} + +function getDuplicateReferences (object, state) { + const objects = [] + const duplicatesIndexes = [] + + inspectNode(object, objects, duplicatesIndexes) + + const length = duplicatesIndexes.length + for (let index = 0; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]) + } + state.usedDuplicates = new Array(length) +} + +function inspectNode (object, objects, duplicatesIndexes) { + if (object !== null && typeof object === 'object') { + const index = objects.indexOf(object) + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index) + } + } else { + objects.push(object) + + if (Array.isArray(object)) { + for (let i = 0, length = object.length; i < length; i += 1) { + inspectNode(object[i], objects, duplicatesIndexes) + } + } else { + const objectKeyList = Object.keys(object) + + for (let i = 0, length = objectKeyList.length; i < length; i += 1) { + inspectNode(object[objectKeyList[i]], objects, duplicatesIndexes) + } + } + } + } +} + +function dump (input, options) { + options = options || {} + + const state = new State(options) + + if (!state.noRefs) getDuplicateReferences(input, state) + + let value = input + + if (state.replacer) { + value = state.replacer.call({ '': value }, '', value) + } + + if (writeNode(state, 0, value, true, true)) return state.dump + '\n' + + return '' +} + +module.exports.dump = dump diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/exception.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/exception.js new file mode 100644 index 0000000..8571562 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/exception.js @@ -0,0 +1,51 @@ +// YAML error class. http://stackoverflow.com/questions/8458984 +// +'use strict' + +function formatError (exception, compact) { + let where = '' + const message = exception.reason || '(unknown reason)' + + if (!exception.mark) return message + + if (exception.mark.name) { + where += 'in "' + exception.mark.name + '" ' + } + + where += '(' + (exception.mark.line + 1) + ':' + (exception.mark.column + 1) + ')' + + if (!compact && exception.mark.snippet) { + where += '\n\n' + exception.mark.snippet + } + + return message + ' ' + where +} + +function YAMLException (reason, mark) { + // Super constructor + Error.call(this) + + this.name = 'YAMLException' + this.reason = reason + this.mark = mark + this.message = formatError(this, false) + + // Include stack trace in error object + if (Error.captureStackTrace) { + // Chrome and NodeJS + Error.captureStackTrace(this, this.constructor) + } else { + // FF, IE 10+ and Safari 6+. Fallback for others + this.stack = (new Error()).stack || '' + } +} + +// Inherit from Error +YAMLException.prototype = Object.create(Error.prototype) +YAMLException.prototype.constructor = YAMLException + +YAMLException.prototype.toString = function toString (compact) { + return this.name + ': ' + formatError(this, compact) +} + +module.exports = YAMLException diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/index_vite_proxy.tmp.mjs b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/index_vite_proxy.tmp.mjs new file mode 100644 index 0000000..303f231 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/index_vite_proxy.tmp.mjs @@ -0,0 +1,37 @@ +import yaml from '../index.js' + +const { + Type, + Schema, + FAILSAFE_SCHEMA, + JSON_SCHEMA, + CORE_SCHEMA, + DEFAULT_SCHEMA, + load, + loadAll, + dump, + YAMLException, + types, + safeLoad, + safeLoadAll, + safeDump +} = yaml + +export { + Type, + Schema, + FAILSAFE_SCHEMA, + JSON_SCHEMA, + CORE_SCHEMA, + DEFAULT_SCHEMA, + load, + loadAll, + dump, + YAMLException, + types, + safeLoad, + safeLoadAll, + safeDump +} + +export default yaml diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/loader.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/loader.js new file mode 100644 index 0000000..a68af15 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/loader.js @@ -0,0 +1,1790 @@ +'use strict' + +const common = require('./common') +const YAMLException = require('./exception') +const makeSnippet = require('./snippet') +const DEFAULT_SCHEMA = require('./schema/default') + +const _hasOwnProperty = Object.prototype.hasOwnProperty + +const CONTEXT_FLOW_IN = 1 +const CONTEXT_FLOW_OUT = 2 +const CONTEXT_BLOCK_IN = 3 +const CONTEXT_BLOCK_OUT = 4 + +const CHOMPING_CLIP = 1 +const CHOMPING_STRIP = 2 +const CHOMPING_KEEP = 3 + +// eslint-disable-next-line no-control-regex +const PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/ +const PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/ +// eslint-disable-next-line no-useless-escape +const PATTERN_FLOW_INDICATORS = /[,\[\]{}]/ +// eslint-disable-next-line no-useless-escape +const PATTERN_TAG_HANDLE = /^(?:!|!!|![0-9A-Za-z-]+!)$/ +// eslint-disable-next-line no-useless-escape +const PATTERN_TAG_URI = /^(?:!|[^,\[\]{}])(?:%[0-9a-f]{2}|[0-9a-z\-#;/?:@&=+$,_.!~*'()\[\]])*$/i + +function _class (obj) { return Object.prototype.toString.call(obj) } + +function isEol (c) { + return (c === 0x0A/* LF */) || (c === 0x0D/* CR */) +} + +function isWhiteSpace (c) { + return (c === 0x09/* Tab */) || (c === 0x20/* Space */) +} + +function isWsOrEol (c) { + return (c === 0x09/* Tab */) || + (c === 0x20/* Space */) || + (c === 0x0A/* LF */) || + (c === 0x0D/* CR */) +} + +function isFlowIndicator (c) { + return c === 0x2C/* , */ || + c === 0x5B/* [ */ || + c === 0x5D/* ] */ || + c === 0x7B/* { */ || + c === 0x7D/* } */ +} + +function fromHexCode (c) { + if ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) { + return c - 0x30 + } + + const lc = c | 0x20 + + if ((lc >= 0x61/* a */) && (lc <= 0x66/* f */)) { + return lc - 0x61 + 10 + } + + return -1 +} + +function escapedHexLen (c) { + if (c === 0x78/* x */) { return 2 } + if (c === 0x75/* u */) { return 4 } + if (c === 0x55/* U */) { return 8 } + return 0 +} + +function fromDecimalCode (c) { + if ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) { + return c - 0x30 + } + + return -1 +} + +function simpleEscapeSequence (c) { + switch (c) { + case 0x30/* 0 */: return '\x00' + case 0x61/* a */: return '\x07' + case 0x62/* b */: return '\x08' + case 0x74/* t */: return '\x09' + case 0x09/* Tab */: return '\x09' + case 0x6E/* n */: return '\x0A' + case 0x76/* v */: return '\x0B' + case 0x66/* f */: return '\x0C' + case 0x72/* r */: return '\x0D' + case 0x65/* e */: return '\x1B' + case 0x20/* Space */: return ' ' + case 0x22/* " */: return '\x22' + case 0x2F/* / */: return '/' + case 0x5C/* \ */: return '\x5C' + case 0x4E/* N */: return '\x85' + case 0x5F/* _ */: return '\xA0' + case 0x4C/* L */: return '\u2028' + case 0x50/* P */: return '\u2029' + default: return '' + } +} + +function charFromCodepoint (c) { + if (c <= 0xFFFF) { + return String.fromCharCode(c) + } + // Encode UTF-16 surrogate pair + // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF + return String.fromCharCode( + ((c - 0x010000) >> 10) + 0xD800, + ((c - 0x010000) & 0x03FF) + 0xDC00 + ) +} + +// set a property of a literal object, while protecting against prototype pollution, +// see https://github.com/nodeca/js-yaml/issues/164 for more details +function setProperty (object, key, value) { + // used for this specific key only because Object.defineProperty is slow + if (key === '__proto__') { + Object.defineProperty(object, key, { + configurable: true, + enumerable: true, + writable: true, + value: value + }) + } else { + object[key] = value + } +} + +const simpleEscapeCheck = new Array(256) // integer, for fast access +const simpleEscapeMap = new Array(256) +for (let i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0 + simpleEscapeMap[i] = simpleEscapeSequence(i) +} + +function State (input, options) { + this.input = input + + this.filename = options['filename'] || null + this.schema = options['schema'] || DEFAULT_SCHEMA + this.onWarning = options['onWarning'] || null + // (Hidden) Remove? makes the loader to expect YAML 1.1 documents + // if such documents have no explicit %YAML directive + this.legacy = options['legacy'] || false + + this.json = options['json'] || false + this.listener = options['listener'] || null + this.maxDepth = typeof options['maxDepth'] === 'number' ? options['maxDepth'] : 100 + this.maxTotalMergeKeys = typeof options['maxTotalMergeKeys'] === 'number' ? options['maxTotalMergeKeys'] : 10000 + + this.implicitTypes = this.schema.compiledImplicit + this.typeMap = this.schema.compiledTypeMap + + this.length = input.length + this.position = 0 + this.line = 0 + this.lineStart = 0 + this.lineIndent = 0 + this.depth = 0 + this.totalMergeKeys = 0 + + // position of first leading tab in the current line, + // used to make sure there are no tabs in the indentation + this.firstTabInLine = -1 + + this.documents = [] + this.anchorMapTransactions = [] + + /* + this.version; + this.checkLineBreaks; + this.tagMap; + this.anchorMap; + this.tag; + this.anchor; + this.kind; + this.result; */ +} + +function generateError (state, message) { + const mark = { + name: state.filename, + buffer: state.input.slice(0, -1), // omit trailing \0 + position: state.position, + line: state.line, + column: state.position - state.lineStart + } + + mark.snippet = makeSnippet(mark) + + return new YAMLException(message, mark) +} + +function throwError (state, message) { + throw generateError(state, message) +} + +function throwWarning (state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)) + } +} + +function storeAnchor (state, name, value) { + const transactions = state.anchorMapTransactions + + if (transactions.length !== 0) { + const transaction = transactions[transactions.length - 1] + + if (!_hasOwnProperty.call(transaction, name)) { + transaction[name] = { + existed: _hasOwnProperty.call(state.anchorMap, name), + value: state.anchorMap[name] + } + } + } + + state.anchorMap[name] = value +} + +function beginAnchorTransaction (state) { + state.anchorMapTransactions.push(Object.create(null)) +} + +function commitAnchorTransaction (state) { + const transaction = state.anchorMapTransactions.pop() + const transactions = state.anchorMapTransactions + + if (transactions.length === 0) return + + const parent = transactions[transactions.length - 1] + const names = Object.keys(transaction) + + for (let index = 0, length = names.length; index < length; index += 1) { + const name = names[index] + + if (!_hasOwnProperty.call(parent, name)) { + parent[name] = transaction[name] + } + } +} + +function rollbackAnchorTransaction (state) { + const transaction = state.anchorMapTransactions.pop() + const names = Object.keys(transaction) + + for (let index = names.length - 1; index >= 0; index -= 1) { + const entry = transaction[names[index]] + + if (entry.existed) { + state.anchorMap[names[index]] = entry.value + } else { + delete state.anchorMap[names[index]] + } + } +} + +function snapshotState (state) { + return { + position: state.position, + line: state.line, + lineStart: state.lineStart, + lineIndent: state.lineIndent, + firstTabInLine: state.firstTabInLine, + tag: state.tag, + anchor: state.anchor, + kind: state.kind, + result: state.result + } +} + +function restoreState (state, snapshot) { + state.position = snapshot.position + state.line = snapshot.line + state.lineStart = snapshot.lineStart + state.lineIndent = snapshot.lineIndent + state.firstTabInLine = snapshot.firstTabInLine + state.tag = snapshot.tag + state.anchor = snapshot.anchor + state.kind = snapshot.kind + state.result = snapshot.result +} + +const directiveHandlers = { + + YAML: function handleYamlDirective (state, name, args) { + if (state.version !== null) { + throwError(state, 'duplication of %YAML directive') + } + + if (args.length !== 1) { + throwError(state, 'YAML directive accepts exactly one argument') + } + + const match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]) + + if (match === null) { + throwError(state, 'ill-formed argument of the YAML directive') + } + + const major = parseInt(match[1], 10) + const minor = parseInt(match[2], 10) + + if (major !== 1) { + throwError(state, 'unacceptable YAML version of the document') + } + + state.version = args[0] + state.checkLineBreaks = (minor < 2) + + if (minor !== 1 && minor !== 2) { + throwWarning(state, 'unsupported YAML version of the document') + } + }, + + TAG: function handleTagDirective (state, name, args) { + let prefix + + if (args.length !== 2) { + throwError(state, 'TAG directive accepts exactly two arguments') + } + + const handle = args[0] + prefix = args[1] + + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, 'ill-formed tag handle (first argument) of the TAG directive') + } + + if (_hasOwnProperty.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle') + } + + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive') + } + + try { + prefix = decodeURIComponent(prefix) + } catch (err) { + throwError(state, 'tag prefix is malformed: ' + prefix) + } + + state.tagMap[handle] = prefix + } +} + +function captureSegment (state, start, end, checkJson) { + if (start < end) { + const _result = state.input.slice(start, end) + + if (checkJson) { + for (let _position = 0, _length = _result.length; _position < _length; _position += 1) { + const _character = _result.charCodeAt(_position) + if (!(_character === 0x09 || + (_character >= 0x20 && _character <= 0x10FFFF))) { + throwError(state, 'expected valid JSON character') + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, 'the stream contains non-printable characters') + } + + state.result += _result + } +} + +function mergeMappings (state, destination, source, overridableKeys) { + if (!common.isObject(source)) { + throwError(state, 'cannot merge mappings; the provided source object is unacceptable') + } + + const sourceKeys = Object.keys(source) + + for (let index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + const key = sourceKeys[index] + + if (state.maxTotalMergeKeys !== -1 && ++state.totalMergeKeys > state.maxTotalMergeKeys) { + throwError(state, 'merge keys exceeded maxTotalMergeKeys (' + state.maxTotalMergeKeys + ')') + } + + if (!_hasOwnProperty.call(destination, key)) { + setProperty(destination, key, source[key]) + overridableKeys[key] = true + } + } +} + +function storeMappingPair (state, _result, overridableKeys, keyTag, keyNode, valueNode, + startLine, startLineStart, startPos) { + // The output is a plain object here, so keys can only be strings. + // We need to convert keyNode to a string, but doing so can hang the process + // (deeply nested arrays that explode exponentially using aliases). + if (Array.isArray(keyNode)) { + keyNode = Array.prototype.slice.call(keyNode) + + for (let index = 0, quantity = keyNode.length; index < quantity; index += 1) { + if (Array.isArray(keyNode[index])) { + throwError(state, 'nested arrays are not supported inside keys') + } + + if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') { + keyNode[index] = '[object Object]' + } + } + } + + // Avoid code execution in load() via toString property + // (still use its own toString for arrays, timestamps, + // and whatever user schema extensions happen to have @@toStringTag) + if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') { + keyNode = '[object Object]' + } + + keyNode = String(keyNode) + + if (_result === null) { + _result = {} + } + + if (keyTag === 'tag:yaml.org,2002:merge') { + if (Array.isArray(valueNode)) { + for (let index = 0, quantity = valueNode.length; index < quantity; index += 1) { + mergeMappings(state, _result, valueNode[index], overridableKeys) + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys) + } + } else { + if (!state.json && + !_hasOwnProperty.call(overridableKeys, keyNode) && + _hasOwnProperty.call(_result, keyNode)) { + state.line = startLine || state.line + state.lineStart = startLineStart || state.lineStart + state.position = startPos || state.position + throwError(state, 'duplicated mapping key') + } + + setProperty(_result, keyNode, valueNode) + delete overridableKeys[keyNode] + } + + return _result +} + +function readLineBreak (state) { + const ch = state.input.charCodeAt(state.position) + + if (ch === 0x0A/* LF */) { + state.position++ + } else if (ch === 0x0D/* CR */) { + state.position++ + if (state.input.charCodeAt(state.position) === 0x0A/* LF */) { + state.position++ + } + } else { + throwError(state, 'a line break is expected') + } + + state.line += 1 + state.lineStart = state.position + state.firstTabInLine = -1 +} + +function skipSeparationSpace (state, allowComments, checkIndent) { + let lineBreaks = 0 + let ch = state.input.charCodeAt(state.position) + + while (ch !== 0) { + while (isWhiteSpace(ch)) { + if (ch === 0x09/* Tab */ && state.firstTabInLine === -1) { + state.firstTabInLine = state.position + } + ch = state.input.charCodeAt(++state.position) + } + + if (allowComments && ch === 0x23/* # */) { + do { + ch = state.input.charCodeAt(++state.position) + } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0) + } + + if (isEol(ch)) { + readLineBreak(state) + + ch = state.input.charCodeAt(state.position) + lineBreaks++ + state.lineIndent = 0 + + while (ch === 0x20/* Space */) { + state.lineIndent++ + ch = state.input.charCodeAt(++state.position) + } + } else { + break + } + } + + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, 'deficient indentation') + } + + return lineBreaks +} + +function testDocumentSeparator (state) { + let _position = state.position + let ch = state.input.charCodeAt(_position) + + // Condition state.position === state.lineStart is tested + // in parent on each call, for efficiency. No needs to test here again. + if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) && + ch === state.input.charCodeAt(_position + 1) && + ch === state.input.charCodeAt(_position + 2)) { + _position += 3 + + ch = state.input.charCodeAt(_position) + + if (ch === 0 || isWsOrEol(ch)) { + return true + } + } + + return false +} + +function writeFoldedLines (state, count) { + if (count === 1) { + state.result += ' ' + } else if (count > 1) { + state.result += common.repeat('\n', count - 1) + } +} + +function readPlainScalar (state, nodeIndent, withinFlowCollection) { + let captureStart + let captureEnd + let hasPendingContent + let _line + let _lineStart + let _lineIndent + const _kind = state.kind + const _result = state.result + + let ch = state.input.charCodeAt(state.position) + + if (isWsOrEol(ch) || + isFlowIndicator(ch) || + ch === 0x23/* # */ || + ch === 0x26/* & */ || + ch === 0x2A/* * */ || + ch === 0x21/* ! */ || + ch === 0x7C/* | */ || + ch === 0x3E/* > */ || + ch === 0x27/* ' */ || + ch === 0x22/* " */ || + ch === 0x25/* % */ || + ch === 0x40/* @ */ || + ch === 0x60/* ` */) { + return false + } + + if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { + const following = state.input.charCodeAt(state.position + 1) + + if (isWsOrEol(following) || + (withinFlowCollection && isFlowIndicator(following))) { + return false + } + } + + state.kind = 'scalar' + state.result = '' + captureStart = captureEnd = state.position + hasPendingContent = false + + while (ch !== 0) { + if (ch === 0x3A/* : */) { + const following = state.input.charCodeAt(state.position + 1) + + if (isWsOrEol(following) || + (withinFlowCollection && isFlowIndicator(following))) { + break + } + } else if (ch === 0x23/* # */) { + const preceding = state.input.charCodeAt(state.position - 1) + + if (isWsOrEol(preceding)) { + break + } + } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || + (withinFlowCollection && isFlowIndicator(ch))) { + break + } else if (isEol(ch)) { + _line = state.line + _lineStart = state.lineStart + _lineIndent = state.lineIndent + skipSeparationSpace(state, false, -1) + + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true + ch = state.input.charCodeAt(state.position) + continue + } else { + state.position = captureEnd + state.line = _line + state.lineStart = _lineStart + state.lineIndent = _lineIndent + break + } + } + + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false) + writeFoldedLines(state, state.line - _line) + captureStart = captureEnd = state.position + hasPendingContent = false + } + + if (!isWhiteSpace(ch)) { + captureEnd = state.position + 1 + } + + ch = state.input.charCodeAt(++state.position) + } + + captureSegment(state, captureStart, captureEnd, false) + + if (state.result) { + return true + } + + state.kind = _kind + state.result = _result + return false +} + +function readSingleQuotedScalar (state, nodeIndent) { + let captureStart + let captureEnd + + let ch = state.input.charCodeAt(state.position) + + if (ch !== 0x27/* ' */) { + return false + } + + state.kind = 'scalar' + state.result = '' + state.position++ + captureStart = captureEnd = state.position + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x27/* ' */) { + captureSegment(state, captureStart, state.position, true) + ch = state.input.charCodeAt(++state.position) + + if (ch === 0x27/* ' */) { + captureStart = state.position + state.position++ + captureEnd = state.position + } else { + return true + } + } else if (isEol(ch)) { + captureSegment(state, captureStart, captureEnd, true) + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)) + captureStart = captureEnd = state.position + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a single quoted scalar') + } else { + state.position++ + if (!isWhiteSpace(ch)) { + captureEnd = state.position + } + } + } + + throwError(state, 'unexpected end of the stream within a single quoted scalar') +} + +function readDoubleQuotedScalar (state, nodeIndent) { + let captureStart + let captureEnd + let tmp + + let ch = state.input.charCodeAt(state.position) + + if (ch !== 0x22/* " */) { + return false + } + + state.kind = 'scalar' + state.result = '' + state.position++ + captureStart = captureEnd = state.position + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x22/* " */) { + captureSegment(state, captureStart, state.position, true) + state.position++ + return true + } else if (ch === 0x5C/* \ */) { + captureSegment(state, captureStart, state.position, true) + ch = state.input.charCodeAt(++state.position) + + if (isEol(ch)) { + skipSeparationSpace(state, false, nodeIndent) + + // TODO: rework to inline fn with no type cast? + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch] + state.position++ + } else if ((tmp = escapedHexLen(ch)) > 0) { + let hexLength = tmp + let hexResult = 0 + + for (; hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position) + + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp + } else { + throwError(state, 'expected hexadecimal character') + } + } + + state.result += charFromCodepoint(hexResult) + + state.position++ + } else { + throwError(state, 'unknown escape sequence') + } + + captureStart = captureEnd = state.position + } else if (isEol(ch)) { + captureSegment(state, captureStart, captureEnd, true) + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)) + captureStart = captureEnd = state.position + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a double quoted scalar') + } else { + state.position++ + if (!isWhiteSpace(ch)) { + captureEnd = state.position + } + } + } + + throwError(state, 'unexpected end of the stream within a double quoted scalar') +} + +function readFlowCollection (state, nodeIndent) { + let readNext = true + let _line + let _lineStart + let _pos + const _tag = state.tag + let _result + const _anchor = state.anchor + let terminator + let isPair + let isExplicitPair + let isMapping + const overridableKeys = Object.create(null) + let keyNode + let keyTag + let valueNode + + let ch = state.input.charCodeAt(state.position) + + if (ch === 0x5B/* [ */) { + terminator = 0x5D/* ] */ + isMapping = false + _result = [] + } else if (ch === 0x7B/* { */) { + terminator = 0x7D/* } */ + isMapping = true + _result = {} + } else { + return false + } + + if (state.anchor !== null) { + storeAnchor(state, state.anchor, _result) + } + + ch = state.input.charCodeAt(++state.position) + + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent) + + ch = state.input.charCodeAt(state.position) + + if (ch === terminator) { + state.position++ + state.tag = _tag + state.anchor = _anchor + state.kind = isMapping ? 'mapping' : 'sequence' + state.result = _result + return true + } else if (!readNext) { + throwError(state, 'missed comma between flow collection entries') + } else if (ch === 0x2C/* , */) { + // "flow collection entries can never be completely empty", as per YAML 1.2, section 7.4 + throwError(state, "expected the node content, but found ','") + } + + keyTag = keyNode = valueNode = null + isPair = isExplicitPair = false + + if (ch === 0x3F/* ? */) { + const following = state.input.charCodeAt(state.position + 1) + + if (isWsOrEol(following)) { + isPair = isExplicitPair = true + state.position++ + skipSeparationSpace(state, true, nodeIndent) + } + } + + _line = state.line // Save the current line. + _lineStart = state.lineStart + _pos = state.position + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true) + keyTag = state.tag + keyNode = state.result + skipSeparationSpace(state, true, nodeIndent) + + ch = state.input.charCodeAt(state.position) + + if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) { + isPair = true + ch = state.input.charCodeAt(++state.position) + skipSeparationSpace(state, true, nodeIndent) + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true) + valueNode = state.result + } + + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos) + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)) + } else { + _result.push(keyNode) + } + + skipSeparationSpace(state, true, nodeIndent) + + ch = state.input.charCodeAt(state.position) + + if (ch === 0x2C/* , */) { + readNext = true + ch = state.input.charCodeAt(++state.position) + } else { + readNext = false + } + } + + throwError(state, 'unexpected end of the stream within a flow collection') +} + +function readBlockScalar (state, nodeIndent) { + let folding + let chomping = CHOMPING_CLIP + let didReadContent = false + let detectedIndent = false + let textIndent = nodeIndent + let emptyLines = 0 + let atMoreIndented = false + let tmp + + let ch = state.input.charCodeAt(state.position) + + if (ch === 0x7C/* | */) { + folding = false + } else if (ch === 0x3E/* > */) { + folding = true + } else { + return false + } + + state.kind = 'scalar' + state.result = '' + + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position) + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + if (CHOMPING_CLIP === chomping) { + chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP + } else { + throwError(state, 'repeat of a chomping mode identifier') + } + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one') + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1 + detectedIndent = true + } else { + throwError(state, 'repeat of an indentation width identifier') + } + } else { + break + } + } + + if (isWhiteSpace(ch)) { + do { ch = state.input.charCodeAt(++state.position) } + while (isWhiteSpace(ch)) + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position) } + while (!isEol(ch) && (ch !== 0)) + } + } + + while (ch !== 0) { + readLineBreak(state) + state.lineIndent = 0 + + ch = state.input.charCodeAt(state.position) + + // eslint-disable-next-line no-unmodified-loop-condition + while ((!detectedIndent || state.lineIndent < textIndent) && + (ch === 0x20/* Space */)) { + state.lineIndent++ + ch = state.input.charCodeAt(++state.position) + } + + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent + } + + if (isEol(ch)) { + emptyLines++ + continue + } + + if (!detectedIndent && textIndent === 0) { + throwError(state, 'missing indentation for block scalar') + } + + // End of the scalar. + if (state.lineIndent < textIndent) { + // Perform the chomping. + if (chomping === CHOMPING_KEEP) { + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines) + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { // i.e. only if the scalar is not empty. + state.result += '\n' + } + } + + // Break this `while` cycle and go to the funciton's epilogue. + break + } + + // Folded style: use fancy rules to handle line breaks. + if (folding) { + // Lines starting with white space characters (more-indented lines) are not folded. + if (isWhiteSpace(ch)) { + atMoreIndented = true + // except for the first content line (cf. Example 8.1) + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines) + + // End of more-indented block. + } else if (atMoreIndented) { + atMoreIndented = false + state.result += common.repeat('\n', emptyLines + 1) + + // Just one line break - perceive as the same line. + } else if (emptyLines === 0) { + if (didReadContent) { // i.e. only if we have already read some scalar content. + state.result += ' ' + } + + // Several line breaks - perceive as different lines. + } else { + state.result += common.repeat('\n', emptyLines) + } + + // Literal style: just add exact number of line breaks between content lines. + } else { + // Keep all line breaks except the header line break. + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines) + } + + didReadContent = true + detectedIndent = true + emptyLines = 0 + const captureStart = state.position + + while (!isEol(ch) && (ch !== 0)) { + ch = state.input.charCodeAt(++state.position) + } + + captureSegment(state, captureStart, state.position, false) + } + + return true +} + +function readBlockSequence (state, nodeIndent) { + const _tag = state.tag + const _anchor = state.anchor + const _result = [] + let detected = false + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false + + if (state.anchor !== null) { + storeAnchor(state, state.anchor, _result) + } + + let ch = state.input.charCodeAt(state.position) + + while (ch !== 0) { + if (state.firstTabInLine !== -1) { + state.position = state.firstTabInLine + throwError(state, 'tab characters must not be used in indentation') + } + + if (ch !== 0x2D/* - */) { + break + } + + const following = state.input.charCodeAt(state.position + 1) + + if (!isWsOrEol(following)) { + break + } + + detected = true + state.position++ + + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null) + ch = state.input.charCodeAt(state.position) + continue + } + } + + const _line = state.line + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true) + _result.push(state.result) + skipSeparationSpace(state, true, -1) + + ch = state.input.charCodeAt(state.position) + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a sequence entry') + } else if (state.lineIndent < nodeIndent) { + break + } + } + + if (detected) { + state.tag = _tag + state.anchor = _anchor + state.kind = 'sequence' + state.result = _result + return true + } + return false +} + +function readBlockMapping (state, nodeIndent, flowIndent) { + let allowCompact + let _keyLine + let _keyLineStart + let _keyPos + const _tag = state.tag + const _anchor = state.anchor + const _result = {} + const overridableKeys = Object.create(null) + let keyTag = null + let keyNode = null + let valueNode = null + let atExplicitKey = false + let detected = false + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false + + if (state.anchor !== null) { + storeAnchor(state, state.anchor, _result) + } + + let ch = state.input.charCodeAt(state.position) + + while (ch !== 0) { + if (!atExplicitKey && state.firstTabInLine !== -1) { + state.position = state.firstTabInLine + throwError(state, 'tab characters must not be used in indentation') + } + + const following = state.input.charCodeAt(state.position + 1) + const _line = state.line // Save the current line. + + // + // Explicit notation case. There are two separate blocks: + // first for the key (denoted by "?") and second for the value (denoted by ":") + // + if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && isWsOrEol(following)) { + if (ch === 0x3F/* ? */) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos) + keyTag = keyNode = valueNode = null + } + + detected = true + atExplicitKey = true + allowCompact = true + } else if (atExplicitKey) { + // i.e. 0x3A/* : */ === character after the explicit key. + atExplicitKey = false + allowCompact = true + } else { + throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line') + } + + state.position += 1 + ch = following + + // + // Implicit notation case. Flow-style node as the key first, then ":", and the value. + // + } else { + _keyLine = state.line + _keyLineStart = state.lineStart + _keyPos = state.position + + if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + // Neither implicit nor explicit notation. + // Reading is done. Go to the epilogue. + break + } + + if (state.line === _line) { + ch = state.input.charCodeAt(state.position) + + while (isWhiteSpace(ch)) { + ch = state.input.charCodeAt(++state.position) + } + + if (ch === 0x3A/* : */) { + ch = state.input.charCodeAt(++state.position) + + if (!isWsOrEol(ch)) { + throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping') + } + + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos) + keyTag = keyNode = valueNode = null + } + + detected = true + atExplicitKey = false + allowCompact = false + keyTag = state.tag + keyNode = state.result + } else if (detected) { + throwError(state, 'can not read an implicit mapping pair; a colon is missed') + } else { + state.tag = _tag + state.anchor = _anchor + return true // Keep the result of `composeNode`. + } + } else if (detected) { + throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key') + } else { + state.tag = _tag + state.anchor = _anchor + return true // Keep the result of `composeNode`. + } + } + + // + // Common reading code for both explicit and implicit notations. + // + if (state.line === _line || state.lineIndent > nodeIndent) { + if (atExplicitKey) { + _keyLine = state.line + _keyLineStart = state.lineStart + _keyPos = state.position + } + + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result + } else { + valueNode = state.result + } + } + + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos) + keyTag = keyNode = valueNode = null + } + + skipSeparationSpace(state, true, -1) + ch = state.input.charCodeAt(state.position) + } + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a mapping entry') + } else if (state.lineIndent < nodeIndent) { + break + } + } + + // + // Epilogue. + // + + // Special case: last mapping's node contains only the key in explicit notation. + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos) + } + + // Expose the resulting mapping. + if (detected) { + state.tag = _tag + state.anchor = _anchor + state.kind = 'mapping' + state.result = _result + } + + return detected +} + +function readTagProperty (state) { + let isVerbatim = false + let isNamed = false + let tagHandle + let tagName + + let ch = state.input.charCodeAt(state.position) + + if (ch !== 0x21/* ! */) return false + + if (state.tag !== null) { + throwError(state, 'duplication of a tag property') + } + + ch = state.input.charCodeAt(++state.position) + + if (ch === 0x3C/* < */) { + isVerbatim = true + ch = state.input.charCodeAt(++state.position) + } else if (ch === 0x21/* ! */) { + isNamed = true + tagHandle = '!!' + ch = state.input.charCodeAt(++state.position) + } else { + tagHandle = '!' + } + + let _position = state.position + + if (isVerbatim) { + do { ch = state.input.charCodeAt(++state.position) } + while (ch !== 0 && ch !== 0x3E/* > */) + + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position) + ch = state.input.charCodeAt(++state.position) + } else { + throwError(state, 'unexpected end of the stream within a verbatim tag') + } + } else { + while (ch !== 0 && !isWsOrEol(ch)) { + if (ch === 0x21/* ! */) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1) + + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, 'named tag handle cannot contain such characters') + } + + isNamed = true + _position = state.position + 1 + } else { + throwError(state, 'tag suffix cannot contain exclamation marks') + } + } + + ch = state.input.charCodeAt(++state.position) + } + + tagName = state.input.slice(_position, state.position) + + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, 'tag suffix cannot contain flow indicator characters') + } + } + + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, 'tag name cannot contain such characters: ' + tagName) + } + + try { + tagName = decodeURIComponent(tagName) + } catch (err) { + throwError(state, 'tag name is malformed: ' + tagName) + } + + if (isVerbatim) { + state.tag = tagName + } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName + } else if (tagHandle === '!') { + state.tag = '!' + tagName + } else if (tagHandle === '!!') { + state.tag = 'tag:yaml.org,2002:' + tagName + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"') + } + + return true +} + +function readAnchorProperty (state) { + let ch = state.input.charCodeAt(state.position) + + if (ch !== 0x26/* & */) return false + + if (state.anchor !== null) { + throwError(state, 'duplication of an anchor property') + } + + ch = state.input.charCodeAt(++state.position) + const _position = state.position + + while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) { + ch = state.input.charCodeAt(++state.position) + } + + if (state.position === _position) { + throwError(state, 'name of an anchor node must contain at least one character') + } + + state.anchor = state.input.slice(_position, state.position) + return true +} + +function readAlias (state) { + let ch = state.input.charCodeAt(state.position) + + if (ch !== 0x2A/* * */) return false + + ch = state.input.charCodeAt(++state.position) + const _position = state.position + + while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) { + ch = state.input.charCodeAt(++state.position) + } + + if (state.position === _position) { + throwError(state, 'name of an alias node must contain at least one character') + } + + const alias = state.input.slice(_position, state.position) + + if (!_hasOwnProperty.call(state.anchorMap, alias)) { + throwError(state, 'unidentified alias "' + alias + '"') + } + + state.result = state.anchorMap[alias] + skipSeparationSpace(state, true, -1) + return true +} + +function tryReadBlockMappingFromProperty (state, propertyStart, nodeIndent, flowIndent) { + const fallbackState = snapshotState(state) + + beginAnchorTransaction(state) + restoreState(state, propertyStart) + + // Re-read the leading properties as part of the first implicit key, not as + // properties of the current node. + state.tag = null + state.anchor = null + state.kind = null + state.result = null + + if (readBlockMapping(state, nodeIndent, flowIndent) && state.kind === 'mapping') { + commitAnchorTransaction(state) + return true + } + + rollbackAnchorTransaction(state) + restoreState(state, fallbackState) + return false +} + +function composeNode (state, parentIndent, nodeContext, allowToSeek, allowCompact) { + let allowBlockScalars + let allowBlockCollections + let indentStatus = 1 // 1: this>parent, 0: this=parent, -1: this= state.maxDepth) { + throwError(state, 'nesting exceeded maxDepth (' + state.maxDepth + ')') + } + + state.depth += 1 + + if (state.listener !== null) { + state.listener('open', state) + } + + state.tag = null + state.anchor = null + state.kind = null + state.result = null + + const allowBlockStyles = allowBlockScalars = allowBlockCollections = + CONTEXT_BLOCK_OUT === nodeContext || + CONTEXT_BLOCK_IN === nodeContext + + if (allowToSeek) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true + + if (state.lineIndent > parentIndent) { + indentStatus = 1 + } else if (state.lineIndent === parentIndent) { + indentStatus = 0 + } else if (state.lineIndent < parentIndent) { + indentStatus = -1 + } + } + } + + if (indentStatus === 1) { + while (true) { + const ch = state.input.charCodeAt(state.position) + const propertyState = snapshotState(state) + + // A duplicate property token after a line break can be the first key of + // a nested block mapping, e.g. `!!map\n !!str key: value`. + if (atNewLine && + ((ch === 0x21/* ! */ && state.tag !== null) || + (ch === 0x26/* & */ && state.anchor !== null))) { + break + } + + if (!readTagProperty(state) && !readAnchorProperty(state)) { + break + } + + if (propertyStart === null) { + propertyStart = propertyState + } + + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true + allowBlockCollections = allowBlockStyles + + if (state.lineIndent > parentIndent) { + indentStatus = 1 + } else if (state.lineIndent === parentIndent) { + indentStatus = 0 + } else if (state.lineIndent < parentIndent) { + indentStatus = -1 + } + } else { + allowBlockCollections = false + } + } + } + + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact + } + + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent + } else { + flowIndent = parentIndent + 1 + } + + blockIndent = state.position - state.lineStart + + if (indentStatus === 1) { + if ((allowBlockCollections && + (readBlockSequence(state, blockIndent) || readBlockMapping(state, blockIndent, flowIndent))) || + readFlowCollection(state, flowIndent)) { + hasContent = true + } else { + const ch = state.input.charCodeAt(state.position) + + if (propertyStart !== null && allowBlockStyles && !allowBlockCollections && + ch !== 0x7C/* | */ && ch !== 0x3E/* > */ && + tryReadBlockMappingFromProperty( + state, + propertyStart, + propertyStart.position - propertyStart.lineStart, + flowIndent + )) { + hasContent = true + } else if ((allowBlockScalars && readBlockScalar(state, flowIndent)) || + readSingleQuotedScalar(state, flowIndent) || + readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true + } else if (readAlias(state)) { + hasContent = true + + if (state.tag !== null || state.anchor !== null) { + throwError(state, 'alias node should not have any properties') + } + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true + + if (state.tag === null) { + state.tag = '?' + } + } + + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result) + } + } + } else if (indentStatus === 0) { + // Special case: block sequences are allowed to have same indentation level as the parent. + // http://www.yaml.org/spec/1.2/spec.html#id2799784 + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent) + } + } + + if (state.tag === null) { + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result) + } + } else if (state.tag === '?') { + // Implicit resolving is not allowed for non-scalar types, and '?' + // non-specific tag is only automatically assigned to plain scalars. + // + // We only need to check kind conformity in case user explicitly assigns '?' + // tag, for example like this: "! [0]" + // + if (state.result !== null && state.kind !== 'scalar') { + throwError(state, 'unacceptable node kind for ! tag; it should be "scalar", not "' + state.kind + '"') + } + + for (let typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) { + type = state.implicitTypes[typeIndex] + + if (type.resolve(state.result)) { // `state.result` updated in resolver if matched + state.result = type.construct(state.result) + state.tag = type.tag + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result) + } + break + } + } + } else if (state.tag !== '!') { + if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) { + type = state.typeMap[state.kind || 'fallback'][state.tag] + } else { + // looking for multi type + type = null + const typeList = state.typeMap.multi[state.kind || 'fallback'] + + for (let typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) { + if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) { + type = typeList[typeIndex] + break + } + } + } + + if (!type) { + throwError(state, 'unknown tag !<' + state.tag + '>') + } + + if (state.result !== null && type.kind !== state.kind) { + throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"') + } + + if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched + throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag') + } else { + state.result = type.construct(state.result, state.tag) + if (state.anchor !== null) { + storeAnchor(state, state.anchor, state.result) + } + } + } + + if (state.listener !== null) { + state.listener('close', state) + } + + state.depth -= 1 + return state.tag !== null || state.anchor !== null || hasContent +} + +function readDocument (state) { + const documentStart = state.position + let hasDirectives = false + let ch + + state.version = null + state.checkLineBreaks = state.legacy + state.tagMap = Object.create(null) + state.anchorMap = Object.create(null) + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1) + + ch = state.input.charCodeAt(state.position) + + if (state.lineIndent > 0 || ch !== 0x25/* % */) { + break + } + + hasDirectives = true + ch = state.input.charCodeAt(++state.position) + let _position = state.position + + while (ch !== 0 && !isWsOrEol(ch)) { + ch = state.input.charCodeAt(++state.position) + } + + const directiveName = state.input.slice(_position, state.position) + const directiveArgs = [] + + if (directiveName.length < 1) { + throwError(state, 'directive name must not be less than one character in length') + } + + while (ch !== 0) { + while (isWhiteSpace(ch)) { + ch = state.input.charCodeAt(++state.position) + } + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position) } + while (ch !== 0 && !isEol(ch)) + break + } + + if (isEol(ch)) break + + _position = state.position + + while (ch !== 0 && !isWsOrEol(ch)) { + ch = state.input.charCodeAt(++state.position) + } + + directiveArgs.push(state.input.slice(_position, state.position)) + } + + if (ch !== 0) readLineBreak(state) + + if (_hasOwnProperty.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs) + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"') + } + } + + skipSeparationSpace(state, true, -1) + + if (state.lineIndent === 0 && + state.input.charCodeAt(state.position) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 1) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 2) === 0x2D/* - */) { + state.position += 3 + skipSeparationSpace(state, true, -1) + } else if (hasDirectives) { + throwError(state, 'directives end mark is expected') + } + + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true) + skipSeparationSpace(state, true, -1) + + if (state.checkLineBreaks && + PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, 'non-ASCII line breaks are interpreted as content') + } + + state.documents.push(state.result) + + if (state.position === state.lineStart && testDocumentSeparator(state)) { + if (state.input.charCodeAt(state.position) === 0x2E/* . */) { + state.position += 3 + skipSeparationSpace(state, true, -1) + } + return + } + + if (state.position < (state.length - 1)) { + throwError(state, 'end of the stream or a document separator is expected') + } +} + +function loadDocuments (input, options) { + input = String(input) + options = options || {} + + if (input.length !== 0) { + // Add tailing `\n` if not exists + if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ && + input.charCodeAt(input.length - 1) !== 0x0D/* CR */) { + input += '\n' + } + + // Strip BOM + if (input.charCodeAt(0) === 0xFEFF) { + input = input.slice(1) + } + } + + const state = new State(input, options) + + const nullpos = input.indexOf('\0') + + if (nullpos !== -1) { + state.position = nullpos + throwError(state, 'null byte is not allowed in input') + } + + // Use 0 as string terminator. That significantly simplifies bounds check. + state.input += '\0' + + while (state.input.charCodeAt(state.position) === 0x20/* Space */) { + state.lineIndent += 1 + state.position += 1 + } + + while (state.position < (state.length - 1)) { + readDocument(state) + } + + return state.documents +} + +function loadAll (input, iterator, options) { + if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') { + options = iterator + iterator = null + } + + const documents = loadDocuments(input, options) + + if (typeof iterator !== 'function') { + return documents + } + + for (let index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]) + } +} + +function load (input, options) { + const documents = loadDocuments(input, options) + + if (documents.length === 0) { + return undefined + } else if (documents.length === 1) { + return documents[0] + } + throw new YAMLException('expected a single document in the stream, but found more') +} + +module.exports.loadAll = loadAll +module.exports.load = load diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema.js new file mode 100644 index 0000000..52e8f41 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema.js @@ -0,0 +1,109 @@ +'use strict' + +const YAMLException = require('./exception') +const Type = require('./type') + +function compileList (schema, name) { + const result = [] + + schema[name].forEach(function (currentType) { + let newIndex = result.length + + result.forEach(function (previousType, previousIndex) { + if (previousType.tag === currentType.tag && + previousType.kind === currentType.kind && + previousType.multi === currentType.multi) { + newIndex = previousIndex + } + }) + + result[newIndex] = currentType + }) + + return result +} + +function compileMap (/* lists... */) { + const result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {}, + multi: { + scalar: [], + sequence: [], + mapping: [], + fallback: [] + } + } + function collectType (type) { + if (type.multi) { + result.multi[type.kind].push(type) + result.multi['fallback'].push(type) + } else { + result[type.kind][type.tag] = result['fallback'][type.tag] = type + } + } + + for (let index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType) + } + return result +} + +function Schema (definition) { + return this.extend(definition) +} + +Schema.prototype.extend = function extend (definition) { + let implicit = [] + let explicit = [] + + if (definition instanceof Type) { + // Schema.extend(type) + explicit.push(definition) + } else if (Array.isArray(definition)) { + // Schema.extend([ type1, type2, ... ]) + explicit = explicit.concat(definition) + } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) { + // Schema.extend({ explicit: [ type1, type2, ... ], implicit: [ type1, type2, ... ] }) + if (definition.implicit) implicit = implicit.concat(definition.implicit) + if (definition.explicit) explicit = explicit.concat(definition.explicit) + } else { + throw new YAMLException('Schema.extend argument should be a Type, [ Type ], ' + + 'or a schema definition ({ implicit: [...], explicit: [...] })') + } + + implicit.forEach(function (type) { + if (!(type instanceof Type)) { + throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.') + } + + if (type.loadKind && type.loadKind !== 'scalar') { + throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.') + } + + if (type.multi) { + throw new YAMLException('There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.') + } + }) + + explicit.forEach(function (type) { + if (!(type instanceof Type)) { + throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.') + } + }) + + const result = Object.create(Schema.prototype) + + result.implicit = (this.implicit || []).concat(implicit) + result.explicit = (this.explicit || []).concat(explicit) + + result.compiledImplicit = compileList(result, 'implicit') + result.compiledExplicit = compileList(result, 'explicit') + result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit) + + return result +} + +module.exports = Schema diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/core.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/core.js new file mode 100644 index 0000000..2660239 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/core.js @@ -0,0 +1,9 @@ +// Standard YAML's Core schema. +// http://www.yaml.org/spec/1.2/spec.html#id2804923 +// +// NOTE: JS-YAML does not support schema-specific tag resolution restrictions. +// So, Core schema has no distinctions from JSON schema is JS-YAML. + +'use strict' + +module.exports = require('./json') diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/default.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/default.js new file mode 100644 index 0000000..fb232d6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/default.js @@ -0,0 +1,20 @@ +// JS-YAML's default schema for `safeLoad` function. +// It is not described in the YAML specification. +// +// This schema is based on standard YAML's Core schema and includes most of +// extra types described at YAML tag repository. (http://yaml.org/type/) + +'use strict' + +module.exports = require('./core').extend({ + implicit: [ + require('../type/timestamp'), + require('../type/merge') + ], + explicit: [ + require('../type/binary'), + require('../type/omap'), + require('../type/pairs'), + require('../type/set') + ] +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/failsafe.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/failsafe.js new file mode 100644 index 0000000..ee63fe0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/failsafe.js @@ -0,0 +1,14 @@ +// Standard YAML's Failsafe schema. +// http://www.yaml.org/spec/1.2/spec.html#id2802346 + +'use strict' + +const Schema = require('../schema') + +module.exports = new Schema({ + explicit: [ + require('../type/str'), + require('../type/seq'), + require('../type/map') + ] +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/json.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/json.js new file mode 100644 index 0000000..ac75fa2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/schema/json.js @@ -0,0 +1,17 @@ +// Standard YAML's JSON schema. +// http://www.yaml.org/spec/1.2/spec.html#id2803231 +// +// NOTE: JS-YAML does not support schema-specific tag resolution restrictions. +// So, this schema is not such strict as defined in the YAML specification. +// It allows numbers in binary notaion, use `Null` and `NULL` as `null`, etc. + +'use strict' + +module.exports = require('./failsafe').extend({ + implicit: [ + require('../type/null'), + require('../type/bool'), + require('../type/int'), + require('../type/float') + ] +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/snippet.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/snippet.js new file mode 100644 index 0000000..71004a4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/snippet.js @@ -0,0 +1,96 @@ +'use strict' + +const common = require('./common') + +// get snippet for a single line, respecting maxLength +function getLine (buffer, lineStart, lineEnd, position, maxLineLength) { + let head = '' + let tail = '' + const maxHalfLength = Math.floor(maxLineLength / 2) - 1 + + if (position - lineStart > maxHalfLength) { + head = ' ... ' + lineStart = position - maxHalfLength + head.length + } + + if (lineEnd - position > maxHalfLength) { + tail = ' ...' + lineEnd = position + maxHalfLength - tail.length + } + + return { + str: head + buffer.slice(lineStart, lineEnd).replace(/\t/g, '→') + tail, + pos: position - lineStart + head.length // relative position + } +} + +function padStart (string, max) { + return common.repeat(' ', max - string.length) + string +} + +function makeSnippet (mark, options) { + options = Object.create(options || null) + + if (!mark.buffer) return null + + if (!options.maxLength) options.maxLength = 79 + if (typeof options.indent !== 'number') options.indent = 1 + if (typeof options.linesBefore !== 'number') options.linesBefore = 3 + if (typeof options.linesAfter !== 'number') options.linesAfter = 2 + + const re = /\r?\n|\r|\0/g + const lineStarts = [0] + const lineEnds = [] + let match + let foundLineNo = -1 + + while ((match = re.exec(mark.buffer))) { + lineEnds.push(match.index) + lineStarts.push(match.index + match[0].length) + + if (mark.position <= match.index && foundLineNo < 0) { + foundLineNo = lineStarts.length - 2 + } + } + + if (foundLineNo < 0) foundLineNo = lineStarts.length - 1 + + let result = '' + const lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length + const maxLineLength = options.maxLength - (options.indent + lineNoLength + 3) + + for (let i = 1; i <= options.linesBefore; i++) { + if (foundLineNo - i < 0) break + const line = getLine( + mark.buffer, + lineStarts[foundLineNo - i], + lineEnds[foundLineNo - i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]), + maxLineLength + ) + result = common.repeat(' ', options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n' + result + } + + const line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength) + result += common.repeat(' ', options.indent) + padStart((mark.line + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n' + result += common.repeat('-', options.indent + lineNoLength + 3 + line.pos) + '^' + '\n' + + for (let i = 1; i <= options.linesAfter; i++) { + if (foundLineNo + i >= lineEnds.length) break + const line = getLine( + mark.buffer, + lineStarts[foundLineNo + i], + lineEnds[foundLineNo + i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]), + maxLineLength + ) + result += common.repeat(' ', options.indent) + padStart((mark.line + i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n' + } + + return result.replace(/\n$/, '') +} + +module.exports = makeSnippet diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type.js new file mode 100644 index 0000000..8ec3dbe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type.js @@ -0,0 +1,66 @@ +'use strict' + +const YAMLException = require('./exception') + +const TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'multi', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'representName', + 'defaultStyle', + 'styleAliases' +] + +const YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' +] + +function compileStyleAliases (map) { + const result = {} + + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style + }) + }) + } + + return result +} + +function Type (tag, options) { + options = options || {} + + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new YAMLException('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.') + } + }) + + // TODO: Add tag format check. + this.options = options // keep original options in case user wants to extend this type later + this.tag = tag + this.kind = options['kind'] || null + this.resolve = options['resolve'] || function () { return true } + this.construct = options['construct'] || function (data) { return data } + this.instanceOf = options['instanceOf'] || null + this.predicate = options['predicate'] || null + this.represent = options['represent'] || null + this.representName = options['representName'] || null + this.defaultStyle = options['defaultStyle'] || null + this.multi = options['multi'] || false + this.styleAliases = compileStyleAliases(options['styleAliases'] || null) + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new YAMLException('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.') + } +} + +module.exports = Type diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/binary.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/binary.js new file mode 100644 index 0000000..dbe2300 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/binary.js @@ -0,0 +1,122 @@ +'use strict' + +const Type = require('../type') + +// [ 64, 65, 66 ] -> [ padding, CR, LF ] +const BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r' + +function resolveYamlBinary (data) { + if (data === null) return false + + let bitlen = 0 + const max = data.length + const map = BASE64_MAP + + // Convert one by one. + for (let idx = 0; idx < max; idx++) { + const code = map.indexOf(data.charAt(idx)) + + // Skip CR/LF + if (code > 64) continue + + // Fail on illegal characters + if (code < 0) return false + + bitlen += 6 + } + + // If there are any bits left, source was corrupted + return (bitlen % 8) === 0 +} + +function constructYamlBinary (data) { + const input = data.replace(/[\r\n=]/g, '') // remove CR/LF & padding to simplify scan + const max = input.length + const map = BASE64_MAP + let bits = 0 + const result = [] + + // Collect by 6*4 bits (3 bytes) + + for (let idx = 0; idx < max; idx++) { + if ((idx % 4 === 0) && idx) { + result.push((bits >> 16) & 0xFF) + result.push((bits >> 8) & 0xFF) + result.push(bits & 0xFF) + } + + bits = (bits << 6) | map.indexOf(input.charAt(idx)) + } + + // Dump tail + + const tailbits = (max % 4) * 6 + + if (tailbits === 0) { + result.push((bits >> 16) & 0xFF) + result.push((bits >> 8) & 0xFF) + result.push(bits & 0xFF) + } else if (tailbits === 18) { + result.push((bits >> 10) & 0xFF) + result.push((bits >> 2) & 0xFF) + } else if (tailbits === 12) { + result.push((bits >> 4) & 0xFF) + } + + return new Uint8Array(result) +} + +function representYamlBinary (object /*, style */) { + let result = '' + let bits = 0 + const max = object.length + const map = BASE64_MAP + + // Convert every three bytes to 4 ASCII characters. + + for (let idx = 0; idx < max; idx++) { + if ((idx % 3 === 0) && idx) { + result += map[(bits >> 18) & 0x3F] + result += map[(bits >> 12) & 0x3F] + result += map[(bits >> 6) & 0x3F] + result += map[bits & 0x3F] + } + + bits = (bits << 8) + object[idx] + } + + // Dump tail + + const tail = max % 3 + + if (tail === 0) { + result += map[(bits >> 18) & 0x3F] + result += map[(bits >> 12) & 0x3F] + result += map[(bits >> 6) & 0x3F] + result += map[bits & 0x3F] + } else if (tail === 2) { + result += map[(bits >> 10) & 0x3F] + result += map[(bits >> 4) & 0x3F] + result += map[(bits << 2) & 0x3F] + result += map[64] + } else if (tail === 1) { + result += map[(bits >> 2) & 0x3F] + result += map[(bits << 4) & 0x3F] + result += map[64] + result += map[64] + } + + return result +} + +function isBinary (obj) { + return Object.prototype.toString.call(obj) === '[object Uint8Array]' +} + +module.exports = new Type('tag:yaml.org,2002:binary', { + kind: 'scalar', + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/bool.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/bool.js new file mode 100644 index 0000000..ba3d44f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/bool.js @@ -0,0 +1,35 @@ +'use strict' + +const Type = require('../type') + +function resolveYamlBoolean (data) { + if (data === null) return false + + const max = data.length + + return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) || + (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE')) +} + +function constructYamlBoolean (data) { + return data === 'true' || + data === 'True' || + data === 'TRUE' +} + +function isBoolean (object) { + return Object.prototype.toString.call(object) === '[object Boolean]' +} + +module.exports = new Type('tag:yaml.org,2002:bool', { + kind: 'scalar', + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function (object) { return object ? 'true' : 'false' }, + uppercase: function (object) { return object ? 'TRUE' : 'FALSE' }, + camelcase: function (object) { return object ? 'True' : 'False' } + }, + defaultStyle: 'lowercase' +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/float.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/float.js new file mode 100644 index 0000000..07a5c93 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/float.js @@ -0,0 +1,99 @@ +'use strict' + +const common = require('../common') +const Type = require('../type') + +const YAML_FLOAT_PATTERN = new RegExp( + // 2.5e4, 2.5 and integers + '^(?:[-+]?(?:[0-9]+)(?:\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?' + + // .2e4, .2 + // special case, seems not from spec + '|\\.[0-9]+(?:[eE][-+]?[0-9]+)?' + + // .inf + '|[-+]?\\.(?:inf|Inf|INF)' + + // .nan + '|\\.(?:nan|NaN|NAN))$') + +const YAML_FLOAT_SPECIAL_PATTERN = new RegExp( + '^(?:' + + // .inf + '[-+]?\\.(?:inf|Inf|INF)' + + // .nan + '|\\.(?:nan|NaN|NAN))$') + +function resolveYamlFloat (data) { + if (data === null) return false + + if (!YAML_FLOAT_PATTERN.test(data)) { + return false + } + + if (isFinite(parseFloat(data, 10))) { + return true + } + + return YAML_FLOAT_SPECIAL_PATTERN.test(data) +} + +function constructYamlFloat (data) { + let value = data.toLowerCase() + const sign = value[0] === '-' ? -1 : 1 + + if ('+-'.indexOf(value[0]) >= 0) { + value = value.slice(1) + } + + if (value === '.inf') { + return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY + } else if (value === '.nan') { + return NaN + } + return sign * parseFloat(value, 10) +} + +const SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/ + +function representYamlFloat (object, style) { + if (isNaN(object)) { + switch (style) { + case 'lowercase': return '.nan' + case 'uppercase': return '.NAN' + case 'camelcase': return '.NaN' + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '.inf' + case 'uppercase': return '.INF' + case 'camelcase': return '.Inf' + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '-.inf' + case 'uppercase': return '-.INF' + case 'camelcase': return '-.Inf' + } + } else if (common.isNegativeZero(object)) { + return '-0.0' + } + + const res = object.toString(10) + + // JS stringifier can build scientific format without dots: 5e-100, + // while YAML requres dot: 5.e-100. Fix it with simple hack + + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res +} + +function isFloat (object) { + return (Object.prototype.toString.call(object) === '[object Number]') && + (object % 1 !== 0 || common.isNegativeZero(object)) +} + +module.exports = new Type('tag:yaml.org,2002:float', { + kind: 'scalar', + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: 'lowercase' +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/int.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/int.js new file mode 100644 index 0000000..759a62f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/int.js @@ -0,0 +1,142 @@ +'use strict' + +const common = require('../common') +const Type = require('../type') + +function isHexCode (c) { + return ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) || + ((c >= 0x41/* A */) && (c <= 0x46/* F */)) || + ((c >= 0x61/* a */) && (c <= 0x66/* f */)) +} + +function isOctCode (c) { + return ((c >= 0x30/* 0 */) && (c <= 0x37/* 7 */)) +} + +function isDecCode (c) { + return ((c >= 0x30/* 0 */) && (c <= 0x39/* 9 */)) +} + +function resolveYamlInteger (data) { + if (data === null) return false + + const max = data.length + let index = 0 + let hasDigits = false + + if (!max) return false + + let ch = data[index] + + // sign + if (ch === '-' || ch === '+') { + ch = data[++index] + } + + if (ch === '0') { + // 0 + if (index + 1 === max) return true + ch = data[++index] + + // base 2, base 8, base 16 + + if (ch === 'b') { + // base 2 + index++ + + for (; index < max; index++) { + ch = data[index] + if (ch !== '0' && ch !== '1') return false + hasDigits = true + } + return hasDigits && isFinite(parseYamlInteger(data)) + } + + if (ch === 'x') { + // base 16 + index++ + + for (; index < max; index++) { + if (!isHexCode(data.charCodeAt(index))) return false + hasDigits = true + } + return hasDigits && isFinite(parseYamlInteger(data)) + } + + if (ch === 'o') { + // base 8 + index++ + + for (; index < max; index++) { + if (!isOctCode(data.charCodeAt(index))) return false + hasDigits = true + } + return hasDigits && isFinite(parseYamlInteger(data)) + } + } + + // base 10 (except 0) + + for (; index < max; index++) { + if (!isDecCode(data.charCodeAt(index))) { + return false + } + hasDigits = true + } + + if (!hasDigits) return false + + return isFinite(parseYamlInteger(data)) +} + +function parseYamlInteger (data) { + let value = data + let sign = 1 + + let ch = value[0] + + if (ch === '-' || ch === '+') { + if (ch === '-') sign = -1 + value = value.slice(1) + ch = value[0] + } + + if (value === '0') return 0 + + if (ch === '0') { + if (value[1] === 'b') return sign * parseInt(value.slice(2), 2) + if (value[1] === 'x') return sign * parseInt(value.slice(2), 16) + if (value[1] === 'o') return sign * parseInt(value.slice(2), 8) + } + + return sign * parseInt(value, 10) +} + +function constructYamlInteger (data) { + return parseYamlInteger(data) +} + +function isInteger (object) { + return (Object.prototype.toString.call(object)) === '[object Number]' && + (object % 1 === 0 && !common.isNegativeZero(object)) +} + +module.exports = new Type('tag:yaml.org,2002:int', { + kind: 'scalar', + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1) }, + octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1) }, + decimal: function (obj) { return obj.toString(10) }, + hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1) } + }, + defaultStyle: 'decimal', + styleAliases: { + binary: [2, 'bin'], + octal: [8, 'oct'], + decimal: [10, 'dec'], + hexadecimal: [16, 'hex'] + } +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/map.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/map.js new file mode 100644 index 0000000..aa27874 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/map.js @@ -0,0 +1,8 @@ +'use strict' + +const Type = require('../type') + +module.exports = new Type('tag:yaml.org,2002:map', { + kind: 'mapping', + construct: function (data) { return data !== null ? data : {} } +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/merge.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/merge.js new file mode 100644 index 0000000..5781ff5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/merge.js @@ -0,0 +1,12 @@ +'use strict' + +const Type = require('../type') + +function resolveYamlMerge (data) { + return data === '<<' || data === null +} + +module.exports = new Type('tag:yaml.org,2002:merge', { + kind: 'scalar', + resolve: resolveYamlMerge +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/null.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/null.js new file mode 100644 index 0000000..0a9d7e5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/null.js @@ -0,0 +1,35 @@ +'use strict' + +const Type = require('../type') + +function resolveYamlNull (data) { + if (data === null) return true + + const max = data.length + + return (max === 1 && data === '~') || + (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL')) +} + +function constructYamlNull () { + return null +} + +function isNull (object) { + return object === null +} + +module.exports = new Type('tag:yaml.org,2002:null', { + kind: 'scalar', + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function () { return '~' }, + lowercase: function () { return 'null' }, + uppercase: function () { return 'NULL' }, + camelcase: function () { return 'Null' }, + empty: function () { return '' } + }, + defaultStyle: 'lowercase' +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/omap.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/omap.js new file mode 100644 index 0000000..d6caa3a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/omap.js @@ -0,0 +1,45 @@ +'use strict' + +const Type = require('../type') + +const _hasOwnProperty = Object.prototype.hasOwnProperty +const _toString = Object.prototype.toString + +function resolveYamlOmap (data) { + if (data === null) return true + + const objectKeys = {} + const object = data + + for (let index = 0, length = object.length; index < length; index += 1) { + const pair = object[index] + let pairHasKey = false + + if (_toString.call(pair) !== '[object Object]') return false + + let pairKey + for (pairKey in pair) { + if (_hasOwnProperty.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true + else return false + } + } + + if (!pairHasKey) return false + + if (_hasOwnProperty.call(objectKeys, pairKey)) return false + Object.defineProperty(objectKeys, pairKey, { value: true }) + } + + return true +} + +function constructYamlOmap (data) { + return data !== null ? data : [] +} + +module.exports = new Type('tag:yaml.org,2002:omap', { + kind: 'sequence', + resolve: resolveYamlOmap, + construct: constructYamlOmap +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/pairs.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/pairs.js new file mode 100644 index 0000000..4b90222 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/pairs.js @@ -0,0 +1,50 @@ +'use strict' + +const Type = require('../type') + +const _toString = Object.prototype.toString + +function resolveYamlPairs (data) { + if (data === null) return true + + const object = data + + const result = new Array(object.length) + + for (let index = 0, length = object.length; index < length; index += 1) { + const pair = object[index] + + if (_toString.call(pair) !== '[object Object]') return false + + const keys = Object.keys(pair) + + if (keys.length !== 1) return false + + result[index] = [keys[0], pair[keys[0]]] + } + + return true +} + +function constructYamlPairs (data) { + if (data === null) return [] + + const object = data + const result = new Array(object.length) + + for (let index = 0, length = object.length; index < length; index += 1) { + const pair = object[index] + + const keys = Object.keys(pair) + + result[index] = [keys[0], pair[keys[0]]] + } + + return result +} + +module.exports = new Type('tag:yaml.org,2002:pairs', { + kind: 'sequence', + resolve: resolveYamlPairs, + construct: constructYamlPairs +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/seq.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/seq.js new file mode 100644 index 0000000..e85ab66 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/seq.js @@ -0,0 +1,8 @@ +'use strict' + +const Type = require('../type') + +module.exports = new Type('tag:yaml.org,2002:seq', { + kind: 'sequence', + construct: function (data) { return data !== null ? data : [] } +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/set.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/set.js new file mode 100644 index 0000000..8e8a119 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/set.js @@ -0,0 +1,29 @@ +'use strict' + +const Type = require('../type') + +const _hasOwnProperty = Object.prototype.hasOwnProperty + +function resolveYamlSet (data) { + if (data === null) return true + + const object = data + + for (const key in object) { + if (_hasOwnProperty.call(object, key)) { + if (object[key] !== null) return false + } + } + + return true +} + +function constructYamlSet (data) { + return data !== null ? data : {} +} + +module.exports = new Type('tag:yaml.org,2002:set', { + kind: 'mapping', + resolve: resolveYamlSet, + construct: constructYamlSet +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/str.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/str.js new file mode 100644 index 0000000..072ef27 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/str.js @@ -0,0 +1,8 @@ +'use strict' + +const Type = require('../type') + +module.exports = new Type('tag:yaml.org,2002:str', { + kind: 'scalar', + construct: function (data) { return data !== null ? data : '' } +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/timestamp.js b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/timestamp.js new file mode 100644 index 0000000..05f323b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/lib/type/timestamp.js @@ -0,0 +1,88 @@ +'use strict' + +const Type = require('../type') + +const YAML_DATE_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9])' + // [2] month + '-([0-9][0-9])$') // [3] day + +const YAML_TIMESTAMP_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9]?)' + // [2] month + '-([0-9][0-9]?)' + // [3] day + '(?:[Tt]|[ \\t]+)' + // ... + '([0-9][0-9]?)' + // [4] hour + ':([0-9][0-9])' + // [5] minute + ':([0-9][0-9])' + // [6] second + '(?:\\.([0-9]*))?' + // [7] fraction + '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tzHour + '(?::([0-9][0-9]))?))?$') // [11] tzMinute + +function resolveYamlTimestamp (data) { + if (data === null) return false + if (YAML_DATE_REGEXP.exec(data) !== null) return true + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true + return false +} + +function constructYamlTimestamp (data) { + let fraction = 0 + let delta = null + + let match = YAML_DATE_REGEXP.exec(data) + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data) + + if (match === null) throw new Error('Date resolve error') + + // match: [1] year [2] month [3] day + + const year = +(match[1]) + const month = +(match[2]) - 1 // JS month starts with 0 + const day = +(match[3]) + + if (!match[4]) { // no hour + return new Date(Date.UTC(year, month, day)) + } + + // match: [4] hour [5] minute [6] second [7] fraction + + const hour = +(match[4]) + const minute = +(match[5]) + const second = +(match[6]) + + if (match[7]) { + fraction = match[7].slice(0, 3) + while (fraction.length < 3) { // milli-seconds + fraction += '0' + } + fraction = +fraction + } + + // match: [8] tz [9] tz_sign [10] tzHour [11] tzMinute + + if (match[9]) { + const tzHour = +(match[10]) + const tzMinute = +(match[11] || 0) + delta = (tzHour * 60 + tzMinute) * 60000 // delta in mili-seconds + if (match[9] === '-') delta = -delta + } + + const date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)) + + if (delta) date.setTime(date.getTime() - delta) + + return date +} + +function representYamlTimestamp (object /*, style */) { + return object.toISOString() +} + +module.exports = new Type('tag:yaml.org,2002:timestamp', { + kind: 'scalar', + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp +}) diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules/.bin/js-yaml b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules/.bin/js-yaml new file mode 100755 index 0000000..b2d7d67 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules/.bin/js-yaml @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../../bin/js-yaml.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../bin/js-yaml.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../../bin/js-yaml.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../../bin/js-yaml.js" "$@" +else + exec node "$basedir/../../bin/js-yaml.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/bin/js-yaml.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/package.json b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/package.json new file mode 100644 index 0000000..00755ab --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/package.json @@ -0,0 +1,83 @@ +{ + "name": "js-yaml", + "version": "4.3.1", + "description": "YAML 1.2 parser and serializer", + "keywords": [ + "yaml", + "parser", + "serializer", + "pyyaml" + ], + "author": "Vladimir Zapparov ", + "contributors": [ + "Aleksey V Zapparov (http://www.ixti.net/)", + "Vitaly Puzrin (https://github.com/puzrin)", + "Martin Grenfell (http://got-ravings.blogspot.com)" + ], + "license": "MIT", + "repository": "nodeca/js-yaml", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "files": [ + "index.js", + "lib/", + "bin/", + "dist/" + ], + "publishConfig": { + "tag": "v4-legacy" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + }, + "module": "./dist/js-yaml.mjs", + "exports": { + ".": { + "import": "./dist/js-yaml.mjs", + "require": "./index.js" + }, + "./package.json": "./package.json" + }, + "scripts": { + "lint": "eslint .", + "lint-fix": "eslint . --fix", + "test": "npm run lint && npm run test:core && npm run test:build", + "test:core": "node --test test/core/*.test.*", + "test:build": "npm run build && node --test test/build/*.test.*", + "coverage": "npm run build && c8 --include 'lib/**' -r text -r html -r lcov node --test test/core/*.test.*", + "build": "node support/build-dist.mjs", + "build:demo": "npm run lint && node support/build_demo.mjs", + "gh-demo": "npm run build:demo && gh-pages -d demo -f", + "prepack": "npm test && npm run build" + }, + "unpkg": "dist/js-yaml.min.js", + "jsdelivr": "dist/js-yaml.min.js", + "dependencies": { + "argparse": "^2.0.1" + }, + "devDependencies": { + "@babel/core": "8.0.1", + "@babel/preset-env": "8.0.1", + "@rollup/plugin-commonjs": "29.0.3", + "@rollup/plugin-terser": "0.4.4", + "c8": "^11.0.0", + "codemirror": "^5.65.21", + "eslint": "^9.39.4", + "fast-check": "^4.8.0", + "gh-pages": "^6.3.0", + "neostandard": "^0.13.0", + "tinybench": "^6.0.2", + "vite": "7.3.6", + "vite-plugin-node-polyfills": "^0.28.0", + "vite-plugin-singlefile": "^2.3.3", + "workerpool": "^10.0.2" + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/lock.yaml b/dsh-local-403-fix/node_modules/.pnpm/lock.yaml new file mode 100644 index 0000000..1e092c8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/lock.yaml @@ -0,0 +1,991 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@deepseek-ai/dsh-host-apiproxy': + specifier: ^0.1.0-rc.7 + version: 0.1.0-rc.7(227e91a6307a4a5d4a380ed795ce9271) + +packages: + + '@deepseek-ai/cordis-plugin-include@1.0.6': + resolution: {integrity: sha512-i1VXrZCbv6tk/iUgedCNjrxxArbWT3IvRZGB5sdqJ3ectnihivXXQbRZ8JJ73DSmAPvlMGmrbtjFAfm10yvXRg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/cordis-plugin-loader': ^1.0.2 + + '@deepseek-ai/cordis-plugin-loader@1.0.2': + resolution: {integrity: sha512-RIW9hoVyhYDWdCI9BsvtZccPde1ECLC4OAxupwowGTak78vwVTVdb3HezTSOK1Y1/Ax3Ru0LA1pYOB04CnTxIQ==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + node-addon-require-builtin: ^0.1.4 + peerDependenciesMeta: + node-addon-require-builtin: + optional: true + + '@deepseek-ai/cordis@4.0.1': + resolution: {integrity: sha512-YBdskTU2Po1kru3GgcUWUbkTsPMA9LkSQDAY8rBkFJeajdgcQad3QPJZE26JyK99Xb6HaASvoXg2DSUTeN/0Nw==} + hasBin: true + peerDependencies: + '@deepseek-ai/cordis-plugin-include': ^1.0.6 + '@deepseek-ai/cordis-plugin-loader': ^1.0.2 + peerDependenciesMeta: + '@deepseek-ai/cordis-plugin-include': + optional: true + '@deepseek-ai/cordis-plugin-loader': + optional: true + + '@deepseek-ai/cosmokit@1.8.2': + resolution: {integrity: sha512-muBOKtSrUKU5m/xpq8ZXWL6hQ/jgd4PhU2PqH97bcxIiLEJfNwZOGQEx4t/aS/GgxRAR+ra9pMHPMtTHU4sqqA==} + + '@deepseek-ai/dsh-agent-default-model@0.1.0-rc.7': + resolution: {integrity: sha512-zHtD4FAqxzidyNiyx1bpvLHdOTTsKnmjlHRqDS1KegIMSTNFmmp1B2bHdAUXp/OH7fPDmv+1ZXzDoJhBNUY9jA==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-settings': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-agent-presets@0.1.0-rc.7': + resolution: {integrity: sha512-T/VcMV7lrXCFmRKrtoMTAz5DAdUmku6hz95wbikRvRc0WizIwQ3R04ke9KIeDiQcxK8xkE8cx+IYqEWa9C5gPg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/cordis-plugin-include': ^1.0.6 + '@deepseek-ai/cordis-plugin-loader': ^1.0.2 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-atomic-write': ^0.1.0-rc.7 + '@deepseek-ai/dsh-home-paths': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-settings': ^0.1.0-rc.7 + '@deepseek-ai/dsh-system-prompt': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-agent@0.1.0-rc.7': + resolution: {integrity: sha512-AqBQavJYgbCUUYBHP7OGCaw8WN5082NXYQOoOfNRO72bub3E+/nWkl8b4B7BAJdFfyLo9ce+Kgb1BCHSJU/JLg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-system-prompt': ^0.1.0-rc.7 + '@deepseek-ai/dsh-typert-protocol': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-api-gateway@0.1.0-rc.7': + resolution: {integrity: sha512-tcoOuHMSqYqCtMxLjWBHKN+glS56XaUo3ImphvDvUkB84FyU3btHNJbYeAt2oXoWbHfOedcIRWpfNN4tSmhPwQ==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-client-connection': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-typert-registry': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-api-remotes@0.1.0-rc.7': + resolution: {integrity: sha512-dsP69u0avHRcJTPzngudqCm73UaTxNvGi/557DNPi3cOSoIh1SyPzPgk8W8rQQEFTL07rkwt8KfdQoMU5ga1fg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-agent-presets': ^0.1.0-rc.7 + '@deepseek-ai/dsh-api-gateway': ^0.1.0-rc.7 + '@deepseek-ai/dsh-commands': ^0.1.0-rc.7 + '@deepseek-ai/dsh-cordis-host-runner': ^0.1.0-rc.7 + '@deepseek-ai/dsh-credentials': ^0.1.0-rc.7 + '@deepseek-ai/dsh-goal': ^0.1.0-rc.7 + '@deepseek-ai/dsh-host-plugin-inventory': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-message-feedback': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-persistence': ^0.1.0-rc.7 + '@deepseek-ai/dsh-settings': ^0.1.0-rc.7 + '@deepseek-ai/dsh-typert-registry': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-atomic-write@0.1.0-rc.7': + resolution: {integrity: sha512-LxRx6K8FJ8bXZHiNhH6Rvj+jh/ZIpolmsmi138XrvMUGvbOBWE6QLbdzcgTgwrYZm5GP2kqqLe/3gQlgtt2bXA==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-attachment@0.1.0-rc.7': + resolution: {integrity: sha512-rsR/xVNOGIig8gXxhrKnkd6YD7aYliGtA/e7b4DlPawMpLhsItAh0HQ832n8LJn1aGZxKf68y9PRgzfljsveOQ==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-brand@0.1.0-rc.7': + resolution: {integrity: sha512-P7+w0fN40yXXQkV360p6jQi63pcl68OOWebNGN5gf8w8sguvni2mA1cU8RLZzDkRNFSZD+BCw3D4uWYM+hhh7A==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-client-connection@0.1.0-rc.7': + resolution: {integrity: sha512-JZWDKCbwKHOUcm7+JadKA3aJCSEB34XfPycCtPgdWfABIiHMaSpnmSVy/8Jed4hw6hxhnR6A3rnvW02Xr2yqwA==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-host-webserver': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-code-runtime@0.1.0-rc.7': + resolution: {integrity: sha512-vzW82eU4so0qJQ/XS7BGBUSguJMAgEOW3GaJJW0g+W5ysBJg+UC/Jjo1Np8mPjSpjjl4eoyXpshJzrwjoxCpRg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-commands@0.1.0-rc.7': + resolution: {integrity: sha512-SYrQpJZQ4fvfyfw3IJ5j0goUiOFZb1ZhcANgUp99HVlhhN/l1oEOAvEZL1efaSE7KIG6qp4JEn7iLtNdo8+mEA==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-typert-protocol': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-cordis-host-runner@0.1.0-rc.7': + resolution: {integrity: sha512-A7R39cSNsLwjm+P54bUFBUd5+YbdyKkC5cLQqYt12STt0Z06az10Qt5rsL25rnWkxW7x7Ql0wVA83tOmO2oy0g==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-tools': ^0.1.0-rc.7 + '@deepseek-ai/dsh-typert-protocol': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-credentials@0.1.0-rc.7': + resolution: {integrity: sha512-24oY36x90GN3QG2BASlryjzsO5eLA1U9vsvH1tPtBRJ1pBC6JqnW2v0SfDI/pcMT0ZbWo0uEATiik8rrv6xRpA==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-goal@0.1.0-rc.7': + resolution: {integrity: sha512-/pI2o0YcP21ReT+OQx7aA8SyUsnuEHxTQtMbu3DvN9ChvaFeptCTXGvHWocwVtzEEi48mdvAXF4Mx0Ptj1LJYA==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-projection': ^0.1.0-rc.7 + '@deepseek-ai/dsh-typert-protocol': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-home-paths@0.1.0-rc.7': + resolution: {integrity: sha512-9Bu0eAbPw/FfCNpiX9hvyP5wedMUUQBc2sVTtU+xtH27/iUPxXoamFtBt3ydBJUeuVhja/leuhJ/d3MRhXO9fQ==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-host-apiproxy@0.1.0-rc.7': + resolution: {integrity: sha512-oBCIJzzvVXijtxAPqSlQUlYTywEmkn3JEpMB2PM8W4UafnxNhqvDh8ikGE7/1y6KWoFUS4jHGwerUzyp3C6oWw==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent-presets': ^0.1.0-rc.7 + '@deepseek-ai/dsh-cordis-host-runner': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-host-directory-picker@0.1.0-rc.7': + resolution: {integrity: sha512-CamVZ4wOjGcgzOiRFQtG0J0hy4EY3nXJBRFs0S397+H7b9eJUTtaMdOxP5w7VhMQ0Aq2ND7gpadwIcFaqINsMw==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-host-plugin-inventory@0.1.0-rc.7': + resolution: {integrity: sha512-B8ITfMnBAdgkkuvoMrBdVgydhsCYGnP8XIGXIouOQyT9/eWbD3WqO76XG+u+e2G36ACXu2NaIxsRh3ijzyorwg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/cordis-plugin-loader': ^1.0.2 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-typert-protocol': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-host-webserver@0.1.0-rc.7': + resolution: {integrity: sha512-ip6HeN9YpWJXgWKAWsL3JUrI8j+MHEvbQ/m3U5ubP/Pc0AQ9x+6xZ/nYe+22112I12rihiwb85ykFwFfx0QbKQ==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-invariants@0.1.0-rc.7': + resolution: {integrity: sha512-PnO1F4aZGUmqZPyuPJpBUfQ4DZmjCGCNGr0yuN2iURTP/e6h0kGnTNTYgR2NqMvAtpP66WNiHhvH2LMqumk1+A==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + + '@deepseek-ai/dsh-jobs@0.1.0-rc.7': + resolution: {integrity: sha512-+omM89dEsaiAL1XtsSTMmRF46POp5g25Qs5KVj+Zfrk7whlXjLXwFiaukt/htdVdHIOM51qM+tCleqlHOU0Chw==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-llm@0.1.0-rc.7': + resolution: {integrity: sha512-VaB9kQ8XOA+R5jtsWf92QMc1WpaatEAFUvQePGUYrzQ7Z86b9VhQQzmchh5VmknT4oRSSdn0re5tReCvfcYNXQ==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-attachment': ^0.1.0-rc.7 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-timeout': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-message-feedback@0.1.0-rc.7': + resolution: {integrity: sha512-P/Inw7dQMZCC6I6NC6G0UF9SeOVlpQxOBg2+LoCdvyTt40itDow2wmlThqkQDIt4UMHLT4yRc0Gd6a4gmTNJ2w==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-persistence': ^0.1.0-rc.7 + '@deepseek-ai/dsh-storage-domain': ^0.1.0-rc.7 + '@deepseek-ai/dsh-typert-protocol': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-native-command@0.1.0-rc.7': + resolution: {integrity: sha512-c7NiAYPx5Ho2ZYOODRvt0yTZ9l00n7QvRh8paiyLaYBOuzo30KDo5wTJXGLxMkfzi6EQsWw1tljd8MnpGL2P4Q==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-scope@0.1.0-rc.7': + resolution: {integrity: sha512-8gn+sANXhpv+9egbNwq49/uI3XhbmB33obo9yMyzyzruan3zFoxeH4UV54jTC2hjbu8gFNPsyNam9AAtRV8/Cg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-session-persistence@0.1.0-rc.7': + resolution: {integrity: sha512-NFH1uIGQDgMFOijgAv8lLWRiY3eHFEZW2alwuHlu4C32P4+jdChh9fjPlzBar3ZZTq0ZW0qWCdbYZS02DNxsvA==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-timeout': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-session-projection-cache@0.1.0-rc.7': + resolution: {integrity: sha512-qWf7p2Xgr0LnY4o466ei3L/81QbGFQcCbEi+4XX9rxLKgnU+RvlQzwmIilrgz9N2hK/RqwS1Nb03bFRisxVeaw==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-persistence': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-projection': ^0.1.0-rc.7 + '@deepseek-ai/dsh-storage-domain': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-session-projection@0.1.0-rc.7': + resolution: {integrity: sha512-BXehLYt6wYnV0PNNhv5GECePkH1w+1yuu/R63d2tdYdUQ7XVrd6tu5hMwfTH0P9AnBDxJir08FRu2WKO69JypA==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-session-query@0.1.0-rc.7': + resolution: {integrity: sha512-JKlEpByllYQU9JZLadrS3ClWCVZMcKRB4nc6iCWuNExyRi/Whwa5GicKFs+jXwGKe/rdSbTCom/jYLwkqipjuw==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-persistence': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-title': ^0.1.0-rc.7 + peerDependenciesMeta: + '@deepseek-ai/dsh-session-persistence': + optional: true + + '@deepseek-ai/dsh-session-title@0.1.0-rc.7': + resolution: {integrity: sha512-jhFiZa/C58zchuJkBodnkiPil7AEK8mHfB/hMOAW3N/7tUg5nbMLBERNqHdDMbIrvhTndrF4SN9qy+ltUf0cOQ==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-projection': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-session@0.1.0-rc.7': + resolution: {integrity: sha512-02WVTkqIH+TyDL7dhMN3Hm+qcTEdhD0fVDC0aIAyND2fBdXj3CagEXXvpmt3mzwWfKwOTGL1RdxtC6pMA4Bl1A==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + '@deepseek-ai/dsh-typert-protocol': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-settings@0.1.0-rc.7': + resolution: {integrity: sha512-cS1+StK2xIVykrskw+KrO+hKJxYaVVgY2Jex2we5zASTNLHYCj74WQluPlaFjFgnXoZ1RYz8HNXL5/Ho6h1Ynw==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/schemastery': ^3.18.1 + + '@deepseek-ai/dsh-skill@0.1.0-rc.7': + resolution: {integrity: sha512-tDaqB1TOs27fSt6FZdjvPs4THXAFKoKOEgQG+iFUv63O5bm+glyLY3K1LTK8JeofB4lg3+4JIAeWRslnLJH57w==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-storage-domain@0.1.0-rc.7': + resolution: {integrity: sha512-UxXwoCB0q4+/F+zddvi8I4LknTIlGD/1ec57Ym52kWRb7a8qGgrcIYrOC3yPCozn8rkirAuhEAkyAhR6AO5QDw==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-storage': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-storage@0.1.0-rc.7': + resolution: {integrity: sha512-M+6+SOjWWcfYoGASBMx+b1sHmWPFAHXF57rE/Mew9k5tHC5bEV8+owWwYOWQfv41eO1FfRMibZd0rH6mwPNApg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-subagent@0.1.0-rc.7': + resolution: {integrity: sha512-PEpA9XT6E4hg7N8m7GYQyDLwFUwoqWTz0Cm9SrdAoNcju4byG08qy4+muDZbG0a1tm3PR4rxNB5zKcobDhDocg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-agent-presets': ^0.1.0-rc.7 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-jobs': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-sandbox': ^0.1.0-rc.7 + '@deepseek-ai/dsh-sandbox-policy': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-persistence': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-projection': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-projection-cache': ^0.1.0-rc.7 + '@deepseek-ai/dsh-tools': ^0.1.0-rc.7 + '@deepseek-ai/dsh-user-approval': ^0.1.0-rc.7 + peerDependenciesMeta: + '@deepseek-ai/dsh-agent-presets': + optional: true + '@deepseek-ai/dsh-jobs': + optional: true + '@deepseek-ai/dsh-sandbox': + optional: true + '@deepseek-ai/dsh-sandbox-policy': + optional: true + '@deepseek-ai/dsh-session-persistence': + optional: true + '@deepseek-ai/dsh-session-projection': + optional: true + '@deepseek-ai/dsh-session-projection-cache': + optional: true + '@deepseek-ai/dsh-user-approval': + optional: true + + '@deepseek-ai/dsh-system-prompt@0.1.0-rc.7': + resolution: {integrity: sha512-Rair2ZkzgoIIr+UstYVYeqeUgORNPIW1LNcsXz3Zjglx4FGjsmzs0UALdNYvSBpBvCLNmt4E6+XQIrBbS/s9jw==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-timeout@0.1.0-rc.7': + resolution: {integrity: sha512-Ufl9G7zP7Tky/zkXscavEiolEfAwutfbPeLb5sUU/tPQlDykhh1NwGrarNJ11fdR723zmA/3co4LgxtDtWCOEQ==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-tools@0.1.0-rc.7': + resolution: {integrity: sha512-7Kq3EEv354aNcxbS0NRfxxyJiZhCsvFV/03a3MdkYO/gG2eM9+E4xQum0N2FL5bw7JiGlgw8jdLMkcNGmavEaA==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-code-runtime': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-system-prompt': ^0.1.0-rc.7 + '@deepseek-ai/dsh-user-approval': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7': + resolution: {integrity: sha512-R7qdvaRRHbz5xijoVOxueeBB/VT0eDzuQNQN4iNEBUbI/L9xG9bZutktTQlgrIlBSn1sPH4pLqiCiM6ErQPTaQ==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-typert-registry@0.1.0-rc.7': + resolution: {integrity: sha512-7AQNJLNZTw7/5DzjbfBy4dRqr6VSwc74HBOSPpxm0zzzbmXOEqRCRzMps25IByoAeltRz1ZyY4fzN3tcYa+XwQ==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-user-approval@0.1.0-rc.7': + resolution: {integrity: sha512-kYMpU6eg1m1BcfSC4FLWUcNH/QAE8tcu0WRkQzqzoCw8bK/Nl3dqHtd2qSVzI/emIviTulM5I230e4wPi/kuVg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + '@deepseek-ai/dsh-scope': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-system-prompt': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-user-questions@0.1.0-rc.7': + resolution: {integrity: sha512-dfT6pj84lJdhrtbW2pV6hRftoKDkqx0aJevrhUhOy7Lv3CqTOheuLwwyT69Lww+n/q80Z+yp41qJq9loCkrOaw==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-agent': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-llm': ^0.1.0-rc.7 + + '@deepseek-ai/dsh-workspace@0.1.0-rc.7': + resolution: {integrity: sha512-0czW0bI+uFFOS8h8eJ9SGZSdv+StEsa/+E1WEjZQXVeIOxo520Pv47dq+Z3mTyBfV8gJB+UcY0AQ3F0FddYohg==} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/dsh-brand': ^0.1.0-rc.7 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session': ^0.1.0-rc.7 + '@deepseek-ai/dsh-session-persistence': ^0.1.0-rc.7 + '@deepseek-ai/dsh-storage': ^0.1.0-rc.7 + '@deepseek-ai/dsh-storage-domain': ^0.1.0-rc.7 + + '@deepseek-ai/schemastery@3.18.1': + resolution: {integrity: sha512-Qn0FCSwCQnpnj6SB31I6i2sIKgKWnkbJM8O0EU91Gv2UsYVvtZTl6IA0sCwk2e2MZf5S8w5hpq9QkeVvK9qwxg==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + fflate@0.8.3: + resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} + + js-yaml@4.3.1: + resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} + hasBin: true + + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + +snapshots: + + '@deepseek-ai/cordis-plugin-include@1.0.6(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/cordis-plugin-loader': 1.0.2(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/cosmokit': 1.8.2 + js-yaml: 4.3.1 + + '@deepseek-ai/cordis-plugin-loader@1.0.2(@deepseek-ai/cordis@4.0.1)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/cosmokit': 1.8.2 + + '@deepseek-ai/cordis@4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2)': + dependencies: + '@deepseek-ai/cosmokit': 1.8.2 + '@standard-schema/spec': 1.1.0 + optionalDependencies: + '@deepseek-ai/cordis-plugin-include': 1.0.6(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/cordis-plugin-loader': 1.0.2(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/cosmokit@1.8.2': {} + + '@deepseek-ai/dsh-agent-default-model@0.1.0-rc.7(1eb7ceb2998733be9eba21a37a3dc291)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-settings': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1) + '@deepseek-ai/schemastery': 3.18.1 + + '@deepseek-ai/dsh-agent-presets@0.1.0-rc.7(c0f9f44edab94cddae92cd4b4f319bab)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/cordis-plugin-include': 1.0.6(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/cordis-plugin-loader': 1.0.2(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-atomic-write': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-home-paths': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-settings': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1) + '@deepseek-ai/dsh-system-prompt': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/schemastery': 3.18.1 + js-yaml: 4.3.1 + + '@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-system-prompt': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + + '@deepseek-ai/dsh-api-gateway@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-client-connection@0.1.0-rc.7)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-client-connection': 0.1.0-rc.7(18ff0c05ab41670b8daa2e2e166479db) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-typert-registry': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + + '@deepseek-ai/dsh-api-remotes@0.1.0-rc.7(022498c733cc9b813e36f108b907ce4c)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-agent-presets': 0.1.0-rc.7(c0f9f44edab94cddae92cd4b4f319bab) + '@deepseek-ai/dsh-api-gateway': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-client-connection@0.1.0-rc.7)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-commands': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-cordis-host-runner': 0.1.0-rc.7(2a80d56ba6af58ca8075e00e0fa2157b) + '@deepseek-ai/dsh-credentials': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-goal': 0.1.0-rc.7(9616cea51a4bea931c5522310292a042) + '@deepseek-ai/dsh-host-plugin-inventory': 0.1.0-rc.7(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-message-feedback': 0.1.0-rc.7(1fcfefbbf5e365eda1a59fadd94056b9) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-session-persistence': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-settings': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1) + '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-typert-registry': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + + '@deepseek-ai/dsh-atomic-write@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-client-connection@0.1.0-rc.7(18ff0c05ab41670b8daa2e2e166479db)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-attachment': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-commands': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-host-apiproxy': 0.1.0-rc.7(227e91a6307a4a5d4a380ed795ce9271) + '@deepseek-ai/dsh-host-webserver': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-tools': 0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa) + '@deepseek-ai/schemastery': 3.18.1 + ws: 8.21.3 + transitivePeerDependencies: + - '@deepseek-ai/dsh-agent' + - '@deepseek-ai/dsh-agent-presets' + - '@deepseek-ai/dsh-api-gateway' + - '@deepseek-ai/dsh-brand' + - '@deepseek-ai/dsh-code-runtime' + - '@deepseek-ai/dsh-cordis-host-runner' + - '@deepseek-ai/dsh-host-plugin-inventory' + - '@deepseek-ai/dsh-message-feedback' + - '@deepseek-ai/dsh-sandbox' + - '@deepseek-ai/dsh-sandbox-policy' + - '@deepseek-ai/dsh-scope' + - '@deepseek-ai/dsh-storage' + - '@deepseek-ai/dsh-storage-domain' + - '@deepseek-ai/dsh-system-prompt' + - '@deepseek-ai/dsh-timeout' + - '@deepseek-ai/dsh-typert-protocol' + - '@deepseek-ai/dsh-typert-registry' + - '@deepseek-ai/dsh-user-approval' + - bufferutil + - utf-8-validate + + '@deepseek-ai/dsh-code-runtime@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-commands@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + zod: 4.4.3 + + '@deepseek-ai/dsh-cordis-host-runner@0.1.0-rc.7(2a80d56ba6af58ca8075e00e0fa2157b)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-tools': 0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa) + '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/schemastery': 3.18.1 + zod: 4.4.3 + + '@deepseek-ai/dsh-credentials@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-goal@0.1.0-rc.7(9616cea51a4bea931c5522310292a042)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-session-projection': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)) + '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/schemastery': 3.18.1 + zod: 4.4.3 + + '@deepseek-ai/dsh-home-paths@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-host-apiproxy@0.1.0-rc.7(227e91a6307a4a5d4a380ed795ce9271)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-agent-default-model': 0.1.0-rc.7(1eb7ceb2998733be9eba21a37a3dc291) + '@deepseek-ai/dsh-agent-presets': 0.1.0-rc.7(c0f9f44edab94cddae92cd4b4f319bab) + '@deepseek-ai/dsh-api-remotes': 0.1.0-rc.7(022498c733cc9b813e36f108b907ce4c) + '@deepseek-ai/dsh-attachment': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-commands': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-cordis-host-runner': 0.1.0-rc.7(2a80d56ba6af58ca8075e00e0fa2157b) + '@deepseek-ai/dsh-credentials': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-goal': 0.1.0-rc.7(9616cea51a4bea931c5522310292a042) + '@deepseek-ai/dsh-host-directory-picker': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-jobs': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-native-command': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-session-persistence': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-session-projection': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)) + '@deepseek-ai/dsh-session-projection-cache': 0.1.0-rc.7(5ae699d01eec9f3ccaa1e8c13f88dd36) + '@deepseek-ai/dsh-session-query': 0.1.0-rc.7(fa24861d08a9d735fc78888af6ddf326) + '@deepseek-ai/dsh-session-title': 0.1.0-rc.7(54a387d0d580a07b8dbef208df0b04c2) + '@deepseek-ai/dsh-settings': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1) + '@deepseek-ai/dsh-skill': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-subagent': 0.1.0-rc.7(17b22c2aa5d99096c13835bb226cad51) + '@deepseek-ai/dsh-tools': 0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa) + '@deepseek-ai/dsh-user-approval': 0.1.0-rc.7(6b8cefd624fd84694a941b103cc9b3fb) + '@deepseek-ai/dsh-user-questions': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))) + '@deepseek-ai/dsh-workspace': 0.1.0-rc.7(52d55750df813bb508c3c8815dfcc2bd) + '@deepseek-ai/schemastery': 3.18.1 + fflate: 0.8.3 + zod: 4.4.3 + transitivePeerDependencies: + - '@deepseek-ai/dsh-api-gateway' + - '@deepseek-ai/dsh-code-runtime' + - '@deepseek-ai/dsh-host-plugin-inventory' + - '@deepseek-ai/dsh-message-feedback' + - '@deepseek-ai/dsh-sandbox' + - '@deepseek-ai/dsh-sandbox-policy' + - '@deepseek-ai/dsh-scope' + - '@deepseek-ai/dsh-storage' + - '@deepseek-ai/dsh-storage-domain' + - '@deepseek-ai/dsh-system-prompt' + - '@deepseek-ai/dsh-timeout' + - '@deepseek-ai/dsh-typert-protocol' + - '@deepseek-ai/dsh-typert-registry' + + '@deepseek-ai/dsh-host-directory-picker@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-host-plugin-inventory@0.1.0-rc.7(@deepseek-ai/cordis-plugin-loader@1.0.2)(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/cordis-plugin-loader': 1.0.2(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + zod: 4.4.3 + + '@deepseek-ai/dsh-host-webserver@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/schemastery': 3.18.1 + + '@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/schemastery': 3.18.1 + + '@deepseek-ai/dsh-jobs@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + + '@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-attachment': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-timeout': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/schemastery': 3.18.1 + + '@deepseek-ai/dsh-message-feedback@0.1.0-rc.7(1fcfefbbf5e365eda1a59fadd94056b9)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-session-persistence': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-storage-domain': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/schemastery': 3.18.1 + zod: 4.4.3 + + '@deepseek-ai/dsh-native-command@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-session-persistence@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-timeout': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + + '@deepseek-ai/dsh-session-projection-cache@0.1.0-rc.7(5ae699d01eec9f3ccaa1e8c13f88dd36)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-session-persistence': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-session-projection': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)) + '@deepseek-ai/dsh-storage-domain': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/schemastery': 3.18.1 + zod: 4.4.3 + + '@deepseek-ai/dsh-session-projection@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + zod: 4.4.3 + + '@deepseek-ai/dsh-session-query@0.1.0-rc.7(fa24861d08a9d735fc78888af6ddf326)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-session-title': 0.1.0-rc.7(54a387d0d580a07b8dbef208df0b04c2) + optionalDependencies: + '@deepseek-ai/dsh-session-persistence': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + + '@deepseek-ai/dsh-session-title@0.1.0-rc.7(54a387d0d580a07b8dbef208df0b04c2)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-session-projection': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)) + '@deepseek-ai/schemastery': 3.18.1 + zod: 4.4.3 + + '@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + + '@deepseek-ai/dsh-settings@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/schemastery': 3.18.1 + + '@deepseek-ai/dsh-skill@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/schemastery': 3.18.1 + + '@deepseek-ai/dsh-storage-domain@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-storage': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/schemastery': 3.18.1 + zod: 4.4.3 + + '@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-subagent@0.1.0-rc.7(17b22c2aa5d99096c13835bb226cad51)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-tools': 0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa) + zod: 4.4.3 + optionalDependencies: + '@deepseek-ai/dsh-agent-presets': 0.1.0-rc.7(c0f9f44edab94cddae92cd4b4f319bab) + '@deepseek-ai/dsh-jobs': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)) + '@deepseek-ai/dsh-session-persistence': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-session-projection': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346)) + '@deepseek-ai/dsh-session-projection-cache': 0.1.0-rc.7(5ae699d01eec9f3ccaa1e8c13f88dd36) + '@deepseek-ai/dsh-user-approval': 0.1.0-rc.7(6b8cefd624fd84694a941b103cc9b3fb) + + '@deepseek-ai/dsh-system-prompt@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/schemastery': 3.18.1 + + '@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-tools@0.1.0-rc.7(38c91eb2d47c5b4ba2c8ead86dfcb4aa)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-code-runtime': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-system-prompt': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-user-approval': 0.1.0-rc.7(6b8cefd624fd84694a941b103cc9b3fb) + '@deepseek-ai/schemastery': 3.18.1 + + '@deepseek-ai/dsh-typert-protocol@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + + '@deepseek-ai/dsh-typert-registry@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + zod: 4.4.3 + + '@deepseek-ai/dsh-user-approval@0.1.0-rc.7(6b8cefd624fd84694a941b103cc9b3fb)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-scope': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-system-prompt': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-scope@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/schemastery': 3.18.1 + + '@deepseek-ai/dsh-user-questions@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-agent@0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-llm@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))))': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-agent': 0.1.0-rc.7(1e28fca6adb316c000fd361f8e5f3a08) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-llm': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + + '@deepseek-ai/dsh-workspace@0.1.0-rc.7(52d55750df813bb508c3c8815dfcc2bd)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + '@deepseek-ai/dsh-brand': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/dsh-session': 0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346) + '@deepseek-ai/dsh-session-persistence': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.7(1dcde9bfc9fa0140c66648fbcb67b346))(@deepseek-ai/dsh-timeout@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + '@deepseek-ai/dsh-storage': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-storage-domain': 0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-storage@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.7(@deepseek-ai/cordis@4.0.1))) + zod: 4.4.3 + + '@deepseek-ai/schemastery@3.18.1': + dependencies: + '@deepseek-ai/cosmokit': 1.8.2 + '@standard-schema/spec': 1.1.0 + + '@standard-schema/spec@1.1.0': {} + + argparse@2.0.1: {} + + fflate@0.8.3: {} + + js-yaml@4.3.1: + dependencies: + argparse: 2.0.1 + + ws@8.21.3: {} + + zod@4.4.3: {} diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/.bin/cordis b/dsh-local-403-fix/node_modules/.pnpm/node_modules/.bin/cordis new file mode 100755 index 0000000..b2f401d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/.bin/cordis @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../@deepseek-ai/cordis/bin.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../@deepseek-ai/cordis/bin.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../@deepseek-ai/cordis/bin.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../@deepseek-ai/cordis/bin.js" "$@" +else + exec node "$basedir/../@deepseek-ai/cordis/bin.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis/bin.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/.bin/js-yaml b/dsh-local-403-fix/node_modules/.pnpm/node_modules/.bin/js-yaml new file mode 100755 index 0000000..d5768d1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/.bin/js-yaml @@ -0,0 +1,55 @@ +#!/bin/sh +# Resolve $0 through symlinks so basedir is the shim's real directory. +# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim. +link="$0" +hops=0 +while [ -L "$link" ] && [ "$hops" -lt 40 ]; do + hops=$((hops+1)) + target=$(readlink "$link") + case "$target" in + /*) link="$target" ;; + *) link="$(dirname "$link")/$target" ;; + esac +done +basedir=$(dirname "$(echo "$link" | sed -e 's,\\,/,g')") +basedir_win="$basedir" +exe="" +msys="" + +case `uname -a` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir_win=`cygpath -w "$basedir"` + fi + exe=".exe" + msys="true" + ;; + *WSL2*) + if command -v wslpath > /dev/null 2>&1; then + basedir_win="$(wslpath -w "$basedir" 2> /dev/null)" + if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then + basedir_win="$basedir" + else + exe=".exe" + fi + fi + ;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/js-yaml@4.3.1/node_modules:/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then + exec "$basedir/node.exe" "$basedir_win/../js-yaml/bin/js-yaml.js" "$@" +elif [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../js-yaml/bin/js-yaml.js" "$@" +elif command -v node >/dev/null 2>&1; then + exec node "$basedir/../js-yaml/bin/js-yaml.js" "$@" +elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then + exec node.exe "$basedir_win/../js-yaml/bin/js-yaml.js" "$@" +else + exec node "$basedir/../js-yaml/bin/js-yaml.js" "$@" +fi +# cmd-shim-target=/home/salmonstill/projects/server/dsh-local-403-fix/node_modules/.pnpm/node_modules/js-yaml/bin/js-yaml.js diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis new file mode 120000 index 0000000..af53495 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis @@ -0,0 +1 @@ +../../@deepseek-ai+cordis@4.0.1_@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2/node_modules/@deepseek-ai/cordis \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis-plugin-include b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis-plugin-include new file mode 120000 index 0000000..ecedb52 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis-plugin-include @@ -0,0 +1 @@ +../../@deepseek-ai+cordis-plugin-include@1.0.6_@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-include \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis-plugin-loader b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis-plugin-loader new file mode 120000 index 0000000..e001f96 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cordis-plugin-loader @@ -0,0 +1 @@ +../../@deepseek-ai+cordis-plugin-loader@1.0.2_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/cordis-plugin-loader \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cosmokit b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cosmokit new file mode 120000 index 0000000..f2e2eb9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/cosmokit @@ -0,0 +1 @@ +../../@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent new file mode 120000 index 0000000..f7c2dd5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-agent@0.1.0-rc.7_1e28fca6adb316c000fd361f8e5f3a08/node_modules/@deepseek-ai/dsh-agent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent-default-model b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent-default-model new file mode 120000 index 0000000..f050253 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent-default-model @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-agent-default-model@0.1.0-rc.7_1eb7ceb2998733be9eba21a37a3dc291/node_modules/@deepseek-ai/dsh-agent-default-model \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent-presets b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent-presets new file mode 120000 index 0000000..469d36f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-agent-presets @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-agent-presets@0.1.0-rc.7_c0f9f44edab94cddae92cd4b4f319bab/node_modules/@deepseek-ai/dsh-agent-presets \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-api-gateway b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-api-gateway new file mode 120000 index 0000000..ebb3a38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-api-gateway @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-api-gateway@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-clie_ac42a25ae6ae684b0a113b07b0eea6fd/node_modules/@deepseek-ai/dsh-api-gateway \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-api-remotes b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-api-remotes new file mode 120000 index 0000000..f9d0c36 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-api-remotes @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-api-remotes@0.1.0-rc.7_022498c733cc9b813e36f108b907ce4c/node_modules/@deepseek-ai/dsh-api-remotes \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-atomic-write b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-atomic-write new file mode 120000 index 0000000..169fb31 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-atomic-write @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-atomic-write@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_64f51587e4d86f1947ff5d455560d29c/node_modules/@deepseek-ai/dsh-atomic-write \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-attachment b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-attachment new file mode 120000 index 0000000..779c6ec --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-attachment @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-attachment@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand_a449f8aefc4db09024dfd8133adf8e7b/node_modules/@deepseek-ai/dsh-attachment \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-brand b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-brand new file mode 120000 index 0000000..58a5c2e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-brand @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-brand@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_6a8c34f5312bab201025249905159fbe/node_modules/@deepseek-ai/dsh-brand \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-client-connection b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-client-connection new file mode 120000 index 0000000..3c01a38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-client-connection @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-client-connection@0.1.0-rc.7_18ff0c05ab41670b8daa2e2e166479db/node_modules/@deepseek-ai/dsh-client-connection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-code-runtime b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-code-runtime new file mode 120000 index 0000000..6e8309d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-code-runtime @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-code-runtime@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-inv_dbb5d3234cab2721ee2314790c820c11/node_modules/@deepseek-ai/dsh-code-runtime \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-commands b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-commands new file mode 120000 index 0000000..ef4700f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-commands @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-commands@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0_cbc96102c3e6d869c612b5d42d4d4cc7/node_modules/@deepseek-ai/dsh-commands \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-cordis-host-runner b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-cordis-host-runner new file mode 120000 index 0000000..1d0b8e8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-cordis-host-runner @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-cordis-host-runner@0.1.0-rc.7_2a80d56ba6af58ca8075e00e0fa2157b/node_modules/@deepseek-ai/dsh-cordis-host-runner \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-credentials b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-credentials new file mode 120000 index 0000000..1bd170e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-credentials @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-credentials@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-bran_6df341f05d8885c9ff6d5b51570dc623/node_modules/@deepseek-ai/dsh-credentials \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-goal b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-goal new file mode 120000 index 0000000..4625d85 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-goal @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-goal@0.1.0-rc.7_9616cea51a4bea931c5522310292a042/node_modules/@deepseek-ai/dsh-goal \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-home-paths b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-home-paths new file mode 120000 index 0000000..6b88fe0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-home-paths @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-home-paths@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invar_769580a48b74bc9cf5adad9d464e25ab/node_modules/@deepseek-ai/dsh-home-paths \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-directory-picker b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-directory-picker new file mode 120000 index 0000000..3fa4863 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-directory-picker @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-host-directory-picker@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-a_92aeaa3bc214441f19e24333ba7cf8bf/node_modules/@deepseek-ai/dsh-host-directory-picker \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-plugin-inventory b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-plugin-inventory new file mode 120000 index 0000000..796b681 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-plugin-inventory @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-host-plugin-inventory@0.1.0-rc.7_@deepseek-ai+cordis-plugin-loader@1.0_cd4e42fbe5707f1fc102f76d31db36d3/node_modules/@deepseek-ai/dsh-host-plugin-inventory \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-webserver b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-webserver new file mode 120000 index 0000000..6f131a8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-host-webserver @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-host-webserver@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_a31dc1b1d81d054b87a3a031575a2a1b/node_modules/@deepseek-ai/dsh-host-webserver \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-invariants b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-invariants new file mode 120000 index 0000000..605d257 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-invariants @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-invariants@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1/node_modules/@deepseek-ai/dsh-invariants \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-jobs b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-jobs new file mode 120000 index 0000000..c29d424 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-jobs @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-jobs@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-agent@0.1.0_b0f44d8fbe328863cdad7aba57b9835b/node_modules/@deepseek-ai/dsh-jobs \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-llm b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-llm new file mode 120000 index 0000000..32f4c87 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-llm @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-llm@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-attachment@0_0d6788f2a94d438ba9affaa284e28ab3/node_modules/@deepseek-ai/dsh-llm \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-message-feedback b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-message-feedback new file mode 120000 index 0000000..f713a9e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-message-feedback @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-message-feedback@0.1.0-rc.7_1fcfefbbf5e365eda1a59fadd94056b9/node_modules/@deepseek-ai/dsh-message-feedback \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-native-command b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-native-command new file mode 120000 index 0000000..836a281 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-native-command @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-native-command@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_f655e5389b1fb310bb7e8ff2dcaaa310/node_modules/@deepseek-ai/dsh-native-command \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-scope b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-scope new file mode 120000 index 0000000..92d040b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-scope @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-scope@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_3209d8827439c33684c2bfb6239ba3bb/node_modules/@deepseek-ai/dsh-scope \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session new file mode 120000 index 0000000..8de02e4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-session@0.1.0-rc.7_1dcde9bfc9fa0140c66648fbcb67b346/node_modules/@deepseek-ai/dsh-session \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-persistence b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-persistence new file mode 120000 index 0000000..5778094 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-persistence @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-session-persistence@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+_88610be7a13b59c8f081d53eab6a6aa1/node_modules/@deepseek-ai/dsh-session-persistence \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-projection b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-projection new file mode 120000 index 0000000..9fc5ccc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-projection @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-session-projection@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_8e39d6d2bfa60a8f909a7c75946a79b3/node_modules/@deepseek-ai/dsh-session-projection \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-projection-cache b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-projection-cache new file mode 120000 index 0000000..8b67d00 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-projection-cache @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-session-projection-cache@0.1.0-rc.7_5ae699d01eec9f3ccaa1e8c13f88dd36/node_modules/@deepseek-ai/dsh-session-projection-cache \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-query b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-query new file mode 120000 index 0000000..92cbc32 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-query @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-session-query@0.1.0-rc.7_fa24861d08a9d735fc78888af6ddf326/node_modules/@deepseek-ai/dsh-session-query \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-title b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-title new file mode 120000 index 0000000..11233d4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-session-title @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-session-title@0.1.0-rc.7_54a387d0d580a07b8dbef208df0b04c2/node_modules/@deepseek-ai/dsh-session-title \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-settings b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-settings new file mode 120000 index 0000000..4401a46 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-settings @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-settings@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_6b0eb868fb92d854799855c05c5fa43c/node_modules/@deepseek-ai/dsh-settings \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-skill b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-skill new file mode 120000 index 0000000..706ef07 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-skill @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-skill@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invariants_d630e0a5aa21f036fba6ea108b498f5f/node_modules/@deepseek-ai/dsh-skill \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-storage b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-storage new file mode 120000 index 0000000..9185b1f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-storage @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-storage@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_41f258c6c1c8e5a572c2ce9723fb792e/node_modules/@deepseek-ai/dsh-storage \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-storage-domain b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-storage-domain new file mode 120000 index 0000000..54856fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-storage-domain @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-storage-domain@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-i_d538713f293c1e705aa65cb74f25db56/node_modules/@deepseek-ai/dsh-storage-domain \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-subagent b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-subagent new file mode 120000 index 0000000..b9277b7 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-subagent @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-subagent@0.1.0-rc.7_17b22c2aa5d99096c13835bb226cad51/node_modules/@deepseek-ai/dsh-subagent \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-system-prompt b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-system-prompt new file mode 120000 index 0000000..48eceea --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-system-prompt @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-system-prompt@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-in_bcdfe0d28b2a374e8c734f4b00c971ea/node_modules/@deepseek-ai/dsh-system-prompt \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-timeout b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-timeout new file mode 120000 index 0000000..3b4b94f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-timeout @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-timeout@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-invarian_22adfdf3ba29bade6675fa7bb401c215/node_modules/@deepseek-ai/dsh-timeout \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-tools b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-tools new file mode 120000 index 0000000..f279b3b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-tools @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-tools@0.1.0-rc.7_38c91eb2d47c5b4ba2c8ead86dfcb4aa/node_modules/@deepseek-ai/dsh-tools \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-typert-protocol b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-typert-protocol new file mode 120000 index 0000000..2bf328d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-typert-protocol @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-typert-protocol@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_174f55289b567c5697c3ab08b42c0dfb/node_modules/@deepseek-ai/dsh-typert-protocol \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-typert-registry b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-typert-registry new file mode 120000 index 0000000..b49bd72 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-typert-registry @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-typert-registry@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-_ce0168d04ec5a7f63ef8546015138c2b/node_modules/@deepseek-ai/dsh-typert-registry \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-user-approval b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-user-approval new file mode 120000 index 0000000..e104ae8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-user-approval @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-user-approval@0.1.0-rc.7_6b8cefd624fd84694a941b103cc9b3fb/node_modules/@deepseek-ai/dsh-user-approval \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-user-questions b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-user-questions new file mode 120000 index 0000000..c40a9ff --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-user-questions @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-user-questions@0.1.0-rc.7_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-a_b9280b9741ca2842f07dddfbf24e26a3/node_modules/@deepseek-ai/dsh-user-questions \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-workspace b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-workspace new file mode 120000 index 0000000..9d85270 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/dsh-workspace @@ -0,0 +1 @@ +../../@deepseek-ai+dsh-workspace@0.1.0-rc.7_52d55750df813bb508c3c8815dfcc2bd/node_modules/@deepseek-ai/dsh-workspace \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/schemastery b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/schemastery new file mode 120000 index 0000000..ec5a451 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@deepseek-ai/schemastery @@ -0,0 +1 @@ +../../@deepseek-ai+schemastery@3.18.1/node_modules/@deepseek-ai/schemastery \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/@standard-schema/spec b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@standard-schema/spec new file mode 120000 index 0000000..ddfb8a4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/@standard-schema/spec @@ -0,0 +1 @@ +../../@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/argparse b/dsh-local-403-fix/node_modules/.pnpm/node_modules/argparse new file mode 120000 index 0000000..f5563d3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/argparse @@ -0,0 +1 @@ +../argparse@2.0.1/node_modules/argparse \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/fflate b/dsh-local-403-fix/node_modules/.pnpm/node_modules/fflate new file mode 120000 index 0000000..e45a759 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/fflate @@ -0,0 +1 @@ +../fflate@0.8.3/node_modules/fflate \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/js-yaml b/dsh-local-403-fix/node_modules/.pnpm/node_modules/js-yaml new file mode 120000 index 0000000..038a55c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/js-yaml @@ -0,0 +1 @@ +../js-yaml@4.3.1/node_modules/js-yaml \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/ws b/dsh-local-403-fix/node_modules/.pnpm/node_modules/ws new file mode 120000 index 0000000..177c7af --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/ws @@ -0,0 +1 @@ +../ws@8.21.3/node_modules/ws \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/node_modules/zod b/dsh-local-403-fix/node_modules/.pnpm/node_modules/zod new file mode 120000 index 0000000..8e563fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/node_modules/zod @@ -0,0 +1 @@ +../zod@4.4.3/node_modules/zod \ No newline at end of file diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/LICENSE new file mode 100644 index 0000000..1da5b96 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2011 Einar Otto Stangvik +Copyright (c) 2013 Arnout Kazemier and contributors +Copyright (c) 2016 Luigi Pinca and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/README.md b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/README.md new file mode 100644 index 0000000..21f10df --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/README.md @@ -0,0 +1,548 @@ +# ws: a Node.js WebSocket library + +[![Version npm](https://img.shields.io/npm/v/ws.svg?logo=npm)](https://www.npmjs.com/package/ws) +[![CI](https://img.shields.io/github/actions/workflow/status/websockets/ws/ci.yml?branch=master&label=CI&logo=github)](https://github.com/websockets/ws/actions?query=workflow%3ACI+branch%3Amaster) +[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg?logo=coveralls)](https://coveralls.io/github/websockets/ws) + +ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and +server implementation. + +Passes the quite extensive Autobahn test suite: [server][server-report], +[client][client-report]. + +**Note**: This module does not work in the browser. The client in the docs is a +reference to a backend with the role of a client in the WebSocket communication. +Browser clients must use the native +[`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) +object. To make the same code work seamlessly on Node.js and the browser, you +can use one of the many wrappers available on npm, like +[isomorphic-ws](https://github.com/heineiuo/isomorphic-ws). + +## Table of Contents + +- [Protocol support](#protocol-support) +- [Installing](#installing) + - [Opt-in for performance](#opt-in-for-performance) + - [Legacy opt-in for performance](#legacy-opt-in-for-performance) +- [API docs](#api-docs) +- [WebSocket compression](#websocket-compression) +- [Usage examples](#usage-examples) + - [Sending and receiving text data](#sending-and-receiving-text-data) + - [Sending binary data](#sending-binary-data) + - [Simple server](#simple-server) + - [External HTTP/S server](#external-https-server) + - [Multiple servers sharing a single HTTP/S server](#multiple-servers-sharing-a-single-https-server) + - [Client authentication](#client-authentication) + - [Server broadcast](#server-broadcast) + - [Round-trip time](#round-trip-time) + - [Use the Node.js streams API](#use-the-nodejs-streams-api) + - [Other examples](#other-examples) +- [FAQ](#faq) + - [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client) + - [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections) + - [How to connect via a proxy?](#how-to-connect-via-a-proxy) +- [Changelog](#changelog) +- [License](#license) + +## Protocol support + +- **HyBi drafts 07-12** (Use the option `protocolVersion: 8`) +- **HyBi drafts 13-17** (Current default, alternatively option + `protocolVersion: 13`) + +## Installing + +``` +npm install ws +``` + +### Opt-in for performance + +[bufferutil][] is an optional module that can be installed alongside the ws +module: + +``` +npm install --save-optional bufferutil +``` + +This is a binary addon that improves the performance of certain operations such +as masking and unmasking the data payload of the WebSocket frames. Prebuilt +binaries are available for the most popular platforms, so you don't necessarily +need to have a C++ compiler installed on your machine. + +To force ws to not use bufferutil, use the +[`WS_NO_BUFFER_UTIL`](./doc/ws.md#ws_no_buffer_util) environment variable. This +can be useful to enhance security in systems where a user can put a package in +the package search path of an application of another user, due to how the +Node.js resolver algorithm works. + +#### Legacy opt-in for performance + +If you are running on an old version of Node.js (prior to v18.14.0), ws also +supports the [utf-8-validate][] module: + +``` +npm install --save-optional utf-8-validate +``` + +This contains a binary polyfill for [`buffer.isUtf8()`][]. + +To force ws not to use utf-8-validate, use the +[`WS_NO_UTF_8_VALIDATE`](./doc/ws.md#ws_no_utf_8_validate) environment variable. + +## API docs + +See [`/doc/ws.md`](./doc/ws.md) for Node.js-like documentation of ws classes and +utility functions. + +## WebSocket compression + +ws supports the [permessage-deflate extension][permessage-deflate] which enables +the client and server to negotiate a compression algorithm and its parameters, +and then selectively apply it to the data payloads of each WebSocket message. + +The extension is disabled by default on the server and enabled by default on the +client. It adds a significant overhead in terms of performance and memory +consumption so we suggest to enable it only if it is really needed. + +Note that Node.js has a variety of issues with high-performance compression, +where increased concurrency, especially on Linux, can lead to [catastrophic +memory fragmentation][node-zlib-bug] and slow performance. If you intend to use +permessage-deflate in production, it is worthwhile to set up a test +representative of your workload and ensure Node.js/zlib will handle it with +acceptable performance and memory usage. + +Tuning of permessage-deflate can be done via the options defined below. You can +also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly +into the creation of [raw deflate/inflate streams][node-zlib-deflaterawdocs]. + +See [the docs][ws-server-options] for more options. + +```js +import WebSocket, { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ + port: 8080, + perMessageDeflate: { + zlibDeflateOptions: { + // See zlib defaults. + chunkSize: 1024, + memLevel: 7, + level: 3 + }, + zlibInflateOptions: { + chunkSize: 10 * 1024 + }, + // Other options settable: + clientNoContextTakeover: true, // Defaults to negotiated value. + serverNoContextTakeover: true, // Defaults to negotiated value. + serverMaxWindowBits: 10, // Defaults to negotiated value. + // Below options specified as default values. + concurrencyLimit: 10, // Limits zlib concurrency for perf. + threshold: 1024 // Size (in bytes) below which messages + // should not be compressed if context takeover is disabled. + } +}); +``` + +The client will only use the extension if it is supported and enabled on the +server. To always disable the extension on the client, set the +`perMessageDeflate` option to `false`. + +```js +import WebSocket from 'ws'; + +const ws = new WebSocket('ws://www.host.com/path', { + perMessageDeflate: false +}); +``` + +## Usage examples + +### Sending and receiving text data + +```js +import WebSocket from 'ws'; + +const ws = new WebSocket('ws://www.host.com/path'); + +ws.on('error', console.error); + +ws.on('open', function open() { + ws.send('something'); +}); + +ws.on('message', function message(data) { + console.log('received: %s', data); +}); +``` + +### Sending binary data + +```js +import WebSocket from 'ws'; + +const ws = new WebSocket('ws://www.host.com/path'); + +ws.on('error', console.error); + +ws.on('open', function open() { + const array = new Float32Array(5); + + for (var i = 0; i < array.length; ++i) { + array[i] = i / 2; + } + + ws.send(array); +}); +``` + +### Simple server + +```js +import { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws) { + ws.on('error', console.error); + + ws.on('message', function message(data) { + console.log('received: %s', data); + }); + + ws.send('something'); +}); +``` + +### External HTTP/S server + +```js +import { createServer } from 'https'; +import { readFileSync } from 'fs'; +import { WebSocketServer } from 'ws'; + +const server = createServer({ + cert: readFileSync('/path/to/cert.pem'), + key: readFileSync('/path/to/key.pem') +}); +const wss = new WebSocketServer({ server }); + +wss.on('connection', function connection(ws) { + ws.on('error', console.error); + + ws.on('message', function message(data) { + console.log('received: %s', data); + }); + + ws.send('something'); +}); + +server.listen(8080); +``` + +### Multiple servers sharing a single HTTP/S server + +```js +import { createServer } from 'http'; +import { WebSocketServer } from 'ws'; + +const server = createServer(); +const wss1 = new WebSocketServer({ noServer: true }); +const wss2 = new WebSocketServer({ noServer: true }); + +wss1.on('connection', function connection(ws) { + ws.on('error', console.error); + + // ... +}); + +wss2.on('connection', function connection(ws) { + ws.on('error', console.error); + + // ... +}); + +server.on('upgrade', function upgrade(request, socket, head) { + const { pathname } = new URL(request.url, 'wss://base.url'); + + if (pathname === '/foo') { + wss1.handleUpgrade(request, socket, head, function done(ws) { + wss1.emit('connection', ws, request); + }); + } else if (pathname === '/bar') { + wss2.handleUpgrade(request, socket, head, function done(ws) { + wss2.emit('connection', ws, request); + }); + } else { + socket.destroy(); + } +}); + +server.listen(8080); +``` + +### Client authentication + +```js +import { createServer } from 'http'; +import { WebSocketServer } from 'ws'; + +function onSocketError(err) { + console.error(err); +} + +const server = createServer(); +const wss = new WebSocketServer({ noServer: true }); + +wss.on('connection', function connection(ws, request, client) { + ws.on('error', console.error); + + ws.on('message', function message(data) { + console.log(`Received message ${data} from user ${client}`); + }); +}); + +server.on('upgrade', function upgrade(request, socket, head) { + socket.on('error', onSocketError); + + // This function is not defined on purpose. Implement it with your own logic. + authenticate(request, function next(err, client) { + if (err || !client) { + socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n'); + socket.destroy(); + return; + } + + socket.removeListener('error', onSocketError); + + wss.handleUpgrade(request, socket, head, function done(ws) { + wss.emit('connection', ws, request, client); + }); + }); +}); + +server.listen(8080); +``` + +Also see the provided [example][session-parse-example] using `express-session`. + +### Server broadcast + +A client WebSocket broadcasting to all connected WebSocket clients, including +itself. + +```js +import WebSocket, { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws) { + ws.on('error', console.error); + + ws.on('message', function message(data, isBinary) { + wss.clients.forEach(function each(client) { + if (client.readyState === WebSocket.OPEN) { + client.send(data, { binary: isBinary }); + } + }); + }); +}); +``` + +A client WebSocket broadcasting to every other connected WebSocket clients, +excluding itself. + +```js +import WebSocket, { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws) { + ws.on('error', console.error); + + ws.on('message', function message(data, isBinary) { + wss.clients.forEach(function each(client) { + if (client !== ws && client.readyState === WebSocket.OPEN) { + client.send(data, { binary: isBinary }); + } + }); + }); +}); +``` + +### Round-trip time + +```js +import WebSocket from 'ws'; + +const ws = new WebSocket('wss://websocket-echo.com/'); + +ws.on('error', console.error); + +ws.on('open', function open() { + console.log('connected'); + ws.send(Date.now()); +}); + +ws.on('close', function close() { + console.log('disconnected'); +}); + +ws.on('message', function message(data) { + console.log(`Round-trip time: ${Date.now() - data} ms`); + + setTimeout(function timeout() { + ws.send(Date.now()); + }, 500); +}); +``` + +### Use the Node.js streams API + +```js +import WebSocket, { createWebSocketStream } from 'ws'; + +const ws = new WebSocket('wss://websocket-echo.com/'); + +const duplex = createWebSocketStream(ws, { encoding: 'utf8' }); + +duplex.on('error', console.error); + +duplex.pipe(process.stdout); +process.stdin.pipe(duplex); +``` + +### Other examples + +For a full example with a browser client communicating with a ws server, see the +examples folder. + +Otherwise, see the test cases. + +## FAQ + +### How to get the IP address of the client? + +The remote IP address can be obtained from the raw socket. + +```js +import { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws, req) { + const ip = req.socket.remoteAddress; + + ws.on('error', console.error); +}); +``` + +When the server runs behind a proxy like NGINX, the de-facto standard is to use +the `X-Forwarded-For` header. + +```js +wss.on('connection', function connection(ws, req) { + const ip = req.headers['x-forwarded-for'].split(',')[0].trim(); + + ws.on('error', console.error); +}); +``` + +### How to detect and close broken connections? + +Sometimes, the link between the server and the client can be interrupted in a +way that keeps both the server and the client unaware of the broken state of the +connection (e.g. when pulling the cord). + +In these cases, ping messages can be used as a means to verify that the remote +endpoint is still responsive. + +```js +import { WebSocketServer } from 'ws'; + +function heartbeat() { + this.isAlive = true; +} + +const wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws) { + ws.isAlive = true; + ws.on('error', console.error); + ws.on('pong', heartbeat); +}); + +const interval = setInterval(function ping() { + wss.clients.forEach(function each(ws) { + if (ws.isAlive === false) return ws.terminate(); + + ws.isAlive = false; + ws.ping(); + }); +}, 30000); + +wss.on('close', function close() { + clearInterval(interval); +}); +``` + +Pong messages are automatically sent in response to ping messages as required by +the spec. + +Just like the server example above, your clients might as well lose connection +without knowing it. You might want to add a ping listener on your clients to +prevent that. A simple implementation would be: + +```js +import WebSocket from 'ws'; + +function heartbeat() { + clearTimeout(this.pingTimeout); + + // Use `WebSocket#terminate()`, which immediately destroys the connection, + // instead of `WebSocket#close()`, which waits for the close timer. + // Delay should be equal to the interval at which your server + // sends out pings plus a conservative assumption of the latency. + this.pingTimeout = setTimeout(() => { + this.terminate(); + }, 30000 + 1000); +} + +const client = new WebSocket('wss://websocket-echo.com/'); + +client.on('error', console.error); +client.on('open', heartbeat); +client.on('ping', heartbeat); +client.on('close', function clear() { + clearTimeout(this.pingTimeout); +}); +``` + +### How to connect via a proxy? + +Use a custom `http.Agent` implementation like [https-proxy-agent][] or +[socks-proxy-agent][]. + +## Changelog + +We're using the GitHub [releases][changelog] for changelog entries. + +## License + +[MIT](LICENSE) + +[`buffer.isutf8()`]: https://nodejs.org/api/buffer.html#bufferisutf8input +[bufferutil]: https://github.com/websockets/bufferutil +[changelog]: https://github.com/websockets/ws/releases +[client-report]: http://websockets.github.io/ws/autobahn/clients/ +[https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent +[node-zlib-bug]: https://github.com/nodejs/node/issues/8871 +[node-zlib-deflaterawdocs]: + https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options +[permessage-deflate]: https://tools.ietf.org/html/rfc7692 +[server-report]: http://websockets.github.io/ws/autobahn/servers/ +[session-parse-example]: ./examples/express-session-parse +[socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent +[utf-8-validate]: https://github.com/websockets/utf-8-validate +[ws-server-options]: ./doc/ws.md#new-websocketserveroptions-callback diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/browser.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/browser.js new file mode 100644 index 0000000..ca4f628 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/browser.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = function () { + throw new Error( + 'ws does not work in the browser. Browser clients must use the native ' + + 'WebSocket object' + ); +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/index.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/index.js new file mode 100644 index 0000000..3fdb7b2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/index.js @@ -0,0 +1,22 @@ +'use strict'; + +const createWebSocketStream = require('./lib/stream'); +const extension = require('./lib/extension'); +const PerMessageDeflate = require('./lib/permessage-deflate'); +const Receiver = require('./lib/receiver'); +const Sender = require('./lib/sender'); +const subprotocol = require('./lib/subprotocol'); +const WebSocket = require('./lib/websocket'); +const WebSocketServer = require('./lib/websocket-server'); + +WebSocket.createWebSocketStream = createWebSocketStream; +WebSocket.extension = extension; +WebSocket.PerMessageDeflate = PerMessageDeflate; +WebSocket.Receiver = Receiver; +WebSocket.Sender = Sender; +WebSocket.Server = WebSocketServer; +WebSocket.subprotocol = subprotocol; +WebSocket.WebSocket = WebSocket; +WebSocket.WebSocketServer = WebSocketServer; + +module.exports = WebSocket; diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/buffer-util.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/buffer-util.js new file mode 100644 index 0000000..f7536e2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/buffer-util.js @@ -0,0 +1,131 @@ +'use strict'; + +const { EMPTY_BUFFER } = require('./constants'); + +const FastBuffer = Buffer[Symbol.species]; + +/** + * Merges an array of buffers into a new buffer. + * + * @param {Buffer[]} list The array of buffers to concat + * @param {Number} totalLength The total length of buffers in the list + * @return {Buffer} The resulting buffer + * @public + */ +function concat(list, totalLength) { + if (list.length === 0) return EMPTY_BUFFER; + if (list.length === 1) return list[0]; + + const target = Buffer.allocUnsafe(totalLength); + let offset = 0; + + for (let i = 0; i < list.length; i++) { + const buf = list[i]; + target.set(buf, offset); + offset += buf.length; + } + + if (offset < totalLength) { + return new FastBuffer(target.buffer, target.byteOffset, offset); + } + + return target; +} + +/** + * Masks a buffer using the given mask. + * + * @param {Buffer} source The buffer to mask + * @param {Buffer} mask The mask to use + * @param {Buffer} output The buffer where to store the result + * @param {Number} offset The offset at which to start writing + * @param {Number} length The number of bytes to mask. + * @public + */ +function _mask(source, mask, output, offset, length) { + for (let i = 0; i < length; i++) { + output[offset + i] = source[i] ^ mask[i & 3]; + } +} + +/** + * Unmasks a buffer using the given mask. + * + * @param {Buffer} buffer The buffer to unmask + * @param {Buffer} mask The mask to use + * @public + */ +function _unmask(buffer, mask) { + for (let i = 0; i < buffer.length; i++) { + buffer[i] ^= mask[i & 3]; + } +} + +/** + * Converts a buffer to an `ArrayBuffer`. + * + * @param {Buffer} buf The buffer to convert + * @return {ArrayBuffer} Converted buffer + * @public + */ +function toArrayBuffer(buf) { + if (buf.length === buf.buffer.byteLength) { + return buf.buffer; + } + + return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length); +} + +/** + * Converts `data` to a `Buffer`. + * + * @param {*} data The data to convert + * @return {Buffer} The buffer + * @throws {TypeError} + * @public + */ +function toBuffer(data) { + toBuffer.readOnly = true; + + if (Buffer.isBuffer(data)) return data; + + let buf; + + if (data instanceof ArrayBuffer) { + buf = new FastBuffer(data); + } else if (ArrayBuffer.isView(data)) { + buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength); + } else { + buf = Buffer.from(data); + toBuffer.readOnly = false; + } + + return buf; +} + +module.exports = { + concat, + mask: _mask, + toArrayBuffer, + toBuffer, + unmask: _unmask +}; + +/* istanbul ignore else */ +if (!process.env.WS_NO_BUFFER_UTIL) { + try { + const bufferUtil = require('bufferutil'); + + module.exports.mask = function (source, mask, output, offset, length) { + if (length < 48) _mask(source, mask, output, offset, length); + else bufferUtil.mask(source, mask, output, offset, length); + }; + + module.exports.unmask = function (buffer, mask) { + if (buffer.length < 32) _unmask(buffer, mask); + else bufferUtil.unmask(buffer, mask); + }; + } catch (e) { + // Continue regardless of the error. + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/constants.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/constants.js new file mode 100644 index 0000000..69b2fe3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/constants.js @@ -0,0 +1,19 @@ +'use strict'; + +const BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments']; +const hasBlob = typeof Blob !== 'undefined'; + +if (hasBlob) BINARY_TYPES.push('blob'); + +module.exports = { + BINARY_TYPES, + CLOSE_TIMEOUT: 30000, + EMPTY_BUFFER: Buffer.alloc(0), + GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', + hasBlob, + kForOnEventAttribute: Symbol('kIsForOnEventAttribute'), + kListener: Symbol('kListener'), + kStatusCode: Symbol('status-code'), + kWebSocket: Symbol('websocket'), + NOOP: () => {} +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/event-target.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/event-target.js new file mode 100644 index 0000000..fea4cbc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/event-target.js @@ -0,0 +1,292 @@ +'use strict'; + +const { kForOnEventAttribute, kListener } = require('./constants'); + +const kCode = Symbol('kCode'); +const kData = Symbol('kData'); +const kError = Symbol('kError'); +const kMessage = Symbol('kMessage'); +const kReason = Symbol('kReason'); +const kTarget = Symbol('kTarget'); +const kType = Symbol('kType'); +const kWasClean = Symbol('kWasClean'); + +/** + * Class representing an event. + */ +class Event { + /** + * Create a new `Event`. + * + * @param {String} type The name of the event + * @throws {TypeError} If the `type` argument is not specified + */ + constructor(type) { + this[kTarget] = null; + this[kType] = type; + } + + /** + * @type {*} + */ + get target() { + return this[kTarget]; + } + + /** + * @type {String} + */ + get type() { + return this[kType]; + } +} + +Object.defineProperty(Event.prototype, 'target', { enumerable: true }); +Object.defineProperty(Event.prototype, 'type', { enumerable: true }); + +/** + * Class representing a close event. + * + * @extends Event + */ +class CloseEvent extends Event { + /** + * Create a new `CloseEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {Number} [options.code=0] The status code explaining why the + * connection was closed + * @param {String} [options.reason=''] A human-readable string explaining why + * the connection was closed + * @param {Boolean} [options.wasClean=false] Indicates whether or not the + * connection was cleanly closed + */ + constructor(type, options = {}) { + super(type); + + this[kCode] = options.code === undefined ? 0 : options.code; + this[kReason] = options.reason === undefined ? '' : options.reason; + this[kWasClean] = options.wasClean === undefined ? false : options.wasClean; + } + + /** + * @type {Number} + */ + get code() { + return this[kCode]; + } + + /** + * @type {String} + */ + get reason() { + return this[kReason]; + } + + /** + * @type {Boolean} + */ + get wasClean() { + return this[kWasClean]; + } +} + +Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true }); +Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true }); +Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true }); + +/** + * Class representing an error event. + * + * @extends Event + */ +class ErrorEvent extends Event { + /** + * Create a new `ErrorEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.error=null] The error that generated this event + * @param {String} [options.message=''] The error message + */ + constructor(type, options = {}) { + super(type); + + this[kError] = options.error === undefined ? null : options.error; + this[kMessage] = options.message === undefined ? '' : options.message; + } + + /** + * @type {*} + */ + get error() { + return this[kError]; + } + + /** + * @type {String} + */ + get message() { + return this[kMessage]; + } +} + +Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true }); +Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true }); + +/** + * Class representing a message event. + * + * @extends Event + */ +class MessageEvent extends Event { + /** + * Create a new `MessageEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.data=null] The message content + */ + constructor(type, options = {}) { + super(type); + + this[kData] = options.data === undefined ? null : options.data; + } + + /** + * @type {*} + */ + get data() { + return this[kData]; + } +} + +Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true }); + +/** + * This provides methods for emulating the `EventTarget` interface. It's not + * meant to be used directly. + * + * @mixin + */ +const EventTarget = { + /** + * Register an event listener. + * + * @param {String} type A string representing the event type to listen for + * @param {(Function|Object)} handler The listener to add + * @param {Object} [options] An options object specifies characteristics about + * the event listener + * @param {Boolean} [options.once=false] A `Boolean` indicating that the + * listener should be invoked at most once after being added. If `true`, + * the listener would be automatically removed when invoked. + * @public + */ + addEventListener(type, handler, options = {}) { + for (const listener of this.listeners(type)) { + if ( + !options[kForOnEventAttribute] && + listener[kListener] === handler && + !listener[kForOnEventAttribute] + ) { + return; + } + } + + let wrapper; + + if (type === 'message') { + wrapper = function onMessage(data, isBinary) { + const event = new MessageEvent('message', { + data: isBinary ? data : data.toString() + }); + + event[kTarget] = this; + callListener(handler, this, event); + }; + } else if (type === 'close') { + wrapper = function onClose(code, message) { + const event = new CloseEvent('close', { + code, + reason: message.toString(), + wasClean: this._closeFrameReceived && this._closeFrameSent + }); + + event[kTarget] = this; + callListener(handler, this, event); + }; + } else if (type === 'error') { + wrapper = function onError(error) { + const event = new ErrorEvent('error', { + error, + message: error.message + }); + + event[kTarget] = this; + callListener(handler, this, event); + }; + } else if (type === 'open') { + wrapper = function onOpen() { + const event = new Event('open'); + + event[kTarget] = this; + callListener(handler, this, event); + }; + } else { + return; + } + + wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute]; + wrapper[kListener] = handler; + + if (options.once) { + this.once(type, wrapper); + } else { + this.on(type, wrapper); + } + }, + + /** + * Remove an event listener. + * + * @param {String} type A string representing the event type to remove + * @param {(Function|Object)} handler The listener to remove + * @public + */ + removeEventListener(type, handler) { + for (const listener of this.listeners(type)) { + if (listener[kListener] === handler && !listener[kForOnEventAttribute]) { + this.removeListener(type, listener); + break; + } + } + } +}; + +module.exports = { + CloseEvent, + ErrorEvent, + Event, + EventTarget, + MessageEvent +}; + +/** + * Call an event listener + * + * @param {(Function|Object)} listener The listener to call + * @param {*} thisArg The value to use as `this`` when calling the listener + * @param {Event} event The event to pass to the listener + * @private + */ +function callListener(listener, thisArg, event) { + if (typeof listener === 'object' && listener.handleEvent) { + listener.handleEvent.call(listener, event); + } else { + listener.call(thisArg, event); + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/extension.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/extension.js new file mode 100644 index 0000000..3d7895c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/extension.js @@ -0,0 +1,203 @@ +'use strict'; + +const { tokenChars } = require('./validation'); + +/** + * Adds an offer to the map of extension offers or a parameter to the map of + * parameters. + * + * @param {Object} dest The map of extension offers or parameters + * @param {String} name The extension or parameter name + * @param {(Object|Boolean|String)} elem The extension parameters or the + * parameter value + * @private + */ +function push(dest, name, elem) { + if (dest[name] === undefined) dest[name] = [elem]; + else dest[name].push(elem); +} + +/** + * Parses the `Sec-WebSocket-Extensions` header into an object. + * + * @param {String} header The field value of the header + * @return {Object} The parsed object + * @public + */ +function parse(header) { + const offers = Object.create(null); + let params = Object.create(null); + let mustUnescape = false; + let isEscaping = false; + let inQuotes = false; + let extensionName; + let paramName; + let start = -1; + let code = -1; + let end = -1; + let i = 0; + + for (; i < header.length; i++) { + code = header.charCodeAt(i); + + if (extensionName === undefined) { + if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if ( + i !== 0 && + (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */ + ) { + if (end === -1 && start !== -1) end = i; + } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + const name = header.slice(start, end); + if (code === 0x2c) { + push(offers, name, params); + params = Object.create(null); + } else { + extensionName = name; + } + + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else if (paramName === undefined) { + if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if (code === 0x20 || code === 0x09) { + if (end === -1 && start !== -1) end = i; + } else if (code === 0x3b || code === 0x2c) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + push(params, header.slice(start, end), true); + if (code === 0x2c) { + push(offers, extensionName, params); + params = Object.create(null); + extensionName = undefined; + } + + start = end = -1; + } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) { + paramName = header.slice(start, i); + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else { + // + // The value of a quoted-string after unescaping must conform to the + // token ABNF, so only token characters are valid. + // Ref: https://tools.ietf.org/html/rfc6455#section-9.1 + // + if (isEscaping) { + if (tokenChars[code] !== 1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + if (start === -1) start = i; + else if (!mustUnescape) mustUnescape = true; + isEscaping = false; + } else if (inQuotes) { + if (tokenChars[code] === 1) { + if (start === -1) start = i; + } else if (code === 0x22 /* '"' */ && start !== -1) { + inQuotes = false; + end = i; + } else if (code === 0x5c /* '\' */) { + isEscaping = true; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) { + inQuotes = true; + } else if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if (start !== -1 && (code === 0x20 || code === 0x09)) { + if (end === -1) end = i; + } else if (code === 0x3b || code === 0x2c) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + let value = header.slice(start, end); + if (mustUnescape) { + value = value.replace(/\\/g, ''); + mustUnescape = false; + } + push(params, paramName, value); + if (code === 0x2c) { + push(offers, extensionName, params); + params = Object.create(null); + extensionName = undefined; + } + + paramName = undefined; + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } + } + + if (start === -1 || inQuotes || code === 0x20 || code === 0x09) { + throw new SyntaxError('Unexpected end of input'); + } + + if (end === -1) end = i; + const token = header.slice(start, end); + if (extensionName === undefined) { + push(offers, token, params); + } else { + if (paramName === undefined) { + push(params, token, true); + } else if (mustUnescape) { + push(params, paramName, token.replace(/\\/g, '')); + } else { + push(params, paramName, token); + } + push(offers, extensionName, params); + } + + return offers; +} + +/** + * Builds the `Sec-WebSocket-Extensions` header field value. + * + * @param {Object} extensions The map of extensions and parameters to format + * @return {String} A string representing the given object + * @public + */ +function format(extensions) { + return Object.keys(extensions) + .map((extension) => { + let configurations = extensions[extension]; + if (!Array.isArray(configurations)) configurations = [configurations]; + return configurations + .map((params) => { + return [extension] + .concat( + Object.keys(params).map((k) => { + let values = params[k]; + if (!Array.isArray(values)) values = [values]; + return values + .map((v) => (v === true ? k : `${k}=${v}`)) + .join('; '); + }) + ) + .join('; '); + }) + .join(', '); + }) + .join(', '); +} + +module.exports = { format, parse }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/limiter.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/limiter.js new file mode 100644 index 0000000..3fd3578 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/limiter.js @@ -0,0 +1,55 @@ +'use strict'; + +const kDone = Symbol('kDone'); +const kRun = Symbol('kRun'); + +/** + * A very simple job queue with adjustable concurrency. Adapted from + * https://github.com/STRML/async-limiter + */ +class Limiter { + /** + * Creates a new `Limiter`. + * + * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed + * to run concurrently + */ + constructor(concurrency) { + this[kDone] = () => { + this.pending--; + this[kRun](); + }; + this.concurrency = concurrency || Infinity; + this.jobs = []; + this.pending = 0; + } + + /** + * Adds a job to the queue. + * + * @param {Function} job The job to run + * @public + */ + add(job) { + this.jobs.push(job); + this[kRun](); + } + + /** + * Removes a job from the queue and runs it if possible. + * + * @private + */ + [kRun]() { + if (this.pending === this.concurrency) return; + + if (this.jobs.length) { + const job = this.jobs.shift(); + + this.pending++; + job(this[kDone]); + } + } +} + +module.exports = Limiter; diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/permessage-deflate.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/permessage-deflate.js new file mode 100644 index 0000000..c51d8f5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/permessage-deflate.js @@ -0,0 +1,530 @@ +'use strict'; + +const zlib = require('zlib'); + +const bufferUtil = require('./buffer-util'); +const Limiter = require('./limiter'); +const { kStatusCode } = require('./constants'); + +const FastBuffer = Buffer[Symbol.species]; +const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]); +const kPerMessageDeflate = Symbol('permessage-deflate'); +const kTotalLength = Symbol('total-length'); +const kCallback = Symbol('callback'); +const kBuffers = Symbol('buffers'); +const kError = Symbol('error'); + +// +// We limit zlib concurrency, which prevents severe memory fragmentation +// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913 +// and https://github.com/websockets/ws/issues/1202 +// +// Intentionally global; it's the global thread pool that's an issue. +// +let zlibLimiter; + +/** + * permessage-deflate implementation. + */ +class PerMessageDeflate { + /** + * Creates a PerMessageDeflate instance. + * + * @param {Object} [options] Configuration options + * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support + * for, or request, a custom client window size + * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/ + * acknowledge disabling of client context takeover + * @param {Number} [options.concurrencyLimit=10] The number of concurrent + * calls to zlib + * @param {Boolean} [options.isServer=false] Create the instance in either + * server or client mode + * @param {Number} [options.maxPayload=0] The maximum allowed message length + * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the + * use of a custom server window size + * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept + * disabling of server context takeover + * @param {Number} [options.threshold=1024] Size (in bytes) below which + * messages should not be compressed if context takeover is disabled + * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on + * deflate + * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on + * inflate + */ + constructor(options) { + this._options = options || {}; + this._threshold = + this._options.threshold !== undefined ? this._options.threshold : 1024; + this._maxPayload = this._options.maxPayload | 0; + this._isServer = !!this._options.isServer; + this._deflate = null; + this._inflate = null; + + this.params = null; + + if (!zlibLimiter) { + const concurrency = + this._options.concurrencyLimit !== undefined + ? this._options.concurrencyLimit + : 10; + zlibLimiter = new Limiter(concurrency); + } + } + + /** + * @type {String} + */ + static get extensionName() { + return 'permessage-deflate'; + } + + /** + * Create an extension negotiation offer. + * + * @return {Object} Extension parameters + * @public + */ + offer() { + const params = {}; + + if (this._options.serverNoContextTakeover) { + params.server_no_context_takeover = true; + } + if (this._options.clientNoContextTakeover) { + params.client_no_context_takeover = true; + } + if (this._options.serverMaxWindowBits) { + params.server_max_window_bits = this._options.serverMaxWindowBits; + } + if (this._options.clientMaxWindowBits) { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } else if (this._options.clientMaxWindowBits == null) { + params.client_max_window_bits = true; + } + + return params; + } + + /** + * Accept an extension negotiation offer/response. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Object} Accepted configuration + * @public + */ + accept(configurations) { + configurations = this.normalizeParams(configurations); + + this.params = this._isServer + ? this.acceptAsServer(configurations) + : this.acceptAsClient(configurations); + + return this.params; + } + + /** + * Releases all resources used by the extension. + * + * @public + */ + cleanup() { + if (this._inflate) { + this._inflate.close(); + this._inflate = null; + } + + if (this._deflate) { + const callback = this._deflate[kCallback]; + + this._deflate.close(); + this._deflate = null; + + if (callback) { + callback( + new Error( + 'The deflate stream was closed while data was being processed' + ) + ); + } + } + } + + /** + * Accept an extension negotiation offer. + * + * @param {Array} offers The extension negotiation offers + * @return {Object} Accepted configuration + * @private + */ + acceptAsServer(offers) { + const opts = this._options; + const accepted = offers.find((params) => { + if ( + (opts.serverNoContextTakeover === false && + params.server_no_context_takeover) || + (params.server_max_window_bits && + (opts.serverMaxWindowBits === false || + (typeof opts.serverMaxWindowBits === 'number' && + opts.serverMaxWindowBits > params.server_max_window_bits))) || + (typeof opts.clientMaxWindowBits === 'number' && + (typeof params.client_max_window_bits === 'number' + ? opts.clientMaxWindowBits > params.client_max_window_bits + : !params.client_max_window_bits)) + ) { + return false; + } + + return true; + }); + + if (!accepted) { + throw new Error('None of the extension offers can be accepted'); + } + + if (opts.serverNoContextTakeover) { + accepted.server_no_context_takeover = true; + } + if (opts.clientNoContextTakeover) { + accepted.client_no_context_takeover = true; + } + if (typeof opts.serverMaxWindowBits === 'number') { + accepted.server_max_window_bits = opts.serverMaxWindowBits; + } + if (typeof opts.clientMaxWindowBits === 'number') { + accepted.client_max_window_bits = opts.clientMaxWindowBits; + } else if ( + accepted.client_max_window_bits === true || + opts.clientMaxWindowBits === false + ) { + delete accepted.client_max_window_bits; + } + + return accepted; + } + + /** + * Accept the extension negotiation response. + * + * @param {Array} response The extension negotiation response + * @return {Object} Accepted configuration + * @private + */ + acceptAsClient(response) { + const params = response[0]; + + if ( + this._options.clientNoContextTakeover === false && + params.client_no_context_takeover + ) { + throw new Error('Unexpected parameter "client_no_context_takeover"'); + } + + if (!params.client_max_window_bits) { + if (typeof this._options.clientMaxWindowBits === 'number') { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } + } else if ( + this._options.clientMaxWindowBits === false || + (typeof this._options.clientMaxWindowBits === 'number' && + params.client_max_window_bits > this._options.clientMaxWindowBits) + ) { + throw new Error( + 'Unexpected or invalid parameter "client_max_window_bits"' + ); + } + + return params; + } + + /** + * Normalize parameters. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Array} The offers/response with normalized parameters + * @private + */ + normalizeParams(configurations) { + configurations.forEach((params) => { + Object.keys(params).forEach((key) => { + let value = params[key]; + + if (value.length > 1) { + throw new Error(`Parameter "${key}" must have only a single value`); + } + + value = value[0]; + + if (key === 'client_max_window_bits') { + if (value !== true) { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if (!this._isServer) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else if (key === 'server_max_window_bits') { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if ( + key === 'client_no_context_takeover' || + key === 'server_no_context_takeover' + ) { + if (value !== true) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else { + throw new Error(`Unknown parameter "${key}"`); + } + + params[key] = value; + }); + }); + + return configurations; + } + + /** + * Decompress data. Concurrency limited. + * + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public + */ + decompress(data, fin, callback) { + zlibLimiter.add((done) => { + this._decompress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); + } + + /** + * Compress data. Concurrency limited. + * + * @param {(Buffer|String)} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public + */ + compress(data, fin, callback) { + zlibLimiter.add((done) => { + this._compress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); + } + + /** + * Decompress data. + * + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private + */ + _decompress(data, fin, callback) { + const endpoint = this._isServer ? 'client' : 'server'; + + if (!this._inflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = + typeof this.params[key] !== 'number' + ? zlib.Z_DEFAULT_WINDOWBITS + : this.params[key]; + + this._inflate = zlib.createInflateRaw({ + ...this._options.zlibInflateOptions, + windowBits + }); + this._inflate[kPerMessageDeflate] = this; + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + this._inflate.on('error', inflateOnError); + this._inflate.on('data', inflateOnData); + } + + this._inflate[kCallback] = callback; + + this._inflate.write(data); + if (fin) this._inflate.write(TRAILER); + + this._inflate.flush(() => { + const err = this._inflate[kError]; + + if (err) { + this._inflate.close(); + this._inflate = null; + callback(err); + return; + } + + const data = bufferUtil.concat( + this._inflate[kBuffers], + this._inflate[kTotalLength] + ); + + if (this._inflate._readableState.endEmitted) { + this._inflate.close(); + this._inflate = null; + } else { + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._inflate.reset(); + } + } + + callback(null, data); + }); + } + + /** + * Compress data. + * + * @param {(Buffer|String)} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private + */ + _compress(data, fin, callback) { + const endpoint = this._isServer ? 'server' : 'client'; + + if (!this._deflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = + typeof this.params[key] !== 'number' + ? zlib.Z_DEFAULT_WINDOWBITS + : this.params[key]; + + this._deflate = zlib.createDeflateRaw({ + ...this._options.zlibDeflateOptions, + windowBits + }); + + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + + this._deflate.on('data', deflateOnData); + } + + this._deflate[kCallback] = callback; + + this._deflate.write(data); + this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { + if (!this._deflate) { + // + // The deflate stream was closed while data was being processed. + // + return; + } + + let data = bufferUtil.concat( + this._deflate[kBuffers], + this._deflate[kTotalLength] + ); + + if (fin) { + data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4); + } + + // + // Ensure that the callback will not be called again in + // `PerMessageDeflate#cleanup()`. + // + this._deflate[kCallback] = null; + + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._deflate.reset(); + } + + callback(null, data); + }); + } +} + +module.exports = PerMessageDeflate; + +/** + * The listener of the `zlib.DeflateRaw` stream `'data'` event. + * + * @param {Buffer} chunk A chunk of data + * @private + */ +function deflateOnData(chunk) { + this[kBuffers].push(chunk); + this[kTotalLength] += chunk.length; +} + +/** + * The listener of the `zlib.InflateRaw` stream `'data'` event. + * + * @param {Buffer} chunk A chunk of data + * @private + */ +function inflateOnData(chunk) { + this[kTotalLength] += chunk.length; + + if ( + this[kPerMessageDeflate]._maxPayload < 1 || + this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload + ) { + this[kBuffers].push(chunk); + return; + } + + this[kError] = new RangeError('Max payload size exceeded'); + this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'; + this[kError][kStatusCode] = 1009; + this.removeListener('data', inflateOnData); + + // + // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the + // fact that in Node.js versions prior to 13.10.0, the callback for + // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing + // `zlib.reset()` ensures that either the callback is invoked or an error is + // emitted. + // + this.reset(); +} + +/** + * The listener of the `zlib.InflateRaw` stream `'error'` event. + * + * @param {Error} err The emitted error + * @private + */ +function inflateOnError(err) { + // + // There is no need to call `Zlib#close()` as the handle is automatically + // closed when an error is emitted. + // + this[kPerMessageDeflate]._inflate = null; + + if (this[kError]) { + this[kCallback](this[kError]); + return; + } + + err[kStatusCode] = 1007; + this[kCallback](err); +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/receiver.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/receiver.js new file mode 100644 index 0000000..784dbe1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/receiver.js @@ -0,0 +1,743 @@ +'use strict'; + +const { Writable } = require('stream'); + +const PerMessageDeflate = require('./permessage-deflate'); +const { + BINARY_TYPES, + EMPTY_BUFFER, + kStatusCode, + kWebSocket +} = require('./constants'); +const { concat, toArrayBuffer, unmask } = require('./buffer-util'); +const { isValidStatusCode, isValidUTF8 } = require('./validation'); + +const FastBuffer = Buffer[Symbol.species]; + +const GET_INFO = 0; +const GET_PAYLOAD_LENGTH_16 = 1; +const GET_PAYLOAD_LENGTH_64 = 2; +const GET_MASK = 3; +const GET_DATA = 4; +const INFLATING = 5; +const DEFER_EVENT = 6; + +/** + * HyBi Receiver implementation. + * + * @extends Writable + */ +class Receiver extends Writable { + /** + * Creates a Receiver instance. + * + * @param {Object} [options] Options object + * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether + * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted + * multiple times in the same tick + * @param {String} [options.binaryType=nodebuffer] The type for binary data + * @param {Object} [options.extensions] An object containing the negotiated + * extensions + * @param {Boolean} [options.isServer=false] Specifies whether to operate in + * client or server mode + * @param {Number} [options.maxBufferedChunks=0] The maximum number of + * buffered data chunks + * @param {Number} [options.maxFragments=0] The maximum number of message + * fragments + * @param {Number} [options.maxPayload=0] The maximum allowed message length + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + */ + constructor(options = {}) { + super(); + + this._allowSynchronousEvents = + options.allowSynchronousEvents !== undefined + ? options.allowSynchronousEvents + : true; + this._binaryType = options.binaryType || BINARY_TYPES[0]; + this._extensions = options.extensions || {}; + this._isServer = !!options.isServer; + this._maxBufferedChunks = options.maxBufferedChunks | 0; + this._maxFragments = options.maxFragments | 0; + this._maxPayload = options.maxPayload | 0; + this._skipUTF8Validation = !!options.skipUTF8Validation; + this[kWebSocket] = undefined; + + this._bufferedBytes = 0; + this._buffers = []; + + this._compressed = false; + this._payloadLength = 0; + this._mask = undefined; + this._fragmented = 0; + this._masked = false; + this._fin = false; + this._opcode = 0; + + this._totalPayloadLength = 0; + this._messageLength = 0; + this._numFragments = 0; + this._fragments = []; + + this._errored = false; + this._loop = false; + this._state = GET_INFO; + } + + /** + * Implements `Writable.prototype._write()`. + * + * @param {Buffer} chunk The chunk of data to write + * @param {String} encoding The character encoding of `chunk` + * @param {Function} cb Callback + * @private + */ + _write(chunk, encoding, cb) { + if (this._opcode === 0x08 && this._state == GET_INFO) return cb(); + + if ( + this._maxBufferedChunks > 0 && + this._buffers.length >= this._maxBufferedChunks + ) { + cb( + this.createError( + RangeError, + 'Too many buffered chunks', + false, + 1008, + 'WS_ERR_TOO_MANY_BUFFERED_PARTS' + ) + ); + return; + } + + this._bufferedBytes += chunk.length; + this._buffers.push(chunk); + this.startLoop(cb); + } + + /** + * Consumes `n` bytes from the buffered data. + * + * @param {Number} n The number of bytes to consume + * @return {Buffer} The consumed bytes + * @private + */ + consume(n) { + this._bufferedBytes -= n; + + if (n === this._buffers[0].length) return this._buffers.shift(); + + if (n < this._buffers[0].length) { + const buf = this._buffers[0]; + this._buffers[0] = new FastBuffer( + buf.buffer, + buf.byteOffset + n, + buf.length - n + ); + + return new FastBuffer(buf.buffer, buf.byteOffset, n); + } + + const dst = Buffer.allocUnsafe(n); + + do { + const buf = this._buffers[0]; + const offset = dst.length - n; + + if (n >= buf.length) { + dst.set(this._buffers.shift(), offset); + } else { + dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset); + this._buffers[0] = new FastBuffer( + buf.buffer, + buf.byteOffset + n, + buf.length - n + ); + } + + n -= buf.length; + } while (n > 0); + + return dst; + } + + /** + * Starts the parsing loop. + * + * @param {Function} cb Callback + * @private + */ + startLoop(cb) { + this._loop = true; + + do { + switch (this._state) { + case GET_INFO: + this.getInfo(cb); + break; + case GET_PAYLOAD_LENGTH_16: + this.getPayloadLength16(cb); + break; + case GET_PAYLOAD_LENGTH_64: + this.getPayloadLength64(cb); + break; + case GET_MASK: + this.getMask(); + break; + case GET_DATA: + this.getData(cb); + break; + case INFLATING: + case DEFER_EVENT: + this._loop = false; + return; + } + } while (this._loop); + + if (!this._errored) cb(); + } + + /** + * Reads the first two bytes of a frame. + * + * @param {Function} cb Callback + * @private + */ + getInfo(cb) { + if (this._bufferedBytes < 2) { + this._loop = false; + return; + } + + const buf = this.consume(2); + + if ((buf[0] & 0x30) !== 0x00) { + const error = this.createError( + RangeError, + 'RSV2 and RSV3 must be clear', + true, + 1002, + 'WS_ERR_UNEXPECTED_RSV_2_3' + ); + + cb(error); + return; + } + + const compressed = (buf[0] & 0x40) === 0x40; + + if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { + const error = this.createError( + RangeError, + 'RSV1 must be clear', + true, + 1002, + 'WS_ERR_UNEXPECTED_RSV_1' + ); + + cb(error); + return; + } + + this._fin = (buf[0] & 0x80) === 0x80; + this._opcode = buf[0] & 0x0f; + this._payloadLength = buf[1] & 0x7f; + + if (this._opcode === 0x00) { + if (compressed) { + const error = this.createError( + RangeError, + 'RSV1 must be clear', + true, + 1002, + 'WS_ERR_UNEXPECTED_RSV_1' + ); + + cb(error); + return; + } + + if (!this._fragmented) { + const error = this.createError( + RangeError, + 'invalid opcode 0', + true, + 1002, + 'WS_ERR_INVALID_OPCODE' + ); + + cb(error); + return; + } + + this._opcode = this._fragmented; + } else if (this._opcode === 0x01 || this._opcode === 0x02) { + if (this._fragmented) { + const error = this.createError( + RangeError, + `invalid opcode ${this._opcode}`, + true, + 1002, + 'WS_ERR_INVALID_OPCODE' + ); + + cb(error); + return; + } + + this._compressed = compressed; + } else if (this._opcode > 0x07 && this._opcode < 0x0b) { + if (!this._fin) { + const error = this.createError( + RangeError, + 'FIN must be set', + true, + 1002, + 'WS_ERR_EXPECTED_FIN' + ); + + cb(error); + return; + } + + if (compressed) { + const error = this.createError( + RangeError, + 'RSV1 must be clear', + true, + 1002, + 'WS_ERR_UNEXPECTED_RSV_1' + ); + + cb(error); + return; + } + + if ( + this._payloadLength > 0x7d || + (this._opcode === 0x08 && this._payloadLength === 1) + ) { + const error = this.createError( + RangeError, + `invalid payload length ${this._payloadLength}`, + true, + 1002, + 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH' + ); + + cb(error); + return; + } + } else { + const error = this.createError( + RangeError, + `invalid opcode ${this._opcode}`, + true, + 1002, + 'WS_ERR_INVALID_OPCODE' + ); + + cb(error); + return; + } + + if (!this._fin && !this._fragmented) this._fragmented = this._opcode; + this._masked = (buf[1] & 0x80) === 0x80; + + if (this._isServer) { + if (!this._masked) { + const error = this.createError( + RangeError, + 'MASK must be set', + true, + 1002, + 'WS_ERR_EXPECTED_MASK' + ); + + cb(error); + return; + } + } else if (this._masked) { + const error = this.createError( + RangeError, + 'MASK must be clear', + true, + 1002, + 'WS_ERR_UNEXPECTED_MASK' + ); + + cb(error); + return; + } + + if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; + else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; + else this.haveLength(cb); + } + + /** + * Gets extended payload length (7+16). + * + * @param {Function} cb Callback + * @private + */ + getPayloadLength16(cb) { + if (this._bufferedBytes < 2) { + this._loop = false; + return; + } + + this._payloadLength = this.consume(2).readUInt16BE(0); + this.haveLength(cb); + } + + /** + * Gets extended payload length (7+64). + * + * @param {Function} cb Callback + * @private + */ + getPayloadLength64(cb) { + if (this._bufferedBytes < 8) { + this._loop = false; + return; + } + + const buf = this.consume(8); + const num = buf.readUInt32BE(0); + + // + // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned + // if payload length is greater than this number. + // + if (num > Math.pow(2, 53 - 32) - 1) { + const error = this.createError( + RangeError, + 'Unsupported WebSocket frame: payload length > 2^53 - 1', + false, + 1009, + 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH' + ); + + cb(error); + return; + } + + this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4); + this.haveLength(cb); + } + + /** + * Payload length has been read. + * + * @param {Function} cb Callback + * @private + */ + haveLength(cb) { + if (this._payloadLength && this._opcode < 0x08) { + this._totalPayloadLength += this._payloadLength; + if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { + const error = this.createError( + RangeError, + 'Max payload size exceeded', + false, + 1009, + 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' + ); + + cb(error); + return; + } + } + + if (this._masked) this._state = GET_MASK; + else this._state = GET_DATA; + } + + /** + * Reads mask bytes. + * + * @private + */ + getMask() { + if (this._bufferedBytes < 4) { + this._loop = false; + return; + } + + this._mask = this.consume(4); + this._state = GET_DATA; + } + + /** + * Reads data bytes. + * + * @param {Function} cb Callback + * @private + */ + getData(cb) { + let data = EMPTY_BUFFER; + + if (this._payloadLength) { + if (this._bufferedBytes < this._payloadLength) { + this._loop = false; + return; + } + + data = this.consume(this._payloadLength); + + if ( + this._masked && + (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0 + ) { + unmask(data, this._mask); + } + } + + if (this._opcode > 0x07) { + this.controlMessage(data, cb); + return; + } + + if (this._maxFragments > 0 && ++this._numFragments > this._maxFragments) { + const error = this.createError( + RangeError, + 'Too many message fragments', + false, + 1008, + 'WS_ERR_TOO_MANY_BUFFERED_PARTS' + ); + + cb(error); + return; + } + + if (this._compressed) { + this._state = INFLATING; + this.decompress(data, cb); + return; + } + + if (data.length) { + // + // This message is not compressed so its length is the sum of the payload + // length of all fragments. + // + this._messageLength = this._totalPayloadLength; + this._fragments.push(data); + } + + this.dataMessage(cb); + } + + /** + * Decompresses data. + * + * @param {Buffer} data Compressed data + * @param {Function} cb Callback + * @private + */ + decompress(data, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + + perMessageDeflate.decompress(data, this._fin, (err, buf) => { + if (err) return cb(err); + + if (buf.length) { + this._messageLength += buf.length; + if (this._messageLength > this._maxPayload && this._maxPayload > 0) { + const error = this.createError( + RangeError, + 'Max payload size exceeded', + false, + 1009, + 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' + ); + + cb(error); + return; + } + + this._fragments.push(buf); + } + + this.dataMessage(cb); + if (this._state === GET_INFO) this.startLoop(cb); + }); + } + + /** + * Handles a data message. + * + * @param {Function} cb Callback + * @private + */ + dataMessage(cb) { + if (!this._fin) { + this._state = GET_INFO; + return; + } + + const messageLength = this._messageLength; + const fragments = this._fragments; + + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragmented = 0; + this._numFragments = 0; + this._fragments = []; + + if (this._opcode === 2) { + let data; + + if (this._binaryType === 'nodebuffer') { + data = concat(fragments, messageLength); + } else if (this._binaryType === 'arraybuffer') { + data = toArrayBuffer(concat(fragments, messageLength)); + } else if (this._binaryType === 'blob') { + data = new Blob(fragments); + } else { + data = fragments; + } + + if (this._allowSynchronousEvents) { + this.emit('message', data, true); + this._state = GET_INFO; + } else { + this._state = DEFER_EVENT; + setImmediate(() => { + this.emit('message', data, true); + this._state = GET_INFO; + this.startLoop(cb); + }); + } + } else { + const buf = concat(fragments, messageLength); + + if (!this._skipUTF8Validation && !isValidUTF8(buf)) { + const error = this.createError( + Error, + 'invalid UTF-8 sequence', + true, + 1007, + 'WS_ERR_INVALID_UTF8' + ); + + cb(error); + return; + } + + if (this._state === INFLATING || this._allowSynchronousEvents) { + this.emit('message', buf, false); + this._state = GET_INFO; + } else { + this._state = DEFER_EVENT; + setImmediate(() => { + this.emit('message', buf, false); + this._state = GET_INFO; + this.startLoop(cb); + }); + } + } + } + + /** + * Handles a control message. + * + * @param {Buffer} data Data to handle + * @return {(Error|RangeError|undefined)} A possible error + * @private + */ + controlMessage(data, cb) { + if (this._opcode === 0x08) { + if (data.length === 0) { + this._loop = false; + this.emit('conclude', 1005, EMPTY_BUFFER); + this.end(); + } else { + const code = data.readUInt16BE(0); + + if (!isValidStatusCode(code)) { + const error = this.createError( + RangeError, + `invalid status code ${code}`, + true, + 1002, + 'WS_ERR_INVALID_CLOSE_CODE' + ); + + cb(error); + return; + } + + const buf = new FastBuffer( + data.buffer, + data.byteOffset + 2, + data.length - 2 + ); + + if (!this._skipUTF8Validation && !isValidUTF8(buf)) { + const error = this.createError( + Error, + 'invalid UTF-8 sequence', + true, + 1007, + 'WS_ERR_INVALID_UTF8' + ); + + cb(error); + return; + } + + this._loop = false; + this.emit('conclude', code, buf); + this.end(); + } + + this._state = GET_INFO; + return; + } + + if (this._allowSynchronousEvents) { + this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data); + this._state = GET_INFO; + } else { + this._state = DEFER_EVENT; + setImmediate(() => { + this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data); + this._state = GET_INFO; + this.startLoop(cb); + }); + } + } + + /** + * Builds an error object. + * + * @param {function(new:Error|RangeError)} ErrorCtor The error constructor + * @param {String} message The error message + * @param {Boolean} prefix Specifies whether or not to add a default prefix to + * `message` + * @param {Number} statusCode The status code + * @param {String} errorCode The exposed error code + * @return {(Error|RangeError)} The error + * @private + */ + createError(ErrorCtor, message, prefix, statusCode, errorCode) { + this._loop = false; + this._errored = true; + + const err = new ErrorCtor( + prefix ? `Invalid WebSocket frame: ${message}` : message + ); + + Error.captureStackTrace(err, this.createError); + err.code = errorCode; + err[kStatusCode] = statusCode; + return err; + } +} + +module.exports = Receiver; diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/sender.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/sender.js new file mode 100644 index 0000000..2c767e2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/sender.js @@ -0,0 +1,607 @@ +/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex" }] */ + +'use strict'; + +const { Duplex } = require('stream'); +const { randomFillSync } = require('crypto'); +const { + types: { isUint8Array } +} = require('util'); + +const PerMessageDeflate = require('./permessage-deflate'); +const { EMPTY_BUFFER, kWebSocket, NOOP } = require('./constants'); +const { isBlob, isValidStatusCode } = require('./validation'); +const { mask: applyMask, toBuffer } = require('./buffer-util'); + +const kByteLength = Symbol('kByteLength'); +const maskBuffer = Buffer.alloc(4); +const RANDOM_POOL_SIZE = 8 * 1024; +let randomPool; +let randomPoolPointer = RANDOM_POOL_SIZE; + +const DEFAULT = 0; +const DEFLATING = 1; +const GET_BLOB_DATA = 2; + +/** + * HyBi Sender implementation. + */ +class Sender { + /** + * Creates a Sender instance. + * + * @param {Duplex} socket The connection socket + * @param {Object} [extensions] An object containing the negotiated extensions + * @param {Function} [generateMask] The function used to generate the masking + * key + */ + constructor(socket, extensions, generateMask) { + this._extensions = extensions || {}; + + if (generateMask) { + this._generateMask = generateMask; + this._maskBuffer = Buffer.alloc(4); + } + + this._socket = socket; + + this._firstFragment = true; + this._compress = false; + + this._bufferedBytes = 0; + this._queue = []; + this._state = DEFAULT; + this.onerror = NOOP; + this[kWebSocket] = undefined; + } + + /** + * Frames a piece of data according to the HyBi WebSocket protocol. + * + * @param {(Buffer|String)} data The data to frame + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @return {(Buffer|String)[]} The framed data + * @public + */ + static frame(data, options) { + let mask; + let merge = false; + let offset = 2; + let skipMasking = false; + + if (options.mask) { + mask = options.maskBuffer || maskBuffer; + + if (options.generateMask) { + options.generateMask(mask); + } else { + if (randomPoolPointer === RANDOM_POOL_SIZE) { + /* istanbul ignore else */ + if (randomPool === undefined) { + // + // This is lazily initialized because server-sent frames must not + // be masked so it may never be used. + // + randomPool = Buffer.alloc(RANDOM_POOL_SIZE); + } + + randomFillSync(randomPool, 0, RANDOM_POOL_SIZE); + randomPoolPointer = 0; + } + + mask[0] = randomPool[randomPoolPointer++]; + mask[1] = randomPool[randomPoolPointer++]; + mask[2] = randomPool[randomPoolPointer++]; + mask[3] = randomPool[randomPoolPointer++]; + } + + skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0; + offset = 6; + } + + let dataLength; + + if (typeof data === 'string') { + if ( + (!options.mask || skipMasking) && + options[kByteLength] !== undefined + ) { + dataLength = options[kByteLength]; + } else { + data = Buffer.from(data); + dataLength = data.length; + } + } else { + dataLength = data.length; + merge = options.mask && options.readOnly && !skipMasking; + } + + let payloadLength = dataLength; + + if (dataLength >= 65536) { + offset += 8; + payloadLength = 127; + } else if (dataLength > 125) { + offset += 2; + payloadLength = 126; + } + + const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset); + + target[0] = options.fin ? options.opcode | 0x80 : options.opcode; + if (options.rsv1) target[0] |= 0x40; + + target[1] = payloadLength; + + if (payloadLength === 126) { + target.writeUInt16BE(dataLength, 2); + } else if (payloadLength === 127) { + target[2] = target[3] = 0; + target.writeUIntBE(dataLength, 4, 6); + } + + if (!options.mask) return [target, data]; + + target[1] |= 0x80; + target[offset - 4] = mask[0]; + target[offset - 3] = mask[1]; + target[offset - 2] = mask[2]; + target[offset - 1] = mask[3]; + + if (skipMasking) return [target, data]; + + if (merge) { + applyMask(data, mask, target, offset, dataLength); + return [target]; + } + + applyMask(data, mask, data, 0, dataLength); + return [target, data]; + } + + /** + * Sends a close message to the other peer. + * + * @param {Number} [code] The status code component of the body + * @param {(String|Buffer)} [data] The message component of the body + * @param {Boolean} [mask=false] Specifies whether or not to mask the message + * @param {Function} [cb] Callback + * @public + */ + close(code, data, mask, cb) { + let buf; + + if (code === undefined) { + buf = EMPTY_BUFFER; + } else if (typeof code !== 'number' || !isValidStatusCode(code)) { + throw new TypeError('First argument must be a valid error code number'); + } else if (data === undefined || !data.length) { + buf = Buffer.allocUnsafe(2); + buf.writeUInt16BE(code, 0); + } else { + const length = Buffer.byteLength(data); + + if (length > 123) { + throw new RangeError('The message must not be greater than 123 bytes'); + } + + buf = Buffer.allocUnsafe(2 + length); + buf.writeUInt16BE(code, 0); + + if (typeof data === 'string') { + buf.write(data, 2); + } else if (isUint8Array(data)) { + buf.set(data, 2); + } else { + throw new TypeError('Second argument must be a string or a Uint8Array'); + } + } + + const options = { + [kByteLength]: buf.length, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 0x08, + readOnly: false, + rsv1: false + }; + + if (this._state !== DEFAULT) { + this.enqueue([this.dispatch, buf, false, options, cb]); + } else { + this.sendFrame(Sender.frame(buf, options), cb); + } + } + + /** + * Sends a ping message to the other peer. + * + * @param {*} data The message to send + * @param {Boolean} [mask=false] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback + * @public + */ + ping(data, mask, cb) { + let byteLength; + let readOnly; + + if (typeof data === 'string') { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else if (isBlob(data)) { + byteLength = data.size; + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; + } + + if (byteLength > 125) { + throw new RangeError('The data size must not be greater than 125 bytes'); + } + + const options = { + [kByteLength]: byteLength, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 0x09, + readOnly, + rsv1: false + }; + + if (isBlob(data)) { + if (this._state !== DEFAULT) { + this.enqueue([this.getBlobData, data, false, options, cb]); + } else { + this.getBlobData(data, false, options, cb); + } + } else if (this._state !== DEFAULT) { + this.enqueue([this.dispatch, data, false, options, cb]); + } else { + this.sendFrame(Sender.frame(data, options), cb); + } + } + + /** + * Sends a pong message to the other peer. + * + * @param {*} data The message to send + * @param {Boolean} [mask=false] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback + * @public + */ + pong(data, mask, cb) { + let byteLength; + let readOnly; + + if (typeof data === 'string') { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else if (isBlob(data)) { + byteLength = data.size; + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; + } + + if (byteLength > 125) { + throw new RangeError('The data size must not be greater than 125 bytes'); + } + + const options = { + [kByteLength]: byteLength, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 0x0a, + readOnly, + rsv1: false + }; + + if (isBlob(data)) { + if (this._state !== DEFAULT) { + this.enqueue([this.getBlobData, data, false, options, cb]); + } else { + this.getBlobData(data, false, options, cb); + } + } else if (this._state !== DEFAULT) { + this.enqueue([this.dispatch, data, false, options, cb]); + } else { + this.sendFrame(Sender.frame(data, options), cb); + } + } + + /** + * Sends a data message to the other peer. + * + * @param {*} data The message to send + * @param {Object} options Options object + * @param {Boolean} [options.binary=false] Specifies whether `data` is binary + * or text + * @param {Boolean} [options.compress=false] Specifies whether or not to + * compress `data` + * @param {Boolean} [options.fin=false] Specifies whether the fragment is the + * last one + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Function} [cb] Callback + * @public + */ + send(data, options, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + let opcode = options.binary ? 2 : 1; + let rsv1 = options.compress; + + let byteLength; + let readOnly; + + if (typeof data === 'string') { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else if (isBlob(data)) { + byteLength = data.size; + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; + } + + if (this._firstFragment) { + this._firstFragment = false; + if ( + rsv1 && + perMessageDeflate && + perMessageDeflate.params[ + perMessageDeflate._isServer + ? 'server_no_context_takeover' + : 'client_no_context_takeover' + ] + ) { + rsv1 = byteLength >= perMessageDeflate._threshold; + } + this._compress = rsv1; + } else { + rsv1 = false; + opcode = 0; + } + + if (options.fin) this._firstFragment = true; + + const opts = { + [kByteLength]: byteLength, + fin: options.fin, + generateMask: this._generateMask, + mask: options.mask, + maskBuffer: this._maskBuffer, + opcode, + readOnly, + rsv1 + }; + + if (isBlob(data)) { + if (this._state !== DEFAULT) { + this.enqueue([this.getBlobData, data, this._compress, opts, cb]); + } else { + this.getBlobData(data, this._compress, opts, cb); + } + } else if (this._state !== DEFAULT) { + this.enqueue([this.dispatch, data, this._compress, opts, cb]); + } else { + this.dispatch(data, this._compress, opts, cb); + } + } + + /** + * Gets the contents of a blob as binary data. + * + * @param {Blob} blob The blob + * @param {Boolean} [compress=false] Specifies whether or not to compress + * the data + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @param {Function} [cb] Callback + * @private + */ + getBlobData(blob, compress, options, cb) { + this._bufferedBytes += options[kByteLength]; + this._state = GET_BLOB_DATA; + + blob + .arrayBuffer() + .then((arrayBuffer) => { + if (this._socket.destroyed) { + const err = new Error( + 'The socket was closed while the blob was being read' + ); + + // + // `callCallbacks` is called in the next tick to ensure that errors + // that might be thrown in the callbacks behave like errors thrown + // outside the promise chain. + // + process.nextTick(callCallbacks, this, err, cb); + return; + } + + this._bufferedBytes -= options[kByteLength]; + const data = toBuffer(arrayBuffer); + + if (!compress) { + this._state = DEFAULT; + this.sendFrame(Sender.frame(data, options), cb); + this.dequeue(); + } else { + this.dispatch(data, compress, options, cb); + } + }) + .catch((err) => { + // + // `onError` is called in the next tick for the same reason that + // `callCallbacks` above is. + // + process.nextTick(onError, this, err, cb); + }); + } + + /** + * Dispatches a message. + * + * @param {(Buffer|String)} data The message to send + * @param {Boolean} [compress=false] Specifies whether or not to compress + * `data` + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @param {Function} [cb] Callback + * @private + */ + dispatch(data, compress, options, cb) { + if (!compress) { + this.sendFrame(Sender.frame(data, options), cb); + return; + } + + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + + this._bufferedBytes += options[kByteLength]; + this._state = DEFLATING; + perMessageDeflate.compress(data, options.fin, (_, buf) => { + if (this._socket.destroyed) { + const err = new Error( + 'The socket was closed while data was being compressed' + ); + + callCallbacks(this, err, cb); + return; + } + + this._bufferedBytes -= options[kByteLength]; + this._state = DEFAULT; + options.readOnly = false; + this.sendFrame(Sender.frame(buf, options), cb); + this.dequeue(); + }); + } + + /** + * Executes queued send operations. + * + * @private + */ + dequeue() { + while (this._state === DEFAULT && this._queue.length) { + const params = this._queue.shift(); + + this._bufferedBytes -= params[3][kByteLength]; + Reflect.apply(params[0], this, params.slice(1)); + } + } + + /** + * Enqueues a send operation. + * + * @param {Array} params Send operation parameters. + * @private + */ + enqueue(params) { + this._bufferedBytes += params[3][kByteLength]; + this._queue.push(params); + } + + /** + * Sends a frame. + * + * @param {(Buffer | String)[]} list The frame to send + * @param {Function} [cb] Callback + * @private + */ + sendFrame(list, cb) { + if (list.length === 2) { + this._socket.cork(); + this._socket.write(list[0]); + this._socket.write(list[1], cb); + this._socket.uncork(); + } else { + this._socket.write(list[0], cb); + } + } +} + +module.exports = Sender; + +/** + * Calls queued callbacks with an error. + * + * @param {Sender} sender The `Sender` instance + * @param {Error} err The error to call the callbacks with + * @param {Function} [cb] The first callback + * @private + */ +function callCallbacks(sender, err, cb) { + if (typeof cb === 'function') cb(err); + + for (let i = 0; i < sender._queue.length; i++) { + const params = sender._queue[i]; + const callback = params[params.length - 1]; + + if (typeof callback === 'function') callback(err); + } +} + +/** + * Handles a `Sender` error. + * + * @param {Sender} sender The `Sender` instance + * @param {Error} err The error + * @param {Function} [cb] The first pending callback + * @private + */ +function onError(sender, err, cb) { + callCallbacks(sender, err, cb); + sender.onerror(err); +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/stream.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/stream.js new file mode 100644 index 0000000..4c58c91 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/stream.js @@ -0,0 +1,161 @@ +/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^WebSocket$" }] */ +'use strict'; + +const WebSocket = require('./websocket'); +const { Duplex } = require('stream'); + +/** + * Emits the `'close'` event on a stream. + * + * @param {Duplex} stream The stream. + * @private + */ +function emitClose(stream) { + stream.emit('close'); +} + +/** + * The listener of the `'end'` event. + * + * @private + */ +function duplexOnEnd() { + if (!this.destroyed && this._writableState.finished) { + this.destroy(); + } +} + +/** + * The listener of the `'error'` event. + * + * @param {Error} err The error + * @private + */ +function duplexOnError(err) { + this.removeListener('error', duplexOnError); + this.destroy(); + if (this.listenerCount('error') === 0) { + // Do not suppress the throwing behavior. + this.emit('error', err); + } +} + +/** + * Wraps a `WebSocket` in a duplex stream. + * + * @param {WebSocket} ws The `WebSocket` to wrap + * @param {Object} [options] The options for the `Duplex` constructor + * @return {Duplex} The duplex stream + * @public + */ +function createWebSocketStream(ws, options) { + let terminateOnDestroy = true; + + const duplex = new Duplex({ + ...options, + autoDestroy: false, + emitClose: false, + objectMode: false, + writableObjectMode: false + }); + + ws.on('message', function message(msg, isBinary) { + const data = + !isBinary && duplex._readableState.objectMode ? msg.toString() : msg; + + if (!duplex.push(data)) ws.pause(); + }); + + ws.once('error', function error(err) { + if (duplex.destroyed) return; + + // Prevent `ws.terminate()` from being called by `duplex._destroy()`. + // + // - If the `'error'` event is emitted before the `'open'` event, then + // `ws.terminate()` is a noop as no socket is assigned. + // - Otherwise, the error is re-emitted by the listener of the `'error'` + // event of the `Receiver` object. The listener already closes the + // connection by calling `ws.close()`. This allows a close frame to be + // sent to the other peer. If `ws.terminate()` is called right after this, + // then the close frame might not be sent. + terminateOnDestroy = false; + duplex.destroy(err); + }); + + ws.once('close', function close() { + if (duplex.destroyed) return; + + duplex.push(null); + }); + + duplex._destroy = function (err, callback) { + if (ws.readyState === ws.CLOSED) { + callback(err); + process.nextTick(emitClose, duplex); + return; + } + + let called = false; + + ws.once('error', function error(err) { + called = true; + callback(err); + }); + + ws.once('close', function close() { + if (!called) callback(err); + process.nextTick(emitClose, duplex); + }); + + if (terminateOnDestroy) ws.terminate(); + }; + + duplex._final = function (callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once('open', function open() { + duplex._final(callback); + }); + return; + } + + // If the value of the `_socket` property is `null` it means that `ws` is a + // client websocket and the handshake failed. In fact, when this happens, a + // socket is never assigned to the websocket. Wait for the `'error'` event + // that will be emitted by the websocket. + if (ws._socket === null) return; + + if (ws._socket._writableState.finished) { + callback(); + if (duplex._readableState.endEmitted) duplex.destroy(); + } else { + ws._socket.once('finish', function finish() { + // `duplex` is not destroyed here because the `'end'` event will be + // emitted on `duplex` after this `'finish'` event. The EOF signaling + // `null` chunk is, in fact, pushed when the websocket emits `'close'`. + callback(); + }); + ws.close(); + } + }; + + duplex._read = function () { + if (ws.isPaused) ws.resume(); + }; + + duplex._write = function (chunk, encoding, callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once('open', function open() { + duplex._write(chunk, encoding, callback); + }); + return; + } + + ws.send(chunk, callback); + }; + + duplex.on('end', duplexOnEnd); + duplex.on('error', duplexOnError); + return duplex; +} + +module.exports = createWebSocketStream; diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/subprotocol.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/subprotocol.js new file mode 100644 index 0000000..d4381e8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/subprotocol.js @@ -0,0 +1,62 @@ +'use strict'; + +const { tokenChars } = require('./validation'); + +/** + * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names. + * + * @param {String} header The field value of the header + * @return {Set} The subprotocol names + * @public + */ +function parse(header) { + const protocols = new Set(); + let start = -1; + let end = -1; + let i = 0; + + for (i; i < header.length; i++) { + const code = header.charCodeAt(i); + + if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if ( + i !== 0 && + (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */ + ) { + if (end === -1 && start !== -1) end = i; + } else if (code === 0x2c /* ',' */) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + + const protocol = header.slice(start, end); + + if (protocols.has(protocol)) { + throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + } + + protocols.add(protocol); + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } + + if (start === -1 || end !== -1) { + throw new SyntaxError('Unexpected end of input'); + } + + const protocol = header.slice(start, i); + + if (protocols.has(protocol)) { + throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + } + + protocols.add(protocol); + return protocols; +} + +module.exports = { parse }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/validation.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/validation.js new file mode 100644 index 0000000..4a2e68d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/validation.js @@ -0,0 +1,152 @@ +'use strict'; + +const { isUtf8 } = require('buffer'); + +const { hasBlob } = require('./constants'); + +// +// Allowed token characters: +// +// '!', '#', '$', '%', '&', ''', '*', '+', '-', +// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~' +// +// tokenChars[32] === 0 // ' ' +// tokenChars[33] === 1 // '!' +// tokenChars[34] === 0 // '"' +// ... +// +// prettier-ignore +const tokenChars = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127 +]; + +/** + * Checks if a status code is allowed in a close frame. + * + * @param {Number} code The status code + * @return {Boolean} `true` if the status code is valid, else `false` + * @public + */ +function isValidStatusCode(code) { + return ( + (code >= 1000 && + code <= 1014 && + code !== 1004 && + code !== 1005 && + code !== 1006) || + (code >= 3000 && code <= 4999) + ); +} + +/** + * Checks if a given buffer contains only correct UTF-8. + * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by + * Markus Kuhn. + * + * @param {Buffer} buf The buffer to check + * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false` + * @public + */ +function _isValidUTF8(buf) { + const len = buf.length; + let i = 0; + + while (i < len) { + if ((buf[i] & 0x80) === 0) { + // 0xxxxxxx + i++; + } else if ((buf[i] & 0xe0) === 0xc0) { + // 110xxxxx 10xxxxxx + if ( + i + 1 === len || + (buf[i + 1] & 0xc0) !== 0x80 || + (buf[i] & 0xfe) === 0xc0 // Overlong + ) { + return false; + } + + i += 2; + } else if ((buf[i] & 0xf0) === 0xe0) { + // 1110xxxx 10xxxxxx 10xxxxxx + if ( + i + 2 >= len || + (buf[i + 1] & 0xc0) !== 0x80 || + (buf[i + 2] & 0xc0) !== 0x80 || + (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong + (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF) + ) { + return false; + } + + i += 3; + } else if ((buf[i] & 0xf8) === 0xf0) { + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + if ( + i + 3 >= len || + (buf[i + 1] & 0xc0) !== 0x80 || + (buf[i + 2] & 0xc0) !== 0x80 || + (buf[i + 3] & 0xc0) !== 0x80 || + (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong + (buf[i] === 0xf4 && buf[i + 1] > 0x8f) || + buf[i] > 0xf4 // > U+10FFFF + ) { + return false; + } + + i += 4; + } else { + return false; + } + } + + return true; +} + +/** + * Determines whether a value is a `Blob`. + * + * @param {*} value The value to be tested + * @return {Boolean} `true` if `value` is a `Blob`, else `false` + * @private + */ +function isBlob(value) { + return ( + hasBlob && + typeof value === 'object' && + typeof value.arrayBuffer === 'function' && + typeof value.type === 'string' && + typeof value.stream === 'function' && + (value[Symbol.toStringTag] === 'Blob' || + value[Symbol.toStringTag] === 'File') + ); +} + +module.exports = { + isBlob, + isValidStatusCode, + isValidUTF8: _isValidUTF8, + tokenChars +}; + +if (isUtf8) { + module.exports.isValidUTF8 = function (buf) { + return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf); + }; +} /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) { + try { + const isValidUTF8 = require('utf-8-validate'); + + module.exports.isValidUTF8 = function (buf) { + return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf); + }; + } catch (e) { + // Continue regardless of the error. + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/websocket-server.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/websocket-server.js new file mode 100644 index 0000000..4d85919 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/websocket-server.js @@ -0,0 +1,562 @@ +/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$", "caughtErrors": "none" }] */ + +'use strict'; + +const EventEmitter = require('events'); +const http = require('http'); +const { Duplex } = require('stream'); +const { createHash } = require('crypto'); + +const extension = require('./extension'); +const PerMessageDeflate = require('./permessage-deflate'); +const subprotocol = require('./subprotocol'); +const WebSocket = require('./websocket'); +const { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants'); + +const keyRegex = /^[+/0-9A-Za-z]{22}==$/; + +const RUNNING = 0; +const CLOSING = 1; +const CLOSED = 2; + +/** + * Class representing a WebSocket server. + * + * @extends EventEmitter + */ +class WebSocketServer extends EventEmitter { + /** + * Create a `WebSocketServer` instance. + * + * @param {Object} options Configuration options + * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether + * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted + * multiple times in the same tick + * @param {Boolean} [options.autoPong=true] Specifies whether or not to + * automatically send a pong in response to a ping + * @param {Number} [options.backlog=511] The maximum length of the queue of + * pending connections + * @param {Boolean} [options.clientTracking=true] Specifies whether or not to + * track clients + * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to + * wait for the closing handshake to finish after `websocket.close()` is + * called + * @param {Function} [options.handleProtocols] A hook to handle protocols + * @param {String} [options.host] The hostname where to bind the server + * @param {Number} [options.maxBufferedChunks=262144] The maximum number of + * buffered data chunks + * @param {Number} [options.maxFragments=16384] The maximum number of message + * fragments + * @param {Number} [options.maxPayload=104857600] The maximum allowed message + * size + * @param {Boolean} [options.noServer=false] Enable no server mode + * @param {String} [options.path] Accept only connections matching this path + * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable + * permessage-deflate + * @param {Number} [options.port] The port where to bind the server + * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S + * server to use + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @param {Function} [options.verifyClient] A hook to reject connections + * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket` + * class to use. It must be the `WebSocket` class or class that extends it + * @param {Function} [callback] A listener for the `listening` event + */ + constructor(options, callback) { + super(); + + options = { + allowSynchronousEvents: true, + autoPong: true, + maxBufferedChunks: 256 * 1024, + maxFragments: 16 * 1024, + maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, + perMessageDeflate: false, + handleProtocols: null, + clientTracking: true, + closeTimeout: CLOSE_TIMEOUT, + verifyClient: null, + noServer: false, + backlog: null, // use default (511 as implemented in net.js) + server: null, + host: null, + path: null, + port: null, + WebSocket, + ...options + }; + + if ( + (options.port == null && !options.server && !options.noServer) || + (options.port != null && (options.server || options.noServer)) || + (options.server && options.noServer) + ) { + throw new TypeError( + 'One and only one of the "port", "server", or "noServer" options ' + + 'must be specified' + ); + } + + if (options.port != null) { + this._server = http.createServer((req, res) => { + const body = http.STATUS_CODES[426]; + + res.writeHead(426, { + 'Content-Length': body.length, + 'Content-Type': 'text/plain' + }); + res.end(body); + }); + this._server.listen( + options.port, + options.host, + options.backlog, + callback + ); + } else if (options.server) { + this._server = options.server; + } + + if (this._server) { + const emitConnection = this.emit.bind(this, 'connection'); + + this._removeListeners = addListeners(this._server, { + listening: this.emit.bind(this, 'listening'), + error: this.emit.bind(this, 'error'), + upgrade: (req, socket, head) => { + this.handleUpgrade(req, socket, head, emitConnection); + } + }); + } + + if (options.perMessageDeflate === true) options.perMessageDeflate = {}; + if (options.clientTracking) { + this.clients = new Set(); + this._shouldEmitClose = false; + } + + this.options = options; + this._state = RUNNING; + } + + /** + * Returns the bound address, the address family name, and port of the server + * as reported by the operating system if listening on an IP socket. + * If the server is listening on a pipe or UNIX domain socket, the name is + * returned as a string. + * + * @return {(Object|String|null)} The address of the server + * @public + */ + address() { + if (this.options.noServer) { + throw new Error('The server is operating in "noServer" mode'); + } + + if (!this._server) return null; + return this._server.address(); + } + + /** + * Stop the server from accepting new connections and emit the `'close'` event + * when all existing connections are closed. + * + * @param {Function} [cb] A one-time listener for the `'close'` event + * @public + */ + close(cb) { + if (this._state === CLOSED) { + if (cb) { + this.once('close', () => { + cb(new Error('The server is not running')); + }); + } + + process.nextTick(emitClose, this); + return; + } + + if (cb) this.once('close', cb); + + if (this._state === CLOSING) return; + this._state = CLOSING; + + if (this.options.noServer || this.options.server) { + if (this._server) { + this._removeListeners(); + this._removeListeners = this._server = null; + } + + if (this.clients) { + if (!this.clients.size) { + process.nextTick(emitClose, this); + } else { + this._shouldEmitClose = true; + } + } else { + process.nextTick(emitClose, this); + } + } else { + const server = this._server; + + this._removeListeners(); + this._removeListeners = this._server = null; + + // + // The HTTP/S server was created internally. Close it, and rely on its + // `'close'` event. + // + server.close(() => { + emitClose(this); + }); + } + } + + /** + * See if a given request should be handled by this server instance. + * + * @param {http.IncomingMessage} req Request object to inspect + * @return {Boolean} `true` if the request is valid, else `false` + * @public + */ + shouldHandle(req) { + if (this.options.path) { + const index = req.url.indexOf('?'); + const pathname = index !== -1 ? req.url.slice(0, index) : req.url; + + if (pathname !== this.options.path) return false; + } + + return true; + } + + /** + * Handle a HTTP Upgrade request. + * + * @param {http.IncomingMessage} req The request object + * @param {Duplex} socket The network socket between the server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @public + */ + handleUpgrade(req, socket, head, cb) { + socket.on('error', socketOnError); + + const key = req.headers['sec-websocket-key']; + const upgrade = req.headers.upgrade; + const version = +req.headers['sec-websocket-version']; + + if (req.method !== 'GET') { + const message = 'Invalid HTTP method'; + abortHandshakeOrEmitwsClientError(this, req, socket, 405, message); + return; + } + + if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') { + const message = 'Invalid Upgrade header'; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + + if (key === undefined || !keyRegex.test(key)) { + const message = 'Missing or invalid Sec-WebSocket-Key header'; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + + if (version !== 13 && version !== 8) { + const message = 'Missing or invalid Sec-WebSocket-Version header'; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, { + 'Sec-WebSocket-Version': '13, 8' + }); + return; + } + + if (!this.shouldHandle(req)) { + abortHandshake(socket, 400); + return; + } + + const secWebSocketProtocol = req.headers['sec-websocket-protocol']; + let protocols = new Set(); + + if (secWebSocketProtocol !== undefined) { + try { + protocols = subprotocol.parse(secWebSocketProtocol); + } catch (err) { + const message = 'Invalid Sec-WebSocket-Protocol header'; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + } + + const secWebSocketExtensions = req.headers['sec-websocket-extensions']; + const extensions = {}; + + if ( + this.options.perMessageDeflate && + secWebSocketExtensions !== undefined + ) { + const perMessageDeflate = new PerMessageDeflate({ + ...this.options.perMessageDeflate, + isServer: true, + maxPayload: this.options.maxPayload + }); + + try { + const offers = extension.parse(secWebSocketExtensions); + + if (offers[PerMessageDeflate.extensionName]) { + perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); + extensions[PerMessageDeflate.extensionName] = perMessageDeflate; + } + } catch (err) { + const message = + 'Invalid or unacceptable Sec-WebSocket-Extensions header'; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + } + + // + // Optionally call external client verification handler. + // + if (this.options.verifyClient) { + const info = { + origin: + req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`], + secure: !!(req.socket.authorized || req.socket.encrypted), + req + }; + + if (this.options.verifyClient.length === 2) { + this.options.verifyClient(info, (verified, code, message, headers) => { + if (!verified) { + return abortHandshake(socket, code || 401, message, headers); + } + + this.completeUpgrade( + extensions, + key, + protocols, + req, + socket, + head, + cb + ); + }); + return; + } + + if (!this.options.verifyClient(info)) return abortHandshake(socket, 401); + } + + this.completeUpgrade(extensions, key, protocols, req, socket, head, cb); + } + + /** + * Upgrade the connection to WebSocket. + * + * @param {Object} extensions The accepted extensions + * @param {String} key The value of the `Sec-WebSocket-Key` header + * @param {Set} protocols The subprotocols + * @param {http.IncomingMessage} req The request object + * @param {Duplex} socket The network socket between the server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @throws {Error} If called more than once with the same socket + * @private + */ + completeUpgrade(extensions, key, protocols, req, socket, head, cb) { + // + // Destroy the socket if the client has already sent a FIN packet. + // + if (!socket.readable || !socket.writable) return socket.destroy(); + + if (socket[kWebSocket]) { + throw new Error( + 'server.handleUpgrade() was called more than once with the same ' + + 'socket, possibly due to a misconfiguration' + ); + } + + if (this._state > RUNNING) return abortHandshake(socket, 503); + + const digest = createHash('sha1') + .update(key + GUID) + .digest('base64'); + + const headers = [ + 'HTTP/1.1 101 Switching Protocols', + 'Upgrade: websocket', + 'Connection: Upgrade', + `Sec-WebSocket-Accept: ${digest}` + ]; + + const ws = new this.options.WebSocket(null, undefined, this.options); + + if (protocols.size) { + // + // Optionally call external protocol selection handler. + // + const protocol = this.options.handleProtocols + ? this.options.handleProtocols(protocols, req) + : protocols.values().next().value; + + if (protocol) { + headers.push(`Sec-WebSocket-Protocol: ${protocol}`); + ws._protocol = protocol; + } + } + + if (extensions[PerMessageDeflate.extensionName]) { + const params = extensions[PerMessageDeflate.extensionName].params; + const value = extension.format({ + [PerMessageDeflate.extensionName]: [params] + }); + headers.push(`Sec-WebSocket-Extensions: ${value}`); + ws._extensions = extensions; + } + + // + // Allow external modification/inspection of handshake headers. + // + this.emit('headers', headers, req); + + socket.write(headers.concat('\r\n').join('\r\n')); + socket.removeListener('error', socketOnError); + + ws.setSocket(socket, head, { + allowSynchronousEvents: this.options.allowSynchronousEvents, + maxBufferedChunks: this.options.maxBufferedChunks, + maxFragments: this.options.maxFragments, + maxPayload: this.options.maxPayload, + skipUTF8Validation: this.options.skipUTF8Validation + }); + + if (this.clients) { + this.clients.add(ws); + ws.on('close', () => { + this.clients.delete(ws); + + if (this._shouldEmitClose && !this.clients.size) { + process.nextTick(emitClose, this); + } + }); + } + + cb(ws, req); + } +} + +module.exports = WebSocketServer; + +/** + * Add event listeners on an `EventEmitter` using a map of + * pairs. + * + * @param {EventEmitter} server The event emitter + * @param {Object.} map The listeners to add + * @return {Function} A function that will remove the added listeners when + * called + * @private + */ +function addListeners(server, map) { + for (const event of Object.keys(map)) server.on(event, map[event]); + + return function removeListeners() { + for (const event of Object.keys(map)) { + server.removeListener(event, map[event]); + } + }; +} + +/** + * Emit a `'close'` event on an `EventEmitter`. + * + * @param {EventEmitter} server The event emitter + * @private + */ +function emitClose(server) { + server._state = CLOSED; + server.emit('close'); +} + +/** + * Handle socket errors. + * + * @private + */ +function socketOnError() { + this.destroy(); +} + +/** + * Close the connection when preconditions are not fulfilled. + * + * @param {Duplex} socket The socket of the upgrade request + * @param {Number} code The HTTP response status code + * @param {String} [message] The HTTP response body + * @param {Object} [headers] Additional HTTP response headers + * @private + */ +function abortHandshake(socket, code, message, headers) { + // + // The socket is writable unless the user destroyed or ended it before calling + // `server.handleUpgrade()` or in the `verifyClient` function, which is a user + // error. Handling this does not make much sense as the worst that can happen + // is that some of the data written by the user might be discarded due to the + // call to `socket.end()` below, which triggers an `'error'` event that in + // turn causes the socket to be destroyed. + // + message = message || http.STATUS_CODES[code]; + headers = { + Connection: 'close', + 'Content-Type': 'text/html', + 'Content-Length': Buffer.byteLength(message), + ...headers + }; + + socket.once('finish', socket.destroy); + + socket.end( + `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` + + Object.keys(headers) + .map((h) => `${h}: ${headers[h]}`) + .join('\r\n') + + '\r\n\r\n' + + message + ); +} + +/** + * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least + * one listener for it, otherwise call `abortHandshake()`. + * + * @param {WebSocketServer} server The WebSocket server + * @param {http.IncomingMessage} req The request object + * @param {Duplex} socket The socket of the upgrade request + * @param {Number} code The HTTP response status code + * @param {String} message The HTTP response body + * @param {Object} [headers] The HTTP response headers + * @private + */ +function abortHandshakeOrEmitwsClientError( + server, + req, + socket, + code, + message, + headers +) { + if (server.listenerCount('wsClientError')) { + const err = new Error(message); + Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError); + + server.emit('wsClientError', err, socket, req); + } else { + abortHandshake(socket, code, message, headers); + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/websocket.js b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/websocket.js new file mode 100644 index 0000000..ea58e7d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/websocket.js @@ -0,0 +1,1407 @@ +/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$", "caughtErrors": "none" }] */ + +'use strict'; + +const EventEmitter = require('events'); +const https = require('https'); +const http = require('http'); +const net = require('net'); +const tls = require('tls'); +const { randomBytes, createHash } = require('crypto'); +const { Duplex, Readable } = require('stream'); +const { URL } = require('url'); + +const PerMessageDeflate = require('./permessage-deflate'); +const Receiver = require('./receiver'); +const Sender = require('./sender'); +const { isBlob } = require('./validation'); + +const { + BINARY_TYPES, + CLOSE_TIMEOUT, + EMPTY_BUFFER, + GUID, + kForOnEventAttribute, + kListener, + kStatusCode, + kWebSocket, + NOOP +} = require('./constants'); +const { + EventTarget: { addEventListener, removeEventListener } +} = require('./event-target'); +const { format, parse } = require('./extension'); +const { toBuffer } = require('./buffer-util'); + +const kAborted = Symbol('kAborted'); +const protocolVersions = [8, 13]; +const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; +const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; + +/** + * Class representing a WebSocket. + * + * @extends EventEmitter + */ +class WebSocket extends EventEmitter { + /** + * Create a new `WebSocket`. + * + * @param {(String|URL)} address The URL to which to connect + * @param {(String|String[])} [protocols] The subprotocols + * @param {Object} [options] Connection options + */ + constructor(address, protocols, options) { + super(); + + this._binaryType = BINARY_TYPES[0]; + this._closeCode = 1006; + this._closeFrameReceived = false; + this._closeFrameSent = false; + this._closeMessage = EMPTY_BUFFER; + this._closeTimer = null; + this._errorEmitted = false; + this._extensions = {}; + this._paused = false; + this._protocol = ''; + this._readyState = WebSocket.CONNECTING; + this._receiver = null; + this._sender = null; + this._socket = null; + + if (address !== null) { + this._bufferedAmount = 0; + this._isServer = false; + this._redirects = 0; + + if (protocols === undefined) { + protocols = []; + } else if (!Array.isArray(protocols)) { + if (typeof protocols === 'object' && protocols !== null) { + options = protocols; + protocols = []; + } else { + protocols = [protocols]; + } + } + + initAsClient(this, address, protocols, options); + } else { + this._autoPong = options.autoPong; + this._closeTimeout = options.closeTimeout; + this._isServer = true; + } + } + + /** + * For historical reasons, the custom "nodebuffer" type is used by the default + * instead of "blob". + * + * @type {String} + */ + get binaryType() { + return this._binaryType; + } + + set binaryType(type) { + if (!BINARY_TYPES.includes(type)) return; + + this._binaryType = type; + + // + // Allow to change `binaryType` on the fly. + // + if (this._receiver) this._receiver._binaryType = type; + } + + /** + * @type {Number} + */ + get bufferedAmount() { + if (!this._socket) return this._bufferedAmount; + + return this._socket._writableState.length + this._sender._bufferedBytes; + } + + /** + * @type {String} + */ + get extensions() { + return Object.keys(this._extensions).join(); + } + + /** + * @type {Boolean} + */ + get isPaused() { + return this._paused; + } + + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onclose() { + return null; + } + + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onerror() { + return null; + } + + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onopen() { + return null; + } + + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onmessage() { + return null; + } + + /** + * @type {String} + */ + get protocol() { + return this._protocol; + } + + /** + * @type {Number} + */ + get readyState() { + return this._readyState; + } + + /** + * @type {String} + */ + get url() { + return this._url; + } + + /** + * Set up the socket and the internal resources. + * + * @param {Duplex} socket The network socket between the server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Object} options Options object + * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether + * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted + * multiple times in the same tick + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Number} [options.maxBufferedChunks=0] The maximum number of + * buffered data chunks + * @param {Number} [options.maxFragments=0] The maximum number of message + * fragments + * @param {Number} [options.maxPayload=0] The maximum allowed message size + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @private + */ + setSocket(socket, head, options) { + const receiver = new Receiver({ + allowSynchronousEvents: options.allowSynchronousEvents, + binaryType: this.binaryType, + extensions: this._extensions, + isServer: this._isServer, + maxBufferedChunks: options.maxBufferedChunks, + maxFragments: options.maxFragments, + maxPayload: options.maxPayload, + skipUTF8Validation: options.skipUTF8Validation + }); + + const sender = new Sender(socket, this._extensions, options.generateMask); + + this._receiver = receiver; + this._sender = sender; + this._socket = socket; + + receiver[kWebSocket] = this; + sender[kWebSocket] = this; + socket[kWebSocket] = this; + + receiver.on('conclude', receiverOnConclude); + receiver.on('drain', receiverOnDrain); + receiver.on('error', receiverOnError); + receiver.on('message', receiverOnMessage); + receiver.on('ping', receiverOnPing); + receiver.on('pong', receiverOnPong); + + sender.onerror = senderOnError; + + // + // These methods may not be available if `socket` is just a `Duplex`. + // + if (socket.setTimeout) socket.setTimeout(0); + if (socket.setNoDelay) socket.setNoDelay(); + + if (head.length > 0) socket.unshift(head); + + socket.on('close', socketOnClose); + socket.on('data', socketOnData); + socket.on('end', socketOnEnd); + socket.on('error', socketOnError); + + this._readyState = WebSocket.OPEN; + this.emit('open'); + } + + /** + * Emit the `'close'` event. + * + * @private + */ + emitClose() { + if (!this._socket) { + this._readyState = WebSocket.CLOSED; + this.emit('close', this._closeCode, this._closeMessage); + return; + } + + if (this._extensions[PerMessageDeflate.extensionName]) { + this._extensions[PerMessageDeflate.extensionName].cleanup(); + } + + this._receiver.removeAllListeners(); + this._readyState = WebSocket.CLOSED; + this.emit('close', this._closeCode, this._closeMessage); + } + + /** + * Start a closing handshake. + * + * +----------+ +-----------+ +----------+ + * - - -|ws.close()|-->|close frame|-->|ws.close()|- - - + * | +----------+ +-----------+ +----------+ | + * +----------+ +-----------+ | + * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING + * +----------+ +-----------+ | + * | | | +---+ | + * +------------------------+-->|fin| - - - - + * | +---+ | +---+ + * - - - - -|fin|<---------------------+ + * +---+ + * + * @param {Number} [code] Status code explaining why the connection is closing + * @param {(String|Buffer)} [data] The reason why the connection is + * closing + * @public + */ + close(code, data) { + if (this.readyState === WebSocket.CLOSED) return; + if (this.readyState === WebSocket.CONNECTING) { + const msg = 'WebSocket was closed before the connection was established'; + abortHandshake(this, this._req, msg); + return; + } + + if (this.readyState === WebSocket.CLOSING) { + if ( + this._closeFrameSent && + (this._closeFrameReceived || this._receiver._writableState.errorEmitted) + ) { + this._socket.end(); + } + + return; + } + + this._readyState = WebSocket.CLOSING; + this._sender.close(code, data, !this._isServer, (err) => { + // + // This error is handled by the `'error'` listener on the socket. We only + // want to know if the close frame has been sent here. + // + if (err) return; + + this._closeFrameSent = true; + + if ( + this._closeFrameReceived || + this._receiver._writableState.errorEmitted + ) { + this._socket.end(); + } + }); + + setCloseTimer(this); + } + + /** + * Pause the socket. + * + * @public + */ + pause() { + if ( + this.readyState === WebSocket.CONNECTING || + this.readyState === WebSocket.CLOSED + ) { + return; + } + + this._paused = true; + this._socket.pause(); + } + + /** + * Send a ping. + * + * @param {*} [data] The data to send + * @param {Boolean} [mask] Indicates whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when the ping is sent + * @public + */ + ping(data, mask, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); + } + + if (typeof data === 'function') { + cb = data; + data = mask = undefined; + } else if (typeof mask === 'function') { + cb = mask; + mask = undefined; + } + + if (typeof data === 'number') data = data.toString(); + + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + + if (mask === undefined) mask = !this._isServer; + this._sender.ping(data || EMPTY_BUFFER, mask, cb); + } + + /** + * Send a pong. + * + * @param {*} [data] The data to send + * @param {Boolean} [mask] Indicates whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when the pong is sent + * @public + */ + pong(data, mask, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); + } + + if (typeof data === 'function') { + cb = data; + data = mask = undefined; + } else if (typeof mask === 'function') { + cb = mask; + mask = undefined; + } + + if (typeof data === 'number') data = data.toString(); + + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + + if (mask === undefined) mask = !this._isServer; + this._sender.pong(data || EMPTY_BUFFER, mask, cb); + } + + /** + * Resume the socket. + * + * @public + */ + resume() { + if ( + this.readyState === WebSocket.CONNECTING || + this.readyState === WebSocket.CLOSED + ) { + return; + } + + this._paused = false; + if (!this._receiver._writableState.needDrain) this._socket.resume(); + } + + /** + * Send a data message. + * + * @param {*} data The message to send + * @param {Object} [options] Options object + * @param {Boolean} [options.binary] Specifies whether `data` is binary or + * text + * @param {Boolean} [options.compress] Specifies whether or not to compress + * `data` + * @param {Boolean} [options.fin=true] Specifies whether the fragment is the + * last one + * @param {Boolean} [options.mask] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when data is written out + * @public + */ + send(data, options, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); + } + + if (typeof options === 'function') { + cb = options; + options = {}; + } + + if (typeof data === 'number') data = data.toString(); + + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + + const opts = { + binary: typeof data !== 'string', + mask: !this._isServer, + compress: true, + fin: true, + ...options + }; + + if (!this._extensions[PerMessageDeflate.extensionName]) { + opts.compress = false; + } + + this._sender.send(data || EMPTY_BUFFER, opts, cb); + } + + /** + * Forcibly close the connection. + * + * @public + */ + terminate() { + if (this.readyState === WebSocket.CLOSED) return; + if (this.readyState === WebSocket.CONNECTING) { + const msg = 'WebSocket was closed before the connection was established'; + abortHandshake(this, this._req, msg); + return; + } + + if (this._socket) { + this._readyState = WebSocket.CLOSING; + this._socket.destroy(); + } + } +} + +/** + * @constant {Number} CONNECTING + * @memberof WebSocket + */ +Object.defineProperty(WebSocket, 'CONNECTING', { + enumerable: true, + value: readyStates.indexOf('CONNECTING') +}); + +/** + * @constant {Number} CONNECTING + * @memberof WebSocket.prototype + */ +Object.defineProperty(WebSocket.prototype, 'CONNECTING', { + enumerable: true, + value: readyStates.indexOf('CONNECTING') +}); + +/** + * @constant {Number} OPEN + * @memberof WebSocket + */ +Object.defineProperty(WebSocket, 'OPEN', { + enumerable: true, + value: readyStates.indexOf('OPEN') +}); + +/** + * @constant {Number} OPEN + * @memberof WebSocket.prototype + */ +Object.defineProperty(WebSocket.prototype, 'OPEN', { + enumerable: true, + value: readyStates.indexOf('OPEN') +}); + +/** + * @constant {Number} CLOSING + * @memberof WebSocket + */ +Object.defineProperty(WebSocket, 'CLOSING', { + enumerable: true, + value: readyStates.indexOf('CLOSING') +}); + +/** + * @constant {Number} CLOSING + * @memberof WebSocket.prototype + */ +Object.defineProperty(WebSocket.prototype, 'CLOSING', { + enumerable: true, + value: readyStates.indexOf('CLOSING') +}); + +/** + * @constant {Number} CLOSED + * @memberof WebSocket + */ +Object.defineProperty(WebSocket, 'CLOSED', { + enumerable: true, + value: readyStates.indexOf('CLOSED') +}); + +/** + * @constant {Number} CLOSED + * @memberof WebSocket.prototype + */ +Object.defineProperty(WebSocket.prototype, 'CLOSED', { + enumerable: true, + value: readyStates.indexOf('CLOSED') +}); + +[ + 'binaryType', + 'bufferedAmount', + 'extensions', + 'isPaused', + 'protocol', + 'readyState', + 'url' +].forEach((property) => { + Object.defineProperty(WebSocket.prototype, property, { enumerable: true }); +}); + +// +// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes. +// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface +// +['open', 'error', 'close', 'message'].forEach((method) => { + Object.defineProperty(WebSocket.prototype, `on${method}`, { + enumerable: true, + get() { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) return listener[kListener]; + } + + return null; + }, + set(handler) { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) { + this.removeListener(method, listener); + break; + } + } + + if (typeof handler !== 'function') return; + + this.addEventListener(method, handler, { + [kForOnEventAttribute]: true + }); + } + }); +}); + +WebSocket.prototype.addEventListener = addEventListener; +WebSocket.prototype.removeEventListener = removeEventListener; + +module.exports = WebSocket; + +/** + * Initialize a WebSocket client. + * + * @param {WebSocket} websocket The client to initialize + * @param {(String|URL)} address The URL to which to connect + * @param {Array} protocols The subprotocols + * @param {Object} [options] Connection options + * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any + * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple + * times in the same tick + * @param {Boolean} [options.autoPong=true] Specifies whether or not to + * automatically send a pong in response to a ping + * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait + * for the closing handshake to finish after `websocket.close()` is called + * @param {Function} [options.finishRequest] A function which can be used to + * customize the headers of each http request before it is sent + * @param {Boolean} [options.followRedirects=false] Whether or not to follow + * redirects + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the + * handshake request + * @param {Number} [options.maxBufferedChunks=262144] The maximum number of + * buffered data chunks + * @param {Number} [options.maxFragments=16384] The maximum number of message + * fragments + * @param {Number} [options.maxPayload=104857600] The maximum allowed message + * size + * @param {Number} [options.maxRedirects=10] The maximum number of redirects + * allowed + * @param {String} [options.origin] Value of the `Origin` or + * `Sec-WebSocket-Origin` header + * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable + * permessage-deflate + * @param {Number} [options.protocolVersion=13] Value of the + * `Sec-WebSocket-Version` header + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @private + */ +function initAsClient(websocket, address, protocols, options) { + const opts = { + allowSynchronousEvents: true, + autoPong: true, + closeTimeout: CLOSE_TIMEOUT, + protocolVersion: protocolVersions[1], + maxBufferedChunks: 256 * 1024, + maxFragments: 16 * 1024, + maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, + perMessageDeflate: true, + followRedirects: false, + maxRedirects: 10, + ...options, + socketPath: undefined, + hostname: undefined, + protocol: undefined, + timeout: undefined, + method: 'GET', + host: undefined, + path: undefined, + port: undefined + }; + + websocket._autoPong = opts.autoPong; + websocket._closeTimeout = opts.closeTimeout; + + if (!protocolVersions.includes(opts.protocolVersion)) { + throw new RangeError( + `Unsupported protocol version: ${opts.protocolVersion} ` + + `(supported versions: ${protocolVersions.join(', ')})` + ); + } + + let parsedUrl; + + if (address instanceof URL) { + parsedUrl = address; + } else { + try { + parsedUrl = new URL(address); + } catch { + throw new SyntaxError(`Invalid URL: ${address}`); + } + } + + if (parsedUrl.protocol === 'http:') { + parsedUrl.protocol = 'ws:'; + } else if (parsedUrl.protocol === 'https:') { + parsedUrl.protocol = 'wss:'; + } + + websocket._url = parsedUrl.href; + + const isSecure = parsedUrl.protocol === 'wss:'; + const isIpcUrl = parsedUrl.protocol === 'ws+unix:'; + let invalidUrlMessage; + + if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) { + invalidUrlMessage = + 'The URL\'s protocol must be one of "ws:", "wss:", ' + + '"http:", "https:", or "ws+unix:"'; + } else if (isIpcUrl && !parsedUrl.pathname) { + invalidUrlMessage = "The URL's pathname is empty"; + } else if (parsedUrl.hash) { + invalidUrlMessage = 'The URL contains a fragment identifier'; + } + + if (invalidUrlMessage) { + const err = new SyntaxError(invalidUrlMessage); + + if (websocket._redirects === 0) { + throw err; + } else { + emitErrorAndClose(websocket, err); + return; + } + } + + const defaultPort = isSecure ? 443 : 80; + const key = randomBytes(16).toString('base64'); + const request = isSecure ? https.request : http.request; + const protocolSet = new Set(); + let perMessageDeflate; + + opts.createConnection = + opts.createConnection || (isSecure ? tlsConnect : netConnect); + opts.defaultPort = opts.defaultPort || defaultPort; + opts.port = parsedUrl.port || defaultPort; + opts.host = parsedUrl.hostname.startsWith('[') + ? parsedUrl.hostname.slice(1, -1) + : parsedUrl.hostname; + opts.headers = { + ...opts.headers, + 'Sec-WebSocket-Version': opts.protocolVersion, + 'Sec-WebSocket-Key': key, + Connection: 'Upgrade', + Upgrade: 'websocket' + }; + opts.path = parsedUrl.pathname + parsedUrl.search; + opts.timeout = opts.handshakeTimeout; + + if (opts.perMessageDeflate) { + perMessageDeflate = new PerMessageDeflate({ + ...opts.perMessageDeflate, + isServer: false, + maxPayload: opts.maxPayload + }); + opts.headers['Sec-WebSocket-Extensions'] = format({ + [PerMessageDeflate.extensionName]: perMessageDeflate.offer() + }); + } + if (protocols.length) { + for (const protocol of protocols) { + if ( + typeof protocol !== 'string' || + !subprotocolRegex.test(protocol) || + protocolSet.has(protocol) + ) { + throw new SyntaxError( + 'An invalid or duplicated subprotocol was specified' + ); + } + + protocolSet.add(protocol); + } + + opts.headers['Sec-WebSocket-Protocol'] = protocols.join(','); + } + if (opts.origin) { + if (opts.protocolVersion < 13) { + opts.headers['Sec-WebSocket-Origin'] = opts.origin; + } else { + opts.headers.Origin = opts.origin; + } + } + if (parsedUrl.username || parsedUrl.password) { + opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; + } + + if (isIpcUrl) { + const parts = opts.path.split(':'); + + opts.socketPath = parts[0]; + opts.path = parts[1]; + } + + let req; + + if (opts.followRedirects) { + if (websocket._redirects === 0) { + websocket._originalIpc = isIpcUrl; + websocket._originalSecure = isSecure; + websocket._originalHostOrSocketPath = isIpcUrl + ? opts.socketPath + : parsedUrl.host; + + const headers = options && options.headers; + + // + // Shallow copy the user provided options so that headers can be changed + // without mutating the original object. + // + options = { ...options, headers: {} }; + + if (headers) { + for (const [key, value] of Object.entries(headers)) { + options.headers[key.toLowerCase()] = value; + } + } + } else if (websocket.listenerCount('redirect') === 0) { + const isSameHost = isIpcUrl + ? websocket._originalIpc + ? opts.socketPath === websocket._originalHostOrSocketPath + : false + : websocket._originalIpc + ? false + : parsedUrl.host === websocket._originalHostOrSocketPath; + + if (!isSameHost || (websocket._originalSecure && !isSecure)) { + // + // Match curl 7.77.0 behavior and drop the following headers. These + // headers are also dropped when following a redirect to a subdomain. + // + delete opts.headers.authorization; + delete opts.headers.cookie; + + if (!isSameHost) delete opts.headers.host; + + opts.auth = undefined; + } + } + + // + // Match curl 7.77.0 behavior and make the first `Authorization` header win. + // If the `Authorization` header is set, then there is nothing to do as it + // will take precedence. + // + if (opts.auth && !options.headers.authorization) { + options.headers.authorization = + 'Basic ' + Buffer.from(opts.auth).toString('base64'); + } + + req = websocket._req = request(opts); + + if (websocket._redirects) { + // + // Unlike what is done for the `'upgrade'` event, no early exit is + // triggered here if the user calls `websocket.close()` or + // `websocket.terminate()` from a listener of the `'redirect'` event. This + // is because the user can also call `request.destroy()` with an error + // before calling `websocket.close()` or `websocket.terminate()` and this + // would result in an error being emitted on the `request` object with no + // `'error'` event listeners attached. + // + websocket.emit('redirect', websocket.url, req); + } + } else { + req = websocket._req = request(opts); + } + + if (opts.timeout) { + req.on('timeout', () => { + abortHandshake(websocket, req, 'Opening handshake has timed out'); + }); + } + + req.on('error', (err) => { + if (req === null || req[kAborted]) return; + + req = websocket._req = null; + emitErrorAndClose(websocket, err); + }); + + req.on('response', (res) => { + const location = res.headers.location; + const statusCode = res.statusCode; + + if ( + location && + opts.followRedirects && + statusCode >= 300 && + statusCode < 400 + ) { + if (++websocket._redirects > opts.maxRedirects) { + abortHandshake(websocket, req, 'Maximum redirects exceeded'); + return; + } + + req.abort(); + + let addr; + + try { + addr = new URL(location, address); + } catch (e) { + const err = new SyntaxError(`Invalid URL: ${location}`); + emitErrorAndClose(websocket, err); + return; + } + + initAsClient(websocket, addr, protocols, options); + } else if (!websocket.emit('unexpected-response', req, res)) { + abortHandshake( + websocket, + req, + `Unexpected server response: ${res.statusCode}` + ); + } + }); + + req.on('upgrade', (res, socket, head) => { + websocket.emit('upgrade', res); + + // + // The user may have closed the connection from a listener of the + // `'upgrade'` event. + // + if (websocket.readyState !== WebSocket.CONNECTING) return; + + req = websocket._req = null; + + const upgrade = res.headers.upgrade; + + if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') { + abortHandshake(websocket, socket, 'Invalid Upgrade header'); + return; + } + + const digest = createHash('sha1') + .update(key + GUID) + .digest('base64'); + + if (res.headers['sec-websocket-accept'] !== digest) { + abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header'); + return; + } + + const serverProt = res.headers['sec-websocket-protocol']; + let protError; + + if (serverProt !== undefined) { + if (!protocolSet.size) { + protError = 'Server sent a subprotocol but none was requested'; + } else if (!protocolSet.has(serverProt)) { + protError = 'Server sent an invalid subprotocol'; + } + } else if (protocolSet.size) { + protError = 'Server sent no subprotocol'; + } + + if (protError) { + abortHandshake(websocket, socket, protError); + return; + } + + if (serverProt) websocket._protocol = serverProt; + + const secWebSocketExtensions = res.headers['sec-websocket-extensions']; + + if (secWebSocketExtensions !== undefined) { + if (!perMessageDeflate) { + const message = + 'Server sent a Sec-WebSocket-Extensions header but no extension ' + + 'was requested'; + abortHandshake(websocket, socket, message); + return; + } + + let extensions; + + try { + extensions = parse(secWebSocketExtensions); + } catch (err) { + const message = 'Invalid Sec-WebSocket-Extensions header'; + abortHandshake(websocket, socket, message); + return; + } + + const extensionNames = Object.keys(extensions); + + if ( + extensionNames.length !== 1 || + extensionNames[0] !== PerMessageDeflate.extensionName + ) { + const message = 'Server indicated an extension that was not requested'; + abortHandshake(websocket, socket, message); + return; + } + + try { + perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); + } catch (err) { + const message = 'Invalid Sec-WebSocket-Extensions header'; + abortHandshake(websocket, socket, message); + return; + } + + websocket._extensions[PerMessageDeflate.extensionName] = + perMessageDeflate; + } + + websocket.setSocket(socket, head, { + allowSynchronousEvents: opts.allowSynchronousEvents, + generateMask: opts.generateMask, + maxBufferedChunks: opts.maxBufferedChunks, + maxFragments: opts.maxFragments, + maxPayload: opts.maxPayload, + skipUTF8Validation: opts.skipUTF8Validation + }); + }); + + if (opts.finishRequest) { + opts.finishRequest(req, websocket); + } else { + req.end(); + } +} + +/** + * Emit the `'error'` and `'close'` events. + * + * @param {WebSocket} websocket The WebSocket instance + * @param {Error} The error to emit + * @private + */ +function emitErrorAndClose(websocket, err) { + websocket._readyState = WebSocket.CLOSING; + // + // The following assignment is practically useless and is done only for + // consistency. + // + websocket._errorEmitted = true; + websocket.emit('error', err); + websocket.emitClose(); +} + +/** + * Create a `net.Socket` and initiate a connection. + * + * @param {Object} options Connection options + * @return {net.Socket} The newly created socket used to start the connection + * @private + */ +function netConnect(options) { + options.path = options.socketPath; + return net.connect(options); +} + +/** + * Create a `tls.TLSSocket` and initiate a connection. + * + * @param {Object} options Connection options + * @return {tls.TLSSocket} The newly created socket used to start the connection + * @private + */ +function tlsConnect(options) { + options.path = undefined; + + if (!options.servername && options.servername !== '') { + options.servername = net.isIP(options.host) ? '' : options.host; + } + + return tls.connect(options); +} + +/** + * Abort the handshake and emit an error. + * + * @param {WebSocket} websocket The WebSocket instance + * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to + * abort or the socket to destroy + * @param {String} message The error message + * @private + */ +function abortHandshake(websocket, stream, message) { + websocket._readyState = WebSocket.CLOSING; + + const err = new Error(message); + Error.captureStackTrace(err, abortHandshake); + + if (stream.setHeader) { + stream[kAborted] = true; + stream.abort(); + + if (stream.socket && !stream.socket.destroyed) { + // + // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if + // called after the request completed. See + // https://github.com/websockets/ws/issues/1869. + // + stream.socket.destroy(); + } + + process.nextTick(emitErrorAndClose, websocket, err); + } else { + stream.destroy(err); + stream.once('error', websocket.emit.bind(websocket, 'error')); + stream.once('close', websocket.emitClose.bind(websocket)); + } +} + +/** + * Handle cases where the `ping()`, `pong()`, or `send()` methods are called + * when the `readyState` attribute is `CLOSING` or `CLOSED`. + * + * @param {WebSocket} websocket The WebSocket instance + * @param {*} [data] The data to send + * @param {Function} [cb] Callback + * @private + */ +function sendAfterClose(websocket, data, cb) { + if (data) { + const length = isBlob(data) ? data.size : toBuffer(data).length; + + // + // The `_bufferedAmount` property is used only when the peer is a client and + // the opening handshake fails. Under these circumstances, in fact, the + // `setSocket()` method is not called, so the `_socket` and `_sender` + // properties are set to `null`. + // + if (websocket._socket) websocket._sender._bufferedBytes += length; + else websocket._bufferedAmount += length; + } + + if (cb) { + const err = new Error( + `WebSocket is not open: readyState ${websocket.readyState} ` + + `(${readyStates[websocket.readyState]})` + ); + process.nextTick(cb, err); + } +} + +/** + * The listener of the `Receiver` `'conclude'` event. + * + * @param {Number} code The status code + * @param {Buffer} reason The reason for closing + * @private + */ +function receiverOnConclude(code, reason) { + const websocket = this[kWebSocket]; + + websocket._closeFrameReceived = true; + websocket._closeMessage = reason; + websocket._closeCode = code; + + if (websocket._socket[kWebSocket] === undefined) return; + + websocket._socket.removeListener('data', socketOnData); + process.nextTick(resume, websocket._socket); + + if (code === 1005) websocket.close(); + else websocket.close(code, reason); +} + +/** + * The listener of the `Receiver` `'drain'` event. + * + * @private + */ +function receiverOnDrain() { + const websocket = this[kWebSocket]; + + if (!websocket.isPaused) websocket._socket.resume(); +} + +/** + * The listener of the `Receiver` `'error'` event. + * + * @param {(RangeError|Error)} err The emitted error + * @private + */ +function receiverOnError(err) { + const websocket = this[kWebSocket]; + + if (websocket._socket[kWebSocket] !== undefined) { + websocket._socket.removeListener('data', socketOnData); + + // + // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See + // https://github.com/websockets/ws/issues/1940. + // + process.nextTick(resume, websocket._socket); + + websocket.close(err[kStatusCode]); + } + + if (!websocket._errorEmitted) { + websocket._errorEmitted = true; + websocket.emit('error', err); + } +} + +/** + * The listener of the `Receiver` `'finish'` event. + * + * @private + */ +function receiverOnFinish() { + this[kWebSocket].emitClose(); +} + +/** + * The listener of the `Receiver` `'message'` event. + * + * @param {Buffer|ArrayBuffer|Buffer[])} data The message + * @param {Boolean} isBinary Specifies whether the message is binary or not + * @private + */ +function receiverOnMessage(data, isBinary) { + this[kWebSocket].emit('message', data, isBinary); +} + +/** + * The listener of the `Receiver` `'ping'` event. + * + * @param {Buffer} data The data included in the ping frame + * @private + */ +function receiverOnPing(data) { + const websocket = this[kWebSocket]; + + if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP); + websocket.emit('ping', data); +} + +/** + * The listener of the `Receiver` `'pong'` event. + * + * @param {Buffer} data The data included in the pong frame + * @private + */ +function receiverOnPong(data) { + this[kWebSocket].emit('pong', data); +} + +/** + * Resume a readable stream + * + * @param {Readable} stream The readable stream + * @private + */ +function resume(stream) { + stream.resume(); +} + +/** + * The `Sender` error event handler. + * + * @param {Error} The error + * @private + */ +function senderOnError(err) { + const websocket = this[kWebSocket]; + + if (websocket.readyState === WebSocket.CLOSED) return; + if (websocket.readyState === WebSocket.OPEN) { + websocket._readyState = WebSocket.CLOSING; + setCloseTimer(websocket); + } + + // + // `socket.end()` is used instead of `socket.destroy()` to allow the other + // peer to finish sending queued data. There is no need to set a timer here + // because `CLOSING` means that it is already set or not needed. + // + this._socket.end(); + + if (!websocket._errorEmitted) { + websocket._errorEmitted = true; + websocket.emit('error', err); + } +} + +/** + * Set a timer to destroy the underlying raw socket of a WebSocket. + * + * @param {WebSocket} websocket The WebSocket instance + * @private + */ +function setCloseTimer(websocket) { + websocket._closeTimer = setTimeout( + websocket._socket.destroy.bind(websocket._socket), + websocket._closeTimeout + ); +} + +/** + * The listener of the socket `'close'` event. + * + * @private + */ +function socketOnClose() { + const websocket = this[kWebSocket]; + + this.removeListener('close', socketOnClose); + this.removeListener('data', socketOnData); + this.removeListener('end', socketOnEnd); + + websocket._readyState = WebSocket.CLOSING; + + // + // The close frame might not have been received or the `'end'` event emitted, + // for example, if the socket was destroyed due to an error. Ensure that the + // `receiver` stream is closed after writing any remaining buffered data to + // it. If the readable side of the socket is in flowing mode then there is no + // buffered data as everything has been already written. If instead, the + // socket is paused, any possible buffered data will be read as a single + // chunk. + // + if ( + !this._readableState.endEmitted && + !websocket._closeFrameReceived && + !websocket._receiver._writableState.errorEmitted && + this._readableState.length !== 0 + ) { + const chunk = this.read(this._readableState.length); + + websocket._receiver.write(chunk); + } + + websocket._receiver.end(); + + this[kWebSocket] = undefined; + + clearTimeout(websocket._closeTimer); + + if ( + websocket._receiver._writableState.finished || + websocket._receiver._writableState.errorEmitted + ) { + websocket.emitClose(); + } else { + websocket._receiver.on('error', receiverOnFinish); + websocket._receiver.on('finish', receiverOnFinish); + } +} + +/** + * The listener of the socket `'data'` event. + * + * @param {Buffer} chunk A chunk of data + * @private + */ +function socketOnData(chunk) { + if (!this[kWebSocket]._receiver.write(chunk)) { + this.pause(); + } +} + +/** + * The listener of the socket `'end'` event. + * + * @private + */ +function socketOnEnd() { + const websocket = this[kWebSocket]; + + websocket._readyState = WebSocket.CLOSING; + websocket._receiver.end(); + this.end(); +} + +/** + * The listener of the socket `'error'` event. + * + * @private + */ +function socketOnError() { + const websocket = this[kWebSocket]; + + this.removeListener('error', socketOnError); + this.on('error', NOOP); + + if (websocket) { + websocket._readyState = WebSocket.CLOSING; + this.destroy(); + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/package.json b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/package.json new file mode 100644 index 0000000..f3eceef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/package.json @@ -0,0 +1,74 @@ +{ + "name": "ws", + "version": "8.21.3", + "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js", + "keywords": [ + "HyBi", + "Push", + "RFC-6455", + "WebSocket", + "WebSockets", + "real-time" + ], + "homepage": "https://github.com/websockets/ws", + "bugs": "https://github.com/websockets/ws/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/websockets/ws.git" + }, + "author": "Einar Otto Stangvik (http://2x.io)", + "license": "MIT", + "main": "index.js", + "exports": { + ".": { + "browser": "./browser.js", + "import": "./wrapper.mjs", + "require": "./index.js" + }, + "./package.json": "./package.json" + }, + "browser": "browser.js", + "engines": { + "node": ">=10.0.0" + }, + "files": [ + "browser.js", + "index.js", + "lib/*.js", + "wrapper.mjs" + ], + "scripts": { + "test": "nyc --reporter=lcov --reporter=text mocha --throw-deprecation test/*.test.js", + "integration": "mocha --throw-deprecation test/*.integration.js", + "lint": "eslint . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\"" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "benchmark": "^2.1.4", + "bufferutil": "^4.0.1", + "eslint": "^10.0.1", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.0.0", + "globals": "^17.0.0", + "mocha": "^8.4.0", + "nyc": "^15.0.0", + "prettier": "^3.0.0", + "utf-8-validate": "^6.0.0" + }, + "allowScripts": { + "bufferutil": true, + "utf-8-validate": true + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/wrapper.mjs b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/wrapper.mjs new file mode 100644 index 0000000..a8ffabb --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/ws@8.21.3/node_modules/ws/wrapper.mjs @@ -0,0 +1,21 @@ +import createWebSocketStream from './lib/stream.js'; +import extension from './lib/extension.js'; +import PerMessageDeflate from './lib/permessage-deflate.js'; +import Receiver from './lib/receiver.js'; +import Sender from './lib/sender.js'; +import subprotocol from './lib/subprotocol.js'; +import WebSocket from './lib/websocket.js'; +import WebSocketServer from './lib/websocket-server.js'; + +export { + createWebSocketStream, + extension, + PerMessageDeflate, + Receiver, + Sender, + subprotocol, + WebSocket, + WebSocketServer +}; + +export default WebSocket; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/LICENSE b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/LICENSE new file mode 100644 index 0000000..c065796 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Colin McDonnell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/README.md b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/README.md new file mode 100644 index 0000000..cefb2a3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/README.md @@ -0,0 +1,191 @@ +

+ Zod logo +

Zod

+

+ TypeScript-first schema validation with static type inference +
+ by @colinhacks +

+

+
+ +

+Zod CI status +License +npm +discord server +stars +

+ +
+ Docs +   •   + Discord +   •   + 𝕏 +   •   + Bluesky +
+
+ +
+
+ +### [Read the docs →](https://zod.dev/api) + +
+
+ +## What is Zod? + +Zod is a TypeScript-first validation library. Define a schema and parse some data with it. You'll get back a strongly typed, validated result. + +```ts +import * as z from "zod"; + +const User = z.object({ + name: z.string(), +}); + +// some untrusted data... +const input = { + /* stuff */ +}; + +// the parsed result is validated and type safe! +const data = User.parse(input); + +// so you can use it with confidence :) +console.log(data.name); +``` + +
+ +## Features + +- Zero external dependencies +- Works in Node.js and all modern browsers +- Tiny: `2kb` core bundle (gzipped) +- Immutable API: methods return a new instance +- Concise interface +- Works with TypeScript and plain JS +- Built-in JSON Schema conversion +- Extensive ecosystem + +
+ +## Installation + +```sh +npm install zod +``` + +
+ +## Basic usage + +Before you can do anything else, you need to define a schema. For the purposes of this guide, we'll use a simple object schema. + +```ts +import * as z from "zod"; + +const Player = z.object({ + username: z.string(), + xp: z.number(), +}); +``` + +### Parsing data + +Given any Zod schema, use `.parse` to validate an input. If it's valid, Zod returns a strongly-typed _deep clone_ of the input. + +```ts +Player.parse({ username: "billie", xp: 100 }); +// => returns { username: "billie", xp: 100 } +``` + +**Note** — If your schema uses certain asynchronous APIs like `async` [refinements](https://zod.dev/api#refinements) or [transforms](https://zod.dev/api#transforms), you'll need to use the `.parseAsync()` method instead. + +```ts +const schema = z.string().refine(async (val) => val.length <= 8); + +await schema.parseAsync("hello"); +// => "hello" +``` + +### Handling errors + +When validation fails, the `.parse()` method will throw a `ZodError` instance with granular information about the validation issues. + +```ts +try { + Player.parse({ username: 42, xp: "100" }); +} catch (err) { + if (err instanceof z.ZodError) { + err.issues; + /* [ + { + expected: 'string', + code: 'invalid_type', + path: [ 'username' ], + message: 'Invalid input: expected string' + }, + { + expected: 'number', + code: 'invalid_type', + path: [ 'xp' ], + message: 'Invalid input: expected number' + } + ] */ + } +} +``` + +To avoid a `try/catch` block, you can use the `.safeParse()` method to get back a plain result object containing either the successfully parsed data or a `ZodError`. The result type is a [discriminated union](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions), so you can handle both cases conveniently. + +```ts +const result = Player.safeParse({ username: 42, xp: "100" }); +if (!result.success) { + result.error; // ZodError instance +} else { + result.data; // { username: string; xp: number } +} +``` + +**Note** — If your schema uses certain asynchronous APIs like `async` [refinements](https://zod.dev/api#refinements) or [transforms](https://zod.dev/api#transforms), you'll need to use the `.safeParseAsync()` method instead. + +```ts +const schema = z.string().refine(async (val) => val.length <= 8); + +await schema.safeParseAsync("hello"); +// => { success: true; data: "hello" } +``` + +### Inferring types + +Zod infers a static type from your schema definitions. You can extract this type with the `z.infer<>` utility and use it however you like. + +```ts +const Player = z.object({ + username: z.string(), + xp: z.number(), +}); + +// extract the inferred type +type Player = z.infer; + +// use it in your code +const player: Player = { username: "billie", xp: 100 }; +``` + +In some cases, the input & output types of a schema can diverge. For instance, the `.transform()` API can convert the input from one type to another. In these cases, you can extract the input and output types independently: + +```ts +const mySchema = z.string().transform((val) => val.length); + +type MySchemaIn = z.input; +// => string + +type MySchemaOut = z.output; // equivalent to z.infer +// number +``` diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.cjs b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.cjs new file mode 100644 index 0000000..3e30380 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.cjs @@ -0,0 +1,33 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.z = void 0; +const z = __importStar(require("./v4/classic/external.cjs")); +exports.z = z; +__exportStar(require("./v4/classic/external.cjs"), exports); +exports.default = z; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.d.cts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.d.cts new file mode 100644 index 0000000..ed2f3c3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.d.cts @@ -0,0 +1,4 @@ +import * as z from "./v4/classic/external.cjs"; +export * from "./v4/classic/external.cjs"; +export { z }; +export default z; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.d.ts new file mode 100644 index 0000000..b0bbaef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.d.ts @@ -0,0 +1,4 @@ +import * as z from "./v4/classic/external.js"; +export * from "./v4/classic/external.js"; +export { z }; +export default z; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js new file mode 100644 index 0000000..b0bbaef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js @@ -0,0 +1,4 @@ +import * as z from "./v4/classic/external.js"; +export * from "./v4/classic/external.js"; +export { z }; +export default z; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.cjs b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.cjs new file mode 100644 index 0000000..65f2079 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.cjs @@ -0,0 +1,17 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("../v4/locales/index.cjs"), exports); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.d.cts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.d.cts new file mode 100644 index 0000000..cd70ce6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.d.cts @@ -0,0 +1 @@ +export * from "../v4/locales/index.cjs"; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.d.ts new file mode 100644 index 0000000..e6e7dd6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.d.ts @@ -0,0 +1 @@ +export * from "../v4/locales/index.js"; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.js b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.js new file mode 100644 index 0000000..e6e7dd6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/index.js @@ -0,0 +1 @@ +export * from "../v4/locales/index.js"; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/package.json b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/package.json new file mode 100644 index 0000000..f5d2e90 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/locales/package.json @@ -0,0 +1,7 @@ +{ + "type": "module", + "main": "./index.cjs", + "module": "./index.js", + "types": "./index.d.cts", + "sideEffects": false +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.cjs b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.cjs new file mode 100644 index 0000000..90a31e2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.cjs @@ -0,0 +1,32 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.z = void 0; +const z = __importStar(require("../v4/mini/external.cjs")); +exports.z = z; +__exportStar(require("../v4/mini/external.cjs"), exports); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.d.cts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.d.cts new file mode 100644 index 0000000..bca69bd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.d.cts @@ -0,0 +1,3 @@ +import * as z from "../v4/mini/external.cjs"; +export * from "../v4/mini/external.cjs"; +export { z }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.d.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.d.ts new file mode 100644 index 0000000..bb95da0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.d.ts @@ -0,0 +1,3 @@ +import * as z from "../v4/mini/external.js"; +export * from "../v4/mini/external.js"; +export { z }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.js b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.js new file mode 100644 index 0000000..bb95da0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/index.js @@ -0,0 +1,3 @@ +import * as z from "../v4/mini/external.js"; +export * from "../v4/mini/external.js"; +export { z }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/package.json b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/package.json new file mode 100644 index 0000000..f5d2e90 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/mini/package.json @@ -0,0 +1,7 @@ +{ + "type": "module", + "main": "./index.cjs", + "module": "./index.js", + "types": "./index.d.cts", + "sideEffects": false +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/package.json b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/package.json new file mode 100644 index 0000000..8a0c194 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/package.json @@ -0,0 +1,135 @@ +{ + "name": "zod", + "version": "4.4.3", + "type": "module", + "license": "MIT", + "author": "Colin McDonnell ", + "description": "TypeScript-first schema declaration and validation library with static type inference", + "homepage": "https://zod.dev", + "llms": "https://zod.dev/llms.txt", + "llmsFull": "https://zod.dev/llms-full.txt", + "mcpServer": "https://mcp.inkeep.com/zod/mcp", + "funding": "https://github.com/sponsors/colinhacks", + "sideEffects": false, + "files": [ + "src", + "**/*.js", + "**/*.mjs", + "**/*.cjs", + "**/*.d.ts", + "**/*.d.mts", + "**/*.d.cts", + "**/package.json" + ], + "keywords": [ + "typescript", + "schema", + "validation", + "type", + "inference" + ], + "main": "./index.cjs", + "types": "./index.d.cts", + "module": "./index.js", + "zshy": { + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./mini": "./src/mini/index.ts", + "./locales": "./src/locales/index.ts", + "./v3": "./src/v3/index.ts", + "./v4": "./src/v4/index.ts", + "./v4-mini": "./src/v4-mini/index.ts", + "./v4/mini": "./src/v4/mini/index.ts", + "./v4/core": "./src/v4/core/index.ts", + "./v4/locales": "./src/v4/locales/index.ts", + "./v4/locales/*": "./src/v4/locales/*" + }, + "conditions": { + "@zod/source": "src" + } + }, + "exports": { + "./package.json": "./package.json", + ".": { + "@zod/source": "./src/index.ts", + "types": "./index.d.cts", + "import": "./index.js", + "require": "./index.cjs" + }, + "./mini": { + "@zod/source": "./src/mini/index.ts", + "types": "./mini/index.d.cts", + "import": "./mini/index.js", + "require": "./mini/index.cjs" + }, + "./locales": { + "@zod/source": "./src/locales/index.ts", + "types": "./locales/index.d.cts", + "import": "./locales/index.js", + "require": "./locales/index.cjs" + }, + "./v3": { + "@zod/source": "./src/v3/index.ts", + "types": "./v3/index.d.cts", + "import": "./v3/index.js", + "require": "./v3/index.cjs" + }, + "./v4": { + "@zod/source": "./src/v4/index.ts", + "types": "./v4/index.d.cts", + "import": "./v4/index.js", + "require": "./v4/index.cjs" + }, + "./v4-mini": { + "@zod/source": "./src/v4-mini/index.ts", + "types": "./v4-mini/index.d.cts", + "import": "./v4-mini/index.js", + "require": "./v4-mini/index.cjs" + }, + "./v4/mini": { + "@zod/source": "./src/v4/mini/index.ts", + "types": "./v4/mini/index.d.cts", + "import": "./v4/mini/index.js", + "require": "./v4/mini/index.cjs" + }, + "./v4/core": { + "@zod/source": "./src/v4/core/index.ts", + "types": "./v4/core/index.d.cts", + "import": "./v4/core/index.js", + "require": "./v4/core/index.cjs" + }, + "./v4/locales": { + "@zod/source": "./src/v4/locales/index.ts", + "types": "./v4/locales/index.d.cts", + "import": "./v4/locales/index.js", + "require": "./v4/locales/index.cjs" + }, + "./v4/locales/*": { + "@zod/source": "./src/v4/locales/*", + "types": "./v4/locales/*", + "import": "./v4/locales/*", + "require": "./v4/locales/*" + } + }, + "repository": { + "type": "git", + "url": "git+https://github.com/colinhacks/zod.git" + }, + "bugs": { + "url": "https://github.com/colinhacks/zod/issues" + }, + "support": { + "backing": { + "npm-funding": true + } + }, + "scripts": { + "clean": "git clean -xdf . -e node_modules", + "build": "zshy --project tsconfig.build.json", + "postbuild": "tsx ../../scripts/write-stub-package-jsons.ts && pnpm biome check --write .", + "test:watch": "pnpm vitest", + "test": "pnpm vitest run", + "prepublishOnly": "tsx ../../scripts/check-versions.ts" + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/index.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/index.ts new file mode 100644 index 0000000..b0bbaef --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/index.ts @@ -0,0 +1,4 @@ +import * as z from "./v4/classic/external.js"; +export * from "./v4/classic/external.js"; +export { z }; +export default z; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/locales/index.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/locales/index.ts new file mode 100644 index 0000000..e6e7dd6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/locales/index.ts @@ -0,0 +1 @@ +export * from "../v4/locales/index.js"; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/mini/index.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/mini/index.ts new file mode 100644 index 0000000..bb95da0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/mini/index.ts @@ -0,0 +1,3 @@ +import * as z from "../v4/mini/external.js"; +export * from "../v4/mini/external.js"; +export { z }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/ZodError.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/ZodError.ts new file mode 100644 index 0000000..b4c6865 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/ZodError.ts @@ -0,0 +1,330 @@ +import type { Primitive } from "./helpers/typeAliases.js"; +import { util, type ZodParsedType } from "./helpers/util.js"; +import type { TypeOf, ZodType } from "./index.js"; + +type allKeys = T extends any ? keyof T : never; + +export type inferFlattenedErrors, U = string> = typeToFlattenedError, U>; +export type typeToFlattenedError = { + formErrors: U[]; + fieldErrors: { + [P in allKeys]?: U[]; + }; +}; + +export const ZodIssueCode = util.arrayToEnum([ + "invalid_type", + "invalid_literal", + "custom", + "invalid_union", + "invalid_union_discriminator", + "invalid_enum_value", + "unrecognized_keys", + "invalid_arguments", + "invalid_return_type", + "invalid_date", + "invalid_string", + "too_small", + "too_big", + "invalid_intersection_types", + "not_multiple_of", + "not_finite", +]); + +export type ZodIssueCode = keyof typeof ZodIssueCode; + +export type ZodIssueBase = { + path: (string | number)[]; + message?: string | undefined; +}; + +export interface ZodInvalidTypeIssue extends ZodIssueBase { + code: typeof ZodIssueCode.invalid_type; + expected: ZodParsedType; + received: ZodParsedType; +} + +export interface ZodInvalidLiteralIssue extends ZodIssueBase { + code: typeof ZodIssueCode.invalid_literal; + expected: unknown; + received: unknown; +} + +export interface ZodUnrecognizedKeysIssue extends ZodIssueBase { + code: typeof ZodIssueCode.unrecognized_keys; + keys: string[]; +} + +export interface ZodInvalidUnionIssue extends ZodIssueBase { + code: typeof ZodIssueCode.invalid_union; + unionErrors: ZodError[]; +} + +export interface ZodInvalidUnionDiscriminatorIssue extends ZodIssueBase { + code: typeof ZodIssueCode.invalid_union_discriminator; + options: Primitive[]; +} + +export interface ZodInvalidEnumValueIssue extends ZodIssueBase { + received: string | number; + code: typeof ZodIssueCode.invalid_enum_value; + options: (string | number)[]; +} + +export interface ZodInvalidArgumentsIssue extends ZodIssueBase { + code: typeof ZodIssueCode.invalid_arguments; + argumentsError: ZodError; +} + +export interface ZodInvalidReturnTypeIssue extends ZodIssueBase { + code: typeof ZodIssueCode.invalid_return_type; + returnTypeError: ZodError; +} + +export interface ZodInvalidDateIssue extends ZodIssueBase { + code: typeof ZodIssueCode.invalid_date; +} + +export type StringValidation = + | "email" + | "url" + | "emoji" + | "uuid" + | "nanoid" + | "regex" + | "cuid" + | "cuid2" + | "ulid" + | "datetime" + | "date" + | "time" + | "duration" + | "ip" + | "cidr" + | "base64" + | "jwt" + | "base64url" + | { includes: string; position?: number | undefined } + | { startsWith: string } + | { endsWith: string }; + +export interface ZodInvalidStringIssue extends ZodIssueBase { + code: typeof ZodIssueCode.invalid_string; + validation: StringValidation; +} + +export interface ZodTooSmallIssue extends ZodIssueBase { + code: typeof ZodIssueCode.too_small; + minimum: number | bigint; + inclusive: boolean; + exact?: boolean; + type: "array" | "string" | "number" | "set" | "date" | "bigint"; +} + +export interface ZodTooBigIssue extends ZodIssueBase { + code: typeof ZodIssueCode.too_big; + maximum: number | bigint; + inclusive: boolean; + exact?: boolean; + type: "array" | "string" | "number" | "set" | "date" | "bigint"; +} + +export interface ZodInvalidIntersectionTypesIssue extends ZodIssueBase { + code: typeof ZodIssueCode.invalid_intersection_types; +} + +export interface ZodNotMultipleOfIssue extends ZodIssueBase { + code: typeof ZodIssueCode.not_multiple_of; + multipleOf: number | bigint; +} + +export interface ZodNotFiniteIssue extends ZodIssueBase { + code: typeof ZodIssueCode.not_finite; +} + +export interface ZodCustomIssue extends ZodIssueBase { + code: typeof ZodIssueCode.custom; + params?: { [k: string]: any }; +} + +export type DenormalizedError = { [k: string]: DenormalizedError | string[] }; + +export type ZodIssueOptionalMessage = + | ZodInvalidTypeIssue + | ZodInvalidLiteralIssue + | ZodUnrecognizedKeysIssue + | ZodInvalidUnionIssue + | ZodInvalidUnionDiscriminatorIssue + | ZodInvalidEnumValueIssue + | ZodInvalidArgumentsIssue + | ZodInvalidReturnTypeIssue + | ZodInvalidDateIssue + | ZodInvalidStringIssue + | ZodTooSmallIssue + | ZodTooBigIssue + | ZodInvalidIntersectionTypesIssue + | ZodNotMultipleOfIssue + | ZodNotFiniteIssue + | ZodCustomIssue; + +export type ZodIssue = ZodIssueOptionalMessage & { + fatal?: boolean | undefined; + message: string; +}; + +export const quotelessJson = (obj: any) => { + const json = JSON.stringify(obj, null, 2); + return json.replace(/"([^"]+)":/g, "$1:"); +}; + +type recursiveZodFormattedError = T extends [any, ...any[]] + ? { [K in keyof T]?: ZodFormattedError } + : T extends any[] + ? { [k: number]: ZodFormattedError } + : T extends object + ? { [K in keyof T]?: ZodFormattedError } + : unknown; + +export type ZodFormattedError = { + _errors: U[]; +} & recursiveZodFormattedError>; + +export type inferFormattedError, U = string> = ZodFormattedError, U>; + +export class ZodError extends Error { + issues: ZodIssue[] = []; + + get errors() { + return this.issues; + } + + constructor(issues: ZodIssue[]) { + super(); + + const actualProto = new.target.prototype; + if (Object.setPrototypeOf) { + // eslint-disable-next-line ban/ban + Object.setPrototypeOf(this, actualProto); + } else { + (this as any).__proto__ = actualProto; + } + this.name = "ZodError"; + this.issues = issues; + } + + format(): ZodFormattedError; + format(mapper: (issue: ZodIssue) => U): ZodFormattedError; + format(_mapper?: any) { + const mapper: (issue: ZodIssue) => any = + _mapper || + function (issue: ZodIssue) { + return issue.message; + }; + const fieldErrors: ZodFormattedError = { _errors: [] } as any; + const processError = (error: ZodError) => { + for (const issue of error.issues) { + if (issue.code === "invalid_union") { + issue.unionErrors.map(processError); + } else if (issue.code === "invalid_return_type") { + processError(issue.returnTypeError); + } else if (issue.code === "invalid_arguments") { + processError(issue.argumentsError); + } else if (issue.path.length === 0) { + (fieldErrors as any)._errors.push(mapper(issue)); + } else { + let curr: any = fieldErrors; + let i = 0; + while (i < issue.path.length) { + const el = issue.path[i]!; + const terminal = i === issue.path.length - 1; + + if (!terminal) { + curr[el] = curr[el] || { _errors: [] }; + // if (typeof el === "string") { + // curr[el] = curr[el] || { _errors: [] }; + // } else if (typeof el === "number") { + // const errorArray: any = []; + // errorArray._errors = []; + // curr[el] = curr[el] || errorArray; + // } + } else { + curr[el] = curr[el] || { _errors: [] }; + curr[el]._errors.push(mapper(issue)); + } + + curr = curr[el]; + i++; + } + } + } + }; + + processError(this); + return fieldErrors; + } + + static create = (issues: ZodIssue[]) => { + const error = new ZodError(issues); + return error; + }; + + static assert(value: unknown): asserts value is ZodError { + if (!(value instanceof ZodError)) { + throw new Error(`Not a ZodError: ${value}`); + } + } + + override toString() { + return this.message; + } + override get message() { + return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2); + } + + get isEmpty(): boolean { + return this.issues.length === 0; + } + + addIssue = (sub: ZodIssue) => { + this.issues = [...this.issues, sub]; + }; + + addIssues = (subs: ZodIssue[] = []) => { + this.issues = [...this.issues, ...subs]; + }; + + flatten(): typeToFlattenedError; + flatten(mapper?: (issue: ZodIssue) => U): typeToFlattenedError; + flatten(mapper: (issue: ZodIssue) => U = (issue: ZodIssue) => issue.message as any): any { + const fieldErrors: any = Object.create(null); + const formErrors: U[] = []; + for (const sub of this.issues) { + if (sub.path.length > 0) { + const firstEl = sub.path[0]!; + fieldErrors[firstEl] = fieldErrors[firstEl] || []; + fieldErrors[firstEl].push(mapper(sub)); + } else { + formErrors.push(mapper(sub)); + } + } + return { formErrors, fieldErrors }; + } + + get formErrors() { + return this.flatten(); + } +} + +type stripPath = T extends any ? util.OmitKeys : never; + +export type IssueData = stripPath & { + path?: (string | number)[]; + fatal?: boolean | undefined; +}; + +export type ErrorMapCtx = { + defaultError: string; + data: any; +}; + +export type ZodErrorMap = (issue: ZodIssueOptionalMessage, _ctx: ErrorMapCtx) => { message: string }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/datetime.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/datetime.ts new file mode 100644 index 0000000..85552c2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/datetime.ts @@ -0,0 +1,58 @@ +import Benchmark from "benchmark"; + +const datetimeValidationSuite = new Benchmark.Suite("datetime"); + +const DATA = "2021-01-01"; +const MONTHS_31 = new Set([1, 3, 5, 7, 8, 10, 12]); +const MONTHS_30 = new Set([4, 6, 9, 11]); + +const simpleDatetimeRegex = /^(\d{4})-(\d{2})-(\d{2})$/; +const datetimeRegexNoLeapYearValidation = + /^\d{4}-((0[13578]|10|12)-31|(0[13-9]|1[0-2])-30|(0[1-9]|1[0-2])-(0[1-9]|1\d|2\d))$/; +const datetimeRegexWithLeapYearValidation = + /^((\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\d|3[01])|(0[469]|11)-(0[1-9]|[12]\d|30)|(02)-(0[1-9]|1\d|2[0-8])))$/; + +datetimeValidationSuite + .add("new Date()", () => { + return !Number.isNaN(new Date(DATA).getTime()); + }) + .add("regex (no validation)", () => { + return simpleDatetimeRegex.test(DATA); + }) + .add("regex (no leap year)", () => { + return datetimeRegexNoLeapYearValidation.test(DATA); + }) + .add("regex (w/ leap year)", () => { + return datetimeRegexWithLeapYearValidation.test(DATA); + }) + .add("capture groups + code", () => { + const match = DATA.match(simpleDatetimeRegex); + if (!match) return false; + + // Extract year, month, and day from the capture groups + const year = Number.parseInt(match[1], 10); + const month = Number.parseInt(match[2], 10); // month is 0-indexed in JavaScript Date, so subtract 1 + const day = Number.parseInt(match[3], 10); + + if (month === 2) { + if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) { + return day <= 29; + } + return day <= 28; + } + if (MONTHS_30.has(month)) { + return day <= 30; + } + if (MONTHS_31.has(month)) { + return day <= 31; + } + return false; + }) + + .on("cycle", (e: Benchmark.Event) => { + console.log(`${datetimeValidationSuite.name!}: ${e.target}`); + }); + +export default { + suites: [datetimeValidationSuite], +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/discriminatedUnion.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/discriminatedUnion.ts new file mode 100644 index 0000000..47737e6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/discriminatedUnion.ts @@ -0,0 +1,80 @@ +import Benchmark from "benchmark"; + +import { z } from "zod/v3"; + +const doubleSuite = new Benchmark.Suite("z.discriminatedUnion: double"); +const manySuite = new Benchmark.Suite("z.discriminatedUnion: many"); + +const aSchema = z.object({ + type: z.literal("a"), +}); +const objA = { + type: "a", +}; + +const bSchema = z.object({ + type: z.literal("b"), +}); +const objB = { + type: "b", +}; + +const cSchema = z.object({ + type: z.literal("c"), +}); +const objC = { + type: "c", +}; + +const dSchema = z.object({ + type: z.literal("d"), +}); + +const double = z.discriminatedUnion("type", [aSchema, bSchema]); +const many = z.discriminatedUnion("type", [aSchema, bSchema, cSchema, dSchema]); + +doubleSuite + .add("valid: a", () => { + double.parse(objA); + }) + .add("valid: b", () => { + double.parse(objB); + }) + .add("invalid: null", () => { + try { + double.parse(null); + } catch (_err) {} + }) + .add("invalid: wrong shape", () => { + try { + double.parse(objC); + } catch (_err) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${(doubleSuite as any).name}: ${e.target}`); + }); + +manySuite + .add("valid: a", () => { + many.parse(objA); + }) + .add("valid: c", () => { + many.parse(objC); + }) + .add("invalid: null", () => { + try { + many.parse(null); + } catch (_err) {} + }) + .add("invalid: wrong shape", () => { + try { + many.parse({ type: "unknown" }); + } catch (_err) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${(manySuite as any).name}: ${e.target}`); + }); + +export default { + suites: [doubleSuite, manySuite], +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/index.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/index.ts new file mode 100644 index 0000000..ca81c5b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/index.ts @@ -0,0 +1,59 @@ +import type Benchmark from "benchmark"; + +import datetimeBenchmarks from "./datetime.js"; +import discriminatedUnionBenchmarks from "./discriminatedUnion.js"; +import ipv4Benchmarks from "./ipv4.js"; +import objectBenchmarks from "./object.js"; +import primitiveBenchmarks from "./primitives.js"; +import realworld from "./realworld.js"; +import stringBenchmarks from "./string.js"; +import unionBenchmarks from "./union.js"; + +const argv = process.argv.slice(2); +let suites: Benchmark.Suite[] = []; + +if (!argv.length) { + suites = [ + ...realworld.suites, + ...primitiveBenchmarks.suites, + ...stringBenchmarks.suites, + ...objectBenchmarks.suites, + ...unionBenchmarks.suites, + ...discriminatedUnionBenchmarks.suites, + ]; +} else { + if (argv.includes("--realworld")) { + suites.push(...realworld.suites); + } + if (argv.includes("--primitives")) { + suites.push(...primitiveBenchmarks.suites); + } + if (argv.includes("--string")) { + suites.push(...stringBenchmarks.suites); + } + if (argv.includes("--object")) { + suites.push(...objectBenchmarks.suites); + } + if (argv.includes("--union")) { + suites.push(...unionBenchmarks.suites); + } + if (argv.includes("--discriminatedUnion")) { + suites.push(...datetimeBenchmarks.suites); + } + if (argv.includes("--datetime")) { + suites.push(...datetimeBenchmarks.suites); + } + if (argv.includes("--ipv4")) { + suites.push(...ipv4Benchmarks.suites); + } +} + +for (const suite of suites) { + suite.run({}); +} + +// exit on Ctrl-C +process.on("SIGINT", function () { + console.log("Exiting..."); + process.exit(); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/ipv4.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/ipv4.ts new file mode 100644 index 0000000..913ffd4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/ipv4.ts @@ -0,0 +1,57 @@ +import Benchmark from "benchmark"; + +const suite = new Benchmark.Suite("ipv4"); + +const DATA = "127.0.0.1"; +const ipv4RegexA = + /^(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))$/; +const ipv4RegexB = + /^(?:(?:(?=(25[0-5]))\1|(?=(2[0-4][0-9]))\2|(?=(1[0-9]{2}))\3|(?=([0-9]{1,2}))\4)\.){3}(?:(?=(25[0-5]))\5|(?=(2[0-4][0-9]))\6|(?=(1[0-9]{2}))\7|(?=([0-9]{1,2}))\8)$/; +const ipv4RegexC = /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/; +const ipv4RegexD = /^(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/; +const ipv4RegexE = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.){3}(25[0-5]|(2[0-4]|1\d|[1-9]|)\d)$/; +const ipv4RegexF = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/; +const ipv4RegexG = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$/; +const ipv4RegexH = /^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\.(?!$)|$)){4}$/; +const ipv4RegexI = + /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; + +suite + .add("A", () => { + return ipv4RegexA.test(DATA); + }) + .add("B", () => { + return ipv4RegexB.test(DATA); + }) + .add("C", () => { + return ipv4RegexC.test(DATA); + }) + .add("D", () => { + return ipv4RegexD.test(DATA); + }) + .add("E", () => { + return ipv4RegexE.test(DATA); + }) + .add("F", () => { + return ipv4RegexF.test(DATA); + }) + .add("G", () => { + return ipv4RegexG.test(DATA); + }) + .add("H", () => { + return ipv4RegexH.test(DATA); + }) + .add("I", () => { + return ipv4RegexI.test(DATA); + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${suite.name!}: ${e.target}`); + }); + +export default { + suites: [suite], +}; + +if (require.main === module) { + suite.run(); +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/object.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/object.ts new file mode 100644 index 0000000..3c1da10 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/object.ts @@ -0,0 +1,69 @@ +import Benchmark from "benchmark"; + +import { z } from "zod/v3"; + +const emptySuite = new Benchmark.Suite("z.object: empty"); +const shortSuite = new Benchmark.Suite("z.object: short"); +const longSuite = new Benchmark.Suite("z.object: long"); + +const empty = z.object({}); +const short = z.object({ + string: z.string(), +}); +const long = z.object({ + string: z.string(), + number: z.number(), + boolean: z.boolean(), +}); + +emptySuite + .add("valid", () => { + empty.parse({}); + }) + .add("valid: extra keys", () => { + empty.parse({ string: "string" }); + }) + .add("invalid: null", () => { + try { + empty.parse(null); + } catch (_err) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${(emptySuite as any).name}: ${e.target}`); + }); + +shortSuite + .add("valid", () => { + short.parse({ string: "string" }); + }) + .add("valid: extra keys", () => { + short.parse({ string: "string", number: 42 }); + }) + .add("invalid: null", () => { + try { + short.parse(null); + } catch (_err) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${(shortSuite as any).name}: ${e.target}`); + }); + +longSuite + .add("valid", () => { + long.parse({ string: "string", number: 42, boolean: true }); + }) + .add("valid: extra keys", () => { + long.parse({ string: "string", number: 42, boolean: true, list: [] }); + }) + .add("invalid: null", () => { + try { + long.parse(null); + } catch (_err) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${(longSuite as any).name}: ${e.target}`); + }); + +export default { + suites: [emptySuite, shortSuite, longSuite], +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/primitives.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/primitives.ts new file mode 100644 index 0000000..fd61b38 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/primitives.ts @@ -0,0 +1,162 @@ +import Benchmark from "benchmark"; + +import { z } from "zod/v3"; +import { Mocker } from "../tests/Mocker.js"; + +const val = new Mocker(); + +const enumSuite = new Benchmark.Suite("z.enum"); +const enumSchema = z.enum(["a", "b", "c"]); + +enumSuite + .add("valid", () => { + enumSchema.parse("a"); + }) + .add("invalid", () => { + try { + enumSchema.parse("x"); + } catch (_e: any) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`z.enum: ${e.target}`); + }); + +const longEnumSuite = new Benchmark.Suite("long z.enum"); +const longEnumSchema = z.enum([ + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "ten", + "eleven", + "twelve", + "thirteen", + "fourteen", + "fifteen", + "sixteen", + "seventeen", +]); + +longEnumSuite + .add("valid", () => { + longEnumSchema.parse("five"); + }) + .add("invalid", () => { + try { + longEnumSchema.parse("invalid"); + } catch (_e: any) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`long z.enum: ${e.target}`); + }); + +const undefinedSuite = new Benchmark.Suite("z.undefined"); +const undefinedSchema = z.undefined(); + +undefinedSuite + .add("valid", () => { + undefinedSchema.parse(undefined); + }) + .add("invalid", () => { + try { + undefinedSchema.parse(1); + } catch (_e: any) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`z.undefined: ${e.target}`); + }); + +const literalSuite = new Benchmark.Suite("z.literal"); +const short = "short"; +const bad = "bad"; +const literalSchema = z.literal("short"); + +literalSuite + .add("valid", () => { + literalSchema.parse(short); + }) + .add("invalid", () => { + try { + literalSchema.parse(bad); + } catch (_e: any) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`z.literal: ${e.target}`); + }); + +const numberSuite = new Benchmark.Suite("z.number"); +const numberSchema = z.number().int(); + +numberSuite + .add("valid", () => { + numberSchema.parse(1); + }) + .add("invalid type", () => { + try { + numberSchema.parse("bad"); + } catch (_e: any) {} + }) + .add("invalid number", () => { + try { + numberSchema.parse(0.5); + } catch (_e: any) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`z.number: ${e.target}`); + }); + +const dateSuite = new Benchmark.Suite("z.date"); + +const plainDate = z.date(); +const minMaxDate = z.date().min(new Date("2021-01-01")).max(new Date("2030-01-01")); + +dateSuite + .add("valid", () => { + plainDate.parse(new Date()); + }) + .add("invalid", () => { + try { + plainDate.parse(1); + } catch (_e: any) {} + }) + .add("valid min and max", () => { + minMaxDate.parse(new Date("2023-01-01")); + }) + .add("invalid min", () => { + try { + minMaxDate.parse(new Date("2019-01-01")); + } catch (_e: any) {} + }) + .add("invalid max", () => { + try { + minMaxDate.parse(new Date("2031-01-01")); + } catch (_e: any) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`z.date: ${e.target}`); + }); + +const symbolSuite = new Benchmark.Suite("z.symbol"); +const symbolSchema = z.symbol(); + +symbolSuite + .add("valid", () => { + symbolSchema.parse(val.symbol); + }) + .add("invalid", () => { + try { + symbolSchema.parse(1); + } catch (_e: any) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`z.symbol: ${e.target}`); + }); + +export default { + suites: [enumSuite, longEnumSuite, undefinedSuite, literalSuite, numberSuite, dateSuite, symbolSuite], +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/realworld.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/realworld.ts new file mode 100644 index 0000000..d64c4f0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/realworld.ts @@ -0,0 +1,63 @@ +import Benchmark from "benchmark"; + +import { z } from "zod/v3"; + +const shortSuite = new Benchmark.Suite("realworld"); + +const People = z.array( + z.object({ + type: z.literal("person"), + hair: z.enum(["blue", "brown"]), + active: z.boolean(), + name: z.string(), + age: z.number().int(), + hobbies: z.array(z.string()), + address: z.object({ + street: z.string(), + zip: z.string(), + country: z.string(), + }), + }) +); + +let i = 0; + +function num() { + return ++i; +} + +function str() { + return (++i % 100).toString(16); +} + +function array(fn: () => T): T[] { + return Array.from({ length: ++i % 10 }, () => fn()); +} + +const people = Array.from({ length: 100 }, () => { + return { + type: "person", + hair: i % 2 ? "blue" : "brown", + active: !!(i % 2), + name: str(), + age: num(), + hobbies: array(str), + address: { + street: str(), + zip: str(), + country: str(), + }, + }; +}); + +shortSuite + .add("valid", () => { + People.parse(people); + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${(shortSuite as any).name}: ${e.target}`); + }); + +export default { + suites: [shortSuite], +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/string.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/string.ts new file mode 100644 index 0000000..6b3d29f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/string.ts @@ -0,0 +1,55 @@ +import Benchmark from "benchmark"; + +import { z } from "zod/v3"; + +const SUITE_NAME = "z.string"; +const suite = new Benchmark.Suite(SUITE_NAME); + +const empty = ""; +const short = "short"; +const long = "long".repeat(256); +const manual = (str: unknown) => { + if (typeof str !== "string") { + throw new Error("Not a string"); + } + + return str; +}; +const stringSchema = z.string(); +const optionalStringSchema = z.string().optional(); +const optionalNullableStringSchema = z.string().optional().nullable(); + +suite + .add("empty string", () => { + stringSchema.parse(empty); + }) + .add("short string", () => { + stringSchema.parse(short); + }) + .add("long string", () => { + stringSchema.parse(long); + }) + .add("optional string", () => { + optionalStringSchema.parse(long); + }) + .add("nullable string", () => { + optionalNullableStringSchema.parse(long); + }) + .add("nullable (null) string", () => { + optionalNullableStringSchema.parse(null); + }) + .add("invalid: null", () => { + try { + stringSchema.parse(null); + } catch (_err) {} + }) + .add("manual parser: long", () => { + manual(long); + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${SUITE_NAME}: ${e.target}`); + }); + +export default { + suites: [suite], +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/union.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/union.ts new file mode 100644 index 0000000..d716dce --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/benchmarks/union.ts @@ -0,0 +1,80 @@ +import Benchmark from "benchmark"; + +import { z } from "zod/v3"; + +const doubleSuite = new Benchmark.Suite("z.union: double"); +const manySuite = new Benchmark.Suite("z.union: many"); + +const aSchema = z.object({ + type: z.literal("a"), +}); +const objA = { + type: "a", +}; + +const bSchema = z.object({ + type: z.literal("b"), +}); +const objB = { + type: "b", +}; + +const cSchema = z.object({ + type: z.literal("c"), +}); +const objC = { + type: "c", +}; + +const dSchema = z.object({ + type: z.literal("d"), +}); + +const double = z.union([aSchema, bSchema]); +const many = z.union([aSchema, bSchema, cSchema, dSchema]); + +doubleSuite + .add("valid: a", () => { + double.parse(objA); + }) + .add("valid: b", () => { + double.parse(objB); + }) + .add("invalid: null", () => { + try { + double.parse(null); + } catch (_err) {} + }) + .add("invalid: wrong shape", () => { + try { + double.parse(objC); + } catch (_err) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${(doubleSuite as any).name}: ${e.target}`); + }); + +manySuite + .add("valid: a", () => { + many.parse(objA); + }) + .add("valid: c", () => { + many.parse(objC); + }) + .add("invalid: null", () => { + try { + many.parse(null); + } catch (_err) {} + }) + .add("invalid: wrong shape", () => { + try { + many.parse({ type: "unknown" }); + } catch (_err) {} + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${(manySuite as any).name}: ${e.target}`); + }); + +export default { + suites: [doubleSuite, manySuite], +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/errors.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/errors.ts new file mode 100644 index 0000000..3c0dae6 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/errors.ts @@ -0,0 +1,13 @@ +import type { ZodErrorMap } from "./ZodError.js"; +import defaultErrorMap from "./locales/en.js"; + +let overrideErrorMap = defaultErrorMap; +export { defaultErrorMap }; + +export function setErrorMap(map: ZodErrorMap) { + overrideErrorMap = map; +} + +export function getErrorMap() { + return overrideErrorMap; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/external.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/external.ts new file mode 100644 index 0000000..f0a4be4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/external.ts @@ -0,0 +1,6 @@ +export * from "./errors.js"; +export * from "./helpers/parseUtil.js"; +export * from "./helpers/typeAliases.js"; +export * from "./helpers/util.js"; +export * from "./types.js"; +export * from "./ZodError.js"; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/enumUtil.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/enumUtil.ts new file mode 100644 index 0000000..526b227 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/enumUtil.ts @@ -0,0 +1,17 @@ +export namespace enumUtil { + type UnionToIntersectionFn = (T extends unknown ? (k: () => T) => void : never) extends ( + k: infer Intersection + ) => void + ? Intersection + : never; + + type GetUnionLast = UnionToIntersectionFn extends () => infer Last ? Last : never; + + type UnionToTuple = [T] extends [never] + ? Tuple + : UnionToTuple>, [GetUnionLast, ...Tuple]>; + + type CastToStringTuple = T extends [string, ...string[]] ? T : never; + + export type UnionToTupleString = CastToStringTuple>; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/errorUtil.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/errorUtil.ts new file mode 100644 index 0000000..319ef6b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/errorUtil.ts @@ -0,0 +1,8 @@ +export namespace errorUtil { + export type ErrMessage = string | { message?: string | undefined }; + export const errToObj = (message?: ErrMessage): { message?: string | undefined } => + typeof message === "string" ? { message } : message || {}; + // biome-ignore lint: + export const toString = (message?: ErrMessage): string | undefined => + typeof message === "string" ? message : message?.message; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/parseUtil.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/parseUtil.ts new file mode 100644 index 0000000..1076ad9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/parseUtil.ts @@ -0,0 +1,176 @@ +import type { IssueData, ZodErrorMap, ZodIssue } from "../ZodError.js"; +import { getErrorMap } from "../errors.js"; +import defaultErrorMap from "../locales/en.js"; +import type { ZodParsedType } from "./util.js"; + +export const makeIssue = (params: { + data: any; + path: (string | number)[]; + errorMaps: ZodErrorMap[]; + issueData: IssueData; +}): ZodIssue => { + const { data, path, errorMaps, issueData } = params; + const fullPath = [...path, ...(issueData.path || [])]; + const fullIssue = { + ...issueData, + path: fullPath, + }; + + if (issueData.message !== undefined) { + return { + ...issueData, + path: fullPath, + message: issueData.message, + }; + } + + let errorMessage = ""; + const maps = errorMaps + .filter((m) => !!m) + .slice() + .reverse(); + for (const map of maps) { + errorMessage = map(fullIssue, { data, defaultError: errorMessage }).message; + } + + return { + ...issueData, + path: fullPath, + message: errorMessage, + }; +}; + +export type ParseParams = { + path: (string | number)[]; + errorMap: ZodErrorMap; + async: boolean; +}; + +export type ParsePathComponent = string | number; +export type ParsePath = ParsePathComponent[]; +export const EMPTY_PATH: ParsePath = []; + +export interface ParseContext { + readonly common: { + readonly issues: ZodIssue[]; + readonly contextualErrorMap?: ZodErrorMap | undefined; + readonly async: boolean; + }; + readonly path: ParsePath; + readonly schemaErrorMap?: ZodErrorMap | undefined; + readonly parent: ParseContext | null; + readonly data: any; + readonly parsedType: ZodParsedType; +} + +export type ParseInput = { + data: any; + path: (string | number)[]; + parent: ParseContext; +}; + +export function addIssueToContext(ctx: ParseContext, issueData: IssueData): void { + const overrideMap = getErrorMap(); + const issue = makeIssue({ + issueData: issueData, + data: ctx.data, + path: ctx.path, + errorMaps: [ + ctx.common.contextualErrorMap, // contextual error map is first priority + ctx.schemaErrorMap, // then schema-bound map if available + overrideMap, // then global override map + overrideMap === defaultErrorMap ? undefined : defaultErrorMap, // then global default map + ].filter((x) => !!x), + }); + ctx.common.issues.push(issue); +} + +export type ObjectPair = { + key: SyncParseReturnType; + value: SyncParseReturnType; +}; +export class ParseStatus { + value: "aborted" | "dirty" | "valid" = "valid"; + dirty(): void { + if (this.value === "valid") this.value = "dirty"; + } + abort(): void { + if (this.value !== "aborted") this.value = "aborted"; + } + + static mergeArray(status: ParseStatus, results: SyncParseReturnType[]): SyncParseReturnType { + const arrayValue: any[] = []; + for (const s of results) { + if (s.status === "aborted") return INVALID; + if (s.status === "dirty") status.dirty(); + arrayValue.push(s.value); + } + + return { status: status.value, value: arrayValue }; + } + + static async mergeObjectAsync( + status: ParseStatus, + pairs: { key: ParseReturnType; value: ParseReturnType }[] + ): Promise> { + const syncPairs: ObjectPair[] = []; + for (const pair of pairs) { + const key = await pair.key; + const value = await pair.value; + syncPairs.push({ + key, + value, + }); + } + return ParseStatus.mergeObjectSync(status, syncPairs); + } + + static mergeObjectSync( + status: ParseStatus, + pairs: { + key: SyncParseReturnType; + value: SyncParseReturnType; + alwaysSet?: boolean; + }[] + ): SyncParseReturnType { + const finalObject: any = {}; + for (const pair of pairs) { + const { key, value } = pair; + if (key.status === "aborted") return INVALID; + if (value.status === "aborted") return INVALID; + if (key.status === "dirty") status.dirty(); + if (value.status === "dirty") status.dirty(); + + if (key.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) { + finalObject[key.value] = value.value; + } + } + + return { status: status.value, value: finalObject }; + } +} +export interface ParseResult { + status: "aborted" | "dirty" | "valid"; + data: any; +} + +export type INVALID = { status: "aborted" }; +export const INVALID: INVALID = Object.freeze({ + status: "aborted", +}); + +export type DIRTY = { status: "dirty"; value: T }; +export const DIRTY = (value: T): DIRTY => ({ status: "dirty", value }); + +export type OK = { status: "valid"; value: T }; +export const OK = (value: T): OK => ({ status: "valid", value }); + +export type SyncParseReturnType = OK | DIRTY | INVALID; +export type AsyncParseReturnType = Promise>; +export type ParseReturnType = SyncParseReturnType | AsyncParseReturnType; + +export const isAborted = (x: ParseReturnType): x is INVALID => (x as any).status === "aborted"; +export const isDirty = (x: ParseReturnType): x is OK | DIRTY => (x as any).status === "dirty"; +export const isValid = (x: ParseReturnType): x is OK => (x as any).status === "valid"; +export const isAsync = (x: ParseReturnType): x is AsyncParseReturnType => + typeof Promise !== "undefined" && x instanceof Promise; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/partialUtil.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/partialUtil.ts new file mode 100644 index 0000000..0eff8ff --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/partialUtil.ts @@ -0,0 +1,34 @@ +import type { + ZodArray, + ZodNullable, + ZodObject, + ZodOptional, + ZodRawShape, + ZodTuple, + ZodTupleItems, + ZodTypeAny, +} from "../types.js"; + +export namespace partialUtil { + export type DeepPartial = T extends ZodObject + ? ZodObject< + { [k in keyof T["shape"]]: ZodOptional> }, + T["_def"]["unknownKeys"], + T["_def"]["catchall"] + > + : T extends ZodArray + ? ZodArray, Card> + : T extends ZodOptional + ? ZodOptional> + : T extends ZodNullable + ? ZodNullable> + : T extends ZodTuple + ? { + [k in keyof Items]: Items[k] extends ZodTypeAny ? DeepPartial : never; + } extends infer PI + ? PI extends ZodTupleItems + ? ZodTuple + : never + : never + : T; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/typeAliases.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/typeAliases.ts new file mode 100644 index 0000000..32df022 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/typeAliases.ts @@ -0,0 +1,2 @@ +export type Primitive = string | number | symbol | bigint | boolean | null | undefined; +export type Scalars = Primitive | Primitive[]; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/util.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/util.ts new file mode 100644 index 0000000..030ea82 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/helpers/util.ts @@ -0,0 +1,224 @@ +export namespace util { + type AssertEqual = (() => V extends T ? 1 : 2) extends () => V extends U ? 1 : 2 ? true : false; + + export type isAny = 0 extends 1 & T ? true : false; + export const assertEqual = (_: AssertEqual): void => {}; + export function assertIs(_arg: T): void {} + export function assertNever(_x: never): never { + throw new Error(); + } + + export type Omit = Pick>; + export type OmitKeys = Pick>; + export type MakePartial = Omit & Partial>; + export type Exactly = T & Record, never>; + export type InexactPartial = { [k in keyof T]?: T[k] | undefined }; + export const arrayToEnum = (items: U): { [k in U[number]]: k } => { + const obj: any = {}; + for (const item of items) { + obj[item] = item; + } + return obj; + }; + + export const getValidEnumValues = (obj: any): any[] => { + const validKeys = objectKeys(obj).filter((k: any) => typeof obj[obj[k]] !== "number"); + const filtered: any = {}; + for (const k of validKeys) { + filtered[k] = obj[k]; + } + return objectValues(filtered); + }; + + export const objectValues = (obj: any): any[] => { + return objectKeys(obj).map(function (e) { + return obj[e]; + }); + }; + + export const objectKeys: ObjectConstructor["keys"] = + typeof Object.keys === "function" // eslint-disable-line ban/ban + ? (obj: any) => Object.keys(obj) // eslint-disable-line ban/ban + : (object: any) => { + const keys = []; + for (const key in object) { + if (Object.prototype.hasOwnProperty.call(object, key)) { + keys.push(key); + } + } + return keys; + }; + + export const find = (arr: T[], checker: (arg: T) => any): T | undefined => { + for (const item of arr) { + if (checker(item)) return item; + } + return undefined; + }; + + export type identity = objectUtil.identity; + export type flatten = objectUtil.flatten; + + export type noUndefined = T extends undefined ? never : T; + + export const isInteger: NumberConstructor["isInteger"] = + typeof Number.isInteger === "function" + ? (val) => Number.isInteger(val) // eslint-disable-line ban/ban + : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val; + + export function joinValues(array: T, separator = " | "): string { + return array.map((val) => (typeof val === "string" ? `'${val}'` : val)).join(separator); + } + + export const jsonStringifyReplacer = (_: string, value: any): any => { + if (typeof value === "bigint") { + return value.toString(); + } + return value; + }; +} + +export namespace objectUtil { + export type MergeShapes = + // fast path when there is no keys overlap + keyof U & keyof V extends never + ? U & V + : { + [k in Exclude]: U[k]; + } & V; + + type optionalKeys = { + [k in keyof T]: undefined extends T[k] ? k : never; + }[keyof T]; + type requiredKeys = { + [k in keyof T]: undefined extends T[k] ? never : k; + }[keyof T]; + export type addQuestionMarks = { + [K in requiredKeys]: T[K]; + } & { + [K in optionalKeys]?: T[K]; + } & { [k in keyof T]?: unknown }; + + export type identity = T; + export type flatten = identity<{ [k in keyof T]: T[k] }>; + + export type noNeverKeys = { + [k in keyof T]: [T[k]] extends [never] ? never : k; + }[keyof T]; + + export type noNever = identity<{ + [k in noNeverKeys]: k extends keyof T ? T[k] : never; + }>; + + export const mergeShapes = (first: U, second: T): T & U => { + return { + ...first, + ...second, // second overwrites first + }; + }; + + export type extendShape = keyof A & keyof B extends never // fast path when there is no keys overlap + ? A & B + : { + [K in keyof A as K extends keyof B ? never : K]: A[K]; + } & { + [K in keyof B]: B[K]; + }; +} + +export const ZodParsedType: { + string: "string"; + nan: "nan"; + number: "number"; + integer: "integer"; + float: "float"; + boolean: "boolean"; + date: "date"; + bigint: "bigint"; + symbol: "symbol"; + function: "function"; + undefined: "undefined"; + null: "null"; + array: "array"; + object: "object"; + unknown: "unknown"; + promise: "promise"; + void: "void"; + never: "never"; + map: "map"; + set: "set"; +} = util.arrayToEnum([ + "string", + "nan", + "number", + "integer", + "float", + "boolean", + "date", + "bigint", + "symbol", + "function", + "undefined", + "null", + "array", + "object", + "unknown", + "promise", + "void", + "never", + "map", + "set", +]); + +export type ZodParsedType = keyof typeof ZodParsedType; + +export const getParsedType = (data: any): ZodParsedType => { + const t = typeof data; + + switch (t) { + case "undefined": + return ZodParsedType.undefined; + + case "string": + return ZodParsedType.string; + + case "number": + return Number.isNaN(data) ? ZodParsedType.nan : ZodParsedType.number; + + case "boolean": + return ZodParsedType.boolean; + + case "function": + return ZodParsedType.function; + + case "bigint": + return ZodParsedType.bigint; + + case "symbol": + return ZodParsedType.symbol; + + case "object": + if (Array.isArray(data)) { + return ZodParsedType.array; + } + if (data === null) { + return ZodParsedType.null; + } + if (data.then && typeof data.then === "function" && data.catch && typeof data.catch === "function") { + return ZodParsedType.promise; + } + if (typeof Map !== "undefined" && data instanceof Map) { + return ZodParsedType.map; + } + if (typeof Set !== "undefined" && data instanceof Set) { + return ZodParsedType.set; + } + if (typeof Date !== "undefined" && data instanceof Date) { + return ZodParsedType.date; + } + return ZodParsedType.object; + + default: + return ZodParsedType.unknown; + } +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/index.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/index.ts new file mode 100644 index 0000000..a9dab57 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/index.ts @@ -0,0 +1,4 @@ +import * as z from "./external.js"; +export * from "./external.js"; +export { z }; +export default z; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/locales/en.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/locales/en.ts new file mode 100644 index 0000000..0264f82 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/locales/en.ts @@ -0,0 +1,124 @@ +import { type ZodErrorMap, ZodIssueCode } from "../ZodError.js"; +import { util, ZodParsedType } from "../helpers/util.js"; + +const errorMap: ZodErrorMap = (issue, _ctx) => { + let message: string; + switch (issue.code) { + case ZodIssueCode.invalid_type: + if (issue.received === ZodParsedType.undefined) { + message = "Required"; + } else { + message = `Expected ${issue.expected}, received ${issue.received}`; + } + break; + case ZodIssueCode.invalid_literal: + message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util.jsonStringifyReplacer)}`; + break; + case ZodIssueCode.unrecognized_keys: + message = `Unrecognized key(s) in object: ${util.joinValues(issue.keys, ", ")}`; + break; + case ZodIssueCode.invalid_union: + message = `Invalid input`; + break; + case ZodIssueCode.invalid_union_discriminator: + message = `Invalid discriminator value. Expected ${util.joinValues(issue.options)}`; + break; + case ZodIssueCode.invalid_enum_value: + message = `Invalid enum value. Expected ${util.joinValues(issue.options)}, received '${issue.received}'`; + break; + case ZodIssueCode.invalid_arguments: + message = `Invalid function arguments`; + break; + case ZodIssueCode.invalid_return_type: + message = `Invalid function return type`; + break; + case ZodIssueCode.invalid_date: + message = `Invalid date`; + break; + case ZodIssueCode.invalid_string: + if (typeof issue.validation === "object") { + if ("includes" in issue.validation) { + message = `Invalid input: must include "${issue.validation.includes}"`; + + if (typeof issue.validation.position === "number") { + message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`; + } + } else if ("startsWith" in issue.validation) { + message = `Invalid input: must start with "${issue.validation.startsWith}"`; + } else if ("endsWith" in issue.validation) { + message = `Invalid input: must end with "${issue.validation.endsWith}"`; + } else { + util.assertNever(issue.validation); + } + } else if (issue.validation !== "regex") { + message = `Invalid ${issue.validation}`; + } else { + message = "Invalid"; + } + break; + case ZodIssueCode.too_small: + if (issue.type === "array") + message = `Array must contain ${ + issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than` + } ${issue.minimum} element(s)`; + else if (issue.type === "string") + message = `String must contain ${ + issue.exact ? "exactly" : issue.inclusive ? `at least` : `over` + } ${issue.minimum} character(s)`; + else if (issue.type === "number") + message = `Number must be ${ + issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than ` + }${issue.minimum}`; + else if (issue.type === "bigint") + message = `Number must be ${ + issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than ` + }${issue.minimum}`; + else if (issue.type === "date") + message = `Date must be ${ + issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than ` + }${new Date(Number(issue.minimum))}`; + else message = "Invalid input"; + break; + case ZodIssueCode.too_big: + if (issue.type === "array") + message = `Array must contain ${ + issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than` + } ${issue.maximum} element(s)`; + else if (issue.type === "string") + message = `String must contain ${ + issue.exact ? `exactly` : issue.inclusive ? `at most` : `under` + } ${issue.maximum} character(s)`; + else if (issue.type === "number") + message = `Number must be ${ + issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than` + } ${issue.maximum}`; + else if (issue.type === "bigint") + message = `BigInt must be ${ + issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than` + } ${issue.maximum}`; + else if (issue.type === "date") + message = `Date must be ${ + issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than` + } ${new Date(Number(issue.maximum))}`; + else message = "Invalid input"; + break; + case ZodIssueCode.custom: + message = `Invalid input`; + break; + case ZodIssueCode.invalid_intersection_types: + message = `Intersection results could not be merged`; + break; + case ZodIssueCode.not_multiple_of: + message = `Number must be a multiple of ${issue.multipleOf}`; + break; + case ZodIssueCode.not_finite: + message = "Number must be finite"; + break; + default: + message = _ctx.defaultError; + util.assertNever(issue); + } + return { message }; +}; + +export default errorMap; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/standard-schema.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/standard-schema.ts new file mode 100644 index 0000000..07193fd --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/standard-schema.ts @@ -0,0 +1,113 @@ +/** + * The Standard Schema interface. + */ +export type StandardSchemaV1 = { + /** + * The Standard Schema properties. + */ + readonly "~standard": StandardSchemaV1.Props; +}; + +export declare namespace StandardSchemaV1 { + /** + * The Standard Schema properties interface. + */ + export interface Props { + /** + * The version number of the standard. + */ + readonly version: 1; + /** + * The vendor name of the schema library. + */ + readonly vendor: string; + /** + * Validates unknown input values. + */ + readonly validate: (value: unknown) => Result | Promise>; + /** + * Inferred types associated with the schema. + */ + readonly types?: Types | undefined; + } + + /** + * The result interface of the validate function. + */ + export type Result = SuccessResult | FailureResult; + + /** + * The result interface if validation succeeds. + */ + export interface SuccessResult { + /** + * The typed output value. + */ + readonly value: Output; + /** + * The non-existent issues. + */ + readonly issues?: undefined; + } + + /** + * The result interface if validation fails. + */ + export interface FailureResult { + /** + * The issues of failed validation. + */ + readonly issues: ReadonlyArray; + } + + /** + * The issue interface of the failure output. + */ + export interface Issue { + /** + * The error message of the issue. + */ + readonly message: string; + /** + * The path of the issue, if any. + */ + readonly path?: ReadonlyArray | undefined; + } + + /** + * The path segment interface of the issue. + */ + export interface PathSegment { + /** + * The key representing a path segment. + */ + readonly key: PropertyKey; + } + + /** + * The Standard Schema types interface. + */ + export interface Types { + /** + * The input type of the schema. + */ + readonly input: Input; + /** + * The output type of the schema. + */ + readonly output: Output; + } + + /** + * Infers the input type of a Standard Schema. + */ + export type InferInput = NonNullable["input"]; + + /** + * Infers the output type of a Standard Schema. + */ + export type InferOutput = NonNullable["output"]; + + // biome-ignore lint/complexity/noUselessEmptyExport: needed for granular visibility control of TS namespace + export {}; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/Mocker.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/Mocker.ts new file mode 100644 index 0000000..c9fbdd5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/Mocker.ts @@ -0,0 +1,54 @@ +function getRandomInt(max: number) { + return Math.floor(Math.random() * Math.floor(max)); +} + +const testSymbol = Symbol("test"); + +export class Mocker { + pick = (...args: any[]): any => { + return args[getRandomInt(args.length)]; + }; + + get string(): string { + return Math.random().toString(36).substring(7); + } + get number(): number { + return Math.random() * 100; + } + get bigint(): bigint { + return BigInt(Math.floor(Math.random() * 10000)); + } + get boolean(): boolean { + return Math.random() < 0.5; + } + get date(): Date { + return new Date(Math.floor(Date.now() * Math.random())); + } + get symbol(): symbol { + return testSymbol; + } + get null(): null { + return null; + } + get undefined(): undefined { + return undefined; + } + get stringOptional(): string | undefined { + return this.pick(this.string, this.undefined); + } + get stringNullable(): string | null { + return this.pick(this.string, this.null); + } + get numberOptional(): number | undefined { + return this.pick(this.number, this.undefined); + } + get numberNullable(): number | null { + return this.pick(this.number, this.null); + } + get booleanOptional(): boolean | undefined { + return this.pick(this.boolean, this.undefined); + } + get booleanNullable(): boolean | null { + return this.pick(this.boolean, this.null); + } +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/all-errors.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/all-errors.test.ts new file mode 100644 index 0000000..212cfa8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/all-errors.test.ts @@ -0,0 +1,157 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +const Test = z.object({ + f1: z.number(), + f2: z.string().optional(), + f3: z.string().nullable(), + f4: z.array(z.object({ t: z.union([z.string(), z.boolean()]) })), +}); +type TestFlattenedErrors = z.inferFlattenedErrors; +type TestFormErrors = z.inferFlattenedErrors; + +test("default flattened errors type inference", () => { + type TestTypeErrors = { + formErrors: string[]; + fieldErrors: { [P in keyof z.TypeOf]?: string[] }; + }; + + util.assertEqual, TestTypeErrors>(true); + util.assertEqual, TestTypeErrors>(false); +}); + +test("custom flattened errors type inference", () => { + type ErrorType = { message: string; code: number }; + type TestTypeErrors = { + formErrors: ErrorType[]; + fieldErrors: { + [P in keyof z.TypeOf]?: ErrorType[]; + }; + }; + + util.assertEqual, TestTypeErrors>(false); + util.assertEqual, TestTypeErrors>(true); + util.assertEqual, TestTypeErrors>(false); +}); + +test("form errors type inference", () => { + type TestTypeErrors = { + formErrors: string[]; + fieldErrors: { [P in keyof z.TypeOf]?: string[] }; + }; + + util.assertEqual, TestTypeErrors>(true); +}); + +test(".flatten() type assertion", () => { + const parsed = Test.safeParse({}) as z.SafeParseError; + const validFlattenedErrors: TestFlattenedErrors = parsed.error.flatten(() => ({ message: "", code: 0 })); + // @ts-expect-error should fail assertion between `TestFlattenedErrors` and unmapped `flatten()`. + const invalidFlattenedErrors: TestFlattenedErrors = parsed.error.flatten(); + const validFormErrors: TestFormErrors = parsed.error.flatten(); + // @ts-expect-error should fail assertion between `TestFormErrors` and mapped `flatten()`. + const invalidFormErrors: TestFormErrors = parsed.error.flatten(() => ({ + message: "string", + code: 0, + })); + + [validFlattenedErrors, invalidFlattenedErrors, validFormErrors, invalidFormErrors]; +}); + +test(".formErrors type assertion", () => { + const parsed = Test.safeParse({}) as z.SafeParseError; + const validFormErrors: TestFormErrors = parsed.error.formErrors; + // @ts-expect-error should fail assertion between `TestFlattenedErrors` and `.formErrors`. + const invalidFlattenedErrors: TestFlattenedErrors = parsed.error.formErrors; + + [validFormErrors, invalidFlattenedErrors]; +}); + +test("all errors", () => { + const propertySchema = z.string(); + const schema = z + .object({ + a: propertySchema, + b: propertySchema, + }) + .refine( + (val) => { + return val.a === val.b; + }, + { message: "Must be equal" } + ); + + try { + schema.parse({ + a: "asdf", + b: "qwer", + }); + } catch (error) { + if (error instanceof z.ZodError) { + expect(error.flatten()).toEqual({ + formErrors: ["Must be equal"], + fieldErrors: {}, + }); + } + } + + try { + schema.parse({ + a: null, + b: null, + }); + } catch (_error) { + const error = _error as z.ZodError; + expect(error.flatten()).toEqual({ + formErrors: [], + fieldErrors: { + a: ["Expected string, received null"], + b: ["Expected string, received null"], + }, + }); + + expect(error.flatten((iss) => iss.message.toUpperCase())).toEqual({ + formErrors: [], + fieldErrors: { + a: ["EXPECTED STRING, RECEIVED NULL"], + b: ["EXPECTED STRING, RECEIVED NULL"], + }, + }); + // Test identity + + expect(error.flatten((i: z.ZodIssue) => i)).toEqual({ + formErrors: [], + fieldErrors: { + a: [ + { + code: "invalid_type", + expected: "string", + message: "Expected string, received null", + path: ["a"], + received: "null", + }, + ], + b: [ + { + code: "invalid_type", + expected: "string", + message: "Expected string, received null", + path: ["b"], + received: "null", + }, + ], + }, + }); + // Test mapping + expect(error.flatten((i: z.ZodIssue) => i.message.length)).toEqual({ + formErrors: [], + fieldErrors: { + a: ["Expected string, received null".length], + b: ["Expected string, received null".length], + }, + }); + } +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/anyunknown.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/anyunknown.test.ts new file mode 100644 index 0000000..49d07db --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/anyunknown.test.ts @@ -0,0 +1,28 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("check any inference", () => { + const t1 = z.any(); + t1.optional(); + t1.nullable(); + type t1 = z.infer; + util.assertEqual(true); +}); + +test("check unknown inference", () => { + const t1 = z.unknown(); + t1.optional(); + t1.nullable(); + type t1 = z.infer; + util.assertEqual(true); +}); + +test("check never inference", () => { + const t1 = z.never(); + expect(() => t1.parse(undefined)).toThrow(); + expect(() => t1.parse("asdf")).toThrow(); + expect(() => t1.parse(null)).toThrow(); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/array.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/array.test.ts new file mode 100644 index 0000000..df5b9d3 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/array.test.ts @@ -0,0 +1,71 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +const minTwo = z.string().array().min(2); +const maxTwo = z.string().array().max(2); +const justTwo = z.string().array().length(2); +const intNum = z.string().array().nonempty(); +const nonEmptyMax = z.string().array().nonempty().max(2); + +type t1 = z.infer; +util.assertEqual<[string, ...string[]], t1>(true); + +type t2 = z.infer; +util.assertEqual(true); + +test("passing validations", () => { + minTwo.parse(["a", "a"]); + minTwo.parse(["a", "a", "a"]); + maxTwo.parse(["a", "a"]); + maxTwo.parse(["a"]); + justTwo.parse(["a", "a"]); + intNum.parse(["a"]); + nonEmptyMax.parse(["a"]); +}); + +test("failing validations", () => { + expect(() => minTwo.parse(["a"])).toThrow(); + expect(() => maxTwo.parse(["a", "a", "a"])).toThrow(); + expect(() => justTwo.parse(["a"])).toThrow(); + expect(() => justTwo.parse(["a", "a", "a"])).toThrow(); + expect(() => intNum.parse([])).toThrow(); + expect(() => nonEmptyMax.parse([])).toThrow(); + expect(() => nonEmptyMax.parse(["a", "a", "a"])).toThrow(); +}); + +test("parse empty array in nonempty", () => { + expect(() => + z + .array(z.string()) + .nonempty() + .parse([] as any) + ).toThrow(); +}); + +test("get element", () => { + justTwo.element.parse("asdf"); + expect(() => justTwo.element.parse(12)).toThrow(); +}); + +test("continue parsing despite array size error", () => { + const schema = z.object({ + people: z.string().array().min(2), + }); + + const result = schema.safeParse({ + people: [123], + }); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues.length).toEqual(2); + } +}); + +test("parse should fail given sparse array", () => { + const schema = z.array(z.string()).nonempty().min(1).max(3); + + expect(() => schema.parse(new Array(3))).toThrow(); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/async-parsing.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/async-parsing.test.ts new file mode 100644 index 0000000..01dbc4f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/async-parsing.test.ts @@ -0,0 +1,388 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +/// string +const stringSchema = z.string(); + +test("string async parse", async () => { + const goodData = "XXX"; + const badData = 12; + + const goodResult = await stringSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await stringSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// number +const numberSchema = z.number(); +test("number async parse", async () => { + const goodData = 1234.2353; + const badData = "1234"; + + const goodResult = await numberSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await numberSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// bigInt +const bigIntSchema = z.bigint(); +test("bigInt async parse", async () => { + const goodData = BigInt(145); + const badData = 134; + + const goodResult = await bigIntSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await bigIntSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// boolean +const booleanSchema = z.boolean(); +test("boolean async parse", async () => { + const goodData = true; + const badData = 1; + + const goodResult = await booleanSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await booleanSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// date +const dateSchema = z.date(); +test("date async parse", async () => { + const goodData = new Date(); + const badData = new Date().toISOString(); + + const goodResult = await dateSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await dateSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// undefined +const undefinedSchema = z.undefined(); +test("undefined async parse", async () => { + const goodData = undefined; + const badData = "XXX"; + + const goodResult = await undefinedSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(undefined); + + const badResult = await undefinedSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// null +const nullSchema = z.null(); +test("null async parse", async () => { + const goodData = null; + const badData = undefined; + + const goodResult = await nullSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await nullSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// any +const anySchema = z.any(); +test("any async parse", async () => { + const goodData = [{}]; + // const badData = 'XXX'; + + const goodResult = await anySchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + // const badResult = await anySchema.safeParseAsync(badData); + // expect(badResult.success).toBe(false); + // if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// unknown +const unknownSchema = z.unknown(); +test("unknown async parse", async () => { + const goodData = ["asdf", 124, () => {}]; + // const badData = 'XXX'; + + const goodResult = await unknownSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + // const badResult = await unknownSchema.safeParseAsync(badData); + // expect(badResult.success).toBe(false); + // if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// void +const voidSchema = z.void(); +test("void async parse", async () => { + const goodData = undefined; + const badData = 0; + + const goodResult = await voidSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await voidSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// array +const arraySchema = z.array(z.string()); +test("array async parse", async () => { + const goodData = ["XXX"]; + const badData = "XXX"; + + const goodResult = await arraySchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await arraySchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// object +const objectSchema = z.object({ string: z.string() }); +test("object async parse", async () => { + const goodData = { string: "XXX" }; + const badData = { string: 12 }; + + const goodResult = await objectSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await objectSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// union +const unionSchema = z.union([z.string(), z.undefined()]); +test("union async parse", async () => { + const goodData = undefined; + const badData = null; + + const goodResult = await unionSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await unionSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// record +const recordSchema = z.record(z.object({})); +test("record async parse", async () => { + const goodData = { adsf: {}, asdf: {} }; + const badData = [{}]; + + const goodResult = await recordSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await recordSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// function +const functionSchema = z.function(); +test("function async parse", async () => { + const goodData = () => {}; + const badData = "XXX"; + + const goodResult = await functionSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(typeof goodResult.data).toEqual("function"); + + const badResult = await functionSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// literal +const literalSchema = z.literal("asdf"); +test("literal async parse", async () => { + const goodData = "asdf"; + const badData = "asdff"; + + const goodResult = await literalSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await literalSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// enum +const enumSchema = z.enum(["fish", "whale"]); +test("enum async parse", async () => { + const goodData = "whale"; + const badData = "leopard"; + + const goodResult = await enumSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await enumSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// nativeEnum +enum nativeEnumTest { + asdf = "qwer", +} +// @ts-ignore +const nativeEnumSchema = z.nativeEnum(nativeEnumTest); +test("nativeEnum async parse", async () => { + const goodData = nativeEnumTest.asdf; + const badData = "asdf"; + + const goodResult = await nativeEnumSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) expect(goodResult.data).toEqual(goodData); + + const badResult = await nativeEnumSchema.safeParseAsync(badData); + expect(badResult.success).toBe(false); + if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); +}); + +/// promise +const promiseSchema = z.promise(z.number()); +test("promise async parse good", async () => { + const goodData = Promise.resolve(123); + + const goodResult = await promiseSchema.safeParseAsync(goodData); + expect(goodResult.success).toBe(true); + if (goodResult.success) { + expect(goodResult.data).toBeInstanceOf(Promise); + const data = await goodResult.data; + expect(data).toEqual(123); + // expect(goodResult.data).resolves.toEqual(124); + // return goodResult.data; + } else { + throw new Error("success should be true"); + } +}); + +test("promise async parse bad", async () => { + const badData = Promise.resolve("XXX"); + const badResult = await promiseSchema.safeParseAsync(badData); + expect(badResult.success).toBe(true); + if (badResult.success) { + await expect(badResult.data).rejects.toBeInstanceOf(z.ZodError); + } else { + throw new Error("success should be true"); + } +}); + +test("async validation non-empty strings", async () => { + const base = z.object({ + hello: z.string().refine((x) => x && x.length > 0), + foo: z.string().refine((x) => x && x.length > 0), + }); + + const testval = { hello: "", foo: "" }; + const result1 = base.safeParse(testval); + const result2 = base.safeParseAsync(testval); + + const r1 = result1; + await result2.then((r2) => { + if (r1.success === false && r2.success === false) expect(r1.error.issues.length).toBe(r2.error.issues.length); // <--- r1 has length 2, r2 has length 1 + }); +}); + +test("async validation multiple errors 1", async () => { + const base = z.object({ + hello: z.string(), + foo: z.number(), + }); + + const testval = { hello: 3, foo: "hello" }; + const result1 = base.safeParse(testval); + const result2 = base.safeParseAsync(testval); + + const r1 = result1; + await result2.then((r2) => { + if (r1.success === false && r2.success === false) expect(r2.error.issues.length).toBe(r1.error.issues.length); + }); +}); + +test("async validation multiple errors 2", async () => { + const base = (is_async?: boolean) => + z.object({ + hello: z.string(), + foo: z.object({ + bar: z.number().refine(is_async ? async () => false : () => false), + }), + }); + + const testval = { hello: 3, foo: { bar: 4 } }; + const result1 = base().safeParse(testval); + const result2 = base(true).safeParseAsync(testval); + + const r1 = result1; + await result2.then((r2) => { + if (r1.success === false && r2.success === false) expect(r2.error.issues.length).toBe(r1.error.issues.length); + }); +}); + +test("ensure early async failure prevents follow-up refinement checks", async () => { + let count = 0; + const base = z.object({ + hello: z.string(), + foo: z + .number() + .refine(async () => { + count++; + return true; + }) + .refine(async () => { + count++; + return true; + }, "Good"), + }); + + const testval = { hello: "bye", foo: 3 }; + const result = await base.safeParseAsync(testval); + if (result.success === false) { + expect(result.error.issues.length).toBe(1); + expect(count).toBe(1); + } + + // await result.then((r) => { + // if (r.success === false) expect(r.error.issues.length).toBe(1); + // expect(count).toBe(2); + // }); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/async-refinements.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/async-refinements.test.ts new file mode 100644 index 0000000..509475d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/async-refinements.test.ts @@ -0,0 +1,46 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +test("parse async test", async () => { + const schema1 = z.string().refine(async (_val) => false); + expect(() => schema1.parse("asdf")).toThrow(); + + const schema2 = z.string().refine((_val) => Promise.resolve(true)); + return await expect(() => schema2.parse("asdf")).toThrow(); +}); + +test("parseAsync async test", async () => { + const schema1 = z.string().refine(async (_val) => true); + await schema1.parseAsync("asdf"); + + const schema2 = z.string().refine(async (_val) => false); + return await expect(schema2.parseAsync("asdf")).rejects.toBeDefined(); + // expect(async () => await schema2.parseAsync('asdf')).toThrow(); +}); + +test("parseAsync async test", async () => { + // expect.assertions(2); + + const schema1 = z.string().refine((_val) => Promise.resolve(true)); + const v1 = await schema1.parseAsync("asdf"); + expect(v1).toEqual("asdf"); + + const schema2 = z.string().refine((_val) => Promise.resolve(false)); + await expect(schema2.parseAsync("asdf")).rejects.toBeDefined(); + + const schema3 = z.string().refine((_val) => Promise.resolve(true)); + await expect(schema3.parseAsync("asdf")).resolves.toEqual("asdf"); + return await expect(schema3.parseAsync("qwer")).resolves.toEqual("qwer"); +}); + +test("parseAsync async with value", async () => { + const schema1 = z.string().refine(async (val) => { + return val.length > 5; + }); + await expect(schema1.parseAsync("asdf")).rejects.toBeDefined(); + + const v = await schema1.parseAsync("asdf123"); + return await expect(v).toEqual("asdf123"); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/base.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/base.test.ts new file mode 100644 index 0000000..ab743d5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/base.test.ts @@ -0,0 +1,29 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("type guard", () => { + const stringToNumber = z.string().transform((arg) => arg.length); + + const s1 = z.object({ + stringToNumber, + }); + type t1 = z.input; + + const data = { stringToNumber: "asdf" }; + const parsed = s1.safeParse(data); + if (parsed.success) { + util.assertEqual(true); + } +}); + +test("test this binding", () => { + const callback = (predicate: (val: string) => boolean) => { + return predicate("hello"); + }; + + expect(callback((value) => z.string().safeParse(value).success)).toBe(true); // true + expect(callback((value) => z.string().safeParse(value).success)).toBe(true); // true +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/bigint.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/bigint.test.ts new file mode 100644 index 0000000..9692f57 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/bigint.test.ts @@ -0,0 +1,55 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +const gtFive = z.bigint().gt(BigInt(5)); +const gteFive = z.bigint().gte(BigInt(5)); +const ltFive = z.bigint().lt(BigInt(5)); +const lteFive = z.bigint().lte(BigInt(5)); +const positive = z.bigint().positive(); +const negative = z.bigint().negative(); +const nonnegative = z.bigint().nonnegative(); +const nonpositive = z.bigint().nonpositive(); +const multipleOfFive = z.bigint().multipleOf(BigInt(5)); + +test("passing validations", () => { + z.bigint().parse(BigInt(1)); + z.bigint().parse(BigInt(0)); + z.bigint().parse(BigInt(-1)); + gtFive.parse(BigInt(6)); + gteFive.parse(BigInt(5)); + gteFive.parse(BigInt(6)); + ltFive.parse(BigInt(4)); + lteFive.parse(BigInt(5)); + lteFive.parse(BigInt(4)); + positive.parse(BigInt(3)); + negative.parse(BigInt(-2)); + nonnegative.parse(BigInt(0)); + nonnegative.parse(BigInt(7)); + nonpositive.parse(BigInt(0)); + nonpositive.parse(BigInt(-12)); + multipleOfFive.parse(BigInt(15)); +}); + +test("failing validations", () => { + expect(() => gtFive.parse(BigInt(5))).toThrow(); + expect(() => gteFive.parse(BigInt(4))).toThrow(); + expect(() => ltFive.parse(BigInt(5))).toThrow(); + expect(() => lteFive.parse(BigInt(6))).toThrow(); + expect(() => positive.parse(BigInt(0))).toThrow(); + expect(() => positive.parse(BigInt(-2))).toThrow(); + expect(() => negative.parse(BigInt(0))).toThrow(); + expect(() => negative.parse(BigInt(3))).toThrow(); + expect(() => nonnegative.parse(BigInt(-1))).toThrow(); + expect(() => nonpositive.parse(BigInt(1))).toThrow(); + expect(() => multipleOfFive.parse(BigInt(13))).toThrow(); +}); + +test("min max getters", () => { + expect(z.bigint().min(BigInt(5)).minValue).toEqual(BigInt(5)); + expect(z.bigint().min(BigInt(5)).min(BigInt(10)).minValue).toEqual(BigInt(10)); + + expect(z.bigint().max(BigInt(5)).maxValue).toEqual(BigInt(5)); + expect(z.bigint().max(BigInt(5)).max(BigInt(1)).maxValue).toEqual(BigInt(1)); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/branded.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/branded.test.ts new file mode 100644 index 0000000..b19786c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/branded.test.ts @@ -0,0 +1,53 @@ +// @ts-ignore TS6133 +import { test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("branded types", () => { + const mySchema = z + .object({ + name: z.string(), + }) + .brand<"superschema">(); + + // simple branding + type MySchema = z.infer; + util.assertEqual(true); + + const doStuff = (arg: MySchema) => arg; + doStuff(mySchema.parse({ name: "hello there" })); + + // inheritance + const extendedSchema = mySchema.brand<"subschema">(); + type ExtendedSchema = z.infer; + util.assertEqual & z.BRAND<"subschema">>(true); + + doStuff(extendedSchema.parse({ name: "hello again" })); + + // number branding + const numberSchema = z.number().brand<42>(); + type NumberSchema = z.infer; + util.assertEqual(true); + + // symbol branding + const MyBrand: unique symbol = Symbol("hello"); + type MyBrand = typeof MyBrand; + const symbolBrand = z.number().brand<"sup">().brand(); + type SymbolBrand = z.infer; + // number & { [z.BRAND]: { sup: true, [MyBrand]: true } } + util.assertEqual & z.BRAND>(true); + + // keeping brands out of input types + const age = z.number().brand<"age">(); + + type Age = z.infer; + type AgeInput = z.input; + + util.assertEqual(false); + util.assertEqual(true); + util.assertEqual, Age>(true); + + // @ts-expect-error + doStuff({ name: "hello there!" }); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/catch.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/catch.test.ts new file mode 100644 index 0000000..94d12aa --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/catch.test.ts @@ -0,0 +1,220 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import { z } from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("basic catch", () => { + expect(z.string().catch("default").parse(undefined)).toBe("default"); +}); + +test("catch fn does not run when parsing succeeds", () => { + let isCalled = false; + const cb = () => { + isCalled = true; + return "asdf"; + }; + expect(z.string().catch(cb).parse("test")).toBe("test"); + expect(isCalled).toEqual(false); +}); + +test("basic catch async", async () => { + const result = await z.string().catch("default").parseAsync(1243); + expect(result).toBe("default"); +}); + +test("catch replace wrong types", () => { + expect(z.string().catch("default").parse(true)).toBe("default"); + expect(z.string().catch("default").parse(true)).toBe("default"); + expect(z.string().catch("default").parse(15)).toBe("default"); + expect(z.string().catch("default").parse([])).toBe("default"); + expect(z.string().catch("default").parse(new Map())).toBe("default"); + expect(z.string().catch("default").parse(new Set())).toBe("default"); + expect(z.string().catch("default").parse({})).toBe("default"); +}); + +test("catch with transform", () => { + const stringWithDefault = z + .string() + .transform((val) => val.toUpperCase()) + .catch("default"); + expect(stringWithDefault.parse(undefined)).toBe("default"); + expect(stringWithDefault.parse(15)).toBe("default"); + expect(stringWithDefault).toBeInstanceOf(z.ZodCatch); + expect(stringWithDefault._def.innerType).toBeInstanceOf(z.ZodEffects); + expect(stringWithDefault._def.innerType._def.schema).toBeInstanceOf(z.ZodSchema); + + type inp = z.input; + util.assertEqual(true); + type out = z.output; + util.assertEqual(true); +}); + +test("catch on existing optional", () => { + const stringWithDefault = z.string().optional().catch("asdf"); + expect(stringWithDefault.parse(undefined)).toBe(undefined); + expect(stringWithDefault.parse(15)).toBe("asdf"); + expect(stringWithDefault).toBeInstanceOf(z.ZodCatch); + expect(stringWithDefault._def.innerType).toBeInstanceOf(z.ZodOptional); + expect(stringWithDefault._def.innerType._def.innerType).toBeInstanceOf(z.ZodString); + + type inp = z.input; + util.assertEqual(true); + type out = z.output; + util.assertEqual(true); +}); + +test("optional on catch", () => { + const stringWithDefault = z.string().catch("asdf").optional(); + + type inp = z.input; + util.assertEqual(true); + type out = z.output; + util.assertEqual(true); +}); + +test("complex chain example", () => { + const complex = z + .string() + .catch("asdf") + .transform((val) => val + "!") + .transform((val) => val.toUpperCase()) + .catch("qwer") + .removeCatch() + .optional() + .catch("asdfasdf"); + + expect(complex.parse("qwer")).toBe("QWER!"); + expect(complex.parse(15)).toBe("ASDF!"); + expect(complex.parse(true)).toBe("ASDF!"); +}); + +test("removeCatch", () => { + const stringWithRemovedDefault = z.string().catch("asdf").removeCatch(); + + type out = z.output; + util.assertEqual(true); +}); + +test("nested", () => { + const inner = z.string().catch("asdf"); + const outer = z.object({ inner }).catch({ + inner: "asdf", + }); + type input = z.input; + util.assertEqual(true); + type out = z.output; + util.assertEqual(true); + expect(outer.parse(undefined)).toEqual({ inner: "asdf" }); + expect(outer.parse({})).toEqual({ inner: "asdf" }); + expect(outer.parse({ inner: undefined })).toEqual({ inner: "asdf" }); +}); + +test("chained catch", () => { + const stringWithDefault = z.string().catch("inner").catch("outer"); + const result = stringWithDefault.parse(undefined); + expect(result).toEqual("inner"); + const resultDiff = stringWithDefault.parse(5); + expect(resultDiff).toEqual("inner"); +}); + +test("factory", () => { + z.ZodCatch.create(z.string(), { + catch: "asdf", + }).parse(undefined); +}); + +test("native enum", () => { + enum Fruits { + apple = "apple", + orange = "orange", + } + + const schema = z.object({ + fruit: z.nativeEnum(Fruits).catch(Fruits.apple), + }); + + expect(schema.parse({})).toEqual({ fruit: Fruits.apple }); + expect(schema.parse({ fruit: 15 })).toEqual({ fruit: Fruits.apple }); +}); + +test("enum", () => { + const schema = z.object({ + fruit: z.enum(["apple", "orange"]).catch("apple"), + }); + + expect(schema.parse({})).toEqual({ fruit: "apple" }); + expect(schema.parse({ fruit: true })).toEqual({ fruit: "apple" }); + expect(schema.parse({ fruit: 15 })).toEqual({ fruit: "apple" }); +}); + +test("reported issues with nested usage", () => { + const schema = z.object({ + string: z.string(), + obj: z.object({ + sub: z.object({ + lit: z.literal("a"), + subCatch: z.number().catch(23), + }), + midCatch: z.number().catch(42), + }), + number: z.number().catch(0), + bool: z.boolean(), + }); + + try { + schema.parse({ + string: {}, + obj: { + sub: { + lit: "b", + subCatch: "24", + }, + midCatch: 444, + }, + number: "", + bool: "yes", + }); + } catch (error) { + const issues = (error as z.ZodError).issues; + + expect(issues.length).toEqual(3); + expect(issues[0].message).toMatch("string"); + expect(issues[1].message).toMatch("literal"); + expect(issues[2].message).toMatch("boolean"); + } +}); + +test("catch error", () => { + let catchError: z.ZodError | undefined = undefined; + + const schema = z.object({ + age: z.number(), + name: z.string().catch((ctx) => { + catchError = ctx.error; + + return "John Doe"; + }), + }); + + const result = schema.safeParse({ + age: null, + name: null, + }); + + expect(result.success).toEqual(false); + expect(!result.success && result.error.issues.length).toEqual(1); + expect(!result.success && result.error.issues[0].message).toMatch("number"); + + expect(catchError).toBeInstanceOf(z.ZodError); + expect(catchError !== undefined && (catchError as z.ZodError).issues.length).toEqual(1); + expect(catchError !== undefined && (catchError as z.ZodError).issues[0].message).toMatch("string"); +}); + +test("ctx.input", () => { + const schema = z.string().catch((ctx) => { + return String(ctx.input); + }); + + expect(schema.parse(123)).toEqual("123"); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/coerce.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/coerce.test.ts new file mode 100644 index 0000000..1f53004 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/coerce.test.ts @@ -0,0 +1,133 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +test("string coercion", () => { + const schema = z.coerce.string(); + expect(schema.parse("sup")).toEqual("sup"); + expect(schema.parse("")).toEqual(""); + expect(schema.parse(12)).toEqual("12"); + expect(schema.parse(0)).toEqual("0"); + expect(schema.parse(-12)).toEqual("-12"); + expect(schema.parse(3.14)).toEqual("3.14"); + expect(schema.parse(BigInt(15))).toEqual("15"); + expect(schema.parse(Number.NaN)).toEqual("NaN"); + expect(schema.parse(Number.POSITIVE_INFINITY)).toEqual("Infinity"); + expect(schema.parse(Number.NEGATIVE_INFINITY)).toEqual("-Infinity"); + expect(schema.parse(true)).toEqual("true"); + expect(schema.parse(false)).toEqual("false"); + expect(schema.parse(null)).toEqual("null"); + expect(schema.parse(undefined)).toEqual("undefined"); + expect(schema.parse({ hello: "world!" })).toEqual("[object Object]"); + expect(schema.parse(["item", "another_item"])).toEqual("item,another_item"); + expect(schema.parse([])).toEqual(""); + expect(schema.parse(new Date("2022-01-01T00:00:00.000Z"))).toEqual(new Date("2022-01-01T00:00:00.000Z").toString()); +}); + +test("number coercion", () => { + const schema = z.coerce.number(); + expect(schema.parse("12")).toEqual(12); + expect(schema.parse("0")).toEqual(0); + expect(schema.parse("-12")).toEqual(-12); + expect(schema.parse("3.14")).toEqual(3.14); + expect(schema.parse("")).toEqual(0); + expect(() => schema.parse("NOT_A_NUMBER")).toThrow(); // z.ZodError + expect(schema.parse(12)).toEqual(12); + expect(schema.parse(0)).toEqual(0); + expect(schema.parse(-12)).toEqual(-12); + expect(schema.parse(3.14)).toEqual(3.14); + expect(schema.parse(BigInt(15))).toEqual(15); + expect(() => schema.parse(Number.NaN)).toThrow(); // z.ZodError + expect(schema.parse(Number.POSITIVE_INFINITY)).toEqual(Number.POSITIVE_INFINITY); + expect(schema.parse(Number.NEGATIVE_INFINITY)).toEqual(Number.NEGATIVE_INFINITY); + expect(schema.parse(true)).toEqual(1); + expect(schema.parse(false)).toEqual(0); + expect(schema.parse(null)).toEqual(0); + expect(() => schema.parse(undefined)).toThrow(); // z.ZodError + expect(() => schema.parse({ hello: "world!" })).toThrow(); // z.ZodError + expect(() => schema.parse(["item", "another_item"])).toThrow(); // z.ZodError + expect(schema.parse([])).toEqual(0); + expect(schema.parse(new Date(1670139203496))).toEqual(1670139203496); +}); + +test("boolean coercion", () => { + const schema = z.coerce.boolean(); + expect(schema.parse("true")).toEqual(true); + expect(schema.parse("false")).toEqual(true); + expect(schema.parse("0")).toEqual(true); + expect(schema.parse("1")).toEqual(true); + expect(schema.parse("")).toEqual(false); + expect(schema.parse(1)).toEqual(true); + expect(schema.parse(0)).toEqual(false); + expect(schema.parse(-1)).toEqual(true); + expect(schema.parse(3.14)).toEqual(true); + expect(schema.parse(BigInt(15))).toEqual(true); + expect(schema.parse(Number.NaN)).toEqual(false); + expect(schema.parse(Number.POSITIVE_INFINITY)).toEqual(true); + expect(schema.parse(Number.NEGATIVE_INFINITY)).toEqual(true); + expect(schema.parse(true)).toEqual(true); + expect(schema.parse(false)).toEqual(false); + expect(schema.parse(null)).toEqual(false); + expect(schema.parse(undefined)).toEqual(false); + expect(schema.parse({ hello: "world!" })).toEqual(true); + expect(schema.parse(["item", "another_item"])).toEqual(true); + expect(schema.parse([])).toEqual(true); + expect(schema.parse(new Date(1670139203496))).toEqual(true); +}); + +test("bigint coercion", () => { + const schema = z.coerce.bigint(); + expect(schema.parse("5")).toEqual(BigInt(5)); + expect(schema.parse("0")).toEqual(BigInt(0)); + expect(schema.parse("-5")).toEqual(BigInt(-5)); + expect(() => schema.parse("3.14")).toThrow(); // not a z.ZodError! + expect(schema.parse("")).toEqual(BigInt(0)); + expect(() => schema.parse("NOT_A_NUMBER")).toThrow(); // not a z.ZodError! + expect(schema.parse(5)).toEqual(BigInt(5)); + expect(schema.parse(0)).toEqual(BigInt(0)); + expect(schema.parse(-5)).toEqual(BigInt(-5)); + expect(() => schema.parse(3.14)).toThrow(); // not a z.ZodError! + expect(schema.parse(BigInt(5))).toEqual(BigInt(5)); + expect(() => schema.parse(Number.NaN)).toThrow(); // not a z.ZodError! + expect(() => schema.parse(Number.POSITIVE_INFINITY)).toThrow(); // not a z.ZodError! + expect(() => schema.parse(Number.NEGATIVE_INFINITY)).toThrow(); // not a z.ZodError! + expect(schema.parse(true)).toEqual(BigInt(1)); + expect(schema.parse(false)).toEqual(BigInt(0)); + expect(() => schema.parse(null)).toThrow(); // not a z.ZodError! + expect(() => schema.parse(undefined)).toThrow(); // not a z.ZodError! + expect(() => schema.parse({ hello: "world!" })).toThrow(); // not a z.ZodError! + expect(() => schema.parse(["item", "another_item"])).toThrow(); // not a z.ZodError! + expect(schema.parse([])).toEqual(BigInt(0)); + expect(schema.parse(new Date(1670139203496))).toEqual(BigInt(1670139203496)); +}); + +test("date coercion", () => { + const schema = z.coerce.date(); + expect(schema.parse(new Date().toDateString())).toBeInstanceOf(Date); + expect(schema.parse(new Date().toISOString())).toBeInstanceOf(Date); + expect(schema.parse(new Date().toUTCString())).toBeInstanceOf(Date); + expect(schema.parse("5")).toBeInstanceOf(Date); + expect(schema.parse("2000-01-01")).toBeInstanceOf(Date); + // expect(schema.parse("0")).toBeInstanceOf(Date); + // expect(schema.parse("-5")).toBeInstanceOf(Date); + // expect(schema.parse("3.14")).toBeInstanceOf(Date); + expect(() => schema.parse("")).toThrow(); // z.ZodError + expect(() => schema.parse("NOT_A_DATE")).toThrow(); // z.ZodError + expect(schema.parse(5)).toBeInstanceOf(Date); + expect(schema.parse(0)).toBeInstanceOf(Date); + expect(schema.parse(-5)).toBeInstanceOf(Date); + expect(schema.parse(3.14)).toBeInstanceOf(Date); + expect(() => schema.parse(BigInt(5))).toThrow(); // not a z.ZodError! + expect(() => schema.parse(Number.NaN)).toThrow(); // z.ZodError + expect(() => schema.parse(Number.POSITIVE_INFINITY)).toThrow(); // z.ZodError + expect(() => schema.parse(Number.NEGATIVE_INFINITY)).toThrow(); // z.ZodError + expect(schema.parse(true)).toBeInstanceOf(Date); + expect(schema.parse(false)).toBeInstanceOf(Date); + expect(schema.parse(null)).toBeInstanceOf(Date); + expect(() => schema.parse(undefined)).toThrow(); // z.ZodError + expect(() => schema.parse({ hello: "world!" })).toThrow(); // z.ZodError + expect(() => schema.parse(["item", "another_item"])).toThrow(); // z.ZodError + expect(() => schema.parse([])).toThrow(); // z.ZodError + expect(schema.parse(new Date())).toBeInstanceOf(Date); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/complex.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/complex.test.ts new file mode 100644 index 0000000..1d03033 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/complex.test.ts @@ -0,0 +1,70 @@ +import { expect, test } from "vitest"; +import * as z from "zod/v3"; + +const crazySchema = z.object({ + tuple: z.tuple([ + z.string().nullable().optional(), + z.number().nullable().optional(), + z.boolean().nullable().optional(), + z.null().nullable().optional(), + z.undefined().nullable().optional(), + z.literal("1234").nullable().optional(), + ]), + merged: z + .object({ + k1: z.string().optional(), + }) + .merge(z.object({ k1: z.string().nullable(), k2: z.number() })), + union: z.array(z.union([z.literal("asdf"), z.literal(12)])).nonempty(), + array: z.array(z.number()), + // sumTransformer: z.transformer(z.array(z.number()), z.number(), (arg) => { + // return arg.reduce((a, b) => a + b, 0); + // }), + sumMinLength: z.array(z.number()).refine((arg) => arg.length > 5), + intersection: z.intersection(z.object({ p1: z.string().optional() }), z.object({ p1: z.number().optional() })), + enum: z.intersection(z.enum(["zero", "one"]), z.enum(["one", "two"])), + nonstrict: z.object({ points: z.number() }).nonstrict(), + numProm: z.promise(z.number()), + lenfun: z.function(z.tuple([z.string()]), z.boolean()), +}); + +// const asyncCrazySchema = crazySchema.extend({ +// // async_transform: z.transformer( +// // z.array(z.number()), +// // z.number(), +// // async (arg) => { +// // return arg.reduce((a, b) => a + b, 0); +// // } +// // ), +// async_refine: z.array(z.number()).refine(async (arg) => arg.length > 5), +// }); + +test("parse", () => { + const input = { + tuple: ["asdf", 1234, true, null, undefined, "1234"], + merged: { k1: "asdf", k2: 12 }, + union: ["asdf", 12, "asdf", 12, "asdf", 12], + array: [12, 15, 16], + // sumTransformer: [12, 15, 16], + sumMinLength: [12, 15, 16, 98, 24, 63], + intersection: {}, + enum: "one", + nonstrict: { points: 1234 }, + numProm: Promise.resolve(12), + lenfun: (x: string) => x.length, + }; + + const result = crazySchema.parse(input); + + // Verify the parsed result structure + expect(result.tuple).toEqual(input.tuple); + expect(result.merged).toEqual(input.merged); + expect(result.union).toEqual(input.union); + expect(result.array).toEqual(input.array); + expect(result.sumMinLength).toEqual(input.sumMinLength); + expect(result.intersection).toEqual(input.intersection); + expect(result.enum).toEqual(input.enum); + expect(result.nonstrict).toEqual(input.nonstrict); + expect(result.numProm).toBeInstanceOf(Promise); + expect(typeof result.lenfun).toBe("function"); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/custom.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/custom.test.ts new file mode 100644 index 0000000..b24b676 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/custom.test.ts @@ -0,0 +1,31 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +test("passing validations", () => { + const example1 = z.custom((x) => typeof x === "number"); + example1.parse(1234); + expect(() => example1.parse({})).toThrow(); +}); + +test("string params", () => { + const example1 = z.custom((x) => typeof x !== "number", "customerr"); + const result = example1.safeParse(1234); + expect(result.success).toEqual(false); + // @ts-ignore + expect(JSON.stringify(result.error).includes("customerr")).toEqual(true); +}); + +test("async validations", async () => { + const example1 = z.custom(async (x) => { + return typeof x === "number"; + }); + const r1 = await example1.safeParseAsync(1234); + expect(r1.success).toEqual(true); + expect(r1.data).toEqual(1234); + + const r2 = await example1.safeParseAsync("asdf"); + expect(r2.success).toEqual(false); + expect(r2.error!.issues.length).toEqual(1); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/date.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/date.test.ts new file mode 100644 index 0000000..c86dc84 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/date.test.ts @@ -0,0 +1,32 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +const beforeBenchmarkDate = new Date(2022, 10, 4); +const benchmarkDate = new Date(2022, 10, 5); +const afterBenchmarkDate = new Date(2022, 10, 6); + +const minCheck = z.date().min(benchmarkDate); +const maxCheck = z.date().max(benchmarkDate); + +test("passing validations", () => { + minCheck.parse(benchmarkDate); + minCheck.parse(afterBenchmarkDate); + + maxCheck.parse(benchmarkDate); + maxCheck.parse(beforeBenchmarkDate); +}); + +test("failing validations", () => { + expect(() => minCheck.parse(beforeBenchmarkDate)).toThrow(); + expect(() => maxCheck.parse(afterBenchmarkDate)).toThrow(); +}); + +test("min max getters", () => { + expect(minCheck.minDate).toEqual(benchmarkDate); + expect(minCheck.min(afterBenchmarkDate).minDate).toEqual(afterBenchmarkDate); + + expect(maxCheck.maxDate).toEqual(benchmarkDate); + expect(maxCheck.max(beforeBenchmarkDate).maxDate).toEqual(beforeBenchmarkDate); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/deepmasking.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/deepmasking.test.ts new file mode 100644 index 0000000..d707e79 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/deepmasking.test.ts @@ -0,0 +1,186 @@ +// @ts-ignore TS6133 +import { test } from "vitest"; + +import * as z from "zod/v3"; + +test("test", () => { + z; +}); + +// const fish = z.object({ +// name: z.string(), +// props: z.object({ +// color: z.string(), +// numScales: z.number(), +// }), +// }); + +// const nonStrict = z +// .object({ +// name: z.string(), +// color: z.string(), +// }) +// .nonstrict(); + +// test('object pick type', () => { +// const modNonStrictFish = nonStrict.omit({ name: true }); +// modNonStrictFish.parse({ color: 'asdf' }); + +// const bad1 = () => fish.pick({ props: { unknown: true } } as any); +// const bad2 = () => fish.omit({ name: true, props: { unknown: true } } as any); + +// expect(bad1).toThrow(); +// expect(bad2).toThrow(); +// }); + +// test('f1', () => { +// const f1 = fish.pick(true); +// f1.parse({ name: 'a', props: { color: 'b', numScales: 3 } }); +// }); +// test('f2', () => { +// const f2 = fish.pick({ props: true }); +// f2.parse({ props: { color: 'asdf', numScales: 1 } }); +// const badcheck2 = () => f2.parse({ name: 'a', props: { color: 'b', numScales: 3 } } as any); +// expect(badcheck2).toThrow(); +// }); +// test('f3', () => { +// const f3 = fish.pick({ props: { color: true } }); +// f3.parse({ props: { color: 'b' } }); +// const badcheck3 = () => f3.parse({ name: 'a', props: { color: 'b', numScales: 3 } } as any); +// expect(badcheck3).toThrow(); +// }); +// test('f4', () => { +// const badcheck4 = () => fish.pick({ props: { color: true, unknown: true } }); +// expect(badcheck4).toThrow(); +// }); +// test('f6', () => { +// const f6 = fish.omit({ props: true }); +// const badcheck6 = () => f6.parse({ name: 'a', props: { color: 'b', numScales: 3 } } as any); +// f6.parse({ name: 'adsf' }); +// expect(badcheck6).toThrow(); +// }); +// test('f7', () => { +// const f7 = fish.omit({ props: { color: true } }); +// f7.parse({ name: 'a', props: { numScales: 3 } }); +// const badcheck7 = () => f7.parse({ name: 'a', props: { color: 'b', numScales: 3 } } as any); +// expect(badcheck7).toThrow(); +// }); +// test('f8', () => { +// const badcheck8 = () => fish.omit({ props: { color: true, unknown: true } }); +// expect(badcheck8).toThrow(); +// }); +// test('f9', () => { +// const f9 = nonStrict.pick(true); +// f9.parse({ name: 'a', color: 'asdf' }); +// }); +// test('f10', () => { +// const f10 = nonStrict.pick({ name: true }); +// f10.parse({ name: 'a' }); +// const val = f10.parse({ name: 'a', color: 'b' }); +// expect(val).toEqual({ name: 'a' }); +// }); +// test('f12', () => { +// const badfcheck12 = () => nonStrict.omit({ color: true, asdf: true }); +// expect(badfcheck12).toThrow(); +// }); + +// test('array masking', () => { +// const fishArray = z.array(fish); +// const modFishArray = fishArray.pick({ +// name: true, +// props: { +// numScales: true, +// }, +// }); + +// modFishArray.parse([{ name: 'fish', props: { numScales: 12 } }]); +// const bad1 = () => modFishArray.parse([{ name: 'fish', props: { numScales: 12, color: 'asdf' } }] as any); +// expect(bad1).toThrow(); +// }); + +// test('array masking', () => { +// const fishArray = z.array(fish); +// const fail = () => +// fishArray.pick({ +// name: true, +// props: { +// whatever: true, +// }, +// } as any); +// expect(fail).toThrow(); +// }); + +// test('array masking', () => { +// const fishArray = z.array(fish); +// const fail = () => +// fishArray.omit({ +// whateve: true, +// } as any); +// expect(fail).toThrow(); +// }); + +// test('array masking', () => { +// const fishArray = z.array(fish); +// const modFishList = fishArray.omit({ +// name: true, +// props: { +// color: true, +// }, +// }); + +// modFishList.parse([{ props: { numScales: 12 } }]); +// const fail = () => modFishList.parse([{ name: 'hello', props: { numScales: 12 } }] as any); +// expect(fail).toThrow(); +// }); + +// test('primitive array masking', () => { +// const fishArray = z.array(z.number()); +// const fail = () => fishArray.pick({} as any); +// expect(fail).toThrow(); +// }); + +// test('other array masking', () => { +// const fishArray = z.array(z.array(z.number())); +// const fail = () => fishArray.pick({} as any); +// expect(fail).toThrow(); +// }); + +// test('invalid mask #1', () => { +// const fail = () => fish.pick(1 as any); +// expect(fail).toThrow(); +// }); + +// test('invalid mask #2', () => { +// const fail = () => fish.pick([] as any); +// expect(fail).toThrow(); +// }); + +// test('invalid mask #3', () => { +// const fail = () => fish.pick(false as any); +// expect(fail).toThrow(); +// }); + +// test('invalid mask #4', () => { +// const fail = () => fish.pick('asdf' as any); +// expect(fail).toThrow(); +// }); + +// test('invalid mask #5', () => { +// const fail = () => fish.omit(1 as any); +// expect(fail).toThrow(); +// }); + +// test('invalid mask #6', () => { +// const fail = () => fish.omit([] as any); +// expect(fail).toThrow(); +// }); + +// test('invalid mask #7', () => { +// const fail = () => fish.omit(false as any); +// expect(fail).toThrow(); +// }); + +// test('invalid mask #8', () => { +// const fail = () => fish.omit('asdf' as any); +// expect(fail).toThrow(); +// }); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/default.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/default.test.ts new file mode 100644 index 0000000..29e007c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/default.test.ts @@ -0,0 +1,112 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import { z } from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("basic defaults", () => { + expect(z.string().default("default").parse(undefined)).toBe("default"); +}); + +test("default with transform", () => { + const stringWithDefault = z + .string() + .transform((val) => val.toUpperCase()) + .default("default"); + expect(stringWithDefault.parse(undefined)).toBe("DEFAULT"); + expect(stringWithDefault).toBeInstanceOf(z.ZodDefault); + expect(stringWithDefault._def.innerType).toBeInstanceOf(z.ZodEffects); + expect(stringWithDefault._def.innerType._def.schema).toBeInstanceOf(z.ZodSchema); + + type inp = z.input; + util.assertEqual(true); + type out = z.output; + util.assertEqual(true); +}); + +test("default on existing optional", () => { + const stringWithDefault = z.string().optional().default("asdf"); + expect(stringWithDefault.parse(undefined)).toBe("asdf"); + expect(stringWithDefault).toBeInstanceOf(z.ZodDefault); + expect(stringWithDefault._def.innerType).toBeInstanceOf(z.ZodOptional); + expect(stringWithDefault._def.innerType._def.innerType).toBeInstanceOf(z.ZodString); + + type inp = z.input; + util.assertEqual(true); + type out = z.output; + util.assertEqual(true); +}); + +test("optional on default", () => { + const stringWithDefault = z.string().default("asdf").optional(); + + type inp = z.input; + util.assertEqual(true); + type out = z.output; + util.assertEqual(true); +}); + +test("complex chain example", () => { + const complex = z + .string() + .default("asdf") + .transform((val) => val.toUpperCase()) + .default("qwer") + .removeDefault() + .optional() + .default("asdfasdf"); + + expect(complex.parse(undefined)).toBe("ASDFASDF"); +}); + +test("removeDefault", () => { + const stringWithRemovedDefault = z.string().default("asdf").removeDefault(); + + type out = z.output; + util.assertEqual(true); +}); + +test("nested", () => { + const inner = z.string().default("asdf"); + const outer = z.object({ inner }).default({ + inner: undefined, + }); + type input = z.input; + util.assertEqual(true); + type out = z.output; + util.assertEqual(true); + expect(outer.parse(undefined)).toEqual({ inner: "asdf" }); + expect(outer.parse({})).toEqual({ inner: "asdf" }); + expect(outer.parse({ inner: undefined })).toEqual({ inner: "asdf" }); +}); + +test("chained defaults", () => { + const stringWithDefault = z.string().default("inner").default("outer"); + const result = stringWithDefault.parse(undefined); + expect(result).toEqual("outer"); +}); + +test("factory", () => { + expect(z.ZodDefault.create(z.string(), { default: "asdf" }).parse(undefined)).toEqual("asdf"); +}); + +test("native enum", () => { + enum Fruits { + apple = "apple", + orange = "orange", + } + + const schema = z.object({ + fruit: z.nativeEnum(Fruits).default(Fruits.apple), + }); + + expect(schema.parse({})).toEqual({ fruit: Fruits.apple }); +}); + +test("enum", () => { + const schema = z.object({ + fruit: z.enum(["apple", "orange"]).default("apple"), + }); + + expect(schema.parse({})).toEqual({ fruit: "apple" }); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/description.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/description.test.ts new file mode 100644 index 0000000..1edaa1c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/description.test.ts @@ -0,0 +1,33 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +const description = "a description"; + +test("passing `description` to schema should add a description", () => { + expect(z.string({ description }).description).toEqual(description); + expect(z.number({ description }).description).toEqual(description); + expect(z.boolean({ description }).description).toEqual(description); +}); + +test("`.describe` should add a description", () => { + expect(z.string().describe(description).description).toEqual(description); + expect(z.number().describe(description).description).toEqual(description); + expect(z.boolean().describe(description).description).toEqual(description); +}); + +test("description should carry over to chained schemas", () => { + const schema = z.string({ description }); + expect(schema.description).toEqual(description); + expect(schema.optional().description).toEqual(description); + expect(schema.optional().nullable().default("default").description).toEqual(description); +}); + +test("description should not carry over to chained array schema", () => { + const schema = z.string().describe(description); + + expect(schema.description).toEqual(description); + expect(schema.array().description).toEqual(undefined); + expect(z.array(schema).description).toEqual(undefined); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/discriminated-unions.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/discriminated-unions.test.ts new file mode 100644 index 0000000..7fb5cfe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/discriminated-unions.test.ts @@ -0,0 +1,315 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +test("valid", () => { + expect( + z + .discriminatedUnion("type", [ + z.object({ type: z.literal("a"), a: z.string() }), + z.object({ type: z.literal("b"), b: z.string() }), + ]) + .parse({ type: "a", a: "abc" }) + ).toEqual({ type: "a", a: "abc" }); +}); + +test("valid - discriminator value of various primitive types", () => { + const schema = z.discriminatedUnion("type", [ + z.object({ type: z.literal("1"), val: z.literal(1) }), + z.object({ type: z.literal(1), val: z.literal(2) }), + z.object({ type: z.literal(BigInt(1)), val: z.literal(3) }), + z.object({ type: z.literal("true"), val: z.literal(4) }), + z.object({ type: z.literal(true), val: z.literal(5) }), + z.object({ type: z.literal("null"), val: z.literal(6) }), + z.object({ type: z.literal(null), val: z.literal(7) }), + z.object({ type: z.literal("undefined"), val: z.literal(8) }), + z.object({ type: z.literal(undefined), val: z.literal(9) }), + z.object({ type: z.literal("transform"), val: z.literal(10) }), + z.object({ type: z.literal("refine"), val: z.literal(11) }), + z.object({ type: z.literal("superRefine"), val: z.literal(12) }), + ]); + + expect(schema.parse({ type: "1", val: 1 })).toEqual({ type: "1", val: 1 }); + expect(schema.parse({ type: 1, val: 2 })).toEqual({ type: 1, val: 2 }); + expect(schema.parse({ type: BigInt(1), val: 3 })).toEqual({ + type: BigInt(1), + val: 3, + }); + expect(schema.parse({ type: "true", val: 4 })).toEqual({ + type: "true", + val: 4, + }); + expect(schema.parse({ type: true, val: 5 })).toEqual({ + type: true, + val: 5, + }); + expect(schema.parse({ type: "null", val: 6 })).toEqual({ + type: "null", + val: 6, + }); + expect(schema.parse({ type: null, val: 7 })).toEqual({ + type: null, + val: 7, + }); + expect(schema.parse({ type: "undefined", val: 8 })).toEqual({ + type: "undefined", + val: 8, + }); + expect(schema.parse({ type: undefined, val: 9 })).toEqual({ + type: undefined, + val: 9, + }); +}); + +test("invalid - null", () => { + try { + z.discriminatedUnion("type", [ + z.object({ type: z.literal("a"), a: z.string() }), + z.object({ type: z.literal("b"), b: z.string() }), + ]).parse(null); + throw new Error(); + } catch (e: any) { + expect(JSON.parse(e.message)).toEqual([ + { + code: z.ZodIssueCode.invalid_type, + expected: z.ZodParsedType.object, + message: "Expected object, received null", + received: z.ZodParsedType.null, + path: [], + }, + ]); + } +}); + +test("invalid discriminator value", () => { + try { + z.discriminatedUnion("type", [ + z.object({ type: z.literal("a"), a: z.string() }), + z.object({ type: z.literal("b"), b: z.string() }), + ]).parse({ type: "x", a: "abc" }); + throw new Error(); + } catch (e: any) { + expect(JSON.parse(e.message)).toEqual([ + { + code: z.ZodIssueCode.invalid_union_discriminator, + options: ["a", "b"], + message: "Invalid discriminator value. Expected 'a' | 'b'", + path: ["type"], + }, + ]); + } +}); + +test("valid discriminator value, invalid data", () => { + try { + z.discriminatedUnion("type", [ + z.object({ type: z.literal("a"), a: z.string() }), + z.object({ type: z.literal("b"), b: z.string() }), + ]).parse({ type: "a", b: "abc" }); + throw new Error(); + } catch (e: any) { + expect(JSON.parse(e.message)).toEqual([ + { + code: z.ZodIssueCode.invalid_type, + expected: z.ZodParsedType.string, + message: "Required", + path: ["a"], + received: z.ZodParsedType.undefined, + }, + ]); + } +}); + +test("wrong schema - missing discriminator", () => { + try { + z.discriminatedUnion("type", [ + z.object({ type: z.literal("a"), a: z.string() }), + z.object({ b: z.string() }) as any, + ]); + throw new Error(); + } catch (e: any) { + expect(e.message.includes("could not be extracted")).toBe(true); + } +}); + +test("wrong schema - duplicate discriminator values", () => { + try { + z.discriminatedUnion("type", [ + z.object({ type: z.literal("a"), a: z.string() }), + z.object({ type: z.literal("a"), b: z.string() }), + ]); + throw new Error(); + } catch (e: any) { + expect(e.message.includes("has duplicate value")).toEqual(true); + } +}); + +test("async - valid", async () => { + expect( + await z + .discriminatedUnion("type", [ + z.object({ + type: z.literal("a"), + a: z + .string() + .refine(async () => true) + .transform(async (val) => Number(val)), + }), + z.object({ + type: z.literal("b"), + b: z.string(), + }), + ]) + .parseAsync({ type: "a", a: "1" }) + ).toEqual({ type: "a", a: 1 }); +}); + +test("async - invalid", async () => { + try { + await z + .discriminatedUnion("type", [ + z.object({ + type: z.literal("a"), + a: z + .string() + .refine(async () => true) + .transform(async (val) => val), + }), + z.object({ + type: z.literal("b"), + b: z.string(), + }), + ]) + .parseAsync({ type: "a", a: 1 }); + throw new Error(); + } catch (e: any) { + expect(JSON.parse(e.message)).toEqual([ + { + code: "invalid_type", + expected: "string", + received: "number", + path: ["a"], + message: "Expected string, received number", + }, + ]); + } +}); + +test("valid - literals with .default or .preprocess", () => { + const schema = z.discriminatedUnion("type", [ + z.object({ + type: z.literal("foo").default("foo"), + a: z.string(), + }), + z.object({ + type: z.literal("custom"), + method: z.string(), + }), + z.object({ + type: z.preprocess((val) => String(val), z.literal("bar")), + c: z.string(), + }), + ]); + expect(schema.parse({ type: "foo", a: "foo" })).toEqual({ + type: "foo", + a: "foo", + }); +}); + +test("enum and nativeEnum", () => { + enum MyEnum { + d = 0, + e = "e", + } + + const schema = z.discriminatedUnion("key", [ + z.object({ + key: z.literal("a"), + // Add other properties specific to this option + }), + z.object({ + key: z.enum(["b", "c"]), + // Add other properties specific to this option + }), + z.object({ + key: z.nativeEnum(MyEnum), + // Add other properties specific to this option + }), + ]); + + // type schema = z.infer; + + schema.parse({ key: "a" }); + schema.parse({ key: "b" }); + schema.parse({ key: "c" }); + schema.parse({ key: MyEnum.d }); + schema.parse({ key: MyEnum.e }); + schema.parse({ key: "e" }); +}); + +test("branded", () => { + const schema = z.discriminatedUnion("key", [ + z.object({ + key: z.literal("a"), + // Add other properties specific to this option + }), + z.object({ + key: z.literal("b").brand("asdfaf"), + // Add other properties specific to this option + }), + ]); + + // type schema = z.infer; + + schema.parse({ key: "a" }); + schema.parse({ key: "b" }); + expect(() => { + schema.parse({ key: "c" }); + }).toThrow(); +}); + +test("optional and nullable", () => { + const schema = z.discriminatedUnion("key", [ + z.object({ + key: z.literal("a").optional(), + a: z.literal(true), + }), + z.object({ + key: z.literal("b").nullable(), + b: z.literal(true), + // Add other properties specific to this option + }), + ]); + + type schema = z.infer; + z.util.assertEqual(true); + + schema.parse({ key: "a", a: true }); + schema.parse({ key: undefined, a: true }); + schema.parse({ key: "b", b: true }); + schema.parse({ key: null, b: true }); + expect(() => { + schema.parse({ key: null, a: true }); + }).toThrow(); + expect(() => { + schema.parse({ key: "b", a: true }); + }).toThrow(); + + const value = schema.parse({ key: null, b: true }); + + if (!("key" in value)) value.a; + if (value.key === undefined) value.a; + if (value.key === "a") value.a; + if (value.key === "b") value.b; + if (value.key === null) value.b; +}); + +test("readonly array of options", () => { + const options = [ + z.object({ type: z.literal("x"), val: z.literal(1) }), + z.object({ type: z.literal("y"), val: z.literal(2) }), + ] as const; + + expect(z.discriminatedUnion("type", options).parse({ type: "x", val: 1 })).toEqual({ type: "x", val: 1 }); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/enum.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/enum.test.ts new file mode 100644 index 0000000..53f4a3e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/enum.test.ts @@ -0,0 +1,80 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("create enum", () => { + const MyEnum = z.enum(["Red", "Green", "Blue"]); + expect(MyEnum.Values.Red).toEqual("Red"); + expect(MyEnum.Enum.Red).toEqual("Red"); + expect(MyEnum.enum.Red).toEqual("Red"); +}); + +test("infer enum", () => { + const MyEnum = z.enum(["Red", "Green", "Blue"]); + type MyEnum = z.infer; + util.assertEqual(true); +}); + +test("get options", () => { + expect(z.enum(["tuna", "trout"]).options).toEqual(["tuna", "trout"]); +}); + +test("readonly enum", () => { + const HTTP_SUCCESS = ["200", "201"] as const; + const arg = z.enum(HTTP_SUCCESS); + type arg = z.infer; + util.assertEqual(true); + + arg.parse("201"); + expect(() => arg.parse("202")).toThrow(); +}); + +test("error params", () => { + const result = z.enum(["test"], { required_error: "REQUIRED" }).safeParse(undefined); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].message).toEqual("REQUIRED"); + } +}); + +test("extract/exclude", () => { + const foods = ["Pasta", "Pizza", "Tacos", "Burgers", "Salad"] as const; + const FoodEnum = z.enum(foods); + const ItalianEnum = FoodEnum.extract(["Pasta", "Pizza"]); + const UnhealthyEnum = FoodEnum.exclude(["Salad"]); + const EmptyFoodEnum = FoodEnum.exclude(foods); + + util.assertEqual, "Pasta" | "Pizza">(true); + util.assertEqual, "Pasta" | "Pizza" | "Tacos" | "Burgers">(true); + // @ts-expect-error TS2344 + util.assertEqual>(true); + util.assertEqual, never>(true); +}); + +test("error map in extract/exclude", () => { + const foods = ["Pasta", "Pizza", "Tacos", "Burgers", "Salad"] as const; + const FoodEnum = z.enum(foods, { + errorMap: () => ({ message: "This is not food!" }), + }); + const ItalianEnum = FoodEnum.extract(["Pasta", "Pizza"]); + const foodsError = FoodEnum.safeParse("Cucumbers"); + const italianError = ItalianEnum.safeParse("Tacos"); + if (!foodsError.success && !italianError.success) { + expect(foodsError.error.issues[0].message).toEqual(italianError.error.issues[0].message); + } + + const UnhealthyEnum = FoodEnum.exclude(["Salad"], { + errorMap: () => ({ message: "This is not healthy food!" }), + }); + const unhealthyError = UnhealthyEnum.safeParse("Salad"); + if (!unhealthyError.success) { + expect(unhealthyError.error.issues[0].message).toEqual("This is not healthy food!"); + } +}); + +test("readonly in ZodEnumDef", () => { + let _t!: z.ZodEnumDef; + _t; +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/error.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/error.test.ts new file mode 100644 index 0000000..5caaa6d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/error.test.ts @@ -0,0 +1,551 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { ZodError, ZodIssueCode } from "../ZodError.js"; +import { ZodParsedType } from "../helpers/util.js"; + +test("error creation", () => { + const err1 = ZodError.create([]); + err1.addIssue({ + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.object, + received: ZodParsedType.string, + path: [], + message: "", + fatal: true, + }); + err1.isEmpty; + + const err2 = ZodError.create(err1.issues); + const err3 = new ZodError([]); + err3.addIssues(err1.issues); + err3.addIssue(err1.issues[0]); + err1.message; + err2.message; + err3.message; +}); + +const errorMap: z.ZodErrorMap = (error, ctx) => { + if (error.code === ZodIssueCode.invalid_type) { + if (error.expected === "string") { + return { message: "bad type!" }; + } + } + if (error.code === ZodIssueCode.custom) { + return { message: `less-than-${error.params?.minimum}` }; + } + return { message: ctx.defaultError }; +}; + +test("type error with custom error map", () => { + try { + z.string().parse(234, { errorMap }); + } catch (err) { + const zerr: z.ZodError = err as any; + + expect(zerr.issues[0].code).toEqual(z.ZodIssueCode.invalid_type); + expect(zerr.issues[0].message).toEqual(`bad type!`); + } +}); + +test("refinement fail with params", () => { + try { + z.number() + .refine((val) => val >= 3, { + params: { minimum: 3 }, + }) + .parse(2, { errorMap }); + } catch (err) { + const zerr: z.ZodError = err as any; + expect(zerr.issues[0].code).toEqual(z.ZodIssueCode.custom); + expect(zerr.issues[0].message).toEqual(`less-than-3`); + } +}); + +test("custom error with custom errormap", () => { + try { + z.string() + .refine((val) => val.length > 12, { + params: { minimum: 13 }, + message: "override", + }) + .parse("asdf", { errorMap }); + } catch (err) { + const zerr: z.ZodError = err as any; + expect(zerr.issues[0].message).toEqual("override"); + } +}); + +test("default error message", () => { + try { + z.number() + .refine((x) => x > 3) + .parse(2); + } catch (err) { + const zerr: z.ZodError = err as any; + expect(zerr.issues.length).toEqual(1); + expect(zerr.issues[0].message).toEqual("Invalid input"); + } +}); + +test("override error in refine", () => { + try { + z.number() + .refine((x) => x > 3, "override") + .parse(2); + } catch (err) { + const zerr: z.ZodError = err as any; + expect(zerr.issues.length).toEqual(1); + expect(zerr.issues[0].message).toEqual("override"); + } +}); + +test("override error in refinement", () => { + try { + z.number() + .refine((x) => x > 3, { + message: "override", + }) + .parse(2); + } catch (err) { + const zerr: z.ZodError = err as any; + expect(zerr.issues.length).toEqual(1); + expect(zerr.issues[0].message).toEqual("override"); + } +}); + +test("array minimum", () => { + try { + z.array(z.string()).min(3, "tooshort").parse(["asdf", "qwer"]); + } catch (err) { + const zerr: ZodError = err as any; + expect(zerr.issues[0].code).toEqual(ZodIssueCode.too_small); + expect(zerr.issues[0].message).toEqual("tooshort"); + } + try { + z.array(z.string()).min(3).parse(["asdf", "qwer"]); + } catch (err) { + const zerr: ZodError = err as any; + expect(zerr.issues[0].code).toEqual(ZodIssueCode.too_small); + expect(zerr.issues[0].message).toEqual(`Array must contain at least 3 element(s)`); + } +}); + +// implement test for semi-smart union logic that checks for type error on either left or right +// test("union smart errors", () => { +// // expect.assertions(2); + +// const p1 = z +// .union([z.string(), z.number().refine((x) => x > 0)]) +// .safeParse(-3.2); + +// if (p1.success === true) throw new Error(); +// expect(p1.success).toBe(false); +// expect(p1.error.issues[0].code).toEqual(ZodIssueCode.custom); + +// const p2 = z.union([z.string(), z.number()]).safeParse(false); +// // .catch(err => expect(err.issues[0].code).toEqual(ZodIssueCode.invalid_union)); +// if (p2.success === true) throw new Error(); +// expect(p2.success).toBe(false); +// expect(p2.error.issues[0].code).toEqual(ZodIssueCode.invalid_union); +// }); + +test("custom path in custom error map", () => { + const schema = z.object({ + items: z.array(z.string()).refine((data) => data.length > 3, { + path: ["items-too-few"], + }), + }); + + const errorMap: z.ZodErrorMap = (error) => { + expect(error.path.length).toBe(2); + return { message: "doesnt matter" }; + }; + const result = schema.safeParse({ items: ["first"] }, { errorMap }); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].path).toEqual(["items", "items-too-few"]); + } +}); + +test("error metadata from value", () => { + const dynamicRefine = z.string().refine( + (val) => val === val.toUpperCase(), + (val) => ({ params: { val } }) + ); + + const result = dynamicRefine.safeParse("asdf"); + expect(result.success).toEqual(false); + if (!result.success) { + const sub = result.error.issues[0]; + expect(result.error.issues[0].code).toEqual("custom"); + if (sub.code === "custom") { + expect(sub.params!.val).toEqual("asdf"); + } + } +}); + +// test("don't call refine after validation failed", () => { +// const asdf = z +// .union([ +// z.number(), +// z.string().transform(z.number(), (val) => { +// return parseFloat(val); +// }), +// ]) +// .refine((v) => v >= 1); + +// expect(() => asdf.safeParse("foo")).not.toThrow(); +// }); + +test("root level formatting", () => { + const schema = z.string().email(); + const result = schema.safeParse("asdfsdf"); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.format()._errors).toEqual(["Invalid email"]); + } +}); + +test("custom path", () => { + const schema = z + .object({ + password: z.string(), + confirm: z.string(), + }) + .refine((val) => val.confirm === val.password, { path: ["confirm"] }); + + const result = schema.safeParse({ + password: "peanuts", + confirm: "qeanuts", + }); + + expect(result.success).toEqual(false); + if (!result.success) { + // nested errors + const error = result.error.format(); + expect(error._errors).toEqual([]); + expect(error.password?._errors).toEqual(undefined); + expect(error.confirm?._errors).toEqual(["Invalid input"]); + } +}); + +test("custom path", () => { + const schema = z + .object({ + password: z.string().min(6), + confirm: z.string().min(6), + }) + .refine((val) => val.confirm === val.password); + + const result = schema.safeParse({ + password: "qwer", + confirm: "asdf", + }); + + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues.length).toEqual(3); + } +}); + +const schema = z.object({ + inner: z.object({ + name: z + .string() + .refine((val) => val.length > 5) + .array() + .refine((val) => val.length <= 1), + }), +}); + +test("no abort early on refinements", () => { + const invalidItem = { + inner: { name: ["aasd", "asdfasdfasfd"] }, + }; + + const result1 = schema.safeParse(invalidItem); + expect(result1.success).toEqual(false); + if (!result1.success) { + expect(result1.error.issues.length).toEqual(2); + } +}); +test("formatting", () => { + const invalidItem = { + inner: { name: ["aasd", "asdfasdfasfd"] }, + }; + const invalidArray = { + inner: { name: ["asdfasdf", "asdfasdfasfd"] }, + }; + const result1 = schema.safeParse(invalidItem); + const result2 = schema.safeParse(invalidArray); + + expect(result1.success).toEqual(false); + expect(result2.success).toEqual(false); + if (!result1.success) { + const error = result1.error.format(); + + expect(error._errors).toEqual([]); + expect(error.inner?._errors).toEqual([]); + // expect(error.inner?.name?._errors).toEqual(["Invalid input"]); + // expect(error.inner?.name?.[0]._errors).toEqual(["Invalid input"]); + expect(error.inner?.name?.[1]).toEqual(undefined); + } + if (!result2.success) { + type FormattedError = z.inferFormattedError; + const error: FormattedError = result2.error.format(); + expect(error._errors).toEqual([]); + expect(error.inner?._errors).toEqual([]); + expect(error.inner?.name?._errors).toEqual(["Invalid input"]); + expect(error.inner?.name?.[0]).toEqual(undefined); + expect(error.inner?.name?.[1]).toEqual(undefined); + expect(error.inner?.name?.[2]).toEqual(undefined); + } + + // test custom mapper + if (!result2.success) { + type FormattedError = z.inferFormattedError; + const error: FormattedError = result2.error.format(() => 5); + expect(error._errors).toEqual([]); + expect(error.inner?._errors).toEqual([]); + expect(error.inner?.name?._errors).toEqual([5]); + } +}); + +test("formatting with nullable and optional fields", () => { + const nameSchema = z.string().refine((val) => val.length > 5); + const schema = z.object({ + nullableObject: z.object({ name: nameSchema }).nullable(), + nullableArray: z.array(nameSchema).nullable(), + nullableTuple: z.tuple([nameSchema, nameSchema, z.number()]).nullable(), + optionalObject: z.object({ name: nameSchema }).optional(), + optionalArray: z.array(nameSchema).optional(), + optionalTuple: z.tuple([nameSchema, nameSchema, z.number()]).optional(), + }); + const invalidItem = { + nullableObject: { name: "abcd" }, + nullableArray: ["abcd"], + nullableTuple: ["abcd", "abcd", 1], + optionalObject: { name: "abcd" }, + optionalArray: ["abcd"], + optionalTuple: ["abcd", "abcd", 1], + }; + const result = schema.safeParse(invalidItem); + expect(result.success).toEqual(false); + if (!result.success) { + type FormattedError = z.inferFormattedError; + const error: FormattedError = result.error.format(); + expect(error._errors).toEqual([]); + expect(error.nullableObject?._errors).toEqual([]); + expect(error.nullableObject?.name?._errors).toEqual(["Invalid input"]); + expect(error.nullableArray?._errors).toEqual([]); + expect(error.nullableArray?.[0]?._errors).toEqual(["Invalid input"]); + expect(error.nullableTuple?._errors).toEqual([]); + expect(error.nullableTuple?.[0]?._errors).toEqual(["Invalid input"]); + expect(error.nullableTuple?.[1]?._errors).toEqual(["Invalid input"]); + expect(error.optionalObject?._errors).toEqual([]); + expect(error.optionalObject?.name?._errors).toEqual(["Invalid input"]); + expect(error.optionalArray?._errors).toEqual([]); + expect(error.optionalArray?.[0]?._errors).toEqual(["Invalid input"]); + expect(error.optionalTuple?._errors).toEqual([]); + expect(error.optionalTuple?.[0]?._errors).toEqual(["Invalid input"]); + expect(error.optionalTuple?.[1]?._errors).toEqual(["Invalid input"]); + } +}); + +const stringWithCustomError = z.string({ + errorMap: (issue, ctx) => ({ + message: issue.code === "invalid_type" ? (ctx.data ? "Invalid name" : "Name is required") : ctx.defaultError, + }), +}); + +test("schema-bound error map", () => { + const result = stringWithCustomError.safeParse(1234); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].message).toEqual("Invalid name"); + } + + const result2 = stringWithCustomError.safeParse(undefined); + expect(result2.success).toEqual(false); + if (!result2.success) { + expect(result2.error.issues[0].message).toEqual("Name is required"); + } + + // support contextual override + const result3 = stringWithCustomError.safeParse(undefined, { + errorMap: () => ({ message: "OVERRIDE" }), + }); + expect(result3.success).toEqual(false); + if (!result3.success) { + expect(result3.error.issues[0].message).toEqual("OVERRIDE"); + } +}); + +test("overrideErrorMap", () => { + // support overrideErrorMap + z.setErrorMap(() => ({ message: "OVERRIDE" })); + const result4 = stringWithCustomError.min(10).safeParse("tooshort"); + expect(result4.success).toEqual(false); + if (!result4.success) { + expect(result4.error.issues[0].message).toEqual("OVERRIDE"); + } + z.setErrorMap(z.defaultErrorMap); +}); + +test("invalid and required", () => { + const str = z.string({ + invalid_type_error: "Invalid name", + required_error: "Name is required", + }); + const result1 = str.safeParse(1234); + expect(result1.success).toEqual(false); + if (!result1.success) { + expect(result1.error.issues[0].message).toEqual("Invalid name"); + } + const result2 = str.safeParse(undefined); + expect(result2.success).toEqual(false); + if (!result2.success) { + expect(result2.error.issues[0].message).toEqual("Name is required"); + } +}); + +test("Fallback to default required error", () => { + const str = z.string({ + invalid_type_error: "Invalid name", + // required_error: "Name is required", + }); + + const result2 = str.safeParse(undefined); + expect(result2.success).toEqual(false); + if (!result2.success) { + expect(result2.error.issues[0].message).toEqual("Required"); + } +}); + +test("invalid and required and errorMap", () => { + expect(() => { + return z.string({ + invalid_type_error: "Invalid name", + required_error: "Name is required", + errorMap: () => ({ message: "OVERRIDE" }), + }); + }).toThrow(); +}); + +test("strict error message", () => { + const errorMsg = "Invalid object"; + const obj = z.object({ x: z.string() }).strict(errorMsg); + const result = obj.safeParse({ x: "a", y: "b" }); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].message).toEqual(errorMsg); + } +}); + +test("enum error message, invalid enum elementstring", () => { + try { + z.enum(["Tuna", "Trout"]).parse("Salmon"); + } catch (err) { + const zerr: z.ZodError = err as any; + expect(zerr.issues.length).toEqual(1); + expect(zerr.issues[0].message).toEqual("Invalid enum value. Expected 'Tuna' | 'Trout', received 'Salmon'"); + } +}); + +test("enum error message, invalid type", () => { + try { + z.enum(["Tuna", "Trout"]).parse(12); + } catch (err) { + const zerr: z.ZodError = err as any; + expect(zerr.issues.length).toEqual(1); + expect(zerr.issues[0].message).toEqual("Expected 'Tuna' | 'Trout', received number"); + } +}); + +test("nativeEnum default error message", () => { + enum Fish { + Tuna = "Tuna", + Trout = "Trout", + } + try { + z.nativeEnum(Fish).parse("Salmon"); + } catch (err) { + const zerr: z.ZodError = err as any; + expect(zerr.issues.length).toEqual(1); + expect(zerr.issues[0].message).toEqual("Invalid enum value. Expected 'Tuna' | 'Trout', received 'Salmon'"); + } +}); + +test("literal default error message", () => { + try { + z.literal("Tuna").parse("Trout"); + } catch (err) { + const zerr: z.ZodError = err as any; + expect(zerr.issues.length).toEqual(1); + expect(zerr.issues[0].message).toEqual(`Invalid literal value, expected "Tuna"`); + } +}); + +test("literal bigint default error message", () => { + try { + z.literal(BigInt(12)).parse(BigInt(13)); + } catch (err) { + const zerr: z.ZodError = err as any; + expect(zerr.issues.length).toEqual(1); + expect(zerr.issues[0].message).toEqual(`Invalid literal value, expected "12"`); + } +}); + +test("enum with message returns the custom error message", () => { + const schema = z.enum(["apple", "banana"], { + message: "the value provided is invalid", + }); + + const result1 = schema.safeParse("berries"); + expect(result1.success).toEqual(false); + if (!result1.success) { + expect(result1.error.issues[0].message).toEqual("the value provided is invalid"); + } + + const result2 = schema.safeParse(undefined); + expect(result2.success).toEqual(false); + if (!result2.success) { + expect(result2.error.issues[0].message).toEqual("the value provided is invalid"); + } + + const result3 = schema.safeParse("banana"); + expect(result3.success).toEqual(true); + + const result4 = schema.safeParse(null); + expect(result4.success).toEqual(false); + if (!result4.success) { + expect(result4.error.issues[0].message).toEqual("the value provided is invalid"); + } +}); + +test("when the message is falsy, it is used as is provided", () => { + const schema = z.string().max(1, { message: "" }); + const result = schema.safeParse("asdf"); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].message).toEqual(""); + } +}); + +// test("dont short circuit on continuable errors", () => { +// const user = z +// .object({ +// password: z.string().min(6), +// confirm: z.string(), +// }) +// .refine((data) => data.password === data.confirm, { +// message: "Passwords don't match", +// path: ["confirm"], +// }); +// const result = user.safeParse({ password: "asdf", confirm: "qwer" }); +// if (!result.success) { +// expect(result.error.issues.length).toEqual(2); +// } +// }); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/firstparty.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/firstparty.test.ts new file mode 100644 index 0000000..017a1c1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/firstparty.test.ts @@ -0,0 +1,87 @@ +// @ts-ignore TS6133 +import { test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("first party switch", () => { + const myType = z.string() as z.ZodFirstPartySchemaTypes; + const def = myType._def; + + switch (def.typeName) { + case z.ZodFirstPartyTypeKind.ZodString: + break; + case z.ZodFirstPartyTypeKind.ZodNumber: + break; + case z.ZodFirstPartyTypeKind.ZodNaN: + break; + case z.ZodFirstPartyTypeKind.ZodBigInt: + break; + case z.ZodFirstPartyTypeKind.ZodBoolean: + break; + case z.ZodFirstPartyTypeKind.ZodDate: + break; + case z.ZodFirstPartyTypeKind.ZodUndefined: + break; + case z.ZodFirstPartyTypeKind.ZodNull: + break; + case z.ZodFirstPartyTypeKind.ZodAny: + break; + case z.ZodFirstPartyTypeKind.ZodUnknown: + break; + case z.ZodFirstPartyTypeKind.ZodNever: + break; + case z.ZodFirstPartyTypeKind.ZodVoid: + break; + case z.ZodFirstPartyTypeKind.ZodArray: + break; + case z.ZodFirstPartyTypeKind.ZodObject: + break; + case z.ZodFirstPartyTypeKind.ZodUnion: + break; + case z.ZodFirstPartyTypeKind.ZodDiscriminatedUnion: + break; + case z.ZodFirstPartyTypeKind.ZodIntersection: + break; + case z.ZodFirstPartyTypeKind.ZodTuple: + break; + case z.ZodFirstPartyTypeKind.ZodRecord: + break; + case z.ZodFirstPartyTypeKind.ZodMap: + break; + case z.ZodFirstPartyTypeKind.ZodSet: + break; + case z.ZodFirstPartyTypeKind.ZodFunction: + break; + case z.ZodFirstPartyTypeKind.ZodLazy: + break; + case z.ZodFirstPartyTypeKind.ZodLiteral: + break; + case z.ZodFirstPartyTypeKind.ZodEnum: + break; + case z.ZodFirstPartyTypeKind.ZodEffects: + break; + case z.ZodFirstPartyTypeKind.ZodNativeEnum: + break; + case z.ZodFirstPartyTypeKind.ZodOptional: + break; + case z.ZodFirstPartyTypeKind.ZodNullable: + break; + case z.ZodFirstPartyTypeKind.ZodDefault: + break; + case z.ZodFirstPartyTypeKind.ZodCatch: + break; + case z.ZodFirstPartyTypeKind.ZodPromise: + break; + case z.ZodFirstPartyTypeKind.ZodBranded: + break; + case z.ZodFirstPartyTypeKind.ZodPipeline: + break; + case z.ZodFirstPartyTypeKind.ZodSymbol: + break; + case z.ZodFirstPartyTypeKind.ZodReadonly: + break; + default: + util.assertNever(def); + } +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/firstpartyschematypes.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/firstpartyschematypes.test.ts new file mode 100644 index 0000000..ad397d8 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/firstpartyschematypes.test.ts @@ -0,0 +1,21 @@ +// @ts-ignore TS6133 +import { test } from "vitest"; + +import type { ZodFirstPartySchemaTypes, ZodFirstPartyTypeKind } from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("Identify missing [ZodFirstPartySchemaTypes]", () => { + type ZodFirstPartySchemaForType = ZodFirstPartySchemaTypes extends infer Schema + ? Schema extends { _def: { typeName: T } } + ? Schema + : never + : never; + type ZodMappedTypes = { + [key in ZodFirstPartyTypeKind]: ZodFirstPartySchemaForType; + }; + type ZodFirstPartySchemaTypesMissingFromUnion = keyof { + [key in keyof ZodMappedTypes as ZodMappedTypes[key] extends { _def: never } ? key : never]: unknown; + }; + + util.assertEqual(true); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/function.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/function.test.ts new file mode 100644 index 0000000..9a9e193 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/function.test.ts @@ -0,0 +1,261 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +const args1 = z.tuple([z.string()]); +const returns1 = z.number(); +const func1 = z.function(args1, returns1); + +test("function parsing", () => { + const parsed = func1.parse((arg: any) => arg.length); + const result = parsed("asdf"); + expect(result).toBe(4); +}); + +test("parsed function fail 1", () => { + const parsed = func1.parse((x: string) => x); + expect(() => parsed("asdf")).toThrow(); +}); + +test("parsed function fail 2", () => { + const parsed = func1.parse((x: string) => x); + expect(() => parsed(13 as any)).toThrow(); +}); + +test("function inference 1", () => { + type func1 = z.TypeOf; + util.assertEqual number>(true); +}); + +test("method parsing", () => { + const methodObject = z.object({ + property: z.number(), + method: z.function().args(z.string()).returns(z.number()), + }); + const methodInstance = { + property: 3, + method: function (s: string) { + return s.length + this.property; + }, + }; + const parsed = methodObject.parse(methodInstance); + expect(parsed.method("length=8")).toBe(11); // 8 length + 3 property +}); + +test("async method parsing", async () => { + const methodObject = z.object({ + property: z.number(), + method: z.function().args(z.string()).returns(z.promise(z.number())), + }); + const methodInstance = { + property: 3, + method: async function (s: string) { + return s.length + this.property; + }, + }; + const parsed = methodObject.parse(methodInstance); + expect(await parsed.method("length=8")).toBe(11); // 8 length + 3 property +}); + +test("args method", () => { + const t1 = z.function(); + type t1 = z.infer; + util.assertEqual unknown>(true); + + const t2 = t1.args(z.string()); + type t2 = z.infer; + util.assertEqual unknown>(true); + + const t3 = t2.returns(z.boolean()); + type t3 = z.infer; + util.assertEqual boolean>(true); +}); + +const args2 = z.tuple([ + z.object({ + f1: z.number(), + f2: z.string().nullable(), + f3: z.array(z.boolean().optional()).optional(), + }), +]); +const returns2 = z.union([z.string(), z.number()]); + +const func2 = z.function(args2, returns2); + +test("function inference 2", () => { + type func2 = z.TypeOf; + util.assertEqual< + func2, + (arg: { + f1: number; + f2: string | null; + f3?: (boolean | undefined)[] | undefined; + }) => string | number + >(true); +}); + +test("valid function run", () => { + const validFunc2Instance = func2.validate((_x) => { + return "adf" as any; + }); + + const checker = () => { + validFunc2Instance({ + f1: 21, + f2: "asdf", + f3: [true, false], + }); + }; + + checker(); +}); + +test("input validation error", () => { + const invalidFuncInstance = func2.validate((_x) => { + return "adf" as any; + }); + + const checker = () => { + invalidFuncInstance("Invalid_input" as any); + }; + + expect(checker).toThrow(); +}); + +test("output validation error", () => { + const invalidFuncInstance = func2.validate((_x) => { + return ["this", "is", "not", "valid", "output"] as any; + }); + + const checker = () => { + invalidFuncInstance({ + f1: 21, + f2: "asdf", + f3: [true, false], + }); + }; + + expect(checker).toThrow(); +}); + +z.function(z.tuple([z.string()])).args()._def.args; + +test("special function error codes", () => { + const checker = z.function(z.tuple([z.string()]), z.boolean()).implement((arg) => { + return arg.length as any; + }); + try { + checker("12" as any); + } catch (err) { + const zerr = err as z.ZodError; + const first = zerr.issues[0]; + if (first.code !== z.ZodIssueCode.invalid_return_type) throw new Error(); + + expect(first.returnTypeError).toBeInstanceOf(z.ZodError); + } + + try { + checker(12 as any); + } catch (err) { + const zerr = err as z.ZodError; + const first = zerr.issues[0]; + if (first.code !== z.ZodIssueCode.invalid_arguments) throw new Error(); + expect(first.argumentsError).toBeInstanceOf(z.ZodError); + } +}); + +test("function with async refinements", async () => { + const func = z + .function() + .args(z.string().refine(async (val) => val.length > 10)) + .returns(z.promise(z.number().refine(async (val) => val > 10))) + .implement(async (val) => { + return val.length; + }); + const results = []; + try { + await func("asdfasdf"); + results.push("success"); + } catch (_err) { + results.push("fail"); + } + try { + await func("asdflkjasdflkjsf"); + results.push("success"); + } catch (_err) { + results.push("fail"); + } + + expect(results).toEqual(["fail", "success"]); +}); + +test("non async function with async refinements should fail", async () => { + const func = z + .function() + .args(z.string().refine(async (val) => val.length > 10)) + .returns(z.number().refine(async (val) => val > 10)) + .implement((val) => { + return val.length; + }); + + const results = []; + try { + await func("asdasdfasdffasdf"); + results.push("success"); + } catch (_err) { + results.push("fail"); + } + + expect(results).toEqual(["fail"]); +}); + +test("allow extra parameters", () => { + const maxLength5 = z + .function() + .args(z.string()) + .returns(z.boolean()) + .implement((str, _arg, _qewr) => { + return str.length <= 5; + }); + + const filteredList = ["apple", "orange", "pear", "banana", "strawberry"].filter(maxLength5); + expect(filteredList.length).toEqual(2); +}); + +test("params and returnType getters", () => { + const func = z.function().args(z.string()).returns(z.string()); + + const paramResult = func.parameters().items[0].parse("asdf"); + expect(paramResult).toBe("asdf"); + + const returnResult = func.returnType().parse("asdf"); + expect(returnResult).toBe("asdf"); +}); + +test("inference with transforms", () => { + const funcSchema = z + .function() + .args(z.string().transform((val) => val.length)) + .returns(z.object({ val: z.number() })); + const myFunc = funcSchema.implement((val) => { + return { val, extra: "stuff" }; + }); + myFunc("asdf"); + + util.assertEqual { val: number; extra: string }>(true); +}); + +test("fallback to OuterTypeOfFunction", () => { + const funcSchema = z + .function() + .args(z.string().transform((val) => val.length)) + .returns(z.object({ arg: z.number() }).transform((val) => val.arg)); + + const myFunc = funcSchema.implement((val) => { + return { arg: val, arg2: false }; + }); + + util.assertEqual number>(true); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/generics.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/generics.test.ts new file mode 100644 index 0000000..e0af470 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/generics.test.ts @@ -0,0 +1,48 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("generics", () => { + async function stripOuter(schema: TData, data: unknown) { + return z + .object({ + nested: schema, // as z.ZodTypeAny, + }) + .transform((data) => { + return data.nested!; + }) + .parse({ nested: data }); + } + + const result = stripOuter(z.object({ a: z.string() }), { a: "asdf" }); + util.assertEqual>(true); +}); + +// test("assignability", () => { +// const createSchemaAndParse = ( +// key: K, +// valueSchema: VS, +// data: unknown +// ) => { +// const schema = z.object({ +// [key]: valueSchema, +// } as { [k in K]: VS }); +// return { [key]: valueSchema }; +// const parsed = schema.parse(data); +// return parsed; +// // const inferred: z.infer> = parsed; +// // return inferred; +// }; +// const parsed = createSchemaAndParse("foo", z.string(), { foo: "" }); +// util.assertEqual(true); +// }); + +test("nested no undefined", () => { + const inner = z.string().or(z.array(z.string())); + const outer = z.object({ inner }); + type outerSchema = z.infer; + z.util.assertEqual(true); + expect(outer.safeParse({ inner: undefined }).success).toEqual(false); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/instanceof.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/instanceof.test.ts new file mode 100644 index 0000000..de66f3f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/instanceof.test.ts @@ -0,0 +1,37 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("instanceof", async () => { + class Test {} + class Subtest extends Test {} + abstract class AbstractBar { + constructor(public val: string) {} + } + class Bar extends AbstractBar {} + + const TestSchema = z.instanceof(Test); + const SubtestSchema = z.instanceof(Subtest); + const AbstractSchema = z.instanceof(AbstractBar); + const BarSchema = z.instanceof(Bar); + + TestSchema.parse(new Test()); + TestSchema.parse(new Subtest()); + SubtestSchema.parse(new Subtest()); + AbstractSchema.parse(new Bar("asdf")); + const bar = BarSchema.parse(new Bar("asdf")); + expect(bar.val).toEqual("asdf"); + + await expect(() => SubtestSchema.parse(new Test())).toThrow(/Input not instance of Subtest/); + await expect(() => TestSchema.parse(12)).toThrow(/Input not instance of Test/); + + util.assertEqual>(true); +}); + +test("instanceof fatal", () => { + const schema = z.instanceof(Date).refine((d) => d.toString()); + const res = schema.safeParse(null); + expect(res.success).toBe(false); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/intersection.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/intersection.test.ts new file mode 100644 index 0000000..6d7936c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/intersection.test.ts @@ -0,0 +1,110 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +test("object intersection", () => { + const BaseTeacher = z.object({ + subjects: z.array(z.string()), + }); + const HasID = z.object({ id: z.string() }); + + const Teacher = z.intersection(BaseTeacher.passthrough(), HasID); // BaseTeacher.merge(HasID); + const data = { + subjects: ["math"], + id: "asdfasdf", + }; + expect(Teacher.parse(data)).toEqual(data); + expect(() => Teacher.parse({ subject: data.subjects })).toThrow(); + expect(Teacher.parse({ ...data, extra: 12 })).toEqual({ ...data, extra: 12 }); + + expect(() => z.intersection(BaseTeacher.strict(), HasID).parse({ ...data, extra: 12 })).toThrow(); +}); + +test("deep intersection", () => { + const Animal = z.object({ + properties: z.object({ + is_animal: z.boolean(), + }), + }); + const Cat = z + .object({ + properties: z.object({ + jumped: z.boolean(), + }), + }) + .and(Animal); + + type _Cat = z.infer; + // const cat:Cat = 'asdf' as any; + const cat = Cat.parse({ properties: { is_animal: true, jumped: true } }); + expect(cat.properties).toEqual({ is_animal: true, jumped: true }); +}); + +test("deep intersection of arrays", async () => { + const Author = z.object({ + posts: z.array( + z.object({ + post_id: z.number(), + }) + ), + }); + const Registry = z + .object({ + posts: z.array( + z.object({ + title: z.string(), + }) + ), + }) + .and(Author); + + const posts = [ + { post_id: 1, title: "Novels" }, + { post_id: 2, title: "Fairy tales" }, + ]; + const cat = Registry.parse({ posts }); + expect(cat.posts).toEqual(posts); + const asyncCat = await Registry.parseAsync({ posts }); + expect(asyncCat.posts).toEqual(posts); +}); + +test("invalid intersection types", async () => { + const numberIntersection = z.intersection( + z.number(), + z.number().transform((x) => x + 1) + ); + + const syncResult = numberIntersection.safeParse(1234); + expect(syncResult.success).toEqual(false); + if (!syncResult.success) { + expect(syncResult.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_intersection_types); + } + + const asyncResult = await numberIntersection.spa(1234); + expect(asyncResult.success).toEqual(false); + if (!asyncResult.success) { + expect(asyncResult.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_intersection_types); + } +}); + +test("invalid array merge", async () => { + const stringArrInt = z.intersection( + z.string().array(), + z + .string() + .array() + .transform((val) => [...val, "asdf"]) + ); + const syncResult = stringArrInt.safeParse(["asdf", "qwer"]); + expect(syncResult.success).toEqual(false); + if (!syncResult.success) { + expect(syncResult.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_intersection_types); + } + + const asyncResult = await stringArrInt.spa(["asdf", "qwer"]); + expect(asyncResult.success).toEqual(false); + if (!asyncResult.success) { + expect(asyncResult.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_intersection_types); + } +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/language-server.source.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/language-server.source.ts new file mode 100644 index 0000000..cbe818b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/language-server.source.ts @@ -0,0 +1,76 @@ +import * as z from "zod/v3"; + +export const filePath = __filename; + +// z.object() + +export const Test = z.object({ + f1: z.number(), +}); + +export type Test = z.infer; + +export const instanceOfTest: Test = { + f1: 1, +}; + +// z.object().merge() + +export const TestMerge = z + .object({ + f2: z.string().optional(), + }) + .merge(Test); + +export type TestMerge = z.infer; + +export const instanceOfTestMerge: TestMerge = { + f1: 1, + f2: "string", +}; + +// z.union() + +export const TestUnion = z.union([ + z.object({ + f2: z.string().optional(), + }), + Test, +]); + +export type TestUnion = z.infer; + +export const instanceOfTestUnion: TestUnion = { + f1: 1, + f2: "string", +}; + +// z.object().partial() + +export const TestPartial = Test.partial(); + +export type TestPartial = z.infer; + +export const instanceOfTestPartial: TestPartial = { + f1: 1, +}; + +// z.object().pick() + +export const TestPick = TestMerge.pick({ f1: true }); + +export type TestPick = z.infer; + +export const instanceOfTestPick: TestPick = { + f1: 1, +}; + +// z.object().omit() + +export const TestOmit = TestMerge.omit({ f2: true }); + +export type TestOmit = z.infer; + +export const instanceOfTestOmit: TestOmit = { + f1: 1, +}; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/language-server.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/language-server.test.ts new file mode 100644 index 0000000..851fdc4 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/language-server.test.ts @@ -0,0 +1,207 @@ +import { test } from "vitest"; +// import path from "path"; +// import { Node, Project, SyntaxKind } from "ts-morph"; + +// import { filePath } from "./language-server.source"; + +// The following tool is helpful for understanding the TypeScript AST associated with these tests: +// https://ts-ast-viewer.com/ (just copy the contents of language-server.source into the viewer) + +test("", () => {}); +// describe("Executing Go To Definition (and therefore Find Usages and Rename Refactoring) using an IDE works on inferred object properties", () => { +// // Compile file developmentEnvironment.source +// const project = new Project({ +// tsConfigFilePath: path.join(__dirname, "..", "..", "tsconfig.json"), +// skipAddingFilesFromTsConfig: true, +// }); +// const sourceFile = project.addSourceFileAtPath(filePath); + +// test("works for object properties inferred from z.object()", () => { +// // Find usage of Test.f1 property +// const instanceVariable = +// sourceFile.getVariableDeclarationOrThrow("instanceOfTest"); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of Test.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// // test("works for first object properties inferred from z.object().merge()", () => { +// // // Find usage of TestMerge.f1 property +// // const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// // "instanceOfTestMerge" +// // ); +// // const propertyBeingAssigned = getPropertyBeingAssigned( +// // instanceVariable, +// // "f1" +// // ); + +// // // Find definition of TestMerge.f1 property +// // const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// // const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// // SyntaxKind.VariableDeclaration +// // ); + +// // // Assert that find definition returned the Zod definition of Test +// // expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// // expect(parentOfProperty?.getName()).toEqual("Test"); +// // }); + +// // test("works for second object properties inferred from z.object().merge()", () => { +// // // Find usage of TestMerge.f2 property +// // const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// // "instanceOfTestMerge" +// // ); +// // const propertyBeingAssigned = getPropertyBeingAssigned( +// // instanceVariable, +// // "f2" +// // ); + +// // // Find definition of TestMerge.f2 property +// // const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// // const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// // SyntaxKind.VariableDeclaration +// // ); + +// // // Assert that find definition returned the Zod definition of TestMerge +// // expect(definitionOfProperty?.getText()).toEqual( +// // "f2: z.string().optional()" +// // ); +// // expect(parentOfProperty?.getName()).toEqual("TestMerge"); +// // }); + +// test("works for first object properties inferred from z.union()", () => { +// // Find usage of TestUnion.f1 property +// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// "instanceOfTestUnion" +// ); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestUnion.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// test("works for second object properties inferred from z.union()", () => { +// // Find usage of TestUnion.f2 property +// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// "instanceOfTestUnion" +// ); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f2" +// ); + +// // Find definition of TestUnion.f2 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of TestUnion +// expect(definitionOfProperty?.getText()).toEqual( +// "f2: z.string().optional()" +// ); +// expect(parentOfProperty?.getName()).toEqual("TestUnion"); +// }); + +// test("works for object properties inferred from z.object().partial()", () => { +// // Find usage of TestPartial.f1 property +// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// "instanceOfTestPartial" +// ); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestPartial.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// test("works for object properties inferred from z.object().pick()", () => { +// // Find usage of TestPick.f1 property +// const instanceVariable = +// sourceFile.getVariableDeclarationOrThrow("instanceOfTestPick"); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestPick.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// test("works for object properties inferred from z.object().omit()", () => { +// // Find usage of TestOmit.f1 property +// const instanceVariable = +// sourceFile.getVariableDeclarationOrThrow("instanceOfTestOmit"); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestOmit.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); +// }); + +// const getPropertyBeingAssigned = (node: Node, name: string) => { +// const propertyAssignment = node.forEachDescendant((descendent) => +// Node.isPropertyAssignment(descendent) && descendent.getName() == name +// ? descendent +// : undefined +// ); + +// if (propertyAssignment == null) +// fail(`Could not find property assignment with name ${name}`); + +// const propertyLiteral = propertyAssignment.getFirstDescendantByKind( +// SyntaxKind.Identifier +// ); + +// if (propertyLiteral == null) +// fail(`Could not find property literal with name ${name}`); + +// return propertyLiteral; +// }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/literal.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/literal.test.ts new file mode 100644 index 0000000..d166a24 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/literal.test.ts @@ -0,0 +1,36 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +const literalTuna = z.literal("tuna"); +const literalFortyTwo = z.literal(42); +const literalTrue = z.literal(true); + +const terrificSymbol = Symbol("terrific"); +const literalTerrificSymbol = z.literal(terrificSymbol); + +test("passing validations", () => { + literalTuna.parse("tuna"); + literalFortyTwo.parse(42); + literalTrue.parse(true); + literalTerrificSymbol.parse(terrificSymbol); +}); + +test("failing validations", () => { + expect(() => literalTuna.parse("shark")).toThrow(); + expect(() => literalFortyTwo.parse(43)).toThrow(); + expect(() => literalTrue.parse(false)).toThrow(); + expect(() => literalTerrificSymbol.parse(Symbol("terrific"))).toThrow(); +}); + +test("invalid_literal should have `received` field with data", () => { + const data = "shark"; + const result = literalTuna.safeParse(data); + if (!result.success) { + const issue = result.error.issues[0]; + if (issue.code === "invalid_literal") { + expect(issue.received).toBe(data); + } + } +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/map.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/map.test.ts new file mode 100644 index 0000000..9471819 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/map.test.ts @@ -0,0 +1,110 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { ZodIssueCode } from "zod/v3"; +import { util } from "../helpers/util.js"; + +const stringMap = z.map(z.string(), z.string()); +type stringMap = z.infer; + +test("type inference", () => { + util.assertEqual>(true); +}); + +test("valid parse", () => { + const result = stringMap.safeParse( + new Map([ + ["first", "foo"], + ["second", "bar"], + ]) + ); + expect(result.success).toEqual(true); + if (result.success) { + expect(result.data.has("first")).toEqual(true); + expect(result.data.has("second")).toEqual(true); + expect(result.data.get("first")).toEqual("foo"); + expect(result.data.get("second")).toEqual("bar"); + } +}); + +test("valid parse async", async () => { + const result = await stringMap.spa( + new Map([ + ["first", "foo"], + ["second", "bar"], + ]) + ); + expect(result.success).toEqual(true); + if (result.success) { + expect(result.data.has("first")).toEqual(true); + expect(result.data.has("second")).toEqual(true); + expect(result.data.get("first")).toEqual("foo"); + expect(result.data.get("second")).toEqual("bar"); + } +}); + +test("throws when a Set is given", () => { + const result = stringMap.safeParse(new Set([])); + expect(result.success).toEqual(false); + if (result.success === false) { + expect(result.error.issues.length).toEqual(1); + expect(result.error.issues[0].code).toEqual(ZodIssueCode.invalid_type); + } +}); + +test("throws when the given map has invalid key and invalid input", () => { + const result = stringMap.safeParse(new Map([[42, Symbol()]])); + expect(result.success).toEqual(false); + if (result.success === false) { + expect(result.error.issues.length).toEqual(2); + expect(result.error.issues[0].code).toEqual(ZodIssueCode.invalid_type); + expect(result.error.issues[0].path).toEqual([0, "key"]); + expect(result.error.issues[1].code).toEqual(ZodIssueCode.invalid_type); + expect(result.error.issues[1].path).toEqual([0, "value"]); + } +}); + +test("throws when the given map has multiple invalid entries", () => { + // const result = stringMap.safeParse(new Map([[42, Symbol()]])); + + const result = stringMap.safeParse( + new Map([ + [1, "foo"], + ["bar", 2], + ] as [any, any][]) as Map + ); + + // const result = stringMap.safeParse(new Map([[42, Symbol()]])); + expect(result.success).toEqual(false); + if (result.success === false) { + expect(result.error.issues.length).toEqual(2); + expect(result.error.issues[0].code).toEqual(ZodIssueCode.invalid_type); + expect(result.error.issues[0].path).toEqual([0, "key"]); + expect(result.error.issues[1].code).toEqual(ZodIssueCode.invalid_type); + expect(result.error.issues[1].path).toEqual([1, "value"]); + } +}); + +test("dirty", async () => { + const map = z.map( + z.string().refine((val) => val === val.toUpperCase(), { + message: "Keys must be uppercase", + }), + z.string() + ); + const result = await map.spa( + new Map([ + ["first", "foo"], + ["second", "bar"], + ]) + ); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues.length).toEqual(2); + expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.custom); + expect(result.error.issues[0].message).toEqual("Keys must be uppercase"); + expect(result.error.issues[1].code).toEqual(z.ZodIssueCode.custom); + expect(result.error.issues[1].message).toEqual("Keys must be uppercase"); + } +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/masking.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/masking.test.ts new file mode 100644 index 0000000..63817e2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/masking.test.ts @@ -0,0 +1,4 @@ +// @ts-ignore TS6133 +import { test } from "vitest"; + +test("masking test", () => {}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/mocker.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/mocker.test.ts new file mode 100644 index 0000000..3a2506b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/mocker.test.ts @@ -0,0 +1,19 @@ +// @ts-ignore TS6133 +import { test } from "vitest"; + +import { Mocker } from "./Mocker.js"; + +test("mocker", () => { + const mocker = new Mocker(); + mocker.string; + mocker.number; + mocker.boolean; + mocker.null; + mocker.undefined; + mocker.stringOptional; + mocker.stringNullable; + mocker.numberOptional; + mocker.numberNullable; + mocker.booleanOptional; + mocker.booleanNullable; +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nan.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nan.test.ts new file mode 100644 index 0000000..ce1214e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nan.test.ts @@ -0,0 +1,24 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +const schema = z.nan(); + +test("passing validations", () => { + const result1 = schema.parse(Number.NaN); + expect(Number.isNaN(result1)).toBe(true); + + const result2 = schema.parse(Number("Not a number")); + expect(Number.isNaN(result2)).toBe(true); +}); + +test("failing validations", () => { + expect(() => schema.parse(5)).toThrow(); + expect(() => schema.parse("John")).toThrow(); + expect(() => schema.parse(true)).toThrow(); + expect(() => schema.parse(null)).toThrow(); + expect(() => schema.parse(undefined)).toThrow(); + expect(() => schema.parse({})).toThrow(); + expect(() => schema.parse([])).toThrow(); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nativeEnum.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nativeEnum.test.ts new file mode 100644 index 0000000..61eb37a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nativeEnum.test.ts @@ -0,0 +1,87 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("nativeEnum test with consts", () => { + const Fruits: { Apple: "apple"; Banana: "banana" } = { + Apple: "apple", + Banana: "banana", + }; + const fruitEnum = z.nativeEnum(Fruits); + type fruitEnum = z.infer; + fruitEnum.parse("apple"); + fruitEnum.parse("banana"); + fruitEnum.parse(Fruits.Apple); + fruitEnum.parse(Fruits.Banana); + util.assertEqual(true); +}); + +test("nativeEnum test with real enum", () => { + enum Fruits { + Apple = "apple", + Banana = "banana", + } + // @ts-ignore + const fruitEnum = z.nativeEnum(Fruits); + type fruitEnum = z.infer; + fruitEnum.parse("apple"); + fruitEnum.parse("banana"); + fruitEnum.parse(Fruits.Apple); + fruitEnum.parse(Fruits.Banana); + util.assertIs(true); +}); + +test("nativeEnum test with const with numeric keys", () => { + const FruitValues = { + Apple: 10, + Banana: 20, + // @ts-ignore + } as const; + const fruitEnum = z.nativeEnum(FruitValues); + type fruitEnum = z.infer; + fruitEnum.parse(10); + fruitEnum.parse(20); + fruitEnum.parse(FruitValues.Apple); + fruitEnum.parse(FruitValues.Banana); + util.assertEqual(true); +}); + +test("from enum", () => { + enum Fruits { + Cantaloupe = 0, + Apple = "apple", + Banana = "banana", + } + + const FruitEnum = z.nativeEnum(Fruits as any); + type _FruitEnum = z.infer; + FruitEnum.parse(Fruits.Cantaloupe); + FruitEnum.parse(Fruits.Apple); + FruitEnum.parse("apple"); + FruitEnum.parse(0); + expect(() => FruitEnum.parse(1)).toThrow(); + expect(() => FruitEnum.parse("Apple")).toThrow(); + expect(() => FruitEnum.parse("Cantaloupe")).toThrow(); +}); + +test("from const", () => { + const Greek = { + Alpha: "a", + Beta: "b", + Gamma: 3, + // @ts-ignore + } as const; + + const GreekEnum = z.nativeEnum(Greek); + type _GreekEnum = z.infer; + GreekEnum.parse("a"); + GreekEnum.parse("b"); + GreekEnum.parse(3); + expect(() => GreekEnum.parse("v")).toThrow(); + expect(() => GreekEnum.parse("Alpha")).toThrow(); + expect(() => GreekEnum.parse(2)).toThrow(); + + expect(GreekEnum.enum.Alpha).toEqual("a"); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nullable.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nullable.test.ts new file mode 100644 index 0000000..90c1eed --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/nullable.test.ts @@ -0,0 +1,42 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +function checkErrors(a: z.ZodTypeAny, bad: any) { + let expected: any; + try { + a.parse(bad); + } catch (error) { + expected = (error as z.ZodError).formErrors; + } + try { + a.nullable().parse(bad); + } catch (error) { + expect((error as z.ZodError).formErrors).toEqual(expected); + } +} + +test("Should have error messages appropriate for the underlying type", () => { + checkErrors(z.string().min(2), 1); + z.string().min(2).nullable().parse(null); + checkErrors(z.number().gte(2), 1); + z.number().gte(2).nullable().parse(null); + checkErrors(z.boolean(), ""); + z.boolean().nullable().parse(null); + checkErrors(z.null(), null); + z.null().nullable().parse(null); + checkErrors(z.null(), {}); + z.null().nullable().parse(null); + checkErrors(z.object({}), 1); + z.object({}).nullable().parse(null); + checkErrors(z.tuple([]), 1); + z.tuple([]).nullable().parse(null); + checkErrors(z.unknown(), 1); + z.unknown().nullable().parse(null); +}); + +test("unwrap", () => { + const unwrapped = z.string().nullable().unwrap(); + expect(unwrapped).toBeInstanceOf(z.ZodString); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/number.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/number.test.ts new file mode 100644 index 0000000..db3f73b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/number.test.ts @@ -0,0 +1,176 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +const gtFive = z.number().gt(5); +const gteFive = z.number().gte(-5).gte(5); +const minFive = z.number().min(0).min(5); +const ltFive = z.number().lte(10).lt(5); +const lteFive = z.number().lte(5); +const maxFive = z.number().max(10).max(5); +const intNum = z.number().int(); +const positive = z.number().positive(); +const negative = z.number().negative(); +const nonpositive = z.number().nonpositive(); +const nonnegative = z.number().nonnegative(); +const multipleOfFive = z.number().multipleOf(5); +const multipleOfNegativeFive = z.number().multipleOf(-5); +const finite = z.number().finite(); +const safe = z.number().safe(); +const stepPointOne = z.number().step(0.1); +const stepPointZeroZeroZeroOne = z.number().step(0.0001); +const stepSixPointFour = z.number().step(6.4); + +test("passing validations", () => { + z.number().parse(1); + z.number().parse(1.5); + z.number().parse(0); + z.number().parse(-1.5); + z.number().parse(-1); + z.number().parse(Number.POSITIVE_INFINITY); + z.number().parse(Number.NEGATIVE_INFINITY); + gtFive.parse(6); + gtFive.parse(Number.POSITIVE_INFINITY); + gteFive.parse(5); + gteFive.parse(Number.POSITIVE_INFINITY); + minFive.parse(5); + minFive.parse(Number.POSITIVE_INFINITY); + ltFive.parse(4); + ltFive.parse(Number.NEGATIVE_INFINITY); + lteFive.parse(5); + lteFive.parse(Number.NEGATIVE_INFINITY); + maxFive.parse(5); + maxFive.parse(Number.NEGATIVE_INFINITY); + intNum.parse(4); + positive.parse(1); + positive.parse(Number.POSITIVE_INFINITY); + negative.parse(-1); + negative.parse(Number.NEGATIVE_INFINITY); + nonpositive.parse(0); + nonpositive.parse(-1); + nonpositive.parse(Number.NEGATIVE_INFINITY); + nonnegative.parse(0); + nonnegative.parse(1); + nonnegative.parse(Number.POSITIVE_INFINITY); + multipleOfFive.parse(15); + multipleOfFive.parse(-15); + multipleOfNegativeFive.parse(-15); + multipleOfNegativeFive.parse(15); + finite.parse(123); + safe.parse(Number.MIN_SAFE_INTEGER); + safe.parse(Number.MAX_SAFE_INTEGER); + stepPointOne.parse(6); + stepPointOne.parse(6.1); + stepPointOne.parse(6.1); + stepSixPointFour.parse(12.8); + stepPointZeroZeroZeroOne.parse(3.01); +}); + +test("failing validations", () => { + expect(() => ltFive.parse(5)).toThrow(); + expect(() => lteFive.parse(6)).toThrow(); + expect(() => maxFive.parse(6)).toThrow(); + expect(() => gtFive.parse(5)).toThrow(); + expect(() => gteFive.parse(4)).toThrow(); + expect(() => minFive.parse(4)).toThrow(); + expect(() => intNum.parse(3.14)).toThrow(); + expect(() => positive.parse(0)).toThrow(); + expect(() => positive.parse(-1)).toThrow(); + expect(() => negative.parse(0)).toThrow(); + expect(() => negative.parse(1)).toThrow(); + expect(() => nonpositive.parse(1)).toThrow(); + expect(() => nonnegative.parse(-1)).toThrow(); + expect(() => multipleOfFive.parse(7.5)).toThrow(); + expect(() => multipleOfFive.parse(-7.5)).toThrow(); + expect(() => multipleOfNegativeFive.parse(-7.5)).toThrow(); + expect(() => multipleOfNegativeFive.parse(7.5)).toThrow(); + expect(() => finite.parse(Number.POSITIVE_INFINITY)).toThrow(); + expect(() => finite.parse(Number.NEGATIVE_INFINITY)).toThrow(); + expect(() => safe.parse(Number.MIN_SAFE_INTEGER - 1)).toThrow(); + expect(() => safe.parse(Number.MAX_SAFE_INTEGER + 1)).toThrow(); + + expect(() => stepPointOne.parse(6.11)).toThrow(); + expect(() => stepPointOne.parse(6.1000000001)).toThrow(); + expect(() => stepSixPointFour.parse(6.41)).toThrow(); +}); + +test("parse NaN", () => { + expect(() => z.number().parse(Number.NaN)).toThrow(); +}); + +test("min max getters", () => { + expect(z.number().minValue).toBeNull; + expect(ltFive.minValue).toBeNull; + expect(lteFive.minValue).toBeNull; + expect(maxFive.minValue).toBeNull; + expect(negative.minValue).toBeNull; + expect(nonpositive.minValue).toBeNull; + expect(intNum.minValue).toBeNull; + expect(multipleOfFive.minValue).toBeNull; + expect(finite.minValue).toBeNull; + expect(gtFive.minValue).toEqual(5); + expect(gteFive.minValue).toEqual(5); + expect(minFive.minValue).toEqual(5); + expect(minFive.min(10).minValue).toEqual(10); + expect(positive.minValue).toEqual(0); + expect(nonnegative.minValue).toEqual(0); + expect(safe.minValue).toEqual(Number.MIN_SAFE_INTEGER); + + expect(z.number().maxValue).toBeNull; + expect(gtFive.maxValue).toBeNull; + expect(gteFive.maxValue).toBeNull; + expect(minFive.maxValue).toBeNull; + expect(positive.maxValue).toBeNull; + expect(nonnegative.maxValue).toBeNull; + expect(intNum.minValue).toBeNull; + expect(multipleOfFive.minValue).toBeNull; + expect(finite.minValue).toBeNull; + expect(ltFive.maxValue).toEqual(5); + expect(lteFive.maxValue).toEqual(5); + expect(maxFive.maxValue).toEqual(5); + expect(maxFive.max(1).maxValue).toEqual(1); + expect(negative.maxValue).toEqual(0); + expect(nonpositive.maxValue).toEqual(0); + expect(safe.maxValue).toEqual(Number.MAX_SAFE_INTEGER); +}); + +test("int getter", () => { + expect(z.number().isInt).toEqual(false); + expect(z.number().multipleOf(1.5).isInt).toEqual(false); + expect(gtFive.isInt).toEqual(false); + expect(gteFive.isInt).toEqual(false); + expect(minFive.isInt).toEqual(false); + expect(positive.isInt).toEqual(false); + expect(nonnegative.isInt).toEqual(false); + expect(finite.isInt).toEqual(false); + expect(ltFive.isInt).toEqual(false); + expect(lteFive.isInt).toEqual(false); + expect(maxFive.isInt).toEqual(false); + expect(negative.isInt).toEqual(false); + expect(nonpositive.isInt).toEqual(false); + expect(safe.isInt).toEqual(false); + + expect(intNum.isInt).toEqual(true); + expect(multipleOfFive.isInt).toEqual(true); +}); + +test("finite getter", () => { + expect(z.number().isFinite).toEqual(false); + expect(gtFive.isFinite).toEqual(false); + expect(gteFive.isFinite).toEqual(false); + expect(minFive.isFinite).toEqual(false); + expect(positive.isFinite).toEqual(false); + expect(nonnegative.isFinite).toEqual(false); + expect(ltFive.isFinite).toEqual(false); + expect(lteFive.isFinite).toEqual(false); + expect(maxFive.isFinite).toEqual(false); + expect(negative.isFinite).toEqual(false); + expect(nonpositive.isFinite).toEqual(false); + + expect(finite.isFinite).toEqual(true); + expect(intNum.isFinite).toEqual(true); + expect(multipleOfFive.isFinite).toEqual(true); + expect(z.number().min(5).max(10).isFinite).toEqual(true); + expect(safe.isFinite).toEqual(true); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object-augmentation.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object-augmentation.test.ts new file mode 100644 index 0000000..964ea3d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object-augmentation.test.ts @@ -0,0 +1,29 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +test("object augmentation", () => { + const Animal = z + .object({ + species: z.string(), + }) + .augment({ + population: z.number(), + }); + // overwrites `species` + const ModifiedAnimal = Animal.augment({ + species: z.array(z.string()), + }); + ModifiedAnimal.parse({ + species: ["asd"], + population: 1324, + }); + + const bad = () => + ModifiedAnimal.parse({ + species: "asdf", + population: 1324, + } as any); + expect(bad).toThrow(); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object-in-es5-env.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object-in-es5-env.test.ts new file mode 100644 index 0000000..293ebf0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object-in-es5-env.test.ts @@ -0,0 +1,29 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +const RealSet = Set; +const RealMap = Map; +const RealDate = Date; + +test("doesn’t throw when Date is undefined", () => { + delete (globalThis as any).Date; + const result = z.object({}).safeParse({}); + expect(result.success).toEqual(true); + globalThis.Date = RealDate; +}); + +test("doesn’t throw when Set is undefined", () => { + delete (globalThis as any).Set; + const result = z.object({}).safeParse({}); + expect(result.success).toEqual(true); + globalThis.Set = RealSet; +}); + +test("doesn’t throw when Map is undefined", () => { + delete (globalThis as any).Map; + const result = z.object({}).safeParse({}); + expect(result.success).toEqual(true); + globalThis.Map = RealMap; +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object.test.ts new file mode 100644 index 0000000..fbb2673 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/object.test.ts @@ -0,0 +1,434 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +const Test = z.object({ + f1: z.number(), + f2: z.string().optional(), + f3: z.string().nullable(), + f4: z.array(z.object({ t: z.union([z.string(), z.boolean()]) })), +}); + +test("object type inference", () => { + type TestType = { + f1: number; + f2?: string | undefined; + f3: string | null; + f4: { t: string | boolean }[]; + }; + + util.assertEqual, TestType>(true); +}); + +test("unknown throw", () => { + const asdf: unknown = 35; + expect(() => Test.parse(asdf)).toThrow(); +}); + +test("shape() should return schema of particular key", () => { + const f1Schema = Test.shape.f1; + const f2Schema = Test.shape.f2; + const f3Schema = Test.shape.f3; + const f4Schema = Test.shape.f4; + + expect(f1Schema).toBeInstanceOf(z.ZodNumber); + expect(f2Schema).toBeInstanceOf(z.ZodOptional); + expect(f3Schema).toBeInstanceOf(z.ZodNullable); + expect(f4Schema).toBeInstanceOf(z.ZodArray); +}); + +test("correct parsing", () => { + Test.parse({ + f1: 12, + f2: "string", + f3: "string", + f4: [ + { + t: "string", + }, + ], + }); + + Test.parse({ + f1: 12, + f3: null, + f4: [ + { + t: false, + }, + ], + }); +}); + +test("incorrect #1", () => { + expect(() => Test.parse({} as any)).toThrow(); +}); + +test("nonstrict by default", () => { + z.object({ points: z.number() }).parse({ + points: 2314, + unknown: "asdf", + }); +}); + +const data = { + points: 2314, + unknown: "asdf", +}; + +test("strip by default", () => { + const val = z.object({ points: z.number() }).parse(data); + expect(val).toEqual({ points: 2314 }); +}); + +test("unknownkeys override", () => { + const val = z.object({ points: z.number() }).strict().passthrough().strip().nonstrict().parse(data); + + expect(val).toEqual(data); +}); + +test("passthrough unknown", () => { + const val = z.object({ points: z.number() }).passthrough().parse(data); + + expect(val).toEqual(data); +}); + +test("strip unknown", () => { + const val = z.object({ points: z.number() }).strip().parse(data); + + expect(val).toEqual({ points: 2314 }); +}); + +test("strict", () => { + const val = z.object({ points: z.number() }).strict().safeParse(data); + + expect(val.success).toEqual(false); +}); + +test("catchall inference", () => { + const o1 = z + .object({ + first: z.string(), + }) + .catchall(z.number()); + + const d1 = o1.parse({ first: "asdf", num: 1243 }); + util.assertEqual(true); + util.assertEqual(true); +}); + +test("catchall overrides strict", () => { + const o1 = z.object({ first: z.string().optional() }).strict().catchall(z.number()); + + // should run fine + // setting a catchall overrides the unknownKeys behavior + o1.parse({ + asdf: 1234, + }); + + // should only run catchall validation + // against unknown keys + o1.parse({ + first: "asdf", + asdf: 1234, + }); +}); + +test("catchall overrides strict", () => { + const o1 = z + .object({ + first: z.string(), + }) + .strict() + .catchall(z.number()); + + // should run fine + // setting a catchall overrides the unknownKeys behavior + o1.parse({ + first: "asdf", + asdf: 1234, + }); +}); + +test("test that optional keys are unset", () => { + const SNamedEntity = z.object({ + id: z.string(), + set: z.string().optional(), + unset: z.string().optional(), + }); + const result = SNamedEntity.parse({ + id: "asdf", + set: undefined, + }); + // eslint-disable-next-line ban/ban + expect(Object.keys(result)).toEqual(["id", "set"]); +}); + +test("test catchall parsing", async () => { + const result = z.object({ name: z.string() }).catchall(z.number()).parse({ name: "Foo", validExtraKey: 61 }); + + expect(result).toEqual({ name: "Foo", validExtraKey: 61 }); + + const result2 = z + .object({ name: z.string() }) + .catchall(z.number()) + .safeParse({ name: "Foo", validExtraKey: 61, invalid: "asdf" }); + + expect(result2.success).toEqual(false); +}); + +test("test nonexistent keys", async () => { + const Schema = z.union([z.object({ a: z.string() }), z.object({ b: z.number() })]); + const obj = { a: "A" }; + const result = await Schema.spa(obj); // Works with 1.11.10, breaks with 2.0.0-beta.21 + expect(result.success).toBe(true); +}); + +test("test async union", async () => { + const Schema2 = z.union([ + z.object({ + ty: z.string(), + }), + z.object({ + ty: z.number(), + }), + ]); + + const obj = { ty: "A" }; + const result = await Schema2.spa(obj); // Works with 1.11.10, breaks with 2.0.0-beta.21 + expect(result.success).toEqual(true); +}); + +test("test inferred merged type", async () => { + const asdf = z.object({ a: z.string() }).merge(z.object({ a: z.number() })); + type asdf = z.infer; + util.assertEqual(true); +}); + +test("inferred merged object type with optional properties", async () => { + const Merged = z + .object({ a: z.string(), b: z.string().optional() }) + .merge(z.object({ a: z.string().optional(), b: z.string() })); + type Merged = z.infer; + util.assertEqual(true); + // todo + // util.assertEqual(true); +}); + +test("inferred unioned object type with optional properties", async () => { + const Unioned = z.union([ + z.object({ a: z.string(), b: z.string().optional() }), + z.object({ a: z.string().optional(), b: z.string() }), + ]); + type Unioned = z.infer; + util.assertEqual(true); +}); + +test("inferred enum type", async () => { + const Enum = z.object({ a: z.string(), b: z.string().optional() }).keyof(); + + expect(Enum.Values).toEqual({ + a: "a", + b: "b", + }); + expect(Enum.enum).toEqual({ + a: "a", + b: "b", + }); + expect(Enum._def.values).toEqual(["a", "b"]); + type Enum = z.infer; + util.assertEqual(true); +}); + +test("inferred partial object type with optional properties", async () => { + const Partial = z.object({ a: z.string(), b: z.string().optional() }).partial(); + type Partial = z.infer; + util.assertEqual(true); +}); + +test("inferred picked object type with optional properties", async () => { + const Picked = z.object({ a: z.string(), b: z.string().optional() }).pick({ b: true }); + type Picked = z.infer; + util.assertEqual(true); +}); + +test("inferred type for unknown/any keys", () => { + const myType = z.object({ + anyOptional: z.any().optional(), + anyRequired: z.any(), + unknownOptional: z.unknown().optional(), + unknownRequired: z.unknown(), + }); + type myType = z.infer; + util.assertEqual< + myType, + { + anyOptional?: any; + anyRequired?: any; + unknownOptional?: unknown; + unknownRequired?: unknown; + } + >(true); +}); + +test("setKey", () => { + const base = z.object({ name: z.string() }); + const withNewKey = base.setKey("age", z.number()); + + type withNewKey = z.infer; + util.assertEqual(true); + withNewKey.parse({ name: "asdf", age: 1234 }); +}); + +test("strictcreate", async () => { + const strictObj = z.strictObject({ + name: z.string(), + }); + + const syncResult = strictObj.safeParse({ name: "asdf", unexpected: 13 }); + expect(syncResult.success).toEqual(false); + + const asyncResult = await strictObj.spa({ name: "asdf", unexpected: 13 }); + expect(asyncResult.success).toEqual(false); +}); + +test("object with refine", async () => { + const schema = z + .object({ + a: z.string().default("foo"), + b: z.number(), + }) + .refine(() => true); + expect(schema.parse({ b: 5 })).toEqual({ b: 5, a: "foo" }); + const result = await schema.parseAsync({ b: 5 }); + expect(result).toEqual({ b: 5, a: "foo" }); +}); + +test("intersection of object with date", async () => { + const schema = z.object({ + a: z.date(), + }); + expect(schema.and(schema).parse({ a: new Date(1637353595983) })).toEqual({ + a: new Date(1637353595983), + }); + const result = await schema.parseAsync({ a: new Date(1637353595983) }); + expect(result).toEqual({ a: new Date(1637353595983) }); +}); + +test("intersection of object with refine with date", async () => { + const schema = z + .object({ + a: z.date(), + }) + .refine(() => true); + expect(schema.and(schema).parse({ a: new Date(1637353595983) })).toEqual({ + a: new Date(1637353595983), + }); + const result = await schema.parseAsync({ a: new Date(1637353595983) }); + expect(result).toEqual({ a: new Date(1637353595983) }); +}); + +test("constructor key", () => { + const person = z + .object({ + name: z.string(), + }) + .strict(); + + expect(() => + person.parse({ + name: "bob dylan", + constructor: 61, + }) + ).toThrow(); +}); + +test("constructor key", () => { + const Example = z.object({ + prop: z.string(), + opt: z.number().optional(), + arr: z.string().array(), + }); + + type Example = z.infer; + util.assertEqual(true); +}); + +test("unknownkeys merging", () => { + // This one is "strict" + const schemaA = z + .object({ + a: z.string(), + }) + .strict(); + + // This one is "strip" + const schemaB = z + .object({ + b: z.string(), + }) + .catchall(z.string()); + + const mergedSchema = schemaA.merge(schemaB); + type mergedSchema = typeof mergedSchema; + util.assertEqual(true); + expect(mergedSchema._def.unknownKeys).toEqual("strip"); + + util.assertEqual(true); + expect(mergedSchema._def.catchall instanceof z.ZodString).toEqual(true); +}); + +const personToExtend = z.object({ + firstName: z.string(), + lastName: z.string(), +}); + +test("extend() should return schema with new key", () => { + const PersonWithNickname = personToExtend.extend({ nickName: z.string() }); + type PersonWithNickname = z.infer; + + const expected = { firstName: "f", nickName: "n", lastName: "l" }; + const actual = PersonWithNickname.parse(expected); + + expect(actual).toEqual(expected); + util.assertEqual(true); + util.assertEqual(true); +}); + +test("extend() should have power to override existing key", () => { + const PersonWithNumberAsLastName = personToExtend.extend({ + lastName: z.number(), + }); + type PersonWithNumberAsLastName = z.infer; + + const expected = { firstName: "f", lastName: 42 }; + const actual = PersonWithNumberAsLastName.parse(expected); + + expect(actual).toEqual(expected); + util.assertEqual(true); +}); + +test("passthrough index signature", () => { + const a = z.object({ a: z.string() }); + type a = z.infer; + util.assertEqual<{ a: string }, a>(true); + const b = a.passthrough(); + type b = z.infer; + util.assertEqual<{ a: string } & { [k: string]: unknown }, b>(true); +}); + +test("xor", () => { + type Without = { [P in Exclude]?: never }; + type XOR = T extends object ? (U extends object ? (Without & U) | (Without & T) : U) : T; + + type A = { name: string; a: number }; + type B = { name: string; b: number }; + type C = XOR; + type Outer = { data: C }; + + const _Outer: z.ZodType = z.object({ + data: z.union([z.object({ name: z.string(), a: z.number() }), z.object({ name: z.string(), b: z.number() })]), + }); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/optional.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/optional.test.ts new file mode 100644 index 0000000..016c954 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/optional.test.ts @@ -0,0 +1,42 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +function checkErrors(a: z.ZodTypeAny, bad: any) { + let expected: any; + try { + a.parse(bad); + } catch (error) { + expected = (error as z.ZodError).formErrors; + } + try { + a.optional().parse(bad); + } catch (error) { + expect((error as z.ZodError).formErrors).toEqual(expected); + } +} + +test("Should have error messages appropriate for the underlying type", () => { + checkErrors(z.string().min(2), 1); + z.string().min(2).optional().parse(undefined); + checkErrors(z.number().gte(2), 1); + z.number().gte(2).optional().parse(undefined); + checkErrors(z.boolean(), ""); + z.boolean().optional().parse(undefined); + checkErrors(z.undefined(), null); + z.undefined().optional().parse(undefined); + checkErrors(z.null(), {}); + z.null().optional().parse(undefined); + checkErrors(z.object({}), 1); + z.object({}).optional().parse(undefined); + checkErrors(z.tuple([]), 1); + z.tuple([]).optional().parse(undefined); + checkErrors(z.unknown(), 1); + z.unknown().optional().parse(undefined); +}); + +test("unwrap", () => { + const unwrapped = z.string().optional().unwrap(); + expect(unwrapped).toBeInstanceOf(z.ZodString); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/parseUtil.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/parseUtil.test.ts new file mode 100644 index 0000000..8882d4c --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/parseUtil.test.ts @@ -0,0 +1,23 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import { type SyncParseReturnType, isAborted, isDirty, isValid } from "../helpers/parseUtil.js"; + +test("parseUtil isInvalid should use structural typing", () => { + // Test for issue #556: https://github.com/colinhacks/zod/issues/556 + const aborted: SyncParseReturnType = { status: "aborted" }; + const dirty: SyncParseReturnType = { status: "dirty", value: "whatever" }; + const valid: SyncParseReturnType = { status: "valid", value: "whatever" }; + + expect(isAborted(aborted)).toBe(true); + expect(isAborted(dirty)).toBe(false); + expect(isAborted(valid)).toBe(false); + + expect(isDirty(aborted)).toBe(false); + expect(isDirty(dirty)).toBe(true); + expect(isDirty(valid)).toBe(false); + + expect(isValid(aborted)).toBe(false); + expect(isValid(dirty)).toBe(false); + expect(isValid(valid)).toBe(true); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/parser.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/parser.test.ts new file mode 100644 index 0000000..6e685f9 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/parser.test.ts @@ -0,0 +1,41 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +test("parse strict object with unknown keys", () => { + expect(() => + z + .object({ name: z.string() }) + .strict() + .parse({ name: "bill", unknownKey: 12 } as any) + ).toThrow(); +}); + +test("parse nonstrict object with unknown keys", () => { + z.object({ name: z.string() }).nonstrict().parse({ name: "bill", unknownKey: 12 }); +}); + +test("invalid left side of intersection", () => { + expect(() => z.intersection(z.string(), z.number()).parse(12 as any)).toThrow(); +}); + +test("invalid right side of intersection", () => { + expect(() => z.intersection(z.string(), z.number()).parse("12" as any)).toThrow(); +}); + +test("parsing non-array in tuple schema", () => { + expect(() => z.tuple([]).parse("12" as any)).toThrow(); +}); + +test("incorrect num elements in tuple", () => { + expect(() => z.tuple([]).parse(["asdf"] as any)).toThrow(); +}); + +test("invalid enum value", () => { + expect(() => z.enum(["Blue"]).parse("Red" as any)).toThrow(); +}); + +test("parsing unknown", () => { + z.string().parse("Red" as unknown); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/partials.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/partials.test.ts new file mode 100644 index 0000000..9f2deba --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/partials.test.ts @@ -0,0 +1,243 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { ZodNullable, ZodOptional } from "zod/v3"; +import { util } from "../helpers/util.js"; + +const nested = z.object({ + name: z.string(), + age: z.number(), + outer: z.object({ + inner: z.string(), + }), + array: z.array(z.object({ asdf: z.string() })), +}); + +test("shallow inference", () => { + const shallow = nested.partial(); + type shallow = z.infer; + type correct = { + name?: string | undefined; + age?: number | undefined; + outer?: { inner: string } | undefined; + array?: { asdf: string }[] | undefined; + }; + util.assertEqual(true); +}); + +test("shallow partial parse", () => { + const shallow = nested.partial(); + shallow.parse({}); + shallow.parse({ + name: "asdf", + age: 23143, + }); +}); + +test("deep partial inference", () => { + const deep = nested.deepPartial(); + const asdf = deep.shape.array.unwrap().element.shape.asdf.unwrap(); + asdf.parse("asdf"); + type deep = z.infer; + type correct = { + array?: { asdf?: string | undefined }[] | undefined; + name?: string | undefined; + age?: number | undefined; + outer?: { inner?: string | undefined } | undefined; + }; + + util.assertEqual(true); +}); + +test("deep partial parse", () => { + const deep = nested.deepPartial(); + + expect(deep.shape.name instanceof z.ZodOptional).toBe(true); + expect(deep.shape.outer instanceof z.ZodOptional).toBe(true); + expect(deep.shape.outer._def.innerType instanceof z.ZodObject).toBe(true); + expect(deep.shape.outer._def.innerType.shape.inner instanceof z.ZodOptional).toBe(true); + expect(deep.shape.outer._def.innerType.shape.inner._def.innerType instanceof z.ZodString).toBe(true); +}); + +test("deep partial runtime tests", () => { + const deep = nested.deepPartial(); + deep.parse({}); + deep.parse({ + outer: {}, + }); + deep.parse({ + name: "asdf", + age: 23143, + outer: { + inner: "adsf", + }, + }); +}); + +test("deep partial optional/nullable", () => { + const schema = z + .object({ + name: z.string().optional(), + age: z.number().nullable(), + }) + .deepPartial(); + + expect(schema.shape.name.unwrap()).toBeInstanceOf(ZodOptional); + expect(schema.shape.age.unwrap()).toBeInstanceOf(ZodNullable); +}); + +test("deep partial tuple", () => { + const schema = z + .object({ + tuple: z.tuple([ + z.object({ + name: z.string().optional(), + age: z.number().nullable(), + }), + ]), + }) + .deepPartial(); + + expect(schema.shape.tuple.unwrap().items[0].shape.name).toBeInstanceOf(ZodOptional); +}); + +test("deep partial inference", () => { + const mySchema = z.object({ + name: z.string(), + array: z.array(z.object({ asdf: z.string() })), + tuple: z.tuple([z.object({ value: z.string() })]), + }); + + const partialed = mySchema.deepPartial(); + type partialed = z.infer; + type expected = { + name?: string | undefined; + array?: + | { + asdf?: string | undefined; + }[] + | undefined; + tuple?: [{ value?: string | undefined }] | undefined; + }; + util.assertEqual(true); +}); + +test("required", () => { + const object = z.object({ + name: z.string(), + age: z.number().optional(), + field: z.string().optional().default("asdf"), + nullableField: z.number().nullable(), + nullishField: z.string().nullish(), + }); + + const requiredObject = object.required(); + expect(requiredObject.shape.name).toBeInstanceOf(z.ZodString); + expect(requiredObject.shape.age).toBeInstanceOf(z.ZodNumber); + expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault); + expect(requiredObject.shape.nullableField).toBeInstanceOf(z.ZodNullable); + expect(requiredObject.shape.nullishField).toBeInstanceOf(z.ZodNullable); +}); + +test("required inference", () => { + const object = z.object({ + name: z.string(), + age: z.number().optional(), + field: z.string().optional().default("asdf"), + nullableField: z.number().nullable(), + nullishField: z.string().nullish(), + }); + + const requiredObject = object.required(); + + type required = z.infer; + type expected = { + name: string; + age: number; + field: string; + nullableField: number | null; + nullishField: string | null; + }; + util.assertEqual(true); +}); + +test("required with mask", () => { + const object = z.object({ + name: z.string(), + age: z.number().optional(), + field: z.string().optional().default("asdf"), + country: z.string().optional(), + }); + + const requiredObject = object.required({ age: true }); + expect(requiredObject.shape.name).toBeInstanceOf(z.ZodString); + expect(requiredObject.shape.age).toBeInstanceOf(z.ZodNumber); + expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault); + expect(requiredObject.shape.country).toBeInstanceOf(z.ZodOptional); +}); + +test("required with mask -- ignore falsy values", () => { + const object = z.object({ + name: z.string(), + age: z.number().optional(), + field: z.string().optional().default("asdf"), + country: z.string().optional(), + }); + + // @ts-expect-error + const requiredObject = object.required({ age: true, country: false }); + expect(requiredObject.shape.name).toBeInstanceOf(z.ZodString); + expect(requiredObject.shape.age).toBeInstanceOf(z.ZodNumber); + expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault); + expect(requiredObject.shape.country).toBeInstanceOf(z.ZodOptional); +}); + +test("partial with mask", async () => { + const object = z.object({ + name: z.string(), + age: z.number().optional(), + field: z.string().optional().default("asdf"), + country: z.string(), + }); + + const masked = object.partial({ age: true, field: true, name: true }).strict(); + + expect(masked.shape.name).toBeInstanceOf(z.ZodOptional); + expect(masked.shape.age).toBeInstanceOf(z.ZodOptional); + expect(masked.shape.field).toBeInstanceOf(z.ZodOptional); + expect(masked.shape.country).toBeInstanceOf(z.ZodString); + + masked.parse({ country: "US" }); + await masked.parseAsync({ country: "US" }); +}); + +test("partial with mask -- ignore falsy values", async () => { + const object = z.object({ + name: z.string(), + age: z.number().optional(), + field: z.string().optional().default("asdf"), + country: z.string(), + }); + + // @ts-expect-error + const masked = object.partial({ name: true, country: false }).strict(); + + expect(masked.shape.name).toBeInstanceOf(z.ZodOptional); + expect(masked.shape.age).toBeInstanceOf(z.ZodOptional); + expect(masked.shape.field).toBeInstanceOf(z.ZodDefault); + expect(masked.shape.country).toBeInstanceOf(z.ZodString); + + masked.parse({ country: "US" }); + await masked.parseAsync({ country: "US" }); +}); + +test("deeppartial array", () => { + const schema = z.object({ array: z.string().array().min(42) }).deepPartial(); + + // works as expected + schema.parse({}); + + // should be false, but is true + expect(schema.safeParse({ array: [] }).success).toBe(false); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/pickomit.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/pickomit.test.ts new file mode 100644 index 0000000..b1056e5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/pickomit.test.ts @@ -0,0 +1,111 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +const fish = z.object({ + name: z.string(), + age: z.number(), + nested: z.object({}), +}); + +test("pick type inference", () => { + const nameonlyFish = fish.pick({ name: true }); + type nameonlyFish = z.infer; + util.assertEqual(true); +}); + +test("pick parse - success", () => { + const nameonlyFish = fish.pick({ name: true }); + nameonlyFish.parse({ name: "bob" }); + + // @ts-expect-error checking runtime picks `name` only. + const anotherNameonlyFish = fish.pick({ name: true, age: false }); + anotherNameonlyFish.parse({ name: "bob" }); +}); + +test("pick parse - fail", () => { + fish.pick({ name: true }).parse({ name: "12" } as any); + fish.pick({ name: true }).parse({ name: "bob", age: 12 } as any); + fish.pick({ age: true }).parse({ age: 12 } as any); + + const nameonlyFish = fish.pick({ name: true }).strict(); + const bad1 = () => nameonlyFish.parse({ name: 12 } as any); + const bad2 = () => nameonlyFish.parse({ name: "bob", age: 12 } as any); + const bad3 = () => nameonlyFish.parse({ age: 12 } as any); + + // @ts-expect-error checking runtime picks `name` only. + const anotherNameonlyFish = fish.pick({ name: true, age: false }).strict(); + const bad4 = () => anotherNameonlyFish.parse({ name: "bob", age: 12 } as any); + + expect(bad1).toThrow(); + expect(bad2).toThrow(); + expect(bad3).toThrow(); + expect(bad4).toThrow(); +}); + +test("omit type inference", () => { + const nonameFish = fish.omit({ name: true }); + type nonameFish = z.infer; + util.assertEqual(true); +}); + +test("omit parse - success", () => { + const nonameFish = fish.omit({ name: true }); + nonameFish.parse({ age: 12, nested: {} }); + + // @ts-expect-error checking runtime omits `name` only. + const anotherNonameFish = fish.omit({ name: true, age: false }); + anotherNonameFish.parse({ age: 12, nested: {} }); +}); + +test("omit parse - fail", () => { + const nonameFish = fish.omit({ name: true }); + const bad1 = () => nonameFish.parse({ name: 12 } as any); + const bad2 = () => nonameFish.parse({ age: 12 } as any); + const bad3 = () => nonameFish.parse({} as any); + + // @ts-expect-error checking runtime omits `name` only. + const anotherNonameFish = fish.omit({ name: true, age: false }); + const bad4 = () => anotherNonameFish.parse({ nested: {} } as any); + + expect(bad1).toThrow(); + expect(bad2).toThrow(); + expect(bad3).toThrow(); + expect(bad4).toThrow(); +}); + +test("nonstrict inference", () => { + const laxfish = fish.pick({ name: true }).catchall(z.any()); + type laxfish = z.infer; + util.assertEqual(true); +}); + +test("nonstrict parsing - pass", () => { + const laxfish = fish.passthrough().pick({ name: true }); + laxfish.parse({ name: "asdf", whatever: "asdf" }); + laxfish.parse({ name: "asdf", age: 12, nested: {} }); +}); + +test("nonstrict parsing - fail", () => { + const laxfish = fish.passthrough().pick({ name: true }); + const bad = () => laxfish.parse({ whatever: "asdf" } as any); + expect(bad).toThrow(); +}); + +test("pick/omit/required/partial - do not allow unknown keys", () => { + const schema = z.object({ + name: z.string(), + age: z.number(), + }); + + // @ts-expect-error + schema.pick({ $unknown: true }); + // @ts-expect-error + schema.omit({ $unknown: true }); + // @ts-expect-error + schema.required({ $unknown: true }); + // @ts-expect-error + schema.partial({ $unknown: true }); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/pipeline.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/pipeline.test.ts new file mode 100644 index 0000000..cc94fc5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/pipeline.test.ts @@ -0,0 +1,29 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +test("string to number pipeline", () => { + const schema = z.string().transform(Number).pipe(z.number()); + expect(schema.parse("1234")).toEqual(1234); +}); + +test("string to number pipeline async", async () => { + const schema = z + .string() + .transform(async (val) => Number(val)) + .pipe(z.number()); + expect(await schema.parseAsync("1234")).toEqual(1234); +}); + +test("break if dirty", () => { + const schema = z + .string() + .refine((c) => c === "1234") + .transform(async (val) => Number(val)) + .pipe(z.number().refine((v) => v < 100)); + const r1: any = schema.safeParse("12345"); + expect(r1.error.issues.length).toBe(1); + const r2: any = schema.safeParse("3"); + expect(r2.error.issues.length).toBe(1); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/preprocess.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/preprocess.test.ts new file mode 100644 index 0000000..7e1b5a1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/preprocess.test.ts @@ -0,0 +1,186 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +test("preprocess", () => { + const schema = z.preprocess((data) => [data], z.string().array()); + + const value = schema.parse("asdf"); + expect(value).toEqual(["asdf"]); + util.assertEqual<(typeof schema)["_input"], unknown>(true); +}); + +test("async preprocess", async () => { + const schema = z.preprocess(async (data) => [data], z.string().array()); + + const value = await schema.parseAsync("asdf"); + expect(value).toEqual(["asdf"]); +}); + +test("preprocess ctx.addIssue with parse", () => { + expect(() => { + z.preprocess((data, ctx) => { + ctx.addIssue({ + code: "custom", + message: `${data} is not one of our allowed strings`, + }); + return data; + }, z.string()).parse("asdf"); + }).toThrow( + JSON.stringify( + [ + { + code: "custom", + message: "asdf is not one of our allowed strings", + path: [], + }, + ], + null, + 2 + ) + ); +}); + +test("preprocess ctx.addIssue non-fatal by default", () => { + try { + z.preprocess((data, ctx) => { + ctx.addIssue({ + code: "custom", + message: `custom error`, + }); + return data; + }, z.string()).parse(1234); + } catch (err) { + z.ZodError.assert(err); + expect(err.issues.length).toEqual(2); + } +}); + +test("preprocess ctx.addIssue fatal true", () => { + try { + z.preprocess((data, ctx) => { + ctx.addIssue({ + code: "custom", + message: `custom error`, + fatal: true, + }); + return data; + }, z.string()).parse(1234); + } catch (err) { + z.ZodError.assert(err); + expect(err.issues.length).toEqual(1); + } +}); + +test("async preprocess ctx.addIssue with parse", async () => { + const schema = z.preprocess(async (data, ctx) => { + ctx.addIssue({ + code: "custom", + message: `custom error`, + }); + return data; + }, z.string()); + + expect(await schema.safeParseAsync("asdf")).toMatchInlineSnapshot(` + { + "error": [ZodError: [ + { + "code": "custom", + "message": "custom error", + "path": [] + } + ]], + "success": false, + } + `); +}); + +test("preprocess ctx.addIssue with parseAsync", async () => { + const result = await z + .preprocess(async (data, ctx) => { + ctx.addIssue({ + code: "custom", + message: `${data} is not one of our allowed strings`, + }); + return data; + }, z.string()) + .safeParseAsync("asdf"); + + expect(JSON.parse(JSON.stringify(result))).toEqual({ + success: false, + error: { + issues: [ + { + code: "custom", + message: "asdf is not one of our allowed strings", + path: [], + }, + ], + name: "ZodError", + }, + }); +}); + +test("z.NEVER in preprocess", () => { + const foo = z.preprocess((val, ctx) => { + if (!val) { + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "bad" }); + return z.NEVER; + } + return val; + }, z.number()); + + type foo = z.infer; + util.assertEqual(true); + const arg = foo.safeParse(undefined); + expect(arg.error!.issues).toHaveLength(2); + expect(arg.error!.issues[0].message).toEqual("bad"); +}); +test("preprocess as the second property of object", () => { + const schema = z.object({ + nonEmptyStr: z.string().min(1), + positiveNum: z.preprocess((v) => Number(v), z.number().positive()), + }); + const result = schema.safeParse({ + nonEmptyStr: "", + positiveNum: "", + }); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues.length).toEqual(2); + expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.too_small); + expect(result.error.issues[1].code).toEqual(z.ZodIssueCode.too_small); + } +}); + +test("preprocess validates with sibling errors", () => { + expect(() => { + z.object({ + // Must be first + missing: z.string().refine(() => false), + preprocess: z.preprocess((data: any) => data?.trim(), z.string().regex(/ asdf/)), + }).parse({ preprocess: " asdf" }); + }).toThrow( + JSON.stringify( + [ + { + code: "invalid_type", + expected: "string", + received: "undefined", + path: ["missing"], + message: "Required", + }, + { + validation: "regex", + code: "invalid_string", + message: "Invalid", + path: ["preprocess"], + }, + ], + null, + 2 + ) + ); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/primitive.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/primitive.test.ts new file mode 100644 index 0000000..48e36a2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/primitive.test.ts @@ -0,0 +1,440 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; +import { Mocker } from "./Mocker.js"; + +const literalStringSchema = z.literal("asdf"); +const literalNumberSchema = z.literal(12); +const literalBooleanSchema = z.literal(true); +const literalBigIntSchema = z.literal(BigInt(42)); +const MySymbol = Symbol("stuff"); +const literalSymbolSchema = z.literal(MySymbol); +const stringSchema = z.string(); +const numberSchema = z.number(); +const bigintSchema = z.bigint(); +const booleanSchema = z.boolean(); +const dateSchema = z.date(); +const symbolSchema = z.symbol(); + +const nullSchema = z.null(); +const undefinedSchema = z.undefined(); +const stringSchemaOptional = z.string().optional(); +const stringSchemaNullable = z.string().nullable(); +const numberSchemaOptional = z.number().optional(); +const numberSchemaNullable = z.number().nullable(); +const bigintSchemaOptional = z.bigint().optional(); +const bigintSchemaNullable = z.bigint().nullable(); +const booleanSchemaOptional = z.boolean().optional(); +const booleanSchemaNullable = z.boolean().nullable(); +const dateSchemaOptional = z.date().optional(); +const dateSchemaNullable = z.date().nullable(); +const symbolSchemaOptional = z.symbol().optional(); +const symbolSchemaNullable = z.symbol().nullable(); + +const val = new Mocker(); + +test("literal string correct", () => { + expect(literalStringSchema.parse("asdf")).toBe("asdf"); +}); + +test("literal string incorrect", () => { + const f = () => literalStringSchema.parse("not_asdf"); + expect(f).toThrow(); +}); + +test("literal string number", () => { + const f = () => literalStringSchema.parse(123); + expect(f).toThrow(); +}); + +test("literal string boolean", () => { + const f = () => literalStringSchema.parse(true); + expect(f).toThrow(); +}); + +test("literal string boolean", () => { + const f = () => literalStringSchema.parse(true); + expect(f).toThrow(); +}); + +test("literal string object", () => { + const f = () => literalStringSchema.parse({}); + expect(f).toThrow(); +}); + +test("literal number correct", () => { + expect(literalNumberSchema.parse(12)).toBe(12); +}); + +test("literal number incorrect", () => { + const f = () => literalNumberSchema.parse(13); + expect(f).toThrow(); +}); + +test("literal number number", () => { + const f = () => literalNumberSchema.parse(val.string); + expect(f).toThrow(); +}); + +test("literal number boolean", () => { + const f = () => literalNumberSchema.parse(val.boolean); + expect(f).toThrow(); +}); + +test("literal number object", () => { + const f = () => literalStringSchema.parse({}); + expect(f).toThrow(); +}); + +test("literal boolean correct", () => { + expect(literalBooleanSchema.parse(true)).toBe(true); +}); + +test("literal boolean incorrect", () => { + const f = () => literalBooleanSchema.parse(false); + expect(f).toThrow(); +}); + +test("literal boolean number", () => { + const f = () => literalBooleanSchema.parse("asdf"); + expect(f).toThrow(); +}); + +test("literal boolean boolean", () => { + const f = () => literalBooleanSchema.parse(123); + expect(f).toThrow(); +}); + +test("literal boolean object", () => { + const f = () => literalBooleanSchema.parse({}); + expect(f).toThrow(); +}); + +test("literal bigint correct", () => { + expect(literalBigIntSchema.parse(BigInt(42))).toBe(BigInt(42)); +}); + +test("literal bigint incorrect", () => { + const f = () => literalBigIntSchema.parse(BigInt(43)); + expect(f).toThrow(); +}); + +test("literal bigint number", () => { + const f = () => literalBigIntSchema.parse("asdf"); + expect(f).toThrow(); +}); + +test("literal bigint boolean", () => { + const f = () => literalBigIntSchema.parse(123); + expect(f).toThrow(); +}); + +test("literal bigint object", () => { + const f = () => literalBigIntSchema.parse({}); + expect(f).toThrow(); +}); + +test("literal symbol", () => { + util.assertEqual, typeof MySymbol>(true); + literalSymbolSchema.parse(MySymbol); + expect(() => literalSymbolSchema.parse(Symbol("asdf"))).toThrow(); +}); + +test("parse stringSchema string", () => { + stringSchema.parse(val.string); +}); + +test("parse stringSchema number", () => { + const f = () => stringSchema.parse(val.number); + expect(f).toThrow(); +}); + +test("parse stringSchema boolean", () => { + const f = () => stringSchema.parse(val.boolean); + expect(f).toThrow(); +}); + +test("parse stringSchema undefined", () => { + const f = () => stringSchema.parse(val.undefined); + expect(f).toThrow(); +}); + +test("parse stringSchema null", () => { + const f = () => stringSchema.parse(val.null); + expect(f).toThrow(); +}); + +test("parse numberSchema string", () => { + const f = () => numberSchema.parse(val.string); + expect(f).toThrow(); +}); + +test("parse numberSchema number", () => { + numberSchema.parse(val.number); +}); + +test("parse numberSchema bigint", () => { + const f = () => numberSchema.parse(val.bigint); + expect(f).toThrow(); +}); + +test("parse numberSchema boolean", () => { + const f = () => numberSchema.parse(val.boolean); + expect(f).toThrow(); +}); + +test("parse numberSchema undefined", () => { + const f = () => numberSchema.parse(val.undefined); + expect(f).toThrow(); +}); + +test("parse numberSchema null", () => { + const f = () => numberSchema.parse(val.null); + expect(f).toThrow(); +}); + +test("parse bigintSchema string", () => { + const f = () => bigintSchema.parse(val.string); + expect(f).toThrow(); +}); + +test("parse bigintSchema number", () => { + const f = () => bigintSchema.parse(val.number); + expect(f).toThrow(); +}); + +test("parse bigintSchema bigint", () => { + bigintSchema.parse(val.bigint); +}); + +test("parse bigintSchema boolean", () => { + const f = () => bigintSchema.parse(val.boolean); + expect(f).toThrow(); +}); + +test("parse bigintSchema undefined", () => { + const f = () => bigintSchema.parse(val.undefined); + expect(f).toThrow(); +}); + +test("parse bigintSchema null", () => { + const f = () => bigintSchema.parse(val.null); + expect(f).toThrow(); +}); + +test("parse booleanSchema string", () => { + const f = () => booleanSchema.parse(val.string); + expect(f).toThrow(); +}); + +test("parse booleanSchema number", () => { + const f = () => booleanSchema.parse(val.number); + expect(f).toThrow(); +}); + +test("parse booleanSchema boolean", () => { + booleanSchema.parse(val.boolean); +}); + +test("parse booleanSchema undefined", () => { + const f = () => booleanSchema.parse(val.undefined); + expect(f).toThrow(); +}); + +test("parse booleanSchema null", () => { + const f = () => booleanSchema.parse(val.null); + expect(f).toThrow(); +}); + +// ============== + +test("parse dateSchema string", () => { + const f = () => dateSchema.parse(val.string); + expect(f).toThrow(); +}); + +test("parse dateSchema number", () => { + const f = () => dateSchema.parse(val.number); + expect(f).toThrow(); +}); + +test("parse dateSchema boolean", () => { + const f = () => dateSchema.parse(val.boolean); + expect(f).toThrow(); +}); + +test("parse dateSchema date", () => { + dateSchema.parse(val.date); +}); + +test("parse dateSchema undefined", () => { + const f = () => dateSchema.parse(val.undefined); + expect(f).toThrow(); +}); + +test("parse dateSchema null", () => { + const f = () => dateSchema.parse(val.null); + expect(f).toThrow(); +}); + +test("parse dateSchema invalid date", async () => { + try { + await dateSchema.parseAsync(new Date("invalid")); + } catch (err) { + expect((err as z.ZodError).issues[0].code).toEqual(z.ZodIssueCode.invalid_date); + } +}); +// ============== + +test("parse symbolSchema string", () => { + const f = () => symbolSchema.parse(val.string); + expect(f).toThrow(); +}); + +test("parse symbolSchema number", () => { + const f = () => symbolSchema.parse(val.number); + expect(f).toThrow(); +}); + +test("parse symbolSchema boolean", () => { + const f = () => symbolSchema.parse(val.boolean); + expect(f).toThrow(); +}); + +test("parse symbolSchema date", () => { + const f = () => symbolSchema.parse(val.date); + expect(f).toThrow(); +}); + +test("parse symbolSchema symbol", () => { + symbolSchema.parse(val.symbol); +}); + +test("parse symbolSchema undefined", () => { + const f = () => symbolSchema.parse(val.undefined); + expect(f).toThrow(); +}); + +test("parse symbolSchema null", () => { + const f = () => symbolSchema.parse(val.null); + expect(f).toThrow(); +}); + +// ============== + +test("parse undefinedSchema string", () => { + const f = () => undefinedSchema.parse(val.string); + expect(f).toThrow(); +}); + +test("parse undefinedSchema number", () => { + const f = () => undefinedSchema.parse(val.number); + expect(f).toThrow(); +}); + +test("parse undefinedSchema boolean", () => { + const f = () => undefinedSchema.parse(val.boolean); + expect(f).toThrow(); +}); + +test("parse undefinedSchema undefined", () => { + undefinedSchema.parse(val.undefined); +}); + +test("parse undefinedSchema null", () => { + const f = () => undefinedSchema.parse(val.null); + expect(f).toThrow(); +}); + +test("parse nullSchema string", () => { + const f = () => nullSchema.parse(val.string); + expect(f).toThrow(); +}); + +test("parse nullSchema number", () => { + const f = () => nullSchema.parse(val.number); + expect(f).toThrow(); +}); + +test("parse nullSchema boolean", () => { + const f = () => nullSchema.parse(val.boolean); + expect(f).toThrow(); +}); + +test("parse nullSchema undefined", () => { + const f = () => nullSchema.parse(val.undefined); + expect(f).toThrow(); +}); + +test("parse nullSchema null", () => { + nullSchema.parse(val.null); +}); + +test("primitive inference", () => { + util.assertEqual, "asdf">(true); + util.assertEqual, 12>(true); + util.assertEqual, true>(true); + util.assertEqual, bigint>(true); + util.assertEqual, string>(true); + util.assertEqual, number>(true); + util.assertEqual, bigint>(true); + util.assertEqual, boolean>(true); + util.assertEqual, Date>(true); + util.assertEqual, symbol>(true); + + util.assertEqual, null>(true); + util.assertEqual, undefined>(true); + util.assertEqual, string | undefined>(true); + util.assertEqual, string | null>(true); + util.assertEqual, number | undefined>(true); + util.assertEqual, number | null>(true); + util.assertEqual, bigint | undefined>(true); + util.assertEqual, bigint | null>(true); + util.assertEqual, boolean | undefined>(true); + util.assertEqual, boolean | null>(true); + util.assertEqual, Date | undefined>(true); + util.assertEqual, Date | null>(true); + util.assertEqual, symbol | undefined>(true); + util.assertEqual, symbol | null>(true); + + // [ + // literalStringSchemaTest, + // literalNumberSchemaTest, + // literalBooleanSchemaTest, + // literalBigIntSchemaTest, + // stringSchemaTest, + // numberSchemaTest, + // bigintSchemaTest, + // booleanSchemaTest, + // dateSchemaTest, + // symbolSchemaTest, + + // nullSchemaTest, + // undefinedSchemaTest, + // stringSchemaOptionalTest, + // stringSchemaNullableTest, + // numberSchemaOptionalTest, + // numberSchemaNullableTest, + // bigintSchemaOptionalTest, + // bigintSchemaNullableTest, + // booleanSchemaOptionalTest, + // booleanSchemaNullableTest, + // dateSchemaOptionalTest, + // dateSchemaNullableTest, + // symbolSchemaOptionalTest, + // symbolSchemaNullableTest, + + // ]; +}); + +test("get literal value", () => { + expect(literalStringSchema.value).toEqual("asdf"); +}); + +test("optional convenience method", () => { + z.ostring().parse(undefined); + z.onumber().parse(undefined); + z.oboolean().parse(undefined); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/promise.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/promise.test.ts new file mode 100644 index 0000000..23b6de1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/promise.test.ts @@ -0,0 +1,90 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +const promSchema = z.promise( + z.object({ + name: z.string(), + age: z.number(), + }) +); + +test("promise inference", () => { + type promSchemaType = z.infer; + util.assertEqual>(true); +}); + +test("promise parsing success", async () => { + const pr = promSchema.parse(Promise.resolve({ name: "Bobby", age: 10 })); + expect(pr).toBeInstanceOf(Promise); + const result = await pr; + expect(typeof result).toBe("object"); + expect(typeof result.age).toBe("number"); + expect(typeof result.name).toBe("string"); +}); + +test("promise parsing success 2", () => { + const fakePromise = { + then() { + return this; + }, + catch() { + return this; + }, + }; + promSchema.parse(fakePromise); +}); + +test("promise parsing fail", async () => { + const bad = promSchema.parse(Promise.resolve({ name: "Bobby", age: "10" })); + // return await expect(bad).resolves.toBe({ name: 'Bobby', age: '10' }); + return await expect(bad).rejects.toBeInstanceOf(z.ZodError); + // done(); +}); + +test("promise parsing fail 2", async () => { + const failPromise = promSchema.parse(Promise.resolve({ name: "Bobby", age: "10" })); + await expect(failPromise).rejects.toBeInstanceOf(z.ZodError); + // done();/z +}); + +test("promise parsing fail", () => { + const bad = () => promSchema.parse({ then: () => {}, catch: {} }); + expect(bad).toThrow(); +}); + +// test('sync promise parsing', () => { +// expect(() => z.promise(z.string()).parse(Promise.resolve('asfd'))).toThrow(); +// }); + +const asyncFunction = z.function(z.tuple([]), promSchema); + +test("async function pass", async () => { + const validatedFunction = asyncFunction.implement(async () => { + return { name: "jimmy", age: 14 }; + }); + await expect(validatedFunction()).resolves.toEqual({ + name: "jimmy", + age: 14, + }); +}); + +test("async function fail", async () => { + const validatedFunction = asyncFunction.implement(() => { + return Promise.resolve("asdf" as any); + }); + await expect(validatedFunction()).rejects.toBeInstanceOf(z.ZodError); +}); + +test("async promise parsing", () => { + const res = z.promise(z.number()).parseAsync(Promise.resolve(12)); + expect(res).toBeInstanceOf(Promise); +}); + +test("resolves", () => { + const foo = z.literal("foo"); + const res = z.promise(foo); + expect(res.unwrap()).toEqual(foo); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/readonly.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/readonly.test.ts new file mode 100644 index 0000000..5078955 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/readonly.test.ts @@ -0,0 +1,194 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +enum testEnum { + A = 0, + B = 1, +} + +const schemas = [ + z.string().readonly(), + z.number().readonly(), + z.nan().readonly(), + z.bigint().readonly(), + z.boolean().readonly(), + z.date().readonly(), + z.undefined().readonly(), + z.null().readonly(), + z.any().readonly(), + z.unknown().readonly(), + z.void().readonly(), + z.function().args(z.string(), z.number()).readonly(), + + z.array(z.string()).readonly(), + z.tuple([z.string(), z.number()]).readonly(), + z.map(z.string(), z.date()).readonly(), + z.set(z.promise(z.string())).readonly(), + z.record(z.string()).readonly(), + z.record(z.string(), z.number()).readonly(), + z.object({ a: z.string(), 1: z.number() }).readonly(), + z.nativeEnum(testEnum).readonly(), + z.promise(z.string()).readonly(), +] as const; + +test("flat inference", () => { + util.assertEqual, string>(true); + util.assertEqual, number>(true); + util.assertEqual, number>(true); + util.assertEqual, bigint>(true); + util.assertEqual, boolean>(true); + util.assertEqual, Date>(true); + util.assertEqual, undefined>(true); + util.assertEqual, null>(true); + util.assertEqual, any>(true); + util.assertEqual, Readonly>(true); + util.assertEqual, void>(true); + util.assertEqual, (args_0: string, args_1: number, ...args_2: unknown[]) => unknown>( + true + ); + util.assertEqual, readonly string[]>(true); + + util.assertEqual, readonly [string, number]>(true); + util.assertEqual, ReadonlyMap>(true); + util.assertEqual, ReadonlySet>>(true); + util.assertEqual, Readonly>>(true); + util.assertEqual, Readonly>>(true); + util.assertEqual, { readonly a: string; readonly 1: number }>(true); + util.assertEqual, Readonly>(true); + util.assertEqual, Promise>(true); +}); + +// test("deep inference", () => { +// util.assertEqual, string>(true); +// util.assertEqual, number>(true); +// util.assertEqual, number>(true); +// util.assertEqual, bigint>(true); +// util.assertEqual, boolean>(true); +// util.assertEqual, Date>(true); +// util.assertEqual, undefined>(true); +// util.assertEqual, null>(true); +// util.assertEqual, any>(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[9]>, +// Readonly +// >(true); +// util.assertEqual, void>(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[11]>, +// (args_0: string, args_1: number, ...args_2: unknown[]) => unknown +// >(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[12]>, +// readonly string[] +// >(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[13]>, +// readonly [string, number] +// >(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[14]>, +// ReadonlyMap +// >(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[15]>, +// ReadonlySet> +// >(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[16]>, +// Readonly> +// >(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[17]>, +// Readonly> +// >(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[18]>, +// { readonly a: string; readonly 1: number } +// >(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[19]>, +// Readonly +// >(true); +// util.assertEqual< +// z.infer<(typeof deepReadonlySchemas_0)[20]>, +// Promise +// >(true); + +// util.assertEqual< +// z.infer, +// ReadonlyMap< +// ReadonlySet, +// { +// readonly a: { +// readonly [x: string]: readonly any[]; +// }; +// readonly b: { +// readonly c: { +// readonly d: { +// readonly e: { +// readonly f: { +// readonly g?: {}; +// }; +// }; +// }; +// }; +// }; +// } +// > +// >(true); +// }); + +test("object freezing", () => { + expect(Object.isFrozen(z.array(z.string()).readonly().parse(["a"]))).toBe(true); + expect(Object.isFrozen(z.tuple([z.string(), z.number()]).readonly().parse(["a", 1]))).toBe(true); + expect( + Object.isFrozen( + z + .map(z.string(), z.date()) + .readonly() + .parse(new Map([["a", new Date()]])) + ) + ).toBe(true); + expect( + Object.isFrozen( + z + .set(z.promise(z.string())) + .readonly() + .parse(new Set([Promise.resolve("a")])) + ) + ).toBe(true); + expect(Object.isFrozen(z.record(z.string()).readonly().parse({ a: "b" }))).toBe(true); + expect(Object.isFrozen(z.record(z.string(), z.number()).readonly().parse({ a: 1 }))).toBe(true); + expect(Object.isFrozen(z.object({ a: z.string(), 1: z.number() }).readonly().parse({ a: "b", 1: 2 }))).toBe(true); + expect(Object.isFrozen(z.promise(z.string()).readonly().parse(Promise.resolve("a")))).toBe(true); +}); + +test("async object freezing", async () => { + expect(Object.isFrozen(await z.array(z.string()).readonly().parseAsync(["a"]))).toBe(true); + expect(Object.isFrozen(await z.tuple([z.string(), z.number()]).readonly().parseAsync(["a", 1]))).toBe(true); + expect( + Object.isFrozen( + await z + .map(z.string(), z.date()) + .readonly() + .parseAsync(new Map([["a", new Date()]])) + ) + ).toBe(true); + expect( + Object.isFrozen( + await z + .set(z.promise(z.string())) + .readonly() + .parseAsync(new Set([Promise.resolve("a")])) + ) + ).toBe(true); + expect(Object.isFrozen(await z.record(z.string()).readonly().parseAsync({ a: "b" }))).toBe(true); + expect(Object.isFrozen(await z.record(z.string(), z.number()).readonly().parseAsync({ a: 1 }))).toBe(true); + expect( + Object.isFrozen(await z.object({ a: z.string(), 1: z.number() }).readonly().parseAsync({ a: "b", 1: 2 })) + ).toBe(true); + expect(Object.isFrozen(await z.promise(z.string()).readonly().parseAsync(Promise.resolve("a")))).toBe(true); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/record.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/record.test.ts new file mode 100644 index 0000000..83c363f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/record.test.ts @@ -0,0 +1,171 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +const booleanRecord = z.record(z.boolean()); +type booleanRecord = z.infer; + +const recordWithEnumKeys = z.record(z.enum(["Tuna", "Salmon"]), z.string()); +type recordWithEnumKeys = z.infer; + +const recordWithLiteralKeys = z.record(z.union([z.literal("Tuna"), z.literal("Salmon")]), z.string()); +type recordWithLiteralKeys = z.infer; + +test("type inference", () => { + util.assertEqual>(true); + + util.assertEqual>>(true); + + util.assertEqual>>(true); +}); + +test("methods", () => { + booleanRecord.optional(); + booleanRecord.nullable(); +}); + +test("string record parse - pass", () => { + booleanRecord.parse({ + k1: true, + k2: false, + 1234: false, + }); +}); + +test("string record parse - fail", () => { + const badCheck = () => + booleanRecord.parse({ + asdf: 1234, + } as any); + expect(badCheck).toThrow(); + + expect(() => booleanRecord.parse("asdf")).toThrow(); +}); + +test("string record parse - fail", () => { + const badCheck = () => + booleanRecord.parse({ + asdf: {}, + } as any); + expect(badCheck).toThrow(); +}); + +test("string record parse - fail", () => { + const badCheck = () => + booleanRecord.parse({ + asdf: [], + } as any); + expect(badCheck).toThrow(); +}); + +test("key schema", () => { + const result1 = recordWithEnumKeys.parse({ + Tuna: "asdf", + Salmon: "asdf", + }); + expect(result1).toEqual({ + Tuna: "asdf", + Salmon: "asdf", + }); + + const result2 = recordWithLiteralKeys.parse({ + Tuna: "asdf", + Salmon: "asdf", + }); + expect(result2).toEqual({ + Tuna: "asdf", + Salmon: "asdf", + }); + + // shouldn't require us to specify all props in record + const result3 = recordWithEnumKeys.parse({ + Tuna: "abcd", + }); + expect(result3).toEqual({ + Tuna: "abcd", + }); + + // shouldn't require us to specify all props in record + const result4 = recordWithLiteralKeys.parse({ + Salmon: "abcd", + }); + expect(result4).toEqual({ + Salmon: "abcd", + }); + + expect(() => + recordWithEnumKeys.parse({ + Tuna: "asdf", + Salmon: "asdf", + Trout: "asdf", + }) + ).toThrow(); + + expect(() => + recordWithLiteralKeys.parse({ + Tuna: "asdf", + Salmon: "asdf", + + Trout: "asdf", + }) + ).toThrow(); +}); + +// test("record element", () => { +// expect(booleanRecord.element).toBeInstanceOf(z.ZodBoolean); +// }); + +test("key and value getters", () => { + const rec = z.record(z.string(), z.number()); + + rec.keySchema.parse("asdf"); + rec.valueSchema.parse(1234); + rec.element.parse(1234); +}); + +test("is not vulnerable to prototype pollution", async () => { + const rec = z.record( + z.object({ + a: z.string(), + }) + ); + + const data = JSON.parse(` + { + "__proto__": { + "a": "evil" + }, + "b": { + "a": "good" + } + } + `); + + const obj1 = rec.parse(data); + expect(obj1.a).toBeUndefined(); + + const obj2 = rec.safeParse(data); + expect(obj2.success).toBe(true); + if (obj2.success) { + expect(obj2.data.a).toBeUndefined(); + } + + const obj3 = await rec.parseAsync(data); + expect(obj3.a).toBeUndefined(); + + const obj4 = await rec.safeParseAsync(data); + expect(obj4.success).toBe(true); + if (obj4.success) { + expect(obj4.data.a).toBeUndefined(); + } +}); + +test("dont parse undefined values", () => { + const result1 = z.record(z.any()).parse({ foo: undefined }); + + expect(result1).toEqual({ + foo: undefined, + }); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/recursive.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/recursive.test.ts new file mode 100644 index 0000000..f5bb108 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/recursive.test.ts @@ -0,0 +1,197 @@ +// @ts-ignore TS6133 +import { test } from "vitest"; + +import { z } from "zod/v3"; + +interface Category { + name: string; + subcategories: Category[]; +} + +const testCategory: Category = { + name: "I", + subcategories: [ + { + name: "A", + subcategories: [ + { + name: "1", + subcategories: [ + { + name: "a", + subcategories: [], + }, + ], + }, + ], + }, + ], +}; + +test("recursion with z.late.object", () => { + const Category: z.ZodType = z.late.object(() => ({ + name: z.string(), + subcategories: z.array(Category), + })); + Category.parse(testCategory); +}); + +test("recursion with z.lazy", () => { + const Category: z.ZodType = z.lazy(() => + z.object({ + name: z.string(), + subcategories: z.array(Category), + }) + ); + Category.parse(testCategory); +}); + +test("schema getter", () => { + z.lazy(() => z.string()).schema.parse("asdf"); +}); + +type LinkedList = null | { value: number; next: LinkedList }; + +const linkedListExample = { + value: 1, + next: { + value: 2, + next: { + value: 3, + next: { + value: 4, + next: null, + }, + }, + }, +}; + +test("recursion involving union type", () => { + const LinkedListSchema: z.ZodType = z.lazy(() => + z.union([ + z.null(), + z.object({ + value: z.number(), + next: LinkedListSchema, + }), + ]) + ); + LinkedListSchema.parse(linkedListExample); +}); + +// interface A { +// val: number; +// b: B; +// } + +// interface B { +// val: number; +// a: A; +// } + +// const A: z.ZodType = z.late.object(() => ({ +// val: z.number(), +// b: B, +// })); + +// const B: z.ZodType = z.late.object(() => ({ +// val: z.number(), +// a: A, +// })); + +// const Alazy: z.ZodType = z.lazy(() => z.object({ +// val: z.number(), +// b: B, +// })); + +// const Blazy: z.ZodType = z.lazy(() => z.object({ +// val: z.number(), +// a: A, +// })); + +// const a: any = { val: 1 }; +// const b: any = { val: 2 }; +// a.b = b; +// b.a = a; + +// test('valid check', () => { +// A.parse(a); +// B.parse(b); +// }); + +// test("valid check lazy", () => { +// A.parse({val:1, b:}); +// B.parse(b); +// }); + +// test('masking check', () => { +// const FragmentOnA = z +// .object({ +// val: z.number(), +// b: z +// .object({ +// val: z.number(), +// a: z +// .object({ +// val: z.number(), +// }) +// .nonstrict(), +// }) +// .nonstrict(), +// }) +// .nonstrict(); + +// const fragment = FragmentOnA.parse(a); +// fragment; +// }); + +// test('invalid check', () => { +// expect(() => A.parse({} as any)).toThrow(); +// }); + +// test('schema getter', () => { +// (A as z.ZodLazy).schema; +// }); + +// test("self recursion with cyclical data", () => { +// interface Category { +// name: string; +// subcategories: Category[]; +// } + +// const Category: z.ZodType = z.late.object(() => ({ +// name: z.string(), +// subcategories: z.array(Category), +// })); + +// const untypedCategory: any = { +// name: "Category A", +// }; +// // creating a cycle +// untypedCategory.subcategories = [untypedCategory]; +// Category.parse(untypedCategory); +// }); + +// test("self recursion with base type", () => { +// const BaseCategory = z.object({ +// name: z.string(), +// }); +// type BaseCategory = z.infer; + +// type Category = BaseCategory & { subcategories: Category[] }; + +// const Category: z.ZodType = z.late +// .object(() => ({ +// subcategories: z.array(Category), +// })) +// .extend({ +// name: z.string(), +// }); + +// const untypedCategory: any = { +// name: "Category A", +// }; +// // creating a cycle +// untypedCategory.subcategories = [untypedCategory]; +// Category.parse(untypedCategory); // parses successfully +// }); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/refine.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/refine.test.ts new file mode 100644 index 0000000..55c27fe --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/refine.test.ts @@ -0,0 +1,313 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { ZodIssueCode } from "../ZodError.js"; +import { util } from "../helpers/util.js"; + +test("refinement", () => { + const obj1 = z.object({ + first: z.string(), + second: z.string(), + }); + const obj2 = obj1.partial().strict(); + + const obj3 = obj2.refine((data) => data.first || data.second, "Either first or second should be filled in."); + + expect(obj1 === (obj2 as any)).toEqual(false); + expect(obj2 === (obj3 as any)).toEqual(false); + + expect(() => obj1.parse({})).toThrow(); + expect(() => obj2.parse({ third: "adsf" })).toThrow(); + expect(() => obj3.parse({})).toThrow(); + obj3.parse({ first: "a" }); + obj3.parse({ second: "a" }); + obj3.parse({ first: "a", second: "a" }); +}); + +test("refinement 2", () => { + const validationSchema = z + .object({ + email: z.string().email(), + password: z.string(), + confirmPassword: z.string(), + }) + .refine((data) => data.password === data.confirmPassword, "Both password and confirmation must match"); + + expect(() => + validationSchema.parse({ + email: "aaaa@gmail.com", + password: "aaaaaaaa", + confirmPassword: "bbbbbbbb", + }) + ).toThrow(); +}); + +test("refinement type guard", () => { + const validationSchema = z.object({ + a: z.string().refine((s): s is "a" => s === "a"), + }); + type Input = z.input; + type Schema = z.infer; + + util.assertEqual<"a", Input["a"]>(false); + util.assertEqual(true); + + util.assertEqual<"a", Schema["a"]>(true); + util.assertEqual(false); +}); + +test("refinement Promise", async () => { + const validationSchema = z + .object({ + email: z.string().email(), + password: z.string(), + confirmPassword: z.string(), + }) + .refine( + (data) => Promise.resolve().then(() => data.password === data.confirmPassword), + "Both password and confirmation must match" + ); + + await validationSchema.parseAsync({ + email: "aaaa@gmail.com", + password: "password", + confirmPassword: "password", + }); +}); + +test("custom path", async () => { + const result = await z + .object({ + password: z.string(), + confirm: z.string(), + }) + .refine((data) => data.confirm === data.password, { path: ["confirm"] }) + .spa({ password: "asdf", confirm: "qewr" }); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].path).toEqual(["confirm"]); + } +}); + +test("use path in refinement context", async () => { + const noNested = z.string()._refinement((_val, ctx) => { + if (ctx.path.length > 0) { + ctx.addIssue({ + code: ZodIssueCode.custom, + message: `schema cannot be nested. path: ${ctx.path.join(".")}`, + }); + return false; + } else { + return true; + } + }); + + const data = z.object({ + foo: noNested, + }); + + const t1 = await noNested.spa("asdf"); + const t2 = await data.spa({ foo: "asdf" }); + + expect(t1.success).toBe(true); + expect(t2.success).toBe(false); + if (t2.success === false) { + expect(t2.error.issues[0].message).toEqual("schema cannot be nested. path: foo"); + } +}); + +test("superRefine", () => { + const Strings = z.array(z.string()).superRefine((val, ctx) => { + if (val.length > 3) { + ctx.addIssue({ + code: z.ZodIssueCode.too_big, + maximum: 3, + type: "array", + inclusive: true, + exact: true, + message: "Too many items 😡", + }); + } + + if (val.length !== new Set(val).size) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `No duplicates allowed.`, + }); + } + }); + + const result = Strings.safeParse(["asfd", "asfd", "asfd", "asfd"]); + + expect(result.success).toEqual(false); + if (!result.success) expect(result.error.issues.length).toEqual(2); + + Strings.parse(["asfd", "qwer"]); +}); + +test("superRefine async", async () => { + const Strings = z.array(z.string()).superRefine(async (val, ctx) => { + if (val.length > 3) { + ctx.addIssue({ + code: z.ZodIssueCode.too_big, + maximum: 3, + type: "array", + inclusive: true, + exact: true, + message: "Too many items 😡", + }); + } + + if (val.length !== new Set(val).size) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `No duplicates allowed.`, + }); + } + }); + + const result = await Strings.safeParseAsync(["asfd", "asfd", "asfd", "asfd"]); + + expect(result.success).toEqual(false); + if (!result.success) expect(result.error.issues.length).toEqual(2); + + Strings.parseAsync(["asfd", "qwer"]); +}); + +test("superRefine - type narrowing", () => { + type NarrowType = { type: string; age: number }; + const schema = z + .object({ + type: z.string(), + age: z.number(), + }) + .nullable() + .superRefine((arg, ctx): arg is NarrowType => { + if (!arg) { + // still need to make a call to ctx.addIssue + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "cannot be null", + fatal: true, + }); + return false; + } + return true; + }); + + util.assertEqual, NarrowType>(true); + + expect(schema.safeParse({ type: "test", age: 0 }).success).toEqual(true); + expect(schema.safeParse(null).success).toEqual(false); +}); + +test("chained mixed refining types", () => { + type firstRefinement = { first: string; second: number; third: true }; + type secondRefinement = { first: "bob"; second: number; third: true }; + type thirdRefinement = { first: "bob"; second: 33; third: true }; + const schema = z + .object({ + first: z.string(), + second: z.number(), + third: z.boolean(), + }) + .nullable() + .refine((arg): arg is firstRefinement => !!arg?.third) + .superRefine((arg, ctx): arg is secondRefinement => { + util.assertEqual(true); + if (arg.first !== "bob") { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "`first` property must be `bob`", + }); + return false; + } + return true; + }) + .refine((arg): arg is thirdRefinement => { + util.assertEqual(true); + return arg.second === 33; + }); + + util.assertEqual, thirdRefinement>(true); +}); + +test("get inner type", () => { + z.string() + .refine(() => true) + .innerType() + .parse("asdf"); +}); + +test("chained refinements", () => { + const objectSchema = z + .object({ + length: z.number(), + size: z.number(), + }) + .refine(({ length }) => length > 5, { + path: ["length"], + message: "length greater than 5", + }) + .refine(({ size }) => size > 7, { + path: ["size"], + message: "size greater than 7", + }); + const r1 = objectSchema.safeParse({ + length: 4, + size: 9, + }); + expect(r1.success).toEqual(false); + if (!r1.success) expect(r1.error.issues.length).toEqual(1); + + const r2 = objectSchema.safeParse({ + length: 4, + size: 3, + }); + expect(r2.success).toEqual(false); + if (!r2.success) expect(r2.error.issues.length).toEqual(2); +}); + +test("fatal superRefine", () => { + const Strings = z + .string() + .superRefine((val, ctx) => { + if (val === "") { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "foo", + fatal: true, + }); + } + }) + .superRefine((val, ctx) => { + if (val !== " ") { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "bar", + }); + } + }); + + const result = Strings.safeParse(""); + + expect(result.success).toEqual(false); + if (!result.success) expect(result.error.issues.length).toEqual(1); +}); + +test("superRefine after skipped transform", () => { + const schema = z + .string() + .regex(/^\d+$/) + .transform((val) => Number(val)) + .superRefine((val) => { + if (typeof val !== "number") { + throw new Error("Called without transform"); + } + }); + + const result = schema.safeParse(""); + + expect(result.success).toEqual(false); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/safeparse.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/safeparse.test.ts new file mode 100644 index 0000000..950a2df --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/safeparse.test.ts @@ -0,0 +1,27 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +const stringSchema = z.string(); + +test("safeparse fail", () => { + const safe = stringSchema.safeParse(12); + expect(safe.success).toEqual(false); + expect(safe.error).toBeInstanceOf(z.ZodError); +}); + +test("safeparse pass", () => { + const safe = stringSchema.safeParse("12"); + expect(safe.success).toEqual(true); + expect(safe.data).toEqual("12"); +}); + +test("safeparse unexpected error", () => { + expect(() => + stringSchema + .refine((data) => { + throw new Error(data); + }) + .safeParse("12") + ).toThrow(); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/set.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/set.test.ts new file mode 100644 index 0000000..890cdd2 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/set.test.ts @@ -0,0 +1,142 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { ZodIssueCode } from "zod/v3"; +import { util } from "../helpers/util.js"; + +const stringSet = z.set(z.string()); +type stringSet = z.infer; + +const minTwo = z.set(z.string()).min(2); +const maxTwo = z.set(z.string()).max(2); +const justTwo = z.set(z.string()).size(2); +const nonEmpty = z.set(z.string()).nonempty(); +const nonEmptyMax = z.set(z.string()).nonempty().max(2); + +test("type inference", () => { + util.assertEqual>(true); +}); + +test("valid parse", () => { + const result = stringSet.safeParse(new Set(["first", "second"])); + expect(result.success).toEqual(true); + if (result.success) { + expect(result.data.has("first")).toEqual(true); + expect(result.data.has("second")).toEqual(true); + expect(result.data.has("third")).toEqual(false); + } + + expect(() => { + minTwo.parse(new Set(["a", "b"])); + minTwo.parse(new Set(["a", "b", "c"])); + maxTwo.parse(new Set(["a", "b"])); + maxTwo.parse(new Set(["a"])); + justTwo.parse(new Set(["a", "b"])); + nonEmpty.parse(new Set(["a"])); + nonEmptyMax.parse(new Set(["a"])); + }).not.toThrow(); +}); + +test("valid parse async", async () => { + const result = await stringSet.spa(new Set(["first", "second"])); + expect(result.success).toEqual(true); + if (result.success) { + expect(result.data.has("first")).toEqual(true); + expect(result.data.has("second")).toEqual(true); + expect(result.data.has("third")).toEqual(false); + } + + const asyncResult = await stringSet.safeParse(new Set(["first", "second"])); + expect(asyncResult.success).toEqual(true); + if (asyncResult.success) { + expect(asyncResult.data.has("first")).toEqual(true); + expect(asyncResult.data.has("second")).toEqual(true); + expect(asyncResult.data.has("third")).toEqual(false); + } +}); + +test("valid parse: size-related methods", () => { + expect(() => { + minTwo.parse(new Set(["a", "b"])); + minTwo.parse(new Set(["a", "b", "c"])); + maxTwo.parse(new Set(["a", "b"])); + maxTwo.parse(new Set(["a"])); + justTwo.parse(new Set(["a", "b"])); + nonEmpty.parse(new Set(["a"])); + nonEmptyMax.parse(new Set(["a"])); + }).not.toThrow(); + + const sizeZeroResult = stringSet.parse(new Set()); + expect(sizeZeroResult.size).toBe(0); + + const sizeTwoResult = minTwo.parse(new Set(["a", "b"])); + expect(sizeTwoResult.size).toBe(2); +}); + +test("failing when parsing empty set in nonempty ", () => { + const result = nonEmpty.safeParse(new Set()); + expect(result.success).toEqual(false); + + if (result.success === false) { + expect(result.error.issues.length).toEqual(1); + expect(result.error.issues[0].code).toEqual(ZodIssueCode.too_small); + } +}); + +test("failing when set is smaller than min() ", () => { + const result = minTwo.safeParse(new Set(["just_one"])); + expect(result.success).toEqual(false); + + if (result.success === false) { + expect(result.error.issues.length).toEqual(1); + expect(result.error.issues[0].code).toEqual(ZodIssueCode.too_small); + } +}); + +test("failing when set is bigger than max() ", () => { + const result = maxTwo.safeParse(new Set(["one", "two", "three"])); + expect(result.success).toEqual(false); + + if (result.success === false) { + expect(result.error.issues.length).toEqual(1); + expect(result.error.issues[0].code).toEqual(ZodIssueCode.too_big); + } +}); + +test("doesn’t throw when an empty set is given", () => { + const result = stringSet.safeParse(new Set([])); + expect(result.success).toEqual(true); +}); + +test("throws when a Map is given", () => { + const result = stringSet.safeParse(new Map([])); + expect(result.success).toEqual(false); + if (result.success === false) { + expect(result.error.issues.length).toEqual(1); + expect(result.error.issues[0].code).toEqual(ZodIssueCode.invalid_type); + } +}); + +test("throws when the given set has invalid input", () => { + const result = stringSet.safeParse(new Set([Symbol()])); + expect(result.success).toEqual(false); + if (result.success === false) { + expect(result.error.issues.length).toEqual(1); + expect(result.error.issues[0].code).toEqual(ZodIssueCode.invalid_type); + expect(result.error.issues[0].path).toEqual([0]); + } +}); + +test("throws when the given set has multiple invalid entries", () => { + const result = stringSet.safeParse(new Set([1, 2] as any[]) as Set); + + expect(result.success).toEqual(false); + if (result.success === false) { + expect(result.error.issues.length).toEqual(2); + expect(result.error.issues[0].code).toEqual(ZodIssueCode.invalid_type); + expect(result.error.issues[0].path).toEqual([0]); + expect(result.error.issues[1].code).toEqual(ZodIssueCode.invalid_type); + expect(result.error.issues[1].path).toEqual([1]); + } +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/standard-schema.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/standard-schema.test.ts new file mode 100644 index 0000000..74b3d2b --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/standard-schema.test.ts @@ -0,0 +1,83 @@ +// import type { StandardSchemaV1 } from "@standard-schema/spec"; +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; +import type { StandardSchemaV1 } from "../standard-schema.js"; + +test("assignability", () => { + const _s1: StandardSchemaV1 = z.string(); + const _s2: StandardSchemaV1 = z.string(); + const _s3: StandardSchemaV1 = z.string(); + const _s4: StandardSchemaV1 = z.string(); + [_s1, _s2, _s3, _s4]; +}); + +test("type inference", () => { + const stringToNumber = z.string().transform((x) => x.length); + type input = StandardSchemaV1.InferInput; + util.assertEqual(true); + type output = StandardSchemaV1.InferOutput; + util.assertEqual(true); +}); + +test("valid parse", () => { + const schema = z.string(); + const result = schema["~standard"].validate("hello"); + if (result instanceof Promise) { + throw new Error("Expected sync result"); + } + expect(result.issues).toEqual(undefined); + if (result.issues) { + throw new Error("Expected no issues"); + } else { + expect(result.value).toEqual("hello"); + } +}); + +test("invalid parse", () => { + const schema = z.string(); + const result = schema["~standard"].validate(1234); + if (result instanceof Promise) { + throw new Error("Expected sync result"); + } + expect(result.issues).toBeDefined(); + if (!result.issues) { + throw new Error("Expected issues"); + } + expect(result.issues.length).toEqual(1); + expect(result.issues[0].path).toEqual([]); +}); + +test("valid parse async", async () => { + const schema = z.string().refine(async () => true); + const _result = schema["~standard"].validate("hello"); + if (_result instanceof Promise) { + const result = await _result; + expect(result.issues).toEqual(undefined); + if (result.issues) { + throw new Error("Expected no issues"); + } else { + expect(result.value).toEqual("hello"); + } + } else { + throw new Error("Expected async result"); + } +}); + +test("invalid parse async", async () => { + const schema = z.string().refine(async () => false); + const _result = schema["~standard"].validate("hello"); + if (_result instanceof Promise) { + const result = await _result; + expect(result.issues).toBeDefined(); + if (!result.issues) { + throw new Error("Expected issues"); + } + expect(result.issues.length).toEqual(1); + expect(result.issues[0].path).toEqual([]); + } else { + throw new Error("Expected async result"); + } +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/string.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/string.test.ts new file mode 100644 index 0000000..2d712e1 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/string.test.ts @@ -0,0 +1,916 @@ +import { Buffer } from "node:buffer"; +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +const minFive = z.string().min(5, "min5"); +const maxFive = z.string().max(5, "max5"); +const justFive = z.string().length(5); +const nonempty = z.string().nonempty("nonempty"); +const includes = z.string().includes("includes"); +const includesFromIndex2 = z.string().includes("includes", { position: 2 }); +const startsWith = z.string().startsWith("startsWith"); +const endsWith = z.string().endsWith("endsWith"); + +test("passing validations", () => { + minFive.parse("12345"); + minFive.parse("123456"); + maxFive.parse("12345"); + maxFive.parse("1234"); + nonempty.parse("1"); + justFive.parse("12345"); + includes.parse("XincludesXX"); + includesFromIndex2.parse("XXXincludesXX"); + startsWith.parse("startsWithX"); + endsWith.parse("XendsWith"); +}); + +test("failing validations", () => { + expect(() => minFive.parse("1234")).toThrow(); + expect(() => maxFive.parse("123456")).toThrow(); + expect(() => nonempty.parse("")).toThrow(); + expect(() => justFive.parse("1234")).toThrow(); + expect(() => justFive.parse("123456")).toThrow(); + expect(() => includes.parse("XincludeXX")).toThrow(); + expect(() => includesFromIndex2.parse("XincludesXX")).toThrow(); + expect(() => startsWith.parse("x")).toThrow(); + expect(() => endsWith.parse("x")).toThrow(); +}); + +test("email validations", () => { + const validEmails = [ + `email@domain.com`, + `firstname.lastname@domain.com`, + `email@subdomain.domain.com`, + `firstname+lastname@domain.com`, + `1234567890@domain.com`, + `email@domain-one.com`, + `_______@domain.com`, + `email@domain.name`, + `email@domain.co.jp`, + `firstname-lastname@domain.com`, + `very.common@example.com`, + `disposable.style.email.with+symbol@example.com`, + `other.email-with-hyphen@example.com`, + `fully-qualified-domain@example.com`, + `user.name+tag+sorting@example.com`, + `x@example.com`, + `mojojojo@asdf.example.com`, + `example-indeed@strange-example.com`, + `example@s.example`, + `user-@example.org`, + `user@my-example.com`, + `a@b.cd`, + `work+user@mail.com`, + `tom@test.te-st.com`, + `something@subdomain.domain-with-hyphens.tld`, + `common'name@domain.com`, + `francois@etu.inp-n7.fr`, + ]; + const invalidEmails = [ + // no "printable characters" + // `user%example.com@example.org`, + // `mailhost!username@example.org`, + // `test/test@test.com`, + + // double @ + `francois@@etu.inp-n7.fr`, + // do not support quotes + `"email"@domain.com`, + `"e asdf sadf ?<>ail"@domain.com`, + `" "@example.org`, + `"john..doe"@example.org`, + `"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com`, + // do not support comma + `a,b@domain.com`, + + // do not support IPv4 + `email@123.123.123.123`, + `email@[123.123.123.123]`, + `postmaster@123.123.123.123`, + `user@[68.185.127.196]`, + `ipv4@[85.129.96.247]`, + `valid@[79.208.229.53]`, + `valid@[255.255.255.255]`, + `valid@[255.0.55.2]`, + `valid@[255.0.55.2]`, + + // do not support ipv6 + `hgrebert0@[IPv6:4dc8:ac7:ce79:8878:1290:6098:5c50:1f25]`, + `bshapiro4@[IPv6:3669:c709:e981:4884:59a3:75d1:166b:9ae]`, + `jsmith@[IPv6:2001:db8::1]`, + `postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]`, + `postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:192.168.1.1]`, + + // microsoft test cases + `plainaddress`, + `#@%^%#$@#$@#.com`, + `@domain.com`, + `Joe Smith <email@domain.com>`, + `email.domain.com`, + `email@domain@domain.com`, + `.email@domain.com`, + `email.@domain.com`, + `email..email@domain.com`, + `あいうえお@domain.com`, + `email@domain.com (Joe Smith)`, + `email@domain`, + `email@-domain.com`, + `email@111.222.333.44444`, + `email@domain..com`, + `Abc.example.com`, + `A@b@c@example.com`, + `colin..hacks@domain.com`, + `a"b(c)d,e:f;gi[j\k]l@example.com`, + `just"not"right@example.com`, + `this is"not\allowed@example.com`, + `this\ still\"not\\allowed@example.com`, + + // random + `i_like_underscore@but_its_not_allowed_in_this_part.example.com`, + `QA[icon]CHOCOLATE[icon]@test.com`, + `invalid@-start.com`, + `invalid@end.com-`, + `a.b@c.d`, + `invalid@[1.1.1.-1]`, + `invalid@[68.185.127.196.55]`, + `temp@[192.168.1]`, + `temp@[9.18.122.]`, + `double..point@test.com`, + `asdad@test..com`, + `asdad@hghg...sd...au`, + `asdad@hghg........au`, + `invalid@[256.2.2.48]`, + `invalid@[256.2.2.48]`, + `invalid@[999.465.265.1]`, + `jkibbey4@[IPv6:82c4:19a8::70a9:2aac:557::ea69:d985:28d]`, + `mlivesay3@[9952:143f:b4df:2179:49a1:5e82:b92e:6b6]`, + `gbacher0@[IPv6:bc37:4d3f:5048:2e26:37cc:248e:df8e:2f7f:af]`, + `invalid@[IPv6:5348:4ed3:5d38:67fb:e9b:acd2:c13:192.168.256.1]`, + `test@.com`, + `aaaaaaaaaaaaaaalongemailthatcausesregexDoSvulnerability@test.c`, + ]; + const emailSchema = z.string().email(); + + expect( + validEmails.every((email) => { + return emailSchema.safeParse(email).success; + }) + ).toBe(true); + expect( + invalidEmails.every((email) => { + return emailSchema.safeParse(email).success === false; + }) + ).toBe(true); +}); + +const validBase64Strings = [ + "SGVsbG8gV29ybGQ=", // "Hello World" + "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==", // "This is an encoded string" + "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=", // "Many hands make light work" + "UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // "Patience is the key to success" + "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // "Base64 encoding is fun" + "MTIzNDU2Nzg5MA==", // "1234567890" + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", // "abcdefghijklmnopqrstuvwxyz" + "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "ISIkJSMmJyonKCk=", // "!\"#$%&'()*" + "", // Empty string is technically valid base64 + "w7/Dv8O+w74K", // ÿÿþþ +]; + +for (const str of validBase64Strings) { + test(`base64 should accept ${str}`, () => { + expect(z.string().base64().safeParse(str).success).toBe(true); + }); +} + +const invalidBase64Strings = [ + "12345", // Not padded correctly, not a multiple of 4 characters + "12345===", // Not padded correctly + "SGVsbG8gV29ybGQ", // Missing padding + "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw", // Missing padding + "!UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // Invalid character '!' + "?QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // Invalid character '?' + ".MTIzND2Nzg5MC4=", // Invalid character '.' + "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", // Missing padding + "w7_Dv8O-w74K", // Has - and _ characters (is base64url) +]; + +for (const str of invalidBase64Strings) { + test(`base64 should reject ${str}`, () => { + expect(z.string().base64().safeParse(str).success).toBe(false); + }); +} + +const validBase64URLStrings = [ + "SGVsbG8gV29ybGQ", // "Hello World" + "SGVsbG8gV29ybGQ=", // "Hello World" with padding + "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw", // "This is an encoded string" + "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==", // "This is an encoded string" with padding + "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms", // "Many hands make light work" + "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=", // "Many hands make light work" with padding + "UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // "Patience is the key to success" + "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg", // "Base64 encoding is fun" + "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // "Base64 encoding is fun" with padding + "MTIzNDU2Nzg5MA", // "1234567890" + "MTIzNDU2Nzg5MA==", // "1234567890" with padding + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo", // "abcdefghijklmnopqrstuvwxyz" + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", // "abcdefghijklmnopqrstuvwxyz with padding" + "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" with padding + "ISIkJSMmJyonKCk", // "!\"#$%&'()*" + "ISIkJSMmJyonKCk=", // "!\"#$%&'()*" with padding + "", // Empty string is technically valid base64url + "w7_Dv8O-w74K", // ÿÿþþ + "123456", +]; + +for (const str of validBase64URLStrings) { + test(`base64url should accept ${str}`, () => { + expect(z.string().base64url().safeParse(str).success).toBe(true); + }); +} + +const invalidBase64URLStrings = [ + "w7/Dv8O+w74K", // Has + and / characters (is base64) + "12345", // Invalid length (not a multiple of 4 characters when adding allowed number of padding characters) + "12345===", // Not padded correctly + "!UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // Invalid character '!' + "?QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // Invalid character '?' + ".MTIzND2Nzg5MC4=", // Invalid character '.' +]; + +for (const str of invalidBase64URLStrings) { + test(`base64url should reject ${str}`, () => { + expect(z.string().base64url().safeParse(str).success).toBe(false); + }); +} + +function makeJwt(header: object, payload: object) { + const headerBase64 = Buffer.from(JSON.stringify(header)).toString("base64url"); + const payloadBase64 = Buffer.from(JSON.stringify(payload)).toString("base64url"); + const signature = "signature"; // Placeholder for the signature + return `${headerBase64}.${payloadBase64}.${signature}`; +} + +test("jwt validations", () => { + const jwt = z.string().jwt(); + const jwtWithAlg = z.string().jwt({ alg: "HS256" }); + + expect(() => jwt.parse("invalid")).toThrow(); + expect(() => jwt.parse("invalid.invalid")).toThrow(); + expect(() => jwt.parse("invalid.invalid.invalid")).toThrow(); + + // Valid JWTs + const d1 = makeJwt({ typ: "JWT", alg: "HS256" }, {}); + expect(() => jwt.parse(d1)).not.toThrow(); + expect(() => jwtWithAlg.parse(d1)).not.toThrow(); + + // Invalid header + const d2 = makeJwt({}, {}); + expect(() => jwt.parse(d2)).toThrow(); + + // Wrong algorithm + const d3 = makeJwt({ typ: "JWT", alg: "RS256" }, {}); + expect(() => jwtWithAlg.parse(d3)).toThrow(); + + // missing typ is fine + const d4 = makeJwt({ alg: "HS256" }, {}); + jwt.parse(d4); + + // type isn't JWT + const d5 = makeJwt({ typ: "SUP", alg: "HS256" }, { foo: "bar" }); + expect(() => jwt.parse(d5)).toThrow(); + + // Custom error message + const customMsg = "Invalid JWT token"; + const jwtWithMsg = z.string().jwt({ message: customMsg }); + try { + jwtWithMsg.parse("invalid"); + } catch (error) { + expect((error as z.ZodError).issues[0].message).toBe(customMsg); + } +}); + +test("url validations", () => { + const url = z.string().url(); + url.parse("http://google.com"); + url.parse("https://google.com/asdf?asdf=ljk3lk4&asdf=234#asdf"); + expect(() => url.parse("asdf")).toThrow(); + expect(() => url.parse("https:/")).toThrow(); + expect(() => url.parse("asdfj@lkjsdf.com")).toThrow(); +}); + +test("url error overrides", () => { + try { + z.string().url().parse("https"); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Invalid url"); + } + try { + z.string().url("badurl").parse("https"); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("badurl"); + } + try { + z.string().url({ message: "badurl" }).parse("https"); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("badurl"); + } +}); + +test("emoji validations", () => { + const emoji = z.string().emoji(); + + emoji.parse("👋👋👋👋"); + emoji.parse("🍺👩‍🚀🫡"); + emoji.parse("💚💙💜💛❤️"); + emoji.parse("🐛🗝🐏🍡🎦🚢🏨💫🎌☘🗡😹🔒🎬➡️🍹🗂🚨⚜🕑〽️🚦🌊🍴💍🍌💰😳🌺🍃"); + emoji.parse("🇹🇷🤽🏿‍♂️"); + emoji.parse( + "😀😁😂🤣😃😄😅😆😉😊😋😎😍😘🥰😗😙😚☺️☺🙂🤗🤩🤔🤨😐😑😶🙄😏😣😥😮🤐😯😪😫😴😌😛😜😝🤤😒😓😔😕🙃🤑😲☹️☹🙁😖😞😟😤😢😭😦😧😨😩🤯😬😰😱🥵🥶😳🤪😵😡😠🤬😷🤒🤕🤢🤮🤧😇🤠🥳🥴🥺🤥🤫🤭🧐🤓😈👿🤡👹👺💀☠️☠👻👽👾🤖💩😺😸😹😻😼😽🙀😿😾🙈🙉🙊🏻🏼🏽🏾🏿👶👶🏻👶🏼👶🏽👶🏾👶🏿🧒🧒🏻🧒🏼🧒🏽🧒🏾🧒🏿👦👦🏻👦🏼👦🏽👦🏾👦🏿👧👧🏻👧🏼👧🏽👧🏾👧🏿🧑🧑🏻🧑🏼🧑🏽🧑🏾🧑🏿👨👨🏻👨🏼👨🏽👨🏾👨🏿👩👩🏻👩🏼👩🏽👩🏾👩🏿🧓🧓🏻🧓🏼🧓🏽🧓🏾🧓🏿👴👴🏻👴🏼👴🏽👴🏾👴🏿👵👵🏻👵🏼👵🏽👵🏾👵🏿👨‍⚕️👨‍⚕👨🏻‍⚕️👨🏻‍⚕👨🏼‍⚕️👨🏼‍⚕👨🏽‍⚕️👨🏽‍⚕👨🏾‍⚕️👨🏾‍⚕👨🏿‍⚕️👨🏿‍⚕👩‍⚕️👩‍⚕👩🏻‍⚕️👩🏻‍⚕👩🏼‍⚕️👩🏼‍⚕👩🏽‍⚕️👩🏽‍⚕👩🏾‍⚕️👩🏾‍⚕👩🏿‍⚕️👩🏿‍⚕👨‍🎓👨🏻‍🎓👨🏼‍🎓👨🏽‍🎓👨🏾‍🎓👨🏿‍🎓👩‍🎓👩🏻‍🎓👩🏼‍🎓👩🏽‍🎓👩🏾‍🎓👩🏿‍🎓👨‍🏫👨🏻‍🏫👨🏼‍🏫👨🏽‍🏫👨🏾‍🏫👨🏿‍🏫👩‍🏫👩🏻‍🏫👩🏼‍🏫👩🏽‍🏫👩🏾‍🏫👩🏿‍🏫👨‍⚖️👨‍⚖👨🏻‍⚖️👨🏻‍⚖👨🏼‍⚖️👨🏼‍⚖👨🏽‍⚖️👨🏽‍⚖👨🏾‍⚖️👨🏾‍⚖👨🏿‍⚖️👨🏿‍⚖👩‍⚖️👩‍⚖👩🏻‍⚖️👩🏻‍⚖👩🏼‍⚖️👩🏼‍⚖👩🏽‍⚖️👩🏽‍⚖👩🏾‍⚖️👩🏾‍⚖👩🏿‍⚖️👩🏿‍⚖👨‍🌾👨🏻‍🌾👨🏼‍🌾👨🏽‍🌾👨🏾‍🌾👨🏿‍🌾👩‍🌾👩🏻‍🌾👩🏼‍🌾👩🏽‍🌾👩🏾‍🌾👩🏿‍🌾👨‍🍳👨🏻‍🍳👨🏼‍🍳👨🏽‍🍳👨🏾‍🍳👨🏿‍🍳👩‍🍳👩🏻‍🍳👩🏼‍🍳👩🏽‍🍳👩🏾‍🍳👩🏿‍🍳👨‍🔧👨🏻‍🔧👨🏼‍🔧👨🏽‍🔧👨🏾‍🔧👨🏿‍🔧👩‍🔧👩🏻‍🔧👩🏼‍🔧👩🏽‍🔧👩🏾‍🔧👩🏿‍🔧👨‍🏭👨🏻‍🏭👨🏼‍🏭👨🏽‍🏭👨🏾‍🏭👨🏿‍🏭👩‍🏭👩🏻‍🏭👩🏼‍🏭👩🏽‍🏭👩🏾‍🏭👩🏿‍🏭👨‍💼👨🏻‍💼👨🏼‍💼👨🏽‍💼👨🏾‍💼👨🏿‍💼👩‍💼👩🏻‍💼👩🏼‍💼👩🏽‍💼👩🏾‍💼👩🏿‍💼👨‍🔬👨🏻‍🔬👨🏼‍🔬👨🏽‍🔬👨🏾‍🔬👨🏿‍🔬👩‍🔬👩🏻‍🔬👩🏼‍🔬👩🏽‍🔬👩🏾‍🔬👩🏿‍🔬👨‍💻👨🏻‍💻👨🏼‍💻👨🏽‍💻👨🏾‍💻👨🏿‍💻👩‍💻👩🏻‍💻👩🏼‍💻👩🏽‍💻👩🏾‍💻👩🏿‍💻👨‍🎤👨🏻‍🎤👨🏼‍🎤👨🏽‍🎤👨🏾‍🎤👨🏿‍🎤👩‍🎤👩🏻‍🎤👩🏼‍🎤👩🏽‍🎤👩🏾‍🎤👩🏿‍🎤👨‍🎨👨🏻‍🎨👨🏼‍🎨👨🏽‍🎨👨🏾‍🎨👨🏿‍🎨👩‍🎨👩🏻‍🎨👩🏼‍🎨👩🏽‍🎨👩🏾‍🎨👩🏿‍🎨👨‍✈️👨‍✈👨🏻‍✈️👨🏻‍✈👨🏼‍✈️👨🏼‍✈👨🏽‍✈️👨🏽‍✈👨🏾‍✈️👨🏾‍✈👨🏿‍✈️👨🏿‍✈👩‍✈️👩‍✈👩🏻‍✈️👩🏻‍✈👩🏼‍✈️👩🏼‍✈👩🏽‍✈️👩🏽‍✈👩🏾‍✈️👩🏾‍✈👩🏿‍✈️👩🏿‍✈👨‍🚀👨🏻‍🚀👨🏼‍🚀👨🏽‍🚀👨🏾‍🚀👨🏿‍🚀👩‍🚀👩🏻‍🚀👩🏼‍🚀👩🏽‍🚀👩🏾‍🚀👩🏿‍🚀👨‍🚒👨🏻‍🚒👨🏼‍🚒👨🏽‍🚒👨🏾‍🚒👨🏿‍🚒👩‍🚒👩🏻‍🚒👩🏼‍🚒👩🏽‍🚒👩🏾‍🚒👩🏿‍🚒👮👮🏻👮🏼👮🏽👮🏾👮🏿👮‍♂️👮‍♂👮🏻‍♂️👮🏻‍♂👮🏼‍♂️👮🏼‍♂👮🏽‍♂️👮🏽‍♂👮🏾‍♂️👮🏾‍♂👮🏿‍♂️👮🏿‍♂👮‍♀️👮‍♀👮🏻‍♀️👮🏻‍♀👮🏼‍♀️👮🏼‍♀👮🏽‍♀️👮🏽‍♀👮🏾‍♀️👮🏾‍♀👮🏿‍♀️👮🏿‍♀🕵️🕵🕵🏻🕵🏼🕵🏽🕵🏾🕵🏿🕵️‍♂️🕵‍♂️🕵️‍♂🕵‍♂🕵🏻‍♂️🕵🏻‍♂🕵🏼‍♂️🕵🏼‍♂🕵🏽‍♂️🕵🏽‍♂🕵🏾‍♂️🕵🏾‍♂🕵🏿‍♂️🕵🏿‍♂🕵️‍♀️🕵‍♀️🕵️‍♀🕵‍♀🕵🏻‍♀️🕵🏻‍♀🕵🏼‍♀️🕵🏼‍♀🕵🏽‍♀️🕵🏽‍♀🕵🏾‍♀️🕵🏾‍♀🕵🏿‍♀️🕵🏿‍♀💂💂🏻💂🏼💂🏽💂🏾💂🏿💂‍♂️💂‍♂💂🏻‍♂️💂🏻‍♂💂🏼‍♂️💂🏼‍♂💂🏽‍♂️💂🏽‍♂💂🏾‍♂️💂🏾‍♂💂🏿‍♂️💂🏿‍♂💂‍♀️💂‍♀💂🏻‍♀️💂🏻‍♀💂🏼‍♀️💂🏼‍♀💂🏽‍♀️💂🏽‍♀💂🏾‍♀️💂🏾‍♀💂🏿‍♀️💂🏿‍♀👷👷🏻👷🏼👷🏽👷🏾👷🏿👷‍♂️👷‍♂👷🏻‍♂️👷🏻‍♂👷🏼‍♂️👷🏼‍♂👷🏽‍♂️👷🏽‍♂👷🏾‍♂️👷🏾‍♂👷🏿‍♂️👷🏿‍♂👷‍♀️👷‍♀👷🏻‍♀️👷🏻‍♀👷🏼‍♀️👷🏼‍♀👷🏽‍♀️👷🏽‍♀👷🏾‍♀️👷🏾‍♀👷🏿‍♀️👷🏿‍♀🤴🤴🏻🤴🏼🤴🏽🤴🏾🤴🏿👸👸🏻👸🏼👸🏽👸🏾👸🏿👳👳🏻👳🏼👳🏽👳🏾👳🏿👳‍♂️👳‍♂👳🏻‍♂️👳🏻‍♂👳🏼‍♂️👳🏼‍♂👳🏽‍♂️👳🏽‍♂👳🏾‍♂️👳🏾‍♂👳🏿‍♂️👳🏿‍♂👳‍♀️👳‍♀👳🏻‍♀️👳🏻‍♀👳🏼‍♀️👳🏼‍♀👳🏽‍♀️👳🏽‍♀👳🏾‍♀️👳🏾‍♀👳🏿‍♀️👳🏿‍♀👲👲🏻👲🏼👲🏽👲🏾👲🏿🧕🧕🏻🧕🏼🧕🏽🧕🏾🧕🏿🧔🧔🏻🧔🏼🧔🏽🧔🏾🧔🏿👱👱🏻👱🏼👱🏽👱🏾👱🏿👱‍♂️👱‍♂👱🏻‍♂️👱🏻‍♂👱🏼‍♂️👱🏼‍♂👱🏽‍♂️👱🏽‍♂👱🏾‍♂️👱🏾‍♂👱🏿‍♂️👱🏿‍♂👱‍♀️👱‍♀👱🏻‍♀️👱🏻‍♀👱🏼‍♀️👱🏼‍♀👱🏽‍♀️👱🏽‍♀👱🏾‍♀️👱🏾‍♀👱🏿‍♀️👱🏿‍♀👨‍🦰👨🏻‍🦰👨🏼‍🦰👨🏽‍🦰👨🏾‍🦰👨🏿‍🦰👩‍🦰👩🏻‍🦰👩🏼‍🦰👩🏽‍🦰👩🏾‍🦰👩🏿‍🦰👨‍🦱👨🏻‍🦱👨🏼‍🦱👨🏽‍🦱👨🏾‍🦱👨🏿‍🦱👩‍🦱👩🏻‍🦱👩🏼‍🦱👩🏽‍🦱👩🏾‍🦱👩🏿‍🦱👨‍🦲👨🏻‍🦲👨🏼‍🦲👨🏽‍🦲👨🏾‍🦲👨🏿‍🦲👩‍🦲👩🏻‍🦲👩🏼‍🦲👩🏽‍🦲👩🏾‍🦲👩🏿‍🦲👨‍🦳👨🏻‍🦳👨🏼‍🦳👨🏽‍🦳👨🏾‍🦳👨🏿‍🦳👩‍🦳👩🏻‍🦳👩🏼‍🦳👩🏽‍🦳👩🏾‍🦳👩🏿‍🦳🤵🤵🏻🤵🏼🤵🏽🤵🏾🤵🏿👰👰🏻👰🏼👰🏽👰🏾👰🏿🤰🤰🏻🤰🏼🤰🏽🤰🏾🤰🏿🤱🤱🏻🤱🏼🤱🏽🤱🏾🤱🏿👼👼🏻👼🏼👼🏽👼🏾👼🏿🎅🎅🏻🎅🏼🎅🏽🎅🏾🎅🏿🤶🤶🏻🤶🏼🤶🏽🤶🏾🤶🏿🦸🦸🏻🦸🏼🦸🏽🦸🏾🦸🏿🦸‍♀️🦸‍♀🦸🏻‍♀️🦸🏻‍♀🦸🏼‍♀️🦸🏼‍♀🦸🏽‍♀️🦸🏽‍♀🦸🏾‍♀️🦸🏾‍♀🦸🏿‍♀️🦸🏿‍♀🦸‍♂️🦸‍♂🦸🏻‍♂️🦸🏻‍♂🦸🏼‍♂️🦸🏼‍♂🦸🏽‍♂️🦸🏽‍♂🦸🏾‍♂️🦸🏾‍♂🦸🏿‍♂️🦸🏿‍♂🦹🦹🏻🦹🏼🦹🏽🦹🏾🦹🏿🦹‍♀️🦹‍♀🦹🏻‍♀️🦹🏻‍♀🦹🏼‍♀️🦹🏼‍♀🦹🏽‍♀️🦹🏽‍♀🦹🏾‍♀️🦹🏾‍♀🦹🏿‍♀️🦹🏿‍♀🦹‍♂️🦹‍♂🦹🏻‍♂️🦹🏻‍♂🦹🏼‍♂️🦹🏼‍♂🦹🏽‍♂️🦹🏽‍♂🦹🏾‍♂️🦹🏾‍♂🦹🏿‍♂️🦹🏿‍♂🧙🧙🏻🧙🏼🧙🏽🧙🏾🧙🏿🧙‍♀️🧙‍♀🧙🏻‍♀️🧙🏻‍♀🧙🏼‍♀️🧙🏼‍♀🧙🏽‍♀️🧙🏽‍♀🧙🏾‍♀️🧙🏾‍♀🧙🏿‍♀️🧙🏿‍♀🧙‍♂️🧙‍♂🧙🏻‍♂️🧙🏻‍♂🧙🏼‍♂️🧙🏼‍♂🧙🏽‍♂️🧙🏽‍♂🧙🏾‍♂️🧙🏾‍♂🧙🏿‍♂️🧙🏿‍♂🧚🧚🏻🧚🏼🧚🏽🧚🏾🧚🏿🧚‍♀️🧚‍♀🧚🏻‍♀️🧚🏻‍♀🧚🏼‍♀️🧚🏼‍♀🧚🏽‍♀️🧚🏽‍♀🧚🏾‍♀️🧚🏾‍♀🧚🏿‍♀️🧚🏿‍♀🧚‍♂️🧚‍♂🧚🏻‍♂️🧚🏻‍♂🧚🏼‍♂️🧚🏼‍♂🧚🏽‍♂️🧚🏽‍♂🧚🏾‍♂️🧚🏾‍♂🧚🏿‍♂️🧚🏿‍♂🧛🧛🏻🧛🏼🧛🏽🧛🏾🧛🏿🧛‍♀️🧛‍♀🧛🏻‍♀️🧛🏻‍♀🧛🏼‍♀️🧛🏼‍♀🧛🏽‍♀️🧛🏽‍♀🧛🏾‍♀️🧛🏾‍♀🧛🏿‍♀️🧛🏿‍♀🧛‍♂️🧛‍♂🧛🏻‍♂️🧛🏻‍♂🧛🏼‍♂️🧛🏼‍♂🧛🏽‍♂️🧛🏽‍♂🧛🏾‍♂️🧛🏾‍♂🧛🏿‍♂️🧛🏿‍♂🧜🧜🏻🧜🏼🧜🏽🧜🏾🧜🏿🧜‍♀️🧜‍♀🧜🏻‍♀️🧜🏻‍♀🧜🏼‍♀️🧜🏼‍♀🧜🏽‍♀️🧜🏽‍♀🧜🏾‍♀️🧜🏾‍♀🧜🏿‍♀️🧜🏿‍♀🧜‍♂️🧜‍♂🧜🏻‍♂️🧜🏻‍♂🧜🏼‍♂️🧜🏼‍♂🧜🏽‍♂️🧜🏽‍♂🧜🏾‍♂️🧜🏾‍♂🧜🏿‍♂️🧜🏿‍♂🧝🧝🏻🧝🏼🧝🏽🧝🏾🧝🏿🧝‍♀️🧝‍♀🧝🏻‍♀️🧝🏻‍♀🧝🏼‍♀️🧝🏼‍♀🧝🏽‍♀️🧝🏽‍♀🧝🏾‍♀️🧝🏾‍♀🧝🏿‍♀️🧝🏿‍♀🧝‍♂️🧝‍♂🧝🏻‍♂️🧝🏻‍♂🧝🏼‍♂️🧝🏼‍♂🧝🏽‍♂️🧝🏽‍♂🧝🏾‍♂️🧝🏾‍♂🧝🏿‍♂️🧝🏿‍♂🧞🧞‍♀️🧞‍♀🧞‍♂️🧞‍♂🧟🧟‍♀️🧟‍♀🧟‍♂️🧟‍♂🙍🙍🏻🙍🏼🙍🏽🙍🏾🙍🏿🙍‍♂️🙍‍♂🙍🏻‍♂️🙍🏻‍♂🙍🏼‍♂️🙍🏼‍♂🙍🏽‍♂️🙍🏽‍♂🙍🏾‍♂️🙍🏾‍♂🙍🏿‍♂️🙍🏿‍♂🙍‍♀️🙍‍♀🙍🏻‍♀️🙍🏻‍♀🙍🏼‍♀️🙍🏼‍♀🙍🏽‍♀️🙍🏽‍♀🙍🏾‍♀️🙍🏾‍♀🙍🏿‍♀️🙍🏿‍♀🙎🙎🏻🙎🏼🙎🏽🙎🏾🙎🏿🙎‍♂️🙎‍♂🙎🏻‍♂️🙎🏻‍♂🙎🏼‍♂️🙎🏼‍♂🙎🏽‍♂️🙎🏽‍♂🙎🏾‍♂️🙎🏾‍♂🙎🏿‍♂️🙎🏿‍♂🙎‍♀️🙎‍♀🙎🏻‍♀️🙎🏻‍♀🙎🏼‍♀️🙎🏼‍♀🙎🏽‍♀️🙎🏽‍♀🙎🏾‍♀️🙎🏾‍♀🙎🏿‍♀️🙎🏿‍♀🙅🙅🏻🙅🏼🙅🏽🙅🏾🙅🏿🙅‍♂️🙅‍♂🙅🏻‍♂️🙅🏻‍♂🙅🏼‍♂️🙅🏼‍♂🙅🏽‍♂️🙅🏽‍♂🙅🏾‍♂️🙅🏾‍♂🙅🏿‍♂️🙅🏿‍♂🙅‍♀️🙅‍♀🙅🏻‍♀️🙅🏻‍♀🙅🏼‍♀️🙅🏼‍♀🙅🏽‍♀️🙅🏽‍♀🙅🏾‍♀️🙅🏾‍♀🙅🏿‍♀️🙅🏿‍♀🙆🙆🏻🙆🏼🙆🏽🙆🏾🙆🏿🙆‍♂️🙆‍♂🙆🏻‍♂️🙆🏻‍♂🙆🏼‍♂️🙆🏼‍♂🙆🏽‍♂️🙆🏽‍♂🙆🏾‍♂️🙆🏾‍♂🙆🏿‍♂️🙆🏿‍♂🙆‍♀️🙆‍♀🙆🏻‍♀️🙆🏻‍♀🙆🏼‍♀️🙆🏼‍♀🙆🏽‍♀️🙆🏽‍♀🙆🏾‍♀️🙆🏾‍♀🙆🏿‍♀️🙆🏿‍♀💁💁🏻💁🏼💁🏽💁🏾💁🏿💁‍♂️💁‍♂💁🏻‍♂️💁🏻‍♂💁🏼‍♂️💁🏼‍♂💁🏽‍♂️💁🏽‍♂💁🏾‍♂️💁🏾‍♂💁🏿‍♂️💁🏿‍♂💁‍♀️💁‍♀💁🏻‍♀️💁🏻‍♀💁🏼‍♀️💁🏼‍♀💁🏽‍♀️💁🏽‍♀💁🏾‍♀️💁🏾‍♀💁🏿‍♀️💁🏿‍♀🙋🙋🏻🙋🏼🙋🏽🙋🏾🙋🏿🙋‍♂️🙋‍♂🙋🏻‍♂️🙋🏻‍♂🙋🏼‍♂️🙋🏼‍♂🙋🏽‍♂️🙋🏽‍♂🙋🏾‍♂️🙋🏾‍♂🙋🏿‍♂️🙋🏿‍♂🙋‍♀️🙋‍♀🙋🏻‍♀️🙋🏻‍♀🙋🏼‍♀️🙋🏼‍♀🙋🏽‍♀️🙋🏽‍♀🙋🏾‍♀️🙋🏾‍♀🙋🏿‍♀️🙋🏿‍♀🙇🙇🏻🙇🏼🙇🏽🙇🏾🙇🏿🙇‍♂️🙇‍♂🙇🏻‍♂️🙇🏻‍♂🙇🏼‍♂️🙇🏼‍♂🙇🏽‍♂️🙇🏽‍♂🙇🏾‍♂️🙇🏾‍♂🙇🏿‍♂️🙇🏿‍♂🙇‍♀️🙇‍♀🙇🏻‍♀️🙇🏻‍♀🙇🏼‍♀️🙇🏼‍♀🙇🏽‍♀️🙇🏽‍♀🙇🏾‍♀️🙇🏾‍♀🙇🏿‍♀️🙇🏿‍♀🤦🤦🏻🤦🏼🤦🏽🤦🏾🤦🏿🤦‍♂️🤦‍♂🤦🏻‍♂️🤦🏻‍♂🤦🏼‍♂️🤦🏼‍♂🤦🏽‍♂️🤦🏽‍♂🤦🏾‍♂️🤦🏾‍♂🤦🏿‍♂️🤦🏿‍♂🤦‍♀️🤦‍♀🤦🏻‍♀️🤦🏻‍♀🤦🏼‍♀️🤦🏼‍♀🤦🏽‍♀️🤦🏽‍♀🤦🏾‍♀️🤦🏾‍♀🤦🏿‍♀️🤦🏿‍♀🤷🤷🏻🤷🏼🤷🏽🤷🏾🤷🏿🤷‍♂️🤷‍♂🤷🏻‍♂️🤷🏻‍♂🤷🏼‍♂️🤷🏼‍♂🤷🏽‍♂️🤷🏽‍♂🤷🏾‍♂️🤷🏾‍♂🤷🏿‍♂️🤷🏿‍♂🤷‍♀️🤷‍♀🤷🏻‍♀️🤷🏻‍♀🤷🏼‍♀️🤷🏼‍♀🤷🏽‍♀️🤷🏽‍♀🤷🏾‍♀️🤷🏾‍♀🤷🏿‍♀️🤷🏿‍♀💆💆🏻💆🏼💆🏽💆🏾💆🏿💆‍♂️💆‍♂💆🏻‍♂️💆🏻‍♂💆🏼‍♂️💆🏼‍♂💆🏽‍♂️💆🏽‍♂💆🏾‍♂️💆🏾‍♂💆🏿‍♂️💆🏿‍♂💆‍♀️💆‍♀💆🏻‍♀️💆🏻‍♀💆🏼‍♀️💆🏼‍♀💆🏽‍♀️💆🏽‍♀💆🏾‍♀️💆🏾‍♀💆🏿‍♀️💆🏿‍♀💇💇🏻💇🏼💇🏽💇🏾💇🏿💇‍♂️💇‍♂💇🏻‍♂️💇🏻‍♂💇🏼‍♂️💇🏼‍♂💇🏽‍♂️💇🏽‍♂💇🏾‍♂️💇🏾‍♂💇🏿‍♂️💇🏿‍♂💇‍♀️💇‍♀💇🏻‍♀️💇🏻‍♀💇🏼‍♀️💇🏼‍♀💇🏽‍♀️💇🏽‍♀💇🏾‍♀️💇🏾‍♀💇🏿‍♀️💇🏿‍♀🚶🚶🏻🚶🏼🚶🏽🚶🏾🚶🏿🚶‍♂️🚶‍♂🚶🏻‍♂️🚶🏻‍♂🚶🏼‍♂️🚶🏼‍♂🚶🏽‍♂️🚶🏽‍♂🚶🏾‍♂️🚶🏾‍♂🚶🏿‍♂️🚶🏿‍♂🚶‍♀️🚶‍♀🚶🏻‍♀️🚶🏻‍♀🚶🏼‍♀️🚶🏼‍♀🚶🏽‍♀️🚶🏽‍♀🚶🏾‍♀️🚶🏾‍♀🚶🏿‍♀️🚶🏿‍♀🏃🏃🏻🏃🏼🏃🏽🏃🏾🏃🏿🏃‍♂️🏃‍♂🏃🏻‍♂️🏃🏻‍♂🏃🏼‍♂️🏃🏼‍♂🏃🏽‍♂️🏃🏽‍♂🏃🏾‍♂️🏃🏾‍♂🏃🏿‍♂️🏃🏿‍♂🏃‍♀️🏃‍♀🏃🏻‍♀️🏃🏻‍♀🏃🏼‍♀️🏃🏼‍♀🏃🏽‍♀️🏃🏽‍♀🏃🏾‍♀️🏃🏾‍♀🏃🏿‍♀️🏃🏿‍♀💃💃🏻💃🏼💃🏽💃🏾💃🏿🕺🕺🏻🕺🏼🕺🏽🕺🏾🕺🏿👯👯‍♂️👯‍♂👯‍♀️👯‍♀🧖🧖🏻🧖🏼🧖🏽🧖🏾🧖🏿🧖‍♀️🧖‍♀🧖🏻‍♀️🧖🏻‍♀🧖🏼‍♀️🧖🏼‍♀🧖🏽‍♀️🧖🏽‍♀🧖🏾‍♀️🧖🏾‍♀🧖🏿‍♀️🧖🏿‍♀🧖‍♂️🧖‍♂🧖🏻‍♂️🧖🏻‍♂🧖🏼‍♂️🧖🏼‍♂🧖🏽‍♂️🧖🏽‍♂🧖🏾‍♂️🧖🏾‍♂🧖🏿‍♂️🧖🏿‍♂🧗🧗🏻🧗🏼🧗🏽🧗🏾🧗🏿🧗‍♀️🧗‍♀🧗🏻‍♀️🧗🏻‍♀🧗🏼‍♀️🧗🏼‍♀🧗🏽‍♀️🧗🏽‍♀🧗🏾‍♀️🧗🏾‍♀🧗🏿‍♀️🧗🏿‍♀🧗‍♂️🧗‍♂🧗🏻‍♂️🧗🏻‍♂🧗🏼‍♂️🧗🏼‍♂🧗🏽‍♂️🧗🏽‍♂🧗🏾‍♂️🧗🏾‍♂🧗🏿‍♂️🧗🏿‍♂🧘🧘🏻🧘🏼🧘🏽🧘🏾🧘🏿🧘‍♀️🧘‍♀🧘🏻‍♀️🧘🏻‍♀🧘🏼‍♀️🧘🏼‍♀🧘🏽‍♀️🧘🏽‍♀🧘🏾‍♀️🧘🏾‍♀🧘🏿‍♀️🧘🏿‍♀🧘‍♂️🧘‍♂🧘🏻‍♂️🧘🏻‍♂🧘🏼‍♂️🧘🏼‍♂🧘🏽‍♂️🧘🏽‍♂🧘🏾‍♂️🧘🏾‍♂🧘🏿‍♂️🧘🏿‍♂🛀🛀🏻🛀🏼🛀🏽🛀🏾🛀🏿🛌🛌🏻🛌🏼🛌🏽🛌🏾🛌🏿🕴️🕴🕴🏻🕴🏼🕴🏽🕴🏾🕴🏿🗣️🗣👤👥🤺🏇🏇🏻🏇🏼🏇🏽🏇🏾🏇🏿⛷️⛷🏂🏂🏻🏂🏼🏂🏽🏂🏾🏂🏿🏌️🏌🏌🏻🏌🏼🏌🏽🏌🏾🏌🏿🏌️‍♂️🏌‍♂️🏌️‍♂🏌‍♂🏌🏻‍♂️🏌🏻‍♂🏌🏼‍♂️🏌🏼‍♂🏌🏽‍♂️🏌🏽‍♂🏌🏾‍♂️🏌🏾‍♂🏌🏿‍♂️🏌🏿‍♂🏌️‍♀️🏌‍♀️🏌️‍♀🏌‍♀🏌🏻‍♀️🏌🏻‍♀🏌🏼‍♀️🏌🏼‍♀🏌🏽‍♀️🏌🏽‍♀🏌🏾‍♀️🏌🏾‍♀🏌🏿‍♀️🏌🏿‍♀🏄🏄🏻🏄🏼🏄🏽🏄🏾🏄🏿🏄‍♂️🏄‍♂🏄🏻‍♂️🏄🏻‍♂🏄🏼‍♂️🏄🏼‍♂🏄🏽‍♂️🏄🏽‍♂🏄🏾‍♂️🏄🏾‍♂🏄🏿‍♂️🏄🏿‍♂🏄‍♀️🏄‍♀🏄🏻‍♀️🏄🏻‍♀🏄🏼‍♀️🏄🏼‍♀🏄🏽‍♀️🏄🏽‍♀🏄🏾‍♀️🏄🏾‍♀🏄🏿‍♀️🏄🏿‍♀🚣🚣🏻🚣🏼🚣🏽🚣🏾🚣🏿🚣‍♂️🚣‍♂🚣🏻‍♂️🚣🏻‍♂🚣🏼‍♂️🚣🏼‍♂🚣🏽‍♂️🚣🏽‍♂🚣🏾‍♂️🚣🏾‍♂🚣🏿‍♂️🚣🏿‍♂🚣‍♀️🚣‍♀🚣🏻‍♀️🚣🏻‍♀🚣🏼‍♀️🚣🏼‍♀🚣🏽‍♀️🚣🏽‍♀🚣🏾‍♀️🚣🏾‍♀🚣🏿‍♀️🚣🏿‍♀🏊🏊🏻🏊🏼🏊🏽🏊🏾🏊🏿🏊‍♂️🏊‍♂🏊🏻‍♂️🏊🏻‍♂🏊🏼‍♂️🏊🏼‍♂🏊🏽‍♂️🏊🏽‍♂🏊🏾‍♂️🏊🏾‍♂🏊🏿‍♂️🏊🏿‍♂🏊‍♀️🏊‍♀🏊🏻‍♀️🏊🏻‍♀🏊🏼‍♀️🏊🏼‍♀🏊🏽‍♀️🏊🏽‍♀🏊🏾‍♀️🏊🏾‍♀🏊🏿‍♀️🏊🏿‍♀⛹️⛹⛹🏻⛹🏼⛹🏽⛹🏾⛹🏿⛹️‍♂️⛹‍♂️⛹️‍♂⛹‍♂⛹🏻‍♂️⛹🏻‍♂⛹🏼‍♂️⛹🏼‍♂⛹🏽‍♂️⛹🏽‍♂⛹🏾‍♂️⛹🏾‍♂⛹🏿‍♂️⛹🏿‍♂⛹️‍♀️⛹‍♀️⛹️‍♀⛹‍♀⛹🏻‍♀️⛹🏻‍♀⛹🏼‍♀️⛹🏼‍♀⛹🏽‍♀️⛹🏽‍♀⛹🏾‍♀️⛹🏾‍♀⛹🏿‍♀️⛹🏿‍♀🏋️🏋🏋🏻🏋🏼🏋🏽🏋🏾🏋🏿🏋️‍♂️🏋‍♂️🏋️‍♂🏋‍♂🏋🏻‍♂️🏋🏻‍♂🏋🏼‍♂️🏋🏼‍♂🏋🏽‍♂️🏋🏽‍♂🏋🏾‍♂️🏋🏾‍♂🏋🏿‍♂️🏋🏿‍♂🏋️‍♀️🏋‍♀️🏋️‍♀🏋‍♀🏋🏻‍♀️🏋🏻‍♀🏋🏼‍♀️🏋🏼‍♀🏋🏽‍♀️🏋🏽‍♀🏋🏾‍♀️🏋🏾‍♀🏋🏿‍♀️🏋🏿‍♀🚴🚴🏻🚴🏼🚴🏽🚴🏾🚴🏿🚴‍♂️🚴‍♂🚴🏻‍♂️🚴🏻‍♂🚴🏼‍♂️🚴🏼‍♂🚴🏽‍♂️🚴🏽‍♂🚴🏾‍♂️🚴🏾‍♂🚴🏿‍♂️🚴🏿‍♂🚴‍♀️🚴‍♀🚴🏻‍♀️🚴🏻‍♀🚴🏼‍♀️🚴🏼‍♀🚴🏽‍♀️🚴🏽‍♀🚴🏾‍♀️🚴🏾‍♀🚴🏿‍♀️🚴🏿‍♀🚵🚵🏻🚵🏼🚵🏽🚵🏾🚵🏿🚵‍♂️🚵‍♂🚵🏻‍♂️🚵🏻‍♂🚵🏼‍♂️🚵🏼‍♂🚵🏽‍♂️🚵🏽‍♂🚵🏾‍♂️🚵🏾‍♂🚵🏿‍♂️🚵🏿‍♂🚵‍♀️🚵‍♀🚵🏻‍♀️🚵🏻‍♀🚵🏼‍♀️🚵🏼‍♀🚵🏽‍♀️🚵🏽‍♀🚵🏾‍♀️🚵🏾‍♀🚵🏿‍♀️🚵🏿‍♀🏎️🏎🏍️🏍🤸🤸🏻🤸🏼🤸🏽🤸🏾🤸🏿🤸‍♂️🤸‍♂🤸🏻‍♂️🤸🏻‍♂🤸🏼‍♂️🤸🏼‍♂🤸🏽‍♂️🤸🏽‍♂🤸🏾‍♂️🤸🏾‍♂🤸🏿‍♂️🤸🏿‍♂🤸‍♀️🤸‍♀🤸🏻‍♀️🤸🏻‍♀🤸🏼‍♀️🤸🏼‍♀🤸🏽‍♀️🤸🏽‍♀🤸🏾‍♀️🤸🏾‍♀🤸🏿‍♀️🤸🏿‍♀🤼🤼‍♂️🤼‍♂🤼‍♀️🤼‍♀🤽🤽🏻🤽🏼🤽🏽🤽🏾🤽🏿🤽‍♂️🤽‍♂🤽🏻‍♂️🤽🏻‍♂🤽🏼‍♂️🤽🏼‍♂🤽🏽‍♂️🤽🏽‍♂🤽🏾‍♂️🤽🏾‍♂🤽🏿‍♂️🤽🏿‍♂🤽‍♀️🤽‍♀🤽🏻‍♀️🤽🏻‍♀🤽🏼‍♀️🤽🏼‍♀🤽🏽‍♀️🤽🏽‍♀🤽🏾‍♀️🤽🏾‍♀🤽🏿‍♀️🤽🏿‍♀🤾🤾🏻🤾🏼🤾🏽🤾🏾🤾🏿🤾‍♂️🤾‍♂🤾🏻‍♂️🤾🏻‍♂🤾🏼‍♂️🤾🏼‍♂🤾🏽‍♂️🤾🏽‍♂🤾🏾‍♂️🤾🏾‍♂🤾🏿‍♂️🤾🏿‍♂🤾‍♀️🤾‍♀🤾🏻‍♀️🤾🏻‍♀🤾🏼‍♀️🤾🏼‍♀🤾🏽‍♀️🤾🏽‍♀🤾🏾‍♀️🤾🏾‍♀🤾🏿‍♀️🤾🏿‍♀🤹🤹🏻🤹🏼🤹🏽🤹🏾🤹🏿🤹‍♂️🤹‍♂🤹🏻‍♂️🤹🏻‍♂🤹🏼‍♂️🤹🏼‍♂🤹🏽‍♂️🤹🏽‍♂🤹🏾‍♂️🤹🏾‍♂🤹🏿‍♂️🤹🏿‍♂🤹‍♀️🤹‍♀🤹🏻‍♀️🤹🏻‍♀🤹🏼‍♀️🤹🏼‍♀🤹🏽‍♀️🤹🏽‍♀🤹🏾‍♀️🤹🏾‍♀🤹🏿‍♀️🤹🏿‍♀👫👬👭💏👩‍❤️‍💋‍👨👩‍❤‍💋‍👨👨‍❤️‍💋‍👨👨‍❤‍💋‍👨👩‍❤️‍💋‍👩👩‍❤‍💋‍👩💑👩‍❤️‍👨👩‍❤‍👨👨‍❤️‍👨👨‍❤‍👨👩‍❤️‍👩👩‍❤‍👩👪👨‍👩‍👦👨‍👩‍👧👨‍👩‍👧‍👦👨‍👩‍👦‍👦👨‍👩‍👧‍👧👨‍👨‍👦👨‍👨‍👧👨‍👨‍👧‍👦👨‍👨‍👦‍👦👨‍👨‍👧‍👧👩‍👩‍👦👩‍👩‍👧👩‍👩‍👧‍👦👩‍👩‍👦‍👦👩‍👩‍👧‍👧👨‍👦👨‍👦‍👦👨‍👧👨‍👧‍👦👨‍👧‍👧👩‍👦👩‍👦‍👦👩‍👧👩‍👧‍👦👩‍👧‍👧🤳🤳🏻🤳🏼🤳🏽🤳🏾🤳🏿💪💪🏻💪🏼💪🏽💪🏾💪🏿🦵🦵🏻🦵🏼🦵🏽🦵🏾🦵🏿🦶🦶🏻🦶🏼🦶🏽🦶🏾🦶🏿👈👈🏻👈🏼👈🏽👈🏾👈🏿👉👉🏻👉🏼👉🏽👉🏾👉🏿☝️☝☝🏻☝🏼☝🏽☝🏾☝🏿👆👆🏻👆🏼👆🏽👆🏾👆🏿🖕🖕🏻🖕🏼🖕🏽🖕🏾🖕🏿👇👇🏻👇🏼👇🏽👇🏾👇🏿✌️✌✌🏻✌🏼✌🏽✌🏾✌🏿🤞🤞🏻🤞🏼🤞🏽🤞🏾🤞🏿🖖🖖🏻🖖🏼🖖🏽🖖🏾🖖🏿🤘🤘🏻🤘🏼🤘🏽🤘🏾🤘🏿🤙🤙🏻🤙🏼🤙🏽🤙🏾🤙🏿🖐️🖐🖐🏻🖐🏼🖐🏽🖐🏾🖐🏿✋✋🏻✋🏼✋🏽✋🏾✋🏿👌👌🏻👌🏼👌🏽👌🏾👌🏿👍👍🏻👍🏼👍🏽👍🏾👍🏿👎👎🏻👎🏼👎🏽👎🏾👎🏿✊✊🏻✊🏼✊🏽✊🏾✊🏿👊👊🏻👊🏼👊🏽👊🏾👊🏿🤛🤛🏻🤛🏼🤛🏽🤛🏾🤛🏿🤜🤜🏻🤜🏼🤜🏽🤜🏾🤜🏿🤚🤚🏻🤚🏼🤚🏽🤚🏾🤚🏿👋👋🏻👋🏼👋🏽👋🏾👋🏿🤟🤟🏻🤟🏼🤟🏽🤟🏾🤟🏿✍️✍✍🏻✍🏼✍🏽✍🏾✍🏿👏👏🏻👏🏼👏🏽👏🏾👏🏿👐👐🏻👐🏼👐🏽👐🏾👐🏿🙌🙌🏻🙌🏼🙌🏽🙌🏾🙌🏿🤲🤲🏻🤲🏼🤲🏽🤲🏾🤲🏿🙏🙏🏻🙏🏼🙏🏽🙏🏾🙏🏿🤝💅💅🏻💅🏼💅🏽💅🏾💅🏿👂👂🏻👂🏼👂🏽👂🏾👂🏿👃👃🏻👃🏼👃🏽👃🏾👃🏿🦰🦱🦲🦳👣👀👁️👁👁️‍🗨️👁‍🗨️👁️‍🗨👁‍🗨🧠🦴🦷👅👄💋💘❤️❤💓💔💕💖💗💙💚💛🧡💜🖤💝💞💟❣️❣💌💤💢💣💥💦💨💫💬🗨️🗨🗯️🗯💭🕳️🕳👓🕶️🕶🥽🥼👔👕👖🧣🧤🧥🧦👗👘👙👚👛👜👝🛍️🛍🎒👞👟🥾🥿👠👡👢👑👒🎩🎓🧢⛑️⛑📿💄💍💎🐵🐒🦍🐶🐕🐩🐺🦊🦝🐱🐈🦁🐯🐅🐆🐴🐎🦄🦓🦌🐮🐂🐃🐄🐷🐖🐗🐽🐏🐑🐐🐪🐫🦙🦒🐘🦏🦛🐭🐁🐀🐹🐰🐇🐿️🐿🦔🦇🐻🐨🐼🦘🦡🐾🦃🐔🐓🐣🐤🐥🐦🐧🕊️🕊🦅🦆🦢🦉🦚🦜🐸🐊🐢🦎🐍🐲🐉🦕🦖🐳🐋🐬🐟🐠🐡🦈🐙🐚🦀🦞🦐🦑🐌🦋🐛🐜🐝🐞🦗🕷️🕷🕸️🕸🦂🦟🦠💐🌸💮🏵️🏵🌹🥀🌺🌻🌼🌷🌱🌲🌳🌴🌵🌾🌿☘️☘🍀🍁🍂🍃🍇🍈🍉🍊🍋🍌🍍🥭🍎🍏🍐🍑🍒🍓🥝🍅🥥🥑🍆🥔🥕🌽🌶️🌶🥒🥬🥦🍄🥜🌰🍞🥐🥖🥨🥯🥞🧀🍖🍗🥩🥓🍔🍟🍕🌭🥪🌮🌯🥙🥚🍳🥘🍲🥣🥗🍿🧂🥫🍱🍘🍙🍚🍛🍜🍝🍠🍢🍣🍤🍥🥮🍡🥟🥠🥡🍦🍧🍨🍩🍪🎂🍰🧁🥧🍫🍬🍭🍮🍯🍼🥛☕🍵🍶🍾🍷🍸🍹🍺🍻🥂🥃🥤🥢🍽️🍽🍴🥄🔪🏺🌍🌎🌏🌐🗺️🗺🗾🧭🏔️🏔⛰️⛰🌋🗻🏕️🏕🏖️🏖🏜️🏜🏝️🏝🏞️🏞🏟️🏟🏛️🏛🏗️🏗🧱🏘️🏘🏚️🏚🏠🏡🏢🏣🏤🏥🏦🏨🏩🏪🏫🏬🏭🏯🏰💒🗼🗽⛪🕌🕍⛩️⛩🕋⛲⛺🌁🌃🏙️🏙🌄🌅🌆🌇🌉♨️♨🌌🎠🎡🎢💈🎪🚂🚃🚄🚅🚆🚇🚈🚉🚊🚝🚞🚋🚌🚍🚎🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🚚🚛🚜🚲🛴🛹🛵🚏🛣️🛣🛤️🛤🛢️🛢⛽🚨🚥🚦🛑🚧⚓⛵🛶🚤🛳️🛳⛴️⛴🛥️🛥🚢✈️✈🛩️🛩🛫🛬💺🚁🚟🚠🚡🛰️🛰🚀🛸🛎️🛎🧳⌛⏳⌚⏰⏱️⏱⏲️⏲🕰️🕰🕛🕧🕐🕜🕑🕝🕒🕞🕓🕟🕔🕠🕕🕡🕖🕢🕗🕣🕘🕤🕙🕥🕚🕦🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌡️🌡☀️☀🌝🌞⭐🌟🌠☁️☁⛅⛈️⛈🌤️🌤🌥️🌥🌦️🌦🌧️🌧🌨️🌨🌩️🌩🌪️🌪🌫️🌫🌬️🌬🌀🌈🌂☂️☂☔⛱️⛱⚡❄️❄☃️☃⛄☄️☄🔥💧🌊🎃🎄🎆🎇🧨✨🎈🎉🎊🎋🎍🎎🎏🎐🎑🧧🎀🎁🎗️🎗🎟️🎟🎫🎖️🎖🏆🏅🥇🥈🥉⚽⚾🥎🏀🏐🏈🏉🎾🥏🎳🏏🏑🏒🥍🏓🏸🥊🥋🥅⛳⛸️⛸🎣🎽🎿🛷🥌🎯🎱🔮🧿🎮🕹️🕹🎰🎲🧩🧸♠️♠♥️♥♦️♦♣️♣♟️♟🃏🀄🎴🎭🖼️🖼🎨🧵🧶🔇🔈🔉🔊📢📣📯🔔🔕🎼🎵🎶🎙️🎙🎚️🎚🎛️🎛🎤🎧📻🎷🎸🎹🎺🎻🥁📱📲☎️☎📞📟📠🔋🔌💻🖥️🖥🖨️🖨⌨️⌨🖱️🖱🖲️🖲💽💾💿📀🧮🎥🎞️🎞📽️📽🎬📺📷📸📹📼🔍🔎🕯️🕯💡🔦🏮📔📕📖📗📘📙📚📓📒📃📜📄📰🗞️🗞📑🔖🏷️🏷💰💴💵💶💷💸💳🧾💹💱💲✉️✉📧📨📩📤📥📦📫📪📬📭📮🗳️🗳✏️✏✒️✒🖋️🖋🖊️🖊🖌️🖌🖍️🖍📝💼📁📂🗂️🗂📅📆🗒️🗒🗓️🗓📇📈📉📊📋📌📍📎🖇️🖇📏📐✂️✂🗃️🗃🗄️🗄🗑️🗑🔒🔓🔏🔐🔑🗝️🗝🔨⛏️⛏⚒️⚒🛠️🛠🗡️🗡⚔️⚔🔫🏹🛡️🛡🔧🔩⚙️⚙🗜️🗜⚖️⚖🔗⛓️⛓🧰🧲⚗️⚗🧪🧫🧬🔬🔭📡💉💊🚪🛏️🛏🛋️🛋🚽🚿🛁🧴🧷🧹🧺🧻🧼🧽🧯🛒🚬⚰️⚰⚱️⚱🗿🏧🚮🚰♿🚹🚺🚻🚼🚾🛂🛃🛄🛅⚠️⚠🚸⛔🚫🚳🚭🚯🚱🚷📵🔞☢️☢☣️☣⬆️⬆↗️↗➡️➡↘️↘⬇️⬇↙️↙⬅️⬅↖️↖↕️↕↔️↔↩️↩↪️↪⤴️⤴⤵️⤵🔃🔄🔙🔚🔛🔜🔝🛐⚛️⚛🕉️🕉✡️✡☸️☸☯️☯✝️✝☦️☦☪️☪☮️☮🕎🔯♈♉♊♋♌♍♎♏♐♑♒♓⛎🔀🔁🔂▶️▶⏩⏭️⏭⏯️⏯◀️◀⏪⏮️⏮🔼⏫🔽⏬⏸️⏸⏹️⏹⏺️⏺⏏️⏏🎦🔅🔆📶📳📴♀️♀♂️♂⚕️⚕♾️♾♻️♻⚜️⚜🔱📛🔰⭕✅☑️☑✔️✔✖️✖❌❎➕➖➗➰➿〽️〽✳️✳✴️✴❇️❇‼️‼⁉️⁉❓❔❕❗〰️〰©️©®️®™️™#️⃣#⃣*️⃣*⃣0️⃣0⃣1️⃣1⃣2️⃣2⃣3️⃣3⃣4️⃣4⃣5️⃣5⃣6️⃣6⃣7️⃣7⃣8️⃣8⃣9️⃣9⃣🔟💯🔠🔡🔢🔣🔤🅰️🅰🆎🅱️🅱🆑🆒🆓ℹ️ℹ🆔Ⓜ️Ⓜ🆕🆖🅾️🅾🆗🅿️🅿🆘🆙🆚🈁🈂️🈂🈷️🈷🈶🈯🉐🈹🈚🈲🉑🈸🈴🈳㊗️㊗㊙️㊙🈺🈵▪️▪▫️▫◻️◻◼️◼◽◾⬛⬜🔶🔷🔸🔹🔺🔻💠🔘🔲🔳⚪⚫🔴🔵🏁🚩🎌🏴🏳️🏳🏳️‍🌈🏳‍🌈🏴‍☠️🏴‍☠🇦🇨🇦🇩🇦🇪🇦🇫🇦🇬🇦🇮🇦🇱🇦🇲🇦🇴🇦🇶🇦🇷🇦🇸🇦🇹🇦🇺🇦🇼🇦🇽🇦🇿🇧🇦🇧🇧🇧🇩🇧🇪🇧🇫🇧🇬🇧🇭🇧🇮🇧🇯🇧🇱🇧🇲🇧🇳🇧🇴🇧🇶🇧🇷🇧🇸🇧🇹🇧🇻🇧🇼🇧🇾🇧🇿🇨🇦🇨🇨🇨🇩🇨🇫🇨🇬🇨🇭🇨🇮🇨🇰🇨🇱🇨🇲🇨🇳🇨🇴🇨🇵🇨🇷🇨🇺🇨🇻🇨🇼🇨🇽🇨🇾🇨🇿🇩🇪🇩🇬🇩🇯🇩🇰🇩🇲🇩🇴🇩🇿🇪🇦🇪🇨🇪🇪🇪🇬🇪🇭🇪🇷🇪🇸🇪🇹🇪🇺🇫🇮🇫🇯🇫🇰🇫🇲🇫🇴🇫🇷🇬🇦🇬🇧🇬🇩🇬🇪🇬🇫🇬🇬🇬🇭🇬🇮🇬🇱🇬🇲🇬🇳🇬🇵🇬🇶🇬🇷🇬🇸🇬🇹🇬🇺🇬🇼🇬🇾🇭🇰🇭🇲🇭🇳🇭🇷🇭🇹🇭🇺🇮🇨🇮🇩🇮🇪🇮🇱🇮🇲🇮🇳🇮🇴🇮🇶🇮🇷🇮🇸🇮🇹🇯🇪🇯🇲🇯🇴🇯🇵🇰🇪🇰🇬🇰🇭🇰🇮🇰🇲🇰🇳🇰🇵🇰🇷🇰🇼🇰🇾🇰🇿🇱🇦🇱🇧🇱🇨🇱🇮🇱🇰🇱🇷🇱🇸🇱🇹🇱🇺🇱🇻🇱🇾🇲🇦🇲🇨🇲🇩🇲🇪🇲🇫🇲🇬🇲🇭🇲🇰🇲🇱🇲🇲🇲🇳🇲🇴🇲🇵🇲🇶🇲🇷🇲🇸🇲🇹🇲🇺🇲🇻🇲🇼🇲🇽🇲🇾🇲🇿🇳🇦🇳🇨🇳🇪🇳🇫🇳🇬🇳🇮🇳🇱🇳🇴🇳🇵🇳🇷🇳🇺🇳🇿🇴🇲🇵🇦🇵🇪🇵🇫🇵🇬🇵🇭🇵🇰🇵🇱🇵🇲🇵🇳🇵🇷🇵🇸🇵🇹🇵🇼🇵🇾🇶🇦🇷🇪🇷🇴🇷🇸🇷🇺🇷🇼🇸🇦🇸🇧🇸🇨🇸🇩🇸🇪🇸🇬🇸🇭🇸🇮🇸🇯🇸🇰🇸🇱🇸🇲🇸🇳🇸🇴🇸🇷🇸🇸🇸🇹🇸🇻🇸🇽🇸🇾🇸🇿🇹🇦🇹🇨🇹🇩🇹🇫🇹🇬🇹🇭🇹🇯🇹🇰🇹🇱🇹🇲🇹🇳🇹🇴🇹🇷🇹🇹🇹🇻🇹🇼🇹🇿🇺🇦🇺🇬🇺🇲🇺🇳🇺🇸🇺🇾🇺🇿🇻🇦🇻🇨🇻🇪🇻🇬🇻🇮🇻🇳🇻🇺🇼🇫🇼🇸🇽🇰🇾🇪🇾🇹🇿🇦🇿🇲🇿🇼🏴󠁧󠁢󠁥󠁮󠁧󠁿🏴󠁧󠁢󠁳󠁣󠁴󠁿🏴󠁧󠁢󠁷󠁬󠁳󠁿" + ); + expect(() => emoji.parse(":-)")).toThrow(); + expect(() => emoji.parse("😀 is an emoji")).toThrow(); + expect(() => emoji.parse("😀stuff")).toThrow(); + expect(() => emoji.parse("stuff😀")).toThrow(); +}); + +test("uuid", () => { + const uuid = z.string().uuid("custom error"); + uuid.parse("9491d710-3185-4e06-bea0-6a2f275345e0"); + uuid.parse("d89e7b01-7598-ed11-9d7a-0022489382fd"); // new sequential id + uuid.parse("00000000-0000-0000-0000-000000000000"); + uuid.parse("b3ce60f8-e8b9-40f5-1150-172ede56ff74"); // Variant 0 - RFC 9562/4122: Reserved, NCS backward compatibility + uuid.parse("92e76bf9-28b3-4730-cd7f-cb6bc51f8c09"); // Variant 2 - RFC 9562/4122: Reserved, Microsoft Corporation backward compatibility + const result = uuid.safeParse("9491d710-3185-4e06-bea0-6a2f275345e0X"); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].message).toEqual("custom error"); + } +}); + +test("bad uuid", () => { + const uuid = z.string().uuid("custom error"); + uuid.parse("9491d710-3185-4e06-bea0-6a2f275345e0"); + const result = uuid.safeParse("invalid uuid"); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].message).toEqual("custom error"); + } +}); + +test("nanoid", () => { + const nanoid = z.string().nanoid("custom error"); + nanoid.parse("lfNZluvAxMkf7Q8C5H-QS"); + nanoid.parse("mIU_4PJWikaU8fMbmkouz"); + nanoid.parse("Hb9ZUtUa2JDm_dD-47EGv"); + nanoid.parse("5Noocgv_8vQ9oPijj4ioQ"); + const result = nanoid.safeParse("Xq90uDyhddC53KsoASYJGX"); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].message).toEqual("custom error"); + } +}); + +test("bad nanoid", () => { + const nanoid = z.string().nanoid("custom error"); + nanoid.parse("ySh_984wpDUu7IQRrLXAp"); + const result = nanoid.safeParse("invalid nanoid"); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].message).toEqual("custom error"); + } +}); + +test("cuid", () => { + const cuid = z.string().cuid(); + cuid.parse("ckopqwooh000001la8mbi2im9"); + const result = cuid.safeParse("cifjhdsfhsd-invalid-cuid"); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].message).toEqual("Invalid cuid"); + } +}); + +test("cuid2", () => { + const cuid2 = z.string().cuid2(); + const validStrings = [ + "a", // short string + "tz4a98xxat96iws9zmbrgj3a", // normal string + "kf5vz6ssxe4zjcb409rjgo747tc5qjazgptvotk6", // longer than require("@paralleldrive/cuid2").bigLength + ]; + for (const s of validStrings) { + cuid2.parse(s); + } + + const invalidStrings = [ + "", // empty string + "tz4a98xxat96iws9zMbrgj3a", // include uppercase + "tz4a98xxat96iws-zmbrgj3a", // involve symbols + ]; + const results = invalidStrings.map((s) => cuid2.safeParse(s)); + expect(results.every((r) => !r.success)).toEqual(true); + if (!results[0].success) { + expect(results[0].error.issues[0].message).toEqual("Invalid cuid2"); + } +}); + +test("ulid", () => { + const ulid = z.string().ulid(); + ulid.parse("01ARZ3NDEKTSV4RRFFQ69G5FAV"); + const result = ulid.safeParse("invalidulid"); + expect(result.success).toEqual(false); + const tooLong = "01ARZ3NDEKTSV4RRFFQ69G5FAVA"; + expect(ulid.safeParse(tooLong).success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].message).toEqual("Invalid ulid"); + } + const caseInsensitive = ulid.safeParse("01arZ3nDeKTsV4RRffQ69G5FAV"); + expect(caseInsensitive.success).toEqual(true); +}); + +test("regex", () => { + z.string() + .regex(/^moo+$/) + .parse("mooooo"); + expect(() => z.string().uuid().parse("purr")).toThrow(); +}); + +test("regexp error message", () => { + const result = z + .string() + .regex(/^moo+$/) + .safeParse("boooo"); + if (!result.success) { + expect(result.error.issues[0].message).toEqual("Invalid"); + } else { + throw new Error("validation should have failed"); + } + + expect(() => z.string().uuid().parse("purr")).toThrow(); +}); + +test("regex lastIndex reset", () => { + const schema = z.string().regex(/^\d+$/g); + expect(schema.safeParse("123").success).toEqual(true); + expect(schema.safeParse("123").success).toEqual(true); + expect(schema.safeParse("123").success).toEqual(true); + expect(schema.safeParse("123").success).toEqual(true); + expect(schema.safeParse("123").success).toEqual(true); +}); + +test("checks getters", () => { + expect(z.string().email().isEmail).toEqual(true); + expect(z.string().email().isURL).toEqual(false); + expect(z.string().email().isCUID).toEqual(false); + expect(z.string().email().isCUID2).toEqual(false); + expect(z.string().email().isUUID).toEqual(false); + expect(z.string().email().isNANOID).toEqual(false); + expect(z.string().email().isIP).toEqual(false); + expect(z.string().email().isCIDR).toEqual(false); + expect(z.string().email().isULID).toEqual(false); + + expect(z.string().url().isEmail).toEqual(false); + expect(z.string().url().isURL).toEqual(true); + expect(z.string().url().isCUID).toEqual(false); + expect(z.string().url().isCUID2).toEqual(false); + expect(z.string().url().isUUID).toEqual(false); + expect(z.string().url().isNANOID).toEqual(false); + expect(z.string().url().isIP).toEqual(false); + expect(z.string().url().isCIDR).toEqual(false); + expect(z.string().url().isULID).toEqual(false); + + expect(z.string().cuid().isEmail).toEqual(false); + expect(z.string().cuid().isURL).toEqual(false); + expect(z.string().cuid().isCUID).toEqual(true); + expect(z.string().cuid().isCUID2).toEqual(false); + expect(z.string().cuid().isUUID).toEqual(false); + expect(z.string().cuid().isNANOID).toEqual(false); + expect(z.string().cuid().isIP).toEqual(false); + expect(z.string().cuid().isCIDR).toEqual(false); + expect(z.string().cuid().isULID).toEqual(false); + + expect(z.string().cuid2().isEmail).toEqual(false); + expect(z.string().cuid2().isURL).toEqual(false); + expect(z.string().cuid2().isCUID).toEqual(false); + expect(z.string().cuid2().isCUID2).toEqual(true); + expect(z.string().cuid2().isUUID).toEqual(false); + expect(z.string().cuid2().isNANOID).toEqual(false); + expect(z.string().cuid2().isIP).toEqual(false); + expect(z.string().cuid2().isCIDR).toEqual(false); + expect(z.string().cuid2().isULID).toEqual(false); + + expect(z.string().uuid().isEmail).toEqual(false); + expect(z.string().uuid().isURL).toEqual(false); + expect(z.string().uuid().isCUID).toEqual(false); + expect(z.string().uuid().isCUID2).toEqual(false); + expect(z.string().uuid().isUUID).toEqual(true); + expect(z.string().uuid().isNANOID).toEqual(false); + expect(z.string().uuid().isIP).toEqual(false); + expect(z.string().uuid().isCIDR).toEqual(false); + expect(z.string().uuid().isULID).toEqual(false); + + expect(z.string().nanoid().isEmail).toEqual(false); + expect(z.string().nanoid().isURL).toEqual(false); + expect(z.string().nanoid().isCUID).toEqual(false); + expect(z.string().nanoid().isCUID2).toEqual(false); + expect(z.string().nanoid().isUUID).toEqual(false); + expect(z.string().nanoid().isNANOID).toEqual(true); + expect(z.string().nanoid().isIP).toEqual(false); + expect(z.string().nanoid().isCIDR).toEqual(false); + expect(z.string().nanoid().isULID).toEqual(false); + + expect(z.string().ip().isEmail).toEqual(false); + expect(z.string().ip().isURL).toEqual(false); + expect(z.string().ip().isCUID).toEqual(false); + expect(z.string().ip().isCUID2).toEqual(false); + expect(z.string().ip().isUUID).toEqual(false); + expect(z.string().ip().isNANOID).toEqual(false); + expect(z.string().ip().isIP).toEqual(true); + expect(z.string().ip().isCIDR).toEqual(false); + expect(z.string().ip().isULID).toEqual(false); + + expect(z.string().cidr().isEmail).toEqual(false); + expect(z.string().cidr().isURL).toEqual(false); + expect(z.string().cidr().isCUID).toEqual(false); + expect(z.string().cidr().isCUID2).toEqual(false); + expect(z.string().cidr().isUUID).toEqual(false); + expect(z.string().cidr().isNANOID).toEqual(false); + expect(z.string().cidr().isIP).toEqual(false); + expect(z.string().cidr().isCIDR).toEqual(true); + expect(z.string().cidr().isULID).toEqual(false); + + expect(z.string().ulid().isEmail).toEqual(false); + expect(z.string().ulid().isURL).toEqual(false); + expect(z.string().ulid().isCUID).toEqual(false); + expect(z.string().ulid().isCUID2).toEqual(false); + expect(z.string().ulid().isUUID).toEqual(false); + expect(z.string().ulid().isNANOID).toEqual(false); + expect(z.string().ulid().isIP).toEqual(false); + expect(z.string().ulid().isCIDR).toEqual(false); + expect(z.string().ulid().isULID).toEqual(true); +}); + +test("min max getters", () => { + expect(z.string().min(5).minLength).toEqual(5); + expect(z.string().min(5).min(10).minLength).toEqual(10); + expect(z.string().minLength).toEqual(null); + + expect(z.string().max(5).maxLength).toEqual(5); + expect(z.string().max(5).max(1).maxLength).toEqual(1); + expect(z.string().maxLength).toEqual(null); +}); + +test("trim", () => { + expect(z.string().trim().min(2).parse(" 12 ")).toEqual("12"); + + // ordering of methods is respected + expect(z.string().min(2).trim().parse(" 1 ")).toEqual("1"); + expect(() => z.string().trim().min(2).parse(" 1 ")).toThrow(); +}); + +test("lowerCase", () => { + expect(z.string().toLowerCase().parse("ASDF")).toEqual("asdf"); + expect(z.string().toUpperCase().parse("asdf")).toEqual("ASDF"); +}); + +test("datetime", () => { + const a = z.string().datetime({}); + expect(a.isDatetime).toEqual(true); + + const b = z.string().datetime({ offset: true }); + expect(b.isDatetime).toEqual(true); + + const c = z.string().datetime({ precision: 3 }); + expect(c.isDatetime).toEqual(true); + + const d = z.string().datetime({ offset: true, precision: 0 }); + expect(d.isDatetime).toEqual(true); + + const { isDatetime } = z.string().datetime(); + expect(isDatetime).toEqual(true); +}); + +test("datetime parsing", () => { + const datetime = z.string().datetime(); + datetime.parse("1970-01-01T00:00:00.000Z"); + datetime.parse("2022-10-13T09:52:31.816Z"); + datetime.parse("2022-10-13T09:52:31.8162314Z"); + datetime.parse("1970-01-01T00:00:00Z"); + datetime.parse("2022-10-13T09:52:31Z"); + datetime.parse("2022-10-13T09:52Z"); + expect(() => datetime.parse("")).toThrow(); + expect(() => datetime.parse("foo")).toThrow(); + expect(() => datetime.parse("2020-10-14")).toThrow(); + expect(() => datetime.parse("T18:45:12.123")).toThrow(); + expect(() => datetime.parse("2020-10-14T17:42:29+00:00")).toThrow(); + expect(() => datetime.parse("2020-10-14T17:42.123+00:00")).toThrow(); + + const datetimeNoMs = z.string().datetime({ precision: 0 }); + datetimeNoMs.parse("1970-01-01T00:00:00Z"); + datetimeNoMs.parse("2022-10-13T09:52:31Z"); + datetimeNoMs.parse("2022-10-13T09:52Z"); + expect(() => datetimeNoMs.parse("tuna")).toThrow(); + expect(() => datetimeNoMs.parse("1970-01-01T00:00:00.000Z")).toThrow(); + expect(() => datetimeNoMs.parse("1970-01-01T00:00:00.Z")).toThrow(); + expect(() => datetimeNoMs.parse("2022-10-13T09:52:31.816Z")).toThrow(); + + const datetime3Ms = z.string().datetime({ precision: 3 }); + datetime3Ms.parse("1970-01-01T00:00:00.000Z"); + datetime3Ms.parse("2022-10-13T09:52:31.123Z"); + expect(() => datetime3Ms.parse("tuna")).toThrow(); + expect(() => datetime3Ms.parse("1970-01-01T00:00:00.1Z")).toThrow(); + expect(() => datetime3Ms.parse("1970-01-01T00:00:00.12Z")).toThrow(); + expect(() => datetime3Ms.parse("2022-10-13T09:52:31Z")).toThrow(); + expect(() => datetime3Ms.parse("2022-10-13T09:52Z")).toThrow(); + + const datetimeOffset = z.string().datetime({ offset: true }); + datetimeOffset.parse("1970-01-01T00:00:00.000Z"); + datetimeOffset.parse("2022-10-13T09:52:31.816234134Z"); + datetimeOffset.parse("1970-01-01T00:00:00Z"); + datetimeOffset.parse("2022-10-13T09:52:31.4Z"); + datetimeOffset.parse("2020-10-14T17:42:29+00:00"); + datetimeOffset.parse("2020-10-14T17:42:29+03:15"); + datetimeOffset.parse("2020-10-14T17:42:29+0315"); + datetimeOffset.parse("2020-10-14T17:42+0315"); + expect(() => datetimeOffset.parse("2020-10-14T17:42:29+03")); + expect(() => datetimeOffset.parse("tuna")).toThrow(); + expect(() => datetimeOffset.parse("2022-10-13T09:52:31.Z")).toThrow(); + + const datetimeOffsetNoMs = z.string().datetime({ offset: true, precision: 0 }); + datetimeOffsetNoMs.parse("1970-01-01T00:00:00Z"); + datetimeOffsetNoMs.parse("2022-10-13T09:52:31Z"); + datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00:00"); + datetimeOffsetNoMs.parse("2020-10-14T17:42:29+0000"); + datetimeOffsetNoMs.parse("2020-10-14T17:42+0000"); + expect(() => datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00")).toThrow(); + expect(() => datetimeOffsetNoMs.parse("tuna")).toThrow(); + expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.000Z")).toThrow(); + expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.Z")).toThrow(); + expect(() => datetimeOffsetNoMs.parse("2022-10-13T09:52:31.816Z")).toThrow(); + expect(() => datetimeOffsetNoMs.parse("2020-10-14T17:42:29.124+00:00")).toThrow(); + + const datetimeOffset4Ms = z.string().datetime({ offset: true, precision: 4 }); + datetimeOffset4Ms.parse("1970-01-01T00:00:00.1234Z"); + datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00:00"); + datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+0000"); + expect(() => datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00")).toThrow(); + expect(() => datetimeOffset4Ms.parse("tuna")).toThrow(); + expect(() => datetimeOffset4Ms.parse("1970-01-01T00:00:00.123Z")).toThrow(); + expect(() => datetimeOffset4Ms.parse("2020-10-14T17:42:29.124+00:00")).toThrow(); + expect(() => datetimeOffset4Ms.parse("2020-10-14T17:42+00:00")).toThrow(); +}); + +test("date", () => { + const a = z.string().date(); + expect(a.isDate).toEqual(true); +}); + +test("date parsing", () => { + const date = z.string().date(); + date.parse("1970-01-01"); + date.parse("2022-01-31"); + date.parse("2022-03-31"); + date.parse("2022-04-30"); + date.parse("2022-05-31"); + date.parse("2022-06-30"); + date.parse("2022-07-31"); + date.parse("2022-08-31"); + date.parse("2022-09-30"); + date.parse("2022-10-31"); + date.parse("2022-11-30"); + date.parse("2022-12-31"); + + date.parse("2000-02-29"); + date.parse("2400-02-29"); + expect(() => date.parse("2022-02-29")).toThrow(); + expect(() => date.parse("2100-02-29")).toThrow(); + expect(() => date.parse("2200-02-29")).toThrow(); + expect(() => date.parse("2300-02-29")).toThrow(); + expect(() => date.parse("2500-02-29")).toThrow(); + + expect(() => date.parse("")).toThrow(); + expect(() => date.parse("foo")).toThrow(); + expect(() => date.parse("200-01-01")).toThrow(); + expect(() => date.parse("20000-01-01")).toThrow(); + expect(() => date.parse("2000-0-01")).toThrow(); + expect(() => date.parse("2000-011-01")).toThrow(); + expect(() => date.parse("2000-01-0")).toThrow(); + expect(() => date.parse("2000-01-011")).toThrow(); + expect(() => date.parse("2000/01/01")).toThrow(); + expect(() => date.parse("01-01-2022")).toThrow(); + expect(() => date.parse("01/01/2022")).toThrow(); + expect(() => date.parse("2000-01-01 00:00:00Z")).toThrow(); + expect(() => date.parse("2020-10-14T17:42:29+00:00")).toThrow(); + expect(() => date.parse("2020-10-14T17:42:29Z")).toThrow(); + expect(() => date.parse("2020-10-14T17:42:29")).toThrow(); + expect(() => date.parse("2020-10-14T17:42:29.123Z")).toThrow(); + + expect(() => date.parse("2000-00-12")).toThrow(); + expect(() => date.parse("2000-12-00")).toThrow(); + expect(() => date.parse("2000-01-32")).toThrow(); + expect(() => date.parse("2000-13-01")).toThrow(); + expect(() => date.parse("2000-21-01")).toThrow(); + + expect(() => date.parse("2000-02-30")).toThrow(); + expect(() => date.parse("2000-02-31")).toThrow(); + expect(() => date.parse("2000-04-31")).toThrow(); + expect(() => date.parse("2000-06-31")).toThrow(); + expect(() => date.parse("2000-09-31")).toThrow(); + expect(() => date.parse("2000-11-31")).toThrow(); +}); + +test("time", () => { + const a = z.string().time(); + expect(a.isTime).toEqual(true); +}); + +test("time parsing", () => { + const time = z.string().time(); + time.parse("00:00:00"); + time.parse("23:00:00"); + time.parse("00:59:00"); + time.parse("00:00:59"); + time.parse("23:59:59"); + time.parse("09:52:31"); + time.parse("23:59:59.9999999"); + time.parse("23:59"); + expect(() => time.parse("")).toThrow(); + expect(() => time.parse("foo")).toThrow(); + expect(() => time.parse("00:00:00Z")).toThrow(); + expect(() => time.parse("0:00:00")).toThrow(); + expect(() => time.parse("00:0:00")).toThrow(); + expect(() => time.parse("00:00:0")).toThrow(); + expect(() => time.parse("00:00:00.000+00:00")).toThrow(); + + expect(() => time.parse("24:00:00")).toThrow(); + expect(() => time.parse("00:60:00")).toThrow(); + expect(() => time.parse("00:00:60")).toThrow(); + expect(() => time.parse("24:60:60")).toThrow(); + expect(() => time.parse("24:60")).toThrow(); + + const time2 = z.string().time({ precision: 2 }); + time2.parse("00:00:00.00"); + time2.parse("09:52:31.12"); + time2.parse("23:59:59.99"); + expect(() => time2.parse("")).toThrow(); + expect(() => time2.parse("foo")).toThrow(); + expect(() => time2.parse("00:00:00")).toThrow(); + expect(() => time2.parse("00:00:00.00Z")).toThrow(); + expect(() => time2.parse("00:00:00.0")).toThrow(); + expect(() => time2.parse("00:00:00.000")).toThrow(); + expect(() => time2.parse("00:00:00.00+00:00")).toThrow(); + expect(() => time2.parse("23:59")).toThrow(); + + // const time3 = z.string().time({ offset: true }); + // time3.parse("00:00:00Z"); + // time3.parse("09:52:31Z"); + // time3.parse("00:00:00+00:00"); + // time3.parse("00:00:00+0000"); + // time3.parse("00:00:00.000Z"); + // time3.parse("00:00:00.000+00:00"); + // time3.parse("00:00:00.000+0000"); + // expect(() => time3.parse("")).toThrow(); + // expect(() => time3.parse("foo")).toThrow(); + // expect(() => time3.parse("00:00:00")).toThrow(); + // expect(() => time3.parse("00:00:00.000")).toThrow(); + + // const time4 = z.string().time({ offset: true, precision: 0 }); + // time4.parse("00:00:00Z"); + // time4.parse("09:52:31Z"); + // time4.parse("00:00:00+00:00"); + // time4.parse("00:00:00+0000"); + // expect(() => time4.parse("")).toThrow(); + // expect(() => time4.parse("foo")).toThrow(); + // expect(() => time4.parse("00:00:00.0")).toThrow(); + // expect(() => time4.parse("00:00:00.000")).toThrow(); + // expect(() => time4.parse("00:00:00.000+00:00")).toThrow(); +}); + +test("duration", () => { + const duration = z.string().duration(); + expect(duration.isDuration).toEqual(true); + + const validDurations = [ + "P3Y6M4DT12H30M5S", + "P2Y9M3DT12H31M8.001S", + "+P3Y6M4DT12H30M5S", + "-PT0.001S", + "+PT0.001S", + "PT0,001S", + "PT12H30M5S", + "-P2M1D", + "P-2M-1D", + "-P5DT10H", + "P-5DT-10H", + "P1Y", + "P2MT30M", + "PT6H", + "P5W", + "P0.5Y", + "P0,5Y", + "P42YT7.004M", + ]; + + const invalidDurations = ["foo bar", "", " ", "P", "T1H", "P0.5Y1D", "P0,5Y6M", "P1YT"]; + + for (const val of validDurations) { + const result = duration.safeParse(val); + if (!result.success) { + throw Error(`Valid duration could not be parsed: ${val}`); + } + } + + for (const val of invalidDurations) { + const result = duration.safeParse(val); + + if (result.success) { + throw Error(`Invalid duration was successful parsed: ${val}`); + } + + expect(result.error.issues[0].message).toEqual("Invalid duration"); + } +}); + +test("IP validation", () => { + const ip = z.string().ip(); + expect(ip.safeParse("122.122.122.122").success).toBe(true); + + const ipv4 = z.string().ip({ version: "v4" }); + expect(() => ipv4.parse("6097:adfa:6f0b:220d:db08:5021:6191:7990")).toThrow(); + + const ipv6 = z.string().ip({ version: "v6" }); + expect(() => ipv6.parse("254.164.77.1")).toThrow(); + + const validIPs = [ + "1e5e:e6c8:daac:514b:114b:e360:d8c0:682c", + "9d4:c956:420f:5788:4339:9b3b:2418:75c3", + "474f:4c83::4e40:a47:ff95:0cda", + "d329:0:25b4:db47:a9d1:0:4926:0000", + "e48:10fb:1499:3e28:e4b6:dea5:4692:912c", + "114.71.82.94", + "0.0.0.0", + "37.85.236.115", + "2001:4888:50:ff00:500:d::", + "2001:4888:50:ff00:0500:000d:000:0000", + "2001:4888:50:ff00:0500:000d:0000:0000", + ]; + + const invalidIPs = [ + "d329:1be4:25b4:db47:a9d1:dc71:4926:992c:14af", + "d5e7:7214:2b78::3906:85e6:53cc:709:32ba", + "8f69::c757:395e:976e::3441", + "54cb::473f:d516:0.255.256.22", + "54cb::473f:d516:192.168.1", + "256.0.4.4", + "-1.0.555.4", + "0.0.0.0.0", + "1.1.1", + ]; + // no parameters check IPv4 or IPv6 + const ipSchema = z.string().ip(); + expect(validIPs.every((ip) => ipSchema.safeParse(ip).success)).toBe(true); + expect(invalidIPs.every((ip) => ipSchema.safeParse(ip).success === false)).toBe(true); +}); + +test("CIDR validation", () => { + const ipv4Cidr = z.string().cidr({ version: "v4" }); + expect(() => ipv4Cidr.parse("2001:0db8:85a3::8a2e:0370:7334/64")).toThrow(); + + const ipv6Cidr = z.string().cidr({ version: "v6" }); + expect(() => ipv6Cidr.parse("192.168.0.1/24")).toThrow(); + + const validCidrs = [ + "192.168.0.0/24", + "10.0.0.0/8", + "203.0.113.0/24", + "192.0.2.0/24", + "127.0.0.0/8", + "172.16.0.0/12", + "192.168.1.0/24", + "fc00::/7", + "fd00::/8", + "2001:db8::/32", + "2607:f0d0:1002:51::4/64", + "2001:0db8:85a3:0000:0000:8a2e:0370:7334/128", + "2001:0db8:1234:0000::/64", + ]; + + const invalidCidrs = [ + "192.168.1.1/33", + "10.0.0.1/-1", + "192.168.1.1/24/24", + "192.168.1.0/abc", + "2001:db8::1/129", + "2001:db8::1/-1", + "2001:db8::1/64/64", + "2001:db8::1/abc", + ]; + + // no parameters check IPv4 or IPv6 + const cidrSchema = z.string().cidr(); + expect(validCidrs.every((ip) => cidrSchema.safeParse(ip).success)).toBe(true); + expect(invalidCidrs.every((ip) => cidrSchema.safeParse(ip).success === false)).toBe(true); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/transformer.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/transformer.test.ts new file mode 100644 index 0000000..ddd9e9a --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/transformer.test.ts @@ -0,0 +1,233 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; + +const stringToNumber = z.string().transform((arg) => Number.parseFloat(arg)); +// const numberToString = z +// .transformer(z.number()) +// .transform((n) => String(n)); +const asyncNumberToString = z.number().transform(async (n) => String(n)); + +test("transform ctx.addIssue with parse", () => { + const strs = ["foo", "bar"]; + + expect(() => { + z.string() + .transform((data, ctx) => { + const i = strs.indexOf(data); + if (i === -1) { + ctx.addIssue({ + code: "custom", + message: `${data} is not one of our allowed strings`, + }); + } + return data.length; + }) + .parse("asdf"); + }).toThrow( + JSON.stringify( + [ + { + code: "custom", + message: "asdf is not one of our allowed strings", + path: [], + }, + ], + null, + 2 + ) + ); +}); + +test("transform ctx.addIssue with parseAsync", async () => { + const strs = ["foo", "bar"]; + + const result = await z + .string() + .transform(async (data, ctx) => { + const i = strs.indexOf(data); + if (i === -1) { + ctx.addIssue({ + code: "custom", + message: `${data} is not one of our allowed strings`, + }); + } + return data.length; + }) + .safeParseAsync("asdf"); + + expect(JSON.parse(JSON.stringify(result))).toEqual({ + success: false, + error: { + issues: [ + { + code: "custom", + message: "asdf is not one of our allowed strings", + path: [], + }, + ], + name: "ZodError", + }, + }); +}); + +test("z.NEVER in transform", () => { + const foo = z + .number() + .optional() + .transform((val, ctx) => { + if (!val) { + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "bad" }); + return z.NEVER; + } + return val; + }); + type foo = z.infer; + util.assertEqual(true); + const arg = foo.safeParse(undefined); + if (!arg.success) { + expect(arg.error.issues[0].message).toEqual("bad"); + } +}); + +test("basic transformations", () => { + const r1 = z + .string() + .transform((data) => data.length) + .parse("asdf"); + expect(r1).toEqual(4); +}); + +test("coercion", () => { + const numToString = z.number().transform((n) => String(n)); + const data = z + .object({ + id: numToString, + }) + .parse({ id: 5 }); + + expect(data).toEqual({ id: "5" }); +}); + +test("async coercion", async () => { + const numToString = z.number().transform(async (n) => String(n)); + const data = await z + .object({ + id: numToString, + }) + .parseAsync({ id: 5 }); + + expect(data).toEqual({ id: "5" }); +}); + +test("sync coercion async error", async () => { + expect(() => + z + .object({ + id: asyncNumberToString, + }) + .parse({ id: 5 }) + ).toThrow(); + // expect(data).toEqual({ id: '5' }); +}); + +test("default", () => { + const data = z.string().default("asdf").parse(undefined); // => "asdf" + expect(data).toEqual("asdf"); +}); + +test("dynamic default", () => { + const data = z + .string() + .default(() => "string") + .parse(undefined); // => "asdf" + expect(data).toEqual("string"); +}); + +test("default when property is null or undefined", () => { + const data = z + .object({ + foo: z.boolean().nullable().default(true), + bar: z.boolean().default(true), + }) + .parse({ foo: null }); + + expect(data).toEqual({ foo: null, bar: true }); +}); + +test("default with falsy values", () => { + const schema = z.object({ + emptyStr: z.string().default("def"), + zero: z.number().default(5), + falseBoolean: z.boolean().default(true), + }); + const input = { emptyStr: "", zero: 0, falseBoolean: true }; + const output = schema.parse(input); + // defaults are not supposed to be used + expect(output).toEqual(input); +}); + +test("object typing", () => { + const t1 = z.object({ + stringToNumber, + }); + + type t1 = z.input; + type t2 = z.output; + + util.assertEqual(true); + util.assertEqual(true); +}); + +test("transform method overloads", () => { + const t1 = z.string().transform((val) => val.toUpperCase()); + expect(t1.parse("asdf")).toEqual("ASDF"); + + const t2 = z.string().transform((val) => val.length); + expect(t2.parse("asdf")).toEqual(4); +}); + +test("multiple transformers", () => { + const doubler = stringToNumber.transform((val) => { + return val * 2; + }); + expect(doubler.parse("5")).toEqual(10); +}); + +test("short circuit on dirty", () => { + const schema = z + .string() + .refine(() => false) + .transform((val) => val.toUpperCase()); + const result = schema.safeParse("asdf"); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.custom); + } + + const result2 = schema.safeParse(1234); + expect(result2.success).toEqual(false); + if (!result2.success) { + expect(result2.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_type); + } +}); + +test("async short circuit on dirty", async () => { + const schema = z + .string() + .refine(() => false) + .transform((val) => val.toUpperCase()); + const result = await schema.spa("asdf"); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.custom); + } + + const result2 = await schema.spa(1234); + expect(result2.success).toEqual(false); + if (!result2.success) { + expect(result2.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_type); + } +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/tuple.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/tuple.test.ts new file mode 100644 index 0000000..e525d3f --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/tuple.test.ts @@ -0,0 +1,90 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { ZodError } from "../ZodError.js"; +import { util } from "../helpers/util.js"; + +const testTuple = z.tuple([z.string(), z.object({ name: z.literal("Rudy") }), z.array(z.literal("blue"))]); +const testData = ["asdf", { name: "Rudy" }, ["blue"]]; +const badData = [123, { name: "Rudy2" }, ["blue", "red"]]; + +test("tuple inference", () => { + const args1 = z.tuple([z.string()]); + const returns1 = z.number(); + const func1 = z.function(args1, returns1); + type func1 = z.TypeOf; + util.assertEqual number>(true); +}); + +test("successful validation", () => { + const val = testTuple.parse(testData); + expect(val).toEqual(["asdf", { name: "Rudy" }, ["blue"]]); +}); + +test("successful async validation", async () => { + const val = await testTuple.parseAsync(testData); + return expect(val).toEqual(testData); +}); + +test("failed validation", () => { + const checker = () => { + testTuple.parse([123, { name: "Rudy2" }, ["blue", "red"]] as any); + }; + try { + checker(); + } catch (err) { + if (err instanceof ZodError) { + expect(err.issues.length).toEqual(3); + } + } +}); + +test("failed async validation", async () => { + const res = await testTuple.safeParse(badData); + expect(res.success).toEqual(false); + if (!res.success) { + expect(res.error.issues.length).toEqual(3); + } + // try { + // checker(); + // } catch (err) { + // if (err instanceof ZodError) { + // expect(err.issues.length).toEqual(3); + // } + // } +}); + +test("tuple with transformers", () => { + const stringToNumber = z.string().transform((val) => val.length); + const val = z.tuple([stringToNumber]); + + type t1 = z.input; + util.assertEqual(true); + type t2 = z.output; + util.assertEqual(true); + expect(val.parse(["1234"])).toEqual([4]); +}); + +test("tuple with rest schema", () => { + const myTuple = z.tuple([z.string(), z.number()]).rest(z.boolean()); + expect(myTuple.parse(["asdf", 1234, true, false, true])).toEqual(["asdf", 1234, true, false, true]); + + expect(myTuple.parse(["asdf", 1234])).toEqual(["asdf", 1234]); + + expect(() => myTuple.parse(["asdf", 1234, "asdf"])).toThrow(); + type t1 = z.output; + + util.assertEqual(true); +}); + +test("parse should fail given sparse array as tuple", () => { + expect(() => testTuple.parse(new Array(3))).toThrow(); +}); + +// test('tuple with optional elements', () => { +// const result = z +// .tuple([z.string(), z.number().optional()]) +// .safeParse(['asdf']); +// expect(result).toEqual(['asdf']); +// }); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/unions.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/unions.test.ts new file mode 100644 index 0000000..2c3dc67 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/unions.test.ts @@ -0,0 +1,57 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +test("function parsing", () => { + const schema = z.union([z.string().refine(() => false), z.number().refine(() => false)]); + const result = schema.safeParse("asdf"); + expect(result.success).toEqual(false); +}); + +test("union 2", () => { + const result = z.union([z.number(), z.string().refine(() => false)]).safeParse("a"); + expect(result.success).toEqual(false); +}); + +test("return valid over invalid", () => { + const schema = z.union([ + z.object({ + email: z.string().email(), + }), + z.string(), + ]); + expect(schema.parse("asdf")).toEqual("asdf"); + expect(schema.parse({ email: "asdlkjf@lkajsdf.com" })).toEqual({ + email: "asdlkjf@lkajsdf.com", + }); +}); + +test("return dirty result over aborted", () => { + const result = z.union([z.number(), z.string().refine(() => false)]).safeParse("a"); + expect(result.success).toEqual(false); + if (!result.success) { + expect(result.error.issues).toEqual([ + { + code: "custom", + message: "Invalid input", + path: [], + }, + ]); + } +}); + +test("options getter", async () => { + const union = z.union([z.string(), z.number()]); + union.options[0].parse("asdf"); + union.options[1].parse(1234); + await union.options[0].parseAsync("asdf"); + await union.options[1].parseAsync(1234); +}); + +test("readonly union", async () => { + const options = [z.string(), z.number()] as const; + const union = z.union(options); + union.parse("asdf"); + union.parse(12); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/validations.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/validations.test.ts new file mode 100644 index 0000000..66f41da --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/validations.test.ts @@ -0,0 +1,133 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; + +test("array min", async () => { + try { + await z.array(z.string()).min(4).parseAsync([]); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Array must contain at least 4 element(s)"); + } +}); + +test("array max", async () => { + try { + await z.array(z.string()).max(2).parseAsync(["asdf", "asdf", "asdf"]); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Array must contain at most 2 element(s)"); + } +}); + +test("array length", async () => { + try { + await z.array(z.string()).length(2).parseAsync(["asdf", "asdf", "asdf"]); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Array must contain exactly 2 element(s)"); + } + + try { + await z.array(z.string()).length(2).parseAsync(["asdf"]); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Array must contain exactly 2 element(s)"); + } +}); + +test("string length", async () => { + try { + await z.string().length(4).parseAsync("asd"); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("String must contain exactly 4 character(s)"); + } + + try { + await z.string().length(4).parseAsync("asdaa"); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("String must contain exactly 4 character(s)"); + } +}); + +test("string min", async () => { + try { + await z.string().min(4).parseAsync("asd"); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("String must contain at least 4 character(s)"); + } +}); + +test("string max", async () => { + try { + await z.string().max(4).parseAsync("aasdfsdfsd"); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("String must contain at most 4 character(s)"); + } +}); + +test("number min", async () => { + try { + await z.number().gte(3).parseAsync(2); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Number must be greater than or equal to 3"); + } +}); + +test("number max", async () => { + try { + await z.number().lte(3).parseAsync(4); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Number must be less than or equal to 3"); + } +}); + +test("number nonnegative", async () => { + try { + await z.number().nonnegative().parseAsync(-1); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Number must be greater than or equal to 0"); + } +}); + +test("number nonpositive", async () => { + try { + await z.number().nonpositive().parseAsync(1); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Number must be less than or equal to 0"); + } +}); + +test("number negative", async () => { + try { + await z.number().negative().parseAsync(1); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Number must be less than 0"); + } +}); + +test("number positive", async () => { + try { + await z.number().positive().parseAsync(-1); + } catch (err) { + expect((err as z.ZodError).issues[0].message).toEqual("Number must be greater than 0"); + } +}); + +test("instantiation", () => { + z.string().min(5); + z.string().max(5); + z.string().length(5); + z.string().email(); + z.string().url(); + z.string().uuid(); + z.string().min(5, { message: "Must be 5 or more characters long" }); + z.string().max(5, { message: "Must be 5 or fewer characters long" }); + z.string().length(5, { message: "Must be exactly 5 characters long" }); + z.string().email({ message: "Invalid email address." }); + z.string().url({ message: "Invalid url" }); + z.string().uuid({ message: "Invalid UUID" }); +}); + +test("int", async () => { + const int = z.number().int(); + int.parse(4); + expect(() => int.parse(3.5)).toThrow(); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/void.test.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/void.test.ts new file mode 100644 index 0000000..b128f11 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/tests/void.test.ts @@ -0,0 +1,15 @@ +// @ts-ignore TS6133 +import { expect, test } from "vitest"; + +import * as z from "zod/v3"; +import { util } from "../helpers/util.js"; +test("void", () => { + const v = z.void(); + v.parse(undefined); + + expect(() => v.parse(null)).toThrow(); + expect(() => v.parse("")).toThrow(); + + type v = z.infer; + util.assertEqual(true); +}); diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/types.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/types.ts new file mode 100644 index 0000000..f402854 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v3/types.ts @@ -0,0 +1,5138 @@ +import { + type IssueData, + type StringValidation, + type ZodCustomIssue, + ZodError, + type ZodErrorMap, + type ZodIssue, + ZodIssueCode, +} from "./ZodError.js"; +import { defaultErrorMap, getErrorMap } from "./errors.js"; +import type { enumUtil } from "./helpers/enumUtil.js"; +import { errorUtil } from "./helpers/errorUtil.js"; +import { + type AsyncParseReturnType, + DIRTY, + INVALID, + OK, + type ParseContext, + type ParseInput, + type ParseParams, + type ParsePath, + type ParseReturnType, + ParseStatus, + type SyncParseReturnType, + addIssueToContext, + isAborted, + isAsync, + isDirty, + isValid, + makeIssue, +} from "./helpers/parseUtil.js"; +import type { partialUtil } from "./helpers/partialUtil.js"; +import type { Primitive } from "./helpers/typeAliases.js"; +import { util, ZodParsedType, getParsedType, type objectUtil } from "./helpers/util.js"; +import type { StandardSchemaV1 } from "./standard-schema.js"; + +/////////////////////////////////////// +/////////////////////////////////////// +////////// ////////// +////////// ZodType ////////// +////////// ////////// +/////////////////////////////////////// +/////////////////////////////////////// + +export interface RefinementCtx { + addIssue: (arg: IssueData) => void; + path: (string | number)[]; +} +export type ZodRawShape = { [k: string]: ZodTypeAny }; +export type ZodTypeAny = ZodType; +export type TypeOf> = T["_output"]; +export type input> = T["_input"]; +export type output> = T["_output"]; +export type { TypeOf as infer }; + +export type CustomErrorParams = Partial>; +export interface ZodTypeDef { + errorMap?: ZodErrorMap | undefined; + description?: string | undefined; +} + +class ParseInputLazyPath implements ParseInput { + parent: ParseContext; + data: any; + _path: ParsePath; + _key: string | number | (string | number)[]; + _cachedPath: ParsePath = []; + constructor(parent: ParseContext, value: any, path: ParsePath, key: string | number | (string | number)[]) { + this.parent = parent; + this.data = value; + this._path = path; + this._key = key; + } + get path() { + if (!this._cachedPath.length) { + if (Array.isArray(this._key)) { + this._cachedPath.push(...this._path, ...this._key); + } else { + this._cachedPath.push(...this._path, this._key); + } + } + + return this._cachedPath; + } +} + +const handleResult = ( + ctx: ParseContext, + result: SyncParseReturnType +): { success: true; data: Output } | { success: false; error: ZodError } => { + if (isValid(result)) { + return { success: true, data: result.value }; + } else { + if (!ctx.common.issues.length) { + throw new Error("Validation failed but no issues detected."); + } + + return { + success: false, + get error() { + if ((this as any)._error) return (this as any)._error as Error; + const error = new ZodError(ctx.common.issues); + (this as any)._error = error; + return (this as any)._error; + }, + }; + } +}; + +export type RawCreateParams = + | { + errorMap?: ZodErrorMap | undefined; + invalid_type_error?: string | undefined; + required_error?: string | undefined; + message?: string | undefined; + description?: string | undefined; + } + | undefined; +export type ProcessedCreateParams = { + errorMap?: ZodErrorMap | undefined; + description?: string | undefined; +}; +function processCreateParams(params: RawCreateParams): ProcessedCreateParams { + if (!params) return {}; + const { errorMap, invalid_type_error, required_error, description } = params; + if (errorMap && (invalid_type_error || required_error)) { + throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`); + } + if (errorMap) return { errorMap: errorMap, description }; + const customMap: ZodErrorMap = (iss, ctx) => { + const { message } = params; + + if (iss.code === "invalid_enum_value") { + return { message: message ?? ctx.defaultError }; + } + if (typeof ctx.data === "undefined") { + return { message: message ?? required_error ?? ctx.defaultError }; + } + if (iss.code !== "invalid_type") return { message: ctx.defaultError }; + return { message: message ?? invalid_type_error ?? ctx.defaultError }; + }; + return { errorMap: customMap, description }; +} + +export type SafeParseSuccess = { + success: true; + data: Output; + error?: never; +}; +export type SafeParseError = { + success: false; + error: ZodError; + data?: never; +}; + +export type SafeParseReturnType = SafeParseSuccess | SafeParseError; + +export abstract class ZodType { + readonly _type!: Output; + readonly _output!: Output; + readonly _input!: Input; + readonly _def!: Def; + + get description(): string | undefined { + return this._def.description; + } + + "~standard": StandardSchemaV1.Props; + + abstract _parse(input: ParseInput): ParseReturnType; + + _getType(input: ParseInput): string { + return getParsedType(input.data); + } + + _getOrReturnCtx(input: ParseInput, ctx?: ParseContext | undefined): ParseContext { + return ( + ctx || { + common: input.parent.common, + data: input.data, + + parsedType: getParsedType(input.data), + + schemaErrorMap: this._def.errorMap, + path: input.path, + parent: input.parent, + } + ); + } + + _processInputParams(input: ParseInput): { + status: ParseStatus; + ctx: ParseContext; + } { + return { + status: new ParseStatus(), + ctx: { + common: input.parent.common, + data: input.data, + + parsedType: getParsedType(input.data), + + schemaErrorMap: this._def.errorMap, + path: input.path, + parent: input.parent, + }, + }; + } + + _parseSync(input: ParseInput): SyncParseReturnType { + const result = this._parse(input); + if (isAsync(result)) { + throw new Error("Synchronous parse encountered promise."); + } + return result; + } + + _parseAsync(input: ParseInput): AsyncParseReturnType { + const result = this._parse(input); + return Promise.resolve(result); + } + + parse(data: unknown, params?: util.InexactPartial): Output { + const result = this.safeParse(data, params); + if (result.success) return result.data; + throw result.error; + } + + safeParse(data: unknown, params?: util.InexactPartial): SafeParseReturnType { + const ctx: ParseContext = { + common: { + issues: [], + async: params?.async ?? false, + contextualErrorMap: params?.errorMap, + }, + path: params?.path || [], + schemaErrorMap: this._def.errorMap, + parent: null, + data, + parsedType: getParsedType(data), + }; + const result = this._parseSync({ data, path: ctx.path, parent: ctx }); + + return handleResult(ctx, result); + } + + "~validate"(data: unknown): StandardSchemaV1.Result | Promise> { + const ctx: ParseContext = { + common: { + issues: [], + async: !!(this["~standard"] as any).async, + }, + path: [], + schemaErrorMap: this._def.errorMap, + parent: null, + data, + parsedType: getParsedType(data), + }; + + if (!(this["~standard"] as any).async) { + try { + const result = this._parseSync({ data, path: [], parent: ctx }); + return isValid(result) + ? { + value: result.value, + } + : { + issues: ctx.common.issues, + }; + } catch (err: any) { + if ((err as Error)?.message?.toLowerCase()?.includes("encountered")) { + (this["~standard"] as any).async = true; + } + (ctx as any).common = { + issues: [], + async: true, + }; + } + } + + return this._parseAsync({ data, path: [], parent: ctx }).then((result) => + isValid(result) + ? { + value: result.value, + } + : { + issues: ctx.common.issues, + } + ); + } + + async parseAsync(data: unknown, params?: util.InexactPartial): Promise { + const result = await this.safeParseAsync(data, params); + if (result.success) return result.data; + throw result.error; + } + + async safeParseAsync( + data: unknown, + params?: util.InexactPartial + ): Promise> { + const ctx: ParseContext = { + common: { + issues: [], + contextualErrorMap: params?.errorMap, + async: true, + }, + path: params?.path || [], + schemaErrorMap: this._def.errorMap, + parent: null, + data, + parsedType: getParsedType(data), + }; + + const maybeAsyncResult = this._parse({ data, path: ctx.path, parent: ctx }); + const result = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult)); + return handleResult(ctx, result); + } + + /** Alias of safeParseAsync */ + spa = this.safeParseAsync; + + refine( + check: (arg: Output) => arg is RefinedOutput, + message?: string | CustomErrorParams | ((arg: Output) => CustomErrorParams) + ): ZodEffects; + refine( + check: (arg: Output) => unknown | Promise, + message?: string | CustomErrorParams | ((arg: Output) => CustomErrorParams) + ): ZodEffects; + refine( + check: (arg: Output) => unknown, + message?: string | CustomErrorParams | ((arg: Output) => CustomErrorParams) + ): ZodEffects { + const getIssueProperties = (val: Output) => { + if (typeof message === "string" || typeof message === "undefined") { + return { message }; + } else if (typeof message === "function") { + return message(val); + } else { + return message; + } + }; + return this._refinement((val, ctx) => { + const result = check(val); + const setError = () => + ctx.addIssue({ + code: ZodIssueCode.custom, + ...getIssueProperties(val), + }); + if (typeof Promise !== "undefined" && result instanceof Promise) { + return result.then((data) => { + if (!data) { + setError(); + return false; + } else { + return true; + } + }); + } + if (!result) { + setError(); + return false; + } else { + return true; + } + }); + } + + refinement( + check: (arg: Output) => arg is RefinedOutput, + refinementData: IssueData | ((arg: Output, ctx: RefinementCtx) => IssueData) + ): ZodEffects; + refinement( + check: (arg: Output) => boolean, + refinementData: IssueData | ((arg: Output, ctx: RefinementCtx) => IssueData) + ): ZodEffects; + refinement( + check: (arg: Output) => unknown, + refinementData: IssueData | ((arg: Output, ctx: RefinementCtx) => IssueData) + ): ZodEffects { + return this._refinement((val, ctx) => { + if (!check(val)) { + ctx.addIssue(typeof refinementData === "function" ? refinementData(val, ctx) : refinementData); + return false; + } else { + return true; + } + }); + } + + _refinement(refinement: RefinementEffect["refinement"]): ZodEffects { + return new ZodEffects({ + schema: this, + typeName: ZodFirstPartyTypeKind.ZodEffects, + effect: { type: "refinement", refinement }, + }); + } + + superRefine( + refinement: (arg: Output, ctx: RefinementCtx) => arg is RefinedOutput + ): ZodEffects; + superRefine(refinement: (arg: Output, ctx: RefinementCtx) => void): ZodEffects; + superRefine(refinement: (arg: Output, ctx: RefinementCtx) => Promise): ZodEffects; + superRefine( + refinement: (arg: Output, ctx: RefinementCtx) => unknown | Promise + ): ZodEffects { + return this._refinement(refinement); + } + + constructor(def: Def) { + this._def = def; + this.parse = this.parse.bind(this); + this.safeParse = this.safeParse.bind(this); + this.parseAsync = this.parseAsync.bind(this); + this.safeParseAsync = this.safeParseAsync.bind(this); + this.spa = this.spa.bind(this); + this.refine = this.refine.bind(this); + this.refinement = this.refinement.bind(this); + this.superRefine = this.superRefine.bind(this); + this.optional = this.optional.bind(this); + this.nullable = this.nullable.bind(this); + this.nullish = this.nullish.bind(this); + this.array = this.array.bind(this); + this.promise = this.promise.bind(this); + this.or = this.or.bind(this); + this.and = this.and.bind(this); + this.transform = this.transform.bind(this); + this.brand = this.brand.bind(this); + this.default = this.default.bind(this); + this.catch = this.catch.bind(this); + this.describe = this.describe.bind(this); + this.pipe = this.pipe.bind(this); + this.readonly = this.readonly.bind(this); + this.isNullable = this.isNullable.bind(this); + this.isOptional = this.isOptional.bind(this); + this["~standard"] = { + version: 1, + vendor: "zod", + validate: (data) => this["~validate"](data), + }; + } + + optional(): ZodOptional { + return ZodOptional.create(this, this._def) as any; + } + nullable(): ZodNullable { + return ZodNullable.create(this, this._def) as any; + } + nullish(): ZodOptional> { + return this.nullable().optional(); + } + array(): ZodArray { + return ZodArray.create(this); + } + promise(): ZodPromise { + return ZodPromise.create(this, this._def); + } + + or(option: T): ZodUnion<[this, T]> { + return ZodUnion.create([this, option], this._def) as any; + } + + and(incoming: T): ZodIntersection { + return ZodIntersection.create(this, incoming, this._def); + } + + transform( + transform: (arg: Output, ctx: RefinementCtx) => NewOut | Promise + ): ZodEffects { + return new ZodEffects({ + ...processCreateParams(this._def), + schema: this, + typeName: ZodFirstPartyTypeKind.ZodEffects, + effect: { type: "transform", transform }, + }) as any; + } + + default(def: util.noUndefined): ZodDefault; + default(def: () => util.noUndefined): ZodDefault; + default(def: any) { + const defaultValueFunc = typeof def === "function" ? def : () => def; + + return new ZodDefault({ + ...processCreateParams(this._def), + innerType: this, + defaultValue: defaultValueFunc, + typeName: ZodFirstPartyTypeKind.ZodDefault, + }) as any; + } + + brand(brand?: B): ZodBranded; + brand(): ZodBranded { + return new ZodBranded({ + typeName: ZodFirstPartyTypeKind.ZodBranded, + type: this, + ...processCreateParams(this._def), + }); + } + + catch(def: Output): ZodCatch; + catch(def: (ctx: { error: ZodError; input: Input }) => Output): ZodCatch; + catch(def: any) { + const catchValueFunc = typeof def === "function" ? def : () => def; + + return new ZodCatch({ + ...processCreateParams(this._def), + innerType: this, + catchValue: catchValueFunc, + typeName: ZodFirstPartyTypeKind.ZodCatch, + }) as any; + } + + describe(description: string): this { + const This = (this as any).constructor; + return new This({ + ...this._def, + description, + }); + } + + pipe(target: T): ZodPipeline { + return ZodPipeline.create(this, target); + } + readonly(): ZodReadonly { + return ZodReadonly.create(this); + } + + isOptional(): boolean { + return this.safeParse(undefined).success; + } + isNullable(): boolean { + return this.safeParse(null).success; + } +} + +///////////////////////////////////////// +///////////////////////////////////////// +////////// ////////// +////////// ZodString ////////// +////////// ////////// +///////////////////////////////////////// +///////////////////////////////////////// +export type IpVersion = "v4" | "v6"; +export type ZodStringCheck = + | { kind: "min"; value: number; message?: string | undefined } + | { kind: "max"; value: number; message?: string | undefined } + | { kind: "length"; value: number; message?: string | undefined } + | { kind: "email"; message?: string | undefined } + | { kind: "url"; message?: string | undefined } + | { kind: "emoji"; message?: string | undefined } + | { kind: "uuid"; message?: string | undefined } + | { kind: "nanoid"; message?: string | undefined } + | { kind: "cuid"; message?: string | undefined } + | { kind: "includes"; value: string; position?: number | undefined; message?: string | undefined } + | { kind: "cuid2"; message?: string | undefined } + | { kind: "ulid"; message?: string | undefined } + | { kind: "startsWith"; value: string; message?: string | undefined } + | { kind: "endsWith"; value: string; message?: string | undefined } + | { kind: "regex"; regex: RegExp; message?: string | undefined } + | { kind: "trim"; message?: string | undefined } + | { kind: "toLowerCase"; message?: string | undefined } + | { kind: "toUpperCase"; message?: string | undefined } + | { kind: "jwt"; alg?: string; message?: string | undefined } + | { + kind: "datetime"; + offset: boolean; + local: boolean; + precision: number | null; + message?: string | undefined; + } + | { + kind: "date"; + // withDate: true; + message?: string | undefined; + } + | { + kind: "time"; + precision: number | null; + message?: string | undefined; + } + | { kind: "duration"; message?: string | undefined } + | { kind: "ip"; version?: IpVersion | undefined; message?: string | undefined } + | { kind: "cidr"; version?: IpVersion | undefined; message?: string | undefined } + | { kind: "base64"; message?: string | undefined } + | { kind: "base64url"; message?: string | undefined }; + +export interface ZodStringDef extends ZodTypeDef { + checks: ZodStringCheck[]; + typeName: ZodFirstPartyTypeKind.ZodString; + coerce: boolean; +} + +const cuidRegex = /^c[^\s-]{8,}$/i; +const cuid2Regex = /^[0-9a-z]+$/; +const ulidRegex = /^[0-9A-HJKMNP-TV-Z]{26}$/i; +// const uuidRegex = +// /^([a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[a-f0-9]{4}-[a-f0-9]{12}|00000000-0000-0000-0000-000000000000)$/i; +const uuidRegex = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i; +const nanoidRegex = /^[a-z0-9_-]{21}$/i; +const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/; +const durationRegex = + /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/; + +// from https://stackoverflow.com/a/46181/1550155 +// old version: too slow, didn't support unicode +// const emailRegex = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; +//old email regex +// const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((?!-)([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{1,})[^-<>()[\].,;:\s@"]$/i; +// eslint-disable-next-line +// const emailRegex = +// /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\])|(\[IPv6:(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))\])|([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])*(\.[A-Za-z]{2,})+))$/; +// const emailRegex = +// /^[a-zA-Z0-9\.\!\#\$\%\&\'\*\+\/\=\?\^\_\`\{\|\}\~\-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; +// const emailRegex = +// /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i; +const emailRegex = /^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i; +// const emailRegex = +// /^[a-z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9\-]+)*$/i; + +// from https://thekevinscott.com/emojis-in-javascript/#writing-a-regular-expression +const _emojiRegex = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; +let emojiRegex: RegExp; + +// faster, simpler, safer +const ipv4Regex = + /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; +const ipv4CidrRegex = + /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/; + +// const ipv6Regex = +// /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/; +const ipv6Regex = + /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/; +const ipv6CidrRegex = + /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; + +// https://stackoverflow.com/questions/7860392/determine-if-string-is-in-base64-using-javascript +const base64Regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/; + +// https://base64.guru/standards/base64url +const base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/; + +// simple +// const dateRegexSource = `\\d{4}-\\d{2}-\\d{2}`; +// no leap year validation +// const dateRegexSource = `\\d{4}-((0[13578]|10|12)-31|(0[13-9]|1[0-2])-30|(0[1-9]|1[0-2])-(0[1-9]|1\\d|2\\d))`; +// with leap year validation +const dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`; +const dateRegex = new RegExp(`^${dateRegexSource}$`); + +function timeRegexSource(args: { precision?: number | null }) { + let secondsRegexSource = `[0-5]\\d`; + if (args.precision) { + secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`; + } else if (args.precision == null) { + secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`; + } + + const secondsQuantifier = args.precision ? "+" : "?"; // require seconds if precision is nonzero + return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`; +} + +function timeRegex(args: { + offset?: boolean; + local?: boolean; + precision?: number | null; +}) { + return new RegExp(`^${timeRegexSource(args)}$`); +} + +// Adapted from https://stackoverflow.com/a/3143231 +export function datetimeRegex(args: { + precision?: number | null; + offset?: boolean; + local?: boolean; +}) { + let regex = `${dateRegexSource}T${timeRegexSource(args)}`; + + const opts: string[] = []; + opts.push(args.local ? `Z?` : `Z`); + if (args.offset) opts.push(`([+-]\\d{2}:?\\d{2})`); + regex = `${regex}(${opts.join("|")})`; + return new RegExp(`^${regex}$`); +} + +function isValidIP(ip: string, version?: IpVersion) { + if ((version === "v4" || !version) && ipv4Regex.test(ip)) { + return true; + } + if ((version === "v6" || !version) && ipv6Regex.test(ip)) { + return true; + } + + return false; +} + +function isValidJWT(jwt: string, alg?: string): boolean { + if (!jwtRegex.test(jwt)) return false; + try { + const [header] = jwt.split("."); + if (!header) return false; + // Convert base64url to base64 + const base64 = header + .replace(/-/g, "+") + .replace(/_/g, "/") + .padEnd(header.length + ((4 - (header.length % 4)) % 4), "="); + // @ts-ignore + const decoded = JSON.parse(atob(base64)); + if (typeof decoded !== "object" || decoded === null) return false; + if ("typ" in decoded && decoded?.typ !== "JWT") return false; + if (!decoded.alg) return false; + if (alg && decoded.alg !== alg) return false; + return true; + } catch { + return false; + } +} + +function isValidCidr(ip: string, version?: IpVersion) { + if ((version === "v4" || !version) && ipv4CidrRegex.test(ip)) { + return true; + } + if ((version === "v6" || !version) && ipv6CidrRegex.test(ip)) { + return true; + } + + return false; +} + +export class ZodString extends ZodType { + _parse(input: ParseInput): ParseReturnType { + if (this._def.coerce) { + input.data = String(input.data); + } + const parsedType = this._getType(input); + + if (parsedType !== ZodParsedType.string) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.string, + received: ctx.parsedType, + }); + return INVALID; + } + + const status = new ParseStatus(); + let ctx: undefined | ParseContext = undefined; + + for (const check of this._def.checks) { + if (check.kind === "min") { + if (input.data.length < check.value) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: check.value, + type: "string", + inclusive: true, + exact: false, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "max") { + if (input.data.length > check.value) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: check.value, + type: "string", + inclusive: true, + exact: false, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "length") { + const tooBig = input.data.length > check.value; + const tooSmall = input.data.length < check.value; + if (tooBig || tooSmall) { + ctx = this._getOrReturnCtx(input, ctx); + if (tooBig) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: check.value, + type: "string", + inclusive: true, + exact: true, + message: check.message, + }); + } else if (tooSmall) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: check.value, + type: "string", + inclusive: true, + exact: true, + message: check.message, + }); + } + status.dirty(); + } + } else if (check.kind === "email") { + if (!emailRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "email", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "emoji") { + if (!emojiRegex) { + emojiRegex = new RegExp(_emojiRegex, "u"); + } + if (!emojiRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "emoji", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "uuid") { + if (!uuidRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "uuid", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "nanoid") { + if (!nanoidRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "nanoid", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "cuid") { + if (!cuidRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "cuid", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "cuid2") { + if (!cuid2Regex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "cuid2", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "ulid") { + if (!ulidRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "ulid", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "url") { + try { + // @ts-ignore + new URL(input.data); + } catch { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "url", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "regex") { + check.regex.lastIndex = 0; + const testResult = check.regex.test(input.data); + if (!testResult) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "regex", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "trim") { + input.data = input.data.trim(); + } else if (check.kind === "includes") { + if (!(input.data as string).includes(check.value, check.position)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: { includes: check.value, position: check.position }, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "toLowerCase") { + input.data = input.data.toLowerCase(); + } else if (check.kind === "toUpperCase") { + input.data = input.data.toUpperCase(); + } else if (check.kind === "startsWith") { + if (!(input.data as string).startsWith(check.value)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: { startsWith: check.value }, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "endsWith") { + if (!(input.data as string).endsWith(check.value)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: { endsWith: check.value }, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "datetime") { + const regex = datetimeRegex(check); + + if (!regex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: "datetime", + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "date") { + const regex = dateRegex; + + if (!regex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: "date", + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "time") { + const regex = timeRegex(check); + + if (!regex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: "time", + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "duration") { + if (!durationRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "duration", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "ip") { + if (!isValidIP(input.data, check.version)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "ip", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "jwt") { + if (!isValidJWT(input.data, check.alg)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "jwt", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "cidr") { + if (!isValidCidr(input.data, check.version)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "cidr", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "base64") { + if (!base64Regex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "base64", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "base64url") { + if (!base64urlRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "base64url", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } else { + util.assertNever(check); + } + } + + return { status: status.value, value: input.data }; + } + + protected _regex(regex: RegExp, validation: StringValidation, message?: errorUtil.ErrMessage) { + return this.refinement((data) => regex.test(data), { + validation, + code: ZodIssueCode.invalid_string, + ...errorUtil.errToObj(message), + }); + } + + _addCheck(check: ZodStringCheck) { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, check], + }); + } + + email(message?: errorUtil.ErrMessage) { + return this._addCheck({ kind: "email", ...errorUtil.errToObj(message) }); + } + + url(message?: errorUtil.ErrMessage) { + return this._addCheck({ kind: "url", ...errorUtil.errToObj(message) }); + } + + emoji(message?: errorUtil.ErrMessage) { + return this._addCheck({ kind: "emoji", ...errorUtil.errToObj(message) }); + } + + uuid(message?: errorUtil.ErrMessage) { + return this._addCheck({ kind: "uuid", ...errorUtil.errToObj(message) }); + } + nanoid(message?: errorUtil.ErrMessage) { + return this._addCheck({ kind: "nanoid", ...errorUtil.errToObj(message) }); + } + cuid(message?: errorUtil.ErrMessage) { + return this._addCheck({ kind: "cuid", ...errorUtil.errToObj(message) }); + } + + cuid2(message?: errorUtil.ErrMessage) { + return this._addCheck({ kind: "cuid2", ...errorUtil.errToObj(message) }); + } + ulid(message?: errorUtil.ErrMessage) { + return this._addCheck({ kind: "ulid", ...errorUtil.errToObj(message) }); + } + base64(message?: errorUtil.ErrMessage) { + return this._addCheck({ kind: "base64", ...errorUtil.errToObj(message) }); + } + base64url(message?: errorUtil.ErrMessage) { + // base64url encoding is a modification of base64 that can safely be used in URLs and filenames + return this._addCheck({ + kind: "base64url", + ...errorUtil.errToObj(message), + }); + } + + jwt(options?: { alg?: string; message?: string | undefined }) { + return this._addCheck({ kind: "jwt", ...errorUtil.errToObj(options) }); + } + + ip(options?: string | { version?: IpVersion; message?: string | undefined }) { + return this._addCheck({ kind: "ip", ...errorUtil.errToObj(options) }); + } + + cidr(options?: string | { version?: IpVersion; message?: string | undefined }) { + return this._addCheck({ kind: "cidr", ...errorUtil.errToObj(options) }); + } + + datetime( + options?: + | string + | { + message?: string | undefined; + precision?: number | null; + offset?: boolean; + local?: boolean; + } + ) { + if (typeof options === "string") { + return this._addCheck({ + kind: "datetime", + precision: null, + offset: false, + local: false, + message: options, + }); + } + return this._addCheck({ + kind: "datetime", + + precision: typeof options?.precision === "undefined" ? null : options?.precision, + offset: options?.offset ?? false, + local: options?.local ?? false, + ...errorUtil.errToObj(options?.message), + }); + } + + date(message?: string) { + return this._addCheck({ kind: "date", message }); + } + + time( + options?: + | string + | { + message?: string | undefined; + precision?: number | null; + } + ) { + if (typeof options === "string") { + return this._addCheck({ + kind: "time", + precision: null, + message: options, + }); + } + return this._addCheck({ + kind: "time", + precision: typeof options?.precision === "undefined" ? null : options?.precision, + ...errorUtil.errToObj(options?.message), + }); + } + + duration(message?: errorUtil.ErrMessage) { + return this._addCheck({ kind: "duration", ...errorUtil.errToObj(message) }); + } + + regex(regex: RegExp, message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "regex", + regex: regex, + ...errorUtil.errToObj(message), + }); + } + + includes(value: string, options?: { message?: string; position?: number }) { + return this._addCheck({ + kind: "includes", + value: value, + position: options?.position, + ...errorUtil.errToObj(options?.message), + }); + } + + startsWith(value: string, message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "startsWith", + value: value, + ...errorUtil.errToObj(message), + }); + } + + endsWith(value: string, message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "endsWith", + value: value, + ...errorUtil.errToObj(message), + }); + } + + min(minLength: number, message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "min", + value: minLength, + ...errorUtil.errToObj(message), + }); + } + + max(maxLength: number, message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "max", + value: maxLength, + ...errorUtil.errToObj(message), + }); + } + + length(len: number, message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "length", + value: len, + ...errorUtil.errToObj(message), + }); + } + + /** + * Equivalent to `.min(1)` + */ + nonempty(message?: errorUtil.ErrMessage) { + return this.min(1, errorUtil.errToObj(message)); + } + + trim() { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, { kind: "trim" }], + }); + } + + toLowerCase() { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, { kind: "toLowerCase" }], + }); + } + + toUpperCase() { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, { kind: "toUpperCase" }], + }); + } + + get isDatetime() { + return !!this._def.checks.find((ch) => ch.kind === "datetime"); + } + + get isDate() { + return !!this._def.checks.find((ch) => ch.kind === "date"); + } + + get isTime() { + return !!this._def.checks.find((ch) => ch.kind === "time"); + } + get isDuration() { + return !!this._def.checks.find((ch) => ch.kind === "duration"); + } + + get isEmail() { + return !!this._def.checks.find((ch) => ch.kind === "email"); + } + + get isURL() { + return !!this._def.checks.find((ch) => ch.kind === "url"); + } + + get isEmoji() { + return !!this._def.checks.find((ch) => ch.kind === "emoji"); + } + + get isUUID() { + return !!this._def.checks.find((ch) => ch.kind === "uuid"); + } + get isNANOID() { + return !!this._def.checks.find((ch) => ch.kind === "nanoid"); + } + get isCUID() { + return !!this._def.checks.find((ch) => ch.kind === "cuid"); + } + + get isCUID2() { + return !!this._def.checks.find((ch) => ch.kind === "cuid2"); + } + get isULID() { + return !!this._def.checks.find((ch) => ch.kind === "ulid"); + } + get isIP() { + return !!this._def.checks.find((ch) => ch.kind === "ip"); + } + get isCIDR() { + return !!this._def.checks.find((ch) => ch.kind === "cidr"); + } + get isBase64() { + return !!this._def.checks.find((ch) => ch.kind === "base64"); + } + get isBase64url() { + // base64url encoding is a modification of base64 that can safely be used in URLs and filenames + return !!this._def.checks.find((ch) => ch.kind === "base64url"); + } + + get minLength() { + let min: number | null = null; + for (const ch of this._def.checks) { + if (ch.kind === "min") { + if (min === null || ch.value > min) min = ch.value; + } + } + return min; + } + + get maxLength() { + let max: number | null = null; + for (const ch of this._def.checks) { + if (ch.kind === "max") { + if (max === null || ch.value < max) max = ch.value; + } + } + return max; + } + + static create = (params?: RawCreateParams & { coerce?: true }): ZodString => { + return new ZodString({ + checks: [], + typeName: ZodFirstPartyTypeKind.ZodString, + coerce: params?.coerce ?? false, + ...processCreateParams(params), + }); + }; +} + +///////////////////////////////////////// +///////////////////////////////////////// +////////// ////////// +////////// ZodNumber ////////// +////////// ////////// +///////////////////////////////////////// +///////////////////////////////////////// +export type ZodNumberCheck = + | { kind: "min"; value: number; inclusive: boolean; message?: string | undefined } + | { kind: "max"; value: number; inclusive: boolean; message?: string | undefined } + | { kind: "int"; message?: string | undefined } + | { kind: "multipleOf"; value: number; message?: string | undefined } + | { kind: "finite"; message?: string | undefined }; + +// https://stackoverflow.com/questions/3966484/why-does-modulus-operator-return-fractional-number-in-javascript/31711034#31711034 +function floatSafeRemainder(val: number, step: number) { + const valDecCount = (val.toString().split(".")[1] || "").length; + const stepDecCount = (step.toString().split(".")[1] || "").length; + const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount; + const valInt = Number.parseInt(val.toFixed(decCount).replace(".", "")); + const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", "")); + return (valInt % stepInt) / 10 ** decCount; +} + +export interface ZodNumberDef extends ZodTypeDef { + checks: ZodNumberCheck[]; + typeName: ZodFirstPartyTypeKind.ZodNumber; + coerce: boolean; +} + +export class ZodNumber extends ZodType { + _parse(input: ParseInput): ParseReturnType { + if (this._def.coerce) { + input.data = Number(input.data); + } + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.number) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.number, + received: ctx.parsedType, + }); + return INVALID; + } + + let ctx: undefined | ParseContext = undefined; + const status = new ParseStatus(); + + for (const check of this._def.checks) { + if (check.kind === "int") { + if (!util.isInteger(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: "integer", + received: "float", + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "min") { + const tooSmall = check.inclusive ? input.data < check.value : input.data <= check.value; + if (tooSmall) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: check.value, + type: "number", + inclusive: check.inclusive, + exact: false, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "max") { + const tooBig = check.inclusive ? input.data > check.value : input.data >= check.value; + if (tooBig) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: check.value, + type: "number", + inclusive: check.inclusive, + exact: false, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "multipleOf") { + if (floatSafeRemainder(input.data, check.value) !== 0) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.not_multiple_of, + multipleOf: check.value, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "finite") { + if (!Number.isFinite(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.not_finite, + message: check.message, + }); + status.dirty(); + } + } else { + util.assertNever(check); + } + } + + return { status: status.value, value: input.data }; + } + + static create = (params?: RawCreateParams & { coerce?: boolean }): ZodNumber => { + return new ZodNumber({ + checks: [], + typeName: ZodFirstPartyTypeKind.ZodNumber, + coerce: params?.coerce || false, + ...processCreateParams(params), + }); + }; + + gte(value: number, message?: errorUtil.ErrMessage) { + return this.setLimit("min", value, true, errorUtil.toString(message)); + } + min = this.gte; + + gt(value: number, message?: errorUtil.ErrMessage) { + return this.setLimit("min", value, false, errorUtil.toString(message)); + } + + lte(value: number, message?: errorUtil.ErrMessage) { + return this.setLimit("max", value, true, errorUtil.toString(message)); + } + max = this.lte; + + lt(value: number, message?: errorUtil.ErrMessage) { + return this.setLimit("max", value, false, errorUtil.toString(message)); + } + + protected setLimit(kind: "min" | "max", value: number, inclusive: boolean, message?: string) { + return new ZodNumber({ + ...this._def, + checks: [ + ...this._def.checks, + { + kind, + value, + inclusive, + message: errorUtil.toString(message), + }, + ], + }); + } + + _addCheck(check: ZodNumberCheck) { + return new ZodNumber({ + ...this._def, + checks: [...this._def.checks, check], + }); + } + + int(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "int", + message: errorUtil.toString(message), + }); + } + + positive(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "min", + value: 0, + inclusive: false, + message: errorUtil.toString(message), + }); + } + + negative(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "max", + value: 0, + inclusive: false, + message: errorUtil.toString(message), + }); + } + + nonpositive(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "max", + value: 0, + inclusive: true, + message: errorUtil.toString(message), + }); + } + + nonnegative(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "min", + value: 0, + inclusive: true, + message: errorUtil.toString(message), + }); + } + + multipleOf(value: number, message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "multipleOf", + value: value, + message: errorUtil.toString(message), + }); + } + step = this.multipleOf; + + finite(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "finite", + message: errorUtil.toString(message), + }); + } + + safe(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "min", + inclusive: true, + value: Number.MIN_SAFE_INTEGER, + message: errorUtil.toString(message), + })._addCheck({ + kind: "max", + inclusive: true, + value: Number.MAX_SAFE_INTEGER, + message: errorUtil.toString(message), + }); + } + + get minValue() { + let min: number | null = null; + for (const ch of this._def.checks) { + if (ch.kind === "min") { + if (min === null || ch.value > min) min = ch.value; + } + } + return min; + } + + get maxValue() { + let max: number | null = null; + for (const ch of this._def.checks) { + if (ch.kind === "max") { + if (max === null || ch.value < max) max = ch.value; + } + } + return max; + } + + get isInt() { + return !!this._def.checks.find((ch) => ch.kind === "int" || (ch.kind === "multipleOf" && util.isInteger(ch.value))); + } + + get isFinite() { + let max: number | null = null; + let min: number | null = null; + for (const ch of this._def.checks) { + if (ch.kind === "finite" || ch.kind === "int" || ch.kind === "multipleOf") { + return true; + } else if (ch.kind === "min") { + if (min === null || ch.value > min) min = ch.value; + } else if (ch.kind === "max") { + if (max === null || ch.value < max) max = ch.value; + } + } + return Number.isFinite(min) && Number.isFinite(max); + } +} + +///////////////////////////////////////// +///////////////////////////////////////// +////////// ////////// +////////// ZodBigInt ////////// +////////// ////////// +///////////////////////////////////////// +///////////////////////////////////////// +export type ZodBigIntCheck = + | { kind: "min"; value: bigint; inclusive: boolean; message?: string | undefined } + | { kind: "max"; value: bigint; inclusive: boolean; message?: string | undefined } + | { kind: "multipleOf"; value: bigint; message?: string | undefined }; + +export interface ZodBigIntDef extends ZodTypeDef { + checks: ZodBigIntCheck[]; + typeName: ZodFirstPartyTypeKind.ZodBigInt; + coerce: boolean; +} + +export class ZodBigInt extends ZodType { + _parse(input: ParseInput): ParseReturnType { + if (this._def.coerce) { + try { + input.data = BigInt(input.data); + } catch { + return this._getInvalidInput(input); + } + } + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.bigint) { + return this._getInvalidInput(input); + } + + let ctx: undefined | ParseContext = undefined; + const status = new ParseStatus(); + + for (const check of this._def.checks) { + if (check.kind === "min") { + const tooSmall = check.inclusive ? input.data < check.value : input.data <= check.value; + if (tooSmall) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + type: "bigint", + minimum: check.value, + inclusive: check.inclusive, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "max") { + const tooBig = check.inclusive ? input.data > check.value : input.data >= check.value; + if (tooBig) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + type: "bigint", + maximum: check.value, + inclusive: check.inclusive, + message: check.message, + }); + status.dirty(); + } + } else if (check.kind === "multipleOf") { + if (input.data % check.value !== BigInt(0)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.not_multiple_of, + multipleOf: check.value, + message: check.message, + }); + status.dirty(); + } + } else { + util.assertNever(check); + } + } + + return { status: status.value, value: input.data }; + } + + _getInvalidInput(input: ParseInput) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.bigint, + received: ctx.parsedType, + }); + return INVALID; + } + + static create = (params?: RawCreateParams & { coerce?: boolean }): ZodBigInt => { + return new ZodBigInt({ + checks: [], + typeName: ZodFirstPartyTypeKind.ZodBigInt, + coerce: params?.coerce ?? false, + ...processCreateParams(params), + }); + }; + + gte(value: bigint, message?: errorUtil.ErrMessage) { + return this.setLimit("min", value, true, errorUtil.toString(message)); + } + min = this.gte; + + gt(value: bigint, message?: errorUtil.ErrMessage) { + return this.setLimit("min", value, false, errorUtil.toString(message)); + } + + lte(value: bigint, message?: errorUtil.ErrMessage) { + return this.setLimit("max", value, true, errorUtil.toString(message)); + } + max = this.lte; + + lt(value: bigint, message?: errorUtil.ErrMessage) { + return this.setLimit("max", value, false, errorUtil.toString(message)); + } + + protected setLimit(kind: "min" | "max", value: bigint, inclusive: boolean, message?: string) { + return new ZodBigInt({ + ...this._def, + checks: [ + ...this._def.checks, + { + kind, + value, + inclusive, + message: errorUtil.toString(message), + }, + ], + }); + } + + _addCheck(check: ZodBigIntCheck) { + return new ZodBigInt({ + ...this._def, + checks: [...this._def.checks, check], + }); + } + + positive(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "min", + value: BigInt(0), + inclusive: false, + message: errorUtil.toString(message), + }); + } + + negative(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "max", + value: BigInt(0), + inclusive: false, + message: errorUtil.toString(message), + }); + } + + nonpositive(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "max", + value: BigInt(0), + inclusive: true, + message: errorUtil.toString(message), + }); + } + + nonnegative(message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "min", + value: BigInt(0), + inclusive: true, + message: errorUtil.toString(message), + }); + } + + multipleOf(value: bigint, message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "multipleOf", + value, + message: errorUtil.toString(message), + }); + } + + get minValue() { + let min: bigint | null = null; + for (const ch of this._def.checks) { + if (ch.kind === "min") { + if (min === null || ch.value > min) min = ch.value; + } + } + return min; + } + + get maxValue() { + let max: bigint | null = null; + for (const ch of this._def.checks) { + if (ch.kind === "max") { + if (max === null || ch.value < max) max = ch.value; + } + } + return max; + } +} + +////////////////////////////////////////// +////////////////////////////////////////// +////////// /////////// +////////// ZodBoolean ////////// +////////// /////////// +////////////////////////////////////////// +////////////////////////////////////////// +export interface ZodBooleanDef extends ZodTypeDef { + typeName: ZodFirstPartyTypeKind.ZodBoolean; + coerce: boolean; +} + +export class ZodBoolean extends ZodType { + _parse(input: ParseInput): ParseReturnType { + if (this._def.coerce) { + input.data = Boolean(input.data); + } + const parsedType = this._getType(input); + + if (parsedType !== ZodParsedType.boolean) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.boolean, + received: ctx.parsedType, + }); + return INVALID; + } + return OK(input.data); + } + + static create = (params?: RawCreateParams & { coerce?: boolean }): ZodBoolean => { + return new ZodBoolean({ + typeName: ZodFirstPartyTypeKind.ZodBoolean, + coerce: params?.coerce || false, + ...processCreateParams(params), + }); + }; +} + +/////////////////////////////////////// +/////////////////////////////////////// +////////// //////// +////////// ZodDate //////// +////////// //////// +/////////////////////////////////////// +/////////////////////////////////////// +export type ZodDateCheck = + | { kind: "min"; value: number; message?: string | undefined } + | { kind: "max"; value: number; message?: string | undefined }; +export interface ZodDateDef extends ZodTypeDef { + checks: ZodDateCheck[]; + coerce: boolean; + typeName: ZodFirstPartyTypeKind.ZodDate; +} + +export class ZodDate extends ZodType { + _parse(input: ParseInput): ParseReturnType { + if (this._def.coerce) { + input.data = new Date(input.data); + } + const parsedType = this._getType(input); + + if (parsedType !== ZodParsedType.date) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.date, + received: ctx.parsedType, + }); + return INVALID; + } + + if (Number.isNaN(input.data.getTime())) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_date, + }); + return INVALID; + } + + const status = new ParseStatus(); + let ctx: undefined | ParseContext = undefined; + + for (const check of this._def.checks) { + if (check.kind === "min") { + if (input.data.getTime() < check.value) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + message: check.message, + inclusive: true, + exact: false, + minimum: check.value, + type: "date", + }); + status.dirty(); + } + } else if (check.kind === "max") { + if (input.data.getTime() > check.value) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + message: check.message, + inclusive: true, + exact: false, + maximum: check.value, + type: "date", + }); + status.dirty(); + } + } else { + util.assertNever(check); + } + } + + return { + status: status.value, + value: new Date((input.data as Date).getTime()), + }; + } + + _addCheck(check: ZodDateCheck) { + return new ZodDate({ + ...this._def, + checks: [...this._def.checks, check], + }); + } + + min(minDate: Date, message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "min", + value: minDate.getTime(), + message: errorUtil.toString(message), + }); + } + + max(maxDate: Date, message?: errorUtil.ErrMessage) { + return this._addCheck({ + kind: "max", + value: maxDate.getTime(), + message: errorUtil.toString(message), + }); + } + + get minDate() { + let min: number | null = null; + for (const ch of this._def.checks) { + if (ch.kind === "min") { + if (min === null || ch.value > min) min = ch.value; + } + } + + return min != null ? new Date(min) : null; + } + + get maxDate() { + let max: number | null = null; + for (const ch of this._def.checks) { + if (ch.kind === "max") { + if (max === null || ch.value < max) max = ch.value; + } + } + + return max != null ? new Date(max) : null; + } + + static create = (params?: RawCreateParams & { coerce?: boolean }): ZodDate => { + return new ZodDate({ + checks: [], + coerce: params?.coerce || false, + typeName: ZodFirstPartyTypeKind.ZodDate, + ...processCreateParams(params), + }); + }; +} + +//////////////////////////////////////////// +//////////////////////////////////////////// +////////// ////////// +////////// ZodSymbol ////////// +////////// ////////// +//////////////////////////////////////////// +//////////////////////////////////////////// +export interface ZodSymbolDef extends ZodTypeDef { + typeName: ZodFirstPartyTypeKind.ZodSymbol; +} + +export class ZodSymbol extends ZodType { + _parse(input: ParseInput): ParseReturnType { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.symbol) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.symbol, + received: ctx.parsedType, + }); + return INVALID; + } + + return OK(input.data); + } + + static create = (params?: RawCreateParams): ZodSymbol => { + return new ZodSymbol({ + typeName: ZodFirstPartyTypeKind.ZodSymbol, + ...processCreateParams(params), + }); + }; +} + +//////////////////////////////////////////// +//////////////////////////////////////////// +////////// ////////// +////////// ZodUndefined ////////// +////////// ////////// +//////////////////////////////////////////// +//////////////////////////////////////////// +export interface ZodUndefinedDef extends ZodTypeDef { + typeName: ZodFirstPartyTypeKind.ZodUndefined; +} + +export class ZodUndefined extends ZodType { + _parse(input: ParseInput): ParseReturnType { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.undefined) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.undefined, + received: ctx.parsedType, + }); + return INVALID; + } + return OK(input.data); + } + params?: RawCreateParams; + + static create = (params?: RawCreateParams): ZodUndefined => { + return new ZodUndefined({ + typeName: ZodFirstPartyTypeKind.ZodUndefined, + ...processCreateParams(params), + }); + }; +} + +/////////////////////////////////////// +/////////////////////////////////////// +////////// ////////// +////////// ZodNull ////////// +////////// ////////// +/////////////////////////////////////// +/////////////////////////////////////// +export interface ZodNullDef extends ZodTypeDef { + typeName: ZodFirstPartyTypeKind.ZodNull; +} + +export class ZodNull extends ZodType { + _parse(input: ParseInput): ParseReturnType { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.null) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.null, + received: ctx.parsedType, + }); + return INVALID; + } + return OK(input.data); + } + static create = (params?: RawCreateParams): ZodNull => { + return new ZodNull({ + typeName: ZodFirstPartyTypeKind.ZodNull, + ...processCreateParams(params), + }); + }; +} + +////////////////////////////////////// +////////////////////////////////////// +////////// ////////// +////////// ZodAny ////////// +////////// ////////// +////////////////////////////////////// +////////////////////////////////////// +export interface ZodAnyDef extends ZodTypeDef { + typeName: ZodFirstPartyTypeKind.ZodAny; +} + +export class ZodAny extends ZodType { + // to prevent instances of other classes from extending ZodAny. this causes issues with catchall in ZodObject. + _any = true as const; + _parse(input: ParseInput): ParseReturnType { + return OK(input.data); + } + static create = (params?: RawCreateParams): ZodAny => { + return new ZodAny({ + typeName: ZodFirstPartyTypeKind.ZodAny, + ...processCreateParams(params), + }); + }; +} + +////////////////////////////////////////// +////////////////////////////////////////// +////////// ////////// +////////// ZodUnknown ////////// +////////// ////////// +////////////////////////////////////////// +////////////////////////////////////////// +export interface ZodUnknownDef extends ZodTypeDef { + typeName: ZodFirstPartyTypeKind.ZodUnknown; +} + +export class ZodUnknown extends ZodType { + // required + _unknown = true as const; + _parse(input: ParseInput): ParseReturnType { + return OK(input.data); + } + + static create = (params?: RawCreateParams): ZodUnknown => { + return new ZodUnknown({ + typeName: ZodFirstPartyTypeKind.ZodUnknown, + ...processCreateParams(params), + }); + }; +} + +//////////////////////////////////////// +//////////////////////////////////////// +////////// ////////// +////////// ZodNever ////////// +////////// ////////// +//////////////////////////////////////// +//////////////////////////////////////// +export interface ZodNeverDef extends ZodTypeDef { + typeName: ZodFirstPartyTypeKind.ZodNever; +} + +export class ZodNever extends ZodType { + _parse(input: ParseInput): ParseReturnType { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.never, + received: ctx.parsedType, + }); + return INVALID; + } + static create = (params?: RawCreateParams): ZodNever => { + return new ZodNever({ + typeName: ZodFirstPartyTypeKind.ZodNever, + ...processCreateParams(params), + }); + }; +} + +/////////////////////////////////////// +/////////////////////////////////////// +////////// ////////// +////////// ZodVoid ////////// +////////// ////////// +/////////////////////////////////////// +/////////////////////////////////////// +export interface ZodVoidDef extends ZodTypeDef { + typeName: ZodFirstPartyTypeKind.ZodVoid; +} + +export class ZodVoid extends ZodType { + _parse(input: ParseInput): ParseReturnType { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.undefined) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.void, + received: ctx.parsedType, + }); + return INVALID; + } + return OK(input.data); + } + + static create = (params?: RawCreateParams): ZodVoid => { + return new ZodVoid({ + typeName: ZodFirstPartyTypeKind.ZodVoid, + ...processCreateParams(params), + }); + }; +} + +//////////////////////////////////////// +//////////////////////////////////////// +////////// ////////// +////////// ZodArray ////////// +////////// ////////// +//////////////////////////////////////// +//////////////////////////////////////// +export interface ZodArrayDef extends ZodTypeDef { + type: T; + typeName: ZodFirstPartyTypeKind.ZodArray; + exactLength: { value: number; message?: string | undefined } | null; + minLength: { value: number; message?: string | undefined } | null; + maxLength: { value: number; message?: string | undefined } | null; +} + +export type ArrayCardinality = "many" | "atleastone"; +export type arrayOutputType< + T extends ZodTypeAny, + Cardinality extends ArrayCardinality = "many", +> = Cardinality extends "atleastone" ? [T["_output"], ...T["_output"][]] : T["_output"][]; + +export class ZodArray extends ZodType< + arrayOutputType, + ZodArrayDef, + Cardinality extends "atleastone" ? [T["_input"], ...T["_input"][]] : T["_input"][] +> { + _parse(input: ParseInput): ParseReturnType { + const { ctx, status } = this._processInputParams(input); + + const def = this._def; + + if (ctx.parsedType !== ZodParsedType.array) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.array, + received: ctx.parsedType, + }); + return INVALID; + } + + if (def.exactLength !== null) { + const tooBig = ctx.data.length > def.exactLength.value; + const tooSmall = ctx.data.length < def.exactLength.value; + if (tooBig || tooSmall) { + addIssueToContext(ctx, { + code: tooBig ? ZodIssueCode.too_big : ZodIssueCode.too_small, + minimum: (tooSmall ? def.exactLength.value : undefined) as number, + maximum: (tooBig ? def.exactLength.value : undefined) as number, + type: "array", + inclusive: true, + exact: true, + message: def.exactLength.message, + }); + status.dirty(); + } + } + + if (def.minLength !== null) { + if (ctx.data.length < def.minLength.value) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: def.minLength.value, + type: "array", + inclusive: true, + exact: false, + message: def.minLength.message, + }); + status.dirty(); + } + } + + if (def.maxLength !== null) { + if (ctx.data.length > def.maxLength.value) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: def.maxLength.value, + type: "array", + inclusive: true, + exact: false, + message: def.maxLength.message, + }); + status.dirty(); + } + } + + if (ctx.common.async) { + return Promise.all( + ([...ctx.data] as any[]).map((item, i) => { + return def.type._parseAsync(new ParseInputLazyPath(ctx, item, ctx.path, i)); + }) + ).then((result) => { + return ParseStatus.mergeArray(status, result); + }); + } + + const result = ([...ctx.data] as any[]).map((item, i) => { + return def.type._parseSync(new ParseInputLazyPath(ctx, item, ctx.path, i)); + }); + + return ParseStatus.mergeArray(status, result); + } + + get element() { + return this._def.type; + } + + min(minLength: number, message?: errorUtil.ErrMessage): this { + return new ZodArray({ + ...this._def, + minLength: { value: minLength, message: errorUtil.toString(message) }, + }) as any; + } + + max(maxLength: number, message?: errorUtil.ErrMessage): this { + return new ZodArray({ + ...this._def, + maxLength: { value: maxLength, message: errorUtil.toString(message) }, + }) as any; + } + + length(len: number, message?: errorUtil.ErrMessage): this { + return new ZodArray({ + ...this._def, + exactLength: { value: len, message: errorUtil.toString(message) }, + }) as any; + } + + nonempty(message?: errorUtil.ErrMessage): ZodArray { + return this.min(1, message) as any; + } + + static create = (schema: El, params?: RawCreateParams): ZodArray => { + return new ZodArray({ + type: schema, + minLength: null, + maxLength: null, + exactLength: null, + typeName: ZodFirstPartyTypeKind.ZodArray, + ...processCreateParams(params), + }); + }; +} + +export type ZodNonEmptyArray = ZodArray; + +///////////////////////////////////////// +///////////////////////////////////////// +////////// ////////// +////////// ZodObject ////////// +////////// ////////// +///////////////////////////////////////// +///////////////////////////////////////// + +export type UnknownKeysParam = "passthrough" | "strict" | "strip"; + +export interface ZodObjectDef< + T extends ZodRawShape = ZodRawShape, + UnknownKeys extends UnknownKeysParam = UnknownKeysParam, + Catchall extends ZodTypeAny = ZodTypeAny, +> extends ZodTypeDef { + typeName: ZodFirstPartyTypeKind.ZodObject; + shape: () => T; + catchall: Catchall; + unknownKeys: UnknownKeys; +} + +export type mergeTypes = { + [k in keyof A | keyof B]: k extends keyof B ? B[k] : k extends keyof A ? A[k] : never; +}; + +export type objectOutputType< + Shape extends ZodRawShape, + Catchall extends ZodTypeAny, + UnknownKeys extends UnknownKeysParam = UnknownKeysParam, +> = objectUtil.flatten>> & + CatchallOutput & + PassthroughType; + +export type baseObjectOutputType = { + [k in keyof Shape]: Shape[k]["_output"]; +}; + +export type objectInputType< + Shape extends ZodRawShape, + Catchall extends ZodTypeAny, + UnknownKeys extends UnknownKeysParam = UnknownKeysParam, +> = objectUtil.flatten> & CatchallInput & PassthroughType; +export type baseObjectInputType = objectUtil.addQuestionMarks<{ + [k in keyof Shape]: Shape[k]["_input"]; +}>; + +export type CatchallOutput = ZodType extends T ? unknown : { [k: string]: T["_output"] }; + +export type CatchallInput = ZodType extends T ? unknown : { [k: string]: T["_input"] }; + +export type PassthroughType = T extends "passthrough" ? { [k: string]: unknown } : unknown; + +export type deoptional = T extends ZodOptional + ? deoptional + : T extends ZodNullable + ? ZodNullable> + : T; + +export type SomeZodObject = ZodObject; + +export type noUnrecognized = { + [k in keyof Obj]: k extends keyof Shape ? Obj[k] : never; +}; + +function deepPartialify(schema: ZodTypeAny): any { + if (schema instanceof ZodObject) { + const newShape: any = {}; + + for (const key in schema.shape) { + const fieldSchema = schema.shape[key]; + newShape[key] = ZodOptional.create(deepPartialify(fieldSchema)); + } + return new ZodObject({ + ...schema._def, + shape: () => newShape, + }) as any; + } else if (schema instanceof ZodArray) { + return new ZodArray({ + ...schema._def, + type: deepPartialify(schema.element), + }); + } else if (schema instanceof ZodOptional) { + return ZodOptional.create(deepPartialify(schema.unwrap())); + } else if (schema instanceof ZodNullable) { + return ZodNullable.create(deepPartialify(schema.unwrap())); + } else if (schema instanceof ZodTuple) { + return ZodTuple.create(schema.items.map((item: any) => deepPartialify(item))); + } else { + return schema; + } +} + +export class ZodObject< + T extends ZodRawShape, + UnknownKeys extends UnknownKeysParam = UnknownKeysParam, + Catchall extends ZodTypeAny = ZodTypeAny, + Output = objectOutputType, + Input = objectInputType, +> extends ZodType, Input> { + _cached: { shape: T; keys: string[] } | null = null; + + _getCached(): { shape: T; keys: string[] } { + if (this._cached !== null) return this._cached; + const shape = this._def.shape(); + const keys = util.objectKeys(shape); + this._cached = { shape, keys }; + return this._cached; + } + + _parse(input: ParseInput): ParseReturnType { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.object) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.object, + received: ctx.parsedType, + }); + return INVALID; + } + + const { status, ctx } = this._processInputParams(input); + + const { shape, keys: shapeKeys } = this._getCached(); + const extraKeys: string[] = []; + + if (!(this._def.catchall instanceof ZodNever && this._def.unknownKeys === "strip")) { + for (const key in ctx.data) { + if (!shapeKeys.includes(key)) { + extraKeys.push(key); + } + } + } + + const pairs: { + key: ParseReturnType; + value: ParseReturnType; + alwaysSet?: boolean; + }[] = []; + for (const key of shapeKeys) { + const keyValidator = shape[key]!; + const value = ctx.data[key]; + pairs.push({ + key: { status: "valid", value: key }, + value: keyValidator._parse(new ParseInputLazyPath(ctx, value, ctx.path, key)), + alwaysSet: key in ctx.data, + }); + } + + if (this._def.catchall instanceof ZodNever) { + const unknownKeys = this._def.unknownKeys; + + if (unknownKeys === "passthrough") { + for (const key of extraKeys) { + pairs.push({ + key: { status: "valid", value: key }, + value: { status: "valid", value: ctx.data[key] }, + }); + } + } else if (unknownKeys === "strict") { + if (extraKeys.length > 0) { + addIssueToContext(ctx, { + code: ZodIssueCode.unrecognized_keys, + keys: extraKeys, + }); + status.dirty(); + } + } else if (unknownKeys === "strip") { + } else { + throw new Error(`Internal ZodObject error: invalid unknownKeys value.`); + } + } else { + // run catchall validation + const catchall = this._def.catchall; + + for (const key of extraKeys) { + const value = ctx.data[key]; + pairs.push({ + key: { status: "valid", value: key }, + value: catchall._parse( + new ParseInputLazyPath(ctx, value, ctx.path, key) //, ctx.child(key), value, getParsedType(value) + ), + alwaysSet: key in ctx.data, + }); + } + } + + if (ctx.common.async) { + return Promise.resolve() + .then(async () => { + const syncPairs: any[] = []; + for (const pair of pairs) { + const key = await pair.key; + const value = await pair.value; + syncPairs.push({ + key, + value, + alwaysSet: pair.alwaysSet, + }); + } + return syncPairs; + }) + .then((syncPairs) => { + return ParseStatus.mergeObjectSync(status, syncPairs); + }); + } else { + return ParseStatus.mergeObjectSync(status, pairs as any); + } + } + + get shape() { + return this._def.shape(); + } + + strict(message?: errorUtil.ErrMessage): ZodObject { + errorUtil.errToObj; + return new ZodObject({ + ...this._def, + unknownKeys: "strict", + ...(message !== undefined + ? { + errorMap: (issue, ctx) => { + const defaultError = this._def.errorMap?.(issue, ctx).message ?? ctx.defaultError; + if (issue.code === "unrecognized_keys") + return { + message: errorUtil.errToObj(message).message ?? defaultError, + }; + return { + message: defaultError, + }; + }, + } + : {}), + }) as any; + } + + strip(): ZodObject { + return new ZodObject({ + ...this._def, + unknownKeys: "strip", + }) as any; + } + + passthrough(): ZodObject { + return new ZodObject({ + ...this._def, + unknownKeys: "passthrough", + }) as any; + } + + /** + * @deprecated In most cases, this is no longer needed - unknown properties are now silently stripped. + * If you want to pass through unknown properties, use `.passthrough()` instead. + */ + nonstrict = this.passthrough; + + // const AugmentFactory = + // (def: Def) => + // ( + // augmentation: Augmentation + // ): ZodObject< + // extendShape, Augmentation>, + // Def["unknownKeys"], + // Def["catchall"] + // > => { + // return new ZodObject({ + // ...def, + // shape: () => ({ + // ...def.shape(), + // ...augmentation, + // }), + // }) as any; + // }; + extend( + augmentation: Augmentation + ): ZodObject, UnknownKeys, Catchall> { + return new ZodObject({ + ...this._def, + shape: () => ({ + ...this._def.shape(), + ...augmentation, + }), + }) as any; + } + // extend< + // Augmentation extends ZodRawShape, + // NewOutput extends util.flatten<{ + // [k in keyof Augmentation | keyof Output]: k extends keyof Augmentation + // ? Augmentation[k]["_output"] + // : k extends keyof Output + // ? Output[k] + // : never; + // }>, + // NewInput extends util.flatten<{ + // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation + // ? Augmentation[k]["_input"] + // : k extends keyof Input + // ? Input[k] + // : never; + // }> + // >( + // augmentation: Augmentation + // ): ZodObject< + // extendShape, + // UnknownKeys, + // Catchall, + // NewOutput, + // NewInput + // > { + // return new ZodObject({ + // ...this._def, + // shape: () => ({ + // ...this._def.shape(), + // ...augmentation, + // }), + // }) as any; + // } + /** + * @deprecated Use `.extend` instead + * */ + augment = this.extend; + + /** + * Prior to zod@1.0.12 there was a bug in the + * inferred type of merged objects. Please + * upgrade if you are experiencing issues. + */ + merge( + merging: Incoming + ): ZodObject, Incoming["_def"]["unknownKeys"], Incoming["_def"]["catchall"]> { + const merged: any = new ZodObject({ + unknownKeys: merging._def.unknownKeys, + catchall: merging._def.catchall, + shape: () => ({ + ...this._def.shape(), + ...merging._def.shape(), + }), + typeName: ZodFirstPartyTypeKind.ZodObject, + }) as any; + return merged; + } + // merge< + // Incoming extends AnyZodObject, + // Augmentation extends Incoming["shape"], + // NewOutput extends { + // [k in keyof Augmentation | keyof Output]: k extends keyof Augmentation + // ? Augmentation[k]["_output"] + // : k extends keyof Output + // ? Output[k] + // : never; + // }, + // NewInput extends { + // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation + // ? Augmentation[k]["_input"] + // : k extends keyof Input + // ? Input[k] + // : never; + // } + // >( + // merging: Incoming + // ): ZodObject< + // extendShape>, + // Incoming["_def"]["unknownKeys"], + // Incoming["_def"]["catchall"], + // NewOutput, + // NewInput + // > { + // const merged: any = new ZodObject({ + // unknownKeys: merging._def.unknownKeys, + // catchall: merging._def.catchall, + // shape: () => + // objectUtil.mergeShapes(this._def.shape(), merging._def.shape()), + // typeName: ZodFirstPartyTypeKind.ZodObject, + // }) as any; + // return merged; + // } + + setKey( + key: Key, + schema: Schema + ): ZodObject { + return this.augment({ [key]: schema }) as any; + } + // merge( + // merging: Incoming + // ): //ZodObject = (merging) => { + // ZodObject< + // extendShape>, + // Incoming["_def"]["unknownKeys"], + // Incoming["_def"]["catchall"] + // > { + // // const mergedShape = objectUtil.mergeShapes( + // // this._def.shape(), + // // merging._def.shape() + // // ); + // const merged: any = new ZodObject({ + // unknownKeys: merging._def.unknownKeys, + // catchall: merging._def.catchall, + // shape: () => + // objectUtil.mergeShapes(this._def.shape(), merging._def.shape()), + // typeName: ZodFirstPartyTypeKind.ZodObject, + // }) as any; + // return merged; + // } + + catchall(index: Index): ZodObject { + return new ZodObject({ + ...this._def, + catchall: index, + }) as any; + } + + pick>( + mask: Mask + ): ZodObject>, UnknownKeys, Catchall> { + const shape: any = {}; + + for (const key of util.objectKeys(mask)) { + if (mask[key] && this.shape[key]) { + shape[key] = this.shape[key]; + } + } + + return new ZodObject({ + ...this._def, + shape: () => shape, + }) as any; + } + + omit>( + mask: Mask + ): ZodObject, UnknownKeys, Catchall> { + const shape: any = {}; + + for (const key of util.objectKeys(this.shape)) { + if (!mask[key]) { + shape[key] = this.shape[key]; + } + } + + return new ZodObject({ + ...this._def, + shape: () => shape, + }) as any; + } + + /** + * @deprecated + */ + deepPartial(): partialUtil.DeepPartial { + return deepPartialify(this); + } + + partial(): ZodObject<{ [k in keyof T]: ZodOptional }, UnknownKeys, Catchall>; + partial>( + mask: Mask + ): ZodObject< + objectUtil.noNever<{ + [k in keyof T]: k extends keyof Mask ? ZodOptional : T[k]; + }>, + UnknownKeys, + Catchall + >; + partial(mask?: any) { + const newShape: any = {}; + + for (const key of util.objectKeys(this.shape)) { + const fieldSchema = this.shape[key]!; + + if (mask && !mask[key]) { + newShape[key] = fieldSchema; + } else { + newShape[key] = fieldSchema.optional(); + } + } + + return new ZodObject({ + ...this._def, + shape: () => newShape, + }) as any; + } + + required(): ZodObject<{ [k in keyof T]: deoptional }, UnknownKeys, Catchall>; + required>( + mask: Mask + ): ZodObject< + objectUtil.noNever<{ + [k in keyof T]: k extends keyof Mask ? deoptional : T[k]; + }>, + UnknownKeys, + Catchall + >; + required(mask?: any) { + const newShape: any = {}; + + for (const key of util.objectKeys(this.shape)) { + if (mask && !mask[key]) { + newShape[key] = this.shape[key]; + } else { + const fieldSchema = this.shape[key]; + let newField = fieldSchema; + + while (newField instanceof ZodOptional) { + newField = (newField as ZodOptional)._def.innerType; + } + + newShape[key] = newField; + } + } + + return new ZodObject({ + ...this._def, + shape: () => newShape, + }) as any; + } + + keyof(): ZodEnum> { + return createZodEnum(util.objectKeys(this.shape) as [string, ...string[]]) as any; + } + + static create = ( + shape: Shape, + params?: RawCreateParams + ): ZodObject< + Shape, + "strip", + ZodTypeAny, + objectOutputType, + objectInputType + > => { + return new ZodObject({ + shape: () => shape, + unknownKeys: "strip", + catchall: ZodNever.create(), + typeName: ZodFirstPartyTypeKind.ZodObject, + ...processCreateParams(params), + }) as any; + }; + + static strictCreate = ( + shape: Shape, + params?: RawCreateParams + ): ZodObject => { + return new ZodObject({ + shape: () => shape, + unknownKeys: "strict", + catchall: ZodNever.create(), + typeName: ZodFirstPartyTypeKind.ZodObject, + ...processCreateParams(params), + }) as any; + }; + + static lazycreate = ( + shape: () => Shape, + params?: RawCreateParams + ): ZodObject => { + return new ZodObject({ + shape, + unknownKeys: "strip", + catchall: ZodNever.create(), + typeName: ZodFirstPartyTypeKind.ZodObject, + ...processCreateParams(params), + }) as any; + }; +} + +export type AnyZodObject = ZodObject; + +//////////////////////////////////////// +//////////////////////////////////////// +////////// ////////// +////////// ZodUnion ////////// +////////// ////////// +//////////////////////////////////////// +//////////////////////////////////////// +export type ZodUnionOptions = Readonly<[ZodTypeAny, ...ZodTypeAny[]]>; +export interface ZodUnionDef> + extends ZodTypeDef { + options: T; + typeName: ZodFirstPartyTypeKind.ZodUnion; +} + +export class ZodUnion extends ZodType< + T[number]["_output"], + ZodUnionDef, + T[number]["_input"] +> { + _parse(input: ParseInput): ParseReturnType { + const { ctx } = this._processInputParams(input); + const options = this._def.options; + + function handleResults(results: { ctx: ParseContext; result: SyncParseReturnType }[]) { + // return first issue-free validation if it exists + for (const result of results) { + if (result.result.status === "valid") { + return result.result; + } + } + + for (const result of results) { + if (result.result.status === "dirty") { + // add issues from dirty option + + ctx.common.issues.push(...result.ctx.common.issues); + return result.result; + } + } + + // return invalid + const unionErrors = results.map((result) => new ZodError(result.ctx.common.issues)); + + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_union, + unionErrors, + }); + return INVALID; + } + + if (ctx.common.async) { + return Promise.all( + options.map(async (option) => { + const childCtx: ParseContext = { + ...ctx, + common: { + ...ctx.common, + issues: [], + }, + parent: null, + }; + return { + result: await option._parseAsync({ + data: ctx.data, + path: ctx.path, + parent: childCtx, + }), + ctx: childCtx, + }; + }) + ).then(handleResults); + } else { + let dirty: undefined | { result: DIRTY; ctx: ParseContext } = undefined; + const issues: ZodIssue[][] = []; + for (const option of options) { + const childCtx: ParseContext = { + ...ctx, + common: { + ...ctx.common, + issues: [], + }, + parent: null, + }; + const result = option._parseSync({ + data: ctx.data, + path: ctx.path, + parent: childCtx, + }); + + if (result.status === "valid") { + return result; + } else if (result.status === "dirty" && !dirty) { + dirty = { result, ctx: childCtx }; + } + + if (childCtx.common.issues.length) { + issues.push(childCtx.common.issues); + } + } + + if (dirty) { + ctx.common.issues.push(...dirty.ctx.common.issues); + return dirty.result; + } + + const unionErrors = issues.map((issues) => new ZodError(issues)); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_union, + unionErrors, + }); + + return INVALID; + } + } + + get options() { + return this._def.options; + } + + static create = >( + types: Options, + params?: RawCreateParams + ): ZodUnion => { + return new ZodUnion({ + options: types, + typeName: ZodFirstPartyTypeKind.ZodUnion, + ...processCreateParams(params), + }); + }; +} + +///////////////////////////////////////////////////// +///////////////////////////////////////////////////// +////////// ////////// +////////// ZodDiscriminatedUnion ////////// +////////// ////////// +///////////////////////////////////////////////////// +///////////////////////////////////////////////////// + +const getDiscriminator = (type: T): Primitive[] => { + if (type instanceof ZodLazy) { + return getDiscriminator(type.schema); + } else if (type instanceof ZodEffects) { + return getDiscriminator(type.innerType()); + } else if (type instanceof ZodLiteral) { + return [type.value]; + } else if (type instanceof ZodEnum) { + return type.options; + } else if (type instanceof ZodNativeEnum) { + // eslint-disable-next-line ban/ban + return util.objectValues(type.enum); + } else if (type instanceof ZodDefault) { + return getDiscriminator(type._def.innerType); + } else if (type instanceof ZodUndefined) { + return [undefined]; + } else if (type instanceof ZodNull) { + return [null]; + } else if (type instanceof ZodOptional) { + return [undefined, ...getDiscriminator(type.unwrap())]; + } else if (type instanceof ZodNullable) { + return [null, ...getDiscriminator(type.unwrap())]; + } else if (type instanceof ZodBranded) { + return getDiscriminator(type.unwrap()); + } else if (type instanceof ZodReadonly) { + return getDiscriminator(type.unwrap()); + } else if (type instanceof ZodCatch) { + return getDiscriminator(type._def.innerType); + } else { + return []; + } +}; + +export type ZodDiscriminatedUnionOption = ZodObject< + { [key in Discriminator]: ZodTypeAny } & ZodRawShape, + UnknownKeysParam, + ZodTypeAny +>; + +export interface ZodDiscriminatedUnionDef< + Discriminator extends string, + Options extends readonly ZodDiscriminatedUnionOption[] = ZodDiscriminatedUnionOption[], +> extends ZodTypeDef { + discriminator: Discriminator; + options: Options; + optionsMap: Map>; + typeName: ZodFirstPartyTypeKind.ZodDiscriminatedUnion; +} + +export class ZodDiscriminatedUnion< + Discriminator extends string, + Options extends readonly ZodDiscriminatedUnionOption[], +> extends ZodType, ZodDiscriminatedUnionDef, input> { + _parse(input: ParseInput): ParseReturnType { + const { ctx } = this._processInputParams(input); + + if (ctx.parsedType !== ZodParsedType.object) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.object, + received: ctx.parsedType, + }); + return INVALID; + } + + const discriminator = this.discriminator; + + const discriminatorValue: string = ctx.data[discriminator]; + + const option = this.optionsMap.get(discriminatorValue); + + if (!option) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_union_discriminator, + options: Array.from(this.optionsMap.keys()), + path: [discriminator], + }); + return INVALID; + } + + if (ctx.common.async) { + return option._parseAsync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }) as any; + } else { + return option._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }) as any; + } + } + + get discriminator() { + return this._def.discriminator; + } + + get options() { + return this._def.options; + } + + get optionsMap() { + return this._def.optionsMap; + } + + /** + * The constructor of the discriminated union schema. Its behaviour is very similar to that of the normal z.union() constructor. + * However, it only allows a union of objects, all of which need to share a discriminator property. This property must + * have a different value for each object in the union. + * @param discriminator the name of the discriminator property + * @param types an array of object schemas + * @param params + */ + static create< + Discriminator extends string, + Types extends readonly [ + ZodDiscriminatedUnionOption, + ...ZodDiscriminatedUnionOption[], + ], + >( + discriminator: Discriminator, + options: Types, + params?: RawCreateParams + ): ZodDiscriminatedUnion { + // Get all the valid discriminator values + const optionsMap: Map = new Map(); + + // try { + for (const type of options) { + const discriminatorValues = getDiscriminator(type.shape[discriminator]); + if (!discriminatorValues.length) { + throw new Error( + `A discriminator value for key \`${discriminator}\` could not be extracted from all schema options` + ); + } + for (const value of discriminatorValues) { + if (optionsMap.has(value)) { + throw new Error(`Discriminator property ${String(discriminator)} has duplicate value ${String(value)}`); + } + + optionsMap.set(value, type); + } + } + + return new ZodDiscriminatedUnion< + Discriminator, + // DiscriminatorValue, + Types + >({ + typeName: ZodFirstPartyTypeKind.ZodDiscriminatedUnion, + discriminator, + options, + optionsMap, + ...processCreateParams(params), + }); + } +} + +/////////////////////////////////////////////// +/////////////////////////////////////////////// +////////// ////////// +////////// ZodIntersection ////////// +////////// ////////// +/////////////////////////////////////////////// +/////////////////////////////////////////////// +export interface ZodIntersectionDef + extends ZodTypeDef { + left: T; + right: U; + typeName: ZodFirstPartyTypeKind.ZodIntersection; +} + +function mergeValues(a: any, b: any): { valid: true; data: any } | { valid: false } { + const aType = getParsedType(a); + const bType = getParsedType(b); + + if (a === b) { + return { valid: true, data: a }; + } else if (aType === ZodParsedType.object && bType === ZodParsedType.object) { + const bKeys = util.objectKeys(b); + const sharedKeys = util.objectKeys(a).filter((key) => bKeys.indexOf(key) !== -1); + + const newObj: any = { ...a, ...b }; + for (const key of sharedKeys) { + const sharedValue = mergeValues(a[key], b[key]); + if (!sharedValue.valid) { + return { valid: false }; + } + newObj[key] = sharedValue.data; + } + + return { valid: true, data: newObj }; + } else if (aType === ZodParsedType.array && bType === ZodParsedType.array) { + if (a.length !== b.length) { + return { valid: false }; + } + + const newArray: unknown[] = []; + for (let index = 0; index < a.length; index++) { + const itemA = a[index]; + const itemB = b[index]; + const sharedValue = mergeValues(itemA, itemB); + + if (!sharedValue.valid) { + return { valid: false }; + } + + newArray.push(sharedValue.data); + } + + return { valid: true, data: newArray }; + } else if (aType === ZodParsedType.date && bType === ZodParsedType.date && +a === +b) { + return { valid: true, data: a }; + } else { + return { valid: false }; + } +} + +export class ZodIntersection extends ZodType< + T["_output"] & U["_output"], + ZodIntersectionDef, + T["_input"] & U["_input"] +> { + _parse(input: ParseInput): ParseReturnType { + const { status, ctx } = this._processInputParams(input); + const handleParsed = ( + parsedLeft: SyncParseReturnType, + parsedRight: SyncParseReturnType + ): SyncParseReturnType => { + if (isAborted(parsedLeft) || isAborted(parsedRight)) { + return INVALID; + } + + const merged = mergeValues(parsedLeft.value, parsedRight.value); + + if (!merged.valid) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_intersection_types, + }); + return INVALID; + } + + if (isDirty(parsedLeft) || isDirty(parsedRight)) { + status.dirty(); + } + + return { status: status.value, value: merged.data }; + }; + + if (ctx.common.async) { + return Promise.all([ + this._def.left._parseAsync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }), + this._def.right._parseAsync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }), + ]).then(([left, right]: any) => handleParsed(left, right)); + } else { + return handleParsed( + this._def.left._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }), + this._def.right._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }) + ); + } + } + + static create = ( + left: TSchema, + right: USchema, + params?: RawCreateParams + ): ZodIntersection => { + return new ZodIntersection({ + left: left, + right: right, + typeName: ZodFirstPartyTypeKind.ZodIntersection, + ...processCreateParams(params), + }); + }; +} + +//////////////////////////////////////// +//////////////////////////////////////// +////////// ////////// +////////// ZodTuple ////////// +////////// ////////// +//////////////////////////////////////// +//////////////////////////////////////// +export type ZodTupleItems = [ZodTypeAny, ...ZodTypeAny[]]; +export type AssertArray = T extends any[] ? T : never; +export type OutputTypeOfTuple = AssertArray<{ + [k in keyof T]: T[k] extends ZodType ? T[k]["_output"] : never; +}>; +export type OutputTypeOfTupleWithRest< + T extends ZodTupleItems | [], + Rest extends ZodTypeAny | null = null, +> = Rest extends ZodTypeAny ? [...OutputTypeOfTuple, ...Rest["_output"][]] : OutputTypeOfTuple; + +export type InputTypeOfTuple = AssertArray<{ + [k in keyof T]: T[k] extends ZodType ? T[k]["_input"] : never; +}>; +export type InputTypeOfTupleWithRest< + T extends ZodTupleItems | [], + Rest extends ZodTypeAny | null = null, +> = Rest extends ZodTypeAny ? [...InputTypeOfTuple, ...Rest["_input"][]] : InputTypeOfTuple; + +export interface ZodTupleDef + extends ZodTypeDef { + items: T; + rest: Rest; + typeName: ZodFirstPartyTypeKind.ZodTuple; +} + +export type AnyZodTuple = ZodTuple<[ZodTypeAny, ...ZodTypeAny[]] | [], ZodTypeAny | null>; +// type ZodTupleItems = [ZodTypeAny, ...ZodTypeAny[]]; +export class ZodTuple< + T extends ZodTupleItems | [] = ZodTupleItems, + Rest extends ZodTypeAny | null = null, +> extends ZodType, ZodTupleDef, InputTypeOfTupleWithRest> { + _parse(input: ParseInput): ParseReturnType { + const { status, ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.array) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.array, + received: ctx.parsedType, + }); + return INVALID; + } + + if (ctx.data.length < this._def.items.length) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: this._def.items.length, + inclusive: true, + exact: false, + type: "array", + }); + + return INVALID; + } + + const rest = this._def.rest; + + if (!rest && ctx.data.length > this._def.items.length) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: this._def.items.length, + inclusive: true, + exact: false, + type: "array", + }); + status.dirty(); + } + + const items = ([...ctx.data] as any[]) + .map((item, itemIndex) => { + const schema = this._def.items[itemIndex] || this._def.rest; + if (!schema) return null as any as SyncParseReturnType; + return schema._parse(new ParseInputLazyPath(ctx, item, ctx.path, itemIndex)); + }) + .filter((x) => !!x); // filter nulls + + if (ctx.common.async) { + return Promise.all(items).then((results) => { + return ParseStatus.mergeArray(status, results); + }); + } else { + return ParseStatus.mergeArray(status, items as SyncParseReturnType[]); + } + } + + get items() { + return this._def.items; + } + + rest(rest: RestSchema): ZodTuple { + return new ZodTuple({ + ...this._def, + rest, + }); + } + + static create = ( + schemas: Items, + params?: RawCreateParams + ): ZodTuple => { + if (!Array.isArray(schemas)) { + throw new Error("You must pass an array of schemas to z.tuple([ ... ])"); + } + return new ZodTuple({ + items: schemas, + typeName: ZodFirstPartyTypeKind.ZodTuple, + rest: null, + ...processCreateParams(params), + }); + }; +} + +///////////////////////////////////////// +///////////////////////////////////////// +////////// ////////// +////////// ZodRecord ////////// +////////// ////////// +///////////////////////////////////////// +///////////////////////////////////////// +export interface ZodRecordDef + extends ZodTypeDef { + valueType: Value; + keyType: Key; + typeName: ZodFirstPartyTypeKind.ZodRecord; +} + +export type KeySchema = ZodType; +export type RecordType = [string] extends [K] + ? Record + : [number] extends [K] + ? Record + : [symbol] extends [K] + ? Record + : [BRAND] extends [K] + ? Record + : Partial>; +export class ZodRecord extends ZodType< + RecordType, + ZodRecordDef, + RecordType +> { + get keySchema() { + return this._def.keyType; + } + get valueSchema() { + return this._def.valueType; + } + _parse(input: ParseInput): ParseReturnType { + const { status, ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.object) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.object, + received: ctx.parsedType, + }); + return INVALID; + } + + const pairs: { + key: ParseReturnType; + value: ParseReturnType; + alwaysSet: boolean; + }[] = []; + + const keyType = this._def.keyType; + const valueType = this._def.valueType; + + for (const key in ctx.data) { + pairs.push({ + key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, key)), + value: valueType._parse(new ParseInputLazyPath(ctx, ctx.data[key], ctx.path, key)), + alwaysSet: key in ctx.data, + }); + } + + if (ctx.common.async) { + return ParseStatus.mergeObjectAsync(status, pairs); + } else { + return ParseStatus.mergeObjectSync(status, pairs as any); + } + } + + get element() { + return this._def.valueType; + } + + static create(valueType: Value, params?: RawCreateParams): ZodRecord; + static create( + keySchema: Keys, + valueType: Value, + params?: RawCreateParams + ): ZodRecord; + static create(first: any, second?: any, third?: any): ZodRecord { + if (second instanceof ZodType) { + return new ZodRecord({ + keyType: first, + valueType: second, + typeName: ZodFirstPartyTypeKind.ZodRecord, + ...processCreateParams(third), + }); + } + + return new ZodRecord({ + keyType: ZodString.create(), + valueType: first, + typeName: ZodFirstPartyTypeKind.ZodRecord, + ...processCreateParams(second), + }); + } +} + +////////////////////////////////////// +////////////////////////////////////// +////////// ////////// +////////// ZodMap ////////// +////////// ////////// +////////////////////////////////////// +////////////////////////////////////// +export interface ZodMapDef + extends ZodTypeDef { + valueType: Value; + keyType: Key; + typeName: ZodFirstPartyTypeKind.ZodMap; +} + +export class ZodMap extends ZodType< + Map, + ZodMapDef, + Map +> { + get keySchema() { + return this._def.keyType; + } + get valueSchema() { + return this._def.valueType; + } + _parse(input: ParseInput): ParseReturnType { + const { status, ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.map) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.map, + received: ctx.parsedType, + }); + return INVALID; + } + + const keyType = this._def.keyType; + const valueType = this._def.valueType; + + const pairs = [...(ctx.data as Map).entries()].map(([key, value], index) => { + return { + key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index, "key"])), + value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index, "value"])), + }; + }); + + if (ctx.common.async) { + const finalMap = new Map(); + return Promise.resolve().then(async () => { + for (const pair of pairs) { + const key = await pair.key; + const value = await pair.value; + if (key.status === "aborted" || value.status === "aborted") { + return INVALID; + } + if (key.status === "dirty" || value.status === "dirty") { + status.dirty(); + } + + finalMap.set(key.value, value.value); + } + return { status: status.value, value: finalMap }; + }); + } else { + const finalMap = new Map(); + for (const pair of pairs) { + const key = pair.key as SyncParseReturnType; + const value = pair.value as SyncParseReturnType; + if (key.status === "aborted" || value.status === "aborted") { + return INVALID; + } + if (key.status === "dirty" || value.status === "dirty") { + status.dirty(); + } + + finalMap.set(key.value, value.value); + } + return { status: status.value, value: finalMap }; + } + } + static create = ( + keyType: KeySchema, + valueType: ValueSchema, + params?: RawCreateParams + ): ZodMap => { + return new ZodMap({ + valueType, + keyType, + typeName: ZodFirstPartyTypeKind.ZodMap, + ...processCreateParams(params), + }); + }; +} + +////////////////////////////////////// +////////////////////////////////////// +////////// ////////// +////////// ZodSet ////////// +////////// ////////// +////////////////////////////////////// +////////////////////////////////////// +export interface ZodSetDef extends ZodTypeDef { + valueType: Value; + typeName: ZodFirstPartyTypeKind.ZodSet; + minSize: { value: number; message?: string | undefined } | null; + maxSize: { value: number; message?: string | undefined } | null; +} + +export class ZodSet extends ZodType< + Set, + ZodSetDef, + Set +> { + _parse(input: ParseInput): ParseReturnType { + const { status, ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.set) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.set, + received: ctx.parsedType, + }); + return INVALID; + } + + const def = this._def; + + if (def.minSize !== null) { + if (ctx.data.size < def.minSize.value) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: def.minSize.value, + type: "set", + inclusive: true, + exact: false, + message: def.minSize.message, + }); + status.dirty(); + } + } + + if (def.maxSize !== null) { + if (ctx.data.size > def.maxSize.value) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: def.maxSize.value, + type: "set", + inclusive: true, + exact: false, + message: def.maxSize.message, + }); + status.dirty(); + } + } + + const valueType = this._def.valueType; + + function finalizeSet(elements: SyncParseReturnType[]) { + const parsedSet = new Set(); + for (const element of elements) { + if (element.status === "aborted") return INVALID; + if (element.status === "dirty") status.dirty(); + parsedSet.add(element.value); + } + return { status: status.value, value: parsedSet }; + } + + const elements = [...(ctx.data as Set).values()].map((item, i) => + valueType._parse(new ParseInputLazyPath(ctx, item, ctx.path, i)) + ); + + if (ctx.common.async) { + return Promise.all(elements).then((elements) => finalizeSet(elements)); + } else { + return finalizeSet(elements as SyncParseReturnType[]); + } + } + + min(minSize: number, message?: errorUtil.ErrMessage): this { + return new ZodSet({ + ...this._def, + minSize: { value: minSize, message: errorUtil.toString(message) }, + }) as any; + } + + max(maxSize: number, message?: errorUtil.ErrMessage): this { + return new ZodSet({ + ...this._def, + maxSize: { value: maxSize, message: errorUtil.toString(message) }, + }) as any; + } + + size(size: number, message?: errorUtil.ErrMessage): this { + return this.min(size, message).max(size, message) as any; + } + + nonempty(message?: errorUtil.ErrMessage): ZodSet { + return this.min(1, message) as any; + } + + static create = ( + valueType: ValueSchema, + params?: RawCreateParams + ): ZodSet => { + return new ZodSet({ + valueType, + minSize: null, + maxSize: null, + typeName: ZodFirstPartyTypeKind.ZodSet, + ...processCreateParams(params), + }); + }; +} + +/////////////////////////////////////////// +/////////////////////////////////////////// +////////// ////////// +////////// ZodFunction ////////// +////////// ////////// +/////////////////////////////////////////// +/////////////////////////////////////////// +export interface ZodFunctionDef< + Args extends ZodTuple = ZodTuple, + Returns extends ZodTypeAny = ZodTypeAny, +> extends ZodTypeDef { + args: Args; + returns: Returns; + typeName: ZodFirstPartyTypeKind.ZodFunction; +} + +export type OuterTypeOfFunction< + Args extends ZodTuple, + Returns extends ZodTypeAny, +> = Args["_input"] extends Array ? (...args: Args["_input"]) => Returns["_output"] : never; + +export type InnerTypeOfFunction< + Args extends ZodTuple, + Returns extends ZodTypeAny, +> = Args["_output"] extends Array ? (...args: Args["_output"]) => Returns["_input"] : never; + +export class ZodFunction, Returns extends ZodTypeAny> extends ZodType< + OuterTypeOfFunction, + ZodFunctionDef, + InnerTypeOfFunction +> { + _parse(input: ParseInput): ParseReturnType { + const { ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.function) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.function, + received: ctx.parsedType, + }); + return INVALID; + } + + function makeArgsIssue(args: any, error: ZodError): ZodIssue { + return makeIssue({ + data: args, + path: ctx.path, + errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), defaultErrorMap].filter( + (x) => !!x + ), + issueData: { + code: ZodIssueCode.invalid_arguments, + argumentsError: error, + }, + }); + } + + function makeReturnsIssue(returns: any, error: ZodError): ZodIssue { + return makeIssue({ + data: returns, + path: ctx.path, + errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), defaultErrorMap].filter( + (x) => !!x + ), + issueData: { + code: ZodIssueCode.invalid_return_type, + returnTypeError: error, + }, + }); + } + + const params = { errorMap: ctx.common.contextualErrorMap }; + const fn = ctx.data; + + if (this._def.returns instanceof ZodPromise) { + // Would love a way to avoid disabling this rule, but we need + // an alias (using an arrow function was what caused 2651). + // eslint-disable-next-line @typescript-eslint/no-this-alias + const me = this; + return OK(async function (this: any, ...args: any[]) { + const error = new ZodError([]); + const parsedArgs = await me._def.args.parseAsync(args, params).catch((e) => { + error.addIssue(makeArgsIssue(args, e)); + throw error; + }); + const result = await Reflect.apply(fn, this, parsedArgs as any); + const parsedReturns = await (me._def.returns as unknown as ZodPromise)._def.type + .parseAsync(result, params) + .catch((e) => { + error.addIssue(makeReturnsIssue(result, e)); + throw error; + }); + return parsedReturns; + }); + } else { + // Would love a way to avoid disabling this rule, but we need + // an alias (using an arrow function was what caused 2651). + // eslint-disable-next-line @typescript-eslint/no-this-alias + const me = this; + return OK(function (this: any, ...args: any[]) { + const parsedArgs = me._def.args.safeParse(args, params); + if (!parsedArgs.success) { + throw new ZodError([makeArgsIssue(args, parsedArgs.error)]); + } + const result = Reflect.apply(fn, this, parsedArgs.data); + const parsedReturns = me._def.returns.safeParse(result, params); + if (!parsedReturns.success) { + throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]); + } + return parsedReturns.data; + }) as any; + } + } + + parameters() { + return this._def.args; + } + + returnType() { + return this._def.returns; + } + + args[0]>( + ...items: Items + ): ZodFunction, Returns> { + return new ZodFunction({ + ...this._def, + args: ZodTuple.create(items).rest(ZodUnknown.create()) as any, + }); + } + + returns>(returnType: NewReturnType): ZodFunction { + return new ZodFunction({ + ...this._def, + returns: returnType, + }); + } + + implement>( + func: F + ): ReturnType extends Returns["_output"] + ? (...args: Args["_input"]) => ReturnType + : OuterTypeOfFunction { + const validatedFunc = this.parse(func); + return validatedFunc as any; + } + + strictImplement(func: InnerTypeOfFunction): InnerTypeOfFunction { + const validatedFunc = this.parse(func); + return validatedFunc as any; + } + + validate = this.implement; + + static create(): ZodFunction, ZodUnknown>; + static create>(args: T): ZodFunction; + static create(args: T, returns: U): ZodFunction; + static create, U extends ZodTypeAny = ZodUnknown>( + args: T, + returns: U, + params?: RawCreateParams + ): ZodFunction; + static create(args?: AnyZodTuple, returns?: ZodTypeAny, params?: RawCreateParams) { + return new ZodFunction({ + args: (args ? args : ZodTuple.create([]).rest(ZodUnknown.create())) as any, + returns: returns || ZodUnknown.create(), + typeName: ZodFirstPartyTypeKind.ZodFunction, + ...processCreateParams(params), + }) as any; + } +} + +/////////////////////////////////////// +/////////////////////////////////////// +////////// ////////// +////////// ZodLazy ////////// +////////// ////////// +/////////////////////////////////////// +/////////////////////////////////////// +export interface ZodLazyDef extends ZodTypeDef { + getter: () => T; + typeName: ZodFirstPartyTypeKind.ZodLazy; +} + +export class ZodLazy extends ZodType, ZodLazyDef, input> { + get schema(): T { + return this._def.getter(); + } + + _parse(input: ParseInput): ParseReturnType { + const { ctx } = this._processInputParams(input); + const lazySchema = this._def.getter(); + return lazySchema._parse({ data: ctx.data, path: ctx.path, parent: ctx }); + } + + static create = (getter: () => Inner, params?: RawCreateParams): ZodLazy => { + return new ZodLazy({ + getter: getter, + typeName: ZodFirstPartyTypeKind.ZodLazy, + ...processCreateParams(params), + }); + }; +} + +////////////////////////////////////////// +////////////////////////////////////////// +////////// ////////// +////////// ZodLiteral ////////// +////////// ////////// +////////////////////////////////////////// +////////////////////////////////////////// +export interface ZodLiteralDef extends ZodTypeDef { + value: T; + typeName: ZodFirstPartyTypeKind.ZodLiteral; +} + +export class ZodLiteral extends ZodType, T> { + _parse(input: ParseInput): ParseReturnType { + if (input.data !== this._def.value) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + received: ctx.data, + code: ZodIssueCode.invalid_literal, + expected: this._def.value, + }); + return INVALID; + } + return { status: "valid", value: input.data }; + } + + get value() { + return this._def.value; + } + + static create = (value: Value, params?: RawCreateParams): ZodLiteral => { + return new ZodLiteral({ + value: value, + typeName: ZodFirstPartyTypeKind.ZodLiteral, + ...processCreateParams(params), + }); + }; +} + +/////////////////////////////////////// +/////////////////////////////////////// +////////// ////////// +////////// ZodEnum ////////// +////////// ////////// +/////////////////////////////////////// +/////////////////////////////////////// +export type ArrayKeys = keyof any[]; +export type Indices = Exclude; + +export type EnumValues = readonly [T, ...T[]]; + +export type Values = { + [k in T[number]]: k; +}; + +export interface ZodEnumDef extends ZodTypeDef { + values: T; + typeName: ZodFirstPartyTypeKind.ZodEnum; +} + +export type Writeable = { -readonly [P in keyof T]: T[P] }; + +export type FilterEnum = Values extends [] + ? [] + : Values extends [infer Head, ...infer Rest] + ? Head extends ToExclude + ? FilterEnum + : [Head, ...FilterEnum] + : never; + +export type typecast = A extends T ? A : never; + +function createZodEnum>( + values: T, + params?: RawCreateParams +): ZodEnum>; +function createZodEnum(values: T, params?: RawCreateParams): ZodEnum; +function createZodEnum(values: [string, ...string[]], params?: RawCreateParams) { + return new ZodEnum({ + values, + typeName: ZodFirstPartyTypeKind.ZodEnum, + ...processCreateParams(params), + }); +} + +export class ZodEnum extends ZodType, T[number]> { + _cache: Set | undefined; + + _parse(input: ParseInput): ParseReturnType { + if (typeof input.data !== "string") { + const ctx = this._getOrReturnCtx(input); + const expectedValues = this._def.values; + addIssueToContext(ctx, { + expected: util.joinValues(expectedValues) as "string", + received: ctx.parsedType, + code: ZodIssueCode.invalid_type, + }); + return INVALID; + } + + if (!this._cache) { + this._cache = new Set(this._def.values); + } + + if (!this._cache.has(input.data)) { + const ctx = this._getOrReturnCtx(input); + const expectedValues = this._def.values; + + addIssueToContext(ctx, { + received: ctx.data, + code: ZodIssueCode.invalid_enum_value, + options: expectedValues, + }); + return INVALID; + } + return OK(input.data); + } + + get options() { + return this._def.values; + } + + get enum(): Values { + const enumValues: any = {}; + for (const val of this._def.values) { + enumValues[val] = val; + } + return enumValues; + } + + get Values(): Values { + const enumValues: any = {}; + for (const val of this._def.values) { + enumValues[val] = val; + } + return enumValues; + } + + get Enum(): Values { + const enumValues: any = {}; + for (const val of this._def.values) { + enumValues[val] = val; + } + return enumValues; + } + + extract( + values: ToExtract, + newDef: RawCreateParams = this._def + ): ZodEnum> { + return ZodEnum.create(values, { + ...this._def, + ...newDef, + }) as any; + } + + exclude( + values: ToExclude, + newDef: RawCreateParams = this._def + ): ZodEnum>, [string, ...string[]]>> { + return ZodEnum.create(this.options.filter((opt) => !values.includes(opt)) as FilterEnum, { + ...this._def, + ...newDef, + }) as any; + } + + static create = createZodEnum; +} + +///////////////////////////////////////////// +///////////////////////////////////////////// +////////// ////////// +////////// ZodNativeEnum ////////// +////////// ////////// +///////////////////////////////////////////// +///////////////////////////////////////////// +export interface ZodNativeEnumDef extends ZodTypeDef { + values: T; + typeName: ZodFirstPartyTypeKind.ZodNativeEnum; +} + +export type EnumLike = { [k: string]: string | number; [nu: number]: string }; + +export class ZodNativeEnum extends ZodType, T[keyof T]> { + _cache: Set | undefined; + _parse(input: ParseInput): ParseReturnType { + const nativeEnumValues = util.getValidEnumValues(this._def.values); + + const ctx = this._getOrReturnCtx(input); + if (ctx.parsedType !== ZodParsedType.string && ctx.parsedType !== ZodParsedType.number) { + const expectedValues = util.objectValues(nativeEnumValues); + addIssueToContext(ctx, { + expected: util.joinValues(expectedValues) as "string", + received: ctx.parsedType, + code: ZodIssueCode.invalid_type, + }); + return INVALID; + } + + if (!this._cache) { + this._cache = new Set(util.getValidEnumValues(this._def.values)); + } + + if (!this._cache.has(input.data)) { + const expectedValues = util.objectValues(nativeEnumValues); + + addIssueToContext(ctx, { + received: ctx.data, + code: ZodIssueCode.invalid_enum_value, + options: expectedValues, + }); + return INVALID; + } + return OK(input.data); + } + + get enum() { + return this._def.values; + } + + static create = (values: Elements, params?: RawCreateParams): ZodNativeEnum => { + return new ZodNativeEnum({ + values: values, + typeName: ZodFirstPartyTypeKind.ZodNativeEnum, + ...processCreateParams(params), + }); + }; +} + +////////////////////////////////////////// +////////////////////////////////////////// +////////// ////////// +////////// ZodPromise ////////// +////////// ////////// +////////////////////////////////////////// +////////////////////////////////////////// +export interface ZodPromiseDef extends ZodTypeDef { + type: T; + typeName: ZodFirstPartyTypeKind.ZodPromise; +} + +export class ZodPromise extends ZodType< + Promise, + ZodPromiseDef, + Promise +> { + unwrap() { + return this._def.type; + } + + _parse(input: ParseInput): ParseReturnType { + const { ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.promise && ctx.common.async === false) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.promise, + received: ctx.parsedType, + }); + return INVALID; + } + + const promisified = ctx.parsedType === ZodParsedType.promise ? ctx.data : Promise.resolve(ctx.data); + + return OK( + promisified.then((data: any) => { + return this._def.type.parseAsync(data, { + path: ctx.path, + errorMap: ctx.common.contextualErrorMap, + }); + }) + ); + } + + static create = (schema: Inner, params?: RawCreateParams): ZodPromise => { + return new ZodPromise({ + type: schema, + typeName: ZodFirstPartyTypeKind.ZodPromise, + ...processCreateParams(params), + }); + }; +} + +////////////////////////////////////////////// +////////////////////////////////////////////// +////////// ////////// +////////// ZodEffects ////////// +////////// ////////// +////////////////////////////////////////////// +////////////////////////////////////////////// + +export type Refinement = (arg: T, ctx: RefinementCtx) => any; +export type SuperRefinement = (arg: T, ctx: RefinementCtx) => void | Promise; + +export type RefinementEffect = { + type: "refinement"; + refinement: (arg: T, ctx: RefinementCtx) => any; +}; +export type TransformEffect = { + type: "transform"; + transform: (arg: T, ctx: RefinementCtx) => any; +}; +export type PreprocessEffect = { + type: "preprocess"; + transform: (arg: T, ctx: RefinementCtx) => any; +}; +export type Effect = RefinementEffect | TransformEffect | PreprocessEffect; + +export interface ZodEffectsDef extends ZodTypeDef { + schema: T; + typeName: ZodFirstPartyTypeKind.ZodEffects; + effect: Effect; +} + +export class ZodEffects, Input = input> extends ZodType< + Output, + ZodEffectsDef, + Input +> { + innerType() { + return this._def.schema; + } + + sourceType(): T { + return this._def.schema._def.typeName === ZodFirstPartyTypeKind.ZodEffects + ? (this._def.schema as unknown as ZodEffects).sourceType() + : (this._def.schema as T); + } + + _parse(input: ParseInput): ParseReturnType { + const { status, ctx } = this._processInputParams(input); + + const effect = this._def.effect || null; + + const checkCtx: RefinementCtx = { + addIssue: (arg: IssueData) => { + addIssueToContext(ctx, arg); + if (arg.fatal) { + status.abort(); + } else { + status.dirty(); + } + }, + get path() { + return ctx.path; + }, + }; + + checkCtx.addIssue = checkCtx.addIssue.bind(checkCtx); + + if (effect.type === "preprocess") { + const processed = effect.transform(ctx.data, checkCtx); + + if (ctx.common.async) { + return Promise.resolve(processed).then(async (processed) => { + if (status.value === "aborted") return INVALID; + + const result = await this._def.schema._parseAsync({ + data: processed, + path: ctx.path, + parent: ctx, + }); + if (result.status === "aborted") return INVALID; + if (result.status === "dirty") return DIRTY(result.value); + if (status.value === "dirty") return DIRTY(result.value); + return result; + }); + } else { + if (status.value === "aborted") return INVALID; + const result = this._def.schema._parseSync({ + data: processed, + path: ctx.path, + parent: ctx, + }); + if (result.status === "aborted") return INVALID; + if (result.status === "dirty") return DIRTY(result.value); + if (status.value === "dirty") return DIRTY(result.value); + return result; + } + } + if (effect.type === "refinement") { + const executeRefinement = (acc: unknown): any => { + const result = effect.refinement(acc, checkCtx); + if (ctx.common.async) { + return Promise.resolve(result); + } + if (result instanceof Promise) { + throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead."); + } + return acc; + }; + + if (ctx.common.async === false) { + const inner = this._def.schema._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }); + if (inner.status === "aborted") return INVALID; + if (inner.status === "dirty") status.dirty(); + + // return value is ignored + executeRefinement(inner.value); + return { status: status.value, value: inner.value }; + } else { + return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => { + if (inner.status === "aborted") return INVALID; + if (inner.status === "dirty") status.dirty(); + + return executeRefinement(inner.value).then(() => { + return { status: status.value, value: inner.value }; + }); + }); + } + } + + if (effect.type === "transform") { + if (ctx.common.async === false) { + const base = this._def.schema._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }); + + if (!isValid(base)) return INVALID; + + const result = effect.transform(base.value, checkCtx); + if (result instanceof Promise) { + throw new Error( + `Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.` + ); + } + + return { status: status.value, value: result }; + } else { + return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base) => { + if (!isValid(base)) return INVALID; + + return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({ + status: status.value, + value: result, + })); + }); + } + } + + util.assertNever(effect); + } + + static create = ( + schema: I, + effect: Effect, + params?: RawCreateParams + ): ZodEffects => { + return new ZodEffects({ + schema, + typeName: ZodFirstPartyTypeKind.ZodEffects, + effect, + ...processCreateParams(params), + }); + }; + + static createWithPreprocess = ( + preprocess: (arg: unknown, ctx: RefinementCtx) => unknown, + schema: I, + params?: RawCreateParams + ): ZodEffects => { + return new ZodEffects({ + schema, + effect: { type: "preprocess", transform: preprocess }, + typeName: ZodFirstPartyTypeKind.ZodEffects, + ...processCreateParams(params), + }); + }; +} + +export { ZodEffects as ZodTransformer }; + +/////////////////////////////////////////// +/////////////////////////////////////////// +////////// ////////// +////////// ZodOptional ////////// +////////// ////////// +/////////////////////////////////////////// +/////////////////////////////////////////// +export interface ZodOptionalDef extends ZodTypeDef { + innerType: T; + typeName: ZodFirstPartyTypeKind.ZodOptional; +} + +export type ZodOptionalType = ZodOptional; + +export class ZodOptional extends ZodType< + T["_output"] | undefined, + ZodOptionalDef, + T["_input"] | undefined +> { + _parse(input: ParseInput): ParseReturnType { + const parsedType = this._getType(input); + if (parsedType === ZodParsedType.undefined) { + return OK(undefined); + } + return this._def.innerType._parse(input); + } + + unwrap() { + return this._def.innerType; + } + + static create = (type: Inner, params?: RawCreateParams): ZodOptional => { + return new ZodOptional({ + innerType: type, + typeName: ZodFirstPartyTypeKind.ZodOptional, + ...processCreateParams(params), + }) as any; + }; +} + +/////////////////////////////////////////// +/////////////////////////////////////////// +////////// ////////// +////////// ZodNullable ////////// +////////// ////////// +/////////////////////////////////////////// +/////////////////////////////////////////// +export interface ZodNullableDef extends ZodTypeDef { + innerType: T; + typeName: ZodFirstPartyTypeKind.ZodNullable; +} + +export type ZodNullableType = ZodNullable; + +export class ZodNullable extends ZodType< + T["_output"] | null, + ZodNullableDef, + T["_input"] | null +> { + _parse(input: ParseInput): ParseReturnType { + const parsedType = this._getType(input); + if (parsedType === ZodParsedType.null) { + return OK(null); + } + return this._def.innerType._parse(input); + } + + unwrap() { + return this._def.innerType; + } + + static create = (type: Inner, params?: RawCreateParams): ZodNullable => { + return new ZodNullable({ + innerType: type, + typeName: ZodFirstPartyTypeKind.ZodNullable, + ...processCreateParams(params), + }) as any; + }; +} + +//////////////////////////////////////////// +//////////////////////////////////////////// +////////// ////////// +////////// ZodDefault ////////// +////////// ////////// +//////////////////////////////////////////// +//////////////////////////////////////////// +export interface ZodDefaultDef extends ZodTypeDef { + innerType: T; + defaultValue: () => util.noUndefined; + typeName: ZodFirstPartyTypeKind.ZodDefault; +} + +export class ZodDefault extends ZodType< + util.noUndefined, + ZodDefaultDef, + T["_input"] | undefined +> { + _parse(input: ParseInput): ParseReturnType { + const { ctx } = this._processInputParams(input); + let data = ctx.data; + if (ctx.parsedType === ZodParsedType.undefined) { + data = this._def.defaultValue(); + } + return this._def.innerType._parse({ + data, + path: ctx.path, + parent: ctx, + }); + } + + removeDefault() { + return this._def.innerType; + } + + static create = ( + type: Inner, + params: RawCreateParams & { + default: Inner["_input"] | (() => util.noUndefined); + } + ): ZodDefault => { + return new ZodDefault({ + innerType: type, + typeName: ZodFirstPartyTypeKind.ZodDefault, + defaultValue: typeof params.default === "function" ? params.default : () => params.default as any, + ...processCreateParams(params), + }) as any; + }; +} + +////////////////////////////////////////// +////////////////////////////////////////// +////////// ////////// +////////// ZodCatch ////////// +////////// ////////// +////////////////////////////////////////// +////////////////////////////////////////// +export interface ZodCatchDef extends ZodTypeDef { + innerType: T; + catchValue: (ctx: { error: ZodError; input: unknown }) => T["_input"]; + typeName: ZodFirstPartyTypeKind.ZodCatch; +} + +export class ZodCatch extends ZodType< + T["_output"], + ZodCatchDef, + unknown // any input will pass validation // T["_input"] +> { + _parse(input: ParseInput): ParseReturnType { + const { ctx } = this._processInputParams(input); + + // newCtx is used to not collect issues from inner types in ctx + const newCtx: ParseContext = { + ...ctx, + common: { + ...ctx.common, + issues: [], + }, + }; + + const result = this._def.innerType._parse({ + data: newCtx.data, + path: newCtx.path, + parent: { + ...newCtx, + }, + }); + + if (isAsync(result)) { + return result.then((result) => { + return { + status: "valid", + value: + result.status === "valid" + ? result.value + : this._def.catchValue({ + get error() { + return new ZodError(newCtx.common.issues); + }, + input: newCtx.data, + }), + }; + }); + } else { + return { + status: "valid", + value: + result.status === "valid" + ? result.value + : this._def.catchValue({ + get error() { + return new ZodError(newCtx.common.issues); + }, + input: newCtx.data, + }), + }; + } + } + + removeCatch() { + return this._def.innerType; + } + + static create = ( + type: Inner, + params: RawCreateParams & { + catch: Inner["_output"] | (() => Inner["_output"]); + } + ): ZodCatch => { + return new ZodCatch({ + innerType: type, + typeName: ZodFirstPartyTypeKind.ZodCatch, + catchValue: typeof params.catch === "function" ? params.catch : () => params.catch, + ...processCreateParams(params), + }); + }; +} + +///////////////////////////////////////// +///////////////////////////////////////// +////////// ////////// +////////// ZodNaN ////////// +////////// ////////// +///////////////////////////////////////// +///////////////////////////////////////// + +export interface ZodNaNDef extends ZodTypeDef { + typeName: ZodFirstPartyTypeKind.ZodNaN; +} + +export class ZodNaN extends ZodType { + _parse(input: ParseInput): ParseReturnType { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.nan) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.nan, + received: ctx.parsedType, + }); + return INVALID; + } + + return { status: "valid", value: input.data }; + } + + static create = (params?: RawCreateParams): ZodNaN => { + return new ZodNaN({ + typeName: ZodFirstPartyTypeKind.ZodNaN, + ...processCreateParams(params), + }); + }; +} + +////////////////////////////////////////// +////////////////////////////////////////// +////////// ////////// +////////// ZodBranded ////////// +////////// ////////// +////////////////////////////////////////// +////////////////////////////////////////// + +export interface ZodBrandedDef extends ZodTypeDef { + type: T; + typeName: ZodFirstPartyTypeKind.ZodBranded; +} + +export const BRAND: unique symbol = Symbol("zod_brand"); +export type BRAND = { + [BRAND]: { [k in T]: true }; +}; + +export class ZodBranded extends ZodType< + T["_output"] & BRAND, + ZodBrandedDef, + T["_input"] +> { + _parse(input: ParseInput): ParseReturnType { + const { ctx } = this._processInputParams(input); + const data = ctx.data; + return this._def.type._parse({ + data, + path: ctx.path, + parent: ctx, + }); + } + + unwrap() { + return this._def.type; + } +} + +//////////////////////////////////////////// +//////////////////////////////////////////// +////////// ////////// +////////// ZodPipeline ////////// +////////// ////////// +//////////////////////////////////////////// +//////////////////////////////////////////// + +export interface ZodPipelineDef extends ZodTypeDef { + in: A; + out: B; + typeName: ZodFirstPartyTypeKind.ZodPipeline; +} + +export class ZodPipeline extends ZodType< + B["_output"], + ZodPipelineDef, + A["_input"] +> { + _parse(input: ParseInput): ParseReturnType { + const { status, ctx } = this._processInputParams(input); + if (ctx.common.async) { + const handleAsync = async () => { + const inResult = await this._def.in._parseAsync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }); + if (inResult.status === "aborted") return INVALID; + if (inResult.status === "dirty") { + status.dirty(); + return DIRTY(inResult.value); + } else { + return this._def.out._parseAsync({ + data: inResult.value, + path: ctx.path, + parent: ctx, + }); + } + }; + return handleAsync(); + } else { + const inResult = this._def.in._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }); + if (inResult.status === "aborted") return INVALID; + if (inResult.status === "dirty") { + status.dirty(); + return { + status: "dirty", + value: inResult.value, + }; + } else { + return this._def.out._parseSync({ + data: inResult.value, + path: ctx.path, + parent: ctx, + }); + } + } + } + + static create( + a: ASchema, + b: BSchema + ): ZodPipeline { + return new ZodPipeline({ + in: a, + out: b, + typeName: ZodFirstPartyTypeKind.ZodPipeline, + }); + } +} + +/////////////////////////////////////////// +/////////////////////////////////////////// +////////// ////////// +////////// ZodReadonly ////////// +////////// ////////// +/////////////////////////////////////////// +/////////////////////////////////////////// +type BuiltIn = + | (((...args: any[]) => any) | (new (...args: any[]) => any)) + | { readonly [Symbol.toStringTag]: string } + | Date + | Error + | Generator + | Promise + | RegExp; + +type MakeReadonly = T extends Map + ? ReadonlyMap + : T extends Set + ? ReadonlySet + : T extends [infer Head, ...infer Tail] + ? readonly [Head, ...Tail] + : T extends Array + ? ReadonlyArray + : T extends BuiltIn + ? T + : Readonly; + +export interface ZodReadonlyDef extends ZodTypeDef { + innerType: T; + typeName: ZodFirstPartyTypeKind.ZodReadonly; +} + +export class ZodReadonly extends ZodType< + MakeReadonly, + ZodReadonlyDef, + MakeReadonly +> { + _parse(input: ParseInput): ParseReturnType { + const result = this._def.innerType._parse(input); + const freeze = (data: ParseReturnType) => { + if (isValid(data)) { + data.value = Object.freeze(data.value); + } + return data; + }; + return isAsync(result) ? result.then((data) => freeze(data)) : freeze(result); + } + + static create = (type: Inner, params?: RawCreateParams): ZodReadonly => { + return new ZodReadonly({ + innerType: type, + typeName: ZodFirstPartyTypeKind.ZodReadonly, + ...processCreateParams(params), + }) as any; + }; + + unwrap() { + return this._def.innerType; + } +} + +//////////////////////////////////////// +//////////////////////////////////////// +////////// ////////// +////////// z.custom ////////// +////////// ////////// +//////////////////////////////////////// +//////////////////////////////////////// +function cleanParams(params: unknown, data: unknown) { + const p = typeof params === "function" ? params(data) : typeof params === "string" ? { message: params } : params; + + const p2 = typeof p === "string" ? { message: p } : p; + return p2; +} +type CustomParams = CustomErrorParams & { fatal?: boolean }; +export function custom( + check?: (data: any) => any, + _params: string | CustomParams | ((input: any) => CustomParams) = {}, + /** + * @deprecated + * + * Pass `fatal` into the params object instead: + * + * ```ts + * z.string().custom((val) => val.length > 5, { fatal: false }) + * ``` + * + */ + fatal?: boolean +): ZodType { + if (check) + return ZodAny.create().superRefine((data, ctx) => { + const r = check(data); + if (r instanceof Promise) { + return r.then((r) => { + if (!r) { + const params = cleanParams(_params, data); + const _fatal = params.fatal ?? fatal ?? true; + ctx.addIssue({ code: "custom", ...params, fatal: _fatal }); + } + }); + } + if (!r) { + const params = cleanParams(_params, data); + const _fatal = params.fatal ?? fatal ?? true; + ctx.addIssue({ code: "custom", ...params, fatal: _fatal }); + } + return; + }); + return ZodAny.create(); +} + +export { ZodType as Schema, ZodType as ZodSchema }; + +export const late = { + object: ZodObject.lazycreate, +}; + +export enum ZodFirstPartyTypeKind { + ZodString = "ZodString", + ZodNumber = "ZodNumber", + ZodNaN = "ZodNaN", + ZodBigInt = "ZodBigInt", + ZodBoolean = "ZodBoolean", + ZodDate = "ZodDate", + ZodSymbol = "ZodSymbol", + ZodUndefined = "ZodUndefined", + ZodNull = "ZodNull", + ZodAny = "ZodAny", + ZodUnknown = "ZodUnknown", + ZodNever = "ZodNever", + ZodVoid = "ZodVoid", + ZodArray = "ZodArray", + ZodObject = "ZodObject", + ZodUnion = "ZodUnion", + ZodDiscriminatedUnion = "ZodDiscriminatedUnion", + ZodIntersection = "ZodIntersection", + ZodTuple = "ZodTuple", + ZodRecord = "ZodRecord", + ZodMap = "ZodMap", + ZodSet = "ZodSet", + ZodFunction = "ZodFunction", + ZodLazy = "ZodLazy", + ZodLiteral = "ZodLiteral", + ZodEnum = "ZodEnum", + ZodEffects = "ZodEffects", + ZodNativeEnum = "ZodNativeEnum", + ZodOptional = "ZodOptional", + ZodNullable = "ZodNullable", + ZodDefault = "ZodDefault", + ZodCatch = "ZodCatch", + ZodPromise = "ZodPromise", + ZodBranded = "ZodBranded", + ZodPipeline = "ZodPipeline", + ZodReadonly = "ZodReadonly", +} +export type ZodFirstPartySchemaTypes = + | ZodString + | ZodNumber + | ZodNaN + | ZodBigInt + | ZodBoolean + | ZodDate + | ZodUndefined + | ZodNull + | ZodAny + | ZodUnknown + | ZodNever + | ZodVoid + | ZodArray + | ZodObject + | ZodUnion + | ZodDiscriminatedUnion + | ZodIntersection + | ZodTuple + | ZodRecord + | ZodMap + | ZodSet + | ZodFunction + | ZodLazy + | ZodLiteral + | ZodEnum + | ZodEffects + | ZodNativeEnum + | ZodOptional + | ZodNullable + | ZodDefault + | ZodCatch + | ZodPromise + | ZodBranded + | ZodPipeline + | ZodReadonly + | ZodSymbol; + +// requires TS 4.4+ +abstract class Class { + constructor(..._: any[]) {} +} +const instanceOfType = ( + // const instanceOfType = any>( + cls: T, + params: CustomParams = { + message: `Input not instance of ${cls.name}`, + } +) => custom>((data) => data instanceof cls, params); + +const stringType = ZodString.create; +const numberType = ZodNumber.create; +const nanType = ZodNaN.create; +const bigIntType = ZodBigInt.create; +const booleanType = ZodBoolean.create; +const dateType = ZodDate.create; +const symbolType = ZodSymbol.create; +const undefinedType = ZodUndefined.create; +const nullType = ZodNull.create; +const anyType = ZodAny.create; +const unknownType = ZodUnknown.create; +const neverType = ZodNever.create; +const voidType = ZodVoid.create; +const arrayType = ZodArray.create; +const objectType = ZodObject.create; +const strictObjectType = ZodObject.strictCreate; +const unionType = ZodUnion.create; +const discriminatedUnionType = ZodDiscriminatedUnion.create; +const intersectionType = ZodIntersection.create; +const tupleType = ZodTuple.create; +const recordType = ZodRecord.create; +const mapType = ZodMap.create; +const setType = ZodSet.create; +const functionType = ZodFunction.create; +const lazyType = ZodLazy.create; +const literalType = ZodLiteral.create; +const enumType = ZodEnum.create; +const nativeEnumType = ZodNativeEnum.create; +const promiseType = ZodPromise.create; +const effectsType = ZodEffects.create; +const optionalType = ZodOptional.create; +const nullableType = ZodNullable.create; +const preprocessType = ZodEffects.createWithPreprocess; +const pipelineType = ZodPipeline.create; +const ostring = () => stringType().optional(); +const onumber = () => numberType().optional(); +const oboolean = () => booleanType().optional(); + +export const coerce = { + string: ((arg) => ZodString.create({ ...arg, coerce: true })) as (typeof ZodString)["create"], + number: ((arg) => ZodNumber.create({ ...arg, coerce: true })) as (typeof ZodNumber)["create"], + boolean: ((arg) => + ZodBoolean.create({ + ...arg, + coerce: true, + })) as (typeof ZodBoolean)["create"], + bigint: ((arg) => ZodBigInt.create({ ...arg, coerce: true })) as (typeof ZodBigInt)["create"], + date: ((arg) => ZodDate.create({ ...arg, coerce: true })) as (typeof ZodDate)["create"], +}; + +export { + anyType as any, + arrayType as array, + bigIntType as bigint, + booleanType as boolean, + dateType as date, + discriminatedUnionType as discriminatedUnion, + effectsType as effect, + enumType as enum, + functionType as function, + instanceOfType as instanceof, + intersectionType as intersection, + lazyType as lazy, + literalType as literal, + mapType as map, + nanType as nan, + nativeEnumType as nativeEnum, + neverType as never, + nullType as null, + nullableType as nullable, + numberType as number, + objectType as object, + oboolean, + onumber, + optionalType as optional, + ostring, + pipelineType as pipeline, + preprocessType as preprocess, + promiseType as promise, + recordType as record, + setType as set, + strictObjectType as strictObject, + stringType as string, + symbolType as symbol, + effectsType as transformer, + tupleType as tuple, + undefinedType as undefined, + unionType as union, + unknownType as unknown, + voidType as void, +}; + +export const NEVER = INVALID as never; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4-mini/index.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4-mini/index.ts new file mode 100644 index 0000000..bb95da0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4-mini/index.ts @@ -0,0 +1,3 @@ +import * as z from "../v4/mini/external.js"; +export * from "../v4/mini/external.js"; +export { z }; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/checks.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/checks.ts new file mode 100644 index 0000000..cd78c0e --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/checks.ts @@ -0,0 +1,32 @@ +export { + _lt as lt, + _lte as lte, + _gt as gt, + _gte as gte, + _positive as positive, + _negative as negative, + _nonpositive as nonpositive, + _nonnegative as nonnegative, + _multipleOf as multipleOf, + _maxSize as maxSize, + _minSize as minSize, + _size as size, + _maxLength as maxLength, + _minLength as minLength, + _length as length, + _regex as regex, + _lowercase as lowercase, + _uppercase as uppercase, + _includes as includes, + _startsWith as startsWith, + _endsWith as endsWith, + _property as property, + _mime as mime, + _overwrite as overwrite, + _normalize as normalize, + _trim as trim, + _toLowerCase as toLowerCase, + _toUpperCase as toUpperCase, + _slugify as slugify, + type $RefinementCtx as RefinementCtx, +} from "../core/index.js"; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/coerce.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/coerce.ts new file mode 100644 index 0000000..cc400e0 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/coerce.ts @@ -0,0 +1,27 @@ +import * as core from "../core/index.js"; +import * as schemas from "./schemas.js"; + +export interface ZodCoercedString extends schemas._ZodString> {} +export function string(params?: string | core.$ZodStringParams): ZodCoercedString { + return core._coercedString(schemas.ZodString, params) as any; +} + +export interface ZodCoercedNumber extends schemas._ZodNumber> {} +export function number(params?: string | core.$ZodNumberParams): ZodCoercedNumber { + return core._coercedNumber(schemas.ZodNumber, params) as ZodCoercedNumber; +} + +export interface ZodCoercedBoolean extends schemas._ZodBoolean> {} +export function boolean(params?: string | core.$ZodBooleanParams): ZodCoercedBoolean { + return core._coercedBoolean(schemas.ZodBoolean, params) as ZodCoercedBoolean; +} + +export interface ZodCoercedBigInt extends schemas._ZodBigInt> {} +export function bigint(params?: string | core.$ZodBigIntParams): ZodCoercedBigInt { + return core._coercedBigint(schemas.ZodBigInt, params) as ZodCoercedBigInt; +} + +export interface ZodCoercedDate extends schemas._ZodDate> {} +export function date(params?: string | core.$ZodDateParams): ZodCoercedDate { + return core._coercedDate(schemas.ZodDate, params) as ZodCoercedDate; +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/compat.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/compat.ts new file mode 100644 index 0000000..86a5813 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/compat.ts @@ -0,0 +1,70 @@ +// Zod 3 compat layer + +import * as core from "../core/index.js"; +import type { ZodType } from "./schemas.js"; + +export type { + /** @deprecated Use `z.output` instead. */ + output as TypeOf, + /** @deprecated Use `z.output` instead. */ + output as Infer, + /** @deprecated Use `z.core.$$ZodFirstPartyTypes` instead */ + $ZodTypes as ZodFirstPartySchemaTypes, +} from "../core/index.js"; + +/** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */ +export const ZodIssueCode = { + invalid_type: "invalid_type", + too_big: "too_big", + too_small: "too_small", + invalid_format: "invalid_format", + not_multiple_of: "not_multiple_of", + unrecognized_keys: "unrecognized_keys", + invalid_union: "invalid_union", + invalid_key: "invalid_key", + invalid_element: "invalid_element", + invalid_value: "invalid_value", + custom: "custom", +} as const; + +/** @deprecated Use `z.$ZodFlattenedError` */ +export type inferFlattenedErrors = core.$ZodFlattenedError, U>; + +/** @deprecated Use `z.$ZodFormattedError` */ +export type inferFormattedError, U = string> = core.$ZodFormattedError< + core.output, + U +>; + +/** Use `z.$brand` instead */ +export type BRAND = { + [core.$brand]: { [k in T]: true }; +}; +export { $brand, config } from "../core/index.js"; + +/** @deprecated Use `z.config(params)` instead. */ +export function setErrorMap(map: core.$ZodErrorMap): void { + core.config({ + customError: map, + }); +} + +/** @deprecated Use `z.config()` instead. */ +export function getErrorMap(): core.$ZodErrorMap | undefined { + return core.config().customError; +} + +export type { + /** @deprecated Use z.ZodType (without generics) instead. */ + ZodType as ZodTypeAny, + /** @deprecated Use `z.ZodType` */ + ZodType as ZodSchema, + /** @deprecated Use `z.ZodType` */ + ZodType as Schema, +}; + +/** Included for Zod 3 compatibility */ +export type ZodRawShape = core.$ZodShape; + +/** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */ +export enum ZodFirstPartyTypeKind {} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/errors.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/errors.ts new file mode 100644 index 0000000..e4eb99d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/errors.ts @@ -0,0 +1,82 @@ +import * as core from "../core/index.js"; +import { $ZodError } from "../core/index.js"; +import * as util from "../core/util.js"; + +/** @deprecated Use `z.core.$ZodIssue` from `@zod/core` instead, especially if you are building a library on top of Zod. */ +export type ZodIssue = core.$ZodIssue; + +/** An Error-like class used to store Zod validation issues. */ +export interface ZodError extends $ZodError { + /** @deprecated Use the `z.treeifyError(err)` function instead. */ + format(): core.$ZodFormattedError; + format(mapper: (issue: core.$ZodIssue) => U): core.$ZodFormattedError; + /** @deprecated Use the `z.treeifyError(err)` function instead. */ + flatten(): core.$ZodFlattenedError; + flatten(mapper: (issue: core.$ZodIssue) => U): core.$ZodFlattenedError; + /** @deprecated Push directly to `.issues` instead. */ + addIssue(issue: core.$ZodIssue): void; + /** @deprecated Push directly to `.issues` instead. */ + addIssues(issues: core.$ZodIssue[]): void; + + /** @deprecated Check `err.issues.length === 0` instead. */ + isEmpty: boolean; +} + +const initializer = (inst: ZodError, issues: core.$ZodIssue[]) => { + $ZodError.init(inst, issues); + inst.name = "ZodError"; + Object.defineProperties(inst, { + format: { + value: (mapper: any) => core.formatError(inst, mapper), + // enumerable: false, + }, + flatten: { + value: (mapper: any) => core.flattenError(inst, mapper), + // enumerable: false, + }, + addIssue: { + value: (issue: any) => { + inst.issues.push(issue); + inst.message = JSON.stringify(inst.issues, util.jsonStringifyReplacer, 2); + }, + // enumerable: false, + }, + addIssues: { + value: (issues: any) => { + inst.issues.push(...issues); + inst.message = JSON.stringify(inst.issues, util.jsonStringifyReplacer, 2); + }, + // enumerable: false, + }, + isEmpty: { + get() { + return inst.issues.length === 0; + }, + // enumerable: false, + }, + }); + // Object.defineProperty(inst, "isEmpty", { + // get() { + // return inst.issues.length === 0; + // }, + // }); +}; +export const ZodError: core.$constructor = /*@__PURE__*/ core.$constructor("ZodError", initializer); +export const ZodRealError: core.$constructor = /*@__PURE__*/ core.$constructor("ZodError", initializer, { + Parent: Error, +}); + +export type { + /** @deprecated Use `z.core.$ZodFlattenedError` instead. */ + $ZodFlattenedError as ZodFlattenedError, + /** @deprecated Use `z.core.$ZodFormattedError` instead. */ + $ZodFormattedError as ZodFormattedError, + /** @deprecated Use `z.core.$ZodErrorMap` instead. */ + $ZodErrorMap as ZodErrorMap, +} from "../core/index.js"; + +/** @deprecated Use `z.core.$ZodRawIssue` instead. */ +export type IssueData = core.$ZodRawIssue; + +// /** @deprecated Use `z.core.$ZodErrorMapCtx` instead. */ +// export type ErrorMapCtx = core.$ZodErrorMapCtx; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/external.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/external.ts new file mode 100644 index 0000000..56cabdc --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/external.ts @@ -0,0 +1,52 @@ +export * as core from "../core/index.js"; +export * from "./schemas.js"; +export * from "./checks.js"; +export * from "./errors.js"; +export * from "./parse.js"; +export * from "./compat.js"; + +// zod-specified +import { config } from "../core/index.js"; +import en from "../locales/en.js"; +config(en()); + +export type { infer, output, input } from "../core/index.js"; +export type { JSONType } from "../core/util.js"; +export { + globalRegistry, + type GlobalMeta, + registry, + config, + $output, + $input, + $brand, + clone, + regexes, + treeifyError, + prettifyError, + formatError, + flattenError, + TimePrecision, + util, + NEVER, +} from "../core/index.js"; +export { toJSONSchema } from "../core/json-schema-processors.js"; +export { fromJSONSchema } from "./from-json-schema.js"; + +export * as locales from "../locales/index.js"; + +// iso +// must be exported from top-level +// https://github.com/colinhacks/zod/issues/4491 +export { ZodISODateTime, ZodISODate, ZodISOTime, ZodISODuration } from "./iso.js"; +export * as iso from "./iso.js"; + +// coerce +export type { + ZodCoercedString, + ZodCoercedNumber, + ZodCoercedBigInt, + ZodCoercedBoolean, + ZodCoercedDate, +} from "./coerce.js"; +export * as coerce from "./coerce.js"; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/from-json-schema.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/from-json-schema.ts new file mode 100644 index 0000000..7934f33 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/from-json-schema.ts @@ -0,0 +1,659 @@ +import type * as JSONSchema from "../core/json-schema.js"; +import { type $ZodRegistry, globalRegistry } from "../core/registries.js"; +import * as _checks from "./checks.js"; +import * as _iso from "./iso.js"; +import * as _schemas from "./schemas.js"; +import type { ZodNumber, ZodString, ZodType } from "./schemas.js"; + +// Local z object to avoid circular dependency with ../index.js +const z = { + ..._schemas, + ..._checks, + iso: _iso, +}; + +type JSONSchemaVersion = "draft-2020-12" | "draft-7" | "draft-4" | "openapi-3.0"; + +interface FromJSONSchemaParams { + defaultTarget?: JSONSchemaVersion; + registry?: $ZodRegistry; +} + +interface ConversionContext { + version: JSONSchemaVersion; + defs: Record; + refs: Map; + processing: Set; + rootSchema: JSONSchema.JSONSchema; + registry: $ZodRegistry; +} + +// Keys that are recognized and handled by the conversion logic +const RECOGNIZED_KEYS = /*@__PURE__*/ new Set([ + // Schema identification + "$schema", + "$ref", + "$defs", + "definitions", + // Core schema keywords + "$id", + "id", + "$comment", + "$anchor", + "$vocabulary", + "$dynamicRef", + "$dynamicAnchor", + // Type + "type", + "enum", + "const", + // Composition + "anyOf", + "oneOf", + "allOf", + "not", + // Object + "properties", + "required", + "additionalProperties", + "patternProperties", + "propertyNames", + "minProperties", + "maxProperties", + // Array + "items", + "prefixItems", + "additionalItems", + "minItems", + "maxItems", + "uniqueItems", + "contains", + "minContains", + "maxContains", + // String + "minLength", + "maxLength", + "pattern", + "format", + // Number + "minimum", + "maximum", + "exclusiveMinimum", + "exclusiveMaximum", + "multipleOf", + // Already handled metadata + "description", + "default", + // Content + "contentEncoding", + "contentMediaType", + "contentSchema", + // Unsupported (error-throwing) + "unevaluatedItems", + "unevaluatedProperties", + "if", + "then", + "else", + "dependentSchemas", + "dependentRequired", + // OpenAPI + "nullable", + "readOnly", +]); + +function detectVersion(schema: JSONSchema.JSONSchema, defaultTarget?: JSONSchemaVersion): JSONSchemaVersion { + const $schema = schema.$schema; + + if ($schema === "https://json-schema.org/draft/2020-12/schema") { + return "draft-2020-12"; + } + if ($schema === "http://json-schema.org/draft-07/schema#") { + return "draft-7"; + } + if ($schema === "http://json-schema.org/draft-04/schema#") { + return "draft-4"; + } + + // Use defaultTarget if provided, otherwise default to draft-2020-12 + return defaultTarget ?? "draft-2020-12"; +} + +function resolveRef(ref: string, ctx: ConversionContext): JSONSchema.JSONSchema { + if (!ref.startsWith("#")) { + throw new Error("External $ref is not supported, only local refs (#/...) are allowed"); + } + + const path = ref.slice(1).split("/").filter(Boolean); + + // Handle root reference "#" + if (path.length === 0) { + return ctx.rootSchema; + } + + const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions"; + + if (path[0] === defsKey) { + const key = path[1]; + if (!key || !ctx.defs[key]) { + throw new Error(`Reference not found: ${ref}`); + } + return ctx.defs[key]!; + } + + throw new Error(`Reference not found: ${ref}`); +} + +function convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext): ZodType { + // Handle unsupported features + if (schema.not !== undefined) { + // Special case: { not: {} } represents never + if (typeof schema.not === "object" && Object.keys(schema.not).length === 0) { + return z.never(); + } + throw new Error("not is not supported in Zod (except { not: {} } for never)"); + } + if (schema.unevaluatedItems !== undefined) { + throw new Error("unevaluatedItems is not supported"); + } + if (schema.unevaluatedProperties !== undefined) { + throw new Error("unevaluatedProperties is not supported"); + } + if (schema.if !== undefined || schema.then !== undefined || schema.else !== undefined) { + throw new Error("Conditional schemas (if/then/else) are not supported"); + } + if (schema.dependentSchemas !== undefined || schema.dependentRequired !== undefined) { + throw new Error("dependentSchemas and dependentRequired are not supported"); + } + + // Handle $ref + if (schema.$ref) { + const refPath = schema.$ref; + if (ctx.refs.has(refPath)) { + return ctx.refs.get(refPath)!; + } + + if (ctx.processing.has(refPath)) { + // Circular reference - use lazy + return z.lazy(() => { + if (!ctx.refs.has(refPath)) { + throw new Error(`Circular reference not resolved: ${refPath}`); + } + return ctx.refs.get(refPath)!; + }); + } + + ctx.processing.add(refPath); + const resolved = resolveRef(refPath, ctx); + const zodSchema = convertSchema(resolved, ctx); + ctx.refs.set(refPath, zodSchema); + ctx.processing.delete(refPath); + return zodSchema; + } + + // Handle enum + if (schema.enum !== undefined) { + const enumValues = schema.enum; + + // Special case: OpenAPI 3.0 null representation { type: "string", nullable: true, enum: [null] } + if ( + ctx.version === "openapi-3.0" && + schema.nullable === true && + enumValues.length === 1 && + enumValues[0] === null + ) { + return z.null(); + } + + if (enumValues.length === 0) { + return z.never(); + } + if (enumValues.length === 1) { + return z.literal(enumValues[0]!); + } + // Check if all values are strings + if (enumValues.every((v) => typeof v === "string")) { + return z.enum(enumValues as [string, ...string[]]); + } + // Mixed types - use union of literals + const literalSchemas = enumValues.map((v) => z.literal(v)); + if (literalSchemas.length < 2) { + return literalSchemas[0]!; + } + return z.union([literalSchemas[0]!, literalSchemas[1]!, ...literalSchemas.slice(2)] as [ + ZodType, + ZodType, + ...ZodType[], + ]); + } + + // Handle const + if (schema.const !== undefined) { + return z.literal(schema.const); + } + + // Handle type + const type = schema.type; + + if (Array.isArray(type)) { + // Expand type array into anyOf union + const typeSchemas = type.map((t) => { + const typeSchema: JSONSchema.JSONSchema = { ...schema, type: t }; + return convertBaseSchema(typeSchema, ctx); + }); + if (typeSchemas.length === 0) { + return z.never(); + } + if (typeSchemas.length === 1) { + return typeSchemas[0]!; + } + return z.union(typeSchemas as [ZodType, ZodType, ...ZodType[]]); + } + + if (!type) { + // No type specified - empty schema (any) + return z.any(); + } + + let zodSchema: ZodType; + + switch (type) { + case "string": { + let stringSchema: ZodString = z.string(); + + // Apply format using .check() with Zod format functions + if (schema.format) { + const format = schema.format; + // Map common formats to Zod check functions + if (format === "email") { + stringSchema = stringSchema.check(z.email()); + } else if (format === "uri" || format === "uri-reference") { + stringSchema = stringSchema.check(z.url()); + } else if (format === "uuid" || format === "guid") { + stringSchema = stringSchema.check(z.uuid()); + } else if (format === "date-time") { + stringSchema = stringSchema.check(z.iso.datetime()); + } else if (format === "date") { + stringSchema = stringSchema.check(z.iso.date()); + } else if (format === "time") { + stringSchema = stringSchema.check(z.iso.time()); + } else if (format === "duration") { + stringSchema = stringSchema.check(z.iso.duration()); + } else if (format === "ipv4") { + stringSchema = stringSchema.check(z.ipv4()); + } else if (format === "ipv6") { + stringSchema = stringSchema.check(z.ipv6()); + } else if (format === "mac") { + stringSchema = stringSchema.check(z.mac()); + } else if (format === "cidr") { + stringSchema = stringSchema.check(z.cidrv4()); + } else if (format === "cidr-v6") { + stringSchema = stringSchema.check(z.cidrv6()); + } else if (format === "base64") { + stringSchema = stringSchema.check(z.base64()); + } else if (format === "base64url") { + stringSchema = stringSchema.check(z.base64url()); + } else if (format === "e164") { + stringSchema = stringSchema.check(z.e164()); + } else if (format === "jwt") { + stringSchema = stringSchema.check(z.jwt()); + } else if (format === "emoji") { + stringSchema = stringSchema.check(z.emoji()); + } else if (format === "nanoid") { + stringSchema = stringSchema.check(z.nanoid()); + } else if (format === "cuid") { + stringSchema = stringSchema.check(z.cuid()); + } else if (format === "cuid2") { + stringSchema = stringSchema.check(z.cuid2()); + } else if (format === "ulid") { + stringSchema = stringSchema.check(z.ulid()); + } else if (format === "xid") { + stringSchema = stringSchema.check(z.xid()); + } else if (format === "ksuid") { + stringSchema = stringSchema.check(z.ksuid()); + } + // Note: json-string format is not currently supported by Zod + // Custom formats are ignored - keep as plain string + } + + // Apply constraints + if (typeof schema.minLength === "number") { + stringSchema = stringSchema.min(schema.minLength); + } + if (typeof schema.maxLength === "number") { + stringSchema = stringSchema.max(schema.maxLength); + } + if (schema.pattern) { + // JSON Schema patterns are not implicitly anchored (match anywhere in string) + stringSchema = stringSchema.regex(new RegExp(schema.pattern)); + } + + zodSchema = stringSchema; + break; + } + + case "number": + case "integer": { + let numberSchema: ZodNumber = type === "integer" ? z.number().int() : z.number(); + + // Apply constraints + if (typeof schema.minimum === "number") { + numberSchema = numberSchema.min(schema.minimum); + } + if (typeof schema.maximum === "number") { + numberSchema = numberSchema.max(schema.maximum); + } + if (typeof schema.exclusiveMinimum === "number") { + numberSchema = numberSchema.gt(schema.exclusiveMinimum); + } else if (schema.exclusiveMinimum === true && typeof schema.minimum === "number") { + numberSchema = numberSchema.gt(schema.minimum); + } + if (typeof schema.exclusiveMaximum === "number") { + numberSchema = numberSchema.lt(schema.exclusiveMaximum); + } else if (schema.exclusiveMaximum === true && typeof schema.maximum === "number") { + numberSchema = numberSchema.lt(schema.maximum); + } + if (typeof schema.multipleOf === "number") { + numberSchema = numberSchema.multipleOf(schema.multipleOf); + } + + zodSchema = numberSchema; + break; + } + + case "boolean": { + zodSchema = z.boolean(); + break; + } + + case "null": { + zodSchema = z.null(); + break; + } + + case "object": { + const shape: Record = {}; + const properties = schema.properties || {}; + const requiredSet = new Set(schema.required || []); + + // Convert properties - mark optional ones + for (const [key, propSchema] of Object.entries(properties)) { + const propZodSchema = convertSchema(propSchema as JSONSchema.JSONSchema, ctx); + // If not in required array, make it optional + shape[key] = requiredSet.has(key) ? propZodSchema : propZodSchema.optional(); + } + + // Handle propertyNames + if (schema.propertyNames) { + const keySchema = convertSchema(schema.propertyNames, ctx) as ZodString; + const valueSchema = + schema.additionalProperties && typeof schema.additionalProperties === "object" + ? convertSchema(schema.additionalProperties as JSONSchema.JSONSchema, ctx) + : z.any(); + + // Case A: No properties (pure record) + if (Object.keys(shape).length === 0) { + zodSchema = z.record(keySchema, valueSchema); + break; + } + + // Case B: With properties (intersection of object and looseRecord) + const objectSchema = z.object(shape).passthrough(); + const recordSchema = z.looseRecord(keySchema, valueSchema); + zodSchema = z.intersection(objectSchema, recordSchema); + break; + } + + // Handle patternProperties + if (schema.patternProperties) { + // patternProperties: keys matching pattern must satisfy corresponding schema + // Use loose records so non-matching keys pass through + const patternProps = schema.patternProperties; + const patternKeys = Object.keys(patternProps); + const looseRecords: ZodType[] = []; + + for (const pattern of patternKeys) { + const patternValue = convertSchema(patternProps[pattern] as JSONSchema.JSONSchema, ctx); + const keySchema = z.string().regex(new RegExp(pattern)); + looseRecords.push(z.looseRecord(keySchema, patternValue)); + } + + // Build intersection: object schema + all pattern property records + const schemasToIntersect: ZodType[] = []; + if (Object.keys(shape).length > 0) { + // Use passthrough so patternProperties can validate additional keys + schemasToIntersect.push(z.object(shape).passthrough()); + } + schemasToIntersect.push(...looseRecords); + + if (schemasToIntersect.length === 0) { + zodSchema = z.object({}).passthrough(); + } else if (schemasToIntersect.length === 1) { + zodSchema = schemasToIntersect[0]!; + } else { + // Chain intersections: (A & B) & C & D ... + let result = z.intersection(schemasToIntersect[0]!, schemasToIntersect[1]!); + for (let i = 2; i < schemasToIntersect.length; i++) { + result = z.intersection(result, schemasToIntersect[i]!); + } + zodSchema = result; + } + break; + } + + // Handle additionalProperties + // In JSON Schema, additionalProperties defaults to true (allow any extra properties) + // In Zod, objects strip unknown keys by default, so we need to handle this explicitly + const objectSchema = z.object(shape); + if (schema.additionalProperties === false) { + // Strict mode - no extra properties allowed + zodSchema = objectSchema.strict(); + } else if (typeof schema.additionalProperties === "object") { + // Extra properties must match the specified schema + zodSchema = objectSchema.catchall(convertSchema(schema.additionalProperties as JSONSchema.JSONSchema, ctx)); + } else { + // additionalProperties is true or undefined - allow any extra properties (passthrough) + zodSchema = objectSchema.passthrough(); + } + break; + } + + case "array": { + // TODO: uniqueItems is not supported + // TODO: contains/minContains/maxContains are not supported + // Check if this is a tuple (prefixItems or items as array) + const prefixItems = schema.prefixItems; + const items = schema.items; + + if (prefixItems && Array.isArray(prefixItems)) { + // Tuple with prefixItems (draft-2020-12) + const tupleItems = prefixItems.map((item) => convertSchema(item as JSONSchema.JSONSchema, ctx)); + const rest = + items && typeof items === "object" && !Array.isArray(items) + ? convertSchema(items as JSONSchema.JSONSchema, ctx) + : undefined; + if (rest) { + zodSchema = z.tuple(tupleItems as [ZodType, ...ZodType[]]).rest(rest); + } else { + zodSchema = z.tuple(tupleItems as [ZodType, ...ZodType[]]); + } + // Apply minItems/maxItems constraints to tuples + if (typeof schema.minItems === "number") { + zodSchema = zodSchema.check(z.minLength(schema.minItems)); + } + if (typeof schema.maxItems === "number") { + zodSchema = zodSchema.check(z.maxLength(schema.maxItems)); + } + } else if (Array.isArray(items)) { + // Tuple with items array (draft-7) + const tupleItems = items.map((item) => convertSchema(item as JSONSchema.JSONSchema, ctx)); + const rest = + schema.additionalItems && typeof schema.additionalItems === "object" + ? convertSchema(schema.additionalItems as JSONSchema.JSONSchema, ctx) + : undefined; // additionalItems: false means no rest, handled by default tuple behavior + if (rest) { + zodSchema = z.tuple(tupleItems as [ZodType, ...ZodType[]]).rest(rest); + } else { + zodSchema = z.tuple(tupleItems as [ZodType, ...ZodType[]]); + } + // Apply minItems/maxItems constraints to tuples + if (typeof schema.minItems === "number") { + zodSchema = zodSchema.check(z.minLength(schema.minItems)); + } + if (typeof schema.maxItems === "number") { + zodSchema = zodSchema.check(z.maxLength(schema.maxItems)); + } + } else if (items !== undefined) { + // Regular array + const element = convertSchema(items as JSONSchema.JSONSchema, ctx); + let arraySchema = z.array(element); + + // Apply constraints + if (typeof schema.minItems === "number") { + arraySchema = arraySchema.min(schema.minItems); + } + if (typeof schema.maxItems === "number") { + arraySchema = arraySchema.max(schema.maxItems); + } + + zodSchema = arraySchema; + } else { + // No items specified - array of any + zodSchema = z.array(z.any()); + } + break; + } + + default: + throw new Error(`Unsupported type: ${type}`); + } + + return zodSchema; +} + +function convertSchema(schema: JSONSchema.JSONSchema | boolean, ctx: ConversionContext): ZodType { + if (typeof schema === "boolean") { + return schema ? z.any() : z.never(); + } + + // Convert base schema first (ignoring composition keywords) + let baseSchema = convertBaseSchema(schema, ctx); + const hasExplicitType = schema.type || schema.enum !== undefined || schema.const !== undefined; + + // Process composition keywords LAST (they can appear together) + // Handle anyOf - wrap base schema with union + if (schema.anyOf && Array.isArray(schema.anyOf)) { + const options = schema.anyOf.map((s) => convertSchema(s, ctx)); + const anyOfUnion = z.union(options as [ZodType, ZodType, ...ZodType[]]); + baseSchema = hasExplicitType ? z.intersection(baseSchema, anyOfUnion) : anyOfUnion; + } + + // Handle oneOf - exclusive union (exactly one must match) + if (schema.oneOf && Array.isArray(schema.oneOf)) { + const options = schema.oneOf.map((s) => convertSchema(s, ctx)); + const oneOfUnion = z.xor(options as [ZodType, ZodType, ...ZodType[]]); + baseSchema = hasExplicitType ? z.intersection(baseSchema, oneOfUnion) : oneOfUnion; + } + + // Handle allOf - wrap base schema with intersection + if (schema.allOf && Array.isArray(schema.allOf)) { + if (schema.allOf.length === 0) { + baseSchema = hasExplicitType ? baseSchema : z.any(); + } else { + let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0]!, ctx); + const startIdx = hasExplicitType ? 0 : 1; + for (let i = startIdx; i < schema.allOf.length; i++) { + result = z.intersection(result, convertSchema(schema.allOf[i]!, ctx)); + } + baseSchema = result; + } + } + + // Handle nullable (OpenAPI 3.0) + if (schema.nullable === true && ctx.version === "openapi-3.0") { + baseSchema = z.nullable(baseSchema); + } + + // Handle readOnly + if (schema.readOnly === true) { + baseSchema = z.readonly(baseSchema); + } + + // Apply `default` so it wraps the fully-composed schema. This ensures + // `parse(undefined) -> default` works regardless of which branch of + // `convertBaseSchema` produced the inner schema (enum/const/not/typed/etc.). + if (schema.default !== undefined) { + baseSchema = baseSchema.default(schema.default); + } + + // Collect non-description annotation metadata into the user-supplied + // registry. Description is handled separately below via `.describe()` to + // preserve the contract that `schema.description` reads from globalRegistry. + const extraMeta: Record = {}; + + const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"]; + for (const key of coreMetadataKeys) { + if (key in schema) { + extraMeta[key] = schema[key]; + } + } + + const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"]; + for (const key of contentMetadataKeys) { + if (key in schema) { + extraMeta[key] = schema[key]; + } + } + + for (const key of Object.keys(schema)) { + if (!RECOGNIZED_KEYS.has(key)) { + extraMeta[key] = schema[key]; + } + } + + if (Object.keys(extraMeta).length > 0) { + ctx.registry.add(baseSchema, extraMeta); + } + + // Apply description last. `.describe()` clones the schema and sets + // `_zod.parent` on the clone, so registry lookups on the returned reference + // still resolve `extraMeta` via parent inheritance. + if (schema.description) { + baseSchema = baseSchema.describe(schema.description); + } + + return baseSchema; +} + +/** + * Converts a JSON Schema to a Zod schema. This function should be considered semi-experimental. It's behavior is liable to change. */ +export function fromJSONSchema(schema: JSONSchema.JSONSchema | boolean, params?: FromJSONSchemaParams): ZodType { + // Handle boolean schemas + if (typeof schema === "boolean") { + return schema ? z.any() : z.never(); + } + + // Normalize input via a JSON round-trip. This guarantees the converter + // walks a plain, finite, JSON-valid object graph: cyclic inputs fail here, + // getter/Proxy-based properties are materialized into static values, and + // class instances collapse to plain objects. + let normalized: JSONSchema.JSONSchema; + try { + normalized = JSON.parse(JSON.stringify(schema)); + } catch { + throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas"); + } + + const version = detectVersion(normalized, params?.defaultTarget); + const defs = (normalized.$defs || normalized.definitions || {}) as Record; + + const ctx: ConversionContext = { + version, + defs, + refs: new Map(), + processing: new Set(), + rootSchema: normalized, + registry: params?.registry ?? globalRegistry, + }; + + return convertSchema(normalized, ctx); +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/index.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/index.ts new file mode 100644 index 0000000..f0f7547 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/index.ts @@ -0,0 +1,5 @@ +import * as z from "./external.js"; + +export { z }; +export * from "./external.js"; +export default z; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/iso.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/iso.ts new file mode 100644 index 0000000..b08696d --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/iso.ts @@ -0,0 +1,90 @@ +import * as core from "../core/index.js"; +import * as schemas from "./schemas.js"; + +////////////////////////////////////////////// +////////////////////////////////////////////// +////////// ////////// +////////// ZodISODateTime ////////// +////////// ////////// +////////////////////////////////////////////// +////////////////////////////////////////////// + +export interface ZodISODateTime extends schemas.ZodStringFormat { + _zod: core.$ZodISODateTimeInternals; +} +export const ZodISODateTime: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodISODateTime", + (inst, def) => { + core.$ZodISODateTime.init(inst, def); + schemas.ZodStringFormat.init(inst, def); + } +); + +export function datetime(params?: string | core.$ZodISODateTimeParams): ZodISODateTime { + return core._isoDateTime(ZodISODateTime, params); +} + +////////////////////////////////////////// +////////////////////////////////////////// +////////// ////////// +////////// ZodISODate ////////// +////////// ////////// +////////////////////////////////////////// +////////////////////////////////////////// + +export interface ZodISODate extends schemas.ZodStringFormat { + _zod: core.$ZodISODateInternals; +} +export const ZodISODate: core.$constructor = /*@__PURE__*/ core.$constructor("ZodISODate", (inst, def) => { + core.$ZodISODate.init(inst, def); + schemas.ZodStringFormat.init(inst, def); +}); + +export function date(params?: string | core.$ZodISODateParams): ZodISODate { + return core._isoDate(ZodISODate, params); +} + +// ZodISOTime + +////////////////////////////////////////// +////////////////////////////////////////// +////////// ////////// +////////// ZodISOTime ////////// +////////// ////////// +////////////////////////////////////////// +////////////////////////////////////////// + +export interface ZodISOTime extends schemas.ZodStringFormat { + _zod: core.$ZodISOTimeInternals; +} +export const ZodISOTime: core.$constructor = /*@__PURE__*/ core.$constructor("ZodISOTime", (inst, def) => { + core.$ZodISOTime.init(inst, def); + schemas.ZodStringFormat.init(inst, def); +}); + +export function time(params?: string | core.$ZodISOTimeParams): ZodISOTime { + return core._isoTime(ZodISOTime, params); +} + +////////////////////////////////////////////// +////////////////////////////////////////////// +////////// ////////// +////////// ZodISODuration ////////// +////////// ////////// +////////////////////////////////////////////// +////////////////////////////////////////////// + +export interface ZodISODuration extends schemas.ZodStringFormat { + _zod: core.$ZodISODurationInternals; +} +export const ZodISODuration: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodISODuration", + (inst, def) => { + core.$ZodISODuration.init(inst, def); + schemas.ZodStringFormat.init(inst, def); + } +); + +export function duration(params?: string | core.$ZodISODurationParams): ZodISODuration { + return core._isoDuration(ZodISODuration, params); +} diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/parse.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/parse.ts new file mode 100644 index 0000000..7df7b29 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/parse.ts @@ -0,0 +1,82 @@ +import * as core from "../core/index.js"; +import { type ZodError, ZodRealError } from "./errors.js"; + +export type ZodSafeParseResult = ZodSafeParseSuccess | ZodSafeParseError; +export type ZodSafeParseSuccess = { success: true; data: T; error?: never }; +export type ZodSafeParseError = { success: false; data?: never; error: ZodError }; + +export const parse: ( + schema: T, + value: unknown, + _ctx?: core.ParseContext, + _params?: { callee?: core.util.AnyFunc; Err?: core.$ZodErrorClass } +) => core.output = /* @__PURE__ */ core._parse(ZodRealError); + +export const parseAsync: ( + schema: T, + value: unknown, + _ctx?: core.ParseContext, + _params?: { callee?: core.util.AnyFunc; Err?: core.$ZodErrorClass } +) => Promise> = /* @__PURE__ */ core._parseAsync(ZodRealError); + +export const safeParse: ( + schema: T, + value: unknown, + _ctx?: core.ParseContext + // _params?: { callee?: core.util.AnyFunc; Err?: core.$ZodErrorClass } +) => ZodSafeParseResult> = /* @__PURE__ */ core._safeParse(ZodRealError) as any; + +export const safeParseAsync: ( + schema: T, + value: unknown, + _ctx?: core.ParseContext +) => Promise>> = /* @__PURE__ */ core._safeParseAsync(ZodRealError) as any; + +// Codec functions +export const encode: ( + schema: T, + value: core.output, + _ctx?: core.ParseContext +) => core.input = /* @__PURE__ */ core._encode(ZodRealError); + +export const decode: ( + schema: T, + value: core.input, + _ctx?: core.ParseContext +) => core.output = /* @__PURE__ */ core._decode(ZodRealError); + +export const encodeAsync: ( + schema: T, + value: core.output, + _ctx?: core.ParseContext +) => Promise> = /* @__PURE__ */ core._encodeAsync(ZodRealError); + +export const decodeAsync: ( + schema: T, + value: core.input, + _ctx?: core.ParseContext +) => Promise> = /* @__PURE__ */ core._decodeAsync(ZodRealError); + +export const safeEncode: ( + schema: T, + value: core.output, + _ctx?: core.ParseContext +) => ZodSafeParseResult> = /* @__PURE__ */ core._safeEncode(ZodRealError) as any; + +export const safeDecode: ( + schema: T, + value: core.input, + _ctx?: core.ParseContext +) => ZodSafeParseResult> = /* @__PURE__ */ core._safeDecode(ZodRealError) as any; + +export const safeEncodeAsync: ( + schema: T, + value: core.output, + _ctx?: core.ParseContext +) => Promise>> = /* @__PURE__ */ core._safeEncodeAsync(ZodRealError) as any; + +export const safeDecodeAsync: ( + schema: T, + value: core.input, + _ctx?: core.ParseContext +) => Promise>> = /* @__PURE__ */ core._safeDecodeAsync(ZodRealError) as any; diff --git a/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/schemas.ts b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/schemas.ts new file mode 100644 index 0000000..e46abf5 --- /dev/null +++ b/dsh-local-403-fix/node_modules/.pnpm/zod@4.4.3/node_modules/zod/src/v4/classic/schemas.ts @@ -0,0 +1,2672 @@ +import * as core from "../core/index.js"; +import { util } from "../core/index.js"; +import * as processors from "../core/json-schema-processors.js"; +import type { StandardSchemaWithJSONProps } from "../core/standard-schema.js"; +import { createStandardJSONSchemaMethod, createToJSONSchemaMethod } from "../core/to-json-schema.js"; + +import * as checks from "./checks.js"; +import * as iso from "./iso.js"; +import * as parse from "./parse.js"; + +// Lazy-bind builder methods. +// +// Builder methods (`.optional`, `.array`, `.refine`, ...) live as +// non-enumerable getters on each concrete schema constructor's +// prototype. On first access from an instance the getter allocates +// `fn.bind(this)` and caches it as an own property on that instance, +// so detached usage (`const m = schema.optional; m()`) still works +// and the per-instance allocation only happens for methods actually +// touched. +// +// One install per (prototype, group), memoized by `_installedGroups`. +const _installedGroups = /* @__PURE__ */ new WeakMap>(); + +/** + * Methods of `T` reshaped so each body has `this: T` and matches the + * declared (args, return) of the corresponding interface method. Allows + * us to type-check inline method-shorthand bodies against the + * `ZodType` / `_ZodString` / etc. interface declarations. + */ +type _LazyMethodsOf = Partial<{ + [K in keyof T]: T[K] extends (...args: infer A) => infer R ? (this: T, ...args: A) => R : never; +}>; + +function _installLazyMethods(inst: T, group: string, methods: _LazyMethodsOf): void { + const proto = Object.getPrototypeOf(inst); + let installed = _installedGroups.get(proto); + if (!installed) { + installed = new Set(); + _installedGroups.set(proto, installed); + } + if (installed.has(group)) return; + installed.add(group); + for (const key in methods) { + const fn = methods[key]!; + Object.defineProperty(proto, key, { + configurable: true, + enumerable: false, + get(this: any) { + const bound = fn.bind(this); + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: bound, + }); + return bound; + }, + set(this: any, v: unknown) { + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: v, + }); + }, + }); + } +} + +/////////////////////////////////////////// +/////////////////////////////////////////// +//////////// //////////// +//////////// ZodType //////////// +//////////// //////////// +/////////////////////////////////////////// +/////////////////////////////////////////// + +export type ZodStandardSchemaWithJSON = StandardSchemaWithJSONProps, core.output>; +export interface ZodType< + out Output = unknown, + out Input = unknown, + out Internals extends core.$ZodTypeInternals = core.$ZodTypeInternals, +> extends core.$ZodType { + def: Internals["def"]; + type: Internals["def"]["type"]; + + /** @deprecated Use `.def` instead. */ + _def: Internals["def"]; + /** @deprecated Use `z.output` instead. */ + _output: Internals["output"]; + /** @deprecated Use `z.input` instead. */ + _input: Internals["input"]; + + "~standard": ZodStandardSchemaWithJSON; + /** Converts this schema to a JSON Schema representation. */ + toJSONSchema(params?: core.ToJSONSchemaParams): core.ZodStandardJSONSchemaPayload; + + // base methods + check(...checks: (core.CheckFn> | core.$ZodCheck>)[]): this; + with(...checks: (core.CheckFn> | core.$ZodCheck>)[]): this; + clone(def?: Internals["def"], params?: { parent: boolean }): this; + register( + registry: R, + ...meta: this extends R["_schema"] + ? undefined extends R["_meta"] + ? [core.$replace?] + : [core.$replace] + : ["Incompatible schema"] + ): this; + + brand( + value?: T + ): PropertyKey extends T ? this : core.$ZodBranded; + + // parsing + parse(data: unknown, params?: core.ParseContext): core.output; + safeParse(data: unknown, params?: core.ParseContext): parse.ZodSafeParseResult>; + parseAsync(data: unknown, params?: core.ParseContext): Promise>; + safeParseAsync( + data: unknown, + params?: core.ParseContext + ): Promise>>; + spa: ( + data: unknown, + params?: core.ParseContext + ) => Promise>>; + + // encoding/decoding + encode(data: core.output, params?: core.ParseContext): core.input; + decode(data: core.input, params?: core.ParseContext): core.output; + encodeAsync(data: core.output, params?: core.ParseContext): Promise>; + decodeAsync(data: core.input, params?: core.ParseContext): Promise>; + safeEncode( + data: core.output, + params?: core.ParseContext + ): parse.ZodSafeParseResult>; + safeDecode( + data: core.input, + params?: core.ParseContext + ): parse.ZodSafeParseResult>; + safeEncodeAsync( + data: core.output, + params?: core.ParseContext + ): Promise>>; + safeDecodeAsync( + data: core.input, + params?: core.ParseContext + ): Promise>>; + + // refinements + refine) => unknown | Promise>( + check: Ch, + params?: string | core.$ZodCustomParams + ): Ch extends (arg: any) => arg is infer R ? this & ZodType> : this; + superRefine( + refinement: (arg: core.output, ctx: core.$RefinementCtx>) => void | Promise, + params?: core.$ZodSuperRefineParams + ): this; + overwrite(fn: (x: core.output) => core.output): this; + + // wrappers + optional(): ZodOptional; + exactOptional(): ZodExactOptional; + nonoptional(params?: string | core.$ZodNonOptionalParams): ZodNonOptional; + nullable(): ZodNullable; + nullish(): ZodOptional>; + default(def: util.NoUndefined>): ZodDefault; + default(def: () => util.NoUndefined>): ZodDefault; + prefault(def: () => core.input): ZodPrefault; + prefault(def: core.input): ZodPrefault; + array(): ZodArray; + or(option: T): ZodUnion<[this, T]>; + and(incoming: T): ZodIntersection; + transform( + transform: (arg: core.output, ctx: core.$RefinementCtx>) => NewOut | Promise + ): ZodPipe, core.output>>; + catch(def: core.output): ZodCatch; + catch(def: (ctx: core.$ZodCatchCtx) => core.output): ZodCatch; + pipe>>( + target: T | core.$ZodType> + ): ZodPipe; + readonly(): ZodReadonly; + + /** Returns a new instance that has been registered in `z.globalRegistry` with the specified description */ + describe(description: string): this; + description?: string; + /** Returns the metadata associated with this instance in `z.globalRegistry` */ + meta(): core.$replace | undefined; + /** Returns a new instance that has been registered in `z.globalRegistry` with the specified metadata */ + meta(data: core.$replace): this; + + // helpers + /** @deprecated Try safe-parsing `undefined` (this is what `isOptional` does internally): + * + * ```ts + * const schema = z.string().optional(); + * const isOptional = schema.safeParse(undefined).success; // true + * ``` + */ + isOptional(): boolean; + /** + * @deprecated Try safe-parsing `null` (this is what `isNullable` does internally): + * + * ```ts + * const schema = z.string().nullable(); + * const isNullable = schema.safeParse(null).success; // true + * ``` + */ + isNullable(): boolean; + apply(fn: (schema: this) => T): T; +} + +export interface _ZodType + extends ZodType {} + +export const ZodType: core.$constructor = /*@__PURE__*/ core.$constructor("ZodType", (inst, def) => { + core.$ZodType.init(inst, def); + Object.assign(inst["~standard"], { + jsonSchema: { + input: createStandardJSONSchemaMethod(inst, "input"), + output: createStandardJSONSchemaMethod(inst, "output"), + }, + }); + inst.toJSONSchema = createToJSONSchemaMethod(inst, {}); + + inst.def = def; + inst.type = def.type; + Object.defineProperty(inst, "_def", { value: def }); + + // Parse-family is intentionally kept as per-instance closures: these are + // the hot path AND the most-detached methods (`arr.map(schema.parse)`, + // `const { parse } = schema`, etc.). Eager closures here mean callers pay + // ~12 closure allocations per schema but get monomorphic call sites and + // detached usage that "just works". + inst.parse = (data, params) => parse.parse(inst, data, params, { callee: inst.parse }); + inst.safeParse = (data, params) => parse.safeParse(inst, data, params); + inst.parseAsync = async (data, params) => parse.parseAsync(inst, data, params, { callee: inst.parseAsync }); + inst.safeParseAsync = async (data, params) => parse.safeParseAsync(inst, data, params); + inst.spa = inst.safeParseAsync; + inst.encode = (data, params) => parse.encode(inst, data, params); + inst.decode = (data, params) => parse.decode(inst, data, params); + inst.encodeAsync = async (data, params) => parse.encodeAsync(inst, data, params); + inst.decodeAsync = async (data, params) => parse.decodeAsync(inst, data, params); + inst.safeEncode = (data, params) => parse.safeEncode(inst, data, params); + inst.safeDecode = (data, params) => parse.safeDecode(inst, data, params); + inst.safeEncodeAsync = async (data, params) => parse.safeEncodeAsync(inst, data, params); + inst.safeDecodeAsync = async (data, params) => parse.safeDecodeAsync(inst, data, params); + + // All builder methods are placed on the internal prototype as lazy-bind + // getters. On first access per-instance, a bound thunk is allocated and + // cached as an own property; subsequent accesses skip the getter. This + // means: no per-instance allocation for unused methods, full + // detachability preserved (`const m = schema.optional; m()` works), and + // shared underlying function references across all instances. + _installLazyMethods(inst, "ZodType", { + check(...chks) { + const def = this.def; + return this.clone( + util.mergeDefs(def, { + checks: [ + ...(def.checks ?? []), + ...chks.map((ch) => + typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch + ), + ], + }), + { parent: true } + ); + }, + with(...chks) { + return this.check(...chks); + }, + clone(def, params) { + return core.clone(this, def, params); + }, + brand() { + return this; + }, + register(reg, meta) { + reg.add(this, meta); + return this; + }, + refine(check, params) { + return this.check(refine(check, params)); + }, + superRefine(refinement, params) { + return this.check(superRefine(refinement, params)); + }, + overwrite(fn) { + return this.check(checks.overwrite(fn)); + }, + optional() { + return optional(this); + }, + exactOptional() { + return exactOptional(this); + }, + nullable() { + return nullable(this); + }, + nullish() { + return optional(nullable(this)); + }, + nonoptional(params) { + return nonoptional(this, params); + }, + array() { + return array(this); + }, + or(arg) { + return union([this, arg]); + }, + and(arg) { + return intersection(this, arg); + }, + transform(tx) { + return pipe(this, transform(tx)); + }, + default(d) { + return _default(this, d); + }, + prefault(d) { + return prefault(this, d); + }, + catch(params) { + return _catch(this, params); + }, + pipe(target) { + return pipe(this, target); + }, + readonly() { + return readonly(this); + }, + describe(description) { + const cl = this.clone(); + core.globalRegistry.add(cl, { description }); + return cl; + }, + meta(...args: any[]): any { + // overloaded: meta() returns the registered metadata, meta(data) + // returns a clone with `data` registered. The mapped type picks + // up the second overload, so we accept variadic any-args and + // return `any` to satisfy both at runtime. + if (args.length === 0) return core.globalRegistry.get(this); + const cl = this.clone(); + core.globalRegistry.add(cl, args[0]); + return cl; + }, + isOptional() { + return this.safeParse(undefined).success; + }, + isNullable() { + return this.safeParse(null).success; + }, + apply(fn) { + return fn(this); + }, + }); + Object.defineProperty(inst, "description", { + get() { + return core.globalRegistry.get(inst)?.description; + }, + configurable: true, + }); + return inst; +}); + +// ZodString +export interface _ZodString = core.$ZodStringInternals> + extends _ZodType { + format: string | null; + minLength: number | null; + maxLength: number | null; + + // miscellaneous checks + regex(regex: RegExp, params?: string | core.$ZodCheckRegexParams): this; + includes(value: string, params?: string | core.$ZodCheckIncludesParams): this; + startsWith(value: string, params?: string | core.$ZodCheckStartsWithParams): this; + endsWith(value: string, params?: string | core.$ZodCheckEndsWithParams): this; + min(minLength: number, params?: string | core.$ZodCheckMinLengthParams): this; + max(maxLength: number, params?: string | core.$ZodCheckMaxLengthParams): this; + length(len: number, params?: string | core.$ZodCheckLengthEqualsParams): this; + nonempty(params?: string | core.$ZodCheckMinLengthParams): this; + lowercase(params?: string | core.$ZodCheckLowerCaseParams): this; + uppercase(params?: string | core.$ZodCheckUpperCaseParams): this; + + // transforms + trim(): this; + normalize(form?: "NFC" | "NFD" | "NFKC" | "NFKD" | (string & {})): this; + toLowerCase(): this; + toUpperCase(): this; + slugify(): this; +} + +/** @internal */ +export const _ZodString: core.$constructor<_ZodString> = /*@__PURE__*/ core.$constructor("_ZodString", (inst, def) => { + core.$ZodString.init(inst, def); + ZodType.init(inst, def); + + inst._zod.processJSONSchema = (ctx, json, params) => processors.stringProcessor(inst, ctx, json, params); + + const bag = inst._zod.bag; + inst.format = bag.format ?? null; + inst.minLength = bag.minimum ?? null; + inst.maxLength = bag.maximum ?? null; + + _installLazyMethods(inst, "_ZodString", { + regex(...args) { + return this.check((checks.regex as any)(...args)); + }, + includes(...args) { + return this.check((checks.includes as any)(...args)); + }, + startsWith(...args) { + return this.check((checks.startsWith as any)(...args)); + }, + endsWith(...args) { + return this.check((checks.endsWith as any)(...args)); + }, + min(...args) { + return this.check((checks.minLength as any)(...args)); + }, + max(...args) { + return this.check((checks.maxLength as any)(...args)); + }, + length(...args) { + return this.check((checks.length as any)(...args)); + }, + nonempty(...args) { + return this.check((checks.minLength as any)(1, ...args)); + }, + lowercase(params) { + return this.check(checks.lowercase(params)); + }, + uppercase(params) { + return this.check(checks.uppercase(params)); + }, + trim() { + return this.check(checks.trim()); + }, + normalize(...args) { + return this.check(checks.normalize(...args)); + }, + toLowerCase() { + return this.check(checks.toLowerCase()); + }, + toUpperCase() { + return this.check(checks.toUpperCase()); + }, + slugify() { + return this.check(checks.slugify()); + }, + }); +}); + +export interface ZodString extends _ZodString> { + // string format checks + + /** @deprecated Use `z.email()` instead. */ + email(params?: string | core.$ZodCheckEmailParams): this; + /** @deprecated Use `z.url()` instead. */ + url(params?: string | core.$ZodCheckURLParams): this; + /** @deprecated Use `z.jwt()` instead. */ + jwt(params?: string | core.$ZodCheckJWTParams): this; + /** @deprecated Use `z.emoji()` instead. */ + emoji(params?: string | core.$ZodCheckEmojiParams): this; + /** @deprecated Use `z.guid()` instead. */ + guid(params?: string | core.$ZodCheckGUIDParams): this; + /** @deprecated Use `z.uuid()` instead. */ + uuid(params?: string | core.$ZodCheckUUIDParams): this; + /** @deprecated Use `z.uuid()` instead. */ + uuidv4(params?: string | core.$ZodCheckUUIDParams): this; + /** @deprecated Use `z.uuid()` instead. */ + uuidv6(params?: string | core.$ZodCheckUUIDParams): this; + /** @deprecated Use `z.uuid()` instead. */ + uuidv7(params?: string | core.$ZodCheckUUIDParams): this; + /** @deprecated Use `z.nanoid()` instead. */ + nanoid(params?: string | core.$ZodCheckNanoIDParams): this; + /** @deprecated Use `z.guid()` instead. */ + guid(params?: string | core.$ZodCheckGUIDParams): this; + /** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use `z.cuid2()` instead. + * See https://github.com/paralleldrive/cuid. + */ + cuid(params?: string | core.$ZodCheckCUIDParams): this; + /** @deprecated Use `z.cuid2()` instead. */ + cuid2(params?: string | core.$ZodCheckCUID2Params): this; + /** @deprecated Use `z.ulid()` instead. */ + ulid(params?: string | core.$ZodCheckULIDParams): this; + /** @deprecated Use `z.base64()` instead. */ + base64(params?: string | core.$ZodCheckBase64Params): this; + /** @deprecated Use `z.base64url()` instead. */ + base64url(params?: string | core.$ZodCheckBase64URLParams): this; + // /** @deprecated Use `z.jsonString()` instead. */ + // jsonString(params?: string | core.$ZodCheckJSONStringParams): this; + /** @deprecated Use `z.xid()` instead. */ + xid(params?: string | core.$ZodCheckXIDParams): this; + /** @deprecated Use `z.ksuid()` instead. */ + ksuid(params?: string | core.$ZodCheckKSUIDParams): this; + // /** @deprecated Use `z.ipv4()` or `z.ipv6()` instead. */ + // ip(params?: string | (core.$ZodCheckIPv4Params & { version?: "v4" | "v6" })): ZodUnion<[this, this]>; + /** @deprecated Use `z.ipv4()` instead. */ + ipv4(params?: string | core.$ZodCheckIPv4Params): this; + /** @deprecated Use `z.ipv6()` instead. */ + ipv6(params?: string | core.$ZodCheckIPv6Params): this; + /** @deprecated Use `z.cidrv4()` instead. */ + cidrv4(params?: string | core.$ZodCheckCIDRv4Params): this; + /** @deprecated Use `z.cidrv6()` instead. */ + cidrv6(params?: string | core.$ZodCheckCIDRv6Params): this; + /** @deprecated Use `z.e164()` instead. */ + e164(params?: string | core.$ZodCheckE164Params): this; + + // ISO 8601 checks + /** @deprecated Use `z.iso.datetime()` instead. */ + datetime(params?: string | core.$ZodCheckISODateTimeParams): this; + /** @deprecated Use `z.iso.date()` instead. */ + date(params?: string | core.$ZodCheckISODateParams): this; + /** @deprecated Use `z.iso.time()` instead. */ + time( + params?: + | string + // | { + // message?: string | undefined; + // precision?: number | null; + // } + | core.$ZodCheckISOTimeParams + ): this; + /** @deprecated Use `z.iso.duration()` instead. */ + duration(params?: string | core.$ZodCheckISODurationParams): this; +} + +export const ZodString: core.$constructor = /*@__PURE__*/ core.$constructor("ZodString", (inst, def) => { + core.$ZodString.init(inst, def); + _ZodString.init(inst, def); + + inst.email = (params) => inst.check(core._email(ZodEmail, params)); + inst.url = (params) => inst.check(core._url(ZodURL, params)); + inst.jwt = (params) => inst.check(core._jwt(ZodJWT, params)); + inst.emoji = (params) => inst.check(core._emoji(ZodEmoji, params)); + inst.guid = (params) => inst.check(core._guid(ZodGUID, params)); + inst.uuid = (params) => inst.check(core._uuid(ZodUUID, params)); + inst.uuidv4 = (params) => inst.check(core._uuidv4(ZodUUID, params)); + inst.uuidv6 = (params) => inst.check(core._uuidv6(ZodUUID, params)); + inst.uuidv7 = (params) => inst.check(core._uuidv7(ZodUUID, params)); + inst.nanoid = (params) => inst.check(core._nanoid(ZodNanoID, params)); + inst.guid = (params) => inst.check(core._guid(ZodGUID, params)); + inst.cuid = (params) => inst.check(core._cuid(ZodCUID, params)); + inst.cuid2 = (params) => inst.check(core._cuid2(ZodCUID2, params)); + inst.ulid = (params) => inst.check(core._ulid(ZodULID, params)); + inst.base64 = (params) => inst.check(core._base64(ZodBase64, params)); + inst.base64url = (params) => inst.check(core._base64url(ZodBase64URL, params)); + inst.xid = (params) => inst.check(core._xid(ZodXID, params)); + inst.ksuid = (params) => inst.check(core._ksuid(ZodKSUID, params)); + inst.ipv4 = (params) => inst.check(core._ipv4(ZodIPv4, params)); + inst.ipv6 = (params) => inst.check(core._ipv6(ZodIPv6, params)); + inst.cidrv4 = (params) => inst.check(core._cidrv4(ZodCIDRv4, params)); + inst.cidrv6 = (params) => inst.check(core._cidrv6(ZodCIDRv6, params)); + inst.e164 = (params) => inst.check(core._e164(ZodE164, params)); + + // iso + inst.datetime = (params) => inst.check(iso.datetime(params as any)); + inst.date = (params) => inst.check(iso.date(params as any)); + inst.time = (params) => inst.check(iso.time(params as any)); + inst.duration = (params) => inst.check(iso.duration(params as any)); +}); + +export function string(params?: string | core.$ZodStringParams): ZodString; +export function string(params?: string | core.$ZodStringParams): core.$ZodType; +export function string(params?: string | core.$ZodStringParams): ZodString { + return core._string(ZodString, params); +} + +// ZodStringFormat +export interface ZodStringFormat + extends _ZodString> {} +export const ZodStringFormat: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodStringFormat", + (inst, def) => { + core.$ZodStringFormat.init(inst, def); + _ZodString.init(inst, def); + } +); + +// ZodEmail +export interface ZodEmail extends ZodStringFormat<"email"> { + _zod: core.$ZodEmailInternals; +} +export const ZodEmail: core.$constructor = /*@__PURE__*/ core.$constructor("ZodEmail", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodEmail.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function email(params?: string | core.$ZodEmailParams): ZodEmail { + return core._email(ZodEmail, params); +} + +// ZodGUID +export interface ZodGUID extends ZodStringFormat<"guid"> { + _zod: core.$ZodGUIDInternals; +} +export const ZodGUID: core.$constructor = /*@__PURE__*/ core.$constructor("ZodGUID", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodGUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function guid(params?: string | core.$ZodGUIDParams): ZodGUID { + return core._guid(ZodGUID, params); +} + +// ZodUUID +export interface ZodUUID extends ZodStringFormat<"uuid"> { + _zod: core.$ZodUUIDInternals; +} +export const ZodUUID: core.$constructor = /*@__PURE__*/ core.$constructor("ZodUUID", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodUUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function uuid(params?: string | core.$ZodUUIDParams): ZodUUID { + return core._uuid(ZodUUID, params); +} + +export function uuidv4(params?: string | core.$ZodUUIDv4Params): ZodUUID { + return core._uuidv4(ZodUUID, params); +} + +// ZodUUIDv6 + +export function uuidv6(params?: string | core.$ZodUUIDv6Params): ZodUUID { + return core._uuidv6(ZodUUID, params); +} + +// ZodUUIDv7 + +export function uuidv7(params?: string | core.$ZodUUIDv7Params): ZodUUID { + return core._uuidv7(ZodUUID, params); +} + +// ZodURL +export interface ZodURL extends ZodStringFormat<"url"> { + _zod: core.$ZodURLInternals; +} +export const ZodURL: core.$constructor = /*@__PURE__*/ core.$constructor("ZodURL", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodURL.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function url(params?: string | core.$ZodURLParams): ZodURL { + return core._url(ZodURL, params); +} + +export function httpUrl(params?: string | Omit): ZodURL { + return core._url(ZodURL, { + protocol: core.regexes.httpProtocol, + hostname: core.regexes.domain, + ...util.normalizeParams(params), + }); +} + +// ZodEmoji +export interface ZodEmoji extends ZodStringFormat<"emoji"> { + _zod: core.$ZodEmojiInternals; +} +export const ZodEmoji: core.$constructor = /*@__PURE__*/ core.$constructor("ZodEmoji", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodEmoji.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function emoji(params?: string | core.$ZodEmojiParams): ZodEmoji { + return core._emoji(ZodEmoji, params); +} + +// ZodNanoID +export interface ZodNanoID extends ZodStringFormat<"nanoid"> { + _zod: core.$ZodNanoIDInternals; +} +export const ZodNanoID: core.$constructor = /*@__PURE__*/ core.$constructor("ZodNanoID", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodNanoID.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function nanoid(params?: string | core.$ZodNanoIDParams): ZodNanoID { + return core._nanoid(ZodNanoID, params); +} + +// ZodCUID +/** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link ZodCUID2} instead. + * See https://github.com/paralleldrive/cuid. + */ +export interface ZodCUID extends ZodStringFormat<"cuid"> { + _zod: core.$ZodCUIDInternals; +} +/** + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link ZodCUID2} instead. + * See https://github.com/paralleldrive/cuid. + */ +export const ZodCUID: core.$constructor = /*@__PURE__*/ core.$constructor("ZodCUID", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodCUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +/** + * Validates a CUID v1 string. + * + * @deprecated CUID v1 is deprecated by its authors due to information leakage + * (timestamps embedded in the id). Use {@link cuid2 | `z.cuid2()`} instead. + * See https://github.com/paralleldrive/cuid. + */ +export function cuid(params?: string | core.$ZodCUIDParams): ZodCUID { + return core._cuid(ZodCUID, params); +} + +// ZodCUID2 +export interface ZodCUID2 extends ZodStringFormat<"cuid2"> { + _zod: core.$ZodCUID2Internals; +} +export const ZodCUID2: core.$constructor = /*@__PURE__*/ core.$constructor("ZodCUID2", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodCUID2.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function cuid2(params?: string | core.$ZodCUID2Params): ZodCUID2 { + return core._cuid2(ZodCUID2, params); +} + +// ZodULID +export interface ZodULID extends ZodStringFormat<"ulid"> { + _zod: core.$ZodULIDInternals; +} +export const ZodULID: core.$constructor = /*@__PURE__*/ core.$constructor("ZodULID", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodULID.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function ulid(params?: string | core.$ZodULIDParams): ZodULID { + return core._ulid(ZodULID, params); +} + +// ZodXID +export interface ZodXID extends ZodStringFormat<"xid"> { + _zod: core.$ZodXIDInternals; +} +export const ZodXID: core.$constructor = /*@__PURE__*/ core.$constructor("ZodXID", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodXID.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function xid(params?: string | core.$ZodXIDParams): ZodXID { + return core._xid(ZodXID, params); +} + +// ZodKSUID +export interface ZodKSUID extends ZodStringFormat<"ksuid"> { + _zod: core.$ZodKSUIDInternals; +} +export const ZodKSUID: core.$constructor = /*@__PURE__*/ core.$constructor("ZodKSUID", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodKSUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function ksuid(params?: string | core.$ZodKSUIDParams): ZodKSUID { + return core._ksuid(ZodKSUID, params); +} + +// ZodIP +// export interface ZodIP extends ZodStringFormat<"ip"> { +// _zod: core.$ZodIPInternals; +// } +// export const ZodIP: core.$constructor = /*@__PURE__*/ core.$constructor("ZodIP", (inst, def) => { +// // ZodStringFormat.init(inst, def); +// core.$ZodIP.init(inst, def); +// ZodStringFormat.init(inst, def); +// }); + +// export function ip(params?: string | core.$ZodIPParams): ZodIP { +// return core._ip(ZodIP, params); +// } + +// ZodIPv4 +export interface ZodIPv4 extends ZodStringFormat<"ipv4"> { + _zod: core.$ZodIPv4Internals; +} +export const ZodIPv4: core.$constructor = /*@__PURE__*/ core.$constructor("ZodIPv4", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodIPv4.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function ipv4(params?: string | core.$ZodIPv4Params): ZodIPv4 { + return core._ipv4(ZodIPv4, params); +} + +// ZodMAC +export interface ZodMAC extends ZodStringFormat<"mac"> { + _zod: core.$ZodMACInternals; +} +export const ZodMAC: core.$constructor = /*@__PURE__*/ core.$constructor("ZodMAC", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodMAC.init(inst, def); + ZodStringFormat.init(inst, def); +}); +export function mac(params?: string | core.$ZodMACParams): ZodMAC { + return core._mac(ZodMAC, params); +} + +// ZodIPv6 +export interface ZodIPv6 extends ZodStringFormat<"ipv6"> { + _zod: core.$ZodIPv6Internals; +} +export const ZodIPv6: core.$constructor = /*@__PURE__*/ core.$constructor("ZodIPv6", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodIPv6.init(inst, def); + ZodStringFormat.init(inst, def); +}); +export function ipv6(params?: string | core.$ZodIPv6Params): ZodIPv6 { + return core._ipv6(ZodIPv6, params); +} + +// ZodCIDRv4 +export interface ZodCIDRv4 extends ZodStringFormat<"cidrv4"> { + _zod: core.$ZodCIDRv4Internals; +} +export const ZodCIDRv4: core.$constructor = /*@__PURE__*/ core.$constructor("ZodCIDRv4", (inst, def) => { + core.$ZodCIDRv4.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function cidrv4(params?: string | core.$ZodCIDRv4Params): ZodCIDRv4 { + return core._cidrv4(ZodCIDRv4, params); +} + +// ZodCIDRv6 +export interface ZodCIDRv6 extends ZodStringFormat<"cidrv6"> { + _zod: core.$ZodCIDRv6Internals; +} +export const ZodCIDRv6: core.$constructor = /*@__PURE__*/ core.$constructor("ZodCIDRv6", (inst, def) => { + core.$ZodCIDRv6.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function cidrv6(params?: string | core.$ZodCIDRv6Params): ZodCIDRv6 { + return core._cidrv6(ZodCIDRv6, params); +} + +// ZodBase64 +export interface ZodBase64 extends ZodStringFormat<"base64"> { + _zod: core.$ZodBase64Internals; +} +export const ZodBase64: core.$constructor = /*@__PURE__*/ core.$constructor("ZodBase64", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodBase64.init(inst, def); + ZodStringFormat.init(inst, def); +}); +export function base64(params?: string | core.$ZodBase64Params): ZodBase64 { + return core._base64(ZodBase64, params); +} + +// ZodBase64URL +export interface ZodBase64URL extends ZodStringFormat<"base64url"> { + _zod: core.$ZodBase64URLInternals; +} +export const ZodBase64URL: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodBase64URL", + (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodBase64URL.init(inst, def); + ZodStringFormat.init(inst, def); + } +); +export function base64url(params?: string | core.$ZodBase64URLParams): ZodBase64URL { + return core._base64url(ZodBase64URL, params); +} + +// ZodE164 +export interface ZodE164 extends ZodStringFormat<"e164"> { + _zod: core.$ZodE164Internals; +} +export const ZodE164: core.$constructor = /*@__PURE__*/ core.$constructor("ZodE164", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodE164.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function e164(params?: string | core.$ZodE164Params): ZodE164 { + return core._e164(ZodE164, params); +} + +// ZodJWT +export interface ZodJWT extends ZodStringFormat<"jwt"> { + _zod: core.$ZodJWTInternals; +} +export const ZodJWT: core.$constructor = /*@__PURE__*/ core.$constructor("ZodJWT", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodJWT.init(inst, def); + ZodStringFormat.init(inst, def); +}); + +export function jwt(params?: string | core.$ZodJWTParams): ZodJWT { + return core._jwt(ZodJWT, params); +} + +// ZodCustomStringFormat +export interface ZodCustomStringFormat + extends ZodStringFormat, + core.$ZodCustomStringFormat { + _zod: core.$ZodCustomStringFormatInternals; + "~standard": ZodStandardSchemaWithJSON; +} +export const ZodCustomStringFormat: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodCustomStringFormat", + (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodCustomStringFormat.init(inst, def); + ZodStringFormat.init(inst, def); + } +); +export function stringFormat( + format: Format, + fnOrRegex: ((arg: string) => util.MaybeAsync) | RegExp, + _params: string | core.$ZodStringFormatParams = {} +): ZodCustomStringFormat { + return core._stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params) as any; +} + +export function hostname(_params?: string | core.$ZodStringFormatParams): ZodCustomStringFormat<"hostname"> { + return core._stringFormat(ZodCustomStringFormat, "hostname", core.regexes.hostname, _params) as any; +} + +export function hex(_params?: string | core.$ZodStringFormatParams): ZodCustomStringFormat<"hex"> { + return core._stringFormat(ZodCustomStringFormat, "hex", core.regexes.hex, _params) as any; +} + +export function hash( + alg: Alg, + params?: { + enc?: Enc; + } & core.$ZodStringFormatParams +): ZodCustomStringFormat<`${Alg}_${Enc}`> { + const enc = params?.enc ?? "hex"; + const format = `${alg}_${enc}` as const; + const regex = core.regexes[format as keyof typeof core.regexes] as RegExp; + if (!regex) throw new Error(`Unrecognized hash format: ${format}`); + return core._stringFormat(ZodCustomStringFormat, format, regex, params) as any; +} + +// ZodNumber +export interface _ZodNumber + extends _ZodType { + gt(value: number, params?: string | core.$ZodCheckGreaterThanParams): this; + /** Identical to .min() */ + gte(value: number, params?: string | core.$ZodCheckGreaterThanParams): this; + min(value: number, params?: string | core.$ZodCheckGreaterThanParams): this; + lt(value: number, params?: string | core.$ZodCheckLessThanParams): this; + /** Identical to .max() */ + lte(value: number, params?: string | core.$ZodCheckLessThanParams): this; + max(value: number, params?: string | core.$ZodCheckLessThanParams): this; + /** Consider `z.int()` instead. This API is considered *legacy*; it will never be removed but a better alternative exists. */ + int(params?: string | core.$ZodCheckNumberFormatParams): this; + /** @deprecated This is now identical to `.int()`. Only numbers in the safe integer range are accepted. */ + safe(params?: string | core.$ZodCheckNumberFormatParams): this; + positive(params?: string | core.$ZodCheckGreaterThanParams): this; + nonnegative(params?: string | core.$ZodCheckGreaterThanParams): this; + negative(params?: string | core.$ZodCheckLessThanParams): this; + nonpositive(params?: string | core.$ZodCheckLessThanParams): this; + multipleOf(value: number, params?: string | core.$ZodCheckMultipleOfParams): this; + /** @deprecated Use `.multipleOf()` instead. */ + step(value: number, params?: string | core.$ZodCheckMultipleOfParams): this; + + /** @deprecated In v4 and later, z.number() does not allow infinite values by default. This is a no-op. */ + finite(params?: unknown): this; + + minValue: number | null; + maxValue: number | null; + /** @deprecated Check the `format` property instead. */ + isInt: boolean; + /** @deprecated Number schemas no longer accept infinite values, so this always returns `true`. */ + isFinite: boolean; + format: string | null; +} + +export interface ZodNumber extends _ZodNumber> {} + +export const ZodNumber: core.$constructor = /*@__PURE__*/ core.$constructor("ZodNumber", (inst, def) => { + core.$ZodNumber.init(inst, def); + + ZodType.init(inst, def); + + inst._zod.processJSONSchema = (ctx, json, params) => processors.numberProcessor(inst, ctx, json, params); + + _installLazyMethods(inst, "ZodNumber", { + gt(value, params) { + return this.check(checks.gt(value, params)); + }, + gte(value, params) { + return this.check(checks.gte(value, params)); + }, + min(value, params) { + return this.check(checks.gte(value, params)); + }, + lt(value, params) { + return this.check(checks.lt(value, params)); + }, + lte(value, params) { + return this.check(checks.lte(value, params)); + }, + max(value, params) { + return this.check(checks.lte(value, params)); + }, + int(params) { + return this.check(int(params)); + }, + safe(params) { + return this.check(int(params)); + }, + positive(params) { + return this.check(checks.gt(0, params)); + }, + nonnegative(params) { + return this.check(checks.gte(0, params)); + }, + negative(params) { + return this.check(checks.lt(0, params)); + }, + nonpositive(params) { + return this.check(checks.lte(0, params)); + }, + multipleOf(value, params) { + return this.check(checks.multipleOf(value, params)); + }, + step(value, params) { + return this.check(checks.multipleOf(value, params)); + }, + finite() { + return this; + }, + }); + + const bag = inst._zod.bag; + inst.minValue = + Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null; + inst.maxValue = + Math.min(bag.maximum ?? Number.POSITIVE_INFINITY, bag.exclusiveMaximum ?? Number.POSITIVE_INFINITY) ?? null; + inst.isInt = (bag.format ?? "").includes("int") || Number.isSafeInteger(bag.multipleOf ?? 0.5); + inst.isFinite = true; + inst.format = bag.format ?? null; +}); + +export function number(params?: string | core.$ZodNumberParams): ZodNumber { + return core._number(ZodNumber, params); +} + +// ZodNumberFormat +export interface ZodNumberFormat extends ZodNumber { + _zod: core.$ZodNumberFormatInternals; +} +export const ZodNumberFormat: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodNumberFormat", + (inst, def) => { + core.$ZodNumberFormat.init(inst, def); + ZodNumber.init(inst, def); + } +); + +// int +export interface ZodInt extends ZodNumberFormat {} +export function int(params?: string | core.$ZodCheckNumberFormatParams): ZodInt { + return core._int(ZodNumberFormat, params); +} + +// float32 +export interface ZodFloat32 extends ZodNumberFormat {} +export function float32(params?: string | core.$ZodCheckNumberFormatParams): ZodFloat32 { + return core._float32(ZodNumberFormat, params); +} + +// float64 +export interface ZodFloat64 extends ZodNumberFormat {} +export function float64(params?: string | core.$ZodCheckNumberFormatParams): ZodFloat64 { + return core._float64(ZodNumberFormat, params); +} + +// int32 +export interface ZodInt32 extends ZodNumberFormat {} +export function int32(params?: string | core.$ZodCheckNumberFormatParams): ZodInt32 { + return core._int32(ZodNumberFormat, params); +} + +// uint32 +export interface ZodUInt32 extends ZodNumberFormat {} +export function uint32(params?: string | core.$ZodCheckNumberFormatParams): ZodUInt32 { + return core._uint32(ZodNumberFormat, params); +} + +// boolean +export interface _ZodBoolean extends _ZodType {} +export interface ZodBoolean extends _ZodBoolean> {} +export const ZodBoolean: core.$constructor = /*@__PURE__*/ core.$constructor("ZodBoolean", (inst, def) => { + core.$ZodBoolean.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.booleanProcessor(inst, ctx, json, params); +}); + +export function boolean(params?: string | core.$ZodBooleanParams): ZodBoolean { + return core._boolean(ZodBoolean, params); +} + +// bigint +export interface _ZodBigInt extends _ZodType { + gte(value: bigint, params?: string | core.$ZodCheckGreaterThanParams): this; + /** Alias of `.gte()` */ + min(value: bigint, params?: string | core.$ZodCheckGreaterThanParams): this; + gt(value: bigint, params?: string | core.$ZodCheckGreaterThanParams): this; + /** Alias of `.lte()` */ + lte(value: bigint, params?: string | core.$ZodCheckLessThanParams): this; + max(value: bigint, params?: string | core.$ZodCheckLessThanParams): this; + lt(value: bigint, params?: string | core.$ZodCheckLessThanParams): this; + positive(params?: string | core.$ZodCheckGreaterThanParams): this; + negative(params?: string | core.$ZodCheckLessThanParams): this; + nonpositive(params?: string | core.$ZodCheckLessThanParams): this; + nonnegative(params?: string | core.$ZodCheckGreaterThanParams): this; + multipleOf(value: bigint, params?: string | core.$ZodCheckMultipleOfParams): this; + + minValue: bigint | null; + maxValue: bigint | null; + format: string | null; +} + +export interface ZodBigInt extends _ZodBigInt> {} +export const ZodBigInt: core.$constructor = /*@__PURE__*/ core.$constructor("ZodBigInt", (inst, def) => { + core.$ZodBigInt.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.bigintProcessor(inst, ctx, json, params); + + inst.gte = (value, params) => inst.check(checks.gte(value, params)); + inst.min = (value, params) => inst.check(checks.gte(value, params)); + inst.gt = (value, params) => inst.check(checks.gt(value, params)); + inst.gte = (value, params) => inst.check(checks.gte(value, params)); + inst.min = (value, params) => inst.check(checks.gte(value, params)); + inst.lt = (value, params) => inst.check(checks.lt(value, params)); + inst.lte = (value, params) => inst.check(checks.lte(value, params)); + inst.max = (value, params) => inst.check(checks.lte(value, params)); + inst.positive = (params) => inst.check(checks.gt(BigInt(0), params)); + inst.negative = (params) => inst.check(checks.lt(BigInt(0), params)); + inst.nonpositive = (params) => inst.check(checks.lte(BigInt(0), params)); + inst.nonnegative = (params) => inst.check(checks.gte(BigInt(0), params)); + inst.multipleOf = (value, params) => inst.check(checks.multipleOf(value, params)); + + const bag = inst._zod.bag; + inst.minValue = bag.minimum ?? null; + inst.maxValue = bag.maximum ?? null; + inst.format = bag.format ?? null; +}); + +export function bigint(params?: string | core.$ZodBigIntParams): ZodBigInt { + return core._bigint(ZodBigInt, params); +} +// bigint formats + +// ZodBigIntFormat +export interface ZodBigIntFormat extends ZodBigInt { + _zod: core.$ZodBigIntFormatInternals; +} +export const ZodBigIntFormat: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodBigIntFormat", + (inst, def) => { + core.$ZodBigIntFormat.init(inst, def); + ZodBigInt.init(inst, def); + } +); + +// int64 +export function int64(params?: string | core.$ZodBigIntFormatParams): ZodBigIntFormat { + return core._int64(ZodBigIntFormat, params); +} + +// uint64 +export function uint64(params?: string | core.$ZodBigIntFormatParams): ZodBigIntFormat { + return core._uint64(ZodBigIntFormat, params); +} + +// symbol +export interface ZodSymbol extends _ZodType {} +export const ZodSymbol: core.$constructor = /*@__PURE__*/ core.$constructor("ZodSymbol", (inst, def) => { + core.$ZodSymbol.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.symbolProcessor(inst, ctx, json, params); +}); + +export function symbol(params?: string | core.$ZodSymbolParams): ZodSymbol { + return core._symbol(ZodSymbol, params); +} + +// ZodUndefined +export interface ZodUndefined extends _ZodType {} +export const ZodUndefined: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodUndefined", + (inst, def) => { + core.$ZodUndefined.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.undefinedProcessor(inst, ctx, json, params); + } +); + +function _undefined(params?: string | core.$ZodUndefinedParams): ZodUndefined { + return core._undefined(ZodUndefined, params); +} +export { _undefined as undefined }; + +// ZodNull +export interface ZodNull extends _ZodType {} +export const ZodNull: core.$constructor = /*@__PURE__*/ core.$constructor("ZodNull", (inst, def) => { + core.$ZodNull.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.nullProcessor(inst, ctx, json, params); +}); + +function _null(params?: string | core.$ZodNullParams): ZodNull { + return core._null(ZodNull, params); +} +export { _null as null }; + +// ZodAny +export interface ZodAny extends _ZodType {} +export const ZodAny: core.$constructor = /*@__PURE__*/ core.$constructor("ZodAny", (inst, def) => { + core.$ZodAny.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.anyProcessor(inst, ctx, json, params); +}); + +export function any(): ZodAny { + return core._any(ZodAny); +} + +// ZodUnknown +export interface ZodUnknown extends _ZodType {} +export const ZodUnknown: core.$constructor = /*@__PURE__*/ core.$constructor("ZodUnknown", (inst, def) => { + core.$ZodUnknown.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.unknownProcessor(inst, ctx, json, params); +}); + +export function unknown(): ZodUnknown { + return core._unknown(ZodUnknown); +} + +// ZodNever +export interface ZodNever extends _ZodType {} +export const ZodNever: core.$constructor = /*@__PURE__*/ core.$constructor("ZodNever", (inst, def) => { + core.$ZodNever.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.neverProcessor(inst, ctx, json, params); +}); + +export function never(params?: string | core.$ZodNeverParams): ZodNever { + return core._never(ZodNever, params); +} + +// ZodVoid +export interface ZodVoid extends _ZodType {} +export const ZodVoid: core.$constructor = /*@__PURE__*/ core.$constructor("ZodVoid", (inst, def) => { + core.$ZodVoid.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.voidProcessor(inst, ctx, json, params); +}); + +function _void(params?: string | core.$ZodVoidParams): ZodVoid { + return core._void(ZodVoid, params); +} +export { _void as void }; + +// ZodDate +export interface _ZodDate extends _ZodType { + min(value: number | Date, params?: string | core.$ZodCheckGreaterThanParams): this; + max(value: number | Date, params?: string | core.$ZodCheckLessThanParams): this; + + /** @deprecated Not recommended. */ + minDate: Date | null; + /** @deprecated Not recommended. */ + maxDate: Date | null; +} + +export interface ZodDate extends _ZodDate> {} +export const ZodDate: core.$constructor = /*@__PURE__*/ core.$constructor("ZodDate", (inst, def) => { + core.$ZodDate.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.dateProcessor(inst, ctx, json, params); + + inst.min = (value, params) => inst.check(checks.gte(value, params)); + inst.max = (value, params) => inst.check(checks.lte(value, params)); + + const c = inst._zod.bag; + inst.minDate = c.minimum ? new Date(c.minimum) : null; + inst.maxDate = c.maximum ? new Date(c.maximum) : null; +}); + +export function date(params?: string | core.$ZodDateParams): ZodDate { + return core._date(ZodDate, params); +} + +// ZodArray +export interface ZodArray + extends _ZodType>, + core.$ZodArray { + element: T; + min(minLength: number, params?: string | core.$ZodCheckMinLengthParams): this; + nonempty(params?: string | core.$ZodCheckMinLengthParams): this; + max(maxLength: number, params?: string | core.$ZodCheckMaxLengthParams): this; + length(len: number, params?: string | core.$ZodCheckLengthEqualsParams): this; + + unwrap(): T; + "~standard": ZodStandardSchemaWithJSON; +} +export const ZodArray: core.$constructor = /*@__PURE__*/ core.$constructor("ZodArray", (inst, def) => { + core.$ZodArray.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.arrayProcessor(inst, ctx, json, params); + + inst.element = def.element; + _installLazyMethods(inst, "ZodArray", { + min(n, params) { + return this.check(checks.minLength(n, params)); + }, + nonempty(params) { + return this.check(checks.minLength(1, params)); + }, + max(n, params) { + return this.check(checks.maxLength(n, params)); + }, + length(n, params) { + return this.check(checks.length(n, params)); + }, + unwrap() { + return this.element; + }, + }); +}); + +export function array(element: T, params?: string | core.$ZodArrayParams): ZodArray { + return core._array(ZodArray, element as any, params) as any; +} + +// .keyof +export function keyof(schema: T): ZodEnum> { + const shape = schema._zod.def.shape; + return _enum(Object.keys(shape)) as any; +} + +// ZodObject + +export type SafeExtendShape = { + [K in keyof Ext]: K extends keyof Base + ? core.output extends core.output + ? core.input extends core.input + ? Ext[K] + : never + : never + : Ext[K]; +}; + +export interface ZodObject< + /** @ts-ignore Cast variance */ + out Shape extends core.$ZodShape = core.$ZodLooseShape, + out Config extends core.$ZodObjectConfig = core.$strip, +> extends _ZodType>, + core.$ZodObject { + "~standard": ZodStandardSchemaWithJSON; + shape: Shape; + + keyof(): ZodEnum>; + /** Define a schema to validate all unrecognized keys. This overrides the existing strict/loose behavior. */ + catchall(schema: T): ZodObject>; + + /** @deprecated Use `z.looseObject()` or `.loose()` instead. */ + passthrough(): ZodObject; + /** Consider `z.looseObject(A.shape)` instead */ + loose(): ZodObject; + + /** Consider `z.strictObject(A.shape)` instead */ + strict(): ZodObject; + + /** This is the default behavior. This method call is likely unnecessary. */ + strip(): ZodObject; + + extend(shape: U): ZodObject>, Config>; + + safeExtend( + shape: SafeExtendShape & Partial> + ): ZodObject>, Config>; + + /** + * @deprecated Use [`A.extend(B.shape)`](https://zod.dev/api?id=extend) instead. + */ + merge(other: U): ZodObject, U["_zod"]["config"]>; + + pick>( + mask: M & Record, never> + ): ZodObject>>, Config>; + + omit>( + mask: M & Record, never> + ): ZodObject>>, Config>; + + partial(): ZodObject< + { + -readonly [k in keyof Shape]: ZodOptional; + }, + Config + >; + partial>( + mask: M & Record, never> + ): ZodObject< + { + -readonly [k in keyof Shape]: k extends keyof M + ? // Shape[k] extends OptionalInSchema + // ? Shape[k] + // : + ZodOptional + : Shape[k]; + }, + Config + >; + + // required + required(): ZodObject< + { + -readonly [k in keyof Shape]: ZodNonOptional; + }, + Config + >; + required>( + mask: M & Record, never> + ): ZodObject< + { + -readonly [k in keyof Shape]: k extends keyof M ? ZodNonOptional : Shape[k]; + }, + Config + >; +} + +export const ZodObject: core.$constructor = /*@__PURE__*/ core.$constructor("ZodObject", (inst, def) => { + core.$ZodObjectJIT.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.objectProcessor(inst, ctx, json, params); + + util.defineLazy(inst, "shape", () => { + return def.shape; + }); + + _installLazyMethods(inst, "ZodObject", { + keyof() { + return _enum(Object.keys(this._zod.def.shape)); + }, + catchall(catchall) { + return this.clone({ ...this._zod.def, catchall: catchall as any }); + }, + passthrough() { + return this.clone({ ...this._zod.def, catchall: unknown() }); + }, + loose() { + return this.clone({ ...this._zod.def, catchall: unknown() }); + }, + strict() { + return this.clone({ ...this._zod.def, catchall: never() }); + }, + strip() { + return this.clone({ ...this._zod.def, catchall: undefined }); + }, + extend(incoming) { + return util.extend(this, incoming); + }, + safeExtend(incoming) { + return util.safeExtend(this, incoming); + }, + merge(other) { + return util.merge(this, other); + }, + pick(mask) { + return util.pick(this, mask); + }, + omit(mask) { + return util.omit(this, mask); + }, + partial(...args) { + return util.partial(ZodOptional, this, args[0]); + }, + required(...args) { + return util.required(ZodNonOptional, this, args[0]); + }, + }); +}); + +export function object>>( + shape?: T, + params?: string | core.$ZodObjectParams +): ZodObject, core.$strip> { + const def: core.$ZodObjectDef = { + type: "object", + shape: shape ?? {}, + ...util.normalizeParams(params), + }; + return new ZodObject(def) as any; +} + +// strictObject + +export function strictObject( + shape: T, + params?: string | core.$ZodObjectParams +): ZodObject, core.$strict> { + return new ZodObject({ + type: "object", + shape, + catchall: never(), + ...util.normalizeParams(params), + }) as any; +} + +// looseObject + +export function looseObject( + shape: T, + params?: string | core.$ZodObjectParams +): ZodObject, core.$loose> { + return new ZodObject({ + type: "object", + shape, + catchall: unknown(), + ...util.normalizeParams(params), + }) as any; +} + +// ZodUnion +export interface ZodUnion + extends _ZodType>, + core.$ZodUnion { + "~standard": ZodStandardSchemaWithJSON; + options: T; +} +export const ZodUnion: core.$constructor = /*@__PURE__*/ core.$constructor("ZodUnion", (inst, def) => { + core.$ZodUnion.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.unionProcessor(inst, ctx, json, params); + inst.options = def.options; +}); + +export function union( + options: T, + params?: string | core.$ZodUnionParams +): ZodUnion { + return new ZodUnion({ + type: "union", + options: options as any as core.$ZodType[], + ...util.normalizeParams(params), + }) as any; +} + +// ZodXor +export interface ZodXor + extends _ZodType>, + core.$ZodXor { + "~standard": ZodStandardSchemaWithJSON; + options: T; +} +export const ZodXor: core.$constructor = /*@__PURE__*/ core.$constructor("ZodXor", (inst, def) => { + ZodUnion.init(inst, def); + core.$ZodXor.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.unionProcessor(inst, ctx, json, params); + inst.options = def.options; +}); + +/** Creates an exclusive union (XOR) where exactly one option must match. + * Unlike regular unions that succeed when any option matches, xor fails if + * zero or more than one option matches the input. */ +export function xor( + options: T, + params?: string | core.$ZodXorParams +): ZodXor { + return new ZodXor({ + type: "union", + options: options as any as core.$ZodType[], + inclusive: false, + ...util.normalizeParams(params), + }) as any; +} + +// ZodDiscriminatedUnion +export interface ZodDiscriminatedUnion< + Options extends readonly core.SomeType[] = readonly core.$ZodType[], + Disc extends string = string, +> extends ZodUnion, + core.$ZodDiscriminatedUnion { + "~standard": ZodStandardSchemaWithJSON; + _zod: core.$ZodDiscriminatedUnionInternals; + def: core.$ZodDiscriminatedUnionDef; +} +export const ZodDiscriminatedUnion: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodDiscriminatedUnion", + (inst, def) => { + ZodUnion.init(inst, def); + core.$ZodDiscriminatedUnion.init(inst, def); + } +); + +export function discriminatedUnion< + Types extends readonly [core.$ZodTypeDiscriminable, ...core.$ZodTypeDiscriminable[]], + Disc extends string, +>( + discriminator: Disc, + options: Types, + params?: string | core.$ZodDiscriminatedUnionParams +): ZodDiscriminatedUnion { + // const [options, params] = args; + return new ZodDiscriminatedUnion({ + type: "union", + options, + discriminator, + ...util.normalizeParams(params), + }) as any; +} + +// ZodIntersection +export interface ZodIntersection + extends _ZodType>, + core.$ZodIntersection { + "~standard": ZodStandardSchemaWithJSON; +} +export const ZodIntersection: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodIntersection", + (inst, def) => { + core.$ZodIntersection.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.intersectionProcessor(inst, ctx, json, params); + } +); + +export function intersection( + left: T, + right: U +): ZodIntersection { + return new ZodIntersection({ + type: "intersection", + left: left as any as core.$ZodType, + right: right as any as core.$ZodType, + }) as any; +} + +// ZodTuple +export interface ZodTuple< + T extends util.TupleItems = readonly core.$ZodType[], + Rest extends core.SomeType | null = core.$ZodType | null, +> extends _ZodType>, + core.$ZodTuple { + "~standard": ZodStandardSchemaWithJSON; + rest(rest: Rest): ZodTuple; +} +export const ZodTuple: core.$constructor = /*@__PURE__*/ core.$constructor("ZodTuple", (inst, def) => { + core.$ZodTuple.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.tupleProcessor(inst, ctx, json, params); + inst.rest = (rest) => + inst.clone({ + ...inst._zod.def, + rest: rest as any as core.$ZodType, + }) as any; +}); + +export function tuple( + items: T, + params?: string | core.$ZodTupleParams +): ZodTuple; +export function tuple( + items: T, + rest: Rest, + params?: string | core.$ZodTupleParams +): ZodTuple; +export function tuple(items: [], params?: string | core.$ZodTupleParams): ZodTuple<[], null>; +export function tuple( + items: core.SomeType[], + _paramsOrRest?: string | core.$ZodTupleParams | core.SomeType, + _params?: string | core.$ZodTupleParams +) { + const hasRest = _paramsOrRest instanceof core.$ZodType; + const params = hasRest ? _params : _paramsOrRest; + const rest = hasRest ? _paramsOrRest : null; + return new ZodTuple({ + type: "tuple", + items: items as any as core.$ZodType[], + rest, + ...util.normalizeParams(params), + }); +} + +// ZodRecord +export interface ZodRecord< + Key extends core.$ZodRecordKey = core.$ZodRecordKey, + Value extends core.SomeType = core.$ZodType, +> extends _ZodType>, + core.$ZodRecord { + "~standard": ZodStandardSchemaWithJSON; + keyType: Key; + valueType: Value; +} +export const ZodRecord: core.$constructor = /*@__PURE__*/ core.$constructor("ZodRecord", (inst, def) => { + core.$ZodRecord.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.recordProcessor(inst, ctx, json, params); + + inst.keyType = def.keyType; + inst.valueType = def.valueType; +}); + +export function record( + keyType: Key, + valueType: Value, + params?: string | core.$ZodRecordParams +): ZodRecord { + // v3-compat: z.record(valueType, params?) — defaults keyType to z.string() + if (!valueType || !(valueType as any)._zod) { + return new ZodRecord({ + type: "record", + keyType: string() as any, + valueType: keyType as any as core.$ZodType, + ...util.normalizeParams(valueType as string | core.$ZodRecordParams | undefined), + }) as any; + } + return new ZodRecord({ + type: "record", + keyType, + valueType: valueType as any as core.$ZodType, + ...util.normalizeParams(params), + }) as any; +} +// type alksjf = core.output; +export function partialRecord( + keyType: Key, + valueType: Value, + params?: string | core.$ZodRecordParams +): ZodRecord { + const k = core.clone(keyType); + k._zod.values = undefined; + return new ZodRecord({ + type: "record", + keyType: k, + valueType: valueType as any, + ...util.normalizeParams(params), + }) as any; +} + +export function looseRecord( + keyType: Key, + valueType: Value, + params?: string | core.$ZodRecordParams +): ZodRecord { + return new ZodRecord({ + type: "record", + keyType, + valueType: valueType as any as core.$ZodType, + mode: "loose", + ...util.normalizeParams(params), + }) as any; +} + +// ZodMap +export interface ZodMap + extends _ZodType>, + core.$ZodMap { + "~standard": ZodStandardSchemaWithJSON; + keyType: Key; + valueType: Value; + min(minSize: number, params?: string | core.$ZodCheckMinSizeParams): this; + nonempty(params?: string | core.$ZodCheckMinSizeParams): this; + max(maxSize: number, params?: string | core.$ZodCheckMaxSizeParams): this; + size(size: number, params?: string | core.$ZodCheckSizeEqualsParams): this; +} +export const ZodMap: core.$constructor = /*@__PURE__*/ core.$constructor("ZodMap", (inst, def) => { + core.$ZodMap.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.mapProcessor(inst, ctx, json, params); + inst.keyType = def.keyType; + inst.valueType = def.valueType; + inst.min = (...args) => inst.check(core._minSize(...args)); + inst.nonempty = (params) => inst.check(core._minSize(1, params)); + inst.max = (...args) => inst.check(core._maxSize(...args)); + inst.size = (...args) => inst.check(core._size(...args)); +}); + +export function map( + keyType: Key, + valueType: Value, + params?: string | core.$ZodMapParams +): ZodMap { + return new ZodMap({ + type: "map", + keyType: keyType as any as core.$ZodType, + valueType: valueType as any as core.$ZodType, + ...util.normalizeParams(params), + }) as any; +} + +// ZodSet +export interface ZodSet + extends _ZodType>, + core.$ZodSet { + "~standard": ZodStandardSchemaWithJSON; + min(minSize: number, params?: string | core.$ZodCheckMinSizeParams): this; + nonempty(params?: string | core.$ZodCheckMinSizeParams): this; + max(maxSize: number, params?: string | core.$ZodCheckMaxSizeParams): this; + size(size: number, params?: string | core.$ZodCheckSizeEqualsParams): this; +} +export const ZodSet: core.$constructor = /*@__PURE__*/ core.$constructor("ZodSet", (inst, def) => { + core.$ZodSet.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.setProcessor(inst, ctx, json, params); + + inst.min = (...args) => inst.check(core._minSize(...args)); + inst.nonempty = (params) => inst.check(core._minSize(1, params)); + inst.max = (...args) => inst.check(core._maxSize(...args)); + inst.size = (...args) => inst.check(core._size(...args)); +}); + +export function set( + valueType: Value, + params?: string | core.$ZodSetParams +): ZodSet { + return new ZodSet({ + type: "set", + valueType: valueType as any as core.$ZodType, + ...util.normalizeParams(params), + }) as any; +} + +// ZodEnum +export interface ZodEnum< + /** @ts-ignore Cast variance */ + out T extends util.EnumLike = util.EnumLike, +> extends _ZodType>, + core.$ZodEnum { + "~standard": ZodStandardSchemaWithJSON; + enum: T; + options: Array; + + extract( + values: U, + params?: string | core.$ZodEnumParams + ): ZodEnum>>; + exclude( + values: U, + params?: string | core.$ZodEnumParams + ): ZodEnum>>; +} +export const ZodEnum: core.$constructor = /*@__PURE__*/ core.$constructor("ZodEnum", (inst, def) => { + core.$ZodEnum.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.enumProcessor(inst, ctx, json, params); + + inst.enum = def.entries; + inst.options = Object.values(def.entries); + + const keys = new Set(Object.keys(def.entries)); + + inst.extract = (values, params) => { + const newEntries: Record = {}; + for (const value of values) { + if (keys.has(value)) { + newEntries[value] = def.entries[value]; + } else throw new Error(`Key ${value} not found in enum`); + } + return new ZodEnum({ + ...def, + checks: [], + ...util.normalizeParams(params), + entries: newEntries, + }) as any; + }; + + inst.exclude = (values, params) => { + const newEntries: Record = { ...def.entries }; + for (const value of values) { + if (keys.has(value)) { + delete newEntries[value]; + } else throw new Error(`Key ${value} not found in enum`); + } + return new ZodEnum({ + ...def, + checks: [], + ...util.normalizeParams(params), + entries: newEntries, + }) as any; + }; +}); + +function _enum( + values: T, + params?: string | core.$ZodEnumParams +): ZodEnum>; +function _enum(entries: T, params?: string | core.$ZodEnumParams): ZodEnum; +function _enum(values: any, params?: string | core.$ZodEnumParams) { + const entries: any = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values; + + return new ZodEnum({ + type: "enum", + entries, + ...util.normalizeParams(params), + }) as any; +} +export { _enum as enum }; + +/** @deprecated This API has been merged into `z.enum()`. Use `z.enum()` instead. + * + * ```ts + * enum Colors { red, green, blue } + * z.enum(Colors); + * ``` + */ +export function nativeEnum(entries: T, params?: string | core.$ZodEnumParams): ZodEnum { + return new ZodEnum({ + type: "enum", + entries, + ...util.normalizeParams(params), + }) as ZodEnum; +} + +// ZodLiteral +export interface ZodLiteral + extends _ZodType>, + core.$ZodLiteral { + "~standard": ZodStandardSchemaWithJSON; + values: Set; + /** @legacy Use `.values` instead. Accessing this property will throw an error if the literal accepts multiple values. */ + value: T; +} +export const ZodLiteral: core.$constructor = /*@__PURE__*/ core.$constructor("ZodLiteral", (inst, def) => { + core.$ZodLiteral.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.literalProcessor(inst, ctx, json, params); + inst.values = new Set(def.values); + Object.defineProperty(inst, "value", { + get() { + if (def.values.length > 1) { + throw new Error("This schema contains multiple valid literal values. Use `.values` instead."); + } + return def.values[0]; + }, + }); +}); + +export function literal>( + value: T, + params?: string | core.$ZodLiteralParams +): ZodLiteral; +export function literal( + value: T, + params?: string | core.$ZodLiteralParams +): ZodLiteral; +export function literal(value: any, params: any) { + return new ZodLiteral({ + type: "literal", + values: Array.isArray(value) ? value : [value], + ...util.normalizeParams(params), + }); +} + +// ZodFile +export interface ZodFile extends _ZodType, core.$ZodFile { + "~standard": ZodStandardSchemaWithJSON; + min(size: number, params?: string | core.$ZodCheckMinSizeParams): this; + max(size: number, params?: string | core.$ZodCheckMaxSizeParams): this; + mime(types: util.MimeTypes | Array, params?: string | core.$ZodCheckMimeTypeParams): this; +} +export const ZodFile: core.$constructor = /*@__PURE__*/ core.$constructor("ZodFile", (inst, def) => { + core.$ZodFile.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.fileProcessor(inst, ctx, json, params); + + inst.min = (size, params) => inst.check(core._minSize(size, params)); + inst.max = (size, params) => inst.check(core._maxSize(size, params)); + inst.mime = (types, params) => inst.check(core._mime(Array.isArray(types) ? types : [types], params)); +}); + +export function file(params?: string | core.$ZodFileParams): ZodFile { + return core._file(ZodFile, params) as any; +} + +// ZodTransform +export interface ZodTransform + extends _ZodType>, + core.$ZodTransform { + "~standard": ZodStandardSchemaWithJSON; +} +export const ZodTransform: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodTransform", + (inst, def) => { + core.$ZodTransform.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.transformProcessor(inst, ctx, json, params); + + inst._zod.parse = (payload, _ctx) => { + if (_ctx.direction === "backward") { + throw new core.$ZodEncodeError(inst.constructor.name); + } + + (payload as core.$RefinementCtx).addIssue = (issue) => { + if (typeof issue === "string") { + payload.issues.push(util.issue(issue, payload.value, def)); + } else { + // for Zod 3 backwards compatibility + const _issue = issue as any; + + if (_issue.fatal) _issue.continue = false; + _issue.code ??= "custom"; + _issue.input ??= payload.value; + _issue.inst ??= inst; + // _issue.continue ??= true; + payload.issues.push(util.issue(_issue)); + } + }; + + const output = def.transform(payload.value, payload); + if (output instanceof Promise) { + return output.then((output) => { + payload.value = output; + payload.fallback = true; + return payload; + }); + } + payload.value = output; + payload.fallback = true; + return payload; + }; + } +); + +export function transform( + fn: (input: I, ctx: core.$RefinementCtx) => O +): ZodTransform, I> { + return new ZodTransform({ + type: "transform", + transform: fn as any, + }) as any; +} + +// ZodOptional +export interface ZodOptional + extends _ZodType>, + core.$ZodOptional { + "~standard": ZodStandardSchemaWithJSON; + unwrap(): T; +} +export const ZodOptional: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodOptional", + (inst, def) => { + core.$ZodOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.optionalProcessor(inst, ctx, json, params); + + inst.unwrap = () => inst._zod.def.innerType; + } +); + +export function optional(innerType: T): ZodOptional { + return new ZodOptional({ + type: "optional", + innerType: innerType as any as core.$ZodType, + }) as any; +} + +// ZodExactOptional +export interface ZodExactOptional + extends _ZodType>, + core.$ZodExactOptional { + "~standard": ZodStandardSchemaWithJSON; + unwrap(): T; +} +export const ZodExactOptional: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodExactOptional", + (inst, def) => { + core.$ZodExactOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.optionalProcessor(inst, ctx, json, params); + + inst.unwrap = () => inst._zod.def.innerType; + } +); + +export function exactOptional(innerType: T): ZodExactOptional { + return new ZodExactOptional({ + type: "optional", + innerType: innerType as any as core.$ZodType, + }) as any; +} + +// ZodNullable +export interface ZodNullable + extends _ZodType>, + core.$ZodNullable { + "~standard": ZodStandardSchemaWithJSON; + unwrap(): T; +} +export const ZodNullable: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodNullable", + (inst, def) => { + core.$ZodNullable.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.nullableProcessor(inst, ctx, json, params); + + inst.unwrap = () => inst._zod.def.innerType; + } +); + +export function nullable(innerType: T): ZodNullable { + return new ZodNullable({ + type: "nullable", + innerType: innerType as any as core.$ZodType, + }) as any; +} + +// nullish +export function nullish(innerType: T): ZodOptional> { + return optional(nullable(innerType)); +} + +// ZodDefault +export interface ZodDefault + extends _ZodType>, + core.$ZodDefault { + "~standard": ZodStandardSchemaWithJSON; + unwrap(): T; + /** @deprecated Use `.unwrap()` instead. */ + removeDefault(): T; +} +export const ZodDefault: core.$constructor = /*@__PURE__*/ core.$constructor("ZodDefault", (inst, def) => { + core.$ZodDefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.defaultProcessor(inst, ctx, json, params); + + inst.unwrap = () => inst._zod.def.innerType; + inst.removeDefault = inst.unwrap; +}); + +export function _default( + innerType: T, + defaultValue: util.NoUndefined> | (() => util.NoUndefined>) +): ZodDefault { + return new ZodDefault({ + type: "default", + innerType: innerType as any as core.$ZodType, + get defaultValue() { + return typeof defaultValue === "function" ? (defaultValue as Function)() : util.shallowClone(defaultValue); + }, + }) as any; +} + +// ZodPrefault +export interface ZodPrefault + extends _ZodType>, + core.$ZodPrefault { + "~standard": ZodStandardSchemaWithJSON; + unwrap(): T; +} +export const ZodPrefault: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodPrefault", + (inst, def) => { + core.$ZodPrefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.prefaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + } +); + +export function prefault( + innerType: T, + defaultValue: core.input | (() => core.input) +): ZodPrefault { + return new ZodPrefault({ + type: "prefault", + innerType: innerType as any as core.$ZodType, + get defaultValue() { + return typeof defaultValue === "function" ? (defaultValue as Function)() : util.shallowClone(defaultValue); + }, + }) as any; +} + +// ZodNonOptional +export interface ZodNonOptional + extends _ZodType>, + core.$ZodNonOptional { + "~standard": ZodStandardSchemaWithJSON; + unwrap(): T; +} +export const ZodNonOptional: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodNonOptional", + (inst, def) => { + core.$ZodNonOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.nonoptionalProcessor(inst, ctx, json, params); + + inst.unwrap = () => inst._zod.def.innerType; + } +); + +export function nonoptional( + innerType: T, + params?: string | core.$ZodNonOptionalParams +): ZodNonOptional { + return new ZodNonOptional({ + type: "nonoptional", + innerType: innerType as any as core.$ZodType, + ...util.normalizeParams(params), + }) as any; +} + +// ZodSuccess +export interface ZodSuccess + extends _ZodType>, + core.$ZodSuccess { + "~standard": ZodStandardSchemaWithJSON; + unwrap(): T; +} +export const ZodSuccess: core.$constructor = /*@__PURE__*/ core.$constructor("ZodSuccess", (inst, def) => { + core.$ZodSuccess.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.successProcessor(inst, ctx, json, params); + + inst.unwrap = () => inst._zod.def.innerType; +}); + +export function success(innerType: T): ZodSuccess { + return new ZodSuccess({ + type: "success", + innerType: innerType as any as core.$ZodType, + }) as any; +} + +// ZodCatch +export interface ZodCatch + extends _ZodType>, + core.$ZodCatch { + "~standard": ZodStandardSchemaWithJSON; + unwrap(): T; + /** @deprecated Use `.unwrap()` instead. */ + removeCatch(): T; +} +export const ZodCatch: core.$constructor = /*@__PURE__*/ core.$constructor("ZodCatch", (inst, def) => { + core.$ZodCatch.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.catchProcessor(inst, ctx, json, params); + + inst.unwrap = () => inst._zod.def.innerType; + inst.removeCatch = inst.unwrap; +}); + +function _catch( + innerType: T, + catchValue: core.output | ((ctx: core.$ZodCatchCtx) => core.output) +): ZodCatch { + return new ZodCatch({ + type: "catch", + innerType: innerType as any as core.$ZodType, + catchValue: (typeof catchValue === "function" ? catchValue : () => catchValue) as ( + ctx: core.$ZodCatchCtx + ) => core.output, + }) as any; +} +export { _catch as catch }; + +// ZodNaN +export interface ZodNaN extends _ZodType, core.$ZodNaN { + "~standard": ZodStandardSchemaWithJSON; +} +export const ZodNaN: core.$constructor = /*@__PURE__*/ core.$constructor("ZodNaN", (inst, def) => { + core.$ZodNaN.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.nanProcessor(inst, ctx, json, params); +}); + +export function nan(params?: string | core.$ZodNaNParams): ZodNaN { + return core._nan(ZodNaN, params); +} + +// ZodPipe +export interface ZodPipe + extends _ZodType>, + core.$ZodPipe { + "~standard": ZodStandardSchemaWithJSON; + in: A; + out: B; +} +export const ZodPipe: core.$constructor = /*@__PURE__*/ core.$constructor("ZodPipe", (inst, def) => { + core.$ZodPipe.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.pipeProcessor(inst, ctx, json, params); + + inst.in = def.in; + inst.out = def.out; +}); + +export function pipe< + const A extends core.SomeType, + B extends core.$ZodType> = core.$ZodType>, +>(in_: A, out: B | core.$ZodType>): ZodPipe; +export function pipe(in_: core.SomeType, out: core.SomeType) { + return new ZodPipe({ + type: "pipe", + in: in_ as unknown as core.$ZodType, + out: out as unknown as core.$ZodType, + // ...util.normalizeParams(params), + }); +} + +// ZodCodec +export interface ZodCodec + extends ZodPipe, + core.$ZodCodec { + "~standard": ZodStandardSchemaWithJSON; + _zod: core.$ZodCodecInternals; + def: core.$ZodCodecDef; +} +export const ZodCodec: core.$constructor = /*@__PURE__*/ core.$constructor("ZodCodec", (inst, def) => { + ZodPipe.init(inst, def); + core.$ZodCodec.init(inst, def); +}); + +export function codec( + in_: A, + out: B, + params: { + decode: (value: core.output, payload: core.ParsePayload>) => core.util.MaybeAsync>; + encode: (value: core.input, payload: core.ParsePayload>) => core.util.MaybeAsync>; + } +): ZodCodec { + return new ZodCodec({ + type: "pipe", + in: in_ as any as core.$ZodType, + out: out as any as core.$ZodType, + transform: params.decode as any, + reverseTransform: params.encode as any, + }) as any; +} + +export function invertCodec(codec: ZodCodec): ZodCodec { + const def = codec._zod.def; + return new ZodCodec({ + type: "pipe", + in: def.out as any, + out: def.in as any, + transform: def.reverseTransform as any, + reverseTransform: def.transform as any, + }) as any; +} + +// ZodPreprocess +export interface ZodPreprocess + extends ZodPipe, + core.$ZodPreprocess { + "~standard": ZodStandardSchemaWithJSON; + _zod: core.$ZodPreprocessInternals; + def: core.$ZodPreprocessDef; +} +export const ZodPreprocess: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodPreprocess", + (inst, def) => { + ZodPipe.init(inst, def); + core.$ZodPreprocess.init(inst, def); + } +); + +// ZodReadonly +export interface ZodReadonly + extends _ZodType>, + core.$ZodReadonly { + "~standard": ZodStandardSchemaWithJSON; + unwrap(): T; +} +export const ZodReadonly: core.$constructor = /*@__PURE__*/ core.$constructor( + "ZodReadonly", + (inst, def) => { + core.$ZodReadonly.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => processors.readonlyProcessor(inst, ctx, json, params); + + inst.unwrap = () => inst._zod.def.innerType; + } +); + +export function readonly(innerType: T): ZodReadonly { + return new ZodReadonly({ + type: "readonly", + innerType: innerType as any as core.$ZodType, + }) as any; +} + +// ZodTemplateLiteral +export interface ZodTemplateLiteral